summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/double-conversion/double-conversion/bignum.cc12
-rw-r--r--src/3rdparty/double-conversion/double-conversion/double-to-string.cc9
-rw-r--r--src/3rdparty/double-conversion/double-conversion/double-to-string.h27
-rw-r--r--src/3rdparty/double-conversion/qt_attribution.json4
-rw-r--r--src/3rdparty/easing/qt_attribution.json2
-rw-r--r--src/3rdparty/forkfd/forkfd.c16
-rw-r--r--src/3rdparty/forkfd/forkfd_linux.c2
-rw-r--r--src/3rdparty/forkfd/qt_attribution.json4
-rw-r--r--src/3rdparty/freetype/README8
-rw-r--r--src/3rdparty/freetype/docs/CHANGES64
-rw-r--r--src/3rdparty/freetype/docs/DEBUG6
-rwxr-xr-xsrc/3rdparty/freetype/import_from_tarball.sh42
-rw-r--r--src/3rdparty/freetype/include/dlg/dlg.h190
-rw-r--r--src/3rdparty/freetype/include/freetype/config/ftoption.h47
-rw-r--r--src/3rdparty/freetype/include/freetype/config/ftstdlib.h14
-rw-r--r--src/3rdparty/freetype/include/freetype/freetype.h563
-rw-r--r--src/3rdparty/freetype/include/freetype/ftcache.h88
-rw-r--r--src/3rdparty/freetype/include/freetype/ftchapters.h23
-rw-r--r--src/3rdparty/freetype/include/freetype/ftdriver.h11
-rw-r--r--src/3rdparty/freetype/include/freetype/ftimage.h10
-rw-r--r--src/3rdparty/freetype/include/freetype/ftlogging.h2
-rw-r--r--src/3rdparty/freetype/include/freetype/ftmm.h57
-rw-r--r--src/3rdparty/freetype/include/freetype/ftoutln.h2
-rw-r--r--src/3rdparty/freetype/include/freetype/ftrender.h2
-rw-r--r--src/3rdparty/freetype/include/freetype/ftsynth.h12
-rw-r--r--src/3rdparty/freetype/include/freetype/ftsystem.h16
-rw-r--r--src/3rdparty/freetype/include/freetype/internal/compiler-macros.h7
-rw-r--r--src/3rdparty/freetype/include/freetype/internal/ftcalc.h4
-rw-r--r--src/3rdparty/freetype/include/freetype/internal/ftdrv.h1
-rw-r--r--src/3rdparty/freetype/include/freetype/internal/ftmmtypes.h20
-rw-r--r--src/3rdparty/freetype/include/freetype/internal/services/svmetric.h10
-rw-r--r--src/3rdparty/freetype/include/freetype/internal/services/svmm.h109
-rw-r--r--src/3rdparty/freetype/include/freetype/internal/services/svpscmap.h2
-rw-r--r--src/3rdparty/freetype/include/freetype/internal/t1types.h26
-rw-r--r--src/3rdparty/freetype/include/freetype/internal/tttypes.h137
-rw-r--r--src/3rdparty/freetype/qt_attribution.json76
-rw-r--r--src/3rdparty/freetype/src/autofit/afblue.dat2
-rw-r--r--src/3rdparty/freetype/src/autofit/afcjk.c62
-rw-r--r--src/3rdparty/freetype/src/autofit/afcjk.h20
-rw-r--r--src/3rdparty/freetype/src/autofit/afglobal.c5
-rw-r--r--src/3rdparty/freetype/src/autofit/afglobal.h2
-rw-r--r--src/3rdparty/freetype/src/autofit/afhints.c58
-rw-r--r--src/3rdparty/freetype/src/autofit/afindic.c32
-rw-r--r--src/3rdparty/freetype/src/autofit/aflatin.c87
-rw-r--r--src/3rdparty/freetype/src/autofit/aflatin.h4
-rw-r--r--src/3rdparty/freetype/src/autofit/afloader.c6
-rw-r--r--src/3rdparty/freetype/src/autofit/afmodule.c37
-rw-r--r--src/3rdparty/freetype/src/autofit/afshaper.c6
-rw-r--r--src/3rdparty/freetype/src/autofit/ft-hb.c2
-rw-r--r--src/3rdparty/freetype/src/base/ftbbox.c42
-rw-r--r--src/3rdparty/freetype/src/base/ftcalc.c86
-rw-r--r--src/3rdparty/freetype/src/base/ftdbgmem.c2
-rw-r--r--src/3rdparty/freetype/src/base/ftmac.c2
-rw-r--r--src/3rdparty/freetype/src/base/ftmm.c146
-rw-r--r--src/3rdparty/freetype/src/base/ftobjs.c26
-rw-r--r--src/3rdparty/freetype/src/base/ftoutln.c52
-rw-r--r--src/3rdparty/freetype/src/base/ftstream.c8
-rw-r--r--src/3rdparty/freetype/src/base/ftstroke.c21
-rw-r--r--src/3rdparty/freetype/src/base/ftsynth.c20
-rw-r--r--src/3rdparty/freetype/src/base/ftsystem.c9
-rw-r--r--src/3rdparty/freetype/src/base/ftver.rc4
-rw-r--r--src/3rdparty/freetype/src/bdf/bdf.h4
-rw-r--r--src/3rdparty/freetype/src/bdf/bdfdrivr.c116
-rw-r--r--src/3rdparty/freetype/src/bdf/bdflib.c67
-rw-r--r--src/3rdparty/freetype/src/bzip2/ftbzip2.c19
-rw-r--r--src/3rdparty/freetype/src/cache/ftcbasic.c8
-rw-r--r--src/3rdparty/freetype/src/cache/ftccache.c125
-rw-r--r--src/3rdparty/freetype/src/cache/ftccache.h17
-rw-r--r--src/3rdparty/freetype/src/cache/ftcglyph.c46
-rw-r--r--src/3rdparty/freetype/src/cache/ftcglyph.h15
-rw-r--r--src/3rdparty/freetype/src/cache/ftcmanag.c42
-rw-r--r--src/3rdparty/freetype/src/cache/ftcmru.c28
-rw-r--r--src/3rdparty/freetype/src/cache/ftcsbits.c17
-rw-r--r--src/3rdparty/freetype/src/cache/ftcsbits.h11
-rw-r--r--src/3rdparty/freetype/src/cff/cffcmap.c107
-rw-r--r--src/3rdparty/freetype/src/cff/cffdrivr.c443
-rw-r--r--src/3rdparty/freetype/src/cff/cffgload.c6
-rw-r--r--src/3rdparty/freetype/src/cff/cffload.c40
-rw-r--r--src/3rdparty/freetype/src/cff/cffload.h4
-rw-r--r--src/3rdparty/freetype/src/cff/cffobjs.c24
-rw-r--r--src/3rdparty/freetype/src/cff/cffparse.c250
-rw-r--r--src/3rdparty/freetype/src/cff/cffparse.h13
-rw-r--r--src/3rdparty/freetype/src/cid/cidgload.c141
-rw-r--r--src/3rdparty/freetype/src/cid/cidgload.h8
-rw-r--r--src/3rdparty/freetype/src/cid/cidload.c51
-rw-r--r--src/3rdparty/freetype/src/cid/cidobjs.c14
-rw-r--r--src/3rdparty/freetype/src/cid/cidparse.c16
-rw-r--r--src/3rdparty/freetype/src/cid/cidriver.c97
-rw-r--r--src/3rdparty/freetype/src/dlg/dlgwrap.c2
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvfgen.c3
-rw-r--r--src/3rdparty/freetype/src/gzip/README.freetype2
-rw-r--r--src/3rdparty/freetype/src/gzip/ftgzip.c5
-rw-r--r--src/3rdparty/freetype/src/gzip/infback.c644
-rw-r--r--src/3rdparty/freetype/src/gzip/rules.mk34
-rw-r--r--src/3rdparty/freetype/src/pcf/pcfdrivr.c122
-rw-r--r--src/3rdparty/freetype/src/pfr/pfrcmap.c48
-rw-r--r--src/3rdparty/freetype/src/pfr/pfrdrivr.c26
-rw-r--r--src/3rdparty/freetype/src/pfr/pfrgload.c3
-rw-r--r--src/3rdparty/freetype/src/pfr/pfrload.c60
-rw-r--r--src/3rdparty/freetype/src/pfr/pfrobjs.c6
-rw-r--r--src/3rdparty/freetype/src/psaux/afmparse.c2
-rw-r--r--src/3rdparty/freetype/src/psaux/cffdecode.c6
-rw-r--r--src/3rdparty/freetype/src/psaux/pshints.c2
-rw-r--r--src/3rdparty/freetype/src/psaux/t1cmap.c141
-rw-r--r--src/3rdparty/freetype/src/psaux/t1decode.c4
-rw-r--r--src/3rdparty/freetype/src/pshinter/pshalgo.c2
-rw-r--r--src/3rdparty/freetype/src/pshinter/pshmod.c9
-rw-r--r--src/3rdparty/freetype/src/pshinter/pshrec.c63
-rw-r--r--src/3rdparty/freetype/src/psnames/psmodule.c42
-rw-r--r--src/3rdparty/freetype/src/raster/ftraster.c44
-rw-r--r--src/3rdparty/freetype/src/raster/ftrend1.c21
-rw-r--r--src/3rdparty/freetype/src/sdf/ftbsdf.c7
-rw-r--r--src/3rdparty/freetype/src/sdf/ftsdf.c21
-rw-r--r--src/3rdparty/freetype/src/sdf/ftsdfrend.c35
-rw-r--r--src/3rdparty/freetype/src/sfnt/pngshim.c7
-rw-r--r--src/3rdparty/freetype/src/sfnt/sfdriver.c143
-rw-r--r--src/3rdparty/freetype/src/sfnt/sfobjs.c30
-rw-r--r--src/3rdparty/freetype/src/sfnt/sfwoff.c2
-rw-r--r--src/3rdparty/freetype/src/sfnt/sfwoff2.c20
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttbdf.c13
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttbdf.h2
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttcmap.c547
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttcolr.c10
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttcpal.c2
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttload.c7
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttmtx.c2
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttpost.c284
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttsbit.c2
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttsvg.c2
-rw-r--r--src/3rdparty/freetype/src/sfnt/woff2tags.c2
-rw-r--r--src/3rdparty/freetype/src/smooth/ftgrays.c54
-rw-r--r--src/3rdparty/freetype/src/smooth/ftsmooth.c22
-rw-r--r--src/3rdparty/freetype/src/svg/ftsvg.c45
-rw-r--r--src/3rdparty/freetype/src/tools/apinames.c44
-rw-r--r--src/3rdparty/freetype/src/tools/ftrandom/ftrandom.c2
-rw-r--r--src/3rdparty/freetype/src/tools/vms_shorten_symbol.c250
-rw-r--r--src/3rdparty/freetype/src/truetype/rules.mk3
-rw-r--r--src/3rdparty/freetype/src/truetype/truetype.c1
-rw-r--r--src/3rdparty/freetype/src/truetype/ttdriver.c157
-rw-r--r--src/3rdparty/freetype/src/truetype/ttgload.c559
-rw-r--r--src/3rdparty/freetype/src/truetype/ttgxvar.c524
-rw-r--r--src/3rdparty/freetype/src/truetype/ttgxvar.h40
-rw-r--r--src/3rdparty/freetype/src/truetype/ttinterp.c959
-rw-r--r--src/3rdparty/freetype/src/truetype/ttinterp.h84
-rw-r--r--src/3rdparty/freetype/src/truetype/ttobjs.c88
-rw-r--r--src/3rdparty/freetype/src/truetype/ttobjs.h8
-rw-r--r--src/3rdparty/freetype/src/truetype/ttpload.c37
-rw-r--r--src/3rdparty/freetype/src/truetype/ttpload.h6
-rw-r--r--src/3rdparty/freetype/src/truetype/ttsubpix.c1013
-rw-r--r--src/3rdparty/freetype/src/truetype/ttsubpix.h110
-rw-r--r--src/3rdparty/freetype/src/type1/t1afm.c4
-rw-r--r--src/3rdparty/freetype/src/type1/t1driver.c93
-rw-r--r--src/3rdparty/freetype/src/type1/t1load.c260
-rw-r--r--src/3rdparty/freetype/src/type1/t1load.h22
-rw-r--r--src/3rdparty/freetype/src/type1/t1objs.c8
-rw-r--r--src/3rdparty/freetype/src/type42/t42drivr.c43
-rw-r--r--src/3rdparty/freetype/src/type42/t42parse.c94
-rw-r--r--src/3rdparty/freetype/src/winfonts/winfnt.c40
-rw-r--r--src/3rdparty/gradle/gradle.properties3
-rw-r--r--src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.jarbin59821 -> 63721 bytes
-rw-r--r--src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties4
-rwxr-xr-xsrc/3rdparty/gradle/gradlew31
-rw-r--r--src/3rdparty/gradle/gradlew.bat15
-rw-r--r--src/3rdparty/gradle/qt_attribution.json4
-rw-r--r--src/3rdparty/harfbuzz-ng/CMakeLists.txt2
-rw-r--r--src/3rdparty/harfbuzz-ng/NEWS3217
-rw-r--r--src/3rdparty/harfbuzz-ng/README.md21
-rw-r--r--src/3rdparty/harfbuzz-ng/import_from_tarball.sh43
-rw-r--r--src/3rdparty/harfbuzz-ng/qt_attribution.json38
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Color/CBDT/CBDT.hh17
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh502
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh48
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Color/sbix/sbix.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Color/svg/svg.hh1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh27
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat1.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat2.hh19
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/RangeRecord.hh12
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh253
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Anchor.hh1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorFormat3.hh38
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh20
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Common.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh48
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/GPOS.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/LigatureArray.hh13
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkArray.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkBasePosFormat1.hh15
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkLigPosFormat1.hh33
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh19
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkRecord.hh11
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh48
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh92
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh17
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairValueRecord.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePos.hh12
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat1.hh40
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat2.hh43
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh143
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Common.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh7
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSet.hh73
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh9
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Sequence.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubst.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat1.hh38
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat2.hh25
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh120
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh318
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh45
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/glyf/SubsetGlyph.hh81
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/glyf/VarCompositeGlyph.hh269
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/glyf/coord-setter.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh67
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh120
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/glyf/path-builder.hh62
-rw-r--r--src/3rdparty/harfbuzz-ng/src/OT/name/name.hh24
-rw-r--r--src/3rdparty/harfbuzz-ng/src/graph/classdef-graph.hh91
-rw-r--r--src/3rdparty/harfbuzz-ng/src/graph/coverage-graph.hh13
-rw-r--r--src/3rdparty/harfbuzz-ng/src/graph/graph.hh379
-rw-r--r--src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-context.cc6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-context.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-graph.hh41
-rw-r--r--src/3rdparty/harfbuzz-ng/src/graph/markbasepos-graph.hh16
-rw-r--r--src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh25
-rw-r--r--src/3rdparty/harfbuzz-ng/src/graph/serialize.hh7
-rw-r--r--src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc225
-rw-r--r--src/3rdparty/harfbuzz-ng/src/harfbuzz-subset.cc1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/harfbuzz.cc2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-ankr-table.hh1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-bsln-table.hh1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh84
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-feat-table.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-just-table.hh3
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh25
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh42
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-opbd-table.hh1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout-trak-table.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout.cc8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-layout.h4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-aat-ltag-table.hh5
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-algs.hh283
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-array.hh66
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-atomic.hh11
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-bimap.hh82
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-bit-page.hh40
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh17
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh46
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-blob.cc21
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-blob.h2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-json.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-text-unicode.hh10
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc80
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-buffer.cc61
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-buffer.h8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-buffer.hh18
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-cache.hh22
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-cairo-utils.cc35
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-cairo.cc29
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-cff-interp-common.hh4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-cff-interp-cs-common.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-cff-interp-dict-common.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-common.cc5
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-common.h25
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-config.hh43
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-cplusplus.hh16
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-debug.hh27
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-deprecated.h68
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-draw.hh30
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-face.cc8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-face.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-features.h119
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-font.cc87
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-font.h50
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-font.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ft-colr.hh40
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ft.cc24
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-gobject-structs.cc2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc42
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-icu.cc13
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-iter.hh9
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-kern.hh4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-limits.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-machinery.hh11
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-map.cc6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-map.h2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-map.hh254
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-meta.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-multimap.hh34
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-null.hh10
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-number-parser.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-object.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-open-file.hh10
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-open-type.hh104
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh313
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.cc6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh364
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh102
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh167
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-face-table-list.hh1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc80
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-hdmx-table.hh55
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-head-table.hh21
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-hhea-table.hh4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh108
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-kern-table.hh9
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh307
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh838
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh652
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh1
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc260
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout.h37
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh14
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc30
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-map.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh49
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-math.cc2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-maxp-table.hh5
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-meta-table.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-metrics.cc2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-name.cc2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh56
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-post-table-v2subset.hh12
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh39
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape-normalize.cc15
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc37
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic-fallback.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic-joining-list.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic-table.hh8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic.cc39
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-machine.hh14
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-table.cc12
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic.cc5
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-khmer-machine.hh14
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-syllabic.cc12
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use-machine.hh1325
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use-table.hh964
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use.cc3
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-vowel-constraints.cc4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh64
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-tag-table.hh41
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh171
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh2186
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-cvar-table.hh220
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-fvar-table.hh119
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh900
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh185
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-var-mvar-table.hh62
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ot-vorg-table.hh3
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-outline.cc5
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-outline.hh2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-paint.cc25
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-paint.h44
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-paint.hh16
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-pool.hh13
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh43
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-repacker.hh72
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-sanitize.hh120
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-serialize.hh102
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh24
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-set.cc24
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-set.h2
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-set.hh14
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-shape.cc246
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-shape.h12
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-shaper-list.hh7
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-static.cc27
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-style.cc4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-accelerator.hh53
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.cc29
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh112
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc343
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc147
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc172
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-input.hh4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.cc532
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.hh37
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc230
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.hh112
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-plan-member-list.hh158
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc621
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh221
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset.cc195
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-subset.h34
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-ucd-table.hh3450
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-unicode-emoji-table.hh6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-unicode.h4
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-uniscribe.cc6
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-vector.hh155
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-version.h8
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-wasm-api-blob.hh50
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-wasm-api-buffer.hh217
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-wasm-api-common.hh (renamed from src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.hh)27
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-wasm-api-face.hh109
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-wasm-api-font.hh263
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-wasm-api-shape.hh70
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-wasm-api.cc (renamed from src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.hh)29
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-wasm-api.h319
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-wasm-api.hh117
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc470
-rw-r--r--src/3rdparty/harfbuzz-ng/src/hb.hh41
-rw-r--r--src/3rdparty/harfbuzz-ng/src/main.cc532
-rw-r--r--src/3rdparty/harfbuzz-ng/src/test.cc95
-rw-r--r--src/3rdparty/iaccessible2/qt_attribution.json8
-rw-r--r--src/3rdparty/icc/qt_attribution.json2
-rw-r--r--src/3rdparty/libjpeg/CMakeLists.txt169
-rw-r--r--src/3rdparty/libjpeg/COPYRIGHT.txt3
-rwxr-xr-xsrc/3rdparty/libjpeg/import_from_libjpeg_tarball.sh57
-rw-r--r--src/3rdparty/libjpeg/qt_attribution.json5
-rw-r--r--src/3rdparty/libjpeg/src/ChangeLog.md286
-rw-r--r--src/3rdparty/libjpeg/src/README.ijg26
-rw-r--r--src/3rdparty/libjpeg/src/README.md84
-rw-r--r--src/3rdparty/libjpeg/src/jcapimin.c27
-rw-r--r--src/3rdparty/libjpeg/src/jcapistd.c53
-rw-r--r--src/3rdparty/libjpeg/src/jccoefct.c47
-rw-r--r--src/3rdparty/libjpeg/src/jccolext.c50
-rw-r--r--src/3rdparty/libjpeg/src/jccolor.c225
-rw-r--r--src/3rdparty/libjpeg/src/jcdctmgr.c94
-rw-r--r--src/3rdparty/libjpeg/src/jcdiffct.c411
-rw-r--r--src/3rdparty/libjpeg/src/jchuff.c201
-rw-r--r--src/3rdparty/libjpeg/src/jchuff.h6
-rw-r--r--src/3rdparty/libjpeg/src/jcicc.c105
-rw-r--r--src/3rdparty/libjpeg/src/jcinit.c111
-rw-r--r--src/3rdparty/libjpeg/src/jclhuff.c587
-rw-r--r--src/3rdparty/libjpeg/src/jclossls.c319
-rw-r--r--src/3rdparty/libjpeg/src/jcmainct.c45
-rw-r--r--src/3rdparty/libjpeg/src/jcmarker.c36
-rw-r--r--src/3rdparty/libjpeg/src/jcmaster.c193
-rw-r--r--src/3rdparty/libjpeg/src/jcmaster.h43
-rw-r--r--src/3rdparty/libjpeg/src/jconfig.h9
-rw-r--r--src/3rdparty/libjpeg/src/jconfig.h.in47
-rw-r--r--src/3rdparty/libjpeg/src/jconfigint.h34
-rw-r--r--src/3rdparty/libjpeg/src/jconfigint.h.in32
-rw-r--r--src/3rdparty/libjpeg/src/jcparam.c52
-rw-r--r--src/3rdparty/libjpeg/src/jcphuff.c53
-rw-r--r--src/3rdparty/libjpeg/src/jcprepct.c88
-rw-r--r--src/3rdparty/libjpeg/src/jcsample.c103
-rw-r--r--src/3rdparty/libjpeg/src/jctrans.c16
-rw-r--r--src/3rdparty/libjpeg/src/jdapimin.c20
-rw-r--r--src/3rdparty/libjpeg/src/jdapistd.c149
-rw-r--r--src/3rdparty/libjpeg/src/jdatadst.c10
-rw-r--r--src/3rdparty/libjpeg/src/jdatasrc.c6
-rw-r--r--src/3rdparty/libjpeg/src/jdcoefct.c75
-rw-r--r--src/3rdparty/libjpeg/src/jdcoefct.h5
-rw-r--r--src/3rdparty/libjpeg/src/jdcol565.c62
-rw-r--r--src/3rdparty/libjpeg/src/jdcolext.c48
-rw-r--r--src/3rdparty/libjpeg/src/jdcolor.c192
-rw-r--r--src/3rdparty/libjpeg/src/jdct.h135
-rw-r--r--src/3rdparty/libjpeg/src/jddctmgr.c61
-rw-r--r--src/3rdparty/libjpeg/src/jddiffct.c403
-rw-r--r--src/3rdparty/libjpeg/src/jdhuff.c20
-rw-r--r--src/3rdparty/libjpeg/src/jdhuff.h7
-rw-r--r--src/3rdparty/libjpeg/src/jdicc.c167
-rw-r--r--src/3rdparty/libjpeg/src/jdinput.c63
-rw-r--r--src/3rdparty/libjpeg/src/jdlhuff.c302
-rw-r--r--src/3rdparty/libjpeg/src/jdlossls.c289
-rw-r--r--src/3rdparty/libjpeg/src/jdmainct.c111
-rw-r--r--src/3rdparty/libjpeg/src/jdmainct.h15
-rw-r--r--src/3rdparty/libjpeg/src/jdmarker.c26
-rw-r--r--src/3rdparty/libjpeg/src/jdmaster.c635
-rw-r--r--src/3rdparty/libjpeg/src/jdmerge.c71
-rw-r--r--src/3rdparty/libjpeg/src/jdmerge.h9
-rw-r--r--src/3rdparty/libjpeg/src/jdmrg565.c43
-rw-r--r--src/3rdparty/libjpeg/src/jdmrgext.c40
-rw-r--r--src/3rdparty/libjpeg/src/jdphuff.c4
-rw-r--r--src/3rdparty/libjpeg/src/jdpostct.c109
-rw-r--r--src/3rdparty/libjpeg/src/jdsample.c128
-rw-r--r--src/3rdparty/libjpeg/src/jdsample.h9
-rw-r--r--src/3rdparty/libjpeg/src/jdtrans.c12
-rw-r--r--src/3rdparty/libjpeg/src/jerror.h17
-rw-r--r--src/3rdparty/libjpeg/src/jfdctfst.c2
-rw-r--r--src/3rdparty/libjpeg/src/jfdctint.c4
-rw-r--r--src/3rdparty/libjpeg/src/jidctflt.c14
-rw-r--r--src/3rdparty/libjpeg/src/jidctfst.c18
-rw-r--r--src/3rdparty/libjpeg/src/jidctint.c136
-rw-r--r--src/3rdparty/libjpeg/src/jidctred.c38
-rw-r--r--src/3rdparty/libjpeg/src/jinclude.h4
-rw-r--r--src/3rdparty/libjpeg/src/jlossls.h101
-rw-r--r--src/3rdparty/libjpeg/src/jmemmgr.c181
-rw-r--r--src/3rdparty/libjpeg/src/jmemsys.h31
-rw-r--r--src/3rdparty/libjpeg/src/jmorecfg.h39
-rw-r--r--src/3rdparty/libjpeg/src/jpeg_nbits.c (renamed from src/3rdparty/libjpeg/src/jpeg_nbits_table.h)38
-rw-r--r--src/3rdparty/libjpeg/src/jpeg_nbits.h43
-rw-r--r--src/3rdparty/libjpeg/src/jpegapicomp.h (renamed from src/3rdparty/libjpeg/src/jpegcomp.h)2
-rw-r--r--src/3rdparty/libjpeg/src/jpegint.h226
-rw-r--r--src/3rdparty/libjpeg/src/jpeglib.h153
-rw-r--r--src/3rdparty/libjpeg/src/jquant1.c164
-rw-r--r--src/3rdparty/libjpeg/src/jquant2.c130
-rw-r--r--src/3rdparty/libjpeg/src/jsamplecomp.h336
-rw-r--r--src/3rdparty/libjpeg/src/jsimd.h4
-rw-r--r--src/3rdparty/libjpeg/src/jsimd_none.c431
-rw-r--r--src/3rdparty/libjpeg/src/jutils.c25
-rw-r--r--src/3rdparty/libjpeg/src/jversion.h7
-rw-r--r--src/3rdparty/libpng/ANNOUNCE49
-rw-r--r--src/3rdparty/libpng/CHANGES87
-rw-r--r--src/3rdparty/libpng/LICENSE4
-rw-r--r--src/3rdparty/libpng/README172
-rwxr-xr-xsrc/3rdparty/libpng/import_from_libpng_tarball.sh41
-rw-r--r--src/3rdparty/libpng/libpng-manual.txt147
-rw-r--r--src/3rdparty/libpng/png.c110
-rw-r--r--src/3rdparty/libpng/png.h61
-rw-r--r--src/3rdparty/libpng/pngconf.h4
-rw-r--r--src/3rdparty/libpng/pngerror.c34
-rw-r--r--src/3rdparty/libpng/pngget.c254
-rw-r--r--src/3rdparty/libpng/pnglibconf.h9
-rw-r--r--src/3rdparty/libpng/pngpread.c16
-rw-r--r--src/3rdparty/libpng/pngpriv.h122
-rw-r--r--src/3rdparty/libpng/pngread.c12
-rw-r--r--src/3rdparty/libpng/pngrtran.c34
-rw-r--r--src/3rdparty/libpng/pngrutil.c19
-rw-r--r--src/3rdparty/libpng/pngset.c80
-rw-r--r--src/3rdparty/libpng/pngtrans.c14
-rw-r--r--src/3rdparty/libpng/pngwrite.c27
-rw-r--r--src/3rdparty/libpng/pngwutil.c10
-rw-r--r--src/3rdparty/libpng/qt_attribution.json49
-rw-r--r--src/3rdparty/libpsl/psl_data.cpp8851
-rw-r--r--src/3rdparty/libpsl/qt_attribution.json13
-rw-r--r--src/3rdparty/md4/qt_attribution.json2
-rw-r--r--src/3rdparty/md4c/0001-md4c-Fix-MSVC-compiler-level-3-warnings.patch40
-rw-r--r--src/3rdparty/md4c/LICENSE.md2
-rw-r--r--src/3rdparty/md4c/md4c.c1480
-rw-r--r--src/3rdparty/md4c/md4c.h4
-rw-r--r--src/3rdparty/md4c/qt_attribution.json7
-rw-r--r--src/3rdparty/md5/qt_attribution.json5
-rw-r--r--src/3rdparty/pcre2/AUTHORS6
-rw-r--r--src/3rdparty/pcre2/CMakeLists.txt1
-rw-r--r--src/3rdparty/pcre2/LICENCE6
-rwxr-xr-xsrc/3rdparty/pcre2/import_from_pcre2_tarball.sh56
-rw-r--r--src/3rdparty/pcre2/qt_attribution.json15
-rw-r--r--src/3rdparty/pcre2/src/config.h8
-rw-r--r--src/3rdparty/pcre2/src/pcre2.h30
-rw-r--r--src/3rdparty/pcre2/src/pcre2_auto_possess.c16
-rw-r--r--src/3rdparty/pcre2/src/pcre2_chartables.c12
-rw-r--r--src/3rdparty/pcre2/src/pcre2_chkdint.c96
-rw-r--r--src/3rdparty/pcre2/src/pcre2_compile.c1279
-rw-r--r--src/3rdparty/pcre2/src/pcre2_context.c46
-rw-r--r--src/3rdparty/pcre2/src/pcre2_dfa_match.c167
-rw-r--r--src/3rdparty/pcre2/src/pcre2_error.c9
-rw-r--r--src/3rdparty/pcre2/src/pcre2_find_bracket.c10
-rw-r--r--src/3rdparty/pcre2/src/pcre2_internal.h155
-rw-r--r--src/3rdparty/pcre2/src/pcre2_intmodedep.h57
-rw-r--r--src/3rdparty/pcre2/src/pcre2_jit_compile.c1281
-rw-r--r--src/3rdparty/pcre2/src/pcre2_jit_match.c16
-rw-r--r--src/3rdparty/pcre2/src/pcre2_jit_neon_inc.h53
-rw-r--r--src/3rdparty/pcre2/src/pcre2_jit_simd_inc.h1061
-rw-r--r--src/3rdparty/pcre2/src/pcre2_maketables.c8
-rw-r--r--src/3rdparty/pcre2/src/pcre2_match.c469
-rw-r--r--src/3rdparty/pcre2/src/pcre2_match_data.c12
-rw-r--r--src/3rdparty/pcre2/src/pcre2_study.c104
-rw-r--r--src/3rdparty/pcre2/src/pcre2_substring.c7
-rw-r--r--src/3rdparty/pcre2/src/pcre2_ucd.c5584
-rw-r--r--src/3rdparty/pcre2/src/pcre2_ucp.h48
-rw-r--r--src/3rdparty/pcre2/src/pcre2_ucptables.c529
-rw-r--r--src/3rdparty/pcre2/src/pcre2_valid_utf.c48
-rw-r--r--src/3rdparty/pcre2/src/pcre2_xclass.c53
-rw-r--r--src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorApple.c133
-rw-r--r--src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorCore.c330
-rw-r--r--src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorFreeBSD.c89
-rw-r--r--src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorPosix.c62
-rw-r--r--src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorWindows.c40
-rw-r--r--src/3rdparty/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorNetBSD.c72
-rw-r--r--src/3rdparty/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorPosix.c172
-rw-r--r--src/3rdparty/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorPosix.c141
-rw-r--r--src/3rdparty/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorWindows.c102
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitConfig.h26
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitConfigCPU.h188
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitConfigInternal.h338
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitLir.c1628
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitLir.h936
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeARM_32.c1941
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeARM_64.c1283
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeARM_T2_32.c1303
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_32.c172
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_64.c78
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_common.c1177
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativePPC_32.c153
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativePPC_64.c152
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativePPC_common.c753
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeRISCV_32.c71
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeRISCV_64.c43
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeRISCV_common.c603
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeS390X.c1246
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeX86_32.c465
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeX86_64.c446
-rw-r--r--src/3rdparty/pcre2/src/sljit/sljitNativeX86_common.c3117
-rw-r--r--src/3rdparty/rfc6234/qt_attribution.json2
-rw-r--r--src/3rdparty/sha1/qt_attribution.json6
-rw-r--r--src/3rdparty/sha1/sha1.cpp50
-rw-r--r--src/3rdparty/sha3/brg_endian.h2
-rw-r--r--src/3rdparty/sha3/brg_endian.h.patch19
-rw-r--r--src/3rdparty/sha3/qt_attribution.json23
-rw-r--r--src/3rdparty/sqlite/qt_attribution.json9
-rw-r--r--src/3rdparty/sqlite/sqlite3.c22840
-rw-r--r--src/3rdparty/sqlite/sqlite3.h650
-rw-r--r--src/3rdparty/tinycbor/0001-tst_Encoder-port-away-from-Q_FOREACH.patch79
-rw-r--r--src/3rdparty/tinycbor/qt_attribution.json1
-rw-r--r--src/3rdparty/tinycbor/src/cborparser.c2
-rw-r--r--src/3rdparty/tinycbor/tests/encoder/data.cpp61
-rw-r--r--src/3rdparty/tinycbor/tests/encoder/tst_encoder.cpp15
-rw-r--r--src/3rdparty/tinycbor/tests/parser/data.cpp3
-rw-r--r--src/3rdparty/wasm/VERA-LICENSE15
-rw-r--r--src/3rdparty/wasm/Vera.ttfbin65932 -> 0 bytes
-rw-r--r--src/3rdparty/wasm/qt_attribution.json21
-rw-r--r--src/3rdparty/xcb/qt_attribution.json4
-rwxr-xr-xsrc/3rdparty/zlib/import_from_zlib_tarball.sh63
-rw-r--r--src/3rdparty/zlib/qt_attribution.json6
-rw-r--r--src/3rdparty/zlib/qtpatches.diff106
-rw-r--r--src/3rdparty/zlib/src/ChangeLog32
-rw-r--r--src/3rdparty/zlib/src/README19
-rw-r--r--src/3rdparty/zlib/src/adler32.c32
-rw-r--r--src/3rdparty/zlib/src/compress.c21
-rw-r--r--src/3rdparty/zlib/src/crc32.c248
-rw-r--r--src/3rdparty/zlib/src/deflate.c612
-rw-r--r--src/3rdparty/zlib/src/deflate.h51
-rw-r--r--src/3rdparty/zlib/src/gzclose.c4
-rw-r--r--src/3rdparty/zlib/src/gzguts.h31
-rw-r--r--src/3rdparty/zlib/src/gzlib.c113
-rw-r--r--src/3rdparty/zlib/src/gzread.c88
-rw-r--r--src/3rdparty/zlib/src/gzwrite.c84
-rw-r--r--src/3rdparty/zlib/src/infback.c30
-rw-r--r--src/3rdparty/zlib/src/inffast.c5
-rw-r--r--src/3rdparty/zlib/src/inffast.h2
-rw-r--r--src/3rdparty/zlib/src/inflate.c131
-rw-r--r--src/3rdparty/zlib/src/inftrees.c17
-rw-r--r--src/3rdparty/zlib/src/inftrees.h10
-rw-r--r--src/3rdparty/zlib/src/trees.c542
-rw-r--r--src/3rdparty/zlib/src/uncompr.c16
-rw-r--r--src/3rdparty/zlib/src/zconf.h18
-rw-r--r--src/3rdparty/zlib/src/zlib.h391
-rw-r--r--src/3rdparty/zlib/src/zutil.c60
-rw-r--r--src/3rdparty/zlib/src/zutil.h52
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/android/jar/CMakeLists.txt32
-rw-r--r--src/android/jar/build.gradle7
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/CursorHandle.java80
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/EditContextView.java62
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/EditPopupMenu.java44
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/ExtractStyle.java61
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java (renamed from src/android/jar/src/org/qtproject/qt/android/accessibility/QtAccessibilityDelegate.java)230
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtActivityBase.java325
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java1521
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java267
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtActivityLoader.java151
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtApplicationBase.java15
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtClipboardManager.java232
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtDisplayManager.java287
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtEditText.java207
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegate.java178
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegateFactory.java37
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtEmbeddedLoader.java53
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtEmbeddedViewInterface.java15
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtInputConnection.java128
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java654
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtLayout.java139
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtLoader.java558
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtMessageDialogHelper.java366
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtNative.java1209
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtNativeAccessibility.java (renamed from src/android/jar/src/org/qtproject/qt/android/accessibility/QtNativeAccessibility.java)3
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtNativeLibrariesDir.java24
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtRootLayout.java98
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtServiceBase.java51
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtServiceDelegate.java164
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java115
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtServiceLoader.java28
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtSurface.java59
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtSurfaceInterface.java13
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtTextureView.java52
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtThread.java25
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtView.java190
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtWindow.java215
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/UsedFromNativeCode.java10
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/extras/QtAndroidBinder.java5
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/extras/QtAndroidServiceConnection.java5
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/extras/QtNative.java4
-rw-r--r--src/android/java/CMakeLists.txt15
-rw-r--r--src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java1127
-rw-r--r--src/android/java/src/org/qtproject/qt/android/bindings/QtActivityLoader.java117
-rw-r--r--src/android/java/src/org/qtproject/qt/android/bindings/QtApplication.java121
-rw-r--r--src/android/java/src/org/qtproject/qt/android/bindings/QtLoader.java386
-rw-r--r--src/android/java/src/org/qtproject/qt/android/bindings/QtService.java138
-rw-r--r--src/android/java/src/org/qtproject/qt/android/bindings/QtServiceLoader.java48
-rw-r--r--src/android/templates/AndroidManifest.xml6
-rw-r--r--src/android/templates/build.gradle4
-rw-r--r--src/android/templates/doc/src/android-manifest-file-configuration.qdoc26
-rw-r--r--src/assets/CMakeLists.txt1
-rw-r--r--src/assets/icons/128x128/document-new.pngbin0 -> 1258 bytes
-rw-r--r--src/assets/icons/128x128/document-open.pngbin0 -> 1855 bytes
-rw-r--r--src/assets/icons/128x128/document-print.pngbin0 -> 1576 bytes
-rw-r--r--src/assets/icons/128x128/document-save.pngbin0 -> 1298 bytes
-rw-r--r--src/assets/icons/128x128/edit-copy.pngbin0 -> 1480 bytes
-rw-r--r--src/assets/icons/128x128/edit-cut.pngbin0 -> 2012 bytes
-rw-r--r--src/assets/icons/128x128/edit-delete.pngbin0 -> 2665 bytes
-rw-r--r--src/assets/icons/128x128/edit-paste.pngbin0 -> 1892 bytes
-rw-r--r--src/assets/icons/128x128/edit-redo.pngbin0 -> 1239 bytes
-rw-r--r--src/assets/icons/128x128/edit-undo.pngbin0 -> 1233 bytes
-rw-r--r--src/assets/icons/128x128/format-justify-center.pngbin0 -> 663 bytes
-rw-r--r--src/assets/icons/128x128/format-justify-fill.pngbin0 -> 506 bytes
-rw-r--r--src/assets/icons/128x128/format-justify-left.pngbin0 -> 603 bytes
-rw-r--r--src/assets/icons/128x128/format-justify-right.pngbin0 -> 634 bytes
-rw-r--r--src/assets/icons/128x128/format-text-bold.pngbin0 -> 1459 bytes
-rw-r--r--src/assets/icons/128x128/format-text-italic.pngbin0 -> 1158 bytes
-rw-r--r--src/assets/icons/128x128/format-text-underline.pngbin0 -> 1263 bytes
-rw-r--r--src/assets/icons/128x128@2/document-new@2x.pngbin0 -> 2541 bytes
-rw-r--r--src/assets/icons/128x128@2/document-open@2x.pngbin0 -> 3865 bytes
-rw-r--r--src/assets/icons/128x128@2/document-print@2x.pngbin0 -> 3721 bytes
-rw-r--r--src/assets/icons/128x128@2/document-save@2x.pngbin0 -> 2682 bytes
-rw-r--r--src/assets/icons/128x128@2/edit-copy@2x.pngbin0 -> 3467 bytes
-rw-r--r--src/assets/icons/128x128@2/edit-cut@2x.pngbin0 -> 5004 bytes
-rw-r--r--src/assets/icons/128x128@2/edit-delete@2x.pngbin0 -> 5870 bytes
-rw-r--r--src/assets/icons/128x128@2/edit-paste@2x.pngbin0 -> 4005 bytes
-rw-r--r--src/assets/icons/128x128@2/edit-redo@2x.pngbin0 -> 2528 bytes
-rw-r--r--src/assets/icons/128x128@2/edit-undo@2x.pngbin0 -> 2530 bytes
-rw-r--r--src/assets/icons/128x128@2/format-justify-center@2x.pngbin0 -> 1599 bytes
-rw-r--r--src/assets/icons/128x128@2/format-justify-fill@2x.pngbin0 -> 1475 bytes
-rw-r--r--src/assets/icons/128x128@2/format-justify-left@2x.pngbin0 -> 1539 bytes
-rw-r--r--src/assets/icons/128x128@2/format-justify-right@2x.pngbin0 -> 1557 bytes
-rw-r--r--src/assets/icons/128x128@2/format-text-bold@2x.pngbin0 -> 3092 bytes
-rw-r--r--src/assets/icons/128x128@2/format-text-italic@2x.pngbin0 -> 2374 bytes
-rw-r--r--src/assets/icons/128x128@2/format-text-underline@2x.pngbin0 -> 2477 bytes
-rw-r--r--src/assets/icons/16x16/document-new.pngbin0 -> 241 bytes
-rw-r--r--src/assets/icons/16x16/document-open.pngbin0 -> 286 bytes
-rw-r--r--src/assets/icons/16x16/document-print.pngbin0 -> 261 bytes
-rw-r--r--src/assets/icons/16x16/document-save.pngbin0 -> 224 bytes
-rw-r--r--src/assets/icons/16x16/edit-copy.pngbin0 -> 216 bytes
-rw-r--r--src/assets/icons/16x16/edit-cut.pngbin0 -> 267 bytes
-rw-r--r--src/assets/icons/16x16/edit-delete.pngbin0 -> 250 bytes
-rw-r--r--src/assets/icons/16x16/edit-paste.pngbin0 -> 272 bytes
-rw-r--r--src/assets/icons/16x16/edit-redo.pngbin0 -> 253 bytes
-rw-r--r--src/assets/icons/16x16/edit-undo.pngbin0 -> 253 bytes
-rw-r--r--src/assets/icons/16x16/format-justify-center.pngbin0 -> 134 bytes
-rw-r--r--src/assets/icons/16x16/format-justify-fill.pngbin0 -> 122 bytes
-rw-r--r--src/assets/icons/16x16/format-justify-left.pngbin0 -> 128 bytes
-rw-r--r--src/assets/icons/16x16/format-justify-right.pngbin0 -> 134 bytes
-rw-r--r--src/assets/icons/16x16/format-text-bold.pngbin0 -> 264 bytes
-rw-r--r--src/assets/icons/16x16/format-text-italic.pngbin0 -> 255 bytes
-rw-r--r--src/assets/icons/16x16/format-text-underline.pngbin0 -> 186 bytes
-rw-r--r--src/assets/icons/16x16@2/document-new@2x.pngbin0 -> 318 bytes
-rw-r--r--src/assets/icons/16x16@2/document-open@2x.pngbin0 -> 455 bytes
-rw-r--r--src/assets/icons/16x16@2/document-print@2x.pngbin0 -> 393 bytes
-rw-r--r--src/assets/icons/16x16@2/document-save@2x.pngbin0 -> 311 bytes
-rw-r--r--src/assets/icons/16x16@2/edit-copy@2x.pngbin0 -> 333 bytes
-rw-r--r--src/assets/icons/16x16@2/edit-cut@2x.pngbin0 -> 416 bytes
-rw-r--r--src/assets/icons/16x16@2/edit-delete@2x.pngbin0 -> 495 bytes
-rw-r--r--src/assets/icons/16x16@2/edit-paste@2x.pngbin0 -> 464 bytes
-rw-r--r--src/assets/icons/16x16@2/edit-redo@2x.pngbin0 -> 346 bytes
-rw-r--r--src/assets/icons/16x16@2/edit-undo@2x.pngbin0 -> 347 bytes
-rw-r--r--src/assets/icons/16x16@2/format-justify-center@2x.pngbin0 -> 179 bytes
-rw-r--r--src/assets/icons/16x16@2/format-justify-fill@2x.pngbin0 -> 156 bytes
-rw-r--r--src/assets/icons/16x16@2/format-justify-left@2x.pngbin0 -> 171 bytes
-rw-r--r--src/assets/icons/16x16@2/format-justify-right@2x.pngbin0 -> 173 bytes
-rw-r--r--src/assets/icons/16x16@2/format-text-bold@2x.pngbin0 -> 430 bytes
-rw-r--r--src/assets/icons/16x16@2/format-text-italic@2x.pngbin0 -> 391 bytes
-rw-r--r--src/assets/icons/16x16@2/format-text-underline@2x.pngbin0 -> 290 bytes
-rw-r--r--src/assets/icons/256x256/document-new.pngbin0 -> 2541 bytes
-rw-r--r--src/assets/icons/256x256/document-open.pngbin0 -> 3865 bytes
-rw-r--r--src/assets/icons/256x256/document-print.pngbin0 -> 3721 bytes
-rw-r--r--src/assets/icons/256x256/document-save.pngbin0 -> 2682 bytes
-rw-r--r--src/assets/icons/256x256/edit-copy.pngbin0 -> 3467 bytes
-rw-r--r--src/assets/icons/256x256/edit-cut.pngbin0 -> 5004 bytes
-rw-r--r--src/assets/icons/256x256/edit-delete.pngbin0 -> 5870 bytes
-rw-r--r--src/assets/icons/256x256/edit-paste.pngbin0 -> 4005 bytes
-rw-r--r--src/assets/icons/256x256/edit-redo.pngbin0 -> 2528 bytes
-rw-r--r--src/assets/icons/256x256/edit-undo.pngbin0 -> 2530 bytes
-rw-r--r--src/assets/icons/256x256/format-justify-center.pngbin0 -> 1599 bytes
-rw-r--r--src/assets/icons/256x256/format-justify-fill.pngbin0 -> 1475 bytes
-rw-r--r--src/assets/icons/256x256/format-justify-left.pngbin0 -> 1539 bytes
-rw-r--r--src/assets/icons/256x256/format-justify-right.pngbin0 -> 1557 bytes
-rw-r--r--src/assets/icons/256x256/format-text-bold.pngbin0 -> 3092 bytes
-rw-r--r--src/assets/icons/256x256/format-text-italic.pngbin0 -> 2374 bytes
-rw-r--r--src/assets/icons/256x256/format-text-underline.pngbin0 -> 2477 bytes
-rw-r--r--src/assets/icons/256x256@2/document-new@2x.pngbin0 -> 5683 bytes
-rw-r--r--src/assets/icons/256x256@2/document-open@2x.pngbin0 -> 8174 bytes
-rw-r--r--src/assets/icons/256x256@2/document-print@2x.pngbin0 -> 8055 bytes
-rw-r--r--src/assets/icons/256x256@2/document-save@2x.pngbin0 -> 5666 bytes
-rw-r--r--src/assets/icons/256x256@2/edit-copy@2x.pngbin0 -> 7329 bytes
-rw-r--r--src/assets/icons/256x256@2/edit-cut@2x.pngbin0 -> 11388 bytes
-rw-r--r--src/assets/icons/256x256@2/edit-delete@2x.pngbin0 -> 12743 bytes
-rw-r--r--src/assets/icons/256x256@2/edit-paste@2x.pngbin0 -> 8485 bytes
-rw-r--r--src/assets/icons/256x256@2/edit-redo@2x.pngbin0 -> 5378 bytes
-rw-r--r--src/assets/icons/256x256@2/edit-undo@2x.pngbin0 -> 5433 bytes
-rw-r--r--src/assets/icons/256x256@2/format-justify-center@2x.pngbin0 -> 3855 bytes
-rw-r--r--src/assets/icons/256x256@2/format-justify-fill@2x.pngbin0 -> 3681 bytes
-rw-r--r--src/assets/icons/256x256@2/format-justify-left@2x.pngbin0 -> 3775 bytes
-rw-r--r--src/assets/icons/256x256@2/format-justify-right@2x.pngbin0 -> 3756 bytes
-rw-r--r--src/assets/icons/256x256@2/format-text-bold@2x.pngbin0 -> 7046 bytes
-rw-r--r--src/assets/icons/256x256@2/format-text-italic@2x.pngbin0 -> 6224 bytes
-rw-r--r--src/assets/icons/256x256@2/format-text-underline@2x.pngbin0 -> 5168 bytes
-rw-r--r--src/assets/icons/32x32/document-new.pngbin0 -> 318 bytes
-rw-r--r--src/assets/icons/32x32/document-open.pngbin0 -> 455 bytes
-rw-r--r--src/assets/icons/32x32/document-print.pngbin0 -> 393 bytes
-rw-r--r--src/assets/icons/32x32/document-save.pngbin0 -> 311 bytes
-rw-r--r--src/assets/icons/32x32/edit-copy.pngbin0 -> 333 bytes
-rw-r--r--src/assets/icons/32x32/edit-cut.pngbin0 -> 416 bytes
-rw-r--r--src/assets/icons/32x32/edit-delete.pngbin0 -> 495 bytes
-rw-r--r--src/assets/icons/32x32/edit-paste.pngbin0 -> 464 bytes
-rw-r--r--src/assets/icons/32x32/edit-redo.pngbin0 -> 346 bytes
-rw-r--r--src/assets/icons/32x32/edit-undo.pngbin0 -> 347 bytes
-rw-r--r--src/assets/icons/32x32/format-justify-center.pngbin0 -> 179 bytes
-rw-r--r--src/assets/icons/32x32/format-justify-fill.pngbin0 -> 156 bytes
-rw-r--r--src/assets/icons/32x32/format-justify-left.pngbin0 -> 171 bytes
-rw-r--r--src/assets/icons/32x32/format-justify-right.pngbin0 -> 173 bytes
-rw-r--r--src/assets/icons/32x32/format-text-bold.pngbin0 -> 430 bytes
-rw-r--r--src/assets/icons/32x32/format-text-italic.pngbin0 -> 391 bytes
-rw-r--r--src/assets/icons/32x32/format-text-underline.pngbin0 -> 290 bytes
-rw-r--r--src/assets/icons/32x32@2/document-new@2x.pngbin0 -> 588 bytes
-rw-r--r--src/assets/icons/32x32@2/document-open@2x.pngbin0 -> 923 bytes
-rw-r--r--src/assets/icons/32x32@2/document-print@2x.pngbin0 -> 762 bytes
-rw-r--r--src/assets/icons/32x32@2/document-save@2x.pngbin0 -> 565 bytes
-rw-r--r--src/assets/icons/32x32@2/edit-copy@2x.pngbin0 -> 710 bytes
-rw-r--r--src/assets/icons/32x32@2/edit-cut@2x.pngbin0 -> 843 bytes
-rw-r--r--src/assets/icons/32x32@2/edit-delete@2x.pngbin0 -> 954 bytes
-rw-r--r--src/assets/icons/32x32@2/edit-paste@2x.pngbin0 -> 909 bytes
-rw-r--r--src/assets/icons/32x32@2/edit-redo@2x.pngbin0 -> 628 bytes
-rw-r--r--src/assets/icons/32x32@2/edit-undo@2x.pngbin0 -> 608 bytes
-rw-r--r--src/assets/icons/32x32@2/format-justify-center@2x.pngbin0 -> 317 bytes
-rw-r--r--src/assets/icons/32x32@2/format-justify-fill@2x.pngbin0 -> 266 bytes
-rw-r--r--src/assets/icons/32x32@2/format-justify-left@2x.pngbin0 -> 298 bytes
-rw-r--r--src/assets/icons/32x32@2/format-justify-right@2x.pngbin0 -> 305 bytes
-rw-r--r--src/assets/icons/32x32@2/format-text-bold@2x.pngbin0 -> 777 bytes
-rw-r--r--src/assets/icons/32x32@2/format-text-italic@2x.pngbin0 -> 657 bytes
-rw-r--r--src/assets/icons/32x32@2/format-text-underline@2x.pngbin0 -> 577 bytes
-rw-r--r--src/assets/icons/CMakeLists.txt174
-rw-r--r--src/assets/icons/README29
-rw-r--r--src/assets/icons/index.theme46
-rw-r--r--src/assets/icons/scalable/document-new.svg1
-rw-r--r--src/assets/icons/scalable/document-open.svg1
-rw-r--r--src/assets/icons/scalable/document-print.svg1
-rw-r--r--src/assets/icons/scalable/document-save.svg1
-rw-r--r--src/assets/icons/scalable/edit-copy.svg1
-rw-r--r--src/assets/icons/scalable/edit-cut.svg1
-rw-r--r--src/assets/icons/scalable/edit-delete.svg1
-rw-r--r--src/assets/icons/scalable/edit-paste.svg1
-rw-r--r--src/assets/icons/scalable/edit-redo.svg1
-rw-r--r--src/assets/icons/scalable/edit-undo.svg1
-rw-r--r--src/assets/icons/scalable/format-justify-center.svg1
-rw-r--r--src/assets/icons/scalable/format-justify-fill.svg1
-rw-r--r--src/assets/icons/scalable/format-justify-left.svg1
-rw-r--r--src/assets/icons/scalable/format-justify-right.svg1
-rw-r--r--src/assets/icons/scalable/format-text-bold.svg1
-rw-r--r--src/assets/icons/scalable/format-text-italic.svg1
-rw-r--r--src/assets/icons/scalable/format-text-underline.svg1
-rw-r--r--src/concurrent/CMakeLists.txt2
-rw-r--r--src/concurrent/doc/qtconcurrent.qdocconf4
-rw-r--r--src/concurrent/doc/snippets/CMakeLists.txt2
-rw-r--r--src/concurrent/doc/snippets/code/src_concurrent_qtconcurrenttask.cpp2
-rw-r--r--src/concurrent/doc/src/qt6-changes.qdoc2
-rw-r--r--src/concurrent/qtaskbuilder.qdoc2
-rw-r--r--src/concurrent/qtconcurrentiteratekernel.cpp2
-rw-r--r--src/concurrent/qtconcurrentiteratekernel.h8
-rw-r--r--src/concurrent/qtconcurrentreducekernel.h2
-rw-r--r--src/concurrent/qtconcurrentrun.cpp15
-rw-r--r--src/concurrent/qtconcurrentrun.h15
-rw-r--r--src/concurrent/qtconcurrentthreadengine.cpp2
-rw-r--r--src/corelib/CMakeLists.txt318
-rw-r--r--src/corelib/Qt6AndroidMacros.cmake326
-rw-r--r--src/corelib/Qt6CTestMacros.cmake13
-rw-r--r--src/corelib/Qt6CoreConfigExtras.cmake.in20
-rw-r--r--src/corelib/Qt6CoreDeploySupport.cmake98
-rw-r--r--src/corelib/Qt6CoreMacros.cmake877
-rw-r--r--src/corelib/Qt6CoreResourceInit.in.cpp14
-rw-r--r--src/corelib/Qt6WasmMacros.cmake38
-rw-r--r--src/corelib/QtInstallPaths.cmake.in16
-rw-r--r--src/corelib/animation/qabstractanimation.cpp68
-rw-r--r--src/corelib/animation/qabstractanimation_p.h6
-rw-r--r--src/corelib/animation/qpauseanimation.cpp7
-rw-r--r--src/corelib/animation/qpropertyanimation.cpp26
-rw-r--r--src/corelib/animation/qvariantanimation.cpp31
-rw-r--r--src/corelib/animation/qvariantanimation.h2
-rw-r--r--src/corelib/compat/removed_api.cpp584
-rw-r--r--src/corelib/configure.cmake218
-rw-r--r--src/corelib/debug_script.py42
-rw-r--r--src/corelib/doc/include/QtCoreDoc1
-rw-r--r--src/corelib/doc/qtcore.qdocconf10
-rw-r--r--src/corelib/doc/snippets/cmake-macros/deployment.cmake2
-rw-r--r--src/corelib/doc/snippets/cmake-macros/examples.cmake42
-rw-r--r--src/corelib/doc/snippets/cmake-macros/examples.cpp16
-rw-r--r--src/corelib/doc/snippets/code/doc_src_containers.cpp9
-rw-r--r--src/corelib/doc/snippets/code/doc_src_properties.cpp5
-rw-r--r--src/corelib/doc/snippets/code/doc_src_qalgorithms.cpp9
-rw-r--r--src/corelib/doc/snippets/code/doc_src_qiterator.cpp9
-rw-r--r--src/corelib/doc/snippets/code/doc_src_qnamespace.qdoc2
-rw-r--r--src/corelib/doc/snippets/code/doc_src_qplugin.cpp6
-rw-r--r--src/corelib/doc/snippets/code/doc_src_qset.cpp46
-rw-r--r--src/corelib/doc/snippets/code/doc_src_resources.cpp13
-rw-r--r--src/corelib/doc/snippets/code/doc_src_resources.qdoc2
-rw-r--r--src/corelib/doc/snippets/code/qlogging/qlogging.cpp10
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_animation_qpropertyanimation.cpp3
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp69
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_io_qabstractfileengine.cpp47
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_io_qdirlisting.cpp70
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_io_qfile.cpp10
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_io_qfileinfo.cpp61
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_io_qsettings.cpp6
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_io_qstorageinfo.cpp2
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_io_qtextstream.cpp6
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_io_qurl.cpp2
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp10
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qcoreapplication.cpp8
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qdeadlinetimer.cpp12
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qmetatype.cpp10
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qmimedata.cpp2
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp58
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qvariant.cpp7
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_serialization_qcborstream.cpp12
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_serialization_qdatastream.cpp8
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_text_qbytearray.cpp12
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_text_qstaticlatin1stringmatcher.cpp8
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_text_qstringconverter.cpp24
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_thread_qfuture.cpp63
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_thread_qmutexpool.cpp24
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_thread_qsemaphore.cpp6
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_time_qdatetime.cpp8
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_tools_qcommandlineparser.cpp8
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_tools_qhash.cpp84
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_tools_qlist.cpp16
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_tools_qmap.cpp132
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_tools_qmultimap.cpp90
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_tools_qqueue.cpp2
-rw-r--r--src/corelib/doc/snippets/code/src_gui_dialogs_qmessagebox.cpp111
-rw-r--r--src/corelib/doc/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp8
-rw-r--r--src/corelib/doc/snippets/customtype/customtypeexample.cpp90
-rw-r--r--src/corelib/doc/snippets/jni/src_qjniobject.cpp17
-rw-r--r--src/corelib/doc/snippets/qsignalmapper/buttonwidget.cpp2
-rw-r--r--src/corelib/doc/snippets/qstring/main.cpp10
-rw-r--r--src/corelib/doc/snippets/qstring/stringbuilder.cpp10
-rw-r--r--src/corelib/doc/snippets/qstringlist/main.cpp9
-rw-r--r--src/corelib/doc/snippets/resource-system/CMakeLists.txt2
-rw-r--r--src/corelib/doc/snippets/resource-system/application.pro4
-rw-r--r--src/corelib/doc/snippets/resource-system/mainwindow.cpp72
-rw-r--r--src/corelib/doc/snippets/threads/threads.cpp6
-rw-r--r--src/corelib/doc/snippets/timers/analogclock.cpp46
-rw-r--r--src/corelib/doc/snippets/timers/timers.cpp44
-rw-r--r--src/corelib/doc/src/animation.qdoc2
-rw-r--r--src/corelib/doc/src/cbor.qdoc3
-rw-r--r--src/corelib/doc/src/cmake/cmake-configure-variables.qdoc173
-rw-r--r--src/corelib/doc/src/cmake/cmake-deploy-variables.qdoc58
-rw-r--r--src/corelib/doc/src/cmake/cmake-properties.qdoc65
-rw-r--r--src/corelib/doc/src/cmake/cmake-standard-properties.qdoc24
-rw-r--r--src/corelib/doc/src/cmake/policy/qtp0002.qdoc63
-rw-r--r--src/corelib/doc/src/cmake/policy/qtp0003.qdoc46
-rw-r--r--src/corelib/doc/src/cmake/qt_add_executable.qdoc2
-rw-r--r--src/corelib/doc/src/cmake/qt_add_library.qdoc8
-rw-r--r--src/corelib/doc/src/cmake/qt_add_resources.qdoc4
-rw-r--r--src/corelib/doc/src/cmake/qt_deploy_runtime_dependencies.qdoc64
-rw-r--r--src/corelib/doc/src/cmake/qt_deploy_translations.qdoc2
-rw-r--r--src/corelib/doc/src/cmake/qt_extract_metatypes.qdoc14
-rw-r--r--src/corelib/doc/src/cmake/qt_finalize_project.qdoc2
-rw-r--r--src/corelib/doc/src/cmake/qt_finalize_target.qdoc8
-rw-r--r--src/corelib/doc/src/cmake/qt_generate_deploy_app_script.qdoc29
-rw-r--r--src/corelib/doc/src/cmake/qt_import_plugins.qdoc34
-rw-r--r--src/corelib/doc/src/cmake/qt_policy.qdoc3
-rw-r--r--src/corelib/doc/src/cmake/qt_standard_project_setup.qdoc16
-rw-r--r--src/corelib/doc/src/cmake/qt_wrap_cpp.qdoc38
-rw-r--r--src/corelib/doc/src/containers.qdoc11
-rw-r--r--src/corelib/doc/src/custom-types.qdoc31
-rw-r--r--src/corelib/doc/src/datastreamformat.qdoc45
-rw-r--r--src/corelib/doc/src/external-resources.qdoc5
-rw-r--r--src/corelib/doc/src/foreach-keyword.qdoc13
-rw-r--r--src/corelib/doc/src/includes/cmake-android-qt-finalize-project-warning.qdocinc2
-rw-r--r--src/corelib/doc/src/includes/cmake-deploy-modified-variable-values.qdocinc6
-rw-r--r--src/corelib/doc/src/includes/cmake-deploy-runtime-dependencies-deploy-tool-options.qdocinc20
-rw-r--r--src/corelib/doc/src/includes/cmake-deploy-var-usage.qdocinc4
-rw-r--r--src/corelib/doc/src/includes/cmake-generate-deploy-app-script-deploy-tool-options.qdocinc16
-rw-r--r--src/corelib/doc/src/includes/cmake-generate-deploy-app-script.qdocinc21
-rw-r--r--src/corelib/doc/src/includes/models.qdocinc14
-rw-r--r--src/corelib/doc/src/includes/qstring.qdocinc4
-rw-r--r--src/corelib/doc/src/ipc.qdoc12
-rw-r--r--src/corelib/doc/src/json.qdoc6
-rw-r--r--src/corelib/doc/src/objectmodel/bindableproperties.qdoc6
-rw-r--r--src/corelib/doc/src/objectmodel/metaobjects.qdoc2
-rw-r--r--src/corelib/doc/src/objectmodel/properties.qdoc15
-rw-r--r--src/corelib/doc/src/objectmodel/signalsandslots.qdoc8
-rw-r--r--src/corelib/doc/src/qt6-changes.qdoc2
-rw-r--r--src/corelib/doc/src/qtcore-index.qdoc1
-rw-r--r--src/corelib/doc/src/qtserialization.qdoc9
-rw-r--r--src/corelib/doc/src/resource-system.qdoc34
-rw-r--r--src/corelib/doc/src/timers.qdoc112
-rw-r--r--src/corelib/global/minimum-linux_p.h9
-rw-r--r--src/corelib/global/q20algorithm.h6
-rw-r--r--src/corelib/global/q20chrono.h62
-rw-r--r--src/corelib/global/q20iterator.h10
-rw-r--r--src/corelib/global/q20map.h72
-rw-r--r--src/corelib/global/q20memory.h45
-rw-r--r--src/corelib/global/q20type_traits.h38
-rw-r--r--src/corelib/global/q20vector.h90
-rw-r--r--src/corelib/global/qassert.cpp94
-rw-r--r--src/corelib/global/qassert.h9
-rw-r--r--src/corelib/global/qcompare.cpp1357
-rw-r--r--src/corelib/global/qcompare.h863
-rw-r--r--src/corelib/global/qcompare.qdoc113
-rw-r--r--src/corelib/global/qcompare_impl.h11
-rw-r--r--src/corelib/global/qcomparehelpers.h567
-rw-r--r--src/corelib/global/qcompilerdetection.h85
-rw-r--r--src/corelib/global/qcompilerdetection.qdoc35
-rw-r--r--src/corelib/global/qconfig-bootstrapped.h9
-rw-r--r--src/corelib/global/qcontainerinfo.h5
-rw-r--r--src/corelib/global/qdarwinhelpers.h4
-rw-r--r--src/corelib/global/qendian.cpp4
-rw-r--r--src/corelib/global/qendian.h17
-rw-r--r--src/corelib/global/qexceptionhandling.h1
-rw-r--r--src/corelib/global/qflags.h6
-rw-r--r--src/corelib/global/qflags.qdoc4
-rw-r--r--src/corelib/global/qfloat16.cpp22
-rw-r--r--src/corelib/global/qfloat16.h164
-rw-r--r--src/corelib/global/qglobal.cpp114
-rw-r--r--src/corelib/global/qglobal_p.h5
-rw-r--r--src/corelib/global/qglobalstatic.h21
-rw-r--r--src/corelib/global/qlibraryinfo.cpp34
-rw-r--r--src/corelib/global/qlibraryinfo_p.h2
-rw-r--r--src/corelib/global/qlogging.cpp720
-rw-r--r--src/corelib/global/qlogging.h20
-rw-r--r--src/corelib/global/qlogging_p.h48
-rw-r--r--src/corelib/global/qnamespace.h33
-rw-r--r--src/corelib/global/qnamespace.qdoc80
-rw-r--r--src/corelib/global/qnumeric.h4
-rw-r--r--src/corelib/global/qnumeric_p.h125
-rw-r--r--src/corelib/global/qoperatingsystemversion.cpp38
-rw-r--r--src/corelib/global/qoperatingsystemversion.h103
-rw-r--r--src/corelib/global/qrandom.cpp7
-rw-r--r--src/corelib/global/qsimd.cpp14
-rw-r--r--src/corelib/global/qsimd_p.h79
-rw-r--r--src/corelib/global/qsimd_x86.cpp66
-rw-r--r--src/corelib/global/qsimd_x86_p.h218
-rw-r--r--src/corelib/global/qswap.h30
-rw-r--r--src/corelib/global/qswap.qdoc36
-rw-r--r--src/corelib/global/qsysinfo.cpp20
-rw-r--r--src/corelib/global/qsysinfo.h8
-rw-r--r--src/corelib/global/qsystemdetection.h131
-rw-r--r--src/corelib/global/qsystemdetection.qdoc17
-rw-r--r--src/corelib/global/qt_pch.h49
-rw-r--r--src/corelib/global/qtconfigmacros.h58
-rw-r--r--src/corelib/global/qtdeprecationmarkers.h16
-rw-r--r--src/corelib/global/qtenvironmentvariables.cpp6
-rw-r--r--src/corelib/global/qtnoop.h9
-rw-r--r--src/corelib/global/qtsymbolmacros.h65
-rw-r--r--src/corelib/global/qttypetraits.h8
-rw-r--r--src/corelib/global/qttypetraits.qdoc38
-rw-r--r--src/corelib/global/qtversionchecks.h41
-rw-r--r--src/corelib/global/qtypeinfo.h30
-rw-r--r--src/corelib/global/qtypeinfo.qdoc23
-rw-r--r--src/corelib/global/qtypes.cpp129
-rw-r--r--src/corelib/global/qtypes.h130
-rw-r--r--src/corelib/global/qversiontagging.h12
-rw-r--r--src/corelib/global/qxpfunctional.h27
-rw-r--r--src/corelib/global/qxptype_traits.h60
-rw-r--r--src/corelib/io/forkfd_qt.c (renamed from src/corelib/io/forkfd_qt.cpp)3
-rw-r--r--src/corelib/io/qabstractfileengine.cpp228
-rw-r--r--src/corelib/io/qabstractfileengine_p.h55
-rw-r--r--src/corelib/io/qbuffer.cpp2
-rw-r--r--src/corelib/io/qdataurl.cpp22
-rw-r--r--src/corelib/io/qdataurl_p.h1
-rw-r--r--src/corelib/io/qdebug.cpp255
-rw-r--r--src/corelib/io/qdebug.h75
-rw-r--r--src/corelib/io/qdir.cpp74
-rw-r--r--src/corelib/io/qdir.h6
-rw-r--r--src/corelib/io/qdirentryinfo_p.h156
-rw-r--r--src/corelib/io/qdiriterator.cpp348
-rw-r--r--src/corelib/io/qdirlisting.cpp673
-rw-r--r--src/corelib/io/qdirlisting.h119
-rw-r--r--src/corelib/io/qfile.cpp140
-rw-r--r--src/corelib/io/qfile.h13
-rw-r--r--src/corelib/io/qfiledevice.cpp42
-rw-r--r--src/corelib/io/qfiledevice.h16
-rw-r--r--src/corelib/io/qfileinfo.cpp531
-rw-r--r--src/corelib/io/qfileinfo.h26
-rw-r--r--src/corelib/io/qfileinfo_p.h20
-rw-r--r--src/corelib/io/qfilesystemengine.cpp23
-rw-r--r--src/corelib/io/qfilesystemengine_p.h12
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp488
-rw-r--r--src/corelib/io/qfilesystemengine_win.cpp36
-rw-r--r--src/corelib/io/qfilesystementry.cpp24
-rw-r--r--src/corelib/io/qfilesystemiterator_p.h26
-rw-r--r--src/corelib/io/qfilesystemiterator_unix.cpp73
-rw-r--r--src/corelib/io/qfilesystemiterator_win.cpp9
-rw-r--r--src/corelib/io/qfilesystemmetadata_p.h16
-rw-r--r--src/corelib/io/qfilesystemwatcher.cpp53
-rw-r--r--src/corelib/io/qfilesystemwatcher.h4
-rw-r--r--src/corelib/io/qfilesystemwatcher_inotify.cpp5
-rw-r--r--src/corelib/io/qfilesystemwatcher_kqueue.cpp4
-rw-r--r--src/corelib/io/qfilesystemwatcher_p.h12
-rw-r--r--src/corelib/io/qfilesystemwatcher_polling.cpp28
-rw-r--r--src/corelib/io/qfilesystemwatcher_polling_p.h10
-rw-r--r--src/corelib/io/qfilesystemwatcher_win.cpp1
-rw-r--r--src/corelib/io/qfsfileengine.cpp85
-rw-r--r--src/corelib/io/qfsfileengine_iterator.cpp41
-rw-r--r--src/corelib/io/qfsfileengine_iterator_p.h12
-rw-r--r--src/corelib/io/qfsfileengine_p.h24
-rw-r--r--src/corelib/io/qfsfileengine_unix.cpp10
-rw-r--r--src/corelib/io/qfsfileengine_win.cpp35
-rw-r--r--src/corelib/io/qiodevice.cpp16
-rw-r--r--src/corelib/io/qipaddress.cpp2
-rw-r--r--src/corelib/io/qlockfile.cpp6
-rw-r--r--src/corelib/io/qlockfile.h11
-rw-r--r--src/corelib/io/qlockfile_unix.cpp2
-rw-r--r--src/corelib/io/qloggingcategory.h7
-rw-r--r--src/corelib/io/qloggingregistry.cpp53
-rw-r--r--src/corelib/io/qloggingregistry_p.h16
-rw-r--r--src/corelib/io/qnoncontiguousbytedevice.cpp69
-rw-r--r--src/corelib/io/qnoncontiguousbytedevice_p.h3
-rw-r--r--src/corelib/io/qprocess.cpp327
-rw-r--r--src/corelib/io/qprocess.h36
-rw-r--r--src/corelib/io/qprocess_p.h50
-rw-r--r--src/corelib/io/qprocess_unix.cpp645
-rw-r--r--src/corelib/io/qprocess_win.cpp42
-rw-r--r--src/corelib/io/qresource.cpp185
-rw-r--r--src/corelib/io/qresource_iterator.cpp38
-rw-r--r--src/corelib/io/qresource_iterator_p.h7
-rw-r--r--src/corelib/io/qresource_p.h6
-rw-r--r--src/corelib/io/qsavefile.cpp16
-rw-r--r--src/corelib/io/qsavefile.h6
-rw-r--r--src/corelib/io/qsavefile_p.h4
-rw-r--r--src/corelib/io/qsettings.cpp130
-rw-r--r--src/corelib/io/qsettings.h15
-rw-r--r--src/corelib/io/qsettings_p.h3
-rw-r--r--src/corelib/io/qsettings_wasm.cpp453
-rw-r--r--src/corelib/io/qstandardpaths.cpp26
-rw-r--r--src/corelib/io/qstandardpaths.h4
-rw-r--r--src/corelib/io/qstandardpaths_android.cpp5
-rw-r--r--src/corelib/io/qstandardpaths_haiku.cpp4
-rw-r--r--src/corelib/io/qstandardpaths_mac.mm11
-rw-r--r--src/corelib/io/qstandardpaths_unix.cpp89
-rw-r--r--src/corelib/io/qstandardpaths_win.cpp23
-rw-r--r--src/corelib/io/qstorageinfo.cpp33
-rw-r--r--src/corelib/io/qstorageinfo.h15
-rw-r--r--src/corelib/io/qstorageinfo_linux.cpp288
-rw-r--r--src/corelib/io/qstorageinfo_linux_p.h244
-rw-r--r--src/corelib/io/qstorageinfo_mac.cpp9
-rw-r--r--src/corelib/io/qstorageinfo_p.h119
-rw-r--r--src/corelib/io/qstorageinfo_stub.cpp25
-rw-r--r--src/corelib/io/qstorageinfo_unix.cpp468
-rw-r--r--src/corelib/io/qstorageinfo_win.cpp7
-rw-r--r--src/corelib/io/qtemporarydir.cpp6
-rw-r--r--src/corelib/io/qtemporarydir.h4
-rw-r--r--src/corelib/io/qtemporaryfile.cpp55
-rw-r--r--src/corelib/io/qtemporaryfile.h41
-rw-r--r--src/corelib/io/qtemporaryfile_p.h7
-rw-r--r--src/corelib/io/qurl.cpp123
-rw-r--r--src/corelib/io/qurl.h12
-rw-r--r--src/corelib/io/qurl_p.h4
-rw-r--r--src/corelib/io/qurlidna.cpp92
-rw-r--r--src/corelib/io/qurlquery.cpp62
-rw-r--r--src/corelib/io/qurlquery.h16
-rw-r--r--src/corelib/io/qwindowspipereader.cpp2
-rw-r--r--src/corelib/io/qwindowspipewriter.cpp2
-rw-r--r--src/corelib/io/qzip.cpp (renamed from src/gui/text/qzip.cpp)21
-rw-r--r--src/corelib/io/qzipreader_p.h (renamed from src/gui/text/qzipreader_p.h)8
-rw-r--r--src/corelib/io/qzipwriter_p.h (renamed from src/gui/text/qzipwriter_p.h)8
-rw-r--r--src/corelib/ipc/qsharedmemory.cpp39
-rw-r--r--src/corelib/ipc/qsharedmemory.h5
-rw-r--r--src/corelib/ipc/qsharedmemory_p.h4
-rw-r--r--src/corelib/ipc/qsharedmemory_posix.cpp8
-rw-r--r--src/corelib/ipc/qsharedmemory_systemv.cpp5
-rw-r--r--src/corelib/ipc/qsystemsemaphore.cpp27
-rw-r--r--src/corelib/ipc/qsystemsemaphore.h5
-rw-r--r--src/corelib/ipc/qsystemsemaphore_p.h2
-rw-r--r--src/corelib/ipc/qsystemsemaphore_posix.cpp14
-rw-r--r--src/corelib/ipc/qsystemsemaphore_systemv.cpp8
-rw-r--r--src/corelib/ipc/qtipccommon.cpp246
-rw-r--r--src/corelib/ipc/qtipccommon.h107
-rw-r--r--src/corelib/ipc/qtipccommon_p.h37
-rw-r--r--src/corelib/itemmodels/qabstractitemmodel.cpp37
-rw-r--r--src/corelib/itemmodels/qabstractitemmodel.h18
-rw-r--r--src/corelib/itemmodels/qabstractproxymodel.cpp79
-rw-r--r--src/corelib/itemmodels/qabstractproxymodel_p.h10
-rw-r--r--src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp178
-rw-r--r--src/corelib/itemmodels/qconcatenatetablesproxymodel.h15
-rw-r--r--src/corelib/itemmodels/qidentityproxymodel.cpp208
-rw-r--r--src/corelib/itemmodels/qidentityproxymodel.h25
-rw-r--r--src/corelib/itemmodels/qidentityproxymodel_p.h52
-rw-r--r--src/corelib/itemmodels/qitemselectionmodel.cpp118
-rw-r--r--src/corelib/itemmodels/qitemselectionmodel.h21
-rw-r--r--src/corelib/itemmodels/qitemselectionmodel_p.h34
-rw-r--r--src/corelib/itemmodels/qsortfilterproxymodel.cpp120
-rw-r--r--src/corelib/itemmodels/qstringlistmodel.cpp8
-rw-r--r--src/corelib/kernel/qabstracteventdispatcher.cpp283
-rw-r--r--src/corelib/kernel/qabstracteventdispatcher.h60
-rw-r--r--src/corelib/kernel/qabstracteventdispatcher_p.h14
-rw-r--r--src/corelib/kernel/qapplicationstatic.h21
-rw-r--r--src/corelib/kernel/qapplicationstatic.qdoc30
-rw-r--r--src/corelib/kernel/qbasictimer.cpp20
-rw-r--r--src/corelib/kernel/qchronotimer.cpp452
-rw-r--r--src/corelib/kernel/qchronotimer.h149
-rw-r--r--src/corelib/kernel/qcore_foundation.mm4
-rw-r--r--src/corelib/kernel/qcore_mac.mm198
-rw-r--r--src/corelib/kernel/qcore_mac_p.h67
-rw-r--r--src/corelib/kernel/qcore_unix.cpp63
-rw-r--r--src/corelib/kernel/qcore_unix_p.h71
-rw-r--r--src/corelib/kernel/qcore_wasm.cpp8
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp326
-rw-r--r--src/corelib/kernel/qcoreapplication.h81
-rw-r--r--src/corelib/kernel/qcoreapplication_p.h6
-rw-r--r--src/corelib/kernel/qcoreapplication_platform.h4
-rw-r--r--src/corelib/kernel/qcoreevent.cpp38
-rw-r--r--src/corelib/kernel/qcoreevent.h23
-rw-r--r--src/corelib/kernel/qcoreevent_p.h39
-rw-r--r--src/corelib/kernel/qdeadlinetimer.cpp514
-rw-r--r--src/corelib/kernel/qdeadlinetimer.h85
-rw-r--r--src/corelib/kernel/qdeadlinetimer_p.h34
-rw-r--r--src/corelib/kernel/qelapsedtimer.cpp237
-rw-r--r--src/corelib/kernel/qelapsedtimer.h9
-rw-r--r--src/corelib/kernel/qelapsedtimer_generic.cpp169
-rw-r--r--src/corelib/kernel/qelapsedtimer_mac.cpp130
-rw-r--r--src/corelib/kernel/qelapsedtimer_unix.cpp209
-rw-r--r--src/corelib/kernel/qelapsedtimer_win.cpp123
-rw-r--r--src/corelib/kernel/qeventdispatcher_cf.mm54
-rw-r--r--src/corelib/kernel/qeventdispatcher_cf_p.h33
-rw-r--r--src/corelib/kernel/qeventdispatcher_glib.cpp63
-rw-r--r--src/corelib/kernel/qeventdispatcher_glib_p.h14
-rw-r--r--src/corelib/kernel/qeventdispatcher_unix.cpp115
-rw-r--r--src/corelib/kernel/qeventdispatcher_unix_p.h22
-rw-r--r--src/corelib/kernel/qeventdispatcher_wasm.cpp323
-rw-r--r--src/corelib/kernel/qeventdispatcher_wasm_p.h28
-rw-r--r--src/corelib/kernel/qeventdispatcher_win.cpp22
-rw-r--r--src/corelib/kernel/qeventdispatcher_win_p.h9
-rw-r--r--src/corelib/kernel/qeventloop.cpp180
-rw-r--r--src/corelib/kernel/qeventloop.h40
-rw-r--r--src/corelib/kernel/qfunctions_p.h4
-rw-r--r--src/corelib/kernel/qfunctions_vxworks.cpp172
-rw-r--r--src/corelib/kernel/qfunctions_vxworks.h159
-rw-r--r--src/corelib/kernel/qfunctions_win.cpp2
-rw-r--r--src/corelib/kernel/qfunctions_win_p.h1
-rw-r--r--src/corelib/kernel/qiterable.cpp3
-rw-r--r--src/corelib/kernel/qiterable.h48
-rw-r--r--src/corelib/kernel/qjniarray.h464
-rw-r--r--src/corelib/kernel/qjnienvironment.cpp82
-rw-r--r--src/corelib/kernel/qjnienvironment.h16
-rw-r--r--src/corelib/kernel/qjnihelpers.cpp82
-rw-r--r--src/corelib/kernel/qjnihelpers_p.h29
-rw-r--r--src/corelib/kernel/qjniobject.cpp556
-rw-r--r--src/corelib/kernel/qjniobject.h790
-rw-r--r--src/corelib/kernel/qjnitypes.h465
-rw-r--r--src/corelib/kernel/qjnitypes_impl.h373
-rw-r--r--src/corelib/kernel/qmath.qdoc2
-rw-r--r--src/corelib/kernel/qmetacontainer.cpp16
-rw-r--r--src/corelib/kernel/qmetacontainer.h29
-rw-r--r--src/corelib/kernel/qmetaobject.cpp537
-rw-r--r--src/corelib/kernel/qmetaobject.h31
-rw-r--r--src/corelib/kernel/qmetaobject_p.h8
-rw-r--r--src/corelib/kernel/qmetaobjectbuilder.cpp33
-rw-r--r--src/corelib/kernel/qmetaobjectbuilder_p.h3
-rw-r--r--src/corelib/kernel/qmetatype.cpp194
-rw-r--r--src/corelib/kernel/qmetatype.h71
-rw-r--r--src/corelib/kernel/qmetatype_p.h21
-rw-r--r--src/corelib/kernel/qmimedata.cpp92
-rw-r--r--src/corelib/kernel/qobject.cpp650
-rw-r--r--src/corelib/kernel/qobject.h203
-rw-r--r--src/corelib/kernel/qobject_impl.h24
-rw-r--r--src/corelib/kernel/qobject_p.h89
-rw-r--r--src/corelib/kernel/qobject_p_p.h13
-rw-r--r--src/corelib/kernel/qobjectcleanuphandler.cpp4
-rw-r--r--src/corelib/kernel/qobjectdefs.h192
-rw-r--r--src/corelib/kernel/qobjectdefs_impl.h418
-rw-r--r--src/corelib/kernel/qpermissions.cpp111
-rw-r--r--src/corelib/kernel/qpermissions.h33
-rw-r--r--src/corelib/kernel/qpermissions_android.cpp56
-rw-r--r--src/corelib/kernel/qpermissions_wasm.cpp5
-rw-r--r--src/corelib/kernel/qpointer.h60
-rw-r--r--src/corelib/kernel/qpointer.qdoc (renamed from src/corelib/kernel/qpointer.cpp)51
-rw-r--r--src/corelib/kernel/qpoll.cpp4
-rw-r--r--src/corelib/kernel/qproperty.cpp50
-rw-r--r--src/corelib/kernel/qproperty.h30
-rw-r--r--src/corelib/kernel/qproperty_p.h74
-rw-r--r--src/corelib/kernel/qpropertyprivate.h18
-rw-r--r--src/corelib/kernel/qsignalmapper.cpp11
-rw-r--r--src/corelib/kernel/qsignalmapper.h1
-rw-r--r--src/corelib/kernel/qsingleshottimer_p.h141
-rw-r--r--src/corelib/kernel/qsocketnotifier.cpp1
-rw-r--r--src/corelib/kernel/qsystemerror_p.h7
-rw-r--r--src/corelib/kernel/qt_attribution.json2
-rw-r--r--src/corelib/kernel/qtestsupport_core.cpp117
-rw-r--r--src/corelib/kernel/qtestsupport_core.h34
-rw-r--r--src/corelib/kernel/qtimer.cpp373
-rw-r--r--src/corelib/kernel/qtimer.h156
-rw-r--r--src/corelib/kernel/qtimer_p.h48
-rw-r--r--src/corelib/kernel/qtimerinfo_unix.cpp440
-rw-r--r--src/corelib/kernel/qtimerinfo_unix_p.h94
-rw-r--r--src/corelib/kernel/qtmetamacros.h2
-rw-r--r--src/corelib/kernel/qtmochelpers.h48
-rw-r--r--src/corelib/kernel/qtranslator.cpp9
-rw-r--r--src/corelib/kernel/qvariant.cpp291
-rw-r--r--src/corelib/kernel/qvariant.h216
-rw-r--r--src/corelib/kernel/qvariant_p.h25
-rw-r--r--src/corelib/kernel/qwineventnotifier.cpp2
-rw-r--r--src/corelib/kernel/qwinregistry.cpp4
-rw-r--r--src/corelib/kernel/qwinregistry_p.h2
-rw-r--r--src/corelib/mimetypes/mime/packages/freedesktop.org.xml11552
-rw-r--r--src/corelib/mimetypes/qmimedatabase.cpp109
-rw-r--r--src/corelib/mimetypes/qmimedatabase_p.h9
-rw-r--r--src/corelib/mimetypes/qmimeglobpattern.cpp49
-rw-r--r--src/corelib/mimetypes/qmimeglobpattern_p.h35
-rw-r--r--src/corelib/mimetypes/qmimemagicrule.cpp11
-rw-r--r--src/corelib/mimetypes/qmimemagicrule_p.h4
-rw-r--r--src/corelib/mimetypes/qmimeprovider.cpp333
-rw-r--r--src/corelib/mimetypes/qmimeprovider_p.h77
-rw-r--r--src/corelib/mimetypes/qmimetype.cpp126
-rw-r--r--src/corelib/mimetypes/qmimetype.h8
-rw-r--r--src/corelib/mimetypes/qmimetype_p.h38
-rw-r--r--src/corelib/mimetypes/qmimetypeparser.cpp39
-rw-r--r--src/corelib/mimetypes/qmimetypeparser_p.h21
-rw-r--r--src/corelib/platform/android/qandroidextras.cpp52
-rw-r--r--src/corelib/platform/android/qandroidnativeinterface.cpp13
-rw-r--r--src/corelib/platform/darwin/qdarwinpermissionplugin_bluetooth.mm6
-rw-r--r--src/corelib/platform/darwin/qdarwinpermissionplugin_calendar.mm22
-rw-r--r--src/corelib/platform/darwin/qdarwinpermissionplugin_location.mm22
-rw-r--r--src/corelib/platform/darwin/qdarwinpermissionplugin_p_p.h4
-rw-r--r--src/corelib/platform/ios/PrivacyInfo.xcprivacy31
-rw-r--r--src/corelib/platform/wasm/qstdweb.cpp412
-rw-r--r--src/corelib/platform/wasm/qstdweb_p.h138
-rw-r--r--src/corelib/platform/windows/qcomobject_p.h127
-rw-r--r--src/corelib/plugin/qcoffpeparser.cpp2
-rw-r--r--src/corelib/plugin/qelfparser_p.cpp17
-rw-r--r--src/corelib/plugin/qfactoryloader.cpp272
-rw-r--r--src/corelib/plugin/qfactoryloader_p.h1
-rw-r--r--src/corelib/plugin/qlibrary.cpp85
-rw-r--r--src/corelib/plugin/qlibrary_p.h8
-rw-r--r--src/corelib/plugin/qlibrary_unix.cpp50
-rw-r--r--src/corelib/plugin/qplugin.qdoc9
-rw-r--r--src/corelib/plugin/qpluginloader.cpp34
-rw-r--r--src/corelib/plugin/quuid.cpp104
-rw-r--r--src/corelib/plugin/quuid.h115
-rw-r--r--src/corelib/qt_cmdline.cmake1
-rwxr-xr-xsrc/corelib/serialization/make-xml-parser.sh2
-rw-r--r--src/corelib/serialization/qcborarray.cpp159
-rw-r--r--src/corelib/serialization/qcborarray.h140
-rw-r--r--src/corelib/serialization/qcborcommon.cpp5
-rw-r--r--src/corelib/serialization/qcbormap.cpp180
-rw-r--r--src/corelib/serialization/qcbormap.h195
-rw-r--r--src/corelib/serialization/qcborstreamreader.cpp274
-rw-r--r--src/corelib/serialization/qcborstreamreader.h35
-rw-r--r--src/corelib/serialization/qcborstreamwriter.cpp17
-rw-r--r--src/corelib/serialization/qcborvalue.cpp461
-rw-r--r--src/corelib/serialization/qcborvalue.h94
-rw-r--r--src/corelib/serialization/qcborvalue_p.h49
-rw-r--r--src/corelib/serialization/qdatastream.cpp249
-rw-r--r--src/corelib/serialization/qdatastream.h196
-rw-r--r--src/corelib/serialization/qdatastream_p.h5
-rw-r--r--src/corelib/serialization/qjsonarray.cpp134
-rw-r--r--src/corelib/serialization/qjsonarray.h104
-rw-r--r--src/corelib/serialization/qjsoncbor.cpp8
-rw-r--r--src/corelib/serialization/qjsondocument.cpp26
-rw-r--r--src/corelib/serialization/qjsondocument.h10
-rw-r--r--src/corelib/serialization/qjsonobject.cpp141
-rw-r--r--src/corelib/serialization/qjsonobject.h129
-rw-r--r--src/corelib/serialization/qjsonparser.cpp96
-rw-r--r--src/corelib/serialization/qjsonvalue.cpp50
-rw-r--r--src/corelib/serialization/qjsonvalue.h62
-rw-r--r--src/corelib/serialization/qjsonwriter.cpp17
-rw-r--r--src/corelib/serialization/qtextstream.cpp16
-rw-r--r--src/corelib/serialization/qxmlstream.cpp449
-rw-r--r--src/corelib/serialization/qxmlstream.g23
-rw-r--r--src/corelib/serialization/qxmlstream.h117
-rw-r--r--src/corelib/serialization/qxmlstream_p.h18
-rw-r--r--src/corelib/serialization/qxmlstreamgrammar_p.h2
-rw-r--r--src/corelib/serialization/qxmlstreamparser_p.h17
-rw-r--r--src/corelib/serialization/qxmlutils.cpp2
-rw-r--r--src/corelib/text/UNICODE_LICENSE.txt46
-rw-r--r--src/corelib/text/qanystringview.cpp (renamed from src/corelib/text/qanystringview.qdoc)98
-rw-r--r--src/corelib/text/qanystringview.h93
-rw-r--r--src/corelib/text/qbytearray.cpp559
-rw-r--r--src/corelib/text/qbytearray.h260
-rw-r--r--src/corelib/text/qbytearray_p.h29
-rw-r--r--src/corelib/text/qbytearrayalgorithms.h6
-rw-r--r--src/corelib/text/qbytearrayview.h105
-rw-r--r--src/corelib/text/qbytearrayview.qdoc40
-rw-r--r--src/corelib/text/qchar.cpp28
-rw-r--r--src/corelib/text/qchar.h142
-rw-r--r--src/corelib/text/qcollator.cpp58
-rw-r--r--src/corelib/text/qcollator.h2
-rw-r--r--src/corelib/text/qlatin1stringmatcher.cpp3
-rw-r--r--src/corelib/text/qlatin1stringview.h147
-rw-r--r--src/corelib/text/qlatin1stringview.qdoc290
-rw-r--r--src/corelib/text/qlocale.cpp555
-rw-r--r--src/corelib/text/qlocale.h67
-rw-r--r--src/corelib/text/qlocale.qdoc13
-rw-r--r--src/corelib/text/qlocale_data_p.h9830
-rw-r--r--src/corelib/text/qlocale_mac.mm272
-rw-r--r--src/corelib/text/qlocale_p.h75
-rw-r--r--src/corelib/text/qlocale_tools.cpp16
-rw-r--r--src/corelib/text/qlocale_tools_p.h11
-rw-r--r--src/corelib/text/qlocale_unix.cpp8
-rw-r--r--src/corelib/text/qlocale_wasm.cpp54
-rw-r--r--src/corelib/text/qlocale_win.cpp202
-rw-r--r--src/corelib/text/qregularexpression.cpp93
-rw-r--r--src/corelib/text/qregularexpression.h24
-rw-r--r--src/corelib/text/qstaticlatin1stringmatcher.h140
-rw-r--r--src/corelib/text/qstaticlatin1stringmatcher.qdoc86
-rw-r--r--src/corelib/text/qstring.cpp1322
-rw-r--r--src/corelib/text/qstring.h726
-rw-r--r--src/corelib/text/qstringalgorithms.h93
-rw-r--r--src/corelib/text/qstringalgorithms_p.h19
-rw-r--r--src/corelib/text/qstringbuilder.cpp6
-rw-r--r--src/corelib/text/qstringbuilder.h146
-rw-r--r--src/corelib/text/qstringconverter.cpp624
-rw-r--r--src/corelib/text/qstringconverter.h84
-rw-r--r--src/corelib/text/qstringconverter_base.h5
-rw-r--r--src/corelib/text/qstringconverter_p.h11
-rw-r--r--src/corelib/text/qstringlist.cpp231
-rw-r--r--src/corelib/text/qstringlist.h43
-rw-r--r--src/corelib/text/qstringmatcher.cpp11
-rw-r--r--src/corelib/text/qstringmatcher.h3
-rw-r--r--src/corelib/text/qstringtokenizer.h1
-rw-r--r--src/corelib/text/qstringview.cpp88
-rw-r--r--src/corelib/text/qstringview.h137
-rw-r--r--src/corelib/text/qt_attribution.json30
-rw-r--r--src/corelib/text/qtextboundaryfinder.cpp4
-rw-r--r--src/corelib/text/qtextboundaryfinder.h2
-rw-r--r--src/corelib/text/qtliterals.qdoc2
-rw-r--r--src/corelib/text/qunicodetables.cpp14888
-rw-r--r--src/corelib/text/qunicodetables_p.h12
-rw-r--r--src/corelib/text/qunicodetools.cpp128
-rw-r--r--src/corelib/text/qutf8stringview.h140
-rw-r--r--src/corelib/text/qutf8stringview.qdoc47
-rw-r--r--src/corelib/thread/qatomic.cpp6
-rw-r--r--src/corelib/thread/qatomic.h2
-rw-r--r--src/corelib/thread/qatomic_cxx11.h1
-rw-r--r--src/corelib/thread/qbasicatomic.h4
-rw-r--r--src/corelib/thread/qfutex_freebsd_p.h82
-rw-r--r--src/corelib/thread/qfutex_linux_p.h95
-rw-r--r--src/corelib/thread/qfutex_mac_p.h140
-rw-r--r--src/corelib/thread/qfutex_p.h117
-rw-r--r--src/corelib/thread/qfutex_win_p.h58
-rw-r--r--src/corelib/thread/qfuture.h13
-rw-r--r--src/corelib/thread/qfuture.qdoc176
-rw-r--r--src/corelib/thread/qfuture_impl.h190
-rw-r--r--src/corelib/thread/qfutureinterface.cpp145
-rw-r--r--src/corelib/thread/qfutureinterface.h23
-rw-r--r--src/corelib/thread/qfuturesynchronizer.h15
-rw-r--r--src/corelib/thread/qfuturesynchronizer.qdoc6
-rw-r--r--src/corelib/thread/qfuturewatcher.cpp4
-rw-r--r--src/corelib/thread/qgenericatomic.h335
-rw-r--r--src/corelib/thread/qmutex.cpp75
-rw-r--r--src/corelib/thread/qmutex.h79
-rw-r--r--src/corelib/thread/qmutex_mac.cpp11
-rw-r--r--src/corelib/thread/qmutex_p.h19
-rw-r--r--src/corelib/thread/qmutex_unix.cpp78
-rw-r--r--src/corelib/thread/qorderedmutexlocker_p.h35
-rw-r--r--src/corelib/thread/qpromise.h14
-rw-r--r--src/corelib/thread/qpromise.qdoc33
-rw-r--r--src/corelib/thread/qreadwritelock.cpp199
-rw-r--r--src/corelib/thread/qreadwritelock.h70
-rw-r--r--src/corelib/thread/qreadwritelock_p.h59
-rw-r--r--src/corelib/thread/qresultstore.h13
-rw-r--r--src/corelib/thread/qrunnable.cpp48
-rw-r--r--src/corelib/thread/qrunnable.h111
-rw-r--r--src/corelib/thread/qsemaphore.cpp108
-rw-r--r--src/corelib/thread/qsemaphore.h20
-rw-r--r--src/corelib/thread/qthread.cpp110
-rw-r--r--src/corelib/thread/qthread.h25
-rw-r--r--src/corelib/thread/qthread_p.h10
-rw-r--r--src/corelib/thread/qthread_unix.cpp19
-rw-r--r--src/corelib/thread/qthread_win.cpp63
-rw-r--r--src/corelib/thread/qthreadpool.cpp64
-rw-r--r--src/corelib/thread/qthreadpool.h33
-rw-r--r--src/corelib/thread/qwaitcondition.qdoc8
-rw-r--r--src/corelib/thread/qwaitcondition_p.h104
-rw-r--r--src/corelib/thread/qwaitcondition_unix.cpp142
-rw-r--r--src/corelib/thread/qwaitcondition_win.cpp62
-rw-r--r--src/corelib/thread/qyieldcpu.h64
-rw-r--r--src/corelib/thread/qyieldcpu.qdoc59
-rw-r--r--src/corelib/time/qcalendar.cpp95
-rw-r--r--src/corelib/time/qcalendar.h1
-rw-r--r--src/corelib/time/qcalendarbackend_p.h5
-rw-r--r--src/corelib/time/qdatetime.cpp1299
-rw-r--r--src/corelib/time/qdatetime.h228
-rw-r--r--src/corelib/time/qdatetime_p.h28
-rw-r--r--src/corelib/time/qdatetimeparser.cpp342
-rw-r--r--src/corelib/time/qdatetimeparser_p.h15
-rw-r--r--src/corelib/time/qgregoriancalendar.cpp68
-rw-r--r--src/corelib/time/qgregoriancalendar_p.h11
-rw-r--r--src/corelib/time/qhijricalendar_data_p.h1972
-rw-r--r--src/corelib/time/qjalalicalendar.cpp5
-rw-r--r--src/corelib/time/qjalalicalendar_data_p.h1166
-rw-r--r--src/corelib/time/qlocaltime.cpp566
-rw-r--r--src/corelib/time/qlocaltime_p.h4
-rw-r--r--src/corelib/time/qromancalendar_data_p.h7781
-rw-r--r--src/corelib/time/qromancalendar_p.h6
-rw-r--r--src/corelib/time/qtimezone.cpp321
-rw-r--r--src/corelib/time/qtimezone.h28
-rw-r--r--src/corelib/time/qtimezonelocale.cpp29
-rw-r--r--src/corelib/time/qtimezonelocale_data_p.h39
-rw-r--r--src/corelib/time/qtimezonelocale_p.h31
-rw-r--r--src/corelib/time/qtimezoneprivate.cpp586
-rw-r--r--src/corelib/time/qtimezoneprivate_android.cpp30
-rw-r--r--src/corelib/time/qtimezoneprivate_data_p.h2280
-rw-r--r--src/corelib/time/qtimezoneprivate_icu.cpp60
-rw-r--r--src/corelib/time/qtimezoneprivate_mac.mm29
-rw-r--r--src/corelib/time/qtimezoneprivate_p.h56
-rw-r--r--src/corelib/time/qtimezoneprivate_tz.cpp266
-rw-r--r--src/corelib/time/qtimezoneprivate_win.cpp63
-rw-r--r--src/corelib/tools/qarraydata.cpp128
-rw-r--r--src/corelib/tools/qarraydata.h72
-rw-r--r--src/corelib/tools/qarraydataops.h21
-rw-r--r--src/corelib/tools/qarraydatapointer.h137
-rw-r--r--src/corelib/tools/qatomicscopedvaluerollback.h (renamed from src/corelib/tools/qatomicscopedvaluerollback_p.h)70
-rw-r--r--src/corelib/tools/qatomicscopedvaluerollback.qdoc123
-rw-r--r--src/corelib/tools/qbitarray.cpp356
-rw-r--r--src/corelib/tools/qbitarray.h135
-rw-r--r--src/corelib/tools/qcommandlineoption.cpp6
-rw-r--r--src/corelib/tools/qcommandlineparser.cpp98
-rw-r--r--src/corelib/tools/qcontainerfwd.h21
-rw-r--r--src/corelib/tools/qcontainertools_impl.h27
-rw-r--r--src/corelib/tools/qcontiguouscache.cpp2
-rw-r--r--src/corelib/tools/qcontiguouscache.h8
-rw-r--r--src/corelib/tools/qcryptographichash.cpp133
-rw-r--r--src/corelib/tools/qduplicatetracker_p.h2
-rw-r--r--src/corelib/tools/qflatmap_p.h11
-rw-r--r--src/corelib/tools/qfreelist.cpp10
-rw-r--r--src/corelib/tools/qfunctionaltools_impl.cpp47
-rw-r--r--src/corelib/tools/qfunctionaltools_impl.h77
-rw-r--r--src/corelib/tools/qhash.cpp638
-rw-r--r--src/corelib/tools/qhash.h466
-rw-r--r--src/corelib/tools/qhashfunctions.h85
-rw-r--r--src/corelib/tools/qiterator.h44
-rw-r--r--src/corelib/tools/qiterator.qdoc56
-rw-r--r--src/corelib/tools/qlist.h100
-rw-r--r--src/corelib/tools/qlist.qdoc109
-rw-r--r--src/corelib/tools/qmap.h35
-rw-r--r--src/corelib/tools/qmap.qdoc75
-rw-r--r--src/corelib/tools/qminimalflatset_p.h156
-rw-r--r--src/corelib/tools/qmultimap.qdoc64
-rw-r--r--src/corelib/tools/qpair.h6
-rw-r--r--src/corelib/tools/qringbuffer.cpp9
-rw-r--r--src/corelib/tools/qscopedpointer.cpp2
-rw-r--r--src/corelib/tools/qscopedpointer.h7
-rw-r--r--src/corelib/tools/qscopedvaluerollback.h4
-rw-r--r--src/corelib/tools/qscopeguard.h5
-rw-r--r--src/corelib/tools/qset.h31
-rw-r--r--src/corelib/tools/qset.qdoc34
-rw-r--r--src/corelib/tools/qshareddata.h11
-rw-r--r--src/corelib/tools/qsharedpointer.cpp93
-rw-r--r--src/corelib/tools/qsharedpointer.h26
-rw-r--r--src/corelib/tools/qsharedpointer_impl.h93
-rw-r--r--src/corelib/tools/qspan.h452
-rw-r--r--src/corelib/tools/qspan.qdoc651
-rw-r--r--src/corelib/tools/qspan_p.h24
-rw-r--r--src/corelib/tools/qtaggedpointer.h6
-rw-r--r--src/corelib/tools/qtimeline.cpp42
-rw-r--r--src/corelib/tools/qtools_p.h3
-rw-r--r--src/corelib/tools/qtyperevision.cpp217
-rw-r--r--src/corelib/tools/qtyperevision.h167
-rw-r--r--src/corelib/tools/quniquehandle_p.h225
-rw-r--r--src/corelib/tools/qvarlengtharray.h67
-rw-r--r--src/corelib/tools/qvarlengtharray.qdoc39
-rw-r--r--src/corelib/tools/qversionnumber.cpp260
-rw-r--r--src/corelib/tools/qversionnumber.h243
-rw-r--r--src/corelib/tracing/qctf.cpp39
-rw-r--r--src/corelib/tracing/qctf_p.h5
-rw-r--r--src/dbus/CMakeLists.txt10
-rw-r--r--src/dbus/doc/qtdbus.qdocconf2
-rw-r--r--src/dbus/doc/snippets/CMakeLists.txt2
-rw-r--r--src/dbus/doc/snippets/cmake/examples.cmake2
-rw-r--r--src/dbus/doc/snippets/code/doc_src_introtodbus.qdoc2
-rw-r--r--src/dbus/doc/snippets/code/src_qdbus_qdbusabstractinterface.cpp20
-rw-r--r--src/dbus/doc/snippets/code/src_qdbus_qdbuscontext.cpp2
-rw-r--r--src/dbus/doc/snippets/code/src_qdbus_qdbuspendingcall.cpp4
-rw-r--r--src/dbus/doc/src/dbus-adaptors.qdoc14
-rw-r--r--src/dbus/doc/src/qt6-changes.qdoc2
-rw-r--r--src/dbus/doc/src/qtdbus-cmake.qdoc2
-rw-r--r--src/dbus/doc/src/qtdbus-overview.qdoc3
-rw-r--r--src/dbus/qdbus_symbols.cpp12
-rw-r--r--src/dbus/qdbus_symbols_p.h52
-rw-r--r--src/dbus/qdbusabstractadaptor.cpp32
-rw-r--r--src/dbus/qdbusabstractinterface.cpp52
-rw-r--r--src/dbus/qdbusabstractinterface.h3
-rw-r--r--src/dbus/qdbusabstractinterface_p.h1
-rw-r--r--src/dbus/qdbusargument.cpp28
-rw-r--r--src/dbus/qdbusargument.h26
-rw-r--r--src/dbus/qdbusargument_p.h58
-rw-r--r--src/dbus/qdbusconnection.cpp319
-rw-r--r--src/dbus/qdbusconnection_p.h67
-rw-r--r--src/dbus/qdbusconnectionmanager.cpp334
-rw-r--r--src/dbus/qdbusconnectionmanager_p.h51
-rw-r--r--src/dbus/qdbusextratypes.cpp9
-rw-r--r--src/dbus/qdbusextratypes.h5
-rw-r--r--src/dbus/qdbusintegrator.cpp349
-rw-r--r--src/dbus/qdbusintegrator_p.h43
-rw-r--r--src/dbus/qdbusinternalfilters.cpp76
-rw-r--r--src/dbus/qdbusintrospection.cpp23
-rw-r--r--src/dbus/qdbusintrospection_p.h48
-rw-r--r--src/dbus/qdbusmarshaller.cpp16
-rw-r--r--src/dbus/qdbusmessage.cpp126
-rw-r--r--src/dbus/qdbusmessage.h1
-rw-r--r--src/dbus/qdbusmessage_p.h8
-rw-r--r--src/dbus/qdbusmetaobject.cpp72
-rw-r--r--src/dbus/qdbusmetatype.cpp89
-rw-r--r--src/dbus/qdbusmetatype_p.h23
-rw-r--r--src/dbus/qdbusmisc.cpp69
-rw-r--r--src/dbus/qdbuspendingcall.cpp45
-rw-r--r--src/dbus/qdbuspendingcall.h5
-rw-r--r--src/dbus/qdbuspendingcall_p.h3
-rw-r--r--src/dbus/qdbusreply.cpp2
-rw-r--r--src/dbus/qdbusserver.cpp53
-rw-r--r--src/dbus/qdbusserver.h1
-rw-r--r--src/dbus/qdbusservicewatcher.cpp77
-rw-r--r--src/dbus/qdbusthreaddebug_p.h4
-rw-r--r--src/dbus/qdbusutil.cpp42
-rw-r--r--src/dbus/qdbusxmlgenerator.cpp50
-rw-r--r--src/dbus/qdbusxmlparser.cpp367
-rw-r--r--src/dbus/qdbusxmlparser_p.h21
-rw-r--r--src/dbus/qt_attribution.json6
-rw-r--r--src/dbus/qtdbusglobal.h4
-rw-r--r--src/entrypoint/CMakeLists.txt4
-rw-r--r--src/gui/CMakeLists.txt162
-rw-r--r--src/gui/accessible/linux/atspiadaptor.cpp126
-rw-r--r--src/gui/accessible/linux/dbusconnection.cpp23
-rw-r--r--src/gui/accessible/linux/dbusxml/Socket.xml2
-rw-r--r--src/gui/accessible/linux/qspi_constant_mappings.cpp5
-rw-r--r--src/gui/accessible/linux/qspiaccessiblebridge.cpp12
-rw-r--r--src/gui/accessible/linux/qspiapplicationadaptor.cpp14
-rw-r--r--src/gui/accessible/qaccessible.cpp101
-rw-r--r--src/gui/accessible/qaccessible.h13
-rw-r--r--src/gui/accessible/qaccessible_base.h8
-rw-r--r--src/gui/accessible/windows/apisupport/qwindowsuiawrapper.cpp89
-rw-r--r--src/gui/accessible/windows/apisupport/qwindowsuiawrapper_p.h67
-rw-r--r--src/gui/accessible/windows/apisupport/uiaattributeids_p.h63
-rw-r--r--src/gui/accessible/windows/apisupport/uiaclientinterfaces_p.h230
-rw-r--r--src/gui/accessible/windows/apisupport/uiacontroltypeids_p.h60
-rw-r--r--src/gui/accessible/windows/apisupport/uiaerrorids_p.h26
-rw-r--r--src/gui/accessible/windows/apisupport/uiaeventids_p.h54
-rw-r--r--src/gui/accessible/windows/apisupport/uiageneralids_p.h21
-rw-r--r--src/gui/accessible/windows/apisupport/uiapatternids_p.h53
-rw-r--r--src/gui/accessible/windows/apisupport/uiapropertyids_p.h188
-rw-r--r--src/gui/accessible/windows/apisupport/uiaserverinterfaces_p.h367
-rw-r--r--src/gui/accessible/windows/apisupport/uiatypes_p.h157
-rw-r--r--src/gui/compat/removed_api.cpp70
-rw-r--r--src/gui/configure.cmake73
-rw-r--r--src/gui/doc/images/qpainter-concentriccircles.pngbin31294 -> 95529 bytes
-rw-r--r--src/gui/doc/includes/QtGuiDoc5
-rw-r--r--src/gui/doc/qtgui.qdocconf5
-rw-r--r--src/gui/doc/snippets/code/doc_src_richtext.qdoc2
-rw-r--r--src/gui/doc/snippets/code/src_gui_image_qicon.cpp28
-rw-r--r--src/gui/doc/snippets/code/src_gui_kernel_qapplication.cpp83
-rw-r--r--src/gui/doc/snippets/code/src_gui_kernel_qguiapplication.cpp22
-rw-r--r--src/gui/doc/snippets/code/src_gui_painting_qpainter.cpp33
-rw-r--r--src/gui/doc/snippets/code/src_gui_text_qtextdocument.cpp12
-rw-r--r--src/gui/doc/snippets/code/src_gui_util_qdesktopservices.cpp9
-rw-r--r--src/gui/doc/snippets/code/src_gui_vulkan_qvulkanfunctions.cpp10
-rw-r--r--src/gui/doc/snippets/image/image.cpp7
-rw-r--r--src/gui/doc/snippets/rhioffscreen/color.frag16
-rw-r--r--src/gui/doc/snippets/rhioffscreen/color.vert18
-rw-r--r--src/gui/doc/snippets/rhioffscreen/main.cpp151
-rw-r--r--src/gui/doc/snippets/separations/separations.qdoc2
-rw-r--r--src/gui/doc/src/dnd.qdoc6
-rw-r--r--src/gui/doc/src/external-resources.qdoc11
-rw-r--r--src/gui/doc/src/qt6-changes.qdoc36
-rw-r--r--src/gui/doc/src/qtgui-overview.qdoc85
-rw-r--r--src/gui/doc/src/qtgui.qdoc19
-rw-r--r--src/gui/doc/src/richtext.qdoc9
-rw-r--r--src/gui/image/qabstractfileiconengine_p.h1
-rw-r--r--src/gui/image/qabstractfileiconprovider.cpp18
-rw-r--r--src/gui/image/qabstractfileiconprovider_p.h1
-rw-r--r--src/gui/image/qbmphandler.cpp2
-rw-r--r--src/gui/image/qicon.cpp678
-rw-r--r--src/gui/image/qicon.h161
-rw-r--r--src/gui/image/qicon_p.h4
-rw-r--r--src/gui/image/qiconengine.cpp75
-rw-r--r--src/gui/image/qiconengine_p.h59
-rw-r--r--src/gui/image/qiconloader.cpp318
-rw-r--r--src/gui/image/qiconloader_p.h49
-rw-r--r--src/gui/image/qimage.cpp804
-rw-r--r--src/gui/image/qimage.h12
-rw-r--r--src/gui/image/qimage_conversions.cpp60
-rw-r--r--src/gui/image/qimage_p.h180
-rw-r--r--src/gui/image/qimageiohandler.cpp6
-rw-r--r--src/gui/image/qimagereader.cpp106
-rw-r--r--src/gui/image/qimagereaderwriterhelpers.cpp10
-rw-r--r--src/gui/image/qimagereaderwriterhelpers_p.h2
-rw-r--r--src/gui/image/qmovie.cpp41
-rw-r--r--src/gui/image/qpixmap.cpp5
-rw-r--r--src/gui/image/qpixmap_win.cpp3
-rw-r--r--src/gui/image/qpixmapcache.cpp129
-rw-r--r--src/gui/image/qpixmapcache.h21
-rw-r--r--src/gui/image/qpixmapcache_p.h3
-rw-r--r--src/gui/image/qplatformpixmap.cpp18
-rw-r--r--src/gui/image/qpnghandler.cpp20
-rw-r--r--src/gui/image/qppmhandler.cpp15
-rw-r--r--src/gui/itemmodels/qfileinfogatherer.cpp126
-rw-r--r--src/gui/itemmodels/qfileinfogatherer_p.h13
-rw-r--r--src/gui/itemmodels/qfilesystemmodel.cpp209
-rw-r--r--src/gui/itemmodels/qfilesystemmodel.h13
-rw-r--r--src/gui/itemmodels/qfilesystemmodel_p.h27
-rw-r--r--src/gui/itemmodels/qstandarditemmodel.cpp75
-rw-r--r--src/gui/itemmodels/qstandarditemmodel_p.h8
-rw-r--r--src/gui/kernel/qaction.cpp6
-rw-r--r--src/gui/kernel/qaction_p.h2
-rw-r--r--src/gui/kernel/qactiongroup_p.h2
-rw-r--r--src/gui/kernel/qcursor.cpp30
-rw-r--r--src/gui/kernel/qdnd_p.h2
-rw-r--r--src/gui/kernel/qdrag.cpp4
-rw-r--r--src/gui/kernel/qevent.cpp76
-rw-r--r--src/gui/kernel/qevent.h14
-rw-r--r--src/gui/kernel/qeventpoint.cpp1
-rw-r--r--src/gui/kernel/qeventpoint.h1
-rw-r--r--src/gui/kernel/qeventpoint_p.h2
-rw-r--r--src/gui/kernel/qguiapplication.cpp228
-rw-r--r--src/gui/kernel/qguiapplication_p.h11
-rw-r--r--src/gui/kernel/qguiapplication_platform.h4
-rw-r--r--src/gui/kernel/qguivariant.cpp3
-rw-r--r--src/gui/kernel/qhighdpiscaling.cpp21
-rw-r--r--src/gui/kernel/qinputdevice.cpp9
-rw-r--r--src/gui/kernel/qinternalmimedata.cpp2
-rw-r--r--src/gui/kernel/qkeymapper.cpp74
-rw-r--r--src/gui/kernel/qkeymapper_p.h24
-rw-r--r--src/gui/kernel/qkeysequence.cpp162
-rw-r--r--src/gui/kernel/qkeysequence.h4
-rw-r--r--src/gui/kernel/qkeysequence_p.h8
-rw-r--r--src/gui/kernel/qoffscreensurface.h2
-rw-r--r--src/gui/kernel/qopenglcontext.cpp25
-rw-r--r--src/gui/kernel/qpaintdevicewindow.cpp2
-rw-r--r--src/gui/kernel/qpaintdevicewindow_p.h4
-rw-r--r--src/gui/kernel/qpalette.cpp136
-rw-r--r--src/gui/kernel/qpalette.h5
-rw-r--r--src/gui/kernel/qpalette_p.h77
-rw-r--r--src/gui/kernel/qplatformdialoghelper.cpp57
-rw-r--r--src/gui/kernel/qplatformdialoghelper.h24
-rw-r--r--src/gui/kernel/qplatformgraphicsbufferhelper.cpp4
-rw-r--r--src/gui/kernel/qplatforminputcontext.cpp16
-rw-r--r--src/gui/kernel/qplatforminputcontext.h2
-rw-r--r--src/gui/kernel/qplatforminputcontextfactory.cpp29
-rw-r--r--src/gui/kernel/qplatforminputcontextfactory_p.h3
-rw-r--r--src/gui/kernel/qplatformintegration.cpp21
-rw-r--r--src/gui/kernel/qplatformintegration.h8
-rw-r--r--src/gui/kernel/qplatformkeymapper.cpp38
-rw-r--r--src/gui/kernel/qplatformkeymapper.h36
-rw-r--r--src/gui/kernel/qplatformscreen.cpp11
-rw-r--r--src/gui/kernel/qplatformscreen.h3
-rw-r--r--src/gui/kernel/qplatformscreen_p.h33
-rw-r--r--src/gui/kernel/qplatformservices.cpp2
-rw-r--r--src/gui/kernel/qplatformsystemtrayicon.h3
-rw-r--r--src/gui/kernel/qplatformtheme.cpp12
-rw-r--r--src/gui/kernel/qplatformwindow.cpp17
-rw-r--r--src/gui/kernel/qplatformwindow_p.h17
-rw-r--r--src/gui/kernel/qpointingdevice.cpp8
-rw-r--r--src/gui/kernel/qpointingdevice_p.h2
-rw-r--r--src/gui/kernel/qrasterwindow.cpp16
-rw-r--r--src/gui/kernel/qrasterwindow.h1
-rw-r--r--src/gui/kernel/qscreen.cpp94
-rw-r--r--src/gui/kernel/qscreen.h2
-rw-r--r--src/gui/kernel/qscreen_p.h1
-rw-r--r--src/gui/kernel/qscreen_platform.h61
-rw-r--r--src/gui/kernel/qsessionmanager.cpp8
-rw-r--r--src/gui/kernel/qsessionmanager_p.h2
-rw-r--r--src/gui/kernel/qshortcut.cpp2
-rw-r--r--src/gui/kernel/qshortcut_p.h2
-rw-r--r--src/gui/kernel/qshortcutmap.cpp181
-rw-r--r--src/gui/kernel/qshortcutmap_p.h1
-rw-r--r--src/gui/kernel/qsimpledrag.cpp7
-rw-r--r--src/gui/kernel/qstylehints.cpp8
-rw-r--r--src/gui/kernel/qstylehints_p.h2
-rw-r--r--src/gui/kernel/qsurfaceformat.cpp2
-rw-r--r--src/gui/kernel/qtestsupport_gui.cpp23
-rw-r--r--src/gui/kernel/qtestsupport_gui.h1
-rw-r--r--src/gui/kernel/qwindow.cpp185
-rw-r--r--src/gui/kernel/qwindow_p.h20
-rw-r--r--src/gui/kernel/qwindowsysteminterface.cpp139
-rw-r--r--src/gui/kernel/qwindowsysteminterface.h30
-rw-r--r--src/gui/kernel/qwindowsysteminterface_p.h14
-rw-r--r--src/gui/math3d/qmatrix4x4.cpp2
-rw-r--r--src/gui/math3d/qquaternion.cpp88
-rw-r--r--src/gui/math3d/qquaternion.h197
-rw-r--r--src/gui/opengl/platform/egl/qeglconvenience.cpp16
-rw-r--r--src/gui/opengl/qopengl.cpp3
-rw-r--r--src/gui/opengl/qopengl.h41
-rw-r--r--src/gui/opengl/qopenglextensions_p.h14
-rw-r--r--src/gui/opengl/qopenglfunctions.cpp26
-rw-r--r--src/gui/opengl/qopenglprogrambinarycache_p.h2
-rw-r--r--src/gui/painting/qbackingstore.cpp10
-rw-r--r--src/gui/painting/qbackingstoredefaultcompositor.cpp148
-rw-r--r--src/gui/painting/qbackingstoredefaultcompositor_p.h35
-rw-r--r--src/gui/painting/qbackingstorerhisupport.cpp45
-rw-r--r--src/gui/painting/qbackingstorerhisupport_p.h2
-rw-r--r--src/gui/painting/qbezier_p.h1
-rw-r--r--src/gui/painting/qblendfunctions.cpp4
-rw-r--r--src/gui/painting/qblendfunctions_p.h4
-rw-r--r--src/gui/painting/qcmyk_p.h88
-rw-r--r--src/gui/painting/qcolorclut_p.h127
-rw-r--r--src/gui/painting/qcolormatrix_p.h250
-rw-r--r--src/gui/painting/qcolorspace.cpp515
-rw-r--r--src/gui/painting/qcolorspace.h19
-rw-r--r--src/gui/painting/qcolorspace_p.h28
-rw-r--r--src/gui/painting/qcolortransferfunction_p.h76
-rw-r--r--src/gui/painting/qcolortransfertable_p.h106
-rw-r--r--src/gui/painting/qcolortransform.cpp1164
-rw-r--r--src/gui/painting/qcolortransform_p.h26
-rw-r--r--src/gui/painting/qcolortrc_p.h19
-rw-r--r--src/gui/painting/qcolortrclut.cpp77
-rw-r--r--src/gui/painting/qcolortrclut_p.h85
-rw-r--r--src/gui/painting/qcompositionfunctions.cpp30
-rw-r--r--src/gui/painting/qcoregraphics.mm35
-rw-r--r--src/gui/painting/qcoregraphics_p.h19
-rw-r--r--src/gui/painting/qcosmeticstroker.cpp4
-rw-r--r--src/gui/painting/qcssutil.cpp21
-rw-r--r--src/gui/painting/qdatabuffer_p.h3
-rw-r--r--src/gui/painting/qdrawhelper.cpp186
-rw-r--r--src/gui/painting/qdrawhelper_avx2.cpp33
-rw-r--r--src/gui/painting/qdrawhelper_mips_dsp.cpp4
-rw-r--r--src/gui/painting/qdrawhelper_neon.cpp6
-rw-r--r--src/gui/painting/qdrawhelper_p.h9
-rw-r--r--src/gui/painting/qdrawhelper_sse2.cpp12
-rw-r--r--src/gui/painting/qdrawhelper_sse4.cpp8
-rw-r--r--src/gui/painting/qfixed_p.h17
-rw-r--r--src/gui/painting/qicc.cpp973
-rw-r--r--src/gui/painting/qimageeffects.cpp327
-rw-r--r--src/gui/painting/qoutlinemapper.cpp2
-rw-r--r--src/gui/painting/qpagelayout.cpp196
-rw-r--r--src/gui/painting/qpagelayout.h13
-rw-r--r--src/gui/painting/qpageranges.cpp4
-rw-r--r--src/gui/painting/qpagesize.cpp4
-rw-r--r--src/gui/painting/qpagesize.h2
-rw-r--r--src/gui/painting/qpaintengine.cpp2
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp42
-rw-r--r--src/gui/painting/qpaintengineex.cpp4
-rw-r--r--src/gui/painting/qpainter.cpp79
-rw-r--r--src/gui/painting/qpainterpath.cpp20
-rw-r--r--src/gui/painting/qpainterpath_p.h15
-rw-r--r--src/gui/painting/qpathclipper.cpp3
-rw-r--r--src/gui/painting/qpdf.cpp401
-rw-r--r--src/gui/painting/qpdf_p.h51
-rw-r--r--src/gui/painting/qpdfwriter.cpp47
-rw-r--r--src/gui/painting/qpdfwriter.h12
-rw-r--r--src/gui/painting/qpen.cpp132
-rw-r--r--src/gui/painting/qpen.h16
-rw-r--r--src/gui/painting/qpen_p.h5
-rw-r--r--src/gui/painting/qpixellayout.cpp129
-rw-r--r--src/gui/painting/qpixellayout_p.h8
-rw-r--r--src/gui/painting/qplatformbackingstore.h5
-rw-r--r--src/gui/painting/qpolygon.cpp34
-rw-r--r--src/gui/painting/qrasterbackingstore.cpp2
-rw-r--r--src/gui/painting/qregion.cpp2
-rw-r--r--src/gui/painting/qrgbafloat.h26
-rw-r--r--src/gui/painting/qrgbafloat.qdoc14
-rw-r--r--src/gui/painting/qrhibackingstore.cpp30
-rw-r--r--src/gui/painting/qrhibackingstore_p.h1
-rw-r--r--src/gui/painting/qt_attribution.json12
-rw-r--r--src/gui/painting/qtransform.cpp191
-rw-r--r--src/gui/platform/android/qandroidnativeinterface.cpp16
-rw-r--r--src/gui/platform/darwin/qappleiconengine.mm464
-rw-r--r--src/gui/platform/darwin/qappleiconengine_p.h64
-rw-r--r--src/gui/platform/darwin/qapplekeymapper.mm159
-rw-r--r--src/gui/platform/darwin/qapplekeymapper_p.h14
-rw-r--r--src/gui/platform/darwin/qmacmimeregistry.mm14
-rw-r--r--src/gui/platform/darwin/qutimimeconverter.mm21
-rw-r--r--src/gui/platform/ios/PrivacyInfo.xcprivacy23
-rw-r--r--src/gui/platform/macos/qcocoanativeinterface.mm6
-rw-r--r--src/gui/platform/unix/dbusmenu/qdbusmenuconnection.cpp10
-rw-r--r--src/gui/platform/unix/dbusmenu/qdbusmenuconnection_p.h4
-rw-r--r--src/gui/platform/unix/dbusmenu/qdbusmenutypes.cpp14
-rw-r--r--src/gui/platform/unix/dbustray/qdbustrayicon.cpp12
-rw-r--r--src/gui/platform/unix/qgenericunixservices.cpp65
-rw-r--r--src/gui/platform/unix/qgenericunixservices_p.h1
-rw-r--r--src/gui/platform/unix/qgenericunixthemes.cpp311
-rw-r--r--src/gui/platform/unix/qunixnativeinterface.cpp26
-rw-r--r--src/gui/platform/unix/qxkbcommon.cpp94
-rw-r--r--src/gui/platform/unix/qxkbcommon_p.h57
-rw-r--r--src/gui/platform/wasm/qlocalfileapi.cpp16
-rw-r--r--src/gui/platform/wasm/qwasmlocalfileaccess.cpp100
-rw-r--r--src/gui/platform/wasm/qwasmnativeinterface.cpp17
-rw-r--r--src/gui/platform/windows/qwindowsguieventdispatcher.cpp2
-rw-r--r--src/gui/platform/windows/qwindowsmimeconverter.cpp18
-rw-r--r--src/gui/platform/windows/qwindowsnativeinterface.cpp26
-rw-r--r--src/gui/platform/windows/qwindowsthemecache.cpp79
-rw-r--r--src/gui/platform/windows/qwindowsthemecache_p.h35
-rw-r--r--src/gui/rhi/qrhi.cpp3997
-rw-r--r--src/gui/rhi/qrhi.h2026
-rw-r--r--src/gui/rhi/qrhi_p.h2422
-rw-r--r--src/gui/rhi/qrhi_p_p.h819
-rw-r--r--src/gui/rhi/qrhi_platform.h175
-rw-r--r--src/gui/rhi/qrhid3d11.cpp734
-rw-r--r--src/gui/rhi/qrhid3d11_p.h854
-rw-r--r--src/gui/rhi/qrhid3d11_p_p.h833
-rw-r--r--src/gui/rhi/qrhid3d12.cpp1255
-rw-r--r--src/gui/rhi/qrhid3d12_p.h1236
-rw-r--r--src/gui/rhi/qrhid3d12_p_p.h1194
-rw-r--r--src/gui/rhi/qrhid3dhelpers.cpp172
-rw-r--r--src/gui/rhi/qrhid3dhelpers_p.h53
-rw-r--r--src/gui/rhi/qrhigles2.cpp945
-rw-r--r--src/gui/rhi/qrhigles2_p.h1128
-rw-r--r--src/gui/rhi/qrhigles2_p_p.h1076
-rw-r--r--src/gui/rhi/qrhimetal.mm530
-rw-r--r--src/gui/rhi/qrhimetal_p.h497
-rw-r--r--src/gui/rhi/qrhimetal_p_p.h509
-rw-r--r--src/gui/rhi/qrhinull.cpp69
-rw-r--r--src/gui/rhi/qrhinull_p.h275
-rw-r--r--src/gui/rhi/qrhinull_p_p.h295
-rw-r--r--src/gui/rhi/qrhivulkan.cpp1078
-rw-r--r--src/gui/rhi/qrhivulkan_p.h1027
-rw-r--r--src/gui/rhi/qrhivulkan_p_p.h1001
-rw-r--r--src/gui/rhi/qrhivulkanext_p.h48
-rw-r--r--src/gui/rhi/qshader.cpp255
-rw-r--r--src/gui/rhi/qshader.h241
-rw-r--r--src/gui/rhi/qshader_p.h276
-rw-r--r--src/gui/rhi/qshader_p_p.h90
-rw-r--r--src/gui/rhi/qshaderdescription.cpp333
-rw-r--r--src/gui/rhi/qshaderdescription.h386
-rw-r--r--src/gui/rhi/qshaderdescription_p.h421
-rw-r--r--src/gui/rhi/qshaderdescription_p_p.h81
-rw-r--r--src/gui/text/coretext/qcoretextfontdatabase.mm63
-rw-r--r--src/gui/text/coretext/qcoretextfontdatabase_p.h1
-rw-r--r--src/gui/text/coretext/qfontengine_coretext.mm49
-rw-r--r--src/gui/text/coretext/qfontengine_coretext_p.h4
-rw-r--r--src/gui/text/freetype/qfontengine_ft.cpp202
-rw-r--r--src/gui/text/freetype/qfontengine_ft_p.h7
-rw-r--r--src/gui/text/freetype/qfreetypefontdatabase.cpp141
-rw-r--r--src/gui/text/freetype/qfreetypefontdatabase_p.h9
-rw-r--r--src/gui/text/qabstracttextdocumentlayout.cpp2
-rw-r--r--src/gui/text/qabstracttextdocumentlayout_p.h2
-rw-r--r--src/gui/text/qcssparser.cpp47
-rw-r--r--src/gui/text/qcssparser_p.h8
-rw-r--r--src/gui/text/qdistancefield.cpp2
-rw-r--r--src/gui/text/qfont.cpp563
-rw-r--r--src/gui/text/qfont.h76
-rw-r--r--src/gui/text/qfont_p.h30
-rw-r--r--src/gui/text/qfontdatabase.cpp133
-rw-r--r--src/gui/text/qfontdatabase.h5
-rw-r--r--src/gui/text/qfontdatabase_p.h2
-rw-r--r--src/gui/text/qfontengine.cpp177
-rw-r--r--src/gui/text/qfontengine_p.h39
-rw-r--r--src/gui/text/qfontinfo.h2
-rw-r--r--src/gui/text/qfontmetrics.cpp2
-rw-r--r--src/gui/text/qfontmetrics.h2
-rw-r--r--src/gui/text/qfontsubset.cpp22
-rw-r--r--src/gui/text/qplatformfontdatabase.cpp12
-rw-r--r--src/gui/text/qplatformfontdatabase.h2
-rw-r--r--src/gui/text/qrawfont.cpp34
-rw-r--r--src/gui/text/qrawfont.h1
-rw-r--r--src/gui/text/qtextcursor.cpp4
-rw-r--r--src/gui/text/qtextdocument.cpp171
-rw-r--r--src/gui/text/qtextdocument.h8
-rw-r--r--src/gui/text/qtextdocument_p.cpp8
-rw-r--r--src/gui/text/qtextdocument_p.h5
-rw-r--r--src/gui/text/qtextdocumentfragment.cpp13
-rw-r--r--src/gui/text/qtextdocumentlayout.cpp36
-rw-r--r--src/gui/text/qtextengine.cpp142
-rw-r--r--src/gui/text/qtextengine_p.h29
-rw-r--r--src/gui/text/qtextformat.cpp57
-rw-r--r--src/gui/text/qtexthtmlparser.cpp93
-rw-r--r--src/gui/text/qtexthtmlparser_p.h2
-rw-r--r--src/gui/text/qtextimagehandler.cpp14
-rw-r--r--src/gui/text/qtextlayout.cpp416
-rw-r--r--src/gui/text/qtextlist.cpp14
-rw-r--r--src/gui/text/qtextmarkdownimporter.cpp135
-rw-r--r--src/gui/text/qtextmarkdownimporter_p.h10
-rw-r--r--src/gui/text/qtextmarkdownwriter.cpp165
-rw-r--r--src/gui/text/qtextmarkdownwriter_p.h3
-rw-r--r--src/gui/text/qtextobject.cpp2
-rw-r--r--src/gui/text/qtextodfwriter.cpp3
-rw-r--r--src/gui/text/qtextoption.cpp2
-rw-r--r--src/gui/text/unix/qfontconfigdatabase.cpp229
-rw-r--r--src/gui/text/unix/qfontconfigdatabase_p.h1
-rw-r--r--src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp701
-rw-r--r--src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h24
-rw-r--r--src/gui/text/windows/qwindowsfontdatabase.cpp203
-rw-r--r--src/gui/text/windows/qwindowsfontdatabase_ft.cpp19
-rw-r--r--src/gui/text/windows/qwindowsfontdatabase_ft_p.h3
-rw-r--r--src/gui/text/windows/qwindowsfontdatabase_p.h15
-rw-r--r--src/gui/text/windows/qwindowsfontdatabasebase.cpp218
-rw-r--r--src/gui/text/windows/qwindowsfontdatabasebase_p.h14
-rw-r--r--src/gui/text/windows/qwindowsfontengine.cpp22
-rw-r--r--src/gui/text/windows/qwindowsfontengine_p.h4
-rw-r--r--src/gui/text/windows/qwindowsfontenginedirectwrite.cpp107
-rw-r--r--src/gui/text/windows/qwindowsfontenginedirectwrite_p.h15
-rw-r--r--src/gui/util/qastchandler.cpp6
-rw-r--r--src/gui/util/qdesktopservices.cpp9
-rw-r--r--src/gui/util/qgraphicsframecapture.cpp123
-rw-r--r--src/gui/util/qgraphicsframecapture_p.h55
-rw-r--r--src/gui/util/qgraphicsframecapture_p_p.h67
-rw-r--r--src/gui/util/qgraphicsframecapturemetal.mm169
-rw-r--r--src/gui/util/qgraphicsframecapturemetal_p_p.h57
-rw-r--r--src/gui/util/qgraphicsframecapturerenderdoc.cpp310
-rw-r--r--src/gui/util/qgraphicsframecapturerenderdoc_p_p.h53
-rw-r--r--src/gui/util/qgridlayoutengine.cpp70
-rw-r--r--src/gui/util/qgridlayoutengine_p.h11
-rw-r--r--src/gui/util/qktxhandler.cpp231
-rw-r--r--src/gui/util/qktxhandler_p.h4
-rw-r--r--src/gui/util/qvalidator.cpp93
-rw-r--r--src/gui/vulkan/licenseheader.h.in (renamed from src/gui/vulkan/generated_header.txt)0
-rw-r--r--src/gui/vulkan/qbasicvulkanplatforminstance.cpp9
-rw-r--r--src/gui/vulkan/qplatformvulkaninstance.cpp11
-rw-r--r--src/gui/vulkan/qplatformvulkaninstance.h2
-rw-r--r--src/gui/vulkan/qvulkandefaultinstance.cpp2
-rw-r--r--src/gui/vulkan/qvulkanfunctions.cpp24
-rw-r--r--src/gui/vulkan/qvulkaninstance.cpp8
-rw-r--r--src/gui/vulkan/qvulkanwindow.cpp125
-rw-r--r--src/gui/vulkan/qvulkanwindow.h10
-rw-r--r--src/gui/vulkan/qvulkanwindow_p.h2
-rw-r--r--src/network/CMakeLists.txt115
-rw-r--r--src/network/access/http2/hpack.cpp49
-rw-r--r--src/network/access/http2/hpack_p.h3
-rw-r--r--src/network/access/http2/hpacktable.cpp6
-rw-r--r--src/network/access/http2/http2frames.cpp13
-rw-r--r--src/network/access/http2/http2frames_p.h19
-rw-r--r--src/network/access/http2/http2protocol.cpp50
-rw-r--r--src/network/access/http2/http2protocol_p.h3
-rw-r--r--src/network/access/qabstractnetworkcache.cpp43
-rw-r--r--src/network/access/qabstractnetworkcache.h3
-rw-r--r--src/network/access/qabstractprotocolhandler_p.h4
-rw-r--r--src/network/access/qdecompresshelper.cpp26
-rw-r--r--src/network/access/qdecompresshelper_p.h4
-rw-r--r--src/network/access/qhsts.cpp62
-rw-r--r--src/network/access/qhsts_p.h6
-rw-r--r--src/network/access/qhstspolicy.cpp4
-rw-r--r--src/network/access/qhttp1configuration.h2
-rw-r--r--src/network/access/qhttp2configuration.h2
-rw-r--r--src/network/access/qhttp2connection.cpp1752
-rw-r--r--src/network/access/qhttp2connection_p.h372
-rw-r--r--src/network/access/qhttp2protocolhandler.cpp359
-rw-r--r--src/network/access/qhttp2protocolhandler_p.h5
-rw-r--r--src/network/access/qhttpheaderparser.cpp42
-rw-r--r--src/network/access/qhttpheaderparser_p.h15
-rw-r--r--src/network/access/qhttpheaders.cpp1551
-rw-r--r--src/network/access/qhttpheaders.h282
-rw-r--r--src/network/access/qhttpheadershelper.cpp25
-rw-r--r--src/network/access/qhttpheadershelper_p.h30
-rw-r--r--src/network/access/qhttpmultipart.cpp49
-rw-r--r--src/network/access/qhttpmultipart.h4
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp205
-rw-r--r--src/network/access/qhttpnetworkconnection_p.h49
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp98
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel_p.h1
-rw-r--r--src/network/access/qhttpnetworkheader.cpp6
-rw-r--r--src/network/access/qhttpnetworkheader_p.h11
-rw-r--r--src/network/access/qhttpnetworkreply.cpp48
-rw-r--r--src/network/access/qhttpnetworkreply_p.h32
-rw-r--r--src/network/access/qhttpnetworkrequest.cpp16
-rw-r--r--src/network/access/qhttpnetworkrequest_p.h4
-rw-r--r--src/network/access/qhttpprotocolhandler.cpp18
-rw-r--r--src/network/access/qhttpthreaddelegate.cpp18
-rw-r--r--src/network/access/qhttpthreaddelegate_p.h24
-rw-r--r--src/network/access/qnetworkaccesscache.cpp3
-rw-r--r--src/network/access/qnetworkaccesscache_p.h3
-rw-r--r--src/network/access/qnetworkaccesscachebackend.cpp10
-rw-r--r--src/network/access/qnetworkaccessdebugpipebackend.cpp2
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp129
-rw-r--r--src/network/access/qnetworkaccessmanager.h24
-rw-r--r--src/network/access/qnetworkaccessmanager_p.h2
-rw-r--r--src/network/access/qnetworkcookie.cpp79
-rw-r--r--src/network/access/qnetworkcookie.h3
-rw-r--r--src/network/access/qnetworkcookie_p.h4
-rw-r--r--src/network/access/qnetworkcookiejar.cpp65
-rw-r--r--src/network/access/qnetworkdiskcache.cpp74
-rw-r--r--src/network/access/qnetworkreply.cpp62
-rw-r--r--src/network/access/qnetworkreply.h10
-rw-r--r--src/network/access/qnetworkreplyfileimpl.cpp2
-rw-r--r--src/network/access/qnetworkreplyfileimpl_p.h8
-rw-r--r--src/network/access/qnetworkreplyhttpimpl.cpp200
-rw-r--r--src/network/access/qnetworkreplyhttpimpl_p.h2
-rw-r--r--src/network/access/qnetworkreplyimpl.cpp7
-rw-r--r--src/network/access/qnetworkreplywasmimpl.cpp28
-rw-r--r--src/network/access/qnetworkreplywasmimpl_p.h4
-rw-r--r--src/network/access/qnetworkrequest.cpp362
-rw-r--r--src/network/access/qnetworkrequest.h46
-rw-r--r--src/network/access/qnetworkrequest_p.h14
-rw-r--r--src/network/access/qnetworkrequestfactory.cpp727
-rw-r--r--src/network/access/qnetworkrequestfactory.h100
-rw-r--r--src/network/access/qnetworkrequestfactory_p.h56
-rw-r--r--src/network/access/qrestaccessmanager.cpp828
-rw-r--r--src/network/access/qrestaccessmanager.h127
-rw-r--r--src/network/access/qrestaccessmanager_p.h89
-rw-r--r--src/network/access/qrestreply.cpp608
-rw-r--r--src/network/access/qrestreply.h71
-rw-r--r--src/network/access/qrestreply_p.h40
-rw-r--r--src/network/access/qsocketabstraction_p.h91
-rw-r--r--src/network/android/jar/build.gradle6
-rw-r--r--src/network/compat/removed_api.cpp67
-rw-r--r--src/network/configure.cmake56
-rw-r--r--src/network/doc/qtnetwork.qdocconf11
-rw-r--r--src/network/doc/snippets/CMakeLists.txt2
-rw-r--r--src/network/doc/snippets/code/doc_src_qtnetwork.cpp6
-rw-r--r--src/network/doc/snippets/code/src_network_access_qhttpmultipart.cpp2
-rw-r--r--src/network/doc/snippets/code/src_network_access_qhttppart.cpp2
-rw-r--r--src/network/doc/snippets/code/src_network_access_qnetworkrequestfactory.cpp27
-rw-r--r--src/network/doc/snippets/code/src_network_access_qrestaccessmanager.cpp104
-rw-r--r--src/network/doc/snippets/code/src_network_kernel_qnetworkinterface.cpp2
-rw-r--r--src/network/doc/snippets/code/src_network_ssl_qsslconfiguration.cpp7
-rw-r--r--src/network/doc/snippets/code/src_network_ssl_qsslpresharedkeyauthenticator.cpp2
-rw-r--r--src/network/doc/snippets/code/src_network_ssl_qsslsocket.cpp6
-rw-r--r--src/network/doc/snippets/network/CMakeLists.txt2
-rw-r--r--src/network/doc/src/ssl.qdoc2
-rw-r--r--src/network/kernel/qauthenticator.cpp59
-rw-r--r--src/network/kernel/qauthenticator.h1
-rw-r--r--src/network/kernel/qauthenticator_p.h4
-rw-r--r--src/network/kernel/qdnslookup.cpp238
-rw-r--r--src/network/kernel/qdnslookup.h13
-rw-r--r--src/network/kernel/qdnslookup_android.cpp20
-rw-r--r--src/network/kernel/qdnslookup_dummy.cpp15
-rw-r--r--src/network/kernel/qdnslookup_p.h158
-rw-r--r--src/network/kernel/qdnslookup_unix.cpp543
-rw-r--r--src/network/kernel/qdnslookup_win.cpp150
-rw-r--r--src/network/kernel/qhostaddress.cpp2
-rw-r--r--src/network/kernel/qhostinfo.cpp120
-rw-r--r--src/network/kernel/qhostinfo.h63
-rw-r--r--src/network/kernel/qhostinfo_p.h30
-rw-r--r--src/network/kernel/qhostinfo_unix.cpp228
-rw-r--r--src/network/kernel/qnetconmonitor_win.cpp6
-rw-r--r--src/network/kernel/qnetworkdatagram.cpp2
-rw-r--r--src/network/kernel/qnetworkinformation.cpp78
-rw-r--r--src/network/kernel/qnetworkinformation.h2
-rw-r--r--src/network/kernel/qnetworkinformation_p.h37
-rw-r--r--src/network/kernel/qnetworkinterface_linux.cpp9
-rw-r--r--src/network/kernel/qnetworkinterface_unix.cpp59
-rw-r--r--src/network/kernel/qnetworkproxy.cpp47
-rw-r--r--src/network/kernel/qnetworkproxy.h5
-rw-r--r--src/network/kernel/qnetworkproxy_android.cpp2
-rw-r--r--src/network/kernel/qnetworkproxy_darwin.cpp8
-rw-r--r--src/network/kernel/qnetworkproxy_libproxy.cpp9
-rw-r--r--src/network/kernel/qtnetworkglobal_p.h1
-rw-r--r--src/network/socket/qabstractsocket.cpp62
-rw-r--r--src/network/socket/qabstractsocket_p.h1
-rw-r--r--src/network/socket/qabstractsocketengine_p.h14
-rw-r--r--src/network/socket/qhttpsocketengine.cpp86
-rw-r--r--src/network/socket/qhttpsocketengine_p.h11
-rw-r--r--src/network/socket/qlocalserver.cpp20
-rw-r--r--src/network/socket/qlocalserver.h1
-rw-r--r--src/network/socket/qlocalserver_unix.cpp3
-rw-r--r--src/network/socket/qlocalsocket_unix.cpp18
-rw-r--r--src/network/socket/qnativesocketengine.cpp30
-rw-r--r--src/network/socket/qnativesocketengine_p.h63
-rw-r--r--src/network/socket/qnativesocketengine_p_p.h44
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp42
-rw-r--r--src/network/socket/qnativesocketengine_win.cpp33
-rw-r--r--src/network/socket/qnet_unix_p.h11
-rw-r--r--src/network/socket/qsctpsocket.cpp3
-rw-r--r--src/network/socket/qsocks5socketengine.cpp72
-rw-r--r--src/network/socket/qsocks5socketengine_p.h11
-rw-r--r--src/network/socket/qtcpserver.cpp2
-rw-r--r--src/network/socket/qudpsocket.cpp4
-rw-r--r--src/network/ssl/qssl.cpp2
-rw-r--r--src/network/ssl/qssl.h13
-rw-r--r--src/network/ssl/qsslcertificate.cpp72
-rw-r--r--src/network/ssl/qsslcertificate_p.h4
-rw-r--r--src/network/ssl/qsslconfiguration.cpp33
-rw-r--r--src/network/ssl/qssldiffiehellmanparameters.cpp13
-rw-r--r--src/network/ssl/qsslpresharedkeyauthenticator.h1
-rw-r--r--src/network/ssl/qsslserver.cpp4
-rw-r--r--src/network/ssl/qsslsocket.cpp34
-rw-r--r--src/network/ssl/qsslsocket.h2
-rw-r--r--src/network/ssl/qtlsbackend.cpp22
-rw-r--r--src/network/ssl/qtlsbackend_p.h17
-rw-r--r--src/opengl/CMakeLists.txt17
-rw-r--r--src/opengl/doc/qtopengl.qdocconf15
-rw-r--r--src/opengl/doc/snippets/CMakeLists.txt2
-rw-r--r--src/opengl/doc/src/qt6-changes.qdoc2
-rw-r--r--src/opengl/doc/src/qtopengl-examples.qdoc2
-rw-r--r--src/opengl/doc/src/qtopengl-index.qdoc2
-rw-r--r--src/opengl/qopenglcompositor.cpp49
-rw-r--r--src/opengl/qopenglcompositor_p.h17
-rw-r--r--src/opengl/qopenglcompositorbackingstore.cpp7
-rw-r--r--src/opengl/qopenglcustomshaderstage.cpp2
-rw-r--r--src/opengl/qopenglframebufferobject.cpp38
-rw-r--r--src/opengl/qopenglfunctions_2_0.cpp1
-rw-r--r--src/opengl/qopenglfunctions_2_0.h2
-rw-r--r--src/opengl/qopenglfunctions_2_1.cpp1
-rw-r--r--src/opengl/qopenglfunctions_2_1.h2
-rw-r--r--src/opengl/qopenglfunctions_3_0.cpp2
-rw-r--r--src/opengl/qopenglfunctions_3_0.h4
-rw-r--r--src/opengl/qopenglfunctions_3_2_compatibility.cpp2
-rw-r--r--src/opengl/qopenglfunctions_3_2_compatibility.h4
-rw-r--r--src/opengl/qopenglfunctions_3_3_compatibility.cpp1
-rw-r--r--src/opengl/qopenglfunctions_3_3_compatibility.h2
-rw-r--r--src/opengl/qopenglfunctions_4_0_compatibility.cpp1
-rw-r--r--src/opengl/qopenglfunctions_4_0_compatibility.h2
-rw-r--r--src/opengl/qopenglfunctions_4_1_compatibility.cpp1
-rw-r--r--src/opengl/qopenglfunctions_4_1_compatibility.h2
-rw-r--r--src/opengl/qopenglfunctions_4_2_compatibility.cpp1
-rw-r--r--src/opengl/qopenglfunctions_4_2_compatibility.h2
-rw-r--r--src/opengl/qopenglfunctions_4_3_compatibility.cpp1
-rw-r--r--src/opengl/qopenglfunctions_4_3_compatibility.h2
-rw-r--r--src/opengl/qopenglfunctions_4_5_compatibility.h63
-rw-r--r--src/opengl/qopenglfunctions_4_5_core.h63
-rw-r--r--src/opengl/qopenglversionfunctions.h18
-rw-r--r--src/opengl/qopenglversionfunctionsfactory.cpp2
-rw-r--r--src/opengl/qopenglwindow.cpp2
-rw-r--r--src/openglwidgets/CMakeLists.txt2
-rw-r--r--src/openglwidgets/qopenglwidget.cpp129
-rw-r--r--src/platformsupport/devicediscovery/CMakeLists.txt1
-rw-r--r--src/platformsupport/fbconvenience/CMakeLists.txt1
-rw-r--r--src/platformsupport/fbconvenience/qfbscreen.cpp8
-rw-r--r--src/platformsupport/input/CMakeLists.txt1
-rw-r--r--src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h2
-rw-r--r--src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp2
-rw-r--r--src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp11
-rw-r--r--src/platformsupport/input/libinput/qlibinputhandler.cpp2
-rw-r--r--src/platformsupport/input/libinput/qlibinputkeyboard.cpp2
-rw-r--r--src/platformsupport/input/libinput/qlibinputtouch.cpp28
-rw-r--r--src/platformsupport/input/tslib/qtslib.cpp9
-rw-r--r--src/platformsupport/kmsconvenience/CMakeLists.txt1
-rw-r--r--src/platformsupport/kmsconvenience/qkmsdevice.cpp1
-rw-r--r--src/plugins/CMakeLists.txt2
-rw-r--r--src/plugins/doc/snippets/code/src_plugins_platforms_qnx_qqnxwindow.cpp2
-rw-r--r--src/plugins/generic/CMakeLists.txt4
-rw-r--r--src/plugins/generic/tuiotouch/qtuiohandler.cpp1
-rw-r--r--src/plugins/imageformats/ico/qicohandler.cpp5
-rw-r--r--src/plugins/imageformats/ico/qicohandler.h2
-rw-r--r--src/plugins/imageformats/jpeg/qjpeghandler.cpp107
-rw-r--r--src/plugins/networkinformation/android/CMakeLists.txt2
-rw-r--r--src/plugins/networkinformation/android/jar/build.gradle6
-rw-r--r--src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp4
-rw-r--r--src/plugins/networkinformation/glib/qglibnetworkinformationbackend.cpp31
-rw-r--r--src/plugins/networkinformation/networklistmanager/CMakeLists.txt3
-rw-r--r--src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp40
-rw-r--r--src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp1
-rw-r--r--src/plugins/networkinformation/networkmanager/CMakeLists.txt1
-rw-r--r--src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp99
-rw-r--r--src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.h60
-rw-r--r--src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp95
-rw-r--r--src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h15
-rw-r--r--src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml12
-rw-r--r--src/plugins/platforminputcontexts/ibus/main.cpp2
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.cpp3
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h68
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp40
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h3
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusproxy.h2
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusproxyportal.cpp3
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusproxyportal.h19
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibustypes.cpp40
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibustypes.h40
-rw-r--r--src/plugins/platforms/CMakeLists.txt6
-rw-r--r--src/plugins/platforms/android/CMakeLists.txt24
-rw-r--r--src/plugins/platforms/android/androidcontentfileengine.cpp110
-rw-r--r--src/plugins/platforms/android/androidcontentfileengine.h17
-rw-r--r--src/plugins/platforms/android/androidjniaccessibility.cpp35
-rw-r--r--src/plugins/platforms/android/androidjniaccessibility.h4
-rw-r--r--src/plugins/platforms/android/androidjniclipboard.cpp96
-rw-r--r--src/plugins/platforms/android/androidjniclipboard.h27
-rw-r--r--src/plugins/platforms/android/androidjniinput.cpp335
-rw-r--r--src/plugins/platforms/android/androidjniinput.h27
-rw-r--r--src/plugins/platforms/android/androidjnimain.cpp447
-rw-r--r--src/plugins/platforms/android/androidjnimain.h25
-rw-r--r--src/plugins/platforms/android/androidjnimenu.cpp60
-rw-r--r--src/plugins/platforms/android/androidjnimenu.h5
-rw-r--r--src/plugins/platforms/android/androidsurfaceclient.h24
-rw-r--r--src/plugins/platforms/android/androidwindowembedding.cpp70
-rw-r--r--src/plugins/platforms/android/androidwindowembedding.h41
-rw-r--r--src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp53
-rw-r--r--src/plugins/platforms/android/qandroidassetsfileenginehandler.h3
-rw-r--r--src/plugins/platforms/android/qandroidinputcontext.cpp152
-rw-r--r--src/plugins/platforms/android/qandroidinputcontext.h6
-rw-r--r--src/plugins/platforms/android/qandroidplatformaccessibility.cpp2
-rw-r--r--src/plugins/platforms/android/qandroidplatformbackingstore.cpp52
-rw-r--r--src/plugins/platforms/android/qandroidplatformbackingstore.h29
-rw-r--r--src/plugins/platforms/android/qandroidplatformclipboard.cpp83
-rw-r--r--src/plugins/platforms/android/qandroidplatformclipboard.h16
-rw-r--r--src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp14
-rw-r--r--src/plugins/platforms/android/qandroidplatformdialoghelpers.h5
-rw-r--r--src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp19
-rw-r--r--src/plugins/platforms/android/qandroidplatformfontdatabase.cpp33
-rw-r--r--src/plugins/platforms/android/qandroidplatformforeignwindow.cpp89
-rw-r--r--src/plugins/platforms/android/qandroidplatformforeignwindow.h14
-rw-r--r--src/plugins/platforms/android/qandroidplatformiconengine.cpp616
-rw-r--r--src/plugins/platforms/android/qandroidplatformiconengine.h44
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.cpp88
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.h2
-rw-r--r--src/plugins/platforms/android/qandroidplatformmenu.cpp2
-rw-r--r--src/plugins/platforms/android/qandroidplatformopenglwindow.cpp72
-rw-r--r--src/plugins/platforms/android/qandroidplatformopenglwindow.h9
-rw-r--r--src/plugins/platforms/android/qandroidplatformscreen.cpp345
-rw-r--r--src/plugins/platforms/android/qandroidplatformscreen.h43
-rw-r--r--src/plugins/platforms/android/qandroidplatformservices.cpp29
-rw-r--r--src/plugins/platforms/android/qandroidplatformtheme.cpp28
-rw-r--r--src/plugins/platforms/android/qandroidplatformtheme.h5
-rw-r--r--src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp50
-rw-r--r--src/plugins/platforms/android/qandroidplatformvulkanwindow.h11
-rw-r--r--src/plugins/platforms/android/qandroidplatformwindow.cpp268
-rw-r--r--src/plugins/platforms/android/qandroidplatformwindow.h68
-rw-r--r--src/plugins/platforms/android/qandroidsystemlocale.cpp45
-rw-r--r--src/plugins/platforms/android/qandroidsystemlocale.h3
-rw-r--r--src/plugins/platforms/cocoa/CMakeLists.txt1
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm502
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm88
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.h4
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.mm134
-rw-r--r--src/plugins/platforms/cocoa/qcocoadrag.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoadrag.mm20
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.h19
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm62
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm358
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.h13
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.mm9
-rw-r--r--src/plugins/platforms/cocoa/qcocoainputcontext.mm11
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.h7
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm52
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm20
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.h4
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.mm123
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.mm106
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuloader.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoamessagedialog.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoamessagedialog.mm132
-rw-r--r--src/plugins/platforms/cocoa/qcocoansmenu.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoascreen.h4
-rw-r--r--src/plugins/platforms/cocoa/qcocoascreen.mm100
-rw-r--r--src/plugins/platforms/cocoa/qcocoaservices.h10
-rw-r--r--src/plugins/platforms/cocoa/qcocoaservices.mm50
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm13
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.h4
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.mm55
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm261
-rw-r--r--src/plugins/platforms/cocoa/qmacclipboard.h2
-rw-r--r--src/plugins/platforms/cocoa/qnsview.h6
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm53
-rw-r--r--src/plugins/platforms/cocoa/qnsview_accessibility.mm14
-rw-r--r--src/plugins/platforms/cocoa/qnsview_complextext.mm30
-rw-r--r--src/plugins/platforms/cocoa/qnsview_dragging.mm4
-rw-r--r--src/plugins/platforms/cocoa/qnsview_drawing.mm41
-rw-r--r--src/plugins/platforms/cocoa/qnsview_keys.mm44
-rw-r--r--src/plugins/platforms/cocoa/qnsview_menus.mm114
-rw-r--r--src/plugins/platforms/cocoa/qnsview_mouse.mm41
-rw-r--r--src/plugins/platforms/cocoa/qnsview_touch.mm20
-rw-r--r--src/plugins/platforms/cocoa/qnswindow.h2
-rw-r--r--src/plugins/platforms/cocoa/qnswindow.mm39
-rw-r--r--src/plugins/platforms/cocoa/qnswindowdelegate.mm4
-rw-r--r--src/plugins/platforms/direct2d/CMakeLists.txt20
-rw-r--r--src/plugins/platforms/directfb/qdirectfbblitter.cpp2
-rw-r--r--src/plugins/platforms/directfb/qdirectfbconvenience.h2
-rw-r--r--src/plugins/platforms/directfb/qdirectfbinput.cpp2
-rw-r--r--src/plugins/platforms/eglfs/CMakeLists.txt2
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfscursor.cpp18
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp6
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsintegration.cpp11
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsintegration_p.h2
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfsscreen.cpp2
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfswindow.cpp2
-rw-r--r--src/plugins/platforms/eglfs/api/qeglfswindow_p.h4
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/CMakeLists.txt6
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/CMakeLists.txt1
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp38
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen_p.h2
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp5
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp62
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h3
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/CMakeLists.txt1
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qlinuxmediadevice.cpp2
-rw-r--r--src/plugins/platforms/haiku/qhaikuintegration.cpp4
-rw-r--r--src/plugins/platforms/haiku/qhaikuwindow.cpp2
-rw-r--r--src/plugins/platforms/ios/CMakeLists.txt30
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h4
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm41
-rw-r--r--src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileenginefactory.h9
-rw-r--r--src/plugins/platforms/ios/qiosapplicationdelegate.mm45
-rw-r--r--src/plugins/platforms/ios/qiosclipboard.mm45
-rw-r--r--src/plugins/platforms/ios/qioscolordialog.mm4
-rw-r--r--src/plugins/platforms/ios/qioscontext.mm2
-rw-r--r--src/plugins/platforms/ios/qiosdocumentpickercontroller.mm8
-rw-r--r--src/plugins/platforms/ios/qiosfiledialog.h1
-rw-r--r--src/plugins/platforms/ios/qiosfiledialog.mm49
-rw-r--r--src/plugins/platforms/ios/qiosfontdialog.mm4
-rw-r--r--src/plugins/platforms/ios/qiosglobal.h9
-rw-r--r--src/plugins/platforms/ios/qiosglobal.mm53
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.mm29
-rw-r--r--src/plugins/platforms/ios/qiosintegration.h12
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm28
-rw-r--r--src/plugins/platforms/ios/qiosmenu.h2
-rw-r--r--src/plugins/platforms/ios/qiosmenu.mm2
-rw-r--r--src/plugins/platforms/ios/qiosmessagedialog.mm30
-rw-r--r--src/plugins/platforms/ios/qiosplatformaccessibility.mm30
-rw-r--r--src/plugins/platforms/ios/qiosscreen.h21
-rw-r--r--src/plugins/platforms/ios/qiosscreen.mm265
-rw-r--r--src/plugins/platforms/ios/qiostextinputoverlay.mm31
-rw-r--r--src/plugins/platforms/ios/qiostextresponder.mm22
-rw-r--r--src/plugins/platforms/ios/qiostheme.h3
-rw-r--r--src/plugins/platforms/ios/qiostheme.mm55
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.h4
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.mm115
-rw-r--r--src/plugins/platforms/ios/qioswindow.h12
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm231
-rw-r--r--src/plugins/platforms/ios/quiaccessibilityelement.h2
-rw-r--r--src/plugins/platforms/ios/quiaccessibilityelement.mm17
-rw-r--r--src/plugins/platforms/ios/quiview.h3
-rw-r--r--src/plugins/platforms/ios/quiview.mm39
-rw-r--r--src/plugins/platforms/ios/quiview_accessibility.mm1
-rw-r--r--src/plugins/platforms/ios/quiwindow.h13
-rw-r--r--src/plugins/platforms/ios/quiwindow.mm56
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenwindow.cpp4
-rw-r--r--src/plugins/platforms/qnx/CMakeLists.txt6
-rw-r--r--src/plugins/platforms/qnx/qqnxabstractnavigator.cpp10
-rw-r--r--src/plugins/platforms/qnx/qqnxabstractnavigator.h3
-rw-r--r--src/plugins/platforms/qnx/qqnxbuffer.cpp24
-rw-r--r--src/plugins/platforms/qnx/qqnxbuffer.h3
-rw-r--r--src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp28
-rw-r--r--src/plugins/platforms/qnx/qqnxbuttoneventnotifier.h6
-rw-r--r--src/plugins/platforms/qnx/qqnxclipboard.cpp24
-rw-r--r--src/plugins/platforms/qnx/qqnxclipboard.h2
-rw-r--r--src/plugins/platforms/qnx/qqnxcursor.cpp12
-rw-r--r--src/plugins/platforms/qnx/qqnxcursor.h3
-rw-r--r--src/plugins/platforms/qnx/qqnxeglwindow.cpp12
-rw-r--r--src/plugins/platforms/qnx/qqnxeglwindow.h3
-rw-r--r--src/plugins/platforms/qnx/qqnxglcontext.cpp12
-rw-r--r--src/plugins/platforms/qnx/qqnxglobal.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp116
-rw-r--r--src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp22
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.cpp56
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.h8
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp20
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h3
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp31
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.h3
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatorpps.cpp25
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatorpps.h6
-rw-r--r--src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp20
-rw-r--r--src/plugins/platforms/qnx/qqnxrasterwindow.cpp14
-rw-r--r--src/plugins/platforms/qnx/qqnxscreen.cpp58
-rw-r--r--src/plugins/platforms/qnx/qqnxscreen.h4
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp53
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventhandler.h3
-rw-r--r--src/plugins/platforms/qnx/qqnxscreeneventthread.cpp14
-rw-r--r--src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp24
-rw-r--r--src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h2
-rw-r--r--src/plugins/platforms/qnx/qqnxwindow.cpp58
-rw-r--r--src/plugins/platforms/qnx/qqnxwindow.h3
-rw-r--r--src/plugins/platforms/vkkhrdisplay/qvkkhrdisplayvulkaninstance.cpp2
-rw-r--r--src/plugins/platforms/wasm/CMakeLists.txt3
-rw-r--r--src/plugins/platforms/wasm/main.cpp4
-rw-r--r--src/plugins/platforms/wasm/qtloader.js827
-rw-r--r--src/plugins/platforms/wasm/qwasmaccessibility.cpp100
-rw-r--r--src/plugins/platforms/wasm/qwasmaccessibility.h8
-rw-r--r--src/plugins/platforms/wasm/qwasmbackingstore.cpp34
-rw-r--r--src/plugins/platforms/wasm/qwasmbase64iconstore.h1
-rw-r--r--src/plugins/platforms/wasm/qwasmclipboard.cpp49
-rw-r--r--src/plugins/platforms/wasm/qwasmclipboard.h2
-rw-r--r--src/plugins/platforms/wasm/qwasmcompositor.cpp216
-rw-r--r--src/plugins/platforms/wasm/qwasmcompositor.h45
-rw-r--r--src/plugins/platforms/wasm/qwasmcssstyle.cpp7
-rw-r--r--src/plugins/platforms/wasm/qwasmcursor.cpp27
-rw-r--r--src/plugins/platforms/wasm/qwasmdom.cpp264
-rw-r--r--src/plugins/platforms/wasm/qwasmdom.h32
-rw-r--r--src/plugins/platforms/wasm/qwasmdrag.cpp291
-rw-r--r--src/plugins/platforms/wasm/qwasmdrag.h47
-rw-r--r--src/plugins/platforms/wasm/qwasmevent.cpp50
-rw-r--r--src/plugins/platforms/wasm/qwasmevent.h28
-rw-r--r--src/plugins/platforms/wasm/qwasmeventdispatcher.cpp24
-rw-r--r--src/plugins/platforms/wasm/qwasmeventdispatcher.h3
-rw-r--r--src/plugins/platforms/wasm/qwasmfontdatabase.cpp418
-rw-r--r--src/plugins/platforms/wasm/qwasmfontdatabase.h27
-rw-r--r--src/plugins/platforms/wasm/qwasminputcontext.cpp65
-rw-r--r--src/plugins/platforms/wasm/qwasminputcontext.h6
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.cpp150
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.h20
-rw-r--r--src/plugins/platforms/wasm/qwasmoffscreensurface.cpp5
-rw-r--r--src/plugins/platforms/wasm/qwasmoffscreensurface.h1
-rw-r--r--src/plugins/platforms/wasm/qwasmopenglcontext.cpp88
-rw-r--r--src/plugins/platforms/wasm/qwasmopenglcontext.h6
-rw-r--r--src/plugins/platforms/wasm/qwasmplatform.cpp5
-rw-r--r--src/plugins/platforms/wasm/qwasmplatform.h2
-rw-r--r--src/plugins/platforms/wasm/qwasmscreen.cpp75
-rw-r--r--src/plugins/platforms/wasm/qwasmscreen.h17
-rw-r--r--src/plugins/platforms/wasm/qwasmservices.cpp2
-rw-r--r--src/plugins/platforms/wasm/qwasmwindow.cpp248
-rw-r--r--src/plugins/platforms/wasm/qwasmwindow.h41
-rw-r--r--src/plugins/platforms/wasm/qwasmwindowclientarea.cpp88
-rw-r--r--src/plugins/platforms/wasm/qwasmwindowclientarea.h6
-rw-r--r--src/plugins/platforms/wasm/qwasmwindownonclientarea.cpp25
-rw-r--r--src/plugins/platforms/wasm/qwasmwindowtreenode.cpp108
-rw-r--r--src/plugins/platforms/wasm/qwasmwindowtreenode.h53
-rw-r--r--src/plugins/platforms/wasm/wasm_shell.html74
-rw-r--r--src/plugins/platforms/windows/CMakeLists.txt26
-rw-r--r--src/plugins/platforms/windows/qtwindowsglobal.h4
-rw-r--r--src/plugins/platforms/windows/qwindowsapplication.cpp9
-rw-r--r--src/plugins/platforms/windows/qwindowsapplication.h3
-rw-r--r--src/plugins/platforms/windows/qwindowsbackingstore.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowscombase.h80
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp64
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.h6
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.cpp25
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.cpp44
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.cpp16
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.h6
-rw-r--r--src/plugins/platforms/windows/qwindowsdropdataobject.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowsglcontext.cpp1
-rw-r--r--src/plugins/platforms/windows/qwindowsiconengine.cpp394
-rw-r--r--src/plugins/platforms/windows/qwindowsiconengine.h47
-rw-r--r--src/plugins/platforms/windows/qwindowsinputcontext.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp80
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.h5
-rw-r--r--src/plugins/platforms/windows/qwindowskeymapper.cpp96
-rw-r--r--src/plugins/platforms/windows/qwindowskeymapper.h8
-rw-r--r--src/plugins/platforms/windows/qwindowsmenu.h1
-rw-r--r--src/plugins/platforms/windows/qwindowsmimeregistry.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.cpp29
-rw-r--r--src/plugins/platforms/windows/qwindowsole.h6
-rw-r--r--src/plugins/platforms/windows/qwindowspointerhandler.cpp55
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.cpp231
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.h15
-rw-r--r--src/plugins/platforms/windows/qwindowsservices.cpp7
-rw-r--r--src/plugins/platforms/windows/qwindowssystemtrayicon.cpp59
-rw-r--r--src/plugins/platforms/windows/qwindowssystemtrayicon.h2
-rw-r--r--src/plugins/platforms/windows/qwindowstabletsupport.cpp3
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.cpp439
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.h15
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp232
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h7
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp26
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h1
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h4
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.h2
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h2
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h3
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h3
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp132
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h9
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h2
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp38
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h2
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp168
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h21
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h2
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h3
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp21
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h19
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp53
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h4
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h3
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp3
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiautils.h2
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp74
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h70
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h3
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.h3
-rw-r--r--src/plugins/platforms/xcb/CMakeLists.txt13
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp5
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.h3
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp17
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp11
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp2
-rw-r--r--src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp2
-rw-r--r--src/plugins/platforms/xcb/qxcbatom.cpp8
-rw-r--r--src/plugins/platforms/xcb/qxcbatom.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbbackingstore.cpp2
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp11
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h3
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp49
-rw-r--r--src/plugins/platforms/xcb/qxcbcursor.cpp8
-rw-r--r--src/plugins/platforms/xcb/qxcbcursor.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbdrag.cpp11
-rw-r--r--src/plugins/platforms/xcb/qxcbimage.h1
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp50
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.h5
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp14
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.h8
-rw-r--r--src/plugins/platforms/xcb/qxcbmime.cpp7
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp235
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h14
-rw-r--r--src/plugins/platformthemes/gtk3/CMakeLists.txt9
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp2
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3interface.cpp57
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3interface_p.h2
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3portalinterface.cpp123
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3portalinterface_p.h49
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3storage.cpp247
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3storage_p.h7
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3theme.cpp14
-rw-r--r--src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp28
-rw-r--r--src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp29
-rw-r--r--src/plugins/printsupport/cups/qcupsprintengine.cpp24
-rw-r--r--src/plugins/sqldrivers/.cmake.conf2
-rw-r--r--src/plugins/sqldrivers/CMakeLists.txt8
-rw-r--r--src/plugins/sqldrivers/db2/qsql_db2.cpp4
-rw-r--r--src/plugins/sqldrivers/ibase/CMakeLists.txt1
-rw-r--r--src/plugins/sqldrivers/ibase/qsql_ibase.cpp162
-rw-r--r--src/plugins/sqldrivers/mimer/CMakeLists.txt1
-rw-r--r--src/plugins/sqldrivers/mimer/qsql_mimer.cpp238
-rw-r--r--src/plugins/sqldrivers/mysql/CMakeLists.txt1
-rw-r--r--src/plugins/sqldrivers/mysql/qsql_mysql.cpp215
-rw-r--r--src/plugins/sqldrivers/oci/qsql_oci.cpp92
-rw-r--r--src/plugins/sqldrivers/odbc/CMakeLists.txt1
-rw-r--r--src/plugins/sqldrivers/odbc/qsql_odbc.cpp608
-rw-r--r--src/plugins/sqldrivers/psql/CMakeLists.txt1
-rw-r--r--src/plugins/sqldrivers/psql/qsql_psql.cpp167
-rw-r--r--src/plugins/sqldrivers/qt_cmdline.cmake2
-rw-r--r--src/plugins/sqldrivers/sqlite/CMakeLists.txt7
-rw-r--r--src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp247
-rw-r--r--src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h7
-rw-r--r--src/plugins/sqldrivers/sqlite/qsql_sqlite_vfs.cpp258
-rw-r--r--src/plugins/sqldrivers/sqlite/qsql_sqlite_vfs_p.h21
-rw-r--r--src/plugins/sqldrivers/sqlite/smain.cpp2
-rw-r--r--src/plugins/styles/CMakeLists.txt2
-rw-r--r--src/plugins/styles/android/qandroidstyle.cpp2
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac.mm125
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac_p_p.h1
-rw-r--r--src/plugins/styles/modernwindows/CMakeLists.txt (renamed from src/plugins/styles/windowsvista/CMakeLists.txt)6
-rw-r--r--src/plugins/styles/modernwindows/main.cpp36
-rw-r--r--src/plugins/styles/modernwindows/modernwindowsstyles.json3
-rw-r--r--src/plugins/styles/modernwindows/qwindows11style.cpp2140
-rw-r--r--src/plugins/styles/modernwindows/qwindows11style_p.h70
-rw-r--r--src/plugins/styles/modernwindows/qwindowsthemedata.cpp (renamed from src/plugins/styles/windowsvista/qwindowsthemedata.cpp)0
-rw-r--r--src/plugins/styles/modernwindows/qwindowsthemedata_p.h (renamed from src/plugins/styles/windowsvista/qwindowsthemedata_p.h)0
-rw-r--r--src/plugins/styles/modernwindows/qwindowsvistaanimation.cpp (renamed from src/plugins/styles/windowsvista/qwindowsvistaanimation.cpp)0
-rw-r--r--src/plugins/styles/modernwindows/qwindowsvistaanimation_p.h (renamed from src/plugins/styles/windowsvista/qwindowsvistaanimation_p.h)0
-rw-r--r--src/plugins/styles/modernwindows/qwindowsvistastyle.cpp (renamed from src/plugins/styles/windowsvista/qwindowsvistastyle.cpp)98
-rw-r--r--src/plugins/styles/modernwindows/qwindowsvistastyle_p.h (renamed from src/plugins/styles/windowsvista/qwindowsvistastyle_p.h)3
-rw-r--r--src/plugins/styles/modernwindows/qwindowsvistastyle_p_p.h (renamed from src/plugins/styles/windowsvista/qwindowsvistastyle_p_p.h)3
-rw-r--r--src/plugins/styles/windowsvista/main.cpp28
-rw-r--r--src/plugins/styles/windowsvista/windowsvistastyle.json3
-rw-r--r--src/plugins/tls/openssl/qdtls_openssl.cpp4
-rw-r--r--src/plugins/tls/openssl/qsslcontext_openssl.cpp4
-rw-r--r--src/plugins/tls/openssl/qssldiffiehellmanparameters_openssl.cpp3
-rw-r--r--src/plugins/tls/openssl/qsslsocket_openssl_symbols.cpp47
-rw-r--r--src/plugins/tls/openssl/qsslsocket_openssl_symbols_p.h11
-rw-r--r--src/plugins/tls/openssl/qtls_openssl.cpp2
-rw-r--r--src/plugins/tls/openssl/qtlsbackend_openssl.cpp19
-rw-r--r--src/plugins/tls/openssl/qtlskey_openssl.cpp2
-rw-r--r--src/plugins/tls/openssl/qwindowscarootfetcher.cpp2
-rw-r--r--src/plugins/tls/schannel/CMakeLists.txt2
-rw-r--r--src/plugins/tls/schannel/qtls_schannel.cpp536
-rw-r--r--src/plugins/tls/schannel/qtls_schannel_p.h1
-rw-r--r--src/plugins/tls/schannel/qtlsbackend_schannel_p.h1
-rw-r--r--src/plugins/tls/schannel/qx509_schannel.cpp170
-rw-r--r--src/plugins/tls/schannel/qx509_schannel_p.h4
-rw-r--r--src/plugins/tls/securetransport/qtlsbackend_st.cpp2
-rw-r--r--src/plugins/tls/shared/qasn1element.cpp32
-rw-r--r--src/plugins/tls/shared/qwincrypt_p.h10
-rw-r--r--src/plugins/tls/shared/qx509_generic.cpp2
-rw-r--r--src/plugins/tracing/CMakeLists.txt13
-rw-r--r--src/plugins/tracing/qctflib.cpp318
-rw-r--r--src/plugins/tracing/qctflib_p.h23
-rw-r--r--src/plugins/tracing/qctfplugin.cpp11
-rw-r--r--src/plugins/tracing/qctfserver.cpp404
-rw-r--r--src/plugins/tracing/qctfserver_p.h194
-rw-r--r--src/printsupport/CMakeLists.txt15
-rw-r--r--src/printsupport/dialogs/qabstractprintdialog_p.h2
-rw-r--r--src/printsupport/dialogs/qpagesetupdialog_win.cpp18
-rw-r--r--src/printsupport/dialogs/qprintdialog_mac.mm5
-rw-r--r--src/printsupport/dialogs/qprintdialog_unix.cpp6
-rw-r--r--src/printsupport/dialogs/qprintdialog_win.cpp36
-rw-r--r--src/printsupport/dialogs/qprintpreviewdialog.cpp2
-rw-r--r--src/printsupport/doc/qtprintsupport.qdocconf2
-rw-r--r--src/printsupport/doc/snippets/CMakeLists.txt2
-rw-r--r--src/printsupport/doc/src/qt6-changes.qdoc2
-rw-r--r--src/printsupport/kernel/qcups.cpp4
-rw-r--r--src/printsupport/kernel/qplatformprintdevice.cpp4
-rw-r--r--src/printsupport/kernel/qprint_p.h1
-rw-r--r--src/printsupport/kernel/qprintengine_pdf.cpp32
-rw-r--r--src/printsupport/kernel/qprintengine_pdf_p.h2
-rw-r--r--src/printsupport/kernel/qprinter.cpp5
-rw-r--r--src/printsupport/kernel/qprinter_p.h1
-rw-r--r--src/printsupport/kernel/qprinterinfo.cpp4
-rw-r--r--src/printsupport/kernel/qprinterinfo.h1
-rw-r--r--src/printsupport/platform/macos/qpaintengine_mac.mm2
-rw-r--r--src/printsupport/platform/macos/qprintengine_mac.mm11
-rw-r--r--src/printsupport/platform/windows/qprintengine_win.cpp79
-rw-r--r--src/printsupport/platform/windows/qprintengine_win_p.h64
-rw-r--r--src/printsupport/platform/windows/qwindowsprintdevice.cpp2
-rw-r--r--src/printsupport/widgets/qprintpreviewwidget.cpp4
-rw-r--r--src/sql/CMakeLists.txt5
-rw-r--r--src/sql/compat/removed_api.cpp19
-rw-r--r--src/sql/doc/qtsql.qdocconf7
-rw-r--r--src/sql/doc/snippets/CMakeLists.txt2
-rw-r--r--src/sql/doc/snippets/code/CMakeLists.txt2
-rw-r--r--src/sql/doc/snippets/code/doc_src_sql-driver.cpp2
-rw-r--r--src/sql/doc/snippets/code/doc_src_sql-driver.qdoc2
-rw-r--r--src/sql/doc/snippets/sqldatabase/CMakeLists.txt2
-rw-r--r--src/sql/doc/snippets/sqldatabase/sqldatabase_snippet.cpp256
-rw-r--r--src/sql/doc/src/qsqldatatype-table.qdoc105
-rw-r--r--src/sql/doc/src/qt6-changes.qdoc2
-rw-r--r--src/sql/doc/src/sql-driver.qdoc41
-rw-r--r--src/sql/doc/src/sql-programming.qdoc4
-rw-r--r--src/sql/kernel/qsqldatabase.cpp270
-rw-r--r--src/sql/kernel/qsqldatabase.h10
-rw-r--r--src/sql/kernel/qsqldriver.cpp30
-rw-r--r--src/sql/kernel/qsqldriver.h5
-rw-r--r--src/sql/kernel/qsqlerror.cpp47
-rw-r--r--src/sql/kernel/qsqlerror.h20
-rw-r--r--src/sql/kernel/qsqlfield.cpp281
-rw-r--r--src/sql/kernel/qsqlfield.h35
-rw-r--r--src/sql/kernel/qsqlindex.cpp70
-rw-r--r--src/sql/kernel/qsqlindex.h20
-rw-r--r--src/sql/kernel/qsqlquery.cpp168
-rw-r--r--src/sql/kernel/qsqlquery.h15
-rw-r--r--src/sql/kernel/qsqlrecord.cpp158
-rw-r--r--src/sql/kernel/qsqlrecord.h46
-rw-r--r--src/sql/kernel/qsqlresult.cpp68
-rw-r--r--src/sql/kernel/qsqlresult.h13
-rw-r--r--src/sql/kernel/qsqlresult_p.h1
-rw-r--r--src/sql/kernel/qtsqlglobal.h1
-rw-r--r--src/sql/models/qsqlquerymodel.cpp7
-rw-r--r--src/sql/models/qsqlrelationaltablemodel.cpp3
-rw-r--r--src/sql/models/qsqltablemodel.cpp2
-rw-r--r--src/testlib/3rdparty/linux_perf_event_p.h2
-rw-r--r--src/testlib/3rdparty/qt_attribution.json22
-rw-r--r--src/testlib/3rdparty/valgrind_p.h2
-rw-r--r--src/testlib/CMakeLists.txt17
-rw-r--r--src/testlib/doc/qttestlib.qdocconf2
-rw-r--r--src/testlib/doc/snippets/CMakeLists.txt2
-rw-r--r--src/testlib/doc/snippets/code/CMakeLists.txt3
-rw-r--r--src/testlib/doc/snippets/code/doc_src_cmakelists.txt2
-rw-r--r--src/testlib/doc/snippets/code/doc_src_qsignalspy.cpp3
-rw-r--r--src/testlib/doc/snippets/code/doc_src_qtestlib.qdoc2
-rw-r--r--src/testlib/doc/snippets/code/doc_src_qttest.cpp6
-rw-r--r--src/testlib/doc/snippets/code/src_corelib_kernel_qtestsupport_core.cpp20
-rw-r--r--src/testlib/doc/snippets/code/src_corelib_kernel_qtestsupport_core_snippet.cpp10
-rw-r--r--src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp5
-rw-r--r--src/testlib/doc/src/qt6-changes.qdoc2
-rw-r--r--src/testlib/doc/src/qttest-best-practices.qdoc21
-rw-r--r--src/testlib/doc/src/qttestlib-manual.qdoc488
-rw-r--r--src/testlib/doc/src/qttestlib-tutorial1.qdoc76
-rw-r--r--src/testlib/doc/src/qttestlib-tutorial2.qdoc132
-rw-r--r--src/testlib/doc/src/qttestlib-tutorial3.qdoc75
-rw-r--r--src/testlib/doc/src/qttestlib-tutorial4.qdoc95
-rw-r--r--src/testlib/doc/src/qttestlib-tutorial5.qdoc57
-rw-r--r--src/testlib/doc/src/qttestlib-tutorial6.qdoc50
-rw-r--r--src/testlib/qabstracttestlogger.cpp13
-rw-r--r--src/testlib/qabstracttestlogger_p.h2
-rw-r--r--src/testlib/qappletestlogger.cpp10
-rw-r--r--src/testlib/qasciikey.cpp4
-rw-r--r--src/testlib/qbenchmark.cpp6
-rw-r--r--src/testlib/qbenchmark.h4
-rw-r--r--src/testlib/qbenchmark_p.h2
-rw-r--r--src/testlib/qbenchmarkperfevents.cpp3
-rw-r--r--src/testlib/qbenchmarkvalgrind.cpp5
-rw-r--r--src/testlib/qcomparisontesthelper.cpp22
-rw-r--r--src/testlib/qcomparisontesthelper_p.h373
-rw-r--r--src/testlib/qemulationdetector_p.h2
-rw-r--r--src/testlib/qjunittestlogger.cpp7
-rw-r--r--src/testlib/qplaintestlogger.cpp16
-rw-r--r--src/testlib/qplaintestlogger_p.h2
-rw-r--r--src/testlib/qpropertytesthelper_p.h99
-rw-r--r--src/testlib/qsignaldumper.cpp27
-rw-r--r--src/testlib/qsignalspy.cpp318
-rw-r--r--src/testlib/qsignalspy.h189
-rw-r--r--src/testlib/qsignalspy.qdoc144
-rw-r--r--src/testlib/qtest.h363
-rw-r--r--src/testlib/qtest_gui.h1
-rw-r--r--src/testlib/qtest_network.h9
-rw-r--r--src/testlib/qtest_widgets.h9
-rw-r--r--src/testlib/qtestaccessible.h6
-rw-r--r--src/testlib/qtestassert.h5
-rw-r--r--src/testlib/qtestblacklist.cpp16
-rw-r--r--src/testlib/qtestblacklist_p.h2
-rw-r--r--src/testlib/qtestcase.cpp1291
-rw-r--r--src/testlib/qtestcase.h370
-rw-r--r--src/testlib/qtestcase.qdoc89
-rw-r--r--src/testlib/qtestcase_p.h5
-rw-r--r--src/testlib/qtestcrashhandler.cpp663
-rw-r--r--src/testlib/qtestcrashhandler_p.h251
-rw-r--r--src/testlib/qtestevent.qdoc8
-rw-r--r--src/testlib/qtestlog.cpp18
-rw-r--r--src/testlib/qtestlog_p.h1
-rw-r--r--src/testlib/qtestmouse.h2
-rw-r--r--src/testlib/qtestresult.cpp38
-rw-r--r--src/testlib/qtestresult_p.h6
-rw-r--r--src/testlib/qtesttable.cpp14
-rw-r--r--src/testlib/qtesttostring.h499
-rw-r--r--src/testlib/qtestwheel.h72
-rw-r--r--src/testlib/qttestglobal.h4
-rw-r--r--src/testlib/removed_api.cpp29
-rw-r--r--src/tools/CMakeLists.txt2
-rw-r--r--src/tools/androiddeployqt/CMakeLists.txt1
-rw-r--r--src/tools/androiddeployqt/doc/src/androiddeployqt.qdoc129
-rw-r--r--src/tools/androiddeployqt/main.cpp236
-rw-r--r--src/tools/androidtestrunner/CMakeLists.txt2
-rw-r--r--src/tools/androidtestrunner/main.cpp649
-rw-r--r--src/tools/bootstrap/CMakeLists.txt27
-rw-r--r--src/tools/cmake_automoc_parser/CMakeLists.txt1
-rw-r--r--src/tools/cmake_automoc_parser/main.cpp12
-rw-r--r--src/tools/configure.cmake4
-rw-r--r--src/tools/macdeployqt/macdeployqt/CMakeLists.txt2
-rw-r--r--src/tools/macdeployqt/shared/shared.cpp34
-rw-r--r--src/tools/macdeployqt/shared/shared.h5
-rw-r--r--src/tools/moc/CMakeLists.txt4
-rw-r--r--src/tools/moc/cbordevice.h2
-rw-r--r--src/tools/moc/generator.cpp369
-rw-r--r--src/tools/moc/generator.h7
-rw-r--r--src/tools/moc/main.cpp28
-rw-r--r--src/tools/moc/moc.cpp333
-rw-r--r--src/tools/moc/moc.h27
-rw-r--r--src/tools/moc/parser.cpp76
-rw-r--r--src/tools/moc/parser.h11
-rw-r--r--src/tools/moc/preprocessor.cpp99
-rw-r--r--src/tools/moc/preprocessor.h9
-rw-r--r--src/tools/moc/symbols.h107
-rwxr-xr-xsrc/tools/moc/util/generate.sh4
-rw-r--r--src/tools/moc/util/licenseheader.cpp.in (renamed from src/tools/moc/util/licenseheader.txt)0
-rw-r--r--src/tools/moc/utils.h42
-rw-r--r--src/tools/qdbuscpp2xml/CMakeLists.txt2
-rw-r--r--src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp33
-rw-r--r--src/tools/qdbusxml2cpp/CMakeLists.txt1
-rw-r--r--src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp734
-rw-r--r--src/tools/qlalr/CMakeLists.txt2
-rw-r--r--src/tools/qlalr/cppgenerator.cpp48
-rw-r--r--src/tools/qlalr/cppgenerator.h6
-rw-r--r--src/tools/qlalr/examples/dummy-xml/ll/dummy-xml-ll.cpp2
-rw-r--r--src/tools/qlalr/examples/dummy-xml/xml.g2
-rw-r--r--src/tools/qlalr/examples/glsl/build.sh2
-rw-r--r--src/tools/qlalr/examples/glsl/glsl-lex.l2
-rw-r--r--src/tools/qlalr/examples/glsl/glsl.g2
-rw-r--r--src/tools/qlalr/examples/lambda/lambda.g2
-rw-r--r--src/tools/qlalr/examples/lambda/main.cpp2
-rw-r--r--src/tools/qlalr/examples/qparser/calc.g2
-rw-r--r--src/tools/qlalr/examples/qparser/calc.l2
-rw-r--r--src/tools/qlalr/examples/qparser/qparser.cpp2
-rw-r--r--src/tools/qlalr/examples/qparser/qparser.h2
-rw-r--r--src/tools/qlalr/lalr.cpp22
-rw-r--r--src/tools/qlalr/lalr.h15
-rw-r--r--src/tools/qlalr/main.cpp8
-rw-r--r--src/tools/qtpaths/CMakeLists.txt4
-rw-r--r--src/tools/qtpaths/qtpaths.cpp13
-rw-r--r--src/tools/rcc/CMakeLists.txt2
-rw-r--r--src/tools/rcc/main.cpp10
-rw-r--r--src/tools/rcc/rcc.cpp32
-rw-r--r--src/tools/syncqt/CMakeLists.txt91
-rw-r--r--src/tools/syncqt/main.cpp399
-rw-r--r--src/tools/tracegen/ctf.cpp5
-rw-r--r--src/tools/tracegen/ctf.h2
-rw-r--r--src/tools/tracegen/etw.cpp3
-rw-r--r--src/tools/tracegen/etw.h2
-rw-r--r--src/tools/tracegen/helpers.cpp11
-rw-r--r--src/tools/tracegen/helpers.h5
-rw-r--r--src/tools/tracegen/lttng.cpp42
-rw-r--r--src/tools/tracegen/lttng.h2
-rw-r--r--src/tools/tracegen/panic.cpp2
-rw-r--r--src/tools/tracegen/panic.h2
-rw-r--r--src/tools/tracegen/provider.cpp2
-rw-r--r--src/tools/tracegen/provider.h2
-rw-r--r--src/tools/tracegen/qtheaders.cpp2
-rw-r--r--src/tools/tracegen/qtheaders.h2
-rw-r--r--src/tools/tracegen/tracegen.cpp2
-rw-r--r--src/tools/tracepointgen/parser.cpp33
-rw-r--r--src/tools/tracepointgen/parser.h2
-rw-r--r--src/tools/tracepointgen/tracepointgen.cpp2
-rw-r--r--src/tools/tracepointgen/tracepointgen.h2
-rw-r--r--src/tools/uic/CMakeLists.txt2
-rw-r--r--src/tools/uic/cpp/cppwriteinitialization.cpp254
-rw-r--r--src/tools/uic/cpp/cppwriteinitialization.h3
-rw-r--r--src/tools/uic/customwidgetsinfo.cpp86
-rw-r--r--src/tools/uic/customwidgetsinfo.h5
-rw-r--r--src/tools/uic/driver.cpp7
-rw-r--r--src/tools/uic/python/pythonwriteimports.cpp8
-rw-r--r--src/tools/uic/shared/language.cpp159
-rw-r--r--src/tools/uic/shared/language.h8
-rw-r--r--src/tools/uic/ui4.cpp36
-rw-r--r--src/tools/uic/ui4.h16
-rw-r--r--src/tools/uic/uic.cpp7
-rw-r--r--src/tools/windeployqt/CMakeLists.txt3
-rw-r--r--src/tools/windeployqt/elfreader.cpp417
-rw-r--r--src/tools/windeployqt/elfreader.h151
-rw-r--r--src/tools/windeployqt/main.cpp622
-rw-r--r--src/tools/windeployqt/qmlutils.cpp3
-rw-r--r--src/tools/windeployqt/qtmoduleinfo.cpp12
-rw-r--r--src/tools/windeployqt/qtplugininfo.cpp100
-rw-r--r--src/tools/windeployqt/qtplugininfo.h48
-rw-r--r--src/tools/windeployqt/utils.cpp169
-rw-r--r--src/tools/windeployqt/utils.h29
-rw-r--r--src/widgets/CMakeLists.txt102
-rw-r--r--src/widgets/accessible/complexwidgets.cpp192
-rw-r--r--src/widgets/accessible/complexwidgets_p.h14
-rw-r--r--src/widgets/accessible/itemviews.cpp228
-rw-r--r--src/widgets/accessible/itemviews_p.h2
-rw-r--r--src/widgets/accessible/qaccessiblewidgetfactory.cpp1
-rw-r--r--src/widgets/accessible/qaccessiblewidgets.cpp8
-rw-r--r--src/widgets/accessible/qaccessiblewidgets_p.h1
-rw-r--r--src/widgets/compat/removed_api.cpp21
-rw-r--r--src/widgets/configure.cmake4
-rw-r--r--src/widgets/dialogs/images/qtlogo-64.pngbin1032 -> 1219 bytes
-rw-r--r--src/widgets/dialogs/qcolordialog.cpp160
-rw-r--r--src/widgets/dialogs/qcolordialog.h12
-rw-r--r--src/widgets/dialogs/qdialog.cpp61
-rw-r--r--src/widgets/dialogs/qdialog.h1
-rw-r--r--src/widgets/dialogs/qdialog_p.h6
-rw-r--r--src/widgets/dialogs/qerrormessage.cpp6
-rw-r--r--src/widgets/dialogs/qfiledialog.cpp778
-rw-r--r--src/widgets/dialogs/qfiledialog.h44
-rw-r--r--src/widgets/dialogs/qfiledialog_p.h59
-rw-r--r--src/widgets/dialogs/qfontdialog.cpp85
-rw-r--r--src/widgets/dialogs/qfontdialog.h7
-rw-r--r--src/widgets/dialogs/qfontdialog_p.h15
-rw-r--r--src/widgets/dialogs/qinputdialog.cpp68
-rw-r--r--src/widgets/dialogs/qinputdialog.h3
-rw-r--r--src/widgets/dialogs/qmessagebox.cpp419
-rw-r--r--src/widgets/dialogs/qmessagebox.h42
-rw-r--r--src/widgets/dialogs/qprogressdialog.cpp52
-rw-r--r--src/widgets/dialogs/qsidebar.cpp91
-rw-r--r--src/widgets/dialogs/qsidebar_p.h2
-rw-r--r--src/widgets/dialogs/qwizard.cpp59
-rw-r--r--src/widgets/dialogs/qwizard_win.cpp6
-rw-r--r--src/widgets/dialogs/qwizard_win_p.h2
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part1-labeled-layout.pngbin19114 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part1-labeled-screenshot.pngbin23223 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part1-screenshot.pngbin9872 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part2-add-contact.pngbin12936 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part2-add-flowchart.pngbin23533 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part2-add-successful.pngbin10825 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part2-labeled-layout.pngbin27103 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part2-signals-and-slots.pngbin9968 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part2-stretch-effects.pngbin12268 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part3-labeled-layout.pngbin27467 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part3-linkedlist.pngbin10209 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part3-screenshot.pngbin14041 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part4-remove.pngbin22248 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part5-finddialog.pngbin10046 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part5-notfound.pngbin10789 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part5-screenshot.pngbin15849 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part5-signals-and-slots.pngbin5542 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part6-load.pngbin24797 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part6-save.pngbin24747 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part6-screenshot.pngbin16819 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-part7-screenshot.pngbin18369 -> 0 bytes
-rw-r--r--src/widgets/doc/images/addressbook-tutorial-screenshot.pngbin15275 -> 0 bytes
-rw-r--r--src/widgets/doc/images/collapsed_combobox.pngbin0 -> 6507 bytes
-rw-r--r--src/widgets/doc/images/cuberhiwidget-example.jpgbin0 -> 70232 bytes
-rw-r--r--src/widgets/doc/images/expanded_combobox.pngbin0 -> 11699 bytes
-rw-r--r--src/widgets/doc/images/qrhiwidget-intro.jpgbin0 -> 9508 bytes
-rw-r--r--src/widgets/doc/images/qtquickdialogs-filedialog-gtk.pngbin0 -> 39560 bytes
-rw-r--r--src/widgets/doc/images/simplerhiwidget-example.jpgbin0 -> 12489 bytes
-rw-r--r--src/widgets/doc/images/spinboxdelegate-example.pngbin4762 -> 0 bytes
-rw-r--r--src/widgets/doc/images/spinboxdelegate-example.webpbin0 -> 40364 bytes
-rw-r--r--src/widgets/doc/images/stylesheet-coffee-cleanlooks.pngbin14820 -> 0 bytes
-rw-r--r--src/widgets/doc/images/stylesheet-pagefold-mac.pngbin20618 -> 0 bytes
-rw-r--r--src/widgets/doc/images/system-tray.pngbin6326 -> 0 bytes
-rw-r--r--src/widgets/doc/images/system-tray.webpbin0 -> 19180 bytes
-rw-r--r--src/widgets/doc/qtwidgets.qdocconf29
-rw-r--r--src/widgets/doc/snippets/CMakeLists.txt2
-rw-r--r--src/widgets/doc/snippets/cmake-macros/examples.cmake4
-rw-r--r--src/widgets/doc/snippets/code/doc_src_qt4-mainwindow.cpp45
-rw-r--r--src/widgets/doc/snippets/code/doc_src_qt4-styles.cpp19
-rw-r--r--src/widgets/doc/snippets/code/doc_src_stylesheet.qdoc56
-rw-r--r--src/widgets/doc/snippets/code/src_gui_dialogs_qmessagebox.cpp26
-rw-r--r--src/widgets/doc/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp34
-rw-r--r--src/widgets/doc/snippets/code/src_gui_graphicsview_qgraphicsview.cpp10
-rw-r--r--src/widgets/doc/snippets/code/src_gui_itemviews_qitemeditorfactory.cpp4
-rw-r--r--src/widgets/doc/snippets/code/src_gui_kernel_qapplication.cpp94
-rw-r--r--src/widgets/doc/snippets/code/src_gui_kernel_qformlayout.cpp2
-rw-r--r--src/widgets/doc/snippets/code/src_gui_kernel_qwidget.cpp18
-rw-r--r--src/widgets/doc/snippets/code/src_gui_widgets_qgroupbox.cpp17
-rw-r--r--src/widgets/doc/snippets/code/src_gui_widgets_qmenu.cpp4
-rw-r--r--src/widgets/doc/snippets/code/src_gui_widgets_qspinbox.cpp20
-rw-r--r--src/widgets/doc/snippets/code/src_gui_widgets_qstatusbar.cpp8
-rw-r--r--src/widgets/doc/snippets/code/src_widgets_util_qscroller.cpp2
-rw-r--r--src/widgets/doc/snippets/code/src_widgets_widgets_qmainwindow.cpp2
-rw-r--r--src/widgets/doc/snippets/customviewstyle/CMakeLists.txt2
-rw-r--r--src/widgets/doc/snippets/dialogs/dialogs.cpp29
-rw-r--r--src/widgets/doc/snippets/filedialogurls/CMakeLists.txt2
-rw-r--r--src/widgets/doc/snippets/graphicssceneadditem/CMakeLists.txt2
-rw-r--r--src/widgets/doc/snippets/graphicsview/CMakeLists.txt2
-rw-r--r--src/widgets/doc/snippets/mdiarea/CMakeLists.txt2
-rw-r--r--src/widgets/doc/snippets/myscrollarea/CMakeLists.txt2
-rw-r--r--src/widgets/doc/snippets/qitemdelegate/CMakeLists.txt12
-rw-r--r--src/widgets/doc/snippets/qitemdelegate/spinbox-delegate.cpp79
-rw-r--r--src/widgets/doc/snippets/qrhiwidget/rhiwidgetintro.cpp109
-rw-r--r--src/widgets/doc/snippets/qrhiwidget/rhiwidgetintro.frag10
-rw-r--r--src/widgets/doc/snippets/qrhiwidget/rhiwidgetintro.vert15
-rw-r--r--src/widgets/doc/snippets/splitter/splitter.cpp6
-rw-r--r--src/widgets/doc/snippets/styles/qcustompixmapstyle.cpp2
-rw-r--r--src/widgets/doc/snippets/tooltips/main.cpp74
-rw-r--r--src/widgets/doc/src/model-view-programming.qdoc32
-rw-r--r--src/widgets/doc/src/modelview.qdoc7
-rw-r--r--src/widgets/doc/src/qt6-changes.qdoc2
-rw-r--r--src/widgets/doc/src/qtwidgets-index.qdoc16
-rw-r--r--src/widgets/doc/src/widgets-and-layouts/focus.qdoc8
-rw-r--r--src/widgets/doc/src/widgets-and-layouts/gallery.qdoc27
-rw-r--r--src/widgets/doc/src/widgets-and-layouts/layout.qdoc8
-rw-r--r--src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc1443
-rw-r--r--src/widgets/doc/src/widgets-tutorial.qdoc6
-rw-r--r--src/widgets/doc/src/windows-and-dialogs/mainwindow.qdoc65
-rw-r--r--src/widgets/effects/qpixmapfilter.cpp311
-rw-r--r--src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp26
-rw-r--r--src/widgets/graphicsview/qgraphicsanchorlayout_p.h7
-rw-r--r--src/widgets/graphicsview/qgraphicsgridlayout.cpp2
-rw-r--r--src/widgets/graphicsview/qgraphicsitem.cpp2
-rw-r--r--src/widgets/graphicsview/qgraphicslayout_p.h4
-rw-r--r--src/widgets/graphicsview/qgraphicslayoutstyleinfo.cpp2
-rw-r--r--src/widgets/graphicsview/qgraphicsproxywidget.cpp10
-rw-r--r--src/widgets/graphicsview/qgraphicsproxywidget_p.h2
-rw-r--r--src/widgets/graphicsview/qgraphicsscene.cpp5
-rw-r--r--src/widgets/graphicsview/qgraphicsview.cpp17
-rw-r--r--src/widgets/graphicsview/qgraphicsview_p.h2
-rw-r--r--src/widgets/itemviews/qabstractitemdelegate.cpp10
-rw-r--r--src/widgets/itemviews/qabstractitemview.cpp406
-rw-r--r--src/widgets/itemviews/qabstractitemview.h14
-rw-r--r--src/widgets/itemviews/qabstractitemview_p.h49
-rw-r--r--src/widgets/itemviews/qcolumnview.cpp82
-rw-r--r--src/widgets/itemviews/qcolumnview.h3
-rw-r--r--src/widgets/itemviews/qcolumnview_p.h17
-rw-r--r--src/widgets/itemviews/qdatawidgetmapper.cpp73
-rw-r--r--src/widgets/itemviews/qdatawidgetmapper.h6
-rw-r--r--src/widgets/itemviews/qheaderview.cpp201
-rw-r--r--src/widgets/itemviews/qheaderview.h10
-rw-r--r--src/widgets/itemviews/qheaderview_p.h32
-rw-r--r--src/widgets/itemviews/qitemdelegate.cpp36
-rw-r--r--src/widgets/itemviews/qitemeditorfactory.cpp8
-rw-r--r--src/widgets/itemviews/qlistview.cpp26
-rw-r--r--src/widgets/itemviews/qlistview_p.h1
-rw-r--r--src/widgets/itemviews/qlistwidget.cpp167
-rw-r--r--src/widgets/itemviews/qlistwidget.h10
-rw-r--r--src/widgets/itemviews/qlistwidget_p.h25
-rw-r--r--src/widgets/itemviews/qstyleditemdelegate.cpp30
-rw-r--r--src/widgets/itemviews/qtableview.cpp226
-rw-r--r--src/widgets/itemviews/qtableview.h7
-rw-r--r--src/widgets/itemviews/qtableview_p.h32
-rw-r--r--src/widgets/itemviews/qtablewidget.cpp88
-rw-r--r--src/widgets/itemviews/qtablewidget.h16
-rw-r--r--src/widgets/itemviews/qtablewidget_p.h30
-rw-r--r--src/widgets/itemviews/qtreeview.cpp258
-rw-r--r--src/widgets/itemviews/qtreeview.h5
-rw-r--r--src/widgets/itemviews/qtreeview_p.h42
-rw-r--r--src/widgets/itemviews/qtreewidget.cpp90
-rw-r--r--src/widgets/itemviews/qtreewidget.h13
-rw-r--r--src/widgets/itemviews/qtreewidget_p.h29
-rw-r--r--src/widgets/itemviews/qwidgetitemdata_p.h1
-rw-r--r--src/widgets/kernel/qaction_widgets.cpp5
-rw-r--r--src/widgets/kernel/qaction_widgets_p.h2
-rw-r--r--src/widgets/kernel/qapplication.cpp76
-rw-r--r--src/widgets/kernel/qapplication_p.h3
-rw-r--r--src/widgets/kernel/qgesturemanager.cpp53
-rw-r--r--src/widgets/kernel/qgesturemanager_p.h10
-rw-r--r--src/widgets/kernel/qlayout.cpp16
-rw-r--r--src/widgets/kernel/qlayoutitem.cpp2
-rw-r--r--src/widgets/kernel/qrhiwidget.cpp1309
-rw-r--r--src/widgets/kernel/qrhiwidget.h101
-rw-r--r--src/widgets/kernel/qrhiwidget_p.h64
-rw-r--r--src/widgets/kernel/qshortcut_widgets.cpp18
-rw-r--r--src/widgets/kernel/qstackedlayout.cpp2
-rw-r--r--src/widgets/kernel/qtestsupport_widgets.cpp30
-rw-r--r--src/widgets/kernel/qtestsupport_widgets.h1
-rw-r--r--src/widgets/kernel/qtooltip.cpp36
-rw-r--r--src/widgets/kernel/qwhatsthis.cpp14
-rw-r--r--src/widgets/kernel/qwidget.cpp1106
-rw-r--r--src/widgets/kernel/qwidget.h5
-rw-r--r--src/widgets/kernel/qwidget_p.h53
-rw-r--r--src/widgets/kernel/qwidgetaction.cpp18
-rw-r--r--src/widgets/kernel/qwidgetaction.h1
-rw-r--r--src/widgets/kernel/qwidgetaction_p.h4
-rw-r--r--src/widgets/kernel/qwidgetrepaintmanager.cpp56
-rw-r--r--src/widgets/kernel/qwidgetsvariant.cpp3
-rw-r--r--src/widgets/kernel/qwidgetwindow.cpp93
-rw-r--r--src/widgets/kernel/qwidgetwindow_p.h2
-rw-r--r--src/widgets/kernel/qwindowcontainer.cpp73
-rw-r--r--src/widgets/kernel/qwindowcontainer_p.h4
-rw-r--r--src/widgets/platform/ios/PrivacyInfo.xcprivacy25
-rw-r--r--src/widgets/styles/images/cleartext-128.pngbin0 -> 3638 bytes
-rw-r--r--src/widgets/styles/images/cleartext-16.pngbin760 -> 985 bytes
-rw-r--r--src/widgets/styles/images/cleartext-32.pngbin410 -> 1310 bytes
-rw-r--r--src/widgets/styles/images/cleartext.svg71
-rw-r--r--src/widgets/styles/images/critical-128.pngbin0 -> 2938 bytes
-rw-r--r--src/widgets/styles/images/critical-16.pngbin0 -> 835 bytes
-rw-r--r--src/widgets/styles/images/critical-32.pngbin0 -> 1148 bytes
-rw-r--r--src/widgets/styles/images/filedialog_end-128.pngbin0 -> 1393 bytes
-rw-r--r--src/widgets/styles/images/filedialog_end-16.pngbin0 -> 686 bytes
-rw-r--r--src/widgets/styles/images/filedialog_end-32.pngbin0 -> 787 bytes
-rw-r--r--src/widgets/styles/images/filedialog_start-128.pngbin0 -> 1326 bytes
-rw-r--r--src/widgets/styles/images/filedialog_start-16.pngbin0 -> 677 bytes
-rw-r--r--src/widgets/styles/images/filedialog_start-32.pngbin0 -> 761 bytes
-rw-r--r--src/widgets/styles/images/fusion_closedock-10.pngbin0 -> 238 bytes
-rw-r--r--src/widgets/styles/images/fusion_closedock-16.pngbin0 -> 288 bytes
-rw-r--r--src/widgets/styles/images/fusion_closedock-20.pngbin0 -> 303 bytes
-rw-r--r--src/widgets/styles/images/fusion_closedock-32.pngbin0 -> 333 bytes
-rw-r--r--src/widgets/styles/images/fusion_closedock-48.pngbin0 -> 492 bytes
-rw-r--r--src/widgets/styles/images/fusion_closedock-64.pngbin0 -> 617 bytes
-rw-r--r--src/widgets/styles/images/fusion_closedock.svg87
-rw-r--r--src/widgets/styles/images/fusion_normalizedockup-16.pngbin0 -> 314 bytes
-rw-r--r--src/widgets/styles/images/fusion_normalizedockup-32.pngbin0 -> 413 bytes
-rw-r--r--src/widgets/styles/images/fusion_normalizedockup.svg75
-rw-r--r--src/widgets/styles/images/fusion_normalizedockup_10.pngbin0 -> 234 bytes
-rw-r--r--src/widgets/styles/images/fusion_normalizedockup_20.pngbin0 -> 342 bytes
-rw-r--r--src/widgets/styles/images/fusion_normalizedockup_48.pngbin0 -> 487 bytes
-rw-r--r--src/widgets/styles/images/fusion_normalizedockup_64.pngbin0 -> 579 bytes
-rw-r--r--src/widgets/styles/images/fusion_titlebar-min-10.pngbin0 -> 167 bytes
-rw-r--r--src/widgets/styles/images/fusion_titlebar-min-16.pngbin0 -> 141 bytes
-rw-r--r--src/widgets/styles/images/fusion_titlebar-min-20.pngbin0 -> 176 bytes
-rw-r--r--src/widgets/styles/images/fusion_titlebar-min-32.pngbin0 -> 214 bytes
-rw-r--r--src/widgets/styles/images/fusion_titlebar-min-48.pngbin0 -> 179 bytes
-rw-r--r--src/widgets/styles/images/fusion_titlebar-min-64.pngbin0 -> 190 bytes
-rw-r--r--src/widgets/styles/images/fusion_titlebar-min.svg67
-rw-r--r--src/widgets/styles/images/information-128.pngbin0 -> 2099 bytes
-rw-r--r--src/widgets/styles/images/information-16.pngbin0 -> 697 bytes
-rw-r--r--src/widgets/styles/images/information-32.pngbin0 -> 874 bytes
-rw-r--r--src/widgets/styles/images/media-pause-128.pngbin0 -> 262 bytes
-rw-r--r--src/widgets/styles/images/media-pause-16.pngbin229 -> 141 bytes
-rw-r--r--src/widgets/styles/images/media-pause-32.pngbin185 -> 157 bytes
-rw-r--r--src/widgets/styles/images/media-pause.svg67
-rw-r--r--src/widgets/styles/images/media-play-128.pngbin0 -> 584 bytes
-rw-r--r--src/widgets/styles/images/media-play-16.pngbin262 -> 172 bytes
-rw-r--r--src/widgets/styles/images/media-play-32.pngbin413 -> 227 bytes
-rw-r--r--src/widgets/styles/images/media-play.svg57
-rw-r--r--src/widgets/styles/images/media-seek-backward-128.pngbin0 -> 532 bytes
-rw-r--r--src/widgets/styles/images/media-seek-backward-16.pngbin384 -> 182 bytes
-rw-r--r--src/widgets/styles/images/media-seek-backward-32.pngbin548 -> 235 bytes
-rw-r--r--src/widgets/styles/images/media-seek-backward.svg62
-rw-r--r--src/widgets/styles/images/media-seek-forward-128.pngbin0 -> 544 bytes
-rw-r--r--src/widgets/styles/images/media-seek-forward-16.pngbin370 -> 175 bytes
-rw-r--r--src/widgets/styles/images/media-seek-forward-32.pngbin524 -> 232 bytes
-rw-r--r--src/widgets/styles/images/media-seek-forward.svg61
-rw-r--r--src/widgets/styles/images/media-skip-backward-128.pngbin0 -> 582 bytes
-rw-r--r--src/widgets/styles/images/media-skip-backward-16.pngbin396 -> 183 bytes
-rw-r--r--src/widgets/styles/images/media-skip-backward-32.pngbin570 -> 248 bytes
-rw-r--r--src/widgets/styles/images/media-skip-backward.svg67
-rw-r--r--src/widgets/styles/images/media-skip-forward-128.pngbin0 -> 532 bytes
-rw-r--r--src/widgets/styles/images/media-skip-forward-16.pngbin384 -> 176 bytes
-rw-r--r--src/widgets/styles/images/media-skip-forward-32.pngbin549 -> 233 bytes
-rw-r--r--src/widgets/styles/images/media-skip-forward.svg67
-rw-r--r--src/widgets/styles/images/media-stop-128.pngbin0 -> 264 bytes
-rw-r--r--src/widgets/styles/images/media-stop-16.pngbin166 -> 136 bytes
-rw-r--r--src/widgets/styles/images/media-stop-32.pngbin176 -> 147 bytes
-rw-r--r--src/widgets/styles/images/media-stop.svg60
-rw-r--r--src/widgets/styles/images/question-128.pngbin0 -> 2770 bytes
-rw-r--r--src/widgets/styles/images/question-16.pngbin0 -> 797 bytes
-rw-r--r--src/widgets/styles/images/question-32.pngbin0 -> 1063 bytes
-rw-r--r--src/widgets/styles/images/standardbutton-closetab-128.pngbin0 -> 1657 bytes
-rw-r--r--src/widgets/styles/images/standardbutton-closetab-16.pngbin406 -> 674 bytes
-rw-r--r--src/widgets/styles/images/standardbutton-closetab-32.pngbin305 -> 819 bytes
-rw-r--r--src/widgets/styles/images/standardbutton-closetab-down-128.pngbin0 -> 1599 bytes
-rw-r--r--src/widgets/styles/images/standardbutton-closetab-down-16.pngbin481 -> 666 bytes
-rw-r--r--src/widgets/styles/images/standardbutton-closetab-down-32.pngbin278 -> 810 bytes
-rw-r--r--src/widgets/styles/images/standardbutton-closetab-down.svg85
-rw-r--r--src/widgets/styles/images/standardbutton-closetab-hover-128.pngbin0 -> 1660 bytes
-rw-r--r--src/widgets/styles/images/standardbutton-closetab-hover-16.pngbin570 -> 675 bytes
-rw-r--r--src/widgets/styles/images/standardbutton-closetab-hover-32.pngbin305 -> 822 bytes
-rw-r--r--src/widgets/styles/images/standardbutton-closetab-hover.svg86
-rw-r--r--src/widgets/styles/images/standardbutton-closetab.svg86
-rw-r--r--src/widgets/styles/images/toolbar-ext-h-128.pngbin0 -> 1765 bytes
-rw-r--r--src/widgets/styles/images/toolbar-ext-h-rtl-128.pngbin0 -> 1740 bytes
-rw-r--r--src/widgets/styles/images/toolbar-ext-v-80.pngbin0 -> 2035 bytes
-rw-r--r--src/widgets/styles/images/warning-128.pngbin0 -> 1625 bytes
-rw-r--r--src/widgets/styles/images/warning-16.pngbin0 -> 660 bytes
-rw-r--r--src/widgets/styles/images/warning-32.pngbin0 -> 799 bytes
-rw-r--r--src/widgets/styles/qcommonstyle.cpp1725
-rw-r--r--src/widgets/styles/qcommonstyle.h3
-rw-r--r--src/widgets/styles/qcommonstyle_p.h22
-rw-r--r--src/widgets/styles/qdrawutil.cpp112
-rw-r--r--src/widgets/styles/qdrawutil.h11
-rw-r--r--src/widgets/styles/qfusionstyle.cpp581
-rw-r--r--src/widgets/styles/qfusionstyle_p.h1
-rw-r--r--src/widgets/styles/qproxystyle_p.h2
-rw-r--r--src/widgets/styles/qstyle.cpp8
-rw-r--r--src/widgets/styles/qstyle.h10
-rw-r--r--src/widgets/styles/qstyle_p.h28
-rw-r--r--src/widgets/styles/qstyleanimation.cpp1
-rw-r--r--src/widgets/styles/qstylehelper.cpp15
-rw-r--r--src/widgets/styles/qstylehelper_p.h2
-rw-r--r--src/widgets/styles/qstyleoption.cpp77
-rw-r--r--src/widgets/styles/qstyleoption.h3
-rw-r--r--src/widgets/styles/qstylesheetstyle.cpp249
-rw-r--r--src/widgets/styles/qstylesheetstyle_default.cpp61
-rw-r--r--src/widgets/styles/qwindowsstyle.cpp158
-rw-r--r--src/widgets/styles/qwindowsstyle_p_p.h8
-rw-r--r--src/widgets/util/qcompleter.cpp23
-rw-r--r--src/widgets/util/qcompleter_p.h2
-rw-r--r--src/widgets/util/qflickgesture_p.h2
-rw-r--r--src/widgets/util/qscroller.cpp3
-rw-r--r--src/widgets/util/qsystemtrayicon.cpp10
-rw-r--r--src/widgets/util/qsystemtrayicon_qpa.cpp10
-rw-r--r--src/widgets/widgets/qabstractbutton.cpp13
-rw-r--r--src/widgets/widgets/qabstractscrollarea.cpp16
-rw-r--r--src/widgets/widgets/qabstractspinbox.cpp22
-rw-r--r--src/widgets/widgets/qabstractspinbox.h3
-rw-r--r--src/widgets/widgets/qabstractspinbox_p.h4
-rw-r--r--src/widgets/widgets/qcalendarwidget.cpp15
-rw-r--r--src/widgets/widgets/qcheckbox.cpp28
-rw-r--r--src/widgets/widgets/qcheckbox.h6
-rw-r--r--src/widgets/widgets/qcombobox.cpp451
-rw-r--r--src/widgets/widgets/qcombobox.h15
-rw-r--r--src/widgets/widgets/qcombobox_p.h44
-rw-r--r--src/widgets/widgets/qcommandlinkbutton.cpp8
-rw-r--r--src/widgets/widgets/qdatetimeedit.cpp83
-rw-r--r--src/widgets/widgets/qdatetimeedit.h11
-rw-r--r--src/widgets/widgets/qdatetimeedit_p.h3
-rw-r--r--src/widgets/widgets/qdial.cpp2
-rw-r--r--src/widgets/widgets/qdialogbuttonbox.cpp329
-rw-r--r--src/widgets/widgets/qdialogbuttonbox.h2
-rw-r--r--src/widgets/widgets/qdialogbuttonbox_p.h80
-rw-r--r--src/widgets/widgets/qdockarealayout.cpp93
-rw-r--r--src/widgets/widgets/qdockarealayout_p.h8
-rw-r--r--src/widgets/widgets/qdockwidget.cpp183
-rw-r--r--src/widgets/widgets/qdockwidget.h10
-rw-r--r--src/widgets/widgets/qdockwidget_p.h19
-rw-r--r--src/widgets/widgets/qeffects.cpp7
-rw-r--r--src/widgets/widgets/qfocusframe.cpp8
-rw-r--r--src/widgets/widgets/qfontcombobox.cpp72
-rw-r--r--src/widgets/widgets/qfontcombobox.h2
-rw-r--r--src/widgets/widgets/qgroupbox.cpp11
-rw-r--r--src/widgets/widgets/qkeysequenceedit.cpp16
-rw-r--r--src/widgets/widgets/qlabel.cpp47
-rw-r--r--src/widgets/widgets/qlabel.h9
-rw-r--r--src/widgets/widgets/qlabel_p.h12
-rw-r--r--src/widgets/widgets/qlcdnumber.cpp4
-rw-r--r--src/widgets/widgets/qlineedit.cpp427
-rw-r--r--src/widgets/widgets/qlineedit.h14
-rw-r--r--src/widgets/widgets/qlineedit_p.cpp110
-rw-r--r--src/widgets/widgets/qlineedit_p.h22
-rw-r--r--src/widgets/widgets/qmainwindow.cpp51
-rw-r--r--src/widgets/widgets/qmainwindow.h1
-rw-r--r--src/widgets/widgets/qmainwindowlayout.cpp522
-rw-r--r--src/widgets/widgets/qmainwindowlayout_p.h45
-rw-r--r--src/widgets/widgets/qmdiarea.cpp74
-rw-r--r--src/widgets/widgets/qmdiarea_p.h2
-rw-r--r--src/widgets/widgets/qmdisubwindow.h1
-rw-r--r--src/widgets/widgets/qmenu.cpp44
-rw-r--r--src/widgets/widgets/qmenu_p.h7
-rw-r--r--src/widgets/widgets/qmenubar.cpp46
-rw-r--r--src/widgets/widgets/qmenubar_p.h2
-rw-r--r--src/widgets/widgets/qplaintextedit.cpp80
-rw-r--r--src/widgets/widgets/qplaintextedit.h5
-rw-r--r--src/widgets/widgets/qplaintextedit_p.h21
-rw-r--r--src/widgets/widgets/qpushbutton.cpp18
-rw-r--r--src/widgets/widgets/qpushbutton.h5
-rw-r--r--src/widgets/widgets/qpushbutton_p.h4
-rw-r--r--src/widgets/widgets/qradiobutton.cpp2
-rw-r--r--src/widgets/widgets/qscrollarea.cpp6
-rw-r--r--src/widgets/widgets/qscrollarea_p.h2
-rw-r--r--src/widgets/widgets/qscrollbar.cpp3
-rw-r--r--src/widgets/widgets/qsizegrip.cpp6
-rw-r--r--src/widgets/widgets/qspinbox.cpp7
-rw-r--r--src/widgets/widgets/qsplashscreen.cpp54
-rw-r--r--src/widgets/widgets/qsplitter.cpp2
-rw-r--r--src/widgets/widgets/qsplitter_p.h2
-rw-r--r--src/widgets/widgets/qstackedwidget.cpp6
-rw-r--r--src/widgets/widgets/qstatusbar.cpp14
-rw-r--r--src/widgets/widgets/qtabbar.cpp94
-rw-r--r--src/widgets/widgets/qtabbar.h2
-rw-r--r--src/widgets/widgets/qtabbar_p.h12
-rw-r--r--src/widgets/widgets/qtabwidget.cpp36
-rw-r--r--src/widgets/widgets/qtabwidget.h3
-rw-r--r--src/widgets/widgets/qtextbrowser.cpp29
-rw-r--r--src/widgets/widgets/qtextbrowser.h3
-rw-r--r--src/widgets/widgets/qtextedit.cpp153
-rw-r--r--src/widgets/widgets/qtextedit.h8
-rw-r--r--src/widgets/widgets/qtextedit_p.h19
-rw-r--r--src/widgets/widgets/qtoolbar.cpp52
-rw-r--r--src/widgets/widgets/qtoolbarextension.cpp6
-rw-r--r--src/widgets/widgets/qtoolbutton.cpp60
-rw-r--r--src/widgets/widgets/qtoolbutton.h8
-rw-r--r--src/widgets/widgets/qwidgetanimator.cpp3
-rw-r--r--src/widgets/widgets/qwidgetlinecontrol.cpp12
-rw-r--r--src/widgets/widgets/qwidgetlinecontrol_p.h2
-rw-r--r--src/widgets/widgets/qwidgettextcontrol.cpp12
-rw-r--r--src/widgets/widgets/qwidgettextcontrol_p.h5
-rw-r--r--src/xml/CMakeLists.txt2
-rw-r--r--src/xml/doc/qtxml.qdocconf2
-rw-r--r--src/xml/doc/snippets/CMakeLists.txt2
-rw-r--r--src/xml/doc/snippets/code/doc_src_qtxml.qdoc2
-rw-r--r--src/xml/doc/snippets/code/src_xml_dom_qdom.cpp11
-rw-r--r--src/xml/doc/snippets/code/src_xml_sax_qxml.cpp6
-rw-r--r--src/xml/doc/snippets/rsslisting/handler.cpp145
-rw-r--r--src/xml/doc/snippets/rsslisting/listing.cpp214
-rw-r--r--src/xml/doc/src/qt6-changes.qdoc2
-rw-r--r--src/xml/doc/src/qtxml-index.qdoc6
-rw-r--r--src/xml/doc/src/qtxml.qdoc2
-rw-r--r--src/xml/doc/src/xml-processing.qdoc46
-rw-r--r--src/xml/dom/qdom.cpp360
-rw-r--r--src/xml/dom/qdom.h101
-rw-r--r--src/xml/dom/qdom_p.h7
-rw-r--r--src/xml/dom/qdomhelpers.cpp7
3250 files changed, 228004 insertions, 128024 deletions
diff --git a/src/3rdparty/double-conversion/double-conversion/bignum.cc b/src/3rdparty/double-conversion/double-conversion/bignum.cc
index d6745d755a..5c74d70d3d 100644
--- a/src/3rdparty/double-conversion/double-conversion/bignum.cc
+++ b/src/3rdparty/double-conversion/double-conversion/bignum.cc
@@ -147,7 +147,7 @@ void Bignum::AssignHexString(Vector<const char> value) {
}
if (tmp > 0) {
DOUBLE_CONVERSION_ASSERT(tmp <= kBigitMask);
- RawBigit(used_bigits_++) = (tmp & kBigitMask);
+ RawBigit(used_bigits_++) = static_cast<Bignum::Chunk>(tmp & kBigitMask);
}
Clamp();
}
@@ -204,7 +204,7 @@ void Bignum::AddBignum(const Bignum& other) {
carry = sum >> kBigitSize;
++bigit_pos;
}
- used_bigits_ = (std::max)(bigit_pos, static_cast<int>(used_bigits_));
+ used_bigits_ = static_cast<int16_t>(std::max(bigit_pos, static_cast<int>(used_bigits_)));
DOUBLE_CONVERSION_ASSERT(IsClamped());
}
@@ -240,7 +240,7 @@ void Bignum::ShiftLeft(const int shift_amount) {
if (used_bigits_ == 0) {
return;
}
- exponent_ += (shift_amount / kBigitSize);
+ exponent_ += static_cast<int16_t>(shift_amount / kBigitSize);
const int local_shift = shift_amount % kBigitSize;
EnsureCapacity(used_bigits_ + 1);
BigitsShiftLeft(local_shift);
@@ -418,7 +418,7 @@ void Bignum::Square() {
DOUBLE_CONVERSION_ASSERT(accumulator == 0);
// Don't forget to update the used_digits and the exponent.
- used_bigits_ = product_length;
+ used_bigits_ = static_cast<int16_t>(product_length);
exponent_ *= 2;
Clamp();
}
@@ -739,8 +739,8 @@ void Bignum::Align(const Bignum& other) {
for (int i = 0; i < zero_bigits; ++i) {
RawBigit(i) = 0;
}
- used_bigits_ += zero_bigits;
- exponent_ -= zero_bigits;
+ used_bigits_ += static_cast<int16_t>(zero_bigits);
+ exponent_ -= static_cast<int16_t>(zero_bigits);
DOUBLE_CONVERSION_ASSERT(used_bigits_ >= 0);
DOUBLE_CONVERSION_ASSERT(exponent_ >= 0);
diff --git a/src/3rdparty/double-conversion/double-conversion/double-to-string.cc b/src/3rdparty/double-conversion/double-conversion/double-to-string.cc
index bb369fe8e1..215eaa96d4 100644
--- a/src/3rdparty/double-conversion/double-conversion/double-to-string.cc
+++ b/src/3rdparty/double-conversion/double-conversion/double-to-string.cc
@@ -79,7 +79,14 @@ void DoubleToStringConverter::CreateExponentialRepresentation(
StringBuilder* result_builder) const {
DOUBLE_CONVERSION_ASSERT(length != 0);
result_builder->AddCharacter(decimal_digits[0]);
- if (length != 1) {
+ if (length == 1) {
+ if ((flags_ & EMIT_TRAILING_DECIMAL_POINT_IN_EXPONENTIAL) != 0) {
+ result_builder->AddCharacter('.');
+ if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT_IN_EXPONENTIAL) != 0) {
+ result_builder->AddCharacter('0');
+ }
+ }
+ } else {
result_builder->AddCharacter('.');
result_builder->AddSubstring(&decimal_digits[1], length-1);
}
diff --git a/src/3rdparty/double-conversion/double-conversion/double-to-string.h b/src/3rdparty/double-conversion/double-conversion/double-to-string.h
index 04a4ac3840..abe60e8810 100644
--- a/src/3rdparty/double-conversion/double-conversion/double-to-string.h
+++ b/src/3rdparty/double-conversion/double-conversion/double-to-string.h
@@ -78,7 +78,9 @@ class DoubleToStringConverter {
EMIT_TRAILING_DECIMAL_POINT = 2,
EMIT_TRAILING_ZERO_AFTER_POINT = 4,
UNIQUE_ZERO = 8,
- NO_TRAILING_ZERO = 16
+ NO_TRAILING_ZERO = 16,
+ EMIT_TRAILING_DECIMAL_POINT_IN_EXPONENTIAL = 32,
+ EMIT_TRAILING_ZERO_AFTER_POINT_IN_EXPONENTIAL = 64
};
// Flags should be a bit-or combination of the possible Flags-enum.
@@ -97,6 +99,13 @@ class DoubleToStringConverter {
// of the result in precision mode. Matches printf's %g.
// When EMIT_TRAILING_ZERO_AFTER_POINT is also given, one trailing zero is
// preserved.
+ // - EMIT_TRAILING_DECIMAL_POINT_IN_EXPONENTIAL: when the input number has
+ // exactly one significant digit and is converted into exponent form then a
+ // trailing decimal point is appended to the significand in shortest mode
+ // or in precision mode with one requested digit.
+ // - EMIT_TRAILING_ZERO_AFTER_POINT_IN_EXPONENTIAL: in addition to a trailing
+ // decimal point emits a trailing '0'-character. This flag requires the
+ // EMIT_TRAILING_DECIMAL_POINT_IN_EXPONENTIAL flag.
//
// Infinity symbol and nan_symbol provide the string representation for these
// special values. If the string is NULL and the special value is encountered
@@ -132,6 +141,22 @@ class DoubleToStringConverter {
// ToPrecision(230.0, 2) -> "230." with EMIT_TRAILING_DECIMAL_POINT.
// ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT.
//
+ // When converting numbers with exactly one significant digit to exponent
+ // form in shortest mode or in precision mode with one requested digit, the
+ // EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT flags have
+ // no effect. Use the EMIT_TRAILING_DECIMAL_POINT_IN_EXPONENTIAL flag to
+ // append a decimal point in this case and the
+ // EMIT_TRAILING_ZERO_AFTER_POINT_IN_EXPONENTIAL flag to also append a
+ // '0'-character in this case.
+ // Example with decimal_in_shortest_low = 0:
+ // ToShortest(0.0009) -> "9e-4"
+ // with EMIT_TRAILING_DECIMAL_POINT_IN_EXPONENTIAL deactivated.
+ // ToShortest(0.0009) -> "9.e-4"
+ // with EMIT_TRAILING_DECIMAL_POINT_IN_EXPONENTIAL activated.
+ // ToShortest(0.0009) -> "9.0e-4"
+ // with EMIT_TRAILING_DECIMAL_POINT_IN_EXPONENTIAL activated and
+ // EMIT_TRAILING_ZERO_AFTER_POINT_IN_EXPONENTIAL activated.
+ //
// The min_exponent_width is used for exponential representations.
// The converter adds leading '0's to the exponent until the exponent
// is at least min_exponent_width digits long.
diff --git a/src/3rdparty/double-conversion/qt_attribution.json b/src/3rdparty/double-conversion/qt_attribution.json
index 21692f0490..4166ccef32 100644
--- a/src/3rdparty/double-conversion/qt_attribution.json
+++ b/src/3rdparty/double-conversion/qt_attribution.json
@@ -5,8 +5,8 @@
"QtUsage": "Used in Qt Core. Configure with -system-doubleconversion or -no-doubleconversion to avoid.",
"Homepage": "https://github.com/google/double-conversion",
- "Version": "3.2.1",
- "DownloadLocation": "https://github.com/google/double-conversion/releases/tag/v3.2.1",
+ "Version": "3.3.0",
+ "DownloadLocation": "https://github.com/google/double-conversion/releases/tag/v3.3.0",
"License": "BSD 3-clause \"New\" or \"Revised\" License",
"LicenseId": "BSD-3-Clause",
"LicenseFile": "LICENSE",
diff --git a/src/3rdparty/easing/qt_attribution.json b/src/3rdparty/easing/qt_attribution.json
index bccc67b6d4..1535efa585 100644
--- a/src/3rdparty/easing/qt_attribution.json
+++ b/src/3rdparty/easing/qt_attribution.json
@@ -5,7 +5,7 @@
"QtUsage": "Used in Qt Core (QEasingCurve).",
"Files": "easing.cpp",
- "Homepage": "treat as final",
+ "Comment": "treat as final",
"Homepage": "http://robertpenner.com/easing/",
"License": "BSD 3-clause \"New\" or \"Revised\" License",
"LicenseId": "BSD-3-Clause",
diff --git a/src/3rdparty/forkfd/forkfd.c b/src/3rdparty/forkfd/forkfd.c
index 9960e45d4e..edef3c5bcc 100644
--- a/src/3rdparty/forkfd/forkfd.c
+++ b/src/3rdparty/forkfd/forkfd.c
@@ -72,6 +72,10 @@
# undef HAVE_WAITID
#endif
+#if (defined(__FreeBSD__) && defined(__FreeBSD_version) && __FreeBSD_version >= 1300000)
+# include <sys/eventfd.h>
+# define HAVE_EVENTFD 1
+#endif
#if (defined(__FreeBSD__) && defined(__FreeBSD_version) && __FreeBSD_version >= 1000032) || \
(defined(__OpenBSD__) && OpenBSD >= 201505) || \
(defined(__NetBSD__) && __NetBSD_Version__ >= 600000000)
@@ -605,9 +609,7 @@ static int forkfd_fork_fallback(int flags, pid_t *ppid)
int death_pipe[2];
int sync_pipe[2];
int ret;
-#ifdef __linux__
- int efd;
-#endif
+ int efd = -1;
(void) pthread_once(&forkfd_initialization, forkfd_initialize);
@@ -624,9 +626,8 @@ static int forkfd_fork_fallback(int flags, pid_t *ppid)
#ifdef HAVE_EVENTFD
/* try using an eventfd, which consumes less resources */
efd = eventfd(0, EFD_CLOEXEC);
- if (efd == -1)
#endif
- {
+ if (efd == -1) {
/* try a pipe */
if (create_pipe(sync_pipe, FFD_CLOEXEC) == -1) {
/* failed both at eventfd and pipe; fail and pass errno */
@@ -653,14 +654,13 @@ static int forkfd_fork_fallback(int flags, pid_t *ppid)
if (pid == 0) {
/* this is the child process */
/* first, wait for the all clear */
-#ifdef HAVE_EVENTFD
if (efd != -1) {
+#ifdef HAVE_EVENTFD
eventfd_t val64;
EINTR_LOOP(ret, eventfd_read(efd, &val64));
EINTR_LOOP(ret, close(efd));
- } else
#endif
- {
+ } else {
char c;
EINTR_LOOP(ret, close(sync_pipe[1]));
EINTR_LOOP(ret, read(sync_pipe[0], &c, sizeof c));
diff --git a/src/3rdparty/forkfd/forkfd_linux.c b/src/3rdparty/forkfd/forkfd_linux.c
index cc7af6cb53..4dacc1919d 100644
--- a/src/3rdparty/forkfd/forkfd_linux.c
+++ b/src/3rdparty/forkfd/forkfd_linux.c
@@ -157,7 +157,7 @@ static int system_forkfd_pidfd_set_flags(int pidfd, int flags)
int system_vforkfd(int flags, pid_t *ppid, int (*childFn)(void *), void *token, int *system)
{
- __attribute__((aligned(64))) char childStack[4096];
+ __attribute__((aligned(64))) char childStack[SIGSTKSZ];
pid_t pid;
int pidfd;
unsigned long cloneflags = CLONE_PIDFD | CLONE_VFORK | CLONE_VM | SIGCHLD;
diff --git a/src/3rdparty/forkfd/qt_attribution.json b/src/3rdparty/forkfd/qt_attribution.json
index ebbb19c718..1b84779133 100644
--- a/src/3rdparty/forkfd/qt_attribution.json
+++ b/src/3rdparty/forkfd/qt_attribution.json
@@ -3,8 +3,8 @@
"Name": "forkfd",
"QDocModule": "qtcore",
"QtUsage": "Used on most Unix platforms in Qt Core.",
- "Files": "No upstream; treat as final",
- "Files": "forkfd.c forkfd.h forkfd_gcc.h",
+ "Comment": "No upstream; treat as final",
+ "Files": [ "forkfd.c", "forkfd.h", "forkfd_gcc.h" ],
"License": "MIT License",
"LicenseId": "MIT",
diff --git a/src/3rdparty/freetype/README b/src/3rdparty/freetype/README
index 327b94d8e5..cd4c1d7d11 100644
--- a/src/3rdparty/freetype/README
+++ b/src/3rdparty/freetype/README
@@ -1,4 +1,4 @@
-FreeType 2.13.0
+FreeType 2.13.2
===============
Homepage: https://www.freetype.org
@@ -32,9 +32,9 @@ sites. Go to
and download one of the following files.
- freetype-doc-2.13.0.tar.xz
- freetype-doc-2.13.0.tar.gz
- ftdoc2130.zip
+ freetype-doc-2.13.2.tar.xz
+ freetype-doc-2.13.2.tar.gz
+ ftdoc2132.zip
To view the documentation online, go to
diff --git a/src/3rdparty/freetype/docs/CHANGES b/src/3rdparty/freetype/docs/CHANGES
index 3c6a8774b1..96cf607d70 100644
--- a/src/3rdparty/freetype/docs/CHANGES
+++ b/src/3rdparty/freetype/docs/CHANGES
@@ -1,3 +1,57 @@
+CHANGES BETWEEN 2.13.1 and 2.13.2 (2023-Aug-25)
+
+ I. MISCELLANEOUS
+
+ - Better support for CFF2 variation fonts.
+
+ - TrueType interpreter version 38 (also known as 'Infinality') has
+ been removed.
+
+ - Improved OpenVMS support.
+
+
+======================================================================
+
+CHANGES BETWEEN 2.13.0 and 2.13.1 (2023-Jun-24)
+
+ I. MISCELLANEOUS
+
+ - New function `FT_Get_Default_Named_Instance` to get the index of
+ the default named instance of an OpenType Variation Font.
+
+ - A new load flag `FT_LOAD_NO_SVG` to make FreeType ignore glyphs in
+ an 'SVG ' table.
+
+ - New function `FT_GlyphSlot_AdjustWeight` to adjust the glyph
+ weight either horizontally or vertically. This is part of the
+ `ftsynth.h` header file, which is still considered to be in alpha
+ stage.
+
+ - TrueType interpreter version 38 (also known as 'Infinality') has
+ been deactivated; the value of `TT_INTERPRETER_VERSION_38` is now
+ the same as `TT_INTERPRETER_VERSION_40`.
+
+ - Updated OpenVMS support.
+
+ - The base API documentation has been modularized for easier
+ handling.
+
+ - Switching named instances on and off in Variation Fonts was buggy
+ if the design coordinates didn't change.
+
+ - `ftbench` has a new command-line option `-a` to apply design
+ coordinates.
+
+ - `ftview` can now flip SVG rendering on and off using the 'Z' key.
+
+ - In `ftmulti` it is now possible to toggle the fill rule and
+ overlap flag used for rendering glyphs using the 'F3' and 'F4'
+ keys, respectively. Toggling the anti-aliased mode has been
+ changed to the 'TAB' key.
+
+
+======================================================================
+
CHANGES BETWEEN 2.12.1 and 2.13.0 (2023-Feb-09)
I. IMPORTANT CHANGES
@@ -12,7 +66,7 @@ CHANGES BETWEEN 2.12.1 and 2.13.0 (2023-Feb-09)
https://learn.microsoft.com/en-us/typography/opentype/spec/colr
- III. MISCELLANEOUS
+ II. MISCELLANEOUS
- For OpenType Variable Fonts, `avar` table format 2.0 is now
supported. The code was contributed by Behdad Esfahbod.
@@ -75,6 +129,10 @@ CHANGES BETWEEN 2.12.1 and 2.13.0 (2023-Feb-09)
af_debug_hints_
```
+ - The internal zlib library was updated to version 1.2.13. Note,
+ however, that FreeType is *not* affected by CVE-2022-37434 since
+ it doesn't use the `inflateGetHeader` function.
+
======================================================================
@@ -2420,7 +2478,7 @@ CHANGES BETWEEN 2.3.8 and 2.3.7
is provided for x86 and ARM. See FT_CONFIG_OPTION_INLINE_MULFIX
and FT_CONFIG_OPTION_NO_ASSEMBLER (in ftoption.h) for more.
- - The handling of `tricky' fonts (this is, fonts which don't work
+ - The handling of `tricky' fonts (that is, fonts which don't work
with the autohinter, needing the font format's hinting engine)
has been generalized and changed slightly:
@@ -2877,7 +2935,7 @@ CHANGES BETWEEN 2.2 and 2.1.10
II. IMPORTANT CHANGES
- - Version 2.2 no longer exposes its internals, this is, the header
+ - Version 2.2 no longer exposes its internals, that is, the header
files located in the `include/freetype/internal' directory of
the source package are not copied anymore by the `make install'
command. Consequently, a number of rogue clients which directly
diff --git a/src/3rdparty/freetype/docs/DEBUG b/src/3rdparty/freetype/docs/DEBUG
index 4a5ac3a40c..7398df69b1 100644
--- a/src/3rdparty/freetype/docs/DEBUG
+++ b/src/3rdparty/freetype/docs/DEBUG
@@ -270,12 +270,12 @@ to access them.
`FT2_DEBUG' environment variable. Use this function to override
the value with `level'. Use value `NULL' to disable tracing.
- FT_Trace_Set_Default_Level():
+ FT_Trace_Set_Default_Level( void )
Reset the tracing levels to the default value, i.e., the value of
the `FT2_DEBUG' environment variable or no tracing if not set.
- FT_Set_Log_Handler( ft_custom_log_handler handler ):
+ FT_Set_Log_Handler( ft_custom_log_handler handler )
Use `handler' as a custom handler for formatting tracing and error
messages. The `ft_custom_log_handler' typedef has the following
@@ -290,7 +290,7 @@ to access them.
first argument of `FT_TRACE' or `FT_ERROR', and `args' holds the
remaining arguments.
- FT_Set_Default_Log_Handler():
+ FT_Set_Default_Log_Handler( void )
Reset the log handler to the default version.
diff --git a/src/3rdparty/freetype/import_from_tarball.sh b/src/3rdparty/freetype/import_from_tarball.sh
index e7d1bb8c37..ff691ff99e 100755
--- a/src/3rdparty/freetype/import_from_tarball.sh
+++ b/src/3rdparty/freetype/import_from_tarball.sh
@@ -1,44 +1,8 @@
#! /bin/sh
-#############################################################################
-##
-## Copyright (C) 2016 The Qt Company Ltd.
-## Contact: https://www.qt.io/licensing/
-##
-## This file is the build configuration utility 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$
-##
-#############################################################################
-
+# Copyright (C) 2016 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+#
# This is a small script to copy the required files from a freetype tarball
# into 3rdparty/freetype/ . Documentation, tests, demos etc. are not imported.
diff --git a/src/3rdparty/freetype/include/dlg/dlg.h b/src/3rdparty/freetype/include/dlg/dlg.h
index 3a7abf8f05..fa10730e83 100644
--- a/src/3rdparty/freetype/include/dlg/dlg.h
+++ b/src/3rdparty/freetype/include/dlg/dlg.h
@@ -85,6 +85,13 @@
#endif
#endif
+// This macro is used when an assertion fails. It gets the source expression
+// and can return an alternative (that must stay alive).
+// Mainly useful to execute something on failed assertion.
+#ifndef DLG_FAILED_ASSERTION_TEXT
+ #define DLG_FAILED_ASSERTION_TEXT(x) x
+#endif
+
// - utility -
// two methods needed since cplusplus does not support compound literals
// and c does not support uniform initialization/initializer lists
@@ -131,83 +138,12 @@ struct dlg_origin {
// Type of the output handler, see dlg_set_handler.
typedef void(*dlg_handler)(const struct dlg_origin* origin, const char* string, void* data);
-#ifdef DLG_DISABLE
+#ifndef DLG_DISABLE
// Tagged/Untagged logging with variable level
// Tags must always be in the format `("tag1", "tag2")` (including brackets)
- #define dlg_log(level, ...)
- #define dlg_logt(level, tags, ...)
-
- // Dynamic level assert macros in various versions for additional arguments
- #define dlg_assertl(level, expr) // assert without tags/message
- #define dlg_assertlt(level, tags, expr) // assert with tags
- #define dlg_assertlm(level, expr, ...) // assert with message
- #define dlg_assertltm(level, tags, expr, ...) // assert with tags & message
-
- // Sets the handler that is responsible for formatting and outputting log calls.
- // This function is not thread safe and the handler is set globally.
- // The handler itself must not change dlg tags or call a dlg macro (if it
- // does so, the provided string or tags array in 'origin' might get invalid).
- // The handler can also be used for various other things such as dealing
- // with failed assertions or filtering calls based on the passed tags.
- // The default handler is dlg_default_output (see its doc for more info).
- // If using c++ make sure the registered handler cannot throw e.g. by
- // wrapping everything into a try-catch blog.
- inline void dlg_set_handler(dlg_handler handler, void* data) {
- (void) handler;
- (void) data;
- }
-
- // Returns the currently active dlg handler and sets `data` to
- // its user data pointer. `data` must not be NULL.
- // Useful to create handler chains.
- // This function is not threadsafe, i.e. retrieving the handler while
- // changing it from another thread is unsafe.
- // See `dlg_set_handler`.
- inline dlg_handler dlg_get_handler(void** data) {
- *data = NULL;
- return NULL;
- }
-
- // The default output handler.
- // Only use this to reset the output handler, prefer to use
- // dlg_generic_output (from output.h) which this function simply calls.
- // It also flushes the stream used and correctly outputs even from multiple threads.
- inline void dlg_default_output(const struct dlg_origin* o, const char* str, void* data) {
- (void) o;
- (void) str;
- (void) data;
- }
-
- // Adds the given tag associated with the given function to the thread specific list.
- // If func is not NULL the tag will only applied to calls from the same function.
- // Remove the tag again calling dlg_remove_tag (with exactly the same pointers!).
- // Does not check if the tag is already present.
- inline void dlg_add_tag(const char* tag, const char* func) {
- (void) tag;
- (void) func;
- }
-
- // Removes a tag added with dlg_add_tag (has no effect for tags no present).
- // The pointers must be exactly the same pointers that were supplied to dlg_add_tag,
- // this function will not check using strcmp. When the same tag/func combination
- // is added multiple times, this function remove exactly one candidate, it is
- // undefined which. Returns whether a tag was found (and removed).
- inline bool dlg_remove_tag(const char* tag, const char* func) {
- (void) tag;
- (void) func;
- return true;
- }
-
- // Returns the thread-specific buffer and its size for dlg.
- // The buffer should only be used by formatting functions.
- // The buffer can be reallocated and the size changed, just make sure
- // to update both values correctly.
- inline char** dlg_thread_buffer(size_t** size) {
- (void) size;
- return NULL;
- }
-
-#else // DLG_DISABLE
+ // Example usages:
+ // dlg_log(dlg_level_warning, "test 1")
+ // dlg_logt(("tag1, "tag2"), dlg_level_debug, "test %d", 2)
#define dlg_log(level, ...) if(level >= DLG_LOG_LEVEL) \
dlg__do_log(level, DLG_CREATE_TAGS(NULL), DLG_FILE, __LINE__, __func__, \
DLG_FMT_FUNC(__VA_ARGS__), NULL)
@@ -215,23 +151,31 @@ typedef void(*dlg_handler)(const struct dlg_origin* origin, const char* string,
dlg__do_log(level, DLG_CREATE_TAGS tags, DLG_FILE, __LINE__, __func__, \
DLG_FMT_FUNC(__VA_ARGS__), NULL)
+ // Dynamic level assert macros in various versions for additional arguments
+ // Example usages:
+ // dlg_assertl(dlg_level_warning, data != nullptr);
+ // dlg_assertlt(("tag1, "tag2"), dlg_level_trace, data != nullptr);
+ // dlg_asserttlm(("tag1), dlg_level_warning, data != nullptr, "Data must not be null");
+ // dlg_assertlm(dlg_level_error, data != nullptr, "Data must not be null");
#define dlg_assertl(level, expr) if(level >= DLG_ASSERT_LEVEL && !(expr)) \
- dlg__do_log(level, DLG_CREATE_TAGS(NULL), DLG_FILE, __LINE__, __func__, NULL, #expr)
+ dlg__do_log(level, DLG_CREATE_TAGS(NULL), DLG_FILE, __LINE__, __func__, NULL, \
+ DLG_FAILED_ASSERTION_TEXT(#expr))
#define dlg_assertlt(level, tags, expr) if(level >= DLG_ASSERT_LEVEL && !(expr)) \
- dlg__do_log(level, DLG_CREATE_TAGS tags, DLG_FILE, __LINE__, __func__, NULL, #expr)
+ dlg__do_log(level, DLG_CREATE_TAGS tags, DLG_FILE, __LINE__, __func__, NULL, \
+ DLG_FAILED_ASSERTION_TEXT(#expr))
#define dlg_assertlm(level, expr, ...) if(level >= DLG_ASSERT_LEVEL && !(expr)) \
dlg__do_log(level, DLG_CREATE_TAGS(NULL), DLG_FILE, __LINE__, __func__, \
- DLG_FMT_FUNC(__VA_ARGS__), #expr)
+ DLG_FMT_FUNC(__VA_ARGS__), DLG_FAILED_ASSERTION_TEXT(#expr))
#define dlg_assertltm(level, tags, expr, ...) if(level >= DLG_ASSERT_LEVEL && !(expr)) \
dlg__do_log(level, DLG_CREATE_TAGS tags, DLG_FILE, __LINE__, \
- __func__, DLG_FMT_FUNC(__VA_ARGS__), #expr)
+ __func__, DLG_FMT_FUNC(__VA_ARGS__), DLG_FAILED_ASSERTION_TEXT(#expr))
- DLG_API void dlg_set_handler(dlg_handler handler, void* data);
- DLG_API dlg_handler dlg_get_handler(void** data);
- DLG_API void dlg_default_output(const struct dlg_origin*, const char* string, void*);
- DLG_API void dlg_add_tag(const char* tag, const char* func);
- DLG_API bool dlg_remove_tag(const char* tag, const char* func);
- DLG_API char** dlg_thread_buffer(size_t** size);
+ #define dlg__assert_or(level, tags, expr, code, msg) if(!(expr)) {\
+ if(level >= DLG_ASSERT_LEVEL) \
+ dlg__do_log(level, tags, DLG_FILE, __LINE__, __func__, msg, \
+ DLG_FAILED_ASSERTION_TEXT(#expr)); \
+ code; \
+ } (void) NULL
// - Private interface: not part of the abi/api but needed in macros -
// Formats the given format string and arguments as printf would, uses the thread buffer.
@@ -239,8 +183,66 @@ typedef void(*dlg_handler)(const struct dlg_origin* origin, const char* string,
DLG_API void dlg__do_log(enum dlg_level lvl, const char* const*, const char*, int,
const char*, const char*, const char*);
DLG_API const char* dlg__strip_root_path(const char* file, const char* base);
+
+#else // DLG_DISABLE
+
+ #define dlg_log(level, ...)
+ #define dlg_logt(level, tags, ...)
+
+ #define dlg_assertl(level, expr) // assert without tags/message
+ #define dlg_assertlt(level, tags, expr) // assert with tags
+ #define dlg_assertlm(level, expr, ...) // assert with message
+ #define dlg_assertltm(level, tags, expr, ...) // assert with tags & message
+
+ #define dlg__assert_or(level, tags, expr, code, msg) if(!(expr)) { code; } (void) NULL
#endif // DLG_DISABLE
+// The API below is independent from DLG_DISABLE
+
+// Sets the handler that is responsible for formatting and outputting log calls.
+// This function is not thread safe and the handler is set globally.
+// The handler itself must not change dlg tags or call a dlg macro (if it
+// does so, the provided string or tags array in 'origin' might get invalid).
+// The handler can also be used for various other things such as dealing
+// with failed assertions or filtering calls based on the passed tags.
+// The default handler is dlg_default_output (see its doc for more info).
+// If using c++ make sure the registered handler cannot throw e.g. by
+// wrapping everything into a try-catch blog.
+DLG_API void dlg_set_handler(dlg_handler handler, void* data);
+
+// The default output handler.
+// Only use this to reset the output handler, prefer to use
+// dlg_generic_output (from output.h) which this function simply calls.
+// It also flushes the stream used and correctly outputs even from multiple threads.
+DLG_API void dlg_default_output(const struct dlg_origin*, const char* string, void*);
+
+// Returns the currently active dlg handler and sets `data` to
+// its user data pointer. `data` must not be NULL.
+// Useful to create handler chains.
+// This function is not threadsafe, i.e. retrieving the handler while
+// changing it from another thread is unsafe.
+// See `dlg_set_handler`.
+DLG_API dlg_handler dlg_get_handler(void** data);
+
+// Adds the given tag associated with the given function to the thread specific list.
+// If func is not NULL the tag will only applied to calls from the same function.
+// Remove the tag again calling dlg_remove_tag (with exactly the same pointers!).
+// Does not check if the tag is already present.
+DLG_API void dlg_add_tag(const char* tag, const char* func);
+
+// Removes a tag added with dlg_add_tag (has no effect for tags no present).
+// The pointers must be exactly the same pointers that were supplied to dlg_add_tag,
+// this function will not check using strcmp. When the same tag/func combination
+// is added multiple times, this function remove exactly one candidate, it is
+// undefined which. Returns whether a tag was found (and removed).
+DLG_API bool dlg_remove_tag(const char* tag, const char* func);
+
+// Returns the thread-specific buffer and its size for dlg.
+// The buffer should only be used by formatting functions.
+// The buffer can be reallocated and the size changed, just make sure
+// to update both values correctly.
+DLG_API char** dlg_thread_buffer(size_t** size);
+
// Untagged leveled logging
#define dlg_trace(...) dlg_log(dlg_level_trace, __VA_ARGS__)
#define dlg_debug(...) dlg_log(dlg_level_debug, __VA_ARGS__)
@@ -263,6 +265,24 @@ typedef void(*dlg_handler)(const struct dlg_origin* origin, const char* string,
#define dlg_assertm(expr, ...) dlg_assertlm(DLG_DEFAULT_ASSERT, expr, __VA_ARGS__)
#define dlg_asserttm(tags, expr, ...) dlg_assertltm(DLG_DEFAULT_ASSERT, tags, expr, __VA_ARGS__)
+// If (expr) does not evaluate to true, always executes 'code' (no matter what
+// DLG_ASSERT_LEVEL is or if dlg is disabled or not).
+// When dlg is enabled and the level is greater or equal to DLG_ASSERT_LEVEL,
+// logs the failed assertion.
+// Example usages:
+// dlg_assertl_or(dlg_level_warn, data != nullptr, return);
+// dlg_assertlm_or(dlg_level_fatal, data != nullptr, return, "Data must not be null");
+// dlg_assert_or(data != nullptr, logError(); return false);
+#define dlg_assertltm_or(level, tags, expr, code, ...) dlg__assert_or(level, \
+ DLG_CREATE_TAGS tags, expr, code, DLG_FMT_FUNC(__VA_ARGS__))
+#define dlg_assertlm_or(level, expr, code, ...) dlg__assert_or(level, \
+ DLG_CREATE_TAGS(NULL), expr, code, DLG_FMT_FUNC(__VA_ARGS__))
+#define dlg_assertl_or(level, expr, code) dlg__assert_or(level, \
+ DLG_CREATE_TAGS(NULL), expr, code, NULL)
+
+#define dlg_assert_or(expr, code) dlg_assertl_or(DLG_DEFAULT_ASSERT, expr, code)
+#define dlg_assertm_or(expr, code, ...) dlg_assertlm_or(DLG_DEFAULT_ASSERT, expr, code, __VA_ARGS__)
+
#ifdef __cplusplus
}
#endif
diff --git a/src/3rdparty/freetype/include/freetype/config/ftoption.h b/src/3rdparty/freetype/include/freetype/config/ftoption.h
index 9e03e1783b..1976b33af9 100644
--- a/src/3rdparty/freetype/include/freetype/config/ftoption.h
+++ b/src/3rdparty/freetype/include/freetype/config/ftoption.h
@@ -661,36 +661,12 @@ FT_BEGIN_HEADER
* not) instructions in a certain way so that all TrueType fonts look like
* they do in a Windows ClearType (DirectWrite) environment. See [1] for a
* technical overview on what this means. See `ttinterp.h` for more
- * details on the LEAN option.
+ * details on this option.
*
- * There are three possible values.
- *
- * Value 1:
- * This value is associated with the 'Infinality' moniker, contributed by
- * an individual nicknamed Infinality with the goal of making TrueType
- * fonts render better than on Windows. A high amount of configurability
- * and flexibility, down to rules for single glyphs in fonts, but also
- * very slow. Its experimental and slow nature and the original
- * developer losing interest meant that this option was never enabled in
- * default builds.
- *
- * The corresponding interpreter version is v38.
- *
- * Value 2:
- * The new default mode for the TrueType driver. The Infinality code
- * base was stripped to the bare minimum and all configurability removed
- * in the name of speed and simplicity. The configurability was mainly
- * aimed at legacy fonts like 'Arial', 'Times New Roman', or 'Courier'.
- * Legacy fonts are fonts that modify vertical stems to achieve clean
- * black-and-white bitmaps. The new mode focuses on applying a minimal
- * set of rules to all fonts indiscriminately so that modern and web
- * fonts render well while legacy fonts render okay.
- *
- * The corresponding interpreter version is v40.
- *
- * Value 3:
- * Compile both, making both v38 and v40 available (the latter is the
- * default).
+ * The new default mode focuses on applying a minimal set of rules to all
+ * fonts indiscriminately so that modern and web fonts render well while
+ * legacy fonts render okay. The corresponding interpreter version is v40.
+ * The so-called Infinality mode (v38) is no longer available in FreeType.
*
* By undefining these, you get rendering behavior like on Windows without
* ClearType, i.e., Windows XP without ClearType enabled and Win9x
@@ -705,9 +681,7 @@ FT_BEGIN_HEADER
* [1]
* https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx
*/
-/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING 1 */
-#define TT_CONFIG_OPTION_SUBPIXEL_HINTING 2
-/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING ( 1 | 2 ) */
+#define TT_CONFIG_OPTION_SUBPIXEL_HINTING
/**************************************************************************
@@ -977,22 +951,15 @@ FT_BEGIN_HEADER
/*
- * The next three macros are defined if native TrueType hinting is
+ * The next two macros are defined if native TrueType hinting is
* requested by the definitions above. Don't change this.
*/
#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
#define TT_USE_BYTECODE_INTERPRETER
-
#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
-#if TT_CONFIG_OPTION_SUBPIXEL_HINTING & 1
-#define TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-#endif
-
-#if TT_CONFIG_OPTION_SUBPIXEL_HINTING & 2
#define TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
#endif
#endif
-#endif
/*
diff --git a/src/3rdparty/freetype/include/freetype/config/ftstdlib.h b/src/3rdparty/freetype/include/freetype/config/ftstdlib.h
index 3c9d2ae59a..f65148a902 100644
--- a/src/3rdparty/freetype/include/freetype/config/ftstdlib.h
+++ b/src/3rdparty/freetype/include/freetype/config/ftstdlib.h
@@ -111,13 +111,13 @@
#include <stdio.h>
-#define FT_FILE FILE
-#define ft_fclose fclose
-#define ft_fopen fopen
-#define ft_fread fread
-#define ft_fseek fseek
-#define ft_ftell ftell
-#define ft_sprintf sprintf
+#define FT_FILE FILE
+#define ft_fclose fclose
+#define ft_fopen fopen
+#define ft_fread fread
+#define ft_fseek fseek
+#define ft_ftell ftell
+#define ft_snprintf snprintf
/**************************************************************************
diff --git a/src/3rdparty/freetype/include/freetype/freetype.h b/src/3rdparty/freetype/include/freetype/freetype.h
index efff74fe39..92acf3794a 100644
--- a/src/3rdparty/freetype/include/freetype/freetype.h
+++ b/src/3rdparty/freetype/include/freetype/freetype.h
@@ -102,61 +102,25 @@ FT_BEGIN_HEADER
*/
-
- /*************************************************************************/
- /*************************************************************************/
- /* */
- /* B A S I C T Y P E S */
- /* */
- /*************************************************************************/
- /*************************************************************************/
-
-
/**************************************************************************
*
* @section:
- * base_interface
+ * font_testing_macros
*
* @title:
- * Base Interface
+ * Font Testing Macros
*
* @abstract:
- * The FreeType~2 base font interface.
+ * Macros to test various properties of fonts.
*
* @description:
- * This section describes the most important public high-level API
- * functions of FreeType~2.
+ * Macros to test the most important font properties.
*
- * @order:
- * FT_Library
- * FT_Face
- * FT_Size
- * FT_GlyphSlot
- * FT_CharMap
- * FT_Encoding
- * FT_ENC_TAG
- *
- * FT_FaceRec
- *
- * FT_FACE_FLAG_SCALABLE
- * FT_FACE_FLAG_FIXED_SIZES
- * FT_FACE_FLAG_FIXED_WIDTH
- * FT_FACE_FLAG_HORIZONTAL
- * FT_FACE_FLAG_VERTICAL
- * FT_FACE_FLAG_COLOR
- * FT_FACE_FLAG_SFNT
- * FT_FACE_FLAG_CID_KEYED
- * FT_FACE_FLAG_TRICKY
- * FT_FACE_FLAG_KERNING
- * FT_FACE_FLAG_MULTIPLE_MASTERS
- * FT_FACE_FLAG_VARIATION
- * FT_FACE_FLAG_GLYPH_NAMES
- * FT_FACE_FLAG_EXTERNAL_STREAM
- * FT_FACE_FLAG_HINTER
- * FT_FACE_FLAG_SVG
- * FT_FACE_FLAG_SBIX
- * FT_FACE_FLAG_SBIX_OVERLAY
+ * It is recommended to use these high-level macros instead of directly
+ * testing the corresponding flags, which are scattered over various
+ * structures.
*
+ * @order:
* FT_HAS_HORIZONTAL
* FT_HAS_VERTICAL
* FT_HAS_KERNING
@@ -176,21 +140,59 @@ FT_BEGIN_HEADER
* FT_IS_NAMED_INSTANCE
* FT_IS_VARIATION
*
- * FT_STYLE_FLAG_BOLD
- * FT_STYLE_FLAG_ITALIC
+ */
+
+
+ /**************************************************************************
+ *
+ * @section:
+ * library_setup
*
- * FT_SizeRec
- * FT_Size_Metrics
+ * @title:
+ * Library Setup
*
- * FT_GlyphSlotRec
- * FT_Glyph_Metrics
- * FT_SubGlyph
+ * @abstract:
+ * Functions to start and end the usage of the FreeType library.
*
- * FT_Bitmap_Size
+ * @description:
+ * Functions to start and end the usage of the FreeType library.
+ *
+ * Note that @FT_Library_Version and @FREETYPE_XXX are of limited use
+ * because even a new release of FreeType with only documentation
+ * changes increases the version number.
*
+ * @order:
+ * FT_Library
* FT_Init_FreeType
* FT_Done_FreeType
*
+ * FT_Library_Version
+ * FREETYPE_XXX
+ *
+ */
+
+
+ /**************************************************************************
+ *
+ * @section:
+ * face_creation
+ *
+ * @title:
+ * Face Creation
+ *
+ * @abstract:
+ * Functions to manage fonts.
+ *
+ * @description:
+ * The functions and structures collected in this section operate on
+ * fonts globally.
+ *
+ * @order:
+ * FT_Face
+ * FT_FaceRec
+ * FT_FACE_FLAG_XXX
+ * FT_STYLE_FLAG_XXX
+ *
* FT_New_Face
* FT_Done_Face
* FT_Reference_Face
@@ -198,10 +200,36 @@ FT_BEGIN_HEADER
* FT_Face_Properties
* FT_Open_Face
* FT_Open_Args
+ * FT_OPEN_XXX
* FT_Parameter
* FT_Attach_File
* FT_Attach_Stream
*
+ */
+
+
+ /**************************************************************************
+ *
+ * @section:
+ * sizing_and_scaling
+ *
+ * @title:
+ * Sizing and Scaling
+ *
+ * @abstract:
+ * Functions to manage font sizes.
+ *
+ * @description:
+ * The functions and structures collected in this section are related to
+ * selecting and manipulating the size of a font globally.
+ *
+ * @order:
+ * FT_Size
+ * FT_SizeRec
+ * FT_Size_Metrics
+ *
+ * FT_Bitmap_Size
+ *
* FT_Set_Char_Size
* FT_Set_Pixel_Sizes
* FT_Request_Size
@@ -209,44 +237,37 @@ FT_BEGIN_HEADER
* FT_Size_Request_Type
* FT_Size_RequestRec
* FT_Size_Request
+ *
* FT_Set_Transform
* FT_Get_Transform
- * FT_Load_Glyph
- * FT_Get_Char_Index
- * FT_Get_First_Char
- * FT_Get_Next_Char
- * FT_Load_Char
*
- * FT_OPEN_MEMORY
- * FT_OPEN_STREAM
- * FT_OPEN_PATHNAME
- * FT_OPEN_DRIVER
- * FT_OPEN_PARAMS
- *
- * FT_LOAD_DEFAULT
- * FT_LOAD_RENDER
- * FT_LOAD_MONOCHROME
- * FT_LOAD_LINEAR_DESIGN
- * FT_LOAD_NO_SCALE
- * FT_LOAD_NO_HINTING
- * FT_LOAD_NO_BITMAP
- * FT_LOAD_SBITS_ONLY
- * FT_LOAD_NO_AUTOHINT
- * FT_LOAD_COLOR
- *
- * FT_LOAD_VERTICAL_LAYOUT
- * FT_LOAD_IGNORE_TRANSFORM
- * FT_LOAD_FORCE_AUTOHINT
- * FT_LOAD_NO_RECURSE
- * FT_LOAD_PEDANTIC
- *
- * FT_LOAD_TARGET_NORMAL
- * FT_LOAD_TARGET_LIGHT
- * FT_LOAD_TARGET_MONO
- * FT_LOAD_TARGET_LCD
- * FT_LOAD_TARGET_LCD_V
+ */
+
+
+ /**************************************************************************
+ *
+ * @section:
+ * glyph_retrieval
+ *
+ * @title:
+ * Glyph Retrieval
+ *
+ * @abstract:
+ * Functions to manage glyphs.
+ *
+ * @description:
+ * The functions and structures collected in this section operate on
+ * single glyphs, of which @FT_Load_Glyph is most important.
*
+ * @order:
+ * FT_GlyphSlot
+ * FT_GlyphSlotRec
+ * FT_Glyph_Metrics
+ *
+ * FT_Load_Glyph
+ * FT_LOAD_XXX
* FT_LOAD_TARGET_MODE
+ * FT_LOAD_TARGET_XXX
*
* FT_Render_Glyph
* FT_Render_Mode
@@ -254,34 +275,121 @@ FT_BEGIN_HEADER
* FT_Kerning_Mode
* FT_Get_Track_Kerning
*
+ */
+
+
+ /**************************************************************************
+ *
+ * @section:
+ * character_mapping
+ *
+ * @title:
+ * Character Mapping
+ *
+ * @abstract:
+ * Functions to manage character-to-glyph maps.
+ *
+ * @description:
+ * This section holds functions and structures that are related to
+ * mapping character input codes to glyph indices.
+ *
+ * Note that for many scripts the simplistic approach used by FreeType
+ * of mapping a single character to a single glyph is not valid or
+ * possible! In general, a higher-level library like HarfBuzz or ICU
+ * should be used for handling text strings.
+ *
+ * @order:
+ * FT_CharMap
* FT_CharMapRec
+ * FT_Encoding
+ * FT_ENC_TAG
+ *
* FT_Select_Charmap
* FT_Set_Charmap
* FT_Get_Charmap_Index
*
+ * FT_Get_Char_Index
+ * FT_Get_First_Char
+ * FT_Get_Next_Char
+ * FT_Load_Char
+ *
+ */
+
+
+ /**************************************************************************
+ *
+ * @section:
+ * information_retrieval
+ *
+ * @title:
+ * Information Retrieval
+ *
+ * @abstract:
+ * Functions to retrieve font and glyph information.
+ *
+ * @description:
+ * Functions to retrieve font and glyph information. Only some very
+ * basic data is covered; see also the chapter on the format-specific
+ * API for more.
+ *
+ *
+ * @order:
* FT_Get_Name_Index
* FT_Get_Glyph_Name
* FT_Get_Postscript_Name
* FT_Get_FSType_Flags
+ * FT_FSTYPE_XXX
* FT_Get_SubGlyph_Info
+ * FT_SUBGLYPH_FLAG_XXX
+ *
+ */
+
+
+ /**************************************************************************
+ *
+ * @section:
+ * other_api_data
+ *
+ * @title:
+ * Other API Data
+ *
+ * @abstract:
+ * Other structures, enumerations, and macros.
*
+ * @description:
+ * Other structures, enumerations, and macros. Deprecated functions are
+ * also listed here.
+ *
+ * @order:
* FT_Face_Internal
* FT_Size_Internal
* FT_Slot_Internal
*
- * FT_FACE_FLAG_XXX
- * FT_STYLE_FLAG_XXX
- * FT_OPEN_XXX
- * FT_LOAD_XXX
- * FT_LOAD_TARGET_XXX
- * FT_SUBGLYPH_FLAG_XXX
- * FT_FSTYPE_XXX
+ * FT_SubGlyph
*
* FT_HAS_FAST_GLYPHS
+ * FT_Face_CheckTrueTypePatents
+ * FT_Face_SetUnpatentedHinting
*
*/
+ /*************************************************************************/
+ /*************************************************************************/
+ /* */
+ /* B A S I C T Y P E S */
+ /* */
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /**************************************************************************
+ *
+ * @section:
+ * glyph_retrieval
+ *
+ */
+
/**************************************************************************
*
* @struct:
@@ -351,6 +459,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * sizing_and_scaling
+ *
+ */
+
+ /**************************************************************************
+ *
* @struct:
* FT_Bitmap_Size
*
@@ -411,6 +526,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * library_setup
+ *
+ */
+
+ /**************************************************************************
+ *
* @type:
* FT_Library
*
@@ -483,7 +605,7 @@ FT_BEGIN_HEADER
/**************************************************************************
*
* @section:
- * base_interface
+ * face_creation
*
*/
@@ -521,6 +643,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * sizing_and_scaling
+ *
+ */
+
+ /**************************************************************************
+ *
* @type:
* FT_Size
*
@@ -553,6 +682,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * glyph_retrieval
+ *
+ */
+
+ /**************************************************************************
+ *
* @type:
* FT_GlyphSlot
*
@@ -572,6 +708,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * character_mapping
+ *
+ */
+
+ /**************************************************************************
+ *
* @type:
* FT_CharMap
*
@@ -879,6 +1022,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * other_api_data
+ *
+ */
+
+ /**************************************************************************
+ *
* @type:
* FT_Face_Internal
*
@@ -894,6 +1044,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * face_creation
+ *
+ */
+
+ /**************************************************************************
+ *
* @struct:
* FT_FaceRec
*
@@ -918,7 +1075,7 @@ FT_BEGIN_HEADER
* If we have the third named instance of face~4, say, `face_index` is
* set to 0x00030004.
*
- * Bit 31 is always zero (this is, `face_index` is always a positive
+ * Bit 31 is always zero (that is, `face_index` is always a positive
* value).
*
* [Since 2.9] Changing the design coordinates with
@@ -936,7 +1093,7 @@ FT_BEGIN_HEADER
*
* [Since 2.6.1] Bits 16-30 hold the number of named instances
* available for the current face if we have a GX or OpenType variation
- * (sub)font. Bit 31 is always zero (this is, `style_flags` is always
+ * (sub)font. Bit 31 is always zero (that is, `style_flags` is always
* a positive value). Note that a variation font has always at least
* one named instance, namely the default instance.
*
@@ -1002,7 +1159,7 @@ FT_BEGIN_HEADER
* Note that the bounding box might be off by (at least) one pixel for
* hinted fonts. See @FT_Size_Metrics for further discussion.
*
- * Note that the bounding box does not vary in OpenType variable fonts
+ * Note that the bounding box does not vary in OpenType variation fonts
* and should only be used in relation to the default instance.
*
* units_per_EM ::
@@ -1090,9 +1247,9 @@ FT_BEGIN_HEADER
FT_Generic generic;
- /*# The following member variables (down to `underline_thickness`) */
- /*# are only relevant to scalable outlines; cf. @FT_Bitmap_Size */
- /*# for bitmap fonts. */
+ /* The following member variables (down to `underline_thickness`) */
+ /* are only relevant to scalable outlines; cf. @FT_Bitmap_Size */
+ /* for bitmap fonts. */
FT_BBox bbox;
FT_UShort units_per_EM;
@@ -1110,7 +1267,7 @@ FT_BEGIN_HEADER
FT_Size size;
FT_CharMap charmap;
- /*@private begin */
+ /* private fields, internal to FreeType */
FT_Driver driver;
FT_Memory memory;
@@ -1123,8 +1280,6 @@ FT_BEGIN_HEADER
FT_Face_Internal internal;
- /*@private end */
-
} FT_FaceRec;
@@ -1207,13 +1362,13 @@ FT_BEGIN_HEADER
* successfully; in all other cases you get an
* `FT_Err_Invalid_Argument` error.
*
- * Note that CID-keyed fonts that are in an SFNT wrapper (this is, all
+ * Note that CID-keyed fonts that are in an SFNT wrapper (that is, all
* OpenType/CFF fonts) don't have this flag set since the glyphs are
* accessed in the normal way (using contiguous indices); the
* 'CID-ness' isn't visible to the application.
*
* FT_FACE_FLAG_TRICKY ::
- * The face is 'tricky', this is, it always needs the font format's
+ * The face is 'tricky', that is, it always needs the font format's
* native hinting engine to get a reasonable result. A typical example
* is the old Chinese font `mingli.ttf` (but not `mingliu.ttc`) that
* uses TrueType bytecode instructions to move and scale all of its
@@ -1235,8 +1390,8 @@ FT_BEGIN_HEADER
* FT_FACE_FLAG_VARIATION ::
* [Since 2.9] Set if the current face (or named instance) has been
* altered with @FT_Set_MM_Design_Coordinates,
- * @FT_Set_Var_Design_Coordinates, or @FT_Set_Var_Blend_Coordinates.
- * This flag is unset by a call to @FT_Set_Named_Instance.
+ * @FT_Set_Var_Design_Coordinates, @FT_Set_Var_Blend_Coordinates, or
+ * @FT_Set_MM_WeightVector to select a non-default instance.
*
* FT_FACE_FLAG_SVG ::
* [Since 2.12] The face has an 'SVG~' OpenType table.
@@ -1274,6 +1429,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * font_testing_macros
+ *
+ */
+
+ /**************************************************************************
+ *
* @macro:
* FT_HAS_HORIZONTAL
*
@@ -1383,6 +1545,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * other_api_data
+ *
+ */
+
+ /**************************************************************************
+ *
* @macro:
* FT_HAS_FAST_GLYPHS
*
@@ -1395,6 +1564,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * font_testing_macros
+ *
+ */
+
+ /**************************************************************************
+ *
* @macro:
* FT_HAS_GLYPH_NAMES
*
@@ -1451,8 +1627,8 @@ FT_BEGIN_HEADER
*
* @description:
* A macro that returns true whenever a face object has been altered by
- * @FT_Set_MM_Design_Coordinates, @FT_Set_Var_Design_Coordinates, or
- * @FT_Set_Var_Blend_Coordinates.
+ * @FT_Set_MM_Design_Coordinates, @FT_Set_Var_Design_Coordinates,
+ * @FT_Set_Var_Blend_Coordinates, or @FT_Set_MM_WeightVector.
*
* @since:
* 2.9
@@ -1630,6 +1806,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * face_creation
+ *
+ */
+
+ /**************************************************************************
+ *
* @enum:
* FT_STYLE_FLAG_XXX
*
@@ -1656,6 +1839,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * other_api_data
+ *
+ */
+
+ /**************************************************************************
+ *
* @type:
* FT_Size_Internal
*
@@ -1668,6 +1858,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * sizing_and_scaling
+ *
+ */
+
+ /**************************************************************************
+ *
* @struct:
* FT_Size_Metrics
*
@@ -1819,6 +2016,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * other_api_data
+ *
+ */
+
+ /**************************************************************************
+ *
* @struct:
* FT_SubGlyph
*
@@ -1850,6 +2054,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * glyph_retrieval
+ *
+ */
+
+ /**************************************************************************
+ *
* @struct:
* FT_GlyphSlotRec
*
@@ -2094,6 +2305,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * library_setup
+ *
+ */
+
+ /**************************************************************************
+ *
* @function:
* FT_Init_FreeType
*
@@ -2151,6 +2369,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * face_creation
+ *
+ */
+
+ /**************************************************************************
+ *
* @enum:
* FT_OPEN_XXX
*
@@ -2451,7 +2676,7 @@ FT_BEGIN_HEADER
* Each new face object created with this function also owns a default
* @FT_Size object, accessible as `face->size`.
*
- * One @FT_Library instance can have multiple face objects, this is,
+ * One @FT_Library instance can have multiple face objects, that is,
* @FT_Open_Face and its siblings can be called multiple times using the
* same `library` argument.
*
@@ -2652,6 +2877,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * sizing_and_scaling
+ *
+ */
+
+ /**************************************************************************
+ *
* @function:
* FT_Select_Size
*
@@ -2679,7 +2911,7 @@ FT_BEGIN_HEADER
* silently uses outlines if there is no bitmap for a given glyph index.
*
* For GX and OpenType variation fonts, a bitmap strike makes sense only
- * if the default instance is active (this is, no glyph variation takes
+ * if the default instance is active (that is, no glyph variation takes
* place); otherwise, FreeType simply ignores bitmap strikes. The same
* is true for all named instances that are different from the default
* instance.
@@ -2944,6 +3176,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * glyph_retrieval
+ *
+ */
+
+ /**************************************************************************
+ *
* @function:
* FT_Load_Glyph
*
@@ -2976,7 +3215,7 @@ FT_BEGIN_HEADER
* glyph may be transformed. See @FT_Set_Transform for the details.
*
* For subsetted CID-keyed fonts, `FT_Err_Invalid_Argument` is returned
- * for invalid CID values (this is, for CID values that don't have a
+ * for invalid CID values (that is, for CID values that don't have a
* corresponding glyph in the font). See the discussion of the
* @FT_FACE_FLAG_CID_KEYED flag for more details.
*
@@ -2992,6 +3231,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * character_mapping
+ *
+ */
+
+ /**************************************************************************
+ *
* @function:
* FT_Load_Char
*
@@ -3035,6 +3281,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * glyph_retrieval
+ *
+ */
+
+ /**************************************************************************
+ *
* @enum:
* FT_LOAD_XXX
*
@@ -3172,10 +3425,11 @@ FT_BEGIN_HEADER
*
* [Since 2.12] If the glyph index maps to an entry in the face's
* 'SVG~' table, load the associated SVG document from this table and
- * set the `format` field of @FT_GlyphSlotRec to @FT_GLYPH_FORMAT_SVG.
- * Note that FreeType itself can't render SVG documents; however, the
- * library provides hooks to seamlessly integrate an external renderer.
- * See sections @ot_svg_driver and @svg_fonts for more.
+ * set the `format` field of @FT_GlyphSlotRec to @FT_GLYPH_FORMAT_SVG
+ * ([since 2.13.1] provided @FT_LOAD_NO_SVG is not set). Note that
+ * FreeType itself can't render SVG documents; however, the library
+ * provides hooks to seamlessly integrate an external renderer. See
+ * sections @ot_svg_driver and @svg_fonts for more.
*
* [Since 2.10, experimental] If the glyph index maps to an entry in
* the face's 'COLR' table with a 'CPAL' palette table (as defined in
@@ -3189,6 +3443,9 @@ FT_BEGIN_HEADER
* @FT_Palette_Select instead of setting @FT_LOAD_COLOR for rendering
* so that the client application can handle blending by itself.
*
+ * FT_LOAD_NO_SVG ::
+ * [Since 2.13.1] Ignore SVG glyph data when loading.
+ *
* FT_LOAD_COMPUTE_METRICS ::
* [Since 2.6.1] Compute glyph metrics from the glyph data, without the
* use of bundled metrics tables (for example, the 'hdmx' table in
@@ -3254,6 +3511,7 @@ FT_BEGIN_HEADER
#define FT_LOAD_COLOR ( 1L << 20 )
#define FT_LOAD_COMPUTE_METRICS ( 1L << 21 )
#define FT_LOAD_BITMAP_METRICS_ONLY ( 1L << 22 )
+#define FT_LOAD_NO_SVG ( 1L << 24 )
/* */
@@ -3374,6 +3632,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * sizing_and_scaling
+ *
+ */
+
+ /**************************************************************************
+ *
* @function:
* FT_Set_Transform
*
@@ -3449,6 +3714,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * glyph_retrieval
+ *
+ */
+
+ /**************************************************************************
+ *
* @enum:
* FT_Render_Mode
*
@@ -3843,6 +4115,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * character_mapping
+ *
+ */
+
+ /**************************************************************************
+ *
* @function:
* FT_Select_Charmap
*
@@ -4059,6 +4338,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * face_creation
+ *
+ */
+
+ /**************************************************************************
+ *
* @function:
* FT_Face_Properties
*
@@ -4157,6 +4443,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * information_retrieval
+ *
+ */
+
+ /**************************************************************************
+ *
* @function:
* FT_Get_Name_Index
*
@@ -4266,9 +4559,10 @@ FT_BEGIN_HEADER
*
* [Since 2.9] Special PostScript names for named instances are only
* returned if the named instance is set with @FT_Set_Named_Instance (and
- * the font has corresponding entries in its 'fvar' table). If
- * @FT_IS_VARIATION returns true, the algorithmically derived PostScript
- * name is provided, not looking up special entries for named instances.
+ * the font has corresponding entries in its 'fvar' table or is the
+ * default named instance). If @FT_IS_VARIATION returns true, the
+ * algorithmically derived PostScript name is provided, not looking up
+ * special entries for named instances.
*/
FT_EXPORT( const char* )
FT_Get_Postscript_Name( FT_Face face );
@@ -4900,32 +5194,10 @@ FT_BEGIN_HEADER
/**************************************************************************
*
* @section:
- * version
- *
- * @title:
- * FreeType Version
- *
- * @abstract:
- * Functions and macros related to FreeType versions.
- *
- * @description:
- * Note that those functions and macros are of limited use because even a
- * new release of FreeType with only documentation changes increases the
- * version number.
- *
- * @order:
- * FT_Library_Version
- *
- * FREETYPE_MAJOR
- * FREETYPE_MINOR
- * FREETYPE_PATCH
- *
- * FT_Face_CheckTrueTypePatents
- * FT_Face_SetUnpatentedHinting
+ * library_setup
*
*/
-
/**************************************************************************
*
* @enum:
@@ -4950,7 +5222,7 @@ FT_BEGIN_HEADER
*/
#define FREETYPE_MAJOR 2
#define FREETYPE_MINOR 13
-#define FREETYPE_PATCH 0
+#define FREETYPE_PATCH 2
/**************************************************************************
@@ -4994,6 +5266,13 @@ FT_BEGIN_HEADER
/**************************************************************************
*
+ * @section:
+ * other_api_data
+ *
+ */
+
+ /**************************************************************************
+ *
* @function:
* FT_Face_CheckTrueTypePatents
*
diff --git a/src/3rdparty/freetype/include/freetype/ftcache.h b/src/3rdparty/freetype/include/freetype/ftcache.h
index c76869545a..a2072e26b8 100644
--- a/src/3rdparty/freetype/include/freetype/ftcache.h
+++ b/src/3rdparty/freetype/include/freetype/ftcache.h
@@ -43,61 +43,61 @@ FT_BEGIN_HEADER
* objects, as well as caching information like character maps and glyph
* images while limiting their maximum memory usage.
*
- * Note that all types and functions begin with the `FTC_` prefix.
- *
- * The cache is highly portable and thus doesn't know anything about the
- * fonts installed on your system, or how to access them. This implies
- * the following scheme:
- *
- * First, available or installed font faces are uniquely identified by
- * @FTC_FaceID values, provided to the cache by the client. Note that
- * the cache only stores and compares these values, and doesn't try to
- * interpret them in any way.
- *
- * Second, the cache calls, only when needed, a client-provided function
- * to convert an @FTC_FaceID into a new @FT_Face object. The latter is
- * then completely managed by the cache, including its termination
- * through @FT_Done_Face. To monitor termination of face objects, the
- * finalizer callback in the `generic` field of the @FT_Face object can
- * be used, which might also be used to store the @FTC_FaceID of the
- * face.
- *
- * Clients are free to map face IDs to anything else. The most simple
- * usage is to associate them to a (pathname,face_index) pair that is
- * used to call @FT_New_Face. However, more complex schemes are also
- * possible.
+ * Note that all types and functions begin with the `FTC_` prefix rather
+ * than the usual `FT_` prefix in the rest of FreeType.
+ *
+ * The cache is highly portable and, thus, doesn't know anything about
+ * the fonts installed on your system, or how to access them. Therefore,
+ * it requires the following.
+ *
+ * * @FTC_FaceID, an arbitrary non-zero value that uniquely identifies
+ * available or installed font faces, has to be provided to the
+ * cache by the client. Note that the cache only stores and compares
+ * these values and doesn't try to interpret them in any way, but they
+ * have to be persistent on the client side.
+ *
+ * * @FTC_Face_Requester, a method to convert an @FTC_FaceID into a new
+ * @FT_Face object when necessary, has to be provided to the cache by
+ * the client. The @FT_Face object is completely managed by the cache,
+ * including its termination through @FT_Done_Face. To monitor
+ * termination of face objects, the finalizer callback in the `generic`
+ * field of the @FT_Face object can be used, which might also be used
+ * to store the @FTC_FaceID of the face.
+ *
+ * Clients are free to map face IDs to anything useful. The most simple
+ * usage is, for example, to associate them to a `{pathname,face_index}`
+ * pair that is then used by @FTC_Face_Requester to call @FT_New_Face.
+ * However, more complex schemes are also possible.
*
* Note that for the cache to work correctly, the face ID values must be
* **persistent**, which means that the contents they point to should not
* change at runtime, or that their value should not become invalid.
- *
* If this is unavoidable (e.g., when a font is uninstalled at runtime),
- * you should call @FTC_Manager_RemoveFaceID as soon as possible, to let
+ * you should call @FTC_Manager_RemoveFaceID as soon as possible to let
* the cache get rid of any references to the old @FTC_FaceID it may keep
* internally. Failure to do so will lead to incorrect behaviour or even
- * crashes.
+ * crashes in @FTC_Face_Requester.
*
* To use the cache, start with calling @FTC_Manager_New to create a new
* @FTC_Manager object, which models a single cache instance. You can
* then look up @FT_Face and @FT_Size objects with
- * @FTC_Manager_LookupFace and @FTC_Manager_LookupSize, respectively.
- *
- * If you want to use the charmap caching, call @FTC_CMapCache_New, then
- * later use @FTC_CMapCache_Lookup to perform the equivalent of
- * @FT_Get_Char_Index, only much faster.
- *
- * If you want to use the @FT_Glyph caching, call @FTC_ImageCache_New,
- * then later use @FTC_ImageCache_Lookup to retrieve the corresponding
- * @FT_Glyph objects from the cache.
- *
- * If you need lots of small bitmaps, it is much more memory efficient to
- * call @FTC_SBitCache_New followed by @FTC_SBitCache_Lookup. This
- * returns @FTC_SBitRec structures, which are used to store small bitmaps
- * directly. (A small bitmap is one whose metrics and dimensions all fit
- * into 8-bit integers).
- *
- * We hope to also provide a kerning cache in the near future.
- *
+ * @FTC_Manager_LookupFace and @FTC_Manager_LookupSize, respectively, and
+ * use them in any FreeType work stream. You can also cache other
+ * FreeType objects as follows.
+ *
+ * * If you want to use the charmap caching, call @FTC_CMapCache_New,
+ * then later use @FTC_CMapCache_Lookup to perform the equivalent of
+ * @FT_Get_Char_Index, only much faster.
+ *
+ * * If you want to use the @FT_Glyph caching, call @FTC_ImageCache_New,
+ * then later use @FTC_ImageCache_Lookup to retrieve the corresponding
+ * @FT_Glyph objects from the cache.
+ *
+ * * If you need lots of small bitmaps, it is much more memory-efficient
+ * to call @FTC_SBitCache_New followed by @FTC_SBitCache_Lookup. This
+ * returns @FTC_SBitRec structures, which are used to store small
+ * bitmaps directly. (A small bitmap is one whose metrics and
+ * dimensions all fit into 8-bit integers).
*
* @order:
* FTC_Manager
diff --git a/src/3rdparty/freetype/include/freetype/ftchapters.h b/src/3rdparty/freetype/include/freetype/ftchapters.h
index 6a9733ad7c..7566fbd10f 100644
--- a/src/3rdparty/freetype/include/freetype/ftchapters.h
+++ b/src/3rdparty/freetype/include/freetype/ftchapters.h
@@ -31,9 +31,28 @@
* Core API
*
* @sections:
- * version
* basic_types
- * base_interface
+ * library_setup
+ * face_creation
+ * font_testing_macros
+ * sizing_and_scaling
+ * glyph_retrieval
+ * character_mapping
+ * information_retrieval
+ * other_api_data
+ *
+ */
+
+
+ /**************************************************************************
+ *
+ * @chapter:
+ * extended_api
+ *
+ * @title:
+ * Extended API
+ *
+ * @sections:
* glyph_variants
* color_management
* layer_management
diff --git a/src/3rdparty/freetype/include/freetype/ftdriver.h b/src/3rdparty/freetype/include/freetype/ftdriver.h
index f90946fd17..7af7465bc7 100644
--- a/src/3rdparty/freetype/include/freetype/ftdriver.h
+++ b/src/3rdparty/freetype/include/freetype/ftdriver.h
@@ -134,7 +134,7 @@ FT_BEGIN_HEADER
* each being rounded to the nearest pixel edge, taking care of overshoot
* suppression at small sizes, stem darkening, and scaling.
*
- * Hstems (this is, hint values defined in the font to help align
+ * Hstems (that is, hint values defined in the font to help align
* horizontal features) that fall within a blue zone are said to be
* 'captured' and are aligned to that zone. Uncaptured stems are moved
* in one of four ways, top edge up or down, bottom edge up or down.
@@ -446,7 +446,7 @@ FT_BEGIN_HEADER
* at smaller sizes.
*
* For the auto-hinter, stem-darkening is experimental currently and thus
- * switched off by default (this is, `no-stem-darkening` is set to TRUE
+ * switched off by default (that is, `no-stem-darkening` is set to TRUE
* by default). Total consistency with the CFF driver is not achieved
* right now because the emboldening method differs and glyphs must be
* scaled down on the Y-axis to keep outline points inside their
@@ -651,11 +651,8 @@ FT_BEGIN_HEADER
* Windows~98; only grayscale and B/W rasterizing is supported.
*
* TT_INTERPRETER_VERSION_38 ::
- * Version~38 corresponds to MS rasterizer v.1.9; it is roughly
- * equivalent to the hinting provided by DirectWrite ClearType (as can
- * be found, for example, in the Internet Explorer~9 running on
- * Windows~7). It is used in FreeType to select the 'Infinality'
- * subpixel hinting code. The code may be removed in a future version.
+ * Version~38 is the same Version~40. The original 'Infinality' code is
+ * no longer available.
*
* TT_INTERPRETER_VERSION_40 ::
* Version~40 corresponds to MS rasterizer v.2.1; it is roughly
diff --git a/src/3rdparty/freetype/include/freetype/ftimage.h b/src/3rdparty/freetype/include/freetype/ftimage.h
index 2e8e6734cc..6baa812560 100644
--- a/src/3rdparty/freetype/include/freetype/ftimage.h
+++ b/src/3rdparty/freetype/include/freetype/ftimage.h
@@ -19,7 +19,7 @@
/**************************************************************************
*
* Note: A 'raster' is simply a scan-line converter, used to render
- * FT_Outlines into FT_Bitmaps.
+ * `FT_Outline`s into `FT_Bitmap`s.
*
*/
@@ -256,6 +256,12 @@ FT_BEGIN_HEADER
* palette ::
* A typeless pointer to the bitmap palette; this field is intended for
* paletted pixel modes. Not used currently.
+ *
+ * @note:
+ * `width` and `rows` refer to the *physical* size of the bitmap, not the
+ * *logical* one. For example, if @FT_Pixel_Mode is set to
+ * `FT_PIXEL_MODE_LCD`, the logical width is a just a third of the
+ * physical one.
*/
typedef struct FT_Bitmap_
{
@@ -856,7 +862,7 @@ FT_BEGIN_HEADER
* @FT_SpanFunc that takes the y~coordinate of the span as a parameter.
*
* The anti-aliased rasterizer produces coverage values from 0 to 255,
- * this is, from completely transparent to completely opaque.
+ * that is, from completely transparent to completely opaque.
*/
typedef struct FT_Span_
{
diff --git a/src/3rdparty/freetype/include/freetype/ftlogging.h b/src/3rdparty/freetype/include/freetype/ftlogging.h
index 2246dc8365..53b8b89642 100644
--- a/src/3rdparty/freetype/include/freetype/ftlogging.h
+++ b/src/3rdparty/freetype/include/freetype/ftlogging.h
@@ -62,7 +62,7 @@ FT_BEGIN_HEADER
* component.
*
* ```
- * FT_Trace_Set_Level( "any:7 memory:0 );
+ * FT_Trace_Set_Level( "any:7 memory:0" );
* ```
*
* @note:
diff --git a/src/3rdparty/freetype/include/freetype/ftmm.h b/src/3rdparty/freetype/include/freetype/ftmm.h
index e381ef3d30..d145128a9b 100644
--- a/src/3rdparty/freetype/include/freetype/ftmm.h
+++ b/src/3rdparty/freetype/include/freetype/ftmm.h
@@ -153,7 +153,7 @@ FT_BEGIN_HEADER
* @note:
* The fields `minimum`, `def`, and `maximum` are 16.16 fractional values
* for TrueType GX and OpenType variation fonts. For Adobe MM fonts, the
- * values are integers.
+ * values are whole numbers (i.e., the fractional part is zero).
*/
typedef struct FT_Var_Axis_
{
@@ -399,8 +399,8 @@ FT_BEGIN_HEADER
*
* @note:
* The design coordinates are 16.16 fractional values for TrueType GX and
- * OpenType variation fonts. For Adobe MM fonts, the values are
- * integers.
+ * OpenType variation fonts. For Adobe MM fonts, the values are supposed
+ * to be whole numbers (i.e., the fractional part is zero).
*
* [Since 2.8.1] To reset all axes to the default values, call the
* function with `num_coords` set to zero and `coords` set to `NULL`.
@@ -446,8 +446,8 @@ FT_BEGIN_HEADER
*
* @note:
* The design coordinates are 16.16 fractional values for TrueType GX and
- * OpenType variation fonts. For Adobe MM fonts, the values are
- * integers.
+ * OpenType variation fonts. For Adobe MM fonts, the values are whole
+ * numbers (i.e., the fractional part is zero).
*
* @since:
* 2.7.1
@@ -602,10 +602,12 @@ FT_BEGIN_HEADER
*
* @note:
* Adobe Multiple Master fonts limit the number of designs, and thus the
- * length of the weight vector to~16.
+ * length of the weight vector to 16~elements.
*
- * If `len` is zero and `weightvector` is `NULL`, the weight vector array
- * is reset to the default values.
+ * If `len` is larger than zero, this function sets the
+ * @FT_FACE_FLAG_VARIATION bit in @FT_Face's `face_flags` field (i.e.,
+ * @FT_IS_VARIATION will return true). If `len` is zero, this bit flag
+ * is unset and the weight vector array is reset to the default values.
*
* The Adobe documentation also states that the values in the
* WeightVector array must total 1.0 +/-~0.001. In practice this does
@@ -753,6 +755,45 @@ FT_BEGIN_HEADER
FT_Set_Named_Instance( FT_Face face,
FT_UInt instance_index );
+
+ /**************************************************************************
+ *
+ * @function:
+ * FT_Get_Default_Named_Instance
+ *
+ * @description:
+ * Retrieve the index of the default named instance, to be used with
+ * @FT_Set_Named_Instance.
+ *
+ * The default instance of a variation font is that instance for which
+ * the nth axis coordinate is equal to `axis[n].def` (as specified in the
+ * @FT_MM_Var structure), with~n covering all axes.
+ *
+ * FreeType synthesizes a named instance for the default instance if the
+ * font does not contain such an entry.
+ *
+ * @input:
+ * face ::
+ * A handle to the source face.
+ *
+ * @output:
+ * instance_index ::
+ * The index of the default named instance.
+ *
+ * @return:
+ * FreeType error code. 0~means success.
+ *
+ * @note:
+ * For Adobe MM fonts (which don't have named instances) this function
+ * always returns zero for `instance_index`.
+ *
+ * @since:
+ * 2.13.1
+ */
+ FT_EXPORT( FT_Error )
+ FT_Get_Default_Named_Instance( FT_Face face,
+ FT_UInt *instance_index );
+
/* */
diff --git a/src/3rdparty/freetype/include/freetype/ftoutln.h b/src/3rdparty/freetype/include/freetype/ftoutln.h
index 54434b25f6..f9329ca40c 100644
--- a/src/3rdparty/freetype/include/freetype/ftoutln.h
+++ b/src/3rdparty/freetype/include/freetype/ftoutln.h
@@ -118,7 +118,7 @@ FT_BEGIN_HEADER
* attachement.
*
* Similarly, the function returns success for an empty outline also
- * (doing nothing, this is, not calling any emitter); if necessary, you
+ * (doing nothing, that is, not calling any emitter); if necessary, you
* should filter this out, too.
*/
FT_EXPORT( FT_Error )
diff --git a/src/3rdparty/freetype/include/freetype/ftrender.h b/src/3rdparty/freetype/include/freetype/ftrender.h
index a8576dab00..0b6fad32e8 100644
--- a/src/3rdparty/freetype/include/freetype/ftrender.h
+++ b/src/3rdparty/freetype/include/freetype/ftrender.h
@@ -158,7 +158,7 @@ FT_BEGIN_HEADER
FT_Renderer_GetCBoxFunc get_glyph_cbox;
FT_Renderer_SetModeFunc set_mode;
- FT_Raster_Funcs* raster_class;
+ const FT_Raster_Funcs* raster_class;
} FT_Renderer_Class;
diff --git a/src/3rdparty/freetype/include/freetype/ftsynth.h b/src/3rdparty/freetype/include/freetype/ftsynth.h
index 5d19697657..af90967dda 100644
--- a/src/3rdparty/freetype/include/freetype/ftsynth.h
+++ b/src/3rdparty/freetype/include/freetype/ftsynth.h
@@ -68,6 +68,18 @@ FT_BEGIN_HEADER
FT_EXPORT( void )
FT_GlyphSlot_Embolden( FT_GlyphSlot slot );
+ /* Precisely adjust the glyph weight either horizontally or vertically. */
+ /* The `xdelta` and `ydelta` values are fractions of the face Em size */
+ /* (in fixed-point format). Considering that a regular face would have */
+ /* stem widths on the order of 0.1 Em, a delta of 0.05 (0x0CCC) should */
+ /* be very noticeable. To increase or decrease the weight, use positive */
+ /* or negative values, respectively. */
+ FT_EXPORT( void )
+ FT_GlyphSlot_AdjustWeight( FT_GlyphSlot slot,
+ FT_Fixed xdelta,
+ FT_Fixed ydelta );
+
+
/* Slant an outline glyph to the right by about 12 degrees. */
FT_EXPORT( void )
FT_GlyphSlot_Oblique( FT_GlyphSlot slot );
diff --git a/src/3rdparty/freetype/include/freetype/ftsystem.h b/src/3rdparty/freetype/include/freetype/ftsystem.h
index a995b078de..3a08f4912c 100644
--- a/src/3rdparty/freetype/include/freetype/ftsystem.h
+++ b/src/3rdparty/freetype/include/freetype/ftsystem.h
@@ -229,8 +229,7 @@ FT_BEGIN_HEADER
* A handle to the source stream.
*
* offset ::
- * The offset from the start of the stream to seek to if this is a seek
- * operation (see note).
+ * The offset from the start of the stream to seek to.
*
* buffer ::
* The address of the read buffer.
@@ -239,16 +238,9 @@ FT_BEGIN_HEADER
* The number of bytes to read from the stream.
*
* @return:
- * The number of bytes effectively read by the stream.
- *
- * @note:
- * This function performs a seek *or* a read operation depending on the
- * argument values. If `count` is zero, the operation is a seek to
- * `offset` bytes. If `count` is >~0, the operation is a read of `count`
- * bytes from the current position in the stream, and the `offset` value
- * should be ignored.
- *
- * For seek operations, a non-zero return value indicates an error.
+ * If count >~0, return the number of bytes effectively read by the
+ * stream (after seeking to `offset`). If count ==~0, return the status
+ * of the seek operation (non-zero indicates an error).
*
*/
typedef unsigned long
diff --git a/src/3rdparty/freetype/include/freetype/internal/compiler-macros.h b/src/3rdparty/freetype/include/freetype/internal/compiler-macros.h
index 7883317fed..6f67650979 100644
--- a/src/3rdparty/freetype/include/freetype/internal/compiler-macros.h
+++ b/src/3rdparty/freetype/include/freetype/internal/compiler-macros.h
@@ -41,8 +41,11 @@ FT_BEGIN_HEADER
# if ( defined( __STDC_VERSION__ ) && __STDC_VERSION__ > 201710L ) || \
( defined( __cplusplus ) && __cplusplus > 201402L )
# define FALL_THROUGH [[__fallthrough__]]
-# elif ( defined( __GNUC__ ) && __GNUC__ >= 7 ) || \
- ( defined( __clang__ ) && __clang_major__ >= 10 )
+# elif ( defined( __GNUC__ ) && __GNUC__ >= 7 ) || \
+ ( defined( __clang__ ) && \
+ ( defined( __apple_build_version__ ) \
+ ? __apple_build_version__ >= 12000000 \
+ : __clang_major__ >= 10 ) )
# define FALL_THROUGH __attribute__(( __fallthrough__ ))
# else
# define FALL_THROUGH ( (void)0 )
diff --git a/src/3rdparty/freetype/include/freetype/internal/ftcalc.h b/src/3rdparty/freetype/include/freetype/internal/ftcalc.h
index d1baa392bd..d9aea23602 100644
--- a/src/3rdparty/freetype/include/freetype/internal/ftcalc.h
+++ b/src/3rdparty/freetype/include/freetype/internal/ftcalc.h
@@ -332,9 +332,9 @@ FT_BEGIN_HEADER
* Based on geometric considerations we use the following inequality to
* identify a degenerate matrix.
*
- * 50 * abs(xx*yy - xy*yx) < xx^2 + xy^2 + yx^2 + yy^2
+ * 32 * abs(xx*yy - xy*yx) < xx^2 + xy^2 + yx^2 + yy^2
*
- * Value 50 is heuristic.
+ * Value 32 is heuristic.
*/
FT_BASE( FT_Bool )
FT_Matrix_Check( const FT_Matrix* matrix );
diff --git a/src/3rdparty/freetype/include/freetype/internal/ftdrv.h b/src/3rdparty/freetype/include/freetype/internal/ftdrv.h
index f78912ca0c..9001c07ad0 100644
--- a/src/3rdparty/freetype/include/freetype/internal/ftdrv.h
+++ b/src/3rdparty/freetype/include/freetype/internal/ftdrv.h
@@ -157,6 +157,7 @@ FT_BEGIN_HEADER
* A handle to a function used to select a new fixed size. It is used
* only if @FT_FACE_FLAG_FIXED_SIZES is set. Can be set to 0 if the
* scaling done in the base layer suffices.
+ *
* @note:
* Most function pointers, with the exception of `load_glyph`, can be set
* to 0 to indicate a default behaviour.
diff --git a/src/3rdparty/freetype/include/freetype/internal/ftmmtypes.h b/src/3rdparty/freetype/include/freetype/internal/ftmmtypes.h
index b7c66c35de..c4b21d6144 100644
--- a/src/3rdparty/freetype/include/freetype/internal/ftmmtypes.h
+++ b/src/3rdparty/freetype/include/freetype/internal/ftmmtypes.h
@@ -28,13 +28,19 @@ FT_BEGIN_HEADER
typedef struct GX_ItemVarDataRec_
{
- FT_UInt itemCount; /* number of delta sets per item */
- FT_UInt regionIdxCount; /* number of region indices */
- FT_UInt* regionIndices; /* array of `regionCount' indices; */
- /* these index `varRegionList' */
- FT_ItemVarDelta* deltaSet; /* array of `itemCount' deltas */
- /* use `innerIndex' for this array */
-
+ FT_UInt itemCount; /* Number of delta sets per item. */
+ FT_UInt regionIdxCount; /* Number of region indices. */
+ FT_UInt* regionIndices; /* Array of `regionCount` indices; */
+ /* these index `varRegionList`. */
+ FT_Byte* deltaSet; /* Array of `itemCount` deltas; */
+ /* use `innerIndex` for this array. */
+ FT_UShort wordDeltaCount; /* Number of the first 32-bit ints */
+ /* or 16-bit ints of `deltaSet` */
+ /* depending on `longWords`. */
+ FT_Bool longWords; /* If true, `deltaSet` is a 32-bit */
+ /* array followed by a 16-bit */
+ /* array, otherwise a 16-bit array */
+ /* followed by an 8-bit array. */
} GX_ItemVarDataRec, *GX_ItemVarData;
diff --git a/src/3rdparty/freetype/include/freetype/internal/services/svmetric.h b/src/3rdparty/freetype/include/freetype/internal/services/svmetric.h
index e588ea4872..167617ebb3 100644
--- a/src/3rdparty/freetype/include/freetype/internal/services/svmetric.h
+++ b/src/3rdparty/freetype/include/freetype/internal/services/svmetric.h
@@ -77,6 +77,9 @@ FT_BEGIN_HEADER
typedef void
(*FT_Metrics_Adjust_Func)( FT_Face face );
+ typedef FT_Error
+ (*FT_Size_Reset_Func)( FT_Size size );
+
FT_DEFINE_SERVICE( MetricsVariations )
{
@@ -90,6 +93,7 @@ FT_BEGIN_HEADER
FT_VOrg_Adjust_Func vorg_adjust;
FT_Metrics_Adjust_Func metrics_adjust;
+ FT_Size_Reset_Func size_reset;
};
@@ -101,7 +105,8 @@ FT_BEGIN_HEADER
tsb_adjust_, \
bsb_adjust_, \
vorg_adjust_, \
- metrics_adjust_ ) \
+ metrics_adjust_, \
+ size_reset_ ) \
static const FT_Service_MetricsVariationsRec class_ = \
{ \
hadvance_adjust_, \
@@ -111,7 +116,8 @@ FT_BEGIN_HEADER
tsb_adjust_, \
bsb_adjust_, \
vorg_adjust_, \
- metrics_adjust_ \
+ metrics_adjust_, \
+ size_reset_ \
};
/* */
diff --git a/src/3rdparty/freetype/include/freetype/internal/services/svmm.h b/src/3rdparty/freetype/include/freetype/internal/services/svmm.h
index d94204232e..7e76ab8324 100644
--- a/src/3rdparty/freetype/include/freetype/internal/services/svmm.h
+++ b/src/3rdparty/freetype/include/freetype/internal/services/svmm.h
@@ -60,9 +60,9 @@ FT_BEGIN_HEADER
/* use return value -1 to indicate that the new coordinates */
/* are equal to the current ones; no changes are thus needed */
typedef FT_Error
- (*FT_Set_MM_Blend_Func)( FT_Face face,
- FT_UInt num_coords,
- FT_Long* coords );
+ (*FT_Set_MM_Blend_Func)( FT_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords );
typedef FT_Error
(*FT_Get_Var_Design_Func)( FT_Face face,
@@ -70,13 +70,17 @@ FT_BEGIN_HEADER
FT_Fixed* coords );
typedef FT_Error
- (*FT_Set_Instance_Func)( FT_Face face,
- FT_UInt instance_index );
+ (*FT_Set_Named_Instance_Func)( FT_Face face,
+ FT_UInt instance_index );
typedef FT_Error
- (*FT_Get_MM_Blend_Func)( FT_Face face,
- FT_UInt num_coords,
- FT_Long* coords );
+ (*FT_Get_Default_Named_Instance_Func)( FT_Face face,
+ FT_UInt *instance_index );
+
+ typedef FT_Error
+ (*FT_Get_MM_Blend_Func)( FT_Face face,
+ FT_UInt num_coords,
+ FT_Fixed* coords );
typedef FT_Error
(*FT_Get_Var_Blend_Func)( FT_Face face,
@@ -86,7 +90,7 @@ FT_BEGIN_HEADER
FT_MM_Var* *mm_var );
typedef void
- (*FT_Done_Blend_Func)( FT_Face );
+ (*FT_Done_Blend_Func)( FT_Face face );
typedef FT_Error
(*FT_Set_MM_WeightVector_Func)( FT_Face face,
@@ -98,6 +102,9 @@ FT_BEGIN_HEADER
FT_UInt* len,
FT_Fixed* weight_vector );
+ typedef void
+ (*FT_Construct_PS_Name_Func)( FT_Face face );
+
typedef FT_Error
(*FT_Var_Load_Delta_Set_Idx_Map_Func)( FT_Face face,
FT_ULong offset,
@@ -134,11 +141,13 @@ FT_BEGIN_HEADER
FT_Get_MM_Var_Func get_mm_var;
FT_Set_Var_Design_Func set_var_design;
FT_Get_Var_Design_Func get_var_design;
- FT_Set_Instance_Func set_instance;
+ FT_Set_Named_Instance_Func set_named_instance;
+ FT_Get_Default_Named_Instance_Func get_default_named_instance;
FT_Set_MM_WeightVector_Func set_mm_weightvector;
FT_Get_MM_WeightVector_Func get_mm_weightvector;
/* for internal use; only needed for code sharing between modules */
+ FT_Construct_PS_Name_Func construct_ps_name;
FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map;
FT_Var_Load_Item_Var_Store_Func load_item_var_store;
FT_Var_Get_Item_Delta_Func get_item_delta;
@@ -149,43 +158,49 @@ FT_BEGIN_HEADER
};
-#define FT_DEFINE_SERVICE_MULTIMASTERSREC( class_, \
- get_mm_, \
- set_mm_design_, \
- set_mm_blend_, \
- get_mm_blend_, \
- get_mm_var_, \
- set_var_design_, \
- get_var_design_, \
- set_instance_, \
- set_weightvector_, \
- get_weightvector_, \
- load_delta_set_idx_map_, \
- load_item_var_store_, \
- get_item_delta_, \
- done_item_var_store_, \
- done_delta_set_idx_map_, \
- get_var_blend_, \
- done_blend_ ) \
- static const FT_Service_MultiMastersRec class_ = \
- { \
- get_mm_, \
- set_mm_design_, \
- set_mm_blend_, \
- get_mm_blend_, \
- get_mm_var_, \
- set_var_design_, \
- get_var_design_, \
- set_instance_, \
- set_weightvector_, \
- get_weightvector_, \
- load_delta_set_idx_map_, \
- load_item_var_store_, \
- get_item_delta_, \
- done_item_var_store_, \
- done_delta_set_idx_map_, \
- get_var_blend_, \
- done_blend_ \
+#define FT_DEFINE_SERVICE_MULTIMASTERSREC( class_, \
+ get_mm_, \
+ set_mm_design_, \
+ set_mm_blend_, \
+ get_mm_blend_, \
+ get_mm_var_, \
+ set_var_design_, \
+ get_var_design_, \
+ set_named_instance_, \
+ get_default_named_instance_, \
+ set_mm_weightvector_, \
+ get_mm_weightvector_, \
+ \
+ construct_ps_name_, \
+ load_delta_set_idx_map_, \
+ load_item_var_store_, \
+ get_item_delta_, \
+ done_item_var_store_, \
+ done_delta_set_idx_map_, \
+ get_var_blend_, \
+ done_blend_ ) \
+ static const FT_Service_MultiMastersRec class_ = \
+ { \
+ get_mm_, \
+ set_mm_design_, \
+ set_mm_blend_, \
+ get_mm_blend_, \
+ get_mm_var_, \
+ set_var_design_, \
+ get_var_design_, \
+ set_named_instance_, \
+ get_default_named_instance_, \
+ set_mm_weightvector_, \
+ get_mm_weightvector_, \
+ \
+ construct_ps_name_, \
+ load_delta_set_idx_map_, \
+ load_item_var_store_, \
+ get_item_delta_, \
+ done_item_var_store_, \
+ done_delta_set_idx_map_, \
+ get_var_blend_, \
+ done_blend_ \
};
/* */
diff --git a/src/3rdparty/freetype/include/freetype/internal/services/svpscmap.h b/src/3rdparty/freetype/include/freetype/internal/services/svpscmap.h
index fd99d857e4..6e599f3aab 100644
--- a/src/3rdparty/freetype/include/freetype/internal/services/svpscmap.h
+++ b/src/3rdparty/freetype/include/freetype/internal/services/svpscmap.h
@@ -97,7 +97,7 @@ FT_BEGIN_HEADER
(*PS_Unicodes_CharIndexFunc)( PS_Unicodes unicodes,
FT_UInt32 unicode );
- typedef FT_UInt32
+ typedef FT_UInt
(*PS_Unicodes_CharNextFunc)( PS_Unicodes unicodes,
FT_UInt32 *unicode );
diff --git a/src/3rdparty/freetype/include/freetype/internal/t1types.h b/src/3rdparty/freetype/include/freetype/internal/t1types.h
index 5a105c5879..b9c94398fd 100644
--- a/src/3rdparty/freetype/include/freetype/internal/t1types.h
+++ b/src/3rdparty/freetype/include/freetype/internal/t1types.h
@@ -201,30 +201,30 @@ FT_BEGIN_HEADER
typedef struct T1_FaceRec_
{
- FT_FaceRec root;
- T1_FontRec type1;
- const void* psnames;
- const void* psaux;
- const void* afm_data;
- FT_CharMapRec charmaprecs[2];
- FT_CharMap charmaps[2];
+ FT_FaceRec root;
+ T1_FontRec type1;
+ const void* psnames;
+ const void* psaux;
+ const void* afm_data;
+ FT_CharMapRec charmaprecs[2];
+ FT_CharMap charmaps[2];
/* support for Multiple Masters fonts */
- PS_Blend blend;
+ PS_Blend blend;
/* undocumented, optional: indices of subroutines that express */
/* the NormalizeDesignVector and the ConvertDesignVector procedure, */
/* respectively, as Type 2 charstrings; -1 if keywords not present */
- FT_Int ndv_idx;
- FT_Int cdv_idx;
+ FT_Int ndv_idx;
+ FT_Int cdv_idx;
/* undocumented, optional: has the same meaning as len_buildchar */
/* for Type 2 fonts; manipulated by othersubrs 19, 24, and 25 */
- FT_UInt len_buildchar;
- FT_Long* buildchar;
+ FT_UInt len_buildchar;
+ FT_Long* buildchar;
/* since version 2.1 - interface to PostScript hinter */
- const void* pshinter;
+ const void* pshinter;
} T1_FaceRec;
diff --git a/src/3rdparty/freetype/include/freetype/internal/tttypes.h b/src/3rdparty/freetype/include/freetype/internal/tttypes.h
index 3b521924ca..b9788c7831 100644
--- a/src/3rdparty/freetype/include/freetype/internal/tttypes.h
+++ b/src/3rdparty/freetype/include/freetype/internal/tttypes.h
@@ -779,13 +779,15 @@ FT_BEGIN_HEADER
/**************************************************************************
*
* @struct:
- * TT_Post_20Rec
+ * TT_Post_NamesRec
*
* @description:
- * Postscript names sub-table, format 2.0. Stores the PS name of each
- * glyph in the font face.
+ * Postscript names table, either format 2.0 or 2.5.
*
* @fields:
+ * loaded ::
+ * A flag to indicate whether the PS names are loaded.
+ *
* num_glyphs ::
* The number of named glyphs in the table.
*
@@ -798,68 +800,13 @@ FT_BEGIN_HEADER
* glyph_names ::
* The PS names not in Mac Encoding.
*/
- typedef struct TT_Post_20Rec_
+ typedef struct TT_Post_NamesRec_
{
+ FT_Bool loaded;
FT_UShort num_glyphs;
FT_UShort num_names;
FT_UShort* glyph_indices;
- FT_Char** glyph_names;
-
- } TT_Post_20Rec, *TT_Post_20;
-
-
- /**************************************************************************
- *
- * @struct:
- * TT_Post_25Rec
- *
- * @description:
- * Postscript names sub-table, format 2.5. Stores the PS name of each
- * glyph in the font face.
- *
- * @fields:
- * num_glyphs ::
- * The number of glyphs in the table.
- *
- * offsets ::
- * An array of signed offsets in a normal Mac Postscript name encoding.
- */
- typedef struct TT_Post_25_
- {
- FT_UShort num_glyphs;
- FT_Char* offsets;
-
- } TT_Post_25Rec, *TT_Post_25;
-
-
- /**************************************************************************
- *
- * @struct:
- * TT_Post_NamesRec
- *
- * @description:
- * Postscript names table, either format 2.0 or 2.5.
- *
- * @fields:
- * loaded ::
- * A flag to indicate whether the PS names are loaded.
- *
- * format_20 ::
- * The sub-table used for format 2.0.
- *
- * format_25 ::
- * The sub-table used for format 2.5.
- */
- typedef struct TT_Post_NamesRec_
- {
- FT_Bool loaded;
-
- union
- {
- TT_Post_20Rec format_20;
- TT_Post_25Rec format_25;
-
- } names;
+ FT_Byte** glyph_names;
} TT_Post_NamesRec, *TT_Post_Names;
@@ -1253,12 +1200,16 @@ FT_BEGIN_HEADER
* mm ::
* A pointer to the Multiple Masters service.
*
- * var ::
- * A pointer to the Metrics Variations service.
+ * tt_var ::
+ * A pointer to the Metrics Variations service for the "truetype"
+ * driver.
*
- * hdmx ::
- * The face's horizontal device metrics ('hdmx' table). This table is
- * optional in TrueType/OpenType fonts.
+ * face_var ::
+ * A pointer to the Metrics Variations service for this `TT_Face`'s
+ * driver.
+ *
+ * psaux ::
+ * A pointer to the PostScript Auxiliary service.
*
* gasp ::
* The grid-fitting and scaling properties table ('gasp'). This table
@@ -1364,6 +1315,12 @@ FT_BEGIN_HEADER
* var_postscript_prefix_len ::
* The length of the `var_postscript_prefix` string.
*
+ * var_default_named_instance ::
+ * The index of the default named instance.
+ *
+ * non_var_style_name ::
+ * The non-variation style name, used as a backup.
+ *
* horz_metrics_size ::
* The size of the 'hmtx' table.
*
@@ -1410,14 +1367,6 @@ FT_BEGIN_HEADER
* A mapping between the strike indices exposed by the API and the
* indices used in the font's sbit table.
*
- * cpal ::
- * A pointer to data related to the 'CPAL' table. `NULL` if the table
- * is not available.
- *
- * colr ::
- * A pointer to data related to the 'COLR' table. `NULL` if the table
- * is not available.
- *
* kern_table ::
* A pointer to the 'kern' table.
*
@@ -1445,19 +1394,23 @@ FT_BEGIN_HEADER
* vert_metrics_offset ::
* The file offset of the 'vmtx' table.
*
- * sph_found_func_flags ::
- * Flags identifying special bytecode functions (used by the v38
- * implementation of the bytecode interpreter).
- *
- * sph_compatibility_mode ::
- * This flag is set if we are in ClearType backward compatibility mode
- * (used by the v38 implementation of the bytecode interpreter).
- *
* ebdt_start ::
* The file offset of the sbit data table (CBDT, bdat, etc.).
*
* ebdt_size ::
* The size of the sbit data table.
+ *
+ * cpal ::
+ * A pointer to data related to the 'CPAL' table. `NULL` if the table
+ * is not available.
+ *
+ * colr ::
+ * A pointer to data related to the 'COLR' table. `NULL` if the table
+ * is not available.
+ *
+ * svg ::
+ * A pointer to data related to the 'SVG' table. `NULL` if the table
+ * is not available.
*/
typedef struct TT_FaceRec_
{
@@ -1508,8 +1461,14 @@ FT_BEGIN_HEADER
void* mm;
/* a typeless pointer to the FT_Service_MetricsVariationsRec table */
- /* used to handle the HVAR, VVAR, and MVAR OpenType tables */
- void* var;
+ /* used to handle the HVAR, VVAR, and MVAR OpenType tables by the */
+ /* "truetype" driver */
+ void* tt_var;
+
+ /* a typeless pointer to the FT_Service_MetricsVariationsRec table */
+ /* used to handle the HVAR, VVAR, and MVAR OpenType tables by this */
+ /* TT_Face's driver */
+ void* face_var; /* since 2.13.1 */
#endif
/* a typeless pointer to the PostScript Aux service */
@@ -1591,6 +1550,9 @@ FT_BEGIN_HEADER
const char* var_postscript_prefix; /* since 2.7.2 */
FT_UInt var_postscript_prefix_len; /* since 2.7.2 */
+ FT_UInt var_default_named_instance; /* since 2.13.1 */
+
+ const char* non_var_style_name; /* since 2.13.1 */
#endif
/* since version 2.2 */
@@ -1627,13 +1589,6 @@ FT_BEGIN_HEADER
FT_ULong horz_metrics_offset;
FT_ULong vert_metrics_offset;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- /* since 2.4.12 */
- FT_ULong sph_found_func_flags; /* special functions found */
- /* for this face */
- FT_Bool sph_compatibility_mode;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
/* since 2.7 */
FT_ULong ebdt_start; /* either `CBDT', `EBDT', or `bdat' */
diff --git a/src/3rdparty/freetype/qt_attribution.json b/src/3rdparty/freetype/qt_attribution.json
index abfc43aaf1..5ffd9450d5 100644
--- a/src/3rdparty/freetype/qt_attribution.json
+++ b/src/3rdparty/freetype/qt_attribution.json
@@ -4,44 +4,46 @@
"Name": "Freetype 2",
"QDocModule": "qtgui",
"QtUsage": "Optionally used in Qt GUI and platform plugins. Configure with -no-freetype, or -system-freetype to avoid.",
+ "SecurityCritical": true,
"Description": "FreeType is a freely available software library to render fonts.",
"Homepage": "http://www.freetype.org",
- "Version": "2.13.0",
+ "Version": "2.13.2",
+ "DownloadLocation": "https://download.savannah.gnu.org/releases/freetype/freetype-2.13.2.tar.gz",
"License": "Freetype Project License or GNU General Public License v2.0 only",
- "LicenseId": "FTL OR GPL-2.0",
+ "LicenseId": "FTL OR GPL-2.0-only",
"LicenseFile": "LICENSE.txt",
- "Copyright": "Copyright (c) 2007-2014 Adobe Systems Incorporated
-Copyright (c) 2004-2023 Albert Chin-A-Young
-Copyright (c) 2018-2023 Armin Hasitzka, David Turner, Robert Wilhelm, and Werner Lemberg
-Copyright (c) 2000 Computing Research Labs, New Mexico State University
-Copyright (c) 1996-2023 David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg
-Copyright (c) 2004-2023 David Turner, Robert Wilhelm, Werner Lemberg and George Williams
-Copyright (c) 2022-2023 David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti
-Copyright (c) 2008-2023 David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya
-Copyright (c) 2003-2023 David Turner, Robert Wilhelm, and Werner Lemberg
-Copyright (c) 2005-2023 David Turner
-Copyright (c) 2007-2023 Derek Clegg and Michael Toftdal
-Copyright (c) 2007 Dmitry Timoshkov for Codeweavers
-Copyright (c) 2001-2015 Francesco Zappa Nardelli
-Copyright (c) 2005, 2007, 2008, 2013 George Williams
-Copyright (c) 2013-2023 Google, Inc. Google Author(s) Behdad Esfahbod and Stuart Gill
-Copyright (c) 2013-2022 Google, Inc.
-Copyright (c) 2003 Huw D M Davies for Codeweavers
-Copyright (c) 2010-2023 Joel Klinghed
-Copyright (c) 1996-2023 Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg
-Copyright (c) 2003-2023 Masatake YAMATO and Redhat K.K.
-Copyright (c) 2004-2023 Masatake YAMATO, Redhat K.K, David Turner, Robert Wilhelm, and Werner Lemberg
-Copyright (c) 2019-2023 Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg
-Copyright (c) 2009-2023 Oran Agra and Mickey Gabel
-Copyright (c) 2007-2023 Rahul Bhalerao <rahul.bhalerao@redhat.com>
-Copyright (c) 2002-2023 Roberto Alameda
-Copyright (c) 2015-2022 Werner Lemberg
-Copyright (c) 2004-2023 suzuki toshiya, Masatake YAMATO, Red Hat K.K., David Turner, Robert Wilhelm, and Werner Lemberg
-Copyright (c) 2019 nyorain
-Copyright (c) 2022-2023 David Turner, Robert Wilhelm, Werner Lemberg, George Williams, and Dominik Röttsches
-Copyright (C) 2009, 2023 Red Hat, Inc."
+ "Copyright": ["Copyright (c) 2007-2014 Adobe Systems Incorporated",
+ "Copyright (c) 2004-2023 Albert Chin-A-Young",
+ "Copyright (c) 2018-2023 Armin Hasitzka, David Turner, Robert Wilhelm, and Werner Lemberg",
+ "Copyright (c) 2000 Computing Research Labs, New Mexico State University",
+ "Copyright (c) 1996-2023 David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg",
+ "Copyright (c) 2004-2023 David Turner, Robert Wilhelm, Werner Lemberg and George Williams",
+ "Copyright (c) 2022-2023 David Turner, Robert Wilhelm, Werner Lemberg, and Moazin Khatti",
+ "Copyright (c) 2008-2023 David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya",
+ "Copyright (c) 2003-2023 David Turner, Robert Wilhelm, and Werner Lemberg",
+ "Copyright (c) 2005-2023 David Turner",
+ "Copyright (c) 2007-2023 Derek Clegg and Michael Toftdal",
+ "Copyright (c) 2007 Dmitry Timoshkov for Codeweavers",
+ "Copyright (c) 2001-2015 Francesco Zappa Nardelli",
+ "Copyright (c) 2005, 2007, 2008, 2013 George Williams",
+ "Copyright (c) 2013-2023 Google, Inc. Google Author(s) Behdad Esfahbod and Stuart Gill",
+ "Copyright (c) 2013-2022 Google, Inc.",
+ "Copyright (c) 2003 Huw D M Davies for Codeweavers",
+ "Copyright (c) 2010-2023 Joel Klinghed",
+ "Copyright (c) 1996-2023 Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg",
+ "Copyright (c) 2003-2023 Masatake YAMATO and Redhat K.K.",
+ "Copyright (c) 2004-2023 Masatake YAMATO, Redhat K.K, David Turner, Robert Wilhelm, and Werner Lemberg",
+ "Copyright (c) 2019-2023 Nikhil Ramakrishnan, David Turner, Robert Wilhelm, and Werner Lemberg",
+ "Copyright (c) 2009-2023 Oran Agra and Mickey Gabel",
+ "Copyright (c) 2007-2023 Rahul Bhalerao <rahul.bhalerao@redhat.com>",
+ "Copyright (c) 2002-2023 Roberto Alameda",
+ "Copyright (c) 2015-2022 Werner Lemberg",
+ "Copyright (c) 2004-2023 suzuki toshiya, Masatake YAMATO, Red Hat K.K., David Turner, Robert Wilhelm, and Werner Lemberg",
+ "Copyright (c) 2019 nyorain",
+ "Copyright (c) 2022-2023 David Turner, Robert Wilhelm, Werner Lemberg, George Williams, and Dominik Röttsches",
+ "Copyright (C) 2009, 2023 Red Hat, Inc."]
},
{
"Id": "freetype-zlib",
@@ -69,8 +71,8 @@ Copyright (C) 2009, 2023 Red Hat, Inc."
"License": "MIT License",
"LicenseId": "MIT",
"LicenseFile": "BDF-LICENSE.txt",
- "Copyright": "Copyright (c) 2000 Computing Research Labs, New Mexico State University
-Copyright (c) 2001-2014 Francesco Zappa Nardelli"
+ "Copyright": ["Copyright (c) 2000 Computing Research Labs, New Mexico State University",
+ "Copyright (c) 2001-2014 Francesco Zappa Nardelli"]
},
{
"Id": "freetype-pcf",
@@ -84,8 +86,8 @@ Copyright (c) 2001-2014 Francesco Zappa Nardelli"
"License": "MIT License and MIT Open Group variant",
"LicenseId": "MIT AND MIT-open-group",
"LicenseFile": "PCF-LICENSE.txt",
- "Copyright": "Copyright (c) 2001, 2012 David Turner, Robert Wilhelm, and Werner Lemberg
-Copyright (c) 2000-2014 Francesco Zappa Nardelli
-Copyright (c) 1990, 1994, 1998 The Open Group"
+ "Copyright": ["Copyright (c) 2001, 2012 David Turner, Robert Wilhelm, and Werner Lemberg",
+ "Copyright (c) 2000-2014 Francesco Zappa Nardelli",
+ "Copyright (c) 1990, 1994, 1998 The Open Group"]
}
]
diff --git a/src/3rdparty/freetype/src/autofit/afblue.dat b/src/3rdparty/freetype/src/autofit/afblue.dat
index b7efe8be6c..8299baa259 100644
--- a/src/3rdparty/freetype/src/autofit/afblue.dat
+++ b/src/3rdparty/freetype/src/autofit/afblue.dat
@@ -89,7 +89,7 @@ AF_BLUE_STRING_ENUM AF_BLUE_STRINGS_ARRAY AF_BLUE_STRING_MAX_LEN:
"ت ث ط ظ ك"
// We don't necessarily have access to medial forms via Unicode in case
// Arabic presentational forms are missing. The only character that is
- // guaranteed to have the same vertical position with joining (this is,
+ // guaranteed to have the same vertical position with joining (that is,
// non-isolated) forms is U+0640, ARABIC TATWEEL, which must join both
// round and flat curves.
AF_BLUE_STRING_ARABIC_JOIN
diff --git a/src/3rdparty/freetype/src/autofit/afcjk.c b/src/3rdparty/freetype/src/autofit/afcjk.c
index 5daefff359..f414289adc 100644
--- a/src/3rdparty/freetype/src/autofit/afcjk.c
+++ b/src/3rdparty/freetype/src/autofit/afcjk.c
@@ -417,16 +417,14 @@
{
FT_Int nn;
- FT_Int first = 0;
- FT_Int last = -1;
+ FT_Int pp, first, last;
- for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ )
+ last = -1;
+ for ( nn = 0; nn < outline.n_contours; nn++ )
{
- FT_Int pp;
-
-
- last = outline.contours[nn];
+ first = last + 1;
+ last = outline.contours[nn];
/* Avoid single-point contours since they are never rasterized. */
/* In some fonts, they correspond to mark attachment points */
@@ -569,8 +567,8 @@
af_cjk_metrics_check_digits( AF_CJKMetrics metrics,
FT_Face face )
{
- FT_Bool started = 0, same_width = 1;
- FT_Fixed advance = 0, old_advance = 0;
+ FT_Bool started = 0, same_width = 1;
+ FT_Long advance = 0, old_advance = 0;
/* If HarfBuzz is not available, we need a pointer to a single */
/* unsigned long value. */
@@ -635,10 +633,11 @@
/* Initialize global metrics. */
FT_LOCAL_DEF( FT_Error )
- af_cjk_metrics_init( AF_CJKMetrics metrics,
- FT_Face face )
+ af_cjk_metrics_init( AF_StyleMetrics metrics_, /* AF_CJKMetrics */
+ FT_Face face )
{
- FT_CharMap oldmap = face->charmap;
+ AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
+ FT_CharMap oldmap = face->charmap;
metrics->units_per_em = face->units_per_EM;
@@ -756,9 +755,12 @@
/* Scale global values in both directions. */
FT_LOCAL_DEF( void )
- af_cjk_metrics_scale( AF_CJKMetrics metrics,
- AF_Scaler scaler )
+ af_cjk_metrics_scale( AF_StyleMetrics metrics_, /* AF_CJKMetrics */
+ AF_Scaler scaler )
{
+ AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
+
+
/* we copy the whole structure since the x and y scaling values */
/* are not modified, contrary to e.g. the `latin' auto-hinter */
metrics->root.scaler = *scaler;
@@ -771,11 +773,14 @@
/* Extract standard_width from writing system/script specific */
/* metrics class. */
- FT_LOCAL_DEF( void )
- af_cjk_get_standard_widths( AF_CJKMetrics metrics,
- FT_Pos* stdHW,
- FT_Pos* stdVW )
+ FT_CALLBACK_DEF( void )
+ af_cjk_get_standard_widths( AF_StyleMetrics metrics_, /* AF_CJKMetrics */
+ FT_Pos* stdHW,
+ FT_Pos* stdVW )
{
+ AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
+
+
if ( stdHW )
*stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
@@ -1376,9 +1381,10 @@
/* Initalize hinting engine. */
FT_LOCAL_DEF( FT_Error )
- af_cjk_hints_init( AF_GlyphHints hints,
- AF_CJKMetrics metrics )
+ af_cjk_hints_init( AF_GlyphHints hints,
+ AF_StyleMetrics metrics_ ) /* AF_CJKMetrics */
{
+ AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
FT_Render_Mode mode;
FT_UInt32 scaler_flags, other_flags;
@@ -1628,7 +1634,7 @@
stem_edge->pos = base_edge->pos + fitted_width;
- FT_TRACE5(( " CJKLINK: edge %ld @%d (opos=%.2f) linked to %.2f,"
+ FT_TRACE5(( " CJKLINK: edge %td @%d (opos=%.2f) linked to %.2f,"
" dist was %.2f, now %.2f\n",
stem_edge - hints->axis[dim].edges, stem_edge->fpos,
(double)stem_edge->opos / 64,
@@ -1852,7 +1858,7 @@
continue;
#ifdef FT_DEBUG_LEVEL_TRACE
- FT_TRACE5(( " CJKBLUE: edge %ld @%d (opos=%.2f) snapped to %.2f,"
+ FT_TRACE5(( " CJKBLUE: edge %td @%d (opos=%.2f) snapped to %.2f,"
" was %.2f\n",
edge1 - edges, edge1->fpos, (double)edge1->opos / 64,
(double)blue->fit / 64, (double)edge1->pos / 64 ));
@@ -1916,7 +1922,7 @@
/* this should not happen, but it's better to be safe */
if ( edge2->blue_edge )
{
- FT_TRACE5(( "ASSERTION FAILED for edge %ld\n", edge2-edges ));
+ FT_TRACE5(( "ASSERTION FAILED for edge %td\n", edge2 - edges ));
af_cjk_align_linked_edge( hints, dim, edge2, edge );
edge->flags |= AF_EDGE_DONE;
@@ -2268,11 +2274,13 @@
/* Apply the complete hinting algorithm to a CJK glyph. */
FT_LOCAL_DEF( FT_Error )
- af_cjk_hints_apply( FT_UInt glyph_index,
- AF_GlyphHints hints,
- FT_Outline* outline,
- AF_CJKMetrics metrics )
+ af_cjk_hints_apply( FT_UInt glyph_index,
+ AF_GlyphHints hints,
+ FT_Outline* outline,
+ AF_StyleMetrics metrics_ ) /* AF_CJKMetrics */
{
+ AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
+
FT_Error error;
int dim;
diff --git a/src/3rdparty/freetype/src/autofit/afcjk.h b/src/3rdparty/freetype/src/autofit/afcjk.h
index bd7b81b3e2..f380ef6e03 100644
--- a/src/3rdparty/freetype/src/autofit/afcjk.h
+++ b/src/3rdparty/freetype/src/autofit/afcjk.h
@@ -103,22 +103,22 @@ FT_BEGIN_HEADER
#ifdef AF_CONFIG_OPTION_CJK
FT_LOCAL( FT_Error )
- af_cjk_metrics_init( AF_CJKMetrics metrics,
- FT_Face face );
+ af_cjk_metrics_init( AF_StyleMetrics metrics,
+ FT_Face face );
FT_LOCAL( void )
- af_cjk_metrics_scale( AF_CJKMetrics metrics,
- AF_Scaler scaler );
+ af_cjk_metrics_scale( AF_StyleMetrics metrics,
+ AF_Scaler scaler );
FT_LOCAL( FT_Error )
- af_cjk_hints_init( AF_GlyphHints hints,
- AF_CJKMetrics metrics );
+ af_cjk_hints_init( AF_GlyphHints hints,
+ AF_StyleMetrics metrics );
FT_LOCAL( FT_Error )
- af_cjk_hints_apply( FT_UInt glyph_index,
- AF_GlyphHints hints,
- FT_Outline* outline,
- AF_CJKMetrics metrics );
+ af_cjk_hints_apply( FT_UInt glyph_index,
+ AF_GlyphHints hints,
+ FT_Outline* outline,
+ AF_StyleMetrics metrics );
/* shared; called from afindic.c */
FT_LOCAL( void )
diff --git a/src/3rdparty/freetype/src/autofit/afglobal.c b/src/3rdparty/freetype/src/autofit/afglobal.c
index ede27eb166..b1957570f0 100644
--- a/src/3rdparty/freetype/src/autofit/afglobal.c
+++ b/src/3rdparty/freetype/src/autofit/afglobal.c
@@ -376,8 +376,11 @@
FT_LOCAL_DEF( void )
- af_face_globals_free( AF_FaceGlobals globals )
+ af_face_globals_free( void* globals_ )
{
+ AF_FaceGlobals globals = (AF_FaceGlobals)globals_;
+
+
if ( globals )
{
FT_Memory memory = globals->face->memory;
diff --git a/src/3rdparty/freetype/src/autofit/afglobal.h b/src/3rdparty/freetype/src/autofit/afglobal.h
index 83a7c2ff15..66170e419d 100644
--- a/src/3rdparty/freetype/src/autofit/afglobal.h
+++ b/src/3rdparty/freetype/src/autofit/afglobal.h
@@ -156,7 +156,7 @@ FT_BEGIN_HEADER
AF_StyleMetrics *ametrics );
FT_LOCAL( void )
- af_face_globals_free( AF_FaceGlobals globals );
+ af_face_globals_free( void* globals );
FT_LOCAL( FT_Bool )
af_face_globals_is_digit( AF_FaceGlobals globals,
diff --git a/src/3rdparty/freetype/src/autofit/afhints.c b/src/3rdparty/freetype/src/autofit/afhints.c
index 6515af9f04..e4a378fbf7 100644
--- a/src/3rdparty/freetype/src/autofit/afhints.c
+++ b/src/3rdparty/freetype/src/autofit/afhints.c
@@ -320,8 +320,9 @@
static char*
- af_print_idx( char* p,
- int idx )
+ af_print_idx( char* p,
+ size_t n,
+ int idx )
{
if ( idx == -1 )
{
@@ -330,7 +331,7 @@
p[2] = '\0';
}
else
- ft_sprintf( p, "%d", idx );
+ ft_snprintf( p, n, "%d", idx );
return p;
}
@@ -457,12 +458,12 @@
" %5d %5d %7.2f %7.2f %7.2f %7.2f"
" %5s %5s %5s %5s\n",
point_idx,
- af_print_idx( buf1,
+ af_print_idx( buf1, 16,
af_get_edge_index( hints, segment_idx_1, 1 ) ),
- af_print_idx( buf2, segment_idx_1 ),
- af_print_idx( buf3,
+ af_print_idx( buf2, 16, segment_idx_1 ),
+ af_print_idx( buf3, 16,
af_get_edge_index( hints, segment_idx_0, 0 ) ),
- af_print_idx( buf4, segment_idx_0 ),
+ af_print_idx( buf4, 16, segment_idx_0 ),
( point->flags & AF_FLAG_NEAR )
? " near "
: ( point->flags & AF_FLAG_WEAK_INTERPOLATION )
@@ -476,18 +477,22 @@
(double)point->x / 64,
(double)point->y / 64,
- af_print_idx( buf5, af_get_strong_edge_index( hints,
- point->before,
- 1 ) ),
- af_print_idx( buf6, af_get_strong_edge_index( hints,
- point->after,
- 1 ) ),
- af_print_idx( buf7, af_get_strong_edge_index( hints,
- point->before,
- 0 ) ),
- af_print_idx( buf8, af_get_strong_edge_index( hints,
- point->after,
- 0 ) ) ));
+ af_print_idx( buf5, 16,
+ af_get_strong_edge_index( hints,
+ point->before,
+ 1 ) ),
+ af_print_idx( buf6, 16,
+ af_get_strong_edge_index( hints,
+ point->after,
+ 1 ) ),
+ af_print_idx( buf7, 16,
+ af_get_strong_edge_index( hints,
+ point->before,
+ 0 ) ),
+ af_print_idx( buf8, 16,
+ af_get_strong_edge_index( hints,
+ point->after,
+ 0 ) ) ));
}
AF_DUMP(( "\n" ));
}
@@ -574,9 +579,12 @@
AF_INDEX_NUM( seg->first, points ),
AF_INDEX_NUM( seg->last, points ),
- af_print_idx( buf1, AF_INDEX_NUM( seg->link, segments ) ),
- af_print_idx( buf2, AF_INDEX_NUM( seg->serif, segments ) ),
- af_print_idx( buf3, AF_INDEX_NUM( seg->edge, edges ) ),
+ af_print_idx( buf1, 16,
+ AF_INDEX_NUM( seg->link, segments ) ),
+ af_print_idx( buf2, 16,
+ AF_INDEX_NUM( seg->serif, segments ) ),
+ af_print_idx( buf3, 16,
+ AF_INDEX_NUM( seg->edge, edges ) ),
seg->height,
seg->height - ( seg->max_coord - seg->min_coord ),
@@ -716,8 +724,10 @@
AF_INDEX_NUM( edge, edges ),
(double)(int)edge->opos / 64,
af_dir_str( (AF_Direction)edge->dir ),
- af_print_idx( buf1, AF_INDEX_NUM( edge->link, edges ) ),
- af_print_idx( buf2, AF_INDEX_NUM( edge->serif, edges ) ),
+ af_print_idx( buf1, 16,
+ AF_INDEX_NUM( edge->link, edges ) ),
+ af_print_idx( buf2, 16,
+ AF_INDEX_NUM( edge->serif, edges ) ),
edge->blue_edge ? 'y' : 'n',
(double)edge->opos / 64,
diff --git a/src/3rdparty/freetype/src/autofit/afindic.c b/src/3rdparty/freetype/src/autofit/afindic.c
index 289a09d71d..7fb12c63d5 100644
--- a/src/3rdparty/freetype/src/autofit/afindic.c
+++ b/src/3rdparty/freetype/src/autofit/afindic.c
@@ -28,9 +28,12 @@
static FT_Error
- af_indic_metrics_init( AF_CJKMetrics metrics,
- FT_Face face )
+ af_indic_metrics_init( AF_StyleMetrics metrics_, /* AF_CJKMetrics */
+ FT_Face face )
{
+ AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
+
+
/* skip blue zone init in CJK routines */
FT_CharMap oldmap = face->charmap;
@@ -55,8 +58,8 @@
static void
- af_indic_metrics_scale( AF_CJKMetrics metrics,
- AF_Scaler scaler )
+ af_indic_metrics_scale( AF_StyleMetrics metrics,
+ AF_Scaler scaler )
{
/* use CJK routines */
af_cjk_metrics_scale( metrics, scaler );
@@ -64,8 +67,8 @@
static FT_Error
- af_indic_hints_init( AF_GlyphHints hints,
- AF_CJKMetrics metrics )
+ af_indic_hints_init( AF_GlyphHints hints,
+ AF_StyleMetrics metrics )
{
/* use CJK routines */
return af_cjk_hints_init( hints, metrics );
@@ -73,10 +76,10 @@
static FT_Error
- af_indic_hints_apply( FT_UInt glyph_index,
- AF_GlyphHints hints,
- FT_Outline* outline,
- AF_CJKMetrics metrics )
+ af_indic_hints_apply( FT_UInt glyph_index,
+ AF_GlyphHints hints,
+ FT_Outline* outline,
+ AF_StyleMetrics metrics )
{
/* use CJK routines */
return af_cjk_hints_apply( glyph_index, hints, outline, metrics );
@@ -87,10 +90,13 @@
/* metrics class. */
static void
- af_indic_get_standard_widths( AF_CJKMetrics metrics,
- FT_Pos* stdHW,
- FT_Pos* stdVW )
+ af_indic_get_standard_widths( AF_StyleMetrics metrics_, /* AF_CJKMetrics */
+ FT_Pos* stdHW,
+ FT_Pos* stdVW )
{
+ AF_CJKMetrics metrics = (AF_CJKMetrics)metrics_;
+
+
if ( stdHW )
*stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
diff --git a/src/3rdparty/freetype/src/autofit/aflatin.c b/src/3rdparty/freetype/src/autofit/aflatin.c
index 4b3c59b3c3..b86367aa94 100644
--- a/src/3rdparty/freetype/src/autofit/aflatin.c
+++ b/src/3rdparty/freetype/src/autofit/aflatin.c
@@ -496,23 +496,20 @@
/* now compute min or max point indices and coordinates */
points = outline.points;
best_point = -1;
+ best_contour_first = -1;
+ best_contour_last = -1;
best_y = 0; /* make compiler happy */
- best_contour_first = 0; /* ditto */
- best_contour_last = 0; /* ditto */
{
FT_Int nn;
- FT_Int first = 0;
- FT_Int last = -1;
+ FT_Int pp, first, last;
- for ( nn = 0; nn < outline.n_contours; first = last + 1, nn++ )
+ last = -1;
+ for ( nn = 0; nn < outline.n_contours; nn++ )
{
- FT_Int old_best_point = best_point;
- FT_Int pp;
-
-
- last = outline.contours[nn];
+ first = last + 1;
+ last = outline.contours[nn];
/* Avoid single-point contours since they are never */
/* rasterized. In some fonts, they correspond to mark */
@@ -551,7 +548,7 @@
}
}
- if ( best_point != old_best_point )
+ if ( best_point > best_contour_last )
{
best_contour_first = first;
best_contour_last = last;
@@ -1025,7 +1022,7 @@
{
*a = *b;
FT_TRACE5(( "blue zone overlap:"
- " adjusting %s %ld to %ld\n",
+ " adjusting %s %td to %ld\n",
a_is_top ? "overshoot" : "reference",
blue_sorted[i] - axis->blues,
*a ));
@@ -1068,8 +1065,8 @@
af_latin_metrics_check_digits( AF_LatinMetrics metrics,
FT_Face face )
{
- FT_Bool started = 0, same_width = 1;
- FT_Fixed advance = 0, old_advance = 0;
+ FT_Bool started = 0, same_width = 1;
+ FT_Long advance = 0, old_advance = 0;
/* If HarfBuzz is not available, we need a pointer to a single */
/* unsigned long value. */
@@ -1134,9 +1131,11 @@
/* Initialize global metrics. */
FT_LOCAL_DEF( FT_Error )
- af_latin_metrics_init( AF_LatinMetrics metrics,
+ af_latin_metrics_init( AF_StyleMetrics metrics_, /* AF_LatinMetrics */
FT_Face face )
{
+ AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_;
+
FT_Error error = FT_Err_Ok;
FT_CharMap oldmap = face->charmap;
@@ -1489,9 +1488,12 @@
/* Scale global values in both directions. */
FT_LOCAL_DEF( void )
- af_latin_metrics_scale( AF_LatinMetrics metrics,
+ af_latin_metrics_scale( AF_StyleMetrics metrics_, /* AF_LatinMetrics */
AF_Scaler scaler )
{
+ AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_;
+
+
metrics->root.scaler.render_mode = scaler->render_mode;
metrics->root.scaler.face = scaler->face;
metrics->root.scaler.flags = scaler->flags;
@@ -1504,11 +1506,14 @@
/* Extract standard_width from writing system/script specific */
/* metrics class. */
- FT_LOCAL_DEF( void )
- af_latin_get_standard_widths( AF_LatinMetrics metrics,
+ FT_CALLBACK_DEF( void )
+ af_latin_get_standard_widths( AF_StyleMetrics metrics_, /* AF_LatinMetrics */
FT_Pos* stdHW,
FT_Pos* stdVW )
{
+ AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_;
+
+
if ( stdHW )
*stdHW = metrics->axis[AF_DIMENSION_VERT].standard_width;
@@ -2041,7 +2046,7 @@
max = seg2->max_coord;
/* compute maximum coordinate difference of the two segments */
- /* (this is, how much they overlap) */
+ /* (that is, how much they overlap) */
len = max - min;
if ( len >= len_threshold )
{
@@ -2610,8 +2615,10 @@
static FT_Error
af_latin_hints_init( AF_GlyphHints hints,
- AF_LatinMetrics metrics )
+ AF_StyleMetrics metrics_ ) /* AF_LatinMetrics */
{
+ AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_;
+
FT_Render_Mode mode;
FT_UInt32 scaler_flags, other_flags;
FT_Face face = metrics->root.scaler.face;
@@ -2953,7 +2960,7 @@
stem_edge->pos = base_edge->pos + fitted_width;
- FT_TRACE5(( " LINK: edge %ld (opos=%.2f) linked to %.2f,"
+ FT_TRACE5(( " LINK: edge %td (opos=%.2f) linked to %.2f,"
" dist was %.2f, now %.2f\n",
stem_edge - hints->axis[dim].edges,
(double)stem_edge->opos / 64, (double)stem_edge->pos / 64,
@@ -3078,13 +3085,13 @@
#ifdef FT_DEBUG_LEVEL_TRACE
if ( !anchor )
- FT_TRACE5(( " BLUE_ANCHOR: edge %ld (opos=%.2f) snapped to %.2f,"
- " was %.2f (anchor=edge %ld)\n",
+ FT_TRACE5(( " BLUE_ANCHOR: edge %td (opos=%.2f) snapped to %.2f,"
+ " was %.2f (anchor=edge %td)\n",
edge1 - edges,
(double)edge1->opos / 64, (double)blue->fit / 64,
(double)edge1->pos / 64, edge - edges ));
else
- FT_TRACE5(( " BLUE: edge %ld (opos=%.2f) snapped to %.2f,"
+ FT_TRACE5(( " BLUE: edge %td (opos=%.2f) snapped to %.2f,"
" was %.2f\n",
edge1 - edges,
(double)edge1->opos / 64, (double)blue->fit / 64,
@@ -3134,7 +3141,7 @@
/* this should not happen, but it's better to be safe */
if ( edge2->blue_edge )
{
- FT_TRACE5(( " ASSERTION FAILED for edge %ld\n", edge2 - edges ));
+ FT_TRACE5(( " ASSERTION FAILED for edge %td\n", edge2 - edges ));
af_latin_align_linked_edge( hints, dim, edge2, edge );
edge->flags |= AF_EDGE_DONE;
@@ -3202,7 +3209,7 @@
anchor = edge;
edge->flags |= AF_EDGE_DONE;
- FT_TRACE5(( " ANCHOR: edge %ld (opos=%.2f) and %ld (opos=%.2f)"
+ FT_TRACE5(( " ANCHOR: edge %td (opos=%.2f) and %td (opos=%.2f)"
" snapped to %.2f and %.2f\n",
edge - edges, (double)edge->opos / 64,
edge2 - edges, (double)edge2->opos / 64,
@@ -3231,7 +3238,7 @@
if ( edge2->flags & AF_EDGE_DONE )
{
- FT_TRACE5(( " ADJUST: edge %ld (pos=%.2f) moved to %.2f\n",
+ FT_TRACE5(( " ADJUST: edge %td (pos=%.2f) moved to %.2f\n",
edge - edges, (double)edge->pos / 64,
(double)( edge2->pos - cur_len ) / 64 ));
@@ -3272,7 +3279,7 @@
edge->pos = cur_pos1 - cur_len / 2;
edge2->pos = cur_pos1 + cur_len / 2;
- FT_TRACE5(( " STEM: edge %ld (opos=%.2f) linked to %ld (opos=%.2f)"
+ FT_TRACE5(( " STEM: edge %td (opos=%.2f) linked to %td (opos=%.2f)"
" snapped to %.2f and %.2f\n",
edge - edges, (double)edge->opos / 64,
edge2 - edges, (double)edge2->opos / 64,
@@ -3303,7 +3310,7 @@
edge->pos = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2;
edge2->pos = edge->pos + cur_len;
- FT_TRACE5(( " STEM: edge %ld (opos=%.2f) linked to %ld (opos=%.2f)"
+ FT_TRACE5(( " STEM: edge %td (opos=%.2f) linked to %td (opos=%.2f)"
" snapped to %.2f and %.2f\n",
edge - edges, (double)edge->opos / 64,
edge2 - edges, (double)edge2->opos / 64,
@@ -3326,7 +3333,7 @@
if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 )
{
#ifdef FT_DEBUG_LEVEL_TRACE
- FT_TRACE5(( " BOUND: edge %ld (pos=%.2f) moved to %.2f\n",
+ FT_TRACE5(( " BOUND: edge %td (pos=%.2f) moved to %.2f\n",
edge - edges,
(double)edge->pos / 64,
(double)edge[-1].pos / 64 ));
@@ -3428,7 +3435,7 @@
if ( delta < 64 + 16 )
{
af_latin_align_serif_edge( hints, edge->serif, edge );
- FT_TRACE5(( " SERIF: edge %ld (opos=%.2f) serif to %ld (opos=%.2f)"
+ FT_TRACE5(( " SERIF: edge %td (opos=%.2f) serif to %td (opos=%.2f)"
" aligned to %.2f\n",
edge - edges, (double)edge->opos / 64,
edge->serif - edges, (double)edge->serif->opos / 64,
@@ -3438,9 +3445,9 @@
{
edge->pos = FT_PIX_ROUND( edge->opos );
anchor = edge;
- FT_TRACE5(( " SERIF_ANCHOR: edge %ld (opos=%.2f)"
+ FT_TRACE5(( " SERIF_ANCHOR: edge %td (opos=%.2f)"
" snapped to %.2f\n",
- edge-edges,
+ edge - edges,
(double)edge->opos / 64, (double)edge->pos / 64 ));
}
else
@@ -3467,8 +3474,8 @@
after->pos - before->pos,
after->opos - before->opos );
- FT_TRACE5(( " SERIF_LINK1: edge %ld (opos=%.2f) snapped to %.2f"
- " from %ld (opos=%.2f)\n",
+ FT_TRACE5(( " SERIF_LINK1: edge %td (opos=%.2f) snapped to %.2f"
+ " from %td (opos=%.2f)\n",
edge - edges, (double)edge->opos / 64,
(double)edge->pos / 64,
before - edges, (double)before->opos / 64 ));
@@ -3477,7 +3484,7 @@
{
edge->pos = anchor->pos +
( ( edge->opos - anchor->opos + 16 ) & ~31 );
- FT_TRACE5(( " SERIF_LINK2: edge %ld (opos=%.2f)"
+ FT_TRACE5(( " SERIF_LINK2: edge %td (opos=%.2f)"
" snapped to %.2f\n",
edge - edges,
(double)edge->opos / 64, (double)edge->pos / 64 ));
@@ -3498,7 +3505,7 @@
if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 )
{
#ifdef FT_DEBUG_LEVEL_TRACE
- FT_TRACE5(( " BOUND: edge %ld (pos=%.2f) moved to %.2f\n",
+ FT_TRACE5(( " BOUND: edge %td (pos=%.2f) moved to %.2f\n",
edge - edges,
(double)edge->pos / 64,
(double)edge[-1].pos / 64 ));
@@ -3519,7 +3526,7 @@
if ( edge->link && FT_ABS( edge->link->pos - edge[-1].pos ) > 16 )
{
#ifdef FT_DEBUG_LEVEL_TRACE
- FT_TRACE5(( " BOUND: edge %ld (pos=%.2f) moved to %.2f\n",
+ FT_TRACE5(( " BOUND: edge %td (pos=%.2f) moved to %.2f\n",
edge - edges,
(double)edge->pos / 64,
(double)edge[1].pos / 64 ));
@@ -3547,8 +3554,10 @@
af_latin_hints_apply( FT_UInt glyph_index,
AF_GlyphHints hints,
FT_Outline* outline,
- AF_LatinMetrics metrics )
+ AF_StyleMetrics metrics_ ) /* AF_LatinMetrics */
{
+ AF_LatinMetrics metrics = (AF_LatinMetrics)metrics_;
+
FT_Error error;
int dim;
diff --git a/src/3rdparty/freetype/src/autofit/aflatin.h b/src/3rdparty/freetype/src/autofit/aflatin.h
index 3c6a7ee4f6..31aa91d3bd 100644
--- a/src/3rdparty/freetype/src/autofit/aflatin.h
+++ b/src/3rdparty/freetype/src/autofit/aflatin.h
@@ -116,11 +116,11 @@ FT_BEGIN_HEADER
FT_LOCAL( FT_Error )
- af_latin_metrics_init( AF_LatinMetrics metrics,
+ af_latin_metrics_init( AF_StyleMetrics metrics,
FT_Face face );
FT_LOCAL( void )
- af_latin_metrics_scale( AF_LatinMetrics metrics,
+ af_latin_metrics_scale( AF_StyleMetrics metrics,
AF_Scaler scaler );
FT_LOCAL( void )
diff --git a/src/3rdparty/freetype/src/autofit/afloader.c b/src/3rdparty/freetype/src/autofit/afloader.c
index c8082796fe..7c47d562af 100644
--- a/src/3rdparty/freetype/src/autofit/afloader.c
+++ b/src/3rdparty/freetype/src/autofit/afloader.c
@@ -55,10 +55,8 @@
error = af_face_globals_new( face, &loader->globals, module );
if ( !error )
{
- face->autohint.data =
- (FT_Pointer)loader->globals;
- face->autohint.finalizer =
- (FT_Generic_Finalizer)af_face_globals_free;
+ face->autohint.data = (FT_Pointer)loader->globals;
+ face->autohint.finalizer = af_face_globals_free;
}
}
diff --git a/src/3rdparty/freetype/src/autofit/afmodule.c b/src/3rdparty/freetype/src/autofit/afmodule.c
index 92e5156ab2..20a6b96bc4 100644
--- a/src/3rdparty/freetype/src/autofit/afmodule.c
+++ b/src/3rdparty/freetype/src/autofit/afmodule.c
@@ -89,10 +89,8 @@
error = af_face_globals_new( face, &globals, module );
if ( !error )
{
- face->autohint.data =
- (FT_Pointer)globals;
- face->autohint.finalizer =
- (FT_Generic_Finalizer)af_face_globals_free;
+ face->autohint.data = (FT_Pointer)globals;
+ face->autohint.finalizer = af_face_globals_free;
}
}
@@ -374,8 +372,9 @@
FT_DEFINE_SERVICE_PROPERTIESREC(
af_service_properties,
- (FT_Properties_SetFunc)af_property_set, /* set_property */
- (FT_Properties_GetFunc)af_property_get ) /* get_property */
+ af_property_set, /* FT_Properties_SetFunc set_property */
+ af_property_get /* FT_Properties_GetFunc get_property */
+ )
FT_DEFINE_SERVICEDESCREC1(
@@ -430,12 +429,14 @@
FT_CALLBACK_DEF( FT_Error )
- af_autofitter_load_glyph( AF_Module module,
- FT_GlyphSlot slot,
- FT_Size size,
- FT_UInt glyph_index,
- FT_Int32 load_flags )
+ af_autofitter_load_glyph( FT_AutoHinter module_,
+ FT_GlyphSlot slot,
+ FT_Size size,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags )
{
+ AF_Module module = (AF_Module)module_;
+
FT_Error error = FT_Err_Ok;
FT_Memory memory = module->root.library->memory;
@@ -499,10 +500,10 @@
FT_DEFINE_AUTOHINTER_INTERFACE(
af_autofitter_interface,
- NULL, /* reset_face */
- NULL, /* get_global_hints */
- NULL, /* done_global_hints */
- (FT_AutoHinter_GlyphLoadFunc)af_autofitter_load_glyph /* load_glyph */
+ NULL, /* FT_AutoHinter_GlobalResetFunc reset_face */
+ NULL, /* FT_AutoHinter_GlobalGetFunc get_global_hints */
+ NULL, /* FT_AutoHinter_GlobalDoneFunc done_global_hints */
+ af_autofitter_load_glyph /* FT_AutoHinter_GlyphLoadFunc load_glyph */
)
FT_DEFINE_MODULE(
@@ -517,9 +518,9 @@
(const void*)&af_autofitter_interface,
- (FT_Module_Constructor)af_autofitter_init, /* module_init */
- (FT_Module_Destructor) af_autofitter_done, /* module_done */
- (FT_Module_Requester) af_get_interface /* get_interface */
+ af_autofitter_init, /* FT_Module_Constructor module_init */
+ af_autofitter_done, /* FT_Module_Destructor module_done */
+ af_get_interface /* FT_Module_Requester get_interface */
)
diff --git a/src/3rdparty/freetype/src/autofit/afshaper.c b/src/3rdparty/freetype/src/autofit/afshaper.c
index 1b8b870e89..abc6f1d292 100644
--- a/src/3rdparty/freetype/src/autofit/afshaper.c
+++ b/src/3rdparty/freetype/src/autofit/afshaper.c
@@ -258,7 +258,7 @@
/*
* We now check whether we can construct blue zones, using glyphs
* covered by the feature only. In case there is not a single zone
- * (this is, not a single character is covered), we skip this coverage.
+ * (that is, not a single character is covered), we skip this coverage.
*
*/
if ( style_class->coverage != AF_COVERAGE_DEFAULT )
@@ -313,9 +313,9 @@
* hinted and usually rendered glyph.
*
* Consider the superscript feature of font `pala.ttf': Some of the
- * glyphs are `real', this is, they have a zero vertical offset, but
+ * glyphs are `real', that is, they have a zero vertical offset, but
* most of them are small caps glyphs shifted up to the superscript
- * position (this is, the `sups' feature is present in both the GSUB and
+ * position (that is, the `sups' feature is present in both the GSUB and
* GPOS tables). The code for blue zones computation actually uses a
* feature's y offset so that the `real' glyphs get correct hints. But
* later on it is impossible to decide whether a glyph index belongs to,
diff --git a/src/3rdparty/freetype/src/autofit/ft-hb.c b/src/3rdparty/freetype/src/autofit/ft-hb.c
index 09a8401c4a..71aee04550 100644
--- a/src/3rdparty/freetype/src/autofit/ft-hb.c
+++ b/src/3rdparty/freetype/src/autofit/ft-hb.c
@@ -108,7 +108,7 @@ hb_ft_font_create_ (FT_Face ft_face,
#else /* !FT_CONFIG_OPTION_USE_HARFBUZZ */
/* ANSI C doesn't like empty source files */
-typedef int _ft_hb_dummy;
+typedef int ft_hb_dummy_;
#endif /* !FT_CONFIG_OPTION_USE_HARFBUZZ */
diff --git a/src/3rdparty/freetype/src/base/ftbbox.c b/src/3rdparty/freetype/src/base/ftbbox.c
index 7dd71882ea..385fea4040 100644
--- a/src/3rdparty/freetype/src/base/ftbbox.c
+++ b/src/3rdparty/freetype/src/base/ftbbox.c
@@ -82,10 +82,13 @@
* @Return:
* Always 0. Needed for the interface only.
*/
- static int
- BBox_Move_To( FT_Vector* to,
- TBBox_Rec* user )
+ FT_CALLBACK_DEF( int )
+ BBox_Move_To( const FT_Vector* to,
+ void* user_ )
{
+ TBBox_Rec* user = (TBBox_Rec*)user_;
+
+
FT_UPDATE_BBOX( to, user->bbox );
user->last = *to;
@@ -116,10 +119,13 @@
* @Return:
* Always 0. Needed for the interface only.
*/
- static int
- BBox_Line_To( FT_Vector* to,
- TBBox_Rec* user )
+ FT_CALLBACK_DEF( int )
+ BBox_Line_To( const FT_Vector* to,
+ void* user_ )
{
+ TBBox_Rec* user = (TBBox_Rec*)user_;
+
+
user->last = *to;
return 0;
@@ -205,11 +211,14 @@
* In the case of a non-monotonous arc, we compute directly the
* extremum coordinates, as it is sufficiently fast.
*/
- static int
- BBox_Conic_To( FT_Vector* control,
- FT_Vector* to,
- TBBox_Rec* user )
+ FT_CALLBACK_DEF( int )
+ BBox_Conic_To( const FT_Vector* control,
+ const FT_Vector* to,
+ void* user_ )
{
+ TBBox_Rec* user = (TBBox_Rec*)user_;
+
+
/* in case `to' is implicit and not included in bbox yet */
FT_UPDATE_BBOX( to, user->bbox );
@@ -410,12 +419,15 @@
* In the case of a non-monotonous arc, we don't compute directly
* extremum coordinates, we subdivide instead.
*/
- static int
- BBox_Cubic_To( FT_Vector* control1,
- FT_Vector* control2,
- FT_Vector* to,
- TBBox_Rec* user )
+ FT_CALLBACK_DEF( int )
+ BBox_Cubic_To( const FT_Vector* control1,
+ const FT_Vector* control2,
+ const FT_Vector* to,
+ void* user_ )
{
+ TBBox_Rec* user = (TBBox_Rec*)user_;
+
+
/* We don't need to check `to' since it is always an on-point, */
/* thus within the bbox. Only segments with an off-point outside */
/* the bbox can possibly reach new extreme values. */
diff --git a/src/3rdparty/freetype/src/base/ftcalc.c b/src/3rdparty/freetype/src/base/ftcalc.c
index 13e74f3353..c5bc7e3b14 100644
--- a/src/3rdparty/freetype/src/base/ftcalc.c
+++ b/src/3rdparty/freetype/src/base/ftcalc.c
@@ -749,65 +749,43 @@
FT_BASE_DEF( FT_Bool )
FT_Matrix_Check( const FT_Matrix* matrix )
{
- FT_Matrix m;
- FT_Fixed val[4];
- FT_Fixed nonzero_minval, maxval;
- FT_Fixed temp1, temp2;
- FT_UInt i;
+ FT_Fixed xx, xy, yx, yy;
+ FT_Fixed val;
+ FT_Int shift;
+ FT_ULong temp1, temp2;
if ( !matrix )
return 0;
- val[0] = FT_ABS( matrix->xx );
- val[1] = FT_ABS( matrix->xy );
- val[2] = FT_ABS( matrix->yx );
- val[3] = FT_ABS( matrix->yy );
+ xx = matrix->xx;
+ xy = matrix->xy;
+ yx = matrix->yx;
+ yy = matrix->yy;
+ val = FT_ABS( xx ) | FT_ABS( xy ) | FT_ABS( yx ) | FT_ABS( yy );
- /*
- * To avoid overflow, we ensure that each value is not larger than
- *
- * int(sqrt(2^31 / 4)) = 23170 ;
- *
- * we also check that no value becomes zero if we have to scale.
- */
-
- maxval = 0;
- nonzero_minval = FT_LONG_MAX;
-
- for ( i = 0; i < 4; i++ )
- {
- if ( val[i] > maxval )
- maxval = val[i];
- if ( val[i] && val[i] < nonzero_minval )
- nonzero_minval = val[i];
- }
-
- /* we only handle 32bit values */
- if ( maxval > 0x7FFFFFFFL )
+ /* we only handle non-zero 32-bit values */
+ if ( !val || val > 0x7FFFFFFFL )
return 0;
- if ( maxval > 23170 )
- {
- FT_Fixed scale = FT_DivFix( maxval, 23170 );
-
+ /* Scale matrix to avoid the temp1 overflow, which is */
+ /* more stringent than avoiding the temp2 overflow. */
- if ( !FT_DivFix( nonzero_minval, scale ) )
- return 0; /* value range too large */
+ shift = FT_MSB( val ) - 12;
- m.xx = FT_DivFix( matrix->xx, scale );
- m.xy = FT_DivFix( matrix->xy, scale );
- m.yx = FT_DivFix( matrix->yx, scale );
- m.yy = FT_DivFix( matrix->yy, scale );
+ if ( shift > 0 )
+ {
+ xx >>= shift;
+ xy >>= shift;
+ yx >>= shift;
+ yy >>= shift;
}
- else
- m = *matrix;
- temp1 = FT_ABS( m.xx * m.yy - m.xy * m.yx );
- temp2 = m.xx * m.xx + m.xy * m.xy + m.yx * m.yx + m.yy * m.yy;
+ temp1 = 32U * (FT_ULong)FT_ABS( xx * yy - xy * yx );
+ temp2 = (FT_ULong)( xx * xx ) + (FT_ULong)( xy * xy ) +
+ (FT_ULong)( yx * yx ) + (FT_ULong)( yy * yy );
- if ( temp1 == 0 ||
- temp2 / temp1 > 50 )
+ if ( temp1 <= temp2 )
return 0;
return 1;
@@ -1061,7 +1039,7 @@
/* */
/* This approach has the advantage that the angle between */
/* `in' and `out' is not checked. In case one of the two */
- /* vectors is `dominant', this is, much larger than the */
+ /* vectors is `dominant', that is, much larger than the */
/* other vector, we thus always have a flat corner. */
/* */
/* hypotenuse */
@@ -1092,9 +1070,6 @@
{
FT_UInt i;
FT_Int64 temp;
-#ifndef FT_INT64
- FT_Int64 halfUnit;
-#endif
#ifdef FT_INT64
@@ -1103,7 +1078,7 @@
for ( i = 0; i < count; ++i )
temp += (FT_Int64)s[i] * f[i];
- return ( temp + 0x8000 ) >> 16;
+ return (FT_Int32)( ( temp + 0x8000 ) >> 16 );
#else
temp.hi = 0;
temp.lo = 0;
@@ -1139,13 +1114,10 @@
FT_Add64( &temp, &multResult, &temp );
}
- /* Round value. */
- halfUnit.hi = 0;
- halfUnit.lo = 0x8000;
- FT_Add64( &temp, &halfUnit, &temp );
+ /* Shift and round value. */
+ return (FT_Int32)( ( ( temp.hi << 16 ) | ( temp.lo >> 16 ) )
+ + ( 1 & ( temp.lo >> 15 ) ) );
- return (FT_Int32)( ( (FT_Int32)( temp.hi & 0xFFFF ) << 16 ) |
- ( temp.lo >> 16 ) );
#endif /* !FT_INT64 */
diff --git a/src/3rdparty/freetype/src/base/ftdbgmem.c b/src/3rdparty/freetype/src/base/ftdbgmem.c
index 6730c4c8d3..8fab50dd01 100644
--- a/src/3rdparty/freetype/src/base/ftdbgmem.c
+++ b/src/3rdparty/freetype/src/base/ftdbgmem.c
@@ -963,7 +963,7 @@
#else /* !FT_DEBUG_MEMORY */
/* ANSI C doesn't like empty source files */
- typedef int _debug_mem_dummy;
+ typedef int debug_mem_dummy_;
#endif /* !FT_DEBUG_MEMORY */
diff --git a/src/3rdparty/freetype/src/base/ftmac.c b/src/3rdparty/freetype/src/base/ftmac.c
index de34e834f2..492d055384 100644
--- a/src/3rdparty/freetype/src/base/ftmac.c
+++ b/src/3rdparty/freetype/src/base/ftmac.c
@@ -1082,7 +1082,7 @@
#else /* !FT_MACINTOSH */
/* ANSI C doesn't like empty source files */
- typedef int _ft_mac_dummy;
+ typedef int ft_mac_dummy_;
#endif /* !FT_MACINTOSH */
diff --git a/src/3rdparty/freetype/src/base/ftmm.c b/src/3rdparty/freetype/src/base/ftmm.c
index a2b4bd03d7..9e2dd7ee79 100644
--- a/src/3rdparty/freetype/src/base/ftmm.c
+++ b/src/3rdparty/freetype/src/base/ftmm.c
@@ -185,6 +185,14 @@
error = FT_ERR( Invalid_Argument );
if ( service->set_mm_design )
error = service->set_mm_design( face, num_coords, coords );
+
+ if ( !error )
+ {
+ if ( num_coords )
+ face->face_flags |= FT_FACE_FLAG_VARIATION;
+ else
+ face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+ }
}
/* enforce recomputation of auto-hinting data */
@@ -220,6 +228,14 @@
error = FT_ERR( Invalid_Argument );
if ( service->set_mm_weightvector )
error = service->set_mm_weightvector( face, len, weightvector );
+
+ if ( !error )
+ {
+ if ( len )
+ face->face_flags |= FT_FACE_FLAG_VARIATION;
+ else
+ face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+ }
}
/* enforce recomputation of auto-hinting data */
@@ -283,6 +299,30 @@
if ( service_mm->set_var_design )
error = service_mm->set_var_design( face, num_coords, coords );
+ if ( !error || error == -1 )
+ {
+ FT_Bool is_variation_old = FT_IS_VARIATION( face );
+
+
+ if ( num_coords )
+ face->face_flags |= FT_FACE_FLAG_VARIATION;
+ else
+ face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+
+ if ( service_mm->construct_ps_name )
+ {
+ if ( error == -1 )
+ {
+ /* The PS name of a named instance and a non-named instance */
+ /* usually differs, even if the axis values are identical. */
+ if ( is_variation_old != FT_IS_VARIATION( face ) )
+ service_mm->construct_ps_name( face );
+ }
+ else
+ service_mm->construct_ps_name( face );
+ }
+ }
+
/* internal error code -1 means `no change'; we can exit immediately */
if ( error == -1 )
return FT_Err_Ok;
@@ -359,6 +399,30 @@
if ( service_mm->set_mm_blend )
error = service_mm->set_mm_blend( face, num_coords, coords );
+ if ( !error || error == -1 )
+ {
+ FT_Bool is_variation_old = FT_IS_VARIATION( face );
+
+
+ if ( num_coords )
+ face->face_flags |= FT_FACE_FLAG_VARIATION;
+ else
+ face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+
+ if ( service_mm->construct_ps_name )
+ {
+ if ( error == -1 )
+ {
+ /* The PS name of a named instance and a non-named instance */
+ /* usually differs, even if the axis values are identical. */
+ if ( is_variation_old != FT_IS_VARIATION( face ) )
+ service_mm->construct_ps_name( face );
+ }
+ else
+ service_mm->construct_ps_name( face );
+ }
+ }
+
/* internal error code -1 means `no change'; we can exit immediately */
if ( error == -1 )
return FT_Err_Ok;
@@ -410,6 +474,30 @@
if ( service_mm->set_mm_blend )
error = service_mm->set_mm_blend( face, num_coords, coords );
+ if ( !error || error == -1 )
+ {
+ FT_Bool is_variation_old = FT_IS_VARIATION( face );
+
+
+ if ( num_coords )
+ face->face_flags |= FT_FACE_FLAG_VARIATION;
+ else
+ face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+
+ if ( service_mm->construct_ps_name )
+ {
+ if ( error == -1 )
+ {
+ /* The PS name of a named instance and a non-named instance */
+ /* usually differs, even if the axis values are identical. */
+ if ( is_variation_old != FT_IS_VARIATION( face ) )
+ service_mm->construct_ps_name( face );
+ }
+ else
+ service_mm->construct_ps_name( face );
+ }
+ }
+
/* internal error code -1 means `no change'; we can exit immediately */
if ( error == -1 )
return FT_Err_Ok;
@@ -535,8 +623,35 @@
if ( !error )
{
error = FT_ERR( Invalid_Argument );
- if ( service_mm->set_instance )
- error = service_mm->set_instance( face, instance_index );
+ if ( service_mm->set_named_instance )
+ error = service_mm->set_named_instance( face, instance_index );
+
+ if ( !error || error == -1 )
+ {
+ FT_Bool is_variation_old = FT_IS_VARIATION( face );
+
+
+ face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+ face->face_index = ( instance_index << 16 ) |
+ ( face->face_index & 0xFFFFL );
+
+ if ( service_mm->construct_ps_name )
+ {
+ if ( error == -1 )
+ {
+ /* The PS name of a named instance and a non-named instance */
+ /* usually differs, even if the axis values are identical. */
+ if ( is_variation_old != FT_IS_VARIATION( face ) )
+ service_mm->construct_ps_name( face );
+ }
+ else
+ service_mm->construct_ps_name( face );
+ }
+ }
+
+ /* internal error code -1 means `no change'; we can exit immediately */
+ if ( error == -1 )
+ return FT_Err_Ok;
}
if ( !error )
@@ -554,11 +669,32 @@
face->autohint.data = NULL;
}
+ return error;
+ }
+
+
+ /* documentation is in ftmm.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_Default_Named_Instance( FT_Face face,
+ FT_UInt *instance_index )
+ {
+ FT_Error error;
+
+ FT_Service_MultiMasters service_mm = NULL;
+
+
+ /* check of `face' delayed to `ft_face_get_mm_service' */
+
+ error = ft_face_get_mm_service( face, &service_mm );
if ( !error )
{
- face->face_index = ( instance_index << 16 ) |
- ( face->face_index & 0xFFFFL );
- face->face_flags &= ~FT_FACE_FLAG_VARIATION;
+ /* no error if `get_default_named_instance` is not available */
+ if ( service_mm->get_default_named_instance )
+ error = service_mm->get_default_named_instance( face,
+ instance_index );
+ else
+ error = FT_Err_Ok;
}
return error;
diff --git a/src/3rdparty/freetype/src/base/ftobjs.c b/src/3rdparty/freetype/src/base/ftobjs.c
index ad6ef0ae16..89a25bc732 100644
--- a/src/3rdparty/freetype/src/base/ftobjs.c
+++ b/src/3rdparty/freetype/src/base/ftobjs.c
@@ -1019,7 +1019,8 @@
/* elegant. */
/* try to load SVG documents if available */
- if ( FT_HAS_SVG( face ) )
+ if ( ( load_flags & FT_LOAD_NO_SVG ) == 0 &&
+ FT_HAS_SVG( face ) )
{
error = driver->clazz->load_glyph( slot, face->size,
glyph_index,
@@ -1245,9 +1246,13 @@
/* destructor for sizes list */
static void
destroy_size( FT_Memory memory,
- FT_Size size,
- FT_Driver driver )
+ void* size_,
+ void* driver_ )
{
+ FT_Size size = (FT_Size)size_;
+ FT_Driver driver = (FT_Driver)driver_;
+
+
/* finalize client-specific data */
if ( size->generic.finalizer )
size->generic.finalizer( size );
@@ -1293,10 +1298,12 @@
/* destructor for faces list */
static void
destroy_face( FT_Memory memory,
- FT_Face face,
- FT_Driver driver )
+ void* face_,
+ void* driver_ )
{
- FT_Driver_Class clazz = driver->clazz;
+ FT_Face face = (FT_Face)face_;
+ FT_Driver driver = (FT_Driver)driver_;
+ FT_Driver_Class clazz = driver->clazz;
/* discard auto-hinting data */
@@ -1310,7 +1317,7 @@
/* discard all sizes for this face */
FT_List_Finalize( &face->sizes_list,
- (FT_List_Destructor)destroy_size,
+ destroy_size,
memory,
driver );
face->size = NULL;
@@ -1346,7 +1353,7 @@
Destroy_Driver( FT_Driver driver )
{
FT_List_Finalize( &driver->faces_list,
- (FT_List_Destructor)destroy_face,
+ destroy_face,
driver->root.memory,
driver );
}
@@ -1740,7 +1747,8 @@
FT_Memory memory = library->memory;
- args.flags = 0;
+ args.driver = NULL;
+ args.flags = 0;
if ( driver_name )
{
diff --git a/src/3rdparty/freetype/src/base/ftoutln.c b/src/3rdparty/freetype/src/base/ftoutln.c
index 30ff21ff39..134f39d2b1 100644
--- a/src/3rdparty/freetype/src/base/ftoutln.c
+++ b/src/3rdparty/freetype/src/base/ftoutln.c
@@ -58,7 +58,9 @@
FT_Error error;
FT_Int n; /* index of contour in outline */
- FT_UInt first; /* index of first point in contour */
+ FT_Int first; /* index of first point in contour */
+ FT_Int last; /* index of last point in contour */
+
FT_Int tag; /* current point's state */
FT_Int shift;
@@ -73,18 +75,17 @@
shift = func_interface->shift;
delta = func_interface->delta;
- first = 0;
+ last = -1;
for ( n = 0; n < outline->n_contours; n++ )
{
- FT_Int last; /* index of last point in contour */
-
-
- FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n ));
+ FT_TRACE5(( "FT_Outline_Decompose: Contour %d\n", n ));
- last = outline->contours[n];
- if ( last < 0 )
+ first = last + 1;
+ last = outline->contours[n];
+ if ( last < first )
goto Invalid_Outline;
+
limit = outline->points + last;
v_start = outline->points[first];
@@ -282,8 +283,6 @@
Close:
if ( error )
goto Exit;
-
- first = (FT_UInt)last + 1;
}
FT_TRACE5(( "FT_Outline_Decompose: Done\n" ));
@@ -368,7 +367,7 @@
if ( n_points <= 0 || n_contours <= 0 )
goto Bad;
- end0 = end = -1;
+ end0 = -1;
for ( n = 0; n < n_contours; n++ )
{
end = outline->contours[n];
@@ -380,7 +379,7 @@
end0 = end;
}
- if ( end != n_points - 1 )
+ if ( end0 != n_points - 1 )
goto Bad;
/* XXX: check the tags array */
@@ -388,7 +387,7 @@
}
Bad:
- return FT_THROW( Invalid_Argument );
+ return FT_THROW( Invalid_Outline );
}
@@ -550,10 +549,12 @@
if ( !outline )
return;
- first = 0;
-
+ last = -1;
for ( n = 0; n < outline->n_contours; n++ )
{
+ /* keep the first contour point as is and swap points around it */
+ /* to guarantee that the cubic arches stay valid after reverse */
+ first = last + 2;
last = outline->contours[n];
/* reverse point table */
@@ -591,8 +592,6 @@
q--;
}
}
-
- first = last + 1;
}
outline->flags ^= FT_OUTLINE_REVERSE_FILL;
@@ -941,7 +940,7 @@
points = outline->points;
- first = 0;
+ last = -1;
for ( c = 0; c < outline->n_contours; c++ )
{
FT_Vector in, out, anchor, shift;
@@ -949,8 +948,9 @@
FT_Int i, j, k;
- l_in = 0;
- last = outline->contours[c];
+ first = last + 1;
+ last = outline->contours[c];
+ l_in = 0;
/* pacify compiler */
in.x = in.y = anchor.x = anchor.y = 0;
@@ -1037,8 +1037,6 @@
in = out;
l_in = l_out;
}
-
- first = last + 1;
}
return FT_Err_Ok;
@@ -1054,7 +1052,7 @@
FT_Int xshift, yshift;
FT_Vector* points;
FT_Vector v_prev, v_cur;
- FT_Int c, n, first;
+ FT_Int c, n, first, last;
FT_Pos area = 0;
@@ -1086,11 +1084,11 @@
points = outline->points;
- first = 0;
+ last = -1;
for ( c = 0; c < outline->n_contours; c++ )
{
- FT_Int last = outline->contours[c];
-
+ first = last + 1;
+ last = outline->contours[c];
v_prev.x = points[last].x >> xshift;
v_prev.y = points[last].y >> yshift;
@@ -1106,8 +1104,6 @@
v_prev = v_cur;
}
-
- first = last + 1;
}
if ( area > 0 )
diff --git a/src/3rdparty/freetype/src/base/ftstream.c b/src/3rdparty/freetype/src/base/ftstream.c
index 05c5637578..64826acebe 100644
--- a/src/3rdparty/freetype/src/base/ftstream.c
+++ b/src/3rdparty/freetype/src/base/ftstream.c
@@ -141,7 +141,9 @@
if ( read_bytes > count )
read_bytes = count;
- FT_MEM_COPY( buffer, stream->base + pos, read_bytes );
+ /* Allow "reading" zero bytes without UB even if buffer is NULL */
+ if ( count )
+ FT_MEM_COPY( buffer, stream->base + pos, read_bytes );
}
stream->pos = pos + read_bytes;
@@ -178,7 +180,9 @@
if ( read_bytes > count )
read_bytes = count;
- FT_MEM_COPY( buffer, stream->base + stream->pos, read_bytes );
+ /* Allow "reading" zero bytes without UB even if buffer is NULL */
+ if ( count )
+ FT_MEM_COPY( buffer, stream->base + stream->pos, read_bytes );
}
stream->pos += read_bytes;
diff --git a/src/3rdparty/freetype/src/base/ftstroke.c b/src/3rdparty/freetype/src/base/ftstroke.c
index db358e772e..92f1e43080 100644
--- a/src/3rdparty/freetype/src/base/ftstroke.c
+++ b/src/3rdparty/freetype/src/base/ftstroke.c
@@ -2055,7 +2055,9 @@
FT_Error error;
FT_Int n; /* index of contour in outline */
- FT_UInt first; /* index of first point in contour */
+ FT_Int first; /* index of first point in contour */
+ FT_Int last; /* index of last point in contour */
+
FT_Int tag; /* current point's state */
@@ -2067,22 +2069,17 @@
FT_Stroker_Rewind( stroker );
- first = 0;
-
+ last = -1;
for ( n = 0; n < outline->n_contours; n++ )
{
- FT_UInt last; /* index of last point in contour */
-
-
- last = (FT_UInt)outline->contours[n];
- limit = outline->points + last;
+ first = last + 1;
+ last = outline->contours[n];
/* skip empty points; we don't stroke these */
if ( last <= first )
- {
- first = last + 1;
continue;
- }
+
+ limit = outline->points + last;
v_start = outline->points[first];
v_last = outline->points[last];
@@ -2231,8 +2228,6 @@
if ( error )
goto Exit;
}
-
- first = last + 1;
}
return FT_Err_Ok;
diff --git a/src/3rdparty/freetype/src/base/ftsynth.c b/src/3rdparty/freetype/src/base/ftsynth.c
index 6ec25e13e4..f32edd3388 100644
--- a/src/3rdparty/freetype/src/base/ftsynth.c
+++ b/src/3rdparty/freetype/src/base/ftsynth.c
@@ -98,8 +98,17 @@
FT_EXPORT_DEF( void )
FT_GlyphSlot_Embolden( FT_GlyphSlot slot )
{
+ FT_GlyphSlot_AdjustWeight( slot, 0x0AAA, 0x0AAA );
+ }
+
+
+ FT_EXPORT_DEF( void )
+ FT_GlyphSlot_AdjustWeight( FT_GlyphSlot slot,
+ FT_Fixed xdelta,
+ FT_Fixed ydelta )
+ {
FT_Library library;
- FT_Face face;
+ FT_Size size;
FT_Error error;
FT_Pos xstr, ystr;
@@ -108,16 +117,15 @@
return;
library = slot->library;
- face = slot->face;
+ size = slot->face->size;
if ( slot->format != FT_GLYPH_FORMAT_OUTLINE &&
slot->format != FT_GLYPH_FORMAT_BITMAP )
return;
- /* some reasonable strength */
- xstr = FT_MulFix( face->units_per_EM,
- face->size->metrics.y_scale ) / 24;
- ystr = xstr;
+ /* express deltas in pixels in 26.6 format */
+ xstr = (FT_Pos)size->metrics.x_ppem * xdelta / 1024;
+ ystr = (FT_Pos)size->metrics.y_ppem * ydelta / 1024;
if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
FT_Outline_EmboldenXY( &slot->outline, xstr, ystr );
diff --git a/src/3rdparty/freetype/src/base/ftsystem.c b/src/3rdparty/freetype/src/base/ftsystem.c
index fcd289d19f..61c99e3635 100644
--- a/src/3rdparty/freetype/src/base/ftsystem.c
+++ b/src/3rdparty/freetype/src/base/ftsystem.c
@@ -206,7 +206,7 @@
* The number of bytes to read from the stream.
*
* @Return:
- * The number of bytes actually read. If `count' is zero (this is,
+ * The number of bytes actually read. If `count' is zero (that is,
* the function is used for seeking), a non-zero return value
* indicates an error.
*/
@@ -219,7 +219,7 @@
FT_FILE* file;
- if ( !count && offset > stream->size )
+ if ( offset > stream->size && !count )
return 1;
file = STREAM_FILE( stream );
@@ -227,6 +227,11 @@
if ( stream->pos != offset )
ft_fseek( file, (long)offset, SEEK_SET );
+ /* Avoid calling `fread` with `buffer=NULL` and `count=0`, */
+ /* which is undefined behaviour. */
+ if ( !count )
+ return 0;
+
return (unsigned long)ft_fread( buffer, 1, count, file );
}
diff --git a/src/3rdparty/freetype/src/base/ftver.rc b/src/3rdparty/freetype/src/base/ftver.rc
index f113cb892b..137a6334b7 100644
--- a/src/3rdparty/freetype/src/base/ftver.rc
+++ b/src/3rdparty/freetype/src/base/ftver.rc
@@ -18,8 +18,8 @@
#include<windows.h>
-#define FT_VERSION 2,13,0,0
-#define FT_VERSION_STR "2.13.0"
+#define FT_VERSION 2,13,2,0
+#define FT_VERSION_STR "2.13.2"
VS_VERSION_INFO VERSIONINFO
FILEVERSION FT_VERSION
diff --git a/src/3rdparty/freetype/src/bdf/bdf.h b/src/3rdparty/freetype/src/bdf/bdf.h
index 5acbd5f2f9..e2cb52c10a 100644
--- a/src/3rdparty/freetype/src/bdf/bdf.h
+++ b/src/3rdparty/freetype/src/bdf/bdf.h
@@ -240,10 +240,6 @@ FT_BEGIN_HEADER
bdf_free_font( bdf_font_t* font );
FT_LOCAL( bdf_property_t * )
- bdf_get_property( char* name,
- bdf_font_t* font );
-
- FT_LOCAL( bdf_property_t * )
bdf_get_font_property( bdf_font_t* font,
const char* name );
diff --git a/src/3rdparty/freetype/src/bdf/bdfdrivr.c b/src/3rdparty/freetype/src/bdf/bdfdrivr.c
index d7e8e0efc5..e02a160930 100644
--- a/src/3rdparty/freetype/src/bdf/bdfdrivr.c
+++ b/src/3rdparty/freetype/src/bdf/bdfdrivr.c
@@ -311,9 +311,9 @@ THE SOFTWARE.
FT_CALLBACK_DEF( void )
- BDF_Face_Done( FT_Face bdfface ) /* BDF_Face */
+ BDF_Face_Done( FT_Face face ) /* BDF_Face */
{
- BDF_Face face = (BDF_Face)bdfface;
+ BDF_Face bdfface = (BDF_Face)face;
FT_Memory memory;
@@ -322,31 +322,31 @@ THE SOFTWARE.
memory = FT_FACE_MEMORY( face );
- bdf_free_font( face->bdffont );
+ bdf_free_font( bdfface->bdffont );
- FT_FREE( face->en_table );
+ FT_FREE( bdfface->en_table );
- FT_FREE( face->charset_encoding );
- FT_FREE( face->charset_registry );
- FT_FREE( bdfface->family_name );
- FT_FREE( bdfface->style_name );
+ FT_FREE( bdfface->charset_encoding );
+ FT_FREE( bdfface->charset_registry );
+ FT_FREE( face->family_name );
+ FT_FREE( face->style_name );
- FT_FREE( bdfface->available_sizes );
+ FT_FREE( face->available_sizes );
- FT_FREE( face->bdffont );
+ FT_FREE( bdfface->bdffont );
}
FT_CALLBACK_DEF( FT_Error )
BDF_Face_Init( FT_Stream stream,
- FT_Face bdfface, /* BDF_Face */
+ FT_Face face, /* BDF_Face */
FT_Int face_index,
FT_Int num_params,
FT_Parameter* params )
{
- FT_Error error = FT_Err_Ok;
- BDF_Face face = (BDF_Face)bdfface;
- FT_Memory memory = FT_FACE_MEMORY( face );
+ FT_Error error = FT_Err_Ok;
+ BDF_Face bdfface = (BDF_Face)face;
+ FT_Memory memory = FT_FACE_MEMORY( face );
bdf_font_t* font = NULL;
bdf_options_t options;
@@ -375,7 +375,7 @@ THE SOFTWARE.
goto Exit;
/* we have a bdf font: let's construct the face object */
- face->bdffont = font;
+ bdfface->bdffont = font;
/* BDF cannot have multiple faces in a single font file.
* XXX: non-zero face_index is already invalid argument, but
@@ -386,7 +386,7 @@ THE SOFTWARE.
if ( face_index > 0 && ( face_index & 0xFFFF ) > 0 )
{
FT_ERROR(( "BDF_Face_Init: invalid face index\n" ));
- BDF_Face_Done( bdfface );
+ BDF_Face_Done( face );
return FT_THROW( Invalid_Argument );
}
@@ -401,18 +401,18 @@ THE SOFTWARE.
font->unencoded_size,
font->unencoded_used ));
- bdfface->num_faces = 1;
- bdfface->face_index = 0;
+ face->num_faces = 1;
+ face->face_index = 0;
- bdfface->face_flags |= FT_FACE_FLAG_FIXED_SIZES |
- FT_FACE_FLAG_HORIZONTAL;
+ face->face_flags |= FT_FACE_FLAG_FIXED_SIZES |
+ FT_FACE_FLAG_HORIZONTAL;
prop = bdf_get_font_property( font, "SPACING" );
if ( prop && prop->format == BDF_ATOM &&
prop->value.atom &&
( *(prop->value.atom) == 'M' || *(prop->value.atom) == 'm' ||
*(prop->value.atom) == 'C' || *(prop->value.atom) == 'c' ) )
- bdfface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+ face->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
/* FZ XXX: TO DO: FT_FACE_FLAGS_VERTICAL */
/* FZ XXX: I need a font to implement this */
@@ -420,26 +420,27 @@ THE SOFTWARE.
prop = bdf_get_font_property( font, "FAMILY_NAME" );
if ( prop && prop->value.atom )
{
- if ( FT_STRDUP( bdfface->family_name, prop->value.atom ) )
+ if ( FT_STRDUP( face->family_name, prop->value.atom ) )
goto Exit;
}
else
- bdfface->family_name = NULL;
+ face->family_name = NULL;
- if ( FT_SET_ERROR( bdf_interpret_style( face ) ) )
+ if ( FT_SET_ERROR( bdf_interpret_style( bdfface ) ) )
goto Exit;
/* the number of glyphs (with one slot for the undefined glyph */
/* at position 0 and all unencoded glyphs) */
- bdfface->num_glyphs = (FT_Long)( font->glyphs_size + 1 );
+ face->num_glyphs = (FT_Long)( font->glyphs_size + 1 );
- bdfface->num_fixed_sizes = 1;
- if ( FT_NEW( bdfface->available_sizes ) )
+ face->num_fixed_sizes = 1;
+ if ( FT_NEW( face->available_sizes ) )
goto Exit;
{
- FT_Bitmap_Size* bsize = bdfface->available_sizes;
- FT_Short resolution_x = 0, resolution_y = 0;
+ FT_Bitmap_Size* bsize = face->available_sizes;
+ FT_Short resolution_x = 0;
+ FT_Short resolution_y = 0;
long value;
@@ -598,20 +599,20 @@ THE SOFTWARE.
unsigned long n;
- if ( FT_QNEW_ARRAY( face->en_table, font->glyphs_size ) )
+ if ( FT_QNEW_ARRAY( bdfface->en_table, font->glyphs_size ) )
goto Exit;
- face->default_glyph = 0;
+ bdfface->default_glyph = 0;
for ( n = 0; n < font->glyphs_size; n++ )
{
- (face->en_table[n]).enc = cur[n].encoding;
+ (bdfface->en_table[n]).enc = cur[n].encoding;
FT_TRACE4(( " idx %ld, val 0x%lX\n", n, cur[n].encoding ));
- (face->en_table[n]).glyph = (FT_UShort)n;
+ (bdfface->en_table[n]).glyph = (FT_UShort)n;
if ( cur[n].encoding == font->default_char )
{
if ( n < FT_UINT_MAX )
- face->default_glyph = (FT_UInt)n;
+ bdfface->default_glyph = (FT_UInt)n;
else
FT_TRACE1(( "BDF_Face_Init:"
" idx %ld is too large for this system\n", n ));
@@ -639,27 +640,27 @@ THE SOFTWARE.
const char* s;
- if ( FT_STRDUP( face->charset_encoding,
+ if ( FT_STRDUP( bdfface->charset_encoding,
charset_encoding->value.atom ) ||
- FT_STRDUP( face->charset_registry,
+ FT_STRDUP( bdfface->charset_registry,
charset_registry->value.atom ) )
goto Exit;
/* Uh, oh, compare first letters manually to avoid dependency */
/* on locales. */
- s = face->charset_registry;
+ s = bdfface->charset_registry;
if ( ( s[0] == 'i' || s[0] == 'I' ) &&
( s[1] == 's' || s[1] == 'S' ) &&
( s[2] == 'o' || s[2] == 'O' ) )
{
s += 3;
- if ( !ft_strcmp( s, "10646" ) ||
- ( !ft_strcmp( s, "8859" ) &&
- !ft_strcmp( face->charset_encoding, "1" ) ) )
+ if ( !ft_strcmp( s, "10646" ) ||
+ ( !ft_strcmp( s, "8859" ) &&
+ !ft_strcmp( bdfface->charset_encoding, "1" ) ) )
unicode_charmap = 1;
/* another name for ASCII */
- else if ( !ft_strcmp( s, "646.1991" ) &&
- !ft_strcmp( face->charset_encoding, "IRV" ) )
+ else if ( !ft_strcmp( s, "646.1991" ) &&
+ !ft_strcmp( bdfface->charset_encoding, "IRV" ) )
unicode_charmap = 1;
}
@@ -667,7 +668,7 @@ THE SOFTWARE.
FT_CharMapRec charmap;
- charmap.face = FT_FACE( face );
+ charmap.face = face;
charmap.encoding = FT_ENCODING_NONE;
/* initial platform/encoding should indicate unset status? */
charmap.platform_id = TT_PLATFORM_APPLE_UNICODE;
@@ -693,7 +694,7 @@ THE SOFTWARE.
FT_CharMapRec charmap;
- charmap.face = FT_FACE( face );
+ charmap.face = face;
charmap.encoding = FT_ENCODING_ADOBE_STANDARD;
charmap.platform_id = TT_PLATFORM_ADOBE;
charmap.encoding_id = TT_ADOBE_ID_STANDARD;
@@ -701,8 +702,8 @@ THE SOFTWARE.
error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL );
/* Select default charmap */
- if ( bdfface->num_charmaps )
- bdfface->charmap = bdfface->charmaps[0];
+ if ( face->num_charmaps )
+ face->charmap = face->charmaps[0];
}
}
}
@@ -711,7 +712,7 @@ THE SOFTWARE.
return error;
Fail:
- BDF_Face_Done( bdfface );
+ BDF_Face_Done( face );
return FT_THROW( Unknown_File_Format );
}
@@ -868,17 +869,18 @@ THE SOFTWARE.
*
*/
- static FT_Error
- bdf_get_bdf_property( BDF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ bdf_get_bdf_property( FT_Face face, /* BDF_Face */
const char* prop_name,
BDF_PropertyRec *aproperty )
{
+ BDF_Face bdfface = (BDF_Face)face;
bdf_property_t* prop;
- FT_ASSERT( face && face->bdffont );
+ FT_ASSERT( bdfface && bdfface->bdffont );
- prop = bdf_get_font_property( face->bdffont, prop_name );
+ prop = bdf_get_font_property( bdfface->bdffont, prop_name );
if ( prop )
{
switch ( prop->format )
@@ -921,13 +923,16 @@ THE SOFTWARE.
}
- static FT_Error
- bdf_get_charset_id( BDF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ bdf_get_charset_id( FT_Face face, /* BDF_Face */
const char* *acharset_encoding,
const char* *acharset_registry )
{
- *acharset_encoding = face->charset_encoding;
- *acharset_registry = face->charset_registry;
+ BDF_Face bdfface = (BDF_Face)face;
+
+
+ *acharset_encoding = bdfface->charset_encoding;
+ *acharset_registry = bdfface->charset_registry;
return 0;
}
@@ -964,7 +969,6 @@ THE SOFTWARE.
}
-
FT_CALLBACK_TABLE_DEF
const FT_Driver_ClassRec bdf_driver_class =
{
diff --git a/src/3rdparty/freetype/src/bdf/bdflib.c b/src/3rdparty/freetype/src/bdf/bdflib.c
index 2224698fc0..0fa7e0a8c5 100644
--- a/src/3rdparty/freetype/src/bdf/bdflib.c
+++ b/src/3rdparty/freetype/src/bdf/bdflib.c
@@ -51,6 +51,9 @@
#define FT_COMPONENT bdflib
+#define BUFSIZE 128
+
+
/**************************************************************************
*
* Default BDF font options.
@@ -378,7 +381,7 @@
*alen = 0;
if ( list == NULL || list->used == 0 )
- return 0;
+ return NULL;
dp = list->field[0];
for ( i = j = 0; i < list->used; i++ )
@@ -887,18 +890,18 @@
}
- FT_LOCAL_DEF( bdf_property_t* )
- bdf_get_property( char* name,
+ static bdf_property_t*
+ bdf_get_property( const char* name,
bdf_font_t* font )
{
size_t* propid;
if ( name == NULL || *name == 0 )
- return 0;
+ return NULL;
if ( ( propid = ft_hash_str_lookup( name, &(font->proptbl) ) ) == NULL )
- return 0;
+ return NULL;
if ( *propid >= num_bdf_properties_ )
return font->user_props + ( *propid - num_bdf_properties_ );
@@ -944,7 +947,7 @@
static FT_Error
bdf_add_comment_( bdf_font_t* font,
- char* comment,
+ const char* comment,
unsigned long len )
{
char* cp;
@@ -1053,27 +1056,24 @@
bdf_property_t* p;
- *name = sp = ep = line;
+ sp = ep = line;
while ( *ep && *ep != ' ' && *ep != '\t' )
ep++;
- hold = -1;
- if ( *ep )
- {
- hold = *ep;
- *ep = 0;
- }
+ hold = *ep;
+ *ep = '\0';
p = bdf_get_property( sp, font );
- /* Restore the character that was saved before any return can happen. */
- if ( hold != -1 )
- *ep = (char)hold;
-
/* If the property exists and is not an atom, just return here. */
if ( p && p->format != BDF_ATOM )
+ {
+ *ep = (char)hold; /* Undo NUL-termination. */
return 0;
+ }
+
+ *name = sp;
/* The property is an atom. Trim all leading and trailing whitespace */
/* and double quotes for the atom value. */
@@ -1081,25 +1081,26 @@
ep = line + linelen;
/* Trim the leading whitespace if it exists. */
- if ( *sp )
- *sp++ = 0;
- while ( *sp &&
- ( *sp == ' ' || *sp == '\t' ) )
- sp++;
+ if ( sp < ep )
+ do
+ sp++;
+ while ( *sp == ' ' || *sp == '\t' );
/* Trim the leading double quote if it exists. */
if ( *sp == '"' )
sp++;
+
*value = sp;
/* Trim the trailing whitespace if it exists. */
- while ( ep > sp &&
- ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
- *--ep = 0;
+ if ( sp < ep )
+ do
+ *ep-- = '\0';
+ while ( *ep == ' ' || *ep == '\t' );
/* Trim the trailing double quote if it exists. */
- if ( ep > sp && *( ep - 1 ) == '"' )
- *--ep = 0;
+ if ( *ep == '"' )
+ *ep = '\0';
return 1;
}
@@ -1775,7 +1776,7 @@
bdf_parse_t_* p;
char* name;
char* value;
- char nbuf[128];
+ char nbuf[BUFSIZE];
FT_Error error = FT_Err_Ok;
FT_UNUSED( lineno );
@@ -1796,7 +1797,7 @@
if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
{
p->font->font_ascent = p->font->bbx.ascent;
- ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
+ ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.ascent );
error = bdf_add_property_( p->font, "FONT_ASCENT",
nbuf, lineno );
if ( error )
@@ -1808,7 +1809,7 @@
if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
{
p->font->font_descent = p->font->bbx.descent;
- ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
+ ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.descent );
error = bdf_add_property_( p->font, "FONT_DESCENT",
nbuf, lineno );
if ( error )
@@ -2116,7 +2117,7 @@
/* Check for the CHARS field -- font properties are optional */
if ( _bdf_strncmp( line, "CHARS", 5 ) == 0 )
{
- char nbuf[128];
+ char nbuf[BUFSIZE];
if ( !( p->flags & BDF_FONT_BBX_ ) )
@@ -2130,7 +2131,7 @@
/* Add the two standard X11 properties which are required */
/* for compiling fonts. */
p->font->font_ascent = p->font->bbx.ascent;
- ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
+ ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.ascent );
error = bdf_add_property_( p->font, "FONT_ASCENT",
nbuf, lineno );
if ( error )
@@ -2138,7 +2139,7 @@
FT_TRACE2(( "bdf_parse_properties_: " ACMSG1, p->font->bbx.ascent ));
p->font->font_descent = p->font->bbx.descent;
- ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
+ ft_snprintf( nbuf, BUFSIZE, "%hd", p->font->bbx.descent );
error = bdf_add_property_( p->font, "FONT_DESCENT",
nbuf, lineno );
if ( error )
diff --git a/src/3rdparty/freetype/src/bzip2/ftbzip2.c b/src/3rdparty/freetype/src/bzip2/ftbzip2.c
index 6cf10678b7..ad342bd011 100644
--- a/src/3rdparty/freetype/src/bzip2/ftbzip2.c
+++ b/src/3rdparty/freetype/src/bzip2/ftbzip2.c
@@ -62,10 +62,12 @@
static void*
- ft_bzip2_alloc( FT_Memory memory,
- int items,
- int size )
+ ft_bzip2_alloc( void* memory_, /* FT_Memory */
+ int items,
+ int size )
{
+ FT_Memory memory = (FT_Memory)memory_;
+
FT_ULong sz = (FT_ULong)size * (FT_ULong)items;
FT_Error error;
FT_Pointer p = NULL;
@@ -77,9 +79,12 @@
static void
- ft_bzip2_free( FT_Memory memory,
- void* address )
+ ft_bzip2_free( void* memory_, /* FT_Memory */
+ void* address )
{
+ FT_Memory memory = (FT_Memory)memory_;
+
+
FT_MEM_FREE( address );
}
@@ -170,8 +175,8 @@
}
/* initialize bzlib */
- bzstream->bzalloc = (alloc_func)ft_bzip2_alloc;
- bzstream->bzfree = (free_func) ft_bzip2_free;
+ bzstream->bzalloc = ft_bzip2_alloc;
+ bzstream->bzfree = ft_bzip2_free;
bzstream->opaque = zip->memory;
bzstream->avail_in = 0;
diff --git a/src/3rdparty/freetype/src/cache/ftcbasic.c b/src/3rdparty/freetype/src/cache/ftcbasic.c
index 4c6d41b2cd..24a56c8d26 100644
--- a/src/3rdparty/freetype/src/cache/ftcbasic.c
+++ b/src/3rdparty/freetype/src/cache/ftcbasic.c
@@ -337,7 +337,7 @@
#if 1 /* inlining is about 50% faster! */
FTC_GCACHE_LOOKUP_CMP( cache,
ftc_basic_family_compare,
- FTC_GNode_Compare,
+ ftc_gnode_compare,
hash, gindex,
&query,
node,
@@ -411,7 +411,7 @@
FTC_GCACHE_LOOKUP_CMP( cache,
ftc_basic_family_compare,
- FTC_GNode_Compare,
+ ftc_gnode_compare,
hash, gindex,
&query,
node,
@@ -537,7 +537,7 @@
#if 1 /* inlining is about 50% faster! */
FTC_GCACHE_LOOKUP_CMP( cache,
ftc_basic_family_compare,
- FTC_SNode_Compare,
+ ftc_snode_compare,
hash, gindex,
&query,
node,
@@ -613,7 +613,7 @@
FTC_GCACHE_LOOKUP_CMP( cache,
ftc_basic_family_compare,
- FTC_SNode_Compare,
+ ftc_snode_compare,
hash, gindex,
&query,
node,
diff --git a/src/3rdparty/freetype/src/cache/ftccache.c b/src/3rdparty/freetype/src/cache/ftccache.c
index d54e68ca9a..e0698557b7 100644
--- a/src/3rdparty/freetype/src/cache/ftccache.c
+++ b/src/3rdparty/freetype/src/cache/ftccache.c
@@ -94,8 +94,8 @@
idx = hash & cache->mask;
- if ( idx < cache->p )
- idx = hash & ( 2 * cache->mask + 1 );
+ if ( idx >= cache->p )
+ idx = hash & ( cache->mask >> 1 );
return cache->buckets + idx;
}
@@ -113,9 +113,9 @@
for (;;)
{
FTC_Node node, *pnode;
- FT_UFast p = cache->p;
- FT_UFast mask = cache->mask;
- FT_UFast count = mask + p + 1; /* number of buckets */
+ FT_UFast p = cache->p;
+ FT_UFast size = cache->mask + 1; /* available size */
+ FT_UFast half = size >> 1;
/* do we need to expand the buckets array? */
@@ -127,20 +127,22 @@
/* try to expand the buckets array _before_ splitting
* the bucket lists
*/
- if ( p >= mask )
+ if ( p == size )
{
FT_Memory memory = cache->memory;
FT_Error error;
/* if we can't expand the array, leave immediately */
- if ( FT_RENEW_ARRAY( cache->buckets,
- ( mask + 1 ) * 2, ( mask + 1 ) * 4 ) )
+ if ( FT_QRENEW_ARRAY( cache->buckets, size, size * 2 ) )
break;
+
+ cache->mask = 2 * size - 1;
+ half = size;
}
- /* split a single bucket */
- pnode = cache->buckets + p;
+ /* the bucket to split */
+ pnode = cache->buckets + p - half;
for (;;)
{
@@ -148,7 +150,7 @@
if ( !node )
break;
- if ( node->hash & ( mask + 1 ) )
+ if ( node->hash & half )
{
*pnode = node->link;
node->link = new_list;
@@ -158,56 +160,50 @@
pnode = &node->link;
}
- cache->buckets[p + mask + 1] = new_list;
+ cache->buckets[p] = new_list;
cache->slack += FTC_HASH_MAX_LOAD;
+ cache->p = p + 1;
- if ( p >= mask )
- {
- cache->mask = 2 * mask + 1;
- cache->p = 0;
- }
- else
- cache->p = p + 1;
+ FT_TRACE2(( "ftc_cache_resize: cache %u increased to %u hashes\n",
+ cache->index, cache->p ));
}
/* do we need to shrink the buckets array? */
- else if ( cache->slack > (FT_Long)count * FTC_HASH_SUB_LOAD )
+ else if ( cache->slack > (FT_Long)p * FTC_HASH_SUB_LOAD )
{
- FT_UFast old_index = p + mask;
- FTC_Node* pold;
+ FTC_Node old_list = cache->buckets[--p];
- if ( old_index + 1 <= FTC_HASH_INITIAL_SIZE )
+ if ( p < FTC_HASH_INITIAL_SIZE )
break;
- if ( p == 0 )
+ if ( p == half )
{
FT_Memory memory = cache->memory;
FT_Error error;
/* if we can't shrink the array, leave immediately */
- if ( FT_QRENEW_ARRAY( cache->buckets,
- ( mask + 1 ) * 2, mask + 1 ) )
+ if ( FT_QRENEW_ARRAY( cache->buckets, size, half ) )
break;
- cache->mask >>= 1;
- p = cache->mask;
+ cache->mask = half - 1;
}
- else
- p--;
- pnode = cache->buckets + p;
+ /* the bucket to merge */
+ pnode = cache->buckets + p - half;
+
while ( *pnode )
pnode = &(*pnode)->link;
- pold = cache->buckets + old_index;
- *pnode = *pold;
- *pold = NULL;
+ *pnode = old_list;
cache->slack -= FTC_HASH_MAX_LOAD;
cache->p = p;
+
+ FT_TRACE2(( "ftc_cache_resize: cache %u decreased to %u hashes\n",
+ cache->index, cache->p ));
}
/* otherwise, the hash table is balanced */
@@ -239,7 +235,7 @@
if ( node == node0 )
break;
- pnode = &(*pnode)->link;
+ pnode = &node->link;
}
*pnode = node0->link;
@@ -323,40 +319,41 @@
FT_LOCAL_DEF( FT_Error )
- FTC_Cache_Init( FTC_Cache cache )
- {
- return ftc_cache_init( cache );
- }
-
-
- FT_LOCAL_DEF( FT_Error )
ftc_cache_init( FTC_Cache cache )
{
FT_Memory memory = cache->memory;
FT_Error error;
- cache->p = 0;
+ cache->p = FTC_HASH_INITIAL_SIZE;
cache->mask = FTC_HASH_INITIAL_SIZE - 1;
cache->slack = FTC_HASH_INITIAL_SIZE * FTC_HASH_MAX_LOAD;
- FT_MEM_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE * 2 );
+ FT_MEM_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE );
return error;
}
- static void
- FTC_Cache_Clear( FTC_Cache cache )
+ FT_LOCAL_DEF( FT_Error )
+ FTC_Cache_Init( FTC_Cache cache )
{
- if ( cache && cache->buckets )
+ return ftc_cache_init( cache );
+ }
+
+
+ FT_LOCAL_DEF( void )
+ ftc_cache_done( FTC_Cache cache )
+ {
+ FT_Memory memory = cache->memory;
+
+
+ if ( cache->buckets )
{
FTC_Manager manager = cache->manager;
+ FT_UFast count = cache->p;
FT_UFast i;
- FT_UFast count;
- count = cache->p + cache->mask + 1;
-
for ( i = 0; i < count; i++ )
{
FTC_Node node = cache->buckets[i], next;
@@ -376,30 +373,14 @@
cache->clazz.node_free( node, cache );
node = next;
}
- cache->buckets[i] = NULL;
}
- ftc_cache_resize( cache );
}
- }
+ FT_FREE( cache->buckets );
- FT_LOCAL_DEF( void )
- ftc_cache_done( FTC_Cache cache )
- {
- if ( cache->memory )
- {
- FT_Memory memory = cache->memory;
-
-
- FTC_Cache_Clear( cache );
-
- FT_FREE( cache->buckets );
- cache->mask = 0;
- cache->p = 0;
- cache->slack = 0;
-
- cache->memory = NULL;
- }
+ cache->p = 0;
+ cache->mask = 0;
+ cache->slack = 0;
}
@@ -562,12 +543,12 @@
FTC_Cache_RemoveFaceID( FTC_Cache cache,
FTC_FaceID face_id )
{
- FT_UFast i, count;
FTC_Manager manager = cache->manager;
FTC_Node frees = NULL;
+ FT_UFast count = cache->p;
+ FT_UFast i;
- count = cache->p + cache->mask + 1;
for ( i = 0; i < count; i++ )
{
FTC_Node* pnode = cache->buckets + i;
diff --git a/src/3rdparty/freetype/src/cache/ftccache.h b/src/3rdparty/freetype/src/cache/ftccache.h
index 23bcb65858..850d2554b5 100644
--- a/src/3rdparty/freetype/src/cache/ftccache.h
+++ b/src/3rdparty/freetype/src/cache/ftccache.h
@@ -72,11 +72,12 @@ FT_BEGIN_HEADER
#define FTC_NODE_NEXT( x ) FTC_NODE( (x)->mru.next )
#define FTC_NODE_PREV( x ) FTC_NODE( (x)->mru.prev )
+ /* address the hash table entries */
#ifdef FTC_INLINE
-#define FTC_NODE_TOP_FOR_HASH( cache, hash ) \
- ( ( cache )->buckets + \
- ( ( ( ( hash ) & ( cache )->mask ) < ( cache )->p ) \
- ? ( ( hash ) & ( ( cache )->mask * 2 + 1 ) ) \
+#define FTC_NODE_TOP_FOR_HASH( cache, hash ) \
+ ( ( cache )->buckets + \
+ ( ( ( ( hash ) & ( cache )->mask ) >= ( cache )->p ) \
+ ? ( ( hash ) & ( ( cache )->mask >> 1 ) ) \
: ( ( hash ) & ( cache )->mask ) ) )
#else
FT_LOCAL( FTC_Node* )
@@ -139,11 +140,13 @@ FT_BEGIN_HEADER
} FTC_CacheClassRec;
- /* each cache really implements a dynamic hash table to manage its nodes */
+ /* each cache really implements a hash table to manage its nodes */
+ /* the number of the table entries (buckets) can change dynamically */
+ /* each bucket contains a linked lists of nodes for a given hash */
typedef struct FTC_CacheRec_
{
- FT_UFast p;
- FT_UFast mask;
+ FT_UFast p; /* hash table counter */
+ FT_UFast mask; /* hash table index range */
FT_Long slack;
FTC_Node* buckets;
diff --git a/src/3rdparty/freetype/src/cache/ftcglyph.c b/src/3rdparty/freetype/src/cache/ftcglyph.c
index b3fb2f219c..d344733f37 100644
--- a/src/3rdparty/freetype/src/cache/ftcglyph.c
+++ b/src/3rdparty/freetype/src/cache/ftcglyph.c
@@ -79,20 +79,6 @@
}
-#ifdef FTC_INLINE
-
- FT_LOCAL_DEF( FT_Bool )
- FTC_GNode_Compare( FTC_GNode gnode,
- FTC_GQuery gquery,
- FTC_Cache cache,
- FT_Bool* list_changed )
- {
- return ftc_gnode_compare( FTC_NODE( gnode ), gquery,
- cache, list_changed );
- }
-
-#endif
-
/*************************************************************************/
/*************************************************************************/
/***** *****/
@@ -115,22 +101,22 @@
FT_LOCAL_DEF( FT_Error )
- ftc_gcache_init( FTC_Cache ftccache )
+ ftc_gcache_init( FTC_Cache cache )
{
- FTC_GCache cache = (FTC_GCache)ftccache;
+ FTC_GCache gcache = (FTC_GCache)cache;
FT_Error error;
- error = FTC_Cache_Init( FTC_CACHE( cache ) );
+ error = FTC_Cache_Init( cache );
if ( !error )
{
- FTC_GCacheClass clazz = (FTC_GCacheClass)FTC_CACHE( cache )->org_class;
+ FTC_GCacheClass clazz = (FTC_GCacheClass)cache->org_class;
- FTC_MruList_Init( &cache->families,
+ FTC_MruList_Init( &gcache->families,
clazz->family_class,
0, /* no maximum here! */
cache,
- FTC_CACHE( cache )->memory );
+ cache->memory );
}
return error;
@@ -140,31 +126,31 @@
#if 0
FT_LOCAL_DEF( FT_Error )
- FTC_GCache_Init( FTC_GCache cache )
+ FTC_GCache_Init( FTC_GCache gcache )
{
- return ftc_gcache_init( FTC_CACHE( cache ) );
+ return ftc_gcache_init( FTC_CACHE( gcache ) );
}
#endif /* 0 */
FT_LOCAL_DEF( void )
- ftc_gcache_done( FTC_Cache ftccache )
+ ftc_gcache_done( FTC_Cache cache )
{
- FTC_GCache cache = (FTC_GCache)ftccache;
+ FTC_GCache gcache = (FTC_GCache)cache;
- FTC_Cache_Done( (FTC_Cache)cache );
- FTC_MruList_Done( &cache->families );
+ FTC_Cache_Done( cache );
+ FTC_MruList_Done( &gcache->families );
}
#if 0
FT_LOCAL_DEF( void )
- FTC_GCache_Done( FTC_GCache cache )
+ FTC_GCache_Done( FTC_GCache gcache )
{
- ftc_gcache_done( FTC_CACHE( cache ) );
+ ftc_gcache_done( FTC_CACHE( gcache ) );
}
#endif /* 0 */
@@ -183,7 +169,7 @@
#ifndef FTC_INLINE
FT_LOCAL_DEF( FT_Error )
- FTC_GCache_Lookup( FTC_GCache cache,
+ FTC_GCache_Lookup( FTC_GCache gcache,
FT_Offset hash,
FT_UInt gindex,
FTC_GQuery query,
@@ -204,7 +190,7 @@
/* out-of-memory condition occurs during glyph node initialization. */
family->num_nodes++;
- error = FTC_Cache_Lookup( FTC_CACHE( cache ), hash, query, anode );
+ error = FTC_Cache_Lookup( FTC_CACHE( gcache ), hash, query, anode );
if ( --family->num_nodes == 0 )
FTC_FAMILY_FREE( family, cache );
diff --git a/src/3rdparty/freetype/src/cache/ftcglyph.h b/src/3rdparty/freetype/src/cache/ftcglyph.h
index 728d4db1d6..0181e98166 100644
--- a/src/3rdparty/freetype/src/cache/ftcglyph.h
+++ b/src/3rdparty/freetype/src/cache/ftcglyph.h
@@ -58,7 +58,7 @@
* - FTC_GNode sub-class, e.g. MyNode, with relevant methods:
* my_node_new (must call FTC_GNode_Init)
* my_node_free (must call FTC_GNode_Done)
- * my_node_compare (must call FTC_GNode_Compare)
+ * my_node_compare (must call ftc_gnode_compare)
* my_node_remove_faceid (must call ftc_gnode_unselect in case
* of match)
*
@@ -179,19 +179,6 @@ FT_BEGIN_HEADER
FT_UInt gindex, /* glyph index for node */
FTC_Family family );
-#ifdef FTC_INLINE
-
- /* returns TRUE iff the query's glyph index correspond to the node; */
- /* this assumes that the `family' and `hash' fields of the query are */
- /* already correctly set */
- FT_LOCAL( FT_Bool )
- FTC_GNode_Compare( FTC_GNode gnode,
- FTC_GQuery gquery,
- FTC_Cache cache,
- FT_Bool* list_changed );
-
-#endif
-
/* call this function to clear a node's family -- this is necessary */
/* to implement the `node_remove_faceid' cache method correctly */
FT_LOCAL( void )
diff --git a/src/3rdparty/freetype/src/cache/ftcmanag.c b/src/3rdparty/freetype/src/cache/ftcmanag.c
index 6c84339100..94f8469c92 100644
--- a/src/3rdparty/freetype/src/cache/ftcmanag.c
+++ b/src/3rdparty/freetype/src/cache/ftcmanag.c
@@ -426,7 +426,7 @@
memory = manager->memory;
/* now discard all caches */
- for (idx = manager->num_caches; idx-- > 0; )
+ for ( idx = manager->num_caches; idx-- > 0; )
{
FTC_Cache cache = manager->caches[idx];
@@ -537,7 +537,7 @@
FT_LOCAL_DEF( void )
FTC_Manager_Compress( FTC_Manager manager )
{
- FTC_Node node, first;
+ FTC_Node node, prev, first;
if ( !manager )
@@ -557,20 +557,16 @@
return;
/* go to last node -- it's a circular list */
- node = FTC_NODE_PREV( first );
+ prev = FTC_NODE_PREV( first );
do
{
- FTC_Node prev;
-
-
- prev = ( node == first ) ? NULL : FTC_NODE_PREV( node );
+ node = prev;
+ prev = FTC_NODE_PREV( node );
if ( node->ref_count <= 0 )
ftc_node_destroy( node, manager );
- node = prev;
-
- } while ( node && manager->cur_weight > manager->max_weight );
+ } while ( node != first && manager->cur_weight > manager->max_weight );
}
@@ -633,20 +629,20 @@
FT_UInt count )
{
FTC_Node first = manager->nodes_list;
- FTC_Node node;
- FT_UInt result;
+ FTC_Node prev, node;
+ FT_UInt result = 0;
/* try to remove `count' nodes from the list */
- if ( !first ) /* empty list! */
- return 0;
+ if ( !first || !count )
+ return result;
- /* go to last node - it's a circular list */
- node = FTC_NODE_PREV(first);
- for ( result = 0; result < count; )
+ /* go to last node -- it's a circular list */
+ prev = FTC_NODE_PREV( first );
+ do
{
- FTC_Node prev = FTC_NODE_PREV( node );
-
+ node = prev;
+ prev = FTC_NODE_PREV( node );
/* don't touch locked nodes */
if ( node->ref_count <= 0 )
@@ -654,13 +650,9 @@
ftc_node_destroy( node, manager );
result++;
}
+ } while ( node != first && result < count );
- if ( node == first )
- break;
-
- node = prev;
- }
- return result;
+ return result;
}
diff --git a/src/3rdparty/freetype/src/cache/ftcmru.c b/src/3rdparty/freetype/src/cache/ftcmru.c
index 67227033e7..ad10a06bc4 100644
--- a/src/3rdparty/freetype/src/cache/ftcmru.c
+++ b/src/3rdparty/freetype/src/cache/ftcmru.c
@@ -329,29 +329,23 @@
FTC_MruNode_CompareFunc selection,
FT_Pointer key )
{
- FTC_MruNode first, node, next;
+ FTC_MruNode first = list->nodes;
+ FTC_MruNode prev, node;
- first = list->nodes;
- while ( first && ( !selection || selection( first, key ) ) )
- {
- FTC_MruList_Remove( list, first );
- first = list->nodes;
- }
+ if ( !first || !selection )
+ return;
- if ( first )
+ prev = first->prev;
+ do
{
- node = first->next;
- while ( node != first )
- {
- next = node->next;
+ node = prev;
+ prev = node->prev;
- if ( selection( node, key ) )
- FTC_MruList_Remove( list, node );
+ if ( selection( node, key ) )
+ FTC_MruList_Remove( list, node );
- node = next;
- }
- }
+ } while ( node != first );
}
diff --git a/src/3rdparty/freetype/src/cache/ftcsbits.c b/src/3rdparty/freetype/src/cache/ftcsbits.c
index ee9dab2632..9929a0bcc3 100644
--- a/src/3rdparty/freetype/src/cache/ftcsbits.c
+++ b/src/3rdparty/freetype/src/cache/ftcsbits.c
@@ -342,7 +342,7 @@
FT_Bool result;
- if (list_changed)
+ if ( list_changed )
*list_changed = FALSE;
result = FT_BOOL( gnode->family == gquery->family &&
gindex - gnode->gindex < snode->count );
@@ -411,19 +411,4 @@
return result;
}
-
-#ifdef FTC_INLINE
-
- FT_LOCAL_DEF( FT_Bool )
- FTC_SNode_Compare( FTC_SNode snode,
- FTC_GQuery gquery,
- FTC_Cache cache,
- FT_Bool* list_changed )
- {
- return ftc_snode_compare( FTC_NODE( snode ), gquery,
- cache, list_changed );
- }
-
-#endif
-
/* END */
diff --git a/src/3rdparty/freetype/src/cache/ftcsbits.h b/src/3rdparty/freetype/src/cache/ftcsbits.h
index 3473923f03..e833cb5c30 100644
--- a/src/3rdparty/freetype/src/cache/ftcsbits.h
+++ b/src/3rdparty/freetype/src/cache/ftcsbits.h
@@ -81,17 +81,6 @@ FT_BEGIN_HEADER
FTC_SNode_Weight( FTC_SNode inode );
#endif
-
-#ifdef FTC_INLINE
-
- FT_LOCAL( FT_Bool )
- FTC_SNode_Compare( FTC_SNode snode,
- FTC_GQuery gquery,
- FTC_Cache cache,
- FT_Bool* list_changed);
-
-#endif
-
/* */
FT_END_HEADER
diff --git a/src/3rdparty/freetype/src/cff/cffcmap.c b/src/3rdparty/freetype/src/cff/cffcmap.c
index 6ed3143222..10d287bc81 100644
--- a/src/3rdparty/freetype/src/cff/cffcmap.c
+++ b/src/3rdparty/freetype/src/cff/cffcmap.c
@@ -32,9 +32,10 @@
/*************************************************************************/
FT_CALLBACK_DEF( FT_Error )
- cff_cmap_encoding_init( CFF_CMapStd cmap,
- FT_Pointer pointer )
+ cff_cmap_encoding_init( FT_CMap cmap,
+ FT_Pointer pointer )
{
+ CFF_CMapStd cffcmap = (CFF_CMapStd)cmap;
TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
CFF_Font cff = (CFF_Font)face->extra.data;
CFF_Encoding encoding = &cff->encoding;
@@ -42,63 +43,56 @@
FT_UNUSED( pointer );
- cmap->gids = encoding->codes;
+ cffcmap->gids = encoding->codes;
return 0;
}
FT_CALLBACK_DEF( void )
- cff_cmap_encoding_done( CFF_CMapStd cmap )
+ cff_cmap_encoding_done( FT_CMap cmap )
{
- cmap->gids = NULL;
+ CFF_CMapStd cffcmap = (CFF_CMapStd)cmap;
+
+
+ cffcmap->gids = NULL;
}
FT_CALLBACK_DEF( FT_UInt )
- cff_cmap_encoding_char_index( CFF_CMapStd cmap,
- FT_UInt32 char_code )
+ cff_cmap_encoding_char_index( FT_CMap cmap,
+ FT_UInt32 char_code )
{
- FT_UInt result = 0;
+ CFF_CMapStd cffcmap = (CFF_CMapStd)cmap;
+ FT_UInt result = 0;
if ( char_code < 256 )
- result = cmap->gids[char_code];
+ result = cffcmap->gids[char_code];
return result;
}
- FT_CALLBACK_DEF( FT_UInt32 )
- cff_cmap_encoding_char_next( CFF_CMapStd cmap,
- FT_UInt32 *pchar_code )
+ FT_CALLBACK_DEF( FT_UInt )
+ cff_cmap_encoding_char_next( FT_CMap cmap,
+ FT_UInt32 *pchar_code )
{
- FT_UInt result = 0;
- FT_UInt32 char_code = *pchar_code;
+ CFF_CMapStd cffcmap = (CFF_CMapStd)cmap;
+ FT_UInt result = 0;
+ FT_UInt32 char_code = *pchar_code;
- *pchar_code = 0;
-
- if ( char_code < 255 )
+ while ( char_code < 255 )
{
- FT_UInt code = (FT_UInt)( char_code + 1 );
-
-
- for (;;)
+ result = cffcmap->gids[++char_code];
+ if ( result )
{
- if ( code >= 256 )
- break;
-
- result = cmap->gids[code];
- if ( result != 0 )
- {
- *pchar_code = code;
- break;
- }
-
- code++;
+ *pchar_code = char_code;
+ break;
}
}
+
return result;
}
@@ -130,9 +124,10 @@
/*************************************************************************/
FT_CALLBACK_DEF( const char* )
- cff_sid_to_glyph_name( TT_Face face,
+ cff_sid_to_glyph_name( void* face_, /* TT_Face */
FT_UInt idx )
{
+ TT_Face face = (TT_Face)face_;
CFF_Font cff = (CFF_Font)face->extra.data;
CFF_Charset charset = &cff->charset;
FT_UInt sid = charset->sids[idx];
@@ -143,14 +138,15 @@
FT_CALLBACK_DEF( FT_Error )
- cff_cmap_unicode_init( PS_Unicodes unicodes,
+ cff_cmap_unicode_init( FT_CMap cmap, /* PS_Unicodes */
FT_Pointer pointer )
{
- TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes );
- FT_Memory memory = FT_FACE_MEMORY( face );
- CFF_Font cff = (CFF_Font)face->extra.data;
- CFF_Charset charset = &cff->charset;
- FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames;
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
+ CFF_Font cff = (CFF_Font)face->extra.data;
+ CFF_Charset charset = &cff->charset;
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames;
FT_UNUSED( pointer );
@@ -166,17 +162,18 @@
return psnames->unicodes_init( memory,
unicodes,
cff->num_glyphs,
- (PS_GetGlyphNameFunc)&cff_sid_to_glyph_name,
+ &cff_sid_to_glyph_name,
(PS_FreeGlyphNameFunc)NULL,
(FT_Pointer)face );
}
FT_CALLBACK_DEF( void )
- cff_cmap_unicode_done( PS_Unicodes unicodes )
+ cff_cmap_unicode_done( FT_CMap cmap ) /* PS_Unicodes */
{
- FT_Face face = FT_CMAP_FACE( unicodes );
- FT_Memory memory = FT_FACE_MEMORY( face );
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ FT_Face face = FT_CMAP_FACE( cmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
FT_FREE( unicodes->maps );
@@ -185,25 +182,27 @@
FT_CALLBACK_DEF( FT_UInt )
- cff_cmap_unicode_char_index( PS_Unicodes unicodes,
- FT_UInt32 char_code )
+ cff_cmap_unicode_char_index( FT_CMap cmap, /* PS_Unicodes */
+ FT_UInt32 char_code )
{
- TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes );
- CFF_Font cff = (CFF_Font)face->extra.data;
- FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames;
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
+ CFF_Font cff = (CFF_Font)face->extra.data;
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames;
return psnames->unicodes_char_index( unicodes, char_code );
}
- FT_CALLBACK_DEF( FT_UInt32 )
- cff_cmap_unicode_char_next( PS_Unicodes unicodes,
- FT_UInt32 *pchar_code )
+ FT_CALLBACK_DEF( FT_UInt )
+ cff_cmap_unicode_char_next( FT_CMap cmap, /* PS_Unicodes */
+ FT_UInt32 *pchar_code )
{
- TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes );
- CFF_Font cff = (CFF_Font)face->extra.data;
- FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames;
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
+ CFF_Font cff = (CFF_Font)face->extra.data;
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)cff->psnames;
return psnames->unicodes_char_next( unicodes, pchar_code );
diff --git a/src/3rdparty/freetype/src/cff/cffdrivr.c b/src/3rdparty/freetype/src/cff/cffdrivr.c
index 4e2e0e00de..9898d625ca 100644
--- a/src/3rdparty/freetype/src/cff/cffdrivr.c
+++ b/src/3rdparty/freetype/src/cff/cffdrivr.c
@@ -108,20 +108,20 @@
* They can be implemented by format-specific interfaces.
*/
FT_CALLBACK_DEF( FT_Error )
- cff_get_kerning( FT_Face ttface, /* TT_Face */
+ cff_get_kerning( FT_Face face, /* CFF_Face */
FT_UInt left_glyph,
FT_UInt right_glyph,
FT_Vector* kerning )
{
- TT_Face face = (TT_Face)ttface;
- SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+ CFF_Face cffface = (CFF_Face)face;
+ SFNT_Service sfnt = (SFNT_Service)cffface->sfnt;
kerning->x = 0;
kerning->y = 0;
if ( sfnt )
- kerning->x = sfnt->get_kerning( face, left_glyph, right_glyph );
+ kerning->x = sfnt->get_kerning( cffface, left_glyph, right_glyph );
return FT_Err_Ok;
}
@@ -158,23 +158,23 @@
* FreeType error code. 0 means success.
*/
FT_CALLBACK_DEF( FT_Error )
- cff_glyph_load( FT_GlyphSlot cffslot, /* CFF_GlyphSlot */
- FT_Size cffsize, /* CFF_Size */
+ cff_glyph_load( FT_GlyphSlot slot, /* CFF_GlyphSlot */
+ FT_Size size, /* CFF_Size */
FT_UInt glyph_index,
FT_Int32 load_flags )
{
FT_Error error;
- CFF_GlyphSlot slot = (CFF_GlyphSlot)cffslot;
- CFF_Size size = (CFF_Size)cffsize;
+ CFF_GlyphSlot cffslot = (CFF_GlyphSlot)slot;
+ CFF_Size cffsize = (CFF_Size)size;
- if ( !slot )
+ if ( !cffslot )
return FT_THROW( Invalid_Slot_Handle );
FT_TRACE1(( "cff_glyph_load: glyph index %d\n", glyph_index ));
/* check whether we want a scaled outline or bitmap */
- if ( !size )
+ if ( !cffsize )
load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
/* reset the size object if necessary */
@@ -184,12 +184,12 @@
if ( size )
{
/* these two objects must have the same parent */
- if ( cffsize->face != cffslot->face )
+ if ( size->face != slot->face )
return FT_THROW( Invalid_Face_Handle );
}
/* now load the glyph outline if necessary */
- error = cff_slot_load( slot, size, glyph_index, load_flags );
+ error = cff_slot_load( cffslot, cffsize, glyph_index, load_flags );
/* force drop-out mode to 2 - irrelevant now */
/* slot->outline.dropout_mode = 2; */
@@ -216,7 +216,7 @@
/* it is no longer necessary that those values are identical to */
/* the values in the `CFF' table */
- TT_Face ttface = (TT_Face)face;
+ CFF_Face cffface = (CFF_Face)face;
FT_Short dummy;
@@ -225,7 +225,7 @@
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
/* no fast retrieval for blended MM fonts without VVAR table */
if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) &&
- !( ttface->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) )
+ !( cffface->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) )
return FT_THROW( Unimplemented_Feature );
#endif
@@ -233,7 +233,7 @@
/* otherwise we extract the info from the CFF glyphstrings */
/* (instead of synthesizing a global value using the `OS/2' */
/* table) */
- if ( !ttface->vertical_info )
+ if ( !cffface->vertical_info )
goto Missing_Table;
for ( nn = 0; nn < count; nn++ )
@@ -241,11 +241,11 @@
FT_UShort ah;
- ( (SFNT_Service)ttface->sfnt )->get_metrics( ttface,
- 1,
- start + nn,
- &dummy,
- &ah );
+ ( (SFNT_Service)cffface->sfnt )->get_metrics( cffface,
+ 1,
+ start + nn,
+ &dummy,
+ &ah );
FT_TRACE5(( " idx %d: advance height %d font unit%s\n",
start + nn,
@@ -259,12 +259,12 @@
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
/* no fast retrieval for blended MM fonts without HVAR table */
if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) &&
- !( ttface->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) )
+ !( cffface->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) )
return FT_THROW( Unimplemented_Feature );
#endif
/* check whether we have data from the `hmtx' table at all */
- if ( !ttface->horizontal.number_Of_HMetrics )
+ if ( !cffface->horizontal.number_Of_HMetrics )
goto Missing_Table;
for ( nn = 0; nn < count; nn++ )
@@ -272,11 +272,11 @@
FT_UShort aw;
- ( (SFNT_Service)ttface->sfnt )->get_metrics( ttface,
- 0,
- start + nn,
- &dummy,
- &aw );
+ ( (SFNT_Service)cffface->sfnt )->get_metrics( cffface,
+ 0,
+ start + nn,
+ &dummy,
+ &aw );
FT_TRACE5(( " idx %d: advance width %d font unit%s\n",
start + nn,
@@ -312,13 +312,14 @@
*
*/
- static FT_Error
- cff_get_glyph_name( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_get_glyph_name( FT_Face face, /* CFF_Face */
FT_UInt glyph_index,
FT_Pointer buffer,
FT_UInt buffer_max )
{
- CFF_Font font = (CFF_Font)face->extra.data;
+ CFF_Face cffface = (CFF_Face)face;
+ CFF_Font font = (CFF_Font)cffface->extra.data;
FT_String* gname;
FT_UShort sid;
FT_Error error;
@@ -338,10 +339,7 @@
if ( service && service->get_name )
- return service->get_name( FT_FACE( face ),
- glyph_index,
- buffer,
- buffer_max );
+ return service->get_name( face, glyph_index, buffer, buffer_max );
else
{
FT_ERROR(( "cff_get_glyph_name:"
@@ -366,7 +364,7 @@
/* first, locate the sid in the charset table */
sid = font->charset.sids[glyph_index];
- /* now, lookup the name itself */
+ /* now, look up the name itself */
gname = cff_index_get_sid_string( font, sid );
if ( gname )
@@ -379,21 +377,19 @@
}
- static FT_UInt
- cff_get_name_index( CFF_Face face,
+ FT_CALLBACK_DEF( FT_UInt )
+ cff_get_name_index( FT_Face face, /* CFF_Face */
const FT_String* glyph_name )
{
- CFF_Font cff;
- CFF_Charset charset;
+ CFF_Face cffface = (CFF_Face)face;
+ CFF_Font cff = (CFF_Font)cffface->extra.data;
+ CFF_Charset charset = &cff->charset;
FT_Service_PsCMaps psnames;
FT_String* name;
FT_UShort sid;
FT_UInt i;
- cff = (CFF_FontRec *)face->extra.data;
- charset = &cff->charset;
-
/* CFF2 table does not have glyph names; */
/* we need to use `post' table method */
if ( cff->version_major == 2 )
@@ -408,7 +404,7 @@
if ( service && service->name_index )
- return service->name_index( FT_FACE( face ), glyph_name );
+ return service->name_index( face, glyph_name );
else
{
FT_ERROR(( "cff_get_name_index:"
@@ -446,8 +442,8 @@
FT_DEFINE_SERVICE_GLYPHDICTREC(
cff_service_glyph_dict,
- (FT_GlyphDict_GetNameFunc) cff_get_glyph_name, /* get_name */
- (FT_GlyphDict_NameIndexFunc)cff_get_name_index /* name_index */
+ cff_get_glyph_name, /* FT_GlyphDict_GetNameFunc get_name */
+ cff_get_name_index /* FT_GlyphDict_NameIndexFunc name_index */
)
@@ -456,25 +452,32 @@
*
*/
- static FT_Int
+ FT_CALLBACK_DEF( FT_Int )
cff_ps_has_glyph_names( FT_Face face )
{
return ( face->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) > 0;
}
- static FT_Error
- cff_ps_get_font_info( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_ps_get_font_info( FT_Face face, /* CFF_Face */
PS_FontInfoRec* afont_info )
{
- CFF_Font cff = (CFF_Font)face->extra.data;
- FT_Error error = FT_Err_Ok;
+ CFF_Face cffface = (CFF_Face)face;
+ CFF_Font cff = (CFF_Font)cffface->extra.data;
+ FT_Error error = FT_Err_Ok;
+ if ( cffface->is_cff2 )
+ {
+ error = FT_THROW( Invalid_Argument );
+ goto Fail;
+ }
+
if ( cff && !cff->font_info )
{
CFF_FontRecDict dict = &cff->top_font.font_dict;
- FT_Memory memory = face->root.memory;
+ FT_Memory memory = FT_FACE_MEMORY( face );
PS_FontInfoRec* font_info = NULL;
@@ -507,18 +510,19 @@
}
- static FT_Error
- cff_ps_get_font_extra( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_ps_get_font_extra( FT_Face face, /* CFF_Face */
PS_FontExtraRec* afont_extra )
{
- CFF_Font cff = (CFF_Font)face->extra.data;
- FT_Error error = FT_Err_Ok;
+ CFF_Face cffface = (CFF_Face)face;
+ CFF_Font cff = (CFF_Font)cffface->extra.data;
+ FT_Error error = FT_Err_Ok;
if ( cff && !cff->font_extra )
{
CFF_FontRecDict dict = &cff->top_font.font_dict;
- FT_Memory memory = face->root.memory;
+ FT_Memory memory = FT_FACE_MEMORY( face );
PS_FontExtraRec* font_extra = NULL;
FT_String* embedded_postscript;
@@ -588,13 +592,13 @@
FT_DEFINE_SERVICE_PSINFOREC(
cff_service_ps_info,
- (PS_GetFontInfoFunc) cff_ps_get_font_info, /* ps_get_font_info */
- (PS_GetFontExtraFunc) cff_ps_get_font_extra, /* ps_get_font_extra */
- (PS_HasGlyphNamesFunc) cff_ps_has_glyph_names, /* ps_has_glyph_names */
+ cff_ps_get_font_info, /* PS_GetFontInfoFunc ps_get_font_info */
+ cff_ps_get_font_extra, /* PS_GetFontExtraFunc ps_get_font_extra */
+ cff_ps_has_glyph_names, /* PS_HasGlyphNamesFunc ps_has_glyph_names */
/* unsupported with CFF fonts */
- (PS_GetFontPrivateFunc)NULL, /* ps_get_font_private */
+ NULL, /* PS_GetFontPrivateFunc ps_get_font_private */
/* not implemented */
- (PS_GetFontValueFunc) NULL /* ps_get_font_value */
+ NULL /* PS_GetFontValueFunc ps_get_font_value */
)
@@ -603,17 +607,18 @@
*
*/
- static const char*
- cff_get_ps_name( CFF_Face face )
+ FT_CALLBACK_DEF( const char* )
+ cff_get_ps_name( FT_Face face ) /* CFF_Face */
{
- CFF_Font cff = (CFF_Font)face->extra.data;
- SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+ CFF_Face cffface = (CFF_Face)face;
+ CFF_Font cff = (CFF_Font)cffface->extra.data;
+ SFNT_Service sfnt = (SFNT_Service)cffface->sfnt;
/* following the OpenType specification 1.7, we return the name stored */
/* in the `name' table for a CFF wrapped into an SFNT container */
- if ( FT_IS_SFNT( FT_FACE( face ) ) && sfnt )
+ if ( FT_IS_SFNT( face ) && sfnt )
{
FT_Library library = FT_FACE_LIBRARY( face );
FT_Module sfnt_module = FT_Get_Module( library, "sfnt" );
@@ -625,17 +630,17 @@
if ( service && service->get_ps_font_name )
- return service->get_ps_font_name( FT_FACE( face ) );
+ return service->get_ps_font_name( face );
}
- return (const char*)cff->font_name;
+ return cff ? (const char*)cff->font_name : NULL;
}
FT_DEFINE_SERVICE_PSFONTNAMEREC(
cff_service_ps_name,
- (FT_PsName_GetFunc)cff_get_ps_name /* get_ps_font_name */
+ cff_get_ps_name /* FT_PsName_GetFunc get_ps_font_name */
)
@@ -649,7 +654,7 @@
* Otherwise call the service function in the sfnt module.
*
*/
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
cff_get_cmap_info( FT_CharMap charmap,
TT_CMapInfo *cmap_info )
{
@@ -683,7 +688,7 @@
FT_DEFINE_SERVICE_TTCMAPSREC(
cff_service_get_cmap_info,
- (TT_CMap_Info_GetFunc)cff_get_cmap_info /* get_cmap_info */
+ cff_get_cmap_info /* TT_CMap_Info_GetFunc get_cmap_info */
)
@@ -691,14 +696,15 @@
* CID INFO SERVICE
*
*/
- static FT_Error
- cff_get_ros( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_get_ros( FT_Face face, /* FT_Face */
const char* *registry,
const char* *ordering,
FT_Int *supplement )
{
- FT_Error error = FT_Err_Ok;
- CFF_Font cff = (CFF_Font)face->extra.data;
+ FT_Error error = FT_Err_Ok;
+ CFF_Face cffface = (CFF_Face)face;
+ CFF_Font cff = (CFF_Font)cffface->extra.data;
if ( cff )
@@ -748,12 +754,13 @@
}
- static FT_Error
- cff_get_is_cid( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_get_is_cid( FT_Face face, /* CFF_Face */
FT_Bool *is_cid )
{
- FT_Error error = FT_Err_Ok;
- CFF_Font cff = (CFF_Font)face->extra.data;
+ FT_Error error = FT_Err_Ok;
+ CFF_Face cffface = (CFF_Face)face;
+ CFF_Font cff = (CFF_Font)cffface->extra.data;
*is_cid = 0;
@@ -771,16 +778,15 @@
}
- static FT_Error
- cff_get_cid_from_glyph_index( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_get_cid_from_glyph_index( FT_Face face, /* CFF_Face */
FT_UInt glyph_index,
FT_UInt *cid )
{
- FT_Error error = FT_Err_Ok;
- CFF_Font cff;
-
+ FT_Error error = FT_Err_Ok;
+ CFF_Face cffface = (CFF_Face)face;
+ CFF_Font cff = (CFF_Font)cffface->extra.data;
- cff = (CFF_Font)face->extra.data;
if ( cff )
{
@@ -814,12 +820,12 @@
FT_DEFINE_SERVICE_CIDREC(
cff_service_cid_info,
- (FT_CID_GetRegistryOrderingSupplementFunc)
- cff_get_ros, /* get_ros */
- (FT_CID_GetIsInternallyCIDKeyedFunc)
- cff_get_is_cid, /* get_is_cid */
- (FT_CID_GetCIDFromGlyphIndexFunc)
- cff_get_cid_from_glyph_index /* get_cid_from_glyph_index */
+ cff_get_ros,
+ /* FT_CID_GetRegistryOrderingSupplementFunc get_ros */
+ cff_get_is_cid,
+ /* FT_CID_GetIsInternallyCIDKeyedFunc get_is_cid */
+ cff_get_cid_from_glyph_index
+ /* FT_CID_GetCIDFromGlyphIndexFunc get_cid_from_glyph_index */
)
@@ -831,9 +837,9 @@
FT_DEFINE_SERVICE_PROPERTIESREC(
cff_service_properties,
- (FT_Properties_SetFunc)ps_property_set, /* set_property */
- (FT_Properties_GetFunc)ps_property_get ) /* get_property */
-
+ ps_property_set, /* FT_Properties_SetFunc set_property */
+ ps_property_get /* FT_Properties_GetFunc get_property */
+ )
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
@@ -842,160 +848,195 @@
*
*/
- static FT_Error
- cff_set_mm_blend( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_set_mm_blend( FT_Face face, /* CFF_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->set_mm_blend( FT_FACE( face ), num_coords, coords );
+ return mm->set_mm_blend( face, num_coords, coords );
}
- static FT_Error
- cff_get_mm_blend( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_get_mm_blend( FT_Face face, /* CFF_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->get_mm_blend( FT_FACE( face ), num_coords, coords );
+ return mm->get_mm_blend( face, num_coords, coords );
}
- static FT_Error
- cff_set_mm_weightvector( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_set_mm_weightvector( FT_Face face, /* CFF_Face */
FT_UInt len,
FT_Fixed* weightvector )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->set_mm_weightvector( FT_FACE( face ), len, weightvector );
+ return mm->set_mm_weightvector( face, len, weightvector );
}
- static FT_Error
- cff_get_mm_weightvector( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_get_mm_weightvector( FT_Face face, /* CFF_Face */
FT_UInt* len,
FT_Fixed* weightvector )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->get_mm_weightvector( FT_FACE( face ), len, weightvector );
+ return mm->get_mm_weightvector( face, len, weightvector );
}
- static FT_Error
- cff_get_mm_var( CFF_Face face,
+ FT_CALLBACK_DEF( void )
+ cff_construct_ps_name( FT_Face face ) /* CFF_Face */
+ {
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
+
+
+ mm->construct_ps_name( face );
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ cff_get_mm_var( FT_Face face, /* CFF_Face */
FT_MM_Var* *master )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->get_mm_var( FT_FACE( face ), master );
+ return mm->get_mm_var( face, master );
}
- static FT_Error
- cff_set_var_design( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_set_var_design( FT_Face face, /* CFF_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->set_var_design( FT_FACE( face ), num_coords, coords );
+ return mm->set_var_design( face, num_coords, coords );
}
- static FT_Error
- cff_get_var_design( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_get_var_design( FT_Face face, /* CFF_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->get_var_design( FT_FACE( face ), num_coords, coords );
+ return mm->get_var_design( face, num_coords, coords );
}
- static FT_Error
- cff_set_instance( CFF_Face face,
- FT_UInt instance_index )
+ FT_CALLBACK_DEF( FT_Error )
+ cff_set_named_instance( FT_Face face, /* CFF_Face */
+ FT_UInt instance_index )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->set_instance( FT_FACE( face ), instance_index );
+ return mm->set_named_instance( face, instance_index );
}
- static FT_Error
- cff_load_item_variation_store( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_get_default_named_instance( FT_Face face, /* CFF_Face */
+ FT_UInt *instance_index )
+ {
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
+
+
+ return mm->get_default_named_instance( face, instance_index );
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ cff_load_item_variation_store( FT_Face face, /* CFF_Face */
FT_ULong offset,
GX_ItemVarStore itemStore )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->load_item_var_store( FT_FACE(face), offset, itemStore );
+ return mm->load_item_var_store( face, offset, itemStore );
}
- static FT_Error
- cff_load_delta_set_index_mapping( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_load_delta_set_index_mapping( FT_Face face, /* CFF_Face */
FT_ULong offset,
GX_DeltaSetIdxMap map,
GX_ItemVarStore itemStore,
FT_ULong table_len )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->load_delta_set_idx_map( FT_FACE( face ), offset, map,
+ return mm->load_delta_set_idx_map( face, offset, map,
itemStore, table_len );
}
- static FT_Int
- cff_get_item_delta( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Int )
+ cff_get_item_delta( FT_Face face, /* CFF_Face */
GX_ItemVarStore itemStore,
FT_UInt outerIndex,
FT_UInt innerIndex )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->get_item_delta( FT_FACE( face ), itemStore,
- outerIndex, innerIndex );
+ return mm->get_item_delta( face, itemStore, outerIndex, innerIndex );
}
- static void
- cff_done_item_variation_store( CFF_Face face,
+ FT_CALLBACK_DEF( void )
+ cff_done_item_variation_store( FT_Face face, /* CFF_Face */
GX_ItemVarStore itemStore )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- mm->done_item_var_store( FT_FACE( face ), itemStore );
+ mm->done_item_var_store( face, itemStore );
}
- static void
- cff_done_delta_set_index_map( CFF_Face face,
+ FT_CALLBACK_DEF( void )
+ cff_done_delta_set_index_map( FT_Face face, /* CFF_Face */
GX_DeltaSetIdxMap deltaSetIdxMap )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- mm->done_delta_set_idx_map( FT_FACE ( face ), deltaSetIdxMap );
+ mm->done_delta_set_idx_map( face, deltaSetIdxMap );
}
@@ -1003,36 +1044,35 @@
FT_DEFINE_SERVICE_MULTIMASTERSREC(
cff_service_multi_masters,
- (FT_Get_MM_Func) NULL, /* get_mm */
- (FT_Set_MM_Design_Func) NULL, /* set_mm_design */
- (FT_Set_MM_Blend_Func) cff_set_mm_blend, /* set_mm_blend */
- (FT_Get_MM_Blend_Func) cff_get_mm_blend, /* get_mm_blend */
- (FT_Get_MM_Var_Func) cff_get_mm_var, /* get_mm_var */
- (FT_Set_Var_Design_Func)cff_set_var_design, /* set_var_design */
- (FT_Get_Var_Design_Func)cff_get_var_design, /* get_var_design */
- (FT_Set_Instance_Func) cff_set_instance, /* set_instance */
- (FT_Set_MM_WeightVector_Func)
- cff_set_mm_weightvector,
- /* set_mm_weightvector */
- (FT_Get_MM_WeightVector_Func)
- cff_get_mm_weightvector,
- /* get_mm_weightvector */
- (FT_Var_Load_Delta_Set_Idx_Map_Func)
- cff_load_delta_set_index_mapping,
- /* load_delta_set_idx_map */
- (FT_Var_Load_Item_Var_Store_Func)
- cff_load_item_variation_store,
- /* load_item_variation_store */
- (FT_Var_Get_Item_Delta_Func)
- cff_get_item_delta, /* get_item_delta */
- (FT_Var_Done_Item_Var_Store_Func)
- cff_done_item_variation_store,
- /* done_item_variation_store */
- (FT_Var_Done_Delta_Set_Idx_Map_Func)
- cff_done_delta_set_index_map,
- /* done_delta_set_index_map */
- (FT_Get_Var_Blend_Func) cff_get_var_blend, /* get_var_blend */
- (FT_Done_Blend_Func) cff_done_blend /* done_blend */
+ NULL, /* FT_Get_MM_Func get_mm */
+ NULL, /* FT_Set_MM_Design_Func set_mm_design */
+ cff_set_mm_blend, /* FT_Set_MM_Blend_Func set_mm_blend */
+ cff_get_mm_blend, /* FT_Get_MM_Blend_Func get_mm_blend */
+ cff_get_mm_var, /* FT_Get_MM_Var_Func get_mm_var */
+ cff_set_var_design, /* FT_Set_Var_Design_Func set_var_design */
+ cff_get_var_design, /* FT_Get_Var_Design_Func get_var_design */
+ cff_set_named_instance,
+ /* FT_Set_Named_Instance_Func set_named_instance */
+ cff_get_default_named_instance,
+ /* FT_Get_Default_Named_Instance_Func get_default_named_instance */
+ cff_set_mm_weightvector,
+ /* FT_Set_MM_WeightVector_Func set_mm_weightvector */
+ cff_get_mm_weightvector,
+ /* FT_Get_MM_WeightVector_Func get_mm_weightvector */
+ cff_construct_ps_name,
+ /* FT_Construct_PS_Name_Func construct_ps_name */
+ cff_load_delta_set_index_mapping,
+ /* FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map */
+ cff_load_item_variation_store,
+ /* FT_Var_Load_Item_Var_Store_Func load_item_variation_store */
+ cff_get_item_delta,
+ /* FT_Var_Get_Item_Delta_Func get_item_delta */
+ cff_done_item_variation_store,
+ /* FT_Var_Done_Item_Var_Store_Func done_item_variation_store */
+ cff_done_delta_set_index_map,
+ /* FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_index_map */
+ cff_get_var_blend, /* FT_Get_Var_Blend_Func get_var_blend */
+ cff_done_blend /* FT_Done_Blend_Func done_blend */
)
@@ -1041,41 +1081,46 @@
*
*/
- static FT_Error
- cff_hadvance_adjust( CFF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cff_hadvance_adjust( FT_Face face, /* CFF_Face */
FT_UInt gindex,
FT_Int *avalue )
{
- FT_Service_MetricsVariations var = (FT_Service_MetricsVariations)face->var;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MetricsVariations
+ var = (FT_Service_MetricsVariations)cffface->tt_var;
- return var->hadvance_adjust( FT_FACE( face ), gindex, avalue );
+ return var->hadvance_adjust( face, gindex, avalue );
}
- static void
- cff_metrics_adjust( CFF_Face face )
+ FT_CALLBACK_DEF( void )
+ cff_metrics_adjust( FT_Face face ) /* CFF_Face */
{
- FT_Service_MetricsVariations var = (FT_Service_MetricsVariations)face->var;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MetricsVariations
+ var = (FT_Service_MetricsVariations)cffface->tt_var;
- var->metrics_adjust( FT_FACE( face ) );
+ var->metrics_adjust( face );
}
FT_DEFINE_SERVICE_METRICSVARIATIONSREC(
cff_service_metrics_variations,
- (FT_HAdvance_Adjust_Func)cff_hadvance_adjust, /* hadvance_adjust */
- (FT_LSB_Adjust_Func) NULL, /* lsb_adjust */
- (FT_RSB_Adjust_Func) NULL, /* rsb_adjust */
+ cff_hadvance_adjust, /* FT_HAdvance_Adjust_Func hadvance_adjust */
+ NULL, /* FT_LSB_Adjust_Func lsb_adjust */
+ NULL, /* FT_RSB_Adjust_Func rsb_adjust */
- (FT_VAdvance_Adjust_Func)NULL, /* vadvance_adjust */
- (FT_TSB_Adjust_Func) NULL, /* tsb_adjust */
- (FT_BSB_Adjust_Func) NULL, /* bsb_adjust */
- (FT_VOrg_Adjust_Func) NULL, /* vorg_adjust */
+ NULL, /* FT_VAdvance_Adjust_Func vadvance_adjust */
+ NULL, /* FT_TSB_Adjust_Func tsb_adjust */
+ NULL, /* FT_BSB_Adjust_Func bsb_adjust */
+ NULL, /* FT_VOrg_Adjust_Func vorg_adjust */
- (FT_Metrics_Adjust_Func) cff_metrics_adjust /* metrics_adjust */
+ cff_metrics_adjust, /* FT_Metrics_Adjust_Func metrics_adjust */
+ NULL /* FT_Size_Reset_Func size_reset */
)
#endif
@@ -1088,11 +1133,11 @@
FT_DEFINE_SERVICE_CFFLOADREC(
cff_service_cff_load,
- (FT_Get_Standard_Encoding_Func)cff_get_standard_encoding,
- (FT_Load_Private_Dict_Func) cff_load_private_dict,
- (FT_FD_Select_Get_Func) cff_fd_select_get,
- (FT_Blend_Check_Vector_Func) cff_blend_check_vector,
- (FT_Blend_Build_Vector_Func) cff_blend_build_vector
+ cff_get_standard_encoding, /* FT_Get_Standard_Encoding_Func get_standard_encoding */
+ cff_load_private_dict, /* FT_Load_Private_Dict_Func load_private_dict */
+ cff_fd_select_get, /* FT_FD_Select_Get_Func fd_select_get */
+ cff_blend_check_vector, /* FT_Blend_Check_Vector_Func blend_check_vector */
+ cff_blend_build_vector /* FT_Blend_Build_Vector_Func blend_build_vector */
)
diff --git a/src/3rdparty/freetype/src/cff/cffgload.c b/src/3rdparty/freetype/src/cff/cffgload.c
index cfa0aaf2b6..c483d1d1a5 100644
--- a/src/3rdparty/freetype/src/cff/cffgload.c
+++ b/src/3rdparty/freetype/src/cff/cffgload.c
@@ -356,14 +356,16 @@
#ifdef FT_CONFIG_OPTION_SVG
/* check for OT-SVG */
- if ( ( load_flags & FT_LOAD_COLOR ) && face->svg )
+ if ( ( load_flags & FT_LOAD_NO_SVG ) == 0 &&
+ ( load_flags & FT_LOAD_COLOR ) &&
+ face->svg )
{
/*
* We load the SVG document and try to grab the advances from the
* table. For the bearings we rely on the presetting hook to do that.
*/
- SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+ SFNT_Service sfnt = (SFNT_Service)face->sfnt;
if ( size && (size->root.metrics.x_ppem < 1 ||
diff --git a/src/3rdparty/freetype/src/cff/cffload.c b/src/3rdparty/freetype/src/cff/cffload.c
index 4b8c6e16c5..af79082e98 100644
--- a/src/3rdparty/freetype/src/cff/cffload.c
+++ b/src/3rdparty/freetype/src/cff/cffload.c
@@ -400,7 +400,7 @@
/* Allocate a table containing pointers to an index's elements. */
/* The `pool' argument makes this function convert the index */
- /* entries to C-style strings (this is, null-terminated). */
+ /* entries to C-style strings (that is, null-terminated). */
static FT_Error
cff_index_get_pointers( CFF_Index idx,
FT_Byte*** table,
@@ -1361,14 +1361,15 @@
for ( i = 0; i < numBlends; i++ )
{
const FT_Int32* weight = &blend->BV[1];
- FT_UInt32 sum;
+ FT_Fixed sum;
- /* convert inputs to 16.16 fixed-point */
- sum = cff_parse_num( parser, &parser->stack[i + base] ) * 0x10000;
+ /* convert inputs to 16.16 fixed point */
+ sum = cff_parse_fixed( parser, &parser->stack[i + base] );
for ( j = 1; j < blend->lenBV; j++ )
- sum += cff_parse_num( parser, &parser->stack[delta++] ) * *weight++;
+ sum += FT_MulFix( cff_parse_fixed( parser, &parser->stack[delta++] ),
+ *weight++ );
/* point parser stack to new value on blend_stack */
parser->stack[i + base] = subFont->blend_top;
@@ -1589,16 +1590,17 @@
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
FT_LOCAL_DEF( FT_Error )
- cff_get_var_blend( CFF_Face face,
+ cff_get_var_blend( FT_Face face, /* CFF_Face */
FT_UInt *num_coords,
FT_Fixed* *coords,
FT_Fixed* *normalizedcoords,
FT_MM_Var* *mm_var )
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- return mm->get_var_blend( FT_FACE( face ),
+ return mm->get_var_blend( face,
num_coords,
coords,
normalizedcoords,
@@ -1607,13 +1609,14 @@
FT_LOCAL_DEF( void )
- cff_done_blend( CFF_Face face )
+ cff_done_blend( FT_Face face ) /* CFF_Face */
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
+ CFF_Face cffface = (CFF_Face)face;
+ FT_Service_MultiMasters mm = (FT_Service_MultiMasters)cffface->mm;
- if (mm)
- mm->done_blend( FT_FACE( face ) );
+ if ( mm )
+ mm->done_blend( face );
}
#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
@@ -1650,13 +1653,6 @@
goto Exit;
}
- /* Zero out the code to gid/sid mappings. */
- for ( j = 0; j < 256; j++ )
- {
- encoding->sids [j] = 0;
- encoding->codes[j] = 0;
- }
-
/* Note: The encoding table in a CFF font is indexed by glyph index; */
/* the first encoded glyph index is 1. Hence, we read the character */
/* code (`glyph_code') at index j and make the assignment: */
@@ -1671,6 +1667,10 @@
if ( offset > 1 )
{
+ /* Zero out the code to gid/sid mappings. */
+ FT_ARRAY_ZERO( encoding->sids, 256 );
+ FT_ARRAY_ZERO( encoding->codes, 256 );
+
encoding->offset = base_offset + offset;
/* we need to parse the table to determine its size */
@@ -2012,7 +2012,7 @@
/* Top and Font DICTs are not allowed to have blend operators. */
error = cff_parser_init( &parser,
code,
- &subfont->font_dict,
+ top,
font->library,
stackSize,
0,
diff --git a/src/3rdparty/freetype/src/cff/cffload.h b/src/3rdparty/freetype/src/cff/cffload.h
index 5a41cdebc8..b5286b0c8c 100644
--- a/src/3rdparty/freetype/src/cff/cffload.h
+++ b/src/3rdparty/freetype/src/cff/cffload.h
@@ -105,14 +105,14 @@ FT_BEGIN_HEADER
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
FT_LOCAL( FT_Error )
- cff_get_var_blend( CFF_Face face,
+ cff_get_var_blend( FT_Face face,
FT_UInt *num_coords,
FT_Fixed* *coords,
FT_Fixed* *normalizedcoords,
FT_MM_Var* *mm_var );
FT_LOCAL( void )
- cff_done_blend( CFF_Face face );
+ cff_done_blend( FT_Face face );
#endif
diff --git a/src/3rdparty/freetype/src/cff/cffobjs.c b/src/3rdparty/freetype/src/cff/cffobjs.c
index 40cd9bf917..6d08620c48 100644
--- a/src/3rdparty/freetype/src/cff/cffobjs.c
+++ b/src/3rdparty/freetype/src/cff/cffobjs.c
@@ -69,8 +69,8 @@
FT_Module module;
- module = FT_Get_Module( size->root.face->driver->root.library,
- "pshinter" );
+ module = FT_Get_Module( font->library, "pshinter" );
+
return ( module && pshinter && pshinter->get_globals_funcs )
? pshinter->get_globals_funcs( module )
: 0;
@@ -182,8 +182,7 @@
goto Exit;
cff_make_private_dict( &font->top_font, &priv );
- error = funcs->create( cffsize->face->memory, &priv,
- &internal->topfont );
+ error = funcs->create( memory, &priv, &internal->topfont );
if ( error )
goto Exit;
@@ -193,8 +192,7 @@
cff_make_private_dict( sub, &priv );
- error = funcs->create( cffsize->face->memory, &priv,
- &internal->subfonts[i - 1] );
+ error = funcs->create( memory, &priv, &internal->subfonts[i - 1] );
if ( error )
goto Exit;
}
@@ -381,8 +379,7 @@
FT_Module module;
- module = FT_Get_Module( slot->face->driver->root.library,
- "pshinter" );
+ module = FT_Get_Module( slot->library, "pshinter" );
if ( module )
{
T2_Hints_Funcs funcs;
@@ -722,22 +719,15 @@
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
{
- FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
- FT_Service_MetricsVariations var = (FT_Service_MetricsVariations)face->var;
-
FT_UInt instance_index = (FT_UInt)face_index >> 16;
if ( FT_HAS_MULTIPLE_MASTERS( cffface ) &&
- mm &&
instance_index > 0 )
{
- error = mm->set_instance( cffface, instance_index );
+ error = FT_Set_Named_Instance( cffface, instance_index );
if ( error )
goto Exit;
-
- if ( var )
- var->metrics_adjust( cffface );
}
}
#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
@@ -1160,7 +1150,7 @@
}
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
- cff_done_blend( face );
+ cff_done_blend( cffface );
face->blend = NULL;
#endif
}
diff --git a/src/3rdparty/freetype/src/cff/cffparse.c b/src/3rdparty/freetype/src/cff/cffparse.c
index e16206fd55..3b076704cf 100644
--- a/src/3rdparty/freetype/src/cff/cffparse.c
+++ b/src/3rdparty/freetype/src/cff/cffparse.c
@@ -63,10 +63,7 @@
/* allocate the stack buffer */
if ( FT_QNEW_ARRAY( parser->stack, stackSize ) )
- {
- FT_FREE( parser->stack );
goto Exit;
- }
parser->stackSize = stackSize;
parser->top = parser->stack; /* empty stack */
@@ -76,23 +73,6 @@
}
-#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
- static void
- finalize_t2_strings( FT_Memory memory,
- void* data,
- void* user )
- {
- CFF_T2_String t2 = (CFF_T2_String)data;
-
-
- FT_UNUSED( user );
-
- memory->free( memory, t2->start );
- memory->free( memory, data );
- }
-#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
-
-
FT_LOCAL_DEF( void )
cff_parser_done( CFF_Parser parser )
{
@@ -102,63 +82,19 @@
FT_FREE( parser->stack );
#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
- FT_List_Finalize( &parser->t2_strings,
- finalize_t2_strings,
- memory,
- NULL );
+ FT_List_Finalize( &parser->t2_strings, NULL, memory, NULL );
#endif
}
- /* Assuming `first >= last'. */
-
- static FT_Error
- cff_parser_within_limits( CFF_Parser parser,
- FT_Byte* first,
- FT_Byte* last )
- {
-#ifndef CFF_CONFIG_OPTION_OLD_ENGINE
-
- /* Fast path for regular FreeType builds with the "new" engine; */
- /* `first >= parser->start' can be assumed. */
-
- FT_UNUSED( first );
-
- return last < parser->limit ? FT_Err_Ok : FT_THROW( Invalid_Argument );
-
-#else /* CFF_CONFIG_OPTION_OLD_ENGINE */
-
- FT_ListNode node;
-
-
- if ( first >= parser->start &&
- last < parser->limit )
- return FT_Err_Ok;
-
- node = parser->t2_strings.head;
-
- while ( node )
- {
- CFF_T2_String t2 = (CFF_T2_String)node->data;
-
-
- if ( first >= t2->start &&
- last < t2->limit )
- return FT_Err_Ok;
-
- node = node->next;
- }
-
- return FT_THROW( Invalid_Argument );
-
-#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
- }
-
+ /* The parser limit checks in the next two functions are supposed */
+ /* to detect the immediate crossing of the stream boundary. They */
+ /* shall not be triggered from the distant t2_strings buffers. */
/* read an integer */
static FT_Long
- cff_parse_integer( CFF_Parser parser,
- FT_Byte* start )
+ cff_parse_integer( FT_Byte* start,
+ FT_Byte* limit )
{
FT_Byte* p = start;
FT_Int v = *p++;
@@ -167,14 +103,14 @@
if ( v == 28 )
{
- if ( cff_parser_within_limits( parser, p, p + 1 ) )
+ if ( p + 2 > limit && limit >= p )
goto Bad;
val = (FT_Short)( ( (FT_UShort)p[0] << 8 ) | p[1] );
}
else if ( v == 29 )
{
- if ( cff_parser_within_limits( parser, p, p + 3 ) )
+ if ( p + 4 > limit && limit >= p )
goto Bad;
val = (FT_Long)( ( (FT_ULong)p[0] << 24 ) |
@@ -188,14 +124,14 @@
}
else if ( v < 251 )
{
- if ( cff_parser_within_limits( parser, p, p ) )
+ if ( p + 1 > limit && limit >= p )
goto Bad;
val = ( v - 247 ) * 256 + p[0] + 108;
}
else
{
- if ( cff_parser_within_limits( parser, p, p ) )
+ if ( p + 1 > limit && limit >= p )
goto Bad;
val = -( v - 251 ) * 256 - p[0] - 108;
@@ -244,10 +180,10 @@
/* read a real */
static FT_Fixed
- cff_parse_real( CFF_Parser parser,
- FT_Byte* start,
- FT_Long power_ten,
- FT_Long* scaling )
+ cff_parse_real( FT_Byte* start,
+ FT_Byte* limit,
+ FT_Long power_ten,
+ FT_Long* scaling )
{
FT_Byte* p = start;
FT_Int nib;
@@ -282,7 +218,7 @@
p++;
/* Make sure we don't read past the end. */
- if ( cff_parser_within_limits( parser, p, p ) )
+ if ( p + 1 > limit && limit >= p )
goto Bad;
}
@@ -319,7 +255,7 @@
p++;
/* Make sure we don't read past the end. */
- if ( cff_parser_within_limits( parser, p, p ) )
+ if ( p + 1 > limit && limit >= p )
goto Bad;
}
@@ -358,7 +294,7 @@
p++;
/* Make sure we don't read past the end. */
- if ( cff_parser_within_limits( parser, p, p ) )
+ if ( p + 1 > limit && limit >= p )
goto Bad;
}
@@ -525,7 +461,7 @@
if ( **d == 30 )
{
/* binary-coded decimal is truncated to integer */
- return cff_parse_real( parser, *d, 0, NULL ) >> 16;
+ return cff_parse_real( *d, parser->limit, 0, NULL ) >> 16;
}
else if ( **d == 255 )
@@ -551,7 +487,7 @@
}
else
- return cff_parse_integer( parser, *d );
+ return cff_parse_integer( *d, parser->limit );
}
@@ -562,15 +498,33 @@
FT_Long scaling )
{
if ( **d == 30 )
- return cff_parse_real( parser, *d, scaling, NULL );
+ return cff_parse_real( *d, parser->limit, scaling, NULL );
+ else if ( **d == 255 )
+ {
+ FT_Fixed val = ( ( ( (FT_UInt32)*( d[0] + 1 ) << 24 ) |
+ ( (FT_UInt32)*( d[0] + 2 ) << 16 ) |
+ ( (FT_UInt32)*( d[0] + 3 ) << 8 ) |
+ (FT_UInt32)*( d[0] + 4 ) ) );
+
+ if ( scaling )
+ {
+ if ( FT_ABS( val ) > power_ten_limits[scaling] )
+ {
+ FT_TRACE4(( "!!!OVERFLOW:!!!" ));
+ return val > 0 ? 0x7FFFFFFFL : -0x7FFFFFFFL;
+ }
+ val *= power_tens[scaling];
+ }
+ return val;
+ }
else
{
- FT_Long val = cff_parse_integer( parser, *d );
+ FT_Long val = cff_parse_integer( *d, parser->limit );
if ( scaling )
{
- if ( FT_ABS( val ) > power_ten_limits[scaling] )
+ if ( ( FT_ABS( val ) << 16 ) > power_ten_limits[scaling] )
{
val = val > 0 ? 0x7FFFFFFFL : -0x7FFFFFFFL;
goto Overflow;
@@ -600,7 +554,7 @@
/* read a floating point number, either integer or real */
- static FT_Fixed
+ FT_LOCAL_DEF( FT_Fixed )
cff_parse_fixed( CFF_Parser parser,
FT_Byte** d )
{
@@ -630,14 +584,14 @@
FT_ASSERT( scaling );
if ( **d == 30 )
- return cff_parse_real( parser, *d, 0, scaling );
+ return cff_parse_real( *d, parser->limit, 0, scaling );
else
{
FT_Long number;
FT_Int integer_length;
- number = cff_parse_integer( parser, d[0] );
+ number = cff_parse_integer( *d, parser->limit );
if ( number > 0x7FFFL )
{
@@ -686,7 +640,7 @@
dict->has_font_matrix = TRUE;
- /* We expect a well-formed font matrix, this is, the matrix elements */
+ /* We expect a well-formed font matrix, that is, the matrix elements */
/* `xx' and `yy' are of approximately the same magnitude. To avoid */
/* loss of precision, we use the magnitude of the largest matrix */
/* element to scale all other elements. The scaling factor is then */
@@ -1264,11 +1218,8 @@
FT_Byte* charstring_base;
FT_ULong charstring_len;
- FT_Fixed* stack;
- FT_ListNode node;
- CFF_T2_String t2;
- FT_Fixed t2_size;
- FT_Byte* q;
+ FT_Fixed* stack;
+ FT_Byte* q = NULL;
charstring_base = ++p;
@@ -1309,39 +1260,18 @@
/* Now copy the stack data in the temporary decoder object, */
/* converting it back to charstring number representations */
/* (this is ugly, I know). */
+ /* The maximum required size is 5 bytes per stack element. */
+ if ( FT_QALLOC( q, (FT_Long)( 2 * sizeof ( FT_ListNode ) ) +
+ 5 * ( decoder.top - decoder.stack ) ) )
+ goto Exit;
- node = (FT_ListNode)memory->alloc( memory,
- sizeof ( FT_ListNodeRec ) );
- if ( !node )
- goto Out_Of_Memory_Error;
-
- FT_List_Add( &parser->t2_strings, node );
-
- t2 = (CFF_T2_String)memory->alloc( memory,
- sizeof ( CFF_T2_StringRec ) );
- if ( !t2 )
- goto Out_Of_Memory_Error;
-
- node->data = t2;
-
- /* `5' is the conservative upper bound of required bytes per stack */
- /* element. */
-
- t2_size = 5 * ( decoder.top - decoder.stack );
-
- q = (FT_Byte*)memory->alloc( memory, t2_size );
- if ( !q )
- goto Out_Of_Memory_Error;
-
- t2->start = q;
- t2->limit = q + t2_size;
+ FT_List_Add( &parser->t2_strings, (FT_ListNode)q );
- stack = decoder.stack;
+ q += 2 * sizeof ( FT_ListNode );
- while ( stack < decoder.top )
+ for ( stack = decoder.stack; stack < decoder.top; stack++ )
{
- FT_ULong num;
- FT_Bool neg;
+ FT_Long num = *stack;
if ( (FT_UInt)( parser->top - parser->stack ) >= parser->stackSize )
@@ -1349,69 +1279,37 @@
*parser->top++ = q;
- if ( *stack < 0 )
- {
- num = (FT_ULong)NEG_LONG( *stack );
- neg = 1;
- }
- else
- {
- num = (FT_ULong)*stack;
- neg = 0;
- }
-
if ( num & 0xFFFFU )
{
- if ( neg )
- num = (FT_ULong)-num;
-
*q++ = 255;
- *q++ = ( num & 0xFF000000U ) >> 24;
- *q++ = ( num & 0x00FF0000U ) >> 16;
- *q++ = ( num & 0x0000FF00U ) >> 8;
- *q++ = num & 0x000000FFU;
+ *q++ = (FT_Byte)( ( num >> 24 ) & 0xFF );
+ *q++ = (FT_Byte)( ( num >> 16 ) & 0xFF );
+ *q++ = (FT_Byte)( ( num >> 8 ) & 0xFF );
+ *q++ = (FT_Byte)( ( num ) & 0xFF );
}
else
{
num >>= 16;
- if ( neg )
+ if ( -107 <= num && num <= 107 )
+ *q++ = (FT_Byte)( num + 139 );
+ else if ( 108 <= num && num <= 1131 )
{
- if ( num <= 107 )
- *q++ = (FT_Byte)( 139 - num );
- else if ( num <= 1131 )
- {
- *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 251 );
- *q++ = (FT_Byte)( ( num - 108 ) & 0xFF );
- }
- else
- {
- num = (FT_ULong)-num;
-
- *q++ = 28;
- *q++ = (FT_Byte)( num >> 8 );
- *q++ = (FT_Byte)( num & 0xFF );
- }
+ *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 247 );
+ *q++ = (FT_Byte)( ( num - 108 ) & 0xFF );
+ }
+ else if ( -1131 <= num && num <= -108 )
+ {
+ *q++ = (FT_Byte)( ( ( -num - 108 ) >> 8 ) + 251 );
+ *q++ = (FT_Byte)( ( -num - 108) & 0xFF );
}
else
{
- if ( num <= 107 )
- *q++ = (FT_Byte)( num + 139 );
- else if ( num <= 1131 )
- {
- *q++ = (FT_Byte)( ( ( num - 108 ) >> 8 ) + 247 );
- *q++ = (FT_Byte)( ( num - 108 ) & 0xFF );
- }
- else
- {
- *q++ = 28;
- *q++ = (FT_Byte)( num >> 8 );
- *q++ = (FT_Byte)( num & 0xFF );
- }
+ *q++ = 28;
+ *q++ = (FT_Byte)( num >> 8 );
+ *q++ = (FT_Byte)( num & 0xFF );
}
}
-
- stack++;
}
}
#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
@@ -1598,12 +1496,6 @@
Exit:
return error;
-#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
- Out_Of_Memory_Error:
- error = FT_THROW( Out_Of_Memory );
- goto Exit;
-#endif
-
Stack_Overflow:
error = FT_THROW( Invalid_Argument );
goto Exit;
diff --git a/src/3rdparty/freetype/src/cff/cffparse.h b/src/3rdparty/freetype/src/cff/cffparse.h
index 58d59fa4ac..418caacc68 100644
--- a/src/3rdparty/freetype/src/cff/cffparse.h
+++ b/src/3rdparty/freetype/src/cff/cffparse.h
@@ -76,6 +76,10 @@ FT_BEGIN_HEADER
cff_parse_num( CFF_Parser parser,
FT_Byte** d );
+ FT_LOCAL( FT_Fixed )
+ cff_parse_fixed( CFF_Parser parser,
+ FT_Byte** d );
+
FT_LOCAL( FT_Error )
cff_parser_init( CFF_Parser parser,
FT_UInt code,
@@ -133,15 +137,6 @@ FT_BEGIN_HEADER
FT_END_HEADER
-#ifdef CFF_CONFIG_OPTION_OLD_ENGINE
- typedef struct CFF_T2_String_
- {
- FT_Byte* start;
- FT_Byte* limit;
-
- } CFF_T2_StringRec, *CFF_T2_String;
-#endif /* CFF_CONFIG_OPTION_OLD_ENGINE */
-
#endif /* CFFPARSE_H_ */
diff --git a/src/3rdparty/freetype/src/cid/cidgload.c b/src/3rdparty/freetype/src/cid/cidgload.c
index ba4b7565d5..eaca765ad0 100644
--- a/src/3rdparty/freetype/src/cid/cidgload.c
+++ b/src/3rdparty/freetype/src/cid/cidgload.c
@@ -40,6 +40,117 @@
#define FT_COMPONENT cidgload
+ /*
+ * A helper function to compute FD number (`fd_select`), the offset to the
+ * head of the glyph data (`off1`), and the offset to the and of the glyph
+ * data (`off2`).
+ *
+ * The number how many times `cid_get_offset` is invoked can be controlled
+ * by the number of non-NULL arguments. If `fd_select` is non-NULL but
+ * `off1` and `off2` are NULL, `cid_get_offset` is invoked only for
+ * `fd_select`; `off1` and `off2` are not validated.
+ *
+ */
+ FT_LOCAL_DEF( FT_Error )
+ cid_compute_fd_and_offsets( CID_Face face,
+ FT_UInt glyph_index,
+ FT_ULong* fd_select_p,
+ FT_ULong* off1_p,
+ FT_ULong* off2_p )
+ {
+ FT_Error error = FT_Err_Ok;
+
+ CID_FaceInfo cid = &face->cid;
+ FT_Stream stream = face->cid_stream;
+ FT_UInt entry_len = cid->fd_bytes + cid->gd_bytes;
+
+ FT_Byte* p;
+ FT_Bool need_frame_exit = 0;
+ FT_ULong fd_select, off1, off2;
+
+
+ /* For ordinary fonts, read the CID font dictionary index */
+ /* and charstring offset from the CIDMap. */
+
+ if ( FT_STREAM_SEEK( cid->data_offset + cid->cidmap_offset +
+ glyph_index * entry_len ) ||
+ FT_FRAME_ENTER( 2 * entry_len ) )
+ goto Exit;
+
+ need_frame_exit = 1;
+
+ p = (FT_Byte*)stream->cursor;
+ fd_select = cid_get_offset( &p, cid->fd_bytes );
+ off1 = cid_get_offset( &p, cid->gd_bytes );
+
+ p += cid->fd_bytes;
+ off2 = cid_get_offset( &p, cid->gd_bytes );
+
+ if ( fd_select_p )
+ *fd_select_p = fd_select;
+ if ( off1_p )
+ *off1_p = off1;
+ if ( off2_p )
+ *off2_p = off2;
+
+ if ( fd_select >= cid->num_dicts )
+ {
+ /*
+ * fd_select == 0xFF is often used to indicate that the CID
+ * has no charstring to be rendered, similar to GID = 0xFFFF
+ * in TrueType fonts.
+ */
+ if ( ( cid->fd_bytes == 1 && fd_select == 0xFFU ) ||
+ ( cid->fd_bytes == 2 && fd_select == 0xFFFFU ) )
+ {
+ FT_TRACE1(( "cid_load_glyph: fail for glyph index %d:\n",
+ glyph_index ));
+ FT_TRACE1(( " FD number %ld is the maximum\n",
+ fd_select ));
+ FT_TRACE1(( " integer fitting into %d byte%s\n",
+ cid->fd_bytes, cid->fd_bytes == 1 ? "" : "s" ));
+ }
+ else
+ {
+ FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n",
+ glyph_index ));
+ FT_TRACE0(( " FD number %ld is larger\n",
+ fd_select ));
+ FT_TRACE0(( " than number of dictionaries (%d)\n",
+ cid->num_dicts ));
+ }
+
+ error = FT_THROW( Invalid_Offset );
+ goto Exit;
+ }
+ else if ( off2 > stream->size )
+ {
+ FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n",
+ glyph_index ));
+ FT_TRACE0(( " end of the glyph data\n" ));
+ FT_TRACE0(( " is beyond the data stream\n" ));
+
+ error = FT_THROW( Invalid_Offset );
+ goto Exit;
+ }
+ else if ( off1 > off2 )
+ {
+ FT_TRACE0(( "cid_load_glyph: fail for glyph index %d:\n",
+ glyph_index ));
+ FT_TRACE0(( " the end position of glyph data\n" ));
+ FT_TRACE0(( " is set before the start position\n" ));
+
+ error = FT_THROW( Invalid_Offset );
+ }
+
+ Exit:
+ if ( need_frame_exit )
+ FT_FRAME_EXIT();
+
+ return error;
+ }
+
+
FT_CALLBACK_DEF( FT_Error )
cid_load_glyph( T1_Decoder decoder,
FT_UInt glyph_index )
@@ -97,34 +208,14 @@
else
#endif /* FT_CONFIG_OPTION_INCREMENTAL */
-
- /* For ordinary fonts read the CID font dictionary index */
- /* and charstring offset from the CIDMap. */
{
- FT_UInt entry_len = cid->fd_bytes + cid->gd_bytes;
FT_ULong off1, off2;
- if ( FT_STREAM_SEEK( cid->data_offset + cid->cidmap_offset +
- glyph_index * entry_len ) ||
- FT_FRAME_ENTER( 2 * entry_len ) )
- goto Exit;
-
- p = (FT_Byte*)stream->cursor;
- fd_select = cid_get_offset( &p, cid->fd_bytes );
- off1 = cid_get_offset( &p, cid->gd_bytes );
- p += cid->fd_bytes;
- off2 = cid_get_offset( &p, cid->gd_bytes );
- FT_FRAME_EXIT();
-
- if ( fd_select >= cid->num_dicts ||
- off2 > stream->size ||
- off1 > off2 )
- {
- FT_TRACE0(( "cid_load_glyph: invalid glyph stream offsets\n" ));
- error = FT_THROW( Invalid_Offset );
+ error = cid_compute_fd_and_offsets( face, glyph_index,
+ &fd_select, &off1, &off2 );
+ if ( error )
goto Exit;
- }
glyph_length = off2 - off1;
@@ -161,7 +252,9 @@
cs_offset = decoder->lenIV >= 0 ? (FT_UInt)decoder->lenIV : 0;
if ( cs_offset > glyph_length )
{
- FT_TRACE0(( "cid_load_glyph: invalid glyph stream offsets\n" ));
+ FT_TRACE0(( "cid_load_glyph: fail for glyph_index=%d, "
+ "offset to the charstring is beyond glyph length\n",
+ glyph_index ));
error = FT_THROW( Invalid_Offset );
goto Exit;
}
diff --git a/src/3rdparty/freetype/src/cid/cidgload.h b/src/3rdparty/freetype/src/cid/cidgload.h
index 97954d418f..edd6229234 100644
--- a/src/3rdparty/freetype/src/cid/cidgload.h
+++ b/src/3rdparty/freetype/src/cid/cidgload.h
@@ -42,6 +42,14 @@ FT_BEGIN_HEADER
FT_Int32 load_flags );
+ FT_LOCAL( FT_Error )
+ cid_compute_fd_and_offsets( CID_Face face,
+ FT_UInt glyph_index,
+ FT_ULong* fd_select_p,
+ FT_ULong* off1_p,
+ FT_ULong* off2_p );
+
+
FT_END_HEADER
#endif /* CIDGLOAD_H_ */
diff --git a/src/3rdparty/freetype/src/cid/cidload.c b/src/3rdparty/freetype/src/cid/cidload.c
index 26daa5da7f..a7da8ea39d 100644
--- a/src/3rdparty/freetype/src/cid/cidload.c
+++ b/src/3rdparty/freetype/src/cid/cidload.c
@@ -155,23 +155,24 @@
FT_CALLBACK_DEF( void )
- cid_parse_font_matrix( CID_Face face,
- CID_Parser* parser )
+ cid_parse_font_matrix( FT_Face face, /* CID_Face */
+ void* parser_ )
{
+ CID_Face cidface = (CID_Face)face;
+ CID_Parser* parser = (CID_Parser*)parser_;
CID_FaceDict dict;
- FT_Face root = (FT_Face)&face->root;
FT_Fixed temp[6];
FT_Fixed temp_scale;
- if ( parser->num_dict < face->cid.num_dicts )
+ if ( parser->num_dict < cidface->cid.num_dicts )
{
FT_Matrix* matrix;
FT_Vector* offset;
FT_Int result;
- dict = face->cid.font_dicts + parser->num_dict;
+ dict = cidface->cid.font_dicts + parser->num_dict;
matrix = &dict->font_matrix;
offset = &dict->font_offset;
@@ -204,7 +205,7 @@
if ( temp_scale != 0x10000L )
{
/* set units per EM based on FontMatrix values */
- root->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale );
+ face->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale );
temp[0] = FT_DivFix( temp[0], temp_scale );
temp[1] = FT_DivFix( temp[1], temp_scale );
@@ -237,13 +238,15 @@
FT_CALLBACK_DEF( void )
- parse_fd_array( CID_Face face,
- CID_Parser* parser )
+ parse_fd_array( FT_Face face, /* CID_Face */
+ void* parser_ )
{
- CID_FaceInfo cid = &face->cid;
- FT_Memory memory = face->root.memory;
- FT_Stream stream = parser->stream;
- FT_Error error = FT_Err_Ok;
+ CID_Face cidface = (CID_Face)face;
+ CID_Parser* parser = (CID_Parser*)parser_;
+ CID_FaceInfo cid = &cidface->cid;
+ FT_Memory memory = FT_FACE_MEMORY( face );
+ FT_Stream stream = parser->stream;
+ FT_Error error = FT_Err_Ok;
FT_Long num_dicts, max_dicts;
@@ -313,18 +316,20 @@
/* By mistake, `expansion_factor' appears both in PS_PrivateRec */
/* and CID_FaceDictRec (both are public header files and can't */
- /* changed). We simply copy the value. */
+ /* be thus changed). We simply copy the value. */
FT_CALLBACK_DEF( void )
- parse_expansion_factor( CID_Face face,
- CID_Parser* parser )
+ parse_expansion_factor( FT_Face face, /* CID_Face */
+ void* parser_ )
{
+ CID_Face cidface = (CID_Face)face;
+ CID_Parser* parser = (CID_Parser*)parser_;
CID_FaceDict dict;
- if ( parser->num_dict < face->cid.num_dicts )
+ if ( parser->num_dict < cidface->cid.num_dicts )
{
- dict = face->cid.font_dicts + parser->num_dict;
+ dict = cidface->cid.font_dicts + parser->num_dict;
dict->expansion_factor = cid_parser_to_fixed( parser, 0 );
dict->private_dict.expansion_factor = dict->expansion_factor;
@@ -341,11 +346,15 @@
/* to catch it for producing better trace output. */
FT_CALLBACK_DEF( void )
- parse_font_name( CID_Face face,
- CID_Parser* parser )
+ parse_font_name( FT_Face face, /* CID_Face */
+ void* parser_ )
{
#ifdef FT_DEBUG_LEVEL_TRACE
- if ( parser->num_dict < face->cid.num_dicts )
+ CID_Face cidface = (CID_Face)face;
+ CID_Parser* parser = (CID_Parser*)parser_;
+
+
+ if ( parser->num_dict < cidface->cid.num_dicts )
{
T1_TokenRec token;
FT_UInt len;
@@ -361,7 +370,7 @@
}
#else
FT_UNUSED( face );
- FT_UNUSED( parser );
+ FT_UNUSED( parser_ );
#endif
return;
diff --git a/src/3rdparty/freetype/src/cid/cidobjs.c b/src/3rdparty/freetype/src/cid/cidobjs.c
index 06b2139a93..f698a41928 100644
--- a/src/3rdparty/freetype/src/cid/cidobjs.c
+++ b/src/3rdparty/freetype/src/cid/cidobjs.c
@@ -69,8 +69,7 @@
FT_Module module;
- module = FT_Get_Module( slot->face->driver->root.library,
- "pshinter" );
+ module = FT_Get_Module( slot->library, "pshinter" );
if ( module )
{
T1_Hints_Funcs funcs;
@@ -268,7 +267,8 @@
*
* @Input:
* stream ::
- * The source font stream.
+ * Dummy argument for compatibility with the `FT_Face_InitFunc` API.
+ * Ignored. The stream should be passed through `face->root.stream`.
*
* face_index ::
* The index of the font face in the resource.
@@ -375,6 +375,14 @@
if ( info->is_fixed_pitch )
cidface->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+ /*
+ * For the sfnt-wrapped CID fonts for MacOS, currently,
+ * its `cmap' tables are ignored, and the content in
+ * its `CID ' table is treated the same as naked CID-keyed
+ * font. See ft_lookup_PS_in_sfnt_stream().
+ */
+ cidface->face_flags |= FT_FACE_FLAG_CID_KEYED;
+
/* XXX: TODO: add kerning with .afm support */
/* get style name -- be careful, some broken fonts only */
diff --git a/src/3rdparty/freetype/src/cid/cidparse.c b/src/3rdparty/freetype/src/cid/cidparse.c
index 16889db9b6..171a886215 100644
--- a/src/3rdparty/freetype/src/cid/cidparse.c
+++ b/src/3rdparty/freetype/src/cid/cidparse.c
@@ -214,18 +214,24 @@
cur <= limit - STARTDATA_LEN &&
ft_strncmp( (char*)cur, STARTDATA, STARTDATA_LEN ) == 0 )
{
- if ( ft_strncmp( (char*)arg1, "(Hex)", 5 ) == 0 )
- {
- FT_Long tmp = ft_strtol( (const char *)arg2, NULL, 10 );
+ T1_TokenRec type_token;
+ FT_Long binary_length;
- if ( tmp < 0 )
+ parser->root.cursor = arg1;
+ cid_parser_to_token( parser, &type_token );
+ if ( type_token.limit - type_token.start == 5 &&
+ ft_memcmp( (char*)type_token.start, "(Hex)", 5 ) == 0 )
+ {
+ parser->root.cursor = arg2;
+ binary_length = cid_parser_to_int( parser );
+ if ( binary_length < 0 )
{
FT_ERROR(( "cid_parser_new: invalid length of hex data\n" ));
error = FT_THROW( Invalid_File_Format );
}
else
- parser->binary_length = (FT_ULong)tmp;
+ parser->binary_length = (FT_ULong)binary_length;
}
goto Exit;
diff --git a/src/3rdparty/freetype/src/cid/cidriver.c b/src/3rdparty/freetype/src/cid/cidriver.c
index f7499237d7..99e7b11839 100644
--- a/src/3rdparty/freetype/src/cid/cidriver.c
+++ b/src/3rdparty/freetype/src/cid/cidriver.c
@@ -48,10 +48,11 @@
*
*/
- static const char*
- cid_get_postscript_name( CID_Face face )
+ FT_CALLBACK_DEF( const char* )
+ cid_get_postscript_name( FT_Face face ) /* CID_Face */
{
- const char* result = face->cid.cid_font_name;
+ CID_Face cidface = (CID_Face)face;
+ const char* result = cidface->cid.cid_font_name;
if ( result && result[0] == '/' )
@@ -72,34 +73,36 @@
*
*/
- static FT_Error
- cid_ps_get_font_info( FT_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cid_ps_get_font_info( FT_Face face, /* CID_Face */
PS_FontInfoRec* afont_info )
{
- *afont_info = ((CID_Face)face)->cid.font_info;
+ *afont_info = ( (CID_Face)face )->cid.font_info;
return FT_Err_Ok;
}
- static FT_Error
- cid_ps_get_font_extra( FT_Face face,
- PS_FontExtraRec* afont_extra )
+
+ FT_CALLBACK_DEF( FT_Error )
+ cid_ps_get_font_extra( FT_Face face, /* CID_Face */
+ PS_FontExtraRec* afont_extra )
{
- *afont_extra = ((CID_Face)face)->font_extra;
+ *afont_extra = ( (CID_Face)face )->font_extra;
return FT_Err_Ok;
}
+
static const FT_Service_PsInfoRec cid_service_ps_info =
{
- (PS_GetFontInfoFunc) cid_ps_get_font_info, /* ps_get_font_info */
- (PS_GetFontExtraFunc) cid_ps_get_font_extra, /* ps_get_font_extra */
+ cid_ps_get_font_info, /* PS_GetFontInfoFunc ps_get_font_info */
+ cid_ps_get_font_extra, /* PS_GetFontExtraFunc ps_get_font_extra */
/* unsupported with CID fonts */
- (PS_HasGlyphNamesFunc) NULL, /* ps_has_glyph_names */
+ NULL, /* PS_HasGlyphNamesFunc ps_has_glyph_names */
/* unsupported */
- (PS_GetFontPrivateFunc)NULL, /* ps_get_font_private */
+ NULL, /* PS_GetFontPrivateFunc ps_get_font_private */
/* not implemented */
- (PS_GetFontValueFunc) NULL /* ps_get_font_value */
+ NULL /* PS_GetFontValueFunc ps_get_font_value */
};
@@ -107,13 +110,14 @@
* CID INFO SERVICE
*
*/
- static FT_Error
- cid_get_ros( CID_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cid_get_ros( FT_Face face, /* CID_Face */
const char* *registry,
const char* *ordering,
FT_Int *supplement )
{
- CID_FaceInfo cid = &face->cid;
+ CID_Face cidface = (CID_Face)face;
+ CID_FaceInfo cid = &cidface->cid;
if ( registry )
@@ -129,32 +133,48 @@
}
- static FT_Error
- cid_get_is_cid( CID_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cid_get_is_cid( FT_Face face, /* CID_Face */
FT_Bool *is_cid )
{
FT_Error error = FT_Err_Ok;
FT_UNUSED( face );
+ /*
+ * XXX: If the ROS is Adobe-Identity-H or -V,
+ * the font has no reliable information about
+ * its glyph collection. Should we not set
+ * *is_cid in such cases?
+ */
if ( is_cid )
- *is_cid = 1; /* cid driver is only used for CID keyed fonts */
+ *is_cid = 1;
return error;
}
- static FT_Error
- cid_get_cid_from_glyph_index( CID_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ cid_get_cid_from_glyph_index( FT_Face face, /* CID_Face */
FT_UInt glyph_index,
FT_UInt *cid )
{
- FT_Error error = FT_Err_Ok;
- FT_UNUSED( face );
-
-
- if ( cid )
- *cid = glyph_index; /* identity mapping */
+ FT_Error error = FT_Err_Ok;
+ CID_Face cidface = (CID_Face)face;
+
+
+ /*
+ * Currently, FreeType does not support incrementally-defined, CID-keyed
+ * fonts that store the glyph description data in a `/GlyphDirectory`
+ * array or dictionary. Fonts loaded by the incremental loading feature
+ * are thus not handled here.
+ */
+ error = cid_compute_fd_and_offsets( cidface, glyph_index,
+ NULL, NULL, NULL );
+ if ( error )
+ *cid = 0;
+ else
+ *cid = glyph_index;
return error;
}
@@ -162,12 +182,12 @@
static const FT_Service_CIDRec cid_service_cid_info =
{
- (FT_CID_GetRegistryOrderingSupplementFunc)
- cid_get_ros, /* get_ros */
- (FT_CID_GetIsInternallyCIDKeyedFunc)
- cid_get_is_cid, /* get_is_cid */
- (FT_CID_GetCIDFromGlyphIndexFunc)
- cid_get_cid_from_glyph_index /* get_cid_from_glyph_index */
+ cid_get_ros,
+ /* FT_CID_GetRegistryOrderingSupplementFunc get_ros */
+ cid_get_is_cid,
+ /* FT_CID_GetIsInternallyCIDKeyedFunc get_is_cid */
+ cid_get_cid_from_glyph_index
+ /* FT_CID_GetCIDFromGlyphIndexFunc get_cid_from_glyph_index */
};
@@ -179,9 +199,9 @@
FT_DEFINE_SERVICE_PROPERTIESREC(
cid_service_properties,
- (FT_Properties_SetFunc)ps_property_set, /* set_property */
- (FT_Properties_GetFunc)ps_property_get ) /* get_property */
-
+ ps_property_set, /* FT_Properties_SetFunc set_property */
+ ps_property_get /* FT_Properties_GetFunc get_property */
+ )
/*
* SERVICE LIST
@@ -209,7 +229,6 @@
}
-
FT_CALLBACK_TABLE_DEF
const FT_Driver_ClassRec t1cid_driver_class =
{
diff --git a/src/3rdparty/freetype/src/dlg/dlgwrap.c b/src/3rdparty/freetype/src/dlg/dlgwrap.c
index 271241f0a8..e9dc3410a4 100644
--- a/src/3rdparty/freetype/src/dlg/dlgwrap.c
+++ b/src/3rdparty/freetype/src/dlg/dlgwrap.c
@@ -25,7 +25,7 @@
#include "dlg.c"
#else
/* ANSI C doesn't like empty source files */
- typedef int _dlg_dummy;
+ typedef int dlg_dummy_;
#endif
diff --git a/src/3rdparty/freetype/src/gxvalid/gxvfgen.c b/src/3rdparty/freetype/src/gxvalid/gxvfgen.c
index 1153542286..cf98bb36c3 100644
--- a/src/3rdparty/freetype/src/gxvalid/gxvfgen.c
+++ b/src/3rdparty/freetype/src/gxvalid/gxvfgen.c
@@ -97,7 +97,8 @@
#define EMPTYFEAT {0, 0, {NULL}}
- static GX_Feature_RegistryRec featreg_table[] = {
+ static GX_Feature_RegistryRec featreg_table[] =
+ {
{ /* 0 */
"All Typographic Features",
0,
diff --git a/src/3rdparty/freetype/src/gzip/README.freetype b/src/3rdparty/freetype/src/gzip/README.freetype
index e0c8ced180..76298b06b5 100644
--- a/src/3rdparty/freetype/src/gzip/README.freetype
+++ b/src/3rdparty/freetype/src/gzip/README.freetype
@@ -1,7 +1,7 @@
Name: zlib
Short Name: zlib
URL: http://zlib.net/
-Version: 1.2.12
+Version: 1.2.13
License: see `zlib.h`
Description:
diff --git a/src/3rdparty/freetype/src/gzip/ftgzip.c b/src/3rdparty/freetype/src/gzip/ftgzip.c
index 48da6ff9c7..ca6a2aabe6 100644
--- a/src/3rdparty/freetype/src/gzip/ftgzip.c
+++ b/src/3rdparty/freetype/src/gzip/ftgzip.c
@@ -70,10 +70,9 @@
/* so that configuration with `FT_CONFIG_OPTION_SYSTEM_ZLIB' might */
/* include the wrong `zconf.h' file, leading to errors. */
-#if defined( __GNUC__ ) || defined( __clang__ )
#define ZEXPORT
-#define ZEXTERN static
-#endif
+ /* prevent zlib functions from being visible outside their object files */
+#define ZEXTERN static
#define HAVE_MEMCPY 1
#define Z_SOLO 1
diff --git a/src/3rdparty/freetype/src/gzip/infback.c b/src/3rdparty/freetype/src/gzip/infback.c
deleted file mode 100644
index 264c14e0df..0000000000
--- a/src/3rdparty/freetype/src/gzip/infback.c
+++ /dev/null
@@ -1,644 +0,0 @@
-/* infback.c -- inflate using a call-back interface
- * Copyright (C) 1995-2022 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h
- */
-
-/*
- This code is largely copied from inflate.c. Normally either infback.o or
- inflate.o would be linked into an application--not both. The interface
- with inffast.c is retained so that optimized assembler-coded versions of
- inflate_fast() can be used with either inflate.c or infback.c.
- */
-
-#include "zutil.h"
-#include "inftrees.h"
-#include "inflate.h"
-#include "inffast.h"
-
-/* function prototypes */
-local void fixedtables OF((struct inflate_state FAR *state));
-
-/*
- strm provides memory allocation functions in zalloc and zfree, or
- Z_NULL to use the library memory allocation functions.
-
- windowBits is in the range 8..15, and window is a user-supplied
- window and output buffer that is 2**windowBits bytes.
- */
-int ZEXPORT inflateBackInit_(
- z_streamp strm,
- int windowBits,
- unsigned char FAR *window,
- const char *version,
- int stream_size)
-{
- struct inflate_state FAR *state;
-
- if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
- stream_size != (int)(sizeof(z_stream)))
- return Z_VERSION_ERROR;
- if (strm == Z_NULL || window == Z_NULL ||
- windowBits < 8 || windowBits > 15)
- return Z_STREAM_ERROR;
- strm->msg = Z_NULL; /* in case we return an error */
- if (strm->zalloc == (alloc_func)0) {
-#ifdef Z_SOLO
- return Z_STREAM_ERROR;
-#else
- strm->zalloc = zcalloc;
- strm->opaque = (voidpf)0;
-#endif
- }
- if (strm->zfree == (free_func)0)
-#ifdef Z_SOLO
- return Z_STREAM_ERROR;
-#else
- strm->zfree = zcfree;
-#endif
- state = (struct inflate_state FAR *)ZALLOC(strm, 1,
- sizeof(struct inflate_state));
- if (state == Z_NULL) return Z_MEM_ERROR;
- Tracev((stderr, "inflate: allocated\n"));
- strm->state = (struct internal_state FAR *)state;
- state->dmax = 32768U;
- state->wbits = (uInt)windowBits;
- state->wsize = 1U << windowBits;
- state->window = window;
- state->wnext = 0;
- state->whave = 0;
- state->sane = 1;
- return Z_OK;
-}
-
-/*
- Return state with length and distance decoding tables and index sizes set to
- fixed code decoding. Normally this returns fixed tables from inffixed.h.
- If BUILDFIXED is defined, then instead this routine builds the tables the
- first time it's called, and returns those tables the first time and
- thereafter. This reduces the size of the code by about 2K bytes, in
- exchange for a little execution time. However, BUILDFIXED should not be
- used for threaded applications, since the rewriting of the tables and virgin
- may not be thread-safe.
- */
-local void fixedtables(
- struct inflate_state FAR *state)
-{
-#ifdef BUILDFIXED
- static int virgin = 1;
- static code *lenfix, *distfix;
- static code fixed[544];
-
- /* build fixed huffman tables if first call (may not be thread safe) */
- if (virgin) {
- unsigned sym, bits;
- static code *next;
-
- /* literal/length table */
- sym = 0;
- while (sym < 144) state->lens[sym++] = 8;
- while (sym < 256) state->lens[sym++] = 9;
- while (sym < 280) state->lens[sym++] = 7;
- while (sym < 288) state->lens[sym++] = 8;
- next = fixed;
- lenfix = next;
- bits = 9;
- inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
-
- /* distance table */
- sym = 0;
- while (sym < 32) state->lens[sym++] = 5;
- distfix = next;
- bits = 5;
- inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
-
- /* do this just once */
- virgin = 0;
- }
-#else /* !BUILDFIXED */
-# include "inffixed.h"
-#endif /* BUILDFIXED */
- state->lencode = lenfix;
- state->lenbits = 9;
- state->distcode = distfix;
- state->distbits = 5;
-}
-
-/* Macros for inflateBack(): */
-
-/* Load returned state from inflate_fast() */
-#define LOAD() \
- do { \
- put = strm->next_out; \
- left = strm->avail_out; \
- next = strm->next_in; \
- have = strm->avail_in; \
- hold = state->hold; \
- bits = state->bits; \
- } while (0)
-
-/* Set state from registers for inflate_fast() */
-#define RESTORE() \
- do { \
- strm->next_out = put; \
- strm->avail_out = left; \
- strm->next_in = next; \
- strm->avail_in = have; \
- state->hold = hold; \
- state->bits = bits; \
- } while (0)
-
-/* Clear the input bit accumulator */
-#define INITBITS() \
- do { \
- hold = 0; \
- bits = 0; \
- } while (0)
-
-/* Assure that some input is available. If input is requested, but denied,
- then return a Z_BUF_ERROR from inflateBack(). */
-#define PULL() \
- do { \
- if (have == 0) { \
- have = in(in_desc, &next); \
- if (have == 0) { \
- next = Z_NULL; \
- ret = Z_BUF_ERROR; \
- goto inf_leave; \
- } \
- } \
- } while (0)
-
-/* Get a byte of input into the bit accumulator, or return from inflateBack()
- with an error if there is no input available. */
-#define PULLBYTE() \
- do { \
- PULL(); \
- have--; \
- hold += (unsigned long)(*next++) << bits; \
- bits += 8; \
- } while (0)
-
-/* Assure that there are at least n bits in the bit accumulator. If there is
- not enough available input to do that, then return from inflateBack() with
- an error. */
-#define NEEDBITS(n) \
- do { \
- while (bits < (unsigned)(n)) \
- PULLBYTE(); \
- } while (0)
-
-/* Return the low n bits of the bit accumulator (n < 16) */
-#define BITS(n) \
- ((unsigned)hold & ((1U << (n)) - 1))
-
-/* Remove n bits from the bit accumulator */
-#define DROPBITS(n) \
- do { \
- hold >>= (n); \
- bits -= (unsigned)(n); \
- } while (0)
-
-/* Remove zero to seven bits as needed to go to a byte boundary */
-#define BYTEBITS() \
- do { \
- hold >>= bits & 7; \
- bits -= bits & 7; \
- } while (0)
-
-/* Assure that some output space is available, by writing out the window
- if it's full. If the write fails, return from inflateBack() with a
- Z_BUF_ERROR. */
-#define ROOM() \
- do { \
- if (left == 0) { \
- put = state->window; \
- left = state->wsize; \
- state->whave = left; \
- if (out(out_desc, put, left)) { \
- ret = Z_BUF_ERROR; \
- goto inf_leave; \
- } \
- } \
- } while (0)
-
-/*
- strm provides the memory allocation functions and window buffer on input,
- and provides information on the unused input on return. For Z_DATA_ERROR
- returns, strm will also provide an error message.
-
- in() and out() are the call-back input and output functions. When
- inflateBack() needs more input, it calls in(). When inflateBack() has
- filled the window with output, or when it completes with data in the
- window, it calls out() to write out the data. The application must not
- change the provided input until in() is called again or inflateBack()
- returns. The application must not change the window/output buffer until
- inflateBack() returns.
-
- in() and out() are called with a descriptor parameter provided in the
- inflateBack() call. This parameter can be a structure that provides the
- information required to do the read or write, as well as accumulated
- information on the input and output such as totals and check values.
-
- in() should return zero on failure. out() should return non-zero on
- failure. If either in() or out() fails, than inflateBack() returns a
- Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it
- was in() or out() that caused in the error. Otherwise, inflateBack()
- returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
- error, or Z_MEM_ERROR if it could not allocate memory for the state.
- inflateBack() can also return Z_STREAM_ERROR if the input parameters
- are not correct, i.e. strm is Z_NULL or the state was not initialized.
- */
-int ZEXPORT inflateBack(
- z_streamp strm,
- in_func in,
- void FAR *in_desc,
- out_func out,
- void FAR *out_desc)
-{
- struct inflate_state FAR *state;
- z_const unsigned char FAR *next; /* next input */
- unsigned char FAR *put; /* next output */
- unsigned have, left; /* available input and output */
- unsigned long hold; /* bit buffer */
- unsigned bits; /* bits in bit buffer */
- unsigned copy; /* number of stored or match bytes to copy */
- unsigned char FAR *from; /* where to copy match bytes from */
- code here; /* current decoding table entry */
- code last; /* parent table entry */
- unsigned len; /* length to copy for repeats, bits to drop */
- int ret; /* return code */
- static const unsigned short order[19] = /* permutation of code lengths */
- {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
-
- /* Check that the strm exists and that the state was initialized */
- if (strm == Z_NULL || strm->state == Z_NULL)
- return Z_STREAM_ERROR;
- state = (struct inflate_state FAR *)strm->state;
-
- /* Reset the state */
- strm->msg = Z_NULL;
- state->mode = TYPE;
- state->last = 0;
- state->whave = 0;
- next = strm->next_in;
- have = next != Z_NULL ? strm->avail_in : 0;
- hold = 0;
- bits = 0;
- put = state->window;
- left = state->wsize;
-
- /* Inflate until end of block marked as last */
- for (;;)
- switch (state->mode) {
- case TYPE:
- /* determine and dispatch block type */
- if (state->last) {
- BYTEBITS();
- state->mode = DONE;
- break;
- }
- NEEDBITS(3);
- state->last = BITS(1);
- DROPBITS(1);
- switch (BITS(2)) {
- case 0: /* stored block */
- Tracev((stderr, "inflate: stored block%s\n",
- state->last ? " (last)" : ""));
- state->mode = STORED;
- break;
- case 1: /* fixed block */
- fixedtables(state);
- Tracev((stderr, "inflate: fixed codes block%s\n",
- state->last ? " (last)" : ""));
- state->mode = LEN; /* decode codes */
- break;
- case 2: /* dynamic block */
- Tracev((stderr, "inflate: dynamic codes block%s\n",
- state->last ? " (last)" : ""));
- state->mode = TABLE;
- break;
- case 3:
- strm->msg = (char *)"invalid block type";
- state->mode = BAD;
- }
- DROPBITS(2);
- break;
-
- case STORED:
- /* get and verify stored block length */
- BYTEBITS(); /* go to byte boundary */
- NEEDBITS(32);
- if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
- strm->msg = (char *)"invalid stored block lengths";
- state->mode = BAD;
- break;
- }
- state->length = (unsigned)hold & 0xffff;
- Tracev((stderr, "inflate: stored length %u\n",
- state->length));
- INITBITS();
-
- /* copy stored block from input to output */
- while (state->length != 0) {
- copy = state->length;
- PULL();
- ROOM();
- if (copy > have) copy = have;
- if (copy > left) copy = left;
- zmemcpy(put, next, copy);
- have -= copy;
- next += copy;
- left -= copy;
- put += copy;
- state->length -= copy;
- }
- Tracev((stderr, "inflate: stored end\n"));
- state->mode = TYPE;
- break;
-
- case TABLE:
- /* get dynamic table entries descriptor */
- NEEDBITS(14);
- state->nlen = BITS(5) + 257;
- DROPBITS(5);
- state->ndist = BITS(5) + 1;
- DROPBITS(5);
- state->ncode = BITS(4) + 4;
- DROPBITS(4);
-#ifndef PKZIP_BUG_WORKAROUND
- if (state->nlen > 286 || state->ndist > 30) {
- strm->msg = (char *)"too many length or distance symbols";
- state->mode = BAD;
- break;
- }
-#endif
- Tracev((stderr, "inflate: table sizes ok\n"));
-
- /* get code length code lengths (not a typo) */
- state->have = 0;
- while (state->have < state->ncode) {
- NEEDBITS(3);
- state->lens[order[state->have++]] = (unsigned short)BITS(3);
- DROPBITS(3);
- }
- while (state->have < 19)
- state->lens[order[state->have++]] = 0;
- state->next = state->codes;
- state->lencode = (code const FAR *)(state->next);
- state->lenbits = 7;
- ret = inflate_table(CODES, state->lens, 19, &(state->next),
- &(state->lenbits), state->work);
- if (ret) {
- strm->msg = (char *)"invalid code lengths set";
- state->mode = BAD;
- break;
- }
- Tracev((stderr, "inflate: code lengths ok\n"));
-
- /* get length and distance code code lengths */
- state->have = 0;
- while (state->have < state->nlen + state->ndist) {
- for (;;) {
- here = state->lencode[BITS(state->lenbits)];
- if ((unsigned)(here.bits) <= bits) break;
- PULLBYTE();
- }
- if (here.val < 16) {
- DROPBITS(here.bits);
- state->lens[state->have++] = here.val;
- }
- else {
- if (here.val == 16) {
- NEEDBITS(here.bits + 2);
- DROPBITS(here.bits);
- if (state->have == 0) {
- strm->msg = (char *)"invalid bit length repeat";
- state->mode = BAD;
- break;
- }
- len = (unsigned)(state->lens[state->have - 1]);
- copy = 3 + BITS(2);
- DROPBITS(2);
- }
- else if (here.val == 17) {
- NEEDBITS(here.bits + 3);
- DROPBITS(here.bits);
- len = 0;
- copy = 3 + BITS(3);
- DROPBITS(3);
- }
- else {
- NEEDBITS(here.bits + 7);
- DROPBITS(here.bits);
- len = 0;
- copy = 11 + BITS(7);
- DROPBITS(7);
- }
- if (state->have + copy > state->nlen + state->ndist) {
- strm->msg = (char *)"invalid bit length repeat";
- state->mode = BAD;
- break;
- }
- while (copy--)
- state->lens[state->have++] = (unsigned short)len;
- }
- }
-
- /* handle error breaks in while */
- if (state->mode == BAD) break;
-
- /* check for end-of-block code (better have one) */
- if (state->lens[256] == 0) {
- strm->msg = (char *)"invalid code -- missing end-of-block";
- state->mode = BAD;
- break;
- }
-
- /* build code tables -- note: do not change the lenbits or distbits
- values here (9 and 6) without reading the comments in inftrees.h
- concerning the ENOUGH constants, which depend on those values */
- state->next = state->codes;
- state->lencode = (code const FAR *)(state->next);
- state->lenbits = 9;
- ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
- &(state->lenbits), state->work);
- if (ret) {
- strm->msg = (char *)"invalid literal/lengths set";
- state->mode = BAD;
- break;
- }
- state->distcode = (code const FAR *)(state->next);
- state->distbits = 6;
- ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
- &(state->next), &(state->distbits), state->work);
- if (ret) {
- strm->msg = (char *)"invalid distances set";
- state->mode = BAD;
- break;
- }
- Tracev((stderr, "inflate: codes ok\n"));
- state->mode = LEN;
- /* fallthrough */
-
- case LEN:
- /* use inflate_fast() if we have enough input and output */
- if (have >= 6 && left >= 258) {
- RESTORE();
- if (state->whave < state->wsize)
- state->whave = state->wsize - left;
- inflate_fast(strm, state->wsize);
- LOAD();
- break;
- }
-
- /* get a literal, length, or end-of-block code */
- for (;;) {
- here = state->lencode[BITS(state->lenbits)];
- if ((unsigned)(here.bits) <= bits) break;
- PULLBYTE();
- }
- if (here.op && (here.op & 0xf0) == 0) {
- last = here;
- for (;;) {
- here = state->lencode[last.val +
- (BITS(last.bits + last.op) >> last.bits)];
- if ((unsigned)(last.bits + here.bits) <= bits) break;
- PULLBYTE();
- }
- DROPBITS(last.bits);
- }
- DROPBITS(here.bits);
- state->length = (unsigned)here.val;
-
- /* process literal */
- if (here.op == 0) {
- Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
- "inflate: literal '%c'\n" :
- "inflate: literal 0x%02x\n", here.val));
- ROOM();
- *put++ = (unsigned char)(state->length);
- left--;
- state->mode = LEN;
- break;
- }
-
- /* process end of block */
- if (here.op & 32) {
- Tracevv((stderr, "inflate: end of block\n"));
- state->mode = TYPE;
- break;
- }
-
- /* invalid code */
- if (here.op & 64) {
- strm->msg = (char *)"invalid literal/length code";
- state->mode = BAD;
- break;
- }
-
- /* length code -- get extra bits, if any */
- state->extra = (unsigned)(here.op) & 15;
- if (state->extra != 0) {
- NEEDBITS(state->extra);
- state->length += BITS(state->extra);
- DROPBITS(state->extra);
- }
- Tracevv((stderr, "inflate: length %u\n", state->length));
-
- /* get distance code */
- for (;;) {
- here = state->distcode[BITS(state->distbits)];
- if ((unsigned)(here.bits) <= bits) break;
- PULLBYTE();
- }
- if ((here.op & 0xf0) == 0) {
- last = here;
- for (;;) {
- here = state->distcode[last.val +
- (BITS(last.bits + last.op) >> last.bits)];
- if ((unsigned)(last.bits + here.bits) <= bits) break;
- PULLBYTE();
- }
- DROPBITS(last.bits);
- }
- DROPBITS(here.bits);
- if (here.op & 64) {
- strm->msg = (char *)"invalid distance code";
- state->mode = BAD;
- break;
- }
- state->offset = (unsigned)here.val;
-
- /* get distance extra bits, if any */
- state->extra = (unsigned)(here.op) & 15;
- if (state->extra != 0) {
- NEEDBITS(state->extra);
- state->offset += BITS(state->extra);
- DROPBITS(state->extra);
- }
- if (state->offset > state->wsize - (state->whave < state->wsize ?
- left : 0)) {
- strm->msg = (char *)"invalid distance too far back";
- state->mode = BAD;
- break;
- }
- Tracevv((stderr, "inflate: distance %u\n", state->offset));
-
- /* copy match from window to output */
- do {
- ROOM();
- copy = state->wsize - state->offset;
- if (copy < left) {
- from = put + copy;
- copy = left - copy;
- }
- else {
- from = put - state->offset;
- copy = left;
- }
- if (copy > state->length) copy = state->length;
- state->length -= copy;
- left -= copy;
- do {
- *put++ = *from++;
- } while (--copy);
- } while (state->length != 0);
- break;
-
- case DONE:
- /* inflate stream terminated properly */
- ret = Z_STREAM_END;
- goto inf_leave;
-
- case BAD:
- ret = Z_DATA_ERROR;
- goto inf_leave;
-
- default:
- /* can't happen, but makes compilers happy */
- ret = Z_STREAM_ERROR;
- goto inf_leave;
- }
-
- /* Write leftover output and return unused input */
- inf_leave:
- if (left < state->wsize) {
- if (out(out_desc, state->window, state->wsize - left) &&
- ret == Z_STREAM_END)
- ret = Z_BUF_ERROR;
- }
- strm->next_in = next;
- strm->avail_in = have;
- return ret;
-}
-
-int ZEXPORT inflateBackEnd(
- z_streamp strm)
-{
- if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
- return Z_STREAM_ERROR;
- ZFREE(strm, strm->state);
- strm->state = Z_NULL;
- Tracev((stderr, "inflate: end\n"));
- return Z_OK;
-}
diff --git a/src/3rdparty/freetype/src/gzip/rules.mk b/src/3rdparty/freetype/src/gzip/rules.mk
index 6feb6f51ce..c76eacb1ae 100644
--- a/src/3rdparty/freetype/src/gzip/rules.mk
+++ b/src/3rdparty/freetype/src/gzip/rules.mk
@@ -36,25 +36,23 @@ endif
#
# All source and header files get loaded by `ftgzip.c' only if SYSTEM_ZLIB
# is not defined (regardless whether we have a `single' or a `multi' build).
-# However, it doesn't harm if we add everything as a dependency
-# unconditionally.
#
-GZIP_DRV_SRCS := $(GZIP_DIR)/adler32.c \
- $(GZIP_DIR)/crc32.c \
- $(GZIP_DIR)/crc32.h \
- $(GZIP_DIR)/ftzconf.h \
- $(GZIP_DIR)/infback.c \
- $(GZIP_DIR)/inffast.c \
- $(GZIP_DIR)/inffast.h \
- $(GZIP_DIR)/inffixed.h \
- $(GZIP_DIR)/inflate.c \
- $(GZIP_DIR)/inflate.h \
- $(GZIP_DIR)/inftrees.c \
- $(GZIP_DIR)/inftrees.h \
- $(GZIP_DIR)/zlib.h \
- $(GZIP_DIR)/zutil.c \
- $(GZIP_DIR)/zutil.h
-
+ifeq ($(SYSTEM_ZLIB),)
+ GZIP_DRV_SRCS := $(GZIP_DIR)/adler32.c \
+ $(GZIP_DIR)/crc32.c \
+ $(GZIP_DIR)/crc32.h \
+ $(GZIP_DIR)/ftzconf.h \
+ $(GZIP_DIR)/inffast.c \
+ $(GZIP_DIR)/inffast.h \
+ $(GZIP_DIR)/inffixed.h \
+ $(GZIP_DIR)/inflate.c \
+ $(GZIP_DIR)/inflate.h \
+ $(GZIP_DIR)/inftrees.c \
+ $(GZIP_DIR)/inftrees.h \
+ $(GZIP_DIR)/zlib.h \
+ $(GZIP_DIR)/zutil.c \
+ $(GZIP_DIR)/zutil.h
+endif
# gzip driver object(s)
#
diff --git a/src/3rdparty/freetype/src/pcf/pcfdrivr.c b/src/3rdparty/freetype/src/pcf/pcfdrivr.c
index bfa6eacca4..f1dba02404 100644
--- a/src/3rdparty/freetype/src/pcf/pcfdrivr.c
+++ b/src/3rdparty/freetype/src/pcf/pcfdrivr.c
@@ -75,36 +75,36 @@ THE SOFTWARE.
FT_CALLBACK_DEF( FT_Error )
- pcf_cmap_init( FT_CMap pcfcmap, /* PCF_CMap */
+ pcf_cmap_init( FT_CMap cmap, /* PCF_CMap */
FT_Pointer init_data )
{
- PCF_CMap cmap = (PCF_CMap)pcfcmap;
- PCF_Face face = (PCF_Face)FT_CMAP_FACE( pcfcmap );
+ PCF_CMap pcfcmap = (PCF_CMap)cmap;
+ PCF_Face face = (PCF_Face)FT_CMAP_FACE( cmap );
FT_UNUSED( init_data );
- cmap->enc = &face->enc;
+ pcfcmap->enc = &face->enc;
return FT_Err_Ok;
}
FT_CALLBACK_DEF( void )
- pcf_cmap_done( FT_CMap pcfcmap ) /* PCF_CMap */
+ pcf_cmap_done( FT_CMap cmap ) /* PCF_CMap */
{
- PCF_CMap cmap = (PCF_CMap)pcfcmap;
+ PCF_CMap pcfcmap = (PCF_CMap)cmap;
- cmap->enc = NULL;
+ pcfcmap->enc = NULL;
}
FT_CALLBACK_DEF( FT_UInt )
- pcf_cmap_char_index( FT_CMap pcfcmap, /* PCF_CMap */
+ pcf_cmap_char_index( FT_CMap cmap, /* PCF_CMap */
FT_UInt32 charcode )
{
- PCF_Enc enc = ( (PCF_CMap)pcfcmap )->enc;
+ PCF_Enc enc = ( (PCF_CMap)cmap )->enc;
FT_UInt32 i = ( charcode >> 8 ) - enc->firstRow;
FT_UInt32 j = ( charcode & 0xFF ) - enc->firstCol;
@@ -121,10 +121,10 @@ THE SOFTWARE.
FT_CALLBACK_DEF( FT_UInt )
- pcf_cmap_char_next( FT_CMap pcfcmap, /* PCF_CMap */
+ pcf_cmap_char_next( FT_CMap cmap, /* PCF_CMap */
FT_UInt32 *acharcode )
{
- PCF_Enc enc = ( (PCF_CMap)pcfcmap )->enc;
+ PCF_Enc enc = ( (PCF_CMap)cmap )->enc;
FT_UInt32 charcode = *acharcode + 1;
FT_UInt32 i = ( charcode >> 8 ) - enc->firstRow;
@@ -170,9 +170,9 @@ THE SOFTWARE.
FT_CALLBACK_DEF( void )
- PCF_Face_Done( FT_Face pcfface ) /* PCF_Face */
+ PCF_Face_Done( FT_Face face ) /* PCF_Face */
{
- PCF_Face face = (PCF_Face)pcfface;
+ PCF_Face pcfface = (PCF_Face)face;
FT_Memory memory;
@@ -181,18 +181,18 @@ THE SOFTWARE.
memory = FT_FACE_MEMORY( face );
- FT_FREE( face->metrics );
- FT_FREE( face->enc.offset );
+ FT_FREE( pcfface->metrics );
+ FT_FREE( pcfface->enc.offset );
/* free properties */
- if ( face->properties )
+ if ( pcfface->properties )
{
FT_Int i;
- for ( i = 0; i < face->nprops; i++ )
+ for ( i = 0; i < pcfface->nprops; i++ )
{
- PCF_Property prop = &face->properties[i];
+ PCF_Property prop = &pcfface->properties[i];
if ( prop )
@@ -203,33 +203,33 @@ THE SOFTWARE.
}
}
- FT_FREE( face->properties );
+ FT_FREE( pcfface->properties );
}
- FT_FREE( face->toc.tables );
- FT_FREE( pcfface->family_name );
- FT_FREE( pcfface->style_name );
- FT_FREE( pcfface->available_sizes );
- FT_FREE( face->charset_encoding );
- FT_FREE( face->charset_registry );
+ FT_FREE( pcfface->toc.tables );
+ FT_FREE( face->family_name );
+ FT_FREE( face->style_name );
+ FT_FREE( face->available_sizes );
+ FT_FREE( pcfface->charset_encoding );
+ FT_FREE( pcfface->charset_registry );
/* close compressed stream if any */
- if ( pcfface->stream == &face->comp_stream )
+ if ( face->stream == &pcfface->comp_stream )
{
- FT_Stream_Close( &face->comp_stream );
- pcfface->stream = face->comp_source;
+ FT_Stream_Close( &pcfface->comp_stream );
+ face->stream = pcfface->comp_source;
}
}
FT_CALLBACK_DEF( FT_Error )
PCF_Face_Init( FT_Stream stream,
- FT_Face pcfface, /* PCF_Face */
+ FT_Face face, /* PCF_Face */
FT_Int face_index,
FT_Int num_params,
FT_Parameter* params )
{
- PCF_Face face = (PCF_Face)pcfface;
+ PCF_Face pcfface = (PCF_Face)face;
FT_Error error;
FT_UNUSED( num_params );
@@ -238,10 +238,10 @@ THE SOFTWARE.
FT_TRACE2(( "PCF driver\n" ));
- error = pcf_load_font( stream, face, face_index );
+ error = pcf_load_font( stream, pcfface, face_index );
if ( error )
{
- PCF_Face_Done( pcfface );
+ PCF_Face_Done( face );
#if defined( FT_CONFIG_OPTION_USE_ZLIB ) || \
defined( FT_CONFIG_OPTION_USE_LZW ) || \
@@ -254,7 +254,7 @@ THE SOFTWARE.
/* this didn't work, try gzip support! */
FT_TRACE2(( " ... try gzip stream\n" ));
- error2 = FT_Stream_OpenGzip( &face->comp_stream, stream );
+ error2 = FT_Stream_OpenGzip( &pcfface->comp_stream, stream );
if ( FT_ERR_EQ( error2, Unimplemented_Feature ) )
goto Fail;
@@ -270,7 +270,7 @@ THE SOFTWARE.
/* this didn't work, try LZW support! */
FT_TRACE2(( " ... try LZW stream\n" ));
- error3 = FT_Stream_OpenLZW( &face->comp_stream, stream );
+ error3 = FT_Stream_OpenLZW( &pcfface->comp_stream, stream );
if ( FT_ERR_EQ( error3, Unimplemented_Feature ) )
goto Fail;
@@ -286,7 +286,7 @@ THE SOFTWARE.
/* this didn't work, try Bzip2 support! */
FT_TRACE2(( " ... try Bzip2 stream\n" ));
- error4 = FT_Stream_OpenBzip2( &face->comp_stream, stream );
+ error4 = FT_Stream_OpenBzip2( &pcfface->comp_stream, stream );
if ( FT_ERR_EQ( error4, Unimplemented_Feature ) )
goto Fail;
@@ -297,12 +297,12 @@ THE SOFTWARE.
if ( error )
goto Fail;
- face->comp_source = stream;
- pcfface->stream = &face->comp_stream;
+ pcfface->comp_source = stream;
+ face->stream = &pcfface->comp_stream;
- stream = pcfface->stream;
+ stream = face->stream;
- error = pcf_load_font( stream, face, face_index );
+ error = pcf_load_font( stream, pcfface, face_index );
if ( error )
goto Fail;
@@ -326,14 +326,14 @@ THE SOFTWARE.
else if ( face_index > 0 && ( face_index & 0xFFFF ) > 0 )
{
FT_ERROR(( "PCF_Face_Init: invalid face index\n" ));
- PCF_Face_Done( pcfface );
+ PCF_Face_Done( face );
return FT_THROW( Invalid_Argument );
}
/* set up charmap */
{
- FT_String *charset_registry = face->charset_registry;
- FT_String *charset_encoding = face->charset_encoding;
+ FT_String *charset_registry = pcfface->charset_registry;
+ FT_String *charset_encoding = pcfface->charset_encoding;
FT_Bool unicode_charmap = 0;
@@ -349,13 +349,13 @@ THE SOFTWARE.
( s[2] == 'o' || s[2] == 'O' ) )
{
s += 3;
- if ( !ft_strcmp( s, "10646" ) ||
- ( !ft_strcmp( s, "8859" ) &&
- !ft_strcmp( face->charset_encoding, "1" ) ) )
+ if ( !ft_strcmp( s, "10646" ) ||
+ ( !ft_strcmp( s, "8859" ) &&
+ !ft_strcmp( pcfface->charset_encoding, "1" ) ) )
unicode_charmap = 1;
/* another name for ASCII */
- else if ( !ft_strcmp( s, "646.1991" ) &&
- !ft_strcmp( face->charset_encoding, "IRV" ) )
+ else if ( !ft_strcmp( s, "646.1991" ) &&
+ !ft_strcmp( pcfface->charset_encoding, "IRV" ) )
unicode_charmap = 1;
}
}
@@ -364,7 +364,7 @@ THE SOFTWARE.
FT_CharMapRec charmap;
- charmap.face = FT_FACE( face );
+ charmap.face = face;
charmap.encoding = FT_ENCODING_NONE;
/* initial platform/encoding should indicate unset status? */
charmap.platform_id = TT_PLATFORM_APPLE_UNICODE;
@@ -386,7 +386,7 @@ THE SOFTWARE.
Fail:
FT_TRACE2(( " not a PCF file\n" ));
- PCF_Face_Done( pcfface );
+ PCF_Face_Done( face );
error = FT_THROW( Unknown_File_Format ); /* error */
goto Exit;
}
@@ -569,15 +569,16 @@ THE SOFTWARE.
*
*/
- static FT_Error
- pcf_get_bdf_property( PCF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ pcf_get_bdf_property( FT_Face face, /* PCF_Face */
const char* prop_name,
BDF_PropertyRec *aproperty )
{
+ PCF_Face pcfface = (PCF_Face)face;
PCF_Property prop;
- prop = pcf_find_property( face, prop_name );
+ prop = pcf_find_property( pcfface, prop_name );
if ( prop )
{
if ( prop->isString )
@@ -611,13 +612,16 @@ THE SOFTWARE.
}
- static FT_Error
- pcf_get_charset_id( PCF_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ pcf_get_charset_id( FT_Face face, /* PCF_Face */
const char* *acharset_encoding,
const char* *acharset_registry )
{
- *acharset_encoding = face->charset_encoding;
- *acharset_registry = face->charset_registry;
+ PCF_Face pcfface = (PCF_Face)face;
+
+
+ *acharset_encoding = pcfface->charset_encoding;
+ *acharset_registry = pcfface->charset_registry;
return FT_Err_Ok;
}
@@ -634,7 +638,7 @@ THE SOFTWARE.
* PROPERTY SERVICE
*
*/
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
pcf_property_set( FT_Module module, /* PCF_Driver */
const char* property_name,
const void* value,
@@ -695,10 +699,10 @@ THE SOFTWARE.
}
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
pcf_property_get( FT_Module module, /* PCF_Driver */
const char* property_name,
- const void* value )
+ void* value )
{
#ifdef PCF_CONFIG_OPTION_LONG_FAMILY_NAMES
diff --git a/src/3rdparty/freetype/src/pfr/pfrcmap.c b/src/3rdparty/freetype/src/pfr/pfrcmap.c
index 312a9ffe17..08fe41d54e 100644
--- a/src/3rdparty/freetype/src/pfr/pfrcmap.c
+++ b/src/3rdparty/freetype/src/pfr/pfrcmap.c
@@ -24,17 +24,18 @@
FT_CALLBACK_DEF( FT_Error )
- pfr_cmap_init( PFR_CMap cmap,
+ pfr_cmap_init( FT_CMap cmap, /* PFR_CMap */
FT_Pointer pointer )
{
- FT_Error error = FT_Err_Ok;
- PFR_Face face = (PFR_Face)FT_CMAP_FACE( cmap );
+ PFR_CMap pfrcmap = (PFR_CMap)cmap;
+ FT_Error error = FT_Err_Ok;
+ PFR_Face face = (PFR_Face)FT_CMAP_FACE( cmap );
FT_UNUSED( pointer );
- cmap->num_chars = face->phy_font.num_chars;
- cmap->chars = face->phy_font.chars;
+ pfrcmap->num_chars = face->phy_font.num_chars;
+ pfrcmap->chars = face->phy_font.chars;
/* just for safety, check that the character entries are correctly */
/* sorted in increasing character code order */
@@ -42,9 +43,9 @@
FT_UInt n;
- for ( n = 1; n < cmap->num_chars; n++ )
+ for ( n = 1; n < pfrcmap->num_chars; n++ )
{
- if ( cmap->chars[n - 1].char_code >= cmap->chars[n].char_code )
+ if ( pfrcmap->chars[n - 1].char_code >= pfrcmap->chars[n].char_code )
{
error = FT_THROW( Invalid_Table );
goto Exit;
@@ -58,26 +59,30 @@
FT_CALLBACK_DEF( void )
- pfr_cmap_done( PFR_CMap cmap )
+ pfr_cmap_done( FT_CMap cmap ) /* PFR_CMap */
{
- cmap->chars = NULL;
- cmap->num_chars = 0;
+ PFR_CMap pfrcmap = (PFR_CMap)cmap;
+
+
+ pfrcmap->chars = NULL;
+ pfrcmap->num_chars = 0;
}
FT_CALLBACK_DEF( FT_UInt )
- pfr_cmap_char_index( PFR_CMap cmap,
+ pfr_cmap_char_index( FT_CMap cmap, /* PFR_CMap */
FT_UInt32 char_code )
{
- FT_UInt min = 0;
- FT_UInt max = cmap->num_chars;
- FT_UInt mid = min + ( max - min ) / 2;
+ PFR_CMap pfrcmap = (PFR_CMap)cmap;
+ FT_UInt min = 0;
+ FT_UInt max = pfrcmap->num_chars;
+ FT_UInt mid = min + ( max - min ) / 2;
PFR_Char gchar;
while ( min < max )
{
- gchar = cmap->chars + mid;
+ gchar = pfrcmap->chars + mid;
if ( gchar->char_code == char_code )
return mid + 1;
@@ -96,10 +101,11 @@
}
- FT_CALLBACK_DEF( FT_UInt32 )
- pfr_cmap_char_next( PFR_CMap cmap,
+ FT_CALLBACK_DEF( FT_UInt )
+ pfr_cmap_char_next( FT_CMap cmap, /* PFR_CMap */
FT_UInt32 *pchar_code )
{
+ PFR_CMap pfrcmap = (PFR_CMap)cmap;
FT_UInt result = 0;
FT_UInt32 char_code = *pchar_code + 1;
@@ -107,14 +113,14 @@
Restart:
{
FT_UInt min = 0;
- FT_UInt max = cmap->num_chars;
+ FT_UInt max = pfrcmap->num_chars;
FT_UInt mid = min + ( max - min ) / 2;
PFR_Char gchar;
while ( min < max )
{
- gchar = cmap->chars + mid;
+ gchar = pfrcmap->chars + mid;
if ( gchar->char_code == char_code )
{
@@ -143,9 +149,9 @@
/* we didn't find it, but we have a pair just above it */
char_code = 0;
- if ( min < cmap->num_chars )
+ if ( min < pfrcmap->num_chars )
{
- gchar = cmap->chars + min;
+ gchar = pfrcmap->chars + min;
result = min;
if ( result != 0 )
{
diff --git a/src/3rdparty/freetype/src/pfr/pfrdrivr.c b/src/3rdparty/freetype/src/pfr/pfrdrivr.c
index 78c6c6882c..0048f52411 100644
--- a/src/3rdparty/freetype/src/pfr/pfrdrivr.c
+++ b/src/3rdparty/freetype/src/pfr/pfrdrivr.c
@@ -27,16 +27,16 @@
FT_CALLBACK_DEF( FT_Error )
- pfr_get_kerning( FT_Face pfrface, /* PFR_Face */
+ pfr_get_kerning( FT_Face face, /* PFR_Face */
FT_UInt left,
FT_UInt right,
FT_Vector *avector )
{
- PFR_Face face = (PFR_Face)pfrface;
- PFR_PhyFont phys = &face->phy_font;
+ PFR_Face pfrface = (PFR_Face)face;
+ PFR_PhyFont phys = &pfrface->phy_font;
- (void)pfr_face_get_kerning( pfrface, left, right, avector );
+ (void)pfr_face_get_kerning( face, left, right, avector );
/* convert from metrics to outline units when necessary */
if ( phys->outline_resolution != phys->metrics_resolution )
@@ -62,12 +62,12 @@
*/
FT_CALLBACK_DEF( FT_Error )
- pfr_get_advance( FT_Face pfrface, /* PFR_Face */
+ pfr_get_advance( FT_Face face, /* PFR_Face */
FT_UInt gindex,
FT_Pos *anadvance )
{
- PFR_Face face = (PFR_Face)pfrface;
- FT_Error error = FT_ERR( Invalid_Argument );
+ PFR_Face pfrface = (PFR_Face)face;
+ FT_Error error = FT_ERR( Invalid_Argument );
*anadvance = 0;
@@ -77,9 +77,9 @@
gindex--;
- if ( face )
+ if ( pfrface )
{
- PFR_PhyFont phys = &face->phy_font;
+ PFR_PhyFont phys = &pfrface->phy_font;
if ( gindex < phys->num_chars )
@@ -95,16 +95,16 @@
FT_CALLBACK_DEF( FT_Error )
- pfr_get_metrics( FT_Face pfrface, /* PFR_Face */
+ pfr_get_metrics( FT_Face face, /* PFR_Face */
FT_UInt *anoutline_resolution,
FT_UInt *ametrics_resolution,
FT_Fixed *ametrics_x_scale,
FT_Fixed *ametrics_y_scale )
{
- PFR_Face face = (PFR_Face)pfrface;
- PFR_PhyFont phys = &face->phy_font;
+ PFR_Face pfrface = (PFR_Face)face;
+ PFR_PhyFont phys = &pfrface->phy_font;
FT_Fixed x_scale, y_scale;
- FT_Size size = face->root.size;
+ FT_Size size = pfrface->root.size;
if ( anoutline_resolution )
diff --git a/src/3rdparty/freetype/src/pfr/pfrgload.c b/src/3rdparty/freetype/src/pfr/pfrgload.c
index 14f2ec3778..48cf27ec80 100644
--- a/src/3rdparty/freetype/src/pfr/pfrgload.c
+++ b/src/3rdparty/freetype/src/pfr/pfrgload.c
@@ -560,8 +560,7 @@
FT_Byte* limit )
{
FT_Error error = FT_Err_Ok;
- FT_GlyphLoader loader = glyph->loader;
- FT_Memory memory = loader->memory;
+ FT_Memory memory = glyph->loader->memory;
PFR_SubGlyph subglyph;
FT_UInt flags, i, count, org_count;
FT_Int x_pos, y_pos;
diff --git a/src/3rdparty/freetype/src/pfr/pfrload.c b/src/3rdparty/freetype/src/pfr/pfrload.c
index de85ee6aad..856a5942f5 100644
--- a/src/3rdparty/freetype/src/pfr/pfrload.c
+++ b/src/3rdparty/freetype/src/pfr/pfrload.c
@@ -449,15 +449,16 @@
/* load bitmap strikes lists */
FT_CALLBACK_DEF( FT_Error )
- pfr_extra_item_load_bitmap_info( FT_Byte* p,
- FT_Byte* limit,
- PFR_PhyFont phy_font )
+ pfr_extra_item_load_bitmap_info( FT_Byte* p,
+ FT_Byte* limit,
+ void* phy_font_ )
{
- FT_Memory memory = phy_font->memory;
- PFR_Strike strike;
- FT_UInt flags0;
- FT_UInt n, count, size1;
- FT_Error error = FT_Err_Ok;
+ PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_;
+ FT_Memory memory = phy_font->memory;
+ PFR_Strike strike;
+ FT_UInt flags0;
+ FT_UInt n, count, size1;
+ FT_Error error = FT_Err_Ok;
PFR_CHECK( 5 );
@@ -549,13 +550,14 @@
* family.
*/
FT_CALLBACK_DEF( FT_Error )
- pfr_extra_item_load_font_id( FT_Byte* p,
- FT_Byte* limit,
- PFR_PhyFont phy_font )
+ pfr_extra_item_load_font_id( FT_Byte* p,
+ FT_Byte* limit,
+ void* phy_font_ )
{
- FT_Error error = FT_Err_Ok;
- FT_Memory memory = phy_font->memory;
- FT_UInt len = (FT_UInt)( limit - p );
+ PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_;
+ FT_Error error = FT_Err_Ok;
+ FT_Memory memory = phy_font->memory;
+ FT_UInt len = (FT_UInt)( limit - p );
if ( phy_font->font_id )
@@ -575,14 +577,15 @@
/* load stem snap tables */
FT_CALLBACK_DEF( FT_Error )
- pfr_extra_item_load_stem_snaps( FT_Byte* p,
- FT_Byte* limit,
- PFR_PhyFont phy_font )
+ pfr_extra_item_load_stem_snaps( FT_Byte* p,
+ FT_Byte* limit,
+ void* phy_font_ )
{
- FT_UInt count, num_vert, num_horz;
- FT_Int* snaps = NULL;
- FT_Error error = FT_Err_Ok;
- FT_Memory memory = phy_font->memory;
+ PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_;
+ FT_UInt count, num_vert, num_horz;
+ FT_Int* snaps = NULL;
+ FT_Error error = FT_Err_Ok;
+ FT_Memory memory = phy_font->memory;
if ( phy_font->vertical.stem_snaps )
@@ -619,10 +622,11 @@
/* load kerning pair data */
FT_CALLBACK_DEF( FT_Error )
- pfr_extra_item_load_kerning_pairs( FT_Byte* p,
- FT_Byte* limit,
- PFR_PhyFont phy_font )
+ pfr_extra_item_load_kerning_pairs( FT_Byte* p,
+ FT_Byte* limit,
+ void* phy_font_ )
{
+ PFR_PhyFont phy_font = (PFR_PhyFont)phy_font_;
PFR_KernItem item = NULL;
FT_Error error = FT_Err_Ok;
FT_Memory memory = phy_font->memory;
@@ -715,10 +719,10 @@
static const PFR_ExtraItemRec pfr_phy_font_extra_items[] =
{
- { 1, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_bitmap_info },
- { 2, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_font_id },
- { 3, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_stem_snaps },
- { 4, (PFR_ExtraItem_ParseFunc)pfr_extra_item_load_kerning_pairs },
+ { 1, pfr_extra_item_load_bitmap_info },
+ { 2, pfr_extra_item_load_font_id },
+ { 3, pfr_extra_item_load_stem_snaps },
+ { 4, pfr_extra_item_load_kerning_pairs },
{ 0, NULL }
};
diff --git a/src/3rdparty/freetype/src/pfr/pfrobjs.c b/src/3rdparty/freetype/src/pfr/pfrobjs.c
index 3db8f0a060..8ef17c6636 100644
--- a/src/3rdparty/freetype/src/pfr/pfrobjs.c
+++ b/src/3rdparty/freetype/src/pfr/pfrobjs.c
@@ -50,14 +50,14 @@
if ( !face )
return;
- memory = pfrface->driver->root.memory;
+ memory = pfrface->memory;
/* we don't want dangling pointers */
pfrface->family_name = NULL;
pfrface->style_name = NULL;
/* finalize the physical font record */
- pfr_phy_font_done( &face->phy_font, FT_FACE_MEMORY( face ) );
+ pfr_phy_font_done( &face->phy_font, memory );
/* no need to finalize the logical font or the header */
FT_FREE( pfrface->available_sizes );
@@ -214,7 +214,7 @@
FT_UInt n, count = phy_font->num_strikes;
FT_Bitmap_Size* size;
PFR_Strike strike;
- FT_Memory memory = pfrface->stream->memory;
+ FT_Memory memory = pfrface->memory;
if ( FT_QNEW_ARRAY( pfrface->available_sizes, count ) )
diff --git a/src/3rdparty/freetype/src/psaux/afmparse.c b/src/3rdparty/freetype/src/psaux/afmparse.c
index 68f95698e6..db08941def 100644
--- a/src/3rdparty/freetype/src/psaux/afmparse.c
+++ b/src/3rdparty/freetype/src/psaux/afmparse.c
@@ -1086,7 +1086,7 @@
#else /* T1_CONFIG_OPTION_NO_AFM */
/* ANSI C doesn't like empty source files */
- typedef int _afm_parse_dummy;
+ typedef int afm_parse_dummy_;
#endif /* T1_CONFIG_OPTION_NO_AFM */
diff --git a/src/3rdparty/freetype/src/psaux/cffdecode.c b/src/3rdparty/freetype/src/psaux/cffdecode.c
index 2cd91c96f3..562d17d221 100644
--- a/src/3rdparty/freetype/src/psaux/cffdecode.c
+++ b/src/3rdparty/freetype/src/psaux/cffdecode.c
@@ -2153,7 +2153,7 @@
decoder->locals_bias );
- FT_TRACE4(( " callsubr (idx %d, entering level %ld)\n",
+ FT_TRACE4(( " callsubr (idx %d, entering level %td)\n",
idx,
zone - decoder->zones + 1 ));
@@ -2197,7 +2197,7 @@
decoder->globals_bias );
- FT_TRACE4(( " callgsubr (idx %d, entering level %ld)\n",
+ FT_TRACE4(( " callgsubr (idx %d, entering level %td)\n",
idx,
zone - decoder->zones + 1 ));
@@ -2236,7 +2236,7 @@
break;
case cff_op_return:
- FT_TRACE4(( " return (leaving level %ld)\n",
+ FT_TRACE4(( " return (leaving level %td)\n",
decoder->zone - decoder->zones ));
if ( decoder->zone <= decoder->zones )
diff --git a/src/3rdparty/freetype/src/psaux/pshints.c b/src/3rdparty/freetype/src/psaux/pshints.c
index 6f44d0adbb..7bd08a9c9b 100644
--- a/src/3rdparty/freetype/src/psaux/pshints.c
+++ b/src/3rdparty/freetype/src/psaux/pshints.c
@@ -310,7 +310,7 @@
CF2_Hint hint = &hintmap->edge[i];
- FT_TRACE6(( " %3ld %7.2f %7.2f %5d %s%s%s%s\n",
+ FT_TRACE6(( " %3zu %7.2f %7.2f %5d %s%s%s%s\n",
hint->index,
hint->csCoord / 65536.0,
hint->dsCoord / ( hint->scale * 1.0 ),
diff --git a/src/3rdparty/freetype/src/psaux/t1cmap.c b/src/3rdparty/freetype/src/psaux/t1cmap.c
index bf0a393b45..c4bcf599ea 100644
--- a/src/3rdparty/freetype/src/psaux/t1cmap.c
+++ b/src/3rdparty/freetype/src/psaux/t1cmap.c
@@ -50,8 +50,11 @@
FT_CALLBACK_DEF( void )
- t1_cmap_std_done( T1_CMapStd cmap )
+ t1_cmap_std_done( FT_CMap cmap_ ) /* T1_CMapStd */
{
+ T1_CMapStd cmap = (T1_CMapStd)cmap_;
+
+
cmap->num_glyphs = 0;
cmap->glyph_names = NULL;
cmap->sid_to_string = NULL;
@@ -60,10 +63,11 @@
FT_CALLBACK_DEF( FT_UInt )
- t1_cmap_std_char_index( T1_CMapStd cmap,
- FT_UInt32 char_code )
+ t1_cmap_std_char_index( FT_CMap cmap, /* T1_CMapStd */
+ FT_UInt32 char_code )
{
- FT_UInt result = 0;
+ T1_CMapStd t1cmap = (T1_CMapStd)cmap;
+ FT_UInt result = 0;
if ( char_code < 256 )
@@ -73,13 +77,13 @@
/* convert character code to Adobe SID string */
- code = cmap->code_to_sid[char_code];
- glyph_name = cmap->sid_to_string( code );
+ code = t1cmap->code_to_sid[char_code];
+ glyph_name = t1cmap->sid_to_string( code );
/* look for the corresponding glyph name */
- for ( n = 0; n < cmap->num_glyphs; n++ )
+ for ( n = 0; n < t1cmap->num_glyphs; n++ )
{
- const char* gname = cmap->glyph_names[n];
+ const char* gname = t1cmap->glyph_names[n];
if ( gname && gname[0] == glyph_name[0] &&
@@ -95,9 +99,9 @@
}
- FT_CALLBACK_DEF( FT_UInt32 )
- t1_cmap_std_char_next( T1_CMapStd cmap,
- FT_UInt32 *pchar_code )
+ FT_CALLBACK_DEF( FT_UInt )
+ t1_cmap_std_char_next( FT_CMap cmap,
+ FT_UInt32 *pchar_code )
{
FT_UInt result = 0;
FT_UInt32 char_code = *pchar_code + 1;
@@ -120,13 +124,14 @@
FT_CALLBACK_DEF( FT_Error )
- t1_cmap_standard_init( T1_CMapStd cmap,
+ t1_cmap_standard_init( FT_CMap cmap, /* T1_CMapStd */
FT_Pointer pointer )
{
+ T1_CMapStd t1cmap = (T1_CMapStd)cmap;
FT_UNUSED( pointer );
- t1_cmap_std_init( cmap, 0 );
+ t1_cmap_std_init( t1cmap, 0 );
return 0;
}
@@ -150,13 +155,14 @@
FT_CALLBACK_DEF( FT_Error )
- t1_cmap_expert_init( T1_CMapStd cmap,
+ t1_cmap_expert_init( FT_CMap cmap, /* T1_CMapStd */
FT_Pointer pointer )
{
+ T1_CMapStd t1cmap = (T1_CMapStd)cmap;
FT_UNUSED( pointer );
- t1_cmap_std_init( cmap, 1 );
+ t1_cmap_std_init( t1cmap, 1 );
return 0;
}
@@ -188,20 +194,21 @@
FT_CALLBACK_DEF( FT_Error )
- t1_cmap_custom_init( T1_CMapCustom cmap,
- FT_Pointer pointer )
+ t1_cmap_custom_init( FT_CMap cmap, /* T1_CMapCustom */
+ FT_Pointer pointer )
{
- T1_Face face = (T1_Face)FT_CMAP_FACE( cmap );
- T1_Encoding encoding = &face->type1.encoding;
+ T1_CMapCustom t1cmap = (T1_CMapCustom)cmap;
+ T1_Face face = (T1_Face)FT_CMAP_FACE( cmap );
+ T1_Encoding encoding = &face->type1.encoding;
FT_UNUSED( pointer );
- cmap->first = (FT_UInt)encoding->code_first;
- cmap->count = (FT_UInt)encoding->code_last - cmap->first;
- cmap->indices = encoding->char_index;
+ t1cmap->first = (FT_UInt)encoding->code_first;
+ t1cmap->count = (FT_UInt)encoding->code_last - t1cmap->first;
+ t1cmap->indices = encoding->char_index;
- FT_ASSERT( cmap->indices );
+ FT_ASSERT( t1cmap->indices );
FT_ASSERT( encoding->code_first <= encoding->code_last );
return 0;
@@ -209,45 +216,50 @@
FT_CALLBACK_DEF( void )
- t1_cmap_custom_done( T1_CMapCustom cmap )
+ t1_cmap_custom_done( FT_CMap cmap ) /* T1_CMapCustom */
{
- cmap->indices = NULL;
- cmap->first = 0;
- cmap->count = 0;
+ T1_CMapCustom t1cmap = (T1_CMapCustom)cmap;
+
+
+ t1cmap->indices = NULL;
+ t1cmap->first = 0;
+ t1cmap->count = 0;
}
FT_CALLBACK_DEF( FT_UInt )
- t1_cmap_custom_char_index( T1_CMapCustom cmap,
- FT_UInt32 char_code )
+ t1_cmap_custom_char_index( FT_CMap cmap, /* T1_CMapCustom */
+ FT_UInt32 char_code )
{
- FT_UInt result = 0;
+ T1_CMapCustom t1cmap = (T1_CMapCustom)cmap;
+ FT_UInt result = 0;
- if ( ( char_code >= cmap->first ) &&
- ( char_code < ( cmap->first + cmap->count ) ) )
- result = cmap->indices[char_code];
+ if ( char_code >= t1cmap->first &&
+ char_code < ( t1cmap->first + t1cmap->count ) )
+ result = t1cmap->indices[char_code];
return result;
}
- FT_CALLBACK_DEF( FT_UInt32 )
- t1_cmap_custom_char_next( T1_CMapCustom cmap,
- FT_UInt32 *pchar_code )
+ FT_CALLBACK_DEF( FT_UInt )
+ t1_cmap_custom_char_next( FT_CMap cmap, /* T1_CMapCustom */
+ FT_UInt32 *pchar_code )
{
- FT_UInt result = 0;
- FT_UInt32 char_code = *pchar_code;
+ T1_CMapCustom t1cmap = (T1_CMapCustom)cmap;
+ FT_UInt result = 0;
+ FT_UInt32 char_code = *pchar_code;
char_code++;
- if ( char_code < cmap->first )
- char_code = cmap->first;
+ if ( char_code < t1cmap->first )
+ char_code = t1cmap->first;
- for ( ; char_code < ( cmap->first + cmap->count ); char_code++ )
+ for ( ; char_code < ( t1cmap->first + t1cmap->count ); char_code++ )
{
- result = cmap->indices[char_code];
+ result = t1cmap->indices[char_code];
if ( result != 0 )
goto Exit;
}
@@ -287,20 +299,24 @@
/*************************************************************************/
FT_CALLBACK_DEF( const char * )
- psaux_get_glyph_name( T1_Face face,
+ psaux_get_glyph_name( void* face_,
FT_UInt idx )
{
+ T1_Face face = (T1_Face)face_;
+
+
return face->type1.glyph_names[idx];
}
FT_CALLBACK_DEF( FT_Error )
- t1_cmap_unicode_init( PS_Unicodes unicodes,
- FT_Pointer pointer )
+ t1_cmap_unicode_init( FT_CMap cmap, /* PS_Unicodes */
+ FT_Pointer pointer )
{
- T1_Face face = (T1_Face)FT_CMAP_FACE( unicodes );
- FT_Memory memory = FT_FACE_MEMORY( face );
- FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ T1_Face face = (T1_Face)FT_CMAP_FACE( cmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
FT_UNUSED( pointer );
@@ -311,17 +327,18 @@
return psnames->unicodes_init( memory,
unicodes,
(FT_UInt)face->type1.num_glyphs,
- (PS_GetGlyphNameFunc)&psaux_get_glyph_name,
+ &psaux_get_glyph_name,
(PS_FreeGlyphNameFunc)NULL,
(FT_Pointer)face );
}
FT_CALLBACK_DEF( void )
- t1_cmap_unicode_done( PS_Unicodes unicodes )
+ t1_cmap_unicode_done( FT_CMap cmap ) /* PS_Unicodes */
{
- FT_Face face = FT_CMAP_FACE( unicodes );
- FT_Memory memory = FT_FACE_MEMORY( face );
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ FT_Face face = FT_CMAP_FACE( cmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
FT_FREE( unicodes->maps );
@@ -330,23 +347,25 @@
FT_CALLBACK_DEF( FT_UInt )
- t1_cmap_unicode_char_index( PS_Unicodes unicodes,
- FT_UInt32 char_code )
+ t1_cmap_unicode_char_index( FT_CMap cmap, /* PS_Unicodes */
+ FT_UInt32 char_code )
{
- T1_Face face = (T1_Face)FT_CMAP_FACE( unicodes );
- FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ T1_Face face = (T1_Face)FT_CMAP_FACE( cmap );
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
return psnames->unicodes_char_index( unicodes, char_code );
}
- FT_CALLBACK_DEF( FT_UInt32 )
- t1_cmap_unicode_char_next( PS_Unicodes unicodes,
- FT_UInt32 *pchar_code )
+ FT_CALLBACK_DEF( FT_UInt )
+ t1_cmap_unicode_char_next( FT_CMap cmap, /* PS_Unicodes */
+ FT_UInt32 *pchar_code )
{
- T1_Face face = (T1_Face)FT_CMAP_FACE( unicodes );
- FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ T1_Face face = (T1_Face)FT_CMAP_FACE( cmap );
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
return psnames->unicodes_char_next( unicodes, pchar_code );
diff --git a/src/3rdparty/freetype/src/psaux/t1decode.c b/src/3rdparty/freetype/src/psaux/t1decode.c
index bfed45b53a..4b6b969bcb 100644
--- a/src/3rdparty/freetype/src/psaux/t1decode.c
+++ b/src/3rdparty/freetype/src/psaux/t1decode.c
@@ -520,7 +520,7 @@
#ifdef FT_DEBUG_LEVEL_TRACE
if ( bol )
{
- FT_TRACE5(( " (%ld)", decoder->top - decoder->stack ));
+ FT_TRACE5(( " (%td)", decoder->top - decoder->stack ));
bol = FALSE;
}
#endif
@@ -1165,7 +1165,7 @@
if ( top - decoder->stack != num_args )
FT_TRACE0(( "t1_decoder_parse_charstrings:"
" too much operands on the stack"
- " (seen %ld, expected %d)\n",
+ " (seen %td, expected %d)\n",
top - decoder->stack, num_args ));
break;
}
diff --git a/src/3rdparty/freetype/src/pshinter/pshalgo.c b/src/3rdparty/freetype/src/pshinter/pshalgo.c
index a7f321291a..4f622e1e44 100644
--- a/src/3rdparty/freetype/src/pshinter/pshalgo.c
+++ b/src/3rdparty/freetype/src/pshinter/pshalgo.c
@@ -516,7 +516,7 @@
if ( !psh_hint_is_fitted( parent ) )
psh_hint_align( parent, globals, dimension, glyph );
- /* keep original relation between hints, this is, use the */
+ /* keep original relation between hints, that is, use the */
/* scaled distance between the centers of the hints to */
/* compute the new position */
par_org_center = parent->org_pos + ( parent->org_len >> 1 );
diff --git a/src/3rdparty/freetype/src/pshinter/pshmod.c b/src/3rdparty/freetype/src/pshinter/pshmod.c
index a12e485660..974a99e018 100644
--- a/src/3rdparty/freetype/src/pshinter/pshmod.c
+++ b/src/3rdparty/freetype/src/pshinter/pshmod.c
@@ -37,8 +37,11 @@
/* finalize module */
FT_CALLBACK_DEF( void )
- ps_hinter_done( PS_Hinter_Module module )
+ ps_hinter_done( FT_Module module_ ) /* PS_Hinter_Module */
{
+ PS_Hinter_Module module = (PS_Hinter_Module)module_;
+
+
module->t1_funcs.hints = NULL;
module->t2_funcs.hints = NULL;
@@ -48,8 +51,10 @@
/* initialize module, create hints recorder and the interface */
FT_CALLBACK_DEF( FT_Error )
- ps_hinter_init( PS_Hinter_Module module )
+ ps_hinter_init( FT_Module module_ ) /* PS_Hinter_Module */
{
+ PS_Hinter_Module module = (PS_Hinter_Module)module_;
+
FT_Memory memory = module->root.memory;
void* ph = &module->ps_hints;
diff --git a/src/3rdparty/freetype/src/pshinter/pshrec.c b/src/3rdparty/freetype/src/pshinter/pshrec.c
index 58c8cf1b48..680e6d0135 100644
--- a/src/3rdparty/freetype/src/pshinter/pshrec.c
+++ b/src/3rdparty/freetype/src/pshinter/pshrec.c
@@ -851,10 +851,11 @@
/* add one Type1 counter stem to the current hints table */
static void
- ps_hints_t1stem3( PS_Hints hints,
+ ps_hints_t1stem3( T1_Hints hints_, /* PS_Hints */
FT_UInt dimension,
FT_Fixed* stems )
{
+ PS_Hints hints = (PS_Hints)hints_;
FT_Error error = FT_Err_Ok;
@@ -914,9 +915,10 @@
/* reset hints (only with Type 1 hints) */
static void
- ps_hints_t1reset( PS_Hints hints,
+ ps_hints_t1reset( T1_Hints hints_, /* PS_Hints */
FT_UInt end_point )
{
+ PS_Hints hints = (PS_Hints)hints_;
FT_Error error = FT_Err_Ok;
@@ -953,11 +955,12 @@
/* Type2 "hintmask" operator, add a new hintmask to each direction */
static void
- ps_hints_t2mask( PS_Hints hints,
+ ps_hints_t2mask( T2_Hints hints_, /* PS_Hints */
FT_UInt end_point,
FT_UInt bit_count,
const FT_Byte* bytes )
{
+ PS_Hints hints = (PS_Hints)hints_;
FT_Error error;
@@ -999,10 +1002,11 @@
static void
- ps_hints_t2counter( PS_Hints hints,
+ ps_hints_t2counter( T2_Hints hints_, /* PS_Hints */
FT_UInt bit_count,
const FT_Byte* bytes )
{
+ PS_Hints hints = (PS_Hints)hints_;
FT_Error error;
@@ -1087,6 +1091,13 @@
ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_1 );
}
+ static FT_Error
+ t1_hints_close( T1_Hints hints,
+ FT_UInt end_point )
+ {
+ return ps_hints_close( (PS_Hints)hints, end_point );
+ }
+
static void
t1_hints_stem( T1_Hints hints,
FT_UInt dimension,
@@ -1102,17 +1113,27 @@
}
+ static FT_Error
+ t1_hints_apply( T1_Hints hints,
+ FT_Outline* outline,
+ PSH_Globals globals,
+ FT_Render_Mode hint_mode )
+ {
+ return ps_hints_apply( (PS_Hints)hints, outline, globals, hint_mode );
+ }
+
+
FT_LOCAL_DEF( void )
t1_hints_funcs_init( T1_Hints_FuncsRec* funcs )
{
FT_ZERO( funcs );
funcs->open = (T1_Hints_OpenFunc) t1_hints_open;
- funcs->close = (T1_Hints_CloseFunc) ps_hints_close;
+ funcs->close = (T1_Hints_CloseFunc) t1_hints_close;
funcs->stem = (T1_Hints_SetStemFunc) t1_hints_stem;
funcs->stem3 = (T1_Hints_SetStem3Func)ps_hints_t1stem3;
funcs->reset = (T1_Hints_ResetFunc) ps_hints_t1reset;
- funcs->apply = (T1_Hints_ApplyFunc) ps_hints_apply;
+ funcs->apply = (T1_Hints_ApplyFunc) t1_hints_apply;
}
@@ -1131,6 +1152,14 @@
}
+ static FT_Error
+ t2_hints_close( T2_Hints hints,
+ FT_UInt end_point )
+ {
+ return ps_hints_close( (PS_Hints)hints, end_point );
+ }
+
+
static void
t2_hints_stems( T2_Hints hints,
FT_UInt dimension,
@@ -1168,17 +1197,27 @@
}
+ static FT_Error
+ t2_hints_apply( T2_Hints hints,
+ FT_Outline* outline,
+ PSH_Globals globals,
+ FT_Render_Mode hint_mode )
+ {
+ return ps_hints_apply( (PS_Hints)hints, outline, globals, hint_mode );
+ }
+
+
FT_LOCAL_DEF( void )
t2_hints_funcs_init( T2_Hints_FuncsRec* funcs )
{
FT_ZERO( funcs );
- funcs->open = (T2_Hints_OpenFunc) t2_hints_open;
- funcs->close = (T2_Hints_CloseFunc) ps_hints_close;
- funcs->stems = (T2_Hints_StemsFunc) t2_hints_stems;
- funcs->hintmask= (T2_Hints_MaskFunc) ps_hints_t2mask;
- funcs->counter = (T2_Hints_CounterFunc)ps_hints_t2counter;
- funcs->apply = (T2_Hints_ApplyFunc) ps_hints_apply;
+ funcs->open = (T2_Hints_OpenFunc) t2_hints_open;
+ funcs->close = (T2_Hints_CloseFunc) t2_hints_close;
+ funcs->stems = (T2_Hints_StemsFunc) t2_hints_stems;
+ funcs->hintmask = (T2_Hints_MaskFunc) ps_hints_t2mask;
+ funcs->counter = (T2_Hints_CounterFunc)ps_hints_t2counter;
+ funcs->apply = (T2_Hints_ApplyFunc) t2_hints_apply;
}
diff --git a/src/3rdparty/freetype/src/psnames/psmodule.c b/src/3rdparty/freetype/src/psnames/psmodule.c
index db454e558e..8203a0465d 100644
--- a/src/3rdparty/freetype/src/psnames/psmodule.c
+++ b/src/3rdparty/freetype/src/psnames/psmodule.c
@@ -57,7 +57,7 @@
/* the name, as in `A.swash' or `e.final'; in this case, the */
/* VARIANT_BIT is set in the return value. */
/* */
- static FT_UInt32
+ FT_CALLBACK_DEF( FT_UInt32 )
ps_unicode_value( const char* glyph_name )
{
/* If the name begins with `uni', then the glyph name may be a */
@@ -309,7 +309,7 @@
/* Build a table that maps Unicode values to glyph indices. */
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
ps_unicodes_init( FT_Memory memory,
PS_Unicodes table,
FT_UInt num_glyphs,
@@ -408,7 +408,7 @@
}
- static FT_UInt
+ FT_CALLBACK_DEF( FT_UInt )
ps_unicodes_char_index( PS_Unicodes table,
FT_UInt32 unicode )
{
@@ -453,7 +453,7 @@
}
- static FT_UInt32
+ FT_CALLBACK_DEF( FT_UInt )
ps_unicodes_char_next( PS_Unicodes table,
FT_UInt32 *unicode )
{
@@ -518,7 +518,7 @@
#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
- static const char*
+ FT_CALLBACK_DEF( const char* )
ps_get_macintosh_name( FT_UInt name_index )
{
if ( name_index >= FT_NUM_MAC_NAMES )
@@ -528,7 +528,7 @@
}
- static const char*
+ FT_CALLBACK_DEF( const char* )
ps_get_standard_strings( FT_UInt sid )
{
if ( sid >= FT_NUM_SID_NAMES )
@@ -543,13 +543,13 @@
FT_DEFINE_SERVICE_PSCMAPSREC(
pscmaps_interface,
- (PS_Unicode_ValueFunc) ps_unicode_value, /* unicode_value */
- (PS_Unicodes_InitFunc) ps_unicodes_init, /* unicodes_init */
- (PS_Unicodes_CharIndexFunc)ps_unicodes_char_index, /* unicodes_char_index */
- (PS_Unicodes_CharNextFunc) ps_unicodes_char_next, /* unicodes_char_next */
+ ps_unicode_value, /* PS_Unicode_ValueFunc unicode_value */
+ ps_unicodes_init, /* PS_Unicodes_InitFunc unicodes_init */
+ ps_unicodes_char_index, /* PS_Unicodes_CharIndexFunc unicodes_char_index */
+ ps_unicodes_char_next, /* PS_Unicodes_CharNextFunc unicodes_char_next */
- (PS_Macintosh_NameFunc) ps_get_macintosh_name, /* macintosh_name */
- (PS_Adobe_Std_StringsFunc) ps_get_standard_strings, /* adobe_std_strings */
+ ps_get_macintosh_name, /* PS_Macintosh_NameFunc macintosh_name */
+ ps_get_standard_strings, /* PS_Adobe_Std_StringsFunc adobe_std_strings */
t1_standard_encoding, /* adobe_std_encoding */
t1_expert_encoding /* adobe_expert_encoding */
@@ -560,13 +560,13 @@
FT_DEFINE_SERVICE_PSCMAPSREC(
pscmaps_interface,
- NULL, /* unicode_value */
- NULL, /* unicodes_init */
- NULL, /* unicodes_char_index */
- NULL, /* unicodes_char_next */
+ NULL, /* PS_Unicode_ValueFunc unicode_value */
+ NULL, /* PS_Unicodes_InitFunc unicodes_init */
+ NULL, /* PS_Unicodes_CharIndexFunc unicodes_char_index */
+ NULL, /* PS_Unicodes_CharNextFunc unicodes_char_next */
- (PS_Macintosh_NameFunc) ps_get_macintosh_name, /* macintosh_name */
- (PS_Adobe_Std_StringsFunc) ps_get_standard_strings, /* adobe_std_strings */
+ ps_get_macintosh_name, /* PS_Macintosh_NameFunc macintosh_name */
+ ps_get_standard_strings, /* PS_Adobe_Std_StringsFunc adobe_std_strings */
t1_standard_encoding, /* adobe_std_encoding */
t1_expert_encoding /* adobe_expert_encoding */
@@ -612,9 +612,9 @@
PUT_PS_NAMES_SERVICE(
(void*)&pscmaps_interface ), /* module specific interface */
- (FT_Module_Constructor)NULL, /* module_init */
- (FT_Module_Destructor) NULL, /* module_done */
- (FT_Module_Requester) PUT_PS_NAMES_SERVICE( psnames_get_service ) /* get_interface */
+ NULL, /* FT_Module_Constructor module_init */
+ NULL, /* FT_Module_Destructor module_done */
+ PUT_PS_NAMES_SERVICE( psnames_get_service ) /* FT_Module_Requester get_interface */
)
diff --git a/src/3rdparty/freetype/src/raster/ftraster.c b/src/3rdparty/freetype/src/raster/ftraster.c
index 67cbfd5d9b..192ca0701a 100644
--- a/src/3rdparty/freetype/src/raster/ftraster.c
+++ b/src/3rdparty/freetype/src/raster/ftraster.c
@@ -1742,9 +1742,9 @@
* SUCCESS on success, FAILURE on error.
*/
static Bool
- Decompose_Curve( RAS_ARGS UShort first,
- UShort last,
- Int flipped )
+ Decompose_Curve( RAS_ARGS Int first,
+ Int last,
+ Int flipped )
{
FT_Vector v_last;
FT_Vector v_control;
@@ -1969,8 +1969,8 @@
static Bool
Convert_Glyph( RAS_ARGS Int flipped )
{
- Int i;
- UInt start;
+ Int i;
+ Int first, last;
ras.fProfile = NULL;
@@ -1985,8 +1985,7 @@
ras.cProfile->offset = ras.top;
ras.num_Profs = 0;
- start = 0;
-
+ last = -1;
for ( i = 0; i < ras.outline.n_contours; i++ )
{
PProfile lastProfile;
@@ -1996,12 +1995,11 @@
ras.state = Unknown_State;
ras.gProfile = NULL;
- if ( Decompose_Curve( RAS_VARS (UShort)start,
- (UShort)ras.outline.contours[i],
- flipped ) )
- return FAILURE;
+ first = last + 1;
+ last = ras.outline.contours[i];
- start = (UShort)ras.outline.contours[i] + 1;
+ if ( Decompose_Curve( RAS_VARS first, last, flipped ) )
+ return FAILURE;
/* we must now check whether the extreme arcs join or not */
if ( FRAC( ras.lastY ) == 0 &&
@@ -3167,9 +3165,12 @@
static int
- ft_black_new( FT_Memory memory,
- black_PRaster *araster )
+ ft_black_new( void* memory_, /* FT_Memory */
+ FT_Raster *araster_ ) /* black_PRaster */
{
+ FT_Memory memory = (FT_Memory)memory_;
+ black_PRaster *araster = (black_PRaster*)araster_;
+
FT_Error error;
black_PRaster raster = NULL;
@@ -3184,9 +3185,10 @@
static void
- ft_black_done( black_PRaster raster )
+ ft_black_done( FT_Raster raster_ ) /* black_PRaster */
{
- FT_Memory memory = (FT_Memory)raster->memory;
+ black_PRaster raster = (black_PRaster)raster_;
+ FT_Memory memory = (FT_Memory)raster->memory;
FT_FREE( raster );
@@ -3281,11 +3283,11 @@
FT_GLYPH_FORMAT_OUTLINE,
- (FT_Raster_New_Func) ft_black_new, /* raster_new */
- (FT_Raster_Reset_Func) ft_black_reset, /* raster_reset */
- (FT_Raster_Set_Mode_Func)ft_black_set_mode, /* raster_set_mode */
- (FT_Raster_Render_Func) ft_black_render, /* raster_render */
- (FT_Raster_Done_Func) ft_black_done /* raster_done */
+ ft_black_new, /* FT_Raster_New_Func raster_new */
+ ft_black_reset, /* FT_Raster_Reset_Func raster_reset */
+ ft_black_set_mode, /* FT_Raster_Set_Mode_Func raster_set_mode */
+ ft_black_render, /* FT_Raster_Render_Func raster_render */
+ ft_black_done /* FT_Raster_Done_Func raster_done */
)
diff --git a/src/3rdparty/freetype/src/raster/ftrend1.c b/src/3rdparty/freetype/src/raster/ftrend1.c
index 0b5d867147..6d442b1ff8 100644
--- a/src/3rdparty/freetype/src/raster/ftrend1.c
+++ b/src/3rdparty/freetype/src/raster/ftrend1.c
@@ -27,8 +27,11 @@
/* initialize renderer -- init its raster */
static FT_Error
- ft_raster1_init( FT_Renderer render )
+ ft_raster1_init( FT_Module module ) /* FT_Renderer */
{
+ FT_Renderer render = (FT_Renderer)module;
+
+
render->clazz->raster_class->raster_reset( render->raster, NULL, 0 );
return FT_Err_Ok;
@@ -188,18 +191,18 @@
NULL, /* module specific interface */
- (FT_Module_Constructor)ft_raster1_init, /* module_init */
- (FT_Module_Destructor) NULL, /* module_done */
- (FT_Module_Requester) NULL, /* get_interface */
+ ft_raster1_init, /* FT_Module_Constructor module_init */
+ NULL, /* FT_Module_Destructor module_done */
+ NULL, /* FT_Module_Requester get_interface */
FT_GLYPH_FORMAT_OUTLINE,
- (FT_Renderer_RenderFunc) ft_raster1_render, /* render_glyph */
- (FT_Renderer_TransformFunc)ft_raster1_transform, /* transform_glyph */
- (FT_Renderer_GetCBoxFunc) ft_raster1_get_cbox, /* get_glyph_cbox */
- (FT_Renderer_SetModeFunc) ft_raster1_set_mode, /* set_mode */
+ ft_raster1_render, /* FT_Renderer_RenderFunc render_glyph */
+ ft_raster1_transform, /* FT_Renderer_TransformFunc transform_glyph */
+ ft_raster1_get_cbox, /* FT_Renderer_GetCBoxFunc get_glyph_cbox */
+ ft_raster1_set_mode, /* FT_Renderer_SetModeFunc set_mode */
- (FT_Raster_Funcs*)&ft_standard_raster /* raster_class */
+ &ft_standard_raster /* FT_Raster_Funcs* raster_class */
)
diff --git a/src/3rdparty/freetype/src/sdf/ftbsdf.c b/src/3rdparty/freetype/src/sdf/ftbsdf.c
index 901d8b7402..e472738339 100644
--- a/src/3rdparty/freetype/src/sdf/ftbsdf.c
+++ b/src/3rdparty/freetype/src/sdf/ftbsdf.c
@@ -1173,9 +1173,12 @@
/* called when adding a new module through @FT_Add_Module */
static FT_Error
- bsdf_raster_new( FT_Memory memory,
- BSDF_PRaster* araster )
+ bsdf_raster_new( void* memory_, /* FT_Memory */
+ FT_Raster* araster_ ) /* BSDF_PRaster* */
{
+ FT_Memory memory = (FT_Memory)memory_;
+ BSDF_PRaster* araster = (BSDF_PRaster*)araster_;
+
FT_Error error;
BSDF_PRaster raster = NULL;
diff --git a/src/3rdparty/freetype/src/sdf/ftsdf.c b/src/3rdparty/freetype/src/sdf/ftsdf.c
index 26a6d00e4a..bc4625d984 100644
--- a/src/3rdparty/freetype/src/sdf/ftsdf.c
+++ b/src/3rdparty/freetype/src/sdf/ftsdf.c
@@ -2371,11 +2371,11 @@
* ```
*
* (6) Our task is to find a value of `t` such that the above equation
- * `Q(t)` becomes zero, this is, the point-to-curve vector makes
+ * `Q(t)` becomes zero, that is, the point-to-curve vector makes
* 90~degrees with the curve. We solve this with the Newton-Raphson
* method.
*
- * (7) We first assume an arbitary value of factor `t`, which we then
+ * (7) We first assume an arbitrary value of factor `t`, which we then
* improve.
*
* ```
@@ -2684,11 +2684,11 @@
* ```
*
* (6) Our task is to find a value of `t` such that the above equation
- * `Q(t)` becomes zero, this is, the point-to-curve vector makes
+ * `Q(t)` becomes zero, that is, the point-to-curve vector makes
* 90~degree with curve. We solve this with the Newton-Raphson
* method.
*
- * (7) We first assume an arbitary value of factor `t`, which we then
+ * (7) We first assume an arbitrary value of factor `t`, which we then
* improve.
*
* ```
@@ -2718,8 +2718,9 @@
FT_Error error = FT_Err_Ok;
- FT_26D6_Vec aA, bB, cC, dD; /* A, B, C in the above comment */
- FT_16D16_Vec nearest_point; /* point on curve nearest to `point` */
+ FT_26D6_Vec aA, bB, cC, dD; /* A, B, C, D in the above comment */
+ FT_16D16_Vec nearest_point = { 0, 0 };
+ /* point on curve nearest to `point` */
FT_16D16_Vec direction; /* direction of curve at `nearest_point` */
FT_26D6_Vec p0, p1, p2, p3; /* control points of a cubic curve */
@@ -3761,9 +3762,13 @@
*/
static FT_Error
- sdf_raster_new( FT_Memory memory,
- SDF_PRaster* araster )
+ sdf_raster_new( void* memory_, /* FT_Memory */
+ FT_Raster* araster_ ) /* SDF_PRaster* */
{
+ FT_Memory memory = (FT_Memory)memory_;
+ SDF_PRaster* araster = (SDF_PRaster*)araster_;
+
+
FT_Error error;
SDF_PRaster raster = NULL;
diff --git a/src/3rdparty/freetype/src/sdf/ftsdfrend.c b/src/3rdparty/freetype/src/sdf/ftsdfrend.c
index 9ac7d6f620..5610c119f8 100644
--- a/src/3rdparty/freetype/src/sdf/ftsdfrend.c
+++ b/src/3rdparty/freetype/src/sdf/ftsdfrend.c
@@ -197,10 +197,10 @@
static FT_Module_Interface
- ft_sdf_requester( FT_Renderer render,
+ ft_sdf_requester( FT_Module module,
const char* module_interface )
{
- FT_UNUSED( render );
+ FT_UNUSED( module );
return ft_service_list_lookup( sdf_services, module_interface );
}
@@ -221,9 +221,9 @@
*/
static FT_Error
- ft_sdf_init( FT_Renderer render )
+ ft_sdf_init( FT_Module module ) /* SDF_Renderer */
{
- SDF_Renderer sdf_render = SDF_RENDERER( render );
+ SDF_Renderer sdf_render = SDF_RENDERER( module );
sdf_render->spread = DEFAULT_SPREAD;
@@ -236,9 +236,9 @@
static void
- ft_sdf_done( FT_Renderer render )
+ ft_sdf_done( FT_Module module )
{
- FT_UNUSED( render );
+ FT_UNUSED( module );
}
@@ -300,7 +300,7 @@
/* nothing to render */
if ( !bitmap->rows || !bitmap->pitch )
- return FT_Err_Ok;
+ goto Exit;
/* the padding will simply be equal to the `spread' */
x_pad = sdf_module->spread;
@@ -508,6 +508,10 @@
goto Exit;
}
+ /* nothing to render */
+ if ( !bitmap->rows || !bitmap->pitch )
+ goto Exit;
+
/* Do not generate SDF if the bitmap is not owned by the */
/* glyph: it might be that the source buffer is already freed. */
if ( !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) )
@@ -519,10 +523,6 @@
goto Exit;
}
- /* nothing to render */
- if ( !bitmap->rows || !bitmap->pitch )
- return FT_Err_Ok;
-
FT_Bitmap_New( &target );
/* padding will simply be equal to `spread` */
@@ -557,15 +557,14 @@
{
/* the glyph is successfully converted to a SDF */
if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
- {
FT_FREE( bitmap->buffer );
- slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
- }
- slot->bitmap = target;
- slot->bitmap_top += y_pad;
- slot->bitmap_left -= x_pad;
- slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
+ slot->bitmap = target;
+ slot->bitmap_top += y_pad;
+ slot->bitmap_left -= x_pad;
+
+ if ( target.buffer )
+ slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
}
else if ( target.buffer )
FT_FREE( target.buffer );
diff --git a/src/3rdparty/freetype/src/sfnt/pngshim.c b/src/3rdparty/freetype/src/sfnt/pngshim.c
index 423b07b02a..33712162e0 100644
--- a/src/3rdparty/freetype/src/sfnt/pngshim.c
+++ b/src/3rdparty/freetype/src/sfnt/pngshim.c
@@ -406,10 +406,7 @@
switch ( color_type )
{
- default:
- /* Shouldn't happen, but ... */
- FALL_THROUGH;
-
+ default: /* Shouldn't happen, but ... */
case PNG_COLOR_TYPE_RGB_ALPHA:
png_set_read_user_transform_fn( png, premultiply_data );
break;
@@ -457,7 +454,7 @@
#else /* !(TT_CONFIG_OPTION_EMBEDDED_BITMAPS && FT_CONFIG_OPTION_USE_PNG) */
/* ANSI C doesn't like empty source files */
- typedef int _pngshim_dummy;
+ typedef int pngshim_dummy_;
#endif /* !(TT_CONFIG_OPTION_EMBEDDED_BITMAPS && FT_CONFIG_OPTION_USE_PNG) */
diff --git a/src/3rdparty/freetype/src/sfnt/sfdriver.c b/src/3rdparty/freetype/src/sfnt/sfdriver.c
index 762883db54..0925940b03 100644
--- a/src/3rdparty/freetype/src/sfnt/sfdriver.c
+++ b/src/3rdparty/freetype/src/sfnt/sfdriver.c
@@ -79,41 +79,57 @@
*
*/
- static void*
- get_sfnt_table( TT_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ sfnt_load_table( FT_Face face, /* TT_Face */
+ FT_ULong tag,
+ FT_Long offset,
+ FT_Byte* buffer,
+ FT_ULong* length )
+ {
+ TT_Face ttface = (TT_Face)face;
+
+
+ return tt_face_load_any( ttface, tag, offset, buffer, length );
+ }
+
+
+ FT_CALLBACK_DEF( void* )
+ get_sfnt_table( FT_Face face, /* TT_Face */
FT_Sfnt_Tag tag )
{
+ TT_Face ttface = (TT_Face)face;
+
void* table;
switch ( tag )
{
case FT_SFNT_HEAD:
- table = &face->header;
+ table = &ttface->header;
break;
case FT_SFNT_HHEA:
- table = &face->horizontal;
+ table = &ttface->horizontal;
break;
case FT_SFNT_VHEA:
- table = face->vertical_info ? &face->vertical : NULL;
+ table = ttface->vertical_info ? &ttface->vertical : NULL;
break;
case FT_SFNT_OS2:
- table = ( face->os2.version == 0xFFFFU ) ? NULL : &face->os2;
+ table = ( ttface->os2.version == 0xFFFFU ) ? NULL : &ttface->os2;
break;
case FT_SFNT_POST:
- table = &face->postscript;
+ table = &ttface->postscript;
break;
case FT_SFNT_MAXP:
- table = &face->max_profile;
+ table = &ttface->max_profile;
break;
case FT_SFNT_PCLT:
- table = face->pclt.Version ? &face->pclt : NULL;
+ table = ttface->pclt.Version ? &ttface->pclt : NULL;
break;
default:
@@ -124,26 +140,29 @@
}
- static FT_Error
- sfnt_table_info( TT_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ sfnt_table_info( FT_Face face, /* TT_Face */
FT_UInt idx,
FT_ULong *tag,
FT_ULong *offset,
FT_ULong *length )
{
+ TT_Face ttface = (TT_Face)face;
+
+
if ( !offset || !length )
return FT_THROW( Invalid_Argument );
if ( !tag )
- *length = face->num_tables;
+ *length = ttface->num_tables;
else
{
- if ( idx >= face->num_tables )
+ if ( idx >= ttface->num_tables )
return FT_THROW( Table_Missing );
- *tag = face->dir_tables[idx].Tag;
- *offset = face->dir_tables[idx].Offset;
- *length = face->dir_tables[idx].Length;
+ *tag = ttface->dir_tables[idx].Tag;
+ *offset = ttface->dir_tables[idx].Offset;
+ *length = ttface->dir_tables[idx].Length;
}
return FT_Err_Ok;
@@ -153,9 +172,9 @@
FT_DEFINE_SERVICE_SFNT_TABLEREC(
sfnt_service_sfnt_table,
- (FT_SFNT_TableLoadFunc)tt_face_load_any, /* load_table */
- (FT_SFNT_TableGetFunc) get_sfnt_table, /* get_table */
- (FT_SFNT_TableInfoFunc)sfnt_table_info /* table_info */
+ sfnt_load_table, /* FT_SFNT_TableLoadFunc load_table */
+ get_sfnt_table, /* FT_SFNT_TableGetFunc get_table */
+ sfnt_table_info /* FT_SFNT_TableInfoFunc table_info */
)
@@ -166,7 +185,7 @@
*
*/
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
sfnt_get_glyph_name( FT_Face face,
FT_UInt glyph_index,
FT_Pointer buffer,
@@ -184,7 +203,7 @@
}
- static FT_UInt
+ FT_CALLBACK_DEF( FT_UInt )
sfnt_get_name_index( FT_Face face,
const FT_String* glyph_name )
{
@@ -221,8 +240,8 @@
FT_DEFINE_SERVICE_GLYPHDICTREC(
sfnt_service_glyph_dict,
- (FT_GlyphDict_GetNameFunc) sfnt_get_glyph_name, /* get_name */
- (FT_GlyphDict_NameIndexFunc)sfnt_get_name_index /* name_index */
+ sfnt_get_glyph_name, /* FT_GlyphDict_GetNameFunc get_name */
+ sfnt_get_name_index /* FT_GlyphDict_NameIndexFunc name_index */
)
#endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
@@ -523,15 +542,14 @@
FT_TRACE0(( "get_win_string:"
" Character 0x%X invalid in PS name string\n",
((unsigned)p[0])*256 + (unsigned)p[1] ));
- break;
+ continue;
}
}
- if ( !len )
- *r = '\0';
+ *r = '\0';
FT_FRAME_EXIT();
- if ( !len )
+ if ( r != result )
return result;
get_win_string_error:
@@ -580,15 +598,14 @@
FT_TRACE0(( "get_apple_string:"
" Character `%c' (0x%X) invalid in PS name string\n",
*p, *p ));
- break;
+ continue;
}
}
- if ( !len )
- *r = '\0';
+ *r = '\0';
FT_FRAME_EXIT();
- if ( !len )
+ if ( r != result )
return result;
get_apple_string_error:
@@ -602,7 +619,7 @@
}
- static FT_Bool
+ FT_CALLBACK_DEF( FT_Bool )
sfnt_get_name_id( TT_Face face,
FT_UShort id,
FT_Int *win,
@@ -819,9 +836,9 @@
if ( !found )
{
- /* as a last resort we try the family name; note that this is */
- /* not in the Adobe TechNote, but GX fonts (which predate the */
- /* TechNote) benefit from this behaviour */
+ /* according to the 'name' documentation in the OpenType */
+ /* specification the font family name is to be used if the */
+ /* typographic family name is missing, so let's do that */
found = sfnt_get_name_id( face,
TT_NAME_ID_FONT_FAMILY,
&win,
@@ -853,6 +870,10 @@
{
FT_TRACE0(( "sfnt_get_var_ps_name:"
" No valid PS name prefix for font instances found\n" ));
+ /* XXX It probably makes sense to never let this fail */
+ /* since an arbitrary prefix should work, too. */
+ /* On the other hand, it is very unlikely that */
+ /* we ever reach this code at all. */
return NULL;
}
@@ -1041,47 +1062,49 @@
#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
- static const char*
- sfnt_get_ps_name( TT_Face face )
+ FT_CALLBACK_DEF( const char* )
+ sfnt_get_ps_name( FT_Face face ) /* TT_Face */
{
+ TT_Face ttface = (TT_Face)face;
+
FT_Int found, win, apple;
const char* result = NULL;
- if ( face->postscript_name )
- return face->postscript_name;
+ if ( ttface->postscript_name )
+ return ttface->postscript_name;
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
- if ( face->blend &&
- ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) ||
- FT_IS_VARIATION( FT_FACE( face ) ) ) )
+ if ( ttface->blend &&
+ ( FT_IS_NAMED_INSTANCE( face ) ||
+ FT_IS_VARIATION( face ) ) )
{
- face->postscript_name = sfnt_get_var_ps_name( face );
- return face->postscript_name;
+ ttface->postscript_name = sfnt_get_var_ps_name( ttface );
+ return ttface->postscript_name;
}
#endif
/* scan the name table to see whether we have a Postscript name here, */
/* either in Macintosh or Windows platform encodings */
- found = sfnt_get_name_id( face, TT_NAME_ID_PS_NAME, &win, &apple );
+ found = sfnt_get_name_id( ttface, TT_NAME_ID_PS_NAME, &win, &apple );
if ( !found )
return NULL;
/* prefer Windows entries over Apple */
if ( win != -1 )
- result = get_win_string( face->root.memory,
- face->name_table.stream,
- face->name_table.names + win,
+ result = get_win_string( FT_FACE_MEMORY( face ),
+ ttface->name_table.stream,
+ ttface->name_table.names + win,
sfnt_is_postscript,
1 );
if ( !result && apple != -1 )
- result = get_apple_string( face->root.memory,
- face->name_table.stream,
- face->name_table.names + apple,
+ result = get_apple_string( FT_FACE_MEMORY( face ),
+ ttface->name_table.stream,
+ ttface->name_table.names + apple,
sfnt_is_postscript,
1 );
- face->postscript_name = result;
+ ttface->postscript_name = result;
return result;
}
@@ -1090,7 +1113,7 @@
FT_DEFINE_SERVICE_PSFONTNAMEREC(
sfnt_service_ps_name,
- (FT_PsName_GetFunc)sfnt_get_ps_name /* get_ps_font_name */
+ sfnt_get_ps_name /* FT_PsName_GetFunc get_ps_font_name */
)
@@ -1100,14 +1123,14 @@
FT_DEFINE_SERVICE_TTCMAPSREC(
tt_service_get_cmap_info,
- (TT_CMap_Info_GetFunc)tt_get_cmap_info /* get_cmap_info */
+ tt_get_cmap_info /* TT_CMap_Info_GetFunc get_cmap_info */
)
#ifdef TT_CONFIG_OPTION_BDF
static FT_Error
- sfnt_get_charset_id( TT_Face face,
+ sfnt_get_charset_id( FT_Face face,
const char* *acharset_encoding,
const char* *acharset_registry )
{
@@ -1145,8 +1168,8 @@
FT_DEFINE_SERVICE_BDFRec(
sfnt_service_bdf,
- (FT_BDF_GetCharsetIdFunc)sfnt_get_charset_id, /* get_charset_id */
- (FT_BDF_GetPropertyFunc) tt_face_find_bdf_prop /* get_property */
+ sfnt_get_charset_id, /* FT_BDF_GetCharsetIdFunc get_charset_id */
+ tt_face_find_bdf_prop /* FT_BDF_GetPropertyFunc get_property */
)
@@ -1337,9 +1360,9 @@
(const void*)&sfnt_interface, /* module specific interface */
- (FT_Module_Constructor)NULL, /* module_init */
- (FT_Module_Destructor) NULL, /* module_done */
- (FT_Module_Requester) sfnt_get_interface /* get_interface */
+ NULL, /* FT_Module_Constructor module_init */
+ NULL, /* FT_Module_Destructor module_done */
+ sfnt_get_interface /* FT_Module_Requester get_interface */
)
diff --git a/src/3rdparty/freetype/src/sfnt/sfobjs.c b/src/3rdparty/freetype/src/sfnt/sfobjs.c
index e018934cca..f5d66ef840 100644
--- a/src/3rdparty/freetype/src/sfnt/sfobjs.c
+++ b/src/3rdparty/freetype/src/sfnt/sfobjs.c
@@ -534,17 +534,23 @@
0 );
}
- if ( !face->var )
+ if ( !face->tt_var )
{
/* we want the metrics variations interface */
/* from the `truetype' module only */
FT_Module tt_module = FT_Get_Module( library, "truetype" );
- face->var = ft_module_get_service( tt_module,
- FT_SERVICE_ID_METRICS_VARIATIONS,
- 0 );
+ face->tt_var = ft_module_get_service( tt_module,
+ FT_SERVICE_ID_METRICS_VARIATIONS,
+ 0 );
}
+
+ if ( !face->face_var )
+ face->face_var = ft_module_get_service(
+ &face->root.driver->root,
+ FT_SERVICE_ID_METRICS_VARIATIONS,
+ 0 );
#endif
FT_TRACE2(( "SFNT driver\n" ));
@@ -692,6 +698,9 @@
instance_offset += instance_size;
}
+ /* named instance indices start with value 1 */
+ face->var_default_named_instance = i + 1;
+
if ( i == num_instances )
{
/* no default instance in named instance table; */
@@ -1054,6 +1063,16 @@
GET_NAME( FONT_SUBFAMILY, &face->root.style_name );
}
+#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
+ {
+ FT_Memory memory = face->root.memory;
+
+
+ if ( FT_STRDUP( face->non_var_style_name, face->root.style_name ) )
+ goto Exit;
+ }
+#endif
+
/* now set up root fields */
{
FT_Face root = &face->root;
@@ -1221,7 +1240,7 @@
if ( count > 0 )
{
- FT_Memory memory = face->root.stream->memory;
+ FT_Memory memory = face->root.memory;
FT_UShort em_size = face->header.Units_Per_EM;
FT_Short avgwidth = face->os2.xAvgCharWidth;
FT_Size_Metrics metrics;
@@ -1500,6 +1519,7 @@
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
FT_FREE( face->var_postscript_prefix );
+ FT_FREE( face->non_var_style_name );
#endif
/* freeing glyph color palette data */
diff --git a/src/3rdparty/freetype/src/sfnt/sfwoff.c b/src/3rdparty/freetype/src/sfnt/sfwoff.c
index 9559bf3421..7c0ce2205e 100644
--- a/src/3rdparty/freetype/src/sfnt/sfwoff.c
+++ b/src/3rdparty/freetype/src/sfnt/sfwoff.c
@@ -426,7 +426,7 @@
#else /* !FT_CONFIG_OPTION_USE_ZLIB */
/* ANSI C doesn't like empty source files */
- typedef int _sfwoff_dummy;
+ typedef int sfwoff_dummy_;
#endif /* !FT_CONFIG_OPTION_USE_ZLIB */
diff --git a/src/3rdparty/freetype/src/sfnt/sfwoff2.c b/src/3rdparty/freetype/src/sfnt/sfwoff2.c
index 7a01977f86..2be44a347a 100644
--- a/src/3rdparty/freetype/src/sfnt/sfwoff2.c
+++ b/src/3rdparty/freetype/src/sfnt/sfwoff2.c
@@ -36,6 +36,8 @@
#undef FT_COMPONENT
#define FT_COMPONENT sfwoff2
+ /* An arbitrary, heuristic size limit (67MByte) for expanded WOFF2 data. */
+#define MAX_SFNT_SIZE ( 1 << 26 )
#define READ_255USHORT( var ) FT_SET_ERROR( Read255UShort( stream, &var ) )
@@ -2180,9 +2182,8 @@
else
sfnt_size = woff2.totalSfntSize;
- /* Value 1<<26 = 67108864 is heuristic. */
- if (sfnt_size >= (1 << 26))
- sfnt_size = 1 << 26;
+ if ( sfnt_size >= MAX_SFNT_SIZE )
+ sfnt_size = MAX_SFNT_SIZE;
#ifdef FT_DEBUG_LEVEL_TRACE
if ( sfnt_size != woff2.totalSfntSize )
@@ -2257,10 +2258,15 @@
goto Exit;
}
- if ( woff2.uncompressed_size > sfnt_size )
+ /* We must not blindly trust `uncompressed_size` since its */
+ /* value might be corrupted. If it is too large, reject the */
+ /* font. In other words, we don't accept a WOFF2 font that */
+ /* expands to something larger than MAX_SFNT_SIZE. If ever */
+ /* necessary, this limit can be easily adjusted. */
+ if ( woff2.uncompressed_size > MAX_SFNT_SIZE )
{
- FT_ERROR(( "woff2_open_font: SFNT table lengths are too large.\n" ));
- error = FT_THROW( Invalid_Table );
+ FT_ERROR(( "Uncompressed font too large.\n" ));
+ error = FT_THROW( Array_Too_Large );
goto Exit;
}
@@ -2378,7 +2384,7 @@
#else /* !FT_CONFIG_OPTION_USE_BROTLI */
/* ANSI C doesn't like empty source files */
- typedef int _sfwoff2_dummy;
+ typedef int sfwoff2_dummy_;
#endif /* !FT_CONFIG_OPTION_USE_BROTLI */
diff --git a/src/3rdparty/freetype/src/sfnt/ttbdf.c b/src/3rdparty/freetype/src/sfnt/ttbdf.c
index 118f475e7f..536fa7467e 100644
--- a/src/3rdparty/freetype/src/sfnt/ttbdf.c
+++ b/src/3rdparty/freetype/src/sfnt/ttbdf.c
@@ -136,13 +136,14 @@
FT_LOCAL_DEF( FT_Error )
- tt_face_find_bdf_prop( TT_Face face,
+ tt_face_find_bdf_prop( FT_Face face, /* TT_Face */
const char* property_name,
BDF_PropertyRec *aprop )
{
- TT_BDF bdf = &face->bdf;
- FT_Size size = FT_FACE( face )->size;
- FT_Error error = FT_Err_Ok;
+ TT_Face ttface = (TT_Face)face;
+ TT_BDF bdf = &ttface->bdf;
+ FT_Size size = FT_FACE_SIZE( face );
+ FT_Error error = FT_Err_Ok;
FT_Byte* p;
FT_UInt count;
FT_Byte* strike;
@@ -153,7 +154,7 @@
if ( bdf->loaded == 0 )
{
- error = tt_face_load_bdf_props( face, FT_FACE( face )->stream );
+ error = tt_face_load_bdf_props( ttface, FT_FACE_STREAM( face ) );
if ( error )
goto Exit;
}
@@ -248,7 +249,7 @@
#else /* !TT_CONFIG_OPTION_BDF */
/* ANSI C doesn't like empty source files */
- typedef int _tt_bdf_dummy;
+ typedef int tt_bdf_dummy_;
#endif /* !TT_CONFIG_OPTION_BDF */
diff --git a/src/3rdparty/freetype/src/sfnt/ttbdf.h b/src/3rdparty/freetype/src/sfnt/ttbdf.h
index 595aeb76c2..0d7a0acecc 100644
--- a/src/3rdparty/freetype/src/sfnt/ttbdf.h
+++ b/src/3rdparty/freetype/src/sfnt/ttbdf.h
@@ -34,7 +34,7 @@ FT_BEGIN_HEADER
FT_LOCAL( FT_Error )
- tt_face_find_bdf_prop( TT_Face face,
+ tt_face_find_bdf_prop( FT_Face face,
const char* property_name,
BDF_PropertyRec *aprop );
diff --git a/src/3rdparty/freetype/src/sfnt/ttcmap.c b/src/3rdparty/freetype/src/sfnt/ttcmap.c
index 820cd08e6d..9ba25dcbc1 100644
--- a/src/3rdparty/freetype/src/sfnt/ttcmap.c
+++ b/src/3rdparty/freetype/src/sfnt/ttcmap.c
@@ -59,10 +59,14 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap_init( TT_CMap cmap,
- FT_Byte* table )
+ tt_cmap_init( FT_CMap cmap, /* TT_CMap */
+ void* table_ )
{
- cmap->data = table;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* table = (FT_Byte*)table_;
+
+
+ ttcmap->data = table;
return FT_Err_Ok;
}
@@ -128,21 +132,23 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap0_char_index( TT_CMap cmap,
+ tt_cmap0_char_index( FT_CMap cmap, /* TT_CMap */
FT_UInt32 char_code )
{
- FT_Byte* table = cmap->data;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* table = ttcmap->data;
return char_code < 256 ? table[6 + char_code] : 0;
}
- FT_CALLBACK_DEF( FT_UInt32 )
- tt_cmap0_char_next( TT_CMap cmap,
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap0_char_next( FT_CMap cmap, /* TT_CMap */
FT_UInt32 *pchar_code )
{
- FT_Byte* table = cmap->data;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* table = ttcmap->data;
FT_UInt32 charcode = *pchar_code;
FT_UInt32 result = 0;
FT_UInt gindex = 0;
@@ -165,10 +171,11 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap0_get_info( TT_CMap cmap,
+ tt_cmap0_get_info( FT_CharMap cmap, /* TT_CMap */
TT_CMapInfo *cmap_info )
{
- FT_Byte* p = cmap->data + 4;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* p = ttcmap->data + 4;
cmap_info->format = 0;
@@ -453,10 +460,11 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap2_char_index( TT_CMap cmap,
+ tt_cmap2_char_index( FT_CMap cmap, /* TT_CMap */
FT_UInt32 char_code )
{
- FT_Byte* table = cmap->data;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* table = ttcmap->data;
FT_UInt result = 0;
FT_Byte* subheader;
@@ -491,11 +499,12 @@
}
- FT_CALLBACK_DEF( FT_UInt32 )
- tt_cmap2_char_next( TT_CMap cmap,
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap2_char_next( FT_CMap cmap, /* TT_CMap */
FT_UInt32 *pcharcode )
{
- FT_Byte* table = cmap->data;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* table = ttcmap->data;
FT_UInt gindex = 0;
FT_UInt32 result = 0;
FT_UInt32 charcode = *pcharcode + 1;
@@ -579,10 +588,11 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap2_get_info( TT_CMap cmap,
+ tt_cmap2_get_info( FT_CharMap cmap, /* TT_CMap */
TT_CMapInfo *cmap_info )
{
- FT_Byte* p = cmap->data + 4;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* p = ttcmap->data + 4;
cmap_info->format = 2;
@@ -706,18 +716,20 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap4_init( TT_CMap4 cmap,
- FT_Byte* table )
+ tt_cmap4_init( FT_CMap cmap, /* TT_CMap4 */
+ void* table_ )
{
+ TT_CMap4 ttcmap = (TT_CMap4)cmap;
+ FT_Byte* table = (FT_Byte*)table_;
FT_Byte* p;
- cmap->cmap.data = table;
+ ttcmap->cmap.data = table;
- p = table + 6;
- cmap->num_ranges = FT_PEEK_USHORT( p ) >> 1;
- cmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL;
- cmap->cur_gindex = 0;
+ p = table + 6;
+ ttcmap->num_ranges = FT_PEEK_USHORT( p ) >> 1;
+ ttcmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL;
+ ttcmap->cur_gindex = 0;
return FT_Err_Ok;
}
@@ -755,7 +767,7 @@
cmap->cur_start == 0xFFFFU &&
cmap->cur_end == 0xFFFFU )
{
- TT_Face face = (TT_Face)cmap->cmap.cmap.charmap.face;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
FT_Byte* limit = face->cmap_table + face->cmap_size;
@@ -788,15 +800,12 @@
static void
tt_cmap4_next( TT_CMap4 cmap )
{
- TT_Face face = (TT_Face)cmap->cmap.cmap.charmap.face;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
FT_Byte* limit = face->cmap_table + face->cmap_size;
FT_UInt charcode;
- if ( cmap->cur_charcode >= 0xFFFFUL )
- goto Fail;
-
charcode = (FT_UInt)cmap->cur_charcode + 1;
if ( charcode < cmap->cur_start )
@@ -882,7 +891,6 @@
charcode = cmap->cur_start;
}
- Fail:
cmap->cur_charcode = (FT_UInt32)0xFFFFFFFFUL;
cmap->cur_gindex = 0;
}
@@ -1097,32 +1105,26 @@
FT_UInt32* pcharcode,
FT_Bool next )
{
- TT_Face face = (TT_Face)cmap->cmap.charmap.face;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
FT_Byte* limit = face->cmap_table + face->cmap_size;
FT_UInt num_segs2, start, end, offset;
FT_Int delta;
FT_UInt i, num_segs;
- FT_UInt32 charcode = *pcharcode;
+ FT_UInt32 charcode = *pcharcode + next;
FT_UInt gindex = 0;
FT_Byte* p;
FT_Byte* q;
p = cmap->data + 6;
- num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 );
-
- num_segs = num_segs2 >> 1;
+ num_segs = TT_PEEK_USHORT( p ) >> 1;
if ( !num_segs )
return 0;
- if ( next )
- charcode++;
-
- if ( charcode > 0xFFFFU )
- return 0;
+ num_segs2 = num_segs << 1;
/* linear search */
p = cmap->data + 14; /* ends table */
@@ -1232,37 +1234,30 @@
FT_UInt32* pcharcode,
FT_Bool next )
{
- TT_Face face = (TT_Face)cmap->cmap.charmap.face;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
FT_Byte* limit = face->cmap_table + face->cmap_size;
FT_UInt num_segs2, start, end, offset;
FT_Int delta;
FT_UInt max, min, mid, num_segs;
- FT_UInt charcode = (FT_UInt)*pcharcode;
+ FT_UInt charcode = (FT_UInt)*pcharcode + next;
FT_UInt gindex = 0;
FT_Byte* p;
p = cmap->data + 6;
- num_segs2 = FT_PAD_FLOOR( TT_PEEK_USHORT( p ), 2 );
+ num_segs = TT_PEEK_USHORT( p ) >> 1;
- if ( !num_segs2 )
+ if ( !num_segs )
return 0;
- num_segs = num_segs2 >> 1;
-
- /* make compiler happy */
- mid = num_segs;
- end = 0xFFFFU;
-
- if ( next )
- charcode++;
+ num_segs2 = num_segs << 1;
min = 0;
max = num_segs;
/* binary search */
- while ( min < max )
+ do
{
mid = ( min + max ) >> 1;
p = cmap->data + 14 + mid * 2;
@@ -1445,6 +1440,7 @@
break;
}
}
+ while ( min < max );
if ( next )
{
@@ -1454,12 +1450,8 @@
/* if `charcode' is not in any segment, then `mid' is */
/* the segment nearest to `charcode' */
- if ( charcode > end )
- {
- mid++;
- if ( mid == num_segs )
- return 0;
- }
+ if ( charcode > end && ++mid == num_segs )
+ return 0;
if ( tt_cmap4_set_range( cmap4, mid ) )
{
@@ -1474,7 +1466,6 @@
cmap4->cur_gindex = gindex;
else
{
- cmap4->cur_charcode = charcode;
tt_cmap4_next( cmap4 );
gindex = cmap4->cur_gindex;
}
@@ -1489,31 +1480,35 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap4_char_index( TT_CMap cmap,
+ tt_cmap4_char_index( FT_CMap cmap, /* TT_CMap */
FT_UInt32 char_code )
{
+ TT_CMap ttcmap = (TT_CMap)cmap;
+
+
if ( char_code >= 0x10000UL )
return 0;
- if ( cmap->flags & TT_CMAP_FLAG_UNSORTED )
- return tt_cmap4_char_map_linear( cmap, &char_code, 0 );
+ if ( ttcmap->flags & TT_CMAP_FLAG_UNSORTED )
+ return tt_cmap4_char_map_linear( ttcmap, &char_code, 0 );
else
- return tt_cmap4_char_map_binary( cmap, &char_code, 0 );
+ return tt_cmap4_char_map_binary( ttcmap, &char_code, 0 );
}
- FT_CALLBACK_DEF( FT_UInt32 )
- tt_cmap4_char_next( TT_CMap cmap,
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap4_char_next( FT_CMap cmap, /* TT_CMap */
FT_UInt32 *pchar_code )
{
+ TT_CMap ttcmap = (TT_CMap)cmap;
FT_UInt gindex;
if ( *pchar_code >= 0xFFFFU )
return 0;
- if ( cmap->flags & TT_CMAP_FLAG_UNSORTED )
- gindex = tt_cmap4_char_map_linear( cmap, pchar_code, 1 );
+ if ( ttcmap->flags & TT_CMAP_FLAG_UNSORTED )
+ gindex = tt_cmap4_char_map_linear( ttcmap, pchar_code, 1 );
else
{
TT_CMap4 cmap4 = (TT_CMap4)cmap;
@@ -1528,7 +1523,7 @@
*pchar_code = cmap4->cur_charcode;
}
else
- gindex = tt_cmap4_char_map_binary( cmap, pchar_code, 1 );
+ gindex = tt_cmap4_char_map_binary( ttcmap, pchar_code, 1 );
}
return gindex;
@@ -1536,10 +1531,11 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap4_get_info( TT_CMap cmap,
+ tt_cmap4_get_info( FT_CharMap cmap, /* TT_CMap */
TT_CMapInfo *cmap_info )
{
- FT_Byte* p = cmap->data + 4;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* p = ttcmap->data + 4;
cmap_info->format = 4;
@@ -1640,10 +1636,11 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap6_char_index( TT_CMap cmap,
+ tt_cmap6_char_index( FT_CMap cmap, /* TT_CMap */
FT_UInt32 char_code )
{
- FT_Byte* table = cmap->data;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* table = ttcmap->data;
FT_UInt result = 0;
FT_Byte* p = table + 6;
FT_UInt start = TT_NEXT_USHORT( p );
@@ -1661,11 +1658,12 @@
}
- FT_CALLBACK_DEF( FT_UInt32 )
- tt_cmap6_char_next( TT_CMap cmap,
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap6_char_next( FT_CMap cmap, /* TT_CMap */
FT_UInt32 *pchar_code )
{
- FT_Byte* table = cmap->data;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* table = ttcmap->data;
FT_UInt32 result = 0;
FT_UInt32 char_code = *pchar_code + 1;
FT_UInt gindex = 0;
@@ -1706,10 +1704,11 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap6_get_info( TT_CMap cmap,
+ tt_cmap6_get_info( FT_CharMap cmap, /* TT_CMap */
TT_CMapInfo *cmap_info )
{
- FT_Byte* p = cmap->data + 4;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* p = ttcmap->data + 4;
cmap_info->format = 6;
@@ -1900,10 +1899,11 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap8_char_index( TT_CMap cmap,
+ tt_cmap8_char_index( FT_CMap cmap, /* TT_CMap */
FT_UInt32 char_code )
{
- FT_Byte* table = cmap->data;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* table = ttcmap->data;
FT_UInt result = 0;
FT_Byte* p = table + 8204;
FT_UInt32 num_groups = TT_NEXT_ULONG( p );
@@ -1932,15 +1932,16 @@
}
- FT_CALLBACK_DEF( FT_UInt32 )
- tt_cmap8_char_next( TT_CMap cmap,
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap8_char_next( FT_CMap cmap, /* TT_CMap */
FT_UInt32 *pchar_code )
{
- FT_Face face = cmap->cmap.charmap.face;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Face face = FT_CMAP_FACE( cmap );
FT_UInt32 result = 0;
FT_UInt32 char_code;
FT_UInt gindex = 0;
- FT_Byte* table = cmap->data;
+ FT_Byte* table = ttcmap->data;
FT_Byte* p = table + 8204;
FT_UInt32 num_groups = TT_NEXT_ULONG( p );
FT_UInt32 start, end, start_id;
@@ -2000,10 +2001,11 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap8_get_info( TT_CMap cmap,
+ tt_cmap8_get_info( FT_CharMap cmap, /* TT_CMap */
TT_CMapInfo *cmap_info )
{
- FT_Byte* p = cmap->data + 8;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* p = ttcmap->data + 8;
cmap_info->format = 8;
@@ -2104,10 +2106,11 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap10_char_index( TT_CMap cmap,
+ tt_cmap10_char_index( FT_CMap cmap, /* TT_CMap */
FT_UInt32 char_code )
{
- FT_Byte* table = cmap->data;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* table = ttcmap->data;
FT_UInt result = 0;
FT_Byte* p = table + 12;
FT_UInt32 start = TT_NEXT_ULONG( p );
@@ -2130,11 +2133,12 @@
}
- FT_CALLBACK_DEF( FT_UInt32 )
- tt_cmap10_char_next( TT_CMap cmap,
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap10_char_next( FT_CMap cmap, /* TT_CMap */
FT_UInt32 *pchar_code )
{
- FT_Byte* table = cmap->data;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* table = ttcmap->data;
FT_UInt32 char_code;
FT_UInt gindex = 0;
FT_Byte* p = table + 12;
@@ -2172,10 +2176,11 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap10_get_info( TT_CMap cmap,
+ tt_cmap10_get_info( FT_CharMap cmap, /* TT_CMap */
TT_CMapInfo *cmap_info )
{
- FT_Byte* p = cmap->data + 8;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* p = ttcmap->data + 8;
cmap_info->format = 10;
@@ -2253,15 +2258,19 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap12_init( TT_CMap12 cmap,
- FT_Byte* table )
+ tt_cmap12_init( FT_CMap cmap, /* TT_CMap12 */
+ void* table_ )
{
- cmap->cmap.data = table;
+ TT_CMap12 ttcmap = (TT_CMap12)cmap;
+ FT_Byte* table = (FT_Byte*)table_;
+
- table += 12;
- cmap->num_groups = FT_PEEK_ULONG( table );
+ ttcmap->cmap.data = table;
- cmap->valid = 0;
+ table += 12;
+ ttcmap->num_groups = FT_PEEK_ULONG( table );
+
+ ttcmap->valid = 0;
return FT_Err_Ok;
}
@@ -2331,23 +2340,21 @@
/* cmap->cur_group should be set up properly by caller */
/* */
static void
- tt_cmap12_next( TT_CMap12 cmap )
+ tt_cmap12_next( FT_CMap cmap ) /* TT_CMap12 */
{
- FT_Face face = cmap->cmap.cmap.charmap.face;
- FT_Byte* p;
- FT_ULong start, end, start_id, char_code;
- FT_ULong n;
- FT_UInt gindex;
-
+ TT_CMap12 ttcmap = (TT_CMap12)cmap;
+ FT_Face face = FT_CMAP_FACE( cmap );
+ FT_Byte* p;
+ FT_ULong start, end, start_id, char_code;
+ FT_ULong n;
+ FT_UInt gindex;
- if ( cmap->cur_charcode >= 0xFFFFFFFFUL )
- goto Fail;
- char_code = cmap->cur_charcode + 1;
+ char_code = ttcmap->cur_charcode + 1;
- for ( n = cmap->cur_group; n < cmap->num_groups; n++ )
+ for ( n = ttcmap->cur_group; n < ttcmap->num_groups; n++ )
{
- p = cmap->cmap.data + 16 + 12 * n;
+ p = ttcmap->cmap.data + 16 + 12 * n;
start = TT_NEXT_ULONG( p );
end = TT_NEXT_ULONG( p );
start_id = TT_PEEK_ULONG( p );
@@ -2379,16 +2386,16 @@
if ( gindex >= (FT_UInt)face->num_glyphs )
continue;
- cmap->cur_charcode = char_code;
- cmap->cur_gindex = gindex;
- cmap->cur_group = n;
+ ttcmap->cur_charcode = char_code;
+ ttcmap->cur_gindex = gindex;
+ ttcmap->cur_group = n;
return;
}
}
Fail:
- cmap->valid = 0;
+ ttcmap->valid = 0;
}
@@ -2400,7 +2407,7 @@
FT_UInt gindex = 0;
FT_Byte* p = cmap->data + 12;
FT_UInt32 num_groups = TT_PEEK_ULONG( p );
- FT_UInt32 char_code = *pchar_code;
+ FT_UInt32 char_code = *pchar_code + next;
FT_UInt32 start, end, start_id;
FT_UInt32 max, min, mid;
@@ -2408,23 +2415,11 @@
if ( !num_groups )
return 0;
- /* make compiler happy */
- mid = num_groups;
- end = 0xFFFFFFFFUL;
-
- if ( next )
- {
- if ( char_code >= 0xFFFFFFFFUL )
- return 0;
-
- char_code++;
- }
-
min = 0;
max = num_groups;
/* binary search */
- while ( min < max )
+ do
{
mid = ( min + max ) >> 1;
p = cmap->data + 16 + 12 * mid;
@@ -2448,22 +2443,19 @@
break;
}
}
+ while ( min < max );
if ( next )
{
- FT_Face face = cmap->cmap.charmap.face;
+ FT_Face face = FT_CMAP_FACE( cmap );
TT_CMap12 cmap12 = (TT_CMap12)cmap;
/* if `char_code' is not in any group, then `mid' is */
/* the group nearest to `char_code' */
- if ( char_code > end )
- {
- mid++;
- if ( mid == num_groups )
- return 0;
- }
+ if ( char_code > end && ++mid == num_groups )
+ return 0;
cmap12->valid = 1;
cmap12->cur_charcode = char_code;
@@ -2474,7 +2466,7 @@
if ( !gindex )
{
- tt_cmap12_next( cmap12 );
+ tt_cmap12_next( FT_CMAP( cmap12 ) );
if ( cmap12->valid )
gindex = cmap12->cur_gindex;
@@ -2490,25 +2482,28 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap12_char_index( TT_CMap cmap,
+ tt_cmap12_char_index( FT_CMap cmap, /* TT_CMap */
FT_UInt32 char_code )
{
- return tt_cmap12_char_map_binary( cmap, &char_code, 0 );
+ return tt_cmap12_char_map_binary( (TT_CMap)cmap, &char_code, 0 );
}
- FT_CALLBACK_DEF( FT_UInt32 )
- tt_cmap12_char_next( TT_CMap cmap,
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap12_char_next( FT_CMap cmap, /* TT_CMap12 */
FT_UInt32 *pchar_code )
{
TT_CMap12 cmap12 = (TT_CMap12)cmap;
FT_UInt gindex;
+ if ( *pchar_code >= 0xFFFFFFFFUL )
+ return 0;
+
/* no need to search */
if ( cmap12->valid && cmap12->cur_charcode == *pchar_code )
{
- tt_cmap12_next( cmap12 );
+ tt_cmap12_next( FT_CMAP( cmap12 ) );
if ( cmap12->valid )
{
gindex = cmap12->cur_gindex;
@@ -2518,17 +2513,18 @@
gindex = 0;
}
else
- gindex = tt_cmap12_char_map_binary( cmap, pchar_code, 1 );
+ gindex = tt_cmap12_char_map_binary( (TT_CMap)cmap, pchar_code, 1 );
return gindex;
}
FT_CALLBACK_DEF( FT_Error )
- tt_cmap12_get_info( TT_CMap cmap,
+ tt_cmap12_get_info( FT_CharMap cmap, /* TT_CMap */
TT_CMapInfo *cmap_info )
{
- FT_Byte* p = cmap->data + 8;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* p = ttcmap->data + 8;
cmap_info->format = 12;
@@ -2606,15 +2602,19 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap13_init( TT_CMap13 cmap,
- FT_Byte* table )
+ tt_cmap13_init( FT_CMap cmap, /* TT_CMap13 */
+ void* table_ )
{
- cmap->cmap.data = table;
+ TT_CMap13 ttcmap = (TT_CMap13)cmap;
+ FT_Byte* table = (FT_Byte*)table_;
+
+
+ ttcmap->cmap.data = table;
- table += 12;
- cmap->num_groups = FT_PEEK_ULONG( table );
+ table += 12;
+ ttcmap->num_groups = FT_PEEK_ULONG( table );
- cmap->valid = 0;
+ ttcmap->valid = 0;
return FT_Err_Ok;
}
@@ -2679,23 +2679,21 @@
/* cmap->cur_group should be set up properly by caller */
/* */
static void
- tt_cmap13_next( TT_CMap13 cmap )
+ tt_cmap13_next( FT_CMap cmap ) /* TT_CMap13 */
{
- FT_Face face = cmap->cmap.cmap.charmap.face;
- FT_Byte* p;
- FT_ULong start, end, glyph_id, char_code;
- FT_ULong n;
- FT_UInt gindex;
-
+ TT_CMap13 ttcmap = (TT_CMap13)cmap;
+ FT_Face face = FT_CMAP_FACE( cmap );
+ FT_Byte* p;
+ FT_ULong start, end, glyph_id, char_code;
+ FT_ULong n;
+ FT_UInt gindex;
- if ( cmap->cur_charcode >= 0xFFFFFFFFUL )
- goto Fail;
- char_code = cmap->cur_charcode + 1;
+ char_code = ttcmap->cur_charcode + 1;
- for ( n = cmap->cur_group; n < cmap->num_groups; n++ )
+ for ( n = ttcmap->cur_group; n < ttcmap->num_groups; n++ )
{
- p = cmap->cmap.data + 16 + 12 * n;
+ p = ttcmap->cmap.data + 16 + 12 * n;
start = TT_NEXT_ULONG( p );
end = TT_NEXT_ULONG( p );
glyph_id = TT_PEEK_ULONG( p );
@@ -2709,17 +2707,16 @@
if ( gindex && gindex < (FT_UInt)face->num_glyphs )
{
- cmap->cur_charcode = char_code;
- cmap->cur_gindex = gindex;
- cmap->cur_group = n;
+ ttcmap->cur_charcode = char_code;
+ ttcmap->cur_gindex = gindex;
+ ttcmap->cur_group = n;
return;
}
}
}
- Fail:
- cmap->valid = 0;
+ ttcmap->valid = 0;
}
@@ -2731,7 +2728,7 @@
FT_UInt gindex = 0;
FT_Byte* p = cmap->data + 12;
FT_UInt32 num_groups = TT_PEEK_ULONG( p );
- FT_UInt32 char_code = *pchar_code;
+ FT_UInt32 char_code = *pchar_code + next;
FT_UInt32 start, end;
FT_UInt32 max, min, mid;
@@ -2739,23 +2736,11 @@
if ( !num_groups )
return 0;
- /* make compiler happy */
- mid = num_groups;
- end = 0xFFFFFFFFUL;
-
- if ( next )
- {
- if ( char_code >= 0xFFFFFFFFUL )
- return 0;
-
- char_code++;
- }
-
min = 0;
max = num_groups;
/* binary search */
- while ( min < max )
+ do
{
mid = ( min + max ) >> 1;
p = cmap->data + 16 + 12 * mid;
@@ -2774,6 +2759,7 @@
break;
}
}
+ while ( min < max );
if ( next )
{
@@ -2784,12 +2770,8 @@
/* if `char_code' is not in any group, then `mid' is */
/* the group nearest to `char_code' */
- if ( char_code > end )
- {
- mid++;
- if ( mid == num_groups )
- return 0;
- }
+ if ( char_code > end && ++mid == num_groups )
+ return 0;
cmap13->valid = 1;
cmap13->cur_charcode = char_code;
@@ -2800,7 +2782,7 @@
if ( !gindex )
{
- tt_cmap13_next( cmap13 );
+ tt_cmap13_next( FT_CMAP( cmap13 ) );
if ( cmap13->valid )
gindex = cmap13->cur_gindex;
@@ -2816,25 +2798,28 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap13_char_index( TT_CMap cmap,
+ tt_cmap13_char_index( FT_CMap cmap, /* TT_CMap */
FT_UInt32 char_code )
{
- return tt_cmap13_char_map_binary( cmap, &char_code, 0 );
+ return tt_cmap13_char_map_binary( (TT_CMap)cmap, &char_code, 0 );
}
- FT_CALLBACK_DEF( FT_UInt32 )
- tt_cmap13_char_next( TT_CMap cmap,
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap13_char_next( FT_CMap cmap, /* TT_CMap13 */
FT_UInt32 *pchar_code )
{
TT_CMap13 cmap13 = (TT_CMap13)cmap;
FT_UInt gindex;
+ if ( *pchar_code >= 0xFFFFFFFFUL )
+ return 0;
+
/* no need to search */
if ( cmap13->valid && cmap13->cur_charcode == *pchar_code )
{
- tt_cmap13_next( cmap13 );
+ tt_cmap13_next( FT_CMAP( cmap13 ) );
if ( cmap13->valid )
{
gindex = cmap13->cur_gindex;
@@ -2844,17 +2829,18 @@
gindex = 0;
}
else
- gindex = tt_cmap13_char_map_binary( cmap, pchar_code, 1 );
+ gindex = tt_cmap13_char_map_binary( (TT_CMap)cmap, pchar_code, 1 );
return gindex;
}
FT_CALLBACK_DEF( FT_Error )
- tt_cmap13_get_info( TT_CMap cmap,
+ tt_cmap13_get_info( FT_CharMap cmap, /* TT_CMap */
TT_CMapInfo *cmap_info )
{
- FT_Byte* p = cmap->data + 8;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* p = ttcmap->data + 8;
cmap_info->format = 13;
@@ -2969,14 +2955,15 @@
FT_CALLBACK_DEF( void )
- tt_cmap14_done( TT_CMap14 cmap )
+ tt_cmap14_done( FT_CMap cmap ) /* TT_CMap14 */
{
- FT_Memory memory = cmap->memory;
+ TT_CMap14 ttcmap = (TT_CMap14)cmap;
+ FT_Memory memory = ttcmap->memory;
- cmap->max_results = 0;
- if ( memory && cmap->results )
- FT_FREE( cmap->results );
+ ttcmap->max_results = 0;
+ if ( memory && ttcmap->results )
+ FT_FREE( ttcmap->results );
}
@@ -3004,15 +2991,19 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap14_init( TT_CMap14 cmap,
- FT_Byte* table )
+ tt_cmap14_init( FT_CMap cmap, /* TT_CMap14 */
+ void* table_ )
{
- cmap->cmap.data = table;
+ TT_CMap14 ttcmap = (TT_CMap14)cmap;
+ FT_Byte* table = (FT_Byte*)table_;
+
- table += 6;
- cmap->num_selectors = FT_PEEK_ULONG( table );
- cmap->max_results = 0;
- cmap->results = NULL;
+ ttcmap->cmap.data = table;
+
+ table += 6;
+ ttcmap->num_selectors = FT_PEEK_ULONG( table );
+ ttcmap->max_results = 0;
+ ttcmap->results = NULL;
return FT_Err_Ok;
}
@@ -3142,7 +3133,7 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap14_char_index( TT_CMap cmap,
+ tt_cmap14_char_index( FT_CMap cmap,
FT_UInt32 char_code )
{
FT_UNUSED( cmap );
@@ -3153,8 +3144,8 @@
}
- FT_CALLBACK_DEF( FT_UInt32 )
- tt_cmap14_char_next( TT_CMap cmap,
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap14_char_next( FT_CMap cmap,
FT_UInt32 *pchar_code )
{
FT_UNUSED( cmap );
@@ -3166,7 +3157,7 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap14_get_info( TT_CMap cmap,
+ tt_cmap14_get_info( FT_CharMap cmap,
TT_CMapInfo *cmap_info )
{
FT_UNUSED( cmap );
@@ -3280,12 +3271,16 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap14_char_var_index( TT_CMap cmap,
- TT_CMap ucmap,
+ tt_cmap14_char_var_index( FT_CMap cmap, /* TT_CMap */
+ FT_CMap ucmap, /* TT_CMap */
FT_UInt32 charcode,
FT_UInt32 variantSelector )
{
- FT_Byte* p = tt_cmap14_find_variant( cmap->data + 6, variantSelector );
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ TT_CMap ttucmap = (TT_CMap)ucmap;
+
+ FT_Byte* p = tt_cmap14_find_variant( ttcmap->data + 6,
+ variantSelector );
FT_ULong defOff;
FT_ULong nondefOff;
@@ -3296,16 +3291,16 @@
defOff = TT_NEXT_ULONG( p );
nondefOff = TT_PEEK_ULONG( p );
- if ( defOff != 0 &&
- tt_cmap14_char_map_def_binary( cmap->data + defOff, charcode ) )
+ if ( defOff != 0 &&
+ tt_cmap14_char_map_def_binary( ttcmap->data + defOff, charcode ) )
{
/* This is the default variant of this charcode. GID not stored */
/* here; stored in the normal Unicode charmap instead. */
- return ucmap->cmap.clazz->char_index( &ucmap->cmap, charcode );
+ return ttucmap->cmap.clazz->char_index( &ttucmap->cmap, charcode );
}
if ( nondefOff != 0 )
- return tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff,
+ return tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff,
charcode );
return 0;
@@ -3313,11 +3308,13 @@
FT_CALLBACK_DEF( FT_Int )
- tt_cmap14_char_var_isdefault( TT_CMap cmap,
+ tt_cmap14_char_var_isdefault( FT_CMap cmap, /* TT_CMap */
FT_UInt32 charcode,
FT_UInt32 variantSelector )
{
- FT_Byte* p = tt_cmap14_find_variant( cmap->data + 6, variantSelector );
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte* p = tt_cmap14_find_variant( ttcmap->data + 6,
+ variantSelector );
FT_ULong defOff;
FT_ULong nondefOff;
@@ -3328,13 +3325,13 @@
defOff = TT_NEXT_ULONG( p );
nondefOff = TT_NEXT_ULONG( p );
- if ( defOff != 0 &&
- tt_cmap14_char_map_def_binary( cmap->data + defOff, charcode ) )
+ if ( defOff != 0 &&
+ tt_cmap14_char_map_def_binary( ttcmap->data + defOff, charcode ) )
return 1;
- if ( nondefOff != 0 &&
- tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff,
- charcode ) != 0 )
+ if ( nondefOff != 0 &&
+ tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff,
+ charcode ) != 0 )
return 0;
return -1;
@@ -3342,12 +3339,13 @@
FT_CALLBACK_DEF( FT_UInt32* )
- tt_cmap14_variants( TT_CMap cmap,
+ tt_cmap14_variants( FT_CMap cmap, /* TT_CMap14 */
FT_Memory memory )
{
+ TT_CMap ttcmap = (TT_CMap)cmap;
TT_CMap14 cmap14 = (TT_CMap14)cmap;
FT_UInt32 count = cmap14->num_selectors;
- FT_Byte* p = cmap->data + 10;
+ FT_Byte* p = ttcmap->data + 10;
FT_UInt32* result;
FT_UInt32 i;
@@ -3368,13 +3366,14 @@
FT_CALLBACK_DEF( FT_UInt32 * )
- tt_cmap14_char_variants( TT_CMap cmap,
+ tt_cmap14_char_variants( FT_CMap cmap, /* TT_CMap14 */
FT_Memory memory,
FT_UInt32 charCode )
{
- TT_CMap14 cmap14 = (TT_CMap14) cmap;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ TT_CMap14 cmap14 = (TT_CMap14)cmap;
FT_UInt32 count = cmap14->num_selectors;
- FT_Byte* p = cmap->data + 10;
+ FT_Byte* p = ttcmap->data + 10;
FT_UInt32* q;
@@ -3388,12 +3387,12 @@
FT_ULong nondefOff = TT_NEXT_ULONG( p );
- if ( ( defOff != 0 &&
- tt_cmap14_char_map_def_binary( cmap->data + defOff,
- charCode ) ) ||
- ( nondefOff != 0 &&
- tt_cmap14_char_map_nondef_binary( cmap->data + nondefOff,
- charCode ) != 0 ) )
+ if ( ( defOff != 0 &&
+ tt_cmap14_char_map_def_binary( ttcmap->data + defOff,
+ charCode ) ) ||
+ ( nondefOff != 0 &&
+ tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff,
+ charCode ) != 0 ) )
{
q[0] = varSel;
q++;
@@ -3489,15 +3488,16 @@
FT_CALLBACK_DEF( FT_UInt32 * )
- tt_cmap14_variant_chars( TT_CMap cmap,
+ tt_cmap14_variant_chars( FT_CMap cmap, /* TT_CMap */
FT_Memory memory,
FT_UInt32 variantSelector )
{
- FT_Byte *p = tt_cmap14_find_variant( cmap->data + 6,
- variantSelector );
- FT_Int i;
- FT_ULong defOff;
- FT_ULong nondefOff;
+ TT_CMap ttcmap = (TT_CMap)cmap;
+ FT_Byte *p = tt_cmap14_find_variant( ttcmap->data + 6,
+ variantSelector );
+ FT_Int i;
+ FT_ULong defOff;
+ FT_ULong nondefOff;
if ( !p )
@@ -3510,16 +3510,16 @@
return NULL;
if ( defOff == 0 )
- return tt_cmap14_get_nondef_chars( cmap, cmap->data + nondefOff,
+ return tt_cmap14_get_nondef_chars( ttcmap, ttcmap->data + nondefOff,
memory );
else if ( nondefOff == 0 )
- return tt_cmap14_get_def_chars( cmap, cmap->data + defOff,
+ return tt_cmap14_get_def_chars( ttcmap, ttcmap->data + defOff,
memory );
else
{
/* Both a default and a non-default glyph set? That's probably not */
/* good font design, but the spec allows for it... */
- TT_CMap14 cmap14 = (TT_CMap14) cmap;
+ TT_CMap14 cmap14 = (TT_CMap14)cmap;
FT_UInt32 numRanges;
FT_UInt32 numMappings;
FT_UInt32 duni;
@@ -3531,18 +3531,18 @@
FT_UInt32 *ret;
- p = cmap->data + nondefOff;
- dp = cmap->data + defOff;
+ p = ttcmap->data + nondefOff;
+ dp = ttcmap->data + defOff;
numMappings = (FT_UInt32)TT_NEXT_ULONG( p );
dcnt = tt_cmap14_def_char_count( dp );
numRanges = (FT_UInt32)TT_NEXT_ULONG( dp );
if ( numMappings == 0 )
- return tt_cmap14_get_def_chars( cmap, cmap->data + defOff,
+ return tt_cmap14_get_def_chars( ttcmap, ttcmap->data + defOff,
memory );
if ( dcnt == 0 )
- return tt_cmap14_get_nondef_chars( cmap, cmap->data + nondefOff,
+ return tt_cmap14_get_nondef_chars( ttcmap, ttcmap->data + nondefOff,
memory );
if ( tt_cmap14_ensure( cmap14, ( dcnt + numMappings + 1 ), memory ) )
@@ -3664,9 +3664,10 @@
#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
FT_CALLBACK_DEF( const char * )
- tt_get_glyph_name( TT_Face face,
+ tt_get_glyph_name( void* face_, /* TT_Face */
FT_UInt idx )
{
+ TT_Face face = (TT_Face)face_;
FT_String* PSname = NULL;
@@ -3677,12 +3678,13 @@
FT_CALLBACK_DEF( FT_Error )
- tt_cmap_unicode_init( PS_Unicodes unicodes,
- FT_Pointer pointer )
+ tt_cmap_unicode_init( FT_CMap cmap, /* PS_Unicodes */
+ FT_Pointer pointer )
{
- TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes );
- FT_Memory memory = FT_FACE_MEMORY( face );
- FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
FT_UNUSED( pointer );
@@ -3693,17 +3695,18 @@
return psnames->unicodes_init( memory,
unicodes,
face->root.num_glyphs,
- (PS_GetGlyphNameFunc)&tt_get_glyph_name,
+ &tt_get_glyph_name,
(PS_FreeGlyphNameFunc)NULL,
(FT_Pointer)face );
}
FT_CALLBACK_DEF( void )
- tt_cmap_unicode_done( PS_Unicodes unicodes )
+ tt_cmap_unicode_done( FT_CMap cmap ) /* PS_Unicodes */
{
- FT_Face face = FT_CMAP_FACE( unicodes );
- FT_Memory memory = FT_FACE_MEMORY( face );
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ FT_Face face = FT_CMAP_FACE( cmap );
+ FT_Memory memory = FT_FACE_MEMORY( face );
FT_FREE( unicodes->maps );
@@ -3712,23 +3715,25 @@
FT_CALLBACK_DEF( FT_UInt )
- tt_cmap_unicode_char_index( PS_Unicodes unicodes,
- FT_UInt32 char_code )
+ tt_cmap_unicode_char_index( FT_CMap cmap, /* PS_Unicodes */
+ FT_UInt32 char_code )
{
- TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes );
- FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
return psnames->unicodes_char_index( unicodes, char_code );
}
- FT_CALLBACK_DEF( FT_UInt32 )
- tt_cmap_unicode_char_next( PS_Unicodes unicodes,
- FT_UInt32 *pchar_code )
+ FT_CALLBACK_DEF( FT_UInt )
+ tt_cmap_unicode_char_next( FT_CMap cmap, /* PS_Unicodes */
+ FT_UInt32 *pchar_code )
{
- TT_Face face = (TT_Face)FT_CMAP_FACE( unicodes );
- FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
+ PS_Unicodes unicodes = (PS_Unicodes)cmap;
+ TT_Face face = (TT_Face)FT_CMAP_FACE( cmap );
+ FT_Service_PsCMaps psnames = (FT_Service_PsCMaps)face->psnames;
return psnames->unicodes_char_next( unicodes, pchar_code );
@@ -3883,7 +3888,7 @@
tt_get_cmap_info( FT_CharMap charmap,
TT_CMapInfo *cmap_info )
{
- FT_CMap cmap = (FT_CMap)charmap;
+ FT_CMap cmap = FT_CMAP( charmap );
TT_CMap_Class clazz = (TT_CMap_Class)cmap->clazz;
diff --git a/src/3rdparty/freetype/src/sfnt/ttcolr.c b/src/3rdparty/freetype/src/sfnt/ttcolr.c
index 5d98dcab8f..281e7135ee 100644
--- a/src/3rdparty/freetype/src/sfnt/ttcolr.c
+++ b/src/3rdparty/freetype/src/sfnt/ttcolr.c
@@ -229,7 +229,7 @@
base_glyphs_offset_v1 = FT_NEXT_ULONG( p );
- if ( base_glyphs_offset_v1 + 4 >= table_size )
+ if ( base_glyphs_offset_v1 >= table_size - 4 )
goto InvalidTable;
p1 = (FT_Byte*)( table + base_glyphs_offset_v1 );
@@ -249,7 +249,7 @@
if ( layer_offset_v1 )
{
- if ( layer_offset_v1 + 4 >= table_size )
+ if ( layer_offset_v1 >= table_size - 4 )
goto InvalidTable;
p1 = (FT_Byte*)( table + layer_offset_v1 );
@@ -699,7 +699,7 @@
item_deltas ) )
return 0;
- apaint->u.solid.color.alpha += item_deltas[0];
+ apaint->u.solid.color.alpha += (FT_F2Dot14)item_deltas[0];
}
#endif
@@ -1646,7 +1646,7 @@
return 0;
color_stop->stop_offset += F2DOT14_TO_FIXED( item_deltas[0] );
- color_stop->color.alpha += item_deltas[1];
+ color_stop->color.alpha += (FT_F2Dot14)item_deltas[1];
}
#else
FT_UNUSED( var_index_base );
@@ -1914,7 +1914,7 @@
#else /* !TT_CONFIG_OPTION_COLOR_LAYERS */
/* ANSI C doesn't like empty source files */
- typedef int _tt_colr_dummy;
+ typedef int tt_colr_dummy_;
#endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */
diff --git a/src/3rdparty/freetype/src/sfnt/ttcpal.c b/src/3rdparty/freetype/src/sfnt/ttcpal.c
index 4279bc0bd1..46ae08596f 100644
--- a/src/3rdparty/freetype/src/sfnt/ttcpal.c
+++ b/src/3rdparty/freetype/src/sfnt/ttcpal.c
@@ -303,7 +303,7 @@
#else /* !TT_CONFIG_OPTION_COLOR_LAYERS */
/* ANSI C doesn't like empty source files */
- typedef int _tt_cpal_dummy;
+ typedef int tt_cpal_dummy_;
#endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */
diff --git a/src/3rdparty/freetype/src/sfnt/ttload.c b/src/3rdparty/freetype/src/sfnt/ttload.c
index 14f625c824..7b44e9cd2e 100644
--- a/src/3rdparty/freetype/src/sfnt/ttload.c
+++ b/src/3rdparty/freetype/src/sfnt/ttload.c
@@ -504,6 +504,13 @@
FT_FRAME_EXIT();
+ if ( !valid_entries )
+ {
+ FT_TRACE2(( "tt_face_load_font_dir: no valid tables found\n" ));
+ error = FT_THROW( Unknown_File_Format );
+ goto Exit;
+ }
+
FT_TRACE2(( "table directory loaded\n" ));
FT_TRACE2(( "\n" ));
diff --git a/src/3rdparty/freetype/src/sfnt/ttmtx.c b/src/3rdparty/freetype/src/sfnt/ttmtx.c
index 5e53e6dd4a..38ee9ae728 100644
--- a/src/3rdparty/freetype/src/sfnt/ttmtx.c
+++ b/src/3rdparty/freetype/src/sfnt/ttmtx.c
@@ -239,7 +239,7 @@
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
FT_Service_MetricsVariations var =
- (FT_Service_MetricsVariations)face->var;
+ (FT_Service_MetricsVariations)face->tt_var;
#endif
diff --git a/src/3rdparty/freetype/src/sfnt/ttpost.c b/src/3rdparty/freetype/src/sfnt/ttpost.c
index 0e17c6f34a..1dfad4298b 100644
--- a/src/3rdparty/freetype/src/sfnt/ttpost.c
+++ b/src/3rdparty/freetype/src/sfnt/ttpost.c
@@ -156,86 +156,66 @@
static FT_Error
- load_format_20( TT_Face face,
- FT_Stream stream,
- FT_ULong post_len )
+ load_format_20( TT_Post_Names names,
+ FT_Stream stream,
+ FT_UShort num_glyphs,
+ FT_ULong post_len )
{
FT_Memory memory = stream->memory;
FT_Error error;
- FT_Int num_glyphs;
- FT_UShort num_names;
+ FT_UShort n;
+ FT_UShort num_names = 0;
FT_UShort* glyph_indices = NULL;
- FT_Char** name_strings = NULL;
- FT_Byte* strings = NULL;
+ FT_Byte** name_strings = NULL;
+ FT_Byte* q;
- if ( FT_READ_USHORT( num_glyphs ) )
- goto Exit;
-
- /* UNDOCUMENTED! The number of glyphs in this table can be smaller */
- /* than the value in the maxp table (cf. cyberbit.ttf). */
-
- /* There already exist fonts which have more than 32768 glyph names */
- /* in this table, so the test for this threshold has been dropped. */
-
- if ( num_glyphs > face->max_profile.numGlyphs ||
- (FT_ULong)num_glyphs * 2UL > post_len - 2 )
+ if ( (FT_ULong)num_glyphs * 2 > post_len )
{
error = FT_THROW( Invalid_File_Format );
goto Exit;
}
- /* load the indices */
- {
- FT_Int n;
-
-
- if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) ||
- FT_FRAME_ENTER( num_glyphs * 2L ) )
- goto Fail;
-
- for ( n = 0; n < num_glyphs; n++ )
- glyph_indices[n] = FT_GET_USHORT();
+ /* load the indices and note their maximum */
+ if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) ||
+ FT_FRAME_ENTER( num_glyphs * 2 ) )
+ goto Fail;
- FT_FRAME_EXIT();
- }
+ q = (FT_Byte*)stream->cursor;
- /* compute number of names stored in table */
+ for ( n = 0; n < num_glyphs; n++ )
{
- FT_Int n;
+ FT_UShort idx = FT_NEXT_USHORT( q );
- num_names = 0;
+ if ( idx > num_names )
+ num_names = idx;
- for ( n = 0; n < num_glyphs; n++ )
- {
- FT_Int idx;
+ glyph_indices[n] = idx;
+ }
+ FT_FRAME_EXIT();
- idx = glyph_indices[n];
- if ( idx >= 258 )
- {
- idx -= 257;
- if ( idx > num_names )
- num_names = (FT_UShort)idx;
- }
- }
- }
+ /* compute number of names stored in the table */
+ num_names = num_names > 257 ? num_names - 257 : 0;
/* now load the name strings */
if ( num_names )
{
- FT_UShort n;
FT_ULong p;
+ FT_Byte* strings;
- post_len -= (FT_ULong)num_glyphs * 2UL + 2;
+ post_len -= (FT_ULong)num_glyphs * 2;
+
+ if ( FT_QALLOC( name_strings, num_names * sizeof ( FT_Byte* ) +
+ post_len + 1 ) )
+ goto Fail;
- if ( FT_QALLOC( strings, post_len + 1 ) ||
- FT_STREAM_READ( strings, post_len ) ||
- FT_QNEW_ARRAY( name_strings, num_names ) )
+ strings = (FT_Byte*)( name_strings + num_names );
+ if ( FT_STREAM_READ( strings, post_len ) )
goto Fail;
/* convert from Pascal- to C-strings and set pointers */
@@ -251,7 +231,7 @@
}
strings[p] = 0;
- name_strings[n] = (FT_Char*)strings + p + 1;
+ name_strings[n] = strings + p + 1;
p += len + 1;
}
strings[post_len] = 0;
@@ -259,40 +239,24 @@
/* deal with missing or insufficient string data */
if ( n < num_names )
{
- if ( post_len == 0 )
- {
- /* fake empty string */
- if ( FT_QREALLOC( strings, 1, 2 ) )
- goto Fail;
-
- post_len = 1;
- strings[post_len] = 0;
- }
+ FT_TRACE4(( "load_format_20: %hu PostScript names are truncated\n",
+ num_names - n ));
- FT_ERROR(( "load_format_20:"
- " all entries in post table are already parsed,"
- " using NULL names for gid %d - %d\n",
- n, num_names - 1 ));
for ( ; n < num_names; n++ )
- name_strings[n] = (FT_Char*)strings + post_len;
+ name_strings[n] = strings + post_len;
}
}
/* all right, set table fields and exit successfully */
- {
- TT_Post_20 table = &face->postscript_names.names.format_20;
-
+ names->num_glyphs = num_glyphs;
+ names->num_names = num_names;
+ names->glyph_indices = glyph_indices;
+ names->glyph_names = name_strings;
- table->num_glyphs = (FT_UShort)num_glyphs;
- table->num_names = (FT_UShort)num_names;
- table->glyph_indices = glyph_indices;
- table->glyph_names = name_strings;
- }
return FT_Err_Ok;
Fail:
FT_FREE( name_strings );
- FT_FREE( strings );
FT_FREE( glyph_indices );
Exit:
@@ -301,66 +265,55 @@
static FT_Error
- load_format_25( TT_Face face,
- FT_Stream stream,
- FT_ULong post_len )
+ load_format_25( TT_Post_Names names,
+ FT_Stream stream,
+ FT_UShort num_glyphs,
+ FT_ULong post_len )
{
FT_Memory memory = stream->memory;
FT_Error error;
- FT_Int num_glyphs;
- FT_Char* offset_table = NULL;
-
- FT_UNUSED( post_len );
+ FT_UShort n;
+ FT_UShort* glyph_indices = NULL;
+ FT_Byte* q;
- if ( FT_READ_USHORT( num_glyphs ) )
- goto Exit;
-
- /* check the number of glyphs */
- if ( num_glyphs > face->max_profile.numGlyphs ||
- num_glyphs > 258 ||
- num_glyphs < 1 )
+ /* check the number of glyphs, including the theoretical limit */
+ if ( num_glyphs > post_len ||
+ num_glyphs > 258 + 128 )
{
error = FT_THROW( Invalid_File_Format );
goto Exit;
}
- if ( FT_QNEW_ARRAY( offset_table, num_glyphs ) ||
- FT_STREAM_READ( offset_table, num_glyphs ) )
+ /* load the indices and check their Mac range */
+ if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) ||
+ FT_FRAME_ENTER( num_glyphs ) )
goto Fail;
- /* now check the offset table */
- {
- FT_Int n;
+ q = (FT_Byte*)stream->cursor;
+ for ( n = 0; n < num_glyphs; n++ )
+ {
+ FT_Int idx = n + FT_NEXT_CHAR( q );
- for ( n = 0; n < num_glyphs; n++ )
- {
- FT_Long idx = (FT_Long)n + offset_table[n];
+ if ( idx < 0 || idx > 257 )
+ idx = 0;
- if ( idx < 0 || idx > num_glyphs )
- {
- error = FT_THROW( Invalid_File_Format );
- goto Fail;
- }
- }
+ glyph_indices[n] = (FT_UShort)idx;
}
- /* OK, set table fields and exit successfully */
- {
- TT_Post_25 table = &face->postscript_names.names.format_25;
-
+ FT_FRAME_EXIT();
- table->num_glyphs = (FT_UShort)num_glyphs;
- table->offsets = offset_table;
- }
+ /* OK, set table fields and exit successfully */
+ names->num_glyphs = num_glyphs;
+ names->glyph_indices = glyph_indices;
return FT_Err_Ok;
Fail:
- FT_FREE( offset_table );
+ FT_FREE( glyph_indices );
Exit:
return error;
@@ -370,37 +323,37 @@
static FT_Error
load_post_names( TT_Face face )
{
- FT_Stream stream;
- FT_Error error;
- FT_Fixed format;
+ FT_Error error = FT_Err_Ok;
+ FT_Stream stream = face->root.stream;
+ FT_Fixed format = face->postscript.FormatType;
FT_ULong post_len;
+ FT_UShort num_glyphs;
- /* get a stream for the face's resource */
- stream = face->root.stream;
-
/* seek to the beginning of the PS names table */
error = face->goto_table( face, TTAG_post, stream, &post_len );
if ( error )
goto Exit;
- format = face->postscript.FormatType;
-
- /* go to beginning of subtable */
- if ( FT_STREAM_SKIP( 32 ) )
+ /* UNDOCUMENTED! The number of glyphs in this table can be smaller */
+ /* than the value in the maxp table (cf. cyberbit.ttf). */
+ if ( post_len < 34 ||
+ FT_STREAM_SKIP( 32 ) ||
+ FT_READ_USHORT( num_glyphs ) ||
+ num_glyphs > face->max_profile.numGlyphs ||
+ num_glyphs == 0 )
goto Exit;
- /* now read postscript table */
- if ( format == 0x00020000L && post_len >= 34 )
- error = load_format_20( face, stream, post_len - 32 );
- else if ( format == 0x00025000L && post_len >= 34 )
- error = load_format_25( face, stream, post_len - 32 );
- else
- error = FT_THROW( Invalid_File_Format );
-
- face->postscript_names.loaded = 1;
+ /* now read postscript names data */
+ if ( format == 0x00020000L )
+ error = load_format_20( &face->postscript_names, stream,
+ num_glyphs, post_len - 34 );
+ else if ( format == 0x00025000L )
+ error = load_format_25( &face->postscript_names, stream,
+ num_glyphs, post_len - 34 );
Exit:
+ face->postscript_names.loaded = 1; /* even if failed */
return error;
}
@@ -410,39 +363,20 @@
{
FT_Memory memory = face->root.memory;
TT_Post_Names names = &face->postscript_names;
- FT_Fixed format;
- if ( names->loaded )
+ if ( names->num_glyphs )
{
- format = face->postscript.FormatType;
-
- if ( format == 0x00020000L )
- {
- TT_Post_20 table = &names->names.format_20;
-
-
- FT_FREE( table->glyph_indices );
- table->num_glyphs = 0;
-
- if ( table->num_names )
- {
- table->glyph_names[0]--;
- FT_FREE( table->glyph_names[0] );
-
- FT_FREE( table->glyph_names );
- table->num_names = 0;
- }
- }
- else if ( format == 0x00025000L )
- {
- TT_Post_25 table = &names->names.format_25;
-
+ FT_FREE( names->glyph_indices );
+ names->num_glyphs = 0;
+ }
- FT_FREE( table->offsets );
- table->num_glyphs = 0;
- }
+ if ( names->num_names )
+ {
+ FT_FREE( names->glyph_names );
+ names->num_names = 0;
}
+
names->loaded = 0;
}
@@ -478,7 +412,6 @@
FT_String** PSname )
{
FT_Error error;
- TT_Post_Names names;
FT_Fixed format;
#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
@@ -498,8 +431,6 @@
return FT_THROW( Unimplemented_Feature );
#endif
- names = &face->postscript_names;
-
/* `.notdef' by default */
*PSname = MAC_NAME( 0 );
@@ -510,9 +441,10 @@
if ( idx < 258 ) /* paranoid checking */
*PSname = MAC_NAME( idx );
}
- else if ( format == 0x00020000L )
+ else if ( format == 0x00020000L ||
+ format == 0x00025000L )
{
- TT_Post_20 table = &names->names.format_20;
+ TT_Post_Names names = &face->postscript_names;
if ( !names->loaded )
@@ -522,43 +454,29 @@
goto End;
}
- if ( idx < (FT_UInt)table->num_glyphs )
+ if ( idx < (FT_UInt)names->num_glyphs )
{
- FT_UShort name_index = table->glyph_indices[idx];
+ FT_UShort name_index = names->glyph_indices[idx];
if ( name_index < 258 )
*PSname = MAC_NAME( name_index );
- else
- *PSname = (FT_String*)table->glyph_names[name_index - 258];
- }
- }
- else if ( format == 0x00025000L )
- {
- TT_Post_25 table = &names->names.format_25;
-
-
- if ( !names->loaded )
- {
- error = load_post_names( face );
- if ( error )
- goto End;
+ else /* only for version 2.0 */
+ *PSname = (FT_String*)names->glyph_names[name_index - 258];
}
-
- if ( idx < (FT_UInt)table->num_glyphs ) /* paranoid checking */
- *PSname = MAC_NAME( (FT_Int)idx + table->offsets[idx] );
}
/* nothing to do for format == 0x00030000L */
End:
+ /* post format errors ignored */
return FT_Err_Ok;
}
#else /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
/* ANSI C doesn't like empty source files */
- typedef int _tt_post_dummy;
+ typedef int tt_post_dummy_;
#endif /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
diff --git a/src/3rdparty/freetype/src/sfnt/ttsbit.c b/src/3rdparty/freetype/src/sfnt/ttsbit.c
index 3c06955131..03f90a628d 100644
--- a/src/3rdparty/freetype/src/sfnt/ttsbit.c
+++ b/src/3rdparty/freetype/src/sfnt/ttsbit.c
@@ -1677,7 +1677,7 @@
#else /* !TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
/* ANSI C doesn't like empty source files */
- typedef int _tt_sbit_dummy;
+ typedef int tt_sbit_dummy_;
#endif /* !TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
diff --git a/src/3rdparty/freetype/src/sfnt/ttsvg.c b/src/3rdparty/freetype/src/sfnt/ttsvg.c
index c1bbb66b81..4461d483b0 100644
--- a/src/3rdparty/freetype/src/sfnt/ttsvg.c
+++ b/src/3rdparty/freetype/src/sfnt/ttsvg.c
@@ -405,7 +405,7 @@
#else /* !FT_CONFIG_OPTION_SVG */
/* ANSI C doesn't like empty source files */
- typedef int _tt_svg_dummy;
+ typedef int tt_svg_dummy_;
#endif /* !FT_CONFIG_OPTION_SVG */
diff --git a/src/3rdparty/freetype/src/sfnt/woff2tags.c b/src/3rdparty/freetype/src/sfnt/woff2tags.c
index 7a0a351f06..eeedd9906b 100644
--- a/src/3rdparty/freetype/src/sfnt/woff2tags.c
+++ b/src/3rdparty/freetype/src/sfnt/woff2tags.c
@@ -111,7 +111,7 @@
#else /* !FT_CONFIG_OPTION_USE_BROTLI */
/* ANSI C doesn't like empty source files */
- typedef int _woff2tags_dummy;
+ typedef int woff2tags_dummy_;
#endif /* !FT_CONFIG_OPTION_USE_BROTLI */
diff --git a/src/3rdparty/freetype/src/smooth/ftgrays.c b/src/3rdparty/freetype/src/smooth/ftgrays.c
index d9f20eef13..0918272f87 100644
--- a/src/3rdparty/freetype/src/smooth/ftgrays.c
+++ b/src/3rdparty/freetype/src/smooth/ftgrays.c
@@ -1006,10 +1006,11 @@ typedef ptrdiff_t FT_PtrDist;
*
* For other cases, using binary splits is actually slightly faster.
*/
-#if defined( __SSE2__ ) || \
- defined( __x86_64__ ) || \
- defined( _M_AMD64 ) || \
- ( defined( _M_IX86_FP ) && _M_IX86_FP >= 2 )
+#if ( defined( __SSE2__ ) || \
+ defined( __x86_64__ ) || \
+ defined( _M_AMD64 ) || \
+ ( defined( _M_IX86_FP ) && _M_IX86_FP >= 2 ) ) && \
+ !defined( __VMS )
# define FT_SSE2 1
#else
# define FT_SSE2 0
@@ -1427,8 +1428,10 @@ typedef ptrdiff_t FT_PtrDist;
static int
gray_move_to( const FT_Vector* to,
- gray_PWorker worker )
+ void* worker_ ) /* gray_PWorker */
{
+ gray_PWorker worker = (gray_PWorker)worker_;
+
TPos x, y;
@@ -1446,8 +1449,11 @@ typedef ptrdiff_t FT_PtrDist;
static int
gray_line_to( const FT_Vector* to,
- gray_PWorker worker )
+ void* worker_ ) /* gray_PWorker */
{
+ gray_PWorker worker = (gray_PWorker)worker_;
+
+
gray_render_line( RAS_VAR_ UPSCALE( to->x ), UPSCALE( to->y ) );
return 0;
}
@@ -1456,8 +1462,11 @@ typedef ptrdiff_t FT_PtrDist;
static int
gray_conic_to( const FT_Vector* control,
const FT_Vector* to,
- gray_PWorker worker )
+ void* worker_ ) /* gray_PWorker */
{
+ gray_PWorker worker = (gray_PWorker)worker_;
+
+
gray_render_conic( RAS_VAR_ control, to );
return 0;
}
@@ -1467,8 +1476,11 @@ typedef ptrdiff_t FT_PtrDist;
gray_cubic_to( const FT_Vector* control1,
const FT_Vector* control2,
const FT_Vector* to,
- gray_PWorker worker )
+ void* worker_ ) /* gray_PWorker */
{
+ gray_PWorker worker = (gray_PWorker)worker_;
+
+
gray_render_cubic( RAS_VAR_ control1, control2, to );
return 0;
}
@@ -1666,6 +1678,8 @@ typedef ptrdiff_t FT_PtrDist;
int n; /* index of contour in outline */
int first; /* index of first point in contour */
+ int last; /* index of last point in contour */
+
char tag; /* current point's state */
int shift;
@@ -1680,18 +1694,17 @@ typedef ptrdiff_t FT_PtrDist;
shift = func_interface->shift;
delta = func_interface->delta;
- first = 0;
+ last = -1;
for ( n = 0; n < outline->n_contours; n++ )
{
- int last; /* index of last point in contour */
-
-
- FT_TRACE5(( "FT_Outline_Decompose: Outline %d\n", n ));
+ FT_TRACE5(( "FT_Outline_Decompose: Contour %d\n", n ));
+ first = last + 1;
last = outline->contours[n];
- if ( last < 0 )
+ if ( last < first )
goto Invalid_Outline;
+
limit = outline->points + last;
v_start = outline->points[first];
@@ -1874,11 +1887,9 @@ typedef ptrdiff_t FT_PtrDist;
v_start.x / 64.0, v_start.y / 64.0 ));
error = func_interface->line_to( &v_start, user );
- Close:
+ Close:
if ( error )
goto Exit;
-
- first = last + 1;
}
FT_TRACE5(( "FT_Outline_Decompose: Done\n", n ));
@@ -1923,7 +1934,7 @@ typedef ptrdiff_t FT_PtrDist;
if ( continued )
FT_Trace_Enable();
- FT_TRACE7(( "band [%d..%d]: %ld cell%s remaining/\n",
+ FT_TRACE7(( "band [%d..%d]: %td cell%s remaining/\n",
ras.min_ey,
ras.max_ey,
ras.cell_null - ras.cell_free,
@@ -2156,9 +2167,12 @@ typedef ptrdiff_t FT_PtrDist;
#else /* !STANDALONE_ */
static int
- gray_raster_new( FT_Memory memory,
- gray_PRaster* araster )
+ gray_raster_new( void* memory_,
+ FT_Raster* araster_ )
{
+ FT_Memory memory = (FT_Memory)memory_;
+ gray_PRaster* araster = (gray_PRaster*)araster_;
+
FT_Error error;
gray_PRaster raster = NULL;
diff --git a/src/3rdparty/freetype/src/smooth/ftsmooth.c b/src/3rdparty/freetype/src/smooth/ftsmooth.c
index cdbc78c3e5..9b0e8886cb 100644
--- a/src/3rdparty/freetype/src/smooth/ftsmooth.c
+++ b/src/3rdparty/freetype/src/smooth/ftsmooth.c
@@ -87,8 +87,10 @@
/* initialize renderer -- init its raster */
static FT_Error
- ft_smooth_init( FT_Renderer render )
+ ft_smooth_init( FT_Module module ) /* FT_Renderer */
{
+ FT_Renderer render = (FT_Renderer)module;
+
FT_Vector* sub = render->root.library->lcd_geometry;
@@ -111,8 +113,10 @@
ft_smooth_lcd_spans( int y,
int count,
const FT_Span* spans,
- TOrigin* target )
+ void* target_ ) /* TOrigin* */
{
+ TOrigin* target = (TOrigin*)target_;
+
unsigned char* dst_line = target->origin - y * target->pitch;
unsigned char* dst;
unsigned short w;
@@ -141,7 +145,7 @@
/* Set up direct rendering to record them on each third byte. */
params.source = outline;
params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
- params.gray_spans = (FT_SpanFunc)ft_smooth_lcd_spans;
+ params.gray_spans = ft_smooth_lcd_spans;
params.user = &target;
params.clip_box.xMin = 0;
@@ -256,8 +260,11 @@
/* initialize renderer -- init its raster */
static FT_Error
- ft_smooth_init( FT_Renderer render )
+ ft_smooth_init( FT_Module module ) /* FT_Renderer */
{
+ FT_Renderer render = (FT_Renderer)module;
+
+
/* set up default LCD filtering */
FT_Library_SetLcdFilter( render->root.library, FT_LCD_FILTER_DEFAULT );
@@ -340,8 +347,11 @@
ft_smooth_overlap_spans( int y,
int count,
const FT_Span* spans,
- TOrigin* target )
+ void* target_ )
{
+ TOrigin* target = (TOrigin*)target_;
+
+
unsigned char* dst = target->origin - ( y / SCALE ) * target->pitch;
unsigned short x;
unsigned int cover, sum;
@@ -386,7 +396,7 @@
/* Set up direct rendering to average oversampled spans. */
params.source = outline;
params.flags = FT_RASTER_FLAG_AA | FT_RASTER_FLAG_DIRECT;
- params.gray_spans = (FT_SpanFunc)ft_smooth_overlap_spans;
+ params.gray_spans = ft_smooth_overlap_spans;
params.user = &target;
params.clip_box.xMin = 0;
diff --git a/src/3rdparty/freetype/src/svg/ftsvg.c b/src/3rdparty/freetype/src/svg/ftsvg.c
index 7edb1a338e..ba237f6380 100644
--- a/src/3rdparty/freetype/src/svg/ftsvg.c
+++ b/src/3rdparty/freetype/src/svg/ftsvg.c
@@ -40,26 +40,31 @@
/* ft_svg_init */
static FT_Error
- ft_svg_init( SVG_Renderer svg_module )
+ ft_svg_init( FT_Module module )
{
+ SVG_Renderer render = (SVG_Renderer)module;
+
FT_Error error = FT_Err_Ok;
- svg_module->loaded = FALSE;
- svg_module->hooks_set = FALSE;
+ render->loaded = FALSE;
+ render->hooks_set = FALSE;
return error;
}
static void
- ft_svg_done( SVG_Renderer svg_module )
+ ft_svg_done( FT_Module module )
{
- if ( svg_module->loaded == TRUE &&
- svg_module->hooks_set == TRUE )
- svg_module->hooks.free_svg( &svg_module->state );
+ SVG_Renderer render = (SVG_Renderer)module;
+
+
+ if ( render->loaded == TRUE &&
+ render->hooks_set == TRUE )
+ render->hooks.free_svg( &render->state );
- svg_module->loaded = FALSE;
+ render->loaded = FALSE;
}
@@ -148,7 +153,7 @@
static const SVG_Interface svg_interface =
{
- (Preset_Bitmap_Func)ft_svg_preset_slot
+ ft_svg_preset_slot /* Preset_Bitmap_Func preset_slot */
};
@@ -203,7 +208,7 @@
static FT_Error
ft_svg_property_get( FT_Module module,
const char* property_name,
- const void* value )
+ void* value )
{
FT_Error error = FT_Err_Ok;
SVG_Renderer renderer = (SVG_Renderer)module;
@@ -226,8 +231,8 @@
FT_DEFINE_SERVICE_PROPERTIESREC(
ft_svg_service_properties,
- (FT_Properties_SetFunc)ft_svg_property_set, /* set_property */
- (FT_Properties_GetFunc)ft_svg_property_get /* get_property */
+ ft_svg_property_set, /* FT_Properties_SetFunc set_property */
+ ft_svg_property_get /* FT_Properties_GetFunc get_property */
)
@@ -333,17 +338,17 @@
(const void*)PUT_SVG_MODULE( &svg_interface ), /* module specific interface */
- (FT_Module_Constructor)PUT_SVG_MODULE( ft_svg_init ), /* module_init */
- (FT_Module_Destructor)PUT_SVG_MODULE( ft_svg_done ), /* module_done */
- PUT_SVG_MODULE( ft_svg_get_interface ), /* get_interface */
+ PUT_SVG_MODULE( ft_svg_init ), /* FT_Module_Constructor module_init */
+ PUT_SVG_MODULE( ft_svg_done ), /* FT_Module_Destructor module_done */
+ PUT_SVG_MODULE( ft_svg_get_interface ), /* FT_Module_Requester get_interface */
SVG_GLYPH_FORMAT,
- (FT_Renderer_RenderFunc) PUT_SVG_MODULE( ft_svg_render ), /* render_glyph */
- (FT_Renderer_TransformFunc)PUT_SVG_MODULE( ft_svg_transform ), /* transform_glyph */
- NULL, /* get_glyph_cbox */
- NULL, /* set_mode */
- NULL /* raster_class */
+ PUT_SVG_MODULE( ft_svg_render ), /* FT_Renderer_RenderFunc render_glyph */
+ PUT_SVG_MODULE( ft_svg_transform ), /* FT_Renderer_TransformFunc transform_glyph */
+ NULL, /* FT_Renderer_GetCBoxFunc get_glyph_cbox */
+ NULL, /* FT_Renderer_SetModeFunc set_mode */
+ NULL /* FT_Raster_Funcs* raster_class */
)
diff --git a/src/3rdparty/freetype/src/tools/apinames.c b/src/3rdparty/freetype/src/tools/apinames.c
index 8a8b0822b1..dfa258fd7d 100644
--- a/src/3rdparty/freetype/src/tools/apinames.c
+++ b/src/3rdparty/freetype/src/tools/apinames.c
@@ -18,11 +18,14 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stdarg.h>
#include <string.h>
#include <ctype.h>
+#include "vms_shorten_symbol.c"
+
#define PROGRAM_NAME "apinames"
-#define PROGRAM_VERSION "0.4"
+#define PROGRAM_VERSION "0.5"
#define LINEBUFF_SIZE 1024
@@ -41,9 +44,20 @@ typedef enum OutputFormat_
static void
-panic( const char* message )
+panic( const char* fmt,
+ ... )
{
- fprintf( stderr, "PANIC: %s\n", message );
+ va_list ap;
+
+
+ fprintf( stderr, "PANIC: " );
+
+ va_start( ap, fmt );
+ vfprintf( stderr, fmt, ap );
+ va_end( ap );
+
+ fprintf( stderr, "\n" );
+
exit(2);
}
@@ -202,12 +216,24 @@ names_dump( FILE* out,
break;
case OUTPUT_VMS_OPT:
- fprintf( out, "GSMATCH=LEQUAL,2,0\n"
- "CASE_SENSITIVE=YES\n"
- "SYMBOL_VECTOR=(-\n" );
- for ( nn = 0; nn < num_names - 1; nn++ )
- fprintf( out, " %s=PROCEDURE,-\n", the_names[nn].name );
- fprintf( out, " %s=PROCEDURE)\n", the_names[num_names - 1].name );
+ fprintf( out, "case_sensitive=YES\n" );
+
+ for ( nn = 0; nn < num_names; nn++ )
+ {
+ char short_symbol[32];
+
+
+ if ( vms_shorten_symbol( the_names[nn].name, short_symbol, 1 ) == -1 )
+ panic( "could not shorten name '%s'", the_names[nn].name );
+ fprintf( out, "symbol_vector = ( %s = PROCEDURE)\n", short_symbol );
+
+ /* Also emit a 64-bit symbol, as created by the `vms_auto64` tool. */
+ /* It has the string '64__' appended to its name. */
+ strcat( the_names[nn].name , "64__" );
+ if ( vms_shorten_symbol( the_names[nn].name, short_symbol, 1 ) == -1 )
+ panic( "could not shorten name '%s'", the_names[nn].name );
+ fprintf( out, "symbol_vector = ( %s = PROCEDURE)\n", short_symbol );
+ }
break;
diff --git a/src/3rdparty/freetype/src/tools/ftrandom/ftrandom.c b/src/3rdparty/freetype/src/tools/ftrandom/ftrandom.c
index 4f912cd21d..0ee765e528 100644
--- a/src/3rdparty/freetype/src/tools/ftrandom/ftrandom.c
+++ b/src/3rdparty/freetype/src/tools/ftrandom/ftrandom.c
@@ -520,7 +520,7 @@
char buffer[1024];
- sprintf( buffer, "%s/test%d", results_dir, test_num++ );
+ snprintf( buffer, 1024, "%s/test%d", results_dir, test_num++ );
if ( copyfont ( &fontlist[i], buffer ) )
{
diff --git a/src/3rdparty/freetype/src/tools/vms_shorten_symbol.c b/src/3rdparty/freetype/src/tools/vms_shorten_symbol.c
new file mode 100644
index 0000000000..81f2a71877
--- /dev/null
+++ b/src/3rdparty/freetype/src/tools/vms_shorten_symbol.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2010, 2017 Craig A. Berry
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* vms_shorten_symbol
+ *
+ * This program provides shortening of long symbols (> 31 characters) using the
+ * same mechanism as the OpenVMS C compiler. The basic procedure is to compute
+ * an AUTODIN II checksum of the entire symbol, encode the checksum in base32,
+ * and glue together a shortened symbol from the first 23 characters of the
+ * original symbol plus the encoded checksum appended. The output format is
+ * the same used in the name mangler database, stored by default in
+ * [.CXX_REPOSITORY]CXX$DEMANGLER_DB.
+ *
+ * To obtain the same result as CC/NAMES=SHORTENED, run like so:
+ *
+ * $ mcr []vms_shorten_symbol "Please_forgive_this_absurdly_long_symbol_name"
+ * PLEASE_FORGIVE_THIS_ABS1ARO4QU$Please_forgive_this_absurdly_long_symbol_name
+ *
+ * To obtain the same result as CC/NAMES=(SHORTENED,AS_IS), pass a non-zero
+ * value as the second argument, like so:
+ *
+ * $ mcr []vms_shorten_symbol "Please_forgive_this_absurdly_long_symbol_name" 1
+ * Please_forgive_this_abs3rv8rnn$Please_forgive_this_absurdly_long_symbol_name
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __VMS
+#define UINT32 unsigned int
+#else
+#include <inttypes.h>
+#define UINT32 uint32_t
+#endif
+
+extern UINT32 crc32(const char *input_string);
+extern int u32_to_base32(UINT32 input, char *output);
+extern int vms_shorten_symbol(const char *symbol, char *shortened, char as_is_flag);
+
+/*
+ * This routine implements the AUTODIN II polynomial.
+ */
+
+UINT32
+crc32(const char *input_string)
+{
+
+/*
+ * CRC code and data based partly on FreeBSD implementation, which
+ * notes:
+ *
+ * The crc32 functions and data was originally written by Spencer
+ * Garrett <srg@quick.com> and was cleaned from the PostgreSQL source
+ * tree via the files contrib/ltree/crc32.[ch]. No license was
+ * included, therefore it is assumed that this code is public
+ * domain. Attribution still noted.
+ *
+ * (I think they mean "gleaned" not "cleaned".)
+ */
+
+ static const UINT32 autodin_ii_table[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+ };
+
+ UINT32 crc = ~0U;
+ char *c;
+ for (c = (char *)input_string; *c; ++c)
+ crc = (crc >> 8) ^ autodin_ii_table[(crc ^ *c) & 0xff];
+ return ~crc;
+}
+
+/*
+ * This is the RFC2938 variant of base32, not RFC3548, Crockford's, or
+ * other newer variant. It produces an 8-byte encoded character string
+ * (plus trailing null) from a 32-bit integer input.
+ */
+
+int
+u32_to_base32(UINT32 input, char *output)
+{
+ static const char base32hex_table[32] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
+ 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
+ 'u', 'v'
+ };
+ int i;
+
+ /*
+ * Grab lowest 5 bits and look up conversion in table. Lather, rinse,
+ * repeat for a total of 7, 5-bit chunks to accommodate 32 bits of input.
+ */
+ for (i = 0; i < 7; i++) {
+ output[6 - i] = base32hex_table[input & 0x1f];
+ input >>= 5; /* position to look at next 5 */
+ }
+ output[7] = '$'; /* It's DEC, so use '$' not '=' to pad. */
+ output[8] = '\0';
+ return 0;
+}
+
+/*
+ * Take an input symbol name of arbitrary length and produce a symbol shortened
+ * to 31 characters. The shortened symbol consists of the first 23 characters
+ * of the original symbol plus the 8 characters of the encoded checksum. The
+ * third argument is a boolean indicating whether to emulate the compiler's
+ * /NAMES=AS_IS option. When false (the compiler's default), the shortened
+ * symbol will be upper cased. When the original symbol is 31 characters or
+ * fewer in length, no checksum will be appended and the original symbol is
+ * returned verbatim (though upper cased if the as_is_flag is false).
+ */
+
+int
+vms_shorten_symbol(const char *input_symbol, char *shortened, char as_is_flag)
+{
+ char b32str[9];
+ UINT32 crc;
+ char *c, *symbol;
+ int symlen;
+
+ symlen = strlen(input_symbol);
+ symbol = (char *)malloc(symlen + 1);
+ if (symbol == NULL)
+ return -1;
+
+ strncpy(symbol, input_symbol, symlen);
+ symbol[symlen] = '\0';
+
+ if (!as_is_flag) {
+ for (c = symbol; *c; c++)
+ *c = toupper(*c);
+ }
+
+ if (symlen <= 31) {
+ strncpy(shortened, symbol, symlen);
+ shortened[symlen] = '\0';
+ free(symbol);
+ return 0;
+ }
+
+ /*
+ * Compute the checksum on the whole symbol.
+ */
+
+ crc = crc32(symbol);
+
+ /* The compiler does not use the inverted checksum, so we invert it
+ * back before encoding in base32.
+ */
+
+ if (u32_to_base32(~crc, (char *)&b32str) == -1) {
+ free(symbol);
+ return -1;
+ }
+
+ if (!as_is_flag) {
+ for (c = (char *)&b32str; *c; c++)
+ *c = toupper(*c);
+ }
+
+ sprintf(shortened, "%.23s%.8s", symbol, b32str);
+ shortened[31] = '\0';
+ free(symbol);
+ return 0;
+}
+
+#ifdef TEST_MAIN
+int
+main(int argc, char **argv)
+{
+ char short_symbol[32];
+ char as_is_flag = 0;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s <symbol name> [<AS_IS flag>]\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ if (argc > 2)
+ as_is_flag = 1;
+
+ if (vms_shorten_symbol(argv[1], (char *)&short_symbol, as_is_flag) == -1) {
+ fprintf(stderr, "Symbol shortening failed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("%s%s\n", (char *)&short_symbol, argv[1]);
+}
+#endif
diff --git a/src/3rdparty/freetype/src/truetype/rules.mk b/src/3rdparty/freetype/src/truetype/rules.mk
index 23f6f006dd..dde26de1cc 100644
--- a/src/3rdparty/freetype/src/truetype/rules.mk
+++ b/src/3rdparty/freetype/src/truetype/rules.mk
@@ -33,8 +33,7 @@ TT_DRV_SRC := $(TT_DIR)/ttdriver.c \
$(TT_DIR)/ttgxvar.c \
$(TT_DIR)/ttinterp.c \
$(TT_DIR)/ttobjs.c \
- $(TT_DIR)/ttpload.c \
- $(TT_DIR)/ttsubpix.c
+ $(TT_DIR)/ttpload.c
# TrueType driver headers
#
diff --git a/src/3rdparty/freetype/src/truetype/truetype.c b/src/3rdparty/freetype/src/truetype/truetype.c
index c5faa96270..fcc0ea334f 100644
--- a/src/3rdparty/freetype/src/truetype/truetype.c
+++ b/src/3rdparty/freetype/src/truetype/truetype.c
@@ -24,7 +24,6 @@
#include "ttinterp.c"
#include "ttobjs.c" /* object manager */
#include "ttpload.c" /* tables loader */
-#include "ttsubpix.c"
/* END */
diff --git a/src/3rdparty/freetype/src/truetype/ttdriver.c b/src/3rdparty/freetype/src/truetype/ttdriver.c
index 4bea63ef84..d1496fec7f 100644
--- a/src/3rdparty/freetype/src/truetype/ttdriver.c
+++ b/src/3rdparty/freetype/src/truetype/ttdriver.c
@@ -57,7 +57,7 @@
* PROPERTY SERVICE
*
*/
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
tt_property_set( FT_Module module, /* TT_Driver */
const char* property_name,
const void* value,
@@ -93,17 +93,22 @@
interpreter_version = *iv;
}
- if ( interpreter_version == TT_INTERPRETER_VERSION_35
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- || interpreter_version == TT_INTERPRETER_VERSION_38
-#endif
+ switch ( interpreter_version )
+ {
+ case TT_INTERPRETER_VERSION_35:
+ driver->interpreter_version = TT_INTERPRETER_VERSION_35;
+ break;
+
+ case TT_INTERPRETER_VERSION_38:
+ case TT_INTERPRETER_VERSION_40:
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
- || interpreter_version == TT_INTERPRETER_VERSION_40
+ driver->interpreter_version = TT_INTERPRETER_VERSION_40;
+ break;
#endif
- )
- driver->interpreter_version = interpreter_version;
- else
+
+ default:
error = FT_ERR( Unimplemented_Feature );
+ }
return error;
}
@@ -114,10 +119,10 @@
}
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
tt_property_get( FT_Module module, /* TT_Driver */
const char* property_name,
- const void* value )
+ void* value )
{
FT_Error error = FT_Err_Ok;
TT_Driver driver = (TT_Driver)module;
@@ -144,8 +149,8 @@
FT_DEFINE_SERVICE_PROPERTIESREC(
tt_service_properties,
- (FT_Properties_SetFunc)tt_property_set, /* set_property */
- (FT_Properties_GetFunc)tt_property_get /* get_property */
+ tt_property_set, /* FT_Properties_SetFunc set_property */
+ tt_property_get /* FT_Properties_GetFunc get_property */
)
@@ -198,35 +203,35 @@
*
* They can be implemented by format-specific interfaces.
*/
- static FT_Error
- tt_get_kerning( FT_Face ttface, /* TT_Face */
+ FT_CALLBACK_DEF( FT_Error )
+ tt_get_kerning( FT_Face face, /* TT_Face */
FT_UInt left_glyph,
FT_UInt right_glyph,
FT_Vector* kerning )
{
- TT_Face face = (TT_Face)ttface;
- SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+ TT_Face ttface = (TT_Face)face;
+ SFNT_Service sfnt = (SFNT_Service)ttface->sfnt;
kerning->x = 0;
kerning->y = 0;
if ( sfnt )
- kerning->x = sfnt->get_kerning( face, left_glyph, right_glyph );
+ kerning->x = sfnt->get_kerning( ttface, left_glyph, right_glyph );
return 0;
}
- static FT_Error
- tt_get_advances( FT_Face ttface,
+ FT_CALLBACK_DEF( FT_Error )
+ tt_get_advances( FT_Face face, /* TT_Face */
FT_UInt start,
FT_UInt count,
FT_Int32 flags,
FT_Fixed *advances )
{
FT_UInt nn;
- TT_Face face = (TT_Face)ttface;
+ TT_Face ttface = (TT_Face)face;
/* XXX: TODO: check for sbits */
@@ -235,8 +240,8 @@
{
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
/* no fast retrieval for blended MM fonts without VVAR table */
- if ( ( FT_IS_NAMED_INSTANCE( ttface ) || FT_IS_VARIATION( ttface ) ) &&
- !( face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) )
+ if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) &&
+ !( ttface->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) )
return FT_THROW( Unimplemented_Feature );
#endif
@@ -247,7 +252,7 @@
/* since we don't need `tsb', we use zero for `yMax' parameter */
- TT_Get_VMetrics( face, start + nn, 0, &tsb, &ah );
+ TT_Get_VMetrics( ttface, start + nn, 0, &tsb, &ah );
advances[nn] = ah;
}
}
@@ -255,8 +260,8 @@
{
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
/* no fast retrieval for blended MM fonts without HVAR table */
- if ( ( FT_IS_NAMED_INSTANCE( ttface ) || FT_IS_VARIATION( ttface ) ) &&
- !( face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) )
+ if ( ( FT_IS_NAMED_INSTANCE( face ) || FT_IS_VARIATION( face ) ) &&
+ !( ttface->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) )
return FT_THROW( Unimplemented_Feature );
#endif
@@ -266,7 +271,7 @@
FT_UShort aw;
- TT_Get_HMetrics( face, start + nn, &lsb, &aw );
+ TT_Get_HMetrics( ttface, start + nn, &lsb, &aw );
advances[nn] = aw;
}
}
@@ -290,7 +295,7 @@
#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
tt_size_select( FT_Size size,
FT_ULong strike_index )
{
@@ -306,7 +311,7 @@
/* use the scaled metrics, even when tt_size_reset fails */
FT_Select_Metrics( size->face, strike_index );
- tt_size_reset( ttsize, 0 ); /* ignore return value */
+ tt_size_reset( ttsize ); /* ignore return value */
}
else
{
@@ -327,7 +332,7 @@
#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
tt_size_request( FT_Size size,
FT_Size_Request req )
{
@@ -367,7 +372,7 @@
if ( FT_IS_SCALABLE( size->face ) )
{
- error = tt_size_reset( ttsize, 0 );
+ error = tt_size_reset( ttsize );
#ifdef TT_USE_BYTECODE_INTERPRETER
/* for the `MPS' bytecode instruction we need the point size */
@@ -426,15 +431,15 @@
* @Return:
* FreeType error code. 0 means success.
*/
- static FT_Error
- tt_glyph_load( FT_GlyphSlot ttslot, /* TT_GlyphSlot */
- FT_Size ttsize, /* TT_Size */
+ FT_CALLBACK_DEF( FT_Error )
+ tt_glyph_load( FT_GlyphSlot slot, /* TT_GlyphSlot */
+ FT_Size size, /* TT_Size */
FT_UInt glyph_index,
FT_Int32 load_flags )
{
- TT_GlyphSlot slot = (TT_GlyphSlot)ttslot;
- TT_Size size = (TT_Size)ttsize;
- FT_Face face = ttslot->face;
+ TT_GlyphSlot ttslot = (TT_GlyphSlot)slot;
+ TT_Size ttsize = (TT_Size)size;
+ FT_Face face = ttslot->face;
FT_Error error;
@@ -476,12 +481,12 @@
}
/* use hinted metrics only if we load a glyph with hinting */
- size->metrics = ( load_flags & FT_LOAD_NO_HINTING )
- ? &ttsize->metrics
- : &size->hinted_metrics;
+ ttsize->metrics = ( load_flags & FT_LOAD_NO_HINTING )
+ ? &size->metrics
+ : &ttsize->hinted_metrics;
/* now fill in the glyph slot with outline/bitmap/layered */
- error = TT_Load_Glyph( size, slot, glyph_index, load_flags );
+ error = TT_Load_Glyph( ttsize, ttslot, glyph_index, load_flags );
/* force drop-out mode to 2 - irrelevant now */
/* slot->outline.dropout_mode = 2; */
@@ -507,49 +512,47 @@
FT_DEFINE_SERVICE_MULTIMASTERSREC(
tt_service_gx_multi_masters,
- (FT_Get_MM_Func) NULL, /* get_mm */
- (FT_Set_MM_Design_Func) NULL, /* set_mm_design */
- (FT_Set_MM_Blend_Func) TT_Set_MM_Blend, /* set_mm_blend */
- (FT_Get_MM_Blend_Func) TT_Get_MM_Blend, /* get_mm_blend */
- (FT_Get_MM_Var_Func) TT_Get_MM_Var, /* get_mm_var */
- (FT_Set_Var_Design_Func)TT_Set_Var_Design, /* set_var_design */
- (FT_Get_Var_Design_Func)TT_Get_Var_Design, /* get_var_design */
- (FT_Set_Instance_Func) TT_Set_Named_Instance, /* set_instance */
- (FT_Set_MM_WeightVector_Func)
- NULL, /* set_mm_weightvector */
- (FT_Get_MM_WeightVector_Func)
- NULL, /* get_mm_weightvector */
- (FT_Var_Load_Delta_Set_Idx_Map_Func)
- tt_var_load_delta_set_index_mapping,
- /* load_delta_set_idx_map */
- (FT_Var_Load_Item_Var_Store_Func)
- tt_var_load_item_variation_store,
- /* load_item_variation_store */
- (FT_Var_Get_Item_Delta_Func)
- tt_var_get_item_delta, /* get_item_delta */
- (FT_Var_Done_Item_Var_Store_Func)
- tt_var_done_item_variation_store,
- /* done_item_variation_store */
- (FT_Var_Done_Delta_Set_Idx_Map_Func)
- tt_var_done_delta_set_index_map,
- /* done_delta_set_index_map */
- (FT_Get_Var_Blend_Func) tt_get_var_blend, /* get_var_blend */
- (FT_Done_Blend_Func) tt_done_blend /* done_blend */
+ NULL, /* FT_Get_MM_Func get_mm */
+ NULL, /* FT_Set_MM_Design_Func set_mm_design */
+ TT_Set_MM_Blend, /* FT_Set_MM_Blend_Func set_mm_blend */
+ TT_Get_MM_Blend, /* FT_Get_MM_Blend_Func get_mm_blend */
+ TT_Get_MM_Var, /* FT_Get_MM_Var_Func get_mm_var */
+ TT_Set_Var_Design, /* FT_Set_Var_Design_Func set_var_design */
+ TT_Get_Var_Design, /* FT_Get_Var_Design_Func get_var_design */
+ TT_Set_Named_Instance, /* FT_Set_Named_Instance_Func set_named_instance */
+ TT_Get_Default_Named_Instance,
+ /* FT_Get_Default_Named_Instance_Func get_default_named_instance */
+ NULL, /* FT_Set_MM_WeightVector_Func set_mm_weightvector */
+ NULL, /* FT_Get_MM_WeightVector_Func get_mm_weightvector */
+
+ tt_construct_ps_name, /* FT_Construct_PS_Name_Func construct_ps_name */
+ tt_var_load_delta_set_index_mapping,
+ /* FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map */
+ tt_var_load_item_variation_store,
+ /* FT_Var_Load_Item_Var_Store_Func load_item_variation_store */
+ tt_var_get_item_delta, /* FT_Var_Get_Item_Delta_Func get_item_delta */
+ tt_var_done_item_variation_store,
+ /* FT_Var_Done_Item_Var_Store_Func done_item_variation_store */
+ tt_var_done_delta_set_index_map,
+ /* FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_index_map */
+ tt_get_var_blend, /* FT_Get_Var_Blend_Func get_var_blend */
+ tt_done_blend /* FT_Done_Blend_Func done_blend */
)
FT_DEFINE_SERVICE_METRICSVARIATIONSREC(
tt_service_metrics_variations,
- (FT_HAdvance_Adjust_Func)tt_hadvance_adjust, /* hadvance_adjust */
- (FT_LSB_Adjust_Func) NULL, /* lsb_adjust */
- (FT_RSB_Adjust_Func) NULL, /* rsb_adjust */
+ tt_hadvance_adjust, /* FT_HAdvance_Adjust_Func hadvance_adjust */
+ NULL, /* FT_LSB_Adjust_Func lsb_adjust */
+ NULL, /* FT_RSB_Adjust_Func rsb_adjust */
- (FT_VAdvance_Adjust_Func)tt_vadvance_adjust, /* vadvance_adjust */
- (FT_TSB_Adjust_Func) NULL, /* tsb_adjust */
- (FT_BSB_Adjust_Func) NULL, /* bsb_adjust */
- (FT_VOrg_Adjust_Func) NULL, /* vorg_adjust */
+ tt_vadvance_adjust, /* FT_VAdvance_Adjust_Func vadvance_adjust */
+ NULL, /* FT_TSB_Adjust_Func tsb_adjust */
+ NULL, /* FT_BSB_Adjust_Func bsb_adjust */
+ NULL, /* FT_VOrg_Adjust_Func vorg_adjust */
- (FT_Metrics_Adjust_Func) tt_apply_mvar /* metrics_adjust */
+ tt_apply_mvar, /* FT_Metrics_Adjust_Func metrics_adjust */
+ tt_size_reset_height /* FT_Size_Reset_Func size_reset */
)
#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
diff --git a/src/3rdparty/freetype/src/truetype/ttgload.c b/src/3rdparty/freetype/src/truetype/ttgload.c
index d33bdad642..dc427e8a11 100644
--- a/src/3rdparty/freetype/src/truetype/ttgload.c
+++ b/src/3rdparty/freetype/src/truetype/ttgload.c
@@ -35,7 +35,6 @@
#endif
#include "tterrors.h"
-#include "ttsubpix.h"
/**************************************************************************
@@ -152,9 +151,6 @@
FT_UInt glyph_index )
{
TT_Face face = loader->face;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face );
-#endif
FT_Error error;
FT_Stream stream = loader->stream;
@@ -183,20 +179,6 @@
loader->top_bearing = top_bearing;
loader->vadvance = advance_height;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 &&
- loader->exec )
- {
- loader->exec->sph_tweak_flags = 0;
-
- /* This may not be the right place for this, but it works... */
- /* Note that we have to unconditionally load the tweaks since */
- /* it is possible that glyphs individually switch ClearType's */
- /* backward compatibility mode on and off. */
- sph_set_tweaks( loader, glyph_index );
- }
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
#ifdef FT_CONFIG_OPTION_INCREMENTAL
/* With the incremental interface, these values are set by */
/* a call to `tt_get_metrics_incremental'. */
@@ -362,17 +344,16 @@
FT_Byte* p = load->cursor;
FT_Byte* limit = load->limit;
FT_GlyphLoader gloader = load->gloader;
+ FT_Outline* outline = &gloader->current.outline;
FT_Int n_contours = load->n_contours;
- FT_Outline* outline;
- FT_UShort n_ins;
FT_Int n_points;
+ FT_UShort n_ins;
FT_Byte *flag, *flag_limit;
FT_Byte c, count;
FT_Vector *vec, *vec_limit;
FT_Pos x, y;
- FT_Short *cont, *cont_limit, prev_cont;
- FT_Int xy_size = 0;
+ FT_Short *cont, *cont_limit, last;
/* check that we can add the contours to the glyph */
@@ -380,41 +361,27 @@
if ( error )
goto Fail;
- /* reading the contours' endpoints & number of points */
- cont = gloader->current.outline.contours;
- cont_limit = cont + n_contours;
-
/* check space for contours array + instructions count */
- if ( n_contours >= 0xFFF || p + ( n_contours + 1 ) * 2 > limit )
+ if ( n_contours >= 0xFFF || p + 2 * n_contours + 2 > limit )
goto Invalid_Outline;
- prev_cont = FT_NEXT_SHORT( p );
-
- if ( n_contours > 0 )
- cont[0] = prev_cont;
-
- if ( prev_cont < 0 )
- goto Invalid_Outline;
+ /* reading the contours' endpoints & number of points */
+ cont = outline->contours;
+ cont_limit = cont + n_contours;
- for ( cont++; cont < cont_limit; cont++ )
+ last = -1;
+ for ( ; cont < cont_limit; cont++ )
{
- cont[0] = FT_NEXT_SHORT( p );
- if ( cont[0] <= prev_cont )
- {
- /* unordered contours: this is invalid */
- goto Invalid_Outline;
- }
- prev_cont = cont[0];
- }
+ *cont = FT_NEXT_SHORT( p );
- n_points = 0;
- if ( n_contours > 0 )
- {
- n_points = cont[-1] + 1;
- if ( n_points < 0 )
+ if ( *cont <= last )
goto Invalid_Outline;
+
+ last = *cont;
}
+ n_points = last + 1;
+
FT_TRACE5(( " # of points: %d\n", n_points ));
/* note that we will add four phantom points later */
@@ -422,59 +389,48 @@
if ( error )
goto Fail;
- /* reading the bytecode instructions */
- load->glyph->control_len = 0;
- load->glyph->control_data = NULL;
-
- if ( p + 2 > limit )
- goto Invalid_Outline;
-
+ /* space checked above */
n_ins = FT_NEXT_USHORT( p );
FT_TRACE5(( " Instructions size: %u\n", n_ins ));
+ /* check instructions size */
+ if ( p + n_ins > limit )
+ {
+ FT_TRACE1(( "TT_Load_Simple_Glyph: excessive instruction count\n" ));
+ error = FT_THROW( Too_Many_Hints );
+ goto Fail;
+ }
+
#ifdef TT_USE_BYTECODE_INTERPRETER
if ( IS_HINTED( load->load_flags ) )
{
- FT_ULong tmp;
+ TT_ExecContext exec = load->exec;
+ FT_Memory memory = exec->memory;
- /* check instructions size */
- if ( ( limit - p ) < n_ins )
- {
- FT_TRACE1(( "TT_Load_Simple_Glyph: instruction count mismatch\n" ));
- error = FT_THROW( Too_Many_Hints );
- goto Fail;
- }
+ if ( exec->glyphSize )
+ FT_FREE( exec->glyphIns );
+ exec->glyphSize = 0;
/* we don't trust `maxSizeOfInstructions' in the `maxp' table */
- /* and thus update the bytecode array size by ourselves */
-
- tmp = load->exec->glyphSize;
- error = Update_Max( load->exec->memory,
- &tmp,
- sizeof ( FT_Byte ),
- (void*)&load->exec->glyphIns,
- n_ins );
-
- load->exec->glyphSize = (FT_UInt)tmp;
- if ( error )
- return error;
+ /* and thus allocate the bytecode array size by ourselves */
+ if ( n_ins )
+ {
+ if ( FT_QNEW_ARRAY( exec->glyphIns, n_ins ) )
+ return error;
- load->glyph->control_len = n_ins;
- load->glyph->control_data = load->exec->glyphIns;
+ FT_MEM_COPY( exec->glyphIns, p, (FT_Long)n_ins );
- if ( n_ins )
- FT_MEM_COPY( load->exec->glyphIns, p, (FT_Long)n_ins );
+ exec->glyphSize = n_ins;
+ }
}
#endif /* TT_USE_BYTECODE_INTERPRETER */
p += n_ins;
- outline = &gloader->current.outline;
-
/* reading the point tags */
flag = (FT_Byte*)outline->tags;
flag_limit = flag + n_points;
@@ -512,9 +468,6 @@
flag = (FT_Byte*)outline->tags;
x = 0;
- if ( p + xy_size > limit )
- goto Invalid_Outline;
-
for ( ; vec < vec_limit; vec++, flag++ )
{
FT_Pos delta = 0;
@@ -544,7 +497,7 @@
/* reading the Y coordinates */
- vec = gloader->current.outline.points;
+ vec = outline->points;
vec_limit = vec + n_points;
flag = (FT_Byte*)outline->tags;
y = 0;
@@ -827,8 +780,7 @@
TT_Hint_Glyph( TT_Loader loader,
FT_Bool is_composite )
{
-#if defined TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY || \
- defined TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
+#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
TT_Face face = loader->face;
TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face );
#endif
@@ -836,35 +788,34 @@
TT_GlyphZone zone = &loader->zone;
#ifdef TT_USE_BYTECODE_INTERPRETER
- FT_Long n_ins;
+ TT_ExecContext exec = loader->exec;
+ FT_Long n_ins = exec->glyphSize;
#else
FT_UNUSED( is_composite );
#endif
#ifdef TT_USE_BYTECODE_INTERPRETER
- n_ins = loader->glyph->control_len;
-
/* save original point positions in `org' array */
if ( n_ins > 0 )
FT_ARRAY_COPY( zone->org, zone->cur, zone->n_points );
/* Reset graphics state. */
- loader->exec->GS = loader->size->GS;
+ exec->GS = loader->size->GS;
/* XXX: UNDOCUMENTED! Hinting instructions of a composite glyph */
/* completely refer to the (already) hinted subglyphs. */
if ( is_composite )
{
- loader->exec->metrics.x_scale = 1 << 16;
- loader->exec->metrics.y_scale = 1 << 16;
+ exec->metrics.x_scale = 1 << 16;
+ exec->metrics.y_scale = 1 << 16;
FT_ARRAY_COPY( zone->orus, zone->cur, zone->n_points );
}
else
{
- loader->exec->metrics.x_scale = loader->size->metrics->x_scale;
- loader->exec->metrics.y_scale = loader->size->metrics->y_scale;
+ exec->metrics.x_scale = loader->size->metrics->x_scale;
+ exec->metrics.y_scale = loader->size->metrics->y_scale;
}
#endif
@@ -884,53 +835,37 @@
{
FT_Error error;
- FT_GlyphLoader gloader = loader->gloader;
- FT_Outline current_outline = gloader->current.outline;
-
- TT_Set_CodeRange( loader->exec, tt_coderange_glyph,
- loader->exec->glyphIns, n_ins );
+ TT_Set_CodeRange( exec, tt_coderange_glyph, exec->glyphIns, n_ins );
- loader->exec->is_composite = is_composite;
- loader->exec->pts = *zone;
+ exec->is_composite = is_composite;
+ exec->pts = *zone;
- error = TT_Run_Context( loader->exec );
- if ( error && loader->exec->pedantic_hinting )
+ error = TT_Run_Context( exec );
+ if ( error && exec->pedantic_hinting )
return error;
/* store drop-out mode in bits 5-7; set bit 2 also as a marker */
- current_outline.tags[0] |=
- ( loader->exec->GS.scan_type << 5 ) | FT_CURVE_TAG_HAS_SCANMODE;
+ loader->gloader->current.outline.tags[0] |=
+ ( exec->GS.scan_type << 5 ) | FT_CURVE_TAG_HAS_SCANMODE;
}
#endif
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
/* Save possibly modified glyph phantom points unless in v40 backward */
/* compatibility mode, where no movement on the x axis means no reason */
/* to change bearings or advance widths. */
- if ( !( driver->interpreter_version == TT_INTERPRETER_VERSION_40 &&
- loader->exec->backward_compatibility ) )
- {
-#endif
- loader->pp1 = zone->cur[zone->n_points - 4];
- loader->pp2 = zone->cur[zone->n_points - 3];
- loader->pp3 = zone->cur[zone->n_points - 2];
- loader->pp4 = zone->cur[zone->n_points - 1];
+
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
- }
+ if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 &&
+ exec->backward_compatibility )
+ return FT_Err_Ok;
#endif
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
- {
- if ( loader->exec->sph_tweak_flags & SPH_TWEAK_DEEMBOLDEN )
- FT_Outline_EmboldenXY( &loader->gloader->current.outline, -24, 0 );
-
- else if ( loader->exec->sph_tweak_flags & SPH_TWEAK_EMBOLDEN )
- FT_Outline_EmboldenXY( &loader->gloader->current.outline, 24, 0 );
- }
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
+ loader->pp1 = zone->cur[zone->n_points - 4];
+ loader->pp2 = zone->cur[zone->n_points - 3];
+ loader->pp3 = zone->cur[zone->n_points - 2];
+ loader->pp4 = zone->cur[zone->n_points - 1];
return FT_Err_Ok;
}
@@ -949,10 +884,10 @@
static FT_Error
TT_Process_Simple_Glyph( TT_Loader loader )
{
- FT_GlyphLoader gloader = loader->gloader;
- FT_Error error = FT_Err_Ok;
- FT_Outline* outline;
- FT_Int n_points;
+ FT_Error error = FT_Err_Ok;
+ FT_GlyphLoader gloader = loader->gloader;
+ FT_Outline* outline = &gloader->current.outline;
+ FT_Int n_points = outline->n_points;
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
FT_Memory memory = loader->face->root.memory;
@@ -960,11 +895,7 @@
#endif
- outline = &gloader->current.outline;
- n_points = outline->n_points;
-
/* set phantom points */
-
outline->points[n_points ] = loader->pp1;
outline->points[n_points + 1] = loader->pp2;
outline->points[n_points + 2] = loader->pp3;
@@ -976,7 +907,7 @@
if ( !IS_DEFAULT_INSTANCE( FT_FACE( loader->face ) ) )
{
- if ( FT_NEW_ARRAY( unrounded, n_points ) )
+ if ( FT_QNEW_ARRAY( unrounded, n_points ) )
goto Exit;
/* Deltas apply to the unscaled data. */
@@ -998,16 +929,6 @@
}
{
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- TT_Face face = loader->face;
- TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face );
-
- FT_String* family = face->root.family_name;
- FT_UInt ppem = loader->size->metrics->x_ppem;
- FT_String* style = face->root.style_name;
- FT_UInt x_scale_factor = 1000;
-#endif
-
FT_Vector* vec = outline->points;
FT_Vector* limit = outline->points + n_points;
@@ -1017,52 +938,6 @@
FT_Bool do_scale = FALSE;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-
- if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
- {
- /* scale, but only if enabled and only if TT hinting is being used */
- if ( IS_HINTED( loader->load_flags ) )
- x_scale_factor = sph_test_tweak_x_scaling( face,
- family,
- ppem,
- style,
- loader->glyph_index );
- /* scale the glyph */
- if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ||
- x_scale_factor != 1000 )
- {
- x_scale = FT_MulDiv( loader->size->metrics->x_scale,
- (FT_Long)x_scale_factor, 1000 );
- y_scale = loader->size->metrics->y_scale;
-
- /* compensate for any scaling by de/emboldening; */
- /* the amount was determined via experimentation */
- if ( x_scale_factor != 1000 && ppem > 11 )
- {
-#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
- FT_Vector* orig_points = outline->points;
-
-
- if ( !IS_DEFAULT_INSTANCE( FT_FACE( loader->face ) ) )
- outline->points = unrounded;
-#endif
- FT_Outline_EmboldenXY( outline,
- FT_MulFix( 1280 * ppem,
- 1000 - x_scale_factor ),
- 0 );
-#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
- if ( !IS_DEFAULT_INSTANCE( FT_FACE( loader->face ) ) )
- outline->points = orig_points;
-#endif
- }
- do_scale = TRUE;
- }
- }
- else
-
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
{
/* scale the glyph */
if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
@@ -1331,12 +1206,12 @@
FT_UInt start_contour )
{
FT_Error error;
- FT_Outline* outline;
+ FT_Outline* outline = &loader->gloader->base.outline;
+ FT_Stream stream = loader->stream;
+ FT_UShort n_ins;
FT_UInt i;
- outline = &loader->gloader->base.outline;
-
/* make room for phantom points */
error = FT_GLYPHLOADER_CHECK_POINTS( loader->gloader,
outline->n_points + 4,
@@ -1352,10 +1227,13 @@
#ifdef TT_USE_BYTECODE_INTERPRETER
{
- FT_Stream stream = loader->stream;
- FT_UShort n_ins, max_ins;
- FT_ULong tmp;
+ TT_ExecContext exec = loader->exec;
+ FT_Memory memory = exec->memory;
+
+ if ( exec->glyphSize )
+ FT_FREE( exec->glyphIns );
+ exec->glyphSize = 0;
/* TT_Load_Composite_Glyph only gives us the offset of instructions */
/* so we read them here */
@@ -1365,39 +1243,24 @@
FT_TRACE5(( " Instructions size = %hu\n", n_ins ));
- /* check it */
- max_ins = loader->face->max_profile.maxSizeOfInstructions;
- if ( n_ins > max_ins )
- {
- /* don't trust `maxSizeOfInstructions'; */
- /* only do a rough safety check */
- if ( n_ins > loader->byte_len )
- {
- FT_TRACE1(( "TT_Process_Composite_Glyph:"
- " too many instructions (%hu) for glyph with length %u\n",
- n_ins, loader->byte_len ));
- return FT_THROW( Too_Many_Hints );
- }
-
- tmp = loader->exec->glyphSize;
- error = Update_Max( loader->exec->memory,
- &tmp,
- sizeof ( FT_Byte ),
- (void*)&loader->exec->glyphIns,
- n_ins );
+ if ( !n_ins )
+ return FT_Err_Ok;
- loader->exec->glyphSize = (FT_UShort)tmp;
- if ( error )
- return error;
+ /* don't trust `maxSizeOfInstructions'; */
+ /* only do a rough safety check */
+ if ( n_ins > loader->byte_len )
+ {
+ FT_TRACE1(( "TT_Process_Composite_Glyph:"
+ " too many instructions (%hu) for glyph with length %u\n",
+ n_ins, loader->byte_len ));
+ return FT_THROW( Too_Many_Hints );
}
- else if ( n_ins == 0 )
- return FT_Err_Ok;
- if ( FT_STREAM_READ( loader->exec->glyphIns, n_ins ) )
+ if ( FT_QNEW_ARRAY( exec->glyphIns, n_ins ) ||
+ FT_STREAM_READ( exec->glyphIns, n_ins ) )
return error;
- loader->glyph->control_data = loader->exec->glyphIns;
- loader->glyph->control_len = n_ins;
+ exec->glyphSize = n_ins;
}
#endif
@@ -1501,45 +1364,31 @@
static void
tt_loader_set_pp( TT_Loader loader )
{
- FT_Bool subpixel_hinting = 0;
- FT_Bool grayscale = 0;
- FT_Bool use_aw_2 = 0;
-
-#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
- TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( loader->face );
-#endif
-
-
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
- {
- subpixel_hinting = loader->exec ? loader->exec->subpixel_hinting
- : 0;
- grayscale = loader->exec ? loader->exec->grayscale
- : 0;
- }
-#endif
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
- if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 )
- {
- subpixel_hinting = loader->exec ? loader->exec->subpixel_hinting_lean
- : 0;
- grayscale = loader->exec ? loader->exec->grayscale_cleartype
- : 0;
- }
-#endif
-
- use_aw_2 = FT_BOOL( subpixel_hinting && grayscale );
-
loader->pp1.x = loader->bbox.xMin - loader->left_bearing;
loader->pp1.y = 0;
loader->pp2.x = loader->pp1.x + loader->advance;
loader->pp2.y = 0;
- loader->pp3.x = use_aw_2 ? loader->advance / 2 : 0;
+ loader->pp3.x = 0;
loader->pp3.y = loader->bbox.yMax + loader->top_bearing;
- loader->pp4.x = use_aw_2 ? loader->advance / 2 : 0;
+ loader->pp4.x = 0;
loader->pp4.y = loader->pp3.y - loader->vadvance;
+
+#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
+ {
+ TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( loader->face );
+
+
+ if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 &&
+ loader->exec &&
+ loader->exec->subpixel_hinting_lean &&
+ loader->exec->grayscale_cleartype )
+ {
+ loader->pp3.x = loader->advance / 2;
+ loader->pp4.x = loader->advance / 2;
+ }
+ }
+#endif
}
@@ -1662,8 +1511,14 @@
else
#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+ {
+ FT_ULong len;
+
- offset = tt_face_get_location( face, glyph_index, &loader->byte_len );
+ offset = tt_face_get_location( FT_FACE( face ), glyph_index, &len );
+
+ loader->byte_len = (FT_UInt)len;
+ }
if ( loader->byte_len > 0 )
{
@@ -1889,10 +1744,7 @@
short i, limit;
FT_SubGlyph subglyph;
- FT_Outline outline;
- FT_Vector* points = NULL;
- char* tags = NULL;
- short* contours = NULL;
+ FT_Outline outline = { 0, 0, NULL, NULL, NULL, 0 };
FT_Vector* unrounded = NULL;
@@ -1900,18 +1752,14 @@
/* construct an outline structure for */
/* communication with `TT_Vary_Apply_Glyph_Deltas' */
- outline.n_contours = outline.n_points = limit;
-
- outline.points = NULL;
- outline.tags = NULL;
- outline.contours = NULL;
-
- if ( FT_NEW_ARRAY( points, limit + 4 ) ||
- FT_NEW_ARRAY( tags, limit + 4 ) ||
- FT_NEW_ARRAY( contours, limit + 4 ) ||
- FT_NEW_ARRAY( unrounded, limit + 4 ) )
+ if ( FT_QNEW_ARRAY( outline.points, limit + 4 ) ||
+ FT_QNEW_ARRAY( outline.tags, limit ) ||
+ FT_QNEW_ARRAY( outline.contours, limit ) ||
+ FT_QNEW_ARRAY( unrounded, limit + 4 ) )
goto Exit1;
+ outline.n_contours = outline.n_points = limit;
+
subglyph = gloader->current.subglyphs;
for ( i = 0; i < limit; i++, subglyph++ )
@@ -1919,20 +1767,16 @@
/* applying deltas for anchor points doesn't make sense, */
/* but we don't have to specially check this since */
/* unused delta values are zero anyways */
- points[i].x = subglyph->arg1;
- points[i].y = subglyph->arg2;
- tags[i] = 1;
- contours[i] = i;
+ outline.points[i].x = subglyph->arg1;
+ outline.points[i].y = subglyph->arg2;
+ outline.tags[i] = ON_CURVE_POINT;
+ outline.contours[i] = i;
}
- points[i++] = loader->pp1;
- points[i++] = loader->pp2;
- points[i++] = loader->pp3;
- points[i ] = loader->pp4;
-
- outline.points = points;
- outline.tags = tags;
- outline.contours = contours;
+ outline.points[i++] = loader->pp1;
+ outline.points[i++] = loader->pp2;
+ outline.points[i++] = loader->pp3;
+ outline.points[i ] = loader->pp4;
/* this call provides additional offsets */
/* for each component's translation */
@@ -1947,8 +1791,8 @@
{
if ( subglyph->flags & ARGS_ARE_XY_VALUES )
{
- subglyph->arg1 = (FT_Int16)points[i].x;
- subglyph->arg2 = (FT_Int16)points[i].y;
+ subglyph->arg1 = (FT_Int16)outline.points[i].x;
+ subglyph->arg2 = (FT_Int16)outline.points[i].y;
}
}
@@ -2332,8 +2176,7 @@
#ifdef TT_USE_BYTECODE_INTERPRETER
FT_Error error;
FT_Bool pedantic = FT_BOOL( load_flags & FT_LOAD_PEDANTIC );
-#if defined TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY || \
- defined TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
+#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( glyph->face );
#endif
#endif
@@ -2353,20 +2196,6 @@
FT_Bool grayscale_cleartype;
#endif
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- FT_Bool subpixel_hinting = FALSE;
-
-#if 0
- /* not used yet */
- FT_Bool compatible_widths;
- FT_Bool symmetrical_smoothing;
- FT_Bool bgr;
- FT_Bool vertical_lcd;
- FT_Bool subpixel_positioned;
- FT_Bool gray_cleartype;
-#endif
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
FT_Bool reexecute = FALSE;
@@ -2386,6 +2215,9 @@
if ( !exec )
return FT_THROW( Could_Not_Find_Context );
+ grayscale = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
+ FT_RENDER_MODE_MONO );
+
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 )
{
@@ -2402,6 +2234,7 @@
FT_BOOL( subpixel_hinting_lean &&
( load_flags &
FT_LOAD_TARGET_LCD_V ) );
+ grayscale = FT_BOOL( grayscale && !subpixel_hinting_lean );
}
else
{
@@ -2411,111 +2244,11 @@
}
#endif
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-
- if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
- {
- subpixel_hinting = FT_BOOL( ( FT_LOAD_TARGET_MODE( load_flags ) !=
- FT_RENDER_MODE_MONO ) &&
- SPH_OPTION_SET_SUBPIXEL );
-
- if ( subpixel_hinting )
- grayscale = FALSE;
- else if ( SPH_OPTION_SET_GRAYSCALE )
- {
- grayscale = TRUE;
- subpixel_hinting = FALSE;
- }
- else
- grayscale = FALSE;
-
- if ( FT_IS_TRICKY( glyph->face ) )
- subpixel_hinting = FALSE;
-
- exec->ignore_x_mode = subpixel_hinting || grayscale;
- exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION;
- if ( exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 )
- exec->rasterizer_version = TT_INTERPRETER_VERSION_35;
-
-#if 1
- exec->compatible_widths = SPH_OPTION_SET_COMPATIBLE_WIDTHS;
- exec->symmetrical_smoothing = TRUE;
- exec->bgr = FALSE;
- exec->vertical_lcd = FALSE;
- exec->subpixel_positioned = TRUE;
- exec->gray_cleartype = FALSE;
-#else /* 0 */
- exec->compatible_widths =
- FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
- TT_LOAD_COMPATIBLE_WIDTHS );
- exec->symmetrical_smoothing =
- FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
- TT_LOAD_SYMMETRICAL_SMOOTHING );
- exec->bgr =
- FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
- TT_LOAD_BGR );
- exec->vertical_lcd =
- FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
- TT_LOAD_VERTICAL_LCD );
- exec->subpixel_positioned =
- FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
- TT_LOAD_SUBPIXEL_POSITIONED );
- exec->gray_cleartype =
- FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
- TT_LOAD_GRAY_CLEARTYPE );
-#endif /* 0 */
-
- }
- else
-
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
- if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 )
- grayscale = FT_BOOL( !subpixel_hinting_lean &&
- FT_LOAD_TARGET_MODE( load_flags ) !=
- FT_RENDER_MODE_MONO );
- else
-#endif
- grayscale = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
- FT_RENDER_MODE_MONO );
-
error = TT_Load_Context( exec, face, size );
if ( error )
return error;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-
- if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
- {
- /* a change from mono to subpixel rendering (and vice versa) */
- /* requires a re-execution of the CVT program */
- if ( subpixel_hinting != exec->subpixel_hinting )
- {
- FT_TRACE4(( "tt_loader_init: subpixel hinting change,"
- " re-executing `prep' table\n" ));
-
- exec->subpixel_hinting = subpixel_hinting;
- reexecute = TRUE;
- }
-
- /* a change from mono to grayscale rendering (and vice versa) */
- /* requires a re-execution of the CVT program */
- if ( grayscale != exec->grayscale )
- {
- FT_TRACE4(( "tt_loader_init: grayscale hinting change,"
- " re-executing `prep' table\n" ));
-
- exec->grayscale = grayscale;
- reexecute = TRUE;
- }
- }
- else
-
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
{
-
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 )
{
@@ -2573,14 +2306,6 @@
if ( exec->GS.instruct_control & 2 )
exec->GS = tt_default_graphics_state;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- /* check whether we have a font hinted for ClearType -- */
- /* note that this flag can also be modified in a glyph's bytecode */
- if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 &&
- exec->GS.instruct_control & 4 )
- exec->ignore_x_mode = FALSE;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
/*
* Toggle backward compatibility according to what font wants, except
@@ -2617,13 +2342,6 @@
!( driver->interpreter_version == TT_INTERPRETER_VERSION_40 &&
exec->backward_compatibility ) &&
#endif
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- !( driver->interpreter_version == TT_INTERPRETER_VERSION_38 &&
- !SPH_OPTION_BITMAP_WIDTHS &&
- FT_LOAD_TARGET_MODE( loader->load_flags ) !=
- FT_RENDER_MODE_MONO &&
- exec->compatible_widths ) &&
-#endif
!face->postscript.isFixedPitch )
{
loader->widthp = size->widthp;
@@ -2857,7 +2575,9 @@
#ifdef FT_CONFIG_OPTION_SVG
/* check for OT-SVG */
- if ( ( load_flags & FT_LOAD_COLOR ) && face->svg )
+ if ( ( load_flags & FT_LOAD_NO_SVG ) == 0 &&
+ ( load_flags & FT_LOAD_COLOR ) &&
+ face->svg )
{
SFNT_Service sfnt = (SFNT_Service)face->sfnt;
@@ -2955,6 +2675,9 @@
if ( IS_HINTED( load_flags ) )
{
+ glyph->control_data = loader.exec->glyphIns;
+ glyph->control_len = loader.exec->glyphSize;
+
if ( loader.exec->GS.scan_control )
{
/* convert scan conversion mode to FT_OUTLINE_XXX flags */
diff --git a/src/3rdparty/freetype/src/truetype/ttgxvar.c b/src/3rdparty/freetype/src/truetype/ttgxvar.c
index 60a0095b6e..ad4f266b27 100644
--- a/src/3rdparty/freetype/src/truetype/ttgxvar.c
+++ b/src/3rdparty/freetype/src/truetype/ttgxvar.c
@@ -45,6 +45,7 @@
#include <freetype/internal/ftcalc.h>
#include <freetype/internal/ftstream.h>
#include <freetype/internal/sfnt.h>
+#include <freetype/internal/services/svmetric.h>
#include <freetype/tttags.h>
#include <freetype/ttnameid.h>
#include <freetype/ftmm.h>
@@ -465,7 +466,7 @@
if ( store_offset )
{
error = tt_var_load_item_variation_store(
- face,
+ FT_FACE( face ),
table_offset + store_offset,
&table->itemStore );
if ( error )
@@ -475,7 +476,7 @@
if ( axisMap_offset )
{
error = tt_var_load_delta_set_index_mapping(
- face,
+ FT_FACE( face ),
table_offset + axisMap_offset,
&table->axisMap,
&table->itemStore,
@@ -492,10 +493,11 @@
FT_LOCAL_DEF( FT_Error )
- tt_var_load_item_variation_store( TT_Face face,
+ tt_var_load_item_variation_store( FT_Face face, /* TT_Face */
FT_ULong offset,
GX_ItemVarStore itemStore )
{
+ TT_Face ttface = (TT_Face)face;
FT_Stream stream = FT_FACE_STREAM( face );
FT_Memory memory = stream->memory;
@@ -507,10 +509,10 @@
FT_UShort axis_count;
FT_UInt region_count;
- FT_UInt i, j, k;
+ FT_UInt i, j;
FT_Bool long_words;
- GX_Blend blend = face->blend;
+ GX_Blend blend = ttface->blend;
FT_ULong* dataOffsetArray = NULL;
@@ -619,9 +621,10 @@
{
GX_ItemVarData varData = &itemStore->varData[i];
- FT_UInt item_count;
- FT_UInt word_delta_count;
- FT_UInt region_idx_count;
+ FT_UInt item_count;
+ FT_UShort word_delta_count;
+ FT_UInt region_idx_count;
+ FT_UInt per_region_size;
if ( FT_STREAM_SEEK( offset + dataOffsetArray[i] ) )
@@ -658,6 +661,8 @@
if ( FT_NEW_ARRAY( varData->regionIndices, region_idx_count ) )
goto Exit;
varData->regionIdxCount = region_idx_count;
+ varData->wordDeltaCount = word_delta_count;
+ varData->longWords = long_words;
for ( j = 0; j < varData->regionIdxCount; j++ )
{
@@ -673,37 +678,22 @@
}
}
- /* Parse delta set. */
- /* */
- /* On input, deltas are (word_delta_count + region_idx_count) bytes */
- /* each if `long_words` isn't set, and twice as much otherwise. */
- /* */
- /* On output, deltas are expanded to `region_idx_count` shorts each. */
- if ( FT_NEW_ARRAY( varData->deltaSet, item_count * region_idx_count ) )
- goto Exit;
- varData->itemCount = item_count;
+ per_region_size = word_delta_count + region_idx_count;
+ if ( long_words )
+ per_region_size *= 2;
- for ( j = 0; j < item_count * region_idx_count; )
+ if ( FT_NEW_ARRAY( varData->deltaSet, per_region_size * item_count ) )
+ goto Exit;
+ if ( FT_Stream_Read( stream,
+ varData->deltaSet,
+ per_region_size * item_count ) )
{
- if ( long_words )
- {
- for ( k = 0; k < word_delta_count; k++, j++ )
- if ( FT_READ_LONG( varData->deltaSet[j] ) )
- goto Exit;
- for ( ; k < region_idx_count; k++, j++ )
- if ( FT_READ_SHORT( varData->deltaSet[j] ) )
- goto Exit;
- }
- else
- {
- for ( k = 0; k < word_delta_count; k++, j++ )
- if ( FT_READ_SHORT( varData->deltaSet[j] ) )
- goto Exit;
- for ( ; k < region_idx_count; k++, j++ )
- if ( FT_READ_CHAR( varData->deltaSet[j] ) )
- goto Exit;
- }
+ FT_TRACE2(( "deltaSet read failed." ));
+ error = FT_THROW( Invalid_Table );
+ goto Exit;
}
+
+ varData->itemCount = item_count;
}
Exit:
@@ -714,7 +704,7 @@
FT_LOCAL_DEF( FT_Error )
- tt_var_load_delta_set_index_mapping( TT_Face face,
+ tt_var_load_delta_set_index_mapping( FT_Face face, /* TT_Face */
FT_ULong offset,
GX_DeltaSetIdxMap map,
GX_ItemVarStore itemStore,
@@ -941,7 +931,7 @@
}
error = tt_var_load_item_variation_store(
- face,
+ FT_FACE( face ),
table_offset + store_offset,
&table->itemStore );
if ( error )
@@ -950,7 +940,7 @@
if ( widthMap_offset )
{
error = tt_var_load_delta_set_index_mapping(
- face,
+ FT_FACE( face ),
table_offset + widthMap_offset,
&table->widthMap,
&table->itemStore,
@@ -992,24 +982,30 @@
FT_LOCAL_DEF( FT_ItemVarDelta )
- tt_var_get_item_delta( TT_Face face,
+ tt_var_get_item_delta( FT_Face face, /* TT_Face */
GX_ItemVarStore itemStore,
FT_UInt outerIndex,
FT_UInt innerIndex )
{
+ TT_Face ttface = (TT_Face)face;
FT_Stream stream = FT_FACE_STREAM( face );
FT_Memory memory = stream->memory;
FT_Error error = FT_Err_Ok;
GX_ItemVarData varData;
- FT_ItemVarDelta* deltaSet;
+ FT_ItemVarDelta* deltaSet = NULL;
+ FT_ItemVarDelta deltaSetStack[16];
+
+ FT_Fixed* scalars = NULL;
+ FT_Fixed scalarsStack[16];
FT_UInt master, j;
- FT_Fixed* scalars = NULL;
- FT_ItemVarDelta returnValue;
+ FT_ItemVarDelta returnValue = 0;
+ FT_UInt per_region_size;
+ FT_Byte* bytes;
- if ( !face->blend || !face->blend->normalizedcoords )
+ if ( !ttface->blend || !ttface->blend->normalizedcoords )
return 0;
/* OpenType 1.8.4+: No variation data for this item */
@@ -1023,15 +1019,48 @@
if ( outerIndex >= itemStore->dataCount )
return 0; /* Out of range. */
- varData = &itemStore->varData[outerIndex];
- deltaSet = FT_OFFSET( varData->deltaSet,
- varData->regionIdxCount * innerIndex );
+ varData = &itemStore->varData[outerIndex];
if ( innerIndex >= varData->itemCount )
return 0; /* Out of range. */
- if ( FT_QNEW_ARRAY( scalars, varData->regionIdxCount ) )
- return 0;
+ if ( varData->regionIdxCount < 16 )
+ {
+ deltaSet = deltaSetStack;
+ scalars = scalarsStack;
+ }
+ else
+ {
+ if ( FT_QNEW_ARRAY( deltaSet, varData->regionIdxCount ) )
+ goto Exit;
+ if ( FT_QNEW_ARRAY( scalars, varData->regionIdxCount ) )
+ goto Exit;
+ }
+
+ /* Parse delta set. */
+ /* */
+ /* Deltas are (word_delta_count + region_idx_count) bytes each */
+ /* if `longWords` isn't set, and twice as much otherwise. */
+ per_region_size = varData->wordDeltaCount + varData->regionIdxCount;
+ if ( varData->longWords )
+ per_region_size *= 2;
+
+ bytes = varData->deltaSet + per_region_size * innerIndex;
+
+ if ( varData->longWords )
+ {
+ for ( master = 0; master < varData->wordDeltaCount; master++ )
+ deltaSet[master] = FT_NEXT_LONG( bytes );
+ for ( ; master < varData->regionIdxCount; master++ )
+ deltaSet[master] = FT_NEXT_SHORT( bytes );
+ }
+ else
+ {
+ for ( master = 0; master < varData->wordDeltaCount; master++ )
+ deltaSet[master] = FT_NEXT_SHORT( bytes );
+ for ( ; master < varData->regionIdxCount; master++ )
+ deltaSet[master] = FT_NEXT_CHAR( bytes );
+ }
/* outer loop steps through master designs to be blended */
for ( master = 0; master < varData->regionIdxCount; master++ )
@@ -1060,27 +1089,27 @@
else if ( axis->peakCoord == 0 )
continue;
- else if ( face->blend->normalizedcoords[j] == axis->peakCoord )
+ else if ( ttface->blend->normalizedcoords[j] == axis->peakCoord )
continue;
/* ignore this region if coords are out of range */
- else if ( face->blend->normalizedcoords[j] <= axis->startCoord ||
- face->blend->normalizedcoords[j] >= axis->endCoord )
+ else if ( ttface->blend->normalizedcoords[j] <= axis->startCoord ||
+ ttface->blend->normalizedcoords[j] >= axis->endCoord )
{
scalar = 0;
break;
}
/* cumulative product of all the axis scalars */
- else if ( face->blend->normalizedcoords[j] < axis->peakCoord )
+ else if ( ttface->blend->normalizedcoords[j] < axis->peakCoord )
scalar =
FT_MulDiv( scalar,
- face->blend->normalizedcoords[j] - axis->startCoord,
+ ttface->blend->normalizedcoords[j] - axis->startCoord,
axis->peakCoord - axis->startCoord );
else
scalar =
FT_MulDiv( scalar,
- axis->endCoord - face->blend->normalizedcoords[j],
+ axis->endCoord - ttface->blend->normalizedcoords[j],
axis->endCoord - axis->peakCoord );
} /* per-axis loop */
@@ -1106,7 +1135,11 @@
*/
returnValue = FT_MulAddFix( scalars, deltaSet, varData->regionIdxCount );
- FT_FREE( scalars );
+ Exit:
+ if ( scalars != scalarsStack )
+ FT_FREE( scalars );
+ if ( deltaSet != deltaSetStack )
+ FT_FREE( deltaSet );
return returnValue;
}
@@ -1206,7 +1239,7 @@
innerIndex = gindex;
}
- delta = tt_var_get_item_delta( face,
+ delta = tt_var_get_item_delta( FT_FACE( face ),
&table->itemStore,
outerIndex,
innerIndex );
@@ -1229,20 +1262,20 @@
FT_LOCAL_DEF( FT_Error )
- tt_hadvance_adjust( TT_Face face,
+ tt_hadvance_adjust( FT_Face face, /* TT_Face */
FT_UInt gindex,
FT_Int *avalue )
{
- return tt_hvadvance_adjust( face, gindex, avalue, 0 );
+ return tt_hvadvance_adjust( (TT_Face)face, gindex, avalue, 0 );
}
FT_LOCAL_DEF( FT_Error )
- tt_vadvance_adjust( TT_Face face,
+ tt_vadvance_adjust( FT_Face face, /* TT_Face */
FT_UInt gindex,
FT_Int *avalue )
{
- return tt_hvadvance_adjust( face, gindex, avalue, 1 );
+ return tt_hvadvance_adjust( (TT_Face)face, gindex, avalue, 1 );
}
@@ -1389,7 +1422,7 @@
records_offset = FT_STREAM_POS();
error = tt_var_load_item_variation_store(
- face,
+ FT_FACE( face ),
table_offset + store_offset,
&blend->mvar_table->itemStore );
if ( error )
@@ -1462,15 +1495,14 @@
static FT_Error
- tt_size_reset_iterator( FT_ListNode node,
+ ft_size_reset_iterator( FT_ListNode node,
void* user )
{
- TT_Size size = (TT_Size)node->data;
-
- FT_UNUSED( user );
+ FT_Size size = (FT_Size)node->data;
+ FT_Service_MetricsVariations var = (FT_Service_MetricsVariations)user;
- tt_size_reset( size, 1 );
+ var->size_reset( size );
return FT_Err_Ok;
}
@@ -1489,16 +1521,19 @@
* The font face.
*/
FT_LOCAL_DEF( void )
- tt_apply_mvar( TT_Face face )
+ tt_apply_mvar( FT_Face face ) /* TT_Face */
{
- GX_Blend blend = face->blend;
+ TT_Face ttface = (TT_Face)face;
+
+ GX_Blend blend = ttface->blend;
GX_Value value, limit;
+
FT_Short mvar_hasc_delta = 0;
FT_Short mvar_hdsc_delta = 0;
FT_Short mvar_hlgp_delta = 0;
- if ( !( face->variation_support & TT_FACE_FLAG_VAR_MVAR ) )
+ if ( !( ttface->variation_support & TT_FACE_FLAG_VAR_MVAR ) )
return;
value = blend->mvar_table->values;
@@ -1506,7 +1541,7 @@
for ( ; value < limit; value++ )
{
- FT_Short* p = ft_var_get_value_pointer( face, value->tag );
+ FT_Short* p = ft_var_get_value_pointer( ttface, value->tag );
FT_Int delta;
@@ -1543,7 +1578,8 @@
/* adjust all derived values */
{
- FT_Face root = &face->root;
+ FT_Service_MetricsVariations var =
+ (FT_Service_MetricsVariations)ttface->face_var;
/*
* Apply the deltas of hasc, hdsc and hlgp to the FT_Face's ascender,
@@ -1571,24 +1607,25 @@
* whether they were actually changed or the font had the OS/2 table's
* fsSelection's bit 7 (USE_TYPO_METRICS) set.
*/
- FT_Short current_line_gap = root->height - root->ascender +
- root->descender;
+ FT_Short current_line_gap = face->height - face->ascender +
+ face->descender;
- root->ascender = root->ascender + mvar_hasc_delta;
- root->descender = root->descender + mvar_hdsc_delta;
- root->height = root->ascender - root->descender +
+ face->ascender = face->ascender + mvar_hasc_delta;
+ face->descender = face->descender + mvar_hdsc_delta;
+ face->height = face->ascender - face->descender +
current_line_gap + mvar_hlgp_delta;
- root->underline_position = face->postscript.underlinePosition -
- face->postscript.underlineThickness / 2;
- root->underline_thickness = face->postscript.underlineThickness;
+ face->underline_position = ttface->postscript.underlinePosition -
+ ttface->postscript.underlineThickness / 2;
+ face->underline_thickness = ttface->postscript.underlineThickness;
- /* iterate over all FT_Size objects and call `tt_size_reset' */
- /* to propagate the metrics changes */
- FT_List_Iterate( &root->sizes_list,
- tt_size_reset_iterator,
- NULL );
+ /* iterate over all FT_Size objects and call `var->size_reset' */
+ /* to propagate the metrics changes */
+ if ( var && var->size_reset )
+ FT_List_Iterate( &face->sizes_list,
+ ft_size_reset_iterator,
+ (void*)var );
}
}
@@ -2099,7 +2136,7 @@
innerIndex = table->axisMap.innerIndex[idx];
}
- delta = tt_var_get_item_delta( face,
+ delta = tt_var_get_item_delta( FT_FACE( face ),
&table->itemStore,
outerIndex,
innerIndex );
@@ -2261,11 +2298,12 @@
* FreeType error code. 0 means success.
*/
FT_LOCAL_DEF( FT_Error )
- TT_Get_MM_Var( TT_Face face,
+ TT_Get_MM_Var( FT_Face face, /* TT_Face */
FT_MM_Var* *master )
{
- FT_Stream stream = face->root.stream;
- FT_Memory memory = face->root.memory;
+ TT_Face ttface = (TT_Face)face;
+ FT_Stream stream = FT_FACE_STREAM( face );
+ FT_Memory memory = FT_FACE_MEMORY( face );
FT_ULong table_len;
FT_Error error = FT_Err_Ok;
FT_ULong fvar_start = 0;
@@ -2329,19 +2367,19 @@
/* the default instance, which might be missing in the table of named */
/* instances (in 'fvar'). This value is validated in `sfobjs.c` and */
/* may be reset to 0 if consistency checks fail. */
- num_instances = (FT_UInt)face->root.style_flags >> 16;
+ num_instances = (FT_UInt)face->style_flags >> 16;
/* read the font data and set up the internal representation */
/* if not already done */
- need_init = !face->blend;
+ need_init = !ttface->blend;
if ( need_init )
{
FT_TRACE2(( "FVAR " ));
- if ( FT_SET_ERROR( face->goto_table( face, TTAG_fvar,
- stream, &table_len ) ) )
+ if ( FT_SET_ERROR( ttface->goto_table( ttface, TTAG_fvar,
+ stream, &table_len ) ) )
{
FT_TRACE1(( "is missing\n" ));
goto Exit;
@@ -2374,14 +2412,14 @@
fvar_head.axisCount,
fvar_head.axisCount == 1 ? "is" : "es" ));
- if ( FT_NEW( face->blend ) )
+ if ( FT_NEW( ttface->blend ) )
goto Exit;
- num_axes = fvar_head.axisCount;
- face->blend->num_axis = num_axes;
+ num_axes = fvar_head.axisCount;
+ ttface->blend->num_axis = num_axes;
}
else
- num_axes = face->blend->num_axis;
+ num_axes = ttface->blend->num_axis;
/* prepare storage area for MM data; this cannot overflow */
/* 32-bit arithmetic because of the size limits used in the */
@@ -2410,16 +2448,16 @@
if ( need_init )
{
- face->blend->mmvar_len = mmvar_size +
- axis_flags_size +
- axis_size +
- namedstyle_size +
- next_coords_size +
- next_name_size;
-
- if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
+ ttface->blend->mmvar_len = mmvar_size +
+ axis_flags_size +
+ axis_size +
+ namedstyle_size +
+ next_coords_size +
+ next_name_size;
+
+ if ( FT_ALLOC( mmvar, ttface->blend->mmvar_len ) )
goto Exit;
- face->blend->mmvar = mmvar;
+ ttface->blend->mmvar = mmvar;
/* set up pointers and offsets into the `mmvar' array; */
/* the data gets filled in later on */
@@ -2525,27 +2563,27 @@
/* named instance coordinates are stored as design coordinates; */
/* we have to convert them to normalized coordinates also */
- if ( FT_NEW_ARRAY( face->blend->normalized_stylecoords,
+ if ( FT_NEW_ARRAY( ttface->blend->normalized_stylecoords,
num_axes * num_instances ) )
goto Exit;
- if ( fvar_head.instanceCount && !face->blend->avar_loaded )
+ if ( fvar_head.instanceCount && !ttface->blend->avar_loaded )
{
FT_ULong offset = FT_STREAM_POS();
- ft_var_load_avar( face );
+ ft_var_load_avar( ttface );
if ( FT_STREAM_SEEK( offset ) )
goto Exit;
}
- FT_TRACE5(( "%d instance%s\n",
+ FT_TRACE5(( "%d named instance%s\n",
fvar_head.instanceCount,
fvar_head.instanceCount == 1 ? "" : "s" ));
ns = mmvar->namedstyle;
- nsc = face->blend->normalized_stylecoords;
+ nsc = ttface->blend->normalized_stylecoords;
for ( i = 0; i < fvar_head.instanceCount; i++, ns++ )
{
/* PostScript names add 2 bytes to the instance record size */
@@ -2568,7 +2606,7 @@
#ifdef FT_DEBUG_LEVEL_TRACE
{
- SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+ SFNT_Service sfnt = (SFNT_Service)ttface->sfnt;
FT_String* strname = NULL;
FT_String* psname = NULL;
@@ -2580,7 +2618,7 @@
if ( ns->strid != 0xFFFF )
{
- (void)sfnt->get_name( face,
+ (void)sfnt->get_name( ttface,
(FT_UShort)ns->strid,
&strname );
if ( strname && !ft_strcmp( strname, ".notdef" ) )
@@ -2589,7 +2627,7 @@
if ( ns->psid != 0xFFFF )
{
- (void)sfnt->get_name( face,
+ (void)sfnt->get_name( ttface,
(FT_UShort)ns->psid,
&psname );
if ( psname && !ft_strcmp( psname, ".notdef" ) )
@@ -2598,7 +2636,7 @@
(void)FT_STREAM_SEEK( pos );
- FT_TRACE5(( " instance %d (%s%s%s, %s%s%s)\n",
+ FT_TRACE5(( " named instance %d (%s%s%s, %s%s%s)\n",
i,
strname ? "name: `" : "",
strname ? strname : "unnamed",
@@ -2612,7 +2650,7 @@
}
#endif /* FT_DEBUG_LEVEL_TRACE */
- ft_var_to_normalized( face, num_axes, ns->coords, nsc );
+ ft_var_to_normalized( ttface, num_axes, ns->coords, nsc );
nsc += num_axes;
FT_FRAME_EXIT();
@@ -2620,15 +2658,17 @@
if ( num_instances != fvar_head.instanceCount )
{
- SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+ SFNT_Service sfnt = (SFNT_Service)ttface->sfnt;
FT_Int found, dummy1, dummy2;
FT_UInt strid = ~0U;
- /* the default instance is missing in array the */
- /* of named instances; try to synthesize an entry */
- found = sfnt->get_name_id( face,
+ /* The default instance is missing in array the */
+ /* of named instances; try to synthesize an entry. */
+ /* If this fails, `default_named_instance` remains */
+ /* at value zero, which doesn't do any harm. */
+ found = sfnt->get_name_id( ttface,
TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY,
&dummy1,
&dummy2 );
@@ -2636,7 +2676,7 @@
strid = TT_NAME_ID_TYPOGRAPHIC_SUBFAMILY;
else
{
- found = sfnt->get_name_id( face,
+ found = sfnt->get_name_id( ttface,
TT_NAME_ID_FONT_SUBFAMILY,
&dummy1,
&dummy2 );
@@ -2646,7 +2686,7 @@
if ( found )
{
- found = sfnt->get_name_id( face,
+ found = sfnt->get_name_id( ttface,
TT_NAME_ID_PS_NAME,
&dummy1,
&dummy2 );
@@ -2655,6 +2695,9 @@
FT_TRACE5(( "TT_Get_MM_Var:"
" Adding default instance to named instances\n" ));
+ /* named instance indices start with value 1 */
+ ttface->var_default_named_instance = num_instances;
+
ns = &mmvar->namedstyle[fvar_head.instanceCount];
ns->strid = strid;
@@ -2668,7 +2711,7 @@
}
}
- ft_var_load_mvar( face );
+ ft_var_load_mvar( ttface );
}
/* fill the output array if requested */
@@ -2678,9 +2721,9 @@
FT_UInt n;
- if ( FT_ALLOC( mmvar, face->blend->mmvar_len ) )
+ if ( FT_ALLOC( mmvar, ttface->blend->mmvar_len ) )
goto Exit;
- FT_MEM_COPY( mmvar, face->blend->mmvar, face->blend->mmvar_len );
+ FT_MEM_COPY( mmvar, ttface->blend->mmvar, ttface->blend->mmvar_len );
axis_flags =
(FT_UShort*)( (char*)mmvar + mmvar_size );
@@ -2756,7 +2799,7 @@
if ( !face->blend )
{
- if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
+ if ( FT_SET_ERROR( TT_Get_MM_Var( FT_FACE( face ), NULL ) ) )
goto Exit;
}
@@ -2841,26 +2884,29 @@
}
}
- if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) )
+ if ( !have_diff )
{
- FT_UInt instance_index = (FT_UInt)face->root.face_index >> 16;
+ if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) )
+ {
+ FT_UInt instance_index = (FT_UInt)face->root.face_index >> 16;
- c = blend->normalizedcoords + i;
- n = blend->normalized_stylecoords +
- ( instance_index - 1 ) * mmvar->num_axis +
- i;
+ c = blend->normalizedcoords + i;
+ n = blend->normalized_stylecoords +
+ ( instance_index - 1 ) * mmvar->num_axis +
+ i;
- for ( j = i; j < mmvar->num_axis; j++, n++, c++ )
- if ( *c != *n )
- have_diff = 1;
- }
- else
- {
- c = blend->normalizedcoords + i;
- for ( j = i; j < mmvar->num_axis; j++, c++ )
- if ( *c != 0 )
- have_diff = 1;
+ for ( j = i; j < mmvar->num_axis; j++, n++, c++ )
+ if ( *c != *n )
+ have_diff = 1;
+ }
+ else
+ {
+ c = blend->normalizedcoords + i;
+ for ( j = i; j < mmvar->num_axis; j++, c++ )
+ if ( *c != 0 )
+ have_diff = 1;
+ }
}
/* return value -1 indicates `no change' */
@@ -2924,9 +2970,6 @@
}
}
- /* enforce recomputation of the PostScript name; */
- FT_FREE( face->postscript_name );
-
Exit:
return error;
}
@@ -2958,26 +3001,15 @@
* An array of `num_coords', each between [-1,1].
*
* @Return:
- * FreeType error code. 0 means success.
+ * FreeType error code. 0 means success, -1 means success and unchanged
+ * axis values.
*/
FT_LOCAL_DEF( FT_Error )
- TT_Set_MM_Blend( TT_Face face,
+ TT_Set_MM_Blend( FT_Face face, /* TT_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
- FT_Error error;
-
-
- error = tt_set_mm_blend( face, num_coords, coords, 1 );
- if ( error )
- return error;
-
- if ( num_coords )
- face->root.face_flags |= FT_FACE_FLAG_VARIATION;
- else
- face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
-
- return FT_Err_Ok;
+ return tt_set_mm_blend( (TT_Face)face, num_coords, coords, 1 );
}
@@ -3005,31 +3037,34 @@
* An array of `num_coords', each between [-1,1].
*
* @Return:
- * FreeType error code. 0 means success.
+ * FreeType error code. 0 means success, -1 means success and unchanged
+ * axis values.
*/
FT_LOCAL_DEF( FT_Error )
- TT_Get_MM_Blend( TT_Face face,
+ TT_Get_MM_Blend( FT_Face face, /* TT_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
+ TT_Face ttface = (TT_Face)face;
+
FT_Error error = FT_Err_Ok;
GX_Blend blend;
FT_UInt i, nc;
- if ( !face->blend )
+ if ( !ttface->blend )
{
if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
return error;
}
- blend = face->blend;
+ blend = ttface->blend;
if ( !blend->coords )
{
/* select default instance coordinates */
/* if no instance is selected yet */
- if ( FT_SET_ERROR( tt_set_mm_blend( face, 0, NULL, 1 ) ) )
+ if ( FT_SET_ERROR( tt_set_mm_blend( ttface, 0, NULL, 1 ) ) )
return error;
}
@@ -3042,7 +3077,7 @@
nc = blend->num_axis;
}
- if ( face->doblend )
+ if ( ttface->doblend )
{
for ( i = 0; i < nc; i++ )
coords[i] = blend->normalizedcoords[i];
@@ -3089,15 +3124,16 @@
* FreeType error code. 0 means success.
*/
FT_LOCAL_DEF( FT_Error )
- TT_Set_Var_Design( TT_Face face,
+ TT_Set_Var_Design( FT_Face face, /* TT_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
+ TT_Face ttface = (TT_Face)face;
FT_Error error = FT_Err_Ok;
GX_Blend blend;
FT_MM_Var* mmvar;
FT_UInt i;
- FT_Memory memory = face->root.memory;
+ FT_Memory memory = FT_FACE_MEMORY( face );
FT_Fixed* c;
FT_Fixed* n;
@@ -3106,13 +3142,13 @@
FT_Bool have_diff = 0;
- if ( !face->blend )
+ if ( !ttface->blend )
{
if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
goto Exit;
}
- blend = face->blend;
+ blend = ttface->blend;
mmvar = blend->mmvar;
if ( num_coords > mmvar->num_axis )
@@ -3140,13 +3176,13 @@
}
}
- if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) )
+ if ( FT_IS_NAMED_INSTANCE( face ) )
{
FT_UInt instance_index;
FT_Var_Named_Style* named_style;
- instance_index = (FT_UInt)face->root.face_index >> 16;
+ instance_index = (FT_UInt)face->face_index >> 16;
named_style = mmvar->namedstyle + instance_index - 1;
n = named_style->coords + num_coords;
@@ -3183,22 +3219,17 @@
if ( FT_NEW_ARRAY( normalized, mmvar->num_axis ) )
goto Exit;
- if ( !face->blend->avar_loaded )
- ft_var_load_avar( face );
+ if ( !ttface->blend->avar_loaded )
+ ft_var_load_avar( ttface );
FT_TRACE5(( "TT_Set_Var_Design:\n" ));
FT_TRACE5(( " normalized design coordinates:\n" ));
- ft_var_to_normalized( face, num_coords, blend->coords, normalized );
+ ft_var_to_normalized( ttface, num_coords, blend->coords, normalized );
- error = tt_set_mm_blend( face, mmvar->num_axis, normalized, 0 );
+ error = tt_set_mm_blend( ttface, mmvar->num_axis, normalized, 0 );
if ( error )
goto Exit;
- if ( num_coords )
- face->root.face_flags |= FT_FACE_FLAG_VARIATION;
- else
- face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
-
Exit:
FT_FREE( normalized );
return error;
@@ -3231,28 +3262,29 @@
* FreeType error code. 0~means success.
*/
FT_LOCAL_DEF( FT_Error )
- TT_Get_Var_Design( TT_Face face,
+ TT_Get_Var_Design( FT_Face face, /* TT_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
- FT_Error error = FT_Err_Ok;
+ TT_Face ttface = (TT_Face)face;
+ FT_Error error = FT_Err_Ok;
GX_Blend blend;
FT_UInt i, nc;
- if ( !face->blend )
+ if ( !ttface->blend )
{
if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
return error;
}
- blend = face->blend;
+ blend = ttface->blend;
if ( !blend->coords )
{
/* select default instance coordinates */
/* if no instance is selected yet */
- if ( FT_SET_ERROR( tt_set_mm_blend( face, 0, NULL, 1 ) ) )
+ if ( FT_SET_ERROR( tt_set_mm_blend( ttface, 0, NULL, 1 ) ) )
return error;
}
@@ -3265,7 +3297,7 @@
nc = blend->num_axis;
}
- if ( face->doblend )
+ if ( ttface->doblend )
{
for ( i = 0; i < nc; i++ )
coords[i] = blend->coords[i];
@@ -3301,29 +3333,33 @@
* Value 0 indicates to not use an instance.
*
* @Return:
- * FreeType error code. 0~means success.
+ * FreeType error code. 0~means success, -1 means success and unchanged
+ * axis values.
*/
FT_LOCAL_DEF( FT_Error )
- TT_Set_Named_Instance( TT_Face face,
+ TT_Set_Named_Instance( FT_Face face, /* TT_Face */
FT_UInt instance_index )
{
+ TT_Face ttface = (TT_Face)face;
FT_Error error;
GX_Blend blend;
FT_MM_Var* mmvar;
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
FT_UInt num_instances;
- if ( !face->blend )
+ if ( !ttface->blend )
{
if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
goto Exit;
}
- blend = face->blend;
+ blend = ttface->blend;
mmvar = blend->mmvar;
- num_instances = (FT_UInt)face->root.style_flags >> 16;
+ num_instances = (FT_UInt)face->style_flags >> 16;
/* `instance_index' starts with value 1, thus `>' */
if ( instance_index > num_instances )
@@ -3334,8 +3370,7 @@
if ( instance_index > 0 )
{
- FT_Memory memory = face->root.memory;
- SFNT_Service sfnt = (SFNT_Service)face->sfnt;
+ SFNT_Service sfnt = (SFNT_Service)ttface->sfnt;
FT_Var_Named_Style* named_style;
FT_String* style_name;
@@ -3343,40 +3378,89 @@
named_style = mmvar->namedstyle + instance_index - 1;
- error = sfnt->get_name( face,
+ error = sfnt->get_name( ttface,
(FT_UShort)named_style->strid,
&style_name );
if ( error )
goto Exit;
/* set (or replace) style name */
- FT_FREE( face->root.style_name );
- face->root.style_name = style_name;
+ FT_FREE( face->style_name );
+ face->style_name = style_name;
/* finally, select the named instance */
error = TT_Set_Var_Design( face,
mmvar->num_axis,
named_style->coords );
- if ( error )
- {
- /* internal error code -1 means `no change' */
- if ( error == -1 )
- error = FT_Err_Ok;
- goto Exit;
- }
}
else
+ {
+ /* restore non-VF style name */
+ FT_FREE( face->style_name );
+ if ( FT_STRDUP( face->style_name, ttface->non_var_style_name ) )
+ goto Exit;
error = TT_Set_Var_Design( face, 0, NULL );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /**************************************************************************
+ *
+ * @Function:
+ * TT_Get_Default_Named_Instance
+ *
+ * @Description:
+ * Get the default named instance.
+ *
+ * @Input:
+ * face ::
+ * A handle to the source face.
+ *
+ * @Output:
+ * instance_index ::
+ * The default named instance index.
+ *
+ * @Return:
+ * FreeType error code. 0~means success.
+ */
+ FT_LOCAL_DEF( FT_Error )
+ TT_Get_Default_Named_Instance( FT_Face face,
+ FT_UInt *instance_index )
+ {
+ TT_Face ttface = (TT_Face)face;
+ FT_Error error = FT_Err_Ok;
- face->root.face_index = ( instance_index << 16 ) |
- ( face->root.face_index & 0xFFFFL );
- face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
+
+ if ( !ttface->blend )
+ {
+ if ( FT_SET_ERROR( TT_Get_MM_Var( face, NULL ) ) )
+ goto Exit;
+ }
+
+ *instance_index = ttface->var_default_named_instance;
Exit:
return error;
}
+ /* This function triggers (lazy) recomputation of the `postscript_name` */
+ /* field in `TT_Face`. */
+
+ FT_LOCAL_DEF( void )
+ tt_construct_ps_name( FT_Face face )
+ {
+ TT_Face ttface = (TT_Face)face;
+ FT_Memory memory = FT_FACE_MEMORY( face );
+
+
+ FT_FREE( ttface->postscript_name );
+ }
+
+
/*************************************************************************/
/*************************************************************************/
/***** *****/
@@ -4409,22 +4493,25 @@
* the MM machinery in case it isn't loaded yet.
*/
FT_LOCAL_DEF( FT_Error )
- tt_get_var_blend( TT_Face face,
+ tt_get_var_blend( FT_Face face, /* TT_Face */
FT_UInt *num_coords,
FT_Fixed* *coords,
FT_Fixed* *normalizedcoords,
FT_MM_Var* *mm_var )
{
- if ( face->blend )
+ TT_Face ttface = (TT_Face)face;
+
+
+ if ( ttface->blend )
{
if ( num_coords )
- *num_coords = face->blend->num_axis;
+ *num_coords = ttface->blend->num_axis;
if ( coords )
- *coords = face->blend->coords;
+ *coords = ttface->blend->coords;
if ( normalizedcoords )
- *normalizedcoords = face->blend->normalizedcoords;
+ *normalizedcoords = ttface->blend->normalizedcoords;
if ( mm_var )
- *mm_var = face->blend->mmvar;
+ *mm_var = ttface->blend->mmvar;
}
else
{
@@ -4441,7 +4528,7 @@
FT_LOCAL_DEF( void )
- tt_var_done_item_variation_store( TT_Face face,
+ tt_var_done_item_variation_store( FT_Face face,
GX_ItemVarStore itemStore )
{
FT_Memory memory = FT_FACE_MEMORY( face );
@@ -4470,7 +4557,7 @@
FT_LOCAL_DEF( void )
- tt_var_done_delta_set_index_map( TT_Face face,
+ tt_var_done_delta_set_index_map( FT_Face face,
GX_DeltaSetIdxMap deltaSetIdxMap )
{
FT_Memory memory = FT_FACE_MEMORY( face );
@@ -4490,10 +4577,11 @@
* Free the blend internal data structure.
*/
FT_LOCAL_DEF( void )
- tt_done_blend( TT_Face face )
+ tt_done_blend( FT_Face face )
{
+ TT_Face ttface = (TT_Face)face;
FT_Memory memory = FT_FACE_MEMORY( face );
- GX_Blend blend = face->blend;
+ GX_Blend blend = ttface->blend;
if ( blend )
@@ -4565,7 +4653,7 @@
#else /* !TT_CONFIG_OPTION_GX_VAR_SUPPORT */
/* ANSI C doesn't like empty source files */
- typedef int _tt_gxvar_dummy;
+ typedef int tt_gxvar_dummy_;
#endif /* !TT_CONFIG_OPTION_GX_VAR_SUPPORT */
diff --git a/src/3rdparty/freetype/src/truetype/ttgxvar.h b/src/3rdparty/freetype/src/truetype/ttgxvar.h
index 4fec980dcc..e3da6d1705 100644
--- a/src/3rdparty/freetype/src/truetype/ttgxvar.h
+++ b/src/3rdparty/freetype/src/truetype/ttgxvar.h
@@ -347,34 +347,41 @@ FT_BEGIN_HEADER
FT_LOCAL( FT_Error )
- TT_Set_MM_Blend( TT_Face face,
+ TT_Set_MM_Blend( FT_Face face,
FT_UInt num_coords,
FT_Fixed* coords );
FT_LOCAL( FT_Error )
- TT_Get_MM_Blend( TT_Face face,
+ TT_Get_MM_Blend( FT_Face face,
FT_UInt num_coords,
FT_Fixed* coords );
FT_LOCAL( FT_Error )
- TT_Set_Var_Design( TT_Face face,
+ TT_Set_Var_Design( FT_Face face,
FT_UInt num_coords,
FT_Fixed* coords );
FT_LOCAL( FT_Error )
- TT_Get_MM_Var( TT_Face face,
+ TT_Get_MM_Var( FT_Face face,
FT_MM_Var* *master );
FT_LOCAL( FT_Error )
- TT_Get_Var_Design( TT_Face face,
+ TT_Get_Var_Design( FT_Face face,
FT_UInt num_coords,
FT_Fixed* coords );
FT_LOCAL( FT_Error )
- TT_Set_Named_Instance( TT_Face face,
+ TT_Set_Named_Instance( FT_Face face,
FT_UInt instance_index );
FT_LOCAL( FT_Error )
+ TT_Get_Default_Named_Instance( FT_Face face,
+ FT_UInt *instance_index );
+
+ FT_LOCAL( void )
+ tt_construct_ps_name( FT_Face face );
+
+ FT_LOCAL( FT_Error )
tt_face_vary_cvt( TT_Face face,
FT_Stream stream );
@@ -385,55 +392,54 @@ FT_BEGIN_HEADER
FT_Vector* unrounded );
FT_LOCAL( FT_Error )
- tt_hadvance_adjust( TT_Face face,
+ tt_hadvance_adjust( FT_Face face,
FT_UInt gindex,
FT_Int *adelta );
FT_LOCAL( FT_Error )
- tt_vadvance_adjust( TT_Face face,
+ tt_vadvance_adjust( FT_Face face,
FT_UInt gindex,
FT_Int *adelta );
FT_LOCAL( void )
- tt_apply_mvar( TT_Face face );
-
+ tt_apply_mvar( FT_Face face );
FT_LOCAL( FT_Error )
- tt_var_load_item_variation_store( TT_Face face,
+ tt_var_load_item_variation_store( FT_Face face,
FT_ULong offset,
GX_ItemVarStore itemStore );
FT_LOCAL( FT_Error )
- tt_var_load_delta_set_index_mapping( TT_Face face,
+ tt_var_load_delta_set_index_mapping( FT_Face face,
FT_ULong offset,
GX_DeltaSetIdxMap map,
GX_ItemVarStore itemStore,
FT_ULong table_len );
FT_LOCAL( FT_ItemVarDelta )
- tt_var_get_item_delta( TT_Face face,
+ tt_var_get_item_delta( FT_Face face,
GX_ItemVarStore itemStore,
FT_UInt outerIndex,
FT_UInt innerIndex );
FT_LOCAL( void )
- tt_var_done_item_variation_store( TT_Face face,
+ tt_var_done_item_variation_store( FT_Face face,
GX_ItemVarStore itemStore );
FT_LOCAL( void )
- tt_var_done_delta_set_index_map( TT_Face face,
+ tt_var_done_delta_set_index_map( FT_Face face,
GX_DeltaSetIdxMap deltaSetIdxMap );
FT_LOCAL( FT_Error )
- tt_get_var_blend( TT_Face face,
+ tt_get_var_blend( FT_Face face,
FT_UInt *num_coords,
FT_Fixed* *coords,
FT_Fixed* *normalizedcoords,
FT_MM_Var* *mm_var );
FT_LOCAL( void )
- tt_done_blend( TT_Face face );
+ tt_done_blend( FT_Face face );
#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
diff --git a/src/3rdparty/freetype/src/truetype/ttinterp.c b/src/3rdparty/freetype/src/truetype/ttinterp.c
index 4fcfaa3e43..79df4555d9 100644
--- a/src/3rdparty/freetype/src/truetype/ttinterp.c
+++ b/src/3rdparty/freetype/src/truetype/ttinterp.c
@@ -29,7 +29,6 @@
#include "ttinterp.h"
#include "tterrors.h"
-#include "ttsubpix.h"
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
#include "ttgxvar.h"
#endif
@@ -52,12 +51,6 @@
( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \
TT_INTERPRETER_VERSION_35 )
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-#define SUBPIXEL_HINTING_INFINALITY \
- ( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \
- TT_INTERPRETER_VERSION_38 )
-#endif
-
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
#define SUBPIXEL_HINTING_MINIMAL \
( ((TT_Driver)FT_FACE_DRIVER( exc->face ))->interpreter_version == \
@@ -278,57 +271,6 @@
/**************************************************************************
*
* @Function:
- * Update_Max
- *
- * @Description:
- * Checks the size of a buffer and reallocates it if necessary.
- *
- * @Input:
- * memory ::
- * A handle to the parent memory object.
- *
- * multiplier ::
- * The size in bytes of each element in the buffer.
- *
- * new_max ::
- * The new capacity (size) of the buffer.
- *
- * @InOut:
- * size ::
- * The address of the buffer's current size expressed
- * in elements.
- *
- * buff ::
- * The address of the buffer base pointer.
- *
- * @Return:
- * FreeType error code. 0 means success.
- */
- FT_LOCAL_DEF( FT_Error )
- Update_Max( FT_Memory memory,
- FT_ULong* size,
- FT_ULong multiplier,
- void* _pbuff,
- FT_ULong new_max )
- {
- FT_Error error;
- void** pbuff = (void**)_pbuff;
-
-
- if ( *size < new_max )
- {
- if ( FT_QREALLOC( *pbuff, *size * multiplier, new_max * multiplier ) )
- return error;
- *size = new_max;
- }
-
- return FT_Err_Ok;
- }
-
-
- /**************************************************************************
- *
- * @Function:
* TT_Load_Context
*
* @Description:
@@ -359,9 +301,9 @@
TT_Size size )
{
FT_Int i;
- FT_ULong tmp;
TT_MaxProfile* maxp;
FT_Error error;
+ FT_Memory memory = exec->memory;
exec->face = face;
@@ -406,25 +348,15 @@
/* XXX: We reserve a little more elements on the stack to deal safely */
/* with broken fonts like arialbs, courbs, timesbs, etc. */
- tmp = (FT_ULong)exec->stackSize;
- error = Update_Max( exec->memory,
- &tmp,
- sizeof ( FT_F26Dot6 ),
- (void*)&exec->stack,
- maxp->maxStackElements + 32 );
- exec->stackSize = (FT_Long)tmp;
- if ( error )
+ if ( FT_QRENEW_ARRAY( exec->stack,
+ exec->stackSize,
+ maxp->maxStackElements + 32 ) )
return error;
+ exec->stackSize = maxp->maxStackElements + 32;
- tmp = (FT_ULong)exec->glyphSize;
- error = Update_Max( exec->memory,
- &tmp,
- sizeof ( FT_Byte ),
- (void*)&exec->glyphIns,
- maxp->maxSizeOfInstructions );
- exec->glyphSize = (FT_UInt)tmp;
- if ( error )
- return error;
+ /* free previous glyph code range */
+ FT_FREE( exec->glyphIns );
+ exec->glyphSize = 0;
exec->pts.n_points = 0;
exec->pts.n_contours = 0;
@@ -1530,14 +1462,16 @@
if ( exc->iniRange == tt_coderange_glyph &&
exc->cvt != exc->glyfCvt )
{
- exc->error = Update_Max( exc->memory,
- &exc->glyfCvtSize,
- sizeof ( FT_Long ),
- (void*)&exc->glyfCvt,
- exc->cvtSize );
- if ( exc->error )
+ FT_Memory memory = exc->memory;
+ FT_Error error;
+
+
+ FT_MEM_QRENEW_ARRAY( exc->glyfCvt, exc->glyfCvtSize, exc->cvtSize );
+ exc->error = error;
+ if ( error )
return;
+ exc->glyfCvtSize = exc->cvtSize;
FT_ARRAY_COPY( exc->glyfCvt, exc->cvt, exc->glyfCvtSize );
exc->cvt = exc->glyfCvt;
}
@@ -1744,17 +1678,6 @@
if ( v != 0 )
{
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- if ( SUBPIXEL_HINTING_INFINALITY &&
- ( !exc->ignore_x_mode ||
- ( exc->sph_tweak_flags & SPH_TWEAK_ALLOW_X_DMOVE ) ) )
- zone->cur[point].x = ADD_LONG( zone->cur[point].x,
- FT_MulDiv( distance,
- v,
- exc->F_dot_P ) );
- else
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
/* Exception to the post-IUP curfew: Allow the x component of */
/* diagonal moves, but only post-IUP. DejaVu tries to adjust */
@@ -1860,12 +1783,6 @@
FT_UShort point,
FT_F26Dot6 distance )
{
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- if ( SUBPIXEL_HINTING_INFINALITY && !exc->ignore_x_mode )
- zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance );
- else
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
if ( SUBPIXEL_HINTING_MINIMAL && !exc->backward_compatibility )
zone->cur[point].x = ADD_LONG( zone->cur[point].x, distance );
@@ -3069,28 +2986,7 @@
args[0] = 0;
}
else
- {
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- /* subpixel hinting - avoid Typeman Dstroke and */
- /* IStroke and Vacuform rounds */
- if ( SUBPIXEL_HINTING_INFINALITY &&
- exc->ignore_x_mode &&
- ( ( I == 24 &&
- ( exc->face->sph_found_func_flags &
- ( SPH_FDEF_SPACING_1 |
- SPH_FDEF_SPACING_2 ) ) ) ||
- ( I == 22 &&
- ( exc->sph_in_func_flags &
- SPH_FDEF_TYPEMAN_STROKES ) ) ||
- ( I == 8 &&
- ( exc->face->sph_found_func_flags &
- SPH_FDEF_VACUFORM_ROUND_1 ) &&
- exc->iup_called ) ) )
- args[0] = 0;
- else
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
- args[0] = exc->storage[I];
- }
+ args[0] = exc->storage[I];
}
@@ -3117,18 +3013,18 @@
if ( exc->iniRange == tt_coderange_glyph &&
exc->storage != exc->glyfStorage )
{
- FT_ULong tmp = (FT_ULong)exc->glyfStoreSize;
+ FT_Memory memory = exc->memory;
+ FT_Error error;
- exc->error = Update_Max( exc->memory,
- &tmp,
- sizeof ( FT_Long ),
- (void*)&exc->glyfStorage,
- exc->storeSize );
- exc->glyfStoreSize = (FT_UShort)tmp;
- if ( exc->error )
+ FT_MEM_QRENEW_ARRAY( exc->glyfStorage,
+ exc->glyfStoreSize,
+ exc->storeSize );
+ exc->error = error;
+ if ( error )
return;
+ exc->glyfStoreSize = exc->storeSize;
FT_ARRAY_COPY( exc->glyfStorage, exc->storage, exc->glyfStoreSize );
exc->storage = exc->glyfStorage;
}
@@ -3604,106 +3500,6 @@
TT_DefRecord* rec;
TT_DefRecord* limit;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- /* arguments to opcodes are skipped by `SKIP_Code' */
- FT_Byte opcode_pattern[9][12] = {
- /* #0 inline delta function 1 */
- {
- 0x4B, /* PPEM */
- 0x53, /* GTEQ */
- 0x23, /* SWAP */
- 0x4B, /* PPEM */
- 0x51, /* LTEQ */
- 0x5A, /* AND */
- 0x58, /* IF */
- 0x38, /* SHPIX */
- 0x1B, /* ELSE */
- 0x21, /* POP */
- 0x21, /* POP */
- 0x59 /* EIF */
- },
- /* #1 inline delta function 2 */
- {
- 0x4B, /* PPEM */
- 0x54, /* EQ */
- 0x58, /* IF */
- 0x38, /* SHPIX */
- 0x1B, /* ELSE */
- 0x21, /* POP */
- 0x21, /* POP */
- 0x59 /* EIF */
- },
- /* #2 diagonal stroke function */
- {
- 0x20, /* DUP */
- 0x20, /* DUP */
- 0xB0, /* PUSHB_1 */
- /* 1 */
- 0x60, /* ADD */
- 0x46, /* GC_cur */
- 0xB0, /* PUSHB_1 */
- /* 64 */
- 0x23, /* SWAP */
- 0x42 /* WS */
- },
- /* #3 VacuFormRound function */
- {
- 0x45, /* RCVT */
- 0x23, /* SWAP */
- 0x46, /* GC_cur */
- 0x60, /* ADD */
- 0x20, /* DUP */
- 0xB0 /* PUSHB_1 */
- /* 38 */
- },
- /* #4 TTFautohint bytecode (old) */
- {
- 0x20, /* DUP */
- 0x64, /* ABS */
- 0xB0, /* PUSHB_1 */
- /* 32 */
- 0x60, /* ADD */
- 0x66, /* FLOOR */
- 0x23, /* SWAP */
- 0xB0 /* PUSHB_1 */
- },
- /* #5 spacing function 1 */
- {
- 0x01, /* SVTCA_x */
- 0xB0, /* PUSHB_1 */
- /* 24 */
- 0x43, /* RS */
- 0x58 /* IF */
- },
- /* #6 spacing function 2 */
- {
- 0x01, /* SVTCA_x */
- 0x18, /* RTG */
- 0xB0, /* PUSHB_1 */
- /* 24 */
- 0x43, /* RS */
- 0x58 /* IF */
- },
- /* #7 TypeMan Talk DiagEndCtrl function */
- {
- 0x01, /* SVTCA_x */
- 0x20, /* DUP */
- 0xB0, /* PUSHB_1 */
- /* 3 */
- 0x25, /* CINDEX */
- },
- /* #8 TypeMan Talk Align */
- {
- 0x06, /* SPVTL */
- 0x7D, /* RDTG */
- },
- };
- FT_UShort opcode_patterns = 9;
- FT_UShort opcode_pointer[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- FT_UShort opcode_size[9] = { 12, 8, 8, 6, 7, 4, 5, 4, 2 };
- FT_UShort i;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
/* FDEF is only allowed in `prep' or `fpgm' */
if ( exc->iniRange == tt_coderange_glyph )
@@ -3748,136 +3544,15 @@
rec->opc = (FT_UInt16)n;
rec->start = exc->IP + 1;
rec->active = TRUE;
- rec->inline_delta = FALSE;
- rec->sph_fdef_flags = 0x0000;
if ( n > exc->maxFunc )
exc->maxFunc = (FT_UInt16)n;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- /* We don't know for sure these are typeman functions, */
- /* however they are only active when RS 22 is called */
- if ( n >= 64 && n <= 66 )
- rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_STROKES;
-#endif
-
/* Now skip the whole function definition. */
/* We don't allow nested IDEFS & FDEFs. */
while ( SkipCode( exc ) == SUCCESS )
{
-
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-
- if ( SUBPIXEL_HINTING_INFINALITY )
- {
- for ( i = 0; i < opcode_patterns; i++ )
- {
- if ( opcode_pointer[i] < opcode_size[i] &&
- exc->opcode == opcode_pattern[i][opcode_pointer[i]] )
- {
- opcode_pointer[i] += 1;
-
- if ( opcode_pointer[i] == opcode_size[i] )
- {
- FT_TRACE6(( "sph: Function %d, opcode ptrn: %ld, %s %s\n",
- i, n,
- exc->face->root.family_name,
- exc->face->root.style_name ));
-
- switch ( i )
- {
- case 0:
- rec->sph_fdef_flags |= SPH_FDEF_INLINE_DELTA_1;
- exc->face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_1;
- break;
-
- case 1:
- rec->sph_fdef_flags |= SPH_FDEF_INLINE_DELTA_2;
- exc->face->sph_found_func_flags |= SPH_FDEF_INLINE_DELTA_2;
- break;
-
- case 2:
- switch ( n )
- {
- /* needs to be implemented still */
- case 58:
- rec->sph_fdef_flags |= SPH_FDEF_DIAGONAL_STROKE;
- exc->face->sph_found_func_flags |= SPH_FDEF_DIAGONAL_STROKE;
- }
- break;
-
- case 3:
- switch ( n )
- {
- case 0:
- rec->sph_fdef_flags |= SPH_FDEF_VACUFORM_ROUND_1;
- exc->face->sph_found_func_flags |= SPH_FDEF_VACUFORM_ROUND_1;
- }
- break;
-
- case 4:
- /* probably not necessary to detect anymore */
- rec->sph_fdef_flags |= SPH_FDEF_TTFAUTOHINT_1;
- exc->face->sph_found_func_flags |= SPH_FDEF_TTFAUTOHINT_1;
- break;
-
- case 5:
- switch ( n )
- {
- case 0:
- case 1:
- case 2:
- case 4:
- case 7:
- case 8:
- rec->sph_fdef_flags |= SPH_FDEF_SPACING_1;
- exc->face->sph_found_func_flags |= SPH_FDEF_SPACING_1;
- }
- break;
-
- case 6:
- switch ( n )
- {
- case 0:
- case 1:
- case 2:
- case 4:
- case 7:
- case 8:
- rec->sph_fdef_flags |= SPH_FDEF_SPACING_2;
- exc->face->sph_found_func_flags |= SPH_FDEF_SPACING_2;
- }
- break;
-
- case 7:
- rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
- exc->face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
- break;
-
- case 8:
-#if 0
- rec->sph_fdef_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
- exc->face->sph_found_func_flags |= SPH_FDEF_TYPEMAN_DIAGENDCTRL;
-#endif
- break;
- }
- opcode_pointer[i] = 0;
- }
- }
-
- else
- opcode_pointer[i] = 0;
- }
-
- /* Set sph_compatibility_mode only when deltas are detected */
- exc->face->sph_compatibility_mode =
- ( ( exc->face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_1 ) |
- ( exc->face->sph_found_func_flags & SPH_FDEF_INLINE_DELTA_2 ) );
- }
-
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
switch ( exc->opcode )
{
case 0x89: /* IDEF */
@@ -3905,10 +3580,6 @@
TT_CallRec* pRec;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- exc->sph_in_func_flags = 0x0000;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
if ( exc->callTop <= 0 ) /* We encountered an ENDF without a call */
{
exc->error = FT_THROW( ENDF_In_Exec_Stream );
@@ -3996,17 +3667,6 @@
if ( !def->active )
goto Fail;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- if ( SUBPIXEL_HINTING_INFINALITY &&
- exc->ignore_x_mode &&
- ( ( exc->iup_called &&
- ( exc->sph_tweak_flags & SPH_TWEAK_NO_CALL_AFTER_IUP ) ) ||
- ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 ) ) )
- goto Fail;
- else
- exc->sph_in_func_flags = def->sph_fdef_flags;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
/* check the call stack */
if ( exc->callTop >= exc->callSize )
{
@@ -4084,15 +3744,6 @@
if ( !def->active )
goto Fail;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- if ( SUBPIXEL_HINTING_INFINALITY &&
- exc->ignore_x_mode &&
- ( def->sph_fdef_flags & SPH_FDEF_VACUFORM_ROUND_1 ) )
- goto Fail;
- else
- exc->sph_in_func_flags = def->sph_fdef_flags;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
/* check stack */
if ( exc->callTop >= exc->callSize )
{
@@ -4998,14 +4649,6 @@
}
}
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- /* Disable Type 2 Vacuform Rounds - e.g. Arial Narrow */
- if ( SUBPIXEL_HINTING_INFINALITY &&
- exc->ignore_x_mode &&
- ( D < 0 ? NEG_LONG( D ) : D ) == 64 )
- D += 1;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
args[0] = D;
}
@@ -5267,13 +4910,6 @@
/* except to change the subpixel flags temporarily */
else if ( exc->iniRange == tt_coderange_glyph && K == 3 )
{
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- /* INSTCTRL modifying flag 3 also has an effect */
- /* outside of the CVT program */
- if ( SUBPIXEL_HINTING_INFINALITY )
- exc->ignore_x_mode = !FT_BOOL( L == 4 );
-#endif
-
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
/* Native ClearType fonts sign a waiver that turns off all backward */
/* compatibility hacks and lets them program points to the grid like */
@@ -5605,12 +5241,6 @@
}
}
else
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- /* doesn't follow Cleartype spec but produces better result */
- if ( SUBPIXEL_HINTING_INFINALITY && exc->ignore_x_mode )
- Move_Zp2_Point( exc, point, 0, dy, TRUE );
- else
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
Move_Zp2_Point( exc, point, dx, dy, TRUE );
exc->GS.loop--;
@@ -5771,76 +5401,6 @@
}
}
else
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- if ( SUBPIXEL_HINTING_INFINALITY &&
- exc->ignore_x_mode )
- {
- FT_Int B1, B2;
-
-
- /* If not using ignore_x_mode rendering, allow ZP2 move. */
- /* If inline deltas aren't allowed, skip ZP2 move. */
- /* If using ignore_x_mode rendering, allow ZP2 point move if: */
- /* - freedom vector is y and sph_compatibility_mode is off */
- /* - the glyph is composite and the move is in the Y direction */
- /* - the glyph is specifically set to allow SHPIX moves */
- /* - the move is on a previously Y-touched point */
-
- /* save point for later comparison */
- B1 = exc->zp2.cur[point].y;
-
- if ( exc->face->sph_compatibility_mode )
- {
- if ( exc->sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES )
- dy = FT_PIX_ROUND( B1 + dy ) - B1;
-
- /* skip post-iup deltas */
- if ( exc->iup_called &&
- ( ( exc->sph_in_func_flags & SPH_FDEF_INLINE_DELTA_1 ) ||
- ( exc->sph_in_func_flags & SPH_FDEF_INLINE_DELTA_2 ) ) )
- goto Skip;
-
- if ( !( exc->sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) &&
- ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||
- ( exc->zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y ) ||
- ( exc->sph_tweak_flags & SPH_TWEAK_DO_SHPIX ) ) )
- Move_Zp2_Point( exc, point, 0, dy, TRUE );
-
- /* save new point */
- if ( exc->GS.freeVector.y != 0 )
- {
- B2 = exc->zp2.cur[point].y;
-
- /* reverse any disallowed moves */
- if ( ( B1 & 63 ) == 0 &&
- ( B2 & 63 ) != 0 &&
- B1 != B2 )
- Move_Zp2_Point( exc, point, 0, NEG_LONG( dy ), TRUE );
- }
- }
- else if ( exc->GS.freeVector.y != 0 )
- {
- Move_Zp2_Point( exc, point, dx, dy, TRUE );
-
- /* save new point */
- B2 = exc->zp2.cur[point].y;
-
- /* reverse any disallowed moves */
- if ( ( exc->sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
- ( B1 & 63 ) != 0 &&
- ( B2 & 63 ) != 0 &&
- B1 != B2 )
- Move_Zp2_Point( exc,
- point,
- NEG_LONG( dx ),
- NEG_LONG( dy ),
- TRUE );
- }
- else if ( exc->sph_in_func_flags & SPH_FDEF_TYPEMAN_DIAGENDCTRL )
- Move_Zp2_Point( exc, point, dx, dy, TRUE );
- }
- else
-#endif
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
if ( SUBPIXEL_HINTING_MINIMAL &&
exc->backward_compatibility )
@@ -5860,9 +5420,6 @@
#endif
Move_Zp2_Point( exc, point, dx, dy, TRUE );
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- Skip:
-#endif
exc->GS.loop--;
}
@@ -5907,28 +5464,6 @@
distance = PROJECT( exc->zp1.cur + point, exc->zp0.cur + exc->GS.rp0 );
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- /* subpixel hinting - make MSIRP respect CVT cut-in; */
- if ( SUBPIXEL_HINTING_INFINALITY &&
- exc->ignore_x_mode &&
- exc->GS.freeVector.x != 0 )
- {
- FT_F26Dot6 control_value_cutin = exc->GS.control_value_cutin;
- FT_F26Dot6 delta;
-
-
- if ( !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
- control_value_cutin = 0;
-
- delta = SUB_LONG( distance, args[1] );
- if ( delta < 0 )
- delta = NEG_LONG( delta );
-
- if ( delta >= control_value_cutin )
- distance = args[1];
- }
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
exc->func_move( exc,
&exc->zp1,
point,
@@ -5969,14 +5504,7 @@
if ( ( exc->opcode & 1 ) != 0 )
{
cur_dist = FAST_PROJECT( &exc->zp0.cur[point] );
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- if ( SUBPIXEL_HINTING_INFINALITY &&
- exc->ignore_x_mode &&
- exc->GS.freeVector.x != 0 )
- distance = SUB_LONG( Round_None( exc, cur_dist, 3 ), cur_dist );
- else
-#endif
- distance = SUB_LONG( exc->func_round( exc, cur_dist, 3 ), cur_dist );
+ distance = SUB_LONG( exc->func_round( exc, cur_dist, 3 ), cur_dist );
}
else
distance = 0;
@@ -6039,27 +5567,12 @@
if ( exc->GS.gep0 == 0 ) /* If in twilight zone */
{
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- /* Only adjust if not in sph_compatibility_mode or ignore_x_mode. */
- /* Determined via experimentation and may be incorrect... */
- if ( !( SUBPIXEL_HINTING_INFINALITY &&
- ( exc->ignore_x_mode &&
- exc->face->sph_compatibility_mode ) ) )
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
- exc->zp0.org[point].x = TT_MulFix14( distance,
+ exc->zp0.org[point].x = TT_MulFix14( distance,
exc->GS.freeVector.x );
exc->zp0.org[point].y = TT_MulFix14( distance,
exc->GS.freeVector.y );
exc->zp0.cur[point] = exc->zp0.org[point];
}
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- if ( SUBPIXEL_HINTING_INFINALITY &&
- exc->ignore_x_mode &&
- ( exc->sph_tweak_flags & SPH_TWEAK_MIAP_HACK ) &&
- distance > 0 &&
- exc->GS.freeVector.y != 0 )
- distance = 0;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
org_dist = FAST_PROJECT( &exc->zp0.cur[point] );
@@ -6069,15 +5582,6 @@
FT_F26Dot6 delta;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- if ( SUBPIXEL_HINTING_INFINALITY &&
- exc->ignore_x_mode &&
- exc->GS.freeVector.x != 0 &&
- exc->GS.freeVector.y == 0 &&
- !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
- control_value_cutin = 0;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
delta = SUB_LONG( distance, org_dist );
if ( delta < 0 )
delta = NEG_LONG( delta );
@@ -6085,14 +5589,7 @@
if ( delta > control_value_cutin )
distance = org_dist;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- if ( SUBPIXEL_HINTING_INFINALITY &&
- exc->ignore_x_mode &&
- exc->GS.freeVector.x != 0 )
- distance = Round_None( exc, distance, 3 );
- else
-#endif
- distance = exc->func_round( exc, distance, 3 );
+ distance = exc->func_round( exc, distance, 3 );
}
exc->func_move( exc, &exc->zp0, point, SUB_LONG( distance, org_dist ) );
@@ -6185,14 +5682,7 @@
if ( ( exc->opcode & 4 ) != 0 )
{
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- if ( SUBPIXEL_HINTING_INFINALITY &&
- exc->ignore_x_mode &&
- exc->GS.freeVector.x != 0 )
- distance = Round_None( exc, org_dist, exc->opcode & 3 );
- else
-#endif
- distance = exc->func_round( exc, org_dist, exc->opcode & 3 );
+ distance = exc->func_round( exc, org_dist, exc->opcode & 3 );
}
else
distance = Round_None( exc, org_dist, exc->opcode & 3 );
@@ -6204,14 +5694,6 @@
FT_F26Dot6 minimum_distance = exc->GS.minimum_distance;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- if ( SUBPIXEL_HINTING_INFINALITY &&
- exc->ignore_x_mode &&
- exc->GS.freeVector.x != 0 &&
- !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
- minimum_distance = 0;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
if ( org_dist >= 0 )
{
if ( distance < minimum_distance )
@@ -6354,41 +5836,7 @@
distance = exc->func_round( exc, cvt_dist, exc->opcode & 3 );
}
else
- {
-
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- /* do cvt cut-in always in MIRP for sph */
- if ( SUBPIXEL_HINTING_INFINALITY &&
- exc->ignore_x_mode &&
- exc->GS.gep0 == exc->GS.gep1 )
- {
- FT_F26Dot6 control_value_cutin = exc->GS.control_value_cutin;
-
-
- if ( exc->GS.freeVector.x != 0 &&
- !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
- control_value_cutin = 0;
-
- if ( exc->GS.freeVector.y != 0 &&
- ( exc->sph_tweak_flags & SPH_TWEAK_TIMES_NEW_ROMAN_HACK ) )
- {
- if ( cur_dist < -64 )
- cvt_dist -= 16;
- else if ( cur_dist > 64 && cur_dist < 84 )
- cvt_dist += 32;
- }
-
- delta = SUB_LONG( cvt_dist, org_dist );
- if ( delta < 0 )
- delta = NEG_LONG( delta );
-
- if ( delta > control_value_cutin )
- cvt_dist = org_dist;
- }
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
distance = Round_None( exc, cvt_dist, exc->opcode & 3 );
- }
/* minimum distance test */
@@ -6397,14 +5845,6 @@
FT_F26Dot6 minimum_distance = exc->GS.minimum_distance;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- if ( SUBPIXEL_HINTING_INFINALITY &&
- exc->ignore_x_mode &&
- exc->GS.freeVector.x != 0 &&
- !( exc->sph_tweak_flags & SPH_TWEAK_NORMAL_ROUND ) )
- minimum_distance = 0;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
if ( org_dist >= 0 )
{
if ( distance < minimum_distance )
@@ -6417,51 +5857,10 @@
}
}
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- if ( SUBPIXEL_HINTING_INFINALITY &&
- exc->ignore_x_mode &&
- exc->GS.freeVector.y != 0 )
- {
- FT_Int B1, B2;
-
-
- B1 = exc->zp1.cur[point].y;
-
- /* Round moves if necessary */
- if ( exc->sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES )
- distance = FT_PIX_ROUND( B1 + distance - cur_dist ) - B1 + cur_dist;
-
- if ( ( exc->opcode & 16 ) == 0 &&
- ( exc->opcode & 8 ) == 0 &&
- ( exc->sph_tweak_flags & SPH_TWEAK_COURIER_NEW_2_HACK ) )
- distance += 64;
-
- exc->func_move( exc,
- &exc->zp1,
- point,
- SUB_LONG( distance, cur_dist ) );
-
- B2 = exc->zp1.cur[point].y;
-
- /* Reverse move if necessary */
- if ( ( exc->face->sph_compatibility_mode &&
- ( B1 & 63 ) == 0 &&
- ( B2 & 63 ) != 0 ) ||
- ( ( exc->sph_tweak_flags & SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES ) &&
- ( B1 & 63 ) != 0 &&
- ( B2 & 63 ) != 0 ) )
- exc->func_move( exc,
- &exc->zp1,
- point,
- SUB_LONG( cur_dist, distance ) );
- }
- else
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
- exc->func_move( exc,
- &exc->zp1,
- point,
- SUB_LONG( distance, cur_dist ) );
+ exc->func_move( exc,
+ &exc->zp1,
+ point,
+ SUB_LONG( distance, cur_dist ) );
Fail:
exc->GS.rp1 = exc->GS.rp0;
@@ -6486,17 +5885,6 @@
FT_F26Dot6 distance;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- if ( SUBPIXEL_HINTING_INFINALITY &&
- exc->ignore_x_mode &&
- exc->iup_called &&
- ( exc->sph_tweak_flags & SPH_TWEAK_NO_ALIGNRP_AFTER_IUP ) )
- {
- exc->error = FT_THROW( Invalid_Reference );
- goto Fail;
- }
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
if ( exc->top < exc->GS.loop ||
BOUNDS( exc->GS.rp0, exc->zp0.n_points ) )
{
@@ -7055,16 +6443,6 @@
contour = 0;
point = 0;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- if ( SUBPIXEL_HINTING_INFINALITY &&
- exc->ignore_x_mode )
- {
- exc->iup_called = TRUE;
- if ( exc->sph_tweak_flags & SPH_TWEAK_SKIP_IUP )
- return;
- }
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
do
{
end_point = exc->pts.contours[contour] - exc->pts.first_point;
@@ -7137,14 +6515,6 @@
FT_Long B;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- if ( SUBPIXEL_HINTING_INFINALITY &&
- exc->ignore_x_mode &&
- exc->iup_called &&
- ( exc->sph_tweak_flags & SPH_TWEAK_NO_DELTAP_AFTER_IUP ) )
- goto Fail;
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
P = (FT_ULong)exc->func_cur_ppem( exc );
nump = (FT_ULong)args[0]; /* some points theoretically may occur more
than once, thus UShort isn't enough */
@@ -7197,87 +6567,21 @@
B++;
B *= 1L << ( 6 - exc->GS.delta_shift );
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- if ( SUBPIXEL_HINTING_INFINALITY )
+#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
+ /* See `ttinterp.h' for details on backward compatibility */
+ /* mode. */
+ if ( SUBPIXEL_HINTING_MINIMAL &&
+ exc->backward_compatibility )
{
- /*
- * Allow delta move if
- *
- * - not using ignore_x_mode rendering,
- * - glyph is specifically set to allow it, or
- * - glyph is composite and freedom vector is not in subpixel
- * direction.
- */
- if ( !exc->ignore_x_mode ||
- ( exc->sph_tweak_flags & SPH_TWEAK_ALWAYS_DO_DELTAP ) ||
- ( exc->is_composite && exc->GS.freeVector.y != 0 ) )
+ if ( !( exc->iupx_called && exc->iupy_called ) &&
+ ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||
+ ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) ) )
exc->func_move( exc, &exc->zp0, A, B );
-
- /* Otherwise, apply subpixel hinting and compatibility mode */
- /* rules, always skipping deltas in subpixel direction. */
- else if ( exc->ignore_x_mode && exc->GS.freeVector.y != 0 )
- {
- FT_UShort B1, B2;
-
-
- /* save the y value of the point now; compare after move */
- B1 = (FT_UShort)exc->zp0.cur[A].y;
-
- /* Standard subpixel hinting: Allow y move for y-touched */
- /* points. This messes up DejaVu ... */
- if ( !exc->face->sph_compatibility_mode &&
- ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) )
- exc->func_move( exc, &exc->zp0, A, B );
-
- /* compatibility mode */
- else if ( exc->face->sph_compatibility_mode &&
- !( exc->sph_tweak_flags & SPH_TWEAK_ALWAYS_SKIP_DELTAP ) )
- {
- if ( exc->sph_tweak_flags & SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES )
- B = FT_PIX_ROUND( B1 + B ) - B1;
-
- /* Allow delta move if using sph_compatibility_mode, */
- /* IUP has not been called, and point is touched on Y. */
- if ( !exc->iup_called &&
- ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) )
- exc->func_move( exc, &exc->zp0, A, B );
- }
-
- B2 = (FT_UShort)exc->zp0.cur[A].y;
-
- /* Reverse this move if it results in a disallowed move */
- if ( exc->GS.freeVector.y != 0 &&
- ( ( exc->face->sph_compatibility_mode &&
- ( B1 & 63 ) == 0 &&
- ( B2 & 63 ) != 0 ) ||
- ( ( exc->sph_tweak_flags &
- SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES_DELTAP ) &&
- ( B1 & 63 ) != 0 &&
- ( B2 & 63 ) != 0 ) ) )
- exc->func_move( exc, &exc->zp0, A, NEG_LONG( B ) );
- }
}
else
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
- {
-
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
- /* See `ttinterp.h' for details on backward compatibility */
- /* mode. */
- if ( SUBPIXEL_HINTING_MINIMAL &&
- exc->backward_compatibility )
- {
- if ( !( exc->iupx_called && exc->iupy_called ) &&
- ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) ||
- ( exc->zp0.tags[A] & FT_CURVE_TAG_TOUCH_Y ) ) )
- exc->func_move( exc, &exc->zp0, A, B );
- }
- else
#endif
- exc->func_move( exc, &exc->zp0, A, B );
- }
+ exc->func_move( exc, &exc->zp0, A, B );
}
}
else
@@ -7380,14 +6684,6 @@
* GETINFO[]: GET INFOrmation
* Opcode range: 0x88
* Stack: uint32 --> uint32
- *
- * XXX: UNDOCUMENTED: Selector bits higher than 9 are currently (May
- * 2015) not documented in the OpenType specification.
- *
- * Selector bit 11 is incorrectly described as bit 8, while the
- * real meaning of bit 8 (vertical LCD subpixels) stays
- * undocumented. The same mistake can be found in Greg Hitchcock's
- * whitepaper.
*/
static void
Ins_GETINFO( TT_ExecContext exc,
@@ -7399,31 +6695,8 @@
K = 0;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- /*********************************
- * RASTERIZER VERSION
- * Selector Bit: 0
- * Return Bit(s): 0-7
- */
- if ( SUBPIXEL_HINTING_INFINALITY &&
- ( args[0] & 1 ) != 0 &&
- exc->subpixel_hinting )
- {
- if ( exc->ignore_x_mode )
- {
- /* if in ClearType backward compatibility mode, */
- /* we sometimes change the TrueType version dynamically */
- K = exc->rasterizer_version;
- FT_TRACE6(( "Setting rasterizer version %d\n",
- exc->rasterizer_version ));
- }
- else
- K = TT_INTERPRETER_VERSION_38;
- }
- else
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
- if ( ( args[0] & 1 ) != 0 )
- K = driver->interpreter_version;
+ if ( ( args[0] & 1 ) != 0 )
+ K = driver->interpreter_version;
/*********************************
* GLYPH ROTATED
@@ -7446,8 +6719,6 @@
* VARIATION GLYPH
* Selector Bit: 3
* Return Bit(s): 10
- *
- * XXX: UNDOCUMENTED!
*/
if ( (args[0] & 8 ) != 0 && exc->face->blend )
K |= 1 << 10;
@@ -7522,89 +6793,6 @@
}
#endif
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-
- if ( SUBPIXEL_HINTING_INFINALITY &&
- exc->rasterizer_version >= TT_INTERPRETER_VERSION_35 )
- {
-
- if ( exc->rasterizer_version >= 37 )
- {
- /*********************************
- * HINTING FOR SUBPIXEL
- * Selector Bit: 6
- * Return Bit(s): 13
- */
- if ( ( args[0] & 64 ) != 0 && exc->subpixel_hinting )
- K |= 1 << 13;
-
- /*********************************
- * COMPATIBLE WIDTHS ENABLED
- * Selector Bit: 7
- * Return Bit(s): 14
- *
- * Functionality still needs to be added
- */
- if ( ( args[0] & 128 ) != 0 && exc->compatible_widths )
- K |= 1 << 14;
-
- /*********************************
- * VERTICAL LCD SUBPIXELS?
- * Selector Bit: 8
- * Return Bit(s): 15
- *
- * Functionality still needs to be added
- */
- if ( ( args[0] & 256 ) != 0 && exc->vertical_lcd )
- K |= 1 << 15;
-
- /*********************************
- * HINTING FOR BGR?
- * Selector Bit: 9
- * Return Bit(s): 16
- *
- * Functionality still needs to be added
- */
- if ( ( args[0] & 512 ) != 0 && exc->bgr )
- K |= 1 << 16;
-
- if ( exc->rasterizer_version >= 38 )
- {
- /*********************************
- * SUBPIXEL POSITIONED?
- * Selector Bit: 10
- * Return Bit(s): 17
- *
- * Functionality still needs to be added
- */
- if ( ( args[0] & 1024 ) != 0 && exc->subpixel_positioned )
- K |= 1 << 17;
-
- /*********************************
- * SYMMETRICAL SMOOTHING
- * Selector Bit: 11
- * Return Bit(s): 18
- *
- * Functionality still needs to be added
- */
- if ( ( args[0] & 2048 ) != 0 && exc->symmetrical_smoothing )
- K |= 1 << 18;
-
- /*********************************
- * GRAY CLEARTYPE
- * Selector Bit: 12
- * Return Bit(s): 19
- *
- * Functionality still needs to be added
- */
- if ( ( args[0] & 4096 ) != 0 && exc->gray_cleartype )
- K |= 1 << 19;
- }
- }
- }
-
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
args[0] = K;
}
@@ -7739,25 +6927,14 @@
/* documentation is in ttinterp.h */
FT_EXPORT_DEF( FT_Error )
- TT_RunIns( TT_ExecContext exc )
+ TT_RunIns( void* exec )
{
+ TT_ExecContext exc = (TT_ExecContext)exec;
+
FT_ULong ins_counter = 0; /* executed instructions counter */
FT_ULong num_twilight_points;
FT_UShort i;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- FT_Byte opcode_pattern[1][2] = {
- /* #8 TypeMan Talk Align */
- {
- 0x06, /* SPVTL */
- 0x7D, /* RDTG */
- },
- };
- FT_UShort opcode_patterns = 1;
- FT_UShort opcode_pointer[1] = { 0 };
- FT_UShort opcode_size[1] = { 1 };
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
/* We restrict the number of twilight points to a reasonable, */
/* heuristic value to avoid slow execution of malformed bytecode. */
@@ -7835,9 +7012,6 @@
Compute_Round( exc, (FT_Byte)exc->GS.round_state );
/* These flags cancel execution of some opcodes after IUP is called */
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- exc->iup_called = FALSE;
-#endif
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
exc->iupx_called = FALSE;
exc->iupy_called = FALSE;
@@ -7906,7 +7080,7 @@
/* a variable number of arguments */
/* it is the job of the application to `activate' GX handling, */
- /* this is, calling any of the GX API functions on the current */
+ /* that is, calling any of the GX API functions on the current */
/* font to select a variation instance */
if ( exc->face->blend )
exc->new_top = exc->args + exc->face->blend->num_axis;
@@ -7927,39 +7101,6 @@
exc->step_ins = TRUE;
exc->error = FT_Err_Ok;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-
- if ( SUBPIXEL_HINTING_INFINALITY )
- {
- for ( i = 0; i < opcode_patterns; i++ )
- {
- if ( opcode_pointer[i] < opcode_size[i] &&
- exc->opcode == opcode_pattern[i][opcode_pointer[i]] )
- {
- opcode_pointer[i] += 1;
-
- if ( opcode_pointer[i] == opcode_size[i] )
- {
- FT_TRACE6(( "sph: opcode ptrn: %d, %s %s\n",
- i,
- exc->face->root.family_name,
- exc->face->root.style_name ));
-
- switch ( i )
- {
- case 0:
- break;
- }
- opcode_pointer[i] = 0;
- }
- }
- else
- opcode_pointer[i] = 0;
- }
- }
-
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
{
FT_Long* args = exc->stack + exc->args;
FT_Byte opcode = exc->opcode;
@@ -8466,7 +7607,7 @@
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
case 0x91:
/* it is the job of the application to `activate' GX handling, */
- /* this is, calling any of the GX API functions on the current */
+ /* that is, calling any of the GX API functions on the current */
/* font to select a variation instance */
if ( exc->face->blend )
Ins_GETVARIATION( exc, args );
@@ -8604,7 +7745,7 @@
#else /* !TT_USE_BYTECODE_INTERPRETER */
/* ANSI C doesn't like empty source files */
- typedef int _tt_interp_dummy;
+ typedef int tt_interp_dummy_;
#endif /* !TT_USE_BYTECODE_INTERPRETER */
diff --git a/src/3rdparty/freetype/src/truetype/ttinterp.h b/src/3rdparty/freetype/src/truetype/ttinterp.h
index c54c053b29..e98e258fe7 100644
--- a/src/3rdparty/freetype/src/truetype/ttinterp.h
+++ b/src/3rdparty/freetype/src/truetype/ttinterp.h
@@ -98,48 +98,6 @@ FT_BEGIN_HEADER
} TT_CallRec, *TT_CallStack;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-
- /**************************************************************************
- *
- * These structures define rules used to tweak subpixel hinting for
- * various fonts. "", 0, "", NULL value indicates to match any value.
- */
-
-#define SPH_MAX_NAME_SIZE 32
-#define SPH_MAX_CLASS_MEMBERS 100
-
- typedef struct SPH_TweakRule_
- {
- const char family[SPH_MAX_NAME_SIZE];
- const FT_UInt ppem;
- const char style[SPH_MAX_NAME_SIZE];
- const FT_ULong glyph;
-
- } SPH_TweakRule;
-
-
- typedef struct SPH_ScaleRule_
- {
- const char family[SPH_MAX_NAME_SIZE];
- const FT_UInt ppem;
- const char style[SPH_MAX_NAME_SIZE];
- const FT_ULong glyph;
- const FT_ULong scale;
-
- } SPH_ScaleRule;
-
-
- typedef struct SPH_Font_Class_
- {
- const char name[SPH_MAX_NAME_SIZE];
- const char member[SPH_MAX_CLASS_MEMBERS][SPH_MAX_NAME_SIZE];
-
- } SPH_Font_Class;
-
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
-
/**************************************************************************
*
* The main structure for the interpreter which collects all necessary
@@ -399,38 +357,6 @@ FT_BEGIN_HEADER
FT_Bool grayscale_cleartype;
#endif /* TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL */
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- TT_Round_Func func_round_sphn; /* subpixel rounding function */
-
- FT_Bool subpixel_hinting; /* Using subpixel hinting? */
- FT_Bool ignore_x_mode; /* Standard rendering mode for */
- /* subpixel hinting. On if gray */
- /* or subpixel hinting is on. */
-
- /* The following 6 aren't fully implemented but here for MS rasterizer */
- /* compatibility. */
- FT_Bool compatible_widths; /* compatible widths? */
- FT_Bool symmetrical_smoothing; /* symmetrical_smoothing? */
- FT_Bool bgr; /* bgr instead of rgb? */
- FT_Bool vertical_lcd; /* long side of LCD subpixel */
- /* rectangles is horizontal */
- FT_Bool subpixel_positioned; /* subpixel positioned */
- /* (DirectWrite ClearType)? */
- FT_Bool gray_cleartype; /* ClearType hinting but */
- /* grayscale rendering */
-
- FT_Int rasterizer_version; /* MS rasterizer version */
-
- FT_Bool iup_called; /* IUP called for glyph? */
-
- FT_ULong sph_tweak_flags; /* flags to control */
- /* hint tweaks */
-
- FT_ULong sph_in_func_flags; /* flags to indicate if in */
- /* special functions */
-
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
/* We maintain two counters (in addition to the instruction counter) */
/* that act as loop detectors for LOOPCALL and jump opcodes with */
/* negative arguments. */
@@ -460,14 +386,6 @@ FT_BEGIN_HEADER
FT_LOCAL( void )
TT_Clear_CodeRange( TT_ExecContext exec,
FT_Int range );
-
-
- FT_LOCAL( FT_Error )
- Update_Max( FT_Memory memory,
- FT_ULong* size,
- FT_ULong multiplier,
- void* _pbuff,
- FT_ULong new_max );
#endif /* TT_USE_BYTECODE_INTERPRETER */
@@ -536,7 +454,7 @@ FT_BEGIN_HEADER
* invoked by the TrueType debugger.
*/
FT_EXPORT( FT_Error )
- TT_RunIns( TT_ExecContext exec );
+ TT_RunIns( void* exec );
FT_END_HEADER
diff --git a/src/3rdparty/freetype/src/truetype/ttobjs.c b/src/3rdparty/freetype/src/truetype/ttobjs.c
index 4a8873fd8c..5b56af711d 100644
--- a/src/3rdparty/freetype/src/truetype/ttobjs.c
+++ b/src/3rdparty/freetype/src/truetype/ttobjs.c
@@ -312,7 +312,8 @@
#define TRICK_SFNT_IDS_NUM_FACES 31
static const tt_sfnt_id_rec sfnt_id[TRICK_SFNT_IDS_NUM_FACES]
- [TRICK_SFNT_IDS_PER_FACE] = {
+ [TRICK_SFNT_IDS_PER_FACE] =
+ {
#define TRICK_SFNT_ID_cvt 0
#define TRICK_SFNT_ID_fpgm 1
@@ -581,7 +582,7 @@
FT_Bool result = FALSE;
TT_Face face = (TT_Face)ttface;
- FT_UInt asize;
+ FT_ULong asize;
FT_ULong i;
FT_ULong glyph_index = 0;
FT_UInt count = 0;
@@ -589,7 +590,7 @@
for( i = 0; i < face->num_locations; i++ )
{
- tt_face_get_location( face, i, &asize );
+ tt_face_get_location( ttface, i, &asize );
if ( asize > 0 )
{
count += 1;
@@ -777,7 +778,6 @@
}
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
-
{
FT_UInt instance_index = (FT_UInt)face_index >> 16;
@@ -785,14 +785,11 @@
if ( FT_HAS_MULTIPLE_MASTERS( ttface ) &&
instance_index > 0 )
{
- error = TT_Set_Named_Instance( face, instance_index );
+ error = FT_Set_Named_Instance( ttface, instance_index );
if ( error )
goto Exit;
-
- tt_apply_mvar( face );
}
}
-
#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
/* initialize standard glyph loading routines */
@@ -858,7 +855,7 @@
face->cvt_program_size = 0;
#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
- tt_done_blend( face );
+ tt_done_blend( ttface );
face->blend = NULL;
#endif
}
@@ -1338,39 +1335,29 @@
/**************************************************************************
*
* @Function:
- * tt_size_reset
+ * tt_size_reset_height
*
* @Description:
- * Reset a TrueType size when resolutions and character dimensions
- * have been changed.
+ * Recompute a TrueType size's ascender, descender, and height
+ * when resolutions and character dimensions have been changed.
+ * Used for variation fonts as an iterator function.
*
* @Input:
- * size ::
- * A handle to the target size object.
- *
- * only_height ::
- * Only recompute ascender, descender, and height;
- * this flag is used for variation fonts where
- * `tt_size_reset' is used as an iterator function.
+ * ft_size ::
+ * A handle to the target TT_Size object. This function will be called
+ * through a `FT_Size_Reset_Func` pointer which takes `FT_Size`. This
+ * function must take `FT_Size` as a result. The passed `FT_Size` is
+ * expected to point to a `TT_Size`.
*/
FT_LOCAL_DEF( FT_Error )
- tt_size_reset( TT_Size size,
- FT_Bool only_height )
+ tt_size_reset_height( FT_Size ft_size )
{
- TT_Face face;
- FT_Size_Metrics* size_metrics;
-
-
- face = (TT_Face)size->root.face;
-
- /* nothing to do for CFF2 */
- if ( face->is_cff2 )
- return FT_Err_Ok;
+ TT_Size size = (TT_Size)ft_size;
+ TT_Face face = (TT_Face)size->root.face;
+ FT_Size_Metrics* size_metrics = &size->hinted_metrics;
size->ttmetrics.valid = FALSE;
- size_metrics = &size->hinted_metrics;
-
/* copy the result from base layer */
*size_metrics = size->root.metrics;
@@ -1397,12 +1384,34 @@
size->ttmetrics.valid = TRUE;
- if ( only_height )
- {
- /* we must not recompute the scaling values here since */
- /* `tt_size_reset' was already called (with only_height = 0) */
- return FT_Err_Ok;
- }
+ return FT_Err_Ok;
+ }
+
+
+ /**************************************************************************
+ *
+ * @Function:
+ * tt_size_reset
+ *
+ * @Description:
+ * Reset a TrueType size when resolutions and character dimensions
+ * have been changed.
+ *
+ * @Input:
+ * size ::
+ * A handle to the target size object.
+ */
+ FT_LOCAL_DEF( FT_Error )
+ tt_size_reset( TT_Size size )
+ {
+ FT_Error error;
+ TT_Face face = (TT_Face)size->root.face;
+ FT_Size_Metrics* size_metrics = &size->hinted_metrics;
+
+
+ error = tt_size_reset_height( (FT_Size)size );
+ if ( error )
+ return error;
if ( face->header.Flags & 8 )
{
@@ -1472,9 +1481,6 @@
TT_Driver driver = (TT_Driver)ttdriver;
driver->interpreter_version = TT_INTERPRETER_VERSION_35;
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
- driver->interpreter_version = TT_INTERPRETER_VERSION_38;
-#endif
#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
driver->interpreter_version = TT_INTERPRETER_VERSION_40;
#endif
diff --git a/src/3rdparty/freetype/src/truetype/ttobjs.h b/src/3rdparty/freetype/src/truetype/ttobjs.h
index bc6fbe7f19..40eb37b4c4 100644
--- a/src/3rdparty/freetype/src/truetype/ttobjs.h
+++ b/src/3rdparty/freetype/src/truetype/ttobjs.h
@@ -162,8 +162,6 @@ FT_BEGIN_HEADER
FT_Long end; /* where does it end? */
FT_UInt opc; /* function #, or instruction code */
FT_Bool active; /* is it active? */
- FT_Bool inline_delta; /* is function that defines inline delta? */
- FT_ULong sph_fdef_flags; /* flags to identify special functions */
} TT_DefRecord, *TT_DefArray;
@@ -391,8 +389,10 @@ FT_BEGIN_HEADER
#endif /* TT_USE_BYTECODE_INTERPRETER */
FT_LOCAL( FT_Error )
- tt_size_reset( TT_Size size,
- FT_Bool only_height );
+ tt_size_reset_height( FT_Size size );
+
+ FT_LOCAL( FT_Error )
+ tt_size_reset( TT_Size size );
/**************************************************************************
diff --git a/src/3rdparty/freetype/src/truetype/ttpload.c b/src/3rdparty/freetype/src/truetype/ttpload.c
index e08bf309e3..54a64c7b46 100644
--- a/src/3rdparty/freetype/src/truetype/ttpload.c
+++ b/src/3rdparty/freetype/src/truetype/ttpload.c
@@ -180,10 +180,11 @@
FT_LOCAL_DEF( FT_ULong )
- tt_face_get_location( TT_Face face,
- FT_UInt gindex,
- FT_UInt *asize )
+ tt_face_get_location( FT_Face face, /* TT_Face */
+ FT_UInt gindex,
+ FT_ULong *asize )
{
+ TT_Face ttface = (TT_Face)face;
FT_ULong pos1, pos2;
FT_Byte* p;
FT_Byte* p_limit;
@@ -191,12 +192,12 @@
pos1 = pos2 = 0;
- if ( gindex < face->num_locations )
+ if ( gindex < ttface->num_locations )
{
- if ( face->header.Index_To_Loc_Format != 0 )
+ if ( ttface->header.Index_To_Loc_Format != 0 )
{
- p = face->glyph_locations + gindex * 4;
- p_limit = face->glyph_locations + face->num_locations * 4;
+ p = ttface->glyph_locations + gindex * 4;
+ p_limit = ttface->glyph_locations + ttface->num_locations * 4;
pos1 = FT_NEXT_ULONG( p );
pos2 = pos1;
@@ -206,8 +207,8 @@
}
else
{
- p = face->glyph_locations + gindex * 2;
- p_limit = face->glyph_locations + face->num_locations * 2;
+ p = ttface->glyph_locations + gindex * 2;
+ p_limit = ttface->glyph_locations + ttface->num_locations * 2;
pos1 = FT_NEXT_USHORT( p );
pos2 = pos1;
@@ -221,30 +222,30 @@
}
/* Check broken location data. */
- if ( pos1 > face->glyf_len )
+ if ( pos1 > ttface->glyf_len )
{
FT_TRACE1(( "tt_face_get_location:"
" too large offset (0x%08lx) found for glyph index %d,\n",
pos1, gindex ));
FT_TRACE1(( " "
" exceeding the end of `glyf' table (0x%08lx)\n",
- face->glyf_len ));
+ ttface->glyf_len ));
*asize = 0;
return 0;
}
- if ( pos2 > face->glyf_len )
+ if ( pos2 > ttface->glyf_len )
{
/* We try to sanitize the last `loca' entry. */
- if ( gindex == face->num_locations - 2 )
+ if ( gindex == ttface->num_locations - 2 )
{
FT_TRACE1(( "tt_face_get_location:"
" too large size (%ld bytes) found for glyph index %d,\n",
pos2 - pos1, gindex ));
FT_TRACE1(( " "
" truncating at the end of `glyf' table to %ld bytes\n",
- face->glyf_len - pos1 ));
- pos2 = face->glyf_len;
+ ttface->glyf_len - pos1 ));
+ pos2 = ttface->glyf_len;
}
else
{
@@ -253,7 +254,7 @@
pos2, gindex + 1 ));
FT_TRACE1(( " "
" exceeding the end of `glyf' table (0x%08lx)\n",
- face->glyf_len ));
+ ttface->glyf_len ));
*asize = 0;
return 0;
}
@@ -268,9 +269,9 @@
/* We get (intentionally) a wrong, non-zero result in case the */
/* `glyf' table is missing. */
if ( pos2 >= pos1 )
- *asize = (FT_UInt)( pos2 - pos1 );
+ *asize = (FT_ULong)( pos2 - pos1 );
else
- *asize = (FT_UInt)( face->glyf_len - pos1 );
+ *asize = (FT_ULong)( ttface->glyf_len - pos1 );
return pos1;
}
diff --git a/src/3rdparty/freetype/src/truetype/ttpload.h b/src/3rdparty/freetype/src/truetype/ttpload.h
index 939e02fe4f..ed229fa461 100644
--- a/src/3rdparty/freetype/src/truetype/ttpload.h
+++ b/src/3rdparty/freetype/src/truetype/ttpload.h
@@ -31,9 +31,9 @@ FT_BEGIN_HEADER
FT_Stream stream );
FT_LOCAL( FT_ULong )
- tt_face_get_location( TT_Face face,
- FT_UInt gindex,
- FT_UInt *asize );
+ tt_face_get_location( FT_Face face,
+ FT_UInt gindex,
+ FT_ULong *asize );
FT_LOCAL( void )
tt_face_done_loca( TT_Face face );
diff --git a/src/3rdparty/freetype/src/truetype/ttsubpix.c b/src/3rdparty/freetype/src/truetype/ttsubpix.c
deleted file mode 100644
index d811beef0d..0000000000
--- a/src/3rdparty/freetype/src/truetype/ttsubpix.c
+++ /dev/null
@@ -1,1013 +0,0 @@
-/****************************************************************************
- *
- * ttsubpix.c
- *
- * TrueType Subpixel Hinting.
- *
- * Copyright (C) 2010-2023 by
- * David Turner, Robert Wilhelm, and Werner Lemberg.
- *
- * This file is part of the FreeType project, and may only be used,
- * modified, and distributed under the terms of the FreeType project
- * license, LICENSE.TXT. By continuing to use, modify, or distribute
- * this file you indicate that you have read the license and
- * understand and accept it fully.
- *
- */
-
-#include <freetype/internal/ftdebug.h>
-#include <freetype/internal/ftcalc.h>
-#include <freetype/internal/ftstream.h>
-#include <freetype/internal/sfnt.h>
-#include <freetype/tttags.h>
-#include <freetype/ftoutln.h>
-#include <freetype/ftdriver.h>
-
-#include "ttsubpix.h"
-
-
-#if defined( TT_USE_BYTECODE_INTERPRETER ) && \
- defined( TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY )
-
- /**************************************************************************
- *
- * These rules affect how the TT Interpreter does hinting, with the
- * goal of doing subpixel hinting by (in general) ignoring x moves.
- * Some of these rules are fixes that go above and beyond the
- * stated techniques in the MS whitepaper on Cleartype, due to
- * artifacts in many glyphs. So, these rules make some glyphs render
- * better than they do in the MS rasterizer.
- *
- * "" string or 0 int/char indicates to apply to all glyphs.
- * "-" used as dummy placeholders, but any non-matching string works.
- *
- * Some of this could arguably be implemented in fontconfig, however:
- *
- * - Fontconfig can't set things on a glyph-by-glyph basis.
- * - The tweaks that happen here are very low-level, from an average
- * user's point of view and are best implemented in the hinter.
- *
- * The goal is to make the subpixel hinting techniques as generalized
- * as possible across all fonts to prevent the need for extra rules such
- * as these.
- *
- * The rule structure is designed so that entirely new rules can easily
- * be added when a new compatibility feature is discovered.
- *
- * The rule structures could also use some enhancement to handle ranges.
- *
- * ****************** WORK IN PROGRESS *******************
- */
-
- /* These are `classes' of fonts that can be grouped together and used in */
- /* rules below. A blank entry "" is required at the end of these! */
-#define FAMILY_CLASS_RULES_SIZE 7
-
- static const SPH_Font_Class FAMILY_CLASS_Rules
- [FAMILY_CLASS_RULES_SIZE] =
- {
- { "MS Legacy Fonts",
- { "Aharoni",
- "Andale Mono",
- "Andalus",
- "Angsana New",
- "AngsanaUPC",
- "Arabic Transparent",
- "Arial Black",
- "Arial Narrow",
- "Arial Unicode MS",
- "Arial",
- "Batang",
- "Browallia New",
- "BrowalliaUPC",
- "Comic Sans MS",
- "Cordia New",
- "CordiaUPC",
- "Courier New",
- "DFKai-SB",
- "David Transparent",
- "David",
- "DilleniaUPC",
- "Estrangelo Edessa",
- "EucrosiaUPC",
- "FangSong_GB2312",
- "Fixed Miriam Transparent",
- "FrankRuehl",
- "Franklin Gothic Medium",
- "FreesiaUPC",
- "Garamond",
- "Gautami",
- "Georgia",
- "Gulim",
- "Impact",
- "IrisUPC",
- "JasmineUPC",
- "KaiTi_GB2312",
- "KodchiangUPC",
- "Latha",
- "Levenim MT",
- "LilyUPC",
- "Lucida Console",
- "Lucida Sans Unicode",
- "MS Gothic",
- "MS Mincho",
- "MV Boli",
- "Mangal",
- "Marlett",
- "Microsoft Sans Serif",
- "Mingliu",
- "Miriam Fixed",
- "Miriam Transparent",
- "Miriam",
- "Narkisim",
- "Palatino Linotype",
- "Raavi",
- "Rod Transparent",
- "Rod",
- "Shruti",
- "SimHei",
- "Simplified Arabic Fixed",
- "Simplified Arabic",
- "Simsun",
- "Sylfaen",
- "Symbol",
- "Tahoma",
- "Times New Roman",
- "Traditional Arabic",
- "Trebuchet MS",
- "Tunga",
- "Verdana",
- "Webdings",
- "Wingdings",
- "",
- },
- },
- { "Core MS Legacy Fonts",
- { "Arial Black",
- "Arial Narrow",
- "Arial Unicode MS",
- "Arial",
- "Comic Sans MS",
- "Courier New",
- "Garamond",
- "Georgia",
- "Impact",
- "Lucida Console",
- "Lucida Sans Unicode",
- "Microsoft Sans Serif",
- "Palatino Linotype",
- "Tahoma",
- "Times New Roman",
- "Trebuchet MS",
- "Verdana",
- "",
- },
- },
- { "Apple Legacy Fonts",
- { "Geneva",
- "Times",
- "Monaco",
- "Century",
- "Chalkboard",
- "Lobster",
- "Century Gothic",
- "Optima",
- "Lucida Grande",
- "Gill Sans",
- "Baskerville",
- "Helvetica",
- "Helvetica Neue",
- "",
- },
- },
- { "Legacy Sans Fonts",
- { "Andale Mono",
- "Arial Unicode MS",
- "Arial",
- "Century Gothic",
- "Comic Sans MS",
- "Franklin Gothic Medium",
- "Geneva",
- "Lucida Console",
- "Lucida Grande",
- "Lucida Sans Unicode",
- "Lucida Sans Typewriter",
- "Microsoft Sans Serif",
- "Monaco",
- "Tahoma",
- "Trebuchet MS",
- "Verdana",
- "",
- },
- },
-
- { "Misc Legacy Fonts",
- { "Dark Courier", "", }, },
- { "Verdana Clones",
- { "DejaVu Sans",
- "Bitstream Vera Sans", "", }, },
- { "Verdana and Clones",
- { "DejaVu Sans",
- "Bitstream Vera Sans",
- "Verdana", "", }, },
- };
-
-
- /* Define this to force natural (i.e. not bitmap-compatible) widths. */
- /* The default leans strongly towards natural widths except for a few */
- /* legacy fonts where a selective combination produces nicer results. */
-/* #define FORCE_NATURAL_WIDTHS */
-
-
- /* Define `classes' of styles that can be grouped together and used in */
- /* rules below. A blank entry "" is required at the end of these! */
-#define STYLE_CLASS_RULES_SIZE 5
-
- static const SPH_Font_Class STYLE_CLASS_Rules
- [STYLE_CLASS_RULES_SIZE] =
- {
- { "Regular Class",
- { "Regular",
- "Book",
- "Medium",
- "Roman",
- "Normal",
- "",
- },
- },
- { "Regular/Italic Class",
- { "Regular",
- "Book",
- "Medium",
- "Italic",
- "Oblique",
- "Roman",
- "Normal",
- "",
- },
- },
- { "Bold/BoldItalic Class",
- { "Bold",
- "Bold Italic",
- "Black",
- "",
- },
- },
- { "Bold/Italic/BoldItalic Class",
- { "Bold",
- "Bold Italic",
- "Black",
- "Italic",
- "Oblique",
- "",
- },
- },
- { "Regular/Bold Class",
- { "Regular",
- "Book",
- "Medium",
- "Normal",
- "Roman",
- "Bold",
- "Black",
- "",
- },
- },
- };
-
-
- /* Force special legacy fixes for fonts. */
-#define COMPATIBILITY_MODE_RULES_SIZE 1
-
- static const SPH_TweakRule COMPATIBILITY_MODE_Rules
- [COMPATIBILITY_MODE_RULES_SIZE] =
- {
- { "Verdana Clones", 0, "", 0 },
- };
-
-
- /* Don't do subpixel (ignore_x_mode) hinting; do normal hinting. */
-#define PIXEL_HINTING_RULES_SIZE 2
-
- static const SPH_TweakRule PIXEL_HINTING_Rules
- [PIXEL_HINTING_RULES_SIZE] =
- {
- /* these characters are almost always safe */
- { "Courier New", 12, "Italic", 'z' },
- { "Courier New", 11, "Italic", 'z' },
- };
-
-
- /* Subpixel hinting ignores SHPIX rules on X. Force SHPIX for these. */
-#define DO_SHPIX_RULES_SIZE 1
-
- static const SPH_TweakRule DO_SHPIX_Rules
- [DO_SHPIX_RULES_SIZE] =
- {
- { "-", 0, "", 0 },
- };
-
-
- /* Skip Y moves that start with a point that is not on a Y pixel */
- /* boundary and don't move that point to a Y pixel boundary. */
-#define SKIP_NONPIXEL_Y_MOVES_RULES_SIZE 4
-
- static const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_Rules
- [SKIP_NONPIXEL_Y_MOVES_RULES_SIZE] =
- {
- /* fix vwxyz thinness */
- { "Consolas", 0, "", 0 },
- /* Fix thin middle stems */
- { "Core MS Legacy Fonts", 0, "Regular", 0 },
- /* Cyrillic small letter I */
- { "Legacy Sans Fonts", 0, "", 0 },
- /* Fix artifacts with some Regular & Bold */
- { "Verdana Clones", 0, "", 0 },
- };
-
-
-#define SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1
-
- static const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_Rules_Exceptions
- [SKIP_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] =
- {
- /* Fixes < and > */
- { "Courier New", 0, "Regular", 0 },
- };
-
-
- /* Skip Y moves that start with a point that is not on a Y pixel */
- /* boundary and don't move that point to a Y pixel boundary. */
-#define SKIP_NONPIXEL_Y_MOVES_DELTAP_RULES_SIZE 2
-
- static const SPH_TweakRule SKIP_NONPIXEL_Y_MOVES_DELTAP_Rules
- [SKIP_NONPIXEL_Y_MOVES_DELTAP_RULES_SIZE] =
- {
- /* Maintain thickness of diagonal in 'N' */
- { "Times New Roman", 0, "Regular/Bold Class", 'N' },
- { "Georgia", 0, "Regular/Bold Class", 'N' },
- };
-
-
- /* Skip Y moves that move a point off a Y pixel boundary. */
-#define SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE 1
-
- static const SPH_TweakRule SKIP_OFFPIXEL_Y_MOVES_Rules
- [SKIP_OFFPIXEL_Y_MOVES_RULES_SIZE] =
- {
- { "-", 0, "", 0 },
- };
-
-
-#define SKIP_OFFPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1
-
- static const SPH_TweakRule SKIP_OFFPIXEL_Y_MOVES_Rules_Exceptions
- [SKIP_OFFPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] =
- {
- { "-", 0, "", 0 },
- };
-
-
- /* Round moves that don't move a point to a Y pixel boundary. */
-#define ROUND_NONPIXEL_Y_MOVES_RULES_SIZE 2
-
- static const SPH_TweakRule ROUND_NONPIXEL_Y_MOVES_Rules
- [ROUND_NONPIXEL_Y_MOVES_RULES_SIZE] =
- {
- /* Droid font instructions don't snap Y to pixels */
- { "Droid Sans", 0, "Regular/Italic Class", 0 },
- { "Droid Sans Mono", 0, "", 0 },
- };
-
-
-#define ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE 1
-
- static const SPH_TweakRule ROUND_NONPIXEL_Y_MOVES_Rules_Exceptions
- [ROUND_NONPIXEL_Y_MOVES_RULES_EXCEPTIONS_SIZE] =
- {
- { "-", 0, "", 0 },
- };
-
-
- /* Allow a Direct_Move along X freedom vector if matched. */
-#define ALLOW_X_DMOVE_RULES_SIZE 1
-
- static const SPH_TweakRule ALLOW_X_DMOVE_Rules
- [ALLOW_X_DMOVE_RULES_SIZE] =
- {
- /* Fixes vanishing diagonal in 4 */
- { "Verdana", 0, "Regular", '4' },
- };
-
-
- /* Return MS rasterizer version 35 if matched. */
-#define RASTERIZER_35_RULES_SIZE 8
-
- static const SPH_TweakRule RASTERIZER_35_Rules
- [RASTERIZER_35_RULES_SIZE] =
- {
- /* This seems to be the only way to make these look good */
- { "Times New Roman", 0, "Regular", 'i' },
- { "Times New Roman", 0, "Regular", 'j' },
- { "Times New Roman", 0, "Regular", 'm' },
- { "Times New Roman", 0, "Regular", 'r' },
- { "Times New Roman", 0, "Regular", 'a' },
- { "Times New Roman", 0, "Regular", 'n' },
- { "Times New Roman", 0, "Regular", 'p' },
- { "Times", 0, "", 0 },
- };
-
-
- /* Don't round to the subpixel grid. Round to pixel grid. */
-#define NORMAL_ROUND_RULES_SIZE 1
-
- static const SPH_TweakRule NORMAL_ROUND_Rules
- [NORMAL_ROUND_RULES_SIZE] =
- {
- /* Fix serif thickness for certain ppems */
- /* Can probably be generalized somehow */
- { "Courier New", 0, "", 0 },
- };
-
-
- /* Skip IUP instructions if matched. */
-#define SKIP_IUP_RULES_SIZE 1
-
- static const SPH_TweakRule SKIP_IUP_Rules
- [SKIP_IUP_RULES_SIZE] =
- {
- { "Arial", 13, "Regular", 'a' },
- };
-
-
- /* Skip MIAP Twilight hack if matched. */
-#define MIAP_HACK_RULES_SIZE 1
-
- static const SPH_TweakRule MIAP_HACK_Rules
- [MIAP_HACK_RULES_SIZE] =
- {
- { "Geneva", 12, "", 0 },
- };
-
-
- /* Skip DELTAP instructions if matched. */
-#define ALWAYS_SKIP_DELTAP_RULES_SIZE 23
-
- static const SPH_TweakRule ALWAYS_SKIP_DELTAP_Rules
- [ALWAYS_SKIP_DELTAP_RULES_SIZE] =
- {
- { "Georgia", 0, "Regular", 'k' },
- /* fix various problems with e in different versions */
- { "Trebuchet MS", 14, "Regular", 'e' },
- { "Trebuchet MS", 13, "Regular", 'e' },
- { "Trebuchet MS", 15, "Regular", 'e' },
- { "Trebuchet MS", 0, "Italic", 'v' },
- { "Trebuchet MS", 0, "Italic", 'w' },
- { "Trebuchet MS", 0, "Regular", 'Y' },
- { "Arial", 11, "Regular", 's' },
- /* prevent problems with '3' and others */
- { "Verdana", 10, "Regular", 0 },
- { "Verdana", 9, "Regular", 0 },
- /* Cyrillic small letter short I */
- { "Legacy Sans Fonts", 0, "", 0x438 },
- { "Legacy Sans Fonts", 0, "", 0x439 },
- { "Arial", 10, "Regular", '6' },
- { "Arial", 0, "Bold/BoldItalic Class", 'a' },
- /* Make horizontal stems consistent with the rest */
- { "Arial", 24, "Bold", 'a' },
- { "Arial", 25, "Bold", 'a' },
- { "Arial", 24, "Bold", 's' },
- { "Arial", 25, "Bold", 's' },
- { "Arial", 34, "Bold", 's' },
- { "Arial", 35, "Bold", 's' },
- { "Arial", 36, "Bold", 's' },
- { "Arial", 25, "Regular", 's' },
- { "Arial", 26, "Regular", 's' },
- };
-
-
- /* Always do DELTAP instructions if matched. */
-#define ALWAYS_DO_DELTAP_RULES_SIZE 1
-
- static const SPH_TweakRule ALWAYS_DO_DELTAP_Rules
- [ALWAYS_DO_DELTAP_RULES_SIZE] =
- {
- { "-", 0, "", 0 },
- };
-
-
- /* Don't allow ALIGNRP after IUP. */
-#define NO_ALIGNRP_AFTER_IUP_RULES_SIZE 1
-
- static const SPH_TweakRule NO_ALIGNRP_AFTER_IUP_Rules
- [NO_ALIGNRP_AFTER_IUP_RULES_SIZE] =
- {
- /* Prevent creation of dents in outline */
- { "-", 0, "", 0 },
- };
-
-
- /* Don't allow DELTAP after IUP. */
-#define NO_DELTAP_AFTER_IUP_RULES_SIZE 1
-
- static const SPH_TweakRule NO_DELTAP_AFTER_IUP_Rules
- [NO_DELTAP_AFTER_IUP_RULES_SIZE] =
- {
- { "-", 0, "", 0 },
- };
-
-
- /* Don't allow CALL after IUP. */
-#define NO_CALL_AFTER_IUP_RULES_SIZE 1
-
- static const SPH_TweakRule NO_CALL_AFTER_IUP_Rules
- [NO_CALL_AFTER_IUP_RULES_SIZE] =
- {
- /* Prevent creation of dents in outline */
- { "-", 0, "", 0 },
- };
-
-
- /* De-embolden these glyphs slightly. */
-#define DEEMBOLDEN_RULES_SIZE 9
-
- static const SPH_TweakRule DEEMBOLDEN_Rules
- [DEEMBOLDEN_RULES_SIZE] =
- {
- { "Courier New", 0, "Bold", 'A' },
- { "Courier New", 0, "Bold", 'W' },
- { "Courier New", 0, "Bold", 'w' },
- { "Courier New", 0, "Bold", 'M' },
- { "Courier New", 0, "Bold", 'X' },
- { "Courier New", 0, "Bold", 'K' },
- { "Courier New", 0, "Bold", 'x' },
- { "Courier New", 0, "Bold", 'z' },
- { "Courier New", 0, "Bold", 'v' },
- };
-
-
- /* Embolden these glyphs slightly. */
-#define EMBOLDEN_RULES_SIZE 2
-
- static const SPH_TweakRule EMBOLDEN_Rules
- [EMBOLDEN_RULES_SIZE] =
- {
- { "Courier New", 0, "Regular", 0 },
- { "Courier New", 0, "Italic", 0 },
- };
-
-
- /* This is a CVT hack that makes thick horizontal stems on 2, 5, 7 */
- /* similar to Windows XP. */
-#define TIMES_NEW_ROMAN_HACK_RULES_SIZE 12
-
- static const SPH_TweakRule TIMES_NEW_ROMAN_HACK_Rules
- [TIMES_NEW_ROMAN_HACK_RULES_SIZE] =
- {
- { "Times New Roman", 16, "Italic", '2' },
- { "Times New Roman", 16, "Italic", '5' },
- { "Times New Roman", 16, "Italic", '7' },
- { "Times New Roman", 16, "Regular", '2' },
- { "Times New Roman", 16, "Regular", '5' },
- { "Times New Roman", 16, "Regular", '7' },
- { "Times New Roman", 17, "Italic", '2' },
- { "Times New Roman", 17, "Italic", '5' },
- { "Times New Roman", 17, "Italic", '7' },
- { "Times New Roman", 17, "Regular", '2' },
- { "Times New Roman", 17, "Regular", '5' },
- { "Times New Roman", 17, "Regular", '7' },
- };
-
-
- /* This fudges distance on 2 to get rid of the vanishing stem issue. */
- /* A real solution to this is certainly welcome. */
-#define COURIER_NEW_2_HACK_RULES_SIZE 15
-
- static const SPH_TweakRule COURIER_NEW_2_HACK_Rules
- [COURIER_NEW_2_HACK_RULES_SIZE] =
- {
- { "Courier New", 10, "Regular", '2' },
- { "Courier New", 11, "Regular", '2' },
- { "Courier New", 12, "Regular", '2' },
- { "Courier New", 13, "Regular", '2' },
- { "Courier New", 14, "Regular", '2' },
- { "Courier New", 15, "Regular", '2' },
- { "Courier New", 16, "Regular", '2' },
- { "Courier New", 17, "Regular", '2' },
- { "Courier New", 18, "Regular", '2' },
- { "Courier New", 19, "Regular", '2' },
- { "Courier New", 20, "Regular", '2' },
- { "Courier New", 21, "Regular", '2' },
- { "Courier New", 22, "Regular", '2' },
- { "Courier New", 23, "Regular", '2' },
- { "Courier New", 24, "Regular", '2' },
- };
-
-
-#ifndef FORCE_NATURAL_WIDTHS
-
- /* Use compatible widths with these glyphs. Compatible widths is always */
- /* on when doing B/W TrueType instructing, but is used selectively here, */
- /* typically on glyphs with 3 or more vertical stems. */
-#define COMPATIBLE_WIDTHS_RULES_SIZE 38
-
- static const SPH_TweakRule COMPATIBLE_WIDTHS_Rules
- [COMPATIBLE_WIDTHS_RULES_SIZE] =
- {
- { "Arial Unicode MS", 12, "Regular Class", 'm' },
- { "Arial Unicode MS", 14, "Regular Class", 'm' },
- /* Cyrillic small letter sha */
- { "Arial", 10, "Regular Class", 0x448 },
- { "Arial", 11, "Regular Class", 'm' },
- { "Arial", 12, "Regular Class", 'm' },
- /* Cyrillic small letter sha */
- { "Arial", 12, "Regular Class", 0x448 },
- { "Arial", 13, "Regular Class", 0x448 },
- { "Arial", 14, "Regular Class", 'm' },
- /* Cyrillic small letter sha */
- { "Arial", 14, "Regular Class", 0x448 },
- { "Arial", 15, "Regular Class", 0x448 },
- { "Arial", 17, "Regular Class", 'm' },
- { "DejaVu Sans", 15, "Regular Class", 0 },
- { "Microsoft Sans Serif", 11, "Regular Class", 0 },
- { "Microsoft Sans Serif", 12, "Regular Class", 0 },
- { "Segoe UI", 11, "Regular Class", 0 },
- { "Monaco", 0, "Regular Class", 0 },
- { "Segoe UI", 12, "Regular Class", 'm' },
- { "Segoe UI", 14, "Regular Class", 'm' },
- { "Tahoma", 11, "Regular Class", 0 },
- { "Times New Roman", 16, "Regular Class", 'c' },
- { "Times New Roman", 16, "Regular Class", 'm' },
- { "Times New Roman", 16, "Regular Class", 'o' },
- { "Times New Roman", 16, "Regular Class", 'w' },
- { "Trebuchet MS", 11, "Regular Class", 0 },
- { "Trebuchet MS", 12, "Regular Class", 0 },
- { "Trebuchet MS", 14, "Regular Class", 0 },
- { "Trebuchet MS", 15, "Regular Class", 0 },
- { "Ubuntu", 12, "Regular Class", 'm' },
- /* Cyrillic small letter sha */
- { "Verdana", 10, "Regular Class", 0x448 },
- { "Verdana", 11, "Regular Class", 0x448 },
- { "Verdana and Clones", 12, "Regular Class", 'i' },
- { "Verdana and Clones", 12, "Regular Class", 'j' },
- { "Verdana and Clones", 12, "Regular Class", 'l' },
- { "Verdana and Clones", 12, "Regular Class", 'm' },
- { "Verdana and Clones", 13, "Regular Class", 'i' },
- { "Verdana and Clones", 13, "Regular Class", 'j' },
- { "Verdana and Clones", 13, "Regular Class", 'l' },
- { "Verdana and Clones", 14, "Regular Class", 'm' },
- };
-
-
- /* Scaling slightly in the x-direction prior to hinting results in */
- /* more visually pleasing glyphs in certain cases. */
- /* This sometimes needs to be coordinated with compatible width rules. */
- /* A value of 1000 corresponds to a scaled value of 1.0. */
-
-#define X_SCALING_RULES_SIZE 50
-
- static const SPH_ScaleRule X_SCALING_Rules[X_SCALING_RULES_SIZE] =
- {
- { "DejaVu Sans", 12, "Regular Class", 'm', 950 },
- { "Verdana and Clones", 12, "Regular Class", 'a', 1100 },
- { "Verdana and Clones", 13, "Regular Class", 'a', 1050 },
- { "Arial", 11, "Regular Class", 'm', 975 },
- { "Arial", 12, "Regular Class", 'm', 1050 },
- /* Cyrillic small letter el */
- { "Arial", 13, "Regular Class", 0x43B, 950 },
- { "Arial", 13, "Regular Class", 'o', 950 },
- { "Arial", 13, "Regular Class", 'e', 950 },
- { "Arial", 14, "Regular Class", 'm', 950 },
- /* Cyrillic small letter el */
- { "Arial", 15, "Regular Class", 0x43B, 925 },
- { "Bitstream Vera Sans", 10, "Regular/Italic Class", 0, 1100 },
- { "Bitstream Vera Sans", 12, "Regular/Italic Class", 0, 1050 },
- { "Bitstream Vera Sans", 16, "Regular Class", 0, 1050 },
- { "Bitstream Vera Sans", 9, "Regular/Italic Class", 0, 1050 },
- { "DejaVu Sans", 12, "Regular Class", 'l', 975 },
- { "DejaVu Sans", 12, "Regular Class", 'i', 975 },
- { "DejaVu Sans", 12, "Regular Class", 'j', 975 },
- { "DejaVu Sans", 13, "Regular Class", 'l', 950 },
- { "DejaVu Sans", 13, "Regular Class", 'i', 950 },
- { "DejaVu Sans", 13, "Regular Class", 'j', 950 },
- { "DejaVu Sans", 10, "Regular/Italic Class", 0, 1100 },
- { "DejaVu Sans", 12, "Regular/Italic Class", 0, 1050 },
- { "Georgia", 10, "", 0, 1050 },
- { "Georgia", 11, "", 0, 1100 },
- { "Georgia", 12, "", 0, 1025 },
- { "Georgia", 13, "", 0, 1050 },
- { "Georgia", 16, "", 0, 1050 },
- { "Georgia", 17, "", 0, 1030 },
- { "Liberation Sans", 12, "Regular Class", 'm', 1100 },
- { "Lucida Grande", 11, "Regular Class", 'm', 1100 },
- { "Microsoft Sans Serif", 11, "Regular Class", 'm', 950 },
- { "Microsoft Sans Serif", 12, "Regular Class", 'm', 1050 },
- { "Segoe UI", 12, "Regular Class", 'H', 1050 },
- { "Segoe UI", 12, "Regular Class", 'm', 1050 },
- { "Segoe UI", 14, "Regular Class", 'm', 1050 },
- { "Tahoma", 11, "Regular Class", 'i', 975 },
- { "Tahoma", 11, "Regular Class", 'l', 975 },
- { "Tahoma", 11, "Regular Class", 'j', 900 },
- { "Tahoma", 11, "Regular Class", 'm', 918 },
- { "Verdana", 10, "Regular/Italic Class", 0, 1100 },
- { "Verdana", 12, "Regular Class", 'm', 975 },
- { "Verdana", 12, "Regular/Italic Class", 0, 1050 },
- { "Verdana", 13, "Regular/Italic Class", 'i', 950 },
- { "Verdana", 13, "Regular/Italic Class", 'j', 950 },
- { "Verdana", 13, "Regular/Italic Class", 'l', 950 },
- { "Verdana", 16, "Regular Class", 0, 1050 },
- { "Verdana", 9, "Regular/Italic Class", 0, 1050 },
- { "Times New Roman", 16, "Regular Class", 'm', 918 },
- { "Trebuchet MS", 11, "Regular Class", 'm', 800 },
- { "Trebuchet MS", 12, "Regular Class", 'm', 800 },
- };
-
-#else
-
-#define COMPATIBLE_WIDTHS_RULES_SIZE 1
-
- static const SPH_TweakRule COMPATIBLE_WIDTHS_Rules
- [COMPATIBLE_WIDTHS_RULES_SIZE] =
- {
- { "-", 0, "", 0 },
- };
-
-
-#define X_SCALING_RULES_SIZE 1
-
- static const SPH_ScaleRule X_SCALING_Rules
- [X_SCALING_RULES_SIZE] =
- {
- { "-", 0, "", 0, 1000 },
- };
-
-#endif /* FORCE_NATURAL_WIDTHS */
-
-
- static FT_Bool
- is_member_of_family_class( const FT_String* detected_font_name,
- const FT_String* rule_font_name )
- {
- FT_UInt i, j;
-
-
- /* Does font name match rule family? */
- if ( ft_strcmp( detected_font_name, rule_font_name ) == 0 )
- return TRUE;
-
- /* Is font name a wildcard ""? */
- if ( ft_strcmp( rule_font_name, "" ) == 0 )
- return TRUE;
-
- /* Is font name contained in a class list? */
- for ( i = 0; i < FAMILY_CLASS_RULES_SIZE; i++ )
- {
- if ( ft_strcmp( FAMILY_CLASS_Rules[i].name, rule_font_name ) == 0 )
- {
- for ( j = 0; j < SPH_MAX_CLASS_MEMBERS; j++ )
- {
- if ( ft_strcmp( FAMILY_CLASS_Rules[i].member[j], "" ) == 0 )
- continue;
- if ( ft_strcmp( FAMILY_CLASS_Rules[i].member[j],
- detected_font_name ) == 0 )
- return TRUE;
- }
- }
- }
-
- return FALSE;
- }
-
-
- static FT_Bool
- is_member_of_style_class( const FT_String* detected_font_style,
- const FT_String* rule_font_style )
- {
- FT_UInt i, j;
-
-
- /* Does font style match rule style? */
- if ( ft_strcmp( detected_font_style, rule_font_style ) == 0 )
- return TRUE;
-
- /* Is font style a wildcard ""? */
- if ( ft_strcmp( rule_font_style, "" ) == 0 )
- return TRUE;
-
- /* Is font style contained in a class list? */
- for ( i = 0; i < STYLE_CLASS_RULES_SIZE; i++ )
- {
- if ( ft_strcmp( STYLE_CLASS_Rules[i].name, rule_font_style ) == 0 )
- {
- for ( j = 0; j < SPH_MAX_CLASS_MEMBERS; j++ )
- {
- if ( ft_strcmp( STYLE_CLASS_Rules[i].member[j], "" ) == 0 )
- continue;
- if ( ft_strcmp( STYLE_CLASS_Rules[i].member[j],
- detected_font_style ) == 0 )
- return TRUE;
- }
- }
- }
-
- return FALSE;
- }
-
-
- FT_LOCAL_DEF( FT_Bool )
- sph_test_tweak( TT_Face face,
- const FT_String* family,
- FT_UInt ppem,
- const FT_String* style,
- FT_UInt glyph_index,
- const SPH_TweakRule* rule,
- FT_UInt num_rules )
- {
- FT_UInt i;
-
-
- /* rule checks may be able to be optimized further */
- for ( i = 0; i < num_rules; i++ )
- {
- if ( family &&
- ( is_member_of_family_class ( family, rule[i].family ) ) )
- if ( rule[i].ppem == 0 ||
- rule[i].ppem == ppem )
- if ( style &&
- is_member_of_style_class ( style, rule[i].style ) )
- if ( rule[i].glyph == 0 ||
- FT_Get_Char_Index( (FT_Face)face,
- rule[i].glyph ) == glyph_index )
- return TRUE;
- }
-
- return FALSE;
- }
-
-
- static FT_UInt
- scale_test_tweak( TT_Face face,
- const FT_String* family,
- FT_UInt ppem,
- const FT_String* style,
- FT_UInt glyph_index,
- const SPH_ScaleRule* rule,
- FT_UInt num_rules )
- {
- FT_UInt i;
-
-
- /* rule checks may be able to be optimized further */
- for ( i = 0; i < num_rules; i++ )
- {
- if ( family &&
- ( is_member_of_family_class ( family, rule[i].family ) ) )
- if ( rule[i].ppem == 0 ||
- rule[i].ppem == ppem )
- if ( style &&
- is_member_of_style_class( style, rule[i].style ) )
- if ( rule[i].glyph == 0 ||
- FT_Get_Char_Index( (FT_Face)face,
- rule[i].glyph ) == glyph_index )
- return rule[i].scale;
- }
-
- return 1000;
- }
-
-
- FT_LOCAL_DEF( FT_UInt )
- sph_test_tweak_x_scaling( TT_Face face,
- const FT_String* family,
- FT_UInt ppem,
- const FT_String* style,
- FT_UInt glyph_index )
- {
- return scale_test_tweak( face, family, ppem, style, glyph_index,
- X_SCALING_Rules, X_SCALING_RULES_SIZE );
- }
-
-
-#define TWEAK_RULES( x ) \
- if ( sph_test_tweak( face, family, ppem, style, glyph_index, \
- x##_Rules, x##_RULES_SIZE ) ) \
- loader->exec->sph_tweak_flags |= SPH_TWEAK_##x
-
-#define TWEAK_RULES_EXCEPTIONS( x ) \
- if ( sph_test_tweak( face, family, ppem, style, glyph_index, \
- x##_Rules_Exceptions, x##_RULES_EXCEPTIONS_SIZE ) ) \
- loader->exec->sph_tweak_flags &= ~SPH_TWEAK_##x
-
-
- FT_LOCAL_DEF( void )
- sph_set_tweaks( TT_Loader loader,
- FT_UInt glyph_index )
- {
- TT_Face face = loader->face;
- FT_String* family = face->root.family_name;
- FT_UInt ppem = loader->size->metrics->x_ppem;
- FT_String* style = face->root.style_name;
-
-
- /* don't apply rules if style isn't set */
- if ( !face->root.style_name )
- return;
-
-#ifdef SPH_DEBUG_MORE_VERBOSE
- printf( "%s,%d,%s,%c=%d ",
- family, ppem, style, glyph_index, glyph_index );
-#endif
-
- TWEAK_RULES( PIXEL_HINTING );
-
- if ( loader->exec->sph_tweak_flags & SPH_TWEAK_PIXEL_HINTING )
- {
- loader->exec->ignore_x_mode = FALSE;
- return;
- }
-
- TWEAK_RULES( ALLOW_X_DMOVE );
- TWEAK_RULES( ALWAYS_DO_DELTAP );
- TWEAK_RULES( ALWAYS_SKIP_DELTAP );
- TWEAK_RULES( DEEMBOLDEN );
- TWEAK_RULES( DO_SHPIX );
- TWEAK_RULES( EMBOLDEN );
- TWEAK_RULES( MIAP_HACK );
- TWEAK_RULES( NORMAL_ROUND );
- TWEAK_RULES( NO_ALIGNRP_AFTER_IUP );
- TWEAK_RULES( NO_CALL_AFTER_IUP );
- TWEAK_RULES( NO_DELTAP_AFTER_IUP );
- TWEAK_RULES( RASTERIZER_35 );
- TWEAK_RULES( SKIP_IUP );
-
- TWEAK_RULES( SKIP_OFFPIXEL_Y_MOVES );
- TWEAK_RULES_EXCEPTIONS( SKIP_OFFPIXEL_Y_MOVES );
-
- TWEAK_RULES( SKIP_NONPIXEL_Y_MOVES_DELTAP );
-
- TWEAK_RULES( SKIP_NONPIXEL_Y_MOVES );
- TWEAK_RULES_EXCEPTIONS( SKIP_NONPIXEL_Y_MOVES );
-
- TWEAK_RULES( ROUND_NONPIXEL_Y_MOVES );
- TWEAK_RULES_EXCEPTIONS( ROUND_NONPIXEL_Y_MOVES );
-
- if ( loader->exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 )
- {
- if ( loader->exec->rasterizer_version != TT_INTERPRETER_VERSION_35 )
- {
- loader->exec->rasterizer_version = TT_INTERPRETER_VERSION_35;
- loader->exec->size->cvt_ready = -1;
-
- tt_size_ready_bytecode(
- loader->exec->size,
- FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) );
- }
- else
- loader->exec->rasterizer_version = TT_INTERPRETER_VERSION_35;
- }
- else
- {
- if ( loader->exec->rasterizer_version !=
- SPH_OPTION_SET_RASTERIZER_VERSION )
- {
- loader->exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION;
- loader->exec->size->cvt_ready = -1;
-
- tt_size_ready_bytecode(
- loader->exec->size,
- FT_BOOL( loader->load_flags & FT_LOAD_PEDANTIC ) );
- }
- else
- loader->exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION;
- }
-
- if ( IS_HINTED( loader->load_flags ) )
- {
- TWEAK_RULES( TIMES_NEW_ROMAN_HACK );
- TWEAK_RULES( COURIER_NEW_2_HACK );
- }
-
- if ( sph_test_tweak( face, family, ppem, style, glyph_index,
- COMPATIBILITY_MODE_Rules, COMPATIBILITY_MODE_RULES_SIZE ) )
- loader->exec->face->sph_compatibility_mode = TRUE;
-
-
- if ( IS_HINTED( loader->load_flags ) )
- {
- if ( sph_test_tweak( face, family, ppem, style, glyph_index,
- COMPATIBLE_WIDTHS_Rules, COMPATIBLE_WIDTHS_RULES_SIZE ) )
- loader->exec->compatible_widths |= TRUE;
- }
- }
-
-#else /* !(TT_USE_BYTECODE_INTERPRETER && */
- /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY) */
-
- /* ANSI C doesn't like empty source files */
- typedef int _tt_subpix_dummy;
-
-#endif /* !(TT_USE_BYTECODE_INTERPRETER && */
- /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY) */
-
-
-/* END */
diff --git a/src/3rdparty/freetype/src/truetype/ttsubpix.h b/src/3rdparty/freetype/src/truetype/ttsubpix.h
deleted file mode 100644
index 62af4c272d..0000000000
--- a/src/3rdparty/freetype/src/truetype/ttsubpix.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/****************************************************************************
- *
- * ttsubpix.h
- *
- * TrueType Subpixel Hinting.
- *
- * Copyright (C) 2010-2023 by
- * David Turner, Robert Wilhelm, and Werner Lemberg.
- *
- * This file is part of the FreeType project, and may only be used,
- * modified, and distributed under the terms of the FreeType project
- * license, LICENSE.TXT. By continuing to use, modify, or distribute
- * this file you indicate that you have read the license and
- * understand and accept it fully.
- *
- */
-
-
-#ifndef TTSUBPIX_H_
-#define TTSUBPIX_H_
-
-#include "ttobjs.h"
-#include "ttinterp.h"
-
-
-FT_BEGIN_HEADER
-
-
-#ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
-
- /**************************************************************************
- *
- * ID flags to identify special functions at FDEF and runtime.
- *
- */
-#define SPH_FDEF_INLINE_DELTA_1 0x0000001
-#define SPH_FDEF_INLINE_DELTA_2 0x0000002
-#define SPH_FDEF_DIAGONAL_STROKE 0x0000004
-#define SPH_FDEF_VACUFORM_ROUND_1 0x0000008
-#define SPH_FDEF_TTFAUTOHINT_1 0x0000010
-#define SPH_FDEF_SPACING_1 0x0000020
-#define SPH_FDEF_SPACING_2 0x0000040
-#define SPH_FDEF_TYPEMAN_STROKES 0x0000080
-#define SPH_FDEF_TYPEMAN_DIAGENDCTRL 0x0000100
-
-
- /**************************************************************************
- *
- * Tweak flags that are set for each glyph by the below rules.
- *
- */
-#define SPH_TWEAK_ALLOW_X_DMOVE 0x0000001UL
-#define SPH_TWEAK_ALWAYS_DO_DELTAP 0x0000002UL
-#define SPH_TWEAK_ALWAYS_SKIP_DELTAP 0x0000004UL
-#define SPH_TWEAK_COURIER_NEW_2_HACK 0x0000008UL
-#define SPH_TWEAK_DEEMBOLDEN 0x0000010UL
-#define SPH_TWEAK_DO_SHPIX 0x0000020UL
-#define SPH_TWEAK_EMBOLDEN 0x0000040UL
-#define SPH_TWEAK_MIAP_HACK 0x0000080UL
-#define SPH_TWEAK_NORMAL_ROUND 0x0000100UL
-#define SPH_TWEAK_NO_ALIGNRP_AFTER_IUP 0x0000200UL
-#define SPH_TWEAK_NO_CALL_AFTER_IUP 0x0000400UL
-#define SPH_TWEAK_NO_DELTAP_AFTER_IUP 0x0000800UL
-#define SPH_TWEAK_PIXEL_HINTING 0x0001000UL
-#define SPH_TWEAK_RASTERIZER_35 0x0002000UL
-#define SPH_TWEAK_ROUND_NONPIXEL_Y_MOVES 0x0004000UL
-#define SPH_TWEAK_SKIP_IUP 0x0008000UL
-#define SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES 0x0010000UL
-#define SPH_TWEAK_SKIP_OFFPIXEL_Y_MOVES 0x0020000UL
-#define SPH_TWEAK_TIMES_NEW_ROMAN_HACK 0x0040000UL
-#define SPH_TWEAK_SKIP_NONPIXEL_Y_MOVES_DELTAP 0x0080000UL
-
-
- FT_LOCAL( FT_Bool )
- sph_test_tweak( TT_Face face,
- const FT_String* family,
- FT_UInt ppem,
- const FT_String* style,
- FT_UInt glyph_index,
- const SPH_TweakRule* rule,
- FT_UInt num_rules );
-
- FT_LOCAL( FT_UInt )
- sph_test_tweak_x_scaling( TT_Face face,
- const FT_String* family,
- FT_UInt ppem,
- const FT_String* style,
- FT_UInt glyph_index );
-
- FT_LOCAL( void )
- sph_set_tweaks( TT_Loader loader,
- FT_UInt glyph_index );
-
-
- /* These macros are defined absent a method for setting them */
-#define SPH_OPTION_BITMAP_WIDTHS FALSE
-#define SPH_OPTION_SET_SUBPIXEL TRUE
-#define SPH_OPTION_SET_GRAYSCALE FALSE
-#define SPH_OPTION_SET_COMPATIBLE_WIDTHS FALSE
-#define SPH_OPTION_SET_RASTERIZER_VERSION 38
-
-#endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
-
-
-FT_END_HEADER
-
-#endif /* TTSUBPIX_H_ */
-
-
-/* END */
diff --git a/src/3rdparty/freetype/src/type1/t1afm.c b/src/3rdparty/freetype/src/type1/t1afm.c
index 787aa92c98..d9b9398b01 100644
--- a/src/3rdparty/freetype/src/type1/t1afm.c
+++ b/src/3rdparty/freetype/src/type1/t1afm.c
@@ -299,7 +299,7 @@
/* ascender and descender are optional and could both be zero */
/* check if values are meaningful before overriding defaults */
if ( fi->Ascender > fi->Descender )
- {
+ {
/* no `U' suffix here to 0x8000! */
t1_face->ascender = (FT_Short)( ( fi->Ascender + 0x8000 ) >> 16 );
t1_face->descender = (FT_Short)( ( fi->Descender + 0x8000 ) >> 16 );
@@ -405,7 +405,7 @@
#else /* T1_CONFIG_OPTION_NO_AFM */
/* ANSI C doesn't like empty source files */
- typedef int _t1_afm_dummy;
+ typedef int t1_afm_dummy_;
#endif /* T1_CONFIG_OPTION_NO_AFM */
diff --git a/src/3rdparty/freetype/src/type1/t1driver.c b/src/3rdparty/freetype/src/type1/t1driver.c
index ded3b264e8..a4cdf372a9 100644
--- a/src/3rdparty/freetype/src/type1/t1driver.c
+++ b/src/3rdparty/freetype/src/type1/t1driver.c
@@ -56,28 +56,32 @@
*
*/
- static FT_Error
- t1_get_glyph_name( T1_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ t1_get_glyph_name( FT_Face face, /* T1_Face */
FT_UInt glyph_index,
FT_Pointer buffer,
FT_UInt buffer_max )
{
- FT_STRCPYN( buffer, face->type1.glyph_names[glyph_index], buffer_max );
+ T1_Face t1face = (T1_Face)face;
+
+
+ FT_STRCPYN( buffer, t1face->type1.glyph_names[glyph_index], buffer_max );
return FT_Err_Ok;
}
- static FT_UInt
- t1_get_name_index( T1_Face face,
+ FT_CALLBACK_DEF( FT_UInt )
+ t1_get_name_index( FT_Face face, /* T1_Face */
const FT_String* glyph_name )
{
- FT_Int i;
+ T1_Face t1face = (T1_Face)face;
+ FT_Int i;
- for ( i = 0; i < face->type1.num_glyphs; i++ )
+ for ( i = 0; i < t1face->type1.num_glyphs; i++ )
{
- FT_String* gname = face->type1.glyph_names[i];
+ FT_String* gname = t1face->type1.glyph_names[i];
if ( !ft_strcmp( glyph_name, gname ) )
@@ -90,8 +94,8 @@
static const FT_Service_GlyphDictRec t1_service_glyph_dict =
{
- (FT_GlyphDict_GetNameFunc) t1_get_glyph_name, /* get_name */
- (FT_GlyphDict_NameIndexFunc)t1_get_name_index /* name_index */
+ t1_get_glyph_name, /* FT_GlyphDict_GetNameFunc get_name */
+ t1_get_name_index /* FT_GlyphDict_NameIndexFunc name_index */
};
@@ -101,9 +105,12 @@
*/
static const char*
- t1_get_ps_name( T1_Face face )
+ t1_get_ps_name( FT_Face face ) /* T1_Face */
{
- return (const char*) face->type1.font_name;
+ T1_Face t1face = (T1_Face)face;
+
+
+ return (const char*) t1face->type1.font_name;
}
@@ -121,30 +128,28 @@
#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
static const FT_Service_MultiMastersRec t1_service_multi_masters =
{
- (FT_Get_MM_Func) T1_Get_Multi_Master, /* get_mm */
- (FT_Set_MM_Design_Func) T1_Set_MM_Design, /* set_mm_design */
- (FT_Set_MM_Blend_Func) T1_Set_MM_Blend, /* set_mm_blend */
- (FT_Get_MM_Blend_Func) T1_Get_MM_Blend, /* get_mm_blend */
- (FT_Get_MM_Var_Func) T1_Get_MM_Var, /* get_mm_var */
- (FT_Set_Var_Design_Func)T1_Set_Var_Design, /* set_var_design */
- (FT_Get_Var_Design_Func)T1_Get_Var_Design, /* get_var_design */
- (FT_Set_Instance_Func) T1_Reset_MM_Blend, /* set_instance */
- (FT_Set_MM_WeightVector_Func)
- T1_Set_MM_WeightVector, /* set_mm_weightvector */
- (FT_Get_MM_WeightVector_Func)
- T1_Get_MM_WeightVector, /* get_mm_weightvector */
- (FT_Var_Load_Delta_Set_Idx_Map_Func)
- NULL, /* load_delta_set_idx_map */
- (FT_Var_Load_Item_Var_Store_Func)
- NULL, /* load_item_variation_store */
- (FT_Var_Get_Item_Delta_Func)
- NULL, /* get_item_delta */
- (FT_Var_Done_Item_Var_Store_Func)
- NULL, /* done_item_variation_store */
- (FT_Var_Done_Delta_Set_Idx_Map_Func)
- NULL, /* done_delta_set_index_map */
- (FT_Get_Var_Blend_Func) NULL, /* get_var_blend */
- (FT_Done_Blend_Func) T1_Done_Blend /* done_blend */
+ T1_Get_Multi_Master, /* FT_Get_MM_Func get_mm */
+ T1_Set_MM_Design, /* FT_Set_MM_Design_Func set_mm_design */
+ T1_Set_MM_Blend, /* FT_Set_MM_Blend_Func set_mm_blend */
+ T1_Get_MM_Blend, /* FT_Get_MM_Blend_Func get_mm_blend */
+ T1_Get_MM_Var, /* FT_Get_MM_Var_Func get_mm_var */
+ T1_Set_Var_Design, /* FT_Set_Var_Design_Func set_var_design */
+ T1_Get_Var_Design, /* FT_Get_Var_Design_Func get_var_design */
+ T1_Reset_MM_Blend, /* FT_Set_Named_Instance_Func set_named_instance */
+ NULL, /* FT_Get_Default_Named_Instance_Func get_default_named_instance */
+ T1_Set_MM_WeightVector,
+ /* FT_Set_MM_WeightVector_Func set_mm_weightvector */
+ T1_Get_MM_WeightVector,
+ /* FT_Get_MM_WeightVector_Func get_mm_weightvector */
+
+ NULL, /* FT_Construct_PS_Name_Func construct_ps_name */
+ NULL, /* FT_Var_Load_Delta_Set_Idx_Map_Func load_delta_set_idx_map */
+ NULL, /* FT_Var_Load_Item_Var_Store_Func load_item_variation_store */
+ NULL, /* FT_Var_Get_Item_Delta_Func get_item_delta */
+ NULL, /* FT_Var_Done_Item_Var_Store_Func done_item_variation_store */
+ NULL, /* FT_Var_Done_Delta_Set_Idx_Map_Func done_delta_set_index_map */
+ NULL, /* FT_Get_Var_Blend_Func get_var_blend */
+ T1_Done_Blend /* FT_Done_Blend_Func done_blend */
};
#endif
@@ -632,11 +637,11 @@
static const FT_Service_PsInfoRec t1_service_ps_info =
{
- (PS_GetFontInfoFunc) t1_ps_get_font_info, /* ps_get_font_info */
- (PS_GetFontExtraFunc) t1_ps_get_font_extra, /* ps_get_font_extra */
- (PS_HasGlyphNamesFunc) t1_ps_has_glyph_names, /* ps_has_glyph_names */
- (PS_GetFontPrivateFunc)t1_ps_get_font_private, /* ps_get_font_private */
- (PS_GetFontValueFunc) t1_ps_get_font_value, /* ps_get_font_value */
+ t1_ps_get_font_info, /* PS_GetFontInfoFunc ps_get_font_info */
+ t1_ps_get_font_extra, /* PS_GetFontExtraFunc ps_get_font_extra */
+ t1_ps_has_glyph_names, /* PS_HasGlyphNamesFunc ps_has_glyph_names */
+ t1_ps_get_font_private, /* PS_GetFontPrivateFunc ps_get_font_private */
+ t1_ps_get_font_value, /* PS_GetFontValueFunc ps_get_font_value */
};
@@ -656,9 +661,9 @@
FT_DEFINE_SERVICE_PROPERTIESREC(
t1_service_properties,
- (FT_Properties_SetFunc)ps_property_set, /* set_property */
- (FT_Properties_GetFunc)ps_property_get ) /* get_property */
-
+ ps_property_set, /* FT_Properties_SetFunc set_property */
+ ps_property_get /* FT_Properties_GetFunc get_property */
+ )
/*
* SERVICE LIST
diff --git a/src/3rdparty/freetype/src/type1/t1load.c b/src/3rdparty/freetype/src/type1/t1load.c
index 5a1afd8d9f..be7cd0fd5e 100644
--- a/src/3rdparty/freetype/src/type1/t1load.c
+++ b/src/3rdparty/freetype/src/type1/t1load.c
@@ -73,7 +73,8 @@
#ifdef FT_CONFIG_OPTION_INCREMENTAL
-#define IS_INCREMENTAL FT_BOOL( face->root.internal->incremental_interface )
+#define IS_INCREMENTAL \
+ FT_BOOL( FT_FACE( face )->internal->incremental_interface )
#else
#define IS_INCREMENTAL 0
#endif
@@ -174,10 +175,11 @@
FT_LOCAL_DEF( FT_Error )
- T1_Get_Multi_Master( T1_Face face,
+ T1_Get_Multi_Master( FT_Face face, /* T1_Face */
FT_Multi_Master* master )
{
- PS_Blend blend = face->blend;
+ T1_Face t1face = (T1_Face)face;
+ PS_Blend blend = t1face->blend;
FT_UInt n;
FT_Error error;
@@ -225,11 +227,12 @@
for ( j = 1; j < axismap->num_points; j++ )
{
if ( ncv <= axismap->blend_points[j] )
- return INT_TO_FIXED( axismap->design_points[j - 1] ) +
- ( axismap->design_points[j] - axismap->design_points[j - 1] ) *
- FT_DivFix( ncv - axismap->blend_points[j - 1],
- axismap->blend_points[j] -
- axismap->blend_points[j - 1] );
+ return INT_TO_FIXED( axismap->design_points[j - 1] +
+ FT_MulDiv( ncv - axismap->blend_points[j - 1],
+ axismap->design_points[j] -
+ axismap->design_points[j - 1],
+ axismap->blend_points[j] -
+ axismap->blend_points[j - 1] ) );
}
return INT_TO_FIXED( axismap->design_points[axismap->num_points - 1] );
@@ -284,16 +287,17 @@
* arguments needed by the GX var distortable fonts.
*/
FT_LOCAL_DEF( FT_Error )
- T1_Get_MM_Var( T1_Face face,
+ T1_Get_MM_Var( FT_Face face, /* T1_Face */
FT_MM_Var* *master )
{
- FT_Memory memory = face->root.memory;
- FT_MM_Var *mmvar = NULL;
+ T1_Face t1face = (T1_Face)face;
+ FT_Memory memory = FT_FACE_MEMORY( face );
+ FT_MM_Var *mmvar = NULL;
FT_Multi_Master mmaster;
FT_Error error;
FT_UInt i;
FT_Fixed axiscoords[T1_MAX_MM_AXIS];
- PS_Blend blend = face->blend;
+ PS_Blend blend = t1face->blend;
FT_UShort* axis_flags;
FT_Offset mmvar_size;
@@ -319,9 +323,9 @@
sizeof ( FT_UShort ) );
axis_size = mmaster.num_axis * sizeof ( FT_Var_Axis );
- if ( FT_ALLOC( mmvar, mmvar_size +
- axis_flags_size +
- axis_size ) )
+ if ( FT_QALLOC( mmvar, mmvar_size +
+ axis_flags_size +
+ axis_size ) )
goto Exit;
mmvar->num_axis = mmaster.num_axis;
@@ -332,8 +336,7 @@
/* to make `FT_Get_Var_Axis_Flags' work: the function expects that the */
/* values directly follow the data of `FT_MM_Var' */
axis_flags = (FT_UShort*)( (char*)mmvar + mmvar_size );
- for ( i = 0; i < mmaster.num_axis; i++ )
- axis_flags[i] = 0;
+ FT_ARRAY_ZERO( axis_flags, mmaster.num_axis );
mmvar->axis = (FT_Var_Axis*)( (char*)axis_flags + axis_flags_size );
mmvar->namedstyle = NULL;
@@ -438,32 +441,21 @@
FT_LOCAL_DEF( FT_Error )
- T1_Set_MM_Blend( T1_Face face,
+ T1_Set_MM_Blend( FT_Face face, /* T1_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
- FT_Error error;
-
-
- error = t1_set_mm_blend( face, num_coords, coords );
- if ( error )
- return error;
-
- if ( num_coords )
- face->root.face_flags |= FT_FACE_FLAG_VARIATION;
- else
- face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
-
- return FT_Err_Ok;
+ return t1_set_mm_blend( (T1_Face)face, num_coords, coords );
}
FT_LOCAL_DEF( FT_Error )
- T1_Get_MM_Blend( T1_Face face,
+ T1_Get_MM_Blend( FT_Face face, /* T1_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
- PS_Blend blend = face->blend;
+ T1_Face t1face = (T1_Face)face;
+ PS_Blend blend = t1face->blend;
FT_Fixed axiscoords[4];
FT_UInt i, nc;
@@ -494,11 +486,12 @@
FT_LOCAL_DEF( FT_Error )
- T1_Set_MM_WeightVector( T1_Face face,
+ T1_Set_MM_WeightVector( FT_Face face, /* T1_Face */
FT_UInt len,
FT_Fixed* weightvector )
{
- PS_Blend blend = face->blend;
+ T1_Face t1face = (T1_Face)face;
+ PS_Blend blend = t1face->blend;
FT_UInt i, n;
@@ -522,11 +515,6 @@
for ( ; i < blend->num_designs; i++ )
blend->weight_vector[i] = (FT_Fixed)0;
-
- if ( len )
- face->root.face_flags |= FT_FACE_FLAG_VARIATION;
- else
- face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
}
return FT_Err_Ok;
@@ -534,11 +522,12 @@
FT_LOCAL_DEF( FT_Error )
- T1_Get_MM_WeightVector( T1_Face face,
+ T1_Get_MM_WeightVector( FT_Face face, /* T1_Face */
FT_UInt* len,
FT_Fixed* weightvector )
{
- PS_Blend blend = face->blend;
+ T1_Face t1face = (T1_Face)face;
+ PS_Blend blend = t1face->blend;
FT_UInt i;
@@ -563,12 +552,13 @@
FT_LOCAL_DEF( FT_Error )
- T1_Set_MM_Design( T1_Face face,
+ T1_Set_MM_Design( FT_Face face, /* T1_Face */
FT_UInt num_coords,
FT_Long* coords )
{
+ T1_Face t1face = (T1_Face)face;
FT_Error error;
- PS_Blend blend = face->blend;
+ PS_Blend blend = t1face->blend;
FT_UInt n;
FT_Fixed final_blends[T1_MAX_MM_DESIGNS];
@@ -634,15 +624,10 @@
final_blends[n] = the_blend;
}
- error = t1_set_mm_blend( face, blend->num_axis, final_blends );
+ error = t1_set_mm_blend( t1face, blend->num_axis, final_blends );
if ( error )
return error;
- if ( num_coords )
- face->root.face_flags |= FT_FACE_FLAG_VARIATION;
- else
- face->root.face_flags &= ~FT_FACE_FLAG_VARIATION;
-
return FT_Err_Ok;
}
@@ -650,7 +635,7 @@
/* MM fonts don't have named instances, so only the design is reset */
FT_LOCAL_DEF( FT_Error )
- T1_Reset_MM_Blend( T1_Face face,
+ T1_Reset_MM_Blend( FT_Face face,
FT_UInt instance_index )
{
FT_UNUSED( instance_index );
@@ -665,7 +650,7 @@
* arguments needed by the GX var distortable fonts.
*/
FT_LOCAL_DEF( FT_Error )
- T1_Set_Var_Design( T1_Face face,
+ T1_Set_Var_Design( FT_Face face, /* T1_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
@@ -684,11 +669,12 @@
FT_LOCAL_DEF( FT_Error )
- T1_Get_Var_Design( T1_Face face,
+ T1_Get_Var_Design( FT_Face face, /* T1_Face */
FT_UInt num_coords,
FT_Fixed* coords )
{
- PS_Blend blend = face->blend;
+ T1_Face t1face = (T1_Face)face;
+ PS_Blend blend = t1face->blend;
FT_Fixed axiscoords[4];
FT_UInt i, nc;
@@ -720,10 +706,11 @@
FT_LOCAL_DEF( void )
- T1_Done_Blend( T1_Face face )
+ T1_Done_Blend( FT_Face face ) /* T1_Face */
{
- FT_Memory memory = face->root.memory;
- PS_Blend blend = face->blend;
+ T1_Face t1face = (T1_Face)face;
+ FT_Memory memory = FT_FACE_MEMORY( face );
+ PS_Blend blend = t1face->blend;
if ( blend )
@@ -768,20 +755,22 @@
dmap->num_points = 0;
}
- FT_FREE( face->blend );
+ FT_FREE( t1face->blend );
}
}
static void
- parse_blend_axis_types( T1_Face face,
- T1_Loader loader )
+ parse_blend_axis_types( FT_Face face, /* T1_Face */
+ void* loader_ )
{
+ T1_Face t1face = (T1_Face)face;
+ T1_Loader loader = (T1_Loader)loader_;
T1_TokenRec axis_tokens[T1_MAX_MM_AXIS];
FT_Int n, num_axis;
- FT_Error error = FT_Err_Ok;
+ FT_Error error = FT_Err_Ok;
PS_Blend blend;
- FT_Memory memory;
+ FT_Memory memory = FT_FACE_MEMORY( face );
/* take an array of objects */
@@ -801,14 +790,13 @@
}
/* allocate blend if necessary */
- error = t1_allocate_blend( face, 0, (FT_UInt)num_axis );
+ error = t1_allocate_blend( t1face, 0, (FT_UInt)num_axis );
if ( error )
goto Exit;
FT_TRACE4(( " [" ));
- blend = face->blend;
- memory = face->root.memory;
+ blend = t1face->blend;
/* each token is an immediate containing the name of the axis */
for ( n = 0; n < num_axis; n++ )
@@ -856,14 +844,16 @@
static void
- parse_blend_design_positions( T1_Face face,
- T1_Loader loader )
+ parse_blend_design_positions( FT_Face face, /* T1_Face */
+ void* loader_ )
{
+ T1_Face t1face = (T1_Face)face;
+ T1_Loader loader = (T1_Loader)loader_;
T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS];
FT_Int num_designs;
FT_Int num_axis = 0; /* make compiler happy */
T1_Parser parser = &loader->parser;
- FT_Memory memory = face->root.memory;
+ FT_Memory memory = FT_FACE_MEMORY( face );
FT_Error error = FT_Err_Ok;
FT_Fixed* design_pos[T1_MAX_MM_DESIGNS];
@@ -921,7 +911,7 @@
}
num_axis = n_axis;
- error = t1_allocate_blend( face,
+ error = t1_allocate_blend( t1face,
(FT_UInt)num_designs,
(FT_UInt)num_axis );
if ( error )
@@ -962,7 +952,7 @@
loader->parser.root.limit = old_limit;
/* a valid BlendDesignPosition has been parsed */
- blend = face->blend;
+ blend = t1face->blend;
if ( blend->design_pos[0] )
FT_FREE( blend->design_pos[0] );
@@ -980,9 +970,11 @@
static void
- parse_blend_design_map( T1_Face face,
- T1_Loader loader )
+ parse_blend_design_map( FT_Face face, /* T1_Face */
+ void* loader_ )
{
+ T1_Face t1face = (T1_Face)face;
+ T1_Loader loader = (T1_Loader)loader_;
FT_Error error = FT_Err_Ok;
T1_Parser parser = &loader->parser;
PS_Blend blend;
@@ -990,7 +982,7 @@
FT_Int n, num_axis;
FT_Byte* old_cursor;
FT_Byte* old_limit;
- FT_Memory memory = face->root.memory;
+ FT_Memory memory = FT_FACE_MEMORY( face );
T1_ToTokenArray( parser, axis_tokens,
@@ -1011,10 +1003,10 @@
old_cursor = parser->root.cursor;
old_limit = parser->root.limit;
- error = t1_allocate_blend( face, 0, (FT_UInt)num_axis );
+ error = t1_allocate_blend( t1face, 0, (FT_UInt)num_axis );
if ( error )
goto Exit;
- blend = face->blend;
+ blend = t1face->blend;
FT_TRACE4(( " [" ));
@@ -1089,15 +1081,17 @@
static void
- parse_weight_vector( T1_Face face,
- T1_Loader loader )
+ parse_weight_vector( FT_Face face, /* T1_Face */
+ void* loader_ )
{
+ T1_Face t1face = (T1_Face)face;
+ T1_Loader loader = (T1_Loader)loader_;
T1_TokenRec design_tokens[T1_MAX_MM_DESIGNS];
FT_Int num_designs;
FT_Error error = FT_Err_Ok;
- FT_Memory memory = face->root.memory;
+ FT_Memory memory = FT_FACE_MEMORY( face );
T1_Parser parser = &loader->parser;
- PS_Blend blend = face->blend;
+ PS_Blend blend = t1face->blend;
T1_Token token;
FT_Int n;
FT_Byte* old_cursor;
@@ -1122,10 +1116,10 @@
if ( !blend || !blend->num_designs )
{
- error = t1_allocate_blend( face, (FT_UInt)num_designs, 0 );
+ error = t1_allocate_blend( t1face, (FT_UInt)num_designs, 0 );
if ( error )
goto Exit;
- blend = face->blend;
+ blend = t1face->blend;
}
else if ( blend->num_designs != (FT_UInt)num_designs )
{
@@ -1173,11 +1167,15 @@
/* e.g., /BuildCharArray [0 0 0 0 0 0 0 0] def */
/* we're only interested in the number of array elements */
static void
- parse_buildchar( T1_Face face,
- T1_Loader loader )
+ parse_buildchar( FT_Face face, /* T1_Face */
+ void* loader_ )
{
- face->len_buildchar = (FT_UInt)T1_ToFixedArray( &loader->parser,
- 0, NULL, 0 );
+ T1_Face t1face = (T1_Face)face;
+ T1_Loader loader = (T1_Loader)loader_;
+
+
+ t1face->len_buildchar = (FT_UInt)T1_ToFixedArray( &loader->parser,
+ 0, NULL, 0 );
#ifdef FT_DEBUG_LEVEL_TRACE
{
@@ -1185,7 +1183,7 @@
FT_TRACE4(( " [" ));
- for ( i = 0; i < face->len_buildchar; i++ )
+ for ( i = 0; i < t1face->len_buildchar; i++ )
FT_TRACE4(( " 0" ));
FT_TRACE4(( "]\n" ));
@@ -1335,9 +1333,10 @@
static void
- parse_private( T1_Face face,
- T1_Loader loader )
+ parse_private( FT_Face face,
+ void* loader_ )
{
+ T1_Loader loader = (T1_Loader)loader_;
FT_UNUSED( face );
loader->keywords_encountered |= T1_PRIVATE;
@@ -1401,13 +1400,14 @@
/* and `/CharStrings' dictionaries. */
static void
- t1_parse_font_matrix( T1_Face face,
- T1_Loader loader )
+ t1_parse_font_matrix( FT_Face face, /* T1_Face */
+ void* loader_ )
{
+ T1_Face t1face = (T1_Face)face;
+ T1_Loader loader = (T1_Loader)loader_;
T1_Parser parser = &loader->parser;
- FT_Matrix* matrix = &face->type1.font_matrix;
- FT_Vector* offset = &face->type1.font_offset;
- FT_Face root = (FT_Face)&face->root;
+ FT_Matrix* matrix = &t1face->type1.font_matrix;
+ FT_Vector* offset = &t1face->type1.font_offset;
FT_Fixed temp[6];
FT_Fixed temp_scale;
FT_Int result;
@@ -1443,7 +1443,7 @@
if ( temp_scale != 0x10000L )
{
/* set units per EM based on FontMatrix values */
- root->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale );
+ face->units_per_EM = (FT_UShort)FT_DivFix( 1000, temp_scale );
temp[0] = FT_DivFix( temp[0], temp_scale );
temp[1] = FT_DivFix( temp[1], temp_scale );
@@ -1471,14 +1471,16 @@
static void
- parse_encoding( T1_Face face,
- T1_Loader loader )
+ parse_encoding( FT_Face face, /* T1_Face */
+ void* loader_ )
{
+ T1_Face t1face = (T1_Face)face;
+ T1_Loader loader = (T1_Loader)loader_;
T1_Parser parser = &loader->parser;
FT_Byte* cur;
FT_Byte* limit = parser->root.limit;
- PSAux_Service psaux = (PSAux_Service)face->psaux;
+ PSAux_Service psaux = (PSAux_Service)t1face->psaux;
T1_Skip_Spaces( parser );
@@ -1494,7 +1496,7 @@
/* and we must load it now */
if ( ft_isdigit( *cur ) || *cur == '[' )
{
- T1_Encoding encode = &face->type1.encoding;
+ T1_Encoding encode = &t1face->type1.encoding;
FT_Int count, array_size, n;
PS_Table char_table = &loader->encoding_table;
FT_Memory memory = parser->root.memory;
@@ -1676,7 +1678,7 @@
FT_TRACE4(( "]\n" ));
#endif
- face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
+ t1face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
parser->root.cursor = cur;
}
@@ -1687,21 +1689,21 @@
if ( cur + 17 < limit &&
ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
{
- face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
+ t1face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
FT_TRACE4(( " StandardEncoding\n" ));
}
else if ( cur + 15 < limit &&
ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
{
- face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
+ t1face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
FT_TRACE4(( " ExpertEncoding\n" ));
}
else if ( cur + 18 < limit &&
ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
{
- face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
+ t1face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
FT_TRACE4(( " ISOLatin1Encoding\n" ));
}
@@ -1715,9 +1717,11 @@
static void
- parse_subrs( T1_Face face,
- T1_Loader loader )
+ parse_subrs( FT_Face face, /* T1_Face */
+ void* loader_ )
{
+ T1_Face t1face = (T1_Face)face;
+ T1_Loader loader = (T1_Loader)loader_;
T1_Parser parser = &loader->parser;
PS_Table table = &loader->subrs;
FT_Memory memory = parser->root.memory;
@@ -1725,7 +1729,7 @@
FT_Int num_subrs;
FT_UInt count;
- PSAux_Service psaux = (PSAux_Service)face->psaux;
+ PSAux_Service psaux = (PSAux_Service)t1face->psaux;
T1_Skip_Spaces( parser );
@@ -1769,7 +1773,7 @@
*/
FT_TRACE0(( "parse_subrs: adjusting number of subroutines"
- " (from %d to %ld)\n",
+ " (from %d to %zu)\n",
num_subrs,
( parser->root.limit - parser->root.cursor ) >> 3 ));
num_subrs = ( parser->root.limit - parser->root.cursor ) >> 3;
@@ -1857,7 +1861,7 @@
/* */
/* thanks to Tom Kacvinsky for pointing this out */
/* */
- if ( face->type1.private_dict.lenIV >= 0 )
+ if ( t1face->type1.private_dict.lenIV >= 0 )
{
FT_Byte* temp = NULL;
@@ -1865,7 +1869,7 @@
/* some fonts define empty subr records -- this is not totally */
/* compliant to the specification (which says they should at */
/* least contain a `return'), but we support them anyway */
- if ( size < (FT_ULong)face->type1.private_dict.lenIV )
+ if ( size < (FT_ULong)t1face->type1.private_dict.lenIV )
{
error = FT_THROW( Invalid_File_Format );
goto Fail;
@@ -1876,9 +1880,11 @@
goto Fail;
FT_MEM_COPY( temp, base, size );
psaux->t1_decrypt( temp, size, 4330 );
- size -= (FT_ULong)face->type1.private_dict.lenIV;
- error = T1_Add_Table( table, (FT_Int)idx,
- temp + face->type1.private_dict.lenIV, size );
+ size -= (FT_ULong)t1face->type1.private_dict.lenIV;
+ error = T1_Add_Table( table,
+ (FT_Int)idx,
+ temp + t1face->type1.private_dict.lenIV,
+ size );
FT_FREE( temp );
}
else
@@ -1910,9 +1916,11 @@
static void
- parse_charstrings( T1_Face face,
- T1_Loader loader )
+ parse_charstrings( FT_Face face, /* T1_Face */
+ void* loader_ )
{
+ T1_Face t1face = (T1_Face)face;
+ T1_Loader loader = (T1_Loader)loader_;
T1_Parser parser = &loader->parser;
PS_Table code_table = &loader->charstrings;
PS_Table name_table = &loader->glyph_names;
@@ -1920,7 +1928,7 @@
FT_Memory memory = parser->root.memory;
FT_Error error;
- PSAux_Service psaux = (PSAux_Service)face->psaux;
+ PSAux_Service psaux = (PSAux_Service)t1face->psaux;
FT_Byte* cur = parser->root.cursor;
FT_Byte* limit = parser->root.limit;
@@ -1940,7 +1948,7 @@
if ( num_glyphs > ( limit - cur ) >> 3 )
{
FT_TRACE0(( "parse_charstrings: adjusting number of glyphs"
- " (from %d to %ld)\n",
+ " (from %d to %zu)\n",
num_glyphs, ( limit - cur ) >> 3 ));
num_glyphs = ( limit - cur ) >> 3;
}
@@ -2069,13 +2077,13 @@
notdef_found = 1;
}
- if ( face->type1.private_dict.lenIV >= 0 &&
+ if ( t1face->type1.private_dict.lenIV >= 0 &&
n < num_glyphs + TABLE_EXTEND )
{
FT_Byte* temp = NULL;
- if ( size <= (FT_ULong)face->type1.private_dict.lenIV )
+ if ( size <= (FT_ULong)t1face->type1.private_dict.lenIV )
{
error = FT_THROW( Invalid_File_Format );
goto Fail;
@@ -2086,9 +2094,11 @@
goto Fail;
FT_MEM_COPY( temp, base, size );
psaux->t1_decrypt( temp, size, 4330 );
- size -= (FT_ULong)face->type1.private_dict.lenIV;
- error = T1_Add_Table( code_table, n,
- temp + face->type1.private_dict.lenIV, size );
+ size -= (FT_ULong)t1face->type1.private_dict.lenIV;
+ error = T1_Add_Table( code_table,
+ n,
+ temp + t1face->type1.private_dict.lenIV,
+ size );
FT_FREE( temp );
}
else
@@ -2570,7 +2580,7 @@
{
FT_ERROR(( "T1_Open_Face:"
" number-of-designs != 2 ^^ number-of-axes\n" ));
- T1_Done_Blend( face );
+ T1_Done_Blend( FT_FACE( face ) );
}
if ( face->blend &&
@@ -2590,15 +2600,15 @@
/* font as a normal PS font */
if ( face->blend &&
( !face->blend->num_designs || !face->blend->num_axis ) )
- T1_Done_Blend( face );
+ T1_Done_Blend( FT_FACE( face ) );
/* the font may have no valid WeightVector */
if ( face->blend && !face->blend->weight_vector )
- T1_Done_Blend( face );
+ T1_Done_Blend( FT_FACE( face ) );
/* the font may have no valid BlendDesignPositions */
if ( face->blend && !face->blend->design_pos[0] )
- T1_Done_Blend( face );
+ T1_Done_Blend( FT_FACE( face ) );
/* the font may have no valid BlendDesignMap */
if ( face->blend )
@@ -2609,7 +2619,7 @@
for ( i = 0; i < face->blend->num_axis; i++ )
if ( !face->blend->design_map[i].num_points )
{
- T1_Done_Blend( face );
+ T1_Done_Blend( FT_FACE( face ) );
break;
}
}
diff --git a/src/3rdparty/freetype/src/type1/t1load.h b/src/3rdparty/freetype/src/type1/t1load.h
index f8511cccf6..d8c9d2d8ab 100644
--- a/src/3rdparty/freetype/src/type1/t1load.h
+++ b/src/3rdparty/freetype/src/type1/t1load.h
@@ -66,52 +66,52 @@ FT_BEGIN_HEADER
#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
FT_LOCAL( FT_Error )
- T1_Get_Multi_Master( T1_Face face,
+ T1_Get_Multi_Master( FT_Face face,
FT_Multi_Master* master );
FT_LOCAL( FT_Error )
- T1_Get_MM_Var( T1_Face face,
+ T1_Get_MM_Var( FT_Face face,
FT_MM_Var* *master );
FT_LOCAL( FT_Error )
- T1_Set_MM_Blend( T1_Face face,
+ T1_Set_MM_Blend( FT_Face face,
FT_UInt num_coords,
FT_Fixed* coords );
FT_LOCAL( FT_Error )
- T1_Get_MM_Blend( T1_Face face,
+ T1_Get_MM_Blend( FT_Face face,
FT_UInt num_coords,
FT_Fixed* coords );
FT_LOCAL( FT_Error )
- T1_Set_MM_Design( T1_Face face,
+ T1_Set_MM_Design( FT_Face face,
FT_UInt num_coords,
FT_Long* coords );
FT_LOCAL( FT_Error )
- T1_Reset_MM_Blend( T1_Face face,
+ T1_Reset_MM_Blend( FT_Face face,
FT_UInt instance_index );
FT_LOCAL( FT_Error )
- T1_Get_Var_Design( T1_Face face,
+ T1_Get_Var_Design( FT_Face face,
FT_UInt num_coords,
FT_Fixed* coords );
FT_LOCAL( FT_Error )
- T1_Set_Var_Design( T1_Face face,
+ T1_Set_Var_Design( FT_Face face,
FT_UInt num_coords,
FT_Fixed* coords );
FT_LOCAL( void )
- T1_Done_Blend( T1_Face face );
+ T1_Done_Blend( FT_Face face );
FT_LOCAL( FT_Error )
- T1_Set_MM_WeightVector( T1_Face face,
+ T1_Set_MM_WeightVector( FT_Face face,
FT_UInt len,
FT_Fixed* weightvector );
FT_LOCAL( FT_Error )
- T1_Get_MM_WeightVector( T1_Face face,
+ T1_Get_MM_WeightVector( FT_Face face,
FT_UInt* len,
FT_Fixed* weightvector );
diff --git a/src/3rdparty/freetype/src/type1/t1objs.c b/src/3rdparty/freetype/src/type1/t1objs.c
index 1bb2f15f3a..69e4fd5065 100644
--- a/src/3rdparty/freetype/src/type1/t1objs.c
+++ b/src/3rdparty/freetype/src/type1/t1objs.c
@@ -167,8 +167,7 @@
FT_Module module;
- module = FT_Get_Module( slot->face->driver->root.library,
- "pshinter" );
+ module = FT_Get_Module( slot->library, "pshinter" );
if ( module )
{
T1_Hints_Funcs funcs;
@@ -227,7 +226,7 @@
face->len_buildchar = 0;
}
- T1_Done_Blend( face );
+ T1_Done_Blend( t1face );
face->blend = NULL;
#endif
@@ -290,7 +289,8 @@
*
* @Input:
* stream ::
- * input stream where to load font data.
+ * Dummy argument for compatibility with the `FT_Face_InitFunc` API.
+ * Ignored. The stream should be passed through `face->root.stream`.
*
* face_index ::
* The index of the font face in the resource.
diff --git a/src/3rdparty/freetype/src/type42/t42drivr.c b/src/3rdparty/freetype/src/type42/t42drivr.c
index ce1528e5db..ee5fd44a9f 100644
--- a/src/3rdparty/freetype/src/type42/t42drivr.c
+++ b/src/3rdparty/freetype/src/type42/t42drivr.c
@@ -56,33 +56,41 @@
*
*/
- static FT_Error
- t42_get_glyph_name( T42_Face face,
+ FT_CALLBACK_DEF( FT_Error )
+ t42_get_glyph_name( FT_Face face, /* T42_Face */
FT_UInt glyph_index,
FT_Pointer buffer,
FT_UInt buffer_max )
{
- FT_STRCPYN( buffer, face->type1.glyph_names[glyph_index], buffer_max );
+ T42_Face t42face = (T42_Face)face;
+
+
+ FT_STRCPYN( buffer,
+ t42face->type1.glyph_names[glyph_index],
+ buffer_max );
return FT_Err_Ok;
}
- static FT_UInt
- t42_get_name_index( T42_Face face,
+ FT_CALLBACK_DEF( FT_UInt )
+ t42_get_name_index( FT_Face face, /* T42_Face */
const FT_String* glyph_name )
{
- FT_Int i;
+ T42_Face t42face = (T42_Face)face;
+ FT_Int i;
- for ( i = 0; i < face->type1.num_glyphs; i++ )
+ for ( i = 0; i < t42face->type1.num_glyphs; i++ )
{
- FT_String* gname = face->type1.glyph_names[i];
+ FT_String* gname = t42face->type1.glyph_names[i];
if ( glyph_name[0] == gname[0] && !ft_strcmp( glyph_name, gname ) )
- return (FT_UInt)ft_strtol( (const char *)face->type1.charstrings[i],
- NULL, 10 );
+ return (FT_UInt)ft_strtol(
+ (const char *)t42face->type1.charstrings[i],
+ NULL,
+ 10 );
}
return 0;
@@ -102,10 +110,13 @@
*
*/
- static const char*
- t42_get_ps_font_name( T42_Face face )
+ FT_CALLBACK_DEF( const char* )
+ t42_get_ps_font_name( FT_Face face ) /* T42_Face */
{
- return (const char*)face->type1.font_name;
+ T42_Face t42face = (T42_Face)face;
+
+
+ return (const char*)t42face->type1.font_name;
}
@@ -121,7 +132,7 @@
*
*/
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
t42_ps_get_font_info( FT_Face face,
PS_FontInfoRec* afont_info )
{
@@ -131,7 +142,7 @@
}
- static FT_Error
+ FT_CALLBACK_DEF( FT_Error )
t42_ps_get_font_extra( FT_Face face,
PS_FontExtraRec* afont_extra )
{
@@ -141,7 +152,7 @@
}
- static FT_Int
+ FT_CALLBACK_DEF( FT_Int )
t42_ps_has_glyph_names( FT_Face face )
{
FT_UNUSED( face );
diff --git a/src/3rdparty/freetype/src/type42/t42parse.c b/src/3rdparty/freetype/src/type42/t42parse.c
index 6d765c8c10..f96a43b14d 100644
--- a/src/3rdparty/freetype/src/type42/t42parse.c
+++ b/src/3rdparty/freetype/src/type42/t42parse.c
@@ -34,19 +34,19 @@
static void
- t42_parse_font_matrix( T42_Face face,
- T42_Loader loader );
+ t42_parse_font_matrix( FT_Face face,
+ void* loader_ );
static void
- t42_parse_encoding( T42_Face face,
- T42_Loader loader );
+ t42_parse_encoding( FT_Face face,
+ void* loader_ );
static void
- t42_parse_charstrings( T42_Face face,
- T42_Loader loader );
+ t42_parse_charstrings( FT_Face face,
+ void* loader_ );
static void
- t42_parse_sfnts( T42_Face face,
- T42_Loader loader );
+ t42_parse_sfnts( FT_Face face,
+ void* loader_ );
/* as Type42 fonts have no Private dict, */
@@ -241,12 +241,14 @@
static void
- t42_parse_font_matrix( T42_Face face,
- T42_Loader loader )
+ t42_parse_font_matrix( FT_Face face, /* T42_Face */
+ void* loader_ )
{
- T42_Parser parser = &loader->parser;
- FT_Matrix* matrix = &face->type1.font_matrix;
- FT_Vector* offset = &face->type1.font_offset;
+ T42_Face t42face = (T42_Face)face;
+ T42_Loader loader = (T42_Loader)loader_;
+ T42_Parser parser = &loader->parser;
+ FT_Matrix* matrix = &t42face->type1.font_matrix;
+ FT_Vector* offset = &t42face->type1.font_offset;
FT_Fixed temp[6];
FT_Fixed temp_scale;
FT_Int result;
@@ -299,14 +301,16 @@
static void
- t42_parse_encoding( T42_Face face,
- T42_Loader loader )
+ t42_parse_encoding( FT_Face face,
+ void* loader_ )
{
- T42_Parser parser = &loader->parser;
+ T42_Face t42face = (T42_Face)face;
+ T42_Loader loader = (T42_Loader)loader_;
+ T42_Parser parser = &loader->parser;
FT_Byte* cur;
- FT_Byte* limit = parser->root.limit;
+ FT_Byte* limit = parser->root.limit;
- PSAux_Service psaux = (PSAux_Service)face->psaux;
+ PSAux_Service psaux = (PSAux_Service)t42face->psaux;
T1_Skip_Spaces( parser );
@@ -322,7 +326,7 @@
/* and we must load it now */
if ( ft_isdigit( *cur ) || *cur == '[' )
{
- T1_Encoding encode = &face->type1.encoding;
+ T1_Encoding encode = &t42face->type1.encoding;
FT_Int count, n;
PS_Table char_table = &loader->encoding_table;
FT_Memory memory = parser->root.memory;
@@ -493,8 +497,8 @@
T1_Skip_Spaces( parser );
}
- face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
- parser->root.cursor = cur;
+ t42face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
+ parser->root.cursor = cur;
}
/* Otherwise, we should have either `StandardEncoding', */
@@ -503,15 +507,15 @@
{
if ( cur + 17 < limit &&
ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
- face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
+ t42face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
else if ( cur + 15 < limit &&
ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
- face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
+ t42face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
else if ( cur + 18 < limit &&
ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
- face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
+ t42face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
else
parser->root.error = FT_ERR( Ignore );
@@ -529,9 +533,11 @@
static void
- t42_parse_sfnts( T42_Face face,
- T42_Loader loader )
+ t42_parse_sfnts( FT_Face face,
+ void* loader_ )
{
+ T42_Face t42face = (T42_Face)face;
+ T42_Loader loader = (T42_Loader)loader_;
T42_Parser parser = &loader->parser;
FT_Memory memory = parser->root.memory;
FT_Byte* cur;
@@ -548,8 +554,8 @@
T42_Load_Status status;
/** There should only be one sfnts array, but free any previous. */
- FT_FREE( face->ttf_data );
- face->ttf_size = 0;
+ FT_FREE( t42face->ttf_data );
+ t42face->ttf_size = 0;
/* The format is */
/* */
@@ -580,7 +586,7 @@
old_string_size = 0;
ttf_count = 0;
ttf_reserved = 12;
- if ( FT_QALLOC( face->ttf_data, ttf_reserved ) )
+ if ( FT_QALLOC( t42face->ttf_data, ttf_reserved ) )
goto Fail;
FT_TRACE2(( "\n" ));
@@ -596,7 +602,7 @@
if ( *cur == ']' )
{
parser->root.cursor++;
- face->ttf_size = ttf_count;
+ t42face->ttf_size = ttf_count;
goto Exit;
}
@@ -707,7 +713,7 @@
/* load offset table, 12 bytes */
if ( ttf_count < 12 )
{
- face->ttf_data[ttf_count++] = string_buf[n];
+ t42face->ttf_data[ttf_count++] = string_buf[n];
continue;
}
else
@@ -715,7 +721,7 @@
FT_Long ttf_reserved_prev = ttf_reserved;
- num_tables = 16 * face->ttf_data[4] + face->ttf_data[5];
+ num_tables = 16 * t42face->ttf_data[4] + t42face->ttf_data[5];
status = BEFORE_TABLE_DIR;
ttf_reserved = 12 + 16 * num_tables;
@@ -729,7 +735,7 @@
goto Fail;
}
- if ( FT_QREALLOC( face->ttf_data, ttf_reserved_prev,
+ if ( FT_QREALLOC( t42face->ttf_data, ttf_reserved_prev,
ttf_reserved ) )
goto Fail;
}
@@ -739,7 +745,7 @@
/* the offset table is read; read the table directory */
if ( ttf_count < ttf_reserved )
{
- face->ttf_data[ttf_count++] = string_buf[n];
+ t42face->ttf_data[ttf_count++] = string_buf[n];
continue;
}
else
@@ -755,7 +761,7 @@
for ( i = 0; i < num_tables; i++ )
{
- FT_Byte* p = face->ttf_data + 12 + 16 * i + 12;
+ FT_Byte* p = t42face->ttf_data + 12 + 16 * i + 12;
len = FT_PEEK_ULONG( p );
@@ -781,7 +787,7 @@
FT_TRACE2(( " allocating %ld bytes\n", ttf_reserved ));
FT_TRACE2(( "\n" ));
- if ( FT_QREALLOC( face->ttf_data, ttf_reserved_prev,
+ if ( FT_QREALLOC( t42face->ttf_data, ttf_reserved_prev,
ttf_reserved ) )
goto Fail;
}
@@ -795,7 +801,7 @@
error = FT_THROW( Invalid_File_Format );
goto Fail;
}
- face->ttf_data[ttf_count++] = string_buf[n];
+ t42face->ttf_data[ttf_count++] = string_buf[n];
}
}
@@ -811,8 +817,8 @@
Exit:
if ( parser->root.error )
{
- FT_FREE( face->ttf_data );
- face->ttf_size = 0;
+ FT_FREE( t42face->ttf_data );
+ t42face->ttf_size = 0;
}
if ( allocated )
FT_FREE( string_buf );
@@ -820,9 +826,11 @@
static void
- t42_parse_charstrings( T42_Face face,
- T42_Loader loader )
+ t42_parse_charstrings( FT_Face face, /* T42_Face */
+ void* loader_ )
{
+ T42_Face t42face = (T42_Face)face;
+ T42_Loader loader = (T42_Loader)loader_;
T42_Parser parser = &loader->parser;
PS_Table code_table = &loader->charstrings;
PS_Table name_table = &loader->glyph_names;
@@ -830,7 +838,7 @@
FT_Memory memory = parser->root.memory;
FT_Error error;
- PSAux_Service psaux = (PSAux_Service)face->psaux;
+ PSAux_Service psaux = (PSAux_Service)t42face->psaux;
FT_Byte* cur;
FT_Byte* limit = parser->root.limit;
@@ -864,7 +872,7 @@
if ( loader->num_glyphs > ( limit - parser->root.cursor ) >> 2 )
{
FT_TRACE0(( "t42_parse_charstrings: adjusting number of glyphs"
- " (from %d to %ld)\n",
+ " (from %d to %zu)\n",
loader->num_glyphs,
( limit - parser->root.cursor ) >> 2 ));
loader->num_glyphs = ( limit - parser->root.cursor ) >> 2;
diff --git a/src/3rdparty/freetype/src/winfonts/winfnt.c b/src/3rdparty/freetype/src/winfonts/winfnt.c
index fa73ae4a93..1160e4ef36 100644
--- a/src/3rdparty/freetype/src/winfonts/winfnt.c
+++ b/src/3rdparty/freetype/src/winfonts/winfnt.c
@@ -624,31 +624,34 @@
static FT_Error
- fnt_cmap_init( FNT_CMap cmap,
+ fnt_cmap_init( FT_CMap cmap, /* FNT_CMap */
FT_Pointer pointer )
{
- FNT_Face face = (FNT_Face)FT_CMAP_FACE( cmap );
- FNT_Font font = face->font;
+ FNT_CMap fntcmap = (FNT_CMap)cmap;
+ FNT_Face face = (FNT_Face)FT_CMAP_FACE( cmap );
+ FNT_Font font = face->font;
FT_UNUSED( pointer );
- cmap->first = (FT_UInt32) font->header.first_char;
- cmap->count = (FT_UInt32)( font->header.last_char - cmap->first + 1 );
+ fntcmap->first = (FT_UInt32)font->header.first_char;
+ fntcmap->count = (FT_UInt32)( font->header.last_char -
+ fntcmap->first + 1 );
return 0;
}
static FT_UInt
- fnt_cmap_char_index( FNT_CMap cmap,
+ fnt_cmap_char_index( FT_CMap cmap, /* FNT_CMap */
FT_UInt32 char_code )
{
- FT_UInt gindex = 0;
+ FNT_CMap fntcmap = (FNT_CMap)cmap;
+ FT_UInt gindex = 0;
- char_code -= cmap->first;
- if ( char_code < cmap->count )
+ char_code -= fntcmap->first;
+ if ( char_code < fntcmap->count )
/* we artificially increase the glyph index; */
/* FNT_Load_Glyph reverts to the right one */
gindex = (FT_UInt)( char_code + 1 );
@@ -656,26 +659,27 @@
}
- static FT_UInt32
- fnt_cmap_char_next( FNT_CMap cmap,
+ static FT_UInt
+ fnt_cmap_char_next( FT_CMap cmap, /* FNT_CMap */
FT_UInt32 *pchar_code )
{
- FT_UInt gindex = 0;
- FT_UInt32 result = 0;
+ FNT_CMap fntcmap = (FNT_CMap)cmap;
+ FT_UInt gindex = 0;
+ FT_UInt32 result = 0;
FT_UInt32 char_code = *pchar_code + 1;
- if ( char_code <= cmap->first )
+ if ( char_code <= fntcmap->first )
{
- result = cmap->first;
+ result = fntcmap->first;
gindex = 1;
}
else
{
- char_code -= cmap->first;
- if ( char_code < cmap->count )
+ char_code -= fntcmap->first;
+ if ( char_code < fntcmap->count )
{
- result = cmap->first + char_code;
+ result = fntcmap->first + char_code;
gindex = (FT_UInt)( char_code + 1 );
}
}
diff --git a/src/3rdparty/gradle/gradle.properties b/src/3rdparty/gradle/gradle.properties
index 8308822585..4fe1674abd 100644
--- a/src/3rdparty/gradle/gradle.properties
+++ b/src/3rdparty/gradle/gradle.properties
@@ -3,7 +3,7 @@
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
-org.gradle.jvmargs=-Xmx2500m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+org.gradle.jvmargs=-Xmx2500m -XX:MaxMetaspaceSize=768m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# Enable building projects in parallel
org.gradle.parallel=true
@@ -12,6 +12,7 @@ org.gradle.parallel=true
# build with the same inputs. However, over time, the cache size will
# grow. Uncomment the following line to enable it.
#org.gradle.caching=true
+#org.gradle.configuration-cache=true
# Allow AndroidX usage
android.useAndroidX=true
diff --git a/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.jar b/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.jar
index 41d9927a4d..7f93135c49 100644
--- a/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.jar
+++ b/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties b/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties
index da1db5f04e..ac72c34e8a 100644
--- a/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties
+++ b/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/src/3rdparty/gradle/gradlew b/src/3rdparty/gradle/gradlew
index 005bcde042..c22a5176c6 100755
--- a/src/3rdparty/gradle/gradlew
+++ b/src/3rdparty/gradle/gradlew
@@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -80,13 +80,11 @@ do
esac
done
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
-
-APP_NAME="Gradle"
+# This is normally unused
+# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m"'
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -133,22 +131,29 @@ location of your Java installation."
fi
else
JAVACMD=java
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
+ fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -193,6 +198,10 @@ if "$cygwin" || "$msys" ; then
done
fi
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m"'
+
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
@@ -205,6 +214,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \
"$@"
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
diff --git a/src/3rdparty/gradle/gradlew.bat b/src/3rdparty/gradle/gradlew.bat
index 6a68175eb7..ea603b4102 100644
--- a/src/3rdparty/gradle/gradlew.bat
+++ b/src/3rdparty/gradle/gradlew.bat
@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
-@if "%DEBUG%" == "" @echo off
+@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
+if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
diff --git a/src/3rdparty/gradle/qt_attribution.json b/src/3rdparty/gradle/qt_attribution.json
index 5f5d434b83..8e759c8877 100644
--- a/src/3rdparty/gradle/qt_attribution.json
+++ b/src/3rdparty/gradle/qt_attribution.json
@@ -4,8 +4,8 @@
"QDocModule": "qtcore",
"QtParts": ["tools"],
"Homepage": "https://gradle.org",
- "Version": "8.0",
- "DownloadLocation": "https://github.com/gradle/gradle/releases/tag/v8.0",
+ "Version": "8.3",
+ "DownloadLocation": "https://github.com/gradle/gradle/releases/tag/v8.3.0",
"QtUsage": "Needed to create Android packages",
"License": "Apache License 2.0",
"LicenseId": "Apache-2.0",
diff --git a/src/3rdparty/harfbuzz-ng/CMakeLists.txt b/src/3rdparty/harfbuzz-ng/CMakeLists.txt
index c761bda388..1fd404ba74 100644
--- a/src/3rdparty/harfbuzz-ng/CMakeLists.txt
+++ b/src/3rdparty/harfbuzz-ng/CMakeLists.txt
@@ -56,8 +56,10 @@ qt_internal_add_3rdparty_library(BundledHarfbuzz
src/hb-subset-cff1.cc
src/hb-subset-cff2.cc
src/hb-subset-input.cc
+ src/hb-subset-instancer-iup.cc src/hb-subset-instancer-iup.hh
src/hb-subset-instancer-solver.cc
src/hb-subset-plan.cc
+ src/hb-subset-plan-member-list.hh
src/hb-subset-repacker.cc src/hb-subset-repacker.h
src/hb-unicode.cc src/hb-unicode.h src/hb-unicode.hh
src/hb-utf.hh
diff --git a/src/3rdparty/harfbuzz-ng/NEWS b/src/3rdparty/harfbuzz-ng/NEWS
deleted file mode 100644
index 9a5914525c..0000000000
--- a/src/3rdparty/harfbuzz-ng/NEWS
+++ /dev/null
@@ -1,3217 +0,0 @@
-Overview of changes leading to 7.0.1
-Monday, February 20, 2023
-====================================
-- Various build and bug fixes.
-
-
-Overview of changes leading to 7.0.0
-Saturday, February 11, 2023
-====================================
-- New hb-paint API that is designed mainly to paint “COLRv1” glyphs, but can be
- also used as a unified API to paint any of the glyph representations
- supported by HarfBuzz (B/W outlines, color layers, or color bitmaps).
- (Behdad Esfahbod, Matthias Clasen)
-- New hb-cairo API for integrating with cairo graphics library. This is provided
- as a separate harfbuzz-cairo library. (Behdad Esfahbod, Matthias Clasen)
-- Support for instancing “CFF2” table. (Behdad Esfahbod)
-- Support font emboldening. (Behdad Esfahbod)
-- Support feature ranges with AAT shaping. (Behdad Esfahbod)
-- Experimental support to cubic curves in “glyf” table, see
- https://github.com/harfbuzz/boring-expansion-spec/blob/main/glyf1-cubicOutlines.md
- for spec. (Behdad Esfahbod)
-- Various subsetter improvements. (Garret Rieger, Qunxin Liu, Behdad Esfahbod)
-- Various documentation improvements.
- (Behdad Esfahbod, Matthias Clasen, Khaled Hosny)
-- Significantly reduced memory use during shaping. (Behdad Esfahbod)
-- Greatly reduced memory use during subsetting “CFF” table. (Behdad Esfahbod)
-- New command line utility, hb-info, for querying various font information.
- (Behdad Esfahbod, Matthias Clasen)
-- New hb-shape/hb-view options: --glyphs, --color-palette, --font-bold,
- --font-grade, and --named-instance. (Behdad Esfahbod)
-- Miscellaneous fixes and improvements.
- (Amir Masoud Abdol, Andres Salomon, Behdad Esfahbod, Chun-wei Fan,
- Garret Rieger, Jens Kutilek, Khaled Hosny, Konstantin Käfer, Matthias Clasen,
- Nirbheek Chauhan, Pedro J. Estébanez, Qunxin Liu, Sergei Trofimovich)
-
-- New API:
-+HB_FONT_NO_VAR_NAMED_INSTANCE
-+HB_PAINT_IMAGE_FORMAT_BGRA
-+HB_PAINT_IMAGE_FORMAT_PNG
-+HB_PAINT_IMAGE_FORMAT_SVG
-+hb_cairo_font_face_create_for_face
-+hb_cairo_font_face_create_for_font
-+hb_cairo_font_face_get_face
-+hb_cairo_font_face_get_font
-+hb_cairo_font_face_get_scale_factor
-+hb_cairo_font_face_set_font_init_func
-+hb_cairo_font_face_set_scale_factor
-+hb_cairo_font_init_func_t
-+hb_cairo_glyphs_from_buffer
-+hb_cairo_scaled_font_get_font
-+hb_color_line_get_color_stops
-+hb_color_line_get_color_stops_func_t
-+hb_color_line_get_extend
-+hb_color_line_get_extend_func_t
-+hb_color_line_t
-+hb_color_stop_t
-+hb_draw_funcs_get_empty
-+hb_draw_funcs_get_user_data
-+hb_draw_funcs_set_user_data
-+hb_face_collect_nominal_glyph_mapping
-+hb_font_draw_glyph
-+hb_font_draw_glyph_func_t
-+hb_font_funcs_set_draw_glyph_func
-+hb_font_funcs_set_paint_glyph_func
-+hb_font_get_synthetic_bold
-+hb_font_get_var_named_instance
-+hb_font_paint_glyph
-+hb_font_paint_glyph_func_t
-+hb_font_set_synthetic_bold
-+hb_map_keys
-+hb_map_next
-+hb_map_update
-+hb_map_values
-+hb_ot_color_glyph_has_paint
-+hb_ot_color_has_paint
-+hb_ot_layout_script_select_language2
-+hb_ot_name_id_predefined_t
-+hb_paint_color
-+hb_paint_color_func_t
-+hb_paint_composite_mode_t
-+hb_paint_custom_palette_color
-+hb_paint_custom_palette_color_func_t
-+hb_paint_extend_t
-+hb_paint_funcs_create
-+hb_paint_funcs_destroy
-+hb_paint_funcs_get_empty
-+hb_paint_funcs_get_user_data
-+hb_paint_funcs_is_immutable
-+hb_paint_funcs_make_immutable
-+hb_paint_funcs_reference
-+hb_paint_funcs_set_color_func
-+hb_paint_funcs_set_custom_palette_color_func
-+hb_paint_funcs_set_image_func
-+hb_paint_funcs_set_linear_gradient_func
-+hb_paint_funcs_set_pop_clip_func
-+hb_paint_funcs_set_pop_group_func
-+hb_paint_funcs_set_pop_transform_func
-+hb_paint_funcs_set_push_clip_glyph_func
-+hb_paint_funcs_set_push_clip_rectangle_func
-+hb_paint_funcs_set_push_group_func
-+hb_paint_funcs_set_push_transform_func
-+hb_paint_funcs_set_radial_gradient_func
-+hb_paint_funcs_set_sweep_gradient_func
-+hb_paint_funcs_set_user_data
-+hb_paint_funcs_t
-+hb_paint_image
-+hb_paint_image_func_t
-+hb_paint_linear_gradient
-+hb_paint_linear_gradient_func_t
-+hb_paint_pop_clip
-+hb_paint_pop_clip_func_t
-+hb_paint_pop_group
-+hb_paint_pop_group_func_t
-+hb_paint_pop_transform
-+hb_paint_pop_transform_func_t
-+hb_paint_push_clip_glyph
-+hb_paint_push_clip_glyph_func_t
-+hb_paint_push_clip_rectangle
-+hb_paint_push_clip_rectangle_func_t
-+hb_paint_push_group
-+hb_paint_push_group_func_t
-+hb_paint_push_transform
-+hb_paint_push_transform_func_t
-+hb_paint_radial_gradient
-+hb_paint_radial_gradient_func_t
-+hb_paint_sweep_gradient
-+hb_paint_sweep_gradient_func_t
-+hb_set_is_inverted
-+hb_subset_input_keep_everything
-
-- Deprecated API:
-+hb_font_funcs_set_glyph_shape_func
-+hb_font_get_glyph_shape_func_t
-+hb_font_get_glyph_shape
-
-
-Overview of changes leading to 6.0.0
-Friday, December 16, 2022
-====================================
-- A new API have been added to pre-process the face and speed up future
- subsetting operations on that face. Provides up to a 95% reduction in
- subsetting times when the same face is subset more than once.
-
- For more details and benchmarks, see:
- https://github.com/harfbuzz/harfbuzz/blob/main/docs/subset-preprocessing.md
-
- (Garret Rieger, Behdad Esfahbod)
-
-- Shaping have been speedup by skipping entire lookups when the buffer contents
- don't intersect with the lookup. Shows up to a 10% speedup in shaping some
- fonts. (Behdad Esfahbod)
-
-- A new experimental feature, “Variable Composites” (enabled by passing
- -Dexperimental_api=true to meson), is also featured in this release.
- This technology enables drastic compression of fonts in the Chinese,
- Japanese, Korean, and other writing systems, by reusing the OpenType Font
- Variations technology for encoding “smart components” into the font.
-
- The specification for these extensions to the font format can be found in:
- https://github.com/harfbuzz/boring-expansion-spec/blob/glyf1/glyf1.md
-
- A test variable-font with ~7160 Hangul syllables derived from the
- NotoSerifKR-VF font has been built, with existing OpenType technology, as
- well as with the new Variable Composites (VarComposites) technology. The
- VarComposites font is over 90% smaller than the OpenType version of the font!
- Both fonts can be obtained from the “smarties” repository:
- https://github.com/behdad/smarties/tree/3.0/fonts/hangul/serif
-
- When building HarfBuzz with experimental features enabled, you can test
- the “smarties” font with a sample character like this:
-
- $ hb-view butchered-hangul-serif-smarties-variable.ttf -u AE01 --variations=wght=700
-
- (Behdad Esfahbod)
-
-- The HarfBuzz subsetter can now drop axes by pinning them to specific values
- (also referred to as instancing). There are a couple of restrictions
- currently:
-
- - Only works with TrueType (“glyf”) based fonts. “CFF2” fonts are not yet
- supported.
- - Only supports the case where all axes in a font are pinned.
-
- (Garret Rieger, Qunxin Liu)
-
-- Miscellaneous fixes and improvements.
-
- (Behdad Esfahbod, Christoph Reiter, David Corbett, Eli Schwartz, Garret
- Rieger, Joel Auterson, Jordan Petridis, Khaled Hosny, Lorenz Wildberg,
- Marco Rebhan, Martin Storsjö, Matthias Clasen, Qunxin Liu, Satadru Pramanik)
-
-
-- New API
-+hb_subset_input_pin_axis_location()
-+hb_subset_input_pin_axis_to_default()
-+hb_subset_preprocess()
-
-
-Overview of changes leading to 5.3.1
-Wednesday, October 19, 2022
-====================================
-- Subsetter repacker fixes. (Garret Rieger)
-- Adjust Grapheme clusters for Katakana voiced sound marks. (Behdad Esfahbod)
-- New “hb-subset” option “--preprocess-face”. (Garret Rieger)
-
-
-Overview of changes leading to 5.3.0
-Saturday, October 8, 2022
-"Women, Life, Freedom" #MahsaAmini
-====================================
-- Don’t add glyphs from dropped MATH or COLR tables to the subset glyphs.
- (Khaled Hosny)
-- Map “rlig” to appropriate AAT feature selectors. (Jonathan Kew)
-- Update USE data files to latest version. (David Corbett)
-- Check “CBDT” extents first before outline tables, to help with fonts that
- also include an empty “glyf” table. (Khaled Hosny)
-- More work towards variable font instancing in the subsetter. (Qunxin Liu)
-- Subsetter repacker improvements. (Garret Rieger)
-- New API:
-+hb_ot_layout_lookup_get_optical_bound()
-+hb_face_builder_sort_tables()
-
-
-Overview of changes leading to 5.2.0
-Saturday, September 17, 2022
-====================================
-- Fix regressions in hb-ft font functions for FT_Face’s with transformation
- matrix. (Behdad Esfahbod)
-- The experimental hb-repacker API now supports splitting several GPOS subtable
- types when needed. (Garret Rieger)
-- The HarfBuzz extensions to OpenType font format are now opt-in behind
- build-time flags. (Behdad Esfahbod)
-- The experimental hb-subset variable fonts instantiation API can now
- instantiate more font tables and arbitrary axis locations. (Qunxin Liu)
-- Unicode 15 support. (David Corbett)
-- Various documentation improvements. (Behdad Esfahbod, Matthias Clasen)
-- The hb-view command line tool now detects WezTerm inline images support.
- (Wez Furlong)
-- Fix FreeType and ICU dependency lookup with meson. (Xavier Claessens)
-
-- New API:
-+HB_SCRIPT_KAWI
-+HB_SCRIPT_NAG_MUNDARI
-
-
-Overview of changes leading to 5.1.0
-Sunday, July 31, 2022
-====================================
-- More extensive buffer tracing messages. (Behdad Esfahbod)
-- Fix hb-ft regression in bitmap fonts rendering. (Behdad Esfahbod)
-- Support extension promotion of lookups in hb-subset-repacker. (Garret Rieger)
-- A new HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL for scripts that use elongation
- (e.g. Arabic) to signify where it is safe to insert tatweel glyph without
- interrupting shaping. (Behdad Esfahbod)
-- Add “--safe-to-insert-tatweel” to “hb-shape” tool. (Behdad Esfahbod)
-
-- New API
-+HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL
-+HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL
-
-
-Overview of changes leading to 5.0.1
-Saturday, July 23, 2022
-====================================
-- Fix version 2 “avar” table with hb-ft. (Behdad Esfahbod)
-
-
-Overview of changes leading to 5.0.0
-Saturday, July 23, 2022
-====================================
-- Support fonts with more than 65535 glyphs in “GDEF”, “GSUB”, and “GPOS”
- tables. This is part of https://github.com/be-fonts/boring-expansion-spec to
- extend OpenType in a backward-compatible way.
- (Behdad Esfahbod, Garret Rieger)
-- Complete support for more than 65535 glyphs in “glyf” table that started in
- 4.0.0 release. Part of boring-expansion-spec. (Behdad Esfahbod)
-- Support version 2 of “avar” table. Part of boring-expansion-spec.
- (Behdad Esfahbod)
-- Fix mark attachment on multiple substitutions in some cases.
- (Behdad Esfahbod)
-- Fix application of “calt”, “rclt”, and “ccmp” features to better match
- Uniscribe behaviour with some Arabic fonts. (Behdad Esfahbod)
-- Improvement to interaction between multiple cursive attachments.
- (Behdad Esfahbod)
-- Improve multiple mark interactions in Hebrew. (Behdad Esfahbod)
-- Implement language-specific forms in AAT shaping. (Behdad Esfahbod)
-- Fix variation of “VORG” table. (Behdad Esfahbod)
-- Support for specific script tags to be retained in the subsetter, and add
- “--layout-scripts” option to “hb-subset” tool. (Garret Rieger)
-- Accept space as delimiter for --features/--variations in command line tools.
-- Improve subsetting of “COLR” table. (Qunxin Liu)
-- Improved fuzzing coverage for ot-math API. (Frédéric Wang)
-- Fix “kern” table version 2 (AAT) sanitization on 32-bit systems.
- (Behdad Esfahbod)
-- Allow negative glyph advances from “graphite2” shaper. (Stephan Bergmann)
-- Implement loading (color) bitmap fonts with hb-ft. (Behdad Esfahbod)
-- Fix regression in hb-ft when changing font size. (Behdad Esfahbod)
-- Fix build on GCC < 7. (Kleis Auke Wolthuizen)
-- Dynamically load dwrite.dll on windows if “directwrite” shaper is enabled.
- (Luca Bacci)
-- Provide a single-file harfbuzz-subset.cc file for easier alternate building
- of hb-subset library, similar to harfbuzz.cc. (Khaled Hosny)
-
-- New API
-+HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG
-+hb_language_matches()
-
-
-Overview of changes leading to 4.4.1
-Wednesday, June 29, 2022
-====================================
-- Fix test failure with some compilers.
-- Fix Telugu and Kannada kerning regression.
-
-
-Overview of changes leading to 4.4.0
-Monday, June 27, 2022
-====================================
-- Caching of variable fonts shaping, in particular when using HarfBuzz’s own
- font loading functions (ot). Bringing performance of variable shaping in par
- with non-variable fonts shaping. (Behdad Esfahbod)
-- Caching of format 2 “Contextual Substitution” and “Chained Contexts
- Substitution” lookups. Resulting in up to 20% speedup of lookup-heavy fonts
- like Gulzar or Noto Nastaliq Urdu. (Behdad Esfahbod)
-- Improved ANSI output from hb-view. (Behdad Esfahbod)
-- Support for shaping legacy, pre-OpenType Windows 3.1-era, Arabic fonts that
- relied on a fixed PUA encoding. (Khaled Hosny, Behdad Esfahbod)
-- Sinhala script is now shaped by the USE shaper instead of “indic” one.
- (Behdad Esfahbod, David Corbett)
-- Thai shaper improvements. (David Corbett)
-- hb-ot-name API supports approximate BCP-47 language matching, for example
- asking for “en_US” in a font that has only “en” names will return them.
- (Behdad Esfahbod)
-- Optimized TrueType glyph shape loading. (Behdad Esfahbod)
-- Fix subsetting of HarfBuzz faces created via hb_face_create_for_tables().
- (Garret Rieger)
-- Add 32 bit var store support to the subsetter. (Garret Rieger)
-
-- New API
-+HB_BUFFER_FLAG_DEFINED
-+HB_BUFFER_SERIALIZE_FLAG_DEFINED
-+hb_font_changed()
-+hb_font_get_serial()
-+hb_ft_hb_font_changed()
-+hb_set_hash()
-+hb_map_copy()
-+hb_map_hash()
-
-
-Overview of changes leading to 4.3.0
-Friday, May 20, 2022
-====================================
-- Major speed up in loading and subsetting fonts, especially in
- handling CFF table. Subsetting some fonts is now 3 times faster.
- (Behdad Esfahbod, Garret Rieger)
-- Speed up blending CFF2 table. (Behdad Esfahbod)
-- Speed up hb_ot_tags_from_language(). (Behdad Esfahbod, David Corbett)
-- Fix USE classification of U+10A38 to fix multiple marks on single Kharoshthi
- base. (David Corbett)
-- Fix parsing of empty CFF Index. (Behdad Esfahbod)
-- Fix subsetting CPAL table with partial palette overlaps. (Garret Rieger)
-
-- New API
-+hb_map_is_equal() (Behdad Esfahbod)
-
-
-Overview of changes leading to 4.2.1
-Sunday, April 24, 2022
-====================================
-- Make sure hb_blob_create_from_file_or_fail() always returns nullptr in case
- of failure and not empty blob sometimes. (Khaled Hosny)
-- Add --passthrough-tables option to hb-subset. (Cosimo Lupo)
-- Reinstate a pause after basic features in Khmer shaper, fixing a regression
- introduced in previous release. (Behdad Esfahbod)
-- Better handling of Regional_Indicator when shaped with RTL-native scripts,
- reverting earlier fix that caused regressions in AAT shaping. (Behdad Esfahbod)
-
-
-Overview of changes leading to 4.2.0
-Wednesday, March 30, 2022
-====================================
-- Source code reorganization, splitting large hb-ot-layout files into smaller,
- per-subtable ones under OT/Layout/*. Code for more tables will follow suit in
- later releases. (Garret Rieger, Behdad Esfahbod)
-- Revert Indic shaper change in previous release that broke some fonts and
- instead make per-syllable restriction of “GSUB” application limited to
- script-specific Indic features, while applying them and discretionary
- features in one go. (Behdad Esfahbod)
-- Fix decoding of private in gvar table. (Behdad Esfahbod)
-- Fix handling of contextual lookups that delete too many glyphs. (Behdad Esfahbod)
-- Make “morx” deleted glyphs don’t block “GPOS” application. (Behdad Esfahbod)
-- Various build fixes. (Chun-wei Fan, Khaled Hosny)
-
-- New API
-+hb_set_next_many() (Andrew John)
-
-
-Overview of changes leading to 4.1.0
-Wednesday, March 23, 2022
-====================================
-- Various OSS-Fuzz fixes. (Behdad Esfahbod)
-- Make fallback vertical-origin match FreeType’s. (Behdad Esfahbod)
-- Treat visible viramas like dependent vowels in USE shaper. (David Corbett)
-- Apply presentation forms features and discretionary features in one go in
- Indic shaper, which seems to match Uniscribe and CoreText behaviour.
- (Behdad Esfahbod, David Corbett)
-- Various bug fixes.
-
-- New API
-+hb_set_add_sorted_array() (Andrew John)
-
-
-Overview of changes leading to 4.0.1
-Friday, March 11, 2022
-====================================
-- Update OpenType to AAT mappings for “hist” and “vrtr” features.
- (Florian Pircher)
-- Update IANA Language Subtag Registry to 2022-03-02. (David Corbett)
-- Update USE shaper to allow any non-numeric tail in a symbol cluster, and
- remove obsolete data overrides. (David Corbett)
-- Fix handling of baseline variations to return correctly scaled values.
- (Matthias Clasen)
-- A new experimental hb_subset_repack_or_fail() to repack an array of objects,
- eliminating offset overflows. The API is not available unless HarfBuzz is
- built with experimental APIs enabled. (Qunxin Liu)
-
-- New experimental API
-+hb_link_t
-+hb_object_t
-+hb_subset_repack_or_fail()
-
-
-Overview of changes leading to 4.0.0
-Tuesday, March 1, 2022
-====================================
-- New public API to create subset plan and gather information on things like
- glyph mappings in the final subset. The plan can then be passed on to perform
- the subsetting operation. (Garret Rieger)
-- Draw API for extracting glyph shapes have been extended and finalized and is
- no longer an experimental API. The draw API supports glyf, CFF and CFF2
- glyph outlines tables, and applies variation settings set on the font as well
- as synthetic slant. The new public API is not backward compatible with the
- previous, non-public, experimental API. (Behdad Esfahbod)
-- The hb-view tool will use HarfBuzz draw API to render the glyphs instead of
- cairo-ft when compiled with Cairo 1.17.5 or newer, setting HB_DRAW
- environment variable to 1 or 0 will force using or not use the draw API,
- respectively. (Behdad Esfahbod)
-- The hb-shape and hb-view tools now default to using HarfBuzz’s own font
- loading functions (ot) instead of FreeType ones (ft). They also have a new
- option, --font-slant, to apply synthetic slant to the font. (Behdad Esfahbod)
-- HarfBuzz now supports more than 65535 (the OpenType limit) glyph shapes and
- metrics. See https://github.com/be-fonts/boring-expansion-spec/issues/6 and
- https://github.com/be-fonts/boring-expansion-spec/issues/7 for details.
- (Behdad Esfahbod)
-- New API to get the dominant horizontal baseline tag for a given script.
- (Behdad Esfahbod)
-- New API to get the baseline positions from the font, and synthesize missing
- ones. As well as new API to get font metrics and synthesize missing ones.
- (Matthias Clasen)
-- Improvements to finding dependencies on Windows when building with Visual
- Studio. (Chun-wei Fan)
-- New buffer flag, HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT, that must be set
- during shaping for HB_GLYPH_FLAG_UNSAFE_TO_CONCAT flag to be reliably
- produced. This is to limit the performance hit of producing this flag to when
- it is actually needed. (Behdad Esfahbod)
-- Documentation improvements. (Matthias Clasen)
-
-- New API
- - General:
- +HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT
- +hb_var_num_t
-
- - Draw:
- +hb_draw_funcs_t
- +hb_draw_funcs_create()
- +hb_draw_funcs_reference()
- +hb_draw_funcs_destroy()
- +hb_draw_funcs_is_immutable()
- +hb_draw_funcs_make_immutable()
- +hb_draw_move_to_func_t
- +hb_draw_funcs_set_move_to_func()
- +hb_draw_line_to_func_t
- +hb_draw_funcs_set_line_to_func()
- +hb_draw_quadratic_to_func_t
- +hb_draw_funcs_set_quadratic_to_func()
- +hb_draw_cubic_to_func_t
- +hb_draw_funcs_set_cubic_to_func()
- +hb_draw_close_path_func_t
- +hb_draw_funcs_set_close_path_func()
- +hb_draw_state_t
- +HB_DRAW_STATE_DEFAULT
- +hb_draw_move_to()
- +hb_draw_line_to()
- +hb_draw_quadratic_to()
- +hb_draw_cubic_to()
- +hb_draw_close_path()
- +hb_font_get_glyph_shape_func_t
- +hb_font_funcs_set_glyph_shape_func()
- +hb_font_get_glyph_shape()
-
- - OpenType layout
- +HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL
- +HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL
- +hb_ot_layout_get_horizontal_baseline_tag_for_script()
- +hb_ot_layout_get_baseline_with_fallback()
-
- - Metrics:
- +hb_ot_metrics_get_position_with_fallback()
-
- - Subset:
- +hb_subset_plan_t
- +hb_subset_plan_create_or_fail()
- +hb_subset_plan_reference()
- +hb_subset_plan_destroy()
- +hb_subset_plan_set_user_data()
- +hb_subset_plan_get_user_data()
- +hb_subset_plan_execute_or_fail()
- +hb_subset_plan_unicode_to_old_glyph_mapping()
- +hb_subset_plan_new_to_old_glyph_mapping()
- +hb_subset_plan_old_to_new_glyph_mapping()
-
-
-Overview of changes leading to 3.4.0
-Sunday, February 13, 2022
-====================================
-- Perform sanity checks on shaping results is now part of “harfbuzz” library
- and can be enabled by setting the buffer flag HB_BUFFER_FLAG_VERIFY.
- (Behdad Esfahbod)
-- Arabic Mark Transient Reordering Algorithm have been updated to revision 6.
- (Khaled Hosny)
-- ISO 15924 code for mathematical notation, ‘Zmth’, now maps to the OpenType
- ‘math’ tag. (Alexis King)
-- It is now possible to get at once all math kerning values for a given glyph
- at a given corner. (Alexis King)
-- Fix locale_t portability issues on systems the typedef’s it to a void
- pointer. (Behdad Esfahbod)
-
-- New API:
-+HB_BUFFER_FLAG_VERIFY
-+HB_OT_TAG_MATH_SCRIPT
-+HB_SCRIPT_MATH
-+hb_ot_math_kern_entry_t
-+hb_ot_math_get_glyph_kernings()
-
-- Deprecated API
-+HB_OT_MATH_SCRIPT
-
-
-Overview of changes leading to 3.3.2
-Sunday, February 6, 2022
-====================================
-- Revert splitting of pair positioning values introduced in 3.3.0 as it proved
- problematic. (Behdad Esfahbod)
-
-
-Overview of changes leading to 3.3.1
-Monday, January 31, 2022
-====================================
-- Fix heap-use-after-free in harfbuzz-subset introduced in previous release.
- (Garret Rieger)
-
-
-Overview of changes leading to 3.3.0
-Monday, January 31, 2022
-====================================
-- Improved documentation. (Matthias Clasen)
-- Internal code cleanup, using C++ standard library more. (Behdad Esfahbod)
-- The low 16-bits of face index will be used by hb_face_create() to select a
- face inside a font collection file format, while the high 16-bits will be
- used by hb_font_create() to load the named instance. (Behdad Esfahbod)
-- Glyph positions and other font metrics now apply synthetic slant set by
- hb_font_set_synthetic_slant(), for improved positioning for synthetically
- slanted fonts. (Behdad Esfahbod)
-- Fixed unintentional locale dependency in hb_variation_to_string() for decimal
- point representation. (Matthias Clasen)
-- When applying pair positioning (kerning) the positioning value is split
- between the two sides of the pair for improved cursor positioning between
- such pairs. (Behdad Esfahbod)
-- Introduced new HB_GLYPH_FLAG_UNSAFE_TO_CONCAT, to be used in conjunction
- with HB_GLYPH_FLAG_UNSAFE_TO_BREAK for optimizing re-shaping during line
- breaking. Check the documentation for further details. (Behdad Esfahbod)
-- Improved handling of macrolanguages when mapping BCP 47 codes to OpenType
- tags. (David Corbett)
-
-- New API:
-+HB_GLYPH_FLAG_UNSAFE_TO_CONCAT
-+hb_segment_properties_overlay()
-+hb_buffer_create_similar()
-+hb_font_set_synthetic_slant()
-+hb_font_get_synthetic_slant()
-+hb_font_get_var_coords_design()
-
-
-Overview of changes leading to 3.2.0
-Friday, November 26, 2021
-====================================
-“harfbuzz” library improvements:
-- Fixed shaping of Apple Color Emoji flags in right-to-left context. (Behdad Esfahbod)
-- Fixed positioning of CFF fonts in HB_TINY profile. (Behdad Esfahbod)
-- OpenType 1.9 language tags update. (David Corbett)
-- Add HB_NO_VERTICAL config option.
-- Add HB_CONFIG_OVERRIDE_H for easier configuration. (Behdad Esfahbod)
-
-“harfbuzz-subset” library improvements:
-- Improved packing of cmap, loca, and Ligature tables. (Garret Rieger)
-- Significantly improved overflow-resolution strategy in the repacker. (Garret Rieger)
-
-
-Overview of changes leading to 3.1.2
-Friday, November 26, 2021
-====================================
-- hb-shape / hb-view: revert treating text on the commandline as single
- paragraph (was introduced in 3.0.0); add new --single-par to do that.
- (Behdad Esfahbod)
-- Subsetter bug fixes. (Garret Rieger, Qunxin Liu, Behdad Esfahbod)
-
-
-Overview of changes leading to 3.1.1
-Wednesday, November 8, 2021
-====================================
-- Work around GCC cast-align error/warning on some platforms. (Behdad Esfahbod)
-- Documentation improvements. (Matthias Clasen)
-
-
-Overview of changes leading to 3.1.0
-Wednesday, November 3, 2021
-====================================
-- Better offset-overflow handling in the subsetter library. (Garret Rieger)
-- Improved Unicode 14 properties in the USE shaper, and various other USE
- shaper fixes. (David Corbett)
-- MATH and COLR v1 tables subsetting support, and various other subsetter fixes.
- (Qunxin Liu)
-- Support for Pwo Karen / Ason Chin medial la. (Simon Cozens)
-- Apply GPOS positioning when substituting with morx table, if kerx is missing.
- (Behdad Esfahbod)
-- Apply calt and clig features across syllable boundaries in Indic shaper.
- (Behdad Esfahbod)
-- meson option for enabling Graphite 2 has been renamed to graphite2.
-- Build and documentation fixes.
-
-- New API:
-+hb_buffer_set_not_found_glyph()
-+hb_buffer_get_not_found_glyph()
-
-
-Overview of changes leading to 3.0.0
-Friday, September 17, 2021
-====================================
-- Unicode 14.0 support (David Corbett).
-- The hb-subset API and the harfbuzz-subset library's ABI are now declared
- stable. The harfbuzz-subset library would not have been possible without the
- work of Garret Rieger and Qunxin Liu from Google Fonts, and the earlier work
- of Michiharu Ariza from Adobe.
-- The hb-style API is now stable and no longer experimental.
-
-- New API:
-+hb_style_tag_t
-+hb_style_get_value()
-+hb_subset_input_t
-+hb_subset_flags_t
-+hb_subset_sets_t
-+hb_subset_input_create_or_fail()
-+hb_subset_input_reference()
-+hb_subset_input_destroy()
-+hb_subset_input_set_user_data()
-+hb_subset_input_get_user_data()
-+hb_subset_input_unicode_set()
-+hb_subset_input_glyph_set()
-+hb_subset_input_set()
-+hb_subset_input_get_flags()
-+hb_subset_input_set_flags()
-+hb_subset_or_fail()
-
-- Removed old unstable harfbuzz-subset API:
--hb_subset_input_nameid_set()
--hb_subset_input_namelangid_set()
--hb_subset_input_layout_features_set()
--hb_subset_input_no_subset_tables_set()
--hb_subset_input_drop_tables_set()
--hb_subset_input_set_drop_hints()
--hb_subset_input_get_drop_hints()
--hb_subset_input_set_desubroutinize()
--hb_subset_input_get_desubroutinize()
--hb_subset_input_set_retain_gids()
--hb_subset_input_get_retain_gids()
--hb_subset_input_set_name_legacy()
--hb_subset_input_get_name_legacy()
--hb_subset_input_set_overlaps_flag()
--hb_subset_input_get_overlaps_flag()
--hb_subset_input_set_notdef_outline()
--hb_subset_input_get_notdef_outline()
--hb_subset_input_set_no_prune_unicode_ranges()
--hb_subset_input_get_no_prune_unicode_ranges()
--hb_subset()
-
-
-Overview of changes leading to 2.9.1
-Tuesday, September 7, 2021
-====================================
-- Final subset API is in place and if no issues are discovered, it will be the
- stable subset API of HarfBuzz 3.0.0. Old API is kept to ease transition, but
- will be removed in 3.0.0.
-- Various fuzzer-found bug fixes.
-- hb_buffer_append() now handles the pre- and post-context which previously
- were left unchanged in the destination buffer.
-- hb-view / hb-shape now accept following new arguments:
- o --unicodes-before/after: takes a list of hex numbers that represent Unicode
- codepoints.
-- Undeprecated API:
- hb_set_invert()
-
-
-Overview of changes leading to 2.9.0
-Wednesday, August 18, 2021
-History Repeats Itself (Afghanistan)
-====================================
-- Subsetter API is being stabilized, with the first stable API to happen in
- 3.0.0 release (https://github.com/harfbuzz/harfbuzz/issues/3078).
-- Support multiple variation axes with same tag, aka HOI.
-- The “coretext” testing shaper now passes font variations to CoreText.
-- hb-shape/hb-view does not break line at new lines unless text is read from
- file.
-- hb-view and hb-subset has a --batch now, similar to hb-shape.
-- The --batch mode now uses ; as argument separator instead of : used previously.
-- The --batch in hb-shape does not expect 0th argument anymore. That is, the
- lines read are interpreted as argv[1:], instead of argv[0:].
-- The --batch option has been undocumented. We are ready to document it; send
- feedback if you find it useful.
-- hb-subset got arguments revamps. Added much-requested --gids-file, --glyphs,
- --glyphs-file, --unicodes-file, supporting ranges in --unicodes.
-- Various bug fixes.
-
-
-Overview of changes leading to 2.8.2
-Tuesday, July 8, 2021
-====================================
-- Shaping LTR digits for RTL scripts now makes the native direction of the
- digits LTR, applying shaping and positioning rules on the same glyph order as
- Uniscribe. (Jonathan Kew, Khaled Hosny).
-- Subsetting COLR v1 and CPAL tables is now supported. (Garret Rieger, Qunxin Liu)
-- Various fixes and improvements to the subsetter. (Garret Rieger, Qunxin Liu, Behdad)
-- When applying morx table, mark glyph widths should not be zeroed. (Jonathan Kew)
-- GPOS is preferred over kerx, if GSUB was applied. (Behdad)
-- Regional_Indicator pairs are grouped together when clustering. (Behdad)
-- New API:
-+hb_blob_create_or_fail()
-+hb_blob_create_from_file_or_fail()
-+hb_set_copy()
-
-
-Overview of changes leading to 2.8.1
-Tuesday, May 4, 2021
-====================================
-- Subsetter now fully supports GSUB/GPOS/GDEF tables (including variations); as
- such, layout tables are retained by subsetter by default. (Garret Rieger, Qunxin Liu)
-- Build scripts no longer check for FontConfig as HarfBuzz does not use it.
-- hb-view supports iTerm2 and kitty inline image protocols (Khaled Hosny),
- it can also use Chafa for terminal graphics if available (Hans Petter Jansson).
-
-Overview of changes leading to 2.8.0
-Tuesday, March 16, 2021
-====================================
-- Shape joining scripts other than Arabic/Syriac using the Universal Shaping Engine.
- Previously these were shaped using the generalized Arabic shaper. (David Corbett)
-- Fix regression in shaping of U+0B55 ORIYA SIGN OVERLINE. (David Corbett)
-- Update language tags. (David Corbett)
-- Variations: reduce error: do not round each interpolated delta. (Just van Rossum)
-- Documentation improvements. (Khaled Hosny, Nathan Willis)
-- Subsetter improvements: subsets most, if not all, lookup types now. (Garret Rieger, Qunxin Liu)
-- Fuzzer-found fixes and other improvements when memory failures happen. (Behdad)
-- Removed most atomic implementations now that we have C++11 atomic impl. (Behdad)
-- General codebase upkeep; using more C++11 features: constexpr constructors, etc. (Behdad)
-
-
-Overview of changes leading to 2.7.4
-Sunday, December 27, 2020
-====================================
-- Fix missing --enable-introspection configure option from previous release
- tarball.
-- Documentation updates.
-
-
-Overview of changes leading to 2.7.3
-Wednesday, December 23, 2020
-====================================
-- Update USE shaper to 2020-08-13 specification, and other improvements.
-- Don’t disable liga feature in myanmar shaper, to match Uniscribe.
-- Improvements to language and script tags handling.
-- Update language system tag registry to OpenType 1.8.4
-- Support for serializing and deserializing Unicode buffers. Serialized buffers
- are now delimited with `<>` or `[]` based on whether it is a Unicode or
- glyphs buffer.
-- Increase buffer work limits to handle fonts with many complex lookups.
-- Handle more shaping operations in trace output.
-- Memory access fixes.
-- More OOM fixes.
-- Improved documentation.
-- Build system improvements.
-- New API:
-+hb_buffer_has_positions()
-+hb_buffer_serialize()
-+hb_buffer_serialize_unicode()
-+hb_buffer_deserialize_unicode()
-
-
-Overview of changes leading to 2.7.2
-Saturday, August 29, 2020
-====================================
-- Fix a regression in the previous release that caused a crash with Kaithi.
-- More OOM fixes.
-
-
-Overview of changes leading to 2.7.1
-Thursday, August 13, 2020
-====================================
-- ot-funcs now handles variable empty glyphs better when hvar/vvar isn't present.
-- Reverted a GDEF processing regression.
-- A couple of fixes to handle OOM better.
-
-
-Overview of changes leading to 2.7.0
-Saturday, July 25, 2020
-====================================
-- Use an implementation for round that always rounds up, some minor fluctuations
- are expected on var font specially when hb-ot callback is used.
-- Fix an AAT's `kerx` issue on broken rendering of Devanagari Sangam MN.
-- Remove AAT's `lcar` table support from _get_ligature_carets API, not even much
- use on macOS installed fonts (only two files). GDEF support is the recommended
- one and expected to work properly after issues fixed two releases ago.
-- Minor memory fixes to handle OOM better specially in hb-ft.
-- Minor .so files versioning scheme change and remove stable/unstable scheme
- differences, was never used in practice (always default to stable scheme).
-- We are now suggesting careful packaging of the library using meson,
- https://github.com/harfbuzz/harfbuzz/wiki/Notes-on-migration-to-meson
- for more information.
-- Distribution package URL is changed, either use GitHub generated tarballs,
- `https://github.com/harfbuzz/harfbuzz/archive/$pkgver.tar.gz`
- or, even more preferably use commit hash of the release and git checkouts like,
- `git+https://github.com/harfbuzz/harfbuzz#commit=$commit`
-
-
-Overview of changes leading to 2.6.8
-Monday, June 22, 2020
-====================================
-- New API to fetch glyph alternates from GSUB table.
-- hb-coretext build fix for macOS < 10.10.
-- Meson build fixes, cmake port removal is postponed but please prepare for
- it and give us feedback.
- Autotools is still our main build system however please consider
- experimenting with meson also for packaging the library.
-- New API:
-+hb_ot_layout_lookup_get_glyph_alternates()
-
-
-Overview of changes leading to 2.6.7
-Wednesday, June 3, 2020
-====================================
-- Update to Unicode 13.0.0.
-- Fix hb_ot_layout_get_ligature_carets for fonts without lcar table, it was
- completely broken for all the other fonts since 2.1.2.
-- As a part of our migration to meson, this release will be the last one
- to provide cmake port files but autotools still is our main build system.
- There is a possibility that the next version or the after be released
- using meson.
-
-
-Overview of changes leading to 2.6.6
-Tuesday, May 12, 2020
-====================================
-- A fix in AAT kerning for Geeza Pro.
-- Better support for resource fork fonts on macOS.
-
-
-Overview of changes leading to 2.6.5
-Friday, April 17, 2020
-====================================
-- Add experimental meson build system. Autotools is still the primary
- and supported build system.
-- AAT is now always preferred for horizontal scripts when both AAT and OT
- layout tables exist at the same time.
-- Subsetter improvements.
-- New API:
-+hb_ft_font_lock_face()
-+hb_ft_font_unlock_face()
-
-
-Overview of changes leading to 2.6.4
-Monday, October 29, 2019
-====================================
-- Small bug fix.
-- Build fixes.
-
-
-Overview of changes leading to 2.6.3
-Monday, October 28, 2019
-====================================
-- Misc small fixes, mostly to build-related issues.
-- New API:
-+hb_font_get_nominal_glyphs()
-
-
-Overview of changes leading to 2.6.2
-Monday, September 30, 2019
-====================================
-- Misc small fixes, mostly to build-related issues.
-
-
-Overview of changes leading to 2.6.1
-Thursday, August 22, 2019
-====================================
-- Fix regression with hb_font_create_sub_font scaling introduced in 2.6.0.
-- Change interpretation of font PTEM size / CoreText font size handling.
- See https://github.com/harfbuzz/harfbuzz/pull/1484
-- hb-ot-font: Prefer symbol cmap subtable if present.
-- Apply 'dist'/'abvm'/'blwm' features to all scripts.
-- Drop experimental DirectWrite API.
-
-
-Overview of changes leading to 2.6.0
-Tuesday, August 13, 2019
-====================================
-- New OpenType metrics, baseline, and metadata table access APIs.
-- New API to set font variations to a named-instance.
-- New hb-gdi.h header and API for creating hb_face_t from HFONT.
-- Amalgam: Provide a single-file harfbuzz.cc file for easier alternate building.
-- More size-reduction configurable options, enabled by HB_TINY.
-- New API:
-+hb_font_set_var_named_instance()
-+hb_gdi_face_create()
-+hb_ot_layout_baseline_tag_t
-+hb_ot_layout_get_baseline()
-+hb_ot_meta_tag_t
-+hb_ot_meta_get_entry_tags()
-+hb_ot_meta_reference_entry()
-+hb_ot_metrics_tag_t
-+hb_ot_metrics_get_position()
-+hb_ot_metrics_get_variation()
-+hb_ot_metrics_get_x_variation()
-+hb_ot_metrics_get_y_variation()
-
-
-Overview of changes leading to 2.5.3
-Wednesday, June 26, 2019
-====================================
-- Fix UCD script data for Unicode 10+ scripts. This was broken since 2.5.0.
-- More optimizations for HB_TINY.
-
-
-Overview of changes leading to 2.5.2
-Thursday, June 20, 2019
-====================================
-- More hb-config.hh facilities to shrink library size, namely when built as
- HB_TINY.
-- New documentation of custom configurations in CONFIG.md.
-- Fix build on gcc 4.8. That's supported again.
-- Universal Shaping Engine improvements thanks to David Corbett.
-- API Changes: Undeprecate some horizontal-kerning API and re-enable in hb-ft,
- such that Type1 fonts will continue kerning.
-
-
-Overview of changes leading to 2.5.1
-Friday, May 31, 2019
-====================================
-- Fix build with various versions of Visual Studio.
-- Improved documentation, thanks to Nathan Willis.
-- Bugfix in subsetting glyf table.
-- Improved scripts for cross-compiling for Windows using mingw.
-- Rename HB_MATH_GLYPH_PART_FLAG_EXTENDER to HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER.
- A deprecated macro is added for backwards-compatibility.
-
-
-Overview of changes leading to 2.5.0
-Friday, May 24, 2019
-====================================
-- This release does not include much functional changes, but includes major internal
- code-base changes. We now require C++11. Support for gcc 4.8 and earlier has been
- dropped.
-- New hb-config.hh facility for compiling smaller library for embedded and web usecases.
-- New Unicode Character Database implementation that is half the size of previously-used
- UCDN.
-- Subsetter improvements.
-- Improved documentation, thanks to Nathan Willis.
-- Misc shaping fixes.
-
-
-Overview of changes leading to 2.4.0
-Monday, March 25, 2019
-====================================
-- Unicode 12.
-- Misc fixes.
-- Subsetter improvements.
-- New API:
-HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE
-hb_directwrite_face_create()
-
-
-Overview of changes leading to 2.3.1
-Wednesday, January 30, 2019
-====================================
-- AAT bug fixes.
-- Misc internal housekeeping cleanup.
-
-
-Overview of changes leading to 2.3.0
-Thursday, December 20, 2018
-====================================
-- Fix regression on big-endian architectures. Ouch!
-- Misc bug and build fixes.
-- Fix subsetting of simple GSUB/GDEF.
-- Merge CFF / CFF2 support contributed by Adobe. This mostly involves
- the subsetter, but also get_glyph_extents on CFF fonts.
-
-New API in hb-aat.h:
-+hb_aat_layout_has_substitution()
-+hb_aat_layout_has_positioning()
-+hb_aat_layout_has_tracking()
-
-
-Overview of changes leading to 2.2.0
-Thursday, November 29, 2018
-====================================
-- Misc shaping bug fixes.
-- Add font variations named-instance API.
-- Deprecate font variations axis enumeration API and add replacement.
-- AAT shaping improvements:
- o Fixed 'kern' table Format 2 implementation.
- o Implement 'feat' table API for feature detection.
- o Blacklist 'GSUB' table of fonts from 'MUTF' foundry that also have 'morx'.
-
-New API:
-+hb_aat_layout_feature_type_t
-+hb_aat_layout_feature_selector_t
-+hb_aat_layout_get_feature_types()
-+hb_aat_layout_feature_type_get_name_id
-+hb_aat_layout_feature_selector_info_t
-+HB_AAT_LAYOUT_NO_SELECTOR_INDEX
-+hb_aat_layout_feature_type_get_selector_infos()
-+hb_ot_var_axis_flags_t
-+hb_ot_var_axis_info_t
-+hb_ot_var_get_axis_infos()
-+hb_ot_var_find_axis_info()
-+hb_ot_var_get_named_instance_count()
-+hb_ot_var_named_instance_get_subfamily_name_id()
-+hb_ot_var_named_instance_get_postscript_name_id()
-+hb_ot_var_named_instance_get_design_coords()
-
-Deprecated API:
-+HB_OT_VAR_NO_AXIS_INDEX
-+hb_ot_var_axis_t
-+hb_ot_var_get_axes()
-+hb_ot_var_find_axis()
-
-
-Overview of changes leading to 2.1.3
-Friday, November 16, 2018
-====================================
-- Fix AAT 'mort' shaping, which was broken in 2.1.2
-
-
-Overview of changes leading to 2.1.2
-Friday, November 16, 2018
-====================================
-- Various internal changes.
-- AAT shaping improvements:
- o Implement kern table Format 1 state-machine-based kerning.
- o Implement cross-stream kerning (cursive positioning, etc).
- o Ignore emptyish GSUB tables (zero scripts) if morx present.
- o Don't apply GPOS if morx is being applied. Matches Apple.
-
-
--Overview of changes leading to 2.1.1
-Monday, November 5, 2018
-====================================
-- AAT improvements:
- o Implement 'mort' table.
- o Implement 'kern' subtables Format 1 and Format 3.
-
-
-Overview of changes leading to 2.1.0
-Tuesday, October 30, 2018
-====================================
-- AAT shaping improvements:
- o Allow user controlling AAT features, for whole buffer only currently.
- o Several 'morx' fixes.
- o Implement tuple-kerns in 'kerx'; Fixes kerning with Apple default
- San Francisco fonts.
-- Support for color fonts:
- o COLR/CPAL API to fetch color layers.
- o SVG table to fetch SVG documents.
- o CBDT/sbix API to fetch PNG images.
-- New 'name' table API.
-- hb-ot-font now uses 'VORG' table to correctly position CFF glyphs
- in vertical layout.
-- Various fuzzer-found bug fixes.
-
-Changed API:
-
-A type and a macro added in 2.0.0 were renamed:
-
-hb_name_id_t -> hb_ot_name_id_t
-HB_NAME_ID_INVALID -> HB_OT_NAME_ID_INVALID
-
-New API:
-
-+hb_color_t
-+HB_COLOR
-+hb_color_get_alpha()
-+hb_color_get_red()
-+hb_color_get_green()
-+hb_color_get_blue()
-+hb_ot_color_has_palettes()
-+hb_ot_color_palette_get_count()
-+hb_ot_color_palette_get_name_id()
-+hb_ot_color_palette_color_get_name_id()
-+hb_ot_color_palette_flags_t
-+hb_ot_color_palette_get_flags()
-+hb_ot_color_palette_get_colors()
-+hb_ot_color_has_layers()
-+hb_ot_color_layer_t
-+hb_ot_color_glyph_get_layers()
-+hb_ot_color_has_svg()
-+hb_ot_color_glyph_reference_svg()
-+hb_ot_color_has_png()
-+hb_ot_color_glyph_reference_png()
-
-+hb_ot_name_id_t
-+HB_OT_NAME_ID_INVALID
-+HB_OT_NAME_ID_COPYRIGHT
-+HB_OT_NAME_ID_FONT_FAMILY
-+HB_OT_NAME_ID_FONT_SUBFAMILY
-+HB_OT_NAME_ID_UNIQUE_ID
-+HB_OT_NAME_ID_FULL_NAME
-+HB_OT_NAME_ID_VERSION_STRING
-+HB_OT_NAME_ID_POSTSCRIPT_NAME
-+HB_OT_NAME_ID_TRADEMARK
-+HB_OT_NAME_ID_MANUFACTURER
-+HB_OT_NAME_ID_DESIGNER
-+HB_OT_NAME_ID_DESCRIPTION
-+HB_OT_NAME_ID_VENDOR_URL
-+HB_OT_NAME_ID_DESIGNER_URL
-+HB_OT_NAME_ID_LICENSE
-+HB_OT_NAME_ID_LICENSE_URL
-+HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY
-+HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY
-+HB_OT_NAME_ID_MAC_FULL_NAME
-+HB_OT_NAME_ID_SAMPLE_TEXT
-+HB_OT_NAME_ID_CID_FINDFONT_NAME
-+HB_OT_NAME_ID_WWS_FAMILY
-+HB_OT_NAME_ID_WWS_SUBFAMILY
-+HB_OT_NAME_ID_LIGHT_BACKGROUND
-+HB_OT_NAME_ID_DARK_BACKGROUND
-+HB_OT_NAME_ID_VARIATIONS_PS_PREFIX
-+hb_ot_name_entry_t
-+hb_ot_name_list_names()
-+hb_ot_name_get_utf8()
-+hb_ot_name_get_utf16()
-+hb_ot_name_get_utf32()
-
-
-Overview of changes leading to 2.0.2
-Saturday, October 20, 2018
-====================================
-- Fix two minor memory access issues in AAT tables.
-
-
-Overview of changes leading to 2.0.1
-Friday, October 19, 2018
-====================================
-- Fix hb-version.h reported release version that went wrong (1.8.0)
- with previous release.
-- Fix extrapolation in 'trak' table.
-- Fix hb-font infinite-recursion issue with some font funcs and
- subclassed fonts.
-- Implement variation-kerning format in kerx table, although without
- variation.
-- Fix return value of hb_map_is_empty().
-
-
-Overview of changes leading to 2.0.0
-Thursday, October 18, 2018
-====================================
-- Added AAT shaping support (morx/kerx/trak).
- Automatically used if GSUB/GPOS are not available respectively.
- Set HB_OPTIONS=aat env var to have morx/kerx preferred over
- GSUB/GPOS.
-- Apply TrueType kern table internally, instead of relying on
- hb_font_t callbacks.
-- Khmer shaper significantly rewritten to better match Uniscribe.
-- Indic3 tags ('dev3', etc) are passed to USE shaper.
-- .dfont Mac font containers implemented.
-- Script- and language-mapping revamped to better use BCP 47.
-- Misc USE and Indic fixes.
-- Misc everything fixes.
-- Too many things to list. Biggest release since 0.9.1, with
- over 500 commits in just over 5 weeks! Didn't intend it to
- be a big release. Just happened to become.
-- hb-ft now locks underlying FT_Face during use.
-
-API changes:
-
-- Newly-created hb_font_t's now have our internal "hb-ot-font"
- callbacks set on them, so they should work out of the box
- without any callbacks set. If callbacks are set, everything
- is back to what it was before, the fallback callbacks are
- null. If you to get the internal implementation modified,
- sub_font it.
-
-- New hb_font_funcs_set_nominal_glyphs_func() allows speeding
- up character to glyph mapping.
-
-New API:
-+HB_FEATURE_GLOBAL_START
-+HB_FEATURE_GLOBAL_END
-+hb_buffer_set_invisible_glyph()
-+hb_buffer_get_invisible_glyph()
-+hb_font_funcs_set_nominal_glyphs_func()
-+hb_ot_layout_table_select_script()
-+hb_ot_layout_script_select_language()
-+hb_ot_layout_feature_get_name_ids()
-+hb_ot_layout_feature_get_characters()
-+hb_name_id_t
-+HB_NAME_ID_INVALID
-+HB_OT_MAX_TAGS_PER_SCRIPT
-+hb_ot_tags_from_script_and_language()
-+hb_ot_tags_to_script_and_language()
-
-Deprecated API:
--hb_font_funcs_set_glyph_func()
--hb_unicode_eastasian_width_func_t
--hb_unicode_funcs_set_eastasian_width_func()
--hb_unicode_eastasian_width()
--hb_unicode_decompose_compatibility_func_t
--HB_UNICODE_MAX_DECOMPOSITION_LEN
--hb_unicode_funcs_set_decompose_compatibility_func()
--hb_unicode_decompose_compatibility()
--hb_font_funcs_set_glyph_h_kerning_func()
--hb_font_funcs_set_glyph_v_kerning_func()
--hb_font_get_glyph_h_kerning()
--hb_font_get_glyph_v_kerning()
--hb_font_get_glyph_kerning_for_direction()
--hb_ot_layout_table_choose_script()
--hb_ot_layout_script_find_language()
--hb_ot_tags_from_script()
--hb_ot_tag_from_language()
-
-
-Overview of changes leading to 1.9.0
-Monday, September 10, 2018
-====================================
-- Added 'cmap' API to hb_face_t.
-- Face-builder API.
-- hb-ot-font re-creation should be much leaner now, as the
- font tables it uses are cached on hb_face_t now.
-- Internal source header file name changes:
- hb-*-private.hh is renamed to hb-*.hh.
-
-New API:
-+HB_UNICODE_MAX
-+hb_face_collect_unicodes()
-+hb_face_collect_variation_selectors()
-+hb_face_collect_variation_unicodes()
-+hb_face_builder_create()
-+hb_face_builder_add_table()
-
-
-Overview of changes leading to 1.8.8
-Tuesday, August 14, 2018
-====================================
-- Fix hb-icu crash on architectures where compare_exchange_weak() can
- fail falsely. This bug was introduced in 1.8.4.
- https://bugs.chromium.org/p/chromium/issues/detail?id=873568
-- More internal refactoring of atomic operations and singletons.
-- API changes:
- The following functions do NOT reference their return value before
- returning:
- * hb_unicode_funcs_get_default()
- * hb_glib_get_unicode_funcs()
- * hb_icu_get_unicode_funcs()
- This is consistent with their naming ("get", instead of "reference")
- as well as how they are used in the wild (ie. no one calls destroy()
- on their return value.)
-
-
-Overview of changes leading to 1.8.7
-Wednesday, August 8, 2018
-====================================
-- Fix assertion failure with GDEF-blacklisted fonts.
-
-
-Overview of changes leading to 1.8.6
-Tuesday, August 7, 2018
-====================================
-- Internal code shuffling.
-- New API to speed up getting advance widths for implementations
- that have heavy overhead in get_h_advance callback:
-+hb_font_funcs_set_glyph_h_advances_func
-+hb_font_funcs_set_glyph_v_advances_func
-+hb_font_get_glyph_advances_for_direction
-+hb_font_get_glyph_h_advances
-+hb_font_get_glyph_h_advances_func_t
-+hb_font_get_glyph_v_advances
-+hb_font_get_glyph_v_advances_func_t
-
-
-Overview of changes leading to 1.8.5
-Wednesday, August 1, 2018
-====================================
-- Major Khmer shaper improvements to better match Microsoft.
-- Indic bug fixes.
-- Internal improvements to atomic operations.
-
-
-Overview of changes leading to 1.8.4
-Tuesday, July 17, 2018
-====================================
-- Fix build on non-C++11.
-- Use C++-style GCC atomics and C++11 atomics.
-
-
-Overview of changes leading to 1.8.3
-Wednesday, July 11, 2018
-====================================
-- A couple of Indic / USE bug fixes.
-- Disable vectorization, as it was causing unaligned access bus error on
- certain 32bit architectures.
-
-
-Overview of changes leading to 1.8.2
-Tuesday, July 3, 2018
-====================================
-- Fix infinite loop in Khmer shaper.
-- Improve hb_blob_create_from_file() for streams.
-
-
-Overview of changes leading to 1.8.1
-Tuesday, June 12, 2018
-====================================
-- Fix hb-version.h file generation; last two releases went out with wrong ones.
-- Add correctness bug in hb_set_t operations, introduced in 1.7.7.
-- Remove HB_SUBSET_BUILTIN build option. Not necessary.
-
-
-Overview of changes leading to 1.8.0
-Tuesday, June 5, 2018
-====================================
-- Update to Unicode 11.0.0.
-
-
-Overview of changes leading to 1.7.7
-Tuesday, June 5, 2018
-====================================
-- Lots of internal changes, but not yet exposed externally.
-- All HarfBuzz objects are significantly smaller in size now.
-- Sinhala: Position repha on top of post-consonant, not base.
- This better matches Windows 10 behavior, which was changed
- from previous Windows versions.
-- New build options:
- o New cpp macro HB_NO_ATEXIT
- o New cpp macro HB_SUBSET_BUILTIN
-- Significant libharfbuzz-subset changes. API subject to change.
-- New API in libharfbuzz:
-
-+hb_blob_create_from_file()
-+hb_face_count()
-
-A hashmap implementation:
-+hb-map.h
-+HB_MAP_VALUE_INVALID
-+hb_map_t
-+hb_map_create()
-+hb_map_get_empty()
-+hb_map_reference()
-+hb_map_destroy()
-+hb_map_set_user_data()
-+hb_map_get_user_data()
-+hb_map_allocation_successful()
-+hb_map_clear()
-+hb_map_is_empty()
-+hb_map_get_population()
-+hb_map_set()
-+hb_map_get()
-+hb_map_del()
-+hb_map_has()
-
-
-Overview of changes leading to 1.7.6
-Wednesday, March 7, 2018
-====================================
-
-- Fix to hb_set_t binary operations. Ouch.
-- New experimental harfbuzz-subset library. All of hb-subset.h
- is experimental right now and API WILL change.
-
-- New API:
-hb_blob_copy_writable_or_fail()
-HB_OT_TAG_BASE
-hb_set_previous()
-hb_set_previous_range()
-
-
-Overview of changes leading to 1.7.5
-Tuesday, January 30, 2018
-====================================
-
-- Separate Khmer shaper from Indic.
-- First stab at AAT morx. Not hooked up.
-- Misc bug fixes.
-
-
-Overview of changes leading to 1.7.4
-Wednesday, December 20, 2017
-====================================
-
-- Fix collect_glyphs() regression caused by hb_set_t changes.
-
-
-Overview of changes leading to 1.7.3
-Monday, December 18, 2017
-====================================
-
-- hb_set_t performance tuning and optimizations.
-- Speed up collect_glyphs() and reject garbage data.
-- In hb_coretext_font_create() set font point-size (ptem).
-- Misc fixes.
-
-
-Overview of changes leading to 1.7.2
-Monday, December 4, 2017
-====================================
-
-- Optimize hb_set_add_range().
-- Misc fixes.
-- New API:
-hb_coretext_font_create()
-
-
-Overview of changes leading to 1.7.1
-Tuesday, November 14, 2017
-====================================
-
-- Fix atexit object destruction regression.
-- Fix minor integer-overflow.
-
-
-Overview of changes leading to 1.7.0
-Monday, November 13, 2017
-====================================
-
-- Minor Indic fixes.
-- Implement kerning and glyph names in hb-ot-font.
-- Various DSO optimization re .data and .bss sizes.
-- Make C++11 optional; build fixes.
-- Mark all other backends "unsafe-to-break".
-- Graphite fix.
-
-
-Overview of changes leading to 1.6.3
-Thursday, October 26th, 2017
-====================================
-
-- Fix hb_set_t some more. Should be solid now.
-- Implement get_glyph_name() for hb-ot-font.
-- Misc fixes.
-
-
-Overview of changes leading to 1.6.2
-Monday, October 23nd, 2017
-====================================
-
-- Yesterday's release had a bad crasher; don't use it. That's what
- happens when one works on Sunday...
- https://github.com/harfbuzz/harfbuzz/issues/578
-- Build fixes for FreeBSD and Chrome Android.
-
-
-Overview of changes leading to 1.6.1
-Sunday, October 22nd, 2017
-====================================
-
-- Don't skip over COMBINING GRAPHEME JOINER when ligating, etc.
- To be refined: https://github.com/harfbuzz/harfbuzz/issues/554
-- Faster hb_set_t implementation.
-- Don't use deprecated ICU API.
-- Fix undefined-behavior in Myanmar shaper, introduced in 1.6.0
-- Deprecated API:
- hb_set_invert()
-
-
-Overview of changes leading to 1.6.0
-Friday, October the 13th, 2017
-====================================
-
-- Update to Unicode 10.
-
-- Various Indic and Universal Shaping Engine fixes as a result of
- HarfBuzz Hackfest with Jonathan Kew at Web Engines Hackfest at
- the Igalia offices in A Coruña, Spain. Thanks Igalia for having
- us!
-
-- Implement Unicode Arabic Mark Ordering Algorithm UTR#53.
-
-- Implement optical sizing / tracking in CoreText backend, using
- new API hb_font_set_ptem().
-
-- Allow notifying hb_font_t that underlying FT_Face changed sizing,
- using new API hb_ft_font_changed().
-
-- More Graphite backend RTL fixes.
-
-- Fix caching of variable font shaping plans.
-
-- hb-view / hb-shape now accept following new arguments:
-
- o --unicodes: takes a list of hex numbers that represent Unicode
- codepoints.
-
-New API:
-+hb_face_get_table_tags()
-+hb_font_set_ptem()
-+hb_font_get_ptem()
-+hb_ft_font_changed()
-
-
-Overview of changes leading to 1.5.1
-Tuesday, September 5, 2017
-====================================
-
-- Fix "unsafe-to-break" in fallback shaping and other corner cases.
- All our tests pass with --verify now, meaning unsafe-to-break API
- works as expected.
-- Add --unicodes to hb-view / hb-shape.
-- [indic] Treat Consonant_With_Stacker as consonant. This will need
- further tweaking.
-- hb_buffer_diff() tweaks.
-
-
-Overview of changes leading to 1.5.0
-Wednesday, August 23, 2017
-====================================
-
-- Misc new API, for appending a buffer to another, and for comparing
- contents of two buffers for types of differences.
-
-- New "unsafe-to-break" API. Can be used to speed up reshaping
- in line-breaking situations. Essentially, after shaping, it returns
- positions in the input string (some of the cluster boundaries) that
- are "safe to break" in that if the text is segmented at that position
- and two sides reshaped and concatenated, the shaping result is
- exactly the same as shaping the text in one piece.
-
- hb-view and hb-shape and hb-shape now take --verify, which verifies
- the above property.
-
- Some corner cases of the implementation are still not quite working.
- Those will be fixed in subsequent releases.
-
-- New API:
-
-hb_buffer_append()
-
-hb_glyph_flags_t
-HB_GLYPH_FLAG_UNSAFE_TO_BREAK
-HB_GLYPH_FLAG_DEFINED
-hb_glyph_info_get_glyph_flags()
-
-HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS
-
-hb_buffer_diff_flags_t
-HB_BUFFER_DIFF_FLAG_EQUAL
-HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH
-HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH
-HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT
-HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
-HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH
-HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH
-HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH
-HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH
-hb_buffer_diff
-
-
-Overview of changes leading to 1.4.8
-Tuesday, August 8, 2017
-====================================
-
-- Major fix to avar table handling.
-- Rename hb-shape --show-message to --trace.
-- Build fixes.
-
-
-Overview of changes leading to 1.4.7
-Tuesday, July 18, 2017
-====================================
-
-- Multiple Indic, Tibetan, and Cham fixes.
-- CoreText: Allow disabling kerning.
-- Adjust Arabic feature order again.
-- Misc build fixes.
-
-
-Overview of changes leading to 1.4.6
-Sunday, April 23, 2017
-====================================
-
-- Graphite2: Fix RTL positioning issue.
-- Backlist GDEF of more versions of Padauk and Tahoma.
-- New, experimental, cmake alternative build system.
-
-
-Overview of changes leading to 1.4.5
-Friday, March 10, 2017
-====================================
-
-- Revert "Fix Context lookup application when moving back after a glyph..."
- This introduced memory access problems. To be fixed properly soon.
-
-
-Overview of changes leading to 1.4.4
-Sunday, March 5, 2017
-====================================
-
-- Fix Context lookup application when moving back after a glyph deletion.
-- Fix buffer-overrun in Bengali.
-
-
-Overview of changes leading to 1.4.3
-Saturday, February 25, 2017
-====================================
-
-- Route Adlam script to Arabic shaper.
-- Misc fixes.
-- New API:
- hb_font_set_face()
-- Deprecate API:
- hb_graphite2_font_get_gr_font()
-
-
-Overview of changes leading to 1.4.2
-Monday, January 23, 2017
-====================================
-
-- Implement OpenType Font Variation tables avar/fvar/HVAR/VVAR.
-- hb-shape and hb-view now accept --variations.
-- New API:
-
-hb_variation_t
-hb_variation_from_string()
-hb_variation_to_string()
-
-hb_font_set_variations()
-hb_font_set_var_coords_design()
-hb_font_get_var_coords_normalized()
-
-hb-ot-var.h:
-hb_ot_var_axis_t
-hb_ot_var_has_data()
-hb_ot_var_get_axis_count()
-hb_ot_var_get_axes()
-hb_ot_var_find_axis()
-hb_ot_var_normalize_variations()
-hb_ot_var_normalize_coords()
-
-- MVAR to be implemented later. Access to named instances to be
- implemented later as well.
-
-- Misc fixes.
-
-
-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 stabilize 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/harfbuzz/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/harfbuzz/harfbuzz/issues/211
- https://github.com/harfbuzz/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/harfbuzz/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/harfbuzz/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/harfbuzz/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
-====================================
-
-- Reduce max nesting level in OT lookups from 8 to 6.
- Should not affect any real font as far as I know.
-- Fix memory access issue in ot-font.
-- Revert default load-flags of fonts created using hb_ft_font_create()
- back to FT_LOAD_DEFAULT|FT_LOAD_NO_HINTING. This was changed in
- last release (1.0.5), but caused major issues, so revert.
- https://github.com/harfbuzz/harfbuzz/issues/143
-
-
-Overview of changes leading to 1.0.5
-Tuesday, October 13, 2015
-====================================
-
-- Fix multiple memory access bugs discovered using libFuzzer.
- https://github.com/harfbuzz/harfbuzz/issues/139
- Everyone should upgrade to this version as soon as possible.
- We now have continuous fuzzing set up, to avoid issues like
- these creeping in again.
-- Misc fixes.
-
-- New API:
- * hb_font_set_parent().
- * hb_ft_font_[sg]et_load_flags()
- The default flags for fonts created using hb_ft_font_create()
- has changed to default to FT_LOAD_DEFAULT now. Previously it
- was defaulting to FT_LOAD_DFEAULT|FT_LOAD_NO_HINTING.
-
-- API changes:
- * Fonts now default to units-per-EM as their scale, instead of 0.
- * hb_font_create_sub_font() does NOT make parent font immutable
- anymore. hb_font_make_immutable() does.
-
-
-Overview of changes leading to 1.0.4
-Wednesday, September 30, 2015
-====================================
-
-- Fix minor out-of-bounds read error.
-
-
-Overview of changes leading to 1.0.3
-Tuesday, September 1, 2015
-====================================
-
-- Start of user documentation, from Simon Cozens!
-- Implement glyph_extents() for TrueType fonts in hb-ot-font.
-- Improve GPOS cursive attachments with conflicting lookups.
-- More fixes for cluster-level = 1.
-- Uniscribe positioning fix.
-
-
-Overview of changes leading to 1.0.2
-Wednesday, August 19, 2015
-====================================
-
-- Fix shaping with cluster-level > 0.
-- Fix Uniscribe backend font-size scaling.
-- Declare dependencies in harfbuzz.pc.
- FreeType is not declared though, to avoid bugs in pkg-config
- 0.26 with recursive dependencies.
-- Slightly improved debug infrastructure. More to come later.
-- Misc build fixes.
-
-
-Overview of changes leading to 1.0.1
-Monday, July 27, 2015
-====================================
-
-- Fix out-of-bounds access in USE shaper.
-
-
-Overview of changes leading to 1.0.0
-Sunday, July 26, 2015
-====================================
-
-- Implement Universal Shaping Engine:
- https://www.microsoft.com/typography/OpenTypeDev/USE/intro.htm
- http://blogs.windows.com/bloggingwindows/2015/02/23/windows-shapes-the-worlds-languages/
-- Bump version to 1.0.0. The soname was NOT bumped.
-
-
-Overview of changes leading to 0.9.42
-Thursday, July 26, 2015
-=====================================
-
-- New API to allow for retrieving finer-grained cluster
- mappings if the client desires to handle them. Default
- behavior is unchanged.
-- Fix cluster merging when removing default-ignorables.
-- Update to Unicode 8.0
-- hb-graphite2 fixes.
-- Misc fixes.
-- Removed HB_NO_MERGE_CLUSTERS hack.
-- New API:
- hb_buffer_cluster_level_t enum
- hb_buffer_get_cluster_level()
- hb_buffer_set_cluster_level()
- hb-shape / hb-view --cluster-level
-
-
-Overview of changes leading to 0.9.41
-Thursday, June 18, 2015
-=====================================
-
-- Fix hb-coretext with trailing whitespace in right-to-left.
-- New API: hb_buffer_reverse_range().
-- Allow implementing atomic ops in config.h.
-- Fix hb_language_t in language bindings.
-- Misc fixes.
-
-
-Overview of changes leading to 0.9.40
-Friday, March 20, 2015
-=====================================
-
-- Another hb-coretext crasher fix. Ouch!
-- Happy Norouz!
-
-
-Overview of changes leading to 0.9.39
-Wednesday, March 4, 2015
-=====================================
-
-- Critical hb-coretext fixes.
-- Optimizations and refactoring; no functional change
- expected.
-- Misc build fixes.
-
-
-Overview of changes leading to 0.9.38
-Friday, January 23, 2015
-=====================================
-
-- Fix minor out-of-bounds access in Indic shaper.
-- Change New Tai Lue shaping engine from South-East Asian to default,
- reflecting change in Unicode encoding model.
-- Add hb-shape --font-size. Can take up to two numbers for separate
- x / y size.
-- Fix CoreText and FreeType scale issues with negative scales.
-- Reject blobs larger than 2GB. This might break some icu-le-hb clients
- that need security fixes. See:
- http://www.icu-project.org/trac/ticket/11450
-- Avoid accessing font tables during face destruction, in casce rogue
- clients released face data already.
-- Fix up gobject-introspection a bit. Python bindings kinda working.
- See README.python.
-- Misc fixes.
-- API additions:
- hb_ft_face_create_referenced()
- hb_ft_font_create_referenced()
-
-
-Overview of changes leading to 0.9.37
-Wednesday, December 17, 2014
-=====================================
-
-- Fix out-of-bounds access in Context lookup format 3.
-- Indic: Allow ZWJ/ZWNJ before syllable modifiers.
-
-
-Overview of changes leading to 0.9.36
-Thursday, November 20, 2014
-=====================================
-
-- First time that three months went by without a release since
- 0.9.2 was released on August 10, 2012!
-- Fix performance bug in hb_ot_collect_glyphs():
- https://bugzilla.mozilla.org/show_bug.cgi?id=1090869
-- Add basic vertical-text support to hb-ot-font.
-- Misc build fixes.
-
-
-Overview of changes leading to 0.9.35
-Saturday, August 13, 2014
-=====================================
-
-- Fix major shape-plan caching bug when more than one shaper were
- provided to hb_shape_full() (as exercised by XeTeX).
- http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg1246370.html
-- Fix Arabic fallback shaping regression. This was broken in 0.9.32.
-- Major hb-coretext fixes. That backend is complete now, including
- respecing buffer direction and language, down to vertical writing.
-- Build fixes for Windows CE. Should build fine now.
-- Misc fixes:
- Use atexit() only if it's safe to call from shared library
- https://bugs.freedesktop.org/show_bug.cgi?id=82246
- Mandaic had errors in its Unicode Joining_Type
- https://bugs.freedesktop.org/show_bug.cgi?id=82306
-- API changes:
-
- * hb_buffer_clear_contents() does not reset buffer flags now.
-
- After 763e5466c0a03a7c27020e1e2598e488612529a7, one doesn't
- need to set flags for different pieces of text. The flags now
- are something the client sets up once, depending on how it
- actually uses the buffer. As such, don't clear it in
- clear_contents().
-
- I don't expect any changes to be needed to any existing client.
-
-
-Overview of changes leading to 0.9.34
-Saturday, August 2, 2014
-=====================================
-
-- hb_feature_from_string() now accepts CSS font-feature-settings format.
-- As a result, hb-shape / hb-view --features also accept CSS-style strings.
- Eg, "'liga' off" is accepted now.
-- Add old-spec Myanmar shaper:
- https://bugs.freedesktop.org/show_bug.cgi?id=81775
-- Don't apply 'calt' in Hangul shaper.
-- Fix mark advance zeroing for Hebrew shaper:
- https://bugs.freedesktop.org/show_bug.cgi?id=76767
-- Implement Windows-1256 custom Arabic shaping. Only built on Windows,
- and requires help from get_glyph(). Used by Firefox.
- https://bugzilla.mozilla.org/show_bug.cgi?id=1045139
-- Disable 'liga' in vertical text.
-- Build fixes.
-- API changes:
-
- * Make HB_BUFFER_FLAG_BOT/EOT easier to use.
-
- Previously, we expected users to provide BOT/EOT flags when the
- text *segment* was at paragraph boundaries. This meant that for
- clients that provide full paragraph to HarfBuzz (eg. Pango), they
- had code like this:
-
- hb_buffer_set_flags (hb_buffer,
- (item_offset == 0 ? HB_BUFFER_FLAG_BOT : 0) |
- (item_offset + item_length == paragraph_length ?
- HB_BUFFER_FLAG_EOT : 0));
-
- hb_buffer_add_utf8 (hb_buffer,
- paragraph_text, paragraph_length,
- item_offset, item_length);
-
- After this change such clients can simply say:
-
- hb_buffer_set_flags (hb_buffer,
- HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT);
-
- hb_buffer_add_utf8 (hb_buffer,
- paragraph_text, paragraph_length,
- item_offset, item_length);
-
- Ie, HarfBuzz itself checks whether the segment is at the beginning/end
- of the paragraph. Clients that only pass item-at-a-time to HarfBuzz
- continue not setting any flags whatsoever.
-
- Another way to put it is: if there's pre-context text in the buffer,
- HarfBuzz ignores the BOT flag. If there's post-context, it ignores
- EOT flag.
-
-
-Overview of changes leading to 0.9.33
-Tuesday, July 22, 2014
-=====================================
-
-- Turn off ARabic 'cswh' feature that was accidentally turned on.
-- Add HB_TAG_MAX_SIGNED.
-- Make hb_face_make_immutable() really make face immutable!
-- Windows build fixes.
-
-
-Overview of changes leading to 0.9.32
-Thursday, July 17, 2014
-=====================================
-
-- Apply Arabic shaping features in spec order exactly.
-- Another fix for Mongolian free variation selectors.
-- For non-Arabic scripts in Arabic shaper apply 'rlig' and 'calt'
- together.
-- Minor adjustment to U+FFFD logic.
-- Fix hb-coretext build.
-
-
-Overview of changes leading to 0.9.31
-Wednesday, July 16, 2014
-=====================================
-
-- Only accept valid UTF-8/16/32; we missed many cases before.
-- Better shaping of invalid UTF-8/16/32. Falls back to
- U+FFFD REPLACEMENT CHARACTER now.
-- With all changes in this release, the buffer will contain fully
- valid Unicode after hb_buffer_add_utf8/16/32 no matter how
- broken the input is. This can be overridden though. See below.
-- Fix Mongolian Variation Selectors for fonts without GDEF.
-- Fix minor invalid buffer access.
-- Accept zh-Hant and zh-Hans language tags. hb_ot_tag_to_language()
- now uses these instead of private tags.
-- Build fixes.
-- New API:
- * hb_buffer_add_codepoints(). This does what hb_buffer_add_utf32()
- used to do, ie. no validity check on the input at all. add_utf32
- now replaces invalid Unicode codepoints with the replacement
- character (see below).
- * hb_buffer_set_replacement_codepoint()
- * hb_buffer_get_replacement_codepoint()
- Previously, in hb_buffer_add_utf8 and hb_buffer_add_utf16, when
- we detected broken input, we replaced that with (hb_codepoint_t)-1.
- This has changed to use U+FFFD now, but can be changed using these
- new API.
-
-
-Overview of changes leading to 0.9.30
-Wednesday, July 9, 2014
-=====================================
-
-- Update to Unicode 7.0.0:
- * New scripts Manichaean and Psalter Pahlavi are shaped using
- Arabic shaper.
- * All the other new scripts to through the generic shaper for
- now.
-- Minor Indic improvements.
-- Fix graphite2 backend cluster mapping [crasher!]
-- API changes:
- * New HB_SCRIPT_* values for Unicode 7.0 scripts.
- * New function hb_ot_layout_language_get_required_feature().
-- Build fixes.
-
-
-Overview of changes leading to 0.9.29
-Thursday, May 29, 2014
-=====================================
-
-- Implement cmap in hb-ot-font.h. No variation-selectors yet.
-- Myanmar: Allow MedialYa+Asat.
-- Various Indic fixes:
- * Support most characters in Extended Devanagary and Vedic
- Unicode blocks.
- * Allow digits and a some punctuation as consonant placeholders.
-- Build fixes.
-
-
-Overview of changes leading to 0.9.28
-Monday, April 28, 2014
-=====================================
-
-- Unbreak old-spec Indic shaping. (bug 76705)
-- Fix shaping of U+17DD and U+0FC6.
-- Add HB_NO_MERGE_CLUSTERS build option. NOT to be enabled by default
- for shipping libraries. It's an option for further experimentation
- right now. When we are sure how to do it properly, we will add
- public run-time API for the functionality.
-- Build fixes.
-
-
-Overview of changes leading to 0.9.27
-Tuesday, March 18, 2014
-=====================================
-
-- Don't use "register" storage class specifier
-- Wrap definition of free_langs() with HAVE_ATEXIT
-- Add coretext_aat shaper and hb_coretext_face_create() constructor
-- If HAVE_ICU_BUILTIN is defined, use hb-icu Unicode callbacks
-- Add Myanmar test case from OpenType Myanmar spec
-- Only do fallback Hebrew composition if no GPOS 'mark' available
-- Allow bootstrapping without gtk-doc
-- Use AM_MISSING_PROG for ragel and git
-- Typo in ucdn's Makefile.am
-- Improve MemoryBarrier() implementation
-
-
-Overview of changes leading to 0.9.26
-Thursday, January 30, 2014
-=====================================
-
-- Misc fixes.
-- Fix application of 'rtlm' feature.
-- Automatically apply frac/numr/dnom around U+2044 FRACTION SLASH.
-- New header: hb-ot-shape.h
-- Uniscribe: fix scratch-buffer accounting.
-- Reorder Tai Tham SAKOT to after tone-marks.
-- Add Hangul shaper.
-- New files:
- hb-ot-shape-complex-hangul.cc
- hb-ot-shape-complex-hebrew.cc
- hb-ot-shape-complex-tibetan.cc
-- Disable 'cswh' feature in Arabic shaper.
-- Coretext: better handle surrogate pairs.
-- Add HB_TAG_MAX and _HB_SCRIPT_MAX_VALUE.
-
-
-Overview of changes leading to 0.9.25
-Wednesday, December 4, 2013
-=====================================
-
-- Myanmar shaper improvements.
-- Avoid font fallback in CoreText backend.
-- Additional OpenType language tag mappiongs.
-- More aggressive shape-plan caching.
-- Build with / require automake 1.13.
-- Build with libtool 2.4.2.418 alpha to support ppc64le.
-
-
-Overview of changes leading to 0.9.24
-Tuesday, November 13, 2013
-=====================================
-
-- Misc compiler warning fixes with clang.
-- No functional changes.
-
-
-Overview of changes leading to 0.9.23
-Monday, October 28, 2013
-=====================================
-
-- "Udupi HarfBuzz Hackfest", Paris, October 14..18 2013.
-- Fix (Chain)Context recursion with non-monotone lookup positions.
-- Misc Indic bug fixes.
-- New Javanese / Buginese shaping, similar to Windows 8.1.
-
-
-Overview of changes leading to 0.9.22
-Thursday, October 3, 2013
-=====================================
-
-- Fix use-after-end-of-scope in hb_language_from_string().
-- Fix hiding of default_ignorables if font doesn't have space glyph.
-- Protect against out-of-range lookup indices.
-
-- API Changes:
-
- * Added hb_ot_layout_table_get_lookup_count()
-
-
-Overview of changes leading to 0.9.21
-Monday, September 16, 2013
-=====================================
-
-- Rename gobject-introspection library name from harfbuzz to HarfBuzz.
-- Remove (long disabled) hb-old and hb-icu-le test shapers.
-- Misc gtk-doc and gobject-introspection annotations.
-- Misc fixes.
-- API changes:
-
- * Add HB_SET_VALUE_INVALID
-
-Overview of changes leading to 0.9.20
-Thursday, August 29, 2013
-=====================================
-
-General:
-- Misc substitute_closure() fixes.
-- Build fixes.
-
-Documentation:
-- gtk-doc boilerplate integrated. Docs are built now, but
- contain no contents. By next release hopefully we have
- some content in. Enable using --enable-gtk-doc.
-
-GObject and Introspection:
-- Added harfbuzz-gobject library (hb-gobject.h) that has type
- bindings for all HarfBuzz objects and enums. Enable using
- --with-gobject.
-- Added gobject-introspection boilerplate. Nothing useful
- right now. Work in progress. Gets enabled automatically if
- --with-gobject is used. Override with --disable-introspection.
-
-OpenType shaper:
-- Apply 'mark' in Myanmar shaper.
-- Don't apply 'dlig' by default.
-
-Uniscribe shaper:
-- Support user features.
-- Fix loading of fonts that are also installed on the system.
-- Fix shaping of Arabic Presentation Forms.
-- Fix build with wide chars.
-
-CoreText shaper:
-- Support user features.
-
-Source changes:
-- hb_face_t code moved to hb-face.h / hb-face.cc.
-- Added hb-deprecated.h.
-
-API changes:
-- Added HB_DISABLE_DEPRECATED.
-- Deprecated HB_SCRIPT_CANADIAN_ABORIGINAL; replaced by
- HB_SCRIPT_CANADIAN_SYLLABICS.
-- Deprecated HB_BUFFER_FLAGS_DEFAULT; replaced by
- HB_BUFFER_FLAG_DEFAULT.
-- Deprecated HB_BUFFER_SERIALIZE_FLAGS_DEFAULT; replaced by
- HB_BUFFER_SERIALIZE_FLAG_DEFAULT.
-
-
-Overview of changes leading to 0.9.19
-Tuesday, July 16, 2013
-=====================================
-
-- Build fixes.
-- Better handling of multiple variation selectors in a row.
-- Pass on variation selector to GSUB if not consumed by cmap.
-- Fix undefined memory access.
-- Add Javanese config to Indic shaper.
-- Misc bug fixes.
-
-Overview of changes leading to 0.9.18
-Tuesday, May 28, 2013
-=====================================
-
-New build system:
-
-- All unneeded code is all disabled by default,
-
-- Uniscribe and CoreText shapers can be enabled with their --with options,
-
-- icu_le and old shapers cannot be enabled for now,
-
-- glib, freetype, and cairo will be detected automatically.
- They can be force on/off'ed with their --with options,
-
-- icu and graphite2 are default off, can be enabled with their --with
- options,
-
-Moreover, ICU support is now build into a separate library:
-libharfbuzz-icu.so, and a new harfbuzz-icu.pc is shipped for it.
-Distros can enable ICU now without every application on earth
-getting linked to via libharfbuzz.so.
-
-For distros I recommend that they make sure they are building --with-glib
---with-freetype --with-cairo, --with-icu, and optionally --with-graphite2;
-And package harfbuzz and harfbuzz-icu separately.
-
-
-Overview of changes leading to 0.9.17
-Monday, May 20, 2013
-=====================================
-
-- Build fixes.
-- Fix bug in hb_set_get_min().
-- Fix regression with Arabic mark positioning / width-zeroing.
-
-Overview of changes leading to 0.9.16
-Friday, April 19, 2013
-=====================================
-
-- Major speedup in OpenType lookup processing. With the Amiri
- Arabic font, this release is over 3x faster than previous
- release. All scripts / languages should see this speedup.
-
-- New --num-iterations option for hb-shape / hb-view; useful for
- profiling.
-
-Overview of changes leading to 0.9.15
-Friday, April 05, 2013
-=====================================
-
-- Build fixes.
-- Fix crasher in graphite2 shaper.
-- Fix Arabic mark width zeroing regression.
-- Don't compose Hangul jamo into Unicode syllables.
-
-
-Overview of changes leading to 0.9.14
-Thursday, March 21, 2013
-=====================================
-
-- Build fixes.
-- Fix time-consuming sanitize with malicious fonts.
-- Implement hb_buffer_deserialize_glyphs() for both json and text.
-- Do not ignore Hangul filler characters.
-- Indic fixes:
- * Fix Malayalam pre-base reordering interaction with post-forms.
- * Further adjust ZWJ handling. Should fix known regressions from
- 0.9.13.
-
-
-Overview of changes leading to 0.9.13
-Thursday, February 25, 2013
-=====================================
-
-- Build fixes.
-- Ngapi HarfBuzz Hackfest in London (February 2013):
- * Fixed all known Indic bugs,
- * New Win8-style Myanmar shaper,
- * New South-East Asian shaper for Tai Tham, Cham, and New Tai Lue,
- * Smartly ignore Default_Ignorable characters (joiners, etc) wheb
- matching GSUB/GPOS lookups,
- * Fix 'Phags-Pa U+A872 shaping,
- * Fix partial disabling of default-on features,
- * Allow disabling of TrueType kerning.
-- Fix possible crasher with broken fonts with overlapping tables.
-- Removed generated files from git again. So, one needs ragel to
- bootstrap from the git tree.
-
-API changes:
-- hb_shape() and related APIs now abort if buffer direction is
- HB_DIRECTION_INVALID. Previously, hb_shape() was calling
- hb_buffer_guess_segment_properties() on the buffer before
- shaping. The heuristics in that function are fragile. If the
- user really wants the old behvaior, they can call that function
- right before calling hb_shape() to get the old behavior.
-- hb_blob_create_sub_blob() always creates sub-blob with
- HB_MEMORY_MODE_READONLY. See comments for the reason.
-
-
-Overview of changes leading to 0.9.12
-Thursday, January 18, 2013
-=====================================
-
-- Build fixes for Sun compiler.
-- Minor bug fix.
-
-Overview of changes leading to 0.9.11
-Thursday, January 10, 2013
-=====================================
-
-- Build fixes.
-- Fix GPOS mark attachment with null Anchor offsets.
-- [Indic] Fix old-spec reordering of viramas if sequence ends in one.
-- Fix multi-threaded shaper data creation crash.
-- Add atomic ops for Solaris.
-
-API changes:
-- Rename hb_buffer_clear() to hb_buffer_clear_contents().
-
-
-Overview of changes leading to 0.9.10
-Thursday, January 3, 2013
-=====================================
-
-- [Indic] Fixed rendering of Malayalam dot-reph
-- Updated OT language tags.
-- Updated graphite2 backend.
-- Improved hb_ot_layout_get_size_params() logic.
-- Improve hb-shape/hb-view help output.
-- Fixed hb-set.h implementation to not crash.
-- Fixed various issues with hb_ot_layout_collect_lookups().
-- Various build fixes.
-
-New API:
-
-hb_graphite2_face_get_gr_face()
-hb_graphite2_font_get_gr_font()
-hb_coretext_face_get_cg_font()
-
-Modified API:
-
-hb_ot_layout_get_size_params()
-
-
-Overview of changes leading to 0.9.9
-Wednesday, December 5, 2012
-====================================
-
-- Fix build on Windows.
-- Minor improvements.
-
-
-Overview of changes leading to 0.9.8
-Tuesday, December 4, 2012
-====================================
-
-
-- Actually implement hb_shape_plan_get_shaper ().
-- Make UCDB data tables const.
-- Lots of internal refactoring in OTLayout tables.
-- Flesh out hb_ot_layout_lookup_collect_glyphs().
-
-New API:
-
-hb_ot_layout_collect_lookups()
-hb_ot_layout_get_size_params()
-
-
-Overview of changes leading to 0.9.7
-Sunday, November 21, 2012
-====================================
-
-
-HarfBuzz "All-You-Can-Eat-Sushi" (aka Vancouver) Hackfest and follow-on fixes.
-
-- Fix Arabic contextual joining using pre-context text.
-- Fix Sinhala "split matra" mess.
-- Fix Khmer shaping with broken fonts.
-- Implement Thai "PUA" shaping for old fonts.
-- Do NOT route Kharoshthi script through the Indic shaper.
-- Disable fallback positioning for Indic and Thai shapers.
-- Misc fixes.
-
-
-hb-shape / hb-view changes:
-
-- Add --text-before and --text-after
-- Add --bot / --eot / --preserve-default-ignorables
-- hb-shape --output-format=json
-
-
-New API:
-
-hb_buffer_clear()
-
-hb_buffer_flags_t
-
-HB_BUFFER_FLAGS_DEFAULT
-HB_BUFFER_FLAG_BOT
-HB_BUFFER_FLAG_EOT
-HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES
-
-hb_buffer_set_flags()
-hb_buffer_get_flags()
-
-HB_BUFFER_SERIALIZE_FLAGS
-hb_buffer_serialize_glyphs()
-hb_buffer_deserialize_glyphs()
-hb_buffer_serialize_list_formats()
-
-hb_set_add_range()
-hb_set_del_range()
-hb_set_get_population()
-hb_set_next_range()
-
-hb_face_[sg]et_glyph_count()
-
-hb_segment_properties_t
-HB_SEGMENT_PROPERTIES_DEFAULT
-hb_segment_properties_equal()
-hb_segment_properties_hash()
-
-hb_buffer_set_segment_properties()
-hb_buffer_get_segment_properties()
-
-hb_ot_layout_glyph_class_t
-hb_ot_layout_get_glyph_class()
-hb_ot_layout_get_glyphs_in_class()
-
-hb_shape_plan_t
-hb_shape_plan_create()
-hb_shape_plan_create_cached()
-hb_shape_plan_get_empty()
-hb_shape_plan_reference()
-hb_shape_plan_destroy()
-hb_shape_plan_set_user_data()
-hb_shape_plan_get_user_data()
-hb_shape_plan_execute()
-hb_shape_plan_get_shaper()
-
-hb_ot_shape_plan_collect_lookups()
-
-
-API changes:
-
-- Remove "mask" parameter from hb_buffer_add().
-- Rename hb_ot_layout_would_substitute_lookup() and hb_ot_layout_substitute_closure_lookup().
-- hb-set.h API const correction.
-- Renamed hb_set_min/max() to hb_set_get_min/max().
-- Rename hb_ot_layout_feature_get_lookup_indexes() to hb_ot_layout_feature_get_lookups().
-- Rename hb_buffer_guess_properties() to hb_buffer_guess_segment_properties().
-
-
-
-Overview of changes leading to 0.9.6
-Sunday, November 13, 2012
-====================================
-
-- Don't clear pre-context text if no new context is provided.
-- Fix ReverseChainingSubstLookup, which was totally borked.
-- Adjust output format of hb-shape a bit.
-- Include config.h.in in-tree. Makes it easier for alternate build systems.
-- Fix hb_buffer_set_length(buffer, 0) invalid memory allocation.
-- Use ICU LayoutEngine's C API instead of C++. Avoids much headache.
-- Drop glyphs for all of Unicode Default_Ignorable characters.
-- Misc build fixes.
-
-Arabic shaper:
-- Enable 'dlig' and 'mset' features in Arabic shaper.
-- Implement 'Phags-pa shaping, improve Mongolian.
-
-Indic shaper:
-- Decompose Sinhala split matras the way old HarfBuzz / Pango did.
-- Initial support for Consonant Medials.
-- Start adding new-style Myanmar shaping.
-- Make reph and 'pref' logic introspect the font.
-- Route Meetei-Mayek through the Indic shaper.
-- Don't apply 'liga' in Indic shaper.
-- Improve Malayalam pre-base reordering Ra interaction with Chillus.
-
-
-
-Overview of changes leading to 0.9.5
-Sunday, October 14, 2012
-====================================
-
-- Synthetic-GSUB Arabic fallback shaping.
-
-- Misc Indic improvements.
-
-- Add build system support for pthread.
-
-- Imported UCDN for in-tree Unicode callbacks implementation.
-
-- Context-aware Arabic joining.
-
-- Misc other fixes.
-
-- New API:
-
- hb_feature_to/from-string()
- hb_buffer_[sg]et_content_type()
-
-
-
-Overview of changes leading to 0.9.4
-Tuesday, Sep 03, 2012
-====================================
-
-- Indic improvements with old-spec Malayalam.
-
-- Better fallback glyph positioning, specially with Thai / Lao marks.
-
-- Implement dotted-circle insertion.
-
-- Better Arabic fallback shaping / ligation.
-
-- Added ICU LayoutEngine backend for testing. Call it by the 'icu_le' name.
-
-- Misc fixes.
-
-
-
-Overview of changes leading to 0.9.3
-Friday, Aug 18, 2012
-====================================
-
-- Fixed fallback mark positioning for left-to-right text.
-
-- Improve mark positioning for the remaining combining classes.
-
-- Unbreak Thai and fallback Arabic shaping.
-
-- Port Arabic shaper to shape-plan caching.
-
-- Use new ICU normalizer functions.
-
-
-
-Overview of changes leading to 0.9.2
-Friday, Aug 10, 2012
-====================================
-
-- Over a thousand commits! This is the first major release of HarfBuzz.
-
-- HarfBuzz is feature-complete now! It should be in par, or better, than
- both Pango's shapers and old HarfBuzz / Qt shapers.
-
-- New Indic shaper, supporting main Indic scripts, Sinhala, and Khmer.
-
-- Improved Arabic shaper, with fallback Arabic shaping, supporting Arabic,
- Sinhala, N'ko, Mongolian, and Mandaic.
-
-- New Thai / Lao shaper.
-
-- Tibetan / Hangul support in the generic shaper.
-
-- Synthetic GDEF support for fonts without a GDEF table.
-
-- Fallback mark positioning for fonts without a GPOS table.
-
-- Unicode normalization shaping heuristic during glyph mapping.
-
-- New experimental Graphite2 backend.
-
-- New Uniscribe backend (primarily for testing).
-
-- New CoreText backend (primarily for testing).
-
-- Major optimization and speedup.
-
-- Test suites and testing infrastructure (work in progress).
-
-- Greatly improved hb-view cmdline tool.
-
-- hb-shape cmdline tool.
-
-- Unicode 6.1 support.
-
-Summary of API changes:
-
-o Changed API:
-
- - Users are expected to only include main header files now (ie. hb.h,
- hb-glib.h, hb-ft.h, ...)
-
- - All struct tag names had their initial underscore removed.
- Ie. "struct _hb_buffer_t" is "struct hb_buffer_t" now.
-
- - All set_user_data() functions now take a "replace" boolean parameter.
-
- - hb_buffer_create() takes zero arguments now.
- Use hb_buffer_pre_allocate() to pre-allocate.
-
- - hb_buffer_add_utf*() now accept -1 for length parameters,
- meaning "nul-terminated".
-
- - hb_direction_t enum values changed.
-
- - All *_from_string() APIs now take a length parameter to allow for
- non-nul-terminated strings. A -1 length means "nul-terminated".
-
- - Typedef for hb_language_t changed.
-
- - hb_get_table_func_t renamed to hb_reference_table_func_t.
-
- - hb_ot_layout_table_choose_script()
-
- - Various renames in hb-unicode.h.
-
-o New API:
-
- - hb_buffer_guess_properties()
- Automatically called by hb_shape().
-
- - hb_buffer_normalize_glyphs()
-
- - hb_tag_from_string()
-
- - hb-coretext.h
-
- - hb-uniscribe.h
-
- - hb_face_reference_blob()
- - hb_face_[sg]et_index()
- - hb_face_set_upem()
-
- - hb_font_get_glyph_name_func_t
- hb_font_get_glyph_from_name_func_t
- hb_font_funcs_set_glyph_name_func()
- hb_font_funcs_set_glyph_from_name_func()
- hb_font_get_glyph_name()
- hb_font_get_glyph_from_name()
- hb_font_glyph_to_string()
- hb_font_glyph_from_string()
-
- - hb_font_set_funcs_data()
-
- - hb_ft_font_set_funcs()
- - hb_ft_font_get_face()
-
- - hb-gobject.h (work in progress)
-
- - hb_ot_shape_glyphs_closure()
- hb_ot_layout_substitute_closure_lookup()
-
- - hb-set.h
-
- - hb_shape_full()
-
- - hb_unicode_combining_class_t
-
- - hb_unicode_compose_func_t
- hb_unicode_decompose_func_t
- hb_unicode_decompose_compatibility_func_t
- hb_unicode_funcs_set_compose_func()
- hb_unicode_funcs_set_decompose_func()
- hb_unicode_funcs_set_decompose_compatibility_func()
- hb_unicode_compose()
- hb_unicode_decompose()
- hb_unicode_decompose_compatibility()
-
-o Removed API:
-
- - hb_ft_get_font_funcs()
-
- - hb_ot_layout_substitute_start()
- hb_ot_layout_substitute_lookup()
- hb_ot_layout_substitute_finish()
- hb_ot_layout_position_start()
- hb_ot_layout_position_lookup()
- hb_ot_layout_position_finish()
-
-
-
-Overview of changes leading to 0.6.0
-Friday, May 27, 2011
-====================================
-
-- Vertical text support in GPOS
-- Almost all API entries have unit tests now, under test/
-- All thread-safety issues are fixed
-
-Summary of API changes follows.
-
-
-* Simple Types API:
-
- o New API:
- HB_LANGUAGE_INVALID
- hb_language_get_default()
- hb_direction_to_string()
- hb_direction_from_string()
- hb_script_get_horizontal_direction()
- HB_UNTAG()
-
- o Renamed API:
- hb_category_t renamed to hb_unicode_general_category_t
-
- o Changed API:
- hb_language_t is a typed pointers now
-
- o Removed API:
- HB_TAG_STR()
-
-
-* Use ISO 15924 tags for hb_script_t:
-
- o New API:
- hb_script_from_iso15924_tag()
- hb_script_to_iso15924_tag()
- hb_script_from_string()
-
- o Changed API:
- HB_SCRIPT_* enum members changed value.
-
-
-* Buffer API streamlined:
-
- o New API:
- hb_buffer_reset()
- hb_buffer_set_length()
- hb_buffer_allocation_successful()
-
- o Renamed API:
- hb_buffer_ensure() renamed to hb_buffer_pre_allocate()
- hb_buffer_add_glyph() renamed to hb_buffer_add()
-
- o Removed API:
- hb_buffer_clear()
- hb_buffer_clear_positions()
-
- o Changed API:
- hb_buffer_get_glyph_infos() takes an out length parameter now
- hb_buffer_get_glyph_positions() takes an out length parameter now
-
-
-* Blob API streamlined:
-
- o New API:
- hb_blob_get_data()
- hb_blob_get_data_writable()
-
- o Renamed API:
- hb_blob_create_empty() renamed to hb_blob_get_empty()
-
- o Removed API:
- hb_blob_lock()
- hb_blob_unlock()
- hb_blob_is_writable()
- hb_blob_try_writable()
-
- o Changed API:
- hb_blob_create() takes user_data before destroy now
-
-
-* Unicode functions API:
-
- o Unicode function vectors can subclass other unicode function vectors now.
- Unimplemented callbacks in the subclass automatically chainup to the parent.
-
- o All hb_unicode_funcs_t callbacks take a user_data now. Their setters
- take a user_data and its respective destroy callback.
-
- o New API:
- hb_unicode_funcs_get_empty()
- hb_unicode_funcs_get_default()
- hb_unicode_funcs_get_parent()
-
- o Changed API:
- hb_unicode_funcs_create() now takes a parent_funcs.
-
- o Removed func getter functions:
- hb_unicode_funcs_get_mirroring_func()
- hb_unicode_funcs_get_general_category_func()
- hb_unicode_funcs_get_script_func()
- hb_unicode_funcs_get_combining_class_func()
- hb_unicode_funcs_get_eastasian_width_func()
-
-
-* Face API:
-
- o Renamed API:
- hb_face_get_table() renamed to hb_face_reference_table()
- hb_face_create_for_data() renamed to hb_face_create()
-
- o Changed API:
- hb_face_create_for_tables() takes user_data before destroy now
- hb_face_reference_table() returns empty blob instead of NULL
- hb_get_table_func_t accepts the face as first parameter now
-
-* Font API:
-
- o Fonts can subclass other fonts now. Unimplemented callbacks in the
- subclass automatically chainup to the parent. When chaining up,
- scale is adjusted if the parent font has a different scale.
-
- o All hb_font_funcs_t callbacks take a user_data now. Their setters
- take a user_data and its respective destroy callback.
-
- o New API:
- hb_font_get_parent()
- hb_font_funcs_get_empty()
- hb_font_create_sub_font()
-
- o Removed API:
- hb_font_funcs_copy()
- hb_font_unset_funcs()
-
- o Removed func getter functions:
- hb_font_funcs_get_glyph_func()
- hb_font_funcs_get_glyph_advance_func()
- hb_font_funcs_get_glyph_extents_func()
- hb_font_funcs_get_contour_point_func()
- hb_font_funcs_get_kerning_func()
-
- o Changed API:
- hb_font_create() takes a face and references it now
- hb_font_set_funcs() takes user_data before destroy now
- hb_font_set_scale() accepts signed integers now
- hb_font_get_contour_point_func_t now takes glyph first, then point_index
- hb_font_get_glyph_func_t returns a success boolean now
-
-
-* Changed object model:
-
- o All object types have a _get_empty() now:
- hb_blob_get_empty()
- hb_buffer_get_empty()
- hb_face_get_empty()
- hb_font_get_empty()
- hb_font_funcs_get_empty()
- hb_unicode_funcs_get_empty()
-
- o Added _set_user_data() and _get_user_data() for all object types:
- hb_blob_get_user_data()
- hb_blob_set_user_data()
- hb_buffer_get_user_data()
- hb_buffer_set_user_data()
- hb_face_get_user_data()
- hb_face_set_user_data()
- hb_font_funcs_get_user_data()
- hb_font_funcs_set_user_data()
- hb_font_get_user_data()
- hb_font_set_user_data()
- hb_unicode_funcs_get_user_data()
- hb_unicode_funcs_set_user_data()
-
- o Removed the _get_reference_count() from all object types:
- hb_blob_get_reference_count()
- hb_buffer_get_reference_count()
- hb_face_get_reference_count()
- hb_font_funcs_get_reference_count()
- hb_font_get_reference_count()
- hb_unicode_funcs_get_reference_count()
-
- o Added _make_immutable() and _is_immutable() for all object types except for buffer:
- hb_blob_make_immutable()
- hb_blob_is_immutable()
- hb_face_make_immutable()
- hb_face_is_immutable()
-
-
-* Changed API for vertical text support
-
- o The following callbacks where removed:
- hb_font_get_glyph_advance_func_t
- hb_font_get_kerning_func_t
-
- o The following new callbacks added instead:
- hb_font_get_glyph_h_advance_func_t
- hb_font_get_glyph_v_advance_func_t
- hb_font_get_glyph_h_origin_func_t
- hb_font_get_glyph_v_origin_func_t
- hb_font_get_glyph_h_kerning_func_t
- hb_font_get_glyph_v_kerning_func_t
-
- o The following API removed as such:
- hb_font_funcs_set_glyph_advance_func()
- hb_font_funcs_set_kerning_func()
- hb_font_get_glyph_advance()
- hb_font_get_kerning()
-
- o New API added instead:
- hb_font_funcs_set_glyph_h_advance_func()
- hb_font_funcs_set_glyph_v_advance_func()
- hb_font_funcs_set_glyph_h_origin_func()
- hb_font_funcs_set_glyph_v_origin_func()
- hb_font_funcs_set_glyph_h_kerning_func()
- hb_font_funcs_set_glyph_v_kerning_func()
- hb_font_get_glyph_h_advance()
- hb_font_get_glyph_v_advance()
- hb_font_get_glyph_h_origin()
- hb_font_get_glyph_v_origin()
- hb_font_get_glyph_h_kerning()
- hb_font_get_glyph_v_kerning()
-
- o The following higher-leve API added for convenience:
- hb_font_get_glyph_advance_for_direction()
- hb_font_get_glyph_origin_for_direction()
- hb_font_add_glyph_origin_for_direction()
- hb_font_subtract_glyph_origin_for_direction()
- hb_font_get_glyph_kerning_for_direction()
- hb_font_get_glyph_extents_for_origin()
- hb_font_get_glyph_contour_point_for_origin()
-
-
-* OpenType Layout API:
-
- o New API:
- hb_ot_layout_position_start()
- hb_ot_layout_substitute_start()
- hb_ot_layout_substitute_finish()
-
-
-* Glue code:
-
- o New API:
- hb_glib_script_to_script()
- hb_glib_script_from_script()
- hb_icu_script_to_script()
- hb_icu_script_from_script()
-
-
-* Version API added:
-
- o New API:
- HB_VERSION_MAJOR
- HB_VERSION_MINOR
- HB_VERSION_MICRO
- HB_VERSION_STRING
- HB_VERSION_CHECK()
- hb_version()
- hb_version_string()
- hb_version_check()
-
-
diff --git a/src/3rdparty/harfbuzz-ng/README.md b/src/3rdparty/harfbuzz-ng/README.md
index 4202961e04..da4de65cf0 100644
--- a/src/3rdparty/harfbuzz-ng/README.md
+++ b/src/3rdparty/harfbuzz-ng/README.md
@@ -2,16 +2,21 @@
[![CircleCI Build Status](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main.svg?style=svg)](https://circleci.com/gh/harfbuzz/harfbuzz/tree/main)
[![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/harfbuzz.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/15166/badge.svg)](https://scan.coverity.com/projects/harfbuzz)
-[![Codacy Badge](https://app.codacy.com/project/badge/Grade/89c872f5ce1c42af802602bfcd15d90a)](https://www.codacy.com/gh/harfbuzz/harfbuzz/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=harfbuzz/harfbuzz&amp;utm_campaign=Badge_Grade)
+[![Codacy Badge](https://app.codacy.com/project/badge/Grade/89c872f5ce1c42af802602bfcd15d90a)](https://app.codacy.com/gh/harfbuzz/harfbuzz/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
[![Codecov Code Coverage](https://codecov.io/gh/harfbuzz/harfbuzz/branch/main/graph/badge.svg)](https://codecov.io/gh/harfbuzz/harfbuzz)
[![Packaging status](https://repology.org/badge/tiny-repos/harfbuzz.svg)](https://repology.org/project/harfbuzz/versions)
+[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/harfbuzz/harfbuzz/badge)](https://securityscorecards.dev/viewer/?uri=github.com/harfbuzz/harfbuzz)
+
# HarfBuzz
HarfBuzz is a text shaping engine. It primarily supports [OpenType][1], but also
[Apple Advanced Typography][2]. HarfBuzz is used in Android, Chrome,
-ChromeOS, Firefox, GNOME, GTK+, KDE, LibreOffice, OpenJDK, PlayStation, Qt,
-XeTeX, and other places.
+ChromeOS, Firefox, GNOME, GTK+, KDE, Qt, LibreOffice, OpenJDK, XeTeX,
+PlayStation, Microsoft Edge, Adobe Photoshop, Illustrator, InDesign,
+Godot Engine, and other places.
+
+[![xkcd-derived image](xkcd.png)](https://xkcd.com/2347/)
For bug reports, mailing list, and other information please visit:
@@ -26,8 +31,8 @@ For user manual as well as API documentation, check: https://harfbuzz.github.io
## Download
For tarball releases of HarfBuzz, look [here][3]. At the same place you
-will also find Win32/Win64 binary bundles that include libharfbuzz DLL,
-hb-view.exe, hb-shape.exe, and all dependencies.
+will also find Win32/Win64 binary bundles that include `libharfbuzz` DLL,
+`hb-view.exe`, `hb-shape.exe`, and all dependencies.
The canonical source tree is available on [github][4].
@@ -67,9 +72,9 @@ For a comparison of old vs new HarfBuzz memory consumption see [this][10].
## Name
-HarfBuzz (حرف‌باز) is my Persian translation of “[OpenType][1]”,
-transliterated using the Latin script. It sports a second meaning, but that
-ain’t translatable.
+HarfBuzz (حرف‌باز) is the literal Persian translation of “[OpenType][1]”,
+transliterated using the Latin script. It also means "talkative" or
+"glib" (also a nod to the GNOME project where HarfBuzz originates from).
> Background: Originally there was this font format called TrueType. People and
> companies started calling their type engines all things ending in Type:
diff --git a/src/3rdparty/harfbuzz-ng/import_from_tarball.sh b/src/3rdparty/harfbuzz-ng/import_from_tarball.sh
index 627cc51b28..00d069fd79 100644
--- a/src/3rdparty/harfbuzz-ng/import_from_tarball.sh
+++ b/src/3rdparty/harfbuzz-ng/import_from_tarball.sh
@@ -1,44 +1,8 @@
#! /bin/sh
-#############################################################################
-##
-## Copyright (C) 2021 The Qt Company Ltd.
-## Contact: https://www.qt.io/licensing/
-##
-## This file is the build configuration utility 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$
-##
-#############################################################################
-
+# Copyright (C) 2021 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+#
# This is a small script to copy the required files from a harfbuzz tarball
# into 3rdparty/harfbuzz-ng/ . Documentation, tests, demos etc. are not imported.
# Steps:
@@ -81,7 +45,6 @@ copy_file_or_dir() {
FILES=(AUTHORS
COPYING
- NEWS
README.md
THANKS
)
diff --git a/src/3rdparty/harfbuzz-ng/qt_attribution.json b/src/3rdparty/harfbuzz-ng/qt_attribution.json
index 1779409e3b..8b862c418a 100644
--- a/src/3rdparty/harfbuzz-ng/qt_attribution.json
+++ b/src/3rdparty/harfbuzz-ng/qt_attribution.json
@@ -3,29 +3,31 @@
"Name": "HarfBuzz-NG",
"QDocModule": "qtgui",
"QtUsage": "Optionally used in Qt GUI. Configure with -system-harfbuzz to force the use of the system library, or -qt-harfbuzz to link statically to the library that is bundled with your Qt version.",
+ "SecurityCritical": true,
"Description": "HarfBuzz is an OpenType text shaping engine.",
"Homepage": "http://harfbuzz.org",
- "Version": "7.0.1",
+ "Version": "8.4.0",
+ "DownloadLocation": "https://github.com/harfbuzz/harfbuzz/releases/tag/8.4.0",
"License": "MIT License",
"LicenseId": "MIT",
"LicenseFile": "COPYING",
- "Copyright": "Copyright © 2010-2022 Google, Inc.
- Copyright © 2015-2020 Ebrahim Byagowi
- Copyright © 2019,2020 Facebook, Inc.
- Copyright © 2012,2015 Mozilla Foundation
- Copyright © 2011 Codethink Limited
- Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
- Copyright © 2009 Keith Stribley
- Copyright © 2011 Martin Hosken and SIL International
- Copyright © 2007 Chris Wilson
- Copyright © 2005,2006,2020,2021,2022,2023 Behdad Esfahbod
- Copyright © 2004,2007,2008,2009,2010,2013,2021,2022,2023 Red Hat, Inc.
- Copyright © 1998-2005 David Turner and Werner Lemberg
- Copyright © 2016 Igalia S.L.
- Copyright © 2022 Matthias Clasen
- Copyright © 2018,2021 Khaled Hosny
- Copyright © 2018,2019,2020 Adobe, Inc
- Copyright © 2013-2015 Alexei Podtelezhnikov"
+ "Copyright": ["Copyright © 2010-2022 Google, Inc.",
+ "Copyright © 2015-2020 Ebrahim Byagowi",
+ "Copyright © 2019,2020 Facebook, Inc.",
+ "Copyright © 2012,2015 Mozilla Foundation",
+ "Copyright © 2011 Codethink Limited",
+ "Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)",
+ "Copyright © 2009 Keith Stribley",
+ "Copyright © 2011 Martin Hosken and SIL International",
+ "Copyright © 2007 Chris Wilson",
+ "Copyright © 2005,2006,2020,2021,2022,2023 Behdad Esfahbod",
+ "Copyright © 2004,2007,2008,2009,2010,2013,2021,2022,2023 Red Hat, Inc.",
+ "Copyright © 1998-2005 David Turner and Werner Lemberg",
+ "Copyright © 2016 Igalia S.L.",
+ "Copyright © 2022 Matthias Clasen",
+ "Copyright © 2018,2021 Khaled Hosny",
+ "Copyright © 2018,2019,2020 Adobe, Inc",
+ "Copyright © 2013-2015 Alexei Podtelezhnikov"]
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Color/CBDT/CBDT.hh b/src/3rdparty/harfbuzz-ng/src/OT/Color/CBDT/CBDT.hh
index b125052344..bcf1848f49 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Color/CBDT/CBDT.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Color/CBDT/CBDT.hh
@@ -204,6 +204,7 @@ struct IndexSubtable
{
TRACE_SANITIZE (this);
if (!u.header.sanitize (c)) return_trace (false);
+ hb_barrier ();
switch (u.header.indexFormat)
{
case 1: return_trace (u.format1.sanitize (c, glyph_count));
@@ -378,6 +379,7 @@ struct IndexSubtableRecord
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
firstGlyphIndex <= lastGlyphIndex &&
offsetToSubtable.sanitize (c, base, lastGlyphIndex - firstGlyphIndex + 1));
}
@@ -397,7 +399,6 @@ struct IndexSubtableRecord
TRACE_SERIALIZE (this);
auto *subtable = c->serializer->start_embed<IndexSubtable> ();
- if (unlikely (!subtable)) return_trace (false);
if (unlikely (!c->serializer->extend_min (subtable))) return_trace (false);
auto *old_subtable = get_subtable (base);
@@ -545,7 +546,8 @@ struct IndexSubtableArray
const IndexSubtableRecord*>> *lookup /* OUT */) const
{
bool start_glyph_is_set = false;
- for (hb_codepoint_t new_gid = 0; new_gid < c->plan->num_output_glyphs (); new_gid++)
+ unsigned num_glyphs = c->plan->num_output_glyphs ();
+ for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++)
{
hb_codepoint_t old_gid;
if (unlikely (!c->plan->old_gid_for_new_gid (new_gid, &old_gid))) continue;
@@ -576,9 +578,6 @@ struct IndexSubtableArray
{
TRACE_SUBSET (this);
- auto *dst = c->serializer->start_embed<IndexSubtableArray> ();
- if (unlikely (!dst)) return_trace (false);
-
hb_vector_t<hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*>> lookup;
build_lookup (c, bitmap_size_context, &lookup);
if (unlikely (!c->serializer->propagate_error (lookup)))
@@ -638,6 +637,7 @@ struct BitmapSizeTable
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
indexSubtableArrayOffset.sanitize (c, base, numberOfIndexSubtables) &&
horizontal.sanitize (c) &&
vertical.sanitize (c));
@@ -741,7 +741,9 @@ struct CBLC
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
likely (version.major == 2 || version.major == 3) &&
+ hb_barrier () &&
sizeTables.sanitize (c, this));
}
@@ -978,6 +980,7 @@ struct CBDT
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
likely (version.major == 2 || version.major == 3));
}
@@ -993,12 +996,10 @@ CBLC::subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- auto *cblc_prime = c->serializer->start_embed<CBLC> ();
-
// Use a vector as a secondary buffer as the tables need to be built in parallel.
hb_vector_t<char> cbdt_prime;
- if (unlikely (!cblc_prime)) return_trace (false);
+ auto *cblc_prime = c->serializer->start_embed<CBLC> ();
if (unlikely (!c->serializer->extend_min (cblc_prime))) return_trace (false);
cblc_prime->version = version;
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh b/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh
index 31be6585dd..623775a771 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Color/COLR/COLR.hh
@@ -40,7 +40,6 @@
*/
#define HB_OT_TAG_COLR HB_TAG('C','O','L','R')
-
namespace OT {
struct hb_paint_context_t;
}
@@ -54,6 +53,7 @@ struct Paint;
struct hb_paint_context_t :
hb_dispatch_context_t<hb_paint_context_t>
{
+ const char *get_name () { return "PAINT"; }
template <typename T>
return_t dispatch (const T &obj) { obj.paint_glyph (this); return hb_empty_t (); }
static return_t default_return_value () { return hb_empty_t (); }
@@ -68,7 +68,9 @@ public:
hb_font_t *font;
unsigned int palette_index;
hb_color_t foreground;
- VarStoreInstancer &instancer;
+ ItemVarStoreInstancer &instancer;
+ hb_map_t current_glyphs;
+ hb_map_t current_layers;
int depth_left = HB_MAX_NESTING_LEVEL;
int edge_count = HB_COLRV1_MAX_EDGE_COUNT;
@@ -78,7 +80,7 @@ public:
hb_font_t *font_,
unsigned int palette_,
hb_color_t foreground_,
- VarStoreInstancer &instancer_) :
+ ItemVarStoreInstancer &instancer_) :
base (base_),
funcs (funcs_),
data (data_),
@@ -242,10 +244,15 @@ struct Variable
void closurev1 (hb_colrv1_closure_context_t* c) const
{ value.closurev1 (c); }
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
- if (!value.subset (c)) return_trace (false);
+ if (!value.subset (c, instancer, varIdxBase)) return_trace (false);
+ if (c->plan->all_axes_pinned)
+ return_trace (true);
+
+ //TODO: update varIdxBase for partial-instancing
return_trace (c->serializer->embed (varIdxBase));
}
@@ -257,12 +264,13 @@ struct Variable
void paint_glyph (hb_paint_context_t *c) const
{
+ TRACE_PAINT (this);
value.paint_glyph (c, varIdxBase);
}
void get_color_stop (hb_paint_context_t *c,
hb_color_stop_t *stop,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
value.get_color_stop (c, stop, varIdxBase, instancer);
}
@@ -277,7 +285,7 @@ struct Variable
public:
VarIdx varIdxBase;
public:
- DEFINE_SIZE_STATIC (4 + T::static_size);
+ DEFINE_SIZE_MIN (VarIdx::static_size + T::min_size);
};
template <typename T>
@@ -296,10 +304,11 @@ struct NoVariable
void closurev1 (hb_colrv1_closure_context_t* c) const
{ value.closurev1 (c); }
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
- return_trace (value.subset (c));
+ return_trace (value.subset (c, instancer, varIdxBase));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -310,12 +319,13 @@ struct NoVariable
void paint_glyph (hb_paint_context_t *c) const
{
+ TRACE_PAINT (this);
value.paint_glyph (c, varIdxBase);
}
void get_color_stop (hb_paint_context_t *c,
hb_color_stop_t *stop,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
value.get_color_stop (c, stop, VarIdx::NO_VARIATION, instancer);
}
@@ -327,7 +337,7 @@ struct NoVariable
T value;
public:
- DEFINE_SIZE_STATIC (T::static_size);
+ DEFINE_SIZE_MIN (T::min_size);
};
// Color structures
@@ -337,11 +347,20 @@ struct ColorStop
void closurev1 (hb_colrv1_closure_context_t* c) const
{ c->add_palette_index (paletteIndex); }
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer,
+ uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
+
+ if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+ {
+ out->stopOffset.set_float (stopOffset.to_float(instancer (varIdxBase, 0)));
+ out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 1)));
+ }
+
return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex),
HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
@@ -355,7 +374,7 @@ struct ColorStop
void get_color_stop (hb_paint_context_t *c,
hb_color_stop_t *out,
uint32_t varIdx,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
out->offset = stopOffset.to_float(instancer (varIdx, 0));
out->color = c->get_color (paletteIndex,
@@ -390,11 +409,11 @@ struct ColorLine
stop.closurev1 (c);
}
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
- if (unlikely (!out)) return_trace (false);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
if (!c->serializer->check_assign (out->extend, extend, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
@@ -402,7 +421,7 @@ struct ColorLine
for (const auto& stop : stops.iter ())
{
- if (!stop.subset (c)) return_trace (false);
+ if (!stop.subset (c, instancer)) return_trace (false);
}
return_trace (true);
}
@@ -420,7 +439,7 @@ struct ColorLine
unsigned int start,
unsigned int *count,
hb_color_stop_t *color_stops,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
unsigned int len = stops.len;
@@ -523,8 +542,28 @@ struct Affine2x3
return_trace (c->check_struct (this));
}
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer,
+ uint32_t varIdxBase) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+ if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+ {
+ out->xx.set_float (xx.to_float(instancer (varIdxBase, 0)));
+ out->yx.set_float (yx.to_float(instancer (varIdxBase, 1)));
+ out->xy.set_float (xy.to_float(instancer (varIdxBase, 2)));
+ out->yy.set_float (yy.to_float(instancer (varIdxBase, 3)));
+ out->dx.set_float (dx.to_float(instancer (varIdxBase, 4)));
+ out->dy.set_float (dy.to_float(instancer (varIdxBase, 5)));
+ }
+ return_trace (true);
+ }
+
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
+ TRACE_PAINT (this);
c->funcs->push_transform (c->data,
xx.to_float (c->instancer (varIdxBase, 0)),
yx.to_float (c->instancer (varIdxBase, 1)),
@@ -548,7 +587,8 @@ struct PaintColrLayers
{
void closurev1 (hb_colrv1_closure_context_t* c) const;
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer HB_UNUSED) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
@@ -579,11 +619,20 @@ struct PaintSolid
void closurev1 (hb_colrv1_closure_context_t* c) const
{ c->add_palette_index (paletteIndex); }
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer,
+ uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
+
+ if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+ out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 0)));
+
+ if (format == 3 && c->plan->all_axes_pinned)
+ out->format = 2;
+
return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex),
HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
@@ -596,6 +645,7 @@ struct PaintSolid
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
+ TRACE_PAINT (this);
hb_bool_t is_foreground;
hb_color_t color;
@@ -618,13 +668,28 @@ struct PaintLinearGradient
void closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+colorLine).closurev1 (c); }
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer,
+ uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
- return_trace (out->colorLine.serialize_subset (c, colorLine, this));
+ if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+ {
+ out->x0 = x0 + (int) roundf (instancer (varIdxBase, 0));
+ out->y0 = y0 + (int) roundf (instancer (varIdxBase, 1));
+ out->x1 = x1 + (int) roundf (instancer (varIdxBase, 2));
+ out->y1 = y1 + (int) roundf (instancer (varIdxBase, 3));
+ out->x2 = x2 + (int) roundf (instancer (varIdxBase, 4));
+ out->y2 = y2 + (int) roundf (instancer (varIdxBase, 5));
+ }
+
+ if (format == 5 && c->plan->all_axes_pinned)
+ out->format = 4;
+
+ return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -635,6 +700,7 @@ struct PaintLinearGradient
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
+ TRACE_PAINT (this);
hb_color_line_t cl = {
(void *) &(this+colorLine),
(this+colorLine).static_get_color_stops, c,
@@ -669,13 +735,28 @@ struct PaintRadialGradient
void closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+colorLine).closurev1 (c); }
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer,
+ uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
- return_trace (out->colorLine.serialize_subset (c, colorLine, this));
+ if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+ {
+ out->x0 = x0 + (int) roundf (instancer (varIdxBase, 0));
+ out->y0 = y0 + (int) roundf (instancer (varIdxBase, 1));
+ out->radius0 = radius0 + (unsigned) roundf (instancer (varIdxBase, 2));
+ out->x1 = x1 + (int) roundf (instancer (varIdxBase, 3));
+ out->y1 = y1 + (int) roundf (instancer (varIdxBase, 4));
+ out->radius1 = radius1 + (unsigned) roundf (instancer (varIdxBase, 5));
+ }
+
+ if (format == 7 && c->plan->all_axes_pinned)
+ out->format = 6;
+
+ return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -686,6 +767,7 @@ struct PaintRadialGradient
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
+ TRACE_PAINT (this);
hb_color_line_t cl = {
(void *) &(this+colorLine),
(this+colorLine).static_get_color_stops, c,
@@ -720,13 +802,26 @@ struct PaintSweepGradient
void closurev1 (hb_colrv1_closure_context_t* c) const
{ (this+colorLine).closurev1 (c); }
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer,
+ uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
- return_trace (out->colorLine.serialize_subset (c, colorLine, this));
+ if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+ {
+ out->centerX = centerX + (int) roundf (instancer (varIdxBase, 0));
+ out->centerY = centerY + (int) roundf (instancer (varIdxBase, 1));
+ out->startAngle.set_float (startAngle.to_float (instancer (varIdxBase, 2)));
+ out->endAngle.set_float (endAngle.to_float (instancer (varIdxBase, 3)));
+ }
+
+ if (format == 9 && c->plan->all_axes_pinned)
+ out->format = 8;
+
+ return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -737,6 +832,7 @@ struct PaintSweepGradient
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
+ TRACE_PAINT (this);
hb_color_line_t cl = {
(void *) &(this+colorLine),
(this+colorLine).static_get_color_stops, c,
@@ -746,8 +842,8 @@ struct PaintSweepGradient
c->funcs->sweep_gradient (c->data, &cl,
centerX + c->instancer (varIdxBase, 0),
centerY + c->instancer (varIdxBase, 1),
- (startAngle.to_float (c->instancer (varIdxBase, 2)) + 1) * (float) M_PI,
- (endAngle.to_float (c->instancer (varIdxBase, 3)) + 1) * (float) M_PI);
+ (startAngle.to_float (c->instancer (varIdxBase, 2)) + 1) * HB_PI,
+ (endAngle.to_float (c->instancer (varIdxBase, 3)) + 1) * HB_PI);
}
HBUINT8 format; /* format = 8(noVar) or 9 (Var) */
@@ -766,7 +862,8 @@ struct PaintGlyph
{
void closurev1 (hb_colrv1_closure_context_t* c) const;
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
@@ -776,7 +873,7 @@ struct PaintGlyph
HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
- return_trace (out->paint.serialize_subset (c, paint, this));
+ return_trace (out->paint.serialize_subset (c, paint, this, instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -787,6 +884,7 @@ struct PaintGlyph
void paint_glyph (hb_paint_context_t *c) const
{
+ TRACE_PAINT (this);
c->funcs->push_inverse_root_transform (c->data, c->font);
c->funcs->push_clip_glyph (c->data, gid, c->font);
c->funcs->push_root_transform (c->data, c->font);
@@ -807,7 +905,8 @@ struct PaintColrGlyph
{
void closurev1 (hb_colrv1_closure_context_t* c) const;
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer HB_UNUSED) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
@@ -836,13 +935,16 @@ struct PaintTransform
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
- if (!out->transform.serialize_copy (c->serializer, transform, this)) return_trace (false);
- return_trace (out->src.serialize_subset (c, src, this));
+ if (!out->transform.serialize_subset (c, transform, this, instancer)) return_trace (false);
+ if (format == 13 && c->plan->all_axes_pinned)
+ out->format = 12;
+ return_trace (out->src.serialize_subset (c, src, this, instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -855,6 +957,7 @@ struct PaintTransform
void paint_glyph (hb_paint_context_t *c) const
{
+ TRACE_PAINT (this);
(this+transform).paint_glyph (c);
c->recurse (this+src);
c->funcs->pop_transform (c->data);
@@ -871,13 +974,24 @@ struct PaintTranslate
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer,
+ uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
- return_trace (out->src.serialize_subset (c, src, this));
+ if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+ {
+ out->dx = dx + (int) roundf (instancer (varIdxBase, 0));
+ out->dy = dy + (int) roundf (instancer (varIdxBase, 1));
+ }
+
+ if (format == 15 && c->plan->all_axes_pinned)
+ out->format = 14;
+
+ return_trace (out->src.serialize_subset (c, src, this, instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -888,6 +1002,7 @@ struct PaintTranslate
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
+ TRACE_PAINT (this);
float ddx = dx + c->instancer (varIdxBase, 0);
float ddy = dy + c->instancer (varIdxBase, 1);
@@ -908,13 +1023,24 @@ struct PaintScale
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer,
+ uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
- return_trace (out->src.serialize_subset (c, src, this));
+ if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+ {
+ out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0)));
+ out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1)));
+ }
+
+ if (format == 17 && c->plan->all_axes_pinned)
+ out->format = 16;
+
+ return_trace (out->src.serialize_subset (c, src, this, instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -925,6 +1051,7 @@ struct PaintScale
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
+ TRACE_PAINT (this);
float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
@@ -945,13 +1072,26 @@ struct PaintScaleAroundCenter
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer,
+ uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
- return_trace (out->src.serialize_subset (c, src, this));
+ if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+ {
+ out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0)));
+ out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1)));
+ out->centerX = centerX + (int) roundf (instancer (varIdxBase, 2));
+ out->centerY = centerY + (int) roundf (instancer (varIdxBase, 3));
+ }
+
+ if (format == 19 && c->plan->all_axes_pinned)
+ out->format = 18;
+
+ return_trace (out->src.serialize_subset (c, src, this, instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -962,6 +1102,7 @@ struct PaintScaleAroundCenter
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
+ TRACE_PAINT (this);
float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
float tCenterX = centerX + c->instancer (varIdxBase, 2);
@@ -990,13 +1131,21 @@ struct PaintScaleUniform
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer,
+ uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
- return_trace (out->src.serialize_subset (c, src, this));
+ if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+ out->scale.set_float (scale.to_float (instancer (varIdxBase, 0)));
+
+ if (format == 21 && c->plan->all_axes_pinned)
+ out->format = 20;
+
+ return_trace (out->src.serialize_subset (c, src, this, instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -1007,6 +1156,7 @@ struct PaintScaleUniform
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
+ TRACE_PAINT (this);
float s = scale.to_float (c->instancer (varIdxBase, 0));
bool p1 = c->funcs->push_scale (c->data, s, s);
@@ -1025,13 +1175,25 @@ struct PaintScaleUniformAroundCenter
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer,
+ uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
- return_trace (out->src.serialize_subset (c, src, this));
+ if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+ {
+ out->scale.set_float (scale.to_float (instancer (varIdxBase, 0)));
+ out->centerX = centerX + (int) roundf (instancer (varIdxBase, 1));
+ out->centerY = centerY + (int) roundf (instancer (varIdxBase, 2));
+ }
+
+ if (format == 23 && c->plan->all_axes_pinned)
+ out->format = 22;
+
+ return_trace (out->src.serialize_subset (c, src, this, instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -1042,6 +1204,7 @@ struct PaintScaleUniformAroundCenter
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
+ TRACE_PAINT (this);
float s = scale.to_float (c->instancer (varIdxBase, 0));
float tCenterX = centerX + c->instancer (varIdxBase, 1);
float tCenterY = centerY + c->instancer (varIdxBase, 2);
@@ -1068,13 +1231,21 @@ struct PaintRotate
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer,
+ uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
- return_trace (out->src.serialize_subset (c, src, this));
+ if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+ out->angle.set_float (angle.to_float (instancer (varIdxBase, 0)));
+
+ if (format == 25 && c->plan->all_axes_pinned)
+ out->format = 24;
+
+ return_trace (out->src.serialize_subset (c, src, this, instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -1085,6 +1256,7 @@ struct PaintRotate
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
+ TRACE_PAINT (this);
float a = angle.to_float (c->instancer (varIdxBase, 0));
bool p1 = c->funcs->push_rotate (c->data, a);
@@ -1103,13 +1275,25 @@ struct PaintRotateAroundCenter
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer,
+ uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
- return_trace (out->src.serialize_subset (c, src, this));
+ if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+ {
+ out->angle.set_float (angle.to_float (instancer (varIdxBase, 0)));
+ out->centerX = centerX + (int) roundf (instancer (varIdxBase, 1));
+ out->centerY = centerY + (int) roundf (instancer (varIdxBase, 2));
+ }
+
+ if (format ==27 && c->plan->all_axes_pinned)
+ out->format = 26;
+
+ return_trace (out->src.serialize_subset (c, src, this, instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -1120,6 +1304,7 @@ struct PaintRotateAroundCenter
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
+ TRACE_PAINT (this);
float a = angle.to_float (c->instancer (varIdxBase, 0));
float tCenterX = centerX + c->instancer (varIdxBase, 1);
float tCenterY = centerY + c->instancer (varIdxBase, 2);
@@ -1146,13 +1331,24 @@ struct PaintSkew
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer,
+ uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
- return_trace (out->src.serialize_subset (c, src, this));
+ if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+ {
+ out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0)));
+ out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1)));
+ }
+
+ if (format == 29 && c->plan->all_axes_pinned)
+ out->format = 28;
+
+ return_trace (out->src.serialize_subset (c, src, this, instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -1163,6 +1359,7 @@ struct PaintSkew
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
+ TRACE_PAINT (this);
float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
@@ -1183,13 +1380,26 @@ struct PaintSkewAroundCenter
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer,
+ uint32_t varIdxBase) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
- return_trace (out->src.serialize_subset (c, src, this));
+ if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+ {
+ out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0)));
+ out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1)));
+ out->centerX = centerX + (int) roundf (instancer (varIdxBase, 2));
+ out->centerY = centerY + (int) roundf (instancer (varIdxBase, 3));
+ }
+
+ if (format == 31 && c->plan->all_axes_pinned)
+ out->format = 30;
+
+ return_trace (out->src.serialize_subset (c, src, this, instancer));
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -1200,6 +1410,7 @@ struct PaintSkewAroundCenter
void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
{
+ TRACE_PAINT (this);
float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
float tCenterX = centerX + c->instancer (varIdxBase, 2);
@@ -1228,26 +1439,31 @@ struct PaintComposite
{
void closurev1 (hb_colrv1_closure_context_t* c) const;
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
- if (!out->src.serialize_subset (c, src, this)) return_trace (false);
- return_trace (out->backdrop.serialize_subset (c, backdrop, this));
+ bool ret = false;
+ ret |= out->src.serialize_subset (c, src, this, instancer);
+ ret |= out->backdrop.serialize_subset (c, backdrop, this, instancer);
+ return_trace (ret);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ c->check_ops (this->min_size) && // PainComposite can get exponential
src.sanitize (c, this) &&
backdrop.sanitize (c, this));
}
void paint_glyph (hb_paint_context_t *c) const
{
+ TRACE_PAINT (this);
c->recurse (this+backdrop);
c->funcs->push_group (c->data);
c->recurse (this+src);
@@ -1275,7 +1491,7 @@ struct ClipBoxFormat1
return_trace (c->check_struct (this));
}
- void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer HB_UNUSED) const
+ void get_clip_box (ClipBoxData &clip_box, const ItemVarStoreInstancer &instancer HB_UNUSED) const
{
clip_box.xMin = xMin;
clip_box.yMin = yMin;
@@ -1283,6 +1499,28 @@ struct ClipBoxFormat1
clip_box.yMax = yMax;
}
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer,
+ uint32_t varIdxBase) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
+ {
+ out->xMin = xMin + (int) roundf (instancer (varIdxBase, 0));
+ out->yMin = yMin + (int) roundf (instancer (varIdxBase, 1));
+ out->xMax = xMax + (int) roundf (instancer (varIdxBase, 2));
+ out->yMax = yMax + (int) roundf (instancer (varIdxBase, 3));
+ }
+
+ if (format == 2 && c->plan->all_axes_pinned)
+ out->format = 1;
+
+ return_trace (true);
+ }
+
public:
HBUINT8 format; /* format = 1(noVar) or 2(Var)*/
FWORD xMin;
@@ -1295,28 +1533,29 @@ struct ClipBoxFormat1
struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
{
- void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer) const
+ void get_clip_box (ClipBoxData &clip_box, const ItemVarStoreInstancer &instancer) const
{
value.get_clip_box(clip_box, instancer);
if (instancer)
{
- clip_box.xMin += _hb_roundf (instancer (varIdxBase, 0));
- clip_box.yMin += _hb_roundf (instancer (varIdxBase, 1));
- clip_box.xMax += _hb_roundf (instancer (varIdxBase, 2));
- clip_box.yMax += _hb_roundf (instancer (varIdxBase, 3));
+ clip_box.xMin += roundf (instancer (varIdxBase, 0));
+ clip_box.yMin += roundf (instancer (varIdxBase, 1));
+ clip_box.xMax += roundf (instancer (varIdxBase, 2));
+ clip_box.yMax += roundf (instancer (varIdxBase, 3));
}
}
};
struct ClipBox
{
- ClipBox* copy (hb_serialize_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer) const
{
- TRACE_SERIALIZE (this);
+ TRACE_SUBSET (this);
switch (u.format) {
- case 1: return_trace (reinterpret_cast<ClipBox *> (c->embed (u.format1)));
- case 2: return_trace (reinterpret_cast<ClipBox *> (c->embed (u.format2)));
- default:return_trace (nullptr);
+ case 1: return_trace (u.format1.subset (c, instancer, VarIdx::NO_VARIATION));
+ case 2: return_trace (u.format2.subset (c, instancer));
+ default:return_trace (c->default_return_value ());
}
}
@@ -1333,7 +1572,7 @@ struct ClipBox
}
bool get_extents (hb_glyph_extents_t *extents,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
ClipBoxData clip_box;
switch (u.format) {
@@ -1367,13 +1606,15 @@ struct ClipRecord
int cmp (hb_codepoint_t g) const
{ return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; }
- ClipRecord* copy (hb_serialize_context_t *c, const void *base) const
+ bool subset (hb_subset_context_t *c,
+ const void *base,
+ const ItemVarStoreInstancer &instancer) const
{
- TRACE_SERIALIZE (this);
- auto *out = c->embed (this);
- if (unlikely (!out)) return_trace (nullptr);
- if (!out->clipBox.serialize_copy (c, clipBox, base)) return_trace (nullptr);
- return_trace (out);
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ return_trace (out->clipBox.serialize_subset (c, clipBox, base, instancer));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
@@ -1384,7 +1625,7 @@ struct ClipRecord
bool get_extents (hb_glyph_extents_t *extents,
const void *base,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
return (base+clipBox).get_extents (extents, instancer);
}
@@ -1400,7 +1641,8 @@ DECLARE_NULL_NAMESPACE_BYTES (OT, ClipRecord);
struct ClipList
{
- unsigned serialize_clip_records (hb_serialize_context_t *c,
+ unsigned serialize_clip_records (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer,
const hb_set_t& gids,
const hb_map_t& gid_offset_map) const
{
@@ -1432,7 +1674,7 @@ struct ClipList
record.endGlyphID = prev_gid;
record.clipBox = prev_offset;
- if (!c->copy (record, this)) return_trace (0);
+ if (!record.subset (c, this, instancer)) return_trace (0);
count++;
start_gid = _;
@@ -1446,13 +1688,14 @@ struct ClipList
record.startGlyphID = start_gid;
record.endGlyphID = prev_gid;
record.clipBox = prev_offset;
- if (!c->copy (record, this)) return_trace (0);
+ if (!record.subset (c, this, instancer)) return_trace (0);
count++;
}
return_trace (count);
}
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
@@ -1477,7 +1720,7 @@ struct ClipList
}
}
- unsigned count = serialize_clip_records (c->serializer, new_gids, new_gid_offset_map);
+ unsigned count = serialize_clip_records (c, instancer, new_gids, new_gid_offset_map);
if (!count) return_trace (false);
return_trace (c->serializer->check_assign (out->clips.len, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
@@ -1492,7 +1735,7 @@ struct ClipList
bool
get_extents (hb_codepoint_t gid,
hb_glyph_extents_t *extents,
- const VarStoreInstancer &instancer) const
+ const ItemVarStoreInstancer &instancer) const
{
auto *rec = clips.as_array ().bsearch (gid);
if (rec)
@@ -1611,7 +1854,8 @@ struct BaseGlyphPaintRecord
{ return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map,
- const void* src_base, hb_subset_context_t *c) const
+ const void* src_base, hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SERIALIZE (this);
auto *out = s->embed (this);
@@ -1620,7 +1864,7 @@ struct BaseGlyphPaintRecord
HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
- return_trace (out->paint.serialize_subset (c, paint, src_base));
+ return_trace (out->paint.serialize_subset (c, paint, src_base, instancer));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
@@ -1639,7 +1883,8 @@ struct BaseGlyphPaintRecord
struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
{
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
@@ -1651,7 +1896,7 @@ struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
unsigned gid = _.glyphId;
if (!glyphset->has (gid)) continue;
- if (_.serialize (c->serializer, c->plan->glyph_map, this, c)) out->len++;
+ if (_.serialize (c->serializer, c->plan->glyph_map, this, c, instancer)) out->len++;
else return_trace (false);
}
@@ -1670,21 +1915,23 @@ struct LayerList : Array32OfOffset32To<Paint>
const Paint& get_paint (unsigned i) const
{ return this+(*this)[i]; }
- bool subset (hb_subset_context_t *c) const
+ bool subset (hb_subset_context_t *c,
+ const ItemVarStoreInstancer &instancer) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ bool ret = false;
for (const auto& _ : + hb_enumerate (*this)
| hb_filter (c->plan->colrv1_layers, hb_first))
{
auto *o = out->serialize_append (c->serializer);
- if (unlikely (!o) || !o->serialize_subset (c, _.second, this))
- return_trace (false);
+ if (unlikely (!o)) return_trace (false);
+ ret |= o->serialize_subset (c, _.second, this, instancer);
}
- return_trace (true);
+ return_trace (ret);
}
bool sanitize (hb_sanitize_context_t *c) const
@@ -1701,10 +1948,11 @@ struct COLR
bool has_v0_data () const { return numBaseGlyphs; }
bool has_v1_data () const
{
- if (version == 1)
- return (this+baseGlyphList).len > 0;
+ if (version != 1)
+ return false;
+ hb_barrier ();
- return false;
+ return (this+baseGlyphList).len > 0;
}
unsigned int get_glyph_layers (hb_codepoint_t glyph,
@@ -1785,6 +2033,8 @@ struct COLR
hb_set_t *palette_indices) const
{
if (version != 1) return;
+ hb_barrier ();
+
hb_set_t visited_glyphs;
hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices);
@@ -1811,10 +2061,12 @@ struct COLR
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
(this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
(this+layersZ).sanitize (c, numLayers) &&
(version == 0 ||
- (version == 1 &&
+ (hb_barrier () &&
+ version == 1 &&
baseGlyphList.sanitize (c, this) &&
layerList.sanitize (c, this) &&
clipList.sanitize (c, this) &&
@@ -1883,7 +2135,6 @@ struct COLR
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
-
const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
const hb_set_t& glyphset = c->plan->_glyphset_colred;
@@ -1946,7 +2197,7 @@ struct COLR
if (version == 0 && (!base_it || !layer_it))
return_trace (false);
- COLR *colr_prime = c->serializer->start_embed<COLR> ();
+ auto *colr_prime = c->serializer->start_embed<COLR> ();
if (unlikely (!c->serializer->extend_min (colr_prime))) return_trace (false);
if (version == 0)
@@ -1954,7 +2205,12 @@ struct COLR
auto snap = c->serializer->snapshot ();
if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false);
- if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this))
+
+ ItemVarStoreInstancer instancer (varStore ? &(this+varStore) : nullptr,
+ varIdxMap ? &(this+varIdxMap) : nullptr,
+ c->plan->normalized_coords.as_array ());
+
+ if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this, instancer))
{
if (c->serializer->in_error ()) return_trace (false);
//no more COLRv1 glyphs: downgrade to version 0
@@ -1964,8 +2220,11 @@ struct COLR
if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false);
- colr_prime->layerList.serialize_subset (c, layerList, this);
- colr_prime->clipList.serialize_subset (c, clipList, this);
+ colr_prime->layerList.serialize_subset (c, layerList, this, instancer);
+ colr_prime->clipList.serialize_subset (c, clipList, this, instancer);
+ if (!varStore || c->plan->all_axes_pinned)
+ return_trace (true);
+
colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this);
colr_prime->varStore.serialize_copy (c->serializer, varStore, this);
return_trace (true);
@@ -1984,14 +2243,15 @@ struct COLR
return nullptr;
}
+#ifndef HB_NO_PAINT
bool
get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
{
if (version != 1)
return false;
- VarStoreInstancer instancer (this+varStore,
- this+varIdxMap,
+ ItemVarStoreInstancer instancer (&(this+varStore),
+ &(this+varIdxMap),
hb_array (font->coords, font->num_coords));
if (get_clip (glyph, extents, instancer))
@@ -2022,12 +2282,15 @@ struct COLR
return ret;
}
+#endif
bool
has_paint_for_glyph (hb_codepoint_t glyph) const
{
if (version == 1)
{
+ hb_barrier ();
+
const Paint *paint = get_base_glyph_paint (glyph);
return paint != nullptr;
@@ -2038,30 +2301,34 @@ struct COLR
bool get_clip (hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
- const VarStoreInstancer instancer) const
+ const ItemVarStoreInstancer instancer) const
{
return (this+clipList).get_extents (glyph,
extents,
instancer);
}
+#ifndef HB_NO_PAINT
bool
paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const
{
- VarStoreInstancer instancer (this+varStore,
- this+varIdxMap,
+ ItemVarStoreInstancer instancer (&(this+varStore),
+ &(this+varIdxMap),
hb_array (font->coords, font->num_coords));
hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer);
+ c.current_glyphs.add (glyph);
if (version == 1)
{
+ hb_barrier ();
+
const Paint *paint = get_base_glyph_paint (glyph);
if (paint)
{
// COLRv1 glyph
- VarStoreInstancer instancer (this+varStore,
- this+varIdxMap,
+ ItemVarStoreInstancer instancer (&(this+varStore),
+ &(this+varIdxMap),
hb_array (font->coords, font->num_coords));
bool is_bounded = true;
@@ -2131,6 +2398,7 @@ struct COLR
return false;
}
+#endif
protected:
HBUINT16 version; /* Table version number (starts at 0). */
@@ -2145,7 +2413,7 @@ struct COLR
Offset32To<LayerList> layerList;
Offset32To<ClipList> clipList; // Offset to ClipList table (may be NULL)
Offset32To<DeltaSetIndexMap> varIdxMap; // Offset to DeltaSetIndexMap table (may be NULL)
- Offset32To<VariationStore> varStore;
+ Offset32To<ItemVariationStore> varStore;
public:
DEFINE_SIZE_MIN (14);
};
@@ -2166,18 +2434,42 @@ hb_paint_context_t::recurse (const Paint &paint)
void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const
{
+ TRACE_PAINT (this);
const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList ();
for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++)
{
+ if (unlikely (c->current_layers.has (i)))
+ continue;
+
+ c->current_layers.add (i);
+
const Paint &paint = paint_offset_lists.get_paint (i);
c->funcs->push_group (c->data);
c->recurse (paint);
c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
+
+ c->current_layers.del (i);
}
}
void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
{
+ TRACE_PAINT (this);
+
+ if (unlikely (c->current_glyphs.has (gid)))
+ return;
+
+ c->current_glyphs.add (gid);
+
+ c->funcs->push_inverse_root_transform (c->data, c->font);
+ if (c->funcs->color_glyph (c->data, gid, c->font))
+ {
+ c->funcs->pop_transform (c->data);
+ c->current_glyphs.del (gid);
+ return;
+ }
+ c->funcs->pop_transform (c->data);
+
const COLR *colr_table = c->get_colr_table ();
const Paint *paint = colr_table->get_base_glyph_paint (gid);
@@ -2196,6 +2488,8 @@ void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
if (has_clip_box)
c->funcs->pop_clip (c->data);
+
+ c->current_glyphs.del (gid);
}
} /* namespace OT */
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh b/src/3rdparty/harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh
index 4914a0ed57..2821334db7 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Color/CPAL/CPAL.hh
@@ -73,6 +73,30 @@ struct CPALV1Tail
}
public:
+ void collect_name_ids (const void *base,
+ unsigned palette_count,
+ unsigned color_count,
+ const hb_map_t *color_index_map,
+ hb_set_t *nameids_to_retain /* OUT */) const
+ {
+ if (paletteLabelsZ)
+ {
+ + (base+paletteLabelsZ).as_array (palette_count)
+ | hb_sink (nameids_to_retain)
+ ;
+ }
+
+ if (colorLabelsZ)
+ {
+ const hb_array_t<const NameID> colorLabels = (base+colorLabelsZ).as_array (color_count);
+ for (unsigned i = 0; i < color_count; i++)
+ {
+ if (!color_index_map->has (i)) continue;
+ nameids_to_retain->add (colorLabels[i]);
+ }
+ }
+ }
+
bool serialize (hb_serialize_context_t *c,
unsigned palette_count,
unsigned color_count,
@@ -95,13 +119,10 @@ struct CPALV1Tail
if (colorLabelsZ)
{
c->push ();
- for (const auto _ : colorLabels)
+ for (unsigned i = 0; i < color_count; i++)
{
- const hb_codepoint_t *v;
- if (!color_index_map->has (_, &v)) continue;
- NameID new_color_idx;
- new_color_idx = *v;
- if (!c->copy<NameID> (new_color_idx))
+ if (!color_index_map->has (i)) continue;
+ if (!c->copy<NameID> (colorLabels[i]))
{
c->pop_discard ();
return_trace (false);
@@ -189,10 +210,21 @@ struct CPAL
return numColors;
}
+ void collect_name_ids (const hb_map_t *color_index_map,
+ hb_set_t *nameids_to_retain /* OUT */) const
+ {
+ if (version == 1)
+ {
+ hb_barrier ();
+ v1 ().collect_name_ids (this, numPalettes, numColors, color_index_map, nameids_to_retain);
+ }
+ }
+
private:
const CPALV1Tail& v1 () const
{
if (version == 0) return Null (CPALV1Tail);
+ hb_barrier ();
return StructAfter<CPALV1Tail> (*this);
}
@@ -284,7 +316,10 @@ struct CPAL
return_trace (false);
if (version == 1)
+ {
+ hb_barrier ();
return_trace (v1 ().serialize (c->serializer, numPalettes, numColors, this, color_index_map));
+ }
return_trace (true);
}
@@ -293,6 +328,7 @@ struct CPAL
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
(this+colorRecordsZ).sanitize (c, numColorRecords) &&
colorRecordIndicesZ.sanitize (c, numPalettes) &&
(version == 0 || v1 ().sanitize (c, this, numPalettes, numColors)));
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Color/sbix/sbix.hh b/src/3rdparty/harfbuzz-ng/src/OT/Color/sbix/sbix.hh
index 46ad3fd58e..51ae1a9c63 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Color/sbix/sbix.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Color/sbix/sbix.hh
@@ -48,7 +48,6 @@ struct SBIXGlyph
{
TRACE_SERIALIZE (this);
SBIXGlyph* new_glyph = c->start_embed<SBIXGlyph> ();
- if (unlikely (!new_glyph)) return_trace (nullptr);
if (unlikely (!c->extend_min (new_glyph))) return_trace (nullptr);
new_glyph->xOffset = xOffset;
@@ -143,7 +142,6 @@ struct SBIXStrike
unsigned int num_output_glyphs = c->plan->num_output_glyphs ();
auto* out = c->serializer->start_embed<SBIXStrike> ();
- if (unlikely (!out)) return_trace (false);
auto snap = c->serializer->snapshot ();
if (unlikely (!c->serializer->extend (out, num_output_glyphs + 1))) return_trace (false);
out->ppem = ppem;
@@ -370,6 +368,7 @@ struct sbix
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
+ hb_barrier () &&
version >= 1 &&
strikes.sanitize (c, this)));
}
@@ -388,7 +387,6 @@ struct sbix
TRACE_SERIALIZE (this);
auto *out = c->serializer->start_embed<Array32OfOffset32To<SBIXStrike>> ();
- if (unlikely (!out)) return_trace (false);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
hb_vector_t<Offset32To<SBIXStrike>*> new_strikes;
@@ -423,8 +421,6 @@ struct sbix
{
TRACE_SUBSET (this);
- sbix *sbix_prime = c->serializer->start_embed<sbix> ();
- if (unlikely (!sbix_prime)) return_trace (false);
if (unlikely (!c->serializer->embed (this->version))) return_trace (false);
if (unlikely (!c->serializer->embed (this->flags))) return_trace (false);
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Color/svg/svg.hh b/src/3rdparty/harfbuzz-ng/src/OT/Color/svg/svg.hh
index c7d91b88ee..2e1f935109 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Color/svg/svg.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Color/svg/svg.hh
@@ -56,6 +56,7 @@ struct SVGDocumentIndexEntry
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
svgDoc.sanitize (c, base, svgDocLength));
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh
index d35654e245..344e87afb3 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/Coverage.hh
@@ -57,10 +57,14 @@ struct Coverage
public:
DEFINE_SIZE_UNION (2, format);
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
+ hb_barrier ();
switch (u.format)
{
case 1: return_trace (u.format1.sanitize (c));
@@ -113,22 +117,33 @@ struct Coverage
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
- unsigned count = 0;
+ unsigned count = hb_len (glyphs);
unsigned num_ranges = 0;
hb_codepoint_t last = (hb_codepoint_t) -2;
+ hb_codepoint_t max = 0;
+ bool unsorted = false;
for (auto g: glyphs)
{
+ if (last != (hb_codepoint_t) -2 && g < last)
+ unsorted = true;
if (last + 1 != g)
- num_ranges++;
+ num_ranges++;
last = g;
- count++;
+ if (g > max) max = g;
}
- u.format = count <= num_ranges * 3 ? 1 : 2;
+ u.format = !unsorted && count <= num_ranges * 3 ? 1 : 2;
#ifndef HB_NO_BEYOND_64K
- if (count && last > 0xFFFFu)
+ if (max > 0xFFFFu)
u.format += 2;
+ if (unlikely (max > 0xFFFFFFu))
+#else
+ if (unlikely (max > 0xFFFFu))
#endif
+ {
+ c->check_success (false, HB_SERIALIZE_ERROR_INT_OVERFLOW);
+ return_trace (false);
+ }
switch (u.format)
{
@@ -148,8 +163,8 @@ struct Coverage
auto it =
+ iter ()
| hb_take (c->plan->source->get_num_glyphs ())
- | hb_filter (c->plan->glyph_map_gsub)
| hb_map_retains_sorting (c->plan->glyph_map_gsub)
+ | hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; })
;
// Cache the iterator result as it will be iterated multiple times
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat1.hh
index 5d68e3d15e..3f598d40ef 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat1.hh
@@ -79,7 +79,7 @@ struct CoverageFormat1_3
{
if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len) / 2)
{
- for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
+ for (auto g : *glyphs)
if (get_coverage (g) != NOT_COVERED)
return true;
return false;
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat2.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat2.hh
index d7fcc35202..9c87542356 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat2.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/CoverageFormat2.hh
@@ -95,19 +95,26 @@ struct CoverageFormat2_4
unsigned count = 0;
unsigned range = (unsigned) -1;
last = (hb_codepoint_t) -2;
+ unsigned unsorted = false;
for (auto g: glyphs)
{
if (last + 1 != g)
{
+ if (unlikely (last != (hb_codepoint_t) -2 && last + 1 > g))
+ unsorted = true;
+
range++;
- rangeRecord[range].first = g;
- rangeRecord[range].value = count;
+ rangeRecord.arrayZ[range].first = g;
+ rangeRecord.arrayZ[range].value = count;
}
- rangeRecord[range].last = g;
+ rangeRecord.arrayZ[range].last = g;
last = g;
count++;
}
+ if (unlikely (unsorted))
+ rangeRecord.as_array ().qsort (RangeRecord<Types>::cmp_range);
+
return_trace (true);
}
@@ -115,7 +122,7 @@ struct CoverageFormat2_4
{
if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2)
{
- for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
+ for (auto g : *glyphs)
if (get_coverage (g) != NOT_COVERED)
return true;
return false;
@@ -185,8 +192,8 @@ struct CoverageFormat2_4
if (__more__ ())
{
unsigned int old = coverage;
- j = c->rangeRecord[i].first;
- coverage = c->rangeRecord[i].value;
+ j = c->rangeRecord.arrayZ[i].first;
+ coverage = c->rangeRecord.arrayZ[i].value;
if (unlikely (coverage != old + 1))
{
/* Broken table. Skip. Important to avoid DoS.
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/RangeRecord.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/RangeRecord.hh
index a62629fad3..85aacace9a 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/RangeRecord.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/Common/RangeRecord.hh
@@ -51,6 +51,18 @@ struct RangeRecord
int cmp (hb_codepoint_t g) const
{ return g < first ? -1 : g <= last ? 0 : +1; }
+ HB_INTERNAL static int cmp_range (const void *pa, const void *pb) {
+ const RangeRecord *a = (const RangeRecord *) pa;
+ const RangeRecord *b = (const RangeRecord *) pb;
+ if (a->first < b->first) return -1;
+ if (a->first > b->first) return +1;
+ if (a->last < b->last) return -1;
+ if (a->last > b->last) return +1;
+ if (a->value < b->value) return -1;
+ if (a->value > b->value) return +1;
+ return 0;
+ }
+
unsigned get_population () const
{
if (unlikely (last < first)) return 0;
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh
index 0551fcf812..317b96c714 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GDEF/GDEF.hh
@@ -29,9 +29,10 @@
#ifndef OT_LAYOUT_GDEF_GDEF_HH
#define OT_LAYOUT_GDEF_GDEF_HH
-#include "../../../hb-ot-layout-common.hh"
+#include "../../../hb-ot-var-common.hh"
#include "../../../hb-font.hh"
+#include "../../../hb-cache.hh"
namespace OT {
@@ -48,8 +49,6 @@ struct AttachPoint : Array16Of<HBUINT16>
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out)) return_trace (false);
-
return_trace (out->serialize (c->serializer, + iter ()));
}
};
@@ -190,7 +189,7 @@ struct CaretValueFormat3
friend struct CaretValue;
hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction,
- const VariationStore &var_store) const
+ const ItemVariationStore &var_store) const
{
return HB_DIRECTION_IS_HORIZONTAL (direction) ?
font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
@@ -201,22 +200,23 @@ struct CaretValueFormat3
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out)) return_trace (false);
if (!c->serializer->embed (caretValueFormat)) return_trace (false);
if (!c->serializer->embed (coordinate)) return_trace (false);
unsigned varidx = (this+deviceTable).get_variation_index ();
- if (c->plan->layout_variation_idx_delta_map.has (varidx))
+ hb_pair_t<unsigned, int> *new_varidx_delta;
+ if (!c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta))
+ return_trace (false);
+
+ uint32_t new_varidx = hb_first (*new_varidx_delta);
+ int delta = hb_second (*new_varidx_delta);
+ if (delta != 0)
{
- int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (varidx));
- if (delta != 0)
- {
- if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
- return_trace (false);
- }
+ if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (false);
}
- if (c->plan->all_axes_pinned)
+ if (new_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
if (!c->serializer->embed (deviceTable))
@@ -251,7 +251,7 @@ struct CaretValue
hb_position_t get_caret_value (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
- const VariationStore &var_store) const
+ const ItemVariationStore &var_store) const
{
switch (u.format) {
case 1: return u.format1.get_caret_value (font, direction);
@@ -291,6 +291,7 @@ struct CaretValue
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
+ hb_barrier ();
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
@@ -315,7 +316,7 @@ struct LigGlyph
unsigned get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
- const VariationStore &var_store,
+ const ItemVariationStore &var_store,
unsigned start_offset,
unsigned *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
@@ -371,7 +372,7 @@ struct LigCaretList
unsigned int get_lig_carets (hb_font_t *font,
hb_direction_t direction,
hb_codepoint_t glyph_id,
- const VariationStore &var_store,
+ const ItemVariationStore &var_store,
unsigned int start_offset,
unsigned int *caret_count /* IN/OUT */,
hb_position_t *caret_array /* OUT */) const
@@ -441,6 +442,30 @@ struct MarkGlyphSetsFormat1
bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
{ return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
+ void collect_used_mark_sets (const hb_set_t& glyph_set,
+ hb_set_t& used_mark_sets /* OUT */) const
+ {
+ unsigned i = 0;
+ for (const auto &offset : coverage)
+ {
+ const auto &cov = this+offset;
+ if (cov.intersects (&glyph_set))
+ used_mark_sets.add (i);
+
+ i++;
+ }
+ }
+
+ template <typename set_t>
+ void collect_coverage (hb_vector_t<set_t> &sets) const
+ {
+ for (const auto &offset : coverage)
+ {
+ const auto &cov = this+offset;
+ cov.collect_coverage (sets.push ());
+ }
+ }
+
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
@@ -451,6 +476,7 @@ struct MarkGlyphSetsFormat1
bool ret = true;
for (const Offset32To<Coverage>& offset : coverage.iter ())
{
+ auto snap = c->serializer->snapshot ();
auto *o = out->coverage.serialize_append (c->serializer);
if (unlikely (!o))
{
@@ -458,11 +484,17 @@ struct MarkGlyphSetsFormat1
break;
}
- //not using o->serialize_subset (c, offset, this, out) here because
- //OTS doesn't allow null offset.
- //See issue: https://github.com/khaledhosny/ots/issues/172
+ //skip empty coverage
c->serializer->push ();
- c->dispatch (this+offset);
+ bool res = false;
+ if (offset) res = c->dispatch (this+offset);
+ if (!res)
+ {
+ c->serializer->pop_discard ();
+ c->serializer->revert (snap);
+ (out->coverage.len)--;
+ continue;
+ }
c->serializer->add_link (*o, c->serializer->pop_pack ());
}
@@ -494,6 +526,24 @@ struct MarkGlyphSets
}
}
+ template <typename set_t>
+ void collect_coverage (hb_vector_t<set_t> &sets) const
+ {
+ switch (u.format) {
+ case 1: u.format1.collect_coverage (sets); return;
+ default:return;
+ }
+ }
+
+ void collect_used_mark_sets (const hb_set_t& glyph_set,
+ hb_set_t& used_mark_sets /* OUT */) const
+ {
+ switch (u.format) {
+ case 1: u.format1.collect_used_mark_sets (glyph_set, used_mark_sets); return;
+ default:return;
+ }
+ }
+
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
@@ -507,6 +557,7 @@ struct MarkGlyphSets
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
+ hb_barrier ();
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
default:return_trace (true);
@@ -558,7 +609,7 @@ struct GDEFVersion1_2
* definitions--from beginning of GDEF
* header (may be NULL). Introduced
* in version 0x00010002. */
- Offset32To<VariationStore>
+ Offset32To<ItemVariationStore>
varStore; /* Offset to the table of Item Variation
* Store--from beginning of GDEF
* header (may be NULL). Introduced
@@ -581,43 +632,109 @@ struct GDEFVersion1_2
attachList.sanitize (c, this) &&
ligCaretList.sanitize (c, this) &&
markAttachClassDef.sanitize (c, this) &&
+ hb_barrier () &&
(version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
(version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
}
+ static void remap_varidx_after_instantiation (const hb_map_t& varidx_map,
+ hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>>& layout_variation_idx_delta_map /* IN/OUT */)
+ {
+ /* varidx_map is empty which means varstore is empty after instantiation,
+ * no variations, map all varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX.
+ * varidx_map doesn't have original varidx, indicating delta row is all
+ * zeros, map varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */
+ for (auto _ : layout_variation_idx_delta_map.iter_ref ())
+ {
+ /* old_varidx->(varidx, delta) mapping generated for subsetting, then this
+ * varidx is used as key of varidx_map during instantiation */
+ uint32_t varidx = _.second.first;
+ uint32_t *new_varidx;
+ if (varidx_map.has (varidx, &new_varidx))
+ _.second.first = *new_varidx;
+ else
+ _.second.first = HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
+ }
+ }
+
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- auto *out = c->serializer->embed (*this);
- if (unlikely (!out)) return_trace (false);
-
- bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
- bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
- bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
- bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
- bool subset_markglyphsetsdef = false;
- if (version.to_int () >= 0x00010002u)
- {
- subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
- }
+ // Push var store first (if it's needed) so that it's last in the
+ // serialization order. Some font consumers assume that varstore runs to
+ // the end of the GDEF table.
+ // See: https://github.com/harfbuzz/harfbuzz/issues/4636
+ auto snapshot_version0 = c->serializer->snapshot ();
+ if (unlikely (version.to_int () >= 0x00010002u && !c->serializer->embed (markGlyphSetsDef)))
+ return_trace (false);
bool subset_varstore = false;
+ unsigned varstore_index = (unsigned) -1;
+ auto snapshot_version2 = c->serializer->snapshot ();
if (version.to_int () >= 0x00010003u)
{
+ if (unlikely (!c->serializer->embed (varStore))) return_trace (false);
if (c->plan->all_axes_pinned)
out->varStore = 0;
+ else if (c->plan->normalized_coords)
+ {
+ if (varStore)
+ {
+ item_variations_t item_vars;
+ if (item_vars.instantiate (this+varStore, c->plan, true, true,
+ c->plan->gdef_varstore_inner_maps.as_array ())) {
+ subset_varstore = out->varStore.serialize_serialize (c->serializer,
+ item_vars.has_long_word (),
+ c->plan->axis_tags,
+ item_vars.get_region_list (),
+ item_vars.get_vardata_encodings ());
+ varstore_index = c->serializer->last_added_child_index();
+ }
+ remap_varidx_after_instantiation (item_vars.get_varidx_map (),
+ c->plan->layout_variation_idx_delta_map);
+ }
+ }
else
+ {
subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
+ varstore_index = c->serializer->last_added_child_index();
+ }
+ }
+
+ out->version.major = version.major;
+ out->version.minor = version.minor;
+
+ if (!subset_varstore && version.to_int () >= 0x00010002u) {
+ c->serializer->revert (snapshot_version2);
+ }
+
+ bool subset_markglyphsetsdef = false;
+ if (version.to_int () >= 0x00010002u)
+ {
+ subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
}
if (subset_varstore)
{
out->version.minor = 3;
+ c->plan->has_gdef_varstore = true;
} else if (subset_markglyphsetsdef) {
- out->version.minor = 2;
+ out->version.minor = 2;
} else {
out->version.minor = 0;
+ c->serializer->revert (snapshot_version0);
+ }
+
+ bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
+ bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
+ bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
+ bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
+
+ if (subset_varstore && varstore_index != (unsigned) -1) {
+ c->serializer->repack_last(varstore_index);
}
return_trace (subset_glyphclassdef || subset_attachlist ||
@@ -654,6 +771,7 @@ struct GDEF
{
TRACE_SANITIZE (this);
if (unlikely (!u.version.sanitize (c))) return_trace (false);
+ hb_barrier ();
switch (u.version.major) {
case 1: return_trace (u.version1.sanitize (c));
#ifndef HB_NO_BEYOND_64K
@@ -784,14 +902,14 @@ struct GDEF
default: return false;
}
}
- const VariationStore &get_var_store () const
+ const ItemVariationStore &get_var_store () const
{
switch (u.version.major) {
- case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(VariationStore);
+ case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(ItemVariationStore);
#ifndef HB_NO_BEYOND_64K
case 2: return this+u.version2.varStore;
#endif
- default: return Null(VariationStore);
+ default: return Null(ItemVariationStore);
}
}
@@ -858,27 +976,79 @@ struct GDEF
hb_blob_destroy (table.get_blob ());
table = hb_blob_get_empty ();
}
+
+#ifndef HB_NO_GDEF_CACHE
+ table->get_mark_glyph_sets ().collect_coverage (mark_glyph_set_digests);
+#endif
}
~accelerator_t () { table.destroy (); }
+ unsigned int get_glyph_props (hb_codepoint_t glyph) const
+ {
+ unsigned v;
+
+#ifndef HB_NO_GDEF_CACHE
+ if (glyph_props_cache.get (glyph, &v))
+ return v;
+#endif
+
+ v = table->get_glyph_props (glyph);
+
+#ifndef HB_NO_GDEF_CACHE
+ if (likely (table.get_blob ())) // Don't try setting if we are the null instance!
+ glyph_props_cache.set (glyph, v);
+#endif
+
+ return v;
+
+ }
+
+ bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
+ {
+ return
+#ifndef HB_NO_GDEF_CACHE
+ mark_glyph_set_digests[set_index].may_have (glyph_id) &&
+#endif
+ table->mark_set_covers (set_index, glyph_id);
+ }
+
hb_blob_ptr_t<GDEF> table;
+#ifndef HB_NO_GDEF_CACHE
+ hb_vector_t<hb_set_digest_t> mark_glyph_set_digests;
+ mutable hb_cache_t<21, 3, 8> glyph_props_cache;
+#endif
};
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{ get_lig_caret_list ().collect_variation_indices (c); }
void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
+ const hb_vector_t<int>& normalized_coords,
+ bool calculate_delta, /* not pinned at default */
+ bool no_variations, /* all axes pinned */
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const
{
if (!has_var_store ()) return;
- if (layout_variation_indices->is_empty ()) return;
+ const ItemVariationStore &var_store = get_var_store ();
+ float *store_cache = var_store.create_cache ();
unsigned new_major = 0, new_minor = 0;
unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
for (unsigned idx : layout_variation_indices->iter ())
{
+ int delta = 0;
+ if (calculate_delta)
+ delta = roundf (var_store.get_delta (idx, normalized_coords.arrayZ,
+ normalized_coords.length, store_cache));
+
+ if (no_variations)
+ {
+ layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (HB_OT_LAYOUT_NO_VARIATIONS_INDEX, delta));
+ continue;
+ }
+
uint16_t major = idx >> 16;
- if (major >= get_var_store ().get_sub_table_count ()) break;
+ if (major >= var_store.get_sub_table_count ()) break;
if (major != last_major)
{
new_minor = 0;
@@ -886,14 +1056,11 @@ struct GDEF
}
unsigned new_idx = (new_major << 16) + new_minor;
- if (!layout_variation_idx_delta_map->has (idx))
- continue;
- int delta = hb_second (layout_variation_idx_delta_map->get (idx));
-
layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (new_idx, delta));
++new_minor;
last_major = major;
}
+ var_store.destroy_cache (store_cache);
}
protected:
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Anchor.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Anchor.hh
index 49e76e7750..7802e397f4 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Anchor.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Anchor.hh
@@ -25,6 +25,7 @@ struct Anchor
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
+ hb_barrier ();
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorFormat3.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorFormat3.hh
index e7e3c5c6d1..b5422652c4 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorFormat3.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorFormat3.hh
@@ -25,7 +25,9 @@ struct AnchorFormat3
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
+ if (unlikely (!c->check_struct (this))) return_trace (false);
+
+ return_trace (xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
}
void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
@@ -35,25 +37,35 @@ struct AnchorFormat3
*x = font->em_fscale_x (xCoordinate);
*y = font->em_fscale_y (yCoordinate);
- if (font->x_ppem || font->num_coords)
+ if ((font->x_ppem || font->num_coords) && xDeviceTable.sanitize (&c->sanitizer, this))
+ {
+ hb_barrier ();
*x += (this+xDeviceTable).get_x_delta (font, c->var_store, c->var_store_cache);
- if (font->y_ppem || font->num_coords)
+ }
+ if ((font->y_ppem || font->num_coords) && yDeviceTable.sanitize (&c->sanitizer, this))
+ {
+ hb_barrier ();
*y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache);
+ }
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out)) return_trace (false);
if (unlikely (!c->serializer->embed (format))) return_trace (false);
if (unlikely (!c->serializer->embed (xCoordinate))) return_trace (false);
if (unlikely (!c->serializer->embed (yCoordinate))) return_trace (false);
unsigned x_varidx = xDeviceTable ? (this+xDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
- if (c->plan->layout_variation_idx_delta_map.has (x_varidx))
+ if (x_varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
{
- int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (x_varidx));
+ hb_pair_t<unsigned, int> *new_varidx_delta;
+ if (!c->plan->layout_variation_idx_delta_map.has (x_varidx, &new_varidx_delta))
+ return_trace (false);
+
+ x_varidx = hb_first (*new_varidx_delta);
+ int delta = hb_second (*new_varidx_delta);
if (delta != 0)
{
if (!c->serializer->check_assign (out->xCoordinate, xCoordinate + delta,
@@ -63,9 +75,14 @@ struct AnchorFormat3
}
unsigned y_varidx = yDeviceTable ? (this+yDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
- if (c->plan->layout_variation_idx_delta_map.has (y_varidx))
+ if (y_varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
{
- int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (y_varidx));
+ hb_pair_t<unsigned, int> *new_varidx_delta;
+ if (!c->plan->layout_variation_idx_delta_map.has (y_varidx, &new_varidx_delta))
+ return_trace (false);
+
+ y_varidx = hb_first (*new_varidx_delta);
+ int delta = hb_second (*new_varidx_delta);
if (delta != 0)
{
if (!c->serializer->check_assign (out->yCoordinate, yCoordinate + delta,
@@ -74,7 +91,10 @@ struct AnchorFormat3
}
}
- if (c->plan->all_axes_pinned)
+ /* in case that all axes are pinned or no variations after instantiation,
+ * both var_idxes will be mapped to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */
+ if (x_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX &&
+ y_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
return_trace (c->serializer->check_assign (out->format, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
if (!c->serializer->embed (xDeviceTable)) return_trace (false);
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh
index c442efa1ea..2557e9a723 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/AnchorMatrix.hh
@@ -8,7 +8,7 @@ namespace GPOS_impl {
struct AnchorMatrix
{
HBUINT16 rows; /* Number of rows */
- UnsizedArrayOf<Offset16To<Anchor>>
+ UnsizedArrayOf<Offset16To<Anchor, AnchorMatrix>>
matrixZ; /* Matrix of offsets to Anchor tables--
* from beginning of AnchorMatrix table */
public:
@@ -18,21 +18,31 @@ struct AnchorMatrix
{
TRACE_SANITIZE (this);
if (!c->check_struct (this)) return_trace (false);
+ hb_barrier ();
if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false);
unsigned int count = rows * cols;
if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false);
+
+ if (c->lazy_some_gpos)
+ return_trace (true);
+
+ hb_barrier ();
for (unsigned int i = 0; i < count; i++)
if (!matrixZ[i].sanitize (c, this)) return_trace (false);
return_trace (true);
}
- const Anchor& get_anchor (unsigned int row, unsigned int col,
- unsigned int cols, bool *found) const
+ const Anchor& get_anchor (hb_ot_apply_context_t *c,
+ unsigned int row, unsigned int col,
+ unsigned int cols, bool *found) const
{
*found = false;
if (unlikely (row >= rows || col >= cols)) return Null (Anchor);
- *found = !matrixZ[row * cols + col].is_null ();
- return this+matrixZ[row * cols + col];
+ auto &offset = matrixZ[row * cols + col];
+ if (unlikely (!offset.sanitize (&c->sanitizer, this))) return Null (Anchor);
+ hb_barrier ();
+ *found = !offset.is_null ();
+ return this+offset;
}
template <typename Iterator,
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Common.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Common.hh
index 408197454f..696d25d75c 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/Common.hh
@@ -23,7 +23,7 @@ static void SinglePos_serialize (hb_serialize_context_t *c,
const SrcLookup *src,
Iterator it,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
- bool all_axes_pinned);
+ unsigned new_format);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh
index ff255e090a..6b019ac513 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/CursivePosFormat1.hh
@@ -11,37 +11,38 @@ struct EntryExitRecord
{
friend struct CursivePosFormat1;
- bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ bool sanitize (hb_sanitize_context_t *c, const struct CursivePosFormat1 *base) const
{
TRACE_SANITIZE (this);
return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
- const void *src_base) const
+ const struct CursivePosFormat1 *src_base) const
{
(src_base+entryAnchor).collect_variation_indices (c);
(src_base+exitAnchor).collect_variation_indices (c);
}
- EntryExitRecord* subset (hb_subset_context_t *c,
- const void *src_base) const
+ bool subset (hb_subset_context_t *c,
+ const struct CursivePosFormat1 *src_base) const
{
TRACE_SERIALIZE (this);
auto *out = c->serializer->embed (this);
- if (unlikely (!out)) return_trace (nullptr);
+ if (unlikely (!out)) return_trace (false);
- out->entryAnchor.serialize_subset (c, entryAnchor, src_base);
- out->exitAnchor.serialize_subset (c, exitAnchor, src_base);
- return_trace (out);
+ bool ret = false;
+ ret |= out->entryAnchor.serialize_subset (c, entryAnchor, src_base);
+ ret |= out->exitAnchor.serialize_subset (c, exitAnchor, src_base);
+ return_trace (ret);
}
protected:
- Offset16To<Anchor>
+ Offset16To<Anchor, struct CursivePosFormat1>
entryAnchor; /* Offset to EntryAnchor table--from
* beginning of CursivePos
* subtable--may be NULL */
- Offset16To<Anchor>
+ Offset16To<Anchor, struct CursivePosFormat1>
exitAnchor; /* Offset to ExitAnchor table--from
* beginning of CursivePos
* subtable--may be NULL */
@@ -91,7 +92,13 @@ struct CursivePosFormat1
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
+ if (unlikely (!coverage.sanitize (c, this)))
+ return_trace (false);
+
+ if (c->lazy_some_gpos)
+ return_trace (entryExitRecord.sanitize_shallow (c));
+ else
+ return_trace (entryExitRecord.sanitize (c, this));
}
bool intersects (const hb_set_t *glyphs) const
@@ -119,23 +126,27 @@ struct CursivePosFormat1
hb_buffer_t *buffer = c->buffer;
const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)];
- if (!this_record.entryAnchor) return_trace (false);
+ if (!this_record.entryAnchor ||
+ unlikely (!this_record.entryAnchor.sanitize (&c->sanitizer, this))) return_trace (false);
+ hb_barrier ();
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
- skippy_iter.reset (buffer->idx, 1);
+ skippy_iter.reset_fast (buffer->idx);
unsigned unsafe_from;
- if (!skippy_iter.prev (&unsafe_from))
+ if (unlikely (!skippy_iter.prev (&unsafe_from)))
{
buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
return_trace (false);
}
const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)];
- if (!prev_record.exitAnchor)
+ if (!prev_record.exitAnchor ||
+ unlikely (!prev_record.exitAnchor.sanitize (&c->sanitizer, this)))
{
buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
return_trace (false);
}
+ hb_barrier ();
unsigned int i = skippy_iter.idx;
unsigned int j = buffer->idx;
@@ -200,8 +211,8 @@ struct CursivePosFormat1
* Arabic. */
unsigned int child = i;
unsigned int parent = j;
- hb_position_t x_offset = entry_x - exit_x;
- hb_position_t y_offset = entry_y - exit_y;
+ hb_position_t x_offset = roundf (entry_x - exit_x);
+ hb_position_t y_offset = roundf (entry_y - exit_y);
if (!(c->lookup_props & LookupFlag::RightToLeft))
{
unsigned int k = child;
@@ -253,7 +264,7 @@ struct CursivePosFormat1
hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_subset_context_t *c,
Iterator it,
- const void *src_base)
+ const struct CursivePosFormat1 *src_base)
{
if (unlikely (!c->serializer->extend_min ((*this)))) return;
this->format = 1;
@@ -278,7 +289,6 @@ struct CursivePosFormat1
const hb_map_t &glyph_map = *c->plan->glyph_map;
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out)) return_trace (false);
auto it =
+ hb_zip (this+coverage, entryExitRecord)
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/GPOS.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/GPOS.hh
index 9493ec987e..f4af98b25f 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/GPOS.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/GPOS.hh
@@ -156,7 +156,7 @@ GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer)
{
for (unsigned i = 0; i < len; i++)
if (unlikely (pos[i].y_offset))
- pos[i].x_offset += _hb_roundf (font->slant_xy * pos[i].y_offset);
+ pos[i].x_offset += roundf (font->slant_xy * pos[i].y_offset);
}
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/LigatureArray.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/LigatureArray.hh
index a2d807cc32..59cca40aad 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/LigatureArray.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/LigatureArray.hh
@@ -27,6 +27,7 @@ struct LigatureArray : List16OfOffset16To<LigatureAttach>
auto *out = c->serializer->start_embed (this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ bool ret = false;
for (const auto _ : + hb_zip (coverage, *this)
| hb_filter (glyphset, hb_first))
{
@@ -38,13 +39,13 @@ struct LigatureArray : List16OfOffset16To<LigatureAttach>
+ hb_range (src.rows * class_count)
| hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
;
- matrix->serialize_subset (c,
- _.second,
- this,
- src.rows,
- indexes);
+ ret |= matrix->serialize_subset (c,
+ _.second,
+ this,
+ src.rows,
+ indexes);
}
- return_trace (this->len);
+ return_trace (ret);
}
};
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkArray.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkArray.hh
index ff43ffb8c5..0887cc158b 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkArray.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkArray.hh
@@ -28,7 +28,7 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
const Anchor& mark_anchor = this + record.markAnchor;
bool found;
- const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
+ const Anchor& glyph_anchor = anchors.get_anchor (c, glyph_index, mark_class, class_count, &found);
/* If this subtable doesn't have an anchor for this base and this class,
* return false such that the subsequent subtables have a chance at it. */
if (unlikely (!found)) return_trace (false);
@@ -82,10 +82,10 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
| hb_map (hb_second)
;
+ bool ret = false;
unsigned new_length = 0;
for (const auto& mark_record : mark_iter) {
- if (unlikely (!mark_record.subset (c, this, klass_mapping)))
- return_trace (false);
+ ret |= mark_record.subset (c, this, klass_mapping);
new_length++;
}
@@ -93,7 +93,7 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)))
return_trace (false);
- return_trace (true);
+ return_trace (ret);
}
};
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkBasePosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkBasePosFormat1.hh
index eb4712049b..1b8f3c80a9 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkBasePosFormat1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkBasePosFormat1.hh
@@ -197,9 +197,10 @@ struct MarkBasePosFormat1_2
if (!out->markCoverage.serialize_serialize (c->serializer, new_coverage.iter ()))
return_trace (false);
- out->markArray.serialize_subset (c, markArray, this,
- (this+markCoverage).iter (),
- &klass_mapping);
+ if (unlikely (!out->markArray.serialize_subset (c, markArray, this,
+ (this+markCoverage).iter (),
+ &klass_mapping)))
+ return_trace (false);
unsigned basecount = (this+baseArray).rows;
auto base_iter =
@@ -228,11 +229,9 @@ struct MarkBasePosFormat1_2
;
}
- out->baseArray.serialize_subset (c, baseArray, this,
- base_iter.len (),
- base_indexes.iter ());
-
- return_trace (true);
+ return_trace (out->baseArray.serialize_subset (c, baseArray, this,
+ base_iter.len (),
+ base_indexes.iter ()));
}
};
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkLigPosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkLigPosFormat1.hh
index 7e7b438aa7..d6bee277c7 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkLigPosFormat1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkLigPosFormat1.hh
@@ -126,15 +126,15 @@ struct MarkLigPosFormat1_2
return_trace (false);
}
- j = (unsigned) c->last_base;
+ unsigned idx = (unsigned) c->last_base;
/* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
- //if (!_hb_glyph_info_is_ligature (&buffer->info[j])) { return_trace (false); }
+ //if (!_hb_glyph_info_is_ligature (&buffer->info[idx])) { return_trace (false); }
- unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint);
+ unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[idx].codepoint);
if (lig_index == NOT_COVERED)
{
- buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
+ buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
return_trace (false);
}
@@ -145,7 +145,7 @@ struct MarkLigPosFormat1_2
unsigned int comp_count = lig_attach.rows;
if (unlikely (!comp_count))
{
- buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
+ buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
return_trace (false);
}
@@ -154,7 +154,7 @@ struct MarkLigPosFormat1_2
* can directly use the component index. If not, we attach the mark
* glyph to the last component of the ligature. */
unsigned int comp_index;
- unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
+ unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[idx]);
unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
if (lig_id && lig_id == mark_id && mark_comp > 0)
@@ -162,14 +162,14 @@ struct MarkLigPosFormat1_2
else
comp_index = comp_count - 1;
- return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
+ return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, idx));
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
- const hb_map_t &glyph_map = *c->plan->glyph_map;
+ const hb_map_t &glyph_map = c->plan->glyph_map_gsub;
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
@@ -195,23 +195,24 @@ struct MarkLigPosFormat1_2
if (!out->markCoverage.serialize_serialize (c->serializer, new_mark_coverage))
return_trace (false);
- out->markArray.serialize_subset (c, markArray, this,
- (this+markCoverage).iter (),
- &klass_mapping);
+ if (unlikely (!out->markArray.serialize_subset (c, markArray, this,
+ (this+markCoverage).iter (),
+ &klass_mapping)))
+ return_trace (false);
auto new_ligature_coverage =
+ hb_iter (this + ligatureCoverage)
- | hb_filter (glyphset)
+ | hb_take ((this + ligatureArray).len)
| hb_map_retains_sorting (glyph_map)
+ | hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; })
;
if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage))
return_trace (false);
- out->ligatureArray.serialize_subset (c, ligatureArray, this,
- hb_iter (this+ligatureCoverage), classCount, &klass_mapping);
-
- return_trace (true);
+ return_trace (out->ligatureArray.serialize_subset (c, ligatureArray, this,
+ hb_iter (this+ligatureCoverage),
+ classCount, &klass_mapping));
}
};
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
index fbcebb8044..57eb782a95 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkMarkPosFormat1.hh
@@ -42,6 +42,7 @@ struct MarkMarkPosFormat1_2
mark1Coverage.sanitize (c, this) &&
mark2Coverage.sanitize (c, this) &&
mark1Array.sanitize (c, this) &&
+ hb_barrier () &&
mark2Array.sanitize (c, this, (unsigned int) classCount));
}
@@ -100,16 +101,16 @@ struct MarkMarkPosFormat1_2
/* now we search backwards for a suitable mark glyph until a non-mark glyph */
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
- skippy_iter.reset (buffer->idx, 1);
+ skippy_iter.reset_fast (buffer->idx);
skippy_iter.set_lookup_props (c->lookup_props & ~(uint32_t)LookupFlag::IgnoreFlags);
unsigned unsafe_from;
- if (!skippy_iter.prev (&unsafe_from))
+ if (unlikely (!skippy_iter.prev (&unsafe_from)))
{
buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
return_trace (false);
}
- if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]))
+ if (likely (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])))
{
buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
return_trace (false);
@@ -183,9 +184,10 @@ struct MarkMarkPosFormat1_2
if (!out->mark1Coverage.serialize_serialize (c->serializer, new_coverage.iter ()))
return_trace (false);
- out->mark1Array.serialize_subset (c, mark1Array, this,
- (this+mark1Coverage).iter (),
- &klass_mapping);
+ if (unlikely (!out->mark1Array.serialize_subset (c, mark1Array, this,
+ (this+mark1Coverage).iter (),
+ &klass_mapping)))
+ return_trace (false);
unsigned mark2count = (this+mark2Array).rows;
auto mark2_iter =
@@ -214,9 +216,10 @@ struct MarkMarkPosFormat1_2
;
}
- out->mark2Array.serialize_subset (c, mark2Array, this, mark2_iter.len (), mark2_indexes.iter ());
+ return_trace (out->mark2Array.serialize_subset (c, mark2Array, this,
+ mark2_iter.len (),
+ mark2_indexes.iter ()));
- return_trace (true);
}
};
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkRecord.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkRecord.hh
index a7d489d2a5..3d11c7773c 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkRecord.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/MarkRecord.hh
@@ -24,17 +24,16 @@ struct MarkRecord
return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
}
- MarkRecord *subset (hb_subset_context_t *c,
- const void *src_base,
- const hb_map_t *klass_mapping) const
+ bool subset (hb_subset_context_t *c,
+ const void *src_base,
+ const hb_map_t *klass_mapping) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
- if (unlikely (!out)) return_trace (nullptr);
+ if (unlikely (!out)) return_trace (false);
out->klass = klass_mapping->get (klass);
- out->markAnchor.serialize_subset (c, markAnchor, src_base);
- return_trace (out);
+ return_trace (out->markAnchor.serialize_subset (c, markAnchor, src_base));
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh
index b4a9a9ad53..ac2774a76f 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat1.hh
@@ -36,6 +36,7 @@ struct PairPosFormat1_3
TRACE_SANITIZE (this);
if (!c->check_struct (this)) return_trace (false);
+ hb_barrier ();
unsigned int len1 = valueFormat[0].get_len ();
unsigned int len2 = valueFormat[1].get_len ();
@@ -55,7 +56,7 @@ struct PairPosFormat1_3
if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4)
{
- for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
+ for (hb_codepoint_t g : glyphs->iter())
{
unsigned i = cov.get_coverage (g);
if ((this+pairSet[i]).intersects (glyphs, valueFormat))
@@ -110,9 +111,9 @@ struct PairPosFormat1_3
if (likely (index == NOT_COVERED)) return_trace (false);
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
- skippy_iter.reset (buffer->idx, 1);
+ skippy_iter.reset_fast (buffer->idx);
unsigned unsafe_to;
- if (!skippy_iter.next (&unsafe_to))
+ if (unlikely (!skippy_iter.next (&unsafe_to)))
{
buffer->unsafe_to_concat (buffer->idx, unsafe_to);
return_trace (false);
@@ -131,20 +132,33 @@ struct PairPosFormat1_3
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->format = format;
- out->valueFormat[0] = valueFormat[0];
- out->valueFormat[1] = valueFormat[1];
- if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+
+ hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat[0], valueFormat[1]);
+
+ if (c->plan->normalized_coords)
{
- hb_pair_t<unsigned, unsigned> newFormats = compute_effective_value_formats (glyphset);
- out->valueFormat[0] = newFormats.first;
- out->valueFormat[1] = newFormats.second;
+ /* all device flags will be dropped when full instancing, no need to strip
+ * hints, also do not strip emtpy cause we don't compute the new default
+ * value during stripping */
+ newFormats = compute_effective_value_formats (glyphset, false, false, &c->plan->layout_variation_idx_delta_map);
}
-
- if (c->plan->all_axes_pinned)
+ /* do not strip hints for VF */
+ else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
{
- out->valueFormat[0] = out->valueFormat[0].drop_device_table_flags ();
- out->valueFormat[1] = out->valueFormat[1].drop_device_table_flags ();
+ hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r'));
+ bool has_fvar = (blob != hb_blob_get_empty ());
+ hb_blob_destroy (blob);
+
+ bool strip = !has_fvar;
+ /* special case: strip hints when a VF has no GDEF varstore after
+ * subsetting*/
+ if (has_fvar && !c->plan->has_gdef_varstore)
+ strip = true;
+ newFormats = compute_effective_value_formats (glyphset, strip, true);
}
+
+ out->valueFormat[0] = newFormats.first;
+ out->valueFormat[1] = newFormats.second;
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
@@ -175,7 +189,9 @@ struct PairPosFormat1_3
}
- hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const
+ hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset,
+ bool strip_hints, bool strip_empty,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map = nullptr) const
{
unsigned record_size = PairSet::get_size (valueFormat);
@@ -195,8 +211,8 @@ struct PairPosFormat1_3
{
if (record->intersects (glyphset))
{
- format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 ());
- format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]));
+ format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 (), strip_hints, strip_empty, &set, varidx_delta_map);
+ format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]), strip_hints, strip_empty, &set, varidx_delta_map);
}
record = &StructAtOffset<const PairValueRecord> (record, record_size);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh
index de15a29e3c..9c805b39a1 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairPosFormat2.hh
@@ -8,7 +8,7 @@ namespace Layout {
namespace GPOS_impl {
template <typename Types>
-struct PairPosFormat2_4
+struct PairPosFormat2_4 : ValueBase
{
protected:
HBUINT16 format; /* Format identifier--format = 2 */
@@ -50,13 +50,13 @@ struct PairPosFormat2_4
unsigned int len1 = valueFormat1.get_len ();
unsigned int len2 = valueFormat2.get_len ();
unsigned int stride = HBUINT16::static_size * (len1 + len2);
- unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
return_trace (c->check_range ((const void *) values,
count,
- record_size) &&
- valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
- valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
+ stride) &&
+ (c->lazy_some_gpos ||
+ (valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
+ valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride))));
}
bool intersects (const hb_set_t *glyphs) const
@@ -131,40 +131,46 @@ struct PairPosFormat2_4
if (likely (index == NOT_COVERED)) return_trace (false);
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
- skippy_iter.reset (buffer->idx, 1);
+ skippy_iter.reset_fast (buffer->idx);
unsigned unsafe_to;
- if (!skippy_iter.next (&unsafe_to))
+ if (unlikely (!skippy_iter.next (&unsafe_to)))
{
buffer->unsafe_to_concat (buffer->idx, unsafe_to);
return_trace (false);
}
- unsigned int len1 = valueFormat1.get_len ();
- unsigned int len2 = valueFormat2.get_len ();
- unsigned int record_len = len1 + len2;
+ unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
+ if (!klass2)
+ {
+ buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
+ return_trace (false);
+ }
unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
- unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
{
buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1);
return_trace (false);
}
+ unsigned int len1 = valueFormat1.get_len ();
+ unsigned int len2 = valueFormat2.get_len ();
+ unsigned int record_len = len1 + len2;
+
const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
bool applied_first = false, applied_second = false;
/* Isolate simple kerning and apply it half to each side.
- * Results in better cursor positinoing / underline drawing.
+ * Results in better cursor positioning / underline drawing.
*
* Disabled, because causes issues... :-(
* https://github.com/harfbuzz/harfbuzz/issues/3408
* https://github.com/harfbuzz/harfbuzz/pull/3235#issuecomment-1029814978
*/
#ifndef HB_SPLIT_KERN
- if (0)
+ if (false)
#endif
{
if (!len2)
@@ -224,8 +230,8 @@ struct PairPosFormat2_4
c->buffer->idx, skippy_iter.idx);
}
- applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos());
- applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
+ applied_first = len1 && valueFormat1.apply_value (c, this, v, buffer->cur_pos());
+ applied_second = len2 && valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
if (applied_first || applied_second)
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
@@ -281,44 +287,52 @@ struct PairPosFormat2_4
unsigned len2 = valueFormat2.get_len ();
hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat1, valueFormat2);
- if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
- newFormats = compute_effective_value_formats (klass1_map, klass2_map);
-
- out->valueFormat1 = newFormats.first;
- out->valueFormat2 = newFormats.second;
- if (c->plan->all_axes_pinned)
+ if (c->plan->normalized_coords)
+ {
+ /* in case of full instancing, all var device flags will be dropped so no
+ * need to strip hints here */
+ newFormats = compute_effective_value_formats (klass1_map, klass2_map, false, false, &c->plan->layout_variation_idx_delta_map);
+ }
+ /* do not strip hints for VF */
+ else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
{
- out->valueFormat1 = out->valueFormat1.drop_device_table_flags ();
- out->valueFormat2 = out->valueFormat2.drop_device_table_flags ();
+ hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r'));
+ bool has_fvar = (blob != hb_blob_get_empty ());
+ hb_blob_destroy (blob);
+
+ bool strip = !has_fvar;
+ /* special case: strip hints when a VF has no GDEF varstore after
+ * subsetting*/
+ if (has_fvar && !c->plan->has_gdef_varstore)
+ strip = true;
+ newFormats = compute_effective_value_formats (klass1_map, klass2_map, strip, true);
}
+ out->valueFormat1 = newFormats.first;
+ out->valueFormat2 = newFormats.second;
+
+ unsigned total_len = len1 + len2;
+ hb_vector_t<unsigned> class2_idxs (+ hb_range ((unsigned) class2Count) | hb_filter (klass2_map));
for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
{
- for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
+ for (unsigned class2_idx : class2_idxs)
{
- unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
+ unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * total_len;
valueFormat1.copy_values (c->serializer, out->valueFormat1, this, &values[idx], &c->plan->layout_variation_idx_delta_map);
valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], &c->plan->layout_variation_idx_delta_map);
}
}
- const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
- const hb_map_t &glyph_map = *c->plan->glyph_map;
-
- auto it =
- + hb_iter (this+coverage)
- | hb_filter (glyphset)
- | hb_map_retains_sorting (glyph_map)
- ;
-
- out->coverage.serialize_serialize (c->serializer, it);
- return_trace (out->class1Count && out->class2Count && bool (it));
+ bool ret = out->coverage.serialize_subset(c, coverage, this);
+ return_trace (out->class1Count && out->class2Count && ret);
}
hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_map_t& klass1_map,
- const hb_map_t& klass2_map) const
+ const hb_map_t& klass2_map,
+ bool strip_hints, bool strip_empty,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map = nullptr) const
{
unsigned len1 = valueFormat1.get_len ();
unsigned len2 = valueFormat2.get_len ();
@@ -332,8 +346,8 @@ struct PairPosFormat2_4
for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
{
unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * record_size;
- format1 = format1 | valueFormat1.get_effective_format (&values[idx]);
- format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]);
+ format1 = format1 | valueFormat1.get_effective_format (&values[idx], strip_hints, strip_empty, this, varidx_delta_map);
+ format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1], strip_hints, strip_empty, this, varidx_delta_map);
}
if (format1 == valueFormat1 && format2 == valueFormat2)
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh
index 147b8e00ea..5560fab174 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairSet.hh
@@ -9,7 +9,7 @@ namespace GPOS_impl {
template <typename Types>
-struct PairSet
+struct PairSet : ValueBase
{
template <typename Types2>
friend struct PairPosFormat1_3;
@@ -45,15 +45,18 @@ struct PairSet
bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
{
TRACE_SANITIZE (this);
- if (!(c->check_struct (this)
- && c->check_range (&firstPairValueRecord,
+ if (!(c->check_struct (this) &&
+ hb_barrier () &&
+ c->check_range (&firstPairValueRecord,
len,
closure->stride))) return_trace (false);
+ hb_barrier ();
unsigned int count = len;
const PairValueRecord *record = &firstPairValueRecord;
- return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
- closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride));
+ return_trace (c->lazy_some_gpos ||
+ (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
+ closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride)));
}
bool intersects (const hb_set_t *glyphs,
@@ -120,8 +123,8 @@ struct PairSet
c->buffer->idx, pos);
}
- bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
- bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
+ bool applied_first = len1 && valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
+ bool applied_second = len2 && valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
if (applied_first || applied_second)
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairValueRecord.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairValueRecord.hh
index 3222477764..d00618b763 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairValueRecord.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/PairValueRecord.hh
@@ -22,14 +22,14 @@ struct PairValueRecord
ValueRecord values; /* Positioning data for the first glyph
* followed by for second glyph */
public:
- DEFINE_SIZE_ARRAY (Types::size, values);
+ DEFINE_SIZE_ARRAY (Types::HBGlyphID::static_size, values);
int cmp (hb_codepoint_t k) const
{ return secondGlyph.cmp (k); }
struct context_t
{
- const void *base;
+ const ValueBase *base;
const ValueFormat *valueFormats;
const ValueFormat *newFormats;
unsigned len1; /* valueFormats[0].get_len() */
@@ -62,7 +62,7 @@ struct PairValueRecord
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
const ValueFormat *valueFormats,
- const void *base) const
+ const ValueBase *base) const
{
unsigned record1_len = valueFormats[0].get_len ();
unsigned record2_len = valueFormats[1].get_len ();
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePos.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePos.hh
index 3af6c49965..a0243a218c 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePos.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePos.hh
@@ -39,14 +39,12 @@ struct SinglePos
const SrcLookup* src,
Iterator glyph_val_iter_pairs,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
- bool all_axes_pinned)
+ unsigned newFormat)
{
if (unlikely (!c->extend_min (u.format))) return;
unsigned format = 2;
- ValueFormat new_format = src->get_value_format ();
-
- if (all_axes_pinned)
- new_format = new_format.drop_device_table_flags ();
+ ValueFormat new_format;
+ new_format = newFormat;
if (glyph_val_iter_pairs)
format = get_format (glyph_val_iter_pairs);
@@ -89,8 +87,8 @@ SinglePos_serialize (hb_serialize_context_t *c,
const SrcLookup *src,
Iterator it,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
- bool all_axes_pinned)
-{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_delta_map, all_axes_pinned); }
+ unsigned new_format)
+{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_delta_map, new_format); }
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat1.hh
index f7a170f34e..b2d151d446 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat1.hh
@@ -8,7 +8,7 @@ namespace OT {
namespace Layout {
namespace GPOS_impl {
-struct SinglePosFormat1
+struct SinglePosFormat1 : ValueBase
{
protected:
HBUINT16 format; /* Format identifier--format = 1 */
@@ -28,7 +28,16 @@ struct SinglePosFormat1
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
coverage.sanitize (c, this) &&
+ hb_barrier () &&
+ /* The coverage table may use a range to represent a set
+ * of glyphs, which means a small number of bytes can
+ * generate a large glyph set. Manually modify the
+ * sanitizer max ops to take this into account.
+ *
+ * Note: This check *must* be right after coverage sanitize. */
+ c->check_ops ((this + coverage).get_population () >> 1) &&
valueFormat.sanitize_value (c, this, values));
+
}
bool intersects (const hb_set_t *glyphs) const
@@ -82,6 +91,7 @@ struct SinglePosFormat1
bool
position_single (hb_font_t *font,
+ hb_blob_t *table_blob,
hb_direction_t direction,
hb_codepoint_t gid,
hb_glyph_position_t &pos) const
@@ -92,7 +102,7 @@ struct SinglePosFormat1
/* This is ugly... */
hb_buffer_t buffer;
buffer.props.direction = direction;
- OT::hb_ot_apply_context_t c (1, font, &buffer);
+ OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob);
valueFormat.apply_value (&c, this, values, pos);
return true;
@@ -137,6 +147,30 @@ struct SinglePosFormat1
hb_set_t intersection;
(this+coverage).intersect_set (glyphset, intersection);
+ unsigned new_format = valueFormat;
+
+ if (c->plan->normalized_coords)
+ {
+ new_format = valueFormat.get_effective_format (values.arrayZ, false, false, this, &c->plan->layout_variation_idx_delta_map);
+ }
+ /* do not strip hints for VF */
+ else if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+ {
+ hb_blob_t* blob = hb_face_reference_table (c->plan->source, HB_TAG ('f','v','a','r'));
+ bool has_fvar = (blob != hb_blob_get_empty ());
+ hb_blob_destroy (blob);
+
+ bool strip = !has_fvar;
+ /* special case: strip hints when a VF has no GDEF varstore after
+ * subsetting*/
+ if (has_fvar && !c->plan->has_gdef_varstore)
+ strip = true;
+ new_format = valueFormat.get_effective_format (values.arrayZ,
+ strip, /* strip hints */
+ true, /* strip empty */
+ this, nullptr);
+ }
+
auto it =
+ hb_iter (intersection)
| hb_map_retains_sorting (glyph_map)
@@ -144,7 +178,7 @@ struct SinglePosFormat1
;
bool ret = bool (it);
- SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned);
+ SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, new_format);
return_trace (ret);
}
};
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat2.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat2.hh
index e8f2d7c2c6..ae4a5ed756 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat2.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/SinglePosFormat2.hh
@@ -7,7 +7,7 @@ namespace OT {
namespace Layout {
namespace GPOS_impl {
-struct SinglePosFormat2
+struct SinglePosFormat2 : ValueBase
{
protected:
HBUINT16 format; /* Format identifier--format = 2 */
@@ -94,6 +94,7 @@ struct SinglePosFormat2
bool
position_single (hb_font_t *font,
+ hb_blob_t *table_blob,
hb_direction_t direction,
hb_codepoint_t gid,
hb_glyph_position_t &pos) const
@@ -105,7 +106,7 @@ struct SinglePosFormat2
/* This is ugly... */
hb_buffer_t buffer;
buffer.props.direction = direction;
- OT::hb_ot_apply_context_t c (1, font, &buffer);
+ OT::hb_ot_apply_context_t c (1, font, &buffer, table_blob);
valueFormat.apply_value (&c, this,
&values[index * valueFormat.get_len ()],
@@ -142,6 +143,37 @@ struct SinglePosFormat2
coverage.serialize_serialize (c, glyphs);
}
+ template<typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ unsigned compute_effective_format (const hb_face_t *face,
+ Iterator it,
+ bool is_instancing, bool strip_hints,
+ bool has_gdef_varstore,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const
+ {
+ hb_blob_t* blob = hb_face_reference_table (face, HB_TAG ('f','v','a','r'));
+ bool has_fvar = (blob != hb_blob_get_empty ());
+ hb_blob_destroy (blob);
+
+ unsigned new_format = 0;
+ if (is_instancing)
+ {
+ new_format = new_format | valueFormat.get_effective_format (+ it | hb_map (hb_second), false, false, this, varidx_delta_map);
+ }
+ /* do not strip hints for VF */
+ else if (strip_hints)
+ {
+ bool strip = !has_fvar;
+ if (has_fvar && !has_gdef_varstore)
+ strip = true;
+ new_format = new_format | valueFormat.get_effective_format (+ it | hb_map (hb_second), strip, true, this, nullptr);
+ }
+ else
+ new_format = valueFormat;
+
+ return new_format;
+ }
+
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
@@ -162,8 +194,13 @@ struct SinglePosFormat2
})
;
+ unsigned new_format = compute_effective_format (c->plan->source, it,
+ bool (c->plan->normalized_coords),
+ bool (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING),
+ c->plan->has_gdef_varstore,
+ &c->plan->layout_variation_idx_delta_map);
bool ret = bool (it);
- SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned);
+ SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, new_format);
return_trace (ret);
}
};
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh
index 1aa451abcc..9442cc1cc5 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GPOS/ValueFormat.hh
@@ -9,6 +9,8 @@ namespace GPOS_impl {
typedef HBUINT16 Value;
+struct ValueBase {}; // Dummy base class tag for OffsetTo<Value> bases.
+
typedef UnsizedArrayOf<Value> ValueRecord;
struct ValueFormat : HBUINT16
@@ -78,7 +80,7 @@ struct ValueFormat : HBUINT16
}
bool apply_value (hb_ot_apply_context_t *c,
- const void *base,
+ const ValueBase *base,
const Value *values,
hb_glyph_position_t &glyph_pos) const
{
@@ -114,35 +116,57 @@ struct ValueFormat : HBUINT16
if (!use_x_device && !use_y_device) return ret;
- const VariationStore &store = c->var_store;
+ const ItemVariationStore &store = c->var_store;
auto *cache = c->var_store_cache;
/* pixel -> fractional pixel */
- if (format & xPlaDevice) {
- if (use_x_device) glyph_pos.x_offset += (base + get_device (values, &ret)).get_x_delta (font, store, cache);
+ if (format & xPlaDevice)
+ {
+ if (use_x_device) glyph_pos.x_offset += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache);
values++;
}
- if (format & yPlaDevice) {
- if (use_y_device) glyph_pos.y_offset += (base + get_device (values, &ret)).get_y_delta (font, store, cache);
+ if (format & yPlaDevice)
+ {
+ if (use_y_device) glyph_pos.y_offset += get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache);
values++;
}
- if (format & xAdvDevice) {
- if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store, cache);
+ if (format & xAdvDevice)
+ {
+ if (horizontal && use_x_device) glyph_pos.x_advance += get_device (values, &ret, base, c->sanitizer).get_x_delta (font, store, cache);
values++;
}
- if (format & yAdvDevice) {
+ if (format & yAdvDevice)
+ {
/* y_advance values grow downward but font-space grows upward, hence negation */
- if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store, cache);
+ if (!horizontal && use_y_device) glyph_pos.y_advance -= get_device (values, &ret, base, c->sanitizer).get_y_delta (font, store, cache);
values++;
}
return ret;
}
- unsigned int get_effective_format (const Value *values) const
+ unsigned int get_effective_format (const Value *values, bool strip_hints, bool strip_empty, const ValueBase *base,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const
{
unsigned int format = *this;
for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) {
- if (format & flag) should_drop (*values++, (Flags) flag, &format);
+ if (format & flag)
+ {
+ if (strip_hints && flag >= xPlaDevice)
+ {
+ format = format & ~flag;
+ values++;
+ continue;
+ }
+ if (varidx_delta_map && flag >= xPlaDevice)
+ {
+ update_var_flag (values++, (Flags) flag, &format, base, varidx_delta_map);
+ continue;
+ }
+ /* do not strip empty when instancing, cause we don't know whether the new
+ * default value is 0 or not */
+ if (strip_empty) should_drop (*values, (Flags) flag, &format);
+ values++;
+ }
}
return format;
@@ -150,18 +174,19 @@ struct ValueFormat : HBUINT16
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
- unsigned int get_effective_format (Iterator it) const {
+ unsigned int get_effective_format (Iterator it, bool strip_hints, bool strip_empty, const ValueBase *base,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const {
unsigned int new_format = 0;
for (const hb_array_t<const Value>& values : it)
- new_format = new_format | get_effective_format (&values);
+ new_format = new_format | get_effective_format (&values, strip_hints, strip_empty, base, varidx_delta_map);
return new_format;
}
void copy_values (hb_serialize_context_t *c,
unsigned int new_format,
- const void *base,
+ const ValueBase *base,
const Value *values,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
{
@@ -174,6 +199,9 @@ struct ValueFormat : HBUINT16
if (format & xAdvance) x_adv = copy_value (c, new_format, xAdvance, *values++);
if (format & yAdvance) y_adv = copy_value (c, new_format, yAdvance, *values++);
+ if (!has_device ())
+ return;
+
if (format & xPlaDevice)
{
add_delta_to_value (x_placement, base, values, layout_variation_idx_delta_map);
@@ -210,7 +238,7 @@ struct ValueFormat : HBUINT16
}
void collect_variation_indices (hb_collect_variation_indices_context_t *c,
- const void *base,
+ const ValueBase *base,
const hb_array_t<const Value>& values) const
{
unsigned format = *this;
@@ -233,30 +261,19 @@ struct ValueFormat : HBUINT16
if (format & ValueFormat::xAdvDevice)
{
-
(base + get_device (&(values[i]))).collect_variation_indices (c);
i++;
}
if (format & ValueFormat::yAdvDevice)
{
-
(base + get_device (&(values[i]))).collect_variation_indices (c);
i++;
}
}
- unsigned drop_device_table_flags () const
- {
- unsigned format = *this;
- for (unsigned flag = xPlaDevice; flag <= yAdvDevice; flag = flag << 1)
- format = format & ~flag;
-
- return format;
- }
-
private:
- bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
+ bool sanitize_value_devices (hb_sanitize_context_t *c, const ValueBase *base, const Value *values) const
{
unsigned int format = *this;
@@ -273,18 +290,31 @@ struct ValueFormat : HBUINT16
return true;
}
- static inline Offset16To<Device>& get_device (Value* value)
+ static inline Offset16To<Device, ValueBase>& get_device (Value* value)
{
- return *static_cast<Offset16To<Device> *> (value);
+ return *static_cast<Offset16To<Device, ValueBase> *> (value);
}
- static inline const Offset16To<Device>& get_device (const Value* value, bool *worked=nullptr)
+ static inline const Offset16To<Device, ValueBase>& get_device (const Value* value)
+ {
+ return *static_cast<const Offset16To<Device, ValueBase> *> (value);
+ }
+ static inline const Device& get_device (const Value* value,
+ bool *worked,
+ const ValueBase *base,
+ hb_sanitize_context_t &c)
{
if (worked) *worked |= bool (*value);
- return *static_cast<const Offset16To<Device> *> (value);
+ auto &offset = *static_cast<const Offset16To<Device> *> (value);
+
+ if (unlikely (!offset.sanitize (&c, base)))
+ return Null(Device);
+ hb_barrier ();
+
+ return base + offset;
}
void add_delta_to_value (HBINT16 *value,
- const void *base,
+ const ValueBase *base,
const Value *src_value,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map) const
{
@@ -296,7 +326,8 @@ struct ValueFormat : HBUINT16
*value += hb_second (*varidx_delta);
}
- bool copy_device (hb_serialize_context_t *c, const void *base,
+ bool copy_device (hb_serialize_context_t *c,
+ const ValueBase *base,
const Value *src_value,
const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map,
unsigned int new_format, Flags flag) const
@@ -337,32 +368,34 @@ struct ValueFormat : HBUINT16
return (format & devices) != 0;
}
- bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
+ bool sanitize_value (hb_sanitize_context_t *c, const ValueBase *base, const Value *values) const
{
TRACE_SANITIZE (this);
- return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
+
+ if (unlikely (!c->check_range (values, get_size ()))) return_trace (false);
+
+ if (c->lazy_some_gpos)
+ return_trace (true);
+
+ return_trace (!has_device () || sanitize_value_devices (c, base, values));
}
- bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
+ bool sanitize_values (hb_sanitize_context_t *c, const ValueBase *base, const Value *values, unsigned int count) const
{
TRACE_SANITIZE (this);
- unsigned int len = get_len ();
-
- if (!c->check_range (values, count, get_size ())) return_trace (false);
+ unsigned size = get_size ();
- if (!has_device ()) return_trace (true);
+ if (!c->check_range (values, count, size)) return_trace (false);
- for (unsigned int i = 0; i < count; i++) {
- if (!sanitize_value_devices (c, base, values))
- return_trace (false);
- values += len;
- }
+ if (c->lazy_some_gpos)
+ return_trace (true);
- return_trace (true);
+ hb_barrier ();
+ return_trace (sanitize_values_stride_unsafe (c, base, values, count, size));
}
/* Just sanitize referenced Device tables. Doesn't check the values themselves. */
- bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
+ bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const ValueBase *base, const Value *values, unsigned int count, unsigned int stride) const
{
TRACE_SANITIZE (this);
@@ -385,6 +418,20 @@ struct ValueFormat : HBUINT16
*format = *format & ~flag;
}
+ void update_var_flag (const Value* value, Flags flag,
+ unsigned int* format, const ValueBase *base,
+ const hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map) const
+ {
+ if (*value)
+ {
+ unsigned varidx = (base + get_device (value)).get_variation_index ();
+ hb_pair_t<unsigned, int> *varidx_delta;
+ if (varidx_delta_map->has (varidx, &varidx_delta) &&
+ varidx_delta->first != HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
+ return;
+ }
+ *format = *format & ~flag;
+ }
};
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Common.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Common.hh
index 968bba0481..b849494d88 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Common.hh
@@ -8,8 +8,6 @@ namespace OT {
namespace Layout {
namespace GSUB_impl {
-typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
-
template<typename Iterator>
static void SingleSubst_serialize (hb_serialize_context_t *c,
Iterator it);
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh
index ffe39d52ab..402ed12ae2 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Ligature.hh
@@ -10,10 +10,10 @@ namespace GSUB_impl {
template <typename Types>
struct Ligature
{
- protected:
+ public:
typename Types::HBGlyphID
ligGlyph; /* GlyphID of ligature to substitute */
- HeadlessArrayOf<typename Types::HBGlyphID>
+ HeadlessArray16Of<typename Types::HBGlyphID>
component; /* Array of component GlyphIDs--start
* with the second component--ordered
* in writing direction */
@@ -29,6 +29,9 @@ struct Ligature
bool intersects (const hb_set_t *glyphs) const
{ return hb_all (component, glyphs); }
+ bool intersects_lig_glyph (const hb_set_t *glyphs) const
+ { return glyphs->has(ligGlyph); }
+
void closure (hb_closure_context_t *c) const
{
if (!intersects (c->glyphs)) return;
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSet.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSet.hh
index 637cec7137..08665438c4 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSet.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSet.hh
@@ -34,6 +34,18 @@ struct LigatureSet
;
}
+ bool intersects_lig_glyph (const hb_set_t *glyphs) const
+ {
+ return
+ + hb_iter (ligature)
+ | hb_map (hb_add (this))
+ | hb_map ([glyphs] (const Ligature<Types> &_) {
+ return _.intersects_lig_glyph (glyphs) && _.intersects (glyphs);
+ })
+ | hb_any
+ ;
+ }
+
void closure (hb_closure_context_t *c) const
{
+ hb_iter (ligature)
@@ -63,12 +75,69 @@ struct LigatureSet
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
+
unsigned int num_ligs = ligature.len;
+
+#ifndef HB_NO_OT_RULESETS_FAST_PATH
+ if (HB_OPTIMIZE_SIZE_VAL || num_ligs <= 4)
+#endif
+ {
+ slow:
+ for (unsigned int i = 0; i < num_ligs; i++)
+ {
+ const auto &lig = this+ligature.arrayZ[i];
+ if (lig.apply (c)) return_trace (true);
+ }
+ return_trace (false);
+ }
+
+ /* This version is optimized for speed by matching the first component
+ * of the ligature here, instead of calling into the ligation code.
+ *
+ * This is replicated in ChainRuleSet and RuleSet. */
+
+ hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (c->buffer->idx);
+ skippy_iter.set_match_func (match_always, nullptr);
+ skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
+ unsigned unsafe_to;
+ hb_codepoint_t first = (unsigned) -1;
+ bool matched = skippy_iter.next (&unsafe_to);
+ if (likely (matched))
+ {
+ first = c->buffer->info[skippy_iter.idx].codepoint;
+ unsafe_to = skippy_iter.idx + 1;
+
+ if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
+ {
+ /* Can't use the fast path if eg. the next char is a default-ignorable
+ * or other skippable. */
+ goto slow;
+ }
+ }
+ else
+ goto slow;
+
+ bool unsafe_to_concat = false;
+
for (unsigned int i = 0; i < num_ligs; i++)
{
- const auto &lig = this+ligature[i];
- if (lig.apply (c)) return_trace (true);
+ const auto &lig = this+ligature.arrayZ[i];
+ if (unlikely (lig.component.lenP1 <= 1) ||
+ lig.component.arrayZ[0] == first)
+ {
+ if (lig.apply (c))
+ {
+ if (unsafe_to_concat)
+ c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
+ return_trace (true);
+ }
+ }
+ else if (likely (lig.component.lenP1 > 1))
+ unsafe_to_concat = true;
}
+ if (likely (unsafe_to_concat))
+ c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
return_trace (false);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh
index 32b642c38a..5c7df97d13 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/LigatureSubstFormat1.hh
@@ -130,7 +130,7 @@ struct LigatureSubstFormat1_2
+ hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this)))
| hb_filter (glyphset, hb_first)
| hb_filter ([&] (const LigatureSet<Types>& _) {
- return _.intersects (&glyphset);
+ return _.intersects_lig_glyph (&glyphset);
}, hb_second)
| hb_map (hb_first)
| hb_sink (new_coverage);
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
index 2c2e1aa44f..ec374f2f02 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
@@ -33,9 +33,11 @@ struct ReverseChainSingleSubstFormat1
TRACE_SANITIZE (this);
if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
return_trace (false);
+ hb_barrier ();
const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
if (!lookahead.sanitize (c, this))
return_trace (false);
+ hb_barrier ();
const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
return_trace (substitute.sanitize (c));
}
@@ -109,12 +111,12 @@ struct ReverseChainSingleSubstFormat1
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
- 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);
if (likely (index == NOT_COVERED)) return_trace (false);
+ if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
+ return_trace (false); /* No chaining to this type */
+
const auto &lookahead = StructAfter<decltype (lookaheadX)> (backtrack);
const auto &substitute = StructAfter<decltype (substituteX)> (lookahead);
@@ -191,7 +193,6 @@ struct ReverseChainSingleSubstFormat1
TRACE_SERIALIZE (this);
auto *out = c->serializer->start_embed (this);
- if (unlikely (!c->serializer->check_success (out))) return_trace (false);
if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false);
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Sequence.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Sequence.hh
index ae3292f329..a26cf8c6a6 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Sequence.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/Sequence.hh
@@ -53,7 +53,7 @@ struct Sequence
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
{
c->buffer->message (c->font,
- "replaced glyph at %u (multiple subtitution)",
+ "replaced glyph at %u (multiple substitution)",
c->buffer->idx - 1u);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubst.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubst.hh
index 4529927ba6..181c9e52e5 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubst.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubst.hh
@@ -57,7 +57,7 @@ struct SingleSubst
#ifndef HB_NO_BEYOND_64K
if (+ glyphs
- | hb_map_retains_sorting (hb_first)
+ | hb_map_retains_sorting (hb_second)
| hb_filter ([] (hb_codepoint_t gid) { return gid > 0xFFFFu; }))
{
format += 2;
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat1.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat1.hh
index 78725352c2..850be86c04 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat1.hh
@@ -25,7 +25,15 @@ struct SingleSubstFormat1_3
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
+ return_trace (c->check_struct (this) &&
+ coverage.sanitize (c, this) &&
+ /* The coverage table may use a range to represent a set
+ * of glyphs, which means a small number of bytes can
+ * generate a large glyph set. Manually modify the
+ * sanitizer max ops to take this into account.
+ *
+ * Note: This check *must* be right after coverage sanitize. */
+ c->check_ops ((this + coverage).get_population () >> 1));
}
hb_codepoint_t get_mask () const
@@ -87,6 +95,34 @@ struct SingleSubstFormat1_3
bool would_apply (hb_would_apply_context_t *c) const
{ return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
+ unsigned
+ get_glyph_alternates (hb_codepoint_t glyph_id,
+ unsigned start_offset,
+ unsigned *alternate_count /* IN/OUT. May be NULL. */,
+ hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const
+ {
+ unsigned int index = (this+coverage).get_coverage (glyph_id);
+ if (likely (index == NOT_COVERED))
+ {
+ if (alternate_count)
+ *alternate_count = 0;
+ return 0;
+ }
+
+ if (alternate_count && *alternate_count)
+ {
+ hb_codepoint_t d = deltaGlyphID;
+ hb_codepoint_t mask = get_mask ();
+
+ glyph_id = (glyph_id + d) & mask;
+
+ *alternate_glyphs = glyph_id;
+ *alternate_count = 1;
+ }
+
+ return 1;
+ }
+
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat2.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat2.hh
index 17aa087363..9c651abe71 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat2.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/GSUB/SingleSubstFormat2.hh
@@ -75,6 +75,31 @@ struct SingleSubstFormat2_4
bool would_apply (hb_would_apply_context_t *c) const
{ return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
+ unsigned
+ get_glyph_alternates (hb_codepoint_t glyph_id,
+ unsigned start_offset,
+ unsigned *alternate_count /* IN/OUT. May be NULL. */,
+ hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const
+ {
+ unsigned int index = (this+coverage).get_coverage (glyph_id);
+ if (likely (index == NOT_COVERED))
+ {
+ if (alternate_count)
+ *alternate_count = 0;
+ return 0;
+ }
+
+ if (alternate_count && *alternate_count)
+ {
+ glyph_id = substitute[index];
+
+ *alternate_glyphs = glyph_id;
+ *alternate_count = 1;
+ }
+
+ return 1;
+ }
+
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh b/src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh
index 6a43403e94..3840db0598 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/Layout/types.hh
@@ -38,8 +38,8 @@ struct SmallTypes {
using HBUINT = HBUINT16;
using HBGlyphID = HBGlyphID16;
using Offset = Offset16;
- template <typename Type, bool has_null=true>
- using OffsetTo = OT::Offset16To<Type, has_null>;
+ template <typename Type, typename BaseType=void, bool has_null=true>
+ using OffsetTo = OT::Offset16To<Type, BaseType, has_null>;
template <typename Type>
using ArrayOf = OT::Array16Of<Type>;
template <typename Type>
@@ -52,8 +52,8 @@ struct MediumTypes {
using HBUINT = HBUINT24;
using HBGlyphID = HBGlyphID24;
using Offset = Offset24;
- template <typename Type, bool has_null=true>
- using OffsetTo = OT::Offset24To<Type, has_null>;
+ template <typename Type, typename BaseType=void, bool has_null=true>
+ using OffsetTo = OT::Offset24To<Type, BaseType, has_null>;
template <typename Type>
using ArrayOf = OT::Array24Of<Type>;
template <typename Type>
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh
index edf8cd8797..5c0ecd5133 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/CompositeGlyph.hh
@@ -87,27 +87,69 @@ struct CompositeGlyphRecord
}
}
- void transform_points (contour_point_vector_t &points) const
+ static void transform (const float (&matrix)[4],
+ hb_array_t<contour_point_t> points)
{
- float matrix[4];
- contour_point_t trans;
- if (get_transformation (matrix, trans))
+ if (matrix[0] != 1.f || matrix[1] != 0.f ||
+ matrix[2] != 0.f || matrix[3] != 1.f)
+ for (auto &point : points)
+ point.transform (matrix);
+ }
+
+ static void translate (const contour_point_t &trans,
+ hb_array_t<contour_point_t> points)
+ {
+ if (HB_OPTIMIZE_SIZE_VAL)
{
- if (scaled_offsets ())
- {
- points.translate (trans);
- points.transform (matrix);
- }
+ if (trans.x != 0.f || trans.y != 0.f)
+ for (auto &point : points)
+ point.translate (trans);
+ }
+ else
+ {
+ if (trans.x != 0.f && trans.y != 0.f)
+ for (auto &point : points)
+ point.translate (trans);
else
{
- points.transform (matrix);
- points.translate (trans);
+ if (trans.x != 0.f)
+ for (auto &point : points)
+ point.x += trans.x;
+ else if (trans.y != 0.f)
+ for (auto &point : points)
+ point.y += trans.y;
}
}
}
- unsigned compile_with_deltas (const contour_point_t &p_delta,
- char *out) const
+ void transform_points (hb_array_t<contour_point_t> points,
+ const float (&matrix)[4],
+ const contour_point_t &trans) const
+ {
+ if (scaled_offsets ())
+ {
+ translate (trans, points);
+ transform (matrix, points);
+ }
+ else
+ {
+ transform (matrix, points);
+ translate (trans, points);
+ }
+ }
+
+ bool get_points (contour_point_vector_t &points) const
+ {
+ float matrix[4];
+ contour_point_t trans;
+ get_transformation (matrix, trans);
+ if (unlikely (!points.alloc (points.length + 4))) return false; // For phantom points
+ points.push (trans);
+ return true;
+ }
+
+ unsigned compile_with_point (const contour_point_t &point,
+ char *out) const
{
const HBINT8 *p = &StructAfter<const HBINT8> (flags);
#ifndef HB_NO_BEYOND_64K
@@ -121,18 +163,17 @@ struct CompositeGlyphRecord
unsigned len_before_val = (const char *)p - (const char *)this;
if (flags & ARG_1_AND_2_ARE_WORDS)
{
- // no overflow, copy and update value with deltas
+ // no overflow, copy value
hb_memcpy (out, this, len);
- const HBINT16 *px = reinterpret_cast<const HBINT16 *> (p);
HBINT16 *o = reinterpret_cast<HBINT16 *> (out + len_before_val);
- o[0] = px[0] + roundf (p_delta.x);
- o[1] = px[1] + roundf (p_delta.y);
+ o[0] = roundf (point.x);
+ o[1] = roundf (point.y);
}
else
{
- int new_x = p[0] + roundf (p_delta.x);
- int new_y = p[1] + roundf (p_delta.y);
+ int new_x = roundf (point.x);
+ int new_y = roundf (point.y);
if (new_x <= 127 && new_x >= -128 &&
new_y <= 127 && new_y >= -128)
{
@@ -143,7 +184,7 @@ struct CompositeGlyphRecord
}
else
{
- // int8 overflows after deltas applied
+ // new point value has an int8 overflow
hb_memcpy (out, this, len_before_val);
//update flags
@@ -171,6 +212,7 @@ struct CompositeGlyphRecord
bool scaled_offsets () const
{ return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; }
+ public:
bool get_transformation (float (&matrix)[4], contour_point_t &trans) const
{
matrix[0] = matrix[3] = 1.f;
@@ -198,7 +240,8 @@ struct CompositeGlyphRecord
}
if (is_anchored ()) tx = ty = 0;
- trans.init ((float) tx, (float) ty);
+ /* set is_end_point flag to true, used by IUP delta optimization */
+ trans.init ((float) tx, (float) ty, true);
{
const F2DOT14 *points = (const F2DOT14 *) p;
@@ -225,7 +268,6 @@ struct CompositeGlyphRecord
return tx || ty;
}
- public:
hb_codepoint_t get_gid () const
{
#ifndef HB_NO_BEYOND_64K
@@ -246,6 +288,27 @@ struct CompositeGlyphRecord
StructAfter<HBGlyphID16> (flags) = gid;
}
+#ifndef HB_NO_BEYOND_64K
+ void lower_gid_24_to_16 ()
+ {
+ hb_codepoint_t gid = get_gid ();
+ if (!(flags & GID_IS_24BIT) || gid > 0xFFFFu)
+ return;
+
+ /* Lower the flag and move the rest of the struct down. */
+
+ unsigned size = get_size ();
+ char *end = (char *) this + size;
+ char *p = &StructAfter<char> (flags);
+ p += HBGlyphID24::static_size;
+
+ flags = flags & ~GID_IS_24BIT;
+ set_gid (gid);
+
+ memmove (p - HBGlyphID24::static_size + HBGlyphID16::static_size, p, end - p);
+ }
+#endif
+
protected:
HBUINT16 flags;
HBUINT24 pad;
@@ -304,7 +367,7 @@ struct CompositeGlyph
}
bool compile_bytes_with_deltas (const hb_bytes_t &source_bytes,
- const contour_point_vector_t &deltas,
+ const contour_point_vector_t &points_with_deltas,
hb_bytes_t &dest_bytes /* OUT */)
{
if (source_bytes.length <= GlyphHeader::static_size ||
@@ -319,7 +382,7 @@ struct CompositeGlyph
/* try to allocate more memories than source glyph bytes
* in case that there might be an overflow for int8 value
* and we would need to use int16 instead */
- char *o = (char *) hb_calloc (source_len + source_len/2, sizeof (char));
+ char *o = (char *) hb_calloc (source_len * 2, sizeof (char));
if (unlikely (!o)) return false;
const CompositeGlyphRecord *c = reinterpret_cast<const CompositeGlyphRecord *> (source_bytes.arrayZ + GlyphHeader::static_size);
@@ -329,8 +392,11 @@ struct CompositeGlyph
unsigned i = 0, source_comp_len = 0;
for (const auto &component : it)
{
- /* last 4 points in deltas are phantom points and should not be included */
- if (i >= deltas.length - 4) return false;
+ /* last 4 points in points_with_deltas are phantom points and should not be included */
+ if (i >= points_with_deltas.length - 4) {
+ hb_free (o);
+ return false;
+ }
unsigned comp_len = component.get_size ();
if (component.is_anchored ())
@@ -340,7 +406,7 @@ struct CompositeGlyph
}
else
{
- unsigned new_len = component.compile_with_deltas (deltas[i], p);
+ unsigned new_len = component.compile_with_point (points_with_deltas[i], p);
p += new_len;
}
i++;
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh
index 5574ae0722..69a0b625c7 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/Glyph.hh
@@ -29,7 +29,14 @@ enum phantom_point_index_t
struct Glyph
{
- enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE, VAR_COMPOSITE };
+ enum glyph_type_t {
+ EMPTY,
+ SIMPLE,
+ COMPOSITE,
+#ifndef HB_NO_VAR_COMPOSITES
+ VAR_COMPOSITE,
+#endif
+ };
public:
composite_iter_t get_composite_iterator () const
@@ -39,15 +46,23 @@ struct Glyph
}
var_composite_iter_t get_var_composite_iterator () const
{
+#ifndef HB_NO_VAR_COMPOSITES
if (type != VAR_COMPOSITE) return var_composite_iter_t ();
return VarCompositeGlyph (*header, bytes).iter ();
+#else
+ return var_composite_iter_t ();
+#endif
}
const hb_bytes_t trim_padding () const
{
switch (type) {
+#ifndef HB_NO_VAR_COMPOSITES
+ case VAR_COMPOSITE: return VarCompositeGlyph (*header, bytes).trim_padding ();
+#endif
case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding ();
case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding ();
+ case EMPTY: return bytes;
default: return bytes;
}
}
@@ -55,28 +70,97 @@ struct Glyph
void drop_hints ()
{
switch (type) {
+#ifndef HB_NO_VAR_COMPOSITES
+ case VAR_COMPOSITE: return; // No hinting
+#endif
case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return;
case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return;
- default: return;
+ case EMPTY: return;
}
}
void set_overlaps_flag ()
{
switch (type) {
+#ifndef HB_NO_VAR_COMPOSITES
+ case VAR_COMPOSITE: return; // No overlaps flag
+#endif
case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return;
case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return;
- default: return;
+ case EMPTY: return;
}
}
void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
{
switch (type) {
+#ifndef HB_NO_VAR_COMPOSITES
+ case VAR_COMPOSITE: return; // No hinting
+#endif
case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return;
case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return;
- default: return;
+ case EMPTY: return;
+ }
+ }
+
+ bool is_composite () const
+ { return type == COMPOSITE; }
+
+ bool get_all_points_without_var (const hb_face_t *face,
+ contour_point_vector_t &points /* OUT */) const
+ {
+ switch (type) {
+ case SIMPLE:
+ if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points)))
+ return false;
+ break;
+ case COMPOSITE:
+ {
+ for (auto &item : get_composite_iterator ())
+ if (unlikely (!item.get_points (points))) return false;
+ break;
+ }
+#ifndef HB_NO_VAR_COMPOSITES
+ case VAR_COMPOSITE:
+ {
+ for (auto &item : get_var_composite_iterator ())
+ if (unlikely (!item.get_points (points))) return false;
+ break;
+ }
+#endif
+ case EMPTY:
+ break;
+ }
+
+ /* Init phantom points */
+ if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
+ hb_array_t<contour_point_t> phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
+ {
+ int lsb = 0;
+ int h_delta = face->table.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ?
+ (int) header->xMin - lsb : 0;
+ HB_UNUSED int tsb = 0;
+ int v_orig = (int) header->yMax +
+#ifndef HB_NO_VERTICAL
+ ((void) face->table.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb)
+#else
+ 0
+#endif
+ ;
+ unsigned h_adv = face->table.hmtx->get_advance_without_var_unscaled (gid);
+ unsigned v_adv =
+#ifndef HB_NO_VERTICAL
+ face->table.vmtx->get_advance_without_var_unscaled (gid)
+#else
+ - face->get_upem ()
+#endif
+ ;
+ phantoms[PHANTOM_LEFT].x = h_delta;
+ phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta;
+ phantoms[PHANTOM_TOP].y = v_orig;
+ phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
}
+ return true;
}
void update_mtx (const hb_subset_plan_t *plan,
@@ -90,8 +174,8 @@ struct Glyph
if (type != EMPTY)
{
- plan->bounds_width_map.set (new_gid, xMax - xMin);
- plan->bounds_height_map.set (new_gid, yMax - yMin);
+ plan->bounds_width_vec[new_gid] = xMax - xMin;
+ plan->bounds_height_vec[new_gid] = yMax - yMin;
}
unsigned len = all_points.length;
@@ -100,10 +184,12 @@ struct Glyph
float topSideY = all_points[len - 2].y;
float bottomSideY = all_points[len - 1].y;
+ uint32_t hash = hb_hash (new_gid);
+
signed hori_aw = roundf (rightSideX - leftSideX);
if (hori_aw < 0) hori_aw = 0;
int lsb = roundf (xMin - leftSideX);
- plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb));
+ plan->hmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) hori_aw, lsb));
//flag value should be computed using non-empty glyphs
if (type != EMPTY && lsb != xMin)
plan->head_maxp_info.allXMinIsLsb = false;
@@ -111,7 +197,7 @@ struct Glyph
signed vert_aw = roundf (topSideY - bottomSideY);
if (vert_aw < 0) vert_aw = 0;
int tsb = roundf (topSideY - yMax);
- plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb));
+ plan->vmtx_map.set_with_hash (new_gid, hash, hb_pair ((unsigned) vert_aw, tsb));
}
bool compile_header_bytes (const hb_subset_plan_t *plan,
@@ -131,24 +217,28 @@ struct Glyph
{
xMin = xMax = all_points[0].x;
yMin = yMax = all_points[0].y;
- }
- for (unsigned i = 1; i < all_points.length - 4; i++)
- {
- float x = all_points[i].x;
- float y = all_points[i].y;
- xMin = hb_min (xMin, x);
- xMax = hb_max (xMax, x);
- yMin = hb_min (yMin, y);
- yMax = hb_max (yMax, y);
+ unsigned count = all_points.length - 4;
+ for (unsigned i = 1; i < count; i++)
+ {
+ float x = all_points[i].x;
+ float y = all_points[i].y;
+ xMin = hb_min (xMin, x);
+ xMax = hb_max (xMax, x);
+ yMin = hb_min (yMin, y);
+ yMax = hb_max (yMax, y);
+ }
}
- update_mtx (plan, roundf (xMin), roundf (xMax), roundf (yMin), roundf (yMax), all_points);
-
- int rounded_xMin = roundf (xMin);
- int rounded_xMax = roundf (xMax);
- int rounded_yMin = roundf (yMin);
- int rounded_yMax = roundf (yMax);
+
+ // These are destined for storage in a 16 bit field to clamp the values to
+ // fit into a 16 bit signed integer.
+ int rounded_xMin = hb_clamp (roundf (xMin), -32768.0f, 32767.0f);
+ int rounded_xMax = hb_clamp (roundf (xMax), -32768.0f, 32767.0f);
+ int rounded_yMin = hb_clamp (roundf (yMin), -32768.0f, 32767.0f);
+ int rounded_yMax = hb_clamp (roundf (yMax), -32768.0f, 32767.0f);
+
+ update_mtx (plan, rounded_xMin, rounded_xMax, rounded_yMin, rounded_yMax, all_points);
if (type != EMPTY)
{
@@ -181,7 +271,7 @@ struct Glyph
hb_bytes_t &dest_start, /* IN/OUT */
hb_bytes_t &dest_end /* OUT */)
{
- contour_point_vector_t all_points, deltas;
+ contour_point_vector_t all_points, points_with_deltas;
unsigned composite_contours = 0;
head_maxp_info_t *head_maxp_info_p = &plan->head_maxp_info;
unsigned *composite_contours_p = &composite_contours;
@@ -195,7 +285,7 @@ struct Glyph
composite_contours_p = nullptr;
}
- if (!get_points (font, glyf, all_points, &deltas, head_maxp_info_p, composite_contours_p, false, false))
+ if (!get_points (font, glyf, all_points, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false))
return false;
// .notdef, set type to empty so we only update metrics and don't compile bytes for
@@ -209,11 +299,20 @@ struct Glyph
}
//dont compile bytes when pinned at default, just recalculate bounds
- if (!plan->pinned_at_default) {
- switch (type) {
+ if (!plan->pinned_at_default)
+ {
+ switch (type)
+ {
+#ifndef HB_NO_VAR_COMPOSITES
+ case VAR_COMPOSITE:
+ // TODO
+ dest_end = hb_bytes_t ();
+ break;
+#endif
+
case COMPOSITE:
if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
- deltas,
+ points_with_deltas,
dest_end))
return false;
break;
@@ -223,7 +322,7 @@ struct Glyph
dest_end))
return false;
break;
- default:
+ case EMPTY:
/* set empty bytes for empty glyph
* do not use source glyph's pointers */
dest_start = hb_bytes_t ();
@@ -247,13 +346,14 @@ struct Glyph
template <typename accelerator_t>
bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
contour_point_vector_t &all_points /* OUT */,
- contour_point_vector_t *deltas = nullptr, /* OUT */
+ contour_point_vector_t *points_with_deltas = nullptr, /* OUT */
head_maxp_info_t * head_maxp_info = nullptr, /* OUT */
unsigned *composite_contours = nullptr, /* OUT */
bool shift_points_hori = true,
bool use_my_metrics = true,
bool phantom_only = false,
hb_array_t<int> coords = hb_array_t<int> (),
+ hb_map_t *current_glyphs = nullptr,
unsigned int depth = 0,
unsigned *edge_count = nullptr) const
{
@@ -262,7 +362,11 @@ struct Glyph
if (!edge_count) edge_count = &stack_edge_count;
if (unlikely (*edge_count > HB_GLYF_MAX_EDGE_COUNT)) return false;
(*edge_count)++;
-
+
+ hb_map_t current_glyphs_stack;
+ if (current_glyphs == nullptr)
+ current_glyphs = &current_glyphs_stack;
+
if (head_maxp_info)
{
head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth);
@@ -272,9 +376,8 @@ struct Glyph
coords = hb_array (font->coords, font->num_coords);
contour_point_vector_t stack_points;
- bool inplace = type == SIMPLE && all_points.length == 0;
- /* Load into all_points if it's empty, as an optimization. */
- contour_point_vector_t &points = inplace ? all_points : stack_points;
+ contour_point_vector_t &points = type == SIMPLE ? all_points : stack_points;
+ unsigned old_length = points.length;
switch (type) {
case SIMPLE:
@@ -282,14 +385,13 @@ struct Glyph
head_maxp_info->maxContours = hb_max (head_maxp_info->maxContours, (unsigned) header->numberOfContours);
if (depth > 0 && composite_contours)
*composite_contours += (unsigned) header->numberOfContours;
- if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only)))
+ if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (all_points, phantom_only)))
return false;
break;
case COMPOSITE:
{
- /* pseudo component points for each component in composite glyph */
- unsigned num_points = hb_len (CompositeGlyph (*header, bytes).iter ());
- if (unlikely (!points.resize (num_points))) return false;
+ for (auto &item : get_composite_iterator ())
+ if (unlikely (!item.get_points (points))) return false;
break;
}
#ifndef HB_NO_VAR_COMPOSITES
@@ -297,9 +399,10 @@ struct Glyph
{
for (auto &item : get_var_composite_iterator ())
if (unlikely (!item.get_points (points))) return false;
+ break;
}
#endif
- default:
+ case EMPTY:
break;
}
@@ -327,75 +430,84 @@ struct Glyph
#endif
;
phantoms[PHANTOM_LEFT].x = h_delta;
- phantoms[PHANTOM_RIGHT].x = h_adv + h_delta;
+ phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta;
phantoms[PHANTOM_TOP].y = v_orig;
phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
}
- if (deltas != nullptr && depth == 0 && type == COMPOSITE)
- {
- if (unlikely (!deltas->resize (points.length))) return false;
- deltas->copy_vector (points);
- }
-
#ifndef HB_NO_VAR
- glyf_accelerator.gvar->apply_deltas_to_points (gid,
- coords,
- points.as_array ());
+ if (coords)
+ glyf_accelerator.gvar->apply_deltas_to_points (gid,
+ coords,
+ points.as_array ().sub_array (old_length),
+ phantom_only && type == SIMPLE);
#endif
// mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it
// with child glyphs' points
- if (deltas != nullptr && depth == 0 && type == COMPOSITE)
+ if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE)
{
- for (unsigned i = 0 ; i < points.length; i++)
- {
- deltas->arrayZ[i].x = points.arrayZ[i].x - deltas->arrayZ[i].x;
- deltas->arrayZ[i].y = points.arrayZ[i].y - deltas->arrayZ[i].y;
- }
+ if (unlikely (!points_with_deltas->resize (points.length))) return false;
+ *points_with_deltas = points;
}
switch (type) {
case SIMPLE:
if (depth == 0 && head_maxp_info)
- head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, points.length - 4);
- if (!inplace)
- all_points.extend (points.as_array ());
+ head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, all_points.length - old_length - 4);
break;
case COMPOSITE:
{
- contour_point_vector_t comp_points;
unsigned int comp_index = 0;
for (auto &item : get_composite_iterator ())
{
- comp_points.reset ();
- if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
+ hb_codepoint_t item_gid = item.get_gid ();
+
+ if (unlikely (current_glyphs->has (item_gid)))
+ continue;
+
+ current_glyphs->add (item_gid);
+
+ unsigned old_count = all_points.length;
+
+ if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
+ !glyf_accelerator.glyph_for_gid (item_gid)
.get_points (font,
glyf_accelerator,
- comp_points,
- deltas,
+ all_points,
+ points_with_deltas,
head_maxp_info,
composite_contours,
shift_points_hori,
use_my_metrics,
phantom_only,
coords,
+ current_glyphs,
depth + 1,
edge_count)))
+ {
+ current_glyphs->del (item_gid);
return false;
+ }
+
+ auto comp_points = all_points.as_array ().sub_array (old_count);
/* Copy phantom points from component if USE_MY_METRICS flag set */
if (use_my_metrics && item.is_use_my_metrics ())
for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
- /* Apply component transformation & translation */
- item.transform_points (comp_points);
+ if (comp_points) // Empty in case of phantom_only
+ {
+ float matrix[4];
+ contour_point_t default_trans;
+ item.get_transformation (matrix, default_trans);
- /* Apply translation from gvar */
- comp_points.translate (points[comp_index]);
+ /* Apply component transformation & translation (with deltas applied) */
+ item.transform_points (comp_points, matrix, points[comp_index]);
+ }
- if (item.is_anchored ())
+ if (item.is_anchored () && !phantom_only)
{
unsigned int p1, p2;
item.get_anchor_points (p1, p2);
@@ -405,16 +517,20 @@ struct Glyph
delta.init (all_points[p1].x - comp_points[p2].x,
all_points[p1].y - comp_points[p2].y);
- comp_points.translate (delta);
+ item.translate (delta, comp_points);
}
}
- all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT));
+ all_points.resize (all_points.length - PHANTOM_COUNT);
if (all_points.length > HB_GLYF_MAX_POINTS)
+ {
+ current_glyphs->del (item_gid);
return false;
+ }
comp_index++;
+ current_glyphs->del (item_gid);
}
if (head_maxp_info && depth == 0)
@@ -429,55 +545,79 @@ struct Glyph
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE:
{
- contour_point_vector_t comp_points;
hb_array_t<contour_point_t> points_left = points.as_array ();
for (auto &item : get_var_composite_iterator ())
{
- hb_array_t<contour_point_t> record_points = points_left.sub_array (0, item.get_num_points ());
+ hb_codepoint_t item_gid = item.get_gid ();
+
+ if (unlikely (current_glyphs->has (item_gid)))
+ continue;
+
+ current_glyphs->add (item_gid);
- comp_points.reset ();
+ unsigned item_num_points = item.get_num_points ();
+ hb_array_t<contour_point_t> record_points = points_left.sub_array (0, item_num_points);
+ assert (record_points.length == item_num_points);
auto component_coords = coords;
- if (item.is_reset_unspecified_axes ())
+ /* Copying coords is expensive; so we have put an arbitrary
+ * limit on the max number of coords for now. */
+ if (item.is_reset_unspecified_axes () ||
+ coords.length > HB_GLYF_VAR_COMPOSITE_MAX_AXES)
component_coords = hb_array<int> ();
coord_setter_t coord_setter (component_coords);
item.set_variations (coord_setter, record_points);
- if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
+ unsigned old_count = all_points.length;
+
+ if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
+ !glyf_accelerator.glyph_for_gid (item_gid)
.get_points (font,
glyf_accelerator,
- comp_points,
- deltas,
+ all_points,
+ points_with_deltas,
head_maxp_info,
nullptr,
shift_points_hori,
use_my_metrics,
phantom_only,
coord_setter.get_coords (),
+ current_glyphs,
depth + 1,
edge_count)))
+ {
+ current_glyphs->del (item_gid);
return false;
+ }
+
+ auto comp_points = all_points.as_array ().sub_array (old_count);
/* Apply component transformation */
- item.transform_points (record_points, comp_points);
+ if (comp_points) // Empty in case of phantom_only
+ item.transform_points (record_points, comp_points);
/* Copy phantom points from component if USE_MY_METRICS flag set */
if (use_my_metrics && item.is_use_my_metrics ())
for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
- all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT));
+ all_points.resize (all_points.length - PHANTOM_COUNT);
if (all_points.length > HB_GLYF_MAX_POINTS)
+ {
+ current_glyphs->del (item_gid);
return false;
+ }
- points_left += item.get_num_points ();
+ points_left += item_num_points;
+
+ current_glyphs->del (item_gid);
}
all_points.extend (phantoms);
} break;
#endif
- default:
+ case EMPTY:
all_points.extend (phantoms);
break;
}
@@ -487,9 +627,10 @@ struct Glyph
/* Undocumented rasterizer behavior:
* Shift points horizontally by the updated left side bearing
*/
- contour_point_t delta;
- delta.init (-phantoms[PHANTOM_LEFT].x, 0.f);
- if (delta.x) all_points.translate (delta);
+ int v = -phantoms[PHANTOM_LEFT].x;
+ if (v)
+ for (auto &point : all_points)
+ point.x += v;
}
return !all_points.in_error ();
@@ -503,6 +644,8 @@ struct Glyph
}
hb_bytes_t get_bytes () const { return bytes; }
+ glyph_type_t get_type () const { return type; }
+ const GlyphHeader *get_header () const { return header; }
Glyph () : bytes (),
header (bytes.as<GlyphHeader> ()),
@@ -518,15 +661,18 @@ struct Glyph
int num_contours = header->numberOfContours;
if (unlikely (num_contours == 0)) type = EMPTY;
else if (num_contours > 0) type = SIMPLE;
+ else if (num_contours == -1) type = COMPOSITE;
+#ifndef HB_NO_VAR_COMPOSITES
else if (num_contours == -2) type = VAR_COMPOSITE;
- else type = COMPOSITE; /* negative numbers */
+#endif
+ else type = EMPTY; // Spec deviation; Spec says COMPOSITE, but not seen in the wild.
}
protected:
hb_bytes_t bytes;
const GlyphHeader *header;
hb_codepoint_t gid;
- unsigned type;
+ glyph_type_t type;
};
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh
index b6fefce1ac..1d42cc2925 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/SimpleGlyph.hh
@@ -34,6 +34,11 @@ struct SimpleGlyph
unsigned int length (unsigned int instruction_len) const
{ return instruction_len_offset () + 2 + instruction_len; }
+ bool has_instructions_length () const
+ {
+ return instruction_len_offset () + 2 <= bytes.length;
+ }
+
unsigned int instructions_length () const
{
unsigned int instruction_length_offset = instruction_len_offset ();
@@ -94,6 +99,7 @@ struct SimpleGlyph
/* zero instruction length */
void drop_hints ()
{
+ if (!has_instructions_length ()) return;
GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header);
(HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0;
}
@@ -118,7 +124,7 @@ struct SimpleGlyph
}
static bool read_flags (const HBUINT8 *&p /* IN/OUT */,
- contour_point_vector_t &points_ /* IN/OUT */,
+ hb_array_t<contour_point_t> points_ /* IN/OUT */,
const HBUINT8 *end)
{
unsigned count = points_.length;
@@ -140,7 +146,7 @@ struct SimpleGlyph
}
static bool read_points (const HBUINT8 *&p /* IN/OUT */,
- contour_point_vector_t &points_ /* IN/OUT */,
+ hb_array_t<contour_point_t> points_ /* IN/OUT */,
const HBUINT8 *end,
float contour_point_t::*m,
const simple_glyph_flag_t short_flag,
@@ -148,10 +154,9 @@ struct SimpleGlyph
{
int v = 0;
- unsigned count = points_.length;
- for (unsigned i = 0; i < count; i++)
+ for (auto &point : points_)
{
- unsigned flag = points_[i].flag;
+ unsigned flag = point.flag;
if (flag & short_flag)
{
if (unlikely (p + 1 > end)) return false;
@@ -169,23 +174,27 @@ struct SimpleGlyph
p += HBINT16::static_size;
}
}
- points_.arrayZ[i].*m = v;
+ point.*m = v;
}
return true;
}
- bool get_contour_points (contour_point_vector_t &points_ /* OUT */,
+ bool get_contour_points (contour_point_vector_t &points /* OUT */,
bool phantom_only = false) const
{
const HBUINT16 *endPtsOfContours = &StructAfter<HBUINT16> (header);
int num_contours = header.numberOfContours;
- assert (num_contours);
+ assert (num_contours > 0);
/* One extra item at the end, for the instruction-count below. */
if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false;
unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
- points_.alloc (num_points + 4, true); // Allocate for phantom points, to avoid a possible copy
- if (!points_.resize (num_points)) return false;
+ unsigned old_length = points.length;
+ points.alloc (points.length + num_points + 4, true); // Allocate for phantom points, to avoid a possible copy
+ if (unlikely (!points.resize (points.length + num_points, false))) return false;
+ auto points_ = points.as_array ().sub_array (old_length);
+ if (!phantom_only)
+ hb_memset (points_.arrayZ, 0, sizeof (contour_point_t) * num_points);
if (phantom_only) return true;
for (int i = 0; i < num_contours; i++)
@@ -208,7 +217,7 @@ struct SimpleGlyph
}
static void encode_coord (int value,
- uint8_t &flag,
+ unsigned &flag,
const simple_glyph_flag_t short_flag,
const simple_glyph_flag_t same_flag,
hb_vector_t<uint8_t> &coords /* OUT */)
@@ -233,9 +242,9 @@ struct SimpleGlyph
}
}
- static void encode_flag (uint8_t &flag,
- uint8_t &repeat,
- uint8_t lastflag,
+ static void encode_flag (unsigned flag,
+ unsigned &repeat,
+ unsigned lastflag,
hb_vector_t<uint8_t> &flags /* OUT */)
{
if (flag == lastflag && repeat != 255)
@@ -256,7 +265,7 @@ struct SimpleGlyph
else
{
repeat = 0;
- flags.push (flag);
+ flags.arrayZ[flags.length++] = flag;
}
}
@@ -276,13 +285,13 @@ struct SimpleGlyph
if (unlikely (!x_coords.alloc (2*num_points, true))) return false;
if (unlikely (!y_coords.alloc (2*num_points, true))) return false;
- uint8_t lastflag = 255, repeat = 0;
+ unsigned lastflag = 255, repeat = 0;
int prev_x = 0, prev_y = 0;
for (unsigned i = 0; i < num_points; i++)
{
- uint8_t flag = all_points.arrayZ[i].flag;
- flag &= FLAG_ON_CURVE + FLAG_OVERLAP_SIMPLE;
+ unsigned flag = all_points.arrayZ[i].flag;
+ flag &= FLAG_ON_CURVE | FLAG_OVERLAP_SIMPLE | FLAG_CUBIC;
int cur_x = roundf (all_points.arrayZ[i].x);
int cur_y = roundf (all_points.arrayZ[i].y);
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/SubsetGlyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/SubsetGlyph.hh
index 795925bba5..8099d3c126 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/SubsetGlyph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/SubsetGlyph.hh
@@ -18,15 +18,21 @@ struct SubsetGlyph
Glyph source_glyph;
hb_bytes_t dest_start; /* region of source_glyph to copy first */
hb_bytes_t dest_end; /* region of source_glyph to copy second */
+ bool allocated;
bool serialize (hb_serialize_context_t *c,
bool use_short_loca,
- const hb_subset_plan_t *plan)
+ const hb_subset_plan_t *plan) const
{
TRACE_SERIALIZE (this);
hb_bytes_t dest_glyph = dest_start.copy (c);
- dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length);
+ hb_bytes_t end_copy = dest_end.copy (c);
+ if (!end_copy.arrayZ || !dest_glyph.arrayZ) {
+ return false;
+ }
+
+ dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + end_copy.length);
unsigned int pad_length = use_short_loca ? padding () : 0;
DEBUG_MSG (SUBSET, nullptr, "serialize %u byte glyph, width %u pad %u", dest_glyph.length, dest_glyph.length + pad_length, pad_length);
@@ -34,19 +40,74 @@ struct SubsetGlyph
pad = 0;
while (pad_length > 0)
{
- c->embed (pad);
+ (void) c->embed (pad);
pad_length--;
}
if (unlikely (!dest_glyph.length)) return_trace (true);
- /* update components gids */
+ /* update components gids. */
for (auto &_ : Glyph (dest_glyph).get_composite_iterator ())
{
hb_codepoint_t new_gid;
if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
const_cast<CompositeGlyphRecord &> (_).set_gid (new_gid);
}
+#ifndef HB_NO_VAR_COMPOSITES
+ for (auto &_ : Glyph (dest_glyph).get_var_composite_iterator ())
+ {
+ hb_codepoint_t new_gid;
+ if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
+ const_cast<VarCompositeGlyphRecord &> (_).set_gid (new_gid);
+ }
+#endif
+
+#ifndef HB_NO_BEYOND_64K
+ auto it = Glyph (dest_glyph).get_composite_iterator ();
+ if (it)
+ {
+ /* lower GID24 to GID16 in components if possible.
+ *
+ * TODO: VarComposite. Not as critical, since VarComposite supports
+ * gid24 from the first version. */
+ char *p = it ? (char *) &*it : nullptr;
+ char *q = p;
+ const char *end = dest_glyph.arrayZ + dest_glyph.length;
+ while (it)
+ {
+ auto &rec = const_cast<CompositeGlyphRecord &> (*it);
+ ++it;
+
+ q += rec.get_size ();
+
+ rec.lower_gid_24_to_16 ();
+
+ unsigned size = rec.get_size ();
+
+ memmove (p, &rec, size);
+
+ p += size;
+ }
+ memmove (p, q, end - q);
+ p += end - q;
+
+ /* We want to shorten the glyph, but we can't do that without
+ * updating the length in the loca table, which is already
+ * written out :-(. So we just fill the rest of the glyph with
+ * harmless instructions, since that's what they will be
+ * interpreted as.
+ *
+ * Should move the lowering to _populate_subset_glyphs() to
+ * fix this issue. */
+
+ hb_memset (p, 0x7A /* TrueType instruction ROFF; harmless */, end - p);
+ p += end - p;
+ dest_glyph = hb_bytes_t (dest_glyph.arrayZ, p - (char *) dest_glyph.arrayZ);
+
+ // TODO: Padding; & trim serialized bytes.
+ // TODO: Update length in loca. Ugh.
+ }
+#endif
if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
Glyph (dest_glyph).drop_hints ();
@@ -60,12 +121,18 @@ struct SubsetGlyph
bool compile_bytes_with_deltas (const hb_subset_plan_t *plan,
hb_font_t *font,
const glyf_accelerator_t &glyf)
- { return source_glyph.compile_bytes_with_deltas (plan, font, glyf, dest_start, dest_end); }
+ {
+ allocated = source_glyph.compile_bytes_with_deltas (plan, font, glyf, dest_start, dest_end);
+ return allocated;
+ }
void free_compiled_bytes ()
{
- dest_start.fini ();
- dest_end.fini ();
+ if (likely (allocated)) {
+ allocated = false;
+ dest_start.fini ();
+ dest_end.fini ();
+ }
}
void drop_hints_bytes ()
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/VarCompositeGlyph.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/VarCompositeGlyph.hh
index 3685da7913..50cbece3ca 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/VarCompositeGlyph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/VarCompositeGlyph.hh
@@ -27,7 +27,7 @@ struct VarCompositeGlyphRecord
HAVE_SKEW_Y = 0x0200,
HAVE_TCENTER_X = 0x0400,
HAVE_TCENTER_Y = 0x0800,
- GID_IS_24 = 0x1000,
+ GID_IS_24BIT = 0x1000,
AXES_HAVE_VARIATION = 0x2000,
RESET_UNSPECIFIED_AXES = 0x4000,
};
@@ -36,24 +36,21 @@ struct VarCompositeGlyphRecord
unsigned int get_size () const
{
+ unsigned fl = flags;
unsigned int size = min_size;
- unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 4 : 3;
+ unsigned axis_width = (fl & AXIS_INDICES_ARE_SHORT) ? 4 : 3;
size += numAxes * axis_width;
- // gid
- size += 2;
- if (flags & GID_IS_24) size += 1;
+ if (fl & GID_IS_24BIT) size += 1;
- if (flags & HAVE_TRANSLATE_X) size += 2;
- if (flags & HAVE_TRANSLATE_Y) size += 2;
- if (flags & HAVE_ROTATION) size += 2;
- if (flags & HAVE_SCALE_X) size += 2;
- if (flags & HAVE_SCALE_Y) size += 2;
- if (flags & HAVE_SKEW_X) size += 2;
- if (flags & HAVE_SKEW_Y) size += 2;
- if (flags & HAVE_TCENTER_X) size += 2;
- if (flags & HAVE_TCENTER_Y) size += 2;
+ // 2 bytes each for the following flags
+ fl = fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y |
+ HAVE_ROTATION |
+ HAVE_SCALE_X | HAVE_SCALE_Y |
+ HAVE_SKEW_X | HAVE_SKEW_Y |
+ HAVE_TCENTER_X | HAVE_TCENTER_Y);
+ size += hb_popcount (fl) * 2;
return size;
}
@@ -65,10 +62,18 @@ struct VarCompositeGlyphRecord
hb_codepoint_t get_gid () const
{
- if (flags & GID_IS_24)
- return StructAfter<const HBGlyphID24> (numAxes);
+ if (flags & GID_IS_24BIT)
+ return * (const HBGlyphID24 *) &pad;
else
- return StructAfter<const HBGlyphID16> (numAxes);
+ return * (const HBGlyphID16 *) &pad;
+ }
+
+ void set_gid (hb_codepoint_t gid)
+ {
+ if (flags & GID_IS_24BIT)
+ * (HBGlyphID24 *) &pad = gid;
+ else
+ * (HBGlyphID16 *) &pad = gid;
}
unsigned get_numAxes () const
@@ -78,26 +83,44 @@ struct VarCompositeGlyphRecord
unsigned get_num_points () const
{
+ unsigned fl = flags;
unsigned num = 0;
- if (flags & AXES_HAVE_VARIATION) num += numAxes;
- if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) num++;
- if (flags & HAVE_ROTATION) num++;
- if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y)) num++;
- if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y)) num++;
- if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) num++;
+ if (fl & AXES_HAVE_VARIATION) num += numAxes;
+
+ /* Hopefully faster code, relying on the value of the flags. */
+ fl = (((fl & (HAVE_TRANSLATE_Y | HAVE_SCALE_Y | HAVE_SKEW_Y | HAVE_TCENTER_Y)) >> 1) | fl) &
+ (HAVE_TRANSLATE_X | HAVE_ROTATION | HAVE_SCALE_X | HAVE_SKEW_X | HAVE_TCENTER_X);
+ num += hb_popcount (fl);
+ return num;
+
+ /* Slower but more readable code. */
+ if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) num++;
+ if (fl & HAVE_ROTATION) num++;
+ if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y)) num++;
+ if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y)) num++;
+ if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) num++;
return num;
}
- void transform_points (hb_array_t<contour_point_t> record_points,
- contour_point_vector_t &points) const
+ void transform_points (hb_array_t<const contour_point_t> record_points,
+ hb_array_t<contour_point_t> points) const
{
float matrix[4];
contour_point_t trans;
- get_transformation_from_points (record_points, matrix, trans);
+ get_transformation_from_points (record_points.arrayZ, matrix, trans);
+
+ auto arrayZ = points.arrayZ;
+ unsigned count = points.length;
- points.transform (matrix);
- points.translate (trans);
+ if (matrix[0] != 1.f || matrix[1] != 0.f ||
+ matrix[2] != 0.f || matrix[3] != 1.f)
+ for (unsigned i = 0; i < count; i++)
+ arrayZ[i].transform (matrix);
+
+ if (trans.x != 0.f || trans.y != 0.f)
+ for (unsigned i = 0; i < count; i++)
+ arrayZ[i].translate (trans);
}
static inline void transform (float (&matrix)[4], contour_point_t &trans,
@@ -128,26 +151,41 @@ struct VarCompositeGlyphRecord
static void translate (float (&matrix)[4], contour_point_t &trans,
float translateX, float translateY)
{
- // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L213
- float other[6] = {1.f, 0.f, 0.f, 1.f, translateX, translateY};
- transform (matrix, trans, other);
+ if (!translateX && !translateY)
+ return;
+
+ trans.x += matrix[0] * translateX + matrix[2] * translateY;
+ trans.y += matrix[1] * translateX + matrix[3] * translateY;
}
static void scale (float (&matrix)[4], contour_point_t &trans,
float scaleX, float scaleY)
{
- // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L224
- float other[6] = {scaleX, 0.f, 0.f, scaleY, 0.f, 0.f};
- transform (matrix, trans, other);
+ if (scaleX == 1.f && scaleY == 1.f)
+ return;
+
+ matrix[0] *= scaleX;
+ matrix[1] *= scaleX;
+ matrix[2] *= scaleY;
+ matrix[3] *= scaleY;
}
static void rotate (float (&matrix)[4], contour_point_t &trans,
float rotation)
{
+ if (!rotation)
+ return;
+
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240
- rotation = rotation * float (M_PI);
- float c = cosf (rotation);
- float s = sinf (rotation);
+ rotation = rotation * HB_PI;
+ float c;
+ float s;
+#ifdef HAVE_SINCOSF
+ sincosf (rotation, &s, &c);
+#else
+ c = cosf (rotation);
+ s = sinf (rotation);
+#endif
float other[6] = {c, s, -s, c, 0.f, 0.f};
transform (matrix, trans, other);
}
@@ -155,99 +193,100 @@ struct VarCompositeGlyphRecord
static void skew (float (&matrix)[4], contour_point_t &trans,
float skewX, float skewY)
{
+ if (!skewX && !skewY)
+ return;
+
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255
- skewX = skewX * float (M_PI);
- skewY = skewY * float (M_PI);
- float other[6] = {1.f, tanf (skewY), tanf (skewX), 1.f, 0.f, 0.f};
+ skewX = skewX * HB_PI;
+ skewY = skewY * HB_PI;
+ float other[6] = {1.f,
+ skewY ? tanf (skewY) : 0.f,
+ skewX ? tanf (skewX) : 0.f,
+ 1.f,
+ 0.f, 0.f};
transform (matrix, trans, other);
}
bool get_points (contour_point_vector_t &points) const
{
- float translateX = 0.f;
- float translateY = 0.f;
- float rotation = 0.f;
- float scaleX = 1.f * (1 << 10);
- float scaleY = 1.f * (1 << 10);
- float skewX = 0.f;
- float skewY = 0.f;
- float tCenterX = 0.f;
- float tCenterY = 0.f;
+ unsigned num_points = get_num_points ();
- if (unlikely (!points.resize (points.length + get_num_points ()))) return false;
+ points.alloc (points.length + num_points + 4); // For phantom points
+ if (unlikely (!points.resize (points.length + num_points, false))) return false;
+ contour_point_t *rec_points = points.arrayZ + (points.length - num_points);
+ hb_memset (rec_points, 0, num_points * sizeof (rec_points[0]));
- unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
- unsigned axes_size = numAxes * axis_width;
+ unsigned fl = flags;
- const F2DOT14 *q = (const F2DOT14 *) (axes_size +
- (flags & GID_IS_24 ? 3 : 2) +
- &StructAfter<const HBUINT8> (numAxes));
+ unsigned num_axes = numAxes;
+ unsigned axis_width = (fl & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
+ unsigned axes_size = num_axes * axis_width;
- hb_array_t<contour_point_t> rec_points = points.as_array ().sub_array (points.length - get_num_points ());
+ const F2DOT14 *q = (const F2DOT14 *) (axes_size +
+ (fl & GID_IS_24BIT ? 3 : 2) +
+ (const HBUINT8 *) &pad);
- unsigned count = numAxes;
- if (flags & AXES_HAVE_VARIATION)
+ unsigned count = num_axes;
+ if (fl & AXES_HAVE_VARIATION)
{
for (unsigned i = 0; i < count; i++)
- rec_points[i].x = q++->to_int ();
- rec_points += count;
+ rec_points++->x = q++->to_int ();
}
else
q += count;
const HBUINT16 *p = (const HBUINT16 *) q;
- if (flags & HAVE_TRANSLATE_X) translateX = * (const FWORD *) p++;
- if (flags & HAVE_TRANSLATE_Y) translateY = * (const FWORD *) p++;
- if (flags & HAVE_ROTATION) rotation = ((const F4DOT12 *) p++)->to_int ();
- if (flags & HAVE_SCALE_X) scaleX = ((const F6DOT10 *) p++)->to_int ();
- if (flags & HAVE_SCALE_Y) scaleY = ((const F6DOT10 *) p++)->to_int ();
- if (flags & HAVE_SKEW_X) skewX = ((const F4DOT12 *) p++)->to_int ();
- if (flags & HAVE_SKEW_Y) skewY = ((const F4DOT12 *) p++)->to_int ();
- if (flags & HAVE_TCENTER_X) tCenterX = * (const FWORD *) p++;
- if (flags & HAVE_TCENTER_Y) tCenterY = * (const FWORD *) p++;
-
- if ((flags & UNIFORM_SCALE) && !(flags & HAVE_SCALE_Y))
- scaleY = scaleX;
-
- if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
+ if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
{
- rec_points[0].x = translateX;
- rec_points[0].y = translateY;
+ int translateX = (fl & HAVE_TRANSLATE_X) ? * (const FWORD *) p++ : 0;
+ int translateY = (fl & HAVE_TRANSLATE_Y) ? * (const FWORD *) p++ : 0;
+ rec_points->x = translateX;
+ rec_points->y = translateY;
rec_points++;
}
- if (flags & HAVE_ROTATION)
+ if (fl & HAVE_ROTATION)
{
- rec_points[0].x = rotation;
+ int rotation = (fl & HAVE_ROTATION) ? ((const F4DOT12 *) p++)->to_int () : 0;
+ rec_points->x = rotation;
rec_points++;
}
- if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y))
+ if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y))
{
- rec_points[0].x = scaleX;
- rec_points[0].y = scaleY;
+ int scaleX = (fl & HAVE_SCALE_X) ? ((const F6DOT10 *) p++)->to_int () : 1 << 10;
+ int scaleY = (fl & HAVE_SCALE_Y) ? ((const F6DOT10 *) p++)->to_int () : 1 << 10;
+ if ((fl & UNIFORM_SCALE) && !(fl & HAVE_SCALE_Y))
+ scaleY = scaleX;
+ rec_points->x = scaleX;
+ rec_points->y = scaleY;
rec_points++;
}
- if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y))
+ if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y))
{
- rec_points[0].x = skewX;
- rec_points[0].y = skewY;
+ int skewX = (fl & HAVE_SKEW_X) ? ((const F4DOT12 *) p++)->to_int () : 0;
+ int skewY = (fl & HAVE_SKEW_Y) ? ((const F4DOT12 *) p++)->to_int () : 0;
+ rec_points->x = skewX;
+ rec_points->y = skewY;
rec_points++;
}
- if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
+ if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
{
- rec_points[0].x = tCenterX;
- rec_points[0].y = tCenterY;
+ int tCenterX = (fl & HAVE_TCENTER_X) ? * (const FWORD *) p++ : 0;
+ int tCenterY = (fl & HAVE_TCENTER_Y) ? * (const FWORD *) p++ : 0;
+ rec_points->x = tCenterX;
+ rec_points->y = tCenterY;
rec_points++;
}
- assert (!rec_points);
return true;
}
- void get_transformation_from_points (hb_array_t<contour_point_t> rec_points,
+ void get_transformation_from_points (const contour_point_t *rec_points,
float (&matrix)[4], contour_point_t &trans) const
{
- if (flags & AXES_HAVE_VARIATION)
+ unsigned fl = flags;
+
+ if (fl & AXES_HAVE_VARIATION)
rec_points += numAxes;
matrix[0] = matrix[3] = 1.f;
@@ -264,36 +303,35 @@ struct VarCompositeGlyphRecord
float tCenterX = 0.f;
float tCenterY = 0.f;
- if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
+ if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
{
- translateX = rec_points[0].x;
- translateY = rec_points[0].y;
+ translateX = rec_points->x;
+ translateY = rec_points->y;
rec_points++;
}
- if (flags & HAVE_ROTATION)
+ if (fl & HAVE_ROTATION)
{
- rotation = rec_points[0].x / (1 << 12);
+ rotation = rec_points->x / (1 << 12);
rec_points++;
}
- if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y))
+ if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y))
{
- scaleX = rec_points[0].x / (1 << 10);
- scaleY = rec_points[0].y / (1 << 10);
+ scaleX = rec_points->x / (1 << 10);
+ scaleY = rec_points->y / (1 << 10);
rec_points++;
}
- if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y))
+ if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y))
{
- skewX = rec_points[0].x / (1 << 12);
- skewY = rec_points[0].y / (1 << 12);
+ skewX = rec_points->x / (1 << 12);
+ skewY = rec_points->y / (1 << 12);
rec_points++;
}
- if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
+ if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
{
- tCenterX = rec_points[0].x;
- tCenterY = rec_points[0].y;
+ tCenterX = rec_points->x;
+ tCenterY = rec_points->y;
rec_points++;
}
- assert (!rec_points);
translate (matrix, trans, translateX + tCenterX, translateY + tCenterY);
rotate (matrix, trans, rotation);
@@ -307,18 +345,19 @@ struct VarCompositeGlyphRecord
{
bool have_variations = flags & AXES_HAVE_VARIATION;
unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
+ unsigned num_axes = numAxes;
- const HBUINT8 *p = (const HBUINT8 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24 ? 3 : 2));
- const HBUINT16 *q = (const HBUINT16 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24 ? 3 : 2));
+ const HBUINT8 *p = (const HBUINT8 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24BIT ? 3 : 2));
+ const HBUINT16 *q = (const HBUINT16 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24BIT ? 3 : 2));
- const F2DOT14 *a = (const F2DOT14 *) ((HBUINT8 *) (axis_width == 1 ? (p + numAxes) : (HBUINT8 *) (q + numAxes)));
+ const F2DOT14 *a = (const F2DOT14 *) ((HBUINT8 *) (axis_width == 1 ? (p + num_axes) : (HBUINT8 *) (q + num_axes)));
- unsigned count = numAxes;
+ unsigned count = num_axes;
for (unsigned i = 0; i < count; i++)
{
unsigned axis_index = axis_width == 1 ? (unsigned) *p++ : (unsigned) *q++;
- signed v = have_variations ? rec_points[i].x : a++->to_int ();
+ signed v = have_variations ? rec_points.arrayZ[i].x : a++->to_int ();
v = hb_clamp (v, -(1<<14), (1<<14));
setter[axis_index] = v;
@@ -328,8 +367,9 @@ struct VarCompositeGlyphRecord
protected:
HBUINT16 flags;
HBUINT8 numAxes;
+ HBUINT16 pad;
public:
- DEFINE_SIZE_MIN (3);
+ DEFINE_SIZE_MIN (5);
};
using var_composite_iter_t = composite_iter_tmpl<VarCompositeGlyphRecord>;
@@ -344,6 +384,13 @@ struct VarCompositeGlyph
var_composite_iter_t iter () const
{ return var_composite_iter_t (bytes, &StructAfter<VarCompositeGlyphRecord, GlyphHeader> (header)); }
+ const hb_bytes_t trim_padding () const
+ {
+ unsigned length = GlyphHeader::static_size;
+ for (auto &comp : iter ())
+ length += comp.get_size ();
+ return bytes.sub_array (0, length);
+ }
};
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/coord-setter.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/coord-setter.hh
index df64ed5af7..cf05929362 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/coord-setter.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/coord-setter.hh
@@ -16,6 +16,8 @@ struct coord_setter_t
int& operator [] (unsigned idx)
{
+ if (unlikely (idx >= HB_GLYF_VAR_COMPOSITE_MAX_AXES))
+ return Crap(int);
if (coords.length < idx + 1)
coords.resize (idx + 1);
return coords[idx];
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh
index 30106b2b98..f157bf0020 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf-helpers.hh
@@ -12,24 +12,44 @@ namespace OT {
namespace glyf_impl {
-template<typename IteratorIn, typename IteratorOut,
- hb_requires (hb_is_source_of (IteratorIn, unsigned int)),
- hb_requires (hb_is_sink_of (IteratorOut, unsigned))>
+template<typename IteratorIn, typename TypeOut,
+ hb_requires (hb_is_source_of (IteratorIn, unsigned int))>
static void
-_write_loca (IteratorIn&& it, bool short_offsets, IteratorOut&& dest)
+_write_loca (IteratorIn&& it,
+ const hb_sorted_vector_t<hb_codepoint_pair_t> new_to_old_gid_list,
+ bool short_offsets,
+ TypeOut *dest,
+ unsigned num_offsets)
{
unsigned right_shift = short_offsets ? 1 : 0;
- unsigned int offset = 0;
- dest << 0;
- + it
- | hb_map ([=, &offset] (unsigned int padded_size)
- {
- offset += padded_size;
- DEBUG_MSG (SUBSET, nullptr, "loca entry offset %u", offset);
- return offset >> right_shift;
- })
- | hb_sink (dest)
- ;
+ unsigned offset = 0;
+ TypeOut value;
+ value = 0;
+ *dest++ = value;
+ hb_codepoint_t last = 0;
+ for (auto _ : new_to_old_gid_list)
+ {
+ hb_codepoint_t gid = _.first;
+ for (; last < gid; last++)
+ {
+ DEBUG_MSG (SUBSET, nullptr, "loca entry empty offset %u", offset);
+ *dest++ = value;
+ }
+
+ unsigned padded_size = *it++;
+ offset += padded_size;
+ DEBUG_MSG (SUBSET, nullptr, "loca entry gid %" PRIu32 " offset %u padded-size %u", gid, offset, padded_size);
+ value = offset >> right_shift;
+ *dest++ = value;
+
+ last++; // Skip over gid
+ }
+ unsigned num_glyphs = num_offsets - 1;
+ for (; last < num_glyphs; last++)
+ {
+ DEBUG_MSG (SUBSET, nullptr, "loca entry empty offset %u", offset);
+ *dest++ = value;
+ }
}
static bool
@@ -67,11 +87,14 @@ _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca)
template<typename Iterator,
hb_requires (hb_is_source_of (Iterator, unsigned int))>
static bool
-_add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_short_loca)
+_add_loca_and_head (hb_subset_context_t *c,
+ Iterator padded_offsets,
+ bool use_short_loca)
{
- unsigned num_offsets = padded_offsets.len () + 1;
+ unsigned num_offsets = c->plan->num_output_glyphs () + 1;
unsigned entry_size = use_short_loca ? 2 : 4;
- char *loca_prime_data = (char *) hb_calloc (entry_size, num_offsets);
+
+ char *loca_prime_data = (char *) hb_malloc (entry_size * num_offsets);
if (unlikely (!loca_prime_data)) return false;
@@ -79,9 +102,9 @@ _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_s
entry_size, num_offsets, entry_size * num_offsets);
if (use_short_loca)
- _write_loca (padded_offsets, true, hb_array ((HBUINT16 *) loca_prime_data, num_offsets));
+ _write_loca (padded_offsets, c->plan->new_to_old_gid_list, true, (HBUINT16 *) loca_prime_data, num_offsets);
else
- _write_loca (padded_offsets, false, hb_array ((HBUINT32 *) loca_prime_data, num_offsets));
+ _write_loca (padded_offsets, c->plan->new_to_old_gid_list, false, (HBUINT32 *) loca_prime_data, num_offsets);
hb_blob_t *loca_blob = hb_blob_create (loca_prime_data,
entry_size * num_offsets,
@@ -89,8 +112,8 @@ _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_s
loca_prime_data,
hb_free);
- bool result = plan->add_table (HB_OT_TAG_loca, loca_blob)
- && _add_head_and_set_loca_version (plan, use_short_loca);
+ bool result = c->plan->add_table (HB_OT_TAG_loca, loca_blob)
+ && _add_head_and_set_loca_version (c->plan, use_short_loca);
hb_blob_destroy (loca_blob);
return result;
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh
index 29328c7627..6300cf4be0 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/glyf.hh
@@ -31,6 +31,12 @@ struct glyf
static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf;
+ static bool has_valid_glyf_format(const hb_face_t* face)
+ {
+ const OT::head &head = *face->table.head;
+ return head.indexToLocFormat <= 1 && head.glyphDataFormat <= 1;
+ }
+
bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const
{
TRACE_SANITIZE (this);
@@ -72,69 +78,79 @@ struct glyf
{
TRACE_SUBSET (this);
- glyf *glyf_prime = c->serializer->start_embed <glyf> ();
- if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
+ if (!has_valid_glyf_format (c->plan->source)) {
+ // glyf format is unknown don't attempt to subset it.
+ DEBUG_MSG (SUBSET, nullptr,
+ "unkown glyf format, dropping from subset.");
+ return_trace (false);
+ }
hb_font_t *font = nullptr;
if (c->plan->normalized_coords)
{
font = _create_font_for_instancing (c->plan);
- if (unlikely (!font)) return false;
+ if (unlikely (!font))
+ return_trace (false);
}
hb_vector_t<unsigned> padded_offsets;
- unsigned num_glyphs = c->plan->num_output_glyphs ();
- if (unlikely (!padded_offsets.resize (num_glyphs)))
- return false;
+ if (unlikely (!padded_offsets.alloc (c->plan->new_to_old_gid_list.length, true)))
+ return_trace (false);
hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
if (!_populate_subset_glyphs (c->plan, font, glyphs))
- return false;
+ {
+ hb_font_destroy (font);
+ return_trace (false);
+ }
if (font)
hb_font_destroy (font);
unsigned max_offset = 0;
- for (unsigned i = 0; i < num_glyphs; i++)
+ for (auto &g : glyphs)
{
- padded_offsets[i] = glyphs[i].padded_size ();
- max_offset += padded_offsets[i];
+ unsigned size = g.padded_size ();
+ padded_offsets.push (size);
+ max_offset += size;
}
bool use_short_loca = false;
if (likely (!c->plan->force_long_loca))
use_short_loca = max_offset < 0x1FFFF;
- if (!use_short_loca) {
- for (unsigned i = 0; i < num_glyphs; i++)
- padded_offsets[i] = glyphs[i].length ();
+ if (!use_short_loca)
+ {
+ padded_offsets.resize (0);
+ for (auto &g : glyphs)
+ padded_offsets.push (g.length ());
}
- bool result = glyf_prime->serialize (c->serializer, glyphs.writer (), use_short_loca, c->plan);
+ auto *glyf_prime = c->serializer->start_embed <glyf> ();
+ bool result = glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan);
if (c->plan->normalized_coords && !c->plan->pinned_at_default)
- _free_compiled_subset_glyphs (glyphs, glyphs.length - 1);
-
- if (!result) return false;
+ _free_compiled_subset_glyphs (glyphs);
- if (unlikely (c->serializer->in_error ())) return_trace (false);
+ if (unlikely (!c->serializer->check_success (glyf_impl::_add_loca_and_head (c,
+ padded_offsets.iter (),
+ use_short_loca))))
+ return_trace (false);
- return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan,
- padded_offsets.iter (),
- use_short_loca)));
+ return result;
}
bool
_populate_subset_glyphs (const hb_subset_plan_t *plan,
hb_font_t *font,
- hb_vector_t<glyf_impl::SubsetGlyph> &glyphs /* OUT */) const;
+ hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const;
hb_font_t *
_create_font_for_instancing (const hb_subset_plan_t *plan) const;
- void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> &glyphs, unsigned index) const
+ void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> &glyphs) const
{
- for (unsigned i = 0; i <= index && i < glyphs.length; i++)
- glyphs[i].free_compiled_bytes ();
+ for (auto &g : glyphs)
+ g.free_compiled_bytes ();
}
protected:
@@ -162,7 +178,7 @@ struct glyf_accelerator_t
vmtx = nullptr;
#endif
const OT::head &head = *face->table.head;
- if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0)
+ if (!glyf::has_valid_glyf_format (face))
/* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */
return;
short_offset = 0 == head.indexToLocFormat;
@@ -203,13 +219,14 @@ struct glyf_accelerator_t
if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, nullptr, nullptr, true, true, phantom_only)))
return false;
+ unsigned count = all_points.length;
+ assert (count >= glyf_impl::PHANTOM_COUNT);
+ count -= glyf_impl::PHANTOM_COUNT;
+
if (consumer.is_consuming_contour_points ())
{
- unsigned count = all_points.length;
- assert (count >= glyf_impl::PHANTOM_COUNT);
- count -= glyf_impl::PHANTOM_COUNT;
- for (unsigned point_index = 0; point_index < count; point_index++)
- consumer.consume_point (all_points[point_index]);
+ for (auto &point : all_points.as_array ().sub_array (0, count))
+ consumer.consume_point (point);
consumer.points_end ();
}
@@ -217,11 +234,13 @@ struct glyf_accelerator_t
contour_point_t *phantoms = consumer.get_phantoms_sink ();
if (phantoms)
for (unsigned i = 0; i < glyf_impl::PHANTOM_COUNT; ++i)
- phantoms[i] = all_points[all_points.length - glyf_impl::PHANTOM_COUNT + i];
+ phantoms[i] = all_points.arrayZ[count + i];
return true;
}
+ public:
+
#ifndef HB_NO_VAR
struct points_aggregator_t
{
@@ -278,6 +297,7 @@ struct glyf_accelerator_t
if (extents) bounds = contour_bounds_t ();
}
+ HB_ALWAYS_INLINE
void consume_point (const contour_point_t &point) { bounds.add (point); }
void points_end () { bounds.get_extents (font, extents, scaled); }
@@ -285,7 +305,6 @@ struct glyf_accelerator_t
contour_point_t *get_phantoms_sink () { return phantoms; }
};
- public:
unsigned
get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const
{
@@ -327,6 +346,15 @@ struct glyf_accelerator_t
}
#endif
+ bool get_leading_bearing_without_var_unscaled (hb_codepoint_t gid, bool is_vertical, int *lsb) const
+ {
+ if (unlikely (gid >= num_glyphs)) return false;
+ if (is_vertical) return false; // TODO Humm, what to do here?
+
+ *lsb = glyph_for_gid (gid).get_header ()->xMin;
+ return true;
+ }
+
public:
bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
{
@@ -402,17 +430,17 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const
{
OT::glyf_accelerator_t glyf (plan->source);
- unsigned num_glyphs = plan->num_output_glyphs ();
- if (!glyphs.resize (num_glyphs)) return false;
+ if (!glyphs.alloc (plan->new_to_old_gid_list.length, true)) return false;
- unsigned idx = 0;
- for (auto p : plan->glyph_map->iter ())
+ for (const auto &pair : plan->new_to_old_gid_list)
{
- unsigned new_gid = p.second;
- glyf_impl::SubsetGlyph& subset_glyph = glyphs.arrayZ[new_gid];
- subset_glyph.old_gid = p.first;
+ hb_codepoint_t new_gid = pair.first;
+ hb_codepoint_t old_gid = pair.second;
+ glyf_impl::SubsetGlyph *p = glyphs.push ();
+ glyf_impl::SubsetGlyph& subset_glyph = *p;
+ subset_glyph.old_gid = old_gid;
- if (unlikely (new_gid == 0 &&
+ if (unlikely (old_gid == 0 && new_gid == 0 &&
!(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) &&
!plan->normalized_coords)
subset_glyph.source_glyph = glyf_impl::Glyph ();
@@ -433,11 +461,10 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
if (unlikely (!subset_glyph.compile_bytes_with_deltas (plan, font, glyf)))
{
// when pinned at default, only bounds are updated, thus no need to free
- if (!plan->pinned_at_default && idx > 0)
- _free_compiled_subset_glyphs (glyphs, idx - 1);
+ if (!plan->pinned_at_default)
+ _free_compiled_subset_glyphs (glyphs);
return false;
}
- idx++;
}
}
return true;
@@ -451,13 +478,16 @@ glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const
hb_vector_t<hb_variation_t> vars;
if (unlikely (!vars.alloc (plan->user_axes_location.get_population (), true)))
+ {
+ hb_font_destroy (font);
return nullptr;
+ }
for (auto _ : plan->user_axes_location)
{
hb_variation_t var;
var.tag = _.first;
- var.value = _.second;
+ var.value = _.second.middle;
vars.push (var);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/glyf/path-builder.hh b/src/3rdparty/harfbuzz-ng/src/OT/glyf/path-builder.hh
index e35a4dafde..f550524503 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/glyf/path-builder.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/glyf/path-builder.hh
@@ -21,26 +21,23 @@ struct path_builder_t
operator bool () const { return has_data; }
bool has_data = false;
- float x = 0.;
- float y = 0.;
+ float x;
+ float y;
- optional_point_t lerp (optional_point_t p, float t)
- { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); }
- } first_oncurve, first_offcurve, last_offcurve, last_offcurve2;
+ optional_point_t mid (optional_point_t p)
+ { return optional_point_t ((x + p.x) * 0.5f, (y + p.y) * 0.5f); }
+ } first_oncurve, first_offcurve, first_offcurve2, last_offcurve, last_offcurve2;
- path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_)
- {
- font = font_;
- draw_session = &draw_session_;
- first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t ();
- }
+ path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) :
+ font (font_), draw_session (&draw_session_) {}
/* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287
See also:
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html
* https://stackoverflow.com/a/20772557
*
- * Cubic support added (incomplete). */
+ * Cubic support added. */
+ HB_ALWAYS_INLINE
void consume_point (const contour_point_t &point)
{
bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE;
@@ -50,7 +47,7 @@ struct path_builder_t
bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC);
#endif
optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y));
- if (!first_oncurve)
+ if (unlikely (!first_oncurve))
{
if (is_on_curve)
{
@@ -59,9 +56,14 @@ struct path_builder_t
}
else
{
- if (first_offcurve)
+ if (is_cubic && !first_offcurve2)
+ {
+ first_offcurve2 = first_offcurve;
+ first_offcurve = p;
+ }
+ else if (first_offcurve)
{
- optional_point_t mid = first_offcurve.lerp (p, .5f);
+ optional_point_t mid = first_offcurve.mid (p);
first_oncurve = mid;
last_offcurve = p;
draw_session->move_to (mid.x, mid.y);
@@ -97,7 +99,7 @@ struct path_builder_t
}
else
{
- optional_point_t mid = last_offcurve.lerp (p, .5f);
+ optional_point_t mid = last_offcurve.mid (p);
if (is_cubic)
{
@@ -122,20 +124,34 @@ struct path_builder_t
}
}
- if (point.is_end_point)
+ if (unlikely (point.is_end_point))
{
if (first_offcurve && last_offcurve)
{
- optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f);
- draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
- mid.x, mid.y);
+ optional_point_t mid = last_offcurve.mid (first_offcurve2 ?
+ first_offcurve2 :
+ first_offcurve);
+ if (last_offcurve2)
+ draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
+ last_offcurve.x, last_offcurve.y,
+ mid.x, mid.y);
+ else
+ draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
+ mid.x, mid.y);
last_offcurve = optional_point_t ();
- /* now check the rest */
}
+ /* now check the rest */
if (first_offcurve && first_oncurve)
- draw_session->quadratic_to (first_offcurve.x, first_offcurve.y,
- first_oncurve.x, first_oncurve.y);
+ {
+ if (first_offcurve2)
+ draw_session->cubic_to (first_offcurve2.x, first_offcurve2.y,
+ first_offcurve.x, first_offcurve.y,
+ first_oncurve.x, first_oncurve.y);
+ else
+ draw_session->quadratic_to (first_offcurve.x, first_offcurve.y,
+ first_oncurve.x, first_oncurve.y);
+ }
else if (last_offcurve && first_oncurve)
{
if (last_offcurve2)
diff --git a/src/3rdparty/harfbuzz-ng/src/OT/name/name.hh b/src/3rdparty/harfbuzz-ng/src/OT/name/name.hh
index c1839f3b68..e2a25d4a0f 100644
--- a/src/3rdparty/harfbuzz-ng/src/OT/name/name.hh
+++ b/src/3rdparty/harfbuzz-ng/src/OT/name/name.hh
@@ -242,7 +242,9 @@ struct NameRecord
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) && offset.sanitize (c, base, length));
+ return_trace (c->check_struct (this) &&
+ hb_barrier () &&
+ offset.sanitize (c, base, length));
}
HBUINT16 platformID; /* Platform ID. */
@@ -359,7 +361,7 @@ struct name
record.nameID = ids.name_id;
record.length = 0; // handled in NameRecord copy()
record.offset = 0;
- memcpy (name_records, &record, NameRecord::static_size);
+ hb_memcpy (name_records, &record, NameRecord::static_size);
name_records++;
}
#endif
@@ -384,10 +386,7 @@ struct name
bool subset (hb_subset_context_t *c) const
{
- TRACE_SUBSET (this);
-
- name *name_prime = c->serializer->start_embed<name> ();
- if (unlikely (!name_prime)) return_trace (false);
+ auto *name_prime = c->serializer->start_embed<name> ();
#ifdef HB_EXPERIMENTAL_API
const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides =
@@ -436,7 +435,7 @@ struct name
if (!name_table_overrides->is_empty ())
{
if (unlikely (!insert_name_records.alloc (name_table_overrides->get_population (), true)))
- return_trace (false);
+ return false;
for (const auto& record_ids : name_table_overrides->keys ())
{
if (name_table_overrides->get (record_ids).length == 0)
@@ -448,13 +447,13 @@ struct name
}
#endif
- return (name_prime->serialize (c->serializer, it,
- std::addressof (this + stringOffset)
+ return name_prime->serialize (c->serializer, it,
+ std::addressof (this + stringOffset)
#ifdef HB_EXPERIMENTAL_API
- , insert_name_records
- , name_table_overrides
+ , insert_name_records
+ , name_table_overrides
#endif
- ));
+ );
}
bool sanitize_records (hb_sanitize_context_t *c) const
@@ -468,6 +467,7 @@ struct name
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
likely (format == 0 || format == 1) &&
c->check_array (nameRecordZ.arrayZ, count) &&
c->check_range (this, stringOffset) &&
diff --git a/src/3rdparty/harfbuzz-ng/src/graph/classdef-graph.hh b/src/3rdparty/harfbuzz-ng/src/graph/classdef-graph.hh
index c2e24a7067..da6378820b 100644
--- a/src/3rdparty/harfbuzz-ng/src/graph/classdef-graph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/graph/classdef-graph.hh
@@ -39,6 +39,7 @@ struct ClassDefFormat1 : public OT::ClassDefFormat1_3<SmallTypes>
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
constexpr unsigned min_size = OT::ClassDefFormat1_3<SmallTypes>::min_size;
if (vertex_len < min_size) return false;
+ hb_barrier ();
return vertex_len >= min_size + classValue.get_size () - classValue.len.get_size ();
}
};
@@ -50,6 +51,7 @@ struct ClassDefFormat2 : public OT::ClassDefFormat2_4<SmallTypes>
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
constexpr unsigned min_size = OT::ClassDefFormat2_4<SmallTypes>::min_size;
if (vertex_len < min_size) return false;
+ hb_barrier ();
return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size ();
}
};
@@ -72,7 +74,7 @@ struct ClassDef : public OT::ClassDef
class_def_link->width = SmallTypes::size;
class_def_link->objidx = class_def_prime_id;
class_def_link->position = link_position;
- class_def_prime_vertex.parents.push (parent_id);
+ class_def_prime_vertex.add_parent (parent_id);
return true;
}
@@ -94,7 +96,13 @@ struct ClassDef : public OT::ClassDef
}
hb_bytes_t class_def_copy = serializer.copy_bytes ();
- c.add_buffer ((char *) class_def_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer.
+ if (!class_def_copy.arrayZ) return false;
+ // Give ownership to the context, it will cleanup the buffer.
+ if (!c.add_buffer ((char *) class_def_copy.arrayZ))
+ {
+ hb_free ((char *) class_def_copy.arrayZ);
+ return false;
+ }
auto& obj = c.graph.vertices_[dest_obj].obj;
obj.head = (char *) class_def_copy.arrayZ;
@@ -108,6 +116,7 @@ struct ClassDef : public OT::ClassDef
{
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
if (vertex_len < OT::ClassDef::min_size) return false;
+ hb_barrier ();
switch (u.format)
{
case 1: return ((ClassDefFormat1*)this)->sanitize (vertex);
@@ -125,20 +134,23 @@ struct ClassDef : public OT::ClassDef
struct class_def_size_estimator_t
{
+ // TODO(garretrieger): update to support beyond64k coverage/classdef tables.
+ constexpr static unsigned class_def_format1_base_size = 6;
+ constexpr static unsigned class_def_format2_base_size = 4;
+ constexpr static unsigned coverage_base_size = 4;
+ constexpr static unsigned bytes_per_range = 6;
+ constexpr static unsigned bytes_per_glyph = 2;
+
template<typename It>
class_def_size_estimator_t (It glyph_and_class)
- : gids_consecutive (true), num_ranges_per_class (), glyphs_per_class ()
+ : num_ranges_per_class (), glyphs_per_class ()
{
- unsigned last_gid = (unsigned) -1;
+ reset();
for (auto p : + glyph_and_class)
{
unsigned gid = p.first;
unsigned klass = p.second;
- if (last_gid != (unsigned) -1 && gid != last_gid + 1)
- gids_consecutive = false;
- last_gid = gid;
-
hb_set_t* glyphs;
if (glyphs_per_class.has (klass, &glyphs) && glyphs) {
glyphs->add (gid);
@@ -168,28 +180,54 @@ struct class_def_size_estimator_t
}
}
- // Incremental increase in the Coverage and ClassDef table size
- // (worst case) if all glyphs associated with 'klass' were added.
- unsigned incremental_coverage_size (unsigned klass) const
+ void reset() {
+ class_def_1_size = class_def_format1_base_size;
+ class_def_2_size = class_def_format2_base_size;
+ included_glyphs.clear();
+ included_classes.clear();
+ }
+
+ // Compute the size of coverage for all glyphs added via 'add_class_def_size'.
+ unsigned coverage_size () const
{
- // Coverage takes 2 bytes per glyph worst case,
- return 2 * glyphs_per_class.get (klass).get_population ();
+ unsigned format1_size = coverage_base_size + bytes_per_glyph * included_glyphs.get_population();
+ unsigned format2_size = coverage_base_size + bytes_per_range * num_glyph_ranges();
+ return hb_min(format1_size, format2_size);
}
- // Incremental increase in the Coverage and ClassDef table size
- // (worst case) if all glyphs associated with 'klass' were added.
- unsigned incremental_class_def_size (unsigned klass) const
+ // Compute the new size of the ClassDef table if all glyphs associated with 'klass' were added.
+ unsigned add_class_def_size (unsigned klass)
{
- // ClassDef takes 6 bytes per range
- unsigned class_def_2_size = 6 * num_ranges_per_class.get (klass);
- if (gids_consecutive)
- {
- // ClassDef1 takes 2 bytes per glyph, but only can be used
- // when gids are consecutive.
- return hb_min (2 * glyphs_per_class.get (klass).get_population (), class_def_2_size);
+ if (!included_classes.has(klass)) {
+ hb_set_t* glyphs = nullptr;
+ if (glyphs_per_class.has(klass, &glyphs)) {
+ included_glyphs.union_(*glyphs);
+ }
+
+ class_def_1_size = class_def_format1_base_size;
+ if (!included_glyphs.is_empty()) {
+ unsigned min_glyph = included_glyphs.get_min();
+ unsigned max_glyph = included_glyphs.get_max();
+ class_def_1_size += bytes_per_glyph * (max_glyph - min_glyph + 1);
+ }
+
+ class_def_2_size += bytes_per_range * num_ranges_per_class.get (klass);
+
+ included_classes.add(klass);
}
- return class_def_2_size;
+ return hb_min (class_def_1_size, class_def_2_size);
+ }
+
+ unsigned num_glyph_ranges() const {
+ hb_codepoint_t start = HB_SET_VALUE_INVALID;
+ hb_codepoint_t end = HB_SET_VALUE_INVALID;
+
+ unsigned count = 0;
+ while (included_glyphs.next_range (&start, &end)) {
+ count++;
+ }
+ return count;
}
bool in_error ()
@@ -205,9 +243,12 @@ struct class_def_size_estimator_t
}
private:
- bool gids_consecutive;
hb_hashmap_t<unsigned, unsigned> num_ranges_per_class;
hb_hashmap_t<unsigned, hb_set_t> glyphs_per_class;
+ hb_set_t included_classes;
+ hb_set_t included_glyphs;
+ unsigned class_def_1_size;
+ unsigned class_def_2_size;
};
diff --git a/src/3rdparty/harfbuzz-ng/src/graph/coverage-graph.hh b/src/3rdparty/harfbuzz-ng/src/graph/coverage-graph.hh
index 49d0936315..61ca063e34 100644
--- a/src/3rdparty/harfbuzz-ng/src/graph/coverage-graph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/graph/coverage-graph.hh
@@ -39,6 +39,7 @@ struct CoverageFormat1 : public OT::Layout::Common::CoverageFormat1_3<SmallTypes
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
constexpr unsigned min_size = OT::Layout::Common::CoverageFormat1_3<SmallTypes>::min_size;
if (vertex_len < min_size) return false;
+ hb_barrier ();
return vertex_len >= min_size + glyphArray.get_size () - glyphArray.len.get_size ();
}
};
@@ -50,6 +51,7 @@ struct CoverageFormat2 : public OT::Layout::Common::CoverageFormat2_4<SmallTypes
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
constexpr unsigned min_size = OT::Layout::Common::CoverageFormat2_4<SmallTypes>::min_size;
if (vertex_len < min_size) return false;
+ hb_barrier ();
return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size ();
}
};
@@ -96,7 +98,7 @@ struct Coverage : public OT::Layout::Common::Coverage
coverage_link->width = SmallTypes::size;
coverage_link->objidx = coverage_prime_id;
coverage_link->position = link_position;
- coverage_prime_vertex.parents.push (parent_id);
+ coverage_prime_vertex.add_parent (parent_id);
return (Coverage*) coverage_prime_vertex.obj.head;
}
@@ -118,7 +120,13 @@ struct Coverage : public OT::Layout::Common::Coverage
}
hb_bytes_t coverage_copy = serializer.copy_bytes ();
- c.add_buffer ((char *) coverage_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer.
+ if (!coverage_copy.arrayZ) return false;
+ // Give ownership to the context, it will cleanup the buffer.
+ if (!c.add_buffer ((char *) coverage_copy.arrayZ))
+ {
+ hb_free ((char *) coverage_copy.arrayZ);
+ return false;
+ }
auto& obj = c.graph.vertices_[dest_obj].obj;
obj.head = (char *) coverage_copy.arrayZ;
@@ -132,6 +140,7 @@ struct Coverage : public OT::Layout::Common::Coverage
{
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
if (vertex_len < OT::Layout::Common::Coverage::min_size) return false;
+ hb_barrier ();
switch (u.format)
{
case 1: return ((CoverageFormat1*)this)->sanitize (vertex);
diff --git a/src/3rdparty/harfbuzz-ng/src/graph/graph.hh b/src/3rdparty/harfbuzz-ng/src/graph/graph.hh
index 38ca5db096..2a9d8346c0 100644
--- a/src/3rdparty/harfbuzz-ng/src/graph/graph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/graph/graph.hh
@@ -43,12 +43,28 @@ struct graph_t
{
hb_serialize_context_t::object_t obj;
int64_t distance = 0 ;
- int64_t space = 0 ;
- hb_vector_t<unsigned> parents;
+ unsigned space = 0 ;
unsigned start = 0;
unsigned end = 0;
unsigned priority = 0;
-
+ private:
+ unsigned incoming_edges_ = 0;
+ unsigned single_parent = (unsigned) -1;
+ hb_hashmap_t<unsigned, unsigned> parents;
+ public:
+
+ auto parents_iter () const HB_AUTO_RETURN
+ (
+ hb_concat (
+ hb_iter (&single_parent, single_parent != (unsigned) -1),
+ parents.keys_ref ()
+ )
+ )
+
+ bool in_error () const
+ {
+ return parents.in_error ();
+ }
bool link_positions_valid (unsigned num_objects, bool removed_nil)
{
@@ -143,7 +159,9 @@ struct graph_t
hb_swap (a.obj, b.obj);
hb_swap (a.distance, b.distance);
hb_swap (a.space, b.space);
+ hb_swap (a.single_parent, b.single_parent);
hb_swap (a.parents, b.parents);
+ hb_swap (a.incoming_edges_, b.incoming_edges_);
hb_swap (a.start, b.start);
hb_swap (a.end, b.end);
hb_swap (a.priority, b.priority);
@@ -154,6 +172,7 @@ struct graph_t
{
hb_hashmap_t<unsigned, unsigned> result;
+ result.alloc (obj.real_links.length);
for (const auto& l : obj.real_links) {
result.set (l.position, l.objidx);
}
@@ -163,27 +182,92 @@ struct graph_t
bool is_shared () const
{
- return parents.length > 1;
+ return parents.get_population () > 1;
}
unsigned incoming_edges () const
{
- return parents.length;
+ if (HB_DEBUG_SUBSET_REPACK)
+ {
+ assert (incoming_edges_ == (single_parent != (unsigned) -1) +
+ (parents.values_ref () | hb_reduce (hb_add, 0)));
+ }
+ return incoming_edges_;
+ }
+
+ unsigned incoming_edges_from_parent (unsigned parent_index) const {
+ if (single_parent != (unsigned) -1) {
+ return single_parent == parent_index ? 1 : 0;
+ }
+
+ unsigned* count;
+ return parents.has(parent_index, &count) ? *count : 0;
+ }
+
+ void reset_parents ()
+ {
+ incoming_edges_ = 0;
+ single_parent = (unsigned) -1;
+ parents.reset ();
+ }
+
+ void add_parent (unsigned parent_index)
+ {
+ assert (parent_index != (unsigned) -1);
+ if (incoming_edges_ == 0)
+ {
+ single_parent = parent_index;
+ incoming_edges_ = 1;
+ return;
+ }
+ else if (single_parent != (unsigned) -1)
+ {
+ assert (incoming_edges_ == 1);
+ if (!parents.set (single_parent, 1))
+ return;
+ single_parent = (unsigned) -1;
+ }
+
+ unsigned *v;
+ if (parents.has (parent_index, &v))
+ {
+ (*v)++;
+ incoming_edges_++;
+ }
+ else if (parents.set (parent_index, 1))
+ incoming_edges_++;
}
void remove_parent (unsigned parent_index)
{
- for (unsigned i = 0; i < parents.length; i++)
+ if (parent_index == single_parent)
{
- if (parents[i] != parent_index) continue;
- parents.remove_unordered (i);
- break;
+ single_parent = (unsigned) -1;
+ incoming_edges_--;
+ return;
+ }
+
+ unsigned *v;
+ if (parents.has (parent_index, &v))
+ {
+ incoming_edges_--;
+ if (*v > 1)
+ (*v)--;
+ else
+ parents.del (parent_index);
+
+ if (incoming_edges_ == 1)
+ {
+ single_parent = *parents.keys ();
+ parents.reset ();
+ }
}
}
void remove_real_link (unsigned child_index, const void* offset)
{
- for (unsigned i = 0; i < obj.real_links.length; i++)
+ unsigned count = obj.real_links.length;
+ for (unsigned i = 0; i < count; i++)
{
auto& link = obj.real_links.arrayZ[i];
if (link.objidx != child_index)
@@ -197,18 +281,53 @@ struct graph_t
}
}
- void remap_parents (const hb_vector_t<unsigned>& id_map)
+ bool remap_parents (const hb_vector_t<unsigned>& id_map)
{
- for (unsigned i = 0; i < parents.length; i++)
- parents[i] = id_map[parents[i]];
+ if (single_parent != (unsigned) -1)
+ {
+ assert (single_parent < id_map.length);
+ single_parent = id_map[single_parent];
+ return true;
+ }
+
+ hb_hashmap_t<unsigned, unsigned> new_parents;
+ new_parents.alloc (parents.get_population ());
+ for (auto _ : parents)
+ {
+ assert (_.first < id_map.length);
+ assert (!new_parents.has (id_map[_.first]));
+ new_parents.set (id_map[_.first], _.second);
+ }
+
+ if (parents.in_error() || new_parents.in_error ())
+ return false;
+
+ parents = std::move (new_parents);
+ return true;
}
void remap_parent (unsigned old_index, unsigned new_index)
{
- for (unsigned i = 0; i < parents.length; i++)
+ if (single_parent != (unsigned) -1)
{
- if (parents[i] == old_index)
- parents[i] = new_index;
+ if (single_parent == old_index)
+ single_parent = new_index;
+ return;
+ }
+
+ const unsigned *pv;
+ if (parents.has (old_index, &pv))
+ {
+ unsigned v = *pv;
+ if (!parents.set (new_index, v))
+ incoming_edges_ -= v;
+ parents.del (old_index);
+
+ if (incoming_edges_ == 1)
+ {
+ single_parent = *parents.keys ();
+ parents.reset ();
+ }
}
}
@@ -224,6 +343,16 @@ struct graph_t
return true;
}
+ bool give_max_priority ()
+ {
+ bool result = false;
+ while (!has_max_priority()) {
+ result = true;
+ priority++;
+ }
+ return result;
+ }
+
bool has_max_priority () const {
return priority >= 3;
}
@@ -328,11 +457,12 @@ struct graph_t
bool removed_nil = false;
vertices_.alloc (objects.length);
vertices_scratch_.alloc (objects.length);
- for (unsigned i = 0; i < objects.length; i++)
+ unsigned count = objects.length;
+ for (unsigned i = 0; i < count; i++)
{
// If this graph came from a serialization buffer object 0 is the
// nil object. We don't need it for our purposes here so drop it.
- if (i == 0 && !objects[i])
+ if (i == 0 && !objects.arrayZ[i])
{
removed_nil = true;
continue;
@@ -340,9 +470,9 @@ struct graph_t
vertex_t* v = vertices_.push ();
if (check_success (!vertices_.in_error ()))
- v->obj = *objects[i];
+ v->obj = *objects.arrayZ[i];
- check_success (v->link_positions_valid (objects.length, removed_nil));
+ check_success (v->link_positions_valid (count, removed_nil));
if (!removed_nil) continue;
// Fix indices to account for removed nil object.
@@ -354,7 +484,6 @@ struct graph_t
~graph_t ()
{
- vertices_.fini ();
for (char* b : buffers)
hb_free (b);
}
@@ -364,6 +493,18 @@ struct graph_t
return root ().equals (other.root (), *this, other, 0);
}
+ void print () const {
+ for (int i = vertices_.length - 1; i >= 0; i--)
+ {
+ const auto& v = vertices_[i];
+ printf("%d: %u [", i, (unsigned int)v.table_size());
+ for (const auto &l : v.obj.real_links) {
+ printf("%u, ", l.objidx);
+ }
+ printf("]\n");
+ }
+ }
+
// Sorts links of all objects in a consistent manner and zeroes all offsets.
void normalize ()
{
@@ -396,9 +537,10 @@ struct graph_t
return vertices_[i].obj;
}
- void add_buffer (char* buffer)
+ bool add_buffer (char* buffer)
{
buffers.push (buffer);
+ return !buffers.in_error ();
}
/*
@@ -414,7 +556,7 @@ struct graph_t
link->width = 2;
link->objidx = child_id;
link->position = (char*) offset - (char*) v.obj.head;
- vertices_[child_id].parents.push (parent_id);
+ vertices_[child_id].add_parent (parent_id);
}
/*
@@ -443,7 +585,8 @@ struct graph_t
update_distances ();
- hb_priority_queue_t queue;
+ hb_priority_queue_t<int64_t> queue;
+ queue.alloc (vertices_.length);
hb_vector_t<vertex_t> &sorted_graph = vertices_scratch_;
if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return;
hb_vector_t<unsigned> id_map;
@@ -460,7 +603,7 @@ struct graph_t
{
unsigned next_id = queue.pop_minimum().second;
- hb_swap (sorted_graph[new_id], vertices_[next_id]);
+ sorted_graph[new_id] = std::move (vertices_[next_id]);
const vertex_t& next = sorted_graph[new_id];
if (unlikely (!check_success(new_id >= 0))) {
@@ -488,8 +631,8 @@ struct graph_t
check_success (!queue.in_error ());
check_success (!sorted_graph.in_error ());
- remap_all_obj_indices (id_map, &sorted_graph);
- hb_swap (vertices_, sorted_graph);
+ check_success (remap_all_obj_indices (id_map, &sorted_graph));
+ vertices_ = std::move (sorted_graph);
if (!check_success (new_id == -1))
print_orphaned_nodes ();
@@ -579,8 +722,8 @@ struct graph_t
const auto& node = object (node_idx);
if (offset < node.head || offset >= node.tail) return -1;
- unsigned length = node.real_links.length;
- for (unsigned i = 0; i < length; i++)
+ unsigned count = node.real_links.length;
+ for (unsigned i = 0; i < count; i++)
{
// Use direct access for increased performance, this is a hot method.
const auto& link = node.real_links.arrayZ[i];
@@ -600,7 +743,7 @@ struct graph_t
{
unsigned child_idx = index_for_offset (node_idx, offset);
auto& child = vertices_[child_idx];
- for (unsigned p : child.parents)
+ for (unsigned p : child.parents_iter ())
{
if (p != node_idx) {
return duplicate (node_idx, child_idx);
@@ -683,12 +826,15 @@ struct graph_t
subgraph.set (root_idx, wide_parents (root_idx, parents));
find_subgraph (root_idx, subgraph);
}
+ if (subgraph.in_error ())
+ return false;
unsigned original_root_idx = root_idx ();
hb_map_t index_map;
bool made_changes = false;
for (auto entry : subgraph.iter ())
{
+ assert (entry.first < vertices_.length);
const auto& node = vertices_[entry.first];
unsigned subgraph_incoming_edges = entry.second;
@@ -727,8 +873,7 @@ struct graph_t
remap_obj_indices (index_map, parents.iter (), true);
// Update roots set with new indices as needed.
- uint32_t next = HB_SET_VALUE_INVALID;
- while (roots.next (&next))
+ for (auto next : roots)
{
const uint32_t *v;
if (index_map.has (next, &v))
@@ -745,10 +890,10 @@ struct graph_t
{
for (const auto& link : vertices_[node_idx].obj.all_links ())
{
- const uint32_t *v;
+ hb_codepoint_t *v;
if (subgraph.has (link.objidx, &v))
{
- subgraph.set (link.objidx, *v + 1);
+ (*v)++;
continue;
}
subgraph.set (link.objidx, 1);
@@ -820,7 +965,7 @@ struct graph_t
new_link->position = (const char*) new_offset - (const char*) new_v.obj.head;
auto& child = vertices_[child_id];
- child.parents.push (new_parent_idx);
+ child.add_parent (new_parent_idx);
old_v.remove_real_link (child_id, old_offset);
child.remove_parent (old_parent_idx);
@@ -864,18 +1009,18 @@ struct graph_t
clone->obj.tail = child.obj.tail;
clone->distance = child.distance;
clone->space = child.space;
- clone->parents.reset ();
+ clone->reset_parents ();
unsigned clone_idx = vertices_.length - 2;
for (const auto& l : child.obj.real_links)
{
clone->obj.real_links.push (l);
- vertices_[l.objidx].parents.push (clone_idx);
+ vertices_[l.objidx].add_parent (clone_idx);
}
for (const auto& l : child.obj.virtual_links)
{
clone->obj.virtual_links.push (l);
- vertices_[l.objidx].parents.push (clone_idx);
+ vertices_[l.objidx].add_parent (clone_idx);
}
check_success (!clone->obj.real_links.in_error ());
@@ -897,6 +1042,11 @@ struct graph_t
* Creates a copy of child and re-assigns the link from
* parent to the clone. The copy is a shallow copy, objects
* linked from child are not duplicated.
+ *
+ * Returns the index of the newly created duplicate.
+ *
+ * If the child_idx only has incoming edges from parent_idx, this
+ * will do nothing and return the original child_idx.
*/
unsigned duplicate_if_shared (unsigned parent_idx, unsigned child_idx)
{
@@ -910,18 +1060,20 @@ struct graph_t
* Creates a copy of child and re-assigns the link from
* parent to the clone. The copy is a shallow copy, objects
* linked from child are not duplicated.
+ *
+ * Returns the index of the newly created duplicate.
+ *
+ * If the child_idx only has incoming edges from parent_idx,
+ * duplication isn't possible and this will return -1.
*/
unsigned duplicate (unsigned parent_idx, unsigned child_idx)
{
update_parents ();
- unsigned links_to_child = 0;
- for (const auto& l : vertices_[parent_idx].obj.all_links ())
- {
- if (l.objidx == child_idx) links_to_child++;
- }
+ const auto& child = vertices_[child_idx];
+ unsigned links_to_child = child.incoming_edges_from_parent(parent_idx);
- if (vertices_[child_idx].incoming_edges () <= links_to_child)
+ if (child.incoming_edges () <= links_to_child)
{
// Can't duplicate this node, doing so would orphan the original one as all remaining links
// to child are from parent.
@@ -934,7 +1086,7 @@ struct graph_t
parent_idx, child_idx);
unsigned clone_idx = duplicate (child_idx);
- if (clone_idx == (unsigned) -1) return false;
+ if (clone_idx == (unsigned) -1) return -1;
// duplicate shifts the root node idx, so if parent_idx was root update it.
if (parent_idx == clone_idx) parent_idx++;
@@ -950,6 +1102,62 @@ struct graph_t
return clone_idx;
}
+ /*
+ * Creates a copy of child and re-assigns the links from
+ * parents to the clone. The copy is a shallow copy, objects
+ * linked from child are not duplicated.
+ *
+ * Returns the index of the newly created duplicate.
+ *
+ * If the child_idx only has incoming edges from parents,
+ * duplication isn't possible or duplication fails and this will
+ * return -1.
+ */
+ unsigned duplicate (const hb_set_t* parents, unsigned child_idx)
+ {
+ if (parents->is_empty()) {
+ return -1;
+ }
+
+ update_parents ();
+
+ const auto& child = vertices_[child_idx];
+ unsigned links_to_child = 0;
+ unsigned last_parent = parents->get_max();
+ unsigned first_parent = parents->get_min();
+ for (unsigned parent_idx : *parents) {
+ links_to_child += child.incoming_edges_from_parent(parent_idx);
+ }
+
+ if (child.incoming_edges () <= links_to_child)
+ {
+ // Can't duplicate this node, doing so would orphan the original one as all remaining links
+ // to child are from parent.
+ DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %u, ..., %u => %u", first_parent, last_parent, child_idx);
+ return -1;
+ }
+
+ DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %u, ..., %u => %u", first_parent, last_parent, child_idx);
+
+ unsigned clone_idx = duplicate (child_idx);
+ if (clone_idx == (unsigned) -1) return false;
+
+ for (unsigned parent_idx : *parents) {
+ // duplicate shifts the root node idx, so if parent_idx was root update it.
+ if (parent_idx == clone_idx) parent_idx++;
+ auto& parent = vertices_[parent_idx];
+ for (auto& l : parent.obj.all_links_writer ())
+ {
+ if (l.objidx != child_idx)
+ continue;
+
+ reassign_link (l, parent_idx, clone_idx);
+ }
+ }
+
+ return clone_idx;
+ }
+
/*
* Adds a new node to the graph, not connected to anything.
@@ -1004,13 +1212,13 @@ struct graph_t
{
update_parents();
- if (root().parents)
+ if (root().incoming_edges ())
// Root cannot have parents.
return false;
for (unsigned i = 0; i < root_idx (); i++)
{
- if (!vertices_[i].parents)
+ if (!vertices_[i].incoming_edges ())
return false;
}
return true;
@@ -1074,14 +1282,14 @@ struct graph_t
parents_invalid = true;
update_parents();
- if (root().parents) {
+ if (root().incoming_edges ()) {
DEBUG_MSG (SUBSET_REPACK, nullptr, "Root node has incoming edges.");
}
for (unsigned i = 0; i < root_idx (); i++)
{
const auto& v = vertices_[i];
- if (!v.parents)
+ if (!v.incoming_edges ())
DEBUG_MSG (SUBSET_REPACK, nullptr, "Node %u is orphaned.", i);
}
}
@@ -1113,6 +1321,8 @@ struct graph_t
unsigned space_for (unsigned index, unsigned* root = nullptr) const
{
+ loop:
+ assert (index < vertices_.length);
const auto& node = vertices_[index];
if (node.space)
{
@@ -1121,22 +1331,24 @@ struct graph_t
return node.space;
}
- if (!node.parents)
+ if (!node.incoming_edges ())
{
if (root)
*root = index;
return 0;
}
- return space_for (node.parents[0], root);
+ index = *node.parents_iter ();
+ goto loop;
}
void err_other_error () { this->successful = false; }
size_t total_size_in_bytes () const {
size_t total_size = 0;
- for (unsigned i = 0; i < vertices_.length; i++) {
- size_t size = vertices_[i].obj.tail - vertices_[i].obj.head;
+ unsigned count = vertices_.length;
+ for (unsigned i = 0; i < count; i++) {
+ size_t size = vertices_.arrayZ[i].obj.tail - vertices_.arrayZ[i].obj.head;
total_size += size;
}
return total_size;
@@ -1151,12 +1363,8 @@ struct graph_t
unsigned wide_parents (unsigned node_idx, hb_set_t& parents) const
{
unsigned count = 0;
- hb_set_t visited;
- for (unsigned p : vertices_[node_idx].parents)
+ for (unsigned p : vertices_[node_idx].parents_iter ())
{
- if (visited.has (p)) continue;
- visited.add (p);
-
// Only real links can be wide
for (const auto& l : vertices_[p].obj.real_links)
{
@@ -1183,21 +1391,21 @@ struct graph_t
{
if (!parents_invalid) return;
- for (unsigned i = 0; i < vertices_.length; i++)
- vertices_[i].parents.reset ();
+ unsigned count = vertices_.length;
- for (unsigned p = 0; p < vertices_.length; p++)
+ for (unsigned i = 0; i < count; i++)
+ vertices_.arrayZ[i].reset_parents ();
+
+ for (unsigned p = 0; p < count; p++)
{
- for (auto& l : vertices_[p].obj.all_links ())
- {
- vertices_[l.objidx].parents.push (p);
- }
+ for (auto& l : vertices_.arrayZ[p].obj.all_links ())
+ vertices_[l.objidx].add_parent (p);
}
- for (unsigned i = 0; i < vertices_.length; i++)
+ for (unsigned i = 0; i < count; i++)
// parents arrays must be accurate or downstream operations like cycle detection
// and sorting won't work correctly.
- check_success (!vertices_[i].parents.in_error ());
+ check_success (!vertices_.arrayZ[i].in_error ());
parents_invalid = false;
}
@@ -1239,15 +1447,13 @@ struct graph_t
// According to https://www3.cs.stonybrook.edu/~rezaul/papers/TR-07-54.pdf
// for practical performance this is faster then using a more advanced queue
// (such as a fibonacci queue) with a fast decrease priority.
- for (unsigned i = 0; i < vertices_.length; i++)
- {
- if (i == vertices_.length - 1)
- vertices_[i].distance = 0;
- else
- vertices_[i].distance = hb_int_max (int64_t);
- }
+ unsigned count = vertices_.length;
+ for (unsigned i = 0; i < count; i++)
+ vertices_.arrayZ[i].distance = hb_int_max (int64_t);
+ vertices_.tail ().distance = 0;
- hb_priority_queue_t queue;
+ hb_priority_queue_t<int64_t> queue;
+ queue.alloc (count);
queue.insert (0, vertices_.length - 1);
hb_vector_t<bool> visited;
@@ -1265,15 +1471,15 @@ struct graph_t
{
if (visited[link.objidx]) continue;
- const auto& child = vertices_[link.objidx].obj;
+ const auto& child = vertices_.arrayZ[link.objidx].obj;
unsigned link_width = link.width ? link.width : 4; // treat virtual offsets as 32 bits wide
int64_t child_weight = (child.tail - child.head) +
- ((int64_t) 1 << (link_width * 8)) * (vertices_[link.objidx].space + 1);
+ ((int64_t) 1 << (link_width * 8)) * (vertices_.arrayZ[link.objidx].space + 1);
int64_t child_distance = next_distance + child_weight;
- if (child_distance < vertices_[link.objidx].distance)
+ if (child_distance < vertices_.arrayZ[link.objidx].distance)
{
- vertices_[link.objidx].distance = child_distance;
+ vertices_.arrayZ[link.objidx].distance = child_distance;
queue.insert (child_distance, link.objidx);
}
}
@@ -1301,7 +1507,7 @@ struct graph_t
unsigned old_idx = link.objidx;
link.objidx = new_idx;
vertices_[old_idx].remove_parent (parent_idx);
- vertices_[new_idx].parents.push (parent_idx);
+ vertices_[new_idx].add_parent (parent_idx);
}
/*
@@ -1329,17 +1535,20 @@ struct graph_t
/*
* Updates all objidx's in all links using the provided mapping.
*/
- void remap_all_obj_indices (const hb_vector_t<unsigned>& id_map,
+ bool remap_all_obj_indices (const hb_vector_t<unsigned>& id_map,
hb_vector_t<vertex_t>* sorted_graph) const
{
- for (unsigned i = 0; i < sorted_graph->length; i++)
+ unsigned count = sorted_graph->length;
+ for (unsigned i = 0; i < count; i++)
{
- (*sorted_graph)[i].remap_parents (id_map);
- for (auto& link : (*sorted_graph)[i].obj.all_links_writer ())
+ if (!(*sorted_graph)[i].remap_parents (id_map))
+ return false;
+ for (auto& link : sorted_graph->arrayZ[i].obj.all_links_writer ())
{
link.objidx = id_map[link.objidx];
}
}
+ return true;
}
/*
@@ -1370,7 +1579,7 @@ struct graph_t
for (const auto& l : v.obj.all_links ())
find_connected_nodes (l.objidx, targets, visited, connected);
- for (unsigned p : v.parents)
+ for (unsigned p : v.parents_iter ())
find_connected_nodes (p, targets, visited, connected);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-context.cc b/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-context.cc
index b2044426d4..d66eb49cfd 100644
--- a/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-context.cc
+++ b/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-context.cc
@@ -52,7 +52,11 @@ unsigned gsubgpos_graph_context_t::create_node (unsigned size)
if (!buffer)
return -1;
- add_buffer (buffer);
+ if (!add_buffer (buffer)) {
+ // Allocation did not get stored for freeing later.
+ hb_free (buffer);
+ return -1;
+ }
return graph.new_node (buffer, buffer + size);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-context.hh b/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-context.hh
index 9fe9662e64..b25d538fe3 100644
--- a/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-context.hh
+++ b/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-context.hh
@@ -40,16 +40,16 @@ struct gsubgpos_graph_context_t
graph_t& graph;
unsigned lookup_list_index;
hb_hashmap_t<unsigned, graph::Lookup*> lookups;
-
+ hb_hashmap_t<unsigned, unsigned> subtable_to_extension;
HB_INTERNAL gsubgpos_graph_context_t (hb_tag_t table_tag_,
graph_t& graph_);
HB_INTERNAL unsigned create_node (unsigned size);
- void add_buffer (char* buffer)
+ bool add_buffer (char* buffer)
{
- graph.add_buffer (buffer);
+ return graph.add_buffer (buffer);
}
private:
diff --git a/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-graph.hh b/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-graph.hh
index c170638409..0f6d5662e0 100644
--- a/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-graph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/graph/gsubgpos-graph.hh
@@ -76,6 +76,7 @@ struct Lookup : public OT::Lookup
{
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
if (vertex_len < OT::Lookup::min_size) return false;
+ hb_barrier ();
return vertex_len >= this->get_size ();
}
@@ -166,7 +167,7 @@ struct Lookup : public OT::Lookup
}
if (all_new_subtables) {
- add_sub_tables (c, this_index, type, all_new_subtables);
+ return add_sub_tables (c, this_index, type, all_new_subtables);
}
return true;
@@ -184,7 +185,7 @@ struct Lookup : public OT::Lookup
return sub_table->split_subtables (c, parent_idx, objidx);
}
- void add_sub_tables (gsubgpos_graph_context_t& c,
+ bool add_sub_tables (gsubgpos_graph_context_t& c,
unsigned this_index,
unsigned type,
hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>>& subtable_ids)
@@ -200,7 +201,12 @@ struct Lookup : public OT::Lookup
size_t new_size = v.table_size ()
+ new_subtable_count * OT::Offset16::static_size;
char* buffer = (char*) hb_calloc (1, new_size);
- c.add_buffer (buffer);
+ if (!buffer) return false;
+ if (!c.add_buffer (buffer))
+ {
+ hb_free (buffer);
+ return false;
+ }
hb_memcpy (buffer, v.obj.head, v.table_size());
v.obj.head = buffer;
@@ -220,7 +226,7 @@ struct Lookup : public OT::Lookup
if (is_ext)
{
unsigned ext_id = create_extension_subtable (c, subtable_id, type);
- c.graph.vertices_[subtable_id].parents.push (ext_id);
+ c.graph.vertices_[subtable_id].add_parent (ext_id);
subtable_id = ext_id;
}
@@ -229,7 +235,7 @@ struct Lookup : public OT::Lookup
link->objidx = subtable_id;
link->position = (char*) &new_lookup->subTable[offset_index++] -
(char*) new_lookup;
- c.graph.vertices_[subtable_id].parents.push (this_index);
+ c.graph.vertices_[subtable_id].add_parent (this_index);
}
}
@@ -239,6 +245,7 @@ struct Lookup : public OT::Lookup
// The head location of the lookup has changed, invalidating the lookups map entry
// in the context. Update the map.
c.lookups.set (this_index, new_lookup);
+ return true;
}
void fix_existing_subtable_links (gsubgpos_graph_context_t& c,
@@ -293,24 +300,35 @@ struct Lookup : public OT::Lookup
unsigned subtable_index)
{
unsigned type = lookupType;
+ unsigned ext_index = -1;
+ unsigned* existing_ext_index = nullptr;
+ if (c.subtable_to_extension.has(subtable_index, &existing_ext_index)) {
+ ext_index = *existing_ext_index;
+ } else {
+ ext_index = create_extension_subtable(c, subtable_index, type);
+ c.subtable_to_extension.set(subtable_index, ext_index);
+ }
- unsigned ext_index = create_extension_subtable(c, subtable_index, type);
if (ext_index == (unsigned) -1)
return false;
+ auto& subtable_vertex = c.graph.vertices_[subtable_index];
auto& lookup_vertex = c.graph.vertices_[lookup_index];
for (auto& l : lookup_vertex.obj.real_links.writer ())
{
- if (l.objidx == subtable_index)
+ if (l.objidx == subtable_index) {
// Change lookup to point at the extension.
l.objidx = ext_index;
+ if (existing_ext_index)
+ subtable_vertex.remove_parent(lookup_index);
+ }
}
// Make extension point at the subtable.
auto& ext_vertex = c.graph.vertices_[ext_index];
- auto& subtable_vertex = c.graph.vertices_[subtable_index];
- ext_vertex.parents.push (lookup_index);
- subtable_vertex.remap_parent (lookup_index, ext_index);
+ ext_vertex.add_parent (lookup_index);
+ if (!existing_ext_index)
+ subtable_vertex.remap_parent (lookup_index, ext_index);
return true;
}
@@ -334,6 +352,7 @@ struct LookupList : public OT::LookupList<T>
{
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
if (vertex_len < OT::LookupList<T>::min_size) return false;
+ hb_barrier ();
return vertex_len >= OT::LookupList<T>::item_size * this->len;
}
};
@@ -347,6 +366,7 @@ struct GSTAR : public OT::GSUBGPOS
GSTAR* gstar = (GSTAR*) r.obj.head;
if (!gstar || !gstar->sanitize (r))
return nullptr;
+ hb_barrier ();
return gstar;
}
@@ -366,6 +386,7 @@ struct GSTAR : public OT::GSUBGPOS
{
int64_t len = vertex.obj.tail - vertex.obj.head;
if (len < OT::GSUBGPOS::min_size) return false;
+ hb_barrier ();
return len >= get_size ();
}
diff --git a/src/3rdparty/harfbuzz-ng/src/graph/markbasepos-graph.hh b/src/3rdparty/harfbuzz-ng/src/graph/markbasepos-graph.hh
index 84ef5f71b9..fb4166128a 100644
--- a/src/3rdparty/harfbuzz-ng/src/graph/markbasepos-graph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/graph/markbasepos-graph.hh
@@ -40,6 +40,7 @@ struct AnchorMatrix : public OT::Layout::GPOS_impl::AnchorMatrix
{
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
if (vertex_len < AnchorMatrix::min_size) return false;
+ hb_barrier ();
return vertex_len >= AnchorMatrix::min_size +
OT::Offset16::static_size * class_count * this->rows;
@@ -128,6 +129,7 @@ struct MarkArray : public OT::Layout::GPOS_impl::MarkArray
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
unsigned min_size = MarkArray::min_size;
if (vertex_len < min_size) return false;
+ hb_barrier ();
return vertex_len >= get_size ();
}
@@ -217,7 +219,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
const unsigned base_coverage_id = c.graph.index_for_offset (this_index, &baseCoverage);
const unsigned base_size =
- OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size +
+ OT::Layout::GPOS_impl::MarkBasePosFormat1_2<SmallTypes>::min_size +
MarkArray::min_size +
AnchorMatrix::min_size +
c.graph.vertices_[base_coverage_id].table_size ();
@@ -318,8 +320,11 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
{
hb_vector_t<class_info_t> class_to_info;
- unsigned class_count= classCount;
- class_to_info.resize (class_count);
+ unsigned class_count = classCount;
+ if (!class_count) return class_to_info;
+
+ if (!class_to_info.resize (class_count))
+ return hb_vector_t<class_info_t>();
auto mark_array = c.graph.as_table<MarkArray> (this_index, &markArray);
if (!mark_array) return hb_vector_t<class_info_t> ();
@@ -327,6 +332,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
for (unsigned mark = 0; mark < mark_count; mark++)
{
unsigned klass = (*mark_array.table)[mark].get_class ();
+ if (klass >= class_count) continue;
class_to_info[klass].marks.add (mark);
}
@@ -335,6 +341,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
unsigned mark = (link.position - 2) /
OT::Layout::GPOS_impl::MarkRecord::static_size;
unsigned klass = (*mark_array.table)[mark].get_class ();
+ if (klass >= class_count) continue;
class_to_info[klass].child_indices.push (link.objidx);
}
@@ -479,7 +486,7 @@ struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos
return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index);
#ifndef HB_NO_BEYOND_64K
case 2: HB_FALLTHROUGH;
- // Don't split 24bit PairPos's.
+ // Don't split 24bit MarkBasePos's.
#endif
default:
return hb_vector_t<unsigned> ();
@@ -490,6 +497,7 @@ struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos
{
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
if (vertex_len < u.format.get_size ()) return false;
+ hb_barrier ();
switch (u.format) {
case 1:
diff --git a/src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh b/src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh
index 1c13eb24f9..fd46861de4 100644
--- a/src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh
+++ b/src/3rdparty/harfbuzz-ng/src/graph/pairpos-graph.hh
@@ -42,6 +42,7 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size;
if (vertex_len < min_size) return false;
+ hb_barrier ();
return vertex_len >=
min_size + pairSet.get_size () - pairSet.len.get_size();
@@ -198,6 +199,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
size_t vertex_len = vertex.table_size ();
unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size;
if (vertex_len < min_size) return false;
+ hb_barrier ();
const unsigned class1_count = class1Count;
return vertex_len >=
@@ -215,7 +217,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
auto gid_and_class =
+ coverage->iter ()
| hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
- return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1->get_class (gid));
+ return hb_codepoint_pair_t (gid, class_def_1->get_class (gid));
})
;
class_def_size_estimator_t estimator (gid_and_class);
@@ -245,8 +247,8 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
for (unsigned i = 0; i < class1_count; i++)
{
unsigned accumulated_delta = class1_record_size;
- coverage_size += estimator.incremental_coverage_size (i);
- class_def_1_size += estimator.incremental_class_def_size (i);
+ class_def_1_size = estimator.add_class_def_size (i);
+ coverage_size = estimator.coverage_size ();
max_coverage_size = hb_max (max_coverage_size, coverage_size);
max_class_def_1_size = hb_max (max_class_def_1_size, class_def_1_size);
@@ -278,8 +280,10 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
split_points.push (i);
// split does not include i, so add the size for i when we reset the size counters.
accumulated = base_size + accumulated_delta;
- coverage_size = 4 + estimator.incremental_coverage_size (i);
- class_def_1_size = 4 + estimator.incremental_class_def_size (i);
+
+ estimator.reset();
+ class_def_1_size = estimator.add_class_def_size(i);
+ coverage_size = estimator.coverage_size();
visited.clear (); // node sharing isn't allowed between splits.
}
}
@@ -386,14 +390,14 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
auto klass_map =
+ coverage_table->iter ()
| hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
- return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1_table->get_class (gid));
+ return hb_codepoint_pair_t (gid, class_def_1_table->get_class (gid));
})
| hb_filter ([&] (hb_codepoint_t klass) {
return klass >= start && klass < end;
}, hb_second)
- | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, hb_codepoint_t> gid_and_class) {
+ | hb_map_retains_sorting ([&] (hb_codepoint_pair_t gid_and_class) {
// Classes must be from 0...N so subtract start
- return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid_and_class.first, gid_and_class.second - start);
+ return hb_codepoint_pair_t (gid_and_class.first, gid_and_class.second - start);
})
;
@@ -419,7 +423,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
class_def_link->width = SmallTypes::size;
class_def_link->objidx = class_def_2_id;
class_def_link->position = 10;
- graph.vertices_[class_def_2_id].parents.push (pair_pos_prime_id);
+ graph.vertices_[class_def_2_id].add_parent (pair_pos_prime_id);
graph.duplicate (pair_pos_prime_id, class_def_2_id);
return pair_pos_prime_id;
@@ -519,7 +523,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
auto klass_map =
+ coverage.table->iter ()
| hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
- return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1.table->get_class (gid));
+ return hb_codepoint_pair_t (gid, class_def_1.table->get_class (gid));
})
| hb_filter ([&] (hb_codepoint_t klass) {
return klass < count;
@@ -625,6 +629,7 @@ struct PairPos : public OT::Layout::GPOS_impl::PairPos
{
int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
if (vertex_len < u.format.get_size ()) return false;
+ hb_barrier ();
switch (u.format) {
case 1:
diff --git a/src/3rdparty/harfbuzz-ng/src/graph/serialize.hh b/src/3rdparty/harfbuzz-ng/src/graph/serialize.hh
index 040fd1de5f..06e4bf44d8 100644
--- a/src/3rdparty/harfbuzz-ng/src/graph/serialize.hh
+++ b/src/3rdparty/harfbuzz-ng/src/graph/serialize.hh
@@ -116,10 +116,10 @@ will_overflow (graph_t& graph,
for (int parent_idx = vertices.length - 1; parent_idx >= 0; parent_idx--)
{
// Don't need to check virtual links for overflow
- for (const auto& link : vertices[parent_idx].obj.real_links)
+ for (const auto& link : vertices.arrayZ[parent_idx].obj.real_links)
{
int64_t offset = compute_offset (graph, parent_idx, link);
- if (is_valid_offset (offset, link))
+ if (likely (is_valid_offset (offset, link)))
continue;
if (!overflows) return true;
@@ -226,6 +226,9 @@ inline hb_blob_t* serialize (const graph_t& graph)
{
hb_vector_t<char> buffer;
size_t size = graph.total_size_in_bytes ();
+
+ if (!size) return hb_blob_get_empty ();
+
if (!buffer.alloc (size)) {
DEBUG_MSG (SUBSET_REPACK, nullptr, "Unable to allocate output buffer.");
return nullptr;
diff --git a/src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc b/src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc
index 55854ff5c2..2da9348111 100644
--- a/src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc
+++ b/src/3rdparty/harfbuzz-ng/src/graph/test-classdef-graph.cc
@@ -26,27 +26,119 @@
#include "gsubgpos-context.hh"
#include "classdef-graph.hh"
+#include "hb-iter.hh"
+#include "hb-serialize.hh"
-typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> gid_and_class_t;
+typedef hb_codepoint_pair_t gid_and_class_t;
typedef hb_vector_t<gid_and_class_t> gid_and_class_list_t;
+template<typename It>
+static unsigned actual_class_def_size(It glyph_and_class) {
+ char buffer[100];
+ hb_serialize_context_t serializer(buffer, 100);
+ OT::ClassDef_serialize (&serializer, glyph_and_class);
+ serializer.end_serialize ();
+ assert(!serializer.in_error());
-static bool incremental_size_is (const gid_and_class_list_t& list, unsigned klass,
- unsigned cov_expected, unsigned class_def_expected)
+ hb_blob_t* blob = serializer.copy_blob();
+ unsigned size = hb_blob_get_length(blob);
+ hb_blob_destroy(blob);
+ return size;
+}
+
+static unsigned actual_class_def_size(gid_and_class_list_t consecutive_map, hb_vector_t<unsigned> classes) {
+ auto filtered_it =
+ + consecutive_map.as_sorted_array().iter()
+ | hb_filter([&] (unsigned c) {
+ for (unsigned klass : classes) {
+ if (c == klass) {
+ return true;
+ }
+ }
+ return false;
+ }, hb_second);
+ return actual_class_def_size(+ filtered_it);
+}
+
+template<typename It>
+static unsigned actual_coverage_size(It glyphs) {
+ char buffer[100];
+ hb_serialize_context_t serializer(buffer, 100);
+ OT::Layout::Common::Coverage_serialize (&serializer, glyphs);
+ serializer.end_serialize ();
+ assert(!serializer.in_error());
+
+ hb_blob_t* blob = serializer.copy_blob();
+ unsigned size = hb_blob_get_length(blob);
+ hb_blob_destroy(blob);
+ return size;
+}
+
+static unsigned actual_coverage_size(gid_and_class_list_t consecutive_map, hb_vector_t<unsigned> classes) {
+ auto filtered_it =
+ + consecutive_map.as_sorted_array().iter()
+ | hb_filter([&] (unsigned c) {
+ for (unsigned klass : classes) {
+ if (c == klass) {
+ return true;
+ }
+ }
+ return false;
+ }, hb_second);
+ return actual_coverage_size(+ filtered_it | hb_map_retains_sorting(hb_first));
+}
+
+static bool check_coverage_size(graph::class_def_size_estimator_t& estimator,
+ const gid_and_class_list_t& map,
+ hb_vector_t<unsigned> klasses)
+{
+ unsigned result = estimator.coverage_size();
+ unsigned expected = actual_coverage_size(map, klasses);
+ if (result != expected) {
+ printf ("FAIL: estimated coverage expected size %u but was %u\n", expected, result);
+ return false;
+ }
+ return true;
+}
+
+static bool check_add_class_def_size(graph::class_def_size_estimator_t& estimator,
+ const gid_and_class_list_t& map,
+ unsigned klass, hb_vector_t<unsigned> klasses)
+{
+ unsigned result = estimator.add_class_def_size(klass);
+ unsigned expected = actual_class_def_size(map, klasses);
+ if (result != expected) {
+ printf ("FAIL: estimated class def expected size %u but was %u\n", expected, result);
+ return false;
+ }
+
+ return check_coverage_size(estimator, map, klasses);
+}
+
+static bool check_add_class_def_size (const gid_and_class_list_t& list, unsigned klass)
{
graph::class_def_size_estimator_t estimator (list.iter ());
- unsigned result = estimator.incremental_coverage_size (klass);
- if (result != cov_expected)
+ unsigned result = estimator.add_class_def_size (klass);
+ auto filtered_it =
+ + list.as_sorted_array().iter()
+ | hb_filter([&] (unsigned c) {
+ return c == klass;
+ }, hb_second);
+
+ unsigned expected = actual_class_def_size(filtered_it);
+ if (result != expected)
{
- printf ("FAIL: coverage expected size %u but was %u\n", cov_expected, result);
+ printf ("FAIL: class def expected size %u but was %u\n", expected, result);
return false;
}
- result = estimator.incremental_class_def_size (klass);
- if (result != class_def_expected)
+ auto cov_it = + filtered_it | hb_map_retains_sorting(hb_first);
+ result = estimator.coverage_size ();
+ expected = actual_coverage_size(cov_it);
+ if (result != expected)
{
- printf ("FAIL: class def expected size %u but was %u\n", class_def_expected, result);
+ printf ("FAIL: coverage expected size %u but was %u\n", expected, result);
return false;
}
@@ -57,43 +149,45 @@ static void test_class_and_coverage_size_estimates ()
{
gid_and_class_list_t empty = {
};
- assert (incremental_size_is (empty, 0, 0, 0));
- assert (incremental_size_is (empty, 1, 0, 0));
+ assert (check_add_class_def_size (empty, 0));
+ assert (check_add_class_def_size (empty, 1));
gid_and_class_list_t class_zero = {
{5, 0},
};
- assert (incremental_size_is (class_zero, 0, 2, 0));
+ assert (check_add_class_def_size (class_zero, 0));
gid_and_class_list_t consecutive = {
{4, 0},
{5, 0},
+
{6, 1},
{7, 1},
+
{8, 2},
{9, 2},
{10, 2},
{11, 2},
};
- assert (incremental_size_is (consecutive, 0, 4, 0));
- assert (incremental_size_is (consecutive, 1, 4, 4));
- assert (incremental_size_is (consecutive, 2, 8, 6));
+ assert (check_add_class_def_size (consecutive, 0));
+ assert (check_add_class_def_size (consecutive, 1));
+ assert (check_add_class_def_size (consecutive, 2));
gid_and_class_list_t non_consecutive = {
{4, 0},
- {5, 0},
+ {6, 0},
- {6, 1},
- {7, 1},
+ {8, 1},
+ {10, 1},
{9, 2},
{10, 2},
{11, 2},
- {12, 2},
+ {13, 2},
};
- assert (incremental_size_is (non_consecutive, 0, 4, 0));
- assert (incremental_size_is (non_consecutive, 1, 4, 6));
- assert (incremental_size_is (non_consecutive, 2, 8, 6));
+ assert (check_add_class_def_size (non_consecutive, 0));
+ assert (check_add_class_def_size (non_consecutive, 1));
+ assert (check_add_class_def_size (non_consecutive, 2));
gid_and_class_list_t multiple_ranges = {
{4, 0},
@@ -108,12 +202,95 @@ static void test_class_and_coverage_size_estimates ()
{12, 1},
{13, 1},
};
- assert (incremental_size_is (multiple_ranges, 0, 4, 0));
- assert (incremental_size_is (multiple_ranges, 1, 2 * 6, 3 * 6));
+ assert (check_add_class_def_size (multiple_ranges, 0));
+ assert (check_add_class_def_size (multiple_ranges, 1));
+}
+
+static void test_running_class_and_coverage_size_estimates () {
+ // #### With consecutive gids: switches formats ###
+ gid_and_class_list_t consecutive_map = {
+ // range 1-4 (f1: 8 bytes), (f2: 6 bytes)
+ {1, 1},
+ {2, 1},
+ {3, 1},
+ {4, 1},
+
+ // (f1: 2 bytes), (f2: 6 bytes)
+ {5, 2},
+
+ // (f1: 14 bytes), (f2: 6 bytes)
+ {6, 3},
+ {7, 3},
+ {8, 3},
+ {9, 3},
+ {10, 3},
+ {11, 3},
+ {12, 3},
+ };
+
+ graph::class_def_size_estimator_t estimator1(consecutive_map.iter());
+ assert(check_add_class_def_size(estimator1, consecutive_map, 1, {1}));
+ assert(check_add_class_def_size(estimator1, consecutive_map, 2, {1, 2}));
+ assert(check_add_class_def_size(estimator1, consecutive_map, 2, {1, 2})); // check that adding the same class again works
+ assert(check_add_class_def_size(estimator1, consecutive_map, 3, {1, 2, 3}));
+
+ estimator1.reset();
+ assert(check_add_class_def_size(estimator1, consecutive_map, 2, {2}));
+ assert(check_add_class_def_size(estimator1, consecutive_map, 3, {2, 3}));
+
+ // #### With non-consecutive gids: always uses format 2 ###
+ gid_and_class_list_t non_consecutive_map = {
+ // range 1-4 (f1: 8 bytes), (f2: 6 bytes)
+ {1, 1},
+ {2, 1},
+ {3, 1},
+ {4, 1},
+
+ // (f1: 2 bytes), (f2: 12 bytes)
+ {6, 2},
+ {8, 2},
+
+ // (f1: 14 bytes), (f2: 6 bytes)
+ {9, 3},
+ {10, 3},
+ {11, 3},
+ {12, 3},
+ {13, 3},
+ {14, 3},
+ {15, 3},
+ };
+
+ graph::class_def_size_estimator_t estimator2(non_consecutive_map.iter());
+ assert(check_add_class_def_size(estimator2, non_consecutive_map, 1, {1}));
+ assert(check_add_class_def_size(estimator2, non_consecutive_map, 2, {1, 2}));
+ assert(check_add_class_def_size(estimator2, non_consecutive_map, 3, {1, 2, 3}));
+
+ estimator2.reset();
+ assert(check_add_class_def_size(estimator2, non_consecutive_map, 2, {2}));
+ assert(check_add_class_def_size(estimator2, non_consecutive_map, 3, {2, 3}));
+}
+
+static void test_running_class_size_estimates_with_locally_consecutive_glyphs () {
+ gid_and_class_list_t map = {
+ {1, 1},
+ {6, 2},
+ {7, 3},
+ };
+
+ graph::class_def_size_estimator_t estimator(map.iter());
+ assert(check_add_class_def_size(estimator, map, 1, {1}));
+ assert(check_add_class_def_size(estimator, map, 2, {1, 2}));
+ assert(check_add_class_def_size(estimator, map, 3, {1, 2, 3}));
+
+ estimator.reset();
+ assert(check_add_class_def_size(estimator, map, 2, {2}));
+ assert(check_add_class_def_size(estimator, map, 3, {2, 3}));
}
int
main (int argc, char **argv)
{
test_class_and_coverage_size_estimates ();
+ test_running_class_and_coverage_size_estimates ();
+ test_running_class_size_estimates_with_locally_consecutive_glyphs ();
}
diff --git a/src/3rdparty/harfbuzz-ng/src/harfbuzz-subset.cc b/src/3rdparty/harfbuzz-ng/src/harfbuzz-subset.cc
index c0e23b3eb8..f80c004cbb 100644
--- a/src/3rdparty/harfbuzz-ng/src/harfbuzz-subset.cc
+++ b/src/3rdparty/harfbuzz-ng/src/harfbuzz-subset.cc
@@ -54,6 +54,7 @@
#include "hb-subset-cff1.cc"
#include "hb-subset-cff2.cc"
#include "hb-subset-input.cc"
+#include "hb-subset-instancer-iup.cc"
#include "hb-subset-instancer-solver.cc"
#include "hb-subset-plan.cc"
#include "hb-subset-repacker.cc"
diff --git a/src/3rdparty/harfbuzz-ng/src/harfbuzz.cc b/src/3rdparty/harfbuzz-ng/src/harfbuzz.cc
index d7e8a93f39..26e2bc1450 100644
--- a/src/3rdparty/harfbuzz-ng/src/harfbuzz.cc
+++ b/src/3rdparty/harfbuzz-ng/src/harfbuzz.cc
@@ -58,3 +58,5 @@
#include "hb-ucd.cc"
#include "hb-unicode.cc"
#include "hb-uniscribe.cc"
+#include "hb-wasm-api.cc"
+#include "hb-wasm-shape.cc"
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-ankr-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-ankr-table.hh
index 63fac84524..dbb38b1bc0 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-ankr-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-ankr-table.hh
@@ -75,6 +75,7 @@ struct ankr
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
+ hb_barrier () &&
version == 0 &&
c->check_range (this, anchorData) &&
lookupTable.sanitize (c, this, &(this+anchorData))));
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-bsln-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-bsln-table.hh
index bf12d2e699..8e42fab2e0 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-bsln-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-bsln-table.hh
@@ -123,6 +123,7 @@ struct bsln
TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this) && defaultBaseline < 32)))
return_trace (false);
+ hb_barrier ();
switch (format)
{
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh
index efbb623efc..05dd58c6df 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-common.hh
@@ -191,6 +191,7 @@ struct LookupSegmentArray
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
first <= last &&
valuesZ.sanitize (c, base, last - first + 1));
}
@@ -199,6 +200,7 @@ struct LookupSegmentArray
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
first <= last &&
valuesZ.sanitize (c, base, last - first + 1, std::forward<Ts> (ds)...));
}
@@ -360,6 +362,7 @@ struct LookupFormat10
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
valueSize <= 4 &&
valueArrayZ.sanitize (c, glyphCount * valueSize));
}
@@ -415,6 +418,7 @@ struct Lookup
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
+ hb_barrier ();
switch (u.format) {
case 0: return_trace (u.format0.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
@@ -429,6 +433,7 @@ struct Lookup
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
+ hb_barrier ();
switch (u.format) {
case 0: return_trace (u.format0.sanitize (c, base));
case 2: return_trace (u.format2.sanitize (c, base));
@@ -464,7 +469,8 @@ enum { DELETED_GLYPH = 0xFFFF };
template <typename T>
struct Entry
{
- bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
+ // This does seem like it's ever called.
+ bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
/* Note, we don't recurse-sanitize data because we don't access it.
@@ -492,7 +498,8 @@ struct Entry
template <>
struct Entry<void>
{
- bool sanitize (hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const
+ // This does seem like it's ever called.
+ bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
@@ -556,6 +563,7 @@ struct StateTable
{
TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this) &&
+ hb_barrier () &&
nClasses >= 4 /* Ensure pre-defined classes fit. */ &&
classTable.sanitize (c, this)))) return_trace (false);
@@ -849,43 +857,41 @@ struct StateTableDriver
*
* https://github.com/harfbuzz/harfbuzz/issues/2860
*/
- const EntryT *wouldbe_entry;
- bool safe_to_break =
- /* 1. */
- !c->is_actionable (this, entry)
- &&
- /* 2. */
- (
- /* 2a. */
- state == StateTableT::STATE_START_OF_TEXT
- ||
- /* 2b. */
- (
- (entry.flags & context_t::DontAdvance) &&
- next_state == StateTableT::STATE_START_OF_TEXT
- )
- ||
- /* 2c. */
- (
- wouldbe_entry = &machine.get_entry (StateTableT::STATE_START_OF_TEXT, klass)
- ,
- /* 2c'. */
- !c->is_actionable (this, *wouldbe_entry)
- &&
- /* 2c". */
- (
- next_state == machine.new_state (wouldbe_entry->newState)
- &&
- (entry.flags & context_t::DontAdvance) == (wouldbe_entry->flags & context_t::DontAdvance)
- )
- )
- )
- &&
- /* 3. */
- !c->is_actionable (this, machine.get_entry (state, StateTableT::CLASS_END_OF_TEXT))
- ;
-
- if (!safe_to_break && buffer->backtrack_len () && buffer->idx < buffer->len)
+
+ const auto is_safe_to_break_extra = [&]()
+ {
+ /* 2c. */
+ const auto wouldbe_entry = machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass);
+
+ /* 2c'. */
+ if (c->is_actionable (this, wouldbe_entry))
+ return false;
+
+ /* 2c". */
+ return next_state == machine.new_state(wouldbe_entry.newState)
+ && (entry.flags & context_t::DontAdvance) == (wouldbe_entry.flags & context_t::DontAdvance);
+ };
+
+ const auto is_safe_to_break = [&]()
+ {
+ /* 1. */
+ if (c->is_actionable (this, entry))
+ return false;
+
+ /* 2. */
+ // This one is meh, I know...
+ const auto ok =
+ state == StateTableT::STATE_START_OF_TEXT
+ || ((entry.flags & context_t::DontAdvance) && next_state == StateTableT::STATE_START_OF_TEXT)
+ || is_safe_to_break_extra();
+ if (!ok)
+ return false;
+
+ /* 3. */
+ return !c->is_actionable (this, machine.get_entry (state, StateTableT::CLASS_END_OF_TEXT));
+ };
+
+ if (!is_safe_to_break () && buffer->backtrack_len () && buffer->idx < buffer->len)
buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
c->transition (this, entry);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-feat-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-feat-table.hh
index 815a1fd2aa..4fbec332eb 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-feat-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-feat-table.hh
@@ -138,6 +138,7 @@ struct FeatureName
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
+ hb_barrier () &&
(base+settingTableZ).sanitize (c, nSettings)));
}
@@ -200,6 +201,7 @@ struct feat
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
+ hb_barrier () &&
version.major == 1 &&
namesZ.sanitize (c, featureNameCount, this)));
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-just-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-just-table.hh
index 8fd3990f88..ee08da172e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-just-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-just-table.hh
@@ -185,6 +185,7 @@ struct ActionSubrecord
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
+ hb_barrier ();
switch (u.header.actionType)
{
@@ -220,6 +221,7 @@ struct PostcompensationActionChain
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
+ hb_barrier ();
unsigned int offset = min_size;
for (unsigned int i = 0; i < count; i++)
@@ -389,6 +391,7 @@ struct just
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
+ hb_barrier () &&
version.major == 1 &&
horizData.sanitize (c, this, this) &&
vertData.sanitize (c, this, this)));
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh
index 35d7c84c2b..0de54e0a02 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-kerx-table.hh
@@ -54,6 +54,7 @@ kerxTupleKern (int value,
unsigned int offset = value;
const FWORD *pv = &StructAtOffset<FWORD> (base, offset);
if (unlikely (!c->sanitizer.check_array (pv, tupleCount))) return 0;
+ hb_barrier ();
return *pv;
}
@@ -259,6 +260,7 @@ struct KerxSubTableFormat1
depth = 0;
return;
}
+ hb_barrier ();
hb_mask_t kern_mask = c->plan->kern_mask;
@@ -389,6 +391,7 @@ struct KerxSubTableFormat2
kern_idx = Types::offsetToIndex (kern_idx, this, arrayZ.arrayZ);
const FWORD *v = &arrayZ[kern_idx];
if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
+ hb_barrier ();
return kerxTupleKern (*v, header.tuple_count (), this, c);
}
@@ -429,6 +432,7 @@ struct KerxSubTableFormat2
return_trace (likely (c->check_struct (this) &&
leftClassTable.sanitize (c, this) &&
rightClassTable.sanitize (c, this) &&
+ hb_barrier () &&
c->check_range (this, array)));
}
@@ -509,6 +513,7 @@ struct KerxSubTableFormat4
double the ankrActionIndex to get the correct offset here. */
const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2];
if (!c->sanitizer.check_array (data, 2)) return;
+ hb_barrier ();
unsigned int markControlPoint = *data++;
unsigned int currControlPoint = *data++;
hb_position_t markX = 0;
@@ -537,6 +542,7 @@ struct KerxSubTableFormat4
double the ankrActionIndex to get the correct offset here. */
const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2];
if (!c->sanitizer.check_array (data, 2)) return;
+ hb_barrier ();
unsigned int markAnchorPoint = *data++;
unsigned int currAnchorPoint = *data++;
const Anchor &markAnchor = c->ankr_table->get_anchor (c->buffer->info[mark].codepoint,
@@ -557,6 +563,7 @@ struct KerxSubTableFormat4
by 4 to get the correct offset for the given action. */
const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex * 4];
if (!c->sanitizer.check_array (data, 4)) return;
+ hb_barrier ();
int markX = *data++;
int markY = *data++;
int currX = *data++;
@@ -639,6 +646,7 @@ struct KerxSubTableFormat6
if (unlikely (hb_unsigned_mul_overflows (offset, sizeof (FWORD32)))) return 0;
const FWORD32 *v = &StructAtOffset<FWORD32> (&(this+t.array), offset * sizeof (FWORD32));
if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
+ hb_barrier ();
return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c);
}
else
@@ -649,6 +657,7 @@ struct KerxSubTableFormat6
unsigned int offset = l + r;
const FWORD *v = &StructAtOffset<FWORD> (&(this+t.array), offset * sizeof (FWORD));
if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
+ hb_barrier ();
return kerxTupleKern (*v, header.tuple_count (), &(this+vector), c);
}
}
@@ -674,6 +683,7 @@ struct KerxSubTableFormat6
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
+ hb_barrier () &&
(is_long () ?
(
u.l.rowIndexTable.sanitize (c, this) &&
@@ -787,9 +797,10 @@ struct KerxSubTable
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- if (!u.header.sanitize (c) ||
- u.header.length <= u.header.static_size ||
- !c->check_range (this, u.header.length))
+ if (!(u.header.sanitize (c) &&
+ hb_barrier () &&
+ u.header.length >= u.header.static_size &&
+ c->check_range (this, u.header.length)))
return_trace (false);
return_trace (dispatch (c));
@@ -936,9 +947,10 @@ struct KerxTable
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- if (unlikely (!thiz()->version.sanitize (c) ||
- (unsigned) thiz()->version < (unsigned) T::minVersion ||
- !thiz()->tableCount.sanitize (c)))
+ if (unlikely (!(thiz()->version.sanitize (c) &&
+ hb_barrier () &&
+ (unsigned) thiz()->version >= (unsigned) T::minVersion &&
+ thiz()->tableCount.sanitize (c))))
return_trace (false);
typedef typename T::SubTable SubTable;
@@ -949,6 +961,7 @@ struct KerxTable
{
if (unlikely (!st->u.header.sanitize (c)))
return_trace (false);
+ hb_barrier ();
/* OpenType kern table has 2-byte subtable lengths. That's limiting.
* MS implementation also only supports one subtable, of format 0,
* anyway. Certain versions of some fonts, like Calibry, contain
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh
index f41ecc197f..8436551324 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-morx-table.hh
@@ -259,7 +259,9 @@ struct ContextualSubtable
unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
- if (!replacement->sanitize (&c->sanitizer) || !*replacement)
+ if (!(replacement->sanitize (&c->sanitizer) &&
+ hb_barrier () &&
+ *replacement))
replacement = nullptr;
}
if (replacement)
@@ -287,7 +289,9 @@ struct ContextualSubtable
unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs;
replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
- if (!replacement->sanitize (&c->sanitizer) || !*replacement)
+ if (!(replacement->sanitize (&c->sanitizer) &&
+ hb_barrier () &&
+ *replacement))
replacement = nullptr;
}
if (replacement)
@@ -315,7 +319,7 @@ struct ContextualSubtable
bool has_glyph_classes;
unsigned int mark;
const ContextualSubtable *table;
- const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, false> &subs;
+ const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false> &subs;
};
bool apply (hb_aat_apply_context_t *c) const
@@ -336,6 +340,7 @@ struct ContextualSubtable
unsigned int num_entries = 0;
if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false);
+ hb_barrier ();
if (!Types::extended)
return_trace (substitutionTables.sanitize (c, this, 0));
@@ -359,7 +364,7 @@ struct ContextualSubtable
protected:
StateTable<Types, EntryData>
machine;
- NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, false>, HBUINT>
+ NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false>, HBUINT>
substitutionTables;
public:
DEFINE_SIZE_STATIC (20);
@@ -513,6 +518,7 @@ struct LigatureSubtable
if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return;
if (unlikely (!actionData->sanitize (&c->sanitizer))) break;
+ hb_barrier ();
action = *actionData;
uint32_t uoffset = action & LigActionOffset;
@@ -523,6 +529,7 @@ struct LigatureSubtable
component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ);
const HBUINT16 &componentData = component[component_idx];
if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
+ hb_barrier ();
ligature_idx += componentData;
DEBUG_MSG (APPLY, nullptr, "Action store %d last %d",
@@ -533,6 +540,7 @@ struct LigatureSubtable
ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
const HBGlyphID16 &ligatureData = ligature[ligature_idx];
if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
+ hb_barrier ();
hb_codepoint_t lig = ligatureData;
DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig);
@@ -544,6 +552,7 @@ struct LigatureSubtable
{
DEBUG_MSG (APPLY, nullptr, "Skipping ligature component");
if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return;
+ buffer->cur().unicode_props() |= UPROPS_MASK_IGNORABLE;
if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return;
}
@@ -587,6 +596,7 @@ struct LigatureSubtable
TRACE_SANITIZE (this);
/* The rest of array sanitizations are done at run-time. */
return_trace (c->check_struct (this) && machine.sanitize (c) &&
+ hb_barrier () &&
ligAction && component && ligature);
}
@@ -765,6 +775,7 @@ struct InsertionSubtable
unsigned int start = entry.data.markedInsertIndex;
const HBGlyphID16 *glyphs = &insertionAction[start];
if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
+ hb_barrier ();
bool before = flags & MarkedInsertBefore;
@@ -793,6 +804,7 @@ struct InsertionSubtable
unsigned int start = entry.data.currentInsertIndex;
const HBGlyphID16 *glyphs = &insertionAction[start];
if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
+ hb_barrier ();
bool before = flags & CurrentInsertBefore;
@@ -849,6 +861,7 @@ struct InsertionSubtable
TRACE_SANITIZE (this);
/* The rest of array sanitizations are done at run-time. */
return_trace (c->check_struct (this) && machine.sanitize (c) &&
+ hb_barrier () &&
insertionAction);
}
@@ -944,9 +957,10 @@ struct ChainSubtable
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- if (!length.sanitize (c) ||
- length <= min_size ||
- !c->check_range (this, length))
+ if (!(length.sanitize (c) &&
+ hb_barrier () &&
+ length >= min_size &&
+ c->check_range (this, length)))
return_trace (false);
hb_sanitize_with_object_t with (c, this);
@@ -1089,9 +1103,10 @@ struct Chain
bool sanitize (hb_sanitize_context_t *c, unsigned int version HB_UNUSED) const
{
TRACE_SANITIZE (this);
- if (!length.sanitize (c) ||
- length < min_size ||
- !c->check_range (this, length))
+ if (!(length.sanitize (c) &&
+ hb_barrier () &&
+ length >= min_size &&
+ c->check_range (this, length)))
return_trace (false);
if (!c->check_array (featureZ.arrayZ, featureCount))
@@ -1103,6 +1118,7 @@ struct Chain
{
if (!subtable->sanitize (c))
return_trace (false);
+ hb_barrier ();
subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
}
@@ -1173,7 +1189,10 @@ struct mortmorx
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- if (!version.sanitize (c) || !version || !chainCount.sanitize (c))
+ if (!(version.sanitize (c) &&
+ hb_barrier () &&
+ version &&
+ chainCount.sanitize (c)))
return_trace (false);
const Chain<Types> *chain = &firstChain;
@@ -1182,6 +1201,7 @@ struct mortmorx
{
if (!chain->sanitize (c, version))
return_trace (false);
+ hb_barrier ();
chain = &StructAfter<Chain<Types>> (*chain);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-opbd-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-opbd-table.hh
index 51b650fc33..9840d3a554 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-opbd-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-opbd-table.hh
@@ -144,6 +144,7 @@ struct opbd
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this) || version.major != 1))
return_trace (false);
+ hb_barrier ();
switch (format)
{
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-trak-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-trak-table.hh
index 2ba9355b06..345a236e95 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-trak-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout-trak-table.hh
@@ -111,13 +111,13 @@ struct TrackData
break;
}
}
- if (!trackTableEntry) return 0.;
+ if (!trackTableEntry) return 0;
/*
* Choose size.
*/
unsigned int sizes = nSizes;
- if (!sizes) return 0.;
+ if (!sizes) return 0;
if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
@@ -134,6 +134,7 @@ struct TrackData
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
+ hb_barrier () &&
sizeTable.sanitize (c, base, nSizes) &&
trackTable.sanitize (c, nTracks, base, nSizes)));
}
@@ -203,6 +204,7 @@ struct trak
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
+ hb_barrier () &&
version.major == 1 &&
horizData.sanitize (c, this, this) &&
vertData.sanitize (c, this, this)));
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.cc b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.cc
index c9147ff73b..5e4cea2224 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.cc
@@ -55,7 +55,13 @@ AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *p
buffer (buffer_),
sanitizer (),
ankr_table (&Null (AAT::ankr)),
- gdef_table (face->table.GDEF->table),
+ gdef_table (
+#ifndef HB_NO_OT_LAYOUT
+ face->table.GDEF->table
+#else
+ &Null (GDEF)
+#endif
+ ),
lookup_index (0)
{
sanitizer.init (blob);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.h b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.h
index 9af2740088..c682a2f6d7 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-layout.h
@@ -40,7 +40,7 @@ HB_BEGIN_DECLS
* @HB_AAT_LAYOUT_FEATURE_TYPE_INVALID: Initial, unset feature type
* @HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC: [All Typographic Features](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type0)
* @HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES: [Ligatures](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type1)
- * @HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION: [Cursive Connection](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type2)
+ * @HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION: [Cursive Connection](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type2)
* @HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE: [Letter Case](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type3)
* @HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION: [Vertical Substitution](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type4)
* @HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT: [Linguistic Rearrangement](https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html#Type5)
@@ -88,7 +88,7 @@ typedef enum
HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC = 0,
HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES = 1,
- HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION = 2,
+ HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION = 2,
HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE = 3,
HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION = 4,
HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT = 5,
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-aat-ltag-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-aat-ltag-table.hh
index 6d771e1513..c974025d44 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-aat-ltag-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-aat-ltag-table.hh
@@ -46,7 +46,9 @@ struct FTStringRange
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) && (base+tag).sanitize (c, length));
+ return_trace (c->check_struct (this) &&
+ hb_barrier () &&
+ (base+tag).sanitize (c, length));
}
protected:
@@ -73,6 +75,7 @@ struct ltag
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
+ hb_barrier () &&
version >= 1 &&
tagRanges.sanitize (c, this)));
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-algs.hh b/src/3rdparty/harfbuzz-ng/src/hb-algs.hh
index e98645e3e3..efa6074a42 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-algs.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-algs.hh
@@ -87,6 +87,19 @@ static inline constexpr uint16_t hb_uint16_swap (uint16_t v)
static inline constexpr uint32_t hb_uint32_swap (uint32_t v)
{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
+#ifndef HB_FAST_INT_ACCESS
+#if defined(__OPTIMIZE__) && \
+ defined(__BYTE_ORDER) && \
+ (__BYTE_ORDER == __BIG_ENDIAN || \
+ (__BYTE_ORDER == __LITTLE_ENDIAN && \
+ hb_has_builtin(__builtin_bswap16) && \
+ hb_has_builtin(__builtin_bswap32)))
+#define HB_FAST_INT_ACCESS 1
+#else
+#define HB_FAST_INT_ACCESS 0
+#endif
+#endif
+
template <typename Type, int Bytes = sizeof (Type)>
struct BEInt;
template <typename Type>
@@ -101,20 +114,25 @@ struct BEInt<Type, 1>
template <typename Type>
struct BEInt<Type, 2>
{
+ struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
+
public:
BEInt () = default;
- constexpr BEInt (Type V) : v {uint8_t ((V >> 8) & 0xFF),
- uint8_t ((V ) & 0xFF)} {}
- struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
- constexpr operator Type () const
- {
-#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
- ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
- defined(__BYTE_ORDER) && \
- (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
- /* Spoon-feed the compiler a big-endian integer with alignment 1.
- * https://github.com/harfbuzz/harfbuzz/pull/1398 */
+ BEInt (Type V)
+#if HB_FAST_INT_ACCESS
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ { ((packed_uint16_t *) v)->v = __builtin_bswap16 (V); }
+#else /* __BYTE_ORDER == __BIG_ENDIAN */
+ { ((packed_uint16_t *) v)->v = V; }
+#endif
+#else
+ : v {uint8_t ((V >> 8) & 0xFF),
+ uint8_t ((V ) & 0xFF)} {}
+#endif
+
+ constexpr operator Type () const {
+#if HB_FAST_INT_ACCESS
#if __BYTE_ORDER == __LITTLE_ENDIAN
return __builtin_bswap16 (((packed_uint16_t *) v)->v);
#else /* __BYTE_ORDER == __BIG_ENDIAN */
@@ -145,21 +163,27 @@ struct BEInt<Type, 3>
template <typename Type>
struct BEInt<Type, 4>
{
+ struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
+
public:
BEInt () = default;
- constexpr BEInt (Type V) : v {uint8_t ((V >> 24) & 0xFF),
- uint8_t ((V >> 16) & 0xFF),
- uint8_t ((V >> 8) & 0xFF),
- uint8_t ((V ) & 0xFF)} {}
- struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
+ BEInt (Type V)
+#if HB_FAST_INT_ACCESS
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ { ((packed_uint32_t *) v)->v = __builtin_bswap32 (V); }
+#else /* __BYTE_ORDER == __BIG_ENDIAN */
+ { ((packed_uint32_t *) v)->v = V; }
+#endif
+#else
+ : v {uint8_t ((V >> 24) & 0xFF),
+ uint8_t ((V >> 16) & 0xFF),
+ uint8_t ((V >> 8) & 0xFF),
+ uint8_t ((V ) & 0xFF)} {}
+#endif
+
constexpr operator Type () const {
-#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
- ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
- defined(__BYTE_ORDER) && \
- (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
- /* Spoon-feed the compiler a big-endian integer with alignment 1.
- * https://github.com/harfbuzz/harfbuzz/pull/1398 */
+#if HB_FAST_INT_ACCESS
#if __BYTE_ORDER == __LITTLE_ENDIAN
return __builtin_bswap32 (((packed_uint32_t *) v)->v);
#else /* __BYTE_ORDER == __BIG_ENDIAN */
@@ -229,12 +253,123 @@ struct
}
HB_FUNCOBJ (hb_bool);
+
+/* The MIT License
+
+ Copyright (C) 2012 Zilong Tan (eric.zltan@gmail.com)
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use, copy,
+ modify, merge, publish, distribute, sublicense, and/or sell copies
+ of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+*/
+
+
+// Compression function for Merkle-Damgard construction.
+// This function is generated using the framework provided.
+#define mix(h) ( \
+ (void) ((h) ^= (h) >> 23), \
+ (void) ((h) *= 0x2127599bf4325c37ULL), \
+ (h) ^= (h) >> 47)
+
+static inline uint64_t fasthash64(const void *buf, size_t len, uint64_t seed)
+{
+ struct __attribute__((packed)) packed_uint64_t { uint64_t v; };
+ const uint64_t m = 0x880355f21e6d1965ULL;
+ const packed_uint64_t *pos = (const packed_uint64_t *)buf;
+ const packed_uint64_t *end = pos + (len / 8);
+ const unsigned char *pos2;
+ uint64_t h = seed ^ (len * m);
+ uint64_t v;
+
+#ifndef HB_OPTIMIZE_SIZE
+ if (((uintptr_t) pos & 7) == 0)
+ {
+ while (pos != end)
+ {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+ v = * (const uint64_t *) (pos++);
+#pragma GCC diagnostic pop
+ h ^= mix(v);
+ h *= m;
+ }
+ }
+ else
+#endif
+ {
+ while (pos != end)
+ {
+ v = pos++->v;
+ h ^= mix(v);
+ h *= m;
+ }
+ }
+
+ pos2 = (const unsigned char*)pos;
+ v = 0;
+
+ switch (len & 7) {
+ case 7: v ^= (uint64_t)pos2[6] << 48; HB_FALLTHROUGH;
+ case 6: v ^= (uint64_t)pos2[5] << 40; HB_FALLTHROUGH;
+ case 5: v ^= (uint64_t)pos2[4] << 32; HB_FALLTHROUGH;
+ case 4: v ^= (uint64_t)pos2[3] << 24; HB_FALLTHROUGH;
+ case 3: v ^= (uint64_t)pos2[2] << 16; HB_FALLTHROUGH;
+ case 2: v ^= (uint64_t)pos2[1] << 8; HB_FALLTHROUGH;
+ case 1: v ^= (uint64_t)pos2[0];
+ h ^= mix(v);
+ h *= m;
+ }
+
+ return mix(h);
+}
+
+static inline uint32_t fasthash32(const void *buf, size_t len, uint32_t seed)
+{
+ // the following trick converts the 64-bit hashcode to Fermat
+ // residue, which shall retain information from both the higher
+ // and lower parts of hashcode.
+ uint64_t h = fasthash64(buf, len, seed);
+ return h - (h >> 32);
+}
+
struct
{
private:
template <typename T> constexpr auto
- impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref (v).hash ())
+ impl (const T& v, hb_priority<2>) const HB_RETURN (uint32_t, hb_deref (v).hash ())
+
+ // Horrible: std:hash() of integers seems to be identity in gcc / clang?!
+ // https://github.com/harfbuzz/harfbuzz/pull/4228
+ //
+ // For performance characteristics see:
+ // https://github.com/harfbuzz/harfbuzz/pull/4228#issuecomment-1565079537
+ template <typename T,
+ hb_enable_if (std::is_integral<T>::value && sizeof (T) <= sizeof (uint32_t))> constexpr auto
+ impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, (uint32_t) v * 2654435761u /* Knuh's multiplicative hash */)
+ template <typename T,
+ hb_enable_if (std::is_integral<T>::value && sizeof (T) > sizeof (uint32_t))> constexpr auto
+ impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, (uint32_t) (v ^ (v >> 32)) * 2654435761u /* Knuth's multiplicative hash */)
+
+ template <typename T,
+ hb_enable_if (std::is_floating_point<T>::value)> constexpr auto
+ impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, fasthash32 (std::addressof (v), sizeof (T), 0xf437ffe6))
template <typename T> constexpr auto
impl (const T& v, hb_priority<0>) const HB_RETURN (uint32_t, std::hash<hb_decay<decltype (hb_deref (v))>>{} (hb_deref (v)))
@@ -536,7 +671,7 @@ struct hb_pair_t
return 0;
}
- friend void swap (hb_pair_t& a, hb_pair_t& b)
+ friend void swap (hb_pair_t& a, hb_pair_t& b) noexcept
{
hb_swap (a.first, b.first);
hb_swap (a.second, b.second);
@@ -549,6 +684,8 @@ struct hb_pair_t
template <typename T1, typename T2> static inline hb_pair_t<T1, T2>
hb_pair (T1&& a, T2&& b) { return hb_pair_t<T1, T2> (a, b); }
+typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
+
struct
{
template <typename Pair> constexpr typename Pair::first_t
@@ -598,13 +735,17 @@ template <typename T>
static inline unsigned int
hb_popcount (T v)
{
-#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
+#if hb_has_builtin(__builtin_popcount)
if (sizeof (T) <= sizeof (unsigned int))
return __builtin_popcount (v);
+#endif
+#if hb_has_builtin(__builtin_popcountl)
if (sizeof (T) <= sizeof (unsigned long))
return __builtin_popcountl (v);
+#endif
+#if hb_has_builtin(__builtin_popcountll)
if (sizeof (T) <= sizeof (unsigned long long))
return __builtin_popcountll (v);
#endif
@@ -620,8 +761,10 @@ hb_popcount (T v)
if (sizeof (T) == 8)
{
- unsigned int shift = 32;
- return hb_popcount<uint32_t> ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift));
+ uint64_t y = (uint64_t) v;
+ y -= ((y >> 1) & 0x5555555555555555ull);
+ y = (y & 0x3333333333333333ull) + (y >> 2 & 0x3333333333333333ull);
+ return ((y + (y >> 4)) & 0xf0f0f0f0f0f0f0full) * 0x101010101010101ull >> 56;
}
if (sizeof (T) == 16)
@@ -641,13 +784,17 @@ hb_bit_storage (T v)
{
if (unlikely (!v)) return 0;
-#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
+#if hb_has_builtin(__builtin_clz)
if (sizeof (T) <= sizeof (unsigned int))
return sizeof (unsigned int) * 8 - __builtin_clz (v);
+#endif
+#if hb_has_builtin(__builtin_clzl)
if (sizeof (T) <= sizeof (unsigned long))
return sizeof (unsigned long) * 8 - __builtin_clzl (v);
+#endif
+#if hb_has_builtin(__builtin_clzll)
if (sizeof (T) <= sizeof (unsigned long long))
return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
#endif
@@ -715,13 +862,17 @@ hb_ctz (T v)
{
if (unlikely (!v)) return 8 * sizeof (T);
-#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
+#if hb_has_builtin(__builtin_ctz)
if (sizeof (T) <= sizeof (unsigned int))
return __builtin_ctz (v);
+#endif
+#if hb_has_builtin(__builtin_ctzl)
if (sizeof (T) <= sizeof (unsigned long))
return __builtin_ctzl (v);
+#endif
+#if hb_has_builtin(__builtin_ctzll)
if (sizeof (T) <= sizeof (unsigned long long))
return __builtin_ctzll (v);
#endif
@@ -837,7 +988,7 @@ static inline void *
hb_memset (void *s, int c, unsigned int n)
{
/* It's illegal to pass NULL to memset(), even if n is zero. */
- if (unlikely (!n)) return 0;
+ if (unlikely (!n)) return s;
return memset (s, c, n);
}
@@ -875,7 +1026,7 @@ hb_in_ranges (T u, T lo1, T hi1, Ts... ds)
static inline bool
hb_unsigned_mul_overflows (unsigned int count, unsigned int size, unsigned *result = nullptr)
{
-#if (defined(__GNUC__) && (__GNUC__ >= 4)) || (defined(__clang__) && (__clang_major__ >= 8))
+#if hb_has_builtin(__builtin_mul_overflow)
unsigned stack_result;
if (!result)
result = &stack_result;
@@ -902,6 +1053,18 @@ _hb_cmp_method (const void *pkey, const void *pval, Ts... ds)
return val.cmp (key, ds...);
}
+template <typename K, typename V>
+static int
+_hb_cmp_operator (const void *pkey, const void *pval)
+{
+ const K& key = * (const K*) pkey;
+ const V& val = * (const V*) pval;
+
+ if (key < val) return -1;
+ if (key > val) return 1;
+ return 0;
+}
+
template <typename V, typename K, typename ...Ts>
static inline bool
hb_bsearch_impl (unsigned *pos, /* Out */
@@ -1330,4 +1493,62 @@ struct
HB_FUNCOBJ (hb_dec);
+/* Adapted from kurbo implementation with extra parameters added,
+ * and finding for a particular range instead of 0.
+ *
+ * For documentation and implementation see:
+ *
+ * [ITP method]: https://en.wikipedia.org/wiki/ITP_Method
+ * [An Enhancement of the Bisection Method Average Performance Preserving Minmax Optimality]: https://dl.acm.org/doi/10.1145/3423597
+ * https://docs.rs/kurbo/0.8.1/kurbo/common/fn.solve_itp.html
+ * https://github.com/linebender/kurbo/blob/fd839c25ea0c98576c7ce5789305822675a89938/src/common.rs#L162-L248
+ */
+template <typename func_t>
+double solve_itp (func_t f,
+ double a, double b,
+ double epsilon,
+ double min_y, double max_y,
+ double &ya, double &yb, double &y)
+{
+ unsigned n1_2 = (unsigned) (hb_max (ceil (log2 ((b - a) / epsilon)) - 1.0, 0.0));
+ const unsigned n0 = 1; // Hardwired
+ const double k1 = 0.2 / (b - a); // Hardwired.
+ unsigned nmax = n0 + n1_2;
+ double scaled_epsilon = epsilon * double (1llu << nmax);
+ double _2_epsilon = 2.0 * epsilon;
+ while (b - a > _2_epsilon)
+ {
+ double x1_2 = 0.5 * (a + b);
+ double r = scaled_epsilon - 0.5 * (b - a);
+ double xf = (yb * a - ya * b) / (yb - ya);
+ double sigma = x1_2 - xf;
+ double b_a = b - a;
+ // This has k2 = 2 hardwired for efficiency.
+ double b_a_k2 = b_a * b_a;
+ double delta = k1 * b_a_k2;
+ int sigma_sign = sigma >= 0 ? +1 : -1;
+ double xt = delta <= fabs (x1_2 - xf) ? xf + delta * sigma_sign : x1_2;
+ double xitp = fabs (xt - x1_2) <= r ? xt : x1_2 - r * sigma_sign;
+ double yitp = f (xitp);
+ if (yitp > max_y)
+ {
+ b = xitp;
+ yb = yitp;
+ }
+ else if (yitp < min_y)
+ {
+ a = xitp;
+ ya = yitp;
+ }
+ else
+ {
+ y = yitp;
+ return xitp;
+ }
+ scaled_epsilon *= 0.5;
+ }
+ return 0.5 * (a + b);
+}
+
+
#endif /* HB_ALGS_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-array.hh b/src/3rdparty/harfbuzz-ng/src/hb-array.hh
index e82c081535..9037179bc5 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-array.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-array.hh
@@ -47,6 +47,8 @@ enum hb_not_found_t
template <typename Type>
struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
{
+ static constexpr bool realloc_move = true;
+
/*
* Constructors.
*/
@@ -75,11 +77,25 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
*/
typedef Type& __item_t__;
static constexpr bool is_random_access_iterator = true;
+ static constexpr bool has_fast_len = true;
+ Type& __item__ () const
+ {
+ if (unlikely (!length)) return CrapOrNull (Type);
+ return *arrayZ;
+ }
Type& __item_at__ (unsigned i) const
{
if (unlikely (i >= length)) return CrapOrNull (Type);
return arrayZ[i];
}
+ void __next__ ()
+ {
+ if (unlikely (!length))
+ return;
+ length--;
+ backwards_length++;
+ arrayZ++;
+ }
void __forward__ (unsigned n)
{
if (unlikely (n > length))
@@ -88,6 +104,14 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
backwards_length += n;
arrayZ += n;
}
+ void __prev__ ()
+ {
+ if (unlikely (!backwards_length))
+ return;
+ length++;
+ backwards_length--;
+ arrayZ--;
+ }
void __rewind__ (unsigned n)
{
if (unlikely (n > backwards_length))
@@ -122,9 +146,14 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
uint32_t hash () const
{
- uint32_t current = 0;
+ // FNV-1a hash function
+ // https://github.com/harfbuzz/harfbuzz/pull/4228
+ uint32_t current = /*cbf29ce4*/0x84222325;
for (auto &v : *this)
- current = current * 31 + hb_hash (v);
+ {
+ current = current ^ hb_hash (v);
+ current = current * 16777619;
+ }
return current;
}
@@ -322,6 +351,7 @@ struct hb_sorted_array_t :
HB_ITER_USING (iter_base_t);
static constexpr bool is_random_access_iterator = true;
static constexpr bool is_sorted_iterator = true;
+ static constexpr bool has_fast_len = true;
hb_sorted_array_t () = default;
hb_sorted_array_t (const hb_sorted_array_t&) = default;
@@ -449,41 +479,21 @@ inline bool hb_array_t<const unsigned char>::operator == (const hb_array_t<const
/* Specialize hash() for byte arrays. */
+#ifndef HB_OPTIMIZE_SIZE_MORE
template <>
inline uint32_t hb_array_t<const char>::hash () const
{
- uint32_t current = 0;
- unsigned i = 0;
-
-#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
- ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__))
- struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
- for (; i + 4 <= this->length; i += 4)
- current = current * 31 + hb_hash ((uint32_t) ((packed_uint32_t *) &this->arrayZ[i])->v);
-#endif
-
- for (; i < this->length; i++)
- current = current * 31 + hb_hash (this->arrayZ[i]);
- return current;
+ // https://github.com/harfbuzz/harfbuzz/pull/4228
+ return fasthash32(arrayZ, length, 0xf437ffe6 /* magic? */);
}
template <>
inline uint32_t hb_array_t<const unsigned char>::hash () const
{
- uint32_t current = 0;
- unsigned i = 0;
-
-#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
- ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__))
- struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
- for (; i + 4 <= this->length; i += 4)
- current = current * 31 + hb_hash ((uint32_t) ((packed_uint32_t *) &this->arrayZ[i])->v);
-#endif
-
- for (; i < this->length; i++)
- current = current * 31 + hb_hash (this->arrayZ[i]);
- return current;
+ // https://github.com/harfbuzz/harfbuzz/pull/4228
+ return fasthash32(arrayZ, length, 0xf437ffe6 /* magic? */);
}
+#endif
typedef hb_array_t<const char> hb_bytes_t;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-atomic.hh b/src/3rdparty/harfbuzz-ng/src/hb-atomic.hh
index a6283de140..366fb32b7d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-atomic.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-atomic.hh
@@ -118,12 +118,12 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
*/
#ifndef _hb_compiler_memory_r_barrier
#if defined(__ATOMIC_ACQUIRE) // gcc-like
-#define _hb_compiler_memory_r_barrier() asm volatile("": : :"memory")
+static inline void _hb_compiler_memory_r_barrier () { asm volatile("": : :"memory"); }
#elif !defined(_MSC_VER)
#include <atomic>
#define _hb_compiler_memory_r_barrier() std::atomic_signal_fence (std::memory_order_acquire)
#else
-#define _hb_compiler_memory_r_barrier() do {} while (0)
+static inline void _hb_compiler_memory_r_barrier () {}
#endif
#endif
@@ -204,6 +204,7 @@ struct hb_atomic_ptr_t
hb_atomic_ptr_t () = default;
constexpr hb_atomic_ptr_t (T* v) : v (v) {}
+ hb_atomic_ptr_t (const hb_atomic_ptr_t &other) = delete;
void init (T* v_ = nullptr) { set_relaxed (v_); }
void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
@@ -217,5 +218,11 @@ struct hb_atomic_ptr_t
T *v = nullptr;
};
+static inline bool hb_barrier ()
+{
+ _hb_compiler_memory_r_barrier ();
+ return true;
+}
+
#endif /* HB_ATOMIC_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-bimap.hh b/src/3rdparty/harfbuzz-ng/src/hb-bimap.hh
index 8e8c988716..f541472544 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-bimap.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-bimap.hh
@@ -39,10 +39,10 @@ struct hb_bimap_t
back_map.reset ();
}
- void resize (unsigned pop)
+ void alloc (unsigned pop)
{
- forw_map.resize (pop);
- back_map.resize (pop);
+ forw_map.alloc (pop);
+ back_map.alloc (pop);
}
bool in_error () const { return forw_map.in_error () || back_map.in_error (); }
@@ -86,11 +86,38 @@ struct hb_bimap_t
protected:
hb_map_t forw_map;
hb_map_t back_map;
+
+ public:
+ auto keys () const HB_AUTO_RETURN (+ forw_map.keys())
+ auto values () const HB_AUTO_RETURN (+ forw_map.values())
+ auto iter () const HB_AUTO_RETURN (+ forw_map.iter())
};
-/* Inremental bimap: only lhs is given, rhs is incrementally assigned */
-struct hb_inc_bimap_t : hb_bimap_t
+/* Incremental bimap: only lhs is given, rhs is incrementally assigned */
+struct hb_inc_bimap_t
{
+ bool in_error () const { return forw_map.in_error () || back_map.in_error (); }
+
+ unsigned int get_population () const { return forw_map.get_population (); }
+
+ void reset ()
+ {
+ forw_map.reset ();
+ back_map.reset ();
+ }
+
+ void alloc (unsigned pop)
+ {
+ forw_map.alloc (pop);
+ back_map.alloc (pop);
+ }
+
+ void clear ()
+ {
+ forw_map.clear ();
+ back_map.resize (0);
+ }
+
/* Add a mapping from lhs to rhs with a unique value if lhs is unknown.
* Return the rhs value as the result.
*/
@@ -99,29 +126,42 @@ struct hb_inc_bimap_t : hb_bimap_t
hb_codepoint_t rhs = forw_map[lhs];
if (rhs == HB_MAP_VALUE_INVALID)
{
- rhs = next_value++;
- set (lhs, rhs);
+ rhs = back_map.length;
+ forw_map.set (lhs, rhs);
+ back_map.push (lhs);
}
return rhs;
}
hb_codepoint_t skip ()
- { return next_value++; }
+ {
+ hb_codepoint_t start = back_map.length;
+ back_map.push (HB_MAP_VALUE_INVALID);
+ return start;
+ }
+
+ hb_codepoint_t skip (unsigned count)
+ {
+ hb_codepoint_t start = back_map.length;
+ back_map.alloc (back_map.length + count);
+ for (unsigned i = 0; i < count; i++)
+ back_map.push (HB_MAP_VALUE_INVALID);
+ return start;
+ }
hb_codepoint_t get_next_value () const
- { return next_value; }
+ { return back_map.length; }
void add_set (const hb_set_t *set)
{
- hb_codepoint_t i = HB_SET_VALUE_INVALID;
- while (hb_set_next (set, &i)) add (i);
+ for (auto i : *set) add (i);
}
/* Create an identity map. */
bool identity (unsigned int size)
{
clear ();
- for (hb_codepoint_t i = 0; i < size; i++) set (i, i);
+ for (hb_codepoint_t i = 0; i < size; i++) add (i);
return !in_error ();
}
@@ -136,20 +176,30 @@ struct hb_inc_bimap_t : hb_bimap_t
{
hb_codepoint_t count = get_population ();
hb_vector_t <hb_codepoint_t> work;
- work.resize (count);
+ if (unlikely (!work.resize (count, false))) return;
for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
- work[rhs] = back_map[rhs];
+ work.arrayZ[rhs] = back_map[rhs];
work.qsort (cmp_id);
clear ();
for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
- set (work[rhs], rhs);
+ add (work.arrayZ[rhs]);
}
+ hb_codepoint_t get (hb_codepoint_t lhs) const { return forw_map.get (lhs); }
+ hb_codepoint_t backward (hb_codepoint_t rhs) const { return back_map[rhs]; }
+
+ hb_codepoint_t operator [] (hb_codepoint_t lhs) const { return get (lhs); }
+ bool has (hb_codepoint_t lhs) const { return forw_map.has (lhs); }
+
protected:
- unsigned int next_value = 0;
+ hb_map_t forw_map;
+ hb_vector_t<hb_codepoint_t> back_map;
+
+ public:
+ auto keys () const HB_AUTO_RETURN (+ back_map.iter())
};
#endif /* HB_BIMAP_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-bit-page.hh b/src/3rdparty/harfbuzz-ng/src/hb-bit-page.hh
index 9b027ac590..869c678957 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-bit-page.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-bit-page.hh
@@ -89,14 +89,18 @@ struct hb_vector_size_t
struct hb_bit_page_t
{
- void init0 () { v.init0 (); }
- void init1 () { v.init1 (); }
+ void init0 () { v.init0 (); population = 0; }
+ void init1 () { v.init1 (); population = PAGE_BITS; }
+
+ void dirty () { population = UINT_MAX; }
static inline constexpr unsigned len ()
{ return ARRAY_LENGTH_CONST (v); }
+ operator bool () const { return !is_empty (); }
bool is_empty () const
{
+ if (has_population ()) return !population;
return
+ hb_iter (v)
| hb_none
@@ -104,14 +108,11 @@ struct hb_bit_page_t
}
uint32_t hash () const
{
- return
- + hb_iter (v)
- | hb_reduce ([] (uint32_t h, const elt_t &_) { return h * 31 + hb_hash (_); }, (uint32_t) 0u)
- ;
+ return hb_bytes_t ((const char *) &v, sizeof (v)).hash ();
}
- void add (hb_codepoint_t g) { elt (g) |= mask (g); }
- void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
+ void add (hb_codepoint_t g) { elt (g) |= mask (g); dirty (); }
+ void del (hb_codepoint_t g) { elt (g) &= ~mask (g); dirty (); }
void set (hb_codepoint_t g, bool value) { if (value) add (g); else del (g); }
bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
@@ -123,20 +124,21 @@ struct hb_bit_page_t
*la |= (mask (b) << 1) - mask(a);
else
{
- *la |= ~(mask (a) - 1);
+ *la |= ~(mask (a) - 1llu);
la++;
hb_memset (la, 0xff, (char *) lb - (char *) la);
- *lb |= ((mask (b) << 1) - 1);
+ *lb |= ((mask (b) << 1) - 1llu);
}
+ dirty ();
}
void del_range (hb_codepoint_t a, hb_codepoint_t b)
{
elt_t *la = &elt (a);
elt_t *lb = &elt (b);
if (la == lb)
- *la &= ~((mask (b) << 1) - mask(a));
+ *la &= ~((mask (b) << 1llu) - mask(a));
else
{
*la &= mask (a) - 1;
@@ -144,8 +146,9 @@ struct hb_bit_page_t
hb_memset (la, 0, (char *) lb - (char *) la);
- *lb &= ~((mask (b) << 1) - 1);
+ *lb &= ~((mask (b) << 1) - 1llu);
}
+ dirty ();
}
void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v)
{ if (v) add_range (a, b); else del_range (a, b); }
@@ -216,6 +219,7 @@ struct hb_bit_page_t
return count;
}
+ bool operator == (const hb_bit_page_t &other) const { return is_equal (other); }
bool is_equal (const hb_bit_page_t &other) const
{
for (unsigned i = 0; i < len (); i++)
@@ -223,20 +227,28 @@ struct hb_bit_page_t
return false;
return true;
}
+ bool operator <= (const hb_bit_page_t &larger_page) const { return is_subset (larger_page); }
bool is_subset (const hb_bit_page_t &larger_page) const
{
+ if (has_population () && larger_page.has_population () &&
+ population > larger_page.population)
+ return false;
+
for (unsigned i = 0; i < len (); i++)
if (~larger_page.v[i] & v[i])
return false;
return true;
}
+ bool has_population () const { return population != UINT_MAX; }
unsigned int get_population () const
{
- return
+ if (has_population ()) return population;
+ population =
+ hb_iter (v)
| hb_reduce ([] (unsigned pop, const elt_t &_) { return pop + hb_popcount (_); }, 0u)
;
+ return population;
}
bool next (hb_codepoint_t *codepoint) const
@@ -332,9 +344,9 @@ struct hb_bit_page_t
const elt_t& elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; }
static constexpr elt_t mask (hb_codepoint_t g) { return elt_t (1) << (g & ELT_MASK); }
+ mutable unsigned population;
vector_t v;
};
-static_assert (hb_bit_page_t::PAGE_BITS == sizeof (hb_bit_page_t) * 8, "");
#endif /* HB_BIT_PAGE_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh b/src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh
index 1eb1b1c209..d5d1326d9f 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-bit-set-invertible.hh
@@ -39,10 +39,10 @@ struct hb_bit_set_invertible_t
hb_bit_set_invertible_t () = default;
hb_bit_set_invertible_t (const hb_bit_set_invertible_t& o) = default;
- hb_bit_set_invertible_t (hb_bit_set_invertible_t&& other) : hb_bit_set_invertible_t () { hb_swap (*this, other); }
+ hb_bit_set_invertible_t (hb_bit_set_invertible_t&& other) noexcept : hb_bit_set_invertible_t () { hb_swap (*this, other); }
hb_bit_set_invertible_t& operator= (const hb_bit_set_invertible_t& o) = default;
- hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& other) { hb_swap (*this, other); return *this; }
- friend void swap (hb_bit_set_invertible_t &a, hb_bit_set_invertible_t &b)
+ hb_bit_set_invertible_t& operator= (hb_bit_set_invertible_t&& other) noexcept { hb_swap (*this, other); return *this; }
+ friend void swap (hb_bit_set_invertible_t &a, hb_bit_set_invertible_t &b) noexcept
{
if (likely (!a.s.successful || !b.s.successful))
return;
@@ -136,7 +136,7 @@ struct hb_bit_set_invertible_t
/* Sink interface. */
hb_bit_set_invertible_t& operator << (hb_codepoint_t v)
{ add (v); return *this; }
- hb_bit_set_invertible_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
+ hb_bit_set_invertible_t& operator << (const hb_codepoint_pair_t& range)
{ add_range (range.first, range.second); return *this; }
bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
@@ -162,7 +162,7 @@ struct hb_bit_set_invertible_t
auto it1 = iter ();
auto it2 = other.iter ();
return hb_all (+ hb_zip (it1, it2)
- | hb_map ([](hb_pair_t<hb_codepoint_t, hb_codepoint_t> _) { return _.first == _.second; }));
+ | hb_map ([](hb_codepoint_pair_t _) { return _.first == _.second; }));
}
}
@@ -345,6 +345,7 @@ struct hb_bit_set_invertible_t
struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
{
static constexpr bool is_sorted_iterator = true;
+ static constexpr bool has_fast_len = true;
iter_t (const hb_bit_set_invertible_t &s_ = Null (hb_bit_set_invertible_t),
bool init = true) : s (&s_), v (INVALID), l(0)
{
@@ -358,12 +359,12 @@ struct hb_bit_set_invertible_t
typedef hb_codepoint_t __item_t__;
hb_codepoint_t __item__ () const { return v; }
bool __more__ () const { return v != INVALID; }
- void __next__ () { s->next (&v); if (l) l--; }
- void __prev__ () { s->previous (&v); }
+ void __next__ () { s->next (&v); if (likely (l)) l--; }
+ void __prev__ () { s->previous (&v); l++; }
unsigned __len__ () const { return l; }
iter_t end () const { return iter_t (*s, false); }
bool operator != (const iter_t& o) const
- { return s != o.s || v != o.v; }
+ { return v != o.v || s != o.s; }
protected:
const hb_bit_set_invertible_t *s;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh b/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh
index 475b07b810..5f4c6f0afe 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-bit-set.hh
@@ -30,7 +30,6 @@
#include "hb.hh"
#include "hb-bit-page.hh"
-#include "hb-machinery.hh"
struct hb_bit_set_t
@@ -39,10 +38,10 @@ struct hb_bit_set_t
~hb_bit_set_t () = default;
hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other, true); }
- hb_bit_set_t ( hb_bit_set_t&& other) : hb_bit_set_t () { hb_swap (*this, other); }
+ hb_bit_set_t ( hb_bit_set_t&& other) noexcept : hb_bit_set_t () { hb_swap (*this, other); }
hb_bit_set_t& operator= (const hb_bit_set_t& other) { set (other); return *this; }
- hb_bit_set_t& operator= (hb_bit_set_t&& other) { hb_swap (*this, other); return *this; }
- friend void swap (hb_bit_set_t &a, hb_bit_set_t &b)
+ hb_bit_set_t& operator= (hb_bit_set_t&& other) noexcept { hb_swap (*this, other); return *this; }
+ friend void swap (hb_bit_set_t &a, hb_bit_set_t &b) noexcept
{
if (likely (!a.successful || !b.successful))
return;
@@ -134,7 +133,11 @@ struct hb_bit_set_t
{
uint32_t h = 0;
for (auto &map : page_map)
- h = h * 31 + hb_hash (map.major) + hb_hash (pages[map.index]);
+ {
+ auto &page = pages.arrayZ[map.index];
+ if (unlikely (page.is_empty ())) continue;
+ h = h * 31 + hb_hash (map.major) + hb_hash (page);
+ }
return h;
}
@@ -179,6 +182,16 @@ struct hb_bit_set_t
return true;
}
+ /* Duplicated here from hb-machinery.hh to avoid including it. */
+ template<typename Type>
+ static inline const Type& StructAtOffsetUnaligned(const void *P, unsigned int offset)
+ {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-align"
+ return * reinterpret_cast<const Type*> ((const char *) P + offset);
+#pragma GCC diagnostic pop
+ }
+
template <typename T>
void set_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T))
{
@@ -194,7 +207,7 @@ struct hb_bit_set_t
unsigned int end = major_start (m + 1);
do
{
- if (v || page) /* The v check is to optimize out the page check if v is true. */
+ if (g != INVALID && (v || page)) /* The v check is to optimize out the page check if v is true. */
page->set (g, v);
array = &StructAtOffsetUnaligned<T> (array, stride);
@@ -238,7 +251,7 @@ struct hb_bit_set_t
if (g < last_g) return false;
last_g = g;
- if (v || page) /* The v check is to optimize out the page check if v is true. */
+ if (g != INVALID && (v || page)) /* The v check is to optimize out the page check if v is true. */
page->add (g);
array = &StructAtOffsetUnaligned<T> (array, stride);
@@ -342,7 +355,7 @@ struct hb_bit_set_t
/* Sink interface. */
hb_bit_set_t& operator << (hb_codepoint_t v)
{ add (v); return *this; }
- hb_bit_set_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
+ hb_bit_set_t& operator << (const hb_codepoint_pair_t& range)
{ add_range (range.first, range.second); return *this; }
bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
@@ -402,7 +415,6 @@ struct hb_bit_set_t
uint32_t spm = page_map[spi].major;
uint32_t lpm = larger_set.page_map[lpi].major;
auto sp = page_at (spi);
- auto lp = larger_set.page_at (lpi);
if (spm < lpm && !sp.is_empty ())
return false;
@@ -410,6 +422,7 @@ struct hb_bit_set_t
if (lpm < spm)
continue;
+ auto lp = larger_set.page_at (lpi);
if (!sp.is_subset (lp))
return false;
@@ -549,6 +562,7 @@ struct hb_bit_set_t
count--;
page_map.arrayZ[count] = page_map.arrayZ[a];
page_at (count).v = op (page_at (a).v, other.page_at (b).v);
+ page_at (count).dirty ();
}
else if (page_map.arrayZ[a - 1].major > other.page_map.arrayZ[b - 1].major)
{
@@ -567,7 +581,7 @@ struct hb_bit_set_t
count--;
page_map.arrayZ[count].major = other.page_map.arrayZ[b].major;
page_map.arrayZ[count].index = next_page++;
- page_at (count).v = other.page_at (b).v;
+ page_at (count) = other.page_at (b);
}
}
}
@@ -585,7 +599,7 @@ struct hb_bit_set_t
count--;
page_map.arrayZ[count].major = other.page_map.arrayZ[b].major;
page_map.arrayZ[count].index = next_page++;
- page_at (count).v = other.page_at (b).v;
+ page_at (count) = other.page_at (b);
}
assert (!count);
resize (newCount);
@@ -623,6 +637,7 @@ struct hb_bit_set_t
*codepoint = INVALID;
return false;
}
+ last_page_lookup = i;
}
const auto* pages_array = pages.arrayZ;
@@ -632,7 +647,6 @@ struct hb_bit_set_t
if (pages_array[current.index].next (codepoint))
{
*codepoint += current.major * page_t::PAGE_BITS;
- last_page_lookup = i;
return true;
}
i++;
@@ -649,7 +663,6 @@ struct hb_bit_set_t
return true;
}
}
- last_page_lookup = 0;
*codepoint = INVALID;
return false;
}
@@ -863,6 +876,7 @@ struct hb_bit_set_t
struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
{
static constexpr bool is_sorted_iterator = true;
+ static constexpr bool has_fast_len = true;
iter_t (const hb_bit_set_t &s_ = Null (hb_bit_set_t),
bool init = true) : s (&s_), v (INVALID), l(0)
{
@@ -899,7 +913,7 @@ struct hb_bit_set_t
/* The extra page_map length is necessary; can't just rely on vector here,
* since the next check would be tricked because a null page also has
- * major==0, which we can't distinguish from an actualy major==0 page... */
+ * major==0, which we can't distinguish from an actually major==0 page... */
unsigned i = last_page_lookup;
if (likely (i < page_map.length))
{
@@ -921,7 +935,7 @@ struct hb_bit_set_t
memmove (page_map.arrayZ + i + 1,
page_map.arrayZ + i,
(page_map.length - 1 - i) * page_map.item_size);
- page_map[i] = map;
+ page_map.arrayZ[i] = map;
}
last_page_lookup = i;
@@ -933,7 +947,7 @@ struct hb_bit_set_t
/* The extra page_map length is necessary; can't just rely on vector here,
* since the next check would be tricked because a null page also has
- * major==0, which we can't distinguish from an actualy major==0 page... */
+ * major==0, which we can't distinguish from an actually major==0 page... */
unsigned i = last_page_lookup;
if (likely (i < page_map.length))
{
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-blob.cc b/src/3rdparty/harfbuzz-ng/src/hb-blob.cc
index 265effba03..873d9b257a 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-blob.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-blob.cc
@@ -598,6 +598,11 @@ _open_resource_fork (const char *file_name, hb_mapped_file_t *file)
* Creates a new blob containing the data from the
* specified binary font file.
*
+ * The filename is passed directly to the system on all platforms,
+ * except on Windows, where the filename is interpreted as UTF-8.
+ * Only if the filename is not valid UTF-8, it will be interpreted
+ * according to the system codepage.
+ *
* Returns: An #hb_blob_t pointer with the content of the file,
* or hb_blob_get_empty() if failed.
*
@@ -617,6 +622,11 @@ hb_blob_create_from_file (const char *file_name)
* Creates a new blob containing the data from the
* specified binary font file.
*
+ * The filename is passed directly to the system on all platforms,
+ * except on Windows, where the filename is interpreted as UTF-8.
+ * Only if the filename is not valid UTF-8, it will be interpreted
+ * according to the system codepage.
+ *
* Returns: An #hb_blob_t pointer with the content of the file,
* or `NULL` if failed.
*
@@ -672,10 +682,19 @@ fail_without_close:
if (unlikely (!file)) return nullptr;
HANDLE fd;
+ int conversion;
unsigned int size = strlen (file_name) + 1;
wchar_t * wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size);
if (unlikely (!wchar_file_name)) goto fail_without_close;
- mbstowcs (wchar_file_name, file_name, size);
+
+ /* Assume file name is given in UTF-8 encoding */
+ conversion = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, file_name, -1, wchar_file_name, size);
+ if (conversion <= 0)
+ {
+ /* Conversion failed due to invalid UTF-8 characters,
+ Repeat conversion based on system code page */
+ mbstowcs(wchar_file_name, file_name, size);
+ }
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
{
CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 };
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-blob.h b/src/3rdparty/harfbuzz-ng/src/hb-blob.h
index 4eb42314da..db50067e16 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-blob.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-blob.h
@@ -63,7 +63,7 @@ HB_BEGIN_DECLS
* HarfBuzz and doing that just once (no reuse!),
*
* - If the font is mmap()ed, it's okay to use
- * @HB_MEMORY_READONLY_MAY_MAKE_WRITABLE, however, using that mode
+ * @HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, however, using that mode
* correctly is very tricky. Use @HB_MEMORY_MODE_READONLY instead.
**/
typedef enum {
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-json.hh b/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-json.hh
index 004a9fb8b7..1deaaafd87 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-json.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-json.hh
@@ -32,7 +32,7 @@
#include "hb.hh"
-#line 33 "hb-buffer-deserialize-json.hh"
+#line 36 "hb-buffer-deserialize-json.hh"
static const unsigned char _deserialize_json_trans_keys[] = {
0u, 0u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u,
48u, 57u, 9u, 125u, 9u, 125u, 9u, 93u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u,
@@ -555,12 +555,12 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer,
hb_glyph_info_t info = {0};
hb_glyph_position_t pos = {0};
-#line 552 "hb-buffer-deserialize-json.hh"
+#line 559 "hb-buffer-deserialize-json.hh"
{
cs = deserialize_json_start;
}
-#line 555 "hb-buffer-deserialize-json.hh"
+#line 564 "hb-buffer-deserialize-json.hh"
{
int _slen;
int _trans;
@@ -772,7 +772,7 @@ _resume:
*end_ptr = p;
}
break;
-#line 733 "hb-buffer-deserialize-json.hh"
+#line 776 "hb-buffer-deserialize-json.hh"
}
_again:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-text-unicode.hh b/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-text-unicode.hh
index 8ca73bf25f..a8cdf67e73 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-text-unicode.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer-deserialize-text-unicode.hh
@@ -32,7 +32,7 @@
#include "hb.hh"
-#line 33 "hb-buffer-deserialize-text-unicode.hh"
+#line 36 "hb-buffer-deserialize-text-unicode.hh"
static const unsigned char _deserialize_text_unicode_trans_keys[] = {
0u, 0u, 9u, 117u, 43u, 102u, 48u, 102u, 48u, 57u, 9u, 124u, 9u, 124u, 9u, 124u,
9u, 124u, 0
@@ -197,12 +197,12 @@ _hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
hb_glyph_info_t info = {0};
const hb_glyph_position_t pos = {0};
-#line 194 "hb-buffer-deserialize-text-unicode.hh"
+#line 201 "hb-buffer-deserialize-text-unicode.hh"
{
cs = deserialize_text_unicode_start;
}
-#line 197 "hb-buffer-deserialize-text-unicode.hh"
+#line 206 "hb-buffer-deserialize-text-unicode.hh"
{
int _slen;
int _trans;
@@ -269,7 +269,7 @@ _resume:
*end_ptr = p;
}
break;
-#line 256 "hb-buffer-deserialize-text-unicode.hh"
+#line 273 "hb-buffer-deserialize-text-unicode.hh"
}
_again:
@@ -307,7 +307,7 @@ _again:
*end_ptr = p;
}
break;
-#line 289 "hb-buffer-deserialize-text-unicode.hh"
+#line 311 "hb-buffer-deserialize-text-unicode.hh"
}
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc b/src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc
index f111b2d8dc..671d6eda8c 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer-verify.cc
@@ -149,7 +149,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
}
assert (text_start < text_end);
- if (0)
+ if (false)
printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end);
hb_buffer_clear_contents (fragment);
@@ -162,14 +162,8 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
hb_buffer_set_flags (fragment, flags);
hb_buffer_append (fragment, text_buffer, text_start, text_end);
- if (!hb_shape_full (font, fragment, features, num_features, shapers))
- {
- buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment.");
- hb_buffer_destroy (reconstruction);
- hb_buffer_destroy (fragment);
- return false;
- }
- else if (!fragment->successful || fragment->shaping_failed)
+ if (!hb_shape_full (font, fragment, features, num_features, shapers) ||
+ fragment->successful || fragment->shaping_failed)
{
hb_buffer_destroy (reconstruction);
hb_buffer_destroy (fragment);
@@ -185,15 +179,18 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer,
}
bool ret = true;
- hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
- if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH)
+ if (likely (reconstruction->successful))
{
- buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break test failed.");
- ret = false;
+ hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
+ if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH)
+ {
+ buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break test failed.");
+ ret = false;
- /* Return the reconstructed result instead so it can be inspected. */
- hb_buffer_set_length (buffer, 0);
- hb_buffer_append (buffer, reconstruction, 0, -1);
+ /* Return the reconstructed result instead so it can be inspected. */
+ hb_buffer_set_length (buffer, 0);
+ hb_buffer_append (buffer, reconstruction, 0, -1);
+ }
}
hb_buffer_destroy (reconstruction);
@@ -291,7 +288,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
}
assert (text_start < text_end);
- if (0)
+ if (false)
printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end);
#if 0
@@ -316,28 +313,13 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
/*
* Shape the two fragment streams.
*/
- if (!hb_shape_full (font, fragments[0], features, num_features, shapers))
- {
- buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment.");
- ret = false;
- goto out;
- }
- else if (!fragments[0]->successful || fragments[0]->shaping_failed)
- {
- ret = true;
- goto out;
- }
- if (!hb_shape_full (font, fragments[1], features, num_features, shapers))
- {
- buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment.");
- ret = false;
+ if (!hb_shape_full (font, fragments[0], features, num_features, shapers) ||
+ !fragments[0]->successful || fragments[0]->shaping_failed)
goto out;
- }
- else if (!fragments[1]->successful || fragments[1]->shaping_failed)
- {
- ret = true;
+
+ if (!hb_shape_full (font, fragments[1], features, num_features, shapers) ||
+ !fragments[1]->successful || fragments[1]->shaping_failed)
goto out;
- }
if (!forward)
{
@@ -377,21 +359,23 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer,
hb_buffer_reverse (reconstruction);
}
- /*
- * Diff results.
- */
- diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
- if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH)
+ if (likely (reconstruction->successful))
{
- buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed.");
- ret = false;
+ /*
+ * Diff results.
+ */
+ diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0);
+ if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH)
+ {
+ buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed.");
+ ret = false;
- /* Return the reconstructed result instead so it can be inspected. */
- hb_buffer_set_length (buffer, 0);
- hb_buffer_append (buffer, reconstruction, 0, -1);
+ /* Return the reconstructed result instead so it can be inspected. */
+ hb_buffer_set_length (buffer, 0);
+ hb_buffer_append (buffer, reconstruction, 0, -1);
+ }
}
-
out:
hb_buffer_destroy (reconstruction);
hb_buffer_destroy (fragments[0]);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc b/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc
index f557ceee56..d621a7cc55 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer.cc
@@ -40,6 +40,11 @@
* Buffers serve a dual role in HarfBuzz; before shaping, they hold
* the input characters that are passed to hb_shape(), and after
* shaping they hold the output glyphs.
+ *
+ * The input buffer is a sequence of Unicode codepoints, with
+ * associated attributes such as direction and script. The output
+ * buffer is a sequence of glyphs, with associated attributes such
+ * as position and cluster.
**/
@@ -263,7 +268,7 @@ hb_buffer_t::similar (const hb_buffer_t &src)
unicode = hb_unicode_funcs_reference (src.unicode);
flags = src.flags;
cluster_level = src.cluster_level;
- replacement = src.invisible;
+ replacement = src.replacement;
invisible = src.invisible;
not_found = src.not_found;
}
@@ -304,6 +309,7 @@ hb_buffer_t::clear ()
deallocate_var_all ();
serial = 0;
+ random_state = 1;
scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
}
@@ -494,12 +500,12 @@ hb_buffer_t::set_masks (hb_mask_t value,
unsigned int cluster_start,
unsigned int cluster_end)
{
- hb_mask_t not_mask = ~mask;
- value &= mask;
-
if (!mask)
return;
+ hb_mask_t not_mask = ~mask;
+ value &= mask;
+
unsigned int count = len;
for (unsigned int i = 0; i < count; i++)
if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
@@ -1322,7 +1328,7 @@ hb_buffer_get_invisible_glyph (const hb_buffer_t *buffer)
* Sets the #hb_codepoint_t that replaces characters not found in
* the font during shaping.
*
- * The not-found glyph defaults to zero, sometimes knows as the
+ * The not-found glyph defaults to zero, sometimes known as the
* ".notdef" glyph. This API allows for differentiating the two.
*
* Since: 3.1.0
@@ -1354,6 +1360,49 @@ hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer)
return buffer->not_found;
}
+/**
+ * hb_buffer_set_random_state:
+ * @buffer: An #hb_buffer_t
+ * @state: the new random state
+ *
+ * Sets the random state of the buffer. The state changes
+ * every time a glyph uses randomness (eg. the `rand`
+ * OpenType feature). This function together with
+ * hb_buffer_get_random_state() allow for transferring
+ * the current random state to a subsequent buffer, to
+ * get better randomness distribution.
+ *
+ * Defaults to 1 and when buffer contents are cleared.
+ * A value of 0 disables randomness during shaping.
+ *
+ * Since: 8.4.0
+ **/
+void
+hb_buffer_set_random_state (hb_buffer_t *buffer,
+ unsigned state)
+{
+ if (unlikely (hb_object_is_immutable (buffer)))
+ return;
+
+ buffer->random_state = state;
+}
+
+/**
+ * hb_buffer_get_random_state:
+ * @buffer: An #hb_buffer_t
+ *
+ * See hb_buffer_set_random_state().
+ *
+ * Return value:
+ * The @buffer random state
+ *
+ * Since: 8.4.0
+ **/
+unsigned
+hb_buffer_get_random_state (const hb_buffer_t *buffer)
+{
+ return buffer->random_state;
+}
/**
* hb_buffer_clear_contents:
@@ -2071,7 +2120,7 @@ hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_g
* hb_buffer_diff:
* @buffer: a buffer.
* @reference: other buffer to compare to.
- * @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepont_t) -1.
+ * @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepoint_t) -1.
* @position_fuzz: allowed absolute difference in position values.
*
* If dottedcircle_glyph is (hb_codepoint_t) -1 then #HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer.h b/src/3rdparty/harfbuzz-ng/src/hb-buffer.h
index bff78543c8..f75fe96b21 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-buffer.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer.h
@@ -99,7 +99,7 @@ typedef struct hb_glyph_info_t {
* layout, by avoiding re-shaping of each line
* after line-breaking, by limiting the
* reshaping to a small piece around the
- * breaking positin only, even if the breaking
+ * breaking position only, even if the breaking
* position carries the
* #HB_GLYPH_FLAG_UNSAFE_TO_BREAK or when
* hyphenation or other text transformation
@@ -487,6 +487,12 @@ hb_buffer_set_not_found_glyph (hb_buffer_t *buffer,
HB_EXTERN hb_codepoint_t
hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer);
+HB_EXTERN void
+hb_buffer_set_random_state (hb_buffer_t *buffer,
+ unsigned state);
+
+HB_EXTERN unsigned
+hb_buffer_get_random_state (const hb_buffer_t *buffer);
/*
* Content API.
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh b/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh
index 5a43cabcb7..0a198722d6 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-buffer.hh
@@ -116,6 +116,7 @@ struct hb_buffer_t
uint8_t allocated_var_bits;
uint8_t serial;
+ uint32_t random_state;
hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
unsigned int max_len; /* Maximum allowed len. */
int max_ops; /* Maximum allowed operations. */
@@ -464,13 +465,16 @@ struct hb_buffer_t
start, end,
true);
}
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
void unsafe_to_concat (unsigned int start = 0, unsigned int end = -1)
{
if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0))
return;
_set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT,
start, end,
- true);
+ false);
}
void unsafe_to_break_from_outbuffer (unsigned int start = 0, unsigned int end = -1)
{
@@ -478,6 +482,9 @@ struct hb_buffer_t
start, end,
true, true);
}
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
void unsafe_to_concat_from_outbuffer (unsigned int start = 0, unsigned int end = -1)
{
if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0))
@@ -493,6 +500,13 @@ struct hb_buffer_t
HB_NODISCARD HB_INTERNAL bool enlarge (unsigned int size);
+ HB_NODISCARD bool resize (unsigned length)
+ {
+ assert (!have_output);
+ if (unlikely (!ensure (length))) return false;
+ len = length;
+ return true;
+ }
HB_NODISCARD bool ensure (unsigned int size)
{ return likely (!size || size < allocated) ? true : enlarge (size); }
@@ -553,7 +567,7 @@ struct hb_buffer_t
bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
{
#ifdef HB_NO_BUFFER_MESSAGE
- return true;
+ return true;
#else
if (likely (!messaging ()))
return true;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cache.hh b/src/3rdparty/harfbuzz-ng/src/hb-cache.hh
index 2e98187b50..6d8a54cf10 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-cache.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-cache.hh
@@ -30,7 +30,19 @@
#include "hb.hh"
-/* Implements a lockfree cache for int->int functions. */
+/* Implements a lockfree cache for int->int functions.
+ *
+ * The cache is a fixed-size array of 16-bit or 32-bit integers.
+ * The key is split into two parts: the cache index and the rest.
+ *
+ * The cache index is used to index into the array. The rest is used
+ * to store the key and the value.
+ *
+ * The value is stored in the least significant bits of the integer.
+ * The key is stored in the most significant bits of the integer.
+ * The key is shifted by cache_bits to the left to make room for the
+ * value.
+ */
template <unsigned int key_bits=16,
unsigned int value_bits=8 + 32 - key_bits,
@@ -50,14 +62,12 @@ struct hb_cache_t
static_assert ((key_bits >= cache_bits), "");
static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), "");
- hb_cache_t () { init (); }
-
- void init () { clear (); }
+ hb_cache_t () { clear (); }
void clear ()
{
- for (unsigned i = 0; i < ARRAY_LENGTH (values); i++)
- values[i] = -1;
+ for (auto &v : values)
+ v = -1;
}
bool get (unsigned int key, unsigned int *value) const
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cairo-utils.cc b/src/3rdparty/harfbuzz-ng/src/hb-cairo-utils.cc
index 3e5118f213..ec1499e861 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-cairo-utils.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-cairo-utils.cc
@@ -1,5 +1,6 @@
/*
* Copyright © 2022 Red Hat, Inc
+ * Copyright © 2021, 2022 Black Foundry
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -32,9 +33,13 @@
#include <cairo.h>
-#define PREALLOCATED_COLOR_STOPS 16
+/* Some routines in this file were ported from BlackRenderer by Black Foundry.
+ * Used by permission to relicense to HarfBuzz license.
+ *
+ * https://github.com/BlackFoundryCom/black-renderer
+ */
-#define _2_M_PIf (2.f * float (M_PI))
+#define PREALLOCATED_COLOR_STOPS 16
typedef struct {
float r, g, b, a;
@@ -75,7 +80,7 @@ hb_cairo_read_blob (void *closure,
if (r->offset + length > size)
return CAIRO_STATUS_READ_ERROR;
- memcpy (data, d + r->offset, length);
+ hb_memcpy (data, d + r->offset, length);
r->offset += length;
return CAIRO_STATUS_SUCCESS;
@@ -518,7 +523,7 @@ _hb_cairo_add_patch (cairo_pattern_t *pattern, hb_cairo_point_t *center, hb_cair
cairo_mesh_pattern_end_patch (pattern);
}
-#define MAX_ANGLE ((float) M_PI / 8.f)
+#define MAX_ANGLE (HB_PI / 8.f)
static void
_hb_cairo_add_sweep_gradient_patches1 (float cx, float cy, float radius,
@@ -601,7 +606,7 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
start_angle, &c,
pattern);
}
- if (end_angle < _2_M_PIf)
+ if (end_angle < HB_2_PI)
{
c.r = hb_color_get_red (stops[n_stops - 1].color) / 255.;
c.g = hb_color_get_green (stops[n_stops - 1].color) / 255.;
@@ -609,7 +614,7 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
c.a = hb_color_get_alpha (stops[n_stops - 1].color) / 255.;
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
end_angle, &c,
- _2_M_PIf, &c,
+ HB_2_PI, &c,
pattern);
}
}
@@ -673,7 +678,7 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
color0 = colors[n_stops-1];
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
0., &color0,
- _2_M_PIf, &color0,
+ HB_2_PI, &color0,
pattern);
goto done;
}
@@ -685,7 +690,7 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
for (pos++; pos < n_stops; pos++)
{
- if (angles[pos] <= _2_M_PIf)
+ if (angles[pos] <= HB_2_PI)
{
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
angles[pos - 1], &colors[pos-1],
@@ -694,11 +699,11 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
}
else
{
- float k = (_2_M_PIf - angles[pos - 1]) / (angles[pos] - angles[pos - 1]);
+ float k = (HB_2_PI - angles[pos - 1]) / (angles[pos] - angles[pos - 1]);
_hb_cairo_interpolate_colors (&colors[pos - 1], &colors[pos], k, &color1);
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
angles[pos - 1], &colors[pos - 1],
- _2_M_PIf, &color1,
+ HB_2_PI, &color1,
pattern);
break;
}
@@ -710,7 +715,7 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
color0 = colors[n_stops - 1];
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
angles[n_stops - 1], &color0,
- _2_M_PIf, &color0,
+ HB_2_PI, &color0,
pattern);
goto done;
}
@@ -758,7 +763,7 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
}
//assert (angles[0] + k * span <= 0 && 0 < angles[n_stops - 1] + k * span);
- span = fabs (span);
+ span = fabsf (span);
for (signed l = k; l < 1000; l++)
{
@@ -794,14 +799,14 @@ _hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
a1, c1,
pattern);
}
- else if (a1 >= _2_M_PIf)
+ else if (a1 >= HB_2_PI)
{
hb_cairo_color_t color;
- float f = (_2_M_PIf - a0)/(a1 - a0);
+ float f = (HB_2_PI - a0)/(a1 - a0);
_hb_cairo_interpolate_colors (c0, c1, f, &color);
_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
a0, c0,
- _2_M_PIf, &color,
+ HB_2_PI, &color,
pattern);
goto done;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cairo.cc b/src/3rdparty/harfbuzz-ng/src/hb-cairo.cc
index f005afd17e..f4f9f54ab3 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-cairo.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-cairo.cc
@@ -166,6 +166,32 @@ hb_cairo_pop_transform (hb_paint_funcs_t *pfuncs HB_UNUSED,
cairo_restore (cr);
}
+static hb_bool_t
+hb_cairo_paint_color_glyph (hb_paint_funcs_t *pfuncs HB_UNUSED,
+ void *paint_data,
+ hb_codepoint_t glyph,
+ hb_font_t *font,
+ void *user_data HB_UNUSED)
+{
+ hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+ cairo_t *cr = c->cr;
+
+ cairo_save (cr);
+
+ hb_position_t x_scale, y_scale;
+ hb_font_get_scale (font, &x_scale, &y_scale);
+ cairo_scale (cr, x_scale, y_scale);
+
+ cairo_glyph_t cairo_glyph = { glyph, 0, 0 };
+ cairo_set_scaled_font (cr, c->scaled_font);
+ cairo_set_font_size (cr, 1);
+ cairo_show_glyphs (cr, &cairo_glyph, 1);
+
+ cairo_restore (cr);
+
+ return true;
+}
+
static void
hb_cairo_push_clip_glyph (hb_paint_funcs_t *pfuncs HB_UNUSED,
void *paint_data,
@@ -397,6 +423,7 @@ static struct hb_cairo_paint_funcs_lazy_loader_t : hb_paint_funcs_lazy_loader_t<
hb_paint_funcs_set_push_transform_func (funcs, hb_cairo_push_transform, nullptr, nullptr);
hb_paint_funcs_set_pop_transform_func (funcs, hb_cairo_pop_transform, nullptr, nullptr);
+ hb_paint_funcs_set_color_glyph_func (funcs, hb_cairo_paint_color_glyph, nullptr, nullptr);
hb_paint_funcs_set_push_clip_glyph_func (funcs, hb_cairo_push_clip_glyph, nullptr, nullptr);
hb_paint_funcs_set_push_clip_rectangle_func (funcs, hb_cairo_push_clip_rectangle, nullptr, nullptr);
hb_paint_funcs_set_pop_clip_func (funcs, hb_cairo_pop_clip, nullptr, nullptr);
@@ -956,7 +983,7 @@ hb_cairo_glyphs_from_buffer (hb_buffer_t *buffer,
if (clusters && *num_clusters && utf8)
{
- memset ((void *) *clusters, 0, *num_clusters * sizeof ((*clusters)[0]));
+ hb_memset ((void *) *clusters, 0, *num_clusters * sizeof ((*clusters)[0]));
hb_bool_t backward = HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (buffer));
*cluster_flags = backward ? CAIRO_TEXT_CLUSTER_FLAG_BACKWARD : (cairo_text_cluster_flags_t) 0;
unsigned int cluster = 0;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-common.hh
index 949bfebf9b..1d1f10f2bf 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-common.hh
@@ -26,6 +26,8 @@
#ifndef HB_CFF_INTERP_COMMON_HH
#define HB_CFF_INTERP_COMMON_HH
+extern HB_INTERNAL const unsigned char *endchar_str;
+
namespace CFF {
using namespace OT;
@@ -336,8 +338,6 @@ struct byte_str_ref_t
hb_ubytes_t str;
};
-using byte_str_array_t = hb_vector_t<hb_ubytes_t>;
-
/* stack */
template <typename ELEM, int LIMIT>
struct cff_stack_t
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-cs-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-cs-common.hh
index f40be51f0d..28a777eb0d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-cs-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-cs-common.hh
@@ -883,14 +883,12 @@ struct cs_interpreter_t : interpreter_t<ENV>
unsigned max_ops = HB_CFF_MAX_OPS;
for (;;) {
- if (unlikely (!--max_ops))
+ OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
+ if (unlikely (SUPER::env.in_error () || !--max_ops))
{
SUPER::env.set_error ();
- break;
- }
- OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
- if (unlikely (SUPER::env.in_error ()))
return false;
+ }
if (SUPER::env.is_endchar ())
break;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-dict-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-dict-common.hh
index 53226b227e..a08b10b5ff 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-dict-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-cff-interp-dict-common.hh
@@ -54,8 +54,8 @@ struct top_dict_values_t : dict_values_t<OPSTR>
}
void fini () { dict_values_t<OPSTR>::fini (); }
- unsigned int charStringsOffset;
- unsigned int FDArrayOffset;
+ int charStringsOffset;
+ int FDArrayOffset;
};
struct dict_opset_t : opset_t<number_t>
@@ -157,11 +157,11 @@ struct top_dict_opset_t : dict_opset_t
{
switch (op) {
case OpCode_CharStrings:
- dictval.charStringsOffset = env.argStack.pop_uint ();
+ dictval.charStringsOffset = env.argStack.pop_int ();
env.clear_args ();
break;
case OpCode_FDArray:
- dictval.FDArrayOffset = env.argStack.pop_uint ();
+ dictval.FDArrayOffset = env.argStack.pop_int ();
env.clear_args ();
break;
case OpCode_FontMatrix:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh b/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh
index 915b10cf39..55b1d3bf8d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-cff2-interp-cs.hh
@@ -168,7 +168,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
protected:
const int *coords;
unsigned int num_coords;
- const CFF2VariationStore *varStore;
+ const CFF2ItemVariationStore *varStore;
unsigned int region_count;
unsigned int ivs;
hb_vector_t<float> scalars;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-common.cc b/src/3rdparty/harfbuzz-ng/src/hb-common.cc
index c9a40295a3..4b8bae4422 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-common.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-common.cc
@@ -632,6 +632,7 @@ hb_script_get_horizontal_direction (hb_script_t script)
case HB_SCRIPT_OLD_HUNGARIAN:
case HB_SCRIPT_OLD_ITALIC:
case HB_SCRIPT_RUNIC:
+ case HB_SCRIPT_TIFINAGH:
return HB_DIRECTION_INVALID;
}
@@ -814,7 +815,7 @@ parse_tag (const char **pp, const char *end, hb_tag_t *tag)
}
const char *p = *pp;
- while (*pp < end && (ISALNUM(**pp) || **pp == '_'))
+ while (*pp < end && (**pp != ' ' && **pp != '=' && **pp != '[' && **pp != quote))
(*pp)++;
if (p == *pp || *pp - p > 4)
@@ -995,7 +996,7 @@ hb_feature_to_string (hb_feature_t *feature,
if (feature->value > 1)
{
s[len++] = '=';
- len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
+ len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%" PRIu32, feature->value));
}
assert (len < ARRAY_LENGTH (s));
len = hb_min (len, size - 1);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-common.h b/src/3rdparty/harfbuzz-ng/src/hb-common.h
index a5da4e76a3..533de91562 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-common.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-common.h
@@ -47,14 +47,10 @@
# endif /* !__cplusplus */
#endif
-#if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \
- defined (_sgi) || defined (__sun) || defined (sun) || \
- defined (__digital__) || defined (__HP_cc)
-# include <inttypes.h>
-#elif defined (_AIX)
+#if defined (_AIX)
# include <sys/inttypes.h>
#elif defined (_MSC_VER) && _MSC_VER < 1600
-/* VS 2010 (_MSC_VER 1600) has stdint.h */
+/* VS 2010 (_MSC_VER 1600) has stdint.h */
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
@@ -63,10 +59,11 @@ typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
-#elif defined (__KERNEL__)
-# include <linux/types.h>
-#else
+#elif defined (_MSC_VER) && _MSC_VER < 1800
+/* VS 2013 (_MSC_VER 1800) has inttypes.h */
# include <stdint.h>
+#else
+# include <inttypes.h>
#endif
#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
@@ -104,6 +101,16 @@ typedef int hb_bool_t;
*
**/
typedef uint32_t hb_codepoint_t;
+
+/**
+ * HB_CODEPOINT_INVALID:
+ *
+ * Unused #hb_codepoint_t value.
+ *
+ * Since: 8.0.0
+ */
+#define HB_CODEPOINT_INVALID ((hb_codepoint_t) -1)
+
/**
* hb_position_t:
*
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-config.hh b/src/3rdparty/harfbuzz-ng/src/hb-config.hh
index 047518b87d..816c55c7d3 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-config.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-config.hh
@@ -44,14 +44,14 @@
#ifdef HB_TINY
#define HB_LEAN
#define HB_MINI
+#define HB_OPTIMIZE_SIZE
+#define HB_OPTIMIZE_SIZE_MORE
+#define HB_MINIMIZE_MEMORY_USAGE
#define HB_NO_MT
#define HB_NO_UCD_UNASSIGNED
#ifndef NDEBUG
#define NDEBUG
#endif
-#ifndef __OPTIMIZE_SIZE__
-#define __OPTIMIZE_SIZE__
-#endif
#endif
#ifdef HB_LEAN
@@ -97,6 +97,12 @@
#define HB_NO_BORING_EXPANSION
#endif
+#ifdef __OPTIMIZE_SIZE__
+#ifndef HB_OPTIMIZE_SIZE
+#define HB_OPTIMIZE_SIZE
+#endif
+#endif
+
#if defined(HAVE_CONFIG_OVERRIDE_H) || defined(HB_CONFIG_OVERRIDE_H)
#ifndef HB_CONFIG_OVERRIDE_H
#define HB_CONFIG_OVERRIDE_H "config-override.h"
@@ -108,7 +114,8 @@
#ifdef HB_NO_BORING_EXPANSION
#define HB_NO_BEYOND_64K
-#define HB_NO_AVAR2
+#define HB_NO_CUBIC_GLYF
+#define HB_NO_VAR_COMPOSITES
#endif
#ifdef HB_DISABLE_DEPRECATED
@@ -136,6 +143,10 @@
#define HB_NO_SUBSET_CFF
#endif
+#ifdef HB_NO_DRAW
+#define HB_NO_OUTLINE
+#endif
+
#ifdef HB_NO_GETENV
#define HB_NO_UNISCRIBE_BUG_COMPATIBLE
#endif
@@ -171,21 +182,27 @@
#define HB_NO_OT_SHAPER_MYANMAR_ZAWGYI
#endif
-#ifdef NDEBUG
-#ifndef HB_NDEBUG
-#define HB_NDEBUG
-#endif
+#ifdef HB_OPTIMIZE_SIZE_MORE
+#define HB_NO_OT_RULESETS_FAST_PATH
#endif
-#ifdef __OPTIMIZE_SIZE__
-#ifndef HB_OPTIMIZE_SIZE
-#define HB_OPTIMIZE_SIZE
-#endif
+#ifdef HB_MINIMIZE_MEMORY_USAGE
+#define HB_NO_GDEF_CACHE
+#define HB_NO_OT_LAYOUT_LOOKUP_CACHE
+#define HB_NO_OT_FONT_ADVANCE_CACHE
+#define HB_NO_OT_FONT_CMAP_CACHE
#endif
#ifdef HB_OPTIMIZE_SIZE
-#define HB_NO_OT_LAYOUT_LOOKUP_CACHE
+#define HB_OPTIMIZE_SIZE_VAL 1
+#else
+#define HB_OPTIMIZE_SIZE_VAL 0
#endif
+#ifdef HB_MINIMIZE_MEMORY_USAGE
+#define HB_MINIMIZE_MEMORY_USAGE_VAL 1
+#else
+#define HB_MINIMIZE_MEMORY_USAGE_VAL 0
+#endif
#endif /* HB_CONFIG_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-cplusplus.hh b/src/3rdparty/harfbuzz-ng/src/hb-cplusplus.hh
index 531ef1b7c8..a640e192de 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-cplusplus.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-cplusplus.hh
@@ -56,15 +56,15 @@ struct shared_ptr
explicit shared_ptr (T *p = nullptr) : p (p) {}
shared_ptr (const shared_ptr &o) : p (v::reference (o.p)) {}
- shared_ptr (shared_ptr &&o) : p (o.p) { o.p = nullptr; }
+ shared_ptr (shared_ptr &&o) noexcept : p (o.p) { o.p = nullptr; }
shared_ptr& operator = (const shared_ptr &o) { if (p != o.p) { destroy (); p = o.p; reference (); } return *this; }
- shared_ptr& operator = (shared_ptr &&o) { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
+ shared_ptr& operator = (shared_ptr &&o) noexcept { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
~shared_ptr () { v::destroy (p); p = nullptr; }
T* get() const { return p; }
- void swap (shared_ptr &o) { std::swap (p, o.p); }
- friend void swap (shared_ptr &a, shared_ptr &b) { std::swap (a.p, b.p); }
+ void swap (shared_ptr &o) noexcept { std::swap (p, o.p); }
+ friend void swap (shared_ptr &a, shared_ptr &b) noexcept { std::swap (a.p, b.p); }
operator T * () const { return p; }
T& operator * () const { return *get (); }
@@ -98,16 +98,16 @@ struct unique_ptr
explicit unique_ptr (T *p = nullptr) : p (p) {}
unique_ptr (const unique_ptr &o) = delete;
- unique_ptr (unique_ptr &&o) : p (o.p) { o.p = nullptr; }
+ unique_ptr (unique_ptr &&o) noexcept : p (o.p) { o.p = nullptr; }
unique_ptr& operator = (const unique_ptr &o) = delete;
- unique_ptr& operator = (unique_ptr &&o) { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
+ unique_ptr& operator = (unique_ptr &&o) noexcept { v::destroy (p); p = o.p; o.p = nullptr; return *this; }
~unique_ptr () { v::destroy (p); p = nullptr; }
T* get() const { return p; }
T* release () { T* v = p; p = nullptr; return v; }
- void swap (unique_ptr &o) { std::swap (p, o.p); }
- friend void swap (unique_ptr &a, unique_ptr &b) { std::swap (a.p, b.p); }
+ void swap (unique_ptr &o) noexcept { std::swap (p, o.p); }
+ friend void swap (unique_ptr &a, unique_ptr &b) noexcept { std::swap (a.p, b.p); }
operator T * () const { return p; }
T& operator * () const { return *get (); }
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-debug.hh b/src/3rdparty/harfbuzz-ng/src/hb-debug.hh
index efab374646..559db4067e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-debug.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-debug.hh
@@ -265,8 +265,9 @@ static inline void _hb_warn_no_return (bool returned)
}
}
template <>
-/*static*/ inline void _hb_warn_no_return<hb_empty_t> (bool returned HB_UNUSED)
-{}
+/*static*/ inline void _hb_warn_no_return<hb_empty_t> (bool returned HB_UNUSED) {}
+template <>
+/*static*/ inline void _hb_warn_no_return<void> (bool returned HB_UNUSED) {}
template <int max_level, typename ret_t>
struct hb_auto_trace_t
@@ -373,6 +374,10 @@ struct hb_no_trace_t {
#define HB_DEBUG_FT (HB_DEBUG+0)
#endif
+#ifndef HB_DEBUG_JUSTIFY
+#define HB_DEBUG_JUSTIFY (HB_DEBUG+0)
+#endif
+
#ifndef HB_DEBUG_OBJECT
#define HB_DEBUG_OBJECT (HB_DEBUG+0)
#endif
@@ -385,6 +390,10 @@ struct hb_no_trace_t {
#define HB_DEBUG_UNISCRIBE (HB_DEBUG+0)
#endif
+#ifndef HB_DEBUG_WASM
+#define HB_DEBUG_WASM (HB_DEBUG+0)
+#endif
+
/*
* With tracing.
*/
@@ -442,12 +451,26 @@ struct hb_no_trace_t {
#define HB_DEBUG_SUBSET_REPACK (HB_DEBUG+0)
#endif
+#ifndef HB_DEBUG_PAINT
+#define HB_DEBUG_PAINT (HB_DEBUG+0)
+#endif
+#if HB_DEBUG_PAINT
+#define TRACE_PAINT(this) \
+ HB_UNUSED hb_auto_trace_t<HB_DEBUG_PAINT, void> trace \
+ (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+ " ")
+#else
+#define TRACE_PAINT(this) HB_UNUSED hb_no_trace_t<void> trace
+#endif
+
+
#ifndef HB_DEBUG_DISPATCH
#define HB_DEBUG_DISPATCH ( \
HB_DEBUG_APPLY + \
HB_DEBUG_SANITIZE + \
HB_DEBUG_SERIALIZE + \
HB_DEBUG_SUBSET + \
+ HB_DEBUG_PAINT + \
0)
#endif
#if HB_DEBUG_DISPATCH
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-deprecated.h b/src/3rdparty/harfbuzz-ng/src/hb-deprecated.h
index edacfd064c..ad19f9a3e9 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-deprecated.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-deprecated.h
@@ -56,7 +56,7 @@ HB_BEGIN_DECLS
/**
* HB_SCRIPT_CANADIAN_ABORIGINAL:
*
- * Use #HB_SCRIPT_CANADIAN_SYLLABICS instead:
+ * Use #HB_SCRIPT_CANADIAN_SYLLABICS instead.
*
* Deprecated: 0.9.20
*/
@@ -108,6 +108,16 @@ 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);
+/* https://github.com/harfbuzz/harfbuzz/pull/4207 */
+/**
+ * HB_UNICODE_COMBINING_CLASS_CCC133:
+ *
+ * [Tibetan]
+ *
+ * Deprecated: 7.2.0
+ **/
+#define HB_UNICODE_COMBINING_CLASS_CCC133 133
+
/**
* hb_unicode_eastasian_width_func_t:
* @ufuncs: A Unicode-functions structure
@@ -245,8 +255,64 @@ 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_font_get_glyph_shape_func_t:
+ * @font: #hb_font_t to work upon
+ * @font_data: @font user data pointer
+ * @glyph: The glyph ID to query
+ * @draw_funcs: The draw functions to send the shape data to
+ * @draw_data: The data accompanying the draw functions
+ * @user_data: User data pointer passed by the caller
+ *
+ * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
+ *
+ * Since: 4.0.0
+ * Deprecated: 7.0.0: Use #hb_font_draw_glyph_func_t instead
+ **/
+typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data,
+ hb_codepoint_t glyph,
+ hb_draw_funcs_t *draw_funcs, void *draw_data,
+ void *user_data);
+
+/**
+ * hb_font_funcs_set_glyph_shape_func:
+ * @ffuncs: A font-function structure
+ * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): The function to call when @user_data is not needed anymore
+ *
+ * Sets the implementation function for #hb_font_get_glyph_shape_func_t,
+ * which is the same as #hb_font_draw_glyph_func_t.
+ *
+ * Since: 4.0.0
+ * Deprecated: 7.0.0: Use hb_font_funcs_set_draw_glyph_func() instead
+ **/
+HB_DEPRECATED_FOR (hb_font_funcs_set_draw_glyph_func)
+HB_EXTERN void
+hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
+ hb_font_get_glyph_shape_func_t func,
+ void *user_data, hb_destroy_func_t destroy);
+
+HB_DEPRECATED_FOR (hb_font_draw_glyph)
+HB_EXTERN void
+hb_font_get_glyph_shape (hb_font_t *font,
+ hb_codepoint_t glyph,
+ hb_draw_funcs_t *dfuncs, void *draw_data);
+
+
+/**
+ * HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION:
+ *
+ * Use #HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION instead.
+ *
+ * Deprecated: 8.3.0
+ */
+#define HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION HB_AAT_LAYOUT_FEATURE_TYPE_CURSIVE_CONNECTION
+
#endif
+
HB_END_DECLS
#endif /* HB_DEPRECATED_H */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc b/src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc
index 42764a244b..6c90265d0b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-directwrite.cc
@@ -173,7 +173,7 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
t_DWriteCreateFactory p_DWriteCreateFactory;
-#if defined(__GNUC__)
+#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type"
#endif
@@ -181,7 +181,7 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
p_DWriteCreateFactory = (t_DWriteCreateFactory)
GetProcAddress (data->dwrite_dll, "DWriteCreateFactory");
-#if defined(__GNUC__)
+#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-draw.hh b/src/3rdparty/harfbuzz-ng/src/hb-draw.hh
index 768f51a875..25dee1261e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-draw.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-draw.hh
@@ -93,50 +93,57 @@ struct hb_draw_funcs_t
!user_data ? nullptr : user_data->close_path); }
- void move_to (void *draw_data, hb_draw_state_t &st,
- float to_x, float to_y)
+ void
+ HB_ALWAYS_INLINE
+ move_to (void *draw_data, hb_draw_state_t &st,
+ float to_x, float to_y)
{
- if (st.path_open) close_path (draw_data, st);
+ if (unlikely (st.path_open)) close_path (draw_data, st);
st.current_x = to_x;
st.current_y = to_y;
}
- void line_to (void *draw_data, hb_draw_state_t &st,
- float to_x, float to_y)
+ void
+ HB_ALWAYS_INLINE
+ line_to (void *draw_data, hb_draw_state_t &st,
+ float to_x, float to_y)
{
- if (!st.path_open) start_path (draw_data, st);
+ if (unlikely (!st.path_open)) start_path (draw_data, st);
emit_line_to (draw_data, st, to_x, to_y);
st.current_x = to_x;
st.current_y = to_y;
}
void
+ HB_ALWAYS_INLINE
quadratic_to (void *draw_data, hb_draw_state_t &st,
float control_x, float control_y,
float to_x, float to_y)
{
- if (!st.path_open) start_path (draw_data, st);
+ if (unlikely (!st.path_open)) start_path (draw_data, st);
emit_quadratic_to (draw_data, st, control_x, control_y, to_x, to_y);
st.current_x = to_x;
st.current_y = to_y;
}
void
+ HB_ALWAYS_INLINE
cubic_to (void *draw_data, hb_draw_state_t &st,
float control1_x, float control1_y,
float control2_x, float control2_y,
float to_x, float to_y)
{
- if (!st.path_open) start_path (draw_data, st);
+ if (unlikely (!st.path_open)) start_path (draw_data, st);
emit_cubic_to (draw_data, st, control1_x, control1_y, control2_x, control2_y, to_x, to_y);
st.current_x = to_x;
st.current_y = to_y;
}
void
+ HB_ALWAYS_INLINE
close_path (void *draw_data, hb_draw_state_t &st)
{
- if (st.path_open)
+ if (likely (st.path_open))
{
if ((st.path_start_x != st.current_x) || (st.path_start_y != st.current_y))
emit_line_to (draw_data, st, st.path_start_x, st.path_start_y);
@@ -168,6 +175,7 @@ struct hb_draw_session_t
~hb_draw_session_t () { close_path (); }
+ HB_ALWAYS_INLINE
void move_to (float to_x, float to_y)
{
if (likely (not_slanted))
@@ -177,6 +185,7 @@ struct hb_draw_session_t
funcs->move_to (draw_data, st,
to_x + to_y * slant, to_y);
}
+ HB_ALWAYS_INLINE
void line_to (float to_x, float to_y)
{
if (likely (not_slanted))
@@ -187,6 +196,7 @@ struct hb_draw_session_t
to_x + to_y * slant, to_y);
}
void
+ HB_ALWAYS_INLINE
quadratic_to (float control_x, float control_y,
float to_x, float to_y)
{
@@ -200,6 +210,7 @@ struct hb_draw_session_t
to_x + to_y * slant, to_y);
}
void
+ HB_ALWAYS_INLINE
cubic_to (float control1_x, float control1_y,
float control2_x, float control2_y,
float to_x, float to_y)
@@ -215,6 +226,7 @@ struct hb_draw_session_t
control2_x + control2_y * slant, control2_y,
to_x + to_y * slant, to_y);
}
+ HB_ALWAYS_INLINE
void close_path ()
{
funcs->close_path (draw_data, st);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-face.cc b/src/3rdparty/harfbuzz-ng/src/hb-face.cc
index 5fcc4e93d9..e340710586 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-face.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-face.cc
@@ -47,6 +47,12 @@
* More precisely, a font face represents a single face in a binary font file.
* Font faces are typically built from a binary blob and a face index.
* Font faces are used to create fonts.
+ *
+ * A font face can be created from a binary blob using hb_face_create().
+ * The face index is used to select a face from a binary blob that contains
+ * multiple faces. For example, a binary blob that contains both a regular
+ * and a bold face can be used to create two font faces, one for each face
+ * index.
**/
@@ -197,7 +203,7 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
* a face index into that blob.
*
* The face index is used for blobs of file formats such as TTC and
- * and DFont that can contain more than one face. Face indices within
+ * DFont that can contain more than one face. Face indices within
* such collections are zero-based.
*
* <note>Note: If the blob font format is not a collection, @index
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-face.hh b/src/3rdparty/harfbuzz-ng/src/hb-face.hh
index 1bf0606e52..aff3ff0d07 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-face.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-face.hh
@@ -76,7 +76,7 @@ struct hb_face_t
if (unlikely (!reference_table_func))
return hb_blob_get_empty ();
- blob = reference_table_func (/*XXX*/const_cast<hb_face_t *> (this), tag, user_data);
+ blob = reference_table_func (/*Oh, well.*/const_cast<hb_face_t *> (this), tag, user_data);
if (unlikely (!blob))
return hb_blob_get_empty ();
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-features.h b/src/3rdparty/harfbuzz-ng/src/hb-features.h
new file mode 100644
index 0000000000..9199864195
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-features.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright © 2022 Red Hat, 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.
+ */
+
+#ifndef HB_FEATURES_H
+#define HB_FEATURES_H
+
+HB_BEGIN_DECLS
+
+/**
+ * SECTION: hb-features
+ * @title: hb-features
+ * @short_description: Feature detection
+ * @include: hb-features.h
+ *
+ * Macros for detecting optional HarfBuzz features at build time.
+ **/
+
+/**
+ * HB_HAS_CAIRO:
+ *
+ * Defined if Harfbuzz has been built with cairo support.
+ */
+#
+
+/**
+ * HB_HAS_CORETEXT:
+ *
+ * Defined if Harfbuzz has been built with CoreText support.
+ */
+#undef HB_HAS_CORETEXT
+
+/**
+ * HB_HAS_DIRECTWRITE:
+ *
+ * Defined if Harfbuzz has been built with DirectWrite support.
+ */
+#undef HB_HAS_DIRECTWRITE
+
+/**
+ * HB_HAS_FREETYPE:
+ *
+ * Defined if Harfbuzz has been built with Freetype support.
+ */
+#define HB_HAS_FREETYPE 1
+
+/**
+ * HB_HAS_GDI:
+ *
+ * Defined if Harfbuzz has been built with GDI support.
+ */
+#undef HB_HAS_GDI
+
+/**
+ * HB_HAS_GLIB:
+ *
+ * Defined if Harfbuzz has been built with GLib support.
+ */
+#define HB_HAS_GLIB 1
+
+/**
+ * HB_HAS_GOBJECT:
+ *
+ * Defined if Harfbuzz has been built with GObject support.
+ */
+#undef HB_HAS_GOBJECT
+
+/**
+ * HB_HAS_GRAPHITE:
+ *
+ * Defined if Harfbuzz has been built with Graphite support.
+ */
+#undef HB_HAS_GRAPHITE
+
+/**
+ * HB_HAS_ICU:
+ *
+ * Defined if Harfbuzz has been built with ICU support.
+ */
+#undef HB_HAS_ICU
+
+/**
+ * HB_HAS_UNISCRIBE:
+ *
+ * Defined if Harfbuzz has been built with Uniscribe support.
+ */
+#undef HB_HAS_UNISCRIBE
+
+/**
+ * HB_HAS_WASM:
+ *
+ * Defined if Harfbuzz has been built with WebAssembly support.
+ */
+#undef HB_HAS_WASM
+
+
+HB_END_DECLS
+
+#endif /* HB_FEATURES_H */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-font.cc b/src/3rdparty/harfbuzz-ng/src/hb-font.cc
index 3868863105..00f1f6d382 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-font.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-font.cc
@@ -59,6 +59,11 @@
*
* HarfBuzz provides a built-in set of lightweight default
* functions for each method in #hb_font_funcs_t.
+ *
+ * The default font functions are implemented in terms of the
+ * #hb_font_funcs_t methods of the parent font object. This allows
+ * client programs to override only the methods they need to, and
+ * otherwise inherit the parent font's implementation, if any.
**/
@@ -1061,7 +1066,7 @@ hb_font_get_nominal_glyph (hb_font_t *font,
* @glyph_stride: The stride between successive glyph IDs
*
* Fetches the nominal glyph IDs for a sequence of Unicode code points. Glyph
- * IDs must be returned in a #hb_codepoint_t output parameter. Stopes at the
+ * IDs must be returned in a #hb_codepoint_t output parameter. Stops at the
* first unsupported glyph ID.
*
* Return value: the number of code points processed
@@ -1384,10 +1389,11 @@ hb_font_get_glyph_from_name (hb_font_t *font,
return font->get_glyph_from_name (name, len, glyph);
}
+#ifndef HB_DISABLE_DEPRECATED
/**
* hb_font_get_glyph_shape:
* @font: #hb_font_t to work upon
- * @glyph: : The glyph ID
+ * @glyph: The glyph ID
* @dfuncs: #hb_draw_funcs_t to draw to
* @draw_data: User data to pass to draw callbacks
*
@@ -1405,11 +1411,12 @@ hb_font_get_glyph_shape (hb_font_t *font,
{
hb_font_draw_glyph (font, glyph, dfuncs, draw_data);
}
+#endif
/**
* hb_font_draw_glyph:
* @font: #hb_font_t to work upon
- * @glyph: : The glyph ID
+ * @glyph: The glyph ID
* @dfuncs: #hb_draw_funcs_t to draw to
* @draw_data: User data to pass to draw callbacks
*
@@ -2643,13 +2650,83 @@ hb_font_set_variations (hb_font_t *font,
if (axes[axis_index].axisTag == tag)
design_coords[axis_index] = v;
}
- font->face->table.avar->map_coords (normalized, coords_length);
hb_ot_var_normalize_coords (font->face, coords_length, design_coords, normalized);
_hb_font_adopt_var_coords (font, normalized, design_coords, coords_length);
}
/**
+ * hb_font_set_variation:
+ * @font: #hb_font_t to work upon
+ * @tag: The #hb_tag_t tag of the variation-axis name
+ * @value: The value of the variation axis
+ *
+ * Change the value of one variation axis on the font.
+ *
+ * Note: This function is expensive to be called repeatedly.
+ * If you want to set multiple variation axes at the same time,
+ * use hb_font_set_variations() instead.
+ *
+ * Since: 7.1.0
+ */
+void
+hb_font_set_variation (hb_font_t *font,
+ hb_tag_t tag,
+ float value)
+{
+ if (hb_object_is_immutable (font))
+ return;
+
+ font->serial_coords = ++font->serial;
+
+ // TODO Share some of this code with set_variations()
+
+ const OT::fvar &fvar = *font->face->table.fvar;
+ auto axes = fvar.get_axes ();
+ const unsigned coords_length = axes.length;
+
+ int *normalized = coords_length ? (int *) hb_calloc (coords_length, sizeof (int)) : nullptr;
+ float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr;
+
+ if (unlikely (coords_length && !(normalized && design_coords)))
+ {
+ hb_free (normalized);
+ hb_free (design_coords);
+ return;
+ }
+
+ /* Initialize design coords. */
+ if (font->design_coords)
+ {
+ assert (coords_length == font->num_coords);
+ for (unsigned int i = 0; i < coords_length; i++)
+ design_coords[i] = font->design_coords[i];
+ }
+ else
+ {
+ for (unsigned int i = 0; i < coords_length; i++)
+ design_coords[i] = axes[i].get_default ();
+ if (font->instance_index != HB_FONT_NO_VAR_NAMED_INSTANCE)
+ {
+ unsigned count = coords_length;
+ /* This may fail if index is out-of-range;
+ * That's why we initialize design_coords from fvar above
+ * unconditionally. */
+ hb_ot_var_named_instance_get_design_coords (font->face, font->instance_index,
+ &count, design_coords);
+ }
+ }
+
+ for (unsigned axis_index = 0; axis_index < coords_length; axis_index++)
+ if (axes[axis_index].axisTag == tag)
+ design_coords[axis_index] = value;
+
+ hb_ot_var_normalize_coords (font->face, coords_length, design_coords, normalized);
+ _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length);
+
+}
+
+/**
* hb_font_set_var_coords_design:
* @font: #hb_font_t to work upon
* @coords: (array length=coords_length): Array of variation coordinates to apply
@@ -2980,6 +3057,7 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
#endif
+#ifndef HB_DISABLE_DEPRECATED
void
hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_shape_func_t func,
@@ -2988,3 +3066,4 @@ hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
{
hb_font_funcs_set_draw_glyph_func (ffuncs, func, user_data, destroy);
}
+#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-font.h b/src/3rdparty/harfbuzz-ng/src/hb-font.h
index 69457da577..3c2355af2d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-font.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-font.h
@@ -486,25 +486,6 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *
void *user_data);
/**
- * hb_font_get_glyph_shape_func_t:
- * @font: #hb_font_t to work upon
- * @font_data: @font user data pointer
- * @glyph: The glyph ID to query
- * @draw_funcs: The draw functions to send the shape data to
- * @draw_data: The data accompanying the draw functions
- * @user_data: User data pointer passed by the caller
- *
- * A virtual method for the #hb_font_funcs_t of an #hb_font_t object.
- *
- * Since: 4.0.0
- * Deprecated: 7.0.0: Use #hb_font_draw_glyph_func_t instead
- **/
-typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data,
- hb_codepoint_t glyph,
- hb_draw_funcs_t *draw_funcs, void *draw_data,
- void *user_data);
-
-/**
* hb_font_draw_glyph_func_t:
* @font: #hb_font_t to work upon
* @font_data: @font user data pointer
@@ -804,32 +785,13 @@ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs,
void *user_data, hb_destroy_func_t destroy);
/**
- * hb_font_funcs_set_glyph_shape_func:
- * @ffuncs: A font-function structure
- * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
- * @user_data: Data to pass to @func
- * @destroy: (nullable): The function to call when @user_data is not needed anymore
- *
- * Sets the implementation function for #hb_font_get_glyph_shape_func_t,
- * which is the same as #hb_font_draw_glyph_func_t.
- *
- * Since: 4.0.0
- * Deprecated: 7.0.0: Use hb_font_funcs_set_draw_glyph_func() instead
- **/
-HB_EXTERN void
-hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs,
- hb_font_get_glyph_shape_func_t func,
- void *user_data, hb_destroy_func_t destroy);
-
-/**
* hb_font_funcs_set_draw_glyph_func:
* @ffuncs: A font-function structure
* @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign
* @user_data: Data to pass to @func
* @destroy: (nullable): The function to call when @user_data is not needed anymore
*
- * Sets the implementation function for #hb_font_draw_glyph_func_t,
- * which is the same as #hb_font_get_glyph_shape_func_t.
+ * Sets the implementation function for #hb_font_draw_glyph_func_t.
*
* Since: 7.0.0
**/
@@ -935,11 +897,6 @@ hb_font_get_glyph_from_name (hb_font_t *font,
hb_codepoint_t *glyph);
HB_EXTERN void
-hb_font_get_glyph_shape (hb_font_t *font,
- hb_codepoint_t glyph,
- hb_draw_funcs_t *dfuncs, void *draw_data);
-
-HB_EXTERN void
hb_font_draw_glyph (hb_font_t *font,
hb_codepoint_t glyph,
hb_draw_funcs_t *dfuncs, void *draw_data);
@@ -1151,6 +1108,11 @@ hb_font_set_variations (hb_font_t *font,
unsigned int variations_length);
HB_EXTERN void
+hb_font_set_variation (hb_font_t *font,
+ hb_tag_t tag,
+ float value);
+
+HB_EXTERN void
hb_font_set_var_coords_design (hb_font_t *font,
const float *coords,
unsigned int coords_length);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-font.hh b/src/3rdparty/harfbuzz-ng/src/hb-font.hh
index f503575c34..4c8190b0dd 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-font.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-font.hh
@@ -651,7 +651,7 @@ struct hb_font_t
{
if (get_glyph_name (glyph, s, size)) return;
- if (size && snprintf (s, size, "gid%u", glyph) < 0)
+ if (size && snprintf (s, size, "gid%" PRIu32, glyph) < 0)
*s = '\0';
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ft-colr.hh b/src/3rdparty/harfbuzz-ng/src/hb-ft-colr.hh
index b3457933c0..1afbbbb183 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ft-colr.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ft-colr.hh
@@ -105,6 +105,8 @@ struct hb_ft_paint_context_t
FT_Color *palette;
unsigned palette_index;
hb_color_t foreground;
+ hb_map_t current_glyphs;
+ hb_map_t current_layers;
int depth_left = HB_MAX_NESTING_LEVEL;
int edge_count = HB_COLRV1_MAX_EDGE_COUNT;
};
@@ -220,9 +222,18 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
&paint.u.colr_layers.layer_iterator,
&other_paint))
{
+ unsigned i = paint.u.colr_layers.layer_iterator.layer;
+
+ if (unlikely (c->current_layers.has (i)))
+ continue;
+
+ c->current_layers.add (i);
+
c->funcs->push_group (c->data);
c->recurse (other_paint);
c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
+
+ c->current_layers.del (i);
}
}
break;
@@ -301,8 +312,8 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
c->funcs->sweep_gradient (c->data, &cl,
paint.u.sweep_gradient.center.x / 65536.f,
paint.u.sweep_gradient.center.y / 65536.f,
- (paint.u.sweep_gradient.start_angle / 65536.f + 1) * (float) M_PI,
- (paint.u.sweep_gradient.end_angle / 65536.f + 1) * (float) M_PI);
+ (paint.u.sweep_gradient.start_angle / 65536.f + 1) * HB_PI,
+ (paint.u.sweep_gradient.end_angle / 65536.f + 1) * HB_PI);
}
break;
case FT_COLR_PAINTFORMAT_GLYPH:
@@ -320,8 +331,27 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
break;
case FT_COLR_PAINTFORMAT_COLR_GLYPH:
{
+ hb_codepoint_t gid = paint.u.colr_glyph.glyphID;
+
+ if (unlikely (c->current_glyphs.has (gid)))
+ return;
+
+ c->current_glyphs.add (gid);
+
+ c->funcs->push_inverse_root_transform (c->data, c->font);
+ c->ft_font->lock.unlock ();
+ if (c->funcs->color_glyph (c->data, gid, c->font))
+ {
+ c->ft_font->lock.lock ();
+ c->funcs->pop_transform (c->data);
+ c->current_glyphs.del (gid);
+ return;
+ }
+ c->ft_font->lock.lock ();
+ c->funcs->pop_transform (c->data);
+
FT_OpaquePaint other_paint = {0};
- if (FT_Get_Color_Glyph_Paint (ft_face, paint.u.colr_glyph.glyphID,
+ if (FT_Get_Color_Glyph_Paint (ft_face, gid,
FT_COLOR_NO_ROOT_TRANSFORM,
&other_paint))
{
@@ -350,6 +380,8 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
if (has_clip_box)
c->funcs->pop_clip (c->data);
+
+ c->current_glyphs.del (gid);
}
}
break;
@@ -474,6 +506,7 @@ hb_ft_paint_glyph_colr (hb_font_t *font,
hb_ft_paint_context_t c (ft_font, font,
paint_funcs, paint_data,
palette, palette_index, foreground);
+ c.current_glyphs.add (gid);
bool is_bounded = true;
FT_ClipBox clip_box;
@@ -497,6 +530,7 @@ hb_ft_paint_glyph_colr (hb_font_t *font,
hb_ft_paint_context_t ce (ft_font, font,
extents_funcs, &extents_data,
palette, palette_index, foreground);
+ ce.current_glyphs.add (gid);
ce.funcs->push_root_transform (ce.data, font);
ce.recurse (paint);
ce.funcs->pop_transform (ce.data);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ft.cc b/src/3rdparty/harfbuzz-ng/src/hb-ft.cc
index 4bc10e0620..3de4a6d5d4 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ft.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ft.cc
@@ -85,7 +85,7 @@
*/
-using hb_ft_advance_cache_t = hb_cache_t<16, 8, 8, false>;
+using hb_ft_advance_cache_t = hb_cache_t<16, 24, 8, false>;
struct hb_ft_font_t
{
@@ -114,7 +114,7 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
ft_font->cached_serial = (unsigned) -1;
- ft_font->advance_cache.init ();
+ new (&ft_font->advance_cache) hb_ft_advance_cache_t;
return ft_font;
}
@@ -224,8 +224,8 @@ _hb_ft_hb_font_check_changed (hb_font_t *font,
*
* Sets the FT_Load_Glyph load flags for the specified #hb_font_t.
*
- * For more information, see
- * https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx
+ * For more information, see
+ * <https://freetype.org/freetype2/docs/reference/ft2-glyph_retrieval.html#ft_load_xxx>
*
* This function works with #hb_font_t objects created by
* hb_ft_font_create() or hb_ft_font_create_referenced().
@@ -252,8 +252,8 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
*
* Fetches the FT_Load_Glyph load flags of the specified #hb_font_t.
*
- * For more information, see
- * https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx
+ * For more information, see
+ * <https://freetype.org/freetype2/docs/reference/ft2-glyph_retrieval.html#ft_load_xxx>
*
* This function works with #hb_font_t objects created by
* hb_ft_font_create() or hb_ft_font_create_referenced().
@@ -1118,10 +1118,10 @@ _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data
* This variant of the function does not provide any life-cycle management.
*
* Most client programs should use hb_ft_face_create_referenced()
- * (or, perhaps, hb_ft_face_create_cached()) instead.
+ * (or, perhaps, hb_ft_face_create_cached()) instead.
*
* If you know you have valid reasons not to use hb_ft_face_create_referenced(),
- * then it is the client program's responsibility to destroy @ft_face
+ * then it is the client program's responsibility to destroy @ft_face
* after the #hb_face_t face object has been destroyed.
*
* Return value: (transfer full): the new #hb_face_t face object
@@ -1215,7 +1215,7 @@ hb_ft_face_finalize (void *arg)
hb_face_t *
hb_ft_face_create_cached (FT_Face ft_face)
{
- if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
+ if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != hb_ft_face_finalize))
{
if (ft_face->generic.finalizer)
ft_face->generic.finalizer (ft_face);
@@ -1241,13 +1241,13 @@ hb_ft_face_create_cached (FT_Face ft_face)
* This variant of the function does not provide any life-cycle management.
*
* Most client programs should use hb_ft_font_create_referenced()
- * instead.
+ * instead.
*
* If you know you have valid reasons not to use hb_ft_font_create_referenced(),
- * then it is the client program's responsibility to destroy @ft_face
+ * then it is the client program's responsibility to destroy @ft_face
* after the #hb_font_t font object has been destroyed.
*
- * HarfBuzz will use the @destroy callback on the #hb_font_t font object
+ * HarfBuzz will use the @destroy callback on the #hb_font_t font object
* if it is supplied when you use this function. However, even if @destroy
* is provided, it is the client program's responsibility to destroy @ft_face,
* and it is the client program's responsibility to ensure that @ft_face is
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-gobject-structs.cc b/src/3rdparty/harfbuzz-ng/src/hb-gobject-structs.cc
index 332cc84888..d66de0b237 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-gobject-structs.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-gobject-structs.cc
@@ -29,7 +29,7 @@
#ifdef HAVE_GOBJECT
-/**
+/*
* SECTION:hb-gobject
* @title: hb-gobject
* @short_description: GObject integration support
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc b/src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc
index 9e068f8d84..7ea0386223 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-graphite2.cc
@@ -248,6 +248,21 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
gr_fref_set_feature_value (fref, features[i].value, feats);
}
+ hb_direction_t direction = buffer->props.direction;
+ hb_direction_t horiz_dir = hb_script_get_horizontal_direction (buffer->props.script);
+ /* TODO vertical:
+ * The only BTT vertical script is Ogham, but it's not clear to me whether OpenType
+ * Ogham fonts are supposed to be implemented BTT or not. Need to research that
+ * first. */
+ if ((HB_DIRECTION_IS_HORIZONTAL (direction) &&
+ direction != horiz_dir && horiz_dir != HB_DIRECTION_INVALID) ||
+ (HB_DIRECTION_IS_VERTICAL (direction) &&
+ direction != HB_DIRECTION_TTB))
+ {
+ hb_buffer_reverse_clusters (buffer);
+ direction = HB_DIRECTION_REVERSE (direction);
+ }
+
gr_segment *seg = nullptr;
const gr_slot *is;
unsigned int ci = 0, ic = 0;
@@ -261,21 +276,11 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
for (unsigned int i = 0; i < buffer->len; ++i)
chars[i] = buffer->info[i].codepoint;
- /* TODO ensure_native_direction. */
-
- hb_tag_t script_tag[HB_OT_MAX_TAGS_PER_SCRIPT];
- unsigned int count = HB_OT_MAX_TAGS_PER_SCRIPT;
- hb_ot_tags_from_script_and_language (hb_buffer_get_script (buffer),
- HB_LANGUAGE_INVALID,
- &count,
- script_tag,
- nullptr, nullptr);
-
seg = gr_make_seg (nullptr, grface,
- count ? script_tag[count - 1] : HB_OT_TAG_DEFAULT_SCRIPT,
+ HB_TAG_NONE, // https://github.com/harfbuzz/harfbuzz/issues/3439#issuecomment-1442650148
feats,
gr_utf32, chars, buffer->len,
- 2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0));
+ 2 | (direction == HB_DIRECTION_RTL ? 1 : 0));
if (unlikely (!seg)) {
if (feats) gr_featureval_destroy (feats);
@@ -327,7 +332,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
float yscale = (float) font->y_scale / upem;
yscale *= yscale / xscale;
unsigned int curradv = 0;
- if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+ if (HB_DIRECTION_IS_BACKWARD (direction))
{
curradv = gr_slot_origin_X(gr_seg_first_slot(seg)) * xscale;
clusters[0].advance = gr_seg_advance_X(seg) * xscale - curradv;
@@ -356,16 +361,17 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
c->num_chars = before - c->base_char;
c->base_glyph = ic;
c->num_glyphs = 0;
- if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+ if (HB_DIRECTION_IS_BACKWARD (direction))
{
c->advance = curradv - gr_slot_origin_X(is) * xscale;
curradv -= c->advance;
}
else
{
+ auto origin_X = gr_slot_origin_X (is) * xscale;
c->advance = 0;
- clusters[ci].advance += gr_slot_origin_X(is) * xscale - curradv;
- curradv += clusters[ci].advance;
+ clusters[ci].advance += origin_X - curradv;
+ curradv = origin_X;
}
ci++;
}
@@ -375,7 +381,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
}
- if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+ if (HB_DIRECTION_IS_BACKWARD (direction))
clusters[ci].advance += curradv;
else
clusters[ci].advance += gr_seg_advance_X(seg) * xscale - curradv;
@@ -397,7 +403,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
unsigned int currclus = UINT_MAX;
const hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, nullptr);
- if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
+ if (!HB_DIRECTION_IS_BACKWARD (direction))
{
curradvx = 0;
for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is))
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-icu.cc b/src/3rdparty/harfbuzz-ng/src/hb-icu.cc
index e46401f7a6..3707ec30f8 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-icu.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-icu.cc
@@ -93,15 +93,16 @@ hb_icu_script_to_script (UScriptCode script)
UScriptCode
hb_icu_script_from_script (hb_script_t script)
{
+ UScriptCode out = USCRIPT_INVALID_CODE;
+
if (unlikely (script == HB_SCRIPT_INVALID))
- return USCRIPT_INVALID_CODE;
+ return out;
- unsigned int numScriptCode = 1 + u_getIntPropertyMaxValue (UCHAR_SCRIPT);
- for (unsigned int i = 0; i < numScriptCode; i++)
- if (unlikely (hb_icu_script_to_script ((UScriptCode) i) == script))
- return (UScriptCode) i;
+ UErrorCode icu_err = U_ZERO_ERROR;
+ const unsigned char buf[5] = {HB_UNTAG (script), 0};
+ uscript_getCode ((const char *) buf, &out, 1, &icu_err);
- return USCRIPT_UNKNOWN;
+ return out;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-iter.hh b/src/3rdparty/harfbuzz-ng/src/hb-iter.hh
index b123b2f27c..61e05180be 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-iter.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-iter.hh
@@ -63,6 +63,7 @@ struct hb_iter_t
static constexpr bool is_iterator = true;
static constexpr bool is_random_access_iterator = false;
static constexpr bool is_sorted_iterator = false;
+ static constexpr bool has_fast_len = false; // Should be checked in combination with is_random_access_iterator.
private:
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
@@ -393,7 +394,7 @@ struct hb_map_iter_t :
private:
Iter it;
- hb_reference_wrapper<Proj> f;
+ mutable hb_reference_wrapper<Proj> f;
};
template <typename Proj, hb_function_sortedness_t Sorted>
@@ -456,8 +457,8 @@ struct hb_filter_iter_t :
private:
Iter it;
- hb_reference_wrapper<Pred> p;
- hb_reference_wrapper<Proj> f;
+ mutable hb_reference_wrapper<Pred> p;
+ mutable hb_reference_wrapper<Proj> f;
};
template <typename Pred, typename Proj>
struct hb_filter_iter_factory_t
@@ -841,7 +842,7 @@ struct
template <typename Iterable,
hb_requires (hb_is_iterable (Iterable))>
auto operator () (Iterable&& it, unsigned count) const HB_AUTO_RETURN
- ( hb_zip (hb_range (count), it) | hb_map (hb_second) )
+ ( hb_zip (hb_range (count), it) | hb_map_retains_sorting (hb_second) )
/* Specialization arrays. */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-kern.hh b/src/3rdparty/harfbuzz-ng/src/hb-kern.hh
index 9ea945caed..0462a0ea8e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-kern.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-kern.hh
@@ -53,7 +53,7 @@ struct hb_kern_machine_t
return;
buffer->unsafe_to_concat ();
- OT::hb_ot_apply_context_t c (1, font, buffer);
+ OT::hb_ot_apply_context_t c (1, font, buffer, hb_blob_get_empty ());
c.set_lookup_mask (kern_mask);
c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
auto &skippy_iter = c.iter_input;
@@ -70,7 +70,7 @@ struct hb_kern_machine_t
continue;
}
- skippy_iter.reset (idx, 1);
+ skippy_iter.reset (idx);
unsigned unsafe_to;
if (!skippy_iter.next (&unsafe_to))
{
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-limits.hh b/src/3rdparty/harfbuzz-ng/src/hb-limits.hh
index 0f60e9e210..7efc893eae 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-limits.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-limits.hh
@@ -89,6 +89,10 @@
#endif
+#ifndef HB_GLYF_VAR_COMPOSITE_MAX_AXES
+#define HB_GLYF_VAR_COMPOSITE_MAX_AXES 4096
+#endif
+
#ifndef HB_GLYF_MAX_POINTS
#define HB_GLYF_MAX_POINTS 20000
#endif
@@ -102,7 +106,7 @@
#endif
#ifndef HB_COLRV1_MAX_EDGE_COUNT
-#define HB_COLRV1_MAX_EDGE_COUNT 1024
+#define HB_COLRV1_MAX_EDGE_COUNT 2048
#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-machinery.hh b/src/3rdparty/harfbuzz-ng/src/hb-machinery.hh
index 1084725af2..ecff94f1b6 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-machinery.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-machinery.hh
@@ -180,6 +180,9 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
hb_lazy_loader_t<Returned,Subclass,Data,WheresData,Stored>
>::value Funcs;
+ hb_lazy_loader_t () = default;
+ hb_lazy_loader_t (const hb_lazy_loader_t &other) = delete;
+
void init0 () {} /* Init, when memory is already set to 0. No-op for us. */
void init () { instance.set_relaxed (nullptr); }
void fini () { do_destroy (instance.get_acquire ()); init (); }
@@ -278,7 +281,11 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
template <typename T, unsigned int WheresFace>
struct hb_face_lazy_loader_t : hb_lazy_loader_t<T,
hb_face_lazy_loader_t<T, WheresFace>,
- hb_face_t, WheresFace> {};
+ hb_face_t, WheresFace>
+{
+ // Hack; have them here for API parity with hb_table_lazy_loader_t
+ hb_blob_t *get_blob () { return this->get ()->get_blob (); }
+};
template <typename T, unsigned int WheresFace, bool core=false>
struct hb_table_lazy_loader_t : hb_lazy_loader_t<T,
@@ -288,7 +295,7 @@ struct hb_table_lazy_loader_t : hb_lazy_loader_t<T,
{
static hb_blob_t *create (hb_face_t *face)
{
- auto c = hb_sanitize_context_t ();
+ hb_sanitize_context_t c;
if (core)
c.set_num_glyphs (0); // So we don't recurse ad infinitum, or doesn't need num_glyphs
return c.reference_table<T> (face);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-map.cc b/src/3rdparty/harfbuzz-ng/src/hb-map.cc
index 0014570e8e..0dc9246f12 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-map.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-map.cc
@@ -365,7 +365,7 @@ hb_map_update (hb_map_t *map,
* @key: (out): Key retrieved
* @value: (out): Value retrieved
*
- * Fetches the next key/value paire in @map.
+ * Fetches the next key/value pair in @map.
*
* Set @idx to -1 to get started.
*
@@ -399,7 +399,7 @@ void
hb_map_keys (const hb_map_t *map,
hb_set_t *keys)
{
- map->keys (*keys);
+ hb_copy (map->keys() , *keys);
}
/**
@@ -415,5 +415,5 @@ void
hb_map_values (const hb_map_t *map,
hb_set_t *values)
{
- map->values (*values);
+ hb_copy (map->values() , *values);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-map.h b/src/3rdparty/harfbuzz-ng/src/hb-map.h
index e928628fa7..0ae171714e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-map.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-map.h
@@ -44,7 +44,7 @@ HB_BEGIN_DECLS
*
* Since: 1.7.7
*/
-#define HB_MAP_VALUE_INVALID ((hb_codepoint_t) -1)
+#define HB_MAP_VALUE_INVALID HB_CODEPOINT_INVALID
/**
* hb_map_t:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-map.hh b/src/3rdparty/harfbuzz-ng/src/hb-map.hh
index 615d1825ed..6521b1a41d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-map.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-map.hh
@@ -42,13 +42,37 @@ template <typename K, typename V,
bool minus_one = false>
struct hb_hashmap_t
{
+ static constexpr bool realloc_move = true;
+
hb_hashmap_t () { init (); }
~hb_hashmap_t () { fini (); }
- hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { resize (o.population); hb_copy (o, *this); }
- hb_hashmap_t (hb_hashmap_t&& o) : hb_hashmap_t () { hb_swap (*this, o); }
- hb_hashmap_t& operator= (const hb_hashmap_t& o) { reset (); resize (o.population); hb_copy (o, *this); return *this; }
- hb_hashmap_t& operator= (hb_hashmap_t&& o) { hb_swap (*this, o); return *this; }
+ hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t ()
+ {
+ if (unlikely (!o.mask)) return;
+
+ if (item_t::is_trivial)
+ {
+ items = (item_t *) hb_malloc (sizeof (item_t) * (o.mask + 1));
+ if (unlikely (!items))
+ {
+ successful = false;
+ return;
+ }
+ population = o.population;
+ occupancy = o.occupancy;
+ mask = o.mask;
+ prime = o.prime;
+ max_chain_length = o.max_chain_length;
+ memcpy (items, o.items, sizeof (item_t) * (mask + 1));
+ return;
+ }
+
+ alloc (o.population); hb_copy (o, *this);
+ }
+ hb_hashmap_t (hb_hashmap_t&& o) noexcept : hb_hashmap_t () { hb_swap (*this, o); }
+ hb_hashmap_t& operator= (const hb_hashmap_t& o) { reset (); alloc (o.population); hb_copy (o, *this); return *this; }
+ hb_hashmap_t& operator= (hb_hashmap_t&& o) noexcept { hb_swap (*this, o); return *this; }
hb_hashmap_t (std::initializer_list<hb_pair_t<K, V>> lst) : hb_hashmap_t ()
{
@@ -60,29 +84,32 @@ struct hb_hashmap_t
hb_hashmap_t (const Iterable &o) : hb_hashmap_t ()
{
auto iter = hb_iter (o);
- if (iter.is_random_access_iterator)
- resize (hb_len (iter));
+ if (iter.is_random_access_iterator || iter.has_fast_len)
+ alloc (hb_len (iter));
hb_copy (iter, *this);
}
struct item_t
{
K key;
- uint32_t hash : 30;
+ uint32_t is_real_ : 1;
uint32_t is_used_ : 1;
- uint32_t is_tombstone_ : 1;
+ uint32_t hash : 30;
V value;
item_t () : key (),
+ is_real_ (false), is_used_ (false),
hash (0),
- is_used_ (false), is_tombstone_ (false),
value () {}
+ // Needed for https://github.com/harfbuzz/harfbuzz/issues/4138
+ K& get_key () { return key; }
+ V& get_value () { return value; }
+
bool is_used () const { return is_used_; }
void set_used (bool is_used) { is_used_ = is_used; }
- bool is_tombstone () const { return is_tombstone_; }
- void set_tombstone (bool is_tombstone) { is_tombstone_ = is_tombstone; }
- bool is_real () const { return is_used_ && !is_tombstone_; }
+ void set_real (bool is_real) { is_real_ = is_real; }
+ bool is_real () const { return is_real_; }
template <bool v = minus_one,
hb_enable_if (v == false)>
@@ -98,28 +125,32 @@ struct hb_hashmap_t
bool operator == (const K &o) const { return hb_deref (key) == hb_deref (o); }
bool operator == (const item_t &o) const { return *this == o.key; }
hb_pair_t<K, V> get_pair() const { return hb_pair_t<K, V> (key, value); }
- hb_pair_t<const K &, const V &> get_pair_ref() const { return hb_pair_t<const K &, const V &> (key, value); }
+ hb_pair_t<const K &, V &> get_pair_ref() { return hb_pair_t<const K &, V &> (key, value); }
uint32_t total_hash () const
- { return (hash * 31) + hb_hash (value); }
+ { return (hash * 31u) + hb_hash (value); }
+
+ static constexpr bool is_trivial = hb_is_trivially_constructible(K) &&
+ hb_is_trivially_destructible(K) &&
+ hb_is_trivially_constructible(V) &&
+ hb_is_trivially_destructible(V);
};
hb_object_header_t header;
- unsigned int successful : 1; /* Allocations successful */
- unsigned int population : 31; /* Not including tombstones. */
+ bool successful; /* Allocations successful */
+ unsigned short max_chain_length;
+ unsigned int population; /* Not including tombstones. */
unsigned int occupancy; /* Including tombstones. */
unsigned int mask;
unsigned int prime;
item_t *items;
- friend void swap (hb_hashmap_t& a, hb_hashmap_t& b)
+ friend void swap (hb_hashmap_t& a, hb_hashmap_t& b) noexcept
{
if (unlikely (!a.successful || !b.successful))
return;
- unsigned tmp = a.population;
- a.population = b.population;
- b.population = tmp;
- //hb_swap (a.population, b.population);
+ hb_swap (a.max_chain_length, b.max_chain_length);
+ hb_swap (a.population, b.population);
hb_swap (a.occupancy, b.occupancy);
hb_swap (a.mask, b.mask);
hb_swap (a.prime, b.prime);
@@ -130,6 +161,7 @@ struct hb_hashmap_t
hb_object_init (this);
successful = true;
+ max_chain_length = 0;
population = occupancy = 0;
mask = 0;
prime = 0;
@@ -139,10 +171,12 @@ struct hb_hashmap_t
{
hb_object_fini (this);
- if (likely (items)) {
+ if (likely (items))
+ {
unsigned size = mask + 1;
- for (unsigned i = 0; i < size; i++)
- items[i].~item_t ();
+ if (!item_t::is_trivial)
+ for (unsigned i = 0; i < size; i++)
+ items[i].~item_t ();
hb_free (items);
items = nullptr;
}
@@ -157,7 +191,7 @@ struct hb_hashmap_t
bool in_error () const { return !successful; }
- bool resize (unsigned new_population = 0)
+ bool alloc (unsigned new_population = 0)
{
if (unlikely (!successful)) return false;
@@ -171,8 +205,11 @@ struct hb_hashmap_t
successful = false;
return false;
}
- for (auto &_ : hb_iter (new_items, new_size))
- new (&_) item_t ();
+ if (!item_t::is_trivial)
+ for (auto &_ : hb_iter (new_items, new_size))
+ new (&_) item_t ();
+ else
+ hb_memset (new_items, 0, (size_t) new_size * sizeof (item_t));
unsigned int old_size = size ();
item_t *old_items = items;
@@ -181,6 +218,7 @@ struct hb_hashmap_t
population = occupancy = 0;
mask = new_size - 1;
prime = prime_for (power);
+ max_chain_length = power * 2;
items = new_items;
/* Insert back old items. */
@@ -192,8 +230,10 @@ struct hb_hashmap_t
old_items[i].hash,
std::move (old_items[i].value));
}
- old_items[i].~item_t ();
}
+ if (!item_t::is_trivial)
+ for (unsigned int i = 0; i < old_size; i++)
+ old_items[i].~item_t ();
hb_free (old_items);
@@ -201,72 +241,129 @@ struct hb_hashmap_t
}
template <typename KK, typename VV>
- bool set_with_hash (KK&& key, uint32_t hash, VV&& value, bool is_delete=false)
+ bool set_with_hash (KK&& key, uint32_t hash, VV&& value, bool overwrite = true)
{
if (unlikely (!successful)) return false;
- if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false;
- item_t &item = item_for_hash (key, hash);
+ if (unlikely ((occupancy + occupancy / 2) >= mask && !alloc ())) return false;
- if (is_delete && !(item == key))
- return true; /* Trying to delete non-existent key. */
+ hash &= 0x3FFFFFFF; // We only store lower 30bit of hash
+ unsigned int tombstone = (unsigned int) -1;
+ unsigned int i = hash % prime;
+ unsigned length = 0;
+ unsigned step = 0;
+ while (items[i].is_used ())
+ {
+ if ((std::is_integral<K>::value || items[i].hash == hash) &&
+ items[i] == key)
+ {
+ if (!overwrite)
+ return false;
+ else
+ break;
+ }
+ if (!items[i].is_real () && tombstone == (unsigned) -1)
+ tombstone = i;
+ i = (i + ++step) & mask;
+ length++;
+ }
+
+ item_t &item = items[tombstone == (unsigned) -1 ? i : tombstone];
if (item.is_used ())
{
occupancy--;
- if (!item.is_tombstone ())
- population--;
+ population -= item.is_real ();
}
item.key = std::forward<KK> (key);
item.value = std::forward<VV> (value);
item.hash = hash;
item.set_used (true);
- item.set_tombstone (is_delete);
+ item.set_real (true);
occupancy++;
- if (!is_delete)
- population++;
+ population++;
+
+ if (unlikely (length > max_chain_length) && occupancy * 8 > mask)
+ alloc (mask - 8); // This ensures we jump to next larger size
return true;
}
template <typename VV>
- bool set (const K &key, VV&& value) { return set_with_hash (key, hb_hash (key), std::forward<VV> (value)); }
+ bool set (const K &key, VV&& value, bool overwrite = true) { return set_with_hash (key, hb_hash (key), std::forward<VV> (value), overwrite); }
template <typename VV>
- bool set (K &&key, VV&& value) { return set_with_hash (std::move (key), hb_hash (key), std::forward<VV> (value)); }
+ bool set (K &&key, VV&& value, bool overwrite = true)
+ {
+ uint32_t hash = hb_hash (key);
+ return set_with_hash (std::move (key), hash, std::forward<VV> (value), overwrite);
+ }
+ bool add (const K &key)
+ {
+ uint32_t hash = hb_hash (key);
+ return set_with_hash (key, hash, item_t::default_value ());
+ }
const V& get_with_hash (const K &key, uint32_t hash) const
{
- if (unlikely (!items)) return item_t::default_value ();
- auto &item = item_for_hash (key, hash);
- return item.is_real () && item == key ? item.value : item_t::default_value ();
+ if (!items) return item_t::default_value ();
+ auto *item = fetch_item (key, hb_hash (key));
+ if (item)
+ return item->value;
+ return item_t::default_value ();
}
const V& get (const K &key) const
{
- if (unlikely (!items)) return item_t::default_value ();
+ if (!items) return item_t::default_value ();
return get_with_hash (key, hb_hash (key));
}
- void del (const K &key) { set_with_hash (key, hb_hash (key), item_t::default_value (), true); }
+ void del (const K &key)
+ {
+ if (!items) return;
+ auto *item = fetch_item (key, hb_hash (key));
+ if (item)
+ {
+ item->set_real (false);
+ population--;
+ }
+ }
/* Has interface. */
const V& operator [] (K k) const { return get (k); }
template <typename VV=V>
- bool has (K key, VV **vp = nullptr) const
+ bool has (const K &key, VV **vp = nullptr) const
{
- if (unlikely (!items))
- return false;
- auto &item = item_for_hash (key, hb_hash (key));
- if (item.is_real () && item == key)
+ if (!items) return false;
+ auto *item = fetch_item (key, hb_hash (key));
+ if (item)
{
- if (vp) *vp = std::addressof (item.value);
+ if (vp) *vp = std::addressof (item->value);
return true;
}
- else
- return false;
+ return false;
+ }
+ item_t *fetch_item (const K &key, uint32_t hash) const
+ {
+ hash &= 0x3FFFFFFF; // We only store lower 30bit of hash
+ unsigned int i = hash % prime;
+ unsigned step = 0;
+ while (items[i].is_used ())
+ {
+ if ((std::is_integral<K>::value || items[i].hash == hash) &&
+ items[i] == key)
+ {
+ if (items[i].is_real ())
+ return &items[i];
+ else
+ return nullptr;
+ }
+ i = (i + ++step) & mask;
+ }
+ return nullptr;
}
/* Projection. */
- V operator () (K k) const { return get (k); }
+ const V& operator () (K k) const { return get (k); }
unsigned size () const { return mask ? mask + 1 : 0; }
@@ -317,53 +414,43 @@ struct hb_hashmap_t
hb_copy (other, *this);
}
- void keys (hb_set_t &keys_) const
- {
- hb_copy (keys() , keys_);
- }
-
- void values (hb_set_t &values_) const
- {
- hb_copy (values() , values_);
- }
-
/*
* Iterator
*/
auto iter_items () const HB_AUTO_RETURN
(
- + hb_iter (items, size ())
+ + hb_iter (items, this->size ())
| hb_filter (&item_t::is_real)
)
auto iter_ref () const HB_AUTO_RETURN
(
- + iter_items ()
+ + this->iter_items ()
| hb_map (&item_t::get_pair_ref)
)
auto iter () const HB_AUTO_RETURN
(
- + iter_items ()
+ + this->iter_items ()
| hb_map (&item_t::get_pair)
)
auto keys_ref () const HB_AUTO_RETURN
(
- + iter_items ()
- | hb_map (&item_t::key)
+ + this->iter_items ()
+ | hb_map (&item_t::get_key)
)
auto keys () const HB_AUTO_RETURN
(
- + keys_ref ()
+ + this->keys_ref ()
| hb_map (hb_ridentity)
)
auto values_ref () const HB_AUTO_RETURN
(
- + iter_items ()
- | hb_map (&item_t::value)
+ + this->iter_items ()
+ | hb_map (&item_t::get_value)
)
auto values () const HB_AUTO_RETURN
(
- + values_ref ()
+ + this->values_ref ()
| hb_map (hb_ridentity)
)
@@ -401,23 +488,6 @@ struct hb_hashmap_t
hb_hashmap_t& operator << (const hb_pair_t<K&&, V&&>& v)
{ set (std::move (v.first), std::move (v.second)); return *this; }
- item_t& item_for_hash (const K &key, uint32_t hash) const
- {
- hash &= 0x3FFFFFFF; // We only store lower 30bit of hash
- unsigned int i = hash % prime;
- unsigned int step = 0;
- unsigned int tombstone = (unsigned) -1;
- while (items[i].is_used ())
- {
- if (items[i].hash == hash && items[i] == key)
- return items[i];
- if (tombstone == (unsigned) -1 && items[i].is_tombstone ())
- tombstone = i;
- i = (i + ++step) & mask;
- }
- return items[tombstone == (unsigned) -1 ? i : tombstone];
- }
-
static unsigned int prime_for (unsigned int shift)
{
/* Following comment and table copied from glib. */
@@ -485,10 +555,10 @@ struct hb_map_t : hb_hashmap_t<hb_codepoint_t,
~hb_map_t () = default;
hb_map_t () : hashmap () {}
hb_map_t (const hb_map_t &o) : hashmap ((hashmap &) o) {}
- hb_map_t (hb_map_t &&o) : hashmap (std::move ((hashmap &) o)) {}
+ hb_map_t (hb_map_t &&o) noexcept : hashmap (std::move ((hashmap &) o)) {}
hb_map_t& operator= (const hb_map_t&) = default;
hb_map_t& operator= (hb_map_t&&) = default;
- hb_map_t (std::initializer_list<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> lst) : hashmap (lst) {}
+ hb_map_t (std::initializer_list<hb_codepoint_pair_t> lst) : hashmap (lst) {}
template <typename Iterable,
hb_requires (hb_is_iterable (Iterable))>
hb_map_t (const Iterable &o) : hashmap (o) {}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-meta.hh b/src/3rdparty/harfbuzz-ng/src/hb-meta.hh
index 31aa7fa6f1..52ff4a8412 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-meta.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-meta.hh
@@ -153,8 +153,8 @@ struct hb_reference_wrapper
hb_reference_wrapper (T v) : v (v) {}
bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
- operator T () const { return v; }
- T get () const { return v; }
+ operator T& () { return v; }
+ T& get () { return v; }
T v;
};
template <typename T>
@@ -163,8 +163,8 @@ struct hb_reference_wrapper<T&>
hb_reference_wrapper (T& v) : v (std::addressof (v)) {}
bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
- operator T& () const { return *v; }
- T& get () const { return *v; }
+ operator T& () { return *v; }
+ T& get () { return *v; }
T* v;
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-multimap.hh b/src/3rdparty/harfbuzz-ng/src/hb-multimap.hh
index b4a8cc62a3..0184279c12 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-multimap.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-multimap.hh
@@ -38,10 +38,10 @@ struct hb_multimap_t
{
void add (hb_codepoint_t k, hb_codepoint_t v)
{
- hb_codepoint_t *i;
- if (multiples_indices.has (k, &i))
+ hb_vector_t<hb_codepoint_t> *m;
+ if (multiples.has (k, &m))
{
- multiples_values[*i].push (v);
+ m->push (v);
return;
}
@@ -51,12 +51,7 @@ struct hb_multimap_t
hb_codepoint_t old = *old_v;
singulars.del (k);
- multiples_indices.set (k, multiples_values.length);
- auto *vec = multiples_values.push ();
-
- vec->push (old);
- vec->push (v);
-
+ multiples.set (k, hb_vector_t<hb_codepoint_t> {old, v});
return;
}
@@ -69,22 +64,31 @@ struct hb_multimap_t
if (singulars.has (k, &v))
return hb_array (v, 1);
- hb_codepoint_t *i;
- if (multiples_indices.has (k, &i))
- return multiples_values[*i].as_array ();
+ hb_vector_t<hb_codepoint_t> *m;
+ if (multiples.has (k, &m))
+ return m->as_array ();
return hb_array_t<const hb_codepoint_t> ();
}
bool in_error () const
{
- return singulars.in_error () || multiples_indices.in_error () || multiples_values.in_error ();
+ if (singulars.in_error () || multiples.in_error ())
+ return true;
+ for (const auto &m : multiples.values_ref ())
+ if (m.in_error ())
+ return true;
+ return false;
+ }
+
+ void alloc (unsigned size)
+ {
+ singulars.alloc (size);
}
protected:
hb_map_t singulars;
- hb_map_t multiples_indices;
- hb_vector_t<hb_vector_t<hb_codepoint_t>> multiples_values;
+ hb_hashmap_t<hb_codepoint_t, hb_vector_t<hb_codepoint_t>> multiples;
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-null.hh b/src/3rdparty/harfbuzz-ng/src/hb-null.hh
index 0d7f4da79e..854485d3df 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-null.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-null.hh
@@ -37,7 +37,7 @@
/* Global nul-content Null pool. Enlarge as necessary. */
-#define HB_NULL_POOL_SIZE 448
+#define HB_NULL_POOL_SIZE 640
template <typename T, typename>
struct _hb_has_min_size : hb_false_type {};
@@ -85,7 +85,7 @@ using hb_null_size = _hb_null_size<T, void>;
template <typename T, typename>
struct _hb_static_size : hb_integral_constant<unsigned, sizeof (T)> {};
template <typename T>
-struct _hb_static_size<T, hb_void_t<decltype (T::min_size)>> : hb_integral_constant<unsigned, T::static_size> {};
+struct _hb_static_size<T, hb_void_t<decltype (T::static_size)>> : hb_integral_constant<unsigned, T::static_size> {};
template <typename T>
using hb_static_size = _hb_static_size<T, void>;
#define hb_static_size(T) hb_static_size<T>::value
@@ -176,7 +176,7 @@ template <typename Type>
static inline Type& Crap () {
static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
Type *obj = reinterpret_cast<Type *> (_hb_CrapPool);
- memcpy (obj, &Null (Type), sizeof (*obj));
+ memcpy (obj, std::addressof (Null (Type)), sizeof (*obj));
return *obj;
}
template <typename QType>
@@ -211,11 +211,11 @@ struct hb_nonnull_ptr_t
T * operator = (T *v_) { return v = v_; }
T * operator -> () const { return get (); }
T & operator * () const { return *get (); }
- T ** operator & () const { return &v; }
+ T ** operator & () const { return std::addressof (v); }
/* Only auto-cast to const types. */
template <typename C> operator const C * () const { return get (); }
operator const char * () const { return (const char *) get (); }
- T * get () const { return v ? v : const_cast<T *> (&Null (T)); }
+ T * get () const { return v ? v : const_cast<T *> (std::addressof (Null (T))); }
T * get_raw () const { return v; }
private:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-number-parser.hh b/src/3rdparty/harfbuzz-ng/src/hb-number-parser.hh
index ec68c3a728..1a9dbba6dd 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-number-parser.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-number-parser.hh
@@ -31,7 +31,7 @@
#include "hb.hh"
-#line 32 "hb-number-parser.hh"
+#line 35 "hb-number-parser.hh"
static const unsigned char _double_parser_trans_keys[] = {
0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u,
46u, 101u, 0
@@ -135,12 +135,12 @@ strtod_rl (const char *p, const char **end_ptr /* IN/OUT */)
int cs;
-#line 132 "hb-number-parser.hh"
+#line 139 "hb-number-parser.hh"
{
cs = double_parser_start;
}
-#line 135 "hb-number-parser.hh"
+#line 144 "hb-number-parser.hh"
{
int _slen;
int _trans;
@@ -198,7 +198,7 @@ _resume:
exp_overflow = true;
}
break;
-#line 187 "hb-number-parser.hh"
+#line 202 "hb-number-parser.hh"
}
_again:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-object.hh b/src/3rdparty/harfbuzz-ng/src/hb-object.hh
index e2c2c3394c..5cffe1666b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-object.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-object.hh
@@ -325,7 +325,7 @@ retry:
hb_user_data_array_t *user_data = obj->header.user_data.get_acquire ();
if (unlikely (!user_data))
{
- user_data = (hb_user_data_array_t *) hb_calloc (sizeof (hb_user_data_array_t), 1);
+ user_data = (hb_user_data_array_t *) hb_calloc (1, sizeof (hb_user_data_array_t));
if (unlikely (!user_data))
return false;
user_data->init ();
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-open-file.hh b/src/3rdparty/harfbuzz-ng/src/hb-open-file.hh
index 13570a46e0..1157ea46d0 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-open-file.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-open-file.hh
@@ -131,7 +131,7 @@ typedef struct OpenTypeOffsetTable
sfnt_version = sfnt_tag;
/* Take space for numTables, searchRange, entrySelector, RangeShift
* and the TableRecords themselves. */
- unsigned num_items = it.len ();
+ unsigned num_items = hb_len (it);
if (unlikely (!tables.serialize (c, num_items))) return_trace (false);
const char *dir_end = (const char *) c->head;
@@ -145,7 +145,7 @@ typedef struct OpenTypeOffsetTable
unsigned len = blob->length;
/* Allocate room for the table and copy it. */
- char *start = (char *) c->allocate_size<void> (len);
+ char *start = (char *) c->allocate_size<void> (len, false);
if (unlikely (!start)) return false;
TableRecord &rec = tables.arrayZ[i];
@@ -267,6 +267,7 @@ struct TTCHeader
{
TRACE_SANITIZE (this);
if (unlikely (!u.header.version.sanitize (c))) return_trace (false);
+ hb_barrier ();
switch (u.header.version.major) {
case 2: /* version 2 is compatible with version 1 */
case 1: return_trace (u.version1.sanitize (c));
@@ -302,6 +303,7 @@ struct ResourceRecord
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
offset.sanitize (c, data_base) &&
+ hb_barrier () &&
get_face (data_base).sanitize (c));
}
@@ -337,6 +339,7 @@ struct ResourceTypeRecord
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
resourcesZ.sanitize (c, type_base,
get_resource_count (),
data_base));
@@ -385,6 +388,7 @@ struct ResourceMap
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
typeList.sanitize (c, this,
&(this+typeList),
data_base));
@@ -428,6 +432,7 @@ struct ResourceForkHeader
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
data.sanitize (c, this, dataLen) &&
map.sanitize (c, this, &(this+data)));
}
@@ -508,6 +513,7 @@ struct OpenTypeFontFile
{
TRACE_SANITIZE (this);
if (unlikely (!u.tag.sanitize (c))) return_trace (false);
+ hb_barrier ();
switch (u.tag) {
case CFFTag: /* All the non-collection tags */
case TrueTag:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh b/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh
index 4c9bfebcec..9c11f14344 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-open-type.hh
@@ -309,9 +309,11 @@ struct _hb_has_null<Type, true>
static Type *get_crap () { return &Crap (Type); }
};
-template <typename Type, typename OffsetType, bool has_null=true>
+template <typename Type, typename OffsetType, typename BaseType=void, bool has_null=true>
struct OffsetTo : Offset<OffsetType, has_null>
{
+ using target_t = Type;
+
// Make sure Type is not unbounded; works only for types that are fully defined at OffsetTo time.
static_assert (has_null == false ||
(hb_has_null_size (Type) || !hb_has_min_size (Type)), "");
@@ -333,22 +335,22 @@ struct OffsetTo : Offset<OffsetType, has_null>
}
template <typename Base,
- hb_enable_if (hb_is_convertible (const Base, const void *))>
+ hb_enable_if (hb_is_convertible (const Base, const BaseType *))>
friend const Type& operator + (const Base &base, const OffsetTo &offset) { return offset ((const void *) base); }
template <typename Base,
- hb_enable_if (hb_is_convertible (const Base, const void *))>
+ hb_enable_if (hb_is_convertible (const Base, const BaseType *))>
friend const Type& operator + (const OffsetTo &offset, const Base &base) { return offset ((const void *) base); }
template <typename Base,
- hb_enable_if (hb_is_convertible (Base, void *))>
+ hb_enable_if (hb_is_convertible (Base, BaseType *))>
friend Type& operator + (Base &&base, OffsetTo &offset) { return offset ((void *) base); }
template <typename Base,
- hb_enable_if (hb_is_convertible (Base, void *))>
+ hb_enable_if (hb_is_convertible (Base, BaseType *))>
friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); }
- template <typename ...Ts>
+ template <typename Base, typename ...Ts>
bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src,
- const void *src_base, Ts&&... ds)
+ const Base *src_base, Ts&&... ds)
{
*this = 0;
if (src.is_null ())
@@ -412,20 +414,25 @@ struct OffsetTo : Offset<OffsetType, has_null>
const void *src_base, unsigned dst_bias = 0)
{ return serialize_copy (c, src, src_base, dst_bias, hb_serialize_context_t::Head); }
- bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const
+ bool sanitize_shallow (hb_sanitize_context_t *c, const BaseType *base) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) return_trace (false);
- if (unlikely (this->is_null ())) return_trace (true);
+ hb_barrier ();
+ //if (unlikely (this->is_null ())) return_trace (true);
if (unlikely ((const char *) base + (unsigned) *this < (const char *) base)) return_trace (false);
return_trace (true);
}
template <typename ...Ts>
- bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
+ bool sanitize (hb_sanitize_context_t *c, const BaseType *base, Ts&&... ds) const
{
TRACE_SANITIZE (this);
return_trace (sanitize_shallow (c, base) &&
+ hb_barrier () &&
(this->is_null () ||
c->dispatch (StructAtOffset<Type> (base, *this), std::forward<Ts> (ds)...) ||
neuter (c)));
@@ -440,14 +447,14 @@ struct OffsetTo : Offset<OffsetType, has_null>
DEFINE_SIZE_STATIC (sizeof (OffsetType));
};
/* Partial specializations. */
-template <typename Type, bool has_null=true> using Offset16To = OffsetTo<Type, HBUINT16, has_null>;
-template <typename Type, bool has_null=true> using Offset24To = OffsetTo<Type, HBUINT24, has_null>;
-template <typename Type, bool has_null=true> using Offset32To = OffsetTo<Type, HBUINT32, has_null>;
+template <typename Type, typename BaseType=void, bool has_null=true> using Offset16To = OffsetTo<Type, HBUINT16, BaseType, has_null>;
+template <typename Type, typename BaseType=void, bool has_null=true> using Offset24To = OffsetTo<Type, HBUINT24, BaseType, has_null>;
+template <typename Type, typename BaseType=void, bool has_null=true> using Offset32To = OffsetTo<Type, HBUINT32, BaseType, has_null>;
-template <typename Type, typename OffsetType> using NNOffsetTo = OffsetTo<Type, OffsetType, false>;
-template <typename Type> using NNOffset16To = Offset16To<Type, false>;
-template <typename Type> using NNOffset24To = Offset24To<Type, false>;
-template <typename Type> using NNOffset32To = Offset32To<Type, false>;
+template <typename Type, typename OffsetType, typename BaseType=void> using NNOffsetTo = OffsetTo<Type, OffsetType, BaseType, false>;
+template <typename Type, typename BaseType=void> using NNOffset16To = Offset16To<Type, BaseType, false>;
+template <typename Type, typename BaseType=void> using NNOffset24To = Offset24To<Type, BaseType, false>;
+template <typename Type, typename BaseType=void> using NNOffset32To = Offset32To<Type, BaseType, false>;
/*
@@ -462,24 +469,16 @@ struct UnsizedArrayOf
HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf);
- const Type& operator [] (int i_) const
+ const Type& operator [] (unsigned int i) const
{
- unsigned int i = (unsigned int) i_;
- const Type *p = &arrayZ[i];
- if (unlikely ((const void *) p < (const void *) arrayZ)) return Null (Type); /* Overflowed. */
- _hb_compiler_memory_r_barrier ();
- return *p;
+ return arrayZ[i];
}
- Type& operator [] (int i_)
+ Type& operator [] (unsigned int i)
{
- unsigned int i = (unsigned int) i_;
- Type *p = &arrayZ[i];
- if (unlikely ((const void *) p < (const void *) arrayZ)) return Crap (Type); /* Overflowed. */
- _hb_compiler_memory_r_barrier ();
- return *p;
+ return arrayZ[i];
}
- unsigned int get_size (unsigned int len) const
+ static unsigned int get_size (unsigned int len)
{ return len * Type::static_size; }
template <typename T> operator T * () { return arrayZ; }
@@ -533,11 +532,13 @@ struct UnsizedArrayOf
}
template <typename ...Ts>
+ HB_ALWAYS_INLINE
bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
{
TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
+ hb_barrier ();
for (unsigned int i = 0; i < count; i++)
if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
return_trace (false);
@@ -557,17 +558,17 @@ struct UnsizedArrayOf
};
/* Unsized array of offset's */
-template <typename Type, typename OffsetType, bool has_null=true>
-using UnsizedArray16OfOffsetTo = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>;
+template <typename Type, typename OffsetType, typename BaseType=void, bool has_null=true>
+using UnsizedArray16OfOffsetTo = UnsizedArrayOf<OffsetTo<Type, OffsetType, BaseType, has_null>>;
/* Unsized array of offsets relative to the beginning of the array itself. */
-template <typename Type, typename OffsetType, bool has_null=true>
-struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_null>
+template <typename Type, typename OffsetType, typename BaseType=void, bool has_null=true>
+struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, BaseType, has_null>
{
const Type& operator [] (int i_) const
{
unsigned int i = (unsigned int) i_;
- const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
+ const OffsetTo<Type, OffsetType, BaseType, has_null> *p = &this->arrayZ[i];
if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Null (Type); /* Overflowed. */
_hb_compiler_memory_r_barrier ();
return this+*p;
@@ -575,7 +576,7 @@ struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_
Type& operator [] (int i_)
{
unsigned int i = (unsigned int) i_;
- const OffsetTo<Type, OffsetType, has_null> *p = &this->arrayZ[i];
+ const OffsetTo<Type, OffsetType, BaseType, has_null> *p = &this->arrayZ[i];
if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Crap (Type); /* Overflowed. */
_hb_compiler_memory_r_barrier ();
return this+*p;
@@ -585,7 +586,7 @@ struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_
bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
{
TRACE_SANITIZE (this);
- return_trace ((UnsizedArray16OfOffsetTo<Type, OffsetType, has_null>
+ return_trace ((UnsizedArray16OfOffsetTo<Type, OffsetType, BaseType, has_null>
::sanitize (c, count, this, std::forward<Ts> (ds)...)));
}
};
@@ -721,11 +722,13 @@ struct ArrayOf
}
template <typename ...Ts>
+ HB_ALWAYS_INLINE
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
{
TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return_trace (false);
if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
+ hb_barrier ();
unsigned int count = len;
for (unsigned int i = 0; i < count; i++)
if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
@@ -736,7 +739,9 @@ struct ArrayOf
bool sanitize_shallow (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (len.sanitize (c) && c->check_array (arrayZ, len));
+ return_trace (len.sanitize (c) &&
+ hb_barrier () &&
+ c->check_array_sized (arrayZ, len, sizeof (LenType)));
}
public:
@@ -797,7 +802,7 @@ template <typename Type>
using List16OfOffset16To = List16OfOffsetTo<Type, HBUINT16>;
/* An array starting at second element. */
-template <typename Type, typename LenType=HBUINT16>
+template <typename Type, typename LenType>
struct HeadlessArrayOf
{
static constexpr unsigned item_size = Type::static_size;
@@ -861,11 +866,13 @@ struct HeadlessArrayOf
}
template <typename ...Ts>
+ HB_ALWAYS_INLINE
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
{
TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return_trace (false);
if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
+ hb_barrier ();
unsigned int count = get_length ();
for (unsigned int i = 0; i < count; i++)
if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
@@ -878,7 +885,8 @@ struct HeadlessArrayOf
{
TRACE_SANITIZE (this);
return_trace (lenP1.sanitize (c) &&
- (!lenP1 || c->check_array (arrayZ, lenP1 - 1)));
+ hb_barrier () &&
+ (!lenP1 || c->check_array_sized (arrayZ, lenP1 - 1, sizeof (LenType))));
}
public:
@@ -887,6 +895,7 @@ struct HeadlessArrayOf
public:
DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
};
+template <typename Type> using HeadlessArray16Of = HeadlessArrayOf<Type, HBUINT16>;
/* An array storing length-1. */
template <typename Type, typename LenType=HBUINT16>
@@ -912,11 +921,13 @@ struct ArrayOfM1
{ return lenM1.static_size + (lenM1 + 1) * Type::static_size; }
template <typename ...Ts>
+ HB_ALWAYS_INLINE
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
{
TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return_trace (false);
if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
+ hb_barrier ();
unsigned int count = lenM1 + 1;
for (unsigned int i = 0; i < count; i++)
if (unlikely (!c->dispatch (arrayZ[i], std::forward<Ts> (ds)...)))
@@ -929,7 +940,8 @@ struct ArrayOfM1
{
TRACE_SANITIZE (this);
return_trace (lenM1.sanitize (c) &&
- (c->check_array (arrayZ, lenM1 + 1)));
+ hb_barrier () &&
+ (c->check_array_sized (arrayZ, lenM1 + 1, sizeof (LenType))));
}
public:
@@ -973,6 +985,13 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
return_trace (ret);
}
+ SortedArrayOf* copy (hb_serialize_context_t *c) const
+ {
+ TRACE_SERIALIZE (this);
+ SortedArrayOf* out = reinterpret_cast<SortedArrayOf *> (ArrayOf<Type, LenType>::copy (c));
+ return_trace (out);
+ }
+
template <typename T>
Type &bsearch (const T &x, Type &not_found = Crap (Type))
{ return *as_array ().bsearch (x, &not_found); }
@@ -1096,11 +1115,13 @@ struct VarSizedBinSearchArrayOf
{ return header.static_size + header.nUnits * header.unitSize; }
template <typename ...Ts>
+ HB_ALWAYS_INLINE
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
{
TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return_trace (false);
if (!sizeof... (Ts) && hb_is_trivially_copyable(Type)) return_trace (true);
+ hb_barrier ();
unsigned int count = get_length ();
for (unsigned int i = 0; i < count; i++)
if (unlikely (!(*this)[i].sanitize (c, std::forward<Ts> (ds)...)))
@@ -1127,6 +1148,7 @@ struct VarSizedBinSearchArrayOf
{
TRACE_SANITIZE (this);
return_trace (header.sanitize (c) &&
+ hb_barrier () &&
Type::static_size <= header.unitSize &&
c->check_range (bytesZ.arrayZ,
header.nUnits,
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh
index f22824fc69..c7c3264c08 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff-common.hh
@@ -41,19 +41,42 @@ using namespace OT;
using objidx_t = hb_serialize_context_t::objidx_t;
using whence_t = hb_serialize_context_t::whence_t;
-/* utility macro */
-template<typename Type>
-static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset)
-{ return offset ? StructAtOffset<Type> (P, offset) : Null (Type); }
+/* CFF offsets can technically be negative */
+template<typename Type, typename ...Ts>
+static inline const Type& StructAtOffsetOrNull (const void *P, int offset, hb_sanitize_context_t &sc, Ts&&... ds)
+{
+ if (!offset) return Null (Type);
+
+ const char *p = (const char *) P + offset;
+ if (!sc.check_point (p)) return Null (Type);
+
+ const Type &obj = *reinterpret_cast<const Type *> (p);
+ if (!obj.sanitize (&sc, std::forward<Ts> (ds)...)) return Null (Type);
+
+ return obj;
+}
+
struct code_pair_t
{
- hb_codepoint_t code;
+ unsigned code;
hb_codepoint_t glyph;
};
+
using str_buff_t = hb_vector_t<unsigned char>;
using str_buff_vec_t = hb_vector_t<str_buff_t>;
+using glyph_to_sid_map_t = hb_vector_t<code_pair_t>;
+
+struct length_f_t
+{
+ template <typename Iterable,
+ hb_requires (hb_is_iterable (Iterable))>
+ unsigned operator () (const Iterable &_) const { return hb_len (hb_iter (_)); }
+
+ unsigned operator () (unsigned _) const { return _; }
+}
+HB_FUNCOBJ (length_f);
/* CFF INDEX */
template <typename COUNT>
@@ -62,42 +85,55 @@ struct CFFIndex
unsigned int offset_array_size () const
{ return offSize * (count + 1); }
- CFFIndex *copy (hb_serialize_context_t *c) const
- {
- TRACE_SERIALIZE (this);
- unsigned int size = get_size ();
- CFFIndex *out = c->allocate_size<CFFIndex> (size, false);
- if (likely (out))
- hb_memcpy (out, this, size);
- return_trace (out);
- }
-
template <typename Iterable,
hb_requires (hb_is_iterable (Iterable))>
bool serialize (hb_serialize_context_t *c,
- const Iterable &iterable)
+ const Iterable &iterable,
+ const unsigned *p_data_size = nullptr,
+ unsigned min_off_size = 0)
{
TRACE_SERIALIZE (this);
+ unsigned data_size;
+ if (p_data_size)
+ data_size = *p_data_size;
+ else
+ total_size (iterable, &data_size);
+
auto it = hb_iter (iterable);
- serialize_header(c, + it | hb_map (hb_iter) | hb_map (hb_len));
+ if (unlikely (!serialize_header (c, +it, data_size, min_off_size))) return_trace (false);
+ unsigned char *ret = c->allocate_size<unsigned char> (data_size, false);
+ if (unlikely (!ret)) return_trace (false);
for (const auto &_ : +it)
- hb_iter (_).copy (c);
+ {
+ unsigned len = _.length;
+ if (!len)
+ continue;
+ if (len <= 1)
+ {
+ *ret++ = *_.arrayZ;
+ continue;
+ }
+ hb_memcpy (ret, _.arrayZ, len);
+ ret += len;
+ }
return_trace (true);
}
template <typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool serialize_header (hb_serialize_context_t *c,
- Iterator it)
+ Iterator it,
+ unsigned data_size,
+ unsigned min_off_size = 0)
{
TRACE_SERIALIZE (this);
- unsigned total = + it | hb_reduce (hb_add, 0);
- unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8;
+ unsigned off_size = (hb_bit_storage (data_size + 1) + 7) / 8;
+ off_size = hb_max(min_off_size, off_size);
/* serialize CFFIndex header */
if (unlikely (!c->extend_min (this))) return_trace (false);
- this->count = it.len ();
+ this->count = hb_len (it);
if (!this->count) return_trace (true);
if (unlikely (!c->extend (this->offSize))) return_trace (false);
this->offSize = off_size;
@@ -106,26 +142,90 @@ struct CFFIndex
/* serialize indices */
unsigned int offset = 1;
- unsigned int i = 0;
- for (unsigned _ : +it)
+ if (HB_OPTIMIZE_SIZE_VAL)
{
- set_offset_at (i++, offset);
- offset += _;
+ unsigned int i = 0;
+ for (const auto &_ : +it)
+ {
+ set_offset_at (i++, offset);
+ offset += length_f (_);
+ }
+ set_offset_at (i, offset);
}
- set_offset_at (i, offset);
-
+ else
+ switch (off_size)
+ {
+ case 1:
+ {
+ HBUINT8 *p = (HBUINT8 *) offsets;
+ for (const auto &_ : +it)
+ {
+ *p++ = offset;
+ offset += length_f (_);
+ }
+ *p = offset;
+ }
+ break;
+ case 2:
+ {
+ HBUINT16 *p = (HBUINT16 *) offsets;
+ for (const auto &_ : +it)
+ {
+ *p++ = offset;
+ offset += length_f (_);
+ }
+ *p = offset;
+ }
+ break;
+ case 3:
+ {
+ HBUINT24 *p = (HBUINT24 *) offsets;
+ for (const auto &_ : +it)
+ {
+ *p++ = offset;
+ offset += length_f (_);
+ }
+ *p = offset;
+ }
+ break;
+ case 4:
+ {
+ HBUINT32 *p = (HBUINT32 *) offsets;
+ for (const auto &_ : +it)
+ {
+ *p++ = offset;
+ offset += length_f (_);
+ }
+ *p = offset;
+ }
+ break;
+ default:
+ break;
+ }
+
+ assert (offset == data_size + 1);
return_trace (true);
}
template <typename Iterable,
hb_requires (hb_is_iterable (Iterable))>
- static unsigned total_size (const Iterable &iterable)
+ static unsigned total_size (const Iterable &iterable, unsigned *data_size = nullptr, unsigned min_off_size = 0)
{
- auto it = + hb_iter (iterable) | hb_map (hb_iter) | hb_map (hb_len);
- if (!it) return 0;
+ auto it = + hb_iter (iterable);
+ if (!it)
+ {
+ if (data_size) *data_size = 0;
+ return min_size;
+ }
+
+ unsigned total = 0;
+ for (const auto &_ : +it)
+ total += length_f (_);
+
+ if (data_size) *data_size = total;
- unsigned total = + it | hb_reduce (hb_add, 0);
unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8;
+ off_size = hb_max(min_off_size, off_size);
return min_size + HBUINT8::static_size + (hb_len (it) + 1) * off_size + total;
}
@@ -133,13 +233,16 @@ struct CFFIndex
void set_offset_at (unsigned int index, unsigned int offset)
{
assert (index <= count);
- HBUINT8 *p = offsets + offSize * index + offSize;
+
unsigned int size = offSize;
- for (; size; size--)
+ const HBUINT8 *p = offsets;
+ switch (size)
{
- --p;
- *p = offset & 0xFF;
- offset >>= 8;
+ case 1: ((HBUINT8 *) p)[index] = offset; break;
+ case 2: ((HBUINT16 *) p)[index] = offset; break;
+ case 3: ((HBUINT24 *) p)[index] = offset; break;
+ case 4: ((HBUINT32 *) p)[index] = offset; break;
+ default: return;
}
}
@@ -149,37 +252,30 @@ struct CFFIndex
assert (index <= count);
unsigned int size = offSize;
- const HBUINT8 *p = offsets + size * index;
+ const HBUINT8 *p = offsets;
switch (size)
{
- case 1: return * (HBUINT8 *) p;
- case 2: return * (HBUINT16 *) p;
- case 3: return * (HBUINT24 *) p;
- case 4: return * (HBUINT32 *) p;
+ case 1: return ((HBUINT8 *) p)[index];
+ case 2: return ((HBUINT16 *) p)[index];
+ case 3: return ((HBUINT24 *) p)[index];
+ case 4: return ((HBUINT32 *) p)[index];
default: return 0;
}
}
- unsigned int length_at (unsigned int index) const
- {
- unsigned offset0 = offset_at (index);
- unsigned offset1 = offset_at (index + 1);
- if (unlikely (offset1 < offset0 || offset1 > offset_at (count)))
- return 0;
- return offset1 - offset0;
- }
-
const unsigned char *data_base () const
- { return (const unsigned char *) this + min_size + offSize.static_size + offset_array_size (); }
+ { return (const unsigned char *) this + min_size + offSize.static_size - 1 + offset_array_size (); }
public:
hb_ubytes_t operator [] (unsigned int index) const
{
if (unlikely (index >= count)) return hb_ubytes_t ();
_hb_compiler_memory_r_barrier ();
- unsigned length = length_at (index);
- if (unlikely (!length)) return hb_ubytes_t ();
- return hb_ubytes_t (data_base () + offset_at (index) - 1, length);
+ unsigned offset0 = offset_at (index);
+ unsigned offset1 = offset_at (index + 1);
+ if (unlikely (offset1 < offset0 || offset1 > offset_at (count)))
+ return hb_ubytes_t ();
+ return hb_ubytes_t (data_base () + offset0, offset1 - offset0);
}
unsigned int get_size () const
@@ -193,11 +289,13 @@ struct CFFIndex
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
+ hb_barrier () &&
(count == 0 || /* empty INDEX */
(count < count + 1u &&
+ hb_barrier () &&
c->check_struct (&offSize) && offSize >= 1 && offSize <= 4 &&
c->check_array (offsets, offSize, count + 1u) &&
- c->check_array ((const HBUINT8*) data_base (), 1, offset_at (count) - 1)))));
+ c->check_array ((const HBUINT8*) data_base (), 1, offset_at (count))))));
}
public:
@@ -211,47 +309,6 @@ struct CFFIndex
DEFINE_SIZE_MIN (COUNT::static_size);
};
-template <typename COUNT, typename TYPE>
-struct CFFIndexOf : CFFIndex<COUNT>
-{
- template <typename DATA, typename PARAM1, typename PARAM2>
- bool serialize (hb_serialize_context_t *c,
- unsigned int offSize_,
- const DATA *dataArray,
- unsigned int dataArrayLen,
- const hb_vector_t<unsigned int> &dataSizeArray,
- const PARAM1 &param1,
- const PARAM2 &param2)
- {
- TRACE_SERIALIZE (this);
- /* serialize CFFIndex header */
- if (unlikely (!c->extend_min (this))) return_trace (false);
- this->count = dataArrayLen;
- this->offSize = offSize_;
- if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1), false)))
- return_trace (false);
-
- /* serialize indices */
- unsigned int offset = 1;
- unsigned int i = 0;
- for (; i < dataArrayLen; i++)
- {
- this->set_offset_at (i, offset);
- offset += dataSizeArray[i];
- }
- this->set_offset_at (i, offset);
-
- /* serialize data */
- for (unsigned int i = 0; i < dataArrayLen; i++)
- {
- TYPE *dest = c->start_embed<TYPE> ();
- if (unlikely (!dest || !dest->serialize (c, dataArray[i], param1, param2)))
- return_trace (false);
- }
- return_trace (true);
- }
-};
-
/* Top Dict, Font Dict, Private Dict */
struct Dict : UnsizedByteStr
{
@@ -327,7 +384,7 @@ struct table_info_t
};
template <typename COUNT>
-struct FDArray : CFFIndexOf<COUNT, FontDict>
+struct FDArray : CFFIndex<COUNT>
{
template <typename DICTVAL, typename INFO, typename Iterator, typename OP_SERIALIZER>
bool serialize (hb_serialize_context_t *c,
@@ -338,7 +395,11 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
/* serialize INDEX data */
hb_vector_t<unsigned> sizes;
+ if (it.is_random_access_iterator)
+ sizes.alloc (hb_len (it));
+
c->push ();
+ char *data_base = c->head;
+ it
| hb_map ([&] (const hb_pair_t<const DICTVAL&, const INFO&> &_)
{
@@ -348,10 +409,16 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
})
| hb_sink (sizes)
;
+ unsigned data_size = c->head - data_base;
c->pop_pack (false);
+ if (unlikely (sizes.in_error ())) return_trace (false);
+
+ /* It just happens that the above is packed right after the header below.
+ * Such a hack. */
+
/* serialize INDEX header */
- return_trace (CFFIndex<COUNT>::serialize_header (c, hb_iter (sizes)));
+ return_trace (CFFIndex<COUNT>::serialize_header (c, hb_iter (sizes), data_size));
}
};
@@ -362,14 +429,18 @@ struct FDSelect0 {
TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this))))
return_trace (false);
+ hb_barrier ();
if (unlikely (!c->check_array (fds, c->get_num_glyphs ())))
return_trace (false);
return_trace (true);
}
- hb_codepoint_t get_fd (hb_codepoint_t glyph) const
- { return (hb_codepoint_t) fds[glyph]; }
+ unsigned get_fd (hb_codepoint_t glyph) const
+ { return fds[glyph]; }
+
+ hb_pair_t<unsigned, hb_codepoint_t> get_fd_range (hb_codepoint_t glyph) const
+ { return {fds[glyph], glyph + 1}; }
unsigned int get_size (unsigned int num_glyphs) const
{ return HBUINT8::static_size * num_glyphs; }
@@ -385,7 +456,9 @@ struct FDSelect3_4_Range
bool sanitize (hb_sanitize_context_t *c, const void * /*nullptr*/, unsigned int fdcount) const
{
TRACE_SANITIZE (this);
- return_trace (first < c->get_num_glyphs () && (fd < fdcount));
+ return_trace (c->check_struct (this) &&
+ hb_barrier () &&
+ first < c->get_num_glyphs () && (fd < fdcount));
}
GID_TYPE first;
@@ -403,15 +476,20 @@ struct FDSelect3_4
bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
{
TRACE_SANITIZE (this);
- if (unlikely (!c->check_struct (this) || !ranges.sanitize (c, nullptr, fdcount) ||
- (nRanges () == 0) || ranges[0].first != 0))
+ if (unlikely (!(c->check_struct (this) &&
+ ranges.sanitize (c, nullptr, fdcount) &&
+ hb_barrier () &&
+ (nRanges () != 0) &&
+ ranges[0].first == 0)))
return_trace (false);
for (unsigned int i = 1; i < nRanges (); i++)
if (unlikely (ranges[i - 1].first >= ranges[i].first))
return_trace (false);
- if (unlikely (!sentinel().sanitize (c) || (sentinel() != c->get_num_glyphs ())))
+ if (unlikely (!(sentinel().sanitize (c) &&
+ hb_barrier () &&
+ (sentinel() == c->get_num_glyphs ()))))
return_trace (false);
return_trace (true);
@@ -427,12 +505,20 @@ struct FDSelect3_4
return +1;
}
- hb_codepoint_t get_fd (hb_codepoint_t glyph) const
+ unsigned get_fd (hb_codepoint_t glyph) const
{
auto *range = hb_bsearch (glyph, &ranges[0], nRanges () - 1, sizeof (ranges[0]), _cmp_range);
return range ? range->fd : ranges[nRanges () - 1].fd;
}
+ hb_pair_t<unsigned, hb_codepoint_t> get_fd_range (hb_codepoint_t glyph) const
+ {
+ auto *range = hb_bsearch (glyph, &ranges[0], nRanges () - 1, sizeof (ranges[0]), _cmp_range);
+ unsigned fd = range ? range->fd : ranges[nRanges () - 1].fd;
+ hb_codepoint_t end = range ? range[1].first : ranges[nRanges () - 1].first;
+ return {fd, end};
+ }
+
GID_TYPE &nRanges () { return ranges.len; }
GID_TYPE nRanges () const { return ranges.len; }
GID_TYPE &sentinel () { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); }
@@ -469,7 +555,7 @@ struct FDSelect
}
}
- hb_codepoint_t get_fd (hb_codepoint_t glyph) const
+ unsigned get_fd (hb_codepoint_t glyph) const
{
if (this == &Null (FDSelect)) return 0;
@@ -480,12 +566,25 @@ struct FDSelect
default:return 0;
}
}
+ /* Returns pair of fd and one after last glyph in range. */
+ hb_pair_t<unsigned, hb_codepoint_t> get_fd_range (hb_codepoint_t glyph) const
+ {
+ if (this == &Null (FDSelect)) return {0, 1};
+
+ switch (format)
+ {
+ case 0: return u.format0.get_fd_range (glyph);
+ case 3: return u.format3.get_fd_range (glyph);
+ default:return {0, 1};
+ }
+ }
bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
+ hb_barrier ();
switch (format)
{
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.cc
index 5040c74623..66df28aae1 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.cc
@@ -574,11 +574,11 @@ bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, h
struct get_seac_param_t
{
- get_seac_param_t (const OT::cff1::accelerator_t *_cff) : cff (_cff) {}
+ get_seac_param_t (const OT::cff1::accelerator_subset_t *_cff) : cff (_cff) {}
bool has_seac () const { return base && accent; }
- const OT::cff1::accelerator_t *cff;
+ const OT::cff1::accelerator_subset_t *cff;
hb_codepoint_t base = 0;
hb_codepoint_t accent = 0;
};
@@ -596,7 +596,7 @@ struct cff1_cs_opset_seac_t : cff1_cs_opset_t<cff1_cs_opset_seac_t, get_seac_par
}
};
-bool OT::cff1::accelerator_t::get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const
+bool OT::cff1::accelerator_subset_t::get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const
{
if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh
index f461a23044..1bbd463841 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff1-table.hh
@@ -28,7 +28,7 @@
#define HB_OT_CFF1_TABLE_HH
#include "hb-ot-cff-common.hh"
-#include "hb-subset-cff1.hh"
+#include "hb-subset-cff-common.hh"
#include "hb-draw.hh"
#include "hb-paint.hh"
@@ -44,7 +44,7 @@ namespace CFF {
* CFF -- Compact Font Format (CFF)
* https://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf
*/
-#define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ')
+#define HB_OT_TAG_CFF1 HB_TAG('C','F','F',' ')
#define CFF_UNDEF_SID CFF_UNDEF_CODE
@@ -52,7 +52,6 @@ enum EncodingID { StandardEncoding = 0, ExpertEncoding = 1 };
enum CharsetID { ISOAdobeCharset = 0, ExpertCharset = 1, ExpertSubsetCharset = 2 };
typedef CFFIndex<HBUINT16> CFF1Index;
-template <typename Type> struct CFF1IndexOf : CFFIndexOf<HBUINT16, Type> {};
typedef CFFIndex<HBUINT16> CFF1Index;
typedef CFF1Index CFF1CharStrings;
@@ -110,6 +109,7 @@ struct Encoding1 {
hb_codepoint_t get_code (hb_codepoint_t glyph) const
{
+ /* TODO: Add cache like get_sid. */
assert (glyph > 0);
glyph--;
for (unsigned int i = 0; i < nRanges (); i++)
@@ -173,11 +173,7 @@ struct Encoding
bool serialize (hb_serialize_context_t *c, const Encoding &src)
{
TRACE_SERIALIZE (this);
- unsigned int size = src.get_size ();
- Encoding *dest = c->allocate_size<Encoding> (size);
- if (unlikely (!dest)) return_trace (false);
- hb_memcpy (dest, &src, size);
- return_trace (true);
+ return_trace (c->embed (src));
}
/* serialize a subset Encoding */
@@ -279,6 +275,7 @@ struct Encoding
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
+ hb_barrier ();
switch (table_format ())
{
@@ -312,26 +309,29 @@ struct Encoding
};
/* Charset */
-struct Charset0 {
- bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const
+struct Charset0
+{
+ bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs, unsigned *num_charset_entries) const
{
TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) && sids[num_glyphs - 1].sanitize (c));
+ if (num_charset_entries) *num_charset_entries = num_glyphs;
+ return_trace (sids.sanitize (c, num_glyphs - 1));
}
hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs) const
{
if (unlikely (glyph >= num_glyphs)) return 0;
- if (glyph == 0)
+ if (unlikely (glyph == 0))
return 0;
else
return sids[glyph - 1];
}
- void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const
+ void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const
{
+ mapping->resize (num_glyphs, false);
for (hb_codepoint_t gid = 1; gid < num_glyphs; gid++)
- mapping->set (gid, sids[gid - 1]);
+ mapping->arrayZ[gid] = {sids[gid - 1], gid};
}
hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const
@@ -347,13 +347,13 @@ struct Charset0 {
return 0;
}
- unsigned int get_size (unsigned int num_glyphs) const
+ static unsigned int get_size (unsigned int num_glyphs)
{
assert (num_glyphs > 0);
- return HBUINT16::static_size * (num_glyphs - 1);
+ return UnsizedArrayOf<HBUINT16>::get_size (num_glyphs - 1);
}
- HBUINT16 sids[HB_VAR_ARRAY];
+ UnsizedArrayOf<HBUINT16> sids;
DEFINE_SIZE_ARRAY(0, sids);
};
@@ -374,38 +374,62 @@ struct Charset_Range {
template <typename TYPE>
struct Charset1_2 {
- bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const
+ bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs, unsigned *num_charset_entries) const
{
TRACE_SANITIZE (this);
- if (unlikely (!c->check_struct (this)))
- return_trace (false);
num_glyphs--;
- for (unsigned int i = 0; num_glyphs > 0; i++)
+ unsigned i;
+ for (i = 0; num_glyphs > 0; i++)
{
- if (unlikely (!ranges[i].sanitize (c) || (num_glyphs < ranges[i].nLeft + 1)))
+ if (unlikely (!(ranges[i].sanitize (c) &&
+ hb_barrier () &&
+ (num_glyphs >= ranges[i].nLeft + 1))))
return_trace (false);
num_glyphs -= (ranges[i].nLeft + 1);
}
+ if (num_charset_entries)
+ *num_charset_entries = i;
return_trace (true);
}
- hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs) const
+ hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned num_glyphs,
+ code_pair_t *cache = nullptr) const
{
if (unlikely (glyph >= num_glyphs)) return 0;
- if (glyph == 0) return 0;
- glyph--;
- for (unsigned int i = 0;; i++)
+ unsigned i;
+ hb_codepoint_t start_glyph;
+ if (cache && likely (cache->glyph <= glyph))
{
- if (glyph <= ranges[i].nLeft)
- return (hb_codepoint_t) ranges[i].first + glyph;
- glyph -= (ranges[i].nLeft + 1);
+ i = cache->code;
+ start_glyph = cache->glyph;
+ }
+ else
+ {
+ if (unlikely (glyph == 0)) return 0;
+ i = 0;
+ start_glyph = 1;
+ }
+ glyph -= start_glyph;
+ for (;; i++)
+ {
+ unsigned count = ranges[i].nLeft;
+ if (glyph <= count)
+ {
+ if (cache)
+ *cache = {i, start_glyph};
+ return ranges[i].first + glyph;
+ }
+ count++;
+ start_glyph += count;
+ glyph -= count;
}
return 0;
}
- void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const
+ void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const
{
+ mapping->resize (num_glyphs, false);
hb_codepoint_t gid = 1;
if (gid >= num_glyphs)
return;
@@ -413,8 +437,9 @@ struct Charset1_2 {
{
hb_codepoint_t sid = ranges[i].first;
unsigned count = ranges[i].nLeft + 1;
+ unsigned last = gid + count;
for (unsigned j = 0; j < count; j++)
- mapping->set (gid++, sid++);
+ mapping->arrayZ[gid++] = {sid++, last - 1};
if (gid >= num_glyphs)
break;
@@ -439,21 +464,26 @@ struct Charset1_2 {
unsigned int get_size (unsigned int num_glyphs) const
{
- unsigned int size = HBUINT8::static_size;
- int glyph = (int)num_glyphs;
+ int glyph = (int) num_glyphs;
+ unsigned num_ranges = 0;
assert (glyph > 0);
glyph--;
for (unsigned int i = 0; glyph > 0; i++)
{
glyph -= (ranges[i].nLeft + 1);
- size += Charset_Range<TYPE>::static_size;
+ num_ranges++;
}
- return size;
+ return get_size_for_ranges (num_ranges);
+ }
+
+ static unsigned int get_size_for_ranges (unsigned int num_ranges)
+ {
+ return UnsizedArrayOf<Charset_Range<TYPE> >::get_size (num_ranges);
}
- Charset_Range<TYPE> ranges[HB_VAR_ARRAY];
+ UnsizedArrayOf<Charset_Range<TYPE>> ranges;
DEFINE_SIZE_ARRAY (0, ranges);
};
@@ -469,11 +499,7 @@ struct Charset
bool serialize (hb_serialize_context_t *c, const Charset &src, unsigned int num_glyphs)
{
TRACE_SERIALIZE (this);
- unsigned int size = src.get_size (num_glyphs);
- Charset *dest = c->allocate_size<Charset> (size);
- if (unlikely (!dest)) return_trace (false);
- hb_memcpy (dest, &src, size);
- return_trace (true);
+ return_trace (c->embed ((const char *) &src, src.get_size (num_glyphs)));
}
/* serialize a subset Charset */
@@ -490,13 +516,13 @@ struct Charset
{
case 0:
{
- Charset0 *fmt0 = c->allocate_size<Charset0> (Charset0::min_size + HBUINT16::static_size * (num_glyphs - 1));
+ Charset0 *fmt0 = c->allocate_size<Charset0> (Charset0::get_size (num_glyphs), false);
if (unlikely (!fmt0)) return_trace (false);
unsigned int glyph = 0;
for (unsigned int i = 0; i < sid_ranges.length; i++)
{
- hb_codepoint_t sid = sid_ranges[i].code;
- for (int left = (int)sid_ranges[i].glyph; left >= 0; left--)
+ hb_codepoint_t sid = sid_ranges.arrayZ[i].code;
+ for (int left = (int)sid_ranges.arrayZ[i].glyph; left >= 0; left--)
fmt0->sids[glyph++] = sid++;
}
}
@@ -504,29 +530,35 @@ struct Charset
case 1:
{
- Charset1 *fmt1 = c->allocate_size<Charset1> (Charset1::min_size + Charset1_Range::static_size * sid_ranges.length);
+ Charset1 *fmt1 = c->allocate_size<Charset1> (Charset1::get_size_for_ranges (sid_ranges.length), false);
if (unlikely (!fmt1)) return_trace (false);
+ hb_codepoint_t all_glyphs = 0;
for (unsigned int i = 0; i < sid_ranges.length; i++)
{
- if (unlikely (!(sid_ranges[i].glyph <= 0xFF)))
- return_trace (false);
- fmt1->ranges[i].first = sid_ranges[i].code;
- fmt1->ranges[i].nLeft = sid_ranges[i].glyph;
+ auto &_ = sid_ranges.arrayZ[i];
+ all_glyphs |= _.glyph;
+ fmt1->ranges[i].first = _.code;
+ fmt1->ranges[i].nLeft = _.glyph;
}
+ if (unlikely (!(all_glyphs <= 0xFF)))
+ return_trace (false);
}
break;
case 2:
{
- Charset2 *fmt2 = c->allocate_size<Charset2> (Charset2::min_size + Charset2_Range::static_size * sid_ranges.length);
+ Charset2 *fmt2 = c->allocate_size<Charset2> (Charset2::get_size_for_ranges (sid_ranges.length), false);
if (unlikely (!fmt2)) return_trace (false);
+ hb_codepoint_t all_glyphs = 0;
for (unsigned int i = 0; i < sid_ranges.length; i++)
{
- if (unlikely (!(sid_ranges[i].glyph <= 0xFFFF)))
- return_trace (false);
- fmt2->ranges[i].first = sid_ranges[i].code;
- fmt2->ranges[i].nLeft = sid_ranges[i].glyph;
+ auto &_ = sid_ranges.arrayZ[i];
+ all_glyphs |= _.glyph;
+ fmt2->ranges[i].first = _.code;
+ fmt2->ranges[i].nLeft = _.glyph;
}
+ if (unlikely (!(all_glyphs <= 0xFFFF)))
+ return_trace (false);
}
break;
@@ -545,18 +577,19 @@ struct Charset
}
}
- hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned int num_glyphs) const
+ hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned int num_glyphs,
+ code_pair_t *cache = nullptr) const
{
switch (format)
{
case 0: return u.format0.get_sid (glyph, num_glyphs);
- case 1: return u.format1.get_sid (glyph, num_glyphs);
- case 2: return u.format2.get_sid (glyph, num_glyphs);
+ case 1: return u.format1.get_sid (glyph, num_glyphs, cache);
+ case 2: return u.format2.get_sid (glyph, num_glyphs, cache);
default:return 0;
}
}
- void collect_glyph_to_sid_map (hb_map_t *mapping, unsigned int num_glyphs) const
+ void collect_glyph_to_sid_map (glyph_to_sid_map_t *mapping, unsigned int num_glyphs) const
{
switch (format)
{
@@ -578,17 +611,18 @@ struct Charset
}
}
- bool sanitize (hb_sanitize_context_t *c) const
+ bool sanitize (hb_sanitize_context_t *c, unsigned *num_charset_entries) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
+ hb_barrier ();
switch (format)
{
- case 0: return_trace (u.format0.sanitize (c, c->get_num_glyphs ()));
- case 1: return_trace (u.format1.sanitize (c, c->get_num_glyphs ()));
- case 2: return_trace (u.format2.sanitize (c, c->get_num_glyphs ()));
+ case 0: return_trace (u.format0.sanitize (c, c->get_num_glyphs (), num_charset_entries));
+ case 1: return_trace (u.format1.sanitize (c, c->get_num_glyphs (), num_charset_entries));
+ case 2: return_trace (u.format2.sanitize (c, c->get_num_glyphs (), num_charset_entries));
default:return_trace (false);
}
}
@@ -606,10 +640,10 @@ struct Charset
struct CFF1StringIndex : CFF1Index
{
bool serialize (hb_serialize_context_t *c, const CFF1StringIndex &strings,
- const hb_inc_bimap_t &sidmap)
+ const hb_vector_t<unsigned> &sidmap)
{
TRACE_SERIALIZE (this);
- if (unlikely ((strings.count == 0) || (sidmap.get_population () == 0)))
+ if (unlikely ((strings.count == 0) || (sidmap.length == 0)))
{
if (unlikely (!c->extend_min (this->count)))
return_trace (false);
@@ -617,15 +651,13 @@ struct CFF1StringIndex : CFF1Index
return_trace (true);
}
- byte_str_array_t bytesArray;
- if (!bytesArray.resize (sidmap.get_population ()))
- return_trace (false);
- for (unsigned int i = 0; i < strings.count; i++)
- {
- hb_codepoint_t j = sidmap[i];
- if (j != HB_MAP_VALUE_INVALID)
- bytesArray[j] = strings[i];
- }
+ if (unlikely (sidmap.in_error ())) return_trace (false);
+
+ // Save this in a vector since serialize() iterates it twice.
+ hb_vector_t<hb_ubytes_t> bytesArray (+ hb_iter (sidmap)
+ | hb_map (strings));
+
+ if (unlikely (bytesArray.in_error ())) return_trace (false);
bool result = CFF1Index::serialize (c, bytesArray);
return_trace (result);
@@ -731,9 +763,9 @@ struct cff1_top_dict_values_t : top_dict_values_t<cff1_top_dict_val_t>
unsigned int ros_supplement;
unsigned int cidCount;
- unsigned int EncodingOffset;
- unsigned int CharsetOffset;
- unsigned int FDSelectOffset;
+ int EncodingOffset;
+ int CharsetOffset;
+ int FDSelectOffset;
table_info_t privateDictInfo;
};
@@ -789,24 +821,24 @@ struct cff1_top_dict_opset_t : top_dict_opset_t<cff1_top_dict_val_t>
break;
case OpCode_Encoding:
- dictval.EncodingOffset = env.argStack.pop_uint ();
+ dictval.EncodingOffset = env.argStack.pop_int ();
env.clear_args ();
if (unlikely (dictval.EncodingOffset == 0)) return;
break;
case OpCode_charset:
- dictval.CharsetOffset = env.argStack.pop_uint ();
+ dictval.CharsetOffset = env.argStack.pop_int ();
env.clear_args ();
if (unlikely (dictval.CharsetOffset == 0)) return;
break;
case OpCode_FDSelect:
- dictval.FDSelectOffset = env.argStack.pop_uint ();
+ dictval.FDSelectOffset = env.argStack.pop_int ();
env.clear_args ();
break;
case OpCode_Private:
- dictval.privateDictInfo.offset = env.argStack.pop_uint ();
+ dictval.privateDictInfo.offset = env.argStack.pop_int ();
dictval.privateDictInfo.size = env.argStack.pop_uint ();
env.clear_args ();
break;
@@ -881,7 +913,7 @@ struct cff1_private_dict_values_base_t : dict_values_t<VAL>
}
void fini () { dict_values_t<VAL>::fini (); }
- unsigned int subrsOffset;
+ int subrsOffset;
const CFF1Subrs *localSubrs;
};
@@ -916,7 +948,7 @@ struct cff1_private_dict_opset_t : dict_opset_t
env.clear_args ();
break;
case OpCode_Subrs:
- dictval.subrsOffset = env.argStack.pop_uint ();
+ dictval.subrsOffset = env.argStack.pop_int ();
env.clear_args ();
break;
@@ -932,7 +964,7 @@ struct cff1_private_dict_opset_t : dict_opset_t
}
};
-struct cff1_private_dict_opset_subset : dict_opset_t
+struct cff1_private_dict_opset_subset_t : dict_opset_t
{
static void process_op (op_code_t op, num_interp_env_t& env, cff1_private_dict_values_subset_t& dictval)
{
@@ -958,7 +990,7 @@ struct cff1_private_dict_opset_subset : dict_opset_t
break;
case OpCode_Subrs:
- dictval.subrsOffset = env.argStack.pop_uint ();
+ dictval.subrsOffset = env.argStack.pop_int ();
env.clear_args ();
break;
@@ -978,7 +1010,7 @@ typedef dict_interpreter_t<cff1_top_dict_opset_t, cff1_top_dict_values_t, cff1_t
typedef dict_interpreter_t<cff1_font_dict_opset_t, cff1_font_dict_values_t> cff1_font_dict_interpreter_t;
typedef CFF1Index CFF1NameIndex;
-typedef CFF1IndexOf<TopDict> CFF1TopDictIndex;
+typedef CFF1Index CFF1TopDictIndex;
struct cff1_font_dict_values_mod_t
{
@@ -1019,20 +1051,25 @@ using namespace CFF;
struct cff1
{
- static constexpr hb_tag_t tableTag = HB_OT_TAG_cff1;
+ static constexpr hb_tag_t tableTag = HB_OT_TAG_CFF1;
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
likely (version.major == 1));
}
template <typename PRIVOPSET, typename PRIVDICTVAL>
struct accelerator_templ_t
{
- void init (hb_face_t *face)
+ static constexpr hb_tag_t tableTag = cff1::tableTag;
+
+ accelerator_templ_t (hb_face_t *face)
{
+ if (!face) return;
+
topDict.init ();
fontDicts.init ();
privateDicts.init ();
@@ -1046,40 +1083,43 @@ struct cff1
const OT::cff1 *cff = this->blob->template as<OT::cff1> ();
if (cff == &Null (OT::cff1))
- { fini (); return; }
+ goto fail;
nameIndex = &cff->nameIndex (cff);
if ((nameIndex == &Null (CFF1NameIndex)) || !nameIndex->sanitize (&sc))
- { fini (); return; }
+ goto fail;
+ hb_barrier ();
- topDictIndex = &StructAtOffset<CFF1TopDictIndex> (nameIndex, nameIndex->get_size ());
- if ((topDictIndex == &Null (CFF1TopDictIndex)) || !topDictIndex->sanitize (&sc) || (topDictIndex->count == 0))
- { fini (); return; }
+ topDictIndex = &StructAtOffsetOrNull<CFF1TopDictIndex> (nameIndex, nameIndex->get_size (), sc);
+ if (topDictIndex == &Null (CFF1TopDictIndex) || (topDictIndex->count == 0))
+ goto fail;
+ hb_barrier ();
{ /* parse top dict */
const hb_ubytes_t topDictStr = (*topDictIndex)[0];
- if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; }
+ if (unlikely (!topDictStr.sanitize (&sc))) goto fail;
+ hb_barrier ();
cff1_top_dict_interp_env_t env (topDictStr);
cff1_top_dict_interpreter_t top_interp (env);
- if (unlikely (!top_interp.interpret (topDict))) { fini (); return; }
+ if (unlikely (!top_interp.interpret (topDict))) goto fail;
}
if (is_predef_charset ())
charset = &Null (Charset);
else
{
- charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset);
- if (unlikely ((charset == &Null (Charset)) || !charset->sanitize (&sc))) { fini (); return; }
+ charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset, sc, &num_charset_entries);
+ if (unlikely (charset == &Null (Charset))) goto fail;
}
fdCount = 1;
if (is_CID ())
{
- fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDict.FDArrayOffset);
- fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset);
- if (unlikely ((fdArray == &Null (CFF1FDArray)) || !fdArray->sanitize (&sc) ||
- (fdSelect == &Null (CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count)))
- { fini (); return; }
+ fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDict.FDArrayOffset, sc);
+ fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset, sc, fdArray->count);
+ if (unlikely (fdArray == &Null (CFF1FDArray) ||
+ fdSelect == &Null (CFF1FDSelect)))
+ goto fail;
fdCount = fdArray->count;
}
@@ -1092,36 +1132,32 @@ struct cff1
encoding = &Null (Encoding);
if (is_CID ())
{
- if (unlikely (charset == &Null (Charset))) { fini (); return; }
+ if (unlikely (charset == &Null (Charset))) goto fail;
}
else
{
if (!is_predef_encoding ())
{
- encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset);
- if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) { fini (); return; }
+ encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset, sc);
+ if (unlikely (encoding == &Null (Encoding))) goto fail;
}
}
- stringIndex = &StructAtOffset<CFF1StringIndex> (topDictIndex, topDictIndex->get_size ());
- if ((stringIndex == &Null (CFF1StringIndex)) || !stringIndex->sanitize (&sc))
- { fini (); return; }
-
- globalSubrs = &StructAtOffset<CFF1Subrs> (stringIndex, stringIndex->get_size ());
- if ((globalSubrs != &Null (CFF1Subrs)) && !globalSubrs->sanitize (&sc))
- { fini (); return; }
+ stringIndex = &StructAtOffsetOrNull<CFF1StringIndex> (topDictIndex, topDictIndex->get_size (), sc);
+ if (stringIndex == &Null (CFF1StringIndex))
+ goto fail;
- charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset);
-
- if ((charStrings == &Null (CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc)))
- { fini (); return; }
+ globalSubrs = &StructAtOffsetOrNull<CFF1Subrs> (stringIndex, stringIndex->get_size (), sc);
+ charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset, sc);
+ if (charStrings == &Null (CFF1CharStrings))
+ goto fail;
num_glyphs = charStrings->count;
if (num_glyphs != sc.get_num_glyphs ())
- { fini (); return; }
+ goto fail;
if (unlikely (!privateDicts.resize (fdCount)))
- { fini (); return; }
+ goto fail;
for (unsigned int i = 0; i < fdCount; i++)
privateDicts[i].init ();
@@ -1131,27 +1167,24 @@ struct cff1
for (unsigned int i = 0; i < fdCount; i++)
{
hb_ubytes_t fontDictStr = (*fdArray)[i];
- if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; }
+ if (unlikely (!fontDictStr.sanitize (&sc))) goto fail;
+ hb_barrier ();
cff1_font_dict_values_t *font;
cff1_top_dict_interp_env_t env (fontDictStr);
cff1_font_dict_interpreter_t font_interp (env);
font = fontDicts.push ();
- if (unlikely (fontDicts.in_error ())) { fini (); return; }
+ if (unlikely (fontDicts.in_error ())) goto fail;
font->init ();
- if (unlikely (!font_interp.interpret (*font))) { fini (); return; }
+ if (unlikely (!font_interp.interpret (*font))) goto fail;
PRIVDICTVAL *priv = &privateDicts[i];
- const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
- if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
+ const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
num_interp_env_t env2 (privDictStr);
dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env2);
priv->init ();
- if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
+ if (unlikely (!priv_interp.interpret (*priv))) goto fail;
- priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset);
- if (priv->localSubrs != &Null (CFF1Subrs) &&
- unlikely (!priv->localSubrs->sanitize (&sc)))
- { fini (); return; }
+ priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset, sc);
}
}
else /* non-CID */
@@ -1159,21 +1192,23 @@ struct cff1
cff1_top_dict_values_t *font = &topDict;
PRIVDICTVAL *priv = &privateDicts[0];
- const hb_ubytes_t privDictStr = StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
- if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
+ const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
num_interp_env_t env (privDictStr);
dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env);
priv->init ();
- if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
+ if (unlikely (!priv_interp.interpret (*priv))) goto fail;
- priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset);
- if (priv->localSubrs != &Null (CFF1Subrs) &&
- unlikely (!priv->localSubrs->sanitize (&sc)))
- { fini (); return; }
+ priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (&privDictStr, priv->subrsOffset, sc);
+ hb_barrier ();
}
- }
- void fini ()
+ return;
+
+ fail:
+ _fini ();
+ }
+ ~accelerator_templ_t () { _fini (); }
+ void _fini ()
{
sc.end_processing ();
topDict.fini ();
@@ -1183,6 +1218,8 @@ struct cff1
blob = nullptr;
}
+ hb_blob_t *get_blob () const { return blob; }
+
bool is_valid () const { return blob; }
bool is_CID () const { return topDict.is_CID (); }
@@ -1203,13 +1240,14 @@ struct cff1
bool is_predef_encoding () const { return topDict.EncodingOffset <= ExpertEncoding; }
- hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const
+ hb_codepoint_t glyph_to_code (hb_codepoint_t glyph,
+ code_pair_t *glyph_to_sid_cache = nullptr) const
{
if (encoding != &Null (Encoding))
return encoding->get_code (glyph);
else
{
- hb_codepoint_t sid = glyph_to_sid (glyph);
+ hb_codepoint_t sid = glyph_to_sid (glyph, glyph_to_sid_cache);
if (sid == 0) return 0;
hb_codepoint_t code = 0;
switch (topDict.EncodingOffset)
@@ -1227,12 +1265,14 @@ struct cff1
}
}
- hb_map_t *create_glyph_to_sid_map () const
+ glyph_to_sid_map_t *create_glyph_to_sid_map () const
{
if (charset != &Null (Charset))
{
- hb_map_t *mapping = hb_map_create ();
- mapping->set (0, 0);
+ auto *mapping = (glyph_to_sid_map_t *) hb_malloc (sizeof (glyph_to_sid_map_t));
+ if (unlikely (!mapping)) return nullptr;
+ mapping = new (mapping) glyph_to_sid_map_t ();
+ mapping->push (code_pair_t {0, 1});
charset->collect_glyph_to_sid_map (mapping, num_glyphs);
return mapping;
}
@@ -1240,10 +1280,11 @@ struct cff1
return nullptr;
}
- hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const
+ hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph,
+ code_pair_t *cache = nullptr) const
{
if (charset != &Null (Charset))
- return charset->get_sid (glyph, num_glyphs);
+ return charset->get_sid (glyph, num_glyphs, cache);
else
{
hb_codepoint_t sid = 0;
@@ -1312,19 +1353,17 @@ struct cff1
hb_vector_t<PRIVDICTVAL> privateDicts;
unsigned int num_glyphs = 0;
+ unsigned int num_charset_entries = 0;
};
struct accelerator_t : accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t>
{
- accelerator_t (hb_face_t *face)
+ accelerator_t (hb_face_t *face) : SUPER (face)
{
- SUPER::init (face);
-
glyph_names.set_relaxed (nullptr);
if (!is_valid ()) return;
if (is_CID ()) return;
-
}
~accelerator_t ()
{
@@ -1334,8 +1373,6 @@ struct cff1
names->fini ();
hb_free (names);
}
-
- SUPER::fini ();
}
bool get_glyph_name (hb_codepoint_t glyph,
@@ -1379,16 +1416,17 @@ struct cff1
hb_sorted_vector_t<gname_t> *names = glyph_names.get_acquire ();
if (unlikely (!names))
{
- names = (hb_sorted_vector_t<gname_t> *) hb_calloc (sizeof (hb_sorted_vector_t<gname_t>), 1);
+ names = (hb_sorted_vector_t<gname_t> *) hb_calloc (1, sizeof (hb_sorted_vector_t<gname_t>));
if (likely (names))
{
names->init ();
/* TODO */
/* fill glyph names */
+ code_pair_t glyph_to_sid_cache {0, HB_CODEPOINT_INVALID};
for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++)
{
- hb_codepoint_t sid = glyph_to_sid (gid);
+ hb_codepoint_t sid = glyph_to_sid (gid, &glyph_to_sid_cache);
gname_t gname;
gname.sid = sid;
if (sid < cff1_std_strings_length)
@@ -1426,7 +1464,6 @@ struct cff1
HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const;
HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const;
- HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const;
HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
private:
@@ -1453,9 +1490,24 @@ struct cff1
typedef accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t> SUPER;
};
- struct accelerator_subset_t : accelerator_templ_t<cff1_private_dict_opset_subset, cff1_private_dict_values_subset_t> {};
+ struct accelerator_subset_t : accelerator_templ_t<cff1_private_dict_opset_subset_t, cff1_private_dict_values_subset_t>
+ {
+ accelerator_subset_t (hb_face_t *face) : SUPER (face) {}
+ ~accelerator_subset_t ()
+ {
+ if (cff_accelerator)
+ cff_subset_accelerator_t::destroy (cff_accelerator);
+ }
+
+ HB_INTERNAL bool subset (hb_subset_context_t *c) const;
+ HB_INTERNAL bool serialize (hb_serialize_context_t *c,
+ struct cff1_subset_plan &plan) const;
+ HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const;
- bool subset (hb_subset_context_t *c) const { return hb_subset_cff1 (c); }
+ mutable CFF::cff_subset_accelerator_t* cff_accelerator = nullptr;
+
+ typedef accelerator_templ_t<cff1_private_dict_opset_subset_t, cff1_private_dict_values_subset_t> SUPER;
+ };
protected:
HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_code (hb_codepoint_t sid);
@@ -1479,6 +1531,10 @@ struct cff1_accelerator_t : cff1::accelerator_t {
cff1_accelerator_t (hb_face_t *face) : cff1::accelerator_t (face) {}
};
+struct cff1_subset_accelerator_t : cff1::accelerator_subset_t {
+ cff1_subset_accelerator_t (hb_face_t *face) : cff1::accelerator_subset_t (face) {}
+};
+
} /* namespace OT */
#endif /* HB_OT_CFF1_TABLE_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh
index b9a8819ab8..4b3bdc9315 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cff2-table.hh
@@ -28,7 +28,7 @@
#define HB_OT_CFF2_TABLE_HH
#include "hb-ot-cff-common.hh"
-#include "hb-subset-cff2.hh"
+#include "hb-subset-cff-common.hh"
#include "hb-draw.hh"
#include "hb-paint.hh"
@@ -38,10 +38,9 @@ namespace CFF {
* CFF2 -- Compact Font Format (CFF) Version 2
* https://docs.microsoft.com/en-us/typography/opentype/spec/cff2
*/
-#define HB_OT_TAG_cff2 HB_TAG('C','F','F','2')
+#define HB_OT_TAG_CFF2 HB_TAG('C','F','F','2')
typedef CFFIndex<HBUINT32> CFF2Index;
-template <typename Type> struct CFF2IndexOf : CFFIndexOf<HBUINT32, Type> {};
typedef CFF2Index CFF2CharStrings;
typedef Subrs<HBUINT32> CFF2Subrs;
@@ -91,6 +90,7 @@ struct CFF2FDSelect
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
+ hb_barrier ();
switch (format)
{
@@ -111,19 +111,22 @@ struct CFF2FDSelect
DEFINE_SIZE_MIN (2);
};
-struct CFF2VariationStore
+struct CFF2ItemVariationStore
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (likely (c->check_struct (this)) && c->check_range (&varStore, size) && varStore.sanitize (c));
+ return_trace (c->check_struct (this) &&
+ hb_barrier () &&
+ c->check_range (&varStore, size) &&
+ varStore.sanitize (c));
}
- bool serialize (hb_serialize_context_t *c, const CFF2VariationStore *varStore)
+ bool serialize (hb_serialize_context_t *c, const CFF2ItemVariationStore *varStore)
{
TRACE_SERIALIZE (this);
unsigned int size_ = varStore->get_size ();
- CFF2VariationStore *dest = c->allocate_size<CFF2VariationStore> (size_);
+ CFF2ItemVariationStore *dest = c->allocate_size<CFF2ItemVariationStore> (size_);
if (unlikely (!dest)) return_trace (false);
hb_memcpy (dest, varStore, size_);
return_trace (true);
@@ -132,9 +135,9 @@ struct CFF2VariationStore
unsigned int get_size () const { return HBUINT16::static_size + size; }
HBUINT16 size;
- VariationStore varStore;
+ ItemVariationStore varStore;
- DEFINE_SIZE_MIN (2 + VariationStore::min_size);
+ DEFINE_SIZE_MIN (2 + ItemVariationStore::min_size);
};
struct cff2_top_dict_values_t : top_dict_values_t<>
@@ -147,8 +150,8 @@ struct cff2_top_dict_values_t : top_dict_values_t<>
}
void fini () { top_dict_values_t<>::fini (); }
- unsigned int vstoreOffset;
- unsigned int FDSelectOffset;
+ int vstoreOffset;
+ int FDSelectOffset;
};
struct cff2_top_dict_opset_t : top_dict_opset_t<>
@@ -166,11 +169,11 @@ struct cff2_top_dict_opset_t : top_dict_opset_t<>
break;
case OpCode_vstore:
- dictval.vstoreOffset = env.argStack.pop_uint ();
+ dictval.vstoreOffset = env.argStack.pop_int ();
env.clear_args ();
break;
case OpCode_FDSelect:
- dictval.FDSelectOffset = env.argStack.pop_uint ();
+ dictval.FDSelectOffset = env.argStack.pop_int ();
env.clear_args ();
break;
@@ -238,7 +241,7 @@ struct cff2_private_dict_values_base_t : dict_values_t<VAL>
}
void fini () { dict_values_t<VAL>::fini (); }
- unsigned int subrsOffset;
+ int subrsOffset;
const CFF2Subrs *localSubrs;
unsigned int ivs;
};
@@ -292,7 +295,7 @@ struct cff2_private_dict_opset_t : dict_opset_t
env.clear_args ();
break;
case OpCode_Subrs:
- dictval.subrsOffset = env.argStack.pop_uint ();
+ dictval.subrsOffset = env.argStack.pop_int ();
env.clear_args ();
break;
case OpCode_vsindexdict:
@@ -341,7 +344,7 @@ struct cff2_private_dict_opset_subset_t : dict_opset_t
return;
case OpCode_Subrs:
- dictval.subrsOffset = env.argStack.pop_uint ();
+ dictval.subrsOffset = env.argStack.pop_int ();
env.clear_args ();
break;
@@ -379,20 +382,25 @@ using namespace CFF;
struct cff2
{
- static constexpr hb_tag_t tableTag = HB_OT_TAG_cff2;
+ static constexpr hb_tag_t tableTag = HB_OT_TAG_CFF2;
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
likely (version.major == 2));
}
template <typename PRIVOPSET, typename PRIVDICTVAL>
struct accelerator_templ_t
{
+ static constexpr hb_tag_t tableTag = cff2::tableTag;
+
accelerator_templ_t (hb_face_t *face)
{
+ if (!face) return;
+
topDict.init ();
fontDicts.init ();
privateDicts.init ();
@@ -411,23 +419,22 @@ struct cff2
{ /* parse top dict */
hb_ubytes_t topDictStr = (cff2 + cff2->topDict).as_ubytes (cff2->topDictSize);
if (unlikely (!topDictStr.sanitize (&sc))) goto fail;
+ hb_barrier ();
num_interp_env_t env (topDictStr);
cff2_top_dict_interpreter_t top_interp (env);
topDict.init ();
if (unlikely (!top_interp.interpret (topDict))) goto fail;
}
- globalSubrs = &StructAtOffset<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize);
- varStore = &StructAtOffsetOrNull<CFF2VariationStore> (cff2, topDict.vstoreOffset);
- charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset);
- fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset);
- fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset);
-
- if (((varStore != &Null (CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) ||
- (charStrings == &Null (CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) ||
- (globalSubrs == &Null (CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) ||
- (fdArray == &Null (CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) ||
- (((fdSelect != &Null (CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count)))))
+ globalSubrs = &StructAtOffsetOrNull<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize, sc);
+ varStore = &StructAtOffsetOrNull<CFF2ItemVariationStore> (cff2, topDict.vstoreOffset, sc);
+ charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset, sc);
+ fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset, sc);
+ fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset, sc, fdArray->count);
+
+ if (charStrings == &Null (CFF2CharStrings) ||
+ globalSubrs == &Null (CFF2Subrs) ||
+ fdArray == &Null (CFF2FDArray))
goto fail;
num_glyphs = charStrings->count;
@@ -443,6 +450,7 @@ struct cff2
{
const hb_ubytes_t fontDictStr = (*fdArray)[i];
if (unlikely (!fontDictStr.sanitize (&sc))) goto fail;
+ hb_barrier ();
cff2_font_dict_values_t *font;
num_interp_env_t env (fontDictStr);
cff2_font_dict_interpreter_t font_interp (env);
@@ -451,20 +459,15 @@ struct cff2
font->init ();
if (unlikely (!font_interp.interpret (*font))) goto fail;
- const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset).as_ubytes (font->privateDictInfo.size);
- if (unlikely (!privDictStr.sanitize (&sc))) goto fail;
+ const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
cff2_priv_dict_interp_env_t env2 (privDictStr);
dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp (env2);
privateDicts[i].init ();
if (unlikely (!priv_interp.interpret (privateDicts[i]))) goto fail;
- privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset);
- if (privateDicts[i].localSubrs != &Null (CFF2Subrs) &&
- unlikely (!privateDicts[i].localSubrs->sanitize (&sc)))
- goto fail;
+ privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset, sc);
}
-
return;
fail:
@@ -481,11 +484,13 @@ struct cff2
blob = nullptr;
}
- hb_map_t *create_glyph_to_sid_map () const
+ hb_vector_t<uint16_t> *create_glyph_to_sid_map () const
{
return nullptr;
}
+ hb_blob_t *get_blob () const { return blob; }
+
bool is_valid () const { return blob; }
protected:
@@ -495,7 +500,7 @@ struct cff2
hb_blob_t *blob = nullptr;
cff2_top_dict_values_t topDict;
const CFF2Subrs *globalSubrs = nullptr;
- const CFF2VariationStore *varStore = nullptr;
+ const CFF2ItemVariationStore *varStore = nullptr;
const CFF2CharStrings *charStrings = nullptr;
const CFF2FDArray *fdArray = nullptr;
const CFF2FDSelect *fdSelect = nullptr;
@@ -518,9 +523,24 @@ struct cff2
HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
};
- typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> accelerator_subset_t;
+ struct accelerator_subset_t : accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t>
+ {
+ accelerator_subset_t (hb_face_t *face) : SUPER (face) {}
+ ~accelerator_subset_t ()
+ {
+ if (cff_accelerator)
+ cff_subset_accelerator_t::destroy (cff_accelerator);
+ }
+
+ HB_INTERNAL bool subset (hb_subset_context_t *c) const;
+ HB_INTERNAL bool serialize (hb_serialize_context_t *c,
+ struct cff2_subset_plan &plan,
+ hb_array_t<int> normalized_coords) const;
- bool subset (hb_subset_context_t *c) const { return hb_subset_cff2 (c); }
+ mutable CFF::cff_subset_accelerator_t* cff_accelerator = nullptr;
+
+ typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> SUPER;
+ };
public:
FixedVersion<HBUINT8> version; /* Version of CFF2 table. set to 0x0200u */
@@ -535,6 +555,10 @@ struct cff2_accelerator_t : cff2::accelerator_t {
cff2_accelerator_t (hb_face_t *face) : cff2::accelerator_t (face) {}
};
+struct cff2_subset_accelerator_t : cff2::accelerator_subset_t {
+ cff2_subset_accelerator_t (hb_face_t *face) : cff2::accelerator_subset_t (face) {}
+};
+
} /* namespace OT */
#endif /* HB_OT_CFF2_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 f5a03d2b00..64d2b13880 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-cmap-table.hh
@@ -41,6 +41,30 @@
namespace OT {
+static inline uint8_t unicode_to_macroman (hb_codepoint_t u)
+{
+ uint16_t mapping[] = {
+ 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
+ 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
+ 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
+ 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
+ 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
+ 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,
+ 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
+ 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8,
+ 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
+ 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
+ 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
+ 0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02,
+ 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
+ 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
+ 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC,
+ 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7
+ };
+ uint16_t *c = hb_bsearch (u, mapping, ARRAY_LENGTH (mapping), sizeof (mapping[0]),
+ _hb_cmp_operator<uint16_t, uint16_t>);
+ return c ? (c - mapping) + 0x7F : 0;
+}
struct CmapSubtableFormat0
{
@@ -277,10 +301,10 @@ struct CmapSubtableFormat4
}
} writer(c);
- writer.end_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
- c->allocate_size<HBUINT16> (2); // padding
- writer.start_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
- writer.id_delta_ = c->allocate_size<HBINT16> (HBINT16::static_size * segcount);
+ writer.end_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount, false);
+ (void) c->allocate_size<HBUINT16> (2); // padding
+ writer.start_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount, false);
+ writer.id_delta_ = c->allocate_size<HBINT16> (HBINT16::static_size * segcount, false);
if (unlikely (!writer.end_code_ || !writer.start_code_ || !writer.id_delta_)) return false;
@@ -325,7 +349,7 @@ struct CmapSubtableFormat4
{
auto format4_iter =
+ it
- | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
+ | hb_filter ([&] (const hb_codepoint_pair_t _)
{ return _.first <= 0xFFFF; })
;
@@ -335,7 +359,7 @@ struct CmapSubtableFormat4
if (unlikely (!c->extend_min (this))) return;
this->format = 4;
- hb_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> cp_to_gid {
+ hb_vector_t<hb_codepoint_pair_t> cp_to_gid {
format4_iter
};
@@ -404,7 +428,7 @@ struct CmapSubtableFormat4
unsigned distance) const
{
if (k > last) return +1;
- if (k < (&last)[distance]) return -1;
+ if (k < (&last)[distance]/*first*/) return -1;
return 0;
}
HBUINT16 last;
@@ -413,7 +437,7 @@ struct CmapSubtableFormat4
const HBUINT16 *found = hb_bsearch (codepoint,
this->endCount,
this->segCount,
- 2,
+ sizeof (CustomRange),
_hb_cmp_method<hb_codepoint_t, CustomRange, unsigned>,
this->segCount + 1);
if (unlikely (!found))
@@ -556,6 +580,7 @@ struct CmapSubtableFormat4
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
+ hb_barrier ();
if (unlikely (!c->check_range (this, length)))
{
@@ -742,10 +767,11 @@ struct CmapSubtableLongSegmented
unsigned num_glyphs) const
{
hb_codepoint_t last_end = 0;
- for (unsigned i = 0; i < this->groups.len; i++)
+ unsigned count = this->groups.len;
+ for (unsigned i = 0; i < count; i++)
{
- hb_codepoint_t start = this->groups[i].startCharCode;
- hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode,
+ hb_codepoint_t start = this->groups.arrayZ[i].startCharCode;
+ hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups.arrayZ[i].endCharCode,
(hb_codepoint_t) HB_UNICODE_MAX);
if (unlikely (start > end || start < last_end)) {
// Range is not in order and is invalid, skip it.
@@ -754,11 +780,10 @@ struct CmapSubtableLongSegmented
last_end = end;
- hb_codepoint_t gid = this->groups[i].glyphID;
+ hb_codepoint_t gid = this->groups.arrayZ[i].glyphID;
if (!gid)
{
- /* Intention is: if (hb_is_same (T, CmapSubtableFormat13)) continue; */
- if (! T::group_get_glyph (this->groups[i], end)) continue;
+ if (T::formatNumber == 13) continue;
start++;
gid++;
}
@@ -766,11 +791,13 @@ struct CmapSubtableLongSegmented
if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs))
end = start + (hb_codepoint_t) num_glyphs - gid;
+ mapping->alloc (mapping->get_population () + end - start + 1);
+
+ unicodes->add_range (start, end);
for (unsigned cp = start; cp <= end; cp++)
{
- unicodes->add (cp);
mapping->set (cp, gid);
- gid++;
+ gid += T::increment;
}
}
}
@@ -794,6 +821,9 @@ struct CmapSubtableLongSegmented
struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
{
+ static constexpr int increment = 1;
+ static constexpr int formatNumber = 12;
+
static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
hb_codepoint_t u)
{ return likely (group.startCharCode <= group.endCharCode) ?
@@ -866,6 +896,9 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
struct CmapSubtableFormat13 : CmapSubtableLongSegmented<CmapSubtableFormat13>
{
+ static constexpr int increment = 0;
+ static constexpr int formatNumber = 13;
+
static hb_codepoint_t group_get_glyph (const CmapSubtableLongGroup &group,
hb_codepoint_t u HB_UNUSED)
{ return group.glyphID; }
@@ -917,8 +950,7 @@ struct DefaultUVS : SortedArray32Of<UnicodeValueRange>
DefaultUVS* copy (hb_serialize_context_t *c,
const hb_set_t *unicodes) const
{
- DefaultUVS *out = c->start_embed<DefaultUVS> ();
- if (unlikely (!out)) return nullptr;
+ auto *out = c->start_embed<DefaultUVS> ();
auto snap = c->snapshot ();
HBUINT32 len;
@@ -931,8 +963,7 @@ struct DefaultUVS : SortedArray32Of<UnicodeValueRange>
hb_codepoint_t start = HB_SET_VALUE_INVALID;
hb_codepoint_t end = HB_SET_VALUE_INVALID;
- for (hb_codepoint_t u = HB_SET_VALUE_INVALID;
- unicodes->next (&u);)
+ for (auto u : *unicodes)
{
if (!as_array ().bsearch (u))
continue;
@@ -1067,9 +1098,7 @@ struct NonDefaultUVS : SortedArray32Of<UVSMapping>
const hb_set_t *glyphs_requested,
const hb_map_t *glyph_map) const
{
- NonDefaultUVS *out = c->start_embed<NonDefaultUVS> ();
- if (unlikely (!out)) return nullptr;
-
+ auto *out = c->start_embed<NonDefaultUVS> ();
auto it =
+ as_array ()
| hb_filter ([&] (const UVSMapping& _)
@@ -1424,6 +1453,7 @@ struct CmapSubtable
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
+ hb_barrier ();
switch (u.format) {
case 0: return_trace (u.format0 .sanitize (c));
case 4: return_trace (u.format4 .sanitize (c));
@@ -1459,8 +1489,11 @@ struct EncodingRecord
int ret;
ret = platformID.cmp (other.platformID);
if (ret) return ret;
- ret = encodingID.cmp (other.encodingID);
- if (ret) return ret;
+ if (other.encodingID != 0xFFFF)
+ {
+ ret = encodingID.cmp (other.encodingID);
+ if (ret) return ret;
+ }
return 0;
}
@@ -1767,7 +1800,6 @@ struct cmap
TRACE_SUBSET (this);
cmap *cmap_prime = c->serializer->start_embed<cmap> ();
- if (unlikely (!c->serializer->check_success (cmap_prime))) return_trace (false);
auto encodingrec_iter =
+ hb_iter (encodingRecord)
@@ -1798,7 +1830,7 @@ struct cmap
auto it =
+ c->plan->unicode_to_new_gid_list.iter ()
- | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
+ | hb_filter ([&] (const hb_codepoint_pair_t _)
{ return (_.second != HB_MAP_VALUE_INVALID); })
;
@@ -1809,9 +1841,13 @@ struct cmap
c->plan));
}
- const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
+ const CmapSubtable *find_best_subtable (bool *symbol = nullptr,
+ bool *mac = nullptr,
+ bool *macroman = nullptr) const
{
if (symbol) *symbol = false;
+ if (mac) *mac = false;
+ if (macroman) *macroman = false;
const CmapSubtable *subtable;
@@ -1836,6 +1872,20 @@ struct cmap
if ((subtable = this->find_subtable (0, 1))) return subtable;
if ((subtable = this->find_subtable (0, 0))) return subtable;
+ /* MacRoman subtable. */
+ if ((subtable = this->find_subtable (1, 0)))
+ {
+ if (mac) *mac = true;
+ if (macroman) *macroman = true;
+ return subtable;
+ }
+ /* Any other Mac subtable; we just map ASCII for these. */
+ if ((subtable = this->find_subtable (1, 0xFFFF)))
+ {
+ if (mac) *mac = true;
+ return subtable;
+ }
+
/* Meh. */
return &Null (CmapSubtable);
}
@@ -1847,8 +1897,8 @@ struct cmap
accelerator_t (hb_face_t *face)
{
this->table = hb_sanitize_context_t ().reference_table<cmap> (face);
- bool symbol;
- this->subtable = table->find_best_subtable (&symbol);
+ bool symbol, mac, macroman;
+ this->subtable = table->find_best_subtable (&symbol, &mac, &macroman);
this->subtable_uvs = &Null (CmapSubtableFormat14);
{
const CmapSubtable *st = table->find_subtable (0, 5);
@@ -1857,6 +1907,7 @@ struct cmap
}
this->get_glyph_data = subtable;
+#ifndef HB_NO_CMAP_LEGACY_SUBTABLES
if (unlikely (symbol))
{
switch ((unsigned) face->table.OS2->get_font_page ()) {
@@ -1876,7 +1927,16 @@ struct cmap
break;
}
}
+ else if (unlikely (macroman))
+ {
+ this->get_glyph_funcZ = get_glyph_from_macroman<CmapSubtable>;
+ }
+ else if (unlikely (mac))
+ {
+ this->get_glyph_funcZ = get_glyph_from_ascii<CmapSubtable>;
+ }
else
+#endif
{
switch (subtable->u.format) {
/* Accelerate format 4 and format 12. */
@@ -1919,7 +1979,7 @@ struct cmap
hb_codepoint_t *glyph,
cache_t *cache = nullptr) const
{
- if (unlikely (!this->get_glyph_funcZ)) return 0;
+ if (unlikely (!this->get_glyph_funcZ)) return false;
return _cached_get (unicode, glyph, cache);
}
@@ -2001,6 +2061,28 @@ struct cmap
return false;
}
+ template <typename Type>
+ HB_INTERNAL static bool get_glyph_from_ascii (const void *obj,
+ hb_codepoint_t codepoint,
+ hb_codepoint_t *glyph)
+ {
+ const Type *typed_obj = (const Type *) obj;
+ return codepoint < 0x80 && typed_obj->get_glyph (codepoint, glyph);
+ }
+
+ template <typename Type>
+ HB_INTERNAL static bool get_glyph_from_macroman (const void *obj,
+ hb_codepoint_t codepoint,
+ hb_codepoint_t *glyph)
+ {
+ if (get_glyph_from_ascii<Type> (obj, codepoint, glyph))
+ return true;
+
+ const Type *typed_obj = (const Type *) obj;
+ unsigned c = unicode_to_macroman (codepoint);
+ return c && typed_obj->get_glyph (c, glyph);
+ }
+
private:
hb_nonnull_ptr_t<const CmapSubtable> subtable;
hb_nonnull_ptr_t<const CmapSubtableFormat14> subtable_uvs;
@@ -2030,34 +2112,13 @@ struct cmap
return &(this+result.subtable);
}
- const EncodingRecord *find_encodingrec (unsigned int platform_id,
- unsigned int encoding_id) const
- {
- EncodingRecord key;
- key.platformID = platform_id;
- key.encodingID = encoding_id;
-
- return encodingRecord.as_array ().bsearch (key);
- }
-
- bool find_subtable (unsigned format) const
- {
- auto it =
- + hb_iter (encodingRecord)
- | hb_map (&EncodingRecord::subtable)
- | hb_map (hb_add (this))
- | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == format; })
- ;
-
- return it.len ();
- }
-
public:
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
likely (version == 0) &&
encodingRecord.sanitize (c, this));
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-face-table-list.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-face-table-list.hh
index c9da36c1bb..b552dfdd9d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-face-table-list.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-face-table-list.hh
@@ -93,6 +93,7 @@ HB_OT_ACCELERATOR (OT, cff2)
#ifndef HB_NO_VAR
HB_OT_CORE_TABLE (OT, fvar)
HB_OT_CORE_TABLE (OT, avar)
+HB_OT_CORE_TABLE (OT, cvar)
HB_OT_ACCELERATOR (OT, gvar)
HB_OT_CORE_TABLE (OT, MVAR)
#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc
index 19ae02e28b..1da869d697 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-font.cc
@@ -38,8 +38,8 @@
#include "hb-ot-cmap-table.hh"
#include "hb-ot-glyf-table.hh"
-#include "hb-ot-cff1-table.hh"
#include "hb-ot-cff2-table.hh"
+#include "hb-ot-cff1-table.hh"
#include "hb-ot-hmtx-table.hh"
#include "hb-ot-post-table.hh"
#include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise.
@@ -64,13 +64,17 @@
using hb_ot_font_cmap_cache_t = hb_cache_t<21, 16, 8, true>;
using hb_ot_font_advance_cache_t = hb_cache_t<24, 16, 8, true>;
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
static hb_user_data_key_t hb_ot_font_cmap_cache_user_data_key;
+#endif
struct hb_ot_font_t
{
const hb_ot_face_t *ot_face;
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
hb_ot_font_cmap_cache_t *cmap_cache;
+#endif
/* h_advance caching */
mutable hb_atomic_int_t cached_coords_serial;
@@ -86,6 +90,7 @@ _hb_ot_font_create (hb_font_t *font)
ot_font->ot_face = &font->face->table;
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
// retry:
auto *cmap_cache = (hb_ot_font_cmap_cache_t *) hb_face_get_user_data (font->face,
&hb_ot_font_cmap_cache_user_data_key);
@@ -93,7 +98,7 @@ _hb_ot_font_create (hb_font_t *font)
{
cmap_cache = (hb_ot_font_cmap_cache_t *) hb_malloc (sizeof (hb_ot_font_cmap_cache_t));
if (unlikely (!cmap_cache)) goto out;
- cmap_cache->init ();
+ new (cmap_cache) hb_ot_font_cmap_cache_t ();
if (unlikely (!hb_face_set_user_data (font->face,
&hb_ot_font_cmap_cache_user_data_key,
cmap_cache,
@@ -112,6 +117,7 @@ _hb_ot_font_create (hb_font_t *font)
}
out:
ot_font->cmap_cache = cmap_cache;
+#endif
return ot_font;
}
@@ -136,7 +142,11 @@ hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
const hb_ot_face_t *ot_face = ot_font->ot_face;
- return ot_face->cmap->get_nominal_glyph (unicode, glyph, ot_font->cmap_cache);
+ hb_ot_font_cmap_cache_t *cmap_cache = nullptr;
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
+ cmap_cache = ot_font->cmap_cache;
+#endif
+ return ot_face->cmap->get_nominal_glyph (unicode, glyph, cmap_cache);
}
static unsigned int
@@ -151,10 +161,14 @@ hb_ot_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
const hb_ot_face_t *ot_face = ot_font->ot_face;
+ hb_ot_font_cmap_cache_t *cmap_cache = nullptr;
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
+ cmap_cache = ot_font->cmap_cache;
+#endif
return ot_face->cmap->get_nominal_glyphs (count,
first_unicode, unicode_stride,
first_glyph, glyph_stride,
- ot_font->cmap_cache);
+ cmap_cache);
}
static hb_bool_t
@@ -167,9 +181,13 @@ hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED,
{
const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
const hb_ot_face_t *ot_face = ot_font->ot_face;
+ hb_ot_font_cmap_cache_t *cmap_cache = nullptr;
+#ifndef HB_NO_OT_FONT_CMAP_CACHE
+ cmap_cache = ot_font->cmap_cache;
+#endif
return ot_face->cmap->get_variation_glyph (unicode,
variation_selector, glyph,
- ot_font->cmap_cache);
+ cmap_cache);
}
static void
@@ -188,14 +206,14 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
hb_position_t *orig_first_advance = first_advance;
-#ifndef HB_NO_VAR
+#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
const OT::HVAR &HVAR = *hmtx.var_table;
- const OT::VariationStore &varStore = &HVAR + HVAR.varStore;
- OT::VariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr;
+ const OT::ItemVariationStore &varStore = &HVAR + HVAR.varStore;
+ OT::ItemVariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr;
bool use_cache = font->num_coords;
#else
- OT::VariationStore::cache_t *varStore_cache = nullptr;
+ OT::ItemVariationStore::cache_t *varStore_cache = nullptr;
bool use_cache = false;
#endif
@@ -212,8 +230,8 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
use_cache = false;
goto out;
}
+ new (cache) hb_ot_font_advance_cache_t;
- cache->init ();
if (unlikely (!ot_font->advance_cache.cmpexch (nullptr, cache)))
{
hb_free (cache);
@@ -237,7 +255,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
{ /* Use cache. */
if (ot_font->cached_coords_serial.get_acquire () != (int) font->serial_coords)
{
- ot_font->advance_cache->init ();
+ ot_font->advance_cache->clear ();
ot_font->cached_coords_serial.set_release (font->serial_coords);
}
@@ -258,8 +276,8 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data,
}
}
-#ifndef HB_NO_VAR
- OT::VariationStore::destroy_cache (varStore_cache);
+#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
+ OT::ItemVariationStore::destroy_cache (varStore_cache);
#endif
if (font->x_strength && !font->embolden_in_place)
@@ -293,12 +311,12 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
if (vmtx.has_data ())
{
-#ifndef HB_NO_VAR
+#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
const OT::VVAR &VVAR = *vmtx.var_table;
- const OT::VariationStore &varStore = &VVAR + VVAR.varStore;
- OT::VariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr;
+ const OT::ItemVariationStore &varStore = &VVAR + VVAR.varStore;
+ OT::ItemVariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr;
#else
- OT::VariationStore::cache_t *varStore_cache = nullptr;
+ OT::ItemVariationStore::cache_t *varStore_cache = nullptr;
#endif
for (unsigned int i = 0; i < count; i++)
@@ -308,8 +326,8 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data,
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
}
-#ifndef HB_NO_VAR
- OT::VariationStore::destroy_cache (varStore_cache);
+#if !defined(HB_NO_VAR) && !defined(HB_NO_OT_FONT_ADVANCE_CACHE)
+ OT::ItemVariationStore::destroy_cache (varStore_cache);
#endif
}
else
@@ -413,13 +431,13 @@ hb_ot_get_glyph_extents (hb_font_t *font,
if (ot_face->sbix->get_extents (font, glyph, extents)) return true;
if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
#endif
-#if !defined(HB_NO_COLOR)
+#if !defined(HB_NO_COLOR) && !defined(HB_NO_PAINT)
if (ot_face->COLR->get_extents (font, glyph, extents)) return true;
#endif
if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
#ifndef HB_NO_OT_FONT_CFF
- if (ot_face->cff1->get_extents (font, glyph, extents)) return true;
if (ot_face->cff2->get_extents (font, glyph, extents)) return true;
+ if (ot_face->cff1->get_extents (font, glyph, extents)) return true;
#endif
return false;
@@ -507,8 +525,8 @@ hb_ot_draw_glyph (hb_font_t *font,
embolden ? &outline : draw_data, font->slant_xy);
if (!font->face->table.glyf->get_path (font, glyph, draw_session))
#ifndef HB_NO_CFF
- if (!font->face->table.cff1->get_path (font, glyph, draw_session))
if (!font->face->table.cff2->get_path (font, glyph, draw_session))
+ if (!font->face->table.cff1->get_path (font, glyph, draw_session))
#endif
{}
}
@@ -547,8 +565,8 @@ hb_ot_paint_glyph (hb_font_t *font,
#endif
if (font->face->table.glyf->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
#ifndef HB_NO_CFF
- if (font->face->table.cff1->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
if (font->face->table.cff2->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
+ if (font->face->table.cff1->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
#endif
}
#endif
@@ -633,20 +651,4 @@ hb_ot_font_set_funcs (hb_font_t *font)
_hb_ot_font_destroy);
}
-#ifndef HB_NO_VAR
-bool
-_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical,
- int *lsb)
-{
- return font->face->table.glyf->get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb);
-}
-
-unsigned
-_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
-{
- return font->face->table.glyf->get_advance_with_var_unscaled (font, glyph, is_vertical);
-}
-#endif
-
-
#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-hdmx-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-hdmx-table.hh
index a86cc3c311..8582dbe27d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-hdmx-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-hdmx-table.hh
@@ -46,21 +46,23 @@ struct DeviceRecord
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
- bool serialize (hb_serialize_context_t *c, unsigned pixelSize, Iterator it)
+ bool serialize (hb_serialize_context_t *c,
+ unsigned pixelSize,
+ Iterator it,
+ const hb_vector_t<hb_codepoint_pair_t> new_to_old_gid_list,
+ unsigned num_glyphs)
{
TRACE_SERIALIZE (this);
- unsigned length = it.len ();
-
- if (unlikely (!c->extend (this, length))) return_trace (false);
+ if (unlikely (!c->extend (this, num_glyphs))) return_trace (false);
this->pixelSize = pixelSize;
this->maxWidth =
+ it
| hb_reduce (hb_max, 0u);
- + it
- | hb_sink (widthsZ.as_array (length));
+ for (auto &_ : new_to_old_gid_list)
+ widthsZ[_.first] = *it++;
return_trace (true);
}
@@ -69,6 +71,7 @@ struct DeviceRecord
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
+ hb_barrier () &&
c->check_range (this, sizeDeviceRecord)));
}
@@ -76,7 +79,7 @@ struct DeviceRecord
HBUINT8 maxWidth; /* Maximum width. */
UnsizedArrayOf<HBUINT8> widthsZ; /* Array of widths (numGlyphs is from the 'maxp' table). */
public:
- DEFINE_SIZE_ARRAY (2, widthsZ);
+ DEFINE_SIZE_UNBOUNDED (2);
};
@@ -87,17 +90,13 @@ struct hdmx
unsigned int get_size () const
{ return min_size + numRecords * sizeDeviceRecord; }
- const DeviceRecord& operator [] (unsigned int i) const
- {
- /* XXX Null(DeviceRecord) is NOT safe as it's num-glyphs lengthed.
- * https://github.com/harfbuzz/harfbuzz/issues/1300 */
- if (unlikely (i >= numRecords)) return Null (DeviceRecord);
- return StructAtOffset<DeviceRecord> (&this->firstDeviceRecord, i * sizeDeviceRecord);
- }
-
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
- bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it)
+ bool serialize (hb_serialize_context_t *c,
+ unsigned version,
+ Iterator it,
+ const hb_vector_t<hb_codepoint_pair_t> &new_to_old_gid_list,
+ unsigned num_glyphs)
{
TRACE_SERIALIZE (this);
@@ -105,10 +104,10 @@ struct hdmx
this->version = version;
this->numRecords = it.len ();
- this->sizeDeviceRecord = DeviceRecord::get_size (it ? (*it).second.len () : 0);
+ this->sizeDeviceRecord = DeviceRecord::get_size (num_glyphs);
for (const hb_item_type<Iterator>& _ : +it)
- c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second);
+ c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second, new_to_old_gid_list, num_glyphs);
return_trace (c->successful ());
}
@@ -118,31 +117,30 @@ struct hdmx
{
TRACE_SUBSET (this);
- hdmx *hdmx_prime = c->serializer->start_embed <hdmx> ();
- if (unlikely (!hdmx_prime)) return_trace (false);
+ auto *hdmx_prime = c->serializer->start_embed <hdmx> ();
+ unsigned num_input_glyphs = get_num_glyphs ();
auto it =
+ hb_range ((unsigned) numRecords)
- | hb_map ([c, this] (unsigned _)
+ | hb_map ([c, num_input_glyphs, this] (unsigned _)
{
const DeviceRecord *device_record =
&StructAtOffset<DeviceRecord> (&firstDeviceRecord,
_ * sizeDeviceRecord);
auto row =
- + hb_range (c->plan->num_output_glyphs ())
- | hb_map (c->plan->reverse_glyph_map)
- | hb_map ([this, c, device_record] (hb_codepoint_t _)
+ + hb_iter (c->plan->new_to_old_gid_list)
+ | hb_map ([num_input_glyphs, device_record] (hb_codepoint_pair_t _)
{
- if (c->plan->is_empty_glyph (_))
- return Null (HBUINT8);
- return device_record->widthsZ.as_array (get_num_glyphs ()) [_];
+ return device_record->widthsZ.as_array (num_input_glyphs) [_.second];
})
;
return hb_pair ((unsigned) device_record->pixelSize, +row);
})
;
- hdmx_prime->serialize (c->serializer, version, it);
+ hdmx_prime->serialize (c->serializer, version, it,
+ c->plan->new_to_old_gid_list,
+ c->plan->num_output_glyphs ());
return_trace (true);
}
@@ -155,6 +153,7 @@ struct hdmx
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
!hb_unsigned_mul_overflows (numRecords, sizeDeviceRecord) &&
min_size + numRecords * sizeDeviceRecord > numRecords * sizeDeviceRecord &&
sizeDeviceRecord >= DeviceRecord::min_size &&
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 798e82da6c..4cb6c15c67 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-head-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-head-table.hh
@@ -63,7 +63,25 @@ struct head
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- return_trace (serialize (c->serializer));
+ head *out = c->serializer->embed (this);
+ if (unlikely (!out)) return_trace (false);
+
+ if (c->plan->normalized_coords)
+ {
+ if (unlikely (!c->serializer->check_assign (out->xMin, c->plan->head_maxp_info.xMin,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW)))
+ return_trace (false);
+ if (unlikely (!c->serializer->check_assign (out->xMax, c->plan->head_maxp_info.xMax,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW)))
+ return_trace (false);
+ if (unlikely (!c->serializer->check_assign (out->yMin, c->plan->head_maxp_info.yMin,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW)))
+ return_trace (false);
+ if (unlikely (!c->serializer->check_assign (out->yMax, c->plan->head_maxp_info.yMax,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW)))
+ return_trace (false);
+ }
+ return_trace (true);
}
enum mac_style_flag_t {
@@ -85,6 +103,7 @@ struct head
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
version.major == 1 &&
magicNumber == 0x5F0F3CF5u);
}
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 d9c9bd3537..27becfda3d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-hhea-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-hhea-table.hh
@@ -50,7 +50,9 @@ struct _hea
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) &&
+ hb_barrier () &&
+ likely (version.major == 1));
}
public:
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 16eb1eb912..48bd536121 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-hmtx-table.hh
@@ -50,6 +50,9 @@ _glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t gly
HB_INTERNAL unsigned
_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
+HB_INTERNAL bool
+_glyf_get_leading_bearing_without_var_unscaled (hb_face_t *face, hb_codepoint_t gid, bool is_vertical, int *lsb);
+
namespace OT {
@@ -80,7 +83,7 @@ struct hmtxvmtx
bool subset_update_header (hb_subset_context_t *c,
unsigned int num_hmetrics,
const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>> *mtx_map,
- const hb_map_t *bounds_map) const
+ const hb_vector_t<unsigned> &bounds_vec) const
{
hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table<H> (c->plan->source, H::tableTag);
hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob);
@@ -92,7 +95,7 @@ struct hmtxvmtx
unsigned int length;
H *table = (H *) hb_blob_get_data (dest_blob, &length);
- table->numberOfLongMetrics = num_hmetrics;
+ c->serializer->check_assign (table->numberOfLongMetrics, num_hmetrics, HB_SERIALIZE_ERROR_INT_OVERFLOW);
#ifndef HB_NO_VAR
if (c->plan->normalized_coords)
@@ -111,6 +114,7 @@ struct hmtxvmtx
HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET, caretOffset);
}
+ bool empty = true;
int min_lsb = 0x7FFF;
int min_rsb = 0x7FFF;
int max_extent = -0x7FFF;
@@ -122,9 +126,10 @@ struct hmtxvmtx
int lsb = _.second.second;
max_adv = hb_max (max_adv, adv);
- if (bounds_map->has (gid))
+ if (bounds_vec[gid] != 0xFFFFFFFF)
{
- unsigned bound_width = bounds_map->get (gid);
+ empty = false;
+ unsigned bound_width = bounds_vec[gid];
int rsb = adv - lsb - bound_width;
int extent = lsb + bound_width;
min_lsb = hb_min (min_lsb, lsb);
@@ -134,12 +139,35 @@ struct hmtxvmtx
}
table->advanceMax = max_adv;
- if (!bounds_map->is_empty ())
+ if (!empty)
{
table->minLeadingBearing = min_lsb;
table->minTrailingBearing = min_rsb;
table->maxExtent = max_extent;
}
+
+ if (T::is_horizontal)
+ {
+ const auto &OS2 = *c->plan->source->table.OS2;
+ if (OS2.has_data () &&
+ table->ascender == OS2.sTypoAscender &&
+ table->descender == OS2.sTypoDescender &&
+ table->lineGap == OS2.sTypoLineGap)
+ {
+ table->ascender = static_cast<int> (roundf (OS2.sTypoAscender +
+ MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER,
+ c->plan->normalized_coords.arrayZ,
+ c->plan->normalized_coords.length)));
+ table->descender = static_cast<int> (roundf (OS2.sTypoDescender +
+ MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER,
+ c->plan->normalized_coords.arrayZ,
+ c->plan->normalized_coords.length)));
+ table->lineGap = static_cast<int> (roundf (OS2.sTypoLineGap +
+ MVAR.get_var (HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP,
+ c->plan->normalized_coords.arrayZ,
+ c->plan->normalized_coords.length)));
+ }
+ }
}
#endif
@@ -153,25 +181,32 @@ struct hmtxvmtx
hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_serialize_context_t *c,
Iterator it,
- unsigned num_long_metrics)
+ const hb_vector_t<hb_codepoint_pair_t> new_to_old_gid_list,
+ unsigned num_long_metrics,
+ unsigned total_num_metrics)
{
- unsigned idx = 0;
- for (auto _ : it)
+ LongMetric* long_metrics = c->allocate_size<LongMetric> (num_long_metrics * LongMetric::static_size);
+ FWORD* short_metrics = c->allocate_size<FWORD> ((total_num_metrics - num_long_metrics) * FWORD::static_size);
+ if (!long_metrics || !short_metrics) return;
+
+ short_metrics -= num_long_metrics;
+
+ for (auto _ : new_to_old_gid_list)
{
- if (idx < num_long_metrics)
+ hb_codepoint_t gid = _.first;
+ auto mtx = *it++;
+
+ if (gid < num_long_metrics)
{
- LongMetric lm;
- lm.advance = _.first;
- lm.sb = _.second;
- if (unlikely (!c->embed<LongMetric> (&lm))) return;
+ LongMetric& lm = long_metrics[gid];
+ lm.advance = mtx.first;
+ lm.sb = mtx.second;
}
+ // TODO(beyond-64k): This assumes that maxp.numGlyphs is 0xFFFF.
+ else if (gid < 0x10000u)
+ short_metrics[gid] = mtx.second;
else
- {
- FWORD *sb = c->allocate_size<FWORD> (FWORD::static_size);
- if (unlikely (!sb)) return;
- *sb = _.second;
- }
- idx++;
+ ((UFWORD*) short_metrics)[gid] = mtx.first;
}
}
@@ -179,8 +214,7 @@ struct hmtxvmtx
{
TRACE_SUBSET (this);
- T *table_prime = c->serializer->start_embed <T> ();
- if (unlikely (!table_prime)) return_trace (false);
+ auto *table_prime = c->serializer->start_embed <T> ();
accelerator_t _mtx (c->plan->source);
unsigned num_long_metrics;
@@ -189,7 +223,9 @@ struct hmtxvmtx
/* Determine num_long_metrics to encode. */
auto& plan = c->plan;
- num_long_metrics = plan->num_output_glyphs ();
+ // TODO Don't consider retaingid holes here.
+
+ num_long_metrics = hb_min (plan->num_output_glyphs (), 0xFFFFu);
unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx);
while (num_long_metrics > 1 &&
last_advance == get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 2, _mtx))
@@ -199,30 +235,36 @@ struct hmtxvmtx
}
auto it =
- + hb_range (c->plan->num_output_glyphs ())
- | hb_map ([c, &_mtx, mtx_map] (unsigned _)
+ + hb_iter (c->plan->new_to_old_gid_list)
+ | hb_map ([c, &_mtx, mtx_map] (hb_codepoint_pair_t _)
{
- if (!mtx_map->has (_))
+ hb_codepoint_t new_gid = _.first;
+ hb_codepoint_t old_gid = _.second;
+
+ hb_pair_t<unsigned, int> *v = nullptr;
+ if (!mtx_map->has (new_gid, &v))
{
- hb_codepoint_t old_gid;
- if (!c->plan->old_gid_for_new_gid (_, &old_gid))
- return hb_pair (0u, 0);
int lsb = 0;
- (void) _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb);
+ if (!_mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb))
+ (void) _glyf_get_leading_bearing_without_var_unscaled (c->plan->source, old_gid, !T::is_horizontal, &lsb);
return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb);
}
- return mtx_map->get (_);
+ return *v;
})
;
- table_prime->serialize (c->serializer, it, num_long_metrics);
+ table_prime->serialize (c->serializer,
+ it,
+ c->plan->new_to_old_gid_list,
+ num_long_metrics,
+ c->plan->num_output_glyphs ());
if (unlikely (c->serializer->in_error ()))
return_trace (false);
// Amend header num hmetrics
if (unlikely (!subset_update_header (c, num_long_metrics, mtx_map,
- T::is_horizontal ? &c->plan->bounds_width_map : &c->plan->bounds_height_map)))
+ T::is_horizontal ? c->plan->bounds_width_vec : c->plan->bounds_height_vec)))
return_trace (false);
return_trace (true);
@@ -355,7 +397,7 @@ struct hmtxvmtx
unsigned get_advance_with_var_unscaled (hb_codepoint_t glyph,
hb_font_t *font,
- VariationStore::cache_t *store_cache = nullptr) const
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{
unsigned int advance = get_advance_without_var_unscaled (glyph);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-kern-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-kern-table.hh
index ffa11bc249..39444d803f 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-kern-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-kern-table.hh
@@ -79,6 +79,7 @@ struct KernSubTableFormat3
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
c->check_range (kernValueZ,
kernValueCount * sizeof (FWORD) +
glyphCount * 2 +
@@ -147,9 +148,10 @@ struct KernSubTable
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- if (unlikely (!u.header.sanitize (c) ||
- u.header.length < u.header.min_size ||
- !c->check_range (this, u.header.length))) return_trace (false);
+ if (unlikely (!(u.header.sanitize (c) &&
+ hb_barrier () &&
+ u.header.length >= u.header.min_size &&
+ c->check_range (this, u.header.length)))) return_trace (false);
return_trace (dispatch (c));
}
@@ -337,6 +339,7 @@ struct kern
{
TRACE_SANITIZE (this);
if (!u.version32.sanitize (c)) return_trace (false);
+ hb_barrier ();
return_trace (dispatch (c));
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh
index 8179e5acd5..0278399069 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-base-table.hh
@@ -46,6 +46,12 @@ struct BaseCoordFormat1
return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate);
}
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ return_trace ((bool) c->serializer->embed (*this));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -67,6 +73,17 @@ struct BaseCoordFormat2
return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (coordinate) : font->em_scale_x (coordinate);
}
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ return_trace (c->serializer->check_assign (out->referenceGlyph,
+ c->plan->glyph_map->get (referenceGlyph),
+ HB_SERIALIZE_ERROR_INT_OVERFLOW));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -86,7 +103,7 @@ struct BaseCoordFormat2
struct BaseCoordFormat3
{
hb_position_t get_coord (hb_font_t *font,
- const VariationStore &var_store,
+ const ItemVariationStore &var_store,
hb_direction_t direction) const
{
const Device &device = this+deviceTable;
@@ -96,6 +113,23 @@ struct BaseCoordFormat3
: font->em_scale_x (coordinate) + device.get_x_delta (font, var_store);
}
+ void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
+ {
+ unsigned varidx = (this+deviceTable).get_variation_index ();
+ varidx_set.add (varidx);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable,
+ this, 0,
+ hb_serialize_context_t::Head,
+ &c->plan->base_variation_idx_map));
+ }
bool sanitize (hb_sanitize_context_t *c) const
{
@@ -120,7 +154,7 @@ struct BaseCoord
bool has_data () const { return u.format; }
hb_position_t get_coord (hb_font_t *font,
- const VariationStore &var_store,
+ const ItemVariationStore &var_store,
hb_direction_t direction) const
{
switch (u.format) {
@@ -131,10 +165,32 @@ struct BaseCoord
}
}
+ void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
+ {
+ switch (u.format) {
+ case 3: u.format3.collect_variation_indices (varidx_set);
+ default:return;
+ }
+ }
+
+ template <typename context_t, typename ...Ts>
+ typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+ {
+ if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
+ TRACE_DISPATCH (this, u.format);
+ switch (u.format) {
+ case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+ case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+ case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+ default:return_trace (c->default_return_value ());
+ }
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!u.format.sanitize (c))) return_trace (false);
+ hb_barrier ();
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
@@ -160,18 +216,43 @@ struct FeatMinMaxRecord
bool has_data () const { return tag; }
+ hb_tag_t get_feature_tag () const { return tag; }
+
void get_min_max (const BaseCoord **min, const BaseCoord **max) const
{
if (likely (min)) *min = &(this+minCoord);
if (likely (max)) *max = &(this+maxCoord);
}
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ const void *base,
+ hb_set_t& varidx_set /* OUT */) const
+ {
+ if (!plan->layout_features.has (tag))
+ return;
+
+ (base+minCoord).collect_variation_indices (varidx_set);
+ (base+maxCoord).collect_variation_indices (varidx_set);
+ }
+
+ bool subset (hb_subset_context_t *c,
+ const void *base) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+ if (!(out->minCoord.serialize_subset (c, minCoord, base)))
+ return_trace (false);
+
+ return_trace (out->maxCoord.serialize_subset (c, maxCoord, base));
+ }
+
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
- minCoord.sanitize (c, this) &&
- maxCoord.sanitize (c, this)));
+ minCoord.sanitize (c, base) &&
+ maxCoord.sanitize (c, base)));
}
protected:
@@ -187,7 +268,6 @@ struct FeatMinMaxRecord
* of MinMax table (may be NULL) */
public:
DEFINE_SIZE_STATIC (8);
-
};
struct MinMax
@@ -206,6 +286,39 @@ struct MinMax
}
}
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ hb_set_t& varidx_set /* OUT */) const
+ {
+ (this+minCoord).collect_variation_indices (varidx_set);
+ (this+maxCoord).collect_variation_indices (varidx_set);
+ for (const FeatMinMaxRecord& record : featMinMaxRecords)
+ record.collect_variation_indices (plan, this, varidx_set);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+ if (!(out->minCoord.serialize_subset (c, minCoord, this)) ||
+ !(out->maxCoord.serialize_subset (c, maxCoord, this)))
+ return_trace (false);
+
+ unsigned len = 0;
+ for (const FeatMinMaxRecord& _ : featMinMaxRecords)
+ {
+ hb_tag_t feature_tag = _.get_feature_tag ();
+ if (!c->plan->layout_features.has (feature_tag))
+ continue;
+
+ if (!_.subset (c, this)) return false;
+ len++;
+ }
+ return_trace (c->serializer->check_assign (out->featMinMaxRecords.len, len,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -240,6 +353,26 @@ struct BaseValues
return this+baseCoords[baseline_tag_index];
}
+ void collect_variation_indices (hb_set_t& varidx_set /* OUT */) const
+ {
+ for (const auto& _ : baseCoords)
+ (this+_).collect_variation_indices (varidx_set);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ out->defaultIndex = defaultIndex;
+
+ for (const auto& _ : baseCoords)
+ if (!subset_offset_array (c, out->baseCoords, this) (_))
+ return_trace (false);
+
+ return_trace (bool (out->baseCoords));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -270,11 +403,25 @@ struct BaseLangSysRecord
const MinMax &get_min_max () const { return this+minMax; }
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ hb_set_t& varidx_set /* OUT */) const
+ { (this+minMax).collect_variation_indices (plan, varidx_set); }
+
+ bool subset (hb_subset_context_t *c,
+ const void *base) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ return_trace (out->minMax.serialize_subset (c, minMax, base));
+ }
+
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
- minMax.sanitize (c, this)));
+ minMax.sanitize (c, base)));
}
protected:
@@ -297,7 +444,37 @@ struct BaseScript
const BaseCoord &get_base_coord (int baseline_tag_index) const
{ return (this+baseValues).get_base_coord (baseline_tag_index); }
- bool has_data () const { return baseValues; }
+ bool has_values () const { return baseValues; }
+ bool has_min_max () const { return defaultMinMax; /* TODO What if only per-language is present? */ }
+
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ hb_set_t& varidx_set /* OUT */) const
+ {
+ (this+baseValues).collect_variation_indices (varidx_set);
+ (this+defaultMinMax).collect_variation_indices (plan, varidx_set);
+
+ for (const BaseLangSysRecord& _ : baseLangSysRecords)
+ _.collect_variation_indices (plan, varidx_set);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+ if (baseValues && !out->baseValues.serialize_subset (c, baseValues, this))
+ return_trace (false);
+
+ if (defaultMinMax && !out->defaultMinMax.serialize_subset (c, defaultMinMax, this))
+ return_trace (false);
+
+ for (const auto& _ : baseLangSysRecords)
+ if (!_.subset (c, this)) return_trace (false);
+
+ return_trace (c->serializer->check_assign (out->baseLangSysRecords.len, baseLangSysRecords.len,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW));
+ }
bool sanitize (hb_sanitize_context_t *c) const
{
@@ -331,9 +508,31 @@ struct BaseScriptRecord
bool has_data () const { return baseScriptTag; }
+ hb_tag_t get_script_tag () const { return baseScriptTag; }
+
const BaseScript &get_base_script (const BaseScriptList *list) const
{ return list+baseScript; }
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ const void* list,
+ hb_set_t& varidx_set /* OUT */) const
+ {
+ if (!plan->layout_scripts.has (baseScriptTag))
+ return;
+
+ (list+baseScript).collect_variation_indices (plan, varidx_set);
+ }
+
+ bool subset (hb_subset_context_t *c,
+ const void *base) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ return_trace (out->baseScript.serialize_subset (c, baseScript, base));
+ }
+
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
@@ -360,6 +559,33 @@ struct BaseScriptList
return record->has_data () ? record->get_base_script (this) : Null (BaseScript);
}
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ hb_set_t& varidx_set /* OUT */) const
+ {
+ for (const BaseScriptRecord& _ : baseScriptRecords)
+ _.collect_variation_indices (plan, this, varidx_set);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+ unsigned len = 0;
+ for (const BaseScriptRecord& _ : baseScriptRecords)
+ {
+ hb_tag_t script_tag = _.get_script_tag ();
+ if (!c->plan->layout_scripts.has (script_tag))
+ continue;
+
+ if (!_.subset (c, this)) return false;
+ len++;
+ }
+ return_trace (c->serializer->check_assign (out->baseScriptRecords.len, len,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@@ -383,7 +609,7 @@ struct Axis
const BaseCoord **coord) const
{
const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
- if (!base_script.has_data ())
+ if (!base_script.has_values ())
{
*coord = nullptr;
return false;
@@ -410,7 +636,7 @@ struct Axis
const BaseCoord **max_coord) const
{
const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
- if (!base_script.has_data ())
+ if (!base_script.has_min_max ())
{
*min_coord = *max_coord = nullptr;
return false;
@@ -421,12 +647,26 @@ struct Axis
return true;
}
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ hb_set_t& varidx_set /* OUT */) const
+ { (this+baseScriptList).collect_variation_indices (plan, varidx_set); }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ out->baseTagList.serialize_copy (c->serializer, baseTagList, this);
+ return_trace (out->baseScriptList.serialize_subset (c, baseScriptList, this));
+ }
+
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
- (this+baseTagList).sanitize (c) &&
- (this+baseScriptList).sanitize (c)));
+ baseTagList.sanitize (c, this) &&
+ baseScriptList.sanitize (c, this)));
}
protected:
@@ -452,8 +692,41 @@ struct BASE
const Axis &get_axis (hb_direction_t direction) const
{ return HB_DIRECTION_IS_VERTICAL (direction) ? this+vAxis : this+hAxis; }
- const VariationStore &get_var_store () const
- { return version.to_int () < 0x00010001u ? Null (VariationStore) : this+varStore; }
+ bool has_var_store () const
+ { return version.to_int () >= 0x00010001u && varStore != 0; }
+
+ const ItemVariationStore &get_var_store () const
+ { return version.to_int () < 0x00010001u ? Null (ItemVariationStore) : this+varStore; }
+
+ void collect_variation_indices (const hb_subset_plan_t* plan,
+ hb_set_t& varidx_set /* OUT */) const
+ {
+ (this+hAxis).collect_variation_indices (plan, varidx_set);
+ (this+vAxis).collect_variation_indices (plan, varidx_set);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->start_embed (*this);
+ if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+
+ out->version = version;
+ if (hAxis && !out->hAxis.serialize_subset (c, hAxis, this))
+ return_trace (false);
+
+ if (vAxis && !out->vAxis.serialize_subset (c, vAxis, this))
+ return_trace (false);
+
+ if (has_var_store ())
+ {
+ if (!c->serializer->allocate_size<Offset32To<ItemVariationStore>> (Offset32To<ItemVariationStore>::static_size))
+ return_trace (false);
+ return_trace (out->varStore.serialize_subset (c, varStore, this, c->plan->base_varstore_inner_maps.as_array ()));
+ }
+
+ return_trace (true);
+ }
bool get_baseline (hb_font_t *font,
hb_tag_t baseline_tag,
@@ -473,21 +746,20 @@ struct BASE
return true;
}
- /* TODO: Expose this separately sometime? */
bool get_min_max (hb_font_t *font,
hb_direction_t direction,
hb_tag_t script_tag,
hb_tag_t language_tag,
hb_tag_t feature_tag,
hb_position_t *min,
- hb_position_t *max)
+ hb_position_t *max) const
{
const BaseCoord *min_coord, *max_coord;
if (!get_axis (direction).get_min_max (script_tag, language_tag, feature_tag,
&min_coord, &max_coord))
return false;
- const VariationStore &var_store = get_var_store ();
+ const ItemVariationStore &var_store = get_var_store ();
if (likely (min && min_coord)) *min = min_coord->get_coord (font, var_store, direction);
if (likely (max && max_coord)) *max = max_coord->get_coord (font, var_store, direction);
return true;
@@ -497,6 +769,7 @@ struct BASE
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
+ hb_barrier () &&
likely (version.major == 1) &&
hAxis.sanitize (c, this) &&
vAxis.sanitize (c, this) &&
@@ -509,7 +782,7 @@ struct BASE
* of BASE table (may be NULL) */
Offset16To<Axis>vAxis; /* Offset to vertical Axis table, from beginning
* of BASE table (may be NULL) */
- Offset32To<VariationStore>
+ Offset32To<ItemVariationStore>
varStore; /* Offset to the table of Item Variation
* Store--from beginning of BASE
* header (may be NULL). Introduced
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh
index b53f2e9276..aba427368c 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh
@@ -55,19 +55,22 @@ static bool ClassDef_remap_and_serialize (
hb_serialize_context_t *c,
const hb_set_t &klasses,
bool use_class_zero,
- hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> &glyph_and_klass, /* IN/OUT */
+ hb_sorted_vector_t<hb_codepoint_pair_t> &glyph_and_klass, /* IN/OUT */
hb_map_t *klass_map /*IN/OUT*/);
struct hb_collect_feature_substitutes_with_var_context_t
{
const hb_map_t *axes_index_tag_map;
- const hb_hashmap_t<hb_tag_t, int> *axes_location;
+ const hb_hashmap_t<hb_tag_t, Triple> *axes_location;
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *record_cond_idx_map;
hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
+ hb_set_t& catch_all_record_feature_idxes;
// not stored in subset_plan
hb_set_t *feature_indices;
bool apply;
+ bool variation_applied;
+ bool universal;
unsigned cur_record_idx;
hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> *conditionset_map;
};
@@ -139,6 +142,8 @@ struct hb_subset_layout_context_t :
const hb_map_t *feature_index_map;
const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map;
+ const hb_set_t *catch_all_record_feature_idxes;
+ const hb_hashmap_t<unsigned, hb_pair_t<const void*, const void*>> *feature_idx_tag_map;
unsigned cur_script_index;
unsigned cur_feature_var_record_idx;
@@ -161,6 +166,8 @@ struct hb_subset_layout_context_t :
feature_index_map = &c_->plan->gsub_features;
feature_substitutes_map = &c_->plan->gsub_feature_substitutes_map;
feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gsub_feature_record_cond_idx_map;
+ catch_all_record_feature_idxes = &c_->plan->gsub_old_features;
+ feature_idx_tag_map = &c_->plan->gsub_old_feature_idx_tag_map;
}
else
{
@@ -169,6 +176,8 @@ struct hb_subset_layout_context_t :
feature_index_map = &c_->plan->gpos_features;
feature_substitutes_map = &c_->plan->gpos_feature_substitutes_map;
feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gpos_feature_record_cond_idx_map;
+ catch_all_record_feature_idxes = &c_->plan->gpos_old_features;
+ feature_idx_tag_map = &c_->plan->gpos_old_feature_idx_tag_map;
}
}
@@ -179,7 +188,7 @@ struct hb_subset_layout_context_t :
unsigned lookup_index_count;
};
-struct VariationStore;
+struct ItemVariationStore;
struct hb_collect_variation_indices_context_t :
hb_dispatch_context_t<hb_collect_variation_indices_context_t>
{
@@ -188,27 +197,15 @@ struct hb_collect_variation_indices_context_t :
static return_t default_return_value () { return hb_empty_t (); }
hb_set_t *layout_variation_indices;
- hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map;
- hb_font_t *font;
- const VariationStore *var_store;
const hb_set_t *glyph_set;
const hb_map_t *gpos_lookups;
- float *store_cache;
hb_collect_variation_indices_context_t (hb_set_t *layout_variation_indices_,
- hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map_,
- hb_font_t *font_,
- const VariationStore *var_store_,
const hb_set_t *glyph_set_,
- const hb_map_t *gpos_lookups_,
- float *store_cache_) :
+ const hb_map_t *gpos_lookups_) :
layout_variation_indices (layout_variation_indices_),
- varidx_delta_map (varidx_delta_map_),
- font (font_),
- var_store (var_store_),
glyph_set (glyph_set_),
- gpos_lookups (gpos_lookups_),
- store_cache (store_cache_) {}
+ gpos_lookups (gpos_lookups_) {}
};
template<typename OutputArray>
@@ -463,6 +460,7 @@ struct FeatureParamsSize
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) return_trace (false);
+ hb_barrier ();
/* This subtable has some "history", if you will. Some earlier versions of
* Adobe tools calculated the offset of the FeatureParams subtable from the
@@ -529,6 +527,9 @@ struct FeatureParamsSize
return_trace (true);
}
+ void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const
+ { nameids_to_retain->add (subfamilyNameID); }
+
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
@@ -585,6 +586,9 @@ struct FeatureParamsStylisticSet
return_trace (c->check_struct (this));
}
+ void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const
+ { nameids_to_retain->add (uiNameID); }
+
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
@@ -632,6 +636,20 @@ struct FeatureParamsCharacterVariants
unsigned get_size () const
{ return min_size + characters.len * HBUINT24::static_size; }
+ void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const
+ {
+ if (featUILableNameID) nameids_to_retain->add (featUILableNameID);
+ if (featUITooltipTextNameID) nameids_to_retain->add (featUITooltipTextNameID);
+ if (sampleTextNameID) nameids_to_retain->add (sampleTextNameID);
+
+ if (!firstParamUILabelNameID || !numNamedParameters || numNamedParameters >= 0x7FFF)
+ return;
+
+ unsigned last_name_id = (unsigned) firstParamUILabelNameID + (unsigned) numNamedParameters - 1;
+ if (last_name_id >= 256 && last_name_id <= 32767)
+ nameids_to_retain->add_range (firstParamUILabelNameID, last_name_id);
+ }
+
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
@@ -694,6 +712,19 @@ struct FeatureParams
return_trace (true);
}
+ void collect_name_ids (hb_tag_t tag, hb_set_t *nameids_to_retain /* OUT */) const
+ {
+#ifdef HB_NO_LAYOUT_FEATURE_PARAMS
+ return;
+#endif
+ if (tag == HB_TAG ('s','i','z','e'))
+ return (u.size.collect_name_ids (nameids_to_retain));
+ if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */
+ return (u.stylisticSet.collect_name_ids (nameids_to_retain));
+ if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */
+ return (u.characterVariants.collect_name_ids (nameids_to_retain));
+ }
+
bool subset (hb_subset_context_t *c, const Tag* tag) const
{
TRACE_SUBSET (this);
@@ -762,13 +793,19 @@ struct Feature
bool intersects_lookup_indexes (const hb_map_t *lookup_indexes) const
{ return lookupIndex.intersects (lookup_indexes); }
+ void collect_name_ids (hb_tag_t tag, hb_set_t *nameids_to_retain /* OUT */) const
+ {
+ if (featureParams)
+ get_feature_params ().collect_name_ids (tag, nameids_to_retain);
+ }
+
bool subset (hb_subset_context_t *c,
hb_subset_layout_context_t *l,
const Tag *tag = nullptr) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->featureParams.serialize_subset (c, featureParams, this, tag);
@@ -790,6 +827,7 @@ struct Feature
TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
return_trace (false);
+ hb_barrier ();
/* Some earlier versions of Adobe tools calculated the offset of the
* FeatureParams subtable from the beginning of the FeatureList table!
@@ -808,6 +846,7 @@ struct Feature
unsigned int orig_offset = featureParams;
if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)))
return_trace (false);
+ hb_barrier ();
if (featureParams == 0 && closure &&
closure->tag == HB_TAG ('s','i','z','e') &&
@@ -870,7 +909,8 @@ struct Record
{
TRACE_SANITIZE (this);
const Record_sanitize_closure_t closure = {tag, base};
- return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
+ return_trace (c->check_struct (this) &&
+ offset.sanitize (c, base, &closure));
}
Tag tag; /* 4-byte Tag identifier */
@@ -942,7 +982,7 @@ struct RecordListOfFeature : RecordListOf<Feature>
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ hb_enumerate (*this)
| hb_filter (l->feature_index_map, hb_first)
@@ -1039,7 +1079,7 @@ struct LangSys
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
const uint32_t *v;
out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex, &v) ? *v : 0xFFFFu;
@@ -1149,7 +1189,7 @@ struct Script
return false;
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
bool defaultLang = false;
if (has_default_lang_sys ())
@@ -1208,7 +1248,7 @@ struct RecordListOfScript : RecordListOf<Script>
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
for (auto _ : + hb_enumerate (*this))
{
@@ -1328,7 +1368,7 @@ struct Lookup
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->lookupType = lookupType;
out->lookupFlag = lookupFlag;
@@ -1341,10 +1381,20 @@ struct Lookup
if (lookupFlag & LookupFlag::UseMarkFilteringSet)
{
- if (unlikely (!c->serializer->extend (out))) return_trace (false);
const HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
- HBUINT16 &outMarkFilteringSet = StructAfter<HBUINT16> (out->subTable);
- outMarkFilteringSet = markFilteringSet;
+ hb_codepoint_t *idx;
+ if (!c->plan->used_mark_sets_map.has (markFilteringSet, &idx))
+ {
+ unsigned new_flag = lookupFlag;
+ new_flag &= ~LookupFlag::UseMarkFilteringSet;
+ out->lookupFlag = new_flag;
+ }
+ else
+ {
+ if (unlikely (!c->serializer->extend (out))) return_trace (false);
+ HBUINT16 &outMarkFilteringSet = StructAfter<HBUINT16> (out->subTable);
+ outMarkFilteringSet = *idx;
+ }
}
// Always keep the lookup even if it's empty. The rest of layout subsetting depends on lookup
@@ -1361,6 +1411,7 @@ struct Lookup
{
TRACE_SANITIZE (this);
if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false);
+ hb_barrier ();
unsigned subtables = get_subtable_count ();
if (unlikely (!c->visit_subtables (subtables))) return_trace (false);
@@ -1376,6 +1427,8 @@ struct Lookup
if (unlikely (get_type () == TSubTable::Extension && !c->get_edit_count ()))
{
+ hb_barrier ();
+
/* The spec says all subtables of an Extension lookup should
* have the same type, which shall not be the Extension type
* itself (but we already checked for that).
@@ -1417,7 +1470,7 @@ struct LookupOffsetList : List16OfOffsetTo<TLookup, OffsetType>
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
- if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ hb_enumerate (*this)
| hb_filter (l->lookup_index_map, hb_first)
@@ -1443,7 +1496,7 @@ struct LookupOffsetList : List16OfOffsetTo<TLookup, OffsetType>
static bool ClassDef_remap_and_serialize (hb_serialize_context_t *c,
const hb_set_t &klasses,
bool use_class_zero,
- hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> &glyph_and_klass, /* IN/OUT */
+ hb_sorted_vector_t<hb_codepoint_pair_t> &glyph_and_klass, /* IN/OUT */
hb_map_t *klass_map /*IN/OUT*/)
{
if (!klass_map)
@@ -1534,7 +1587,7 @@ struct ClassDefFormat1_3
TRACE_SUBSET (this);
const hb_map_t &glyph_map = c->plan->glyph_map_gsub;
- hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> glyph_and_klass;
+ hb_sorted_vector_t<hb_codepoint_pair_t> glyph_and_klass;
hb_set_t orig_klasses;
hb_codepoint_t start = startGlyph;
@@ -1553,10 +1606,13 @@ struct ClassDefFormat1_3
orig_klasses.add (klass);
}
- unsigned glyph_count = glyph_filter
- ? hb_len (hb_iter (glyph_map.keys()) | hb_filter (glyph_filter))
- : glyph_map.get_population ();
- use_class_zero = use_class_zero && glyph_count <= glyph_and_klass.length;
+ if (use_class_zero)
+ {
+ unsigned glyph_count = glyph_filter
+ ? hb_len (hb_iter (glyph_map.keys()) | hb_filter (glyph_filter))
+ : glyph_map.get_population ();
+ use_class_zero = glyph_count <= glyph_and_klass.length;
+ }
if (!ClassDef_remap_and_serialize (c->serializer,
orig_klasses,
use_class_zero,
@@ -1730,6 +1786,7 @@ struct ClassDefFormat2_4
return_trace (true);
}
+ unsigned unsorted = false;
unsigned num_ranges = 1;
hb_codepoint_t prev_gid = (*it).first;
unsigned prev_klass = (*it).second;
@@ -1750,6 +1807,10 @@ struct ClassDefFormat2_4
if (cur_gid != prev_gid + 1 ||
cur_klass != prev_klass)
{
+
+ if (unlikely (cur_gid < prev_gid))
+ unsorted = true;
+
if (unlikely (!record)) break;
record->last = prev_gid;
num_ranges++;
@@ -1765,8 +1826,14 @@ struct ClassDefFormat2_4
prev_gid = cur_gid;
}
+ if (unlikely (c->in_error ())) return_trace (false);
+
if (likely (record)) record->last = prev_gid;
rangeRecord.len = num_ranges;
+
+ if (unlikely (unsorted))
+ rangeRecord.as_array ().qsort (RangeRecord<Types>::cmp_range);
+
return_trace (true);
}
@@ -1780,7 +1847,7 @@ struct ClassDefFormat2_4
const hb_map_t &glyph_map = c->plan->glyph_map_gsub;
const hb_set_t &glyph_set = *c->plan->glyphset_gsub ();
- hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> glyph_and_klass;
+ hb_sorted_vector_t<hb_codepoint_pair_t> glyph_and_klass;
hb_set_t orig_klasses;
if (glyph_set.get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2
@@ -1866,7 +1933,7 @@ struct ClassDefFormat2_4
{
if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2)
{
- for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);)
+ for (auto g : *glyphs)
if (get_class (g))
return true;
return false;
@@ -1881,13 +1948,22 @@ struct ClassDefFormat2_4
{
/* Match if there's any glyph that is not listed! */
hb_codepoint_t g = HB_SET_VALUE_INVALID;
- for (auto &range : rangeRecord)
+ hb_codepoint_t last = HB_SET_VALUE_INVALID;
+ auto it = hb_iter (rangeRecord);
+ for (auto &range : it)
{
+ if (it->first == last + 1)
+ {
+ it++;
+ continue;
+ }
+
if (!glyphs->next (&g))
break;
if (g < range.first)
return true;
g = range.last;
+ last = g;
}
if (g != HB_SET_VALUE_INVALID && glyphs->next (&g))
return true;
@@ -1926,8 +2002,7 @@ struct ClassDefFormat2_4
unsigned count = rangeRecord.len;
if (count > glyphs->get_population () * hb_bit_storage (count) * 8)
{
- for (hb_codepoint_t g = HB_SET_VALUE_INVALID;
- glyphs->next (&g);)
+ for (auto g : *glyphs)
{
unsigned i;
if (rangeRecord.as_array ().bfind (g, &i) &&
@@ -2058,8 +2133,15 @@ struct ClassDef
#ifndef HB_NO_BEYOND_64K
if (glyph_max > 0xFFFFu)
- format += 2;
+ u.format += 2;
+ if (unlikely (glyph_max > 0xFFFFFFu))
+#else
+ if (unlikely (glyph_max > 0xFFFFu))
#endif
+ {
+ c->check_success (false, HB_SERIALIZE_ERROR_INT_OVERFLOW);
+ return_trace (false);
+ }
u.format = format;
@@ -2097,6 +2179,7 @@ struct ClassDef
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
+ hb_barrier ();
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
@@ -2229,23 +2312,176 @@ static inline bool ClassDef_serialize (hb_serialize_context_t *c,
* Item Variation Store
*/
+/* ported from fonttools (class _Encoding) */
+struct delta_row_encoding_t
+{
+ /* each byte represents a region, value is one of 0/1/2/4, which means bytes
+ * needed for this region */
+ hb_vector_t<uint8_t> chars;
+ unsigned width = 0;
+ hb_vector_t<uint8_t> columns;
+ unsigned overhead = 0;
+ hb_vector_t<const hb_vector_t<int>*> items;
+
+ delta_row_encoding_t () = default;
+ delta_row_encoding_t (hb_vector_t<uint8_t>&& chars_,
+ const hb_vector_t<int>* row = nullptr) :
+ delta_row_encoding_t ()
+
+ {
+ chars = std::move (chars_);
+ width = get_width ();
+ columns = get_columns ();
+ overhead = get_chars_overhead (columns);
+ if (row) items.push (row);
+ }
+
+ bool is_empty () const
+ { return !items; }
+
+ static hb_vector_t<uint8_t> get_row_chars (const hb_vector_t<int>& row)
+ {
+ hb_vector_t<uint8_t> ret;
+ if (!ret.alloc (row.length)) return ret;
+
+ bool long_words = false;
+
+ /* 0/1/2 byte encoding */
+ for (int i = row.length - 1; i >= 0; i--)
+ {
+ int v = row.arrayZ[i];
+ if (v == 0)
+ ret.push (0);
+ else if (v > 32767 || v < -32768)
+ {
+ long_words = true;
+ break;
+ }
+ else if (v > 127 || v < -128)
+ ret.push (2);
+ else
+ ret.push (1);
+ }
+
+ if (!long_words)
+ return ret;
+
+ /* redo, 0/2/4 bytes encoding */
+ ret.reset ();
+ for (int i = row.length - 1; i >= 0; i--)
+ {
+ int v = row.arrayZ[i];
+ if (v == 0)
+ ret.push (0);
+ else if (v > 32767 || v < -32768)
+ ret.push (4);
+ else
+ ret.push (2);
+ }
+ return ret;
+ }
+
+ inline unsigned get_width ()
+ {
+ unsigned ret = + hb_iter (chars)
+ | hb_reduce (hb_add, 0u)
+ ;
+ return ret;
+ }
+
+ hb_vector_t<uint8_t> get_columns ()
+ {
+ hb_vector_t<uint8_t> cols;
+ cols.alloc (chars.length);
+ for (auto v : chars)
+ {
+ uint8_t flag = v ? 1 : 0;
+ cols.push (flag);
+ }
+ return cols;
+ }
+
+ static inline unsigned get_chars_overhead (const hb_vector_t<uint8_t>& cols)
+ {
+ unsigned c = 4 + 6; // 4 bytes for LOffset, 6 bytes for VarData header
+ unsigned cols_bit_count = 0;
+ for (auto v : cols)
+ if (v) cols_bit_count++;
+ return c + cols_bit_count * 2;
+ }
+
+ unsigned get_gain () const
+ {
+ int count = items.length;
+ return hb_max (0, (int) overhead - count);
+ }
+
+ int gain_from_merging (const delta_row_encoding_t& other_encoding) const
+ {
+ int combined_width = 0;
+ for (unsigned i = 0; i < chars.length; i++)
+ combined_width += hb_max (chars.arrayZ[i], other_encoding.chars.arrayZ[i]);
+
+ hb_vector_t<uint8_t> combined_columns;
+ combined_columns.alloc (columns.length);
+ for (unsigned i = 0; i < columns.length; i++)
+ combined_columns.push (columns.arrayZ[i] | other_encoding.columns.arrayZ[i]);
+
+ int combined_overhead = get_chars_overhead (combined_columns);
+ int combined_gain = (int) overhead + (int) other_encoding.overhead - combined_overhead
+ - (combined_width - (int) width) * items.length
+ - (combined_width - (int) other_encoding.width) * other_encoding.items.length;
+
+ return combined_gain;
+ }
+
+ static int cmp (const void *pa, const void *pb)
+ {
+ const delta_row_encoding_t *a = (const delta_row_encoding_t *)pa;
+ const delta_row_encoding_t *b = (const delta_row_encoding_t *)pb;
+
+ int gain_a = a->get_gain ();
+ int gain_b = b->get_gain ();
+
+ if (gain_a != gain_b)
+ return gain_a - gain_b;
+
+ return (b->chars).as_array ().cmp ((a->chars).as_array ());
+ }
+
+ static int cmp_width (const void *pa, const void *pb)
+ {
+ const delta_row_encoding_t *a = (const delta_row_encoding_t *)pa;
+ const delta_row_encoding_t *b = (const delta_row_encoding_t *)pb;
+
+ if (a->width != b->width)
+ return (int) a->width - (int) b->width;
+
+ return (b->chars).as_array ().cmp ((a->chars).as_array ());
+ }
+
+ bool add_row (const hb_vector_t<int>* row)
+ { return items.push (row); }
+};
+
struct VarRegionAxis
{
float evaluate (int coord) const
{
- int start = startCoord.to_int (), peak = peakCoord.to_int (), end = endCoord.to_int ();
+ int peak = peakCoord.to_int ();
+ if (peak == 0 || coord == peak)
+ return 1.f;
+
+ int start = startCoord.to_int (), end = endCoord.to_int ();
/* TODO Move these to sanitize(). */
if (unlikely (start > peak || peak > end))
- return 1.;
+ return 1.f;
if (unlikely (start < 0 && end > 0 && peak != 0))
- return 1.;
-
- if (peak == 0 || coord == peak)
- return 1.;
+ return 1.f;
if (coord <= start || end <= coord)
- return 0.;
+ return 0.f;
/* Interpolate */
if (coord < peak)
@@ -2262,6 +2498,12 @@ struct VarRegionAxis
* have to do that at runtime. */
}
+ bool serialize (hb_serialize_context_t *c) const
+ {
+ TRACE_SERIALIZE (this);
+ return_trace (c->embed (this));
+ }
+
public:
F2DOT14 startCoord;
F2DOT14 peakCoord;
@@ -2316,10 +2558,53 @@ struct VarRegionList
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) && axesZ.sanitize (c, axisCount * regionCount));
+ return_trace (c->check_struct (this) &&
+ hb_barrier () &&
+ axesZ.sanitize (c, axisCount * regionCount));
}
- bool serialize (hb_serialize_context_t *c, const VarRegionList *src, const hb_bimap_t &region_map)
+ bool serialize (hb_serialize_context_t *c,
+ const hb_vector_t<hb_tag_t>& axis_tags,
+ const hb_vector_t<const hb_hashmap_t<hb_tag_t, Triple>*>& regions)
+ {
+ TRACE_SERIALIZE (this);
+ unsigned axis_count = axis_tags.length;
+ unsigned region_count = regions.length;
+ if (!axis_count || !region_count) return_trace (false);
+ if (unlikely (hb_unsigned_mul_overflows (axis_count * region_count,
+ VarRegionAxis::static_size))) return_trace (false);
+ if (unlikely (!c->extend_min (this))) return_trace (false);
+ axisCount = axis_count;
+ regionCount = region_count;
+
+ for (unsigned r = 0; r < region_count; r++)
+ {
+ const auto& region = regions[r];
+ for (unsigned i = 0; i < axis_count; i++)
+ {
+ hb_tag_t tag = axis_tags.arrayZ[i];
+ VarRegionAxis var_region_rec;
+ Triple *coords;
+ if (region->has (tag, &coords))
+ {
+ var_region_rec.startCoord.set_float (coords->minimum);
+ var_region_rec.peakCoord.set_float (coords->middle);
+ var_region_rec.endCoord.set_float (coords->maximum);
+ }
+ else
+ {
+ var_region_rec.startCoord.set_int (0);
+ var_region_rec.peakCoord.set_int (0);
+ var_region_rec.endCoord.set_int (0);
+ }
+ if (!var_region_rec.serialize (c))
+ return_trace (false);
+ }
+ }
+ return_trace (true);
+ }
+
+ bool serialize (hb_serialize_context_t *c, const VarRegionList *src, const hb_inc_bimap_t &region_map)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
@@ -2339,6 +2624,45 @@ struct VarRegionList
return_trace (true);
}
+ bool get_var_region (unsigned region_index,
+ const hb_map_t& axes_old_index_tag_map,
+ hb_hashmap_t<hb_tag_t, Triple>& axis_tuples /* OUT */) const
+ {
+ if (region_index >= regionCount) return false;
+ const VarRegionAxis* axis_region = axesZ.arrayZ + (region_index * axisCount);
+ for (unsigned i = 0; i < axisCount; i++)
+ {
+ hb_tag_t *axis_tag;
+ if (!axes_old_index_tag_map.has (i, &axis_tag))
+ return false;
+
+ float min_val = axis_region->startCoord.to_float ();
+ float def_val = axis_region->peakCoord.to_float ();
+ float max_val = axis_region->endCoord.to_float ();
+
+ if (def_val != 0.f)
+ axis_tuples.set (*axis_tag, Triple (min_val, def_val, max_val));
+ axis_region++;
+ }
+ return !axis_tuples.in_error ();
+ }
+
+ bool get_var_regions (const hb_map_t& axes_old_index_tag_map,
+ hb_vector_t<hb_hashmap_t<hb_tag_t, Triple>>& regions /* OUT */) const
+ {
+ if (!regions.alloc (regionCount))
+ return false;
+
+ for (unsigned i = 0; i < regionCount; i++)
+ {
+ hb_hashmap_t<hb_tag_t, Triple> axis_tuples;
+ if (!get_var_region (i, axes_old_index_tag_map, axis_tuples))
+ return false;
+ regions.push (std::move (axis_tuples));
+ }
+ return !regions.in_error ();
+ }
+
unsigned int get_size () const { return min_size + VarRegionAxis::static_size * axisCount * regionCount; }
public:
@@ -2358,6 +2682,9 @@ struct VarData
unsigned int get_region_index_count () const
{ return regionIndices.len; }
+
+ unsigned get_region_index (unsigned i) const
+ { return i >= regionIndices.len ? -1 : regionIndices[i]; }
unsigned int get_row_size () const
{ return (wordCount () + regionIndices.len) * (longWords () ? 2 : 1); }
@@ -2427,6 +2754,7 @@ struct VarData
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
regionIndices.sanitize (c) &&
+ hb_barrier () &&
wordCount () <= regionIndices.len &&
c->check_range (get_delta_bytes (),
itemCount,
@@ -2434,9 +2762,84 @@ struct VarData
}
bool serialize (hb_serialize_context_t *c,
+ bool has_long,
+ const hb_vector_t<const hb_vector_t<int>*>& rows)
+ {
+ TRACE_SERIALIZE (this);
+ if (unlikely (!c->extend_min (this))) return_trace (false);
+ unsigned row_count = rows.length;
+ itemCount = row_count;
+
+ int min_threshold = has_long ? -65536 : -128;
+ int max_threshold = has_long ? +65535 : +127;
+ enum delta_size_t { kZero=0, kNonWord, kWord };
+ hb_vector_t<delta_size_t> delta_sz;
+ unsigned num_regions = rows[0]->length;
+ if (!delta_sz.resize (num_regions))
+ return_trace (false);
+
+ unsigned word_count = 0;
+ for (unsigned r = 0; r < num_regions; r++)
+ {
+ for (unsigned i = 0; i < row_count; i++)
+ {
+ int delta = rows[i]->arrayZ[r];
+ if (delta < min_threshold || delta > max_threshold)
+ {
+ delta_sz[r] = kWord;
+ word_count++;
+ break;
+ }
+ else if (delta != 0)
+ {
+ delta_sz[r] = kNonWord;
+ }
+ }
+ }
+
+ /* reorder regions: words and then non-words*/
+ unsigned word_index = 0;
+ unsigned non_word_index = word_count;
+ hb_map_t ri_map;
+ for (unsigned r = 0; r < num_regions; r++)
+ {
+ if (!delta_sz[r]) continue;
+ unsigned new_r = (delta_sz[r] == kWord)? word_index++ : non_word_index++;
+ if (!ri_map.set (new_r, r))
+ return_trace (false);
+ }
+
+ wordSizeCount = word_count | (has_long ? 0x8000u /* LONG_WORDS */ : 0);
+
+ unsigned ri_count = ri_map.get_population ();
+ regionIndices.len = ri_count;
+ if (unlikely (!c->extend (this))) return_trace (false);
+
+ for (unsigned r = 0; r < ri_count; r++)
+ {
+ hb_codepoint_t *idx;
+ if (!ri_map.has (r, &idx))
+ return_trace (false);
+ regionIndices[r] = *idx;
+ }
+
+ HBUINT8 *delta_bytes = get_delta_bytes ();
+ unsigned row_size = get_row_size ();
+ for (unsigned int i = 0; i < row_count; i++)
+ {
+ for (unsigned int r = 0; r < ri_count; r++)
+ {
+ int delta = rows[i]->arrayZ[ri_map[r]];
+ set_item_delta_fast (i, r, delta, delta_bytes, row_size);
+ }
+ }
+ return_trace (true);
+ }
+
+ bool serialize (hb_serialize_context_t *c,
const VarData *src,
const hb_inc_bimap_t &inner_map,
- const hb_bimap_t &region_map)
+ const hb_inc_bimap_t &region_map)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (this))) return_trace (false);
@@ -2462,10 +2865,9 @@ struct VarData
{
for (r = 0; r < src_word_count; r++)
{
- for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
+ for (unsigned old_gid : inner_map.keys())
{
- unsigned int old = inner_map.backward (i);
- int32_t delta = src->get_item_delta_fast (old, r, src_delta_bytes, src_row_size);
+ int32_t delta = src->get_item_delta_fast (old_gid, r, src_delta_bytes, src_row_size);
if (delta < -65536 || 65535 < delta)
{
has_long = true;
@@ -2482,10 +2884,9 @@ struct VarData
bool short_circuit = src_long_words == has_long && src_word_count <= r;
delta_sz[r] = kZero;
- for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
+ for (unsigned old_gid : inner_map.keys())
{
- unsigned int old = inner_map.backward (i);
- int32_t delta = src->get_item_delta_fast (old, r, src_delta_bytes, src_row_size);
+ int32_t delta = src->get_item_delta_fast (old_gid, r, src_delta_bytes, src_row_size);
if (delta < min_threshold || max_threshold < delta)
{
delta_sz[r] = kWord;
@@ -2546,8 +2947,8 @@ struct VarData
{
unsigned int region = regionIndices.arrayZ[r];
if (region_indices.has (region)) continue;
- for (unsigned int i = 0; i < inner_map.get_next_value (); i++)
- if (get_item_delta_fast (inner_map.backward (i), r, delta_bytes, row_size) != 0)
+ for (hb_codepoint_t old_gid : inner_map.keys())
+ if (get_item_delta_fast (old_gid, r, delta_bytes, row_size) != 0)
{
region_indices.add (region);
break;
@@ -2555,13 +2956,15 @@ struct VarData
}
}
- protected:
+ public:
const HBUINT8 *get_delta_bytes () const
{ return &StructAfter<HBUINT8> (regionIndices); }
+ protected:
HBUINT8 *get_delta_bytes ()
{ return &StructAfter<HBUINT8> (regionIndices); }
+ public:
int32_t get_item_delta_fast (unsigned int item, unsigned int region,
const HBUINT8 *delta_bytes, unsigned row_size) const
{
@@ -2592,6 +2995,7 @@ struct VarData
get_row_size ());
}
+ protected:
void set_item_delta_fast (unsigned int item, unsigned int region, int32_t delta,
HBUINT8 *delta_bytes, unsigned row_size)
{
@@ -2632,8 +3036,9 @@ struct VarData
DEFINE_SIZE_ARRAY (6, regionIndices);
};
-struct VariationStore
+struct ItemVariationStore
{
+ friend struct item_variations_t;
using cache_t = VarRegionList::cache_t;
cache_t *create_cache () const
@@ -2699,13 +3104,44 @@ struct VariationStore
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
format == 1 &&
regions.sanitize (c, this) &&
dataSets.sanitize (c, this));
}
bool serialize (hb_serialize_context_t *c,
- const VariationStore *src,
+ bool has_long,
+ const hb_vector_t<hb_tag_t>& axis_tags,
+ const hb_vector_t<const hb_hashmap_t<hb_tag_t, Triple>*>& region_list,
+ const hb_vector_t<delta_row_encoding_t>& vardata_encodings)
+ {
+ TRACE_SERIALIZE (this);
+#ifdef HB_NO_VAR
+ return_trace (false);
+#endif
+ if (unlikely (!c->extend_min (this))) return_trace (false);
+
+ format = 1;
+ if (!regions.serialize_serialize (c, axis_tags, region_list))
+ return_trace (false);
+
+ unsigned num_var_data = vardata_encodings.length;
+ if (!num_var_data) return_trace (false);
+ if (unlikely (!c->check_assign (dataSets.len, num_var_data,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW)))
+ return_trace (false);
+
+ if (unlikely (!c->extend (dataSets))) return_trace (false);
+ for (unsigned i = 0; i < num_var_data; i++)
+ if (!dataSets[i].serialize_serialize (c, has_long, vardata_encodings[i].items))
+ return_trace (false);
+
+ return_trace (true);
+ }
+
+ bool serialize (hb_serialize_context_t *c,
+ const ItemVariationStore *src,
const hb_array_t <const hb_inc_bimap_t> &inner_maps)
{
TRACE_SERIALIZE (this);
@@ -2761,7 +3197,7 @@ struct VariationStore
return_trace (true);
}
- VariationStore *copy (hb_serialize_context_t *c) const
+ ItemVariationStore *copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
auto *out = c->start_embed (this);
@@ -2791,7 +3227,7 @@ struct VariationStore
return_trace (false);
#endif
- VariationStore *varstore_prime = c->serializer->start_embed<VariationStore> ();
+ ItemVariationStore *varstore_prime = c->serializer->start_embed<ItemVariationStore> ();
if (unlikely (!varstore_prime)) return_trace (false);
varstore_prime->serialize (c->serializer, this, inner_maps);
@@ -2833,6 +3269,22 @@ struct VariationStore
return dataSets.len;
}
+ const VarData& get_sub_table (unsigned i) const
+ {
+#ifdef HB_NO_VAR
+ return Null (VarData);
+#endif
+ return this+dataSets[i];
+ }
+
+ const VarRegionList& get_region_list () const
+ {
+#ifdef HB_NO_VAR
+ return Null (VarRegionList);
+#endif
+ return this+regions;
+ }
+
protected:
HBUINT16 format;
Offset32To<VarRegionList> regions;
@@ -2849,9 +3301,9 @@ struct VariationStore
enum Cond_with_Var_flag_t
{
KEEP_COND_WITH_VAR = 0,
- DROP_COND_WITH_VAR = 1,
- DROP_RECORD_WITH_VAR = 2,
- MEM_ERR_WITH_VAR = 3,
+ KEEP_RECORD_WITH_VAR = 1,
+ DROP_COND_WITH_VAR = 2,
+ DROP_RECORD_WITH_VAR = 3,
};
struct ConditionFormat1
@@ -2867,9 +3319,29 @@ struct ConditionFormat1
const hb_map_t *index_map = &c->plan->axes_index_map;
if (index_map->is_empty ()) return_trace (true);
- if (!index_map->has (axisIndex))
+ const hb_map_t& axes_old_index_tag_map = c->plan->axes_old_index_tag_map;
+ hb_codepoint_t *axis_tag;
+ if (!axes_old_index_tag_map.has (axisIndex, &axis_tag) ||
+ !index_map->has (axisIndex))
return_trace (false);
+ const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location = c->plan->axes_location;
+ Triple axis_limit{-1.f, 0.f, 1.f};
+ Triple *normalized_limit;
+ if (normalized_axes_location.has (*axis_tag, &normalized_limit))
+ axis_limit = *normalized_limit;
+
+ const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances = c->plan->axes_triple_distances;
+ TripleDistances axis_triple_distances{1.f, 1.f};
+ TripleDistances *triple_dists;
+ if (axes_triple_distances.has (*axis_tag, &triple_dists))
+ axis_triple_distances = *triple_dists;
+
+ float normalized_min = renormalizeValue (filterRangeMinValue.to_float (), axis_limit, axis_triple_distances, false);
+ float normalized_max = renormalizeValue (filterRangeMaxValue.to_float (), axis_limit, axis_triple_distances, false);
+ out->filterRangeMinValue.set_float (normalized_min);
+ out->filterRangeMaxValue.set_float (normalized_max);
+
return_trace (c->serializer->check_assign (out->axisIndex, index_map->get (axisIndex),
HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
@@ -2884,29 +3356,47 @@ struct ConditionFormat1
hb_tag_t axis_tag = c->axes_index_tag_map->get (axisIndex);
- //axis not pinned, keep the condition
- if (!c->axes_location->has (axis_tag))
+ Triple axis_range (-1.f, 0.f, 1.f);
+ Triple *axis_limit;
+ bool axis_set_by_user = false;
+ if (c->axes_location->has (axis_tag, &axis_limit))
{
- // add axisIndex->value into the hashmap so we can check if the record is
- // unique with variations
- int16_t min_val = filterRangeMinValue.to_int ();
- int16_t max_val = filterRangeMaxValue.to_int ();
- hb_codepoint_t val = (max_val << 16) + min_val;
-
- condition_map->set (axisIndex, val);
- return KEEP_COND_WITH_VAR;
+ axis_range = *axis_limit;
+ axis_set_by_user = true;
}
- //axis pinned, check if condition is met
- //TODO: add check for axis Ranges
- int v = c->axes_location->get (axis_tag);
+ float axis_min_val = axis_range.minimum;
+ float axis_default_val = axis_range.middle;
+ float axis_max_val = axis_range.maximum;
+
+ float filter_min_val = filterRangeMinValue.to_float ();
+ float filter_max_val = filterRangeMaxValue.to_float ();
+
+ if (axis_default_val < filter_min_val ||
+ axis_default_val > filter_max_val)
+ c->apply = false;
//condition not met, drop the entire record
- if (v < filterRangeMinValue.to_int () || v > filterRangeMaxValue.to_int ())
+ if (axis_min_val > filter_max_val || axis_max_val < filter_min_val ||
+ filter_min_val > filter_max_val)
return DROP_RECORD_WITH_VAR;
- //axis pinned and condition met, drop the condition
- return DROP_COND_WITH_VAR;
+ //condition met and axis pinned, drop the condition
+ if (axis_set_by_user && axis_range.is_point ())
+ return DROP_COND_WITH_VAR;
+
+ if (filter_max_val != axis_max_val || filter_min_val != axis_min_val)
+ {
+ // add axisIndex->value into the hashmap so we can check if the record is
+ // unique with variations
+ int16_t int_filter_max_val = filterRangeMaxValue.to_int ();
+ int16_t int_filter_min_val = filterRangeMinValue.to_int ();
+ hb_codepoint_t val = (int_filter_max_val << 16) + int_filter_min_val;
+
+ condition_map->set (axisIndex, val);
+ return KEEP_COND_WITH_VAR;
+ }
+ return KEEP_RECORD_WITH_VAR;
}
bool evaluate (const int *coords, unsigned int coord_len) const
@@ -2945,7 +3435,7 @@ struct Condition
{
switch (u.format) {
case 1: return u.format1.keep_with_variations (c, condition_map);
- default:return KEEP_COND_WITH_VAR;
+ default: c->apply = false; return KEEP_COND_WITH_VAR;
}
}
@@ -2964,6 +3454,7 @@ struct Condition
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
+ hb_barrier ();
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
default:return_trace (true);
@@ -2990,54 +3481,62 @@ struct ConditionSet
return true;
}
- Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
+ void keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
{
hb_map_t *condition_map = hb_map_create ();
- if (unlikely (!condition_map)) return MEM_ERR_WITH_VAR;
+ if (unlikely (!condition_map)) return;
hb::shared_ptr<hb_map_t> p {condition_map};
hb_set_t *cond_set = hb_set_create ();
- if (unlikely (!cond_set)) return MEM_ERR_WITH_VAR;
+ if (unlikely (!cond_set)) return;
hb::shared_ptr<hb_set_t> s {cond_set};
+ c->apply = true;
+ bool should_keep = false;
unsigned num_kept_cond = 0, cond_idx = 0;
for (const auto& offset : conditions)
{
Cond_with_Var_flag_t ret = (this+offset).keep_with_variations (c, condition_map);
- // one condition is not met, drop the entire record
+ // condition is not met or condition out of range, drop the entire record
if (ret == DROP_RECORD_WITH_VAR)
- return DROP_RECORD_WITH_VAR;
+ return;
- // axis not pinned, keep this condition
if (ret == KEEP_COND_WITH_VAR)
{
+ should_keep = true;
cond_set->add (cond_idx);
num_kept_cond++;
}
+
+ if (ret == KEEP_RECORD_WITH_VAR)
+ should_keep = true;
+
cond_idx++;
}
- // all conditions met
- if (num_kept_cond == 0) return DROP_COND_WITH_VAR;
+ if (!should_keep) return;
//check if condition_set is unique with variations
if (c->conditionset_map->has (p))
//duplicate found, drop the entire record
- return DROP_RECORD_WITH_VAR;
+ return;
c->conditionset_map->set (p, 1);
c->record_cond_idx_map->set (c->cur_record_idx, s);
-
- return KEEP_COND_WITH_VAR;
+ if (should_keep && num_kept_cond == 0)
+ c->universal = true;
}
bool subset (hb_subset_context_t *c,
- hb_subset_layout_context_t *l) const
+ hb_subset_layout_context_t *l,
+ bool insert_catch_all) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ if (insert_catch_all) return_trace (true);
+
hb_set_t *retained_cond_set = nullptr;
if (l->feature_record_cond_idx_map != nullptr)
retained_cond_set = l->feature_record_cond_idx_map->get (l->cur_feature_var_record_idx);
@@ -3083,29 +3582,52 @@ struct FeatureTableSubstitutionRecord
}
void collect_feature_substitutes_with_variations (hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
+ hb_set_t& catch_all_record_feature_idxes,
const hb_set_t *feature_indices,
const void *base) const
{
if (feature_indices->has (featureIndex))
+ {
feature_substitutes_map->set (featureIndex, &(base+feature));
+ catch_all_record_feature_idxes.add (featureIndex);
+ }
+ }
+
+ bool serialize (hb_subset_layout_context_t *c,
+ unsigned feature_index,
+ const Feature *f, const Tag *tag)
+ {
+ TRACE_SERIALIZE (this);
+ hb_serialize_context_t *s = c->subset_context->serializer;
+ if (unlikely (!s->extend_min (this))) return_trace (false);
+
+ uint32_t *new_feature_idx;
+ if (!c->feature_index_map->has (feature_index, &new_feature_idx))
+ return_trace (false);
+
+ if (!s->check_assign (featureIndex, *new_feature_idx, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (false);
+
+ s->push ();
+ bool ret = f->subset (c->subset_context, c, tag);
+ if (ret) s->add_link (feature, s->pop_pack ());
+ else s->pop_discard ();
+
+ return_trace (ret);
}
bool subset (hb_subset_layout_context_t *c, const void *base) const
{
TRACE_SUBSET (this);
- if (!c->feature_index_map->has (featureIndex) ||
- c->feature_substitutes_map->has (featureIndex)) {
- // Feature that is being substituted is not being retained, so we don't
- // need this.
+ uint32_t *new_feature_index;
+ if (!c->feature_index_map->has (featureIndex, &new_feature_index))
return_trace (false);
- }
auto *out = c->subset_context->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
- out->featureIndex = c->feature_index_map->get (featureIndex);
- bool ret = out->feature.serialize_subset (c->subset_context, feature, base, c);
- return_trace (ret);
+ out->featureIndex = *new_feature_index;
+ return_trace (out->feature.serialize_subset (c->subset_context, feature, base, c));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
@@ -3136,16 +3658,10 @@ struct FeatureTableSubstitution
}
void collect_lookups (const hb_set_t *feature_indexes,
- const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
hb_set_t *lookup_indexes /* OUT */) const
{
+ hb_iter (substitutions)
| hb_filter (feature_indexes, &FeatureTableSubstitutionRecord::featureIndex)
- | hb_filter ([feature_substitutes_map] (const FeatureTableSubstitutionRecord& record)
- {
- if (feature_substitutes_map == nullptr) return true;
- return !feature_substitutes_map->has (record.featureIndex);
- })
| hb_apply ([this, lookup_indexes] (const FeatureTableSubstitutionRecord& r)
{ r.collect_lookups (this, lookup_indexes); })
;
@@ -3170,11 +3686,14 @@ struct FeatureTableSubstitution
void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
{
for (const FeatureTableSubstitutionRecord& record : substitutions)
- record.collect_feature_substitutes_with_variations (c->feature_substitutes_map, c->feature_indices, this);
+ record.collect_feature_substitutes_with_variations (c->feature_substitutes_map,
+ c->catch_all_record_feature_idxes,
+ c->feature_indices, this);
}
bool subset (hb_subset_context_t *c,
- hb_subset_layout_context_t *l) const
+ hb_subset_layout_context_t *l,
+ bool insert_catch_all) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (*this);
@@ -3183,6 +3702,22 @@ struct FeatureTableSubstitution
out->version.major = version.major;
out->version.minor = version.minor;
+ if (insert_catch_all)
+ {
+ for (unsigned feature_index : *(l->catch_all_record_feature_idxes))
+ {
+ hb_pair_t<const void*, const void*> *p;
+ if (!l->feature_idx_tag_map->has (feature_index, &p))
+ return_trace (false);
+ auto *o = out->substitutions.serialize_append (c->serializer);
+ if (!o->serialize (l, feature_index,
+ reinterpret_cast<const Feature*> (p->first),
+ reinterpret_cast<const Tag*> (p->second)))
+ return_trace (false);
+ }
+ return_trace (true);
+ }
+
+ substitutions.iter ()
| hb_apply (subset_record_array (l, &(out->substitutions), this))
;
@@ -3194,6 +3729,7 @@ struct FeatureTableSubstitution
{
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
+ hb_barrier () &&
likely (version.major == 1) &&
substitutions.sanitize (c, this));
}
@@ -3212,10 +3748,9 @@ struct FeatureVariationRecord
void collect_lookups (const void *base,
const hb_set_t *feature_indexes,
- const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
hb_set_t *lookup_indexes /* OUT */) const
{
- return (base+substitutions).collect_lookups (feature_indexes, feature_substitutes_map, lookup_indexes);
+ return (base+substitutions).collect_lookups (feature_indexes, lookup_indexes);
}
void closure_features (const void *base,
@@ -3233,23 +3768,23 @@ struct FeatureVariationRecord
void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
const void *base) const
{
- // ret == 1, all conditions met
- if ((base+conditions).keep_with_variations (c) == DROP_COND_WITH_VAR &&
- c->apply)
+ (base+conditions).keep_with_variations (c);
+ if (c->apply && !c->variation_applied)
{
(base+substitutions).collect_feature_substitutes_with_variations (c);
- c->apply = false; // set variations only once
+ c->variation_applied = true; // set variations only once
}
}
- bool subset (hb_subset_layout_context_t *c, const void *base) const
+ bool subset (hb_subset_layout_context_t *c, const void *base,
+ bool insert_catch_all = false) const
{
TRACE_SUBSET (this);
auto *out = c->subset_context->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
- out->conditions.serialize_subset (c->subset_context, conditions, base, c);
- out->substitutions.serialize_subset (c->subset_context, substitutions, base, c);
+ out->conditions.serialize_subset (c->subset_context, conditions, base, c, insert_catch_all);
+ out->substitutions.serialize_subset (c->subset_context, substitutions, base, c, insert_catch_all);
return_trace (true);
}
@@ -3305,7 +3840,11 @@ struct FeatureVariations
{
c->cur_record_idx = i;
varRecords[i].collect_feature_substitutes_with_variations (c, this);
+ if (c->universal)
+ break;
}
+ if (c->universal || c->record_cond_idx_map->is_empty ())
+ c->catch_all_record_feature_idxes.reset ();
}
FeatureVariations* copy (hb_serialize_context_t *c) const
@@ -3315,11 +3854,17 @@ struct FeatureVariations
}
void collect_lookups (const hb_set_t *feature_indexes,
- const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
+ const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
hb_set_t *lookup_indexes /* OUT */) const
{
- for (const FeatureVariationRecord& r : varRecords)
- r.collect_lookups (this, feature_indexes, feature_substitutes_map, lookup_indexes);
+ unsigned count = varRecords.len;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (feature_record_cond_idx_map &&
+ !feature_record_cond_idx_map->has (i))
+ continue;
+ varRecords[i].collect_lookups (this, feature_indexes, lookup_indexes);
+ }
}
void closure_features (const hb_map_t *lookup_indexes,
@@ -3364,6 +3909,13 @@ struct FeatureVariations
l->cur_feature_var_record_idx = i;
subset_record_array (l, &(out->varRecords), this) (varRecords[i]);
}
+
+ if (out->varRecords.len && !l->catch_all_record_feature_idxes->is_empty ())
+ {
+ bool insert_catch_all_record = true;
+ subset_record_array (l, &(out->varRecords), this, insert_catch_all_record) (varRecords[0]);
+ }
+
return_trace (bool (out->varRecords));
}
@@ -3371,6 +3923,7 @@ struct FeatureVariations
{
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
+ hb_barrier () &&
likely (version.major == 1) &&
varRecords.sanitize (c, this));
}
@@ -3477,13 +4030,13 @@ struct VariationDevice
private:
hb_position_t get_x_delta (hb_font_t *font,
- const VariationStore &store,
- VariationStore::cache_t *store_cache = nullptr) const
+ const ItemVariationStore &store,
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{ return font->em_scalef_x (get_delta (font, store, store_cache)); }
hb_position_t get_y_delta (hb_font_t *font,
- const VariationStore &store,
- VariationStore::cache_t *store_cache = nullptr) const
+ const ItemVariationStore &store,
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{ return font->em_scalef_y (get_delta (font, store, store_cache)); }
VariationDevice* copy (hb_serialize_context_t *c,
@@ -3500,22 +4053,13 @@ struct VariationDevice
auto *out = c->embed (this);
if (unlikely (!out)) return_trace (nullptr);
- unsigned new_idx = hb_first (*v);
- out->varIdx = new_idx;
+ if (!c->check_assign (out->varIdx, hb_first (*v), HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (nullptr);
return_trace (out);
}
void collect_variation_index (hb_collect_variation_indices_context_t *c) const
- {
- c->layout_variation_indices->add (varIdx);
- int delta = 0;
- if (c->font && c->var_store)
- delta = roundf (get_delta (c->font, *c->var_store, c->store_cache));
-
- /* set new varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX here, will remap
- * varidx later*/
- c->varidx_delta_map->set (varIdx, hb_pair_t<unsigned, int> (HB_OT_LAYOUT_NO_VARIATIONS_INDEX, delta));
- }
+ { c->layout_variation_indices->add (varIdx); }
bool sanitize (hb_sanitize_context_t *c) const
{
@@ -3526,10 +4070,10 @@ struct VariationDevice
private:
float get_delta (hb_font_t *font,
- const VariationStore &store,
- VariationStore::cache_t *store_cache = nullptr) const
+ const ItemVariationStore &store,
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{
- return store.get_delta (varIdx, font->coords, font->num_coords, (VariationStore::cache_t *) store_cache);
+ return store.get_delta (varIdx, font->coords, font->num_coords, (ItemVariationStore::cache_t *) store_cache);
}
protected:
@@ -3553,8 +4097,8 @@ struct DeviceHeader
struct Device
{
hb_position_t get_x_delta (hb_font_t *font,
- const VariationStore &store=Null (VariationStore),
- VariationStore::cache_t *store_cache = nullptr) const
+ const ItemVariationStore &store=Null (ItemVariationStore),
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{
switch (u.b.format)
{
@@ -3571,8 +4115,8 @@ struct Device
}
}
hb_position_t get_y_delta (hb_font_t *font,
- const VariationStore &store=Null (VariationStore),
- VariationStore::cache_t *store_cache = nullptr) const
+ const ItemVariationStore &store=Null (ItemVariationStore),
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{
switch (u.b.format)
{
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh
index 10cc105de4..c65ea32b8a 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-gsubgpos.hh
@@ -143,9 +143,12 @@ struct hb_closure_context_t :
return active_glyphs_stack.tail ();
}
- hb_set_t& push_cur_active_glyphs ()
+ hb_set_t* push_cur_active_glyphs ()
{
- return *active_glyphs_stack.push ();
+ hb_set_t *s = active_glyphs_stack.push ();
+ if (unlikely (active_glyphs_stack.in_error ()))
+ return nullptr;
+ return s;
}
bool pop_cur_done_glyphs ()
@@ -399,16 +402,6 @@ struct hb_ot_apply_context_t :
{
struct matcher_t
{
- matcher_t () :
- lookup_props (0),
- mask (-1),
- ignore_zwnj (false),
- ignore_zwj (false),
- per_syllable (false),
- syllable {0},
- match_func (nullptr),
- match_data (nullptr) {}
-
typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data);
void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
@@ -427,6 +420,9 @@ struct hb_ot_apply_context_t :
MATCH_MAYBE
};
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
may_match_t may_match (hb_glyph_info_t &info,
hb_codepoint_t glyph_data) const
{
@@ -446,6 +442,9 @@ struct hb_ot_apply_context_t :
SKIP_MAYBE
};
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
may_skip_t may_skip (const hb_ot_apply_context_t *c,
const hb_glyph_info_t &info) const
{
@@ -461,14 +460,14 @@ struct hb_ot_apply_context_t :
}
protected:
- unsigned int lookup_props;
- hb_mask_t mask;
- bool ignore_zwnj;
- bool ignore_zwj;
- bool per_syllable;
- uint8_t syllable;
- match_func_t match_func;
- const void *match_data;
+ unsigned int lookup_props = 0;
+ hb_mask_t mask = -1;
+ bool ignore_zwnj = false;
+ bool ignore_zwj = false;
+ bool per_syllable = false;
+ uint8_t syllable = 0;
+ match_func_t match_func = nullptr;
+ const void *match_data = nullptr;
};
struct skipping_iterator_t
@@ -476,6 +475,7 @@ struct hb_ot_apply_context_t :
void init (hb_ot_apply_context_t *c_, bool context_match = false)
{
c = c_;
+ end = c->buffer->len;
match_glyph_data16 = nullptr;
#ifndef HB_NO_BEYOND_64K
match_glyph_data24 = nullptr;
@@ -487,7 +487,9 @@ struct hb_ot_apply_context_t :
/* Ignore ZWJ if we are matching context, or asked to. */
matcher.set_ignore_zwj (context_match || c->auto_zwj);
matcher.set_mask (context_match ? -1 : c->lookup_mask);
- matcher.set_per_syllable (c->per_syllable);
+ /* Per syllable matching is only for GSUB. */
+ matcher.set_per_syllable (c->table_index == 0 && c->per_syllable);
+ matcher.set_syllable (0);
}
void set_lookup_props (unsigned int lookup_props)
{
@@ -513,22 +515,34 @@ struct hb_ot_apply_context_t :
}
#endif
- void reset (unsigned int start_index_,
- unsigned int num_items_)
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
+ void reset (unsigned int start_index_)
{
idx = start_index_;
- num_items = num_items_;
end = c->buffer->len;
matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
}
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
+ void reset_fast (unsigned int start_index_)
+ {
+ // Doesn't set end or syllable. Used by GPOS which doesn't care / change.
+ idx = start_index_;
+ }
+
void reject ()
{
- num_items++;
backup_glyph_data ();
}
matcher_t::may_skip_t
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
may_skip (const hb_glyph_info_t &info) const
{ return matcher.may_skip (c, info); }
@@ -538,6 +552,9 @@ struct hb_ot_apply_context_t :
SKIP
};
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
match_t match (hb_glyph_info_t &info)
{
matcher_t::may_skip_t skip = matcher.may_skip (c, info);
@@ -556,14 +573,12 @@ struct hb_ot_apply_context_t :
return SKIP;
}
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
bool next (unsigned *unsafe_to = nullptr)
{
- assert (num_items > 0);
- /* The alternate condition below is faster at string boundaries,
- * but produces subpar "unsafe-to-concat" values. */
- signed stop = (signed) end - (signed) num_items;
- if (c->buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT)
- stop = (signed) end - 1;
+ const signed stop = (signed) end - 1;
while ((signed) idx < stop)
{
idx++;
@@ -571,7 +586,6 @@ struct hb_ot_apply_context_t :
{
case MATCH:
{
- num_items--;
advance_glyph_data ();
return true;
}
@@ -589,14 +603,12 @@ struct hb_ot_apply_context_t :
*unsafe_to = end;
return false;
}
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
bool prev (unsigned *unsafe_from = nullptr)
{
- assert (num_items > 0);
- /* The alternate condition below is faster at string boundaries,
- * but produces subpar "unsafe-to-concat" values. */
- unsigned stop = num_items - 1;
- if (c->buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT)
- stop = 1 - 1;
+ const unsigned stop = 0;
while (idx > stop)
{
idx--;
@@ -604,7 +616,6 @@ struct hb_ot_apply_context_t :
{
case MATCH:
{
- num_items--;
advance_glyph_data ();
return true;
}
@@ -623,6 +634,7 @@ struct hb_ot_apply_context_t :
return false;
}
+ HB_ALWAYS_INLINE
hb_codepoint_t
get_glyph_data ()
{
@@ -633,6 +645,7 @@ struct hb_ot_apply_context_t :
#endif
return 0;
}
+ HB_ALWAYS_INLINE
void
advance_glyph_data ()
{
@@ -661,7 +674,6 @@ struct hb_ot_apply_context_t :
const HBUINT24 *match_glyph_data24;
#endif
- unsigned int num_items;
unsigned int end;
};
@@ -692,10 +704,12 @@ struct hb_ot_apply_context_t :
hb_font_t *font;
hb_face_t *face;
hb_buffer_t *buffer;
+ hb_sanitize_context_t sanitizer;
recurse_func_t recurse_func = nullptr;
const GDEF &gdef;
- const VariationStore &var_store;
- VariationStore::cache_t *var_store_cache;
+ const GDEF::accelerator_t &gdef_accel;
+ const ItemVariationStore &var_store;
+ ItemVariationStore::cache_t *var_store_cache;
hb_set_digest_t digest;
hb_direction_t direction;
@@ -709,7 +723,6 @@ struct hb_ot_apply_context_t :
bool auto_zwj = true;
bool per_syllable = false;
bool random = false;
- uint32_t random_state = 1;
unsigned new_syllables = (unsigned) -1;
signed last_base = -1; // GPOS uses
@@ -717,9 +730,11 @@ struct hb_ot_apply_context_t :
hb_ot_apply_context_t (unsigned int table_index_,
hb_font_t *font_,
- hb_buffer_t *buffer_) :
+ hb_buffer_t *buffer_,
+ hb_blob_t *table_blob_) :
table_index (table_index_),
font (font_), face (font->face), buffer (buffer_),
+ sanitizer (table_blob_),
gdef (
#ifndef HB_NO_OT_LAYOUT
*face->table.GDEF->table
@@ -727,6 +742,13 @@ struct hb_ot_apply_context_t :
Null (GDEF)
#endif
),
+ gdef_accel (
+#ifndef HB_NO_OT_LAYOUT
+ *face->table.GDEF
+#else
+ Null (GDEF::accelerator_t)
+#endif
+ ),
var_store (gdef.get_var_store ()),
var_store_cache (
#ifndef HB_NO_VAR
@@ -743,7 +765,7 @@ struct hb_ot_apply_context_t :
~hb_ot_apply_context_t ()
{
#ifndef HB_NO_VAR
- VariationStore::destroy_cache (var_store_cache);
+ ItemVariationStore::destroy_cache (var_store_cache);
#endif
}
@@ -753,10 +775,10 @@ struct hb_ot_apply_context_t :
iter_context.init (this, true);
}
- void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; last_base = -1; last_base_until = 0; init_iters (); }
- void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
- void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
- void set_per_syllable (bool per_syllable_) { per_syllable = per_syllable_; init_iters (); }
+ void set_lookup_mask (hb_mask_t mask, bool init = true) { lookup_mask = mask; last_base = -1; last_base_until = 0; if (init) init_iters (); }
+ void set_auto_zwj (bool auto_zwj_, bool init = true) { auto_zwj = auto_zwj_; if (init) init_iters (); }
+ void set_auto_zwnj (bool auto_zwnj_, bool init = true) { auto_zwnj = auto_zwnj_; if (init) init_iters (); }
+ void set_per_syllable (bool per_syllable_, bool init = true) { per_syllable = per_syllable_; if (init) init_iters (); }
void set_random (bool random_) { random = random_; }
void set_recurse_func (recurse_func_t func) { recurse_func = func; }
void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
@@ -765,8 +787,8 @@ struct hb_ot_apply_context_t :
uint32_t random_number ()
{
/* http://www.cplusplus.com/reference/random/minstd_rand/ */
- random_state = random_state * 48271 % 2147483647;
- return random_state;
+ buffer->random_state = buffer->random_state * 48271 % 2147483647;
+ return buffer->random_state;
}
bool match_properties_mark (hb_codepoint_t glyph,
@@ -777,7 +799,7 @@ struct hb_ot_apply_context_t :
* match_props has the set index.
*/
if (match_props & LookupFlag::UseMarkFilteringSet)
- return gdef.mark_set_covers (match_props >> 16, glyph);
+ return gdef_accel.mark_set_covers (match_props >> 16, glyph);
/* The second byte of match_props has the meaning
* "ignore marks of attachment type different than
@@ -789,10 +811,12 @@ struct hb_ot_apply_context_t :
return true;
}
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
bool check_glyph_property (const hb_glyph_info_t *info,
unsigned int match_props) const
{
- hb_codepoint_t glyph = info->codepoint;
unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
/* Not covered, if, for example, glyph class is ligature and
@@ -802,7 +826,7 @@ struct hb_ot_apply_context_t :
return false;
if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
- return match_properties_mark (glyph, glyph_props, match_props);
+ return match_properties_mark (info->codepoint, glyph_props, match_props);
return true;
}
@@ -835,7 +859,7 @@ struct hb_ot_apply_context_t :
if (likely (has_glyph_classes))
{
props &= HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
- _hb_glyph_info_set_glyph_props (&buffer->cur(), props | gdef.get_glyph_props (glyph_index));
+ _hb_glyph_info_set_glyph_props (&buffer->cur(), props | gdef_accel.get_glyph_props (glyph_index));
}
else if (class_guess)
{
@@ -883,7 +907,7 @@ struct hb_accelerate_subtables_context_t :
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
template <typename T>
- static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (bool, obj->apply (c, true) )
+ static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (bool, obj->apply_cached (c) )
template <typename T>
static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<0>) HB_RETURN (bool, obj->apply (c) )
template <typename Type>
@@ -1147,6 +1171,10 @@ static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
}
+static inline bool match_always (hb_glyph_info_t &info HB_UNUSED, unsigned value HB_UNUSED, const void *data HB_UNUSED)
+{
+ return true;
+}
static inline bool match_glyph (hb_glyph_info_t &info, unsigned value, const void *data HB_UNUSED)
{
return info.codepoint == value;
@@ -1167,6 +1195,28 @@ static inline bool match_class_cached (hb_glyph_info_t &info, unsigned value, co
info.syllable() = klass;
return klass == value;
}
+static inline bool match_class_cached1 (hb_glyph_info_t &info, unsigned value, const void *data)
+{
+ unsigned klass = info.syllable() & 0x0F;
+ if (klass < 15)
+ return klass == value;
+ const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
+ klass = class_def.get_class (info.codepoint);
+ if (likely (klass < 15))
+ info.syllable() = (info.syllable() & 0xF0) | klass;
+ return klass == value;
+}
+static inline bool match_class_cached2 (hb_glyph_info_t &info, unsigned value, const void *data)
+{
+ unsigned klass = (info.syllable() & 0xF0) >> 4;
+ if (klass < 15)
+ return klass == value;
+ const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
+ klass = class_def.get_class (info.codepoint);
+ if (likely (klass < 15))
+ info.syllable() = (info.syllable() & 0x0F) | (klass << 4);
+ return klass == value;
+}
static inline bool match_coverage (hb_glyph_info_t &info, unsigned value, const void *data)
{
Offset16To<Coverage> coverage;
@@ -1195,14 +1245,17 @@ static inline bool would_match_input (hb_would_apply_context_t *c,
return true;
}
template <typename HBUINT>
-static inline bool match_input (hb_ot_apply_context_t *c,
- unsigned int count, /* Including the first glyph (not matched) */
- const HBUINT input[], /* Array of input values--start with second glyph */
- match_func_t match_func,
- const void *match_data,
- unsigned int *end_position,
- unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
- unsigned int *p_total_component_count = nullptr)
+#ifndef HB_OPTIMIZE_SIZE
+HB_ALWAYS_INLINE
+#endif
+static bool match_input (hb_ot_apply_context_t *c,
+ unsigned int count, /* Including the first glyph (not matched) */
+ const HBUINT input[], /* Array of input values--start with second glyph */
+ match_func_t match_func,
+ const void *match_data,
+ unsigned int *end_position,
+ unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
+ unsigned int *p_total_component_count = nullptr)
{
TRACE_APPLY (nullptr);
@@ -1211,7 +1264,7 @@ static inline bool match_input (hb_ot_apply_context_t *c,
hb_buffer_t *buffer = c->buffer;
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
- skippy_iter.reset (buffer->idx, count - 1);
+ skippy_iter.reset (buffer->idx);
skippy_iter.set_match_func (match_func, match_data);
skippy_iter.set_glyph_data (input);
@@ -1240,7 +1293,6 @@ static inline bool match_input (hb_ot_apply_context_t *c,
*/
unsigned int total_component_count = 0;
- total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
@@ -1251,7 +1303,6 @@ static inline bool match_input (hb_ot_apply_context_t *c,
LIGBASE_MAY_SKIP
} ligbase = LIGBASE_NOT_CHECKED;
- match_positions[0] = buffer->idx;
for (unsigned int i = 1; i < count; i++)
{
unsigned unsafe_to;
@@ -1316,7 +1367,12 @@ static inline bool match_input (hb_ot_apply_context_t *c,
*end_position = skippy_iter.idx + 1;
if (p_total_component_count)
+ {
+ total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
*p_total_component_count = total_component_count;
+ }
+
+ match_positions[0] = buffer->idx;
return_trace (true);
}
@@ -1435,17 +1491,20 @@ static inline bool ligate_input (hb_ot_apply_context_t *c,
}
template <typename HBUINT>
-static inline bool match_backtrack (hb_ot_apply_context_t *c,
- unsigned int count,
- const HBUINT backtrack[],
- match_func_t match_func,
- const void *match_data,
- unsigned int *match_start)
+#ifndef HB_OPTIMIZE_SIZE
+HB_ALWAYS_INLINE
+#endif
+static bool match_backtrack (hb_ot_apply_context_t *c,
+ unsigned int count,
+ const HBUINT backtrack[],
+ match_func_t match_func,
+ const void *match_data,
+ unsigned int *match_start)
{
TRACE_APPLY (nullptr);
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
- skippy_iter.reset (c->buffer->backtrack_len (), count);
+ skippy_iter.reset (c->buffer->backtrack_len ());
skippy_iter.set_match_func (match_func, match_data);
skippy_iter.set_glyph_data (backtrack);
@@ -1464,18 +1523,21 @@ static inline bool match_backtrack (hb_ot_apply_context_t *c,
}
template <typename HBUINT>
-static inline bool match_lookahead (hb_ot_apply_context_t *c,
- unsigned int count,
- const HBUINT lookahead[],
- match_func_t match_func,
- const void *match_data,
- unsigned int start_index,
- unsigned int *end_index)
+#ifndef HB_OPTIMIZE_SIZE
+HB_ALWAYS_INLINE
+#endif
+static bool match_lookahead (hb_ot_apply_context_t *c,
+ unsigned int count,
+ const HBUINT lookahead[],
+ match_func_t match_func,
+ const void *match_data,
+ unsigned int start_index,
+ unsigned int *end_index)
{
TRACE_APPLY (nullptr);
hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
- skippy_iter.reset (start_index - 1, count);
+ skippy_iter.reset (start_index - 1);
skippy_iter.set_match_func (match_func, match_data);
skippy_iter.set_glyph_data (lookahead);
@@ -1594,10 +1656,13 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c,
}
covered_seq_indicies.add (seqIndex);
+ hb_set_t *cur_active_glyphs = c->push_cur_active_glyphs ();
+ if (unlikely (!cur_active_glyphs))
+ return;
if (has_pos_glyphs) {
- c->push_cur_active_glyphs () = std::move (pos_glyphs);
+ *cur_active_glyphs = std::move (pos_glyphs);
} else {
- c->push_cur_active_glyphs ().set (*c->glyphs);
+ *cur_active_glyphs = *c->glyphs;
}
unsigned endIndex = inputCount;
@@ -1847,12 +1912,13 @@ static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
}
template <typename HBUINT>
-static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
- unsigned int inputCount, /* Including the first glyph (not matched) */
- const HBUINT input[], /* Array of input values--start with second glyph */
- unsigned int lookupCount,
- const LookupRecord lookupRecord[],
- const ContextApplyLookupContext &lookup_context)
+HB_ALWAYS_INLINE
+static bool context_apply_lookup (hb_ot_apply_context_t *c,
+ unsigned int inputCount, /* Including the first glyph (not matched) */
+ const HBUINT input[], /* Array of input values--start with second glyph */
+ unsigned int lookupCount,
+ const LookupRecord lookupRecord[],
+ const ContextApplyLookupContext &lookup_context)
{
unsigned match_end = 0;
unsigned match_positions[HB_MAX_CONTEXT_LENGTH];
@@ -1878,6 +1944,9 @@ static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
template <typename Types>
struct Rule
{
+ template <typename T>
+ friend struct RuleSet;
+
bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
{
return context_intersects (glyphs,
@@ -1980,8 +2049,8 @@ struct Rule
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (inputCount.sanitize (c) &&
- lookupCount.sanitize (c) &&
+ return_trace (c->check_struct (this) &&
+ hb_barrier () &&
c->check_range (inputZ.arrayZ,
inputZ.item_size * (inputCount ? inputCount - 1 : 0) +
LookupRecord::static_size * lookupCount));
@@ -2065,13 +2134,105 @@ struct RuleSet
const ContextApplyLookupContext &lookup_context) const
{
TRACE_APPLY (this);
- return_trace (
- + hb_iter (rule)
- | hb_map (hb_add (this))
- | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
- | hb_any
- )
- ;
+
+ unsigned num_rules = rule.len;
+
+#ifndef HB_NO_OT_RULESETS_FAST_PATH
+ if (HB_OPTIMIZE_SIZE_VAL || num_rules <= 4)
+#endif
+ {
+ slow:
+ return_trace (
+ + hb_iter (rule)
+ | hb_map (hb_add (this))
+ | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
+ | hb_any
+ )
+ ;
+ }
+
+ /* This version is optimized for speed by matching the first & second
+ * components of the rule here, instead of calling into the matching code.
+ *
+ * Replicated from LigatureSet::apply(). */
+
+ hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (c->buffer->idx);
+ skippy_iter.set_match_func (match_always, nullptr);
+ skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
+ unsigned unsafe_to = (unsigned) -1, unsafe_to1 = 0, unsafe_to2 = 0;
+ hb_glyph_info_t *first = nullptr, *second = nullptr;
+ bool matched = skippy_iter.next ();
+ if (likely (matched))
+ {
+ first = &c->buffer->info[skippy_iter.idx];
+ unsafe_to = skippy_iter.idx + 1;
+
+ if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
+ {
+ /* Can't use the fast path if eg. the next char is a default-ignorable
+ * or other skippable. */
+ goto slow;
+ }
+ }
+ else
+ {
+ /* Failed to match a next glyph. Only try applying rules that have
+ * no further input. */
+ return_trace (
+ + hb_iter (rule)
+ | hb_map (hb_add (this))
+ | hb_filter ([&] (const Rule &_) { return _.inputCount <= 1; })
+ | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
+ | hb_any
+ )
+ ;
+ }
+ matched = skippy_iter.next ();
+ if (likely (matched && !skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])))
+ {
+ second = &c->buffer->info[skippy_iter.idx];
+ unsafe_to2 = skippy_iter.idx + 1;
+ }
+
+ auto match_input = lookup_context.funcs.match;
+ auto *input_data = lookup_context.match_data;
+ for (unsigned int i = 0; i < num_rules; i++)
+ {
+ const auto &r = this+rule.arrayZ[i];
+
+ const auto &input = r.inputZ;
+
+ if (r.inputCount <= 1 ||
+ (!match_input ||
+ match_input (*first, input.arrayZ[0], input_data)))
+ {
+ if (!second ||
+ (r.inputCount <= 2 ||
+ (!match_input ||
+ match_input (*second, input.arrayZ[1], input_data)))
+ )
+ {
+ if (r.apply (c, lookup_context))
+ {
+ if (unsafe_to != (unsigned) -1)
+ c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
+ return_trace (true);
+ }
+ }
+ else
+ unsafe_to = unsafe_to2;
+ }
+ else
+ {
+ if (unsafe_to == (unsigned) -1)
+ unsafe_to = unsafe_to1;
+ }
+ }
+ if (likely (unsafe_to != (unsigned) -1))
+ c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
+
+ return_trace (false);
}
bool subset (hb_subset_context_t *c,
@@ -2147,8 +2308,9 @@ struct ContextFormat1_4
void closure (hb_closure_context_t *c) const
{
- hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
- get_coverage ().intersect_set (c->previous_parent_active_glyphs (), cur_active_glyphs);
+ hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
+ if (unlikely (!cur_active_glyphs)) return;
+ get_coverage ().intersect_set (c->previous_parent_active_glyphs (), *cur_active_glyphs);
struct ContextClosureLookupContext lookup_context = {
{intersects_glyph, intersected_glyph},
@@ -2317,9 +2479,10 @@ struct ContextFormat2_5
if (!(this+coverage).intersects (c->glyphs))
return;
- hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+ hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
+ if (unlikely (!cur_active_glyphs)) return;
get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
- cur_active_glyphs);
+ *cur_active_glyphs);
const ClassDef &class_def = this+classDef;
@@ -2430,7 +2593,9 @@ struct ContextFormat2_5
}
}
- bool apply (hb_ot_apply_context_t *c, bool cached = false) const
+ bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
+ bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
+ bool _apply (hb_ot_apply_context_t *c, bool cached) const
{
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
@@ -2446,11 +2611,7 @@ struct ContextFormat2_5
if (cached && c->buffer->cur().syllable() < 255)
index = c->buffer->cur().syllable ();
else
- {
index = class_def.get_class (c->buffer->cur().codepoint);
- if (cached && index < 255)
- c->buffer->cur().syllable() = index;
- }
const RuleSet &rule_set = this+ruleSet[index];
return_trace (rule_set.apply (c, lookup_context));
}
@@ -2560,10 +2721,10 @@ struct ContextFormat3
if (!(this+coverageZ[0]).intersects (c->glyphs))
return;
- hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+ hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
+ if (unlikely (!cur_active_glyphs)) return;
get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
- cur_active_glyphs);
-
+ *cur_active_glyphs);
const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
struct ContextClosureLookupContext lookup_context = {
@@ -2664,14 +2825,15 @@ struct ContextFormat3
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- if (!c->check_struct (this)) return_trace (false);
+ if (unlikely (!c->check_struct (this))) return_trace (false);
+ hb_barrier ();
unsigned int count = glyphCount;
- if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
- if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false);
+ if (unlikely (!count)) return_trace (false); /* We want to access coverageZ[0] freely. */
+ if (unlikely (!c->check_array (coverageZ.arrayZ, count))) return_trace (false);
for (unsigned int i = 0; i < count; i++)
- if (!coverageZ[i].sanitize (c, this)) return_trace (false);
+ if (unlikely (!coverageZ[i].sanitize (c, this))) return_trace (false);
const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
- return_trace (c->check_array (lookupRecord, lookupCount));
+ return_trace (likely (c->check_array (lookupRecord, lookupCount)));
}
protected:
@@ -2844,16 +3006,17 @@ static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c
}
template <typename HBUINT>
-static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
- unsigned int backtrackCount,
- const HBUINT backtrack[],
- unsigned int inputCount, /* Including the first glyph (not matched) */
- const HBUINT input[], /* Array of input values--start with second glyph */
- unsigned int lookaheadCount,
- const HBUINT lookahead[],
- unsigned int lookupCount,
- const LookupRecord lookupRecord[],
- const ChainContextApplyLookupContext &lookup_context)
+HB_ALWAYS_INLINE
+static bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
+ unsigned int backtrackCount,
+ const HBUINT backtrack[],
+ unsigned int inputCount, /* Including the first glyph (not matched) */
+ const HBUINT input[], /* Array of input values--start with second glyph */
+ unsigned int lookaheadCount,
+ const HBUINT lookahead[],
+ unsigned int lookupCount,
+ const LookupRecord lookupRecord[],
+ const ChainContextApplyLookupContext &lookup_context)
{
unsigned end_index = c->buffer->idx;
unsigned match_end = 0;
@@ -2892,6 +3055,9 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
template <typename Types>
struct ChainRule
{
+ template <typename T>
+ friend struct ChainRuleSet;
+
bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
{
const auto &input = StructAfter<decltype (inputX)> (backtrack);
@@ -2991,8 +3157,6 @@ struct ChainRule
const hb_map_t *lookahead_map = nullptr) const
{
TRACE_SERIALIZE (this);
- auto *out = c->start_embed (this);
- if (unlikely (!out)) return_trace (false);
const hb_map_t *mapping = backtrack_map;
serialize_array (c, backtrack.len, + backtrack.iter ()
@@ -3054,13 +3218,17 @@ struct ChainRule
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- if (!backtrack.sanitize (c)) return_trace (false);
+ /* Hyper-optimized sanitized because this is really hot. */
+ if (unlikely (!backtrack.len.sanitize (c))) return_trace (false);
+ hb_barrier ();
const auto &input = StructAfter<decltype (inputX)> (backtrack);
- if (!input.sanitize (c)) return_trace (false);
+ if (unlikely (!input.lenP1.sanitize (c))) return_trace (false);
+ hb_barrier ();
const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
- if (!lookahead.sanitize (c)) return_trace (false);
+ if (unlikely (!lookahead.len.sanitize (c))) return_trace (false);
+ hb_barrier ();
const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
- return_trace (lookup.sanitize (c));
+ return_trace (likely (lookup.sanitize (c)));
}
protected:
@@ -3068,7 +3236,7 @@ struct ChainRule
backtrack; /* Array of backtracking values
* (to be matched before the input
* sequence) */
- HeadlessArrayOf<typename Types::HBUINT>
+ HeadlessArray16Of<typename Types::HBUINT>
inputX; /* Array of input values (start with
* second glyph) */
Array16Of<typename Types::HBUINT>
@@ -3141,13 +3309,119 @@ struct ChainRuleSet
const ChainContextApplyLookupContext &lookup_context) const
{
TRACE_APPLY (this);
- return_trace (
- + hb_iter (rule)
- | hb_map (hb_add (this))
- | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
- | hb_any
- )
- ;
+
+ unsigned num_rules = rule.len;
+
+#ifndef HB_NO_OT_RULESETS_FAST_PATH
+ if (HB_OPTIMIZE_SIZE_VAL || num_rules <= 4)
+#endif
+ {
+ slow:
+ return_trace (
+ + hb_iter (rule)
+ | hb_map (hb_add (this))
+ | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
+ | hb_any
+ )
+ ;
+ }
+
+ /* This version is optimized for speed by matching the first & second
+ * components of the rule here, instead of calling into the matching code.
+ *
+ * Replicated from LigatureSet::apply(). */
+
+ hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (c->buffer->idx);
+ skippy_iter.set_match_func (match_always, nullptr);
+ skippy_iter.set_glyph_data ((HBUINT16 *) nullptr);
+ unsigned unsafe_to = (unsigned) -1, unsafe_to1 = 0, unsafe_to2 = 0;
+ hb_glyph_info_t *first = nullptr, *second = nullptr;
+ bool matched = skippy_iter.next ();
+ if (likely (matched))
+ {
+ first = &c->buffer->info[skippy_iter.idx];
+ unsafe_to1 = skippy_iter.idx + 1;
+
+ if (skippy_iter.may_skip (c->buffer->info[skippy_iter.idx]))
+ {
+ /* Can't use the fast path if eg. the next char is a default-ignorable
+ * or other skippable. */
+ goto slow;
+ }
+ }
+ else
+ {
+ /* Failed to match a next glyph. Only try applying rules that have
+ * no further input and lookahead. */
+ return_trace (
+ + hb_iter (rule)
+ | hb_map (hb_add (this))
+ | hb_filter ([&] (const ChainRule &_)
+ {
+ const auto &input = StructAfter<decltype (_.inputX)> (_.backtrack);
+ const auto &lookahead = StructAfter<decltype (_.lookaheadX)> (input);
+ return input.lenP1 <= 1 && lookahead.len == 0;
+ })
+ | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
+ | hb_any
+ )
+ ;
+ }
+ matched = skippy_iter.next ();
+ if (likely (matched && !skippy_iter.may_skip (c->buffer->info[skippy_iter.idx])))
+ {
+ second = &c->buffer->info[skippy_iter.idx];
+ unsafe_to2 = skippy_iter.idx + 1;
+ }
+
+ auto match_input = lookup_context.funcs.match[1];
+ auto match_lookahead = lookup_context.funcs.match[2];
+ auto *input_data = lookup_context.match_data[1];
+ auto *lookahead_data = lookup_context.match_data[2];
+ for (unsigned int i = 0; i < num_rules; i++)
+ {
+ const auto &r = this+rule.arrayZ[i];
+
+ const auto &input = StructAfter<decltype (r.inputX)> (r.backtrack);
+ const auto &lookahead = StructAfter<decltype (r.lookaheadX)> (input);
+
+ unsigned lenP1 = hb_max ((unsigned) input.lenP1, 1u);
+ if (lenP1 > 1 ?
+ (!match_input ||
+ match_input (*first, input.arrayZ[0], input_data))
+ :
+ (!lookahead.len || !match_lookahead ||
+ match_lookahead (*first, lookahead.arrayZ[0], lookahead_data)))
+ {
+ if (!second ||
+ (lenP1 > 2 ?
+ (!match_input ||
+ match_input (*second, input.arrayZ[1], input_data))
+ :
+ (lookahead.len <= 2 - lenP1 || !match_lookahead ||
+ match_lookahead (*second, lookahead.arrayZ[2 - lenP1], lookahead_data))))
+ {
+ if (r.apply (c, lookup_context))
+ {
+ if (unsafe_to != (unsigned) -1)
+ c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
+ return_trace (true);
+ }
+ }
+ else
+ unsafe_to = unsafe_to2;
+ }
+ else
+ {
+ if (unsafe_to == (unsigned) -1)
+ unsafe_to = unsafe_to1;
+ }
+ }
+ if (likely (unsafe_to != (unsigned) -1))
+ c->buffer->unsafe_to_concat (c->buffer->idx, unsafe_to);
+
+ return_trace (false);
}
bool subset (hb_subset_context_t *c,
@@ -3228,9 +3502,10 @@ struct ChainContextFormat1_4
void closure (hb_closure_context_t *c) const
{
- hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+ hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
+ if (unlikely (!cur_active_glyphs)) return;
get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
- cur_active_glyphs);
+ *cur_active_glyphs);
struct ChainContextClosureLookupContext lookup_context = {
{intersects_glyph, intersected_glyph},
@@ -3400,10 +3675,10 @@ struct ChainContextFormat2_5
if (!(this+coverage).intersects (c->glyphs))
return;
- hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+ hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
+ if (unlikely (!cur_active_glyphs)) return;
get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
- cur_active_glyphs);
-
+ *cur_active_glyphs);
const ClassDef &backtrack_class_def = this+backtrackClassDef;
const ClassDef &input_class_def = this+inputClassDef;
@@ -3533,7 +3808,9 @@ struct ChainContextFormat2_5
}
}
- bool apply (hb_ot_apply_context_t *c, bool cached = false) const
+ bool apply_cached (hb_ot_apply_context_t *c) const { return _apply (c, true); }
+ bool apply (hb_ot_apply_context_t *c) const { return _apply (c, false); }
+ bool _apply (hb_ot_apply_context_t *c, bool cached) const
{
TRACE_APPLY (this);
unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
@@ -3543,26 +3820,22 @@ struct ChainContextFormat2_5
const ClassDef &input_class_def = this+inputClassDef;
const ClassDef &lookahead_class_def = this+lookaheadClassDef;
- /* For ChainContextFormat2_5 we cache the LookaheadClassDef instead of InputClassDef.
- * The reason is that most heavy fonts want to identify a glyph in context and apply
- * a lookup to it. In this scenario, the length of the input sequence is one, whereas
- * the lookahead / backtrack are typically longer. The one glyph in input sequence is
- * looked-up below and no input glyph is looked up in individual rules, whereas the
- * lookahead and backtrack glyphs are tried. Since we match lookahead before backtrack,
- * we should cache lookahead. This decisions showed a 20% improvement in shaping of
- * the Gulzar font.
- */
-
+ /* match_class_caches1 is slightly faster. Use it for lookahead,
+ * which is typically longer. */
struct ChainContextApplyLookupContext lookup_context = {
- {{cached && &backtrack_class_def == &lookahead_class_def ? match_class_cached : match_class,
- cached && &input_class_def == &lookahead_class_def ? match_class_cached : match_class,
- cached ? match_class_cached : match_class}},
+ {{cached && &backtrack_class_def == &lookahead_class_def ? match_class_cached1 : match_class,
+ cached ? match_class_cached2 : match_class,
+ cached ? match_class_cached1 : match_class}},
{&backtrack_class_def,
&input_class_def,
&lookahead_class_def}
};
- index = input_class_def.get_class (c->buffer->cur().codepoint);
+ // Note: Corresponds to match_class_cached2
+ if (cached && ((c->buffer->cur().syllable() & 0xF0) >> 4) < 15)
+ index = (c->buffer->cur().syllable () & 0xF0) >> 4;
+ else
+ index = input_class_def.get_class (c->buffer->cur().codepoint);
const ChainRuleSet &rule_set = this+ruleSet[index];
return_trace (rule_set.apply (c, lookup_context));
}
@@ -3702,10 +3975,11 @@ struct ChainContextFormat3
if (!(this+input[0]).intersects (c->glyphs))
return;
- hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
+ hb_set_t* cur_active_glyphs = c->push_cur_active_glyphs ();
+ if (unlikely (!cur_active_glyphs))
+ return;
get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
- cur_active_glyphs);
-
+ *cur_active_glyphs);
const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
@@ -3824,8 +4098,6 @@ struct ChainContextFormat3
{
TRACE_SUBSET (this);
- auto *out = c->serializer->start_embed (this);
- if (unlikely (!out)) return_trace (false);
if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
if (!serialize_coverage_offsets (c, backtrack.iter (), this))
@@ -3852,14 +4124,17 @@ struct ChainContextFormat3
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- if (!backtrack.sanitize (c, this)) return_trace (false);
+ if (unlikely (!backtrack.sanitize (c, this))) return_trace (false);
+ hb_barrier ();
const auto &input = StructAfter<decltype (inputX)> (backtrack);
- if (!input.sanitize (c, this)) return_trace (false);
- if (!input.len) return_trace (false); /* To be consistent with Context. */
+ if (unlikely (!input.sanitize (c, this))) return_trace (false);
+ hb_barrier ();
+ if (unlikely (!input.len)) return_trace (false); /* To be consistent with Context. */
const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
- if (!lookahead.sanitize (c, this)) return_trace (false);
+ if (unlikely (!lookahead.sanitize (c, this))) return_trace (false);
+ hb_barrier ();
const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
- return_trace (lookup.sanitize (c));
+ return_trace (likely (lookup.sanitize (c)));
}
protected:
@@ -3941,6 +4216,7 @@ struct ExtensionFormat1
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
extensionLookupType != T::SubTable::Extension);
}
@@ -3949,7 +4225,7 @@ struct ExtensionFormat1
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
- if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->format = format;
out->extensionLookupType = extensionLookupType;
@@ -4067,6 +4343,9 @@ struct hb_ot_layout_lookup_accelerator_t
bool may_have (hb_codepoint_t g) const
{ return digest.may_have (g); }
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
bool apply (hb_ot_apply_context_t *c, unsigned subtables_count, bool use_cache) const
{
#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
@@ -4201,13 +4480,6 @@ struct GSUBGPOSVersion1_2
if (!c->subset_context->serializer->extend_min (&out->featureVars))
return_trace (false);
- // TODO(qxliu76): the current implementation doesn't correctly handle feature variations
- // that are dropped by instancing when the associated conditions don't trigger.
- // Since partial instancing isn't yet supported this isn't an issue yet but will
- // need to be fixed for partial instancing.
-
-
-
// if all axes are pinned all feature vars are dropped.
bool ret = !c->subset_context->plan->all_axes_pinned
&& out->featureVars.serialize_subset (c->subset_context, featureVars, this, c);
@@ -4242,6 +4514,7 @@ struct GSUBGPOS
{
TRACE_SANITIZE (this);
if (unlikely (!u.version.sanitize (c))) return_trace (false);
+ hb_barrier ();
switch (u.version.major) {
case 1: return_trace (u.version1.sanitize<TLookup> (c));
#ifndef HB_NO_BEYOND_64K
@@ -4367,11 +4640,11 @@ struct GSUBGPOS
}
void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
- const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
+ const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
hb_set_t *lookup_indexes /* OUT */) const
{
#ifndef HB_NO_VAR
- get_feature_variations ().collect_lookups (feature_indexes, feature_substitutes_map, lookup_indexes);
+ get_feature_variations ().collect_lookups (feature_indexes, feature_record_cond_idx_map, lookup_indexes);
#endif
}
@@ -4461,12 +4734,27 @@ struct GSUBGPOS
}
}
+ void collect_name_ids (const hb_map_t *feature_index_map,
+ hb_set_t *nameids_to_retain /* OUT */) const
+ {
+ unsigned count = get_feature_count ();
+ for (unsigned i = 0 ; i < count; i++)
+ {
+ if (!feature_index_map->has (i)) continue;
+ hb_tag_t tag = get_feature_tag (i);
+ get_feature (i).collect_name_ids (tag, nameids_to_retain);
+ }
+ }
+
template <typename T>
struct accelerator_t
{
accelerator_t (hb_face_t *face)
{
- this->table = hb_sanitize_context_t ().reference_table<T> (face);
+ hb_sanitize_context_t sc;
+ sc.lazy_some_gpos = true;
+ this->table = sc.reference_table<T> (face);
+
if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
{
hb_blob_destroy (this->table.get_blob ());
@@ -4491,6 +4779,8 @@ struct GSUBGPOS
this->table.destroy ();
}
+ hb_blob_t *get_blob () const { return table.get_blob (); }
+
hb_ot_layout_lookup_accelerator_t *get_accel (unsigned lookup_index) const
{
if (unlikely (lookup_index >= lookup_count)) return nullptr;
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 a1c125b11b..0ba7eaa2c5 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
@@ -214,6 +214,7 @@ struct JSTF
{
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
+ hb_barrier () &&
likely (version.major == 1) &&
scriptList.sanitize (c, this));
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc
index 6c4055e046..a4c13abadf 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.cc
@@ -64,6 +64,8 @@ using OT::Layout::GPOS;
* @include: hb-ot.h
*
* Functions for querying OpenType Layout features in the font face.
+ * See the [OpenType specification](http://www.microsoft.com/typography/otspec/)
+ * for details.
**/
@@ -255,12 +257,13 @@ _hb_ot_layout_set_glyph_props (hb_font_t *font,
{
_hb_buffer_assert_gsubgpos_vars (buffer);
- const OT::GDEF &gdef = *font->face->table.GDEF->table;
+ const auto &gdef = *font->face->table.GDEF;
unsigned int count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
{
- _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
- _hb_glyph_info_clear_lig_props (&buffer->info[i]);
+ _hb_glyph_info_set_glyph_props (&info[i], gdef.get_glyph_props (info[i].codepoint));
+ _hb_glyph_info_clear_lig_props (&info[i]);
}
}
@@ -1238,7 +1241,7 @@ script_collect_features (hb_collect_features_context_t *c,
* terminated by %HB_TAG_NONE
* @features: (nullable) (array zero-terminated=1): The array of features to collect,
* terminated by %HB_TAG_NONE
- * @feature_indexes: (out): The array of feature indexes found for the query
+ * @feature_indexes: (out): The set of feature indexes found for the query
*
* Fetches a list of all feature indexes in the specified face's GSUB table
* or GPOS table, underneath the specified scripts, languages, and features.
@@ -1279,6 +1282,49 @@ hb_ot_layout_collect_features (hb_face_t *face,
}
}
+/**
+ * hb_ot_layout_collect_features_map:
+ * @face: #hb_face_t to work upon
+ * @table_tag: #HB_OT_TAG_GSUB or #HB_OT_TAG_GPOS
+ * @script_index: The index of the requested script tag
+ * @language_index: The index of the requested language tag
+ * @feature_map: (out): The map of feature tag to feature index.
+ *
+ * Fetches the mapping from feature tags to feature indexes for
+ * the specified script and language.
+ *
+ * Since: 8.1.0
+ **/
+void
+hb_ot_layout_collect_features_map (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned script_index,
+ unsigned language_index,
+ hb_map_t *feature_map /* OUT */)
+{
+ const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
+ const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
+
+ unsigned int count = l.get_feature_indexes (0, nullptr, nullptr);
+ feature_map->alloc (count);
+
+ /* Loop in reverse, such that earlier entries win. That emulates
+ * a linear search, which seems to be what other implementations do.
+ * We found that with arialuni_t.ttf, the "ur" language system has
+ * duplicate features, and the earlier ones work but not later ones.
+ */
+ for (unsigned int i = count; i; i--)
+ {
+ unsigned feature_index = 0;
+ unsigned feature_count = 1;
+ l.get_feature_indexes (i - 1, &feature_count, &feature_index);
+ if (!feature_count)
+ break;
+ hb_tag_t feature_tag = g.get_feature_tag (feature_index);
+ feature_map->set (feature_tag, feature_index);
+ }
+}
+
/**
* hb_ot_layout_collect_lookups:
@@ -1313,8 +1359,7 @@ hb_ot_layout_collect_lookups (hb_face_t *face,
hb_set_t feature_indexes;
hb_ot_layout_collect_features (face, table_tag, scripts, languages, features, &feature_indexes);
- for (hb_codepoint_t feature_index = HB_SET_VALUE_INVALID;
- hb_set_next (&feature_indexes, &feature_index);)
+ for (auto feature_index : feature_indexes)
g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes);
g.feature_variation_collect_lookups (&feature_indexes, nullptr, lookup_indexes);
@@ -1567,7 +1612,7 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face,
glyphs_length = glyphs->get_population ();
if (lookups)
{
- for (hb_codepoint_t lookup_index = HB_SET_VALUE_INVALID; hb_set_next (lookups, &lookup_index);)
+ for (auto lookup_index : *lookups)
gsub.get_lookup (lookup_index).closure (&c, lookup_index);
}
else
@@ -1893,7 +1938,7 @@ apply_backward (OT::hb_ot_apply_context_t *c,
if (accel.digest.may_have (buffer->cur().codepoint) &&
(buffer->cur().mask & c->lookup_mask) &&
c->check_glyph_property (&buffer->cur(), c->lookup_props))
- ret |= accel.apply (c, subtable_count, false);
+ ret |= accel.apply (c, subtable_count, false);
/* The reverse lookup doesn't "advance" cursor (for good reason). */
buffer->idx--;
@@ -1950,7 +1995,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
{
const unsigned int table_index = proxy.table_index;
unsigned int i = 0;
- OT::hb_ot_apply_context_t c (table_index, font, buffer);
+ OT::hb_ot_apply_context_t c (table_index, font, buffer, proxy.accel.get_blob ());
c.set_recurse_func (Proxy::Lookup::template dispatch_recurse_func<OT::hb_ot_apply_context_t>);
for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++)
@@ -1975,11 +2020,12 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
if (accel->digest.may_have (c.digest))
{
c.set_lookup_index (lookup_index);
- c.set_lookup_mask (lookup.mask);
- c.set_auto_zwj (lookup.auto_zwj);
- c.set_auto_zwnj (lookup.auto_zwnj);
+ c.set_lookup_mask (lookup.mask, false);
+ c.set_auto_zwj (lookup.auto_zwj, false);
+ c.set_auto_zwnj (lookup.auto_zwnj, false);
c.set_random (lookup.random);
- c.set_per_syllable (lookup.per_syllable);
+ c.set_per_syllable (lookup.per_syllable, false);
+ /* apply_string's set_lookup_props initializes the iterators. */
apply_string<Proxy> (&c,
proxy.accel.table->get_lookup (lookup_index),
@@ -2007,20 +2053,20 @@ void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, h
{
GSUBProxy proxy (font->face);
if (buffer->messaging () &&
- !buffer->message (font, "start table GSUB")) return;
+ !buffer->message (font, "start table GSUB script tag '%c%c%c%c'", HB_UNTAG (chosen_script[0]))) return;
apply (proxy, plan, font, buffer);
if (buffer->messaging ())
- (void) buffer->message (font, "end table GSUB");
+ (void) buffer->message (font, "end table GSUB script tag '%c%c%c%c'", HB_UNTAG (chosen_script[0]));
}
void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
{
GPOSProxy proxy (font->face);
if (buffer->messaging () &&
- !buffer->message (font, "start table GPOS")) return;
+ !buffer->message (font, "start table GPOS script tag '%c%c%c%c'", HB_UNTAG (chosen_script[1]))) return;
apply (proxy, plan, font, buffer);
if (buffer->messaging ())
- (void) buffer->message (font, "end table GPOS");
+ (void) buffer->message (font, "end table GPOS script tag '%c%c%c%c'", HB_UNTAG (chosen_script[1]));
}
void
@@ -2032,6 +2078,112 @@ hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
}
#ifndef HB_NO_BASE
+
+static void
+choose_base_tags (hb_script_t script,
+ hb_language_t language,
+ hb_tag_t *script_tag,
+ hb_tag_t *language_tag)
+{
+ hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
+ unsigned script_count = ARRAY_LENGTH (script_tags);
+
+ hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
+ unsigned language_count = ARRAY_LENGTH (language_tags);
+
+ hb_ot_tags_from_script_and_language (script, language,
+ &script_count, script_tags,
+ &language_count, language_tags);
+
+ *script_tag = script_count ? script_tags[script_count - 1] : HB_OT_TAG_DEFAULT_SCRIPT;
+ *language_tag = language_count ? language_tags[language_count - 1] : HB_OT_TAG_DEFAULT_LANGUAGE;
+}
+
+/**
+ * hb_ot_layout_get_font_extents:
+ * @font: a font
+ * @direction: text direction.
+ * @script_tag: script tag.
+ * @language_tag: language tag.
+ * @extents: (out) (nullable): font extents if found.
+ *
+ * Fetches script/language-specific font extents. These values are
+ * looked up in the `BASE` table's `MinMax` records.
+ *
+ * If no such extents are found, the default extents for the font are
+ * fetched. As such, the return value of this function can for the
+ * most part be ignored. Note that the per-script/language extents
+ * do not have a line-gap value, and the line-gap is set to zero in
+ * that case.
+ *
+ * Return value: `true` if found script/language-specific font extents.
+ *
+ * Since: 8.0.0
+ **/
+hb_bool_t
+hb_ot_layout_get_font_extents (hb_font_t *font,
+ hb_direction_t direction,
+ hb_tag_t script_tag,
+ hb_tag_t language_tag,
+ hb_font_extents_t *extents)
+{
+ hb_position_t min = 0, max = 0;
+ if (font->face->table.BASE->get_min_max (font, direction, script_tag, language_tag, HB_TAG_NONE,
+ &min, &max))
+ {
+ if (extents)
+ {
+ extents->ascender = max;
+ extents->descender = min;
+ extents->line_gap = 0;
+ }
+ return true;
+ }
+
+ hb_font_get_extents_for_direction (font, direction, extents);
+ return false;
+}
+
+/**
+ * hb_ot_layout_get_font_extents2:
+ * @font: a font
+ * @direction: text direction.
+ * @script: script.
+ * @language: (nullable): language.
+ * @extents: (out) (nullable): font extents if found.
+ *
+ * Fetches script/language-specific font extents. These values are
+ * looked up in the `BASE` table's `MinMax` records.
+ *
+ * If no such extents are found, the default extents for the font are
+ * fetched. As such, the return value of this function can for the
+ * most part be ignored. Note that the per-script/language extents
+ * do not have a line-gap value, and the line-gap is set to zero in
+ * that case.
+ *
+ * This function is like hb_ot_layout_get_font_extents() but takes
+ * #hb_script_t and #hb_language_t instead of OpenType #hb_tag_t.
+ *
+ * Return value: `true` if found script/language-specific font extents.
+ *
+ * Since: 8.0.0
+ **/
+hb_bool_t
+hb_ot_layout_get_font_extents2 (hb_font_t *font,
+ hb_direction_t direction,
+ hb_script_t script,
+ hb_language_t language,
+ hb_font_extents_t *extents)
+{
+ hb_tag_t script_tag, language_tag;
+ choose_base_tags (script, language, &script_tag, &language_tag);
+ return hb_ot_layout_get_font_extents (font,
+ direction,
+ script_tag,
+ language_tag,
+ extents);
+}
+
/**
* hb_ot_layout_get_horizontal_baseline_tag_for_script:
* @script: a script tag.
@@ -2130,6 +2282,42 @@ hb_ot_layout_get_baseline (hb_font_t *font,
}
/**
+ * hb_ot_layout_get_baseline2:
+ * @font: a font
+ * @baseline_tag: a baseline tag
+ * @direction: text direction.
+ * @script: script.
+ * @language: (nullable): language, currently unused.
+ * @coord: (out) (nullable): baseline value if found.
+ *
+ * Fetches a baseline value from the face.
+ *
+ * This function is like hb_ot_layout_get_baseline() but takes
+ * #hb_script_t and #hb_language_t instead of OpenType #hb_tag_t.
+ *
+ * Return value: `true` if found baseline value in the font.
+ *
+ * Since: 8.0.0
+ **/
+hb_bool_t
+hb_ot_layout_get_baseline2 (hb_font_t *font,
+ hb_ot_layout_baseline_tag_t baseline_tag,
+ hb_direction_t direction,
+ hb_script_t script,
+ hb_language_t language,
+ hb_position_t *coord /* OUT. May be NULL. */)
+{
+ hb_tag_t script_tag, language_tag;
+ choose_base_tags (script, language, &script_tag, &language_tag);
+ return hb_ot_layout_get_baseline (font,
+ baseline_tag,
+ direction,
+ script_tag,
+ language_tag,
+ coord);
+}
+
+/**
* hb_ot_layout_get_baseline_with_fallback:
* @font: a font
* @baseline_tag: a baseline tag
@@ -2351,6 +2539,41 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font,
}
}
+/**
+ * hb_ot_layout_get_baseline_with_fallback2:
+ * @font: a font
+ * @baseline_tag: a baseline tag
+ * @direction: text direction.
+ * @script: script.
+ * @language: (nullable): language, currently unused.
+ * @coord: (out): baseline value if found.
+ *
+ * Fetches a baseline value from the face, and synthesizes
+ * it if the font does not have it.
+ *
+ * This function is like hb_ot_layout_get_baseline_with_fallback() but takes
+ * #hb_script_t and #hb_language_t instead of OpenType #hb_tag_t.
+ *
+ * Since: 8.0.0
+ **/
+void
+hb_ot_layout_get_baseline_with_fallback2 (hb_font_t *font,
+ hb_ot_layout_baseline_tag_t baseline_tag,
+ hb_direction_t direction,
+ hb_script_t script,
+ hb_language_t language,
+ hb_position_t *coord /* OUT */)
+{
+ hb_tag_t script_tag, language_tag;
+ choose_base_tags (script, language, &script_tag, &language_tag);
+ hb_ot_layout_get_baseline_with_fallback (font,
+ baseline_tag,
+ direction,
+ script_tag,
+ language_tag,
+ coord);
+}
+
#endif
@@ -2447,9 +2670,10 @@ hb_ot_layout_lookup_get_optical_bound (hb_font_t *font,
hb_codepoint_t glyph)
{
const OT::PosLookup &lookup = font->face->table.GPOS->table->get_lookup (lookup_index);
+ hb_blob_t *blob = font->face->table.GPOS->get_blob ();
hb_glyph_position_t pos = {0};
hb_position_single_dispatch_t c;
- lookup.dispatch (&c, font, direction, glyph, pos);
+ lookup.dispatch (&c, font, blob, direction, glyph, pos);
hb_position_t ret = 0;
switch (direction)
{
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.h b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.h
index 10dcc65ac0..386b98d580 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.h
@@ -325,6 +325,13 @@ hb_ot_layout_collect_features (hb_face_t *face,
hb_set_t *feature_indexes /* OUT */);
HB_EXTERN void
+hb_ot_layout_collect_features_map (hb_face_t *face,
+ hb_tag_t table_tag,
+ unsigned script_index,
+ unsigned language_index,
+ hb_map_t *feature_map /* OUT */);
+
+HB_EXTERN void
hb_ot_layout_collect_lookups (hb_face_t *face,
hb_tag_t table_tag,
const hb_tag_t *scripts,
@@ -447,6 +454,20 @@ hb_ot_layout_feature_get_characters (hb_face_t *face,
* BASE
*/
+HB_EXTERN hb_bool_t
+hb_ot_layout_get_font_extents (hb_font_t *font,
+ hb_direction_t direction,
+ hb_tag_t script_tag,
+ hb_tag_t language_tag,
+ hb_font_extents_t *extents);
+
+HB_EXTERN hb_bool_t
+hb_ot_layout_get_font_extents2 (hb_font_t *font,
+ hb_direction_t direction,
+ hb_script_t script,
+ hb_language_t language,
+ hb_font_extents_t *extents);
+
/**
* hb_ot_layout_baseline_tag_t:
* @HB_OT_LAYOUT_BASELINE_TAG_ROMAN: The baseline used by alphabetic scripts such as Latin, Cyrillic and Greek.
@@ -499,6 +520,14 @@ hb_ot_layout_get_baseline (hb_font_t *font,
hb_tag_t language_tag,
hb_position_t *coord /* OUT. May be NULL. */);
+HB_EXTERN hb_bool_t
+hb_ot_layout_get_baseline2 (hb_font_t *font,
+ hb_ot_layout_baseline_tag_t baseline_tag,
+ hb_direction_t direction,
+ hb_script_t script,
+ hb_language_t language,
+ hb_position_t *coord /* OUT. May be NULL. */);
+
HB_EXTERN void
hb_ot_layout_get_baseline_with_fallback (hb_font_t *font,
hb_ot_layout_baseline_tag_t baseline_tag,
@@ -507,6 +536,14 @@ hb_ot_layout_get_baseline_with_fallback (hb_font_t *font,
hb_tag_t language_tag,
hb_position_t *coord /* OUT */);
+HB_EXTERN void
+hb_ot_layout_get_baseline_with_fallback2 (hb_font_t *font,
+ hb_ot_layout_baseline_tag_t baseline_tag,
+ hb_direction_t direction,
+ hb_script_t script,
+ hb_language_t language,
+ hb_position_t *coord /* OUT */);
+
HB_END_DECLS
#endif /* HB_OT_LAYOUT_H */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh
index 9505d5f147..d71889331d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout.hh
@@ -448,7 +448,7 @@ _hb_glyph_info_get_lig_id (const hb_glyph_info_t *info)
static inline bool
_hb_glyph_info_ligated_internal (const hb_glyph_info_t *info)
{
- return !!(info->lig_props() & IS_LIG_BASE);
+ return info->lig_props() & IS_LIG_BASE;
}
static inline unsigned int
@@ -496,37 +496,37 @@ _hb_glyph_info_get_glyph_props (const hb_glyph_info_t *info)
static inline bool
_hb_glyph_info_is_base_glyph (const hb_glyph_info_t *info)
{
- return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH);
+ return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
}
static inline bool
_hb_glyph_info_is_ligature (const hb_glyph_info_t *info)
{
- return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE);
+ return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
}
static inline bool
_hb_glyph_info_is_mark (const hb_glyph_info_t *info)
{
- return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
+ return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK;
}
static inline bool
_hb_glyph_info_substituted (const hb_glyph_info_t *info)
{
- return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED);
+ return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
}
static inline bool
_hb_glyph_info_ligated (const hb_glyph_info_t *info)
{
- return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED);
+ return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
}
static inline bool
_hb_glyph_info_multiplied (const hb_glyph_info_t *info)
{
- return !!(info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED);
+ return info->glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
}
static inline bool
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc
index 8882dbaccb..fac73eb34e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-map.cc
@@ -213,7 +213,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
/* Sort features and merge duplicates */
if (feature_infos.length)
{
- feature_infos.qsort ();
+ if (!is_simple)
+ feature_infos.qsort ();
auto *f = feature_infos.arrayZ;
unsigned int j = 0;
unsigned count = feature_infos.length;
@@ -238,6 +239,13 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
feature_infos.shrink (j + 1);
}
+ hb_map_t feature_indices[2];
+ for (unsigned int table_index = 0; table_index < 2; table_index++)
+ hb_ot_layout_collect_features_map (face,
+ table_tags[table_index],
+ script_index[table_index],
+ language_index[table_index],
+ &feature_indices[table_index]);
/* Allocate bits now */
static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), "");
@@ -260,7 +268,6 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
if (!info->max_value || next_bit + bits_needed >= global_bit_shift)
continue; /* Feature disabled, or not enough bits. */
-
bool found = false;
unsigned int feature_index[2];
for (unsigned int table_index = 0; table_index < 2; table_index++)
@@ -268,12 +275,14 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
if (required_feature_tag[table_index] == info->tag)
required_feature_stage[table_index] = info->stage[table_index];
- found |= (bool) hb_ot_layout_language_find_feature (face,
- table_tags[table_index],
- script_index[table_index],
- language_index[table_index],
- info->tag,
- &feature_index[table_index]);
+ hb_codepoint_t *index;
+ if (feature_indices[table_index].has (info->tag, &index))
+ {
+ feature_index[table_index] = *index;
+ found = true;
+ }
+ else
+ feature_index[table_index] = HB_OT_LAYOUT_NO_FEATURE_INDEX;
}
if (!found && (info->flags & F_GLOBAL_SEARCH))
{
@@ -314,7 +323,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
map->needs_fallback = !found;
}
//feature_infos.shrink (0); /* Done with these */
-
+ if (is_simple)
+ m.features.qsort ();
add_gsub_pause (nullptr);
add_gpos_pause (nullptr);
@@ -350,7 +360,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
}
/* Sort lookups and merge duplicates */
- if (last_num_lookups < lookups.length)
+ if (last_num_lookups + 1 < lookups.length)
{
lookups.as_array ().sub_array (last_num_lookups, lookups.length - last_num_lookups).qsort ();
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-map.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-map.hh
index efc8cae96a..8af8129ceb 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-map.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-map.hh
@@ -60,6 +60,13 @@ struct hb_ot_map_t
int cmp (const hb_tag_t tag_) const
{ return tag_ < tag ? -1 : tag_ > tag ? 1 : 0; }
+
+ HB_INTERNAL static int cmp (const void *pa, const void *pb)
+ {
+ const feature_map_t *a = (const feature_map_t *) pa;
+ const feature_map_t *b = (const feature_map_t *) pb;
+ return a->tag < b->tag ? -1 : a->tag > b->tag ? 1 : 0;
+ }
};
struct lookup_map_t {
@@ -273,6 +280,7 @@ struct hb_ot_map_builder_t
hb_face_t *face;
hb_segment_properties_t props;
+ bool is_simple;
hb_tag_t chosen_script[2];
bool found_script[2];
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh
index dccf720f46..5839059fde 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-math-table.hh
@@ -73,7 +73,6 @@ struct MathConstants
{
TRACE_SERIALIZE (this);
auto *out = c->start_embed (this);
- if (unlikely (!out)) return_trace (nullptr);
HBINT16 *p = c->allocate_size<HBINT16> (HBINT16::static_size * 2);
if (unlikely (!p)) return_trace (nullptr);
@@ -310,7 +309,6 @@ struct MathKern
{
TRACE_SERIALIZE (this);
auto *out = c->start_embed (this);
- if (unlikely (!out)) return_trace (nullptr);
if (unlikely (!c->embed (heightCount))) return_trace (nullptr);
@@ -335,6 +333,7 @@ struct MathKern
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
c->check_array (mathValueRecordsZ.arrayZ, 2 * heightCount + 1) &&
sanitize_math_value_records (c));
}
@@ -345,27 +344,20 @@ struct MathKern
const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + 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:
+ /* According to OpenType spec (v1.9), except for the boundary cases, the index
+ * chosen for kern value should be i such that
+ * correctionHeight[i-1] <= correction_height < correctionHeight[i]
+ * We can use the binary search algorithm of std::upper_bound(). Or, we can
+ * use the internal hb_bsearch_impl.
*/
- 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;
- }
+ unsigned int pos;
+ auto cmp = +[](const void* key, const void* p,
+ int sign, hb_font_t* font, const MathKern* mathKern) -> int {
+ return sign * *(hb_position_t*)key - sign * ((MathValueRecord*)p)->get_y_value(font, mathKern);
+ };
+ unsigned int i = hb_bsearch_impl(&pos, correction_height, correctionHeight,
+ heightCount, MathValueRecord::static_size,
+ cmp, sign, font, this) ? pos + 1 : pos;
return kernValue[i].get_x_value (font, this);
}
@@ -572,6 +564,7 @@ struct MathGlyphInfo
auto it =
+ hb_iter (this+extendedShapeCoverage)
+ | hb_take (c->plan->source->get_num_glyphs ())
| hb_filter (glyphset)
| hb_map_retains_sorting (glyph_map)
;
@@ -757,8 +750,6 @@ struct MathGlyphAssembly
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- auto *out = c->serializer->start_embed (*this);
- if (unlikely (!out)) return_trace (false);
if (!c->serializer->copy (italicsCorrection, this)) return_trace (false);
if (!c->serializer->copy<HBUINT16> (partRecords.len)) return_trace (false);
@@ -945,13 +936,13 @@ struct MathVariants
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
if (!c->serializer->check_assign (out->minConnectorOverlap, minConnectorOverlap, HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
-
+
hb_sorted_vector_t<hb_codepoint_t> new_vert_coverage;
hb_sorted_vector_t<hb_codepoint_t> new_hori_coverage;
hb_set_t indices;
collect_coverage_and_indices (new_vert_coverage, vertGlyphCoverage, 0, vertGlyphCount, indices, glyphset, glyph_map);
collect_coverage_and_indices (new_hori_coverage, horizGlyphCoverage, vertGlyphCount, vertGlyphCount + horizGlyphCount, indices, glyphset, glyph_map);
-
+
if (!c->serializer->check_assign (out->vertGlyphCount, new_vert_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
if (!c->serializer->check_assign (out->horizGlyphCount, new_hori_coverage.length, HB_SERIALIZE_ERROR_INT_OVERFLOW))
@@ -963,10 +954,10 @@ struct MathVariants
if (!o) return_trace (false);
o->serialize_subset (c, glyphConstruction[i], this);
}
-
+
if (new_vert_coverage)
out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ());
-
+
if (new_hori_coverage)
out->horizGlyphCoverage.serialize_serialize (c->serializer, new_hori_coverage.iter ());
return_trace (true);
@@ -987,6 +978,7 @@ struct MathVariants
return_trace (c->check_struct (this) &&
vertGlyphCoverage.sanitize (c, this) &&
horizGlyphCoverage.sanitize (c, this) &&
+ hb_barrier () &&
c->check_array (glyphConstruction.arrayZ, vertGlyphCount + horizGlyphCount) &&
sanitize_offsets (c));
}
@@ -1106,6 +1098,7 @@ struct MATH
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
likely (version.major == 1) &&
+ hb_barrier () &&
mathConstants.sanitize (c, this) &&
mathGlyphInfo.sanitize (c, this) &&
mathVariants.sanitize (c, this));
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-math.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-math.cc
index c515867bdf..876ad258e3 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-math.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-math.cc
@@ -76,7 +76,7 @@ hb_ot_math_has_data (hb_face_t *face)
*
* However, if the requested 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
+ * #HB_OT_MATH_CONSTANT_RADICAL_DEGREE_BOTTOM_RAISE_PERCENT, then the return value is
* an integer between 0 and 100 representing that percentage.
*
* Return value: the requested constant or zero
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 05cbf2cedf..8f000526b9 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-maxp-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-maxp-table.hh
@@ -85,7 +85,7 @@ struct maxp
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
-
+ hb_barrier ();
if (version.major == 1)
{
const maxpV1Tail &v1 = StructAfter<maxpV1Tail> (*this);
@@ -100,9 +100,10 @@ struct maxp
maxp *maxp_prime = c->serializer->embed (this);
if (unlikely (!maxp_prime)) return_trace (false);
- maxp_prime->numGlyphs = c->plan->num_output_glyphs ();
+ maxp_prime->numGlyphs = hb_min (c->plan->num_output_glyphs (), 0xFFFFu);
if (maxp_prime->version.major == 1)
{
+ hb_barrier ();
const maxpV1Tail *src_v1 = &StructAfter<maxpV1Tail> (*this);
maxpV1Tail *dest_v1 = c->serializer->embed<maxpV1Tail> (src_v1);
if (unlikely (!dest_v1)) return_trace (false);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-meta-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-meta-table.hh
index e1b68bcf91..658db584c7 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-meta-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-meta-table.hh
@@ -51,6 +51,7 @@ struct DataMap
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
+ hb_barrier () &&
dataZ.sanitize (c, base, dataLength)));
}
@@ -101,6 +102,7 @@ struct meta
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
+ hb_barrier () &&
version == 1 &&
dataMaps.sanitize (c, this)));
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-metrics.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-metrics.cc
index 5b12482b97..e314d946b6 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-metrics.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-metrics.cc
@@ -196,7 +196,7 @@ hb_ot_metrics_get_position (hb_font_t *font,
*position *= mult;
if (font->slant)
- *position += _hb_roundf (mult * font->slant_xy * rise);
+ *position += roundf (mult * font->slant_xy * rise);
}
return ret;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-name.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-name.cc
index 0323364aef..6adf1e8fbe 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-name.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-name.cc
@@ -181,6 +181,4 @@ hb_ot_name_get_utf32 (hb_face_t *face,
return hb_ot_name_get_utf<hb_utf32_t> (face, name_id, language, text_size, text);
}
-#include "hb-ot-name-language-static.hh"
-
#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh
index 97d18b9d75..43b58d9bbf 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-os2-table.hh
@@ -209,6 +209,23 @@ struct OS2
return ret;
}
+ static unsigned calc_avg_char_width (const hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>>& hmtx_map)
+ {
+ unsigned num = 0;
+ unsigned total_width = 0;
+ for (const auto& _ : hmtx_map.values_ref ())
+ {
+ unsigned width = _.first;
+ if (width)
+ {
+ total_width += width;
+ num++;
+ }
+ }
+
+ return num ? (unsigned) roundf ((double) total_width / (double) num) : 0;
+ }
+
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
@@ -239,39 +256,40 @@ struct OS2
if (os2_prime->version >= 2)
{
+ hb_barrier ();
auto *table = & const_cast<OS2V2Tail &> (os2_prime->v2 ());
HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_X_HEIGHT, sxHeight);
HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_CAP_HEIGHT, sCapHeight);
}
- }
-#endif
- if (c->plan->user_axes_location.has (HB_TAG ('w','g','h','t')) &&
- !c->plan->pinned_at_default)
- {
- float weight_class = c->plan->user_axes_location.get (HB_TAG ('w','g','h','t'));
- if (!c->serializer->check_assign (os2_prime->usWeightClass,
- roundf (hb_clamp (weight_class, 1.0f, 1000.0f)),
+ unsigned avg_char_width = calc_avg_char_width (c->plan->hmtx_map);
+ if (!c->serializer->check_assign (os2_prime->xAvgCharWidth, avg_char_width,
HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
}
+#endif
- if (c->plan->user_axes_location.has (HB_TAG ('w','d','t','h')) &&
- !c->plan->pinned_at_default)
+ Triple *axis_range;
+ if (c->plan->user_axes_location.has (HB_TAG ('w','g','h','t'), &axis_range))
{
- float width = c->plan->user_axes_location.get (HB_TAG ('w','d','t','h'));
- if (!c->serializer->check_assign (os2_prime->usWidthClass,
- roundf (map_wdth_to_widthclass (width)),
- HB_SERIALIZE_ERROR_INT_OVERFLOW))
- return_trace (false);
+ unsigned weight_class = static_cast<unsigned> (roundf (hb_clamp (axis_range->middle, 1.0f, 1000.0f)));
+ if (os2_prime->usWeightClass != weight_class)
+ os2_prime->usWeightClass = weight_class;
}
- if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
- return_trace (true);
+ if (c->plan->user_axes_location.has (HB_TAG ('w','d','t','h'), &axis_range))
+ {
+ unsigned width_class = static_cast<unsigned> (roundf (map_wdth_to_widthclass (axis_range->middle)));
+ if (os2_prime->usWidthClass != width_class)
+ os2_prime->usWidthClass = width_class;
+ }
os2_prime->usFirstCharIndex = hb_min (0xFFFFu, c->plan->unicodes.get_min ());
os2_prime->usLastCharIndex = hb_min (0xFFFFu, c->plan->unicodes.get_max ());
+ if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
+ return_trace (true);
+
_update_unicode_ranges (&c->plan->unicodes, os2_prime->ulUnicodeRange);
return_trace (true);
@@ -287,8 +305,7 @@ struct OS2
/* This block doesn't show up in profiles. If it ever did,
* we can rewrite it to iterate over OS/2 ranges and use
* set iteration to check if the range matches. */
- for (hb_codepoint_t cp = HB_SET_VALUE_INVALID;
- codepoints->next (&cp);)
+ for (auto cp : *codepoints)
{
unsigned int bit = _hb_ot_os2_get_unicode_range_bit (cp);
if (bit < 128)
@@ -340,6 +357,7 @@ struct OS2
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) return_trace (false);
+ hb_barrier ();
if (unlikely (version >= 1 && !v1X.sanitize (c))) return_trace (false);
if (unlikely (version >= 2 && !v2X.sanitize (c))) return_trace (false);
if (unlikely (version >= 5 && !v5X.sanitize (c))) return_trace (false);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table-v2subset.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table-v2subset.hh
index 951e6395d6..d44233610a 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table-v2subset.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table-v2subset.hh
@@ -79,6 +79,11 @@ HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const
post::accelerator_t _post (c->plan->source);
hb_hashmap_t<hb_bytes_t, uint32_t, true> glyph_name_to_new_index;
+
+ old_new_index_map.alloc (num_glyphs);
+ old_gid_new_index_map.alloc (num_glyphs);
+ glyph_name_to_new_index.alloc (num_glyphs);
+
for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++)
{
hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
@@ -86,11 +91,12 @@ HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const
unsigned new_index;
const uint32_t *new_index2;
- if (old_index <= 257) new_index = old_index;
+ if (old_index <= 257)
+ new_index = old_index;
else if (old_new_index_map.has (old_index, &new_index2))
- {
new_index = *new_index2;
- } else {
+ else
+ {
hb_bytes_t s = _post.find_glyph_name (old_gid);
new_index = glyph_name_to_new_index.get (s);
if (new_index == (unsigned)-1)
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh
index e0eb770948..8132dcfb91 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-post-table.hh
@@ -96,8 +96,11 @@ struct post
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- post *post_prime = c->serializer->start_embed<post> ();
- if (unlikely (!post_prime)) return_trace (false);
+ auto *post_prime = c->serializer->start_embed<post> ();
+
+ bool glyph_names = c->plan->flags & HB_SUBSET_FLAGS_GLYPH_NAMES;
+ if (!serialize (c->serializer, glyph_names))
+ return_trace (false);
#ifndef HB_NO_VAR
if (c->plan->normalized_coords)
@@ -110,20 +113,19 @@ struct post
}
#endif
- bool glyph_names = c->plan->flags & HB_SUBSET_FLAGS_GLYPH_NAMES;
- if (!serialize (c->serializer, glyph_names))
- return_trace (false);
-
- if (c->plan->user_axes_location.has (HB_TAG ('s','l','n','t')) &&
- !c->plan->pinned_at_default)
+ Triple *axis_range;
+ if (c->plan->user_axes_location.has (HB_TAG ('s','l','n','t'), &axis_range))
{
- float italic_angle = c->plan->user_axes_location.get (HB_TAG ('s','l','n','t'));
- italic_angle = hb_max (-90.f, hb_min (italic_angle, 90.f));
- post_prime->italicAngle.set_float (italic_angle);
+ float italic_angle = hb_max (-90.f, hb_min (axis_range->middle, 90.f));
+ if (post_prime->italicAngle.to_float () != italic_angle)
+ post_prime->italicAngle.set_float (italic_angle);
}
if (glyph_names && version.major == 2)
+ {
+ hb_barrier ();
return_trace (v2X.subset (c));
+ }
return_trace (true);
}
@@ -139,6 +141,7 @@ struct post
version = table->version.to_int ();
if (version != 0x00020000) return;
+ hb_barrier ();
const postV2Tail &v2 = table->v2X;
@@ -218,10 +221,16 @@ struct post
unsigned int get_glyph_count () const
{
if (version == 0x00010000)
+ {
+ hb_barrier ();
return format1_names_length;
+ }
if (version == 0x00020000)
+ {
+ hb_barrier ();
return glyphNameIndex->len;
+ }
return 0;
}
@@ -246,13 +255,18 @@ struct post
{
if (version == 0x00010000)
{
+ hb_barrier ();
if (glyph >= format1_names_length)
return hb_bytes_t ();
return format1_names (glyph);
}
- if (version != 0x00020000 || glyph >= glyphNameIndex->len)
+ if (version != 0x00020000)
+ return hb_bytes_t ();
+ hb_barrier ();
+
+ if (glyph >= glyphNameIndex->len)
return hb_bytes_t ();
unsigned int index = glyphNameIndex->arrayZ[glyph];
@@ -285,6 +299,7 @@ struct post
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
(version.to_int () == 0x00010000 ||
(version.to_int () == 0x00020000 && v2X.sanitize (c)) ||
version.to_int () == 0x00030000));
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 897377aa15..69dbec0783 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-normalize.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape-normalize.cc
@@ -383,14 +383,15 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
if (!all_simple && buffer->message(font, "start reorder"))
{
count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
{
- if (_hb_glyph_info_get_modified_combining_class (&buffer->info[i]) == 0)
+ if (_hb_glyph_info_get_modified_combining_class (&info[i]) == 0)
continue;
unsigned int end;
for (end = i + 1; end < count; end++)
- if (_hb_glyph_info_get_modified_combining_class (&buffer->info[end]) == 0)
+ if (_hb_glyph_info_get_modified_combining_class (&info[end]) == 0)
break;
/* We are going to do a O(n^2). Only do this if the sequence is short. */
@@ -414,11 +415,13 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
* If it did NOT, then make it skippable.
* https://github.com/harfbuzz/harfbuzz/issues/554
*/
- for (unsigned int i = 1; i + 1 < buffer->len; i++)
- if (buffer->info[i].codepoint == 0x034Fu/*CGJ*/ &&
- (info_cc(buffer->info[i+1]) == 0 || info_cc(buffer->info[i-1]) <= info_cc(buffer->info[i+1])))
+ unsigned count = buffer->len;
+ hb_glyph_info_t *info = buffer->info;
+ for (unsigned int i = 1; i + 1 < count; i++)
+ if (info[i].codepoint == 0x034Fu/*CGJ*/ &&
+ (info_cc(info[i+1]) == 0 || info_cc(info[i-1]) <= info_cc(info[i+1])))
{
- _hb_glyph_info_unhide (&buffer->info[i]);
+ _hb_glyph_info_unhide (&info[i]);
}
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc
index 3d207e0681..148830022e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shape.cc
@@ -155,7 +155,7 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
#endif
bool has_gpos = !disable_gpos && hb_ot_layout_has_positioning (face);
if (false)
- ;
+ {}
#ifndef HB_NO_AAT_SHAPE
/* Prefer GPOS over kerx if GSUB is present;
* https://github.com/harfbuzz/harfbuzz/issues/3008 */
@@ -167,15 +167,16 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
if (!plan.apply_kerx && (!has_gpos_kern || !plan.apply_gpos))
{
+ if (false) {}
#ifndef HB_NO_AAT_SHAPE
- if (has_kerx)
+ else if (has_kerx)
plan.apply_kerx = true;
- else
#endif
#ifndef HB_NO_OT_KERN
- if (hb_ot_layout_has_kerning (face))
+ else if (hb_ot_layout_has_kerning (face))
plan.apply_kern = true;
#endif
+ else {}
}
plan.apply_fallback_kern = !(plan.apply_gpos || plan.apply_kerx || plan.apply_kern);
@@ -313,6 +314,8 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
{
hb_ot_map_builder_t *map = &planner->map;
+ map->is_simple = true;
+
map->enable_feature (HB_TAG('r','v','r','n'));
map->add_gsub_pause (nullptr);
@@ -354,7 +357,10 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
map->enable_feature (HB_TAG ('H','A','R','F')); /* Considered discretionary. */
if (planner->shaper->collect_features)
+ {
+ map->is_simple = false;
planner->shaper->collect_features (planner);
+ }
map->enable_feature (HB_TAG ('B','u','z','z')); /* Considered required. */
map->enable_feature (HB_TAG ('B','U','Z','Z')); /* Considered discretionary. */
@@ -378,6 +384,8 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
map->enable_feature (HB_TAG ('v','e','r','t'), F_GLOBAL_SEARCH);
}
+ if (num_user_features)
+ map->is_simple = false;
for (unsigned int i = 0; i < num_user_features; i++)
{
const hb_feature_t *feature = &user_features[i];
@@ -469,9 +477,18 @@ hb_set_unicode_props (hb_buffer_t *buffer)
{
_hb_glyph_info_set_unicode_props (&info[i], buffer);
+ unsigned gen_cat = _hb_glyph_info_get_general_category (&info[i]);
+ if (FLAG_UNSAFE (gen_cat) &
+ (FLAG (HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER) |
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER) |
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER) |
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER) |
+ FLAG (HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR)))
+ continue;
+
/* Marks are already set as continuation by the above line.
* Handle Emoji_Modifier and ZWJ-continuation. */
- if (unlikely (_hb_glyph_info_get_general_category (&info[i]) == HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL &&
+ if (unlikely (gen_cat == HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL &&
hb_in_range<hb_codepoint_t> (info[i].codepoint, 0x1F3FBu, 0x1F3FFu)))
{
_hb_glyph_info_set_continuation (&info[i]);
@@ -749,6 +766,14 @@ hb_ot_shape_setup_masks_fraction (const hb_ot_shape_context_t *c)
_hb_glyph_info_get_general_category (&info[end]) ==
HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
end++;
+ if (start == i || end == i + 1)
+ {
+ if (start == i)
+ buffer->unsafe_to_concat (start, start + 1);
+ if (end == i + 1)
+ buffer->unsafe_to_concat (end - 1, end);
+ continue;
+ }
buffer->unsafe_to_break (start, end);
@@ -1030,7 +1055,7 @@ hb_ot_position_plan (const hb_ot_shape_context_t *c)
* direction is backward we don't shift and it will end up
* hanging over the next glyph after the final reordering.
*
- * Note: If fallback positinoing happens, we don't care about
+ * Note: If fallback positioning happens, we don't care about
* this as it will be overridden.
*/
bool adjust_offsets_when_zeroing = c->plan->adjust_mark_positioning_when_zeroing &&
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic-fallback.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic-fallback.hh
index e7a69008b7..66a8bfbd28 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic-fallback.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic-fallback.hh
@@ -368,7 +368,7 @@ arabic_fallback_plan_shape (arabic_fallback_plan_t *fallback_plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
- OT::hb_ot_apply_context_t c (0, font, buffer);
+ OT::hb_ot_apply_context_t c (0, font, buffer, hb_blob_get_empty ());
for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
if (fallback_plan->lookup_array[i]) {
c.set_lookup_mask (fallback_plan->mask_array[i]);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic-joining-list.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic-joining-list.hh
index c7b57820af..a5a7b84af4 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic-joining-list.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic-joining-list.hh
@@ -6,10 +6,10 @@
*
* on files with these headers:
*
- * # ArabicShaping-15.0.0.txt
- * # Date: 2022-02-14, 18:50:00 GMT [KW, RP]
- * # Scripts-15.0.0.txt
- * # Date: 2022-04-26, 23:15:02 GMT
+ * # ArabicShaping-15.1.0.txt
+ * # Date: 2023-01-05
+ * # Scripts-15.1.0.txt
+ * # Date: 2023-07-28, 16:01:07 GMT
*/
#ifndef HB_OT_SHAPER_ARABIC_JOINING_LIST_HH
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic-table.hh
index d7670f2f95..336a1391e9 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic-table.hh
@@ -6,10 +6,10 @@
*
* on files with these headers:
*
- * # ArabicShaping-15.0.0.txt
- * # Date: 2022-02-14, 18:50:00 GMT [KW, RP]
- * # Blocks-15.0.0.txt
- * # Date: 2022-01-28, 20:58:00 GMT [KW]
+ * # ArabicShaping-15.1.0.txt
+ * # Date: 2023-01-05
+ * # Blocks-15.1.0.txt
+ * # Date: 2023-07-28, 15:47:20 GMT
* UnicodeData.txt does not have a header.
*/
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic.cc
index 256f8f1d14..d70746ed2b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-arabic.cc
@@ -486,8 +486,10 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
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. */
+ bool rtl = buffer->props.direction == HB_DIRECTION_RTL;
+
+ if (!rtl)
+ buffer->reverse ();
/* We do a two pass implementation:
* First pass calculates the exact number of extra glyphs we need,
@@ -558,9 +560,9 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
DEBUG_MSG (ARABIC, nullptr, "%s stretch at (%u,%u,%u)",
step == MEASURE ? "measuring" : "cutting", context, start, end);
- DEBUG_MSG (ARABIC, nullptr, "rest of word: count=%u width %d", start - context, w_total);
- DEBUG_MSG (ARABIC, nullptr, "fixed tiles: count=%d width=%d", n_fixed, w_fixed);
- DEBUG_MSG (ARABIC, nullptr, "repeating tiles: count=%d width=%d", n_repeating, w_repeating);
+ DEBUG_MSG (ARABIC, nullptr, "rest of word: count=%u width %" PRId32, start - context, w_total);
+ DEBUG_MSG (ARABIC, nullptr, "fixed tiles: count=%d width=%" PRId32, n_fixed, w_fixed);
+ DEBUG_MSG (ARABIC, nullptr, "repeating tiles: count=%d width=%" PRId32, n_repeating, w_repeating);
/* Number of additional times to repeat each repeating tile. */
int n_copies = 0;
@@ -577,7 +579,10 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
++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);
+ w_remaining = 0;
+ }
}
if (step == MEASURE)
@@ -588,7 +593,7 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
else
{
buffer->unsafe_to_break (context, end);
- hb_position_t x_offset = 0;
+ hb_position_t x_offset = w_remaining / 2;
for (unsigned int k = end; k > start; k--)
{
hb_position_t width = font->get_glyph_h_advance (info[k - 1].codepoint);
@@ -597,18 +602,29 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
if (info[k - 1].arabic_shaping_action() == STCH_REPEATING)
repeat += n_copies;
- DEBUG_MSG (ARABIC, nullptr, "appending %u copies of glyph %u; j=%u",
+ DEBUG_MSG (ARABIC, nullptr, "appending %u copies of glyph %" PRIu32 "; j=%u",
repeat, info[k - 1].codepoint, j);
+ pos[k - 1].x_advance = 0;
for (unsigned int n = 0; n < repeat; n++)
{
- x_offset -= width;
- if (n > 0)
- x_offset += extra_repeat_overlap;
+ if (rtl)
+ {
+ 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 (!rtl)
+ {
+ x_offset += width;
+ if (n > 0)
+ x_offset -= extra_repeat_overlap;
+ }
}
}
}
@@ -625,6 +641,9 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED,
buffer->len = new_len;
}
}
+
+ if (!rtl)
+ buffer->reverse ();
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-machine.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-machine.hh
index 7dd47755af..353e32d32c 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-machine.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-machine.hh
@@ -53,7 +53,7 @@ enum indic_syllable_type_t {
};
-#line 54 "hb-ot-shaper-indic-machine.hh"
+#line 57 "hb-ot-shaper-indic-machine.hh"
#define indic_syllable_machine_ex_A 9u
#define indic_syllable_machine_ex_C 1u
#define indic_syllable_machine_ex_CM 16u
@@ -76,7 +76,7 @@ enum indic_syllable_type_t {
#define indic_syllable_machine_ex_ZWNJ 5u
-#line 75 "hb-ot-shaper-indic-machine.hh"
+#line 80 "hb-ot-shaper-indic-machine.hh"
static const unsigned char _indic_syllable_machine_trans_keys[] = {
8u, 8u, 4u, 13u, 5u, 13u, 5u, 13u, 13u, 13u, 4u, 13u, 4u, 13u, 4u, 13u,
8u, 8u, 5u, 13u, 5u, 13u, 13u, 13u, 4u, 13u, 4u, 13u, 4u, 13u, 4u, 13u,
@@ -460,7 +460,7 @@ find_syllables_indic (hb_buffer_t *buffer)
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 453 "hb-ot-shaper-indic-machine.hh"
+#line 464 "hb-ot-shaper-indic-machine.hh"
{
cs = indic_syllable_machine_start;
ts = 0;
@@ -476,7 +476,7 @@ find_syllables_indic (hb_buffer_t *buffer)
unsigned int syllable_serial = 1;
-#line 465 "hb-ot-shaper-indic-machine.hh"
+#line 480 "hb-ot-shaper-indic-machine.hh"
{
int _slen;
int _trans;
@@ -490,7 +490,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
-#line 477 "hb-ot-shaper-indic-machine.hh"
+#line 494 "hb-ot-shaper-indic-machine.hh"
}
_keys = _indic_syllable_machine_trans_keys + (cs<<1);
@@ -593,7 +593,7 @@ _eof_trans:
#line 114 "hb-ot-shaper-indic-machine.rl"
{act = 6;}
break;
-#line 559 "hb-ot-shaper-indic-machine.hh"
+#line 597 "hb-ot-shaper-indic-machine.hh"
}
_again:
@@ -602,7 +602,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
-#line 566 "hb-ot-shaper-indic-machine.hh"
+#line 606 "hb-ot-shaper-indic-machine.hh"
}
if ( ++p != pe )
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-table.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-table.cc
index d9fb0510e4..d9899a633c 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-table.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic-table.cc
@@ -6,12 +6,12 @@
*
* on files with these headers:
*
- * # IndicSyllabicCategory-15.0.0.txt
- * # Date: 2022-05-26, 02:18:00 GMT [KW, RP]
- * # IndicPositionalCategory-15.0.0.txt
- * # Date: 2022-05-26, 02:18:00 GMT [KW, RP]
- * # Blocks-15.0.0.txt
- * # Date: 2022-01-28, 20:58:00 GMT [KW]
+ * # IndicSyllabicCategory-15.1.0.txt
+ * # Date: 2023-01-05
+ * # IndicPositionalCategory-15.1.0.txt
+ * # Date: 2023-01-05
+ * # Blocks-15.1.0.txt
+ * # Date: 2023-07-28, 15:47:20 GMT
*/
#include "hb.hh"
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic.cc
index e3818cc37f..f8c970fc3e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-indic.cc
@@ -1067,12 +1067,15 @@ final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan,
base = i;
while (base < end && is_halant (info[base]))
base++;
- info[base].indic_position() = POS_BASE_C;
+ if (base < end)
+ info[base].indic_position() = POS_BASE_C;
try_pref = false;
}
break;
}
+ if (base == end)
+ break;
}
/* For Malayalam, skip over unformed below- (but NOT post-) forms. */
if (buffer->props.script == HB_SCRIPT_MALAYALAM)
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-khmer-machine.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-khmer-machine.hh
index 848ed231f7..f1e7a91f05 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-khmer-machine.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-khmer-machine.hh
@@ -48,7 +48,7 @@ enum khmer_syllable_type_t {
};
-#line 49 "hb-ot-shaper-khmer-machine.hh"
+#line 52 "hb-ot-shaper-khmer-machine.hh"
#define khmer_syllable_machine_ex_C 1u
#define khmer_syllable_machine_ex_DOTTEDCIRCLE 11u
#define khmer_syllable_machine_ex_H 4u
@@ -66,7 +66,7 @@ enum khmer_syllable_type_t {
#define khmer_syllable_machine_ex_ZWNJ 5u
-#line 65 "hb-ot-shaper-khmer-machine.hh"
+#line 70 "hb-ot-shaper-khmer-machine.hh"
static const unsigned char _khmer_syllable_machine_trans_keys[] = {
5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u,
5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 5u, 26u, 1u, 15u, 5u, 26u, 5u, 26u,
@@ -294,7 +294,7 @@ find_syllables_khmer (hb_buffer_t *buffer)
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 287 "hb-ot-shaper-khmer-machine.hh"
+#line 298 "hb-ot-shaper-khmer-machine.hh"
{
cs = khmer_syllable_machine_start;
ts = 0;
@@ -310,7 +310,7 @@ find_syllables_khmer (hb_buffer_t *buffer)
unsigned int syllable_serial = 1;
-#line 299 "hb-ot-shaper-khmer-machine.hh"
+#line 314 "hb-ot-shaper-khmer-machine.hh"
{
int _slen;
int _trans;
@@ -324,7 +324,7 @@ _resume:
#line 1 "NONE"
{ts = p;}
break;
-#line 311 "hb-ot-shaper-khmer-machine.hh"
+#line 328 "hb-ot-shaper-khmer-machine.hh"
}
_keys = _khmer_syllable_machine_trans_keys + (cs<<1);
@@ -394,7 +394,7 @@ _eof_trans:
#line 98 "hb-ot-shaper-khmer-machine.rl"
{act = 3;}
break;
-#line 368 "hb-ot-shaper-khmer-machine.hh"
+#line 398 "hb-ot-shaper-khmer-machine.hh"
}
_again:
@@ -403,7 +403,7 @@ _again:
#line 1 "NONE"
{ts = 0;}
break;
-#line 375 "hb-ot-shaper-khmer-machine.hh"
+#line 407 "hb-ot-shaper-khmer-machine.hh"
}
if ( ++p != pe )
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-syllabic.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-syllabic.cc
index 89226ae4a1..97f62035c6 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-syllabic.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-syllabic.cc
@@ -40,6 +40,14 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE))
return false;
if (likely (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE)))
+ {
+ if (buffer->messaging ())
+ (void) buffer->message (font, "skipped inserting dotted-circles because there is no broken syllables");
+ return false;
+ }
+
+ if (buffer->messaging () &&
+ !buffer->message (font, "start inserting dotted-circles"))
return false;
hb_codepoint_t dottedcircle_glyph;
@@ -84,6 +92,10 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font,
(void) buffer->next_glyph ();
}
buffer->sync ();
+
+ if (buffer->messaging ())
+ (void) buffer->message (font, "end inserting dotted-circles");
+
return true;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use-machine.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use-machine.hh
index 7249c33356..be0a2539be 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use-machine.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use-machine.hh
@@ -53,7 +53,7 @@ enum use_syllable_type_t {
};
-#line 54 "hb-ot-shaper-use-machine.hh"
+#line 57 "hb-ot-shaper-use-machine.hh"
#define use_syllable_machine_ex_B 1u
#define use_syllable_machine_ex_CGJ 6u
#define use_syllable_machine_ex_CMAbv 31u
@@ -68,7 +68,9 @@ enum use_syllable_type_t {
#define use_syllable_machine_ex_G 49u
#define use_syllable_machine_ex_GB 5u
#define use_syllable_machine_ex_H 12u
+#define use_syllable_machine_ex_HM 54u
#define use_syllable_machine_ex_HN 13u
+#define use_syllable_machine_ex_HR 55u
#define use_syllable_machine_ex_HVM 53u
#define use_syllable_machine_ex_IS 44u
#define use_syllable_machine_ex_J 50u
@@ -97,673 +99,662 @@ enum use_syllable_type_t {
#define use_syllable_machine_ex_ZWNJ 14u
-#line 96 "hb-ot-shaper-use-machine.hh"
+#line 103 "hb-ot-shaper-use-machine.hh"
static const unsigned char _use_syllable_machine_trans_keys[] = {
- 0u, 53u, 11u, 53u, 11u, 53u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u,
- 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u,
- 14u, 53u, 14u, 53u, 14u, 53u, 14u, 53u, 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u,
- 12u, 53u, 11u, 53u, 1u, 14u, 1u, 48u, 11u, 53u, 14u, 42u, 14u, 42u, 11u, 53u,
+ 49u, 51u, 0u, 53u, 11u, 53u, 11u, 53u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u,
+ 14u, 47u, 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u,
+ 14u, 48u, 14u, 53u, 14u, 53u, 14u, 53u, 14u, 53u, 12u, 53u, 14u, 53u, 12u, 53u,
+ 12u, 53u, 12u, 53u, 11u, 53u, 1u, 14u, 1u, 48u, 14u, 42u, 14u, 42u, 11u, 53u,
+ 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, 14u, 46u, 14u, 46u, 14u, 14u,
+ 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u, 14u, 53u, 14u, 53u, 14u, 53u,
+ 14u, 53u, 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u, 1u, 14u,
+ 1u, 14u, 1u, 48u, 13u, 14u, 4u, 14u, 11u, 53u, 11u, 53u, 1u, 53u, 14u, 48u,
+ 14u, 47u, 14u, 47u, 14u, 47u, 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u,
+ 14u, 48u, 1u, 14u, 14u, 48u, 14u, 53u, 14u, 53u, 14u, 53u, 14u, 53u, 12u, 53u,
+ 14u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u, 1u, 14u, 1u, 14u, 1u, 48u,
11u, 53u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, 14u, 46u, 14u, 46u,
14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u, 14u, 53u, 14u, 53u,
14u, 53u, 14u, 53u, 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u,
- 1u, 14u, 1u, 14u, 1u, 48u, 13u, 14u, 4u, 14u, 11u, 53u, 11u, 53u, 1u, 53u,
- 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u, 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u,
- 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u, 14u, 53u, 14u, 53u, 14u, 53u, 14u, 53u,
- 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u, 12u, 53u, 11u, 53u, 1u, 14u, 1u, 14u,
- 1u, 48u, 11u, 53u, 11u, 53u, 1u, 53u, 14u, 48u, 14u, 47u, 14u, 47u, 14u, 47u,
- 14u, 46u, 14u, 46u, 14u, 14u, 14u, 48u, 14u, 48u, 14u, 48u, 1u, 14u, 14u, 48u,
- 14u, 53u, 14u, 53u, 14u, 53u, 14u, 53u, 12u, 53u, 14u, 53u, 12u, 53u, 12u, 53u,
- 12u, 53u, 11u, 53u, 1u, 14u, 1u, 48u, 4u, 14u, 13u, 14u, 1u, 53u, 11u, 53u,
- 14u, 42u, 14u, 42u, 1u, 5u, 14u, 52u, 14u, 52u, 14u, 51u, 0
+ 1u, 14u, 1u, 48u, 4u, 14u, 13u, 14u, 1u, 53u, 14u, 42u, 14u, 42u, 1u, 5u,
+ 14u, 55u, 14u, 51u, 14u, 52u, 14u, 54u, 11u, 53u, 0
};
static const char _use_syllable_machine_key_spans[] = {
- 54, 43, 43, 53, 35, 34, 34, 34,
- 33, 33, 1, 35, 35, 35, 14, 35,
- 40, 40, 40, 40, 42, 40, 42, 42,
- 42, 43, 14, 48, 43, 29, 29, 43,
+ 3, 54, 43, 43, 53, 35, 34, 34,
+ 34, 33, 33, 1, 35, 35, 35, 14,
+ 35, 40, 40, 40, 40, 42, 40, 42,
+ 42, 42, 43, 14, 48, 29, 29, 43,
+ 53, 35, 34, 34, 34, 33, 33, 1,
+ 35, 35, 35, 14, 35, 40, 40, 40,
+ 40, 42, 40, 42, 42, 42, 43, 14,
+ 14, 48, 2, 11, 43, 43, 53, 35,
+ 34, 34, 34, 33, 33, 1, 35, 35,
+ 35, 14, 35, 40, 40, 40, 40, 42,
+ 40, 42, 42, 42, 43, 14, 14, 48,
43, 53, 35, 34, 34, 34, 33, 33,
1, 35, 35, 35, 14, 35, 40, 40,
40, 40, 42, 40, 42, 42, 42, 43,
- 14, 14, 48, 2, 11, 43, 43, 53,
- 35, 34, 34, 34, 33, 33, 1, 35,
- 35, 35, 14, 35, 40, 40, 40, 40,
- 42, 40, 42, 42, 42, 43, 14, 14,
- 48, 43, 43, 53, 35, 34, 34, 34,
- 33, 33, 1, 35, 35, 35, 14, 35,
- 40, 40, 40, 40, 42, 40, 42, 42,
- 42, 43, 14, 48, 11, 2, 53, 43,
- 29, 29, 5, 39, 39, 38
+ 14, 48, 11, 2, 53, 29, 29, 5,
+ 42, 38, 39, 41, 43
};
static const short _use_syllable_machine_index_offsets[] = {
- 0, 55, 99, 143, 197, 233, 268, 303,
- 338, 372, 406, 408, 444, 480, 516, 531,
- 567, 608, 649, 690, 731, 774, 815, 858,
- 901, 944, 988, 1003, 1052, 1096, 1126, 1156,
- 1200, 1244, 1298, 1334, 1369, 1404, 1439, 1473,
- 1507, 1509, 1545, 1581, 1617, 1632, 1668, 1709,
- 1750, 1791, 1832, 1875, 1916, 1959, 2002, 2045,
- 2089, 2104, 2119, 2168, 2171, 2183, 2227, 2271,
- 2325, 2361, 2396, 2431, 2466, 2500, 2534, 2536,
- 2572, 2608, 2644, 2659, 2695, 2736, 2777, 2818,
- 2859, 2902, 2943, 2986, 3029, 3072, 3116, 3131,
- 3146, 3195, 3239, 3283, 3337, 3373, 3408, 3443,
- 3478, 3512, 3546, 3548, 3584, 3620, 3656, 3671,
- 3707, 3748, 3789, 3830, 3871, 3914, 3955, 3998,
- 4041, 4084, 4128, 4143, 4192, 4204, 4207, 4261,
- 4305, 4335, 4365, 4371, 4411, 4451
+ 0, 4, 59, 103, 147, 201, 237, 272,
+ 307, 342, 376, 410, 412, 448, 484, 520,
+ 535, 571, 612, 653, 694, 735, 778, 819,
+ 862, 905, 948, 992, 1007, 1056, 1086, 1116,
+ 1160, 1214, 1250, 1285, 1320, 1355, 1389, 1423,
+ 1425, 1461, 1497, 1533, 1548, 1584, 1625, 1666,
+ 1707, 1748, 1791, 1832, 1875, 1918, 1961, 2005,
+ 2020, 2035, 2084, 2087, 2099, 2143, 2187, 2241,
+ 2277, 2312, 2347, 2382, 2416, 2450, 2452, 2488,
+ 2524, 2560, 2575, 2611, 2652, 2693, 2734, 2775,
+ 2818, 2859, 2902, 2945, 2988, 3032, 3047, 3062,
+ 3111, 3155, 3209, 3245, 3280, 3315, 3350, 3384,
+ 3418, 3420, 3456, 3492, 3528, 3543, 3579, 3620,
+ 3661, 3702, 3743, 3786, 3827, 3870, 3913, 3956,
+ 4000, 4015, 4064, 4076, 4079, 4133, 4163, 4193,
+ 4199, 4242, 4281, 4321, 4363
};
static const unsigned char _use_syllable_machine_indicies[] = {
- 0, 1, 2, 2, 3, 4, 2, 2,
- 2, 2, 2, 5, 6, 7, 8, 2,
- 2, 2, 9, 2, 2, 2, 10, 11,
- 12, 13, 14, 15, 16, 17, 18, 19,
- 20, 21, 22, 23, 2, 24, 25, 26,
- 2, 27, 28, 29, 30, 31, 32, 33,
- 30, 34, 2, 35, 2, 36, 2, 38,
- 39, 37, 40, 37, 37, 37, 37, 37,
- 37, 37, 41, 42, 43, 44, 45, 46,
- 47, 48, 49, 50, 51, 52, 53, 54,
- 37, 55, 56, 57, 37, 58, 59, 37,
- 60, 61, 62, 63, 60, 37, 37, 37,
- 37, 64, 37, 38, 39, 37, 40, 37,
- 37, 37, 37, 37, 37, 37, 41, 42,
- 43, 44, 45, 46, 47, 48, 49, 51,
- 51, 52, 53, 54, 37, 55, 56, 57,
- 37, 37, 37, 37, 60, 61, 62, 63,
- 60, 37, 37, 37, 37, 64, 37, 38,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 40, 37, 37, 37,
- 37, 37, 37, 37, 37, 42, 43, 44,
- 45, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 55, 56, 57, 37, 37,
- 37, 37, 37, 61, 62, 63, 65, 37,
- 37, 37, 37, 42, 37, 40, 37, 37,
- 37, 37, 37, 37, 37, 37, 42, 43,
- 44, 45, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 55, 56, 57, 37,
- 37, 37, 37, 37, 61, 62, 63, 65,
- 37, 40, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 43, 44, 45, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 61, 62, 63, 37, 40, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 44,
- 45, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 61, 62, 63, 37, 40,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 45, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 61, 62,
- 63, 37, 40, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 61, 62, 37, 40, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 62, 37, 40, 37,
- 40, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 43, 44, 45, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 55,
- 56, 57, 37, 37, 37, 37, 37, 61,
- 62, 63, 65, 37, 40, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 43, 44,
- 45, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 56, 57, 37, 37,
- 37, 37, 37, 61, 62, 63, 65, 37,
- 40, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 43, 44, 45, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 57, 37, 37, 37, 37, 37, 61,
- 62, 63, 65, 37, 66, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 40, 37, 40, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 43, 44, 45,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 61, 62, 63, 65, 37, 40,
- 37, 37, 37, 37, 37, 37, 37, 41,
- 42, 43, 44, 45, 37, 37, 37, 37,
- 37, 37, 52, 53, 54, 37, 55, 56,
- 57, 37, 37, 37, 37, 37, 61, 62,
- 63, 65, 37, 37, 37, 37, 42, 37,
- 40, 37, 37, 37, 37, 37, 37, 37,
- 37, 42, 43, 44, 45, 37, 37, 37,
- 37, 37, 37, 52, 53, 54, 37, 55,
- 56, 57, 37, 37, 37, 37, 37, 61,
- 62, 63, 65, 37, 37, 37, 37, 42,
- 37, 40, 37, 37, 37, 37, 37, 37,
- 37, 37, 42, 43, 44, 45, 37, 37,
- 37, 37, 37, 37, 37, 53, 54, 37,
- 55, 56, 57, 37, 37, 37, 37, 37,
- 61, 62, 63, 65, 37, 37, 37, 37,
- 42, 37, 40, 37, 37, 37, 37, 37,
- 37, 37, 37, 42, 43, 44, 45, 37,
- 37, 37, 37, 37, 37, 37, 37, 54,
- 37, 55, 56, 57, 37, 37, 37, 37,
- 37, 61, 62, 63, 65, 37, 37, 37,
- 37, 42, 37, 67, 37, 40, 37, 37,
- 37, 37, 37, 37, 37, 41, 42, 43,
- 44, 45, 37, 47, 48, 37, 37, 37,
- 52, 53, 54, 37, 55, 56, 57, 37,
- 37, 37, 37, 37, 61, 62, 63, 65,
- 37, 37, 37, 37, 42, 37, 40, 37,
- 37, 37, 37, 37, 37, 37, 37, 42,
- 43, 44, 45, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 55, 56, 57,
- 37, 37, 37, 37, 37, 61, 62, 63,
- 65, 37, 37, 37, 37, 42, 37, 67,
- 37, 40, 37, 37, 37, 37, 37, 37,
- 37, 41, 42, 43, 44, 45, 37, 37,
- 48, 37, 37, 37, 52, 53, 54, 37,
- 55, 56, 57, 37, 37, 37, 37, 37,
- 61, 62, 63, 65, 37, 37, 37, 37,
- 42, 37, 67, 37, 40, 37, 37, 37,
- 37, 37, 37, 37, 41, 42, 43, 44,
- 45, 37, 37, 37, 37, 37, 37, 52,
- 53, 54, 37, 55, 56, 57, 37, 37,
- 37, 37, 37, 61, 62, 63, 65, 37,
- 37, 37, 37, 42, 37, 67, 37, 40,
- 37, 37, 37, 37, 37, 37, 37, 41,
- 42, 43, 44, 45, 46, 47, 48, 37,
- 37, 37, 52, 53, 54, 37, 55, 56,
- 57, 37, 37, 37, 37, 37, 61, 62,
- 63, 65, 37, 37, 37, 37, 42, 37,
- 38, 39, 37, 40, 37, 37, 37, 37,
- 37, 37, 37, 41, 42, 43, 44, 45,
- 46, 47, 48, 49, 37, 51, 52, 53,
- 54, 37, 55, 56, 57, 37, 37, 37,
- 37, 60, 61, 62, 63, 60, 37, 37,
- 37, 37, 64, 37, 38, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 40, 37, 38, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 40, 37, 37, 37, 37, 37, 37, 37,
- 37, 42, 43, 44, 45, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 55,
- 56, 57, 37, 37, 37, 37, 37, 61,
- 62, 63, 65, 37, 38, 39, 37, 40,
- 37, 37, 37, 37, 37, 37, 37, 41,
- 42, 43, 44, 45, 46, 47, 48, 49,
- 50, 51, 52, 53, 54, 37, 55, 56,
- 57, 37, 37, 37, 37, 60, 61, 62,
- 63, 60, 37, 37, 37, 37, 64, 37,
- 40, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 58, 59, 37, 40, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 59, 37, 69, 70, 68, 71,
+ 1, 0, 2, 0, 3, 4, 5, 5,
+ 6, 7, 5, 5, 5, 5, 5, 8,
+ 9, 10, 11, 5, 5, 5, 12, 5,
+ 5, 5, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 8, 22, 23, 24, 25,
+ 5, 26, 27, 28, 5, 29, 30, 31,
+ 32, 33, 34, 35, 32, 1, 5, 36,
+ 5, 37, 5, 39, 40, 38, 41, 38,
+ 38, 38, 38, 38, 38, 38, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 39,
+ 51, 52, 53, 54, 38, 55, 56, 57,
+ 38, 58, 59, 38, 60, 61, 62, 63,
+ 60, 38, 38, 38, 38, 64, 38, 39,
+ 40, 38, 41, 38, 38, 38, 38, 38,
+ 38, 38, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 39, 51, 52, 53, 54,
+ 38, 55, 56, 57, 38, 38, 38, 38,
+ 60, 61, 62, 63, 60, 38, 38, 38,
+ 38, 64, 38, 39, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 41, 38, 38, 38, 38, 38, 38, 38,
+ 38, 43, 44, 45, 46, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 55,
+ 56, 57, 38, 38, 38, 38, 38, 61,
+ 62, 63, 65, 38, 38, 38, 38, 43,
+ 38, 41, 38, 38, 38, 38, 38, 38,
+ 38, 38, 43, 44, 45, 46, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 55, 56, 57, 38, 38, 38, 38, 38,
+ 61, 62, 63, 65, 38, 41, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 44,
+ 45, 46, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 61, 62, 63, 38,
+ 41, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 45, 46, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 61,
+ 62, 63, 38, 41, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 46,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 61, 62, 63, 38, 41, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 61, 62, 38,
+ 41, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 62, 38, 41, 38, 41, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 44, 45,
+ 46, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 55, 56, 57, 38, 38,
+ 38, 38, 38, 61, 62, 63, 65, 38,
+ 41, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 44, 45, 46, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 56, 57, 38, 38, 38, 38, 38, 61,
+ 62, 63, 65, 38, 41, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 44, 45,
+ 46, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 57, 38, 38,
+ 38, 38, 38, 61, 62, 63, 65, 38,
+ 66, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 41, 38, 41,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 44, 45, 46, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 61, 62,
+ 63, 65, 38, 41, 38, 38, 38, 38,
+ 38, 38, 38, 42, 43, 44, 45, 46,
+ 38, 38, 38, 38, 38, 38, 52, 53,
+ 54, 38, 55, 56, 57, 38, 38, 38,
+ 38, 38, 61, 62, 63, 65, 38, 38,
+ 38, 38, 43, 38, 41, 38, 38, 38,
+ 38, 38, 38, 38, 38, 43, 44, 45,
+ 46, 38, 38, 38, 38, 38, 38, 52,
+ 53, 54, 38, 55, 56, 57, 38, 38,
+ 38, 38, 38, 61, 62, 63, 65, 38,
+ 38, 38, 38, 43, 38, 41, 38, 38,
+ 38, 38, 38, 38, 38, 38, 43, 44,
+ 45, 46, 38, 38, 38, 38, 38, 38,
+ 38, 53, 54, 38, 55, 56, 57, 38,
+ 38, 38, 38, 38, 61, 62, 63, 65,
+ 38, 38, 38, 38, 43, 38, 41, 38,
+ 38, 38, 38, 38, 38, 38, 38, 43,
+ 44, 45, 46, 38, 38, 38, 38, 38,
+ 38, 38, 38, 54, 38, 55, 56, 57,
+ 38, 38, 38, 38, 38, 61, 62, 63,
+ 65, 38, 38, 38, 38, 43, 38, 67,
+ 38, 41, 38, 38, 38, 38, 38, 38,
+ 38, 42, 43, 44, 45, 46, 38, 48,
+ 49, 38, 38, 38, 52, 53, 54, 38,
+ 55, 56, 57, 38, 38, 38, 38, 38,
+ 61, 62, 63, 65, 38, 38, 38, 38,
+ 43, 38, 41, 38, 38, 38, 38, 38,
+ 38, 38, 38, 43, 44, 45, 46, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 55, 56, 57, 38, 38, 38, 38,
+ 38, 61, 62, 63, 65, 38, 38, 38,
+ 38, 43, 38, 67, 38, 41, 38, 38,
+ 38, 38, 38, 38, 38, 42, 43, 44,
+ 45, 46, 38, 38, 49, 38, 38, 38,
+ 52, 53, 54, 38, 55, 56, 57, 38,
+ 38, 38, 38, 38, 61, 62, 63, 65,
+ 38, 38, 38, 38, 43, 38, 67, 38,
+ 41, 38, 38, 38, 38, 38, 38, 38,
+ 42, 43, 44, 45, 46, 38, 38, 38,
+ 38, 38, 38, 52, 53, 54, 38, 55,
+ 56, 57, 38, 38, 38, 38, 38, 61,
+ 62, 63, 65, 38, 38, 38, 38, 43,
+ 38, 67, 38, 41, 38, 38, 38, 38,
+ 38, 38, 38, 42, 43, 44, 45, 46,
+ 47, 48, 49, 38, 38, 38, 52, 53,
+ 54, 38, 55, 56, 57, 38, 38, 38,
+ 38, 38, 61, 62, 63, 65, 38, 38,
+ 38, 38, 43, 38, 39, 40, 38, 41,
+ 38, 38, 38, 38, 38, 38, 38, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50,
+ 38, 51, 52, 53, 54, 38, 55, 56,
+ 57, 38, 38, 38, 38, 60, 61, 62,
+ 63, 60, 38, 38, 38, 38, 64, 38,
+ 39, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 41, 38, 39,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 41, 38, 38, 38,
+ 38, 38, 38, 38, 38, 43, 44, 45,
+ 46, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 55, 56, 57, 38, 38,
+ 38, 38, 38, 61, 62, 63, 65, 38,
+ 41, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 58, 59, 38, 41, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38,
+ 38, 38, 59, 38, 4, 69, 68, 70,
+ 68, 68, 68, 68, 68, 68, 68, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 4, 80, 81, 82, 83, 68, 84, 85,
+ 86, 68, 68, 68, 68, 87, 88, 89,
+ 90, 91, 68, 68, 68, 68, 92, 68,
+ 4, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 70, 68, 68,
+ 68, 68, 68, 68, 68, 68, 72, 73,
+ 74, 75, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 84, 85, 86, 68,
+ 68, 68, 68, 68, 88, 89, 90, 93,
+ 68, 68, 68, 68, 72, 68, 70, 68,
68, 68, 68, 68, 68, 68, 68, 72,
- 73, 74, 75, 76, 77, 78, 79, 80,
- 1, 81, 82, 83, 84, 68, 85, 86,
- 87, 68, 68, 68, 68, 88, 89, 90,
- 91, 92, 68, 68, 68, 68, 93, 68,
- 69, 70, 68, 71, 68, 68, 68, 68,
- 68, 68, 68, 72, 73, 74, 75, 76,
- 77, 78, 79, 80, 81, 81, 82, 83,
- 84, 68, 85, 86, 87, 68, 68, 68,
- 68, 88, 89, 90, 91, 92, 68, 68,
- 68, 68, 93, 68, 69, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 71, 68, 68, 68, 68, 68, 68,
- 68, 68, 73, 74, 75, 76, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 85, 86, 87, 68, 68, 68, 68, 68,
- 89, 90, 91, 94, 68, 68, 68, 68,
- 73, 68, 71, 68, 68, 68, 68, 68,
- 68, 68, 68, 73, 74, 75, 76, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 85, 86, 87, 68, 68, 68, 68,
- 68, 89, 90, 91, 94, 68, 71, 68,
+ 73, 74, 75, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 84, 85, 86,
+ 68, 68, 68, 68, 68, 88, 89, 90,
+ 93, 68, 70, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 73, 74, 75, 68,
68, 68, 68, 68, 68, 68, 68, 68,
- 74, 75, 76, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 89, 90, 91,
- 68, 71, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 75, 76, 68, 68,
+ 68, 88, 89, 90, 68, 70, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
+ 74, 75, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
- 89, 90, 91, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 88, 89, 90, 68,
+ 70, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 75, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
- 76, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 88,
+ 89, 90, 68, 70, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 89, 90, 91, 68, 71,
68, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 88, 89, 68, 70, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 89, 90,
- 68, 71, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 89, 68, 70,
+ 68, 70, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 73, 74, 75, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
- 68, 90, 68, 71, 68, 71, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 74,
- 75, 76, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 85, 86, 87, 68,
- 68, 68, 68, 68, 89, 90, 91, 94,
- 68, 71, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 74, 75, 76, 68, 68,
+ 84, 85, 86, 68, 68, 68, 68, 68,
+ 88, 89, 90, 93, 68, 70, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 73,
+ 74, 75, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 85, 86, 68,
+ 68, 68, 68, 68, 88, 89, 90, 93,
+ 68, 70, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 73, 74, 75, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
- 68, 86, 87, 68, 68, 68, 68, 68,
- 89, 90, 91, 94, 68, 71, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 74,
- 75, 76, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 87, 68,
- 68, 68, 68, 68, 89, 90, 91, 94,
- 68, 96, 95, 95, 95, 95, 95, 95,
- 95, 95, 95, 95, 95, 95, 97, 95,
- 71, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 74, 75, 76, 68, 68, 68,
+ 68, 68, 86, 68, 68, 68, 68, 68,
+ 88, 89, 90, 93, 68, 95, 94, 94,
+ 94, 94, 94, 94, 94, 94, 94, 94,
+ 94, 94, 96, 94, 70, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 73, 74,
+ 75, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 89,
- 90, 91, 94, 68, 71, 68, 68, 68,
+ 68, 68, 68, 88, 89, 90, 93, 68,
+ 70, 68, 68, 68, 68, 68, 68, 68,
+ 71, 72, 73, 74, 75, 68, 68, 68,
+ 68, 68, 68, 81, 82, 83, 68, 84,
+ 85, 86, 68, 68, 68, 68, 68, 88,
+ 89, 90, 93, 68, 68, 68, 68, 72,
+ 68, 70, 68, 68, 68, 68, 68, 68,
+ 68, 68, 72, 73, 74, 75, 68, 68,
+ 68, 68, 68, 68, 81, 82, 83, 68,
+ 84, 85, 86, 68, 68, 68, 68, 68,
+ 88, 89, 90, 93, 68, 68, 68, 68,
+ 72, 68, 70, 68, 68, 68, 68, 68,
+ 68, 68, 68, 72, 73, 74, 75, 68,
+ 68, 68, 68, 68, 68, 68, 82, 83,
+ 68, 84, 85, 86, 68, 68, 68, 68,
+ 68, 88, 89, 90, 93, 68, 68, 68,
+ 68, 72, 68, 70, 68, 68, 68, 68,
68, 68, 68, 68, 72, 73, 74, 75,
- 76, 68, 68, 68, 68, 68, 68, 82,
- 83, 84, 68, 85, 86, 87, 68, 68,
- 68, 68, 68, 89, 90, 91, 94, 68,
- 68, 68, 68, 73, 68, 71, 68, 68,
- 68, 68, 68, 68, 68, 68, 73, 74,
- 75, 76, 68, 68, 68, 68, 68, 68,
- 82, 83, 84, 68, 85, 86, 87, 68,
- 68, 68, 68, 68, 89, 90, 91, 94,
- 68, 68, 68, 68, 73, 68, 71, 68,
- 68, 68, 68, 68, 68, 68, 68, 73,
- 74, 75, 76, 68, 68, 68, 68, 68,
- 68, 68, 83, 84, 68, 85, 86, 87,
- 68, 68, 68, 68, 68, 89, 90, 91,
- 94, 68, 68, 68, 68, 73, 68, 71,
68, 68, 68, 68, 68, 68, 68, 68,
- 73, 74, 75, 76, 68, 68, 68, 68,
- 68, 68, 68, 68, 84, 68, 85, 86,
- 87, 68, 68, 68, 68, 68, 89, 90,
- 91, 94, 68, 68, 68, 68, 73, 68,
- 98, 68, 71, 68, 68, 68, 68, 68,
- 68, 68, 72, 73, 74, 75, 76, 68,
- 78, 79, 68, 68, 68, 82, 83, 84,
- 68, 85, 86, 87, 68, 68, 68, 68,
- 68, 89, 90, 91, 94, 68, 68, 68,
- 68, 73, 68, 71, 68, 68, 68, 68,
- 68, 68, 68, 68, 73, 74, 75, 76,
+ 83, 68, 84, 85, 86, 68, 68, 68,
+ 68, 68, 88, 89, 90, 93, 68, 68,
+ 68, 68, 72, 68, 97, 68, 70, 68,
+ 68, 68, 68, 68, 68, 68, 71, 72,
+ 73, 74, 75, 68, 77, 78, 68, 68,
+ 68, 81, 82, 83, 68, 84, 85, 86,
+ 68, 68, 68, 68, 68, 88, 89, 90,
+ 93, 68, 68, 68, 68, 72, 68, 70,
68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 85, 86, 87, 68, 68, 68,
- 68, 68, 89, 90, 91, 94, 68, 68,
- 68, 68, 73, 68, 98, 68, 71, 68,
- 68, 68, 68, 68, 68, 68, 72, 73,
- 74, 75, 76, 68, 68, 79, 68, 68,
- 68, 82, 83, 84, 68, 85, 86, 87,
- 68, 68, 68, 68, 68, 89, 90, 91,
- 94, 68, 68, 68, 68, 73, 68, 98,
- 68, 71, 68, 68, 68, 68, 68, 68,
- 68, 72, 73, 74, 75, 76, 68, 68,
- 68, 68, 68, 68, 82, 83, 84, 68,
- 85, 86, 87, 68, 68, 68, 68, 68,
- 89, 90, 91, 94, 68, 68, 68, 68,
- 73, 68, 98, 68, 71, 68, 68, 68,
- 68, 68, 68, 68, 72, 73, 74, 75,
- 76, 77, 78, 79, 68, 68, 68, 82,
- 83, 84, 68, 85, 86, 87, 68, 68,
- 68, 68, 68, 89, 90, 91, 94, 68,
- 68, 68, 68, 73, 68, 69, 70, 68,
- 71, 68, 68, 68, 68, 68, 68, 68,
- 72, 73, 74, 75, 76, 77, 78, 79,
- 80, 68, 81, 82, 83, 84, 68, 85,
- 86, 87, 68, 68, 68, 68, 88, 89,
- 90, 91, 92, 68, 68, 68, 68, 93,
- 68, 69, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 100, 99,
- 69, 95, 95, 95, 95, 95, 95, 95,
- 95, 95, 95, 95, 95, 97, 95, 69,
+ 72, 73, 74, 75, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 84, 85,
+ 86, 68, 68, 68, 68, 68, 88, 89,
+ 90, 93, 68, 68, 68, 68, 72, 68,
+ 97, 68, 70, 68, 68, 68, 68, 68,
+ 68, 68, 71, 72, 73, 74, 75, 68,
+ 68, 78, 68, 68, 68, 81, 82, 83,
+ 68, 84, 85, 86, 68, 68, 68, 68,
+ 68, 88, 89, 90, 93, 68, 68, 68,
+ 68, 72, 68, 97, 68, 70, 68, 68,
+ 68, 68, 68, 68, 68, 71, 72, 73,
+ 74, 75, 68, 68, 68, 68, 68, 68,
+ 81, 82, 83, 68, 84, 85, 86, 68,
+ 68, 68, 68, 68, 88, 89, 90, 93,
+ 68, 68, 68, 68, 72, 68, 97, 68,
+ 70, 68, 68, 68, 68, 68, 68, 68,
+ 71, 72, 73, 74, 75, 76, 77, 78,
+ 68, 68, 68, 81, 82, 83, 68, 84,
+ 85, 86, 68, 68, 68, 68, 68, 88,
+ 89, 90, 93, 68, 68, 68, 68, 72,
+ 68, 4, 69, 68, 70, 68, 68, 68,
+ 68, 68, 68, 68, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 68, 80, 81,
+ 82, 83, 68, 84, 85, 86, 68, 68,
+ 68, 68, 87, 88, 89, 90, 91, 68,
+ 68, 68, 68, 92, 68, 4, 98, 98,
+ 98, 98, 98, 98, 98, 98, 98, 98,
+ 98, 98, 99, 98, 4, 94, 94, 94,
+ 94, 94, 94, 94, 94, 94, 94, 94,
+ 94, 96, 94, 4, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 71, 68, 68, 68,
- 68, 68, 68, 68, 68, 73, 74, 75,
- 76, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 85, 86, 87, 68, 68,
- 68, 68, 68, 89, 90, 91, 94, 68,
- 102, 103, 101, 3, 104, 104, 104, 104,
- 104, 104, 104, 104, 104, 105, 104, 106,
- 107, 68, 71, 68, 68, 68, 68, 68,
- 68, 68, 108, 109, 110, 111, 112, 113,
- 114, 115, 116, 117, 118, 119, 120, 121,
- 68, 122, 123, 124, 68, 58, 59, 68,
- 125, 126, 127, 128, 129, 68, 68, 68,
- 68, 130, 68, 106, 107, 68, 71, 68,
- 68, 68, 68, 68, 68, 68, 108, 109,
- 110, 111, 112, 113, 114, 115, 116, 118,
- 118, 119, 120, 121, 68, 122, 123, 124,
- 68, 68, 68, 68, 125, 126, 127, 128,
- 129, 68, 68, 68, 68, 130, 68, 106,
+ 70, 68, 68, 68, 68, 68, 68, 68,
+ 68, 72, 73, 74, 75, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 84,
+ 85, 86, 68, 68, 68, 68, 68, 88,
+ 89, 90, 93, 68, 101, 102, 100, 6,
+ 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 104, 103, 105, 106, 68, 70, 68,
+ 68, 68, 68, 68, 68, 68, 107, 108,
+ 109, 110, 111, 112, 113, 114, 115, 105,
+ 116, 117, 118, 119, 68, 120, 121, 122,
+ 68, 58, 59, 68, 123, 124, 125, 126,
+ 127, 68, 68, 68, 68, 128, 68, 105,
+ 106, 68, 70, 68, 68, 68, 68, 68,
+ 68, 68, 107, 108, 109, 110, 111, 112,
+ 113, 114, 115, 105, 116, 117, 118, 119,
+ 68, 120, 121, 122, 68, 68, 68, 68,
+ 123, 124, 125, 126, 127, 68, 68, 68,
+ 68, 128, 68, 105, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 71, 68, 68, 68,
- 68, 68, 68, 68, 68, 109, 110, 111,
- 112, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 122, 123, 124, 68, 68,
- 68, 68, 68, 126, 127, 128, 131, 68,
- 68, 68, 68, 109, 68, 71, 68, 68,
- 68, 68, 68, 68, 68, 68, 109, 110,
- 111, 112, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 122, 123, 124, 68,
- 68, 68, 68, 68, 126, 127, 128, 131,
- 68, 71, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 110, 111, 112, 68, 68,
+ 70, 68, 68, 68, 68, 68, 68, 68,
+ 68, 108, 109, 110, 111, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 120,
+ 121, 122, 68, 68, 68, 68, 68, 124,
+ 125, 126, 129, 68, 68, 68, 68, 108,
+ 68, 70, 68, 68, 68, 68, 68, 68,
+ 68, 68, 108, 109, 110, 111, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 120, 121, 122, 68, 68, 68, 68, 68,
+ 124, 125, 126, 129, 68, 70, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 109,
+ 110, 111, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 124, 125, 126, 68,
+ 70, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 110, 111, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
- 126, 127, 128, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 124,
+ 125, 126, 68, 70, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 111,
- 112, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 126, 127, 128, 68, 71,
68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 112, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 126, 127,
- 128, 68, 71, 68, 68, 68, 68, 68,
+ 68, 68, 124, 125, 126, 68, 70, 68,
68, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
- 68, 126, 127, 68, 71, 68, 68, 68,
+ 68, 68, 68, 68, 68, 124, 125, 68,
+ 70, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 127, 68, 71, 68,
- 71, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 110, 111, 112, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 122,
- 123, 124, 68, 68, 68, 68, 68, 126,
- 127, 128, 131, 68, 71, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 110, 111,
- 112, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 123, 124, 68, 68,
- 68, 68, 68, 126, 127, 128, 131, 68,
- 71, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 110, 111, 112, 68, 68, 68,
+ 125, 68, 70, 68, 70, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 109, 110,
+ 111, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 120, 121, 122, 68, 68,
+ 68, 68, 68, 124, 125, 126, 129, 68,
+ 70, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 109, 110, 111, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
- 68, 124, 68, 68, 68, 68, 68, 126,
- 127, 128, 131, 68, 132, 95, 95, 95,
- 95, 95, 95, 95, 95, 95, 95, 95,
- 95, 97, 95, 71, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 110, 111, 112,
+ 121, 122, 68, 68, 68, 68, 68, 124,
+ 125, 126, 129, 68, 70, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 109, 110,
+ 111, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 122, 68, 68,
+ 68, 68, 68, 124, 125, 126, 129, 68,
+ 130, 94, 94, 94, 94, 94, 94, 94,
+ 94, 94, 94, 94, 94, 96, 94, 70,
68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 109, 110, 111, 68, 68, 68, 68,
68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 126, 127, 128, 131, 68, 71,
- 68, 68, 68, 68, 68, 68, 68, 108,
- 109, 110, 111, 112, 68, 68, 68, 68,
- 68, 68, 119, 120, 121, 68, 122, 123,
- 124, 68, 68, 68, 68, 68, 126, 127,
- 128, 131, 68, 68, 68, 68, 109, 68,
- 71, 68, 68, 68, 68, 68, 68, 68,
- 68, 109, 110, 111, 112, 68, 68, 68,
- 68, 68, 68, 119, 120, 121, 68, 122,
- 123, 124, 68, 68, 68, 68, 68, 126,
- 127, 128, 131, 68, 68, 68, 68, 109,
- 68, 71, 68, 68, 68, 68, 68, 68,
- 68, 68, 109, 110, 111, 112, 68, 68,
- 68, 68, 68, 68, 68, 120, 121, 68,
- 122, 123, 124, 68, 68, 68, 68, 68,
- 126, 127, 128, 131, 68, 68, 68, 68,
- 109, 68, 71, 68, 68, 68, 68, 68,
- 68, 68, 68, 109, 110, 111, 112, 68,
- 68, 68, 68, 68, 68, 68, 68, 121,
- 68, 122, 123, 124, 68, 68, 68, 68,
- 68, 126, 127, 128, 131, 68, 68, 68,
- 68, 109, 68, 133, 68, 71, 68, 68,
+ 68, 68, 68, 68, 68, 68, 124, 125,
+ 126, 129, 68, 70, 68, 68, 68, 68,
+ 68, 68, 68, 107, 108, 109, 110, 111,
+ 68, 68, 68, 68, 68, 68, 117, 118,
+ 119, 68, 120, 121, 122, 68, 68, 68,
+ 68, 68, 124, 125, 126, 129, 68, 68,
+ 68, 68, 108, 68, 70, 68, 68, 68,
68, 68, 68, 68, 68, 108, 109, 110,
- 111, 112, 68, 114, 115, 68, 68, 68,
- 119, 120, 121, 68, 122, 123, 124, 68,
- 68, 68, 68, 68, 126, 127, 128, 131,
- 68, 68, 68, 68, 109, 68, 71, 68,
- 68, 68, 68, 68, 68, 68, 68, 109,
- 110, 111, 112, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 122, 123, 124,
- 68, 68, 68, 68, 68, 126, 127, 128,
- 131, 68, 68, 68, 68, 109, 68, 133,
- 68, 71, 68, 68, 68, 68, 68, 68,
- 68, 108, 109, 110, 111, 112, 68, 68,
- 115, 68, 68, 68, 119, 120, 121, 68,
- 122, 123, 124, 68, 68, 68, 68, 68,
- 126, 127, 128, 131, 68, 68, 68, 68,
- 109, 68, 133, 68, 71, 68, 68, 68,
- 68, 68, 68, 68, 108, 109, 110, 111,
- 112, 68, 68, 68, 68, 68, 68, 119,
- 120, 121, 68, 122, 123, 124, 68, 68,
- 68, 68, 68, 126, 127, 128, 131, 68,
- 68, 68, 68, 109, 68, 133, 68, 71,
+ 111, 68, 68, 68, 68, 68, 68, 117,
+ 118, 119, 68, 120, 121, 122, 68, 68,
+ 68, 68, 68, 124, 125, 126, 129, 68,
+ 68, 68, 68, 108, 68, 70, 68, 68,
+ 68, 68, 68, 68, 68, 68, 108, 109,
+ 110, 111, 68, 68, 68, 68, 68, 68,
+ 68, 118, 119, 68, 120, 121, 122, 68,
+ 68, 68, 68, 68, 124, 125, 126, 129,
+ 68, 68, 68, 68, 108, 68, 70, 68,
68, 68, 68, 68, 68, 68, 68, 108,
- 109, 110, 111, 112, 113, 114, 115, 68,
- 68, 68, 119, 120, 121, 68, 122, 123,
- 124, 68, 68, 68, 68, 68, 126, 127,
- 128, 131, 68, 68, 68, 68, 109, 68,
- 106, 107, 68, 71, 68, 68, 68, 68,
- 68, 68, 68, 108, 109, 110, 111, 112,
- 113, 114, 115, 116, 68, 118, 119, 120,
- 121, 68, 122, 123, 124, 68, 68, 68,
- 68, 125, 126, 127, 128, 129, 68, 68,
- 68, 68, 130, 68, 106, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 100, 99, 106, 95, 95, 95, 95,
- 95, 95, 95, 95, 95, 95, 95, 95,
- 97, 95, 106, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 71,
+ 109, 110, 111, 68, 68, 68, 68, 68,
+ 68, 68, 68, 119, 68, 120, 121, 122,
+ 68, 68, 68, 68, 68, 124, 125, 126,
+ 129, 68, 68, 68, 68, 108, 68, 131,
+ 68, 70, 68, 68, 68, 68, 68, 68,
+ 68, 107, 108, 109, 110, 111, 68, 113,
+ 114, 68, 68, 68, 117, 118, 119, 68,
+ 120, 121, 122, 68, 68, 68, 68, 68,
+ 124, 125, 126, 129, 68, 68, 68, 68,
+ 108, 68, 70, 68, 68, 68, 68, 68,
+ 68, 68, 68, 108, 109, 110, 111, 68,
68, 68, 68, 68, 68, 68, 68, 68,
- 109, 110, 111, 112, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 122, 123,
- 124, 68, 68, 68, 68, 68, 126, 127,
- 128, 131, 68, 106, 107, 68, 71, 68,
- 68, 68, 68, 68, 68, 68, 108, 109,
- 110, 111, 112, 113, 114, 115, 116, 117,
- 118, 119, 120, 121, 68, 122, 123, 124,
- 68, 68, 68, 68, 125, 126, 127, 128,
- 129, 68, 68, 68, 68, 130, 68, 5,
- 6, 134, 8, 134, 134, 134, 134, 134,
- 134, 134, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 20, 20, 21, 22, 23,
- 134, 24, 25, 26, 134, 134, 134, 134,
- 30, 31, 32, 33, 30, 134, 134, 134,
- 134, 36, 134, 5, 134, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 8, 134, 134, 134, 134, 134, 134, 134,
- 134, 11, 12, 13, 14, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 134, 24,
- 25, 26, 134, 134, 134, 134, 134, 31,
- 32, 33, 135, 134, 134, 134, 134, 11,
- 134, 8, 134, 134, 134, 134, 134, 134,
- 134, 134, 11, 12, 13, 14, 134, 134,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 24, 25, 26, 134, 134, 134, 134, 134,
- 31, 32, 33, 135, 134, 8, 134, 134,
- 134, 134, 134, 134, 134, 134, 134, 12,
- 13, 14, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 134, 31, 32, 33, 134,
- 8, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 13, 14, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 134, 31,
- 32, 33, 134, 8, 134, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 134, 14,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 31, 32, 33, 134, 8, 134,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 134, 134, 31, 32, 134,
- 8, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 32, 134, 8, 134, 8, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 12, 13,
- 14, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 24, 25, 26, 134, 134,
- 134, 134, 134, 31, 32, 33, 135, 134,
- 8, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 12, 13, 14, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 25, 26, 134, 134, 134, 134, 134, 31,
- 32, 33, 135, 134, 8, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 12, 13,
- 14, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 134, 134, 26, 134, 134,
- 134, 134, 134, 31, 32, 33, 135, 134,
- 136, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 134, 134, 8, 134, 8,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 134, 12, 13, 14, 134, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 31, 32,
- 33, 135, 134, 8, 134, 134, 134, 134,
- 134, 134, 134, 10, 11, 12, 13, 14,
- 134, 134, 134, 134, 134, 134, 21, 22,
- 23, 134, 24, 25, 26, 134, 134, 134,
- 134, 134, 31, 32, 33, 135, 134, 134,
- 134, 134, 11, 134, 8, 134, 134, 134,
- 134, 134, 134, 134, 134, 11, 12, 13,
- 14, 134, 134, 134, 134, 134, 134, 21,
- 22, 23, 134, 24, 25, 26, 134, 134,
- 134, 134, 134, 31, 32, 33, 135, 134,
- 134, 134, 134, 11, 134, 8, 134, 134,
- 134, 134, 134, 134, 134, 134, 11, 12,
- 13, 14, 134, 134, 134, 134, 134, 134,
- 134, 22, 23, 134, 24, 25, 26, 134,
- 134, 134, 134, 134, 31, 32, 33, 135,
- 134, 134, 134, 134, 11, 134, 8, 134,
- 134, 134, 134, 134, 134, 134, 134, 11,
- 12, 13, 14, 134, 134, 134, 134, 134,
- 134, 134, 134, 23, 134, 24, 25, 26,
- 134, 134, 134, 134, 134, 31, 32, 33,
- 135, 134, 134, 134, 134, 11, 134, 137,
- 134, 8, 134, 134, 134, 134, 134, 134,
- 134, 10, 11, 12, 13, 14, 134, 16,
- 17, 134, 134, 134, 21, 22, 23, 134,
- 24, 25, 26, 134, 134, 134, 134, 134,
- 31, 32, 33, 135, 134, 134, 134, 134,
- 11, 134, 8, 134, 134, 134, 134, 134,
- 134, 134, 134, 11, 12, 13, 14, 134,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 134, 24, 25, 26, 134, 134, 134, 134,
- 134, 31, 32, 33, 135, 134, 134, 134,
- 134, 11, 134, 137, 134, 8, 134, 134,
- 134, 134, 134, 134, 134, 10, 11, 12,
- 13, 14, 134, 134, 17, 134, 134, 134,
- 21, 22, 23, 134, 24, 25, 26, 134,
- 134, 134, 134, 134, 31, 32, 33, 135,
- 134, 134, 134, 134, 11, 134, 137, 134,
- 8, 134, 134, 134, 134, 134, 134, 134,
- 10, 11, 12, 13, 14, 134, 134, 134,
- 134, 134, 134, 21, 22, 23, 134, 24,
- 25, 26, 134, 134, 134, 134, 134, 31,
- 32, 33, 135, 134, 134, 134, 134, 11,
- 134, 137, 134, 8, 134, 134, 134, 134,
- 134, 134, 134, 10, 11, 12, 13, 14,
- 15, 16, 17, 134, 134, 134, 21, 22,
- 23, 134, 24, 25, 26, 134, 134, 134,
- 134, 134, 31, 32, 33, 135, 134, 134,
- 134, 134, 11, 134, 5, 6, 134, 8,
- 134, 134, 134, 134, 134, 134, 134, 10,
- 11, 12, 13, 14, 15, 16, 17, 18,
- 134, 20, 21, 22, 23, 134, 24, 25,
- 26, 134, 134, 134, 134, 30, 31, 32,
- 33, 30, 134, 134, 134, 134, 36, 134,
- 5, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 134, 134, 8, 134, 5,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 134, 8, 134, 134, 134,
- 134, 134, 134, 134, 134, 11, 12, 13,
- 14, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 24, 25, 26, 134, 134,
- 134, 134, 134, 31, 32, 33, 135, 134,
- 138, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 8, 134, 7, 8, 134, 1,
- 134, 134, 134, 1, 134, 134, 134, 134,
- 134, 5, 6, 7, 8, 134, 134, 134,
- 134, 134, 134, 134, 10, 11, 12, 13,
+ 68, 120, 121, 122, 68, 68, 68, 68,
+ 68, 124, 125, 126, 129, 68, 68, 68,
+ 68, 108, 68, 131, 68, 70, 68, 68,
+ 68, 68, 68, 68, 68, 107, 108, 109,
+ 110, 111, 68, 68, 114, 68, 68, 68,
+ 117, 118, 119, 68, 120, 121, 122, 68,
+ 68, 68, 68, 68, 124, 125, 126, 129,
+ 68, 68, 68, 68, 108, 68, 131, 68,
+ 70, 68, 68, 68, 68, 68, 68, 68,
+ 107, 108, 109, 110, 111, 68, 68, 68,
+ 68, 68, 68, 117, 118, 119, 68, 120,
+ 121, 122, 68, 68, 68, 68, 68, 124,
+ 125, 126, 129, 68, 68, 68, 68, 108,
+ 68, 131, 68, 70, 68, 68, 68, 68,
+ 68, 68, 68, 107, 108, 109, 110, 111,
+ 112, 113, 114, 68, 68, 68, 117, 118,
+ 119, 68, 120, 121, 122, 68, 68, 68,
+ 68, 68, 124, 125, 126, 129, 68, 68,
+ 68, 68, 108, 68, 105, 106, 68, 70,
+ 68, 68, 68, 68, 68, 68, 68, 107,
+ 108, 109, 110, 111, 112, 113, 114, 115,
+ 68, 116, 117, 118, 119, 68, 120, 121,
+ 122, 68, 68, 68, 68, 123, 124, 125,
+ 126, 127, 68, 68, 68, 68, 128, 68,
+ 105, 98, 98, 98, 98, 98, 98, 98,
+ 98, 98, 98, 98, 98, 99, 98, 105,
+ 94, 94, 94, 94, 94, 94, 94, 94,
+ 94, 94, 94, 94, 96, 94, 105, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 70, 68, 68, 68, 68,
+ 68, 68, 68, 68, 108, 109, 110, 111,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 120, 121, 122, 68, 68, 68,
+ 68, 68, 124, 125, 126, 129, 68, 8,
+ 9, 132, 11, 132, 132, 132, 132, 132,
+ 132, 132, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 8, 22, 23, 24, 25,
+ 132, 26, 27, 28, 132, 132, 132, 132,
+ 32, 33, 34, 35, 32, 132, 132, 132,
+ 132, 37, 132, 8, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 11, 132, 132, 132, 132, 132, 132, 132,
+ 132, 14, 15, 16, 17, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 26,
+ 27, 28, 132, 132, 132, 132, 132, 33,
+ 34, 35, 133, 132, 132, 132, 132, 14,
+ 132, 11, 132, 132, 132, 132, 132, 132,
+ 132, 132, 14, 15, 16, 17, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 26, 27, 28, 132, 132, 132, 132, 132,
+ 33, 34, 35, 133, 132, 11, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 15,
+ 16, 17, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 33, 34, 35, 132,
+ 11, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 16, 17, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 33,
+ 34, 35, 132, 11, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 17,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 33, 34, 35, 132, 11, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 33, 34, 132,
+ 11, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 34, 132, 11, 132, 11, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 15, 16,
+ 17, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 26, 27, 28, 132, 132,
+ 132, 132, 132, 33, 34, 35, 133, 132,
+ 11, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 15, 16, 17, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 27, 28, 132, 132, 132, 132, 132, 33,
+ 34, 35, 133, 132, 11, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 15, 16,
+ 17, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 28, 132, 132,
+ 132, 132, 132, 33, 34, 35, 133, 132,
+ 134, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 11, 132, 11,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 132, 15, 16, 17, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 33, 34,
+ 35, 133, 132, 11, 132, 132, 132, 132,
+ 132, 132, 132, 13, 14, 15, 16, 17,
+ 132, 132, 132, 132, 132, 132, 23, 24,
+ 25, 132, 26, 27, 28, 132, 132, 132,
+ 132, 132, 33, 34, 35, 133, 132, 132,
+ 132, 132, 14, 132, 11, 132, 132, 132,
+ 132, 132, 132, 132, 132, 14, 15, 16,
+ 17, 132, 132, 132, 132, 132, 132, 23,
+ 24, 25, 132, 26, 27, 28, 132, 132,
+ 132, 132, 132, 33, 34, 35, 133, 132,
+ 132, 132, 132, 14, 132, 11, 132, 132,
+ 132, 132, 132, 132, 132, 132, 14, 15,
+ 16, 17, 132, 132, 132, 132, 132, 132,
+ 132, 24, 25, 132, 26, 27, 28, 132,
+ 132, 132, 132, 132, 33, 34, 35, 133,
+ 132, 132, 132, 132, 14, 132, 11, 132,
+ 132, 132, 132, 132, 132, 132, 132, 14,
+ 15, 16, 17, 132, 132, 132, 132, 132,
+ 132, 132, 132, 25, 132, 26, 27, 28,
+ 132, 132, 132, 132, 132, 33, 34, 35,
+ 133, 132, 132, 132, 132, 14, 132, 135,
+ 132, 11, 132, 132, 132, 132, 132, 132,
+ 132, 13, 14, 15, 16, 17, 132, 19,
+ 20, 132, 132, 132, 23, 24, 25, 132,
+ 26, 27, 28, 132, 132, 132, 132, 132,
+ 33, 34, 35, 133, 132, 132, 132, 132,
+ 14, 132, 11, 132, 132, 132, 132, 132,
+ 132, 132, 132, 14, 15, 16, 17, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 132, 26, 27, 28, 132, 132, 132, 132,
+ 132, 33, 34, 35, 133, 132, 132, 132,
+ 132, 14, 132, 135, 132, 11, 132, 132,
+ 132, 132, 132, 132, 132, 13, 14, 15,
+ 16, 17, 132, 132, 20, 132, 132, 132,
+ 23, 24, 25, 132, 26, 27, 28, 132,
+ 132, 132, 132, 132, 33, 34, 35, 133,
+ 132, 132, 132, 132, 14, 132, 135, 132,
+ 11, 132, 132, 132, 132, 132, 132, 132,
+ 13, 14, 15, 16, 17, 132, 132, 132,
+ 132, 132, 132, 23, 24, 25, 132, 26,
+ 27, 28, 132, 132, 132, 132, 132, 33,
+ 34, 35, 133, 132, 132, 132, 132, 14,
+ 132, 135, 132, 11, 132, 132, 132, 132,
+ 132, 132, 132, 13, 14, 15, 16, 17,
+ 18, 19, 20, 132, 132, 132, 23, 24,
+ 25, 132, 26, 27, 28, 132, 132, 132,
+ 132, 132, 33, 34, 35, 133, 132, 132,
+ 132, 132, 14, 132, 8, 9, 132, 11,
+ 132, 132, 132, 132, 132, 132, 132, 13,
14, 15, 16, 17, 18, 19, 20, 21,
- 22, 23, 134, 24, 25, 26, 134, 27,
- 28, 134, 30, 31, 32, 33, 30, 134,
- 134, 134, 134, 36, 134, 5, 6, 134,
- 8, 134, 134, 134, 134, 134, 134, 134,
- 10, 11, 12, 13, 14, 15, 16, 17,
- 18, 19, 20, 21, 22, 23, 134, 24,
- 25, 26, 134, 134, 134, 134, 30, 31,
- 32, 33, 30, 134, 134, 134, 134, 36,
- 134, 8, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 134, 27, 28, 134, 8,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 134, 134, 134, 134, 134,
- 134, 134, 134, 28, 134, 1, 139, 139,
- 139, 1, 139, 141, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 142,
- 140, 34, 140, 141, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 34, 142,
- 140, 142, 140, 141, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 34, 140,
- 35, 140, 0
+ 132, 22, 23, 24, 25, 132, 26, 27,
+ 28, 132, 132, 132, 132, 32, 33, 34,
+ 35, 32, 132, 132, 132, 132, 37, 132,
+ 8, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 11, 132, 8,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 11, 132, 132, 132,
+ 132, 132, 132, 132, 132, 14, 15, 16,
+ 17, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 26, 27, 28, 132, 132,
+ 132, 132, 132, 33, 34, 35, 133, 132,
+ 136, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 11, 132, 10, 11, 132, 4,
+ 132, 132, 132, 4, 132, 132, 132, 132,
+ 132, 8, 9, 10, 11, 132, 132, 132,
+ 132, 132, 132, 132, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 8, 22, 23,
+ 24, 25, 132, 26, 27, 28, 132, 29,
+ 30, 132, 32, 33, 34, 35, 32, 132,
+ 132, 132, 132, 37, 132, 11, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 29, 30, 132, 11, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 132,
+ 132, 132, 132, 132, 132, 132, 132, 30,
+ 132, 4, 137, 137, 137, 4, 137, 139,
+ 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 140, 138, 141, 138, 141,
+ 142, 138, 139, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 1, 140, 140,
+ 138, 139, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 140, 138, 141,
+ 138, 139, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 140, 138, 141,
+ 138, 141, 138, 39, 40, 38, 41, 38,
+ 38, 38, 38, 38, 38, 38, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 39,
+ 51, 52, 53, 54, 38, 55, 56, 57,
+ 38, 58, 59, 38, 60, 61, 62, 63,
+ 60, 1, 38, 2, 38, 64, 38, 0
};
static const char _use_syllable_machine_trans_targs[] = {
- 1, 31, 0, 59, 61, 90, 91, 116,
- 0, 118, 104, 92, 93, 94, 95, 108,
- 110, 111, 112, 119, 113, 105, 106, 107,
- 99, 100, 101, 120, 121, 122, 114, 96,
- 97, 98, 123, 125, 115, 0, 2, 3,
- 0, 16, 4, 5, 6, 7, 20, 22,
- 23, 24, 28, 25, 17, 18, 19, 11,
- 12, 13, 29, 30, 26, 8, 9, 10,
- 27, 14, 15, 21, 0, 32, 33, 0,
- 46, 34, 35, 36, 37, 50, 52, 53,
- 54, 55, 47, 48, 49, 41, 42, 43,
- 56, 38, 39, 40, 57, 58, 44, 0,
- 45, 0, 51, 0, 0, 0, 60, 0,
- 0, 0, 62, 63, 76, 64, 65, 66,
- 67, 80, 82, 83, 84, 89, 85, 77,
- 78, 79, 71, 72, 73, 86, 68, 69,
- 70, 87, 88, 74, 75, 81, 0, 102,
- 103, 109, 117, 0, 0, 0, 124
+ 1, 120, 0, 2, 31, 1, 58, 60,
+ 88, 89, 114, 1, 116, 102, 90, 91,
+ 92, 93, 106, 108, 109, 110, 111, 103,
+ 104, 105, 97, 98, 99, 117, 118, 119,
+ 112, 94, 95, 96, 124, 113, 1, 3,
+ 4, 1, 17, 5, 6, 7, 8, 21,
+ 23, 24, 25, 26, 18, 19, 20, 12,
+ 13, 14, 29, 30, 27, 9, 10, 11,
+ 28, 15, 16, 22, 1, 32, 1, 45,
+ 33, 34, 35, 36, 49, 51, 52, 53,
+ 54, 46, 47, 48, 40, 41, 42, 55,
+ 37, 38, 39, 56, 57, 43, 1, 44,
+ 1, 50, 1, 1, 1, 59, 1, 1,
+ 1, 61, 62, 75, 63, 64, 65, 66,
+ 79, 81, 82, 83, 84, 76, 77, 78,
+ 70, 71, 72, 85, 67, 68, 69, 86,
+ 87, 73, 74, 80, 1, 100, 101, 107,
+ 115, 1, 1, 1, 121, 122, 123
};
static const char _use_syllable_machine_trans_actions[] = {
- 0, 0, 3, 0, 0, 0, 0, 0,
- 4, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 4, 0, 0,
+ 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, 0, 0, 0, 0, 5, 0, 0,
- 6, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 6, 0, 7, 0,
+ 0, 8, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 7, 0, 0, 8,
+ 0, 0, 0, 0, 9, 0, 10, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 9,
- 0, 10, 0, 11, 12, 13, 0, 14,
- 15, 16, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 11, 0,
+ 12, 0, 13, 14, 15, 0, 16, 17,
+ 18, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 17, 0,
- 0, 0, 0, 18, 19, 20, 0
+ 0, 0, 0, 0, 19, 0, 0, 0,
+ 0, 20, 21, 22, 0, 0, 0
};
static const char _use_syllable_machine_to_state_actions[] = {
- 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 2, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -778,11 +769,11 @@ static const char _use_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, 0
};
static const char _use_syllable_machine_from_state_actions[] = {
- 2, 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,
@@ -797,40 +788,40 @@ static const char _use_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, 0
};
static const short _use_syllable_machine_eof_trans[] = {
- 0, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 69,
- 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 96, 69, 69, 69,
+ 1, 0, 39, 39, 39, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 69,
69, 69, 69, 69, 69, 69, 69, 69,
- 100, 96, 69, 102, 105, 69, 69, 69,
+ 69, 69, 69, 95, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 99,
+ 95, 69, 101, 104, 69, 69, 69, 69,
69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 96, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 100, 96,
- 69, 69, 135, 135, 135, 135, 135, 135,
- 135, 135, 135, 135, 135, 135, 135, 135,
- 135, 135, 135, 135, 135, 135, 135, 135,
- 135, 135, 135, 135, 135, 135, 135, 135,
- 135, 135, 140, 141, 141, 141
+ 69, 95, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 99, 95, 69,
+ 133, 133, 133, 133, 133, 133, 133, 133,
+ 133, 133, 133, 133, 133, 133, 133, 133,
+ 133, 133, 133, 133, 133, 133, 133, 133,
+ 133, 133, 133, 133, 133, 133, 133, 138,
+ 139, 139, 139, 139, 39
};
-static const int use_syllable_machine_start = 0;
-static const int use_syllable_machine_first_final = 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 = 0;
+static const int use_syllable_machine_en_main = 1;
#line 58 "hb-ot-shaper-use-machine.rl"
-#line 182 "hb-ot-shaper-use-machine.rl"
+#line 184 "hb-ot-shaper-use-machine.rl"
#define found_syllable(syllable_type) \
@@ -929,7 +920,7 @@ find_syllables_use (hb_buffer_t *buffer)
unsigned int act HB_UNUSED;
int cs;
-#line 922 "hb-ot-shaper-use-machine.hh"
+#line 924 "hb-ot-shaper-use-machine.hh"
{
cs = use_syllable_machine_start;
ts = 0;
@@ -937,12 +928,12 @@ find_syllables_use (hb_buffer_t *buffer)
act = 0;
}
-#line 282 "hb-ot-shaper-use-machine.rl"
+#line 284 "hb-ot-shaper-use-machine.rl"
unsigned int syllable_serial = 1;
-#line 931 "hb-ot-shaper-use-machine.hh"
+#line 937 "hb-ot-shaper-use-machine.hh"
{
int _slen;
int _trans;
@@ -952,11 +943,11 @@ find_syllables_use (hb_buffer_t *buffer)
goto _test_eof;
_resume:
switch ( _use_syllable_machine_from_state_actions[cs] ) {
- case 2:
+ case 3:
#line 1 "NONE"
{ts = p;}
break;
-#line 943 "hb-ot-shaper-use-machine.hh"
+#line 951 "hb-ot-shaper-use-machine.hh"
}
_keys = _use_syllable_machine_trans_keys + (cs<<1);
@@ -974,88 +965,96 @@ _eof_trans:
goto _again;
switch ( _use_syllable_machine_trans_actions[_trans] ) {
- case 12:
-#line 170 "hb-ot-shaper-use-machine.rl"
+ case 6:
+#line 1 "NONE"
+ {te = p+1;}
+ break;
+ case 14:
+#line 172 "hb-ot-shaper-use-machine.rl"
{te = p+1;{ found_syllable (use_virama_terminated_cluster); }}
break;
- case 10:
-#line 171 "hb-ot-shaper-use-machine.rl"
+ case 12:
+#line 173 "hb-ot-shaper-use-machine.rl"
{te = p+1;{ found_syllable (use_sakot_terminated_cluster); }}
break;
- case 8:
-#line 172 "hb-ot-shaper-use-machine.rl"
+ case 10:
+#line 174 "hb-ot-shaper-use-machine.rl"
{te = p+1;{ found_syllable (use_standard_cluster); }}
break;
- case 16:
-#line 173 "hb-ot-shaper-use-machine.rl"
+ case 18:
+#line 175 "hb-ot-shaper-use-machine.rl"
{te = p+1;{ found_syllable (use_number_joiner_terminated_cluster); }}
break;
- case 14:
-#line 174 "hb-ot-shaper-use-machine.rl"
+ case 16:
+#line 176 "hb-ot-shaper-use-machine.rl"
{te = p+1;{ found_syllable (use_numeral_cluster); }}
break;
- case 6:
-#line 175 "hb-ot-shaper-use-machine.rl"
+ case 8:
+#line 177 "hb-ot-shaper-use-machine.rl"
{te = p+1;{ found_syllable (use_symbol_cluster); }}
break;
- case 20:
-#line 176 "hb-ot-shaper-use-machine.rl"
+ case 22:
+#line 178 "hb-ot-shaper-use-machine.rl"
{te = p+1;{ found_syllable (use_hieroglyph_cluster); }}
break;
- case 4:
-#line 177 "hb-ot-shaper-use-machine.rl"
+ case 5:
+#line 179 "hb-ot-shaper-use-machine.rl"
{te = p+1;{ found_syllable (use_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
break;
- case 3:
-#line 178 "hb-ot-shaper-use-machine.rl"
+ case 4:
+#line 180 "hb-ot-shaper-use-machine.rl"
{te = p+1;{ found_syllable (use_non_cluster); }}
break;
- case 11:
-#line 170 "hb-ot-shaper-use-machine.rl"
+ case 13:
+#line 172 "hb-ot-shaper-use-machine.rl"
{te = p;p--;{ found_syllable (use_virama_terminated_cluster); }}
break;
- case 9:
-#line 171 "hb-ot-shaper-use-machine.rl"
+ case 11:
+#line 173 "hb-ot-shaper-use-machine.rl"
{te = p;p--;{ found_syllable (use_sakot_terminated_cluster); }}
break;
- case 7:
-#line 172 "hb-ot-shaper-use-machine.rl"
+ case 9:
+#line 174 "hb-ot-shaper-use-machine.rl"
{te = p;p--;{ found_syllable (use_standard_cluster); }}
break;
- case 15:
-#line 173 "hb-ot-shaper-use-machine.rl"
+ case 17:
+#line 175 "hb-ot-shaper-use-machine.rl"
{te = p;p--;{ found_syllable (use_number_joiner_terminated_cluster); }}
break;
- case 13:
-#line 174 "hb-ot-shaper-use-machine.rl"
+ case 15:
+#line 176 "hb-ot-shaper-use-machine.rl"
{te = p;p--;{ found_syllable (use_numeral_cluster); }}
break;
- case 5:
-#line 175 "hb-ot-shaper-use-machine.rl"
+ case 7:
+#line 177 "hb-ot-shaper-use-machine.rl"
{te = p;p--;{ found_syllable (use_symbol_cluster); }}
break;
- case 19:
-#line 176 "hb-ot-shaper-use-machine.rl"
+ case 21:
+#line 178 "hb-ot-shaper-use-machine.rl"
{te = p;p--;{ found_syllable (use_hieroglyph_cluster); }}
break;
- case 17:
-#line 177 "hb-ot-shaper-use-machine.rl"
+ case 19:
+#line 179 "hb-ot-shaper-use-machine.rl"
{te = p;p--;{ found_syllable (use_broken_cluster); buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_BROKEN_SYLLABLE; }}
break;
- case 18:
-#line 178 "hb-ot-shaper-use-machine.rl"
+ case 20:
+#line 180 "hb-ot-shaper-use-machine.rl"
{te = p;p--;{ found_syllable (use_non_cluster); }}
break;
-#line 1014 "hb-ot-shaper-use-machine.hh"
+ case 1:
+#line 177 "hb-ot-shaper-use-machine.rl"
+ {{p = ((te))-1;}{ found_syllable (use_symbol_cluster); }}
+ break;
+#line 1049 "hb-ot-shaper-use-machine.hh"
}
_again:
switch ( _use_syllable_machine_to_state_actions[cs] ) {
- case 1:
+ case 2:
#line 1 "NONE"
{ts = 0;}
break;
-#line 1021 "hb-ot-shaper-use-machine.hh"
+#line 1058 "hb-ot-shaper-use-machine.hh"
}
if ( ++p != pe )
@@ -1071,7 +1070,7 @@ _again:
}
-#line 287 "hb-ot-shaper-use-machine.rl"
+#line 289 "hb-ot-shaper-use-machine.rl"
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use-table.hh
index 6b6b552ee5..d581b65c07 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use-table.hh
@@ -6,18 +6,18 @@
*
* on files with these headers:
*
- * # IndicSyllabicCategory-15.0.0.txt
- * # Date: 2022-05-26, 02:18:00 GMT [KW, RP]
- * # IndicPositionalCategory-15.0.0.txt
- * # Date: 2022-05-26, 02:18:00 GMT [KW, RP]
- * # ArabicShaping-15.0.0.txt
- * # Date: 2022-02-14, 18:50:00 GMT [KW, RP]
- * # DerivedCoreProperties-15.0.0.txt
- * # Date: 2022-08-05, 22:17:05 GMT
- * # Blocks-15.0.0.txt
- * # Date: 2022-01-28, 20:58:00 GMT [KW]
- * # Scripts-15.0.0.txt
- * # Date: 2022-04-26, 23:15:02 GMT
+ * # IndicSyllabicCategory-15.1.0.txt
+ * # Date: 2023-01-05
+ * # IndicPositionalCategory-15.1.0.txt
+ * # Date: 2023-01-05
+ * # ArabicShaping-15.1.0.txt
+ * # Date: 2023-01-05
+ * # DerivedCoreProperties-15.1.0.txt
+ * # Date: 2023-08-07, 15:21:24 GMT
+ * # Blocks-15.1.0.txt
+ * # Date: 2023-07-28, 15:47:20 GMT
+ * # Scripts-15.1.0.txt
+ * # Date: 2023-07-28, 16:01:07 GMT
* # Override values For Indic_Syllabic_Category
* # Not derivable
* # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17
@@ -26,6 +26,7 @@
* # Updated for Unicode 13.0 by Andrew Glass 2020-07-28
* # Updated for Unicode 14.0 by Andrew Glass 2021-09-25
* # Updated for Unicode 15.0 by Andrew Glass 2022-09-16
+ * # Updated for Unicode 15.1 by Andrew Glass 2023-09-14
* # Override values For Indic_Positional_Category
* # Not derivable
* # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17
@@ -36,6 +37,7 @@
* # Updated for Unicode 13.0 by Andrew Glass 2020-07-28
* # Updated for Unicode 14.0 by Andrew Glass 2021-09-28
* # Updated for Unicode 15.0 by Andrew Glass 2022-09-16
+ * # Updated for Unicode 15.1 by Andrew Glass 2023-09-14
* UnicodeData.txt does not have a header.
*/
@@ -54,7 +56,9 @@
#define G USE(G) /* HIEROGLYPH */
#define GB USE(GB) /* BASE_OTHER */
#define H USE(H) /* HALANT */
+#define HM USE(HM) /* HIEROGLYPH_MOD */
#define HN USE(HN) /* HALANT_NUM */
+#define HR USE(HR) /* HIEROGLYPH_MIRROR */
#define HVM USE(HVM) /* HALANT_OR_VOWEL_MODIFIER */
#define IS USE(IS) /* INVISIBLE_STACKER */
#define J USE(J) /* HIEROGLYPH_JOINER */
@@ -95,7 +99,7 @@
#ifndef HB_OPTIMIZE_SIZE
static const uint8_t
-hb_use_u8[3141] =
+hb_use_u8[3187] =
{
16, 50, 51, 51, 51, 52, 51, 83, 118, 131, 51, 57, 58, 179, 195, 61,
51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
@@ -109,244 +113,249 @@ hb_use_u8[3141] =
18, 19, 20, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 2, 33, 2, 2, 2,
2, 34, 35, 2, 2, 2, 2, 2, 2, 2, 2, 2, 36, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 37, 2, 2, 2, 2,
+ 37, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 38, 2, 39, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 38, 39, 40, 41, 42, 43, 2, 44, 2, 2, 2, 2, 2, 2, 2,
+ 2, 40, 41, 42, 43, 44, 45, 2, 46, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 45, 46, 2,
- 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 48, 49, 2, 2, 2,
- 2, 2, 2, 2, 2, 50, 51, 2, 52, 2, 2, 53, 2, 2, 54, 55,
- 56, 57, 58, 59, 60, 61, 62, 63, 2, 64, 65, 2, 66, 67, 68, 69,
- 2, 70, 2, 71, 72, 73, 74, 2, 2, 75, 76, 77, 78, 2, 79, 80,
- 2, 81, 81, 81, 81, 81, 81, 81, 81, 82, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 47, 48, 2,
+ 49, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 50, 51, 2, 2, 2,
+ 2, 2, 2, 2, 2, 52, 53, 2, 54, 2, 2, 55, 2, 2, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 65, 2, 66, 67, 2, 68, 69, 70, 71,
+ 2, 72, 2, 73, 74, 75, 76, 2, 2, 77, 78, 79, 80, 2, 81, 82,
+ 2, 83, 83, 83, 83, 83, 83, 83, 83, 84, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 83, 84, 2, 2, 2, 2, 2, 2, 2, 85,
- 86, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 81, 81, 81, 87, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 85, 86, 2, 2, 2, 2, 2, 2, 2, 87,
+ 88, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 89, 89, 89, 90, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 88, 89, 2, 2, 2, 2, 2,
- 2, 2, 2, 90, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 91, 92, 2, 2, 2, 2, 2,
+ 2, 2, 2, 93, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 91, 2, 2, 92, 2, 2, 2, 93, 2, 2, 2, 2, 2,
- 2, 2, 2, 94, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 95, 95, 96, 97, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
- 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
- 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
- 0, 2, 2, 2, 2, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4,
- 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 8, 9, 9, 9, 9, 0, 0, 0, 7, 10,
- 0, 2, 2, 2, 2, 11, 12, 0, 0, 9, 13, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 14, 15, 16, 17, 18, 19, 20, 14, 21, 22,
- 23, 10, 24, 25, 18, 2, 2, 2, 2, 2, 18, 0, 2, 2, 2, 2,
- 2, 0, 2, 2, 2, 2, 2, 2, 2, 26, 27, 28, 2, 2, 2, 7,
- 28, 7, 28, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 2, 2,
- 2, 7, 7, 0, 2, 2, 0, 15, 16, 17, 18, 29, 30, 31, 30, 32,
- 0, 0, 0, 0, 33, 0, 0, 2, 28, 2, 0, 0, 0, 0, 0, 7,
- 34, 10, 13, 28, 2, 2, 7, 0, 28, 7, 2, 28, 7, 2, 0, 35,
- 16, 17, 29, 0, 25, 36, 25, 37, 0, 38, 0, 0, 0, 28, 2, 7,
- 7, 0, 0, 0, 2, 2, 2, 2, 2, 39, 40, 41, 0, 0, 0, 0,
- 0, 10, 13, 28, 2, 2, 2, 2, 28, 2, 28, 2, 2, 2, 2, 2,
- 2, 7, 2, 28, 2, 2, 0, 15, 16, 17, 18, 19, 25, 20, 33, 22,
- 0, 0, 0, 0, 0, 28, 39, 39, 42, 10, 27, 28, 2, 2, 2, 7,
- 28, 7, 2, 28, 2, 2, 0, 15, 43, 0, 0, 25, 20, 0, 0, 2,
- 28, 28, 0, 0, 0, 0, 0, 0, 0, 0, 44, 28, 2, 2, 7, 0,
- 2, 7, 2, 2, 0, 28, 7, 7, 2, 0, 28, 7, 0, 2, 7, 0,
- 2, 2, 2, 2, 2, 2, 0, 0, 21, 14, 45, 0, 46, 31, 46, 32,
- 0, 0, 0, 0, 33, 0, 0, 0, 0, 13, 27, 47, 2, 2, 2, 7,
- 2, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 15,
- 20, 14, 21, 45, 20, 36, 20, 37, 0, 0, 0, 25, 29, 2, 7, 0,
- 0, 8, 27, 28, 2, 2, 2, 7, 2, 2, 2, 28, 2, 2, 0, 15,
- 43, 0, 0, 33, 45, 0, 0, 0, 7, 48, 49, 0, 0, 0, 0, 0,
- 0, 9, 27, 2, 2, 2, 2, 7, 2, 2, 2, 2, 2, 2, 50, 51,
- 21, 21, 17, 29, 46, 31, 46, 32, 52, 0, 0, 0, 33, 0, 0, 0,
- 28, 10, 27, 28, 2, 2, 2, 2, 2, 2, 2, 2, 7, 0, 2, 2,
- 2, 2, 28, 2, 2, 2, 2, 28, 0, 2, 2, 2, 7, 0, 53, 0,
- 33, 21, 20, 29, 29, 16, 46, 46, 23, 0, 21, 0, 0, 0, 0, 0,
- 0, 2, 0, 2, 7, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0,
- 0, 2, 2, 54, 54, 55, 0, 0, 16, 2, 2, 2, 2, 28, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 7, 0, 56, 19, 57, 20, 20, 18, 18,
- 44, 19, 9, 29, 9, 2, 2, 58, 59, 59, 59, 59, 59, 60, 59, 59,
- 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61,
- 0, 0, 0, 0, 62, 0, 0, 0, 0, 2, 2, 2, 2, 2, 63, 43,
- 57, 64, 20, 20, 65, 66, 67, 68, 69, 2, 2, 2, 2, 2, 1, 0,
- 3, 2, 2, 2, 21, 18, 2, 2, 70, 69, 71, 72, 63, 71, 27, 27,
- 2, 50, 20, 51, 2, 2, 2, 2, 2, 2, 73, 74, 75, 27, 27, 76,
- 77, 2, 2, 2, 2, 2, 27, 43, 0, 2, 57, 78, 0, 0, 0, 0,
- 28, 2, 57, 45, 0, 0, 0, 0, 0, 2, 57, 0, 0, 0, 0, 0,
- 0, 2, 2, 2, 2, 2, 2, 7, 2, 7, 57, 0, 0, 0, 0, 0,
- 0, 2, 2, 79, 43, 20, 57, 18, 46, 46, 46, 46, 13, 80, 81, 82,
- 83, 84, 85, 0, 0, 0, 0, 86, 0, 7, 0, 0, 28, 0, 87, 79,
- 88, 2, 2, 2, 2, 7, 0, 0, 0, 40, 40, 89, 90, 2, 2, 2,
- 2, 2, 2, 2, 2, 11, 7, 0, 0, 91, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 7, 20, 78, 43, 20, 92, 59, 0,
- 0, 93, 94, 93, 93, 95, 96, 0, 0, 2, 2, 2, 2, 2, 2, 2,
- 0, 2, 2, 7, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0,
- 0, 2, 2, 2, 2, 27, 0, 0, 0, 2, 2, 2, 2, 2, 7, 0,
- 0, 2, 2, 2, 50, 97, 43, 0, 0, 2, 2, 98, 99, 100, 101, 59,
- 61, 102, 14, 43, 20, 57, 19, 78, 46, 46, 74, 9, 9, 9, 103, 44,
- 38, 9, 104, 72, 2, 2, 2, 2, 2, 2, 2, 105, 20, 18, 18, 20,
- 46, 46, 20, 106, 2, 2, 2, 7, 0, 0, 0, 0, 0, 0, 107, 108,
- 109, 109, 109, 0, 0, 0, 0, 0, 0, 104, 72, 2, 2, 2, 2, 2,
- 2, 58, 59, 57, 23, 20, 110, 59, 2, 2, 2, 2, 105, 20, 21, 43,
- 43, 100, 12, 0, 0, 0, 0, 0, 0, 2, 2, 59, 16, 46, 21, 111,
- 100, 100, 100, 112, 113, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 28,
- 2, 9, 44, 114, 114, 114, 9, 114, 114, 13, 114, 114, 114, 24, 0, 38,
- 0, 0, 0, 115, 49, 9, 3, 0, 0, 0, 0, 0, 0, 0, 116, 0,
- 0, 0, 0, 0, 0, 0, 4, 117, 118, 40, 40, 3, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 118, 118, 119, 118, 118, 118, 118, 118, 118, 118,
- 118, 0, 0, 120, 0, 0, 0, 0, 0, 0, 5, 120, 0, 0, 0, 0,
- 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,
- 0, 2, 2, 2, 2, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0,
- 121, 2, 51, 2, 106, 2, 8, 2, 2, 2, 63, 17, 14, 0, 0, 29,
- 0, 2, 2, 0, 0, 0, 0, 0, 0, 27, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 122, 21, 21, 21, 21, 21, 21, 21, 123, 0, 0, 0, 0,
- 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 0,
- 50, 2, 2, 2, 20, 20, 124, 114, 0, 2, 2, 2, 125, 18, 57, 18,
- 111, 100, 126, 0, 0, 0, 0, 0, 0, 9, 127, 2, 2, 2, 2, 2,
- 2, 2, 128, 21, 20, 18, 46, 129, 130, 131, 0, 0, 0, 0, 0, 0,
- 0, 2, 2, 50, 28, 2, 2, 2, 2, 2, 2, 2, 2, 8, 20, 57,
- 97, 74, 132, 133, 134, 0, 0, 0, 0, 2, 135, 2, 2, 2, 2, 136,
- 0, 28, 2, 40, 3, 0, 77, 13, 2, 51, 20, 137, 50, 51, 2, 2,
- 103, 8, 7, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 138, 19,
- 23, 0, 0, 139, 140, 0, 0, 0, 0, 2, 63, 43, 21, 78, 45, 141,
- 0, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, 0, 0, 0, 0, 0,
- 4, 118, 118, 118, 118, 119, 0, 0, 0, 2, 2, 2, 2, 2, 7, 2,
- 2, 2, 7, 2, 28, 2, 2, 2, 2, 2, 28, 2, 2, 2, 28, 7,
- 0, 125, 18, 25, 29, 0, 0, 142, 143, 2, 2, 28, 2, 28, 2, 2,
- 2, 2, 2, 2, 0, 12, 35, 0, 144, 2, 2, 11, 35, 0, 28, 2,
- 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 2, 2,
- 7, 2, 2, 9, 39, 0, 0, 0, 0, 2, 2, 2, 2, 2, 25, 36,
- 0, 2, 2, 2, 114, 114, 114, 114, 114, 145, 2, 7, 0, 0, 0, 0,
- 0, 2, 12, 12, 0, 0, 0, 0, 0, 7, 2, 2, 7, 2, 2, 2,
- 2, 28, 2, 7, 0, 28, 2, 0, 0, 146, 147, 148, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 20, 20, 18, 18, 18, 20, 20, 131, 0, 0, 0,
- 0, 0, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 2, 2, 2, 2,
- 2, 51, 50, 51, 0, 0, 0, 0, 150, 9, 72, 2, 2, 2, 2, 2,
- 2, 16, 17, 19, 14, 22, 35, 0, 0, 0, 29, 0, 0, 0, 0, 0,
- 0, 9, 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 125, 18, 20, 151,
- 20, 19, 152, 153, 2, 2, 2, 2, 2, 0, 0, 63, 154, 0, 0, 0,
- 0, 2, 11, 0, 0, 0, 0, 0, 0, 2, 63, 23, 18, 18, 18, 20,
- 20, 106, 155, 0, 0, 54, 156, 29, 157, 28, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 21, 17, 20, 20, 158, 42, 0, 0, 0,
- 47, 125, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 7, 7, 2, 2,
- 28, 2, 2, 2, 2, 2, 2, 2, 28, 2, 2, 2, 2, 2, 2, 2,
- 8, 16, 17, 19, 20, 159, 29, 0, 0, 9, 9, 28, 2, 2, 2, 7,
- 28, 7, 2, 28, 2, 2, 56, 15, 21, 14, 21, 45, 30, 31, 30, 32,
- 0, 0, 0, 0, 33, 0, 0, 0, 2, 2, 21, 0, 9, 9, 9, 44,
- 0, 9, 9, 44, 0, 0, 0, 0, 0, 2, 2, 63, 23, 18, 18, 18,
- 20, 21, 123, 13, 15, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0,
- 160, 161, 0, 0, 0, 0, 0, 0, 0, 16, 17, 18, 18, 64, 97, 23,
- 157, 9, 162, 7, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2,
- 63, 23, 18, 18, 0, 46, 46, 9, 163, 35, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 2, 2, 18, 0, 21, 17, 18, 18, 19, 14, 80,
- 163, 36, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 8, 164,
- 23, 18, 20, 20, 162, 7, 0, 0, 0, 2, 2, 2, 2, 2, 7, 41,
- 133, 21, 20, 18, 74, 19, 20, 0, 0, 2, 2, 2, 7, 0, 0, 0,
- 0, 2, 2, 2, 2, 2, 2, 16, 17, 18, 19, 20, 103, 163, 35, 0,
- 0, 2, 2, 2, 7, 28, 0, 2, 2, 2, 2, 28, 7, 2, 2, 2,
- 2, 21, 21, 16, 30, 31, 10, 165, 166, 167, 168, 0, 0, 0, 0, 0,
- 0, 2, 2, 2, 2, 0, 2, 2, 2, 63, 23, 18, 18, 0, 20, 21,
- 27, 106, 0, 31, 0, 0, 0, 0, 0, 50, 18, 20, 20, 20, 137, 2,
- 2, 2, 169, 170, 9, 13, 171, 70, 172, 0, 0, 1, 144, 0, 0, 0,
- 0, 50, 18, 20, 14, 17, 18, 2, 2, 2, 2, 155, 155, 155, 173, 173,
- 173, 173, 173, 173, 13, 174, 0, 28, 0, 20, 18, 18, 29, 20, 20, 9,
- 163, 0, 59, 59, 59, 59, 59, 59, 59, 64, 19, 80, 44, 0, 0, 0,
- 0, 2, 2, 2, 7, 2, 28, 2, 2, 50, 20, 20, 29, 0, 36, 20,
- 25, 9, 156, 175, 171, 0, 0, 0, 0, 2, 2, 2, 28, 7, 2, 2,
- 2, 2, 2, 2, 2, 2, 21, 21, 45, 20, 33, 80, 66, 0, 0, 0,
- 0, 2, 176, 64, 45, 0, 0, 0, 0, 9, 177, 2, 2, 2, 2, 2,
- 2, 2, 2, 21, 20, 18, 29, 0, 46, 14, 140, 0, 0, 0, 0, 0,
- 0, 178, 178, 178, 106, 179, 178, 0, 0, 145, 2, 2, 180, 114, 114, 114,
- 114, 114, 114, 114, 0, 0, 0, 0, 0, 9, 9, 9, 44, 0, 0, 0,
- 0, 2, 2, 2, 2, 2, 7, 0, 56, 181, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0,
- 38, 114, 24, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0,
- 0, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 56,
- 35, 0, 4, 118, 118, 118, 119, 0, 0, 9, 9, 9, 47, 2, 2, 2,
+ 2, 2, 2, 94, 2, 2, 95, 2, 2, 2, 96, 2, 2, 2, 2, 2,
+ 2, 2, 2, 97, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 98, 98, 99, 100, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
+ 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
+ 98, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4,
+ 0, 5, 0, 0, 0, 0, 0, 6, 0, 0, 7, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 11,
+ 11, 11, 11, 0, 0, 0, 9, 12, 0, 2, 2, 2, 2, 13, 14, 0,
+ 0, 11, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 17,
+ 18, 19, 20, 21, 22, 16, 23, 24, 25, 12, 26, 27, 20, 2, 2, 2,
+ 2, 2, 20, 0, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2,
+ 2, 28, 29, 30, 2, 2, 2, 9, 30, 9, 30, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 9, 2, 2, 2, 9, 9, 0, 2, 2, 0, 17,
+ 18, 19, 20, 31, 32, 33, 32, 34, 0, 0, 0, 0, 35, 0, 0, 2,
+ 30, 2, 0, 0, 0, 0, 0, 9, 36, 12, 15, 30, 2, 2, 9, 0,
+ 30, 9, 2, 30, 9, 2, 0, 37, 18, 19, 31, 0, 27, 38, 27, 39,
+ 0, 40, 0, 0, 0, 30, 2, 9, 9, 0, 0, 0, 2, 2, 2, 2,
+ 2, 41, 42, 43, 0, 0, 0, 0, 0, 12, 15, 30, 2, 2, 2, 2,
+ 30, 2, 30, 2, 2, 2, 2, 2, 2, 9, 2, 30, 2, 2, 0, 17,
+ 18, 19, 20, 21, 27, 22, 35, 24, 0, 0, 0, 0, 0, 30, 41, 41,
+ 44, 12, 29, 30, 2, 2, 2, 9, 30, 9, 2, 30, 2, 2, 0, 17,
+ 45, 0, 0, 27, 22, 0, 0, 2, 30, 30, 0, 0, 0, 0, 0, 0,
+ 0, 0, 46, 30, 2, 2, 9, 0, 2, 9, 2, 2, 0, 30, 9, 9,
+ 2, 0, 30, 9, 0, 2, 9, 0, 2, 2, 2, 2, 2, 2, 0, 0,
+ 23, 16, 47, 0, 48, 33, 48, 34, 0, 0, 0, 0, 35, 0, 0, 0,
+ 0, 15, 29, 49, 2, 2, 2, 9, 2, 9, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 0, 17, 22, 16, 23, 47, 22, 38, 22, 39,
+ 0, 0, 0, 27, 31, 2, 9, 0, 0, 10, 29, 30, 2, 2, 2, 9,
+ 2, 2, 2, 30, 2, 2, 0, 17, 45, 0, 0, 35, 47, 0, 0, 0,
+ 9, 50, 51, 0, 0, 0, 0, 0, 0, 11, 29, 2, 2, 2, 2, 9,
+ 2, 2, 2, 2, 2, 2, 52, 53, 23, 23, 19, 31, 48, 33, 48, 34,
+ 54, 0, 0, 0, 35, 0, 0, 0, 30, 12, 29, 30, 2, 2, 2, 2,
+ 2, 2, 2, 2, 9, 0, 2, 2, 2, 2, 30, 2, 2, 2, 2, 30,
+ 0, 2, 2, 2, 9, 0, 55, 0, 35, 23, 22, 31, 31, 18, 48, 48,
+ 25, 0, 23, 0, 0, 0, 0, 0, 0, 2, 0, 2, 9, 0, 0, 0,
+ 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 2, 56, 56, 57, 0, 0,
+ 18, 2, 2, 2, 2, 30, 2, 2, 2, 2, 2, 2, 2, 2, 2, 9,
+ 0, 58, 21, 59, 22, 22, 20, 20, 46, 21, 11, 31, 11, 2, 2, 60,
+ 61, 61, 61, 61, 61, 62, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
+ 61, 61, 61, 61, 61, 61, 61, 63, 0, 0, 0, 0, 64, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 65, 45, 59, 66, 22, 22, 67, 68, 69, 70,
+ 71, 2, 2, 2, 2, 2, 1, 0, 5, 2, 2, 2, 23, 20, 2, 2,
+ 72, 71, 73, 74, 65, 73, 29, 29, 2, 52, 22, 53, 2, 2, 2, 2,
+ 2, 2, 75, 76, 77, 29, 29, 78, 79, 2, 2, 2, 2, 2, 29, 45,
+ 0, 2, 59, 80, 0, 0, 0, 0, 30, 2, 59, 47, 0, 0, 0, 0,
+ 0, 2, 59, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 9,
+ 2, 9, 59, 0, 0, 0, 0, 0, 0, 2, 2, 81, 45, 22, 59, 20,
+ 48, 48, 48, 48, 15, 82, 83, 84, 85, 86, 87, 0, 0, 0, 0, 88,
+ 0, 9, 0, 0, 30, 0, 89, 81, 90, 2, 2, 2, 2, 9, 0, 0,
+ 0, 42, 42, 91, 92, 2, 2, 2, 2, 2, 2, 2, 2, 13, 9, 0,
+ 0, 93, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 9, 22, 80, 45, 22, 94, 61, 0, 0, 95, 96, 95, 95, 97, 98, 0,
+ 0, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 9, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 29, 0, 0,
+ 0, 2, 2, 2, 2, 2, 9, 0, 0, 2, 2, 2, 52, 99, 45, 0,
+ 0, 2, 2, 100, 101, 102, 103, 61, 63, 104, 16, 45, 22, 59, 21, 80,
+ 48, 48, 76, 11, 11, 11, 105, 46, 40, 11, 106, 74, 2, 2, 2, 2,
+ 2, 2, 2, 107, 22, 20, 20, 22, 48, 48, 22, 108, 2, 2, 2, 9,
+ 0, 0, 0, 0, 0, 0, 109, 110, 111, 111, 111, 0, 0, 0, 0, 0,
+ 0, 106, 74, 2, 2, 2, 2, 2, 2, 60, 61, 59, 25, 22, 112, 61,
+ 2, 2, 2, 2, 107, 22, 23, 45, 45, 102, 14, 0, 0, 0, 0, 0,
+ 0, 2, 2, 61, 18, 48, 23, 113, 102, 102, 102, 114, 115, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 0, 30, 2, 11, 46, 116, 116, 116, 11, 116,
+ 116, 15, 116, 116, 116, 26, 0, 40, 0, 0, 0, 117, 51, 11, 5, 0,
+ 0, 0, 0, 0, 0, 0, 118, 0, 0, 0, 0, 0, 0, 0, 6, 119,
+ 120, 42, 42, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120, 120,
+ 121, 120, 120, 120, 120, 120, 120, 120, 120, 0, 0, 122, 0, 0, 0, 0,
+ 0, 0, 7, 122, 0, 0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 123, 123, 0, 0,
+ 0, 2, 2, 2, 2, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0,
+ 124, 0, 123, 123, 0, 0, 0, 0, 0, 2, 53, 2, 108, 2, 10, 2,
+ 2, 2, 65, 19, 16, 0, 0, 31, 0, 2, 2, 0, 0, 0, 0, 0,
+ 0, 29, 2, 2, 2, 2, 2, 2, 2, 2, 2, 125, 23, 23, 23, 23,
+ 23, 23, 23, 126, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 2, 0, 0, 0, 0, 0, 52, 2, 2, 2, 22, 22, 127, 116,
+ 0, 2, 2, 2, 128, 20, 59, 20, 113, 102, 129, 0, 0, 0, 0, 0,
+ 0, 11, 130, 2, 2, 2, 2, 2, 2, 2, 131, 23, 22, 20, 48, 132,
+ 133, 134, 0, 0, 0, 0, 0, 0, 0, 2, 2, 52, 30, 2, 2, 2,
+ 2, 2, 2, 2, 2, 10, 22, 59, 99, 76, 135, 136, 137, 0, 0, 0,
+ 0, 2, 138, 2, 2, 2, 2, 139, 0, 30, 2, 42, 5, 0, 79, 15,
+ 2, 53, 22, 140, 52, 53, 2, 2, 105, 10, 9, 0, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 141, 21, 25, 0, 0, 142, 143, 0, 0, 0,
+ 0, 2, 65, 45, 23, 80, 47, 144, 0, 81, 81, 81, 81, 81, 81, 81,
+ 81, 0, 0, 0, 0, 0, 0, 0, 6, 120, 120, 120, 120, 121, 0, 0,
+ 0, 2, 2, 2, 2, 2, 9, 2, 2, 2, 9, 2, 30, 2, 2, 2,
+ 2, 2, 30, 2, 2, 2, 30, 9, 0, 128, 20, 27, 31, 0, 0, 145,
+ 146, 2, 2, 30, 2, 30, 2, 2, 2, 2, 2, 2, 0, 14, 37, 0,
+ 147, 2, 2, 13, 37, 0, 30, 2, 2, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 30, 2, 2, 9, 2, 2, 11, 41, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 27, 38, 0, 2, 2, 2, 116, 116, 116, 116,
+ 116, 148, 2, 9, 0, 0, 0, 0, 0, 2, 14, 14, 0, 0, 0, 0,
+ 0, 9, 2, 2, 9, 2, 2, 2, 2, 30, 2, 9, 0, 30, 2, 0,
+ 0, 149, 150, 151, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 22, 20,
+ 20, 20, 22, 22, 134, 0, 0, 0, 0, 0, 152, 152, 152, 152, 152, 152,
+ 152, 152, 152, 152, 2, 2, 2, 2, 2, 53, 52, 53, 0, 0, 0, 0,
+ 153, 11, 74, 2, 2, 2, 2, 2, 2, 18, 19, 21, 16, 24, 37, 0,
+ 0, 0, 31, 0, 0, 0, 0, 0, 0, 11, 49, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 128, 20, 22, 154, 22, 21, 155, 156, 2, 2, 2, 2,
+ 2, 0, 0, 65, 157, 0, 0, 0, 0, 2, 13, 0, 0, 0, 0, 0,
+ 0, 2, 65, 25, 20, 20, 20, 22, 22, 108, 158, 0, 0, 56, 159, 31,
+ 160, 30, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 23,
+ 19, 22, 22, 161, 44, 0, 0, 0, 49, 128, 0, 0, 0, 0, 0, 0,
+ 0, 2, 2, 2, 9, 9, 2, 2, 30, 2, 2, 2, 2, 2, 2, 2,
+ 30, 2, 2, 2, 2, 2, 2, 2, 10, 18, 19, 21, 22, 162, 31, 0,
+ 0, 11, 11, 30, 2, 2, 2, 9, 30, 9, 2, 30, 2, 2, 58, 17,
+ 23, 16, 23, 47, 32, 33, 32, 34, 0, 0, 0, 0, 35, 0, 0, 0,
+ 2, 2, 23, 0, 11, 11, 11, 46, 0, 11, 11, 46, 0, 0, 0, 0,
+ 0, 2, 2, 65, 25, 20, 20, 20, 22, 23, 126, 15, 17, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 0, 0, 163, 164, 0, 0, 0, 0, 0, 0,
+ 0, 18, 19, 20, 20, 66, 99, 25, 160, 11, 165, 9, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 2, 2, 65, 25, 20, 20, 0, 48, 48, 11,
+ 166, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 20,
+ 0, 23, 19, 20, 20, 21, 16, 82, 166, 38, 0, 0, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 10, 167, 25, 20, 22, 22, 165, 9, 0, 0,
+ 0, 2, 2, 2, 2, 2, 9, 43, 136, 23, 22, 20, 76, 21, 22, 0,
+ 0, 2, 2, 2, 9, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 18,
+ 19, 20, 21, 22, 105, 166, 37, 0, 0, 2, 2, 2, 9, 30, 0, 2,
+ 2, 2, 2, 30, 9, 2, 2, 2, 2, 23, 23, 18, 32, 33, 12, 168,
+ 169, 170, 171, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 2, 2,
+ 2, 65, 25, 20, 20, 0, 22, 23, 29, 108, 0, 33, 0, 0, 0, 0,
+ 0, 52, 20, 22, 22, 22, 140, 2, 2, 2, 172, 173, 11, 15, 174, 72,
+ 175, 0, 0, 1, 147, 0, 0, 0, 0, 52, 20, 22, 16, 19, 20, 2,
+ 2, 2, 2, 158, 158, 158, 176, 176, 176, 176, 176, 176, 15, 177, 0, 30,
+ 0, 22, 20, 20, 31, 22, 22, 11, 166, 0, 61, 61, 61, 61, 61, 61,
+ 61, 66, 21, 82, 46, 0, 0, 0, 0, 2, 2, 2, 9, 2, 30, 2,
+ 2, 52, 22, 22, 31, 0, 38, 22, 27, 11, 159, 178, 174, 0, 0, 0,
+ 0, 2, 2, 2, 30, 9, 2, 2, 2, 2, 2, 2, 2, 2, 23, 23,
+ 47, 22, 35, 82, 68, 0, 0, 0, 0, 2, 179, 66, 47, 0, 0, 0,
+ 0, 11, 180, 2, 2, 2, 2, 2, 2, 2, 2, 23, 22, 20, 31, 0,
+ 48, 16, 143, 0, 0, 0, 0, 0, 0, 181, 181, 181, 181, 181, 181, 181,
+ 181, 182, 182, 182, 183, 184, 182, 181, 181, 185, 181, 181, 186, 187, 187, 187,
+ 187, 187, 187, 187, 0, 0, 0, 0, 0, 11, 11, 11, 46, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 9, 0, 58, 188, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0,
+ 40, 116, 26, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0,
+ 0, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 58,
+ 37, 0, 6, 120, 120, 120, 121, 0, 0, 11, 11, 11, 49, 2, 2, 2,
0, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
- 44, 2, 2, 2, 2, 2, 2, 9, 9, 2, 2, 2, 2, 2, 2, 20,
- 20, 2, 2, 42, 42, 42, 90, 0, 0, O, O, O, GB, B, B, GB,
- O, O, WJ,FMPst,FMPst, O, CGJ, B, O, B,VMAbv,VMAbv,VMAbv, O,VMAbv, B,
- CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw,
- VAbv, VAbv, VAbv, VPst, VPst, VPst, H, VPre, VPst,VMBlw, O, O, VAbv, GB,VMAbv,VMPst,
- VMPst, O, B, VBlw, O, O, VPre, VPre, O, VPre, H, O, VPst,FMAbv, O,CMBlw,
- O, VAbv, O, VAbv, H, O,VMBlw,VMAbv,CMAbv, GB, GB, O, MBlw,CMAbv,CMAbv, VPst,
- VAbv,VMAbv, O, VPst, O, VPre, VPre,VMAbv, B, O, CS, CS,VMPst, B, VAbv, VAbv,
- B, R, O, HVM, O, O,FMBlw, O,CMAbv, O,CMBlw, VAbv, VBlw, B, SUB, SUB,
- SUB, O, SUB, SUB, O,FMBlw, O, B, VPst, VBlw, VPre,VMAbv,VMBlw,VMPst, IS, VAbv,
- MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst,VMPst,VMPst, B, MBlw, VPst, VPre, VAbv, VAbv,
- VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ, CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,
- VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, B, CGJ, WJ, CGJ, GB,CMAbv,CMAbv, B, GB,
- B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre, B, MPre, MBlw,
- SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst, H, B, O,
- SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst, IS, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv,
- CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ, O,FMPst, O, O, H, MPst, VPst, H,
- VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv,VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, H,
- O, VBlw, MPst, MPre, MAbv, MBlw, O, B, FAbv, FAbv, FPst, VBlw, B, B, VPre, O,
- VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst,
- CS, CS, B, N, N, O, HN, VPre, VBlw, VAbv, IS,CMAbv, O, VPst, B, R,
- R,CMBlw, VAbv, VPre,VMAbv,VMAbv, H, VAbv,CMBlw,FMAbv, B, CS, CS, H,CMBlw,VMPst,
- H,VMPst, VAbv,VMAbv, VPst, IS, R, MPst, R, MPst,CMBlw, B,FMBlw, VBlw,VMAbv, R,
- MBlw, MBlw, GB, FBlw, FBlw,CMAbv, IS, VBlw, IS, GB, VAbv, R,VMPst, H, H, B,
- H, B,VMBlw, O, VBlw,
+ 46, 2, 2, 2, 2, 2, 2, 11, 11, 2, 2, 2, 2, 2, 2, 22,
+ 22, 2, 2, 44, 44, 44, 92, 0, 0, O, O, O, GB, B, B, O,
+ SB, O, SE, GB, O, O, WJ,FMPst,FMPst, O, CGJ, B, O, B,VMAbv,VMAbv,
+ VMAbv, O,VMAbv, B,CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw, B, VPst, VPre, VPst,
+ VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst, VPst, VPst, H, VPre, VPst,VMBlw, O, O,
+ VAbv, GB,VMAbv,VMPst,VMPst, O, B, VBlw, O, O, VPre, VPre, O, VPre, H, O,
+ VPst,FMAbv, O,CMBlw, O, VAbv, O, VAbv, H, O,VMBlw,VMAbv,CMAbv, GB, GB, O,
+ MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv, O, VPst, O, VPre, VPre,VMAbv, B, O, CS, CS,
+ VMPst, B, VAbv, VAbv, B, R, O, HVM, O, O,FMBlw, O,CMAbv, O,CMBlw, VAbv,
+ VBlw, B, SUB, SUB, SUB, O, SUB, SUB, O,FMBlw, O, B, VPst, VBlw, VPre,VMAbv,
+ VMBlw,VMPst, IS, VAbv, MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst,VMPst,VMPst, B, MBlw,
+ VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ, CGJ, VPst,VMAbv,VMAbv,
+ FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, B, CGJ, WJ, CGJ, GB,
+ CMAbv,CMAbv, B, GB, B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv,
+ VPre, B, MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv,
+ VPst, H, B, O,SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst, IS, VBlw, FAbv,VMPre,VMPre,FMAbv,
+ CMBlw,VMBlw,VMBlw,VMAbv, CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ, O,FMPst, O, SB,
+ SE, O, H, MPst, VPst, H,VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv,VMPst, B,
+ CMAbv, VAbv, MBlw, MPst, MBlw, H, O, VBlw, MPst, MPre, MAbv, MBlw, O, B, FAbv, FAbv,
+ FPst, VBlw, B, B, VPre, O,VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv, O,
+ IS,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS, B, N, N, O, HN, VPre, VBlw, VAbv,
+ IS,CMAbv, O, VPst, B, R, R,CMBlw, VAbv, VPre,VMAbv,VMAbv, H, VAbv,CMBlw,FMAbv,
+ B, CS, CS, H,CMBlw,VMPst, H,VMPst, VAbv,VMAbv, VPst, IS, R, MPst, R, MPst,
+ CMBlw, B,FMBlw, VBlw,VMAbv, R, MBlw, MBlw, GB, FBlw, FBlw,CMAbv, IS, VBlw, IS, GB,
+ VAbv, R,VMPst, G, G, J, J, J, SB, SE, J, HR, G, G, HM, HM,
+ HM, O, VBlw,
};
static const uint16_t
-hb_use_u16[784] =
+hb_use_u16[808] =
{
- 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 5, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0,
- 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11,
- 0, 0, 0, 0, 9, 12, 0, 0, 13, 9, 9, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 23, 24, 17, 25, 26, 20, 21, 27, 28, 29, 30, 31,
- 32, 33, 21, 34, 35, 0, 17, 36, 37, 20, 21, 38, 23, 39, 17, 40,
- 41, 42, 43, 44, 45, 46, 30, 0, 47, 48, 21, 49, 50, 51, 17, 0,
- 52, 48, 21, 53, 50, 54, 17, 55, 56, 48, 9, 57, 58, 59, 17, 0,
- 60, 61, 9, 62, 63, 64, 30, 65, 66, 67, 9, 68, 69, 9, 70, 71,
- 72, 73, 74, 75, 76, 0, 0, 0, 9, 9, 77, 78, 79, 80, 81, 82,
- 83, 84, 0, 0, 0, 0, 0, 0, 9, 85, 9, 86, 9, 87, 88, 89,
- 9, 9, 9, 90, 91, 92, 2, 0, 93, 0, 9, 9, 9, 9, 9, 94,
- 95, 9, 96, 0, 0, 0, 0, 0, 97, 98, 99,100, 30, 9,101,102,
- 9, 9,103, 9,104,105, 0, 0, 9,106, 9, 9, 9,107,108,109,
- 2, 2, 0, 0, 0, 0, 0, 0,110, 9, 9,111,112, 2,113,114,
- 115, 9,116, 9, 9, 9,117,118, 9, 9,119,120,121, 0, 0, 0,
- 0, 0, 0, 0, 0,122,123,124, 0, 0, 0, 0, 0, 0, 0,125,
- 126,127,128, 0, 0, 0,129,130,131, 0, 0, 0, 0, 0, 0,132,
- 0, 0, 0, 0,133, 0, 0, 0, 0, 0, 0, 9, 9, 9,134,135,
- 136, 9,137, 0, 9, 9, 9,138,139, 9, 9,140,141, 2,142,143,
- 9, 9,144, 9,145,146, 0, 0,147, 9, 9,148,149, 2,150, 98,
- 9, 9,151,152,153, 2, 9,154, 9, 9, 9,155,156, 0,157,158,
- 0, 0, 0, 0, 9, 9,159, 2,160, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,161, 0, 0, 0, 0, 0, 0, 0,162,
- 0, 0, 0, 0, 0, 0, 0,163,163,164, 33,165, 0, 0, 0, 0,
- 166,167, 9,168, 94, 0, 0, 0, 0, 0, 0, 0, 69, 9,169, 0,
- 9,170,171, 0, 0, 0, 0, 0, 9, 9,172, 2, 0, 0, 0, 0,
- 9, 9,173,170, 0, 0, 0, 0, 0, 0, 0, 9,174,175, 0, 9,
- 176, 0, 0,177,178, 0, 0, 0,179, 9, 9,180,181,182,183,184,
- 185, 9, 9,186,187, 0, 0, 0,188, 9,189,190,191, 9, 9,192,
- 185, 9, 9,193,194,105,195,102, 9, 33,196,197,198, 0, 0, 0,
- 199,200, 94, 9, 9,201,202, 2,203, 20, 21,204,205,206,207,208,
- 9, 9, 9,209,210,211,212, 0,195, 9, 9,213,214, 2, 0, 0,
- 9, 9,215,216,217,218, 0, 0, 9, 9, 9,219,220, 2, 0, 0,
- 9, 9,221,222, 2, 0, 0, 0, 9,223,224,103,225, 0, 0, 0,
- 9, 9,226,227, 0, 0, 0, 0,228,229, 9,230,231, 2, 0, 0,
- 0, 0,232, 9, 9,233,234, 0,235, 9, 9,236,237,238, 9, 9,
- 239,240, 0, 0, 0, 0, 0, 0, 21, 9,215,241, 7, 9, 70, 18,
- 9,242, 73,243, 0, 0, 0, 0,244, 9, 9,245,246, 2,247, 9,
- 248,249, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,250,
- 251, 48, 9,252,253, 2, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9,254,255,256, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
- 9, 9, 9,257, 0, 0, 0, 0, 9, 9, 9, 9,258,259,260,260,
- 261,262, 0, 0, 0, 0,263, 0, 9, 9, 9, 9, 9,264, 0, 0,
- 9, 9, 9, 9, 9, 9,105, 70, 94,265, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,266, 9, 9, 70,267,268, 0, 0, 0,
- 0, 9,269, 0, 9, 9,270, 2, 0, 0, 0, 0, 0, 9,271, 2,
- 9, 9, 9, 9,272, 2, 0, 0,129,129,129,129,129,129,129,129,
- 160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,129,
+ 0, 0, 1, 2, 0, 3, 0, 3, 0, 0, 4, 5, 0, 6, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0,
+ 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 9, 10, 11, 12,
+ 0, 0, 0, 0, 10, 13, 0, 0, 14, 10, 10, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 18, 26, 27, 21, 22, 28, 29, 30, 31, 32,
+ 33, 34, 22, 35, 36, 0, 18, 37, 38, 21, 22, 39, 24, 40, 18, 41,
+ 42, 43, 44, 45, 46, 47, 31, 0, 48, 49, 22, 50, 51, 52, 18, 0,
+ 53, 49, 22, 54, 51, 55, 18, 56, 57, 49, 10, 58, 59, 60, 18, 0,
+ 61, 62, 10, 63, 64, 65, 31, 66, 67, 68, 10, 69, 70, 10, 71, 72,
+ 73, 74, 75, 76, 77, 0, 0, 0, 10, 10, 78, 79, 80, 81, 82, 83,
+ 84, 85, 0, 0, 0, 0, 0, 0, 10, 86, 10, 87, 10, 88, 89, 90,
+ 10, 10, 10, 91, 92, 93, 2, 0, 94, 0, 10, 10, 10, 10, 10, 95,
+ 96, 10, 97, 0, 0, 0, 0, 0, 98, 99,100,101, 31, 10,102,103,
+ 10, 10,104, 10,105,106, 0, 0, 10,107, 10, 10, 10,108,109,110,
+ 2, 2, 0, 0, 0, 0, 0, 0,111, 10, 10,112,113, 2,114,115,
+ 116, 10,117, 10, 10, 10,118,119, 10, 10,120,121,122, 0, 0, 0,
+ 0, 0, 0, 0, 0,123,124,125, 0, 0, 0, 0, 0, 0, 0,126,
+ 127,128,129, 0, 0, 0,130,131,132, 0, 0, 0, 0, 0, 0,133,
+ 0, 0, 0, 0,134, 0, 0, 0, 0, 0, 0, 0, 0, 0,135, 0,
+ 0, 0, 0, 10, 10, 10,136,137, 0, 0,138, 0, 0, 0, 0, 0,
+ 139, 10,140, 0, 10, 10, 10,141,142, 10, 10,143,144, 2,145,146,
+ 10, 10,147, 10,148,149, 0, 0,150, 10, 10,151,152, 2,153, 99,
+ 10, 10,154,155,156, 2, 10,157, 10, 10, 10,158,159, 0,160,161,
+ 0, 0, 0, 0, 10, 10,162, 2,163, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,164, 0, 0, 0, 0, 0, 0, 0,165,
+ 0, 0, 0, 0, 0, 0, 0,166,166,167, 34,168, 0, 0, 0, 0,
+ 169,170, 10,171, 95, 0, 0, 0, 0, 0, 0, 0, 70, 10,172, 0,
+ 10,173,174, 0, 0, 0, 0, 0, 10, 10,175, 2, 0, 0, 0, 0,
+ 10, 10,176,173, 0, 0, 0, 0, 0, 0, 0, 10,177,178, 0, 10,
+ 179, 0, 0,180,181, 0, 0, 0,182, 10, 10,183,184,185,186,187,
+ 188, 10, 10,189,190, 0, 0, 0,191, 10,192,193,194, 10, 10,195,
+ 188, 10, 10,196,197,106,198,103, 10, 34,199,200,201, 0, 0, 0,
+ 202,203, 95, 10, 10,204,205, 2,206, 21, 22,207,208,209,210,211,
+ 10, 10, 10,212,213,214,215, 0,198, 10, 10,216,217, 2, 0, 0,
+ 10, 10,218,219,220,221, 0, 0, 10, 10, 10,222,223, 2, 0, 0,
+ 10, 10,224,225, 2, 0, 0, 0, 10,226,227,104,228, 0, 0, 0,
+ 10, 10,229,230, 0, 0, 0, 0,231,232, 10,233,234, 2, 0, 0,
+ 0, 0,235, 10, 10,236,237, 0,238, 10, 10,239,240,241, 10, 10,
+ 242,243, 0, 0, 0, 0, 0, 0, 22, 10,218,244, 8, 10, 71, 19,
+ 10,245, 74,246, 0, 0, 0, 0,247, 10, 10,248,249, 2,250, 10,
+ 251,252, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10,253,
+ 254, 49, 10,255,256, 2, 0, 0,257,257,257,257,257,257,257,257,
+ 257,257,257,258,259,260, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 10, 10, 10,261, 0, 0, 0, 0, 10, 10, 10, 10,262,263,264,264,
+ 265,266, 0, 0, 0, 0,267, 0, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10,268, 0, 0, 10, 10, 10, 10, 10, 10,106, 71,
+ 95,269, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,270,
+ 10, 10, 71,271,272, 0, 0, 0, 0, 10,273, 0, 10, 10,274, 2,
+ 0, 0, 0, 0, 0, 10,275, 2, 10, 10, 10, 10,276, 2, 0, 0,
+ 130,130,130,130,130,130,130,130,163,163,163,163,163,163,163,163,
+ 163,163,163,163,163,163,163,130,
};
static inline unsigned
@@ -357,14 +366,14 @@ hb_use_b4 (const uint8_t* a, unsigned i)
static inline uint_fast8_t
hb_use_get_category (unsigned u)
{
- return u<921600u?hb_use_u8[2777+(((hb_use_u8[593+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
+ return u<921600u?hb_use_u8[2809+(((hb_use_u8[593+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
}
#else
static const uint8_t
-hb_use_u8[3413] =
+hb_use_u8[3483] =
{
16, 50, 51, 51, 51, 52, 51, 83, 118, 131, 51, 57, 58, 179, 195, 61,
51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
@@ -375,243 +384,248 @@ hb_use_u8[3413] =
51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
14, 0, 1, 1, 2, 1, 1, 3, 4, 5, 6, 7, 8, 9, 10, 1,
11, 12, 1, 1, 1, 1, 1, 1, 13, 14, 15, 16, 17, 18, 19, 1,
- 1, 20, 1, 1, 1, 1, 21, 1, 1, 1, 1, 1, 1, 1, 22, 1,
+ 1, 20, 1, 1, 1, 1, 21, 1, 22, 1, 1, 1, 1, 1, 23, 24,
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, 23, 24, 25, 26, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27,
- 28, 1, 1, 1, 1, 1, 29, 1, 1, 1, 1, 30, 31, 1, 32, 33,
- 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 1, 46, 47, 48,
- 49, 50, 50, 50, 50, 51, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 52, 53, 1, 1, 1,
- 54, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 50, 55, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 56, 1, 1,
- 1, 1, 57, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 58, 59, 1, 60, 1, 1, 1, 1, 61, 1, 1, 1, 1, 1,
- 1, 62, 63, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
- 62, 0, 1, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 6, 7, 0, 0, 8, 0, 0, 0, 0,
- 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 36, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
- 0, 55, 56, 57, 58, 59, 0, 0, 0, 60, 61, 62, 63, 55, 64, 65,
- 66, 67, 55, 55, 68, 69, 70, 0, 0, 71, 72, 73, 74, 55, 75, 76,
- 0, 77, 55, 78, 79, 80, 0, 0, 0, 81, 82, 83, 84, 85, 86, 55,
- 87, 55, 88, 89, 0, 0, 0, 90, 91, 0, 0, 0, 0, 0, 0, 0,
- 92, 93, 94, 0, 95, 96, 0, 0, 97, 0, 0, 0, 0, 0, 0, 98,
- 0, 0, 99, 55, 100, 0, 0, 0, 0, 101, 102, 55, 103, 104, 105, 106,
- 107, 55, 108, 109, 0, 110, 111, 112, 113, 55, 114, 115, 116, 55, 117, 118,
- 119, 0, 0, 0, 0, 0, 0, 55, 120, 121, 0, 0, 0, 0, 0, 0,
- 122, 0, 0, 0, 0, 0, 0, 0, 123, 0, 0, 0, 124, 125, 126, 0,
- 0, 127, 128, 129, 0, 0, 0, 50, 130, 0, 0, 0, 0, 131, 132, 0,
- 0, 55, 133, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 134, 0,
- 0, 0, 99, 135, 99, 136, 137, 138, 0, 139, 140, 141, 142, 143, 144, 145,
- 0, 146, 147, 148, 149, 143, 150, 151, 152, 153, 154, 155, 0, 156, 157, 158,
- 159, 160, 161, 162, 163, 0, 0, 0, 0, 55, 164, 165, 166, 167, 168, 169,
- 0, 0, 0, 0, 0, 55, 170, 171, 0, 55, 172, 173, 0, 55, 174, 66,
- 0, 175, 176, 177, 0, 0, 0, 0, 0, 55, 178, 0, 0, 0, 0, 0,
- 0, 179, 180, 181, 0, 0, 182, 183, 184, 185, 186, 187, 55, 188, 0, 0,
- 0, 189, 190, 191, 192, 193, 194, 0, 0, 195, 196, 197, 198, 199, 66, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 200, 201, 202, 203, 0, 0, 0, 0,
- 0, 55, 55, 55, 55, 55, 55, 55, 55, 55, 204, 205, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 66, 0, 55, 206, 0, 0, 0, 0, 0,
- 0, 55, 55, 207, 208, 209, 0, 0, 210, 55, 55, 55, 55, 55, 55, 211,
- 0, 55, 55, 55, 212, 213, 0, 0, 0, 0, 0, 0, 214, 0, 0, 0,
- 0, 55, 215, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 217, 55,
- 218, 0, 0, 0, 0, 0, 0, 99, 219, 55, 55, 220, 0, 0, 0, 0,
- 0, 221, 221, 221, 221, 221, 221, 221, 221, 222, 222, 222, 222, 222, 222, 222,
- 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
- 0, 2, 2, 2, 2, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4,
- 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 25, 26, 27, 28, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 29,
+ 30, 1, 1, 1, 1, 1, 31, 1, 1, 1, 1, 32, 33, 1, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 1, 48, 49, 50,
+ 51, 52, 52, 52, 52, 53, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 54, 55, 1, 1, 1,
+ 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 57, 58, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 59, 1, 1,
+ 1, 1, 60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 61, 62, 1, 63, 1, 1, 1, 1, 64, 1, 1, 1, 1, 1,
+ 1, 65, 66, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 0, 1, 2, 2, 0, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 7, 8, 0, 0, 9, 0, 0, 0, 0,
+ 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 37, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
+ 0, 56, 57, 58, 59, 60, 0, 0, 0, 61, 62, 63, 64, 56, 65, 66,
+ 67, 68, 56, 56, 69, 70, 71, 0, 0, 72, 73, 74, 75, 56, 76, 77,
+ 0, 78, 56, 79, 80, 81, 0, 0, 0, 82, 83, 84, 85, 86, 87, 56,
+ 88, 56, 89, 90, 0, 0, 0, 91, 92, 0, 0, 0, 0, 0, 0, 0,
+ 93, 94, 95, 0, 96, 97, 0, 0, 98, 0, 0, 0, 0, 0, 0, 99,
+ 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 101, 56, 102, 0, 0, 0,
+ 0, 0, 103, 0, 0, 0, 0, 0, 0, 104, 105, 56, 106, 107, 108, 109,
+ 110, 56, 111, 112, 0, 113, 114, 115, 116, 56, 117, 118, 119, 56, 120, 121,
+ 122, 0, 0, 0, 0, 0, 0, 56, 123, 124, 0, 0, 0, 0, 0, 0,
+ 125, 0, 0, 0, 0, 0, 0, 0, 126, 0, 0, 0, 127, 128, 129, 0,
+ 0, 130, 131, 132, 0, 0, 0, 51, 133, 0, 0, 0, 0, 134, 135, 0,
+ 0, 56, 136, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 137, 0,
+ 0, 0, 101, 138, 101, 139, 140, 141, 0, 142, 143, 144, 145, 146, 147, 148,
+ 0, 149, 150, 151, 152, 146, 153, 154, 155, 156, 157, 158, 0, 159, 160, 161,
+ 162, 163, 164, 165, 166, 0, 0, 0, 0, 56, 167, 168, 169, 170, 171, 172,
+ 0, 0, 0, 0, 0, 56, 173, 174, 0, 56, 175, 176, 0, 56, 177, 67,
+ 0, 178, 179, 180, 0, 0, 0, 0, 0, 56, 181, 0, 0, 0, 0, 0,
+ 0, 182, 183, 184, 0, 0, 185, 186, 187, 188, 189, 190, 56, 191, 0, 0,
+ 0, 192, 193, 194, 195, 196, 197, 0, 0, 198, 199, 200, 201, 202, 67, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 203, 204, 205, 206, 0, 0, 0, 0,
+ 0, 207, 207, 207, 207, 207, 207, 207, 207, 207, 208, 209, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 67, 0, 56, 210, 0, 0, 0, 0, 0,
+ 0, 56, 56, 211, 212, 213, 0, 0, 214, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 215, 0, 56, 56, 56, 216, 217, 0, 0,
+ 0, 0, 0, 0, 218, 0, 0, 0, 0, 56, 219, 220, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 101, 221, 56, 222, 0, 0, 0, 0, 0, 0, 101,
+ 223, 56, 56, 224, 0, 0, 0, 0, 0, 225, 225, 225, 225, 225, 225, 225,
+ 225, 226, 226, 226, 226, 226, 226, 226, 227, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 2, 2, 2, 2, 0, 0,
+ 0, 0, 0, 0, 0, 0, 3, 4, 0, 5, 0, 0, 0, 0, 0, 6,
+ 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 8, 9, 9, 9, 9, 0, 0, 0, 7, 10,
- 0, 2, 2, 2, 2, 11, 12, 0, 0, 9, 13, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 14, 15, 16, 17, 18, 19, 20, 14, 21, 22,
- 23, 10, 24, 25, 18, 2, 2, 2, 2, 2, 18, 0, 2, 2, 2, 2,
- 2, 0, 2, 2, 2, 2, 2, 2, 2, 26, 27, 28, 2, 2, 2, 7,
- 28, 7, 28, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 2, 2,
- 2, 7, 7, 0, 2, 2, 0, 15, 16, 17, 18, 29, 30, 31, 30, 32,
- 0, 0, 0, 0, 33, 0, 0, 2, 28, 2, 0, 0, 0, 0, 0, 7,
- 34, 10, 13, 28, 2, 2, 7, 0, 28, 7, 2, 28, 7, 2, 0, 35,
- 16, 17, 29, 0, 25, 36, 25, 37, 0, 38, 0, 0, 0, 28, 2, 7,
- 7, 0, 0, 0, 2, 2, 2, 2, 2, 39, 40, 41, 0, 0, 0, 0,
- 0, 10, 13, 28, 2, 2, 2, 2, 28, 2, 28, 2, 2, 2, 2, 2,
- 2, 7, 2, 28, 2, 2, 0, 15, 16, 17, 18, 19, 25, 20, 33, 22,
- 0, 0, 0, 0, 0, 28, 39, 39, 42, 10, 27, 28, 2, 2, 2, 7,
- 28, 7, 2, 28, 2, 2, 0, 15, 43, 0, 0, 25, 20, 0, 0, 2,
- 28, 28, 0, 0, 0, 0, 0, 0, 0, 0, 44, 28, 2, 2, 7, 0,
- 2, 7, 2, 2, 0, 28, 7, 7, 2, 0, 28, 7, 0, 2, 7, 0,
- 2, 2, 2, 2, 2, 2, 0, 0, 21, 14, 45, 0, 46, 31, 46, 32,
- 0, 0, 0, 0, 33, 0, 0, 0, 0, 13, 27, 47, 2, 2, 2, 7,
- 2, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 15,
- 20, 14, 21, 45, 20, 36, 20, 37, 0, 0, 0, 25, 29, 2, 7, 0,
- 0, 8, 27, 28, 2, 2, 2, 7, 2, 2, 2, 28, 2, 2, 0, 15,
- 43, 0, 0, 33, 45, 0, 0, 0, 7, 48, 49, 0, 0, 0, 0, 0,
- 0, 9, 27, 2, 2, 2, 2, 7, 2, 2, 2, 2, 2, 2, 50, 51,
- 21, 21, 17, 29, 46, 31, 46, 32, 52, 0, 0, 0, 33, 0, 0, 0,
- 28, 10, 27, 28, 2, 2, 2, 2, 2, 2, 2, 2, 7, 0, 2, 2,
- 2, 2, 28, 2, 2, 2, 2, 28, 0, 2, 2, 2, 7, 0, 53, 0,
- 33, 21, 20, 29, 29, 16, 46, 46, 23, 0, 21, 0, 0, 0, 0, 0,
- 0, 2, 0, 2, 7, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0,
- 0, 2, 2, 54, 54, 55, 0, 0, 16, 2, 2, 2, 2, 28, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 7, 0, 56, 19, 57, 20, 20, 18, 18,
- 44, 19, 9, 29, 9, 2, 2, 58, 59, 59, 59, 59, 59, 60, 59, 59,
- 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61,
- 0, 0, 0, 0, 62, 0, 0, 0, 0, 2, 2, 2, 2, 2, 63, 43,
- 57, 64, 20, 20, 65, 66, 67, 68, 69, 2, 2, 2, 2, 2, 1, 0,
- 3, 2, 2, 2, 21, 18, 2, 2, 70, 69, 71, 72, 63, 71, 27, 27,
- 2, 50, 20, 51, 2, 2, 2, 2, 2, 2, 73, 74, 75, 27, 27, 76,
- 77, 2, 2, 2, 2, 2, 27, 43, 0, 2, 57, 78, 0, 0, 0, 0,
- 28, 2, 57, 45, 0, 0, 0, 0, 0, 2, 57, 0, 0, 0, 0, 0,
- 0, 2, 2, 2, 2, 2, 2, 7, 2, 7, 57, 0, 0, 0, 0, 0,
- 0, 2, 2, 79, 43, 20, 57, 18, 46, 46, 46, 46, 13, 80, 81, 82,
- 83, 84, 85, 0, 0, 0, 0, 86, 0, 7, 0, 0, 28, 0, 87, 79,
- 88, 2, 2, 2, 2, 7, 0, 0, 0, 40, 40, 89, 90, 2, 2, 2,
- 2, 2, 2, 2, 2, 11, 7, 0, 0, 91, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 7, 20, 78, 43, 20, 92, 59, 0,
- 0, 93, 94, 93, 93, 95, 96, 0, 0, 2, 2, 2, 2, 2, 2, 2,
- 0, 2, 2, 7, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0,
- 0, 2, 2, 2, 2, 27, 0, 0, 0, 2, 2, 2, 2, 2, 7, 0,
- 0, 2, 2, 2, 50, 97, 43, 0, 0, 2, 2, 98, 99, 100, 101, 59,
- 61, 102, 14, 43, 20, 57, 19, 78, 46, 46, 74, 9, 9, 9, 103, 44,
- 38, 9, 104, 72, 2, 2, 2, 2, 2, 2, 2, 105, 20, 18, 18, 20,
- 46, 46, 20, 106, 2, 2, 2, 7, 0, 0, 0, 0, 0, 0, 107, 108,
- 109, 109, 109, 0, 0, 0, 0, 0, 0, 104, 72, 2, 2, 2, 2, 2,
- 2, 58, 59, 57, 23, 20, 110, 59, 2, 2, 2, 2, 105, 20, 21, 43,
- 43, 100, 12, 0, 0, 0, 0, 0, 0, 2, 2, 59, 16, 46, 21, 111,
- 100, 100, 100, 112, 113, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 28,
- 2, 9, 44, 114, 114, 114, 9, 114, 114, 13, 114, 114, 114, 24, 0, 38,
- 0, 0, 0, 115, 49, 9, 3, 0, 0, 0, 0, 0, 0, 0, 116, 0,
- 0, 0, 0, 0, 0, 0, 4, 117, 118, 40, 40, 3, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 118, 118, 119, 118, 118, 118, 118, 118, 118, 118,
- 118, 0, 0, 120, 0, 0, 0, 0, 0, 0, 5, 120, 0, 0, 0, 0,
- 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,
- 0, 2, 2, 2, 2, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0,
- 121, 2, 51, 2, 106, 2, 8, 2, 2, 2, 63, 17, 14, 0, 0, 29,
- 0, 2, 2, 0, 0, 0, 0, 0, 0, 27, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 122, 21, 21, 21, 21, 21, 21, 21, 123, 0, 0, 0, 0,
- 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 0,
- 50, 2, 2, 2, 20, 20, 124, 114, 0, 2, 2, 2, 125, 18, 57, 18,
- 111, 100, 126, 0, 0, 0, 0, 0, 0, 9, 127, 2, 2, 2, 2, 2,
- 2, 2, 128, 21, 20, 18, 46, 129, 130, 131, 0, 0, 0, 0, 0, 0,
- 0, 2, 2, 50, 28, 2, 2, 2, 2, 2, 2, 2, 2, 8, 20, 57,
- 97, 74, 132, 133, 134, 0, 0, 0, 0, 2, 135, 2, 2, 2, 2, 136,
- 0, 28, 2, 40, 3, 0, 77, 13, 2, 51, 20, 137, 50, 51, 2, 2,
- 103, 8, 7, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 138, 19,
- 23, 0, 0, 139, 140, 0, 0, 0, 0, 2, 63, 43, 21, 78, 45, 141,
- 0, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, 0, 0, 0, 0, 0,
- 4, 118, 118, 118, 118, 119, 0, 0, 0, 2, 2, 2, 2, 2, 7, 2,
- 2, 2, 7, 2, 28, 2, 2, 2, 2, 2, 28, 2, 2, 2, 28, 7,
- 0, 125, 18, 25, 29, 0, 0, 142, 143, 2, 2, 28, 2, 28, 2, 2,
- 2, 2, 2, 2, 0, 12, 35, 0, 144, 2, 2, 11, 35, 0, 28, 2,
- 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 2, 2,
- 7, 2, 2, 9, 39, 0, 0, 0, 0, 2, 2, 2, 2, 2, 25, 36,
- 0, 2, 2, 2, 114, 114, 114, 114, 114, 145, 2, 7, 0, 0, 0, 0,
- 0, 2, 12, 12, 0, 0, 0, 0, 0, 7, 2, 2, 7, 2, 2, 2,
- 2, 28, 2, 7, 0, 28, 2, 0, 0, 146, 147, 148, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 20, 20, 18, 18, 18, 20, 20, 131, 0, 0, 0,
- 0, 0, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 2, 2, 2, 2,
- 2, 51, 50, 51, 0, 0, 0, 0, 150, 9, 72, 2, 2, 2, 2, 2,
- 2, 16, 17, 19, 14, 22, 35, 0, 0, 0, 29, 0, 0, 0, 0, 0,
- 0, 9, 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 125, 18, 20, 151,
- 20, 19, 152, 153, 2, 2, 2, 2, 2, 0, 0, 63, 154, 0, 0, 0,
- 0, 2, 11, 0, 0, 0, 0, 0, 0, 2, 63, 23, 18, 18, 18, 20,
- 20, 106, 155, 0, 0, 54, 156, 29, 157, 28, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 21, 17, 20, 20, 158, 42, 0, 0, 0,
- 47, 125, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 7, 7, 2, 2,
- 28, 2, 2, 2, 2, 2, 2, 2, 28, 2, 2, 2, 2, 2, 2, 2,
- 8, 16, 17, 19, 20, 159, 29, 0, 0, 9, 9, 28, 2, 2, 2, 7,
- 28, 7, 2, 28, 2, 2, 56, 15, 21, 14, 21, 45, 30, 31, 30, 32,
- 0, 0, 0, 0, 33, 0, 0, 0, 2, 2, 21, 0, 9, 9, 9, 44,
- 0, 9, 9, 44, 0, 0, 0, 0, 0, 2, 2, 63, 23, 18, 18, 18,
- 20, 21, 123, 13, 15, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0,
- 160, 161, 0, 0, 0, 0, 0, 0, 0, 16, 17, 18, 18, 64, 97, 23,
- 157, 9, 162, 7, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2,
- 63, 23, 18, 18, 0, 46, 46, 9, 163, 35, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 2, 2, 18, 0, 21, 17, 18, 18, 19, 14, 80,
- 163, 36, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 8, 164,
- 23, 18, 20, 20, 162, 7, 0, 0, 0, 2, 2, 2, 2, 2, 7, 41,
- 133, 21, 20, 18, 74, 19, 20, 0, 0, 2, 2, 2, 7, 0, 0, 0,
- 0, 2, 2, 2, 2, 2, 2, 16, 17, 18, 19, 20, 103, 163, 35, 0,
- 0, 2, 2, 2, 7, 28, 0, 2, 2, 2, 2, 28, 7, 2, 2, 2,
- 2, 21, 21, 16, 30, 31, 10, 165, 166, 167, 168, 0, 0, 0, 0, 0,
- 0, 2, 2, 2, 2, 0, 2, 2, 2, 63, 23, 18, 18, 0, 20, 21,
- 27, 106, 0, 31, 0, 0, 0, 0, 0, 50, 18, 20, 20, 20, 137, 2,
- 2, 2, 169, 170, 9, 13, 171, 70, 172, 0, 0, 1, 144, 0, 0, 0,
- 0, 50, 18, 20, 14, 17, 18, 2, 2, 2, 2, 155, 155, 155, 173, 173,
- 173, 173, 173, 173, 13, 174, 0, 28, 0, 20, 18, 18, 29, 20, 20, 9,
- 163, 0, 59, 59, 59, 59, 59, 59, 59, 64, 19, 80, 44, 0, 0, 0,
- 0, 2, 2, 2, 7, 2, 28, 2, 2, 50, 20, 20, 29, 0, 36, 20,
- 25, 9, 156, 175, 171, 0, 0, 0, 0, 2, 2, 2, 28, 7, 2, 2,
- 2, 2, 2, 2, 2, 2, 21, 21, 45, 20, 33, 80, 66, 0, 0, 0,
- 0, 2, 176, 64, 45, 0, 0, 0, 0, 9, 177, 2, 2, 2, 2, 2,
- 2, 2, 2, 21, 20, 18, 29, 0, 46, 14, 140, 0, 0, 0, 0, 0,
- 0, 178, 178, 178, 106, 179, 178, 0, 0, 145, 2, 2, 180, 114, 114, 114,
- 114, 114, 114, 114, 0, 0, 0, 0, 0, 9, 9, 9, 44, 0, 0, 0,
- 0, 2, 2, 2, 2, 2, 7, 0, 56, 181, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0,
- 38, 114, 24, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0,
- 0, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 56,
- 35, 0, 4, 118, 118, 118, 119, 0, 0, 9, 9, 9, 47, 2, 2, 2,
- 0, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
- 44, 2, 2, 2, 2, 2, 2, 9, 9, 2, 2, 2, 2, 2, 2, 20,
- 20, 2, 2, 42, 42, 42, 90, 0, 0, O, O, O, GB, B, B, GB,
- O, O, WJ,FMPst,FMPst, O, CGJ, B, O, B,VMAbv,VMAbv,VMAbv, O,VMAbv, B,
- CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw,
- VAbv, VAbv, VAbv, VPst, VPst, VPst, H, VPre, VPst,VMBlw, O, O, VAbv, GB,VMAbv,VMPst,
- VMPst, O, B, VBlw, O, O, VPre, VPre, O, VPre, H, O, VPst,FMAbv, O,CMBlw,
- O, VAbv, O, VAbv, H, O,VMBlw,VMAbv,CMAbv, GB, GB, O, MBlw,CMAbv,CMAbv, VPst,
- VAbv,VMAbv, O, VPst, O, VPre, VPre,VMAbv, B, O, CS, CS,VMPst, B, VAbv, VAbv,
- B, R, O, HVM, O, O,FMBlw, O,CMAbv, O,CMBlw, VAbv, VBlw, B, SUB, SUB,
- SUB, O, SUB, SUB, O,FMBlw, O, B, VPst, VBlw, VPre,VMAbv,VMBlw,VMPst, IS, VAbv,
- MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst,VMPst,VMPst, B, MBlw, VPst, VPre, VAbv, VAbv,
- VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ, CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,
- VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, B, CGJ, WJ, CGJ, GB,CMAbv,CMAbv, B, GB,
- B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre, B, MPre, MBlw,
- SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst, H, B, O,
- SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst, IS, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv,
- CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ, O,FMPst, O, O, H, MPst, VPst, H,
- VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv,VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, H,
- O, VBlw, MPst, MPre, MAbv, MBlw, O, B, FAbv, FAbv, FPst, VBlw, B, B, VPre, O,
- VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst,
- CS, CS, B, N, N, O, HN, VPre, VBlw, VAbv, IS,CMAbv, O, VPst, B, R,
- R,CMBlw, VAbv, VPre,VMAbv,VMAbv, H, VAbv,CMBlw,FMAbv, B, CS, CS, H,CMBlw,VMPst,
- H,VMPst, VAbv,VMAbv, VPst, IS, R, MPst, R, MPst,CMBlw, B,FMBlw, VBlw,VMAbv, R,
- MBlw, MBlw, GB, FBlw, FBlw,CMAbv, IS, VBlw, IS, GB, VAbv, R,VMPst, H, H, B,
- H, B,VMBlw, O, VBlw,
+ 2, 2, 2, 2, 2, 2, 10, 11, 11, 11, 11, 0, 0, 0, 9, 12,
+ 0, 2, 2, 2, 2, 13, 14, 0, 0, 11, 15, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 16, 17, 18, 19, 20, 21, 22, 16, 23, 24,
+ 25, 12, 26, 27, 20, 2, 2, 2, 2, 2, 20, 0, 2, 2, 2, 2,
+ 2, 0, 2, 2, 2, 2, 2, 2, 2, 28, 29, 30, 2, 2, 2, 9,
+ 30, 9, 30, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 9, 2, 2,
+ 2, 9, 9, 0, 2, 2, 0, 17, 18, 19, 20, 31, 32, 33, 32, 34,
+ 0, 0, 0, 0, 35, 0, 0, 2, 30, 2, 0, 0, 0, 0, 0, 9,
+ 36, 12, 15, 30, 2, 2, 9, 0, 30, 9, 2, 30, 9, 2, 0, 37,
+ 18, 19, 31, 0, 27, 38, 27, 39, 0, 40, 0, 0, 0, 30, 2, 9,
+ 9, 0, 0, 0, 2, 2, 2, 2, 2, 41, 42, 43, 0, 0, 0, 0,
+ 0, 12, 15, 30, 2, 2, 2, 2, 30, 2, 30, 2, 2, 2, 2, 2,
+ 2, 9, 2, 30, 2, 2, 0, 17, 18, 19, 20, 21, 27, 22, 35, 24,
+ 0, 0, 0, 0, 0, 30, 41, 41, 44, 12, 29, 30, 2, 2, 2, 9,
+ 30, 9, 2, 30, 2, 2, 0, 17, 45, 0, 0, 27, 22, 0, 0, 2,
+ 30, 30, 0, 0, 0, 0, 0, 0, 0, 0, 46, 30, 2, 2, 9, 0,
+ 2, 9, 2, 2, 0, 30, 9, 9, 2, 0, 30, 9, 0, 2, 9, 0,
+ 2, 2, 2, 2, 2, 2, 0, 0, 23, 16, 47, 0, 48, 33, 48, 34,
+ 0, 0, 0, 0, 35, 0, 0, 0, 0, 15, 29, 49, 2, 2, 2, 9,
+ 2, 9, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 17,
+ 22, 16, 23, 47, 22, 38, 22, 39, 0, 0, 0, 27, 31, 2, 9, 0,
+ 0, 10, 29, 30, 2, 2, 2, 9, 2, 2, 2, 30, 2, 2, 0, 17,
+ 45, 0, 0, 35, 47, 0, 0, 0, 9, 50, 51, 0, 0, 0, 0, 0,
+ 0, 11, 29, 2, 2, 2, 2, 9, 2, 2, 2, 2, 2, 2, 52, 53,
+ 23, 23, 19, 31, 48, 33, 48, 34, 54, 0, 0, 0, 35, 0, 0, 0,
+ 30, 12, 29, 30, 2, 2, 2, 2, 2, 2, 2, 2, 9, 0, 2, 2,
+ 2, 2, 30, 2, 2, 2, 2, 30, 0, 2, 2, 2, 9, 0, 55, 0,
+ 35, 23, 22, 31, 31, 18, 48, 48, 25, 0, 23, 0, 0, 0, 0, 0,
+ 0, 2, 0, 2, 9, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0,
+ 0, 2, 2, 56, 56, 57, 0, 0, 18, 2, 2, 2, 2, 30, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 9, 0, 58, 21, 59, 22, 22, 20, 20,
+ 46, 21, 11, 31, 11, 2, 2, 60, 61, 61, 61, 61, 61, 62, 61, 61,
+ 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 63,
+ 0, 0, 0, 0, 64, 0, 0, 0, 0, 2, 2, 2, 2, 2, 65, 45,
+ 59, 66, 22, 22, 67, 68, 69, 70, 71, 2, 2, 2, 2, 2, 1, 0,
+ 5, 2, 2, 2, 23, 20, 2, 2, 72, 71, 73, 74, 65, 73, 29, 29,
+ 2, 52, 22, 53, 2, 2, 2, 2, 2, 2, 75, 76, 77, 29, 29, 78,
+ 79, 2, 2, 2, 2, 2, 29, 45, 0, 2, 59, 80, 0, 0, 0, 0,
+ 30, 2, 59, 47, 0, 0, 0, 0, 0, 2, 59, 0, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 2, 9, 2, 9, 59, 0, 0, 0, 0, 0,
+ 0, 2, 2, 81, 45, 22, 59, 20, 48, 48, 48, 48, 15, 82, 83, 84,
+ 85, 86, 87, 0, 0, 0, 0, 88, 0, 9, 0, 0, 30, 0, 89, 81,
+ 90, 2, 2, 2, 2, 9, 0, 0, 0, 42, 42, 91, 92, 2, 2, 2,
+ 2, 2, 2, 2, 2, 13, 9, 0, 0, 93, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 9, 22, 80, 45, 22, 94, 61, 0,
+ 0, 95, 96, 95, 95, 97, 98, 0, 0, 2, 2, 2, 2, 2, 2, 2,
+ 0, 2, 2, 9, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0,
+ 0, 2, 2, 2, 2, 29, 0, 0, 0, 2, 2, 2, 2, 2, 9, 0,
+ 0, 2, 2, 2, 52, 99, 45, 0, 0, 2, 2, 100, 101, 102, 103, 61,
+ 63, 104, 16, 45, 22, 59, 21, 80, 48, 48, 76, 11, 11, 11, 105, 46,
+ 40, 11, 106, 74, 2, 2, 2, 2, 2, 2, 2, 107, 22, 20, 20, 22,
+ 48, 48, 22, 108, 2, 2, 2, 9, 0, 0, 0, 0, 0, 0, 109, 110,
+ 111, 111, 111, 0, 0, 0, 0, 0, 0, 106, 74, 2, 2, 2, 2, 2,
+ 2, 60, 61, 59, 25, 22, 112, 61, 2, 2, 2, 2, 107, 22, 23, 45,
+ 45, 102, 14, 0, 0, 0, 0, 0, 0, 2, 2, 61, 18, 48, 23, 113,
+ 102, 102, 102, 114, 115, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 30,
+ 2, 11, 46, 116, 116, 116, 11, 116, 116, 15, 116, 116, 116, 26, 0, 40,
+ 0, 0, 0, 117, 51, 11, 5, 0, 0, 0, 0, 0, 0, 0, 118, 0,
+ 0, 0, 0, 0, 0, 0, 6, 119, 120, 42, 42, 5, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 120, 120, 121, 120, 120, 120, 120, 120, 120, 120,
+ 120, 0, 0, 122, 0, 0, 0, 0, 0, 0, 7, 122, 0, 0, 0, 0,
+ 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,
+ 0, 0, 0, 0, 123, 123, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0,
+ 30, 0, 0, 0, 0, 0, 0, 0, 124, 0, 123, 123, 0, 0, 0, 0,
+ 0, 2, 53, 2, 108, 2, 10, 2, 2, 2, 65, 19, 16, 0, 0, 31,
+ 0, 2, 2, 0, 0, 0, 0, 0, 0, 29, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 125, 23, 23, 23, 23, 23, 23, 23, 126, 0, 0, 0, 0,
+ 0, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 0, 0, 0, 0, 0,
+ 52, 2, 2, 2, 22, 22, 127, 116, 0, 2, 2, 2, 128, 20, 59, 20,
+ 113, 102, 129, 0, 0, 0, 0, 0, 0, 11, 130, 2, 2, 2, 2, 2,
+ 2, 2, 131, 23, 22, 20, 48, 132, 133, 134, 0, 0, 0, 0, 0, 0,
+ 0, 2, 2, 52, 30, 2, 2, 2, 2, 2, 2, 2, 2, 10, 22, 59,
+ 99, 76, 135, 136, 137, 0, 0, 0, 0, 2, 138, 2, 2, 2, 2, 139,
+ 0, 30, 2, 42, 5, 0, 79, 15, 2, 53, 22, 140, 52, 53, 2, 2,
+ 105, 10, 9, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 141, 21,
+ 25, 0, 0, 142, 143, 0, 0, 0, 0, 2, 65, 45, 23, 80, 47, 144,
+ 0, 81, 81, 81, 81, 81, 81, 81, 81, 0, 0, 0, 0, 0, 0, 0,
+ 6, 120, 120, 120, 120, 121, 0, 0, 0, 2, 2, 2, 2, 2, 9, 2,
+ 2, 2, 9, 2, 30, 2, 2, 2, 2, 2, 30, 2, 2, 2, 30, 9,
+ 0, 128, 20, 27, 31, 0, 0, 145, 146, 2, 2, 30, 2, 30, 2, 2,
+ 2, 2, 2, 2, 0, 14, 37, 0, 147, 2, 2, 13, 37, 0, 30, 2,
+ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 2, 2,
+ 9, 2, 2, 11, 41, 0, 0, 0, 0, 2, 2, 2, 2, 2, 27, 38,
+ 0, 2, 2, 2, 116, 116, 116, 116, 116, 148, 2, 9, 0, 0, 0, 0,
+ 0, 2, 14, 14, 0, 0, 0, 0, 0, 9, 2, 2, 9, 2, 2, 2,
+ 2, 30, 2, 9, 0, 30, 2, 0, 0, 149, 150, 151, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 22, 22, 20, 20, 20, 22, 22, 134, 0, 0, 0,
+ 0, 0, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 2, 2, 2, 2,
+ 2, 53, 52, 53, 0, 0, 0, 0, 153, 11, 74, 2, 2, 2, 2, 2,
+ 2, 18, 19, 21, 16, 24, 37, 0, 0, 0, 31, 0, 0, 0, 0, 0,
+ 0, 11, 49, 2, 2, 2, 2, 2, 2, 2, 2, 2, 128, 20, 22, 154,
+ 22, 21, 155, 156, 2, 2, 2, 2, 2, 0, 0, 65, 157, 0, 0, 0,
+ 0, 2, 13, 0, 0, 0, 0, 0, 0, 2, 65, 25, 20, 20, 20, 22,
+ 22, 108, 158, 0, 0, 56, 159, 31, 160, 30, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 23, 19, 22, 22, 161, 44, 0, 0, 0,
+ 49, 128, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 9, 9, 2, 2,
+ 30, 2, 2, 2, 2, 2, 2, 2, 30, 2, 2, 2, 2, 2, 2, 2,
+ 10, 18, 19, 21, 22, 162, 31, 0, 0, 11, 11, 30, 2, 2, 2, 9,
+ 30, 9, 2, 30, 2, 2, 58, 17, 23, 16, 23, 47, 32, 33, 32, 34,
+ 0, 0, 0, 0, 35, 0, 0, 0, 2, 2, 23, 0, 11, 11, 11, 46,
+ 0, 11, 11, 46, 0, 0, 0, 0, 0, 2, 2, 65, 25, 20, 20, 20,
+ 22, 23, 126, 15, 17, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0,
+ 163, 164, 0, 0, 0, 0, 0, 0, 0, 18, 19, 20, 20, 66, 99, 25,
+ 160, 11, 165, 9, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2,
+ 65, 25, 20, 20, 0, 48, 48, 11, 166, 37, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 2, 2, 20, 0, 23, 19, 20, 20, 21, 16, 82,
+ 166, 38, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 10, 167,
+ 25, 20, 22, 22, 165, 9, 0, 0, 0, 2, 2, 2, 2, 2, 9, 43,
+ 136, 23, 22, 20, 76, 21, 22, 0, 0, 2, 2, 2, 9, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 2, 18, 19, 20, 21, 22, 105, 166, 37, 0,
+ 0, 2, 2, 2, 9, 30, 0, 2, 2, 2, 2, 30, 9, 2, 2, 2,
+ 2, 23, 23, 18, 32, 33, 12, 168, 169, 170, 171, 0, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 0, 2, 2, 2, 65, 25, 20, 20, 0, 22, 23,
+ 29, 108, 0, 33, 0, 0, 0, 0, 0, 52, 20, 22, 22, 22, 140, 2,
+ 2, 2, 172, 173, 11, 15, 174, 72, 175, 0, 0, 1, 147, 0, 0, 0,
+ 0, 52, 20, 22, 16, 19, 20, 2, 2, 2, 2, 158, 158, 158, 176, 176,
+ 176, 176, 176, 176, 15, 177, 0, 30, 0, 22, 20, 20, 31, 22, 22, 11,
+ 166, 0, 61, 61, 61, 61, 61, 61, 61, 66, 21, 82, 46, 0, 0, 0,
+ 0, 2, 2, 2, 9, 2, 30, 2, 2, 52, 22, 22, 31, 0, 38, 22,
+ 27, 11, 159, 178, 174, 0, 0, 0, 0, 2, 2, 2, 30, 9, 2, 2,
+ 2, 2, 2, 2, 2, 2, 23, 23, 47, 22, 35, 82, 68, 0, 0, 0,
+ 0, 2, 179, 66, 47, 0, 0, 0, 0, 11, 180, 2, 2, 2, 2, 2,
+ 2, 2, 2, 23, 22, 20, 31, 0, 48, 16, 143, 0, 0, 0, 0, 0,
+ 0, 181, 181, 181, 181, 181, 181, 181, 181, 182, 182, 182, 183, 184, 182, 181,
+ 181, 185, 181, 181, 186, 187, 187, 187, 187, 187, 187, 187, 0, 0, 0, 0,
+ 0, 11, 11, 11, 46, 0, 0, 0, 0, 2, 2, 2, 2, 2, 9, 0,
+ 58, 188, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 0, 0, 0, 40, 116, 26, 0, 0, 0, 0, 0,
+ 0, 0, 0, 9, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 0, 58, 37, 0, 6, 120, 120, 120, 121, 0,
+ 0, 11, 11, 11, 49, 2, 2, 2, 0, 2, 2, 2, 2, 2, 0, 0,
+ 2, 2, 2, 2, 2, 2, 2, 2, 46, 2, 2, 2, 2, 2, 2, 11,
+ 11, 2, 2, 2, 2, 2, 2, 22, 22, 2, 2, 44, 44, 44, 92, 0,
+ 0, O, O, O, GB, B, B, O, SB, O, SE, GB, O, O, WJ,FMPst,
+ FMPst, O, CGJ, B, O, B,VMAbv,VMAbv,VMAbv, O,VMAbv, B,CMBlw,CMBlw,CMBlw,VMAbv,
+ VMPst, VAbv, VPst,CMBlw, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst,
+ VPst, VPst, H, VPre, VPst,VMBlw, O, O, VAbv, GB,VMAbv,VMPst,VMPst, O, B, VBlw,
+ O, O, VPre, VPre, O, VPre, H, O, VPst,FMAbv, O,CMBlw, O, VAbv, O, VAbv,
+ H, O,VMBlw,VMAbv,CMAbv, GB, GB, O, MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv, O, VPst,
+ O, VPre, VPre,VMAbv, B, O, CS, CS,VMPst, B, VAbv, VAbv, B, R, O, HVM,
+ O, O,FMBlw, O,CMAbv, O,CMBlw, VAbv, VBlw, B, SUB, SUB, SUB, O, SUB, SUB,
+ O,FMBlw, O, B, VPst, VBlw, VPre,VMAbv,VMBlw,VMPst, IS, VAbv, MPst, MPre, MBlw, MBlw,
+ B, MBlw, MBlw, VPst,VMPst,VMPst, B, MBlw, VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw, B,
+ VMPst, VBlw, VPst, CGJ, CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv, IS,
+ FMAbv, B,FMAbv, B, CGJ, WJ, CGJ, GB,CMAbv,CMAbv, B, GB, B, VAbv, SUB, FPst,
+ FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre, B, MPre, MBlw, SUB, FAbv, FAbv, MAbv,
+ SUB, Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst, H, B, O,SMAbv,SMBlw,SMAbv,SMAbv,
+ SMAbv, VPst, IS, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv, CS, O,FMAbv, ZWNJ,
+ CGJ, WJ, WJ, WJ, O,FMPst, O, SB, SE, O, H, MPst, VPst, H,VMAbv, VAbv,
+ VMBlw, B, VBlw, FPst, VPst, FAbv,VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, H, O, VBlw,
+ MPst, MPre, MAbv, MBlw, O, B, FAbv, FAbv, FPst, VBlw, B, B, VPre, O,VMPst, IS,
+ O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS,
+ B, N, N, O, HN, VPre, VBlw, VAbv, IS,CMAbv, O, VPst, B, R, R,CMBlw,
+ VAbv, VPre,VMAbv,VMAbv, H, VAbv,CMBlw,FMAbv, B, CS, CS, H,CMBlw,VMPst, H,VMPst,
+ VAbv,VMAbv, VPst, IS, R, MPst, R, MPst,CMBlw, B,FMBlw, VBlw,VMAbv, R, MBlw, MBlw,
+ GB, FBlw, FBlw,CMAbv, IS, VBlw, IS, GB, VAbv, R,VMPst, G, G, J, J, J,
+ SB, SE, J, HR, G, G, HM, HM, HM, O, VBlw,
};
static const uint16_t
-hb_use_u16[448] =
+hb_use_u16[456] =
{
- 0, 0, 1, 2, 3, 4, 0, 5, 6, 0, 7, 0, 8, 9, 10, 11,
- 9, 12, 13, 9, 9, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
- 17, 25, 26, 20, 21, 27, 28, 29, 30, 31, 32, 33, 21, 34, 35, 0,
- 17, 36, 37, 20, 21, 38, 23, 39, 17, 40, 41, 42, 43, 44, 45, 46,
- 30, 0, 47, 48, 21, 49, 50, 51, 17, 0, 52, 48, 21, 53, 50, 54,
- 17, 55, 56, 48, 9, 57, 58, 59, 60, 61, 9, 62, 63, 64, 30, 65,
- 66, 67, 9, 68, 69, 9, 70, 71, 72, 73, 74, 75, 76, 0, 9, 9,
- 77, 78, 79, 80, 81, 82, 83, 84, 9, 85, 9, 86, 9, 87, 88, 89,
- 9, 90, 91, 92, 2, 0, 93, 0, 9, 94, 95, 9, 96, 0, 97, 98,
- 99,100, 30, 9,101,102,103, 9,104,105, 9,106, 9,107,108,109,
- 2, 2,110, 9, 9,111,112, 2,113,114,115, 9,116, 9,117,118,
- 119,120,121, 0, 0,122,123,124, 0,125,126,127,128, 0,129,130,
- 131, 0, 0,132,133, 0, 0, 9,134,135,136, 9,137, 0, 9,138,
- 139, 9, 9,140,141, 2,142,143,144, 9,145,146,147, 9, 9,148,
- 149, 2,150, 98,151,152,153, 2, 9,154, 9,155,156, 0,157,158,
- 159, 2,160, 0, 0,161, 0,162, 0,163,163,164, 33,165,166,167,
- 9,168, 94, 0,169, 0, 9,170,171, 0,172, 2,173,170,174,175,
- 176, 0, 0,177,178, 0,179, 9, 9,180,181,182,183,184,185, 9,
- 9,186,187, 0,188, 9,189,190,191, 9, 9,192, 9,193,194,105,
- 195,102, 9, 33,196,197,198, 0,199,200, 94, 9, 9,201,202, 2,
- 203, 20, 21,204,205,206,207,208, 9,209,210,211,212, 0,195, 9,
- 9,213,214, 2,215,216,217,218, 9,219,220, 2,221,222, 9,223,
- 224,103,225, 0,226,227,228,229, 9,230,231, 2,232, 9, 9,233,
- 234, 0,235, 9, 9,236,237,238,239,240, 21, 9,215,241, 7, 9,
- 70, 18, 9,242, 73,243,244, 9, 9,245,246, 2,247, 9,248,249,
- 9,250,251, 48, 9,252,253, 2, 9,254,255,256, 9,257,258,259,
- 260,260,261,262,263, 0, 9,264,105, 70, 94,265, 0,266, 70,267,
- 268, 0,269, 0,270, 2,271, 2,272, 2,129,129,160,160,160,129,
+ 0, 0, 1, 2, 0, 3, 4, 5, 0, 6, 7, 0, 8, 0, 9, 10,
+ 11, 12, 10, 13, 14, 10, 10, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 18, 26, 27, 21, 22, 28, 29, 30, 31, 32, 33, 34, 22, 35,
+ 36, 0, 18, 37, 38, 21, 22, 39, 24, 40, 18, 41, 42, 43, 44, 45,
+ 46, 47, 31, 0, 48, 49, 22, 50, 51, 52, 18, 0, 53, 49, 22, 54,
+ 51, 55, 18, 56, 57, 49, 10, 58, 59, 60, 61, 62, 10, 63, 64, 65,
+ 31, 66, 67, 68, 10, 69, 70, 10, 71, 72, 73, 74, 75, 76, 77, 0,
+ 10, 10, 78, 79, 80, 81, 82, 83, 84, 85, 10, 86, 10, 87, 10, 88,
+ 89, 90, 10, 91, 92, 93, 2, 0, 94, 0, 10, 95, 96, 10, 97, 0,
+ 98, 99,100,101, 31, 10,102,103,104, 10,105,106, 10,107, 10,108,
+ 109,110, 2, 2,111, 10, 10,112,113, 2,114,115,116, 10,117, 10,
+ 118,119,120,121,122, 0, 0,123,124,125, 0,126,127,128,129, 0,
+ 130,131,132, 0, 0,133,134, 0,135, 0, 0, 10,136,137,138, 0,
+ 139, 10,140, 0, 10,141,142, 10, 10,143,144, 2,145,146,147, 10,
+ 148,149,150, 10, 10,151,152, 2,153, 99,154,155,156, 2, 10,157,
+ 10,158,159, 0,160,161,162, 2,163, 0, 0,164, 0,165, 0,166,
+ 166,167, 34,168,169,170, 10,171, 95, 0,172, 0, 10,173,174, 0,
+ 175, 2,176,173,177,178,179, 0, 0,180,181, 0,182, 10, 10,183,
+ 184,185,186,187,188, 10, 10,189,190, 0,191, 10,192,193,194, 10,
+ 10,195, 10,196,197,106,198,103, 10, 34,199,200,201, 0,202,203,
+ 95, 10, 10,204,205, 2,206, 21, 22,207,208,209,210,211, 10,212,
+ 213,214,215, 0,198, 10, 10,216,217, 2,218,219,220,221, 10,222,
+ 223, 2,224,225, 10,226,227,104,228, 0,229,230,231,232, 10,233,
+ 234, 2,235, 10, 10,236,237, 0,238, 10, 10,239,240,241,242,243,
+ 22, 10,218,244, 8, 10, 71, 19, 10,245, 74,246,247, 10, 10,248,
+ 249, 2,250, 10,251,252, 10,253,254, 49, 10,255,256, 2,257,257,
+ 257,258,259,260, 10,261,262,263,264,264,265,266,267, 0, 10,268,
+ 106, 71, 95,269, 0,270, 71,271,272, 0,273, 0,274, 2,275, 2,
+ 276, 2,130,130,163,163,163,130,
};
static inline unsigned
@@ -622,7 +636,7 @@ hb_use_b4 (const uint8_t* a, unsigned i)
static inline uint_fast8_t
hb_use_get_category (unsigned u)
{
- return u<921600u?hb_use_u8[3049+(((hb_use_u8[865+(((hb_use_u16[((hb_use_u8[353+(((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>1>>3>>4))<<4)+((u>>1>>3>>1>>3)&15u))])<<3)+((u>>1>>3>>1)&7u))])<<1)+((u>>1>>3)&1u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
+ return u<921600u?hb_use_u8[3105+(((hb_use_u8[889+(((hb_use_u16[((hb_use_u8[353+(((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>1>>3>>4))<<4)+((u>>1>>3>>1>>3)&15u))])<<3)+((u>>1>>3>>1)&7u))])<<1)+((u>>1>>3)&1u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
}
#endif
@@ -633,7 +647,9 @@ hb_use_get_category (unsigned u)
#undef G
#undef GB
#undef H
+#undef HM
#undef HN
+#undef HR
#undef HVM
#undef IS
#undef J
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use.cc
index 342aba1235..c35765af95 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-use.cc
@@ -377,6 +377,9 @@ reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end)
#define POST_BASE_FLAGS64 (FLAG64 (USE(FAbv)) | \
FLAG64 (USE(FBlw)) | \
FLAG64 (USE(FPst)) | \
+ FLAG64 (USE(FMAbv)) | \
+ FLAG64 (USE(FMBlw)) | \
+ FLAG64 (USE(FMPst)) | \
FLAG64 (USE(MAbv)) | \
FLAG64 (USE(MBlw)) | \
FLAG64 (USE(MPst)) | \
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-vowel-constraints.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-vowel-constraints.cc
index e76b554b00..d1ed894596 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-vowel-constraints.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-shaper-vowel-constraints.cc
@@ -10,8 +10,8 @@
* # Date: 2015-03-12, 21:17:00 GMT [AG]
* # Date: 2019-11-08, 23:22:00 GMT [AG]
*
- * # Scripts-15.0.0.txt
- * # Date: 2022-04-26, 23:15:02 GMT
+ * # Scripts-15.1.0.txt
+ * # Date: 2023-07-28, 16:01:07 GMT
*/
#include "hb.hh"
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh
index 2006f677d1..e88c82a13c 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-stat-table.hh
@@ -57,6 +57,16 @@ enum
// Reserved = 0xFFFC /* Reserved for future use — set to zero. */
};
+static bool axis_value_is_outside_axis_range (hb_tag_t axis_tag, float axis_value,
+ const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location)
+{
+ if (!user_axes_location->has (axis_tag))
+ return false;
+
+ Triple axis_range = user_axes_location->get (axis_tag);
+ return (axis_value < axis_range.minimum || axis_value > axis_range.maximum);
+}
+
struct StatAxisRecord
{
int cmp (hb_tag_t key) const { return tag.cmp (key); }
@@ -96,23 +106,19 @@ struct AxisValueFormat1
}
bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
- const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+ const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
{
hb_tag_t axis_tag = get_axis_tag (axis_records);
float axis_value = get_value ();
- if (!user_axes_location->has (axis_tag) ||
- fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f)
- return true;
-
- return false;
+ return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
}
bool subset (hb_subset_context_t *c,
const hb_array_t<const StatAxisRecord> axis_records) const
{
TRACE_SUBSET (this);
- const hb_hashmap_t<hb_tag_t, float>* user_axes_location = &c->plan->user_axes_location;
+ const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
if (keep_axis_value (axis_records, user_axes_location))
return_trace (c->serializer->embed (this));
@@ -155,23 +161,19 @@ struct AxisValueFormat2
}
bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
- const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+ const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
{
hb_tag_t axis_tag = get_axis_tag (axis_records);
float axis_value = get_value ();
- if (!user_axes_location->has (axis_tag) ||
- fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f)
- return true;
-
- return false;
+ return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
}
bool subset (hb_subset_context_t *c,
const hb_array_t<const StatAxisRecord> axis_records) const
{
TRACE_SUBSET (this);
- const hb_hashmap_t<hb_tag_t, float>* user_axes_location = &c->plan->user_axes_location;
+ const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
if (keep_axis_value (axis_records, user_axes_location))
return_trace (c->serializer->embed (this));
@@ -218,23 +220,19 @@ struct AxisValueFormat3
}
bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
- const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+ const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
{
hb_tag_t axis_tag = get_axis_tag (axis_records);
float axis_value = get_value ();
- if (!user_axes_location->has (axis_tag) ||
- fabsf(axis_value - user_axes_location->get (axis_tag)) < 0.001f)
- return true;
-
- return false;
+ return !axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location);
}
bool subset (hb_subset_context_t *c,
const hb_array_t<const StatAxisRecord> axis_records) const
{
TRACE_SUBSET (this);
- const hb_hashmap_t<hb_tag_t, float>* user_axes_location = &c->plan->user_axes_location;
+ const hb_hashmap_t<hb_tag_t, Triple>* user_axes_location = &c->plan->user_axes_location;
if (keep_axis_value (axis_records, user_axes_location))
return_trace (c->serializer->embed (this));
@@ -291,7 +289,7 @@ struct AxisValueFormat4
{ return axisValues.as_array (axisCount)[axis_index]; }
bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
- const hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+ const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
{
hb_array_t<const AxisValueRecord> axis_value_records = axisValues.as_array (axisCount);
@@ -301,8 +299,7 @@ struct AxisValueFormat4
float axis_value = rec.get_value ();
hb_tag_t axis_tag = axis_records[axis_idx].get_axis_tag ();
- if (user_axes_location->has (axis_tag) &&
- fabsf(axis_value - user_axes_location->get (axis_tag)) > 0.001f)
+ if (axis_value_is_outside_axis_range (axis_tag, axis_value, user_axes_location))
return false;
}
@@ -313,7 +310,7 @@ struct AxisValueFormat4
const hb_array_t<const StatAxisRecord> axis_records) const
{
TRACE_SUBSET (this);
- const hb_hashmap_t<hb_tag_t, float> *user_axes_location = &c->plan->user_axes_location;
+ const hb_hashmap_t<hb_tag_t, Triple> *user_axes_location = &c->plan->user_axes_location;
if (!keep_axis_value (axis_records, user_axes_location))
return_trace (false);
@@ -330,6 +327,7 @@ struct AxisValueFormat4
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
+ hb_barrier () &&
axisValues.sanitize (c, axisCount)));
}
@@ -351,7 +349,7 @@ struct AxisValueFormat4
struct AxisValue
{
- bool get_value (unsigned int axis_index) const
+ float get_value (unsigned int axis_index) const
{
switch (u.format)
{
@@ -359,7 +357,7 @@ struct AxisValue
case 2: return u.format2.get_value ();
case 3: return u.format3.get_value ();
case 4: return u.format4.get_axis_record (axis_index).get_value ();
- default:return 0;
+ default:return 0.f;
}
}
@@ -402,7 +400,7 @@ struct AxisValue
}
bool keep_axis_value (const hb_array_t<const StatAxisRecord> axis_records,
- hb_hashmap_t<hb_tag_t, float> *user_axes_location) const
+ hb_hashmap_t<hb_tag_t, Triple> *user_axes_location) const
{
switch (u.format)
{
@@ -419,6 +417,7 @@ struct AxisValue
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
+ hb_barrier ();
switch (u.format)
{
@@ -451,8 +450,6 @@ struct AxisValueOffsetArray: UnsizedArrayOf<Offset16To<AxisValue>>
const hb_array_t<const StatAxisRecord> axis_records) const
{
TRACE_SUBSET (this);
- auto *out = c->serializer->start_embed (this);
- if (unlikely (!out)) return_trace (false);
auto axisValueOffsets = as_array (axisValueCount);
count = 0;
@@ -488,7 +485,7 @@ struct STAT
hb_array_t<const Offset16To<AxisValue>> axis_values = get_axis_value_offsets ();
for (unsigned int i = 0; i < axis_values.length; i++)
{
- const AxisValue& axis_value = this+axis_values[i];
+ const AxisValue& axis_value = this+offsetToAxisValueOffsets+axis_values[i];
if (axis_value.get_axis_index () == axis_index)
{
if (value)
@@ -517,7 +514,7 @@ struct STAT
return axis_value.get_value_name_id ();
}
- void collect_name_ids (hb_hashmap_t<hb_tag_t, float> *user_axes_location,
+ void collect_name_ids (hb_hashmap_t<hb_tag_t, Triple> *user_axes_location,
hb_set_t *nameids_to_retain /* OUT */) const
{
if (!has_data ()) return;
@@ -536,6 +533,8 @@ struct STAT
| hb_map (&AxisValue::get_value_name_id)
| hb_sink (nameids_to_retain)
;
+
+ nameids_to_retain->add (elidedFallbackNameID);
}
bool subset (hb_subset_context_t *c) const
@@ -563,6 +562,7 @@ struct STAT
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
+ hb_barrier () &&
version.major == 1 &&
version.minor > 0 &&
designAxesOffset.sanitize (c, this, designAxisCount) &&
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag-table.hh
index 9394b90ee6..db92f4664a 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag-table.hh
@@ -6,8 +6,8 @@
*
* on files with these headers:
*
- * <meta name="updated_at" content="2022-01-28 10:00 PM" />
- * File-Date: 2022-03-02
+ * <meta name="updated_at" content="2023-09-30 01:21 AM" />
+ * File-Date: 2024-03-07
*/
#ifndef HB_OT_TAG_TABLE_HH
@@ -31,7 +31,7 @@ static const LangTag ot_languages2[] = {
{HB_TAG('b','i',' ',' '), HB_TAG('B','I','S',' ')}, /* Bislama */
{HB_TAG('b','i',' ',' '), HB_TAG('C','P','P',' ')}, /* Bislama -> Creoles */
{HB_TAG('b','m',' ',' '), HB_TAG('B','M','B',' ')}, /* Bambara (Bamanankan) */
- {HB_TAG('b','n',' ',' '), HB_TAG('B','E','N',' ')}, /* Bengali */
+ {HB_TAG('b','n',' ',' '), HB_TAG('B','E','N',' ')}, /* Bangla */
{HB_TAG('b','o',' ',' '), HB_TAG('T','I','B',' ')}, /* Tibetan */
{HB_TAG('b','r',' ',' '), HB_TAG('B','R','E',' ')}, /* Breton */
{HB_TAG('b','s',' ',' '), HB_TAG('B','O','S',' ')}, /* Bosnian */
@@ -64,7 +64,7 @@ static const LangTag ot_languages2[] = {
{HB_TAG('f','r',' ',' '), HB_TAG('F','R','A',' ')}, /* French */
{HB_TAG('f','y',' ',' '), HB_TAG('F','R','I',' ')}, /* Western Frisian -> Frisian */
{HB_TAG('g','a',' ',' '), HB_TAG('I','R','I',' ')}, /* Irish */
- {HB_TAG('g','d',' ',' '), HB_TAG('G','A','E',' ')}, /* Scottish Gaelic (Gaelic) */
+ {HB_TAG('g','d',' ',' '), HB_TAG('G','A','E',' ')}, /* Scottish Gaelic */
{HB_TAG('g','l',' ',' '), HB_TAG('G','A','L',' ')}, /* Galician */
{HB_TAG('g','n',' ',' '), HB_TAG('G','U','A',' ')}, /* Guarani [macrolanguage] */
{HB_TAG('g','u',' ',' '), HB_TAG('G','U','J',' ')}, /* Gujarati */
@@ -132,7 +132,7 @@ static const LangTag ot_languages2[] = {
{HB_TAG('m','l',' ',' '), HB_TAG('M','A','L',' ')}, /* Malayalam -> Malayalam Traditional */
{HB_TAG('m','l',' ',' '), HB_TAG('M','L','R',' ')}, /* Malayalam -> Malayalam Reformed */
{HB_TAG('m','n',' ',' '), HB_TAG('M','N','G',' ')}, /* Mongolian [macrolanguage] */
- {HB_TAG('m','o',' ',' '), HB_TAG('M','O','L',' ')}, /* Moldavian (retired code) */
+ {HB_TAG('m','o',' ',' '), HB_TAG('M','O','L',' ')}, /* Moldavian (retired code) -> Romanian (Moldova) */
{HB_TAG('m','o',' ',' '), HB_TAG('R','O','M',' ')}, /* Moldavian (retired code) -> Romanian */
{HB_TAG('m','r',' ',' '), HB_TAG('M','A','R',' ')}, /* Marathi */
{HB_TAG('m','s',' ',' '), HB_TAG('M','L','Y',' ')}, /* Malay [macrolanguage] */
@@ -153,7 +153,7 @@ static const LangTag ot_languages2[] = {
{HB_TAG('o','c',' ',' '), HB_TAG('O','C','I',' ')}, /* Occitan (post 1500) */
{HB_TAG('o','j',' ',' '), HB_TAG('O','J','B',' ')}, /* Ojibwa [macrolanguage] -> Ojibway */
{HB_TAG('o','m',' ',' '), HB_TAG('O','R','O',' ')}, /* Oromo [macrolanguage] */
- {HB_TAG('o','r',' ',' '), HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) [macrolanguage] */
+ {HB_TAG('o','r',' ',' '), HB_TAG('O','R','I',' ')}, /* Odia [macrolanguage] */
{HB_TAG('o','s',' ',' '), HB_TAG('O','S','S',' ')}, /* Ossetian */
{HB_TAG('p','a',' ',' '), HB_TAG('P','A','N',' ')}, /* Punjabi */
{HB_TAG('p','i',' ',' '), HB_TAG('P','A','L',' ')}, /* Pali */
@@ -166,7 +166,7 @@ static const LangTag ot_languages2[] = {
{HB_TAG('r','o',' ',' '), HB_TAG('R','O','M',' ')}, /* Romanian */
{HB_TAG('r','u',' ',' '), HB_TAG('R','U','S',' ')}, /* Russian */
{HB_TAG('r','w',' ',' '), HB_TAG('R','U','A',' ')}, /* Kinyarwanda */
- {HB_TAG('s','a',' ',' '), HB_TAG('S','A','N',' ')}, /* Sanskrit */
+ {HB_TAG('s','a',' ',' '), HB_TAG('S','A','N',' ')}, /* Sanskrit [macrolanguage] */
{HB_TAG('s','c',' ',' '), HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */
{HB_TAG('s','d',' ',' '), HB_TAG('S','N','D',' ')}, /* Sindhi */
{HB_TAG('s','e',' ',' '), HB_TAG('N','S','M',' ')}, /* Northern Sami */
@@ -257,7 +257,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('a','i','i',' '), HB_TAG('S','Y','R',' ')}, /* Assyrian Neo-Aramaic -> Syriac */
/*{HB_TAG('a','i','o',' '), HB_TAG('A','I','O',' ')},*/ /* Aiton */
{HB_TAG('a','i','w',' '), HB_TAG('A','R','I',' ')}, /* Aari */
- {HB_TAG('a','j','p',' '), HB_TAG('A','R','A',' ')}, /* South Levantine Arabic -> Arabic */
+ {HB_TAG('a','j','p',' '), HB_TAG('A','R','A',' ')}, /* South Levantine Arabic (retired code) -> Arabic */
{HB_TAG('a','j','t',' '), HB_TAG('A','R','A',' ')}, /* Judeo-Tunisian Arabic (retired code) -> Arabic */
{HB_TAG('a','k','b',' '), HB_TAG('A','K','B',' ')}, /* Batak Angkola */
{HB_TAG('a','k','b',' '), HB_TAG('B','T','K',' ')}, /* Batak Angkola -> Batak */
@@ -269,7 +269,7 @@ static const LangTag ot_languages3[] = {
/*{HB_TAG('a','n','g',' '), HB_TAG('A','N','G',' ')},*/ /* Old English (ca. 450-1100) -> Anglo-Saxon */
{HB_TAG('a','o','a',' '), HB_TAG('C','P','P',' ')}, /* Angolar -> Creoles */
{HB_TAG('a','p','a',' '), HB_TAG('A','T','H',' ')}, /* Apache [collection] -> Athapaskan */
- {HB_TAG('a','p','c',' '), HB_TAG('A','R','A',' ')}, /* North Levantine Arabic -> Arabic */
+ {HB_TAG('a','p','c',' '), HB_TAG('A','R','A',' ')}, /* Levantine Arabic -> Arabic */
{HB_TAG('a','p','d',' '), HB_TAG('A','R','A',' ')}, /* Sudanese Arabic -> Arabic */
{HB_TAG('a','p','j',' '), HB_TAG('A','T','H',' ')}, /* Jicarilla Apache -> Athapaskan */
{HB_TAG('a','p','k',' '), HB_TAG('A','T','H',' ')}, /* Kiowa Apache -> Athapaskan */
@@ -465,6 +465,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('c','l','d',' '), HB_TAG('S','Y','R',' ')}, /* Chaldean Neo-Aramaic -> Syriac */
{HB_TAG('c','l','e',' '), HB_TAG('C','C','H','N')}, /* Lealao Chinantec -> Chinantec */
{HB_TAG('c','l','j',' '), HB_TAG('Q','I','N',' ')}, /* Laitu Chin -> Chin */
+ {HB_TAG('c','l','s',' '), HB_TAG('S','A','N',' ')}, /* Classical Sanskrit -> Sanskrit */
{HB_TAG('c','l','t',' '), HB_TAG('Q','I','N',' ')}, /* Lautu Chin -> Chin */
{HB_TAG('c','m','n',' '), HB_TAG('Z','H','S',' ')}, /* Mandarin Chinese -> Chinese, Simplified */
{HB_TAG('c','m','r',' '), HB_TAG('Q','I','N',' ')}, /* Mro-Khimi Chin -> Chin */
@@ -637,7 +638,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('g','a','a',' '), HB_TAG('G','A','D',' ')}, /* Ga */
{HB_TAG('g','a','c',' '), HB_TAG('C','P','P',' ')}, /* Mixed Great Andamanese -> Creoles */
{HB_TAG('g','a','d',' '), HB_TAG_NONE }, /* Gaddang != Ga */
- {HB_TAG('g','a','e',' '), HB_TAG_NONE }, /* Guarequena != Scottish Gaelic (Gaelic) */
+ {HB_TAG('g','a','e',' '), HB_TAG_NONE }, /* Guarequena != Scottish Gaelic */
/*{HB_TAG('g','a','g',' '), HB_TAG('G','A','G',' ')},*/ /* Gagauz */
{HB_TAG('g','a','l',' '), HB_TAG_NONE }, /* Galolen != Galician */
{HB_TAG('g','a','n',' '), HB_TAG('Z','H','S',' ')}, /* Gan Chinese -> Chinese, Simplified */
@@ -1160,7 +1161,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('o','r','o',' '), HB_TAG_NONE }, /* Orokolo != Oromo */
{HB_TAG('o','r','r',' '), HB_TAG('I','J','O',' ')}, /* Oruma -> Ijo */
{HB_TAG('o','r','s',' '), HB_TAG('M','L','Y',' ')}, /* Orang Seletar -> Malay */
- {HB_TAG('o','r','y',' '), HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) */
+ {HB_TAG('o','r','y',' '), HB_TAG('O','R','I',' ')}, /* Odia */
{HB_TAG('o','t','w',' '), HB_TAG('O','J','B',' ')}, /* Ottawa -> Ojibway */
{HB_TAG('o','u','a',' '), HB_TAG('B','B','R',' ')}, /* Tagargrent -> Berber */
{HB_TAG('p','a','a',' '), HB_TAG_NONE }, /* Papuan [collection] != Palestinian Aramaic */
@@ -1211,6 +1212,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('p','p','a',' '), HB_TAG('B','A','G',' ')}, /* Pao (retired code) -> Baghelkhandi */
{HB_TAG('p','r','e',' '), HB_TAG('C','P','P',' ')}, /* Principense -> Creoles */
/*{HB_TAG('p','r','o',' '), HB_TAG('P','R','O',' ')},*/ /* Old Provençal (to 1500) -> Provençal / Old Provençal */
+ {HB_TAG('p','r','p',' '), HB_TAG('G','U','J',' ')}, /* Parsi (retired code) -> Gujarati */
{HB_TAG('p','r','s',' '), HB_TAG('D','R','I',' ')}, /* Dari */
{HB_TAG('p','r','s',' '), HB_TAG('F','A','R',' ')}, /* Dari -> Persian */
{HB_TAG('p','s','e',' '), HB_TAG('M','L','Y',' ')}, /* Central Malay -> Malay */
@@ -1394,7 +1396,7 @@ static const LangTag ot_languages3[] = {
/*{HB_TAG('s','n','k',' '), HB_TAG('S','N','K',' ')},*/ /* Soninke */
{HB_TAG('s','o','g',' '), HB_TAG_NONE }, /* Sogdian != Sodo Gurage */
/*{HB_TAG('s','o','p',' '), HB_TAG('S','O','P',' ')},*/ /* Songe */
- {HB_TAG('s','p','v',' '), HB_TAG('O','R','I',' ')}, /* Sambalpuri -> Odia (formerly Oriya) */
+ {HB_TAG('s','p','v',' '), HB_TAG('O','R','I',' ')}, /* Sambalpuri -> Odia */
{HB_TAG('s','p','y',' '), HB_TAG('K','A','L',' ')}, /* Sabaot -> Kalenjin */
{HB_TAG('s','r','b',' '), HB_TAG_NONE }, /* Sora != Serbian */
{HB_TAG('s','r','c',' '), HB_TAG('S','R','D',' ')}, /* Logudorese Sardinian -> Sardinian */
@@ -1439,7 +1441,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('t','c','h',' '), HB_TAG('C','P','P',' ')}, /* Turks And Caicos Creole English -> Creoles */
{HB_TAG('t','c','p',' '), HB_TAG('Q','I','N',' ')}, /* Tawr Chin -> Chin */
{HB_TAG('t','c','s',' '), HB_TAG('C','P','P',' ')}, /* Torres Strait Creole -> Creoles */
- {HB_TAG('t','c','y',' '), HB_TAG('T','U','L',' ')}, /* Tulu -> Tumbuka */
+ {HB_TAG('t','c','y',' '), HB_TAG('T','U','L',' ')}, /* Tulu */
{HB_TAG('t','c','z',' '), HB_TAG('Q','I','N',' ')}, /* Thado Chin -> Chin */
/*{HB_TAG('t','d','d',' '), HB_TAG('T','D','D',' ')},*/ /* Tai Nüa -> Dehong Dai */
{HB_TAG('t','d','x',' '), HB_TAG('M','L','G',' ')}, /* Tandroy-Mahafaly Malagasy -> Malagasy */
@@ -1495,8 +1497,8 @@ static const LangTag ot_languages3[] = {
{HB_TAG('t','t','q',' '), HB_TAG('T','M','H',' ')}, /* Tawallammat Tamajaq -> Tamashek */
{HB_TAG('t','t','q',' '), HB_TAG('B','B','R',' ')}, /* Tawallammat Tamajaq -> Berber */
{HB_TAG('t','u','a',' '), HB_TAG_NONE }, /* Wiarumus != Turoyo Aramaic */
- {HB_TAG('t','u','l',' '), HB_TAG_NONE }, /* Tula != Tumbuka */
-/*{HB_TAG('t','u','m',' '), HB_TAG('T','U','M',' ')},*/ /* Tumbuka -> Tulu */
+ {HB_TAG('t','u','l',' '), HB_TAG_NONE }, /* Tula != Tulu */
+/*{HB_TAG('t','u','m',' '), HB_TAG('T','U','M',' ')},*/ /* Tumbuka */
{HB_TAG('t','u','u',' '), HB_TAG('A','T','H',' ')}, /* Tututni -> Athapaskan */
{HB_TAG('t','u','v',' '), HB_TAG_NONE }, /* Turkana != Tuvin */
{HB_TAG('t','u','y',' '), HB_TAG('K','A','L',' ')}, /* Tugen -> Kalenjin */
@@ -1532,6 +1534,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('v','l','s',' '), HB_TAG('F','L','E',' ')}, /* Vlaams -> Dutch (Flemish) */
{HB_TAG('v','m','w',' '), HB_TAG('M','A','K',' ')}, /* Makhuwa */
/*{HB_TAG('v','r','o',' '), HB_TAG('V','R','O',' ')},*/ /* Võro */
+ {HB_TAG('v','s','n',' '), HB_TAG('S','A','N',' ')}, /* Vedic Sanskrit -> Sanskrit */
{HB_TAG('w','a','g',' '), HB_TAG_NONE }, /* Wa'ema != Wagdi */
/*{HB_TAG('w','a','r',' '), HB_TAG('W','A','R',' ')},*/ /* Waray (Philippines) -> Waray-Waray */
{HB_TAG('w','b','m',' '), HB_TAG('W','A',' ',' ')}, /* Wa */
@@ -1581,6 +1584,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('y','b','a',' '), HB_TAG_NONE }, /* Yala != Yoruba */
{HB_TAG('y','b','b',' '), HB_TAG('B','M','L',' ')}, /* Yemba -> Bamileke */
{HB_TAG('y','b','d',' '), HB_TAG('A','R','K',' ')}, /* Yangbye (retired code) -> Rakhine */
+ {HB_TAG('y','c','r',' '), HB_TAG_NONE }, /* Yilan Creole != Y-Cree */
{HB_TAG('y','d','d',' '), HB_TAG('J','I','I',' ')}, /* Eastern Yiddish -> Yiddish */
/*{HB_TAG('y','g','p',' '), HB_TAG('Y','G','P',' ')},*/ /* Gepo */
{HB_TAG('y','i','h',' '), HB_TAG('J','I','I',' ')}, /* Western Yiddish -> Yiddish */
@@ -1602,6 +1606,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('z','g','n',' '), HB_TAG('Z','H','A',' ')}, /* Guibian Zhuang -> Zhuang */
{HB_TAG('z','h','d',' '), HB_TAG('Z','H','A',' ')}, /* Dai Zhuang -> Zhuang */
{HB_TAG('z','h','n',' '), HB_TAG('Z','H','A',' ')}, /* Nong Zhuang -> Zhuang */
+ {HB_TAG('z','k','b',' '), HB_TAG('K','H','A',' ')}, /* Koibal (retired code) -> Khakass */
{HB_TAG('z','l','j',' '), HB_TAG('Z','H','A',' ')}, /* Liujiang Zhuang -> Zhuang */
{HB_TAG('z','l','m',' '), HB_TAG('M','L','Y',' ')}, /* Malay */
{HB_TAG('z','l','n',' '), HB_TAG('Z','H','A',' ')}, /* Lianshan Zhuang -> Zhuang */
@@ -2640,7 +2645,7 @@ out:
/* Romanian; Moldova */
unsigned int i;
hb_tag_t possible_tags[] = {
- HB_TAG('M','O','L',' '), /* Moldavian */
+ HB_TAG('M','O','L',' '), /* Romanian (Moldova) */
HB_TAG('R','O','M',' '), /* Romanian */
};
for (i = 0; i < 2 && i < *count; i++)
@@ -2917,7 +2922,7 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("mn", -1); /* Mongolian [macrolanguage] */
case HB_TAG('M','N','K',' '): /* Maninka */
return hb_language_from_string ("man", -1); /* Mandingo [macrolanguage] */
- case HB_TAG('M','O','L',' '): /* Moldavian */
+ case HB_TAG('M','O','L',' '): /* Romanian (Moldova) */
return hb_language_from_string ("ro-MD", -1); /* Romanian; Moldova */
case HB_TAG('M','O','N','T'): /* Thailand Mon */
return hb_language_from_string ("mnw-TH", -1); /* Mon; Thailand */
@@ -2955,6 +2960,8 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("ro", -1); /* Romanian */
case HB_TAG('R','O','Y',' '): /* Romany */
return hb_language_from_string ("rom", -1); /* Romany [macrolanguage] */
+ case HB_TAG('S','A','N',' '): /* Sanskrit */
+ return hb_language_from_string ("sa", -1); /* Sanskrit [macrolanguage] */
case HB_TAG('S','Q','I',' '): /* Albanian */
return hb_language_from_string ("sq", -1); /* Albanian [macrolanguage] */
case HB_TAG('S','R','B',' '): /* Serbian */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc
index 547f9573d0..0c63756b14 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-tag.cc
@@ -412,7 +412,7 @@ parse_private_use_subtag (const char *private_use_subtag,
/**
* hb_ot_tags_from_script_and_language:
* @script: an #hb_script_t to convert.
- * @language: an #hb_language_t to convert.
+ * @language: (nullable): an #hb_language_t to convert.
* @script_count: (inout) (optional): maximum number of script tags to retrieve (IN)
* and actual number of script tags retrieved (OUT)
* @script_tags: (out) (optional): array of size at least @script_count to store the
@@ -547,7 +547,7 @@ hb_ot_tag_to_language (hb_tag_t tag)
buf[3] = '-';
str += 4;
}
- snprintf (str, 16, "x-hbot-%08x", tag);
+ snprintf (str, 16, "x-hbot-%08" PRIx32, tag);
return hb_language_from_string (&*buf, -1);
}
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh
index 3449b30499..9149959d79 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-avar-table.hh
@@ -57,7 +57,7 @@ struct avarV2Tail
protected:
Offset32To<DeltaSetIndexMap> varIdxMap; /* Offset from the beginning of 'avar' table. */
- Offset32To<VariationStore> varStore; /* Offset from the beginning of 'avar' table. */
+ Offset32To<ItemVariationStore> varStore; /* Offset from the beginning of 'avar' table. */
public:
DEFINE_SIZE_STATIC (8);
@@ -72,6 +72,65 @@ struct AxisValueMap
return_trace (c->check_struct (this));
}
+ void set_mapping (float from_coord, float to_coord)
+ {
+ coords[0].set_float (from_coord);
+ coords[1].set_float (to_coord);
+ }
+
+ bool is_outside_axis_range (const Triple& axis_range) const
+ {
+ float from_coord = coords[0].to_float ();
+ return !axis_range.contains (from_coord);
+ }
+
+ bool must_include () const
+ {
+ float from_coord = coords[0].to_float ();
+ float to_coord = coords[1].to_float ();
+ return (from_coord == -1.f && to_coord == -1.f) ||
+ (from_coord == 0.f && to_coord == 0.f) ||
+ (from_coord == 1.f && to_coord == 1.f);
+ }
+
+ void instantiate (const Triple& axis_range,
+ const Triple& unmapped_range,
+ const TripleDistances& triple_distances)
+ {
+ float from_coord = coords[0].to_float ();
+ float to_coord = coords[1].to_float ();
+
+ from_coord = renormalizeValue (from_coord, unmapped_range, triple_distances);
+ to_coord = renormalizeValue (to_coord, axis_range, triple_distances);
+
+ coords[0].set_float (from_coord);
+ coords[1].set_float (to_coord);
+ }
+
+ HB_INTERNAL static int cmp (const void *pa, const void *pb)
+ {
+ const AxisValueMap *a = (const AxisValueMap *) pa;
+ const AxisValueMap *b = (const AxisValueMap *) pb;
+
+ int a_from = a->coords[0].to_int ();
+ int b_from = b->coords[0].to_int ();
+ if (a_from != b_from)
+ return a_from - b_from;
+
+ /* this should never be reached. according to the spec, all of the axis
+ * value map records for a given axis must have different fromCoord values
+ * */
+ int a_to = a->coords[1].to_int ();
+ int b_to = b->coords[1].to_int ();
+ return a_to - b_to;
+ }
+
+ bool serialize (hb_serialize_context_t *c) const
+ {
+ TRACE_SERIALIZE (this);
+ return_trace (c->embed (this));
+ }
+
public:
F2DOT14 coords[2];
// F2DOT14 fromCoord; /* A normalized coordinate value obtained using
@@ -122,6 +181,78 @@ struct SegmentMaps : Array16Of<AxisValueMap>
int unmap (int value) const { return map (value, 1, 0); }
+ Triple unmap_axis_range (const Triple& axis_range) const
+ {
+ F2DOT14 val, unmapped_val;
+
+ val.set_float (axis_range.minimum);
+ unmapped_val.set_int (unmap (val.to_int ()));
+ float unmapped_min = unmapped_val.to_float ();
+
+ val.set_float (axis_range.middle);
+ unmapped_val.set_int (unmap (val.to_int ()));
+ float unmapped_middle = unmapped_val.to_float ();
+
+ val.set_float (axis_range.maximum);
+ unmapped_val.set_int (unmap (val.to_int ()));
+ float unmapped_max = unmapped_val.to_float ();
+
+ return Triple{unmapped_min, unmapped_middle, unmapped_max};
+ }
+
+ bool subset (hb_subset_context_t *c, hb_tag_t axis_tag) const
+ {
+ TRACE_SUBSET (this);
+ /* avar mapped normalized axis range*/
+ Triple *axis_range;
+ if (!c->plan->axes_location.has (axis_tag, &axis_range))
+ return c->serializer->embed (*this);
+
+ TripleDistances *axis_triple_distances;
+ if (!c->plan->axes_triple_distances.has (axis_tag, &axis_triple_distances))
+ return_trace (false);
+
+ auto *out = c->serializer->start_embed (this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+ Triple unmapped_range = unmap_axis_range (*axis_range);
+
+ /* create a vector of retained mappings and sort */
+ hb_vector_t<AxisValueMap> value_mappings;
+ for (const auto& _ : as_array ())
+ {
+ if (_.is_outside_axis_range (unmapped_range))
+ continue;
+ AxisValueMap mapping;
+ mapping = _;
+ mapping.instantiate (*axis_range, unmapped_range, *axis_triple_distances);
+ /* (-1, -1), (0, 0), (1, 1) mappings will be added later, so avoid
+ * duplicates here */
+ if (mapping.must_include ())
+ continue;
+ value_mappings.push (mapping);
+ }
+
+ AxisValueMap m;
+ m.set_mapping (-1.f, -1.f);
+ value_mappings.push (m);
+
+ m.set_mapping (0.f, 0.f);
+ value_mappings.push (m);
+
+ m.set_mapping (1.f, 1.f);
+ value_mappings.push (m);
+
+ value_mappings.qsort ();
+
+ for (const auto& _ : value_mappings)
+ {
+ if (!_.serialize (c->serializer))
+ return_trace (false);
+ }
+ return_trace (c->serializer->check_assign (out->len, value_mappings.length, HB_SERIALIZE_ERROR_INT_OVERFLOW));
+ }
+
public:
DEFINE_SIZE_ARRAY (2, *this);
};
@@ -142,6 +273,7 @@ struct avar
{
TRACE_SANITIZE (this);
if (!(version.sanitize (c) &&
+ hb_barrier () &&
(version.major == 1
#ifndef HB_NO_AVAR2
|| version.major == 2
@@ -162,6 +294,7 @@ struct avar
#ifndef HB_NO_AVAR2
if (version.major < 2)
return_trace (true);
+ hb_barrier ();
const auto &v2 = * (const avarV2Tail *) map;
if (unlikely (!v2.sanitize (c, this)))
@@ -185,6 +318,7 @@ struct avar
#ifndef HB_NO_AVAR2
if (version.major < 2)
return;
+ hb_barrier ();
for (; count < axisCount; count++)
map = &StructAfter<SegmentMaps> (*map);
@@ -209,7 +343,7 @@ struct avar
for (unsigned i = 0; i < coords_length; i++)
coords[i] = out[i];
- OT::VariationStore::destroy_cache (var_store_cache);
+ OT::ItemVariationStore::destroy_cache (var_store_cache);
#endif
}
@@ -225,6 +359,39 @@ struct avar
}
}
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ unsigned retained_axis_count = c->plan->axes_index_map.get_population ();
+ if (!retained_axis_count) //all axes are pinned/dropped
+ return_trace (false);
+
+ avar *out = c->serializer->allocate_min<avar> ();
+ if (unlikely (!out)) return_trace (false);
+
+ out->version.major = 1;
+ out->version.minor = 0;
+ if (!c->serializer->check_assign (out->axisCount, retained_axis_count, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+ return_trace (false);
+
+ const hb_map_t& axes_index_map = c->plan->axes_index_map;
+ const SegmentMaps *map = &firstAxisSegmentMaps;
+ unsigned count = axisCount;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ if (axes_index_map.has (i))
+ {
+ hb_tag_t *axis_tag;
+ if (!c->plan->axes_old_index_tag_map.has (i, &axis_tag))
+ return_trace (false);
+ if (!map->subset (c, *axis_tag))
+ return_trace (false);
+ }
+ map = &StructAfter<SegmentMaps> (*map);
+ }
+ return_trace (true);
+ }
+
protected:
FixedVersion<>version; /* Version of the avar table
* initially set to 0x00010000u */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh
index 4997c2e2e8..379e164059 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-common.hh
@@ -27,6 +27,8 @@
#define HB_OT_VAR_COMMON_HH
#include "hb-ot-layout-common.hh"
+#include "hb-priority-queue.hh"
+#include "hb-subset-instancer-iup.hh"
namespace OT {
@@ -36,19 +38,14 @@ struct DeltaSetIndexMapFormat01
{
friend struct DeltaSetIndexMap;
+ unsigned get_size () const
+ { return min_size + mapCount * get_width (); }
+
private:
DeltaSetIndexMapFormat01* copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
- auto *out = c->start_embed (this);
- if (unlikely (!out)) return_trace (nullptr);
-
- unsigned total_size = min_size + mapCount * get_width ();
- HBUINT8 *p = c->allocate_size<HBUINT8> (total_size);
- if (unlikely (!p)) return_trace (nullptr);
-
- hb_memcpy (p, this, HBUINT8::static_size * total_size);
- return_trace (out);
+ return_trace (c->embed (this));
}
template <typename T>
@@ -69,14 +66,17 @@ struct DeltaSetIndexMapFormat01
if (unlikely (!p)) return_trace (false);
for (unsigned int i = 0; i < output_map.length; i++)
{
- unsigned int v = output_map[i];
- unsigned int outer = v >> 16;
- unsigned int inner = v & 0xFFFF;
- unsigned int u = (outer << inner_bit_count) | inner;
- for (unsigned int w = width; w > 0;)
+ unsigned int v = output_map.arrayZ[i];
+ if (v)
{
- p[--w] = u;
- u >>= 8;
+ unsigned int outer = v >> 16;
+ unsigned int inner = v & 0xFFFF;
+ unsigned int u = (outer << inner_bit_count) | inner;
+ for (unsigned int w = width; w > 0;)
+ {
+ p[--w] = u;
+ u >>= 8;
+ }
}
p += width;
}
@@ -120,6 +120,7 @@ struct DeltaSetIndexMapFormat01
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
c->check_range (mapDataZ.arrayZ,
mapCount,
get_width ()));
@@ -192,6 +193,7 @@ struct DeltaSetIndexMap
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
+ hb_barrier ();
switch (u.format) {
case 0: return_trace (u.format0.sanitize (c));
case 1: return_trace (u.format1.sanitize (c));
@@ -220,23 +222,2161 @@ struct DeltaSetIndexMap
};
-struct VarStoreInstancer
+struct ItemVarStoreInstancer
{
- VarStoreInstancer (const VariationStore &varStore,
- const DeltaSetIndexMap &varIdxMap,
+ ItemVarStoreInstancer (const ItemVariationStore *varStore,
+ const DeltaSetIndexMap *varIdxMap,
hb_array_t<int> coords) :
varStore (varStore), varIdxMap (varIdxMap), coords (coords) {}
- operator bool () const { return bool (coords); }
+ operator bool () const { return varStore && bool (coords); }
+ /* according to the spec, if colr table has varStore but does not have
+ * varIdxMap, then an implicit identity mapping is used */
float operator() (uint32_t varIdx, unsigned short offset = 0) const
- { return varStore.get_delta (varIdxMap.map (VarIdx::add (varIdx, offset)), coords); }
+ { return coords ? varStore->get_delta (varIdxMap ? varIdxMap->map (VarIdx::add (varIdx, offset)) : varIdx + offset, coords) : 0; }
- const VariationStore &varStore;
- const DeltaSetIndexMap &varIdxMap;
+ const ItemVariationStore *varStore;
+ const DeltaSetIndexMap *varIdxMap;
hb_array_t<int> coords;
};
+/* https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader */
+struct TupleVariationHeader
+{
+ friend struct tuple_delta_t;
+ unsigned get_size (unsigned axis_count) const
+ { return min_size + get_all_tuples (axis_count).get_size (); }
+
+ unsigned get_data_size () const { return varDataSize; }
+
+ const TupleVariationHeader &get_next (unsigned axis_count) const
+ { return StructAtOffset<TupleVariationHeader> (this, get_size (axis_count)); }
+
+ bool unpack_axis_tuples (unsigned axis_count,
+ const hb_array_t<const F2DOT14> shared_tuples,
+ const hb_map_t *axes_old_index_tag_map,
+ hb_hashmap_t<hb_tag_t, Triple>& axis_tuples /* OUT */) const
+ {
+ const F2DOT14 *peak_tuple = nullptr;
+ if (has_peak ())
+ peak_tuple = get_peak_tuple (axis_count).arrayZ;
+ else
+ {
+ unsigned int index = get_index ();
+ if (unlikely ((index + 1) * axis_count > shared_tuples.length))
+ return false;
+ peak_tuple = shared_tuples.sub_array (axis_count * index, axis_count).arrayZ;
+ }
+
+ const F2DOT14 *start_tuple = nullptr;
+ const F2DOT14 *end_tuple = nullptr;
+ bool has_interm = has_intermediate ();
+
+ if (has_interm)
+ {
+ start_tuple = get_start_tuple (axis_count).arrayZ;
+ end_tuple = get_end_tuple (axis_count).arrayZ;
+ }
+
+ for (unsigned i = 0; i < axis_count; i++)
+ {
+ float peak = peak_tuple[i].to_float ();
+ if (peak == 0.f) continue;
+
+ hb_tag_t *axis_tag;
+ if (!axes_old_index_tag_map->has (i, &axis_tag))
+ return false;
+
+ float start, end;
+ if (has_interm)
+ {
+ start = start_tuple[i].to_float ();
+ end = end_tuple[i].to_float ();
+ }
+ else
+ {
+ start = hb_min (peak, 0.f);
+ end = hb_max (peak, 0.f);
+ }
+ axis_tuples.set (*axis_tag, Triple (start, peak, end));
+ }
+
+ return true;
+ }
+
+ float calculate_scalar (hb_array_t<int> coords, unsigned int coord_count,
+ const hb_array_t<const F2DOT14> shared_tuples,
+ const hb_vector_t<hb_pair_t<int,int>> *shared_tuple_active_idx = nullptr) const
+ {
+ const F2DOT14 *peak_tuple;
+
+ unsigned start_idx = 0;
+ unsigned end_idx = coord_count;
+ unsigned step = 1;
+
+ if (has_peak ())
+ peak_tuple = get_peak_tuple (coord_count).arrayZ;
+ else
+ {
+ unsigned int index = get_index ();
+ if (unlikely ((index + 1) * coord_count > shared_tuples.length))
+ return 0.f;
+ peak_tuple = shared_tuples.sub_array (coord_count * index, coord_count).arrayZ;
+
+ if (shared_tuple_active_idx)
+ {
+ if (unlikely (index >= shared_tuple_active_idx->length))
+ return 0.f;
+ auto _ = (*shared_tuple_active_idx).arrayZ[index];
+ if (_.second != -1)
+ {
+ start_idx = _.first;
+ end_idx = _.second + 1;
+ step = _.second - _.first;
+ }
+ else if (_.first != -1)
+ {
+ start_idx = _.first;
+ end_idx = start_idx + 1;
+ }
+ }
+ }
+
+ const F2DOT14 *start_tuple = nullptr;
+ const F2DOT14 *end_tuple = nullptr;
+ bool has_interm = has_intermediate ();
+ if (has_interm)
+ {
+ start_tuple = get_start_tuple (coord_count).arrayZ;
+ end_tuple = get_end_tuple (coord_count).arrayZ;
+ }
+
+ float scalar = 1.f;
+ for (unsigned int i = start_idx; i < end_idx; i += step)
+ {
+ int peak = peak_tuple[i].to_int ();
+ if (!peak) continue;
+
+ int v = coords[i];
+ if (v == peak) continue;
+
+ if (has_interm)
+ {
+ int start = start_tuple[i].to_int ();
+ int end = end_tuple[i].to_int ();
+ if (unlikely (start > peak || peak > end ||
+ (start < 0 && end > 0 && peak))) continue;
+ if (v < start || v > end) return 0.f;
+ if (v < peak)
+ { if (peak != start) scalar *= (float) (v - start) / (peak - start); }
+ else
+ { if (peak != end) scalar *= (float) (end - v) / (end - peak); }
+ }
+ else if (!v || v < hb_min (0, peak) || v > hb_max (0, peak)) return 0.f;
+ else
+ scalar *= (float) v / peak;
+ }
+ return scalar;
+ }
+
+ bool has_peak () const { return tupleIndex & TuppleIndex::EmbeddedPeakTuple; }
+ bool has_intermediate () const { return tupleIndex & TuppleIndex::IntermediateRegion; }
+ bool has_private_points () const { return tupleIndex & TuppleIndex::PrivatePointNumbers; }
+ unsigned get_index () const { return tupleIndex & TuppleIndex::TupleIndexMask; }
+
+ protected:
+ struct TuppleIndex : HBUINT16
+ {
+ enum Flags {
+ EmbeddedPeakTuple = 0x8000u,
+ IntermediateRegion = 0x4000u,
+ PrivatePointNumbers = 0x2000u,
+ TupleIndexMask = 0x0FFFu
+ };
+
+ TuppleIndex& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
+ DEFINE_SIZE_STATIC (2);
+ };
+
+ hb_array_t<const F2DOT14> get_all_tuples (unsigned axis_count) const
+ { return StructAfter<UnsizedArrayOf<F2DOT14>> (tupleIndex).as_array ((has_peak () + has_intermediate () * 2) * axis_count); }
+ hb_array_t<const F2DOT14> get_peak_tuple (unsigned axis_count) const
+ { return get_all_tuples (axis_count).sub_array (0, axis_count); }
+ hb_array_t<const F2DOT14> get_start_tuple (unsigned axis_count) const
+ { return get_all_tuples (axis_count).sub_array (has_peak () * axis_count, axis_count); }
+ hb_array_t<const F2DOT14> get_end_tuple (unsigned axis_count) const
+ { return get_all_tuples (axis_count).sub_array (has_peak () * axis_count + axis_count, axis_count); }
+
+ HBUINT16 varDataSize; /* The size in bytes of the serialized
+ * data for this tuple variation table. */
+ TuppleIndex tupleIndex; /* A packed field. The high 4 bits are flags (see below).
+ The low 12 bits are an index into a shared tuple
+ records array. */
+ /* UnsizedArrayOf<F2DOT14> peakTuple - optional */
+ /* Peak tuple record for this tuple variation table — optional,
+ * determined by flags in the tupleIndex value.
+ *
+ * Note that this must always be included in the 'cvar' table. */
+ /* UnsizedArrayOf<F2DOT14> intermediateStartTuple - optional */
+ /* Intermediate start tuple record for this tuple variation table — optional,
+ determined by flags in the tupleIndex value. */
+ /* UnsizedArrayOf<F2DOT14> intermediateEndTuple - optional */
+ /* Intermediate end tuple record for this tuple variation table — optional,
+ * determined by flags in the tupleIndex value. */
+ public:
+ DEFINE_SIZE_MIN (4);
+};
+
+enum packed_delta_flag_t
+{
+ DELTAS_ARE_ZERO = 0x80,
+ DELTAS_ARE_WORDS = 0x40,
+ DELTA_RUN_COUNT_MASK = 0x3F
+};
+
+struct tuple_delta_t
+{
+ static constexpr bool realloc_move = true; // Watch out when adding new members!
+
+ public:
+ hb_hashmap_t<hb_tag_t, Triple> axis_tuples;
+
+ /* indices_length = point_count, indice[i] = 1 means point i is referenced */
+ hb_vector_t<bool> indices;
+
+ hb_vector_t<float> deltas_x;
+ /* empty for cvar tuples */
+ hb_vector_t<float> deltas_y;
+
+ /* compiled data: header and deltas
+ * compiled point data is saved in a hashmap within tuple_variations_t cause
+ * some point sets might be reused by different tuple variations */
+ hb_vector_t<char> compiled_tuple_header;
+ hb_vector_t<char> compiled_deltas;
+
+ /* compiled peak coords, empty for non-gvar tuples */
+ hb_vector_t<char> compiled_peak_coords;
+
+ tuple_delta_t () = default;
+ tuple_delta_t (const tuple_delta_t& o) = default;
+
+ friend void swap (tuple_delta_t& a, tuple_delta_t& b) noexcept
+ {
+ hb_swap (a.axis_tuples, b.axis_tuples);
+ hb_swap (a.indices, b.indices);
+ hb_swap (a.deltas_x, b.deltas_x);
+ hb_swap (a.deltas_y, b.deltas_y);
+ hb_swap (a.compiled_tuple_header, b.compiled_tuple_header);
+ hb_swap (a.compiled_deltas, b.compiled_deltas);
+ hb_swap (a.compiled_peak_coords, b.compiled_peak_coords);
+ }
+
+ tuple_delta_t (tuple_delta_t&& o) noexcept : tuple_delta_t ()
+ { hb_swap (*this, o); }
+
+ tuple_delta_t& operator = (tuple_delta_t&& o) noexcept
+ {
+ hb_swap (*this, o);
+ return *this;
+ }
+
+ void remove_axis (hb_tag_t axis_tag)
+ { axis_tuples.del (axis_tag); }
+
+ bool set_tent (hb_tag_t axis_tag, Triple tent)
+ { return axis_tuples.set (axis_tag, tent); }
+
+ tuple_delta_t& operator += (const tuple_delta_t& o)
+ {
+ unsigned num = indices.length;
+ for (unsigned i = 0; i < num; i++)
+ {
+ if (indices.arrayZ[i])
+ {
+ if (o.indices.arrayZ[i])
+ {
+ deltas_x[i] += o.deltas_x[i];
+ if (deltas_y && o.deltas_y)
+ deltas_y[i] += o.deltas_y[i];
+ }
+ }
+ else
+ {
+ if (!o.indices.arrayZ[i]) continue;
+ indices.arrayZ[i] = true;
+ deltas_x[i] = o.deltas_x[i];
+ if (deltas_y && o.deltas_y)
+ deltas_y[i] = o.deltas_y[i];
+ }
+ }
+ return *this;
+ }
+
+ tuple_delta_t& operator *= (float scalar)
+ {
+ if (scalar == 1.0f)
+ return *this;
+
+ unsigned num = indices.length;
+ if (deltas_y)
+ for (unsigned i = 0; i < num; i++)
+ {
+ if (!indices.arrayZ[i]) continue;
+ deltas_x[i] *= scalar;
+ deltas_y[i] *= scalar;
+ }
+ else
+ for (unsigned i = 0; i < num; i++)
+ {
+ if (!indices.arrayZ[i]) continue;
+ deltas_x[i] *= scalar;
+ }
+ return *this;
+ }
+
+ hb_vector_t<tuple_delta_t> change_tuple_var_axis_limit (hb_tag_t axis_tag, Triple axis_limit,
+ TripleDistances axis_triple_distances) const
+ {
+ hb_vector_t<tuple_delta_t> out;
+ Triple *tent;
+ if (!axis_tuples.has (axis_tag, &tent))
+ {
+ out.push (*this);
+ return out;
+ }
+
+ if ((tent->minimum < 0.f && tent->maximum > 0.f) ||
+ !(tent->minimum <= tent->middle && tent->middle <= tent->maximum))
+ return out;
+
+ if (tent->middle == 0.f)
+ {
+ out.push (*this);
+ return out;
+ }
+
+ result_t solutions = rebase_tent (*tent, axis_limit, axis_triple_distances);
+ for (auto t : solutions)
+ {
+ tuple_delta_t new_var = *this;
+ if (t.second == Triple ())
+ new_var.remove_axis (axis_tag);
+ else
+ new_var.set_tent (axis_tag, t.second);
+
+ new_var *= t.first;
+ out.push (std::move (new_var));
+ }
+
+ return out;
+ }
+
+ bool compile_peak_coords (const hb_map_t& axes_index_map,
+ const hb_map_t& axes_old_index_tag_map)
+ {
+ unsigned axis_count = axes_index_map.get_population ();
+ if (unlikely (!compiled_peak_coords.alloc (axis_count * F2DOT14::static_size)))
+ return false;
+
+ unsigned orig_axis_count = axes_old_index_tag_map.get_population ();
+ for (unsigned i = 0; i < orig_axis_count; i++)
+ {
+ if (!axes_index_map.has (i))
+ continue;
+
+ hb_tag_t axis_tag = axes_old_index_tag_map.get (i);
+ Triple *coords;
+ F2DOT14 peak_coord;
+ if (axis_tuples.has (axis_tag, &coords))
+ peak_coord.set_float (coords->middle);
+ else
+ peak_coord.set_int (0);
+
+ /* push F2DOT14 value into char vector */
+ int16_t val = peak_coord.to_int ();
+ compiled_peak_coords.push (static_cast<char> (val >> 8));
+ compiled_peak_coords.push (static_cast<char> (val & 0xFF));
+ }
+
+ return !compiled_peak_coords.in_error ();
+ }
+
+ /* deltas should be compiled already before we compile tuple
+ * variation header cause we need to fill in the size of the
+ * serialized data for this tuple variation */
+ bool compile_tuple_var_header (const hb_map_t& axes_index_map,
+ unsigned points_data_length,
+ const hb_map_t& axes_old_index_tag_map,
+ const hb_hashmap_t<const hb_vector_t<char>*, unsigned>* shared_tuples_idx_map)
+ {
+ /* compiled_deltas could be empty after iup delta optimization, we can skip
+ * compiling this tuple and return true */
+ if (!compiled_deltas) return true;
+
+ unsigned cur_axis_count = axes_index_map.get_population ();
+ /* allocate enough memory: 1 peak + 2 intermediate coords + fixed header size */
+ unsigned alloc_len = 3 * cur_axis_count * (F2DOT14::static_size) + 4;
+ if (unlikely (!compiled_tuple_header.resize (alloc_len))) return false;
+
+ unsigned flag = 0;
+ /* skip the first 4 header bytes: variationDataSize+tupleIndex */
+ F2DOT14* p = reinterpret_cast<F2DOT14 *> (compiled_tuple_header.begin () + 4);
+ F2DOT14* end = reinterpret_cast<F2DOT14 *> (compiled_tuple_header.end ());
+ hb_array_t<F2DOT14> coords (p, end - p);
+
+ /* encode peak coords */
+ unsigned peak_count = 0;
+ unsigned *shared_tuple_idx;
+ if (shared_tuples_idx_map &&
+ shared_tuples_idx_map->has (&compiled_peak_coords, &shared_tuple_idx))
+ {
+ flag = *shared_tuple_idx;
+ }
+ else
+ {
+ peak_count = encode_peak_coords(coords, flag, axes_index_map, axes_old_index_tag_map);
+ if (!peak_count) return false;
+ }
+
+ /* encode interim coords, it's optional so returned num could be 0 */
+ unsigned interim_count = encode_interm_coords (coords.sub_array (peak_count), flag, axes_index_map, axes_old_index_tag_map);
+
+ /* pointdata length = 0 implies "use shared points" */
+ if (points_data_length)
+ flag |= TupleVariationHeader::TuppleIndex::PrivatePointNumbers;
+
+ unsigned serialized_data_size = points_data_length + compiled_deltas.length;
+ TupleVariationHeader *o = reinterpret_cast<TupleVariationHeader *> (compiled_tuple_header.begin ());
+ o->varDataSize = serialized_data_size;
+ o->tupleIndex = flag;
+
+ unsigned total_header_len = 4 + (peak_count + interim_count) * (F2DOT14::static_size);
+ return compiled_tuple_header.resize (total_header_len);
+ }
+
+ unsigned encode_peak_coords (hb_array_t<F2DOT14> peak_coords,
+ unsigned& flag,
+ const hb_map_t& axes_index_map,
+ const hb_map_t& axes_old_index_tag_map) const
+ {
+ unsigned orig_axis_count = axes_old_index_tag_map.get_population ();
+ auto it = peak_coords.iter ();
+ unsigned count = 0;
+ for (unsigned i = 0; i < orig_axis_count; i++)
+ {
+ if (!axes_index_map.has (i)) /* axis pinned */
+ continue;
+ hb_tag_t axis_tag = axes_old_index_tag_map.get (i);
+ Triple *coords;
+ if (!axis_tuples.has (axis_tag, &coords))
+ (*it).set_int (0);
+ else
+ (*it).set_float (coords->middle);
+ it++;
+ count++;
+ }
+ flag |= TupleVariationHeader::TuppleIndex::EmbeddedPeakTuple;
+ return count;
+ }
+
+ /* if no need to encode intermediate coords, then just return p */
+ unsigned encode_interm_coords (hb_array_t<F2DOT14> coords,
+ unsigned& flag,
+ const hb_map_t& axes_index_map,
+ const hb_map_t& axes_old_index_tag_map) const
+ {
+ unsigned orig_axis_count = axes_old_index_tag_map.get_population ();
+ unsigned cur_axis_count = axes_index_map.get_population ();
+
+ auto start_coords_iter = coords.sub_array (0, cur_axis_count).iter ();
+ auto end_coords_iter = coords.sub_array (cur_axis_count).iter ();
+ bool encode_needed = false;
+ unsigned count = 0;
+ for (unsigned i = 0; i < orig_axis_count; i++)
+ {
+ if (!axes_index_map.has (i)) /* axis pinned */
+ continue;
+ hb_tag_t axis_tag = axes_old_index_tag_map.get (i);
+ Triple *coords;
+ float min_val = 0.f, val = 0.f, max_val = 0.f;
+ if (axis_tuples.has (axis_tag, &coords))
+ {
+ min_val = coords->minimum;
+ val = coords->middle;
+ max_val = coords->maximum;
+ }
+
+ (*start_coords_iter).set_float (min_val);
+ (*end_coords_iter).set_float (max_val);
+
+ start_coords_iter++;
+ end_coords_iter++;
+ count += 2;
+ if (min_val != hb_min (val, 0.f) || max_val != hb_max (val, 0.f))
+ encode_needed = true;
+ }
+
+ if (encode_needed)
+ {
+ flag |= TupleVariationHeader::TuppleIndex::IntermediateRegion;
+ return count;
+ }
+ return 0;
+ }
+
+ bool compile_deltas ()
+ { return compile_deltas (indices, deltas_x, deltas_y, compiled_deltas); }
+
+ bool compile_deltas (const hb_vector_t<bool> &point_indices,
+ const hb_vector_t<float> &x_deltas,
+ const hb_vector_t<float> &y_deltas,
+ hb_vector_t<char> &compiled_deltas /* OUT */)
+ {
+ hb_vector_t<int> rounded_deltas;
+ if (unlikely (!rounded_deltas.alloc (point_indices.length)))
+ return false;
+
+ for (unsigned i = 0; i < point_indices.length; i++)
+ {
+ if (!point_indices[i]) continue;
+ int rounded_delta = (int) roundf (x_deltas.arrayZ[i]);
+ rounded_deltas.push (rounded_delta);
+ }
+
+ if (!rounded_deltas) return true;
+ /* allocate enough memories 3 * num_deltas */
+ unsigned alloc_len = 3 * rounded_deltas.length;
+ if (y_deltas)
+ alloc_len *= 2;
+
+ if (unlikely (!compiled_deltas.resize (alloc_len))) return false;
+
+ unsigned i = 0;
+ unsigned encoded_len = encode_delta_run (i, compiled_deltas.as_array (), rounded_deltas);
+
+ if (y_deltas)
+ {
+ /* reuse the rounded_deltas vector, check that y_deltas have the same num of deltas as x_deltas */
+ unsigned j = 0;
+ for (unsigned idx = 0; idx < point_indices.length; idx++)
+ {
+ if (!point_indices[idx]) continue;
+ int rounded_delta = (int) roundf (y_deltas.arrayZ[idx]);
+
+ if (j >= rounded_deltas.length) return false;
+
+ rounded_deltas[j++] = rounded_delta;
+ }
+
+ if (j != rounded_deltas.length) return false;
+ /* reset i because we reuse rounded_deltas for y_deltas */
+ i = 0;
+ encoded_len += encode_delta_run (i, compiled_deltas.as_array ().sub_array (encoded_len), rounded_deltas);
+ }
+ return compiled_deltas.resize (encoded_len);
+ }
+
+ unsigned encode_delta_run (unsigned& i,
+ hb_array_t<char> encoded_bytes,
+ const hb_vector_t<int>& deltas) const
+ {
+ unsigned num_deltas = deltas.length;
+ unsigned encoded_len = 0;
+ while (i < num_deltas)
+ {
+ int val = deltas.arrayZ[i];
+ if (val == 0)
+ encoded_len += encode_delta_run_as_zeroes (i, encoded_bytes.sub_array (encoded_len), deltas);
+ else if (val >= -128 && val <= 127)
+ encoded_len += encode_delta_run_as_bytes (i, encoded_bytes.sub_array (encoded_len), deltas);
+ else
+ encoded_len += encode_delta_run_as_words (i, encoded_bytes.sub_array (encoded_len), deltas);
+ }
+ return encoded_len;
+ }
+
+ unsigned encode_delta_run_as_zeroes (unsigned& i,
+ hb_array_t<char> encoded_bytes,
+ const hb_vector_t<int>& deltas) const
+ {
+ unsigned num_deltas = deltas.length;
+ unsigned run_length = 0;
+ auto it = encoded_bytes.iter ();
+ unsigned encoded_len = 0;
+ while (i < num_deltas && deltas.arrayZ[i] == 0)
+ {
+ i++;
+ run_length++;
+ }
+
+ while (run_length >= 64)
+ {
+ *it++ = char (DELTAS_ARE_ZERO | 63);
+ run_length -= 64;
+ encoded_len++;
+ }
+
+ if (run_length)
+ {
+ *it++ = char (DELTAS_ARE_ZERO | (run_length - 1));
+ encoded_len++;
+ }
+ return encoded_len;
+ }
+
+ unsigned encode_delta_run_as_bytes (unsigned &i,
+ hb_array_t<char> encoded_bytes,
+ const hb_vector_t<int>& deltas) const
+ {
+ unsigned start = i;
+ unsigned num_deltas = deltas.length;
+ while (i < num_deltas)
+ {
+ int val = deltas.arrayZ[i];
+ if (val > 127 || val < -128)
+ break;
+
+ /* from fonttools: if there're 2 or more zeros in a sequence,
+ * it is better to start a new run to save bytes. */
+ if (val == 0 && i + 1 < num_deltas && deltas.arrayZ[i+1] == 0)
+ break;
+
+ i++;
+ }
+ unsigned run_length = i - start;
+
+ unsigned encoded_len = 0;
+ auto it = encoded_bytes.iter ();
+
+ while (run_length >= 64)
+ {
+ *it++ = 63;
+ encoded_len++;
+
+ for (unsigned j = 0; j < 64; j++)
+ {
+ *it++ = static_cast<char> (deltas.arrayZ[start + j]);
+ encoded_len++;
+ }
+
+ start += 64;
+ run_length -= 64;
+ }
+
+ if (run_length)
+ {
+ *it++ = run_length - 1;
+ encoded_len++;
+
+ while (start < i)
+ {
+ *it++ = static_cast<char> (deltas.arrayZ[start++]);
+ encoded_len++;
+ }
+ }
+
+ return encoded_len;
+ }
+
+ unsigned encode_delta_run_as_words (unsigned &i,
+ hb_array_t<char> encoded_bytes,
+ const hb_vector_t<int>& deltas) const
+ {
+ unsigned start = i;
+ unsigned num_deltas = deltas.length;
+ while (i < num_deltas)
+ {
+ int val = deltas.arrayZ[i];
+
+ /* start a new run for a single zero value*/
+ if (val == 0) break;
+
+ /* from fonttools: continue word-encoded run if there's only one
+ * single value in the range [-128, 127] because it is more compact.
+ * Only start a new run when there're 2 continuous such values. */
+ if (val >= -128 && val <= 127 &&
+ i + 1 < num_deltas &&
+ deltas.arrayZ[i+1] >= -128 && deltas.arrayZ[i+1] <= 127)
+ break;
+
+ i++;
+ }
+
+ unsigned run_length = i - start;
+ auto it = encoded_bytes.iter ();
+ unsigned encoded_len = 0;
+ while (run_length >= 64)
+ {
+ *it++ = (DELTAS_ARE_WORDS | 63);
+ encoded_len++;
+
+ for (unsigned j = 0; j < 64; j++)
+ {
+ int16_t delta_val = deltas.arrayZ[start + j];
+ *it++ = static_cast<char> (delta_val >> 8);
+ *it++ = static_cast<char> (delta_val & 0xFF);
+
+ encoded_len += 2;
+ }
+
+ start += 64;
+ run_length -= 64;
+ }
+
+ if (run_length)
+ {
+ *it++ = (DELTAS_ARE_WORDS | (run_length - 1));
+ encoded_len++;
+ while (start < i)
+ {
+ int16_t delta_val = deltas.arrayZ[start++];
+ *it++ = static_cast<char> (delta_val >> 8);
+ *it++ = static_cast<char> (delta_val & 0xFF);
+
+ encoded_len += 2;
+ }
+ }
+ return encoded_len;
+ }
+
+ bool calc_inferred_deltas (const contour_point_vector_t& orig_points)
+ {
+ unsigned point_count = orig_points.length;
+ if (point_count != indices.length)
+ return false;
+
+ unsigned ref_count = 0;
+ hb_vector_t<unsigned> end_points;
+
+ for (unsigned i = 0; i < point_count; i++)
+ {
+ if (indices.arrayZ[i])
+ ref_count++;
+ if (orig_points.arrayZ[i].is_end_point)
+ end_points.push (i);
+ }
+ /* all points are referenced, nothing to do */
+ if (ref_count == point_count)
+ return true;
+ if (unlikely (end_points.in_error ())) return false;
+
+ hb_set_t inferred_idxes;
+ unsigned start_point = 0;
+ for (unsigned end_point : end_points)
+ {
+ /* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */
+ unsigned unref_count = 0;
+ for (unsigned i = start_point; i < end_point + 1; i++)
+ unref_count += indices.arrayZ[i];
+ unref_count = (end_point - start_point + 1) - unref_count;
+
+ unsigned j = start_point;
+ if (unref_count == 0 || unref_count > end_point - start_point)
+ goto no_more_gaps;
+ for (;;)
+ {
+ /* Locate the next gap of unreferenced points between two referenced points prev and next.
+ * Note that a gap may wrap around at left (start_point) and/or at right (end_point).
+ */
+ unsigned int prev, next, i;
+ for (;;)
+ {
+ i = j;
+ j = next_index (i, start_point, end_point);
+ if (indices.arrayZ[i] && !indices.arrayZ[j]) break;
+ }
+ prev = j = i;
+ for (;;)
+ {
+ i = j;
+ j = next_index (i, start_point, end_point);
+ if (!indices.arrayZ[i] && indices.arrayZ[j]) break;
+ }
+ next = j;
+ /* Infer deltas for all unref points in the gap between prev and next */
+ i = prev;
+ for (;;)
+ {
+ i = next_index (i, start_point, end_point);
+ if (i == next) break;
+ deltas_x.arrayZ[i] = infer_delta (orig_points.arrayZ[i].x, orig_points.arrayZ[prev].x, orig_points.arrayZ[next].x,
+ deltas_x.arrayZ[prev], deltas_x.arrayZ[next]);
+ deltas_y.arrayZ[i] = infer_delta (orig_points.arrayZ[i].y, orig_points.arrayZ[prev].y, orig_points.arrayZ[next].y,
+ deltas_y.arrayZ[prev], deltas_y.arrayZ[next]);
+ inferred_idxes.add (i);
+ if (--unref_count == 0) goto no_more_gaps;
+ }
+ }
+ no_more_gaps:
+ start_point = end_point + 1;
+ }
+
+ for (unsigned i = 0; i < point_count; i++)
+ {
+ /* if points are not referenced and deltas are not inferred, set to 0.
+ * reference all points for gvar */
+ if ( !indices[i])
+ {
+ if (!inferred_idxes.has (i))
+ {
+ deltas_x.arrayZ[i] = 0.f;
+ deltas_y.arrayZ[i] = 0.f;
+ }
+ indices[i] = true;
+ }
+ }
+ return true;
+ }
+
+ bool optimize (const contour_point_vector_t& contour_points,
+ bool is_composite,
+ float tolerance = 0.5f)
+ {
+ unsigned count = contour_points.length;
+ if (deltas_x.length != count ||
+ deltas_y.length != count)
+ return false;
+
+ hb_vector_t<bool> opt_indices;
+ hb_vector_t<int> rounded_x_deltas, rounded_y_deltas;
+
+ if (unlikely (!rounded_x_deltas.alloc (count) ||
+ !rounded_y_deltas.alloc (count)))
+ return false;
+
+ for (unsigned i = 0; i < count; i++)
+ {
+ int rounded_x_delta = (int) roundf (deltas_x.arrayZ[i]);
+ int rounded_y_delta = (int) roundf (deltas_y.arrayZ[i]);
+ rounded_x_deltas.push (rounded_x_delta);
+ rounded_y_deltas.push (rounded_y_delta);
+ }
+
+ if (!iup_delta_optimize (contour_points, rounded_x_deltas, rounded_y_deltas, opt_indices, tolerance))
+ return false;
+
+ unsigned ref_count = 0;
+ for (bool ref_flag : opt_indices)
+ ref_count += ref_flag;
+
+ if (ref_count == count) return true;
+
+ hb_vector_t<float> opt_deltas_x, opt_deltas_y;
+ bool is_comp_glyph_wo_deltas = (is_composite && ref_count == 0);
+ if (is_comp_glyph_wo_deltas)
+ {
+ if (unlikely (!opt_deltas_x.resize (count) ||
+ !opt_deltas_y.resize (count)))
+ return false;
+
+ opt_indices.arrayZ[0] = true;
+ for (unsigned i = 1; i < count; i++)
+ opt_indices.arrayZ[i] = false;
+ }
+
+ hb_vector_t<char> opt_point_data;
+ if (!compile_point_set (opt_indices, opt_point_data))
+ return false;
+ hb_vector_t<char> opt_deltas_data;
+ if (!compile_deltas (opt_indices,
+ is_comp_glyph_wo_deltas ? opt_deltas_x : deltas_x,
+ is_comp_glyph_wo_deltas ? opt_deltas_y : deltas_y,
+ opt_deltas_data))
+ return false;
+
+ hb_vector_t<char> point_data;
+ if (!compile_point_set (indices, point_data))
+ return false;
+ hb_vector_t<char> deltas_data;
+ if (!compile_deltas (indices, deltas_x, deltas_y, deltas_data))
+ return false;
+
+ if (opt_point_data.length + opt_deltas_data.length < point_data.length + deltas_data.length)
+ {
+ indices.fini ();
+ indices = std::move (opt_indices);
+
+ if (is_comp_glyph_wo_deltas)
+ {
+ deltas_x.fini ();
+ deltas_x = std::move (opt_deltas_x);
+
+ deltas_y.fini ();
+ deltas_y = std::move (opt_deltas_y);
+ }
+ }
+ return !indices.in_error () && !deltas_x.in_error () && !deltas_y.in_error ();
+ }
+
+ static bool compile_point_set (const hb_vector_t<bool> &point_indices,
+ hb_vector_t<char>& compiled_points /* OUT */)
+ {
+ unsigned num_points = 0;
+ for (bool i : point_indices)
+ if (i) num_points++;
+
+ /* when iup optimization is enabled, num of referenced points could be 0 */
+ if (!num_points) return true;
+
+ unsigned indices_length = point_indices.length;
+ /* If the points set consists of all points in the glyph, it's encoded with a
+ * single zero byte */
+ if (num_points == indices_length)
+ return compiled_points.resize (1);
+
+ /* allocate enough memories: 2 bytes for count + 3 bytes for each point */
+ unsigned num_bytes = 2 + 3 *num_points;
+ if (unlikely (!compiled_points.resize (num_bytes, false)))
+ return false;
+
+ unsigned pos = 0;
+ /* binary data starts with the total number of reference points */
+ if (num_points < 0x80)
+ compiled_points.arrayZ[pos++] = num_points;
+ else
+ {
+ compiled_points.arrayZ[pos++] = ((num_points >> 8) | 0x80);
+ compiled_points.arrayZ[pos++] = num_points & 0xFF;
+ }
+
+ const unsigned max_run_length = 0x7F;
+ unsigned i = 0;
+ unsigned last_value = 0;
+ unsigned num_encoded = 0;
+ while (i < indices_length && num_encoded < num_points)
+ {
+ unsigned run_length = 0;
+ unsigned header_pos = pos;
+ compiled_points.arrayZ[pos++] = 0;
+
+ bool use_byte_encoding = false;
+ bool new_run = true;
+ while (i < indices_length && num_encoded < num_points &&
+ run_length <= max_run_length)
+ {
+ // find out next referenced point index
+ while (i < indices_length && !point_indices[i])
+ i++;
+
+ if (i >= indices_length) break;
+
+ unsigned cur_value = i;
+ unsigned delta = cur_value - last_value;
+
+ if (new_run)
+ {
+ use_byte_encoding = (delta <= 0xFF);
+ new_run = false;
+ }
+
+ if (use_byte_encoding && delta > 0xFF)
+ break;
+
+ if (use_byte_encoding)
+ compiled_points.arrayZ[pos++] = delta;
+ else
+ {
+ compiled_points.arrayZ[pos++] = delta >> 8;
+ compiled_points.arrayZ[pos++] = delta & 0xFF;
+ }
+ i++;
+ last_value = cur_value;
+ run_length++;
+ num_encoded++;
+ }
+
+ if (use_byte_encoding)
+ compiled_points.arrayZ[header_pos] = run_length - 1;
+ else
+ compiled_points.arrayZ[header_pos] = (run_length - 1) | 0x80;
+ }
+ return compiled_points.resize (pos, false);
+ }
+
+ static float infer_delta (float target_val, float prev_val, float next_val, float prev_delta, float next_delta)
+ {
+ if (prev_val == next_val)
+ return (prev_delta == next_delta) ? prev_delta : 0.f;
+ else if (target_val <= hb_min (prev_val, next_val))
+ return (prev_val < next_val) ? prev_delta : next_delta;
+ else if (target_val >= hb_max (prev_val, next_val))
+ return (prev_val > next_val) ? prev_delta : next_delta;
+
+ float r = (target_val - prev_val) / (next_val - prev_val);
+ return prev_delta + r * (next_delta - prev_delta);
+ }
+
+ static unsigned int next_index (unsigned int i, unsigned int start, unsigned int end)
+ { return (i >= end) ? start : (i + 1); }
+};
+
+struct TupleVariationData
+{
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ // here check on min_size only, TupleVariationHeader and var data will be
+ // checked while accessing through iterator.
+ return_trace (c->check_struct (this));
+ }
+
+ unsigned get_size (unsigned axis_count) const
+ {
+ unsigned total_size = min_size;
+ unsigned count = tupleVarCount.get_count ();
+ const TupleVariationHeader *tuple_var_header = &(get_tuple_var_header());
+ for (unsigned i = 0; i < count; i++)
+ {
+ total_size += tuple_var_header->get_size (axis_count) + tuple_var_header->get_data_size ();
+ tuple_var_header = &tuple_var_header->get_next (axis_count);
+ }
+
+ return total_size;
+ }
+
+ const TupleVariationHeader &get_tuple_var_header (void) const
+ { return StructAfter<TupleVariationHeader> (data); }
+
+ struct tuple_iterator_t;
+ struct tuple_variations_t
+ {
+ hb_vector_t<tuple_delta_t> tuple_vars;
+
+ private:
+ /* referenced point set->compiled point data map */
+ hb_hashmap_t<const hb_vector_t<bool>*, hb_vector_t<char>> point_data_map;
+ /* referenced point set-> count map, used in finding shared points */
+ hb_hashmap_t<const hb_vector_t<bool>*, unsigned> point_set_count_map;
+
+ /* empty for non-gvar tuples.
+ * shared_points_bytes is a pointer to some value in the point_data_map,
+ * which will be freed during map destruction. Save it for serialization, so
+ * no need to do find_shared_points () again */
+ hb_vector_t<char> *shared_points_bytes = nullptr;
+
+ /* total compiled byte size as TupleVariationData format, initialized to its
+ * min_size: 4 */
+ unsigned compiled_byte_size = 4;
+
+ /* for gvar iup delta optimization: whether this is a composite glyph */
+ bool is_composite = false;
+
+ public:
+ tuple_variations_t () = default;
+ tuple_variations_t (const tuple_variations_t&) = delete;
+ tuple_variations_t& operator=(const tuple_variations_t&) = delete;
+ tuple_variations_t (tuple_variations_t&&) = default;
+ tuple_variations_t& operator=(tuple_variations_t&&) = default;
+ ~tuple_variations_t () = default;
+
+ explicit operator bool () const { return bool (tuple_vars); }
+ unsigned get_var_count () const
+ {
+ unsigned count = 0;
+ /* when iup delta opt is enabled, compiled_deltas could be empty and we
+ * should skip this tuple */
+ for (auto& tuple: tuple_vars)
+ if (tuple.compiled_deltas) count++;
+
+ if (shared_points_bytes && shared_points_bytes->length)
+ count |= TupleVarCount::SharedPointNumbers;
+ return count;
+ }
+
+ unsigned get_compiled_byte_size () const
+ { return compiled_byte_size; }
+
+ bool create_from_tuple_var_data (tuple_iterator_t iterator,
+ unsigned tuple_var_count,
+ unsigned point_count,
+ bool is_gvar,
+ const hb_map_t *axes_old_index_tag_map,
+ const hb_vector_t<unsigned> &shared_indices,
+ const hb_array_t<const F2DOT14> shared_tuples,
+ bool is_composite_glyph)
+ {
+ do
+ {
+ const HBUINT8 *p = iterator.get_serialized_data ();
+ unsigned int length = iterator.current_tuple->get_data_size ();
+ if (unlikely (!iterator.var_data_bytes.check_range (p, length)))
+ return false;
+
+ hb_hashmap_t<hb_tag_t, Triple> axis_tuples;
+ if (!iterator.current_tuple->unpack_axis_tuples (iterator.get_axis_count (), shared_tuples, axes_old_index_tag_map, axis_tuples)
+ || axis_tuples.is_empty ())
+ return false;
+
+ hb_vector_t<unsigned> private_indices;
+ bool has_private_points = iterator.current_tuple->has_private_points ();
+ const HBUINT8 *end = p + length;
+ if (has_private_points &&
+ !TupleVariationData::unpack_points (p, private_indices, end))
+ return false;
+
+ const hb_vector_t<unsigned> &indices = has_private_points ? private_indices : shared_indices;
+ bool apply_to_all = (indices.length == 0);
+ unsigned num_deltas = apply_to_all ? point_count : indices.length;
+
+ hb_vector_t<int> deltas_x;
+
+ if (unlikely (!deltas_x.resize (num_deltas, false) ||
+ !TupleVariationData::unpack_deltas (p, deltas_x, end)))
+ return false;
+
+ hb_vector_t<int> deltas_y;
+ if (is_gvar)
+ {
+ if (unlikely (!deltas_y.resize (num_deltas, false) ||
+ !TupleVariationData::unpack_deltas (p, deltas_y, end)))
+ return false;
+ }
+
+ tuple_delta_t var;
+ var.axis_tuples = std::move (axis_tuples);
+ if (unlikely (!var.indices.resize (point_count) ||
+ !var.deltas_x.resize (point_count, false)))
+ return false;
+
+ if (is_gvar && unlikely (!var.deltas_y.resize (point_count, false)))
+ return false;
+
+ for (unsigned i = 0; i < num_deltas; i++)
+ {
+ unsigned idx = apply_to_all ? i : indices[i];
+ if (idx >= point_count) continue;
+ var.indices[idx] = true;
+ var.deltas_x[idx] = static_cast<float> (deltas_x[i]);
+ if (is_gvar)
+ var.deltas_y[idx] = static_cast<float> (deltas_y[i]);
+ }
+ tuple_vars.push (std::move (var));
+ } while (iterator.move_to_next ());
+
+ is_composite = is_composite_glyph;
+ return true;
+ }
+
+ bool create_from_item_var_data (const VarData &var_data,
+ const hb_vector_t<hb_hashmap_t<hb_tag_t, Triple>>& regions,
+ const hb_map_t& axes_old_index_tag_map,
+ unsigned& item_count,
+ const hb_inc_bimap_t* inner_map = nullptr)
+ {
+ /* NULL offset, to keep original varidx valid, just return */
+ if (&var_data == &Null (VarData))
+ return true;
+
+ unsigned num_regions = var_data.get_region_index_count ();
+ if (!tuple_vars.alloc (num_regions)) return false;
+
+ item_count = inner_map ? inner_map->get_population () : var_data.get_item_count ();
+ if (!item_count) return true;
+ unsigned row_size = var_data.get_row_size ();
+ const HBUINT8 *delta_bytes = var_data.get_delta_bytes ();
+
+ for (unsigned r = 0; r < num_regions; r++)
+ {
+ /* In VarData, deltas are organized in rows, convert them into
+ * column(region) based tuples, resize deltas_x first */
+ tuple_delta_t tuple;
+ if (!tuple.deltas_x.resize (item_count, false) ||
+ !tuple.indices.resize (item_count, false))
+ return false;
+
+ for (unsigned i = 0; i < item_count; i++)
+ {
+ tuple.indices.arrayZ[i] = true;
+ tuple.deltas_x.arrayZ[i] = var_data.get_item_delta_fast (inner_map ? inner_map->backward (i) : i,
+ r, delta_bytes, row_size);
+ }
+
+ unsigned region_index = var_data.get_region_index (r);
+ if (region_index >= regions.length) return false;
+ tuple.axis_tuples = regions.arrayZ[region_index];
+
+ tuple_vars.push (std::move (tuple));
+ }
+ return !tuple_vars.in_error ();
+ }
+
+ private:
+ static int _cmp_axis_tag (const void *pa, const void *pb)
+ {
+ const hb_tag_t *a = (const hb_tag_t*) pa;
+ const hb_tag_t *b = (const hb_tag_t*) pb;
+ return (int)(*a) - (int)(*b);
+ }
+
+ bool change_tuple_variations_axis_limits (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
+ const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances)
+ {
+ /* sort axis_tag/axis_limits, make result deterministic */
+ hb_vector_t<hb_tag_t> axis_tags;
+ if (!axis_tags.alloc (normalized_axes_location.get_population ()))
+ return false;
+ for (auto t : normalized_axes_location.keys ())
+ axis_tags.push (t);
+
+ axis_tags.qsort (_cmp_axis_tag);
+ for (auto axis_tag : axis_tags)
+ {
+ Triple *axis_limit;
+ if (!normalized_axes_location.has (axis_tag, &axis_limit))
+ return false;
+ TripleDistances axis_triple_distances{1.f, 1.f};
+ if (axes_triple_distances.has (axis_tag))
+ axis_triple_distances = axes_triple_distances.get (axis_tag);
+
+ hb_vector_t<tuple_delta_t> new_vars;
+ for (const tuple_delta_t& var : tuple_vars)
+ {
+ hb_vector_t<tuple_delta_t> out = var.change_tuple_var_axis_limit (axis_tag, *axis_limit, axis_triple_distances);
+ if (!out) continue;
+
+ unsigned new_len = new_vars.length + out.length;
+
+ if (unlikely (!new_vars.alloc (new_len, false)))
+ return false;
+
+ for (unsigned i = 0; i < out.length; i++)
+ new_vars.push (std::move (out[i]));
+ }
+ tuple_vars.fini ();
+ tuple_vars = std::move (new_vars);
+ }
+ return true;
+ }
+
+ /* merge tuple variations with overlapping tents, if iup delta optimization
+ * is enabled, add default deltas to contour_points */
+ bool merge_tuple_variations (contour_point_vector_t* contour_points = nullptr)
+ {
+ hb_vector_t<tuple_delta_t> new_vars;
+ hb_hashmap_t<const hb_hashmap_t<hb_tag_t, Triple>*, unsigned> m;
+ unsigned i = 0;
+ for (const tuple_delta_t& var : tuple_vars)
+ {
+ /* if all axes are pinned, drop the tuple variation */
+ if (var.axis_tuples.is_empty ())
+ {
+ /* if iup_delta_optimize is enabled, add deltas to contour coords */
+ if (contour_points && !contour_points->add_deltas (var.deltas_x,
+ var.deltas_y,
+ var.indices))
+ return false;
+ continue;
+ }
+
+ unsigned *idx;
+ if (m.has (&(var.axis_tuples), &idx))
+ {
+ new_vars[*idx] += var;
+ }
+ else
+ {
+ new_vars.push (var);
+ if (!m.set (&(var.axis_tuples), i))
+ return false;
+ i++;
+ }
+ }
+ tuple_vars.fini ();
+ tuple_vars = std::move (new_vars);
+ return true;
+ }
+
+ /* compile all point set and store byte data in a point_set->hb_bytes_t hashmap,
+ * also update point_set->count map, which will be used in finding shared
+ * point set*/
+ bool compile_all_point_sets ()
+ {
+ for (const auto& tuple: tuple_vars)
+ {
+ const hb_vector_t<bool>* points_set = &(tuple.indices);
+ if (point_data_map.has (points_set))
+ {
+ unsigned *count;
+ if (unlikely (!point_set_count_map.has (points_set, &count) ||
+ !point_set_count_map.set (points_set, (*count) + 1)))
+ return false;
+ continue;
+ }
+
+ hb_vector_t<char> compiled_point_data;
+ if (!tuple_delta_t::compile_point_set (*points_set, compiled_point_data))
+ return false;
+
+ if (!point_data_map.set (points_set, std::move (compiled_point_data)) ||
+ !point_set_count_map.set (points_set, 1))
+ return false;
+ }
+ return true;
+ }
+
+ /* find shared points set which saves most bytes */
+ void find_shared_points ()
+ {
+ unsigned max_saved_bytes = 0;
+
+ for (const auto& _ : point_data_map.iter_ref ())
+ {
+ const hb_vector_t<bool>* points_set = _.first;
+ unsigned data_length = _.second.length;
+ if (!data_length) continue;
+ unsigned *count;
+ if (unlikely (!point_set_count_map.has (points_set, &count) ||
+ *count <= 1))
+ {
+ shared_points_bytes = nullptr;
+ return;
+ }
+
+ unsigned saved_bytes = data_length * ((*count) -1);
+ if (saved_bytes > max_saved_bytes)
+ {
+ max_saved_bytes = saved_bytes;
+ shared_points_bytes = &(_.second);
+ }
+ }
+ }
+
+ bool calc_inferred_deltas (const contour_point_vector_t& contour_points)
+ {
+ for (tuple_delta_t& var : tuple_vars)
+ if (!var.calc_inferred_deltas (contour_points))
+ return false;
+
+ return true;
+ }
+
+ bool iup_optimize (const contour_point_vector_t& contour_points)
+ {
+ for (tuple_delta_t& var : tuple_vars)
+ {
+ if (!var.optimize (contour_points, is_composite))
+ return false;
+ }
+ return true;
+ }
+
+ public:
+ bool instantiate (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
+ const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances,
+ contour_point_vector_t* contour_points = nullptr,
+ bool optimize = false)
+ {
+ if (!tuple_vars) return true;
+ if (!change_tuple_variations_axis_limits (normalized_axes_location, axes_triple_distances))
+ return false;
+ /* compute inferred deltas only for gvar */
+ if (contour_points)
+ if (!calc_inferred_deltas (*contour_points))
+ return false;
+
+ /* if iup delta opt is on, contour_points can't be null */
+ if (optimize && !contour_points)
+ return false;
+
+ if (!merge_tuple_variations (optimize ? contour_points : nullptr))
+ return false;
+
+ if (optimize && !iup_optimize (*contour_points)) return false;
+ return !tuple_vars.in_error ();
+ }
+
+ bool compile_bytes (const hb_map_t& axes_index_map,
+ const hb_map_t& axes_old_index_tag_map,
+ bool use_shared_points,
+ const hb_hashmap_t<const hb_vector_t<char>*, unsigned>* shared_tuples_idx_map = nullptr)
+ {
+ // compile points set and store data in hashmap
+ if (!compile_all_point_sets ())
+ return false;
+
+ if (use_shared_points)
+ {
+ find_shared_points ();
+ if (shared_points_bytes)
+ compiled_byte_size += shared_points_bytes->length;
+ }
+ // compile delta and tuple var header for each tuple variation
+ for (auto& tuple: tuple_vars)
+ {
+ const hb_vector_t<bool>* points_set = &(tuple.indices);
+ hb_vector_t<char> *points_data;
+ if (unlikely (!point_data_map.has (points_set, &points_data)))
+ return false;
+
+ /* when iup optimization is enabled, num of referenced points could be 0
+ * and thus the compiled points bytes is empty, we should skip compiling
+ * this tuple */
+ if (!points_data->length)
+ continue;
+ if (!tuple.compile_deltas ())
+ return false;
+
+ unsigned points_data_length = (points_data != shared_points_bytes) ? points_data->length : 0;
+ if (!tuple.compile_tuple_var_header (axes_index_map, points_data_length, axes_old_index_tag_map,
+ shared_tuples_idx_map))
+ return false;
+ compiled_byte_size += tuple.compiled_tuple_header.length + points_data_length + tuple.compiled_deltas.length;
+ }
+ return true;
+ }
+
+ bool serialize_var_headers (hb_serialize_context_t *c, unsigned& total_header_len) const
+ {
+ TRACE_SERIALIZE (this);
+ for (const auto& tuple: tuple_vars)
+ {
+ tuple.compiled_tuple_header.as_array ().copy (c);
+ if (c->in_error ()) return_trace (false);
+ total_header_len += tuple.compiled_tuple_header.length;
+ }
+ return_trace (true);
+ }
+
+ bool serialize_var_data (hb_serialize_context_t *c, bool is_gvar) const
+ {
+ TRACE_SERIALIZE (this);
+ if (is_gvar && shared_points_bytes)
+ {
+ hb_bytes_t s (shared_points_bytes->arrayZ, shared_points_bytes->length);
+ s.copy (c);
+ }
+
+ for (const auto& tuple: tuple_vars)
+ {
+ const hb_vector_t<bool>* points_set = &(tuple.indices);
+ hb_vector_t<char> *point_data;
+ if (!point_data_map.has (points_set, &point_data))
+ return_trace (false);
+
+ if (!is_gvar || point_data != shared_points_bytes)
+ {
+ hb_bytes_t s (point_data->arrayZ, point_data->length);
+ s.copy (c);
+ }
+
+ tuple.compiled_deltas.as_array ().copy (c);
+ if (c->in_error ()) return_trace (false);
+ }
+
+ /* padding for gvar */
+ if (is_gvar && (compiled_byte_size % 2))
+ {
+ HBUINT8 pad;
+ pad = 0;
+ if (!c->embed (pad)) return_trace (false);
+ }
+ return_trace (true);
+ }
+ };
+
+ struct tuple_iterator_t
+ {
+ unsigned get_axis_count () const { return axis_count; }
+
+ void init (hb_bytes_t var_data_bytes_, unsigned int axis_count_, const void *table_base_)
+ {
+ var_data_bytes = var_data_bytes_;
+ var_data = var_data_bytes_.as<TupleVariationData> ();
+ index = 0;
+ axis_count = axis_count_;
+ current_tuple = &var_data->get_tuple_var_header ();
+ data_offset = 0;
+ table_base = table_base_;
+ }
+
+ bool get_shared_indices (hb_vector_t<unsigned int> &shared_indices /* OUT */)
+ {
+ if (var_data->has_shared_point_numbers ())
+ {
+ const HBUINT8 *base = &(table_base+var_data->data);
+ const HBUINT8 *p = base;
+ if (!unpack_points (p, shared_indices, (const HBUINT8 *) (var_data_bytes.arrayZ + var_data_bytes.length))) return false;
+ data_offset = p - base;
+ }
+ return true;
+ }
+
+ bool is_valid () const
+ {
+ return (index < var_data->tupleVarCount.get_count ()) &&
+ var_data_bytes.check_range (current_tuple, TupleVariationHeader::min_size) &&
+ var_data_bytes.check_range (current_tuple, hb_max (current_tuple->get_data_size (),
+ current_tuple->get_size (axis_count)));
+ }
+
+ bool move_to_next ()
+ {
+ data_offset += current_tuple->get_data_size ();
+ current_tuple = &current_tuple->get_next (axis_count);
+ index++;
+ return is_valid ();
+ }
+
+ const HBUINT8 *get_serialized_data () const
+ { return &(table_base+var_data->data) + data_offset; }
+
+ private:
+ const TupleVariationData *var_data;
+ unsigned int index;
+ unsigned int axis_count;
+ unsigned int data_offset;
+ const void *table_base;
+
+ public:
+ hb_bytes_t var_data_bytes;
+ const TupleVariationHeader *current_tuple;
+ };
+
+ static bool get_tuple_iterator (hb_bytes_t var_data_bytes, unsigned axis_count,
+ const void *table_base,
+ hb_vector_t<unsigned int> &shared_indices /* OUT */,
+ tuple_iterator_t *iterator /* OUT */)
+ {
+ iterator->init (var_data_bytes, axis_count, table_base);
+ if (!iterator->get_shared_indices (shared_indices))
+ return false;
+ return iterator->is_valid ();
+ }
+
+ bool has_shared_point_numbers () const { return tupleVarCount.has_shared_point_numbers (); }
+
+ static bool unpack_points (const HBUINT8 *&p /* IN/OUT */,
+ hb_vector_t<unsigned int> &points /* OUT */,
+ const HBUINT8 *end)
+ {
+ enum packed_point_flag_t
+ {
+ POINTS_ARE_WORDS = 0x80,
+ POINT_RUN_COUNT_MASK = 0x7F
+ };
+
+ if (unlikely (p + 1 > end)) return false;
+
+ unsigned count = *p++;
+ if (count & POINTS_ARE_WORDS)
+ {
+ if (unlikely (p + 1 > end)) return false;
+ count = ((count & POINT_RUN_COUNT_MASK) << 8) | *p++;
+ }
+ if (unlikely (!points.resize (count, false))) return false;
+
+ unsigned n = 0;
+ unsigned i = 0;
+ while (i < count)
+ {
+ if (unlikely (p + 1 > end)) return false;
+ unsigned control = *p++;
+ unsigned run_count = (control & POINT_RUN_COUNT_MASK) + 1;
+ unsigned stop = i + run_count;
+ if (unlikely (stop > count)) return false;
+ if (control & POINTS_ARE_WORDS)
+ {
+ if (unlikely (p + run_count * HBUINT16::static_size > end)) return false;
+ for (; i < stop; i++)
+ {
+ n += *(const HBUINT16 *)p;
+ points.arrayZ[i] = n;
+ p += HBUINT16::static_size;
+ }
+ }
+ else
+ {
+ if (unlikely (p + run_count > end)) return false;
+ for (; i < stop; i++)
+ {
+ n += *p++;
+ points.arrayZ[i] = n;
+ }
+ }
+ }
+ return true;
+ }
+
+ static bool unpack_deltas (const HBUINT8 *&p /* IN/OUT */,
+ hb_vector_t<int> &deltas /* IN/OUT */,
+ const HBUINT8 *end)
+ {
+ unsigned i = 0;
+ unsigned count = deltas.length;
+ while (i < count)
+ {
+ if (unlikely (p + 1 > end)) return false;
+ unsigned control = *p++;
+ unsigned run_count = (control & DELTA_RUN_COUNT_MASK) + 1;
+ unsigned stop = i + run_count;
+ if (unlikely (stop > count)) return false;
+ if (control & DELTAS_ARE_ZERO)
+ {
+ for (; i < stop; i++)
+ deltas.arrayZ[i] = 0;
+ }
+ else if (control & DELTAS_ARE_WORDS)
+ {
+ if (unlikely (p + run_count * HBUINT16::static_size > end)) return false;
+ for (; i < stop; i++)
+ {
+ deltas.arrayZ[i] = * (const HBINT16 *) p;
+ p += HBUINT16::static_size;
+ }
+ }
+ else
+ {
+ if (unlikely (p + run_count > end)) return false;
+ for (; i < stop; i++)
+ {
+ deltas.arrayZ[i] = * (const HBINT8 *) p++;
+ }
+ }
+ }
+ return true;
+ }
+
+ bool has_data () const { return tupleVarCount; }
+
+ bool decompile_tuple_variations (unsigned point_count,
+ bool is_gvar,
+ tuple_iterator_t iterator,
+ const hb_map_t *axes_old_index_tag_map,
+ const hb_vector_t<unsigned> &shared_indices,
+ const hb_array_t<const F2DOT14> shared_tuples,
+ tuple_variations_t& tuple_variations, /* OUT */
+ bool is_composite_glyph = false) const
+ {
+ return tuple_variations.create_from_tuple_var_data (iterator, tupleVarCount,
+ point_count, is_gvar,
+ axes_old_index_tag_map,
+ shared_indices,
+ shared_tuples,
+ is_composite_glyph);
+ }
+
+ bool serialize (hb_serialize_context_t *c,
+ bool is_gvar,
+ const tuple_variations_t& tuple_variations) const
+ {
+ TRACE_SERIALIZE (this);
+ /* empty tuple variations, just return and skip serialization. */
+ if (!tuple_variations) return_trace (true);
+
+ auto *out = c->start_embed (this);
+ if (unlikely (!c->extend_min (out))) return_trace (false);
+
+ if (!c->check_assign (out->tupleVarCount, tuple_variations.get_var_count (),
+ HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
+
+ unsigned total_header_len = 0;
+
+ if (!tuple_variations.serialize_var_headers (c, total_header_len))
+ return_trace (false);
+
+ unsigned data_offset = min_size + total_header_len;
+ if (!is_gvar) data_offset += 4;
+ if (!c->check_assign (out->data, data_offset, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
+
+ return tuple_variations.serialize_var_data (c, is_gvar);
+ }
+
+ protected:
+ struct TupleVarCount : HBUINT16
+ {
+ friend struct tuple_variations_t;
+ bool has_shared_point_numbers () const { return ((*this) & SharedPointNumbers); }
+ unsigned int get_count () const { return (*this) & CountMask; }
+ TupleVarCount& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
+ explicit operator bool () const { return get_count (); }
+
+ protected:
+ enum Flags
+ {
+ SharedPointNumbers= 0x8000u,
+ CountMask = 0x0FFFu
+ };
+ public:
+ DEFINE_SIZE_STATIC (2);
+ };
+
+ TupleVarCount tupleVarCount; /* A packed field. The high 4 bits are flags, and the
+ * low 12 bits are the number of tuple variation tables
+ * for this glyph. The number of tuple variation tables
+ * can be any number between 1 and 4095. */
+ Offset16To<HBUINT8>
+ data; /* Offset from the start of the base table
+ * to the serialized data. */
+ /* TupleVariationHeader tupleVariationHeaders[] *//* Array of tuple variation headers. */
+ public:
+ DEFINE_SIZE_MIN (4);
+};
+
+using tuple_variations_t = TupleVariationData::tuple_variations_t;
+struct item_variations_t
+{
+ using region_t = const hb_hashmap_t<hb_tag_t, Triple>*;
+ private:
+ /* each subtable is decompiled into a tuple_variations_t, in which all tuples
+ * have the same num of deltas (rows) */
+ hb_vector_t<tuple_variations_t> vars;
+
+ /* num of retained rows for each subtable, there're 2 cases when var_data is empty:
+ * 1. retained item_count is zero
+ * 2. regions is empty and item_count is non-zero.
+ * when converting to tuples, both will be dropped because the tuple is empty,
+ * however, we need to retain 2. as all-zero rows to keep original varidx
+ * valid, so we need a way to remember the num of rows for each subtable */
+ hb_vector_t<unsigned> var_data_num_rows;
+
+ /* original region list, decompiled from item varstore, used when rebuilding
+ * region list after instantiation */
+ hb_vector_t<hb_hashmap_t<hb_tag_t, Triple>> orig_region_list;
+
+ /* region list: vector of Regions, maintain the original order for the regions
+ * that existed before instantiate (), append the new regions at the end.
+ * Regions are stored in each tuple already, save pointers only.
+ * When converting back to item varstore, unused regions will be pruned */
+ hb_vector_t<region_t> region_list;
+
+ /* region -> idx map after instantiation and pruning unused regions */
+ hb_hashmap_t<region_t, unsigned> region_map;
+
+ /* all delta rows after instantiation */
+ hb_vector_t<hb_vector_t<int>> delta_rows;
+ /* final optimized vector of encoding objects used to assemble the varstore */
+ hb_vector_t<delta_row_encoding_t> encodings;
+
+ /* old varidxes -> new var_idxes map */
+ hb_map_t varidx_map;
+
+ /* has long words */
+ bool has_long = false;
+
+ public:
+ bool has_long_word () const
+ { return has_long; }
+
+ const hb_vector_t<region_t>& get_region_list () const
+ { return region_list; }
+
+ const hb_vector_t<delta_row_encoding_t>& get_vardata_encodings () const
+ { return encodings; }
+
+ const hb_map_t& get_varidx_map () const
+ { return varidx_map; }
+
+ bool instantiate (const ItemVariationStore& varStore,
+ const hb_subset_plan_t *plan,
+ bool optimize=true,
+ bool use_no_variation_idx=true,
+ const hb_array_t <const hb_inc_bimap_t> inner_maps = hb_array_t<const hb_inc_bimap_t> ())
+ {
+ if (!create_from_item_varstore (varStore, plan->axes_old_index_tag_map, inner_maps))
+ return false;
+ if (!instantiate_tuple_vars (plan->axes_location, plan->axes_triple_distances))
+ return false;
+ return as_item_varstore (optimize, use_no_variation_idx);
+ }
+
+ /* keep below APIs public only for unit test: test-item-varstore */
+ bool create_from_item_varstore (const ItemVariationStore& varStore,
+ const hb_map_t& axes_old_index_tag_map,
+ const hb_array_t <const hb_inc_bimap_t> inner_maps = hb_array_t<const hb_inc_bimap_t> ())
+ {
+ const VarRegionList& regionList = varStore.get_region_list ();
+ if (!regionList.get_var_regions (axes_old_index_tag_map, orig_region_list))
+ return false;
+
+ unsigned num_var_data = varStore.get_sub_table_count ();
+ if (inner_maps && inner_maps.length != num_var_data) return false;
+ if (!vars.alloc (num_var_data) ||
+ !var_data_num_rows.alloc (num_var_data)) return false;
+
+ for (unsigned i = 0; i < num_var_data; i++)
+ {
+ if (inner_maps && !inner_maps.arrayZ[i].get_population ())
+ continue;
+ tuple_variations_t var_data_tuples;
+ unsigned item_count = 0;
+ if (!var_data_tuples.create_from_item_var_data (varStore.get_sub_table (i),
+ orig_region_list,
+ axes_old_index_tag_map,
+ item_count,
+ inner_maps ? &(inner_maps.arrayZ[i]) : nullptr))
+ return false;
+
+ var_data_num_rows.push (item_count);
+ vars.push (std::move (var_data_tuples));
+ }
+ return !vars.in_error () && !var_data_num_rows.in_error () && vars.length == var_data_num_rows.length;
+ }
+
+ bool instantiate_tuple_vars (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
+ const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances)
+ {
+ for (tuple_variations_t& tuple_vars : vars)
+ if (!tuple_vars.instantiate (normalized_axes_location, axes_triple_distances))
+ return false;
+
+ if (!build_region_list ()) return false;
+ return true;
+ }
+
+ bool build_region_list ()
+ {
+ /* scan all tuples and collect all unique regions, prune unused regions */
+ hb_hashmap_t<region_t, unsigned> all_regions;
+ hb_hashmap_t<region_t, unsigned> used_regions;
+
+ /* use a vector when inserting new regions, make result deterministic */
+ hb_vector_t<region_t> all_unique_regions;
+ for (const tuple_variations_t& sub_table : vars)
+ {
+ for (const tuple_delta_t& tuple : sub_table.tuple_vars)
+ {
+ region_t r = &(tuple.axis_tuples);
+ if (!used_regions.has (r))
+ {
+ bool all_zeros = true;
+ for (float d : tuple.deltas_x)
+ {
+ int delta = (int) roundf (d);
+ if (delta != 0)
+ {
+ all_zeros = false;
+ break;
+ }
+ }
+ if (!all_zeros)
+ {
+ if (!used_regions.set (r, 1))
+ return false;
+ }
+ }
+ if (all_regions.has (r))
+ continue;
+ if (!all_regions.set (r, 1))
+ return false;
+ all_unique_regions.push (r);
+ }
+ }
+
+ if (!all_regions || !all_unique_regions) return false;
+ if (!region_list.alloc (all_regions.get_population ()))
+ return false;
+
+ unsigned idx = 0;
+ /* append the original regions that pre-existed */
+ for (const auto& r : orig_region_list)
+ {
+ if (!all_regions.has (&r) || !used_regions.has (&r))
+ continue;
+
+ region_list.push (&r);
+ if (!region_map.set (&r, idx))
+ return false;
+ all_regions.del (&r);
+ idx++;
+ }
+
+ /* append the new regions at the end */
+ for (const auto& r: all_unique_regions)
+ {
+ if (!all_regions.has (r) || !used_regions.has (r))
+ continue;
+ region_list.push (r);
+ if (!region_map.set (r, idx))
+ return false;
+ all_regions.del (r);
+ idx++;
+ }
+ return (!region_list.in_error ()) && (!region_map.in_error ());
+ }
+
+ /* main algorithm ported from fonttools VarStore_optimize() method, optimize
+ * varstore by default */
+
+ struct combined_gain_idx_tuple_t
+ {
+ int gain;
+ unsigned idx_1;
+ unsigned idx_2;
+
+ combined_gain_idx_tuple_t () = default;
+ combined_gain_idx_tuple_t (int gain_, unsigned i, unsigned j)
+ :gain (gain_), idx_1 (i), idx_2 (j) {}
+
+ bool operator < (const combined_gain_idx_tuple_t& o)
+ {
+ if (gain != o.gain)
+ return gain < o.gain;
+
+ if (idx_1 != o.idx_1)
+ return idx_1 < o.idx_1;
+
+ return idx_2 < o.idx_2;
+ }
+
+ bool operator <= (const combined_gain_idx_tuple_t& o)
+ {
+ if (*this < o) return true;
+ return gain == o.gain && idx_1 == o.idx_1 && idx_2 == o.idx_2;
+ }
+ };
+
+ bool as_item_varstore (bool optimize=true, bool use_no_variation_idx=true)
+ {
+ if (!region_list) return false;
+ unsigned num_cols = region_list.length;
+ /* pre-alloc a 2D vector for all sub_table's VarData rows */
+ unsigned total_rows = 0;
+ for (unsigned major = 0; major < var_data_num_rows.length; major++)
+ total_rows += var_data_num_rows[major];
+
+ if (!delta_rows.resize (total_rows)) return false;
+ /* init all rows to [0]*num_cols */
+ for (unsigned i = 0; i < total_rows; i++)
+ if (!(delta_rows[i].resize (num_cols))) return false;
+
+ /* old VarIdxes -> full encoding_row mapping */
+ hb_hashmap_t<unsigned, const hb_vector_t<int>*> front_mapping;
+ unsigned start_row = 0;
+ hb_vector_t<delta_row_encoding_t> encoding_objs;
+ hb_hashmap_t<hb_vector_t<uint8_t>, unsigned> chars_idx_map;
+
+ /* delta_rows map, used for filtering out duplicate rows */
+ hb_hashmap_t<const hb_vector_t<int>*, unsigned> delta_rows_map;
+ for (unsigned major = 0; major < vars.length; major++)
+ {
+ /* deltas are stored in tuples(column based), convert them back into items
+ * (row based) delta */
+ const tuple_variations_t& tuples = vars[major];
+ unsigned num_rows = var_data_num_rows[major];
+ for (const tuple_delta_t& tuple: tuples.tuple_vars)
+ {
+ if (tuple.deltas_x.length != num_rows)
+ return false;
+
+ /* skip unused regions */
+ unsigned *col_idx;
+ if (!region_map.has (&(tuple.axis_tuples), &col_idx))
+ continue;
+
+ for (unsigned i = 0; i < num_rows; i++)
+ {
+ int rounded_delta = roundf (tuple.deltas_x[i]);
+ delta_rows[start_row + i][*col_idx] += rounded_delta;
+ if ((!has_long) && (rounded_delta < -65536 || rounded_delta > 65535))
+ has_long = true;
+ }
+ }
+
+ if (!optimize)
+ {
+ /* assemble a delta_row_encoding_t for this subtable, skip optimization so
+ * chars is not initialized, we only need delta rows for serialization */
+ delta_row_encoding_t obj;
+ for (unsigned r = start_row; r < start_row + num_rows; r++)
+ obj.add_row (&(delta_rows.arrayZ[r]));
+
+ encodings.push (std::move (obj));
+ start_row += num_rows;
+ continue;
+ }
+
+ for (unsigned minor = 0; minor < num_rows; minor++)
+ {
+ const hb_vector_t<int>& row = delta_rows[start_row + minor];
+ if (use_no_variation_idx)
+ {
+ bool all_zeros = true;
+ for (int delta : row)
+ {
+ if (delta != 0)
+ {
+ all_zeros = false;
+ break;
+ }
+ }
+ if (all_zeros)
+ continue;
+ }
+
+ if (!front_mapping.set ((major<<16) + minor, &row))
+ return false;
+
+ hb_vector_t<uint8_t> chars = delta_row_encoding_t::get_row_chars (row);
+ if (!chars) return false;
+
+ if (delta_rows_map.has (&row))
+ continue;
+
+ delta_rows_map.set (&row, 1);
+ unsigned *obj_idx;
+ if (chars_idx_map.has (chars, &obj_idx))
+ {
+ delta_row_encoding_t& obj = encoding_objs[*obj_idx];
+ if (!obj.add_row (&row))
+ return false;
+ }
+ else
+ {
+ if (!chars_idx_map.set (chars, encoding_objs.length))
+ return false;
+ delta_row_encoding_t obj (std::move (chars), &row);
+ encoding_objs.push (std::move (obj));
+ }
+ }
+
+ start_row += num_rows;
+ }
+
+ /* return directly if no optimization, maintain original VariationIndex so
+ * varidx_map would be empty */
+ if (!optimize) return !encodings.in_error ();
+
+ /* sort encoding_objs */
+ encoding_objs.qsort ();
+
+ /* main algorithm: repeatedly pick 2 best encodings to combine, and combine
+ * them */
+ hb_priority_queue_t<combined_gain_idx_tuple_t> queue;
+ unsigned num_todos = encoding_objs.length;
+ for (unsigned i = 0; i < num_todos; i++)
+ {
+ for (unsigned j = i + 1; j < num_todos; j++)
+ {
+ int combining_gain = encoding_objs.arrayZ[i].gain_from_merging (encoding_objs.arrayZ[j]);
+ if (combining_gain > 0)
+ queue.insert (combined_gain_idx_tuple_t (-combining_gain, i, j), 0);
+ }
+ }
+
+ hb_set_t removed_todo_idxes;
+ while (queue)
+ {
+ auto t = queue.pop_minimum ().first;
+ unsigned i = t.idx_1;
+ unsigned j = t.idx_2;
+
+ if (removed_todo_idxes.has (i) || removed_todo_idxes.has (j))
+ continue;
+
+ delta_row_encoding_t& encoding = encoding_objs.arrayZ[i];
+ delta_row_encoding_t& other_encoding = encoding_objs.arrayZ[j];
+
+ removed_todo_idxes.add (i);
+ removed_todo_idxes.add (j);
+
+ hb_vector_t<uint8_t> combined_chars;
+ if (!combined_chars.alloc (encoding.chars.length))
+ return false;
+
+ for (unsigned idx = 0; idx < encoding.chars.length; idx++)
+ {
+ uint8_t v = hb_max (encoding.chars.arrayZ[idx], other_encoding.chars.arrayZ[idx]);
+ combined_chars.push (v);
+ }
+
+ delta_row_encoding_t combined_encoding_obj (std::move (combined_chars));
+ for (const auto& row : hb_concat (encoding.items, other_encoding.items))
+ combined_encoding_obj.add_row (row);
+
+ for (unsigned idx = 0; idx < encoding_objs.length; idx++)
+ {
+ if (removed_todo_idxes.has (idx)) continue;
+
+ const delta_row_encoding_t& obj = encoding_objs.arrayZ[idx];
+ if (obj.chars == combined_chars)
+ {
+ for (const auto& row : obj.items)
+ combined_encoding_obj.add_row (row);
+
+ removed_todo_idxes.add (idx);
+ continue;
+ }
+
+ int combined_gain = combined_encoding_obj.gain_from_merging (obj);
+ if (combined_gain > 0)
+ queue.insert (combined_gain_idx_tuple_t (-combined_gain, idx, encoding_objs.length), 0);
+ }
+
+ encoding_objs.push (std::move (combined_encoding_obj));
+ }
+
+ int num_final_encodings = (int) encoding_objs.length - (int) removed_todo_idxes.get_population ();
+ if (num_final_encodings <= 0) return false;
+
+ if (!encodings.alloc (num_final_encodings)) return false;
+ for (unsigned i = 0; i < encoding_objs.length; i++)
+ {
+ if (removed_todo_idxes.has (i)) continue;
+ encodings.push (std::move (encoding_objs.arrayZ[i]));
+ }
+
+ /* sort again based on width, make result deterministic */
+ encodings.qsort (delta_row_encoding_t::cmp_width);
+
+ return compile_varidx_map (front_mapping);
+ }
+
+ private:
+ /* compile varidx_map for one VarData subtable (index specified by major) */
+ bool compile_varidx_map (const hb_hashmap_t<unsigned, const hb_vector_t<int>*>& front_mapping)
+ {
+ /* full encoding_row -> new VarIdxes mapping */
+ hb_hashmap_t<const hb_vector_t<int>*, unsigned> back_mapping;
+
+ for (unsigned major = 0; major < encodings.length; major++)
+ {
+ delta_row_encoding_t& encoding = encodings[major];
+ /* just sanity check, this shouldn't happen */
+ if (encoding.is_empty ())
+ return false;
+
+ unsigned num_rows = encoding.items.length;
+
+ /* sort rows, make result deterministic */
+ encoding.items.qsort (_cmp_row);
+
+ /* compile old to new var_idxes mapping */
+ for (unsigned minor = 0; minor < num_rows; minor++)
+ {
+ unsigned new_varidx = (major << 16) + minor;
+ back_mapping.set (encoding.items.arrayZ[minor], new_varidx);
+ }
+ }
+
+ for (auto _ : front_mapping.iter ())
+ {
+ unsigned old_varidx = _.first;
+ unsigned *new_varidx;
+ if (back_mapping.has (_.second, &new_varidx))
+ varidx_map.set (old_varidx, *new_varidx);
+ else
+ varidx_map.set (old_varidx, HB_OT_LAYOUT_NO_VARIATIONS_INDEX);
+ }
+ return !varidx_map.in_error ();
+ }
+
+ static int _cmp_row (const void *pa, const void *pb)
+ {
+ /* compare pointers of vectors(const hb_vector_t<int>*) that represent a row */
+ const hb_vector_t<int>** a = (const hb_vector_t<int>**) pa;
+ const hb_vector_t<int>** b = (const hb_vector_t<int>**) pb;
+
+ for (unsigned i = 0; i < (*b)->length; i++)
+ {
+ int va = (*a)->arrayZ[i];
+ int vb = (*b)->arrayZ[i];
+ if (va != vb)
+ return va < vb ? -1 : 1;
+ }
+ return 0;
+ }
+};
} /* namespace OT */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-cvar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-cvar-table.hh
new file mode 100644
index 0000000000..3798ad3e3e
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-cvar-table.hh
@@ -0,0 +1,220 @@
+/*
+ * Copyright © 2023 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.
+ *
+ */
+
+#ifndef HB_OT_VAR_CVAR_TABLE_HH
+#define HB_OT_VAR_CVAR_TABLE_HH
+
+#include "hb-ot-var-common.hh"
+#include "hb-ot-var-fvar-table.hh"
+
+
+namespace OT {
+/*
+ * cvar -- control value table (CVT) Variations
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/cvar
+ */
+#define HB_OT_TAG_cvar HB_TAG('c','v','a','r')
+
+struct cvar
+{
+ static constexpr hb_tag_t tableTag = HB_OT_TAG_cvar;
+
+ bool sanitize (hb_sanitize_context_t *c) const
+ {
+ TRACE_SANITIZE (this);
+ return_trace (c->check_struct (this) &&
+ hb_barrier () &&
+ likely (version.major == 1) &&
+ tupleVariationData.sanitize (c));
+ }
+
+ const TupleVariationData* get_tuple_var_data (void) const
+ { return &tupleVariationData; }
+
+ bool decompile_tuple_variations (unsigned axis_count,
+ unsigned point_count,
+ hb_blob_t *blob,
+ bool is_gvar,
+ const hb_map_t *axes_old_index_tag_map,
+ TupleVariationData::tuple_variations_t& tuple_variations /* OUT */) const
+ {
+ hb_vector_t<unsigned> shared_indices;
+ TupleVariationData::tuple_iterator_t iterator;
+ hb_bytes_t var_data_bytes = blob->as_bytes ().sub_array (4);
+ if (!TupleVariationData::get_tuple_iterator (var_data_bytes, axis_count, this,
+ shared_indices, &iterator))
+ return false;
+
+ return tupleVariationData.decompile_tuple_variations (point_count, is_gvar, iterator,
+ axes_old_index_tag_map,
+ shared_indices,
+ hb_array<const F2DOT14> (),
+ tuple_variations);
+ }
+
+ static bool calculate_cvt_deltas (unsigned axis_count,
+ hb_array_t<int> coords,
+ unsigned num_cvt_item,
+ const TupleVariationData *tuple_var_data,
+ const void *base,
+ hb_vector_t<float>& cvt_deltas /* OUT */)
+ {
+ if (!coords) return true;
+ hb_vector_t<unsigned> shared_indices;
+ TupleVariationData::tuple_iterator_t iterator;
+ unsigned var_data_length = tuple_var_data->get_size (axis_count);
+ hb_bytes_t var_data_bytes = hb_bytes_t (reinterpret_cast<const char*> (tuple_var_data), var_data_length);
+ if (!TupleVariationData::get_tuple_iterator (var_data_bytes, axis_count, base,
+ shared_indices, &iterator))
+ return true; /* isn't applied at all */
+
+ hb_array_t<const F2DOT14> shared_tuples = hb_array<F2DOT14> ();
+ hb_vector_t<unsigned> private_indices;
+ hb_vector_t<int> unpacked_deltas;
+
+ do
+ {
+ float scalar = iterator.current_tuple->calculate_scalar (coords, axis_count, shared_tuples);
+ if (scalar == 0.f) continue;
+ const HBUINT8 *p = iterator.get_serialized_data ();
+ unsigned int length = iterator.current_tuple->get_data_size ();
+ if (unlikely (!iterator.var_data_bytes.check_range (p, length)))
+ return false;
+
+ const HBUINT8 *end = p + length;
+
+ bool has_private_points = iterator.current_tuple->has_private_points ();
+ if (has_private_points &&
+ !TupleVariationData::unpack_points (p, private_indices, end))
+ return false;
+ const hb_vector_t<unsigned int> &indices = has_private_points ? private_indices : shared_indices;
+
+ bool apply_to_all = (indices.length == 0);
+ unsigned num_deltas = apply_to_all ? num_cvt_item : indices.length;
+ if (unlikely (!unpacked_deltas.resize (num_deltas, false))) return false;
+ if (unlikely (!TupleVariationData::unpack_deltas (p, unpacked_deltas, end))) return false;
+
+ for (unsigned int i = 0; i < num_deltas; i++)
+ {
+ unsigned int idx = apply_to_all ? i : indices[i];
+ if (unlikely (idx >= num_cvt_item)) continue;
+ if (scalar != 1.0f) cvt_deltas[idx] += unpacked_deltas[i] * scalar ;
+ else cvt_deltas[idx] += unpacked_deltas[i];
+ }
+ } while (iterator.move_to_next ());
+
+ return true;
+ }
+
+ bool serialize (hb_serialize_context_t *c,
+ TupleVariationData::tuple_variations_t& tuple_variations) const
+ {
+ TRACE_SERIALIZE (this);
+ if (!tuple_variations) return_trace (false);
+ if (unlikely (!c->embed (version))) return_trace (false);
+
+ return_trace (tupleVariationData.serialize (c, false, tuple_variations));
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ if (c->plan->all_axes_pinned)
+ return_trace (false);
+
+ OT::TupleVariationData::tuple_variations_t tuple_variations;
+ unsigned axis_count = c->plan->axes_old_index_tag_map.get_population ();
+
+ const hb_tag_t cvt = HB_TAG('c','v','t',' ');
+ hb_blob_t *cvt_blob = hb_face_reference_table (c->plan->source, cvt);
+ unsigned point_count = hb_blob_get_length (cvt_blob) / FWORD::static_size;
+ hb_blob_destroy (cvt_blob);
+
+ if (!decompile_tuple_variations (axis_count, point_count,
+ c->source_blob, false,
+ &(c->plan->axes_old_index_tag_map),
+ tuple_variations))
+ return_trace (false);
+
+ if (!tuple_variations.instantiate (c->plan->axes_location, c->plan->axes_triple_distances))
+ return_trace (false);
+
+ if (!tuple_variations.compile_bytes (c->plan->axes_index_map, c->plan->axes_old_index_tag_map,
+ false /* do not use shared points */))
+ return_trace (false);
+
+ return_trace (serialize (c->serializer, tuple_variations));
+ }
+
+ static bool add_cvt_and_apply_deltas (hb_subset_plan_t *plan,
+ const TupleVariationData *tuple_var_data,
+ const void *base)
+ {
+ const hb_tag_t cvt = HB_TAG('c','v','t',' ');
+ hb_blob_t *cvt_blob = hb_face_reference_table (plan->source, cvt);
+ hb_blob_t *cvt_prime_blob = hb_blob_copy_writable_or_fail (cvt_blob);
+ hb_blob_destroy (cvt_blob);
+
+ if (unlikely (!cvt_prime_blob))
+ return false;
+
+ unsigned cvt_blob_length = hb_blob_get_length (cvt_prime_blob);
+ unsigned num_cvt_item = cvt_blob_length / FWORD::static_size;
+
+ hb_vector_t<float> cvt_deltas;
+ if (unlikely (!cvt_deltas.resize (num_cvt_item)))
+ {
+ hb_blob_destroy (cvt_prime_blob);
+ return false;
+ }
+
+ if (!calculate_cvt_deltas (plan->normalized_coords.length, plan->normalized_coords.as_array (),
+ num_cvt_item, tuple_var_data, base, cvt_deltas))
+ {
+ hb_blob_destroy (cvt_prime_blob);
+ return false;
+ }
+
+ FWORD *cvt_prime = (FWORD *) hb_blob_get_data_writable (cvt_prime_blob, nullptr);
+ for (unsigned i = 0; i < num_cvt_item; i++)
+ cvt_prime[i] += (int) roundf (cvt_deltas[i]);
+
+ bool success = plan->add_table (cvt, cvt_prime_blob);
+ hb_blob_destroy (cvt_prime_blob);
+ return success;
+ }
+
+ protected:
+ FixedVersion<>version; /* Version of the CVT variation table
+ * initially set to 0x00010000u */
+ TupleVariationData tupleVariationData; /* TupleVariationDate for cvar table */
+ public:
+ DEFINE_SIZE_MIN (8);
+};
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_VAR_CVAR_TABLE_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-fvar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-fvar-table.hh
index a384dfa531..07d7586baa 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-fvar-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-fvar-table.hh
@@ -39,6 +39,24 @@
namespace OT {
+static bool axis_coord_pinned_or_within_axis_range (const hb_array_t<const F16DOT16> coords,
+ unsigned axis_index,
+ Triple axis_limit)
+{
+ float axis_coord = coords[axis_index].to_float ();
+ if (axis_limit.is_point ())
+ {
+ if (axis_limit.minimum != axis_coord)
+ return false;
+ }
+ else
+ {
+ if (axis_coord < axis_limit.minimum ||
+ axis_coord > axis_limit.maximum)
+ return false;
+ }
+ return true;
+}
struct InstanceRecord
{
@@ -47,6 +65,27 @@ struct InstanceRecord
hb_array_t<const F16DOT16> get_coordinates (unsigned int axis_count) const
{ return coordinatesZ.as_array (axis_count); }
+ bool keep_instance (unsigned axis_count,
+ const hb_map_t *axes_index_tag_map,
+ const hb_hashmap_t<hb_tag_t, Triple> *axes_location) const
+ {
+ if (axes_location->is_empty ()) return true;
+ const hb_array_t<const F16DOT16> coords = get_coordinates (axis_count);
+ for (unsigned i = 0 ; i < axis_count; i++)
+ {
+ uint32_t *axis_tag;
+ if (!axes_index_tag_map->has (i, &axis_tag))
+ return false;
+ if (!axes_location->has (*axis_tag))
+ continue;
+
+ Triple axis_limit = axes_location->get (*axis_tag);
+ if (!axis_coord_pinned_or_within_axis_range (coords, i, axis_limit))
+ return false;
+ }
+ return true;
+ }
+
bool subset (hb_subset_context_t *c,
unsigned axis_count,
bool has_postscript_nameid) const
@@ -56,19 +95,22 @@ struct InstanceRecord
if (unlikely (!c->serializer->embed (flags))) return_trace (false);
const hb_array_t<const F16DOT16> coords = get_coordinates (axis_count);
- const hb_hashmap_t<hb_tag_t, float> *axes_location = &c->plan->user_axes_location;
+ const hb_hashmap_t<hb_tag_t, Triple> *axes_location = &c->plan->user_axes_location;
for (unsigned i = 0 ; i < axis_count; i++)
{
uint32_t *axis_tag;
+ Triple *axis_limit;
// only keep instances whose coordinates == pinned axis location
- if (!c->plan->axes_old_index_tag_map.has (i, &axis_tag)) continue;
-
- if (axes_location->has (*axis_tag) &&
- fabsf (axes_location->get (*axis_tag) - coords[i].to_float ()) > 0.001f)
- return_trace (false);
-
- if (!c->plan->axes_index_map.has (i))
- continue;
+ if (!c->plan->axes_old_index_tag_map.has (i, &axis_tag)) return_trace (false);
+ if (axes_location->has (*axis_tag, &axis_limit))
+ {
+ if (!axis_coord_pinned_or_within_axis_range (coords, i, *axis_limit))
+ return_trace (false);
+
+ //skip pinned axis
+ if (axis_limit->is_point ())
+ continue;
+ }
if (!c->serializer->embed (coords[i]))
return_trace (false);
@@ -89,6 +131,7 @@ struct InstanceRecord
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
c->check_array (coordinatesZ.arrayZ, axis_count));
}
@@ -186,6 +229,30 @@ struct AxisRecord
return defaultValue.to_float ();
}
+ TripleDistances get_triple_distances () const
+ {
+ float min, default_, max;
+ get_coordinates (min, default_, max);
+ return TripleDistances (min, default_, max);
+ }
+
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (this);
+ if (unlikely (!out)) return_trace (false);
+
+ const hb_hashmap_t<hb_tag_t, Triple>& user_axes_location = c->plan->user_axes_location;
+ Triple *axis_limit;
+ if (user_axes_location.has (axisTag, &axis_limit))
+ {
+ out->minValue.set_float (axis_limit->minimum);
+ out->defaultValue.set_float (axis_limit->middle);
+ out->maxValue.set_float (axis_limit->maximum);
+ }
+ return_trace (true);
+ }
+
public:
Tag axisTag; /* Tag identifying the design variation for the axis. */
protected:
@@ -211,12 +278,15 @@ struct fvar
{
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
+ hb_barrier () &&
likely (version.major == 1) &&
c->check_struct (this) &&
+ hb_barrier () &&
axisSize == 20 && /* Assumed in our code. */
instanceSize >= axisCount * 4 + 4 &&
get_axes ().sanitize (c) &&
- c->check_range (get_instance (0), instanceCount, instanceSize));
+ c->check_range (&StructAfter<InstanceRecord> (get_axes ()),
+ instanceCount, instanceSize));
}
unsigned int get_axis_count () const { return axisCount; }
@@ -314,21 +384,19 @@ struct fvar
return axisCount;
}
- void collect_name_ids (hb_hashmap_t<hb_tag_t, float> *user_axes_location,
+ void collect_name_ids (hb_hashmap_t<hb_tag_t, Triple> *user_axes_location,
+ hb_map_t *axes_old_index_tag_map,
hb_set_t *nameids /* IN/OUT */) const
{
if (!has_data ()) return;
- hb_map_t pinned_axes;
auto axis_records = get_axes ();
for (unsigned i = 0 ; i < (unsigned)axisCount; i++)
{
hb_tag_t axis_tag = axis_records[i].get_axis_tag ();
- if (user_axes_location->has (axis_tag))
- {
- pinned_axes.set (i, axis_tag);
+ if (user_axes_location->has (axis_tag) &&
+ user_axes_location->get (axis_tag).is_point ())
continue;
- }
nameids->add (axis_records[i].get_name_id ());
}
@@ -337,16 +405,7 @@ struct fvar
{
const InstanceRecord *instance = get_instance (i);
- if (hb_any (+ hb_enumerate (instance->get_coordinates (axisCount))
- | hb_filter (pinned_axes, hb_first)
- | hb_map ([&] (const hb_pair_t<unsigned, const F16DOT16&>& _)
- {
- hb_tag_t axis_tag = pinned_axes.get (_.first);
- float location = user_axes_location->get (axis_tag);
- if (fabs ((double)location - (double)_.second.to_float ()) > 0.001) return true;
- return false;
- })
- ))
+ if (!instance->keep_instance (axisCount, axes_old_index_tag_map, user_axes_location))
continue;
nameids->add (instance->subfamilyNameID);
@@ -384,21 +443,25 @@ struct fvar
for (unsigned i = 0 ; i < (unsigned)axisCount; i++)
{
if (!c->plan->axes_index_map.has (i)) continue;
- if (unlikely (!c->serializer->embed (axes_records[i])))
+ if (unlikely (!axes_records[i].subset (c)))
return_trace (false);
}
if (!c->serializer->check_assign (out->firstAxis, get_size (), HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
+ unsigned num_retained_instances = 0;
for (unsigned i = 0 ; i < (unsigned)instanceCount; i++)
{
const InstanceRecord *instance = get_instance (i);
auto snap = c->serializer->snapshot ();
if (!instance->subset (c, axisCount, has_postscript_nameid))
c->serializer->revert (snap);
+ else
+ num_retained_instances++;
}
- return_trace (true);
+
+ return_trace (c->serializer->check_assign (out->instanceCount, num_retained_instances, HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
public:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh
index 1eae6a3532..59aad57e37 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-gvar-table.hh
@@ -29,6 +29,7 @@
#define HB_OT_VAR_GVAR_TABLE_HH
#include "hb-open-type.hh"
+#include "hb-ot-var-common.hh"
/*
* gvar -- Glyph Variation Table
@@ -38,362 +39,263 @@
namespace OT {
-struct contour_point_t
+struct GlyphVariationData : TupleVariationData
+{};
+
+struct glyph_variations_t
{
- void init (float x_ = 0.f, float y_ = 0.f, bool is_end_point_ = false)
- { flag = 0; x = x_; y = y_; is_end_point = is_end_point_; }
+ using tuple_variations_t = TupleVariationData::tuple_variations_t;
+ hb_vector_t<tuple_variations_t> glyph_variations;
- void translate (const contour_point_t &p) { x += p.x; y += p.y; }
+ hb_vector_t<char> compiled_shared_tuples;
+ private:
+ unsigned shared_tuples_count = 0;
- float x = 0.f;
- float y = 0.f;
- uint8_t flag = 0;
- bool is_end_point = false;
-};
+ /* shared coords-> index map after instantiation */
+ hb_hashmap_t<const hb_vector_t<char>*, unsigned> shared_tuples_idx_map;
-struct contour_point_vector_t : hb_vector_t<contour_point_t>
-{
- void extend (const hb_array_t<contour_point_t> &a)
- {
- unsigned int old_len = length;
- if (unlikely (!resize (old_len + a.length, false)))
- return;
- auto arrayZ = this->arrayZ + old_len;
- unsigned count = a.length;
- hb_memcpy (arrayZ, a.arrayZ, count * sizeof (arrayZ[0]));
- }
+ public:
+ unsigned compiled_shared_tuples_count () const
+ { return shared_tuples_count; }
- void transform (const float (&matrix)[4])
+ unsigned compiled_byte_size () const
{
- if (matrix[0] == 1.f && matrix[1] == 0.f &&
- matrix[2] == 0.f && matrix[3] == 1.f)
- return;
- auto arrayZ = this->arrayZ;
- unsigned count = length;
- for (unsigned i = 0; i < count; i++)
- {
- contour_point_t &p = arrayZ[i];
- float x_ = p.x * matrix[0] + p.y * matrix[2];
- p.y = p.x * matrix[1] + p.y * matrix[3];
- p.x = x_;
- }
- }
+ unsigned byte_size = 0;
+ for (const auto& _ : glyph_variations)
+ byte_size += _.get_compiled_byte_size ();
- void translate (const contour_point_t& delta)
- {
- if (delta.x == 0.f && delta.y == 0.f)
- return;
- auto arrayZ = this->arrayZ;
- unsigned count = length;
- for (unsigned i = 0; i < count; i++)
- arrayZ[i].translate (delta);
+ return byte_size;
}
-};
-
-/* https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader */
-struct TupleVariationHeader
-{
- unsigned get_size (unsigned axis_count) const
- { return min_size + get_all_tuples (axis_count).get_size (); }
-
- unsigned get_data_size () const { return varDataSize; }
- const TupleVariationHeader &get_next (unsigned axis_count) const
- { return StructAtOffset<TupleVariationHeader> (this, get_size (axis_count)); }
-
- float calculate_scalar (hb_array_t<int> coords, unsigned int coord_count,
- const hb_array_t<const F2DOT14> shared_tuples) const
+ bool create_from_glyphs_var_data (unsigned axis_count,
+ const hb_array_t<const F2DOT14> shared_tuples,
+ const hb_subset_plan_t *plan,
+ const hb_hashmap_t<hb_codepoint_t, hb_bytes_t>& new_gid_var_data_map)
{
- hb_array_t<const F2DOT14> peak_tuple;
+ if (unlikely (!glyph_variations.alloc (plan->new_to_old_gid_list.length, true)))
+ return false;
- if (has_peak ())
- peak_tuple = get_peak_tuple (coord_count);
- else
+ auto it = hb_iter (plan->new_to_old_gid_list);
+ for (auto &_ : it)
{
- unsigned int index = get_index ();
- if (unlikely (index * coord_count >= shared_tuples.length))
- return 0.f;
- peak_tuple = shared_tuples.sub_array (coord_count * index, coord_count);
- }
+ hb_codepoint_t new_gid = _.first;
+ contour_point_vector_t *all_contour_points;
+ if (!new_gid_var_data_map.has (new_gid) ||
+ !plan->new_gid_contour_points_map.has (new_gid, &all_contour_points))
+ return false;
+ hb_bytes_t var_data = new_gid_var_data_map.get (new_gid);
+
+ const GlyphVariationData* p = reinterpret_cast<const GlyphVariationData*> (var_data.arrayZ);
+ hb_vector_t<unsigned> shared_indices;
+ GlyphVariationData::tuple_iterator_t iterator;
+ tuple_variations_t tuple_vars;
+
+ /* in case variation data is empty, push an empty struct into the vector,
+ * keep the vector in sync with the new_to_old_gid_list */
+ if (!var_data || ! p->has_data () || !all_contour_points->length ||
+ !GlyphVariationData::get_tuple_iterator (var_data, axis_count,
+ var_data.arrayZ,
+ shared_indices, &iterator))
+ {
+ glyph_variations.push (std::move (tuple_vars));
+ continue;
+ }
- hb_array_t<const F2DOT14> start_tuple;
- hb_array_t<const F2DOT14> end_tuple;
- if (has_intermediate ())
- {
- start_tuple = get_start_tuple (coord_count);
- end_tuple = get_end_tuple (coord_count);
+ bool is_composite_glyph = false;
+#ifdef HB_EXPERIMENTAL_API
+ is_composite_glyph = plan->composite_new_gids.has (new_gid);
+#endif
+ if (!p->decompile_tuple_variations (all_contour_points->length, true /* is_gvar */,
+ iterator, &(plan->axes_old_index_tag_map),
+ shared_indices, shared_tuples,
+ tuple_vars, /* OUT */
+ is_composite_glyph))
+ return false;
+ glyph_variations.push (std::move (tuple_vars));
}
+ return !glyph_variations.in_error () && glyph_variations.length == plan->new_to_old_gid_list.length;
+ }
- float scalar = 1.f;
- for (unsigned int i = 0; i < coord_count; i++)
+ bool instantiate (const hb_subset_plan_t *plan)
+ {
+ unsigned count = plan->new_to_old_gid_list.length;
+ bool iup_optimize = false;
+#ifdef HB_EXPERIMENTAL_API
+ iup_optimize = plan->flags & HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS;
+#endif
+ for (unsigned i = 0; i < count; i++)
{
- int v = coords[i];
- int peak = peak_tuple[i].to_int ();
- if (!peak || v == peak) continue;
-
- if (has_intermediate ())
- {
- int start = start_tuple[i].to_int ();
- int end = end_tuple[i].to_int ();
- if (unlikely (start > peak || peak > end ||
- (start < 0 && end > 0 && peak))) continue;
- if (v < start || v > end) return 0.f;
- if (v < peak)
- { if (peak != start) scalar *= (float) (v - start) / (peak - start); }
- else
- { if (peak != end) scalar *= (float) (end - v) / (end - peak); }
- }
- else if (!v || v < hb_min (0, peak) || v > hb_max (0, peak)) return 0.f;
- else
- scalar *= (float) v / peak;
+ hb_codepoint_t new_gid = plan->new_to_old_gid_list[i].first;
+ contour_point_vector_t *all_points;
+ if (!plan->new_gid_contour_points_map.has (new_gid, &all_points))
+ return false;
+ if (!glyph_variations[i].instantiate (plan->axes_location, plan->axes_triple_distances, all_points, iup_optimize))
+ return false;
}
- return scalar;
+ return true;
}
- bool has_peak () const { return tupleIndex & TuppleIndex::EmbeddedPeakTuple; }
- bool has_intermediate () const { return tupleIndex & TuppleIndex::IntermediateRegion; }
- bool has_private_points () const { return tupleIndex & TuppleIndex::PrivatePointNumbers; }
- unsigned get_index () const { return tupleIndex & TuppleIndex::TupleIndexMask; }
-
- protected:
- struct TuppleIndex : HBUINT16
+ bool compile_bytes (const hb_map_t& axes_index_map,
+ const hb_map_t& axes_old_index_tag_map)
{
- enum Flags {
- EmbeddedPeakTuple = 0x8000u,
- IntermediateRegion = 0x4000u,
- PrivatePointNumbers = 0x2000u,
- TupleIndexMask = 0x0FFFu
- };
-
- DEFINE_SIZE_STATIC (2);
- };
-
- hb_array_t<const F2DOT14> get_all_tuples (unsigned axis_count) const
- { return StructAfter<UnsizedArrayOf<F2DOT14>> (tupleIndex).as_array ((has_peak () + has_intermediate () * 2) * axis_count); }
- hb_array_t<const F2DOT14> get_peak_tuple (unsigned axis_count) const
- { return get_all_tuples (axis_count).sub_array (0, axis_count); }
- hb_array_t<const F2DOT14> get_start_tuple (unsigned axis_count) const
- { return get_all_tuples (axis_count).sub_array (has_peak () * axis_count, axis_count); }
- hb_array_t<const F2DOT14> get_end_tuple (unsigned axis_count) const
- { return get_all_tuples (axis_count).sub_array (has_peak () * axis_count + axis_count, axis_count); }
-
- HBUINT16 varDataSize; /* The size in bytes of the serialized
- * data for this tuple variation table. */
- TuppleIndex tupleIndex; /* A packed field. The high 4 bits are flags (see below).
- The low 12 bits are an index into a shared tuple
- records array. */
- /* UnsizedArrayOf<F2DOT14> peakTuple - optional */
- /* Peak tuple record for this tuple variation table — optional,
- * determined by flags in the tupleIndex value.
- *
- * Note that this must always be included in the 'cvar' table. */
- /* UnsizedArrayOf<F2DOT14> intermediateStartTuple - optional */
- /* Intermediate start tuple record for this tuple variation table — optional,
- determined by flags in the tupleIndex value. */
- /* UnsizedArrayOf<F2DOT14> intermediateEndTuple - optional */
- /* Intermediate end tuple record for this tuple variation table — optional,
- * determined by flags in the tupleIndex value. */
- public:
- DEFINE_SIZE_MIN (4);
-};
+ if (!compile_shared_tuples (axes_index_map, axes_old_index_tag_map))
+ return false;
+ for (tuple_variations_t& vars: glyph_variations)
+ if (!vars.compile_bytes (axes_index_map, axes_old_index_tag_map,
+ true, /* use shared points*/
+ &shared_tuples_idx_map))
+ return false;
-struct GlyphVariationData
-{
- const TupleVariationHeader &get_tuple_var_header (void) const
- { return StructAfter<TupleVariationHeader> (data); }
+ return true;
+ }
- struct tuple_iterator_t
+ bool compile_shared_tuples (const hb_map_t& axes_index_map,
+ const hb_map_t& axes_old_index_tag_map)
{
- void init (hb_bytes_t var_data_bytes_, unsigned int axis_count_)
- {
- var_data_bytes = var_data_bytes_;
- var_data = var_data_bytes_.as<GlyphVariationData> ();
- index = 0;
- axis_count = axis_count_;
- current_tuple = &var_data->get_tuple_var_header ();
- data_offset = 0;
- }
+ /* key is pointer to compiled_peak_coords inside each tuple, hashing
+ * function will always deref pointers first */
+ hb_hashmap_t<const hb_vector_t<char>*, unsigned> coords_count_map;
- bool get_shared_indices (hb_vector_t<unsigned int> &shared_indices /* OUT */)
+ /* count the num of shared coords */
+ for (tuple_variations_t& vars: glyph_variations)
{
- if (var_data->has_shared_point_numbers ())
+ for (tuple_delta_t& var : vars.tuple_vars)
{
- const HBUINT8 *base = &(var_data+var_data->data);
- const HBUINT8 *p = base;
- if (!unpack_points (p, shared_indices, (const HBUINT8 *) (var_data_bytes.arrayZ + var_data_bytes.length))) return false;
- data_offset = p - base;
+ if (!var.compile_peak_coords (axes_index_map, axes_old_index_tag_map))
+ return false;
+ unsigned* count;
+ if (coords_count_map.has (&(var.compiled_peak_coords), &count))
+ coords_count_map.set (&(var.compiled_peak_coords), *count + 1);
+ else
+ coords_count_map.set (&(var.compiled_peak_coords), 1);
}
- return true;
}
- bool is_valid () const
- {
- return (index < var_data->tupleVarCount.get_count ()) &&
- var_data_bytes.check_range (current_tuple, TupleVariationHeader::min_size) &&
- var_data_bytes.check_range (current_tuple, hb_max (current_tuple->get_data_size (),
- current_tuple->get_size (axis_count)));
- }
+ if (!coords_count_map || coords_count_map.in_error ())
+ return false;
- bool move_to_next ()
+ /* add only those coords that are used more than once into the vector and sort */
+ hb_vector_t<const hb_vector_t<char>*> shared_coords;
+ if (unlikely (!shared_coords.alloc (coords_count_map.get_population ())))
+ return false;
+
+ for (const auto _ : coords_count_map.iter ())
{
- data_offset += current_tuple->get_data_size ();
- current_tuple = &current_tuple->get_next (axis_count);
- index++;
- return is_valid ();
+ if (_.second == 1) continue;
+ shared_coords.push (_.first);
}
- const HBUINT8 *get_serialized_data () const
- { return &(var_data+var_data->data) + data_offset; }
-
- private:
- const GlyphVariationData *var_data;
- unsigned int index;
- unsigned int axis_count;
- unsigned int data_offset;
+ /* no shared tuples: no coords are used more than once */
+ if (!shared_coords) return true;
+ /* sorting based on the coords frequency first (high to low), then compare
+ * the coords bytes */
+ hb_qsort (shared_coords.arrayZ, shared_coords.length, sizeof (hb_vector_t<char>*), _cmp_coords, (void *) (&coords_count_map));
- public:
- hb_bytes_t var_data_bytes;
- const TupleVariationHeader *current_tuple;
- };
+ /* build shared_coords->idx map and shared tuples byte array */
- static bool get_tuple_iterator (hb_bytes_t var_data_bytes, unsigned axis_count,
- hb_vector_t<unsigned int> &shared_indices /* OUT */,
- tuple_iterator_t *iterator /* OUT */)
- {
- iterator->init (var_data_bytes, axis_count);
- if (!iterator->get_shared_indices (shared_indices))
+ shared_tuples_count = hb_min (0xFFFu + 1, shared_coords.length);
+ unsigned len = shared_tuples_count * (shared_coords[0]->length);
+ if (unlikely (!compiled_shared_tuples.alloc (len)))
return false;
- return iterator->is_valid ();
- }
- bool has_shared_point_numbers () const { return tupleVarCount.has_shared_point_numbers (); }
+ for (unsigned i = 0; i < shared_tuples_count; i++)
+ {
+ shared_tuples_idx_map.set (shared_coords[i], i);
+ /* add a concat() in hb_vector_t? */
+ for (char c : shared_coords[i]->iter ())
+ compiled_shared_tuples.push (c);
+ }
+
+ return true;
+ }
- static bool unpack_points (const HBUINT8 *&p /* IN/OUT */,
- hb_vector_t<unsigned int> &points /* OUT */,
- const HBUINT8 *end)
+ static int _cmp_coords (const void *pa, const void *pb, void *arg)
{
- enum packed_point_flag_t
- {
- POINTS_ARE_WORDS = 0x80,
- POINT_RUN_COUNT_MASK = 0x7F
- };
+ const hb_hashmap_t<const hb_vector_t<char>*, unsigned>* coords_count_map =
+ reinterpret_cast<const hb_hashmap_t<const hb_vector_t<char>*, unsigned>*> (arg);
- if (unlikely (p + 1 > end)) return false;
+ /* shared_coords is hb_vector_t<const hb_vector_t<char>*> so casting pa/pb
+ * to be a pointer to a pointer */
+ const hb_vector_t<char>** a = reinterpret_cast<const hb_vector_t<char>**> (const_cast<void*>(pa));
+ const hb_vector_t<char>** b = reinterpret_cast<const hb_vector_t<char>**> (const_cast<void*>(pb));
- unsigned count = *p++;
- if (count & POINTS_ARE_WORDS)
- {
- if (unlikely (p + 1 > end)) return false;
- count = ((count & POINT_RUN_COUNT_MASK) << 8) | *p++;
- }
- if (unlikely (!points.resize (count, false))) return false;
+ bool has_a = coords_count_map->has (*a);
+ bool has_b = coords_count_map->has (*b);
- unsigned n = 0;
- unsigned i = 0;
- while (i < count)
+ if (has_a && has_b)
{
- if (unlikely (p + 1 > end)) return false;
- unsigned control = *p++;
- unsigned run_count = (control & POINT_RUN_COUNT_MASK) + 1;
- if (unlikely (i + run_count > count)) return false;
- unsigned j;
- if (control & POINTS_ARE_WORDS)
- {
- if (unlikely (p + run_count * HBUINT16::static_size > end)) return false;
- for (j = 0; j < run_count; j++, i++)
- {
- n += *(const HBUINT16 *)p;
- points.arrayZ[i] = n;
- p += HBUINT16::static_size;
- }
- }
- else
- {
- if (unlikely (p + run_count > end)) return false;
- for (j = 0; j < run_count; j++, i++)
- {
- n += *p++;
- points.arrayZ[i] = n;
- }
- }
+ unsigned a_num = coords_count_map->get (*a);
+ unsigned b_num = coords_count_map->get (*b);
+
+ if (a_num != b_num)
+ return b_num - a_num;
+
+ return (*b)->as_array().cmp ((*a)->as_array ());
}
- return true;
+ else if (has_a) return -1;
+ else if (has_b) return 1;
+ else return 0;
}
- static bool unpack_deltas (const HBUINT8 *&p /* IN/OUT */,
- hb_vector_t<int> &deltas /* IN/OUT */,
- const HBUINT8 *end)
+ template<typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ bool serialize_glyph_var_data (hb_serialize_context_t *c,
+ Iterator it,
+ bool long_offset,
+ unsigned num_glyphs,
+ char* glyph_var_data_offsets /* OUT: glyph var data offsets array */) const
{
- enum packed_delta_flag_t
+ TRACE_SERIALIZE (this);
+
+ if (long_offset)
{
- DELTAS_ARE_ZERO = 0x80,
- DELTAS_ARE_WORDS = 0x40,
- DELTA_RUN_COUNT_MASK = 0x3F
- };
-
- unsigned i = 0;
- unsigned count = deltas.length;
- while (i < count)
+ ((HBUINT32 *) glyph_var_data_offsets)[0] = 0;
+ glyph_var_data_offsets += 4;
+ }
+ else
{
- if (unlikely (p + 1 > end)) return false;
- unsigned control = *p++;
- unsigned run_count = (control & DELTA_RUN_COUNT_MASK) + 1;
- if (unlikely (i + run_count > count)) return false;
- unsigned j;
- if (control & DELTAS_ARE_ZERO)
- {
- for (j = 0; j < run_count; j++, i++)
- deltas.arrayZ[i] = 0;
- }
- else if (control & DELTAS_ARE_WORDS)
- {
- if (unlikely (p + run_count * HBUINT16::static_size > end)) return false;
- for (j = 0; j < run_count; j++, i++)
- {
- deltas.arrayZ[i] = * (const HBINT16 *) p;
- p += HBUINT16::static_size;
- }
- }
- else
- {
- if (unlikely (p + run_count > end)) return false;
- for (j = 0; j < run_count; j++, i++)
- {
- deltas.arrayZ[i] = * (const HBINT8 *) p++;
- }
- }
+ ((HBUINT16 *) glyph_var_data_offsets)[0] = 0;
+ glyph_var_data_offsets += 2;
}
- return true;
- }
+ unsigned glyph_offset = 0;
+ hb_codepoint_t last_gid = 0;
+ unsigned idx = 0;
- bool has_data () const { return tupleVarCount; }
+ TupleVariationData* cur_glyph = c->start_embed<TupleVariationData> ();
+ if (!cur_glyph) return_trace (false);
+ for (auto &_ : it)
+ {
+ hb_codepoint_t gid = _.first;
+ if (long_offset)
+ for (; last_gid < gid; last_gid++)
+ ((HBUINT32 *) glyph_var_data_offsets)[last_gid] = glyph_offset;
+ else
+ for (; last_gid < gid; last_gid++)
+ ((HBUINT16 *) glyph_var_data_offsets)[last_gid] = glyph_offset / 2;
- protected:
- struct TupleVarCount : HBUINT16
- {
- bool has_shared_point_numbers () const { return ((*this) & SharedPointNumbers); }
- unsigned int get_count () const { return (*this) & CountMask; }
+ if (idx >= glyph_variations.length) return_trace (false);
+ if (!cur_glyph->serialize (c, true, glyph_variations[idx])) return_trace (false);
+ TupleVariationData* next_glyph = c->start_embed<TupleVariationData> ();
+ glyph_offset += (char *) next_glyph - (char *) cur_glyph;
- protected:
- enum Flags
- {
- SharedPointNumbers= 0x8000u,
- CountMask = 0x0FFFu
- };
- public:
- DEFINE_SIZE_STATIC (2);
- };
+ if (long_offset)
+ ((HBUINT32 *) glyph_var_data_offsets)[gid] = glyph_offset;
+ else
+ ((HBUINT16 *) glyph_var_data_offsets)[gid] = glyph_offset / 2;
- TupleVarCount tupleVarCount; /* A packed field. The high 4 bits are flags, and the
- * low 12 bits are the number of tuple variation tables
- * for this glyph. The number of tuple variation tables
- * can be any number between 1 and 4095. */
- Offset16To<HBUINT8>
- data; /* Offset from the start of the GlyphVariationData table
- * to the serialized data. */
- /* TupleVariationHeader tupleVariationHeaders[] *//* Array of tuple variation headers. */
- public:
- DEFINE_SIZE_MIN (4);
+ last_gid++;
+ idx++;
+ cur_glyph = next_glyph;
+ }
+
+ if (long_offset)
+ for (; last_gid < num_glyphs; last_gid++)
+ ((HBUINT32 *) glyph_var_data_offsets)[last_gid] = glyph_offset;
+ else
+ for (; last_gid < num_glyphs; last_gid++)
+ ((HBUINT16 *) glyph_var_data_offsets)[last_gid] = glyph_offset / 2;
+ return_trace (true);
+ }
};
struct gvar
@@ -403,20 +305,122 @@ struct gvar
bool sanitize_shallow (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
- return_trace (c->check_struct (this) && (version.major == 1) &&
+ return_trace (c->check_struct (this) &&
+ hb_barrier () &&
+ (version.major == 1) &&
sharedTuples.sanitize (c, this, axisCount * sharedTupleCount) &&
(is_long_offset () ?
- c->check_array (get_long_offset_array (), glyphCount+1) :
- c->check_array (get_short_offset_array (), glyphCount+1)));
+ c->check_array (get_long_offset_array (), c->get_num_glyphs () + 1) :
+ c->check_array (get_short_offset_array (), c->get_num_glyphs () + 1)));
}
/* GlyphVariationData not sanitized here; must be checked while accessing each glyph variation data */
bool sanitize (hb_sanitize_context_t *c) const
{ return sanitize_shallow (c); }
+ bool decompile_glyph_variations (hb_subset_context_t *c,
+ glyph_variations_t& glyph_vars /* OUT */) const
+ {
+ hb_hashmap_t<hb_codepoint_t, hb_bytes_t> new_gid_var_data_map;
+ auto it = hb_iter (c->plan->new_to_old_gid_list);
+ if (it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
+ {
+ new_gid_var_data_map.set (0, hb_bytes_t ());
+ it++;
+ }
+
+ for (auto &_ : it)
+ {
+ hb_codepoint_t new_gid = _.first;
+ hb_codepoint_t old_gid = _.second;
+ hb_bytes_t var_data_bytes = get_glyph_var_data_bytes (c->source_blob, glyphCountX, old_gid);
+ new_gid_var_data_map.set (new_gid, var_data_bytes);
+ }
+
+ if (new_gid_var_data_map.in_error ()) return false;
+
+ hb_array_t<const F2DOT14> shared_tuples = (this+sharedTuples).as_array ((unsigned) sharedTupleCount * (unsigned) axisCount);
+ return glyph_vars.create_from_glyphs_var_data (axisCount, shared_tuples, c->plan, new_gid_var_data_map);
+ }
+
+ template<typename Iterator,
+ hb_requires (hb_is_iterator (Iterator))>
+ bool serialize (hb_serialize_context_t *c,
+ const glyph_variations_t& glyph_vars,
+ Iterator it,
+ unsigned axis_count,
+ unsigned num_glyphs,
+ bool force_long_offsets) const
+ {
+ TRACE_SERIALIZE (this);
+ gvar *out = c->allocate_min<gvar> ();
+ if (unlikely (!out)) return_trace (false);
+
+ out->version.major = 1;
+ out->version.minor = 0;
+ out->axisCount = axis_count;
+ out->glyphCountX = hb_min (0xFFFFu, num_glyphs);
+
+ unsigned glyph_var_data_size = glyph_vars.compiled_byte_size ();
+ bool long_offset = glyph_var_data_size & ~0xFFFFu || force_long_offsets;
+ out->flags = long_offset ? 1 : 0;
+
+ HBUINT8 *glyph_var_data_offsets = c->allocate_size<HBUINT8> ((long_offset ? 4 : 2) * (num_glyphs + 1), false);
+ if (!glyph_var_data_offsets) return_trace (false);
+
+ /* shared tuples */
+ unsigned shared_tuple_count = glyph_vars.compiled_shared_tuples_count ();
+ out->sharedTupleCount = shared_tuple_count;
+
+ if (!shared_tuple_count)
+ out->sharedTuples = 0;
+ else
+ {
+ hb_array_t<const char> shared_tuples = glyph_vars.compiled_shared_tuples.as_array ().copy (c);
+ if (!shared_tuples.arrayZ) return_trace (false);
+ out->sharedTuples = shared_tuples.arrayZ - (char *) out;
+ }
+
+ char *glyph_var_data = c->start_embed<char> ();
+ if (!glyph_var_data) return_trace (false);
+ out->dataZ = glyph_var_data - (char *) out;
+
+ return_trace (glyph_vars.serialize_glyph_var_data (c, it, long_offset, num_glyphs,
+ (char *) glyph_var_data_offsets));
+ }
+
+ bool instantiate (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+ glyph_variations_t glyph_vars;
+ if (!decompile_glyph_variations (c, glyph_vars))
+ return_trace (false);
+
+ if (!glyph_vars.instantiate (c->plan)) return_trace (false);
+ if (!glyph_vars.compile_bytes (c->plan->axes_index_map, c->plan->axes_old_index_tag_map))
+ return_trace (false);
+
+ unsigned axis_count = c->plan->axes_index_map.get_population ();
+ unsigned num_glyphs = c->plan->num_output_glyphs ();
+ auto it = hb_iter (c->plan->new_to_old_gid_list);
+
+ bool force_long_offsets = false;
+#ifdef HB_EXPERIMENTAL_API
+ force_long_offsets = c->plan->flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS;
+#endif
+ return_trace (serialize (c->serializer, glyph_vars, it, axis_count, num_glyphs, force_long_offsets));
+ }
+
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
+ if (c->plan->all_axes_pinned)
+ return_trace (false);
+
+ if (c->plan->normalized_coords)
+ return_trace (instantiate (c));
+
+ unsigned glyph_count = version.to_int () ? c->plan->source->get_num_glyphs () : 0;
gvar *out = c->serializer->allocate_min<gvar> ();
if (unlikely (!out)) return_trace (false);
@@ -427,22 +431,25 @@ struct gvar
out->sharedTupleCount = sharedTupleCount;
unsigned int num_glyphs = c->plan->num_output_glyphs ();
- out->glyphCount = num_glyphs;
+ out->glyphCountX = hb_min (0xFFFFu, num_glyphs);
+ auto it = hb_iter (c->plan->new_to_old_gid_list);
+ if (it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
+ it++;
unsigned int subset_data_size = 0;
- for (hb_codepoint_t gid = (c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE) ? 0 : 1;
- gid < num_glyphs;
- gid++)
+ for (auto &_ : it)
{
- hb_codepoint_t old_gid;
- if (!c->plan->old_gid_for_new_gid (gid, &old_gid)) continue;
- subset_data_size += get_glyph_var_data_bytes (c->source_blob, old_gid).length;
+ hb_codepoint_t old_gid = _.second;
+ subset_data_size += get_glyph_var_data_bytes (c->source_blob, glyph_count, old_gid).length;
}
- bool long_offset = subset_data_size & ~0xFFFFu;
+ bool long_offset = (subset_data_size & ~0xFFFFu);
+#ifdef HB_EXPERIMENTAL_API
+ long_offset = long_offset || (c->plan->flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS);
+#endif
out->flags = long_offset ? 1 : 0;
- HBUINT8 *subset_offsets = c->serializer->allocate_size<HBUINT8> ((long_offset ? 4 : 2) * (num_glyphs + 1));
+ HBUINT8 *subset_offsets = c->serializer->allocate_size<HBUINT8> ((long_offset ? 4 : 2) * (num_glyphs + 1), false);
if (!subset_offsets) return_trace (false);
/* shared tuples */
@@ -457,43 +464,74 @@ struct gvar
hb_memcpy (tuples, this+sharedTuples, shared_tuple_size);
}
- char *subset_data = c->serializer->allocate_size<char> (subset_data_size);
+ /* This ordering relative to the shared tuples array, which puts the glyphVariationData
+ last in the table, is required when HB_SUBSET_FLAGS_IFTB_REQUIREMENTS is set */
+ char *subset_data = c->serializer->allocate_size<char> (subset_data_size, false);
if (!subset_data) return_trace (false);
out->dataZ = subset_data - (char *) out;
+
+ if (long_offset)
+ {
+ ((HBUINT32 *) subset_offsets)[0] = 0;
+ subset_offsets += 4;
+ }
+ else
+ {
+ ((HBUINT16 *) subset_offsets)[0] = 0;
+ subset_offsets += 2;
+ }
unsigned int glyph_offset = 0;
- for (hb_codepoint_t gid = (c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE) ? 0 : 1;
- gid < num_glyphs;
- gid++)
+
+ hb_codepoint_t last = 0;
+ it = hb_iter (c->plan->new_to_old_gid_list);
+ if (it->first == 0 && !(c->plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
+ it++;
+ for (auto &_ : it)
{
- hb_codepoint_t old_gid;
- hb_bytes_t var_data_bytes = c->plan->old_gid_for_new_gid (gid, &old_gid)
- ? get_glyph_var_data_bytes (c->source_blob, old_gid)
- : hb_bytes_t ();
+ hb_codepoint_t gid = _.first;
+ hb_codepoint_t old_gid = _.second;
if (long_offset)
- ((HBUINT32 *) subset_offsets)[gid] = glyph_offset;
+ for (; last < gid; last++)
+ ((HBUINT32 *) subset_offsets)[last] = glyph_offset;
else
- ((HBUINT16 *) subset_offsets)[gid] = glyph_offset / 2;
+ for (; last < gid; last++)
+ ((HBUINT16 *) subset_offsets)[last] = glyph_offset / 2;
+
+ hb_bytes_t var_data_bytes = get_glyph_var_data_bytes (c->source_blob,
+ glyph_count,
+ old_gid);
- if (var_data_bytes.length > 0)
- hb_memcpy (subset_data, var_data_bytes.arrayZ, var_data_bytes.length);
+ hb_memcpy (subset_data, var_data_bytes.arrayZ, var_data_bytes.length);
subset_data += var_data_bytes.length;
glyph_offset += var_data_bytes.length;
+
+ if (long_offset)
+ ((HBUINT32 *) subset_offsets)[gid] = glyph_offset;
+ else
+ ((HBUINT16 *) subset_offsets)[gid] = glyph_offset / 2;
+
+ last++; // Skip over gid
}
+
if (long_offset)
- ((HBUINT32 *) subset_offsets)[num_glyphs] = glyph_offset;
+ for (; last < num_glyphs; last++)
+ ((HBUINT32 *) subset_offsets)[last] = glyph_offset;
else
- ((HBUINT16 *) subset_offsets)[num_glyphs] = glyph_offset / 2;
+ for (; last < num_glyphs; last++)
+ ((HBUINT16 *) subset_offsets)[last] = glyph_offset / 2;
return_trace (true);
}
protected:
- const hb_bytes_t get_glyph_var_data_bytes (hb_blob_t *blob, hb_codepoint_t glyph) const
+ const hb_bytes_t get_glyph_var_data_bytes (hb_blob_t *blob,
+ unsigned glyph_count,
+ hb_codepoint_t glyph) const
{
- unsigned start_offset = get_offset (glyph);
- unsigned end_offset = get_offset (glyph+1);
+ unsigned start_offset = get_offset (glyph_count, glyph);
+ unsigned end_offset = get_offset (glyph_count, glyph+1);
if (unlikely (end_offset < start_offset)) return hb_bytes_t ();
unsigned length = end_offset - start_offset;
hb_bytes_t var_data = blob->as_bytes ().sub_array (((unsigned) dataZ) + start_offset, length);
@@ -502,9 +540,9 @@ struct gvar
bool is_long_offset () const { return flags & 1; }
- unsigned get_offset (unsigned i) const
+ unsigned get_offset (unsigned glyph_count, unsigned i) const
{
- if (unlikely (i > glyphCount)) return 0;
+ if (unlikely (i > glyph_count)) return 0;
_hb_compiler_memory_r_barrier ();
return is_long_offset () ? get_long_offset_array ()[i] : get_short_offset_array ()[i] * 2;
}
@@ -516,7 +554,41 @@ struct gvar
struct accelerator_t
{
accelerator_t (hb_face_t *face)
- { table = hb_sanitize_context_t ().reference_table<gvar> (face); }
+ {
+ table = hb_sanitize_context_t ().reference_table<gvar> (face);
+ /* If sanitize failed, set glyphCount to 0. */
+ glyphCount = table->version.to_int () ? face->get_num_glyphs () : 0;
+
+ /* For shared tuples that only have one axis active, shared the index of
+ * that axis as a cache. This will speed up caclulate_scalar() a lot
+ * for fonts with lots of axes and many "monovar" tuples. */
+ hb_array_t<const F2DOT14> shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount);
+ unsigned count = table->sharedTupleCount;
+ if (unlikely (!shared_tuple_active_idx.resize (count, false))) return;
+ unsigned axis_count = table->axisCount;
+ for (unsigned i = 0; i < count; i++)
+ {
+ hb_array_t<const F2DOT14> tuple = shared_tuples.sub_array (axis_count * i, axis_count);
+ int idx1 = -1, idx2 = -1;
+ for (unsigned j = 0; j < axis_count; j++)
+ {
+ const F2DOT14 &peak = tuple.arrayZ[j];
+ if (peak.to_int () != 0)
+ {
+ if (idx1 == -1)
+ idx1 = j;
+ else if (idx2 == -1)
+ idx2 = j;
+ else
+ {
+ idx1 = idx2 = -1;
+ break;
+ }
+ }
+ }
+ shared_tuple_active_idx.arrayZ[i] = {idx1, idx2};
+ }
+ }
~accelerator_t () { table.destroy (); }
private:
@@ -550,50 +622,56 @@ struct gvar
public:
bool apply_deltas_to_points (hb_codepoint_t glyph,
hb_array_t<int> coords,
- const hb_array_t<contour_point_t> points) const
+ const hb_array_t<contour_point_t> points,
+ bool phantom_only = false) const
{
- if (!coords) return true;
-
- if (unlikely (glyph >= table->glyphCount)) return true;
+ if (unlikely (glyph >= glyphCount)) return true;
- hb_bytes_t var_data_bytes = table->get_glyph_var_data_bytes (table.get_blob (), glyph);
+ hb_bytes_t var_data_bytes = table->get_glyph_var_data_bytes (table.get_blob (), glyphCount, glyph);
if (!var_data_bytes.as<GlyphVariationData> ()->has_data ()) return true;
hb_vector_t<unsigned int> shared_indices;
GlyphVariationData::tuple_iterator_t iterator;
if (!GlyphVariationData::get_tuple_iterator (var_data_bytes, table->axisCount,
+ var_data_bytes.arrayZ,
shared_indices, &iterator))
return true; /* so isn't applied at all */
/* Save original points for inferred delta calculation */
- contour_point_vector_t orig_points_vec;
- orig_points_vec.extend (points);
- if (unlikely (orig_points_vec.in_error ())) return false;
+ contour_point_vector_t orig_points_vec; // Populated lazily
auto orig_points = orig_points_vec.as_array ();
- contour_point_vector_t deltas_vec; /* flag is used to indicate referenced point */
- if (unlikely (!deltas_vec.resize (points.length, false))) return false;
+ /* flag is used to indicate referenced point */
+ contour_point_vector_t deltas_vec; // Populated lazily
auto deltas = deltas_vec.as_array ();
- hb_vector_t<unsigned> end_points;
- for (unsigned i = 0; i < points.length; ++i)
- if (points.arrayZ[i].is_end_point)
- end_points.push (i);
+ hb_vector_t<unsigned> end_points; // Populated lazily
unsigned num_coords = table->axisCount;
- hb_array_t<const F2DOT14> shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount);
+ hb_array_t<const F2DOT14> shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * num_coords);
hb_vector_t<unsigned int> private_indices;
hb_vector_t<int> x_deltas;
hb_vector_t<int> y_deltas;
+ unsigned count = points.length;
+ bool flush = false;
do
{
- float scalar = iterator.current_tuple->calculate_scalar (coords, num_coords, shared_tuples);
+ float scalar = iterator.current_tuple->calculate_scalar (coords, num_coords, shared_tuples,
+ &shared_tuple_active_idx);
if (scalar == 0.f) continue;
const HBUINT8 *p = iterator.get_serialized_data ();
unsigned int length = iterator.current_tuple->get_data_size ();
if (unlikely (!iterator.var_data_bytes.check_range (p, length)))
return false;
+ if (!deltas)
+ {
+ if (unlikely (!deltas_vec.resize (count, false))) return false;
+ deltas = deltas_vec.as_array ();
+ hb_memset (deltas.arrayZ + (phantom_only ? count - 4 : 0), 0,
+ (phantom_only ? 4 : count) * sizeof (deltas[0]));
+ }
+
const HBUINT8 *end = p + length;
bool has_private_points = iterator.current_tuple->has_private_points ();
@@ -609,40 +687,108 @@ struct gvar
if (unlikely (!y_deltas.resize (num_deltas, false))) return false;
if (unlikely (!GlyphVariationData::unpack_deltas (p, y_deltas, end))) return false;
- hb_memset (deltas.arrayZ, 0, deltas.get_size ());
+ if (!apply_to_all)
+ {
+ if (!orig_points && !phantom_only)
+ {
+ orig_points_vec.extend (points);
+ if (unlikely (orig_points_vec.in_error ())) return false;
+ orig_points = orig_points_vec.as_array ();
+ }
- unsigned ref_points = 0;
- if (scalar != 1.0f)
+ if (flush)
+ {
+ for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++)
+ points.arrayZ[i].translate (deltas.arrayZ[i]);
+ flush = false;
+
+ }
+ hb_memset (deltas.arrayZ + (phantom_only ? count - 4 : 0), 0,
+ (phantom_only ? 4 : count) * sizeof (deltas[0]));
+ }
+
+ if (HB_OPTIMIZE_SIZE_VAL)
+ {
for (unsigned int i = 0; i < num_deltas; i++)
{
- unsigned int pt_index = apply_to_all ? i : indices[i];
- if (unlikely (pt_index >= deltas.length)) continue;
+ unsigned int pt_index;
+ if (apply_to_all)
+ pt_index = i;
+ else
+ {
+ pt_index = indices[i];
+ if (unlikely (pt_index >= deltas.length)) continue;
+ }
+ if (phantom_only && pt_index < count - 4) continue;
auto &delta = deltas.arrayZ[pt_index];
- ref_points += !delta.flag;
delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
delta.x += x_deltas.arrayZ[i] * scalar;
delta.y += y_deltas.arrayZ[i] * scalar;
}
+ }
else
- for (unsigned int i = 0; i < num_deltas; i++)
+ {
+ /* Ouch. Four cases... for optimization. */
+ if (scalar != 1.0f)
{
- unsigned int pt_index = apply_to_all ? i : indices[i];
- if (unlikely (pt_index >= deltas.length)) continue;
- auto &delta = deltas.arrayZ[pt_index];
- ref_points += !delta.flag;
- delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
- delta.x += x_deltas.arrayZ[i];
- delta.y += y_deltas.arrayZ[i];
+ if (apply_to_all)
+ for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++)
+ {
+ unsigned int pt_index = i;
+ auto &delta = deltas.arrayZ[pt_index];
+ delta.x += x_deltas.arrayZ[i] * scalar;
+ delta.y += y_deltas.arrayZ[i] * scalar;
+ }
+ else
+ for (unsigned int i = 0; i < num_deltas; i++)
+ {
+ unsigned int pt_index = indices[i];
+ if (unlikely (pt_index >= deltas.length)) continue;
+ if (phantom_only && pt_index < count - 4) continue;
+ auto &delta = deltas.arrayZ[pt_index];
+ delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
+ delta.x += x_deltas.arrayZ[i] * scalar;
+ delta.y += y_deltas.arrayZ[i] * scalar;
+ }
}
+ else
+ {
+ if (apply_to_all)
+ for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++)
+ {
+ unsigned int pt_index = i;
+ auto &delta = deltas.arrayZ[pt_index];
+ delta.x += x_deltas.arrayZ[i];
+ delta.y += y_deltas.arrayZ[i];
+ }
+ else
+ for (unsigned int i = 0; i < num_deltas; i++)
+ {
+ unsigned int pt_index = indices[i];
+ if (unlikely (pt_index >= deltas.length)) continue;
+ if (phantom_only && pt_index < count - 4) continue;
+ auto &delta = deltas.arrayZ[pt_index];
+ delta.flag = 1; /* this point is referenced, i.e., explicit deltas specified */
+ delta.x += x_deltas.arrayZ[i];
+ delta.y += y_deltas.arrayZ[i];
+ }
+ }
+ }
/* infer deltas for unreferenced points */
- if (ref_points && ref_points < orig_points.length)
+ if (!apply_to_all && !phantom_only)
{
- unsigned start_point = 0;
- for (unsigned c = 0; c < end_points.length; c++)
+ if (!end_points)
{
- unsigned end_point = end_points.arrayZ[c];
+ for (unsigned i = 0; i < count; ++i)
+ if (points.arrayZ[i].is_end_point)
+ end_points.push (i);
+ if (unlikely (end_points.in_error ())) return false;
+ }
+ unsigned start_point = 0;
+ for (unsigned end_point : end_points)
+ {
/* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */
unsigned unref_count = 0;
for (unsigned i = start_point; i < end_point + 1; i++)
@@ -689,14 +835,16 @@ struct gvar
}
}
- /* apply specified / inferred deltas to points */
- for (unsigned int i = 0; i < points.length; i++)
- {
- points.arrayZ[i].x += deltas.arrayZ[i].x;
- points.arrayZ[i].y += deltas.arrayZ[i].y;
- }
+ flush = true;
+
} while (iterator.move_to_next ());
+ if (flush)
+ {
+ for (unsigned int i = phantom_only ? count - 4 : 0; i < count; i++)
+ points.arrayZ[i].translate (deltas.arrayZ[i]);
+ }
+
return true;
}
@@ -704,6 +852,8 @@ struct gvar
private:
hb_blob_ptr_t<gvar> table;
+ unsigned glyphCount;
+ hb_vector_t<hb_pair_t<int, int>> shared_tuple_active_idx;
};
protected:
@@ -719,7 +869,7 @@ struct gvar
NNOffset32To<UnsizedArrayOf<F2DOT14>>
sharedTuples; /* Offset from the start of this table to the shared tuple records.
* Array of tuple records shared across all glyph variation data tables. */
- HBUINT16 glyphCount; /* The number of glyphs in this font. This must match the number of
+ HBUINT16 glyphCountX; /* The number of glyphs in this font. This must match the number of
* glyphs stored elsewhere in the font. */
HBUINT16 flags; /* Bit-field that gives the format of the offset array that follows.
* If bit 0 is clear, the offsets are uint16; if bit 0 is set, the
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh
index 53355c5077..33a4e1a40e 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-hvar-table.hh
@@ -45,7 +45,8 @@ struct index_map_subset_plan_t
void init (const DeltaSetIndexMap &index_map,
hb_inc_bimap_t &outer_map,
hb_vector_t<hb_set_t *> &inner_sets,
- const hb_subset_plan_t *plan)
+ const hb_subset_plan_t *plan,
+ bool bypass_empty = true)
{
map_count = 0;
outer_bit_count = 0;
@@ -53,55 +54,51 @@ struct index_map_subset_plan_t
max_inners.init ();
output_map.init ();
- if (&index_map == &Null (DeltaSetIndexMap)) return;
+ if (bypass_empty && !index_map.get_map_count ()) return;
unsigned int last_val = (unsigned int)-1;
- hb_codepoint_t last_gid = (hb_codepoint_t)-1;
- hb_codepoint_t gid = (hb_codepoint_t) hb_min (index_map.get_map_count (), plan->num_output_glyphs ());
+ hb_codepoint_t last_gid = HB_CODEPOINT_INVALID;
outer_bit_count = (index_map.get_width () * 8) - index_map.get_inner_bit_count ();
max_inners.resize (inner_sets.length);
for (unsigned i = 0; i < inner_sets.length; i++) max_inners[i] = 0;
/* Search backwards for a map value different from the last map value */
- for (; gid > 0; gid--)
+ auto &new_to_old_gid_list = plan->new_to_old_gid_list;
+ unsigned count = new_to_old_gid_list.length;
+ for (unsigned j = count; j; j--)
{
- hb_codepoint_t old_gid;
- if (!plan->old_gid_for_new_gid (gid - 1, &old_gid))
- {
- if (last_gid == (hb_codepoint_t) -1)
- continue;
- else
- break;
- }
+ hb_codepoint_t gid = new_to_old_gid_list.arrayZ[j - 1].first;
+ hb_codepoint_t old_gid = new_to_old_gid_list.arrayZ[j - 1].second;
unsigned int v = index_map.map (old_gid);
- if (last_gid == (hb_codepoint_t) -1)
+ if (last_gid == HB_CODEPOINT_INVALID)
{
last_val = v;
last_gid = gid;
continue;
}
- if (v != last_val) break;
+ if (v != last_val)
+ break;
last_gid = gid;
}
if (unlikely (last_gid == (hb_codepoint_t)-1)) return;
- map_count = last_gid;
- for (gid = 0; gid < map_count; gid++)
+ map_count = last_gid + 1;
+ for (auto _ : plan->new_to_old_gid_list)
{
- hb_codepoint_t old_gid;
- if (plan->old_gid_for_new_gid (gid, &old_gid))
- {
- unsigned int v = index_map.map (old_gid);
- unsigned int outer = v >> 16;
- unsigned int inner = v & 0xFFFF;
- outer_map.add (outer);
- if (inner > max_inners[outer]) max_inners[outer] = inner;
- if (outer >= inner_sets.length) return;
- inner_sets[outer]->add (inner);
- }
+ hb_codepoint_t gid = _.first;
+ if (gid >= map_count) break;
+
+ hb_codepoint_t old_gid = _.second;
+ unsigned int v = index_map.map (old_gid);
+ unsigned int outer = v >> 16;
+ unsigned int inner = v & 0xFFFF;
+ outer_map.add (outer);
+ if (inner > max_inners[outer]) max_inners[outer] = inner;
+ if (outer >= inner_sets.length) return;
+ inner_sets[outer]->add (inner);
}
}
@@ -116,8 +113,6 @@ struct index_map_subset_plan_t
const hb_vector_t<hb_inc_bimap_t> &inner_maps,
const hb_subset_plan_t *plan)
{
- if (input_map == &Null (DeltaSetIndexMap)) return;
-
for (unsigned int i = 0; i < max_inners.length; i++)
{
if (inner_maps[i].get_population () == 0) continue;
@@ -125,21 +120,50 @@ struct index_map_subset_plan_t
if (bit_count > inner_bit_count) inner_bit_count = bit_count;
}
- output_map.resize (map_count);
- for (hb_codepoint_t gid = 0; gid < output_map.length; gid++)
+ if (unlikely (!output_map.resize (map_count))) return;
+ for (const auto &_ : plan->new_to_old_gid_list)
{
- hb_codepoint_t old_gid;
- if (plan->old_gid_for_new_gid (gid, &old_gid))
- {
- uint32_t v = input_map->map (old_gid);
- unsigned int outer = v >> 16;
- output_map[gid] = (outer_map[outer] << 16) | (inner_maps[outer][v & 0xFFFF]);
- }
- else
- output_map[gid] = 0; /* Map unused glyph to outer/inner=0/0 */
+ hb_codepoint_t new_gid = _.first;
+ hb_codepoint_t old_gid = _.second;
+
+ if (unlikely (new_gid >= map_count)) break;
+
+ uint32_t v = input_map->map (old_gid);
+ unsigned int outer = v >> 16;
+ output_map.arrayZ[new_gid] = (outer_map[outer] << 16) | (inner_maps[outer][v & 0xFFFF]);
}
}
+ bool remap_after_instantiation (const hb_subset_plan_t *plan,
+ const hb_map_t& varidx_map)
+ {
+ /* recalculate bit_count after remapping */
+ outer_bit_count = 1;
+ inner_bit_count = 1;
+
+ for (const auto &_ : plan->new_to_old_gid_list)
+ {
+ hb_codepoint_t new_gid = _.first;
+ if (unlikely (new_gid >= map_count)) break;
+
+ uint32_t v = output_map.arrayZ[new_gid];
+ uint32_t *new_varidx;
+ if (!varidx_map.has (v, &new_varidx))
+ return false;
+
+ output_map.arrayZ[new_gid] = *new_varidx;
+
+ unsigned outer = (*new_varidx) >> 16;
+ unsigned bit_count = (outer == 0) ? 1 : hb_bit_storage (outer);
+ outer_bit_count = hb_max (bit_count, outer_bit_count);
+
+ unsigned inner = (*new_varidx) & 0xFFFF;
+ bit_count = (inner == 0) ? 1 : hb_bit_storage (inner);
+ inner_bit_count = hb_max (bit_count, inner_bit_count);
+ }
+ return true;
+ }
+
unsigned int get_inner_bit_count () const { return inner_bit_count; }
unsigned int get_width () const { return ((outer_bit_count + inner_bit_count + 7) / 8); }
unsigned int get_map_count () const { return map_count; }
@@ -164,7 +188,7 @@ struct hvarvvar_subset_plan_t
~hvarvvar_subset_plan_t() { fini (); }
void init (const hb_array_t<const DeltaSetIndexMap *> &index_maps,
- const VariationStore &_var_store,
+ const ItemVariationStore &_var_store,
const hb_subset_plan_t *plan)
{
index_map_plans.resize (index_maps.length);
@@ -180,17 +204,13 @@ struct hvarvvar_subset_plan_t
if (unlikely (!index_map_plans.length || !inner_sets.length || !inner_maps.length)) return;
bool retain_adv_map = false;
- index_map_plans[0].init (*index_maps[0], outer_map, inner_sets, plan);
+ index_map_plans[0].init (*index_maps[0], outer_map, inner_sets, plan, false);
if (index_maps[0] == &Null (DeltaSetIndexMap))
{
retain_adv_map = plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS;
outer_map.add (0);
- for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++)
- {
- hb_codepoint_t old_gid;
- if (plan->old_gid_for_new_gid (gid, &old_gid))
- inner_sets[0]->add (old_gid);
- }
+ for (hb_codepoint_t old_gid : plan->glyphset()->iter())
+ inner_sets[0]->add (old_gid);
hb_set_union (adv_set, inner_sets[0]);
}
@@ -201,11 +221,11 @@ struct hvarvvar_subset_plan_t
if (retain_adv_map)
{
- for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++)
- if (inner_sets[0]->has (gid))
- inner_maps[0].add (gid);
- else
- inner_maps[0].skip ();
+ for (const auto &_ : plan->new_to_old_gid_list)
+ {
+ hb_codepoint_t old_gid = _.second;
+ inner_maps[0].add (old_gid);
+ }
}
else
{
@@ -221,6 +241,16 @@ struct hvarvvar_subset_plan_t
index_map_plans[i].remap (index_maps[i], outer_map, inner_maps, plan);
}
+ /* remap */
+ bool remap_index_map_plans (const hb_subset_plan_t *plan,
+ const hb_map_t& varidx_map)
+ {
+ for (unsigned i = 0; i < index_map_plans.length; i++)
+ if (!index_map_plans[i].remap_after_instantiation (plan, varidx_map))
+ return false;
+ return true;
+ }
+
void fini ()
{
for (unsigned int i = 0; i < inner_sets.length; i++)
@@ -233,7 +263,7 @@ struct hvarvvar_subset_plan_t
hb_inc_bimap_t outer_map;
hb_vector_t<hb_inc_bimap_t> inner_maps;
hb_vector_t<index_map_subset_plan_t> index_map_plans;
- const VariationStore *var_store;
+ const ItemVariationStore *var_store;
protected:
hb_vector_t<hb_set_t *> inner_sets;
@@ -258,6 +288,7 @@ struct HVARVVAR
{
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
+ hb_barrier () &&
likely (version.major == 1) &&
varStore.sanitize (c, this) &&
advMap.sanitize (c, this) &&
@@ -265,6 +296,9 @@ struct HVARVVAR
rsbMap.sanitize (c, this));
}
+ const ItemVariationStore& get_var_store () const
+ { return this+varStore; }
+
void listup_index_maps (hb_vector_t<const DeltaSetIndexMap *> &index_maps) const
{
index_maps.push (&(this+advMap));
@@ -296,6 +330,9 @@ struct HVARVVAR
bool _subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
+ if (c->plan->all_axes_pinned)
+ return_trace (false);
+
hvarvvar_subset_plan_t hvar_plan;
hb_vector_t<const DeltaSetIndexMap *>
index_maps;
@@ -309,11 +346,37 @@ struct HVARVVAR
out->version.major = 1;
out->version.minor = 0;
- if (unlikely (!out->varStore
- .serialize_serialize (c->serializer,
- hvar_plan.var_store,
- hvar_plan.inner_maps.as_array ())))
+ if (c->plan->normalized_coords)
+ {
+ item_variations_t item_vars;
+ if (!item_vars.instantiate (this+varStore, c->plan,
+ advMap == 0 ? false : true,
+ false, /* use_no_variation_idx = false */
+ hvar_plan.inner_maps.as_array ()))
+ return_trace (false);
+
+ if (!out->varStore.serialize_serialize (c->serializer,
+ item_vars.has_long_word (),
+ c->plan->axis_tags,
+ item_vars.get_region_list (),
+ item_vars.get_vardata_encodings ()))
+ return_trace (false);
+
+ /* if varstore is optimized, remap output_map */
+ if (advMap)
+ {
+ if (!hvar_plan.remap_index_map_plans (c->plan, item_vars.get_varidx_map ()))
+ return_trace (false);
+ }
+ }
+ else
+ {
+ if (unlikely (!out->varStore
+ .serialize_serialize (c->serializer,
+ hvar_plan.var_store,
+ hvar_plan.inner_maps.as_array ())))
return_trace (false);
+ }
return_trace (out->T::serialize_index_maps (c->serializer,
hvar_plan.index_map_plans.as_array ()));
@@ -321,7 +384,7 @@ struct HVARVVAR
float get_advance_delta_unscaled (hb_codepoint_t glyph,
const int *coords, unsigned int coord_count,
- VariationStore::cache_t *store_cache = nullptr) const
+ ItemVariationStore::cache_t *store_cache = nullptr) const
{
uint32_t varidx = (this+advMap).map (glyph);
return (this+varStore).get_delta (varidx,
@@ -342,7 +405,7 @@ struct HVARVVAR
public:
FixedVersion<>version; /* Version of the metrics variation table
* initially set to 0x00010000u */
- Offset32To<VariationStore>
+ Offset32To<ItemVariationStore>
varStore; /* Offset to item variation store table. */
Offset32To<DeltaSetIndexMap>
advMap; /* Offset to advance var-idx mapping. */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-mvar-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-mvar-table.hh
index d27ebb39c0..1f0401d1d3 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-var-mvar-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-var-mvar-table.hh
@@ -27,7 +27,7 @@
#ifndef HB_OT_VAR_MVAR_TABLE_HH
#define HB_OT_VAR_MVAR_TABLE_HH
-#include "hb-ot-layout-common.hh"
+#include "hb-ot-var-common.hh"
namespace OT {
@@ -41,9 +41,22 @@ struct VariationValueRecord
return_trace (c->check_struct (this));
}
+ bool subset (hb_subset_context_t *c,
+ const hb_map_t& varidx_map) const
+ {
+ TRACE_SUBSET (this);
+ auto *out = c->serializer->embed (*this);
+ if (unlikely (!out)) return_trace (false);
+
+ hb_codepoint_t *new_idx;
+ return_trace (c->serializer->check_assign (out->varIdx,
+ (varidx_map.has (varIdx, &new_idx)) ? *new_idx : HB_OT_LAYOUT_NO_VARIATIONS_INDEX,
+ HB_SERIALIZE_ERROR_INT_OVERFLOW));
+ }
+
public:
Tag valueTag; /* Four-byte tag identifying a font-wide measure. */
- VarIdx varIdx; /* Outer/inner index into VariationStore item. */
+ VarIdx varIdx; /* Outer/inner index into ItemVariationStore item. */
public:
DEFINE_SIZE_STATIC (8);
@@ -64,8 +77,10 @@ struct MVAR
{
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
+ hb_barrier () &&
likely (version.major == 1) &&
c->check_struct (this) &&
+ hb_barrier () &&
valueRecordSize >= VariationValueRecord::static_size &&
varStore.sanitize (c, this) &&
c->check_range (valuesZ.arrayZ,
@@ -73,6 +88,47 @@ struct MVAR
valueRecordSize));
}
+ bool subset (hb_subset_context_t *c) const
+ {
+ TRACE_SUBSET (this);
+#ifdef HB_NO_VAR
+ return_trace (false);
+#endif
+
+ if (c->plan->all_axes_pinned)
+ return_trace (false);
+
+ MVAR *out = c->serializer->start_embed (*this);
+ if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+ out->version = version;
+ out->reserved = reserved;
+ out->valueRecordSize = valueRecordSize;
+ out->valueRecordCount = valueRecordCount;
+
+ item_variations_t item_vars;
+ const ItemVariationStore& src_var_store = this+varStore;
+
+ if (!item_vars.instantiate (src_var_store, c->plan))
+ return_trace (false);
+
+ /* serialize varstore */
+ if (!out->varStore.serialize_serialize (c->serializer, item_vars.has_long_word (),
+ c->plan->axis_tags,
+ item_vars.get_region_list (),
+ item_vars.get_vardata_encodings ()))
+ return_trace (false);
+
+ /* serialize value records array */
+ unsigned value_rec_count = valueRecordCount;
+ const VariationValueRecord *record = reinterpret_cast<const VariationValueRecord*> (valuesZ.arrayZ);
+ for (unsigned i = 0; i < value_rec_count; i++)
+ {
+ if (!record->subset (c, item_vars.get_varidx_map ())) return_trace (false);
+ record++;
+ }
+ return_trace (true);
+ }
+
float get_var (hb_tag_t tag,
const int *coords, unsigned int coord_count) const
{
@@ -103,7 +159,7 @@ protected:
HBUINT16 valueRecordSize;/* The size in bytes of each value record —
* must be greater than zero. */
HBUINT16 valueRecordCount;/* The number of value records — may be zero. */
- Offset16To<VariationStore>
+ Offset16To<ItemVariationStore>
varStore; /* Offset to item variation store table. */
UnsizedArrayOf<HBUINT8>
valuesZ; /* Array of value records. The records must be
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-vorg-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-vorg-table.hh
index 811e13919e..95ae8ef559 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-vorg-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-vorg-table.hh
@@ -90,7 +90,7 @@ struct VORG
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
- VORG *vorg_prime = c->serializer->start_embed<VORG> ();
+ auto *vorg_prime = c->serializer->start_embed<VORG> ();
if (unlikely (!c->serializer->check_success (vorg_prime))) return_trace (false);
auto it =
@@ -117,6 +117,7 @@ struct VORG
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
+ hb_barrier () &&
version.major == 1 &&
vertYOrigins.sanitize (c));
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-outline.cc b/src/3rdparty/harfbuzz-ng/src/hb-outline.cc
index 184e48cfb7..29b1f530d5 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-outline.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-outline.cc
@@ -4,7 +4,6 @@
* Copyright © 2005 Werner Lemberg
* Copyright © 2013-2015 Alexei Podtelezhnikov
*
- *
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
@@ -85,7 +84,7 @@ void hb_outline_t::replay (hb_draw_funcs_t *pen, void *pen_data) const
}
}
-float hb_outline_t::area () const
+float hb_outline_t::control_area () const
{
float a = 0;
unsigned first = 0;
@@ -118,7 +117,7 @@ void hb_outline_t::embolden (float x_strength, float y_strength,
x_strength /= 2.f;
y_strength /= 2.f;
- bool orientation_negative = area () < 0;
+ bool orientation_negative = control_area () < 0;
signed first = 0;
for (unsigned c = 0; c < contours.length; c++)
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-outline.hh b/src/3rdparty/harfbuzz-ng/src/hb-outline.hh
index c463993cfb..c43c06596b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-outline.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-outline.hh
@@ -68,7 +68,7 @@ struct hb_outline_t
void reset () { points.shrink (0, false); contours.resize (0); }
HB_INTERNAL void replay (hb_draw_funcs_t *pen, void *pen_data) const;
- HB_INTERNAL float area () const;
+ HB_INTERNAL float control_area () const;
HB_INTERNAL void embolden (float x_strength, float y_strength,
float x_shift, float y_shift);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-paint.cc b/src/3rdparty/harfbuzz-ng/src/hb-paint.cc
index 28150f1638..8eb24eb28b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-paint.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-paint.cc
@@ -54,6 +54,12 @@ static void
hb_paint_pop_transform_nil (hb_paint_funcs_t *funcs, void *paint_data,
void *user_data) {}
+static hb_bool_t
+hb_paint_color_glyph_nil (hb_paint_funcs_t *funcs, void *paint_data,
+ hb_codepoint_t glyph,
+ hb_font_t *font,
+ void *user_data) { return false; }
+
static void
hb_paint_push_clip_glyph_nil (hb_paint_funcs_t *funcs, void *paint_data,
hb_codepoint_t glyph,
@@ -474,6 +480,25 @@ hb_paint_pop_transform (hb_paint_funcs_t *funcs, void *paint_data)
}
/**
+ * hb_paint_color_glyph:
+ * @funcs: paint functions
+ * @paint_data: associated data passed by the caller
+ * @glyph: the glyph ID
+ * @font: the font
+ *
+ * Perform a "color-glyph" paint operation.
+ *
+ * Since: 8.2.0
+ */
+hb_bool_t
+hb_paint_color_glyph (hb_paint_funcs_t *funcs, void *paint_data,
+ hb_codepoint_t glyph,
+ hb_font_t *font)
+{
+ return funcs->color_glyph (paint_data, glyph, font);
+}
+
+/**
* hb_paint_push_clip_glyph:
* @funcs: paint functions
* @paint_data: associated data passed by the caller
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-paint.h b/src/3rdparty/harfbuzz-ng/src/hb-paint.h
index a734f112cc..b0cd384e28 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-paint.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-paint.h
@@ -137,6 +137,26 @@ typedef void (*hb_paint_pop_transform_func_t) (hb_paint_funcs_t *funcs,
void *user_data);
/**
+ * hb_paint_color_glyph_func_t:
+ * @funcs: paint functions object
+ * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
+ * @glyph: the glyph ID
+ * @font: the font
+ * @user_data: User data pointer passed to hb_paint_funcs_set_color_glyph_func()
+ *
+ * A virtual method for the #hb_paint_funcs_t to render a color glyph by glyph index.
+ *
+ * Return value: %true if the glyph was painted, %false otherwise.
+ *
+ * Since: 8.2.0
+ */
+typedef hb_bool_t (*hb_paint_color_glyph_func_t) (hb_paint_funcs_t *funcs,
+ void *paint_data,
+ hb_codepoint_t glyph,
+ hb_font_t *font,
+ void *user_data);
+
+/**
* hb_paint_push_clip_glyph_func_t:
* @funcs: paint functions object
* @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
@@ -616,7 +636,7 @@ typedef enum {
HB_PAINT_COMPOSITE_MODE_HSL_HUE,
HB_PAINT_COMPOSITE_MODE_HSL_SATURATION,
HB_PAINT_COMPOSITE_MODE_HSL_COLOR,
- HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY,
+ HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY
} hb_paint_composite_mode_t;
/**
@@ -724,6 +744,23 @@ hb_paint_funcs_set_pop_transform_func (hb_paint_funcs_t *funcs,
hb_destroy_func_t destroy);
/**
+ * hb_paint_funcs_set_color_glyph_func:
+ * @funcs: A paint functions struct
+ * @func: (closure user_data) (destroy destroy) (scope notified): The color-glyph callback
+ * @user_data: Data to pass to @func
+ * @destroy: (nullable): Function to call when @user_data is no longer needed
+ *
+ * Sets the color-glyph callback on the paint functions struct.
+ *
+ * Since: 8.2.0
+ */
+HB_EXTERN void
+hb_paint_funcs_set_color_glyph_func (hb_paint_funcs_t *funcs,
+ hb_paint_color_glyph_func_t func,
+ void *user_data,
+ hb_destroy_func_t destroy);
+
+/**
* hb_paint_funcs_set_push_clip_glyph_func:
* @funcs: A paint functions struct
* @func: (closure user_data) (destroy destroy) (scope notified): The push-clip-glyph callback
@@ -922,6 +959,11 @@ hb_paint_push_transform (hb_paint_funcs_t *funcs, void *paint_data,
HB_EXTERN void
hb_paint_pop_transform (hb_paint_funcs_t *funcs, void *paint_data);
+HB_EXTERN hb_bool_t
+hb_paint_color_glyph (hb_paint_funcs_t *funcs, void *paint_data,
+ hb_codepoint_t glyph,
+ hb_font_t *font);
+
HB_EXTERN void
hb_paint_push_clip_glyph (hb_paint_funcs_t *funcs, void *paint_data,
hb_codepoint_t glyph,
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-paint.hh b/src/3rdparty/harfbuzz-ng/src/hb-paint.hh
index f7b71aa19b..56b790dbee 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-paint.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-paint.hh
@@ -32,6 +32,7 @@
#define HB_PAINT_FUNCS_IMPLEMENT_CALLBACKS \
HB_PAINT_FUNC_IMPLEMENT (push_transform) \
HB_PAINT_FUNC_IMPLEMENT (pop_transform) \
+ HB_PAINT_FUNC_IMPLEMENT (color_glyph) \
HB_PAINT_FUNC_IMPLEMENT (push_clip_glyph) \
HB_PAINT_FUNC_IMPLEMENT (push_clip_rectangle) \
HB_PAINT_FUNC_IMPLEMENT (pop_clip) \
@@ -77,6 +78,13 @@ struct hb_paint_funcs_t
void pop_transform (void *paint_data)
{ func.pop_transform (this, paint_data,
!user_data ? nullptr : user_data->pop_transform); }
+ bool color_glyph (void *paint_data,
+ hb_codepoint_t glyph,
+ hb_font_t *font)
+ { return func.color_glyph (this, paint_data,
+ glyph,
+ font,
+ !user_data ? nullptr : user_data->push_clip_glyph); }
void push_clip_glyph (void *paint_data,
hb_codepoint_t glyph,
hb_font_t *font)
@@ -203,8 +211,8 @@ struct hb_paint_funcs_t
if (!a)
return false;
- float cc = cosf (a * (float) M_PI);
- float ss = sinf (a * (float) M_PI);
+ float cc = cosf (a * HB_PI);
+ float ss = sinf (a * HB_PI);
push_transform (paint_data, cc, ss, -ss, cc, 0.f, 0.f);
return true;
}
@@ -216,8 +224,8 @@ struct hb_paint_funcs_t
if (!sx && !sy)
return false;
- float x = tanf (-sx * (float) M_PI);
- float y = tanf (+sy * (float) M_PI);
+ float x = tanf (-sx * HB_PI);
+ float y = tanf (+sy * HB_PI);
push_transform (paint_data, 1.f, y, x, 1.f, 0.f, 0.f);
return true;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-pool.hh b/src/3rdparty/harfbuzz-ng/src/hb-pool.hh
index ee43721a38..fcf10666b0 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-pool.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-pool.hh
@@ -29,7 +29,16 @@
#include "hb.hh"
-/* Memory pool for persistent allocation of small objects. */
+/* Memory pool for persistent allocation of small objects.
+ *
+ * Some AI musings on this, not necessarily true:
+ *
+ * This is a very simple implementation, but it's good enough for our
+ * purposes. It's not thread-safe. It's not very fast. It's not
+ * very memory efficient. It's not very cache efficient. It's not
+ * very anything efficient. But it's simple and it works. And it's
+ * good enough for our purposes. If you need something more
+ * sophisticated, use a real allocator. Or use a real language. */
template <typename T, unsigned ChunkLen = 32>
struct hb_pool_t
@@ -49,7 +58,7 @@ struct hb_pool_t
if (unlikely (!next))
{
if (unlikely (!chunks.alloc (chunks.length + 1))) return nullptr;
- chunk_t *chunk = (chunk_t *) hb_calloc (1, sizeof (chunk_t));
+ chunk_t *chunk = (chunk_t *) hb_malloc (sizeof (chunk_t));
if (unlikely (!chunk)) return nullptr;
chunks.push (chunk);
next = chunk->thread ();
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh b/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh
index 93a7842eb0..274d5df4c5 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-priority-queue.hh
@@ -35,11 +35,18 @@
*
* Priority queue implemented as a binary heap. Supports extract minimum
* and insert operations.
+ *
+ * The priority queue is implemented as a binary heap, which is a complete
+ * binary tree. The root of the tree is the minimum element. The heap
+ * property is that the priority of a node is less than or equal to the
+ * priority of its children. The heap is stored in an array, with the
+ * children of node i stored at indices 2i + 1 and 2i + 2.
*/
+template <typename K>
struct hb_priority_queue_t
{
private:
- typedef hb_pair_t<int64_t, unsigned> item_t;
+ typedef hb_pair_t<K, unsigned> item_t;
hb_vector_t<item_t> heap;
public:
@@ -48,13 +55,22 @@ struct hb_priority_queue_t
bool in_error () const { return heap.in_error (); }
- void insert (int64_t priority, unsigned value)
+ bool alloc (unsigned size)
+ { return heap.alloc (size); }
+
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
+ void insert (K priority, unsigned value)
{
heap.push (item_t (priority, value));
if (unlikely (heap.in_error ())) return;
bubble_up (heap.length - 1);
}
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
item_t pop_minimum ()
{
assert (!is_empty ());
@@ -100,8 +116,10 @@ struct hb_priority_queue_t
return 2 * index + 2;
}
+ HB_ALWAYS_INLINE
void bubble_down (unsigned index)
{
+ repeat:
assert (index < heap.length);
unsigned left = left_child (index);
@@ -117,19 +135,21 @@ struct hb_priority_queue_t
&& (!has_right || heap.arrayZ[index].first <= heap.arrayZ[right].first))
return;
+ unsigned child;
if (!has_right || heap.arrayZ[left].first < heap.arrayZ[right].first)
- {
- swap (index, left);
- bubble_down (left);
- return;
- }
+ child = left;
+ else
+ child = right;
- swap (index, right);
- bubble_down (right);
+ swap (index, child);
+ index = child;
+ goto repeat;
}
+ HB_ALWAYS_INLINE
void bubble_up (unsigned index)
{
+ repeat:
assert (index < heap.length);
if (index == 0) return;
@@ -139,10 +159,11 @@ struct hb_priority_queue_t
return;
swap (index, parent_index);
- bubble_up (parent_index);
+ index = parent_index;
+ goto repeat;
}
- void swap (unsigned a, unsigned b)
+ void swap (unsigned a, unsigned b) noexcept
{
assert (a < heap.length);
assert (b < heap.length);
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-repacker.hh b/src/3rdparty/harfbuzz-ng/src/hb-repacker.hh
index cd57ade072..ed40f271cc 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-repacker.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-repacker.hh
@@ -79,7 +79,12 @@ bool _presplit_subtables_if_needed (graph::gsubgpos_graph_context_t& ext_context
// pass after this processing is done. Not super necessary as splits are
// only done where overflow is likely, so de-dup probably will get undone
// later anyways.
- for (unsigned lookup_index : ext_context.lookups.keys ())
+
+ // The loop below can modify the contents of ext_context.lookups if new subtables are added
+ // to a lookup during a split. So save the initial set of lookup indices so the iteration doesn't
+ // risk access free'd memory if ext_context.lookups gets resized.
+ hb_set_t lookup_indices(ext_context.lookups.keys ());
+ for (unsigned lookup_index : lookup_indices)
{
graph::Lookup* lookup = ext_context.lookups.get(lookup_index);
if (!lookup->split_subtables_if_needed (ext_context, lookup_index))
@@ -114,11 +119,15 @@ bool _promote_extensions_if_needed (graph::gsubgpos_graph_context_t& ext_context
// TODO(grieger): skip this for the 24 bit case.
if (!ext_context.lookups) return true;
+ unsigned total_lookup_table_sizes = 0;
hb_vector_t<lookup_size_t> lookup_sizes;
lookup_sizes.alloc (ext_context.lookups.get_population (), true);
for (unsigned lookup_index : ext_context.lookups.keys ())
{
+ const auto& lookup_v = ext_context.graph.vertices_[lookup_index];
+ total_lookup_table_sizes += lookup_v.table_size ();
+
const graph::Lookup* lookup = ext_context.lookups.get(lookup_index);
hb_set_t visited;
lookup_sizes.push (lookup_size_t {
@@ -131,14 +140,16 @@ bool _promote_extensions_if_needed (graph::gsubgpos_graph_context_t& ext_context
lookup_sizes.qsort ();
size_t lookup_list_size = ext_context.graph.vertices_[ext_context.lookup_list_index].table_size ();
- size_t l2_l3_size = lookup_list_size; // Lookup List + Lookups
- size_t l3_l4_size = 0; // Lookups + SubTables
+ size_t l2_l3_size = lookup_list_size + total_lookup_table_sizes; // Lookup List + Lookups
+ size_t l3_l4_size = total_lookup_table_sizes; // Lookups + SubTables
size_t l4_plus_size = 0; // SubTables + their descendants
// Start by assuming all lookups are using extension subtables, this size will be removed later
// if it's decided to not make a lookup extension.
for (auto p : lookup_sizes)
{
+ // TODO(garretrieger): this overestimates the extension subtables size because some extension subtables may be
+ // reused. However, we can't correct this until we have connected component analysis in place.
unsigned subtables_size = p.num_subtables * 8;
l3_l4_size += subtables_size;
l4_plus_size += subtables_size;
@@ -159,8 +170,7 @@ bool _promote_extensions_if_needed (graph::gsubgpos_graph_context_t& ext_context
size_t subtables_size = ext_context.graph.find_subgraph_size (p.lookup_index, visited, 1) - lookup_size;
size_t remaining_size = p.size - subtables_size - lookup_size;
- l2_l3_size += lookup_size;
- l3_l4_size += lookup_size + subtables_size;
+ l3_l4_size += subtables_size;
l3_l4_size -= p.num_subtables * 8;
l4_plus_size += subtables_size + remaining_size;
@@ -229,6 +239,54 @@ bool _try_isolating_subgraphs (const hb_vector_t<graph::overflow_record_t>& over
}
static inline
+bool _resolve_shared_overflow(const hb_vector_t<graph::overflow_record_t>& overflows,
+ int overflow_index,
+ graph_t& sorted_graph)
+{
+ const graph::overflow_record_t& r = overflows[overflow_index];
+
+ // Find all of the parents in overflowing links that link to this
+ // same child node. We will then try duplicating the child node and
+ // re-assigning all of these parents to the duplicate.
+ hb_set_t parents;
+ parents.add(r.parent);
+ for (int i = overflow_index - 1; i >= 0; i--) {
+ const graph::overflow_record_t& r2 = overflows[i];
+ if (r2.child == r.child) {
+ parents.add(r2.parent);
+ }
+ }
+
+ unsigned result = sorted_graph.duplicate(&parents, r.child);
+ if (result == (unsigned) -1 && parents.get_population() > 2) {
+ // All links to the child are overflowing, so we can't include all
+ // in the duplication. Remove one parent from the duplication.
+ // Remove the lowest index parent, which will be the closest to the child.
+ parents.del(parents.get_min());
+ result = sorted_graph.duplicate(&parents, r.child);
+ }
+
+ if (result == (unsigned) -1) return result;
+
+ if (parents.get_population() > 1) {
+ // If the duplicated node has more than one parent pre-emptively raise it's priority to the maximum.
+ // This will place it close to the parents. Node's with only one parent, don't need this as normal overflow
+ // resolution will raise priority if needed.
+ //
+ // Reasoning: most of the parents to this child are likely at the same layer in the graph. Duplicating
+ // the child will theoretically allow it to be placed closer to it's parents. However, due to the shortest
+ // distance sort by default it's placement will remain in the same layer, thus it will remain in roughly the
+ // same position (and distance from parents) as the original child node. The overflow resolution will attempt
+ // to move nodes closer, but only for non-shared nodes. Since this node is shared, it will simply be given
+ // further duplication which defeats the attempt to duplicate with multiple parents. To fix this we
+ // pre-emptively raise priority now which allows the duplicated node to pack into the same layer as it's parents.
+ sorted_graph.vertices_[result].give_max_priority();
+ }
+
+ return result;
+}
+
+static inline
bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows,
hb_set_t& priority_bumped_parents,
graph_t& sorted_graph)
@@ -244,7 +302,7 @@ bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows,
{
// The child object is shared, we may be able to eliminate the overflow
// by duplicating it.
- if (sorted_graph.duplicate (r.parent, r.child) == (unsigned) -1) continue;
+ if (!_resolve_shared_overflow(overflows, i, sorted_graph)) continue;
return true;
}
@@ -378,7 +436,7 @@ template<typename T>
inline hb_blob_t*
hb_resolve_overflows (const T& packed,
hb_tag_t table_tag,
- unsigned max_rounds = 20,
+ unsigned max_rounds = 32,
bool recalculate_extensions = false) {
graph_t sorted_graph (packed);
if (sorted_graph.in_error ())
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-sanitize.hh b/src/3rdparty/harfbuzz-ng/src/hb-sanitize.hh
index eb907c6b2a..408649c768 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-sanitize.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-sanitize.hh
@@ -122,17 +122,22 @@ struct hb_sanitize_context_t :
{
hb_sanitize_context_t () :
start (nullptr), end (nullptr),
+ length (0),
max_ops (0), max_subtables (0),
recursion_depth (0),
writable (false), edit_count (0),
blob (nullptr),
num_glyphs (65536),
- num_glyphs_set (false) {}
+ num_glyphs_set (false),
+ lazy_some_gpos (false) {}
const char *get_name () { return "SANITIZE"; }
template <typename T, typename F>
bool may_dispatch (const T *obj HB_UNUSED, const F *format)
- { return format->sanitize (this); }
+ {
+ return format->sanitize (this) &&
+ hb_barrier ();
+ }
static return_t default_return_value () { return true; }
static return_t no_dispatch_return_value () { return false; }
bool stop_sublookup_iteration (const return_t r) const { return !r; }
@@ -155,6 +160,19 @@ struct hb_sanitize_context_t :
dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN
( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )
+ hb_sanitize_context_t (hb_blob_t *b) : hb_sanitize_context_t ()
+ {
+ init (b);
+
+ if (blob)
+ start_processing ();
+ }
+
+ ~hb_sanitize_context_t ()
+ {
+ if (blob)
+ end_processing ();
+ }
void init (hb_blob_t *b)
{
@@ -180,11 +198,15 @@ struct hb_sanitize_context_t :
const char *obj_start = (const char *) obj;
if (unlikely (obj_start < this->start || this->end <= obj_start))
+ {
this->start = this->end = nullptr;
+ this->length = 0;
+ }
else
{
this->start = obj_start;
this->end = obj_start + hb_min (size_t (this->end - obj_start), obj->get_size ());
+ this->length = this->end - this->start;
}
}
@@ -192,6 +214,7 @@ struct hb_sanitize_context_t :
{
this->start = this->blob->data;
this->end = this->start + this->blob->length;
+ this->length = this->end - this->start;
assert (this->start <= this->end); /* Must not overflow. */
}
@@ -224,19 +247,34 @@ struct hb_sanitize_context_t :
hb_blob_destroy (this->blob);
this->blob = nullptr;
this->start = this->end = nullptr;
+ this->length = 0;
}
unsigned get_edit_count () { return edit_count; }
+
+ bool check_ops(unsigned count)
+ {
+ /* Avoid underflow */
+ if (unlikely (this->max_ops < 0 || count >= (unsigned) this->max_ops))
+ {
+ this->max_ops = -1;
+ return false;
+ }
+ this->max_ops -= (int) count;
+ return true;
+ }
+
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
bool check_range (const void *base,
unsigned int len) const
{
const char *p = (const char *) base;
- bool ok = !len ||
- (this->start <= p &&
- p <= this->end &&
- (unsigned int) (this->end - p) >= len &&
- (this->max_ops -= len) > 0);
+ bool ok = (uintptr_t) (p - this->start) <= this->length &&
+ (unsigned int) (this->end - p) >= len &&
+ ((this->max_ops -= len) > 0);
DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
"check_range [%p..%p]"
@@ -247,6 +285,43 @@ struct hb_sanitize_context_t :
return likely (ok);
}
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
+ bool check_range_fast (const void *base,
+ unsigned int len) const
+ {
+ const char *p = (const char *) base;
+ bool ok = ((uintptr_t) (p - this->start) <= this->length &&
+ (unsigned int) (this->end - p) >= len);
+
+ DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
+ "check_range_fast [%p..%p]"
+ " (%u bytes) in [%p..%p] -> %s",
+ p, p + len, len,
+ this->start, this->end,
+ ok ? "OK" : "OUT-OF-RANGE");
+
+ return likely (ok);
+ }
+
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
+ bool check_point (const void *base) const
+ {
+ const char *p = (const char *) base;
+ bool ok = (uintptr_t) (p - this->start) <= this->length;
+
+ DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
+ "check_point [%p]"
+ " in [%p..%p] -> %s",
+ p,
+ this->start, this->end,
+ ok ? "OK" : "OUT-OF-RANGE");
+
+ return likely (ok);
+ }
template <typename T>
bool check_range (const T *base,
@@ -270,6 +345,20 @@ struct hb_sanitize_context_t :
}
template <typename T>
+ HB_ALWAYS_INLINE
+ bool check_array_sized (const T *base, unsigned int len, unsigned len_size) const
+ {
+ if (len_size >= 4)
+ {
+ if (unlikely (hb_unsigned_mul_overflows (len, hb_static_size (T), &len)))
+ return false;
+ }
+ else
+ len = len * hb_static_size (T);
+ return this->check_range (base, len);
+ }
+
+ template <typename T>
bool check_array (const T *base, unsigned int len) const
{
return this->check_range (base, len, hb_static_size (T));
@@ -280,7 +369,7 @@ struct hb_sanitize_context_t :
unsigned int a,
unsigned int b) const
{
- return this->check_range (base, a, b, hb_static_size (T));
+ return this->check_range (base, hb_static_size (T), a, b);
}
bool check_start_recursion (int max_depth)
@@ -296,8 +385,16 @@ struct hb_sanitize_context_t :
}
template <typename Type>
+#ifndef HB_OPTIMIZE_SIZE
+ HB_ALWAYS_INLINE
+#endif
bool check_struct (const Type *obj) const
- { return likely (this->check_range (obj, obj->min_size)); }
+ {
+ if (sizeof (uintptr_t) == sizeof (uint32_t))
+ return likely (this->check_range_fast (obj, obj->min_size));
+ else
+ return likely (this->check_point ((const char *) obj + obj->min_size));
+ }
bool may_edit (const void *base, unsigned int len)
{
@@ -359,7 +456,7 @@ struct hb_sanitize_context_t :
edit_count = 0;
sane = t->sanitize (this);
if (edit_count) {
- DEBUG_MSG_FUNC (SANITIZE, start, "requested %u edits in second round; FAILLING", edit_count);
+ DEBUG_MSG_FUNC (SANITIZE, start, "requested %u edits in second round; FAILING", edit_count);
sane = false;
}
}
@@ -404,6 +501,7 @@ struct hb_sanitize_context_t :
}
const char *start, *end;
+ unsigned length;
mutable int max_ops, max_subtables;
private:
int recursion_depth;
@@ -412,6 +510,8 @@ struct hb_sanitize_context_t :
hb_blob_t *blob;
unsigned int num_glyphs;
bool num_glyphs_set;
+ public:
+ bool lazy_some_gpos;
};
struct hb_sanitize_with_object_t
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh b/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh
index 61ec0253a0..e988451eb3 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-serialize.hh
@@ -91,7 +91,27 @@ struct hb_serialize_context_t
}
#endif
- friend void swap (object_t& a, object_t& b)
+ bool add_virtual_link (objidx_t objidx)
+ {
+ if (!objidx)
+ return false;
+
+ auto& link = *virtual_links.push ();
+ if (virtual_links.in_error ())
+ return false;
+
+ link.objidx = objidx;
+ // Remaining fields were previously zero'd by push():
+ // link.width = 0;
+ // link.is_signed = 0;
+ // link.whence = 0;
+ // link.position = 0;
+ // link.bias = 0;
+
+ return true;
+ }
+
+ friend void swap (object_t& a, object_t& b) noexcept
{
hb_swap (a.head, b.head);
hb_swap (a.tail, b.tail);
@@ -113,7 +133,7 @@ struct hb_serialize_context_t
{
// Virtual links aren't considered for equality since they don't affect the functionality
// of the object.
- return hb_bytes_t (head, tail - head).hash () ^
+ return hb_bytes_t (head, hb_min (128, tail - head)).hash () ^
real_links.as_bytes ().hash ();
}
@@ -156,9 +176,9 @@ struct hb_serialize_context_t
object_t *next;
auto all_links () const HB_AUTO_RETURN
- (( hb_concat (this->real_links, this->virtual_links) ));
+ (( hb_concat (real_links, virtual_links) ));
auto all_links_writer () HB_AUTO_RETURN
- (( hb_concat (this->real_links.writer (), this->virtual_links.writer ()) ));
+ (( hb_concat (real_links.writer (), virtual_links.writer ()) ));
};
struct snapshot_t
@@ -172,8 +192,14 @@ struct hb_serialize_context_t
};
snapshot_t snapshot ()
- { return snapshot_t {
- head, tail, current, current->real_links.length, current->virtual_links.length, errors }; }
+ {
+ return snapshot_t {
+ head, tail, current,
+ current ? current->real_links.length : 0,
+ current ? current->virtual_links.length : 0,
+ errors
+ };
+ }
hb_serialize_context_t (void *start_, unsigned int size) :
start ((char *) start_),
@@ -260,7 +286,8 @@ struct hb_serialize_context_t
propagate_error (std::forward<Ts> (os)...); }
/* To be called around main operation. */
- template <typename Type>
+ template <typename Type=char>
+ __attribute__((returns_nonnull))
Type *start_serialize ()
{
DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1,
@@ -303,6 +330,7 @@ struct hb_serialize_context_t
}
template <typename Type = void>
+ __attribute__((returns_nonnull))
Type *push ()
{
if (unlikely (in_error ())) return start_embed<Type> ();
@@ -323,6 +351,8 @@ struct hb_serialize_context_t
{
object_t *obj = current;
if (unlikely (!obj)) return;
+ // Allow cleanup when we've error'd out on int overflows which don't compromise
+ // the serializer state.
if (unlikely (in_error() && !only_overflow ())) return;
current = current->next;
@@ -340,7 +370,9 @@ struct hb_serialize_context_t
{
object_t *obj = current;
if (unlikely (!obj)) return 0;
- if (unlikely (in_error())) return 0;
+ // Allow cleanup when we've error'd out on int overflows which don't compromise
+ // the serializer state.
+ if (unlikely (in_error() && !only_overflow ())) return 0;
current = current->next;
obj->tail = head;
@@ -405,8 +437,11 @@ struct hb_serialize_context_t
// Overflows that happened after the snapshot will be erased by the revert.
if (unlikely (in_error () && !only_overflow ())) return;
assert (snap.current == current);
- current->real_links.shrink (snap.num_real_links);
- current->virtual_links.shrink (snap.num_virtual_links);
+ if (current)
+ {
+ current->real_links.shrink (snap.num_real_links);
+ current->virtual_links.shrink (snap.num_virtual_links);
+ }
errors = snap.errors;
revert (snap.head, snap.tail);
}
@@ -454,16 +489,40 @@ struct hb_serialize_context_t
assert (current);
- auto& link = *current->virtual_links.push ();
- if (current->virtual_links.in_error ())
+ if (!current->add_virtual_link(objidx))
err (HB_SERIALIZE_ERROR_OTHER);
+ }
- link.width = 0;
- link.objidx = objidx;
- link.is_signed = 0;
- link.whence = 0;
- link.position = 0;
- link.bias = 0;
+ objidx_t last_added_child_index() const {
+ if (unlikely (in_error ())) return (objidx_t) -1;
+
+ assert (current);
+ if (!bool(current->real_links)) {
+ return (objidx_t) -1;
+ }
+
+ return current->real_links[current->real_links.length - 1].objidx;
+ }
+
+ // For the current object ensure that the sub-table bytes for child objidx are always placed
+ // after the subtable bytes for any other existing children. This only ensures that the
+ // repacker will not move the target subtable before the other children
+ // (by adding virtual links). It is up to the caller to ensure the initial serialization
+ // order is correct.
+ void repack_last(objidx_t objidx) {
+ if (unlikely (in_error ())) return;
+
+ if (!objidx)
+ return;
+
+ assert (current);
+ for (auto& l : current->real_links) {
+ if (l.objidx == objidx) {
+ continue;
+ }
+
+ packed[l.objidx]->add_virtual_link(objidx);
+ }
}
template <typename T>
@@ -563,13 +622,15 @@ struct hb_serialize_context_t
{
unsigned int l = length () % alignment;
if (l)
- allocate_size<void> (alignment - l);
+ (void) allocate_size<void> (alignment - l);
}
template <typename Type = void>
+ __attribute__((returns_nonnull))
Type *start_embed (const Type *obj HB_UNUSED = nullptr) const
{ return reinterpret_cast<Type *> (this->head); }
template <typename Type>
+ __attribute__((returns_nonnull))
Type *start_embed (const Type &obj) const
{ return start_embed (std::addressof (obj)); }
@@ -597,6 +658,7 @@ struct hb_serialize_context_t
}
template <typename Type>
+ HB_NODISCARD
Type *allocate_size (size_t size, bool clear = true)
{
if (unlikely (in_error ())) return nullptr;
@@ -618,6 +680,7 @@ struct hb_serialize_context_t
{ return this->allocate_size<Type> (Type::min_size); }
template <typename Type>
+ HB_NODISCARD
Type *embed (const Type *obj)
{
unsigned int size = obj->get_size ();
@@ -627,6 +690,7 @@ struct hb_serialize_context_t
return ret;
}
template <typename Type>
+ HB_NODISCARD
Type *embed (const Type &obj)
{ return embed (std::addressof (obj)); }
char *embed (const char *obj, unsigned size)
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh b/src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh
index e8409111f2..5681641baa 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-set-digest.hh
@@ -45,10 +45,16 @@
* a lookup's or subtable's Coverage table(s), and then when we
* want to apply the lookup or subtable to a glyph, before trying
* to apply, we ask the filter if the glyph may be covered. If it's
- * not, we return early.
+ * not, we return early. We can also match a digest against another
+ * digest.
*
- * We use these filters both at the lookup-level, and then again,
- * at the subtable-level. Both have performance win.
+ * We use these filters at three levels:
+ * - If the digest for all the glyphs in the buffer as a whole
+ * does not match the digest for the lookup, skip the lookup.
+ * - For each glyph, if it doesn't match the lookup digest,
+ * skip it.
+ * - For each glyph, if it doesn't match the subtable digest,
+ * skip it.
*
* The main filter we use is a combination of three bits-pattern
* filters. A bits-pattern filter checks a number of bits (5 or 6)
@@ -82,14 +88,19 @@ struct hb_set_digest_bits_pattern_t
bool add_range (hb_codepoint_t a, hb_codepoint_t b)
{
+ if (mask == (mask_t) -1) return false;
if ((b >> shift) - (a >> shift) >= mask_bits - 1)
+ {
mask = (mask_t) -1;
- else {
+ return false;
+ }
+ else
+ {
mask_t ma = mask_for (a);
mask_t mb = mask_for (b);
mask |= mb + (mb - ma) - (mb < ma);
+ return true;
}
- return true;
}
template <typename T>
@@ -148,8 +159,7 @@ struct hb_set_digest_combiner_t
bool add_range (hb_codepoint_t a, hb_codepoint_t b)
{
- return head.add_range (a, b) &&
- tail.add_range (a, b);
+ return (int) head.add_range (a, b) | (int) tail.add_range (a, b);
}
template <typename T>
void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-set.cc b/src/3rdparty/harfbuzz-ng/src/hb-set.cc
index 97caddb226..a9386c5c91 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-set.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-set.cc
@@ -200,7 +200,7 @@ hb_set_copy (const hb_set_t *set)
void
hb_set_clear (hb_set_t *set)
{
- /* Immutible-safe. */
+ /* Immutable-safe. */
set->clear ();
}
@@ -251,7 +251,7 @@ void
hb_set_add (hb_set_t *set,
hb_codepoint_t codepoint)
{
- /* Immutible-safe. */
+ /* Immutable-safe. */
set->add (codepoint);
}
@@ -272,7 +272,7 @@ hb_set_add_sorted_array (hb_set_t *set,
const hb_codepoint_t *sorted_codepoints,
unsigned int num_codepoints)
{
- /* Immutible-safe. */
+ /* Immutable-safe. */
set->add_sorted_array (sorted_codepoints,
num_codepoints,
sizeof(hb_codepoint_t));
@@ -294,7 +294,7 @@ hb_set_add_range (hb_set_t *set,
hb_codepoint_t first,
hb_codepoint_t last)
{
- /* Immutible-safe. */
+ /* Immutable-safe. */
set->add_range (first, last);
}
@@ -311,7 +311,7 @@ void
hb_set_del (hb_set_t *set,
hb_codepoint_t codepoint)
{
- /* Immutible-safe. */
+ /* Immutable-safe. */
set->del (codepoint);
}
@@ -334,7 +334,7 @@ hb_set_del_range (hb_set_t *set,
hb_codepoint_t first,
hb_codepoint_t last)
{
- /* Immutible-safe. */
+ /* Immutable-safe. */
set->del_range (first, last);
}
@@ -405,7 +405,7 @@ void
hb_set_set (hb_set_t *set,
const hb_set_t *other)
{
- /* Immutible-safe. */
+ /* Immutable-safe. */
set->set (*other);
}
@@ -422,7 +422,7 @@ void
hb_set_union (hb_set_t *set,
const hb_set_t *other)
{
- /* Immutible-safe. */
+ /* Immutable-safe. */
set->union_ (*other);
}
@@ -439,7 +439,7 @@ void
hb_set_intersect (hb_set_t *set,
const hb_set_t *other)
{
- /* Immutible-safe. */
+ /* Immutable-safe. */
set->intersect (*other);
}
@@ -456,7 +456,7 @@ void
hb_set_subtract (hb_set_t *set,
const hb_set_t *other)
{
- /* Immutible-safe. */
+ /* Immutable-safe. */
set->subtract (*other);
}
@@ -474,7 +474,7 @@ void
hb_set_symmetric_difference (hb_set_t *set,
const hb_set_t *other)
{
- /* Immutible-safe. */
+ /* Immutable-safe. */
set->symmetric_difference (*other);
}
@@ -489,7 +489,7 @@ hb_set_symmetric_difference (hb_set_t *set,
void
hb_set_invert (hb_set_t *set)
{
- /* Immutible-safe. */
+ /* Immutable-safe. */
set->invert ();
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-set.h b/src/3rdparty/harfbuzz-ng/src/hb-set.h
index de53231030..192abf6f63 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-set.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-set.h
@@ -43,7 +43,7 @@ HB_BEGIN_DECLS
*
* Since: 0.9.21
*/
-#define HB_SET_VALUE_INVALID ((hb_codepoint_t) -1)
+#define HB_SET_VALUE_INVALID HB_CODEPOINT_INVALID
/**
* hb_set_t:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-set.hh b/src/3rdparty/harfbuzz-ng/src/hb-set.hh
index 604802381b..ce69ea2c9b 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-set.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-set.hh
@@ -35,6 +35,8 @@
template <typename impl_t>
struct hb_sparseset_t
{
+ static constexpr bool realloc_move = true;
+
hb_object_header_t header;
impl_t s;
@@ -42,10 +44,10 @@ struct hb_sparseset_t
~hb_sparseset_t () { fini (); }
hb_sparseset_t (const hb_sparseset_t& other) : hb_sparseset_t () { set (other); }
- hb_sparseset_t (hb_sparseset_t&& other) : hb_sparseset_t () { s = std::move (other.s); }
+ hb_sparseset_t (hb_sparseset_t&& other) noexcept : hb_sparseset_t () { s = std::move (other.s); }
hb_sparseset_t& operator = (const hb_sparseset_t& other) { set (other); return *this; }
- hb_sparseset_t& operator = (hb_sparseset_t&& other) { s = std::move (other.s); return *this; }
- friend void swap (hb_sparseset_t& a, hb_sparseset_t& b) { hb_swap (a.s, b.s); }
+ hb_sparseset_t& operator = (hb_sparseset_t&& other) noexcept { s = std::move (other.s); return *this; }
+ friend void swap (hb_sparseset_t& a, hb_sparseset_t& b) noexcept { hb_swap (a.s, b.s); }
hb_sparseset_t (std::initializer_list<hb_codepoint_t> lst) : hb_sparseset_t ()
{
@@ -115,7 +117,7 @@ struct hb_sparseset_t
/* Sink interface. */
hb_sparseset_t& operator << (hb_codepoint_t v)
{ add (v); return *this; }
- hb_sparseset_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
+ hb_sparseset_t& operator << (const hb_codepoint_pair_t& range)
{ add_range (range.first, range.second); return *this; }
bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
@@ -164,7 +166,7 @@ struct hb_set_t : hb_sparseset_t<hb_bit_set_invertible_t>
~hb_set_t () = default;
hb_set_t () : sparseset () {};
hb_set_t (const hb_set_t &o) : sparseset ((sparseset &) o) {};
- hb_set_t (hb_set_t&& o) : sparseset (std::move ((sparseset &) o)) {}
+ hb_set_t (hb_set_t&& o) noexcept : sparseset (std::move ((sparseset &) o)) {}
hb_set_t& operator = (const hb_set_t&) = default;
hb_set_t& operator = (hb_set_t&&) = default;
hb_set_t (std::initializer_list<hb_codepoint_t> lst) : sparseset (lst) {}
@@ -174,7 +176,7 @@ struct hb_set_t : hb_sparseset_t<hb_bit_set_invertible_t>
hb_set_t& operator << (hb_codepoint_t v)
{ sparseset::operator<< (v); return *this; }
- hb_set_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
+ hb_set_t& operator << (const hb_codepoint_pair_t& range)
{ sparseset::operator<< (range); return *this; }
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-shape.cc b/src/3rdparty/harfbuzz-ng/src/hb-shape.cc
index 7b5bf2c5ef..844f7b9e80 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-shape.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-shape.cc
@@ -196,4 +196,250 @@ hb_shape (hb_font_t *font,
}
+#ifdef HB_EXPERIMENTAL_API
+
+static float
+buffer_advance (hb_buffer_t *buffer)
+{
+ float a = 0;
+ auto *pos = buffer->pos;
+ unsigned count = buffer->len;
+ if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
+ for (unsigned i = 0; i < count; i++)
+ a += pos[i].x_advance;
+ else
+ for (unsigned i = 0; i < count; i++)
+ a += pos[i].y_advance;
+ return a;
+}
+
+static void
+reset_buffer (hb_buffer_t *buffer,
+ hb_array_t<const hb_glyph_info_t> text)
+{
+ assert (buffer->ensure (text.length));
+ buffer->have_positions = false;
+ buffer->len = text.length;
+ hb_memcpy (buffer->info, text.arrayZ, text.length * sizeof (buffer->info[0]));
+ hb_buffer_set_content_type (buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
+}
+
+/**
+ * hb_shape_justify:
+ * @font: a mutable #hb_font_t to use for shaping
+ * @buffer: an #hb_buffer_t to shape
+ * @features: (array length=num_features) (nullable): an array of user
+ * specified #hb_feature_t or `NULL`
+ * @num_features: the length of @features array
+ * @shaper_list: (array zero-terminated=1) (nullable): a `NULL`-terminated
+ * array of shapers to use or `NULL`
+ * @min_target_advance: Minimum advance width/height to aim for.
+ * @max_target_advance: Maximum advance width/height to aim for.
+ * @advance: (inout): Input/output advance width/height of the buffer.
+ * @var_tag: (out): Variation-axis tag used for justification.
+ * @var_value: (out): Variation-axis value used to reach target justification.
+ *
+ * See hb_shape_full() for basic details. If @shaper_list is not `NULL`, the specified
+ * shapers will be used in the given order, otherwise the default shapers list
+ * will be used.
+ *
+ * In addition, justify the shaping results such that the shaping results reach
+ * the target advance width/height, depending on the buffer direction.
+ *
+ * If the advance of the buffer shaped with hb_shape_full() is already known,
+ * put that in *advance. Otherwise set *advance to zero.
+ *
+ * This API is currently experimental and will probably change in the future.
+ *
+ * Return value: false if all shapers failed, true otherwise
+ *
+ * XSince: EXPERIMENTAL
+ **/
+hb_bool_t
+hb_shape_justify (hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features,
+ const char * const *shaper_list,
+ float min_target_advance,
+ float max_target_advance,
+ float *advance, /* IN/OUT */
+ hb_tag_t *var_tag, /* OUT */
+ float *var_value /* OUT */)
+{
+ // TODO Negative font scales?
+
+ /* If default advance already matches target, nothing to do. Shape and return. */
+ if (min_target_advance <= *advance && *advance <= max_target_advance)
+ {
+ *var_tag = HB_TAG_NONE;
+ *var_value = 0.0f;
+ return hb_shape_full (font, buffer,
+ features, num_features,
+ shaper_list);
+ }
+
+ hb_face_t *face = font->face;
+
+ /* Choose variation tag to use for justification. */
+
+ hb_tag_t tag = HB_TAG_NONE;
+ hb_ot_var_axis_info_t axis_info;
+
+ hb_tag_t tags[] =
+ {
+ HB_TAG ('j','s','t','f'),
+ HB_TAG ('w','d','t','h'),
+ };
+ for (unsigned i = 0; i < ARRAY_LENGTH (tags); i++)
+ if (hb_ot_var_find_axis_info (face, tags[i], &axis_info))
+ {
+ tag = *var_tag = tags[i];
+ break;
+ }
+
+ /* If no suitable variation axis found, can't justify. Just shape and return. */
+ if (!tag)
+ {
+ *var_tag = HB_TAG_NONE;
+ *var_value = 0.0f;
+ if (hb_shape_full (font, buffer,
+ features, num_features,
+ shaper_list))
+ {
+ *advance = buffer_advance (buffer);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /* Copy buffer text as we need it so we can shape multiple times. */
+ unsigned text_len = buffer->len;
+ auto *text_info = (hb_glyph_info_t *) hb_malloc (text_len * sizeof (buffer->info[0]));
+ if (unlikely (text_len && !text_info))
+ return false;
+ hb_memcpy (text_info, buffer->info, text_len * sizeof (buffer->info[0]));
+ auto text = hb_array<const hb_glyph_info_t> (text_info, text_len);
+
+ /* If default advance was not provided to us, calculate it. */
+ if (!*advance)
+ {
+ hb_font_set_variation (font, tag, axis_info.default_value);
+ if (!hb_shape_full (font, buffer,
+ features, num_features,
+ shaper_list))
+ return false;
+ *advance = buffer_advance (buffer);
+ }
+
+ /* If default advance already matches target, nothing to do. Shape and return.
+ * Do this again, in case advance was just calculated.
+ */
+ if (min_target_advance <= *advance && *advance <= max_target_advance)
+ {
+ *var_tag = HB_TAG_NONE;
+ *var_value = 0.0f;
+ return true;
+ }
+
+ /* Prepare for running the solver. */
+ double a, b, ya, yb;
+ if (*advance < min_target_advance)
+ {
+ /* Need to expand. */
+ ya = (double) *advance;
+ a = (double) axis_info.default_value;
+ b = (double) axis_info.max_value;
+
+ /* Shape buffer for maximum expansion to use as other
+ * starting point for the solver. */
+ hb_font_set_variation (font, tag, (float) b);
+ reset_buffer (buffer, text);
+ if (!hb_shape_full (font, buffer,
+ features, num_features,
+ shaper_list))
+ return false;
+ yb = (double) buffer_advance (buffer);
+ /* If the maximum expansion is less than max target,
+ * there's nothing to solve for. Just return it. */
+ if (yb <= (double) max_target_advance)
+ {
+ *var_value = (float) b;
+ *advance = (float) yb;
+ return true;
+ }
+ }
+ else
+ {
+ /* Need to shrink. */
+ yb = (double) *advance;
+ a = (double) axis_info.min_value;
+ b = (double) axis_info.default_value;
+
+ /* Shape buffer for maximum shrinkate to use as other
+ * starting point for the solver. */
+ hb_font_set_variation (font, tag, (float) a);
+ reset_buffer (buffer, text);
+ if (!hb_shape_full (font, buffer,
+ features, num_features,
+ shaper_list))
+ return false;
+ ya = (double) buffer_advance (buffer);
+ /* If the maximum shrinkate is more than min target,
+ * there's nothing to solve for. Just return it. */
+ if (ya >= (double) min_target_advance)
+ {
+ *var_value = (float) a;
+ *advance = (float) ya;
+ return true;
+ }
+ }
+
+ /* Run the solver to find a var axis value that hits
+ * the desired width. */
+
+ double epsilon = (b - a) / (1<<14);
+ bool failed = false;
+
+ auto f = [&] (double x)
+ {
+ hb_font_set_variation (font, tag, (float) x);
+ reset_buffer (buffer, text);
+ if (unlikely (!hb_shape_full (font, buffer,
+ features, num_features,
+ shaper_list)))
+ {
+ failed = true;
+ return (double) min_target_advance;
+ }
+
+ double w = (double) buffer_advance (buffer);
+ DEBUG_MSG (JUSTIFY, nullptr, "Trying '%c%c%c%c' axis parameter %f. Advance %g. Target: min %g max %g",
+ HB_UNTAG (tag), x, w,
+ (double) min_target_advance, (double) max_target_advance);
+ return w;
+ };
+
+ double y = 0;
+ double itp = solve_itp (f,
+ a, b,
+ epsilon,
+ (double) min_target_advance, (double) max_target_advance,
+ ya, yb, y);
+
+ hb_free (text_info);
+
+ if (failed)
+ return false;
+
+ *var_value = (float) itp;
+ *advance = (float) y;
+
+ return true;
+}
+
+#endif
+
+
#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-shape.h b/src/3rdparty/harfbuzz-ng/src/hb-shape.h
index 922f8c011e..d4d4fdfd26 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-shape.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-shape.h
@@ -53,6 +53,18 @@ hb_shape_full (hb_font_t *font,
unsigned int num_features,
const char * const *shaper_list);
+HB_EXTERN hb_bool_t
+hb_shape_justify (hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features,
+ const char * const *shaper_list,
+ float min_target_advance,
+ float max_target_advance,
+ float *advance, /* IN/OUT */
+ hb_tag_t *var_tag, /* OUT */
+ float *var_value /* OUT */);
+
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 0d63933a76..f079caf4d3 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-shaper-list.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-shaper-list.hh
@@ -33,13 +33,18 @@
/* v--- Add new shapers in the right place here. */
+#ifdef HAVE_WASM
+/* Only picks up fonts that have a "Wasm" table. */
+HB_SHAPER_IMPLEMENT (wasm)
+#endif
+
#ifdef HAVE_GRAPHITE2
/* Only picks up fonts that have a "Silf" table. */
HB_SHAPER_IMPLEMENT (graphite2)
#endif
#ifndef HB_NO_OT_SHAPE
-HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */
+HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main shaper. */
#endif
#ifdef HAVE_UNISCRIBE
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-static.cc b/src/3rdparty/harfbuzz-ng/src/hb-static.cc
index 5f647c6ad9..c9bd0a61bf 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-static.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-static.cc
@@ -31,14 +31,17 @@
#include "hb-aat-layout-common.hh"
#include "hb-aat-layout-feat-table.hh"
+#include "hb-cff-interp-common.hh"
#include "hb-ot-layout-common.hh"
#include "hb-ot-cmap-table.hh"
#include "OT/Color/COLR/COLR.hh"
#include "hb-ot-glyf-table.hh"
#include "hb-ot-head-table.hh"
+#include "hb-ot-hmtx-table.hh"
#include "hb-ot-maxp-table.hh"
#ifndef HB_NO_VISIBILITY
+#include "hb-ot-name-language-static.hh"
uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {};
/*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {};
@@ -56,6 +59,8 @@ DEFINE_NULL_NAMESPACE_BYTES (AAT, Lookup) = {0xFF,0xFF};
/* hb_map_t */
const hb_codepoint_t minus_1 = -1;
+static const unsigned char static_endchar_str[] = {OpCode_endchar};
+const unsigned char *endchar_str = static_endchar_str;
/* hb_face_t */
@@ -108,4 +113,26 @@ hb_face_t::load_upem () const
}
+#ifndef HB_NO_VAR
+bool
+_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical,
+ int *lsb)
+{
+ return font->face->table.glyf->get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb);
+}
+
+unsigned
+_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
+{
+ return font->face->table.glyf->get_advance_with_var_unscaled (font, glyph, is_vertical);
+}
+#endif
+
+bool
+_glyf_get_leading_bearing_without_var_unscaled (hb_face_t *face, hb_codepoint_t gid, bool is_vertical, int *lsb)
+{
+ return face->table.glyf->get_leading_bearing_without_var_unscaled (gid, is_vertical, lsb);
+}
+
+
#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-style.cc b/src/3rdparty/harfbuzz-ng/src/hb-style.cc
index c7d7d713c2..bd5cb5c6be 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-style.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-style.cc
@@ -46,13 +46,13 @@
static inline float
_hb_angle_to_ratio (float a)
{
- return tanf (a * float (-M_PI / 180.));
+ return tanf (a * -HB_PI / 180.f);
}
static inline float
_hb_ratio_to_angle (float r)
{
- return atanf (r) * float (-180. / M_PI);
+ return atanf (r) * -180.f / HB_PI;
}
/**
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-accelerator.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-accelerator.hh
index e523c25820..9258383d28 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-accelerator.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-accelerator.hh
@@ -42,7 +42,9 @@ struct cff_subset_accelerator_t;
namespace OT {
struct SubtableUnicodesCache;
-};
+struct cff1_subset_accelerator_t;
+struct cff2_subset_accelerator_t;
+}
struct hb_subset_accelerator_t
{
@@ -51,15 +53,17 @@ struct hb_subset_accelerator_t
return &_hb_subset_accelerator_user_data_key;
}
- static hb_subset_accelerator_t* create(const hb_map_t& unicode_to_gid_,
- const hb_multimap_t gid_to_unicodes_,
+ static hb_subset_accelerator_t* create(hb_face_t *source,
+ const hb_map_t& unicode_to_gid_,
const hb_set_t& unicodes_,
bool has_seac_) {
hb_subset_accelerator_t* accel =
(hb_subset_accelerator_t*) hb_calloc (1, sizeof(hb_subset_accelerator_t));
- new (accel) hb_subset_accelerator_t (unicode_to_gid_,
- gid_to_unicodes_,
+ if (unlikely (!accel)) return accel;
+
+ new (accel) hb_subset_accelerator_t (source,
+ unicode_to_gid_,
unicodes_,
has_seac_);
@@ -77,36 +81,36 @@ struct hb_subset_accelerator_t
hb_free (accel);
}
- hb_subset_accelerator_t (const hb_map_t& unicode_to_gid_,
- const hb_multimap_t& gid_to_unicodes_,
+ hb_subset_accelerator_t (hb_face_t *source,
+ const hb_map_t& unicode_to_gid_,
const hb_set_t& unicodes_,
bool has_seac_) :
unicode_to_gid(unicode_to_gid_),
- gid_to_unicodes (gid_to_unicodes_),
unicodes(unicodes_),
cmap_cache(nullptr),
destroy_cmap_cache(nullptr),
has_seac(has_seac_),
- cff_accelerator(nullptr),
- destroy_cff_accelerator(nullptr) {}
-
- ~hb_subset_accelerator_t ()
+ source(hb_face_reference (source))
{
- if (cff_accelerator && destroy_cff_accelerator)
- destroy_cff_accelerator ((void*) cff_accelerator);
-
- if (cmap_cache && destroy_cmap_cache)
- destroy_cmap_cache ((void*) cmap_cache);
+ gid_to_unicodes.alloc (unicode_to_gid.get_population ());
+ for (const auto &_ : unicode_to_gid)
+ {
+ auto unicode = _.first;
+ auto gid = _.second;
+ gid_to_unicodes.add (gid, unicode);
+ }
}
+ HB_INTERNAL ~hb_subset_accelerator_t ();
+
// Generic
mutable hb_mutex_t sanitized_table_cache_lock;
mutable hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_blob_t>> sanitized_table_cache;
- const hb_map_t unicode_to_gid;
- const hb_multimap_t gid_to_unicodes;
- const hb_set_t unicodes;
+ hb_map_t unicode_to_gid;
+ hb_multimap_t gid_to_unicodes;
+ hb_set_t unicodes;
// cmap
const OT::SubtableUnicodesCache* cmap_cache;
@@ -114,8 +118,6 @@ struct hb_subset_accelerator_t
// CFF
bool has_seac;
- const CFF::cff_subset_accelerator_t* cff_accelerator;
- hb_destroy_func_t destroy_cff_accelerator;
// TODO(garretrieger): cumulative glyf checksum map
@@ -126,6 +128,13 @@ struct hb_subset_accelerator_t
unicodes.in_error () ||
sanitized_table_cache.in_error ();
}
+
+ hb_face_t *source;
+#ifndef HB_NO_SUBSET_CFF
+ // These have to be immediately after source:
+ mutable hb_face_lazy_loader_t<OT::cff1_subset_accelerator_t, 1> cff1_accel;
+ mutable hb_face_lazy_loader_t<OT::cff2_subset_accelerator_t, 2> cff2_accel;
+#endif
};
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.cc
index 6e1b6f713d..5e4ea5fe7c 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.cc
@@ -68,24 +68,35 @@ hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan,
/* use hb_set to determine the subset of font dicts */
hb_set_t set;
hb_codepoint_t prev_fd = CFF_UNDEF_CODE;
- for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++)
+ hb_pair_t<unsigned, hb_codepoint_t> last_range {0, 0};
+ auto it = hb_iter (plan->new_to_old_gid_list);
+ auto _ = *it;
+ for (hb_codepoint_t gid = 0; gid < subset_num_glyphs; gid++)
{
- hb_codepoint_t glyph;
- hb_codepoint_t fd;
- if (!plan->old_gid_for_new_gid (i, &glyph))
+ hb_codepoint_t old_glyph;
+ if (gid == _.first)
+ {
+ old_glyph = _.second;
+ _ = *++it;
+ }
+ else
{
/* fonttools retains FDSelect & font dicts for missing glyphs. do the same */
- glyph = i;
+ old_glyph = gid;
}
- fd = src.get_fd (glyph);
- set.add (fd);
+ if (old_glyph >= last_range.second)
+ last_range = src.get_fd_range (old_glyph);
+ unsigned fd = last_range.first;
if (fd != prev_fd)
{
+ set.add (fd);
num_ranges++;
prev_fd = fd;
- code_pair_t pair = { fd, i };
- fdselect_ranges.push (pair);
+ fdselect_ranges.push (code_pair_t { fd, gid });
+
+ if (gid == old_glyph)
+ gid = hb_min (_.first - 1, last_range.second - 1);
}
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh
index ff50b0e518..462e99cf8c 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff-common.hh
@@ -480,6 +480,7 @@ struct cff_subset_accelerator_t
const hb_vector_t<parsed_cs_str_vec_t>& parsed_local_subrs) {
cff_subset_accelerator_t* accel =
(cff_subset_accelerator_t*) hb_malloc (sizeof(cff_subset_accelerator_t));
+ if (unlikely (!accel)) return nullptr;
new (accel) cff_subset_accelerator_t (original_blob,
parsed_charstrings,
parsed_global_subrs,
@@ -510,15 +511,21 @@ struct cff_subset_accelerator_t
original_blob = hb_blob_reference (original_blob_);
}
- ~cff_subset_accelerator_t() {
+ ~cff_subset_accelerator_t()
+ {
hb_blob_destroy (original_blob);
- hb_map_destroy (glyph_to_sid_map.get_relaxed ());
+ auto *mapping = glyph_to_sid_map.get_relaxed ();
+ if (mapping)
+ {
+ mapping->~glyph_to_sid_map_t ();
+ hb_free (mapping);
+ }
}
parsed_cs_str_vec_t parsed_charstrings;
parsed_cs_str_vec_t parsed_global_subrs;
hb_vector_t<parsed_cs_str_vec_t> parsed_local_subrs;
- mutable hb_atomic_ptr_t<hb_map_t> glyph_to_sid_map = nullptr;
+ mutable hb_atomic_ptr_t<glyph_to_sid_map_t> glyph_to_sid_map;
private:
hb_blob_t* original_blob;
@@ -600,9 +607,8 @@ struct subr_remap_t : hb_inc_bimap_t
* no optimization based on usage counts. fonttools doesn't appear doing that either.
*/
- resize (closure->get_population ());
- hb_codepoint_t old_num = HB_SET_VALUE_INVALID;
- while (hb_set_next (closure, &old_num))
+ alloc (closure->get_population ());
+ for (auto old_num : *closure)
add (old_num);
if (get_population () < 1240)
@@ -672,8 +678,8 @@ struct subr_subsetter_t
{
unsigned fd_count = acc.fdCount;
const cff_subset_accelerator_t* cff_accelerator = nullptr;
- if (plan->accelerator && plan->accelerator->cff_accelerator) {
- cff_accelerator = plan->accelerator->cff_accelerator;
+ if (acc.cff_accelerator) {
+ cff_accelerator = acc.cff_accelerator;
fd_count = cff_accelerator->parsed_local_subrs.length;
}
@@ -709,14 +715,13 @@ struct subr_subsetter_t
}
/* phase 1 & 2 */
- for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
+ for (auto _ : plan->new_to_old_gid_list)
{
- hb_codepoint_t glyph;
- if (!plan->old_gid_for_new_gid (i, &glyph))
- continue;
+ hb_codepoint_t new_glyph = _.first;
+ hb_codepoint_t old_glyph = _.second;
- const hb_ubytes_t str = (*acc.charStrings)[glyph];
- unsigned int fd = acc.fdSelect->get_fd (glyph);
+ const hb_ubytes_t str = (*acc.charStrings)[old_glyph];
+ unsigned int fd = acc.fdSelect->get_fd (old_glyph);
if (unlikely (fd >= acc.fdCount))
return false;
@@ -725,9 +730,9 @@ struct subr_subsetter_t
// parsed string already exists in accelerator, copy it and move
// on.
if (cached_charstrings)
- cached_charstrings[i] = &cff_accelerator->parsed_charstrings[glyph];
+ cached_charstrings[new_glyph] = &cff_accelerator->parsed_charstrings[old_glyph];
else
- parsed_charstrings[i] = cff_accelerator->parsed_charstrings[glyph];
+ parsed_charstrings[new_glyph] = cff_accelerator->parsed_charstrings[old_glyph];
continue;
}
@@ -735,8 +740,8 @@ struct subr_subsetter_t
ENV env (str, acc, fd);
cs_interpreter_t<ENV, OPSET, subr_subset_param_t> interp (env);
- parsed_charstrings[i].alloc (str.length);
- subr_subset_param_t param (&parsed_charstrings[i],
+ parsed_charstrings[new_glyph].alloc (str.length);
+ subr_subset_param_t param (&parsed_charstrings[new_glyph],
&parsed_global_subrs_storage,
&parsed_local_subrs_storage[fd],
&closures.global_closure,
@@ -747,12 +752,12 @@ struct subr_subsetter_t
return false;
/* complete parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */
- SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[i]);
+ SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[new_glyph]);
/* mark hint ops and arguments for drop */
if ((plan->flags & HB_SUBSET_FLAGS_NO_HINTING) || plan->inprogress_accelerator)
{
- subr_subset_param_t param (&parsed_charstrings[i],
+ subr_subset_param_t param (&parsed_charstrings[new_glyph],
&parsed_global_subrs_storage,
&parsed_local_subrs_storage[fd],
&closures.global_closure,
@@ -760,21 +765,21 @@ struct subr_subsetter_t
plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
drop_hints_param_t drop;
- if (drop_hints_in_str (parsed_charstrings[i], param, drop))
+ if (drop_hints_in_str (parsed_charstrings[new_glyph], param, drop))
{
- parsed_charstrings[i].set_hint_dropped ();
+ parsed_charstrings[new_glyph].set_hint_dropped ();
if (drop.vsindex_dropped)
- parsed_charstrings[i].set_vsindex_dropped ();
+ parsed_charstrings[new_glyph].set_vsindex_dropped ();
}
}
- /* Doing this here one by one instead of compacting all at the en
+ /* Doing this here one by one instead of compacting all at the end
* has massive peak-memory saving.
*
* The compacting both saves memory and makes further operations
* faster.
*/
- parsed_charstrings[i].compact ();
+ parsed_charstrings[new_glyph].compact ();
}
/* Since parsed strings were loaded from accelerator, we still need
@@ -797,23 +802,40 @@ struct subr_subsetter_t
bool encode_charstrings (str_buff_vec_t &buffArray, bool encode_prefix = true) const
{
- if (unlikely (!buffArray.resize_exact (plan->num_output_glyphs ())))
+ unsigned num_glyphs = plan->num_output_glyphs ();
+ if (unlikely (!buffArray.resize_exact (num_glyphs)))
return false;
- for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
+ hb_codepoint_t last = 0;
+ for (auto _ : plan->new_to_old_gid_list)
{
- hb_codepoint_t glyph;
- if (!plan->old_gid_for_new_gid (i, &glyph))
- {
- /* add an endchar only charstring for a missing glyph if CFF1 */
- if (endchar_op != OpCode_Invalid) buffArray.arrayZ[i].push (endchar_op);
- continue;
- }
- unsigned int fd = acc.fdSelect->get_fd (glyph);
+ hb_codepoint_t gid = _.first;
+ hb_codepoint_t old_glyph = _.second;
+
+ if (endchar_op != OpCode_Invalid)
+ for (; last < gid; last++)
+ {
+ // Hack to point vector to static string.
+ auto &b = buffArray.arrayZ[last];
+ b.length = 1;
+ b.arrayZ = const_cast<unsigned char *>(endchar_str);
+ }
+
+ last++; // Skip over gid
+ unsigned int fd = acc.fdSelect->get_fd (old_glyph);
if (unlikely (fd >= acc.fdCount))
return false;
- if (unlikely (!encode_str (get_parsed_charstring (i), fd, buffArray.arrayZ[i], encode_prefix)))
+ if (unlikely (!encode_str (get_parsed_charstring (gid), fd, buffArray.arrayZ[gid], encode_prefix)))
return false;
}
+ if (endchar_op != OpCode_Invalid)
+ for (; last < num_glyphs; last++)
+ {
+ // Hack to point vector to static string.
+ auto &b = buffArray.arrayZ[last];
+ b.length = 1;
+ b.arrayZ = const_cast<unsigned char *>(endchar_str);
+ }
+
return true;
}
@@ -980,24 +1002,23 @@ struct subr_subsetter_t
const hb_vector_t<parsed_cs_str_vec_t>& local_subrs)
{
closures.reset ();
- for (unsigned int i = 0; i < plan->num_output_glyphs (); i++)
+ for (auto _ : plan->new_to_old_gid_list)
{
- hb_codepoint_t glyph;
- if (!plan->old_gid_for_new_gid (i, &glyph))
- continue;
- unsigned int fd = acc.fdSelect->get_fd (glyph);
+ hb_codepoint_t new_glyph = _.first;
+ hb_codepoint_t old_glyph = _.second;
+ unsigned int fd = acc.fdSelect->get_fd (old_glyph);
if (unlikely (fd >= acc.fdCount))
return false;
// Note: const cast is safe here because the collect_subr_refs_in_str only performs a
// closure and does not modify any of the charstrings.
- subr_subset_param_t param (const_cast<parsed_cs_str_t*> (&get_parsed_charstring (i)),
+ subr_subset_param_t param (const_cast<parsed_cs_str_t*> (&get_parsed_charstring (new_glyph)),
const_cast<parsed_cs_str_vec_t*> (&global_subrs),
const_cast<parsed_cs_str_vec_t*> (&local_subrs[fd]),
&closures.global_closure,
&closures.local_closures[fd],
plan->flags & HB_SUBSET_FLAGS_NO_HINTING);
- collect_subr_refs_in_str (get_parsed_charstring (i), param);
+ collect_subr_refs_in_str (get_parsed_charstring (new_glyph), param);
}
return true;
@@ -1105,14 +1126,11 @@ struct subr_subsetter_t
compact_parsed_subrs ();
- plan->inprogress_accelerator->cff_accelerator =
+ acc.cff_accelerator =
cff_subset_accelerator_t::create(acc.blob,
parsed_charstrings,
parsed_global_subrs_storage,
parsed_local_subrs_storage);
- plan->inprogress_accelerator->destroy_cff_accelerator =
- cff_subset_accelerator_t::destroy;
-
}
const parsed_cs_str_t& get_parsed_charstring (unsigned i) const
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc
index 1d7ed6444a..e9dd5d6427 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.cc
@@ -32,36 +32,59 @@
#include "hb-ot-cff1-table.hh"
#include "hb-set.h"
#include "hb-bimap.hh"
-#include "hb-subset-cff1.hh"
#include "hb-subset-plan.hh"
#include "hb-subset-cff-common.hh"
#include "hb-cff1-interp-cs.hh"
using namespace CFF;
-struct remap_sid_t : hb_inc_bimap_t
+struct remap_sid_t
{
+ unsigned get_population () const { return vector.length; }
+
+ void alloc (unsigned size)
+ {
+ map.alloc (size);
+ vector.alloc (size, true);
+ }
+
+ bool in_error () const
+ { return map.in_error () || vector.in_error (); }
+
unsigned int add (unsigned int sid)
{
- if ((sid != CFF_UNDEF_SID) && !is_std_std (sid))
- return offset_sid (hb_inc_bimap_t::add (unoffset_sid (sid)));
- else
+ if (is_std_str (sid) || (sid == CFF_UNDEF_SID))
return sid;
+
+ sid = unoffset_sid (sid);
+ unsigned v = next;
+ if (map.set (sid, v, false))
+ {
+ vector.push (sid);
+ next++;
+ }
+ else
+ v = map.get (sid); // already exists
+ return offset_sid (v);
}
unsigned int operator[] (unsigned int sid) const
{
- if (is_std_std (sid) || (sid == CFF_UNDEF_SID))
+ if (is_std_str (sid) || (sid == CFF_UNDEF_SID))
return sid;
- else
- return offset_sid (get (unoffset_sid (sid)));
+
+ return offset_sid (map.get (unoffset_sid (sid)));
}
static const unsigned int num_std_strings = 391;
- static bool is_std_std (unsigned int sid) { return sid < num_std_strings; }
+ static bool is_std_str (unsigned int sid) { return sid < num_std_strings; }
static unsigned int offset_sid (unsigned int sid) { return sid + num_std_strings; }
static unsigned int unoffset_sid (unsigned int sid) { return sid - num_std_strings; }
+ unsigned next = 0;
+
+ hb_map_t map;
+ hb_vector_t<unsigned> vector;
};
struct cff1_sub_table_info_t : cff_sub_table_info_t
@@ -271,16 +294,17 @@ struct range_list_t : hb_vector_t<code_pair_t>
/* replace the first glyph ID in the "glyph" field each range with a nLeft value */
bool complete (unsigned int last_glyph)
{
- bool two_byte = false;
+ hb_codepoint_t all_glyphs = 0;
unsigned count = this->length;
for (unsigned int i = count; i; i--)
{
code_pair_t &pair = arrayZ[i - 1];
unsigned int nLeft = last_glyph - pair.glyph - 1;
- two_byte |= nLeft >= 0x100;
+ all_glyphs |= nLeft;
last_glyph = pair.glyph;
pair.glyph = nLeft;
}
+ bool two_byte = all_glyphs >= 0x100;
return two_byte;
}
};
@@ -391,8 +415,10 @@ struct cff1_subr_subsetter_t : subr_subsetter_t<cff1_subr_subsetter_t, CFF1Subrs
}
};
-struct cff_subset_plan {
- cff_subset_plan ()
+namespace OT {
+struct cff1_subset_plan
+{
+ cff1_subset_plan ()
{
for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++)
topDictModSIDs[i] = CFF_UNDEF_SID;
@@ -402,7 +428,7 @@ struct cff_subset_plan {
{
const Encoding *encoding = acc.encoding;
unsigned int size0, size1;
- hb_codepoint_t code, last_code = CFF_UNDEF_CODE;
+ unsigned code, last_code = CFF_UNDEF_CODE - 1;
hb_vector_t<hb_codepoint_t> supp_codes;
if (unlikely (!subset_enc_code_ranges.resize (0)))
@@ -413,39 +439,42 @@ struct cff_subset_plan {
supp_codes.init ();
+ code_pair_t glyph_to_sid_cache {0, HB_CODEPOINT_INVALID};
subset_enc_num_codes = plan->num_output_glyphs () - 1;
unsigned int glyph;
- for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++)
+ auto it = hb_iter (plan->new_to_old_gid_list);
+ if (it->first == 0) it++;
+ auto _ = *it;
+ for (glyph = 1; glyph < num_glyphs; glyph++)
{
- hb_codepoint_t old_glyph;
- if (!plan->old_gid_for_new_gid (glyph, &old_glyph))
+ hb_codepoint_t old_glyph;
+ if (glyph == _.first)
+ {
+ old_glyph = _.second;
+ _ = *++it;
+ }
+ else
{
- /* Retain the code for the old missing glyph ID */
+ /* Retain the SID for the old missing glyph ID */
old_glyph = glyph;
}
- code = acc.glyph_to_code (old_glyph);
+ code = acc.glyph_to_code (old_glyph, &glyph_to_sid_cache);
if (code == CFF_UNDEF_CODE)
{
subset_enc_num_codes = glyph - 1;
break;
}
- if ((last_code == CFF_UNDEF_CODE) || (code != last_code + 1))
- {
- code_pair_t pair = { code, glyph };
- subset_enc_code_ranges.push (pair);
- }
+ if (code != last_code + 1)
+ subset_enc_code_ranges.push (code_pair_t {code, glyph});
last_code = code;
if (encoding != &Null (Encoding))
{
- hb_codepoint_t sid = acc.glyph_to_sid (old_glyph);
+ hb_codepoint_t sid = acc.glyph_to_sid (old_glyph, &glyph_to_sid_cache);
encoding->get_supplement_codes (sid, supp_codes);
for (unsigned int i = 0; i < supp_codes.length; i++)
- {
- code_pair_t pair = { supp_codes[i], sid };
- subset_enc_supp_codes.push (pair);
- }
+ subset_enc_supp_codes.push (code_pair_t {supp_codes[i], sid});
}
}
supp_codes.fini ();
@@ -462,65 +491,93 @@ struct cff_subset_plan {
subset_enc_format = 1;
}
- void plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
+ bool plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
{
unsigned int size0, size_ranges;
- hb_codepoint_t sid, last_sid = CFF_UNDEF_CODE;
+ unsigned last_sid = CFF_UNDEF_CODE - 1;
if (unlikely (!subset_charset_ranges.resize (0)))
{
plan->check_success (false);
- return;
+ return false;
}
- hb_map_t *glyph_to_sid_map = (plan->accelerator && plan->accelerator->cff_accelerator) ?
- plan->accelerator->cff_accelerator->glyph_to_sid_map :
- nullptr;
+ code_pair_t glyph_to_sid_cache {0, HB_CODEPOINT_INVALID};
+
+ unsigned num_glyphs = plan->num_output_glyphs ();
+
+ if (unlikely (!subset_charset_ranges.alloc (hb_min (num_glyphs,
+ acc.num_charset_entries))))
+ {
+ plan->check_success (false);
+ return false;
+ }
+
+ glyph_to_sid_map_t *glyph_to_sid_map = acc.cff_accelerator ?
+ acc.cff_accelerator->glyph_to_sid_map.get_acquire () :
+ nullptr;
bool created_map = false;
- if (!glyph_to_sid_map &&
- ((plan->accelerator && plan->accelerator->cff_accelerator) ||
- plan->num_output_glyphs () > plan->source->get_num_glyphs () / 8.))
+ if (!glyph_to_sid_map && acc.cff_accelerator)
{
created_map = true;
glyph_to_sid_map = acc.create_glyph_to_sid_map ();
}
- unsigned int glyph;
- for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++)
+ auto it = hb_iter (plan->new_to_old_gid_list);
+ if (it->first == 0) it++;
+ auto _ = *it;
+ bool not_is_cid = !acc.is_CID ();
+ bool skip = !not_is_cid && glyph_to_sid_map;
+ if (not_is_cid)
+ sidmap.alloc (num_glyphs);
+ for (hb_codepoint_t glyph = 1; glyph < num_glyphs; glyph++)
{
- hb_codepoint_t old_glyph;
- if (!plan->old_gid_for_new_gid (glyph, &old_glyph))
+ hb_codepoint_t old_glyph;
+ if (glyph == _.first)
+ {
+ old_glyph = _.second;
+ _ = *++it;
+ }
+ else
{
/* Retain the SID for the old missing glyph ID */
old_glyph = glyph;
}
- sid = glyph_to_sid_map ? glyph_to_sid_map->get (old_glyph) : acc.glyph_to_sid (old_glyph);
+ unsigned sid = glyph_to_sid_map ?
+ glyph_to_sid_map->arrayZ[old_glyph].code :
+ acc.glyph_to_sid (old_glyph, &glyph_to_sid_cache);
- if (!acc.is_CID ())
+ if (not_is_cid)
sid = sidmap.add (sid);
- if ((last_sid == CFF_UNDEF_CODE) || (sid != last_sid + 1))
+ if (sid != last_sid + 1)
+ subset_charset_ranges.push (code_pair_t {sid, glyph});
+
+ if (glyph == old_glyph && skip)
{
- code_pair_t pair = { sid, glyph };
- subset_charset_ranges.push (pair);
+ glyph = hb_min (_.first - 1, glyph_to_sid_map->arrayZ[old_glyph].glyph);
+ sid += glyph - old_glyph;
}
last_sid = sid;
}
if (created_map)
{
- if (!(plan->accelerator && plan->accelerator->cff_accelerator) ||
- !plan->accelerator->cff_accelerator->glyph_to_sid_map.cmpexch (nullptr, glyph_to_sid_map))
- hb_map_destroy (glyph_to_sid_map);
+ if ((!plan->accelerator && acc.cff_accelerator) ||
+ !acc.cff_accelerator->glyph_to_sid_map.cmpexch (nullptr, glyph_to_sid_map))
+ {
+ glyph_to_sid_map->~glyph_to_sid_map_t ();
+ hb_free (glyph_to_sid_map);
+ }
}
- bool two_byte = subset_charset_ranges.complete (glyph);
+ bool two_byte = subset_charset_ranges.complete (num_glyphs);
- size0 = Charset0::min_size + HBUINT16::static_size * (plan->num_output_glyphs () - 1);
+ size0 = Charset0::get_size (plan->num_output_glyphs ());
if (!two_byte)
- size_ranges = Charset1::min_size + Charset1_Range::static_size * subset_charset_ranges.length;
+ size_ranges = Charset1::get_size_for_ranges (subset_charset_ranges.length);
else
- size_ranges = Charset2::min_size + Charset2_Range::static_size * subset_charset_ranges.length;
+ size_ranges = Charset2::get_size_for_ranges (subset_charset_ranges.length);
if (size0 < size_ranges)
subset_charset_format = 0;
@@ -528,19 +585,18 @@ struct cff_subset_plan {
subset_charset_format = 1;
else
subset_charset_format = 2;
+
+ return true;
}
bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc)
{
- sidmap.reset ();
-
for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++)
{
unsigned int sid = acc.topDict.nameSIDs[i];
if (sid != CFF_UNDEF_SID)
{
- (void)sidmap.add (sid);
- topDictModSIDs[i] = sidmap[sid];
+ topDictModSIDs[i] = sidmap.add (sid);
}
}
@@ -564,19 +620,24 @@ struct cff_subset_plan {
drop_hints = plan->flags & HB_SUBSET_FLAGS_NO_HINTING;
desubroutinize = plan->flags & HB_SUBSET_FLAGS_DESUBROUTINIZE;
- /* check whether the subset renumbers any glyph IDs */
- gid_renum = false;
- for (hb_codepoint_t new_glyph = 0; new_glyph < plan->num_output_glyphs (); new_glyph++)
- {
- if (!plan->old_gid_for_new_gid(new_glyph, &old_glyph))
- continue;
- if (new_glyph != old_glyph) {
- gid_renum = true;
- break;
+ #ifdef HB_EXPERIMENTAL_API
+ min_charstrings_off_size = (plan->flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS) ? 4 : 0;
+ #else
+ min_charstrings_off_size = 0;
+ #endif
+
+ subset_charset = !acc.is_predef_charset ();
+ if (!subset_charset)
+ /* check whether the subset renumbers any glyph IDs */
+ for (const auto &_ : plan->new_to_old_gid_list)
+ {
+ if (_.first != _.second)
+ {
+ subset_charset = true;
+ break;
+ }
}
- }
- subset_charset = gid_renum || !acc.is_predef_charset ();
subset_encoding = !acc.is_CID() && !acc.is_predef_encoding ();
/* top dict INDEX */
@@ -618,7 +679,8 @@ struct cff_subset_plan {
if (unlikely (sidmap.get_population () > 0x8000)) /* assumption: a dict won't reference that many strings */
return false;
- if (subset_charset) plan_subset_charset (acc, plan);
+ if (subset_charset && !plan_subset_charset (acc, plan))
+ return false;
topdict_mod.reassignSIDs (sidmap);
}
@@ -682,8 +744,9 @@ struct cff_subset_plan {
;
}
- return ((subset_charstrings.length == plan->num_output_glyphs ())
- && (fontdicts_mod.length == subset_fdcount));
+ return !plan->in_error () &&
+ (subset_charstrings.length == plan->num_output_glyphs ()) &&
+ (fontdicts_mod.length == subset_fdcount);
}
cff1_top_dict_values_mod_t topdict_mod;
@@ -721,25 +784,53 @@ struct cff_subset_plan {
unsigned int topDictModSIDs[name_dict_values_t::ValCount];
bool desubroutinize = false;
+
+ unsigned min_charstrings_off_size = 0;
};
+} // namespace OT
-static bool _serialize_cff1 (hb_serialize_context_t *c,
- cff_subset_plan &plan,
- const OT::cff1::accelerator_subset_t &acc,
- unsigned int num_glyphs)
+static bool _serialize_cff1_charstrings (hb_serialize_context_t *c,
+ struct OT::cff1_subset_plan &plan,
+ const OT::cff1::accelerator_subset_t &acc)
{
+ c->push<CFF1CharStrings> ();
+
+ unsigned data_size = 0;
+ unsigned total_size = CFF1CharStrings::total_size (plan.subset_charstrings, &data_size, plan.min_charstrings_off_size);
+ if (unlikely (!c->start_zerocopy (total_size)))
+ return false;
+
+ auto *cs = c->start_embed<CFF1CharStrings> ();
+ if (unlikely (!cs->serialize (c, plan.subset_charstrings, &data_size, plan.min_charstrings_off_size))) {
+ c->pop_discard ();
+ return false;
+ }
+
+ plan.info.char_strings_link = c->pop_pack (false);
+ return true;
+}
+
+bool
+OT::cff1::accelerator_subset_t::serialize (hb_serialize_context_t *c,
+ struct OT::cff1_subset_plan &plan) const
+{
+ /* push charstrings onto the object stack first which will ensure it packs as the last
+ object in the table. Keeping the chastrings last satisfies the requirements for patching
+ via IFTB. If this ordering needs to be changed in the future, charstrings should be left
+ at the end whenever HB_SUBSET_FLAGS_ITFB_REQUIREMENTS is enabled. */
+ if (!_serialize_cff1_charstrings(c, plan, *this))
+ return false;
+
/* private dicts & local subrs */
- for (int i = (int)acc.privateDicts.length; --i >= 0 ;)
+ for (int i = (int) privateDicts.length; --i >= 0 ;)
{
if (plan.fdmap.has (i))
{
objidx_t subrs_link = 0;
if (plan.subset_localsubrs[i].length > 0)
{
- CFF1Subrs *dest = c->start_embed <CFF1Subrs> ();
- if (unlikely (!dest)) return false;
- c->push ();
- if (likely (dest && dest->serialize (c, plan.subset_localsubrs[i])))
+ auto *dest = c->push <CFF1Subrs> ();
+ if (likely (dest->serialize (c, plan.subset_localsubrs[i])))
subrs_link = c->pop_pack ();
else
{
@@ -748,12 +839,10 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
}
}
- PrivateDict *pd = c->start_embed<PrivateDict> ();
- if (unlikely (!pd)) return false;
- c->push ();
+ auto *pd = c->push<PrivateDict> ();
cff1_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints);
/* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
- if (likely (pd->serialize (c, acc.privateDicts[i], privSzr, subrs_link)))
+ if (likely (pd->serialize (c, privateDicts[i], privSzr, subrs_link)))
{
unsigned fd = plan.fdmap[i];
plan.fontdicts_mod[fd].privateDictInfo.size = c->length ();
@@ -767,35 +856,13 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
}
}
- if (!acc.is_CID ())
+ if (!is_CID ())
plan.info.privateDictInfo = plan.fontdicts_mod[0].privateDictInfo;
- /* CharStrings */
- {
- c->push<CFF1CharStrings> ();
-
- unsigned total_size = CFF1CharStrings::total_size (plan.subset_charstrings);
- if (unlikely (!c->start_zerocopy (total_size)))
- return false;
-
- CFF1CharStrings *cs = c->start_embed<CFF1CharStrings> ();
- if (unlikely (!cs)) return false;
-
- if (likely (cs->serialize (c, plan.subset_charstrings)))
- plan.info.char_strings_link = c->pop_pack (false);
- else
- {
- c->pop_discard ();
- return false;
- }
- }
-
/* FDArray (FD Index) */
- if (acc.fdArray != &Null (CFF1FDArray))
+ if (fdArray != &Null (CFF1FDArray))
{
- CFF1FDArray *fda = c->start_embed<CFF1FDArray> ();
- if (unlikely (!fda)) return false;
- c->push ();
+ auto *fda = c->push<CFF1FDArray> ();
cff1_font_dict_op_serializer_t fontSzr;
auto it = + hb_zip (+ hb_iter (plan.fontdicts_mod), + hb_iter (plan.fontdicts_mod));
if (likely (fda->serialize (c, it, fontSzr)))
@@ -808,10 +875,10 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
}
/* FDSelect */
- if (acc.fdSelect != &Null (CFF1FDSelect))
+ if (fdSelect != &Null (CFF1FDSelect))
{
c->push ();
- if (likely (hb_serialize_cff_fdselect (c, num_glyphs, *acc.fdSelect, acc.fdCount,
+ if (likely (hb_serialize_cff_fdselect (c, plan.num_glyphs, *fdSelect, fdCount,
plan.subset_fdselect_format, plan.info.fd_select.size,
plan.subset_fdselect_ranges)))
plan.info.fd_select.link = c->pop_pack ();
@@ -825,9 +892,7 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
/* Charset */
if (plan.subset_charset)
{
- Charset *dest = c->start_embed<Charset> ();
- if (unlikely (!dest)) return false;
- c->push ();
+ auto *dest = c->push<Charset> ();
if (likely (dest->serialize (c,
plan.subset_charset_format,
plan.num_glyphs,
@@ -843,9 +908,7 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
/* Encoding */
if (plan.subset_encoding)
{
- Encoding *dest = c->start_embed<Encoding> ();
- if (unlikely (!dest)) return false;
- c->push ();
+ auto *dest = c->push<Encoding> ();
if (likely (dest->serialize (c,
plan.subset_enc_format,
plan.subset_enc_num_codes,
@@ -861,9 +924,7 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
/* global subrs */
{
- c->push ();
- CFF1Subrs *dest = c->start_embed <CFF1Subrs> ();
- if (unlikely (!dest)) return false;
+ auto *dest = c->push <CFF1Subrs> ();
if (likely (dest->serialize (c, plan.subset_globalsubrs)))
c->pop_pack (false);
else
@@ -875,10 +936,9 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
/* String INDEX */
{
- CFF1StringIndex *dest = c->start_embed<CFF1StringIndex> ();
- if (unlikely (!dest)) return false;
- c->push ();
- if (likely (dest->serialize (c, *acc.stringIndex, plan.sidmap)))
+ auto *dest = c->push<CFF1StringIndex> ();
+ if (likely (!plan.sidmap.in_error () &&
+ dest->serialize (c, *stringIndex, plan.sidmap.vector)))
c->pop_pack ();
else
{
@@ -898,14 +958,12 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
cff->offSize = 4; /* unused? */
/* name INDEX */
- if (unlikely (!(*acc.nameIndex).copy (c))) return false;
+ if (unlikely (!c->embed (*nameIndex))) return false;
/* top dict INDEX */
{
/* serialize singleton TopDict */
- TopDict *top = c->start_embed<TopDict> ();
- if (!top) return false;
- c->push ();
+ auto *top = c->push<TopDict> ();
cff1_top_dict_op_serializer_t topSzr;
unsigned top_size = 0;
top_dict_modifiers_t modifier (plan.info, plan.topDictModSIDs);
@@ -920,36 +978,23 @@ static bool _serialize_cff1 (hb_serialize_context_t *c,
return false;
}
/* serialize INDEX header for above */
- CFF1Index *dest = c->start_embed<CFF1Index> ();
- if (!dest) return false;
- return dest->serialize_header (c, hb_iter (hb_array_t<unsigned> (&top_size, 1)));
+ auto *dest = c->start_embed<CFF1Index> ();
+ return dest->serialize_header (c, hb_iter (&top_size, 1), top_size);
}
}
-static bool
-_hb_subset_cff1 (const OT::cff1::accelerator_subset_t &acc,
- hb_subset_context_t *c)
+bool
+OT::cff1::accelerator_subset_t::subset (hb_subset_context_t *c) const
{
- cff_subset_plan cff_plan;
+ cff1_subset_plan cff_plan;
- if (unlikely (!cff_plan.create (acc, c->plan)))
+ if (unlikely (!cff_plan.create (*this, c->plan)))
{
DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan.");
return false;
}
- return _serialize_cff1 (c->serializer, cff_plan, acc, c->plan->num_output_glyphs ());
-}
-
-bool
-hb_subset_cff1 (hb_subset_context_t *c)
-{
- OT::cff1::accelerator_subset_t acc;
- acc.init (c->plan->source);
- bool result = likely (acc.is_valid ()) && _hb_subset_cff1 (acc, c);
- acc.fini ();
-
- return result;
+ return serialize (c->serializer, cff_plan);
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc
index 8ab4620194..eb5cb0c625 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.cc
@@ -31,7 +31,6 @@
#include "hb-open-type.hh"
#include "hb-ot-cff2-table.hh"
#include "hb-set.h"
-#include "hb-subset-cff2.hh"
#include "hb-subset-plan.hh"
#include "hb-subset-cff-common.hh"
#include "hb-cff2-interp-cs.hh"
@@ -249,7 +248,7 @@ struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs
struct cff2_private_blend_encoder_param_t
{
cff2_private_blend_encoder_param_t (hb_serialize_context_t *c,
- const CFF2VariationStore *varStore,
+ const CFF2ItemVariationStore *varStore,
hb_array_t<int> normalized_coords) :
c (c), varStore (varStore), normalized_coords (normalized_coords) {}
@@ -285,7 +284,7 @@ struct cff2_private_blend_encoder_param_t
unsigned ivs = 0;
unsigned region_count = 0;
hb_vector_t<float> scalars;
- const CFF2VariationStore *varStore = nullptr;
+ const CFF2ItemVariationStore *varStore = nullptr;
hb_array_t<int> normalized_coords;
};
@@ -379,7 +378,7 @@ struct cff2_private_dict_blend_opset_t : dict_opset_t
struct cff2_private_dict_op_serializer_t : op_serializer_t
{
cff2_private_dict_op_serializer_t (bool desubroutinize_, bool drop_hints_, bool pinned_,
- const CFF::CFF2VariationStore* varStore_,
+ const CFF::CFF2ItemVariationStore* varStore_,
hb_array_t<int> normalized_coords_)
: desubroutinize (desubroutinize_), drop_hints (drop_hints_), pinned (pinned_),
varStore (varStore_), normalized_coords (normalized_coords_) {}
@@ -417,16 +416,22 @@ struct cff2_private_dict_op_serializer_t : op_serializer_t
const bool desubroutinize;
const bool drop_hints;
const bool pinned;
- const CFF::CFF2VariationStore* varStore;
+ const CFF::CFF2ItemVariationStore* varStore;
hb_array_t<int> normalized_coords;
};
+namespace OT {
struct cff2_subset_plan
{
bool create (const OT::cff2::accelerator_subset_t &acc,
hb_subset_plan_t *plan)
{
+ /* make sure notdef is first */
+ hb_codepoint_t old_glyph;
+ if (!plan->old_gid_for_new_gid (0, &old_glyph) || (old_glyph != 0)) return false;
+
+ num_glyphs = plan->num_output_glyphs ();
orig_fdcount = acc.fdArray->count;
drop_hints = plan->flags & HB_SUBSET_FLAGS_NO_HINTING;
@@ -434,6 +439,12 @@ struct cff2_subset_plan
desubroutinize = plan->flags & HB_SUBSET_FLAGS_DESUBROUTINIZE ||
pinned; // For instancing we need this path
+ #ifdef HB_EXPERIMENTAL_API
+ min_charstrings_off_size = (plan->flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS) ? 4 : 0;
+ #else
+ min_charstrings_off_size = 0;
+ #endif
+
if (desubroutinize)
{
/* Flatten global & local subrs */
@@ -489,6 +500,7 @@ struct cff2_subset_plan
cff2_sub_table_info_t info;
+ unsigned int num_glyphs;
unsigned int orig_fdcount = 0;
unsigned int subset_fdcount = 1;
unsigned int subset_fdselect_size = 0;
@@ -504,19 +516,50 @@ struct cff2_subset_plan
bool drop_hints = false;
bool desubroutinize = false;
+
+ unsigned min_charstrings_off_size = 0;
};
+} // namespace OT
-static bool _serialize_cff2 (hb_serialize_context_t *c,
+static bool _serialize_cff2_charstrings (hb_serialize_context_t *c,
cff2_subset_plan &plan,
- const OT::cff2::accelerator_subset_t &acc,
- unsigned int num_glyphs,
- hb_array_t<int> normalized_coords)
+ const OT::cff2::accelerator_subset_t &acc)
+{
+ c->push ();
+
+ unsigned data_size = 0;
+ unsigned total_size = CFF2CharStrings::total_size (plan.subset_charstrings, &data_size, plan.min_charstrings_off_size);
+ if (unlikely (!c->start_zerocopy (total_size)))
+ return false;
+
+ auto *cs = c->start_embed<CFF2CharStrings> ();
+ if (unlikely (!cs->serialize (c, plan.subset_charstrings, &data_size, plan.min_charstrings_off_size)))
+ {
+ c->pop_discard ();
+ return false;
+ }
+
+ plan.info.char_strings_link = c->pop_pack (false);
+ return true;
+}
+
+bool
+OT::cff2::accelerator_subset_t::serialize (hb_serialize_context_t *c,
+ struct cff2_subset_plan &plan,
+ hb_array_t<int> normalized_coords) const
{
+ /* push charstrings onto the object stack first which will ensure it packs as the last
+ object in the table. Keeping the chastrings last satisfies the requirements for patching
+ via IFTB. If this ordering needs to be changed in the future, charstrings should be left
+ at the end whenever HB_SUBSET_FLAGS_ITFB_REQUIREMENTS is enabled. */
+ if (!_serialize_cff2_charstrings(c, plan, *this))
+ return false;
+
/* private dicts & local subrs */
hb_vector_t<table_info_t> private_dict_infos;
if (unlikely (!private_dict_infos.resize (plan.subset_fdcount))) return false;
- for (int i = (int)acc.privateDicts.length; --i >= 0 ;)
+ for (int i = (int)privateDicts.length; --i >= 0 ;)
{
if (plan.fdmap.has (i))
{
@@ -524,9 +567,7 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
if (plan.subset_localsubrs[i].length > 0)
{
- CFF2Subrs *dest = c->start_embed <CFF2Subrs> ();
- if (unlikely (!dest)) return false;
- c->push ();
+ auto *dest = c->push <CFF2Subrs> ();
if (likely (dest->serialize (c, plan.subset_localsubrs[i])))
subrs_link = c->pop_pack (false);
else
@@ -535,12 +576,10 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
return false;
}
}
- PrivateDict *pd = c->start_embed<PrivateDict> ();
- if (unlikely (!pd)) return false;
- c->push ();
+ auto *pd = c->push<PrivateDict> ();
cff2_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints, plan.pinned,
- acc.varStore, normalized_coords);
- if (likely (pd->serialize (c, acc.privateDicts[i], privSzr, subrs_link)))
+ varStore, normalized_coords);
+ if (likely (pd->serialize (c, privateDicts[i], privSzr, subrs_link)))
{
unsigned fd = plan.fdmap[i];
private_dict_infos[fd].size = c->length ();
@@ -554,31 +593,11 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
}
}
- /* CharStrings */
- {
- c->push ();
-
- unsigned total_size = CFF2CharStrings::total_size (plan.subset_charstrings);
- if (unlikely (!c->start_zerocopy (total_size)))
- return false;
-
- CFF2CharStrings *cs = c->start_embed<CFF2CharStrings> ();
- if (unlikely (!cs)) return false;
-
- if (likely (cs->serialize (c, plan.subset_charstrings)))
- plan.info.char_strings_link = c->pop_pack (false);
- else
- {
- c->pop_discard ();
- return false;
- }
- }
-
/* FDSelect */
- if (acc.fdSelect != &Null (CFF2FDSelect))
+ if (fdSelect != &Null (CFF2FDSelect))
{
c->push ();
- if (likely (hb_serialize_cff_fdselect (c, num_glyphs, *(const FDSelect *)acc.fdSelect,
+ if (likely (hb_serialize_cff_fdselect (c, plan.num_glyphs, *(const FDSelect *)fdSelect,
plan.orig_fdcount,
plan.subset_fdselect_format, plan.subset_fdselect_size,
plan.subset_fdselect_ranges)))
@@ -592,27 +611,32 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
/* FDArray (FD Index) */
{
- c->push ();
- CFF2FDArray *fda = c->start_embed<CFF2FDArray> ();
- if (unlikely (!fda)) return false;
+ auto *fda = c->push<CFF2FDArray> ();
cff_font_dict_op_serializer_t fontSzr;
auto it =
- + hb_zip (+ hb_iter (acc.fontDicts)
+ + hb_zip (+ hb_iter (fontDicts)
| hb_filter ([&] (const cff2_font_dict_values_t &_)
- { return plan.fdmap.has (&_ - &acc.fontDicts[0]); }),
+ { return plan.fdmap.has (&_ - &fontDicts[0]); }),
hb_iter (private_dict_infos))
;
- if (unlikely (!fda->serialize (c, it, fontSzr))) return false;
+ if (unlikely (!fda->serialize (c, it, fontSzr)))
+ {
+ c->pop_discard ();
+ return false;
+ }
plan.info.fd_array_link = c->pop_pack (false);
}
/* variation store */
- if (acc.varStore != &Null (CFF2VariationStore) &&
+ if (varStore != &Null (CFF2ItemVariationStore) &&
!plan.pinned)
{
- c->push ();
- CFF2VariationStore *dest = c->start_embed<CFF2VariationStore> ();
- if (unlikely (!dest || !dest->serialize (c, acc.varStore))) return false;
+ auto *dest = c->push<CFF2ItemVariationStore> ();
+ if (unlikely (!dest->serialize (c, varStore)))
+ {
+ c->pop_discard ();
+ return false;
+ }
plan.info.var_store_link = c->pop_pack (false);
}
@@ -628,34 +652,25 @@ static bool _serialize_cff2 (hb_serialize_context_t *c,
{
TopDict &dict = cff2 + cff2->topDict;
cff2_top_dict_op_serializer_t topSzr;
- if (unlikely (!dict.serialize (c, acc.topDict, topSzr, plan.info))) return false;
+ if (unlikely (!dict.serialize (c, topDict, topSzr, plan.info))) return false;
cff2->topDictSize = c->head - (const char *)&dict;
}
/* global subrs */
{
- CFF2Subrs *dest = c->start_embed <CFF2Subrs> ();
- if (unlikely (!dest)) return false;
+ auto *dest = c->start_embed <CFF2Subrs> ();
return dest->serialize (c, plan.subset_globalsubrs);
}
}
-static bool
-_hb_subset_cff2 (const OT::cff2::accelerator_subset_t &acc,
- hb_subset_context_t *c)
+bool
+OT::cff2::accelerator_subset_t::subset (hb_subset_context_t *c) const
{
cff2_subset_plan cff2_plan;
- if (unlikely (!cff2_plan.create (acc, c->plan))) return false;
- return _serialize_cff2 (c->serializer, cff2_plan, acc, c->plan->num_output_glyphs (),
- c->plan->normalized_coords.as_array ());
-}
-
-bool
-hb_subset_cff2 (hb_subset_context_t *c)
-{
- OT::cff2::accelerator_subset_t acc (c->plan->source);
- return acc.is_valid () && _hb_subset_cff2 (acc, c);
+ if (unlikely (!cff2_plan.create (*this, c->plan))) return false;
+ return serialize (c->serializer, cff2_plan,
+ c->plan->normalized_coords.as_array ());
}
#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc
index ca59de79a2..68a3e77788 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-input.cc
@@ -24,6 +24,7 @@
* Google Author(s): Garret Rieger, Rod Sheeter, Behdad Esfahbod
*/
+#include "hb-subset-instancer-solver.hh"
#include "hb-subset.hh"
#include "hb-set.hh"
#include "hb-utf.hh"
@@ -50,7 +51,6 @@ hb_subset_input_t::hb_subset_input_t ()
HB_TAG ('k', 'e', 'r', 'n'),
// Copied from fontTools:
- HB_TAG ('B', 'A', 'S', 'E'),
HB_TAG ('J', 'S', 'T', 'F'),
HB_TAG ('D', 'S', 'I', 'G'),
HB_TAG ('E', 'B', 'D', 'T'),
@@ -69,15 +69,11 @@ hb_subset_input_t::hb_subset_input_t ()
sets.drop_tables->add_array (default_drop_tables, ARRAY_LENGTH (default_drop_tables));
hb_tag_t default_no_subset_tables[] = {
- HB_TAG ('a', 'v', 'a', 'r'),
HB_TAG ('g', 'a', 's', 'p'),
- HB_TAG ('c', 'v', 't', ' '),
HB_TAG ('f', 'p', 'g', 'm'),
HB_TAG ('p', 'r', 'e', 'p'),
HB_TAG ('V', 'D', 'M', 'X'),
HB_TAG ('D', 'S', 'I', 'G'),
- HB_TAG ('M', 'V', 'A', 'R'),
- HB_TAG ('c', 'v', 'a', 'r'),
};
sets.no_subset_tables->add_array (default_no_subset_tables,
ARRAY_LENGTH (default_no_subset_tables));
@@ -127,6 +123,12 @@ hb_subset_input_t::hb_subset_input_t ()
//justify
HB_TAG ('j', 'a', 'l', 't'), // HarfBuzz doesn't use; others might
+ //East Asian spacing
+ HB_TAG ('c', 'h', 'w', 's'),
+ HB_TAG ('v', 'c', 'h', 'w'),
+ HB_TAG ('h', 'a', 'l', 't'),
+ HB_TAG ('v', 'h', 'a', 'l'),
+
//private
HB_TAG ('H', 'a', 'r', 'f'),
HB_TAG ('H', 'A', 'R', 'F'),
@@ -416,6 +418,46 @@ hb_subset_input_keep_everything (hb_subset_input_t *input)
#ifndef HB_NO_VAR
/**
+ * hb_subset_input_pin_all_axes_to_default: (skip)
+ * @input: a #hb_subset_input_t object.
+ * @face: a #hb_face_t object.
+ *
+ * Pin all axes to default locations in the given subset input object.
+ *
+ * All axes in a font must be pinned. Additionally, `CFF2` table, if present,
+ * will be de-subroutinized.
+ *
+ * Return value: `true` if success, `false` otherwise
+ *
+ * Since: 8.3.1
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_pin_all_axes_to_default (hb_subset_input_t *input,
+ hb_face_t *face)
+{
+ unsigned axis_count = hb_ot_var_get_axis_count (face);
+ if (!axis_count) return false;
+
+ hb_ot_var_axis_info_t *axis_infos = (hb_ot_var_axis_info_t *) hb_calloc (axis_count, sizeof (hb_ot_var_axis_info_t));
+ if (unlikely (!axis_infos)) return false;
+
+ (void) hb_ot_var_get_axis_infos (face, 0, &axis_count, axis_infos);
+
+ for (unsigned i = 0; i < axis_count; i++)
+ {
+ hb_tag_t axis_tag = axis_infos[i].tag;
+ float default_val = axis_infos[i].default_value;
+ if (!input->axes_location.set (axis_tag, Triple (default_val, default_val, default_val)))
+ {
+ hb_free (axis_infos);
+ return false;
+ }
+ }
+ hb_free (axis_infos);
+ return true;
+}
+
+/**
* hb_subset_input_pin_axis_to_default: (skip)
* @input: a #hb_subset_input_t object.
* @face: a #hb_face_t object.
@@ -439,7 +481,8 @@ hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
return false;
- return input->axes_location.set (axis_tag, axis_info.default_value);
+ float default_val = axis_info.default_value;
+ return input->axes_location.set (axis_tag, Triple (default_val, default_val, default_val));
}
/**
@@ -469,8 +512,92 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
return false;
float val = hb_clamp(axis_value, axis_info.min_value, axis_info.max_value);
- return input->axes_location.set (axis_tag, val);
+ return input->axes_location.set (axis_tag, Triple (val, val, val));
}
+
+#ifdef HB_EXPERIMENTAL_API
+/**
+ * hb_subset_input_set_axis_range: (skip)
+ * @input: a #hb_subset_input_t object.
+ * @face: a #hb_face_t object.
+ * @axis_tag: Tag of the axis
+ * @axis_min_value: Minimum value of the axis variation range to set, if NaN the existing min will be used.
+ * @axis_max_value: Maximum value of the axis variation range to set if NaN the existing max will be used.
+ * @axis_def_value: Default value of the axis variation range to set, if NaN the existing default will be used.
+ *
+ * Restricting the range of variation on an axis in the given subset input object.
+ * New min/default/max values will be clamped if they're not within the fvar axis range.
+ *
+ * If the fvar axis default value is not within the new range, the new default
+ * value will be changed to the new min or max value, whichever is closer to the fvar
+ * axis default.
+ *
+ * Note: input min value can not be bigger than input max value. If the input
+ * default value is not within the new min/max range, it'll be clamped.
+ * Note: currently it supports gvar and cvar tables only.
+ *
+ * Return value: `true` if success, `false` otherwise
+ *
+ * XSince: EXPERIMENTAL
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_set_axis_range (hb_subset_input_t *input,
+ hb_face_t *face,
+ hb_tag_t axis_tag,
+ float axis_min_value,
+ float axis_max_value,
+ float axis_def_value)
+{
+ hb_ot_var_axis_info_t axis_info;
+ if (!hb_ot_var_find_axis_info (face, axis_tag, &axis_info))
+ return false;
+
+ float min = !std::isnan(axis_min_value) ? axis_min_value : axis_info.min_value;
+ float max = !std::isnan(axis_max_value) ? axis_max_value : axis_info.max_value;
+ float def = !std::isnan(axis_def_value) ? axis_def_value : axis_info.default_value;
+
+ if (min > max)
+ return false;
+
+ float new_min_val = hb_clamp(min, axis_info.min_value, axis_info.max_value);
+ float new_max_val = hb_clamp(max, axis_info.min_value, axis_info.max_value);
+ float new_default_val = hb_clamp(def, new_min_val, new_max_val);
+ return input->axes_location.set (axis_tag, Triple (new_min_val, new_default_val, new_max_val));
+}
+
+/**
+ * hb_subset_input_get_axis_range: (skip)
+ * @input: a #hb_subset_input_t object.
+ * @axis_tag: Tag of the axis
+ * @axis_min_value: Set to the previously configured minimum value of the axis variation range.
+ * @axis_max_value: Set to the previously configured maximum value of the axis variation range.
+ * @axis_def_value: Set to the previously configured default value of the axis variation range.
+ *
+ * Gets the axis range assigned by previous calls to hb_subset_input_set_axis_range.
+ *
+ * Return value: `true` if a range has been set for this axis tag, `false` otherwise.
+ *
+ * XSince: EXPERIMENTAL
+ **/
+HB_EXTERN hb_bool_t
+hb_subset_input_get_axis_range (hb_subset_input_t *input,
+ hb_tag_t axis_tag,
+ float *axis_min_value,
+ float *axis_max_value,
+ float *axis_def_value)
+
+{
+ Triple* triple;
+ if (!input->axes_location.has(axis_tag, &triple)) {
+ return false;
+ }
+
+ *axis_min_value = triple->minimum;
+ *axis_def_value = triple->middle;
+ *axis_max_value = triple->maximum;
+ return true;
+}
+#endif
#endif
/**
@@ -521,6 +648,37 @@ hb_subset_preprocess (hb_face_t *source)
return new_source;
}
+/**
+ * hb_subset_input_old_to_new_glyph_mapping:
+ * @input: a #hb_subset_input_t object.
+ *
+ * Returns a map which can be used to provide an explicit mapping from old to new glyph
+ * id's in the produced subset. The caller should populate the map as desired.
+ * If this map is left empty then glyph ids will be automatically mapped to new
+ * values by the subsetter. If populated, the mapping must be unique. That
+ * is no two original glyph ids can be mapped to the same new id.
+ * Additionally, if a mapping is provided then the retain gids option cannot
+ * be enabled.
+ *
+ * Any glyphs that are retained in the subset which are not specified
+ * in this mapping will be assigned glyph ids after the highest glyph
+ * id in the mapping.
+ *
+ * Note: this will accept and apply non-monotonic mappings, however this
+ * may result in unsorted Coverage tables. Such fonts may not work for all
+ * use cases (for example ots will reject unsorted coverage tables). So it's
+ * recommended, if possible, to supply a monotonic mapping.
+ *
+ * Return value: (transfer none): pointer to the #hb_map_t of the custom glyphs ID map.
+ *
+ * Since: 7.3.0
+ **/
+HB_EXTERN hb_map_t*
+hb_subset_input_old_to_new_glyph_mapping (hb_subset_input_t *input)
+{
+ return &input->glyph_map;
+}
+
#ifdef HB_EXPERIMENTAL_API
/**
* hb_subset_input_override_name_table:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-input.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-input.hh
index 1550e8b2c3..6ae311e613 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-input.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-input.hh
@@ -35,6 +35,7 @@
#include "hb-set.hh"
#include "hb-cplusplus.hh"
#include "hb-font.hh"
+#include "hb-subset-instancer-solver.hh"
struct hb_ot_name_record_ids_t
{
@@ -118,7 +119,8 @@ struct hb_subset_input_t
// If set loca format will always be the long version.
bool force_long_loca = false;
- hb_hashmap_t<hb_tag_t, float> axes_location;
+ hb_hashmap_t<hb_tag_t, Triple> axes_location;
+ hb_map_t glyph_map;
#ifdef HB_EXPERIMENTAL_API
hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> name_table_overrides;
#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.cc
new file mode 100644
index 0000000000..35a964d082
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.cc
@@ -0,0 +1,532 @@
+/*
+ * Copyright © 2024 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.
+ */
+
+#include "hb-subset-instancer-iup.hh"
+
+/* This file is a straight port of the following:
+ *
+ * https://github.com/fonttools/fonttools/blob/main/Lib/fontTools/varLib/iup.py
+ *
+ * Where that file returns optimzied deltas vector, we return optimized
+ * referenced point indices.
+ */
+
+constexpr static unsigned MAX_LOOKBACK = 8;
+
+static void _iup_contour_bound_forced_set (const hb_array_t<const contour_point_t> contour_points,
+ const hb_array_t<const int> x_deltas,
+ const hb_array_t<const int> y_deltas,
+ hb_set_t& forced_set, /* OUT */
+ float tolerance = 0.f)
+{
+ unsigned len = contour_points.length;
+ unsigned next_i = 0;
+ for (int i = len - 1; i >= 0; i--)
+ {
+ unsigned last_i = (len + i -1) % len;
+ for (unsigned j = 0; j < 2; j++)
+ {
+ float cj, lcj, ncj;
+ int dj, ldj, ndj;
+ if (j == 0)
+ {
+ cj = contour_points.arrayZ[i].x;
+ dj = x_deltas.arrayZ[i];
+ lcj = contour_points.arrayZ[last_i].x;
+ ldj = x_deltas.arrayZ[last_i];
+ ncj = contour_points.arrayZ[next_i].x;
+ ndj = x_deltas.arrayZ[next_i];
+ }
+ else
+ {
+ cj = contour_points.arrayZ[i].y;
+ dj = y_deltas.arrayZ[i];
+ lcj = contour_points.arrayZ[last_i].y;
+ ldj = y_deltas.arrayZ[last_i];
+ ncj = contour_points.arrayZ[next_i].y;
+ ndj = y_deltas.arrayZ[next_i];
+ }
+
+ float c1, c2;
+ int d1, d2;
+ if (lcj <= ncj)
+ {
+ c1 = lcj;
+ c2 = ncj;
+ d1 = ldj;
+ d2 = ndj;
+ }
+ else
+ {
+ c1 = ncj;
+ c2 = lcj;
+ d1 = ndj;
+ d2 = ldj;
+ }
+
+ bool force = false;
+ if (c1 == c2)
+ {
+ if (abs (d1 - d2) > tolerance && abs (dj) > tolerance)
+ force = true;
+ }
+ else if (c1 <= cj && cj <= c2)
+ {
+ if (!(hb_min (d1, d2) - tolerance <= dj &&
+ dj <= hb_max (d1, d2) + tolerance))
+ force = true;
+ }
+ else
+ {
+ if (d1 != d2)
+ {
+ if (cj < c1)
+ {
+ if (abs (dj) > tolerance &&
+ abs (dj - d1) > tolerance &&
+ ((dj - tolerance < d1) != (d1 < d2)))
+ force = true;
+ }
+ else
+ {
+ if (abs (dj) > tolerance &&
+ abs (dj - d2) > tolerance &&
+ ((d2 < dj + tolerance) != (d1 < d2)))
+ force = true;
+ }
+ }
+ }
+
+ if (force)
+ {
+ forced_set.add (i);
+ break;
+ }
+ }
+ next_i = i;
+ }
+}
+
+template <typename T,
+ hb_enable_if (hb_is_trivially_copyable (T))>
+static bool rotate_array (const hb_array_t<const T>& org_array,
+ int k,
+ hb_vector_t<T>& out)
+{
+ unsigned n = org_array.length;
+ if (!n) return true;
+ if (unlikely (!out.resize (n, false)))
+ return false;
+
+ unsigned item_size = hb_static_size (T);
+ if (k < 0)
+ k = n - (-k) % n;
+ else
+ k %= n;
+
+ hb_memcpy ((void *) out.arrayZ, (const void *) (org_array.arrayZ + n - k), k * item_size);
+ hb_memcpy ((void *) (out.arrayZ + k), (const void *) org_array.arrayZ, (n - k) * item_size);
+ return true;
+}
+
+static bool rotate_set (const hb_set_t& org_set,
+ int k,
+ unsigned n,
+ hb_set_t& out)
+{
+ if (!n) return false;
+ k %= n;
+ if (k < 0)
+ k = n + k;
+
+ if (k == 0)
+ {
+ out.set (org_set);
+ }
+ else
+ {
+ for (auto v : org_set)
+ out.add ((v + k) % n);
+ }
+ return !out.in_error ();
+}
+
+/* Given two reference coordinates (start and end of contour_points array),
+ * output interpolated deltas for points in between */
+static bool _iup_segment (const hb_array_t<const contour_point_t> contour_points,
+ const hb_array_t<const int> x_deltas,
+ const hb_array_t<const int> y_deltas,
+ const contour_point_t& p1, const contour_point_t& p2,
+ int p1_dx, int p2_dx,
+ int p1_dy, int p2_dy,
+ hb_vector_t<float>& interp_x_deltas, /* OUT */
+ hb_vector_t<float>& interp_y_deltas /* OUT */)
+{
+ unsigned n = contour_points.length;
+ if (unlikely (!interp_x_deltas.resize (n, false) ||
+ !interp_y_deltas.resize (n, false)))
+ return false;
+
+ for (unsigned j = 0; j < 2; j++)
+ {
+ float x1, x2, d1, d2;
+ float *out;
+ if (j == 0)
+ {
+ x1 = p1.x;
+ x2 = p2.x;
+ d1 = p1_dx;
+ d2 = p2_dx;
+ out = interp_x_deltas.arrayZ;
+ }
+ else
+ {
+ x1 = p1.y;
+ x2 = p2.y;
+ d1 = p1_dy;
+ d2 = p2_dy;
+ out = interp_y_deltas.arrayZ;
+ }
+
+ if (x1 == x2)
+ {
+ if (d1 == d2)
+ {
+ for (unsigned i = 0; i < n; i++)
+ out[i] = d1;
+ }
+ else
+ {
+ for (unsigned i = 0; i < n; i++)
+ out[i] = 0.f;
+ }
+ continue;
+ }
+
+ if (x1 > x2)
+ {
+ hb_swap (x1, x2);
+ hb_swap (d1, d2);
+ }
+
+ float scale = (d2 - d1) / (x2 - x1);
+ for (unsigned i = 0; i < n; i++)
+ {
+ float x = j == 0 ? contour_points.arrayZ[i].x : contour_points.arrayZ[i].y;
+ float d;
+ if (x <= x1)
+ d = d1;
+ else if (x >= x2)
+ d = d2;
+ else
+ d = d1 + (x - x1) * scale;
+
+ out[i] = d;
+ }
+ }
+ return true;
+}
+
+static bool _can_iup_in_between (const hb_array_t<const contour_point_t> contour_points,
+ const hb_array_t<const int> x_deltas,
+ const hb_array_t<const int> y_deltas,
+ const contour_point_t& p1, const contour_point_t& p2,
+ int p1_dx, int p2_dx,
+ int p1_dy, int p2_dy,
+ float tolerance)
+{
+ hb_vector_t<float> interp_x_deltas, interp_y_deltas;
+ if (!_iup_segment (contour_points, x_deltas, y_deltas,
+ p1, p2, p1_dx, p2_dx, p1_dy, p2_dy,
+ interp_x_deltas, interp_y_deltas))
+ return false;
+
+ unsigned num = contour_points.length;
+
+ for (unsigned i = 0; i < num; i++)
+ {
+ float dx = x_deltas.arrayZ[i] - interp_x_deltas.arrayZ[i];
+ float dy = y_deltas.arrayZ[i] - interp_y_deltas.arrayZ[i];
+
+ if (sqrtf ((float)dx * dx + (float)dy * dy) > tolerance)
+ return false;
+ }
+ return true;
+}
+
+static bool _iup_contour_optimize_dp (const contour_point_vector_t& contour_points,
+ const hb_vector_t<int>& x_deltas,
+ const hb_vector_t<int>& y_deltas,
+ const hb_set_t& forced_set,
+ float tolerance,
+ unsigned lookback,
+ hb_vector_t<unsigned>& costs, /* OUT */
+ hb_vector_t<int>& chain /* OUT */)
+{
+ unsigned n = contour_points.length;
+ if (unlikely (!costs.resize (n, false) ||
+ !chain.resize (n, false)))
+ return false;
+
+ lookback = hb_min (lookback, MAX_LOOKBACK);
+
+ for (unsigned i = 0; i < n; i++)
+ {
+ unsigned best_cost = (i == 0 ? 1 : costs.arrayZ[i-1] + 1);
+
+ costs.arrayZ[i] = best_cost;
+ chain.arrayZ[i] = (i == 0 ? -1 : i - 1);
+
+ if (i > 0 && forced_set.has (i - 1))
+ continue;
+
+ int lookback_index = hb_max ((int) i - (int) lookback + 1, -1);
+ for (int j = i - 2; j >= lookback_index; j--)
+ {
+ unsigned cost = j == -1 ? 1 : costs.arrayZ[j] + 1;
+ /* num points between i and j */
+ unsigned num_points = i - j - 1;
+ unsigned p1 = (j == -1 ? n - 1 : j);
+ if (cost < best_cost &&
+ _can_iup_in_between (contour_points.as_array ().sub_array (j + 1, num_points),
+ x_deltas.as_array ().sub_array (j + 1, num_points),
+ y_deltas.as_array ().sub_array (j + 1, num_points),
+ contour_points.arrayZ[p1], contour_points.arrayZ[i],
+ x_deltas.arrayZ[p1], x_deltas.arrayZ[i],
+ y_deltas.arrayZ[p1], y_deltas.arrayZ[i],
+ tolerance))
+ {
+ best_cost = cost;
+ costs.arrayZ[i] = best_cost;
+ chain.arrayZ[i] = j;
+ }
+
+ if (j > 0 && forced_set.has (j))
+ break;
+ }
+ }
+ return true;
+}
+
+static bool _iup_contour_optimize (const hb_array_t<const contour_point_t> contour_points,
+ const hb_array_t<const int> x_deltas,
+ const hb_array_t<const int> y_deltas,
+ hb_array_t<bool> opt_indices, /* OUT */
+ float tolerance = 0.f)
+{
+ unsigned n = contour_points.length;
+ if (opt_indices.length != n ||
+ x_deltas.length != n ||
+ y_deltas.length != n)
+ return false;
+
+ bool all_within_tolerance = true;
+ for (unsigned i = 0; i < n; i++)
+ {
+ int dx = x_deltas.arrayZ[i];
+ int dy = y_deltas.arrayZ[i];
+ if (sqrtf ((float)dx * dx + (float)dy * dy) > tolerance)
+ {
+ all_within_tolerance = false;
+ break;
+ }
+ }
+
+ /* If all are within tolerance distance, do nothing, opt_indices is
+ * initilized to false */
+ if (all_within_tolerance)
+ return true;
+
+ /* If there's exactly one point, return it */
+ if (n == 1)
+ {
+ opt_indices.arrayZ[0] = true;
+ return true;
+ }
+
+ /* If all deltas are exactly the same, return just one (the first one) */
+ bool all_deltas_are_equal = true;
+ for (unsigned i = 1; i < n; i++)
+ if (x_deltas.arrayZ[i] != x_deltas.arrayZ[0] ||
+ y_deltas.arrayZ[i] != y_deltas.arrayZ[0])
+ {
+ all_deltas_are_equal = false;
+ break;
+ }
+
+ if (all_deltas_are_equal)
+ {
+ opt_indices.arrayZ[0] = true;
+ return true;
+ }
+
+ /* else, solve the general problem using Dynamic Programming */
+ hb_set_t forced_set;
+ _iup_contour_bound_forced_set (contour_points, x_deltas, y_deltas, forced_set, tolerance);
+
+ if (!forced_set.is_empty ())
+ {
+ int k = n - 1 - forced_set.get_max ();
+ if (k < 0)
+ return false;
+
+ hb_vector_t<int> rot_x_deltas, rot_y_deltas;
+ contour_point_vector_t rot_points;
+ hb_set_t rot_forced_set;
+ if (!rotate_array (contour_points, k, rot_points) ||
+ !rotate_array (x_deltas, k, rot_x_deltas) ||
+ !rotate_array (y_deltas, k, rot_y_deltas) ||
+ !rotate_set (forced_set, k, n, rot_forced_set))
+ return false;
+
+ hb_vector_t<unsigned> costs;
+ hb_vector_t<int> chain;
+
+ if (!_iup_contour_optimize_dp (rot_points, rot_x_deltas, rot_y_deltas,
+ rot_forced_set, tolerance, n,
+ costs, chain))
+ return false;
+
+ hb_set_t solution;
+ int index = n - 1;
+ while (index != -1)
+ {
+ solution.add (index);
+ index = chain.arrayZ[index];
+ }
+
+ if (solution.is_empty () ||
+ forced_set.get_population () > solution.get_population ())
+ return false;
+
+ for (unsigned i : solution)
+ opt_indices.arrayZ[i] = true;
+
+ hb_vector_t<bool> rot_indices;
+ const hb_array_t<const bool> opt_indices_array (opt_indices.arrayZ, opt_indices.length);
+ rotate_array (opt_indices_array, -k, rot_indices);
+
+ for (unsigned i = 0; i < n; i++)
+ opt_indices.arrayZ[i] = rot_indices.arrayZ[i];
+ }
+ else
+ {
+ hb_vector_t<int> repeat_x_deltas, repeat_y_deltas;
+ contour_point_vector_t repeat_points;
+
+ if (unlikely (!repeat_x_deltas.resize (n * 2, false) ||
+ !repeat_y_deltas.resize (n * 2, false) ||
+ !repeat_points.resize (n * 2, false)))
+ return false;
+
+ unsigned contour_point_size = hb_static_size (contour_point_t);
+ for (unsigned i = 0; i < n; i++)
+ {
+ hb_memcpy ((void *) repeat_x_deltas.arrayZ, (const void *) x_deltas.arrayZ, n * sizeof (float));
+ hb_memcpy ((void *) (repeat_x_deltas.arrayZ + n), (const void *) x_deltas.arrayZ, n * sizeof (float));
+
+ hb_memcpy ((void *) repeat_y_deltas.arrayZ, (const void *) y_deltas.arrayZ, n * sizeof (float));
+ hb_memcpy ((void *) (repeat_y_deltas.arrayZ + n), (const void *) y_deltas.arrayZ, n * sizeof (float));
+
+ hb_memcpy ((void *) repeat_points.arrayZ, (const void *) contour_points.arrayZ, n * contour_point_size);
+ hb_memcpy ((void *) (repeat_points.arrayZ + n), (const void *) contour_points.arrayZ, n * contour_point_size);
+ }
+
+ hb_vector_t<unsigned> costs;
+ hb_vector_t<int> chain;
+ if (!_iup_contour_optimize_dp (repeat_points, repeat_x_deltas, repeat_y_deltas,
+ forced_set, tolerance, n,
+ costs, chain))
+ return false;
+
+ unsigned best_cost = n + 1;
+ int len = costs.length;
+ hb_set_t best_sol;
+ for (int start = n - 1; start < len; start++)
+ {
+ hb_set_t solution;
+ int i = start;
+ int lookback = start - (int) n;
+ while (i > lookback)
+ {
+ solution.add (i % n);
+ i = chain.arrayZ[i];
+ }
+ if (i == lookback)
+ {
+ unsigned cost_i = i < 0 ? 0 : costs.arrayZ[i];
+ unsigned cost = costs.arrayZ[start] - cost_i;
+ if (cost <= best_cost)
+ {
+ best_sol.set (solution);
+ best_cost = cost;
+ }
+ }
+ }
+
+ for (unsigned i = 0; i < n; i++)
+ if (best_sol.has (i))
+ opt_indices.arrayZ[i] = true;
+ }
+ return true;
+}
+
+bool iup_delta_optimize (const contour_point_vector_t& contour_points,
+ const hb_vector_t<int>& x_deltas,
+ const hb_vector_t<int>& y_deltas,
+ hb_vector_t<bool>& opt_indices, /* OUT */
+ float tolerance)
+{
+ if (!opt_indices.resize (contour_points.length))
+ return false;
+
+ hb_vector_t<unsigned> end_points;
+ unsigned count = contour_points.length;
+ if (unlikely (!end_points.alloc (count)))
+ return false;
+
+ for (unsigned i = 0; i < count - 4; i++)
+ if (contour_points.arrayZ[i].is_end_point)
+ end_points.push (i);
+
+ /* phantom points */
+ for (unsigned i = count - 4; i < count; i++)
+ end_points.push (i);
+
+ if (end_points.in_error ()) return false;
+
+ unsigned start = 0;
+ for (unsigned end : end_points)
+ {
+ unsigned len = end - start + 1;
+ if (!_iup_contour_optimize (contour_points.as_array ().sub_array (start, len),
+ x_deltas.as_array ().sub_array (start, len),
+ y_deltas.as_array ().sub_array (start, len),
+ opt_indices.as_array ().sub_array (start, len),
+ tolerance))
+ return false;
+ start = end + 1;
+ }
+ return true;
+}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.hh
new file mode 100644
index 0000000000..7eac5935a4
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-iup.hh
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2024 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.
+ */
+
+#ifndef HB_SUBSET_INSTANCER_IUP_HH
+#define HB_SUBSET_INSTANCER_IUP_HH
+
+#include "hb-subset-plan.hh"
+/* given contour points and deltas, optimize a set of referenced points within error
+ * tolerance. Returns optimized referenced point indices */
+HB_INTERNAL bool iup_delta_optimize (const contour_point_vector_t& contour_points,
+ const hb_vector_t<int>& x_deltas,
+ const hb_vector_t<int>& y_deltas,
+ hb_vector_t<bool>& opt_indices, /* OUT */
+ float tolerance = 0.f);
+
+#endif /* HB_SUBSET_INSTANCER_IUP_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc
index 5c0f43ad4b..70783c0a0d 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.cc
@@ -22,7 +22,7 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
-#include "hb.hh"
+#include "hb-subset-instancer-solver.hh"
/* This file is a straight port of the following:
*
@@ -35,26 +35,6 @@
constexpr static float EPSILON = 1.f / (1 << 14);
constexpr static float MAX_F2DOT14 = float (0x7FFF) / (1 << 14);
-struct Triple {
-
- Triple () :
- minimum (0.f), middle (0.f), maximum (0.f) {}
-
- Triple (float minimum_, float middle_, float maximum_) :
- minimum (minimum_), middle (middle_), maximum (maximum_) {}
-
- bool operator == (const Triple &o) const
- {
- return minimum == o.minimum &&
- middle == o.middle &&
- maximum == o.maximum;
- }
-
- float minimum;
- float middle;
- float maximum;
-};
-
static inline Triple _reverse_negate(const Triple &v)
{ return {-v.maximum, -v.middle, -v.minimum}; }
@@ -82,10 +62,6 @@ static inline float supportScalar (float coord, const Triple &tent)
return (end - coord) / (end - peak);
}
-
-using result_item_t = hb_pair_t<float, Triple>;
-using result_t = hb_vector_t<result_item_t>;
-
static inline result_t
_solve (Triple tent, Triple axisLimit, bool negative = false)
{
@@ -125,7 +101,7 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
return result_t{}; // No overlap
/* case 2: Only the peak and outermost bound fall outside the new limit;
- * we keep the deltaset, update peak and outermost bound and and scale deltas
+ * we keep the deltaset, update peak and outermost bound and scale deltas
* by the scalar value for the restricted axis at the new limit, and solve
* recursively.
*
@@ -192,12 +168,14 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
* |
* crossing
*/
- if (gain > outGain)
+ if (gain >= outGain)
{
+ // Note that this is the branch taken if both gain and outGain are 0.
+
// Crossing point on the axis.
- float crossing = peak + ((1 - gain) * (upper - peak) / (1 - outGain));
+ float crossing = peak + (1 - gain) * (upper - peak);
- Triple loc{peak, peak, crossing};
+ Triple loc{hb_max (lower, axisDef), peak, crossing};
float scalar = 1.f;
// The part before the crossing point.
@@ -213,7 +191,7 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
if (upper >= axisMax)
{
Triple loc {crossing, axisMax, axisMax};
- float scalar = supportScalar (axisMax, tent);
+ float scalar = outGain;
out.push (hb_pair (scalar - gain, loc));
}
@@ -247,89 +225,85 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
// Eternity justify.
Triple loc2 {upper, axisMax, axisMax};
- float scalar2 = 1.f; // supportScalar({"tag": axisMax}, {"tag": tent})
+ float scalar2 = 0.f;
out.push (hb_pair (scalar1 - gain, loc1));
out.push (hb_pair (scalar2 - gain, loc2));
}
}
- /* Case 3: Outermost limit still fits within F2Dot14 bounds;
- * we keep deltas as is and only scale the axes bounds. Deltas beyond -1.0
- * or +1.0 will never be applied as implementations must clamp to that range.
- *
- * A second tent is needed for cases when gain is positive, though we add it
- * unconditionally and it will be dropped because scalar ends up 0.
- *
- * TODO: See if we can just move upper closer to adjust the slope, instead of
- * second tent.
- *
- * | peak |
- * 1.........|............o...|..................
- * | /x\ |
- * | /xxx\ |
- * | /xxxxx\|
- * | /xxxxxxx+
- * | /xxxxxxxx|\
- * 0---|-----|------oxxxxxxxxx|xo---------------1
- * axisMin | lower | upper
- * | |
- * axisDef axisMax
- */
- else if (axisDef + (axisMax - axisDef) * 2 >= upper)
+ else
{
- if (!negative && axisDef + (axisMax - axisDef) * MAX_F2DOT14 < upper)
- {
- // we clamp +2.0 to the max F2Dot14 (~1.99994) for convenience
- upper = axisDef + (axisMax - axisDef) * MAX_F2DOT14;
- assert (peak < upper);
- }
-
// Special-case if peak is at axisMax.
if (axisMax == peak)
upper = peak;
- Triple loc1 {hb_max (axisDef, lower), peak, upper};
- float scalar1 = 1.f;
+ /* Case 3:
+ * we keep deltas as is and only scale the axis upper to achieve
+ * the desired new tent if feasible.
+ *
+ * peak
+ * 1.....................o....................
+ * / \_|
+ * ..................../....+_.........outGain
+ * / | \
+ * gain..............+......|..+_.............
+ * /| | | \
+ * 0---|-----------o | | | o----------1
+ * axisMin lower| | | upper
+ * | | newUpper
+ * axisDef axisMax
+ */
+ float newUpper = peak + (1 - gain) * (upper - peak);
+ assert (axisMax <= newUpper); // Because outGain > gain
+ /* Disabled because ots doesn't like us:
+ * https://github.com/fonttools/fonttools/issues/3350 */
+
+ if (false && (newUpper <= axisDef + (axisMax - axisDef) * 2))
+ {
+ upper = newUpper;
+ if (!negative && axisDef + (axisMax - axisDef) * MAX_F2DOT14 < upper)
+ {
+ // we clamp +2.0 to the max F2Dot14 (~1.99994) for convenience
+ upper = axisDef + (axisMax - axisDef) * MAX_F2DOT14;
+ assert (peak < upper);
+ }
- Triple loc2 {peak, upper, upper};
- float scalar2 = 0.f;
+ Triple loc {hb_max (axisDef, lower), peak, upper};
+ float scalar = 1.f;
- // Don't add a dirac delta!
- if (axisDef < upper)
- out.push (hb_pair (scalar1 - gain, loc1));
- if (peak < upper)
- out.push (hb_pair (scalar2 - gain, loc2));
- }
+ out.push (hb_pair (scalar - gain, loc));
+ }
- /* Case 4: New limit doesn't fit; we need to chop into two tents,
- * because the shape of a triangle with part of one side cut off
- * cannot be represented as a triangle itself.
- *
- * | peak |
- * 1.........|......o.|...................
- * | /x\|
- * | |xxy|\_
- * | /xxxy| \_
- * | |xxxxy| \_
- * | /xxxxy| \_
- * 0---|-----|-oxxxxxx| o----------1
- * axisMin | lower | upper
- * | |
- * axisDef axisMax
- */
- else
- {
- Triple loc1 {hb_max (axisDef, lower), peak, axisMax};
- float scalar1 = 1.f;
+ /* Case 4: New limit doesn't fit; we need to chop into two tents,
+ * because the shape of a triangle with part of one side cut off
+ * cannot be represented as a triangle itself.
+ *
+ * | peak |
+ * 1.........|......o.|....................
+ * ..........|...../x\|.............outGain
+ * | |xxy|\_
+ * | /xxxy| \_
+ * | |xxxxy| \_
+ * | /xxxxy| \_
+ * 0---|-----|-oxxxxxx| o----------1
+ * axisMin | lower | upper
+ * | |
+ * axisDef axisMax
+ */
+ else
+ {
+ Triple loc1 {hb_max (axisDef, lower), peak, axisMax};
+ float scalar1 = 1.f;
- Triple loc2 {peak, axisMax, axisMax};
- float scalar2 = supportScalar (axisMax, tent);
+ Triple loc2 {peak, axisMax, axisMax};
+ float scalar2 = outGain;
- out.push (hb_pair (scalar1 - gain, loc1));
- // Don't add a dirac delta!
- if (peak < axisMax)
- out.push (hb_pair (scalar2 - gain, loc2));
+ out.push (hb_pair (scalar1 - gain, loc1));
+ // Don't add a dirac delta!
+ if (peak < axisMax)
+ out.push (hb_pair (scalar2 - gain, loc2));
+ }
}
/* Now, the negative side
@@ -392,51 +366,47 @@ _solve (Triple tent, Triple axisLimit, bool negative = false)
return out;
}
-/* Normalizes value based on a min/default/max triple. */
-static inline float normalizeValue (float v, const Triple &triple, bool extrapolate = false)
+static inline TripleDistances _reverse_triple_distances (const TripleDistances &v)
+{ return TripleDistances (v.positive, v.negative); }
+
+float renormalizeValue (float v, const Triple &triple,
+ const TripleDistances &triple_distances, bool extrapolate)
{
- /*
- >>> normalizeValue(400, (100, 400, 900))
- 0.0
- >>> normalizeValue(100, (100, 400, 900))
- -1.0
- >>> normalizeValue(650, (100, 400, 900))
- 0.5
- */
float lower = triple.minimum, def = triple.middle, upper = triple.maximum;
assert (lower <= def && def <= upper);
if (!extrapolate)
v = hb_max (hb_min (v, upper), lower);
- if ((v == def) || (lower == upper))
+ if (v == def)
return 0.f;
- if ((v < def && lower != def) || (v > def && upper == def))
+ if (def < 0.f)
+ return -renormalizeValue (-v, _reverse_negate (triple),
+ _reverse_triple_distances (triple_distances), extrapolate);
+
+ /* default >= 0 and v != default */
+ if (v > def)
+ return (v - def) / (upper - def);
+
+ /* v < def */
+ if (lower >= 0.f)
return (v - def) / (def - lower);
+
+ /* lower < 0 and v < default */
+ float total_distance = triple_distances.negative * (-lower) + triple_distances.positive * def;
+
+ float v_distance;
+ if (v >= 0.f)
+ v_distance = (def - v) * triple_distances.positive;
else
- {
- assert ((v > def && upper != def) ||
- (v < def && lower == def));
- return (v - def) / (upper - def);
- }
-}
+ v_distance = (-v) * triple_distances.negative + triple_distances.positive * def;
-/* Given a tuple (lower,peak,upper) "tent" and new axis limits
- * (axisMin,axisDefault,axisMax), solves how to represent the tent
- * under the new axis configuration. All values are in normalized
- * -1,0,+1 coordinate system. Tent values can be outside this range.
- *
- * Return value: a list of tuples. Each tuple is of the form
- * (scalar,tent), where scalar is a multipler to multiply any
- * delta-sets by, and tent is a new tent for that output delta-set.
- * If tent value is Triple{}, that is a special deltaset that should
- * be always-enabled (called "gain").
- */
-HB_INTERNAL result_t rebase_tent (Triple tent, Triple axisLimit);
+ return (-v_distance) /total_distance;
+}
result_t
-rebase_tent (Triple tent, Triple axisLimit)
+rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances)
{
assert (-1.f <= axisLimit.minimum && axisLimit.minimum <= axisLimit.middle && axisLimit.middle <= axisLimit.maximum && axisLimit.maximum <= +1.f);
assert (-2.f <= tent.minimum && tent.minimum <= tent.middle && tent.middle <= tent.maximum && tent.maximum <= +2.f);
@@ -444,7 +414,7 @@ rebase_tent (Triple tent, Triple axisLimit)
result_t sols = _solve (tent, axisLimit);
- auto n = [&axisLimit] (float v) { return normalizeValue (v, axisLimit, true); };
+ auto n = [&axisLimit, &axis_triple_distances] (float v) { return renormalizeValue (v, axisLimit, axis_triple_distances); };
result_t out;
for (auto &p : sols)
@@ -460,5 +430,5 @@ rebase_tent (Triple tent, Triple axisLimit)
Triple{n (t.minimum), n (t.middle), n (t.maximum)}));
}
- return sols;
+ return out;
}
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.hh
new file mode 100644
index 0000000000..563fccbb59
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-instancer-solver.hh
@@ -0,0 +1,112 @@
+/*
+ * Copyright © 2023 Behdad Esfahbod
+ *
+ * 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.
+ */
+
+#ifndef HB_SUBSET_INSTANCER_SOLVER_HH
+#define HB_SUBSET_INSTANCER_SOLVER_HH
+
+#include "hb.hh"
+
+/* pre-normalized distances */
+struct TripleDistances
+{
+ TripleDistances (): negative (1.f), positive (1.f) {}
+ TripleDistances (float neg_, float pos_): negative (neg_), positive (pos_) {}
+ TripleDistances (float min, float default_, float max)
+ {
+ negative = default_ - min;
+ positive = max - default_;
+ }
+
+ float negative;
+ float positive;
+};
+
+struct Triple {
+
+ Triple () :
+ minimum (0.f), middle (0.f), maximum (0.f) {}
+
+ Triple (float minimum_, float middle_, float maximum_) :
+ minimum (minimum_), middle (middle_), maximum (maximum_) {}
+
+ bool operator == (const Triple &o) const
+ {
+ return minimum == o.minimum &&
+ middle == o.middle &&
+ maximum == o.maximum;
+ }
+
+ bool operator != (const Triple o) const
+ { return !(*this == o); }
+
+ bool is_point () const
+ { return minimum == middle && middle == maximum; }
+
+ bool contains (float point) const
+ { return minimum <= point && point <= maximum; }
+
+ /* from hb_array_t hash ()*/
+ uint32_t hash () const
+ {
+ uint32_t current = /*cbf29ce4*/0x84222325;
+ current = current ^ hb_hash (minimum);
+ current = current * 16777619;
+
+ current = current ^ hb_hash (middle);
+ current = current * 16777619;
+
+ current = current ^ hb_hash (maximum);
+ current = current * 16777619;
+ return current;
+ }
+
+
+ float minimum;
+ float middle;
+ float maximum;
+};
+
+using result_item_t = hb_pair_t<float, Triple>;
+using result_t = hb_vector_t<result_item_t>;
+
+/* renormalize a normalized value v to the range of an axis,
+ * considering the prenormalized distances as well as the new axis limits.
+ * Ported from fonttools */
+HB_INTERNAL float renormalizeValue (float v, const Triple &triple,
+ const TripleDistances &triple_distances,
+ bool extrapolate = true);
+/* Given a tuple (lower,peak,upper) "tent" and new axis limits
+ * (axisMin,axisDefault,axisMax), solves how to represent the tent
+ * under the new axis configuration. All values are in normalized
+ * -1,0,+1 coordinate system. Tent values can be outside this range.
+ *
+ * Return value: a list of tuples. Each tuple is of the form
+ * (scalar,tent), where scalar is a multipler to multiply any
+ * delta-sets by, and tent is a new tent for that output delta-set.
+ * If tent value is Triple{}, that is a special deltaset that should
+ * be always-enabled (called "gain").
+ */
+HB_INTERNAL result_t rebase_tent (Triple tent, Triple axisLimit, TripleDistances axis_triple_distances);
+
+#endif /* HB_SUBSET_INSTANCER_SOLVER_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan-member-list.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan-member-list.hh
new file mode 100644
index 0000000000..74416b92f9
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan-member-list.hh
@@ -0,0 +1,158 @@
+/*
+ * Copyright © 2018 Google, Inc.
+ * Copyright © 2023 Behdad Esfahbod
+ *
+ * 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): Garret Rieger, Roderick Sheeter
+ */
+
+#ifndef HB_SUBSET_PLAN_MEMBER_LIST_HH
+#define HB_SUBSET_PLAN_MEMBER_LIST_HH
+#endif /* HB_SUBSET_PLAN_MEMBER_LIST_HH */ /* Dummy header guards */
+
+#define E(x, y) x, y
+
+// For each cp that we'd like to retain maps to the corresponding gid.
+HB_SUBSET_PLAN_MEMBER (hb_set_t, unicodes)
+HB_SUBSET_PLAN_MEMBER (hb_sorted_vector_t<hb_codepoint_pair_t>, unicode_to_new_gid_list)
+
+HB_SUBSET_PLAN_MEMBER (hb_sorted_vector_t<hb_codepoint_pair_t>, new_to_old_gid_list)
+
+// name_ids we would like to retain
+HB_SUBSET_PLAN_MEMBER (hb_set_t, name_ids)
+
+// name_languages we would like to retain
+HB_SUBSET_PLAN_MEMBER (hb_set_t, name_languages)
+
+//layout features which will be preserved
+HB_SUBSET_PLAN_MEMBER (hb_set_t, layout_features)
+
+// layout scripts which will be preserved.
+HB_SUBSET_PLAN_MEMBER (hb_set_t, layout_scripts)
+
+//glyph ids requested to retain
+HB_SUBSET_PLAN_MEMBER (hb_set_t, glyphs_requested)
+
+// Tables which should not be processed, just pass them through.
+HB_SUBSET_PLAN_MEMBER (hb_set_t, no_subset_tables)
+
+// Tables which should be dropped.
+HB_SUBSET_PLAN_MEMBER (hb_set_t, drop_tables)
+
+// Old -> New glyph id mapping
+HB_SUBSET_PLAN_MEMBER (hb_map_t, glyph_map_gsub)
+
+HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset)
+HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset_gsub)
+HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset_mathed)
+HB_SUBSET_PLAN_MEMBER (hb_set_t, _glyphset_colred)
+
+//active lookups we'd like to retain
+HB_SUBSET_PLAN_MEMBER (hb_map_t, gsub_lookups)
+HB_SUBSET_PLAN_MEMBER (hb_map_t, gpos_lookups)
+
+//use_mark_sets mapping: old->new
+HB_SUBSET_PLAN_MEMBER (hb_map_t, used_mark_sets_map)
+
+//active langsys we'd like to retain
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb::unique_ptr<hb_set_t>>), gsub_langsys)
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb::unique_ptr<hb_set_t>>), gpos_langsys)
+
+//active features after removing redundant langsys and prune_features
+HB_SUBSET_PLAN_MEMBER (hb_map_t, gsub_features)
+HB_SUBSET_PLAN_MEMBER (hb_map_t, gpos_features)
+
+//active feature variation records/condition index with variations
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb::shared_ptr<hb_set_t>>), gsub_feature_record_cond_idx_map)
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb::shared_ptr<hb_set_t>>), gpos_feature_record_cond_idx_map)
+
+//feature index-> address of substituation feature table mapping with
+//variations
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, const OT::Feature*>), gsub_feature_substitutes_map)
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, const OT::Feature*>), gpos_feature_substitutes_map)
+
+// old feature_indexes set, used to reinstate the old features
+HB_SUBSET_PLAN_MEMBER (hb_set_t, gsub_old_features)
+HB_SUBSET_PLAN_MEMBER (hb_set_t, gpos_old_features)
+
+//feature_index->pair of (address of old feature, feature tag), used for inserting a catch all record
+//if necessary
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb_pair_t E(<const void*, const void*>)>), gsub_old_feature_idx_tag_map)
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb_pair_t E(<const void*, const void*>)>), gpos_old_feature_idx_tag_map)
+
+//active layers/palettes we'd like to retain
+HB_SUBSET_PLAN_MEMBER (hb_map_t, colrv1_layers)
+HB_SUBSET_PLAN_MEMBER (hb_map_t, colr_palettes)
+
+//Old layout item variation index -> (New varidx, delta) mapping
+HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<unsigned, hb_pair_t E(<unsigned, int>)>), layout_variation_idx_delta_map)
+
+//gdef varstore retained varidx mapping
+HB_SUBSET_PLAN_MEMBER (hb_vector_t<hb_inc_bimap_t>, gdef_varstore_inner_maps)
+
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, hb::unique_ptr<hb_blob_t>>), sanitized_table_cache)
+
+//normalized axes range map
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, Triple>), axes_location)
+HB_SUBSET_PLAN_MEMBER (hb_vector_t<int>, normalized_coords)
+
+//user specified axes range map
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, Triple>), user_axes_location)
+//axis->TripleDistances map (distances in the pre-normalized space)
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_tag_t, TripleDistances>), axes_triple_distances)
+
+//retained old axis index -> new axis index mapping in fvar axis array
+HB_SUBSET_PLAN_MEMBER (hb_map_t, axes_index_map)
+
+//axis_index->axis_tag mapping in fvar axis array
+HB_SUBSET_PLAN_MEMBER (hb_map_t, axes_old_index_tag_map)
+//vector of retained axis tags in the order of axes given in the 'fvar' table
+HB_SUBSET_PLAN_MEMBER (hb_vector_t<hb_tag_t>, axis_tags)
+
+//hmtx metrics map: new gid->(advance, lsb)
+HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<hb_codepoint_t, hb_pair_t E(<unsigned, int>)>), hmtx_map)
+//vmtx metrics map: new gid->(advance, lsb)
+HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<hb_codepoint_t, hb_pair_t E(<unsigned, int>)>), vmtx_map)
+//boundsWidth map: new gid->boundsWidth, boundWidth=xMax - xMin
+HB_SUBSET_PLAN_MEMBER (mutable hb_vector_t<unsigned>, bounds_width_vec)
+//boundsHeight map: new gid->boundsHeight, boundsHeight=yMax - yMin
+HB_SUBSET_PLAN_MEMBER (mutable hb_vector_t<unsigned>, bounds_height_vec)
+
+//map: new_gid -> contour points vector
+HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<hb_codepoint_t, contour_point_vector_t>), new_gid_contour_points_map)
+
+//new gids set for composite glyphs
+HB_SUBSET_PLAN_MEMBER (hb_set_t, composite_new_gids)
+
+//Old BASE item variation index -> (New varidx, 0) mapping
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb_pair_t E(<unsigned, int>)>), base_variation_idx_map)
+
+//BASE table varstore retained varidx mapping
+HB_SUBSET_PLAN_MEMBER (hb_vector_t<hb_inc_bimap_t>, base_varstore_inner_maps)
+
+#ifdef HB_EXPERIMENTAL_API
+// name table overrides map: hb_ot_name_record_ids_t-> name string new value or
+// None to indicate should remove
+HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<hb_ot_name_record_ids_t, hb_bytes_t>), name_table_overrides)
+#endif
+
+#undef E
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc
index 088fdca07b..068fddaedd 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.cc
@@ -32,12 +32,15 @@
#include "hb-ot-cmap-table.hh"
#include "hb-ot-glyf-table.hh"
+#include "hb-ot-layout-base-table.hh"
#include "hb-ot-layout-gdef-table.hh"
#include "hb-ot-layout-gpos-table.hh"
#include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-cff1-table.hh"
+#include "hb-ot-cff2-table.hh"
#include "OT/Color/COLR/COLR.hh"
#include "OT/Color/COLR/colrv1-closure.hh"
+#include "OT/Color/CPAL/CPAL.hh"
#include "hb-ot-var-fvar-table.hh"
#include "hb-ot-var-avar-table.hh"
#include "hb-ot-stat-table.hh"
@@ -46,10 +49,24 @@
using OT::Layout::GSUB;
using OT::Layout::GPOS;
+
+hb_subset_accelerator_t::~hb_subset_accelerator_t ()
+{
+ if (cmap_cache && destroy_cmap_cache)
+ destroy_cmap_cache ((void*) cmap_cache);
+
+#ifndef HB_NO_SUBSET_CFF
+ cff1_accel.fini ();
+ cff2_accel.fini ();
+#endif
+ hb_face_destroy (source);
+}
+
+
typedef hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> script_langsys_map;
#ifndef HB_NO_SUBSET_CFF
static inline bool
-_add_cff_seac_components (const OT::cff1::accelerator_t &cff,
+_add_cff_seac_components (const OT::cff1::accelerator_subset_t &cff,
hb_codepoint_t gid,
hb_set_t *gids_to_retain)
{
@@ -133,7 +150,9 @@ static void _collect_layout_indices (hb_subset_plan_t *plan,
hb_set_t *lookup_indices, /* OUT */
hb_set_t *feature_indices, /* OUT */
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* OUT */
- hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map /* OUT */)
+ hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map, /* OUT */
+ hb_set_t& catch_all_record_feature_idxes, /* OUT */
+ hb_hashmap_t<unsigned, hb_pair_t<const void*, const void*>>& catch_all_record_idx_feature_map /* OUT */)
{
unsigned num_features = table.get_feature_count ();
hb_vector_t<hb_tag_t> features;
@@ -169,8 +188,11 @@ static void _collect_layout_indices (hb_subset_plan_t *plan,
&plan->axes_location,
feature_record_cond_idx_map,
feature_substitutes_map,
+ catch_all_record_feature_idxes,
feature_indices,
- true,
+ false,
+ false,
+ false,
0,
&conditionset_map
};
@@ -188,17 +210,25 @@ static void _collect_layout_indices (hb_subset_plan_t *plan,
f->add_lookup_indexes_to (lookup_indices);
}
+#ifndef HB_NO_VAR
+ if (catch_all_record_feature_idxes)
+ {
+ for (unsigned feature_index : catch_all_record_feature_idxes)
+ {
+ const OT::Feature& f = table.get_feature (feature_index);
+ f.add_lookup_indexes_to (lookup_indices);
+ const void *tag = reinterpret_cast<const void*> (&(table.get_feature_list ().get_tag (feature_index)));
+ catch_all_record_idx_feature_map.set (feature_index, hb_pair (&f, tag));
+ }
+ }
+
// If all axes are pinned then all feature variations will be dropped so there's no need
// to collect lookups from them.
if (!plan->all_axes_pinned)
- {
- // TODO(qxliu76): this collection doesn't work correctly for feature variations that are dropped
- // but not applied. The collection will collect and retain the lookup indices
- // associated with those dropped but not activated rules. Since partial instancing
- // isn't yet supported this isn't an issue yet but will need to be fixed for
- // partial instancing.
- table.feature_variation_collect_lookups (feature_indices, feature_substitutes_map, lookup_indices);
- }
+ table.feature_variation_collect_lookups (feature_indices,
+ plan->user_axes_location.is_empty () ? nullptr: feature_record_cond_idx_map,
+ lookup_indices);
+#endif
}
@@ -281,7 +311,9 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan,
hb_map_t *features,
script_langsys_map *langsys_map,
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
- hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map)
+ hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map,
+ hb_set_t &catch_all_record_feature_idxes,
+ hb_hashmap_t<unsigned, hb_pair_t<const void*, const void*>>& catch_all_record_idx_feature_map)
{
hb_blob_ptr_t<T> table = plan->source_table<T> ();
hb_tag_t table_tag = table->tableTag;
@@ -291,9 +323,11 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan,
&lookup_indices,
&feature_indices,
feature_record_cond_idx_map,
- feature_substitutes_map);
+ feature_substitutes_map,
+ catch_all_record_feature_idxes,
+ catch_all_record_idx_feature_map);
- if (table_tag == HB_OT_TAG_GSUB)
+ if (table_tag == HB_OT_TAG_GSUB && !(plan->flags & HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE))
hb_ot_layout_lookups_substitute_closure (plan->source,
&lookup_indices,
gids_to_retain);
@@ -327,7 +361,7 @@ _generate_varstore_inner_maps (const hb_set_t& varidx_set,
{
if (varidx_set.is_empty () || subtable_count == 0) return;
- inner_maps.resize (subtable_count);
+ if (unlikely (!inner_maps.resize (subtable_count))) return;
for (unsigned idx : varidx_set)
{
uint16_t major = idx >> 16;
@@ -345,13 +379,16 @@ _get_hb_font_with_variations (const hb_subset_plan_t *plan)
hb_font_t *font = hb_font_create (plan->source);
hb_vector_t<hb_variation_t> vars;
- vars.alloc (plan->user_axes_location.get_population ());
+ if (!vars.alloc (plan->user_axes_location.get_population ())) {
+ hb_font_destroy (font);
+ return nullptr;
+ }
for (auto _ : plan->user_axes_location)
{
hb_variation_t var;
var.tag = _.first;
- var.value = _.second;
+ var.value = _.second.middle;
vars.push (var);
}
@@ -374,36 +411,20 @@ _collect_layout_variation_indices (hb_subset_plan_t* plan)
return;
}
- const OT::VariationStore *var_store = nullptr;
hb_set_t varidx_set;
- hb_font_t *font = nullptr;
- float *store_cache = nullptr;
- bool collect_delta = plan->pinned_at_default ? false : true;
- if (collect_delta)
- {
- font = _get_hb_font_with_variations (plan);
- if (gdef->has_var_store ())
- {
- var_store = &(gdef->get_var_store ());
- store_cache = var_store->create_cache ();
- }
- }
-
OT::hb_collect_variation_indices_context_t c (&varidx_set,
- &plan->layout_variation_idx_delta_map,
- font, var_store,
&plan->_glyphset_gsub,
- &plan->gpos_lookups,
- store_cache);
+ &plan->gpos_lookups);
gdef->collect_variation_indices (&c);
if (hb_ot_layout_has_positioning (plan->source))
gpos->collect_variation_indices (&c);
- hb_font_destroy (font);
- var_store->destroy_cache (store_cache);
-
- gdef->remap_layout_variation_indices (&varidx_set, &plan->layout_variation_idx_delta_map);
+ gdef->remap_layout_variation_indices (&varidx_set,
+ plan->normalized_coords,
+ !plan->pinned_at_default,
+ plan->all_axes_pinned,
+ &plan->layout_variation_idx_delta_map);
unsigned subtable_count = gdef->has_var_store () ? gdef->get_var_store ().get_sub_table_count () : 0;
_generate_varstore_inner_maps (varidx_set, subtable_count, plan->gdef_varstore_inner_maps);
@@ -411,6 +432,52 @@ _collect_layout_variation_indices (hb_subset_plan_t* plan)
gdef.destroy ();
gpos.destroy ();
}
+
+#ifndef HB_NO_BASE
+/* used by BASE table only, delta is always set to 0 in the output map */
+static inline void
+_remap_variation_indices (const hb_set_t& indices,
+ unsigned subtable_count,
+ hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>>& variation_idx_delta_map /* OUT */)
+{
+ unsigned new_major = 0, new_minor = 0;
+ unsigned last_major = (indices.get_min ()) >> 16;
+ for (unsigned idx : indices)
+ {
+ uint16_t major = idx >> 16;
+ if (major >= subtable_count) break;
+ if (major != last_major)
+ {
+ new_minor = 0;
+ ++new_major;
+ }
+
+ unsigned new_idx = (new_major << 16) + new_minor;
+ variation_idx_delta_map.set (idx, hb_pair_t<unsigned, int> (new_idx, 0));
+ ++new_minor;
+ last_major = major;
+ }
+}
+
+static inline void
+_collect_base_variation_indices (hb_subset_plan_t* plan)
+{
+ hb_blob_ptr_t<OT::BASE> base = plan->source_table<OT::BASE> ();
+ if (!base->has_var_store ())
+ {
+ base.destroy ();
+ return;
+ }
+
+ hb_set_t varidx_set;
+ base->collect_variation_indices (plan, varidx_set);
+ unsigned subtable_count = base->get_var_store ().get_sub_table_count ();
+ base.destroy ();
+
+ _remap_variation_indices (varidx_set, subtable_count, plan->base_variation_idx_map);
+ _generate_varstore_inner_maps (varidx_set, subtable_count, plan->base_varstore_inner_maps);
+}
+#endif
#endif
static inline void
@@ -456,6 +523,24 @@ _math_closure (hb_subset_plan_t *plan,
math.destroy ();
}
+static inline void
+_remap_used_mark_sets (hb_subset_plan_t *plan,
+ hb_map_t& used_mark_sets_map)
+{
+ hb_blob_ptr_t<OT::GDEF> gdef = plan->source_table<OT::GDEF> ();
+
+ if (!gdef->has_data () || !gdef->has_mark_glyph_sets ())
+ {
+ gdef.destroy ();
+ return;
+ }
+
+ hb_set_t used_mark_sets;
+ gdef->get_mark_glyph_sets ().collect_used_mark_sets (plan->_glyphset_gsub, used_mark_sets);
+ gdef.destroy ();
+
+ _remap_indexes (&used_mark_sets, &used_mark_sets_map);
+}
static inline void
_remove_invalid_gids (hb_set_t *glyphs,
@@ -538,6 +623,8 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
unicodes->get_population () < cmap_unicodes->get_population () &&
glyphs->get_population () < cmap_unicodes->get_population ())
{
+ plan->codepoint_to_glyph->alloc (unicodes->get_population () + glyphs->get_population ());
+
auto &gid_to_unicodes = plan->accelerator->gid_to_unicodes;
for (hb_codepoint_t gid : *glyphs)
{
@@ -555,31 +642,43 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
if (plan->codepoint_to_glyph->has (cp))
continue;
- hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
- plan->codepoint_to_glyph->set (cp, gid);
- plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
+ hb_codepoint_t *gid;
+ if (!unicode_glyphid_map->has(cp, &gid))
+ continue;
+
+ plan->codepoint_to_glyph->set (cp, *gid);
+ plan->unicode_to_new_gid_list.push (hb_pair (cp, *gid));
}
plan->unicode_to_new_gid_list.qsort ();
}
else
{
- for (hb_codepoint_t cp : *cmap_unicodes)
+ plan->codepoint_to_glyph->alloc (cmap_unicodes->get_population ());
+ hb_codepoint_t first = HB_SET_VALUE_INVALID, last = HB_SET_VALUE_INVALID;
+ for (; cmap_unicodes->next_range (&first, &last); )
{
- hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
- if (!unicodes->has (cp) && !glyphs->has (gid))
- continue;
+ for (unsigned cp = first; cp <= last; cp++)
+ {
+ hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
+ if (!unicodes->has (cp) && !glyphs->has (gid))
+ continue;
- plan->codepoint_to_glyph->set (cp, gid);
- plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
+ plan->codepoint_to_glyph->set (cp, gid);
+ plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
+ }
}
}
/* Add gids which where requested, but not mapped in cmap */
- for (hb_codepoint_t gid : *glyphs)
+ unsigned num_glyphs = plan->source->get_num_glyphs ();
+ hb_codepoint_t first = HB_SET_VALUE_INVALID, last = HB_SET_VALUE_INVALID;
+ for (; glyphs->next_range (&first, &last); )
{
- if (gid >= plan->source->get_num_glyphs ())
+ if (first >= num_glyphs)
break;
- plan->_glyphset_gsub.add (gid);
+ if (last >= num_glyphs)
+ last = num_glyphs - 1;
+ plan->_glyphset_gsub.add_range (first, last);
}
}
@@ -602,14 +701,17 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
int operation_count,
unsigned depth = 0)
{
- if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count;
- if (unlikely (--operation_count < 0)) return operation_count;
/* Check if is already visited */
if (gids_to_retain->has (gid)) return operation_count;
gids_to_retain->add (gid);
- for (auto item : glyf.glyph_for_gid (gid).get_composite_iterator ())
+ if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count;
+ if (unlikely (--operation_count < 0)) return operation_count;
+
+ auto glyph = glyf.glyph_for_gid (gid);
+
+ for (auto &item : glyph.get_composite_iterator ())
operation_count =
_glyf_add_gid_and_children (glyf,
item.get_gid (),
@@ -617,16 +719,64 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
operation_count,
depth);
+#ifndef HB_NO_VAR_COMPOSITES
+ for (auto &item : glyph.get_var_composite_iterator ())
+ {
+ operation_count =
+ _glyf_add_gid_and_children (glyf,
+ item.get_gid (),
+ gids_to_retain,
+ operation_count,
+ depth);
+ }
+#endif
+
return operation_count;
}
static void
+_nameid_closure (hb_subset_plan_t* plan,
+ hb_set_t* drop_tables)
+{
+#ifndef HB_NO_STYLE
+ plan->source->table.STAT->collect_name_ids (&plan->user_axes_location, &plan->name_ids);
+#endif
+#ifndef HB_NO_VAR
+ if (!plan->all_axes_pinned)
+ plan->source->table.fvar->collect_name_ids (&plan->user_axes_location, &plan->axes_old_index_tag_map, &plan->name_ids);
+#endif
+#ifndef HB_NO_COLOR
+ if (!drop_tables->has (HB_OT_TAG_CPAL))
+ plan->source->table.CPAL->collect_name_ids (&plan->colr_palettes, &plan->name_ids);
+#endif
+
+#ifndef HB_NO_SUBSET_LAYOUT
+ if (!drop_tables->has (HB_OT_TAG_GPOS))
+ {
+ hb_blob_ptr_t<GPOS> gpos = plan->source_table<GPOS> ();
+ gpos->collect_name_ids (&plan->gpos_features, &plan->name_ids);
+ gpos.destroy ();
+ }
+ if (!drop_tables->has (HB_OT_TAG_GSUB))
+ {
+ hb_blob_ptr_t<GSUB> gsub = plan->source_table<GSUB> ();
+ gsub->collect_name_ids (&plan->gsub_features, &plan->name_ids);
+ gsub.destroy ();
+ }
+#endif
+}
+
+static void
_populate_gids_to_retain (hb_subset_plan_t* plan,
hb_set_t* drop_tables)
{
OT::glyf_accelerator_t glyf (plan->source);
#ifndef HB_NO_SUBSET_CFF
- OT::cff1::accelerator_t cff (plan->source);
+ // Note: we cannot use inprogress_accelerator here, since it has not been
+ // created yet. So in case of preprocessed-face (and otherwise), we do an
+ // extra sanitize pass here, which is not ideal.
+ OT::cff1::accelerator_subset_t stack_cff (plan->accelerator ? nullptr : plan->source);
+ const OT::cff1::accelerator_subset_t *cff (plan->accelerator ? plan->accelerator->cff1_accel.get () : &stack_cff);
#endif
plan->_glyphset_gsub.add (0); // Not-def
@@ -643,7 +793,9 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
&plan->gsub_features,
&plan->gsub_langsys,
&plan->gsub_feature_record_cond_idx_map,
- &plan->gsub_feature_substitutes_map);
+ &plan->gsub_feature_substitutes_map,
+ plan->gsub_old_features,
+ plan->gsub_old_feature_idx_tag_map);
if (!drop_tables->has (HB_OT_TAG_GPOS))
_closure_glyphs_lookups_features<GPOS> (
@@ -653,7 +805,9 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
&plan->gpos_features,
&plan->gpos_langsys,
&plan->gpos_feature_record_cond_idx_map,
- &plan->gpos_feature_substitutes_map);
+ &plan->gpos_feature_substitutes_map,
+ plan->gpos_old_features,
+ plan->gpos_old_feature_idx_tag_map);
#endif
_remove_invalid_gids (&plan->_glyphset_gsub, plan->source->get_num_glyphs ());
@@ -673,6 +827,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
plan->_glyphset_colred = cur_glyphset;
+ _nameid_closure (plan, drop_tables);
/* Populate a full set of glyphs to retain by adding all referenced
* composite glyphs. */
if (glyf.has_data ())
@@ -685,9 +840,9 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
if (!plan->accelerator || plan->accelerator->has_seac)
{
bool has_seac = false;
- if (cff.is_valid ())
+ if (cff->is_valid ())
for (hb_codepoint_t gid : cur_glyphset)
- if (_add_cff_seac_components (cff, gid, &plan->_glyphset))
+ if (_add_cff_seac_components (*cff, gid, &plan->_glyphset))
has_seac = true;
plan->has_seac = has_seac;
}
@@ -695,7 +850,6 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
_remove_invalid_gids (&plan->_glyphset, plan->source->get_num_glyphs ());
-
#ifndef HB_NO_VAR
if (!drop_tables->has (HB_OT_TAG_GDEF))
_collect_layout_variation_indices (plan);
@@ -707,41 +861,90 @@ _create_glyph_map_gsub (const hb_set_t* glyph_set_gsub,
const hb_map_t* glyph_map,
hb_map_t* out)
{
+ out->alloc (glyph_set_gsub->get_population ());
+ hb_iter (glyph_set_gsub)
| hb_map ([&] (hb_codepoint_t gid) {
- return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid,
- glyph_map->get (gid));
+ return hb_codepoint_pair_t (gid, glyph_map->get (gid));
})
| hb_sink (out)
;
}
-static void
+static bool
_create_old_gid_to_new_gid_map (const hb_face_t *face,
bool retain_gids,
const hb_set_t *all_gids_to_retain,
+ const hb_map_t *requested_glyph_map,
hb_map_t *glyph_map, /* OUT */
hb_map_t *reverse_glyph_map, /* OUT */
+ hb_sorted_vector_t<hb_codepoint_pair_t> *new_to_old_gid_list /* OUT */,
unsigned int *num_glyphs /* OUT */)
{
unsigned pop = all_gids_to_retain->get_population ();
- reverse_glyph_map->resize (pop);
- glyph_map->resize (pop);
+ reverse_glyph_map->alloc (pop);
+ glyph_map->alloc (pop);
+ new_to_old_gid_list->alloc (pop);
+
+ if (*requested_glyph_map)
+ {
+ hb_set_t new_gids(requested_glyph_map->values());
+ if (new_gids.get_population() != requested_glyph_map->get_population())
+ {
+ DEBUG_MSG (SUBSET, nullptr, "The provided custom glyph mapping is not unique.");
+ return false;
+ }
+
+ if (retain_gids)
+ {
+ DEBUG_MSG (SUBSET, nullptr,
+ "HB_SUBSET_FLAGS_RETAIN_GIDS cannot be set if "
+ "a custom glyph mapping has been provided.");
+ return false;
+ }
+
+ hb_codepoint_t max_glyph = 0;
+ hb_set_t remaining;
+ for (auto old_gid : all_gids_to_retain->iter ())
+ {
+ if (old_gid == 0) {
+ new_to_old_gid_list->push (hb_pair<hb_codepoint_t, hb_codepoint_t> (0u, 0u));
+ continue;
+ }
+
+ hb_codepoint_t* new_gid;
+ if (!requested_glyph_map->has (old_gid, &new_gid))
+ {
+ remaining.add(old_gid);
+ continue;
+ }
- if (!retain_gids)
+ if (*new_gid > max_glyph)
+ max_glyph = *new_gid;
+ new_to_old_gid_list->push (hb_pair (*new_gid, old_gid));
+ }
+ new_to_old_gid_list->qsort ();
+
+ // Anything that wasn't mapped by the requested mapping should
+ // be placed after the requested mapping.
+ for (auto old_gid : remaining)
+ new_to_old_gid_list->push (hb_pair (++max_glyph, old_gid));
+
+ *num_glyphs = max_glyph + 1;
+ }
+ else if (!retain_gids)
{
+ hb_enumerate (hb_iter (all_gids_to_retain), (hb_codepoint_t) 0)
- | hb_sink (reverse_glyph_map)
+ | hb_sink (new_to_old_gid_list)
;
- *num_glyphs = reverse_glyph_map->get_population ();
+ *num_glyphs = new_to_old_gid_list->length;
}
else
{
+ hb_iter (all_gids_to_retain)
| hb_map ([] (hb_codepoint_t _) {
- return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (_, _);
+ return hb_codepoint_pair_t (_, _);
})
- | hb_sink (reverse_glyph_map)
+ | hb_sink (new_to_old_gid_list)
;
hb_codepoint_t max_glyph = HB_SET_VALUE_INVALID;
@@ -750,25 +953,17 @@ _create_old_gid_to_new_gid_map (const hb_face_t *face,
*num_glyphs = max_glyph + 1;
}
- + reverse_glyph_map->iter ()
- | hb_map (&hb_pair_t<hb_codepoint_t, hb_codepoint_t>::reverse)
+ reverse_glyph_map->alloc (reverse_glyph_map->get_population () + new_to_old_gid_list->length);
+ + hb_iter (new_to_old_gid_list)
+ | hb_sink (reverse_glyph_map)
+ ;
+ glyph_map->alloc (glyph_map->get_population () + new_to_old_gid_list->length);
+ + hb_iter (new_to_old_gid_list)
+ | hb_map (&hb_codepoint_pair_t::reverse)
| hb_sink (glyph_map)
;
-}
-static void
-_nameid_closure (hb_face_t *face,
- hb_set_t *nameids,
- bool all_axes_pinned,
- hb_hashmap_t<hb_tag_t, float> *user_axes_location)
-{
-#ifndef HB_NO_STYLE
- face->table.STAT->collect_name_ids (user_axes_location, nameids);
-#endif
-#ifndef HB_NO_VAR
- if (!all_axes_pinned)
- face->table.fvar->collect_name_ids (user_axes_location, nameids);
-#endif
+ return true;
}
#ifndef HB_NO_VAR
@@ -783,45 +978,181 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
bool has_avar = face->table.avar->has_data ();
const OT::SegmentMaps *seg_maps = nullptr;
+ unsigned avar_axis_count = 0;
if (has_avar)
+ {
seg_maps = face->table.avar->get_segment_maps ();
+ avar_axis_count = face->table.avar->get_axis_count();
+ }
bool axis_not_pinned = false;
unsigned old_axis_idx = 0, new_axis_idx = 0;
- unsigned int i = 0;
for (const auto& axis : axes)
{
hb_tag_t axis_tag = axis.get_axis_tag ();
plan->axes_old_index_tag_map.set (old_axis_idx, axis_tag);
- if (!plan->user_axes_location.has (axis_tag))
+ if (!plan->user_axes_location.has (axis_tag) ||
+ !plan->user_axes_location.get (axis_tag).is_point ())
{
axis_not_pinned = true;
plan->axes_index_map.set (old_axis_idx, new_axis_idx);
+ plan->axis_tags.push (axis_tag);
new_axis_idx++;
}
- else
+
+ Triple *axis_range;
+ if (plan->user_axes_location.has (axis_tag, &axis_range))
{
- int normalized_v = axis.normalize_axis_value (plan->user_axes_location.get (axis_tag));
- if (has_avar && old_axis_idx < face->table.avar->get_axis_count ())
+ plan->axes_triple_distances.set (axis_tag, axis.get_triple_distances ());
+
+ int normalized_min = axis.normalize_axis_value (axis_range->minimum);
+ int normalized_default = axis.normalize_axis_value (axis_range->middle);
+ int normalized_max = axis.normalize_axis_value (axis_range->maximum);
+
+ if (has_avar && old_axis_idx < avar_axis_count)
{
- normalized_v = seg_maps->map (normalized_v);
+ normalized_min = seg_maps->map (normalized_min);
+ normalized_default = seg_maps->map (normalized_default);
+ normalized_max = seg_maps->map (normalized_max);
}
- plan->axes_location.set (axis_tag, normalized_v);
- if (normalized_v != 0)
+ plan->axes_location.set (axis_tag, Triple (static_cast<float> (normalized_min / 16384.f),
+ static_cast<float> (normalized_default / 16384.f),
+ static_cast<float> (normalized_max / 16384.f)));
+
+ if (normalized_default != 0)
plan->pinned_at_default = false;
- plan->normalized_coords[i] = normalized_v;
+ plan->normalized_coords[old_axis_idx] = normalized_default;
}
- if (has_avar)
- seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps);
old_axis_idx++;
- i++;
+ if (has_avar && old_axis_idx < avar_axis_count)
+ seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps);
}
plan->all_axes_pinned = !axis_not_pinned;
}
+
+static void
+_update_instance_metrics_map_from_cff2 (hb_subset_plan_t *plan)
+{
+ if (!plan->normalized_coords) return;
+ OT::cff2::accelerator_t cff2 (plan->source);
+ if (!cff2.is_valid ()) return;
+
+ hb_font_t *font = _get_hb_font_with_variations (plan);
+ if (unlikely (!plan->check_success (font != nullptr)))
+ {
+ hb_font_destroy (font);
+ return;
+ }
+
+ hb_glyph_extents_t extents = {0x7FFF, -0x7FFF};
+ OT::hmtx_accelerator_t _hmtx (plan->source);
+ float *hvar_store_cache = nullptr;
+ if (_hmtx.has_data () && _hmtx.var_table.get_length ())
+ hvar_store_cache = _hmtx.var_table->get_var_store ().create_cache ();
+
+ OT::vmtx_accelerator_t _vmtx (plan->source);
+ float *vvar_store_cache = nullptr;
+ if (_vmtx.has_data () && _vmtx.var_table.get_length ())
+ vvar_store_cache = _vmtx.var_table->get_var_store ().create_cache ();
+
+ for (auto p : *plan->glyph_map)
+ {
+ hb_codepoint_t old_gid = p.first;
+ hb_codepoint_t new_gid = p.second;
+ if (!cff2.get_extents (font, old_gid, &extents)) continue;
+ bool has_bounds_info = true;
+ if (extents.x_bearing == 0 && extents.width == 0 &&
+ extents.height == 0 && extents.y_bearing == 0)
+ has_bounds_info = false;
+
+ if (has_bounds_info)
+ {
+ plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, extents.x_bearing);
+ plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, extents.x_bearing + extents.width);
+ plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, extents.y_bearing);
+ plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, extents.y_bearing + extents.height);
+ }
+
+ if (_hmtx.has_data ())
+ {
+ int hori_aw = _hmtx.get_advance_without_var_unscaled (old_gid);
+ if (_hmtx.var_table.get_length ())
+ hori_aw += (int) roundf (_hmtx.var_table->get_advance_delta_unscaled (old_gid, font->coords, font->num_coords,
+ hvar_store_cache));
+ int lsb = extents.x_bearing;
+ if (!has_bounds_info)
+ {
+ if (!_hmtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb))
+ continue;
+ }
+ plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb));
+ plan->bounds_width_vec[new_gid] = extents.width;
+ }
+
+ if (_vmtx.has_data ())
+ {
+ int vert_aw = _vmtx.get_advance_without_var_unscaled (old_gid);
+ if (_vmtx.var_table.get_length ())
+ vert_aw += (int) roundf (_vmtx.var_table->get_advance_delta_unscaled (old_gid, font->coords, font->num_coords,
+ vvar_store_cache));
+
+ int tsb = extents.y_bearing;
+ if (!has_bounds_info)
+ {
+ if (!_vmtx.get_leading_bearing_without_var_unscaled (old_gid, &tsb))
+ continue;
+ }
+ plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb));
+ plan->bounds_height_vec[new_gid] = extents.height;
+ }
+ }
+ hb_font_destroy (font);
+ if (hvar_store_cache)
+ _hmtx.var_table->get_var_store ().destroy_cache (hvar_store_cache);
+ if (vvar_store_cache)
+ _vmtx.var_table->get_var_store ().destroy_cache (vvar_store_cache);
+}
+
+static bool
+_get_instance_glyphs_contour_points (hb_subset_plan_t *plan)
+{
+ /* contour_points vector only needed for updating gvar table (infer delta and
+ * iup delta optimization) during partial instancing */
+ if (plan->user_axes_location.is_empty () || plan->all_axes_pinned)
+ return true;
+
+ OT::glyf_accelerator_t glyf (plan->source);
+
+ for (auto &_ : plan->new_to_old_gid_list)
+ {
+ hb_codepoint_t new_gid = _.first;
+ contour_point_vector_t all_points;
+ if (new_gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
+ {
+ if (unlikely (!plan->new_gid_contour_points_map.set (new_gid, all_points)))
+ return false;
+ continue;
+ }
+
+ hb_codepoint_t old_gid = _.second;
+ auto glyph = glyf.glyph_for_gid (old_gid);
+ if (unlikely (!glyph.get_all_points_without_var (plan->source, all_points)))
+ return false;
+ if (unlikely (!plan->new_gid_contour_points_map.set (new_gid, all_points)))
+ return false;
+
+#ifdef HB_EXPERIMENTAL_API
+ /* composite new gids are only needed by iup delta optimization */
+ if ((plan->flags & HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS) && glyph.is_composite ())
+ plan->composite_new_gids.add (new_gid);
+#endif
+ }
+ return true;
+}
#endif
hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
@@ -846,11 +1177,14 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
glyph_map = hb_map_create ();
reverse_glyph_map = hb_map_create ();
+ gsub_insert_catch_all_feature_variation_rec = false;
+ gpos_insert_catch_all_feature_variation_rec = false;
gdef_varstore_inner_maps.init ();
user_axes_location = input->axes_location;
all_axes_pinned = false;
pinned_at_default = true;
+ has_gdef_varstore = false;
#ifdef HB_EXPERIMENTAL_API
for (auto _ : input->name_table_overrides)
@@ -870,10 +1204,13 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
attach_accelerator_data = input->attach_accelerator_data;
force_long_loca = input->force_long_loca;
+#ifdef HB_EXPERIMENTAL_API
+ force_long_loca = force_long_loca || (flags & HB_SUBSET_FLAGS_IFTB_REQUIREMENTS);
+#endif
+
if (accel)
accelerator = (hb_subset_accelerator_t*) accel;
-
if (unlikely (in_error ()))
return;
@@ -884,13 +1221,20 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
_populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, this);
_populate_gids_to_retain (this, input->sets.drop_tables);
+ if (unlikely (in_error ()))
+ return;
- _create_old_gid_to_new_gid_map (face,
- input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS,
- &_glyphset,
- glyph_map,
- reverse_glyph_map,
- &_num_output_glyphs);
+ if (!check_success(_create_old_gid_to_new_gid_map(
+ face,
+ input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS,
+ &_glyphset,
+ &input->glyph_map,
+ glyph_map,
+ reverse_glyph_map,
+ &new_to_old_gid_list,
+ &_num_output_glyphs))) {
+ return;
+ }
_create_glyph_map_gsub (
&_glyphset_gsub,
@@ -905,30 +1249,71 @@ hb_subset_plan_t::hb_subset_plan_t (hb_face_t *face,
glyph_map->get(unicode_to_new_gid_list.arrayZ[i].second);
}
- _nameid_closure (face, &name_ids, all_axes_pinned, &user_axes_location);
+ bounds_width_vec.resize (_num_output_glyphs, false);
+ for (auto &v : bounds_width_vec)
+ v = 0xFFFFFFFF;
+ bounds_height_vec.resize (_num_output_glyphs, false);
+ for (auto &v : bounds_height_vec)
+ v = 0xFFFFFFFF;
+
+ if (!drop_tables.has (HB_OT_TAG_GDEF))
+ _remap_used_mark_sets (this, used_mark_sets_map);
+
+#ifndef HB_NO_VAR
+#ifndef HB_NO_BASE
+ if (!drop_tables.has (HB_OT_TAG_BASE))
+ _collect_base_variation_indices (this);
+#endif
+#endif
+
if (unlikely (in_error ()))
return;
+#ifndef HB_NO_VAR
+ _update_instance_metrics_map_from_cff2 (this);
+ if (!check_success (_get_instance_glyphs_contour_points (this)))
+ return;
+#endif
+
if (attach_accelerator_data)
{
- hb_multimap_t gid_to_unicodes;
-
- hb_map_t &unicode_to_gid = *codepoint_to_glyph;
-
- for (auto unicode : unicodes)
- {
- auto gid = unicode_to_gid[unicode];
- gid_to_unicodes.add (gid, unicode);
- }
-
inprogress_accelerator =
- hb_subset_accelerator_t::create (*codepoint_to_glyph,
- gid_to_unicodes,
+ hb_subset_accelerator_t::create (source,
+ *codepoint_to_glyph,
unicodes,
has_seac);
+
+ check_success (inprogress_accelerator);
}
+
+#define HB_SUBSET_PLAN_MEMBER(Type, Name) check_success (!Name.in_error ());
+#include "hb-subset-plan-member-list.hh"
+#undef HB_SUBSET_PLAN_MEMBER
}
+hb_subset_plan_t::~hb_subset_plan_t()
+{
+ hb_face_destroy (dest);
+
+ hb_map_destroy (codepoint_to_glyph);
+ hb_map_destroy (glyph_map);
+ hb_map_destroy (reverse_glyph_map);
+#ifndef HB_NO_SUBSET_CFF
+ cff1_accel.fini ();
+ cff2_accel.fini ();
+#endif
+ hb_face_destroy (source);
+
+#ifdef HB_EXPERIMENTAL_API
+ for (auto _ : name_table_overrides.iter_ref ())
+ _.second.fini ();
+#endif
+
+ if (inprogress_accelerator)
+ hb_subset_accelerator_t::destroy ((void*) inprogress_accelerator);
+}
+
+
/**
* hb_subset_plan_create_or_fail:
* @face: font face to create the plan for.
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh
index c0a85e12dc..19a9fa6918 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset-plan.hh
@@ -67,60 +67,81 @@ struct head_maxp_info_t
typedef struct head_maxp_info_t head_maxp_info_t;
-struct hb_subset_plan_t
+struct contour_point_t
{
- HB_INTERNAL hb_subset_plan_t (hb_face_t *,
- const hb_subset_input_t *input);
+ void init (float x_ = 0.f, float y_ = 0.f, bool is_end_point_ = false)
+ { flag = 0; x = x_; y = y_; is_end_point = is_end_point_; }
- ~hb_subset_plan_t()
+ void transform (const float (&matrix)[4])
{
- hb_face_destroy (source);
- hb_face_destroy (dest);
-
- hb_map_destroy (codepoint_to_glyph);
- hb_map_destroy (glyph_map);
- hb_map_destroy (reverse_glyph_map);
-
-#ifdef HB_EXPERIMENTAL_API
- for (auto _ : name_table_overrides)
- _.second.fini ();
-#endif
+ float x_ = x * matrix[0] + y * matrix[2];
+ y = x * matrix[1] + y * matrix[3];
+ x = x_;
+ }
- if (inprogress_accelerator)
- hb_subset_accelerator_t::destroy ((void*) inprogress_accelerator);
+ void add_delta (float delta_x, float delta_y)
+ {
+ x += delta_x;
+ y += delta_y;
}
- hb_object_header_t header;
+ HB_ALWAYS_INLINE
+ void translate (const contour_point_t &p) { x += p.x; y += p.y; }
- bool successful;
- unsigned flags;
- bool attach_accelerator_data = false;
- bool force_long_loca = false;
- // For each cp that we'd like to retain maps to the corresponding gid.
- hb_set_t unicodes;
- hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> unicode_to_new_gid_list;
+ float x;
+ float y;
+ uint8_t flag;
+ bool is_end_point;
+};
- // name_ids we would like to retain
- hb_set_t name_ids;
+struct contour_point_vector_t : hb_vector_t<contour_point_t>
+{
+ void extend (const hb_array_t<contour_point_t> &a)
+ {
+ unsigned int old_len = length;
+ if (unlikely (!resize (old_len + a.length, false)))
+ return;
+ auto arrayZ = this->arrayZ + old_len;
+ unsigned count = a.length;
+ hb_memcpy (arrayZ, a.arrayZ, count * sizeof (arrayZ[0]));
+ }
- // name_languages we would like to retain
- hb_set_t name_languages;
+ bool add_deltas (const hb_vector_t<float> deltas_x,
+ const hb_vector_t<float> deltas_y,
+ const hb_vector_t<bool> indices)
+ {
+ if (indices.length != deltas_x.length ||
+ indices.length != deltas_y.length)
+ return false;
- //layout features which will be preserved
- hb_set_t layout_features;
+ for (unsigned i = 0; i < indices.length; i++)
+ {
+ if (!indices.arrayZ[i]) continue;
+ arrayZ[i].add_delta (deltas_x.arrayZ[i], deltas_y.arrayZ[i]);
+ }
+ return true;
+ }
+};
- // layout scripts which will be preserved.
- hb_set_t layout_scripts;
+namespace OT {
+ struct cff1_subset_accelerator_t;
+ struct cff2_subset_accelerator_t;
+}
- //glyph ids requested to retain
- hb_set_t glyphs_requested;
+struct hb_subset_plan_t
+{
+ HB_INTERNAL hb_subset_plan_t (hb_face_t *,
+ const hb_subset_input_t *input);
- // Tables which should not be processed, just pass them through.
- hb_set_t no_subset_tables;
+ HB_INTERNAL ~hb_subset_plan_t();
+
+ hb_object_header_t header;
- // Tables which should be dropped.
- hb_set_t drop_tables;
+ bool successful;
+ unsigned flags;
+ bool attach_accelerator_data = false;
+ bool force_long_loca = false;
// The glyph subset
hb_map_t *codepoint_to_glyph; // Needs to be heap-allocated
@@ -128,106 +149,68 @@ struct hb_subset_plan_t
// Old -> New glyph id mapping
hb_map_t *glyph_map; // Needs to be heap-allocated
hb_map_t *reverse_glyph_map; // Needs to be heap-allocated
- hb_map_t glyph_map_gsub;
// Plan is only good for a specific source/dest so keep them with it
hb_face_t *source;
+#ifndef HB_NO_SUBSET_CFF
+ // These have to be immediately after source:
+ hb_face_lazy_loader_t<OT::cff1_subset_accelerator_t, 1> cff1_accel;
+ hb_face_lazy_loader_t<OT::cff2_subset_accelerator_t, 2> cff2_accel;
+#endif
+
hb_face_t *dest;
unsigned int _num_output_glyphs;
- hb_set_t _glyphset;
- hb_set_t _glyphset_gsub;
- hb_set_t _glyphset_mathed;
- hb_set_t _glyphset_colred;
-
- //active lookups we'd like to retain
- hb_map_t gsub_lookups;
- hb_map_t gpos_lookups;
-
- //active langsys we'd like to retain
- hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> gsub_langsys;
- hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> gpos_langsys;
-
- //active features after removing redundant langsys and prune_features
- hb_map_t gsub_features;
- hb_map_t gpos_features;
-
- //active feature variation records/condition index with variations
- hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> gsub_feature_record_cond_idx_map;
- hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> gpos_feature_record_cond_idx_map;
-
- //feature index-> address of substituation feature table mapping with
- //variations
- hb_hashmap_t<unsigned, const OT::Feature*> gsub_feature_substitutes_map;
- hb_hashmap_t<unsigned, const OT::Feature*> gpos_feature_substitutes_map;
-
- //active layers/palettes we'd like to retain
- hb_map_t colrv1_layers;
- hb_map_t colr_palettes;
-
- //Old layout item variation index -> (New varidx, delta) mapping
- hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> layout_variation_idx_delta_map;
-
- //gdef varstore retained varidx mapping
- hb_vector_t<hb_inc_bimap_t> gdef_varstore_inner_maps;
-
- hb_hashmap_t<hb_tag_t, hb::unique_ptr<hb_blob_t>> sanitized_table_cache;
- //normalized axes location map
- hb_hashmap_t<hb_tag_t, int> axes_location;
- hb_vector_t<int> normalized_coords;
- //user specified axes location map
- hb_hashmap_t<hb_tag_t, float> user_axes_location;
- //retained old axis index -> new axis index mapping in fvar axis array
- hb_map_t axes_index_map;
- //axis_index->axis_tag mapping in fvar axis array
- hb_map_t axes_old_index_tag_map;
+
bool all_axes_pinned;
bool pinned_at_default;
bool has_seac;
- //hmtx metrics map: new gid->(advance, lsb)
- mutable hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>> hmtx_map;
- //vmtx metrics map: new gid->(advance, lsb)
- mutable hb_hashmap_t<hb_codepoint_t, hb_pair_t<unsigned, int>> vmtx_map;
- //boundsWidth map: new gid->boundsWidth, boundWidth=xMax - xMin
- mutable hb_map_t bounds_width_map;
- //boundsHeight map: new gid->boundsHeight, boundsHeight=yMax - yMin
- mutable hb_map_t bounds_height_map;
+ // whether to insert a catch-all FeatureVariationRecord
+ bool gsub_insert_catch_all_feature_variation_rec;
+ bool gpos_insert_catch_all_feature_variation_rec;
+
+ // whether GDEF ItemVariationStore is retained
+ mutable bool has_gdef_varstore;
+
+#define HB_SUBSET_PLAN_MEMBER(Type, Name) Type Name;
+#include "hb-subset-plan-member-list.hh"
+#undef HB_SUBSET_PLAN_MEMBER
//recalculated head/maxp table info after instancing
mutable head_maxp_info_t head_maxp_info;
-#ifdef HB_EXPERIMENTAL_API
- // name table overrides map: hb_ot_name_record_ids_t-> name string new value or
- // None to indicate should remove
- hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> name_table_overrides;
-#endif
-
const hb_subset_accelerator_t* accelerator;
hb_subset_accelerator_t* inprogress_accelerator;
public:
template<typename T>
- hb_blob_ptr_t<T> source_table()
+ struct source_table_loader
{
- hb_lock_t (accelerator ? &accelerator->sanitized_table_cache_lock : nullptr);
+ hb_blob_ptr_t<T> operator () (hb_subset_plan_t *plan)
+ {
+ hb_lock_t lock (plan->accelerator ? &plan->accelerator->sanitized_table_cache_lock : nullptr);
- auto *cache = accelerator ? &accelerator->sanitized_table_cache : &sanitized_table_cache;
- if (cache
- && !cache->in_error ()
- && cache->has (+T::tableTag)) {
- return hb_blob_reference (cache->get (+T::tableTag).get ());
- }
+ auto *cache = plan->accelerator ? &plan->accelerator->sanitized_table_cache : &plan->sanitized_table_cache;
+ if (cache
+ && !cache->in_error ()
+ && cache->has (+T::tableTag)) {
+ return hb_blob_reference (cache->get (+T::tableTag).get ());
+ }
- hb::unique_ptr<hb_blob_t> table_blob {hb_sanitize_context_t ().reference_table<T> (source)};
- hb_blob_t* ret = hb_blob_reference (table_blob.get ());
+ hb::unique_ptr<hb_blob_t> table_blob {hb_sanitize_context_t ().reference_table<T> (plan->source)};
+ hb_blob_t* ret = hb_blob_reference (table_blob.get ());
- if (likely (cache))
- cache->set (+T::tableTag, std::move (table_blob));
+ if (likely (cache))
+ cache->set (+T::tableTag, std::move (table_blob));
- return ret;
- }
+ return ret;
+ }
+ };
+
+ template<typename T>
+ auto source_table() HB_AUTO_RETURN (source_table_loader<T> {} (this))
bool in_error () const { return !successful; }
@@ -266,15 +249,6 @@ struct hb_subset_plan_t
return _num_output_glyphs;
}
- /*
- * Given an output gid , returns true if that glyph id is an empty
- * glyph (ie. it's a gid that we are dropping all data for).
- */
- inline bool is_empty_glyph (hb_codepoint_t gid) const
- {
- return !_glyphset.has (gid);
- }
-
inline bool new_gid_for_codepoint (hb_codepoint_t codepoint,
hb_codepoint_t *new_gid) const
{
@@ -324,4 +298,5 @@ struct hb_subset_plan_t
}
};
+
#endif /* HB_SUBSET_PLAN_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset.cc b/src/3rdparty/harfbuzz-ng/src/hb-subset.cc
index 82df3386f5..f10ef54dbd 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset.cc
@@ -48,11 +48,15 @@
#include "hb-ot-cff2-table.hh"
#include "hb-ot-vorg-table.hh"
#include "hb-ot-name-table.hh"
+#include "hb-ot-layout-base-table.hh"
#include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gpos-table.hh"
+#include "hb-ot-var-avar-table.hh"
+#include "hb-ot-var-cvar-table.hh"
#include "hb-ot-var-fvar-table.hh"
#include "hb-ot-var-gvar-table.hh"
#include "hb-ot-var-hvar-table.hh"
+#include "hb-ot-var-mvar-table.hh"
#include "hb-ot-math-table.hh"
#include "hb-ot-stat-table.hh"
#include "hb-repacker.hh"
@@ -61,6 +65,27 @@
using OT::Layout::GSUB;
using OT::Layout::GPOS;
+
+#ifndef HB_NO_SUBSET_CFF
+template<>
+struct hb_subset_plan_t::source_table_loader<const OT::cff1>
+{
+ auto operator () (hb_subset_plan_t *plan)
+ HB_AUTO_RETURN (plan->accelerator ? plan->accelerator->cff1_accel :
+ plan->inprogress_accelerator ? plan->inprogress_accelerator->cff1_accel :
+ plan->cff1_accel)
+};
+template<>
+struct hb_subset_plan_t::source_table_loader<const OT::cff2>
+{
+ auto operator () (hb_subset_plan_t *plan)
+ HB_AUTO_RETURN (plan->accelerator ? plan->accelerator->cff2_accel :
+ plan->inprogress_accelerator ? plan->inprogress_accelerator->cff2_accel :
+ plan->cff2_accel)
+};
+#endif
+
+
/**
* SECTION:hb-subset
* @title: hb-subset
@@ -95,8 +120,8 @@ static hb_tag_t known_tables[] {
HB_OT_TAG_BASE,
HB_OT_TAG_CBDT,
HB_OT_TAG_CBLC,
- HB_OT_TAG_cff1,
- HB_OT_TAG_cff2,
+ HB_OT_TAG_CFF1,
+ HB_OT_TAG_CFF2,
HB_OT_TAG_cmap,
HB_OT_TAG_COLR,
HB_OT_TAG_CPAL,
@@ -191,15 +216,36 @@ _get_table_tags (const hb_subset_plan_t* plan,
static unsigned
_plan_estimate_subset_table_size (hb_subset_plan_t *plan,
unsigned table_len,
- bool same_size)
+ hb_tag_t table_tag)
{
unsigned src_glyphs = plan->source->get_num_glyphs ();
unsigned dst_glyphs = plan->glyphset ()->get_population ();
+ unsigned bulk = 8192;
+ /* Tables that we want to allocate same space as the source table. For GSUB/GPOS it's
+ * because those are expensive to subset, so giving them more room is fine. */
+ bool same_size = table_tag == HB_OT_TAG_GSUB ||
+ table_tag == HB_OT_TAG_GPOS ||
+ table_tag == HB_OT_TAG_name;
+
+ if (plan->flags & HB_SUBSET_FLAGS_RETAIN_GIDS)
+ {
+ if (table_tag == HB_OT_TAG_CFF1)
+ {
+ /* Add some extra room for the CFF charset. */
+ bulk += src_glyphs * 16;
+ }
+ else if (table_tag == HB_OT_TAG_CFF2)
+ {
+ /* Just extra CharString offsets. */
+ bulk += src_glyphs * 4;
+ }
+ }
+
if (unlikely (!src_glyphs) || same_size)
- return 512 + table_len;
+ return bulk + table_len;
- return 512 + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs));
+ return bulk + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs));
}
/*
@@ -230,7 +276,7 @@ _try_subset (const TableType *table,
hb_vector_t<char>* buf,
hb_subset_context_t* c /* OUT */)
{
- c->serializer->start_serialize<TableType> ();
+ c->serializer->start_serialize ();
if (c->serializer->in_error ()) return false;
bool needed = table->subset (c);
@@ -261,45 +307,46 @@ _try_subset (const TableType *table,
return _try_subset (table, buf, c);
}
+template <typename T>
+static auto _do_destroy (T &t, hb_priority<1>) HB_RETURN (void, t.destroy ())
+
+template <typename T>
+static void _do_destroy (T &t, hb_priority<0>) {}
+
template<typename TableType>
static bool
_subset (hb_subset_plan_t *plan, hb_vector_t<char> &buf)
{
- hb_blob_ptr_t<TableType> source_blob = plan->source_table<TableType> ();
- const TableType *table = source_blob.get ();
+ auto &&source_blob = plan->source_table<TableType> ();
+ auto *table = source_blob.get ();
hb_tag_t tag = TableType::tableTag;
- if (!source_blob.get_blob()->data)
+ hb_blob_t *blob = source_blob.get_blob();
+ if (unlikely (!blob || !blob->data))
{
DEBUG_MSG (SUBSET, nullptr,
"OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag));
- source_blob.destroy ();
+ _do_destroy (source_blob, hb_prioritize);
return false;
}
- /* Tables that we want to allocate same space as the source table. For GSUB/GPOS it's
- * because those are expensive to subset, so giving them more room is fine. */
- bool same_size_table = TableType::tableTag == HB_OT_TAG_GSUB ||
- TableType::tableTag == HB_OT_TAG_GPOS ||
- TableType::tableTag == HB_OT_TAG_name;
-
- unsigned buf_size = _plan_estimate_subset_table_size (plan, source_blob.get_length (), same_size_table);
+ unsigned buf_size = _plan_estimate_subset_table_size (plan, blob->length, TableType::tableTag);
DEBUG_MSG (SUBSET, nullptr,
"OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size);
if (unlikely (!buf.alloc (buf_size)))
{
DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size);
- source_blob.destroy ();
+ _do_destroy (source_blob, hb_prioritize);
return false;
}
bool needed = false;
hb_serialize_context_t serializer (buf.arrayZ, buf.allocated);
{
- hb_subset_context_t c (source_blob.get_blob (), plan, &serializer, tag);
+ hb_subset_context_t c (blob, plan, &serializer, tag);
needed = _try_subset (table, &buf, &c);
}
- source_blob.destroy ();
+ _do_destroy (source_blob, hb_prioritize);
if (serializer.in_error () && !serializer.only_offset_overflow ())
{
@@ -414,7 +461,10 @@ _dependencies_satisfied (hb_subset_plan_t *plan, hb_tag_t tag,
case HB_OT_TAG_hmtx:
case HB_OT_TAG_vmtx:
case HB_OT_TAG_maxp:
+ case HB_OT_TAG_OS2:
return !plan->normalized_coords || !pending_subset_tags.has (HB_OT_TAG_glyf);
+ case HB_OT_TAG_GPOS:
+ return plan->all_axes_pinned || !pending_subset_tags.has (HB_OT_TAG_GDEF);
default:
return true;
}
@@ -454,10 +504,11 @@ _subset_table (hb_subset_plan_t *plan,
case HB_OT_TAG_CBLC: return _subset<const OT::CBLC> (plan, buf);
case HB_OT_TAG_CBDT: return true; /* skip CBDT, handled by CBLC */
case HB_OT_TAG_MATH: return _subset<const OT::MATH> (plan, buf);
+ case HB_OT_TAG_BASE: return _subset<const OT::BASE> (plan, buf);
#ifndef HB_NO_SUBSET_CFF
- case HB_OT_TAG_cff1: return _subset<const OT::cff1> (plan, buf);
- case HB_OT_TAG_cff2: return _subset<const OT::cff2> (plan, buf);
+ case HB_OT_TAG_CFF1: return _subset<const OT::cff1> (plan, buf);
+ case HB_OT_TAG_CFF2: return _subset<const OT::cff2> (plan, buf);
case HB_OT_TAG_VORG: return _subset<const OT::VORG> (plan, buf);
#endif
@@ -469,15 +520,37 @@ _subset_table (hb_subset_plan_t *plan,
case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan, buf);
case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan, buf);
#endif
+
+#ifndef HB_NO_VAR
case HB_OT_TAG_fvar:
if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag);
return _subset<const OT::fvar> (plan, buf);
+ case HB_OT_TAG_avar:
+ if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag);
+ return _subset<const OT::avar> (plan, buf);
+ case HB_OT_TAG_cvar:
+ if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag);
+ return _subset<const OT::cvar> (plan, buf);
+ case HB_OT_TAG_MVAR:
+ if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag);
+ return _subset<const OT::MVAR> (plan, buf);
+#endif
+
case HB_OT_TAG_STAT:
- /*TODO(qxliu): change the condition as we support more complex
- * instancing operation*/
- if (plan->all_axes_pinned) return _subset<const OT::STAT> (plan, buf);
+ if (!plan->user_axes_location.is_empty ()) return _subset<const OT::STAT> (plan, buf);
else return _passthrough (plan, tag);
+ case HB_TAG ('c', 'v', 't', ' '):
+#ifndef HB_NO_VAR
+ if (_is_table_present (plan->source, HB_OT_TAG_cvar) &&
+ plan->normalized_coords && !plan->pinned_at_default)
+ {
+ auto &cvar = *plan->source->table.cvar;
+ return OT::cvar::add_cvt_and_apply_deltas (plan, cvar.get_tuple_var_data (), &cvar);
+ }
+#endif
+ return _passthrough (plan, tag);
+
default:
if (plan->flags & HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED)
return _passthrough (plan, tag);
@@ -576,46 +649,49 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
offset += num_tables;
}
- hb_vector_t<char> buf;
- buf.alloc (4096 - 16);
-
-
bool success = true;
- while (!pending_subset_tags.is_empty ())
{
- if (subsetted_tags.in_error ()
- || pending_subset_tags.in_error ()) {
- success = false;
- goto end;
- }
+ // Grouping to deallocate buf before calling hb_face_reference (plan->dest).
+
+ hb_vector_t<char> buf;
+ buf.alloc (8192 - 16);
- bool made_changes = false;
- for (hb_tag_t tag : pending_subset_tags)
+ while (!pending_subset_tags.is_empty ())
{
- if (!_dependencies_satisfied (plan, tag,
- subsetted_tags,
- pending_subset_tags))
- {
- // delayed subsetting for some tables since they might have dependency on other tables
- // in some cases: e.g: during instantiating glyf tables, hmetrics/vmetrics are updated
- // and saved in subset plan, hmtx/vmtx subsetting need to use these updated metrics values
- continue;
+ if (subsetted_tags.in_error ()
+ || pending_subset_tags.in_error ()) {
+ success = false;
+ goto end;
}
- pending_subset_tags.del (tag);
- subsetted_tags.add (tag);
- made_changes = true;
-
- success = _subset_table (plan, buf, tag);
- if (unlikely (!success)) goto end;
- }
+ bool made_changes = false;
+ for (hb_tag_t tag : pending_subset_tags)
+ {
+ if (!_dependencies_satisfied (plan, tag,
+ subsetted_tags,
+ pending_subset_tags))
+ {
+ // delayed subsetting for some tables since they might have dependency on other tables
+ // in some cases: e.g: during instantiating glyf tables, hmetrics/vmetrics are updated
+ // and saved in subset plan, hmtx/vmtx subsetting need to use these updated metrics values
+ continue;
+ }
+
+ pending_subset_tags.del (tag);
+ subsetted_tags.add (tag);
+ made_changes = true;
+
+ success = _subset_table (plan, buf, tag);
+ if (unlikely (!success)) goto end;
+ }
- if (!made_changes)
- {
- DEBUG_MSG (SUBSET, nullptr, "Table dependencies unable to be satisfied. Subset failed.");
- success = false;
- goto end;
+ if (!made_changes)
+ {
+ DEBUG_MSG (SUBSET, nullptr, "Table dependencies unable to be satisfied. Subset failed.");
+ success = false;
+ goto end;
+ }
}
}
@@ -626,8 +702,3 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
end:
return success ? hb_face_reference (plan->dest) : nullptr;
}
-
-#ifndef HB_NO_VISIBILITY
-/* If NO_VISIBILITY, libharfbuzz has this. */
-#include "hb-ot-name-language-static.hh"
-#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset.h b/src/3rdparty/harfbuzz-ng/src/hb-subset.h
index c14b1b1803..73dcae4660 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-subset.h
@@ -71,6 +71,13 @@ typedef struct hb_subset_plan_t hb_subset_plan_t;
* in the final subset.
* @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in
* OS/2 will not be recalculated.
+ * @HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE: If set don't perform glyph closure on layout
+ * substitution rules (GSUB). Since: 7.2.0.
+ * @HB_SUBSET_FLAGS_IFTB_REQUIREMENTS: If set enforce requirements on the output subset
+ * to allow it to be used with incremental font transfer IFTB patches. Primarily,
+ * this forces all outline data to use long (32 bit) offsets. Since: EXPERIMENTAL
+ * @HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS: If set perform IUP delta optimization on the
+ * remaining gvar table's deltas. Since: EXPERIMENTAL
*
* List of boolean properties that can be configured on the subset input.
*
@@ -87,6 +94,11 @@ typedef enum { /*< flags >*/
HB_SUBSET_FLAGS_NOTDEF_OUTLINE = 0x00000040u,
HB_SUBSET_FLAGS_GLYPH_NAMES = 0x00000080u,
HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u,
+ HB_SUBSET_FLAGS_NO_LAYOUT_CLOSURE = 0x00000200u,
+#ifdef HB_EXPERIMENTAL_API
+ HB_SUBSET_FLAGS_IFTB_REQUIREMENTS = 0x00000400u,
+ HB_SUBSET_FLAGS_OPTIMIZE_IUP_DELTAS = 0x00000800u,
+#endif
} hb_subset_flags_t;
/**
@@ -151,6 +163,9 @@ hb_subset_input_glyph_set (hb_subset_input_t *input);
HB_EXTERN hb_set_t *
hb_subset_input_set (hb_subset_input_t *input, hb_subset_sets_t set_type);
+HB_EXTERN hb_map_t*
+hb_subset_input_old_to_new_glyph_mapping (hb_subset_input_t *input);
+
HB_EXTERN hb_subset_flags_t
hb_subset_input_get_flags (hb_subset_input_t *input);
@@ -159,6 +174,10 @@ hb_subset_input_set_flags (hb_subset_input_t *input,
unsigned value);
HB_EXTERN hb_bool_t
+hb_subset_input_pin_all_axes_to_default (hb_subset_input_t *input,
+ hb_face_t *face);
+
+HB_EXTERN hb_bool_t
hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
hb_face_t *face,
hb_tag_t axis_tag);
@@ -171,6 +190,21 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
#ifdef HB_EXPERIMENTAL_API
HB_EXTERN hb_bool_t
+hb_subset_input_get_axis_range (hb_subset_input_t *input,
+ hb_tag_t axis_tag,
+ float *axis_min_value,
+ float *axis_max_value,
+ float *axis_def_value);
+
+HB_EXTERN hb_bool_t
+hb_subset_input_set_axis_range (hb_subset_input_t *input,
+ hb_face_t *face,
+ hb_tag_t axis_tag,
+ float axis_min_value,
+ float axis_max_value,
+ float axis_def_value);
+
+HB_EXTERN hb_bool_t
hb_subset_input_override_name_table (hb_subset_input_t *input,
hb_ot_name_id_t name_id,
unsigned platform_id,
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ucd-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-ucd-table.hh
index f7d76eee18..8d3807a80f 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ucd-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ucd-table.hh
@@ -4,7 +4,7 @@
*
* ./gen-ucd-table.py ucd.nounihan.grouped.xml
*
- * on file with this description: Unicode 15.0.0
+ * on file with this description: Unicode 15.1.0
*/
#ifndef HB_UCD_TABLE_HH
@@ -1069,7 +1069,7 @@ _hb_ucd_dm2_u64_map[388] =
#ifndef HB_OPTIMIZE_SIZE
static const uint8_t
-_hb_ucd_u8[17868] =
+_hb_ucd_u8[17884] =
{
0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 9, 10, 7, 7, 7, 7, 11, 12, 13, 13, 13, 14,
@@ -1146,13 +1146,13 @@ _hb_ucd_u8[17868] =
34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,243, 34,
244, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,245, 34, 34,
- 34, 34, 34, 34, 34, 34, 34,246,122,122,122,122,122,122,122,122,
- 34, 34, 34, 34,247,122,122,122,122,122,122,122,122,122,122,122,
- 34, 34, 34, 34, 34, 34,248, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34,249,122,122,122,122,122,122,122,122,
- 250,122,251,252,122,122,122,122,122,122,122,122,122,122,122,122,
- 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,253,
+ 34, 34, 34, 34, 34, 34, 34,246, 34, 34, 34, 34,247,122,122,122,
+ 34, 34, 34, 34,248,122,122,122,122,122,122,122,122,122,122,122,
+ 34, 34, 34, 34, 34, 34,249, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34,250,122,122,122,122,122,122,122,122,
+ 251,122,252,253,122,122,122,122,122,122,122,122,122,122,122,122,
107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,254,
+ 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,255,
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2,
7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16,
@@ -1315,11 +1315,11 @@ _hb_ucd_u8[17868] =
121, 4, 4, 4, 4, 2, 2, 88, 2, 2, 2, 2, 2,120, 2, 2,
108,151, 2, 2, 2, 2, 2, 2, 67, 2,152,148,148,148,153, 44,
67, 67, 67, 67, 67, 55, 67, 67, 67, 67, 44, 44, 44, 44, 44, 44,
- 67, 67, 67, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 44, 44,
- 1, 2,154,155, 4, 4, 4, 4, 4, 67, 4, 4, 4, 4,156,157,
- 158,105,105,105,105, 43, 43, 86,159, 40, 40, 67,105,160, 63, 67,
- 36, 36, 36, 61, 57,161,162, 69, 36, 36, 36, 36, 36, 63, 40, 69,
- 44, 44, 62, 36, 36, 36, 36, 36, 67, 27, 27, 67, 67, 67, 67, 67,
+ 67, 67, 67, 44, 44, 44, 44, 44, 1, 2,154,155, 4, 4, 4, 4,
+ 4, 67, 4, 4, 4, 4,156,157,158,105,105,105,105, 43, 43, 86,
+ 159, 40, 40, 67,105,160, 63, 67, 36, 36, 36, 61, 57,161,162, 69,
+ 36, 36, 36, 36, 36, 63, 40, 69, 44, 44, 62, 36, 36, 36, 36, 36,
+ 67, 27, 27, 67, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44, 44, 55,
67, 67, 67, 67, 67, 67, 67, 92, 27, 27, 27, 27, 27, 67, 67, 67,
67, 67, 67, 67, 27, 27, 27, 27,163, 27, 27, 27, 27, 27, 27, 27,
36, 36, 83, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,164, 2,
@@ -1487,215 +1487,215 @@ _hb_ucd_u8[17868] =
44, 61, 44, 62, 62, 62, 62, 36, 62, 61, 61, 62, 62, 62, 62, 62,
62, 61, 61, 62, 36, 61, 36, 36, 36, 61, 36, 36, 62, 36, 61, 61,
36, 36, 36, 36, 36, 62, 36, 36, 62, 36, 62, 36, 36, 62, 36, 36,
- 8, 44, 44, 44, 44, 44, 44, 44, 55, 67, 67, 67, 67, 67, 67, 67,
- 27, 27, 27, 27, 27, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 44,
- 44, 44, 44, 67, 67, 67, 67, 67, 67, 92, 44, 44, 44, 44, 44, 44,
- 67, 67, 67, 67, 92, 44, 44, 44, 67, 44, 44, 44, 44, 44, 44, 44,
- 67, 67, 67, 67, 67, 25, 41, 41, 67, 67, 67, 67, 44, 44, 67, 67,
- 67, 67, 67, 92, 44, 55, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44,
- 67, 67, 67, 67, 67, 67, 67, 55, 67, 67, 67, 44, 44, 44, 44, 67,
- 67, 92, 67, 67, 67, 67, 67, 67, 79, 44, 44, 44, 44, 44, 44, 44,
- 171,171,171,171,171,171,171, 44,171,171,171,171,171,171,171, 0,
- 0, 0, 29, 21, 21, 21, 23, 21, 22, 18, 21, 25, 21, 17, 13, 13,
- 25, 25, 25, 21, 21, 9, 9, 9, 9, 22, 21, 18, 24, 16, 24, 5,
- 5, 5, 5, 22, 25, 18, 25, 0, 23, 23, 26, 21, 24, 26, 7, 20,
- 25, 1, 26, 24, 26, 25, 15, 15, 24, 15, 7, 19, 15, 21, 9, 25,
- 9, 5, 5, 25, 5, 9, 5, 7, 7, 7, 9, 8, 8, 5, 7, 5,
- 6, 6, 24, 24, 6, 24, 12, 12, 2, 2, 6, 5, 9, 21, 9, 2,
- 2, 9, 25, 9, 26, 12, 11, 11, 2, 6, 5, 21, 17, 2, 2, 26,
- 26, 23, 2, 12, 17, 12, 21, 12, 12, 21, 7, 2, 2, 7, 7, 21,
- 21, 2, 1, 1, 21, 23, 26, 26, 1, 21, 6, 7, 7, 12, 12, 7,
- 21, 7, 12, 1, 12, 6, 6, 12, 12, 26, 7, 26, 26, 7, 2, 1,
- 12, 2, 6, 2, 24, 7, 7, 6, 1, 12, 12, 10, 10, 10, 10, 12,
- 21, 6, 2, 10, 10, 2, 15, 26, 26, 2, 2, 21, 7, 10, 15, 7,
- 2, 23, 21, 26, 10, 7, 21, 15, 15, 2, 17, 7, 29, 7, 7, 22,
- 18, 2, 14, 14, 14, 7, 10, 21, 17, 21, 11, 12, 5, 2, 5, 6,
- 8, 8, 8, 24, 5, 24, 2, 24, 9, 24, 24, 2, 29, 29, 29, 1,
- 17, 17, 20, 19, 22, 20, 27, 28, 1, 29, 21, 20, 19, 21, 21, 16,
- 16, 21, 25, 22, 18, 21, 21, 29, 1, 2, 15, 6, 18, 6, 23, 2,
- 12, 11, 9, 26, 26, 9, 26, 5, 5, 26, 14, 9, 5, 14, 14, 15,
- 25, 26, 26, 22, 18, 26, 18, 25, 18, 22, 5, 12, 2, 5, 22, 21,
- 21, 22, 18, 17, 26, 6, 7, 14, 17, 22, 18, 18, 26, 14, 17, 6,
- 14, 6, 12, 24, 24, 6, 26, 15, 6, 21, 11, 21, 24, 9, 6, 9,
- 23, 26, 6, 10, 4, 4, 3, 3, 7, 25, 17, 16, 16, 22, 16, 16,
- 25, 17, 25, 2, 25, 24, 2, 15, 12, 15, 14, 2, 21, 14, 7, 15,
- 12, 17, 21, 1, 26, 10, 10, 1, 23, 15, 0, 1, 2, 3, 4, 5,
- 6, 7, 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0,
- 15, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 8, 44, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 44, 44,
+ 55, 67, 67, 67, 67, 67, 67, 67, 27, 27, 27, 27, 27, 27, 91, 67,
+ 67, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 67, 67, 67,
+ 67, 92, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 92, 44, 44, 44,
+ 67, 44, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 25, 41, 41,
+ 67, 67, 67, 67, 44, 44, 67, 67, 67, 67, 67, 92, 44, 55, 67, 67,
+ 67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 67, 55,
+ 67, 67, 67, 44, 44, 44, 44, 67, 67, 92, 67, 67, 67, 67, 67, 67,
+ 79, 44, 44, 44, 44, 44, 44, 44,171,171,171,171,171,171,171, 44,
+ 171,171,171,171,171,171,171, 0, 0, 0, 29, 21, 21, 21, 23, 21,
+ 22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21, 9, 9, 9,
+ 9, 22, 21, 18, 24, 16, 24, 5, 5, 5, 5, 22, 25, 18, 25, 0,
+ 23, 23, 26, 21, 24, 26, 7, 20, 25, 1, 26, 24, 26, 25, 15, 15,
+ 24, 15, 7, 19, 15, 21, 9, 25, 9, 5, 5, 25, 5, 9, 5, 7,
+ 7, 7, 9, 8, 8, 5, 7, 5, 6, 6, 24, 24, 6, 24, 12, 12,
+ 2, 2, 6, 5, 9, 21, 9, 2, 2, 9, 25, 9, 26, 12, 11, 11,
+ 2, 6, 5, 21, 17, 2, 2, 26, 26, 23, 2, 12, 17, 12, 21, 12,
+ 12, 21, 7, 2, 2, 7, 7, 21, 21, 2, 1, 1, 21, 23, 26, 26,
+ 1, 21, 6, 7, 7, 12, 12, 7, 21, 7, 12, 1, 12, 6, 6, 12,
+ 12, 26, 7, 26, 26, 7, 2, 1, 12, 2, 6, 2, 24, 7, 7, 6,
+ 1, 12, 12, 10, 10, 10, 10, 12, 21, 6, 2, 10, 10, 2, 15, 26,
+ 26, 2, 2, 21, 7, 10, 15, 7, 2, 23, 21, 26, 10, 7, 21, 15,
+ 15, 2, 17, 7, 29, 7, 7, 22, 18, 2, 14, 14, 14, 7, 10, 21,
+ 17, 21, 11, 12, 5, 2, 5, 6, 8, 8, 8, 24, 5, 24, 2, 24,
+ 9, 24, 24, 2, 29, 29, 29, 1, 17, 17, 20, 19, 22, 20, 27, 28,
+ 1, 29, 21, 20, 19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29,
+ 1, 2, 15, 6, 18, 6, 23, 2, 12, 11, 9, 26, 26, 9, 26, 5,
+ 5, 26, 14, 9, 5, 14, 14, 15, 25, 26, 26, 22, 18, 26, 18, 25,
+ 18, 22, 5, 12, 2, 5, 22, 21, 21, 22, 18, 17, 26, 6, 7, 14,
+ 17, 22, 18, 18, 26, 14, 17, 6, 14, 6, 12, 24, 24, 6, 26, 15,
+ 6, 21, 11, 21, 24, 9, 6, 9, 23, 26, 6, 10, 4, 4, 3, 3,
+ 7, 25, 17, 16, 16, 22, 16, 16, 25, 17, 25, 2, 25, 24, 2, 15,
+ 12, 15, 14, 2, 21, 14, 7, 15, 12, 17, 21, 1, 26, 10, 10, 1,
+ 23, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12,
+ 13, 0, 14, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19,
+ 0, 0, 0, 0, 0, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20,
+ 0, 21, 22, 23, 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 24,
- 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 35, 0, 36, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35,
- 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 40, 41, 42, 0, 43, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0,
- 0, 0, 3, 0, 0, 0, 4, 5, 6, 7, 0, 8, 9, 10, 0, 11,
- 12, 13, 14, 15, 16, 17, 16, 18, 16, 19, 16, 19, 16, 19, 0, 19,
- 16, 20, 16, 19, 21, 19, 0, 22, 23, 24, 25, 26, 27, 28, 29, 30,
- 31, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0,
- 0, 0, 0, 0, 34, 0, 0, 35, 0, 0, 36, 0, 37, 0, 0, 0,
- 38, 39, 40, 41, 42, 43, 44, 45, 46, 0, 0, 47, 0, 0, 0, 48,
- 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, 0, 52,
- 53, 0, 54, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0,
- 58, 0, 0, 59, 60, 61, 62, 63, 0, 0, 64, 65, 0, 0, 0, 66,
- 0, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 0,
- 72, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 74, 0, 0, 0,
- 0, 0, 75, 76, 0, 77, 78, 0, 0, 79, 80, 0, 81, 62, 0, 82,
- 83, 0, 0, 84, 85, 86, 0, 0, 0, 87, 0, 88, 0, 0, 51, 89,
- 51, 0, 90, 0, 91, 0, 0, 0, 80, 0, 0, 0, 92, 93, 0, 94,
- 95, 96, 97, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 98, 99, 0,
- 0, 0, 0, 0, 0,100, 0, 0, 0, 0, 0,101,102, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,103, 0, 0,104, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,105,106, 0, 0,107, 0, 0, 0, 0, 0, 0,
- 108, 0,109, 0,102, 0, 0, 0, 0, 0,110,111, 0, 0, 0, 0,
- 0, 0, 0,112, 0, 0, 0, 0, 0, 0, 0,113, 0,114, 0, 0,
- 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 8, 0, 0, 0,
- 0, 9, 10, 11, 12, 0, 0, 0, 0, 13, 0, 0, 14, 15, 0, 16,
- 0, 17, 18, 0, 0, 19, 0, 20, 21, 0, 0, 0, 0, 0, 22, 23,
- 0, 24, 25, 0, 0, 26, 0, 0, 0, 27, 0, 0, 28, 29, 30, 31,
- 0, 0, 0, 32, 33, 34, 0, 0, 33, 0, 0, 35, 33, 0, 0, 0,
- 33, 36, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 39,
- 40, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 43, 0, 44,
- 0, 0, 0, 45, 46, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 48,
- 49, 0, 0, 0, 0, 50, 0, 0, 0, 51, 0, 52, 0, 53, 0, 0,
- 0, 0, 54, 0, 0, 0, 0, 55, 0, 56, 0, 0, 0, 0, 57, 58,
- 0, 0, 0, 59, 60, 0, 0, 0, 0, 0, 0, 61, 52, 0, 62, 63,
- 0, 0, 64, 0, 0, 0, 65, 66, 0, 0, 0, 67, 0, 68, 69, 70,
- 71, 72, 1, 73, 0, 74, 75, 76, 0, 0, 77, 78, 0, 0, 0, 79,
- 0, 0, 1, 1, 0, 0, 80, 0, 0, 81, 0, 0, 0, 0, 77, 82,
- 0, 83, 0, 0, 0, 0, 0, 78, 84, 0, 85, 0, 52, 0, 1, 78,
- 0, 0, 86, 0, 0, 87, 0, 0, 0, 0, 0, 88, 57, 0, 0, 0,
- 0, 0, 0, 89, 90, 0, 0, 84, 0, 0, 33, 0, 0, 91, 0, 0,
- 0, 0, 92, 0, 0, 0, 0, 49, 0, 0, 93, 0, 0, 0, 0, 94,
- 95, 0, 0, 96, 0, 0, 97, 0, 0, 0, 98, 0, 0, 0, 99, 0,
- 0, 0, 0,100,101, 93, 0, 0,102, 0, 0, 0, 84, 0, 0,103,
- 0, 0, 0,104,105, 0, 0,106,107, 0, 0, 0, 0, 0, 0,108,
- 0, 0,109, 0, 0, 0, 0,110, 33, 0,111,112,113, 35, 0, 0,
- 114, 0, 0, 0,115, 0, 0, 0, 0, 0, 0,116, 0, 0,117, 0,
- 0, 0, 0,118, 88, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 52,
- 119, 0, 0, 0, 0,120, 0, 0,121, 0, 0, 0, 0,119, 0, 0,
- 122, 0, 0, 0, 0, 0, 0,123, 0, 0, 0,124, 0, 0, 0,125,
- 0,126, 0, 0, 0, 0,127,128,129, 0,130, 0,131, 0, 0, 0,
- 132,133,134, 0, 77, 0, 0, 0, 0, 0, 35, 0, 0, 0,135, 0,
- 0, 0,136, 0, 0,137, 0, 0,138, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 4, 4, 8, 9, 10,
- 1, 11, 12, 13, 14, 15, 16, 17, 18, 1, 1, 1, 19, 1, 0, 0,
- 20, 21, 22, 1, 23, 4, 21, 24, 25, 26, 27, 28, 29, 30, 0, 0,
- 1, 1, 31, 0, 0, 0, 32, 33, 34, 35, 1, 36, 37, 0, 0, 0,
- 0, 38, 1, 39, 14, 39, 40, 41, 42, 0, 0, 0, 43, 36, 44, 45,
- 21, 45, 46, 0, 0, 0, 19, 1, 21, 0, 0, 47, 0, 38, 48, 1,
- 1, 49, 49, 50, 0, 0, 51, 0, 0, 0, 52, 1, 0, 0, 38, 14,
- 4, 1, 1, 1, 53, 21, 43, 52, 54, 21, 35, 1, 0, 0, 0, 55,
- 0, 0, 0, 56, 57, 58, 0, 0, 0, 0, 0, 59, 0, 60, 0, 0,
- 0, 0, 61, 62, 0, 0, 63, 0, 0, 0, 64, 0, 0, 0, 65, 0,
- 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 69, 70, 0,
- 71, 72, 73, 74, 75, 76, 0, 0, 0, 77, 0, 0, 0, 78, 79, 0,
- 0, 0, 0, 47, 0, 0, 0, 49, 0, 80, 0, 0, 0, 62, 0, 0,
- 63, 0, 0, 81, 0, 0, 82, 0, 0, 0, 83, 0, 0, 19, 84, 0,
- 62, 0, 0, 0, 0, 49, 1, 85, 1, 52, 15, 86, 36, 10, 21, 87,
- 0, 55, 0, 0, 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 88, 0,
- 0, 89, 0, 0, 88, 0, 0, 0, 0, 78, 0, 0, 87, 9, 12, 4,
- 90, 8, 91, 47, 0, 58, 50, 0, 21, 1, 21, 92, 93, 1, 1, 1,
- 1, 94, 95, 96, 97, 1, 98, 58, 81, 99,100, 4, 58, 0, 0, 0,
- 0, 0, 0, 19, 50, 0, 0, 0, 0, 0, 0, 61, 0, 0,101,102,
- 0, 0,103, 0, 0, 1, 1, 50, 0, 0, 0, 38, 0, 63, 0, 0,
- 0, 0, 0, 62, 0, 0,104, 68, 61, 0, 0, 0, 78, 0, 0, 0,
- 105,106, 58, 38, 81, 0, 0, 0, 0, 0, 0,107, 1, 14, 4, 12,
- 84, 0, 0, 0, 0, 38, 87, 0, 0, 0, 0,108, 0, 0,109, 61,
- 0,110, 0, 0, 0, 1, 0, 0, 0, 0, 19, 58, 0, 0, 0, 51,
- 0,111, 14, 52,112, 41, 0, 0, 62, 0, 0, 61, 0, 0,113, 0,
- 87, 0, 0, 0, 61, 62, 0, 0, 62, 0, 89, 0, 0,113, 0, 0,
- 0, 0,114, 0, 0, 0, 78, 55, 0, 38, 1, 58, 1, 58, 0, 0,
- 63, 89, 0, 0,115, 0, 0, 0, 55, 0, 0, 0, 0,115, 0, 0,
- 0, 0, 61, 0, 0, 0, 0, 79, 0, 61, 0, 0, 0, 0, 56, 0,
- 89, 80, 0, 0, 79, 0, 0, 0, 8, 91, 0, 0, 1, 87, 0, 0,
- 116, 0, 0, 0, 0, 0, 0,117, 0,118,119,120,121, 0,104, 4,
- 122, 49, 23, 0, 0, 0, 38, 50, 38, 58, 0, 0, 1, 87, 1, 1,
- 1, 1, 39, 1, 48,105, 87, 0, 0, 0, 0, 1, 0, 0, 0,123,
- 4,122, 0, 0, 0, 1,124, 0, 0, 0, 0, 0,230,230,230,230,
- 230,232,220,220,220,220,232,216,220,220,220,220,220,202,202,220,
- 220,220,220,202,202,220,220,220, 1, 1, 1, 1, 1,220,220,220,
- 220,230,230,230,230,240,230,220,220,220,230,230,230,220,220, 0,
- 230,230,230,220,220,220,220,230,232,220,220,230,233,234,234,233,
- 234,234,233,230, 0, 0, 0,230, 0,220,230,230,230,230,220,230,
- 230,230,222,220,230,230,220,220,230,222,228,230, 10, 11, 12, 13,
- 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, 25, 0,
- 230,220, 0, 18, 30, 31, 32, 0, 0, 0, 0, 27, 28, 29, 30, 31,
- 32, 33, 34,230,230,220,220,230,220,230,230,220, 35, 0, 0, 0,
- 0, 0,230,230,230, 0, 0,230,230, 0,220,230,230,220, 0, 0,
- 0, 36, 0, 0,230,220,230,230,220,220,230,220,220,230,220,230,
- 220,230,230, 0, 0,220, 0, 0,230,230, 0,230, 0,230,230,230,
- 230,230, 0, 0, 0,220,220,220,230,220,220,220,230,230, 0,220,
- 27, 28, 29,230, 7, 0, 0, 0, 0, 9, 0, 0, 0,230,220,230,
- 230, 0, 0, 0, 0, 0,230, 0, 0, 84, 91, 0, 0, 0, 0, 9,
- 9, 0, 0, 0, 0, 0, 9, 0,103,103, 9, 0,107,107,107,107,
- 118,118, 9, 0,122,122,122,122,220,220, 0, 0, 0,220, 0,220,
- 0,216, 0, 0, 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130,
- 130,130, 0, 0,130, 0,230,230, 9, 0,230,230, 0, 0,220, 0,
- 0, 0, 0, 7, 0, 9, 9, 0, 9, 9, 0, 0, 0,230, 0, 0,
- 0,228, 0, 0, 0,222,230,220,220, 0, 0, 0,230, 0, 0,220,
- 230,220, 0,220,230,230,230, 0, 0, 0, 9, 9, 0, 0, 7, 0,
- 230, 0, 1, 1, 1, 0, 0, 0,230,234,214,220,202,230,230,230,
- 230,230,232,228,228,220,218,230,233,220,230,220,230,230, 1, 1,
- 1, 1, 1,230, 0, 1, 1,230,220,230, 1, 1, 0, 0,218,228,
- 232,222,224,224, 0, 8, 8, 0, 0, 0, 0,220,230, 0,230,230,
- 220, 0, 0,230, 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0,
- 0,230,220, 0, 0, 0,220,220, 0, 0,230,220, 0, 9, 7, 0,
- 0, 7, 9, 0, 0, 0, 9, 7, 6, 6, 0, 0, 0, 0, 1, 0,
- 0,216,216, 1, 1, 1, 0, 0, 0,226,216,216,216,216,216, 0,
- 220,220,220, 0,232,232,220,230,230,230, 7, 0, 16, 17, 17, 17,
- 17, 17, 17, 33, 17, 17, 17, 19, 17, 17, 17, 17, 20,101, 17,113,
- 129,169, 17, 27, 28, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0,
+ 0, 0, 40, 41, 42, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, 4, 5,
+ 6, 7, 0, 8, 9, 10, 0, 11, 12, 13, 14, 15, 16, 17, 16, 18,
+ 16, 19, 16, 19, 16, 19, 0, 19, 16, 20, 16, 19, 21, 19, 0, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 32, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 35,
+ 0, 0, 36, 0, 37, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45,
+ 46, 0, 0, 47, 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, 0,
+ 0, 0, 0, 50, 0, 51, 0, 52, 53, 0, 54, 0, 0, 0, 0, 0,
+ 0, 55, 56, 57, 0, 0, 0, 0, 58, 0, 0, 59, 60, 61, 62, 63,
+ 0, 0, 64, 65, 0, 0, 0, 66, 0, 0, 0, 0, 67, 0, 0, 0,
+ 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69,
+ 0, 0, 0, 70, 0, 71, 0, 0, 72, 0, 0, 73, 0, 0, 0, 0,
+ 0, 0, 0, 0, 74, 0, 0, 0, 0, 0, 75, 76, 0, 77, 78, 0,
+ 0, 79, 80, 0, 81, 62, 0, 82, 83, 0, 0, 84, 85, 86, 0, 0,
+ 0, 87, 0, 88, 0, 0, 51, 89, 51, 0, 90, 0, 91, 0, 0, 0,
+ 80, 0, 0, 0, 92, 93, 0, 94, 95, 96, 97, 0, 0, 0, 0, 0,
+ 51, 0, 0, 0, 0, 98, 99, 0, 0, 0, 0, 0, 0,100, 0, 0,
+ 0, 0, 0,101,102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,103,
+ 0, 0,104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105,106, 0,
+ 0,107, 0, 0, 0, 0, 0, 0,108, 0,109, 0,102, 0, 0, 0,
+ 0, 0,110,111, 0, 0, 0, 0, 0, 0, 0,112, 0, 0, 0, 0,
+ 0, 0, 0,113, 0,114, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
+ 5, 6, 7, 0, 8, 0, 0, 0, 0, 9, 10, 11, 12, 0, 0, 0,
+ 0, 13, 0, 0, 14, 15, 0, 16, 0, 17, 18, 0, 0, 19, 0, 20,
+ 21, 0, 0, 0, 0, 0, 22, 23, 0, 24, 25, 0, 0, 26, 0, 0,
+ 0, 27, 0, 0, 28, 29, 30, 31, 0, 0, 0, 32, 33, 34, 0, 0,
+ 33, 0, 0, 35, 33, 0, 0, 0, 33, 36, 0, 0, 0, 0, 0, 37,
+ 38, 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 41,
+ 42, 0, 0, 0, 0, 43, 0, 44, 0, 0, 0, 45, 46, 0, 0, 0,
+ 47, 0, 0, 0, 0, 0, 0, 48, 49, 0, 0, 0, 0, 50, 0, 0,
+ 0, 51, 0, 52, 0, 53, 0, 0, 0, 0, 54, 0, 0, 0, 0, 55,
+ 0, 56, 0, 0, 0, 0, 57, 58, 0, 0, 0, 59, 60, 0, 0, 0,
+ 0, 0, 0, 61, 52, 0, 62, 63, 0, 0, 64, 0, 0, 0, 65, 66,
+ 0, 0, 0, 67, 0, 68, 69, 70, 71, 72, 1, 73, 0, 74, 75, 76,
+ 0, 0, 77, 78, 0, 0, 0, 79, 0, 0, 1, 1, 0, 0, 80, 0,
+ 0, 81, 0, 0, 0, 0, 77, 82, 0, 83, 0, 0, 0, 0, 0, 78,
+ 84, 0, 85, 0, 52, 0, 1, 78, 0, 0, 86, 0, 0, 87, 0, 0,
+ 0, 0, 0, 88, 57, 0, 0, 0, 0, 0, 0, 89, 90, 0, 0, 84,
+ 0, 0, 33, 0, 0, 91, 0, 0, 0, 0, 92, 0, 0, 0, 0, 49,
+ 0, 0, 93, 0, 0, 0, 0, 94, 95, 0, 0, 96, 0, 0, 97, 0,
+ 0, 0, 98, 0, 0, 0, 99, 0, 0, 0, 0,100,101, 93, 0, 0,
+ 102, 0, 0, 0, 84, 0, 0,103, 0, 0, 0,104,105, 0, 0,106,
+ 107, 0, 0, 0, 0, 0, 0,108, 0, 0,109, 0, 0, 0, 0,110,
+ 33, 0,111,112,113, 35, 0, 0,114, 0, 0, 0,115, 0, 0, 0,
+ 0, 0, 0,116, 0, 0,117, 0, 0, 0, 0,118, 88, 0, 0, 0,
+ 0, 0, 57, 0, 0, 0, 0, 52,119, 0, 0, 0, 0,120, 0, 0,
+ 121, 0, 0, 0, 0,119, 0, 0,122, 0, 0, 0, 0, 0, 0,123,
+ 0, 0, 0,124, 0, 0, 0,125, 0,126, 0, 0, 0, 0,127,128,
+ 129, 0,130, 0,131, 0, 0, 0,132,133,134, 0, 77, 0, 0, 0,
+ 0, 0, 35, 0, 0, 0,135, 0, 0, 0,136, 0, 0,137, 0, 0,
+ 138, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 4,
+ 5, 6, 7, 4, 4, 8, 9, 10, 1, 11, 12, 13, 14, 15, 16, 17,
+ 18, 1, 1, 1, 19, 1, 0, 0, 20, 21, 22, 1, 23, 4, 21, 24,
+ 25, 26, 27, 28, 29, 30, 0, 0, 1, 1, 31, 0, 0, 0, 32, 33,
+ 34, 35, 1, 36, 37, 0, 0, 0, 0, 38, 1, 39, 14, 39, 40, 41,
+ 42, 0, 0, 0, 43, 36, 44, 45, 21, 45, 46, 0, 0, 0, 19, 1,
+ 21, 0, 0, 47, 0, 38, 48, 1, 1, 49, 49, 50, 0, 0, 51, 0,
+ 0, 0, 52, 1, 0, 0, 38, 14, 4, 1, 1, 1, 53, 21, 43, 52,
+ 54, 21, 35, 1, 0, 0, 0, 55, 0, 0, 0, 56, 57, 58, 0, 0,
+ 0, 0, 0, 59, 0, 60, 0, 0, 0, 0, 61, 62, 0, 0, 63, 0,
+ 0, 0, 64, 0, 0, 0, 65, 0, 0, 0, 66, 0, 0, 0, 67, 0,
+ 0, 0, 68, 0, 0, 69, 70, 0, 71, 72, 73, 74, 75, 76, 0, 0,
+ 0, 77, 0, 0, 0, 78, 79, 0, 0, 0, 0, 47, 0, 0, 0, 49,
+ 0, 80, 0, 0, 0, 62, 0, 0, 63, 0, 0, 81, 0, 0, 82, 0,
+ 0, 0, 83, 0, 0, 19, 84, 0, 62, 0, 0, 0, 0, 49, 1, 85,
+ 1, 52, 15, 86, 36, 10, 21, 87, 0, 55, 0, 0, 0, 0, 19, 10,
+ 1, 0, 0, 0, 0, 0, 88, 0, 0, 89, 0, 0, 88, 0, 0, 0,
+ 0, 78, 0, 0, 87, 9, 12, 4, 90, 8, 91, 47, 0, 58, 50, 0,
+ 21, 1, 21, 92, 93, 1, 1, 1, 1, 94, 95, 96, 97, 1, 98, 58,
+ 81, 99,100, 4, 58, 0, 0, 0, 0, 0, 0, 19, 50, 0, 0, 0,
+ 0, 0, 0, 61, 0, 0,101,102, 0, 0,103, 0, 0, 1, 1, 50,
+ 0, 0, 0, 38, 0, 63, 0, 0, 0, 0, 0, 62, 0, 0,104, 68,
+ 61, 0, 0, 0, 78, 0, 0, 0,105,106, 58, 38, 81, 0, 0, 0,
+ 0, 0, 0,107, 1, 14, 4, 12, 84, 0, 0, 0, 0, 38, 87, 0,
+ 0, 0, 0,108, 0, 0,109, 61, 0,110, 0, 0, 0, 1, 0, 0,
+ 0, 0, 19, 58, 0, 0, 0, 51, 0,111, 14, 52,112, 41, 0, 0,
+ 62, 0, 0, 61, 0, 0,113, 0, 87, 0, 0, 0, 61, 62, 0, 0,
+ 62, 0, 89, 0, 0,113, 0, 0, 0, 0,114, 0, 0, 0, 78, 55,
+ 0, 38, 1, 58, 1, 58, 0, 0, 63, 89, 0, 0,115, 0, 0, 0,
+ 55, 0, 0, 0, 0,115, 0, 0, 0, 0, 61, 0, 0, 0, 0, 79,
+ 0, 61, 0, 0, 0, 0, 56, 0, 89, 80, 0, 0, 79, 0, 0, 0,
+ 8, 91, 0, 0, 1, 87, 0, 0,116, 0, 0, 0, 0, 0, 0,117,
+ 0,118,119,120,121, 0,104, 4,122, 49, 23, 0, 0, 0, 38, 50,
+ 38, 58, 0, 0, 1, 87, 1, 1, 1, 1, 39, 1, 48,105, 87, 0,
+ 0, 0, 0, 1, 0, 0, 0,123, 4,122, 0, 0, 0, 1,124, 0,
+ 0, 0, 0, 0,230,230,230,230,230,232,220,220,220,220,232,216,
+ 220,220,220,220,220,202,202,220,220,220,220,202,202,220,220,220,
+ 1, 1, 1, 1, 1,220,220,220,220,230,230,230,230,240,230,220,
+ 220,220,230,230,230,220,220, 0,230,230,230,220,220,220,220,230,
+ 232,220,220,230,233,234,234,233,234,234,233,230, 0, 0, 0,230,
+ 0,220,230,230,230,230,220,230,230,230,222,220,230,230,220,220,
+ 230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20,
+ 21, 22, 0, 23, 0, 24, 25, 0,230,220, 0, 18, 30, 31, 32, 0,
+ 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34,230,230,220,220,230,
+ 220,230,230,220, 35, 0, 0, 0, 0, 0,230,230,230, 0, 0,230,
+ 230, 0,220,230,230,220, 0, 0, 0, 36, 0, 0,230,220,230,230,
+ 220,220,230,220,220,230,220,230,220,230,230, 0, 0,220, 0, 0,
+ 230,230, 0,230, 0,230,230,230,230,230, 0, 0, 0,220,220,220,
+ 230,220,220,220,230,230, 0,220, 27, 28, 29,230, 7, 0, 0, 0,
+ 0, 9, 0, 0, 0,230,220,230,230, 0, 0, 0, 0, 0,230, 0,
+ 0, 84, 91, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 9, 0,
+ 103,103, 9, 0,107,107,107,107,118,118, 9, 0,122,122,122,122,
+ 220,220, 0, 0, 0,220, 0,220, 0,216, 0, 0, 0,129,130, 0,
+ 132, 0, 0, 0, 0, 0,130,130,130,130, 0, 0,130, 0,230,230,
+ 9, 0,230,230, 0, 0,220, 0, 0, 0, 0, 7, 0, 9, 9, 0,
+ 9, 9, 0, 0, 0,230, 0, 0, 0,228, 0, 0, 0,222,230,220,
+ 220, 0, 0, 0,230, 0, 0,220,230,220, 0,220,230,230,230, 0,
+ 0, 0, 9, 9, 0, 0, 7, 0,230, 0, 1, 1, 1, 0, 0, 0,
+ 230,234,214,220,202,230,230,230,230,230,232,228,228,220,218,230,
+ 233,220,230,220,230,230, 1, 1, 1, 1, 1,230, 0, 1, 1,230,
+ 220,230, 1, 1, 0, 0,218,228,232,222,224,224, 0, 8, 8, 0,
+ 0, 0, 0,220,230, 0,230,230,220, 0, 0,230, 0, 0, 26, 0,
+ 0,220, 0,230,230, 1,220, 0, 0,230,220, 0, 0, 0,220,220,
+ 0, 0,230,220, 0, 9, 7, 0, 0, 7, 9, 0, 0, 0, 9, 7,
+ 6, 6, 0, 0, 0, 0, 1, 0, 0,216,216, 1, 1, 1, 0, 0,
+ 0,226,216,216,216,216,216, 0,220,220,220, 0,232,232,220,230,
+ 230,230, 7, 0, 16, 17, 17, 17, 17, 17, 17, 33, 17, 17, 17, 19,
+ 17, 17, 17, 17, 20,101, 17,113,129,169, 17, 27, 28, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,237, 0, 1, 2, 2,
- 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 6, 7, 8,
- 9, 0, 0, 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 21, 22, 0, 0, 0, 0,
- 23, 24, 25, 26, 0, 27, 0, 28, 29, 30, 31, 32, 0, 0, 0, 0,
- 0, 0, 0, 33, 34, 35, 36, 0, 0, 0, 0, 0, 37, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 1, 2, 40, 41,
- 0, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
- 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 5, 0,
- 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0,
- 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 10,
- 0, 0, 0, 0, 0, 0, 11, 12, 0, 13, 0, 14, 15, 16, 0, 0,
- 0, 0, 0, 1, 17, 18, 0, 19, 7, 1, 0, 0, 0, 20, 20, 7,
- 20, 20, 20, 20, 20, 20, 20, 8, 21, 0, 22, 0, 7, 23, 24, 0,
- 20, 20, 25, 0, 0, 0, 26, 27, 1, 7, 20, 20, 20, 20, 20, 1,
- 28, 29, 30, 31, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 10, 0,
- 0, 0, 0, 0, 0, 0, 20, 20, 20, 1, 0, 0, 8, 21, 32, 4,
- 0, 10, 0, 33, 7, 20, 20, 20, 0, 0, 0, 0, 8, 34, 34, 35,
- 36, 34, 37, 0, 38, 1, 20, 20, 0, 0, 39, 0, 1, 1, 0, 8,
- 21, 1, 20, 0, 0, 0, 1, 0, 0, 40, 1, 1, 0, 0, 8, 21,
- 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 26, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 21, 7, 20, 41, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 21, 0, 42, 43, 44, 0, 45, 0, 8, 21, 0, 0, 0, 0, 0,
- 0, 0, 0, 46, 7, 1, 10, 1, 0, 0, 0, 1, 20, 20, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 34, 9, 0, 0, 20, 20,
- 1, 20, 20, 0, 0, 0, 0, 0, 0, 0, 26, 21, 0, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 47, 48, 0, 0, 0,
- 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 9, 10, 11, 11, 11, 11, 12, 13,
- 13, 13, 13, 14, 15, 16, 17, 18, 19, 20, 21, 13, 22, 13, 13, 13,
- 13, 23, 24, 24, 25, 26, 13, 13, 13, 27, 28, 29, 13, 30, 31, 32,
- 33, 34, 35, 36, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 37, 7, 38, 39, 7, 40, 7, 7,
- 7, 41, 13, 42, 7, 7, 43, 7, 44, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17,237, 0, 1, 2, 2, 0, 3, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 5, 0, 0, 0, 0, 6, 7, 8, 9, 0, 0, 0, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20,
+ 0, 0, 21, 22, 0, 0, 0, 0, 23, 24, 25, 26, 0, 27, 0, 28,
+ 29, 30, 31, 32, 0, 0, 0, 0, 0, 0, 0, 33, 34, 35, 36, 0,
+ 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39,
+ 0, 0, 0, 0, 1, 2, 40, 41, 0, 1, 2, 2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0,
+ 0, 0, 3, 4, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 0, 0,
+ 0, 0, 7, 1, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0,
+ 0, 0, 10, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 11, 12,
+ 0, 13, 0, 14, 15, 16, 0, 0, 0, 0, 0, 1, 17, 18, 0, 19,
+ 7, 1, 0, 0, 0, 20, 20, 7, 20, 20, 20, 20, 20, 20, 20, 8,
+ 21, 0, 22, 0, 7, 23, 24, 0, 20, 20, 25, 0, 0, 0, 26, 27,
+ 1, 7, 20, 20, 20, 20, 20, 1, 28, 29, 30, 31, 0, 0, 20, 0,
+ 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 20, 20,
+ 20, 1, 0, 0, 8, 21, 32, 4, 0, 10, 0, 33, 7, 20, 20, 20,
+ 0, 0, 0, 0, 8, 34, 34, 35, 36, 34, 37, 0, 38, 1, 20, 20,
+ 0, 0, 39, 0, 1, 1, 0, 8, 21, 1, 20, 0, 0, 0, 1, 0,
+ 0, 40, 1, 1, 0, 0, 8, 21, 0, 1, 0, 1, 0, 1, 0, 0,
+ 0, 0, 26, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 7, 20, 41,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 0, 42, 43, 44, 0, 45,
+ 0, 8, 21, 0, 0, 0, 0, 0, 0, 0, 0, 46, 7, 1, 10, 1,
+ 0, 0, 0, 1, 20, 20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 26, 34, 9, 0, 0, 20, 20, 1, 20, 20, 0, 0, 0, 0, 0,
+ 0, 0, 26, 21, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3,
+ 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 9, 10, 11, 11, 11, 11, 12, 13, 13, 13, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 13, 22, 13, 13, 13, 13, 23, 24, 24, 25, 26, 13, 13,
+ 13, 27, 28, 29, 13, 30, 31, 32, 33, 34, 35, 36, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 37, 7, 38, 39, 7, 40, 7, 7, 7, 41, 13, 42, 7, 7, 43, 7,
+ 44, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
@@ -1716,201 +1716,202 @@ _hb_ucd_u8[17868] =
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 45, 0, 0, 1, 2, 2, 2, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 32, 33, 34, 35, 36, 37, 37,
- 37, 37, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
- 51, 52, 2, 2, 53, 54, 55, 56, 57, 58, 59, 59, 59, 59, 60, 59,
- 59, 59, 59, 59, 59, 59, 61, 61, 59, 59, 59, 59, 62, 63, 64, 65,
- 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 59, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 45, 0, 0, 1,
+ 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 32, 33, 34, 35, 36, 37, 37, 37, 37, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 2, 2, 53, 54, 55, 56,
+ 57, 58, 59, 59, 59, 59, 60, 59, 59, 59, 59, 59, 59, 59, 61, 61,
+ 59, 59, 59, 59, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
+ 74, 75, 76, 77, 78, 59, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 79, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 80, 80, 80, 81,
- 82, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 79, 70, 70, 70, 70, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 81, 82, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 95, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 70, 70, 97, 98, 99,100,101,101,
- 102,103,104,105,106,107,108,109,110,111, 96,112,113,114,115,116,
- 117,118,119,119,120,121,122,123,124,125,126,127,128,129,130,131,
- 132, 96,133,134,135,136,137,138,139,140,141,142,143, 96,144,145,
- 96,146,147,148,149, 96,150,151,152,153,154,155,156, 96,157,158,
- 159,160, 96,161,162,163,164,164,164,164,164,164,164,165,166,164,
- 167, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96,168,169,169,169,169,169,169,169,169,170, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,171,171,
- 171,171,172, 96, 96, 96,173,173,173,173,174,175,176,177, 96, 96,
- 96, 96,178,179,180,181,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,183,182,182,182,182,182,182,184,184,184,185,
- 186, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96,187,188,189,190,191,191,192, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,193,194,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 95, 96, 96,
96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96,195,196, 59,197,198,199,200,201,202, 96,203,204,
- 205, 59, 59,206, 59,207,208,208,208,208,208,209, 96, 96, 96, 96,
- 96, 96, 96, 96,210, 96,211,212,213, 96, 96,214, 96, 96, 96,215,
- 96, 96, 96, 96, 96,216,217,218,219, 96, 96, 96, 96, 96,220,221,
- 222, 96,223,224, 96, 96,225,226, 59,227,228, 96, 59, 59, 59, 59,
- 59, 59, 59,229,230,231,232,233, 59, 59,234,235, 59,236, 96, 96,
- 96, 96, 96, 96, 96, 96, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70,237, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70,238, 70,239, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 97, 98, 99,100,101,101,102,103,104,105,106,107,108,109,
+ 110,111, 96,112,113,114,115,116,117,118,119,119,120,121,122,123,
+ 124,125,126,127,128,129,130,131,132, 96,133,134,135,136,137,138,
+ 139,140,141,142,143, 96,144,145, 96,146,147,148,149, 96,150,151,
+ 152,153,154,155,156, 96,157,158,159,160, 96,161,162,163,164,164,
+ 164,164,164,164,164,165,166,164,167, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,168,169,169,
+ 169,169,169,169,169,169,170, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96,171,171,171,171,172, 96, 96, 96,173,173,
+ 173,173,174,175,176,177, 96, 96, 96, 96,178,179,180,181,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,183,182,182,
+ 182,182,182,182,184,184,184,185,186, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,187,188,189,
+ 190,191,191,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96,193,194, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,195,196, 59,197,
+ 198,199,200,201,202, 96,203,204,205, 59, 59,206, 59,207,208,208,
+ 208,208,208,209, 96, 96, 96, 96, 96, 96, 96, 96,210, 96,211,212,
+ 213, 96, 96,214, 96, 96, 96,215, 96, 96, 96, 96, 96,216,217,218,
+ 219, 96, 96, 96, 96, 96,220,221,222, 96,223,224, 96, 96,225,226,
+ 59,227,228, 96, 59, 59, 59, 59, 59, 59, 59,229,230,231,232,233,
+ 59, 59,234,235, 59,236, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,237, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,238, 70,239, 70,
70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70,240, 70, 70, 70, 70, 70, 70, 70, 70, 70,241, 96, 96,
- 96, 96, 96, 96, 96, 96, 70, 70, 70, 70,242, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 70, 70, 70, 70, 70, 70,243, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,244, 96, 96,
- 96, 96, 96, 96, 96, 96,245, 96,246,247, 0, 1, 2, 2, 0, 1,
- 2, 2, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 19, 19,
- 19, 19, 19, 19, 19, 0, 19, 0, 0, 0, 0, 0, 0, 0, 19, 19,
- 19, 19, 19, 0, 0, 0, 0, 0, 26, 26, 0, 0, 0, 0, 1, 1,
- 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, 2, 2,
- 9, 9, 9, 9, 0, 9, 2, 2, 2, 2, 9, 0, 9, 0, 9, 9,
- 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 2, 9, 9, 9, 9, 9, 9, 9, 55, 55, 55, 55, 55, 55, 55, 55,
- 55, 55, 55, 55, 55, 55, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 1, 1, 6, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, 4,
- 4, 2, 2, 4, 4, 4, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 14, 2, 2, 2, 2, 2, 2, 2, 2, 14, 14,
- 14, 2, 2, 2, 2, 14, 14, 14, 14, 14, 14, 2, 2, 2, 3, 3,
- 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 0, 0, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 2, 37, 37, 37,
- 37, 2, 2, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 2, 2, 2, 2, 2, 2, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 2, 2, 64, 64, 64, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
- 90, 90, 90, 90, 2, 2, 90, 90, 90, 90, 90, 90, 90, 2, 95, 95,
- 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 2, 2, 95, 2, 37, 37,
- 37, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3,
- 2, 2, 2, 2, 2, 2, 3, 3, 0, 3, 3, 3, 3, 3, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 7, 7,
- 7, 7, 0, 0, 7, 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5,
- 5, 5, 5, 2, 2, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 2,
- 5, 2, 2, 2, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 5, 2,
- 2, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2,
- 2, 2, 5, 5, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 2, 2, 11, 11, 11, 2, 11, 11, 11, 11, 11,
- 11, 2, 2, 2, 2, 11, 11, 2, 2, 11, 11, 11, 11, 11, 11, 11,
- 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 11, 11, 11, 11, 11, 2,
- 11, 11, 2, 11, 11, 2, 11, 11, 2, 2, 11, 2, 11, 11, 11, 2,
- 2, 11, 11, 11, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11,
- 11, 11, 11, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11,
- 11, 11, 11, 11, 11, 2, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 2,
- 10, 10, 2, 10, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10, 10, 10,
- 2, 10, 10, 10, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 10, 10,
- 10, 10, 2, 2, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 10,
- 10, 10, 10, 10, 10, 10, 2, 21, 21, 21, 2, 21, 21, 21, 21, 21,
- 21, 21, 21, 2, 2, 21, 21, 2, 2, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 2,
- 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 21, 21, 2,
- 2, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 21, 21, 21, 2, 2,
- 2, 2, 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, 2,
- 22, 22, 2, 22, 22, 22, 22, 22, 22, 2, 2, 2, 22, 22, 22, 2,
- 22, 22, 22, 22, 2, 2, 2, 22, 22, 2, 22, 2, 22, 22, 2, 2,
- 2, 22, 22, 2, 2, 2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
- 2, 2, 2, 2, 22, 22, 22, 2, 2, 2, 2, 2, 2, 22, 2, 2,
- 2, 2, 2, 2, 22, 22, 22, 22, 22, 2, 2, 2, 2, 2, 23, 23,
- 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 2, 23, 23, 23, 2,
- 23, 23, 23, 23, 23, 23, 23, 23, 2, 2, 23, 23, 23, 23, 23, 2,
- 23, 23, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 23, 2, 23, 23,
- 23, 2, 2, 23, 2, 2, 23, 23, 23, 23, 2, 2, 23, 23, 2, 2,
- 2, 2, 2, 2, 2, 23, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 2, 16, 16, 16, 2, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 2, 16, 16, 16, 16, 16, 2, 2, 16, 16, 16, 16, 16, 2,
- 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 16, 16, 2, 16, 16,
- 16, 16, 2, 2, 16, 16, 2, 16, 16, 16, 2, 2, 2, 2, 20, 20,
- 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 2, 20, 20, 20, 2,
- 20, 20, 20, 20, 20, 20, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20,
- 20, 20, 2, 2, 20, 20, 2, 36, 36, 36, 2, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2,
- 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 2, 36, 2, 2, 2, 2, 36, 2, 2, 2, 2, 36, 36, 36,
- 36, 36, 36, 2, 36, 2, 2, 2, 2, 2, 2, 2, 36, 36, 2, 2,
- 36, 36, 36, 2, 2, 2, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 24, 24, 24, 24, 24, 24, 24, 24, 24, 2, 2, 2, 2, 0, 24, 24,
- 24, 24, 2, 2, 2, 2, 2, 18, 18, 2, 18, 2, 18, 18, 18, 18,
- 18, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 18, 18, 2, 2, 18, 18,
- 18, 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 18, 18, 2, 18, 18,
- 2, 2, 18, 18, 18, 18, 25, 25, 25, 25, 25, 25, 25, 25, 2, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 2, 2, 2, 25, 25,
- 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 0, 0, 0, 0, 25,
- 25, 2, 2, 2, 2, 2, 33, 33, 33, 33, 33, 33, 33, 33, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 2, 8, 2, 2,
- 2, 2, 2, 8, 2, 2, 8, 8, 8, 0, 8, 8, 8, 8, 12, 12,
- 12, 12, 12, 12, 12, 12, 30, 30, 30, 30, 30, 30, 30, 30, 30, 2,
- 30, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 2, 30, 30,
- 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 30, 2, 2, 2, 30, 30,
- 2, 2, 2, 2, 2, 2, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
- 29, 29, 29, 29, 2, 2, 28, 28, 28, 28, 28, 28, 28, 28, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 2, 2, 2, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 0, 0, 0, 35, 35, 35, 2,
- 2, 2, 2, 2, 2, 2, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
- 45, 45, 45, 45, 2, 2, 2, 2, 2, 2, 2, 2, 2, 45, 44, 44,
- 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 2, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 2, 2, 2, 2, 46, 46,
- 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 2, 46, 46, 46, 2,
- 46, 46, 2, 2, 2, 2, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 2, 2, 31, 31, 2, 2, 2, 2, 2, 2, 32, 32,
- 0, 0, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, 2, 2, 2, 32, 32,
- 32, 2, 2, 2, 2, 2, 28, 28, 28, 28, 28, 28, 2, 2, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 2, 48, 48,
- 48, 48, 2, 2, 2, 2, 48, 2, 2, 2, 48, 48, 48, 48, 52, 52,
- 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 2, 2, 52, 52,
- 52, 52, 52, 2, 2, 2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 2, 2, 2, 2, 58, 58, 2, 2, 2, 2, 2, 2, 58, 58,
- 58, 2, 2, 2, 58, 58, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
- 54, 54, 2, 2, 54, 54, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
- 91, 91, 91, 91, 91, 2, 91, 91, 91, 91, 91, 2, 2, 91, 91, 91,
- 2, 2, 2, 2, 2, 2, 91, 91, 91, 91, 91, 91, 2, 2, 1, 1,
- 1, 1, 1, 1, 1, 2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
- 62, 62, 62, 2, 2, 2, 62, 62, 62, 62, 62, 62, 62, 2, 76, 76,
- 76, 76, 76, 76, 76, 76, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
- 93, 93, 2, 2, 2, 2, 2, 2, 2, 2, 93, 93, 93, 93, 70, 70,
- 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 70, 70, 70, 70,
- 2, 2, 2, 70, 70, 70, 73, 73, 73, 73, 73, 73, 73, 73, 6, 2,
- 2, 2, 2, 2, 2, 2, 8, 8, 8, 2, 2, 8, 8, 8, 1, 1,
- 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0,
- 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1,
- 0, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9,
- 9, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9, 9,
- 19, 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 19, 6, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 9, 9,
- 9, 9, 9, 9, 2, 2, 2, 9, 2, 9, 2, 9, 2, 9, 9, 9,
- 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 2, 2, 9, 9, 9, 9,
- 9, 9, 2, 9, 9, 9, 2, 2, 9, 9, 9, 2, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
- 0, 0, 0, 2, 0, 0, 0, 19, 2, 2, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 2, 19, 19,
- 19, 19, 19, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0,
- 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 19, 0,
- 0, 0, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 27, 27,
- 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0,
- 0, 0, 0, 0, 2, 0, 56, 56, 56, 56, 56, 56, 56, 56, 55, 55,
- 55, 55, 2, 2, 2, 2, 2, 55, 55, 55, 55, 55, 55, 55, 61, 61,
- 61, 61, 61, 61, 61, 61, 2, 2, 2, 2, 2, 2, 2, 61, 61, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 2, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 2, 2, 0, 0,
- 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 13, 0, 13, 0, 13,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,240, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70,241, 70, 70, 70, 70,242, 96, 96, 96, 70, 70,
+ 70, 70,243, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
+ 70, 70, 70, 70,244, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70,245, 96, 96, 96, 96, 96, 96, 96, 96,246, 96,
+ 247,248, 0, 1, 2, 2, 0, 1, 2, 2, 2, 3, 4, 5, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0,
+ 19, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 0, 19, 0,
+ 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0,
+ 26, 26, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9,
+ 9, 9, 0, 9, 9, 9, 2, 2, 9, 9, 9, 9, 0, 9, 2, 2,
+ 2, 2, 9, 0, 9, 0, 9, 9, 9, 2, 9, 2, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9,
+ 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 6, 2, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 2, 4, 4, 4, 2, 2, 4, 4, 4, 2, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 2,
+ 2, 2, 2, 2, 2, 2, 14, 14, 14, 2, 2, 2, 2, 14, 14, 14,
+ 14, 14, 14, 2, 2, 2, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3,
+ 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 3,
+ 3, 3, 3, 3, 3, 3, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 2, 37, 37, 37, 37, 2, 2, 37, 37, 37, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38, 2, 2, 2, 2, 2, 2, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 2, 2, 64, 64, 64, 90, 90,
+ 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 2, 2, 90, 90,
+ 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+ 95, 95, 2, 2, 95, 2, 37, 37, 37, 2, 2, 2, 2, 2, 3, 3,
+ 3, 3, 3, 3, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3,
+ 0, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1,
+ 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7, 5, 5,
+ 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 2,
+ 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2,
+ 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2, 5, 5, 5, 5,
+ 2, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 2, 2, 2,
+ 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 5, 5, 2, 5, 5, 5,
+ 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 11,
+ 11, 11, 2, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 11, 11, 2,
+ 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2,
+ 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11, 11, 2, 11, 11,
+ 2, 2, 11, 2, 11, 11, 11, 2, 2, 11, 11, 11, 2, 2, 2, 11,
+ 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, 2, 11, 2, 2, 2,
+ 2, 2, 2, 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 10,
+ 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10,
+ 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2,
+ 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10, 10, 10, 10, 10,
+ 2, 2, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, 2, 2, 10, 2,
+ 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10,
+ 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 2, 21,
+ 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2,
+ 2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2,
+ 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 2, 21, 21, 21, 21, 21,
+ 2, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 2, 2, 2, 2,
+ 2, 2, 2, 21, 21, 21, 2, 2, 2, 2, 21, 21, 2, 21, 21, 21,
+ 21, 21, 2, 2, 21, 21, 2, 2, 22, 22, 2, 22, 22, 22, 22, 22,
+ 22, 2, 2, 2, 22, 22, 22, 2, 22, 22, 22, 22, 2, 2, 2, 22,
+ 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, 22, 2, 2, 2, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 2, 2, 2, 2, 22, 22, 22, 2,
+ 2, 2, 2, 2, 2, 22, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22,
+ 22, 2, 2, 2, 2, 2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 2, 23, 23, 23, 2, 23, 23, 23, 23, 23, 23, 23, 23,
+ 2, 2, 23, 23, 23, 23, 23, 2, 23, 23, 23, 23, 2, 2, 2, 2,
+ 2, 2, 2, 23, 23, 2, 23, 23, 23, 2, 2, 23, 2, 2, 23, 23,
+ 23, 23, 2, 2, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 2,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 16,
+ 2, 2, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 2, 2, 2, 2,
+ 2, 2, 2, 16, 16, 2, 16, 16, 16, 16, 2, 2, 16, 16, 2, 16,
+ 16, 16, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 2, 20, 20, 20, 2, 20, 20, 20, 20, 20, 20, 2, 2,
+ 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 2, 2, 20, 20, 2, 36,
+ 36, 36, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 2, 2, 2, 36, 36, 36, 36, 36, 36, 36, 36,
+ 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2, 2,
+ 36, 2, 2, 2, 2, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2,
+ 2, 2, 2, 2, 36, 36, 2, 2, 36, 36, 36, 2, 2, 2, 2, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 2, 2, 2, 2, 0, 24, 24, 24, 24, 2, 2, 2, 2, 2, 18,
+ 18, 2, 18, 2, 18, 18, 18, 18, 18, 2, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, 18,
+ 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18,
+ 18, 18, 18, 18, 18, 2, 18, 18, 2, 2, 18, 18, 18, 18, 25, 25,
+ 25, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 2, 2, 2, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25,
+ 25, 25, 25, 0, 0, 0, 0, 25, 25, 2, 2, 2, 2, 2, 33, 33,
+ 33, 33, 33, 33, 33, 33, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 2, 8, 2, 2, 2, 2, 2, 8, 2, 2, 8, 8,
+ 8, 0, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30,
+ 30, 30, 30, 30, 30, 2, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30,
+ 30, 30, 30, 2, 2, 2, 30, 30, 2, 2, 2, 2, 2, 2, 29, 29,
+ 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 2, 2, 28, 28,
+ 28, 28, 28, 28, 28, 28, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 2, 2, 2, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 0, 0, 0, 35, 35, 35, 2, 2, 2, 2, 2, 2, 2, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 45, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 0, 0, 2, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 2, 2, 2, 2, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+ 46, 46, 46, 2, 46, 46, 46, 2, 46, 46, 2, 2, 2, 2, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 2, 2, 31, 31,
+ 2, 2, 2, 2, 2, 2, 32, 32, 0, 0, 32, 0, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 2, 2, 2, 2, 2, 2, 32, 2,
+ 2, 2, 2, 2, 2, 2, 32, 32, 32, 2, 2, 2, 2, 2, 28, 28,
+ 28, 28, 28, 28, 2, 2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 2, 48, 48, 48, 48, 2, 2, 2, 2, 48, 2,
+ 2, 2, 48, 48, 48, 48, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 2, 2, 52, 52, 52, 52, 52, 2, 2, 2, 58, 58,
+ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 2, 2, 2, 2, 58, 58,
+ 2, 2, 2, 2, 2, 2, 58, 58, 58, 2, 2, 2, 58, 58, 54, 54,
+ 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 2, 2, 54, 54, 91, 91,
+ 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 2, 91, 91,
+ 91, 91, 91, 2, 2, 91, 91, 91, 2, 2, 2, 2, 2, 2, 91, 91,
+ 91, 91, 91, 91, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 62, 62,
+ 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 2, 2, 2, 62, 62,
+ 62, 62, 62, 62, 62, 2, 76, 76, 76, 76, 76, 76, 76, 76, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 2, 2, 2, 2, 2, 2,
+ 2, 2, 93, 93, 93, 93, 70, 70, 70, 70, 70, 70, 70, 70, 2, 2,
+ 2, 70, 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 73, 73,
+ 73, 73, 73, 73, 73, 73, 6, 2, 2, 2, 2, 2, 2, 2, 8, 8,
+ 8, 2, 2, 8, 8, 8, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0,
+ 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 1, 0, 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 19, 19,
+ 19, 19, 19, 19, 9, 9, 9, 9, 9, 6, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 9, 9, 9, 9,
+ 9, 19, 19, 19, 19, 19, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 9, 9, 9, 9, 9, 9, 9, 2, 2, 2, 9,
+ 2, 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9,
+ 9, 9, 2, 2, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 2, 2,
+ 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0,
+ 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 19,
+ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0,
+ 0, 0, 0, 0, 0, 2, 19, 19, 19, 19, 19, 2, 2, 2, 0, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0,
+ 0, 0, 0, 0, 9, 0, 0, 0, 19, 19, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 19, 0, 19, 0, 0, 0, 2, 2, 2, 2, 0, 0,
+ 0, 2, 2, 2, 2, 2, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0,
+ 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 56, 56,
+ 56, 56, 56, 56, 56, 56, 55, 55, 55, 55, 2, 2, 2, 2, 2, 55,
+ 55, 55, 55, 55, 55, 55, 61, 61, 61, 61, 61, 61, 61, 61, 2, 2,
+ 2, 2, 2, 2, 2, 61, 61, 2, 2, 2, 2, 2, 2, 2, 0, 0,
+ 0, 0, 0, 0, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 13, 13,
+ 13, 13, 13, 13, 2, 2, 0, 0, 0, 0, 0, 13, 0, 13, 0, 13,
13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, 13, 13,
13, 13, 0, 0, 0, 0, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 1,
1, 0, 0, 15, 15, 15, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 17, 17, 17, 2, 2,
2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 0, 0,
+ 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 12, 12,
12, 12, 12, 12, 12, 0, 17, 17, 17, 17, 17, 17, 17, 0, 39, 39,
39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 2, 2, 2, 39, 39,
39, 39, 39, 39, 39, 2, 86, 86, 86, 86, 86, 86, 86, 86, 77, 77,
@@ -2190,7 +2191,7 @@ _hb_ucd_u8[17868] =
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
};
static const uint16_t
-_hb_ucd_u16[9320] =
+_hb_ucd_u16[9344] =
{
0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12,
13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23,
@@ -2233,9 +2234,9 @@ _hb_ucd_u16[9320] =
209, 306, 209, 209, 209, 209, 209, 209, 9, 9, 9, 11, 11, 11, 307, 308,
13, 13, 13, 13, 13, 13, 309, 310, 11, 11, 311, 48, 48, 48, 312, 313,
48, 314, 315, 315, 315, 315, 32, 32, 316, 317, 318, 319, 320, 321, 140, 140,
- 209, 322, 209, 209, 209, 209, 209, 323, 209, 209, 209, 209, 209, 324, 140, 325,
- 326, 327, 328, 329, 136, 48, 48, 48, 48, 330, 178, 48, 48, 48, 48, 331,
- 332, 48, 48, 136, 48, 48, 48, 48, 200, 333, 48, 48, 209, 209, 323, 48,
+ 209, 322, 209, 209, 209, 209, 209, 323, 209, 209, 209, 209, 209, 324, 140, 209,
+ 325, 326, 327, 328, 136, 48, 48, 48, 48, 329, 178, 48, 48, 48, 48, 330,
+ 331, 48, 48, 136, 48, 48, 48, 48, 200, 332, 48, 48, 209, 209, 333, 48,
209, 334, 335, 209, 336, 337, 209, 209, 335, 209, 209, 337, 209, 209, 209, 209,
48, 48, 48, 48, 209, 209, 209, 209, 48, 338, 48, 48, 48, 48, 48, 48,
151, 209, 209, 209, 287, 48, 48, 229, 339, 48, 340, 140, 13, 13, 341, 342,
@@ -2306,475 +2307,476 @@ _hb_ucd_u16[9320] =
9, 9, 607, 11, 654, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 499,
271, 271, 655, 656, 140, 140, 140, 140, 499, 271, 657, 658, 140, 140, 140, 140,
659, 48, 660, 661, 662, 663, 664, 665, 666, 206, 667, 206, 140, 140, 140, 668,
- 209, 209, 325, 209, 209, 209, 209, 209, 209, 323, 334, 669, 669, 669, 209, 324,
- 670, 209, 209, 209, 209, 209, 209, 209, 209, 209, 671, 140, 140, 140, 672, 209,
- 673, 209, 209, 325, 674, 675, 324, 140, 209, 209, 209, 209, 209, 209, 209, 676,
- 209, 209, 209, 209, 209, 677, 426, 426, 209, 209, 209, 209, 209, 209, 209, 678,
- 209, 209, 209, 209, 209, 176, 325, 427, 325, 209, 209, 209, 679, 176, 209, 209,
- 679, 209, 671, 675, 140, 140, 140, 140, 209, 209, 209, 209, 209, 323, 671, 426,
- 674, 209, 209, 680, 681, 325, 674, 674, 209, 682, 209, 209, 288, 140, 140, 192,
+ 209, 209, 669, 209, 209, 209, 209, 209, 209, 323, 334, 670, 670, 670, 209, 324,
+ 671, 209, 209, 209, 209, 209, 209, 209, 209, 209, 672, 140, 140, 140, 673, 209,
+ 674, 209, 209, 669, 675, 676, 324, 140, 209, 209, 209, 209, 209, 209, 209, 677,
+ 209, 209, 209, 209, 209, 678, 426, 426, 209, 209, 209, 209, 209, 209, 209, 679,
+ 209, 209, 209, 209, 209, 176, 669, 427, 669, 209, 209, 209, 680, 176, 209, 209,
+ 680, 209, 672, 676, 140, 140, 140, 140, 209, 209, 209, 209, 209, 323, 672, 426,
+ 675, 209, 209, 681, 682, 669, 675, 675, 209, 683, 209, 209, 288, 140, 140, 192,
48, 48, 48, 48, 48, 48, 140, 140, 48, 48, 48, 207, 48, 48, 48, 48,
48, 204, 48, 48, 48, 48, 48, 48, 48, 48, 478, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 100, 140, 48, 204, 140, 140, 140, 140, 140, 140,
- 48, 48, 48, 48, 71, 48, 48, 48, 48, 48, 48, 140, 140, 140, 140, 140,
- 683, 140, 570, 570, 570, 570, 570, 570, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 140, 391, 391, 391, 391, 391, 391, 391, 684,
- 391, 391, 391, 391, 391, 391, 391, 685, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 2, 2, 3, 1, 2, 2, 3, 0, 0, 0, 0, 0, 4, 0, 4,
- 2, 2, 5, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6,
- 0, 0, 0, 0, 7, 8, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 10, 11, 12, 13, 14, 14, 15, 14, 14, 14,
- 14, 14, 14, 14, 16, 17, 14, 14, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 18, 19, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 20, 21,
- 21, 21, 22, 20, 21, 21, 21, 21, 21, 23, 24, 25, 25, 25, 25, 25,
- 25, 26, 25, 25, 25, 27, 28, 26, 29, 30, 31, 32, 31, 31, 31, 31,
- 33, 34, 35, 31, 31, 31, 36, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 29, 31, 31, 31, 31, 37, 38, 37, 37, 37, 37, 37, 37,
- 37, 39, 31, 31, 31, 31, 31, 31, 40, 40, 40, 40, 40, 40, 41, 26,
- 42, 42, 42, 42, 42, 42, 42, 43, 44, 44, 44, 44, 44, 45, 44, 46,
- 47, 47, 47, 48, 37, 49, 31, 31, 31, 50, 51, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 52, 31, 31, 31, 53, 53, 53, 53, 53, 53, 53, 53,
- 53, 53, 54, 53, 55, 53, 53, 53, 56, 57, 58, 59, 59, 60, 61, 62,
- 57, 63, 64, 65, 66, 59, 59, 67, 68, 69, 70, 71, 71, 72, 73, 74,
- 69, 75, 76, 77, 78, 71, 79, 26, 80, 81, 82, 83, 83, 84, 85, 86,
- 81, 87, 88, 26, 89, 83, 90, 91, 92, 93, 94, 95, 95, 96, 97, 98,
- 93, 99, 100, 101, 102, 95, 95, 26, 103, 104, 105, 106, 107, 104, 108, 109,
- 104, 105, 110, 26, 111, 108, 108, 112, 113, 114, 115, 113, 113, 115, 113, 116,
- 114, 117, 118, 119, 120, 113, 121, 113, 122, 123, 124, 122, 122, 124, 125, 126,
- 123, 127, 128, 128, 129, 122, 130, 26, 131, 132, 133, 131, 131, 131, 131, 131,
- 132, 133, 134, 131, 135, 131, 131, 131, 136, 137, 138, 139, 137, 137, 140, 141,
- 138, 142, 143, 137, 144, 137, 145, 26, 146, 147, 147, 147, 147, 147, 147, 148,
- 147, 147, 147, 149, 26, 26, 26, 26, 150, 151, 152, 152, 153, 152, 152, 154,
- 155, 156, 152, 157, 26, 26, 26, 26, 158, 158, 158, 158, 158, 158, 158, 158,
- 158, 159, 158, 158, 158, 160, 159, 158, 158, 158, 158, 159, 158, 158, 158, 161,
- 158, 161, 162, 163, 26, 26, 26, 26, 164, 164, 164, 164, 164, 164, 164, 164,
- 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 165, 165, 165, 165,
- 166, 167, 165, 165, 165, 165, 165, 168, 169, 169, 169, 169, 169, 169, 169, 169,
- 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170, 170, 170, 170,
- 170, 171, 172, 171, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 171, 172,
- 171, 170, 172, 170, 170, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 170,
- 170, 170, 170, 173, 170, 170, 170, 174, 170, 170, 170, 175, 176, 176, 176, 176,
- 176, 176, 176, 176, 176, 176, 177, 177, 178, 178, 178, 178, 178, 178, 178, 178,
- 178, 178, 178, 178, 178, 178, 178, 178, 179, 179, 179, 180, 181, 181, 181, 181,
- 181, 181, 181, 181, 181, 182, 181, 183, 184, 184, 185, 186, 187, 187, 188, 26,
- 189, 189, 190, 26, 191, 192, 193, 26, 194, 194, 194, 194, 194, 194, 194, 194,
- 194, 194, 194, 195, 194, 196, 194, 196, 197, 198, 198, 199, 198, 198, 198, 198,
- 198, 198, 198, 198, 198, 198, 198, 200, 198, 198, 198, 198, 198, 201, 178, 178,
- 178, 178, 178, 178, 178, 178, 202, 26, 203, 203, 203, 204, 203, 205, 203, 205,
- 206, 203, 207, 207, 207, 208, 209, 26, 210, 210, 210, 210, 210, 211, 210, 210,
- 210, 212, 210, 213, 194, 194, 194, 194, 214, 214, 214, 215, 216, 216, 216, 216,
- 216, 216, 216, 217, 216, 216, 216, 218, 216, 219, 216, 219, 216, 220, 9, 9,
- 9, 221, 26, 26, 26, 26, 26, 26, 222, 222, 222, 222, 222, 222, 222, 222,
- 222, 223, 222, 222, 222, 222, 222, 224, 225, 225, 225, 225, 225, 225, 225, 225,
- 226, 226, 226, 226, 226, 226, 227, 228, 229, 229, 229, 229, 229, 229, 229, 230,
- 229, 231, 232, 232, 232, 232, 232, 232, 18, 233, 165, 165, 165, 165, 165, 234,
- 225, 26, 235, 9, 236, 237, 238, 239, 2, 2, 2, 2, 240, 241, 2, 2,
- 2, 2, 2, 242, 243, 244, 2, 245, 2, 2, 2, 2, 2, 2, 2, 246,
- 9, 9, 9, 9, 9, 9, 9, 9, 14, 14, 247, 247, 14, 14, 14, 14,
- 247, 247, 14, 248, 14, 14, 14, 247, 14, 14, 14, 14, 14, 14, 249, 14,
- 249, 14, 250, 251, 14, 14, 252, 253, 0, 254, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 255, 0, 256, 257, 0, 258, 2, 259, 0, 0, 0, 0,
- 260, 26, 9, 9, 9, 9, 261, 26, 0, 0, 0, 0, 262, 263, 4, 0,
- 0, 264, 0, 0, 2, 2, 2, 2, 2, 265, 0, 0, 0, 0, 0, 0,
+ 48, 48, 48, 48, 48, 48, 100, 48, 48, 48, 48, 48, 48, 204, 140, 140,
+ 48, 204, 140, 140, 140, 140, 140, 140, 48, 48, 48, 48, 71, 48, 48, 48,
+ 48, 48, 48, 140, 140, 140, 140, 140, 684, 140, 570, 570, 570, 570, 570, 570,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 140,
+ 391, 391, 391, 391, 391, 391, 391, 685, 391, 391, 391, 391, 391, 391, 391, 686,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 1, 2, 2, 3,
+ 0, 0, 0, 0, 0, 4, 0, 4, 2, 2, 5, 2, 2, 2, 5, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 6, 0, 0, 0, 0, 7, 8, 0, 0,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 11,
+ 12, 13, 14, 14, 15, 14, 14, 14, 14, 14, 14, 14, 16, 17, 14, 14,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 19, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 20, 21, 21, 21, 22, 20, 21, 21, 21, 21,
+ 21, 23, 24, 25, 25, 25, 25, 25, 25, 26, 25, 25, 25, 27, 28, 26,
+ 29, 30, 31, 32, 31, 31, 31, 31, 33, 34, 35, 31, 31, 31, 36, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 29, 31, 31, 31, 31,
+ 37, 38, 37, 37, 37, 37, 37, 37, 37, 39, 31, 31, 31, 31, 31, 31,
+ 40, 40, 40, 40, 40, 40, 41, 26, 42, 42, 42, 42, 42, 42, 42, 43,
+ 44, 44, 44, 44, 44, 45, 44, 46, 47, 47, 47, 48, 37, 49, 31, 31,
+ 31, 50, 51, 31, 31, 31, 31, 31, 31, 31, 31, 31, 52, 31, 31, 31,
+ 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 54, 53, 55, 53, 53, 53,
+ 56, 57, 58, 59, 59, 60, 61, 62, 57, 63, 64, 65, 66, 59, 59, 67,
+ 68, 69, 70, 71, 71, 72, 73, 74, 69, 75, 76, 77, 78, 71, 79, 26,
+ 80, 81, 82, 83, 83, 84, 85, 86, 81, 87, 88, 26, 89, 83, 90, 91,
+ 92, 93, 94, 95, 95, 96, 97, 98, 93, 99, 100, 101, 102, 95, 95, 26,
+ 103, 104, 105, 106, 107, 104, 108, 109, 104, 105, 110, 26, 111, 108, 108, 112,
+ 113, 114, 115, 113, 113, 115, 113, 116, 114, 117, 118, 119, 120, 113, 121, 113,
+ 122, 123, 124, 122, 122, 124, 125, 126, 123, 127, 128, 128, 129, 122, 130, 26,
+ 131, 132, 133, 131, 131, 131, 131, 131, 132, 133, 134, 131, 135, 131, 131, 131,
+ 136, 137, 138, 139, 137, 137, 140, 141, 138, 142, 143, 137, 144, 137, 145, 26,
+ 146, 147, 147, 147, 147, 147, 147, 148, 147, 147, 147, 149, 26, 26, 26, 26,
+ 150, 151, 152, 152, 153, 152, 152, 154, 155, 156, 152, 157, 26, 26, 26, 26,
+ 158, 158, 158, 158, 158, 158, 158, 158, 158, 159, 158, 158, 158, 160, 159, 158,
+ 158, 158, 158, 159, 158, 158, 158, 161, 158, 161, 162, 163, 26, 26, 26, 26,
+ 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164,
+ 164, 164, 164, 164, 165, 165, 165, 165, 166, 167, 165, 165, 165, 165, 165, 168,
+ 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169,
+ 170, 170, 170, 170, 170, 170, 170, 170, 170, 171, 172, 171, 170, 170, 170, 170,
+ 170, 171, 170, 170, 170, 170, 171, 172, 171, 170, 172, 170, 170, 170, 170, 170,
+ 170, 170, 171, 170, 170, 170, 170, 170, 170, 170, 170, 173, 170, 170, 170, 174,
+ 170, 170, 170, 175, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 177, 177,
+ 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178,
+ 179, 179, 179, 180, 181, 181, 181, 181, 181, 181, 181, 181, 181, 182, 181, 183,
+ 184, 184, 185, 186, 187, 187, 188, 26, 189, 189, 190, 26, 191, 192, 193, 26,
+ 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 195, 194, 196, 194, 196,
+ 197, 198, 198, 199, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 200,
+ 198, 198, 198, 198, 198, 201, 178, 178, 178, 178, 178, 178, 178, 178, 202, 26,
+ 203, 203, 203, 204, 203, 205, 203, 205, 206, 203, 207, 207, 207, 208, 209, 26,
+ 210, 210, 210, 210, 210, 211, 210, 210, 210, 212, 210, 213, 194, 194, 194, 194,
+ 214, 214, 214, 215, 216, 216, 216, 216, 216, 216, 216, 217, 216, 216, 216, 218,
+ 216, 219, 216, 219, 216, 220, 9, 9, 9, 221, 26, 26, 26, 26, 26, 26,
+ 222, 222, 222, 222, 222, 222, 222, 222, 222, 223, 222, 222, 222, 222, 222, 224,
+ 225, 225, 225, 225, 225, 225, 225, 225, 226, 226, 226, 226, 226, 226, 227, 228,
+ 229, 229, 229, 229, 229, 229, 229, 230, 229, 231, 232, 232, 232, 232, 232, 232,
+ 18, 233, 165, 165, 165, 165, 165, 234, 225, 26, 235, 9, 236, 237, 238, 239,
+ 2, 2, 2, 2, 240, 241, 2, 2, 2, 2, 2, 242, 243, 244, 2, 245,
+ 2, 2, 2, 2, 2, 2, 2, 246, 9, 9, 9, 9, 9, 9, 9, 9,
+ 14, 14, 247, 247, 14, 14, 14, 14, 247, 247, 14, 248, 14, 14, 14, 247,
+ 14, 14, 14, 14, 14, 14, 249, 14, 249, 14, 250, 251, 14, 14, 252, 253,
+ 0, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 256, 257,
+ 0, 258, 2, 259, 0, 0, 0, 0, 260, 26, 9, 9, 9, 9, 261, 26,
+ 0, 0, 0, 0, 262, 263, 4, 0, 0, 264, 0, 0, 2, 2, 2, 2,
+ 2, 265, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 258, 26, 26, 26,
- 0, 266, 26, 26, 0, 0, 0, 0, 267, 267, 267, 267, 267, 267, 267, 267,
- 267, 267, 267, 267, 267, 267, 267, 267, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 268, 0, 0, 0, 269, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 270, 270, 270, 270, 270, 270, 270, 270,
- 270, 270, 270, 270, 2, 2, 2, 2, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 271, 272, 165, 165, 165, 165, 166, 167, 273, 273,
- 273, 273, 273, 273, 273, 274, 275, 274, 170, 170, 172, 26, 172, 172, 172, 172,
- 172, 172, 172, 172, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 276, 26, 26, 26, 26, 277, 277, 277, 278, 277, 277, 277, 277,
- 277, 277, 277, 277, 277, 277, 279, 26, 277, 277, 277, 277, 277, 277, 277, 277,
+ 0, 0, 0, 0, 258, 26, 26, 26, 0, 266, 26, 26, 0, 0, 0, 0,
+ 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267, 267,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 268, 0,
+ 0, 0, 269, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 2, 2, 2, 2,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 271, 272,
+ 165, 165, 165, 165, 166, 167, 273, 273, 273, 273, 273, 273, 273, 274, 275, 274,
+ 170, 170, 172, 26, 172, 172, 172, 172, 172, 172, 172, 172, 18, 18, 18, 18,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 276, 26, 26, 26, 26,
+ 277, 277, 277, 278, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 279, 26,
277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
- 277, 277, 280, 26, 26, 26, 0, 281, 282, 0, 0, 0, 283, 284, 0, 285,
- 286, 287, 287, 287, 287, 287, 287, 287, 287, 287, 288, 289, 290, 291, 291, 291,
- 291, 291, 291, 291, 291, 291, 291, 292, 293, 294, 294, 294, 294, 294, 295, 169,
- 169, 169, 169, 169, 169, 169, 169, 169, 169, 296, 0, 0, 294, 294, 294, 294,
- 0, 0, 0, 0, 281, 26, 291, 291, 169, 169, 169, 296, 0, 0, 0, 0,
- 0, 0, 0, 0, 169, 169, 169, 297, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 291, 291, 291, 291, 291, 298, 291, 291, 291, 291, 291, 291, 291, 291,
- 291, 291, 291, 0, 0, 0, 0, 0, 277, 277, 277, 277, 277, 277, 277, 277,
- 0, 0, 0, 0, 0, 0, 0, 0, 299, 299, 299, 299, 299, 299, 299, 299,
- 299, 299, 299, 299, 299, 299, 299, 299, 299, 300, 299, 299, 299, 299, 299, 299,
- 301, 26, 302, 302, 302, 302, 302, 302, 303, 303, 303, 303, 303, 303, 303, 303,
- 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 304, 26, 26,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 305, 305, 305, 305,
- 305, 305, 305, 305, 305, 305, 305, 26, 0, 0, 0, 0, 306, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 307, 2, 2, 2, 2, 2, 2,
- 2, 308, 309, 310, 26, 26, 311, 2, 312, 312, 312, 312, 312, 313, 0, 314,
- 315, 315, 315, 315, 315, 315, 315, 26, 316, 316, 316, 316, 316, 316, 316, 316,
- 317, 318, 316, 319, 53, 53, 53, 53, 320, 320, 320, 320, 320, 321, 322, 322,
- 322, 322, 323, 324, 169, 169, 169, 325, 326, 326, 326, 326, 326, 326, 326, 326,
- 326, 327, 326, 328, 164, 164, 164, 329, 330, 330, 330, 330, 330, 330, 331, 26,
- 330, 332, 330, 333, 164, 164, 164, 164, 334, 334, 334, 334, 334, 334, 334, 334,
- 335, 26, 26, 336, 337, 337, 338, 26, 339, 339, 339, 26, 172, 172, 2, 2,
- 2, 2, 2, 340, 341, 342, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176,
- 337, 337, 337, 337, 337, 343, 337, 344, 169, 169, 169, 169, 345, 26, 169, 169,
- 296, 346, 169, 169, 169, 169, 169, 345, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277,
- 277, 277, 277, 277, 277, 280, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
- 277, 277, 277, 347, 26, 26, 26, 26, 348, 26, 349, 350, 25, 25, 351, 352,
- 353, 25, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 354, 26, 355, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 356,
- 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 357, 31, 31, 31, 31, 31,
- 31, 358, 26, 26, 26, 26, 31, 31, 9, 9, 0, 314, 9, 359, 0, 0,
- 0, 0, 360, 0, 258, 281, 361, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 362, 363, 0, 0, 0, 1, 2, 2, 3,
- 1, 2, 2, 3, 364, 291, 290, 291, 291, 291, 291, 365, 169, 169, 169, 296,
- 366, 366, 366, 367, 258, 258, 26, 368, 369, 370, 369, 369, 371, 369, 369, 372,
- 369, 373, 369, 373, 26, 26, 26, 26, 369, 369, 369, 369, 369, 369, 369, 369,
- 369, 369, 369, 369, 369, 369, 369, 374, 375, 0, 0, 0, 0, 0, 376, 0,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 253, 0, 377, 378, 26, 26, 26,
- 26, 26, 0, 0, 0, 0, 0, 379, 380, 380, 380, 381, 382, 382, 382, 382,
- 382, 382, 383, 26, 384, 0, 0, 281, 385, 385, 385, 385, 386, 387, 388, 388,
- 388, 389, 390, 390, 390, 390, 390, 391, 392, 392, 392, 393, 394, 394, 394, 394,
- 395, 394, 396, 26, 26, 26, 26, 26, 397, 397, 397, 397, 397, 397, 397, 397,
- 397, 397, 398, 398, 398, 398, 398, 398, 399, 399, 399, 400, 399, 401, 402, 402,
- 402, 402, 403, 402, 402, 402, 402, 403, 404, 404, 404, 404, 404, 26, 405, 405,
- 405, 405, 405, 405, 406, 407, 408, 409, 408, 409, 410, 408, 411, 408, 411, 412,
- 26, 26, 26, 26, 26, 26, 26, 26, 413, 413, 413, 413, 413, 413, 413, 413,
- 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, 414, 26,
- 413, 413, 415, 26, 413, 26, 26, 26, 416, 2, 2, 2, 2, 2, 417, 308,
- 26, 26, 26, 26, 26, 26, 26, 26, 418, 419, 420, 420, 420, 420, 421, 422,
- 423, 423, 424, 423, 425, 425, 425, 425, 426, 426, 426, 427, 428, 426, 26, 26,
- 26, 26, 26, 26, 429, 429, 430, 431, 432, 432, 432, 433, 434, 434, 434, 435,
- 26, 26, 26, 26, 26, 26, 26, 26, 436, 436, 436, 436, 437, 437, 437, 438,
- 437, 437, 439, 437, 437, 437, 437, 437, 440, 441, 442, 443, 444, 444, 445, 446,
- 444, 447, 444, 447, 448, 448, 448, 448, 449, 449, 449, 449, 26, 26, 26, 26,
- 450, 450, 450, 450, 451, 452, 451, 26, 453, 453, 453, 453, 453, 453, 454, 455,
- 456, 456, 457, 456, 458, 458, 459, 458, 460, 460, 461, 462, 26, 463, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 464, 464, 464, 464, 464, 464, 464, 464,
- 464, 465, 26, 26, 26, 26, 26, 26, 466, 466, 466, 466, 466, 466, 467, 26,
- 466, 466, 466, 466, 466, 466, 467, 468, 469, 469, 469, 469, 469, 26, 469, 470,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 31, 31, 31, 50, 471, 471, 471, 471, 471, 472, 473, 26,
- 26, 26, 26, 26, 26, 26, 26, 474, 475, 475, 475, 475, 475, 26, 476, 476,
- 476, 476, 476, 477, 26, 26, 478, 478, 478, 479, 26, 26, 26, 26, 480, 480,
- 480, 481, 26, 26, 482, 482, 483, 26, 484, 484, 484, 484, 484, 484, 484, 484,
- 484, 485, 486, 484, 484, 484, 485, 487, 488, 488, 488, 488, 488, 488, 488, 488,
- 489, 490, 491, 491, 491, 492, 491, 493, 494, 494, 494, 494, 494, 494, 495, 494,
- 494, 26, 496, 496, 496, 496, 497, 26, 498, 498, 498, 498, 498, 498, 498, 498,
- 498, 498, 498, 498, 499, 137, 500, 26, 501, 501, 502, 501, 501, 501, 501, 501,
- 503, 26, 26, 26, 26, 26, 26, 26, 504, 505, 506, 507, 506, 508, 509, 509,
- 509, 509, 509, 509, 509, 510, 509, 511, 512, 513, 514, 515, 515, 516, 517, 518,
- 513, 519, 520, 521, 522, 523, 523, 26, 524, 524, 524, 524, 524, 524, 524, 524,
- 524, 524, 524, 525, 526, 26, 26, 26, 527, 527, 527, 527, 527, 527, 527, 527,
- 527, 26, 527, 528, 26, 26, 26, 26, 529, 529, 529, 529, 529, 529, 530, 529,
- 529, 529, 529, 530, 26, 26, 26, 26, 531, 531, 531, 531, 531, 531, 531, 531,
- 532, 26, 531, 533, 198, 534, 26, 26, 535, 535, 535, 535, 535, 535, 535, 536,
- 535, 536, 26, 26, 26, 26, 26, 26, 537, 537, 537, 538, 537, 539, 537, 537,
- 540, 26, 26, 26, 26, 26, 26, 26, 541, 541, 541, 541, 541, 541, 541, 542,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 543, 543, 543, 543,
- 543, 543, 543, 543, 543, 543, 544, 545, 546, 547, 548, 549, 549, 549, 550, 551,
- 546, 26, 549, 552, 26, 26, 26, 26, 26, 26, 26, 26, 553, 554, 553, 553,
- 553, 553, 553, 554, 555, 26, 26, 26, 556, 556, 556, 556, 556, 556, 556, 556,
- 556, 26, 557, 557, 557, 557, 557, 557, 557, 557, 557, 557, 558, 26, 178, 178,
- 559, 559, 559, 559, 559, 559, 559, 560, 53, 561, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 562, 563, 562, 562, 562, 562, 564, 562,
- 565, 26, 562, 562, 562, 566, 567, 567, 567, 567, 568, 567, 567, 569, 570, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 571, 572, 573, 573, 573, 573, 571, 574,
- 573, 26, 573, 575, 576, 577, 578, 578, 578, 579, 580, 581, 578, 582, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 583, 583, 583, 584, 585, 585, 586, 585, 585, 585, 585, 587,
- 585, 585, 585, 588, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 589, 26,
- 108, 108, 108, 108, 108, 108, 590, 591, 592, 592, 592, 592, 592, 592, 592, 592,
- 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 593, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 592, 592, 592, 592, 592, 592, 592, 592,
- 592, 592, 592, 592, 592, 594, 595, 26, 592, 592, 592, 592, 592, 592, 592, 592,
- 596, 26, 26, 26, 26, 26, 26, 26, 26, 26, 597, 597, 597, 597, 597, 597,
- 597, 597, 597, 597, 597, 597, 598, 26, 599, 599, 599, 599, 599, 599, 599, 599,
- 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599, 599,
- 599, 599, 600, 26, 26, 26, 26, 26, 601, 601, 601, 601, 601, 601, 601, 601,
- 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601, 601,
- 602, 26, 26, 26, 26, 26, 26, 26, 305, 305, 305, 305, 305, 305, 305, 305,
- 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 305, 603,
- 604, 604, 604, 605, 604, 606, 607, 607, 607, 607, 607, 607, 607, 607, 607, 608,
- 607, 609, 610, 610, 610, 611, 611, 26, 612, 612, 612, 612, 612, 612, 612, 612,
- 613, 26, 612, 614, 614, 612, 612, 615, 612, 612, 26, 26, 26, 26, 26, 26,
+ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 280, 26, 26, 26, 0, 0,
+ 281, 0, 0, 0, 282, 283, 0, 284, 285, 286, 286, 286, 286, 286, 286, 286,
+ 286, 286, 287, 288, 289, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 291,
+ 292, 293, 293, 293, 293, 293, 294, 169, 169, 169, 169, 169, 169, 169, 169, 169,
+ 169, 295, 0, 0, 293, 293, 293, 293, 0, 0, 0, 0, 296, 297, 290, 290,
+ 169, 169, 169, 295, 0, 0, 0, 0, 0, 0, 0, 0, 169, 169, 169, 298,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 290, 290, 290, 290, 290, 299,
+ 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 0, 0, 0, 0, 0,
+ 277, 277, 277, 277, 277, 277, 277, 277, 0, 0, 0, 0, 0, 0, 0, 0,
+ 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300,
+ 300, 301, 300, 300, 300, 300, 300, 300, 302, 26, 303, 303, 303, 303, 303, 303,
+ 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304,
+ 304, 304, 304, 304, 304, 305, 26, 26, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 26,
+ 0, 0, 0, 0, 307, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 308, 2, 2, 2, 2, 2, 2, 2, 309, 310, 311, 26, 26, 312, 2,
+ 313, 313, 313, 313, 313, 314, 0, 315, 316, 316, 316, 316, 316, 316, 316, 26,
+ 317, 317, 317, 317, 317, 317, 317, 317, 318, 319, 317, 320, 53, 53, 53, 53,
+ 321, 321, 321, 321, 321, 322, 323, 323, 323, 323, 324, 325, 169, 169, 169, 326,
+ 327, 327, 327, 327, 327, 327, 327, 327, 327, 328, 327, 329, 164, 164, 164, 330,
+ 331, 331, 331, 331, 331, 331, 332, 26, 331, 333, 331, 334, 164, 164, 164, 164,
+ 335, 335, 335, 335, 335, 335, 335, 335, 336, 26, 26, 337, 338, 338, 339, 26,
+ 340, 340, 340, 26, 172, 172, 2, 2, 2, 2, 2, 341, 342, 343, 176, 176,
+ 176, 176, 176, 176, 176, 176, 176, 176, 338, 338, 338, 338, 338, 344, 338, 345,
+ 169, 169, 169, 169, 346, 26, 169, 169, 295, 347, 169, 169, 169, 169, 169, 346,
26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 617, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 618, 618, 618, 618, 618, 618, 618, 618,
- 618, 619, 618, 618, 618, 618, 618, 618, 618, 620, 618, 618, 26, 26, 26, 26,
- 26, 26, 26, 26, 621, 26, 347, 26, 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, 26, 623, 623, 623, 623, 623, 623, 623, 623,
+ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 280, 277, 277,
+ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 348, 26, 26, 26, 26,
+ 349, 26, 350, 351, 25, 25, 352, 353, 354, 25, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 355, 26, 356, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 357, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 358, 31, 31, 31, 31, 31, 31, 359, 26, 26, 26, 26, 31, 31,
+ 9, 9, 0, 315, 9, 360, 0, 0, 0, 0, 361, 0, 258, 296, 362, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 363,
+ 364, 0, 0, 0, 1, 2, 2, 3, 1, 2, 2, 3, 365, 290, 289, 290,
+ 290, 290, 290, 366, 169, 169, 169, 295, 367, 367, 367, 368, 258, 258, 26, 369,
+ 370, 371, 370, 370, 372, 370, 370, 373, 370, 374, 370, 374, 26, 26, 26, 26,
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 375,
+ 376, 0, 0, 0, 0, 0, 377, 0, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 253, 0, 378, 379, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 380,
+ 381, 381, 381, 382, 383, 383, 383, 383, 383, 383, 384, 26, 385, 0, 0, 296,
+ 386, 386, 386, 386, 387, 388, 389, 389, 389, 390, 391, 391, 391, 391, 391, 392,
+ 393, 393, 393, 394, 395, 395, 395, 395, 396, 395, 397, 26, 26, 26, 26, 26,
+ 398, 398, 398, 398, 398, 398, 398, 398, 398, 398, 399, 399, 399, 399, 399, 399,
+ 400, 400, 400, 401, 400, 402, 403, 403, 403, 403, 404, 403, 403, 403, 403, 404,
+ 405, 405, 405, 405, 405, 26, 406, 406, 406, 406, 406, 406, 407, 408, 409, 410,
+ 409, 410, 411, 409, 412, 409, 412, 413, 26, 26, 26, 26, 26, 26, 26, 26,
+ 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414, 414,
+ 414, 414, 414, 414, 414, 414, 415, 26, 414, 414, 416, 26, 414, 26, 26, 26,
+ 417, 2, 2, 2, 2, 2, 418, 309, 26, 26, 26, 26, 26, 26, 26, 26,
+ 419, 420, 421, 421, 421, 421, 422, 423, 424, 424, 425, 424, 426, 426, 426, 426,
+ 427, 427, 427, 428, 429, 427, 26, 26, 26, 26, 26, 26, 430, 430, 431, 432,
+ 433, 433, 433, 434, 435, 435, 435, 436, 26, 26, 26, 26, 26, 26, 26, 26,
+ 437, 437, 437, 437, 438, 438, 438, 439, 438, 438, 440, 438, 438, 438, 438, 438,
+ 441, 442, 443, 444, 445, 445, 446, 447, 445, 448, 445, 448, 449, 449, 449, 449,
+ 450, 450, 450, 450, 26, 26, 26, 26, 451, 451, 451, 451, 452, 453, 452, 26,
+ 454, 454, 454, 454, 454, 454, 455, 456, 457, 457, 458, 457, 459, 459, 460, 459,
+ 461, 461, 462, 463, 26, 464, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 465, 465, 465, 465, 465, 465, 465, 465, 465, 466, 26, 26, 26, 26, 26, 26,
+ 467, 467, 467, 467, 467, 467, 468, 26, 467, 467, 467, 467, 467, 467, 468, 469,
+ 470, 470, 470, 470, 470, 26, 470, 471, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 31, 31, 31, 50,
+ 472, 472, 472, 472, 472, 473, 474, 26, 26, 26, 26, 26, 26, 26, 26, 475,
+ 476, 476, 476, 476, 476, 26, 477, 477, 477, 477, 477, 478, 26, 26, 479, 479,
+ 479, 480, 26, 26, 26, 26, 481, 481, 481, 482, 26, 26, 483, 483, 484, 26,
+ 485, 485, 485, 485, 485, 485, 485, 485, 485, 486, 487, 485, 485, 485, 486, 488,
+ 489, 489, 489, 489, 489, 489, 489, 489, 490, 491, 492, 492, 492, 493, 492, 494,
+ 495, 495, 495, 495, 495, 495, 496, 495, 495, 26, 497, 497, 497, 497, 498, 26,
+ 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, 500, 137, 501, 26,
+ 502, 502, 503, 502, 502, 502, 502, 502, 504, 26, 26, 26, 26, 26, 26, 26,
+ 505, 506, 507, 508, 507, 509, 510, 510, 510, 510, 510, 510, 510, 511, 510, 512,
+ 513, 514, 515, 516, 516, 517, 518, 519, 514, 520, 521, 522, 523, 524, 524, 26,
+ 525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 526, 527, 26, 26, 26,
+ 528, 528, 528, 528, 528, 528, 528, 528, 528, 26, 528, 529, 26, 26, 26, 26,
+ 530, 530, 530, 530, 530, 530, 531, 530, 530, 530, 530, 531, 26, 26, 26, 26,
+ 532, 532, 532, 532, 532, 532, 532, 532, 533, 26, 532, 534, 198, 535, 26, 26,
+ 536, 536, 536, 536, 536, 536, 536, 537, 536, 537, 26, 26, 26, 26, 26, 26,
+ 538, 538, 538, 539, 538, 540, 538, 538, 541, 26, 26, 26, 26, 26, 26, 26,
+ 542, 542, 542, 542, 542, 542, 542, 543, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 544, 544, 544, 544, 544, 544, 544, 544, 544, 544, 545, 546,
+ 547, 548, 549, 550, 550, 550, 551, 552, 547, 26, 550, 553, 26, 26, 26, 26,
+ 26, 26, 26, 26, 554, 555, 554, 554, 554, 554, 554, 555, 556, 26, 26, 26,
+ 557, 557, 557, 557, 557, 557, 557, 557, 557, 26, 558, 558, 558, 558, 558, 558,
+ 558, 558, 558, 558, 559, 26, 178, 178, 560, 560, 560, 560, 560, 560, 560, 561,
+ 53, 562, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 563, 564, 563, 563, 563, 563, 565, 563, 566, 26, 563, 563, 563, 567, 568, 568,
+ 568, 568, 569, 568, 568, 570, 571, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 572, 573, 574, 574, 574, 574, 572, 575, 574, 26, 574, 576, 577, 578, 579, 579,
+ 579, 580, 581, 582, 579, 583, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 584, 584, 584, 585,
+ 586, 586, 587, 586, 586, 586, 586, 588, 586, 586, 586, 589, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 590, 26, 108, 108, 108, 108, 108, 108, 591, 592,
+ 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593,
+ 593, 593, 593, 594, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 593, 595, 596, 26,
+ 593, 593, 593, 593, 593, 593, 593, 593, 597, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 598, 598, 598, 598, 598, 598, 598, 598, 598, 598, 598, 598, 599, 26,
+ 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
+ 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 601, 26, 26, 26, 26, 26,
+ 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, 26, 26, 26, 26, 26, 26, 26,
+ 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306,
+ 306, 306, 306, 306, 306, 306, 306, 604, 605, 605, 605, 606, 605, 607, 608, 608,
+ 608, 608, 608, 608, 608, 608, 608, 609, 608, 610, 611, 611, 611, 612, 612, 26,
+ 613, 613, 613, 613, 613, 613, 613, 613, 614, 26, 613, 615, 615, 613, 613, 616,
+ 613, 613, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 617, 617, 617, 617, 617, 617, 617, 617,
+ 617, 617, 617, 618, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 619, 619, 619, 619, 619, 619, 619, 619, 619, 620, 619, 619, 619, 619, 619, 619,
+ 619, 621, 619, 619, 26, 26, 26, 26, 26, 26, 26, 26, 622, 26, 348, 26,
623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623,
- 623, 623, 624, 26, 26, 26, 26, 26, 622, 625, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 626, 627, 628, 287, 287, 287, 287, 287, 287, 287,
- 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287,
- 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 629, 26, 630, 26,
- 26, 26, 631, 26, 632, 26, 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, 633, 633, 634, 635, 635, 635, 635, 635, 635, 635, 635,
- 635, 635, 635, 635, 635, 636, 635, 637, 635, 638, 635, 639, 281, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 9, 9, 9, 9, 9, 640, 9, 9,
- 221, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 281, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 276, 26, 0, 0, 0, 0, 258, 363, 0, 0,
- 0, 0, 0, 0, 641, 642, 0, 643, 644, 645, 0, 0, 0, 646, 0, 0,
- 0, 0, 0, 0, 0, 266, 26, 26, 14, 14, 14, 14, 14, 14, 14, 14,
- 247, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 0, 0, 281, 26, 0, 0, 281, 26, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 258, 26, 0, 0, 0, 260, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 255, 647, 648, 0, 649,
- 650, 0, 0, 0, 0, 0, 0, 0, 269, 651, 255, 255, 0, 0, 0, 652,
- 653, 654, 655, 0, 0, 0, 0, 0, 0, 0, 0, 0, 276, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 268, 0, 0, 0, 0, 0, 0, 656, 656, 656, 656, 656, 656, 656, 656,
- 656, 656, 656, 656, 656, 656, 656, 656, 656, 657, 26, 658, 659, 656, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 348, 660, 308, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 661, 270, 270, 662, 663, 664, 18, 18,
- 18, 18, 18, 18, 18, 665, 26, 26, 26, 666, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 667, 667, 667, 667, 667, 668, 667, 669,
- 667, 670, 26, 26, 26, 26, 26, 26, 26, 26, 671, 671, 671, 672, 26, 26,
- 673, 673, 673, 673, 673, 673, 673, 674, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 675, 675, 675, 675, 675, 676, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 172, 677, 170, 172, 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, 678, 680, 26, 26, 26, 26, 26, 681, 681, 681, 681, 681, 681, 681, 681,
- 681, 682, 681, 683, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 363, 0, 0, 0, 0, 0, 0, 0, 377, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 363, 0, 0, 0, 0, 0, 0, 276,
- 26, 26, 26, 26, 26, 26, 26, 26, 684, 31, 31, 31, 685, 686, 687, 688,
- 689, 690, 685, 691, 685, 687, 687, 692, 31, 693, 31, 694, 695, 693, 31, 694,
- 26, 26, 26, 26, 26, 26, 51, 26, 0, 0, 0, 0, 0, 281, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 281, 26, 0, 258, 363, 0,
- 363, 0, 363, 0, 0, 0, 276, 26, 0, 0, 0, 0, 0, 276, 26, 26,
- 26, 26, 26, 26, 696, 0, 0, 0, 697, 26, 0, 0, 0, 0, 0, 281,
- 0, 260, 314, 26, 276, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 698, 0, 377, 0, 377, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 258, 699, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 314, 0, 281, 260, 26, 0, 281, 0, 0, 0, 0, 0, 0,
- 0, 26, 0, 314, 0, 0, 0, 0, 0, 26, 0, 0, 0, 276, 314, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 281, 26, 0, 276, 0, 377, 0, 260, 0, 0, 0, 0, 0, 269,
- 276, 696, 0, 281, 0, 260, 0, 260, 0, 0, 360, 0, 0, 0, 0, 0,
- 0, 266, 26, 26, 26, 26, 0, 314, 277, 277, 277, 277, 277, 277, 277, 277,
- 277, 277, 277, 277, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 347,
- 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 280, 277, 277, 277, 277,
- 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 347, 26, 277, 277,
- 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
- 277, 277, 277, 277, 700, 26, 26, 26, 277, 277, 277, 280, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277,
- 277, 701, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 702, 26, 26, 26, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9,
+ 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 623, 26,
+ 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624,
+ 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 625, 26, 26, 26, 26, 26,
+ 623, 626, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 627, 628,
+ 629, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
+ 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
+ 286, 286, 286, 286, 630, 26, 631, 26, 26, 26, 632, 26, 633, 26, 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, 634, 634, 634, 634, 634, 634, 634, 634, 635,
+ 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 637, 636, 638,
+ 636, 639, 636, 640, 296, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 9, 9, 9, 9, 9, 641, 9, 9, 221, 26, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 296, 26, 26, 26, 26, 26, 26, 26,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 276, 26,
+ 0, 0, 0, 0, 258, 364, 0, 0, 0, 0, 0, 0, 642, 643, 0, 644,
+ 645, 646, 0, 0, 0, 647, 0, 0, 0, 0, 0, 0, 0, 266, 26, 26,
+ 14, 14, 14, 14, 14, 14, 14, 14, 247, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 296, 26, 0, 0, 296, 26,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 258, 26, 0, 0, 0, 260,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0,
+ 0, 0, 0, 255, 648, 649, 0, 650, 651, 0, 0, 0, 0, 0, 0, 0,
+ 269, 652, 255, 255, 0, 0, 0, 653, 654, 655, 656, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 276, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 268, 0, 0, 0, 0, 0, 0,
+ 657, 657, 657, 657, 657, 657, 657, 657, 657, 657, 657, 657, 657, 657, 657, 657,
+ 657, 658, 26, 659, 660, 657, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 2, 2, 2, 349, 661, 309, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 662, 270, 270, 663, 664, 665, 18, 18, 18, 18, 18, 18, 18, 666, 26, 26,
+ 26, 667, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 668, 668, 668, 668, 668, 669, 668, 670, 668, 671, 26, 26, 26, 26, 26, 26,
+ 26, 26, 672, 672, 672, 673, 26, 26, 674, 674, 674, 674, 674, 674, 674, 675,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 676, 676, 676, 676, 676, 677,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 172, 678, 170, 172,
+ 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679, 679,
+ 679, 679, 679, 679, 679, 679, 679, 679, 680, 679, 681, 26, 26, 26, 26, 26,
+ 682, 682, 682, 682, 682, 682, 682, 682, 682, 683, 682, 684, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 364, 0,
+ 0, 0, 0, 0, 0, 0, 378, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 364, 0, 0, 0, 0, 0, 0, 276, 26, 26, 26, 26, 26, 26, 26, 26,
+ 685, 31, 31, 31, 686, 687, 688, 689, 690, 691, 686, 692, 686, 688, 688, 693,
+ 31, 694, 31, 695, 696, 694, 31, 695, 26, 26, 26, 26, 26, 26, 51, 26,
+ 0, 0, 0, 0, 0, 296, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 296, 26, 0, 258, 364, 0, 364, 0, 364, 0, 0, 0, 276, 26,
+ 0, 0, 0, 0, 0, 276, 26, 26, 26, 26, 26, 26, 697, 0, 0, 0,
+ 698, 26, 0, 0, 0, 0, 0, 296, 0, 260, 315, 26, 276, 26, 26, 26,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 699, 0, 378, 0, 378,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 258, 700,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 315, 0, 296, 260, 26,
+ 0, 296, 0, 0, 0, 0, 0, 0, 0, 26, 0, 315, 0, 0, 0, 0,
+ 0, 26, 0, 0, 0, 276, 315, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 296, 26, 0, 276, 0, 378,
+ 0, 260, 0, 0, 0, 0, 0, 269, 276, 697, 0, 296, 0, 260, 0, 260,
+ 0, 0, 361, 0, 0, 0, 0, 0, 0, 266, 26, 26, 26, 26, 0, 315,
+ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 26, 26, 26, 26,
+ 277, 277, 277, 277, 277, 277, 277, 348, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 277, 280, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 277, 277, 348, 26, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
+ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 701, 26, 277, 277,
+ 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 280, 26, 26, 26, 26,
+ 277, 277, 277, 280, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 277, 277, 277, 277, 277, 277, 277, 277, 277, 702, 277, 277, 277, 277, 277, 277,
+ 277, 277, 277, 277, 277, 277, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 703, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 939, 940, 941, 942, 946, 948, 0, 962,
- 969, 970, 971, 976,1001,1002,1003,1008, 0,1033,1040,1041,1042,1043,1047, 0,
- 0,1080,1081,1082,1086,1110, 0, 0,1124,1125,1126,1127,1131,1133, 0,1147,
- 1154,1155,1156,1161,1187,1188,1189,1193, 0,1219,1226,1227,1228,1229,1233, 0,
- 0,1267,1268,1269,1273,1298, 0,1303, 943,1128, 944,1129, 954,1139, 958,1143,
- 959,1144, 960,1145, 961,1146, 964,1149, 0, 0, 973,1158, 974,1159, 975,1160,
- 983,1168, 978,1163, 988,1173, 990,1175, 991,1176, 993,1178, 994,1179, 0, 0,
- 1004,1190,1005,1191,1006,1192,1014,1199,1007, 0, 0, 0,1016,1201,1020,1206,
- 0,1022,1208,1025,1211,1023,1209, 0, 0, 0, 0,1032,1218,1037,1223,1035,
- 1221, 0, 0, 0,1044,1230,1045,1231,1049,1235, 0, 0,1058,1244,1064,1250,
- 1060,1246,1066,1252,1067,1253,1072,1258,1069,1255,1077,1264,1074,1261, 0, 0,
- 1083,1270,1084,1271,1085,1272,1088,1275,1089,1276,1096,1283,1103,1290,1111,1299,
- 1115,1118,1307,1120,1309,1121,1310, 0,1053,1239, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,1093,1280, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 949,1134,1010,1195,1050,1236,1090,1277,1341,1368,1340,
- 1367,1342,1369,1339,1366, 0,1320,1347,1418,1419,1323,1350, 0, 0, 992,1177,
- 1018,1204,1055,1241,1416,1417,1415,1424,1202, 0, 0, 0, 987,1172, 0, 0,
- 1031,1217,1321,1348,1322,1349,1338,1365, 950,1135, 951,1136, 979,1164, 980,1165,
- 1011,1196,1012,1197,1051,1237,1052,1238,1061,1247,1062,1248,1091,1278,1092,1279,
- 1071,1257,1076,1263, 0, 0, 997,1182, 0, 0, 0, 0, 0, 0, 945,1130,
- 982,1167,1337,1364,1335,1362,1046,1232,1422,1423,1113,1301, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 10,1425, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,1314,1427, 5,
- 1434,1438,1443, 0,1450, 0,1455,1461,1514, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,1446,1458,1468,1476,1480,1486,1517, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,1489,1503,1494,1500,1508, 0, 0, 0, 0,1520,1521, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1526,1528, 0,1525, 0, 0, 0,1522,
- 0, 0, 0, 0,1536,1532,1539, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1556, 0, 0, 0, 0, 0, 0,1548,1550, 0,1547, 0, 0, 0,1567,
- 0, 0, 0, 0,1558,1554,1561, 0, 0, 0, 0, 0, 0, 0,1568,1569,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1529,1551, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1523,1545,1524,1546, 0, 0,1527,1549,
- 0, 0,1570,1571,1530,1552,1531,1553, 0, 0,1533,1555,1535,1557,1537,1559,
- 0, 0,1572,1573,1544,1566,1538,1560,1540,1562,1541,1563,1542,1564, 0, 0,
- 1543,1565, 0, 0, 0, 0, 0, 0, 0, 0,1606,1607,1609,1608,1610, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1613, 0,1611, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1612, 0, 0, 0, 0,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1620, 0, 0, 0, 0, 0, 0, 0,1623, 0, 0,1624, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1614,1615,1616,1617,1618,1619,1621,1622, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1628,1629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1625,1626, 0,1627, 0, 0, 0,1634, 0, 0,1635, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1630,1631,1632, 0, 0,1633, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1639, 0, 0,1638,1640, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1636,1637, 0, 0, 0, 0, 0, 0,1641, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,1642,1644,1643, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1645, 0, 0, 0, 0, 0, 0, 0,1646, 0, 0, 0, 0, 0, 0,1648,
- 1649, 0,1647,1650, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,1651,1653,1652, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,1654, 0,1655,1657,1656, 0, 0, 0, 0,1659, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,1660, 0, 0, 0, 0,1661, 0, 0, 0, 0,1662,
- 0, 0, 0, 0,1663, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1658, 0, 0, 0, 0, 0, 0, 0, 0, 0,1664, 0,1665,1673, 0,
- 1674, 0, 0, 0, 0, 0, 0, 0, 0,1666, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1668, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,1669, 0, 0, 0, 0,1670, 0, 0, 0, 0,1671,
- 0, 0, 0, 0,1672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1675, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1676, 0,
- 1677, 0,1678, 0,1679, 0,1680, 0, 0, 0,1681, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1682, 0,1683, 0, 0,1684,1685, 0,1686, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 953,1138, 955,1140, 956,1141, 957,1142,
- 1324,1351, 963,1148, 965,1150, 968,1153, 966,1151, 967,1152,1378,1380,1379,1381,
- 984,1169, 985,1170,1420,1421, 986,1171, 989,1174, 995,1180, 998,1183, 996,1181,
- 999,1184,1000,1185,1015,1200,1329,1356,1017,1203,1019,1205,1021,1207,1024,1210,
- 1687,1688,1027,1213,1026,1212,1028,1214,1029,1215,1030,1216,1034,1220,1036,1222,
- 1039,1225,1038,1224,1334,1361,1336,1363,1382,1384,1383,1385,1056,1242,1057,1243,
- 1059,1245,1063,1249,1689,1690,1065,1251,1068,1254,1070,1256,1386,1387,1388,1389,
- 1691,1692,1073,1259,1075,1262,1079,1266,1078,1265,1095,1282,1098,1285,1097,1284,
- 1390,1391,1392,1393,1099,1286,1100,1287,1101,1288,1102,1289,1105,1292,1104,1291,
- 1106,1294,1107,1295,1108,1296,1114,1302,1119,1308,1122,1311,1123,1312,1186,1260,
- 1293,1305, 0,1394, 0, 0, 0, 0, 952,1137, 947,1132,1317,1344,1316,1343,
- 1319,1346,1318,1345,1693,1695,1371,1375,1370,1374,1373,1377,1372,1376,1694,1696,
- 981,1166, 977,1162, 972,1157,1326,1353,1325,1352,1328,1355,1327,1354,1697,1698,
- 1009,1194,1013,1198,1054,1240,1048,1234,1331,1358,1330,1357,1333,1360,1332,1359,
- 1699,1700,1396,1401,1395,1400,1398,1403,1397,1402,1399,1404,1094,1281,1087,1274,
- 1406,1411,1405,1410,1408,1413,1407,1412,1409,1414,1109,1297,1117,1306,1116,1304,
- 1112,1300, 0, 0, 0, 0, 0, 0,1471,1472,1701,1705,1702,1706,1703,1707,
- 1430,1431,1715,1719,1716,1720,1717,1721,1477,1478,1729,1731,1730,1732, 0, 0,
- 1435,1436,1733,1735,1734,1736, 0, 0,1481,1482,1737,1741,1738,1742,1739,1743,
- 1439,1440,1751,1755,1752,1756,1753,1757,1490,1491,1765,1768,1766,1769,1767,1770,
- 1447,1448,1771,1774,1772,1775,1773,1776,1495,1496,1777,1779,1778,1780, 0, 0,
- 1451,1452,1781,1783,1782,1784, 0, 0,1504,1505,1785,1788,1786,1789,1787,1790,
- 0,1459, 0,1791, 0,1792, 0,1793,1509,1510,1794,1798,1795,1799,1796,1800,
- 1462,1463,1808,1812,1809,1813,1810,1814,1467, 21,1475, 22,1479, 23,1485, 24,
- 1493, 27,1499, 28,1507, 29, 0, 0,1704,1708,1709,1710,1711,1712,1713,1714,
- 1718,1722,1723,1724,1725,1726,1727,1728,1740,1744,1745,1746,1747,1748,1749,1750,
- 1754,1758,1759,1760,1761,1762,1763,1764,1797,1801,1802,1803,1804,1805,1806,1807,
- 1811,1815,1816,1817,1818,1819,1820,1821,1470,1469,1822,1474,1465, 0,1473,1825,
- 1429,1428,1426, 12,1432, 0, 26, 0, 0,1315,1823,1484,1466, 0,1483,1829,
- 1433, 13,1437, 14,1441,1826,1827,1828,1488,1487,1513, 19, 0, 0,1492,1515,
- 1445,1444,1442, 15, 0,1831,1832,1833,1502,1501,1516, 25,1497,1498,1506,1518,
- 1457,1456,1454, 17,1453,1313, 11, 3, 0, 0,1824,1512,1519, 0,1511,1830,
- 1449, 16,1460, 18,1464, 4, 0, 0, 30, 31, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0,
- 0, 0, 2, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,1834,1835, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,1836, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,1837,1839,1838, 0, 0, 0, 0,1840, 0, 0, 0,
- 0,1841, 0, 0,1842, 0, 0, 0, 0, 0, 0, 0,1843, 0,1844, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1845, 0, 0,1846, 0, 0,1847,
- 0,1848, 0, 0, 0, 0, 0, 0, 937, 0,1850, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,1849, 936, 938,1851,1852, 0, 0,1853,1854, 0, 0,
- 1855,1856, 0, 0, 0, 0, 0, 0,1857,1858, 0, 0,1861,1862, 0, 0,
- 1863,1864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1867,1868,1869,1870,1859,1860,1865,1866, 0, 0, 0, 0,
- 0, 0,1871,1872,1873,1874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1877, 0,1878, 0,1879, 0,1880, 0,1881, 0,1882, 0,
- 1883, 0,1884, 0,1885, 0,1886, 0,1887, 0,1888, 0, 0,1889, 0,1890,
- 0,1891, 0, 0, 0, 0, 0, 0,1892,1893, 0,1894,1895, 0,1896,1897,
- 0,1898,1899, 0,1900,1901, 0, 0, 0, 0, 0, 0,1876, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,1902, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1904, 0,1905, 0,1906, 0,1907, 0,1908, 0,1909, 0,
- 1910, 0,1911, 0,1912, 0,1913, 0,1914, 0,1915, 0, 0,1916, 0,1917,
- 0,1918, 0, 0, 0, 0, 0, 0,1919,1920, 0,1921,1922, 0,1923,1924,
- 0,1925,1926, 0,1927,1928, 0, 0, 0, 0, 0, 0,1903, 0, 0,1929,
- 1930,1931,1932, 0, 0, 0,1933, 0, 710, 385, 724, 715, 455, 103, 186, 825,
- 825, 242, 751, 205, 241, 336, 524, 601, 663, 676, 688, 738, 411, 434, 474, 500,
- 649, 746, 799, 108, 180, 416, 482, 662, 810, 275, 462, 658, 692, 344, 618, 679,
- 293, 388, 440, 492, 740, 116, 146, 168, 368, 414, 481, 527, 606, 660, 665, 722,
- 781, 803, 809, 538, 553, 588, 642, 758, 811, 701, 233, 299, 573, 612, 487, 540,
- 714, 779, 232, 267, 412, 445, 457, 585, 594, 766, 167, 613, 149, 148, 560, 589,
- 648, 768, 708, 345, 411, 704, 105, 259, 313, 496, 518, 174, 542, 120, 307, 101,
- 430, 372, 584, 183, 228, 529, 650, 697, 424, 732, 428, 349, 632, 355, 517, 110,
- 135, 147, 403, 580, 624, 700, 750, 170, 193, 245, 297, 374, 463, 543, 763, 801,
- 812, 815, 162, 384, 420, 730, 287, 330, 337, 366, 459, 476, 509, 558, 591, 610,
- 726, 652, 734, 759, 154, 163, 198, 473, 683, 697, 292, 311, 353, 423, 572, 494,
- 113, 217, 259, 280, 314, 499, 506, 603, 608, 752, 778, 782, 788, 117, 557, 748,
- 774, 320, 109, 126, 260, 265, 373, 411, 479, 523, 655, 737, 823, 380, 765, 161,
- 395, 398, 438, 451, 502, 516, 537, 583, 791, 136, 340, 769, 122, 273, 446, 727,
- 305, 322, 400, 496, 771, 155, 190, 269, 377, 391, 406, 432, 501, 519, 599, 684,
- 687, 749, 776, 175, 452, 191, 480, 510, 659, 772, 805, 813, 397, 444, 619, 566,
- 568, 575, 491, 471, 707, 111, 636, 156, 153, 288, 346, 578, 256, 435, 383, 729,
- 680, 767, 694, 295, 128, 210, 0, 0, 227, 0, 379, 0, 0, 150, 493, 525,
- 544, 551, 552, 556, 783, 576, 604, 0, 661, 0, 703, 0, 0, 735, 743, 0,
- 0, 0, 793, 794, 795, 808, 741, 773, 118, 127, 130, 166, 169, 177, 207, 213,
- 215, 226, 229, 268, 270, 317, 327, 329, 335, 369, 375, 381, 404, 441, 448, 458,
- 477, 484, 503, 539, 545, 547, 546, 548, 549, 550, 554, 555, 561, 564, 569, 591,
- 593, 595, 598, 607, 620, 625, 625, 651, 690, 695, 705, 706, 716, 717, 733, 735,
- 777, 786, 790, 315, 869, 623, 0, 0, 102, 145, 134, 115, 129, 138, 165, 171,
- 207, 202, 206, 212, 227, 231, 240, 243, 250, 254, 294, 296, 303, 308, 319, 325,
- 321, 329, 326, 335, 341, 357, 360, 362, 370, 379, 388, 389, 393, 421, 424, 438,
- 456, 454, 458, 465, 477, 535, 485, 490, 493, 507, 512, 514, 521, 522, 525, 526,
- 528, 533, 532, 541, 565, 569, 574, 586, 591, 597, 607, 637, 647, 674, 691, 693,
- 695, 698, 703, 699, 705, 704, 702, 706, 709, 717, 728, 736, 747, 754, 770, 777,
- 783, 784, 786, 787, 790, 802, 825, 848, 847, 857, 55, 65, 66, 883, 892, 916,
- 822, 824, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,1586, 0,1605, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,1602,1603,1934,1935,1574,1575,1576,1577,1579,1580,1581,1583,1584, 0,
- 1585,1587,1588,1589,1591, 0,1592, 0,1593,1594, 0,1595,1596, 0,1598,1599,
- 1600,1601,1604,1582,1578,1590,1597, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,1936, 0,1937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,1939,1940, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1941,1942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1944,1943, 0,1945, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,1946,1947, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,1949,1950,1951,1952,1953,1954,1955, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1956,1957,1958,1960,1959,1961, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 106, 104, 107, 826, 114, 118, 119, 121,
- 123, 124, 127, 125, 34, 830, 130, 131, 132, 137, 827, 35, 133, 139, 829, 142,
- 143, 112, 144, 145, 924, 151, 152, 37, 157, 158, 159, 160, 38, 165, 166, 169,
- 171, 172, 173, 174, 176, 177, 178, 179, 181, 182, 182, 182, 833, 468, 184, 185,
- 834, 187, 188, 189, 196, 192, 194, 195, 197, 199, 200, 201, 203, 204, 204, 206,
- 208, 209, 211, 218, 213, 219, 214, 216, 153, 234, 221, 222, 223, 220, 225, 224,
- 230, 835, 235, 236, 237, 238, 239, 244, 836, 837, 247, 248, 249, 246, 251, 39,
- 40, 253, 255, 255, 838, 257, 258, 259, 261, 839, 262, 263, 301, 264, 41, 266,
- 270, 272, 271, 841, 274, 842, 277, 276, 278, 281, 282, 42, 283, 284, 285, 286,
- 43, 843, 44, 289, 290, 291, 293, 934, 298, 845, 845, 621, 300, 300, 45, 852,
- 894, 302, 304, 46, 306, 309, 310, 312, 316, 48, 47, 317, 846, 318, 323, 324,
- 325, 324, 328, 329, 333, 331, 332, 334, 335, 336, 338, 339, 342, 343, 347, 351,
- 849, 350, 348, 352, 354, 359, 850, 361, 358, 356, 49, 363, 365, 367, 364, 50,
- 369, 371, 851, 376, 386, 378, 53, 381, 52, 51, 140, 141, 387, 382, 614, 78,
- 388, 389, 390, 394, 392, 856, 54, 399, 396, 402, 404, 858, 405, 401, 407, 55,
- 408, 409, 410, 413, 859, 415, 56, 417, 860, 418, 57, 419, 422, 424, 425, 861,
- 840, 862, 426, 863, 429, 431, 427, 433, 437, 441, 438, 439, 442, 443, 864, 436,
- 449, 450, 58, 454, 453, 865, 447, 460, 866, 867, 461, 466, 465, 464, 59, 467,
- 470, 469, 472, 828, 475, 868, 478, 870, 483, 485, 486, 871, 488, 489, 872, 873,
- 495, 497, 60, 498, 61, 61, 504, 505, 507, 508, 511, 62, 513, 874, 515, 875,
- 518, 844, 520, 876, 877, 878, 63, 64, 528, 880, 879, 881, 882, 530, 531, 531,
- 533, 66, 534, 67, 68, 884, 536, 538, 541, 69, 885, 549, 886, 887, 556, 559,
- 70, 561, 562, 563, 888, 889, 889, 567, 71, 890, 570, 571, 72, 891, 577, 73,
- 581, 579, 582, 893, 587, 74, 590, 592, 596, 75, 895, 896, 76, 897, 600, 898,
- 602, 605, 607, 899, 900, 609, 901, 611, 853, 77, 615, 616, 79, 617, 252, 902,
- 903, 854, 855, 621, 622, 731, 80, 627, 626, 628, 164, 629, 630, 631, 633, 904,
- 632, 634, 639, 640, 635, 641, 646, 651, 638, 643, 644, 645, 905, 907, 906, 81,
- 653, 654, 656, 911, 657, 908, 82, 83, 909, 910, 84, 664, 665, 666, 667, 669,
- 668, 671, 670, 674, 672, 673, 675, 85, 677, 678, 86, 681, 682, 912, 685, 686,
- 87, 689, 36, 913, 914, 88, 89, 696, 702, 709, 711, 915, 712, 713, 718, 719,
- 917, 831, 721, 720, 723, 832, 725, 728, 918, 919, 739, 742, 744, 920, 745, 753,
- 756, 757, 755, 760, 761, 921, 762, 90, 764, 922, 91, 775, 279, 780, 923, 925,
- 92, 93, 785, 926, 94, 927, 787, 787, 789, 928, 792, 95, 796, 797, 798, 800,
- 96, 929, 802, 804, 806, 97, 98, 807, 930, 99, 931, 932, 933, 814, 100, 816,
- 817, 818, 819, 820, 821, 935, 0, 0,
+ 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008,
+ 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, 0,
+ 1124,1125,1126,1127,1131,1133, 0,1147,1154,1155,1156,1161,1187,1188,1189,1193,
+ 0,1219,1226,1227,1228,1229,1233, 0, 0,1267,1268,1269,1273,1298, 0,1303,
+ 943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149,
+ 0, 0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175,
+ 991,1176, 993,1178, 994,1179, 0, 0,1004,1190,1005,1191,1006,1192,1014,1199,
+ 1007, 0, 0, 0,1016,1201,1020,1206, 0,1022,1208,1025,1211,1023,1209, 0,
+ 0, 0, 0,1032,1218,1037,1223,1035,1221, 0, 0, 0,1044,1230,1045,1231,
+ 1049,1235, 0, 0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258,
+ 1069,1255,1077,1264,1074,1261, 0, 0,1083,1270,1084,1271,1085,1272,1088,1275,
+ 1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310, 0,
+ 1053,1239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1093,
+ 1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 949,1134,1010,
+ 1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366, 0,1320,1347,
+ 1418,1419,1323,1350, 0, 0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424,
+ 1202, 0, 0, 0, 987,1172, 0, 0,1031,1217,1321,1348,1322,1349,1338,1365,
+ 950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238,
+ 1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263, 0, 0, 997,1182,
+ 0, 0, 0, 0, 0, 0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232,
+ 1422,1423,1113,1301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 8, 9, 0, 10,1425, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,1314,1427, 5,1434,1438,1443, 0,1450, 0,1455,1461,
+ 1514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1446,1458,1468,1476,1480,1486,
+ 1517, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1489,1503,1494,1500,1508, 0,
+ 0, 0, 0,1520,1521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1526,1528, 0,1525, 0, 0, 0,1522, 0, 0, 0, 0,1536,1532,1539, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1534, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1556, 0, 0, 0, 0, 0, 0,
+ 1548,1550, 0,1547, 0, 0, 0,1567, 0, 0, 0, 0,1558,1554,1561, 0,
+ 0, 0, 0, 0, 0, 0,1568,1569, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1529,1551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1523,1545,1524,1546, 0, 0,1527,1549, 0, 0,1570,1571,1530,1552,1531,1553,
+ 0, 0,1533,1555,1535,1557,1537,1559, 0, 0,1572,1573,1544,1566,1538,1560,
+ 1540,1562,1541,1563,1542,1564, 0, 0,1543,1565, 0, 0, 0, 0, 0, 0,
+ 0, 0,1606,1607,1609,1608,1610, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1613, 0,1611, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1620, 0, 0, 0, 0, 0, 0,
+ 0,1623, 0, 0,1624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1614,1615,1616,1617,1618,1619,1621,1622,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1628,1629, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1625,1626, 0,1627,
+ 0, 0, 0,1634, 0, 0,1635, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1630,1631,1632, 0, 0,1633, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1639, 0, 0,1638,1640, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1636,1637, 0, 0,
+ 0, 0, 0, 0,1641, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1642,1644,1643, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1645, 0, 0, 0, 0, 0, 0, 0,
+ 1646, 0, 0, 0, 0, 0, 0,1648,1649, 0,1647,1650, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1651,1653,1652, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1654, 0,1655,1657,1656, 0,
+ 0, 0, 0,1659, 0, 0, 0, 0, 0, 0, 0, 0, 0,1660, 0, 0,
+ 0, 0,1661, 0, 0, 0, 0,1662, 0, 0, 0, 0,1663, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1658, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1664, 0,1665,1673, 0,1674, 0, 0, 0, 0, 0, 0, 0,
+ 0,1666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1668, 0, 0, 0, 0, 0, 0, 0, 0, 0,1669, 0, 0,
+ 0, 0,1670, 0, 0, 0, 0,1671, 0, 0, 0, 0,1672, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1667, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1675, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1676, 0,1677, 0,1678, 0,1679, 0,1680, 0,
+ 0, 0,1681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1682, 0,1683, 0, 0,
+ 1684,1685, 0,1686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153,
+ 966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171,
+ 989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356,
+ 1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214,
+ 1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363,
+ 1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251,
+ 1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266,
+ 1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287,
+ 1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302,
+ 1119,1308,1122,1311,1123,1312,1186,1260,1293,1305, 0,1394, 0, 0, 0, 0,
+ 952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375,
+ 1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353,
+ 1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234,
+ 1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403,
+ 1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412,
+ 1409,1414,1109,1297,1117,1306,1116,1304,1112,1300, 0, 0, 0, 0, 0, 0,
+ 1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721,
+ 1477,1478,1729,1731,1730,1732, 0, 0,1435,1436,1733,1735,1734,1736, 0, 0,
+ 1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757,
+ 1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776,
+ 1495,1496,1777,1779,1778,1780, 0, 0,1451,1452,1781,1783,1782,1784, 0, 0,
+ 1504,1505,1785,1788,1786,1789,1787,1790, 0,1459, 0,1791, 0,1792, 0,1793,
+ 1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814,
+ 1467, 21,1475, 22,1479, 23,1485, 24,1493, 27,1499, 28,1507, 29, 0, 0,
+ 1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728,
+ 1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764,
+ 1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821,
+ 1470,1469,1822,1474,1465, 0,1473,1825,1429,1428,1426, 12,1432, 0, 26, 0,
+ 0,1315,1823,1484,1466, 0,1483,1829,1433, 13,1437, 14,1441,1826,1827,1828,
+ 1488,1487,1513, 19, 0, 0,1492,1515,1445,1444,1442, 15, 0,1831,1832,1833,
+ 1502,1501,1516, 25,1497,1498,1506,1518,1457,1456,1454, 17,1453,1313, 11, 3,
+ 0, 0,1824,1512,1519, 0,1511,1830,1449, 16,1460, 18,1464, 4, 0, 0,
+ 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 6, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1834,1835, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1836, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1837,1839,1838,
+ 0, 0, 0, 0,1840, 0, 0, 0, 0,1841, 0, 0,1842, 0, 0, 0,
+ 0, 0, 0, 0,1843, 0,1844, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1845, 0, 0,1846, 0, 0,1847, 0,1848, 0, 0, 0, 0, 0, 0,
+ 937, 0,1850, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1849, 936, 938,
+ 1851,1852, 0, 0,1853,1854, 0, 0,1855,1856, 0, 0, 0, 0, 0, 0,
+ 1857,1858, 0, 0,1861,1862, 0, 0,1863,1864, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1867,1868,1869,1870,
+ 1859,1860,1865,1866, 0, 0, 0, 0, 0, 0,1871,1872,1873,1874, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1875, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1877, 0,1878, 0,
+ 1879, 0,1880, 0,1881, 0,1882, 0,1883, 0,1884, 0,1885, 0,1886, 0,
+ 1887, 0,1888, 0, 0,1889, 0,1890, 0,1891, 0, 0, 0, 0, 0, 0,
+ 1892,1893, 0,1894,1895, 0,1896,1897, 0,1898,1899, 0,1900,1901, 0, 0,
+ 0, 0, 0, 0,1876, 0, 0, 0, 0, 0, 0, 0, 0, 0,1902, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1904, 0,1905, 0,
+ 1906, 0,1907, 0,1908, 0,1909, 0,1910, 0,1911, 0,1912, 0,1913, 0,
+ 1914, 0,1915, 0, 0,1916, 0,1917, 0,1918, 0, 0, 0, 0, 0, 0,
+ 1919,1920, 0,1921,1922, 0,1923,1924, 0,1925,1926, 0,1927,1928, 0, 0,
+ 0, 0, 0, 0,1903, 0, 0,1929,1930,1931,1932, 0, 0, 0,1933, 0,
+ 710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601,
+ 663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662,
+ 810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168,
+ 368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758,
+ 811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585,
+ 594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259,
+ 313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697,
+ 424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170,
+ 193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330,
+ 337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473,
+ 683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603,
+ 608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411,
+ 479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583,
+ 791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269,
+ 377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510,
+ 659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156,
+ 153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210, 0, 0,
+ 227, 0, 379, 0, 0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604, 0,
+ 661, 0, 703, 0, 0, 735, 743, 0, 0, 0, 793, 794, 795, 808, 741, 773,
+ 118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329,
+ 335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548,
+ 549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651,
+ 690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623, 0, 0,
+ 102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243,
+ 250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362,
+ 370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490,
+ 493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586,
+ 591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706,
+ 709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848,
+ 847, 857, 55, 65, 66, 883, 892, 916, 822, 824, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1586, 0,1605,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1602,1603,1934,1935,1574,1575,
+ 1576,1577,1579,1580,1581,1583,1584, 0,1585,1587,1588,1589,1591, 0,1592, 0,
+ 1593,1594, 0,1595,1596, 0,1598,1599,1600,1601,1604,1582,1578,1590,1597, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1936, 0,1937, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1938, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1939,1940,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1941,1942, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1944,1943, 0,1945, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1946,1947, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1948, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1949,1950,
+ 1951,1952,1953,1954,1955, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1956,1957,1958,1960,1959,
+ 1961, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125, 34, 830, 130, 131,
+ 132, 137, 827, 35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152, 37,
+ 157, 158, 159, 160, 38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179,
+ 181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195,
+ 197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216,
+ 153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244,
+ 836, 837, 247, 248, 249, 246, 251, 39, 40, 253, 255, 255, 838, 257, 258, 259,
+ 261, 839, 262, 263, 301, 264, 41, 266, 270, 272, 271, 841, 274, 842, 277, 276,
+ 278, 281, 282, 42, 283, 284, 285, 286, 43, 843, 44, 289, 290, 291, 293, 934,
+ 298, 845, 845, 621, 300, 300, 45, 852, 894, 302, 304, 46, 306, 309, 310, 312,
+ 316, 48, 47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334,
+ 335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361,
+ 358, 356, 49, 363, 365, 367, 364, 50, 369, 371, 851, 376, 386, 378, 53, 381,
+ 52, 51, 140, 141, 387, 382, 614, 78, 388, 389, 390, 394, 392, 856, 54, 399,
+ 396, 402, 404, 858, 405, 401, 407, 55, 408, 409, 410, 413, 859, 415, 56, 417,
+ 860, 418, 57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433,
+ 437, 441, 438, 439, 442, 443, 864, 436, 449, 450, 58, 454, 453, 865, 447, 460,
+ 866, 867, 461, 466, 465, 464, 59, 467, 470, 469, 472, 828, 475, 868, 478, 870,
+ 483, 485, 486, 871, 488, 489, 872, 873, 495, 497, 60, 498, 61, 61, 504, 505,
+ 507, 508, 511, 62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878, 63, 64,
+ 528, 880, 879, 881, 882, 530, 531, 531, 533, 66, 534, 67, 68, 884, 536, 538,
+ 541, 69, 885, 549, 886, 887, 556, 559, 70, 561, 562, 563, 888, 889, 889, 567,
+ 71, 890, 570, 571, 72, 891, 577, 73, 581, 579, 582, 893, 587, 74, 590, 592,
+ 596, 75, 895, 896, 76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611,
+ 853, 77, 615, 616, 79, 617, 252, 902, 903, 854, 855, 621, 622, 731, 80, 627,
+ 626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651,
+ 638, 643, 644, 645, 905, 907, 906, 81, 653, 654, 656, 911, 657, 908, 82, 83,
+ 909, 910, 84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675, 85,
+ 677, 678, 86, 681, 682, 912, 685, 686, 87, 689, 36, 913, 914, 88, 89, 696,
+ 702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728,
+ 918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762, 90,
+ 764, 922, 91, 775, 279, 780, 923, 925, 92, 93, 785, 926, 94, 927, 787, 787,
+ 789, 928, 792, 95, 796, 797, 798, 800, 96, 929, 802, 804, 806, 97, 98, 807,
+ 930, 99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935, 0, 0,
};
static const int16_t
_hb_ucd_i16[196] =
@@ -2797,12 +2799,12 @@ _hb_ucd_i16[196] =
static inline uint_fast8_t
_hb_ucd_gc (unsigned u)
{
- return u<1114110u?_hb_ucd_u8[6800+(((_hb_ucd_u8[1312+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
+ return u<1114110u?_hb_ucd_u8[6808+(((_hb_ucd_u8[1312+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
}
static inline uint_fast8_t
_hb_ucd_ccc (unsigned u)
{
- return u<125259u?_hb_ucd_u8[8792+(((_hb_ucd_u8[8236+(((_hb_ucd_u8[7776+(((_hb_ucd_u8[7424+(((_hb_ucd_u8[7178+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
+ return u<125259u?_hb_ucd_u8[8800+(((_hb_ucd_u8[8244+(((_hb_ucd_u8[7784+(((_hb_ucd_u8[7432+(((_hb_ucd_u8[7186+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
}
static inline unsigned
_hb_ucd_b4 (const uint8_t* a, unsigned i)
@@ -2812,24 +2814,24 @@ _hb_ucd_b4 (const uint8_t* a, unsigned i)
static inline int_fast16_t
_hb_ucd_bmg (unsigned u)
{
- return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9540+(((_hb_ucd_u8[9420+(((_hb_ucd_b4(9292+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0;
+ return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9548+(((_hb_ucd_u8[9428+(((_hb_ucd_b4(9300+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0;
}
static inline uint_fast8_t
_hb_ucd_sc (unsigned u)
{
- return u<918000u?_hb_ucd_u8[11062+(((_hb_ucd_u16[2040+(((_hb_ucd_u8[10326+(((_hb_ucd_u8[9876+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2;
+ return u<918000u?_hb_ucd_u8[11070+(((_hb_ucd_u16[2048+(((_hb_ucd_u8[10334+(((_hb_ucd_u8[9884+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2;
}
static inline uint_fast16_t
_hb_ucd_dm (unsigned u)
{
- return u<195102u?_hb_ucd_u16[6008+(((_hb_ucd_u8[17068+(((_hb_ucd_u8[16686+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
+ return u<195102u?_hb_ucd_u16[6032+(((_hb_ucd_u8[17084+(((_hb_ucd_u8[16702+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
}
#elif !defined(HB_NO_UCD_UNASSIGNED)
static const uint8_t
-_hb_ucd_u8[14744] =
+_hb_ucd_u8[14752] =
{
0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 9, 10, 7, 7, 7, 7, 11, 12, 13, 13, 13, 14,
@@ -2906,13 +2908,13 @@ _hb_ucd_u8[14744] =
34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,243, 34,
244, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,245, 34, 34,
- 34, 34, 34, 34, 34, 34, 34,246,122,122,122,122,122,122,122,122,
- 34, 34, 34, 34,247,122,122,122,122,122,122,122,122,122,122,122,
- 34, 34, 34, 34, 34, 34,248, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34,249,122,122,122,122,122,122,122,122,
- 250,122,251,252,122,122,122,122,122,122,122,122,122,122,122,122,
- 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,253,
+ 34, 34, 34, 34, 34, 34, 34,246, 34, 34, 34, 34,247,122,122,122,
+ 34, 34, 34, 34,248,122,122,122,122,122,122,122,122,122,122,122,
+ 34, 34, 34, 34, 34, 34,249, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34,250,122,122,122,122,122,122,122,122,
+ 251,122,252,253,122,122,122,122,122,122,122,122,122,122,122,122,
107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,254,
+ 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,255,
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2,
7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16,
@@ -3075,11 +3077,11 @@ _hb_ucd_u8[14744] =
121, 4, 4, 4, 4, 2, 2, 88, 2, 2, 2, 2, 2,120, 2, 2,
108,151, 2, 2, 2, 2, 2, 2, 67, 2,152,148,148,148,153, 44,
67, 67, 67, 67, 67, 55, 67, 67, 67, 67, 44, 44, 44, 44, 44, 44,
- 67, 67, 67, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 44, 44,
- 1, 2,154,155, 4, 4, 4, 4, 4, 67, 4, 4, 4, 4,156,157,
- 158,105,105,105,105, 43, 43, 86,159, 40, 40, 67,105,160, 63, 67,
- 36, 36, 36, 61, 57,161,162, 69, 36, 36, 36, 36, 36, 63, 40, 69,
- 44, 44, 62, 36, 36, 36, 36, 36, 67, 27, 27, 67, 67, 67, 67, 67,
+ 67, 67, 67, 44, 44, 44, 44, 44, 1, 2,154,155, 4, 4, 4, 4,
+ 4, 67, 4, 4, 4, 4,156,157,158,105,105,105,105, 43, 43, 86,
+ 159, 40, 40, 67,105,160, 63, 67, 36, 36, 36, 61, 57,161,162, 69,
+ 36, 36, 36, 36, 36, 63, 40, 69, 44, 44, 62, 36, 36, 36, 36, 36,
+ 67, 27, 27, 67, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44, 44, 55,
67, 67, 67, 67, 67, 67, 67, 92, 27, 27, 27, 27, 27, 67, 67, 67,
67, 67, 67, 67, 27, 27, 27, 27,163, 27, 27, 27, 27, 27, 27, 27,
36, 36, 83, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,164, 2,
@@ -3247,218 +3249,218 @@ _hb_ucd_u8[14744] =
44, 61, 44, 62, 62, 62, 62, 36, 62, 61, 61, 62, 62, 62, 62, 62,
62, 61, 61, 62, 36, 61, 36, 36, 36, 61, 36, 36, 62, 36, 61, 61,
36, 36, 36, 36, 36, 62, 36, 36, 62, 36, 62, 36, 36, 62, 36, 36,
- 8, 44, 44, 44, 44, 44, 44, 44, 55, 67, 67, 67, 67, 67, 67, 67,
- 27, 27, 27, 27, 27, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 44,
- 44, 44, 44, 67, 67, 67, 67, 67, 67, 92, 44, 44, 44, 44, 44, 44,
- 67, 67, 67, 67, 92, 44, 44, 44, 67, 44, 44, 44, 44, 44, 44, 44,
- 67, 67, 67, 67, 67, 25, 41, 41, 67, 67, 67, 67, 44, 44, 67, 67,
- 67, 67, 67, 92, 44, 55, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44,
- 67, 67, 67, 67, 67, 67, 67, 55, 67, 67, 67, 44, 44, 44, 44, 67,
- 67, 92, 67, 67, 67, 67, 67, 67, 79, 44, 44, 44, 44, 44, 44, 44,
- 171,171,171,171,171,171,171, 44,171,171,171,171,171,171,171, 0,
- 0, 0, 29, 21, 21, 21, 23, 21, 22, 18, 21, 25, 21, 17, 13, 13,
- 25, 25, 25, 21, 21, 9, 9, 9, 9, 22, 21, 18, 24, 16, 24, 5,
- 5, 5, 5, 22, 25, 18, 25, 0, 23, 23, 26, 21, 24, 26, 7, 20,
- 25, 1, 26, 24, 26, 25, 15, 15, 24, 15, 7, 19, 15, 21, 9, 25,
- 9, 5, 5, 25, 5, 9, 5, 7, 7, 7, 9, 8, 8, 5, 7, 5,
- 6, 6, 24, 24, 6, 24, 12, 12, 2, 2, 6, 5, 9, 21, 9, 2,
- 2, 9, 25, 9, 26, 12, 11, 11, 2, 6, 5, 21, 17, 2, 2, 26,
- 26, 23, 2, 12, 17, 12, 21, 12, 12, 21, 7, 2, 2, 7, 7, 21,
- 21, 2, 1, 1, 21, 23, 26, 26, 1, 21, 6, 7, 7, 12, 12, 7,
- 21, 7, 12, 1, 12, 6, 6, 12, 12, 26, 7, 26, 26, 7, 2, 1,
- 12, 2, 6, 2, 24, 7, 7, 6, 1, 12, 12, 10, 10, 10, 10, 12,
- 21, 6, 2, 10, 10, 2, 15, 26, 26, 2, 2, 21, 7, 10, 15, 7,
- 2, 23, 21, 26, 10, 7, 21, 15, 15, 2, 17, 7, 29, 7, 7, 22,
- 18, 2, 14, 14, 14, 7, 10, 21, 17, 21, 11, 12, 5, 2, 5, 6,
- 8, 8, 8, 24, 5, 24, 2, 24, 9, 24, 24, 2, 29, 29, 29, 1,
- 17, 17, 20, 19, 22, 20, 27, 28, 1, 29, 21, 20, 19, 21, 21, 16,
- 16, 21, 25, 22, 18, 21, 21, 29, 1, 2, 15, 6, 18, 6, 23, 2,
- 12, 11, 9, 26, 26, 9, 26, 5, 5, 26, 14, 9, 5, 14, 14, 15,
- 25, 26, 26, 22, 18, 26, 18, 25, 18, 22, 5, 12, 2, 5, 22, 21,
- 21, 22, 18, 17, 26, 6, 7, 14, 17, 22, 18, 18, 26, 14, 17, 6,
- 14, 6, 12, 24, 24, 6, 26, 15, 6, 21, 11, 21, 24, 9, 6, 9,
- 23, 26, 6, 10, 4, 4, 3, 3, 7, 25, 17, 16, 16, 22, 16, 16,
- 25, 17, 25, 2, 25, 24, 2, 15, 12, 15, 14, 2, 21, 14, 7, 15,
- 12, 17, 21, 1, 26, 10, 10, 1, 23, 15, 0, 1, 2, 3, 4, 5,
- 6, 7, 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0,
- 15, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 8, 44, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 44, 44,
+ 55, 67, 67, 67, 67, 67, 67, 67, 27, 27, 27, 27, 27, 27, 91, 67,
+ 67, 67, 67, 67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 67, 67, 67,
+ 67, 92, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 92, 44, 44, 44,
+ 67, 44, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 25, 41, 41,
+ 67, 67, 67, 67, 44, 44, 67, 67, 67, 67, 67, 92, 44, 55, 67, 67,
+ 67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 67, 55,
+ 67, 67, 67, 44, 44, 44, 44, 67, 67, 92, 67, 67, 67, 67, 67, 67,
+ 79, 44, 44, 44, 44, 44, 44, 44,171,171,171,171,171,171,171, 44,
+ 171,171,171,171,171,171,171, 0, 0, 0, 29, 21, 21, 21, 23, 21,
+ 22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21, 9, 9, 9,
+ 9, 22, 21, 18, 24, 16, 24, 5, 5, 5, 5, 22, 25, 18, 25, 0,
+ 23, 23, 26, 21, 24, 26, 7, 20, 25, 1, 26, 24, 26, 25, 15, 15,
+ 24, 15, 7, 19, 15, 21, 9, 25, 9, 5, 5, 25, 5, 9, 5, 7,
+ 7, 7, 9, 8, 8, 5, 7, 5, 6, 6, 24, 24, 6, 24, 12, 12,
+ 2, 2, 6, 5, 9, 21, 9, 2, 2, 9, 25, 9, 26, 12, 11, 11,
+ 2, 6, 5, 21, 17, 2, 2, 26, 26, 23, 2, 12, 17, 12, 21, 12,
+ 12, 21, 7, 2, 2, 7, 7, 21, 21, 2, 1, 1, 21, 23, 26, 26,
+ 1, 21, 6, 7, 7, 12, 12, 7, 21, 7, 12, 1, 12, 6, 6, 12,
+ 12, 26, 7, 26, 26, 7, 2, 1, 12, 2, 6, 2, 24, 7, 7, 6,
+ 1, 12, 12, 10, 10, 10, 10, 12, 21, 6, 2, 10, 10, 2, 15, 26,
+ 26, 2, 2, 21, 7, 10, 15, 7, 2, 23, 21, 26, 10, 7, 21, 15,
+ 15, 2, 17, 7, 29, 7, 7, 22, 18, 2, 14, 14, 14, 7, 10, 21,
+ 17, 21, 11, 12, 5, 2, 5, 6, 8, 8, 8, 24, 5, 24, 2, 24,
+ 9, 24, 24, 2, 29, 29, 29, 1, 17, 17, 20, 19, 22, 20, 27, 28,
+ 1, 29, 21, 20, 19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29,
+ 1, 2, 15, 6, 18, 6, 23, 2, 12, 11, 9, 26, 26, 9, 26, 5,
+ 5, 26, 14, 9, 5, 14, 14, 15, 25, 26, 26, 22, 18, 26, 18, 25,
+ 18, 22, 5, 12, 2, 5, 22, 21, 21, 22, 18, 17, 26, 6, 7, 14,
+ 17, 22, 18, 18, 26, 14, 17, 6, 14, 6, 12, 24, 24, 6, 26, 15,
+ 6, 21, 11, 21, 24, 9, 6, 9, 23, 26, 6, 10, 4, 4, 3, 3,
+ 7, 25, 17, 16, 16, 22, 16, 16, 25, 17, 25, 2, 25, 24, 2, 15,
+ 12, 15, 14, 2, 21, 14, 7, 15, 12, 17, 21, 1, 26, 10, 10, 1,
+ 23, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12,
+ 13, 0, 14, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19,
+ 0, 0, 0, 0, 0, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20,
+ 0, 21, 22, 23, 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 24,
- 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 35, 0, 36, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35,
- 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 38, 39, 0, 0, 0, 0, 0, 0, 40, 41, 42, 0, 43, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0,
- 0, 0, 3, 0, 0, 0, 4, 5, 6, 7, 0, 8, 9, 10, 0, 11,
- 12, 13, 14, 15, 16, 17, 16, 18, 16, 19, 16, 19, 16, 19, 0, 19,
- 16, 20, 16, 19, 21, 19, 0, 22, 23, 24, 25, 26, 27, 28, 29, 30,
- 31, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0,
- 0, 0, 0, 0, 34, 0, 0, 35, 0, 0, 36, 0, 37, 0, 0, 0,
- 38, 39, 40, 41, 42, 43, 44, 45, 46, 0, 0, 47, 0, 0, 0, 48,
- 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, 0, 52,
- 53, 0, 54, 0, 0, 0, 0, 0, 0, 55, 56, 57, 0, 0, 0, 0,
- 58, 0, 0, 59, 60, 61, 62, 63, 0, 0, 64, 65, 0, 0, 0, 66,
- 0, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 71, 0, 0,
- 72, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 0, 74, 0, 0, 0,
- 0, 0, 75, 76, 0, 77, 78, 0, 0, 79, 80, 0, 81, 62, 0, 82,
- 83, 0, 0, 84, 85, 86, 0, 0, 0, 87, 0, 88, 0, 0, 51, 89,
- 51, 0, 90, 0, 91, 0, 0, 0, 80, 0, 0, 0, 92, 93, 0, 94,
- 95, 96, 97, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 98, 99, 0,
- 0, 0, 0, 0, 0,100, 0, 0, 0, 0, 0,101,102, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,103, 0, 0,104, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,105,106, 0, 0,107, 0, 0, 0, 0, 0, 0,
- 108, 0,109, 0,102, 0, 0, 0, 0, 0,110,111, 0, 0, 0, 0,
- 0, 0, 0,112, 0, 0, 0, 0, 0, 0, 0,113, 0,114, 0, 0,
- 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, 8, 0, 0, 0,
- 0, 9, 10, 11, 12, 0, 0, 0, 0, 13, 0, 0, 14, 15, 0, 16,
- 0, 17, 18, 0, 0, 19, 0, 20, 21, 0, 0, 0, 0, 0, 22, 23,
- 0, 24, 25, 0, 0, 26, 0, 0, 0, 27, 0, 0, 28, 29, 30, 31,
- 0, 0, 0, 32, 33, 34, 0, 0, 33, 0, 0, 35, 33, 0, 0, 0,
- 33, 36, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 39,
- 40, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 43, 0, 44,
- 0, 0, 0, 45, 46, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 48,
- 49, 0, 0, 0, 0, 50, 0, 0, 0, 51, 0, 52, 0, 53, 0, 0,
- 0, 0, 54, 0, 0, 0, 0, 55, 0, 56, 0, 0, 0, 0, 57, 58,
- 0, 0, 0, 59, 60, 0, 0, 0, 0, 0, 0, 61, 52, 0, 62, 63,
- 0, 0, 64, 0, 0, 0, 65, 66, 0, 0, 0, 67, 0, 68, 69, 70,
- 71, 72, 1, 73, 0, 74, 75, 76, 0, 0, 77, 78, 0, 0, 0, 79,
- 0, 0, 1, 1, 0, 0, 80, 0, 0, 81, 0, 0, 0, 0, 77, 82,
- 0, 83, 0, 0, 0, 0, 0, 78, 84, 0, 85, 0, 52, 0, 1, 78,
- 0, 0, 86, 0, 0, 87, 0, 0, 0, 0, 0, 88, 57, 0, 0, 0,
- 0, 0, 0, 89, 90, 0, 0, 84, 0, 0, 33, 0, 0, 91, 0, 0,
- 0, 0, 92, 0, 0, 0, 0, 49, 0, 0, 93, 0, 0, 0, 0, 94,
- 95, 0, 0, 96, 0, 0, 97, 0, 0, 0, 98, 0, 0, 0, 99, 0,
- 0, 0, 0,100,101, 93, 0, 0,102, 0, 0, 0, 84, 0, 0,103,
- 0, 0, 0,104,105, 0, 0,106,107, 0, 0, 0, 0, 0, 0,108,
- 0, 0,109, 0, 0, 0, 0,110, 33, 0,111,112,113, 35, 0, 0,
- 114, 0, 0, 0,115, 0, 0, 0, 0, 0, 0,116, 0, 0,117, 0,
- 0, 0, 0,118, 88, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 52,
- 119, 0, 0, 0, 0,120, 0, 0,121, 0, 0, 0, 0,119, 0, 0,
- 122, 0, 0, 0, 0, 0, 0,123, 0, 0, 0,124, 0, 0, 0,125,
- 0,126, 0, 0, 0, 0,127,128,129, 0,130, 0,131, 0, 0, 0,
- 132,133,134, 0, 77, 0, 0, 0, 0, 0, 35, 0, 0, 0,135, 0,
- 0, 0,136, 0, 0,137, 0, 0,138, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 4, 4, 8, 9, 10,
- 1, 11, 12, 13, 14, 15, 16, 17, 18, 1, 1, 1, 19, 1, 0, 0,
- 20, 21, 22, 1, 23, 4, 21, 24, 25, 26, 27, 28, 29, 30, 0, 0,
- 1, 1, 31, 0, 0, 0, 32, 33, 34, 35, 1, 36, 37, 0, 0, 0,
- 0, 38, 1, 39, 14, 39, 40, 41, 42, 0, 0, 0, 43, 36, 44, 45,
- 21, 45, 46, 0, 0, 0, 19, 1, 21, 0, 0, 47, 0, 38, 48, 1,
- 1, 49, 49, 50, 0, 0, 51, 0, 0, 0, 52, 1, 0, 0, 38, 14,
- 4, 1, 1, 1, 53, 21, 43, 52, 54, 21, 35, 1, 0, 0, 0, 55,
- 0, 0, 0, 56, 57, 58, 0, 0, 0, 0, 0, 59, 0, 60, 0, 0,
- 0, 0, 61, 62, 0, 0, 63, 0, 0, 0, 64, 0, 0, 0, 65, 0,
- 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 69, 70, 0,
- 71, 72, 73, 74, 75, 76, 0, 0, 0, 77, 0, 0, 0, 78, 79, 0,
- 0, 0, 0, 47, 0, 0, 0, 49, 0, 80, 0, 0, 0, 62, 0, 0,
- 63, 0, 0, 81, 0, 0, 82, 0, 0, 0, 83, 0, 0, 19, 84, 0,
- 62, 0, 0, 0, 0, 49, 1, 85, 1, 52, 15, 86, 36, 10, 21, 87,
- 0, 55, 0, 0, 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 88, 0,
- 0, 89, 0, 0, 88, 0, 0, 0, 0, 78, 0, 0, 87, 9, 12, 4,
- 90, 8, 91, 47, 0, 58, 50, 0, 21, 1, 21, 92, 93, 1, 1, 1,
- 1, 94, 95, 96, 97, 1, 98, 58, 81, 99,100, 4, 58, 0, 0, 0,
- 0, 0, 0, 19, 50, 0, 0, 0, 0, 0, 0, 61, 0, 0,101,102,
- 0, 0,103, 0, 0, 1, 1, 50, 0, 0, 0, 38, 0, 63, 0, 0,
- 0, 0, 0, 62, 0, 0,104, 68, 61, 0, 0, 0, 78, 0, 0, 0,
- 105,106, 58, 38, 81, 0, 0, 0, 0, 0, 0,107, 1, 14, 4, 12,
- 84, 0, 0, 0, 0, 38, 87, 0, 0, 0, 0,108, 0, 0,109, 61,
- 0,110, 0, 0, 0, 1, 0, 0, 0, 0, 19, 58, 0, 0, 0, 51,
- 0,111, 14, 52,112, 41, 0, 0, 62, 0, 0, 61, 0, 0,113, 0,
- 87, 0, 0, 0, 61, 62, 0, 0, 62, 0, 89, 0, 0,113, 0, 0,
- 0, 0,114, 0, 0, 0, 78, 55, 0, 38, 1, 58, 1, 58, 0, 0,
- 63, 89, 0, 0,115, 0, 0, 0, 55, 0, 0, 0, 0,115, 0, 0,
- 0, 0, 61, 0, 0, 0, 0, 79, 0, 61, 0, 0, 0, 0, 56, 0,
- 89, 80, 0, 0, 79, 0, 0, 0, 8, 91, 0, 0, 1, 87, 0, 0,
- 116, 0, 0, 0, 0, 0, 0,117, 0,118,119,120,121, 0,104, 4,
- 122, 49, 23, 0, 0, 0, 38, 50, 38, 58, 0, 0, 1, 87, 1, 1,
- 1, 1, 39, 1, 48,105, 87, 0, 0, 0, 0, 1, 0, 0, 0,123,
- 4,122, 0, 0, 0, 1,124, 0, 0, 0, 0, 0,230,230,230,230,
- 230,232,220,220,220,220,232,216,220,220,220,220,220,202,202,220,
- 220,220,220,202,202,220,220,220, 1, 1, 1, 1, 1,220,220,220,
- 220,230,230,230,230,240,230,220,220,220,230,230,230,220,220, 0,
- 230,230,230,220,220,220,220,230,232,220,220,230,233,234,234,233,
- 234,234,233,230, 0, 0, 0,230, 0,220,230,230,230,230,220,230,
- 230,230,222,220,230,230,220,220,230,222,228,230, 10, 11, 12, 13,
- 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, 25, 0,
- 230,220, 0, 18, 30, 31, 32, 0, 0, 0, 0, 27, 28, 29, 30, 31,
- 32, 33, 34,230,230,220,220,230,220,230,230,220, 35, 0, 0, 0,
- 0, 0,230,230,230, 0, 0,230,230, 0,220,230,230,220, 0, 0,
- 0, 36, 0, 0,230,220,230,230,220,220,230,220,220,230,220,230,
- 220,230,230, 0, 0,220, 0, 0,230,230, 0,230, 0,230,230,230,
- 230,230, 0, 0, 0,220,220,220,230,220,220,220,230,230, 0,220,
- 27, 28, 29,230, 7, 0, 0, 0, 0, 9, 0, 0, 0,230,220,230,
- 230, 0, 0, 0, 0, 0,230, 0, 0, 84, 91, 0, 0, 0, 0, 9,
- 9, 0, 0, 0, 0, 0, 9, 0,103,103, 9, 0,107,107,107,107,
- 118,118, 9, 0,122,122,122,122,220,220, 0, 0, 0,220, 0,220,
- 0,216, 0, 0, 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130,
- 130,130, 0, 0,130, 0,230,230, 9, 0,230,230, 0, 0,220, 0,
- 0, 0, 0, 7, 0, 9, 9, 0, 9, 9, 0, 0, 0,230, 0, 0,
- 0,228, 0, 0, 0,222,230,220,220, 0, 0, 0,230, 0, 0,220,
- 230,220, 0,220,230,230,230, 0, 0, 0, 9, 9, 0, 0, 7, 0,
- 230, 0, 1, 1, 1, 0, 0, 0,230,234,214,220,202,230,230,230,
- 230,230,232,228,228,220,218,230,233,220,230,220,230,230, 1, 1,
- 1, 1, 1,230, 0, 1, 1,230,220,230, 1, 1, 0, 0,218,228,
- 232,222,224,224, 0, 8, 8, 0, 0, 0, 0,220,230, 0,230,230,
- 220, 0, 0,230, 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0,
- 0,230,220, 0, 0, 0,220,220, 0, 0,230,220, 0, 9, 7, 0,
- 0, 7, 9, 0, 0, 0, 9, 7, 6, 6, 0, 0, 0, 0, 1, 0,
- 0,216,216, 1, 1, 1, 0, 0, 0,226,216,216,216,216,216, 0,
- 220,220,220, 0,232,232,220,230,230,230, 7, 0, 16, 17, 17, 33,
- 17, 49, 17, 17, 84, 97,135,145, 26, 17, 17, 17, 17, 17, 17, 17,
+ 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39, 0, 0, 0, 0,
+ 0, 0, 40, 41, 42, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, 4, 5,
+ 6, 7, 0, 8, 9, 10, 0, 11, 12, 13, 14, 15, 16, 17, 16, 18,
+ 16, 19, 16, 19, 16, 19, 0, 19, 16, 20, 16, 19, 21, 19, 0, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 32, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 35,
+ 0, 0, 36, 0, 37, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45,
+ 46, 0, 0, 47, 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, 0,
+ 0, 0, 0, 50, 0, 51, 0, 52, 53, 0, 54, 0, 0, 0, 0, 0,
+ 0, 55, 56, 57, 0, 0, 0, 0, 58, 0, 0, 59, 60, 61, 62, 63,
+ 0, 0, 64, 65, 0, 0, 0, 66, 0, 0, 0, 0, 67, 0, 0, 0,
+ 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69,
+ 0, 0, 0, 70, 0, 71, 0, 0, 72, 0, 0, 73, 0, 0, 0, 0,
+ 0, 0, 0, 0, 74, 0, 0, 0, 0, 0, 75, 76, 0, 77, 78, 0,
+ 0, 79, 80, 0, 81, 62, 0, 82, 83, 0, 0, 84, 85, 86, 0, 0,
+ 0, 87, 0, 88, 0, 0, 51, 89, 51, 0, 90, 0, 91, 0, 0, 0,
+ 80, 0, 0, 0, 92, 93, 0, 94, 95, 96, 97, 0, 0, 0, 0, 0,
+ 51, 0, 0, 0, 0, 98, 99, 0, 0, 0, 0, 0, 0,100, 0, 0,
+ 0, 0, 0,101,102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,103,
+ 0, 0,104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105,106, 0,
+ 0,107, 0, 0, 0, 0, 0, 0,108, 0,109, 0,102, 0, 0, 0,
+ 0, 0,110,111, 0, 0, 0, 0, 0, 0, 0,112, 0, 0, 0, 0,
+ 0, 0, 0,113, 0,114, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
+ 5, 6, 7, 0, 8, 0, 0, 0, 0, 9, 10, 11, 12, 0, 0, 0,
+ 0, 13, 0, 0, 14, 15, 0, 16, 0, 17, 18, 0, 0, 19, 0, 20,
+ 21, 0, 0, 0, 0, 0, 22, 23, 0, 24, 25, 0, 0, 26, 0, 0,
+ 0, 27, 0, 0, 28, 29, 30, 31, 0, 0, 0, 32, 33, 34, 0, 0,
+ 33, 0, 0, 35, 33, 0, 0, 0, 33, 36, 0, 0, 0, 0, 0, 37,
+ 38, 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 41,
+ 42, 0, 0, 0, 0, 43, 0, 44, 0, 0, 0, 45, 46, 0, 0, 0,
+ 47, 0, 0, 0, 0, 0, 0, 48, 49, 0, 0, 0, 0, 50, 0, 0,
+ 0, 51, 0, 52, 0, 53, 0, 0, 0, 0, 54, 0, 0, 0, 0, 55,
+ 0, 56, 0, 0, 0, 0, 57, 58, 0, 0, 0, 59, 60, 0, 0, 0,
+ 0, 0, 0, 61, 52, 0, 62, 63, 0, 0, 64, 0, 0, 0, 65, 66,
+ 0, 0, 0, 67, 0, 68, 69, 70, 71, 72, 1, 73, 0, 74, 75, 76,
+ 0, 0, 77, 78, 0, 0, 0, 79, 0, 0, 1, 1, 0, 0, 80, 0,
+ 0, 81, 0, 0, 0, 0, 77, 82, 0, 83, 0, 0, 0, 0, 0, 78,
+ 84, 0, 85, 0, 52, 0, 1, 78, 0, 0, 86, 0, 0, 87, 0, 0,
+ 0, 0, 0, 88, 57, 0, 0, 0, 0, 0, 0, 89, 90, 0, 0, 84,
+ 0, 0, 33, 0, 0, 91, 0, 0, 0, 0, 92, 0, 0, 0, 0, 49,
+ 0, 0, 93, 0, 0, 0, 0, 94, 95, 0, 0, 96, 0, 0, 97, 0,
+ 0, 0, 98, 0, 0, 0, 99, 0, 0, 0, 0,100,101, 93, 0, 0,
+ 102, 0, 0, 0, 84, 0, 0,103, 0, 0, 0,104,105, 0, 0,106,
+ 107, 0, 0, 0, 0, 0, 0,108, 0, 0,109, 0, 0, 0, 0,110,
+ 33, 0,111,112,113, 35, 0, 0,114, 0, 0, 0,115, 0, 0, 0,
+ 0, 0, 0,116, 0, 0,117, 0, 0, 0, 0,118, 88, 0, 0, 0,
+ 0, 0, 57, 0, 0, 0, 0, 52,119, 0, 0, 0, 0,120, 0, 0,
+ 121, 0, 0, 0, 0,119, 0, 0,122, 0, 0, 0, 0, 0, 0,123,
+ 0, 0, 0,124, 0, 0, 0,125, 0,126, 0, 0, 0, 0,127,128,
+ 129, 0,130, 0,131, 0, 0, 0,132,133,134, 0, 77, 0, 0, 0,
+ 0, 0, 35, 0, 0, 0,135, 0, 0, 0,136, 0, 0,137, 0, 0,
+ 138, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 4,
+ 5, 6, 7, 4, 4, 8, 9, 10, 1, 11, 12, 13, 14, 15, 16, 17,
+ 18, 1, 1, 1, 19, 1, 0, 0, 20, 21, 22, 1, 23, 4, 21, 24,
+ 25, 26, 27, 28, 29, 30, 0, 0, 1, 1, 31, 0, 0, 0, 32, 33,
+ 34, 35, 1, 36, 37, 0, 0, 0, 0, 38, 1, 39, 14, 39, 40, 41,
+ 42, 0, 0, 0, 43, 36, 44, 45, 21, 45, 46, 0, 0, 0, 19, 1,
+ 21, 0, 0, 47, 0, 38, 48, 1, 1, 49, 49, 50, 0, 0, 51, 0,
+ 0, 0, 52, 1, 0, 0, 38, 14, 4, 1, 1, 1, 53, 21, 43, 52,
+ 54, 21, 35, 1, 0, 0, 0, 55, 0, 0, 0, 56, 57, 58, 0, 0,
+ 0, 0, 0, 59, 0, 60, 0, 0, 0, 0, 61, 62, 0, 0, 63, 0,
+ 0, 0, 64, 0, 0, 0, 65, 0, 0, 0, 66, 0, 0, 0, 67, 0,
+ 0, 0, 68, 0, 0, 69, 70, 0, 71, 72, 73, 74, 75, 76, 0, 0,
+ 0, 77, 0, 0, 0, 78, 79, 0, 0, 0, 0, 47, 0, 0, 0, 49,
+ 0, 80, 0, 0, 0, 62, 0, 0, 63, 0, 0, 81, 0, 0, 82, 0,
+ 0, 0, 83, 0, 0, 19, 84, 0, 62, 0, 0, 0, 0, 49, 1, 85,
+ 1, 52, 15, 86, 36, 10, 21, 87, 0, 55, 0, 0, 0, 0, 19, 10,
+ 1, 0, 0, 0, 0, 0, 88, 0, 0, 89, 0, 0, 88, 0, 0, 0,
+ 0, 78, 0, 0, 87, 9, 12, 4, 90, 8, 91, 47, 0, 58, 50, 0,
+ 21, 1, 21, 92, 93, 1, 1, 1, 1, 94, 95, 96, 97, 1, 98, 58,
+ 81, 99,100, 4, 58, 0, 0, 0, 0, 0, 0, 19, 50, 0, 0, 0,
+ 0, 0, 0, 61, 0, 0,101,102, 0, 0,103, 0, 0, 1, 1, 50,
+ 0, 0, 0, 38, 0, 63, 0, 0, 0, 0, 0, 62, 0, 0,104, 68,
+ 61, 0, 0, 0, 78, 0, 0, 0,105,106, 58, 38, 81, 0, 0, 0,
+ 0, 0, 0,107, 1, 14, 4, 12, 84, 0, 0, 0, 0, 38, 87, 0,
+ 0, 0, 0,108, 0, 0,109, 61, 0,110, 0, 0, 0, 1, 0, 0,
+ 0, 0, 19, 58, 0, 0, 0, 51, 0,111, 14, 52,112, 41, 0, 0,
+ 62, 0, 0, 61, 0, 0,113, 0, 87, 0, 0, 0, 61, 62, 0, 0,
+ 62, 0, 89, 0, 0,113, 0, 0, 0, 0,114, 0, 0, 0, 78, 55,
+ 0, 38, 1, 58, 1, 58, 0, 0, 63, 89, 0, 0,115, 0, 0, 0,
+ 55, 0, 0, 0, 0,115, 0, 0, 0, 0, 61, 0, 0, 0, 0, 79,
+ 0, 61, 0, 0, 0, 0, 56, 0, 89, 80, 0, 0, 79, 0, 0, 0,
+ 8, 91, 0, 0, 1, 87, 0, 0,116, 0, 0, 0, 0, 0, 0,117,
+ 0,118,119,120,121, 0,104, 4,122, 49, 23, 0, 0, 0, 38, 50,
+ 38, 58, 0, 0, 1, 87, 1, 1, 1, 1, 39, 1, 48,105, 87, 0,
+ 0, 0, 0, 1, 0, 0, 0,123, 4,122, 0, 0, 0, 1,124, 0,
+ 0, 0, 0, 0,230,230,230,230,230,232,220,220,220,220,232,216,
+ 220,220,220,220,220,202,202,220,220,220,220,202,202,220,220,220,
+ 1, 1, 1, 1, 1,220,220,220,220,230,230,230,230,240,230,220,
+ 220,220,230,230,230,220,220, 0,230,230,230,220,220,220,220,230,
+ 232,220,220,230,233,234,234,233,234,234,233,230, 0, 0, 0,230,
+ 0,220,230,230,230,230,220,230,230,230,222,220,230,230,220,220,
+ 230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20,
+ 21, 22, 0, 23, 0, 24, 25, 0,230,220, 0, 18, 30, 31, 32, 0,
+ 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34,230,230,220,220,230,
+ 220,230,230,220, 35, 0, 0, 0, 0, 0,230,230,230, 0, 0,230,
+ 230, 0,220,230,230,220, 0, 0, 0, 36, 0, 0,230,220,230,230,
+ 220,220,230,220,220,230,220,230,220,230,230, 0, 0,220, 0, 0,
+ 230,230, 0,230, 0,230,230,230,230,230, 0, 0, 0,220,220,220,
+ 230,220,220,220,230,230, 0,220, 27, 28, 29,230, 7, 0, 0, 0,
+ 0, 9, 0, 0, 0,230,220,230,230, 0, 0, 0, 0, 0,230, 0,
+ 0, 84, 91, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 9, 0,
+ 103,103, 9, 0,107,107,107,107,118,118, 9, 0,122,122,122,122,
+ 220,220, 0, 0, 0,220, 0,220, 0,216, 0, 0, 0,129,130, 0,
+ 132, 0, 0, 0, 0, 0,130,130,130,130, 0, 0,130, 0,230,230,
+ 9, 0,230,230, 0, 0,220, 0, 0, 0, 0, 7, 0, 9, 9, 0,
+ 9, 9, 0, 0, 0,230, 0, 0, 0,228, 0, 0, 0,222,230,220,
+ 220, 0, 0, 0,230, 0, 0,220,230,220, 0,220,230,230,230, 0,
+ 0, 0, 9, 9, 0, 0, 7, 0,230, 0, 1, 1, 1, 0, 0, 0,
+ 230,234,214,220,202,230,230,230,230,230,232,228,228,220,218,230,
+ 233,220,230,220,230,230, 1, 1, 1, 1, 1,230, 0, 1, 1,230,
+ 220,230, 1, 1, 0, 0,218,228,232,222,224,224, 0, 8, 8, 0,
+ 0, 0, 0,220,230, 0,230,230,220, 0, 0,230, 0, 0, 26, 0,
+ 0,220, 0,230,230, 1,220, 0, 0,230,220, 0, 0, 0,220,220,
+ 0, 0,230,220, 0, 9, 7, 0, 0, 7, 9, 0, 0, 0, 9, 7,
+ 6, 6, 0, 0, 0, 0, 1, 0, 0,216,216, 1, 1, 1, 0, 0,
+ 0,226,216,216,216,216,216, 0,220,220,220, 0,232,232,220,230,
+ 230,230, 7, 0, 16, 17, 17, 33, 17, 49, 17, 17, 84, 97,135,145,
+ 26, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,177, 0, 1, 2, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 4, 3, 3, 3, 3, 3, 5, 3, 3, 3, 3, 3, 6, 7, 8, 3,
- 3, 3, 3, 3, 9, 10, 11, 12, 13, 3, 3, 3, 3, 3, 3, 3,
- 3, 14, 3, 15, 3, 3, 3, 3, 3, 3, 16, 17, 18, 19, 20, 21,
- 3, 3, 3, 22, 23, 24, 3, 3, 3, 3, 3, 3, 25, 3, 3, 3,
- 3, 3, 3, 3, 3, 26, 3, 3, 27, 28, 0, 1, 0, 0, 0, 0,
- 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0,
- 0, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, 9, 0, 9, 0, 0,
- 0, 0, 0, 0, 0, 10, 11, 12, 13, 0, 0, 14, 15, 16, 6, 0,
- 17, 18, 19, 19, 19, 20, 21, 22, 23, 24, 19, 25, 0, 26, 27, 19,
- 19, 28, 29, 30, 0, 31, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0,
- 0, 19, 28, 0, 32, 33, 9, 34, 35, 19, 0, 0, 36, 37, 38, 39,
- 40, 19, 0, 41, 42, 43, 44, 31, 0, 1, 45, 42, 0, 0, 0, 0,
- 0, 32, 14, 14, 0, 0, 0, 0, 14, 0, 0, 46, 47, 47, 47, 47,
- 48, 49, 47, 47, 47, 47, 50, 51, 52, 53, 43, 21, 0, 0, 0, 0,
- 0, 0, 0, 54, 6, 55, 0, 14, 19, 1, 0, 0, 0, 0, 56, 57,
- 0, 0, 0, 0, 0, 19, 58, 31, 0, 0, 0, 0, 0, 0, 0, 59,
- 14, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 60,
- 61, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 3,
- 0, 4, 5, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 1, 1, 0,
- 0, 8, 9, 0, 8, 9, 0, 0, 0, 0, 8, 9, 10, 11, 12, 0,
- 0, 0, 13, 0, 0, 0, 0, 14, 15, 16, 17, 0, 0, 0, 1, 0,
- 0, 18, 19, 0, 0, 0, 20, 0, 0, 0, 1, 1, 1, 1, 0, 1,
- 1, 1, 1, 1, 1, 1, 0, 8, 21, 9, 0, 0, 22, 0, 0, 0,
- 0, 1, 0, 23, 24, 25, 0, 0, 26, 0, 0, 0, 8, 21, 27, 0,
- 1, 0, 0, 1, 1, 1, 1, 0, 1, 28, 29, 30, 0, 31, 32, 20,
- 1, 1, 0, 0, 0, 8, 21, 9, 1, 4, 5, 0, 0, 0, 33, 9,
- 0, 1, 1, 1, 0, 8, 21, 21, 21, 21, 34, 1, 35, 21, 21, 21,
- 9, 36, 0, 0, 37, 38, 1, 0, 39, 0, 0, 0, 1, 0, 1, 0,
- 0, 0, 0, 8, 21, 9, 1, 0, 0, 0, 40, 0, 8, 21, 21, 21,
- 21, 21, 21, 21, 21, 9, 0, 1, 1, 1, 1, 8, 21, 21, 21, 9,
- 0, 0, 0, 41, 0, 42, 43, 0, 0, 0, 1, 44, 0, 0, 0, 45,
- 8, 9, 1, 0, 0, 0, 8, 21, 21, 21, 9, 0, 1, 0, 1, 1,
- 8, 21, 21, 9, 0, 4, 5, 8, 9, 1, 0, 0, 0, 1, 2, 3,
- 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 9, 10, 11, 11, 11, 11, 12, 13, 13, 13, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 13, 22, 13, 13, 13, 13, 23, 24, 24, 25, 26, 13, 13,
- 13, 27, 28, 29, 13, 30, 31, 32, 33, 34, 35, 36, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 37, 7, 38, 39, 7, 40, 7, 7, 7, 41, 13, 42, 7, 7, 43, 7,
- 44, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 17, 17, 17,177, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 5, 3,
+ 3, 3, 3, 3, 6, 7, 8, 3, 3, 3, 3, 3, 9, 10, 11, 12,
+ 13, 3, 3, 3, 3, 3, 3, 3, 3, 14, 3, 15, 3, 3, 3, 3,
+ 3, 3, 16, 17, 18, 19, 20, 21, 3, 3, 3, 22, 23, 24, 3, 3,
+ 3, 3, 3, 3, 25, 3, 3, 3, 3, 3, 3, 3, 3, 26, 3, 3,
+ 27, 28, 0, 1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 3,
+ 0, 0, 0, 3, 0, 0, 0, 0, 0, 4, 0, 5, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 7,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0,
+ 0, 0, 0, 9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12,
+ 13, 0, 0, 14, 15, 16, 6, 0, 17, 18, 19, 19, 19, 20, 21, 22,
+ 23, 24, 19, 25, 0, 26, 27, 19, 19, 28, 29, 30, 0, 31, 0, 0,
+ 0, 8, 0, 0, 0, 0, 0, 0, 0, 19, 28, 0, 32, 33, 9, 34,
+ 35, 19, 0, 0, 36, 37, 38, 39, 40, 19, 0, 41, 42, 43, 44, 31,
+ 0, 1, 45, 42, 0, 0, 0, 0, 0, 32, 14, 14, 0, 0, 0, 0,
+ 14, 0, 0, 46, 47, 47, 47, 47, 48, 49, 47, 47, 47, 47, 50, 51,
+ 52, 53, 43, 21, 0, 0, 0, 0, 0, 0, 0, 54, 6, 55, 0, 14,
+ 19, 1, 0, 0, 0, 0, 56, 57, 0, 0, 0, 0, 0, 19, 58, 31,
+ 0, 0, 0, 0, 0, 0, 0, 59, 14, 0, 0, 0, 0, 1, 0, 2,
+ 0, 0, 0, 3, 0, 0, 0, 60, 61, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 2, 3, 0, 4, 5, 0, 0, 6, 0, 0,
+ 0, 7, 0, 0, 0, 1, 1, 0, 0, 8, 9, 0, 8, 9, 0, 0,
+ 0, 0, 8, 9, 10, 11, 12, 0, 0, 0, 13, 0, 0, 0, 0, 14,
+ 15, 16, 17, 0, 0, 0, 1, 0, 0, 18, 19, 0, 0, 0, 20, 0,
+ 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 8,
+ 21, 9, 0, 0, 22, 0, 0, 0, 0, 1, 0, 23, 24, 25, 0, 0,
+ 26, 0, 0, 0, 8, 21, 27, 0, 1, 0, 0, 1, 1, 1, 1, 0,
+ 1, 28, 29, 30, 0, 31, 32, 20, 1, 1, 0, 0, 0, 8, 21, 9,
+ 1, 4, 5, 0, 0, 0, 33, 9, 0, 1, 1, 1, 0, 8, 21, 21,
+ 21, 21, 34, 1, 35, 21, 21, 21, 9, 36, 0, 0, 37, 38, 1, 0,
+ 39, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 8, 21, 9, 1, 0,
+ 0, 0, 40, 0, 8, 21, 21, 21, 21, 21, 21, 21, 21, 9, 0, 1,
+ 1, 1, 1, 8, 21, 21, 21, 9, 0, 0, 0, 41, 0, 42, 43, 0,
+ 0, 0, 1, 44, 0, 0, 0, 45, 8, 9, 1, 0, 0, 0, 8, 21,
+ 21, 21, 9, 0, 1, 0, 1, 1, 8, 21, 21, 9, 0, 4, 5, 8,
+ 9, 1, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 9, 10, 11, 11, 11, 11, 12, 13,
+ 13, 13, 13, 14, 15, 16, 17, 18, 19, 20, 21, 13, 22, 13, 13, 13,
+ 13, 23, 24, 24, 25, 26, 13, 13, 13, 27, 28, 29, 13, 30, 31, 32,
+ 33, 34, 35, 36, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 37, 7, 38, 39, 7, 40, 7, 7,
+ 7, 41, 13, 42, 7, 7, 43, 7, 44, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
@@ -3479,221 +3481,221 @@ _hb_ucd_u8[14744] =
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 45, 0, 0, 1,
- 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 32, 33, 34, 35, 36, 37, 37, 37, 37, 37, 38, 39, 40, 41, 42,
- 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 2, 2, 53, 54, 55, 56,
- 57, 58, 59, 59, 59, 59, 60, 59, 59, 59, 59, 59, 59, 59, 61, 61,
- 59, 59, 59, 59, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
- 74, 75, 76, 77, 78, 59, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 45, 0, 0, 1, 2, 2, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, 32, 33, 34, 35, 36, 37, 37,
+ 37, 37, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 2, 2, 53, 54, 55, 56, 57, 58, 59, 59, 59, 59, 60, 59,
+ 59, 59, 59, 59, 59, 59, 61, 61, 59, 59, 59, 59, 62, 63, 64, 65,
+ 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 59, 70, 70,
70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 79, 70, 70, 70, 70, 80, 80,
- 80, 80, 80, 80, 80, 80, 80, 81, 82, 82, 83, 84, 85, 86, 87, 88,
- 89, 90, 91, 92, 93, 94, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 79, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 80, 80, 80, 81,
+ 82, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 95, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 70, 70, 97, 98, 99,100,101,101,102,103,104,105,106,107,108,109,
- 110,111, 96,112,113,114,115,116,117,118,119,119,120,121,122,123,
- 124,125,126,127,128,129,130,131,132, 96,133,134,135,136,137,138,
- 139,140,141,142,143, 96,144,145, 96,146,147,148,149, 96,150,151,
- 152,153,154,155,156, 96,157,158,159,160, 96,161,162,163,164,164,
- 164,164,164,164,164,165,166,164,167, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,168,169,169,
- 169,169,169,169,169,169,170, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96,171,171,171,171,172, 96, 96, 96,173,173,
- 173,173,174,175,176,177, 96, 96, 96, 96,178,179,180,181,182,182,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 95, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 70, 70, 97, 98, 99,100,101,101,
+ 102,103,104,105,106,107,108,109,110,111, 96,112,113,114,115,116,
+ 117,118,119,119,120,121,122,123,124,125,126,127,128,129,130,131,
+ 132, 96,133,134,135,136,137,138,139,140,141,142,143, 96,144,145,
+ 96,146,147,148,149, 96,150,151,152,153,154,155,156, 96,157,158,
+ 159,160, 96,161,162,163,164,164,164,164,164,164,164,165,166,164,
+ 167, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96,168,169,169,169,169,169,169,169,169,170, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,171,171,
+ 171,171,172, 96, 96, 96,173,173,173,173,174,175,176,177, 96, 96,
+ 96, 96,178,179,180,181,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,182,183,182,182,
- 182,182,182,182,184,184,184,185,186, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,187,188,189,
- 190,191,191,192, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96,193,194, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,195,196, 59,197,
- 198,199,200,201,202, 96,203,204,205, 59, 59,206, 59,207,208,208,
- 208,208,208,209, 96, 96, 96, 96, 96, 96, 96, 96,210, 96,211,212,
- 213, 96, 96,214, 96, 96, 96,215, 96, 96, 96, 96, 96,216,217,218,
- 219, 96, 96, 96, 96, 96,220,221,222, 96,223,224, 96, 96,225,226,
- 59,227,228, 96, 59, 59, 59, 59, 59, 59, 59,229,230,231,232,233,
- 59, 59,234,235, 59,236, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,237, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,238, 70,239, 70,
+ 182,182,182,182,182,183,182,182,182,182,182,182,184,184,184,185,
+ 186, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96,187,188,189,190,191,191,192, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,193,194,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96,195,196, 59,197,198,199,200,201,202, 96,203,204,
+ 205, 59, 59,206, 59,207,208,208,208,208,208,209, 96, 96, 96, 96,
+ 96, 96, 96, 96,210, 96,211,212,213, 96, 96,214, 96, 96, 96,215,
+ 96, 96, 96, 96, 96,216,217,218,219, 96, 96, 96, 96, 96,220,221,
+ 222, 96,223,224, 96, 96,225,226, 59,227,228, 96, 59, 59, 59, 59,
+ 59, 59, 59,229,230,231,232,233, 59, 59,234,235, 59,236, 96, 96,
+ 96, 96, 96, 96, 96, 96, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70,237, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70,238, 70,239, 70, 70, 70, 70, 70, 70, 70, 70, 70,
70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,240, 70, 70, 70, 70,
- 70, 70, 70, 70, 70,241, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
- 70, 70,242, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
- 70, 70, 70, 70,243, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70,244, 96, 96, 96, 96, 96, 96, 96, 96,245, 96,
- 246,247, 0, 1, 2, 2, 0, 1, 2, 2, 2, 3, 4, 5, 0, 0,
- 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0,
- 19, 0, 19, 0, 0, 0, 0, 0, 26, 26, 1, 1, 1, 1, 9, 9,
- 9, 9, 0, 9, 9, 9, 2, 2, 9, 9, 9, 9, 0, 9, 2, 2,
- 2, 2, 9, 0, 9, 0, 9, 9, 9, 2, 9, 2, 9, 9, 9, 9,
- 2, 9, 9, 9, 55, 55, 55, 55, 55, 55, 6, 6, 6, 6, 6, 1,
- 1, 6, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 14,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 2, 2, 2, 14, 14, 2,
- 2, 2, 3, 3, 3, 3, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3,
- 3, 0, 3, 3, 3, 1, 1, 1, 3, 3, 1, 3, 3, 3, 37, 37,
- 37, 37, 37, 37, 2, 37, 37, 37, 37, 2, 2, 37, 37, 37, 38, 38,
- 38, 38, 38, 38, 2, 2, 64, 64, 64, 64, 64, 64, 64, 2, 2, 64,
- 64, 64, 90, 90, 90, 90, 90, 90, 2, 2, 90, 90, 90, 2, 95, 95,
- 95, 95, 2, 2, 95, 2, 3, 3, 3, 2, 3, 3, 2, 2, 3, 3,
- 0, 3, 7, 7, 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 0, 0,
- 7, 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, 2, 2, 5, 5, 2,
- 5, 5, 5, 2, 5, 2, 2, 2, 5, 5, 5, 5, 2, 2, 5, 5,
- 5, 2, 2, 2, 2, 5, 5, 5, 2, 5, 2, 11, 11, 11, 11, 11,
- 11, 2, 2, 2, 2, 11, 11, 2, 2, 11, 11, 11, 11, 11, 11, 2,
- 11, 11, 2, 11, 11, 2, 11, 11, 2, 2, 2, 11, 2, 2, 11, 2,
- 11, 2, 2, 2, 11, 11, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10,
- 2, 10, 10, 2, 10, 10, 10, 10, 2, 2, 10, 2, 2, 2, 2, 2,
- 10, 10, 2, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2,
- 21, 21, 21, 21, 2, 2, 21, 21, 2, 21, 2, 2, 21, 21, 2, 2,
- 22, 22, 2, 22, 22, 22, 22, 22, 22, 2, 22, 2, 22, 22, 22, 22,
- 2, 2, 2, 22, 22, 2, 2, 2, 2, 22, 22, 2, 2, 2, 22, 22,
- 22, 22, 23, 23, 23, 23, 23, 2, 23, 23, 23, 23, 2, 2, 2, 23,
- 23, 2, 23, 23, 23, 2, 2, 23, 2, 2, 2, 2, 23, 23, 2, 2,
- 2, 23, 16, 16, 16, 16, 16, 2, 16, 16, 2, 16, 16, 16, 16, 16,
- 2, 2, 2, 16, 16, 2, 2, 2, 16, 16, 20, 20, 20, 20, 20, 2,
- 20, 20, 2, 2, 20, 20, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 2, 2, 2, 36, 36, 36, 36, 2, 36, 2, 36, 2, 2, 2, 2,
- 36, 2, 2, 2, 2, 36, 36, 2, 36, 2, 36, 2, 2, 2, 2, 24,
- 24, 24, 24, 24, 24, 24, 24, 24, 24, 2, 2, 2, 2, 0, 2, 18,
- 18, 2, 18, 2, 18, 18, 18, 18, 18, 2, 18, 18, 18, 18, 2, 18,
- 2, 18, 18, 18, 2, 2, 18, 2, 18, 2, 25, 25, 25, 25, 2, 25,
- 25, 25, 25, 2, 2, 2, 25, 2, 25, 25, 25, 0, 0, 0, 0, 25,
- 25, 2, 33, 33, 33, 33, 8, 8, 8, 8, 8, 8, 2, 8, 2, 8,
- 2, 2, 8, 8, 8, 0, 12, 12, 12, 12, 30, 30, 30, 30, 30, 2,
- 30, 30, 30, 30, 2, 2, 30, 30, 30, 2, 2, 30, 30, 30, 30, 2,
- 2, 2, 29, 29, 29, 29, 29, 29, 2, 2, 28, 28, 28, 28, 34, 34,
- 34, 34, 34, 2, 2, 2, 35, 35, 35, 35, 35, 35, 35, 0, 0, 0,
- 35, 35, 35, 2, 2, 2, 45, 45, 45, 45, 45, 45, 2, 2, 2, 2,
- 2, 45, 44, 44, 44, 44, 44, 0, 0, 2, 43, 43, 43, 43, 46, 46,
- 46, 46, 46, 2, 46, 46, 31, 31, 31, 31, 31, 31, 2, 2, 32, 32,
- 0, 0, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 2, 2, 32, 2,
- 2, 2, 32, 32, 32, 2, 28, 28, 2, 2, 48, 48, 48, 48, 48, 48,
- 48, 2, 48, 2, 2, 2, 52, 52, 52, 52, 52, 52, 2, 2, 52, 2,
- 2, 2, 58, 58, 58, 58, 58, 58, 2, 2, 58, 58, 58, 2, 2, 2,
- 58, 58, 54, 54, 54, 54, 2, 2, 54, 54, 91, 91, 91, 91, 91, 91,
- 91, 2, 91, 2, 2, 91, 91, 91, 2, 2, 1, 1, 1, 2, 62, 62,
- 62, 62, 62, 2, 2, 2, 62, 62, 62, 2, 76, 76, 76, 76, 93, 93,
- 93, 93, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 2, 2, 2, 70,
- 70, 70, 73, 73, 73, 73, 6, 2, 2, 2, 8, 8, 8, 2, 2, 8,
- 8, 8, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1,
- 0, 0, 1, 1, 0, 2, 19, 19, 9, 9, 9, 9, 9, 6, 19, 9,
- 9, 9, 9, 9, 19, 19, 9, 9, 9, 19, 6, 19, 19, 19, 19, 19,
- 19, 9, 9, 9, 2, 2, 2, 9, 2, 9, 2, 9, 9, 9, 1, 1,
- 0, 0, 0, 2, 0, 0, 0, 19, 2, 2, 0, 0, 0, 19, 0, 0,
- 0, 2, 19, 2, 2, 2, 0, 2, 2, 2, 1, 2, 2, 2, 0, 0,
- 9, 0, 0, 0, 19, 19, 27, 27, 27, 27, 2, 2, 0, 0, 0, 0,
- 2, 0, 56, 56, 56, 56, 2, 55, 55, 55, 61, 61, 61, 61, 2, 2,
- 2, 61, 61, 2, 2, 2, 0, 0, 2, 2, 13, 13, 13, 13, 13, 13,
- 2, 13, 13, 13, 2, 2, 0, 13, 0, 13, 0, 13, 13, 13, 13, 13,
- 1, 1, 1, 1, 12, 12, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 2, 2, 1, 1, 0, 0, 15, 15, 15, 0, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 0, 2, 26, 26, 26, 26, 26, 26, 26, 2, 12,
- 12, 12, 12, 12, 12, 2, 12, 12, 12, 0, 39, 39, 39, 39, 39, 2,
- 2, 2, 39, 39, 39, 2, 86, 86, 86, 86, 77, 77, 77, 77, 79, 79,
- 79, 79, 19, 19, 19, 2, 19, 19, 2, 19, 2, 19, 19, 19, 19, 19,
- 2, 2, 2, 2, 19, 19, 60, 60, 60, 60, 60, 2, 2, 2, 65, 65,
- 65, 65, 75, 75, 75, 75, 75, 75, 2, 2, 2, 2, 75, 75, 69, 69,
- 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 2, 2, 2, 74, 12, 2,
- 2, 2, 84, 84, 84, 84, 84, 84, 2, 0, 84, 84, 2, 2, 2, 2,
- 84, 84, 33, 33, 33, 2, 68, 68, 68, 68, 68, 68, 68, 2, 68, 68,
- 2, 2, 92, 92, 92, 92, 92, 92, 92, 2, 2, 2, 2, 92, 87, 87,
- 87, 87, 87, 87, 87, 2, 19, 9, 19, 19, 19, 19, 0, 0, 87, 87,
- 2, 2, 2, 2, 2, 12, 2, 2, 2, 4, 14, 2, 14, 2, 14, 14,
- 2, 14, 14, 2, 14, 14, 2, 2, 2, 3, 3, 3, 0, 0, 2, 2,
- 3, 3, 1, 1, 6, 6, 3, 2, 3, 3, 3, 2, 2, 0, 2, 0,
- 0, 0, 0, 0, 17, 17, 17, 17, 0, 0, 2, 2, 12, 12, 49, 49,
- 49, 49, 2, 49, 49, 49, 49, 49, 49, 2, 49, 49, 2, 49, 49, 49,
- 2, 2, 9, 2, 2, 2, 0, 1, 2, 2, 71, 71, 71, 71, 71, 2,
- 2, 2, 67, 67, 67, 67, 67, 2, 2, 2, 42, 42, 42, 42, 2, 42,
- 42, 42, 41, 41, 41, 41, 41, 41, 41, 2,118,118,118,118,118,118,
- 118, 2, 53, 53, 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 59, 59,
- 2, 2, 40, 40, 40, 40, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50,
- 2, 2,135,135,135,135,106,106,106,106,104,104,104,104, 2, 2,
- 2,104,161,161,161,161,161,161,161, 2,161,161, 2,161,161, 2,
- 2, 2,110,110,110,110,110,110,110, 2,110,110, 2, 2, 19, 2,
- 19, 19, 47, 47, 47, 47, 47, 47, 2, 2, 47, 2, 47, 47, 47, 47,
- 2, 47, 47, 2, 2, 2, 47, 2, 2, 47, 81, 81, 81, 81, 81, 81,
- 2, 81,120,120,120,120,116,116,116,116,116,116,116, 2, 2, 2,
- 2,116,128,128,128,128,128,128,128, 2,128,128, 2, 2, 2, 2,
- 2,128, 66, 66, 66, 66, 2, 2, 2, 66, 72, 72, 72, 72, 72, 72,
- 2, 2, 2, 2, 2, 72, 98, 98, 98, 98, 97, 97, 97, 97, 2, 2,
- 97, 97, 57, 57, 57, 57, 2, 57, 57, 2, 2, 57, 57, 57, 57, 57,
- 2, 2, 57, 57, 57, 2, 2, 2, 2, 57, 57, 2, 2, 2, 88, 88,
- 88, 88,117,117,117,117,112,112,112,112,112,112,112, 2, 2, 2,
- 2,112, 78, 78, 78, 78, 78, 78, 2, 2, 2, 78, 78, 78, 83, 83,
- 83, 83, 83, 83, 2, 2, 82, 82, 82, 82, 82, 82, 82, 2,122,122,
- 122,122,122,122, 2, 2, 2,122,122,122,122, 2, 2, 2, 89, 89,
- 89, 89, 89, 2, 2, 2,130,130,130,130,130,130,130, 2, 2, 2,
- 130,130,144,144,144,144,144,144, 2, 2,156,156,156,156,156,156,
- 2,156,156,156, 2, 2, 2, 3, 3, 3,147,147,147,147,148,148,
- 148,148,148,148, 2, 2,158,158,158,158,158,158, 2, 2,153,153,
- 153,153,149,149,149,149,149,149,149, 2, 94, 94, 94, 94, 94, 94,
- 2, 2, 2, 2, 94, 94, 2, 2, 2, 94, 85, 85, 85, 85, 85, 85,
- 85, 2, 2, 85, 2, 2,101,101,101,101,101, 2, 2, 2,101,101,
- 2, 2, 96, 96, 96, 96, 96, 2, 96, 96,111,111,111,111,111,111,
- 111, 2,100,100,100,100,108,108,108,108,108,108, 2,108,108,108,
- 2, 2,129,129,129,129,129,129,129, 2,129, 2,129,129,129,129,
- 2,129,129,129, 2, 2,109,109,109,109,109,109,109, 2,109,109,
- 2, 2,107,107,107,107, 2,107,107,107,107, 2, 2,107,107, 2,
- 107,107,107,107, 2, 1,107,107, 2, 2,107, 2, 2, 2, 2, 2,
- 2,107, 2, 2,107,107,137,137,137,137, 2,137,137,137,137,137,
- 2, 2,124,124,124,124,124,124, 2, 2,123,123,123,123,123,123,
- 2, 2,114,114,114,114,114, 2, 2, 2,114,114, 2, 2,102,102,
- 102,102,102,102, 2, 2,126,126,126,126,126,126,126, 2, 2,126,
- 126,126,142,142,142,142,125,125,125,125,125,125,125, 2, 2, 2,
- 2,125,154,154,154,154,154,154,154, 2, 2,154, 2, 2, 2,154,
- 154, 2,154,154, 2,154,154, 2, 2,154,154,154, 2, 2,150,150,
- 150,150, 2, 2,150,150,150, 2, 2, 2,141,141,141,141,140,140,
- 140,140,140,140,140, 2,121,121,121,121,121, 2, 2, 2, 7, 7,
- 2, 2,133,133,133,133,133, 2,133,133,133,133,133, 2,133,133,
- 2, 2,133, 2, 2, 2,134,134,134,134, 2, 2,134,134, 2,134,
- 134,134,134,134,134, 2,138,138,138,138,138,138,138, 2,138,138,
- 2,138, 2, 2,138, 2,138,138, 2, 2,143,143,143,143,143,143,
- 2,143,143, 2,143,143,143,143,143, 2,143, 2, 2, 2,143,143,
- 2, 2,145,145,145,145,145, 2, 2, 2,163,163,163,163,163, 2,
- 163,163,163,163,163, 2, 2, 2,163,163,163,163, 2, 2, 86, 2,
- 2, 2, 63, 63, 63, 63, 63, 63, 2, 2, 63, 63, 63, 2, 63, 2,
- 2, 2,157,157,157,157,157,157,157, 2, 80, 80, 80, 80, 80, 80,
- 2, 2,127,127,127,127,127,127,127, 2, 79, 2, 2, 2,115,115,
- 115,115,115,115,115, 2,115,115, 2, 2, 2, 2,115,115,159,159,
- 159,159,159,159,159, 2,159,159, 2, 2,103,103,103,103,103,103,
- 2, 2,119,119,119,119,119,119, 2, 2,119,119, 2,119, 2,119,
- 119,119,146,146,146,146,146,146,146, 2, 99, 99, 99, 99, 99, 99,
- 99, 2, 2, 2, 2, 99,136,139, 13, 13,155, 2, 2, 2,136,136,
- 136,136,155,155,155,155,155,155, 2, 2,136, 2, 2, 2, 2, 17,
- 17, 17, 2, 17, 17, 2, 17, 15, 15, 15, 17, 17, 17, 2, 2, 2,
- 15, 2, 2, 17, 2, 2,139,139,139,139,105,105,105,105,105,105,
- 105, 2,105, 2, 2, 2,105,105, 2, 2, 1, 1, 2, 2, 0, 0,
- 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 2, 2, 0, 2, 2, 0,
- 0, 2, 0, 2, 0, 2,131,131,131,131, 2, 2, 2,131, 2,131,
- 131,131, 56, 56, 56, 2, 56, 2, 2, 56, 56, 56, 2, 56, 56, 2,
- 56, 56, 6, 6, 2, 2, 2, 2, 2, 6,151,151,151,151,151, 2,
- 2, 2,151,151, 2, 2, 2, 2,151,151,160,160,160,160,160,160,
- 160, 2,152,152,152,152,152,152, 2, 2, 2, 2, 2,152,164,164,
- 164,164,164,164, 2, 2, 2, 30, 30, 2,113,113,113,113,113, 2,
- 2,113,113,113,113, 2,132,132,132,132,132,132, 2, 2, 2, 2,
- 132,132, 2, 3, 3, 2, 3, 2, 2, 3, 2, 3, 2, 3, 2, 2,
- 3, 2, 3, 2, 3, 2, 3, 3, 2, 3, 15, 0, 0, 2, 13, 2,
- 2, 2, 13, 13, 13, 2, 2, 0, 2, 2, 0, 1, 2, 3, 4, 5,
- 6, 7, 8, 9, 9, 9, 9, 10, 9, 11, 12, 13, 9, 9, 9, 14,
- 9, 9, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 70, 70, 70,240, 70, 70, 70, 70, 70, 70, 70, 70, 70,241, 70, 70,
+ 70, 70,242, 96, 96, 96, 70, 70, 70, 70,243, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 70, 70, 70, 70, 70, 70,244, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,245, 96, 96,
+ 96, 96, 96, 96, 96, 96,246, 96,247,248, 0, 1, 2, 2, 0, 1,
+ 2, 2, 2, 3, 4, 5, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 0, 0, 0, 19, 0, 19, 0, 0, 0, 0, 0,
+ 26, 26, 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, 2, 2,
+ 9, 9, 9, 9, 0, 9, 2, 2, 2, 2, 9, 0, 9, 0, 9, 9,
+ 9, 2, 9, 2, 9, 9, 9, 9, 2, 9, 9, 9, 55, 55, 55, 55,
+ 55, 55, 6, 6, 6, 6, 6, 1, 1, 6, 2, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 2, 2, 2, 2, 14, 14, 2, 2, 2, 3, 3, 3, 3, 3, 0,
+ 3, 3, 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 1, 1, 1,
+ 3, 3, 1, 3, 3, 3, 37, 37, 37, 37, 37, 37, 2, 37, 37, 37,
+ 37, 2, 2, 37, 37, 37, 38, 38, 38, 38, 38, 38, 2, 2, 64, 64,
+ 64, 64, 64, 64, 64, 2, 2, 64, 64, 64, 90, 90, 90, 90, 90, 90,
+ 2, 2, 90, 90, 90, 2, 95, 95, 95, 95, 2, 2, 95, 2, 3, 3,
+ 3, 2, 3, 3, 2, 2, 3, 3, 0, 3, 7, 7, 7, 7, 7, 1,
+ 1, 1, 1, 7, 7, 7, 0, 0, 7, 7, 5, 5, 5, 5, 2, 5,
+ 5, 5, 5, 2, 2, 5, 5, 2, 5, 5, 5, 2, 5, 2, 2, 2,
+ 5, 5, 5, 5, 2, 2, 5, 5, 5, 2, 2, 2, 2, 5, 5, 5,
+ 2, 5, 2, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 11, 11, 2,
+ 2, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11, 11, 2, 11, 11,
+ 2, 2, 2, 11, 2, 2, 11, 2, 11, 2, 2, 2, 11, 11, 2, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10, 10, 10, 10,
+ 2, 2, 10, 2, 2, 2, 2, 2, 10, 10, 2, 21, 21, 21, 21, 21,
+ 21, 21, 21, 2, 2, 21, 21, 2, 21, 21, 21, 21, 2, 2, 21, 21,
+ 2, 21, 2, 2, 21, 21, 2, 2, 22, 22, 2, 22, 22, 22, 22, 22,
+ 22, 2, 22, 2, 22, 22, 22, 22, 2, 2, 2, 22, 22, 2, 2, 2,
+ 2, 22, 22, 2, 2, 2, 22, 22, 22, 22, 23, 23, 23, 23, 23, 2,
+ 23, 23, 23, 23, 2, 2, 2, 23, 23, 2, 23, 23, 23, 2, 2, 23,
+ 2, 2, 2, 2, 23, 23, 2, 2, 2, 23, 16, 16, 16, 16, 16, 2,
+ 16, 16, 2, 16, 16, 16, 16, 16, 2, 2, 2, 16, 16, 2, 2, 2,
+ 16, 16, 20, 20, 20, 20, 20, 2, 20, 20, 2, 2, 20, 20, 2, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2, 36, 36, 36, 36,
+ 2, 36, 2, 36, 2, 2, 2, 2, 36, 2, 2, 2, 2, 36, 36, 2,
+ 36, 2, 36, 2, 2, 2, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 2, 2, 2, 2, 0, 2, 18, 18, 2, 18, 2, 18, 18, 18, 18,
+ 18, 2, 18, 18, 18, 18, 2, 18, 2, 18, 18, 18, 2, 2, 18, 2,
+ 18, 2, 25, 25, 25, 25, 2, 25, 25, 25, 25, 2, 2, 2, 25, 2,
+ 25, 25, 25, 0, 0, 0, 0, 25, 25, 2, 33, 33, 33, 33, 8, 8,
+ 8, 8, 8, 8, 2, 8, 2, 8, 2, 2, 8, 8, 8, 0, 12, 12,
+ 12, 12, 30, 30, 30, 30, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30,
+ 30, 2, 2, 30, 30, 30, 30, 2, 2, 2, 29, 29, 29, 29, 29, 29,
+ 2, 2, 28, 28, 28, 28, 34, 34, 34, 34, 34, 2, 2, 2, 35, 35,
+ 35, 35, 35, 35, 35, 0, 0, 0, 35, 35, 35, 2, 2, 2, 45, 45,
+ 45, 45, 45, 45, 2, 2, 2, 2, 2, 45, 44, 44, 44, 44, 44, 0,
+ 0, 2, 43, 43, 43, 43, 46, 46, 46, 46, 46, 2, 46, 46, 31, 31,
+ 31, 31, 31, 31, 2, 2, 32, 32, 0, 0, 32, 0, 32, 32, 32, 32,
+ 32, 32, 32, 32, 2, 2, 32, 2, 2, 2, 32, 32, 32, 2, 28, 28,
+ 2, 2, 48, 48, 48, 48, 48, 48, 48, 2, 48, 2, 2, 2, 52, 52,
+ 52, 52, 52, 52, 2, 2, 52, 2, 2, 2, 58, 58, 58, 58, 58, 58,
+ 2, 2, 58, 58, 58, 2, 2, 2, 58, 58, 54, 54, 54, 54, 2, 2,
+ 54, 54, 91, 91, 91, 91, 91, 91, 91, 2, 91, 2, 2, 91, 91, 91,
+ 2, 2, 1, 1, 1, 2, 62, 62, 62, 62, 62, 2, 2, 2, 62, 62,
+ 62, 2, 76, 76, 76, 76, 93, 93, 93, 93, 70, 70, 70, 70, 2, 2,
+ 2, 70, 70, 70, 2, 2, 2, 70, 70, 70, 73, 73, 73, 73, 6, 2,
+ 2, 2, 8, 8, 8, 2, 2, 8, 8, 8, 1, 1, 1, 0, 1, 0,
+ 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 2, 19, 19,
+ 9, 9, 9, 9, 9, 6, 19, 9, 9, 9, 9, 9, 19, 19, 9, 9,
+ 9, 19, 6, 19, 19, 19, 19, 19, 19, 9, 9, 9, 2, 2, 2, 9,
+ 2, 9, 2, 9, 9, 9, 1, 1, 0, 0, 0, 2, 0, 0, 0, 19,
+ 2, 2, 0, 0, 0, 19, 0, 0, 0, 2, 19, 2, 2, 2, 0, 2,
+ 2, 2, 1, 2, 2, 2, 0, 0, 9, 0, 0, 0, 19, 19, 27, 27,
+ 27, 27, 2, 2, 0, 0, 0, 0, 2, 0, 56, 56, 56, 56, 2, 55,
+ 55, 55, 61, 61, 61, 61, 2, 2, 2, 61, 61, 2, 2, 2, 0, 0,
+ 2, 2, 13, 13, 13, 13, 13, 13, 2, 13, 13, 13, 2, 2, 0, 13,
+ 0, 13, 0, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, 2, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 1, 1, 0, 0, 15,
+ 15, 15, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 2, 26,
+ 26, 26, 26, 26, 26, 26, 2, 12, 12, 12, 12, 12, 12, 2, 12, 12,
+ 12, 0, 39, 39, 39, 39, 39, 2, 2, 2, 39, 39, 39, 2, 86, 86,
+ 86, 86, 77, 77, 77, 77, 79, 79, 79, 79, 19, 19, 19, 2, 19, 19,
+ 2, 19, 2, 19, 19, 19, 19, 19, 2, 2, 2, 2, 19, 19, 60, 60,
+ 60, 60, 60, 2, 2, 2, 65, 65, 65, 65, 75, 75, 75, 75, 75, 75,
+ 2, 2, 2, 2, 75, 75, 69, 69, 69, 69, 69, 69, 0, 69, 74, 74,
+ 74, 74, 2, 2, 2, 74, 12, 2, 2, 2, 84, 84, 84, 84, 84, 84,
+ 2, 0, 84, 84, 2, 2, 2, 2, 84, 84, 33, 33, 33, 2, 68, 68,
+ 68, 68, 68, 68, 68, 2, 68, 68, 2, 2, 92, 92, 92, 92, 92, 92,
+ 92, 2, 2, 2, 2, 92, 87, 87, 87, 87, 87, 87, 87, 2, 19, 9,
+ 19, 19, 19, 19, 0, 0, 87, 87, 2, 2, 2, 2, 2, 12, 2, 2,
+ 2, 4, 14, 2, 14, 2, 14, 14, 2, 14, 14, 2, 14, 14, 2, 2,
+ 2, 3, 3, 3, 0, 0, 2, 2, 3, 3, 1, 1, 6, 6, 3, 2,
+ 3, 3, 3, 2, 2, 0, 2, 0, 0, 0, 0, 0, 17, 17, 17, 17,
+ 0, 0, 2, 2, 12, 12, 49, 49, 49, 49, 2, 49, 49, 49, 49, 49,
+ 49, 2, 49, 49, 2, 49, 49, 49, 2, 2, 9, 2, 2, 2, 0, 1,
+ 2, 2, 71, 71, 71, 71, 71, 2, 2, 2, 67, 67, 67, 67, 67, 2,
+ 2, 2, 42, 42, 42, 42, 2, 42, 42, 42, 41, 41, 41, 41, 41, 41,
+ 41, 2,118,118,118,118,118,118,118, 2, 53, 53, 53, 53, 53, 53,
+ 2, 53, 59, 59, 59, 59, 59, 59, 2, 2, 40, 40, 40, 40, 51, 51,
+ 51, 51, 50, 50, 50, 50, 50, 50, 2, 2,135,135,135,135,106,106,
+ 106,106,104,104,104,104, 2, 2, 2,104,161,161,161,161,161,161,
+ 161, 2,161,161, 2,161,161, 2, 2, 2,110,110,110,110,110,110,
+ 110, 2,110,110, 2, 2, 19, 2, 19, 19, 47, 47, 47, 47, 47, 47,
+ 2, 2, 47, 2, 47, 47, 47, 47, 2, 47, 47, 2, 2, 2, 47, 2,
+ 2, 47, 81, 81, 81, 81, 81, 81, 2, 81,120,120,120,120,116,116,
+ 116,116,116,116,116, 2, 2, 2, 2,116,128,128,128,128,128,128,
+ 128, 2,128,128, 2, 2, 2, 2, 2,128, 66, 66, 66, 66, 2, 2,
+ 2, 66, 72, 72, 72, 72, 72, 72, 2, 2, 2, 2, 2, 72, 98, 98,
+ 98, 98, 97, 97, 97, 97, 2, 2, 97, 97, 57, 57, 57, 57, 2, 57,
+ 57, 2, 2, 57, 57, 57, 57, 57, 2, 2, 57, 57, 57, 2, 2, 2,
+ 2, 57, 57, 2, 2, 2, 88, 88, 88, 88,117,117,117,117,112,112,
+ 112,112,112,112,112, 2, 2, 2, 2,112, 78, 78, 78, 78, 78, 78,
+ 2, 2, 2, 78, 78, 78, 83, 83, 83, 83, 83, 83, 2, 2, 82, 82,
+ 82, 82, 82, 82, 82, 2,122,122,122,122,122,122, 2, 2, 2,122,
+ 122,122,122, 2, 2, 2, 89, 89, 89, 89, 89, 2, 2, 2,130,130,
+ 130,130,130,130,130, 2, 2, 2,130,130,144,144,144,144,144,144,
+ 2, 2,156,156,156,156,156,156, 2,156,156,156, 2, 2, 2, 3,
+ 3, 3,147,147,147,147,148,148,148,148,148,148, 2, 2,158,158,
+ 158,158,158,158, 2, 2,153,153,153,153,149,149,149,149,149,149,
+ 149, 2, 94, 94, 94, 94, 94, 94, 2, 2, 2, 2, 94, 94, 2, 2,
+ 2, 94, 85, 85, 85, 85, 85, 85, 85, 2, 2, 85, 2, 2,101,101,
+ 101,101,101, 2, 2, 2,101,101, 2, 2, 96, 96, 96, 96, 96, 2,
+ 96, 96,111,111,111,111,111,111,111, 2,100,100,100,100,108,108,
+ 108,108,108,108, 2,108,108,108, 2, 2,129,129,129,129,129,129,
+ 129, 2,129, 2,129,129,129,129, 2,129,129,129, 2, 2,109,109,
+ 109,109,109,109,109, 2,109,109, 2, 2,107,107,107,107, 2,107,
+ 107,107,107, 2, 2,107,107, 2,107,107,107,107, 2, 1,107,107,
+ 2, 2,107, 2, 2, 2, 2, 2, 2,107, 2, 2,107,107,137,137,
+ 137,137, 2,137,137,137,137,137, 2, 2,124,124,124,124,124,124,
+ 2, 2,123,123,123,123,123,123, 2, 2,114,114,114,114,114, 2,
+ 2, 2,114,114, 2, 2,102,102,102,102,102,102, 2, 2,126,126,
+ 126,126,126,126,126, 2, 2,126,126,126,142,142,142,142,125,125,
+ 125,125,125,125,125, 2, 2, 2, 2,125,154,154,154,154,154,154,
+ 154, 2, 2,154, 2, 2, 2,154,154, 2,154,154, 2,154,154, 2,
+ 2,154,154,154, 2, 2,150,150,150,150, 2, 2,150,150,150, 2,
+ 2, 2,141,141,141,141,140,140,140,140,140,140,140, 2,121,121,
+ 121,121,121, 2, 2, 2, 7, 7, 2, 2,133,133,133,133,133, 2,
+ 133,133,133,133,133, 2,133,133, 2, 2,133, 2, 2, 2,134,134,
+ 134,134, 2, 2,134,134, 2,134,134,134,134,134,134, 2,138,138,
+ 138,138,138,138,138, 2,138,138, 2,138, 2, 2,138, 2,138,138,
+ 2, 2,143,143,143,143,143,143, 2,143,143, 2,143,143,143,143,
+ 143, 2,143, 2, 2, 2,143,143, 2, 2,145,145,145,145,145, 2,
+ 2, 2,163,163,163,163,163, 2,163,163,163,163,163, 2, 2, 2,
+ 163,163,163,163, 2, 2, 86, 2, 2, 2, 63, 63, 63, 63, 63, 63,
+ 2, 2, 63, 63, 63, 2, 63, 2, 2, 2,157,157,157,157,157,157,
+ 157, 2, 80, 80, 80, 80, 80, 80, 2, 2,127,127,127,127,127,127,
+ 127, 2, 79, 2, 2, 2,115,115,115,115,115,115,115, 2,115,115,
+ 2, 2, 2, 2,115,115,159,159,159,159,159,159,159, 2,159,159,
+ 2, 2,103,103,103,103,103,103, 2, 2,119,119,119,119,119,119,
+ 2, 2,119,119, 2,119, 2,119,119,119,146,146,146,146,146,146,
+ 146, 2, 99, 99, 99, 99, 99, 99, 99, 2, 2, 2, 2, 99,136,139,
+ 13, 13,155, 2, 2, 2,136,136,136,136,155,155,155,155,155,155,
+ 2, 2,136, 2, 2, 2, 2, 17, 17, 17, 2, 17, 17, 2, 17, 15,
+ 15, 15, 17, 17, 17, 2, 2, 2, 15, 2, 2, 17, 2, 2,139,139,
+ 139,139,105,105,105,105,105,105,105, 2,105, 2, 2, 2,105,105,
+ 2, 2, 1, 1, 2, 2, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0,
+ 1, 1, 2, 2, 0, 2, 2, 0, 0, 2, 0, 2, 0, 2,131,131,
+ 131,131, 2, 2, 2,131, 2,131,131,131, 56, 56, 56, 2, 56, 2,
+ 2, 56, 56, 56, 2, 56, 56, 2, 56, 56, 6, 6, 2, 2, 2, 2,
+ 2, 6,151,151,151,151,151, 2, 2, 2,151,151, 2, 2, 2, 2,
+ 151,151,160,160,160,160,160,160,160, 2,152,152,152,152,152,152,
+ 2, 2, 2, 2, 2,152,164,164,164,164,164,164, 2, 2, 2, 30,
+ 30, 2,113,113,113,113,113, 2, 2,113,113,113,113, 2,132,132,
+ 132,132,132,132, 2, 2, 2, 2,132,132, 2, 3, 3, 2, 3, 2,
+ 2, 3, 2, 3, 2, 3, 2, 2, 3, 2, 3, 2, 3, 2, 3, 3,
+ 2, 3, 15, 0, 0, 2, 13, 2, 2, 2, 13, 13, 13, 2, 2, 0,
+ 2, 2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 10,
+ 9, 11, 12, 13, 9, 9, 9, 14, 9, 9, 15, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 16, 17, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 18, 19, 20, 9, 21, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 16, 17,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 19, 20, 9, 21, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 22, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 22, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
@@ -3702,60 +3704,60 @@ _hb_ucd_u8[14744] =
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
- 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 24,
- 25, 26, 27, 28, 29, 30, 0, 0, 31, 32, 0, 33, 0, 34, 0, 35,
- 0, 0, 0, 0, 36, 37, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 23, 24,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 23, 0, 0, 24, 25, 26, 27, 28, 29, 30, 0, 0,
+ 31, 32, 0, 33, 0, 34, 0, 35, 0, 0, 0, 0, 36, 37, 38, 39,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 45, 0, 0,
- 0, 0, 0, 0, 46, 47, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 51, 0, 0,
- 0, 52, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0,
- 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0,
- 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 59, 60, 61,
- 62, 63, 64, 65, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0,
+ 0, 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, 46, 47, 0, 0,
+ 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 50, 51, 0, 0, 0, 52, 0, 0, 53, 0, 0, 0,
+ 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0,
+ 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 58, 59, 60, 61, 62, 63, 64, 65, 0, 0, 0, 0,
+ 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 67, 68, 0, 69, 70, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 71, 72, 73, 74, 75, 76, 77, 78,
- 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
- 95, 96, 97, 98, 99,100,101,102,103, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0,
- 0,105,106, 0,107, 0, 0, 0,108, 0,109, 0,110, 0,111,112,
- 113, 0,114, 0, 0, 0,115, 0, 0, 0,116, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,118,119,120,121,
- 0,122,123,124,125,126, 0,127, 0, 0, 0, 0, 0, 0, 0, 0,
+ 67, 68, 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
+ 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,
+ 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,104, 0, 0, 0, 0, 0, 0,105,106, 0,107, 0, 0, 0,
+ 108, 0,109, 0,110, 0,111,112,113, 0,114, 0, 0, 0,115, 0,
+ 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,128,129,130,131,132,133,134,135,
- 136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,
- 152,153,154,155,156,157, 0, 0, 0,158,159,160,161, 0, 0, 0,
+ 0, 0, 0, 0,118,119,120,121, 0,122,123,124,125,126, 0,127,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,162,163, 0, 0, 0, 0, 0, 0, 0,164, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,165, 0, 0, 0,
+ 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+ 144,145,146,147,148,149,150,151,152,153,154,155,156,157, 0, 0,
+ 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,162,163, 0, 0, 0, 0, 0,
+ 0, 0,164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,167, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,168, 0, 0, 0, 0,
+ 0, 0, 0, 0,165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,167, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,169,170, 0,
- 0, 0, 0,171,172, 0, 0, 0,173,174,175,176,177,178,179,180,
- 181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,
- 197,198,199,200,201,202,203,204,205,206, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 1, 2, 3, 4,
+ 0, 0, 0, 0, 0,169,170, 0, 0, 0, 0,171,172, 0, 0, 0,
+ 173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,
+ 189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,
+ 205,206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
};
static const uint16_t
-_hb_ucd_u16[10040] =
+_hb_ucd_u16[10060] =
{
0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12,
13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23,
@@ -3798,9 +3800,9 @@ _hb_ucd_u16[10040] =
209, 306, 209, 209, 209, 209, 209, 209, 9, 9, 9, 11, 11, 11, 307, 308,
13, 13, 13, 13, 13, 13, 309, 310, 11, 11, 311, 48, 48, 48, 312, 313,
48, 314, 315, 315, 315, 315, 32, 32, 316, 317, 318, 319, 320, 321, 140, 140,
- 209, 322, 209, 209, 209, 209, 209, 323, 209, 209, 209, 209, 209, 324, 140, 325,
- 326, 327, 328, 329, 136, 48, 48, 48, 48, 330, 178, 48, 48, 48, 48, 331,
- 332, 48, 48, 136, 48, 48, 48, 48, 200, 333, 48, 48, 209, 209, 323, 48,
+ 209, 322, 209, 209, 209, 209, 209, 323, 209, 209, 209, 209, 209, 324, 140, 209,
+ 325, 326, 327, 328, 136, 48, 48, 48, 48, 329, 178, 48, 48, 48, 48, 330,
+ 331, 48, 48, 136, 48, 48, 48, 48, 200, 332, 48, 48, 209, 209, 333, 48,
209, 334, 335, 209, 336, 337, 209, 209, 335, 209, 209, 337, 209, 209, 209, 209,
48, 48, 48, 48, 209, 209, 209, 209, 48, 338, 48, 48, 48, 48, 48, 48,
151, 209, 209, 209, 287, 48, 48, 229, 339, 48, 340, 140, 13, 13, 341, 342,
@@ -3871,143 +3873,144 @@ _hb_ucd_u16[10040] =
9, 9, 607, 11, 654, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 499,
271, 271, 655, 656, 140, 140, 140, 140, 499, 271, 657, 658, 140, 140, 140, 140,
659, 48, 660, 661, 662, 663, 664, 665, 666, 206, 667, 206, 140, 140, 140, 668,
- 209, 209, 325, 209, 209, 209, 209, 209, 209, 323, 334, 669, 669, 669, 209, 324,
- 670, 209, 209, 209, 209, 209, 209, 209, 209, 209, 671, 140, 140, 140, 672, 209,
- 673, 209, 209, 325, 674, 675, 324, 140, 209, 209, 209, 209, 209, 209, 209, 676,
- 209, 209, 209, 209, 209, 677, 426, 426, 209, 209, 209, 209, 209, 209, 209, 678,
- 209, 209, 209, 209, 209, 176, 325, 427, 325, 209, 209, 209, 679, 176, 209, 209,
- 679, 209, 671, 675, 140, 140, 140, 140, 209, 209, 209, 209, 209, 323, 671, 426,
- 674, 209, 209, 680, 681, 325, 674, 674, 209, 682, 209, 209, 288, 140, 140, 192,
+ 209, 209, 669, 209, 209, 209, 209, 209, 209, 323, 334, 670, 670, 670, 209, 324,
+ 671, 209, 209, 209, 209, 209, 209, 209, 209, 209, 672, 140, 140, 140, 673, 209,
+ 674, 209, 209, 669, 675, 676, 324, 140, 209, 209, 209, 209, 209, 209, 209, 677,
+ 209, 209, 209, 209, 209, 678, 426, 426, 209, 209, 209, 209, 209, 209, 209, 679,
+ 209, 209, 209, 209, 209, 176, 669, 427, 669, 209, 209, 209, 680, 176, 209, 209,
+ 680, 209, 672, 676, 140, 140, 140, 140, 209, 209, 209, 209, 209, 323, 672, 426,
+ 675, 209, 209, 681, 682, 669, 675, 675, 209, 683, 209, 209, 288, 140, 140, 192,
48, 48, 48, 48, 48, 48, 140, 140, 48, 48, 48, 207, 48, 48, 48, 48,
48, 204, 48, 48, 48, 48, 48, 48, 48, 48, 478, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 100, 140, 48, 204, 140, 140, 140, 140, 140, 140,
- 48, 48, 48, 48, 71, 48, 48, 48, 48, 48, 48, 140, 140, 140, 140, 140,
- 683, 140, 570, 570, 570, 570, 570, 570, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 140, 391, 391, 391, 391, 391, 391, 391, 684,
- 391, 391, 391, 391, 391, 391, 391, 685, 0, 0, 0, 0, 1, 2, 1, 2,
- 0, 0, 3, 3, 4, 5, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 6, 0, 0, 7, 0, 8, 8, 8, 8, 8, 8, 8, 9,
- 10, 11, 12, 11, 11, 11, 13, 11, 14, 14, 14, 14, 14, 14, 14, 14,
- 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 16, 17, 18, 17, 17,
- 19, 20, 21, 21, 22, 21, 23, 24, 25, 26, 27, 27, 28, 29, 27, 30,
- 27, 27, 27, 27, 27, 31, 27, 27, 32, 33, 33, 33, 34, 27, 27, 27,
- 35, 35, 35, 36, 37, 37, 37, 38, 39, 39, 40, 41, 42, 43, 44, 27,
- 45, 46, 27, 27, 27, 27, 47, 27, 48, 48, 48, 48, 48, 49, 50, 48,
- 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
- 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
- 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
- 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 109, 110, 111, 112, 109,
- 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 122, 123, 122, 124, 125, 125,
- 126, 127, 128, 129, 130, 131, 125, 125, 132, 132, 132, 132, 133, 132, 134, 135,
- 132, 133, 132, 136, 136, 137, 125, 125, 138, 138, 138, 138, 138, 138, 138, 138,
- 138, 138, 139, 139, 140, 139, 139, 141, 142, 142, 142, 142, 142, 142, 142, 142,
- 143, 143, 143, 143, 144, 145, 143, 143, 144, 143, 143, 146, 147, 148, 143, 143,
- 143, 147, 143, 143, 143, 149, 143, 150, 143, 151, 152, 152, 152, 152, 152, 153,
- 154, 154, 154, 154, 154, 154, 154, 154, 155, 156, 157, 157, 157, 157, 158, 159,
- 160, 161, 162, 163, 164, 165, 166, 167, 168, 168, 168, 168, 168, 169, 170, 170,
- 171, 172, 173, 173, 173, 173, 173, 174, 173, 173, 175, 154, 154, 154, 154, 176,
- 177, 178, 179, 179, 180, 181, 182, 183, 184, 184, 185, 184, 186, 187, 168, 168,
- 188, 189, 190, 190, 190, 191, 190, 192, 193, 193, 194, 8, 195, 125, 125, 125,
- 196, 196, 196, 196, 197, 196, 196, 198, 199, 199, 199, 199, 200, 200, 200, 201,
- 202, 202, 202, 203, 204, 205, 205, 205, 206, 139, 139, 207, 208, 209, 210, 211,
- 4, 4, 212, 4, 4, 213, 214, 215, 4, 4, 4, 216, 8, 8, 8, 8,
- 11, 217, 11, 11, 217, 218, 11, 219, 11, 11, 11, 220, 220, 221, 11, 222,
- 223, 0, 0, 0, 0, 0, 224, 225, 226, 227, 0, 0, 228, 8, 8, 229,
- 0, 0, 230, 231, 232, 0, 4, 4, 233, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 234, 125, 235, 125, 0, 0,
- 236, 236, 236, 236, 236, 236, 236, 236, 0, 0, 0, 0, 0, 0, 0, 237,
- 0, 238, 0, 0, 0, 0, 0, 0, 239, 239, 239, 239, 239, 239, 4, 4,
- 240, 240, 240, 240, 240, 240, 240, 241, 139, 139, 140, 242, 242, 242, 243, 244,
- 143, 245, 246, 246, 246, 246, 14, 14, 0, 0, 0, 0, 0, 247, 125, 125,
- 248, 249, 248, 248, 248, 248, 248, 250, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 251, 125, 252, 253, 0, 254, 255, 256, 257, 257, 257,
- 257, 258, 259, 260, 260, 260, 260, 261, 262, 263, 263, 264, 142, 142, 142, 142,
- 265, 0, 263, 263, 0, 0, 266, 260, 142, 265, 0, 0, 0, 0, 142, 267,
- 0, 0, 0, 0, 0, 260, 260, 268, 260, 260, 260, 260, 260, 269, 0, 0,
- 248, 248, 248, 248, 0, 0, 0, 0, 270, 270, 270, 270, 270, 270, 270, 270,
- 271, 270, 270, 270, 272, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274,
- 274, 274, 275, 125, 14, 14, 14, 14, 14, 14, 276, 276, 276, 276, 276, 277,
- 0, 0, 278, 4, 4, 4, 4, 4, 279, 4, 4, 4, 280, 281, 125, 282,
- 283, 283, 284, 285, 286, 286, 286, 287, 288, 288, 288, 288, 289, 290, 48, 48,
- 291, 291, 292, 293, 293, 294, 142, 295, 296, 296, 296, 296, 297, 298, 138, 299,
- 300, 300, 300, 301, 302, 303, 138, 138, 304, 304, 304, 304, 305, 306, 307, 308,
- 309, 310, 246, 4, 4, 311, 312, 152, 152, 152, 152, 152, 307, 307, 313, 314,
- 142, 142, 315, 142, 316, 142, 142, 317, 125, 125, 125, 125, 125, 125, 125, 125,
- 248, 248, 248, 248, 248, 248, 318, 248, 248, 248, 248, 248, 248, 319, 125, 125,
- 320, 321, 21, 322, 323, 27, 27, 27, 27, 27, 27, 27, 324, 325, 27, 27,
- 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 326, 27, 27, 27, 27,
- 27, 327, 27, 27, 328, 125, 125, 27, 8, 285, 329, 0, 0, 330, 331, 332,
- 27, 27, 27, 27, 27, 27, 27, 333, 334, 0, 1, 2, 1, 2, 335, 259,
- 260, 336, 142, 265, 337, 338, 339, 340, 341, 342, 343, 344, 345, 345, 125, 125,
- 342, 342, 342, 342, 342, 342, 342, 346, 347, 0, 0, 348, 11, 11, 11, 11,
- 349, 350, 351, 125, 125, 0, 0, 352, 353, 354, 355, 355, 355, 356, 357, 252,
- 358, 358, 359, 360, 361, 362, 362, 363, 364, 365, 366, 366, 367, 368, 125, 125,
- 369, 369, 369, 369, 369, 370, 370, 370, 371, 372, 373, 374, 374, 375, 374, 376,
- 377, 377, 378, 379, 379, 379, 380, 381, 381, 382, 383, 384, 125, 125, 125, 125,
- 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 386, 385, 387, 388, 125,
- 389, 4, 4, 390, 125, 125, 125, 125, 391, 392, 392, 393, 394, 395, 396, 396,
- 397, 398, 399, 125, 125, 125, 400, 401, 402, 403, 404, 405, 125, 125, 125, 125,
- 406, 406, 407, 408, 407, 409, 407, 407, 410, 411, 412, 413, 414, 414, 415, 415,
- 416, 416, 125, 125, 417, 417, 418, 419, 420, 420, 420, 421, 422, 423, 424, 425,
- 426, 427, 428, 125, 125, 125, 125, 125, 429, 429, 429, 429, 430, 125, 125, 125,
- 431, 431, 431, 432, 431, 431, 431, 433, 434, 434, 435, 436, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 27, 45, 437, 437, 438, 439, 125, 125, 125, 440,
- 441, 441, 442, 443, 443, 444, 125, 445, 446, 125, 125, 447, 448, 125, 449, 450,
- 451, 451, 451, 451, 452, 453, 451, 454, 455, 455, 455, 455, 456, 457, 458, 459,
- 460, 460, 460, 461, 462, 463, 463, 464, 465, 465, 465, 465, 465, 465, 466, 467,
- 468, 469, 468, 468, 470, 125, 125, 125, 471, 472, 473, 474, 474, 474, 475, 476,
- 477, 478, 479, 480, 481, 482, 483, 484, 485, 485, 485, 485, 485, 486, 487, 125,
- 488, 488, 488, 488, 489, 490, 125, 125, 491, 491, 491, 492, 491, 493, 125, 125,
- 494, 494, 494, 494, 495, 496, 497, 125, 498, 498, 498, 499, 499, 125, 125, 125,
- 500, 501, 502, 500, 503, 125, 125, 125, 504, 504, 504, 505, 125, 125, 125, 125,
- 125, 125, 506, 506, 506, 506, 506, 507, 508, 509, 510, 511, 512, 513, 125, 125,
- 125, 125, 514, 515, 515, 514, 516, 125, 517, 517, 517, 517, 518, 519, 519, 519,
- 519, 519, 520, 154, 521, 521, 521, 522, 523, 125, 125, 125, 125, 125, 125, 125,
- 524, 525, 525, 526, 527, 525, 528, 529, 529, 530, 531, 532, 125, 125, 125, 125,
- 533, 534, 534, 535, 536, 537, 538, 539, 540, 541, 542, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 543, 544, 545, 546, 545, 547, 545, 548, 125, 125,
- 125, 125, 125, 549, 550, 550, 550, 551, 552, 552, 552, 552, 552, 552, 552, 552,
- 552, 553, 125, 125, 125, 125, 125, 125, 552, 552, 552, 552, 552, 552, 554, 555,
- 552, 552, 552, 552, 556, 125, 125, 125, 125, 557, 557, 557, 557, 557, 557, 558,
- 559, 559, 559, 559, 559, 559, 559, 559, 559, 559, 559, 559, 559, 560, 125, 125,
- 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, 562, 125, 125, 125,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 563, 564, 565, 566, 567,
- 567, 567, 567, 568, 569, 570, 571, 572, 573, 573, 573, 573, 574, 575, 576, 577,
- 573, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 578, 578, 578, 578,
- 578, 579, 125, 125, 125, 125, 125, 125, 580, 580, 580, 580, 581, 580, 580, 580,
- 582, 580, 125, 125, 125, 125, 583, 584, 585, 585, 585, 585, 585, 585, 585, 585,
- 585, 585, 585, 585, 585, 585, 585, 586, 587, 587, 587, 587, 587, 587, 587, 587,
- 587, 587, 587, 587, 587, 588, 125, 125, 589, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 590, 591, 257, 257, 257, 257, 257, 257, 257,
- 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 592, 593, 125, 594, 595, 596,
- 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 597,
- 598, 598, 598, 598, 598, 598, 599, 600, 601, 602, 266, 125, 125, 125, 125, 125,
- 8, 8, 603, 8, 604, 0, 0, 0, 0, 0, 0, 0, 266, 125, 125, 125,
- 0, 0, 0, 0, 0, 0, 0, 605, 0, 0, 606, 0, 0, 0, 607, 608,
- 609, 0, 610, 0, 0, 0, 235, 125, 11, 11, 11, 11, 611, 125, 125, 125,
- 125, 125, 125, 125, 0, 266, 0, 266, 0, 0, 0, 0, 0, 234, 0, 612,
- 0, 0, 0, 0, 0, 224, 0, 0, 0, 613, 614, 615, 616, 0, 0, 0,
- 617, 618, 0, 619, 620, 621, 0, 0, 0, 0, 622, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 623, 0, 0, 0, 624, 624, 624, 624, 624, 624, 624, 624,
- 625, 626, 627, 125, 125, 125, 125, 125, 4, 628, 629, 125, 125, 125, 125, 125,
- 630, 631, 632, 14, 14, 14, 633, 125, 634, 125, 125, 125, 125, 125, 125, 125,
- 635, 635, 636, 637, 638, 125, 125, 125, 125, 639, 640, 125, 641, 641, 641, 642,
- 125, 125, 125, 125, 125, 643, 643, 644, 125, 125, 125, 125, 125, 125, 645, 646,
- 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 647, 648, 649, 125, 125,
- 650, 650, 650, 650, 651, 652, 125, 125, 125, 125, 125, 125, 125, 125, 125, 334,
- 0, 0, 0, 653, 125, 125, 125, 125, 334, 0, 0, 247, 125, 125, 125, 125,
- 654, 27, 655, 656, 657, 658, 659, 660, 661, 662, 663, 662, 125, 125, 125, 664,
- 0, 0, 252, 0, 0, 0, 0, 0, 0, 266, 226, 334, 334, 334, 0, 605,
- 0, 0, 247, 125, 125, 125, 665, 0, 666, 0, 0, 252, 612, 667, 605, 125,
- 0, 0, 0, 0, 0, 668, 350, 350, 0, 0, 0, 0, 0, 0, 0, 669,
- 0, 0, 0, 0, 0, 285, 252, 228, 252, 0, 0, 0, 670, 285, 0, 0,
- 670, 0, 247, 667, 125, 125, 125, 125, 0, 0, 0, 0, 0, 266, 247, 350,
- 612, 0, 0, 671, 672, 252, 612, 612, 0, 330, 0, 0, 235, 125, 125, 285,
- 248, 248, 248, 248, 248, 248, 125, 125, 248, 248, 248, 319, 248, 248, 248, 248,
- 248, 318, 248, 248, 248, 248, 248, 248, 248, 248, 584, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 673, 125, 248, 318, 125, 125, 125, 125, 125, 125,
- 248, 248, 248, 248, 674, 248, 248, 248, 248, 248, 248, 125, 125, 125, 125, 125,
- 675, 125, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8,
+ 48, 48, 48, 48, 48, 48, 100, 48, 48, 48, 48, 48, 48, 204, 140, 140,
+ 48, 204, 140, 140, 140, 140, 140, 140, 48, 48, 48, 48, 71, 48, 48, 48,
+ 48, 48, 48, 140, 140, 140, 140, 140, 684, 140, 570, 570, 570, 570, 570, 570,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 140,
+ 391, 391, 391, 391, 391, 391, 391, 685, 391, 391, 391, 391, 391, 391, 391, 686,
+ 0, 0, 0, 0, 1, 2, 1, 2, 0, 0, 3, 3, 4, 5, 4, 5,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 0, 0, 7, 0,
+ 8, 8, 8, 8, 8, 8, 8, 9, 10, 11, 12, 11, 11, 11, 13, 11,
+ 14, 14, 14, 14, 14, 14, 14, 14, 15, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 16, 17, 18, 17, 17, 19, 20, 21, 21, 22, 21, 23, 24,
+ 25, 26, 27, 27, 28, 29, 27, 30, 27, 27, 27, 27, 27, 31, 27, 27,
+ 32, 33, 33, 33, 34, 27, 27, 27, 35, 35, 35, 36, 37, 37, 37, 38,
+ 39, 39, 40, 41, 42, 43, 44, 27, 45, 46, 27, 27, 27, 27, 47, 27,
+ 48, 48, 48, 48, 48, 49, 50, 48, 51, 52, 53, 54, 55, 56, 57, 58,
+ 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+ 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
+ 107, 108, 109, 109, 110, 111, 112, 109, 113, 114, 115, 116, 117, 118, 119, 120,
+ 121, 122, 122, 123, 122, 124, 125, 125, 126, 127, 128, 129, 130, 131, 125, 125,
+ 132, 132, 132, 132, 133, 132, 134, 135, 132, 133, 132, 136, 136, 137, 125, 125,
+ 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 139, 139, 140, 139, 139, 141,
+ 142, 142, 142, 142, 142, 142, 142, 142, 143, 143, 143, 143, 144, 145, 143, 143,
+ 144, 143, 143, 146, 147, 148, 143, 143, 143, 147, 143, 143, 143, 149, 143, 150,
+ 143, 151, 152, 152, 152, 152, 152, 153, 154, 154, 154, 154, 154, 154, 154, 154,
+ 155, 156, 157, 157, 157, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167,
+ 168, 168, 168, 168, 168, 169, 170, 170, 171, 172, 173, 173, 173, 173, 173, 174,
+ 173, 173, 175, 154, 154, 154, 154, 176, 177, 178, 179, 179, 180, 181, 182, 183,
+ 184, 184, 185, 184, 186, 187, 168, 168, 188, 189, 190, 190, 190, 191, 190, 192,
+ 193, 193, 194, 8, 195, 125, 125, 125, 196, 196, 196, 196, 197, 196, 196, 198,
+ 199, 199, 199, 199, 200, 200, 200, 201, 202, 202, 202, 203, 204, 205, 205, 205,
+ 206, 139, 139, 207, 208, 209, 210, 211, 4, 4, 212, 4, 4, 213, 214, 215,
+ 4, 4, 4, 216, 8, 8, 8, 8, 11, 217, 11, 11, 217, 218, 11, 219,
+ 11, 11, 11, 220, 220, 221, 11, 222, 223, 0, 0, 0, 0, 0, 224, 225,
+ 226, 227, 0, 0, 228, 8, 8, 229, 0, 0, 230, 231, 232, 0, 4, 4,
+ 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 234, 125, 235, 125, 0, 0, 236, 236, 236, 236, 236, 236, 236, 236,
+ 0, 0, 0, 0, 0, 0, 0, 237, 0, 238, 0, 0, 0, 0, 0, 0,
+ 239, 239, 239, 239, 239, 239, 4, 4, 240, 240, 240, 240, 240, 240, 240, 241,
+ 139, 139, 140, 242, 242, 242, 243, 244, 143, 245, 246, 246, 246, 246, 14, 14,
+ 0, 0, 0, 0, 0, 247, 125, 125, 248, 249, 248, 248, 248, 248, 248, 250,
+ 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 251, 125, 0,
+ 252, 0, 253, 254, 255, 256, 256, 256, 256, 257, 258, 259, 259, 259, 259, 260,
+ 261, 262, 262, 263, 142, 142, 142, 142, 264, 0, 262, 262, 0, 0, 265, 259,
+ 142, 264, 0, 0, 0, 0, 142, 266, 0, 0, 0, 0, 0, 259, 259, 267,
+ 259, 259, 259, 259, 259, 268, 0, 0, 248, 248, 248, 248, 0, 0, 0, 0,
+ 269, 269, 269, 269, 269, 269, 269, 269, 270, 269, 269, 269, 271, 272, 272, 272,
+ 273, 273, 273, 273, 273, 273, 273, 273, 273, 273, 274, 125, 14, 14, 14, 14,
+ 14, 14, 275, 275, 275, 275, 275, 276, 0, 0, 277, 4, 4, 4, 4, 4,
+ 278, 4, 4, 4, 279, 280, 125, 281, 282, 282, 283, 284, 285, 285, 285, 286,
+ 287, 287, 287, 287, 288, 289, 48, 48, 290, 290, 291, 292, 292, 293, 142, 294,
+ 295, 295, 295, 295, 296, 297, 138, 298, 299, 299, 299, 300, 301, 302, 138, 138,
+ 303, 303, 303, 303, 304, 305, 306, 307, 308, 309, 246, 4, 4, 310, 311, 152,
+ 152, 152, 152, 152, 306, 306, 312, 313, 142, 142, 314, 142, 315, 142, 142, 316,
+ 125, 125, 125, 125, 125, 125, 125, 125, 248, 248, 248, 248, 248, 248, 317, 248,
+ 248, 248, 248, 248, 248, 318, 125, 125, 319, 320, 21, 321, 322, 27, 27, 27,
+ 27, 27, 27, 27, 323, 324, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 325, 27, 27, 27, 27, 27, 326, 27, 27, 327, 125, 125, 27,
+ 8, 284, 328, 0, 0, 329, 330, 331, 27, 27, 27, 27, 27, 27, 27, 332,
+ 333, 0, 1, 2, 1, 2, 334, 258, 259, 335, 142, 264, 336, 337, 338, 339,
+ 340, 341, 342, 343, 344, 344, 125, 125, 341, 341, 341, 341, 341, 341, 341, 345,
+ 346, 0, 0, 347, 11, 11, 11, 11, 348, 349, 350, 125, 125, 0, 0, 351,
+ 352, 353, 354, 354, 354, 355, 356, 357, 358, 358, 359, 360, 361, 362, 362, 363,
+ 364, 365, 366, 366, 367, 368, 125, 125, 369, 369, 369, 369, 369, 370, 370, 370,
+ 371, 372, 373, 374, 374, 375, 374, 376, 377, 377, 378, 379, 379, 379, 380, 381,
+ 381, 382, 383, 384, 125, 125, 125, 125, 385, 385, 385, 385, 385, 385, 385, 385,
+ 385, 385, 385, 386, 385, 387, 388, 125, 389, 4, 4, 390, 125, 125, 125, 125,
+ 391, 392, 392, 393, 394, 395, 396, 396, 397, 398, 399, 125, 125, 125, 400, 401,
+ 402, 403, 404, 405, 125, 125, 125, 125, 406, 406, 407, 408, 407, 409, 407, 407,
+ 410, 411, 412, 413, 414, 414, 415, 415, 416, 416, 125, 125, 417, 417, 418, 419,
+ 420, 420, 420, 421, 422, 423, 424, 425, 426, 427, 428, 125, 125, 125, 125, 125,
+ 429, 429, 429, 429, 430, 125, 125, 125, 431, 431, 431, 432, 431, 431, 431, 433,
+ 434, 434, 435, 436, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 27, 45,
+ 437, 437, 438, 439, 125, 125, 125, 440, 441, 441, 442, 443, 443, 444, 125, 445,
+ 446, 125, 125, 447, 448, 125, 449, 450, 451, 451, 451, 451, 452, 453, 451, 454,
+ 455, 455, 455, 455, 456, 457, 458, 459, 460, 460, 460, 461, 462, 463, 463, 464,
+ 465, 465, 465, 465, 465, 465, 466, 467, 468, 469, 468, 468, 470, 125, 125, 125,
+ 471, 472, 473, 474, 474, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484,
+ 485, 485, 485, 485, 485, 486, 487, 125, 488, 488, 488, 488, 489, 490, 125, 125,
+ 491, 491, 491, 492, 491, 493, 125, 125, 494, 494, 494, 494, 495, 496, 497, 125,
+ 498, 498, 498, 499, 499, 125, 125, 125, 500, 501, 502, 500, 503, 125, 125, 125,
+ 504, 504, 504, 505, 125, 125, 125, 125, 125, 125, 506, 506, 506, 506, 506, 507,
+ 508, 509, 510, 511, 512, 513, 125, 125, 125, 125, 514, 515, 515, 514, 516, 125,
+ 517, 517, 517, 517, 518, 519, 519, 519, 519, 519, 520, 154, 521, 521, 521, 522,
+ 523, 125, 125, 125, 125, 125, 125, 125, 524, 525, 525, 526, 527, 525, 528, 529,
+ 529, 530, 531, 532, 125, 125, 125, 125, 533, 534, 534, 535, 536, 537, 538, 539,
+ 540, 541, 542, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 543, 544,
+ 545, 546, 545, 547, 545, 548, 125, 125, 125, 125, 125, 549, 550, 550, 550, 551,
+ 552, 552, 552, 552, 552, 552, 552, 552, 552, 553, 125, 125, 125, 125, 125, 125,
+ 552, 552, 552, 552, 552, 552, 554, 555, 552, 552, 552, 552, 556, 125, 125, 125,
+ 125, 557, 557, 557, 557, 557, 557, 558, 559, 559, 559, 559, 559, 559, 559, 559,
+ 559, 559, 559, 559, 559, 560, 125, 125, 561, 561, 561, 561, 561, 561, 561, 561,
+ 561, 561, 561, 561, 562, 125, 125, 125, 275, 275, 275, 275, 275, 275, 275, 275,
+ 275, 275, 275, 563, 564, 565, 566, 567, 567, 567, 567, 568, 569, 570, 571, 572,
+ 573, 573, 573, 573, 574, 575, 576, 577, 573, 125, 125, 125, 125, 125, 125, 125,
+ 125, 125, 125, 125, 578, 578, 578, 578, 578, 579, 125, 125, 125, 125, 125, 125,
+ 580, 580, 580, 580, 581, 580, 580, 580, 582, 580, 125, 125, 125, 125, 583, 584,
+ 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 586,
+ 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 588, 125, 125,
+ 589, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 590,
+ 591, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
+ 256, 256, 592, 593, 125, 594, 595, 596, 596, 596, 596, 596, 596, 596, 596, 596,
+ 596, 596, 596, 596, 596, 596, 596, 597, 598, 598, 598, 598, 598, 598, 599, 600,
+ 601, 602, 603, 125, 125, 125, 125, 125, 8, 8, 604, 8, 605, 0, 0, 0,
+ 0, 0, 0, 0, 603, 125, 125, 125, 0, 0, 0, 0, 0, 0, 0, 606,
+ 0, 0, 607, 0, 0, 0, 608, 609, 610, 0, 611, 0, 0, 0, 235, 125,
+ 11, 11, 11, 11, 612, 125, 125, 125, 125, 125, 125, 125, 0, 603, 0, 603,
+ 0, 0, 0, 0, 0, 234, 0, 613, 0, 0, 0, 0, 0, 224, 0, 0,
+ 0, 614, 615, 616, 617, 0, 0, 0, 618, 619, 0, 620, 621, 622, 0, 0,
+ 0, 0, 623, 0, 0, 0, 0, 0, 0, 0, 0, 0, 624, 0, 0, 0,
+ 625, 625, 625, 625, 625, 625, 625, 625, 626, 627, 628, 125, 125, 125, 125, 125,
+ 4, 629, 630, 125, 125, 125, 125, 125, 631, 632, 633, 14, 14, 14, 634, 125,
+ 635, 125, 125, 125, 125, 125, 125, 125, 636, 636, 637, 638, 639, 125, 125, 125,
+ 125, 640, 641, 125, 642, 642, 642, 643, 125, 125, 125, 125, 125, 644, 644, 645,
+ 125, 125, 125, 125, 125, 125, 646, 647, 648, 648, 648, 648, 648, 648, 648, 648,
+ 648, 648, 648, 648, 649, 650, 125, 125, 651, 651, 651, 651, 652, 653, 125, 125,
+ 125, 125, 125, 125, 125, 125, 125, 333, 0, 0, 0, 654, 125, 125, 125, 125,
+ 333, 0, 0, 247, 125, 125, 125, 125, 655, 27, 656, 657, 658, 659, 660, 661,
+ 662, 663, 664, 663, 125, 125, 125, 665, 0, 0, 357, 0, 0, 0, 0, 0,
+ 0, 603, 226, 333, 333, 333, 0, 606, 0, 0, 247, 125, 125, 125, 666, 0,
+ 667, 0, 0, 357, 613, 668, 606, 125, 0, 0, 0, 0, 0, 669, 349, 349,
+ 0, 0, 0, 0, 0, 0, 0, 670, 0, 0, 0, 0, 0, 284, 357, 228,
+ 357, 0, 0, 0, 671, 284, 0, 0, 671, 0, 247, 668, 125, 125, 125, 125,
+ 0, 0, 0, 0, 0, 603, 247, 349, 613, 0, 0, 672, 673, 357, 613, 613,
+ 0, 329, 0, 0, 235, 125, 125, 284, 248, 248, 248, 248, 248, 248, 125, 125,
+ 248, 248, 248, 318, 248, 248, 248, 248, 248, 317, 248, 248, 248, 248, 248, 248,
+ 248, 248, 584, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 674, 248,
+ 248, 248, 248, 248, 248, 317, 125, 125, 248, 317, 125, 125, 125, 125, 125, 125,
+ 248, 248, 248, 248, 675, 248, 248, 248, 248, 248, 248, 125, 125, 125, 125, 125,
+ 676, 125, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 1, 2, 2, 2,
2, 2, 3, 0, 0, 0, 4, 0, 2, 2, 2, 2, 2, 3, 2, 2,
2, 2, 5, 0, 2, 5, 6, 0, 7, 7, 7, 7, 8, 9, 10, 11,
@@ -4071,33 +4074,33 @@ _hb_ucd_u16[10040] =
0, 240, 0, 0, 241, 241, 241, 241, 18, 18, 18, 18, 18, 12, 242, 18,
243, 243, 243, 243, 243, 243, 12, 244, 245, 12, 12, 244, 151, 154, 12, 12,
151, 154, 151, 154, 0, 0, 0, 246, 247, 247, 247, 247, 247, 247, 248, 247,
- 247, 12, 12, 12, 247, 249, 12, 12, 0, 0, 0, 12, 0, 250, 0, 0,
- 251, 247, 252, 253, 0, 0, 247, 0, 254, 255, 255, 255, 255, 255, 255, 255,
- 255, 256, 257, 258, 259, 260, 260, 260, 260, 260, 260, 260, 260, 260, 261, 259,
- 12, 262, 263, 263, 263, 263, 263, 263, 264, 150, 150, 150, 150, 150, 150, 265,
- 0, 12, 12, 12, 150, 150, 150, 266, 260, 260, 260, 261, 260, 260, 0, 0,
- 267, 267, 267, 267, 267, 267, 267, 268, 267, 269, 12, 12, 270, 270, 270, 270,
- 271, 271, 271, 271, 271, 271, 271, 12, 272, 272, 272, 272, 272, 272, 12, 12,
- 237, 2, 2, 2, 2, 2, 231, 2, 2, 2, 273, 12, 274, 275, 276, 12,
- 277, 2, 2, 2, 278, 278, 278, 278, 278, 278, 278, 279, 0, 0, 246, 12,
- 280, 280, 280, 280, 280, 280, 12, 12, 281, 281, 281, 281, 281, 282, 12, 283,
- 281, 281, 282, 12, 284, 284, 284, 284, 284, 284, 284, 285, 286, 286, 286, 286,
- 286, 12, 12, 287, 150, 150, 150, 288, 289, 289, 289, 289, 289, 289, 289, 290,
- 289, 289, 291, 292, 145, 145, 145, 293, 294, 294, 294, 294, 294, 295, 12, 12,
- 294, 294, 294, 296, 294, 294, 296, 294, 297, 297, 297, 297, 298, 12, 12, 12,
- 12, 12, 299, 297, 300, 300, 300, 300, 300, 301, 12, 12, 155, 154, 155, 154,
- 155, 154, 12, 12, 2, 2, 3, 2, 2, 302, 303, 12, 300, 300, 300, 304,
- 300, 300, 304, 12, 150, 12, 12, 12, 150, 265, 305, 150, 150, 150, 150, 12,
- 247, 247, 247, 249, 247, 247, 249, 12, 2, 273, 12, 12, 306, 22, 12, 24,
- 25, 26, 25, 307, 308, 309, 25, 25, 50, 12, 12, 12, 310, 29, 29, 29,
- 29, 29, 29, 311, 312, 29, 29, 29, 29, 29, 12, 310, 7, 7, 7, 313,
- 232, 0, 0, 0, 0, 232, 0, 12, 29, 314, 29, 29, 29, 29, 29, 315,
- 316, 0, 0, 0, 0, 317, 260, 260, 260, 260, 260, 318, 319, 150, 319, 150,
- 319, 150, 319, 288, 0, 232, 0, 232, 12, 12, 316, 246, 320, 320, 320, 321,
- 320, 320, 320, 320, 320, 322, 320, 320, 320, 320, 322, 323, 320, 320, 320, 324,
- 320, 320, 322, 12, 232, 131, 0, 0, 0, 131, 0, 0, 8, 8, 8, 14,
- 0, 0, 0, 234, 325, 12, 12, 12, 0, 0, 0, 326, 327, 327, 327, 327,
- 327, 327, 327, 328, 329, 329, 329, 329, 330, 12, 12, 12, 215, 0, 0, 0,
+ 247, 12, 12, 12, 247, 249, 12, 12, 0, 250, 0, 0, 251, 247, 252, 253,
+ 0, 0, 247, 0, 254, 255, 255, 255, 255, 255, 255, 255, 255, 256, 257, 258,
+ 259, 260, 260, 260, 260, 260, 260, 260, 260, 260, 261, 259, 12, 262, 263, 263,
+ 263, 263, 263, 263, 264, 150, 150, 150, 150, 150, 150, 265, 0, 12, 12, 131,
+ 150, 150, 150, 266, 260, 260, 260, 261, 260, 260, 0, 0, 267, 267, 267, 267,
+ 267, 267, 267, 268, 267, 269, 12, 12, 270, 270, 270, 270, 271, 271, 271, 271,
+ 271, 271, 271, 12, 272, 272, 272, 272, 272, 272, 12, 12, 237, 2, 2, 2,
+ 2, 2, 231, 2, 2, 2, 273, 12, 274, 275, 276, 12, 277, 2, 2, 2,
+ 278, 278, 278, 278, 278, 278, 278, 279, 0, 0, 246, 12, 280, 280, 280, 280,
+ 280, 280, 12, 12, 281, 281, 281, 281, 281, 282, 12, 283, 281, 281, 282, 12,
+ 284, 284, 284, 284, 284, 284, 284, 285, 286, 286, 286, 286, 286, 12, 12, 287,
+ 150, 150, 150, 288, 289, 289, 289, 289, 289, 289, 289, 290, 289, 289, 291, 292,
+ 145, 145, 145, 293, 294, 294, 294, 294, 294, 295, 12, 12, 294, 294, 294, 296,
+ 294, 294, 296, 294, 297, 297, 297, 297, 298, 12, 12, 12, 12, 12, 299, 297,
+ 300, 300, 300, 300, 300, 301, 12, 12, 155, 154, 155, 154, 155, 154, 12, 12,
+ 2, 2, 3, 2, 2, 302, 303, 12, 300, 300, 300, 304, 300, 300, 304, 12,
+ 150, 12, 12, 12, 150, 265, 305, 150, 150, 150, 150, 12, 247, 247, 247, 249,
+ 247, 247, 249, 12, 2, 273, 12, 12, 306, 22, 12, 24, 25, 26, 25, 307,
+ 308, 309, 25, 25, 50, 12, 12, 12, 310, 29, 29, 29, 29, 29, 29, 311,
+ 312, 29, 29, 29, 29, 29, 12, 310, 7, 7, 7, 313, 232, 0, 0, 0,
+ 0, 232, 0, 12, 29, 314, 29, 29, 29, 29, 29, 315, 316, 0, 0, 0,
+ 0, 317, 260, 260, 260, 260, 260, 318, 319, 150, 319, 150, 319, 150, 319, 288,
+ 0, 232, 0, 232, 12, 12, 316, 246, 320, 320, 320, 321, 320, 320, 320, 320,
+ 320, 322, 320, 320, 320, 320, 322, 323, 320, 320, 320, 324, 320, 320, 322, 12,
+ 232, 131, 0, 0, 0, 131, 0, 0, 8, 8, 8, 14, 0, 0, 0, 234,
+ 325, 12, 12, 12, 0, 0, 0, 326, 327, 327, 327, 327, 327, 327, 327, 328,
+ 329, 329, 329, 329, 330, 12, 12, 12, 215, 0, 0, 0, 0, 0, 0, 12,
331, 331, 331, 331, 331, 12, 12, 332, 333, 333, 333, 333, 333, 333, 334, 12,
335, 335, 335, 335, 335, 335, 336, 12, 337, 337, 337, 337, 337, 337, 337, 338,
339, 339, 339, 339, 339, 12, 339, 339, 339, 340, 12, 12, 341, 341, 341, 341,
@@ -4159,232 +4162,232 @@ _hb_ucd_u16[10040] =
260, 556, 260, 557, 558, 255, 255, 255, 559, 12, 12, 12, 560, 12, 12, 12,
256, 561, 12, 12, 12, 260, 12, 12, 562, 562, 562, 562, 562, 562, 562, 12,
563, 563, 563, 563, 563, 563, 564, 12, 563, 563, 563, 565, 563, 563, 565, 12,
- 563, 563, 566, 563, 7, 7, 7, 567, 7, 199, 12, 12, 0, 246, 12, 12,
- 0, 232, 316, 0, 0, 568, 228, 0, 0, 0, 568, 7, 213, 569, 7, 0,
- 0, 0, 570, 228, 8, 225, 12, 12, 0, 0, 234, 12, 0, 0, 0, 229,
- 571, 572, 316, 229, 0, 0, 240, 316, 0, 316, 0, 0, 0, 240, 232, 316,
- 0, 229, 0, 229, 0, 0, 240, 232, 0, 573, 239, 0, 229, 0, 0, 0,
- 0, 246, 0, 0, 0, 0, 0, 239, 574, 574, 574, 574, 574, 574, 574, 12,
- 12, 12, 575, 574, 576, 574, 574, 574, 2, 2, 2, 273, 12, 275, 273, 12,
- 241, 577, 241, 241, 241, 241, 578, 241, 579, 580, 577, 12, 19, 19, 19, 581,
- 12, 12, 12, 582, 583, 583, 583, 583, 583, 583, 583, 584, 583, 583, 583, 585,
- 583, 583, 585, 586, 587, 587, 587, 587, 587, 587, 587, 588, 589, 589, 589, 589,
- 589, 589, 590, 591, 592, 592, 592, 592, 592, 592, 593, 12, 151, 154, 151, 594,
- 151, 151, 151, 154, 595, 595, 595, 595, 595, 596, 595, 595, 595, 597, 12, 12,
- 598, 598, 598, 598, 598, 598, 598, 12, 598, 598, 599, 600, 0, 234, 12, 12,
- 29, 414, 29, 29, 601, 602, 414, 29, 50, 29, 603, 12, 604, 310, 603, 414,
- 601, 602, 603, 603, 601, 602, 50, 29, 50, 29, 414, 605, 29, 29, 606, 29,
- 29, 29, 29, 12, 414, 414, 606, 29, 51, 12, 12, 12, 12, 239, 0, 0,
- 607, 12, 12, 12, 246, 12, 12, 12, 0, 0, 12, 0, 0, 232, 131, 0,
- 0, 0, 12, 12, 0, 0, 0, 240, 0, 246, 12, 239, 608, 12, 12, 12,
- 247, 247, 609, 12, 610, 12, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 939, 940, 941, 942, 946, 948, 0, 962,
- 969, 970, 971, 976,1001,1002,1003,1008, 0,1033,1040,1041,1042,1043,1047, 0,
- 0,1080,1081,1082,1086,1110, 0, 0,1124,1125,1126,1127,1131,1133, 0,1147,
- 1154,1155,1156,1161,1187,1188,1189,1193, 0,1219,1226,1227,1228,1229,1233, 0,
- 0,1267,1268,1269,1273,1298, 0,1303, 943,1128, 944,1129, 954,1139, 958,1143,
- 959,1144, 960,1145, 961,1146, 964,1149, 0, 0, 973,1158, 974,1159, 975,1160,
- 983,1168, 978,1163, 988,1173, 990,1175, 991,1176, 993,1178, 994,1179, 0, 0,
- 1004,1190,1005,1191,1006,1192,1014,1199,1007, 0, 0, 0,1016,1201,1020,1206,
- 0,1022,1208,1025,1211,1023,1209, 0, 0, 0, 0,1032,1218,1037,1223,1035,
- 1221, 0, 0, 0,1044,1230,1045,1231,1049,1235, 0, 0,1058,1244,1064,1250,
- 1060,1246,1066,1252,1067,1253,1072,1258,1069,1255,1077,1264,1074,1261, 0, 0,
- 1083,1270,1084,1271,1085,1272,1088,1275,1089,1276,1096,1283,1103,1290,1111,1299,
- 1115,1118,1307,1120,1309,1121,1310, 0,1053,1239, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,1093,1280, 0, 0, 0, 0, 0, 0, 0,
+ 563, 563, 566, 563, 0, 12, 12, 12, 7, 7, 7, 567, 7, 199, 12, 12,
+ 0, 246, 12, 12, 0, 232, 316, 0, 0, 568, 228, 0, 0, 0, 568, 7,
+ 213, 569, 7, 0, 0, 0, 570, 228, 8, 225, 12, 12, 0, 0, 234, 12,
+ 0, 0, 0, 229, 571, 572, 316, 229, 0, 0, 240, 316, 0, 316, 0, 0,
+ 0, 240, 232, 316, 0, 229, 0, 229, 0, 0, 240, 232, 0, 573, 239, 0,
+ 229, 0, 0, 0, 0, 246, 0, 0, 0, 0, 0, 239, 574, 574, 574, 574,
+ 574, 574, 574, 12, 12, 12, 575, 574, 576, 574, 574, 574, 2, 2, 2, 273,
+ 12, 275, 273, 12, 241, 577, 241, 241, 241, 241, 578, 241, 579, 580, 577, 12,
+ 19, 19, 19, 581, 12, 12, 12, 582, 583, 583, 583, 583, 583, 583, 583, 584,
+ 583, 583, 583, 585, 583, 583, 585, 586, 587, 587, 587, 587, 587, 587, 587, 588,
+ 589, 589, 589, 589, 589, 589, 590, 591, 592, 592, 592, 592, 592, 592, 593, 12,
+ 151, 154, 151, 594, 151, 151, 151, 154, 595, 595, 595, 595, 595, 596, 595, 595,
+ 595, 597, 12, 12, 598, 598, 598, 598, 598, 598, 598, 12, 598, 598, 599, 600,
+ 0, 234, 12, 12, 29, 414, 29, 29, 601, 602, 414, 29, 50, 29, 603, 12,
+ 604, 310, 603, 414, 601, 602, 603, 603, 601, 602, 50, 29, 50, 29, 414, 605,
+ 29, 29, 606, 29, 29, 29, 29, 12, 414, 414, 606, 29, 51, 12, 12, 12,
+ 12, 239, 0, 0, 607, 12, 12, 12, 246, 12, 12, 12, 0, 0, 12, 0,
+ 0, 232, 131, 0, 0, 0, 12, 12, 0, 0, 0, 240, 0, 246, 12, 239,
+ 608, 12, 12, 12, 247, 247, 609, 12, 610, 12, 12, 12, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 939, 940, 941, 942,
+ 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008, 0,1033,1040,1041,
+ 1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, 0,1124,1125,1126,1127,
+ 1131,1133, 0,1147,1154,1155,1156,1161,1187,1188,1189,1193, 0,1219,1226,1227,
+ 1228,1229,1233, 0, 0,1267,1268,1269,1273,1298, 0,1303, 943,1128, 944,1129,
+ 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149, 0, 0, 973,1158,
+ 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175, 991,1176, 993,1178,
+ 994,1179, 0, 0,1004,1190,1005,1191,1006,1192,1014,1199,1007, 0, 0, 0,
+ 1016,1201,1020,1206, 0,1022,1208,1025,1211,1023,1209, 0, 0, 0, 0,1032,
+ 1218,1037,1223,1035,1221, 0, 0, 0,1044,1230,1045,1231,1049,1235, 0, 0,
+ 1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258,1069,1255,1077,1264,
+ 1074,1261, 0, 0,1083,1270,1084,1271,1085,1272,1088,1275,1089,1276,1096,1283,
+ 1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310, 0,1053,1239, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1093,1280, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 949,1134,1010,1195,1050,1236,1090,1277,1341,1368,1340,
- 1367,1342,1369,1339,1366, 0,1320,1347,1418,1419,1323,1350, 0, 0, 992,1177,
- 1018,1204,1055,1241,1416,1417,1415,1424,1202, 0, 0, 0, 987,1172, 0, 0,
- 1031,1217,1321,1348,1322,1349,1338,1365, 950,1135, 951,1136, 979,1164, 980,1165,
- 1011,1196,1012,1197,1051,1237,1052,1238,1061,1247,1062,1248,1091,1278,1092,1279,
- 1071,1257,1076,1263, 0, 0, 997,1182, 0, 0, 0, 0, 0, 0, 945,1130,
- 982,1167,1337,1364,1335,1362,1046,1232,1422,1423,1113,1301, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 10,1425, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,1314,1427, 5,
- 1434,1438,1443, 0,1450, 0,1455,1461,1514, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 949,1134,1010,1195,1050,1236,1090,
+ 1277,1341,1368,1340,1367,1342,1369,1339,1366, 0,1320,1347,1418,1419,1323,1350,
+ 0, 0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424,1202, 0, 0, 0,
+ 987,1172, 0, 0,1031,1217,1321,1348,1322,1349,1338,1365, 950,1135, 951,1136,
+ 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238,1061,1247,1062,1248,
+ 1091,1278,1092,1279,1071,1257,1076,1263, 0, 0, 997,1182, 0, 0, 0, 0,
+ 0, 0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232,1422,1423,1113,1301,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 10,
+ 1425, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0,1314,1427, 5,1434,1438,1443, 0,1450, 0,1455,1461,1514, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,1446,1458,1468,1476,1480,1486,1517, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,1489,1503,1494,1500,1508, 0, 0, 0, 0,1520,1521, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1526,1528, 0,1525, 0, 0, 0,1522,
- 0, 0, 0, 0,1536,1532,1539, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1556, 0, 0, 0, 0, 0, 0,1548,1550, 0,1547, 0, 0, 0,1567,
- 0, 0, 0, 0,1558,1554,1561, 0, 0, 0, 0, 0, 0, 0,1568,1569,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1529,1551, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1523,1545,1524,1546, 0, 0,1527,1549,
- 0, 0,1570,1571,1530,1552,1531,1553, 0, 0,1533,1555,1535,1557,1537,1559,
- 0, 0,1572,1573,1544,1566,1538,1560,1540,1562,1541,1563,1542,1564, 0, 0,
- 1543,1565, 0, 0, 0, 0, 0, 0, 0, 0,1606,1607,1609,1608,1610, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1613, 0,1611, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1612, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1446,1458,1468,1476,1480,1486,1517, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1620, 0, 0, 0, 0, 0, 0, 0,1623, 0, 0,1624, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1489,1503,1494,1500,1508, 0, 0, 0, 0,1520,
+ 1521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1526,1528, 0,1525,
+ 0, 0, 0,1522, 0, 0, 0, 0,1536,1532,1539, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1556, 0, 0, 0, 0, 0, 0,1548,1550, 0,1547,
+ 0, 0, 0,1567, 0, 0, 0, 0,1558,1554,1561, 0, 0, 0, 0, 0,
+ 0, 0,1568,1569, 0, 0, 0, 0, 0, 0, 0, 0, 0,1529,1551, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1523,1545,1524,1546,
+ 0, 0,1527,1549, 0, 0,1570,1571,1530,1552,1531,1553, 0, 0,1533,1555,
+ 1535,1557,1537,1559, 0, 0,1572,1573,1544,1566,1538,1560,1540,1562,1541,1563,
+ 1542,1564, 0, 0,1543,1565, 0, 0, 0, 0, 0, 0, 0, 0,1606,1607,
+ 1609,1608,1610, 0, 0, 0, 0, 0, 0, 0, 0, 0,1613, 0,1611, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1612,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1614,1615,1616,1617,1618,1619,1621,1622, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1628,1629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1625,1626, 0,1627, 0, 0, 0,1634, 0, 0,1635, 0,
+ 0, 0, 0, 0, 0,1620, 0, 0, 0, 0, 0, 0, 0,1623, 0, 0,
+ 1624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1614,1615,1616,1617,1618,1619,1621,1622, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,1628,1629, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1625,1626, 0,1627, 0, 0, 0,1634,
+ 0, 0,1635, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1630,1631,1632, 0, 0,1633, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1639, 0, 0,1638,1640, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1636,1637, 0, 0, 0, 0, 0, 0,
+ 1641, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1642,1644,1643, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1645, 0, 0, 0, 0, 0, 0, 0,1646, 0, 0, 0,
+ 0, 0, 0,1648,1649, 0,1647,1650, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1651,1653,1652, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1654, 0,1655,1657,1656, 0, 0, 0, 0,1659,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1660, 0, 0, 0, 0,1661, 0,
+ 0, 0, 0,1662, 0, 0, 0, 0,1663, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1658, 0, 0, 0, 0, 0, 0, 0, 0, 0,1664,
+ 0,1665,1673, 0,1674, 0, 0, 0, 0, 0, 0, 0, 0,1666, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1668,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1669, 0, 0, 0, 0,1670, 0,
+ 0, 0, 0,1671, 0, 0, 0, 0,1672, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,1667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1675, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,1676, 0,1677, 0,1678, 0,1679, 0,1680, 0, 0, 0,1681, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1630,1631,1632, 0, 0,1633, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1639, 0, 0,1638,1640, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1636,1637, 0, 0, 0, 0, 0, 0,1641, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,1682, 0,1683, 0, 0,1684,1685, 0,1686,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 953,1138, 955,1140,
+ 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153, 966,1151, 967,1152,
+ 1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171, 989,1174, 995,1180,
+ 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356,1017,1203,1019,1205,
+ 1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214,1029,1215,1030,1216,
+ 1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363,1382,1384,1383,1385,
+ 1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251,1068,1254,1070,1256,
+ 1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266,1078,1265,1095,1282,
+ 1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287,1101,1288,1102,1289,
+ 1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302,1119,1308,1122,1311,
+ 1123,1312,1186,1260,1293,1305, 0,1394, 0, 0, 0, 0, 952,1137, 947,1132,
+ 1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375,1370,1374,1373,1377,
+ 1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353,1325,1352,1328,1355,
+ 1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234,1331,1358,1330,1357,
+ 1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403,1397,1402,1399,1404,
+ 1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412,1409,1414,1109,1297,
+ 1117,1306,1116,1304,1112,1300, 0, 0, 0, 0, 0, 0,1471,1472,1701,1705,
+ 1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721,1477,1478,1729,1731,
+ 1730,1732, 0, 0,1435,1436,1733,1735,1734,1736, 0, 0,1481,1482,1737,1741,
+ 1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757,1490,1491,1765,1768,
+ 1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776,1495,1496,1777,1779,
+ 1778,1780, 0, 0,1451,1452,1781,1783,1782,1784, 0, 0,1504,1505,1785,1788,
+ 1786,1789,1787,1790, 0,1459, 0,1791, 0,1792, 0,1793,1509,1510,1794,1798,
+ 1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814,1467, 21,1475, 22,
+ 1479, 23,1485, 24,1493, 27,1499, 28,1507, 29, 0, 0,1704,1708,1709,1710,
+ 1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728,1740,1744,1745,1746,
+ 1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764,1797,1801,1802,1803,
+ 1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821,1470,1469,1822,1474,
+ 1465, 0,1473,1825,1429,1428,1426, 12,1432, 0, 26, 0, 0,1315,1823,1484,
+ 1466, 0,1483,1829,1433, 13,1437, 14,1441,1826,1827,1828,1488,1487,1513, 19,
+ 0, 0,1492,1515,1445,1444,1442, 15, 0,1831,1832,1833,1502,1501,1516, 25,
+ 1497,1498,1506,1518,1457,1456,1454, 17,1453,1313, 11, 3, 0, 0,1824,1512,
+ 1519, 0,1511,1830,1449, 16,1460, 18,1464, 4, 0, 0, 30, 31, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,1642,1644,1643, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1645, 0, 0, 0, 0, 0, 0, 0,1646, 0, 0, 0, 0, 0, 0,1648,
- 1649, 0,1647,1650, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,1651,1653,1652, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,1654, 0,1655,1657,1656, 0, 0, 0, 0,1659, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,1660, 0, 0, 0, 0,1661, 0, 0, 0, 0,1662,
- 0, 0, 0, 0,1663, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1658, 0, 0, 0, 0, 0, 0, 0, 0, 0,1664, 0,1665,1673, 0,
- 1674, 0, 0, 0, 0, 0, 0, 0, 0,1666, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1668, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,1669, 0, 0, 0, 0,1670, 0, 0, 0, 0,1671,
- 0, 0, 0, 0,1672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1675, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1676, 0,
- 1677, 0,1678, 0,1679, 0,1680, 0, 0, 0,1681, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1682, 0,1683, 0, 0,1684,1685, 0,1686, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 953,1138, 955,1140, 956,1141, 957,1142,
- 1324,1351, 963,1148, 965,1150, 968,1153, 966,1151, 967,1152,1378,1380,1379,1381,
- 984,1169, 985,1170,1420,1421, 986,1171, 989,1174, 995,1180, 998,1183, 996,1181,
- 999,1184,1000,1185,1015,1200,1329,1356,1017,1203,1019,1205,1021,1207,1024,1210,
- 1687,1688,1027,1213,1026,1212,1028,1214,1029,1215,1030,1216,1034,1220,1036,1222,
- 1039,1225,1038,1224,1334,1361,1336,1363,1382,1384,1383,1385,1056,1242,1057,1243,
- 1059,1245,1063,1249,1689,1690,1065,1251,1068,1254,1070,1256,1386,1387,1388,1389,
- 1691,1692,1073,1259,1075,1262,1079,1266,1078,1265,1095,1282,1098,1285,1097,1284,
- 1390,1391,1392,1393,1099,1286,1100,1287,1101,1288,1102,1289,1105,1292,1104,1291,
- 1106,1294,1107,1295,1108,1296,1114,1302,1119,1308,1122,1311,1123,1312,1186,1260,
- 1293,1305, 0,1394, 0, 0, 0, 0, 952,1137, 947,1132,1317,1344,1316,1343,
- 1319,1346,1318,1345,1693,1695,1371,1375,1370,1374,1373,1377,1372,1376,1694,1696,
- 981,1166, 977,1162, 972,1157,1326,1353,1325,1352,1328,1355,1327,1354,1697,1698,
- 1009,1194,1013,1198,1054,1240,1048,1234,1331,1358,1330,1357,1333,1360,1332,1359,
- 1699,1700,1396,1401,1395,1400,1398,1403,1397,1402,1399,1404,1094,1281,1087,1274,
- 1406,1411,1405,1410,1408,1413,1407,1412,1409,1414,1109,1297,1117,1306,1116,1304,
- 1112,1300, 0, 0, 0, 0, 0, 0,1471,1472,1701,1705,1702,1706,1703,1707,
- 1430,1431,1715,1719,1716,1720,1717,1721,1477,1478,1729,1731,1730,1732, 0, 0,
- 1435,1436,1733,1735,1734,1736, 0, 0,1481,1482,1737,1741,1738,1742,1739,1743,
- 1439,1440,1751,1755,1752,1756,1753,1757,1490,1491,1765,1768,1766,1769,1767,1770,
- 1447,1448,1771,1774,1772,1775,1773,1776,1495,1496,1777,1779,1778,1780, 0, 0,
- 1451,1452,1781,1783,1782,1784, 0, 0,1504,1505,1785,1788,1786,1789,1787,1790,
- 0,1459, 0,1791, 0,1792, 0,1793,1509,1510,1794,1798,1795,1799,1796,1800,
- 1462,1463,1808,1812,1809,1813,1810,1814,1467, 21,1475, 22,1479, 23,1485, 24,
- 1493, 27,1499, 28,1507, 29, 0, 0,1704,1708,1709,1710,1711,1712,1713,1714,
- 1718,1722,1723,1724,1725,1726,1727,1728,1740,1744,1745,1746,1747,1748,1749,1750,
- 1754,1758,1759,1760,1761,1762,1763,1764,1797,1801,1802,1803,1804,1805,1806,1807,
- 1811,1815,1816,1817,1818,1819,1820,1821,1470,1469,1822,1474,1465, 0,1473,1825,
- 1429,1428,1426, 12,1432, 0, 26, 0, 0,1315,1823,1484,1466, 0,1483,1829,
- 1433, 13,1437, 14,1441,1826,1827,1828,1488,1487,1513, 19, 0, 0,1492,1515,
- 1445,1444,1442, 15, 0,1831,1832,1833,1502,1501,1516, 25,1497,1498,1506,1518,
- 1457,1456,1454, 17,1453,1313, 11, 3, 0, 0,1824,1512,1519, 0,1511,1830,
- 1449, 16,1460, 18,1464, 4, 0, 0, 30, 31, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0,
- 0, 0, 2, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,1834,1835, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,1836, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,1837,1839,1838, 0, 0, 0, 0,1840, 0, 0, 0,
- 0,1841, 0, 0,1842, 0, 0, 0, 0, 0, 0, 0,1843, 0,1844, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1845, 0, 0,1846, 0, 0,1847,
- 0,1848, 0, 0, 0, 0, 0, 0, 937, 0,1850, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,1849, 936, 938,1851,1852, 0, 0,1853,1854, 0, 0,
- 1855,1856, 0, 0, 0, 0, 0, 0,1857,1858, 0, 0,1861,1862, 0, 0,
- 1863,1864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1867,1868,1869,1870,1859,1860,1865,1866, 0, 0, 0, 0,
- 0, 0,1871,1872,1873,1874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1877, 0,1878, 0,1879, 0,1880, 0,1881, 0,1882, 0,
- 1883, 0,1884, 0,1885, 0,1886, 0,1887, 0,1888, 0, 0,1889, 0,1890,
- 0,1891, 0, 0, 0, 0, 0, 0,1892,1893, 0,1894,1895, 0,1896,1897,
- 0,1898,1899, 0,1900,1901, 0, 0, 0, 0, 0, 0,1876, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,1902, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1904, 0,1905, 0,1906, 0,1907, 0,1908, 0,1909, 0,
- 1910, 0,1911, 0,1912, 0,1913, 0,1914, 0,1915, 0, 0,1916, 0,1917,
- 0,1918, 0, 0, 0, 0, 0, 0,1919,1920, 0,1921,1922, 0,1923,1924,
- 0,1925,1926, 0,1927,1928, 0, 0, 0, 0, 0, 0,1903, 0, 0,1929,
- 1930,1931,1932, 0, 0, 0,1933, 0, 710, 385, 724, 715, 455, 103, 186, 825,
- 825, 242, 751, 205, 241, 336, 524, 601, 663, 676, 688, 738, 411, 434, 474, 500,
- 649, 746, 799, 108, 180, 416, 482, 662, 810, 275, 462, 658, 692, 344, 618, 679,
- 293, 388, 440, 492, 740, 116, 146, 168, 368, 414, 481, 527, 606, 660, 665, 722,
- 781, 803, 809, 538, 553, 588, 642, 758, 811, 701, 233, 299, 573, 612, 487, 540,
- 714, 779, 232, 267, 412, 445, 457, 585, 594, 766, 167, 613, 149, 148, 560, 589,
- 648, 768, 708, 345, 411, 704, 105, 259, 313, 496, 518, 174, 542, 120, 307, 101,
- 430, 372, 584, 183, 228, 529, 650, 697, 424, 732, 428, 349, 632, 355, 517, 110,
- 135, 147, 403, 580, 624, 700, 750, 170, 193, 245, 297, 374, 463, 543, 763, 801,
- 812, 815, 162, 384, 420, 730, 287, 330, 337, 366, 459, 476, 509, 558, 591, 610,
- 726, 652, 734, 759, 154, 163, 198, 473, 683, 697, 292, 311, 353, 423, 572, 494,
- 113, 217, 259, 280, 314, 499, 506, 603, 608, 752, 778, 782, 788, 117, 557, 748,
- 774, 320, 109, 126, 260, 265, 373, 411, 479, 523, 655, 737, 823, 380, 765, 161,
- 395, 398, 438, 451, 502, 516, 537, 583, 791, 136, 340, 769, 122, 273, 446, 727,
- 305, 322, 400, 496, 771, 155, 190, 269, 377, 391, 406, 432, 501, 519, 599, 684,
- 687, 749, 776, 175, 452, 191, 480, 510, 659, 772, 805, 813, 397, 444, 619, 566,
- 568, 575, 491, 471, 707, 111, 636, 156, 153, 288, 346, 578, 256, 435, 383, 729,
- 680, 767, 694, 295, 128, 210, 0, 0, 227, 0, 379, 0, 0, 150, 493, 525,
- 544, 551, 552, 556, 783, 576, 604, 0, 661, 0, 703, 0, 0, 735, 743, 0,
- 0, 0, 793, 794, 795, 808, 741, 773, 118, 127, 130, 166, 169, 177, 207, 213,
- 215, 226, 229, 268, 270, 317, 327, 329, 335, 369, 375, 381, 404, 441, 448, 458,
- 477, 484, 503, 539, 545, 547, 546, 548, 549, 550, 554, 555, 561, 564, 569, 591,
- 593, 595, 598, 607, 620, 625, 625, 651, 690, 695, 705, 706, 716, 717, 733, 735,
- 777, 786, 790, 315, 869, 623, 0, 0, 102, 145, 134, 115, 129, 138, 165, 171,
- 207, 202, 206, 212, 227, 231, 240, 243, 250, 254, 294, 296, 303, 308, 319, 325,
- 321, 329, 326, 335, 341, 357, 360, 362, 370, 379, 388, 389, 393, 421, 424, 438,
- 456, 454, 458, 465, 477, 535, 485, 490, 493, 507, 512, 514, 521, 522, 525, 526,
- 528, 533, 532, 541, 565, 569, 574, 586, 591, 597, 607, 637, 647, 674, 691, 693,
- 695, 698, 703, 699, 705, 704, 702, 706, 709, 717, 728, 736, 747, 754, 770, 777,
- 783, 784, 786, 787, 790, 802, 825, 848, 847, 857, 55, 65, 66, 883, 892, 916,
- 822, 824, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,1586, 0,1605, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,1602,1603,1934,1935,1574,1575,1576,1577,1579,1580,1581,1583,1584, 0,
- 1585,1587,1588,1589,1591, 0,1592, 0,1593,1594, 0,1595,1596, 0,1598,1599,
- 1600,1601,1604,1582,1578,1590,1597, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,1936, 0,1937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,1939,1940, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1941,1942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1944,1943, 0,1945, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,1946,1947, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,1949,1950,1951,1952,1953,1954,1955, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1956,1957,1958,1960,1959,1961, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 106, 104, 107, 826, 114, 118, 119, 121,
- 123, 124, 127, 125, 34, 830, 130, 131, 132, 137, 827, 35, 133, 139, 829, 142,
- 143, 112, 144, 145, 924, 151, 152, 37, 157, 158, 159, 160, 38, 165, 166, 169,
- 171, 172, 173, 174, 176, 177, 178, 179, 181, 182, 182, 182, 833, 468, 184, 185,
- 834, 187, 188, 189, 196, 192, 194, 195, 197, 199, 200, 201, 203, 204, 204, 206,
- 208, 209, 211, 218, 213, 219, 214, 216, 153, 234, 221, 222, 223, 220, 225, 224,
- 230, 835, 235, 236, 237, 238, 239, 244, 836, 837, 247, 248, 249, 246, 251, 39,
- 40, 253, 255, 255, 838, 257, 258, 259, 261, 839, 262, 263, 301, 264, 41, 266,
- 270, 272, 271, 841, 274, 842, 277, 276, 278, 281, 282, 42, 283, 284, 285, 286,
- 43, 843, 44, 289, 290, 291, 293, 934, 298, 845, 845, 621, 300, 300, 45, 852,
- 894, 302, 304, 46, 306, 309, 310, 312, 316, 48, 47, 317, 846, 318, 323, 324,
- 325, 324, 328, 329, 333, 331, 332, 334, 335, 336, 338, 339, 342, 343, 347, 351,
- 849, 350, 348, 352, 354, 359, 850, 361, 358, 356, 49, 363, 365, 367, 364, 50,
- 369, 371, 851, 376, 386, 378, 53, 381, 52, 51, 140, 141, 387, 382, 614, 78,
- 388, 389, 390, 394, 392, 856, 54, 399, 396, 402, 404, 858, 405, 401, 407, 55,
- 408, 409, 410, 413, 859, 415, 56, 417, 860, 418, 57, 419, 422, 424, 425, 861,
- 840, 862, 426, 863, 429, 431, 427, 433, 437, 441, 438, 439, 442, 443, 864, 436,
- 449, 450, 58, 454, 453, 865, 447, 460, 866, 867, 461, 466, 465, 464, 59, 467,
- 470, 469, 472, 828, 475, 868, 478, 870, 483, 485, 486, 871, 488, 489, 872, 873,
- 495, 497, 60, 498, 61, 61, 504, 505, 507, 508, 511, 62, 513, 874, 515, 875,
- 518, 844, 520, 876, 877, 878, 63, 64, 528, 880, 879, 881, 882, 530, 531, 531,
- 533, 66, 534, 67, 68, 884, 536, 538, 541, 69, 885, 549, 886, 887, 556, 559,
- 70, 561, 562, 563, 888, 889, 889, 567, 71, 890, 570, 571, 72, 891, 577, 73,
- 581, 579, 582, 893, 587, 74, 590, 592, 596, 75, 895, 896, 76, 897, 600, 898,
- 602, 605, 607, 899, 900, 609, 901, 611, 853, 77, 615, 616, 79, 617, 252, 902,
- 903, 854, 855, 621, 622, 731, 80, 627, 626, 628, 164, 629, 630, 631, 633, 904,
- 632, 634, 639, 640, 635, 641, 646, 651, 638, 643, 644, 645, 905, 907, 906, 81,
- 653, 654, 656, 911, 657, 908, 82, 83, 909, 910, 84, 664, 665, 666, 667, 669,
- 668, 671, 670, 674, 672, 673, 675, 85, 677, 678, 86, 681, 682, 912, 685, 686,
- 87, 689, 36, 913, 914, 88, 89, 696, 702, 709, 711, 915, 712, 713, 718, 719,
- 917, 831, 721, 720, 723, 832, 725, 728, 918, 919, 739, 742, 744, 920, 745, 753,
- 756, 757, 755, 760, 761, 921, 762, 90, 764, 922, 91, 775, 279, 780, 923, 925,
- 92, 93, 785, 926, 94, 927, 787, 787, 789, 928, 792, 95, 796, 797, 798, 800,
- 96, 929, 802, 804, 806, 97, 98, 807, 930, 99, 931, 932, 933, 814, 100, 816,
- 817, 818, 819, 820, 821, 935, 0, 0,
+ 0, 0, 20, 0, 0, 0, 2, 6, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1834,1835, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1836, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1837,1839,1838, 0, 0, 0, 0,
+ 1840, 0, 0, 0, 0,1841, 0, 0,1842, 0, 0, 0, 0, 0, 0, 0,
+ 1843, 0,1844, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1845, 0, 0,
+ 1846, 0, 0,1847, 0,1848, 0, 0, 0, 0, 0, 0, 937, 0,1850, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1849, 936, 938,1851,1852, 0, 0,
+ 1853,1854, 0, 0,1855,1856, 0, 0, 0, 0, 0, 0,1857,1858, 0, 0,
+ 1861,1862, 0, 0,1863,1864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1867,1868,1869,1870,1859,1860,1865,1866,
+ 0, 0, 0, 0, 0, 0,1871,1872,1873,1874, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1875, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1877, 0,1878, 0,1879, 0,1880, 0,
+ 1881, 0,1882, 0,1883, 0,1884, 0,1885, 0,1886, 0,1887, 0,1888, 0,
+ 0,1889, 0,1890, 0,1891, 0, 0, 0, 0, 0, 0,1892,1893, 0,1894,
+ 1895, 0,1896,1897, 0,1898,1899, 0,1900,1901, 0, 0, 0, 0, 0, 0,
+ 1876, 0, 0, 0, 0, 0, 0, 0, 0, 0,1902, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1904, 0,1905, 0,1906, 0,1907, 0,
+ 1908, 0,1909, 0,1910, 0,1911, 0,1912, 0,1913, 0,1914, 0,1915, 0,
+ 0,1916, 0,1917, 0,1918, 0, 0, 0, 0, 0, 0,1919,1920, 0,1921,
+ 1922, 0,1923,1924, 0,1925,1926, 0,1927,1928, 0, 0, 0, 0, 0, 0,
+ 1903, 0, 0,1929,1930,1931,1932, 0, 0, 0,1933, 0, 710, 385, 724, 715,
+ 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601, 663, 676, 688, 738,
+ 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662, 810, 275, 462, 658,
+ 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168, 368, 414, 481, 527,
+ 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758, 811, 701, 233, 299,
+ 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585, 594, 766, 167, 613,
+ 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259, 313, 496, 518, 174,
+ 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697, 424, 732, 428, 349,
+ 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170, 193, 245, 297, 374,
+ 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330, 337, 366, 459, 476,
+ 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473, 683, 697, 292, 311,
+ 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603, 608, 752, 778, 782,
+ 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411, 479, 523, 655, 737,
+ 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583, 791, 136, 340, 769,
+ 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269, 377, 391, 406, 432,
+ 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510, 659, 772, 805, 813,
+ 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156, 153, 288, 346, 578,
+ 256, 435, 383, 729, 680, 767, 694, 295, 128, 210, 0, 0, 227, 0, 379, 0,
+ 0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604, 0, 661, 0, 703, 0,
+ 0, 735, 743, 0, 0, 0, 793, 794, 795, 808, 741, 773, 118, 127, 130, 166,
+ 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329, 335, 369, 375, 381,
+ 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548, 549, 550, 554, 555,
+ 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651, 690, 695, 705, 706,
+ 716, 717, 733, 735, 777, 786, 790, 315, 869, 623, 0, 0, 102, 145, 134, 115,
+ 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243, 250, 254, 294, 296,
+ 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362, 370, 379, 388, 389,
+ 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490, 493, 507, 512, 514,
+ 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586, 591, 597, 607, 637,
+ 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706, 709, 717, 728, 736,
+ 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848, 847, 857, 55, 65,
+ 66, 883, 892, 916, 822, 824, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1586, 0,1605, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1602,1603,1934,1935,1574,1575,1576,1577,1579,1580,
+ 1581,1583,1584, 0,1585,1587,1588,1589,1591, 0,1592, 0,1593,1594, 0,1595,
+ 1596, 0,1598,1599,1600,1601,1604,1582,1578,1590,1597, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1936, 0,1937, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,1938, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1939,1940, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,1941,1942, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,1944,1943, 0,1945, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1946,1947, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,1948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1949,1950,1951,1952,1953,1954,
+ 1955, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,1956,1957,1958,1960,1959,1961, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 104, 107, 826,
+ 114, 118, 119, 121, 123, 124, 127, 125, 34, 830, 130, 131, 132, 137, 827, 35,
+ 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152, 37, 157, 158, 159, 160,
+ 38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179, 181, 182, 182, 182,
+ 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195, 197, 199, 200, 201,
+ 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216, 153, 234, 221, 222,
+ 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244, 836, 837, 247, 248,
+ 249, 246, 251, 39, 40, 253, 255, 255, 838, 257, 258, 259, 261, 839, 262, 263,
+ 301, 264, 41, 266, 270, 272, 271, 841, 274, 842, 277, 276, 278, 281, 282, 42,
+ 283, 284, 285, 286, 43, 843, 44, 289, 290, 291, 293, 934, 298, 845, 845, 621,
+ 300, 300, 45, 852, 894, 302, 304, 46, 306, 309, 310, 312, 316, 48, 47, 317,
+ 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334, 335, 336, 338, 339,
+ 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361, 358, 356, 49, 363,
+ 365, 367, 364, 50, 369, 371, 851, 376, 386, 378, 53, 381, 52, 51, 140, 141,
+ 387, 382, 614, 78, 388, 389, 390, 394, 392, 856, 54, 399, 396, 402, 404, 858,
+ 405, 401, 407, 55, 408, 409, 410, 413, 859, 415, 56, 417, 860, 418, 57, 419,
+ 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433, 437, 441, 438, 439,
+ 442, 443, 864, 436, 449, 450, 58, 454, 453, 865, 447, 460, 866, 867, 461, 466,
+ 465, 464, 59, 467, 470, 469, 472, 828, 475, 868, 478, 870, 483, 485, 486, 871,
+ 488, 489, 872, 873, 495, 497, 60, 498, 61, 61, 504, 505, 507, 508, 511, 62,
+ 513, 874, 515, 875, 518, 844, 520, 876, 877, 878, 63, 64, 528, 880, 879, 881,
+ 882, 530, 531, 531, 533, 66, 534, 67, 68, 884, 536, 538, 541, 69, 885, 549,
+ 886, 887, 556, 559, 70, 561, 562, 563, 888, 889, 889, 567, 71, 890, 570, 571,
+ 72, 891, 577, 73, 581, 579, 582, 893, 587, 74, 590, 592, 596, 75, 895, 896,
+ 76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611, 853, 77, 615, 616,
+ 79, 617, 252, 902, 903, 854, 855, 621, 622, 731, 80, 627, 626, 628, 164, 629,
+ 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651, 638, 643, 644, 645,
+ 905, 907, 906, 81, 653, 654, 656, 911, 657, 908, 82, 83, 909, 910, 84, 664,
+ 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675, 85, 677, 678, 86, 681,
+ 682, 912, 685, 686, 87, 689, 36, 913, 914, 88, 89, 696, 702, 709, 711, 915,
+ 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728, 918, 919, 739, 742,
+ 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762, 90, 764, 922, 91, 775,
+ 279, 780, 923, 925, 92, 93, 785, 926, 94, 927, 787, 787, 789, 928, 792, 95,
+ 796, 797, 798, 800, 96, 929, 802, 804, 806, 97, 98, 807, 930, 99, 931, 932,
+ 933, 814, 100, 816, 817, 818, 819, 820, 821, 935, 0, 0,
};
static const int16_t
_hb_ucd_i16[92] =
@@ -4400,12 +4403,12 @@ _hb_ucd_i16[92] =
static inline uint_fast8_t
_hb_ucd_gc (unsigned u)
{
- return u<1114110u?_hb_ucd_u8[6800+(((_hb_ucd_u8[1312+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
+ return u<1114110u?_hb_ucd_u8[6808+(((_hb_ucd_u8[1312+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
}
static inline uint_fast8_t
_hb_ucd_ccc (unsigned u)
{
- return u<125259u?_hb_ucd_u8[8792+(((_hb_ucd_u8[8236+(((_hb_ucd_u8[7776+(((_hb_ucd_u8[7424+(((_hb_ucd_u8[7178+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
+ return u<125259u?_hb_ucd_u8[8800+(((_hb_ucd_u8[8244+(((_hb_ucd_u8[7784+(((_hb_ucd_u8[7432+(((_hb_ucd_u8[7186+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
}
static inline unsigned
_hb_ucd_b4 (const uint8_t* a, unsigned i)
@@ -4415,24 +4418,24 @@ _hb_ucd_b4 (const uint8_t* a, unsigned i)
static inline int_fast16_t
_hb_ucd_bmg (unsigned u)
{
- return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9684+(((_hb_ucd_u8[9452+(((_hb_ucd_u8[9356+(((_hb_ucd_b4(9292+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0;
+ return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9692+(((_hb_ucd_u8[9460+(((_hb_ucd_u8[9364+(((_hb_ucd_b4(9300+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0;
}
static inline uint_fast8_t
_hb_ucd_sc (unsigned u)
{
- return u<918000u?_hb_ucd_u8[11118+(((_hb_ucd_u16[4024+(((_hb_ucd_u16[2040+(((_hb_ucd_u8[10382+(((_hb_ucd_u8[9932+(u>>2>>2>>3>>4)])<<4)+((u>>2>>2>>3)&15u))])<<3)+((u>>2>>2)&7u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2;
+ return u<918000u?_hb_ucd_u8[11126+(((_hb_ucd_u16[4040+(((_hb_ucd_u16[2048+(((_hb_ucd_u8[10390+(((_hb_ucd_u8[9940+(u>>2>>2>>3>>4)])<<4)+((u>>2>>2>>3)&15u))])<<3)+((u>>2>>2)&7u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2;
}
static inline uint_fast16_t
_hb_ucd_dm (unsigned u)
{
- return u<195102u?_hb_ucd_u16[6728+(((_hb_ucd_u8[13944+(((_hb_ucd_u8[13562+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
+ return u<195102u?_hb_ucd_u16[6748+(((_hb_ucd_u8[13952+(((_hb_ucd_u8[13570+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
}
#else
static const uint8_t
-_hb_ucd_u8[13370] =
+_hb_ucd_u8[13386] =
{
0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 9, 10, 7, 7, 7, 7, 7, 11, 12, 12, 12, 13,
@@ -4440,7 +4443,7 @@ _hb_ucd_u8[13370] =
7, 24, 21, 21, 21, 25, 26, 27, 21, 28, 29, 30, 31, 32, 33, 34,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 35, 21, 36,
- 7, 7, 7, 7, 35, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 7, 7, 7, 7, 37, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
@@ -4462,7 +4465,7 @@ _hb_ucd_u8[13370] =
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 37, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 38, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
@@ -4503,8 +4506,9 @@ _hb_ucd_u8[13370] =
34,192,193,111,111,111,111,111,130,194,195,111, 34,196,111,111,
67, 67,197, 67, 67,111, 67,198, 67, 67, 67, 67, 67, 67, 67, 67,
67, 67, 67, 67, 67, 67, 67,199,111,111,111,111,111,111,111,111,
- 34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,111,111,111,
34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111,111,
+ 34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,
200,111,188,188,111,111,111,111,111,111,111,111,111,111,111,111,
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2,
7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11,
@@ -4967,7 +4971,7 @@ _hb_ucd_u8[13370] =
31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 65, 66, 67, 31, 31,
31, 31, 68, 31, 31, 31, 31, 31, 31, 31, 31, 69, 70, 71, 17, 17,
72, 73, 31, 74, 75, 76, 77, 78, 79, 31, 80, 81, 17, 82, 17, 17,
- 17, 17, 31, 31, 23, 23, 23, 23, 23, 23, 31, 31, 31, 31, 31, 31,
+ 17, 17, 31, 31, 23, 23, 23, 23, 23, 23, 23, 83, 31, 31, 31, 31,
23, 83, 31, 31, 23, 23, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
31, 31, 31, 31, 84, 0, 0, 1, 0, 1, 2, 3, 0, 1, 2, 3,
@@ -5597,12 +5601,12 @@ _hb_ucd_i16[92] =
static inline uint_fast8_t
_hb_ucd_gc (unsigned u)
{
- return u<1114112u?_hb_ucd_u8[5080+(((_hb_ucd_u8[1152+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
+ return u<1114112u?_hb_ucd_u8[5096+(((_hb_ucd_u8[1168+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
}
static inline uint_fast8_t
_hb_ucd_ccc (unsigned u)
{
- return u<125259u?_hb_ucd_u8[7038+(((_hb_ucd_u8[6482+(((_hb_ucd_u8[6022+(((_hb_ucd_u8[5670+(((_hb_ucd_u8[5424+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
+ return u<125259u?_hb_ucd_u8[7054+(((_hb_ucd_u8[6498+(((_hb_ucd_u8[6038+(((_hb_ucd_u8[5686+(((_hb_ucd_u8[5440+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
}
static inline unsigned
_hb_ucd_b4 (const uint8_t* a, unsigned i)
@@ -5612,17 +5616,17 @@ _hb_ucd_b4 (const uint8_t* a, unsigned i)
static inline int_fast16_t
_hb_ucd_bmg (unsigned u)
{
- return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[7930+(((_hb_ucd_u8[7698+(((_hb_ucd_u8[7602+(((_hb_ucd_b4(7538+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0;
+ return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[7946+(((_hb_ucd_u8[7714+(((_hb_ucd_u8[7618+(((_hb_ucd_b4(7554+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0;
}
static inline uint_fast8_t
_hb_ucd_sc (unsigned u)
{
- return u<918016u?_hb_ucd_u8[11228+(((_hb_ucd_u8[10264+(((_hb_ucd_u8[9276+(((_hb_ucd_u8[8596+(((_hb_ucd_u8[8292+(((_hb_ucd_u8[8178+(u>>2>>2>>2>>3>>4)])<<4)+((u>>2>>2>>2>>3)&15u))])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2;
+ return u<918016u?_hb_ucd_u8[11244+(((_hb_ucd_u8[10280+(((_hb_ucd_u8[9292+(((_hb_ucd_u8[8612+(((_hb_ucd_u8[8308+(((_hb_ucd_u8[8194+(u>>2>>2>>2>>3>>4)])<<4)+((u>>2>>2>>2>>3)&15u))])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2;
}
static inline uint_fast16_t
_hb_ucd_dm (unsigned u)
{
- return u<195102u?_hb_ucd_u16[1608+(((_hb_ucd_u8[12570+(((_hb_ucd_u8[12188+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
+ return u<195102u?_hb_ucd_u16[1608+(((_hb_ucd_u8[12586+(((_hb_ucd_u8[12204+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
}
#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-unicode-emoji-table.hh b/src/3rdparty/harfbuzz-ng/src/hb-unicode-emoji-table.hh
index 13b1c4b1d4..e607e8ca82 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-unicode-emoji-table.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-unicode-emoji-table.hh
@@ -7,13 +7,13 @@
* on file with this header:
*
* # emoji-data.txt
- * # Date: 2022-08-02, 00:26:10 GMT
- * # © 2022 Unicode®, Inc.
+ * # Date: 2023-02-01, 02:22:54 GMT
+ * # © 2023 Unicode®, Inc.
* # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
* # For terms of use, see https://www.unicode.org/terms_of_use.html
* #
* # Emoji Data for UTS #51
- * # Used with Emoji Version 15.0 and subsequent minor revisions (if any)
+ * # Used with Emoji Version 15.1 and subsequent minor revisions (if any)
* #
* # For documentation and usage, see https://www.unicode.org/reports/tr51
*/
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-unicode.h b/src/3rdparty/harfbuzz-ng/src/hb-unicode.h
index faa8d67924..5b5c45cae3 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-unicode.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-unicode.h
@@ -164,7 +164,7 @@ typedef enum
* @HB_UNICODE_COMBINING_CLASS_CCC122: [Lao]
* @HB_UNICODE_COMBINING_CLASS_CCC129: [Tibetan]
* @HB_UNICODE_COMBINING_CLASS_CCC130: [Tibetan]
- * @HB_UNICODE_COMBINING_CLASS_CCC133: [Tibetan]
+ * @HB_UNICODE_COMBINING_CLASS_CCC132: [Tibetan] Since: 7.2.0
* @HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT: Marks attached at the bottom left
* @HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW: Marks attached directly below
* @HB_UNICODE_COMBINING_CLASS_ATTACHED_ABOVE: Marks attached directly above
@@ -246,7 +246,7 @@ typedef enum
/* Tibetan */
HB_UNICODE_COMBINING_CLASS_CCC129 = 129,
HB_UNICODE_COMBINING_CLASS_CCC130 = 130,
- HB_UNICODE_COMBINING_CLASS_CCC133 = 132,
+ HB_UNICODE_COMBINING_CLASS_CCC132 = 132,
HB_UNICODE_COMBINING_CLASS_ATTACHED_BELOW_LEFT = 200,
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-uniscribe.cc b/src/3rdparty/harfbuzz-ng/src/hb-uniscribe.cc
index 9648e02663..1b8ac367e1 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-uniscribe.cc
+++ b/src/3rdparty/harfbuzz-ng/src/hb-uniscribe.cc
@@ -699,7 +699,7 @@ retry:
script_tags,
&item_count);
if (unlikely (FAILED (hr)))
- FAIL ("ScriptItemizeOpenType() failed: 0x%08lx", hr);
+ FAIL ("ScriptItemizeOpenType() failed: 0x%08lx", (unsigned long) hr);
#undef MAX_ITEMS
@@ -785,7 +785,7 @@ retry:
}
if (unlikely (FAILED (hr)))
{
- FAIL ("ScriptShapeOpenType() failed: 0x%08lx", hr);
+ FAIL ("ScriptShapeOpenType() failed: 0x%08lx", (unsigned long) hr);
}
for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++)
@@ -811,7 +811,7 @@ retry:
offsets + glyphs_offset,
nullptr);
if (unlikely (FAILED (hr)))
- FAIL ("ScriptPlaceOpenType() failed: 0x%08lx", hr);
+ FAIL ("ScriptPlaceOpenType() failed: 0x%08lx", (unsigned long) hr);
if (DEBUG_ENABLED (UNISCRIBE))
fprintf (stderr, "Item %d RTL %d LayoutRTL %d LogicalOrder %d ScriptTag %c%c%c%c\n",
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-vector.hh b/src/3rdparty/harfbuzz-ng/src/hb-vector.hh
index 58d467a405..c0cc7063ff 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-vector.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-vector.hh
@@ -37,6 +37,8 @@ template <typename Type,
bool sorted=false>
struct hb_vector_t
{
+ static constexpr bool realloc_move = true;
+
typedef Type item_t;
static constexpr unsigned item_size = hb_static_size (Type);
using array_t = typename std::conditional<sorted, hb_sorted_array_t<Type>, hb_array_t<Type>>::type;
@@ -54,7 +56,7 @@ struct hb_vector_t
hb_vector_t (const Iterable &o) : hb_vector_t ()
{
auto iter = hb_iter (o);
- if (iter.is_random_access_iterator)
+ if (iter.is_random_access_iterator || iter.has_fast_len)
alloc (hb_len (iter), true);
hb_copy (iter, *this);
}
@@ -62,9 +64,21 @@ struct hb_vector_t
{
alloc (o.length, true);
if (unlikely (in_error ())) return;
- copy_vector (o);
+ copy_array (o.as_array ());
+ }
+ hb_vector_t (array_t o) : hb_vector_t ()
+ {
+ alloc (o.length, true);
+ if (unlikely (in_error ())) return;
+ copy_array (o);
}
- hb_vector_t (hb_vector_t &&o)
+ hb_vector_t (c_array_t o) : hb_vector_t ()
+ {
+ alloc (o.length, true);
+ if (unlikely (in_error ())) return;
+ copy_array (o);
+ }
+ hb_vector_t (hb_vector_t &&o) noexcept
{
allocated = o.allocated;
length = o.length;
@@ -74,7 +88,7 @@ struct hb_vector_t
~hb_vector_t () { fini (); }
public:
- int allocated = 0; /* == -1 means allocation failed. */
+ int allocated = 0; /* < 0 means allocation failed. */
unsigned int length = 0;
public:
Type *arrayZ = nullptr;
@@ -90,23 +104,25 @@ struct hb_vector_t
void fini ()
{
- shrink_vector (0);
- hb_free (arrayZ);
+ /* We allow a hack to make the vector point to a foreign array
+ * by the user. In that case length/arrayZ are non-zero but
+ * allocated is zero. Don't free anything. */
+ if (allocated)
+ {
+ shrink_vector (0);
+ hb_free (arrayZ);
+ }
init ();
}
void reset ()
{
if (unlikely (in_error ()))
- /* Big Hack! We don't know the true allocated size before
- * an allocation failure happened. But we know it was at
- * least as big as length. Restore it to that and continue
- * as if error did not happen. */
- allocated = length;
+ reset_error ();
resize (0);
}
- friend void swap (hb_vector_t& a, hb_vector_t& b)
+ friend void swap (hb_vector_t& a, hb_vector_t& b) noexcept
{
hb_swap (a.allocated, b.allocated);
hb_swap (a.length, b.length);
@@ -119,11 +135,11 @@ struct hb_vector_t
alloc (o.length, true);
if (unlikely (in_error ())) return *this;
- copy_vector (o);
+ copy_array (o.as_array ());
return *this;
}
- hb_vector_t& operator = (hb_vector_t &&o)
+ hb_vector_t& operator = (hb_vector_t &&o) noexcept
{
hb_swap (*this, o);
return *this;
@@ -191,47 +207,38 @@ struct hb_vector_t
Type *push ()
{
if (unlikely (!resize (length + 1)))
- return &Crap (Type);
+ return std::addressof (Crap (Type));
return std::addressof (arrayZ[length - 1]);
}
- template <typename T,
- typename T2 = Type,
- hb_enable_if (!std::is_copy_constructible<T2>::value &&
- std::is_copy_assignable<T>::value)>
- Type *push (T&& v)
+ template <typename... Args> Type *push (Args&&... args)
{
- Type *p = push ();
- if (p == &Crap (Type))
+ if (unlikely ((int) length >= allocated && !alloc (length + 1)))
// If push failed to allocate then don't copy v, since this may cause
// the created copy to leak memory since we won't have stored a
// reference to it.
- return p;
- *p = std::forward<T> (v);
- return p;
- }
- template <typename T,
- typename T2 = Type,
- hb_enable_if (std::is_copy_constructible<T2>::value)>
- Type *push (T&& v)
- {
- if (unlikely (!alloc (length + 1)))
- // If push failed to allocate then don't copy v, since this may cause
- // the created copy to leak memory since we won't have stored a
- // reference to it.
- return &Crap (Type);
+ return std::addressof (Crap (Type));
/* Emplace. */
- length++;
- Type *p = std::addressof (arrayZ[length - 1]);
- return new (p) Type (std::forward<T> (v));
+ Type *p = std::addressof (arrayZ[length++]);
+ return new (p) Type (std::forward<Args> (args)...);
}
bool in_error () const { return allocated < 0; }
+ void set_error ()
+ {
+ assert (allocated >= 0);
+ allocated = -allocated - 1;
+ }
+ void reset_error ()
+ {
+ assert (allocated < 0);
+ allocated = -(allocated + 1);
+ }
template <typename T = Type,
hb_enable_if (hb_is_trivially_copy_assignable(T))>
Type *
- realloc_vector (unsigned new_allocated)
+ realloc_vector (unsigned new_allocated, hb_priority<0>)
{
if (!new_allocated)
{
@@ -243,7 +250,7 @@ struct hb_vector_t
template <typename T = Type,
hb_enable_if (!hb_is_trivially_copy_assignable(T))>
Type *
- realloc_vector (unsigned new_allocated)
+ realloc_vector (unsigned new_allocated, hb_priority<0>)
{
if (!new_allocated)
{
@@ -263,47 +270,65 @@ struct hb_vector_t
}
return new_array;
}
+ /* Specialization for types that can be moved using realloc(). */
+ template <typename T = Type,
+ hb_enable_if (T::realloc_move)>
+ Type *
+ realloc_vector (unsigned new_allocated, hb_priority<1>)
+ {
+ if (!new_allocated)
+ {
+ hb_free (arrayZ);
+ return nullptr;
+ }
+ return (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type));
+ }
template <typename T = Type,
hb_enable_if (hb_is_trivially_constructible(T))>
void
- grow_vector (unsigned size)
+ grow_vector (unsigned size, hb_priority<0>)
{
- memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ));
+ hb_memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ));
length = size;
}
template <typename T = Type,
hb_enable_if (!hb_is_trivially_constructible(T))>
void
- grow_vector (unsigned size)
+ grow_vector (unsigned size, hb_priority<0>)
{
- while (length < size)
- {
- length++;
- new (std::addressof (arrayZ[length - 1])) Type ();
- }
+ for (; length < size; length++)
+ new (std::addressof (arrayZ[length])) Type ();
+ }
+ /* Specialization for hb_vector_t<hb_{vector,array}_t<U>> to speed up. */
+ template <typename T = Type,
+ hb_enable_if (hb_is_same (T, hb_vector_t<typename T::item_t>) ||
+ hb_is_same (T, hb_array_t <typename T::item_t>))>
+ void
+ grow_vector (unsigned size, hb_priority<1>)
+ {
+ hb_memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ));
+ length = size;
}
template <typename T = Type,
hb_enable_if (hb_is_trivially_copyable (T))>
void
- copy_vector (const hb_vector_t &other)
+ copy_array (hb_array_t<const Type> other)
{
length = other.length;
-#ifndef HB_OPTIMIZE_SIZE
- if (sizeof (T) >= sizeof (long long))
+ if (!HB_OPTIMIZE_SIZE_VAL && sizeof (T) >= sizeof (long long))
/* This runs faster because of alignment. */
for (unsigned i = 0; i < length; i++)
arrayZ[i] = other.arrayZ[i];
else
-#endif
hb_memcpy ((void *) arrayZ, (const void *) other.arrayZ, length * item_size);
}
template <typename T = Type,
hb_enable_if (!hb_is_trivially_copyable (T) &&
std::is_copy_constructible<T>::value)>
void
- copy_vector (const hb_vector_t &other)
+ copy_array (hb_array_t<const Type> other)
{
length = 0;
while (length < other.length)
@@ -318,7 +343,7 @@ struct hb_vector_t
std::is_default_constructible<T>::value &&
std::is_copy_assignable<T>::value)>
void
- copy_vector (const hb_vector_t &other)
+ copy_array (hb_array_t<const Type> other)
{
length = 0;
while (length < other.length)
@@ -332,11 +357,15 @@ struct hb_vector_t
void
shrink_vector (unsigned size)
{
- while ((unsigned) length > size)
+ assert (size <= length);
+ if (!std::is_trivially_destructible<Type>::value)
{
- arrayZ[(unsigned) length - 1].~Type ();
- length--;
+ unsigned count = length - size;
+ Type *p = arrayZ + length - 1;
+ while (count--)
+ p--->~Type ();
}
+ length = size;
}
void
@@ -383,18 +412,18 @@ struct hb_vector_t
if (unlikely (overflows))
{
- allocated = -1;
+ set_error ();
return false;
}
- Type *new_array = realloc_vector (new_allocated);
+ Type *new_array = realloc_vector (new_allocated, hb_prioritize);
if (unlikely (new_allocated && !new_array))
{
if (new_allocated <= (unsigned) allocated)
return true; // shrinking failed; it's okay; happens in our fuzzer
- allocated = -1;
+ set_error ();
return false;
}
@@ -413,7 +442,7 @@ struct hb_vector_t
if (size > length)
{
if (initialize)
- grow_vector (size);
+ grow_vector (size, hb_prioritize);
}
else if (size < length)
{
@@ -432,7 +461,7 @@ struct hb_vector_t
Type pop ()
{
if (!length) return Null (Type);
- Type v {std::move (arrayZ[length - 1])};
+ Type v (std::move (arrayZ[length - 1]));
arrayZ[length - 1].~Type ();
length--;
return v;
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-version.h b/src/3rdparty/harfbuzz-ng/src/hb-version.h
index e7efeb395c..68681874ca 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-version.h
+++ b/src/3rdparty/harfbuzz-ng/src/hb-version.h
@@ -41,26 +41,26 @@ HB_BEGIN_DECLS
*
* The major component of the library version available at compile-time.
*/
-#define HB_VERSION_MAJOR 7
+#define HB_VERSION_MAJOR 8
/**
* HB_VERSION_MINOR:
*
* The minor component of the library version available at compile-time.
*/
-#define HB_VERSION_MINOR 0
+#define HB_VERSION_MINOR 4
/**
* HB_VERSION_MICRO:
*
* The micro component of the library version available at compile-time.
*/
-#define HB_VERSION_MICRO 1
+#define HB_VERSION_MICRO 0
/**
* HB_VERSION_STRING:
*
* A string literal containing the library version available at compile-time.
*/
-#define HB_VERSION_STRING "7.0.1"
+#define HB_VERSION_STRING "8.4.0"
/**
* HB_VERSION_ATLEAST:
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-blob.hh b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-blob.hh
new file mode 100644
index 0000000000..310f4023fc
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-blob.hh
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2023 Behdad Esfahbod
+ *
+ * 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.
+ */
+
+#ifndef HB_WASM_API_BLOB_HH
+#define HB_WASM_API_BLOB_HH
+
+#include "hb-wasm-api.hh"
+
+namespace hb {
+namespace wasm {
+
+
+HB_WASM_API (void, blob_free) (HB_WASM_EXEC_ENV
+ ptr_d(blob_t, blob))
+{
+ HB_PTR_PARAM (blob_t, blob);
+ if (unlikely (!blob))
+ return;
+
+ module_free (blob->data);
+
+ blob->data = nullref;
+ blob->length = 0;
+}
+
+
+}}
+
+#endif /* HB_WASM_API_BLOB_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-buffer.hh b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-buffer.hh
new file mode 100644
index 0000000000..64217a041f
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-buffer.hh
@@ -0,0 +1,217 @@
+/*
+ * Copyright © 2023 Behdad Esfahbod
+ *
+ * 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.
+ */
+
+#ifndef HB_WASM_API_BUFFER_HH
+#define HB_WASM_API_BUFFER_HH
+
+#include "hb-wasm-api.hh"
+
+#include "hb-buffer.hh"
+
+namespace hb {
+namespace wasm {
+
+static_assert (sizeof (glyph_info_t) == sizeof (hb_glyph_info_t), "");
+static_assert (sizeof (glyph_position_t) == sizeof (hb_glyph_position_t), "");
+
+HB_WASM_API (bool_t, buffer_contents_realloc) (HB_WASM_EXEC_ENV
+ ptr_d(buffer_contents_t, contents),
+ uint32_t size)
+{
+ HB_PTR_PARAM (buffer_contents_t, contents);
+ if (unlikely (!contents))
+ return false;
+
+ if (size <= contents->length)
+ return true;
+
+ unsigned bytes;
+ if (hb_unsigned_mul_overflows (size, sizeof (glyph_info_t), &bytes))
+ return false;
+
+ glyph_info_t *info = HB_ARRAY_APP2NATIVE (glyph_info_t, contents->info, contents->length);
+ glyph_position_t *pos = HB_ARRAY_APP2NATIVE (glyph_position_t, contents->pos, contents->length);
+
+ if (unlikely (!info || !pos))
+ return false;
+
+ glyph_info_t *new_info = nullptr;
+ uint32_t new_inforef = module_malloc (bytes, (void **) &new_info);
+ glyph_position_t *new_pos = nullptr;
+ uint32_t new_posref = module_malloc (bytes, (void **) &new_pos);
+
+ unsigned old_bytes = contents->length * sizeof (glyph_info_t);
+ if (likely (new_inforef))
+ {
+ hb_memcpy (new_info, info, old_bytes);
+ module_free (contents->info);
+ contents->info = new_inforef;
+ }
+ if (likely (new_posref))
+ {
+ hb_memcpy (new_pos, pos, old_bytes);
+ module_free (contents->pos);
+ contents->pos = new_posref;
+ }
+
+ if (likely (new_info && new_pos))
+ {
+ contents->length = size;
+ return true;
+ }
+
+ return false;
+}
+
+HB_WASM_API (void, buffer_contents_free) (HB_WASM_EXEC_ENV
+ ptr_d(buffer_contents_t, contents))
+{
+ HB_PTR_PARAM (buffer_contents_t, contents);
+ if (unlikely (!contents))
+ return;
+
+ module_free (contents->info);
+ module_free (contents->pos);
+
+ contents->info = nullref;
+ contents->pos = nullref;
+ contents->length = 0;
+}
+
+HB_WASM_API (bool_t, buffer_copy_contents) (HB_WASM_EXEC_ENV
+ ptr_d(buffer_t, buffer),
+ ptr_d(buffer_contents_t, contents))
+{
+ HB_REF2OBJ (buffer);
+ HB_PTR_PARAM (buffer_contents_t, contents);
+ if (unlikely (!contents))
+ return false;
+
+ if (buffer->have_output)
+ buffer->sync ();
+ if (!buffer->have_positions)
+ buffer->clear_positions ();
+
+ unsigned length = buffer->len;
+
+ if (length <= contents->length)
+ {
+ glyph_info_t *info = HB_ARRAY_APP2NATIVE (glyph_info_t, contents->info, length);
+ glyph_position_t *pos = HB_ARRAY_APP2NATIVE (glyph_position_t, contents->pos, length);
+
+ if (unlikely (!info || !pos))
+ {
+ contents->length = 0;
+ return false;
+ }
+
+ unsigned bytes = length * sizeof (hb_glyph_info_t);
+ hb_memcpy (info, buffer->info, bytes);
+ hb_memcpy (pos, buffer->pos, bytes);
+
+ return true;
+ }
+
+ module_free (contents->info);
+ module_free (contents->pos);
+
+ contents->length = length;
+ unsigned bytes = length * sizeof (hb_glyph_info_t);
+ contents->info = wasm_runtime_module_dup_data (module_inst, (const char *) buffer->info, bytes);
+ contents->pos = wasm_runtime_module_dup_data (module_inst, (const char *) buffer->pos, bytes);
+
+ if (length && (!contents->info || !contents->pos))
+ {
+ contents->length = 0;
+ return false;
+ }
+
+ return true;
+}
+
+HB_WASM_API (bool_t, buffer_set_contents) (HB_WASM_EXEC_ENV
+ ptr_d(buffer_t, buffer),
+ ptr_d(const buffer_contents_t, contents))
+{
+ HB_REF2OBJ (buffer);
+ HB_PTR_PARAM (buffer_contents_t, contents);
+ if (unlikely (!contents))
+ return false;
+
+ unsigned length = contents->length;
+ unsigned bytes;
+ if (unlikely (hb_unsigned_mul_overflows (length, sizeof (buffer->info[0]), &bytes)))
+ return false;
+
+ if (unlikely (!buffer->resize (length)))
+ return false;
+
+ glyph_info_t *info = (glyph_info_t *) (validate_app_addr (contents->info, bytes) ? addr_app_to_native (contents->info) : nullptr);
+ glyph_position_t *pos = (glyph_position_t *) (validate_app_addr (contents->pos, bytes) ? addr_app_to_native (contents->pos) : nullptr);
+
+ if (!buffer->have_positions)
+ buffer->clear_positions (); /* This is wasteful. */
+
+ hb_memcpy (buffer->info, info, bytes);
+ hb_memcpy (buffer->pos, pos, bytes);
+ buffer->len = length;
+
+ return true;
+}
+
+HB_WASM_API (direction_t, buffer_get_direction) (HB_WASM_EXEC_ENV
+ ptr_d(buffer_t, buffer))
+{
+ HB_REF2OBJ (buffer);
+
+ return (direction_t) hb_buffer_get_direction (buffer);
+}
+
+HB_WASM_API (script_t, buffer_get_script) (HB_WASM_EXEC_ENV
+ ptr_d(buffer_t, buffer))
+{
+ HB_REF2OBJ (buffer);
+
+ return hb_script_to_iso15924_tag (hb_buffer_get_script (buffer));
+}
+
+HB_WASM_API (void, buffer_reverse) (HB_WASM_EXEC_ENV
+ ptr_d(buffer_t, buffer))
+{
+ HB_REF2OBJ (buffer);
+
+ hb_buffer_reverse (buffer);
+}
+
+HB_WASM_API (void, buffer_reverse_clusters) (HB_WASM_EXEC_ENV
+ ptr_d(buffer_t, buffer))
+{
+ HB_REF2OBJ (buffer);
+
+ hb_buffer_reverse_clusters (buffer);
+}
+
+}}
+
+#endif /* HB_WASM_API_BUFFER_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.hh b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-common.hh
index f10556ddd7..c38ca9cedd 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff2.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-common.hh
@@ -1,5 +1,5 @@
/*
- * Copyright © 2018 Adobe Inc.
+ * Copyright © 2023 Behdad Esfahbod
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -20,18 +20,25 @@
* 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.
- *
- * Adobe Author(s): Michiharu Ariza
*/
-#ifndef HB_SUBSET_CFF2_HH
-#define HB_SUBSET_CFF2_HH
+#ifndef HB_WASM_API_COMMON_HH
+#define HB_WASM_API_COMMON_HH
+
+#include "hb-wasm-api.hh"
+
+namespace hb {
+namespace wasm {
+
-#include "hb.hh"
+HB_WASM_API (direction_t, script_get_horizontal_direction) (HB_WASM_EXEC_ENV
+ script_t script)
+{
+ return (direction_t)
+ hb_script_get_horizontal_direction (hb_script_from_iso15924_tag (script));
+}
-#include "hb-subset-plan.hh"
-HB_INTERNAL bool
-hb_subset_cff2 (hb_subset_context_t *c);
+}}
-#endif /* HB_SUBSET_CFF2_HH */
+#endif /* HB_WASM_API_COMMON_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-face.hh b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-face.hh
new file mode 100644
index 0000000000..22e50e9446
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-face.hh
@@ -0,0 +1,109 @@
+/*
+ * Copyright © 2023 Behdad Esfahbod
+ *
+ * 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.
+ */
+
+#ifndef HB_WASM_API_FACE_HH
+#define HB_WASM_API_FACE_HH
+
+#include "hb-wasm-api.hh"
+
+namespace hb {
+namespace wasm {
+
+
+HB_WASM_API (ptr_t(face_t), face_create) (HB_WASM_EXEC_ENV
+ ptr_d(blob_t, blob),
+ unsigned int index)
+{
+ HB_PTR_PARAM (blob_t, blob);
+ hb_blob_t *hb_blob = hb_blob_create(
+ HB_ARRAY_APP2NATIVE (char, blob->data, blob->length),
+ blob->length,
+ HB_MEMORY_MODE_DUPLICATE,
+ NULL,
+ NULL);
+
+ hb_face_t *face = hb_face_create(hb_blob, index);
+
+ HB_OBJ2REF (face);
+ return faceref;
+}
+
+HB_WASM_API (bool_t, face_copy_table) (HB_WASM_EXEC_ENV
+ ptr_d(face_t, face),
+ tag_t table_tag,
+ ptr_d(blob_t, blob))
+{
+ HB_REF2OBJ (face);
+ HB_PTR_PARAM (blob_t, blob);
+ if (unlikely (!blob))
+ return false;
+
+ hb_blob_t *hb_blob = hb_face_reference_table (face, table_tag);
+
+ unsigned length;
+ const char *hb_data = hb_blob_get_data (hb_blob, &length);
+
+ if (length <= blob->length)
+ {
+ char *data = HB_ARRAY_APP2NATIVE (char, blob->data, length);
+
+ if (unlikely (!data))
+ {
+ blob->length = 0;
+ return false;
+ }
+
+ hb_memcpy (data, hb_data, length);
+
+ return true;
+ }
+
+ module_free (blob->data);
+
+ blob->length = length;
+ blob->data = wasm_runtime_module_dup_data (module_inst, hb_data, length);
+
+ hb_blob_destroy (hb_blob);
+
+ if (blob->length && !blob->data)
+ {
+ blob->length = 0;
+ return false;
+ }
+
+ return true;
+}
+
+HB_WASM_API (unsigned, face_get_upem) (HB_WASM_EXEC_ENV
+ ptr_d(face_t, face))
+{
+ HB_REF2OBJ (face);
+
+ return hb_face_get_upem (face);
+}
+
+
+}}
+
+#endif /* HB_WASM_API_FACE_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-font.hh b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-font.hh
new file mode 100644
index 0000000000..2d85db4aac
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-font.hh
@@ -0,0 +1,263 @@
+/*
+ * Copyright © 2023 Behdad Esfahbod
+ *
+ * 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.
+ */
+
+#ifndef HB_WASM_API_FONT_HH
+#define HB_WASM_API_FONT_HH
+
+#include "hb-wasm-api.hh"
+
+#include "hb-outline.hh"
+
+namespace hb {
+namespace wasm {
+
+
+HB_WASM_API (ptr_t(font_t), font_create) (HB_WASM_EXEC_ENV
+ ptr_d(face_t, face))
+{
+ HB_REF2OBJ (face);
+
+ hb_font_t *font = hb_font_create (face);
+
+ HB_OBJ2REF (font);
+ return fontref;
+}
+
+HB_WASM_API (ptr_t(face_t), font_get_face) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font))
+{
+ HB_REF2OBJ (font);
+
+ hb_face_t *face = hb_font_get_face (font);
+
+ HB_OBJ2REF (face);
+ return faceref;
+}
+
+HB_WASM_API (void, font_get_scale) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font),
+ ptr_d(int32_t, x_scale),
+ ptr_d(int32_t, y_scale))
+{
+ HB_REF2OBJ (font);
+
+ HB_PTR_PARAM(int32_t, x_scale);
+ HB_PTR_PARAM(int32_t, y_scale);
+
+ hb_font_get_scale (font, x_scale, y_scale);
+}
+
+HB_WASM_API (codepoint_t, font_get_glyph) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font),
+ codepoint_t unicode,
+ codepoint_t variation_selector)
+{
+ HB_REF2OBJ (font);
+ codepoint_t glyph;
+
+ hb_font_get_glyph (font, unicode, variation_selector, &glyph);
+ return glyph;
+}
+
+HB_WASM_API (position_t, font_get_glyph_h_advance) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font),
+ codepoint_t glyph)
+{
+ HB_REF2OBJ (font);
+ return hb_font_get_glyph_h_advance (font, glyph);
+}
+
+HB_WASM_API (position_t, font_get_glyph_v_advance) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font),
+ codepoint_t glyph)
+{
+ HB_REF2OBJ (font);
+ return hb_font_get_glyph_v_advance (font, glyph);
+}
+
+static_assert (sizeof (glyph_extents_t) == sizeof (hb_glyph_extents_t), "");
+
+HB_WASM_API (bool_t, font_get_glyph_extents) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font),
+ codepoint_t glyph,
+ ptr_d(glyph_extents_t, extents))
+{
+ HB_REF2OBJ (font);
+ HB_PTR_PARAM (glyph_extents_t, extents);
+ if (unlikely (!extents))
+ return false;
+
+ return hb_font_get_glyph_extents (font, glyph,
+ (hb_glyph_extents_t *) extents);
+}
+
+HB_WASM_API (void, font_glyph_to_string) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font),
+ codepoint_t glyph,
+ char *s, uint32_t size)
+{
+ HB_REF2OBJ (font);
+
+ hb_font_glyph_to_string (font, glyph, s, size);
+}
+
+static_assert (sizeof (glyph_outline_point_t) == sizeof (hb_outline_point_t), "");
+static_assert (sizeof (uint32_t) == sizeof (hb_outline_t::contours[0]), "");
+
+HB_WASM_API (bool_t, font_copy_glyph_outline) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font),
+ codepoint_t glyph,
+ ptr_d(glyph_outline_t, outline))
+{
+ HB_REF2OBJ (font);
+ HB_PTR_PARAM (glyph_outline_t, outline);
+ if (unlikely (!outline))
+ return false;
+
+ hb_outline_t hb_outline;
+ auto *funcs = hb_outline_recording_pen_get_funcs ();
+
+ hb_font_draw_glyph (font, glyph, funcs, &hb_outline);
+
+ if (unlikely (hb_outline.points.in_error () ||
+ hb_outline.contours.in_error ()))
+ {
+ outline->n_points = outline->n_contours = 0;
+ return false;
+ }
+
+ // TODO Check two buffers separately
+ if (hb_outline.points.length <= outline->n_points &&
+ hb_outline.contours.length <= outline->n_contours)
+ {
+ glyph_outline_point_t *points = HB_ARRAY_APP2NATIVE (glyph_outline_point_t, outline->points, hb_outline.points.length);
+ uint32_t *contours = HB_ARRAY_APP2NATIVE (uint32_t, outline->contours, hb_outline.contours.length);
+
+ if (unlikely (!points || !contours))
+ {
+ outline->n_points = outline->n_contours = 0;
+ return false;
+ }
+
+ hb_memcpy (points, hb_outline.points.arrayZ, hb_outline.points.get_size ());
+ hb_memcpy (contours, hb_outline.contours.arrayZ, hb_outline.contours.get_size ());
+
+ return true;
+ }
+
+ outline->n_points = hb_outline.points.length;
+ outline->points = wasm_runtime_module_dup_data (module_inst,
+ (const char *) hb_outline.points.arrayZ,
+ hb_outline.points.get_size ());
+ outline->n_contours = hb_outline.contours.length;
+ outline->contours = wasm_runtime_module_dup_data (module_inst,
+ (const char *) hb_outline.contours.arrayZ,
+ hb_outline.contours.get_size ());
+
+ if ((outline->n_points && !outline->points) ||
+ (!outline->n_contours && !outline->contours))
+ {
+ outline->n_points = outline->n_contours = 0;
+ return false;
+ }
+
+ return true;
+}
+
+HB_WASM_API (void, glyph_outline_free) (HB_WASM_EXEC_ENV
+ ptr_d(glyph_outline_t, outline))
+{
+ HB_PTR_PARAM (glyph_outline_t, outline);
+ if (unlikely (!outline))
+ return;
+
+ module_free (outline->points);
+ module_free (outline->contours);
+
+ outline->n_points = 0;
+ outline->points = nullref;
+ outline->n_contours = 0;
+ outline->contours = nullref;
+}
+
+HB_WASM_API (bool_t, font_copy_coords) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font),
+ ptr_d(coords_t, coords))
+{
+ HB_REF2OBJ (font);
+ HB_PTR_PARAM (coords_t, coords);
+ if (unlikely (!coords))
+ return false;
+
+ unsigned our_length;
+ const int* our_coords = hb_font_get_var_coords_normalized(font, &our_length);
+
+ if (our_length <= coords->length) {
+ int *their_coords = HB_ARRAY_APP2NATIVE (int, coords->coords, our_length);
+ if (unlikely(!their_coords)) {
+ coords->length = 0;
+ return false;
+ }
+ unsigned bytes = our_length * sizeof (int);
+ hb_memcpy (their_coords, our_coords, bytes);
+
+ return true;
+ }
+
+ module_free (coords->coords);
+ coords->length = our_length;
+ unsigned bytes = our_length * sizeof (int);
+ coords->coords = wasm_runtime_module_dup_data (module_inst, (const char *) our_coords, bytes);
+ if (our_length && !coords->coords)
+ {
+ coords->length = 0;
+ return false;
+ }
+
+ return true;
+}
+
+HB_WASM_API (bool_t, font_set_coords) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font),
+ ptr_d(coords_t, coords))
+{
+ HB_REF2OBJ (font);
+ HB_PTR_PARAM (coords_t, coords);
+ if (unlikely (!coords))
+ return false;
+
+ unsigned length = coords->length;
+ unsigned bytes;
+ if (unlikely (hb_unsigned_mul_overflows (length, sizeof (int), &bytes)))
+ return false;
+
+ const int *our_coords = (const int *) (validate_app_addr (coords->coords, bytes) ? addr_app_to_native (coords->coords) : nullptr);
+ hb_font_set_var_coords_normalized(font, our_coords, length);
+ return true;
+}
+
+
+}}
+
+#endif /* HB_WASM_API_FONT_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-shape.hh b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-shape.hh
new file mode 100644
index 0000000000..622ff052b2
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api-shape.hh
@@ -0,0 +1,70 @@
+/*
+ * Copyright © 2023 Behdad Esfahbod
+ *
+ * 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.
+ */
+
+#ifndef HB_WASM_API_SHAPE_HH
+#define HB_WASM_API_SHAPE_HH
+
+#include "hb-wasm-api.hh"
+
+namespace hb {
+namespace wasm {
+
+
+static_assert (sizeof (feature_t) == sizeof (hb_feature_t), "");
+
+HB_WASM_INTERFACE (bool_t, shape_with) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font),
+ ptr_d(buffer_t, buffer),
+ ptr_d(const feature_t, features),
+ uint32_t num_features,
+ const char *shaper)
+{
+ if (unlikely (0 == strcmp (shaper, "wasm")))
+ return false;
+
+ HB_REF2OBJ (font);
+ HB_REF2OBJ (buffer);
+
+ /* Pre-conditions that make hb_shape_full() crash should be checked here. */
+
+ if (unlikely (!buffer->ensure_unicode ()))
+ return false;
+
+ if (unlikely (!HB_DIRECTION_IS_VALID (buffer->props.direction)))
+ return false;
+
+ HB_ARRAY_PARAM (const feature_t, features, num_features);
+ if (unlikely (!features && num_features))
+ return false;
+
+ const char * shaper_list[] = {shaper, nullptr};
+ return hb_shape_full (font, buffer,
+ (hb_feature_t *) features, num_features,
+ shaper_list);
+}
+
+
+}}
+
+#endif /* HB_WASM_API_SHAPE_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.hh b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api.cc
index aaf5def1ed..1da8347a08 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-subset-cff1.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api.cc
@@ -1,5 +1,5 @@
/*
- * Copyright © 2018 Adobe Inc.
+ * Copyright © 2023 Behdad Esfahbod
*
* This is part of HarfBuzz, a text shaping library.
*
@@ -20,18 +20,27 @@
* 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.
- *
- * Adobe Author(s): Michiharu Ariza
*/
-#ifndef HB_SUBSET_CFF1_HH
-#define HB_SUBSET_CFF1_HH
-
#include "hb.hh"
-#include "hb-subset-plan.hh"
+#ifdef HAVE_WASM
+
+#include "hb-wasm-api.hh"
+
+#define module_inst wasm_runtime_get_module_inst (exec_env)
+
+
+#include "hb-wasm-api-blob.hh"
+#include "hb-wasm-api-buffer.hh"
+#include "hb-wasm-api-common.hh"
+#include "hb-wasm-api-face.hh"
+#include "hb-wasm-api-font.hh"
+#include "hb-wasm-api-shape.hh"
+
+
+#undef module_inst
-HB_INTERNAL bool
-hb_subset_cff1 (hb_subset_context_t *c);
+hb_user_data_key_t _hb_wasm_ref_type_key = {};
-#endif /* HB_SUBSET_CFF1_HH */
+#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-wasm-api.h b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api.h
new file mode 100644
index 0000000000..f9bd98e5ea
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api.h
@@ -0,0 +1,319 @@
+/*
+ * Copyright © 2023 Behdad Esfahbod
+ *
+ * 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.
+ */
+
+#ifndef HB_WASM_API_H
+#define HB_WASM_API_H
+
+/*
+#include "hb.h"
+*/
+
+#include <stdint.h>
+
+
+#ifndef HB_WASM_BEGIN_DECLS
+# ifdef __cplusplus
+# define HB_WASM_BEGIN_DECLS extern "C" {
+# define HB_WASM_END_DECLS }
+# else /* !__cplusplus */
+# define HB_WASM_BEGIN_DECLS
+# define HB_WASM_END_DECLS
+# endif /* !__cplusplus */
+#endif
+
+
+HB_WASM_BEGIN_DECLS
+
+#ifndef HB_WASM_API
+#define HB_WASM_API(ret_t, name) ret_t name
+#endif
+#ifndef HB_WASM_API_COMPOUND /* compound return type */
+#define HB_WASM_API_COMPOUND(ret_t, name) HB_WASM_API(ret_t, name)
+#endif
+#ifndef HB_WASM_INTERFACE
+#define HB_WASM_INTERFACE(ret_t, name) ret_t name
+#endif
+#ifndef HB_WASM_EXEC_ENV
+#define HB_WASM_EXEC_ENV
+#endif
+#ifndef HB_WASM_EXEC_ENV_COMPOUND
+#define HB_WASM_EXEC_ENV_COMPOUND HB_WASM_EXEC_ENV
+#endif
+
+
+#ifndef bool_t
+#define bool_t uint32_t
+#endif
+#ifndef ptr_t
+#define ptr_t(type_t) type_t *
+#endif
+#ifndef ptr_d
+#define ptr_d(type_t, name) type_t *name
+#endif
+
+typedef uint32_t codepoint_t;
+typedef int32_t position_t;
+typedef uint32_t mask_t;
+typedef uint32_t tag_t;
+#define TAG(c1,c2,c3,c4) ((tag_t)((((uint32_t)(c1)&0xFF)<<24)|(((uint32_t)(c2)&0xFF)<<16)|(((uint32_t)(c3)&0xFF)<<8)|((uint32_t)(c4)&0xFF)))
+
+typedef enum {
+ DIRECTION_INVALID = 0,
+ DIRECTION_LTR = 4,
+ DIRECTION_RTL,
+ DIRECTION_TTB,
+ DIRECTION_BTT
+} direction_t;
+#define DIRECTION_IS_VALID(dir) ((((unsigned int) (dir)) & ~3U) == 4)
+#define DIRECTION_IS_HORIZONTAL(dir) ((((unsigned int) (dir)) & ~1U) == 4)
+#define DIRECTION_IS_VERTICAL(dir) ((((unsigned int) (dir)) & ~1U) == 6)
+#define DIRECTION_IS_FORWARD(dir) ((((unsigned int) (dir)) & ~2U) == 4)
+#define DIRECTION_IS_BACKWARD(dir) ((((unsigned int) (dir)) & ~2U) == 5)
+#define DIRECTION_REVERSE(dir) ((direction_t) (((unsigned int) (dir)) ^ 1))
+
+typedef tag_t script_t; /* ISO 15924 representation of Unicode scripts. */
+
+
+/* common */
+
+HB_WASM_API (direction_t, script_get_horizontal_direction) (HB_WASM_EXEC_ENV
+ script_t script);
+
+
+/* blob */
+
+typedef struct
+{
+ uint32_t length;
+ ptr_t(char) data;
+} blob_t;
+#define BLOB_INIT {0, 0}
+
+HB_WASM_API (void, blob_free) (HB_WASM_EXEC_ENV
+ ptr_d(blob_t, blob));
+
+/* buffer */
+
+typedef struct
+{
+ uint32_t codepoint;
+ uint32_t mask;
+ uint32_t cluster;
+ uint32_t var1;
+ uint32_t var2;
+} glyph_info_t;
+
+typedef struct
+{
+ position_t x_advance;
+ position_t y_advance;
+ position_t x_offset;
+ position_t y_offset;
+ uint32_t var;
+} glyph_position_t;
+
+typedef struct
+{
+ uint32_t length;
+ ptr_t(glyph_info_t) info;
+ ptr_t(glyph_position_t) pos;
+} buffer_contents_t;
+#define BUFFER_CONTENTS_INIT {0, 0, 0}
+
+HB_WASM_API (bool_t, buffer_contents_realloc) (HB_WASM_EXEC_ENV
+ ptr_d(buffer_contents_t, contents),
+ uint32_t size);
+
+HB_WASM_API (void, buffer_contents_free) (HB_WASM_EXEC_ENV
+ ptr_d(buffer_contents_t, contents));
+
+typedef struct buffer_t buffer_t;
+
+HB_WASM_API (bool_t, buffer_copy_contents) (HB_WASM_EXEC_ENV
+ ptr_d(buffer_t, buffer),
+ ptr_d(buffer_contents_t, contents));
+
+HB_WASM_API (bool_t, buffer_set_contents) (HB_WASM_EXEC_ENV
+ ptr_d(buffer_t, buffer),
+ ptr_d(const buffer_contents_t, contents));
+
+HB_WASM_API (direction_t, buffer_get_direction) (HB_WASM_EXEC_ENV
+ ptr_d(buffer_t, buffer));
+
+HB_WASM_API (script_t, buffer_get_script) (HB_WASM_EXEC_ENV
+ ptr_d(buffer_t, buffer));
+
+HB_WASM_API (void, buffer_reverse) (HB_WASM_EXEC_ENV
+ ptr_d(buffer_t, buffer));
+
+HB_WASM_API (void, buffer_reverse_clusters) (HB_WASM_EXEC_ENV
+ ptr_d(buffer_t, buffer));
+
+/* face */
+
+typedef struct face_t face_t;
+
+HB_WASM_API (ptr_t(face_t), face_create) (HB_WASM_EXEC_ENV
+ ptr_d(blob_t, blob),
+ unsigned int);
+
+HB_WASM_API (bool_t, face_copy_table) (HB_WASM_EXEC_ENV
+ ptr_d(face_t, face),
+ tag_t table_tag,
+ ptr_d(blob_t, blob));
+
+HB_WASM_API (unsigned, face_get_upem) (HB_WASM_EXEC_ENV
+ ptr_d(face_t, face));
+
+/* font */
+
+typedef struct font_t font_t;
+
+HB_WASM_API (ptr_t(font_t), font_create) (HB_WASM_EXEC_ENV
+ ptr_d(face_t, face));
+
+HB_WASM_API (ptr_t(face_t), font_get_face) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font));
+
+HB_WASM_API (void, font_get_scale) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font),
+ ptr_d(int32_t, x_scale),
+ ptr_d(int32_t, y_scale));
+
+HB_WASM_API (codepoint_t, font_get_glyph) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font),
+ codepoint_t unicode,
+ codepoint_t variation_selector);
+
+HB_WASM_API (position_t, font_get_glyph_h_advance) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font),
+ codepoint_t glyph);
+
+HB_WASM_API (position_t, font_get_glyph_v_advance) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font),
+ codepoint_t glyph);
+
+typedef struct
+{
+ position_t x_bearing;
+ position_t y_bearing;
+ position_t width;
+ position_t height;
+} glyph_extents_t;
+
+HB_WASM_API (bool_t, font_get_glyph_extents) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font),
+ codepoint_t glyph,
+ ptr_d(glyph_extents_t, extents));
+
+HB_WASM_API (void, font_glyph_to_string) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font),
+ codepoint_t glyph,
+ char *s, uint32_t size);
+
+
+typedef struct
+{
+ unsigned int length;
+ ptr_t(int) coords;
+} coords_t;
+
+HB_WASM_API (bool_t, font_copy_coords) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font),
+ ptr_d(coords_t, coords));
+
+HB_WASM_API (bool_t, font_set_coords) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font),
+ ptr_d(coords_t, coords));
+
+/* outline */
+
+enum glyph_outline_point_type_t
+{
+ MOVE_TO,
+ LINE_TO,
+ QUADRATIC_TO,
+ CUBIC_TO,
+};
+
+typedef struct
+{
+ float x;
+ float y;
+ uint32_t type;
+} glyph_outline_point_t;
+
+typedef struct
+{
+ uint32_t n_points;
+ ptr_t(glyph_outline_point_t) points;
+ uint32_t n_contours;
+ ptr_t(uint32_t) contours;
+} glyph_outline_t;
+#define GLYPH_OUTLINE_INIT {0, 0, 0, 0}
+
+HB_WASM_API (void, glyph_outline_free) (HB_WASM_EXEC_ENV
+ ptr_d(glyph_outline_t, outline));
+
+HB_WASM_API (bool_t, font_copy_glyph_outline) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font),
+ codepoint_t glyph,
+ ptr_d(glyph_outline_t, outline));
+
+
+/* shape */
+
+typedef struct
+{
+ tag_t tag;
+ uint32_t value;
+ uint32_t start;
+ uint32_t end;
+} feature_t;
+#define FEATURE_GLOBAL_START 0
+#define FEATURE_GLOBAL_END ((uint32_t) -1)
+
+HB_WASM_API (bool_t, shape_with) (HB_WASM_EXEC_ENV
+ ptr_d(font_t, font),
+ ptr_d(buffer_t, buffer),
+ ptr_d(const feature_t, features),
+ uint32_t num_features,
+ const char *shaper);
+
+/* Implement these in your shaper. */
+
+HB_WASM_INTERFACE (ptr_t(void), shape_plan_create) (ptr_d(face_t, face));
+
+HB_WASM_INTERFACE (bool_t, shape) (ptr_d(void, shape_plan),
+ ptr_d(font_t, font),
+ ptr_d(buffer_t, buffer),
+ ptr_d(const feature_t, features),
+ uint32_t num_features);
+
+HB_WASM_INTERFACE (void, shape_plan_destroy) (ptr_d(void, shape_plan));
+
+
+HB_WASM_END_DECLS
+
+#endif /* HB_WASM_API_H */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-wasm-api.hh b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api.hh
new file mode 100644
index 0000000000..4ead01c1f7
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-api.hh
@@ -0,0 +1,117 @@
+/*
+ * Copyright © 2023 Behdad Esfahbod
+ *
+ * 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.
+ */
+
+#ifndef HB_WASM_API_HH
+#define HB_WASM_API_HH
+
+#include "hb.hh"
+
+#include <wasm_export.h>
+
+#define HB_WASM_BEGIN_DECLS namespace hb { namespace wasm {
+#define HB_WASM_END_DECLS }}
+
+#define HB_WASM_API(ret_t, name) HB_INTERNAL ret_t name
+#define HB_WASM_API_COMPOUND(ret_t, name) HB_INTERNAL void name
+
+#define HB_WASM_EXEC_ENV wasm_exec_env_t exec_env,
+#define HB_WASM_EXEC_ENV_COMPOUND wasm_exec_env_t exec_env, ptr_t() retptr,
+
+#define ptr_t(type_t) uint32_t
+#define ptr_d(type_t, name) uint32_t name##ptr
+
+#include "hb-wasm-api.h"
+
+#undef HB_WASM_BEGIN_DECLS
+#undef HB_WASM_END_DECLS
+
+
+enum {
+ hb_wasm_ref_type_none,
+ hb_wasm_ref_type_face,
+ hb_wasm_ref_type_font,
+ hb_wasm_ref_type_buffer,
+};
+
+HB_INTERNAL extern hb_user_data_key_t _hb_wasm_ref_type_key;
+
+#define nullref 0
+
+#define HB_REF2OBJ(obj) \
+ hb_##obj##_t *obj = nullptr; \
+ HB_STMT_START { \
+ (void) wasm_externref_ref2obj (obj##ptr, (void **) &obj); \
+ /* Check object type. */ \
+ /* This works because all our objects have the same hb_object_t layout. */ \
+ if (unlikely (hb_##obj##_get_user_data (obj, &_hb_wasm_ref_type_key) != \
+ (void *) hb_wasm_ref_type_##obj)) \
+ obj = hb_##obj##_get_empty (); \
+ } HB_STMT_END
+
+#define HB_OBJ2REF(obj) \
+ uint32_t obj##ref = nullref; \
+ HB_STMT_START { \
+ hb_##obj##_set_user_data (obj, &_hb_wasm_ref_type_key, \
+ (void *) hb_wasm_ref_type_##obj, \
+ nullptr, false); \
+ (void) wasm_externref_obj2ref (module_inst, obj, &obj##ref); \
+ } HB_STMT_END
+
+#define HB_RETURN_STRUCT(type, name) \
+ type *_name_ptr = nullptr; \
+ { \
+ if (likely (wasm_runtime_validate_app_addr (module_inst, \
+ retptr, sizeof (type)))) \
+ { \
+ _name_ptr = (type *) wasm_runtime_addr_app_to_native (module_inst, retptr); \
+ if (unlikely (!_name_ptr)) \
+ return; \
+ } \
+ } \
+ type &name = *_name_ptr
+
+#define HB_PTR_PARAM(type, name) \
+ type *name = nullptr; \
+ HB_STMT_START { \
+ if (likely (wasm_runtime_validate_app_addr (module_inst, \
+ name##ptr, sizeof (type)))) \
+ name = (type *) wasm_runtime_addr_app_to_native (module_inst, name##ptr); \
+ } HB_STMT_END
+
+#define HB_ARRAY_PARAM(type, name, length) \
+ type *name = nullptr; \
+ HB_STMT_START { \
+ if (likely (!hb_unsigned_mul_overflows (length, sizeof (type)) && \
+ wasm_runtime_validate_app_addr (module_inst, \
+ name##ptr, length * sizeof (type)))) \
+ name = (type *) wasm_runtime_addr_app_to_native (module_inst, name##ptr); \
+ } HB_STMT_END
+
+#define HB_ARRAY_APP2NATIVE(type, name, length) \
+ ((type *) (!hb_unsigned_mul_overflows (length, sizeof (type)) && \
+ validate_app_addr (name, (length) * sizeof (type)) ? \
+ addr_app_to_native (name) : nullptr))
+
+
+#endif /* HB_WASM_API_HH */
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc b/src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc
new file mode 100644
index 0000000000..a8b91879a4
--- /dev/null
+++ b/src/3rdparty/harfbuzz-ng/src/hb-wasm-shape.cc
@@ -0,0 +1,470 @@
+/*
+ * 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
+ */
+
+#undef HB_DEBUG_WASM
+#define HB_DEBUG_WASM 1
+
+#include "hb-shaper-impl.hh"
+
+#ifdef HAVE_WASM
+
+/* Compile wasm-micro-runtime with:
+ *
+ * $ cmake -DWAMR_BUILD_MULTI_MODULE=1 -DWAMR_BUILD_REF_TYPES=1 -DWAMR_BUILD_FAST_JIT=1
+ * $ make
+ *
+ * If you manage to build a wasm shared module successfully and want to use it,
+ * do the following:
+ *
+ * - Add -DWAMR_BUILD_MULTI_MODULE=1 to your cmake build for wasm-micro-runtime,
+ *
+ * - Remove the #define HB_WASM_NO_MODULES line below,
+ *
+ * - Install your shared module with name ending in .wasm in
+ * $(prefix)/$(libdir)/harfbuzz/wasm/
+ *
+ * - Build your font's wasm code importing the shared modules with the desired
+ * name. This can be done eg.: __attribute__((import_module("graphite2")))
+ * before each symbol in the shared-module's headers.
+ *
+ * - Try shaping your font and hope for the best...
+ *
+ * I haven't been able to get this to work since emcc's support for shared libraries
+ * requires support from the host that seems to be missing from wasm-micro-runtime?
+ */
+
+#include "hb-wasm-api.hh"
+#include "hb-wasm-api-list.hh"
+
+#ifndef HB_WASM_NO_MODULES
+#define HB_WASM_NO_MODULES
+#endif
+
+
+#ifndef HB_WASM_NO_MODULES
+static bool HB_UNUSED
+_hb_wasm_module_reader (const char *module_name,
+ uint8_t **p_buffer, uint32_t *p_size)
+{
+ char path[sizeof (HB_WASM_MODULE_DIR) + 64] = HB_WASM_MODULE_DIR "/";
+ strncat (path, module_name, sizeof (path) - sizeof (HB_WASM_MODULE_DIR) - 16);
+ strncat (path, ".wasm", 6);
+
+ auto *blob = hb_blob_create_from_file (path);
+
+ unsigned length;
+ auto *data = hb_blob_get_data (blob, &length);
+
+ *p_buffer = (uint8_t *) hb_malloc (length);
+
+ if (length && !p_buffer)
+ return false;
+
+ memcpy (*p_buffer, data, length);
+ *p_size = length;
+
+ hb_blob_destroy (blob);
+
+ return true;
+}
+
+static void HB_UNUSED
+_hb_wasm_module_destroyer (uint8_t *buffer, uint32_t size)
+{
+ hb_free (buffer);
+}
+#endif
+
+/*
+ * shaper face data
+ */
+
+#define HB_WASM_TAG_WASM HB_TAG('W','a','s','m')
+
+struct hb_wasm_shape_plan_t {
+ wasm_module_inst_t module_inst;
+ wasm_exec_env_t exec_env;
+ ptr_d(void, wasm_shape_plan);
+};
+
+struct hb_wasm_face_data_t {
+ hb_blob_t *wasm_blob;
+ wasm_module_t wasm_module;
+ mutable hb_atomic_ptr_t<hb_wasm_shape_plan_t> plan;
+};
+
+static bool
+_hb_wasm_init ()
+{
+ /* XXX
+ *
+ * Umm. Make this threadsafe. How?!
+ * It's clunky that we can't allocate a static mutex.
+ * So we have to first allocate one on the heap atomically...
+ *
+ * Do we also need to lock around module creation?
+ *
+ * Also, wasm-micro-runtime uses a singleton instance. So if
+ * another library or client uses it, all bets are off. :-(
+ * If nothing else, around HB_REF2OBJ().
+ */
+
+ static bool initialized;
+ if (initialized)
+ return true;
+
+ RuntimeInitArgs init_args;
+ hb_memset (&init_args, 0, sizeof (RuntimeInitArgs));
+
+ init_args.mem_alloc_type = Alloc_With_Allocator;
+ init_args.mem_alloc_option.allocator.malloc_func = (void *) hb_malloc;
+ init_args.mem_alloc_option.allocator.realloc_func = (void *) hb_realloc;
+ init_args.mem_alloc_option.allocator.free_func = (void *) hb_free;
+
+ // Native symbols need below registration phase
+ init_args.n_native_symbols = ARRAY_LENGTH (_hb_wasm_native_symbols);
+ init_args.native_module_name = "env";
+ init_args.native_symbols = _hb_wasm_native_symbols;
+
+ if (unlikely (!wasm_runtime_full_init (&init_args)))
+ {
+ DEBUG_MSG (WASM, nullptr, "Init runtime environment failed.");
+ return false;
+ }
+
+#ifndef HB_WASM_NO_MODULES
+ wasm_runtime_set_module_reader (_hb_wasm_module_reader,
+ _hb_wasm_module_destroyer);
+#endif
+
+ initialized = true;
+ return true;
+}
+
+hb_wasm_face_data_t *
+_hb_wasm_shaper_face_data_create (hb_face_t *face)
+{
+ char error[128];
+ hb_wasm_face_data_t *data = nullptr;
+ hb_blob_t *wasm_blob = nullptr;
+ wasm_module_t wasm_module = nullptr;
+
+ wasm_blob = hb_face_reference_table (face, HB_WASM_TAG_WASM);
+ unsigned length = hb_blob_get_length (wasm_blob);
+ if (!length)
+ goto fail;
+
+ if (!_hb_wasm_init ())
+ goto fail;
+
+ wasm_module = wasm_runtime_load ((uint8_t *) hb_blob_get_data_writable (wasm_blob, nullptr),
+ length, error, sizeof (error));
+ if (unlikely (!wasm_module))
+ {
+ DEBUG_MSG (WASM, nullptr, "Load wasm module failed: %s", error);
+ goto fail;
+ }
+
+ data = (hb_wasm_face_data_t *) hb_calloc (1, sizeof (hb_wasm_face_data_t));
+ if (unlikely (!data))
+ goto fail;
+
+ data->wasm_blob = wasm_blob;
+ data->wasm_module = wasm_module;
+
+ return data;
+
+fail:
+ if (wasm_module)
+ wasm_runtime_unload (wasm_module);
+ hb_blob_destroy (wasm_blob);
+ hb_free (data);
+ return nullptr;
+}
+
+static hb_wasm_shape_plan_t *
+acquire_shape_plan (hb_face_t *face,
+ const hb_wasm_face_data_t *face_data)
+{
+ char error[128];
+
+ /* Fetch cached one if available. */
+ hb_wasm_shape_plan_t *plan = face_data->plan.get_acquire ();
+ if (likely (plan && face_data->plan.cmpexch (plan, nullptr)))
+ return plan;
+
+ plan = (hb_wasm_shape_plan_t *) hb_calloc (1, sizeof (hb_wasm_shape_plan_t));
+
+ wasm_module_inst_t module_inst = nullptr;
+ wasm_exec_env_t exec_env = nullptr;
+ wasm_function_inst_t func = nullptr;
+
+ constexpr uint32_t stack_size = 32 * 1024, heap_size = 2 * 1024 * 1024;
+
+ module_inst = plan->module_inst = wasm_runtime_instantiate (face_data->wasm_module,
+ stack_size, heap_size,
+ error, sizeof (error));
+ if (unlikely (!module_inst))
+ {
+ DEBUG_MSG (WASM, face_data, "Create wasm module instance failed: %s", error);
+ goto fail;
+ }
+
+ exec_env = plan->exec_env = wasm_runtime_create_exec_env (module_inst,
+ stack_size);
+ if (unlikely (!exec_env)) {
+ DEBUG_MSG (WASM, face_data, "Create wasm execution environment failed.");
+ goto fail;
+ }
+
+ func = wasm_runtime_lookup_function (module_inst, "shape_plan_create");
+ if (func)
+ {
+ wasm_val_t results[1];
+ wasm_val_t arguments[1];
+
+ HB_OBJ2REF (face);
+ if (unlikely (!faceref))
+ {
+ DEBUG_MSG (WASM, face_data, "Failed to register face object.");
+ goto fail;
+ }
+
+ results[0].kind = WASM_I32;
+ arguments[0].kind = WASM_I32;
+ arguments[0].of.i32 = faceref;
+ bool ret = wasm_runtime_call_wasm_a (exec_env, func,
+ ARRAY_LENGTH (results), results,
+ ARRAY_LENGTH (arguments), arguments);
+
+ if (unlikely (!ret))
+ {
+ DEBUG_MSG (WASM, module_inst, "Calling shape_plan_create() failed: %s",
+ wasm_runtime_get_exception (module_inst));
+ goto fail;
+ }
+ plan->wasm_shape_planptr = results[0].of.i32;
+ }
+
+ return plan;
+
+fail:
+
+ if (exec_env)
+ wasm_runtime_destroy_exec_env (exec_env);
+ if (module_inst)
+ wasm_runtime_deinstantiate (module_inst);
+ hb_free (plan);
+ return nullptr;
+}
+
+static void
+release_shape_plan (const hb_wasm_face_data_t *face_data,
+ hb_wasm_shape_plan_t *plan,
+ bool cache = false)
+{
+ if (cache && face_data->plan.cmpexch (nullptr, plan))
+ return;
+
+ auto *module_inst = plan->module_inst;
+ auto *exec_env = plan->exec_env;
+
+ /* Is there even any point to having a shape_plan_destroy function
+ * and calling it? */
+ if (plan->wasm_shape_planptr)
+ {
+
+ auto *func = wasm_runtime_lookup_function (module_inst, "shape_plan_destroy");
+ if (func)
+ {
+ wasm_val_t arguments[1];
+
+ arguments[0].kind = WASM_I32;
+ arguments[0].of.i32 = plan->wasm_shape_planptr;
+ bool ret = wasm_runtime_call_wasm_a (exec_env, func,
+ 0, nullptr,
+ ARRAY_LENGTH (arguments), arguments);
+
+ if (unlikely (!ret))
+ {
+ DEBUG_MSG (WASM, module_inst, "Calling shape_plan_destroy() failed: %s",
+ wasm_runtime_get_exception (module_inst));
+ }
+ }
+ }
+
+ wasm_runtime_destroy_exec_env (exec_env);
+ wasm_runtime_deinstantiate (module_inst);
+ hb_free (plan);
+}
+
+void
+_hb_wasm_shaper_face_data_destroy (hb_wasm_face_data_t *data)
+{
+ if (data->plan.get_relaxed ())
+ release_shape_plan (data, data->plan);
+ wasm_runtime_unload (data->wasm_module);
+ hb_blob_destroy (data->wasm_blob);
+ hb_free (data);
+}
+
+
+/*
+ * shaper font data
+ */
+
+struct hb_wasm_font_data_t {};
+
+hb_wasm_font_data_t *
+_hb_wasm_shaper_font_data_create (hb_font_t *font HB_UNUSED)
+{
+ return (hb_wasm_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
+}
+
+void
+_hb_wasm_shaper_font_data_destroy (hb_wasm_font_data_t *data HB_UNUSED)
+{
+}
+
+
+/*
+ * shaper
+ */
+
+hb_bool_t
+_hb_wasm_shape (hb_shape_plan_t *shape_plan,
+ hb_font_t *font,
+ hb_buffer_t *buffer,
+ const hb_feature_t *features,
+ unsigned int num_features)
+{
+ if (unlikely (buffer->in_error ()))
+ return false;
+
+ bool ret = true;
+ hb_face_t *face = font->face;
+ const hb_wasm_face_data_t *face_data = face->data.wasm;
+
+ bool retried = false;
+ if (0)
+ {
+retry:
+ DEBUG_MSG (WASM, font, "Retrying...");
+ }
+
+ wasm_function_inst_t func = nullptr;
+
+ hb_wasm_shape_plan_t *plan = acquire_shape_plan (face, face_data);
+ if (unlikely (!plan))
+ {
+ DEBUG_MSG (WASM, face_data, "Acquiring shape-plan failed.");
+ return false;
+ }
+
+ auto *module_inst = plan->module_inst;
+ auto *exec_env = plan->exec_env;
+
+ HB_OBJ2REF (font);
+ HB_OBJ2REF (buffer);
+ if (unlikely (!fontref || !bufferref))
+ {
+ DEBUG_MSG (WASM, module_inst, "Failed to register objects.");
+ goto fail;
+ }
+
+ func = wasm_runtime_lookup_function (module_inst, "shape");
+ if (unlikely (!func))
+ {
+ DEBUG_MSG (WASM, module_inst, "Shape function not found.");
+ goto fail;
+ }
+
+ wasm_val_t results[1];
+ wasm_val_t arguments[5];
+
+ results[0].kind = WASM_I32;
+ arguments[0].kind = WASM_I32;
+ arguments[0].of.i32 = plan->wasm_shape_planptr;
+ arguments[1].kind = WASM_I32;
+ arguments[1].of.i32 = fontref;
+ arguments[2].kind = WASM_I32;
+ arguments[2].of.i32 = bufferref;
+ arguments[3].kind = WASM_I32;
+ arguments[3].of.i32 = num_features ? wasm_runtime_module_dup_data (module_inst,
+ (const char *) features,
+ num_features * sizeof (features[0])) : 0;
+ arguments[4].kind = WASM_I32;
+ arguments[4].of.i32 = num_features;
+
+ ret = wasm_runtime_call_wasm_a (exec_env, func,
+ ARRAY_LENGTH (results), results,
+ ARRAY_LENGTH (arguments), arguments);
+
+ if (num_features)
+ wasm_runtime_module_free (module_inst, arguments[2].of.i32);
+
+ if (unlikely (!ret || !results[0].of.i32))
+ {
+ DEBUG_MSG (WASM, module_inst, "Calling shape() failed: %s",
+ wasm_runtime_get_exception (module_inst));
+ if (!buffer->ensure_unicode ())
+ {
+ DEBUG_MSG (WASM, font, "Shape failed but buffer is not in Unicode; failing...");
+ goto fail;
+ }
+ if (retried)
+ {
+ DEBUG_MSG (WASM, font, "Giving up...");
+ goto fail;
+ }
+ buffer->successful = true;
+ retried = true;
+ release_shape_plan (face_data, plan);
+ plan = nullptr;
+ goto retry;
+ }
+
+ /* TODO Regularize clusters according to direction & cluster level,
+ * such that client doesn't crash with unmet expectations. */
+
+ if (!results[0].of.i32)
+ {
+fail:
+ ret = false;
+ }
+
+ release_shape_plan (face_data, plan, ret);
+
+ if (ret)
+ {
+ buffer->clear_glyph_flags ();
+ buffer->unsafe_to_break ();
+ }
+
+ return ret;
+}
+
+#endif
diff --git a/src/3rdparty/harfbuzz-ng/src/hb.hh b/src/3rdparty/harfbuzz-ng/src/hb.hh
index 857571b42f..0ceeb99f50 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb.hh
@@ -64,6 +64,8 @@
#pragma GCC diagnostic error "-Wbitwise-instead-of-logical"
#pragma GCC diagnostic error "-Wcast-align"
#pragma GCC diagnostic error "-Wcast-function-type"
+#pragma GCC diagnostic error "-Wcast-function-type-strict"
+#pragma GCC diagnostic error "-Wconstant-conversion"
#pragma GCC diagnostic error "-Wcomma"
#pragma GCC diagnostic error "-Wdelete-non-virtual-dtor"
#pragma GCC diagnostic error "-Wembedded-directive"
@@ -176,6 +178,11 @@
#define HB_EXTERN __declspec (dllexport) extern
#endif
+// https://github.com/harfbuzz/harfbuzz/pull/4619
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS 1
+#endif
+
#include "hb.h"
#define HB_H_IN
#include "hb-ot.h"
@@ -211,6 +218,12 @@
#include <winapifamily.h>
#endif
+#ifndef PRId32
+# define PRId32 "d"
+# define PRIu32 "u"
+# define PRIx32 "x"
+#endif
+
#define HB_PASTE1(a,b) a##b
#define HB_PASTE(a,b) HB_PASTE1(a,b)
@@ -246,9 +259,17 @@ extern "C" void hb_free_impl(void *ptr);
* Compiler attributes
*/
-#if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE__)
-#define likely(expr) (__builtin_expect (!!(expr), 1))
-#define unlikely(expr) (__builtin_expect (!!(expr), 0))
+// gcc 10 has __has_builtin but not earlier versions. Sanction any gcc >= 5
+// clang defines it so no need.
+#ifdef __has_builtin
+#define hb_has_builtin __has_builtin
+#else
+#define hb_has_builtin(x) ((defined(__GNUC__) && __GNUC__ >= 5))
+#endif
+
+#if defined(__OPTIMIZE__) && hb_has_builtin(__builtin_expect)
+#define likely(expr) __builtin_expect (bool(expr), 1)
+#define unlikely(expr) __builtin_expect (bool(expr), 0)
#else
#define likely(expr) (expr)
#define unlikely(expr) (expr)
@@ -307,6 +328,14 @@ extern "C" void hb_free_impl(void *ptr);
#define __restrict
#endif
+#ifndef HB_ALWAYS_INLINE
+#if defined(_MSC_VER)
+#define HB_ALWAYS_INLINE __forceinline
+#else
+#define HB_ALWAYS_INLINE __attribute__((always_inline)) inline
+#endif
+#endif
+
/*
* Borrowed from https://bugzilla.mozilla.org/show_bug.cgi?id=1215411
* HB_FALLTHROUGH is an annotation to suppress compiler warnings about switch
@@ -501,6 +530,12 @@ static_assert ((sizeof (hb_mask_t) == 4), "");
static_assert ((sizeof (hb_var_int_t) == 4), "");
+/* Pie time. */
+// https://github.com/harfbuzz/harfbuzz/issues/4166
+#define HB_PI 3.14159265358979f
+#define HB_2_PI (2.f * HB_PI)
+
+
/* Headers we include for everyone. Keep topologically sorted by dependency.
* They express dependency amongst themselves, but no other file should include
* them directly.*/
diff --git a/src/3rdparty/harfbuzz-ng/src/main.cc b/src/3rdparty/harfbuzz-ng/src/main.cc
deleted file mode 100644
index edc9872eed..0000000000
--- a/src/3rdparty/harfbuzz-ng/src/main.cc
+++ /dev/null
@@ -1,532 +0,0 @@
-/*
- * Copyright © 2007,2008,2009 Red Hat, Inc.
- * Copyright © 2018,2019,2020 Ebrahim Byagowi
- * Copyright © 2018 Khaled Hosny
- *
- * 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.
- *
- * Red Hat Author(s): Behdad Esfahbod
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "hb.h"
-#include "hb-ot.h"
-
-#include <cassert>
-#include <cstdlib>
-#include <cstdio>
-#include <cstring>
-
-#ifdef HB_NO_OPEN
-#define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty ()
-#endif
-
-#if !defined(HB_NO_COLOR) && !defined(HB_NO_DRAW)
-static void
-svg_dump (hb_face_t *face, unsigned face_index)
-{
- unsigned glyph_count = hb_face_get_glyph_count (face);
-
- for (unsigned glyph_id = 0; glyph_id < glyph_count; ++glyph_id)
- {
- hb_blob_t *blob = hb_ot_color_glyph_reference_svg (face, glyph_id);
-
- if (hb_blob_get_length (blob) == 0) continue;
-
- unsigned length;
- const char *data = hb_blob_get_data (blob, &length);
-
- char output_path[255];
- snprintf (output_path, sizeof output_path,
- "out/svg-%u-%u.svg%s",
- glyph_id,
- face_index,
- // append "z" if the content is gzipped, https://stackoverflow.com/a/6059405
- (length > 2 && (data[0] == '\x1F') && (data[1] == '\x8B')) ? "z" : "");
-
- FILE *f = fopen (output_path, "wb");
- fwrite (data, 1, length, f);
- fclose (f);
-
- hb_blob_destroy (blob);
- }
-}
-
-/* _png API is so easy to use unlike the below code, don't get confused */
-static void
-png_dump (hb_face_t *face, unsigned face_index)
-{
- unsigned glyph_count = hb_face_get_glyph_count (face);
- hb_font_t *font = hb_font_create (face);
-
- /* scans the font for strikes */
- unsigned sample_glyph_id;
- /* we don't care about different strikes for different glyphs at this point */
- for (sample_glyph_id = 0; sample_glyph_id < glyph_count; ++sample_glyph_id)
- {
- hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, sample_glyph_id);
- unsigned blob_length = hb_blob_get_length (blob);
- hb_blob_destroy (blob);
- if (blob_length != 0)
- break;
- }
-
- unsigned upem = hb_face_get_upem (face);
- unsigned blob_length = 0;
- unsigned strike = 0;
- for (unsigned ppem = 1; ppem < upem; ++ppem)
- {
- hb_font_set_ppem (font, ppem, ppem);
- hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, sample_glyph_id);
- unsigned new_blob_length = hb_blob_get_length (blob);
- hb_blob_destroy (blob);
- if (new_blob_length != blob_length)
- {
- for (unsigned glyph_id = 0; glyph_id < glyph_count; ++glyph_id)
- {
- hb_blob_t *blob = hb_ot_color_glyph_reference_png (font, glyph_id);
-
- if (hb_blob_get_length (blob) == 0) continue;
-
- unsigned length;
- const char *data = hb_blob_get_data (blob, &length);
-
- char output_path[255];
- snprintf (output_path, sizeof output_path, "out/png-%u-%u-%u.png", glyph_id, strike, face_index);
-
- FILE *f = fopen (output_path, "wb");
- fwrite (data, 1, length, f);
- fclose (f);
-
- hb_blob_destroy (blob);
- }
-
- strike++;
- blob_length = new_blob_length;
- }
- }
-
- hb_font_destroy (font);
-}
-
-struct draw_data_t
-{
- FILE *f;
- hb_position_t ascender;
-};
-
-static void
-move_to (hb_draw_funcs_t *, draw_data_t *draw_data,
- hb_draw_state_t *,
- float to_x, float to_y,
- void *)
-{
- fprintf (draw_data->f, "M%g,%g", to_x, draw_data->ascender - to_y);
-}
-
-static void
-line_to (hb_draw_funcs_t *, draw_data_t *draw_data,
- hb_draw_state_t *,
- float to_x, float to_y,
- void *)
-{
- fprintf (draw_data->f, "L%g,%g", to_x, draw_data->ascender - to_y);
-}
-
-static void
-quadratic_to (hb_draw_funcs_t *, draw_data_t *draw_data,
- hb_draw_state_t *,
- float control_x, float control_y,
- float to_x, float to_y,
- void *)
-{
- fprintf (draw_data->f, "Q%g,%g %g,%g", control_x, draw_data->ascender - control_y,
- to_x, draw_data->ascender - to_y);
-}
-
-static void
-cubic_to (hb_draw_funcs_t *, draw_data_t *draw_data,
- hb_draw_state_t *,
- float control1_x, float control1_y,
- float control2_x, float control2_y,
- float to_x, float to_y,
- void *)
-{
- fprintf (draw_data->f, "C%g,%g %g,%g %g,%g", control1_x, draw_data->ascender - control1_y,
- control2_x, draw_data->ascender - control2_y,
- to_x, draw_data->ascender - to_y);
-}
-
-static void
-close_path (hb_draw_funcs_t *, draw_data_t *draw_data,
- hb_draw_state_t *,
- void *)
-{
- fprintf (draw_data->f, "Z");
-}
-
-static void
-layered_glyph_dump (hb_font_t *font, hb_draw_funcs_t *funcs, unsigned face_index)
-{
- hb_face_t *face = hb_font_get_face (font);
- unsigned palette_count = hb_ot_color_palette_get_count (face);
- for (unsigned palette = 0; palette < palette_count; ++palette)
- {
- unsigned num_colors = hb_ot_color_palette_get_colors (face, palette, 0, nullptr, nullptr);
- if (!num_colors) continue;
-
- hb_color_t *colors = (hb_color_t*) calloc (num_colors, sizeof (hb_color_t));
- hb_ot_color_palette_get_colors (face, palette, 0, &num_colors, colors);
- if (!num_colors)
- {
- free (colors);
- continue;
- }
-
- unsigned num_glyphs = hb_face_get_glyph_count (face);
- for (hb_codepoint_t gid = 0; gid < num_glyphs; ++gid)
- {
- unsigned num_layers = hb_ot_color_glyph_get_layers (face, gid, 0, nullptr, nullptr);
- if (!num_layers) continue;
-
- hb_ot_color_layer_t *layers = (hb_ot_color_layer_t*) malloc (num_layers * sizeof (hb_ot_color_layer_t));
-
- hb_ot_color_glyph_get_layers (face, gid, 0, &num_layers, layers);
- if (num_layers)
- {
- hb_font_extents_t font_extents;
- hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
- hb_glyph_extents_t extents = {0};
- if (!hb_font_get_glyph_extents (font, gid, &extents))
- {
- printf ("Skip gid: %u\n", gid);
- continue;
- }
-
- char output_path[255];
- snprintf (output_path, sizeof output_path, "out/colr-%u-%u-%u.svg", gid, palette, face_index);
- FILE *f = fopen (output_path, "wb");
- fprintf (f, "<svg xmlns=\"http://www.w3.org/2000/svg\""
- " viewBox=\"%d %d %d %d\">\n",
- extents.x_bearing, 0,
- extents.x_bearing + extents.width, -extents.height);
- draw_data_t draw_data;
- draw_data.ascender = extents.y_bearing;
- draw_data.f = f;
-
- for (unsigned layer = 0; layer < num_layers; ++layer)
- {
- hb_color_t color = 0x000000FF;
- if (layers[layer].color_index != 0xFFFF)
- color = colors[layers[layer].color_index];
- fprintf (f, "<path fill=\"#%02X%02X%02X\" ",
- hb_color_get_red (color), hb_color_get_green (color), hb_color_get_green (color));
- if (hb_color_get_alpha (color) != 255)
- fprintf (f, "fill-opacity=\"%.3f\"", (double) hb_color_get_alpha (color) / 255.);
- fprintf (f, "d=\"");
- hb_font_get_glyph_shape (font, layers[layer].glyph, funcs, &draw_data);
- fprintf (f, "\"/>\n");
- }
-
- fprintf (f, "</svg>");
- fclose (f);
- }
- free (layers);
- }
-
- free (colors);
- }
-}
-
-static void
-dump_glyphs (hb_font_t *font, hb_draw_funcs_t *funcs, unsigned face_index)
-{
- unsigned num_glyphs = hb_face_get_glyph_count (hb_font_get_face (font));
- for (unsigned gid = 0; gid < num_glyphs; ++gid)
- {
- hb_font_extents_t font_extents;
- hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
- hb_glyph_extents_t extents = {0};
- if (!hb_font_get_glyph_extents (font, gid, &extents))
- {
- printf ("Skip gid: %u\n", gid);
- continue;
- }
-
- char output_path[255];
- snprintf (output_path, sizeof output_path, "out/%u-%u.svg", face_index, gid);
- FILE *f = fopen (output_path, "wb");
- fprintf (f, "<svg xmlns=\"http://www.w3.org/2000/svg\""
- " viewBox=\"%d %d %d %d\"><path d=\"",
- extents.x_bearing, 0,
- extents.x_bearing + extents.width, font_extents.ascender - font_extents.descender);
- draw_data_t draw_data;
- draw_data.ascender = font_extents.ascender;
- draw_data.f = f;
- hb_font_get_glyph_shape (font, gid, funcs, &draw_data);
- fprintf (f, "\"/></svg>");
- fclose (f);
- }
-}
-
-static void
-dump_glyphs (hb_blob_t *blob, const char *font_name)
-{
- FILE *font_name_file = fopen ("out/.dumped_font_name", "r");
- if (font_name_file)
- {
- fprintf (stderr, "Purge or rename ./out folder if you like to run a glyph dump,\n"
- "run it like `rm -rf out && mkdir out && src/main font-file.ttf`\n");
- return;
- }
-
- font_name_file = fopen ("out/.dumped_font_name", "w");
- if (!font_name_file)
- {
- fprintf (stderr, "./out is not accessible as a folder, create it please\n");
- return;
- }
- fwrite (font_name, 1, strlen (font_name), font_name_file);
- fclose (font_name_file);
-
- hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
- hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) move_to, nullptr, nullptr);
- hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) line_to, nullptr, nullptr);
- hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) quadratic_to, nullptr, nullptr);
- hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) cubic_to, nullptr, nullptr);
- hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) close_path, nullptr, nullptr);
-
- unsigned num_faces = hb_face_count (blob);
- for (unsigned face_index = 0; face_index < num_faces; ++face_index)
- {
- hb_face_t *face = hb_face_create (blob, face_index);
- hb_font_t *font = hb_font_create (face);
-
- if (hb_ot_color_has_png (face))
- printf ("Dumping png (CBDT/sbix)...\n");
- png_dump (face, face_index);
-
- if (hb_ot_color_has_svg (face))
- printf ("Dumping svg (SVG )...\n");
- svg_dump (face, face_index);
-
- if (hb_ot_color_has_layers (face) && hb_ot_color_has_palettes (face))
- printf ("Dumping layered color glyphs (COLR/CPAL)...\n");
- layered_glyph_dump (font, funcs, face_index);
-
- dump_glyphs (font, funcs, face_index);
-
- hb_font_destroy (font);
- hb_face_destroy (face);
- }
-
- hb_draw_funcs_destroy (funcs);
-}
-#endif
-
-#ifndef MAIN_CC_NO_PRIVATE_API
-/* Only this part of this mini app uses private API */
-#include "hb-static.cc"
-#include "hb-open-file.hh"
-#include "hb-ot-layout-gdef-table.hh"
-#include "hb-ot-layout-gsubgpos.hh"
-
-using namespace OT;
-
-static void
-print_layout_info_using_private_api (hb_blob_t *blob)
-{
- const char *font_data = hb_blob_get_data (blob, nullptr);
- hb_blob_t *font_blob = hb_sanitize_context_t ().sanitize_blob<OpenTypeFontFile> (blob);
- const OpenTypeFontFile* sanitized = font_blob->as<OpenTypeFontFile> ();
- if (!font_blob->data)
- {
- printf ("Sanitization of the file wasn't successful. Exit");
- exit (1);
- }
- const OpenTypeFontFile& ot = *sanitized;
-
- switch (ot.get_tag ())
- {
- case OpenTypeFontFile::TrueTypeTag:
- printf ("OpenType font with TrueType outlines\n");
- break;
- case OpenTypeFontFile::CFFTag:
- printf ("OpenType font with CFF (Type1) outlines\n");
- break;
- case OpenTypeFontFile::TTCTag:
- printf ("TrueType Collection of OpenType fonts\n");
- break;
- case OpenTypeFontFile::TrueTag:
- printf ("Obsolete Apple TrueType font\n");
- break;
- case OpenTypeFontFile::Typ1Tag:
- printf ("Obsolete Apple Type1 font in SFNT container\n");
- break;
- case OpenTypeFontFile::DFontTag:
- printf ("DFont Mac Resource Fork\n");
- break;
- default:
- printf ("Unknown font format\n");
- break;
- }
-
- unsigned num_faces = hb_face_count (blob);
- printf ("%u font(s) found in file\n", num_faces);
- for (unsigned n_font = 0; n_font < num_faces; ++n_font)
- {
- const OpenTypeFontFace &font = ot.get_face (n_font);
- printf ("Font %u of %u:\n", n_font, num_faces);
-
- unsigned num_tables = font.get_table_count ();
- printf (" %u table(s) found in font\n", num_tables);
- for (unsigned n_table = 0; n_table < num_tables; ++n_table)
- {
- const OpenTypeTable &table = font.get_table (n_table);
- printf (" Table %2u of %2u: %.4s (0x%08x+0x%08x)\n", n_table, num_tables,
- (const char *) table.tag,
- (unsigned) table.offset,
- (unsigned) table.length);
-
- switch (table.tag)
- {
-
- case HB_OT_TAG_GSUB:
- case HB_OT_TAG_GPOS:
- {
-
- const GSUBGPOS &g = *reinterpret_cast<const GSUBGPOS *> (font_data + table.offset);
-
- unsigned num_scripts = g.get_script_count ();
- printf (" %u script(s) found in table\n", num_scripts);
- for (unsigned n_script = 0; n_script < num_scripts; ++n_script)
- {
- const Script &script = g.get_script (n_script);
- printf (" Script %2u of %2u: %.4s\n", n_script, num_scripts,
- (const char *) g.get_script_tag (n_script));
-
- if (!script.has_default_lang_sys ())
- printf (" No default language system\n");
- int num_langsys = script.get_lang_sys_count ();
- printf (" %d language system(s) found in script\n", num_langsys);
- for (int n_langsys = script.has_default_lang_sys () ? -1 : 0; n_langsys < num_langsys; ++n_langsys)
- {
- const LangSys &langsys = n_langsys == -1
- ? script.get_default_lang_sys ()
- : script.get_lang_sys (n_langsys);
- if (n_langsys == -1)
- printf (" Default Language System\n");
- else
- printf (" Language System %2d of %2d: %.4s\n", n_langsys, num_langsys,
- (const char *) script.get_lang_sys_tag (n_langsys));
- if (!langsys.has_required_feature ())
- printf (" No required feature\n");
- else
- printf (" Required feature index: %u\n",
- langsys.get_required_feature_index ());
-
- unsigned num_features = langsys.get_feature_count ();
- printf (" %u feature(s) found in language system\n", num_features);
- for (unsigned n_feature = 0; n_feature < num_features; ++n_feature)
- {
- printf (" Feature index %2u of %2u: %u\n", n_feature, num_features,
- langsys.get_feature_index (n_feature));
- }
- }
- }
-
- unsigned num_features = g.get_feature_count ();
- printf (" %u feature(s) found in table\n", num_features);
- for (unsigned n_feature = 0; n_feature < num_features; ++n_feature)
- {
- const Feature &feature = g.get_feature (n_feature);
- unsigned num_lookups = feature.get_lookup_count ();
- printf (" Feature %2u of %2u: %c%c%c%c\n", n_feature, num_features,
- HB_UNTAG (g.get_feature_tag (n_feature)));
-
- printf (" %u lookup(s) found in feature\n", num_lookups);
- for (unsigned n_lookup = 0; n_lookup < num_lookups; ++n_lookup) {
- printf (" Lookup index %2u of %2u: %u\n", n_lookup, num_lookups,
- feature.get_lookup_index (n_lookup));
- }
- }
-
- unsigned num_lookups = g.get_lookup_count ();
- printf (" %u lookup(s) found in table\n", num_lookups);
- for (unsigned n_lookup = 0; n_lookup < num_lookups; ++n_lookup)
- {
- const Lookup &lookup = g.get_lookup (n_lookup);
- printf (" Lookup %2u of %2u: type %u, props 0x%04X\n", n_lookup, num_lookups,
- lookup.get_type (), lookup.get_props ());
- }
-
- }
- break;
-
- case GDEF::tableTag:
- {
-
- const GDEF &gdef = *reinterpret_cast<const GDEF *> (font_data + table.offset);
-
- printf (" Has %sglyph classes\n",
- gdef.has_glyph_classes () ? "" : "no ");
- printf (" Has %smark attachment types\n",
- gdef.has_mark_attachment_types () ? "" : "no ");
- printf (" Has %sattach list\n",
- gdef.has_attach_list () ? "" : "no ");
- printf (" Has %slig carets\n",
- gdef.has_lig_carets () ? "" : "no ");
- printf (" Has %smark glyph sets\n",
- gdef.has_mark_glyph_sets () ? "" : "no ");
- break;
- }
- }
- }
- }
-}
-/* end of private API use */
-#endif
-
-int
-main (int argc, char **argv)
-{
- if (argc != 2)
- {
- fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
- exit (1);
- }
-
- hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
- assert (blob);
- printf ("Opened font file %s: %u bytes long\n", argv[1], hb_blob_get_length (blob));
-#ifndef MAIN_CC_NO_PRIVATE_API
- print_layout_info_using_private_api (blob);
-#endif
-#if !defined(HB_NO_COLOR) && !defined(HB_NO_DRAW)
- dump_glyphs (blob, argv[1]);
-#endif
- hb_blob_destroy (blob);
-
- return 0;
-}
diff --git a/src/3rdparty/harfbuzz-ng/src/test.cc b/src/3rdparty/harfbuzz-ng/src/test.cc
deleted file mode 100644
index f7e4e7ecde..0000000000
--- a/src/3rdparty/harfbuzz-ng/src/test.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright © 2010,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
- */
-
-#include "hb.hh"
-
-#ifdef HAVE_FREETYPE
-#include "hb-ft.h"
-#endif
-
-#ifdef HB_NO_OPEN
-#define hb_blob_create_from_file_or_fail(x) hb_blob_get_empty ()
-#endif
-
-int
-main (int argc, char **argv)
-{
- if (argc != 2) {
- fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
- exit (1);
- }
-
- hb_blob_t *blob = hb_blob_create_from_file_or_fail (argv[1]);
- assert (blob);
- printf ("Opened font file %s: %u bytes long\n", argv[1], hb_blob_get_length (blob));
-
- /* Create the face */
- hb_face_t *face = hb_face_create (blob, 0 /* first face */);
- hb_blob_destroy (blob);
- blob = nullptr;
- unsigned int upem = hb_face_get_upem (face);
-
- hb_font_t *font = hb_font_create (face);
- hb_font_set_scale (font, upem, upem);
-
-#ifdef HAVE_FREETYPE
- hb_ft_font_set_funcs (font);
-#endif
-
- hb_buffer_t *buffer = hb_buffer_create ();
-
- hb_buffer_add_utf8 (buffer, "\xe0\xa4\x95\xe0\xa5\x8d\xe0\xa4\xb0\xe0\xa5\x8d\xe0\xa4\x95", -1, 0, -1);
- hb_buffer_guess_segment_properties (buffer);
-
- hb_shape (font, buffer, nullptr, 0);
-
- unsigned int count = hb_buffer_get_length (buffer);
- hb_glyph_info_t *infos = hb_buffer_get_glyph_infos (buffer, nullptr);
- hb_glyph_position_t *positions = hb_buffer_get_glyph_positions (buffer, nullptr);
-
- for (unsigned int i = 0; i < count; i++)
- {
- hb_glyph_info_t *info = &infos[i];
- hb_glyph_position_t *pos = &positions[i];
-
- printf ("cluster %u glyph 0x%x at (%d,%d)+(%d,%d)\n",
- info->cluster,
- info->codepoint,
- pos->x_offset,
- pos->y_offset,
- pos->x_advance,
- pos->y_advance);
-
- }
-
- hb_buffer_destroy (buffer);
- hb_font_destroy (font);
- hb_face_destroy (face);
-
- return 0;
-}
-
-
diff --git a/src/3rdparty/iaccessible2/qt_attribution.json b/src/3rdparty/iaccessible2/qt_attribution.json
index eea8314f1a..fcaee85566 100644
--- a/src/3rdparty/iaccessible2/qt_attribution.json
+++ b/src/3rdparty/iaccessible2/qt_attribution.json
@@ -10,9 +10,7 @@
"License": "BSD 3-clause \"New\" or \"Revised\" License",
"LicenseId": "BSD-3-Clause",
"LicenseFile": "LICENSE",
- "Copyright": "Copyright (c) 2000, 2006 Sun Microsystems, Inc.
-Copyright (c) 2006 IBM Corporation
-Copyright (c) 2007, 2010, 2012, 2013 Linux Foundation
-
-IAccessible2 is a trademark of the Linux Foundation. The IAccessible2 mark may be used in accordance with the Linux Foundation Trademark Policy to indicate compliance with the IAccessible2 specification."
+ "Copyright": ["Copyright (c) 2000, 2006 Sun Microsystems, Inc.",
+ "Copyright (c) 2006 IBM Corporation",
+ "Copyright (c) 2007, 2010, 2012, 2013 Linux Foundation\nIAccessible2 is a trademark of the Linux Foundation. The IAccessible2 mark may be used in accordance with the Linux Foundation Trademark Policy to indicate compliance with the IAccessible2 specification."]
}
diff --git a/src/3rdparty/icc/qt_attribution.json b/src/3rdparty/icc/qt_attribution.json
index 18accd3b54..d2e6807671 100644
--- a/src/3rdparty/icc/qt_attribution.json
+++ b/src/3rdparty/icc/qt_attribution.json
@@ -4,9 +4,9 @@
"Name": "sRGB color profile icc file",
"QDocModule": "qtgui",
"QtUsage": "Used in Qt Gui (Embedded into PDF/A-1b files generated by QPrinter/QPdfWriter).",
- "Files": "No upstream: treat as final",
"Files": "sRGB2014.icc",
+ "Comment": "No upstream: treat as final",
"Description": "An ICC color profile for PDF/A-1b compatible PDF files.",
"Homepage": "http://www.color.org/",
"LicenseId": "LicenseRef-ICC-License",
diff --git a/src/3rdparty/libjpeg/CMakeLists.txt b/src/3rdparty/libjpeg/CMakeLists.txt
index d1da6c6849..6ceb5e5a1a 100644
--- a/src/3rdparty/libjpeg/CMakeLists.txt
+++ b/src/3rdparty/libjpeg/CMakeLists.txt
@@ -1,59 +1,124 @@
+set(jpeg16_original_sources
+ src/jcapistd.c
+ src/jccolor.c
+ src/jcdiffct.c
+ src/jclossls.c
+ src/jcmainct.c
+ src/jcprepct.c
+ src/jcsample.c
+ src/jdapistd.c
+ src/jdcolor.c
+ src/jddiffct.c
+ src/jdlossls.c
+ src/jdmainct.c
+ src/jdpostct.c
+ src/jdsample.c
+ src/jutils.c)
+
+set(jpeg12_original_sources
+ ${jpeg16_original_sources}
+ src/jccoefct.c
+ src/jcdctmgr.c
+ src/jdcoefct.c
+ src/jddctmgr.c
+ src/jdmerge.c
+ src/jfdctfst.c
+ src/jfdctint.c
+ src/jidctflt.c
+ src/jidctfst.c
+ src/jidctint.c
+ src/jidctred.c
+ src/jquant1.c
+ src/jquant2.c)
+
+set(jpeg_original_sources
+ ${jpeg12_original_sources}
+ src/jaricom.c
+ src/jcapimin.c
+ src/jcarith.c
+ src/jchuff.c
+ src/jcicc.c
+ src/jcinit.c
+ src/jclhuff.c
+ src/jcmarker.c
+ src/jcmaster.c
+ src/jcomapi.c
+ src/jcparam.c
+ src/jcphuff.c
+ src/jctrans.c
+ src/jdapimin.c
+ src/jdarith.c
+ src/jdatadst.c
+ src/jdatasrc.c
+ src/jdhuff.c
+ src/jdicc.c
+ src/jdinput.c
+ src/jdlhuff.c
+ src/jdmarker.c
+ src/jdmaster.c
+ src/jdphuff.c
+ src/jdtrans.c
+ src/jerror.c
+ src/jfdctflt.c
+ src/jmemmgr.c
+ src/jmemnobs.c
+ src/jpeg_nbits.c)
+
+# Make copies of the source files for the different bit counts, so that all the object file names
+# are unique in the static archive. This avoids duplicate warnings for certain linkers and debug
+# info extractors (like Apple's ld and dsymutil).
+function(qt_internal_copy_jpeg_sources in_sources infix out_var)
+ set(jpeg_sources "")
+ foreach(src_file ${in_sources})
+ get_filename_component(src_file_name "${src_file}" NAME_WLE)
+ get_filename_component(src_file_extension "${src_file}" LAST_EXT)
+ set(dest_path "${CMAKE_CURRENT_BINARY_DIR}/${src_file_name}${infix}${src_file_extension}")
+ configure_file(${src_file} "${dest_path}" COPYONLY)
+ message(DEBUG "Copying jpeg source file ${src_file} to ${dest_path}.")
+ list(APPEND jpeg_sources "${dest_path}")
+ endforeach()
+ set(${out_var} "${jpeg_sources}" PARENT_SCOPE)
+endfunction()
+
+qt_internal_copy_jpeg_sources("${jpeg16_original_sources}" "_16" jpeg16_sources)
+qt_internal_copy_jpeg_sources("${jpeg12_original_sources}" "_12" jpeg12_sources)
+qt_internal_copy_jpeg_sources("${jpeg_original_sources}" "" jpeg_sources)
+
+qt_internal_add_3rdparty_library(BundledLibjpeg16bits
+ STATIC
+ SKIP_AUTOMOC
+ SOURCES
+ ${jpeg16_sources}
+ DEFINES
+ BITS_IN_JSAMPLE=16
+ INCLUDE_DIRECTORIES
+ src
+ PUBLIC_INCLUDE_DIRECTORIES
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
+)
+
+qt_internal_add_3rdparty_library(BundledLibjpeg12bits
+ STATIC
+ SKIP_AUTOMOC
+ SOURCES
+ ${jpeg12_sources}
+ DEFINES
+ BITS_IN_JSAMPLE=12
+ INCLUDE_DIRECTORIES
+ src
+ PUBLIC_INCLUDE_DIRECTORIES
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
+)
+
qt_internal_add_3rdparty_library(BundledLibjpeg
QMAKE_LIB_NAME libjpeg
STATIC
SKIP_AUTOMOC
INSTALL
SOURCES
- src/jaricom.c
- src/jcapimin.c
- src/jcapistd.c
- src/jcarith.c
- src/jccoefct.c
- src/jccolor.c
- src/jcdctmgr.c
- src/jchuff.c
- src/jcinit.c
- src/jcmainct.c
- src/jcmarker.c
- src/jcmaster.c
- src/jcomapi.c
- src/jcparam.c
- src/jcphuff.c
- src/jcprepct.c
- src/jcsample.c
- src/jctrans.c
- src/jdapimin.c
- src/jdapistd.c
- src/jdarith.c
- src/jdatadst.c
- src/jdatasrc.c
- src/jdcoefct.c
- src/jdcolor.c
- src/jddctmgr.c
- src/jdhuff.c
- src/jdinput.c
- src/jdmainct.c
- src/jdmarker.c
- src/jdmaster.c
- src/jdmerge.c
- src/jdphuff.c
- src/jdpostct.c
- src/jdsample.c
- src/jdtrans.c
- src/jerror.c
- src/jfdctflt.c
- src/jfdctfst.c
- src/jfdctint.c
- src/jidctflt.c
- src/jidctfst.c
- src/jidctint.c
- src/jidctred.c
- src/jmemmgr.c
- src/jmemnobs.c
- src/jquant1.c
- src/jquant2.c
- src/jsimd_none.c
- src/jutils.c
+ ${jpeg_sources}
+ $<TARGET_OBJECTS:BundledLibjpeg12bits>
+ $<TARGET_OBJECTS:BundledLibjpeg16bits>
INCLUDE_DIRECTORIES
src
PUBLIC_INCLUDE_DIRECTORIES
@@ -69,7 +134,11 @@ qt_internal_add_3rdparty_header_module(JpegPrivate
)
qt_disable_warnings(BundledLibjpeg)
+qt_disable_warnings(BundledLibjpeg12bits)
+qt_disable_warnings(BundledLibjpeg16bits)
qt_set_symbol_visibility_hidden(BundledLibjpeg)
+qt_set_symbol_visibility_hidden(BundledLibjpeg12bits)
+qt_set_symbol_visibility_hidden(BundledLibjpeg16bits)
qt_internal_extend_target(BundledLibjpeg CONDITION MSVC
DEFINES
diff --git a/src/3rdparty/libjpeg/COPYRIGHT.txt b/src/3rdparty/libjpeg/COPYRIGHT.txt
index d75ce41458..ce9d95bfeb 100644
--- a/src/3rdparty/libjpeg/COPYRIGHT.txt
+++ b/src/3rdparty/libjpeg/COPYRIGHT.txt
@@ -1,4 +1,4 @@
-Copyright (C) 2009-2023 D. R. Commander
+Copyright (C) 2009-2024 D. R. Commander
Copyright (C) 2015, 2020 Google, Inc.
Copyright (C) 2019-2020 Arm Limited
Copyright (C) 2015-2016, 2018 Matthieu Darbois
@@ -9,4 +9,5 @@ Copyright (C) 2013-2014 MIPS Technologies, Inc.
Copyright (C) 2009, 2012 Pierre Ossman for Cendio AB
Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies)
Copyright (C) 1999-2006 MIYASAKA Masaru
+Copyright (C) 1999 Ken Murchison
Copyright (C) 1991-2020 Thomas G. Lane, Guido Vollbeding
diff --git a/src/3rdparty/libjpeg/import_from_libjpeg_tarball.sh b/src/3rdparty/libjpeg/import_from_libjpeg_tarball.sh
index 4184cc2769..fea6c5c9b4 100755
--- a/src/3rdparty/libjpeg/import_from_libjpeg_tarball.sh
+++ b/src/3rdparty/libjpeg/import_from_libjpeg_tarball.sh
@@ -1,43 +1,8 @@
#! /bin/sh
-#############################################################################
-##
-## Copyright (C) 2017 André Klitzing
-## Contact: https://www.qt.io/licensing/
-##
-## This file is the build configuration utility 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$
-##
-#############################################################################
+# Copyright (C) 2017 André Klitzing
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+#
# This is a small script to copy the required files from a LIBJPEG tarball
# into 3rdparty/libjpeg/.
@@ -92,12 +57,17 @@ FILES="
jccolext.c
jccolor.c
jcdctmgr.c
+ jcdiffct.c
jchuff.c
jchuff.h
+ jcicc.c
jcinit.c
+ jclhuff.c
+ jclossls.c
jcmainct.c
jcmarker.c
jcmaster.c
+ jcmaster.h
jcomapi.c
jcparam.c
jcphuff.c
@@ -116,10 +86,15 @@ FILES="
jdcolor.c
jdct.h
jddctmgr.c
+ jddiffct.c
jdhuff.c
jdhuff.h
+ jdicc.c
jdphuff.c
jdinput.c
+ jdlhuff.c
+ jdlossls.c
+ jlossls.h
jdmainct.c
jdmainct.h
jdmarker.c
@@ -143,18 +118,18 @@ FILES="
jidctfst.c
jidctint.c
jinclude.h
- jpegcomp.h
+ jpegapicomp.h
jpegint.h
jpeglib.h
jmemmgr.c
jmemnobs.c
jmemsys.h
jmorecfg.h
- jpeg_nbits_table.h
+ jpeg_nbits.h
jquant1.c
jquant2.c
+ jsamplecomp.h
jsimd.h
- jsimd_none.c
jsimddct.h
jstdhuff.c
jutils.c
diff --git a/src/3rdparty/libjpeg/qt_attribution.json b/src/3rdparty/libjpeg/qt_attribution.json
index c22c16ea9a..0b06d5c01e 100644
--- a/src/3rdparty/libjpeg/qt_attribution.json
+++ b/src/3rdparty/libjpeg/qt_attribution.json
@@ -3,10 +3,13 @@
"Name": "LibJPEG-turbo",
"QDocModule": "qtgui",
"QtUsage": "Used in the qjpeg image plugin. Configure with -system-libjpeg or -no-libjpeg to avoid.",
+ "SecurityCritical": true,
"Description": "The Independent JPEG Group's JPEG software",
"Homepage": "http://libjpeg-turbo.virtualgl.org/",
- "Version": "2.1.5",
+ "Version": "3.0.2",
+ "DownloadLocation": "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/3.0.2/libjpeg-turbo-3.0.2.tar.gz",
+
"License": "Independent JPEG Group License and BSD 3-Clause \"New\" or \"Revised\" License and zlib License",
"LicenseId": "IJG AND BSD-3-Clause AND Zlib",
"LicenseFiles": [ "LICENSE", "ijg-license.txt", "zlib-license.txt"],
diff --git a/src/3rdparty/libjpeg/src/ChangeLog.md b/src/3rdparty/libjpeg/src/ChangeLog.md
index a547522a15..a929b62a8c 100644
--- a/src/3rdparty/libjpeg/src/ChangeLog.md
+++ b/src/3rdparty/libjpeg/src/ChangeLog.md
@@ -1,3 +1,279 @@
+3.0.2
+=====
+
+### Significant changes relative to 3.0.1:
+
+1. Fixed a signed integer overflow in the `tj3CompressFromYUV8()`,
+`tj3DecodeYUV8()`, `tj3DecompressToYUV8()`, and `tj3EncodeYUV8()` functions,
+detected by the Clang and GCC undefined behavior sanitizers, that could be
+triggered by setting the `align` parameter to an unreasonably large value.
+This issue did not pose a security threat, but removing the warning made it
+easier to detect actual security issues, should they arise in the future.
+
+2. Introduced a new parameter (`TJPARAM_MAXMEMORY` in the TurboJPEG C API and
+`TJ.PARAM_MAXMEMORY` in the TurboJPEG Java API) and a corresponding TJBench
+option (`-maxmemory`) for specifying the maximum amount of memory (in
+megabytes) that will be allocated for intermediate buffers, which are used with
+progressive JPEG compression and decompression, optimized baseline entropy
+coding, lossless JPEG compression, and lossless transformation. The new
+parameter and option serve the same purpose as the `max_memory_to_use` field in
+the `jpeg_memory_mgr` struct in the libjpeg API, the `JPEGMEM` environment
+variable, and the cjpeg/djpeg/jpegtran `-maxmemory` option.
+
+3. Introduced a new parameter (`TJPARAM_MAXPIXELS` in the TurboJPEG C API and
+`TJ.PARAM_MAXPIXELS` in the TurboJPEG Java API) and a corresponding TJBench
+option (`-maxpixels`) for specifying the maximum number of pixels that the
+decompression, lossless transformation, and packed-pixel image loading
+functions/methods will process.
+
+4. Fixed an error ("Unsupported color conversion request") that occurred when
+attempting to decompress a 3-component lossless JPEG image without an Adobe
+APP14 marker. The decompressor now assumes that a 3-component lossless JPEG
+image without an Adobe APP14 marker uses the RGB colorspace if its component
+IDs are 1, 2, and 3.
+
+
+3.0.1
+=====
+
+### Significant changes relative to 3.0.0:
+
+1. The x86-64 SIMD functions now use a standard stack frame, prologue, and
+epilogue so that debuggers and profilers can reliably capture backtraces from
+within the functions.
+
+2. Fixed two minor issues in the interblock smoothing algorithm that caused
+mathematical (but not necessarily perceptible) edge block errors when
+decompressing progressive JPEG images exactly two MCU blocks in width or that
+use vertical chrominance subsampling.
+
+3. Fixed a regression introduced by 3.0 beta2[6] that, in rare cases, caused
+the C Huffman encoder (which is not used by default on x86 and Arm CPUs) to
+generate incorrect results if the Neon SIMD extensions were explicitly disabled
+at build time (by setting the `WITH_SIMD` CMake variable to `0`) in an AArch64
+build of libjpeg-turbo.
+
+
+3.0.0
+=====
+
+### Significant changes relative to 3.0 beta2:
+
+1. The TurboJPEG API now supports 4:4:1 (transposed 4:1:1) chrominance
+subsampling, which allows losslessly transposed or rotated 4:1:1 JPEG images to
+be losslessly cropped, partially decompressed, or decompressed to planar YUV
+images.
+
+2. Fixed various segfaults and buffer overruns (CVE-2023-2804) that occurred
+when attempting to decompress various specially-crafted malformed
+12-bit-per-component and 16-bit-per-component lossless JPEG images using color
+quantization or merged chroma upsampling/color conversion. The underlying
+cause of these issues was that the color quantization and merged chroma
+upsampling/color conversion algorithms were not designed with lossless
+decompression in mind. Since libjpeg-turbo explicitly does not support color
+conversion when compressing or decompressing lossless JPEG images, merged
+chroma upsampling/color conversion never should have been enabled for such
+images. Color quantization is a legacy feature that serves little or no
+purpose with lossless JPEG images, so it is also now disabled when
+decompressing such images. (As a result, djpeg can no longer decompress a
+lossless JPEG image into a GIF image.)
+
+3. Fixed an oversight in 1.4 beta1[8] that caused various segfaults and buffer
+overruns when attempting to decompress various specially-crafted malformed
+12-bit-per-component JPEG images using djpeg with both color quantization and
+RGB565 color conversion enabled.
+
+4. Fixed an issue whereby `jpeg_crop_scanline()` sometimes miscalculated the
+downsampled width for components with 4x2 or 2x4 subsampling factors if
+decompression scaling was enabled. This caused the components to be upsampled
+incompletely, which caused the color converter to read from uninitialized
+memory. With 12-bit data precision, this caused a buffer overrun or underrun
+and subsequent segfault if the sample value read from uninitialized memory was
+outside of the valid sample range.
+
+5. Fixed a long-standing issue whereby the `tj3Transform()` function, when used
+with the `TJXOP_TRANSPOSE`, `TJXOP_TRANSVERSE`, `TJXOP_ROT90`, or
+`TJXOP_ROT270` transform operation and without automatic JPEG destination
+buffer (re)allocation or lossless cropping, computed the worst-case transformed
+JPEG image size based on the source image dimensions rather than the
+transformed image dimensions. If a calling program allocated the JPEG
+destination buffer based on the transformed image dimensions, as the API
+documentation instructs, and attempted to transform a specially-crafted 4:2:2,
+4:4:0, 4:1:1, or 4:4:1 JPEG source image containing a large amount of metadata,
+the issue caused `tj3Transform()` to overflow the JPEG destination buffer
+rather than fail gracefully. The issue could be worked around by setting
+`TJXOPT_COPYNONE`. Note that, irrespective of this issue, `tj3Transform()`
+cannot reliably transform JPEG source images that contain a large amount of
+metadata unless automatic JPEG destination buffer (re)allocation is used or
+`TJXOPT_COPYNONE` is set.
+
+6. Fixed a regression introduced by 3.0 beta2[6] that prevented the djpeg
+`-map` option from working when decompressing 12-bit-per-component lossy JPEG
+images.
+
+7. Fixed an issue that caused the C Huffman encoder (which is not used by
+default on x86 and Arm CPUs) to read from uninitialized memory when attempting
+to transform a specially-crafted malformed arithmetic-coded JPEG source image
+into a baseline Huffman-coded JPEG destination image.
+
+
+2.1.91 (3.0 beta2)
+==================
+
+### Significant changes relative to 2.1.5.1:
+
+1. Significantly sped up the computation of optimal Huffman tables. This
+speeds up the compression of tiny images by as much as 2x and provides a
+noticeable speedup for images as large as 256x256 when using optimal Huffman
+tables.
+
+2. All deprecated fields, constructors, and methods in the TurboJPEG Java API
+have been removed.
+
+3. Arithmetic entropy coding is now supported with 12-bit-per-component JPEG
+images.
+
+4. Overhauled the TurboJPEG API to address long-standing limitations and to
+make the API more extensible and intuitive:
+
+ - All C function names are now prefixed with `tj3`, and all version
+suffixes have been removed from the function names. Future API overhauls will
+increment the prefix to `tj4`, etc., thus retaining backward API/ABI
+compatibility without versioning each individual function.
+ - Stateless boolean flags have been replaced with stateful integer API
+parameters, the values of which persist between function calls. New
+functions/methods (`tj3Set()`/`TJCompressor.set()`/`TJDecompressor.set()` and
+`tj3Get()`/`TJCompressor.get()`/`TJDecompressor.get()`) can be used to set and
+query the value of a particular API parameter.
+ - The JPEG quality and subsampling are now implemented using API
+parameters rather than stateless function arguments (C) or dedicated set/get
+methods (Java.)
+ - `tj3DecompressHeader()` now stores all relevant information about the
+JPEG image, including the width, height, subsampling type, entropy coding
+algorithm, etc., in API parameters rather than returning that information
+through pointer arguments.
+ - `TJFLAG_LIMITSCANS`/`TJ.FLAG_LIMITSCANS` has been reimplemented as an
+API parameter (`TJPARAM_SCANLIMIT`/`TJ.PARAM_SCANLIMIT`) that allows the number
+of scans to be specified.
+ - Optimized baseline entropy coding (the computation of optimal Huffman
+tables, as opposed to using the default Huffman tables) can now be specified,
+using a new API parameter (`TJPARAM_OPTIMIZE`/`TJ.PARAM_OPTIMIZE`), a new
+transform option (`TJXOPT_OPTIMIZE`/`TJTransform.OPT_OPTIMIZE`), and a new
+TJBench option (`-optimize`.)
+ - Arithmetic entropy coding can now be specified or queried, using a new
+API parameter (`TJPARAM_ARITHMETIC`/`TJ.PARAM_ARITHMETIC`), a new transform
+option (`TJXOPT_ARITHMETIC`/`TJTransform.OPT_ARITHMETIC`), and a new TJBench
+option (`-arithmetic`.)
+ - The restart marker interval can now be specified, using new API
+parameters (`TJPARAM_RESTARTROWS`/`TJ.PARAM_RESTARTROWS` and
+`TJPARAM_RESTARTBLOCKS`/`TJ.PARAM_RESTARTBLOCKS`) and a new TJBench option
+(`-restart`.)
+ - Pixel density can now be specified or queried, using new API parameters
+(`TJPARAM_XDENSITY`/`TJ.PARAM_XDENSITY`,
+`TJPARAM_YDENSITY`/`TJ.PARAM_YDENSITY`, and
+`TJPARAM_DENSITYUNITS`/`TJ.PARAM_DENSITYUNITS`.)
+ - The accurate DCT/IDCT algorithms are now the default for both
+compression and decompression, since the "fast" algorithms are considered to be
+a legacy feature. (The "fast" algorithms do not pass the ISO compliance tests,
+and those algorithms are not any faster than the accurate algorithms on modern
+x86 CPUs.)
+ - All C initialization functions have been combined into a single function
+(`tj3Init()`) that accepts an integer argument specifying the subsystems to
+initialize.
+ - All C functions now use the `const` keyword for pointer arguments that
+point to unmodified buffers (and for both dimensions of pointer arguments that
+point to sets of unmodified buffers.)
+ - All C functions now use `size_t` rather than `unsigned long` to
+represent buffer sizes, for compatibility with `malloc()` and to avoid
+disparities in the size of `unsigned long` between LP64 (Un*x) and LLP64
+(Windows) operating systems.
+ - All C buffer size functions now return 0 if an error occurs, rather than
+trying to awkwardly return -1 in an unsigned data type (which could easily be
+misinterpreted as a very large value.)
+ - Decompression scaling is now enabled explicitly, using a new
+function/method (`tj3SetScalingFactor()`/`TJDecompressor.setScalingFactor()`),
+rather than implicitly using awkward "desired width"/"desired height"
+arguments.
+ - Partial image decompression has been implemented, using a new
+function/method (`tj3SetCroppingRegion()`/`TJDecompressor.setCroppingRegion()`)
+and a new TJBench option (`-crop`.)
+ - The JPEG colorspace can now be specified explicitly when compressing,
+using a new API parameter (`TJPARAM_COLORSPACE`/`TJ.PARAM_COLORSPACE`.) This
+allows JPEG images with the RGB and CMYK colorspaces to be created.
+ - TJBench no longer generates error/difference images, since identical
+functionality is already available in ImageMagick.
+ - JPEG images with unknown subsampling configurations can now be
+fully decompressed into packed-pixel images or losslessly transformed (with the
+exception of lossless cropping.) They cannot currently be partially
+decompressed or decompressed into planar YUV images.
+ - `tj3Destroy()` now silently accepts a NULL handle.
+ - `tj3Alloc()` and `tj3Free()` now return/accept void pointers, as
+`malloc()` and `free()` do.
+ - The C image I/O functions now accept a TurboJPEG instance handle, which
+is used to transmit/receive API parameter values and to receive error
+information.
+
+5. Added support for 8-bit-per-component, 12-bit-per-component, and
+16-bit-per-component lossless JPEG images. A new libjpeg API function
+(`jpeg_enable_lossless()`), TurboJPEG API parameters
+(`TJPARAM_LOSSLESS`/`TJ.PARAM_LOSSLESS`,
+`TJPARAM_LOSSLESSPSV`/`TJ.PARAM_LOSSLESSPSV`, and
+`TJPARAM_LOSSLESSPT`/`TJ.PARAM_LOSSLESSPT`), and a cjpeg/TJBench option
+(`-lossless`) can be used to create a lossless JPEG image. (Decompression of
+lossless JPEG images is handled automatically.) Refer to
+[libjpeg.txt](libjpeg.txt), [usage.txt](usage.txt), and the TurboJPEG API
+documentation for more details.
+
+6. Added support for 12-bit-per-component (lossy and lossless) and
+16-bit-per-component (lossless) JPEG images to the libjpeg and TurboJPEG APIs:
+
+ - The existing `data_precision` field in `jpeg_compress_struct` and
+`jpeg_decompress_struct` has been repurposed to enable the creation of
+12-bit-per-component and 16-bit-per-component JPEG images or to detect whether
+a 12-bit-per-component or 16-bit-per-component JPEG image is being
+decompressed.
+ - New 12-bit-per-component and 16-bit-per-component versions of
+`jpeg_write_scanlines()` and `jpeg_read_scanlines()`, as well as new
+12-bit-per-component versions of `jpeg_write_raw_data()`,
+`jpeg_skip_scanlines()`, `jpeg_crop_scanline()`, and `jpeg_read_raw_data()`,
+provide interfaces for compressing from/decompressing to 12-bit-per-component
+and 16-bit-per-component packed-pixel and planar YUV image buffers.
+ - New 12-bit-per-component and 16-bit-per-component compression,
+decompression, and image I/O functions/methods have been added to the TurboJPEG
+API, and a new API parameter (`TJPARAM_PRECISION`/`TJ.PARAM_PRECISION`) can be
+used to query the data precision of a JPEG image. (YUV functions are currently
+limited to 8-bit data precision but can be expanded to accommodate 12-bit data
+precision in the future, if such is deemed beneficial.)
+ - A new cjpeg and TJBench command-line argument (`-precision`) can be used
+to create a 12-bit-per-component or 16-bit-per-component JPEG image.
+(Decompression and transformation of 12-bit-per-component and
+16-bit-per-component JPEG images is handled automatically.)
+
+ Refer to [libjpeg.txt](libjpeg.txt), [usage.txt](usage.txt), and the
+TurboJPEG API documentation for more details.
+
+
+2.1.5.1
+=======
+
+### Significant changes relative to 2.1.5:
+
+1. The SIMD dispatchers in libjpeg-turbo 2.1.4 and prior stored the list of
+supported SIMD instruction sets in a global variable, which caused an innocuous
+race condition whereby the variable could have been initialized multiple times
+if `jpeg_start_*compress()` was called simultaneously in multiple threads.
+libjpeg-turbo 2.1.5 included an undocumented attempt to fix this race condition
+by making the SIMD support variable thread-local. However, that caused another
+issue whereby, if `jpeg_start_*compress()` was called in one thread and
+`jpeg_read_*()` or `jpeg_write_*()` was called in a second thread, the SIMD
+support variable was never initialized in the second thread. On x86 systems,
+this led the second thread to incorrectly assume that AVX2 instructions were
+always available, and when it attempted to use those instructions on older x86
+CPUs that do not support them, an illegal instruction error occurred. The SIMD
+dispatchers now ensure that the SIMD support variable is initialized before
+dispatching based on its value.
+
+
2.1.5
=====
@@ -178,9 +454,9 @@ transform a specially-crafted malformed JPEG image.
### Significant changes relative to 2.1 beta1:
-1. Fixed a regression introduced by 2.1 beta1[6(b)] whereby attempting to
-decompress certain progressive JPEG images with one or more component planes of
-width 8 or less caused a buffer overrun.
+1. Fixed a regression (CVE-2021-29390) introduced by 2.1 beta1[6(b)] whereby
+attempting to decompress certain progressive JPEG images with one or more
+component planes of width 8 or less caused a buffer overrun.
2. Fixed a regression introduced by 2.1 beta1[6(b)] whereby attempting to
decompress a specially-crafted malformed progressive JPEG image caused the
@@ -1419,7 +1695,7 @@ features (such as the colorspace extensions), but in general, it performs no
faster than libjpeg v6b.
14. Added ARM 64-bit SIMD acceleration for the YCC-to-RGB color conversion
-and IDCT algorithms (both are used during JPEG decompression.) For unknown
+and IDCT algorithms (both are used during JPEG decompression.) For
reasons (probably related to clang), this code cannot currently be compiled for
iOS.
@@ -1905,7 +2181,7 @@ and unit tests now work on those architectures.
0.0.93
======
-### Significant changes since 0.0.91:
+### Significant changes relative to 0.0.91:
1. 2982659: Fixed x86-64 build on FreeBSD systems
diff --git a/src/3rdparty/libjpeg/src/README.ijg b/src/3rdparty/libjpeg/src/README.ijg
index 9453c19501..8f3768265f 100644
--- a/src/3rdparty/libjpeg/src/README.ijg
+++ b/src/3rdparty/libjpeg/src/README.ijg
@@ -43,7 +43,7 @@ User documentation:
change.log Version-to-version change highlights.
Programmer and internal documentation:
libjpeg.txt How to use the JPEG library in your own programs.
- example.txt Sample code for calling the JPEG library.
+ example.c Sample code for calling the JPEG library.
structure.txt Overview of the JPEG library's internal structure.
coderules.txt Coding style rules --- please read if you contribute code.
@@ -68,17 +68,17 @@ other abrupt features may not compress well with JPEG, and a higher JPEG
quality may have to be used to avoid visible compression artifacts with such
images.
-JPEG is lossy, meaning that the output pixels are not necessarily identical to
-the input pixels. However, on photographic content and other "smooth" images,
-very good compression ratios can be obtained with no visible compression
-artifacts, and extremely high compression ratios are possible if you are
-willing to sacrifice image quality (by reducing the "quality" setting in the
-compressor.)
-
-This software implements JPEG baseline, extended-sequential, and progressive
-compression processes. Provision is made for supporting all variants of these
-processes, although some uncommon parameter settings aren't implemented yet.
-We have made no provision for supporting the hierarchical or lossless
+JPEG is normally lossy, meaning that the output pixels are not necessarily
+identical to the input pixels. However, on photographic content and other
+"smooth" images, very good compression ratios can be obtained with no visible
+compression artifacts, and extremely high compression ratios are possible if
+you are willing to sacrifice image quality (by reducing the "quality" setting
+in the compressor.)
+
+This software implements JPEG baseline, extended-sequential, progressive, and
+lossless compression processes. Provision is made for supporting all variants
+of these processes, although some uncommon parameter settings aren't
+implemented yet. We have made no provision for supporting the hierarchical
processes defined in the standard.
We provide a set of library routines for reading and writing JPEG image files,
@@ -241,7 +241,7 @@ This software implements ITU T.81 | ISO/IEC 10918 with some extensions from
ITU T.871 | ISO/IEC 10918-5 (JPEG File Interchange Format-- see REFERENCES).
Informally, the term "JPEG image" or "JPEG file" most often refers to JFIF or
a subset thereof, but there are other formats containing the name "JPEG" that
-are incompatible with the DCT-based JPEG standard or with JFIF (for instance,
+are incompatible with the original JPEG standard or with JFIF (for instance,
JPEG 2000 and JPEG XR). This software therefore does not support these
formats. Indeed, one of the original reasons for developing this free software
was to help force convergence on a common, interoperable format standard for
diff --git a/src/3rdparty/libjpeg/src/README.md b/src/3rdparty/libjpeg/src/README.md
index 01e391ea7c..923e61d231 100644
--- a/src/3rdparty/libjpeg/src/README.md
+++ b/src/3rdparty/libjpeg/src/README.md
@@ -21,7 +21,26 @@ derivative of libjpeg v6b developed by Miyasaka Masaru. The TigerVNC and
VirtualGL projects made numerous enhancements to the codec in 2009, and in
early 2010, libjpeg-turbo spun off into an independent project, with the goal
of making high-speed JPEG compression/decompression technology available to a
-broader range of users and developers.
+broader range of users and developers. libjpeg-turbo is an ISO/IEC and ITU-T
+reference implementation of the JPEG standard.
+
+More information about libjpeg-turbo can be found at
+<https://libjpeg-turbo.org>.
+
+
+Funding
+=======
+
+libjpeg-turbo is an independent open source project, but we rely on patronage
+and funded development in order to maintain that independence. The easiest way
+to ensure that libjpeg-turbo remains community-focused and free of any one
+organization's agenda is to
+[sponsor our project through GitHub](https://github.com/sponsors/libjpeg-turbo).
+All sponsorship money goes directly toward funding the labor necessary to
+maintain libjpeg-turbo, support the user community, and implement bug fixes and
+strategically important features.
+
+[![Sponsor libjpeg-turbo](https://img.shields.io/github/sponsors/libjpeg-turbo?label=Sponsor&logo=GitHub)](https://github.com/sponsors/libjpeg-turbo)
License
@@ -245,16 +264,6 @@ programs that need them, without breaking ABI compatibility for programs that
don't, and it allows those functions to be provided in the "official"
libjpeg-turbo binaries.
-Those who are concerned about maintaining strict conformance with the libjpeg
-v6b or v7 API can pass an argument of `-DWITH_MEM_SRCDST=0` to `cmake` prior to
-building libjpeg-turbo. This will restore the pre-1.3 behavior, in which
-`jpeg_mem_src()` and `jpeg_mem_dest()` are only included when emulating the
-libjpeg v8 API/ABI.
-
-On Un*x systems, including the in-memory source/destination managers changes
-the dynamic library version from 62.2.0 to 62.3.0 if using libjpeg v6b API/ABI
-emulation and from 7.2.0 to 7.3.0 if using libjpeg v7 API/ABI emulation.
-
Note that, on most Un*x systems, the dynamic linker will not look for a
function in a library until that function is actually used. Thus, if a program
is built against libjpeg-turbo 1.3+ and uses `jpeg_mem_src()` or
@@ -274,30 +283,35 @@ Mathematical Compatibility
==========================
For the most part, libjpeg-turbo should produce identical output to libjpeg
-v6b. The one exception to this is when using the floating point DCT/IDCT, in
-which case the outputs of libjpeg v6b and libjpeg-turbo can differ for the
-following reasons:
-
-- The SSE/SSE2 floating point DCT implementation in libjpeg-turbo is ever so
- slightly more accurate than the implementation in libjpeg v6b, but not by
- any amount perceptible to human vision (generally in the range of 0.01 to
- 0.08 dB gain in PNSR.)
-
-- When not using the SIMD extensions, libjpeg-turbo uses the more accurate
- (and slightly faster) floating point IDCT algorithm introduced in libjpeg
- v8a as opposed to the algorithm used in libjpeg v6b. It should be noted,
- however, that this algorithm basically brings the accuracy of the floating
- point IDCT in line with the accuracy of the accurate integer IDCT. The
- floating point DCT/IDCT algorithms are mainly a legacy feature, and they do
- not produce significantly more accuracy than the accurate integer algorithms
- (to put numbers on this, the typical difference in PNSR between the two
- algorithms is less than 0.10 dB, whereas changing the quality level by 1 in
- the upper range of the quality scale is typically more like a 1.0 dB
- difference.)
-
-- If the floating point algorithms in libjpeg-turbo are not implemented using
- SIMD instructions on a particular platform, then the accuracy of the
- floating point DCT/IDCT can depend on the compiler settings.
+v6b. There are two exceptions:
+
+1. When decompressing a JPEG image that uses 4:4:0 chrominance subsampling, the
+outputs of libjpeg v6b and libjpeg-turbo can differ because libjpeg-turbo
+implements a "fancy" (smooth) 4:4:0 upsampling algorithm and libjpeg did not.
+
+2. When using the floating point DCT/IDCT, the outputs of libjpeg v6b and
+libjpeg-turbo can differ for the following reasons:
+
+ - The SSE/SSE2 floating point DCT implementation in libjpeg-turbo is ever
+ so slightly more accurate than the implementation in libjpeg v6b, but not
+ by any amount perceptible to human vision (generally in the range of 0.01
+ to 0.08 dB gain in PNSR.)
+
+ - When not using the SIMD extensions, libjpeg-turbo uses the more accurate
+ (and slightly faster) floating point IDCT algorithm introduced in libjpeg
+ v8a as opposed to the algorithm used in libjpeg v6b. It should be noted,
+ however, that this algorithm basically brings the accuracy of the
+ floating point IDCT in line with the accuracy of the accurate integer
+ IDCT. The floating point DCT/IDCT algorithms are mainly a legacy
+ feature, and they do not produce significantly more accuracy than the
+ accurate integer algorithms. (To put numbers on this, the typical
+ difference in PNSR between the two algorithms is less than 0.10 dB,
+ whereas changing the quality level by 1 in the upper range of the quality
+ scale is typically more like a 1.0 dB difference.)
+
+ - If the floating point algorithms in libjpeg-turbo are not implemented
+ using SIMD instructions on a particular platform, then the accuracy of
+ the floating point DCT/IDCT can depend on the compiler settings.
While libjpeg-turbo does emulate the libjpeg v8 API/ABI, under the hood it is
still using the same algorithms as libjpeg v6b, so there are several specific
diff --git a/src/3rdparty/libjpeg/src/jcapimin.c b/src/3rdparty/libjpeg/src/jcapimin.c
index 84e7ecc9a7..cbb3d13e1c 100644
--- a/src/3rdparty/libjpeg/src/jcapimin.c
+++ b/src/3rdparty/libjpeg/src/jcapimin.c
@@ -23,6 +23,7 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#include "jcmaster.h"
/*
@@ -90,8 +91,18 @@ jpeg_CreateCompress(j_compress_ptr cinfo, int version, size_t structsize)
cinfo->input_gamma = 1.0; /* in case application forgets */
+ cinfo->data_precision = BITS_IN_JSAMPLE;
+
/* OK, I'm ready */
cinfo->global_state = CSTATE_START;
+
+ /* The master struct is used to store extension parameters, so we allocate it
+ * here.
+ */
+ cinfo->master = (struct jpeg_comp_master *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_PERMANENT,
+ sizeof(my_comp_master));
+ memset(cinfo->master, 0, sizeof(my_comp_master));
}
@@ -183,8 +194,20 @@ jpeg_finish_compress(j_compress_ptr cinfo)
/* We bypass the main controller and invoke coef controller directly;
* all work is being done from the coefficient buffer.
*/
- if (!(*cinfo->coef->compress_data) (cinfo, (JSAMPIMAGE)NULL))
- ERREXIT(cinfo, JERR_CANT_SUSPEND);
+ if (cinfo->data_precision == 16) {
+#ifdef C_LOSSLESS_SUPPORTED
+ if (!(*cinfo->coef->compress_data_16) (cinfo, (J16SAMPIMAGE)NULL))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+#endif
+ } else if (cinfo->data_precision == 12) {
+ if (!(*cinfo->coef->compress_data_12) (cinfo, (J12SAMPIMAGE)NULL))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+ } else {
+ if (!(*cinfo->coef->compress_data) (cinfo, (JSAMPIMAGE)NULL))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+ }
}
(*cinfo->master->finish_pass) (cinfo);
}
diff --git a/src/3rdparty/libjpeg/src/jcapistd.c b/src/3rdparty/libjpeg/src/jcapistd.c
index aa2aad9f66..2053028f2b 100644
--- a/src/3rdparty/libjpeg/src/jcapistd.c
+++ b/src/3rdparty/libjpeg/src/jcapistd.c
@@ -1,8 +1,10 @@
/*
* jcapistd.c
*
+ * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -18,8 +20,11 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#include "jsamplecomp.h"
+#if BITS_IN_JSAMPLE == 8
+
/*
* Compression initialization.
* Before calling this, all parameters and a data destination must be set up.
@@ -51,13 +56,15 @@ jpeg_start_compress(j_compress_ptr cinfo, boolean write_all_tables)
jinit_compress_master(cinfo);
/* Set up for the first pass */
(*cinfo->master->prepare_for_pass) (cinfo);
- /* Ready for application to drive first pass through jpeg_write_scanlines
- * or jpeg_write_raw_data.
+ /* Ready for application to drive first pass through _jpeg_write_scanlines
+ * or _jpeg_write_raw_data.
*/
cinfo->next_scanline = 0;
cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING);
}
+#endif
+
/*
* Write some scanlines of data to the JPEG compressor.
@@ -67,7 +74,7 @@ jpeg_start_compress(j_compress_ptr cinfo, boolean write_all_tables)
* the data destination module has requested suspension of the compressor,
* or if more than image_height scanlines are passed in.
*
- * Note: we warn about excess calls to jpeg_write_scanlines() since
+ * Note: we warn about excess calls to _jpeg_write_scanlines() since
* this likely signals an application programmer error. However,
* excess scanlines passed in the last valid call are *silently* ignored,
* so that the application need not adjust num_lines for end-of-image
@@ -75,11 +82,15 @@ jpeg_start_compress(j_compress_ptr cinfo, boolean write_all_tables)
*/
GLOBAL(JDIMENSION)
-jpeg_write_scanlines(j_compress_ptr cinfo, JSAMPARRAY scanlines,
- JDIMENSION num_lines)
+_jpeg_write_scanlines(j_compress_ptr cinfo, _JSAMPARRAY scanlines,
+ JDIMENSION num_lines)
{
+#if BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED)
JDIMENSION row_ctr, rows_left;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
if (cinfo->global_state != CSTATE_SCANNING)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
if (cinfo->next_scanline >= cinfo->image_height)
@@ -93,9 +104,9 @@ jpeg_write_scanlines(j_compress_ptr cinfo, JSAMPARRAY scanlines,
}
/* Give master control module another chance if this is first call to
- * jpeg_write_scanlines. This lets output of the frame/scan headers be
+ * _jpeg_write_scanlines. This lets output of the frame/scan headers be
* delayed so that application can write COM, etc, markers between
- * jpeg_start_compress and jpeg_write_scanlines.
+ * jpeg_start_compress and _jpeg_write_scanlines.
*/
if (cinfo->master->call_pass_startup)
(*cinfo->master->pass_startup) (cinfo);
@@ -106,23 +117,35 @@ jpeg_write_scanlines(j_compress_ptr cinfo, JSAMPARRAY scanlines,
num_lines = rows_left;
row_ctr = 0;
- (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines);
+ (*cinfo->main->_process_data) (cinfo, scanlines, &row_ctr, num_lines);
cinfo->next_scanline += row_ctr;
return row_ctr;
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ return 0;
+#endif
}
+#if BITS_IN_JSAMPLE != 16
+
/*
* Alternate entry point to write raw data.
* Processes exactly one iMCU row per call, unless suspended.
*/
GLOBAL(JDIMENSION)
-jpeg_write_raw_data(j_compress_ptr cinfo, JSAMPIMAGE data,
- JDIMENSION num_lines)
+_jpeg_write_raw_data(j_compress_ptr cinfo, _JSAMPIMAGE data,
+ JDIMENSION num_lines)
{
JDIMENSION lines_per_iMCU_row;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+ if (cinfo->master->lossless)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+
if (cinfo->global_state != CSTATE_RAW_OK)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
if (cinfo->next_scanline >= cinfo->image_height) {
@@ -138,9 +161,9 @@ jpeg_write_raw_data(j_compress_ptr cinfo, JSAMPIMAGE data,
}
/* Give master control module another chance if this is first call to
- * jpeg_write_raw_data. This lets output of the frame/scan headers be
+ * _jpeg_write_raw_data. This lets output of the frame/scan headers be
* delayed so that application can write COM, etc, markers between
- * jpeg_start_compress and jpeg_write_raw_data.
+ * jpeg_start_compress and _jpeg_write_raw_data.
*/
if (cinfo->master->call_pass_startup)
(*cinfo->master->pass_startup) (cinfo);
@@ -151,7 +174,7 @@ jpeg_write_raw_data(j_compress_ptr cinfo, JSAMPIMAGE data,
ERREXIT(cinfo, JERR_BUFFER_SIZE);
/* Directly compress the row. */
- if (!(*cinfo->coef->compress_data) (cinfo, data)) {
+ if (!(*cinfo->coef->_compress_data) (cinfo, data)) {
/* If compressor did not consume the whole row, suspend processing. */
return 0;
}
@@ -160,3 +183,5 @@ jpeg_write_raw_data(j_compress_ptr cinfo, JSAMPIMAGE data,
cinfo->next_scanline += lines_per_iMCU_row;
return lines_per_iMCU_row;
}
+
+#endif /* BITS_IN_JSAMPLE != 16 */
diff --git a/src/3rdparty/libjpeg/src/jccoefct.c b/src/3rdparty/libjpeg/src/jccoefct.c
index 068232a527..2a5dde2d07 100644
--- a/src/3rdparty/libjpeg/src/jccoefct.c
+++ b/src/3rdparty/libjpeg/src/jccoefct.c
@@ -3,19 +3,20 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1997, Thomas G. Lane.
- * It was modified by The libjpeg-turbo Project to include only code and
- * information relevant to libjpeg-turbo.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains the coefficient buffer controller for compression.
- * This controller is the top level of the JPEG compressor proper.
+ * This controller is the top level of the lossy JPEG compressor proper.
* The coefficient buffer lies between forward-DCT and entropy encoding steps.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#include "jsamplecomp.h"
/* We use a full-image coefficient buffer when doing Huffman optimization,
@@ -58,11 +59,12 @@ typedef my_coef_controller *my_coef_ptr;
/* Forward declarations */
-METHODDEF(boolean) compress_data(j_compress_ptr cinfo, JSAMPIMAGE input_buf);
+METHODDEF(boolean) compress_data(j_compress_ptr cinfo, _JSAMPIMAGE input_buf);
#ifdef FULL_COEF_BUFFER_SUPPORTED
METHODDEF(boolean) compress_first_pass(j_compress_ptr cinfo,
- JSAMPIMAGE input_buf);
-METHODDEF(boolean) compress_output(j_compress_ptr cinfo, JSAMPIMAGE input_buf);
+ _JSAMPIMAGE input_buf);
+METHODDEF(boolean) compress_output(j_compress_ptr cinfo,
+ _JSAMPIMAGE input_buf);
#endif
@@ -106,18 +108,18 @@ start_pass_coef(j_compress_ptr cinfo, J_BUF_MODE pass_mode)
case JBUF_PASS_THRU:
if (coef->whole_image[0] != NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- coef->pub.compress_data = compress_data;
+ coef->pub._compress_data = compress_data;
break;
#ifdef FULL_COEF_BUFFER_SUPPORTED
case JBUF_SAVE_AND_PASS:
if (coef->whole_image[0] == NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- coef->pub.compress_data = compress_first_pass;
+ coef->pub._compress_data = compress_first_pass;
break;
case JBUF_CRANK_DEST:
if (coef->whole_image[0] == NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- coef->pub.compress_data = compress_output;
+ coef->pub._compress_data = compress_output;
break;
#endif
default:
@@ -138,7 +140,7 @@ start_pass_coef(j_compress_ptr cinfo, J_BUF_MODE pass_mode)
*/
METHODDEF(boolean)
-compress_data(j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+compress_data(j_compress_ptr cinfo, _JSAMPIMAGE input_buf)
{
my_coef_ptr coef = (my_coef_ptr)cinfo->coef;
JDIMENSION MCU_col_num; /* index of current MCU within row */
@@ -172,10 +174,10 @@ compress_data(j_compress_ptr cinfo, JSAMPIMAGE input_buf)
for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
if (coef->iMCU_row_num < last_iMCU_row ||
yoffset + yindex < compptr->last_row_height) {
- (*cinfo->fdct->forward_DCT) (cinfo, compptr,
- input_buf[compptr->component_index],
- coef->MCU_buffer[blkn],
- ypos, xpos, (JDIMENSION)blockcnt);
+ (*cinfo->fdct->_forward_DCT) (cinfo, compptr,
+ input_buf[compptr->component_index],
+ coef->MCU_buffer[blkn],
+ ypos, xpos, (JDIMENSION)blockcnt);
if (blockcnt < compptr->MCU_width) {
/* Create some dummy blocks at the right edge of the image. */
jzero_far((void *)coef->MCU_buffer[blkn + blockcnt],
@@ -242,7 +244,7 @@ compress_data(j_compress_ptr cinfo, JSAMPIMAGE input_buf)
*/
METHODDEF(boolean)
-compress_first_pass(j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+compress_first_pass(j_compress_ptr cinfo, _JSAMPIMAGE input_buf)
{
my_coef_ptr coef = (my_coef_ptr)cinfo->coef;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
@@ -279,10 +281,10 @@ compress_first_pass(j_compress_ptr cinfo, JSAMPIMAGE input_buf)
*/
for (block_row = 0; block_row < block_rows; block_row++) {
thisblockrow = buffer[block_row];
- (*cinfo->fdct->forward_DCT) (cinfo, compptr,
- input_buf[ci], thisblockrow,
- (JDIMENSION)(block_row * DCTSIZE),
- (JDIMENSION)0, blocks_across);
+ (*cinfo->fdct->_forward_DCT) (cinfo, compptr,
+ input_buf[ci], thisblockrow,
+ (JDIMENSION)(block_row * DCTSIZE),
+ (JDIMENSION)0, blocks_across);
if (ndummy > 0) {
/* Create dummy blocks at the right edge of the image. */
thisblockrow += blocks_across; /* => first dummy block */
@@ -338,7 +340,7 @@ compress_first_pass(j_compress_ptr cinfo, JSAMPIMAGE input_buf)
*/
METHODDEF(boolean)
-compress_output(j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+compress_output(j_compress_ptr cinfo, _JSAMPIMAGE input_buf)
{
my_coef_ptr coef = (my_coef_ptr)cinfo->coef;
JDIMENSION MCU_col_num; /* index of current MCU within row */
@@ -402,10 +404,13 @@ compress_output(j_compress_ptr cinfo, JSAMPIMAGE input_buf)
*/
GLOBAL(void)
-jinit_c_coef_controller(j_compress_ptr cinfo, boolean need_full_buffer)
+_jinit_c_coef_controller(j_compress_ptr cinfo, boolean need_full_buffer)
{
my_coef_ptr coef;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
coef = (my_coef_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_coef_controller));
diff --git a/src/3rdparty/libjpeg/src/jccolext.c b/src/3rdparty/libjpeg/src/jccolext.c
index 20f891a633..8eba36c4df 100644
--- a/src/3rdparty/libjpeg/src/jccolext.c
+++ b/src/3rdparty/libjpeg/src/jccolext.c
@@ -29,15 +29,16 @@
INLINE
LOCAL(void)
-rgb_ycc_convert_internal(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row,
+rgb_ycc_convert_internal(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPIMAGE output_buf, JDIMENSION output_row,
int num_rows)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
register int r, g, b;
register JLONG *ctab = cconvert->rgb_ycc_tab;
- register JSAMPROW inptr;
- register JSAMPROW outptr0, outptr1, outptr2;
+ register _JSAMPROW inptr;
+ register _JSAMPROW outptr0, outptr1, outptr2;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->image_width;
@@ -52,22 +53,25 @@ rgb_ycc_convert_internal(j_compress_ptr cinfo, JSAMPARRAY input_buf,
g = RANGE_LIMIT(inptr[RGB_GREEN]);
b = RANGE_LIMIT(inptr[RGB_BLUE]);
inptr += RGB_PIXELSIZE;
- /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations
+ /* If the inputs are 0.._MAXJSAMPLE, the outputs of these equations
* must be too; we do not need an explicit range-limiting operation.
* Hence the value being shifted is never negative, and we don't
* need the general RIGHT_SHIFT macro.
*/
/* Y */
- outptr0[col] = (JSAMPLE)((ctab[r + R_Y_OFF] + ctab[g + G_Y_OFF] +
- ctab[b + B_Y_OFF]) >> SCALEBITS);
+ outptr0[col] = (_JSAMPLE)((ctab[r + R_Y_OFF] + ctab[g + G_Y_OFF] +
+ ctab[b + B_Y_OFF]) >> SCALEBITS);
/* Cb */
- outptr1[col] = (JSAMPLE)((ctab[r + R_CB_OFF] + ctab[g + G_CB_OFF] +
- ctab[b + B_CB_OFF]) >> SCALEBITS);
+ outptr1[col] = (_JSAMPLE)((ctab[r + R_CB_OFF] + ctab[g + G_CB_OFF] +
+ ctab[b + B_CB_OFF]) >> SCALEBITS);
/* Cr */
- outptr2[col] = (JSAMPLE)((ctab[r + R_CR_OFF] + ctab[g + G_CR_OFF] +
- ctab[b + B_CR_OFF]) >> SCALEBITS);
+ outptr2[col] = (_JSAMPLE)((ctab[r + R_CR_OFF] + ctab[g + G_CR_OFF] +
+ ctab[b + B_CR_OFF]) >> SCALEBITS);
}
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
@@ -83,15 +87,16 @@ rgb_ycc_convert_internal(j_compress_ptr cinfo, JSAMPARRAY input_buf,
INLINE
LOCAL(void)
-rgb_gray_convert_internal(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row,
+rgb_gray_convert_internal(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPIMAGE output_buf, JDIMENSION output_row,
int num_rows)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
register int r, g, b;
register JLONG *ctab = cconvert->rgb_ycc_tab;
- register JSAMPROW inptr;
- register JSAMPROW outptr;
+ register _JSAMPROW inptr;
+ register _JSAMPROW outptr;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->image_width;
@@ -105,10 +110,13 @@ rgb_gray_convert_internal(j_compress_ptr cinfo, JSAMPARRAY input_buf,
b = RANGE_LIMIT(inptr[RGB_BLUE]);
inptr += RGB_PIXELSIZE;
/* Y */
- outptr[col] = (JSAMPLE)((ctab[r + R_Y_OFF] + ctab[g + G_Y_OFF] +
- ctab[b + B_Y_OFF]) >> SCALEBITS);
+ outptr[col] = (_JSAMPLE)((ctab[r + R_Y_OFF] + ctab[g + G_Y_OFF] +
+ ctab[b + B_Y_OFF]) >> SCALEBITS);
}
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
@@ -119,12 +127,12 @@ rgb_gray_convert_internal(j_compress_ptr cinfo, JSAMPARRAY input_buf,
INLINE
LOCAL(void)
-rgb_rgb_convert_internal(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row,
+rgb_rgb_convert_internal(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPIMAGE output_buf, JDIMENSION output_row,
int num_rows)
{
- register JSAMPROW inptr;
- register JSAMPROW outptr0, outptr1, outptr2;
+ register _JSAMPROW inptr;
+ register _JSAMPROW outptr0, outptr1, outptr2;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->image_width;
diff --git a/src/3rdparty/libjpeg/src/jccolor.c b/src/3rdparty/libjpeg/src/jccolor.c
index fb9f1cc192..cd3a6a7a56 100644
--- a/src/3rdparty/libjpeg/src/jccolor.c
+++ b/src/3rdparty/libjpeg/src/jccolor.c
@@ -17,15 +17,20 @@
#include "jinclude.h"
#include "jpeglib.h"
#include "jsimd.h"
+#include "jsamplecomp.h"
+#if BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED)
+
/* Private subobject */
typedef struct {
struct jpeg_color_converter pub; /* public fields */
+#if BITS_IN_JSAMPLE != 16
/* Private state for RGB->YCC conversion */
JLONG *rgb_ycc_tab; /* => table for RGB to YCbCr conversion */
+#endif
} my_color_converter;
typedef my_color_converter *my_cconvert_ptr;
@@ -35,14 +40,14 @@ typedef my_color_converter *my_cconvert_ptr;
/*
* YCbCr is defined per CCIR 601-1, except that Cb and Cr are
- * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
+ * normalized to the range 0.._MAXJSAMPLE rather than -0.5 .. 0.5.
* The conversion equations to be implemented are therefore
* Y = 0.29900 * R + 0.58700 * G + 0.11400 * B
- * Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + CENTERJSAMPLE
- * Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + CENTERJSAMPLE
+ * Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + _CENTERJSAMPLE
+ * Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + _CENTERJSAMPLE
* (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
- * Note: older versions of the IJG code used a zero offset of MAXJSAMPLE/2,
- * rather than CENTERJSAMPLE, for Cb and Cr. This gave equal positive and
+ * Note: older versions of the IJG code used a zero offset of _MAXJSAMPLE/2,
+ * rather than _CENTERJSAMPLE, for Cb and Cr. This gave equal positive and
* negative swings for Cb/Cr, but meant that grayscale values (Cb=Cr=0)
* were not represented exactly. Now we sacrifice exact representation of
* maximum red and maximum blue in order to get exact grayscales.
@@ -53,16 +58,16 @@ typedef my_color_converter *my_cconvert_ptr;
*
* For even more speed, we avoid doing any multiplications in the inner loop
* by precalculating the constants times R,G,B for all possible values.
- * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
+ * For 8-bit samples this is very reasonable (only 256 entries per table);
* for 12-bit samples it is still acceptable. It's not very reasonable for
* 16-bit samples, but if you want lossless storage you shouldn't be changing
* colorspace anyway.
- * The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included
+ * The _CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included
* in the tables to save adding them separately in the inner loop.
*/
#define SCALEBITS 16 /* speediest right-shift on some machines */
-#define CBCR_OFFSET ((JLONG)CENTERJSAMPLE << SCALEBITS)
+#define CBCR_OFFSET ((JLONG)_CENTERJSAMPLE << SCALEBITS)
#define ONE_HALF ((JLONG)1 << (SCALEBITS - 1))
#define FIX(x) ((JLONG)((x) * (1L << SCALEBITS) + 0.5))
@@ -73,15 +78,15 @@ typedef my_color_converter *my_cconvert_ptr;
*/
#define R_Y_OFF 0 /* offset to R => Y section */
-#define G_Y_OFF (1 * (MAXJSAMPLE + 1)) /* offset to G => Y section */
-#define B_Y_OFF (2 * (MAXJSAMPLE + 1)) /* etc. */
-#define R_CB_OFF (3 * (MAXJSAMPLE + 1))
-#define G_CB_OFF (4 * (MAXJSAMPLE + 1))
-#define B_CB_OFF (5 * (MAXJSAMPLE + 1))
+#define G_Y_OFF (1 * (_MAXJSAMPLE + 1)) /* offset to G => Y section */
+#define B_Y_OFF (2 * (_MAXJSAMPLE + 1)) /* etc. */
+#define R_CB_OFF (3 * (_MAXJSAMPLE + 1))
+#define G_CB_OFF (4 * (_MAXJSAMPLE + 1))
+#define B_CB_OFF (5 * (_MAXJSAMPLE + 1))
#define R_CR_OFF B_CB_OFF /* B=>Cb, R=>Cr are the same */
-#define G_CR_OFF (6 * (MAXJSAMPLE + 1))
-#define B_CR_OFF (7 * (MAXJSAMPLE + 1))
-#define TABLE_SIZE (8 * (MAXJSAMPLE + 1))
+#define G_CR_OFF (6 * (_MAXJSAMPLE + 1))
+#define B_CR_OFF (7 * (_MAXJSAMPLE + 1))
+#define TABLE_SIZE (8 * (_MAXJSAMPLE + 1))
/* 12-bit samples use a 16-bit data type, so it is possible to pass
* out-of-range sample values (< 0 or > 4095) to jpeg_write_scanlines().
@@ -208,6 +213,7 @@ typedef my_color_converter *my_cconvert_ptr;
METHODDEF(void)
rgb_ycc_start(j_compress_ptr cinfo)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
JLONG *rgb_ycc_tab;
JLONG i;
@@ -217,15 +223,15 @@ rgb_ycc_start(j_compress_ptr cinfo)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
(TABLE_SIZE * sizeof(JLONG)));
- for (i = 0; i <= MAXJSAMPLE; i++) {
+ for (i = 0; i <= _MAXJSAMPLE; i++) {
rgb_ycc_tab[i + R_Y_OFF] = FIX(0.29900) * i;
rgb_ycc_tab[i + G_Y_OFF] = FIX(0.58700) * i;
rgb_ycc_tab[i + B_Y_OFF] = FIX(0.11400) * i + ONE_HALF;
rgb_ycc_tab[i + R_CB_OFF] = (-FIX(0.16874)) * i;
rgb_ycc_tab[i + G_CB_OFF] = (-FIX(0.33126)) * i;
/* We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr.
- * This ensures that the maximum output will round to MAXJSAMPLE
- * not MAXJSAMPLE+1, and thus that we don't have to range-limit.
+ * This ensures that the maximum output will round to _MAXJSAMPLE
+ * not _MAXJSAMPLE+1, and thus that we don't have to range-limit.
*/
rgb_ycc_tab[i + B_CB_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF - 1;
/* B=>Cb and R=>Cr tables are the same
@@ -234,6 +240,9 @@ rgb_ycc_start(j_compress_ptr cinfo)
rgb_ycc_tab[i + G_CR_OFF] = (-FIX(0.41869)) * i;
rgb_ycc_tab[i + B_CR_OFF] = (-FIX(0.08131)) * i;
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
@@ -242,8 +251,8 @@ rgb_ycc_start(j_compress_ptr cinfo)
*/
METHODDEF(void)
-rgb_ycc_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
+rgb_ycc_convert(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
{
switch (cinfo->in_color_space) {
case JCS_EXT_RGB:
@@ -290,8 +299,8 @@ rgb_ycc_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
*/
METHODDEF(void)
-rgb_gray_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
+rgb_gray_convert(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
{
switch (cinfo->in_color_space) {
case JCS_EXT_RGB:
@@ -335,8 +344,8 @@ rgb_gray_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
*/
METHODDEF(void)
-rgb_rgb_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
+rgb_rgb_convert(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
{
switch (cinfo->in_color_space) {
case JCS_EXT_RGB:
@@ -384,14 +393,15 @@ rgb_rgb_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
*/
METHODDEF(void)
-cmyk_ycck_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
+cmyk_ycck_convert(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
register int r, g, b;
register JLONG *ctab = cconvert->rgb_ycc_tab;
- register JSAMPROW inptr;
- register JSAMPROW outptr0, outptr1, outptr2, outptr3;
+ register _JSAMPROW inptr;
+ register _JSAMPROW outptr0, outptr1, outptr2, outptr3;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->image_width;
@@ -403,28 +413,31 @@ cmyk_ycck_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
outptr3 = output_buf[3][output_row];
output_row++;
for (col = 0; col < num_cols; col++) {
- r = MAXJSAMPLE - RANGE_LIMIT(inptr[0]);
- g = MAXJSAMPLE - RANGE_LIMIT(inptr[1]);
- b = MAXJSAMPLE - RANGE_LIMIT(inptr[2]);
+ r = _MAXJSAMPLE - RANGE_LIMIT(inptr[0]);
+ g = _MAXJSAMPLE - RANGE_LIMIT(inptr[1]);
+ b = _MAXJSAMPLE - RANGE_LIMIT(inptr[2]);
/* K passes through as-is */
outptr3[col] = inptr[3];
inptr += 4;
- /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations
+ /* If the inputs are 0.._MAXJSAMPLE, the outputs of these equations
* must be too; we do not need an explicit range-limiting operation.
* Hence the value being shifted is never negative, and we don't
* need the general RIGHT_SHIFT macro.
*/
/* Y */
- outptr0[col] = (JSAMPLE)((ctab[r + R_Y_OFF] + ctab[g + G_Y_OFF] +
- ctab[b + B_Y_OFF]) >> SCALEBITS);
+ outptr0[col] = (_JSAMPLE)((ctab[r + R_Y_OFF] + ctab[g + G_Y_OFF] +
+ ctab[b + B_Y_OFF]) >> SCALEBITS);
/* Cb */
- outptr1[col] = (JSAMPLE)((ctab[r + R_CB_OFF] + ctab[g + G_CB_OFF] +
- ctab[b + B_CB_OFF]) >> SCALEBITS);
+ outptr1[col] = (_JSAMPLE)((ctab[r + R_CB_OFF] + ctab[g + G_CB_OFF] +
+ ctab[b + B_CB_OFF]) >> SCALEBITS);
/* Cr */
- outptr2[col] = (JSAMPLE)((ctab[r + R_CR_OFF] + ctab[g + G_CR_OFF] +
- ctab[b + B_CR_OFF]) >> SCALEBITS);
+ outptr2[col] = (_JSAMPLE)((ctab[r + R_CR_OFF] + ctab[g + G_CR_OFF] +
+ ctab[b + B_CR_OFF]) >> SCALEBITS);
}
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
@@ -435,11 +448,11 @@ cmyk_ycck_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
*/
METHODDEF(void)
-grayscale_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
+grayscale_convert(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
{
- register JSAMPROW inptr;
- register JSAMPROW outptr;
+ register _JSAMPROW inptr;
+ register _JSAMPROW outptr;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->image_width;
int instride = cinfo->input_components;
@@ -463,11 +476,11 @@ grayscale_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
*/
METHODDEF(void)
-null_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
- JDIMENSION output_row, int num_rows)
+null_convert(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)
{
- register JSAMPROW inptr;
- register JSAMPROW outptr, outptr0, outptr1, outptr2, outptr3;
+ register _JSAMPROW inptr;
+ register _JSAMPROW outptr, outptr0, outptr1, outptr2, outptr3;
register JDIMENSION col;
register int ci;
int nc = cinfo->num_components;
@@ -535,10 +548,13 @@ null_method(j_compress_ptr cinfo)
*/
GLOBAL(void)
-jinit_color_converter(j_compress_ptr cinfo)
+_jinit_color_converter(j_compress_ptr cinfo)
{
my_cconvert_ptr cconvert;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
cconvert = (my_cconvert_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_color_converter));
@@ -585,123 +601,116 @@ jinit_color_converter(j_compress_ptr cinfo)
break;
}
- /* Check num_components, set conversion method based on requested space */
+ /* Check num_components, set conversion method based on requested space.
+ * NOTE: We do not allow any lossy color conversion algorithms in lossless
+ * mode.
+ */
switch (cinfo->jpeg_color_space) {
case JCS_GRAYSCALE:
+ if (cinfo->master->lossless &&
+ cinfo->in_color_space != cinfo->jpeg_color_space)
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
if (cinfo->num_components != 1)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
if (cinfo->in_color_space == JCS_GRAYSCALE)
- cconvert->pub.color_convert = grayscale_convert;
- else if (cinfo->in_color_space == JCS_RGB ||
- cinfo->in_color_space == JCS_EXT_RGB ||
- cinfo->in_color_space == JCS_EXT_RGBX ||
- cinfo->in_color_space == JCS_EXT_BGR ||
- cinfo->in_color_space == JCS_EXT_BGRX ||
- cinfo->in_color_space == JCS_EXT_XBGR ||
- cinfo->in_color_space == JCS_EXT_XRGB ||
- cinfo->in_color_space == JCS_EXT_RGBA ||
- cinfo->in_color_space == JCS_EXT_BGRA ||
- cinfo->in_color_space == JCS_EXT_ABGR ||
- cinfo->in_color_space == JCS_EXT_ARGB) {
+ cconvert->pub._color_convert = grayscale_convert;
+ else if (IsExtRGB(cinfo->in_color_space)) {
+#ifdef WITH_SIMD
if (jsimd_can_rgb_gray())
- cconvert->pub.color_convert = jsimd_rgb_gray_convert;
- else {
+ cconvert->pub._color_convert = jsimd_rgb_gray_convert;
+ else
+#endif
+ {
cconvert->pub.start_pass = rgb_ycc_start;
- cconvert->pub.color_convert = rgb_gray_convert;
+ cconvert->pub._color_convert = rgb_gray_convert;
}
} else if (cinfo->in_color_space == JCS_YCbCr)
- cconvert->pub.color_convert = grayscale_convert;
+ cconvert->pub._color_convert = grayscale_convert;
else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
case JCS_RGB:
+ if (cinfo->master->lossless && !IsExtRGB(cinfo->in_color_space))
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
if (cinfo->num_components != 3)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
if (rgb_red[cinfo->in_color_space] == 0 &&
rgb_green[cinfo->in_color_space] == 1 &&
rgb_blue[cinfo->in_color_space] == 2 &&
rgb_pixelsize[cinfo->in_color_space] == 3) {
-#if defined(__mips__)
+#if defined(WITH_SIMD) && defined(__mips__)
if (jsimd_c_can_null_convert())
- cconvert->pub.color_convert = jsimd_c_null_convert;
+ cconvert->pub._color_convert = jsimd_c_null_convert;
else
#endif
- cconvert->pub.color_convert = null_convert;
- } else if (cinfo->in_color_space == JCS_RGB ||
- cinfo->in_color_space == JCS_EXT_RGB ||
- cinfo->in_color_space == JCS_EXT_RGBX ||
- cinfo->in_color_space == JCS_EXT_BGR ||
- cinfo->in_color_space == JCS_EXT_BGRX ||
- cinfo->in_color_space == JCS_EXT_XBGR ||
- cinfo->in_color_space == JCS_EXT_XRGB ||
- cinfo->in_color_space == JCS_EXT_RGBA ||
- cinfo->in_color_space == JCS_EXT_BGRA ||
- cinfo->in_color_space == JCS_EXT_ABGR ||
- cinfo->in_color_space == JCS_EXT_ARGB)
- cconvert->pub.color_convert = rgb_rgb_convert;
+ cconvert->pub._color_convert = null_convert;
+ } else if (IsExtRGB(cinfo->in_color_space))
+ cconvert->pub._color_convert = rgb_rgb_convert;
else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
case JCS_YCbCr:
+ if (cinfo->master->lossless &&
+ cinfo->in_color_space != cinfo->jpeg_color_space)
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
if (cinfo->num_components != 3)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
- if (cinfo->in_color_space == JCS_RGB ||
- cinfo->in_color_space == JCS_EXT_RGB ||
- cinfo->in_color_space == JCS_EXT_RGBX ||
- cinfo->in_color_space == JCS_EXT_BGR ||
- cinfo->in_color_space == JCS_EXT_BGRX ||
- cinfo->in_color_space == JCS_EXT_XBGR ||
- cinfo->in_color_space == JCS_EXT_XRGB ||
- cinfo->in_color_space == JCS_EXT_RGBA ||
- cinfo->in_color_space == JCS_EXT_BGRA ||
- cinfo->in_color_space == JCS_EXT_ABGR ||
- cinfo->in_color_space == JCS_EXT_ARGB) {
+ if (IsExtRGB(cinfo->in_color_space)) {
+#ifdef WITH_SIMD
if (jsimd_can_rgb_ycc())
- cconvert->pub.color_convert = jsimd_rgb_ycc_convert;
- else {
+ cconvert->pub._color_convert = jsimd_rgb_ycc_convert;
+ else
+#endif
+ {
cconvert->pub.start_pass = rgb_ycc_start;
- cconvert->pub.color_convert = rgb_ycc_convert;
+ cconvert->pub._color_convert = rgb_ycc_convert;
}
} else if (cinfo->in_color_space == JCS_YCbCr) {
-#if defined(__mips__)
+#if defined(WITH_SIMD) && defined(__mips__)
if (jsimd_c_can_null_convert())
- cconvert->pub.color_convert = jsimd_c_null_convert;
+ cconvert->pub._color_convert = jsimd_c_null_convert;
else
#endif
- cconvert->pub.color_convert = null_convert;
+ cconvert->pub._color_convert = null_convert;
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
case JCS_CMYK:
+ if (cinfo->master->lossless &&
+ cinfo->in_color_space != cinfo->jpeg_color_space)
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
if (cinfo->num_components != 4)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
if (cinfo->in_color_space == JCS_CMYK) {
-#if defined(__mips__)
+#if defined(WITH_SIMD) && defined(__mips__)
if (jsimd_c_can_null_convert())
- cconvert->pub.color_convert = jsimd_c_null_convert;
+ cconvert->pub._color_convert = jsimd_c_null_convert;
else
#endif
- cconvert->pub.color_convert = null_convert;
+ cconvert->pub._color_convert = null_convert;
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
case JCS_YCCK:
+ if (cinfo->master->lossless &&
+ cinfo->in_color_space != cinfo->jpeg_color_space)
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
if (cinfo->num_components != 4)
ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
if (cinfo->in_color_space == JCS_CMYK) {
cconvert->pub.start_pass = rgb_ycc_start;
- cconvert->pub.color_convert = cmyk_ycck_convert;
+ cconvert->pub._color_convert = cmyk_ycck_convert;
} else if (cinfo->in_color_space == JCS_YCCK) {
-#if defined(__mips__)
+#if defined(WITH_SIMD) && defined(__mips__)
if (jsimd_c_can_null_convert())
- cconvert->pub.color_convert = jsimd_c_null_convert;
+ cconvert->pub._color_convert = jsimd_c_null_convert;
else
#endif
- cconvert->pub.color_convert = null_convert;
+ cconvert->pub._color_convert = null_convert;
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
@@ -710,12 +719,14 @@ jinit_color_converter(j_compress_ptr cinfo)
if (cinfo->jpeg_color_space != cinfo->in_color_space ||
cinfo->num_components != cinfo->input_components)
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
-#if defined(__mips__)
+#if defined(WITH_SIMD) && defined(__mips__)
if (jsimd_c_can_null_convert())
- cconvert->pub.color_convert = jsimd_c_null_convert;
+ cconvert->pub._color_convert = jsimd_c_null_convert;
else
#endif
- cconvert->pub.color_convert = null_convert;
+ cconvert->pub._color_convert = null_convert;
break;
}
}
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED) */
diff --git a/src/3rdparty/libjpeg/src/jcdctmgr.c b/src/3rdparty/libjpeg/src/jcdctmgr.c
index 7dae17a6e1..7191ee7316 100644
--- a/src/3rdparty/libjpeg/src/jcdctmgr.c
+++ b/src/3rdparty/libjpeg/src/jcdctmgr.c
@@ -6,7 +6,7 @@
* libjpeg-turbo Modifications:
* Copyright (C) 1999-2006, MIYASAKA Masaru.
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2011, 2014-2015, D. R. Commander.
+ * Copyright (C) 2011, 2014-2015, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -28,10 +28,10 @@
typedef void (*forward_DCT_method_ptr) (DCTELEM *data);
typedef void (*float_DCT_method_ptr) (FAST_FLOAT *data);
-typedef void (*convsamp_method_ptr) (JSAMPARRAY sample_data,
+typedef void (*convsamp_method_ptr) (_JSAMPARRAY sample_data,
JDIMENSION start_col,
DCTELEM *workspace);
-typedef void (*float_convsamp_method_ptr) (JSAMPARRAY sample_data,
+typedef void (*float_convsamp_method_ptr) (_JSAMPARRAY sample_data,
JDIMENSION start_col,
FAST_FLOAT *workspace);
@@ -265,10 +265,14 @@ start_pass_fdctmgr(j_compress_ptr cinfo)
dtbl = fdct->divisors[qtblno];
for (i = 0; i < DCTSIZE2; i++) {
#if BITS_IN_JSAMPLE == 8
+#ifdef WITH_SIMD
if (!compute_reciprocal(qtbl->quantval[i] << 3, &dtbl[i]) &&
fdct->quantize == jsimd_quantize)
fdct->quantize = quantize;
#else
+ compute_reciprocal(qtbl->quantval[i] << 3, &dtbl[i]);
+#endif
+#else
dtbl[i] = ((DCTELEM)qtbl->quantval[i]) << 3;
#endif
}
@@ -305,6 +309,7 @@ start_pass_fdctmgr(j_compress_ptr cinfo)
dtbl = fdct->divisors[qtblno];
for (i = 0; i < DCTSIZE2; i++) {
#if BITS_IN_JSAMPLE == 8
+#ifdef WITH_SIMD
if (!compute_reciprocal(
DESCALE(MULTIPLY16V16((JLONG)qtbl->quantval[i],
(JLONG)aanscales[i]),
@@ -312,6 +317,12 @@ start_pass_fdctmgr(j_compress_ptr cinfo)
fdct->quantize == jsimd_quantize)
fdct->quantize = quantize;
#else
+ compute_reciprocal(
+ DESCALE(MULTIPLY16V16((JLONG)qtbl->quantval[i],
+ (JLONG)aanscales[i]),
+ CONST_BITS-3), &dtbl[i]);
+#endif
+#else
dtbl[i] = (DCTELEM)
DESCALE(MULTIPLY16V16((JLONG)qtbl->quantval[i],
(JLONG)aanscales[i]),
@@ -370,10 +381,10 @@ start_pass_fdctmgr(j_compress_ptr cinfo)
*/
METHODDEF(void)
-convsamp(JSAMPARRAY sample_data, JDIMENSION start_col, DCTELEM *workspace)
+convsamp(_JSAMPARRAY sample_data, JDIMENSION start_col, DCTELEM *workspace)
{
register DCTELEM *workspaceptr;
- register JSAMPROW elemptr;
+ register _JSAMPROW elemptr;
register int elemr;
workspaceptr = workspace;
@@ -381,19 +392,19 @@ convsamp(JSAMPARRAY sample_data, JDIMENSION start_col, DCTELEM *workspace)
elemptr = sample_data[elemr] + start_col;
#if DCTSIZE == 8 /* unroll the inner loop */
- *workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
- *workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
+ *workspaceptr++ = (*elemptr++) - _CENTERJSAMPLE;
+ *workspaceptr++ = (*elemptr++) - _CENTERJSAMPLE;
+ *workspaceptr++ = (*elemptr++) - _CENTERJSAMPLE;
+ *workspaceptr++ = (*elemptr++) - _CENTERJSAMPLE;
+ *workspaceptr++ = (*elemptr++) - _CENTERJSAMPLE;
+ *workspaceptr++ = (*elemptr++) - _CENTERJSAMPLE;
+ *workspaceptr++ = (*elemptr++) - _CENTERJSAMPLE;
+ *workspaceptr++ = (*elemptr++) - _CENTERJSAMPLE;
#else
{
register int elemc;
for (elemc = DCTSIZE; elemc > 0; elemc--)
- *workspaceptr++ = (*elemptr++) - CENTERJSAMPLE;
+ *workspaceptr++ = (*elemptr++) - _CENTERJSAMPLE;
}
#endif
}
@@ -488,7 +499,7 @@ quantize(JCOEFPTR coef_block, DCTELEM *divisors, DCTELEM *workspace)
METHODDEF(void)
forward_DCT(j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
+ _JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
JDIMENSION start_row, JDIMENSION start_col, JDIMENSION num_blocks)
/* This version is used for integer DCT implementations. */
{
@@ -522,30 +533,30 @@ forward_DCT(j_compress_ptr cinfo, jpeg_component_info *compptr,
#ifdef DCT_FLOAT_SUPPORTED
METHODDEF(void)
-convsamp_float(JSAMPARRAY sample_data, JDIMENSION start_col,
+convsamp_float(_JSAMPARRAY sample_data, JDIMENSION start_col,
FAST_FLOAT *workspace)
{
register FAST_FLOAT *workspaceptr;
- register JSAMPROW elemptr;
+ register _JSAMPROW elemptr;
register int elemr;
workspaceptr = workspace;
for (elemr = 0; elemr < DCTSIZE; elemr++) {
elemptr = sample_data[elemr] + start_col;
#if DCTSIZE == 8 /* unroll the inner loop */
- *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
- *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - _CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - _CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - _CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - _CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - _CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - _CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - _CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - _CENTERJSAMPLE);
#else
{
register int elemc;
for (elemc = DCTSIZE; elemc > 0; elemc--)
- *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - CENTERJSAMPLE);
+ *workspaceptr++ = (FAST_FLOAT)((*elemptr++) - _CENTERJSAMPLE);
}
#endif
}
@@ -577,7 +588,7 @@ quantize_float(JCOEFPTR coef_block, FAST_FLOAT *divisors,
METHODDEF(void)
forward_DCT_float(j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
+ _JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
JDIMENSION start_row, JDIMENSION start_col,
JDIMENSION num_blocks)
/* This version is used for floating-point DCT implementations. */
@@ -617,11 +628,14 @@ forward_DCT_float(j_compress_ptr cinfo, jpeg_component_info *compptr,
*/
GLOBAL(void)
-jinit_forward_dct(j_compress_ptr cinfo)
+_jinit_forward_dct(j_compress_ptr cinfo)
{
my_fdct_ptr fdct;
int i;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
fdct = (my_fdct_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_fdct_controller));
@@ -632,28 +646,34 @@ jinit_forward_dct(j_compress_ptr cinfo)
switch (cinfo->dct_method) {
#ifdef DCT_ISLOW_SUPPORTED
case JDCT_ISLOW:
- fdct->pub.forward_DCT = forward_DCT;
+ fdct->pub._forward_DCT = forward_DCT;
+#ifdef WITH_SIMD
if (jsimd_can_fdct_islow())
fdct->dct = jsimd_fdct_islow;
else
- fdct->dct = jpeg_fdct_islow;
+#endif
+ fdct->dct = _jpeg_fdct_islow;
break;
#endif
#ifdef DCT_IFAST_SUPPORTED
case JDCT_IFAST:
- fdct->pub.forward_DCT = forward_DCT;
+ fdct->pub._forward_DCT = forward_DCT;
+#ifdef WITH_SIMD
if (jsimd_can_fdct_ifast())
fdct->dct = jsimd_fdct_ifast;
else
- fdct->dct = jpeg_fdct_ifast;
+#endif
+ fdct->dct = _jpeg_fdct_ifast;
break;
#endif
#ifdef DCT_FLOAT_SUPPORTED
case JDCT_FLOAT:
- fdct->pub.forward_DCT = forward_DCT_float;
+ fdct->pub._forward_DCT = forward_DCT_float;
+#ifdef WITH_SIMD
if (jsimd_can_fdct_float())
fdct->float_dct = jsimd_fdct_float;
else
+#endif
fdct->float_dct = jpeg_fdct_float;
break;
#endif
@@ -671,25 +691,33 @@ jinit_forward_dct(j_compress_ptr cinfo)
case JDCT_IFAST:
#endif
#if defined(DCT_ISLOW_SUPPORTED) || defined(DCT_IFAST_SUPPORTED)
+#ifdef WITH_SIMD
if (jsimd_can_convsamp())
fdct->convsamp = jsimd_convsamp;
else
+#endif
fdct->convsamp = convsamp;
+#ifdef WITH_SIMD
if (jsimd_can_quantize())
fdct->quantize = jsimd_quantize;
else
+#endif
fdct->quantize = quantize;
break;
#endif
#ifdef DCT_FLOAT_SUPPORTED
case JDCT_FLOAT:
+#ifdef WITH_SIMD
if (jsimd_can_convsamp_float())
fdct->float_convsamp = jsimd_convsamp_float;
else
+#endif
fdct->float_convsamp = convsamp_float;
+#ifdef WITH_SIMD
if (jsimd_can_quantize_float())
fdct->float_quantize = jsimd_quantize_float;
else
+#endif
fdct->float_quantize = quantize_float;
break;
#endif
diff --git a/src/3rdparty/libjpeg/src/jcdiffct.c b/src/3rdparty/libjpeg/src/jcdiffct.c
new file mode 100644
index 0000000000..0bae068919
--- /dev/null
+++ b/src/3rdparty/libjpeg/src/jcdiffct.c
@@ -0,0 +1,411 @@
+/*
+ * jcdiffct.c
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file contains the difference buffer controller for compression.
+ * This controller is the top level of the lossless JPEG compressor proper.
+ * The difference buffer lies between the prediction/differencing and entropy
+ * encoding steps.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jlossls.h" /* Private declarations for lossless codec */
+
+
+#ifdef C_LOSSLESS_SUPPORTED
+
+/* We use a full-image sample buffer when doing Huffman optimization,
+ * and also for writing multiple-scan JPEG files. In all cases, the
+ * full-image buffer is filled during the first pass, and the scaling,
+ * prediction and differencing steps are run during subsequent passes.
+ */
+#ifdef ENTROPY_OPT_SUPPORTED
+#define FULL_SAMP_BUFFER_SUPPORTED
+#else
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+#define FULL_SAMP_BUFFER_SUPPORTED
+#endif
+#endif
+
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_c_coef_controller pub; /* public fields */
+
+ JDIMENSION iMCU_row_num; /* iMCU row # within image */
+ JDIMENSION mcu_ctr; /* counts MCUs processed in current row */
+ int MCU_vert_offset; /* counts MCU rows within iMCU row */
+ int MCU_rows_per_iMCU_row; /* number of such rows needed */
+
+ _JSAMPROW cur_row[MAX_COMPONENTS]; /* row of point-transformed samples */
+ _JSAMPROW prev_row[MAX_COMPONENTS]; /* previous row of Pt'd samples */
+ JDIFFARRAY diff_buf[MAX_COMPONENTS]; /* iMCU row of differences */
+
+ /* In multi-pass modes, we need a virtual sample array for each component. */
+ jvirt_sarray_ptr whole_image[MAX_COMPONENTS];
+} my_diff_controller;
+
+typedef my_diff_controller *my_diff_ptr;
+
+
+/* Forward declarations */
+METHODDEF(boolean) compress_data(j_compress_ptr cinfo, _JSAMPIMAGE input_buf);
+#ifdef FULL_SAMP_BUFFER_SUPPORTED
+METHODDEF(boolean) compress_first_pass(j_compress_ptr cinfo,
+ _JSAMPIMAGE input_buf);
+METHODDEF(boolean) compress_output(j_compress_ptr cinfo,
+ _JSAMPIMAGE input_buf);
+#endif
+
+
+LOCAL(void)
+start_iMCU_row(j_compress_ptr cinfo)
+/* Reset within-iMCU-row counters for a new row */
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+
+ /* In an interleaved scan, an MCU row is the same as an iMCU row.
+ * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
+ * But at the bottom of the image, process only what's left.
+ */
+ if (cinfo->comps_in_scan > 1) {
+ diff->MCU_rows_per_iMCU_row = 1;
+ } else {
+ if (diff->iMCU_row_num < (cinfo->total_iMCU_rows-1))
+ diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
+ else
+ diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
+ }
+
+ diff->mcu_ctr = 0;
+ diff->MCU_vert_offset = 0;
+}
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_diff(j_compress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+
+ /* Because it is hitching a ride on the jpeg_forward_dct struct,
+ * start_pass_lossless() will be called at the start of the initial pass.
+ * This ensures that it will be called at the start of the Huffman
+ * optimization and output passes as well.
+ */
+ if (pass_mode == JBUF_CRANK_DEST)
+ (*cinfo->fdct->start_pass) (cinfo);
+
+ diff->iMCU_row_num = 0;
+ start_iMCU_row(cinfo);
+
+ switch (pass_mode) {
+ case JBUF_PASS_THRU:
+ if (diff->whole_image[0] != NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ diff->pub._compress_data = compress_data;
+ break;
+#ifdef FULL_SAMP_BUFFER_SUPPORTED
+ case JBUF_SAVE_AND_PASS:
+ if (diff->whole_image[0] == NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ diff->pub._compress_data = compress_first_pass;
+ break;
+ case JBUF_CRANK_DEST:
+ if (diff->whole_image[0] == NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ diff->pub._compress_data = compress_output;
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ break;
+ }
+}
+
+
+#define SWAP_ROWS(rowa, rowb) { \
+ _JSAMPROW temp = rowa; \
+ rowa = rowb; rowb = temp; \
+}
+
+/*
+ * Process some data in the single-pass case.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor rows for each component in the image.
+ * Returns TRUE if the iMCU row is completed, FALSE if suspended.
+ *
+ * NB: input_buf contains a plane for each component in image,
+ * which we index according to the component's SOF position.
+ */
+
+METHODDEF(boolean)
+compress_data(j_compress_ptr cinfo, _JSAMPIMAGE input_buf)
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+ lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ JDIMENSION MCU_count; /* number of MCUs encoded */
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ int ci, compi, yoffset, samp_row, samp_rows, samps_across;
+ jpeg_component_info *compptr;
+
+ /* Loop to write as much as one whole iMCU row */
+ for (yoffset = diff->MCU_vert_offset; yoffset < diff->MCU_rows_per_iMCU_row;
+ yoffset++) {
+
+ MCU_col_num = diff->mcu_ctr;
+
+ /* Scale and predict each scanline of the MCU row separately.
+ *
+ * Note: We only do this if we are at the start of an MCU row, ie,
+ * we don't want to reprocess a row suspended by the output.
+ */
+ if (MCU_col_num == 0) {
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ compi = compptr->component_index;
+ if (diff->iMCU_row_num < last_iMCU_row)
+ samp_rows = compptr->v_samp_factor;
+ else {
+ /* NB: can't use last_row_height here, since may not be set! */
+ samp_rows =
+ (int)(compptr->height_in_blocks % compptr->v_samp_factor);
+ if (samp_rows == 0) samp_rows = compptr->v_samp_factor;
+ else {
+ /* Fill dummy difference rows at the bottom edge with zeros, which
+ * will encode to the smallest amount of data.
+ */
+ for (samp_row = samp_rows; samp_row < compptr->v_samp_factor;
+ samp_row++)
+ memset(diff->diff_buf[compi][samp_row], 0,
+ jround_up((long)compptr->width_in_blocks,
+ (long)compptr->h_samp_factor) * sizeof(JDIFF));
+ }
+ }
+ samps_across = compptr->width_in_blocks;
+
+ for (samp_row = 0; samp_row < samp_rows; samp_row++) {
+ (*losslessc->scaler_scale) (cinfo,
+ input_buf[compi][samp_row],
+ diff->cur_row[compi],
+ samps_across);
+ (*losslessc->predict_difference[compi])
+ (cinfo, compi, diff->cur_row[compi], diff->prev_row[compi],
+ diff->diff_buf[compi][samp_row], samps_across);
+ SWAP_ROWS(diff->cur_row[compi], diff->prev_row[compi]);
+ }
+ }
+ }
+ /* Try to write the MCU row (or remaining portion of suspended MCU row). */
+ MCU_count =
+ (*cinfo->entropy->encode_mcus) (cinfo,
+ diff->diff_buf, yoffset, MCU_col_num,
+ cinfo->MCUs_per_row - MCU_col_num);
+ if (MCU_count != cinfo->MCUs_per_row - MCU_col_num) {
+ /* Suspension forced; update state counters and exit */
+ diff->MCU_vert_offset = yoffset;
+ diff->mcu_ctr += MCU_col_num;
+ return FALSE;
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ diff->mcu_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ diff->iMCU_row_num++;
+ start_iMCU_row(cinfo);
+ return TRUE;
+}
+
+
+#ifdef FULL_SAMP_BUFFER_SUPPORTED
+
+/*
+ * Process some data in the first pass of a multi-pass case.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor rows for each component in the image.
+ * This amount of data is read from the source buffer and saved into the
+ * virtual arrays.
+ *
+ * We must also emit the data to the compressor. This is conveniently
+ * done by calling compress_output() after we've loaded the current strip
+ * of the virtual arrays.
+ *
+ * NB: input_buf contains a plane for each component in image. All components
+ * are loaded into the virtual arrays in this pass. However, it may be that
+ * only a subset of the components are emitted to the compressor during
+ * this first pass; be careful about looking at the scan-dependent variables
+ * (MCU dimensions, etc).
+ */
+
+METHODDEF(boolean)
+compress_first_pass(j_compress_ptr cinfo, _JSAMPIMAGE input_buf)
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ JDIMENSION samps_across;
+ int ci, samp_row, samp_rows;
+ _JSAMPARRAY buffer;
+ jpeg_component_info *compptr;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Align the virtual buffer for this component. */
+ buffer = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr)cinfo, diff->whole_image[ci],
+ diff->iMCU_row_num * compptr->v_samp_factor,
+ (JDIMENSION)compptr->v_samp_factor, TRUE);
+
+ /* Count non-dummy sample rows in this iMCU row. */
+ if (diff->iMCU_row_num < last_iMCU_row)
+ samp_rows = compptr->v_samp_factor;
+ else {
+ /* NB: can't use last_row_height here, since may not be set! */
+ samp_rows = (int)(compptr->height_in_blocks % compptr->v_samp_factor);
+ if (samp_rows == 0) samp_rows = compptr->v_samp_factor;
+ }
+ samps_across = compptr->width_in_blocks;
+
+ /* Perform point transform scaling and prediction/differencing for all
+ * non-dummy rows in this iMCU row. Each call on these functions
+ * processes a complete row of samples.
+ */
+ for (samp_row = 0; samp_row < samp_rows; samp_row++) {
+ memcpy(buffer[samp_row], input_buf[ci][samp_row],
+ samps_across * sizeof(_JSAMPLE));
+ }
+ }
+ /* NB: compress_output will increment iMCU_row_num if successful.
+ * A suspension return will result in redoing all the work above next time.
+ */
+
+ /* Emit data to the compressor, sharing code with subsequent passes */
+ return compress_output(cinfo, input_buf);
+}
+
+
+/*
+ * Process some data in subsequent passes of a multi-pass case.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor rows for each component in the scan.
+ * The data is obtained from the virtual arrays and fed to the compressor.
+ * Returns TRUE if the iMCU row is completed, FALSE if suspended.
+ *
+ * NB: input_buf is ignored; it is likely to be a NULL pointer.
+ */
+
+METHODDEF(boolean)
+compress_output(j_compress_ptr cinfo, _JSAMPIMAGE input_buf)
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+ int ci, compi;
+ _JSAMPARRAY buffer[MAX_COMPS_IN_SCAN];
+ jpeg_component_info *compptr;
+
+ /* Align the virtual buffers for the components used in this scan.
+ * NB: during first pass, this is safe only because the buffers will
+ * already be aligned properly, so jmemmgr.c won't need to do any I/O.
+ */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ compi = compptr->component_index;
+ buffer[compi] = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr)cinfo, diff->whole_image[compi],
+ diff->iMCU_row_num * compptr->v_samp_factor,
+ (JDIMENSION)compptr->v_samp_factor, FALSE);
+ }
+
+ return compress_data(cinfo, buffer);
+}
+
+#endif /* FULL_SAMP_BUFFER_SUPPORTED */
+
+
+/*
+ * Initialize difference buffer controller.
+ */
+
+GLOBAL(void)
+_jinit_c_diff_controller(j_compress_ptr cinfo, boolean need_full_buffer)
+{
+ my_diff_ptr diff;
+ int ci, row;
+ jpeg_component_info *compptr;
+
+ diff = (my_diff_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
+ sizeof(my_diff_controller));
+ cinfo->coef = (struct jpeg_c_coef_controller *)diff;
+ diff->pub.start_pass = start_pass_diff;
+
+ /* Create the prediction row buffers. */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ diff->cur_row[ci] = *(_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
+ ((j_common_ptr)cinfo, JPOOL_IMAGE,
+ (JDIMENSION)jround_up((long)compptr->width_in_blocks,
+ (long)compptr->h_samp_factor),
+ (JDIMENSION)1);
+ diff->prev_row[ci] = *(_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
+ ((j_common_ptr)cinfo, JPOOL_IMAGE,
+ (JDIMENSION)jround_up((long)compptr->width_in_blocks,
+ (long)compptr->h_samp_factor),
+ (JDIMENSION)1);
+ }
+
+ /* Create the difference buffer. */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ diff->diff_buf[ci] =
+ ALLOC_DARRAY(JPOOL_IMAGE,
+ (JDIMENSION)jround_up((long)compptr->width_in_blocks,
+ (long)compptr->h_samp_factor),
+ (JDIMENSION)compptr->v_samp_factor);
+ /* Prefill difference rows with zeros. We do this because only actual
+ * data is placed in the buffers during prediction/differencing, leaving
+ * any dummy differences at the right edge as zeros, which will encode
+ * to the smallest amount of data.
+ */
+ for (row = 0; row < compptr->v_samp_factor; row++)
+ memset(diff->diff_buf[ci][row], 0,
+ jround_up((long)compptr->width_in_blocks,
+ (long)compptr->h_samp_factor) * sizeof(JDIFF));
+ }
+
+ /* Create the sample buffer. */
+ if (need_full_buffer) {
+#ifdef FULL_SAMP_BUFFER_SUPPORTED
+ /* Allocate a full-image virtual array for each component, */
+ /* padded to a multiple of samp_factor differences in each direction. */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ diff->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr)cinfo, JPOOL_IMAGE, FALSE,
+ (JDIMENSION)jround_up((long)compptr->width_in_blocks,
+ (long)compptr->h_samp_factor),
+ (JDIMENSION)jround_up((long)compptr->height_in_blocks,
+ (long)compptr->v_samp_factor),
+ (JDIMENSION)compptr->v_samp_factor);
+ }
+#else
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+#endif
+ } else
+ diff->whole_image[0] = NULL; /* flag for no virtual arrays */
+}
+
+#endif /* C_LOSSLESS_SUPPORTED */
diff --git a/src/3rdparty/libjpeg/src/jchuff.c b/src/3rdparty/libjpeg/src/jchuff.c
index 5d0276ad25..488c9b5c3a 100644
--- a/src/3rdparty/libjpeg/src/jchuff.c
+++ b/src/3rdparty/libjpeg/src/jchuff.c
@@ -3,11 +3,14 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2009-2011, 2014-2016, 2018-2022, D. R. Commander.
+ * Copyright (C) 2009-2011, 2014-2016, 2018-2024, D. R. Commander.
* Copyright (C) 2015, Matthieu Darbois.
* Copyright (C) 2018, Matthias Räncker.
* Copyright (C) 2020, Arm Limited.
+ * Copyright (C) 2022, Felix Hanau.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -26,43 +29,13 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#ifdef WITH_SIMD
#include "jsimd.h"
-#include <limits.h>
-
-/*
- * NOTE: If USE_CLZ_INTRINSIC is defined, then clz/bsr instructions will be
- * used for bit counting rather than the lookup table. This will reduce the
- * memory footprint by 64k, which is important for some mobile applications
- * that create many isolated instances of libjpeg-turbo (web browsers, for
- * instance.) This may improve performance on some mobile platforms as well.
- * This feature is enabled by default only on Arm processors, because some x86
- * chips have a slow implementation of bsr, and the use of clz/bsr cannot be
- * shown to have a significant performance impact even on the x86 chips that
- * have a fast implementation of it. When building for Armv6, you can
- * explicitly disable the use of clz/bsr by adding -mthumb to the compiler
- * flags (this defines __thumb__).
- */
-
-/* NOTE: Both GCC and Clang define __GNUC__ */
-#if (defined(__GNUC__) && (defined(__arm__) || defined(__aarch64__))) || \
- defined(_M_ARM) || defined(_M_ARM64)
-#if !defined(__thumb__) || defined(__thumb2__)
-#define USE_CLZ_INTRINSIC
-#endif
-#endif
-
-#ifdef USE_CLZ_INTRINSIC
-#if defined(_MSC_VER) && !defined(__clang__)
-#define JPEG_NBITS_NONZERO(x) (32 - _CountLeadingZeros(x))
-#else
-#define JPEG_NBITS_NONZERO(x) (32 - __builtin_clz(x))
-#endif
-#define JPEG_NBITS(x) (x ? JPEG_NBITS_NONZERO(x) : 0)
#else
-#include "jpeg_nbits_table.h"
-#define JPEG_NBITS(x) (jpeg_nbits_table[x])
-#define JPEG_NBITS_NONZERO(x) JPEG_NBITS(x)
+#include "jchuff.h" /* Declarations shared with jc*huff.c */
#endif
+#include <limits.h>
+#include "jpeg_nbits.h"
/* Expanded entropy encoder object for Huffman encoding.
@@ -101,7 +74,9 @@ typedef bit_buf_type simd_bit_buf_type;
typedef struct {
union {
bit_buf_type c;
+#ifdef WITH_SIMD
simd_bit_buf_type simd;
+#endif
} put_buffer; /* current bit accumulation buffer */
int free_bits; /* # of bits available in it */
/* (Neon GAS: # of bits now in it) */
@@ -126,7 +101,9 @@ typedef struct {
long *ac_count_ptrs[NUM_HUFF_TBLS];
#endif
+#ifdef WITH_SIMD
int simd;
+#endif
} huff_entropy_encoder;
typedef huff_entropy_encoder *huff_entropy_ptr;
@@ -140,7 +117,9 @@ typedef struct {
size_t free_in_buffer; /* # of byte spaces remaining in buffer */
savable_state cur; /* Current bit buffer & DC state */
j_compress_ptr cinfo; /* dump_buffer needs access to this */
+#ifdef WITH_SIMD
int simd;
+#endif
} working_state;
@@ -179,7 +158,9 @@ start_pass_huff(j_compress_ptr cinfo, boolean gather_statistics)
entropy->pub.finish_pass = finish_pass_huff;
}
+#ifdef WITH_SIMD
entropy->simd = jsimd_can_huff_encode_one_block();
+#endif
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
@@ -219,6 +200,7 @@ start_pass_huff(j_compress_ptr cinfo, boolean gather_statistics)
}
/* Initialize bit buffer to empty */
+#ifdef WITH_SIMD
if (entropy->simd) {
entropy->saved.put_buffer.simd = 0;
#if defined(__aarch64__) && !defined(NEON_INTRINSICS)
@@ -226,7 +208,9 @@ start_pass_huff(j_compress_ptr cinfo, boolean gather_statistics)
#else
entropy->saved.free_bits = SIMD_BIT_BUF_SIZE;
#endif
- } else {
+ } else
+#endif
+ {
entropy->saved.put_buffer.c = 0;
entropy->saved.free_bits = BIT_BUF_SIZE;
}
@@ -241,7 +225,7 @@ start_pass_huff(j_compress_ptr cinfo, boolean gather_statistics)
* Compute the derived values for a Huffman table.
* This routine also performs some validation checks on the table.
*
- * Note this is also used by jcphuff.c.
+ * Note this is also used by jcphuff.c and jclhuff.c.
*/
GLOBAL(void)
@@ -317,12 +301,12 @@ jpeg_make_c_derived_tbl(j_compress_ptr cinfo, boolean isDC, int tblno,
memset(dtbl->ehufco, 0, sizeof(dtbl->ehufco));
memset(dtbl->ehufsi, 0, sizeof(dtbl->ehufsi));
- /* This is also a convenient place to check for out-of-range
- * and duplicated VAL entries. We allow 0..255 for AC symbols
- * but only 0..15 for DC. (We could constrain them further
- * based on data depth and mode, but this seems enough.)
+ /* This is also a convenient place to check for out-of-range and duplicated
+ * VAL entries. We allow 0..255 for AC symbols but only 0..15 for DC in
+ * lossy mode and 0..16 for DC in lossless mode. (We could constrain them
+ * further based on data depth and mode, but this seems enough.)
*/
- maxsymbol = isDC ? 15 : 255;
+ maxsymbol = isDC ? (cinfo->master->lossless ? 16 : 15) : 255;
for (p = 0; p < lastp; p++) {
i = htbl->huffval[p];
@@ -499,6 +483,7 @@ flush_bits(working_state *state)
simd_bit_buf_type put_buffer; int put_bits;
int localbuf = 0;
+#ifdef WITH_SIMD
if (state->simd) {
#if defined(__aarch64__) && !defined(NEON_INTRINSICS)
put_bits = state->cur.free_bits;
@@ -506,7 +491,9 @@ flush_bits(working_state *state)
put_bits = SIMD_BIT_BUF_SIZE - state->cur.free_bits;
#endif
put_buffer = state->cur.put_buffer.simd;
- } else {
+ } else
+#endif
+ {
put_bits = BIT_BUF_SIZE - state->cur.free_bits;
put_buffer = state->cur.put_buffer.c;
}
@@ -524,6 +511,7 @@ flush_bits(working_state *state)
EMIT_BYTE(temp)
}
+#ifdef WITH_SIMD
if (state->simd) { /* and reset bit buffer to empty */
state->cur.put_buffer.simd = 0;
#if defined(__aarch64__) && !defined(NEON_INTRINSICS)
@@ -531,7 +519,9 @@ flush_bits(working_state *state)
#else
state->cur.free_bits = SIMD_BIT_BUF_SIZE;
#endif
- } else {
+ } else
+#endif
+ {
state->cur.put_buffer.c = 0;
state->cur.free_bits = BIT_BUF_SIZE;
}
@@ -541,6 +531,8 @@ flush_bits(working_state *state)
}
+#ifdef WITH_SIMD
+
/* Encode a single block's worth of coefficients */
LOCAL(boolean)
@@ -560,6 +552,8 @@ encode_one_block_simd(working_state *state, JCOEFPTR block, int last_dc_val,
return TRUE;
}
+#endif
+
LOCAL(boolean)
encode_one_block(working_state *state, JCOEFPTR block, int last_dc_val,
c_derived_tbl *dctbl, c_derived_tbl *actbl)
@@ -568,6 +562,7 @@ encode_one_block(working_state *state, JCOEFPTR block, int last_dc_val,
bit_buf_type put_buffer;
JOCTET _buffer[BUFSIZE], *buffer;
int localbuf = 0;
+ int max_coef_bits = state->cinfo->data_precision + 2;
free_bits = state->cur.free_bits;
put_buffer = state->cur.put_buffer.c;
@@ -588,6 +583,11 @@ encode_one_block(working_state *state, JCOEFPTR block, int last_dc_val,
/* Find the number of bits needed for the magnitude of the coefficient */
nbits = JPEG_NBITS(nbits);
+ /* Check for out-of-range coefficient values.
+ * Since we're encoding a difference, the range limit is twice as much.
+ */
+ if (nbits > max_coef_bits + 1)
+ ERREXIT(state->cinfo, JERR_BAD_DCT_COEF);
/* Emit the Huffman-coded symbol for the number of bits.
* Emit that number of bits of the value, if positive,
@@ -613,6 +613,9 @@ encode_one_block(working_state *state, JCOEFPTR block, int last_dc_val,
temp += nbits; \
nbits ^= temp; \
nbits = JPEG_NBITS_NONZERO(nbits); \
+ /* Check for out-of-range coefficient values */ \
+ if (nbits > max_coef_bits) \
+ ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); \
/* if run length > 15, must emit special run-length-16 codes (0xF0) */ \
while (r >= 16 * 16) { \
r -= 16 * 16; \
@@ -694,7 +697,9 @@ encode_mcu_huff(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
state.free_in_buffer = cinfo->dest->free_in_buffer;
state.cur = entropy->saved;
state.cinfo = cinfo;
+#ifdef WITH_SIMD
state.simd = entropy->simd;
+#endif
/* Emit restart marker if needed */
if (cinfo->restart_interval) {
@@ -704,6 +709,7 @@ encode_mcu_huff(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
}
/* Encode the MCU data blocks */
+#ifdef WITH_SIMD
if (entropy->simd) {
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
ci = cinfo->MCU_membership[blkn];
@@ -716,7 +722,9 @@ encode_mcu_huff(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
/* Update last_dc_val */
state.cur.last_dc_val[ci] = MCU_data[blkn][0][0];
}
- } else {
+ } else
+#endif
+ {
for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
ci = cinfo->MCU_membership[blkn];
compptr = cinfo->cur_comp_info[ci];
@@ -764,7 +772,9 @@ finish_pass_huff(j_compress_ptr cinfo)
state.free_in_buffer = cinfo->dest->free_in_buffer;
state.cur = entropy->saved;
state.cinfo = cinfo;
+#ifdef WITH_SIMD
state.simd = entropy->simd;
+#endif
/* Flush out the last data */
if (!flush_bits(&state))
@@ -800,6 +810,7 @@ htest_one_block(j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val,
register int temp;
register int nbits;
register int k, r;
+ int max_coef_bits = cinfo->data_precision + 2;
/* Encode the DC coefficient difference per section F.1.2.1 */
@@ -816,7 +827,7 @@ htest_one_block(j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val,
/* Check for out-of-range coefficient values.
* Since we're encoding a difference, the range limit is twice as much.
*/
- if (nbits > MAX_COEF_BITS + 1)
+ if (nbits > max_coef_bits + 1)
ERREXIT(cinfo, JERR_BAD_DCT_COEF);
/* Count the Huffman symbol for the number of bits */
@@ -845,7 +856,7 @@ htest_one_block(j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val,
while ((temp >>= 1))
nbits++;
/* Check for out-of-range coefficient values */
- if (nbits > MAX_COEF_BITS)
+ if (nbits > max_coef_bits)
ERREXIT(cinfo, JERR_BAD_DCT_COEF);
/* Count Huffman symbol for run length / number of bits */
@@ -900,7 +911,7 @@ encode_mcu_gather(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
/*
* Generate the best Huffman code table for the given counts, fill htbl.
- * Note this is also used by jcphuff.c.
+ * Note this is also used by jcphuff.c and jclhuff.c.
*
* The JPEG standard requires that no symbol be assigned a codeword of all
* one bits (so that padding bits added at the end of a compressed segment
@@ -932,11 +943,15 @@ jpeg_gen_optimal_table(j_compress_ptr cinfo, JHUFF_TBL *htbl, long freq[])
{
#define MAX_CLEN 32 /* assumed maximum initial code length */
UINT8 bits[MAX_CLEN + 1]; /* bits[k] = # of symbols with code length k */
+ int bit_pos[MAX_CLEN + 1]; /* # of symbols with smaller code length */
int codesize[257]; /* codesize[k] = code length of symbol k */
+ int nz_index[257]; /* index of nonzero symbol in the original freq
+ array */
int others[257]; /* next symbol in current branch of tree */
int c1, c2;
int p, i, j;
- long v;
+ int num_nz_symbols;
+ long v, v2;
/* This algorithm is explained in section K.2 of the JPEG standard */
@@ -951,28 +966,41 @@ jpeg_gen_optimal_table(j_compress_ptr cinfo, JHUFF_TBL *htbl, long freq[])
* will be placed last in the largest codeword category.
*/
+ /* Group nonzero frequencies together so we can more easily find the
+ * smallest.
+ */
+ num_nz_symbols = 0;
+ for (i = 0; i < 257; i++) {
+ if (freq[i]) {
+ nz_index[num_nz_symbols] = i;
+ freq[num_nz_symbols] = freq[i];
+ num_nz_symbols++;
+ }
+ }
+
/* Huffman's basic algorithm to assign optimal code lengths to symbols */
for (;;) {
- /* Find the smallest nonzero frequency, set c1 = its symbol */
- /* In case of ties, take the larger symbol number */
+ /* Find the two smallest nonzero frequencies; set c1, c2 = their symbols */
+ /* In case of ties, take the larger symbol number. Since we have grouped
+ * the nonzero symbols together, checking for zero symbols is not
+ * necessary.
+ */
c1 = -1;
- v = 1000000000L;
- for (i = 0; i <= 256; i++) {
- if (freq[i] && freq[i] <= v) {
- v = freq[i];
- c1 = i;
- }
- }
-
- /* Find the next smallest nonzero frequency, set c2 = its symbol */
- /* In case of ties, take the larger symbol number */
c2 = -1;
v = 1000000000L;
- for (i = 0; i <= 256; i++) {
- if (freq[i] && freq[i] <= v && i != c1) {
- v = freq[i];
- c2 = i;
+ v2 = 1000000000L;
+ for (i = 0; i < num_nz_symbols; i++) {
+ if (freq[i] <= v2) {
+ if (freq[i] <= v) {
+ c2 = c1;
+ v2 = v;
+ v = freq[i];
+ c1 = i;
+ } else {
+ v2 = freq[i];
+ c2 = i;
+ }
}
}
@@ -982,7 +1010,10 @@ jpeg_gen_optimal_table(j_compress_ptr cinfo, JHUFF_TBL *htbl, long freq[])
/* Else merge the two counts/trees */
freq[c1] += freq[c2];
- freq[c2] = 0;
+ /* Set the frequency to a very high value instead of zero, so we don't have
+ * to check for zero values.
+ */
+ freq[c2] = 1000000001L;
/* Increment the codesize of everything in c1's tree branch */
codesize[c1]++;
@@ -1002,15 +1033,24 @@ jpeg_gen_optimal_table(j_compress_ptr cinfo, JHUFF_TBL *htbl, long freq[])
}
/* Now count the number of symbols of each code length */
- for (i = 0; i <= 256; i++) {
- if (codesize[i]) {
- /* The JPEG standard seems to think that this can't happen, */
- /* but I'm paranoid... */
- if (codesize[i] > MAX_CLEN)
- ERREXIT(cinfo, JERR_HUFF_CLEN_OVERFLOW);
-
- bits[codesize[i]]++;
- }
+ for (i = 0; i < num_nz_symbols; i++) {
+ /* The JPEG standard seems to think that this can't happen, */
+ /* but I'm paranoid... */
+ if (codesize[i] > MAX_CLEN)
+ ERREXIT(cinfo, JERR_HUFF_CLEN_OVERFLOW);
+
+ bits[codesize[i]]++;
+ }
+
+ /* Count the number of symbols with a length smaller than i bits, so we can
+ * construct the symbol table more efficiently. Note that this includes the
+ * pseudo-symbol 256, but since it is the last symbol, it will not affect the
+ * table.
+ */
+ p = 0;
+ for (i = 1; i <= MAX_CLEN; i++) {
+ bit_pos[i] = p;
+ p += bits[i];
}
/* JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure
@@ -1050,14 +1090,9 @@ jpeg_gen_optimal_table(j_compress_ptr cinfo, JHUFF_TBL *htbl, long freq[])
* changes made above, but Rec. ITU-T T.81 | ISO/IEC 10918-1 seems to think
* this works.
*/
- p = 0;
- for (i = 1; i <= MAX_CLEN; i++) {
- for (j = 0; j <= 255; j++) {
- if (codesize[j] == i) {
- htbl->huffval[p] = (UINT8)j;
- p++;
- }
- }
+ for (i = 0; i < num_nz_symbols - 1; i++) {
+ htbl->huffval[bit_pos[codesize[i]]] = (UINT8)nz_index[i];
+ bit_pos[codesize[i]]++;
}
/* Set sent_table FALSE so updated table will be written to JPEG file. */
diff --git a/src/3rdparty/libjpeg/src/jchuff.h b/src/3rdparty/libjpeg/src/jchuff.h
index da7809a94b..21f17b89b0 100644
--- a/src/3rdparty/libjpeg/src/jchuff.h
+++ b/src/3rdparty/libjpeg/src/jchuff.h
@@ -19,12 +19,6 @@
* Hence the magnitude should always fit in 10 or 14 bits respectively.
*/
-#if BITS_IN_JSAMPLE == 8
-#define MAX_COEF_BITS 10
-#else
-#define MAX_COEF_BITS 14
-#endif
-
/* The progressive Huffman encoder uses an unsigned 16-bit data type to store
* absolute values of coefficients, because it is possible to inject a
* coefficient value of -32768 into the encoder by attempting to transform a
diff --git a/src/3rdparty/libjpeg/src/jcicc.c b/src/3rdparty/libjpeg/src/jcicc.c
new file mode 100644
index 0000000000..11037ff694
--- /dev/null
+++ b/src/3rdparty/libjpeg/src/jcicc.c
@@ -0,0 +1,105 @@
+/*
+ * jcicc.c
+ *
+ * Copyright (C) 1997-1998, Thomas G. Lane, Todd Newman.
+ * Copyright (C) 2017, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file provides code to write International Color Consortium (ICC) device
+ * profiles embedded in JFIF JPEG image files. The ICC has defined a standard
+ * for including such data in JPEG "APP2" markers. The code given here does
+ * not know anything about the internal structure of the ICC profile data; it
+ * just knows how to embed the profile data in a JPEG file while writing it.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jerror.h"
+
+
+/*
+ * Since an ICC profile can be larger than the maximum size of a JPEG marker
+ * (64K), we need provisions to split it into multiple markers. The format
+ * defined by the ICC specifies one or more APP2 markers containing the
+ * following data:
+ * Identifying string ASCII "ICC_PROFILE\0" (12 bytes)
+ * Marker sequence number 1 for first APP2, 2 for next, etc (1 byte)
+ * Number of markers Total number of APP2's used (1 byte)
+ * Profile data (remainder of APP2 data)
+ * Decoders should use the marker sequence numbers to reassemble the profile,
+ * rather than assuming that the APP2 markers appear in the correct sequence.
+ */
+
+#define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */
+#define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */
+#define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */
+#define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
+
+
+/*
+ * This routine writes the given ICC profile data into a JPEG file. It *must*
+ * be called AFTER calling jpeg_start_compress() and BEFORE the first call to
+ * jpeg_write_scanlines(). (This ordering ensures that the APP2 marker(s) will
+ * appear after the SOI and JFIF or Adobe markers, but before all else.)
+ */
+
+GLOBAL(void)
+jpeg_write_icc_profile(j_compress_ptr cinfo, const JOCTET *icc_data_ptr,
+ unsigned int icc_data_len)
+{
+ unsigned int num_markers; /* total number of markers we'll write */
+ int cur_marker = 1; /* per spec, counting starts at 1 */
+ unsigned int length; /* number of bytes to write in this marker */
+
+ if (icc_data_ptr == NULL || icc_data_len == 0)
+ ERREXIT(cinfo, JERR_BUFFER_SIZE);
+ if (cinfo->global_state < CSTATE_SCANNING)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ /* Calculate the number of markers we'll need, rounding up of course */
+ num_markers = icc_data_len / MAX_DATA_BYTES_IN_MARKER;
+ if (num_markers * MAX_DATA_BYTES_IN_MARKER != icc_data_len)
+ num_markers++;
+
+ while (icc_data_len > 0) {
+ /* length of profile to put in this marker */
+ length = icc_data_len;
+ if (length > MAX_DATA_BYTES_IN_MARKER)
+ length = MAX_DATA_BYTES_IN_MARKER;
+ icc_data_len -= length;
+
+ /* Write the JPEG marker header (APP2 code and marker length) */
+ jpeg_write_m_header(cinfo, ICC_MARKER,
+ (unsigned int)(length + ICC_OVERHEAD_LEN));
+
+ /* Write the marker identifying string "ICC_PROFILE" (null-terminated). We
+ * code it in this less-than-transparent way so that the code works even if
+ * the local character set is not ASCII.
+ */
+ jpeg_write_m_byte(cinfo, 0x49);
+ jpeg_write_m_byte(cinfo, 0x43);
+ jpeg_write_m_byte(cinfo, 0x43);
+ jpeg_write_m_byte(cinfo, 0x5F);
+ jpeg_write_m_byte(cinfo, 0x50);
+ jpeg_write_m_byte(cinfo, 0x52);
+ jpeg_write_m_byte(cinfo, 0x4F);
+ jpeg_write_m_byte(cinfo, 0x46);
+ jpeg_write_m_byte(cinfo, 0x49);
+ jpeg_write_m_byte(cinfo, 0x4C);
+ jpeg_write_m_byte(cinfo, 0x45);
+ jpeg_write_m_byte(cinfo, 0x0);
+
+ /* Add the sequencing info */
+ jpeg_write_m_byte(cinfo, cur_marker);
+ jpeg_write_m_byte(cinfo, (int)num_markers);
+
+ /* Add the profile data */
+ while (length--) {
+ jpeg_write_m_byte(cinfo, *icc_data_ptr);
+ icc_data_ptr++;
+ }
+ cur_marker++;
+ }
+}
diff --git a/src/3rdparty/libjpeg/src/jcinit.c b/src/3rdparty/libjpeg/src/jcinit.c
index 157353a22e..fe8a13a8d9 100644
--- a/src/3rdparty/libjpeg/src/jcinit.c
+++ b/src/3rdparty/libjpeg/src/jcinit.c
@@ -3,8 +3,10 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2020, D. R. Commander.
+ * Copyright (C) 2020, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -21,7 +23,7 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
/*
@@ -38,34 +40,101 @@ jinit_compress_master(j_compress_ptr cinfo)
/* Preprocessing */
if (!cinfo->raw_data_in) {
- jinit_color_converter(cinfo);
- jinit_downsampler(cinfo);
- jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */);
+ if (cinfo->data_precision == 16) {
+#ifdef C_LOSSLESS_SUPPORTED
+ j16init_color_converter(cinfo);
+ j16init_downsampler(cinfo);
+ j16init_c_prep_controller(cinfo,
+ FALSE /* never need full buffer here */);
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+#endif
+ } else if (cinfo->data_precision == 12) {
+ j12init_color_converter(cinfo);
+ j12init_downsampler(cinfo);
+ j12init_c_prep_controller(cinfo,
+ FALSE /* never need full buffer here */);
+ } else {
+ jinit_color_converter(cinfo);
+ jinit_downsampler(cinfo);
+ jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */);
+ }
}
- /* Forward DCT */
- jinit_forward_dct(cinfo);
- /* Entropy encoding: either Huffman or arithmetic coding. */
- if (cinfo->arith_code) {
-#ifdef C_ARITH_CODING_SUPPORTED
- jinit_arith_encoder(cinfo);
+
+ if (cinfo->master->lossless) {
+#ifdef C_LOSSLESS_SUPPORTED
+ /* Prediction, sample differencing, and point transform */
+ if (cinfo->data_precision == 16)
+ j16init_lossless_compressor(cinfo);
+ else if (cinfo->data_precision == 12)
+ j12init_lossless_compressor(cinfo);
+ else
+ jinit_lossless_compressor(cinfo);
+ /* Entropy encoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code) {
+ ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+ } else {
+ jinit_lhuff_encoder(cinfo);
+ }
+
+ /* Need a full-image difference buffer in any multi-pass mode. */
+ if (cinfo->data_precision == 16)
+ j16init_c_diff_controller(cinfo, (boolean)(cinfo->num_scans > 1 ||
+ cinfo->optimize_coding));
+ else if (cinfo->data_precision == 12)
+ j12init_c_diff_controller(cinfo, (boolean)(cinfo->num_scans > 1 ||
+ cinfo->optimize_coding));
+ else
+ jinit_c_diff_controller(cinfo, (boolean)(cinfo->num_scans > 1 ||
+ cinfo->optimize_coding));
#else
- ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else {
- if (cinfo->progressive_mode) {
+ if (cinfo->data_precision == 16)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ /* Forward DCT */
+ if (cinfo->data_precision == 12)
+ j12init_forward_dct(cinfo);
+ else
+ jinit_forward_dct(cinfo);
+ /* Entropy encoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code) {
+#ifdef C_ARITH_CODING_SUPPORTED
+ jinit_arith_encoder(cinfo);
+#else
+ ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+#endif
+ } else {
+ if (cinfo->progressive_mode) {
#ifdef C_PROGRESSIVE_SUPPORTED
- jinit_phuff_encoder(cinfo);
+ jinit_phuff_encoder(cinfo);
#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
- } else
- jinit_huff_encoder(cinfo);
+ } else
+ jinit_huff_encoder(cinfo);
+ }
+
+ /* Need a full-image coefficient buffer in any multi-pass mode. */
+ if (cinfo->data_precision == 12)
+ j12init_c_coef_controller(cinfo, (boolean)(cinfo->num_scans > 1 ||
+ cinfo->optimize_coding));
+ else
+ jinit_c_coef_controller(cinfo, (boolean)(cinfo->num_scans > 1 ||
+ cinfo->optimize_coding));
}
- /* Need a full-image coefficient buffer in any multi-pass mode. */
- jinit_c_coef_controller(cinfo, (boolean)(cinfo->num_scans > 1 ||
- cinfo->optimize_coding));
- jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */);
+ if (cinfo->data_precision == 16)
+#ifdef C_LOSSLESS_SUPPORTED
+ j16init_c_main_controller(cinfo, FALSE /* never need full buffer here */);
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+#endif
+ else if (cinfo->data_precision == 12)
+ j12init_c_main_controller(cinfo, FALSE /* never need full buffer here */);
+ else
+ jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */);
jinit_marker_writer(cinfo);
diff --git a/src/3rdparty/libjpeg/src/jclhuff.c b/src/3rdparty/libjpeg/src/jclhuff.c
new file mode 100644
index 0000000000..ae4154532e
--- /dev/null
+++ b/src/3rdparty/libjpeg/src/jclhuff.c
@@ -0,0 +1,587 @@
+/*
+ * jclhuff.c
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file contains Huffman entropy encoding routines for lossless JPEG.
+ *
+ * Much of the complexity here has to do with supporting output suspension.
+ * If the data destination module demands suspension, we want to be able to
+ * back up to the start of the current MCU. To do this, we copy state
+ * variables into local working storage, and update them back to the
+ * permanent JPEG objects only upon successful completion of an MCU.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jlossls.h" /* Private declarations for lossless codec */
+#include "jchuff.h" /* Declarations shared with jc*huff.c */
+
+
+#ifdef C_LOSSLESS_SUPPORTED
+
+/* The legal range of a spatial difference is
+ * -32767 .. +32768.
+ * Hence the magnitude should always fit in 16 bits.
+ */
+
+#define MAX_DIFF_BITS 16
+
+
+/* Expanded entropy encoder object for Huffman encoding in lossless mode.
+ *
+ * The savable_state subrecord contains fields that change within an MCU,
+ * but must not be updated permanently until we complete the MCU.
+ */
+
+typedef struct {
+ size_t put_buffer; /* current bit-accumulation buffer */
+ int put_bits; /* # of bits now in it */
+} savable_state;
+
+
+typedef struct {
+ int ci, yoffset, MCU_width;
+} lhe_input_ptr_info;
+
+
+typedef struct {
+ struct jpeg_entropy_encoder pub; /* public fields */
+
+ savable_state saved; /* Bit buffer at start of MCU */
+
+ /* These fields are NOT loaded into local working state. */
+ unsigned int restarts_to_go; /* MCUs left in this restart interval */
+ int next_restart_num; /* next restart number to write (0-7) */
+
+ /* Pointers to derived tables (these workspaces have image lifespan) */
+ c_derived_tbl *derived_tbls[NUM_HUFF_TBLS];
+
+ /* Pointers to derived tables to be used for each data unit within an MCU */
+ c_derived_tbl *cur_tbls[C_MAX_BLOCKS_IN_MCU];
+
+#ifdef ENTROPY_OPT_SUPPORTED /* Statistics tables for optimization */
+ long *count_ptrs[NUM_HUFF_TBLS];
+
+ /* Pointers to stats tables to be used for each data unit within an MCU */
+ long *cur_counts[C_MAX_BLOCKS_IN_MCU];
+#endif
+
+ /* Pointers to the proper input difference row for each group of data units
+ * within an MCU. For each component, there are Vi groups of Hi data units.
+ */
+ JDIFFROW input_ptr[C_MAX_BLOCKS_IN_MCU];
+
+ /* Number of input pointers in use for the current MCU. This is the sum
+ * of all Vi in the MCU.
+ */
+ int num_input_ptrs;
+
+ /* Information used for positioning the input pointers within the input
+ * difference rows.
+ */
+ lhe_input_ptr_info input_ptr_info[C_MAX_BLOCKS_IN_MCU];
+
+ /* Index of the proper input pointer for each data unit within an MCU */
+ int input_ptr_index[C_MAX_BLOCKS_IN_MCU];
+
+} lhuff_entropy_encoder;
+
+typedef lhuff_entropy_encoder *lhuff_entropy_ptr;
+
+/* Working state while writing an MCU.
+ * This struct contains all the fields that are needed by subroutines.
+ */
+
+typedef struct {
+ JOCTET *next_output_byte; /* => next byte to write in buffer */
+ size_t free_in_buffer; /* # of byte spaces remaining in buffer */
+ savable_state cur; /* Current bit buffer & DC state */
+ j_compress_ptr cinfo; /* dump_buffer needs access to this */
+} working_state;
+
+
+/* Forward declarations */
+METHODDEF(JDIMENSION) encode_mcus_huff(j_compress_ptr cinfo,
+ JDIFFIMAGE diff_buf,
+ JDIMENSION MCU_row_num,
+ JDIMENSION MCU_col_num,
+ JDIMENSION nMCU);
+METHODDEF(void) finish_pass_huff(j_compress_ptr cinfo);
+#ifdef ENTROPY_OPT_SUPPORTED
+METHODDEF(JDIMENSION) encode_mcus_gather(j_compress_ptr cinfo,
+ JDIFFIMAGE diff_buf,
+ JDIMENSION MCU_row_num,
+ JDIMENSION MCU_col_num,
+ JDIMENSION nMCU);
+METHODDEF(void) finish_pass_gather(j_compress_ptr cinfo);
+#endif
+
+
+/*
+ * Initialize for a Huffman-compressed scan.
+ * If gather_statistics is TRUE, we do not output anything during the scan,
+ * just count the Huffman symbols used and generate Huffman code tables.
+ */
+
+METHODDEF(void)
+start_pass_lhuff(j_compress_ptr cinfo, boolean gather_statistics)
+{
+ lhuff_entropy_ptr entropy = (lhuff_entropy_ptr)cinfo->entropy;
+ int ci, dctbl, sampn, ptrn, yoffset, xoffset;
+ jpeg_component_info *compptr;
+
+ if (gather_statistics) {
+#ifdef ENTROPY_OPT_SUPPORTED
+ entropy->pub.encode_mcus = encode_mcus_gather;
+ entropy->pub.finish_pass = finish_pass_gather;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ entropy->pub.encode_mcus = encode_mcus_huff;
+ entropy->pub.finish_pass = finish_pass_huff;
+ }
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ dctbl = compptr->dc_tbl_no;
+ if (gather_statistics) {
+#ifdef ENTROPY_OPT_SUPPORTED
+ /* Check for invalid table indexes */
+ /* (make_c_derived_tbl does this in the other path) */
+ if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl);
+ /* Allocate and zero the statistics tables */
+ /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */
+ if (entropy->count_ptrs[dctbl] == NULL)
+ entropy->count_ptrs[dctbl] = (long *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
+ 257 * sizeof(long));
+ memset(entropy->count_ptrs[dctbl], 0, 257 * sizeof(long));
+#endif
+ } else {
+ /* Compute derived values for Huffman tables */
+ /* We may do this more than once for a table, but it's not expensive */
+ jpeg_make_c_derived_tbl(cinfo, TRUE, dctbl,
+ &entropy->derived_tbls[dctbl]);
+ }
+ }
+
+ /* Precalculate encoding info for each sample in an MCU of this scan */
+ for (sampn = 0, ptrn = 0; sampn < cinfo->blocks_in_MCU;) {
+ compptr = cinfo->cur_comp_info[cinfo->MCU_membership[sampn]];
+ ci = compptr->component_index;
+ for (yoffset = 0; yoffset < compptr->MCU_height; yoffset++, ptrn++) {
+ /* Precalculate the setup info for each input pointer */
+ entropy->input_ptr_info[ptrn].ci = ci;
+ entropy->input_ptr_info[ptrn].yoffset = yoffset;
+ entropy->input_ptr_info[ptrn].MCU_width = compptr->MCU_width;
+ for (xoffset = 0; xoffset < compptr->MCU_width; xoffset++, sampn++) {
+ /* Precalculate the input pointer index for each sample */
+ entropy->input_ptr_index[sampn] = ptrn;
+ /* Precalculate which tables to use for each sample */
+ entropy->cur_tbls[sampn] = entropy->derived_tbls[compptr->dc_tbl_no];
+ entropy->cur_counts[sampn] = entropy->count_ptrs[compptr->dc_tbl_no];
+ }
+ }
+ }
+ entropy->num_input_ptrs = ptrn;
+
+ /* Initialize bit buffer to empty */
+ entropy->saved.put_buffer = 0;
+ entropy->saved.put_bits = 0;
+
+ /* Initialize restart stuff */
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num = 0;
+}
+
+
+/* Outputting bytes to the file */
+
+/* Emit a byte, taking 'action' if must suspend. */
+#define emit_byte(state, val, action) { \
+ *(state)->next_output_byte++ = (JOCTET)(val); \
+ if (--(state)->free_in_buffer == 0) \
+ if (!dump_buffer(state)) \
+ { action; } \
+}
+
+
+LOCAL(boolean)
+dump_buffer(working_state *state)
+/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */
+{
+ struct jpeg_destination_mgr *dest = state->cinfo->dest;
+
+ if (!(*dest->empty_output_buffer) (state->cinfo))
+ return FALSE;
+ /* After a successful buffer dump, must reset buffer pointers */
+ state->next_output_byte = dest->next_output_byte;
+ state->free_in_buffer = dest->free_in_buffer;
+ return TRUE;
+}
+
+
+/* Outputting bits to the file */
+
+/* Only the right 24 bits of put_buffer are used; the valid bits are
+ * left-justified in this part. At most 16 bits can be passed to emit_bits
+ * in one call, and we never retain more than 7 bits in put_buffer
+ * between calls, so 24 bits are sufficient.
+ */
+
+INLINE
+LOCAL(boolean)
+emit_bits(working_state *state, unsigned int code, int size)
+/* Emit some bits; return TRUE if successful, FALSE if must suspend */
+{
+ /* This routine is heavily used, so it's worth coding tightly. */
+ register size_t put_buffer = (size_t)code;
+ register int put_bits = state->cur.put_bits;
+
+ /* if size is 0, caller used an invalid Huffman table entry */
+ if (size == 0)
+ ERREXIT(state->cinfo, JERR_HUFF_MISSING_CODE);
+
+ put_buffer &= (((size_t)1) << size) - 1; /* mask off any extra bits in code */
+
+ put_bits += size; /* new number of bits in buffer */
+
+ put_buffer <<= 24 - put_bits; /* align incoming bits */
+
+ put_buffer |= state->cur.put_buffer; /* and merge with old buffer contents */
+
+ while (put_bits >= 8) {
+ int c = (int)((put_buffer >> 16) & 0xFF);
+
+ emit_byte(state, c, return FALSE);
+ if (c == 0xFF) { /* need to stuff a zero byte? */
+ emit_byte(state, 0, return FALSE);
+ }
+ put_buffer <<= 8;
+ put_bits -= 8;
+ }
+
+ state->cur.put_buffer = put_buffer; /* update state variables */
+ state->cur.put_bits = put_bits;
+
+ return TRUE;
+}
+
+
+LOCAL(boolean)
+flush_bits(working_state *state)
+{
+ if (!emit_bits(state, 0x7F, 7)) /* fill any partial byte with ones */
+ return FALSE;
+ state->cur.put_buffer = 0; /* and reset bit-buffer to empty */
+ state->cur.put_bits = 0;
+ return TRUE;
+}
+
+
+/*
+ * Emit a restart marker & resynchronize predictions.
+ */
+
+LOCAL(boolean)
+emit_restart(working_state *state, int restart_num)
+{
+ if (!flush_bits(state))
+ return FALSE;
+
+ emit_byte(state, 0xFF, return FALSE);
+ emit_byte(state, JPEG_RST0 + restart_num, return FALSE);
+
+ /* The restart counter is not updated until we successfully write the MCU. */
+
+ return TRUE;
+}
+
+
+/*
+ * Encode and output nMCU MCUs' worth of Huffman-compressed differences.
+ */
+
+METHODDEF(JDIMENSION)
+encode_mcus_huff(j_compress_ptr cinfo, JDIFFIMAGE diff_buf,
+ JDIMENSION MCU_row_num, JDIMENSION MCU_col_num,
+ JDIMENSION nMCU)
+{
+ lhuff_entropy_ptr entropy = (lhuff_entropy_ptr)cinfo->entropy;
+ working_state state;
+ int sampn, ci, yoffset, MCU_width, ptrn;
+ JDIMENSION mcu_num;
+
+ /* Load up working state */
+ state.next_output_byte = cinfo->dest->next_output_byte;
+ state.free_in_buffer = cinfo->dest->free_in_buffer;
+ state.cur = entropy->saved;
+ state.cinfo = cinfo;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (!emit_restart(&state, entropy->next_restart_num))
+ return 0;
+ }
+
+ /* Set input pointer locations based on MCU_col_num */
+ for (ptrn = 0; ptrn < entropy->num_input_ptrs; ptrn++) {
+ ci = entropy->input_ptr_info[ptrn].ci;
+ yoffset = entropy->input_ptr_info[ptrn].yoffset;
+ MCU_width = entropy->input_ptr_info[ptrn].MCU_width;
+ entropy->input_ptr[ptrn] =
+ diff_buf[ci][MCU_row_num + yoffset] + (MCU_col_num * MCU_width);
+ }
+
+ for (mcu_num = 0; mcu_num < nMCU; mcu_num++) {
+
+ /* Inner loop handles the samples in the MCU */
+ for (sampn = 0; sampn < cinfo->blocks_in_MCU; sampn++) {
+ register int temp, temp2;
+ register int nbits;
+ c_derived_tbl *dctbl = entropy->cur_tbls[sampn];
+
+ /* Encode the difference per section H.1.2.2 */
+
+ /* Input the sample difference */
+ temp = *entropy->input_ptr[entropy->input_ptr_index[sampn]]++;
+
+ if (temp & 0x8000) { /* instead of temp < 0 */
+ temp = (-temp) & 0x7FFF; /* absolute value, mod 2^16 */
+ if (temp == 0) /* special case: magnitude = 32768 */
+ temp2 = temp = 0x8000;
+ temp2 = ~temp; /* one's complement of magnitude */
+ } else {
+ temp &= 0x7FFF; /* abs value mod 2^16 */
+ temp2 = temp; /* magnitude */
+ }
+
+ /* Find the number of bits needed for the magnitude of the difference */
+ nbits = 0;
+ while (temp) {
+ nbits++;
+ temp >>= 1;
+ }
+ /* Check for out-of-range difference values.
+ */
+ if (nbits > MAX_DIFF_BITS)
+ ERREXIT(cinfo, JERR_BAD_DCT_COEF);
+
+ /* Emit the Huffman-coded symbol for the number of bits */
+ if (!emit_bits(&state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits]))
+ return mcu_num;
+
+ /* Emit that number of bits of the value, if positive, */
+ /* or the complement of its magnitude, if negative. */
+ if (nbits && /* emit_bits rejects calls with size 0 */
+ nbits != 16) /* special case: no bits should be emitted */
+ if (!emit_bits(&state, (unsigned int)temp2, nbits))
+ return mcu_num;
+ }
+
+ /* Completed MCU, so update state */
+ cinfo->dest->next_output_byte = state.next_output_byte;
+ cinfo->dest->free_in_buffer = state.free_in_buffer;
+ entropy->saved = state.cur;
+
+ /* Update restart-interval state too */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ }
+
+ return nMCU;
+}
+
+
+/*
+ * Finish up at the end of a Huffman-compressed scan.
+ */
+
+METHODDEF(void)
+finish_pass_huff(j_compress_ptr cinfo)
+{
+ lhuff_entropy_ptr entropy = (lhuff_entropy_ptr)cinfo->entropy;
+ working_state state;
+
+ /* Load up working state ... flush_bits needs it */
+ state.next_output_byte = cinfo->dest->next_output_byte;
+ state.free_in_buffer = cinfo->dest->free_in_buffer;
+ state.cur = entropy->saved;
+ state.cinfo = cinfo;
+
+ /* Flush out the last data */
+ if (!flush_bits(&state))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+
+ /* Update state */
+ cinfo->dest->next_output_byte = state.next_output_byte;
+ cinfo->dest->free_in_buffer = state.free_in_buffer;
+ entropy->saved = state.cur;
+}
+
+
+/*
+ * Huffman coding optimization.
+ *
+ * We first scan the supplied data and count the number of uses of each symbol
+ * that is to be Huffman-coded. (This process MUST agree with the code above.)
+ * Then we build a Huffman coding tree for the observed counts.
+ * Symbols which are not needed at all for the particular image are not
+ * assigned any code, which saves space in the DHT marker as well as in
+ * the compressed data.
+ */
+
+#ifdef ENTROPY_OPT_SUPPORTED
+
+/*
+ * Trial-encode nMCU MCUs' worth of Huffman-compressed differences.
+ * No data is actually output, so no suspension return is possible.
+ */
+
+METHODDEF(JDIMENSION)
+encode_mcus_gather(j_compress_ptr cinfo, JDIFFIMAGE diff_buf,
+ JDIMENSION MCU_row_num, JDIMENSION MCU_col_num,
+ JDIMENSION nMCU)
+{
+ lhuff_entropy_ptr entropy = (lhuff_entropy_ptr)cinfo->entropy;
+ int sampn, ci, yoffset, MCU_width, ptrn;
+ JDIMENSION mcu_num;
+
+ /* Take care of restart intervals if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ /* Update restart state */
+ entropy->restarts_to_go = cinfo->restart_interval;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ /* Set input pointer locations based on MCU_col_num */
+ for (ptrn = 0; ptrn < entropy->num_input_ptrs; ptrn++) {
+ ci = entropy->input_ptr_info[ptrn].ci;
+ yoffset = entropy->input_ptr_info[ptrn].yoffset;
+ MCU_width = entropy->input_ptr_info[ptrn].MCU_width;
+ entropy->input_ptr[ptrn] =
+ diff_buf[ci][MCU_row_num + yoffset] + (MCU_col_num * MCU_width);
+ }
+
+ for (mcu_num = 0; mcu_num < nMCU; mcu_num++) {
+
+ /* Inner loop handles the samples in the MCU */
+ for (sampn = 0; sampn < cinfo->blocks_in_MCU; sampn++) {
+ register int temp;
+ register int nbits;
+ long *counts = entropy->cur_counts[sampn];
+
+ /* Encode the difference per section H.1.2.2 */
+
+ /* Input the sample difference */
+ temp = *entropy->input_ptr[entropy->input_ptr_index[sampn]]++;
+
+ if (temp & 0x8000) { /* instead of temp < 0 */
+ temp = (-temp) & 0x7FFF; /* absolute value, mod 2^16 */
+ if (temp == 0) /* special case: magnitude = 32768 */
+ temp = 0x8000;
+ } else
+ temp &= 0x7FFF; /* abs value mod 2^16 */
+
+ /* Find the number of bits needed for the magnitude of the difference */
+ nbits = 0;
+ while (temp) {
+ nbits++;
+ temp >>= 1;
+ }
+ /* Check for out-of-range difference values.
+ */
+ if (nbits > MAX_DIFF_BITS)
+ ERREXIT(cinfo, JERR_BAD_DCT_COEF);
+
+ /* Count the Huffman symbol for the number of bits */
+ counts[nbits]++;
+ }
+ }
+
+ return nMCU;
+}
+
+
+/*
+ * Finish up a statistics-gathering pass and create the new Huffman tables.
+ */
+
+METHODDEF(void)
+finish_pass_gather(j_compress_ptr cinfo)
+{
+ lhuff_entropy_ptr entropy = (lhuff_entropy_ptr)cinfo->entropy;
+ int ci, dctbl;
+ jpeg_component_info *compptr;
+ JHUFF_TBL **htblptr;
+ boolean did_dc[NUM_HUFF_TBLS];
+
+ /* It's important not to apply jpeg_gen_optimal_table more than once
+ * per table, because it clobbers the input frequency counts!
+ */
+ memset(did_dc, 0, sizeof(did_dc));
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ dctbl = compptr->dc_tbl_no;
+ if (!did_dc[dctbl]) {
+ htblptr = &cinfo->dc_huff_tbl_ptrs[dctbl];
+ if (*htblptr == NULL)
+ *htblptr = jpeg_alloc_huff_table((j_common_ptr)cinfo);
+ jpeg_gen_optimal_table(cinfo, *htblptr, entropy->count_ptrs[dctbl]);
+ did_dc[dctbl] = TRUE;
+ }
+ }
+}
+
+
+#endif /* ENTROPY_OPT_SUPPORTED */
+
+
+/*
+ * Module initialization routine for Huffman entropy encoding.
+ */
+
+GLOBAL(void)
+jinit_lhuff_encoder(j_compress_ptr cinfo)
+{
+ lhuff_entropy_ptr entropy;
+ int i;
+
+ entropy = (lhuff_entropy_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
+ sizeof(lhuff_entropy_encoder));
+ cinfo->entropy = (struct jpeg_entropy_encoder *)entropy;
+ entropy->pub.start_pass = start_pass_lhuff;
+
+ /* Mark tables unallocated */
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ entropy->derived_tbls[i] = NULL;
+#ifdef ENTROPY_OPT_SUPPORTED
+ entropy->count_ptrs[i] = NULL;
+#endif
+ }
+}
+
+#endif /* C_LOSSLESS_SUPPORTED */
diff --git a/src/3rdparty/libjpeg/src/jclossls.c b/src/3rdparty/libjpeg/src/jclossls.c
new file mode 100644
index 0000000000..e9ba92a7df
--- /dev/null
+++ b/src/3rdparty/libjpeg/src/jclossls.c
@@ -0,0 +1,319 @@
+/*
+ * jclossls.c
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1998, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file contains prediction, sample differencing, and point transform
+ * routines for the lossless JPEG compressor.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jlossls.h"
+
+#ifdef C_LOSSLESS_SUPPORTED
+
+
+/************************** Sample differencing **************************/
+
+/*
+ * In order to avoid a performance penalty for checking which predictor is
+ * being used and which row is being processed for each call of the
+ * undifferencer, and to promote optimization, we have separate differencing
+ * functions for each predictor selection value.
+ *
+ * We are able to avoid duplicating source code by implementing the predictors
+ * and differencers as macros. Each of the differencing functions is simply a
+ * wrapper around a DIFFERENCE macro with the appropriate PREDICTOR macro
+ * passed as an argument.
+ */
+
+/* Forward declarations */
+LOCAL(void) reset_predictor(j_compress_ptr cinfo, int ci);
+
+
+/* Predictor for the first column of the first row: 2^(P-Pt-1) */
+#define INITIAL_PREDICTORx (1 << (cinfo->data_precision - cinfo->Al - 1))
+
+/* Predictor for the first column of the remaining rows: Rb */
+#define INITIAL_PREDICTOR2 prev_row[0]
+
+
+/*
+ * 1-Dimensional differencer routine.
+ *
+ * This macro implements the 1-D horizontal predictor (1). INITIAL_PREDICTOR
+ * is used as the special case predictor for the first column, which must be
+ * either INITIAL_PREDICTOR2 or INITIAL_PREDICTORx. The remaining samples
+ * use PREDICTOR1.
+ */
+
+#define DIFFERENCE_1D(INITIAL_PREDICTOR) \
+ lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct; \
+ boolean restart = FALSE; \
+ int samp, Ra; \
+ \
+ samp = *input_buf++; \
+ *diff_buf++ = samp - INITIAL_PREDICTOR; \
+ \
+ while (--width) { \
+ Ra = samp; \
+ samp = *input_buf++; \
+ *diff_buf++ = samp - PREDICTOR1; \
+ } \
+ \
+ /* Account for restart interval (no-op if not using restarts) */ \
+ if (cinfo->restart_interval) { \
+ if (--(losslessc->restart_rows_to_go[ci]) == 0) { \
+ reset_predictor(cinfo, ci); \
+ restart = TRUE; \
+ } \
+ }
+
+
+/*
+ * 2-Dimensional differencer routine.
+ *
+ * This macro implements the 2-D horizontal predictors (#2-7). PREDICTOR2 is
+ * used as the special case predictor for the first column. The remaining
+ * samples use PREDICTOR, which is a function of Ra, Rb, and Rc.
+ *
+ * Because prev_row and output_buf may point to the same storage area (in an
+ * interleaved image with Vi=1, for example), we must take care to buffer Rb/Rc
+ * before writing the current reconstructed sample value into output_buf.
+ */
+
+#define DIFFERENCE_2D(PREDICTOR) \
+ lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct; \
+ int samp, Ra, Rb, Rc; \
+ \
+ Rb = *prev_row++; \
+ samp = *input_buf++; \
+ *diff_buf++ = samp - PREDICTOR2; \
+ \
+ while (--width) { \
+ Rc = Rb; \
+ Rb = *prev_row++; \
+ Ra = samp; \
+ samp = *input_buf++; \
+ *diff_buf++ = samp - PREDICTOR; \
+ } \
+ \
+ /* Account for restart interval (no-op if not using restarts) */ \
+ if (cinfo->restart_interval) { \
+ if (--losslessc->restart_rows_to_go[ci] == 0) \
+ reset_predictor(cinfo, ci); \
+ }
+
+
+/*
+ * Differencers for the second and subsequent rows in a scan or restart
+ * interval. The first sample in the row is differenced using the vertical
+ * predictor (2). The rest of the samples are differenced using the predictor
+ * specified in the scan header.
+ */
+
+METHODDEF(void)
+jpeg_difference1(j_compress_ptr cinfo, int ci,
+ _JSAMPROW input_buf, _JSAMPROW prev_row,
+ JDIFFROW diff_buf, JDIMENSION width)
+{
+ DIFFERENCE_1D(INITIAL_PREDICTOR2);
+ (void)(restart);
+}
+
+METHODDEF(void)
+jpeg_difference2(j_compress_ptr cinfo, int ci,
+ _JSAMPROW input_buf, _JSAMPROW prev_row,
+ JDIFFROW diff_buf, JDIMENSION width)
+{
+ DIFFERENCE_2D(PREDICTOR2);
+ (void)(Ra);
+ (void)(Rc);
+}
+
+METHODDEF(void)
+jpeg_difference3(j_compress_ptr cinfo, int ci,
+ _JSAMPROW input_buf, _JSAMPROW prev_row,
+ JDIFFROW diff_buf, JDIMENSION width)
+{
+ DIFFERENCE_2D(PREDICTOR3);
+ (void)(Ra);
+}
+
+METHODDEF(void)
+jpeg_difference4(j_compress_ptr cinfo, int ci,
+ _JSAMPROW input_buf, _JSAMPROW prev_row,
+ JDIFFROW diff_buf, JDIMENSION width)
+{
+ DIFFERENCE_2D(PREDICTOR4);
+}
+
+METHODDEF(void)
+jpeg_difference5(j_compress_ptr cinfo, int ci,
+ _JSAMPROW input_buf, _JSAMPROW prev_row,
+ JDIFFROW diff_buf, JDIMENSION width)
+{
+ DIFFERENCE_2D(PREDICTOR5);
+}
+
+METHODDEF(void)
+jpeg_difference6(j_compress_ptr cinfo, int ci,
+ _JSAMPROW input_buf, _JSAMPROW prev_row,
+ JDIFFROW diff_buf, JDIMENSION width)
+{
+ DIFFERENCE_2D(PREDICTOR6);
+}
+
+METHODDEF(void)
+jpeg_difference7(j_compress_ptr cinfo, int ci,
+ _JSAMPROW input_buf, _JSAMPROW prev_row,
+ JDIFFROW diff_buf, JDIMENSION width)
+{
+ DIFFERENCE_2D(PREDICTOR7);
+ (void)(Rc);
+}
+
+
+/*
+ * Differencer for the first row in a scan or restart interval. The first
+ * sample in the row is differenced using the special predictor constant
+ * x = 2 ^ (P-Pt-1). The rest of the samples are differenced using the
+ * 1-D horizontal predictor (1).
+ */
+
+METHODDEF(void)
+jpeg_difference_first_row(j_compress_ptr cinfo, int ci,
+ _JSAMPROW input_buf, _JSAMPROW prev_row,
+ JDIFFROW diff_buf, JDIMENSION width)
+{
+ DIFFERENCE_1D(INITIAL_PREDICTORx);
+
+ /*
+ * Now that we have differenced the first row, we want to use the
+ * differencer that corresponds to the predictor specified in the
+ * scan header.
+ *
+ * Note that we don't do this if we have just reset the predictor
+ * for a new restart interval.
+ */
+ if (!restart) {
+ switch (cinfo->Ss) {
+ case 1:
+ losslessc->predict_difference[ci] = jpeg_difference1;
+ break;
+ case 2:
+ losslessc->predict_difference[ci] = jpeg_difference2;
+ break;
+ case 3:
+ losslessc->predict_difference[ci] = jpeg_difference3;
+ break;
+ case 4:
+ losslessc->predict_difference[ci] = jpeg_difference4;
+ break;
+ case 5:
+ losslessc->predict_difference[ci] = jpeg_difference5;
+ break;
+ case 6:
+ losslessc->predict_difference[ci] = jpeg_difference6;
+ break;
+ case 7:
+ losslessc->predict_difference[ci] = jpeg_difference7;
+ break;
+ }
+ }
+}
+
+/*
+ * Reset predictor at the start of a pass or restart interval.
+ */
+
+LOCAL(void)
+reset_predictor(j_compress_ptr cinfo, int ci)
+{
+ lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct;
+
+ /* Initialize restart counter */
+ losslessc->restart_rows_to_go[ci] =
+ cinfo->restart_interval / cinfo->MCUs_per_row;
+
+ /* Set difference function to first row function */
+ losslessc->predict_difference[ci] = jpeg_difference_first_row;
+}
+
+
+/********************** Sample downscaling by 2^Pt ***********************/
+
+METHODDEF(void)
+simple_downscale(j_compress_ptr cinfo,
+ _JSAMPROW input_buf, _JSAMPROW output_buf, JDIMENSION width)
+{
+ do {
+ *output_buf++ = (_JSAMPLE)RIGHT_SHIFT(*input_buf++, cinfo->Al);
+ } while (--width);
+}
+
+
+METHODDEF(void)
+noscale(j_compress_ptr cinfo,
+ _JSAMPROW input_buf, _JSAMPROW output_buf, JDIMENSION width)
+{
+ memcpy(output_buf, input_buf, width * sizeof(_JSAMPLE));
+}
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_lossless(j_compress_ptr cinfo)
+{
+ lossless_comp_ptr losslessc = (lossless_comp_ptr)cinfo->fdct;
+ int ci;
+
+ /* Set scaler function based on Pt */
+ if (cinfo->Al)
+ losslessc->scaler_scale = simple_downscale;
+ else
+ losslessc->scaler_scale = noscale;
+
+ /* Check that the restart interval is an integer multiple of the number
+ * of MCUs in an MCU row.
+ */
+ if (cinfo->restart_interval % cinfo->MCUs_per_row != 0)
+ ERREXIT2(cinfo, JERR_BAD_RESTART,
+ cinfo->restart_interval, cinfo->MCUs_per_row);
+
+ /* Set predictors for start of pass */
+ for (ci = 0; ci < cinfo->num_components; ci++)
+ reset_predictor(cinfo, ci);
+}
+
+
+/*
+ * Initialize the lossless compressor.
+ */
+
+GLOBAL(void)
+_jinit_lossless_compressor(j_compress_ptr cinfo)
+{
+ lossless_comp_ptr losslessc;
+
+ /* Create subobject in permanent pool */
+ losslessc = (lossless_comp_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_PERMANENT,
+ sizeof(jpeg_lossless_compressor));
+ cinfo->fdct = (struct jpeg_forward_dct *)losslessc;
+ losslessc->pub.start_pass = start_pass_lossless;
+}
+
+#endif /* C_LOSSLESS_SUPPORTED */
diff --git a/src/3rdparty/libjpeg/src/jcmainct.c b/src/3rdparty/libjpeg/src/jcmainct.c
index 3f23028c46..fe8fc0b1ac 100644
--- a/src/3rdparty/libjpeg/src/jcmainct.c
+++ b/src/3rdparty/libjpeg/src/jcmainct.c
@@ -3,8 +3,10 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
- * It was modified by The libjpeg-turbo Project to include only code relevant
- * to libjpeg-turbo.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -16,8 +18,11 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#include "jsamplecomp.h"
+#if BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED)
+
/* Private buffer controller object */
typedef struct {
@@ -32,7 +37,7 @@ typedef struct {
* (we allocate one for each component). In the full-image case, this
* points to the currently accessible strips of the virtual arrays.
*/
- JSAMPARRAY buffer[MAX_COMPONENTS];
+ _JSAMPARRAY buffer[MAX_COMPONENTS];
} my_main_controller;
typedef my_main_controller *my_main_ptr;
@@ -40,7 +45,7 @@ typedef my_main_controller *my_main_ptr;
/* Forward declarations */
METHODDEF(void) process_data_simple_main(j_compress_ptr cinfo,
- JSAMPARRAY input_buf,
+ _JSAMPARRAY input_buf,
JDIMENSION *in_row_ctr,
JDIMENSION in_rows_avail);
@@ -65,7 +70,7 @@ start_pass_main(j_compress_ptr cinfo, J_BUF_MODE pass_mode)
main_ptr->rowgroup_ctr = 0;
main_ptr->suspended = FALSE;
main_ptr->pass_mode = pass_mode; /* save mode for use by process_data */
- main_ptr->pub.process_data = process_data_simple_main;
+ main_ptr->pub._process_data = process_data_simple_main;
}
@@ -76,28 +81,28 @@ start_pass_main(j_compress_ptr cinfo, J_BUF_MODE pass_mode)
*/
METHODDEF(void)
-process_data_simple_main(j_compress_ptr cinfo, JSAMPARRAY input_buf,
+process_data_simple_main(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)
{
my_main_ptr main_ptr = (my_main_ptr)cinfo->main;
+ JDIMENSION data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
while (main_ptr->cur_iMCU_row < cinfo->total_iMCU_rows) {
/* Read input data if we haven't filled the main buffer yet */
- if (main_ptr->rowgroup_ctr < DCTSIZE)
- (*cinfo->prep->pre_process_data) (cinfo, input_buf, in_row_ctr,
- in_rows_avail, main_ptr->buffer,
- &main_ptr->rowgroup_ctr,
- (JDIMENSION)DCTSIZE);
+ if (main_ptr->rowgroup_ctr < data_unit)
+ (*cinfo->prep->_pre_process_data) (cinfo, input_buf, in_row_ctr,
+ in_rows_avail, main_ptr->buffer,
+ &main_ptr->rowgroup_ctr, data_unit);
/* If we don't have a full iMCU row buffered, return to application for
* more data. Note that preprocessor will always pad to fill the iMCU row
* at the bottom of the image.
*/
- if (main_ptr->rowgroup_ctr != DCTSIZE)
+ if (main_ptr->rowgroup_ctr != data_unit)
return;
/* Send the completed row to the compressor */
- if (!(*cinfo->coef->compress_data) (cinfo, main_ptr->buffer)) {
+ if (!(*cinfo->coef->_compress_data) (cinfo, main_ptr->buffer)) {
/* If compressor did not consume the whole row, then we must need to
* suspend processing and return to the application. In this situation
* we pretend we didn't yet consume the last input row; otherwise, if
@@ -128,11 +133,15 @@ process_data_simple_main(j_compress_ptr cinfo, JSAMPARRAY input_buf,
*/
GLOBAL(void)
-jinit_c_main_controller(j_compress_ptr cinfo, boolean need_full_buffer)
+_jinit_c_main_controller(j_compress_ptr cinfo, boolean need_full_buffer)
{
my_main_ptr main_ptr;
int ci;
jpeg_component_info *compptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
+
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
main_ptr = (my_main_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
@@ -153,10 +162,12 @@ jinit_c_main_controller(j_compress_ptr cinfo, boolean need_full_buffer)
/* Allocate a strip buffer for each component */
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
- main_ptr->buffer[ci] = (*cinfo->mem->alloc_sarray)
+ main_ptr->buffer[ci] = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE,
- compptr->width_in_blocks * DCTSIZE,
- (JDIMENSION)(compptr->v_samp_factor * DCTSIZE));
+ compptr->width_in_blocks * data_unit,
+ (JDIMENSION)(compptr->v_samp_factor * data_unit));
}
}
}
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED) */
diff --git a/src/3rdparty/libjpeg/src/jcmarker.c b/src/3rdparty/libjpeg/src/jcmarker.c
index 801fbab4ef..a064d4dd9e 100644
--- a/src/3rdparty/libjpeg/src/jcmarker.c
+++ b/src/3rdparty/libjpeg/src/jcmarker.c
@@ -4,8 +4,10 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane.
* Modified 2003-2010 by Guido Vollbeding.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2010, D. R. Commander.
+ * Copyright (C) 2010, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -15,7 +17,7 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
typedef enum { /* JPEG marker codes */
@@ -497,25 +499,26 @@ write_file_header(j_compress_ptr cinfo)
METHODDEF(void)
write_frame_header(j_compress_ptr cinfo)
{
- int ci, prec;
+ int ci, prec = 0;
boolean is_baseline;
jpeg_component_info *compptr;
- /* Emit DQT for each quantization table.
- * Note that emit_dqt() suppresses any duplicate tables.
- */
- prec = 0;
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- prec += emit_dqt(cinfo, compptr->quant_tbl_no);
+ if (!cinfo->master->lossless) {
+ /* Emit DQT for each quantization table.
+ * Note that emit_dqt() suppresses any duplicate tables.
+ */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ prec += emit_dqt(cinfo, compptr->quant_tbl_no);
+ }
+ /* now prec is nonzero iff there are any 16-bit quant tables. */
}
- /* now prec is nonzero iff there are any 16-bit quant tables. */
/* Check for a non-baseline specification.
* Note we assume that Huffman table numbers won't be changed later.
*/
if (cinfo->arith_code || cinfo->progressive_mode ||
- cinfo->data_precision != 8) {
+ cinfo->master->lossless || cinfo->data_precision != 8) {
is_baseline = FALSE;
} else {
is_baseline = TRUE;
@@ -540,6 +543,8 @@ write_frame_header(j_compress_ptr cinfo)
} else {
if (cinfo->progressive_mode)
emit_sof(cinfo, M_SOF2); /* SOF code for progressive Huffman */
+ else if (cinfo->master->lossless)
+ emit_sof(cinfo, M_SOF3); /* SOF code for lossless Huffman */
else if (is_baseline)
emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */
else
@@ -574,10 +579,11 @@ write_scan_header(j_compress_ptr cinfo)
for (i = 0; i < cinfo->comps_in_scan; i++) {
compptr = cinfo->cur_comp_info[i];
/* DC needs no table for refinement scan */
- if (cinfo->Ss == 0 && cinfo->Ah == 0)
+ if ((cinfo->Ss == 0 && cinfo->Ah == 0) || cinfo->master->lossless)
emit_dht(cinfo, compptr->dc_tbl_no, FALSE);
- /* AC needs no table when not present */
- if (cinfo->Se)
+ /* AC needs no table when not present, and lossless mode uses only DC
+ tables. */
+ if (cinfo->Se && !cinfo->master->lossless)
emit_dht(cinfo, compptr->ac_tbl_no, TRUE);
}
}
diff --git a/src/3rdparty/libjpeg/src/jcmaster.c b/src/3rdparty/libjpeg/src/jcmaster.c
index b821710ac3..7e1408fcc9 100644
--- a/src/3rdparty/libjpeg/src/jcmaster.c
+++ b/src/3rdparty/libjpeg/src/jcmaster.c
@@ -4,8 +4,10 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 2003-2010 by Guido Vollbeding.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2016, 2018, D. R. Commander.
+ * Copyright (C) 2010, 2016, 2018, 2022-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -18,39 +20,8 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
-#include "jpegcomp.h"
-
-
-/* Private state */
-
-typedef enum {
- main_pass, /* input data, also do first output step */
- huff_opt_pass, /* Huffman code optimization pass */
- output_pass /* data output pass */
-} c_pass_type;
-
-typedef struct {
- struct jpeg_comp_master pub; /* public fields */
-
- c_pass_type pass_type; /* the type of the current pass */
-
- int pass_number; /* # of passes completed */
- int total_passes; /* total # of passes needed */
-
- int scan_number; /* current index in scan_info[] */
-
- /*
- * This is here so we can add libjpeg-turbo version/build information to the
- * global string table without introducing a new global symbol. Adding this
- * information to the global string table allows one to examine a binary
- * object and determine which version of libjpeg-turbo it was built from or
- * linked against.
- */
- const char *jpeg_version;
-
-} my_comp_master;
-
-typedef my_comp_master *my_master_ptr;
+#include "jpegapicomp.h"
+#include "jcmaster.h"
/*
@@ -68,11 +39,13 @@ GLOBAL(void)
jpeg_calc_jpeg_dimensions(j_compress_ptr cinfo)
/* Do computations that are needed before master selection phase */
{
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
+
/* Hardwire it to "no scaling" */
cinfo->jpeg_width = cinfo->image_width;
cinfo->jpeg_height = cinfo->image_height;
- cinfo->min_DCT_h_scaled_size = DCTSIZE;
- cinfo->min_DCT_v_scaled_size = DCTSIZE;
+ cinfo->min_DCT_h_scaled_size = data_unit;
+ cinfo->min_DCT_v_scaled_size = data_unit;
}
#endif
@@ -85,6 +58,7 @@ initial_setup(j_compress_ptr cinfo, boolean transcode_only)
jpeg_component_info *compptr;
long samplesperrow;
JDIMENSION jd_samplesperrow;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
#if JPEG_LIB_VERSION >= 70
#if JPEG_LIB_VERSION >= 80
@@ -109,8 +83,12 @@ initial_setup(j_compress_ptr cinfo, boolean transcode_only)
if ((long)jd_samplesperrow != samplesperrow)
ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
- /* For now, precision must match compiled-in value... */
- if (cinfo->data_precision != BITS_IN_JSAMPLE)
+#ifdef C_LOSSLESS_SUPPORTED
+ if (cinfo->data_precision != 8 && cinfo->data_precision != 12 &&
+ cinfo->data_precision != 16)
+#else
+ if (cinfo->data_precision != 8 && cinfo->data_precision != 12)
+#endif
ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
/* Check that number of components won't exceed internal array sizes */
@@ -141,17 +119,17 @@ initial_setup(j_compress_ptr cinfo, boolean transcode_only)
compptr->component_index = ci;
/* For compression, we never do DCT scaling. */
#if JPEG_LIB_VERSION >= 70
- compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size = DCTSIZE;
+ compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size = data_unit;
#else
- compptr->DCT_scaled_size = DCTSIZE;
+ compptr->DCT_scaled_size = data_unit;
#endif
- /* Size in DCT blocks */
+ /* Size in data units */
compptr->width_in_blocks = (JDIMENSION)
jdiv_round_up((long)cinfo->_jpeg_width * (long)compptr->h_samp_factor,
- (long)(cinfo->max_h_samp_factor * DCTSIZE));
+ (long)(cinfo->max_h_samp_factor * data_unit));
compptr->height_in_blocks = (JDIMENSION)
jdiv_round_up((long)cinfo->_jpeg_height * (long)compptr->v_samp_factor,
- (long)(cinfo->max_v_samp_factor * DCTSIZE));
+ (long)(cinfo->max_v_samp_factor * data_unit));
/* Size in samples */
compptr->downsampled_width = (JDIMENSION)
jdiv_round_up((long)cinfo->_jpeg_width * (long)compptr->h_samp_factor,
@@ -164,15 +142,19 @@ initial_setup(j_compress_ptr cinfo, boolean transcode_only)
}
/* Compute number of fully interleaved MCU rows (number of times that
- * main controller will call coefficient controller).
+ * main controller will call coefficient or difference controller).
*/
cinfo->total_iMCU_rows = (JDIMENSION)
jdiv_round_up((long)cinfo->_jpeg_height,
- (long)(cinfo->max_v_samp_factor * DCTSIZE));
+ (long)(cinfo->max_v_samp_factor * data_unit));
}
-#ifdef C_MULTISCAN_FILES_SUPPORTED
+#if defined(C_MULTISCAN_FILES_SUPPORTED) || defined(C_LOSSLESS_SUPPORTED)
+#define NEED_SCAN_SCRIPT
+#endif
+
+#ifdef NEED_SCAN_SCRIPT
LOCAL(void)
validate_script(j_compress_ptr cinfo)
@@ -193,13 +175,29 @@ validate_script(j_compress_ptr cinfo)
if (cinfo->num_scans <= 0)
ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, 0);
+#ifndef C_MULTISCAN_FILES_SUPPORTED
+ if (cinfo->num_scans > 1)
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+
+ scanptr = cinfo->scan_info;
+ if (scanptr->Ss != 0 && scanptr->Se == 0) {
+#ifdef C_LOSSLESS_SUPPORTED
+ cinfo->master->lossless = TRUE;
+ cinfo->progressive_mode = FALSE;
+ for (ci = 0; ci < cinfo->num_components; ci++)
+ component_sent[ci] = FALSE;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ }
/* For sequential JPEG, all scans must have Ss=0, Se=DCTSIZE2-1;
* for progressive JPEG, no scan can have this.
*/
- scanptr = cinfo->scan_info;
- if (scanptr->Ss != 0 || scanptr->Se != DCTSIZE2 - 1) {
+ else if (scanptr->Ss != 0 || scanptr->Se != DCTSIZE2 - 1) {
#ifdef C_PROGRESSIVE_SUPPORTED
cinfo->progressive_mode = TRUE;
+ cinfo->master->lossless = FALSE;
last_bitpos_ptr = &last_bitpos[0][0];
for (ci = 0; ci < cinfo->num_components; ci++)
for (coefi = 0; coefi < DCTSIZE2; coefi++)
@@ -208,7 +206,7 @@ validate_script(j_compress_ptr cinfo)
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else {
- cinfo->progressive_mode = FALSE;
+ cinfo->progressive_mode = cinfo->master->lossless = FALSE;
for (ci = 0; ci < cinfo->num_components; ci++)
component_sent[ci] = FALSE;
}
@@ -240,13 +238,10 @@ validate_script(j_compress_ptr cinfo)
* out-of-range reconstructed DC values during the first DC scan,
* which might cause problems for some decoders.
*/
-#if BITS_IN_JSAMPLE == 8
-#define MAX_AH_AL 10
-#else
-#define MAX_AH_AL 13
-#endif
+ int max_Ah_Al = cinfo->data_precision == 12 ? 13 : 10;
+
if (Ss < 0 || Ss >= DCTSIZE2 || Se < Ss || Se >= DCTSIZE2 ||
- Ah < 0 || Ah > MAX_AH_AL || Al < 0 || Al > MAX_AH_AL)
+ Ah < 0 || Ah > max_Ah_Al || Al < 0 || Al > max_Ah_Al)
ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
if (Ss == 0) {
if (Se != 0) /* DC and AC together not OK */
@@ -274,9 +269,25 @@ validate_script(j_compress_ptr cinfo)
}
#endif
} else {
- /* For sequential JPEG, all progression parameters must be these: */
- if (Ss != 0 || Se != DCTSIZE2 - 1 || Ah != 0 || Al != 0)
- ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+#ifdef C_LOSSLESS_SUPPORTED
+ if (cinfo->master->lossless) {
+ /* The JPEG spec simply gives the range 0..15 for Al (Pt), but that
+ * seems wrong: the upper bound ought to depend on data precision.
+ * Perhaps they really meant 0..N-1 for N-bit precision, which is what
+ * we allow here. Values greater than or equal to the data precision
+ * will result in a blank image.
+ */
+ if (Ss < 1 || Ss > 7 || /* predictor selection value */
+ Se != 0 || Ah != 0 ||
+ Al < 0 || Al >= cinfo->data_precision) /* point transform */
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ } else
+#endif
+ {
+ /* For sequential JPEG, all progression parameters must be these: */
+ if (Ss != 0 || Se != DCTSIZE2 - 1 || Ah != 0 || Al != 0)
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ }
/* Make sure components are not sent twice */
for (ci = 0; ci < ncomps; ci++) {
thisi = scanptr->component_index[ci];
@@ -308,7 +319,7 @@ validate_script(j_compress_ptr cinfo)
}
}
-#endif /* C_MULTISCAN_FILES_SUPPORTED */
+#endif /* NEED_SCAN_SCRIPT */
LOCAL(void)
@@ -317,7 +328,7 @@ select_scan_parameters(j_compress_ptr cinfo)
{
int ci;
-#ifdef C_MULTISCAN_FILES_SUPPORTED
+#ifdef NEED_SCAN_SCRIPT
if (cinfo->scan_info != NULL) {
/* Prepare for current scan --- the script is already validated */
my_master_ptr master = (my_master_ptr)cinfo->master;
@@ -343,10 +354,12 @@ select_scan_parameters(j_compress_ptr cinfo)
for (ci = 0; ci < cinfo->num_components; ci++) {
cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci];
}
- cinfo->Ss = 0;
- cinfo->Se = DCTSIZE2 - 1;
- cinfo->Ah = 0;
- cinfo->Al = 0;
+ if (!cinfo->master->lossless) {
+ cinfo->Ss = 0;
+ cinfo->Se = DCTSIZE2 - 1;
+ cinfo->Ah = 0;
+ cinfo->Al = 0;
+ }
}
}
@@ -358,6 +371,7 @@ per_scan_setup(j_compress_ptr cinfo)
{
int ci, mcublks, tmp;
jpeg_component_info *compptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
if (cinfo->comps_in_scan == 1) {
@@ -372,7 +386,7 @@ per_scan_setup(j_compress_ptr cinfo)
compptr->MCU_width = 1;
compptr->MCU_height = 1;
compptr->MCU_blocks = 1;
- compptr->MCU_sample_width = DCTSIZE;
+ compptr->MCU_sample_width = data_unit;
compptr->last_col_width = 1;
/* For noninterleaved scans, it is convenient to define last_row_height
* as the number of block rows present in the last iMCU row.
@@ -395,10 +409,10 @@ per_scan_setup(j_compress_ptr cinfo)
/* Overall image size in MCUs */
cinfo->MCUs_per_row = (JDIMENSION)
jdiv_round_up((long)cinfo->_jpeg_width,
- (long)(cinfo->max_h_samp_factor * DCTSIZE));
+ (long)(cinfo->max_h_samp_factor * data_unit));
cinfo->MCU_rows_in_scan = (JDIMENSION)
jdiv_round_up((long)cinfo->_jpeg_height,
- (long)(cinfo->max_v_samp_factor * DCTSIZE));
+ (long)(cinfo->max_v_samp_factor * data_unit));
cinfo->blocks_in_MCU = 0;
@@ -408,7 +422,7 @@ per_scan_setup(j_compress_ptr cinfo)
compptr->MCU_width = compptr->h_samp_factor;
compptr->MCU_height = compptr->v_samp_factor;
compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;
- compptr->MCU_sample_width = compptr->MCU_width * DCTSIZE;
+ compptr->MCU_sample_width = compptr->MCU_width * data_unit;
/* Figure number of non-dummy blocks in last MCU column & row */
tmp = (int)(compptr->width_in_blocks % compptr->MCU_width);
if (tmp == 0) tmp = compptr->MCU_width;
@@ -480,7 +494,8 @@ prepare_for_pass(j_compress_ptr cinfo)
/* Do Huffman optimization for a scan after the first one. */
select_scan_parameters(cinfo);
per_scan_setup(cinfo);
- if (cinfo->Ss != 0 || cinfo->Ah == 0 || cinfo->arith_code) {
+ if (cinfo->Ss != 0 || cinfo->Ah == 0 || cinfo->arith_code ||
+ cinfo->master->lossless) {
(*cinfo->entropy->start_pass) (cinfo, TRUE);
(*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST);
master->pub.call_pass_startup = FALSE;
@@ -589,22 +604,15 @@ finish_pass_master(j_compress_ptr cinfo)
GLOBAL(void)
jinit_c_master_control(j_compress_ptr cinfo, boolean transcode_only)
{
- my_master_ptr master;
+ my_master_ptr master = (my_master_ptr)cinfo->master;
- master = (my_master_ptr)
- (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- sizeof(my_comp_master));
- cinfo->master = (struct jpeg_comp_master *)master;
master->pub.prepare_for_pass = prepare_for_pass;
master->pub.pass_startup = pass_startup;
master->pub.finish_pass = finish_pass_master;
master->pub.is_last_pass = FALSE;
- /* Validate parameters, determine derived values */
- initial_setup(cinfo, transcode_only);
-
if (cinfo->scan_info != NULL) {
-#ifdef C_MULTISCAN_FILES_SUPPORTED
+#ifdef NEED_SCAN_SCRIPT
validate_script(cinfo);
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
@@ -614,8 +622,33 @@ jinit_c_master_control(j_compress_ptr cinfo, boolean transcode_only)
cinfo->num_scans = 1;
}
- if (cinfo->progressive_mode && !cinfo->arith_code) /* TEMPORARY HACK ??? */
- cinfo->optimize_coding = TRUE; /* assume default tables no good for progressive mode */
+ /* Disable smoothing and subsampling in lossless mode, since those are lossy
+ * algorithms. Set the JPEG colorspace to the input colorspace. Disable raw
+ * (downsampled) data input, because it isn't particularly useful without
+ * subsampling and has not been tested in lossless mode.
+ */
+ if (cinfo->master->lossless) {
+ int ci;
+ jpeg_component_info *compptr;
+
+ cinfo->raw_data_in = FALSE;
+ cinfo->smoothing_factor = 0;
+ jpeg_default_colorspace(cinfo);
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++)
+ compptr->h_samp_factor = compptr->v_samp_factor = 1;
+ }
+
+ /* Validate parameters, determine derived values */
+ initial_setup(cinfo, transcode_only);
+
+ if (cinfo->master->lossless || /* TEMPORARY HACK ??? */
+ (cinfo->progressive_mode && !cinfo->arith_code))
+ cinfo->optimize_coding = TRUE; /* assume default tables no good for
+ progressive mode or lossless mode */
+ if (cinfo->data_precision == 12 && !cinfo->arith_code)
+ cinfo->optimize_coding = TRUE; /* assume default tables no good for 12-bit
+ data precision */
/* Initialize my private state */
if (transcode_only) {
diff --git a/src/3rdparty/libjpeg/src/jcmaster.h b/src/3rdparty/libjpeg/src/jcmaster.h
new file mode 100644
index 0000000000..3b13289b69
--- /dev/null
+++ b/src/3rdparty/libjpeg/src/jcmaster.h
@@ -0,0 +1,43 @@
+/*
+ * jcmaster.h
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1991-1995, Thomas G. Lane.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2016, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file contains master control structure for the JPEG compressor.
+ */
+
+/* Private state */
+
+typedef enum {
+ main_pass, /* input data, also do first output step */
+ huff_opt_pass, /* Huffman code optimization pass */
+ output_pass /* data output pass */
+} c_pass_type;
+
+typedef struct {
+ struct jpeg_comp_master pub; /* public fields */
+
+ c_pass_type pass_type; /* the type of the current pass */
+
+ int pass_number; /* # of passes completed */
+ int total_passes; /* total # of passes needed */
+
+ int scan_number; /* current index in scan_info[] */
+
+ /*
+ * This is here so we can add libjpeg-turbo version/build information to the
+ * global string table without introducing a new global symbol. Adding this
+ * information to the global string table allows one to examine a binary
+ * object and determine which version of libjpeg-turbo it was built from or
+ * linked against.
+ */
+ const char *jpeg_version;
+
+} my_comp_master;
+
+typedef my_comp_master *my_master_ptr;
diff --git a/src/3rdparty/libjpeg/src/jconfig.h b/src/3rdparty/libjpeg/src/jconfig.h
index 51050d0434..1e03e166e7 100644
--- a/src/3rdparty/libjpeg/src/jconfig.h
+++ b/src/3rdparty/libjpeg/src/jconfig.h
@@ -2,9 +2,9 @@
#define JPEG_LIB_VERSION 80
-#define LIBJPEG_TURBO_VERSION 2.1.5
+#define LIBJPEG_TURBO_VERSION 3.0.2
-#define LIBJPEG_TURBO_VERSION_NUMBER 2001005
+#define LIBJPEG_TURBO_VERSION_NUMBER 3000002
#define C_ARITH_CODING_SUPPORTED 1
@@ -12,6 +12,9 @@
#define MEM_SRCDST_SUPPORTED 1
-#define BITS_IN_JSAMPLE 8
+#ifndef BITS_IN_JSAMPLE
+#define BITS_IN_JSAMPLE 8
+#endif
#define NO_PUTENV
+
diff --git a/src/3rdparty/libjpeg/src/jconfig.h.in b/src/3rdparty/libjpeg/src/jconfig.h.in
index e0180122fe..6cb82962ff 100644
--- a/src/3rdparty/libjpeg/src/jconfig.h.in
+++ b/src/3rdparty/libjpeg/src/jconfig.h.in
@@ -9,29 +9,52 @@
/* libjpeg-turbo version in integer form */
#define LIBJPEG_TURBO_VERSION_NUMBER @LIBJPEG_TURBO_VERSION_NUMBER@
-/* Support arithmetic encoding */
+/* Support arithmetic encoding when using 8-bit samples */
#cmakedefine C_ARITH_CODING_SUPPORTED 1
-/* Support arithmetic decoding */
+/* Support arithmetic decoding when using 8-bit samples */
#cmakedefine D_ARITH_CODING_SUPPORTED 1
/* Support in-memory source/destination managers */
-#cmakedefine MEM_SRCDST_SUPPORTED 1
+#define MEM_SRCDST_SUPPORTED 1
-/* Use accelerated SIMD routines. */
+/* Use accelerated SIMD routines when using 8-bit samples */
#cmakedefine WITH_SIMD 1
-/*
- * Define BITS_IN_JSAMPLE as either
- * 8 for 8-bit sample values (the usual setting)
- * 12 for 12-bit sample values
- * Only 8 and 12 are legal data precisions for lossy JPEG according to the
- * JPEG standard, and the IJG code does not support anything else!
- * We do not support run-time selection of data precision, sorry.
+/* This version of libjpeg-turbo supports run-time selection of data precision,
+ * so BITS_IN_JSAMPLE is no longer used to specify the data precision at build
+ * time. However, some downstream software expects the macro to be defined.
+ * Since 12-bit data precision is an opt-in feature that requires explicitly
+ * calling 12-bit-specific libjpeg API functions and using 12-bit-specific data
+ * types, the unmodified portion of the libjpeg API still behaves as if it were
+ * built for 8-bit precision, and JSAMPLE is still literally an 8-bit data
+ * type. Thus, it is correct to define BITS_IN_JSAMPLE to 8 here.
*/
+#ifndef BITS_IN_JSAMPLE
+#define BITS_IN_JSAMPLE 8
+#endif
-#define BITS_IN_JSAMPLE @BITS_IN_JSAMPLE@ /* use 8 or 12 */
+#ifdef _WIN32
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+/* Define "boolean" as unsigned char, not int, per Windows custom */
+#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */
+typedef unsigned char boolean;
+#endif
+#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */
+
+/* Define "INT32" as int, not long, per Windows custom */
+#if !(defined(_BASETSD_H_) || defined(_BASETSD_H)) /* don't conflict if basetsd.h already read */
+typedef short INT16;
+typedef signed int INT32;
+#endif
+#define XMD_H /* prevent jmorecfg.h from redefining it */
+
+#else
/* Define if your (broken) compiler shifts signed values as if they were
unsigned. */
#cmakedefine RIGHT_SHIFT_IS_UNSIGNED 1
+
+#endif
diff --git a/src/3rdparty/libjpeg/src/jconfigint.h b/src/3rdparty/libjpeg/src/jconfigint.h
index 97edb31963..afcb25d247 100644
--- a/src/3rdparty/libjpeg/src/jconfigint.h
+++ b/src/3rdparty/libjpeg/src/jconfigint.h
@@ -4,11 +4,13 @@
#define BUILD ""
+#define HIDDEN
+
#define INLINE inline
#define PACKAGE_NAME "libjpeg-turbo"
-#define VERSION "2.1.5"
+#define VERSION "3.0.2"
#if SIZE_MAX == 0xffffffff
#define SIZEOF_SIZE_T 4
@@ -16,4 +18,34 @@
#define SIZEOF_SIZE_T 8
#endif
+#if defined(_MSC_VER) && defined(HAVE_INTRIN_H)
+#if (SIZEOF_SIZE_T == 8)
+#define HAVE_BITSCANFORWARD64
+#elif (SIZEOF_SIZE_T == 4)
+#define HAVE_BITSCANFORWARD
+#endif
+#endif
+
#define FALLTHROUGH
+
+#ifndef BITS_IN_JSAMPLE
+#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */
+#endif
+
+#undef C_ARITH_CODING_SUPPORTED
+#undef D_ARITH_CODING_SUPPORTED
+#undef WITH_SIMD
+
+#if BITS_IN_JSAMPLE == 8
+
+/* Support arithmetic encoding */
+#define C_ARITH_CODING_SUPPORTED 1
+
+/* Support arithmetic decoding */
+#define D_ARITH_CODING_SUPPORTED 1
+
+/* Use accelerated SIMD routines. */
+/* #undef WITH_SIMD */
+
+#endif
+
diff --git a/src/3rdparty/libjpeg/src/jconfigint.h.in b/src/3rdparty/libjpeg/src/jconfigint.h.in
index d087d7b553..5c14e32a1d 100644
--- a/src/3rdparty/libjpeg/src/jconfigint.h.in
+++ b/src/3rdparty/libjpeg/src/jconfigint.h.in
@@ -1,6 +1,9 @@
/* libjpeg-turbo build number */
#define BUILD "@BUILD@"
+/* How to hide global symbols. */
+#define HIDDEN @HIDDEN@
+
/* Compiler's inline keyword */
#undef inline
@@ -42,3 +45,32 @@
#else
#define FALLTHROUGH
#endif
+
+/*
+ * Define BITS_IN_JSAMPLE as either
+ * 8 for 8-bit sample values (the usual setting)
+ * 12 for 12-bit sample values
+ * Only 8 and 12 are legal data precisions for lossy JPEG according to the
+ * JPEG standard, and the IJG code does not support anything else!
+ */
+
+#ifndef BITS_IN_JSAMPLE
+#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */
+#endif
+
+#undef C_ARITH_CODING_SUPPORTED
+#undef D_ARITH_CODING_SUPPORTED
+#undef WITH_SIMD
+
+#if BITS_IN_JSAMPLE == 8
+
+/* Support arithmetic encoding */
+#cmakedefine C_ARITH_CODING_SUPPORTED 1
+
+/* Support arithmetic decoding */
+#cmakedefine D_ARITH_CODING_SUPPORTED 1
+
+/* Use accelerated SIMD routines. */
+#cmakedefine WITH_SIMD 1
+
+#endif
diff --git a/src/3rdparty/libjpeg/src/jcparam.c b/src/3rdparty/libjpeg/src/jcparam.c
index 5bc7174dcb..d1dee4da3d 100644
--- a/src/3rdparty/libjpeg/src/jcparam.c
+++ b/src/3rdparty/libjpeg/src/jcparam.c
@@ -4,8 +4,10 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane.
* Modified 2003-2008 by Guido Vollbeding.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2009-2011, 2018, D. R. Commander.
+ * Copyright (C) 2009-2011, 2018, 2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -202,7 +204,6 @@ jpeg_set_defaults(j_compress_ptr cinfo)
cinfo->scale_num = 1; /* 1:1 scaling */
cinfo->scale_denom = 1;
#endif
- cinfo->data_precision = BITS_IN_JSAMPLE;
/* Set up two quantization tables using default quality of 75 */
jpeg_set_quality(cinfo, 75, TRUE);
/* Set up two Huffman tables */
@@ -232,7 +233,7 @@ jpeg_set_defaults(j_compress_ptr cinfo)
* tables will be computed. This test can be removed if default tables
* are supplied that are valid for the desired precision.
*/
- if (cinfo->data_precision > 8)
+ if (cinfo->data_precision == 12 && !cinfo->arith_code)
cinfo->optimize_coding = TRUE;
/* By default, use the simpler non-cosited sampling alignment */
@@ -296,7 +297,10 @@ jpeg_default_colorspace(j_compress_ptr cinfo)
case JCS_EXT_BGRA:
case JCS_EXT_ABGR:
case JCS_EXT_ARGB:
- jpeg_set_colorspace(cinfo, JCS_YCbCr);
+ if (cinfo->master->lossless)
+ jpeg_set_colorspace(cinfo, JCS_RGB);
+ else
+ jpeg_set_colorspace(cinfo, JCS_YCbCr);
break;
case JCS_YCbCr:
jpeg_set_colorspace(cinfo, JCS_YCbCr);
@@ -475,6 +479,11 @@ jpeg_simple_progression(j_compress_ptr cinfo)
if (cinfo->global_state != CSTATE_START)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ if (cinfo->master->lossless) {
+ cinfo->master->lossless = FALSE;
+ jpeg_default_colorspace(cinfo);
+ }
+
/* Figure space needed for script. Calculation must match code below! */
if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) {
/* Custom script for YCbCr color images. */
@@ -539,3 +548,38 @@ jpeg_simple_progression(j_compress_ptr cinfo)
}
#endif /* C_PROGRESSIVE_SUPPORTED */
+
+
+#ifdef C_LOSSLESS_SUPPORTED
+
+/*
+ * Enable lossless mode.
+ */
+
+GLOBAL(void)
+jpeg_enable_lossless(j_compress_ptr cinfo, int predictor_selection_value,
+ int point_transform)
+{
+ /* Safety check to ensure start_compress not called yet. */
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ cinfo->master->lossless = TRUE;
+ cinfo->Ss = predictor_selection_value;
+ cinfo->Se = 0;
+ cinfo->Ah = 0;
+ cinfo->Al = point_transform;
+
+ /* The JPEG spec simply gives the range 0..15 for Al (Pt), but that seems
+ * wrong: the upper bound ought to depend on data precision. Perhaps they
+ * really meant 0..N-1 for N-bit precision, which is what we allow here.
+ * Values greater than or equal to the data precision will result in a blank
+ * image.
+ */
+ if (cinfo->Ss < 1 || cinfo->Ss > 7 ||
+ cinfo->Al < 0 || cinfo->Al >= cinfo->data_precision)
+ ERREXIT4(cinfo, JERR_BAD_PROGRESSION,
+ cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
+}
+
+#endif /* C_LOSSLESS_SUPPORTED */
diff --git a/src/3rdparty/libjpeg/src/jcphuff.c b/src/3rdparty/libjpeg/src/jcphuff.c
index 5006b67075..484e2d857f 100644
--- a/src/3rdparty/libjpeg/src/jcphuff.c
+++ b/src/3rdparty/libjpeg/src/jcphuff.c
@@ -3,8 +3,10 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1995-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2011, 2015, 2018, 2021-2022, D. R. Commander.
+ * Copyright (C) 2011, 2015, 2018, 2021-2022, 2024, D. R. Commander.
* Copyright (C) 2016, 2018, 2022, Matthieu Darbois.
* Copyright (C) 2020, Arm Limited.
* Copyright (C) 2021, Alex Richardson.
@@ -21,7 +23,11 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#ifdef WITH_SIMD
#include "jsimd.h"
+#else
+#include "jchuff.h" /* Declarations shared with jc*huff.c */
+#endif
#include <limits.h>
#ifdef HAVE_INTRIN_H
@@ -38,40 +44,7 @@
#ifdef C_PROGRESSIVE_SUPPORTED
-/*
- * NOTE: If USE_CLZ_INTRINSIC is defined, then clz/bsr instructions will be
- * used for bit counting rather than the lookup table. This will reduce the
- * memory footprint by 64k, which is important for some mobile applications
- * that create many isolated instances of libjpeg-turbo (web browsers, for
- * instance.) This may improve performance on some mobile platforms as well.
- * This feature is enabled by default only on Arm processors, because some x86
- * chips have a slow implementation of bsr, and the use of clz/bsr cannot be
- * shown to have a significant performance impact even on the x86 chips that
- * have a fast implementation of it. When building for Armv6, you can
- * explicitly disable the use of clz/bsr by adding -mthumb to the compiler
- * flags (this defines __thumb__).
- */
-
-/* NOTE: Both GCC and Clang define __GNUC__ */
-#if (defined(__GNUC__) && (defined(__arm__) || defined(__aarch64__))) || \
- defined(_M_ARM) || defined(_M_ARM64)
-#if !defined(__thumb__) || defined(__thumb2__)
-#define USE_CLZ_INTRINSIC
-#endif
-#endif
-
-#ifdef USE_CLZ_INTRINSIC
-#if defined(_MSC_VER) && !defined(__clang__)
-#define JPEG_NBITS_NONZERO(x) (32 - _CountLeadingZeros(x))
-#else
-#define JPEG_NBITS_NONZERO(x) (32 - __builtin_clz(x))
-#endif
-#define JPEG_NBITS(x) (x ? JPEG_NBITS_NONZERO(x) : 0)
-#else
-#include "jpeg_nbits_table.h"
-#define JPEG_NBITS(x) (jpeg_nbits_table[x])
-#define JPEG_NBITS_NONZERO(x) JPEG_NBITS(x)
-#endif
+#include "jpeg_nbits.h"
/* Expanded entropy encoder object for progressive Huffman encoding. */
@@ -223,18 +196,22 @@ start_pass_phuff(j_compress_ptr cinfo, boolean gather_statistics)
entropy->pub.encode_mcu = encode_mcu_DC_first;
else
entropy->pub.encode_mcu = encode_mcu_AC_first;
+#ifdef WITH_SIMD
if (jsimd_can_encode_mcu_AC_first_prepare())
entropy->AC_first_prepare = jsimd_encode_mcu_AC_first_prepare;
else
+#endif
entropy->AC_first_prepare = encode_mcu_AC_first_prepare;
} else {
if (is_DC_band)
entropy->pub.encode_mcu = encode_mcu_DC_refine;
else {
entropy->pub.encode_mcu = encode_mcu_AC_refine;
+#ifdef WITH_SIMD
if (jsimd_can_encode_mcu_AC_refine_prepare())
entropy->AC_refine_prepare = jsimd_encode_mcu_AC_refine_prepare;
else
+#endif
entropy->AC_refine_prepare = encode_mcu_AC_refine_prepare;
/* AC refinement needs a correction bit buffer */
if (entropy->bit_buffer == NULL)
@@ -489,6 +466,7 @@ encode_mcu_DC_first(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
JBLOCKROW block;
jpeg_component_info *compptr;
ISHIFT_TEMPS
+ int max_coef_bits = cinfo->data_precision + 2;
entropy->next_output_byte = cinfo->dest->next_output_byte;
entropy->free_in_buffer = cinfo->dest->free_in_buffer;
@@ -531,7 +509,7 @@ encode_mcu_DC_first(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
/* Check for out-of-range coefficient values.
* Since we're encoding a difference, the range limit is twice as much.
*/
- if (nbits > MAX_COEF_BITS + 1)
+ if (nbits > max_coef_bits + 1)
ERREXIT(cinfo, JERR_BAD_DCT_COEF);
/* Count/emit the Huffman-coded symbol for the number of bits */
@@ -642,7 +620,7 @@ label \
/* Find the number of bits needed for the magnitude of the coefficient */ \
nbits = JPEG_NBITS_NONZERO(temp); /* there must be at least one 1 bit */ \
/* Check for out-of-range coefficient values */ \
- if (nbits > MAX_COEF_BITS) \
+ if (nbits > max_coef_bits) \
ERREXIT(cinfo, JERR_BAD_DCT_COEF); \
\
/* Count/emit Huffman symbol for run length / number of bits */ \
@@ -670,6 +648,7 @@ encode_mcu_AC_first(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
const UJCOEF *cvalue;
size_t zerobits;
size_t bits[8 / SIZEOF_SIZE_T];
+ int max_coef_bits = cinfo->data_precision + 2;
entropy->next_output_byte = cinfo->dest->next_output_byte;
entropy->free_in_buffer = cinfo->dest->free_in_buffer;
diff --git a/src/3rdparty/libjpeg/src/jcprepct.c b/src/3rdparty/libjpeg/src/jcprepct.c
index f27cc34507..ac2311c138 100644
--- a/src/3rdparty/libjpeg/src/jcprepct.c
+++ b/src/3rdparty/libjpeg/src/jcprepct.c
@@ -1,8 +1,10 @@
/*
* jcprepct.c
*
- * This file is part of the Independent JPEG Group's software:
+ * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
* Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
@@ -20,8 +22,11 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#include "jsamplecomp.h"
+#if BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED)
+
/* At present, jcsample.c can request context rows only for smoothing.
* In the future, we might also need context rows for CCIR601 sampling
* or other more-complex downsampling procedures. The code to support
@@ -59,7 +64,7 @@ typedef struct {
/* Downsampling input buffer. This buffer holds color-converted data
* until we have enough to do a downsample step.
*/
- JSAMPARRAY color_buf[MAX_COMPONENTS];
+ _JSAMPARRAY color_buf[MAX_COMPONENTS];
JDIMENSION rows_to_go; /* counts rows remaining in source image */
int next_buf_row; /* index of next row to store in color_buf */
@@ -106,14 +111,14 @@ start_pass_prep(j_compress_ptr cinfo, J_BUF_MODE pass_mode)
*/
LOCAL(void)
-expand_bottom_edge(JSAMPARRAY image_data, JDIMENSION num_cols, int input_rows,
+expand_bottom_edge(_JSAMPARRAY image_data, JDIMENSION num_cols, int input_rows,
int output_rows)
{
register int row;
for (row = input_rows; row < output_rows; row++) {
- jcopy_sample_rows(image_data, input_rows - 1, image_data, row, 1,
- num_cols);
+ _jcopy_sample_rows(image_data, input_rows - 1, image_data, row, 1,
+ num_cols);
}
}
@@ -128,15 +133,16 @@ expand_bottom_edge(JSAMPARRAY image_data, JDIMENSION num_cols, int input_rows,
*/
METHODDEF(void)
-pre_process_data(j_compress_ptr cinfo, JSAMPARRAY input_buf,
+pre_process_data(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail,
- JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
+ _JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
JDIMENSION out_row_groups_avail)
{
my_prep_ptr prep = (my_prep_ptr)cinfo->prep;
int numrows, ci;
JDIMENSION inrows;
jpeg_component_info *compptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
while (*in_row_ctr < in_rows_avail &&
*out_row_group_ctr < out_row_groups_avail) {
@@ -144,10 +150,10 @@ pre_process_data(j_compress_ptr cinfo, JSAMPARRAY input_buf,
inrows = in_rows_avail - *in_row_ctr;
numrows = cinfo->max_v_samp_factor - prep->next_buf_row;
numrows = (int)MIN((JDIMENSION)numrows, inrows);
- (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr,
- prep->color_buf,
- (JDIMENSION)prep->next_buf_row,
- numrows);
+ (*cinfo->cconvert->_color_convert) (cinfo, input_buf + *in_row_ctr,
+ prep->color_buf,
+ (JDIMENSION)prep->next_buf_row,
+ numrows);
*in_row_ctr += numrows;
prep->next_buf_row += numrows;
prep->rows_to_go -= numrows;
@@ -162,9 +168,9 @@ pre_process_data(j_compress_ptr cinfo, JSAMPARRAY input_buf,
}
/* If we've filled the conversion buffer, empty it. */
if (prep->next_buf_row == cinfo->max_v_samp_factor) {
- (*cinfo->downsample->downsample) (cinfo,
- prep->color_buf, (JDIMENSION)0,
- output_buf, *out_row_group_ctr);
+ (*cinfo->downsample->_downsample) (cinfo,
+ prep->color_buf, (JDIMENSION)0,
+ output_buf, *out_row_group_ctr);
prep->next_buf_row = 0;
(*out_row_group_ctr)++;
}
@@ -174,7 +180,8 @@ pre_process_data(j_compress_ptr cinfo, JSAMPARRAY input_buf,
if (prep->rows_to_go == 0 && *out_row_group_ctr < out_row_groups_avail) {
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
- expand_bottom_edge(output_buf[ci], compptr->width_in_blocks * DCTSIZE,
+ expand_bottom_edge(output_buf[ci],
+ compptr->width_in_blocks * data_unit,
(int)(*out_row_group_ctr * compptr->v_samp_factor),
(int)(out_row_groups_avail * compptr->v_samp_factor));
}
@@ -192,9 +199,9 @@ pre_process_data(j_compress_ptr cinfo, JSAMPARRAY input_buf,
*/
METHODDEF(void)
-pre_process_context(j_compress_ptr cinfo, JSAMPARRAY input_buf,
+pre_process_context(j_compress_ptr cinfo, _JSAMPARRAY input_buf,
JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail,
- JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
+ _JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
JDIMENSION out_row_groups_avail)
{
my_prep_ptr prep = (my_prep_ptr)cinfo->prep;
@@ -208,17 +215,17 @@ pre_process_context(j_compress_ptr cinfo, JSAMPARRAY input_buf,
inrows = in_rows_avail - *in_row_ctr;
numrows = prep->next_buf_stop - prep->next_buf_row;
numrows = (int)MIN((JDIMENSION)numrows, inrows);
- (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr,
- prep->color_buf,
- (JDIMENSION)prep->next_buf_row,
- numrows);
+ (*cinfo->cconvert->_color_convert) (cinfo, input_buf + *in_row_ctr,
+ prep->color_buf,
+ (JDIMENSION)prep->next_buf_row,
+ numrows);
/* Pad at top of image, if first time through */
if (prep->rows_to_go == cinfo->image_height) {
for (ci = 0; ci < cinfo->num_components; ci++) {
int row;
for (row = 1; row <= cinfo->max_v_samp_factor; row++) {
- jcopy_sample_rows(prep->color_buf[ci], 0, prep->color_buf[ci],
- -row, 1, cinfo->image_width);
+ _jcopy_sample_rows(prep->color_buf[ci], 0, prep->color_buf[ci],
+ -row, 1, cinfo->image_width);
}
}
}
@@ -240,9 +247,9 @@ pre_process_context(j_compress_ptr cinfo, JSAMPARRAY input_buf,
}
/* If we've gotten enough data, downsample a row group. */
if (prep->next_buf_row == prep->next_buf_stop) {
- (*cinfo->downsample->downsample) (cinfo, prep->color_buf,
- (JDIMENSION)prep->this_row_group,
- output_buf, *out_row_group_ctr);
+ (*cinfo->downsample->_downsample) (cinfo, prep->color_buf,
+ (JDIMENSION)prep->this_row_group,
+ output_buf, *out_row_group_ctr);
(*out_row_group_ctr)++;
/* Advance pointers with wraparound as necessary. */
prep->this_row_group += cinfo->max_v_samp_factor;
@@ -267,15 +274,16 @@ create_context_buffer(j_compress_ptr cinfo)
int rgroup_height = cinfo->max_v_samp_factor;
int ci, i;
jpeg_component_info *compptr;
- JSAMPARRAY true_buffer, fake_buffer;
+ _JSAMPARRAY true_buffer, fake_buffer;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
/* Grab enough space for fake row pointers for all the components;
* we need five row groups' worth of pointers for each component.
*/
- fake_buffer = (JSAMPARRAY)
+ fake_buffer = (_JSAMPARRAY)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
(cinfo->num_components * 5 * rgroup_height) *
- sizeof(JSAMPROW));
+ sizeof(_JSAMPROW));
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
@@ -283,14 +291,14 @@ create_context_buffer(j_compress_ptr cinfo)
* We make the buffer wide enough to allow the downsampler to edge-expand
* horizontally within the buffer, if it so chooses.
*/
- true_buffer = (*cinfo->mem->alloc_sarray)
+ true_buffer = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE,
- (JDIMENSION)(((long)compptr->width_in_blocks * DCTSIZE *
+ (JDIMENSION)(((long)compptr->width_in_blocks * data_unit *
cinfo->max_h_samp_factor) / compptr->h_samp_factor),
(JDIMENSION)(3 * rgroup_height));
/* Copy true buffer row pointers into the middle of the fake row array */
memcpy(fake_buffer + rgroup_height, true_buffer,
- 3 * rgroup_height * sizeof(JSAMPROW));
+ 3 * rgroup_height * sizeof(_JSAMPROW));
/* Fill in the above and below wraparound pointers */
for (i = 0; i < rgroup_height; i++) {
fake_buffer[i] = true_buffer[2 * rgroup_height + i];
@@ -309,11 +317,15 @@ create_context_buffer(j_compress_ptr cinfo)
*/
GLOBAL(void)
-jinit_c_prep_controller(j_compress_ptr cinfo, boolean need_full_buffer)
+_jinit_c_prep_controller(j_compress_ptr cinfo, boolean need_full_buffer)
{
my_prep_ptr prep;
int ci;
jpeg_component_info *compptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
+
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
if (need_full_buffer) /* safety check */
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
@@ -331,21 +343,23 @@ jinit_c_prep_controller(j_compress_ptr cinfo, boolean need_full_buffer)
if (cinfo->downsample->need_context_rows) {
/* Set up to provide context rows */
#ifdef CONTEXT_ROWS_SUPPORTED
- prep->pub.pre_process_data = pre_process_context;
+ prep->pub._pre_process_data = pre_process_context;
create_context_buffer(cinfo);
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else {
/* No context, just make it tall enough for one row group */
- prep->pub.pre_process_data = pre_process_data;
+ prep->pub._pre_process_data = pre_process_data;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
- prep->color_buf[ci] = (*cinfo->mem->alloc_sarray)
+ prep->color_buf[ci] = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE,
- (JDIMENSION)(((long)compptr->width_in_blocks * DCTSIZE *
+ (JDIMENSION)(((long)compptr->width_in_blocks * data_unit *
cinfo->max_h_samp_factor) / compptr->h_samp_factor),
(JDIMENSION)cinfo->max_v_samp_factor);
}
}
}
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED) */
diff --git a/src/3rdparty/libjpeg/src/jcsample.c b/src/3rdparty/libjpeg/src/jcsample.c
index e8515ebf0f..30e6e54b40 100644
--- a/src/3rdparty/libjpeg/src/jcsample.c
+++ b/src/3rdparty/libjpeg/src/jcsample.c
@@ -3,10 +3,12 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1996, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2014, MIPS Technologies, Inc., California.
- * Copyright (C) 2015, 2019, D. R. Commander.
+ * Copyright (C) 2015, 2019, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -54,13 +56,16 @@
#include "jinclude.h"
#include "jpeglib.h"
#include "jsimd.h"
+#include "jsamplecomp.h"
+#if BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED)
+
/* Pointer to routine to downsample a single component */
typedef void (*downsample1_ptr) (j_compress_ptr cinfo,
jpeg_component_info *compptr,
- JSAMPARRAY input_data,
- JSAMPARRAY output_data);
+ _JSAMPARRAY input_data,
+ _JSAMPARRAY output_data);
/* Private subobject */
@@ -91,11 +96,11 @@ start_pass_downsample(j_compress_ptr cinfo)
*/
LOCAL(void)
-expand_right_edge(JSAMPARRAY image_data, int num_rows, JDIMENSION input_cols,
+expand_right_edge(_JSAMPARRAY image_data, int num_rows, JDIMENSION input_cols,
JDIMENSION output_cols)
{
- register JSAMPROW ptr;
- register JSAMPLE pixval;
+ register _JSAMPROW ptr;
+ register _JSAMPLE pixval;
register int count;
int row;
int numcols = (int)(output_cols - input_cols);
@@ -118,14 +123,14 @@ expand_right_edge(JSAMPARRAY image_data, int num_rows, JDIMENSION input_cols,
*/
METHODDEF(void)
-sep_downsample(j_compress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_index, JSAMPIMAGE output_buf,
+sep_downsample(j_compress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION in_row_index, _JSAMPIMAGE output_buf,
JDIMENSION out_row_group_index)
{
my_downsample_ptr downsample = (my_downsample_ptr)cinfo->downsample;
int ci;
jpeg_component_info *compptr;
- JSAMPARRAY in_ptr, out_ptr;
+ _JSAMPARRAY in_ptr, out_ptr;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
@@ -145,12 +150,13 @@ sep_downsample(j_compress_ptr cinfo, JSAMPIMAGE input_buf,
METHODDEF(void)
int_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
+ _JSAMPARRAY input_data, _JSAMPARRAY output_data)
{
int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v;
JDIMENSION outcol, outcol_h; /* outcol_h == outcol*h_expand */
- JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
- JSAMPROW inptr, outptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
+ JDIMENSION output_cols = compptr->width_in_blocks * data_unit;
+ _JSAMPROW inptr, outptr;
JLONG outvalue;
h_expand = cinfo->max_h_samp_factor / compptr->h_samp_factor;
@@ -177,7 +183,7 @@ int_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
outvalue += (JLONG)(*inptr++);
}
}
- *outptr++ = (JSAMPLE)((outvalue + numpix2) / numpix);
+ *outptr++ = (_JSAMPLE)((outvalue + numpix2) / numpix);
}
inrow += v_expand;
}
@@ -192,14 +198,16 @@ int_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
METHODDEF(void)
fullsize_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
+ _JSAMPARRAY input_data, _JSAMPARRAY output_data)
{
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
+
/* Copy the data */
- jcopy_sample_rows(input_data, 0, output_data, 0, cinfo->max_v_samp_factor,
- cinfo->image_width);
+ _jcopy_sample_rows(input_data, 0, output_data, 0, cinfo->max_v_samp_factor,
+ cinfo->image_width);
/* Edge-expand */
expand_right_edge(output_data, cinfo->max_v_samp_factor, cinfo->image_width,
- compptr->width_in_blocks * DCTSIZE);
+ compptr->width_in_blocks * data_unit);
}
@@ -217,12 +225,13 @@ fullsize_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
METHODDEF(void)
h2v1_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
+ _JSAMPARRAY input_data, _JSAMPARRAY output_data)
{
int outrow;
JDIMENSION outcol;
- JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
- register JSAMPROW inptr, outptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
+ JDIMENSION output_cols = compptr->width_in_blocks * data_unit;
+ register _JSAMPROW inptr, outptr;
register int bias;
/* Expand input data enough to let all the output samples be generated
@@ -237,7 +246,7 @@ h2v1_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
inptr = input_data[outrow];
bias = 0; /* bias = 0,1,0,1,... for successive samples */
for (outcol = 0; outcol < output_cols; outcol++) {
- *outptr++ = (JSAMPLE)((inptr[0] + inptr[1] + bias) >> 1);
+ *outptr++ = (_JSAMPLE)((inptr[0] + inptr[1] + bias) >> 1);
bias ^= 1; /* 0=>1, 1=>0 */
inptr += 2;
}
@@ -253,12 +262,13 @@ h2v1_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
METHODDEF(void)
h2v2_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
+ _JSAMPARRAY input_data, _JSAMPARRAY output_data)
{
int inrow, outrow;
JDIMENSION outcol;
- JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
- register JSAMPROW inptr0, inptr1, outptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
+ JDIMENSION output_cols = compptr->width_in_blocks * data_unit;
+ register _JSAMPROW inptr0, inptr1, outptr;
register int bias;
/* Expand input data enough to let all the output samples be generated
@@ -275,8 +285,8 @@ h2v2_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
inptr1 = input_data[inrow + 1];
bias = 1; /* bias = 1,2,1,2,... for successive samples */
for (outcol = 0; outcol < output_cols; outcol++) {
- *outptr++ =
- (JSAMPLE)((inptr0[0] + inptr0[1] + inptr1[0] + inptr1[1] + bias) >> 2);
+ *outptr++ = (_JSAMPLE)
+ ((inptr0[0] + inptr0[1] + inptr1[0] + inptr1[1] + bias) >> 2);
bias ^= 3; /* 1=>2, 2=>1 */
inptr0 += 2; inptr1 += 2;
}
@@ -295,12 +305,13 @@ h2v2_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
METHODDEF(void)
h2v2_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
+ _JSAMPARRAY input_data, _JSAMPARRAY output_data)
{
int inrow, outrow;
JDIMENSION colctr;
- JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
- register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
+ JDIMENSION output_cols = compptr->width_in_blocks * data_unit;
+ register _JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr;
JLONG membersum, neighsum, memberscale, neighscale;
/* Expand input data enough to let all the output samples be generated
@@ -341,7 +352,7 @@ h2v2_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
neighsum += neighsum;
neighsum += above_ptr[0] + above_ptr[2] + below_ptr[0] + below_ptr[2];
membersum = membersum * memberscale + neighsum * neighscale;
- *outptr++ = (JSAMPLE)((membersum + 32768) >> 16);
+ *outptr++ = (_JSAMPLE)((membersum + 32768) >> 16);
inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2;
for (colctr = output_cols - 2; colctr > 0; colctr--) {
@@ -357,7 +368,7 @@ h2v2_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
/* form final output scaled up by 2^16 */
membersum = membersum * memberscale + neighsum * neighscale;
/* round, descale and output it */
- *outptr++ = (JSAMPLE)((membersum + 32768) >> 16);
+ *outptr++ = (_JSAMPLE)((membersum + 32768) >> 16);
inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2;
}
@@ -368,7 +379,7 @@ h2v2_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
neighsum += neighsum;
neighsum += above_ptr[-1] + above_ptr[1] + below_ptr[-1] + below_ptr[1];
membersum = membersum * memberscale + neighsum * neighscale;
- *outptr = (JSAMPLE)((membersum + 32768) >> 16);
+ *outptr = (_JSAMPLE)((membersum + 32768) >> 16);
inrow += 2;
}
@@ -383,12 +394,13 @@ h2v2_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
METHODDEF(void)
fullsize_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
+ _JSAMPARRAY input_data, _JSAMPARRAY output_data)
{
int outrow;
JDIMENSION colctr;
- JDIMENSION output_cols = compptr->width_in_blocks * DCTSIZE;
- register JSAMPROW inptr, above_ptr, below_ptr, outptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
+ JDIMENSION output_cols = compptr->width_in_blocks * data_unit;
+ register _JSAMPROW inptr, above_ptr, below_ptr, outptr;
JLONG membersum, neighsum, memberscale, neighscale;
int colsum, lastcolsum, nextcolsum;
@@ -420,7 +432,7 @@ fullsize_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
nextcolsum = above_ptr[0] + below_ptr[0] + inptr[0];
neighsum = colsum + (colsum - membersum) + nextcolsum;
membersum = membersum * memberscale + neighsum * neighscale;
- *outptr++ = (JSAMPLE)((membersum + 32768) >> 16);
+ *outptr++ = (_JSAMPLE)((membersum + 32768) >> 16);
lastcolsum = colsum; colsum = nextcolsum;
for (colctr = output_cols - 2; colctr > 0; colctr--) {
@@ -429,7 +441,7 @@ fullsize_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
nextcolsum = above_ptr[0] + below_ptr[0] + inptr[0];
neighsum = lastcolsum + (colsum - membersum) + nextcolsum;
membersum = membersum * memberscale + neighsum * neighscale;
- *outptr++ = (JSAMPLE)((membersum + 32768) >> 16);
+ *outptr++ = (_JSAMPLE)((membersum + 32768) >> 16);
lastcolsum = colsum; colsum = nextcolsum;
}
@@ -437,7 +449,7 @@ fullsize_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
membersum = *inptr;
neighsum = lastcolsum + (colsum - membersum) + colsum;
membersum = membersum * memberscale + neighsum * neighscale;
- *outptr = (JSAMPLE)((membersum + 32768) >> 16);
+ *outptr = (_JSAMPLE)((membersum + 32768) >> 16);
}
}
@@ -451,19 +463,22 @@ fullsize_smooth_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
*/
GLOBAL(void)
-jinit_downsampler(j_compress_ptr cinfo)
+_jinit_downsampler(j_compress_ptr cinfo)
{
my_downsample_ptr downsample;
int ci;
jpeg_component_info *compptr;
boolean smoothok = TRUE;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
downsample = (my_downsample_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_downsampler));
cinfo->downsample = (struct jpeg_downsampler *)downsample;
downsample->pub.start_pass = start_pass_downsample;
- downsample->pub.downsample = sep_downsample;
+ downsample->pub._downsample = sep_downsample;
downsample->pub.need_context_rows = FALSE;
if (cinfo->CCIR601_sampling)
@@ -484,15 +499,17 @@ jinit_downsampler(j_compress_ptr cinfo)
} else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor &&
compptr->v_samp_factor == cinfo->max_v_samp_factor) {
smoothok = FALSE;
+#ifdef WITH_SIMD
if (jsimd_can_h2v1_downsample())
downsample->methods[ci] = jsimd_h2v1_downsample;
else
+#endif
downsample->methods[ci] = h2v1_downsample;
} else if (compptr->h_samp_factor * 2 == cinfo->max_h_samp_factor &&
compptr->v_samp_factor * 2 == cinfo->max_v_samp_factor) {
#ifdef INPUT_SMOOTHING_SUPPORTED
if (cinfo->smoothing_factor) {
-#if defined(__mips__)
+#if defined(WITH_SIMD) && defined(__mips__)
if (jsimd_can_h2v2_smooth_downsample())
downsample->methods[ci] = jsimd_h2v2_smooth_downsample;
else
@@ -502,9 +519,11 @@ jinit_downsampler(j_compress_ptr cinfo)
} else
#endif
{
+#ifdef WITH_SIMD
if (jsimd_can_h2v2_downsample())
downsample->methods[ci] = jsimd_h2v2_downsample;
else
+#endif
downsample->methods[ci] = h2v2_downsample;
}
} else if ((cinfo->max_h_samp_factor % compptr->h_samp_factor) == 0 &&
@@ -520,3 +539,5 @@ jinit_downsampler(j_compress_ptr cinfo)
TRACEMS(cinfo, 0, JTRC_SMOOTH_NOTIMPL);
#endif
}
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED) */
diff --git a/src/3rdparty/libjpeg/src/jctrans.c b/src/3rdparty/libjpeg/src/jctrans.c
index e121028ec7..ae52e3989e 100644
--- a/src/3rdparty/libjpeg/src/jctrans.c
+++ b/src/3rdparty/libjpeg/src/jctrans.c
@@ -17,7 +17,7 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
/* Forward declarations */
@@ -42,6 +42,9 @@ LOCAL(void) transencode_coef_controller(j_compress_ptr cinfo,
GLOBAL(void)
jpeg_write_coefficients(j_compress_ptr cinfo, jvirt_barray_ptr *coef_arrays)
{
+ if (cinfo->master->lossless)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+
if (cinfo->global_state != CSTATE_START)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
/* Mark all tables to be written */
@@ -72,6 +75,9 @@ jpeg_copy_critical_parameters(j_decompress_ptr srcinfo, j_compress_ptr dstinfo)
JQUANT_TBL *c_quant, *slot_quant;
int tblno, ci, coefi;
+ if (srcinfo->master->lossless)
+ ERREXIT(dstinfo, JERR_NOTIMPL);
+
/* Safety check to ensure start_compress not called yet. */
if (dstinfo->global_state != CSTATE_START)
ERREXIT1(dstinfo, JERR_BAD_STATE, dstinfo->global_state);
@@ -364,6 +370,13 @@ compress_output(j_compress_ptr cinfo, JSAMPIMAGE input_buf)
}
+METHODDEF(boolean)
+compress_output_12(j_compress_ptr cinfo, J12SAMPIMAGE input_buf)
+{
+ return compress_output(cinfo, (JSAMPIMAGE)input_buf);
+}
+
+
/*
* Initialize coefficient buffer controller.
*
@@ -386,6 +399,7 @@ transencode_coef_controller(j_compress_ptr cinfo,
cinfo->coef = (struct jpeg_c_coef_controller *)coef;
coef->pub.start_pass = start_pass_coef;
coef->pub.compress_data = compress_output;
+ coef->pub.compress_data_12 = compress_output_12;
/* Save pointer to virtual arrays */
coef->whole_image = coef_arrays;
diff --git a/src/3rdparty/libjpeg/src/jdapimin.c b/src/3rdparty/libjpeg/src/jdapimin.c
index 30126a048d..30d92841a8 100644
--- a/src/3rdparty/libjpeg/src/jdapimin.c
+++ b/src/3rdparty/libjpeg/src/jdapimin.c
@@ -3,8 +3,10 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1998, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2016, 2022, D. R. Commander.
+ * Copyright (C) 2016, 2022, 2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -82,6 +84,8 @@ jpeg_CreateDecompress(j_decompress_ptr cinfo, int version, size_t structsize)
/* And initialize the overall input controller. */
jinit_input_controller(cinfo);
+ cinfo->data_precision = BITS_IN_JSAMPLE;
+
/* OK, I'm ready */
cinfo->global_state = DSTATE_START;
@@ -156,13 +160,19 @@ default_decompress_parms(j_decompress_ptr cinfo)
int cid1 = cinfo->comp_info[1].component_id;
int cid2 = cinfo->comp_info[2].component_id;
- if (cid0 == 1 && cid1 == 2 && cid2 == 3)
- cinfo->jpeg_color_space = JCS_YCbCr; /* assume JFIF w/out marker */
- else if (cid0 == 82 && cid1 == 71 && cid2 == 66)
+ if (cid0 == 1 && cid1 == 2 && cid2 == 3) {
+ if (cinfo->master->lossless)
+ cinfo->jpeg_color_space = JCS_RGB; /* assume RGB w/out marker */
+ else
+ cinfo->jpeg_color_space = JCS_YCbCr; /* assume JFIF w/out marker */
+ } else if (cid0 == 82 && cid1 == 71 && cid2 == 66)
cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */
else {
TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2);
- cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
+ if (cinfo->master->lossless)
+ cinfo->jpeg_color_space = JCS_RGB; /* assume it's RGB */
+ else
+ cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
}
}
/* Always guess RGB is proper output colorspace. */
diff --git a/src/3rdparty/libjpeg/src/jdapistd.c b/src/3rdparty/libjpeg/src/jdapistd.c
index 02cd0cb93a..1f44927236 100644
--- a/src/3rdparty/libjpeg/src/jdapistd.c
+++ b/src/3rdparty/libjpeg/src/jdapistd.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2015-2020, 2022, D. R. Commander.
+ * Copyright (C) 2010, 2015-2020, 2022-2023, D. R. Commander.
* Copyright (C) 2015, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
@@ -19,13 +19,20 @@
*/
#include "jinclude.h"
+#if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)
#include "jdmainct.h"
#include "jdcoefct.h"
+#else
+#define JPEG_INTERNALS
+#include "jpeglib.h"
+#endif
#include "jdmaster.h"
#include "jdmerge.h"
#include "jdsample.h"
#include "jmemsys.h"
+#if BITS_IN_JSAMPLE == 8
+
/* Forward declarations */
LOCAL(boolean) output_pass_setup(j_decompress_ptr cinfo);
@@ -121,8 +128,20 @@ output_pass_setup(j_decompress_ptr cinfo)
}
/* Process some data */
last_scanline = cinfo->output_scanline;
- (*cinfo->main->process_data) (cinfo, (JSAMPARRAY)NULL,
- &cinfo->output_scanline, (JDIMENSION)0);
+#ifdef D_LOSSLESS_SUPPORTED
+ if (cinfo->data_precision == 16)
+ (*cinfo->main->process_data_16) (cinfo, (J16SAMPARRAY)NULL,
+ &cinfo->output_scanline,
+ (JDIMENSION)0);
+ else
+#endif
+ if (cinfo->data_precision == 12)
+ (*cinfo->main->process_data_12) (cinfo, (J12SAMPARRAY)NULL,
+ &cinfo->output_scanline,
+ (JDIMENSION)0);
+ else
+ (*cinfo->main->process_data) (cinfo, (JSAMPARRAY)NULL,
+ &cinfo->output_scanline, (JDIMENSION)0);
if (cinfo->output_scanline == last_scanline)
return FALSE; /* No progress made, must suspend */
}
@@ -135,25 +154,29 @@ output_pass_setup(j_decompress_ptr cinfo)
#endif /* QUANT_2PASS_SUPPORTED */
}
/* Ready for application to drive output pass through
- * jpeg_read_scanlines or jpeg_read_raw_data.
+ * _jpeg_read_scanlines or _jpeg_read_raw_data.
*/
cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING;
return TRUE;
}
+#endif /* BITS_IN_JSAMPLE == 8 */
+
+
+#if BITS_IN_JSAMPLE != 16
/*
* Enable partial scanline decompression
*
* Must be called after jpeg_start_decompress() and before any calls to
- * jpeg_read_scanlines() or jpeg_skip_scanlines().
+ * _jpeg_read_scanlines() or _jpeg_skip_scanlines().
*
* Refer to libjpeg.txt for more information.
*/
GLOBAL(void)
-jpeg_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset,
- JDIMENSION *width)
+_jpeg_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset,
+ JDIMENSION *width)
{
int ci, align, orig_downsampled_width;
JDIMENSION input_xoffset;
@@ -163,6 +186,12 @@ jpeg_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset,
my_master_ptr master = (my_master_ptr)cinfo->master;
#endif
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+ if (cinfo->master->lossless)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+
if ((cinfo->global_state != DSTATE_SCANNING &&
cinfo->global_state != DSTATE_BUFIMAGE) || cinfo->output_scanline != 0)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
@@ -236,9 +265,11 @@ jpeg_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset,
/* Set downsampled_width to the new output width. */
orig_downsampled_width = compptr->downsampled_width;
compptr->downsampled_width =
- (JDIMENSION)jdiv_round_up((long)(cinfo->output_width *
- compptr->h_samp_factor),
- (long)cinfo->max_h_samp_factor);
+ (JDIMENSION)jdiv_round_up((long)cinfo->output_width *
+ (long)(compptr->h_samp_factor *
+ compptr->_DCT_scaled_size),
+ (long)(cinfo->max_h_samp_factor *
+ cinfo->_min_DCT_scaled_size));
if (compptr->downsampled_width < 2 && orig_downsampled_width >= 2)
reinit_upsampler = TRUE;
@@ -254,11 +285,13 @@ jpeg_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset,
if (reinit_upsampler) {
cinfo->master->jinit_upsampler_no_alloc = TRUE;
- jinit_upsampler(cinfo);
+ _jinit_upsampler(cinfo);
cinfo->master->jinit_upsampler_no_alloc = FALSE;
}
}
+#endif /* BITS_IN_JSAMPLE != 16 */
+
/*
* Read some scanlines of data from the JPEG decompressor.
@@ -268,17 +301,21 @@ jpeg_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset,
* including bottom of image, data source suspension, and operating
* modes that emit multiple scanlines at a time.
*
- * Note: we warn about excess calls to jpeg_read_scanlines() since
+ * Note: we warn about excess calls to _jpeg_read_scanlines() since
* this likely signals an application programmer error. However,
* an oversize buffer (max_lines > scanlines remaining) is not an error.
*/
GLOBAL(JDIMENSION)
-jpeg_read_scanlines(j_decompress_ptr cinfo, JSAMPARRAY scanlines,
- JDIMENSION max_lines)
+_jpeg_read_scanlines(j_decompress_ptr cinfo, _JSAMPARRAY scanlines,
+ JDIMENSION max_lines)
{
+#if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)
JDIMENSION row_ctr;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
if (cinfo->global_state != DSTATE_SCANNING)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
if (cinfo->output_scanline >= cinfo->output_height) {
@@ -295,30 +332,36 @@ jpeg_read_scanlines(j_decompress_ptr cinfo, JSAMPARRAY scanlines,
/* Process some data */
row_ctr = 0;
- (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, max_lines);
+ (*cinfo->main->_process_data) (cinfo, scanlines, &row_ctr, max_lines);
cinfo->output_scanline += row_ctr;
return row_ctr;
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ return 0;
+#endif
}
-/* Dummy color convert function used by jpeg_skip_scanlines() */
+#if BITS_IN_JSAMPLE != 16
+
+/* Dummy color convert function used by _jpeg_skip_scanlines() */
LOCAL(void)
-noop_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+noop_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
}
-/* Dummy quantize function used by jpeg_skip_scanlines() */
+/* Dummy quantize function used by _jpeg_skip_scanlines() */
LOCAL(void)
-noop_quantize(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
+noop_quantize(j_decompress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPARRAY output_buf, int num_rows)
{
}
/*
- * In some cases, it is best to call jpeg_read_scanlines() and discard the
+ * In some cases, it is best to call _jpeg_read_scanlines() and discard the
* output, rather than skipping the scanlines, because this allows us to
* maintain the internal state of the context-based upsampler. In these cases,
* we set up and tear down a dummy color converter in order to avoid valgrind
@@ -332,27 +375,27 @@ read_and_discard_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
#ifdef UPSAMPLE_MERGING_SUPPORTED
my_master_ptr master = (my_master_ptr)cinfo->master;
#endif
- JSAMPLE dummy_sample[1] = { 0 };
- JSAMPROW dummy_row = dummy_sample;
- JSAMPARRAY scanlines = NULL;
- void (*color_convert) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
+ _JSAMPLE dummy_sample[1] = { 0 };
+ _JSAMPROW dummy_row = dummy_sample;
+ _JSAMPARRAY scanlines = NULL;
+ void (*color_convert) (j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf,
int num_rows) = NULL;
- void (*color_quantize) (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows) = NULL;
+ void (*color_quantize) (j_decompress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPARRAY output_buf, int num_rows) = NULL;
- if (cinfo->cconvert && cinfo->cconvert->color_convert) {
- color_convert = cinfo->cconvert->color_convert;
- cinfo->cconvert->color_convert = noop_convert;
+ if (cinfo->cconvert && cinfo->cconvert->_color_convert) {
+ color_convert = cinfo->cconvert->_color_convert;
+ cinfo->cconvert->_color_convert = noop_convert;
/* This just prevents UBSan from complaining about adding 0 to a NULL
* pointer. The pointer isn't actually used.
*/
scanlines = &dummy_row;
}
- if (cinfo->cquantize && cinfo->cquantize->color_quantize) {
- color_quantize = cinfo->cquantize->color_quantize;
- cinfo->cquantize->color_quantize = noop_quantize;
+ if (cinfo->cquantize && cinfo->cquantize->_color_quantize) {
+ color_quantize = cinfo->cquantize->_color_quantize;
+ cinfo->cquantize->_color_quantize = noop_quantize;
}
#ifdef UPSAMPLE_MERGING_SUPPORTED
@@ -363,19 +406,19 @@ read_and_discard_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
#endif
for (n = 0; n < num_lines; n++)
- jpeg_read_scanlines(cinfo, scanlines, 1);
+ _jpeg_read_scanlines(cinfo, scanlines, 1);
if (color_convert)
- cinfo->cconvert->color_convert = color_convert;
+ cinfo->cconvert->_color_convert = color_convert;
if (color_quantize)
- cinfo->cquantize->color_quantize = color_quantize;
+ cinfo->cquantize->_color_quantize = color_quantize;
}
/*
- * Called by jpeg_skip_scanlines(). This partially skips a decompress block by
- * incrementing the rowgroup counter.
+ * Called by _jpeg_skip_scanlines(). This partially skips a decompress block
+ * by incrementing the rowgroup counter.
*/
LOCAL(void)
@@ -414,7 +457,7 @@ increment_simple_rowgroup_ctr(j_decompress_ptr cinfo, JDIMENSION rows)
*/
GLOBAL(JDIMENSION)
-jpeg_skip_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
+_jpeg_skip_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
{
my_main_ptr main_ptr = (my_main_ptr)cinfo->main;
my_coef_ptr coef = (my_coef_ptr)cinfo->coef;
@@ -425,6 +468,12 @@ jpeg_skip_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
JDIMENSION lines_per_iMCU_row, lines_left_in_iMCU_row, lines_after_iMCU_row;
JDIMENSION lines_to_skip, lines_to_read;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+ if (cinfo->master->lossless)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+
/* Two-pass color quantization is not supported. */
if (cinfo->quantize_colors && cinfo->two_pass_quantize)
ERREXIT(cinfo, JERR_NOTIMPL);
@@ -597,11 +646,17 @@ jpeg_skip_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines)
*/
GLOBAL(JDIMENSION)
-jpeg_read_raw_data(j_decompress_ptr cinfo, JSAMPIMAGE data,
- JDIMENSION max_lines)
+_jpeg_read_raw_data(j_decompress_ptr cinfo, _JSAMPIMAGE data,
+ JDIMENSION max_lines)
{
JDIMENSION lines_per_iMCU_row;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+ if (cinfo->master->lossless)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+
if (cinfo->global_state != DSTATE_RAW_OK)
ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
if (cinfo->output_scanline >= cinfo->output_height) {
@@ -622,7 +677,7 @@ jpeg_read_raw_data(j_decompress_ptr cinfo, JSAMPIMAGE data,
ERREXIT(cinfo, JERR_BUFFER_SIZE);
/* Decompress directly into user's buffer. */
- if (!(*cinfo->coef->decompress_data) (cinfo, data))
+ if (!(*cinfo->coef->_decompress_data) (cinfo, data))
return 0; /* suspension forced, can do nothing more */
/* OK, we processed one iMCU row. */
@@ -630,6 +685,10 @@ jpeg_read_raw_data(j_decompress_ptr cinfo, JSAMPIMAGE data,
return lines_per_iMCU_row;
}
+#endif /* BITS_IN_JSAMPLE != 16 */
+
+
+#if BITS_IN_JSAMPLE == 8
/* Additional entry points for buffered-image mode. */
@@ -687,3 +746,5 @@ jpeg_finish_output(j_decompress_ptr cinfo)
}
#endif /* D_MULTISCAN_FILES_SUPPORTED */
+
+#endif /* BITS_IN_JSAMPLE == 8 */
diff --git a/src/3rdparty/libjpeg/src/jdatadst.c b/src/3rdparty/libjpeg/src/jdatadst.c
index 6b4fed2339..529f93b490 100644
--- a/src/3rdparty/libjpeg/src/jdatadst.c
+++ b/src/3rdparty/libjpeg/src/jdatadst.c
@@ -38,7 +38,6 @@ typedef my_destination_mgr *my_dest_ptr;
#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
/* Expanded data destination object for memory output */
typedef struct {
@@ -52,7 +51,6 @@ typedef struct {
} my_mem_destination_mgr;
typedef my_mem_destination_mgr *my_mem_dest_ptr;
-#endif
/*
@@ -74,13 +72,11 @@ init_destination(j_compress_ptr cinfo)
dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
}
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
METHODDEF(void)
init_mem_destination(j_compress_ptr cinfo)
{
/* no work necessary here */
}
-#endif
/*
@@ -121,7 +117,6 @@ empty_output_buffer(j_compress_ptr cinfo)
return TRUE;
}
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
METHODDEF(boolean)
empty_mem_output_buffer(j_compress_ptr cinfo)
{
@@ -150,7 +145,6 @@ empty_mem_output_buffer(j_compress_ptr cinfo)
return TRUE;
}
-#endif
/*
@@ -179,7 +173,6 @@ term_destination(j_compress_ptr cinfo)
ERREXIT(cinfo, JERR_FILE_WRITE);
}
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
METHODDEF(void)
term_mem_destination(j_compress_ptr cinfo)
{
@@ -188,7 +181,6 @@ term_mem_destination(j_compress_ptr cinfo)
*dest->outbuffer = dest->buffer;
*dest->outsize = (unsigned long)(dest->bufsize - dest->pub.free_in_buffer);
}
-#endif
/*
@@ -227,7 +219,6 @@ jpeg_stdio_dest(j_compress_ptr cinfo, FILE *outfile)
}
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
/*
* Prepare for output to a memory buffer.
* The caller may supply an own initial buffer with appropriate size.
@@ -284,4 +275,3 @@ jpeg_mem_dest(j_compress_ptr cinfo, unsigned char **outbuffer,
dest->pub.next_output_byte = dest->buffer = *outbuffer;
dest->pub.free_in_buffer = dest->bufsize = *outsize;
}
-#endif
diff --git a/src/3rdparty/libjpeg/src/jdatasrc.c b/src/3rdparty/libjpeg/src/jdatasrc.c
index e36a30d894..dc135f43a4 100644
--- a/src/3rdparty/libjpeg/src/jdatasrc.c
+++ b/src/3rdparty/libjpeg/src/jdatasrc.c
@@ -56,13 +56,11 @@ init_source(j_decompress_ptr cinfo)
src->start_of_file = TRUE;
}
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
METHODDEF(void)
init_mem_source(j_decompress_ptr cinfo)
{
/* no work necessary here */
}
-#endif
/*
@@ -123,7 +121,6 @@ fill_input_buffer(j_decompress_ptr cinfo)
return TRUE;
}
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
METHODDEF(boolean)
fill_mem_input_buffer(j_decompress_ptr cinfo)
{
@@ -144,7 +141,6 @@ fill_mem_input_buffer(j_decompress_ptr cinfo)
return TRUE;
}
-#endif
/*
@@ -253,7 +249,6 @@ jpeg_stdio_src(j_decompress_ptr cinfo, FILE *infile)
}
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
/*
* Prepare for input from a supplied memory buffer.
* The buffer must contain the whole JPEG data.
@@ -292,4 +287,3 @@ jpeg_mem_src(j_decompress_ptr cinfo, const unsigned char *inbuffer,
src->bytes_in_buffer = (size_t)insize;
src->next_input_byte = (const JOCTET *)inbuffer;
}
-#endif
diff --git a/src/3rdparty/libjpeg/src/jdcoefct.c b/src/3rdparty/libjpeg/src/jdcoefct.c
index 88e10c08cb..40ce27259b 100644
--- a/src/3rdparty/libjpeg/src/jdcoefct.c
+++ b/src/3rdparty/libjpeg/src/jdcoefct.c
@@ -5,13 +5,13 @@
* Copyright (C) 1994-1997, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2010, 2015-2016, 2019-2020, 2022, D. R. Commander.
+ * Copyright (C) 2010, 2015-2016, 2019-2020, 2022-2023, D. R. Commander.
* Copyright (C) 2015, 2020, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
* This file contains the coefficient buffer controller for decompression.
- * This controller is the top level of the JPEG decompressor proper.
+ * This controller is the top level of the lossy JPEG decompressor proper.
* The coefficient buffer lies between entropy decoding and inverse-DCT steps.
*
* In buffered-image mode, this controller is the interface between
@@ -21,19 +21,20 @@
#include "jinclude.h"
#include "jdcoefct.h"
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
+#include "jsamplecomp.h"
/* Forward declarations */
METHODDEF(int) decompress_onepass(j_decompress_ptr cinfo,
- JSAMPIMAGE output_buf);
+ _JSAMPIMAGE output_buf);
#ifdef D_MULTISCAN_FILES_SUPPORTED
-METHODDEF(int) decompress_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf);
+METHODDEF(int) decompress_data(j_decompress_ptr cinfo, _JSAMPIMAGE output_buf);
#endif
#ifdef BLOCK_SMOOTHING_SUPPORTED
LOCAL(boolean) smoothing_ok(j_decompress_ptr cinfo);
METHODDEF(int) decompress_smooth_data(j_decompress_ptr cinfo,
- JSAMPIMAGE output_buf);
+ _JSAMPIMAGE output_buf);
#endif
@@ -62,9 +63,9 @@ start_output_pass(j_decompress_ptr cinfo)
/* If multipass, check to see whether to use block smoothing on this pass */
if (coef->pub.coef_arrays != NULL) {
if (cinfo->do_block_smoothing && smoothing_ok(cinfo))
- coef->pub.decompress_data = decompress_smooth_data;
+ coef->pub._decompress_data = decompress_smooth_data;
else
- coef->pub.decompress_data = decompress_data;
+ coef->pub._decompress_data = decompress_data;
}
#endif
cinfo->output_iMCU_row = 0;
@@ -82,17 +83,17 @@ start_output_pass(j_decompress_ptr cinfo)
*/
METHODDEF(int)
-decompress_onepass(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
+decompress_onepass(j_decompress_ptr cinfo, _JSAMPIMAGE output_buf)
{
my_coef_ptr coef = (my_coef_ptr)cinfo->coef;
JDIMENSION MCU_col_num; /* index of current MCU within row */
JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
int blkn, ci, xindex, yindex, yoffset, useful_width;
- JSAMPARRAY output_ptr;
+ _JSAMPARRAY output_ptr;
JDIMENSION start_col, output_col;
jpeg_component_info *compptr;
- inverse_DCT_method_ptr inverse_DCT;
+ _inverse_DCT_method_ptr inverse_DCT;
/* Loop to process as much as one whole iMCU row */
for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
@@ -129,7 +130,7 @@ decompress_onepass(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
blkn += compptr->MCU_blocks;
continue;
}
- inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index];
+ inverse_DCT = cinfo->idct->_inverse_DCT[compptr->component_index];
useful_width = (MCU_col_num < last_MCU_col) ?
compptr->MCU_width : compptr->last_col_width;
output_ptr = output_buf[compptr->component_index] +
@@ -262,7 +263,7 @@ consume_data(j_decompress_ptr cinfo)
*/
METHODDEF(int)
-decompress_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
+decompress_data(j_decompress_ptr cinfo, _JSAMPIMAGE output_buf)
{
my_coef_ptr coef = (my_coef_ptr)cinfo->coef;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
@@ -270,10 +271,10 @@ decompress_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
int ci, block_row, block_rows;
JBLOCKARRAY buffer;
JBLOCKROW buffer_ptr;
- JSAMPARRAY output_ptr;
+ _JSAMPARRAY output_ptr;
JDIMENSION output_col;
jpeg_component_info *compptr;
- inverse_DCT_method_ptr inverse_DCT;
+ _inverse_DCT_method_ptr inverse_DCT;
/* Force some input to be done if we are getting ahead of the input. */
while (cinfo->input_scan_number < cinfo->output_scan_number ||
@@ -302,7 +303,7 @@ decompress_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
block_rows = (int)(compptr->height_in_blocks % compptr->v_samp_factor);
if (block_rows == 0) block_rows = compptr->v_samp_factor;
}
- inverse_DCT = cinfo->idct->inverse_DCT[ci];
+ inverse_DCT = cinfo->idct->_inverse_DCT[ci];
output_ptr = output_buf[ci];
/* Loop over all DCT blocks to be processed. */
for (block_row = 0; block_row < block_rows; block_row++) {
@@ -425,19 +426,20 @@ smoothing_ok(j_decompress_ptr cinfo)
*/
METHODDEF(int)
-decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
+decompress_smooth_data(j_decompress_ptr cinfo, _JSAMPIMAGE output_buf)
{
my_coef_ptr coef = (my_coef_ptr)cinfo->coef;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
JDIMENSION block_num, last_block_column;
- int ci, block_row, block_rows, access_rows;
+ int ci, block_row, block_rows, access_rows, image_block_row,
+ image_block_rows;
JBLOCKARRAY buffer;
JBLOCKROW buffer_ptr, prev_prev_block_row, prev_block_row;
JBLOCKROW next_block_row, next_next_block_row;
- JSAMPARRAY output_ptr;
+ _JSAMPARRAY output_ptr;
JDIMENSION output_col;
jpeg_component_info *compptr;
- inverse_DCT_method_ptr inverse_DCT;
+ _inverse_DCT_method_ptr inverse_DCT;
boolean change_dc;
JCOEF *workspace;
int *coef_bits;
@@ -496,6 +498,7 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
(JDIMENSION)access_rows, FALSE);
buffer += 2 * compptr->v_samp_factor; /* point to current iMCU row */
} else if (cinfo->output_iMCU_row > 0) {
+ access_rows += compptr->v_samp_factor; /* prior iMCU row too */
buffer = (*cinfo->mem->access_virt_barray)
((j_common_ptr)cinfo, coef->whole_image[ci],
(cinfo->output_iMCU_row - 1) * compptr->v_samp_factor,
@@ -535,32 +538,33 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
Q21 = quanttbl->quantval[Q21_POS];
Q30 = quanttbl->quantval[Q30_POS];
}
- inverse_DCT = cinfo->idct->inverse_DCT[ci];
+ inverse_DCT = cinfo->idct->_inverse_DCT[ci];
output_ptr = output_buf[ci];
/* Loop over all DCT blocks to be processed. */
+ image_block_rows = block_rows * cinfo->total_iMCU_rows;
for (block_row = 0; block_row < block_rows; block_row++) {
+ image_block_row = cinfo->output_iMCU_row * block_rows + block_row;
buffer_ptr = buffer[block_row] + cinfo->master->first_MCU_col[ci];
- if (block_row > 0 || cinfo->output_iMCU_row > 0)
+ if (image_block_row > 0)
prev_block_row =
buffer[block_row - 1] + cinfo->master->first_MCU_col[ci];
else
prev_block_row = buffer_ptr;
- if (block_row > 1 || cinfo->output_iMCU_row > 1)
+ if (image_block_row > 1)
prev_prev_block_row =
buffer[block_row - 2] + cinfo->master->first_MCU_col[ci];
else
prev_prev_block_row = prev_block_row;
- if (block_row < block_rows - 1 || cinfo->output_iMCU_row < last_iMCU_row)
+ if (image_block_row < image_block_rows - 1)
next_block_row =
buffer[block_row + 1] + cinfo->master->first_MCU_col[ci];
else
next_block_row = buffer_ptr;
- if (block_row < block_rows - 2 ||
- cinfo->output_iMCU_row + 1 < last_iMCU_row)
+ if (image_block_row < image_block_rows - 2)
next_next_block_row =
buffer[block_row + 2] + cinfo->master->first_MCU_col[ci];
else
@@ -583,11 +587,11 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
/* Update DC values */
if (block_num == cinfo->master->first_MCU_col[ci] &&
block_num < last_block_column) {
- DC04 = (int)prev_prev_block_row[1][0];
- DC09 = (int)prev_block_row[1][0];
- DC14 = (int)buffer_ptr[1][0];
- DC19 = (int)next_block_row[1][0];
- DC24 = (int)next_next_block_row[1][0];
+ DC04 = DC05 = (int)prev_prev_block_row[1][0];
+ DC09 = DC10 = (int)prev_block_row[1][0];
+ DC14 = DC15 = (int)buffer_ptr[1][0];
+ DC19 = DC20 = (int)next_block_row[1][0];
+ DC24 = DC25 = (int)next_next_block_row[1][0];
}
if (block_num + 1 < last_block_column) {
DC05 = (int)prev_prev_block_row[2][0];
@@ -810,10 +814,13 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
*/
GLOBAL(void)
-jinit_d_coef_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
+_jinit_d_coef_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
{
my_coef_ptr coef;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
coef = (my_coef_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_coef_controller));
@@ -850,7 +857,7 @@ jinit_d_coef_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
(JDIMENSION)access_rows);
}
coef->pub.consume_data = consume_data;
- coef->pub.decompress_data = decompress_data;
+ coef->pub._decompress_data = decompress_data;
coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
@@ -867,7 +874,7 @@ jinit_d_coef_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
coef->MCU_buffer[i] = buffer + i;
}
coef->pub.consume_data = dummy_consume_data;
- coef->pub.decompress_data = decompress_onepass;
+ coef->pub._decompress_data = decompress_onepass;
coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */
}
diff --git a/src/3rdparty/libjpeg/src/jdcoefct.h b/src/3rdparty/libjpeg/src/jdcoefct.h
index 9a0e780663..bbe9e97051 100644
--- a/src/3rdparty/libjpeg/src/jdcoefct.h
+++ b/src/3rdparty/libjpeg/src/jdcoefct.h
@@ -6,6 +6,7 @@
* libjpeg-turbo Modifications:
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2020, Google, Inc.
+ * Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*/
@@ -14,6 +15,8 @@
#include "jpeglib.h"
+#if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)
+
/* Block smoothing is only applicable for progressive JPEG, so: */
#ifndef D_PROGRESSIVE_SUPPORTED
#undef BLOCK_SMOOTHING_SUPPORTED
@@ -81,3 +84,5 @@ start_iMCU_row(j_decompress_ptr cinfo)
coef->MCU_ctr = 0;
coef->MCU_vert_offset = 0;
}
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */
diff --git a/src/3rdparty/libjpeg/src/jdcol565.c b/src/3rdparty/libjpeg/src/jdcol565.c
index 53c7bd9187..2172d98fda 100644
--- a/src/3rdparty/libjpeg/src/jdcol565.c
+++ b/src/3rdparty/libjpeg/src/jdcol565.c
@@ -5,7 +5,7 @@
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modifications:
* Copyright (C) 2013, Linaro Limited.
- * Copyright (C) 2014-2015, D. R. Commander.
+ * Copyright (C) 2014-2015, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -17,18 +17,19 @@
INLINE
LOCAL(void)
-ycc_rgb565_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
+ycc_rgb565_convert_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf,
int num_rows)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
register int y, cb, cr;
- register JSAMPROW outptr;
- register JSAMPROW inptr0, inptr1, inptr2;
+ register _JSAMPROW outptr;
+ register _JSAMPROW inptr0, inptr1, inptr2;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
/* copy these pointers into registers if possible */
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
register int *Crrtab = cconvert->Cr_r_tab;
register int *Cbbtab = cconvert->Cb_b_tab;
register JLONG *Crgtab = cconvert->Cr_g_tab;
@@ -91,23 +92,27 @@ ycc_rgb565_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
*(INT16 *)outptr = (INT16)rgb;
}
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
INLINE
LOCAL(void)
-ycc_rgb565D_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
+ycc_rgb565D_convert_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf,
int num_rows)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
register int y, cb, cr;
- register JSAMPROW outptr;
- register JSAMPROW inptr0, inptr1, inptr2;
+ register _JSAMPROW outptr;
+ register _JSAMPROW inptr0, inptr1, inptr2;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
/* copy these pointers into registers if possible */
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
register int *Crrtab = cconvert->Cr_r_tab;
register int *Cbbtab = cconvert->Cb_b_tab;
register JLONG *Crgtab = cconvert->Cr_g_tab;
@@ -177,17 +182,20 @@ ycc_rgb565D_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
*(INT16 *)outptr = (INT16)rgb;
}
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
INLINE
LOCAL(void)
-rgb_rgb565_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
+rgb_rgb565_convert_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf,
int num_rows)
{
- register JSAMPROW outptr;
- register JSAMPROW inptr0, inptr1, inptr2;
+ register _JSAMPROW outptr;
+ register _JSAMPROW inptr0, inptr1, inptr2;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
SHIFT_TEMPS
@@ -237,14 +245,14 @@ rgb_rgb565_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
INLINE
LOCAL(void)
-rgb_rgb565D_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
+rgb_rgb565D_convert_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf,
int num_rows)
{
- register JSAMPROW outptr;
- register JSAMPROW inptr0, inptr1, inptr2;
+ register _JSAMPROW outptr;
+ register _JSAMPROW inptr0, inptr1, inptr2;
register JDIMENSION col;
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
JDIMENSION num_cols = cinfo->output_width;
JLONG d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
SHIFT_TEMPS
@@ -296,11 +304,11 @@ rgb_rgb565D_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
INLINE
LOCAL(void)
-gray_rgb565_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
+gray_rgb565_convert_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf,
int num_rows)
{
- register JSAMPROW inptr, outptr;
+ register _JSAMPROW inptr, outptr;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
@@ -336,13 +344,13 @@ gray_rgb565_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
INLINE
LOCAL(void)
-gray_rgb565D_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
+gray_rgb565D_convert_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf,
int num_rows)
{
- register JSAMPROW inptr, outptr;
+ register _JSAMPROW inptr, outptr;
register JDIMENSION col;
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
JDIMENSION num_cols = cinfo->output_width;
JLONG d0 = dither_matrix[cinfo->output_scanline & DITHER_MASK];
diff --git a/src/3rdparty/libjpeg/src/jdcolext.c b/src/3rdparty/libjpeg/src/jdcolext.c
index fc7e7b8f00..f22e29d722 100644
--- a/src/3rdparty/libjpeg/src/jdcolext.c
+++ b/src/3rdparty/libjpeg/src/jdcolext.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2009, 2011, 2015, 2023, D. R. Commander.
+ * Copyright (C) 2009, 2011, 2015, 2022-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -28,18 +28,19 @@
INLINE
LOCAL(void)
-ycc_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
+ycc_rgb_convert_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf,
int num_rows)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
register int y, cb, cr;
- register JSAMPROW outptr;
- register JSAMPROW inptr0, inptr1, inptr2;
+ register _JSAMPROW outptr;
+ register _JSAMPROW inptr0, inptr1, inptr2;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
/* copy these pointers into registers if possible */
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
register int *Crrtab = cconvert->Cr_r_tab;
register int *Cbbtab = cconvert->Cb_b_tab;
register JLONG *Crgtab = cconvert->Cr_g_tab;
@@ -62,14 +63,17 @@ ycc_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
SCALEBITS))];
outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]];
- /* Set unused byte to MAXJSAMPLE so it can be interpreted as an opaque */
- /* alpha channel value */
+ /* Set unused byte to _MAXJSAMPLE so it can be interpreted as an */
+ /* opaque alpha channel value */
#ifdef RGB_ALPHA
- outptr[RGB_ALPHA] = MAXJSAMPLE;
+ outptr[RGB_ALPHA] = _MAXJSAMPLE;
#endif
outptr += RGB_PIXELSIZE;
}
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
@@ -81,11 +85,11 @@ ycc_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
INLINE
LOCAL(void)
-gray_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
+gray_rgb_convert_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf,
int num_rows)
{
- register JSAMPROW inptr, outptr;
+ register _JSAMPROW inptr, outptr;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
@@ -94,10 +98,10 @@ gray_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
outptr = *output_buf++;
for (col = 0; col < num_cols; col++) {
outptr[RGB_RED] = outptr[RGB_GREEN] = outptr[RGB_BLUE] = inptr[col];
- /* Set unused byte to MAXJSAMPLE so it can be interpreted as an opaque */
- /* alpha channel value */
+ /* Set unused byte to _MAXJSAMPLE so it can be interpreted as an */
+ /* opaque alpha channel value */
#ifdef RGB_ALPHA
- outptr[RGB_ALPHA] = MAXJSAMPLE;
+ outptr[RGB_ALPHA] = _MAXJSAMPLE;
#endif
outptr += RGB_PIXELSIZE;
}
@@ -111,12 +115,12 @@ gray_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
INLINE
LOCAL(void)
-rgb_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
+rgb_rgb_convert_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf,
int num_rows)
{
- register JSAMPROW inptr0, inptr1, inptr2;
- register JSAMPROW outptr;
+ register _JSAMPROW inptr0, inptr1, inptr2;
+ register _JSAMPROW outptr;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
@@ -130,10 +134,10 @@ rgb_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
outptr[RGB_RED] = inptr0[col];
outptr[RGB_GREEN] = inptr1[col];
outptr[RGB_BLUE] = inptr2[col];
- /* Set unused byte to MAXJSAMPLE so it can be interpreted as an opaque */
- /* alpha channel value */
+ /* Set unused byte to _MAXJSAMPLE so it can be interpreted as an */
+ /* opaque alpha channel value */
#ifdef RGB_ALPHA
- outptr[RGB_ALPHA] = MAXJSAMPLE;
+ outptr[RGB_ALPHA] = _MAXJSAMPLE;
#endif
outptr += RGB_PIXELSIZE;
}
diff --git a/src/3rdparty/libjpeg/src/jdcolor.c b/src/3rdparty/libjpeg/src/jdcolor.c
index 735190b700..e5c7b58ebf 100644
--- a/src/3rdparty/libjpeg/src/jdcolor.c
+++ b/src/3rdparty/libjpeg/src/jdcolor.c
@@ -6,7 +6,7 @@
* Modified 2011 by Guido Vollbeding.
* libjpeg-turbo Modifications:
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009, 2011-2012, 2014-2015, D. R. Commander.
+ * Copyright (C) 2009, 2011-2012, 2014-2015, 2022, D. R. Commander.
* Copyright (C) 2013, Linaro Limited.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
@@ -18,13 +18,17 @@
#include "jinclude.h"
#include "jpeglib.h"
#include "jsimd.h"
+#include "jsamplecomp.h"
+#if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)
+
/* Private subobject */
typedef struct {
struct jpeg_color_deconverter pub; /* public fields */
+#if BITS_IN_JSAMPLE != 16
/* Private state for YCC->RGB conversion */
int *Cr_r_tab; /* => table for Cr to R conversion */
int *Cb_b_tab; /* => table for Cb to B conversion */
@@ -33,6 +37,7 @@ typedef struct {
/* Private state for RGB->Y conversion */
JLONG *rgb_y_tab; /* => table for RGB to Y conversion */
+#endif
} my_color_deconverter;
typedef my_color_deconverter *my_cconvert_ptr;
@@ -43,7 +48,7 @@ typedef my_color_deconverter *my_cconvert_ptr;
/*
* YCbCr is defined per CCIR 601-1, except that Cb and Cr are
- * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
+ * normalized to the range 0.._MAXJSAMPLE rather than -0.5 .. 0.5.
* The conversion equations to be implemented are therefore
*
* R = Y + 1.40200 * Cr
@@ -52,7 +57,7 @@ typedef my_color_deconverter *my_cconvert_ptr;
*
* Y = 0.29900 * R + 0.58700 * G + 0.11400 * B
*
- * where Cb and Cr represent the incoming values less CENTERJSAMPLE.
+ * where Cb and Cr represent the incoming values less _CENTERJSAMPLE.
* (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
*
* To avoid floating-point arithmetic, we represent the fractional constants
@@ -63,7 +68,7 @@ typedef my_color_deconverter *my_cconvert_ptr;
*
* For even more speed, we avoid doing any multiplications in the inner loop
* by precalculating the constants times Cb and Cr for all possible values.
- * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
+ * For 8-bit samples this is very reasonable (only 256 entries per table);
* for 12-bit samples it is still acceptable. It's not very reasonable for
* 16-bit samples, but if you want lossless storage you shouldn't be changing
* colorspace anyway.
@@ -84,9 +89,9 @@ typedef my_color_deconverter *my_cconvert_ptr;
*/
#define R_Y_OFF 0 /* offset to R => Y section */
-#define G_Y_OFF (1 * (MAXJSAMPLE + 1)) /* offset to G => Y section */
-#define B_Y_OFF (2 * (MAXJSAMPLE + 1)) /* etc. */
-#define TABLE_SIZE (3 * (MAXJSAMPLE + 1))
+#define G_Y_OFF (1 * (_MAXJSAMPLE + 1)) /* offset to G => Y section */
+#define B_Y_OFF (2 * (_MAXJSAMPLE + 1)) /* etc. */
+#define TABLE_SIZE (3 * (_MAXJSAMPLE + 1))
/* Include inline routines for colorspace extensions */
@@ -209,6 +214,7 @@ typedef my_color_deconverter *my_cconvert_ptr;
LOCAL(void)
build_ycc_rgb_table(j_decompress_ptr cinfo)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
int i;
JLONG x;
@@ -216,20 +222,20 @@ build_ycc_rgb_table(j_decompress_ptr cinfo)
cconvert->Cr_r_tab = (int *)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE + 1) * sizeof(int));
+ (_MAXJSAMPLE + 1) * sizeof(int));
cconvert->Cb_b_tab = (int *)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE + 1) * sizeof(int));
+ (_MAXJSAMPLE + 1) * sizeof(int));
cconvert->Cr_g_tab = (JLONG *)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE + 1) * sizeof(JLONG));
+ (_MAXJSAMPLE + 1) * sizeof(JLONG));
cconvert->Cb_g_tab = (JLONG *)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE + 1) * sizeof(JLONG));
+ (_MAXJSAMPLE + 1) * sizeof(JLONG));
- for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
- /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
- /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
+ for (i = 0, x = -_CENTERJSAMPLE; i <= _MAXJSAMPLE; i++, x++) {
+ /* i is the actual input pixel value, in the range 0.._MAXJSAMPLE */
+ /* The Cb or Cr value we are thinking of is x = i - _CENTERJSAMPLE */
/* Cr=>R value is nearest int to 1.40200 * x */
cconvert->Cr_r_tab[i] = (int)
RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS);
@@ -242,6 +248,9 @@ build_ycc_rgb_table(j_decompress_ptr cinfo)
/* We also add in ONE_HALF so that need not do it in inner loop */
cconvert->Cb_g_tab[i] = (-FIX(0.34414)) * x + ONE_HALF;
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
@@ -250,8 +259,8 @@ build_ycc_rgb_table(j_decompress_ptr cinfo)
*/
METHODDEF(void)
-ycc_rgb_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+ycc_rgb_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
switch (cinfo->out_color_space) {
case JCS_EXT_RGB:
@@ -300,6 +309,7 @@ ycc_rgb_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
LOCAL(void)
build_rgb_y_table(j_decompress_ptr cinfo)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
JLONG *rgb_y_tab;
JLONG i;
@@ -309,11 +319,14 @@ build_rgb_y_table(j_decompress_ptr cinfo)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
(TABLE_SIZE * sizeof(JLONG)));
- for (i = 0; i <= MAXJSAMPLE; i++) {
+ for (i = 0; i <= _MAXJSAMPLE; i++) {
rgb_y_tab[i + R_Y_OFF] = FIX(0.29900) * i;
rgb_y_tab[i + G_Y_OFF] = FIX(0.58700) * i;
rgb_y_tab[i + B_Y_OFF] = FIX(0.11400) * i + ONE_HALF;
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
@@ -322,14 +335,15 @@ build_rgb_y_table(j_decompress_ptr cinfo)
*/
METHODDEF(void)
-rgb_gray_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+rgb_gray_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
register int r, g, b;
register JLONG *ctab = cconvert->rgb_y_tab;
- register JSAMPROW outptr;
- register JSAMPROW inptr0, inptr1, inptr2;
+ register _JSAMPROW outptr;
+ register _JSAMPROW inptr0, inptr1, inptr2;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
@@ -344,10 +358,13 @@ rgb_gray_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
g = inptr1[col];
b = inptr2[col];
/* Y */
- outptr[col] = (JSAMPLE)((ctab[r + R_Y_OFF] + ctab[g + G_Y_OFF] +
- ctab[b + B_Y_OFF]) >> SCALEBITS);
+ outptr[col] = (_JSAMPLE)((ctab[r + R_Y_OFF] + ctab[g + G_Y_OFF] +
+ ctab[b + B_Y_OFF]) >> SCALEBITS);
}
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
@@ -357,10 +374,10 @@ rgb_gray_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
*/
METHODDEF(void)
-null_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+null_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
- register JSAMPROW inptr, inptr0, inptr1, inptr2, inptr3, outptr;
+ register _JSAMPROW inptr, inptr0, inptr1, inptr2, inptr3, outptr;
register JDIMENSION col;
register int num_components = cinfo->num_components;
JDIMENSION num_cols = cinfo->output_width;
@@ -418,11 +435,11 @@ null_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
*/
METHODDEF(void)
-grayscale_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+grayscale_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
- jcopy_sample_rows(input_buf[0], (int)input_row, output_buf, 0, num_rows,
- cinfo->output_width);
+ _jcopy_sample_rows(input_buf[0], (int)input_row, output_buf, 0, num_rows,
+ cinfo->output_width);
}
@@ -431,8 +448,8 @@ grayscale_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
*/
METHODDEF(void)
-gray_rgb_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+gray_rgb_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
switch (cinfo->out_color_space) {
case JCS_EXT_RGB:
@@ -476,8 +493,8 @@ gray_rgb_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
*/
METHODDEF(void)
-rgb_rgb_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+rgb_rgb_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
switch (cinfo->out_color_space) {
case JCS_EXT_RGB:
@@ -524,17 +541,18 @@ rgb_rgb_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
*/
METHODDEF(void)
-ycck_cmyk_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+ycck_cmyk_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
+#if BITS_IN_JSAMPLE != 16
my_cconvert_ptr cconvert = (my_cconvert_ptr)cinfo->cconvert;
register int y, cb, cr;
- register JSAMPROW outptr;
- register JSAMPROW inptr0, inptr1, inptr2, inptr3;
+ register _JSAMPROW outptr;
+ register _JSAMPROW inptr0, inptr1, inptr2, inptr3;
register JDIMENSION col;
JDIMENSION num_cols = cinfo->output_width;
/* copy these pointers into registers if possible */
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
register int *Crrtab = cconvert->Cr_r_tab;
register int *Cbbtab = cconvert->Cb_b_tab;
register JLONG *Crgtab = cconvert->Cr_g_tab;
@@ -553,16 +571,19 @@ ycck_cmyk_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
cb = inptr1[col];
cr = inptr2[col];
/* Range-limiting is essential due to noise introduced by DCT losses. */
- outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])]; /* red */
- outptr[1] = range_limit[MAXJSAMPLE - (y + /* green */
+ outptr[0] = range_limit[_MAXJSAMPLE - (y + Crrtab[cr])]; /* red */
+ outptr[1] = range_limit[_MAXJSAMPLE - (y + /* green */
((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
SCALEBITS)))];
- outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */
+ outptr[2] = range_limit[_MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */
/* K passes through unchanged */
outptr[3] = inptr3[col];
outptr += 4;
}
}
+#else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+#endif
}
@@ -652,8 +673,8 @@ static INLINE boolean is_big_endian(void)
METHODDEF(void)
-ycc_rgb565_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+ycc_rgb565_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
if (is_big_endian())
ycc_rgb565_convert_be(cinfo, input_buf, input_row, output_buf, num_rows);
@@ -663,8 +684,8 @@ ycc_rgb565_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
METHODDEF(void)
-ycc_rgb565D_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+ycc_rgb565D_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
if (is_big_endian())
ycc_rgb565D_convert_be(cinfo, input_buf, input_row, output_buf, num_rows);
@@ -674,8 +695,8 @@ ycc_rgb565D_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
METHODDEF(void)
-rgb_rgb565_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+rgb_rgb565_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
if (is_big_endian())
rgb_rgb565_convert_be(cinfo, input_buf, input_row, output_buf, num_rows);
@@ -685,8 +706,8 @@ rgb_rgb565_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
METHODDEF(void)
-rgb_rgb565D_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+rgb_rgb565D_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
if (is_big_endian())
rgb_rgb565D_convert_be(cinfo, input_buf, input_row, output_buf, num_rows);
@@ -696,8 +717,8 @@ rgb_rgb565D_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
METHODDEF(void)
-gray_rgb565_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+gray_rgb565_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
if (is_big_endian())
gray_rgb565_convert_be(cinfo, input_buf, input_row, output_buf, num_rows);
@@ -707,8 +728,8 @@ gray_rgb565_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
METHODDEF(void)
-gray_rgb565D_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)
+gray_rgb565D_convert(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION input_row, _JSAMPARRAY output_buf, int num_rows)
{
if (is_big_endian())
gray_rgb565D_convert_be(cinfo, input_buf, input_row, output_buf, num_rows);
@@ -733,11 +754,14 @@ start_pass_dcolor(j_decompress_ptr cinfo)
*/
GLOBAL(void)
-jinit_color_deconverter(j_decompress_ptr cinfo)
+_jinit_color_deconverter(j_decompress_ptr cinfo)
{
my_cconvert_ptr cconvert;
int ci;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
cconvert = (my_cconvert_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_color_deconverter));
@@ -772,19 +796,24 @@ jinit_color_deconverter(j_decompress_ptr cinfo)
/* Set out_color_components and conversion method based on requested space.
* Also clear the component_needed flags for any unused components,
* so that earlier pipeline stages can avoid useless computation.
+ * NOTE: We do not allow any lossy color conversion algorithms in lossless
+ * mode.
*/
switch (cinfo->out_color_space) {
case JCS_GRAYSCALE:
+ if (cinfo->master->lossless &&
+ cinfo->jpeg_color_space != cinfo->out_color_space)
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
cinfo->out_color_components = 1;
if (cinfo->jpeg_color_space == JCS_GRAYSCALE ||
cinfo->jpeg_color_space == JCS_YCbCr) {
- cconvert->pub.color_convert = grayscale_convert;
+ cconvert->pub._color_convert = grayscale_convert;
/* For color->grayscale conversion, only the Y (0) component is needed */
for (ci = 1; ci < cinfo->num_components; ci++)
cinfo->comp_info[ci].component_needed = FALSE;
} else if (cinfo->jpeg_color_space == JCS_RGB) {
- cconvert->pub.color_convert = rgb_gray_convert;
+ cconvert->pub._color_convert = rgb_gray_convert;
build_rgb_y_table(cinfo);
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
@@ -801,65 +830,78 @@ jinit_color_deconverter(j_decompress_ptr cinfo)
case JCS_EXT_BGRA:
case JCS_EXT_ABGR:
case JCS_EXT_ARGB:
+ if (cinfo->master->lossless && cinfo->jpeg_color_space != JCS_RGB)
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
cinfo->out_color_components = rgb_pixelsize[cinfo->out_color_space];
if (cinfo->jpeg_color_space == JCS_YCbCr) {
+#ifdef WITH_SIMD
if (jsimd_can_ycc_rgb())
- cconvert->pub.color_convert = jsimd_ycc_rgb_convert;
- else {
- cconvert->pub.color_convert = ycc_rgb_convert;
+ cconvert->pub._color_convert = jsimd_ycc_rgb_convert;
+ else
+#endif
+ {
+ cconvert->pub._color_convert = ycc_rgb_convert;
build_ycc_rgb_table(cinfo);
}
} else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) {
- cconvert->pub.color_convert = gray_rgb_convert;
+ cconvert->pub._color_convert = gray_rgb_convert;
} else if (cinfo->jpeg_color_space == JCS_RGB) {
if (rgb_red[cinfo->out_color_space] == 0 &&
rgb_green[cinfo->out_color_space] == 1 &&
rgb_blue[cinfo->out_color_space] == 2 &&
rgb_pixelsize[cinfo->out_color_space] == 3)
- cconvert->pub.color_convert = null_convert;
+ cconvert->pub._color_convert = null_convert;
else
- cconvert->pub.color_convert = rgb_rgb_convert;
+ cconvert->pub._color_convert = rgb_rgb_convert;
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
case JCS_RGB565:
+ if (cinfo->master->lossless)
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
cinfo->out_color_components = 3;
if (cinfo->dither_mode == JDITHER_NONE) {
if (cinfo->jpeg_color_space == JCS_YCbCr) {
+#ifdef WITH_SIMD
if (jsimd_can_ycc_rgb565())
- cconvert->pub.color_convert = jsimd_ycc_rgb565_convert;
- else {
- cconvert->pub.color_convert = ycc_rgb565_convert;
+ cconvert->pub._color_convert = jsimd_ycc_rgb565_convert;
+ else
+#endif
+ {
+ cconvert->pub._color_convert = ycc_rgb565_convert;
build_ycc_rgb_table(cinfo);
}
} else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) {
- cconvert->pub.color_convert = gray_rgb565_convert;
+ cconvert->pub._color_convert = gray_rgb565_convert;
} else if (cinfo->jpeg_color_space == JCS_RGB) {
- cconvert->pub.color_convert = rgb_rgb565_convert;
+ cconvert->pub._color_convert = rgb_rgb565_convert;
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
} else {
/* only ordered dithering is supported */
if (cinfo->jpeg_color_space == JCS_YCbCr) {
- cconvert->pub.color_convert = ycc_rgb565D_convert;
+ cconvert->pub._color_convert = ycc_rgb565D_convert;
build_ycc_rgb_table(cinfo);
} else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) {
- cconvert->pub.color_convert = gray_rgb565D_convert;
+ cconvert->pub._color_convert = gray_rgb565D_convert;
} else if (cinfo->jpeg_color_space == JCS_RGB) {
- cconvert->pub.color_convert = rgb_rgb565D_convert;
+ cconvert->pub._color_convert = rgb_rgb565D_convert;
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
}
break;
case JCS_CMYK:
+ if (cinfo->master->lossless &&
+ cinfo->jpeg_color_space != cinfo->out_color_space)
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
cinfo->out_color_components = 4;
if (cinfo->jpeg_color_space == JCS_YCCK) {
- cconvert->pub.color_convert = ycck_cmyk_convert;
+ cconvert->pub._color_convert = ycck_cmyk_convert;
build_ycc_rgb_table(cinfo);
} else if (cinfo->jpeg_color_space == JCS_CMYK) {
- cconvert->pub.color_convert = null_convert;
+ cconvert->pub._color_convert = null_convert;
} else
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
@@ -868,7 +910,7 @@ jinit_color_deconverter(j_decompress_ptr cinfo)
/* Permit null conversion to same output space */
if (cinfo->out_color_space == cinfo->jpeg_color_space) {
cinfo->out_color_components = cinfo->num_components;
- cconvert->pub.color_convert = null_convert;
+ cconvert->pub._color_convert = null_convert;
} else /* unsupported non-null conversion */
ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
break;
@@ -879,3 +921,5 @@ jinit_color_deconverter(j_decompress_ptr cinfo)
else
cinfo->output_components = cinfo->out_color_components;
}
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */
diff --git a/src/3rdparty/libjpeg/src/jdct.h b/src/3rdparty/libjpeg/src/jdct.h
index 66d1718b77..0411a79bc0 100644
--- a/src/3rdparty/libjpeg/src/jdct.h
+++ b/src/3rdparty/libjpeg/src/jdct.h
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2015, D. R. Commander.
+ * Copyright (C) 2015, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -15,13 +15,15 @@
* machine-dependent tuning (e.g., assembly coding).
*/
+#include "jsamplecomp.h"
+
/*
* A forward DCT routine is given a pointer to a work area of type DCTELEM[];
* the DCT is to be performed in-place in that buffer. Type DCTELEM is int
* for 8-bit samples, JLONG for 12-bit samples. (NOTE: Floating-point DCT
* implementations use an array of type FAST_FLOAT, instead.)
- * The DCT inputs are expected to be signed (range +-CENTERJSAMPLE).
+ * The DCT inputs are expected to be signed (range +-_CENTERJSAMPLE).
* The DCT outputs are returned scaled up by a factor of 8; they therefore
* have a range of +-8K for 8-bit data, +-128K for 12-bit data. This
* convention improves accuracy in integer implementations and saves some
@@ -76,78 +78,89 @@ typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */
/*
* Each IDCT routine is responsible for range-limiting its results and
- * converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could
+ * converting them to unsigned form (0.._MAXJSAMPLE). The raw outputs could
* be quite far out of range if the input data is corrupt, so a bulletproof
* range-limiting step is required. We use a mask-and-table-lookup method
* to do the combined operations quickly. See the comments with
* prepare_range_limit_table (in jdmaster.c) for more info.
*/
-#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit + CENTERJSAMPLE)
+#define IDCT_range_limit(cinfo) \
+ ((_JSAMPLE *)((cinfo)->sample_range_limit) + _CENTERJSAMPLE)
-#define RANGE_MASK (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */
+#define RANGE_MASK (_MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */
/* Extern declarations for the forward and inverse DCT routines. */
-EXTERN(void) jpeg_fdct_islow(DCTELEM *data);
-EXTERN(void) jpeg_fdct_ifast(DCTELEM *data);
+EXTERN(void) _jpeg_fdct_islow(DCTELEM *data);
+EXTERN(void) _jpeg_fdct_ifast(DCTELEM *data);
EXTERN(void) jpeg_fdct_float(FAST_FLOAT *data);
-EXTERN(void) jpeg_idct_islow(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_ifast(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_float(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_7x7(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_6x6(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_5x5(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_4x4(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_3x3(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_2x2(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_1x1(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_9x9(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_10x10(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_11x11(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_12x12(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_13x13(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_14x14(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_15x15(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
-EXTERN(void) jpeg_idct_16x16(j_decompress_ptr cinfo,
- jpeg_component_info *compptr, JCOEFPTR coef_block,
- JSAMPARRAY output_buf, JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_islow(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_ifast(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_float(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_7x7(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr, JCOEFPTR coef_block,
+ _JSAMPARRAY output_buf, JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_6x6(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr, JCOEFPTR coef_block,
+ _JSAMPARRAY output_buf, JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_5x5(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr, JCOEFPTR coef_block,
+ _JSAMPARRAY output_buf, JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_4x4(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr, JCOEFPTR coef_block,
+ _JSAMPARRAY output_buf, JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_3x3(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr, JCOEFPTR coef_block,
+ _JSAMPARRAY output_buf, JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_2x2(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr, JCOEFPTR coef_block,
+ _JSAMPARRAY output_buf, JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_1x1(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr, JCOEFPTR coef_block,
+ _JSAMPARRAY output_buf, JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_9x9(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr, JCOEFPTR coef_block,
+ _JSAMPARRAY output_buf, JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_10x10(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_11x11(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_12x12(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_13x13(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_14x14(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_15x15(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col);
+EXTERN(void) _jpeg_idct_16x16(j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col);
/*
diff --git a/src/3rdparty/libjpeg/src/jddctmgr.c b/src/3rdparty/libjpeg/src/jddctmgr.c
index e78d7bebe2..0bd8c2b591 100644
--- a/src/3rdparty/libjpeg/src/jddctmgr.c
+++ b/src/3rdparty/libjpeg/src/jddctmgr.c
@@ -26,7 +26,7 @@
#include "jpeglib.h"
#include "jdct.h" /* Private declarations for DCT subsystem */
#include "jsimddct.h"
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
/*
@@ -100,7 +100,7 @@ start_pass(j_decompress_ptr cinfo)
int ci, i;
jpeg_component_info *compptr;
int method = 0;
- inverse_DCT_method_ptr method_ptr = NULL;
+ _inverse_DCT_method_ptr method_ptr = NULL;
JQUANT_TBL *qtbl;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
@@ -109,42 +109,46 @@ start_pass(j_decompress_ptr cinfo)
switch (compptr->_DCT_scaled_size) {
#ifdef IDCT_SCALING_SUPPORTED
case 1:
- method_ptr = jpeg_idct_1x1;
+ method_ptr = _jpeg_idct_1x1;
method = JDCT_ISLOW; /* jidctred uses islow-style table */
break;
case 2:
+#ifdef WITH_SIMD
if (jsimd_can_idct_2x2())
method_ptr = jsimd_idct_2x2;
else
- method_ptr = jpeg_idct_2x2;
+#endif
+ method_ptr = _jpeg_idct_2x2;
method = JDCT_ISLOW; /* jidctred uses islow-style table */
break;
case 3:
- method_ptr = jpeg_idct_3x3;
+ method_ptr = _jpeg_idct_3x3;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
case 4:
+#ifdef WITH_SIMD
if (jsimd_can_idct_4x4())
method_ptr = jsimd_idct_4x4;
else
- method_ptr = jpeg_idct_4x4;
+#endif
+ method_ptr = _jpeg_idct_4x4;
method = JDCT_ISLOW; /* jidctred uses islow-style table */
break;
case 5:
- method_ptr = jpeg_idct_5x5;
+ method_ptr = _jpeg_idct_5x5;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
case 6:
-#if defined(__mips__)
+#if defined(WITH_SIMD) && defined(__mips__)
if (jsimd_can_idct_6x6())
method_ptr = jsimd_idct_6x6;
else
#endif
- method_ptr = jpeg_idct_6x6;
+ method_ptr = _jpeg_idct_6x6;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
case 7:
- method_ptr = jpeg_idct_7x7;
+ method_ptr = _jpeg_idct_7x7;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
#endif
@@ -152,28 +156,34 @@ start_pass(j_decompress_ptr cinfo)
switch (cinfo->dct_method) {
#ifdef DCT_ISLOW_SUPPORTED
case JDCT_ISLOW:
+#ifdef WITH_SIMD
if (jsimd_can_idct_islow())
method_ptr = jsimd_idct_islow;
else
- method_ptr = jpeg_idct_islow;
+#endif
+ method_ptr = _jpeg_idct_islow;
method = JDCT_ISLOW;
break;
#endif
#ifdef DCT_IFAST_SUPPORTED
case JDCT_IFAST:
+#ifdef WITH_SIMD
if (jsimd_can_idct_ifast())
method_ptr = jsimd_idct_ifast;
else
- method_ptr = jpeg_idct_ifast;
+#endif
+ method_ptr = _jpeg_idct_ifast;
method = JDCT_IFAST;
break;
#endif
#ifdef DCT_FLOAT_SUPPORTED
case JDCT_FLOAT:
+#ifdef WITH_SIMD
if (jsimd_can_idct_float())
method_ptr = jsimd_idct_float;
else
- method_ptr = jpeg_idct_float;
+#endif
+ method_ptr = _jpeg_idct_float;
method = JDCT_FLOAT;
break;
#endif
@@ -184,40 +194,40 @@ start_pass(j_decompress_ptr cinfo)
break;
#ifdef IDCT_SCALING_SUPPORTED
case 9:
- method_ptr = jpeg_idct_9x9;
+ method_ptr = _jpeg_idct_9x9;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
case 10:
- method_ptr = jpeg_idct_10x10;
+ method_ptr = _jpeg_idct_10x10;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
case 11:
- method_ptr = jpeg_idct_11x11;
+ method_ptr = _jpeg_idct_11x11;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
case 12:
-#if defined(__mips__)
+#if defined(WITH_SIMD) && defined(__mips__)
if (jsimd_can_idct_12x12())
method_ptr = jsimd_idct_12x12;
else
#endif
- method_ptr = jpeg_idct_12x12;
+ method_ptr = _jpeg_idct_12x12;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
case 13:
- method_ptr = jpeg_idct_13x13;
+ method_ptr = _jpeg_idct_13x13;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
case 14:
- method_ptr = jpeg_idct_14x14;
+ method_ptr = _jpeg_idct_14x14;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
case 15:
- method_ptr = jpeg_idct_15x15;
+ method_ptr = _jpeg_idct_15x15;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
case 16:
- method_ptr = jpeg_idct_16x16;
+ method_ptr = _jpeg_idct_16x16;
method = JDCT_ISLOW; /* jidctint uses islow-style table */
break;
#endif
@@ -225,7 +235,7 @@ start_pass(j_decompress_ptr cinfo)
ERREXIT1(cinfo, JERR_BAD_DCTSIZE, compptr->_DCT_scaled_size);
break;
}
- idct->pub.inverse_DCT[ci] = method_ptr;
+ idct->pub._inverse_DCT[ci] = method_ptr;
/* Create multiplier table from quant table.
* However, we can skip this if the component is uninteresting
* or if we already built the table. Also, if no quant table
@@ -327,12 +337,15 @@ start_pass(j_decompress_ptr cinfo)
*/
GLOBAL(void)
-jinit_inverse_dct(j_decompress_ptr cinfo)
+_jinit_inverse_dct(j_decompress_ptr cinfo)
{
my_idct_ptr idct;
int ci;
jpeg_component_info *compptr;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
idct = (my_idct_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_idct_controller));
diff --git a/src/3rdparty/libjpeg/src/jddiffct.c b/src/3rdparty/libjpeg/src/jddiffct.c
new file mode 100644
index 0000000000..f1d7f61b52
--- /dev/null
+++ b/src/3rdparty/libjpeg/src/jddiffct.c
@@ -0,0 +1,403 @@
+/*
+ * jddiffct.c
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file contains the [un]difference buffer controller for decompression.
+ * This controller is the top level of the lossless JPEG decompressor proper.
+ * The difference buffer lies between the entropy decoding and
+ * prediction/undifferencing steps. The undifference buffer lies between the
+ * prediction/undifferencing and scaling steps.
+ *
+ * In buffered-image mode, this controller is the interface between
+ * input-oriented processing and output-oriented processing.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jlossls.h" /* Private declarations for lossless codec */
+
+
+#ifdef D_LOSSLESS_SUPPORTED
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_d_coef_controller pub; /* public fields */
+
+ /* These variables keep track of the current location of the input side. */
+ /* cinfo->input_iMCU_row is also used for this. */
+ JDIMENSION MCU_ctr; /* counts MCUs processed in current row */
+ unsigned int restart_rows_to_go; /* MCU rows left in this restart
+ interval */
+ unsigned int MCU_vert_offset; /* counts MCU rows within iMCU row */
+ unsigned int MCU_rows_per_iMCU_row; /* number of such rows needed */
+
+ /* The output side's location is represented by cinfo->output_iMCU_row. */
+
+ JDIFFARRAY diff_buf[MAX_COMPONENTS]; /* iMCU row of differences */
+ JDIFFARRAY undiff_buf[MAX_COMPONENTS]; /* iMCU row of undiff'd samples */
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+ /* In multi-pass modes, we need a virtual sample array for each component. */
+ jvirt_sarray_ptr whole_image[MAX_COMPONENTS];
+#endif
+} my_diff_controller;
+
+typedef my_diff_controller *my_diff_ptr;
+
+/* Forward declarations */
+METHODDEF(int) decompress_data(j_decompress_ptr cinfo, _JSAMPIMAGE output_buf);
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+METHODDEF(int) output_data(j_decompress_ptr cinfo, _JSAMPIMAGE output_buf);
+#endif
+
+
+LOCAL(void)
+start_iMCU_row(j_decompress_ptr cinfo)
+/* Reset within-iMCU-row counters for a new row (input side) */
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+
+ /* In an interleaved scan, an MCU row is the same as an iMCU row.
+ * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
+ * But at the bottom of the image, process only what's left.
+ */
+ if (cinfo->comps_in_scan > 1) {
+ diff->MCU_rows_per_iMCU_row = 1;
+ } else {
+ if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1))
+ diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
+ else
+ diff->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
+ }
+
+ diff->MCU_ctr = 0;
+ diff->MCU_vert_offset = 0;
+}
+
+
+/*
+ * Initialize for an input processing pass.
+ */
+
+METHODDEF(void)
+start_input_pass(j_decompress_ptr cinfo)
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+
+ /* Because it is hitching a ride on the jpeg_inverse_dct struct,
+ * start_pass_lossless() will be called at the start of the output pass.
+ * This ensures that it will be called at the start of the input pass as
+ * well.
+ */
+ (*cinfo->idct->start_pass) (cinfo);
+
+ /* Check that the restart interval is an integer multiple of the number
+ * of MCUs in an MCU row.
+ */
+ if (cinfo->restart_interval % cinfo->MCUs_per_row != 0)
+ ERREXIT2(cinfo, JERR_BAD_RESTART,
+ cinfo->restart_interval, cinfo->MCUs_per_row);
+
+ /* Initialize restart counter */
+ diff->restart_rows_to_go = cinfo->restart_interval / cinfo->MCUs_per_row;
+
+ cinfo->input_iMCU_row = 0;
+ start_iMCU_row(cinfo);
+}
+
+
+/*
+ * Check for a restart marker & resynchronize decoder, undifferencer.
+ * Returns FALSE if must suspend.
+ */
+
+METHODDEF(boolean)
+process_restart(j_decompress_ptr cinfo)
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+
+ if (!(*cinfo->entropy->process_restart) (cinfo))
+ return FALSE;
+
+ (*cinfo->idct->start_pass) (cinfo);
+
+ /* Reset restart counter */
+ diff->restart_rows_to_go = cinfo->restart_interval / cinfo->MCUs_per_row;
+
+ return TRUE;
+}
+
+
+/*
+ * Initialize for an output processing pass.
+ */
+
+METHODDEF(void)
+start_output_pass(j_decompress_ptr cinfo)
+{
+ cinfo->output_iMCU_row = 0;
+}
+
+
+/*
+ * Decompress and return some data in the supplied buffer.
+ * Always attempts to emit one fully interleaved MCU row ("iMCU" row).
+ * Input and output must run in lockstep since we have only a one-MCU buffer.
+ * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
+ *
+ * NB: output_buf contains a plane for each component in image,
+ * which we index according to the component's SOF position.
+ */
+
+METHODDEF(int)
+decompress_data(j_decompress_ptr cinfo, _JSAMPIMAGE output_buf)
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+ lossless_decomp_ptr losslessd = (lossless_decomp_ptr)cinfo->idct;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ JDIMENSION MCU_count; /* number of MCUs decoded */
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ int ci, compi, row, prev_row;
+ unsigned int yoffset;
+ jpeg_component_info *compptr;
+
+ /* Loop to process as much as one whole iMCU row */
+ for (yoffset = diff->MCU_vert_offset; yoffset < diff->MCU_rows_per_iMCU_row;
+ yoffset++) {
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (diff->restart_rows_to_go == 0)
+ if (!process_restart(cinfo))
+ return JPEG_SUSPENDED;
+ }
+
+ MCU_col_num = diff->MCU_ctr;
+ /* Try to fetch an MCU row (or remaining portion of suspended MCU row). */
+ MCU_count =
+ (*cinfo->entropy->decode_mcus) (cinfo,
+ diff->diff_buf, yoffset, MCU_col_num,
+ cinfo->MCUs_per_row - MCU_col_num);
+ if (MCU_count != cinfo->MCUs_per_row - MCU_col_num) {
+ /* Suspension forced; update state counters and exit */
+ diff->MCU_vert_offset = yoffset;
+ diff->MCU_ctr += MCU_count;
+ return JPEG_SUSPENDED;
+ }
+
+ /* Account for restart interval (no-op if not using restarts) */
+ if (cinfo->restart_interval)
+ diff->restart_rows_to_go--;
+
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ diff->MCU_ctr = 0;
+ }
+
+ /*
+ * Undifference and scale each scanline of the disassembled MCU row
+ * separately. We do not process dummy samples at the end of a scanline
+ * or dummy rows at the end of the image.
+ */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ compi = compptr->component_index;
+ for (row = 0, prev_row = compptr->v_samp_factor - 1;
+ row < (cinfo->input_iMCU_row == last_iMCU_row ?
+ compptr->last_row_height : compptr->v_samp_factor);
+ prev_row = row, row++) {
+ (*losslessd->predict_undifference[compi])
+ (cinfo, compi, diff->diff_buf[compi][row],
+ diff->undiff_buf[compi][prev_row], diff->undiff_buf[compi][row],
+ compptr->width_in_blocks);
+ (*losslessd->scaler_scale) (cinfo, diff->undiff_buf[compi][row],
+ output_buf[compi][row],
+ compptr->width_in_blocks);
+ }
+ }
+
+ /* Completed the iMCU row, advance counters for next one.
+ *
+ * NB: output_data will increment output_iMCU_row.
+ * This counter is not needed for the single-pass case
+ * or the input side of the multi-pass case.
+ */
+ if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) {
+ start_iMCU_row(cinfo);
+ return JPEG_ROW_COMPLETED;
+ }
+ /* Completed the scan */
+ (*cinfo->inputctl->finish_input_pass) (cinfo);
+ return JPEG_SCAN_COMPLETED;
+}
+
+
+/*
+ * Dummy consume-input routine for single-pass operation.
+ */
+
+METHODDEF(int)
+dummy_consume_data(j_decompress_ptr cinfo)
+{
+ return JPEG_SUSPENDED; /* Always indicate nothing was done */
+}
+
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+
+/*
+ * Consume input data and store it in the full-image sample buffer.
+ * We read as much as one fully interleaved MCU row ("iMCU" row) per call,
+ * ie, v_samp_factor rows for each component in the scan.
+ * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
+ */
+
+METHODDEF(int)
+consume_data(j_decompress_ptr cinfo)
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+ int ci, compi;
+ _JSAMPARRAY buffer[MAX_COMPS_IN_SCAN];
+ jpeg_component_info *compptr;
+
+ /* Align the virtual buffers for the components used in this scan. */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ compi = compptr->component_index;
+ buffer[compi] = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr)cinfo, diff->whole_image[compi],
+ cinfo->input_iMCU_row * compptr->v_samp_factor,
+ (JDIMENSION)compptr->v_samp_factor, TRUE);
+ }
+
+ return decompress_data(cinfo, buffer);
+}
+
+
+/*
+ * Output some data from the full-image sample buffer in the multi-pass case.
+ * Always attempts to emit one fully interleaved MCU row ("iMCU" row).
+ * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
+ *
+ * NB: output_buf contains a plane for each component in image.
+ */
+
+METHODDEF(int)
+output_data(j_decompress_ptr cinfo, _JSAMPIMAGE output_buf)
+{
+ my_diff_ptr diff = (my_diff_ptr)cinfo->coef;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ int ci, samp_rows, row;
+ _JSAMPARRAY buffer;
+ jpeg_component_info *compptr;
+
+ /* Force some input to be done if we are getting ahead of the input. */
+ while (cinfo->input_scan_number < cinfo->output_scan_number ||
+ (cinfo->input_scan_number == cinfo->output_scan_number &&
+ cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) {
+ if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED)
+ return JPEG_SUSPENDED;
+ }
+
+ /* OK, output from the virtual arrays. */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Align the virtual buffer for this component. */
+ buffer = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr)cinfo, diff->whole_image[ci],
+ cinfo->output_iMCU_row * compptr->v_samp_factor,
+ (JDIMENSION)compptr->v_samp_factor, FALSE);
+
+ if (cinfo->output_iMCU_row < last_iMCU_row)
+ samp_rows = compptr->v_samp_factor;
+ else {
+ /* NB: can't use last_row_height here; it is input-side-dependent! */
+ samp_rows = (int)(compptr->height_in_blocks % compptr->v_samp_factor);
+ if (samp_rows == 0) samp_rows = compptr->v_samp_factor;
+ }
+
+ for (row = 0; row < samp_rows; row++) {
+ memcpy(output_buf[ci][row], buffer[row],
+ compptr->width_in_blocks * sizeof(_JSAMPLE));
+ }
+ }
+
+ if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows)
+ return JPEG_ROW_COMPLETED;
+ return JPEG_SCAN_COMPLETED;
+}
+
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+
+
+/*
+ * Initialize difference buffer controller.
+ */
+
+GLOBAL(void)
+_jinit_d_diff_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
+{
+ my_diff_ptr diff;
+ int ci;
+ jpeg_component_info *compptr;
+
+ diff = (my_diff_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
+ sizeof(my_diff_controller));
+ cinfo->coef = (struct jpeg_d_coef_controller *)diff;
+ diff->pub.start_input_pass = start_input_pass;
+ diff->pub.start_output_pass = start_output_pass;
+
+ /* Create the [un]difference buffers. */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ diff->diff_buf[ci] =
+ ALLOC_DARRAY(JPOOL_IMAGE,
+ (JDIMENSION)jround_up((long)compptr->width_in_blocks,
+ (long)compptr->h_samp_factor),
+ (JDIMENSION)compptr->v_samp_factor);
+ diff->undiff_buf[ci] =
+ ALLOC_DARRAY(JPOOL_IMAGE,
+ (JDIMENSION)jround_up((long)compptr->width_in_blocks,
+ (long)compptr->h_samp_factor),
+ (JDIMENSION)compptr->v_samp_factor);
+ }
+
+ if (need_full_buffer) {
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+ /* Allocate a full-image virtual array for each component. */
+ int access_rows;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ access_rows = compptr->v_samp_factor;
+ diff->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr)cinfo, JPOOL_IMAGE, FALSE,
+ (JDIMENSION)jround_up((long)compptr->width_in_blocks,
+ (long)compptr->h_samp_factor),
+ (JDIMENSION)jround_up((long)compptr->height_in_blocks,
+ (long)compptr->v_samp_factor),
+ (JDIMENSION)access_rows);
+ }
+ diff->pub.consume_data = consume_data;
+ diff->pub._decompress_data = output_data;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ diff->pub.consume_data = dummy_consume_data;
+ diff->pub._decompress_data = decompress_data;
+ diff->whole_image[0] = NULL; /* flag for no virtual arrays */
+ }
+}
+
+#endif /* D_LOSSLESS_SUPPORTED */
diff --git a/src/3rdparty/libjpeg/src/jdhuff.c b/src/3rdparty/libjpeg/src/jdhuff.c
index 679d221685..cd8c0847a2 100644
--- a/src/3rdparty/libjpeg/src/jdhuff.c
+++ b/src/3rdparty/libjpeg/src/jdhuff.c
@@ -3,8 +3,10 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2009-2011, 2016, 2018-2019, D. R. Commander.
+ * Copyright (C) 2009-2011, 2016, 2018-2019, 2022, D. R. Commander.
* Copyright (C) 2018, Matthias Räncker.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
@@ -24,8 +26,8 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
-#include "jdhuff.h" /* Declarations shared with jdphuff.c */
-#include "jpegcomp.h"
+#include "jdhuff.h" /* Declarations shared with jd*huff.c */
+#include "jpegapicomp.h"
#include "jstdhuff.c"
@@ -134,7 +136,7 @@ start_pass_huff_decoder(j_decompress_ptr cinfo)
* Compute the derived values for a Huffman table.
* This routine also performs some validation checks on the table.
*
- * Note this is also used by jdphuff.c.
+ * Note this is also used by jdphuff.c and jdlhuff.c.
*/
GLOBAL(void)
@@ -245,14 +247,14 @@ jpeg_make_d_derived_tbl(j_decompress_ptr cinfo, boolean isDC, int tblno,
/* Validate symbols as being reasonable.
* For AC tables, we make no check, but accept all byte values 0..255.
- * For DC tables, we require the symbols to be in range 0..15.
- * (Tighter bounds could be applied depending on the data depth and mode,
- * but this is sufficient to ensure safe decoding.)
+ * For DC tables, we require the symbols to be in range 0..15 in lossy mode
+ * and 0..16 in lossless mode. (Tighter bounds could be applied depending on
+ * the data depth and mode, but this is sufficient to ensure safe decoding.)
*/
if (isDC) {
for (i = 0; i < numsymbols; i++) {
int sym = htbl->huffval[i];
- if (sym < 0 || sym > 15)
+ if (sym < 0 || sym > (cinfo->master->lossless ? 16 : 15))
ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
}
}
@@ -260,7 +262,7 @@ jpeg_make_d_derived_tbl(j_decompress_ptr cinfo, boolean isDC, int tblno,
/*
- * Out-of-line code for bit fetching (shared with jdphuff.c).
+ * Out-of-line code for bit fetching (shared with jdphuff.c and jdlhuff.c).
* See jdhuff.h for info about usage.
* Note: current values of get_buffer and bits_left are passed as parameters,
* but are returned in the corresponding fields of the state struct.
diff --git a/src/3rdparty/libjpeg/src/jdhuff.h b/src/3rdparty/libjpeg/src/jdhuff.h
index cfa0b7f558..3eee002c02 100644
--- a/src/3rdparty/libjpeg/src/jdhuff.h
+++ b/src/3rdparty/libjpeg/src/jdhuff.h
@@ -3,6 +3,8 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
* Copyright (C) 2010-2011, 2015-2016, 2021, D. R. Commander.
* Copyright (C) 2018, Matthias Räncker.
@@ -10,8 +12,9 @@
* file.
*
* This file contains declarations for Huffman entropy decoding routines
- * that are shared between the sequential decoder (jdhuff.c) and the
- * progressive decoder (jdphuff.c). No other modules need to see these.
+ * that are shared between the sequential decoder (jdhuff.c), the progressive
+ * decoder (jdphuff.c), and the lossless decoder (jdlhuff.c). No other modules
+ * need to see these.
*/
#include "jconfigint.h"
diff --git a/src/3rdparty/libjpeg/src/jdicc.c b/src/3rdparty/libjpeg/src/jdicc.c
new file mode 100644
index 0000000000..50aa9a9676
--- /dev/null
+++ b/src/3rdparty/libjpeg/src/jdicc.c
@@ -0,0 +1,167 @@
+/*
+ * jdicc.c
+ *
+ * Copyright (C) 1997-1998, Thomas G. Lane, Todd Newman.
+ * Copyright (C) 2017, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file provides code to read International Color Consortium (ICC) device
+ * profiles embedded in JFIF JPEG image files. The ICC has defined a standard
+ * for including such data in JPEG "APP2" markers. The code given here does
+ * not know anything about the internal structure of the ICC profile data; it
+ * just knows how to get the profile data from a JPEG file while reading it.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jerror.h"
+
+
+#define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */
+#define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */
+
+
+/*
+ * Handy subroutine to test whether a saved marker is an ICC profile marker.
+ */
+
+LOCAL(boolean)
+marker_is_icc(jpeg_saved_marker_ptr marker)
+{
+ return
+ marker->marker == ICC_MARKER &&
+ marker->data_length >= ICC_OVERHEAD_LEN &&
+ /* verify the identifying string */
+ marker->data[0] == 0x49 &&
+ marker->data[1] == 0x43 &&
+ marker->data[2] == 0x43 &&
+ marker->data[3] == 0x5F &&
+ marker->data[4] == 0x50 &&
+ marker->data[5] == 0x52 &&
+ marker->data[6] == 0x4F &&
+ marker->data[7] == 0x46 &&
+ marker->data[8] == 0x49 &&
+ marker->data[9] == 0x4C &&
+ marker->data[10] == 0x45 &&
+ marker->data[11] == 0x0;
+}
+
+
+/*
+ * See if there was an ICC profile in the JPEG file being read; if so,
+ * reassemble and return the profile data.
+ *
+ * TRUE is returned if an ICC profile was found, FALSE if not. If TRUE is
+ * returned, *icc_data_ptr is set to point to the returned data, and
+ * *icc_data_len is set to its length.
+ *
+ * IMPORTANT: the data at *icc_data_ptr is allocated with malloc() and must be
+ * freed by the caller with free() when the caller no longer needs it.
+ * (Alternatively, we could write this routine to use the IJG library's memory
+ * allocator, so that the data would be freed implicitly when
+ * jpeg_finish_decompress() is called. But it seems likely that many
+ * applications will prefer to have the data stick around after decompression
+ * finishes.)
+ */
+
+GLOBAL(boolean)
+jpeg_read_icc_profile(j_decompress_ptr cinfo, JOCTET **icc_data_ptr,
+ unsigned int *icc_data_len)
+{
+ jpeg_saved_marker_ptr marker;
+ int num_markers = 0;
+ int seq_no;
+ JOCTET *icc_data;
+ unsigned int total_length;
+#define MAX_SEQ_NO 255 /* sufficient since marker numbers are bytes */
+ char marker_present[MAX_SEQ_NO + 1]; /* 1 if marker found */
+ unsigned int data_length[MAX_SEQ_NO + 1]; /* size of profile data in marker */
+ unsigned int data_offset[MAX_SEQ_NO + 1]; /* offset for data in marker */
+
+ if (icc_data_ptr == NULL || icc_data_len == NULL)
+ ERREXIT(cinfo, JERR_BUFFER_SIZE);
+ if (cinfo->global_state < DSTATE_READY)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ *icc_data_ptr = NULL; /* avoid confusion if FALSE return */
+ *icc_data_len = 0;
+
+ /* This first pass over the saved markers discovers whether there are
+ * any ICC markers and verifies the consistency of the marker numbering.
+ */
+
+ for (seq_no = 1; seq_no <= MAX_SEQ_NO; seq_no++)
+ marker_present[seq_no] = 0;
+
+ for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
+ if (marker_is_icc(marker)) {
+ if (num_markers == 0)
+ num_markers = marker->data[13];
+ else if (num_markers != marker->data[13]) {
+ WARNMS(cinfo, JWRN_BOGUS_ICC); /* inconsistent num_markers fields */
+ return FALSE;
+ }
+ seq_no = marker->data[12];
+ if (seq_no <= 0 || seq_no > num_markers) {
+ WARNMS(cinfo, JWRN_BOGUS_ICC); /* bogus sequence number */
+ return FALSE;
+ }
+ if (marker_present[seq_no]) {
+ WARNMS(cinfo, JWRN_BOGUS_ICC); /* duplicate sequence numbers */
+ return FALSE;
+ }
+ marker_present[seq_no] = 1;
+ data_length[seq_no] = marker->data_length - ICC_OVERHEAD_LEN;
+ }
+ }
+
+ if (num_markers == 0)
+ return FALSE;
+
+ /* Check for missing markers, count total space needed,
+ * compute offset of each marker's part of the data.
+ */
+
+ total_length = 0;
+ for (seq_no = 1; seq_no <= num_markers; seq_no++) {
+ if (marker_present[seq_no] == 0) {
+ WARNMS(cinfo, JWRN_BOGUS_ICC); /* missing sequence number */
+ return FALSE;
+ }
+ data_offset[seq_no] = total_length;
+ total_length += data_length[seq_no];
+ }
+
+ if (total_length == 0) {
+ WARNMS(cinfo, JWRN_BOGUS_ICC); /* found only empty markers? */
+ return FALSE;
+ }
+
+ /* Allocate space for assembled data */
+ icc_data = (JOCTET *)malloc(total_length * sizeof(JOCTET));
+ if (icc_data == NULL)
+ ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 11); /* oops, out of memory */
+
+ /* and fill it in */
+ for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
+ if (marker_is_icc(marker)) {
+ JOCTET FAR *src_ptr;
+ JOCTET *dst_ptr;
+ unsigned int length;
+ seq_no = marker->data[12];
+ dst_ptr = icc_data + data_offset[seq_no];
+ src_ptr = marker->data + ICC_OVERHEAD_LEN;
+ length = data_length[seq_no];
+ while (length--) {
+ *dst_ptr++ = *src_ptr++;
+ }
+ }
+ }
+
+ *icc_data_ptr = icc_data;
+ *icc_data_len = total_length;
+
+ return TRUE;
+}
diff --git a/src/3rdparty/libjpeg/src/jdinput.c b/src/3rdparty/libjpeg/src/jdinput.c
index 1bc5aff1a7..136bef59d7 100644
--- a/src/3rdparty/libjpeg/src/jdinput.c
+++ b/src/3rdparty/libjpeg/src/jdinput.c
@@ -3,6 +3,8 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
* Copyright (C) 2010, 2016, 2018, 2022, D. R. Commander.
* Copyright (C) 2015, Google, Inc.
@@ -11,14 +13,15 @@
*
* This file contains input control logic for the JPEG decompressor.
* These routines are concerned with controlling the decompressor's input
- * processing (marker reading and coefficient decoding). The actual input
- * reading is done in jdmarker.c, jdhuff.c, and jdphuff.c.
+ * processing (marker reading and coefficient/difference decoding).
+ * The actual input reading is done in jdmarker.c, jdhuff.c, jdphuff.c,
+ * and jdlhuff.c.
*/
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
/* Private state */
@@ -46,6 +49,7 @@ initial_setup(j_decompress_ptr cinfo)
{
int ci;
jpeg_component_info *compptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
/* Make sure image isn't bigger than I can handle */
if ((long)cinfo->image_height > (long)JPEG_MAX_DIMENSION ||
@@ -53,7 +57,12 @@ initial_setup(j_decompress_ptr cinfo)
ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int)JPEG_MAX_DIMENSION);
/* For now, precision must match compiled-in value... */
- if (cinfo->data_precision != BITS_IN_JSAMPLE)
+#ifdef D_LOSSLESS_SUPPORTED
+ if (cinfo->data_precision != 8 && cinfo->data_precision != 12 &&
+ cinfo->data_precision != 16)
+#else
+ if (cinfo->data_precision != 8 && cinfo->data_precision != 12)
+#endif
ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
/* Check that number of components won't exceed internal array sizes */
@@ -78,36 +87,36 @@ initial_setup(j_decompress_ptr cinfo)
}
#if JPEG_LIB_VERSION >= 80
- cinfo->block_size = DCTSIZE;
+ cinfo->block_size = data_unit;
cinfo->natural_order = jpeg_natural_order;
cinfo->lim_Se = DCTSIZE2 - 1;
#endif
- /* We initialize DCT_scaled_size and min_DCT_scaled_size to DCTSIZE.
- * In the full decompressor, this will be overridden by jdmaster.c;
+ /* We initialize DCT_scaled_size and min_DCT_scaled_size to DCTSIZE in lossy
+ * mode. In the full decompressor, this will be overridden by jdmaster.c;
* but in the transcoder, jdmaster.c is not used, so we must do it here.
*/
#if JPEG_LIB_VERSION >= 70
- cinfo->min_DCT_h_scaled_size = cinfo->min_DCT_v_scaled_size = DCTSIZE;
+ cinfo->min_DCT_h_scaled_size = cinfo->min_DCT_v_scaled_size = data_unit;
#else
- cinfo->min_DCT_scaled_size = DCTSIZE;
+ cinfo->min_DCT_scaled_size = data_unit;
#endif
/* Compute dimensions of components */
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
#if JPEG_LIB_VERSION >= 70
- compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size = DCTSIZE;
+ compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size = data_unit;
#else
- compptr->DCT_scaled_size = DCTSIZE;
+ compptr->DCT_scaled_size = data_unit;
#endif
- /* Size in DCT blocks */
+ /* Size in data units */
compptr->width_in_blocks = (JDIMENSION)
jdiv_round_up((long)cinfo->image_width * (long)compptr->h_samp_factor,
- (long)(cinfo->max_h_samp_factor * DCTSIZE));
+ (long)(cinfo->max_h_samp_factor * data_unit));
compptr->height_in_blocks = (JDIMENSION)
jdiv_round_up((long)cinfo->image_height * (long)compptr->v_samp_factor,
- (long)(cinfo->max_v_samp_factor * DCTSIZE));
+ (long)(cinfo->max_v_samp_factor * data_unit));
/* Set the first and last MCU columns to decompress from multi-scan images.
* By default, decompress all of the MCU columns.
*/
@@ -133,7 +142,7 @@ initial_setup(j_decompress_ptr cinfo)
/* Compute number of fully interleaved MCU rows. */
cinfo->total_iMCU_rows = (JDIMENSION)
jdiv_round_up((long)cinfo->image_height,
- (long)(cinfo->max_v_samp_factor * DCTSIZE));
+ (long)(cinfo->max_v_samp_factor * data_unit));
/* Decide whether file contains multiple scans */
if (cinfo->comps_in_scan < cinfo->num_components || cinfo->progressive_mode)
@@ -150,6 +159,7 @@ per_scan_setup(j_decompress_ptr cinfo)
{
int ci, mcublks, tmp;
jpeg_component_info *compptr;
+ int data_unit = cinfo->master->lossless ? 1 : DCTSIZE;
if (cinfo->comps_in_scan == 1) {
@@ -160,14 +170,14 @@ per_scan_setup(j_decompress_ptr cinfo)
cinfo->MCUs_per_row = compptr->width_in_blocks;
cinfo->MCU_rows_in_scan = compptr->height_in_blocks;
- /* For noninterleaved scan, always one block per MCU */
+ /* For noninterleaved scan, always one data unit per MCU */
compptr->MCU_width = 1;
compptr->MCU_height = 1;
compptr->MCU_blocks = 1;
compptr->MCU_sample_width = compptr->_DCT_scaled_size;
compptr->last_col_width = 1;
/* For noninterleaved scans, it is convenient to define last_row_height
- * as the number of block rows present in the last iMCU row.
+ * as the number of data unit rows present in the last iMCU row.
*/
tmp = (int)(compptr->height_in_blocks % compptr->v_samp_factor);
if (tmp == 0) tmp = compptr->v_samp_factor;
@@ -187,22 +197,22 @@ per_scan_setup(j_decompress_ptr cinfo)
/* Overall image size in MCUs */
cinfo->MCUs_per_row = (JDIMENSION)
jdiv_round_up((long)cinfo->image_width,
- (long)(cinfo->max_h_samp_factor * DCTSIZE));
+ (long)(cinfo->max_h_samp_factor * data_unit));
cinfo->MCU_rows_in_scan = (JDIMENSION)
jdiv_round_up((long)cinfo->image_height,
- (long)(cinfo->max_v_samp_factor * DCTSIZE));
+ (long)(cinfo->max_v_samp_factor * data_unit));
cinfo->blocks_in_MCU = 0;
for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
compptr = cinfo->cur_comp_info[ci];
- /* Sampling factors give # of blocks of component in each MCU */
+ /* Sampling factors give # of data units of component in each MCU */
compptr->MCU_width = compptr->h_samp_factor;
compptr->MCU_height = compptr->v_samp_factor;
compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;
compptr->MCU_sample_width = compptr->MCU_width *
compptr->_DCT_scaled_size;
- /* Figure number of non-dummy blocks in last MCU column & row */
+ /* Figure number of non-dummy data units in last MCU column & row */
tmp = (int)(compptr->width_in_blocks % compptr->MCU_width);
if (tmp == 0) tmp = compptr->MCU_width;
compptr->last_col_width = tmp;
@@ -281,7 +291,8 @@ METHODDEF(void)
start_input_pass(j_decompress_ptr cinfo)
{
per_scan_setup(cinfo);
- latch_quant_tables(cinfo);
+ if (!cinfo->master->lossless)
+ latch_quant_tables(cinfo);
(*cinfo->entropy->start_pass) (cinfo);
(*cinfo->coef->start_input_pass) (cinfo);
cinfo->inputctl->consume_input = cinfo->coef->consume_data;
@@ -290,8 +301,8 @@ start_input_pass(j_decompress_ptr cinfo)
/*
* Finish up after inputting a compressed-data scan.
- * This is called by the coefficient controller after it's read all
- * the expected data of the scan.
+ * This is called by the coefficient or difference controller after it's read
+ * all the expected data of the scan.
*/
METHODDEF(void)
@@ -307,8 +318,8 @@ finish_input_pass(j_decompress_ptr cinfo)
* Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
*
* The consume_input method pointer points either here or to the
- * coefficient controller's consume_data routine, depending on whether
- * we are reading a compressed data segment or inter-segment markers.
+ * coefficient or difference controller's consume_data routine, depending on
+ * whether we are reading a compressed data segment or inter-segment markers.
*/
METHODDEF(int)
diff --git a/src/3rdparty/libjpeg/src/jdlhuff.c b/src/3rdparty/libjpeg/src/jdlhuff.c
new file mode 100644
index 0000000000..9964830dba
--- /dev/null
+++ b/src/3rdparty/libjpeg/src/jdlhuff.c
@@ -0,0 +1,302 @@
+/*
+ * jdlhuff.c
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file contains Huffman entropy decoding routines for lossless JPEG.
+ *
+ * Much of the complexity here has to do with supporting input suspension.
+ * If the data source module demands suspension, we want to be able to back
+ * up to the start of the current MCU. To do this, we copy state variables
+ * into local working storage, and update them back to the permanent
+ * storage only upon successful completion of an MCU.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jlossls.h" /* Private declarations for lossless codec */
+#include "jdhuff.h" /* Declarations shared with jd*huff.c */
+
+
+#ifdef D_LOSSLESS_SUPPORTED
+
+typedef struct {
+ int ci, yoffset, MCU_width;
+} lhd_output_ptr_info;
+
+/*
+ * Expanded entropy decoder object for Huffman decoding in lossless mode.
+ */
+
+typedef struct {
+ struct jpeg_entropy_decoder pub; /* public fields */
+
+ /* These fields are loaded into local variables at start of each MCU.
+ * In case of suspension, we exit WITHOUT updating them.
+ */
+ bitread_perm_state bitstate; /* Bit buffer at start of MCU */
+
+ /* Pointers to derived tables (these workspaces have image lifespan) */
+ d_derived_tbl *derived_tbls[NUM_HUFF_TBLS];
+
+ /* Precalculated info set up by start_pass for use in decode_mcus: */
+
+ /* Pointers to derived tables to be used for each data unit within an MCU */
+ d_derived_tbl *cur_tbls[D_MAX_BLOCKS_IN_MCU];
+
+ /* Pointers to the proper output difference row for each group of data units
+ * within an MCU. For each component, there are Vi groups of Hi data units.
+ */
+ JDIFFROW output_ptr[D_MAX_BLOCKS_IN_MCU];
+
+ /* Number of output pointers in use for the current MCU. This is the sum
+ * of all Vi in the MCU.
+ */
+ int num_output_ptrs;
+
+ /* Information used for positioning the output pointers within the output
+ * difference rows.
+ */
+ lhd_output_ptr_info output_ptr_info[D_MAX_BLOCKS_IN_MCU];
+
+ /* Index of the proper output pointer for each data unit within an MCU */
+ int output_ptr_index[D_MAX_BLOCKS_IN_MCU];
+
+} lhuff_entropy_decoder;
+
+typedef lhuff_entropy_decoder *lhuff_entropy_ptr;
+
+
+/*
+ * Initialize for a Huffman-compressed scan.
+ */
+
+METHODDEF(void)
+start_pass_lhuff_decoder(j_decompress_ptr cinfo)
+{
+ lhuff_entropy_ptr entropy = (lhuff_entropy_ptr)cinfo->entropy;
+ int ci, dctbl, sampn, ptrn, yoffset, xoffset;
+ jpeg_component_info *compptr;
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ dctbl = compptr->dc_tbl_no;
+ /* Make sure requested tables are present */
+ if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS ||
+ cinfo->dc_huff_tbl_ptrs[dctbl] == NULL)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl);
+ /* Compute derived values for Huffman tables */
+ /* We may do this more than once for a table, but it's not expensive */
+ jpeg_make_d_derived_tbl(cinfo, TRUE, dctbl,
+ &entropy->derived_tbls[dctbl]);
+ }
+
+ /* Precalculate decoding info for each sample in an MCU of this scan */
+ for (sampn = 0, ptrn = 0; sampn < cinfo->blocks_in_MCU;) {
+ compptr = cinfo->cur_comp_info[cinfo->MCU_membership[sampn]];
+ ci = compptr->component_index;
+ for (yoffset = 0; yoffset < compptr->MCU_height; yoffset++, ptrn++) {
+ /* Precalculate the setup info for each output pointer */
+ entropy->output_ptr_info[ptrn].ci = ci;
+ entropy->output_ptr_info[ptrn].yoffset = yoffset;
+ entropy->output_ptr_info[ptrn].MCU_width = compptr->MCU_width;
+ for (xoffset = 0; xoffset < compptr->MCU_width; xoffset++, sampn++) {
+ /* Precalculate the output pointer index for each sample */
+ entropy->output_ptr_index[sampn] = ptrn;
+ /* Precalculate which table to use for each sample */
+ entropy->cur_tbls[sampn] = entropy->derived_tbls[compptr->dc_tbl_no];
+ }
+ }
+ }
+ entropy->num_output_ptrs = ptrn;
+
+ /* Initialize bitread state variables */
+ entropy->bitstate.bits_left = 0;
+ entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */
+ entropy->pub.insufficient_data = FALSE;
+}
+
+
+/*
+ * Figure F.12: extend sign bit.
+ * On some machines, a shift and add will be faster than a table lookup.
+ */
+
+#define AVOID_TABLES
+#ifdef AVOID_TABLES
+
+#define NEG_1 ((unsigned int)-1)
+#define HUFF_EXTEND(x, s) \
+ ((x) + ((((x) - (1 << ((s) - 1))) >> 31) & (((NEG_1) << (s)) + 1)))
+
+#else
+
+#define HUFF_EXTEND(x, s) \
+ ((x) < extend_test[s] ? (x) + extend_offset[s] : (x))
+
+static const int extend_test[16] = { /* entry n is 2**(n-1) */
+ 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
+ 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000
+};
+
+static const int extend_offset[16] = { /* entry n is (-1 << n) + 1 */
+ 0, ((-1) << 1) + 1, ((-1) << 2) + 1, ((-1) << 3) + 1, ((-1) << 4) + 1,
+ ((-1) << 5) + 1, ((-1) << 6) + 1, ((-1) << 7) + 1, ((-1) << 8) + 1,
+ ((-1) << 9) + 1, ((-1) << 10) + 1, ((-1) << 11) + 1, ((-1) << 12) + 1,
+ ((-1) << 13) + 1, ((-1) << 14) + 1, ((-1) << 15) + 1
+};
+
+#endif /* AVOID_TABLES */
+
+
+/*
+ * Check for a restart marker & resynchronize decoder.
+ * Returns FALSE if must suspend.
+ */
+
+LOCAL(boolean)
+process_restart(j_decompress_ptr cinfo)
+{
+ lhuff_entropy_ptr entropy = (lhuff_entropy_ptr)cinfo->entropy;
+
+ /* Throw away any unused bits remaining in bit buffer; */
+ /* include any full bytes in next_marker's count of discarded bytes */
+ cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8;
+ entropy->bitstate.bits_left = 0;
+
+ /* Advance past the RSTn marker */
+ if (!(*cinfo->marker->read_restart_marker) (cinfo))
+ return FALSE;
+
+ /* Reset out-of-data flag, unless read_restart_marker left us smack up
+ * against a marker. In that case we will end up treating the next data
+ * segment as empty, and we can avoid producing bogus output pixels by
+ * leaving the flag set.
+ */
+ if (cinfo->unread_marker == 0)
+ entropy->pub.insufficient_data = FALSE;
+
+ return TRUE;
+}
+
+
+/*
+ * Decode and return nMCU MCUs' worth of Huffman-compressed differences.
+ * Each MCU is also disassembled and placed accordingly in diff_buf.
+ *
+ * MCU_col_num specifies the column of the first MCU being requested within
+ * the MCU row. This tells us where to position the output row pointers in
+ * diff_buf.
+ *
+ * Returns the number of MCUs decoded. This may be less than nMCU MCUs if
+ * data source requested suspension. In that case no changes have been made
+ * to permanent state. (Exception: some output differences may already have
+ * been assigned. This is harmless for this module, since we'll just
+ * re-assign them on the next call.)
+ */
+
+METHODDEF(JDIMENSION)
+decode_mcus(j_decompress_ptr cinfo, JDIFFIMAGE diff_buf,
+ JDIMENSION MCU_row_num, JDIMENSION MCU_col_num, JDIMENSION nMCU)
+{
+ lhuff_entropy_ptr entropy = (lhuff_entropy_ptr)cinfo->entropy;
+ int sampn, ci, yoffset, MCU_width, ptrn;
+ JDIMENSION mcu_num;
+ BITREAD_STATE_VARS;
+
+ /* Set output pointer locations based on MCU_col_num */
+ for (ptrn = 0; ptrn < entropy->num_output_ptrs; ptrn++) {
+ ci = entropy->output_ptr_info[ptrn].ci;
+ yoffset = entropy->output_ptr_info[ptrn].yoffset;
+ MCU_width = entropy->output_ptr_info[ptrn].MCU_width;
+ entropy->output_ptr[ptrn] =
+ diff_buf[ci][MCU_row_num + yoffset] + (MCU_col_num * MCU_width);
+ }
+
+ /*
+ * If we've run out of data, zero out the buffers and return.
+ * By resetting the undifferencer, the output samples will be CENTERJSAMPLE.
+ *
+ * NB: We should find a way to do this without interacting with the
+ * undifferencer module directly.
+ */
+ if (entropy->pub.insufficient_data) {
+ for (ptrn = 0; ptrn < entropy->num_output_ptrs; ptrn++)
+ jzero_far((void FAR *)entropy->output_ptr[ptrn],
+ nMCU * entropy->output_ptr_info[ptrn].MCU_width *
+ sizeof(JDIFF));
+
+ (*cinfo->idct->start_pass) (cinfo);
+
+ } else {
+
+ /* Load up working state */
+ BITREAD_LOAD_STATE(cinfo, entropy->bitstate);
+
+ /* Outer loop handles the number of MCUs requested */
+
+ for (mcu_num = 0; mcu_num < nMCU; mcu_num++) {
+
+ /* Inner loop handles the samples in the MCU */
+ for (sampn = 0; sampn < cinfo->blocks_in_MCU; sampn++) {
+ d_derived_tbl *dctbl = entropy->cur_tbls[sampn];
+ register int s, r;
+
+ /* Section H.2.2: decode the sample difference */
+ HUFF_DECODE(s, br_state, dctbl, return mcu_num, label1);
+ if (s) {
+ if (s == 16) /* special case: always output 32768 */
+ s = 32768;
+ else { /* normal case: fetch subsequent bits */
+ CHECK_BIT_BUFFER(br_state, s, return mcu_num);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ }
+ }
+
+ /* Output the sample difference */
+ *entropy->output_ptr[entropy->output_ptr_index[sampn]]++ = (JDIFF)s;
+ }
+
+ /* Completed MCU, so update state */
+ BITREAD_SAVE_STATE(cinfo, entropy->bitstate);
+ }
+ }
+
+ return nMCU;
+}
+
+
+/*
+ * Module initialization routine for lossless mode Huffman entropy decoding.
+ */
+
+GLOBAL(void)
+jinit_lhuff_decoder(j_decompress_ptr cinfo)
+{
+ lhuff_entropy_ptr entropy;
+ int i;
+
+ entropy = (lhuff_entropy_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
+ sizeof(lhuff_entropy_decoder));
+ cinfo->entropy = (struct jpeg_entropy_decoder *)entropy;
+ entropy->pub.start_pass = start_pass_lhuff_decoder;
+ entropy->pub.decode_mcus = decode_mcus;
+ entropy->pub.process_restart = process_restart;
+
+ /* Mark tables unallocated */
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ entropy->derived_tbls[i] = NULL;
+ }
+}
+
+#endif /* D_LOSSLESS_SUPPORTED */
diff --git a/src/3rdparty/libjpeg/src/jdlossls.c b/src/3rdparty/libjpeg/src/jdlossls.c
new file mode 100644
index 0000000000..4d15e6bbaf
--- /dev/null
+++ b/src/3rdparty/libjpeg/src/jdlossls.c
@@ -0,0 +1,289 @@
+/*
+ * jdlossls.c
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1998, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This file contains prediction, sample undifferencing, point transform, and
+ * sample scaling routines for the lossless JPEG decompressor.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jlossls.h"
+
+#ifdef D_LOSSLESS_SUPPORTED
+
+
+/**************** Sample undifferencing (reconstruction) *****************/
+
+/*
+ * In order to avoid a performance penalty for checking which predictor is
+ * being used and which row is being processed for each call of the
+ * undifferencer, and to promote optimization, we have separate undifferencing
+ * functions for each predictor selection value.
+ *
+ * We are able to avoid duplicating source code by implementing the predictors
+ * and undifferencers as macros. Each of the undifferencing functions is
+ * simply a wrapper around an UNDIFFERENCE macro with the appropriate PREDICTOR
+ * macro passed as an argument.
+ */
+
+/* Predictor for the first column of the first row: 2^(P-Pt-1) */
+#define INITIAL_PREDICTORx (1 << (cinfo->data_precision - cinfo->Al - 1))
+
+/* Predictor for the first column of the remaining rows: Rb */
+#define INITIAL_PREDICTOR2 prev_row[0]
+
+
+/*
+ * 1-Dimensional undifferencer routine.
+ *
+ * This macro implements the 1-D horizontal predictor (1). INITIAL_PREDICTOR
+ * is used as the special case predictor for the first column, which must be
+ * either INITIAL_PREDICTOR2 or INITIAL_PREDICTORx. The remaining samples
+ * use PREDICTOR1.
+ *
+ * The reconstructed sample is supposed to be calculated modulo 2^16, so we
+ * logically AND the result with 0xFFFF.
+ */
+
+#define UNDIFFERENCE_1D(INITIAL_PREDICTOR) \
+ int Ra; \
+ \
+ Ra = (*diff_buf++ + INITIAL_PREDICTOR) & 0xFFFF; \
+ *undiff_buf++ = Ra; \
+ \
+ while (--width) { \
+ Ra = (*diff_buf++ + PREDICTOR1) & 0xFFFF; \
+ *undiff_buf++ = Ra; \
+ }
+
+
+/*
+ * 2-Dimensional undifferencer routine.
+ *
+ * This macro implements the 2-D horizontal predictors (#2-7). PREDICTOR2 is
+ * used as the special case predictor for the first column. The remaining
+ * samples use PREDICTOR, which is a function of Ra, Rb, and Rc.
+ *
+ * Because prev_row and output_buf may point to the same storage area (in an
+ * interleaved image with Vi=1, for example), we must take care to buffer Rb/Rc
+ * before writing the current reconstructed sample value into output_buf.
+ *
+ * The reconstructed sample is supposed to be calculated modulo 2^16, so we
+ * logically AND the result with 0xFFFF.
+ */
+
+#define UNDIFFERENCE_2D(PREDICTOR) \
+ int Ra, Rb, Rc; \
+ \
+ Rb = *prev_row++; \
+ Ra = (*diff_buf++ + PREDICTOR2) & 0xFFFF; \
+ *undiff_buf++ = Ra; \
+ \
+ while (--width) { \
+ Rc = Rb; \
+ Rb = *prev_row++; \
+ Ra = (*diff_buf++ + PREDICTOR) & 0xFFFF; \
+ *undiff_buf++ = Ra; \
+ }
+
+
+/*
+ * Undifferencers for the second and subsequent rows in a scan or restart
+ * interval. The first sample in the row is undifferenced using the vertical
+ * predictor (2). The rest of the samples are undifferenced using the
+ * predictor specified in the scan header.
+ */
+
+METHODDEF(void)
+jpeg_undifference1(j_decompress_ptr cinfo, int comp_index,
+ JDIFFROW diff_buf, JDIFFROW prev_row,
+ JDIFFROW undiff_buf, JDIMENSION width)
+{
+ UNDIFFERENCE_1D(INITIAL_PREDICTOR2);
+}
+
+METHODDEF(void)
+jpeg_undifference2(j_decompress_ptr cinfo, int comp_index,
+ JDIFFROW diff_buf, JDIFFROW prev_row,
+ JDIFFROW undiff_buf, JDIMENSION width)
+{
+ UNDIFFERENCE_2D(PREDICTOR2);
+ (void)(Rc);
+}
+
+METHODDEF(void)
+jpeg_undifference3(j_decompress_ptr cinfo, int comp_index,
+ JDIFFROW diff_buf, JDIFFROW prev_row,
+ JDIFFROW undiff_buf, JDIMENSION width)
+{
+ UNDIFFERENCE_2D(PREDICTOR3);
+}
+
+METHODDEF(void)
+jpeg_undifference4(j_decompress_ptr cinfo, int comp_index,
+ JDIFFROW diff_buf, JDIFFROW prev_row,
+ JDIFFROW undiff_buf, JDIMENSION width)
+{
+ UNDIFFERENCE_2D(PREDICTOR4);
+}
+
+METHODDEF(void)
+jpeg_undifference5(j_decompress_ptr cinfo, int comp_index,
+ JDIFFROW diff_buf, JDIFFROW prev_row,
+ JDIFFROW undiff_buf, JDIMENSION width)
+{
+ UNDIFFERENCE_2D(PREDICTOR5);
+}
+
+METHODDEF(void)
+jpeg_undifference6(j_decompress_ptr cinfo, int comp_index,
+ JDIFFROW diff_buf, JDIFFROW prev_row,
+ JDIFFROW undiff_buf, JDIMENSION width)
+{
+ UNDIFFERENCE_2D(PREDICTOR6);
+}
+
+METHODDEF(void)
+jpeg_undifference7(j_decompress_ptr cinfo, int comp_index,
+ JDIFFROW diff_buf, JDIFFROW prev_row,
+ JDIFFROW undiff_buf, JDIMENSION width)
+{
+ UNDIFFERENCE_2D(PREDICTOR7);
+ (void)(Rc);
+}
+
+
+/*
+ * Undifferencer for the first row in a scan or restart interval. The first
+ * sample in the row is undifferenced using the special predictor constant
+ * x=2^(P-Pt-1). The rest of the samples are undifferenced using the
+ * 1-D horizontal predictor (1).
+ */
+
+METHODDEF(void)
+jpeg_undifference_first_row(j_decompress_ptr cinfo, int comp_index,
+ JDIFFROW diff_buf, JDIFFROW prev_row,
+ JDIFFROW undiff_buf, JDIMENSION width)
+{
+ lossless_decomp_ptr losslessd = (lossless_decomp_ptr)cinfo->idct;
+
+ UNDIFFERENCE_1D(INITIAL_PREDICTORx);
+
+ /*
+ * Now that we have undifferenced the first row, we want to use the
+ * undifferencer that corresponds to the predictor specified in the
+ * scan header.
+ */
+ switch (cinfo->Ss) {
+ case 1:
+ losslessd->predict_undifference[comp_index] = jpeg_undifference1;
+ break;
+ case 2:
+ losslessd->predict_undifference[comp_index] = jpeg_undifference2;
+ break;
+ case 3:
+ losslessd->predict_undifference[comp_index] = jpeg_undifference3;
+ break;
+ case 4:
+ losslessd->predict_undifference[comp_index] = jpeg_undifference4;
+ break;
+ case 5:
+ losslessd->predict_undifference[comp_index] = jpeg_undifference5;
+ break;
+ case 6:
+ losslessd->predict_undifference[comp_index] = jpeg_undifference6;
+ break;
+ case 7:
+ losslessd->predict_undifference[comp_index] = jpeg_undifference7;
+ break;
+ }
+}
+
+
+/*********************** Sample upscaling by 2^Pt ************************/
+
+METHODDEF(void)
+simple_upscale(j_decompress_ptr cinfo,
+ JDIFFROW diff_buf, _JSAMPROW output_buf, JDIMENSION width)
+{
+ do {
+ *output_buf++ = (_JSAMPLE)(*diff_buf++ << cinfo->Al);
+ } while (--width);
+}
+
+METHODDEF(void)
+noscale(j_decompress_ptr cinfo,
+ JDIFFROW diff_buf, _JSAMPROW output_buf, JDIMENSION width)
+{
+ do {
+ *output_buf++ = (_JSAMPLE)(*diff_buf++);
+ } while (--width);
+}
+
+
+/*
+ * Initialize for an input processing pass.
+ */
+
+METHODDEF(void)
+start_pass_lossless(j_decompress_ptr cinfo)
+{
+ lossless_decomp_ptr losslessd = (lossless_decomp_ptr)cinfo->idct;
+ int ci;
+
+ /* Check that the scan parameters Ss, Se, Ah, Al are OK for lossless JPEG.
+ *
+ * Ss is the predictor selection value (psv). Legal values for sequential
+ * lossless JPEG are: 1 <= psv <= 7.
+ *
+ * Se and Ah are not used and should be zero.
+ *
+ * Al specifies the point transform (Pt).
+ * Legal values are: 0 <= Pt <= (data precision - 1).
+ */
+ if (cinfo->Ss < 1 || cinfo->Ss > 7 ||
+ cinfo->Se != 0 || cinfo->Ah != 0 ||
+ cinfo->Al < 0 || cinfo->Al >= cinfo->data_precision)
+ ERREXIT4(cinfo, JERR_BAD_PROGRESSION,
+ cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
+
+ /* Set undifference functions to first row function */
+ for (ci = 0; ci < cinfo->num_components; ci++)
+ losslessd->predict_undifference[ci] = jpeg_undifference_first_row;
+
+ /* Set scaler function based on Pt */
+ if (cinfo->Al)
+ losslessd->scaler_scale = simple_upscale;
+ else
+ losslessd->scaler_scale = noscale;
+}
+
+
+/*
+ * Initialize the lossless decompressor.
+ */
+
+GLOBAL(void)
+_jinit_lossless_decompressor(j_decompress_ptr cinfo)
+{
+ lossless_decomp_ptr losslessd;
+
+ /* Create subobject in permanent pool */
+ losslessd = (lossless_decomp_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_PERMANENT,
+ sizeof(jpeg_lossless_decompressor));
+ cinfo->idct = (struct jpeg_inverse_dct *)losslessd;
+ losslessd->pub.start_pass = start_pass_lossless;
+}
+
+#endif /* D_LOSSLESS_SUPPORTED */
diff --git a/src/3rdparty/libjpeg/src/jdmainct.c b/src/3rdparty/libjpeg/src/jdmainct.c
index d332e6b2fa..c672b4baf5 100644
--- a/src/3rdparty/libjpeg/src/jdmainct.c
+++ b/src/3rdparty/libjpeg/src/jdmainct.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2016, D. R. Commander.
+ * Copyright (C) 2010, 2016, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -20,12 +20,15 @@
#include "jdmainct.h"
+#if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)
+
/*
* In the current system design, the main buffer need never be a full-image
- * buffer; any full-height buffers will be found inside the coefficient or
- * postprocessing controllers. Nonetheless, the main controller is not
- * trivial. Its responsibility is to provide context rows for upsampling/
- * rescaling, and doing this in an efficient fashion is a bit tricky.
+ * buffer; any full-height buffers will be found inside the coefficient,
+ * difference, or postprocessing controllers. Nonetheless, the main controller
+ * is not trivial. Its responsibility is to provide context rows for
+ * upsampling/rescaling, and doing this in an efficient fashion is a bit
+ * tricky.
*
* Postprocessor input data is counted in "row groups". A row group
* is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size)
@@ -37,20 +40,20 @@
* row group (times any additional scale factor that the upsampler is
* applying).
*
- * The coefficient controller will deliver data to us one iMCU row at a time;
- * each iMCU row contains v_samp_factor * DCT_scaled_size sample rows, or
- * exactly min_DCT_scaled_size row groups. (This amount of data corresponds
- * to one row of MCUs when the image is fully interleaved.) Note that the
- * number of sample rows varies across components, but the number of row
- * groups does not. Some garbage sample rows may be included in the last iMCU
- * row at the bottom of the image.
+ * The coefficient or difference controller will deliver data to us one iMCU
+ * row at a time; each iMCU row contains v_samp_factor * DCT_scaled_size sample
+ * rows, or exactly min_DCT_scaled_size row groups. (This amount of data
+ * corresponds to one row of MCUs when the image is fully interleaved.) Note
+ * that the number of sample rows varies across components, but the number of
+ * row groups does not. Some garbage sample rows may be included in the last
+ * iMCU row at the bottom of the image.
*
* Depending on the vertical scaling algorithm used, the upsampler may need
* access to the sample row(s) above and below its current input row group.
* The upsampler is required to set need_context_rows TRUE at global selection
* time if so. When need_context_rows is FALSE, this controller can simply
- * obtain one iMCU row at a time from the coefficient controller and dole it
- * out as row groups to the postprocessor.
+ * obtain one iMCU row at a time from the coefficient or difference controller
+ * and dole it out as row groups to the postprocessor.
*
* When need_context_rows is TRUE, this controller guarantees that the buffer
* passed to postprocessing contains at least one row group's worth of samples
@@ -113,16 +116,16 @@
/* Forward declarations */
METHODDEF(void) process_data_simple_main(j_decompress_ptr cinfo,
- JSAMPARRAY output_buf,
+ _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail);
METHODDEF(void) process_data_context_main(j_decompress_ptr cinfo,
- JSAMPARRAY output_buf,
+ _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail);
#ifdef QUANT_2PASS_SUPPORTED
METHODDEF(void) process_data_crank_post(j_decompress_ptr cinfo,
- JSAMPARRAY output_buf,
+ _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail);
#endif
@@ -138,14 +141,15 @@ alloc_funny_pointers(j_decompress_ptr cinfo)
int ci, rgroup;
int M = cinfo->_min_DCT_scaled_size;
jpeg_component_info *compptr;
- JSAMPARRAY xbuf;
+ _JSAMPARRAY xbuf;
/* Get top-level space for component array pointers.
* We alloc both arrays with one call to save a few cycles.
*/
- main_ptr->xbuffer[0] = (JSAMPIMAGE)
+ main_ptr->xbuffer[0] = (_JSAMPIMAGE)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- cinfo->num_components * 2 * sizeof(JSAMPARRAY));
+ cinfo->num_components * 2 *
+ sizeof(_JSAMPARRAY));
main_ptr->xbuffer[1] = main_ptr->xbuffer[0] + cinfo->num_components;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
@@ -155,9 +159,9 @@ alloc_funny_pointers(j_decompress_ptr cinfo)
/* Get space for pointer lists --- M+4 row groups in each list.
* We alloc both pointer lists with one call to save a few cycles.
*/
- xbuf = (JSAMPARRAY)
+ xbuf = (_JSAMPARRAY)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- 2 * (rgroup * (M + 4)) * sizeof(JSAMPROW));
+ 2 * (rgroup * (M + 4)) * sizeof(_JSAMPROW));
xbuf += rgroup; /* want one row group at negative offsets */
main_ptr->xbuffer[0][ci] = xbuf;
xbuf += rgroup * (M + 4);
@@ -179,7 +183,7 @@ make_funny_pointers(j_decompress_ptr cinfo)
int ci, i, rgroup;
int M = cinfo->_min_DCT_scaled_size;
jpeg_component_info *compptr;
- JSAMPARRAY buf, xbuf0, xbuf1;
+ _JSAMPARRAY buf, xbuf0, xbuf1;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
@@ -219,7 +223,7 @@ set_bottom_pointers(j_decompress_ptr cinfo)
my_main_ptr main_ptr = (my_main_ptr)cinfo->main;
int ci, i, rgroup, iMCUheight, rows_left;
jpeg_component_info *compptr;
- JSAMPARRAY xbuf;
+ _JSAMPARRAY xbuf;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
@@ -258,14 +262,14 @@ start_pass_main(j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
switch (pass_mode) {
case JBUF_PASS_THRU:
if (cinfo->upsample->need_context_rows) {
- main_ptr->pub.process_data = process_data_context_main;
+ main_ptr->pub._process_data = process_data_context_main;
make_funny_pointers(cinfo); /* Create the xbuffer[] lists */
main_ptr->whichptr = 0; /* Read first iMCU row into xbuffer[0] */
main_ptr->context_state = CTX_PREPARE_FOR_IMCU;
main_ptr->iMCU_row_ctr = 0;
} else {
/* Simple case with no context needed */
- main_ptr->pub.process_data = process_data_simple_main;
+ main_ptr->pub._process_data = process_data_simple_main;
}
main_ptr->buffer_full = FALSE; /* Mark buffer empty */
main_ptr->rowgroup_ctr = 0;
@@ -273,7 +277,7 @@ start_pass_main(j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
#ifdef QUANT_2PASS_SUPPORTED
case JBUF_CRANK_DEST:
/* For last pass of 2-pass quantization, just crank the postprocessor */
- main_ptr->pub.process_data = process_data_crank_post;
+ main_ptr->pub._process_data = process_data_crank_post;
break;
#endif
default:
@@ -289,7 +293,7 @@ start_pass_main(j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
*/
METHODDEF(void)
-process_data_simple_main(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
+process_data_simple_main(j_decompress_ptr cinfo, _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)
{
my_main_ptr main_ptr = (my_main_ptr)cinfo->main;
@@ -297,7 +301,7 @@ process_data_simple_main(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
/* Read input data if we haven't filled the main buffer yet */
if (!main_ptr->buffer_full) {
- if (!(*cinfo->coef->decompress_data) (cinfo, main_ptr->buffer))
+ if (!(*cinfo->coef->_decompress_data) (cinfo, main_ptr->buffer))
return; /* suspension forced, can do nothing more */
main_ptr->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
}
@@ -310,9 +314,9 @@ process_data_simple_main(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
*/
/* Feed the postprocessor */
- (*cinfo->post->post_process_data) (cinfo, main_ptr->buffer,
- &main_ptr->rowgroup_ctr, rowgroups_avail,
- output_buf, out_row_ctr, out_rows_avail);
+ (*cinfo->post->_post_process_data) (cinfo, main_ptr->buffer,
+ &main_ptr->rowgroup_ctr, rowgroups_avail,
+ output_buf, out_row_ctr, out_rows_avail);
/* Has postprocessor consumed all the data yet? If so, mark buffer empty */
if (main_ptr->rowgroup_ctr >= rowgroups_avail) {
@@ -328,15 +332,15 @@ process_data_simple_main(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
*/
METHODDEF(void)
-process_data_context_main(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
+process_data_context_main(j_decompress_ptr cinfo, _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)
{
my_main_ptr main_ptr = (my_main_ptr)cinfo->main;
/* Read input data if we haven't filled the main buffer yet */
if (!main_ptr->buffer_full) {
- if (!(*cinfo->coef->decompress_data) (cinfo,
- main_ptr->xbuffer[main_ptr->whichptr]))
+ if (!(*cinfo->coef->_decompress_data) (cinfo,
+ main_ptr->xbuffer[main_ptr->whichptr]))
return; /* suspension forced, can do nothing more */
main_ptr->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
main_ptr->iMCU_row_ctr++; /* count rows received */
@@ -350,11 +354,11 @@ process_data_context_main(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
switch (main_ptr->context_state) {
case CTX_POSTPONED_ROW:
/* Call postprocessor using previously set pointers for postponed row */
- (*cinfo->post->post_process_data) (cinfo,
- main_ptr->xbuffer[main_ptr->whichptr],
- &main_ptr->rowgroup_ctr,
- main_ptr->rowgroups_avail, output_buf,
- out_row_ctr, out_rows_avail);
+ (*cinfo->post->_post_process_data) (cinfo,
+ main_ptr->xbuffer[main_ptr->whichptr],
+ &main_ptr->rowgroup_ctr,
+ main_ptr->rowgroups_avail, output_buf,
+ out_row_ctr, out_rows_avail);
if (main_ptr->rowgroup_ctr < main_ptr->rowgroups_avail)
return; /* Need to suspend */
main_ptr->context_state = CTX_PREPARE_FOR_IMCU;
@@ -374,11 +378,11 @@ process_data_context_main(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
FALLTHROUGH /*FALLTHROUGH*/
case CTX_PROCESS_IMCU:
/* Call postprocessor using previously set pointers */
- (*cinfo->post->post_process_data) (cinfo,
- main_ptr->xbuffer[main_ptr->whichptr],
- &main_ptr->rowgroup_ctr,
- main_ptr->rowgroups_avail, output_buf,
- out_row_ctr, out_rows_avail);
+ (*cinfo->post->_post_process_data) (cinfo,
+ main_ptr->xbuffer[main_ptr->whichptr],
+ &main_ptr->rowgroup_ctr,
+ main_ptr->rowgroups_avail, output_buf,
+ out_row_ctr, out_rows_avail);
if (main_ptr->rowgroup_ctr < main_ptr->rowgroups_avail)
return; /* Need to suspend */
/* After the first iMCU, change wraparound pointers to normal state */
@@ -405,12 +409,12 @@ process_data_context_main(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
#ifdef QUANT_2PASS_SUPPORTED
METHODDEF(void)
-process_data_crank_post(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
+process_data_crank_post(j_decompress_ptr cinfo, _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)
{
- (*cinfo->post->post_process_data) (cinfo, (JSAMPIMAGE)NULL,
- (JDIMENSION *)NULL, (JDIMENSION)0,
- output_buf, out_row_ctr, out_rows_avail);
+ (*cinfo->post->_post_process_data) (cinfo, (_JSAMPIMAGE)NULL,
+ (JDIMENSION *)NULL, (JDIMENSION)0,
+ output_buf, out_row_ctr, out_rows_avail);
}
#endif /* QUANT_2PASS_SUPPORTED */
@@ -421,12 +425,15 @@ process_data_crank_post(j_decompress_ptr cinfo, JSAMPARRAY output_buf,
*/
GLOBAL(void)
-jinit_d_main_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
+_jinit_d_main_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
{
my_main_ptr main_ptr;
int ci, rgroup, ngroups;
jpeg_component_info *compptr;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
main_ptr = (my_main_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_main_controller));
@@ -452,9 +459,11 @@ jinit_d_main_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
ci++, compptr++) {
rgroup = (compptr->v_samp_factor * compptr->_DCT_scaled_size) /
cinfo->_min_DCT_scaled_size; /* height of a row group of component */
- main_ptr->buffer[ci] = (*cinfo->mem->alloc_sarray)
+ main_ptr->buffer[ci] = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE,
compptr->width_in_blocks * compptr->_DCT_scaled_size,
(JDIMENSION)(rgroup * ngroups));
}
}
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */
diff --git a/src/3rdparty/libjpeg/src/jdmainct.h b/src/3rdparty/libjpeg/src/jdmainct.h
index 37b201ca88..914ad11f69 100644
--- a/src/3rdparty/libjpeg/src/jdmainct.h
+++ b/src/3rdparty/libjpeg/src/jdmainct.h
@@ -3,22 +3,27 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*/
#define JPEG_INTERNALS
#include "jpeglib.h"
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
+#include "jsamplecomp.h"
+#if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)
+
/* Private buffer controller object */
typedef struct {
struct jpeg_d_main_controller pub; /* public fields */
/* Pointer to allocated workspace (M or M+2 row groups). */
- JSAMPARRAY buffer[MAX_COMPONENTS];
+ _JSAMPARRAY buffer[MAX_COMPONENTS];
boolean buffer_full; /* Have we gotten an iMCU row from decoder? */
JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */
@@ -26,7 +31,7 @@ typedef struct {
/* Remaining fields are only used in the context case. */
/* These are the master pointers to the funny-order pointer lists. */
- JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */
+ _JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */
int whichptr; /* indicates which pointer set is now in use */
int context_state; /* process_data state machine status */
@@ -53,7 +58,7 @@ set_wraparound_pointers(j_decompress_ptr cinfo)
int ci, i, rgroup;
int M = cinfo->_min_DCT_scaled_size;
jpeg_component_info *compptr;
- JSAMPARRAY xbuf0, xbuf1;
+ _JSAMPARRAY xbuf0, xbuf1;
for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
ci++, compptr++) {
@@ -69,3 +74,5 @@ set_wraparound_pointers(j_decompress_ptr cinfo)
}
}
}
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */
diff --git a/src/3rdparty/libjpeg/src/jdmarker.c b/src/3rdparty/libjpeg/src/jdmarker.c
index f7eba615fd..acd28ce62c 100644
--- a/src/3rdparty/libjpeg/src/jdmarker.c
+++ b/src/3rdparty/libjpeg/src/jdmarker.c
@@ -3,6 +3,8 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
* Copyright (C) 2012, 2015, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
@@ -237,7 +239,8 @@ get_soi(j_decompress_ptr cinfo)
LOCAL(boolean)
-get_sof(j_decompress_ptr cinfo, boolean is_prog, boolean is_arith)
+get_sof(j_decompress_ptr cinfo, boolean is_prog, boolean is_lossless,
+ boolean is_arith)
/* Process a SOFn marker */
{
JLONG length;
@@ -246,6 +249,7 @@ get_sof(j_decompress_ptr cinfo, boolean is_prog, boolean is_arith)
INPUT_VARS(cinfo);
cinfo->progressive_mode = is_prog;
+ cinfo->master->lossless = is_lossless;
cinfo->arith_code = is_arith;
INPUT_2BYTES(cinfo, length, return FALSE);
@@ -990,32 +994,40 @@ read_markers(j_decompress_ptr cinfo)
case M_SOF0: /* Baseline */
case M_SOF1: /* Extended sequential, Huffman */
- if (!get_sof(cinfo, FALSE, FALSE))
+ if (!get_sof(cinfo, FALSE, FALSE, FALSE))
return JPEG_SUSPENDED;
break;
case M_SOF2: /* Progressive, Huffman */
- if (!get_sof(cinfo, TRUE, FALSE))
+ if (!get_sof(cinfo, TRUE, FALSE, FALSE))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF3: /* Lossless, Huffman */
+ if (!get_sof(cinfo, FALSE, TRUE, FALSE))
return JPEG_SUSPENDED;
break;
case M_SOF9: /* Extended sequential, arithmetic */
- if (!get_sof(cinfo, FALSE, TRUE))
+ if (!get_sof(cinfo, FALSE, FALSE, TRUE))
return JPEG_SUSPENDED;
break;
case M_SOF10: /* Progressive, arithmetic */
- if (!get_sof(cinfo, TRUE, TRUE))
+ if (!get_sof(cinfo, TRUE, FALSE, TRUE))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF11: /* Lossless, arithmetic */
+ if (!get_sof(cinfo, FALSE, TRUE, TRUE))
return JPEG_SUSPENDED;
break;
/* Currently unsupported SOFn types */
- case M_SOF3: /* Lossless, Huffman */
case M_SOF5: /* Differential sequential, Huffman */
case M_SOF6: /* Differential progressive, Huffman */
case M_SOF7: /* Differential lossless, Huffman */
case M_JPG: /* Reserved for JPEG extensions */
- case M_SOF11: /* Lossless, arithmetic */
case M_SOF13: /* Differential sequential, arithmetic */
case M_SOF14: /* Differential progressive, arithmetic */
case M_SOF15: /* Differential lossless, arithmetic */
diff --git a/src/3rdparty/libjpeg/src/jdmaster.c b/src/3rdparty/libjpeg/src/jdmaster.c
index a3690bf560..80a4842ac1 100644
--- a/src/3rdparty/libjpeg/src/jdmaster.c
+++ b/src/3rdparty/libjpeg/src/jdmaster.c
@@ -4,8 +4,10 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 2002-2009 by Guido Vollbeding.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2009-2011, 2016, 2019, 2022, D. R. Commander.
+ * Copyright (C) 2009-2011, 2016, 2019, 2022-2023, D. R. Commander.
* Copyright (C) 2013, Linaro Limited.
* Copyright (C) 2015, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg
@@ -20,7 +22,7 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
#include "jdmaster.h"
@@ -33,6 +35,9 @@ LOCAL(boolean)
use_merged_upsample(j_decompress_ptr cinfo)
{
#ifdef UPSAMPLE_MERGING_SUPPORTED
+ /* Colorspace conversion is not supported with lossless JPEG images */
+ if (cinfo->master->lossless)
+ return FALSE;
/* Merging is the equivalent of plain box-filter upsampling */
if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling)
return FALSE;
@@ -97,154 +102,154 @@ jpeg_core_output_dimensions(j_decompress_ptr cinfo)
int ci;
jpeg_component_info *compptr;
- /* Compute actual output image dimensions and DCT scaling choices. */
- if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom) {
- /* Provide 1/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 1;
- cinfo->_min_DCT_v_scaled_size = 1;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 2) {
- /* Provide 2/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 2L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 2L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 2;
- cinfo->_min_DCT_v_scaled_size = 2;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 3) {
- /* Provide 3/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 3L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 3L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 3;
- cinfo->_min_DCT_v_scaled_size = 3;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 4) {
- /* Provide 4/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 4L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 4L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 4;
- cinfo->_min_DCT_v_scaled_size = 4;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 5) {
- /* Provide 5/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 5L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 5L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 5;
- cinfo->_min_DCT_v_scaled_size = 5;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 6) {
- /* Provide 6/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 6L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 6L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 6;
- cinfo->_min_DCT_v_scaled_size = 6;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 7) {
- /* Provide 7/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 7L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 7L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 7;
- cinfo->_min_DCT_v_scaled_size = 7;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 8) {
- /* Provide 8/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 8L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 8L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 8;
- cinfo->_min_DCT_v_scaled_size = 8;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 9) {
- /* Provide 9/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 9L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 9L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 9;
- cinfo->_min_DCT_v_scaled_size = 9;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 10) {
- /* Provide 10/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 10L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 10L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 10;
- cinfo->_min_DCT_v_scaled_size = 10;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 11) {
- /* Provide 11/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 11L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 11L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 11;
- cinfo->_min_DCT_v_scaled_size = 11;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 12) {
- /* Provide 12/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 12L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 12L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 12;
- cinfo->_min_DCT_v_scaled_size = 12;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 13) {
- /* Provide 13/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 13L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 13L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 13;
- cinfo->_min_DCT_v_scaled_size = 13;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 14) {
- /* Provide 14/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 14L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 14L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 14;
- cinfo->_min_DCT_v_scaled_size = 14;
- } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 15) {
- /* Provide 15/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 15L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 15L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 15;
- cinfo->_min_DCT_v_scaled_size = 15;
- } else {
- /* Provide 16/block_size scaling */
- cinfo->output_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width * 16L, (long)DCTSIZE);
- cinfo->output_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height * 16L, (long)DCTSIZE);
- cinfo->_min_DCT_h_scaled_size = 16;
- cinfo->_min_DCT_v_scaled_size = 16;
- }
+ if (!cinfo->master->lossless) {
+ /* Compute actual output image dimensions and DCT scaling choices. */
+ if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom) {
+ /* Provide 1/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 1;
+ cinfo->_min_DCT_v_scaled_size = 1;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 2) {
+ /* Provide 2/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 2L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 2L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 2;
+ cinfo->_min_DCT_v_scaled_size = 2;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 3) {
+ /* Provide 3/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 3L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 3L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 3;
+ cinfo->_min_DCT_v_scaled_size = 3;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 4) {
+ /* Provide 4/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 4L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 4L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 4;
+ cinfo->_min_DCT_v_scaled_size = 4;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 5) {
+ /* Provide 5/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 5L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 5L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 5;
+ cinfo->_min_DCT_v_scaled_size = 5;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 6) {
+ /* Provide 6/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 6L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 6L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 6;
+ cinfo->_min_DCT_v_scaled_size = 6;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 7) {
+ /* Provide 7/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 7L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 7L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 7;
+ cinfo->_min_DCT_v_scaled_size = 7;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 8) {
+ /* Provide 8/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 8L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 8L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 8;
+ cinfo->_min_DCT_v_scaled_size = 8;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 9) {
+ /* Provide 9/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 9L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 9L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 9;
+ cinfo->_min_DCT_v_scaled_size = 9;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 10) {
+ /* Provide 10/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 10L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 10L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 10;
+ cinfo->_min_DCT_v_scaled_size = 10;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 11) {
+ /* Provide 11/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 11L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 11L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 11;
+ cinfo->_min_DCT_v_scaled_size = 11;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 12) {
+ /* Provide 12/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 12L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 12L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 12;
+ cinfo->_min_DCT_v_scaled_size = 12;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 13) {
+ /* Provide 13/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 13L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 13L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 13;
+ cinfo->_min_DCT_v_scaled_size = 13;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 14) {
+ /* Provide 14/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 14L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 14L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 14;
+ cinfo->_min_DCT_v_scaled_size = 14;
+ } else if (cinfo->scale_num * DCTSIZE <= cinfo->scale_denom * 15) {
+ /* Provide 15/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 15L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 15L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 15;
+ cinfo->_min_DCT_v_scaled_size = 15;
+ } else {
+ /* Provide 16/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width * 16L, (long)DCTSIZE);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height * 16L, (long)DCTSIZE);
+ cinfo->_min_DCT_h_scaled_size = 16;
+ cinfo->_min_DCT_v_scaled_size = 16;
+ }
- /* Recompute dimensions of components */
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- compptr->_DCT_h_scaled_size = cinfo->_min_DCT_h_scaled_size;
- compptr->_DCT_v_scaled_size = cinfo->_min_DCT_v_scaled_size;
+ /* Recompute dimensions of components */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ compptr->_DCT_h_scaled_size = cinfo->_min_DCT_h_scaled_size;
+ compptr->_DCT_v_scaled_size = cinfo->_min_DCT_v_scaled_size;
+ }
+ } else
+#endif /* !IDCT_SCALING_SUPPORTED */
+ {
+ /* Hardwire it to "no scaling" */
+ cinfo->output_width = cinfo->image_width;
+ cinfo->output_height = cinfo->image_height;
+ /* jdinput.c has already initialized DCT_scaled_size,
+ * and has computed unscaled downsampled_width and downsampled_height.
+ */
}
-
-#else /* !IDCT_SCALING_SUPPORTED */
-
- /* Hardwire it to "no scaling" */
- cinfo->output_width = cinfo->image_width;
- cinfo->output_height = cinfo->image_height;
- /* jdinput.c has already initialized DCT_scaled_size,
- * and has computed unscaled downsampled_width and downsampled_height.
- */
-
-#endif /* IDCT_SCALING_SUPPORTED */
}
@@ -273,54 +278,56 @@ jpeg_calc_output_dimensions(j_decompress_ptr cinfo)
#ifdef IDCT_SCALING_SUPPORTED
- /* In selecting the actual DCT scaling for each component, we try to
- * scale up the chroma components via IDCT scaling rather than upsampling.
- * This saves time if the upsampler gets to use 1:1 scaling.
- * Note this code adapts subsampling ratios which are powers of 2.
- */
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- int ssize = cinfo->_min_DCT_scaled_size;
- while (ssize < DCTSIZE &&
- ((cinfo->max_h_samp_factor * cinfo->_min_DCT_scaled_size) %
- (compptr->h_samp_factor * ssize * 2) == 0) &&
- ((cinfo->max_v_samp_factor * cinfo->_min_DCT_scaled_size) %
- (compptr->v_samp_factor * ssize * 2) == 0)) {
- ssize = ssize * 2;
- }
+ if (!cinfo->master->lossless) {
+ /* In selecting the actual DCT scaling for each component, we try to
+ * scale up the chroma components via IDCT scaling rather than upsampling.
+ * This saves time if the upsampler gets to use 1:1 scaling.
+ * Note this code adapts subsampling ratios which are powers of 2.
+ */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ int ssize = cinfo->_min_DCT_scaled_size;
+ while (ssize < DCTSIZE &&
+ ((cinfo->max_h_samp_factor * cinfo->_min_DCT_scaled_size) %
+ (compptr->h_samp_factor * ssize * 2) == 0) &&
+ ((cinfo->max_v_samp_factor * cinfo->_min_DCT_scaled_size) %
+ (compptr->v_samp_factor * ssize * 2) == 0)) {
+ ssize = ssize * 2;
+ }
#if JPEG_LIB_VERSION >= 70
- compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size = ssize;
+ compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size = ssize;
#else
- compptr->DCT_scaled_size = ssize;
+ compptr->DCT_scaled_size = ssize;
#endif
- }
-
- /* Recompute downsampled dimensions of components;
- * application needs to know these if using raw downsampled data.
- */
- for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
- ci++, compptr++) {
- /* Size in samples, after IDCT scaling */
- compptr->downsampled_width = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_width *
- (long)(compptr->h_samp_factor * compptr->_DCT_scaled_size),
- (long)(cinfo->max_h_samp_factor * DCTSIZE));
- compptr->downsampled_height = (JDIMENSION)
- jdiv_round_up((long)cinfo->image_height *
- (long)(compptr->v_samp_factor * compptr->_DCT_scaled_size),
- (long)(cinfo->max_v_samp_factor * DCTSIZE));
- }
-
-#else /* !IDCT_SCALING_SUPPORTED */
-
- /* Hardwire it to "no scaling" */
- cinfo->output_width = cinfo->image_width;
- cinfo->output_height = cinfo->image_height;
- /* jdinput.c has already initialized DCT_scaled_size to DCTSIZE,
- * and has computed unscaled downsampled_width and downsampled_height.
- */
+ }
+ /* Recompute downsampled dimensions of components;
+ * application needs to know these if using raw downsampled data.
+ */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Size in samples, after IDCT scaling */
+ compptr->downsampled_width = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_width *
+ (long)(compptr->h_samp_factor *
+ compptr->_DCT_scaled_size),
+ (long)(cinfo->max_h_samp_factor * DCTSIZE));
+ compptr->downsampled_height = (JDIMENSION)
+ jdiv_round_up((long)cinfo->image_height *
+ (long)(compptr->v_samp_factor *
+ compptr->_DCT_scaled_size),
+ (long)(cinfo->max_v_samp_factor * DCTSIZE));
+ }
+ } else
#endif /* IDCT_SCALING_SUPPORTED */
+ {
+ /* Hardwire it to "no scaling" */
+ cinfo->output_width = cinfo->image_width;
+ cinfo->output_height = cinfo->image_height;
+ /* jdinput.c has already initialized DCT_scaled_size to DCTSIZE,
+ * and has computed unscaled downsampled_width and downsampled_height.
+ */
+ }
/* Report number of components in selected colorspace. */
/* Probably this should be in the color conversion module... */
@@ -409,27 +416,83 @@ prepare_range_limit_table(j_decompress_ptr cinfo)
/* Allocate and fill in the sample_range_limit table */
{
JSAMPLE *table;
+ J12SAMPLE *table12;
+#ifdef D_LOSSLESS_SUPPORTED
+ J16SAMPLE *table16;
+#endif
int i;
- table = (JSAMPLE *)
- (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- (5 * (MAXJSAMPLE + 1) + CENTERJSAMPLE) * sizeof(JSAMPLE));
- table += (MAXJSAMPLE + 1); /* allow negative subscripts of simple table */
- cinfo->sample_range_limit = table;
- /* First segment of "simple" table: limit[x] = 0 for x < 0 */
- memset(table - (MAXJSAMPLE + 1), 0, (MAXJSAMPLE + 1) * sizeof(JSAMPLE));
- /* Main part of "simple" table: limit[x] = x */
- for (i = 0; i <= MAXJSAMPLE; i++)
- table[i] = (JSAMPLE)i;
- table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */
- /* End of simple table, rest of first half of post-IDCT table */
- for (i = CENTERJSAMPLE; i < 2 * (MAXJSAMPLE + 1); i++)
- table[i] = MAXJSAMPLE;
- /* Second half of post-IDCT table */
- memset(table + (2 * (MAXJSAMPLE + 1)), 0,
- (2 * (MAXJSAMPLE + 1) - CENTERJSAMPLE) * sizeof(JSAMPLE));
- memcpy(table + (4 * (MAXJSAMPLE + 1) - CENTERJSAMPLE),
- cinfo->sample_range_limit, CENTERJSAMPLE * sizeof(JSAMPLE));
+ if (cinfo->data_precision == 16) {
+#ifdef D_LOSSLESS_SUPPORTED
+ table16 = (J16SAMPLE *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
+ (5 * (MAXJ16SAMPLE + 1) + CENTERJ16SAMPLE) *
+ sizeof(J16SAMPLE));
+ table16 += (MAXJ16SAMPLE + 1); /* allow negative subscripts of simple
+ table */
+ cinfo->sample_range_limit = (JSAMPLE *)table16;
+ /* First segment of "simple" table: limit[x] = 0 for x < 0 */
+ memset(table16 - (MAXJ16SAMPLE + 1), 0,
+ (MAXJ16SAMPLE + 1) * sizeof(J16SAMPLE));
+ /* Main part of "simple" table: limit[x] = x */
+ for (i = 0; i <= MAXJ16SAMPLE; i++)
+ table16[i] = (J16SAMPLE)i;
+ table16 += CENTERJ16SAMPLE; /* Point to where post-IDCT table starts */
+ /* End of simple table, rest of first half of post-IDCT table */
+ for (i = CENTERJ16SAMPLE; i < 2 * (MAXJ16SAMPLE + 1); i++)
+ table16[i] = MAXJ16SAMPLE;
+ /* Second half of post-IDCT table */
+ memset(table16 + (2 * (MAXJ16SAMPLE + 1)), 0,
+ (2 * (MAXJ16SAMPLE + 1) - CENTERJ16SAMPLE) * sizeof(J16SAMPLE));
+ memcpy(table16 + (4 * (MAXJ16SAMPLE + 1) - CENTERJ16SAMPLE),
+ cinfo->sample_range_limit, CENTERJ16SAMPLE * sizeof(J16SAMPLE));
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+#endif
+ } else if (cinfo->data_precision == 12) {
+ table12 = (J12SAMPLE *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
+ (5 * (MAXJ12SAMPLE + 1) + CENTERJ12SAMPLE) *
+ sizeof(J12SAMPLE));
+ table12 += (MAXJ12SAMPLE + 1); /* allow negative subscripts of simple
+ table */
+ cinfo->sample_range_limit = (JSAMPLE *)table12;
+ /* First segment of "simple" table: limit[x] = 0 for x < 0 */
+ memset(table12 - (MAXJ12SAMPLE + 1), 0,
+ (MAXJ12SAMPLE + 1) * sizeof(J12SAMPLE));
+ /* Main part of "simple" table: limit[x] = x */
+ for (i = 0; i <= MAXJ12SAMPLE; i++)
+ table12[i] = (J12SAMPLE)i;
+ table12 += CENTERJ12SAMPLE; /* Point to where post-IDCT table starts */
+ /* End of simple table, rest of first half of post-IDCT table */
+ for (i = CENTERJ12SAMPLE; i < 2 * (MAXJ12SAMPLE + 1); i++)
+ table12[i] = MAXJ12SAMPLE;
+ /* Second half of post-IDCT table */
+ memset(table12 + (2 * (MAXJ12SAMPLE + 1)), 0,
+ (2 * (MAXJ12SAMPLE + 1) - CENTERJ12SAMPLE) * sizeof(J12SAMPLE));
+ memcpy(table12 + (4 * (MAXJ12SAMPLE + 1) - CENTERJ12SAMPLE),
+ cinfo->sample_range_limit, CENTERJ12SAMPLE * sizeof(J12SAMPLE));
+ } else {
+ table = (JSAMPLE *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
+ (5 * (MAXJSAMPLE + 1) + CENTERJSAMPLE) * sizeof(JSAMPLE));
+ table += (MAXJSAMPLE + 1); /* allow negative subscripts of simple table */
+ cinfo->sample_range_limit = table;
+ /* First segment of "simple" table: limit[x] = 0 for x < 0 */
+ memset(table - (MAXJSAMPLE + 1), 0, (MAXJSAMPLE + 1) * sizeof(JSAMPLE));
+ /* Main part of "simple" table: limit[x] = x */
+ for (i = 0; i <= MAXJSAMPLE; i++)
+ table[i] = (JSAMPLE)i;
+ table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */
+ /* End of simple table, rest of first half of post-IDCT table */
+ for (i = CENTERJSAMPLE; i < 2 * (MAXJSAMPLE + 1); i++)
+ table[i] = MAXJSAMPLE;
+ /* Second half of post-IDCT table */
+ memset(table + (2 * (MAXJSAMPLE + 1)), 0,
+ (2 * (MAXJSAMPLE + 1) - CENTERJSAMPLE) * sizeof(JSAMPLE));
+ memcpy(table + (4 * (MAXJSAMPLE + 1) - CENTERJSAMPLE),
+ cinfo->sample_range_limit, CENTERJSAMPLE * sizeof(JSAMPLE));
+ }
}
@@ -452,6 +515,17 @@ master_selection(j_decompress_ptr cinfo)
long samplesperrow;
JDIMENSION jd_samplesperrow;
+ /* Disable IDCT scaling and raw (downsampled) data output in lossless mode.
+ * IDCT scaling is not useful in lossless mode, and it must be disabled in
+ * order to properly calculate the output dimensions. Raw data output isn't
+ * particularly useful without subsampling and has not been tested in
+ * lossless mode.
+ */
+ if (cinfo->master->lossless) {
+ cinfo->raw_data_out = FALSE;
+ cinfo->scale_num = cinfo->scale_denom = 1;
+ }
+
/* Initialize dimensions and other stuff */
jpeg_calc_output_dimensions(cinfo);
prepare_range_limit_table(cinfo);
@@ -480,7 +554,8 @@ master_selection(j_decompress_ptr cinfo)
if (cinfo->raw_data_out)
ERREXIT(cinfo, JERR_NOTIMPL);
/* 2-pass quantizer only works in 3-component color space. */
- if (cinfo->out_color_components != 3) {
+ if (cinfo->out_color_components != 3 ||
+ cinfo->out_color_space == JCS_RGB565) {
cinfo->enable_1pass_quant = TRUE;
cinfo->enable_external_quant = FALSE;
cinfo->enable_2pass_quant = FALSE;
@@ -495,7 +570,12 @@ master_selection(j_decompress_ptr cinfo)
if (cinfo->enable_1pass_quant) {
#ifdef QUANT_1PASS_SUPPORTED
- jinit_1pass_quantizer(cinfo);
+ if (cinfo->data_precision == 16)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ else if (cinfo->data_precision == 12)
+ j12init_1pass_quantizer(cinfo);
+ else
+ jinit_1pass_quantizer(cinfo);
master->quantizer_1pass = cinfo->cquantize;
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
@@ -505,7 +585,12 @@ master_selection(j_decompress_ptr cinfo)
/* We use the 2-pass code to map to external colormaps. */
if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) {
#ifdef QUANT_2PASS_SUPPORTED
- jinit_2pass_quantizer(cinfo);
+ if (cinfo->data_precision == 16)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ else if (cinfo->data_precision == 12)
+ j12init_2pass_quantizer(cinfo);
+ else
+ jinit_2pass_quantizer(cinfo);
master->quantizer_2pass = cinfo->cquantize;
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
@@ -520,42 +605,122 @@ master_selection(j_decompress_ptr cinfo)
if (!cinfo->raw_data_out) {
if (master->using_merged_upsample) {
#ifdef UPSAMPLE_MERGING_SUPPORTED
- jinit_merged_upsampler(cinfo); /* does color conversion too */
+ if (cinfo->data_precision == 16)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ else if (cinfo->data_precision == 12)
+ j12init_merged_upsampler(cinfo); /* does color conversion too */
+ else
+ jinit_merged_upsampler(cinfo); /* does color conversion too */
#else
ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else {
- jinit_color_deconverter(cinfo);
- jinit_upsampler(cinfo);
+ if (cinfo->data_precision == 16) {
+#ifdef D_LOSSLESS_SUPPORTED
+ j16init_color_deconverter(cinfo);
+ j16init_upsampler(cinfo);
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+#endif
+ } else if (cinfo->data_precision == 12) {
+ j12init_color_deconverter(cinfo);
+ j12init_upsampler(cinfo);
+ } else {
+ jinit_color_deconverter(cinfo);
+ jinit_upsampler(cinfo);
+ }
}
- jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant);
+ if (cinfo->data_precision == 16)
+#ifdef D_LOSSLESS_SUPPORTED
+ j16init_d_post_controller(cinfo, cinfo->enable_2pass_quant);
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+#endif
+ else if (cinfo->data_precision == 12)
+ j12init_d_post_controller(cinfo, cinfo->enable_2pass_quant);
+ else
+ jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant);
}
- /* Inverse DCT */
- jinit_inverse_dct(cinfo);
- /* Entropy decoding: either Huffman or arithmetic coding. */
- if (cinfo->arith_code) {
-#ifdef D_ARITH_CODING_SUPPORTED
- jinit_arith_decoder(cinfo);
+
+ if (cinfo->master->lossless) {
+#ifdef D_LOSSLESS_SUPPORTED
+ /* Prediction, sample undifferencing, point transform, and sample size
+ * scaling
+ */
+ if (cinfo->data_precision == 16)
+ j16init_lossless_decompressor(cinfo);
+ else if (cinfo->data_precision == 12)
+ j12init_lossless_decompressor(cinfo);
+ else
+ jinit_lossless_decompressor(cinfo);
+ /* Entropy decoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code) {
+ ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+ } else {
+ jinit_lhuff_decoder(cinfo);
+ }
+
+ /* Initialize principal buffer controllers. */
+ use_c_buffer = cinfo->inputctl->has_multiple_scans ||
+ cinfo->buffered_image;
+ if (cinfo->data_precision == 16)
+ j16init_d_diff_controller(cinfo, use_c_buffer);
+ else if (cinfo->data_precision == 12)
+ j12init_d_diff_controller(cinfo, use_c_buffer);
+ else
+ jinit_d_diff_controller(cinfo, use_c_buffer);
#else
- ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
} else {
- if (cinfo->progressive_mode) {
+ if (cinfo->data_precision == 16)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+ /* Inverse DCT */
+ if (cinfo->data_precision == 12)
+ j12init_inverse_dct(cinfo);
+ else
+ jinit_inverse_dct(cinfo);
+ /* Entropy decoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code) {
+#ifdef D_ARITH_CODING_SUPPORTED
+ jinit_arith_decoder(cinfo);
+#else
+ ERREXIT(cinfo, JERR_ARITH_NOTIMPL);
+#endif
+ } else {
+ if (cinfo->progressive_mode) {
#ifdef D_PROGRESSIVE_SUPPORTED
- jinit_phuff_decoder(cinfo);
+ jinit_phuff_decoder(cinfo);
#else
- ERREXIT(cinfo, JERR_NOT_COMPILED);
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
#endif
- } else
- jinit_huff_decoder(cinfo);
- }
+ } else
+ jinit_huff_decoder(cinfo);
+ }
- /* Initialize principal buffer controllers. */
- use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image;
- jinit_d_coef_controller(cinfo, use_c_buffer);
+ /* Initialize principal buffer controllers. */
+ use_c_buffer = cinfo->inputctl->has_multiple_scans ||
+ cinfo->buffered_image;
+ if (cinfo->data_precision == 12)
+ j12init_d_coef_controller(cinfo, use_c_buffer);
+ else
+ jinit_d_coef_controller(cinfo, use_c_buffer);
+ }
- if (!cinfo->raw_data_out)
- jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */);
+ if (!cinfo->raw_data_out) {
+ if (cinfo->data_precision == 16)
+#ifdef D_LOSSLESS_SUPPORTED
+ j16init_d_main_controller(cinfo,
+ FALSE /* never need full buffer here */);
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+#endif
+ else if (cinfo->data_precision == 12)
+ j12init_d_main_controller(cinfo,
+ FALSE /* never need full buffer here */);
+ else
+ jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */);
+ }
/* We can now tell the memory manager to allocate virtual arrays. */
(*cinfo->mem->realize_virt_arrays) ((j_common_ptr)cinfo);
diff --git a/src/3rdparty/libjpeg/src/jdmerge.c b/src/3rdparty/libjpeg/src/jdmerge.c
index 38b002729c..49f2006fc0 100644
--- a/src/3rdparty/libjpeg/src/jdmerge.c
+++ b/src/3rdparty/libjpeg/src/jdmerge.c
@@ -5,7 +5,7 @@
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009, 2011, 2014-2015, 2020, D. R. Commander.
+ * Copyright (C) 2009, 2011, 2014-2015, 2020, 2022, D. R. Commander.
* Copyright (C) 2013, Linaro Limited.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
@@ -167,20 +167,20 @@ build_ycc_rgb_table(j_decompress_ptr cinfo)
upsample->Cr_r_tab = (int *)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE + 1) * sizeof(int));
+ (_MAXJSAMPLE + 1) * sizeof(int));
upsample->Cb_b_tab = (int *)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE + 1) * sizeof(int));
+ (_MAXJSAMPLE + 1) * sizeof(int));
upsample->Cr_g_tab = (JLONG *)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE + 1) * sizeof(JLONG));
+ (_MAXJSAMPLE + 1) * sizeof(JLONG));
upsample->Cb_g_tab = (JLONG *)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- (MAXJSAMPLE + 1) * sizeof(JLONG));
+ (_MAXJSAMPLE + 1) * sizeof(JLONG));
- for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
- /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
- /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
+ for (i = 0, x = -_CENTERJSAMPLE; i <= _MAXJSAMPLE; i++, x++) {
+ /* i is the actual input pixel value, in the range 0.._MAXJSAMPLE */
+ /* The Cb or Cr value we are thinking of is x = i - _CENTERJSAMPLE */
/* Cr=>R value is nearest int to 1.40200 * x */
upsample->Cr_r_tab[i] = (int)
RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS);
@@ -219,14 +219,14 @@ start_pass_merged_upsample(j_decompress_ptr cinfo)
*/
METHODDEF(void)
-merged_2v_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+merged_2v_upsample(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf,
+ JDIMENSION in_row_groups_avail, _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)
/* 2:1 vertical sampling case: may need a spare row. */
{
my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
- JSAMPROW work_ptrs[2];
+ _JSAMPROW work_ptrs[2];
JDIMENSION num_rows; /* number of rows returned to caller */
if (upsample->spare_full) {
@@ -234,8 +234,8 @@ merged_2v_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
JDIMENSION size = upsample->out_row_width;
if (cinfo->out_color_space == JCS_RGB565)
size = cinfo->output_width * 2;
- jcopy_sample_rows(&upsample->spare_row, 0, output_buf + *out_row_ctr, 0, 1,
- size);
+ _jcopy_sample_rows(&upsample->spare_row, 0, output_buf + *out_row_ctr, 0,
+ 1, size);
num_rows = 1;
upsample->spare_full = FALSE;
} else {
@@ -270,9 +270,9 @@ merged_2v_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
METHODDEF(void)
-merged_1v_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+merged_1v_upsample(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf,
+ JDIMENSION in_row_groups_avail, _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)
/* 1:1 vertical sampling case: much easier, never need a spare row. */
{
@@ -302,8 +302,8 @@ merged_1v_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
*/
METHODDEF(void)
-h2v1_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)
+h2v1_merged_upsample(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION in_row_group_ctr, _JSAMPARRAY output_buf)
{
switch (cinfo->out_color_space) {
case JCS_EXT_RGB:
@@ -347,8 +347,8 @@ h2v1_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
*/
METHODDEF(void)
-h2v2_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)
+h2v2_merged_upsample(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION in_row_group_ctr, _JSAMPARRAY output_buf)
{
switch (cinfo->out_color_space) {
case JCS_EXT_RGB:
@@ -474,8 +474,8 @@ static INLINE boolean is_big_endian(void)
METHODDEF(void)
-h2v1_merged_upsample_565(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)
+h2v1_merged_upsample_565(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION in_row_group_ctr, _JSAMPARRAY output_buf)
{
if (is_big_endian())
h2v1_merged_upsample_565_be(cinfo, input_buf, in_row_group_ctr,
@@ -487,8 +487,8 @@ h2v1_merged_upsample_565(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
METHODDEF(void)
-h2v1_merged_upsample_565D(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)
+h2v1_merged_upsample_565D(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION in_row_group_ctr, _JSAMPARRAY output_buf)
{
if (is_big_endian())
h2v1_merged_upsample_565D_be(cinfo, input_buf, in_row_group_ctr,
@@ -500,8 +500,8 @@ h2v1_merged_upsample_565D(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
METHODDEF(void)
-h2v2_merged_upsample_565(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)
+h2v2_merged_upsample_565(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION in_row_group_ctr, _JSAMPARRAY output_buf)
{
if (is_big_endian())
h2v2_merged_upsample_565_be(cinfo, input_buf, in_row_group_ctr,
@@ -513,8 +513,8 @@ h2v2_merged_upsample_565(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
METHODDEF(void)
-h2v2_merged_upsample_565D(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)
+h2v2_merged_upsample_565D(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION in_row_group_ctr, _JSAMPARRAY output_buf)
{
if (is_big_endian())
h2v2_merged_upsample_565D_be(cinfo, input_buf, in_row_group_ctr,
@@ -534,10 +534,13 @@ h2v2_merged_upsample_565D(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
*/
GLOBAL(void)
-jinit_merged_upsampler(j_decompress_ptr cinfo)
+_jinit_merged_upsampler(j_decompress_ptr cinfo)
{
my_merged_upsample_ptr upsample;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
upsample = (my_merged_upsample_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_merged_upsampler));
@@ -548,10 +551,12 @@ jinit_merged_upsampler(j_decompress_ptr cinfo)
upsample->out_row_width = cinfo->output_width * cinfo->out_color_components;
if (cinfo->max_v_samp_factor == 2) {
- upsample->pub.upsample = merged_2v_upsample;
+ upsample->pub._upsample = merged_2v_upsample;
+#ifdef WITH_SIMD
if (jsimd_can_h2v2_merged_upsample())
upsample->upmethod = jsimd_h2v2_merged_upsample;
else
+#endif
upsample->upmethod = h2v2_merged_upsample;
if (cinfo->out_color_space == JCS_RGB565) {
if (cinfo->dither_mode != JDITHER_NONE) {
@@ -561,14 +566,16 @@ jinit_merged_upsampler(j_decompress_ptr cinfo)
}
}
/* Allocate a spare row buffer */
- upsample->spare_row = (JSAMPROW)
+ upsample->spare_row = (_JSAMPROW)
(*cinfo->mem->alloc_large) ((j_common_ptr)cinfo, JPOOL_IMAGE,
- (size_t)(upsample->out_row_width * sizeof(JSAMPLE)));
+ (size_t)(upsample->out_row_width * sizeof(_JSAMPLE)));
} else {
- upsample->pub.upsample = merged_1v_upsample;
+ upsample->pub._upsample = merged_1v_upsample;
+#ifdef WITH_SIMD
if (jsimd_can_h2v1_merged_upsample())
upsample->upmethod = jsimd_h2v1_merged_upsample;
else
+#endif
upsample->upmethod = h2v1_merged_upsample;
if (cinfo->out_color_space == JCS_RGB565) {
if (cinfo->dither_mode != JDITHER_NONE) {
diff --git a/src/3rdparty/libjpeg/src/jdmerge.h b/src/3rdparty/libjpeg/src/jdmerge.h
index b583396b10..73cbd60549 100644
--- a/src/3rdparty/libjpeg/src/jdmerge.h
+++ b/src/3rdparty/libjpeg/src/jdmerge.h
@@ -4,13 +4,14 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2020, D. R. Commander.
+ * Copyright (C) 2020, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*/
#define JPEG_INTERNALS
#include "jpeglib.h"
+#include "jsamplecomp.h"
#ifdef UPSAMPLE_MERGING_SUPPORTED
@@ -21,8 +22,8 @@ typedef struct {
struct jpeg_upsampler pub; /* public fields */
/* Pointer to routine to do actual upsampling/conversion of one row group */
- void (*upmethod) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf);
+ void (*upmethod) (j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
+ JDIMENSION in_row_group_ctr, _JSAMPARRAY output_buf);
/* Private state for YCC->RGB conversion */
int *Cr_r_tab; /* => table for Cr to R conversion */
@@ -35,7 +36,7 @@ typedef struct {
* application provides just a one-row buffer; we also use the spare
* to discard the dummy last row if the image height is odd.
*/
- JSAMPROW spare_row;
+ _JSAMPROW spare_row;
boolean spare_full; /* T if spare buffer is occupied */
JDIMENSION out_row_width; /* samples per output row */
diff --git a/src/3rdparty/libjpeg/src/jdmrg565.c b/src/3rdparty/libjpeg/src/jdmrg565.c
index 980a4e216e..0c719b912c 100644
--- a/src/3rdparty/libjpeg/src/jdmrg565.c
+++ b/src/3rdparty/libjpeg/src/jdmrg565.c
@@ -5,7 +5,7 @@
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2013, Linaro Limited.
- * Copyright (C) 2014-2015, 2018, 2020, D. R. Commander.
+ * Copyright (C) 2014-2015, 2018, 2020, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -15,18 +15,19 @@
INLINE
LOCAL(void)
-h2v1_merged_upsample_565_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+h2v1_merged_upsample_565_internal(j_decompress_ptr cinfo,
+ _JSAMPIMAGE input_buf,
JDIMENSION in_row_group_ctr,
- JSAMPARRAY output_buf)
+ _JSAMPARRAY output_buf)
{
my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
register int y, cred, cgreen, cblue;
int cb, cr;
- register JSAMPROW outptr;
- JSAMPROW inptr0, inptr1, inptr2;
+ register _JSAMPROW outptr;
+ _JSAMPROW inptr0, inptr1, inptr2;
JDIMENSION col;
/* copy these pointers into registers if possible */
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
int *Crrtab = upsample->Cr_r_tab;
int *Cbbtab = upsample->Cb_b_tab;
JLONG *Crgtab = upsample->Cr_g_tab;
@@ -86,18 +87,18 @@ h2v1_merged_upsample_565_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
INLINE
LOCAL(void)
h2v1_merged_upsample_565D_internal(j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf,
+ _JSAMPIMAGE input_buf,
JDIMENSION in_row_group_ctr,
- JSAMPARRAY output_buf)
+ _JSAMPARRAY output_buf)
{
my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
register int y, cred, cgreen, cblue;
int cb, cr;
- register JSAMPROW outptr;
- JSAMPROW inptr0, inptr1, inptr2;
+ register _JSAMPROW outptr;
+ _JSAMPROW inptr0, inptr1, inptr2;
JDIMENSION col;
/* copy these pointers into registers if possible */
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
int *Crrtab = upsample->Cr_r_tab;
int *Cbbtab = upsample->Cb_b_tab;
JLONG *Crgtab = upsample->Cr_g_tab;
@@ -159,18 +160,18 @@ h2v1_merged_upsample_565D_internal(j_decompress_ptr cinfo,
INLINE
LOCAL(void)
-h2v2_merged_upsample_565_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+h2v2_merged_upsample_565_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION in_row_group_ctr,
- JSAMPARRAY output_buf)
+ _JSAMPARRAY output_buf)
{
my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
register int y, cred, cgreen, cblue;
int cb, cr;
- register JSAMPROW outptr0, outptr1;
- JSAMPROW inptr00, inptr01, inptr1, inptr2;
+ register _JSAMPROW outptr0, outptr1;
+ _JSAMPROW inptr00, inptr01, inptr1, inptr2;
JDIMENSION col;
/* copy these pointers into registers if possible */
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
int *Crrtab = upsample->Cr_r_tab;
int *Cbbtab = upsample->Cb_b_tab;
JLONG *Crgtab = upsample->Cr_g_tab;
@@ -255,18 +256,18 @@ h2v2_merged_upsample_565_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
INLINE
LOCAL(void)
h2v2_merged_upsample_565D_internal(j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf,
+ _JSAMPIMAGE input_buf,
JDIMENSION in_row_group_ctr,
- JSAMPARRAY output_buf)
+ _JSAMPARRAY output_buf)
{
my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
register int y, cred, cgreen, cblue;
int cb, cr;
- register JSAMPROW outptr0, outptr1;
- JSAMPROW inptr00, inptr01, inptr1, inptr2;
+ register _JSAMPROW outptr0, outptr1;
+ _JSAMPROW inptr00, inptr01, inptr1, inptr2;
JDIMENSION col;
/* copy these pointers into registers if possible */
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
int *Crrtab = upsample->Cr_r_tab;
int *Cbbtab = upsample->Cb_b_tab;
JLONG *Crgtab = upsample->Cr_g_tab;
diff --git a/src/3rdparty/libjpeg/src/jdmrgext.c b/src/3rdparty/libjpeg/src/jdmrgext.c
index 038abc75d7..8139e0a3ed 100644
--- a/src/3rdparty/libjpeg/src/jdmrgext.c
+++ b/src/3rdparty/libjpeg/src/jdmrgext.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2011, 2015, 2020, 2023, D. R. Commander.
+ * Copyright (C) 2011, 2015, 2020, 2022-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -21,18 +21,18 @@
INLINE
LOCAL(void)
-h2v1_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+h2v1_merged_upsample_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION in_row_group_ctr,
- JSAMPARRAY output_buf)
+ _JSAMPARRAY output_buf)
{
my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
register int y, cred, cgreen, cblue;
int cb, cr;
- register JSAMPROW outptr;
- JSAMPROW inptr0, inptr1, inptr2;
+ register _JSAMPROW outptr;
+ _JSAMPROW inptr0, inptr1, inptr2;
JDIMENSION col;
/* copy these pointers into registers if possible */
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
int *Crrtab = upsample->Cr_r_tab;
int *Cbbtab = upsample->Cb_b_tab;
JLONG *Crgtab = upsample->Cr_g_tab;
@@ -57,7 +57,7 @@ h2v1_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
outptr[RGB_GREEN] = range_limit[y + cgreen];
outptr[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr[RGB_ALPHA] = MAXJSAMPLE;
+ outptr[RGB_ALPHA] = _MAXJSAMPLE;
#endif
outptr += RGB_PIXELSIZE;
y = *inptr0++;
@@ -65,7 +65,7 @@ h2v1_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
outptr[RGB_GREEN] = range_limit[y + cgreen];
outptr[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr[RGB_ALPHA] = MAXJSAMPLE;
+ outptr[RGB_ALPHA] = _MAXJSAMPLE;
#endif
outptr += RGB_PIXELSIZE;
}
@@ -81,7 +81,7 @@ h2v1_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
outptr[RGB_GREEN] = range_limit[y + cgreen];
outptr[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr[RGB_ALPHA] = MAXJSAMPLE;
+ outptr[RGB_ALPHA] = _MAXJSAMPLE;
#endif
}
}
@@ -93,18 +93,18 @@ h2v1_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
INLINE
LOCAL(void)
-h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+h2v2_merged_upsample_internal(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION in_row_group_ctr,
- JSAMPARRAY output_buf)
+ _JSAMPARRAY output_buf)
{
my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample;
register int y, cred, cgreen, cblue;
int cb, cr;
- register JSAMPROW outptr0, outptr1;
- JSAMPROW inptr00, inptr01, inptr1, inptr2;
+ register _JSAMPROW outptr0, outptr1;
+ _JSAMPROW inptr00, inptr01, inptr1, inptr2;
JDIMENSION col;
/* copy these pointers into registers if possible */
- register JSAMPLE *range_limit = cinfo->sample_range_limit;
+ register _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
int *Crrtab = upsample->Cr_r_tab;
int *Cbbtab = upsample->Cb_b_tab;
JLONG *Crgtab = upsample->Cr_g_tab;
@@ -131,7 +131,7 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
outptr0[RGB_GREEN] = range_limit[y + cgreen];
outptr0[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr0[RGB_ALPHA] = MAXJSAMPLE;
+ outptr0[RGB_ALPHA] = _MAXJSAMPLE;
#endif
outptr0 += RGB_PIXELSIZE;
y = *inptr00++;
@@ -139,7 +139,7 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
outptr0[RGB_GREEN] = range_limit[y + cgreen];
outptr0[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr0[RGB_ALPHA] = MAXJSAMPLE;
+ outptr0[RGB_ALPHA] = _MAXJSAMPLE;
#endif
outptr0 += RGB_PIXELSIZE;
y = *inptr01++;
@@ -147,7 +147,7 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
outptr1[RGB_GREEN] = range_limit[y + cgreen];
outptr1[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr1[RGB_ALPHA] = MAXJSAMPLE;
+ outptr1[RGB_ALPHA] = _MAXJSAMPLE;
#endif
outptr1 += RGB_PIXELSIZE;
y = *inptr01++;
@@ -155,7 +155,7 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
outptr1[RGB_GREEN] = range_limit[y + cgreen];
outptr1[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr1[RGB_ALPHA] = MAXJSAMPLE;
+ outptr1[RGB_ALPHA] = _MAXJSAMPLE;
#endif
outptr1 += RGB_PIXELSIZE;
}
@@ -171,14 +171,14 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
outptr0[RGB_GREEN] = range_limit[y + cgreen];
outptr0[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr0[RGB_ALPHA] = MAXJSAMPLE;
+ outptr0[RGB_ALPHA] = _MAXJSAMPLE;
#endif
y = *inptr01;
outptr1[RGB_RED] = range_limit[y + cred];
outptr1[RGB_GREEN] = range_limit[y + cgreen];
outptr1[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr1[RGB_ALPHA] = MAXJSAMPLE;
+ outptr1[RGB_ALPHA] = _MAXJSAMPLE;
#endif
}
}
diff --git a/src/3rdparty/libjpeg/src/jdphuff.c b/src/3rdparty/libjpeg/src/jdphuff.c
index 9680ebcbd0..bf97333a34 100644
--- a/src/3rdparty/libjpeg/src/jdphuff.c
+++ b/src/3rdparty/libjpeg/src/jdphuff.c
@@ -3,6 +3,8 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1995-1997, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
* Copyright (C) 2015-2016, 2018-2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
@@ -23,7 +25,7 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
-#include "jdhuff.h" /* Declarations shared with jdhuff.c */
+#include "jdhuff.h" /* Declarations shared with jd*huff.c */
#include <limits.h>
diff --git a/src/3rdparty/libjpeg/src/jdpostct.c b/src/3rdparty/libjpeg/src/jdpostct.c
index 6a2cf5c1b3..d38495f5f3 100644
--- a/src/3rdparty/libjpeg/src/jdpostct.c
+++ b/src/3rdparty/libjpeg/src/jdpostct.c
@@ -3,8 +3,8 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
- * It was modified by The libjpeg-turbo Project to include only code relevant
- * to libjpeg-turbo.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -22,8 +22,11 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#include "jsamplecomp.h"
+#if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)
+
/* Private buffer controller object */
typedef struct {
@@ -35,7 +38,7 @@ typedef struct {
* for one-pass operation, a strip buffer is sufficient.
*/
jvirt_sarray_ptr whole_image; /* virtual array, or NULL if one-pass */
- JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */
+ _JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */
JDIMENSION strip_height; /* buffer size in rows */
/* for two-pass mode only: */
JDIMENSION starting_row; /* row # of first row in current strip */
@@ -46,26 +49,28 @@ typedef my_post_controller *my_post_ptr;
/* Forward declarations */
+#if BITS_IN_JSAMPLE != 16
METHODDEF(void) post_process_1pass(j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf,
+ _JSAMPIMAGE input_buf,
JDIMENSION *in_row_group_ctr,
JDIMENSION in_row_groups_avail,
- JSAMPARRAY output_buf,
+ _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail);
-#ifdef QUANT_2PASS_SUPPORTED
+#endif
+#if defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16
METHODDEF(void) post_process_prepass(j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf,
+ _JSAMPIMAGE input_buf,
JDIMENSION *in_row_group_ctr,
JDIMENSION in_row_groups_avail,
- JSAMPARRAY output_buf,
+ _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail);
METHODDEF(void) post_process_2pass(j_decompress_ptr cinfo,
- JSAMPIMAGE input_buf,
+ _JSAMPIMAGE input_buf,
JDIMENSION *in_row_group_ctr,
JDIMENSION in_row_groups_avail,
- JSAMPARRAY output_buf,
+ _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail);
#endif
@@ -82,39 +87,42 @@ start_pass_dpost(j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
switch (pass_mode) {
case JBUF_PASS_THRU:
+#if BITS_IN_JSAMPLE != 16
if (cinfo->quantize_colors) {
/* Single-pass processing with color quantization. */
- post->pub.post_process_data = post_process_1pass;
+ post->pub._post_process_data = post_process_1pass;
/* We could be doing buffered-image output before starting a 2-pass
* color quantization; in that case, jinit_d_post_controller did not
* allocate a strip buffer. Use the virtual-array buffer as workspace.
*/
if (post->buffer == NULL) {
- post->buffer = (*cinfo->mem->access_virt_sarray)
+ post->buffer = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray)
((j_common_ptr)cinfo, post->whole_image,
(JDIMENSION)0, post->strip_height, TRUE);
}
- } else {
+ } else
+#endif
+ {
/* For single-pass processing without color quantization,
* I have no work to do; just call the upsampler directly.
*/
- post->pub.post_process_data = cinfo->upsample->upsample;
+ post->pub._post_process_data = cinfo->upsample->_upsample;
}
break;
-#ifdef QUANT_2PASS_SUPPORTED
+#if defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16
case JBUF_SAVE_AND_PASS:
/* First pass of 2-pass quantization */
if (post->whole_image == NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- post->pub.post_process_data = post_process_prepass;
+ post->pub._post_process_data = post_process_prepass;
break;
case JBUF_CRANK_DEST:
/* Second pass of 2-pass quantization */
if (post->whole_image == NULL)
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
- post->pub.post_process_data = post_process_2pass;
+ post->pub._post_process_data = post_process_2pass;
break;
-#endif /* QUANT_2PASS_SUPPORTED */
+#endif /* defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16 */
default:
ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
break;
@@ -128,10 +136,12 @@ start_pass_dpost(j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
* This is used for color precision reduction as well as one-pass quantization.
*/
+#if BITS_IN_JSAMPLE != 16
+
METHODDEF(void)
-post_process_1pass(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+post_process_1pass(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf,
+ JDIMENSION in_row_groups_avail, _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)
{
my_post_ptr post = (my_post_ptr)cinfo->post;
@@ -143,27 +153,29 @@ post_process_1pass(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
if (max_rows > post->strip_height)
max_rows = post->strip_height;
num_rows = 0;
- (*cinfo->upsample->upsample) (cinfo, input_buf, in_row_group_ctr,
- in_row_groups_avail, post->buffer, &num_rows,
- max_rows);
+ (*cinfo->upsample->_upsample) (cinfo, input_buf, in_row_group_ctr,
+ in_row_groups_avail, post->buffer, &num_rows,
+ max_rows);
/* Quantize and emit data. */
- (*cinfo->cquantize->color_quantize) (cinfo, post->buffer,
- output_buf + *out_row_ctr,
- (int)num_rows);
+ (*cinfo->cquantize->_color_quantize) (cinfo, post->buffer,
+ output_buf + *out_row_ctr,
+ (int)num_rows);
*out_row_ctr += num_rows;
}
+#endif
-#ifdef QUANT_2PASS_SUPPORTED
+
+#if defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16
/*
* Process some data in the first pass of 2-pass quantization.
*/
METHODDEF(void)
-post_process_prepass(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+post_process_prepass(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf,
+ JDIMENSION in_row_groups_avail, _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)
{
my_post_ptr post = (my_post_ptr)cinfo->post;
@@ -171,23 +183,23 @@ post_process_prepass(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
/* Reposition virtual buffer if at start of strip. */
if (post->next_row == 0) {
- post->buffer = (*cinfo->mem->access_virt_sarray)
+ post->buffer = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray)
((j_common_ptr)cinfo, post->whole_image,
post->starting_row, post->strip_height, TRUE);
}
/* Upsample some data (up to a strip height's worth). */
old_next_row = post->next_row;
- (*cinfo->upsample->upsample) (cinfo, input_buf, in_row_group_ctr,
- in_row_groups_avail, post->buffer,
- &post->next_row, post->strip_height);
+ (*cinfo->upsample->_upsample) (cinfo, input_buf, in_row_group_ctr,
+ in_row_groups_avail, post->buffer,
+ &post->next_row, post->strip_height);
/* Allow quantizer to scan new data. No data is emitted, */
/* but we advance out_row_ctr so outer loop can tell when we're done. */
if (post->next_row > old_next_row) {
num_rows = post->next_row - old_next_row;
- (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row,
- (JSAMPARRAY)NULL, (int)num_rows);
+ (*cinfo->cquantize->_color_quantize) (cinfo, post->buffer + old_next_row,
+ (_JSAMPARRAY)NULL, (int)num_rows);
*out_row_ctr += num_rows;
}
@@ -204,9 +216,9 @@ post_process_prepass(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
*/
METHODDEF(void)
-post_process_2pass(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+post_process_2pass(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION *in_row_group_ctr,
- JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf,
+ JDIMENSION in_row_groups_avail, _JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)
{
my_post_ptr post = (my_post_ptr)cinfo->post;
@@ -214,7 +226,7 @@ post_process_2pass(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
/* Reposition virtual buffer if at start of strip. */
if (post->next_row == 0) {
- post->buffer = (*cinfo->mem->access_virt_sarray)
+ post->buffer = (_JSAMPARRAY)(*cinfo->mem->access_virt_sarray)
((j_common_ptr)cinfo, post->whole_image,
post->starting_row, post->strip_height, FALSE);
}
@@ -230,9 +242,9 @@ post_process_2pass(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
num_rows = max_rows;
/* Quantize and emit data. */
- (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + post->next_row,
- output_buf + *out_row_ctr,
- (int)num_rows);
+ (*cinfo->cquantize->_color_quantize) (cinfo, post->buffer + post->next_row,
+ output_buf + *out_row_ctr,
+ (int)num_rows);
*out_row_ctr += num_rows;
/* Advance if we filled the strip. */
@@ -243,7 +255,7 @@ post_process_2pass(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
}
}
-#endif /* QUANT_2PASS_SUPPORTED */
+#endif /* defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16 */
/*
@@ -251,10 +263,13 @@ post_process_2pass(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
*/
GLOBAL(void)
-jinit_d_post_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
+_jinit_d_post_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
{
my_post_ptr post;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
post = (my_post_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_post_controller));
@@ -265,6 +280,7 @@ jinit_d_post_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
/* Create the quantization buffer, if needed */
if (cinfo->quantize_colors) {
+#if BITS_IN_JSAMPLE != 16
/* The buffer strip height is max_v_samp_factor, which is typically
* an efficient number of rows for upsampling to return.
* (In the presence of output rescaling, we might want to be smarter?)
@@ -285,10 +301,15 @@ jinit_d_post_controller(j_decompress_ptr cinfo, boolean need_full_buffer)
#endif /* QUANT_2PASS_SUPPORTED */
} else {
/* One-pass color quantization: just make a strip buffer. */
- post->buffer = (*cinfo->mem->alloc_sarray)
+ post->buffer = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE,
cinfo->output_width * cinfo->out_color_components,
post->strip_height);
}
+#else
+ ERREXIT(cinfo, JERR_NOTIMPL);
+#endif
}
}
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */
diff --git a/src/3rdparty/libjpeg/src/jdsample.c b/src/3rdparty/libjpeg/src/jdsample.c
index eaad72a030..cc8015c97d 100644
--- a/src/3rdparty/libjpeg/src/jdsample.c
+++ b/src/3rdparty/libjpeg/src/jdsample.c
@@ -5,7 +5,7 @@
* Copyright (C) 1991-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2010, 2015-2016, D. R. Commander.
+ * Copyright (C) 2010, 2015-2016, 2022, D. R. Commander.
* Copyright (C) 2014, MIPS Technologies, Inc., California.
* Copyright (C) 2015, Google, Inc.
* Copyright (C) 2019-2020, Arm Limited.
@@ -28,10 +28,12 @@
#include "jinclude.h"
#include "jdsample.h"
#include "jsimd.h"
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
+#if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED)
+
/*
* Initialize for an upsampling pass.
*/
@@ -57,9 +59,9 @@ start_pass_upsample(j_decompress_ptr cinfo)
*/
METHODDEF(void)
-sep_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
+sep_upsample(j_decompress_ptr cinfo, _JSAMPIMAGE input_buf,
JDIMENSION *in_row_group_ctr, JDIMENSION in_row_groups_avail,
- JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ _JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail)
{
my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample;
@@ -95,9 +97,10 @@ sep_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
if (num_rows > out_rows_avail)
num_rows = out_rows_avail;
- (*cinfo->cconvert->color_convert) (cinfo, upsample->color_buf,
- (JDIMENSION)upsample->next_row_out,
- output_buf + *out_row_ctr, (int)num_rows);
+ (*cinfo->cconvert->_color_convert) (cinfo, upsample->color_buf,
+ (JDIMENSION)upsample->next_row_out,
+ output_buf + *out_row_ctr,
+ (int)num_rows);
/* Adjust counts */
*out_row_ctr += num_rows;
@@ -124,7 +127,7 @@ sep_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
METHODDEF(void)
fullsize_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
+ _JSAMPARRAY input_data, _JSAMPARRAY *output_data_ptr)
{
*output_data_ptr = input_data;
}
@@ -137,7 +140,7 @@ fullsize_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
METHODDEF(void)
noop_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
+ _JSAMPARRAY input_data, _JSAMPARRAY *output_data_ptr)
{
*output_data_ptr = NULL; /* safety check */
}
@@ -156,14 +159,14 @@ noop_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
METHODDEF(void)
int_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
+ _JSAMPARRAY input_data, _JSAMPARRAY *output_data_ptr)
{
my_upsample_ptr upsample = (my_upsample_ptr)cinfo->upsample;
- JSAMPARRAY output_data = *output_data_ptr;
- register JSAMPROW inptr, outptr;
- register JSAMPLE invalue;
+ _JSAMPARRAY output_data = *output_data_ptr;
+ register _JSAMPROW inptr, outptr;
+ register _JSAMPLE invalue;
register int h;
- JSAMPROW outend;
+ _JSAMPROW outend;
int h_expand, v_expand;
int inrow, outrow;
@@ -184,8 +187,8 @@ int_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
}
/* Generate any additional output rows by duplicating the first one */
if (v_expand > 1) {
- jcopy_sample_rows(output_data, outrow, output_data, outrow + 1,
- v_expand - 1, cinfo->output_width);
+ _jcopy_sample_rows(output_data, outrow, output_data, outrow + 1,
+ v_expand - 1, cinfo->output_width);
}
inrow++;
outrow += v_expand;
@@ -200,12 +203,12 @@ int_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
METHODDEF(void)
h2v1_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
+ _JSAMPARRAY input_data, _JSAMPARRAY *output_data_ptr)
{
- JSAMPARRAY output_data = *output_data_ptr;
- register JSAMPROW inptr, outptr;
- register JSAMPLE invalue;
- JSAMPROW outend;
+ _JSAMPARRAY output_data = *output_data_ptr;
+ register _JSAMPROW inptr, outptr;
+ register _JSAMPLE invalue;
+ _JSAMPROW outend;
int inrow;
for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) {
@@ -228,12 +231,12 @@ h2v1_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
METHODDEF(void)
h2v2_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
+ _JSAMPARRAY input_data, _JSAMPARRAY *output_data_ptr)
{
- JSAMPARRAY output_data = *output_data_ptr;
- register JSAMPROW inptr, outptr;
- register JSAMPLE invalue;
- JSAMPROW outend;
+ _JSAMPARRAY output_data = *output_data_ptr;
+ register _JSAMPROW inptr, outptr;
+ register _JSAMPLE invalue;
+ _JSAMPROW outend;
int inrow, outrow;
inrow = outrow = 0;
@@ -246,8 +249,8 @@ h2v2_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
*outptr++ = invalue;
*outptr++ = invalue;
}
- jcopy_sample_rows(output_data, outrow, output_data, outrow + 1, 1,
- cinfo->output_width);
+ _jcopy_sample_rows(output_data, outrow, output_data, outrow + 1, 1,
+ cinfo->output_width);
inrow++;
outrow += 2;
}
@@ -271,10 +274,10 @@ h2v2_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
METHODDEF(void)
h2v1_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
+ _JSAMPARRAY input_data, _JSAMPARRAY *output_data_ptr)
{
- JSAMPARRAY output_data = *output_data_ptr;
- register JSAMPROW inptr, outptr;
+ _JSAMPARRAY output_data = *output_data_ptr;
+ register _JSAMPROW inptr, outptr;
register int invalue;
register JDIMENSION colctr;
int inrow;
@@ -284,20 +287,20 @@ h2v1_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
outptr = output_data[inrow];
/* Special case for first column */
invalue = *inptr++;
- *outptr++ = (JSAMPLE)invalue;
- *outptr++ = (JSAMPLE)((invalue * 3 + inptr[0] + 2) >> 2);
+ *outptr++ = (_JSAMPLE)invalue;
+ *outptr++ = (_JSAMPLE)((invalue * 3 + inptr[0] + 2) >> 2);
for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) {
/* General case: 3/4 * nearer pixel + 1/4 * further pixel */
invalue = (*inptr++) * 3;
- *outptr++ = (JSAMPLE)((invalue + inptr[-2] + 1) >> 2);
- *outptr++ = (JSAMPLE)((invalue + inptr[0] + 2) >> 2);
+ *outptr++ = (_JSAMPLE)((invalue + inptr[-2] + 1) >> 2);
+ *outptr++ = (_JSAMPLE)((invalue + inptr[0] + 2) >> 2);
}
/* Special case for last column */
invalue = *inptr;
- *outptr++ = (JSAMPLE)((invalue * 3 + inptr[-1] + 1) >> 2);
- *outptr++ = (JSAMPLE)invalue;
+ *outptr++ = (_JSAMPLE)((invalue * 3 + inptr[-1] + 1) >> 2);
+ *outptr++ = (_JSAMPLE)invalue;
}
}
@@ -311,10 +314,10 @@ h2v1_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
METHODDEF(void)
h1v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
+ _JSAMPARRAY input_data, _JSAMPARRAY *output_data_ptr)
{
- JSAMPARRAY output_data = *output_data_ptr;
- JSAMPROW inptr0, inptr1, outptr;
+ _JSAMPARRAY output_data = *output_data_ptr;
+ _JSAMPROW inptr0, inptr1, outptr;
#if BITS_IN_JSAMPLE == 8
int thiscolsum, bias;
#else
@@ -339,7 +342,7 @@ h1v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
for (colctr = 0; colctr < compptr->downsampled_width; colctr++) {
thiscolsum = (*inptr0++) * 3 + (*inptr1++);
- *outptr++ = (JSAMPLE)((thiscolsum + bias) >> 2);
+ *outptr++ = (_JSAMPLE)((thiscolsum + bias) >> 2);
}
}
inrow++;
@@ -357,10 +360,10 @@ h1v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
METHODDEF(void)
h2v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
+ _JSAMPARRAY input_data, _JSAMPARRAY *output_data_ptr)
{
- JSAMPARRAY output_data = *output_data_ptr;
- register JSAMPROW inptr0, inptr1, outptr;
+ _JSAMPARRAY output_data = *output_data_ptr;
+ register _JSAMPROW inptr0, inptr1, outptr;
#if BITS_IN_JSAMPLE == 8
register int thiscolsum, lastcolsum, nextcolsum;
#else
@@ -383,22 +386,22 @@ h2v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
/* Special case for first column */
thiscolsum = (*inptr0++) * 3 + (*inptr1++);
nextcolsum = (*inptr0++) * 3 + (*inptr1++);
- *outptr++ = (JSAMPLE)((thiscolsum * 4 + 8) >> 4);
- *outptr++ = (JSAMPLE)((thiscolsum * 3 + nextcolsum + 7) >> 4);
+ *outptr++ = (_JSAMPLE)((thiscolsum * 4 + 8) >> 4);
+ *outptr++ = (_JSAMPLE)((thiscolsum * 3 + nextcolsum + 7) >> 4);
lastcolsum = thiscolsum; thiscolsum = nextcolsum;
for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) {
/* General case: 3/4 * nearer pixel + 1/4 * further pixel in each */
/* dimension, thus 9/16, 3/16, 3/16, 1/16 overall */
nextcolsum = (*inptr0++) * 3 + (*inptr1++);
- *outptr++ = (JSAMPLE)((thiscolsum * 3 + lastcolsum + 8) >> 4);
- *outptr++ = (JSAMPLE)((thiscolsum * 3 + nextcolsum + 7) >> 4);
+ *outptr++ = (_JSAMPLE)((thiscolsum * 3 + lastcolsum + 8) >> 4);
+ *outptr++ = (_JSAMPLE)((thiscolsum * 3 + nextcolsum + 7) >> 4);
lastcolsum = thiscolsum; thiscolsum = nextcolsum;
}
/* Special case for last column */
- *outptr++ = (JSAMPLE)((thiscolsum * 3 + lastcolsum + 8) >> 4);
- *outptr++ = (JSAMPLE)((thiscolsum * 4 + 7) >> 4);
+ *outptr++ = (_JSAMPLE)((thiscolsum * 3 + lastcolsum + 8) >> 4);
+ *outptr++ = (_JSAMPLE)((thiscolsum * 4 + 7) >> 4);
}
inrow++;
}
@@ -410,7 +413,7 @@ h2v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
*/
GLOBAL(void)
-jinit_upsampler(j_decompress_ptr cinfo)
+_jinit_upsampler(j_decompress_ptr cinfo)
{
my_upsample_ptr upsample;
int ci;
@@ -418,13 +421,16 @@ jinit_upsampler(j_decompress_ptr cinfo)
boolean need_buffer, do_fancy;
int h_in_group, v_in_group, h_out_group, v_out_group;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
if (!cinfo->master->jinit_upsampler_no_alloc) {
upsample = (my_upsample_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_upsampler));
cinfo->upsample = (struct jpeg_upsampler *)upsample;
upsample->pub.start_pass = start_pass_upsample;
- upsample->pub.upsample = sep_upsample;
+ upsample->pub._upsample = sep_upsample;
upsample->pub.need_context_rows = FALSE; /* until we find out differently */
} else
upsample = (my_upsample_ptr)cinfo->upsample;
@@ -464,21 +470,25 @@ jinit_upsampler(j_decompress_ptr cinfo)
} else if (h_in_group * 2 == h_out_group && v_in_group == v_out_group) {
/* Special cases for 2h1v upsampling */
if (do_fancy && compptr->downsampled_width > 2) {
+#ifdef WITH_SIMD
if (jsimd_can_h2v1_fancy_upsample())
upsample->methods[ci] = jsimd_h2v1_fancy_upsample;
else
+#endif
upsample->methods[ci] = h2v1_fancy_upsample;
} else {
+#ifdef WITH_SIMD
if (jsimd_can_h2v1_upsample())
upsample->methods[ci] = jsimd_h2v1_upsample;
else
+#endif
upsample->methods[ci] = h2v1_upsample;
}
} else if (h_in_group == h_out_group &&
v_in_group * 2 == v_out_group && do_fancy) {
/* Non-fancy upsampling is handled by the generic method */
-#if defined(__arm__) || defined(__aarch64__) || \
- defined(_M_ARM) || defined(_M_ARM64)
+#if defined(WITH_SIMD) && (defined(__arm__) || defined(__aarch64__) || \
+ defined(_M_ARM) || defined(_M_ARM64))
if (jsimd_can_h1v2_fancy_upsample())
upsample->methods[ci] = jsimd_h1v2_fancy_upsample;
else
@@ -489,21 +499,25 @@ jinit_upsampler(j_decompress_ptr cinfo)
v_in_group * 2 == v_out_group) {
/* Special cases for 2h2v upsampling */
if (do_fancy && compptr->downsampled_width > 2) {
+#ifdef WITH_SIMD
if (jsimd_can_h2v2_fancy_upsample())
upsample->methods[ci] = jsimd_h2v2_fancy_upsample;
else
+#endif
upsample->methods[ci] = h2v2_fancy_upsample;
upsample->pub.need_context_rows = TRUE;
} else {
+#ifdef WITH_SIMD
if (jsimd_can_h2v2_upsample())
upsample->methods[ci] = jsimd_h2v2_upsample;
else
+#endif
upsample->methods[ci] = h2v2_upsample;
}
} else if ((h_out_group % h_in_group) == 0 &&
(v_out_group % v_in_group) == 0) {
/* Generic integral-factors upsampling method */
-#if defined(__mips__)
+#if defined(WITH_SIMD) && defined(__mips__)
if (jsimd_can_int_upsample())
upsample->methods[ci] = jsimd_int_upsample;
else
@@ -514,7 +528,7 @@ jinit_upsampler(j_decompress_ptr cinfo)
} else
ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL);
if (need_buffer && !cinfo->master->jinit_upsampler_no_alloc) {
- upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray)
+ upsample->color_buf[ci] = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE,
(JDIMENSION)jround_up((long)cinfo->output_width,
(long)cinfo->max_h_samp_factor),
@@ -522,3 +536,5 @@ jinit_upsampler(j_decompress_ptr cinfo)
}
}
}
+
+#endif /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */
diff --git a/src/3rdparty/libjpeg/src/jdsample.h b/src/3rdparty/libjpeg/src/jdsample.h
index a6bf08a032..a8a9298094 100644
--- a/src/3rdparty/libjpeg/src/jdsample.h
+++ b/src/3rdparty/libjpeg/src/jdsample.h
@@ -3,19 +3,22 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1996, Thomas G. Lane.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*/
#define JPEG_INTERNALS
#include "jpeglib.h"
+#include "jsamplecomp.h"
/* Pointer to routine to upsample a single component */
typedef void (*upsample1_ptr) (j_decompress_ptr cinfo,
jpeg_component_info *compptr,
- JSAMPARRAY input_data,
- JSAMPARRAY *output_data_ptr);
+ _JSAMPARRAY input_data,
+ _JSAMPARRAY *output_data_ptr);
/* Private subobject */
@@ -29,7 +32,7 @@ typedef struct {
* ie do not need rescaling. The corresponding entry of color_buf[] is
* simply set to point to the input data array, thereby avoiding copying.
*/
- JSAMPARRAY color_buf[MAX_COMPONENTS];
+ _JSAMPARRAY color_buf[MAX_COMPONENTS];
/* Per-component upsampling method pointers */
upsample1_ptr methods[MAX_COMPONENTS];
diff --git a/src/3rdparty/libjpeg/src/jdtrans.c b/src/3rdparty/libjpeg/src/jdtrans.c
index d7ec4b83b3..719813f676 100644
--- a/src/3rdparty/libjpeg/src/jdtrans.c
+++ b/src/3rdparty/libjpeg/src/jdtrans.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1995-1997, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2020, D. R. Commander.
+ * Copyright (C) 2020, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -16,7 +16,7 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
-#include "jpegcomp.h"
+#include "jpegapicomp.h"
/* Forward declarations */
@@ -48,6 +48,9 @@ LOCAL(void) transdecode_master_selection(j_decompress_ptr cinfo);
GLOBAL(jvirt_barray_ptr *)
jpeg_read_coefficients(j_decompress_ptr cinfo)
{
+ if (cinfo->master->lossless)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+
if (cinfo->global_state == DSTATE_READY) {
/* First call: initialize active modules */
transdecode_master_selection(cinfo);
@@ -127,7 +130,10 @@ transdecode_master_selection(j_decompress_ptr cinfo)
}
/* Always get a full-image coefficient buffer. */
- jinit_d_coef_controller(cinfo, TRUE);
+ if (cinfo->data_precision == 12)
+ j12init_d_coef_controller(cinfo, TRUE);
+ else
+ jinit_d_coef_controller(cinfo, TRUE);
/* We can now tell the memory manager to allocate virtual arrays. */
(*cinfo->mem->realize_virt_arrays) ((j_common_ptr)cinfo);
diff --git a/src/3rdparty/libjpeg/src/jerror.h b/src/3rdparty/libjpeg/src/jerror.h
index eb44a1140a..71ba03e2a3 100644
--- a/src/3rdparty/libjpeg/src/jerror.h
+++ b/src/3rdparty/libjpeg/src/jerror.h
@@ -4,8 +4,10 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1997, Thomas G. Lane.
* Modified 1997-2009 by Guido Vollbeding.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2014, 2017, 2021-2022, D. R. Commander.
+ * Copyright (C) 2014, 2017, 2021-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -53,7 +55,8 @@ JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS")
#if JPEG_LIB_VERSION >= 70
JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request")
#endif
-JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range")
+JMESSAGE(JERR_BAD_DCT_COEF,
+ "DCT coefficient (lossy) or spatial difference (lossless) out of range")
JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported")
#if JPEG_LIB_VERSION >= 70
JMESSAGE(JERR_BAD_DROP_SAMPLING,
@@ -69,9 +72,9 @@ JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan")
JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d")
JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d")
JMESSAGE(JERR_BAD_PROGRESSION,
- "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d")
+ "Invalid progressive/lossless parameters Ss=%d Se=%d Ah=%d Al=%d")
JMESSAGE(JERR_BAD_PROG_SCRIPT,
- "Invalid progressive parameters at scan script entry %d")
+ "Invalid progressive/lossless parameters at scan script entry %d")
JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors")
JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d")
JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d")
@@ -108,7 +111,7 @@ JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time")
#if JPEG_LIB_VERSION >= 70
JMESSAGE(JERR_NO_ARITH_TABLE, "Arithmetic table 0x%02x was not defined")
#endif
-JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported")
+JMESSAGE(JERR_NO_BACKING_STORE, "Memory limit exceeded")
JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined")
JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image")
JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined")
@@ -180,7 +183,7 @@ JMESSAGE(JTRC_THUMB_PALETTE,
JMESSAGE(JTRC_THUMB_RGB,
"JFIF extension marker: RGB thumbnail image, length %u")
JMESSAGE(JTRC_UNKNOWN_IDS,
- "Unrecognized component IDs %d %d %d, assuming YCbCr")
+ "Unrecognized component IDs %d %d %d, assuming YCbCr (lossy) or RGB (lossless)")
JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u")
JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u")
JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d")
@@ -211,6 +214,8 @@ JMESSAGE(JWRN_BOGUS_ICC, "Corrupt JPEG data: bad ICC marker")
JMESSAGE(JERR_BAD_DROP_SAMPLING,
"Component index %d: mismatching sampling ratio %d:%d, %d:%d, %c")
#endif
+JMESSAGE(JERR_BAD_RESTART,
+ "Invalid restart interval %d; must be an integer multiple of the number of MCUs in an MCU row (%d)")
#ifdef JMAKE_ENUM_LIST
diff --git a/src/3rdparty/libjpeg/src/jfdctfst.c b/src/3rdparty/libjpeg/src/jfdctfst.c
index 4c9ce0de8f..26070d19a6 100644
--- a/src/3rdparty/libjpeg/src/jfdctfst.c
+++ b/src/3rdparty/libjpeg/src/jfdctfst.c
@@ -114,7 +114,7 @@
*/
GLOBAL(void)
-jpeg_fdct_ifast(DCTELEM *data)
+_jpeg_fdct_ifast(DCTELEM *data)
{
DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
DCTELEM tmp10, tmp11, tmp12, tmp13;
diff --git a/src/3rdparty/libjpeg/src/jfdctint.c b/src/3rdparty/libjpeg/src/jfdctint.c
index c95a3a7fb8..974013fa40 100644
--- a/src/3rdparty/libjpeg/src/jfdctint.c
+++ b/src/3rdparty/libjpeg/src/jfdctint.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2015, 2020, D. R. Commander.
+ * Copyright (C) 2015, 2020, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -140,7 +140,7 @@
*/
GLOBAL(void)
-jpeg_fdct_islow(DCTELEM *data)
+_jpeg_fdct_islow(DCTELEM *data)
{
JLONG tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
JLONG tmp10, tmp11, tmp12, tmp13;
diff --git a/src/3rdparty/libjpeg/src/jidctflt.c b/src/3rdparty/libjpeg/src/jidctflt.c
index 5aee74e232..ee3a31a616 100644
--- a/src/3rdparty/libjpeg/src/jidctflt.c
+++ b/src/3rdparty/libjpeg/src/jidctflt.c
@@ -5,7 +5,7 @@
* Copyright (C) 1994-1998, Thomas G. Lane.
* Modified 2010 by Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2014, D. R. Commander.
+ * Copyright (C) 2014, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -69,9 +69,9 @@
*/
GLOBAL(void)
-jpeg_idct_float(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_float(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
FAST_FLOAT tmp10, tmp11, tmp12, tmp13;
@@ -79,8 +79,8 @@ jpeg_idct_float(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR inptr;
FLOAT_MULT_TYPE *quantptr;
FAST_FLOAT *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = cinfo->sample_range_limit;
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
int ctr;
FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */
#define _0_125 ((FLOAT_MULT_TYPE)0.125)
@@ -192,7 +192,7 @@ jpeg_idct_float(j_decompress_ptr cinfo, jpeg_component_info *compptr,
/* Even part */
/* Apply signed->unsigned and prepare float->int conversion */
- z5 = wsptr[0] + ((FAST_FLOAT)CENTERJSAMPLE + (FAST_FLOAT)0.5);
+ z5 = wsptr[0] + ((FAST_FLOAT)_CENTERJSAMPLE + (FAST_FLOAT)0.5);
tmp10 = z5 + wsptr[4];
tmp11 = z5 - wsptr[4];
diff --git a/src/3rdparty/libjpeg/src/jidctfst.c b/src/3rdparty/libjpeg/src/jidctfst.c
index 89a20c937b..68119b9942 100644
--- a/src/3rdparty/libjpeg/src/jidctfst.c
+++ b/src/3rdparty/libjpeg/src/jidctfst.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1998, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2015, D. R. Commander.
+ * Copyright (C) 2015, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -64,10 +64,10 @@
* The dequantized coefficients are not integers because the AA&N scaling
* factors have been incorporated. We represent them scaled up by PASS1_BITS,
* so that the first and second IDCT rounds have the same input scaling.
- * For 8-bit JSAMPLEs, we choose IFAST_SCALE_BITS = PASS1_BITS so as to
+ * For 8-bit samples, we choose IFAST_SCALE_BITS = PASS1_BITS so as to
* avoid a descaling shift; this compromises accuracy rather drastically
* for small quantization table entries, but it saves a lot of shifts.
- * For 12-bit JSAMPLEs, there's no hope of using 16x16 multiplies anyway,
+ * For 12-bit samples, there's no hope of using 16x16 multiplies anyway,
* so we use a much larger scaling factor to preserve accuracy.
*
* A final compromise is to represent the multiplicative constants to only
@@ -168,9 +168,9 @@
*/
GLOBAL(void)
-jpeg_idct_ifast(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_ifast(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
DCTELEM tmp10, tmp11, tmp12, tmp13;
@@ -178,8 +178,8 @@ jpeg_idct_ifast(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR inptr;
IFAST_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[DCTSIZE2]; /* buffers data between passes */
SHIFT_TEMPS /* for DESCALE */
@@ -296,7 +296,7 @@ jpeg_idct_ifast(j_decompress_ptr cinfo, jpeg_component_info *compptr,
if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 &&
wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) {
/* AC terms all zero */
- JSAMPLE dcval =
+ _JSAMPLE dcval =
range_limit[IDESCALE(wsptr[0], PASS1_BITS + 3) & RANGE_MASK];
outptr[0] = dcval;
diff --git a/src/3rdparty/libjpeg/src/jidctint.c b/src/3rdparty/libjpeg/src/jidctint.c
index bb08748019..c58592d626 100644
--- a/src/3rdparty/libjpeg/src/jidctint.c
+++ b/src/3rdparty/libjpeg/src/jidctint.c
@@ -5,7 +5,7 @@
* Copyright (C) 1991-1998, Thomas G. Lane.
* Modification developed 2002-2018 by Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2015, 2020, D. R. Commander.
+ * Copyright (C) 2015, 2020, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -170,9 +170,9 @@
*/
GLOBAL(void)
-jpeg_idct_islow(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_islow(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp0, tmp1, tmp2, tmp3;
JLONG tmp10, tmp11, tmp12, tmp13;
@@ -180,8 +180,8 @@ jpeg_idct_islow(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[DCTSIZE2]; /* buffers data between passes */
SHIFT_TEMPS
@@ -314,8 +314,8 @@ jpeg_idct_islow(j_decompress_ptr cinfo, jpeg_component_info *compptr,
if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 &&
wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) {
/* AC terms all zero */
- JSAMPLE dcval = range_limit[(int)DESCALE((JLONG)wsptr[0],
- PASS1_BITS + 3) & RANGE_MASK];
+ _JSAMPLE dcval = range_limit[(int)DESCALE((JLONG)wsptr[0],
+ PASS1_BITS + 3) & RANGE_MASK];
outptr[0] = dcval;
outptr[1] = dcval;
@@ -424,17 +424,17 @@ jpeg_idct_islow(j_decompress_ptr cinfo, jpeg_component_info *compptr,
*/
GLOBAL(void)
-jpeg_idct_7x7(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_7x7(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp0, tmp1, tmp2, tmp10, tmp11, tmp12, tmp13;
JLONG z1, z2, z3;
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[7 * 7]; /* buffers data between passes */
SHIFT_TEMPS
@@ -573,17 +573,17 @@ jpeg_idct_7x7(j_decompress_ptr cinfo, jpeg_component_info *compptr,
*/
GLOBAL(void)
-jpeg_idct_6x6(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_6x6(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp0, tmp1, tmp2, tmp10, tmp11, tmp12;
JLONG z1, z2, z3;
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[6 * 6]; /* buffers data between passes */
SHIFT_TEMPS
@@ -694,17 +694,17 @@ jpeg_idct_6x6(j_decompress_ptr cinfo, jpeg_component_info *compptr,
*/
GLOBAL(void)
-jpeg_idct_5x5(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_5x5(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp0, tmp1, tmp10, tmp11, tmp12;
JLONG z1, z2, z3;
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[5 * 5]; /* buffers data between passes */
SHIFT_TEMPS
@@ -809,16 +809,16 @@ jpeg_idct_5x5(j_decompress_ptr cinfo, jpeg_component_info *compptr,
*/
GLOBAL(void)
-jpeg_idct_3x3(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_3x3(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp0, tmp2, tmp10, tmp12;
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[3 * 3]; /* buffers data between passes */
SHIFT_TEMPS
@@ -899,17 +899,17 @@ jpeg_idct_3x3(j_decompress_ptr cinfo, jpeg_component_info *compptr,
*/
GLOBAL(void)
-jpeg_idct_9x9(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_9x9(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13, tmp14;
JLONG z1, z2, z3, z4;
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[8 * 9]; /* buffers data between passes */
SHIFT_TEMPS
@@ -1070,9 +1070,9 @@ jpeg_idct_9x9(j_decompress_ptr cinfo, jpeg_component_info *compptr,
*/
GLOBAL(void)
-jpeg_idct_10x10(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_10x10(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp10, tmp11, tmp12, tmp13, tmp14;
JLONG tmp20, tmp21, tmp22, tmp23, tmp24;
@@ -1080,8 +1080,8 @@ jpeg_idct_10x10(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[8 * 10]; /* buffers data between passes */
SHIFT_TEMPS
@@ -1265,9 +1265,9 @@ jpeg_idct_10x10(j_decompress_ptr cinfo, jpeg_component_info *compptr,
*/
GLOBAL(void)
-jpeg_idct_11x11(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_11x11(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp10, tmp11, tmp12, tmp13, tmp14;
JLONG tmp20, tmp21, tmp22, tmp23, tmp24, tmp25;
@@ -1275,8 +1275,8 @@ jpeg_idct_11x11(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[8 * 11]; /* buffers data between passes */
SHIFT_TEMPS
@@ -1459,9 +1459,9 @@ jpeg_idct_11x11(j_decompress_ptr cinfo, jpeg_component_info *compptr,
*/
GLOBAL(void)
-jpeg_idct_12x12(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_12x12(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
JLONG tmp20, tmp21, tmp22, tmp23, tmp24, tmp25;
@@ -1469,8 +1469,8 @@ jpeg_idct_12x12(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[8 * 12]; /* buffers data between passes */
SHIFT_TEMPS
@@ -1675,9 +1675,9 @@ jpeg_idct_12x12(j_decompress_ptr cinfo, jpeg_component_info *compptr,
*/
GLOBAL(void)
-jpeg_idct_13x13(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_13x13(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
JLONG tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;
@@ -1685,8 +1685,8 @@ jpeg_idct_13x13(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[8 * 13]; /* buffers data between passes */
SHIFT_TEMPS
@@ -1903,9 +1903,9 @@ jpeg_idct_13x13(j_decompress_ptr cinfo, jpeg_component_info *compptr,
*/
GLOBAL(void)
-jpeg_idct_14x14(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_14x14(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
JLONG tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;
@@ -1913,8 +1913,8 @@ jpeg_idct_14x14(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[8 * 14]; /* buffers data between passes */
SHIFT_TEMPS
@@ -2129,9 +2129,9 @@ jpeg_idct_14x14(j_decompress_ptr cinfo, jpeg_component_info *compptr,
*/
GLOBAL(void)
-jpeg_idct_15x15(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_15x15(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
JLONG tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27;
@@ -2139,8 +2139,8 @@ jpeg_idct_15x15(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[8 * 15]; /* buffers data between passes */
SHIFT_TEMPS
@@ -2371,9 +2371,9 @@ jpeg_idct_15x15(j_decompress_ptr cinfo, jpeg_component_info *compptr,
*/
GLOBAL(void)
-jpeg_idct_16x16(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_16x16(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13;
JLONG tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27;
@@ -2381,8 +2381,8 @@ jpeg_idct_16x16(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[8 * 16]; /* buffers data between passes */
SHIFT_TEMPS
diff --git a/src/3rdparty/libjpeg/src/jidctred.c b/src/3rdparty/libjpeg/src/jidctred.c
index 1dd65a94d9..6521e3ebbf 100644
--- a/src/3rdparty/libjpeg/src/jidctred.c
+++ b/src/3rdparty/libjpeg/src/jidctred.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1998, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2015, D. R. Commander.
+ * Copyright (C) 2015, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -118,17 +118,17 @@
*/
GLOBAL(void)
-jpeg_idct_4x4(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_4x4(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp0, tmp2, tmp10, tmp12;
JLONG z1, z2, z3, z4;
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[DCTSIZE * 4]; /* buffers data between passes */
SHIFT_TEMPS
@@ -210,8 +210,8 @@ jpeg_idct_4x4(j_decompress_ptr cinfo, jpeg_component_info *compptr,
if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 &&
wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) {
/* AC terms all zero */
- JSAMPLE dcval = range_limit[(int)DESCALE((JLONG)wsptr[0],
- PASS1_BITS + 3) & RANGE_MASK];
+ _JSAMPLE dcval = range_limit[(int)DESCALE((JLONG)wsptr[0],
+ PASS1_BITS + 3) & RANGE_MASK];
outptr[0] = dcval;
outptr[1] = dcval;
@@ -276,16 +276,16 @@ jpeg_idct_4x4(j_decompress_ptr cinfo, jpeg_component_info *compptr,
*/
GLOBAL(void)
-jpeg_idct_2x2(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_2x2(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
JLONG tmp0, tmp10, z1;
JCOEFPTR inptr;
ISLOW_MULT_TYPE *quantptr;
int *wsptr;
- JSAMPROW outptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPROW outptr;
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
int ctr;
int workspace[DCTSIZE * 2]; /* buffers data between passes */
SHIFT_TEMPS
@@ -345,8 +345,8 @@ jpeg_idct_2x2(j_decompress_ptr cinfo, jpeg_component_info *compptr,
#ifndef NO_ZERO_ROW_TEST
if (wsptr[1] == 0 && wsptr[3] == 0 && wsptr[5] == 0 && wsptr[7] == 0) {
/* AC terms all zero */
- JSAMPLE dcval = range_limit[(int)DESCALE((JLONG)wsptr[0],
- PASS1_BITS + 3) & RANGE_MASK];
+ _JSAMPLE dcval = range_limit[(int)DESCALE((JLONG)wsptr[0],
+ PASS1_BITS + 3) & RANGE_MASK];
outptr[0] = dcval;
outptr[1] = dcval;
@@ -387,13 +387,13 @@ jpeg_idct_2x2(j_decompress_ptr cinfo, jpeg_component_info *compptr,
*/
GLOBAL(void)
-jpeg_idct_1x1(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
+_jpeg_idct_1x1(j_decompress_ptr cinfo, jpeg_component_info *compptr,
+ JCOEFPTR coef_block, _JSAMPARRAY output_buf,
+ JDIMENSION output_col)
{
int dcval;
ISLOW_MULT_TYPE *quantptr;
- JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ _JSAMPLE *range_limit = IDCT_range_limit(cinfo);
SHIFT_TEMPS
/* We hardly need an inverse DCT routine for this: just take the
diff --git a/src/3rdparty/libjpeg/src/jinclude.h b/src/3rdparty/libjpeg/src/jinclude.h
index e8d983ac17..56e7a4b296 100644
--- a/src/3rdparty/libjpeg/src/jinclude.h
+++ b/src/3rdparty/libjpeg/src/jinclude.h
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1994, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2022, D. R. Commander.
+ * Copyright (C) 2022-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -123,6 +123,8 @@ static INLINE int GETENV_S(char *buffer, size_t buffer_size, const char *name)
#else
+#include <errno.h>
+
/* This provides a similar interface to the Microsoft _putenv_s() function, but
* other than parameter validation, it has no advantages over setenv().
*/
diff --git a/src/3rdparty/libjpeg/src/jlossls.h b/src/3rdparty/libjpeg/src/jlossls.h
new file mode 100644
index 0000000000..ce41704134
--- /dev/null
+++ b/src/3rdparty/libjpeg/src/jlossls.h
@@ -0,0 +1,101 @@
+/*
+ * jlossls.h
+ *
+ * This file was part of the Independent JPEG Group's software:
+ * Copyright (C) 1998, Thomas G. Lane.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ *
+ * This include file contains common declarations for the lossless JPEG
+ * codec modules.
+ */
+
+#ifndef JLOSSLS_H
+#define JLOSSLS_H
+
+#if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED)
+
+#define JPEG_INTERNALS
+#include "jpeglib.h"
+#include "jsamplecomp.h"
+
+
+#define ALLOC_DARRAY(pool_id, diffsperrow, numrows) \
+ (JDIFFARRAY)(*cinfo->mem->alloc_sarray) \
+ ((j_common_ptr)cinfo, pool_id, \
+ (diffsperrow) * sizeof(JDIFF) / sizeof(_JSAMPLE), numrows)
+
+
+/*
+ * Table H.1: Predictors for lossless coding.
+ */
+
+#define PREDICTOR1 Ra
+#define PREDICTOR2 Rb
+#define PREDICTOR3 Rc
+#define PREDICTOR4 (int)((JLONG)Ra + (JLONG)Rb - (JLONG)Rc)
+#define PREDICTOR5 (int)((JLONG)Ra + RIGHT_SHIFT((JLONG)Rb - (JLONG)Rc, 1))
+#define PREDICTOR6 (int)((JLONG)Rb + RIGHT_SHIFT((JLONG)Ra - (JLONG)Rc, 1))
+#define PREDICTOR7 (int)RIGHT_SHIFT((JLONG)Ra + (JLONG)Rb, 1)
+
+#endif
+
+
+#ifdef C_LOSSLESS_SUPPORTED
+
+typedef void (*predict_difference_method_ptr) (j_compress_ptr cinfo, int ci,
+ _JSAMPROW input_buf,
+ _JSAMPROW prev_row,
+ JDIFFROW diff_buf,
+ JDIMENSION width);
+
+/* Lossless compressor */
+typedef struct {
+ struct jpeg_forward_dct pub; /* public fields */
+
+ /* It is useful to allow each component to have a separate diff method. */
+ predict_difference_method_ptr predict_difference[MAX_COMPONENTS];
+
+ /* MCU rows left in the restart interval for each component */
+ unsigned int restart_rows_to_go[MAX_COMPONENTS];
+
+ /* Sample scaling */
+ void (*scaler_scale) (j_compress_ptr cinfo, _JSAMPROW input_buf,
+ _JSAMPROW output_buf, JDIMENSION width);
+} jpeg_lossless_compressor;
+
+typedef jpeg_lossless_compressor *lossless_comp_ptr;
+
+#endif /* C_LOSSLESS_SUPPORTED */
+
+
+#ifdef D_LOSSLESS_SUPPORTED
+
+typedef void (*predict_undifference_method_ptr) (j_decompress_ptr cinfo,
+ int comp_index,
+ JDIFFROW diff_buf,
+ JDIFFROW prev_row,
+ JDIFFROW undiff_buf,
+ JDIMENSION width);
+
+/* Lossless decompressor */
+typedef struct {
+ struct jpeg_inverse_dct pub; /* public fields */
+
+ /* It is useful to allow each component to have a separate undiff method. */
+ predict_undifference_method_ptr predict_undifference[MAX_COMPONENTS];
+
+ /* Sample scaling */
+ void (*scaler_scale) (j_decompress_ptr cinfo, JDIFFROW diff_buf,
+ _JSAMPROW output_buf, JDIMENSION width);
+} jpeg_lossless_decompressor;
+
+typedef jpeg_lossless_decompressor *lossless_decomp_ptr;
+
+#endif /* D_LOSSLESS_SUPPORTED */
+
+#endif /* JLOSSLS_H */
diff --git a/src/3rdparty/libjpeg/src/jmemmgr.c b/src/3rdparty/libjpeg/src/jmemmgr.c
index a40446f6ac..dca8f5c22c 100644
--- a/src/3rdparty/libjpeg/src/jmemmgr.c
+++ b/src/3rdparty/libjpeg/src/jmemmgr.c
@@ -155,7 +155,9 @@ typedef my_memory_mgr *my_mem_ptr;
*/
struct jvirt_sarray_control {
- JSAMPARRAY mem_buffer; /* => the in-memory buffer */
+ JSAMPARRAY mem_buffer; /* => the in-memory buffer (if
+ cinfo->data_precision is 12, then this is
+ actually a J12SAMPARRAY) */
JDIMENSION rows_in_array; /* total virtual array height */
JDIMENSION samplesperrow; /* width of array (and of memory buffer) */
JDIMENSION maxaccess; /* max rows accessed by access_virt_sarray */
@@ -351,9 +353,10 @@ alloc_small(j_common_ptr cinfo, int pool_id, size_t sizeofobject)
* request is large enough that it may as well be passed directly to
* jpeg_get_large; the pool management just links everything together
* so that we can free it all on demand.
- * Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY
- * structures. The routines that create these structures (see below)
- * deliberately bunch rows together to ensure a large request size.
+ * Note: the major use of "large" objects is in
+ * JSAMPARRAY/J12SAMPARRAY/J16SAMPARRAY and JBLOCKARRAY structures. The
+ * routines that create these structures (see below) deliberately bunch rows
+ * together to ensure a large request size.
*/
METHODDEF(void *)
@@ -437,9 +440,22 @@ alloc_sarray(j_common_ptr cinfo, int pool_id, JDIMENSION samplesperrow,
JSAMPROW workspace;
JDIMENSION rowsperchunk, currow, i;
long ltemp;
+ J12SAMPARRAY result12;
+ J12SAMPROW workspace12;
+#if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED)
+ J16SAMPARRAY result16;
+ J16SAMPROW workspace16;
+#endif
+ int data_precision = cinfo->is_decompressor ?
+ ((j_decompress_ptr)cinfo)->data_precision :
+ ((j_compress_ptr)cinfo)->data_precision;
+ size_t sample_size = data_precision == 16 ?
+ sizeof(J16SAMPLE) : (data_precision == 12 ?
+ sizeof(J12SAMPLE) :
+ sizeof(JSAMPLE));
/* Make sure each row is properly aligned */
- if ((ALIGN_SIZE % sizeof(JSAMPLE)) != 0)
+ if ((ALIGN_SIZE % sample_size) != 0)
out_of_memory(cinfo, 5); /* safety check */
if (samplesperrow > MAX_ALLOC_CHUNK) {
@@ -448,11 +464,11 @@ alloc_sarray(j_common_ptr cinfo, int pool_id, JDIMENSION samplesperrow,
out_of_memory(cinfo, 9);
}
samplesperrow = (JDIMENSION)round_up_pow2(samplesperrow, (2 * ALIGN_SIZE) /
- sizeof(JSAMPLE));
+ sample_size);
/* Calculate max # of rows allowed in one allocation chunk */
ltemp = (MAX_ALLOC_CHUNK - sizeof(large_pool_hdr)) /
- ((long)samplesperrow * sizeof(JSAMPLE));
+ ((long)samplesperrow * (long)sample_size);
if (ltemp <= 0)
ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
if (ltemp < (long)numrows)
@@ -461,24 +477,68 @@ alloc_sarray(j_common_ptr cinfo, int pool_id, JDIMENSION samplesperrow,
rowsperchunk = numrows;
mem->last_rowsperchunk = rowsperchunk;
- /* Get space for row pointers (small object) */
- result = (JSAMPARRAY)alloc_small(cinfo, pool_id,
- (size_t)(numrows * sizeof(JSAMPROW)));
+ if (data_precision == 16) {
+#if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED)
+ /* Get space for row pointers (small object) */
+ result16 = (J16SAMPARRAY)alloc_small(cinfo, pool_id,
+ (size_t)(numrows *
+ sizeof(J16SAMPROW)));
+
+ /* Get the rows themselves (large objects) */
+ currow = 0;
+ while (currow < numrows) {
+ rowsperchunk = MIN(rowsperchunk, numrows - currow);
+ workspace16 = (J16SAMPROW)alloc_large(cinfo, pool_id,
+ (size_t)((size_t)rowsperchunk * (size_t)samplesperrow * sample_size));
+ for (i = rowsperchunk; i > 0; i--) {
+ result16[currow++] = workspace16;
+ workspace16 += samplesperrow;
+ }
+ }
- /* Get the rows themselves (large objects) */
- currow = 0;
- while (currow < numrows) {
- rowsperchunk = MIN(rowsperchunk, numrows - currow);
- workspace = (JSAMPROW)alloc_large(cinfo, pool_id,
- (size_t)((size_t)rowsperchunk * (size_t)samplesperrow *
- sizeof(JSAMPLE)));
- for (i = rowsperchunk; i > 0; i--) {
- result[currow++] = workspace;
- workspace += samplesperrow;
+ return (JSAMPARRAY)result16;
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, data_precision);
+ return NULL;
+#endif
+ } else if (data_precision == 12) {
+ /* Get space for row pointers (small object) */
+ result12 = (J12SAMPARRAY)alloc_small(cinfo, pool_id,
+ (size_t)(numrows *
+ sizeof(J12SAMPROW)));
+
+ /* Get the rows themselves (large objects) */
+ currow = 0;
+ while (currow < numrows) {
+ rowsperchunk = MIN(rowsperchunk, numrows - currow);
+ workspace12 = (J12SAMPROW)alloc_large(cinfo, pool_id,
+ (size_t)((size_t)rowsperchunk * (size_t)samplesperrow * sample_size));
+ for (i = rowsperchunk; i > 0; i--) {
+ result12[currow++] = workspace12;
+ workspace12 += samplesperrow;
+ }
}
- }
- return result;
+ return (JSAMPARRAY)result12;
+ } else {
+ /* Get space for row pointers (small object) */
+ result = (JSAMPARRAY)alloc_small(cinfo, pool_id,
+ (size_t)(numrows * sizeof(JSAMPROW)));
+
+ /* Get the rows themselves (large objects) */
+ currow = 0;
+ while (currow < numrows) {
+ rowsperchunk = MIN(rowsperchunk, numrows - currow);
+ workspace = (JSAMPROW)alloc_large(cinfo, pool_id,
+ (size_t)((size_t)rowsperchunk * (size_t)samplesperrow * sample_size));
+ for (i = rowsperchunk; i > 0; i--) {
+ result[currow++] = workspace;
+ workspace += samplesperrow;
+ }
+ }
+
+ return result;
+ }
}
@@ -640,6 +700,13 @@ realize_virt_arrays(j_common_ptr cinfo)
size_t minheights, max_minheights;
jvirt_sarray_ptr sptr;
jvirt_barray_ptr bptr;
+ int data_precision = cinfo->is_decompressor ?
+ ((j_decompress_ptr)cinfo)->data_precision :
+ ((j_compress_ptr)cinfo)->data_precision;
+ size_t sample_size = data_precision == 16 ?
+ sizeof(J16SAMPLE) : (data_precision == 12 ?
+ sizeof(J12SAMPLE) :
+ sizeof(JSAMPLE));
/* Compute the minimum space needed (maxaccess rows in each buffer)
* and the maximum space needed (full image height in each buffer).
@@ -650,10 +717,10 @@ realize_virt_arrays(j_common_ptr cinfo)
for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {
if (sptr->mem_buffer == NULL) { /* if not realized yet */
size_t new_space = (long)sptr->rows_in_array *
- (long)sptr->samplesperrow * sizeof(JSAMPLE);
+ (long)sptr->samplesperrow * sample_size;
space_per_minheight += (long)sptr->maxaccess *
- (long)sptr->samplesperrow * sizeof(JSAMPLE);
+ (long)sptr->samplesperrow * sample_size;
if (SIZE_MAX - maximum_space < new_space)
out_of_memory(cinfo, 10);
maximum_space += new_space;
@@ -708,7 +775,7 @@ realize_virt_arrays(j_common_ptr cinfo)
jpeg_open_backing_store(cinfo, &sptr->b_s_info,
(long)sptr->rows_in_array *
(long)sptr->samplesperrow *
- (long)sizeof(JSAMPLE));
+ (long)sample_size);
sptr->b_s_open = TRUE;
}
sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE,
@@ -751,8 +818,15 @@ do_sarray_io(j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing)
/* Do backing store read or write of a virtual sample array */
{
long bytesperrow, file_offset, byte_count, rows, thisrow, i;
-
- bytesperrow = (long)ptr->samplesperrow * sizeof(JSAMPLE);
+ int data_precision = cinfo->is_decompressor ?
+ ((j_decompress_ptr)cinfo)->data_precision :
+ ((j_compress_ptr)cinfo)->data_precision;
+ size_t sample_size = data_precision == 16 ?
+ sizeof(J16SAMPLE) : (data_precision == 12 ?
+ sizeof(J12SAMPLE) :
+ sizeof(JSAMPLE));
+
+ bytesperrow = (long)ptr->samplesperrow * (long)sample_size;
file_offset = ptr->cur_start_row * bytesperrow;
/* Loop to read or write each allocation chunk in mem_buffer */
for (i = 0; i < (long)ptr->rows_in_mem; i += ptr->rowsperchunk) {
@@ -766,14 +840,42 @@ do_sarray_io(j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing)
if (rows <= 0) /* this chunk might be past end of file! */
break;
byte_count = rows * bytesperrow;
- if (writing)
- (*ptr->b_s_info.write_backing_store) (cinfo, &ptr->b_s_info,
- (void *)ptr->mem_buffer[i],
- file_offset, byte_count);
- else
- (*ptr->b_s_info.read_backing_store) (cinfo, &ptr->b_s_info,
- (void *)ptr->mem_buffer[i],
- file_offset, byte_count);
+ if (data_precision == 16) {
+#if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED)
+ J16SAMPARRAY mem_buffer16 = (J16SAMPARRAY)ptr->mem_buffer;
+
+ if (writing)
+ (*ptr->b_s_info.write_backing_store) (cinfo, &ptr->b_s_info,
+ (void *)mem_buffer16[i],
+ file_offset, byte_count);
+ else
+ (*ptr->b_s_info.read_backing_store) (cinfo, &ptr->b_s_info,
+ (void *)mem_buffer16[i],
+ file_offset, byte_count);
+#else
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, data_precision);
+#endif
+ } else if (data_precision == 12) {
+ J12SAMPARRAY mem_buffer12 = (J12SAMPARRAY)ptr->mem_buffer;
+
+ if (writing)
+ (*ptr->b_s_info.write_backing_store) (cinfo, &ptr->b_s_info,
+ (void *)mem_buffer12[i],
+ file_offset, byte_count);
+ else
+ (*ptr->b_s_info.read_backing_store) (cinfo, &ptr->b_s_info,
+ (void *)mem_buffer12[i],
+ file_offset, byte_count);
+ } else {
+ if (writing)
+ (*ptr->b_s_info.write_backing_store) (cinfo, &ptr->b_s_info,
+ (void *)ptr->mem_buffer[i],
+ file_offset, byte_count);
+ else
+ (*ptr->b_s_info.read_backing_store) (cinfo, &ptr->b_s_info,
+ (void *)ptr->mem_buffer[i],
+ file_offset, byte_count);
+ }
file_offset += byte_count;
}
}
@@ -821,6 +923,13 @@ access_virt_sarray(j_common_ptr cinfo, jvirt_sarray_ptr ptr,
{
JDIMENSION end_row = start_row + num_rows;
JDIMENSION undef_row;
+ int data_precision = cinfo->is_decompressor ?
+ ((j_decompress_ptr)cinfo)->data_precision :
+ ((j_compress_ptr)cinfo)->data_precision;
+ size_t sample_size = data_precision == 16 ?
+ sizeof(J16SAMPLE) : (data_precision == 12 ?
+ sizeof(J12SAMPLE) :
+ sizeof(JSAMPLE));
/* debugging check */
if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||
@@ -876,7 +985,7 @@ access_virt_sarray(j_common_ptr cinfo, jvirt_sarray_ptr ptr,
if (writable)
ptr->first_undef_row = end_row;
if (ptr->pre_zero) {
- size_t bytesperrow = (size_t)ptr->samplesperrow * sizeof(JSAMPLE);
+ size_t bytesperrow = (size_t)ptr->samplesperrow * sample_size;
undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */
end_row -= ptr->cur_start_row;
while (undef_row < end_row) {
diff --git a/src/3rdparty/libjpeg/src/jmemsys.h b/src/3rdparty/libjpeg/src/jmemsys.h
index 9229550afd..ac09ef4c36 100644
--- a/src/3rdparty/libjpeg/src/jmemsys.h
+++ b/src/3rdparty/libjpeg/src/jmemsys.h
@@ -99,24 +99,6 @@ EXTERN(size_t) jpeg_mem_available(j_common_ptr cinfo, size_t min_bytes_needed,
#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */
-#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */
-
-typedef unsigned short XMSH; /* type of extended-memory handles */
-typedef unsigned short EMSH; /* type of expanded-memory handles */
-
-typedef union {
- short file_handle; /* DOS file handle if it's a temp file */
- XMSH xms_handle; /* handle if it's a chunk of XMS */
- EMSH ems_handle; /* handle if it's a chunk of EMS */
-} handle_union;
-
-#endif /* USE_MSDOS_MEMMGR */
-
-#ifdef USE_MAC_MEMMGR /* Mac-specific junk */
-#include <Files.h>
-#endif /* USE_MAC_MEMMGR */
-
-
typedef struct backing_store_struct *backing_store_ptr;
typedef struct backing_store_struct {
@@ -130,22 +112,9 @@ typedef struct backing_store_struct {
void (*close_backing_store) (j_common_ptr cinfo, backing_store_ptr info);
/* Private fields for system-dependent backing-store management */
-#ifdef USE_MSDOS_MEMMGR
- /* For the MS-DOS manager (jmemdos.c), we need: */
- handle_union handle; /* reference to backing-store storage object */
- char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */
-#else
-#ifdef USE_MAC_MEMMGR
- /* For the Mac manager (jmemmac.c), we need: */
- short temp_file; /* file reference number to temp file */
- FSSpec tempSpec; /* the FSSpec for the temp file */
- char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */
-#else
/* For a typical implementation with temp files, we need: */
FILE *temp_file; /* stdio reference to temp file */
char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */
-#endif
-#endif
} backing_store_info;
diff --git a/src/3rdparty/libjpeg/src/jmorecfg.h b/src/3rdparty/libjpeg/src/jmorecfg.h
index b33a991914..89c7842c87 100644
--- a/src/3rdparty/libjpeg/src/jmorecfg.h
+++ b/src/3rdparty/libjpeg/src/jmorecfg.h
@@ -4,8 +4,10 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 1997-2009 by Guido Vollbeding.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2009, 2011, 2014-2015, 2018, 2020, D. R. Commander.
+ * Copyright (C) 2009, 2011, 2014-2015, 2018, 2020, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -41,31 +43,29 @@
* arrays is very slow on your hardware, you might want to change these.
*/
-#if BITS_IN_JSAMPLE == 8
-/* JSAMPLE should be the smallest type that will hold the values 0..255.
- */
+/* JSAMPLE should be the smallest type that will hold the values 0..255. */
typedef unsigned char JSAMPLE;
#define GETJSAMPLE(value) ((int)(value))
-#define MAXJSAMPLE 255
-#define CENTERJSAMPLE 128
+#define MAXJSAMPLE 255
+#define CENTERJSAMPLE 128
-#endif /* BITS_IN_JSAMPLE == 8 */
+/* J12SAMPLE should be the smallest type that will hold the values 0..4095. */
-#if BITS_IN_JSAMPLE == 12
-/* JSAMPLE should be the smallest type that will hold the values 0..4095.
- * On nearly all machines "short" will do nicely.
- */
+typedef short J12SAMPLE;
-typedef short JSAMPLE;
-#define GETJSAMPLE(value) ((int)(value))
+#define MAXJ12SAMPLE 4095
+#define CENTERJ12SAMPLE 2048
+
+
+/* J16SAMPLE should be the smallest type that will hold the values 0..65535. */
-#define MAXJSAMPLE 4095
-#define CENTERJSAMPLE 2048
+typedef unsigned short J16SAMPLE;
-#endif /* BITS_IN_JSAMPLE == 12 */
+#define MAXJ16SAMPLE 65535
+#define CENTERJ16SAMPLE 32768
/* Representation of a DCT frequency coefficient.
@@ -242,14 +242,16 @@ typedef int boolean;
#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */
#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/
+#define C_LOSSLESS_SUPPORTED /* Lossless JPEG? */
#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */
/* Note: if you selected 12-bit data precision, it is dangerous to turn off
* ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit
* precision, so jchuff.c normally uses entropy optimization to compute
* usable tables for higher precision. If you don't want to do optimization,
* you'll have to supply different default Huffman tables.
- * The exact same statements apply for progressive JPEG: the default tables
- * don't work for progressive mode. (This may get fixed, however.)
+ * The exact same statements apply for progressive and lossless JPEG:
+ * the default tables don't work for progressive mode or lossless mode.
+ * (This may get fixed, however.)
*/
#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */
@@ -257,6 +259,7 @@ typedef int boolean;
#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */
#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/
+#define D_LOSSLESS_SUPPORTED /* Lossless JPEG? */
#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */
#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */
#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */
diff --git a/src/3rdparty/libjpeg/src/jpeg_nbits_table.h b/src/3rdparty/libjpeg/src/jpeg_nbits.c
index fcf73878c3..c8ee6b056c 100644
--- a/src/3rdparty/libjpeg/src/jpeg_nbits_table.h
+++ b/src/3rdparty/libjpeg/src/jpeg_nbits.c
@@ -1,4 +1,32 @@
-static const unsigned char jpeg_nbits_table[65536] = {
+/*
+ * Copyright (C) 2024, D. R. Commander.
+ *
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ */
+
+#include "jpeg_nbits.h"
+#include "jconfigint.h"
+
+
+#ifndef USE_CLZ_INTRINSIC
+
+#define INCLUDE_JPEG_NBITS_TABLE
+
+/* When building for x86[-64] with the SIMD extensions enabled, the C Huffman
+ * encoders can reuse jpeg_nbits_table from the SSE2 baseline Huffman encoder.
+ */
+#if (defined(__x86_64__) || defined(__i386__) || defined(_M_IX86) || \
+ defined(_M_X64)) && defined(WITH_SIMD)
+#undef INCLUDE_JPEG_NBITS_TABLE
+#endif
+
+#endif
+
+
+#ifdef INCLUDE_JPEG_NBITS_TABLE
+
+const unsigned char HIDDEN jpeg_nbits_table[65536] = {
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
@@ -4096,3 +4124,11 @@ static const unsigned char jpeg_nbits_table[65536] = {
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16
};
+
+#else
+
+/* Suppress compiler warnings about empty translation unit. */
+
+typedef int dummy_jpeg_nbits_table;
+
+#endif
diff --git a/src/3rdparty/libjpeg/src/jpeg_nbits.h b/src/3rdparty/libjpeg/src/jpeg_nbits.h
new file mode 100644
index 0000000000..6481a1228d
--- /dev/null
+++ b/src/3rdparty/libjpeg/src/jpeg_nbits.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014, 2021, 2024, D. R. Commander.
+ * Copyright (C) 2014, Olle Liljenzin.
+ * Copyright (C) 2020, Arm Limited.
+ *
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ */
+
+/*
+ * NOTE: If USE_CLZ_INTRINSIC is defined, then clz/bsr instructions will be
+ * used for bit counting rather than the lookup table. This will reduce the
+ * memory footprint by 64k, which is important for some mobile applications
+ * that create many isolated instances of libjpeg-turbo (web browsers, for
+ * instance.) This may improve performance on some mobile platforms as well.
+ * This feature is enabled by default only on Arm processors, because some x86
+ * chips have a slow implementation of bsr, and the use of clz/bsr cannot be
+ * shown to have a significant performance impact even on the x86 chips that
+ * have a fast implementation of it. When building for Armv6, you can
+ * explicitly disable the use of clz/bsr by adding -mthumb to the compiler
+ * flags (this defines __thumb__).
+ */
+
+/* NOTE: Both GCC and Clang define __GNUC__ */
+#if (defined(__GNUC__) && (defined(__arm__) || defined(__aarch64__))) || \
+ defined(_M_ARM) || defined(_M_ARM64)
+#if !defined(__thumb__) || defined(__thumb2__)
+#define USE_CLZ_INTRINSIC
+#endif
+#endif
+
+#ifdef USE_CLZ_INTRINSIC
+#if defined(_MSC_VER) && !defined(__clang__)
+#define JPEG_NBITS_NONZERO(x) (32 - _CountLeadingZeros(x))
+#else
+#define JPEG_NBITS_NONZERO(x) (32 - __builtin_clz(x))
+#endif
+#define JPEG_NBITS(x) (x ? JPEG_NBITS_NONZERO(x) : 0)
+#else
+extern const unsigned char jpeg_nbits_table[65536];
+#define JPEG_NBITS(x) (jpeg_nbits_table[x])
+#define JPEG_NBITS_NONZERO(x) JPEG_NBITS(x)
+#endif
diff --git a/src/3rdparty/libjpeg/src/jpegcomp.h b/src/3rdparty/libjpeg/src/jpegapicomp.h
index c4834ac0df..bb3912eb2f 100644
--- a/src/3rdparty/libjpeg/src/jpegcomp.h
+++ b/src/3rdparty/libjpeg/src/jpegapicomp.h
@@ -1,5 +1,5 @@
/*
- * jpegcomp.h
+ * jpegapicomp.h
*
* Copyright (C) 2010, 2020, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
diff --git a/src/3rdparty/libjpeg/src/jpegint.h b/src/3rdparty/libjpeg/src/jpegint.h
index 6af9e2a179..6541420143 100644
--- a/src/3rdparty/libjpeg/src/jpegint.h
+++ b/src/3rdparty/libjpeg/src/jpegint.h
@@ -4,8 +4,10 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 1997-2009 by Guido Vollbeding.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2015-2016, 2019, 2021, D. R. Commander.
+ * Copyright (C) 2015-2017, 2019, 2021-2022, D. R. Commander.
* Copyright (C) 2015, Google, Inc.
* Copyright (C) 2021, Alex Richardson.
* For conditions of distribution and use, see the accompanying README.ijg
@@ -17,6 +19,17 @@
*/
+/* Representation of a spatial difference value.
+ * This should be a signed value of at least 16 bits; int is usually OK.
+ */
+
+typedef int JDIFF;
+
+typedef JDIFF FAR *JDIFFROW; /* pointer to one row of difference values */
+typedef JDIFFROW *JDIFFARRAY; /* ptr to some rows (a 2-D diff array) */
+typedef JDIFFARRAY *JDIFFIMAGE; /* a 3-D diff array: top index is color */
+
+
/* Declarations for both compression & decompression */
typedef enum { /* Operating modes for buffer controllers */
@@ -61,6 +74,9 @@ typedef __UINTPTR_TYPE__ JUINTPTR;
typedef size_t JUINTPTR;
#endif
+#define IsExtRGB(cs) \
+ (cs == JCS_RGB || (cs >= JCS_EXT_RGB && cs <= JCS_EXT_ARGB))
+
/*
* Left shift macro that handles a negative operand without causing any
* sanitizer warnings
@@ -80,6 +96,7 @@ struct jpeg_comp_master {
/* State variables made visible to other modules */
boolean call_pass_startup; /* True if pass_startup must be called */
boolean is_last_pass; /* True during last pass */
+ boolean lossless; /* True if lossless mode is enabled */
};
/* Main buffer control (downsampled-data buffer) */
@@ -87,6 +104,12 @@ struct jpeg_c_main_controller {
void (*start_pass) (j_compress_ptr cinfo, J_BUF_MODE pass_mode);
void (*process_data) (j_compress_ptr cinfo, JSAMPARRAY input_buf,
JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail);
+ void (*process_data_12) (j_compress_ptr cinfo, J12SAMPARRAY input_buf,
+ JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail);
+#ifdef C_LOSSLESS_SUPPORTED
+ void (*process_data_16) (j_compress_ptr cinfo, J16SAMPARRAY input_buf,
+ JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail);
+#endif
};
/* Compression preprocessing (downsampling input buffer control) */
@@ -97,12 +120,32 @@ struct jpeg_c_prep_controller {
JSAMPIMAGE output_buf,
JDIMENSION *out_row_group_ctr,
JDIMENSION out_row_groups_avail);
+ void (*pre_process_data_12) (j_compress_ptr cinfo, J12SAMPARRAY input_buf,
+ JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail,
+ J12SAMPIMAGE output_buf,
+ JDIMENSION *out_row_group_ctr,
+ JDIMENSION out_row_groups_avail);
+#ifdef C_LOSSLESS_SUPPORTED
+ void (*pre_process_data_16) (j_compress_ptr cinfo, J16SAMPARRAY input_buf,
+ JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail,
+ J16SAMPIMAGE output_buf,
+ JDIMENSION *out_row_group_ctr,
+ JDIMENSION out_row_groups_avail);
+#endif
};
-/* Coefficient buffer control */
+/* Lossy mode: Coefficient buffer control
+ * Lossless mode: Difference buffer control
+ */
struct jpeg_c_coef_controller {
void (*start_pass) (j_compress_ptr cinfo, J_BUF_MODE pass_mode);
boolean (*compress_data) (j_compress_ptr cinfo, JSAMPIMAGE input_buf);
+ boolean (*compress_data_12) (j_compress_ptr cinfo, J12SAMPIMAGE input_buf);
+#ifdef C_LOSSLESS_SUPPORTED
+ boolean (*compress_data_16) (j_compress_ptr cinfo, J16SAMPIMAGE input_buf);
+#endif
};
/* Colorspace conversion */
@@ -111,6 +154,14 @@ struct jpeg_color_converter {
void (*color_convert) (j_compress_ptr cinfo, JSAMPARRAY input_buf,
JSAMPIMAGE output_buf, JDIMENSION output_row,
int num_rows);
+ void (*color_convert_12) (j_compress_ptr cinfo, J12SAMPARRAY input_buf,
+ J12SAMPIMAGE output_buf, JDIMENSION output_row,
+ int num_rows);
+#ifdef C_LOSSLESS_SUPPORTED
+ void (*color_convert_16) (j_compress_ptr cinfo, J16SAMPARRAY input_buf,
+ J16SAMPIMAGE output_buf, JDIMENSION output_row,
+ int num_rows);
+#endif
};
/* Downsampling */
@@ -119,24 +170,47 @@ struct jpeg_downsampler {
void (*downsample) (j_compress_ptr cinfo, JSAMPIMAGE input_buf,
JDIMENSION in_row_index, JSAMPIMAGE output_buf,
JDIMENSION out_row_group_index);
+ void (*downsample_12) (j_compress_ptr cinfo, J12SAMPIMAGE input_buf,
+ JDIMENSION in_row_index, J12SAMPIMAGE output_buf,
+ JDIMENSION out_row_group_index);
+#ifdef C_LOSSLESS_SUPPORTED
+ void (*downsample_16) (j_compress_ptr cinfo, J16SAMPIMAGE input_buf,
+ JDIMENSION in_row_index, J16SAMPIMAGE output_buf,
+ JDIMENSION out_row_group_index);
+#endif
boolean need_context_rows; /* TRUE if need rows above & below */
};
-/* Forward DCT (also controls coefficient quantization) */
+/* Lossy mode: Forward DCT (also controls coefficient quantization)
+ * Lossless mode: Prediction, sample differencing, and point transform
+ */
struct jpeg_forward_dct {
void (*start_pass) (j_compress_ptr cinfo);
+
+ /* Lossy mode */
/* perhaps this should be an array??? */
void (*forward_DCT) (j_compress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
JDIMENSION start_row, JDIMENSION start_col,
JDIMENSION num_blocks);
+ void (*forward_DCT_12) (j_compress_ptr cinfo, jpeg_component_info *compptr,
+ J12SAMPARRAY sample_data, JBLOCKROW coef_blocks,
+ JDIMENSION start_row, JDIMENSION start_col,
+ JDIMENSION num_blocks);
};
/* Entropy encoding */
struct jpeg_entropy_encoder {
void (*start_pass) (j_compress_ptr cinfo, boolean gather_statistics);
+
+ /* Lossy mode */
boolean (*encode_mcu) (j_compress_ptr cinfo, JBLOCKROW *MCU_data);
+ /* Lossless mode */
+ JDIMENSION (*encode_mcus) (j_compress_ptr cinfo, JDIFFIMAGE diff_buf,
+ JDIMENSION MCU_row_num, JDIMENSION MCU_col_num,
+ JDIMENSION nMCU);
+
void (*finish_pass) (j_compress_ptr cinfo);
};
@@ -164,6 +238,7 @@ struct jpeg_decomp_master {
/* State variables made visible to other modules */
boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */
+ boolean lossless; /* True if decompressing a lossless image */
/* Partial decompression variables */
JDIMENSION first_iMCU_col;
@@ -193,14 +268,36 @@ struct jpeg_d_main_controller {
void (*start_pass) (j_decompress_ptr cinfo, J_BUF_MODE pass_mode);
void (*process_data) (j_decompress_ptr cinfo, JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail);
+ void (*process_data_12) (j_decompress_ptr cinfo, J12SAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail);
+#ifdef D_LOSSLESS_SUPPORTED
+ void (*process_data_16) (j_decompress_ptr cinfo, J16SAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail);
+#endif
};
-/* Coefficient buffer control */
+/* Lossy mode: Coefficient buffer control
+ * Lossless mode: Difference buffer control
+ */
struct jpeg_d_coef_controller {
void (*start_input_pass) (j_decompress_ptr cinfo);
int (*consume_data) (j_decompress_ptr cinfo);
void (*start_output_pass) (j_decompress_ptr cinfo);
int (*decompress_data) (j_decompress_ptr cinfo, JSAMPIMAGE output_buf);
+ int (*decompress_data_12) (j_decompress_ptr cinfo, J12SAMPIMAGE output_buf);
+#ifdef D_LOSSLESS_SUPPORTED
+ int (*decompress_data_16) (j_decompress_ptr cinfo, J16SAMPIMAGE output_buf);
+#endif
+
+ /* These variables keep track of the current location of the input side. */
+ /* cinfo->input_iMCU_row is also used for this. */
+ JDIMENSION MCU_ctr; /* counts MCUs processed in current row */
+ int MCU_vert_offset; /* counts MCU rows within iMCU row */
+ int MCU_rows_per_iMCU_row; /* number of such rows needed */
+
+ /* The output side's location is represented by cinfo->output_iMCU_row. */
+
+ /* Lossy mode */
/* Pointer to array of coefficient virtual arrays, or NULL if none */
jvirt_barray_ptr *coef_arrays;
};
@@ -213,6 +310,20 @@ struct jpeg_d_post_controller {
JDIMENSION in_row_groups_avail,
JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
JDIMENSION out_rows_avail);
+ void (*post_process_data_12) (j_decompress_ptr cinfo, J12SAMPIMAGE input_buf,
+ JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ J12SAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail);
+#ifdef D_LOSSLESS_SUPPORTED
+ void (*post_process_data_16) (j_decompress_ptr cinfo, J16SAMPIMAGE input_buf,
+ JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ J16SAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail);
+#endif
};
/* Marker reading & parsing */
@@ -238,24 +349,42 @@ struct jpeg_marker_reader {
/* Entropy decoding */
struct jpeg_entropy_decoder {
void (*start_pass) (j_decompress_ptr cinfo);
+
+ /* Lossy mode */
boolean (*decode_mcu) (j_decompress_ptr cinfo, JBLOCKROW *MCU_data);
+ /* Lossless mode */
+ JDIMENSION (*decode_mcus) (j_decompress_ptr cinfo, JDIFFIMAGE diff_buf,
+ JDIMENSION MCU_row_num, JDIMENSION MCU_col_num,
+ JDIMENSION nMCU);
+ boolean (*process_restart) (j_decompress_ptr cinfo);
/* This is here to share code between baseline and progressive decoders; */
/* other modules probably should not use it */
boolean insufficient_data; /* set TRUE after emitting warning */
};
-/* Inverse DCT (also performs dequantization) */
+/* Lossy mode: Inverse DCT (also performs dequantization)
+ * Lossless mode: Prediction, sample undifferencing, point transform, and
+ * sample size scaling
+ */
typedef void (*inverse_DCT_method_ptr) (j_decompress_ptr cinfo,
jpeg_component_info *compptr,
JCOEFPTR coef_block,
JSAMPARRAY output_buf,
JDIMENSION output_col);
+typedef void (*inverse_DCT_12_method_ptr) (j_decompress_ptr cinfo,
+ jpeg_component_info *compptr,
+ JCOEFPTR coef_block,
+ J12SAMPARRAY output_buf,
+ JDIMENSION output_col);
struct jpeg_inverse_dct {
void (*start_pass) (j_decompress_ptr cinfo);
+
+ /* Lossy mode */
/* It is useful to allow each component to have a separate IDCT method. */
inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS];
+ inverse_DCT_12_method_ptr inverse_DCT_12[MAX_COMPONENTS];
};
/* Upsampling (note that upsampler must also call color converter) */
@@ -265,6 +394,16 @@ struct jpeg_upsampler {
JDIMENSION *in_row_group_ctr,
JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf,
JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail);
+ void (*upsample_12) (j_decompress_ptr cinfo, J12SAMPIMAGE input_buf,
+ JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail, J12SAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail);
+#ifdef D_LOSSLESS_SUPPORTED
+ void (*upsample_16) (j_decompress_ptr cinfo, J16SAMPIMAGE input_buf,
+ JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail, J16SAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail);
+#endif
boolean need_context_rows; /* TRUE if need rows above & below */
};
@@ -275,6 +414,14 @@ struct jpeg_color_deconverter {
void (*color_convert) (j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
JDIMENSION input_row, JSAMPARRAY output_buf,
int num_rows);
+ void (*color_convert_12) (j_decompress_ptr cinfo, J12SAMPIMAGE input_buf,
+ JDIMENSION input_row, J12SAMPARRAY output_buf,
+ int num_rows);
+#ifdef D_LOSSLESS_SUPPORTED
+ void (*color_convert_16) (j_decompress_ptr cinfo, J16SAMPIMAGE input_buf,
+ JDIMENSION input_row, J16SAMPARRAY output_buf,
+ int num_rows);
+#endif
};
/* Color quantization or color precision reduction */
@@ -282,6 +429,8 @@ struct jpeg_color_quantizer {
void (*start_pass) (j_decompress_ptr cinfo, boolean is_pre_scan);
void (*color_quantize) (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
JSAMPARRAY output_buf, int num_rows);
+ void (*color_quantize_12) (j_decompress_ptr cinfo, J12SAMPARRAY input_buf,
+ J12SAMPARRAY output_buf, int num_rows);
void (*finish_pass) (j_decompress_ptr cinfo);
void (*new_color_map) (j_decompress_ptr cinfo);
};
@@ -323,36 +472,95 @@ EXTERN(void) jinit_c_master_control(j_compress_ptr cinfo,
boolean transcode_only);
EXTERN(void) jinit_c_main_controller(j_compress_ptr cinfo,
boolean need_full_buffer);
+EXTERN(void) j12init_c_main_controller(j_compress_ptr cinfo,
+ boolean need_full_buffer);
EXTERN(void) jinit_c_prep_controller(j_compress_ptr cinfo,
boolean need_full_buffer);
+EXTERN(void) j12init_c_prep_controller(j_compress_ptr cinfo,
+ boolean need_full_buffer);
EXTERN(void) jinit_c_coef_controller(j_compress_ptr cinfo,
boolean need_full_buffer);
+EXTERN(void) j12init_c_coef_controller(j_compress_ptr cinfo,
+ boolean need_full_buffer);
EXTERN(void) jinit_color_converter(j_compress_ptr cinfo);
+EXTERN(void) j12init_color_converter(j_compress_ptr cinfo);
EXTERN(void) jinit_downsampler(j_compress_ptr cinfo);
+EXTERN(void) j12init_downsampler(j_compress_ptr cinfo);
EXTERN(void) jinit_forward_dct(j_compress_ptr cinfo);
+EXTERN(void) j12init_forward_dct(j_compress_ptr cinfo);
EXTERN(void) jinit_huff_encoder(j_compress_ptr cinfo);
EXTERN(void) jinit_phuff_encoder(j_compress_ptr cinfo);
EXTERN(void) jinit_arith_encoder(j_compress_ptr cinfo);
EXTERN(void) jinit_marker_writer(j_compress_ptr cinfo);
+#ifdef C_LOSSLESS_SUPPORTED
+EXTERN(void) j16init_c_main_controller(j_compress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j16init_c_prep_controller(j_compress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j16init_color_converter(j_compress_ptr cinfo);
+EXTERN(void) j16init_downsampler(j_compress_ptr cinfo);
+EXTERN(void) jinit_c_diff_controller(j_compress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j12init_c_diff_controller(j_compress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j16init_c_diff_controller(j_compress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) jinit_lhuff_encoder(j_compress_ptr cinfo);
+EXTERN(void) jinit_lossless_compressor(j_compress_ptr cinfo);
+EXTERN(void) j12init_lossless_compressor(j_compress_ptr cinfo);
+EXTERN(void) j16init_lossless_compressor(j_compress_ptr cinfo);
+#endif
+
/* Decompression module initialization routines */
EXTERN(void) jinit_master_decompress(j_decompress_ptr cinfo);
EXTERN(void) jinit_d_main_controller(j_decompress_ptr cinfo,
boolean need_full_buffer);
+EXTERN(void) j12init_d_main_controller(j_decompress_ptr cinfo,
+ boolean need_full_buffer);
EXTERN(void) jinit_d_coef_controller(j_decompress_ptr cinfo,
boolean need_full_buffer);
+EXTERN(void) j12init_d_coef_controller(j_decompress_ptr cinfo,
+ boolean need_full_buffer);
EXTERN(void) jinit_d_post_controller(j_decompress_ptr cinfo,
boolean need_full_buffer);
+EXTERN(void) j12init_d_post_controller(j_decompress_ptr cinfo,
+ boolean need_full_buffer);
EXTERN(void) jinit_input_controller(j_decompress_ptr cinfo);
EXTERN(void) jinit_marker_reader(j_decompress_ptr cinfo);
EXTERN(void) jinit_huff_decoder(j_decompress_ptr cinfo);
EXTERN(void) jinit_phuff_decoder(j_decompress_ptr cinfo);
EXTERN(void) jinit_arith_decoder(j_decompress_ptr cinfo);
EXTERN(void) jinit_inverse_dct(j_decompress_ptr cinfo);
+EXTERN(void) j12init_inverse_dct(j_decompress_ptr cinfo);
EXTERN(void) jinit_upsampler(j_decompress_ptr cinfo);
+EXTERN(void) j12init_upsampler(j_decompress_ptr cinfo);
EXTERN(void) jinit_color_deconverter(j_decompress_ptr cinfo);
+EXTERN(void) j12init_color_deconverter(j_decompress_ptr cinfo);
EXTERN(void) jinit_1pass_quantizer(j_decompress_ptr cinfo);
+EXTERN(void) j12init_1pass_quantizer(j_decompress_ptr cinfo);
EXTERN(void) jinit_2pass_quantizer(j_decompress_ptr cinfo);
+EXTERN(void) j12init_2pass_quantizer(j_decompress_ptr cinfo);
EXTERN(void) jinit_merged_upsampler(j_decompress_ptr cinfo);
+EXTERN(void) j12init_merged_upsampler(j_decompress_ptr cinfo);
+#ifdef D_LOSSLESS_SUPPORTED
+EXTERN(void) j16init_d_main_controller(j_decompress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j16init_d_post_controller(j_decompress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j16init_upsampler(j_decompress_ptr cinfo);
+EXTERN(void) j16init_color_deconverter(j_decompress_ptr cinfo);
+EXTERN(void) jinit_d_diff_controller(j_decompress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j12init_d_diff_controller(j_decompress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) j16init_d_diff_controller(j_decompress_ptr cinfo,
+ boolean need_full_buffer);
+EXTERN(void) jinit_lhuff_decoder(j_decompress_ptr cinfo);
+EXTERN(void) jinit_lossless_decompressor(j_decompress_ptr cinfo);
+EXTERN(void) j12init_lossless_decompressor(j_decompress_ptr cinfo);
+EXTERN(void) j16init_lossless_decompressor(j_decompress_ptr cinfo);
+#endif
+
/* Memory manager initialization */
EXTERN(void) jinit_memory_mgr(j_common_ptr cinfo);
@@ -362,6 +570,14 @@ EXTERN(long) jround_up(long a, long b);
EXTERN(void) jcopy_sample_rows(JSAMPARRAY input_array, int source_row,
JSAMPARRAY output_array, int dest_row,
int num_rows, JDIMENSION num_cols);
+EXTERN(void) j12copy_sample_rows(J12SAMPARRAY input_array, int source_row,
+ J12SAMPARRAY output_array, int dest_row,
+ int num_rows, JDIMENSION num_cols);
+#if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED)
+EXTERN(void) j16copy_sample_rows(J16SAMPARRAY input_array, int source_row,
+ J16SAMPARRAY output_array, int dest_row,
+ int num_rows, JDIMENSION num_cols);
+#endif
EXTERN(void) jcopy_block_row(JBLOCKROW input_row, JBLOCKROW output_row,
JDIMENSION num_blocks);
EXTERN(void) jzero_far(void *target, size_t bytestozero);
diff --git a/src/3rdparty/libjpeg/src/jpeglib.h b/src/3rdparty/libjpeg/src/jpeglib.h
index d7664f0630..a59e98c25e 100644
--- a/src/3rdparty/libjpeg/src/jpeglib.h
+++ b/src/3rdparty/libjpeg/src/jpeglib.h
@@ -4,8 +4,11 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1998, Thomas G. Lane.
* Modified 2002-2009 by Guido Vollbeding.
+ * Lossless JPEG Modifications:
+ * Copyright (C) 1999, Ken Murchison.
* libjpeg-turbo Modifications:
- * Copyright (C) 2009-2011, 2013-2014, 2016-2017, 2020, D. R. Commander.
+ * Copyright (C) 2009-2011, 2013-2014, 2016-2017, 2020, 2022-2023,
+ D. R. Commander.
* Copyright (C) 2015, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
@@ -43,6 +46,13 @@ extern "C" {
* if you want to be compatible.
*/
+/* NOTE: In lossless mode, an MCU contains one or more samples rather than one
+ * or more 8x8 DCT blocks, so the term "data unit" is used to generically
+ * describe a sample in lossless mode or an 8x8 DCT block in lossy mode. To
+ * preserve backward API/ABI compatibility, the field and macro names retain
+ * the "block" terminology.
+ */
+
#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */
#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */
#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */
@@ -57,9 +67,9 @@ extern "C" {
* we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe
* sometimes emits noncompliant files doesn't mean you should too.
*/
-#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */
+#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on data units/MCU */
#ifndef D_MAX_BLOCKS_IN_MCU
-#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */
+#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on data units/MCU */
#endif
@@ -70,6 +80,20 @@ typedef JSAMPLE *JSAMPROW; /* ptr to one image row of pixel samples. */
typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */
typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */
+typedef J12SAMPLE *J12SAMPROW; /* ptr to one image row of 12-bit pixel
+ samples. */
+typedef J12SAMPROW *J12SAMPARRAY; /* ptr to some 12-bit sample rows (a 2-D
+ 12-bit sample array) */
+typedef J12SAMPARRAY *J12SAMPIMAGE; /* a 3-D 12-bit sample array: top index is
+ color */
+
+typedef J16SAMPLE *J16SAMPROW; /* ptr to one image row of 16-bit pixel
+ samples. */
+typedef J16SAMPROW *J16SAMPARRAY; /* ptr to some 16-bit sample rows (a 2-D
+ 16-bit sample array) */
+typedef J16SAMPARRAY *J16SAMPIMAGE; /* a 3-D 16-bit sample array: top index is
+ color */
+
typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */
typedef JBLOCK *JBLOCKROW; /* pointer to one row of coefficient blocks */
typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */
@@ -135,17 +159,20 @@ typedef struct {
/* Remaining fields should be treated as private by applications. */
/* These values are computed during compression or decompression startup: */
- /* Component's size in DCT blocks.
- * Any dummy blocks added to complete an MCU are not counted; therefore
- * these values do not depend on whether a scan is interleaved or not.
+ /* Component's size in data units.
+ * In lossy mode, any dummy blocks added to complete an MCU are not counted;
+ * therefore these values do not depend on whether a scan is interleaved or
+ * not. In lossless mode, these are always equal to the image width and
+ * height.
*/
JDIMENSION width_in_blocks;
JDIMENSION height_in_blocks;
- /* Size of a DCT block in samples. Always DCTSIZE for compression.
- * For decompression this is the size of the output from one DCT block,
+ /* Size of a data unit in samples. Always DCTSIZE for lossy compression.
+ * For lossy decompression this is the size of the output from one DCT block,
* reflecting any scaling we choose to apply during the IDCT step.
- * Values from 1 to 16 are supported.
- * Note that different components may receive different IDCT scalings.
+ * Values from 1 to 16 are supported. Note that different components may
+ * receive different IDCT scalings. In lossless mode, this is always equal
+ * to 1.
*/
#if JPEG_LIB_VERSION >= 70
int DCT_h_scaled_size;
@@ -156,8 +183,10 @@ typedef struct {
/* The downsampled dimensions are the component's actual, unpadded number
* of samples at the main buffer (preprocessing/compression interface), thus
* downsampled_width = ceil(image_width * Hi/Hmax)
- * and similarly for height. For decompression, IDCT scaling is included, so
+ * and similarly for height. For lossy decompression, IDCT scaling is
+ * included, so
* downsampled_width = ceil(image_width * Hi/Hmax * DCT_[h_]scaled_size/DCTSIZE)
+ * In lossless mode, these are always equal to the image width and height.
*/
JDIMENSION downsampled_width; /* actual width in samples */
JDIMENSION downsampled_height; /* actual height in samples */
@@ -169,12 +198,12 @@ typedef struct {
/* These values are computed before starting a scan of the component. */
/* The decompressor output side may not use these variables. */
- int MCU_width; /* number of blocks per MCU, horizontally */
- int MCU_height; /* number of blocks per MCU, vertically */
+ int MCU_width; /* number of data units per MCU, horizontally */
+ int MCU_height; /* number of data units per MCU, vertically */
int MCU_blocks; /* MCU_width * MCU_height */
int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_[h_]scaled_size */
- int last_col_width; /* # of non-dummy blocks across in last MCU */
- int last_row_height; /* # of non-dummy blocks down in last MCU */
+ int last_col_width; /* # of non-dummy data units across in last MCU */
+ int last_row_height; /* # of non-dummy data units down in last MCU */
/* Saved quantization table for component; NULL if none yet saved.
* See jdinput.c comments about the need for this information.
@@ -192,8 +221,12 @@ typedef struct {
typedef struct {
int comps_in_scan; /* number of components encoded in this scan */
int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */
- int Ss, Se; /* progressive JPEG spectral selection parms */
- int Ah, Al; /* progressive JPEG successive approx. parms */
+ int Ss, Se; /* progressive JPEG spectral selection parms
+ (Ss is the predictor selection value in
+ lossless mode) */
+ int Ah, Al; /* progressive JPEG successive approx. parms
+ (Al is the point transform value in lossless
+ mode) */
} jpeg_scan_info;
/* The decompressor can save APPn and COM markers in a list of these: */
@@ -238,7 +271,8 @@ typedef enum {
JCS_EXT_BGRA, /* blue/green/red/alpha */
JCS_EXT_ABGR, /* alpha/blue/green/red */
JCS_EXT_ARGB, /* alpha/red/green/blue */
- JCS_RGB565 /* 5-bit red/6-bit green/5-bit blue */
+ JCS_RGB565 /* 5-bit red/6-bit green/5-bit blue
+ [decompression only] */
} J_COLOR_SPACE;
/* DCT/IDCT algorithm options. */
@@ -419,11 +453,13 @@ struct jpeg_compress_struct {
int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */
#endif
- JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */
- /* The coefficient controller receives data in units of MCU rows as defined
- * for fully interleaved scans (whether the JPEG file is interleaved or not).
- * There are v_samp_factor * DCTSIZE sample rows of each component in an
- * "iMCU" (interleaved MCU) row.
+ JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coefficient or
+ difference controller */
+ /* The coefficient or difference controller receives data in units of MCU
+ * rows as defined for fully interleaved scans (whether the JPEG file is
+ * interleaved or not). In lossy mode, there are v_samp_factor * DCTSIZE
+ * sample rows of each component in an "iMCU" (interleaved MCU) row. In
+ * lossless mode, total_iMCU_rows is always equal to the image height.
*/
/*
@@ -437,12 +473,13 @@ struct jpeg_compress_struct {
JDIMENSION MCUs_per_row; /* # of MCUs across the image */
JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */
- int blocks_in_MCU; /* # of DCT blocks per MCU */
+ int blocks_in_MCU; /* # of data units per MCU */
int MCU_membership[C_MAX_BLOCKS_IN_MCU];
/* MCU_membership[i] is index in cur_comp_info of component owning */
- /* i'th block in an MCU */
+ /* i'th data unit in an MCU */
- int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */
+ int Ss, Se, Ah, Al; /* progressive/lossless JPEG parameters for
+ scan */
#if JPEG_LIB_VERSION >= 80
int block_size; /* the basic DCT block size: 1..16 */
@@ -537,7 +574,12 @@ struct jpeg_decompress_struct {
* The map has out_color_components rows and actual_number_of_colors columns.
*/
int actual_number_of_colors; /* number of entries in use */
- JSAMPARRAY colormap; /* The color map as a 2-D pixel array */
+ JSAMPARRAY colormap; /* The color map as a 2-D pixel array
+ If data_precision is 12 or 16, then this is
+ actually a J12SAMPARRAY or a J16SAMPARRAY,
+ so callers must type-cast it in order to
+ read/write 12-bit or 16-bit samples from/to
+ the array. */
/* State variables: these variables indicate the progress of decompression.
* The application may examine these but must not modify them.
@@ -647,15 +689,21 @@ struct jpeg_decompress_struct {
#endif
JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */
- /* The coefficient controller's input and output progress is measured in
- * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows
- * in fully interleaved JPEG scans, but are used whether the scan is
- * interleaved or not. We define an iMCU row as v_samp_factor DCT block
- * rows of each component. Therefore, the IDCT output contains
+ /* The coefficient or difference controller's input and output progress is
+ * measured in units of "iMCU" (interleaved MCU) rows. These are the same as
+ * MCU rows in fully interleaved JPEG scans, but are used whether the scan is
+ * interleaved or not. In lossy mode, we define an iMCU row as v_samp_factor
+ * DCT block rows of each component. Therefore, the IDCT output contains
* v_samp_factor*DCT_[v_]scaled_size sample rows of a component per iMCU row.
+ * In lossless mode, total_iMCU_rows is always equal to the image height.
*/
- JSAMPLE *sample_range_limit; /* table for fast range-limiting */
+ JSAMPLE *sample_range_limit; /* table for fast range-limiting
+ If data_precision is 12 or 16, then this is
+ actually a J12SAMPLE pointer or a J16SAMPLE
+ pointer, so callers must type-cast it in
+ order to read 12-bit or 16-bit samples from
+ the array. */
/*
* These fields are valid during any one scan.
@@ -669,12 +717,13 @@ struct jpeg_decompress_struct {
JDIMENSION MCUs_per_row; /* # of MCUs across the image */
JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */
- int blocks_in_MCU; /* # of DCT blocks per MCU */
+ int blocks_in_MCU; /* # of data units per MCU */
int MCU_membership[D_MAX_BLOCKS_IN_MCU];
/* MCU_membership[i] is index in cur_comp_info of component owning */
- /* i'th block in an MCU */
+ /* i'th data unit in an MCU */
- int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */
+ int Ss, Se, Ah, Al; /* progressive/lossless JPEG parameters for
+ scan */
#if JPEG_LIB_VERSION >= 80
/* These fields are derived from Se of first SOS marker.
@@ -835,6 +884,11 @@ struct jpeg_memory_mgr {
void *(*alloc_small) (j_common_ptr cinfo, int pool_id, size_t sizeofobject);
void *(*alloc_large) (j_common_ptr cinfo, int pool_id,
size_t sizeofobject);
+ /* If cinfo->data_precision is 12 or 16, then this method and the
+ * access_virt_sarray method actually return a J12SAMPARRAY or a
+ * J16SAMPARRAY, so callers must type-cast the return value in order to
+ * read/write 12-bit or 16-bit samples from/to the array.
+ */
JSAMPARRAY (*alloc_sarray) (j_common_ptr cinfo, int pool_id,
JDIMENSION samplesperrow, JDIMENSION numrows);
JBLOCKARRAY (*alloc_barray) (j_common_ptr cinfo, int pool_id,
@@ -916,13 +970,11 @@ EXTERN(void) jpeg_destroy_decompress(j_decompress_ptr cinfo);
EXTERN(void) jpeg_stdio_dest(j_compress_ptr cinfo, FILE *outfile);
EXTERN(void) jpeg_stdio_src(j_decompress_ptr cinfo, FILE *infile);
-#if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED)
/* Data source and destination managers: memory buffers. */
EXTERN(void) jpeg_mem_dest(j_compress_ptr cinfo, unsigned char **outbuffer,
unsigned long *outsize);
EXTERN(void) jpeg_mem_src(j_decompress_ptr cinfo,
const unsigned char *inbuffer, unsigned long insize);
-#endif
/* Default parameter setup for compression */
EXTERN(void) jpeg_set_defaults(j_compress_ptr cinfo);
@@ -942,6 +994,9 @@ EXTERN(void) jpeg_add_quant_table(j_compress_ptr cinfo, int which_tbl,
const unsigned int *basic_table,
int scale_factor, boolean force_baseline);
EXTERN(int) jpeg_quality_scaling(int quality);
+EXTERN(void) jpeg_enable_lossless(j_compress_ptr cinfo,
+ int predictor_selection_value,
+ int point_transform);
EXTERN(void) jpeg_simple_progression(j_compress_ptr cinfo);
EXTERN(void) jpeg_suppress_tables(j_compress_ptr cinfo, boolean suppress);
EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table(j_common_ptr cinfo);
@@ -953,6 +1008,12 @@ EXTERN(void) jpeg_start_compress(j_compress_ptr cinfo,
EXTERN(JDIMENSION) jpeg_write_scanlines(j_compress_ptr cinfo,
JSAMPARRAY scanlines,
JDIMENSION num_lines);
+EXTERN(JDIMENSION) jpeg12_write_scanlines(j_compress_ptr cinfo,
+ J12SAMPARRAY scanlines,
+ JDIMENSION num_lines);
+EXTERN(JDIMENSION) jpeg16_write_scanlines(j_compress_ptr cinfo,
+ J16SAMPARRAY scanlines,
+ JDIMENSION num_lines);
EXTERN(void) jpeg_finish_compress(j_compress_ptr cinfo);
#if JPEG_LIB_VERSION >= 70
@@ -963,6 +1024,9 @@ EXTERN(void) jpeg_calc_jpeg_dimensions(j_compress_ptr cinfo);
/* Replaces jpeg_write_scanlines when writing raw downsampled data. */
EXTERN(JDIMENSION) jpeg_write_raw_data(j_compress_ptr cinfo, JSAMPIMAGE data,
JDIMENSION num_lines);
+EXTERN(JDIMENSION) jpeg12_write_raw_data(j_compress_ptr cinfo,
+ J12SAMPIMAGE data,
+ JDIMENSION num_lines);
/* Write a special marker. See libjpeg.txt concerning safe usage. */
EXTERN(void) jpeg_write_marker(j_compress_ptr cinfo, int marker,
@@ -998,15 +1062,28 @@ EXTERN(boolean) jpeg_start_decompress(j_decompress_ptr cinfo);
EXTERN(JDIMENSION) jpeg_read_scanlines(j_decompress_ptr cinfo,
JSAMPARRAY scanlines,
JDIMENSION max_lines);
+EXTERN(JDIMENSION) jpeg12_read_scanlines(j_decompress_ptr cinfo,
+ J12SAMPARRAY scanlines,
+ JDIMENSION max_lines);
+EXTERN(JDIMENSION) jpeg16_read_scanlines(j_decompress_ptr cinfo,
+ J16SAMPARRAY scanlines,
+ JDIMENSION max_lines);
EXTERN(JDIMENSION) jpeg_skip_scanlines(j_decompress_ptr cinfo,
JDIMENSION num_lines);
+EXTERN(JDIMENSION) jpeg12_skip_scanlines(j_decompress_ptr cinfo,
+ JDIMENSION num_lines);
EXTERN(void) jpeg_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset,
JDIMENSION *width);
+EXTERN(void) jpeg12_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset,
+ JDIMENSION *width);
EXTERN(boolean) jpeg_finish_decompress(j_decompress_ptr cinfo);
/* Replaces jpeg_read_scanlines when reading raw downsampled data. */
EXTERN(JDIMENSION) jpeg_read_raw_data(j_decompress_ptr cinfo, JSAMPIMAGE data,
JDIMENSION max_lines);
+EXTERN(JDIMENSION) jpeg12_read_raw_data(j_decompress_ptr cinfo,
+ J12SAMPIMAGE data,
+ JDIMENSION max_lines);
/* Additional entry points for buffered-image mode. */
EXTERN(boolean) jpeg_has_multiple_scans(j_decompress_ptr cinfo);
diff --git a/src/3rdparty/libjpeg/src/jquant1.c b/src/3rdparty/libjpeg/src/jquant1.c
index 73b83e16e5..2e914b919c 100644
--- a/src/3rdparty/libjpeg/src/jquant1.c
+++ b/src/3rdparty/libjpeg/src/jquant1.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2009, 2015, D. R. Commander.
+ * Copyright (C) 2009, 2015, 2022-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -16,8 +16,9 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#include "jsamplecomp.h"
-#ifdef QUANT_1PASS_SUPPORTED
+#if defined(QUANT_1PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16
/*
@@ -66,7 +67,7 @@
* worse, since the dither may be too much or too little at a given point.
*
* The normal calculation would be to form pixel value + dither, range-limit
- * this to 0..MAXJSAMPLE, and then index into the colorindex table as usual.
+ * this to 0.._MAXJSAMPLE, and then index into the colorindex table as usual.
* We can skip the separate range-limiting step by extending the colorindex
* table in both directions.
*/
@@ -144,13 +145,13 @@ typedef struct {
struct jpeg_color_quantizer pub; /* public fields */
/* Initially allocated colormap is saved here */
- JSAMPARRAY sv_colormap; /* The color map as a 2-D pixel array */
+ _JSAMPARRAY sv_colormap; /* The color map as a 2-D pixel array */
int sv_actual; /* number of entries in use */
- JSAMPARRAY colorindex; /* Precomputed mapping for speed */
+ _JSAMPARRAY colorindex; /* Precomputed mapping for speed */
/* colorindex[i][j] = index of color closest to pixel value j in component i,
* premultiplied as described above. Since colormap indexes must fit into
- * JSAMPLEs, the entries of this array will too.
+ * _JSAMPLEs, the entries of this array will too.
*/
boolean is_padded; /* is the colorindex padded for odither? */
@@ -248,24 +249,24 @@ select_ncolors(j_decompress_ptr cinfo, int Ncolors[])
LOCAL(int)
output_value(j_decompress_ptr cinfo, int ci, int j, int maxj)
/* Return j'th output value, where j will range from 0 to maxj */
-/* The output values must fall in 0..MAXJSAMPLE in increasing order */
+/* The output values must fall in 0.._MAXJSAMPLE in increasing order */
{
- /* We always provide values 0 and MAXJSAMPLE for each component;
+ /* We always provide values 0 and _MAXJSAMPLE for each component;
* any additional values are equally spaced between these limits.
* (Forcing the upper and lower values to the limits ensures that
* dithering can't produce a color outside the selected gamut.)
*/
- return (int)(((JLONG)j * MAXJSAMPLE + maxj / 2) / maxj);
+ return (int)(((JLONG)j * _MAXJSAMPLE + maxj / 2) / maxj);
}
LOCAL(int)
largest_input_value(j_decompress_ptr cinfo, int ci, int j, int maxj)
/* Return largest input value that should map to j'th output value */
-/* Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE */
+/* Must have largest(j=0) >= 0, and largest(j=maxj) >= _MAXJSAMPLE */
{
/* Breakpoints are halfway between values returned by output_value */
- return (int)(((JLONG)(2 * j + 1) * MAXJSAMPLE + maxj) / (2 * maxj));
+ return (int)(((JLONG)(2 * j + 1) * _MAXJSAMPLE + maxj) / (2 * maxj));
}
@@ -277,7 +278,7 @@ LOCAL(void)
create_colormap(j_decompress_ptr cinfo)
{
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
- JSAMPARRAY colormap; /* Created colormap */
+ _JSAMPARRAY colormap; /* Created colormap */
int total_colors; /* Number of distinct output colors */
int i, j, k, nci, blksize, blkdist, ptr, val;
@@ -296,7 +297,7 @@ create_colormap(j_decompress_ptr cinfo)
/* The colors are ordered in the map in standard row-major order, */
/* i.e. rightmost (highest-indexed) color changes most rapidly. */
- colormap = (*cinfo->mem->alloc_sarray)
+ colormap = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE,
(JDIMENSION)total_colors, (JDIMENSION)cinfo->out_color_components);
@@ -315,7 +316,7 @@ create_colormap(j_decompress_ptr cinfo)
for (ptr = j * blksize; ptr < total_colors; ptr += blkdist) {
/* fill in blksize entries beginning at ptr */
for (k = 0; k < blksize; k++)
- colormap[i][ptr + k] = (JSAMPLE)val;
+ colormap[i][ptr + k] = (_JSAMPLE)val;
}
}
blkdist = blksize; /* blksize of this color is blkdist of next */
@@ -337,25 +338,25 @@ LOCAL(void)
create_colorindex(j_decompress_ptr cinfo)
{
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
- JSAMPROW indexptr;
+ _JSAMPROW indexptr;
int i, j, k, nci, blksize, val, pad;
- /* For ordered dither, we pad the color index tables by MAXJSAMPLE in
- * each direction (input index values can be -MAXJSAMPLE .. 2*MAXJSAMPLE).
+ /* For ordered dither, we pad the color index tables by _MAXJSAMPLE in
+ * each direction (input index values can be -_MAXJSAMPLE .. 2*_MAXJSAMPLE).
* This is not necessary in the other dithering modes. However, we
* flag whether it was done in case user changes dithering mode.
*/
if (cinfo->dither_mode == JDITHER_ORDERED) {
- pad = MAXJSAMPLE * 2;
+ pad = _MAXJSAMPLE * 2;
cquantize->is_padded = TRUE;
} else {
pad = 0;
cquantize->is_padded = FALSE;
}
- cquantize->colorindex = (*cinfo->mem->alloc_sarray)
+ cquantize->colorindex = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE,
- (JDIMENSION)(MAXJSAMPLE + 1 + pad),
+ (JDIMENSION)(_MAXJSAMPLE + 1 + pad),
(JDIMENSION)cinfo->out_color_components);
/* blksize is number of adjacent repeated entries for a component */
@@ -368,24 +369,24 @@ create_colorindex(j_decompress_ptr cinfo)
/* adjust colorindex pointers to provide padding at negative indexes. */
if (pad)
- cquantize->colorindex[i] += MAXJSAMPLE;
+ cquantize->colorindex[i] += _MAXJSAMPLE;
/* in loop, val = index of current output value, */
/* and k = largest j that maps to current val */
indexptr = cquantize->colorindex[i];
val = 0;
k = largest_input_value(cinfo, i, 0, nci - 1);
- for (j = 0; j <= MAXJSAMPLE; j++) {
+ for (j = 0; j <= _MAXJSAMPLE; j++) {
while (j > k) /* advance val if past boundary */
k = largest_input_value(cinfo, i, ++val, nci - 1);
/* premultiply so that no multiplication needed in main processing */
- indexptr[j] = (JSAMPLE)(val * blksize);
+ indexptr[j] = (_JSAMPLE)(val * blksize);
}
/* Pad at both ends if necessary */
if (pad)
- for (j = 1; j <= MAXJSAMPLE; j++) {
+ for (j = 1; j <= _MAXJSAMPLE; j++) {
indexptr[-j] = indexptr[0];
- indexptr[MAXJSAMPLE + j] = indexptr[MAXJSAMPLE];
+ indexptr[_MAXJSAMPLE + j] = indexptr[_MAXJSAMPLE];
}
}
}
@@ -406,16 +407,16 @@ make_odither_array(j_decompress_ptr cinfo, int ncolors)
odither = (ODITHER_MATRIX_PTR)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(ODITHER_MATRIX));
- /* The inter-value distance for this color is MAXJSAMPLE/(ncolors-1).
+ /* The inter-value distance for this color is _MAXJSAMPLE/(ncolors-1).
* Hence the dither value for the matrix cell with fill order f
- * (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1).
+ * (f=0..N-1) should be (N-1-2*f)/(2*N) * _MAXJSAMPLE/(ncolors-1).
* On 16-bit-int machine, be careful to avoid overflow.
*/
den = 2 * ODITHER_CELLS * ((JLONG)(ncolors - 1));
for (j = 0; j < ODITHER_SIZE; j++) {
for (k = 0; k < ODITHER_SIZE; k++) {
num = ((JLONG)(ODITHER_CELLS - 1 -
- 2 * ((int)base_dither_matrix[j][k]))) * MAXJSAMPLE;
+ 2 * ((int)base_dither_matrix[j][k]))) * _MAXJSAMPLE;
/* Ensure round towards zero despite C's lack of consistency
* about rounding negative values in integer division...
*/
@@ -460,14 +461,14 @@ create_odither_tables(j_decompress_ptr cinfo)
*/
METHODDEF(void)
-color_quantize(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
+color_quantize(j_decompress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPARRAY output_buf, int num_rows)
/* General case, no dithering */
{
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
- JSAMPARRAY colorindex = cquantize->colorindex;
+ _JSAMPARRAY colorindex = cquantize->colorindex;
register int pixcode, ci;
- register JSAMPROW ptrin, ptrout;
+ register _JSAMPROW ptrin, ptrout;
int row;
JDIMENSION col;
JDIMENSION width = cinfo->output_width;
@@ -481,23 +482,23 @@ color_quantize(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
for (ci = 0; ci < nc; ci++) {
pixcode += colorindex[ci][*ptrin++];
}
- *ptrout++ = (JSAMPLE)pixcode;
+ *ptrout++ = (_JSAMPLE)pixcode;
}
}
}
METHODDEF(void)
-color_quantize3(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
+color_quantize3(j_decompress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPARRAY output_buf, int num_rows)
/* Fast path for out_color_components==3, no dithering */
{
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
register int pixcode;
- register JSAMPROW ptrin, ptrout;
- JSAMPROW colorindex0 = cquantize->colorindex[0];
- JSAMPROW colorindex1 = cquantize->colorindex[1];
- JSAMPROW colorindex2 = cquantize->colorindex[2];
+ register _JSAMPROW ptrin, ptrout;
+ _JSAMPROW colorindex0 = cquantize->colorindex[0];
+ _JSAMPROW colorindex1 = cquantize->colorindex[1];
+ _JSAMPROW colorindex2 = cquantize->colorindex[2];
int row;
JDIMENSION col;
JDIMENSION width = cinfo->output_width;
@@ -509,21 +510,21 @@ color_quantize3(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
pixcode = colorindex0[*ptrin++];
pixcode += colorindex1[*ptrin++];
pixcode += colorindex2[*ptrin++];
- *ptrout++ = (JSAMPLE)pixcode;
+ *ptrout++ = (_JSAMPLE)pixcode;
}
}
}
METHODDEF(void)
-quantize_ord_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
+quantize_ord_dither(j_decompress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPARRAY output_buf, int num_rows)
/* General case, with ordered dithering */
{
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
- register JSAMPROW input_ptr;
- register JSAMPROW output_ptr;
- JSAMPROW colorindex_ci;
+ register _JSAMPROW input_ptr;
+ register _JSAMPROW output_ptr;
+ _JSAMPROW colorindex_ci;
int *dither; /* points to active row of dither matrix */
int row_index, col_index; /* current indexes into dither matrix */
int nc = cinfo->out_color_components;
@@ -534,7 +535,7 @@ quantize_ord_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
for (row = 0; row < num_rows; row++) {
/* Initialize output values to 0 so can process components separately */
- jzero_far((void *)output_buf[row], (size_t)(width * sizeof(JSAMPLE)));
+ jzero_far((void *)output_buf[row], (size_t)(width * sizeof(_JSAMPLE)));
row_index = cquantize->row_index;
for (ci = 0; ci < nc; ci++) {
input_ptr = input_buf[row] + ci;
@@ -544,11 +545,11 @@ quantize_ord_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
col_index = 0;
for (col = width; col > 0; col--) {
- /* Form pixel value + dither, range-limit to 0..MAXJSAMPLE,
+ /* Form pixel value + dither, range-limit to 0.._MAXJSAMPLE,
* select output value, accumulate into output code for this pixel.
* Range-limiting need not be done explicitly, as we have extended
* the colorindex table to produce the right answers for out-of-range
- * inputs. The maximum dither is +- MAXJSAMPLE; this sets the
+ * inputs. The maximum dither is +- _MAXJSAMPLE; this sets the
* required amount of padding.
*/
*output_ptr +=
@@ -566,17 +567,17 @@ quantize_ord_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
METHODDEF(void)
-quantize3_ord_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
+quantize3_ord_dither(j_decompress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPARRAY output_buf, int num_rows)
/* Fast path for out_color_components==3, with ordered dithering */
{
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
register int pixcode;
- register JSAMPROW input_ptr;
- register JSAMPROW output_ptr;
- JSAMPROW colorindex0 = cquantize->colorindex[0];
- JSAMPROW colorindex1 = cquantize->colorindex[1];
- JSAMPROW colorindex2 = cquantize->colorindex[2];
+ register _JSAMPROW input_ptr;
+ register _JSAMPROW output_ptr;
+ _JSAMPROW colorindex0 = cquantize->colorindex[0];
+ _JSAMPROW colorindex1 = cquantize->colorindex[1];
+ _JSAMPROW colorindex2 = cquantize->colorindex[2];
int *dither0; /* points to active row of dither matrix */
int *dither1;
int *dither2;
@@ -598,7 +599,7 @@ quantize3_ord_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
pixcode = colorindex0[(*input_ptr++) + dither0[col_index]];
pixcode += colorindex1[(*input_ptr++) + dither1[col_index]];
pixcode += colorindex2[(*input_ptr++) + dither2[col_index]];
- *output_ptr++ = (JSAMPLE)pixcode;
+ *output_ptr++ = (_JSAMPLE)pixcode;
col_index = (col_index + 1) & ODITHER_MASK;
}
row_index = (row_index + 1) & ODITHER_MASK;
@@ -608,8 +609,8 @@ quantize3_ord_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
METHODDEF(void)
-quantize_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
+quantize_fs_dither(j_decompress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPARRAY output_buf, int num_rows)
/* General case, with Floyd-Steinberg dithering */
{
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
@@ -619,10 +620,10 @@ quantize_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
LOCFSERROR bnexterr; /* error for below/next col */
LOCFSERROR delta;
register FSERRPTR errorptr; /* => fserrors[] at column before current */
- register JSAMPROW input_ptr;
- register JSAMPROW output_ptr;
- JSAMPROW colorindex_ci;
- JSAMPROW colormap_ci;
+ register _JSAMPROW input_ptr;
+ register _JSAMPROW output_ptr;
+ _JSAMPROW colorindex_ci;
+ _JSAMPROW colormap_ci;
int pixcode;
int nc = cinfo->out_color_components;
int dir; /* 1 for left-to-right, -1 for right-to-left */
@@ -631,12 +632,12 @@ quantize_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
int row;
JDIMENSION col;
JDIMENSION width = cinfo->output_width;
- JSAMPLE *range_limit = cinfo->sample_range_limit;
+ _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
SHIFT_TEMPS
for (row = 0; row < num_rows; row++) {
/* Initialize output values to 0 so can process components separately */
- jzero_far((void *)output_buf[row], (size_t)(width * sizeof(JSAMPLE)));
+ jzero_far((void *)output_buf[row], (size_t)(width * sizeof(_JSAMPLE)));
for (ci = 0; ci < nc; ci++) {
input_ptr = input_buf[row] + ci;
output_ptr = output_buf[row];
@@ -670,15 +671,15 @@ quantize_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
* Note: errorptr points to *previous* column's array entry.
*/
cur = RIGHT_SHIFT(cur + errorptr[dir] + 8, 4);
- /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
- * The maximum error is +- MAXJSAMPLE; this sets the required size
+ /* Form pixel value + error, and range-limit to 0.._MAXJSAMPLE.
+ * The maximum error is +- _MAXJSAMPLE; this sets the required size
* of the range_limit array.
*/
cur += *input_ptr;
cur = range_limit[cur];
/* Select output value, accumulate into output code for this pixel */
pixcode = colorindex_ci[cur];
- *output_ptr += (JSAMPLE)pixcode;
+ *output_ptr += (_JSAMPLE)pixcode;
/* Compute actual representation error at this pixel */
/* Note: we can do this even though we don't have the final */
/* pixel code, because the colormap is orthogonal. */
@@ -745,22 +746,22 @@ start_pass_1_quant(j_decompress_ptr cinfo, boolean is_pre_scan)
int i;
/* Install my colormap. */
- cinfo->colormap = cquantize->sv_colormap;
+ cinfo->colormap = (JSAMPARRAY)cquantize->sv_colormap;
cinfo->actual_number_of_colors = cquantize->sv_actual;
/* Initialize for desired dithering mode. */
switch (cinfo->dither_mode) {
case JDITHER_NONE:
if (cinfo->out_color_components == 3)
- cquantize->pub.color_quantize = color_quantize3;
+ cquantize->pub._color_quantize = color_quantize3;
else
- cquantize->pub.color_quantize = color_quantize;
+ cquantize->pub._color_quantize = color_quantize;
break;
case JDITHER_ORDERED:
if (cinfo->out_color_components == 3)
- cquantize->pub.color_quantize = quantize3_ord_dither;
+ cquantize->pub._color_quantize = quantize3_ord_dither;
else
- cquantize->pub.color_quantize = quantize_ord_dither;
+ cquantize->pub._color_quantize = quantize_ord_dither;
cquantize->row_index = 0; /* initialize state for ordered dither */
/* If user changed to ordered dither from another mode,
* we must recreate the color index table with padding.
@@ -773,7 +774,7 @@ start_pass_1_quant(j_decompress_ptr cinfo, boolean is_pre_scan)
create_odither_tables(cinfo);
break;
case JDITHER_FS:
- cquantize->pub.color_quantize = quantize_fs_dither;
+ cquantize->pub._color_quantize = quantize_fs_dither;
cquantize->on_odd_row = FALSE; /* initialize state for F-S dither */
/* Allocate Floyd-Steinberg workspace if didn't already. */
if (cquantize->fserrors[0] == NULL)
@@ -818,10 +819,17 @@ new_color_map_1_quant(j_decompress_ptr cinfo)
*/
GLOBAL(void)
-jinit_1pass_quantizer(j_decompress_ptr cinfo)
+_jinit_1pass_quantizer(j_decompress_ptr cinfo)
{
my_cquantize_ptr cquantize;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+ /* Color quantization is not supported with lossless JPEG images */
+ if (cinfo->master->lossless)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+
cquantize = (my_cquantize_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_cquantizer));
@@ -835,9 +843,9 @@ jinit_1pass_quantizer(j_decompress_ptr cinfo)
/* Make sure my internal arrays won't overflow */
if (cinfo->out_color_components > MAX_Q_COMPS)
ERREXIT1(cinfo, JERR_QUANT_COMPONENTS, MAX_Q_COMPS);
- /* Make sure colormap indexes can be represented by JSAMPLEs */
- if (cinfo->desired_number_of_colors > (MAXJSAMPLE + 1))
- ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXJSAMPLE + 1);
+ /* Make sure colormap indexes can be represented by _JSAMPLEs */
+ if (cinfo->desired_number_of_colors > (_MAXJSAMPLE + 1))
+ ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, _MAXJSAMPLE + 1);
/* Create the colormap and color index table. */
create_colormap(cinfo);
@@ -853,4 +861,4 @@ jinit_1pass_quantizer(j_decompress_ptr cinfo)
alloc_fs_workspace(cinfo);
}
-#endif /* QUANT_1PASS_SUPPORTED */
+#endif /* defined(QUANT_1PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16 */
diff --git a/src/3rdparty/libjpeg/src/jquant2.c b/src/3rdparty/libjpeg/src/jquant2.c
index 44efb18cad..9ba51fa887 100644
--- a/src/3rdparty/libjpeg/src/jquant2.c
+++ b/src/3rdparty/libjpeg/src/jquant2.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2009, 2014-2015, 2020, D. R. Commander.
+ * Copyright (C) 2009, 2014-2015, 2020, 2022-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -23,8 +23,9 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#include "jsamplecomp.h"
-#ifdef QUANT_2PASS_SUPPORTED
+#if defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16
/*
@@ -106,7 +107,7 @@ static const int c_scales[3] = { R_SCALE, G_SCALE, B_SCALE };
* each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries.
*/
-#define MAXNUMCOLORS (MAXJSAMPLE + 1) /* maximum size of colormap */
+#define MAXNUMCOLORS (_MAXJSAMPLE + 1) /* maximum size of colormap */
/* These will do the right thing for either R,G,B or B,G,R color order,
* but you may not like the results for other color orders.
@@ -173,7 +174,7 @@ typedef struct {
struct jpeg_color_quantizer pub; /* public fields */
/* Space for the eventually created colormap is stashed here */
- JSAMPARRAY sv_colormap; /* colormap allocated at init time */
+ _JSAMPARRAY sv_colormap; /* colormap allocated at init time */
int desired; /* desired # of colors = size of colormap */
/* Variables for accumulating image statistics */
@@ -200,11 +201,11 @@ typedef my_cquantizer *my_cquantize_ptr;
*/
METHODDEF(void)
-prescan_quantize(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
+prescan_quantize(j_decompress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPARRAY output_buf, int num_rows)
{
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
- register JSAMPROW ptr;
+ register _JSAMPROW ptr;
register histptr histp;
register hist3d histogram = cquantize->histogram;
int row;
@@ -377,7 +378,7 @@ have_c2max:
* against making long narrow boxes, and it has the side benefit that
* a box is splittable iff norm > 0.
* Since the differences are expressed in histogram-cell units,
- * we have to shift back to JSAMPLE units to get consistent distances;
+ * we have to shift back to _JSAMPLE units to get consistent distances;
* after which, we scale according to the selected distance scale factors.
*/
dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE;
@@ -508,9 +509,12 @@ compute_color(j_decompress_ptr cinfo, boxptr boxp, int icolor)
}
}
- cinfo->colormap[0][icolor] = (JSAMPLE)((c0total + (total >> 1)) / total);
- cinfo->colormap[1][icolor] = (JSAMPLE)((c1total + (total >> 1)) / total);
- cinfo->colormap[2][icolor] = (JSAMPLE)((c2total + (total >> 1)) / total);
+ ((_JSAMPARRAY)cinfo->colormap)[0][icolor] =
+ (_JSAMPLE)((c0total + (total >> 1)) / total);
+ ((_JSAMPARRAY)cinfo->colormap)[1][icolor] =
+ (_JSAMPLE)((c1total + (total >> 1)) / total);
+ ((_JSAMPARRAY)cinfo->colormap)[2][icolor] =
+ (_JSAMPLE)((c2total + (total >> 1)) / total);
}
@@ -528,11 +532,11 @@ select_colors(j_decompress_ptr cinfo, int desired_colors)
/* Initialize one box containing whole space */
numboxes = 1;
boxlist[0].c0min = 0;
- boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT;
+ boxlist[0].c0max = _MAXJSAMPLE >> C0_SHIFT;
boxlist[0].c1min = 0;
- boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT;
+ boxlist[0].c1max = _MAXJSAMPLE >> C1_SHIFT;
boxlist[0].c2min = 0;
- boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT;
+ boxlist[0].c2max = _MAXJSAMPLE >> C2_SHIFT;
/* Shrink it to actually-used volume and set its statistics */
update_box(cinfo, &boxlist[0]);
/* Perform median-cut to produce final box list */
@@ -623,7 +627,7 @@ select_colors(j_decompress_ptr cinfo, int desired_colors)
LOCAL(int)
find_nearby_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
- JSAMPLE colorlist[])
+ _JSAMPLE colorlist[])
/* Locate the colormap entries close enough to an update box to be candidates
* for the nearest entry to some cell(s) in the update box. The update box
* is specified by the center coordinates of its first cell. The number of
@@ -665,7 +669,7 @@ find_nearby_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
for (i = 0; i < numcolors; i++) {
/* We compute the squared-c0-distance term, then add in the other two. */
- x = cinfo->colormap[0][i];
+ x = ((_JSAMPARRAY)cinfo->colormap)[0][i];
if (x < minc0) {
tdist = (x - minc0) * C0_SCALE;
min_dist = tdist * tdist;
@@ -688,7 +692,7 @@ find_nearby_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
}
}
- x = cinfo->colormap[1][i];
+ x = ((_JSAMPARRAY)cinfo->colormap)[1][i];
if (x < minc1) {
tdist = (x - minc1) * C1_SCALE;
min_dist += tdist * tdist;
@@ -710,7 +714,7 @@ find_nearby_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
}
}
- x = cinfo->colormap[2][i];
+ x = ((_JSAMPARRAY)cinfo->colormap)[2][i];
if (x < minc2) {
tdist = (x - minc2) * C2_SCALE;
min_dist += tdist * tdist;
@@ -744,7 +748,7 @@ find_nearby_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
ncolors = 0;
for (i = 0; i < numcolors; i++) {
if (mindist[i] <= minmaxdist)
- colorlist[ncolors++] = (JSAMPLE)i;
+ colorlist[ncolors++] = (_JSAMPLE)i;
}
return ncolors;
}
@@ -752,7 +756,7 @@ find_nearby_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
LOCAL(void)
find_best_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
- int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[])
+ int numcolors, _JSAMPLE colorlist[], _JSAMPLE bestcolor[])
/* Find the closest colormap entry for each cell in the update box,
* given the list of candidate colors prepared by find_nearby_colors.
* Return the indexes of the closest entries in the bestcolor[] array.
@@ -763,7 +767,7 @@ find_best_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
int ic0, ic1, ic2;
int i, icolor;
register JLONG *bptr; /* pointer into bestdist[] array */
- JSAMPLE *cptr; /* pointer into bestcolor[] array */
+ _JSAMPLE *cptr; /* pointer into bestcolor[] array */
JLONG dist0, dist1; /* initial distance values */
register JLONG dist2; /* current distance in inner loop */
JLONG xx0, xx1; /* distance increments */
@@ -790,11 +794,11 @@ find_best_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
for (i = 0; i < numcolors; i++) {
icolor = colorlist[i];
/* Compute (square of) distance from minc0/c1/c2 to this color */
- inc0 = (minc0 - cinfo->colormap[0][icolor]) * C0_SCALE;
+ inc0 = (minc0 - ((_JSAMPARRAY)cinfo->colormap)[0][icolor]) * C0_SCALE;
dist0 = inc0 * inc0;
- inc1 = (minc1 - cinfo->colormap[1][icolor]) * C1_SCALE;
+ inc1 = (minc1 - ((_JSAMPARRAY)cinfo->colormap)[1][icolor]) * C1_SCALE;
dist0 += inc1 * inc1;
- inc2 = (minc2 - cinfo->colormap[2][icolor]) * C2_SCALE;
+ inc2 = (minc2 - ((_JSAMPARRAY)cinfo->colormap)[2][icolor]) * C2_SCALE;
dist0 += inc2 * inc2;
/* Form the initial difference increments */
inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0;
@@ -813,7 +817,7 @@ find_best_colors(j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
for (ic2 = BOX_C2_ELEMS - 1; ic2 >= 0; ic2--) {
if (dist2 < *bptr) {
*bptr = dist2;
- *cptr = (JSAMPLE)icolor;
+ *cptr = (_JSAMPLE)icolor;
}
dist2 += xx2;
xx2 += 2 * STEP_C2 * STEP_C2;
@@ -840,13 +844,13 @@ fill_inverse_cmap(j_decompress_ptr cinfo, int c0, int c1, int c2)
hist3d histogram = cquantize->histogram;
int minc0, minc1, minc2; /* lower left corner of update box */
int ic0, ic1, ic2;
- register JSAMPLE *cptr; /* pointer into bestcolor[] array */
+ register _JSAMPLE *cptr; /* pointer into bestcolor[] array */
register histptr cachep; /* pointer into main cache array */
/* This array lists the candidate colormap indexes. */
- JSAMPLE colorlist[MAXNUMCOLORS];
+ _JSAMPLE colorlist[MAXNUMCOLORS];
int numcolors; /* number of candidate colors */
/* This array holds the actually closest colormap index for each cell. */
- JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS];
+ _JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS];
/* Convert cell coordinates to update box ID */
c0 >>= BOX_C0_LOG;
@@ -891,13 +895,13 @@ fill_inverse_cmap(j_decompress_ptr cinfo, int c0, int c1, int c2)
*/
METHODDEF(void)
-pass2_no_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
+pass2_no_dither(j_decompress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPARRAY output_buf, int num_rows)
/* This version performs no dithering */
{
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
hist3d histogram = cquantize->histogram;
- register JSAMPROW inptr, outptr;
+ register _JSAMPROW inptr, outptr;
register histptr cachep;
register int c0, c1, c2;
int row;
@@ -918,15 +922,15 @@ pass2_no_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
if (*cachep == 0)
fill_inverse_cmap(cinfo, c0, c1, c2);
/* Now emit the colormap index for this cell */
- *outptr++ = (JSAMPLE)(*cachep - 1);
+ *outptr++ = (_JSAMPLE)(*cachep - 1);
}
}
}
METHODDEF(void)
-pass2_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPARRAY output_buf, int num_rows)
+pass2_fs_dither(j_decompress_ptr cinfo, _JSAMPARRAY input_buf,
+ _JSAMPARRAY output_buf, int num_rows)
/* This version performs Floyd-Steinberg dithering */
{
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
@@ -935,19 +939,19 @@ pass2_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */
LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */
register FSERRPTR errorptr; /* => fserrors[] at column before current */
- JSAMPROW inptr; /* => current input pixel */
- JSAMPROW outptr; /* => current output pixel */
+ _JSAMPROW inptr; /* => current input pixel */
+ _JSAMPROW outptr; /* => current output pixel */
histptr cachep;
int dir; /* +1 or -1 depending on direction */
int dir3; /* 3*dir, for advancing inptr & errorptr */
int row;
JDIMENSION col;
JDIMENSION width = cinfo->output_width;
- JSAMPLE *range_limit = cinfo->sample_range_limit;
+ _JSAMPLE *range_limit = (_JSAMPLE *)cinfo->sample_range_limit;
int *error_limit = cquantize->error_limiter;
- JSAMPROW colormap0 = cinfo->colormap[0];
- JSAMPROW colormap1 = cinfo->colormap[1];
- JSAMPROW colormap2 = cinfo->colormap[2];
+ _JSAMPROW colormap0 = ((_JSAMPARRAY)cinfo->colormap)[0];
+ _JSAMPROW colormap1 = ((_JSAMPARRAY)cinfo->colormap)[1];
+ _JSAMPROW colormap2 = ((_JSAMPARRAY)cinfo->colormap)[2];
SHIFT_TEMPS
for (row = 0; row < num_rows; row++) {
@@ -992,8 +996,8 @@ pass2_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
cur0 = error_limit[cur0];
cur1 = error_limit[cur1];
cur2 = error_limit[cur2];
- /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
- * The maximum error is +- MAXJSAMPLE (or less with error limiting);
+ /* Form pixel value + error, and range-limit to 0.._MAXJSAMPLE.
+ * The maximum error is +- _MAXJSAMPLE (or less with error limiting);
* this sets the required size of the range_limit array.
*/
cur0 += inptr[0];
@@ -1013,7 +1017,7 @@ pass2_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
/* Now emit the colormap index for this cell */
{
register int pixcode = *cachep - 1;
- *outptr = (JSAMPLE)pixcode;
+ *outptr = (_JSAMPLE)pixcode;
/* Compute representation error for this pixel */
cur0 -= colormap0[pixcode];
cur1 -= colormap1[pixcode];
@@ -1064,7 +1068,7 @@ pass2_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
/*
* Initialize the error-limiting transfer function (lookup table).
* The raw F-S error computation can potentially compute error values of up to
- * +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be
+ * +- _MAXJSAMPLE. But we want the maximum correction applied to a pixel to be
* much less, otherwise obviously wrong pixels will be created. (Typical
* effects include weird fringes at color-area boundaries, isolated bright
* pixels in a dark area, etc.) The standard advice for avoiding this problem
@@ -1073,7 +1077,7 @@ pass2_fs_dither(j_decompress_ptr cinfo, JSAMPARRAY input_buf,
* error buildup. However, that only prevents the error from getting
* completely out of hand; Aaron Giles reports that error limiting improves
* the results even with corner colors allocated.
- * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty
+ * A simple clamping of the error values to about +- _MAXJSAMPLE/8 works pretty
* well, but the smoother transfer function used below is even better. Thanks
* to Aaron Giles for this idea.
*/
@@ -1087,22 +1091,22 @@ init_error_limit(j_decompress_ptr cinfo)
int in, out;
table = (int *)(*cinfo->mem->alloc_small)
- ((j_common_ptr)cinfo, JPOOL_IMAGE, (MAXJSAMPLE * 2 + 1) * sizeof(int));
- table += MAXJSAMPLE; /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */
+ ((j_common_ptr)cinfo, JPOOL_IMAGE, (_MAXJSAMPLE * 2 + 1) * sizeof(int));
+ table += _MAXJSAMPLE; /* so can index -_MAXJSAMPLE .. +_MAXJSAMPLE */
cquantize->error_limiter = table;
-#define STEPSIZE ((MAXJSAMPLE + 1) / 16)
- /* Map errors 1:1 up to +- MAXJSAMPLE/16 */
+#define STEPSIZE ((_MAXJSAMPLE + 1) / 16)
+ /* Map errors 1:1 up to +- _MAXJSAMPLE/16 */
out = 0;
for (in = 0; in < STEPSIZE; in++, out++) {
table[in] = out; table[-in] = -out;
}
- /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */
+ /* Map errors 1:2 up to +- 3*_MAXJSAMPLE/16 */
for (; in < STEPSIZE * 3; in++, out += (in & 1) ? 0 : 1) {
table[in] = out; table[-in] = -out;
}
- /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */
- for (; in <= MAXJSAMPLE; in++) {
+ /* Clamp the rest to final out value (which is (_MAXJSAMPLE+1)/8) */
+ for (; in <= _MAXJSAMPLE; in++) {
table[in] = out; table[-in] = -out;
}
#undef STEPSIZE
@@ -1119,7 +1123,7 @@ finish_pass1(j_decompress_ptr cinfo)
my_cquantize_ptr cquantize = (my_cquantize_ptr)cinfo->cquantize;
/* Select the representative colors and fill in cinfo->colormap */
- cinfo->colormap = cquantize->sv_colormap;
+ cinfo->colormap = (JSAMPARRAY)cquantize->sv_colormap;
select_colors(cinfo, cquantize->desired);
/* Force next pass to zero the color index table */
cquantize->needs_zeroed = TRUE;
@@ -1151,15 +1155,15 @@ start_pass_2_quant(j_decompress_ptr cinfo, boolean is_pre_scan)
if (is_pre_scan) {
/* Set up method pointers */
- cquantize->pub.color_quantize = prescan_quantize;
+ cquantize->pub._color_quantize = prescan_quantize;
cquantize->pub.finish_pass = finish_pass1;
cquantize->needs_zeroed = TRUE; /* Always zero histogram */
} else {
/* Set up method pointers */
if (cinfo->dither_mode == JDITHER_FS)
- cquantize->pub.color_quantize = pass2_fs_dither;
+ cquantize->pub._color_quantize = pass2_fs_dither;
else
- cquantize->pub.color_quantize = pass2_no_dither;
+ cquantize->pub._color_quantize = pass2_no_dither;
cquantize->pub.finish_pass = finish_pass2;
/* Make sure color count is acceptable */
@@ -1215,11 +1219,14 @@ new_color_map_2_quant(j_decompress_ptr cinfo)
*/
GLOBAL(void)
-jinit_2pass_quantizer(j_decompress_ptr cinfo)
+_jinit_2pass_quantizer(j_decompress_ptr cinfo)
{
my_cquantize_ptr cquantize;
int i;
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
cquantize = (my_cquantize_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
sizeof(my_cquantizer));
@@ -1230,7 +1237,8 @@ jinit_2pass_quantizer(j_decompress_ptr cinfo)
cquantize->error_limiter = NULL;
/* Make sure jdmaster didn't give me a case I can't handle */
- if (cinfo->out_color_components != 3)
+ if (cinfo->out_color_components != 3 ||
+ cinfo->out_color_space == JCS_RGB565 || cinfo->master->lossless)
ERREXIT(cinfo, JERR_NOTIMPL);
/* Allocate the histogram/inverse colormap storage */
@@ -1253,10 +1261,10 @@ jinit_2pass_quantizer(j_decompress_ptr cinfo)
/* Lower bound on # of colors ... somewhat arbitrary as long as > 0 */
if (desired < 8)
ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 8);
- /* Make sure colormap indexes can be represented by JSAMPLEs */
+ /* Make sure colormap indexes can be represented by _JSAMPLEs */
if (desired > MAXNUMCOLORS)
ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS);
- cquantize->sv_colormap = (*cinfo->mem->alloc_sarray)
+ cquantize->sv_colormap = (_JSAMPARRAY)(*cinfo->mem->alloc_sarray)
((j_common_ptr)cinfo, JPOOL_IMAGE, (JDIMENSION)desired, (JDIMENSION)3);
cquantize->desired = desired;
} else
@@ -1282,4 +1290,4 @@ jinit_2pass_quantizer(j_decompress_ptr cinfo)
}
}
-#endif /* QUANT_2PASS_SUPPORTED */
+#endif /* defined(QUANT_2PASS_SUPPORTED) && BITS_IN_JSAMPLE != 16 */
diff --git a/src/3rdparty/libjpeg/src/jsamplecomp.h b/src/3rdparty/libjpeg/src/jsamplecomp.h
new file mode 100644
index 0000000000..f3f275e6e2
--- /dev/null
+++ b/src/3rdparty/libjpeg/src/jsamplecomp.h
@@ -0,0 +1,336 @@
+/*
+ * jsamplecomp.h
+ *
+ * Copyright (C) 2022, D. R. Commander.
+ * For conditions of distribution and use, see the accompanying README.ijg
+ * file.
+ */
+
+/* In source files that must be compiled for multiple data precisions, we
+ * prefix all precision-dependent data types, macros, methods, fields, and
+ * function names with an underscore. Including this file replaces those
+ * precision-independent tokens with their precision-dependent equivalents,
+ * based on the value of BITS_IN_JSAMPLE.
+ */
+
+#ifndef JSAMPLECOMP_H
+#define JSAMPLECOMP_H
+
+#if BITS_IN_JSAMPLE == 16
+
+/* Sample data types and macros (jmorecfg.h) */
+#define _JSAMPLE J16SAMPLE
+
+#define _MAXJSAMPLE MAXJ16SAMPLE
+#define _CENTERJSAMPLE CENTERJ16SAMPLE
+
+#define _JSAMPROW J16SAMPROW
+#define _JSAMPARRAY J16SAMPARRAY
+#define _JSAMPIMAGE J16SAMPIMAGE
+
+/* External functions (jpeglib.h) */
+#define _jpeg_write_scanlines jpeg16_write_scanlines
+#define _jpeg_read_scanlines jpeg16_read_scanlines
+
+/* Internal methods (jpegint.h) */
+
+#ifdef C_LOSSLESS_SUPPORTED
+/* Use the 16-bit method in the jpeg_c_main_controller structure. */
+#define _process_data process_data_16
+/* Use the 16-bit method in the jpeg_c_prep_controller structure. */
+#define _pre_process_data pre_process_data_16
+/* Use the 16-bit method in the jpeg_c_coef_controller structure. */
+#define _compress_data compress_data_16
+/* Use the 16-bit method in the jpeg_color_converter structure. */
+#define _color_convert color_convert_16
+/* Use the 16-bit method in the jpeg_downsampler structure. */
+#define _downsample downsample_16
+#endif
+#ifdef D_LOSSLESS_SUPPORTED
+/* Use the 16-bit method in the jpeg_d_main_controller structure. */
+#define _process_data process_data_16
+/* Use the 16-bit method in the jpeg_d_coef_controller structure. */
+#define _decompress_data decompress_data_16
+/* Use the 16-bit method in the jpeg_d_post_controller structure. */
+#define _post_process_data post_process_data_16
+/* Use the 16-bit method in the jpeg_upsampler structure. */
+#define _upsample upsample_16
+/* Use the 16-bit method in the jpeg_color_converter structure. */
+#define _color_convert color_convert_16
+#endif
+
+/* Global internal functions (jpegint.h) */
+#ifdef C_LOSSLESS_SUPPORTED
+#define _jinit_c_main_controller j16init_c_main_controller
+#define _jinit_c_prep_controller j16init_c_prep_controller
+#define _jinit_color_converter j16init_color_converter
+#define _jinit_downsampler j16init_downsampler
+#define _jinit_c_diff_controller j16init_c_diff_controller
+#define _jinit_lossless_compressor j16init_lossless_compressor
+#endif
+
+#ifdef D_LOSSLESS_SUPPORTED
+#define _jinit_d_main_controller j16init_d_main_controller
+#define _jinit_d_post_controller j16init_d_post_controller
+#define _jinit_upsampler j16init_upsampler
+#define _jinit_color_deconverter j16init_color_deconverter
+#define _jinit_merged_upsampler j16init_merged_upsampler
+#define _jinit_d_diff_controller j16init_d_diff_controller
+#define _jinit_lossless_decompressor j16init_lossless_decompressor
+#endif
+
+#if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED)
+#define _jcopy_sample_rows j16copy_sample_rows
+#endif
+
+/* Internal fields (cdjpeg.h) */
+
+#if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED)
+/* Use the 16-bit buffer in the cjpeg_source_struct and djpeg_dest_struct
+ structures. */
+#define _buffer buffer16
+#endif
+
+/* Image I/O functions (cdjpeg.h) */
+#ifdef C_LOSSLESS_SUPPORTED
+#define _jinit_read_gif j16init_read_gif
+#define _jinit_read_ppm j16init_read_ppm
+#endif
+
+#ifdef D_LOSSLESS_SUPPORTED
+#define _jinit_write_ppm j16init_write_ppm
+#endif
+
+#elif BITS_IN_JSAMPLE == 12
+
+/* Sample data types and macros (jmorecfg.h) */
+#define _JSAMPLE J12SAMPLE
+
+#define _MAXJSAMPLE MAXJ12SAMPLE
+#define _CENTERJSAMPLE CENTERJ12SAMPLE
+
+#define _JSAMPROW J12SAMPROW
+#define _JSAMPARRAY J12SAMPARRAY
+#define _JSAMPIMAGE J12SAMPIMAGE
+
+/* External functions (jpeglib.h) */
+#define _jpeg_write_scanlines jpeg12_write_scanlines
+#define _jpeg_write_raw_data jpeg12_write_raw_data
+#define _jpeg_read_scanlines jpeg12_read_scanlines
+#define _jpeg_skip_scanlines jpeg12_skip_scanlines
+#define _jpeg_crop_scanline jpeg12_crop_scanline
+#define _jpeg_read_raw_data jpeg12_read_raw_data
+
+/* Internal methods (jpegint.h) */
+
+/* Use the 12-bit method in the jpeg_c_main_controller structure. */
+#define _process_data process_data_12
+/* Use the 12-bit method in the jpeg_c_prep_controller structure. */
+#define _pre_process_data pre_process_data_12
+/* Use the 12-bit method in the jpeg_c_coef_controller structure. */
+#define _compress_data compress_data_12
+/* Use the 12-bit method in the jpeg_color_converter structure. */
+#define _color_convert color_convert_12
+/* Use the 12-bit method in the jpeg_downsampler structure. */
+#define _downsample downsample_12
+/* Use the 12-bit method in the jpeg_forward_dct structure. */
+#define _forward_DCT forward_DCT_12
+/* Use the 12-bit method in the jpeg_d_main_controller structure. */
+#define _process_data process_data_12
+/* Use the 12-bit method in the jpeg_d_coef_controller structure. */
+#define _decompress_data decompress_data_12
+/* Use the 12-bit method in the jpeg_d_post_controller structure. */
+#define _post_process_data post_process_data_12
+/* Use the 12-bit method in the jpeg_inverse_dct structure. */
+#define _inverse_DCT_method_ptr inverse_DCT_12_method_ptr
+#define _inverse_DCT inverse_DCT_12
+/* Use the 12-bit method in the jpeg_upsampler structure. */
+#define _upsample upsample_12
+/* Use the 12-bit method in the jpeg_color_converter structure. */
+#define _color_convert color_convert_12
+/* Use the 12-bit method in the jpeg_color_quantizer structure. */
+#define _color_quantize color_quantize_12
+
+/* Global internal functions (jpegint.h) */
+#define _jinit_c_main_controller j12init_c_main_controller
+#define _jinit_c_prep_controller j12init_c_prep_controller
+#define _jinit_c_coef_controller j12init_c_coef_controller
+#define _jinit_color_converter j12init_color_converter
+#define _jinit_downsampler j12init_downsampler
+#define _jinit_forward_dct j12init_forward_dct
+#ifdef C_LOSSLESS_SUPPORTED
+#define _jinit_c_diff_controller j12init_c_diff_controller
+#define _jinit_lossless_compressor j12init_lossless_compressor
+#endif
+
+#define _jinit_d_main_controller j12init_d_main_controller
+#define _jinit_d_coef_controller j12init_d_coef_controller
+#define _jinit_d_post_controller j12init_d_post_controller
+#define _jinit_inverse_dct j12init_inverse_dct
+#define _jinit_upsampler j12init_upsampler
+#define _jinit_color_deconverter j12init_color_deconverter
+#define _jinit_1pass_quantizer j12init_1pass_quantizer
+#define _jinit_2pass_quantizer j12init_2pass_quantizer
+#define _jinit_merged_upsampler j12init_merged_upsampler
+#ifdef D_LOSSLESS_SUPPORTED
+#define _jinit_d_diff_controller j12init_d_diff_controller
+#define _jinit_lossless_decompressor j12init_lossless_decompressor
+#endif
+
+#define _jcopy_sample_rows j12copy_sample_rows
+
+/* Global internal functions (jdct.h) */
+#define _jpeg_fdct_islow jpeg12_fdct_islow
+#define _jpeg_fdct_ifast jpeg12_fdct_ifast
+
+#define _jpeg_idct_islow jpeg12_idct_islow
+#define _jpeg_idct_ifast jpeg12_idct_ifast
+#define _jpeg_idct_float jpeg12_idct_float
+#define _jpeg_idct_7x7 jpeg12_idct_7x7
+#define _jpeg_idct_6x6 jpeg12_idct_6x6
+#define _jpeg_idct_5x5 jpeg12_idct_5x5
+#define _jpeg_idct_4x4 jpeg12_idct_4x4
+#define _jpeg_idct_3x3 jpeg12_idct_3x3
+#define _jpeg_idct_2x2 jpeg12_idct_2x2
+#define _jpeg_idct_1x1 jpeg12_idct_1x1
+#define _jpeg_idct_9x9 jpeg12_idct_9x9
+#define _jpeg_idct_10x10 jpeg12_idct_10x10
+#define _jpeg_idct_11x11 jpeg12_idct_11x11
+#define _jpeg_idct_12x12 jpeg12_idct_12x12
+#define _jpeg_idct_13x13 jpeg12_idct_13x13
+#define _jpeg_idct_14x14 jpeg12_idct_14x14
+#define _jpeg_idct_15x15 jpeg12_idct_15x15
+#define _jpeg_idct_16x16 jpeg12_idct_16x16
+
+/* Internal fields (cdjpeg.h) */
+
+/* Use the 12-bit buffer in the cjpeg_source_struct and djpeg_dest_struct
+ structures. */
+#define _buffer buffer12
+
+/* Image I/O functions (cdjpeg.h) */
+#define _jinit_read_gif j12init_read_gif
+#define _jinit_write_gif j12init_write_gif
+#define _jinit_read_ppm j12init_read_ppm
+#define _jinit_write_ppm j12init_write_ppm
+
+#define _read_color_map read_color_map_12
+
+#else /* BITS_IN_JSAMPLE */
+
+/* Sample data types and macros (jmorecfg.h) */
+#define _JSAMPLE JSAMPLE
+
+#define _MAXJSAMPLE MAXJSAMPLE
+#define _CENTERJSAMPLE CENTERJSAMPLE
+
+#define _JSAMPROW JSAMPROW
+#define _JSAMPARRAY JSAMPARRAY
+#define _JSAMPIMAGE JSAMPIMAGE
+
+/* External functions (jpeglib.h) */
+#define _jpeg_write_scanlines jpeg_write_scanlines
+#define _jpeg_write_raw_data jpeg_write_raw_data
+#define _jpeg_read_scanlines jpeg_read_scanlines
+#define _jpeg_skip_scanlines jpeg_skip_scanlines
+#define _jpeg_crop_scanline jpeg_crop_scanline
+#define _jpeg_read_raw_data jpeg_read_raw_data
+
+/* Internal methods (jpegint.h) */
+
+/* Use the 8-bit method in the jpeg_c_main_controller structure. */
+#define _process_data process_data
+/* Use the 8-bit method in the jpeg_c_prep_controller structure. */
+#define _pre_process_data pre_process_data
+/* Use the 8-bit method in the jpeg_c_coef_controller structure. */
+#define _compress_data compress_data
+/* Use the 8-bit method in the jpeg_color_converter structure. */
+#define _color_convert color_convert
+/* Use the 8-bit method in the jpeg_downsampler structure. */
+#define _downsample downsample
+/* Use the 8-bit method in the jpeg_forward_dct structure. */
+#define _forward_DCT forward_DCT
+/* Use the 8-bit method in the jpeg_d_main_controller structure. */
+#define _process_data process_data
+/* Use the 8-bit method in the jpeg_d_coef_controller structure. */
+#define _decompress_data decompress_data
+/* Use the 8-bit method in the jpeg_d_post_controller structure. */
+#define _post_process_data post_process_data
+/* Use the 8-bit method in the jpeg_inverse_dct structure. */
+#define _inverse_DCT_method_ptr inverse_DCT_method_ptr
+#define _inverse_DCT inverse_DCT
+/* Use the 8-bit method in the jpeg_upsampler structure. */
+#define _upsample upsample
+/* Use the 8-bit method in the jpeg_color_converter structure. */
+#define _color_convert color_convert
+/* Use the 8-bit method in the jpeg_color_quantizer structure. */
+#define _color_quantize color_quantize
+
+/* Global internal functions (jpegint.h) */
+#define _jinit_c_main_controller jinit_c_main_controller
+#define _jinit_c_prep_controller jinit_c_prep_controller
+#define _jinit_c_coef_controller jinit_c_coef_controller
+#define _jinit_color_converter jinit_color_converter
+#define _jinit_downsampler jinit_downsampler
+#define _jinit_forward_dct jinit_forward_dct
+#ifdef C_LOSSLESS_SUPPORTED
+#define _jinit_c_diff_controller jinit_c_diff_controller
+#define _jinit_lossless_compressor jinit_lossless_compressor
+#endif
+
+#define _jinit_d_main_controller jinit_d_main_controller
+#define _jinit_d_coef_controller jinit_d_coef_controller
+#define _jinit_d_post_controller jinit_d_post_controller
+#define _jinit_inverse_dct jinit_inverse_dct
+#define _jinit_upsampler jinit_upsampler
+#define _jinit_color_deconverter jinit_color_deconverter
+#define _jinit_1pass_quantizer jinit_1pass_quantizer
+#define _jinit_2pass_quantizer jinit_2pass_quantizer
+#define _jinit_merged_upsampler jinit_merged_upsampler
+#ifdef D_LOSSLESS_SUPPORTED
+#define _jinit_d_diff_controller jinit_d_diff_controller
+#define _jinit_lossless_decompressor jinit_lossless_decompressor
+#endif
+
+#define _jcopy_sample_rows jcopy_sample_rows
+
+/* Global internal functions (jdct.h) */
+#define _jpeg_fdct_islow jpeg_fdct_islow
+#define _jpeg_fdct_ifast jpeg_fdct_ifast
+
+#define _jpeg_idct_islow jpeg_idct_islow
+#define _jpeg_idct_ifast jpeg_idct_ifast
+#define _jpeg_idct_float jpeg_idct_float
+#define _jpeg_idct_7x7 jpeg_idct_7x7
+#define _jpeg_idct_6x6 jpeg_idct_6x6
+#define _jpeg_idct_5x5 jpeg_idct_5x5
+#define _jpeg_idct_4x4 jpeg_idct_4x4
+#define _jpeg_idct_3x3 jpeg_idct_3x3
+#define _jpeg_idct_2x2 jpeg_idct_2x2
+#define _jpeg_idct_1x1 jpeg_idct_1x1
+#define _jpeg_idct_9x9 jpeg_idct_9x9
+#define _jpeg_idct_10x10 jpeg_idct_10x10
+#define _jpeg_idct_11x11 jpeg_idct_11x11
+#define _jpeg_idct_12x12 jpeg_idct_12x12
+#define _jpeg_idct_13x13 jpeg_idct_13x13
+#define _jpeg_idct_14x14 jpeg_idct_14x14
+#define _jpeg_idct_15x15 jpeg_idct_15x15
+#define _jpeg_idct_16x16 jpeg_idct_16x16
+
+/* Internal fields (cdjpeg.h) */
+
+/* Use the 8-bit buffer in the cjpeg_source_struct and djpeg_dest_struct
+ structures. */
+#define _buffer buffer
+
+/* Image I/O functions (cdjpeg.h) */
+#define _jinit_read_gif jinit_read_gif
+#define _jinit_write_gif jinit_write_gif
+#define _jinit_read_ppm jinit_read_ppm
+#define _jinit_write_ppm jinit_write_ppm
+
+#define _read_color_map read_color_map
+
+#endif /* BITS_IN_JSAMPLE */
+
+#endif /* JSAMPLECOMP_H */
diff --git a/src/3rdparty/libjpeg/src/jsimd.h b/src/3rdparty/libjpeg/src/jsimd.h
index 74d480aa2c..6ae021a651 100644
--- a/src/3rdparty/libjpeg/src/jsimd.h
+++ b/src/3rdparty/libjpeg/src/jsimd.h
@@ -12,6 +12,8 @@
*
*/
+#ifdef WITH_SIMD
+
#include "jchuff.h" /* Declarations shared with jcphuff.c */
EXTERN(int) jsimd_can_rgb_ycc(void);
@@ -121,3 +123,5 @@ EXTERN(int) jsimd_can_encode_mcu_AC_refine_prepare(void);
EXTERN(int) jsimd_encode_mcu_AC_refine_prepare
(const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
UJCOEF *absvalues, size_t *bits);
+
+#endif /* WITH_SIMD */
diff --git a/src/3rdparty/libjpeg/src/jsimd_none.c b/src/3rdparty/libjpeg/src/jsimd_none.c
deleted file mode 100644
index a25db73899..0000000000
--- a/src/3rdparty/libjpeg/src/jsimd_none.c
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- * jsimd_none.c
- *
- * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009-2011, 2014, 2022, D. R. Commander.
- * Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
- * Copyright (C) 2020, Arm Limited.
- *
- * Based on the x86 SIMD extension for IJG JPEG library,
- * Copyright (C) 1999-2006, MIYASAKA Masaru.
- * For conditions of distribution and use, see copyright notice in jsimdext.inc
- *
- * This file contains stubs for when there is no SIMD support available.
- */
-
-#define JPEG_INTERNALS
-#include "jinclude.h"
-#include "jpeglib.h"
-#include "jsimd.h"
-#include "jdct.h"
-#include "jsimddct.h"
-
-GLOBAL(int)
-jsimd_can_rgb_ycc(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_rgb_gray(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_ycc_rgb(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_ycc_rgb565(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_c_can_null_convert(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_rgb_ycc_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row,
- int num_rows)
-{
-}
-
-GLOBAL(void)
-jsimd_rgb_gray_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row,
- int num_rows)
-{
-}
-
-GLOBAL(void)
-jsimd_ycc_rgb_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
- int num_rows)
-{
-}
-
-GLOBAL(void)
-jsimd_ycc_rgb565_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION input_row, JSAMPARRAY output_buf,
- int num_rows)
-{
-}
-
-GLOBAL(void)
-jsimd_c_null_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
- JSAMPIMAGE output_buf, JDIMENSION output_row,
- int num_rows)
-{
-}
-
-GLOBAL(int)
-jsimd_can_h2v2_downsample(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_h2v1_downsample(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_h2v2_smooth_downsample(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_h2v2_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
-{
-}
-
-GLOBAL(void)
-jsimd_h2v2_smooth_downsample(j_compress_ptr cinfo,
- jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
-{
-}
-
-GLOBAL(void)
-jsimd_h2v1_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY output_data)
-{
-}
-
-GLOBAL(int)
-jsimd_can_h2v2_upsample(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_h2v1_upsample(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_int_upsample(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_int_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
-{
-}
-
-GLOBAL(void)
-jsimd_h2v2_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
-{
-}
-
-GLOBAL(void)
-jsimd_h2v1_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
-{
-}
-
-GLOBAL(int)
-jsimd_can_h2v2_fancy_upsample(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_h2v1_fancy_upsample(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_h1v2_fancy_upsample(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_h2v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
-{
-}
-
-GLOBAL(void)
-jsimd_h2v1_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
-{
-}
-
-GLOBAL(void)
-jsimd_h1v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
-{
-}
-
-GLOBAL(int)
-jsimd_can_h2v2_merged_upsample(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_h2v1_merged_upsample(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_h2v2_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)
-{
-}
-
-GLOBAL(void)
-jsimd_h2v1_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
- JDIMENSION in_row_group_ctr, JSAMPARRAY output_buf)
-{
-}
-
-GLOBAL(int)
-jsimd_can_convsamp(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_convsamp_float(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_convsamp(JSAMPARRAY sample_data, JDIMENSION start_col,
- DCTELEM *workspace)
-{
-}
-
-GLOBAL(void)
-jsimd_convsamp_float(JSAMPARRAY sample_data, JDIMENSION start_col,
- FAST_FLOAT *workspace)
-{
-}
-
-GLOBAL(int)
-jsimd_can_fdct_islow(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_fdct_ifast(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_fdct_float(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_fdct_islow(DCTELEM *data)
-{
-}
-
-GLOBAL(void)
-jsimd_fdct_ifast(DCTELEM *data)
-{
-}
-
-GLOBAL(void)
-jsimd_fdct_float(FAST_FLOAT *data)
-{
-}
-
-GLOBAL(int)
-jsimd_can_quantize(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_quantize_float(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_quantize(JCOEFPTR coef_block, DCTELEM *divisors, DCTELEM *workspace)
-{
-}
-
-GLOBAL(void)
-jsimd_quantize_float(JCOEFPTR coef_block, FAST_FLOAT *divisors,
- FAST_FLOAT *workspace)
-{
-}
-
-GLOBAL(int)
-jsimd_can_idct_2x2(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_idct_4x4(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_idct_6x6(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_idct_12x12(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_idct_2x2(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
-{
-}
-
-GLOBAL(void)
-jsimd_idct_4x4(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
-{
-}
-
-GLOBAL(void)
-jsimd_idct_6x6(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
-{
-}
-
-GLOBAL(void)
-jsimd_idct_12x12(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
-{
-}
-
-GLOBAL(int)
-jsimd_can_idct_islow(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_idct_ifast(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_can_idct_float(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_idct_islow(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
-{
-}
-
-GLOBAL(void)
-jsimd_idct_ifast(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
-{
-}
-
-GLOBAL(void)
-jsimd_idct_float(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- JCOEFPTR coef_block, JSAMPARRAY output_buf,
- JDIMENSION output_col)
-{
-}
-
-GLOBAL(int)
-jsimd_can_huff_encode_one_block(void)
-{
- return 0;
-}
-
-GLOBAL(JOCTET *)
-jsimd_huff_encode_one_block(void *state, JOCTET *buffer, JCOEFPTR block,
- int last_dc_val, c_derived_tbl *dctbl,
- c_derived_tbl *actbl)
-{
- return NULL;
-}
-
-GLOBAL(int)
-jsimd_can_encode_mcu_AC_first_prepare(void)
-{
- return 0;
-}
-
-GLOBAL(void)
-jsimd_encode_mcu_AC_first_prepare(const JCOEF *block,
- const int *jpeg_natural_order_start, int Sl,
- int Al, UJCOEF *values, size_t *zerobits)
-{
-}
-
-GLOBAL(int)
-jsimd_can_encode_mcu_AC_refine_prepare(void)
-{
- return 0;
-}
-
-GLOBAL(int)
-jsimd_encode_mcu_AC_refine_prepare(const JCOEF *block,
- const int *jpeg_natural_order_start, int Sl,
- int Al, UJCOEF *absvalues, size_t *bits)
-{
- return 0;
-}
diff --git a/src/3rdparty/libjpeg/src/jutils.c b/src/3rdparty/libjpeg/src/jutils.c
index d86271624a..24caac1902 100644
--- a/src/3rdparty/libjpeg/src/jutils.c
+++ b/src/3rdparty/libjpeg/src/jutils.c
@@ -17,8 +17,11 @@
#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
+#include "jsamplecomp.h"
+#if BITS_IN_JSAMPLE == 8
+
/*
* jpeg_zigzag_order[i] is the zigzag-order position of the i'th element
* of a DCT block read in natural order (left to right, top to bottom).
@@ -89,19 +92,24 @@ jround_up(long a, long b)
return a - (a % b);
}
+#endif /* BITS_IN_JSAMPLE == 8 */
+
+
+#if BITS_IN_JSAMPLE != 16 || \
+ defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED)
GLOBAL(void)
-jcopy_sample_rows(JSAMPARRAY input_array, int source_row,
- JSAMPARRAY output_array, int dest_row, int num_rows,
- JDIMENSION num_cols)
+_jcopy_sample_rows(_JSAMPARRAY input_array, int source_row,
+ _JSAMPARRAY output_array, int dest_row, int num_rows,
+ JDIMENSION num_cols)
/* Copy some rows of samples from one place to another.
* num_rows rows are copied from input_array[source_row++]
* to output_array[dest_row++]; these areas may overlap for duplication.
* The source and destination arrays must be at least as wide as num_cols.
*/
{
- register JSAMPROW inptr, outptr;
- register size_t count = (size_t)(num_cols * sizeof(JSAMPLE));
+ register _JSAMPROW inptr, outptr;
+ register size_t count = (size_t)(num_cols * sizeof(_JSAMPLE));
register int row;
input_array += source_row;
@@ -114,6 +122,11 @@ jcopy_sample_rows(JSAMPARRAY input_array, int source_row,
}
}
+#endif /* BITS_IN_JSAMPLE != 16 ||
+ defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED) */
+
+
+#if BITS_IN_JSAMPLE == 8
GLOBAL(void)
jcopy_block_row(JBLOCKROW input_row, JBLOCKROW output_row,
@@ -131,3 +144,5 @@ jzero_far(void *target, size_t bytestozero)
{
memset(target, 0, bytestozero);
}
+
+#endif /* BITS_IN_JSAMPLE == 8 */
diff --git a/src/3rdparty/libjpeg/src/jversion.h b/src/3rdparty/libjpeg/src/jversion.h
index ea6de648d9..5c127dc635 100644
--- a/src/3rdparty/libjpeg/src/jversion.h
+++ b/src/3rdparty/libjpeg/src/jversion.h
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2012-2023, D. R. Commander.
+ * Copyright (C) 2010, 2012-2024, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -37,7 +37,7 @@
*/
#define JCOPYRIGHT \
- "Copyright (C) 2009-2023 D. R. Commander\n" \
+ "Copyright (C) 2009-2024 D. R. Commander\n" \
"Copyright (C) 2015, 2020 Google, Inc.\n" \
"Copyright (C) 2019-2020 Arm Limited\n" \
"Copyright (C) 2015-2016, 2018 Matthieu Darbois\n" \
@@ -48,7 +48,8 @@
"Copyright (C) 2009, 2012 Pierre Ossman for Cendio AB\n" \
"Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies)\n" \
"Copyright (C) 1999-2006 MIYASAKA Masaru\n" \
+ "Copyright (C) 1999 Ken Murchison\n" \
"Copyright (C) 1991-2020 Thomas G. Lane, Guido Vollbeding"
#define JCOPYRIGHT_SHORT \
- "Copyright (C) 1991-2023 The libjpeg-turbo Project and many others"
+ "Copyright (C) 1991-2024 The libjpeg-turbo Project and many others"
diff --git a/src/3rdparty/libpng/ANNOUNCE b/src/3rdparty/libpng/ANNOUNCE
index 5675b973ab..bc147adb78 100644
--- a/src/3rdparty/libpng/ANNOUNCE
+++ b/src/3rdparty/libpng/ANNOUNCE
@@ -1,4 +1,4 @@
-libpng 1.6.39 - November 20, 2022
+libpng 1.6.43 - February 23, 2024
=================================
This is a public release of libpng, intended for use in production code.
@@ -9,13 +9,13 @@ Files available for download
Source files with LF line endings (for Unix/Linux):
- * libpng-1.6.39.tar.xz (LZMA-compressed, recommended)
- * libpng-1.6.39.tar.gz
+ * libpng-1.6.43.tar.xz (LZMA-compressed, recommended)
+ * libpng-1.6.43.tar.gz (deflate-compressed)
Source files with CRLF line endings (for Windows):
- * lpng1639.7z (LZMA-compressed, recommended)
- * lpng1639.zip
+ * lpng1643.7z (LZMA-compressed, recommended)
+ * lpng1643.zip (deflate-compressed)
Other information:
@@ -25,19 +25,36 @@ Other information:
* TRADEMARK.md
-Changes from version 1.6.38 to version 1.6.39
+Changes from version 1.6.42 to version 1.6.43
---------------------------------------------
- * Changed the error handler of oversized chunks (i.e. larger than
- PNG_USER_CHUNK_MALLOC_MAX) from png_chunk_error to png_benign_error.
- * Fixed a buffer overflow error in contrib/tools/pngfix.
- * Fixed a memory leak (CVE-2019-6129) in contrib/tools/pngcp.
- * Disabled the ARM Neon optimizations by default in the CMake file,
- following the default behavior of the configure script.
- * Allowed configure.ac to work with the trunk version of autoconf.
- * Removed the support for "install" targets from the legacy makefiles;
- removed the obsolete makefile.cegcc.
- * Cleaned up the code and updated the internal documentation.
+ * Fixed the row width check in png_check_IHDR().
+ This corrected a bug that was specific to the 16-bit platforms,
+ and removed a spurious compiler warning from the 64-bit builds.
+ (Reported by Jacek Caban; fixed by John Bowler)
+ * Added eXIf chunk support to the push-mode reader in pngpread.c.
+ (Contributed by Chris Blume)
+ * Added contrib/pngexif for the benefit of the users who would like
+ to inspect the content of eXIf chunks.
+ * Added contrib/conftest/basic.dfa, a basic build-time configuration.
+ (Contributed by John Bowler)
+ * Fixed a preprocessor condition in pngread.c that broke build-time
+ configurations like contrib/conftest/pngcp.dfa.
+ (Contributed by John Bowler)
+ * Added CMake build support for LoongArch LSX.
+ (Contributed by GuXiWei)
+ * Fixed a CMake build error that occurred under a peculiar state of the
+ dependency tree. This was a regression introduced in libpng-1.6.41.
+ (Contributed by Dan Rosser)
+ * Marked the installed libpng headers as system headers in CMake.
+ (Contributed by Benjamin Buch)
+ * Updated the build support for RISCOS.
+ (Contributed by Cameron Cawley)
+ * Updated the makefiles to allow cross-platform builds to initialize
+ conventional make variables like AR and ARFLAGS.
+ * Added various improvements to the CI scripts in areas like version
+ consistency verification and text linting.
+ * Added version consistency verification to pngtest.c also.
Send comments/corrections/commendations to png-mng-implement at lists.sf.net.
diff --git a/src/3rdparty/libpng/CHANGES b/src/3rdparty/libpng/CHANGES
index 366e0f6a7b..441b57ecf1 100644
--- a/src/3rdparty/libpng/CHANGES
+++ b/src/3rdparty/libpng/CHANGES
@@ -204,7 +204,7 @@ Version 0.97 [January, 1998]
Added simple sRGB support (Glenn R-P)
Easier conditional compiling, e.g.,
define PNG_READ/WRITE_NOT_FULLY_SUPPORTED;
- all configurable options can be selected from command-line instead
+ all configurable options can be selected from command line instead
of having to edit pngconf.h (Glenn R-P)
Fixed memory leak in pngwrite.c (free info_ptr->text) (Glenn R-P)
Added more conditions for png_do_background, to avoid changing
@@ -942,7 +942,7 @@ Version 1.0.8 [July 24, 2000]
Version 1.0.9beta1 [November 10, 2000]
Fixed typo in scripts/makefile.hpux
Updated makevms.com in scripts and contrib/* and contrib/* (Martin Zinser)
- Fixed seqence-point bug in contrib/pngminus/png2pnm (Martin Zinser)
+ Fixed sequence-point bug in contrib/pngminus/png2pnm (Martin Zinser)
Changed "cdrom.com" in documentation to "libpng.org"
Revised pnggccrd.c to get it all working, and updated makefile.gcmmx (Greg).
Changed type of "params" from voidp to png_voidp in png_read|write_png().
@@ -2295,7 +2295,7 @@ Version 1.4.0beta58 [May 14, 2009]
Clarified usage of sig_bit versus sig_bit_p in example.c (Vincent Torri)
Version 1.4.0beta59 [May 15, 2009]
- Reformated sources in libpng style (3-space indentation, comment format)
+ Reformatted sources in libpng style (3-space indentation, comment format)
Fixed typo in libpng docs (PNG_FILTER_AVE should be PNG_FILTER_AVG)
Added sections about the git repository and our coding style to the
documentation
@@ -2661,7 +2661,7 @@ Version 1.4.1beta06 [January 28, 2010]
Version 1.4.1beta07 [February 6, 2010]
Folded some long lines in the source files.
- Added defineable PNG_USER_CHUNK_CACHE_MAX, PNG_USER_CHUNK_MALLOC_MAX,
+ Added definable PNG_USER_CHUNK_CACHE_MAX, PNG_USER_CHUNK_MALLOC_MAX,
and a PNG_USER_LIMITS_SUPPORTED flag.
Eliminated use of png_ptr->irowbytes and reused the slot in png_ptr as
png_ptr->png_user_chunk_malloc_max.
@@ -3919,7 +3919,7 @@ Version 1.6.0beta08 [February 1, 2012]
version checking to configure.ac
Improved pngstest speed by not doing redundant tests and add const to
the background parameter of png_image_finish_read. The --background
- option is now done automagically only when required, so that commandline
+ option is now done automagically only when required, so that command-line
option no longer exists.
Cleaned up pngpriv.h to consistently declare all functions and data.
Also eliminated PNG_CONST_DATA, which is apparently not needed but we
@@ -5927,7 +5927,7 @@ Version 1.6.32beta03 [August 2, 2017]
(Bug report from the OSS-fuzz project).
Version 1.6.32beta04 [August 2, 2017]
- Replaced local eXIf_buf with info_ptr-eXIf_buf in png_handle_eXIf().
+ Replaced local eXIf_buf with info_ptr->eXIf_buf in png_handle_eXIf().
Update libpng.3 and libpng-manual.txt about eXIf functions.
Version 1.6.32beta05 [August 2, 2017]
@@ -6121,6 +6121,81 @@ Version 1.6.39 [November 20, 2022]
removed the obsolete makefile.cegcc.
Cleaned up the code and updated the internal documentation.
+Version 1.6.40 [June 21, 2023]
+ Fixed the eXIf chunk multiplicity checks.
+ Fixed a memory leak in pCAL processing.
+ Corrected the validity report about tRNS inside png_get_valid().
+ Fixed various build issues on *BSD, Mac and Windows.
+ Updated the configurations and the scripts for continuous integration.
+ Cleaned up the code, the build scripts, and the documentation.
+
+Version 1.6.41 [January 24, 2024]
+ Added SIMD-optimized code for the LoongArch LSX hardware.
+ (Contributed by GuXiWei, JinBo and ZhangLixia)
+ Fixed the run-time discovery of MIPS MSA hardware.
+ (Contributed by Sui Jingfeng)
+ Fixed an off-by-one error in the function png_do_check_palette_indexes(),
+ which failed to recognize errors that might have existed in the first
+ column of a broken palette-encoded image. This was a benign regression
+ accidentally introduced in libpng-1.6.33. No pixel was harmed.
+ (Contributed by Adam Richter; reviewed by John Bowler)
+ Fixed, improved and modernized the contrib/pngminus programs, i.e.,
+ png2pnm.c and pnm2png.c
+ Removed old and peculiar portability hacks that were meant to silence
+ warnings issued by gcc version 7.1 alone.
+ (Contributed by John Bowler)
+ Fixed and modernized the CMake file, and raised the minimum required
+ CMake version from 3.1 to 3.6.
+ (Contributed by Clinton Ingram, Timothy Lyanguzov, Tyler Kropp, et al.)
+ Allowed the configure script to disable the building of auxiliary tools
+ and tests, thus catching up with the CMake file.
+ (Contributed by Carlo Bramini)
+ Fixed a build issue on Mac.
+ (Contributed by Zixu Wang)
+ Moved the Autoconf macro files to scripts/autoconf.
+ Moved the CMake files (except for the main CMakeLists.txt) to
+ scripts/cmake and moved the list of their contributing authors to
+ scripts/cmake/AUTHORS.md
+ Updated the CI configurations and scripts.
+ Relicensed the CI scripts to the MIT License.
+ Improved the test coverage.
+ (Contributed by John Bowler)
+
+Version 1.6.42 [January 29, 2024]
+ Fixed the implementation of the macro function png_check_sig().
+ This was an API regression, introduced in libpng-1.6.41.
+ (Reported by Matthieu Darbois)
+ Fixed and updated the libpng manual.
+
+Version 1.6.43 [February 23, 2024]
+ Fixed the row width check in png_check_IHDR().
+ This corrected a bug that was specific to the 16-bit platforms,
+ and removed a spurious compiler warning from the 64-bit builds.
+ (Reported by Jacek Caban; fixed by John Bowler)
+ Added eXIf chunk support to the push-mode reader in pngpread.c.
+ (Contributed by Chris Blume)
+ Added contrib/pngexif for the benefit of the users who would like
+ to inspect the content of eXIf chunks.
+ Added contrib/conftest/basic.dfa, a basic build-time configuration.
+ (Contributed by John Bowler)
+ Fixed a preprocessor condition in pngread.c that broke build-time
+ configurations like contrib/conftest/pngcp.dfa.
+ (Contributed by John Bowler)
+ Added CMake build support for LoongArch LSX.
+ (Contributed by GuXiWei)
+ Fixed a CMake build error that occurred under a peculiar state of the
+ dependency tree. This was a regression introduced in libpng-1.6.41.
+ (Contributed by Dan Rosser)
+ Marked the installed libpng headers as system headers in CMake.
+ (Contributed by Benjamin Buch)
+ Updated the build support for RISCOS.
+ (Contributed by Cameron Cawley)
+ Updated the makefiles to allow cross-platform builds to initialize
+ conventional make variables like AR and ARFLAGS.
+ Added various improvements to the CI scripts in areas like version
+ consistency verification and text linting.
+ Added version consistency verification to pngtest.c also.
+
Send comments/corrections/commendations to png-mng-implement at lists.sf.net.
Subscription is required; visit
https://lists.sourceforge.net/lists/listinfo/png-mng-implement
diff --git a/src/3rdparty/libpng/LICENSE b/src/3rdparty/libpng/LICENSE
index c8ad24eecf..25f298f0fc 100644
--- a/src/3rdparty/libpng/LICENSE
+++ b/src/3rdparty/libpng/LICENSE
@@ -4,8 +4,8 @@ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE
PNG Reference Library License version 2
---------------------------------------
- * Copyright (c) 1995-2022 The PNG Reference Library Authors.
- * Copyright (c) 2018-2022 Cosmin Truta.
+ * Copyright (c) 1995-2024 The PNG Reference Library Authors.
+ * Copyright (c) 2018-2024 Cosmin Truta.
* Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
* Copyright (c) 1996-1997 Andreas Dilger.
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
diff --git a/src/3rdparty/libpng/README b/src/3rdparty/libpng/README
index 097a3c2184..a6ca3ae9f9 100644
--- a/src/3rdparty/libpng/README
+++ b/src/3rdparty/libpng/README
@@ -1,110 +1,108 @@
-README for libpng version 1.6.39
+README for libpng version 1.6.43
================================
-See the note about version numbers near the top of png.h.
-See INSTALL for instructions on how to install libpng.
+See the note about version numbers near the top of `png.h`.
+See `INSTALL` for instructions on how to install libpng.
-Libpng comes in several distribution formats. Get libpng-*.tar.gz or
-libpng-*.tar.xz if you want UNIX-style line endings in the text files,
-or lpng*.7z or lpng*.zip if you want DOS-style line endings.
+Libpng comes in several distribution formats. Get `libpng-*.tar.gz`
+or `libpng-*.tar.xz` if you want UNIX-style line endings in the text
+files, or `lpng*.7z` or `lpng*.zip` if you want DOS-style line endings.
-Version 0.89 was the first official release of libpng. Don't let the
-fact that it's the first release fool you. The libpng library has been
-in extensive use and testing since mid-1995. By late 1997 it had
-finally gotten to the stage where there hadn't been significant
-changes to the API in some time, and people have a bad feeling about
-libraries with versions < 1.0. Version 1.0.0 was released in
-March 1998.
+For a detailed description on using libpng, read `libpng-manual.txt`.
+For examples of libpng in a program, see `example.c` and `pngtest.c`.
+For usage information and restrictions (what little they are) on libpng,
+see `png.h`. For a description on using zlib (the compression library
+used by libpng) and zlib's restrictions, see `zlib.h`.
-****
-Note that some of the changes to the png_info structure render this
-version of the library binary incompatible with libpng-0.89 or
-earlier versions if you are using a shared library. The type of the
-"filler" parameter for png_set_filler() has changed from png_byte to
-png_uint_32, which will affect shared-library applications that use
-this function.
-
-To avoid problems with changes to the internals of the png info_struct,
-new APIs have been made available in 0.95 to avoid direct application
-access to info_ptr. These functions are the png_set_<chunk> and
-png_get_<chunk> functions. These functions should be used when
-accessing/storing the info_struct data, rather than manipulating it
-directly, to avoid such problems in the future.
-
-It is important to note that the APIs did not make current programs
-that access the info struct directly incompatible with the new
-library, through libpng-1.2.x. In libpng-1.4.x, which was meant to
-be a transitional release, members of the png_struct and the
-info_struct can still be accessed, but the compiler will issue a
-warning about deprecated usage. Since libpng-1.5.0, direct access
-to these structs is not allowed, and the definitions of the structs
-reside in private pngstruct.h and pnginfo.h header files that are not
-accessible to applications. It is strongly suggested that new
-programs use the new APIs (as shown in example.c and pngtest.c), and
-older programs be converted to the new format, to facilitate upgrades
-in the future.
-****
-
-Additions since 0.90 include the ability to compile libpng as a
-Windows DLL, and new APIs for accessing data in the info struct.
-Experimental functions include the ability to set weighting and cost
-factors for row filter selection, direct reads of integers from buffers
-on big-endian processors that support misaligned data access, faster
-methods of doing alpha composition, and more accurate 16->8 bit color
-conversion.
-
-The additions since 0.89 include the ability to read from a PNG stream
-which has had some (or all) of the signature bytes read by the calling
-application. This also allows the reading of embedded PNG streams that
-do not have the PNG file signature. As well, it is now possible to set
-the library action on the detection of chunk CRC errors. It is possible
-to set different actions based on whether the CRC error occurred in a
-critical or an ancillary chunk.
-
-For a detailed description on using libpng, read libpng-manual.txt.
-For examples of libpng in a program, see example.c and pngtest.c. For
-usage information and restrictions (what little they are) on libpng,
-see png.h. For a description on using zlib (the compression library
-used by libpng) and zlib's restrictions, see zlib.h
-
-I have included a general makefile, as well as several machine and
-compiler specific ones, but you may have to modify one for your own
-needs.
-
-You should use zlib 1.0.4 or later to run this, but it MAY work with
+You should use zlib 1.0.4 or later to run this, but it _may_ work with
versions as old as zlib 0.95. Even so, there are bugs in older zlib
versions which can cause the output of invalid compression streams for
some images.
You should also note that zlib is a compression library that is useful
for more things than just PNG files. You can use zlib as a drop-in
-replacement for fread() and fwrite(), if you are so inclined.
+replacement for `fread()` and `fwrite()`, if you are so inclined.
zlib should be available at the same place that libpng is, or at
-https://zlib.net.
+https://zlib.net .
You may also want a copy of the PNG specification. It is available
as an RFC, a W3C Recommendation, and an ISO/IEC Standard. You can find
these at http://www.libpng.org/pub/png/pngdocs.html .
-This code is currently being archived at libpng.sourceforge.io in the
-[DOWNLOAD] area, and at http://libpng.download/src .
+This code is currently being archived at https://libpng.sourceforge.io
+in the download area, and at http://libpng.download/src .
This release, based in a large way on Glenn's, Guy's and Andreas'
earlier work, was created and will be supported by myself and the PNG
development group.
-Send comments/corrections/commendations to png-mng-implement at
-lists.sourceforge.net (subscription required; visit
+Send comments, corrections and commendations to `png-mng-implement`
+at `lists.sourceforge.net`. (Subscription is required; visit
https://lists.sourceforge.net/lists/listinfo/png-mng-implement
-to subscribe).
+to subscribe.)
+
+Send general questions about the PNG specification to `png-mng-misc`
+at `lists.sourceforge.net`. (Subscription is required; visit
+https://lists.sourceforge.net/lists/listinfo/png-mng-misc
+to subscribe.)
-Send general questions about the PNG specification to png-mng-misc
-at lists.sourceforge.net (subscription required; visit
-https://lists.sourceforge.net/lists/listinfo/png-mng-misc to
-subscribe).
+Historical notes
+----------------
+
+The libpng library has been in extensive use and testing since mid-1995.
+Version 0.89, published a year later, was the first official release.
+By late 1997, it had finally gotten to the stage where there hadn't
+been significant changes to the API in some time, and people have a bad
+feeling about libraries with versions below 1.0. Version 1.0.0 was
+released in March 1998.
+
+Note that some of the changes to the `png_info` structure render this
+version of the library binary incompatible with libpng-0.89 or
+earlier versions if you are using a shared library. The type of the
+`filler` parameter for `png_set_filler()` has changed from `png_byte`
+to `png_uint_32`, which will affect shared-library applications that
+use this function.
+
+To avoid problems with changes to the internals of the `info_struct`,
+new APIs have been made available in 0.95 to avoid direct application
+access to `info_ptr`. These functions are the `png_set_<chunk>` and
+`png_get_<chunk>` functions. These functions should be used when
+accessing/storing the `info_struct` data, rather than manipulating it
+directly, to avoid such problems in the future.
+
+It is important to note that the APIs did not make current programs
+that access the info struct directly incompatible with the new
+library, through libpng-1.2.x. In libpng-1.4.x, which was meant to
+be a transitional release, members of the `png_struct` and the
+`info_struct` can still be accessed, but the compiler will issue a
+warning about deprecated usage. Since libpng-1.5.0, direct access
+to these structs is not allowed, and the definitions of the structs
+reside in private `pngstruct.h` and `pnginfo.h` header files that are
+not accessible to applications. It is strongly suggested that new
+programs use the new APIs (as shown in `example.c` and `pngtest.c`),
+and older programs be converted to the new format, to facilitate
+upgrades in the future.
+
+The additions since 0.89 include the ability to read from a PNG stream
+which has had some (or all) of the signature bytes read by the calling
+application. This also allows the reading of embedded PNG streams that
+do not have the PNG file signature. As well, it is now possible to set
+the library action on the detection of chunk CRC errors. It is possible
+to set different actions based on whether the CRC error occurred in a
+critical or an ancillary chunk.
+
+The additions since 0.90 include the ability to compile libpng as a
+Windows DLL, and new APIs for accessing data in the `info_struct`.
+Experimental functions included the ability to set weighting and cost
+factors for row filter selection, direct reads of integers from buffers
+on big-endian processors that support misaligned data access, faster
+methods of doing alpha composition, and more accurate 16-to-8 bit color
+conversion. Some of these experimental functions, such as the weighted
+filter heuristics, have since been removed.
-Files in this distribution:
+Files included in this distribution
+-----------------------------------
ANNOUNCE => Announcement of this version, with recent changes
AUTHORS => List of contributing authors
@@ -144,22 +142,24 @@ Files in this distribution:
pngwrite.c => High-level write functions
pngwtran.c => Write data transformations
pngwutil.c => Write utility functions
- arm/ => Optimized code for the ARM platform
- intel/ => Optimized code for the INTEL-SSE2 platform
- mips/ => Optimized code for the MIPS platform
- powerpc/ => Optimized code for the PowerPC platform
+ arm/ => Optimized code for ARM Neon
+ intel/ => Optimized code for INTEL SSE2
+ loongarch/ => Optimized code for LoongArch LSX
+ mips/ => Optimized code for MIPS MSA and MIPS MMI
+ powerpc/ => Optimized code for PowerPC VSX
ci/ => Scripts for continuous integration
contrib/ => External contributions
arm-neon/ => Optimized code for the ARM-NEON platform
mips-msa/ => Optimized code for the MIPS-MSA platform
powerpc-vsx/ => Optimized code for the POWERPC-VSX platform
- examples/ => Example programs
+ examples/ => Examples of libpng usage
gregbook/ => Source code for PNG reading and writing, from
"PNG: The Definitive Guide" by Greg Roelofs,
O'Reilly, 1999
libtests/ => Test programs
oss-fuzz/ => Files used by the OSS-Fuzz project for fuzz-testing
libpng
+ pngexif/ => Program to inspect the EXIF information in PNG files
pngminim/ => Minimal decoder, encoder, and progressive decoder
programs demonstrating the use of pngusr.dfa
pngminus/ => Simple pnm2png and png2pnm programs
diff --git a/src/3rdparty/libpng/import_from_libpng_tarball.sh b/src/3rdparty/libpng/import_from_libpng_tarball.sh
index d67b7903a6..b1c5d80347 100755
--- a/src/3rdparty/libpng/import_from_libpng_tarball.sh
+++ b/src/3rdparty/libpng/import_from_libpng_tarball.sh
@@ -1,43 +1,8 @@
#! /bin/sh
-#############################################################################
-##
-## Copyright (C) 2017 André Klitzing
-## Contact: https://www.qt.io/licensing/
-##
-## This file is the build configuration utility 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$
-##
-#############################################################################
+# Copyright (C) 2017 André Klitzing
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+#
# This is a small script to copy the required files from a libpng tarball
# into 3rdparty/libpng/
diff --git a/src/3rdparty/libpng/libpng-manual.txt b/src/3rdparty/libpng/libpng-manual.txt
index d856796169..7988057599 100644
--- a/src/3rdparty/libpng/libpng-manual.txt
+++ b/src/3rdparty/libpng/libpng-manual.txt
@@ -1,6 +1,6 @@
libpng-manual.txt - A description on how to use and modify libpng
- Copyright (c) 2018-2022 Cosmin Truta
+ Copyright (c) 2018-2024 Cosmin Truta
Copyright (c) 1998-2018 Glenn Randers-Pehrson
This document is released under the libpng license.
@@ -9,9 +9,9 @@ libpng-manual.txt - A description on how to use and modify libpng
Based on:
- libpng version 1.6.36, December 2018, through 1.6.39 - November 2022
+ libpng version 1.6.36, December 2018, through 1.6.43 - February 2024
Updated and distributed by Cosmin Truta
- Copyright (c) 2018-2022 Cosmin Truta
+ Copyright (c) 2018-2024 Cosmin Truta
libpng versions 0.97, January 1998, through 1.6.35 - July 2018
Updated and distributed by Glenn Randers-Pehrson
@@ -357,7 +357,7 @@ Customizing libpng.
return ERROR;
}
- is_png = !png_sig_cmp(header, 0, number);
+ is_png = (png_sig_cmp(header, 0, number) == 0);
if (!is_png)
{
return NOT_PNG;
@@ -385,8 +385,7 @@ create the structure, so your application should check for that.
if (!info_ptr)
{
- png_destroy_read_struct(&png_ptr,
- (png_infopp)NULL, (png_infopp)NULL);
+ png_destroy_read_struct(&png_ptr, NULL, NULL);
return ERROR;
}
@@ -419,14 +418,13 @@ free any memory.
if (setjmp(png_jmpbuf(png_ptr)))
{
- png_destroy_read_struct(&png_ptr, &info_ptr,
- &end_info);
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
fclose(fp);
return ERROR;
}
-Pass (png_infopp)NULL instead of &end_info if you didn't create
-an end_info structure.
+Pass NULL instead of &end_info if you didn't create an end_info
+structure.
If you would rather avoid the complexity of setjmp/longjmp issues,
you can compile libpng with PNG_NO_SETJMP, in which case
@@ -496,7 +494,7 @@ You can set up a callback function to handle any unknown chunks in the
input stream. You must supply the function
read_chunk_callback(png_structp png_ptr,
- png_unknown_chunkp chunk);
+ png_unknown_chunkp chunk)
{
/* The unknown chunk structure contains your
chunk data, along with similar data for any other
@@ -547,9 +545,9 @@ a progress meter or the like. It's demonstrated in pngtest.c.
You must supply a function
void read_row_callback(png_structp png_ptr,
- png_uint_32 row, int pass);
+ png_uint_32 row, int pass)
{
- /* put your code here */
+ /* put your code here */
}
(You can give it another name that you like instead of "read_row_callback")
@@ -1180,22 +1178,22 @@ where row_pointers is an array of pointers to the pixel data for each row:
If you know your image size and pixel size ahead of time, you can allocate
row_pointers prior to calling png_read_png() with
- if (height > PNG_UINT_32_MAX/(sizeof (png_byte)))
- png_error (png_ptr,
+ if (height > PNG_UINT_32_MAX / (sizeof (png_bytep)))
+ png_error(png_ptr,
"Image is too tall to process in memory");
- if (width > PNG_UINT_32_MAX/pixel_size)
- png_error (png_ptr,
+ if (width > PNG_UINT_32_MAX / pixel_size)
+ png_error(png_ptr,
"Image is too wide to process in memory");
row_pointers = png_malloc(png_ptr,
height*(sizeof (png_bytep)));
- for (int i=0; i<height, i++)
- row_pointers[i]=NULL; /* security precaution */
+ for (int i = 0; i < height, i++)
+ row_pointers[i] = NULL; /* security precaution */
- for (int i=0; i<height, i++)
- row_pointers[i]=png_malloc(png_ptr,
+ for (int i = 0; i < height, i++)
+ row_pointers[i] = png_malloc(png_ptr,
width*pixel_size);
png_set_rows(png_ptr, info_ptr, &row_pointers);
@@ -1205,14 +1203,14 @@ row_pointers[i] to point into the proper places in your block, but first
be sure that your platform is able to allocate such a large buffer:
/* Guard against integer overflow */
- if (height > PNG_SIZE_MAX/(width*pixel_size)) {
- png_error(png_ptr,"image_data buffer would be too large");
- }
+ if (height > PNG_SIZE_MAX/(width*pixel_size))
+ png_error(png_ptr, "image_data buffer would be too large");
- png_bytep buffer=png_malloc(png_ptr,height*width*pixel_size);
+ png_bytep buffer = png_malloc(png_ptr,
+ height*width*pixel_size);
- for (int i=0; i<height, i++)
- row_pointers[i]=buffer+i*width*pixel_size;
+ for (int i = 0; i < height, i++)
+ row_pointers[i] = buffer + i*width*pixel_size;
png_set_rows(png_ptr, info_ptr, &row_pointers);
@@ -1465,25 +1463,24 @@ png_set_rgb_to_gray()).
non-paletted images (PNG_INFO_tRNS)
png_get_eXIf_1(png_ptr, info_ptr, &num_exif, &exif);
- (PNG_INFO_eXIf)
exif - Exif profile (array of png_byte)
+ (PNG_INFO_eXIf)
png_get_hIST(png_ptr, info_ptr, &hist);
- (PNG_INFO_hIST)
hist - histogram of palette (array of
- png_uint_16)
+ png_uint_16) (PNG_INFO_hIST)
png_get_tIME(png_ptr, info_ptr, &mod_time);
mod_time - time image was last modified
- (PNG_VALID_tIME)
+ (PNG_INFO_tIME)
png_get_bKGD(png_ptr, info_ptr, &background);
background - background color (of type
- png_color_16p) (PNG_VALID_bKGD)
+ png_color_16p) (PNG_INFO_bKGD)
valid 16-bit red, green and blue
values, regardless of color_type
@@ -1743,13 +1740,13 @@ grayscale images with bit depths of 2 or 4 or if there is a multiple-image
viewing application that wishes to treat all images in the same way.
if (color_type == PNG_COLOR_TYPE_PALETTE)
- png_set_palette_to_rgb(png_ptr);
+ png_set_palette_to_rgb(png_ptr);
- if (png_get_valid(png_ptr, info_ptr,
- PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr);
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ png_set_tRNS_to_alpha(png_ptr);
- if (color_type == PNG_COLOR_TYPE_GRAY &&
- bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr);
+ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
+ png_set_expand_gray_1_2_4_to_8(png_ptr);
The first two functions are actually aliases for png_set_expand(), added
in libpng version 1.0.4, with the function names expanded to improve code
@@ -1764,18 +1761,20 @@ png_set_expand(); however, the resultant channels have 16 bits rather than 8.
Use this when the output color or gray channels are made linear to avoid fairly
severe accuracy loss.
- if (bit_depth < 16)
- png_set_expand_16(png_ptr);
+ if (bit_depth < 16)
+ png_set_expand_16(png_ptr);
PNG can have files with 16 bits per channel. If you only can handle
8 bits per channel, this will strip the pixels down to 8-bit.
if (bit_depth == 16)
+ {
#if PNG_LIBPNG_VER >= 10504
png_set_scale_16(png_ptr);
#else
png_set_strip_16(png_ptr);
#endif
+ }
(The more accurate "png_set_scale_16()" API became available in libpng version
1.5.4).
@@ -1901,7 +1900,7 @@ Note that png_set_filler() does not change the color type. If you want
to do that, you can add a true alpha channel with
if (color_type == PNG_COLOR_TYPE_RGB ||
- color_type == PNG_COLOR_TYPE_GRAY)
+ color_type == PNG_COLOR_TYPE_GRAY)
png_set_add_alpha(png_ptr, filler, PNG_FILLER_AFTER);
where "filler" contains the alpha value to assign to each pixel.
@@ -1926,7 +1925,7 @@ with alpha.
if (color_type == PNG_COLOR_TYPE_RGB ||
color_type == PNG_COLOR_TYPE_RGB_ALPHA)
png_set_rgb_to_gray(png_ptr, error_action,
- double red_weight, double green_weight);
+ (double)red_weight, (double)green_weight);
error_action = 1: silently do the conversion
@@ -1949,8 +1948,8 @@ In the corresponding fixed point API the red_weight and green_weight values are
simply scaled by 100,000:
png_set_rgb_to_gray(png_ptr, error_action,
- png_fixed_point red_weight,
- png_fixed_point green_weight);
+ (png_fixed_point)red_weight,
+ (png_fixed_point)green_weight);
If you have set error_action = 1 or 2, you can
later check whether the image really was gray, after processing
@@ -2186,9 +2185,8 @@ do your own check for number_of_rows*width*pixel_size if you are using
a multiple-row buffer:
/* Guard against integer overflow */
- if (number_of_rows > PNG_SIZE_MAX/(width*pixel_size)) {
- png_error(png_ptr,"image_data buffer would be too large");
- }
+ if (number_of_rows > PNG_SIZE_MAX/(width*pixel_size))
+ png_error(png_ptr, "image_data buffer would be too large");
Remember: Before you call png_read_update_info(), the png_get_*()
functions return the values corresponding to the original PNG image.
@@ -2408,12 +2406,11 @@ separate.
if (!end_info)
{
- png_destroy_read_struct(&png_ptr, &info_ptr,
- (png_infopp)NULL);
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return ERROR;
}
- png_read_end(png_ptr, end_info);
+ png_read_end(png_ptr, end_info);
If you are not interested, you should still call png_read_end()
but you can pass NULL, avoiding the need to create an end_info structure.
@@ -2421,7 +2418,7 @@ If you do this, libpng will not process any chunks after IDAT other than
skipping over them and perhaps (depending on whether you have called
png_set_crc_action) checking their CRCs while looking for the IEND chunk.
- png_read_end(png_ptr, (png_infop)NULL);
+ png_read_end(png_ptr, NULL);
If you don't call png_read_end(), then your file pointer will be
left pointing to the first chunk after the last IDAT, which is probably
@@ -2430,13 +2427,11 @@ the PNG datastream.
When you are done, you can free all memory allocated by libpng like this:
- png_destroy_read_struct(&png_ptr, &info_ptr,
- &end_info);
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
or, if you didn't create an end_info structure,
- png_destroy_read_struct(&png_ptr, &info_ptr,
- (png_infopp)NULL);
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
It is also possible to individually free the info_ptr members that
point to libpng-allocated storage with the following function:
@@ -2556,15 +2551,13 @@ png_infop info_ptr;
if (!info_ptr)
{
- png_destroy_read_struct(&png_ptr,
- (png_infopp)NULL, (png_infopp)NULL);
+ png_destroy_read_struct(&png_ptr, NULL, NULL);
return ERROR;
}
if (setjmp(png_jmpbuf(png_ptr)))
{
- png_destroy_read_struct(&png_ptr, &info_ptr,
- (png_infopp)NULL);
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return ERROR;
}
@@ -2597,8 +2590,7 @@ png_infop info_ptr;
{
if (setjmp(png_jmpbuf(png_ptr)))
{
- png_destroy_read_struct(&png_ptr, &info_ptr,
- (png_infopp)NULL);
+ png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return ERROR;
}
@@ -2763,8 +2755,7 @@ both "png_ptr"; you can call them anything you like, such as
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
- png_destroy_write_struct(&png_ptr,
- (png_infopp)NULL);
+ png_destroy_write_struct(&png_ptr, NULL);
return ERROR;
}
@@ -2790,7 +2781,7 @@ section below for more information on the libpng error handling.
if (setjmp(png_jmpbuf(png_ptr)))
{
- png_destroy_write_struct(&png_ptr, &info_ptr);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
return ERROR;
}
@@ -2844,9 +2835,9 @@ a progress meter or the like. It's demonstrated in pngtest.c.
You must supply a function
void write_row_callback(png_structp png_ptr, png_uint_32 row,
- int pass);
+ int pass)
{
- /* put your code here */
+ /* put your code here */
}
(You can give it another name that you like instead of "write_row_callback")
@@ -3116,8 +3107,8 @@ width, height, bit_depth, and color_type must be the same in each call.
png_set_eXIf_1(png_ptr, info_ptr, num_exif, exif);
- exif - Exif profile (array of
- png_byte) (PNG_INFO_eXIf)
+ exif - Exif profile (array of png_byte)
+ (PNG_INFO_eXIf)
png_set_hIST(png_ptr, info_ptr, hist);
@@ -3127,12 +3118,12 @@ width, height, bit_depth, and color_type must be the same in each call.
png_set_tIME(png_ptr, info_ptr, mod_time);
mod_time - time image was last modified
- (PNG_VALID_tIME)
+ (PNG_INFO_tIME)
png_set_bKGD(png_ptr, info_ptr, background);
background - background color (of type
- png_color_16p) (PNG_VALID_bKGD)
+ png_color_16p) (PNG_INFO_bKGD)
png_set_text(png_ptr, info_ptr, text_ptr, num_text);
@@ -4218,7 +4209,7 @@ png_create_read_struct_2() or png_create_write_struct_2() to register your
own functions as described above. These functions also provide a void
pointer that can be retrieved via
- mem_ptr=png_get_mem_ptr(png_ptr);
+ mem_ptr = png_get_mem_ptr(png_ptr);
Your replacement memory functions must have prototypes as follows:
@@ -4515,7 +4506,7 @@ When PNG_DEBUG is defined but is zero, the macros aren't defined, but you
can still use PNG_DEBUG to control your own debugging:
#ifdef PNG_DEBUG
- fprintf(stderr, ...
+ fprintf(stderr, ...);
#endif
When PNG_DEBUG = 1, the macros are defined, but only png_debug statements
@@ -4692,7 +4683,7 @@ deprecated since libpng-1.0.16 and libpng-1.2.6.
The function
png_check_sig(sig, num)
was replaced with
- !png_sig_cmp(sig, 0, num)
+ png_sig_cmp(sig, 0, num) == 0
It has been deprecated since libpng-0.90.
The function
@@ -4756,8 +4747,8 @@ png_get_mmx_bitdepth_threshold(), png_get_mmx_rowbytes_threshold(),
png_set_asm_flags(), and png_mmx_supported()
We removed the obsolete png_check_sig(), png_memcpy_check(), and
-png_memset_check() functions. Instead use !png_sig_cmp(), memcpy(),
-and memset(), respectively.
+png_memset_check() functions. Instead use png_sig_cmp() == 0,
+memcpy(), and memset(), respectively.
The function png_set_gray_1_2_4_to_8() was removed. It has been
deprecated since libpng-1.0.18 and 1.2.9, when it was replaced with
@@ -5239,7 +5230,7 @@ changed, and is unaffected by conditional compilation macros. It is the
best choice for use in configure scripts for detecting the presence of any
libpng version since 0.88. In an autoconf "configure.in" you could use
- AC_CHECK_LIB(png, png_get_io_ptr, ...
+ AC_CHECK_LIB(png, png_get_io_ptr, ...)
XV. Source code repository
@@ -5248,12 +5239,12 @@ control. The git repository was built from old libpng-x.y.z.tar.gz files
going back to version 0.70. You can access the git repository (read only)
at
- https://github.com/glennrp/libpng or
+ https://github.com/pnggroup/libpng or
https://git.code.sf.net/p/libpng/code.git
or you can browse it with a web browser at
- https://github.com/glennrp/libpng or
+ https://github.com/pnggroup/libpng or
https://sourceforge.net/p/libpng/code/ci/libpng16/tree/
Patches can be sent to png-mng-implement at lists.sourceforge.net or
@@ -5263,7 +5254,7 @@ uploaded to the libpng bug tracker at
or as a "pull request" to
- https://github.com/glennrp/libpng/pulls
+ https://github.com/pnggroup/libpng/pulls
We also accept patches built from the tar or zip distributions, and
simple verbal descriptions of bug fixes, reported either to the
diff --git a/src/3rdparty/libpng/png.c b/src/3rdparty/libpng/png.c
index 4f3e8bbd31..9ed3157009 100644
--- a/src/3rdparty/libpng/png.c
+++ b/src/3rdparty/libpng/png.c
@@ -1,7 +1,7 @@
/* png.c - location for general purpose libpng functions
*
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -14,27 +14,7 @@
#include "pngpriv.h"
/* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_39 Your_png_h_is_not_version_1_6_39;
-
-#ifdef __GNUC__
-/* The version tests may need to be added to, but the problem warning has
- * consistently been fixed in GCC versions which obtain wide-spread release.
- * The problem is that many versions of GCC rearrange comparison expressions in
- * the optimizer in such a way that the results of the comparison will change
- * if signed integer overflow occurs. Such comparisons are not permitted in
- * ANSI C90, however GCC isn't clever enough to work out that that do not occur
- * below in png_ascii_from_fp and png_muldiv, so it produces a warning with
- * -Wextra. Unfortunately this is highly dependent on the optimizer and the
- * machine architecture so the warning comes and goes unpredictably and is
- * impossible to "fix", even were that a good idea.
- */
-#if __GNUC__ == 7 && __GNUC_MINOR__ == 1
-#define GCC_STRICT_OVERFLOW 1
-#endif /* GNU 7.1.x */
-#endif /* GNU */
-#ifndef GCC_STRICT_OVERFLOW
-#define GCC_STRICT_OVERFLOW 0
-#endif
+typedef png_libpng_version_1_6_43 Your_png_h_is_not_version_1_6_43;
/* Tells libpng that we have already handled the first "num_bytes" bytes
* of the PNG file signature. If the PNG data is embedded into another
@@ -73,21 +53,21 @@ png_set_sig_bytes(png_structrp png_ptr, int num_bytes)
int PNGAPI
png_sig_cmp(png_const_bytep sig, size_t start, size_t num_to_check)
{
- png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
+ static const png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
if (num_to_check > 8)
num_to_check = 8;
else if (num_to_check < 1)
- return (-1);
+ return -1;
if (start > 7)
- return (-1);
+ return -1;
if (start + num_to_check > 8)
num_to_check = 8 - start;
- return ((int)(memcmp(&sig[start], &png_signature[start], num_to_check)));
+ return memcmp(&sig[start], &png_signature[start], num_to_check);
}
#endif /* READ */
@@ -447,7 +427,6 @@ png_info_init_3,(png_infopp ptr_ptr, size_t png_info_struct_size),
memset(info_ptr, 0, (sizeof *info_ptr));
}
-/* The following API is not called internally */
void PNGAPI
png_data_freer(png_const_structrp png_ptr, png_inforp info_ptr,
int freer, png_uint_32 mask)
@@ -686,9 +665,9 @@ png_voidp PNGAPI
png_get_io_ptr(png_const_structrp png_ptr)
{
if (png_ptr == NULL)
- return (NULL);
+ return NULL;
- return (png_ptr->io_ptr);
+ return png_ptr->io_ptr;
}
#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
@@ -752,7 +731,7 @@ png_convert_to_rfc1123_buffer(char out[29], png_const_timep ptime)
{
size_t pos = 0;
- char number_buf[5]; /* enough for a four-digit year */
+ char number_buf[5] = {0, 0, 0, 0, 0}; /* enough for a four-digit year */
# define APPEND_STRING(string) pos = png_safecat(out, 29, pos, (string))
# define APPEND_NUMBER(format, value)\
@@ -815,8 +794,8 @@ png_get_copyright(png_const_structrp png_ptr)
return PNG_STRING_COPYRIGHT
#else
return PNG_STRING_NEWLINE \
- "libpng version 1.6.39" PNG_STRING_NEWLINE \
- "Copyright (c) 2018-2022 Cosmin Truta" PNG_STRING_NEWLINE \
+ "libpng version 1.6.43" PNG_STRING_NEWLINE \
+ "Copyright (c) 2018-2024 Cosmin Truta" PNG_STRING_NEWLINE \
"Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
PNG_STRING_NEWLINE \
"Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
@@ -977,7 +956,7 @@ png_reset_zstream(png_structrp png_ptr)
return Z_STREAM_ERROR;
/* WARNING: this resets the window bits to the maximum! */
- return (inflateReset(&png_ptr->zstream));
+ return inflateReset(&png_ptr->zstream);
}
#endif /* READ */
@@ -986,7 +965,7 @@ png_uint_32 PNGAPI
png_access_version_number(void)
{
/* Version of *.c files used when building libpng */
- return((png_uint_32)PNG_LIBPNG_VER);
+ return (png_uint_32)PNG_LIBPNG_VER;
}
#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
@@ -1842,14 +1821,14 @@ png_icc_profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace,
}
# ifdef PNG_WARNINGS_SUPPORTED
else
- {
- char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114 */
+ {
+ char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114 */
- pos = png_safecat(message, (sizeof message), pos,
- png_format_number(number, number+(sizeof number),
- PNG_NUMBER_FORMAT_x, value));
- pos = png_safecat(message, (sizeof message), pos, "h: "); /* +2 = 116 */
- }
+ pos = png_safecat(message, (sizeof message), pos,
+ png_format_number(number, number+(sizeof number),
+ PNG_NUMBER_FORMAT_x, value));
+ pos = png_safecat(message, (sizeof message), pos, "h: "); /* +2 = 116 */
+ }
# endif
/* The 'reason' is an arbitrary message, allow +79 maximum 195 */
pos = png_safecat(message, (sizeof message), pos, reason);
@@ -2532,17 +2511,6 @@ png_colorspace_set_rgb_coefficients(png_structrp png_ptr)
#endif /* COLORSPACE */
-#ifdef __GNUC__
-/* This exists solely to work round a warning from GNU C. */
-static int /* PRIVATE */
-png_gt(size_t a, size_t b)
-{
- return a > b;
-}
-#else
-# define png_gt(a,b) ((a) > (b))
-#endif
-
void /* PRIVATE */
png_check_IHDR(png_const_structrp png_ptr,
png_uint_32 width, png_uint_32 height, int bit_depth,
@@ -2564,8 +2532,16 @@ png_check_IHDR(png_const_structrp png_ptr,
error = 1;
}
- if (png_gt(((width + 7) & (~7U)),
- ((PNG_SIZE_MAX
+ /* The bit mask on the first line below must be at least as big as a
+ * png_uint_32. "~7U" is not adequate on 16-bit systems because it will
+ * be an unsigned 16-bit value. Casting to (png_alloc_size_t) makes the
+ * type of the result at least as bit (in bits) as the RHS of the > operator
+ * which also avoids a common warning on 64-bit systems that the comparison
+ * of (png_uint_32) against the constant value on the RHS will always be
+ * false.
+ */
+ if (((width + 7) & ~(png_alloc_size_t)7) >
+ (((PNG_SIZE_MAX
- 48 /* big_row_buf hack */
- 1) /* filter byte */
/ 8) /* 8-byte RGBA pixels */
@@ -2891,14 +2867,6 @@ png_pow10(int power)
/* Function to format a floating point value in ASCII with a given
* precision.
*/
-#if GCC_STRICT_OVERFLOW
-#pragma GCC diagnostic push
-/* The problem arises below with exp_b10, which can never overflow because it
- * comes, originally, from frexp and is therefore limited to a range which is
- * typically +/-710 (log2(DBL_MAX)/log2(DBL_MIN)).
- */
-#pragma GCC diagnostic warning "-Wstrict-overflow=2"
-#endif /* GCC_STRICT_OVERFLOW */
void /* PRIVATE */
png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size,
double fp, unsigned int precision)
@@ -3220,10 +3188,6 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size,
/* Here on buffer too small. */
png_error(png_ptr, "ASCII conversion buffer too small");
}
-#if GCC_STRICT_OVERFLOW
-#pragma GCC diagnostic pop
-#endif /* GCC_STRICT_OVERFLOW */
-
# endif /* FLOATING_POINT */
# ifdef PNG_FIXED_POINT_SUPPORTED
@@ -3251,7 +3215,7 @@ png_ascii_from_fixed(png_const_structrp png_ptr, png_charp ascii,
if (num <= 0x80000000) /* else overflowed */
{
unsigned int ndigits = 0, first = 16 /* flag value */;
- char digits[10];
+ char digits[10] = {0};
while (num)
{
@@ -3336,15 +3300,6 @@ png_fixed(png_const_structrp png_ptr, double fp, png_const_charp text)
* the nearest .00001). Overflow and divide by zero are signalled in
* the result, a boolean - true on success, false on overflow.
*/
-#if GCC_STRICT_OVERFLOW /* from above */
-/* It is not obvious which comparison below gets optimized in such a way that
- * signed overflow would change the result; looking through the code does not
- * reveal any tests which have the form GCC complains about, so presumably the
- * optimizer is moving an add or subtract into the 'if' somewhere.
- */
-#pragma GCC diagnostic push
-#pragma GCC diagnostic warning "-Wstrict-overflow=2"
-#endif /* GCC_STRICT_OVERFLOW */
int
png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,
png_int_32 divisor)
@@ -3459,9 +3414,6 @@ png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,
return 0;
}
-#if GCC_STRICT_OVERFLOW
-#pragma GCC diagnostic pop
-#endif /* GCC_STRICT_OVERFLOW */
#endif /* READ_GAMMA || INCH_CONVERSIONS */
#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED)
diff --git a/src/3rdparty/libpng/png.h b/src/3rdparty/libpng/png.h
index f109cdf336..83d3903126 100644
--- a/src/3rdparty/libpng/png.h
+++ b/src/3rdparty/libpng/png.h
@@ -1,9 +1,9 @@
/* png.h - header file for PNG reference library
*
- * libpng version 1.6.39 - November 20, 2022
+ * libpng version 1.6.43
*
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -15,7 +15,7 @@
* libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
* libpng versions 0.97, January 1998, through 1.6.35, July 2018:
* Glenn Randers-Pehrson
- * libpng versions 1.6.36, December 2018, through 1.6.39, November 2022:
+ * libpng versions 1.6.36, December 2018, through 1.6.43, February 2024:
* Cosmin Truta
* See also "Contributing Authors", below.
*/
@@ -27,8 +27,8 @@
* PNG Reference Library License version 2
* ---------------------------------------
*
- * * Copyright (c) 1995-2022 The PNG Reference Library Authors.
- * * Copyright (c) 2018-2022 Cosmin Truta.
+ * * Copyright (c) 1995-2024 The PNG Reference Library Authors.
+ * * Copyright (c) 2018-2024 Cosmin Truta.
* * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
* * Copyright (c) 1996-1997 Andreas Dilger.
* * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -239,7 +239,7 @@
* ...
* 1.5.30 15 10530 15.so.15.30[.0]
* ...
- * 1.6.39 16 10639 16.so.16.39[.0]
+ * 1.6.43 16 10643 16.so.16.43[.0]
*
* Henceforth the source version will match the shared-library major and
* minor numbers; the shared-library major version number will be used for
@@ -255,9 +255,6 @@
* to the info_ptr or png_ptr members through png.h, and the compiled
* application is loaded with a different version of the library.
*
- * DLLNUM will change each time there are forward or backward changes
- * in binary compatibility (e.g., when a new feature is added).
- *
* See libpng.txt or libpng.3 for more information. The PNG specification
* is available as a W3C Recommendation and as an ISO/IEC Standard; see
* <https://www.w3.org/TR/2003/REC-PNG-20031110/>
@@ -278,19 +275,21 @@
*/
/* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.39"
-#define PNG_HEADER_VERSION_STRING " libpng version 1.6.39 - November 20, 2022\n"
+#define PNG_LIBPNG_VER_STRING "1.6.43"
+#define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n"
-#define PNG_LIBPNG_VER_SONUM 16
-#define PNG_LIBPNG_VER_DLLNUM 16
+/* The versions of shared library builds should stay in sync, going forward */
+#define PNG_LIBPNG_VER_SHAREDLIB 16
+#define PNG_LIBPNG_VER_SONUM PNG_LIBPNG_VER_SHAREDLIB /* [Deprecated] */
+#define PNG_LIBPNG_VER_DLLNUM PNG_LIBPNG_VER_SHAREDLIB /* [Deprecated] */
/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
#define PNG_LIBPNG_VER_MAJOR 1
#define PNG_LIBPNG_VER_MINOR 6
-#define PNG_LIBPNG_VER_RELEASE 39
+#define PNG_LIBPNG_VER_RELEASE 43
/* This should be zero for a public release, or non-zero for a
- * development version. [Deprecated]
+ * development version.
*/
#define PNG_LIBPNG_VER_BUILD 0
@@ -318,7 +317,7 @@
* From version 1.0.1 it is:
* XXYYZZ, where XX=major, YY=minor, ZZ=release
*/
-#define PNG_LIBPNG_VER 10639 /* 1.6.39 */
+#define PNG_LIBPNG_VER 10643 /* 1.6.43 */
/* Library configuration: these options cannot be changed after
* the library has been built.
@@ -428,7 +427,7 @@ extern "C" {
/* This triggers a compiler error in png.c, if png.c and png.h
* do not agree upon the version number.
*/
-typedef char* png_libpng_version_1_6_39;
+typedef char* png_libpng_version_1_6_43;
/* Basic control structions. Read libpng-manual.txt or libpng.3 for more info.
*
@@ -849,7 +848,7 @@ PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)), typedef);
#define PNG_TRANSFORM_GRAY_TO_RGB 0x2000 /* read only */
/* Added to libpng-1.5.4 */
#define PNG_TRANSFORM_EXPAND_16 0x4000 /* read only */
-#if INT_MAX >= 0x8000 /* else this might break */
+#if ~0U > 0xffffU /* or else this might break on a 16-bit machine */
#define PNG_TRANSFORM_SCALE_16 0x8000 /* read only */
#endif
@@ -908,15 +907,15 @@ PNG_EXPORT(2, void, png_set_sig_bytes, (png_structrp png_ptr, int num_bytes));
/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a
* PNG file. Returns zero if the supplied bytes match the 8-byte PNG
* signature, and non-zero otherwise. Having num_to_check == 0 or
- * start > 7 will always fail (ie return non-zero).
+ * start > 7 will always fail (i.e. return non-zero).
*/
PNG_EXPORT(3, int, png_sig_cmp, (png_const_bytep sig, size_t start,
size_t num_to_check));
/* Simple signature checking function. This is the same as calling
- * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n).
+ * png_check_sig(sig, n) := (png_sig_cmp(sig, 0, n) == 0).
*/
-#define png_check_sig(sig, n) !png_sig_cmp((sig), 0, (n))
+#define png_check_sig(sig, n) (png_sig_cmp((sig), 0, (n)) == 0) /* DEPRECATED */
/* Allocate and initialize png_ptr struct for reading, and any other memory. */
PNG_EXPORTA(4, png_structp, png_create_read_struct,
@@ -1730,12 +1729,9 @@ PNG_EXPORT(97, void, png_free, (png_const_structrp png_ptr, png_voidp ptr));
PNG_EXPORT(98, void, png_free_data, (png_const_structrp png_ptr,
png_inforp info_ptr, png_uint_32 free_me, int num));
-/* Reassign responsibility for freeing existing data, whether allocated
+/* Reassign the responsibility for freeing existing data, whether allocated
* by libpng or by the application; this works on the png_info structure passed
- * in, it does not change the state for other png_info structures.
- *
- * It is unlikely that this function works correctly as of 1.6.0 and using it
- * may result either in memory leaks or double free of allocated data.
+ * in, without changing the state for other png_info structures.
*/
PNG_EXPORT(99, void, png_data_freer, (png_const_structrp png_ptr,
png_inforp info_ptr, int freer, png_uint_32 mask));
@@ -3207,11 +3203,18 @@ PNG_EXPORT(245, int, png_image_write_to_memory, (png_imagep image, void *memory,
#ifdef PNG_MIPS_MSA_API_SUPPORTED
# define PNG_MIPS_MSA 6 /* HARDWARE: MIPS Msa SIMD instructions supported */
#endif
-#define PNG_IGNORE_ADLER32 8
+#ifdef PNG_DISABLE_ADLER32_CHECK_SUPPORTED
+# define PNG_IGNORE_ADLER32 8 /* SOFTWARE: disable Adler32 check on IDAT */
+#endif
#ifdef PNG_POWERPC_VSX_API_SUPPORTED
-# define PNG_POWERPC_VSX 10 /* HARDWARE: PowerPC VSX SIMD instructions supported */
+# define PNG_POWERPC_VSX 10 /* HARDWARE: PowerPC VSX SIMD instructions
+ * supported */
#endif
-#define PNG_OPTION_NEXT 12 /* Next option - numbers must be even */
+#ifdef PNG_MIPS_MMI_API_SUPPORTED
+# define PNG_MIPS_MMI 12 /* HARDWARE: MIPS MMI SIMD instructions supported */
+#endif
+
+#define PNG_OPTION_NEXT 14 /* Next option - numbers must be even */
/* Return values: NOTE: there are four values and 'off' is *not* zero */
#define PNG_OPTION_UNSET 0 /* Unset - defaults to off */
diff --git a/src/3rdparty/libpng/pngconf.h b/src/3rdparty/libpng/pngconf.h
index fcb4b43069..000d7b1a8a 100644
--- a/src/3rdparty/libpng/pngconf.h
+++ b/src/3rdparty/libpng/pngconf.h
@@ -1,9 +1,9 @@
/* pngconf.h - machine-configurable file for libpng
*
- * libpng version 1.6.39
+ * libpng version 1.6.43
*
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
diff --git a/src/3rdparty/libpng/pngerror.c b/src/3rdparty/libpng/pngerror.c
index ec3a709b9d..29ebda7943 100644
--- a/src/3rdparty/libpng/pngerror.c
+++ b/src/3rdparty/libpng/pngerror.c
@@ -1,7 +1,7 @@
/* pngerror.c - stub functions for i/o and memory allocation
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -255,7 +255,7 @@ void
png_warning_parameter_unsigned(png_warning_parameters p, int number, int format,
png_alloc_size_t value)
{
- char buffer[PNG_NUMBER_BUFFER_SIZE];
+ char buffer[PNG_NUMBER_BUFFER_SIZE] = {0};
png_warning_parameter(p, number, PNG_FORMAT_NUMBER(buffer, format, value));
}
@@ -265,7 +265,7 @@ png_warning_parameter_signed(png_warning_parameters p, int number, int format,
{
png_alloc_size_t u;
png_charp str;
- char buffer[PNG_NUMBER_BUFFER_SIZE];
+ char buffer[PNG_NUMBER_BUFFER_SIZE] = {0};
/* Avoid overflow by doing the negate in a png_alloc_size_t: */
u = (png_alloc_size_t)value;
@@ -858,7 +858,7 @@ png_get_error_ptr(png_const_structrp png_ptr)
if (png_ptr == NULL)
return NULL;
- return ((png_voidp)png_ptr->error_ptr);
+ return (png_voidp)png_ptr->error_ptr;
}
@@ -933,31 +933,25 @@ png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message)
#endif
int /* PRIVATE */
-png_safe_execute(png_imagep image_in, int (*function)(png_voidp), png_voidp arg)
+png_safe_execute(png_imagep image, int (*function)(png_voidp), png_voidp arg)
{
- volatile png_imagep image = image_in;
- volatile int result;
- volatile png_voidp saved_error_buf;
+ png_voidp saved_error_buf = image->opaque->error_buf;
jmp_buf safe_jmpbuf;
+ int result;
- /* Safely execute function(arg) with png_error returning to this function. */
- saved_error_buf = image->opaque->error_buf;
- result = setjmp(safe_jmpbuf) == 0;
-
- if (result != 0)
+ /* Safely execute function(arg), with png_error returning back here. */
+ if (setjmp(safe_jmpbuf) == 0)
{
-
image->opaque->error_buf = safe_jmpbuf;
result = function(arg);
+ image->opaque->error_buf = saved_error_buf;
+ return result;
}
+ /* On png_error, return via longjmp, pop the jmpbuf, and free the image. */
image->opaque->error_buf = saved_error_buf;
-
- /* And do the cleanup prior to any failure return. */
- if (result == 0)
- png_image_free(image);
-
- return result;
+ png_image_free(image);
+ return 0;
}
#endif /* SIMPLIFIED READ || SIMPLIFIED_WRITE */
#endif /* READ || WRITE */
diff --git a/src/3rdparty/libpng/pngget.c b/src/3rdparty/libpng/pngget.c
index e44933c0d2..1084b268ff 100644
--- a/src/3rdparty/libpng/pngget.c
+++ b/src/3rdparty/libpng/pngget.c
@@ -1,7 +1,7 @@
/* pngget.c - retrieval of values from info struct
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -21,18 +21,29 @@ png_get_valid(png_const_structrp png_ptr, png_const_inforp info_ptr,
png_uint_32 flag)
{
if (png_ptr != NULL && info_ptr != NULL)
- return(info_ptr->valid & flag);
+ {
+#ifdef PNG_READ_tRNS_SUPPORTED
+ /* png_handle_PLTE() may have canceled a valid tRNS chunk but left the
+ * 'valid' flag for the detection of duplicate chunks. Do not report a
+ * valid tRNS chunk in this case.
+ */
+ if (flag == PNG_INFO_tRNS && png_ptr->num_trans == 0)
+ return 0;
+#endif
- return(0);
+ return info_ptr->valid & flag;
+ }
+
+ return 0;
}
size_t PNGAPI
png_get_rowbytes(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
- return(info_ptr->rowbytes);
+ return info_ptr->rowbytes;
- return(0);
+ return 0;
}
#ifdef PNG_INFO_IMAGE_SUPPORTED
@@ -40,9 +51,9 @@ png_bytepp PNGAPI
png_get_rows(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
- return(info_ptr->row_pointers);
+ return info_ptr->row_pointers;
- return(0);
+ return 0;
}
#endif
@@ -54,7 +65,7 @@ png_get_image_width(png_const_structrp png_ptr, png_const_inforp info_ptr)
if (png_ptr != NULL && info_ptr != NULL)
return info_ptr->width;
- return (0);
+ return 0;
}
png_uint_32 PNGAPI
@@ -63,7 +74,7 @@ png_get_image_height(png_const_structrp png_ptr, png_const_inforp info_ptr)
if (png_ptr != NULL && info_ptr != NULL)
return info_ptr->height;
- return (0);
+ return 0;
}
png_byte PNGAPI
@@ -72,7 +83,7 @@ png_get_bit_depth(png_const_structrp png_ptr, png_const_inforp info_ptr)
if (png_ptr != NULL && info_ptr != NULL)
return info_ptr->bit_depth;
- return (0);
+ return 0;
}
png_byte PNGAPI
@@ -81,7 +92,7 @@ png_get_color_type(png_const_structrp png_ptr, png_const_inforp info_ptr)
if (png_ptr != NULL && info_ptr != NULL)
return info_ptr->color_type;
- return (0);
+ return 0;
}
png_byte PNGAPI
@@ -90,7 +101,7 @@ png_get_filter_type(png_const_structrp png_ptr, png_const_inforp info_ptr)
if (png_ptr != NULL && info_ptr != NULL)
return info_ptr->filter_type;
- return (0);
+ return 0;
}
png_byte PNGAPI
@@ -99,7 +110,7 @@ png_get_interlace_type(png_const_structrp png_ptr, png_const_inforp info_ptr)
if (png_ptr != NULL && info_ptr != NULL)
return info_ptr->interlace_type;
- return (0);
+ return 0;
}
png_byte PNGAPI
@@ -108,7 +119,7 @@ png_get_compression_type(png_const_structrp png_ptr, png_const_inforp info_ptr)
if (png_ptr != NULL && info_ptr != NULL)
return info_ptr->compression_type;
- return (0);
+ return 0;
}
png_uint_32 PNGAPI
@@ -116,21 +127,20 @@ png_get_x_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp
info_ptr)
{
#ifdef PNG_pHYs_SUPPORTED
+ png_debug(1, "in png_get_x_pixels_per_meter");
+
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_pHYs) != 0)
- {
- png_debug1(1, "in %s retrieval function",
- "png_get_x_pixels_per_meter");
-
- if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER)
- return (info_ptr->x_pixels_per_unit);
- }
+ {
+ if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER)
+ return info_ptr->x_pixels_per_unit;
+ }
#else
PNG_UNUSED(png_ptr)
PNG_UNUSED(info_ptr)
#endif
- return (0);
+ return 0;
}
png_uint_32 PNGAPI
@@ -138,42 +148,41 @@ png_get_y_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp
info_ptr)
{
#ifdef PNG_pHYs_SUPPORTED
+ png_debug(1, "in png_get_y_pixels_per_meter");
+
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_pHYs) != 0)
{
- png_debug1(1, "in %s retrieval function",
- "png_get_y_pixels_per_meter");
-
if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER)
- return (info_ptr->y_pixels_per_unit);
+ return info_ptr->y_pixels_per_unit;
}
#else
PNG_UNUSED(png_ptr)
PNG_UNUSED(info_ptr)
#endif
- return (0);
+ return 0;
}
png_uint_32 PNGAPI
png_get_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
#ifdef PNG_pHYs_SUPPORTED
+ png_debug(1, "in png_get_pixels_per_meter");
+
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_pHYs) != 0)
{
- png_debug1(1, "in %s retrieval function", "png_get_pixels_per_meter");
-
if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER &&
info_ptr->x_pixels_per_unit == info_ptr->y_pixels_per_unit)
- return (info_ptr->x_pixels_per_unit);
+ return info_ptr->x_pixels_per_unit;
}
#else
PNG_UNUSED(png_ptr)
PNG_UNUSED(info_ptr)
#endif
- return (0);
+ return 0;
}
#ifdef PNG_FLOATING_POINT_SUPPORTED
@@ -182,21 +191,21 @@ png_get_pixel_aspect_ratio(png_const_structrp png_ptr, png_const_inforp
info_ptr)
{
#ifdef PNG_READ_pHYs_SUPPORTED
+ png_debug(1, "in png_get_pixel_aspect_ratio");
+
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_pHYs) != 0)
{
- png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio");
-
if (info_ptr->x_pixels_per_unit != 0)
- return ((float)((float)info_ptr->y_pixels_per_unit
- /(float)info_ptr->x_pixels_per_unit));
+ return (float)info_ptr->y_pixels_per_unit
+ / (float)info_ptr->x_pixels_per_unit;
}
#else
PNG_UNUSED(png_ptr)
PNG_UNUSED(info_ptr)
#endif
- return ((float)0.0);
+ return (float)0.0;
}
#endif
@@ -206,6 +215,8 @@ png_get_pixel_aspect_ratio_fixed(png_const_structrp png_ptr,
png_const_inforp info_ptr)
{
#ifdef PNG_READ_pHYs_SUPPORTED
+ png_debug(1, "in png_get_pixel_aspect_ratio_fixed");
+
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_pHYs) != 0 &&
info_ptr->x_pixels_per_unit > 0 && info_ptr->y_pixels_per_unit > 0 &&
@@ -214,8 +225,6 @@ png_get_pixel_aspect_ratio_fixed(png_const_structrp png_ptr,
{
png_fixed_point res;
- png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio_fixed");
-
/* The following casts work because a PNG 4 byte integer only has a valid
* range of 0..2^31-1; otherwise the cast might overflow.
*/
@@ -236,80 +245,80 @@ png_int_32 PNGAPI
png_get_x_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
#ifdef PNG_oFFs_SUPPORTED
+ png_debug(1, "in png_get_x_offset_microns");
+
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_oFFs) != 0)
{
- png_debug1(1, "in %s retrieval function", "png_get_x_offset_microns");
-
if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER)
- return (info_ptr->x_offset);
+ return info_ptr->x_offset;
}
#else
PNG_UNUSED(png_ptr)
PNG_UNUSED(info_ptr)
#endif
- return (0);
+ return 0;
}
png_int_32 PNGAPI
png_get_y_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
#ifdef PNG_oFFs_SUPPORTED
+ png_debug(1, "in png_get_y_offset_microns");
+
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_oFFs) != 0)
{
- png_debug1(1, "in %s retrieval function", "png_get_y_offset_microns");
-
if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER)
- return (info_ptr->y_offset);
+ return info_ptr->y_offset;
}
#else
PNG_UNUSED(png_ptr)
PNG_UNUSED(info_ptr)
#endif
- return (0);
+ return 0;
}
png_int_32 PNGAPI
png_get_x_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
#ifdef PNG_oFFs_SUPPORTED
+ png_debug(1, "in png_get_x_offset_pixels");
+
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_oFFs) != 0)
{
- png_debug1(1, "in %s retrieval function", "png_get_x_offset_pixels");
-
if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL)
- return (info_ptr->x_offset);
+ return info_ptr->x_offset;
}
#else
PNG_UNUSED(png_ptr)
PNG_UNUSED(info_ptr)
#endif
- return (0);
+ return 0;
}
png_int_32 PNGAPI
png_get_y_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
#ifdef PNG_oFFs_SUPPORTED
+ png_debug(1, "in png_get_y_offset_pixels");
+
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_oFFs) != 0)
{
- png_debug1(1, "in %s retrieval function", "png_get_y_offset_pixels");
-
if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL)
- return (info_ptr->y_offset);
+ return info_ptr->y_offset;
}
#else
PNG_UNUSED(png_ptr)
PNG_UNUSED(info_ptr)
#endif
- return (0);
+ return 0;
}
#ifdef PNG_INCH_CONVERSIONS_SUPPORTED
@@ -423,11 +432,11 @@ png_get_pHYs_dpi(png_const_structrp png_ptr, png_const_inforp info_ptr,
{
png_uint_32 retval = 0;
+ png_debug1(1, "in %s retrieval function", "pHYs");
+
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_pHYs) != 0)
{
- png_debug1(1, "in %s retrieval function", "pHYs");
-
if (res_x != NULL)
{
*res_x = info_ptr->x_pixels_per_unit;
@@ -453,7 +462,7 @@ png_get_pHYs_dpi(png_const_structrp png_ptr, png_const_inforp info_ptr,
}
}
- return (retval);
+ return retval;
}
#endif /* pHYs */
#endif /* INCH_CONVERSIONS */
@@ -467,9 +476,9 @@ png_byte PNGAPI
png_get_channels(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
- return(info_ptr->channels);
+ return info_ptr->channels;
- return (0);
+ return 0;
}
#ifdef PNG_READ_SUPPORTED
@@ -477,9 +486,9 @@ png_const_bytep PNGAPI
png_get_signature(png_const_structrp png_ptr, png_const_inforp info_ptr)
{
if (png_ptr != NULL && info_ptr != NULL)
- return(info_ptr->signature);
+ return info_ptr->signature;
- return (NULL);
+ return NULL;
}
#endif
@@ -488,17 +497,17 @@ png_uint_32 PNGAPI
png_get_bKGD(png_const_structrp png_ptr, png_inforp info_ptr,
png_color_16p *background)
{
+ png_debug1(1, "in %s retrieval function", "bKGD");
+
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_bKGD) != 0 &&
background != NULL)
{
- png_debug1(1, "in %s retrieval function", "bKGD");
-
*background = &(info_ptr->background);
- return (PNG_INFO_bKGD);
+ return PNG_INFO_bKGD;
}
- return (0);
+ return 0;
}
#endif
@@ -513,6 +522,8 @@ png_get_cHRM(png_const_structrp png_ptr, png_const_inforp info_ptr,
double *white_x, double *white_y, double *red_x, double *red_y,
double *green_x, double *green_y, double *blue_x, double *blue_y)
{
+ png_debug1(1, "in %s retrieval function", "cHRM");
+
/* Quiet API change: this code used to only return the end points if a cHRM
* chunk was present, but the end points can also come from iCCP or sRGB
* chunks, so in 1.6.0 the png_get_ APIs return the end points regardless and
@@ -522,8 +533,6 @@ png_get_cHRM(png_const_structrp png_ptr, png_const_inforp info_ptr,
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
{
- png_debug1(1, "in %s retrieval function", "cHRM");
-
if (white_x != NULL)
*white_x = png_float(png_ptr,
info_ptr->colorspace.end_points_xy.whitex, "cHRM white X");
@@ -548,10 +557,10 @@ png_get_cHRM(png_const_structrp png_ptr, png_const_inforp info_ptr,
if (blue_y != NULL)
*blue_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluey,
"cHRM blue Y");
- return (PNG_INFO_cHRM);
+ return PNG_INFO_cHRM;
}
- return (0);
+ return 0;
}
png_uint_32 PNGAPI
@@ -560,11 +569,11 @@ png_get_cHRM_XYZ(png_const_structrp png_ptr, png_const_inforp info_ptr,
double *green_Y, double *green_Z, double *blue_X, double *blue_Y,
double *blue_Z)
{
+ png_debug1(1, "in %s retrieval function", "cHRM_XYZ(float)");
+
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
{
- png_debug1(1, "in %s retrieval function", "cHRM_XYZ(float)");
-
if (red_X != NULL)
*red_X = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_X,
"cHRM red X");
@@ -592,10 +601,10 @@ png_get_cHRM_XYZ(png_const_structrp png_ptr, png_const_inforp info_ptr,
if (blue_Z != NULL)
*blue_Z = png_float(png_ptr,
info_ptr->colorspace.end_points_XYZ.blue_Z, "cHRM blue Z");
- return (PNG_INFO_cHRM);
+ return PNG_INFO_cHRM;
}
- return (0);
+ return 0;
}
# endif
@@ -608,11 +617,11 @@ png_get_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y,
png_fixed_point *int_blue_Z)
{
+ png_debug1(1, "in %s retrieval function", "cHRM_XYZ");
+
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0)
{
- png_debug1(1, "in %s retrieval function", "cHRM_XYZ");
-
if (int_red_X != NULL)
*int_red_X = info_ptr->colorspace.end_points_XYZ.red_X;
if (int_red_Y != NULL)
@@ -631,10 +640,10 @@ png_get_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
*int_blue_Y = info_ptr->colorspace.end_points_XYZ.blue_Y;
if (int_blue_Z != NULL)
*int_blue_Z = info_ptr->colorspace.end_points_XYZ.blue_Z;
- return (PNG_INFO_cHRM);
+ return PNG_INFO_cHRM;
}
- return (0);
+ return 0;
}
png_uint_32 PNGAPI
@@ -664,10 +673,10 @@ png_get_cHRM_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
*blue_x = info_ptr->colorspace.end_points_xy.bluex;
if (blue_y != NULL)
*blue_y = info_ptr->colorspace.end_points_xy.bluey;
- return (PNG_INFO_cHRM);
+ return PNG_INFO_cHRM;
}
- return (0);
+ return 0;
}
# endif
#endif
@@ -685,10 +694,10 @@ png_get_gAMA_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
file_gamma != NULL)
{
*file_gamma = info_ptr->colorspace.gamma;
- return (PNG_INFO_gAMA);
+ return PNG_INFO_gAMA;
}
- return (0);
+ return 0;
}
# endif
@@ -705,10 +714,10 @@ png_get_gAMA(png_const_structrp png_ptr, png_const_inforp info_ptr,
{
*file_gamma = png_float(png_ptr, info_ptr->colorspace.gamma,
"png_get_gAMA");
- return (PNG_INFO_gAMA);
+ return PNG_INFO_gAMA;
}
- return (0);
+ return 0;
}
# endif
#endif
@@ -724,10 +733,10 @@ png_get_sRGB(png_const_structrp png_ptr, png_const_inforp info_ptr,
(info_ptr->valid & PNG_INFO_sRGB) != 0 && file_srgb_intent != NULL)
{
*file_srgb_intent = info_ptr->colorspace.rendering_intent;
- return (PNG_INFO_sRGB);
+ return PNG_INFO_sRGB;
}
- return (0);
+ return 0;
}
#endif
@@ -751,10 +760,10 @@ png_get_iCCP(png_const_structrp png_ptr, png_inforp info_ptr,
*/
if (compression_type != NULL)
*compression_type = PNG_COMPRESSION_TYPE_BASE;
- return (PNG_INFO_iCCP);
+ return PNG_INFO_iCCP;
}
- return (0);
+ return 0;
}
#endif
@@ -764,13 +773,15 @@ int PNGAPI
png_get_sPLT(png_const_structrp png_ptr, png_inforp info_ptr,
png_sPLT_tpp spalettes)
{
+ png_debug1(1, "in %s retrieval function", "sPLT");
+
if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL)
{
*spalettes = info_ptr->splt_palettes;
return info_ptr->splt_palettes_num;
}
- return (0);
+ return 0;
}
#endif
@@ -796,10 +807,10 @@ png_get_eXIf_1(png_const_structrp png_ptr, png_const_inforp info_ptr,
{
*num_exif = info_ptr->num_exif;
*exif = info_ptr->exif;
- return (PNG_INFO_eXIf);
+ return PNG_INFO_eXIf;
}
- return (0);
+ return 0;
}
#endif
@@ -814,10 +825,10 @@ png_get_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
(info_ptr->valid & PNG_INFO_hIST) != 0 && hist != NULL)
{
*hist = info_ptr->hist;
- return (PNG_INFO_hIST);
+ return PNG_INFO_hIST;
}
- return (0);
+ return 0;
}
#endif
@@ -830,7 +841,7 @@ png_get_IHDR(png_const_structrp png_ptr, png_const_inforp info_ptr,
png_debug1(1, "in %s retrieval function", "IHDR");
if (png_ptr == NULL || info_ptr == NULL)
- return (0);
+ return 0;
if (width != NULL)
*width = info_ptr->width;
@@ -862,7 +873,7 @@ png_get_IHDR(png_const_structrp png_ptr, png_const_inforp info_ptr,
info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type,
info_ptr->compression_type, info_ptr->filter_type);
- return (1);
+ return 1;
}
#ifdef PNG_oFFs_SUPPORTED
@@ -879,10 +890,10 @@ png_get_oFFs(png_const_structrp png_ptr, png_const_inforp info_ptr,
*offset_x = info_ptr->x_offset;
*offset_y = info_ptr->y_offset;
*unit_type = (int)info_ptr->offset_unit_type;
- return (PNG_INFO_oFFs);
+ return PNG_INFO_oFFs;
}
- return (0);
+ return 0;
}
#endif
@@ -906,10 +917,10 @@ png_get_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
*nparams = (int)info_ptr->pcal_nparams;
*units = info_ptr->pcal_units;
*params = info_ptr->pcal_params;
- return (PNG_INFO_pCAL);
+ return PNG_INFO_pCAL;
}
- return (0);
+ return 0;
}
#endif
@@ -921,6 +932,8 @@ png_uint_32 PNGAPI
png_get_sCAL_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
int *unit, png_fixed_point *width, png_fixed_point *height)
{
+ png_debug1(1, "in %s retrieval function", "sCAL");
+
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_sCAL) != 0)
{
@@ -932,10 +945,10 @@ png_get_sCAL_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr,
*width = png_fixed(png_ptr, atof(info_ptr->scal_s_width), "sCAL width");
*height = png_fixed(png_ptr, atof(info_ptr->scal_s_height),
"sCAL height");
- return (PNG_INFO_sCAL);
+ return PNG_INFO_sCAL;
}
- return(0);
+ return 0;
}
# endif /* FLOATING_ARITHMETIC */
# endif /* FIXED_POINT */
@@ -944,32 +957,36 @@ png_uint_32 PNGAPI
png_get_sCAL(png_const_structrp png_ptr, png_const_inforp info_ptr,
int *unit, double *width, double *height)
{
+ png_debug1(1, "in %s retrieval function", "sCAL(float)");
+
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_sCAL) != 0)
{
*unit = info_ptr->scal_unit;
*width = atof(info_ptr->scal_s_width);
*height = atof(info_ptr->scal_s_height);
- return (PNG_INFO_sCAL);
+ return PNG_INFO_sCAL;
}
- return(0);
+ return 0;
}
# endif /* FLOATING POINT */
png_uint_32 PNGAPI
png_get_sCAL_s(png_const_structrp png_ptr, png_const_inforp info_ptr,
int *unit, png_charpp width, png_charpp height)
{
+ png_debug1(1, "in %s retrieval function", "sCAL(str)");
+
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_sCAL) != 0)
{
*unit = info_ptr->scal_unit;
*width = info_ptr->scal_s_width;
*height = info_ptr->scal_s_height;
- return (PNG_INFO_sCAL);
+ return PNG_INFO_sCAL;
}
- return(0);
+ return 0;
}
#endif /* sCAL */
@@ -1004,7 +1021,7 @@ png_get_pHYs(png_const_structrp png_ptr, png_const_inforp info_ptr,
}
}
- return (retval);
+ return retval;
}
#endif /* pHYs */
@@ -1020,10 +1037,10 @@ png_get_PLTE(png_const_structrp png_ptr, png_inforp info_ptr,
*palette = info_ptr->palette;
*num_palette = info_ptr->num_palette;
png_debug1(3, "num_palette = %d", *num_palette);
- return (PNG_INFO_PLTE);
+ return PNG_INFO_PLTE;
}
- return (0);
+ return 0;
}
#ifdef PNG_sBIT_SUPPORTED
@@ -1037,10 +1054,10 @@ png_get_sBIT(png_const_structrp png_ptr, png_inforp info_ptr,
(info_ptr->valid & PNG_INFO_sBIT) != 0 && sig_bit != NULL)
{
*sig_bit = &(info_ptr->sig_bit);
- return (PNG_INFO_sBIT);
+ return PNG_INFO_sBIT;
}
- return (0);
+ return 0;
}
#endif
@@ -1051,7 +1068,7 @@ png_get_text(png_const_structrp png_ptr, png_inforp info_ptr,
{
if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0)
{
- png_debug1(1, "in 0x%lx retrieval function",
+ png_debug1(1, "in text retrieval function, chunk typeid = 0x%lx",
(unsigned long)png_ptr->chunk_name);
if (text_ptr != NULL)
@@ -1066,7 +1083,7 @@ png_get_text(png_const_structrp png_ptr, png_inforp info_ptr,
if (num_text != NULL)
*num_text = 0;
- return(0);
+ return 0;
}
#endif
@@ -1081,10 +1098,10 @@ png_get_tIME(png_const_structrp png_ptr, png_inforp info_ptr,
(info_ptr->valid & PNG_INFO_tIME) != 0 && mod_time != NULL)
{
*mod_time = &(info_ptr->mod_time);
- return (PNG_INFO_tIME);
+ return PNG_INFO_tIME;
}
- return (0);
+ return 0;
}
#endif
@@ -1094,11 +1111,12 @@ png_get_tRNS(png_const_structrp png_ptr, png_inforp info_ptr,
png_bytep *trans_alpha, int *num_trans, png_color_16p *trans_color)
{
png_uint_32 retval = 0;
+
+ png_debug1(1, "in %s retrieval function", "tRNS");
+
if (png_ptr != NULL && info_ptr != NULL &&
(info_ptr->valid & PNG_INFO_tRNS) != 0)
{
- png_debug1(1, "in %s retrieval function", "tRNS");
-
if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
if (trans_alpha != NULL)
@@ -1130,7 +1148,7 @@ png_get_tRNS(png_const_structrp png_ptr, png_inforp info_ptr,
}
}
- return (retval);
+ return retval;
}
#endif
@@ -1145,7 +1163,7 @@ png_get_unknown_chunks(png_const_structrp png_ptr, png_inforp info_ptr,
return info_ptr->unknown_chunks_num;
}
- return (0);
+ return 0;
}
#endif
@@ -1241,7 +1259,7 @@ png_get_palette_max(png_const_structp png_ptr, png_const_infop info_ptr)
if (png_ptr != NULL && info_ptr != NULL)
return png_ptr->num_palette_max;
- return (-1);
+ return -1;
}
# endif
#endif
diff --git a/src/3rdparty/libpng/pnglibconf.h b/src/3rdparty/libpng/pnglibconf.h
index e5948c8ce1..83f09fbe77 100644
--- a/src/3rdparty/libpng/pnglibconf.h
+++ b/src/3rdparty/libpng/pnglibconf.h
@@ -1,8 +1,8 @@
/* pnglibconf.h - library build configuration */
-/* libpng version 1.6.39 */
+/* libpng version 1.6.43 */
-/* Copyright (c) 2018-2022 Cosmin Truta */
+/* Copyright (c) 2018-2024 Cosmin Truta */
/* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */
/* This code is released under the libpng license. */
@@ -27,6 +27,7 @@
#define PNG_COLORSPACE_SUPPORTED
#define PNG_CONSOLE_IO_SUPPORTED
#define PNG_CONVERT_tIME_SUPPORTED
+/*#undef PNG_DISABLE_ADLER32_CHECK_SUPPORTED*/
#define PNG_EASY_ACCESS_SUPPORTED
/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/
#define PNG_ERROR_TEXT_SUPPORTED
@@ -41,6 +42,10 @@
#define PNG_INCH_CONVERSIONS_SUPPORTED
#define PNG_INFO_IMAGE_SUPPORTED
#define PNG_IO_STATE_SUPPORTED
+/*#undef PNG_MIPS_MMI_API_SUPPORTED*/
+/*#undef PNG_MIPS_MMI_CHECK_SUPPORTED*/
+/*#undef PNG_MIPS_MSA_API_SUPPORTED*/
+/*#undef PNG_MIPS_MSA_CHECK_SUPPORTED*/
#define PNG_MNG_FEATURES_SUPPORTED
#define PNG_POINTER_INDEXING_SUPPORTED
/*#undef PNG_POWERPC_VSX_API_SUPPORTED*/
diff --git a/src/3rdparty/libpng/pngpread.c b/src/3rdparty/libpng/pngpread.c
index e283627b77..ffab19c08c 100644
--- a/src/3rdparty/libpng/pngpread.c
+++ b/src/3rdparty/libpng/pngpread.c
@@ -1,7 +1,7 @@
/* pngpread.c - read a png file in push mode
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -145,10 +145,10 @@ png_push_read_sig(png_structrp png_ptr, png_inforp info_ptr)
num_to_check);
png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes + num_to_check);
- if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))
+ if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check) != 0)
{
if (num_checked < 4 &&
- png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))
+ png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4) != 0)
png_error(png_ptr, "Not a PNG file");
else
@@ -295,6 +295,14 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr)
}
#endif
+#ifdef PNG_READ_eXIf_SUPPORTED
+ else if (png_ptr->chunk_name == png_eXIf)
+ {
+ PNG_PUSH_SAVE_BUFFER_IF_FULL
+ png_handle_eXIf(png_ptr, info_ptr, png_ptr->push_length);
+ }
+
+#endif
#ifdef PNG_READ_sRGB_SUPPORTED
else if (chunk_name == png_sRGB)
{
@@ -1089,7 +1097,7 @@ png_voidp PNGAPI
png_get_progressive_ptr(png_const_structrp png_ptr)
{
if (png_ptr == NULL)
- return (NULL);
+ return NULL;
return png_ptr->io_ptr;
}
diff --git a/src/3rdparty/libpng/pngpriv.h b/src/3rdparty/libpng/pngpriv.h
index b8a73b685d..9bfdb71342 100644
--- a/src/3rdparty/libpng/pngpriv.h
+++ b/src/3rdparty/libpng/pngpriv.h
@@ -1,7 +1,7 @@
/* pngpriv.h - private declarations for use inside libpng
*
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -36,7 +36,7 @@
* still required (as of 2011-05-02.)
*/
#ifndef _POSIX_SOURCE
-# define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */
+# define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */
#endif
#ifndef PNG_VERSION_INFO_ONLY
@@ -190,13 +190,27 @@
#endif /* PNG_ARM_NEON_OPT > 0 */
#ifndef PNG_MIPS_MSA_OPT
-# if defined(__mips_msa) && (__mips_isa_rev >= 5) && defined(PNG_ALIGNED_MEMORY_SUPPORTED)
+# if defined(__mips_msa) && (__mips_isa_rev >= 5) && \
+ defined(PNG_ALIGNED_MEMORY_SUPPORTED)
# define PNG_MIPS_MSA_OPT 2
# else
# define PNG_MIPS_MSA_OPT 0
# endif
#endif
+#ifndef PNG_MIPS_MMI_OPT
+# ifdef PNG_MIPS_MMI
+# if defined(__mips_loongson_mmi) && (_MIPS_SIM == _ABI64) && \
+ defined(PNG_ALIGNED_MEMORY_SUPPORTED)
+# define PNG_MIPS_MMI_OPT 1
+# else
+# define PNG_MIPS_MMI_OPT 0
+# endif
+# else
+# define PNG_MIPS_MMI_OPT 0
+# endif
+#endif
+
#ifndef PNG_POWERPC_VSX_OPT
# if defined(__PPC64__) && defined(__ALTIVEC__) && defined(__VSX__)
# define PNG_POWERPC_VSX_OPT 2
@@ -205,13 +219,21 @@
# endif
#endif
+#ifndef PNG_LOONGARCH_LSX_OPT
+# if defined(__loongarch_sx)
+# define PNG_LOONGARCH_LSX_OPT 1
+# else
+# define PNG_LOONGARCH_LSX_OPT 0
+# endif
+#endif
+
#ifndef PNG_INTEL_SSE_OPT
# ifdef PNG_INTEL_SSE
/* Only check for SSE if the build configuration has been modified to
* enable SSE optimizations. This means that these optimizations will
* be off by default. See contrib/intel for more details.
*/
-# if defined(__SSE4_1__) || defined(__AVX__) || defined(__SSSE3__) || \
+# if defined(__SSE4_1__) || defined(__AVX__) || defined(__SSSE3__) || \
defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64) || \
(defined(_M_IX86_FP) && _M_IX86_FP >= 2)
# define PNG_INTEL_SSE_OPT 1
@@ -248,7 +270,6 @@
#endif
#if PNG_MIPS_MSA_OPT > 0
-# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_msa
# ifndef PNG_MIPS_MSA_IMPLEMENTATION
# if defined(__mips_msa)
# if defined(__clang__)
@@ -264,11 +285,28 @@
# ifndef PNG_MIPS_MSA_IMPLEMENTATION
# define PNG_MIPS_MSA_IMPLEMENTATION 1
+# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_mips
# endif
#else
# define PNG_MIPS_MSA_IMPLEMENTATION 0
#endif /* PNG_MIPS_MSA_OPT > 0 */
+#if PNG_MIPS_MMI_OPT > 0
+# ifndef PNG_MIPS_MMI_IMPLEMENTATION
+# if defined(__mips_loongson_mmi) && (_MIPS_SIM == _ABI64)
+# define PNG_MIPS_MMI_IMPLEMENTATION 2
+# else /* !defined __mips_loongson_mmi || _MIPS_SIM != _ABI64 */
+# define PNG_MIPS_MMI_IMPLEMENTATION 0
+# endif /* __mips_loongson_mmi && _MIPS_SIM == _ABI64 */
+# endif /* !PNG_MIPS_MMI_IMPLEMENTATION */
+
+# if PNG_MIPS_MMI_IMPLEMENTATION > 0
+# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_mips
+# endif
+#else
+# define PNG_MIPS_MMI_IMPLEMENTATION 0
+#endif /* PNG_MIPS_MMI_OPT > 0 */
+
#if PNG_POWERPC_VSX_OPT > 0
# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_vsx
# define PNG_POWERPC_VSX_IMPLEMENTATION 1
@@ -276,6 +314,12 @@
# define PNG_POWERPC_VSX_IMPLEMENTATION 0
#endif
+#if PNG_LOONGARCH_LSX_OPT > 0
+# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_lsx
+# define PNG_LOONGARCH_LSX_IMPLEMENTATION 1
+#else
+# define PNG_LOONGARCH_LSX_IMPLEMENTATION 0
+#endif
/* Is this a build of a DLL where compilation of the object modules requires
* different preprocessor settings to those required for a simple library? If
@@ -514,18 +558,8 @@
*/
# include <float.h>
-# if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \
- defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC)
- /* We need to check that <math.h> hasn't already been included earlier
- * as it seems it doesn't agree with <fp.h>, yet we should really use
- * <fp.h> if possible.
- */
-# if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__)
-# include <fp.h>
-# endif
-# else
-# include <math.h>
-# endif
+# include <math.h>
+
# if defined(_AMIGA) && defined(__SASC) && defined(_M68881)
/* Amiga SAS/C: We must include builtin FPU functions when compiling using
* MATH=68881
@@ -626,7 +660,7 @@
#define PNG_BACKGROUND_IS_GRAY 0x800U
#define PNG_HAVE_PNG_SIGNATURE 0x1000U
#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */
- /* 0x4000U (unused) */
+#define PNG_WROTE_eXIf 0x4000U
#define PNG_IS_READ_STRUCT 0x8000U /* Else is a write struct */
/* Flags for the transformations the PNG library does on the image data */
@@ -1306,7 +1340,7 @@ PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_neon,(png_row_infop
row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
#endif
-#if PNG_MIPS_MSA_OPT > 0
+#if PNG_MIPS_MSA_IMPLEMENTATION == 1
PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_msa,(png_row_infop row_info,
png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_msa,(png_row_infop
@@ -1323,6 +1357,23 @@ PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_msa,(png_row_infop
row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
#endif
+#if PNG_MIPS_MMI_IMPLEMENTATION > 0
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_mmi,(png_row_infop row_info,
+ png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_mmi,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_mmi,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_mmi,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_mmi,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_mmi,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_mmi,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+#endif
+
#if PNG_POWERPC_VSX_OPT > 0
PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_vsx,(png_row_infop row_info,
png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
@@ -1355,6 +1406,23 @@ PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_sse2,(png_row_infop
row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
#endif
+#if PNG_LOONGARCH_LSX_IMPLEMENTATION == 1
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_lsx,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_lsx,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_lsx,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_lsx,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_lsx,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_lsx,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_lsx,(png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY);
+#endif
+
/* Choose the best filter to use and filter the row data */
PNG_INTERNAL_FUNCTION(void,png_write_find_filter,(png_structrp png_ptr,
png_row_infop row_info),PNG_EMPTY);
@@ -1910,7 +1978,7 @@ PNG_INTERNAL_FUNCTION(void,png_ascii_from_fixed,(png_const_structrp png_ptr,
*/
#define PNG_FP_INVALID 512 /* Available for callers as a distinct value */
-/* Result codes for the parser (boolean - true meants ok, false means
+/* Result codes for the parser (boolean - true means ok, false means
* not ok yet.)
*/
#define PNG_FP_MAYBE 0 /* The number may be valid in the future */
@@ -2094,17 +2162,27 @@ PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_neon,
(png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
#endif
-#if PNG_MIPS_MSA_OPT > 0
-PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_msa,
+#if PNG_MIPS_MSA_IMPLEMENTATION == 1
+PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_mips,
(png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
#endif
+# if PNG_MIPS_MMI_IMPLEMENTATION > 0
+PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_mips,
+ (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
+# endif
+
# if PNG_INTEL_SSE_IMPLEMENTATION > 0
PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_sse2,
(png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
# endif
#endif
+#if PNG_LOONGARCH_LSX_OPT > 0
+PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_lsx,
+ (png_structp png_ptr, unsigned int bpp), PNG_EMPTY);
+#endif
+
PNG_INTERNAL_FUNCTION(png_uint_32, png_check_keyword, (png_structrp png_ptr,
png_const_charp key, png_bytep new_key), PNG_EMPTY);
diff --git a/src/3rdparty/libpng/pngread.c b/src/3rdparty/libpng/pngread.c
index 96996ced5b..07a39df6e2 100644
--- a/src/3rdparty/libpng/pngread.c
+++ b/src/3rdparty/libpng/pngread.c
@@ -1,7 +1,7 @@
/* pngread.c - read a PNG file
*
- * Copyright (c) 2018-2019 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -568,7 +568,11 @@ png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row)
#endif
#ifdef PNG_READ_TRANSFORMS_SUPPORTED
- if (png_ptr->transformations)
+ if (png_ptr->transformations
+# ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
+ || png_ptr->num_palette_max >= 0
+# endif
+ )
png_do_read_transformations(png_ptr, &row_info);
#endif
@@ -785,7 +789,7 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr)
#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
/* Report invalid palette index; added at libng-1.5.10 */
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
- png_ptr->num_palette_max > png_ptr->num_palette)
+ png_ptr->num_palette_max >= png_ptr->num_palette)
png_benign_error(png_ptr, "Read palette index exceeding num_palette");
#endif
@@ -1049,6 +1053,8 @@ void PNGAPI
png_read_png(png_structrp png_ptr, png_inforp info_ptr,
int transforms, voidp params)
{
+ png_debug(1, "in png_read_png");
+
if (png_ptr == NULL || info_ptr == NULL)
return;
diff --git a/src/3rdparty/libpng/pngrtran.c b/src/3rdparty/libpng/pngrtran.c
index 238f5afe7e..1526123e02 100644
--- a/src/3rdparty/libpng/pngrtran.c
+++ b/src/3rdparty/libpng/pngrtran.c
@@ -1,7 +1,7 @@
/* pngrtran.c - transforms the data in a row for PNG readers
*
- * Copyright (c) 2018-2019 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -290,21 +290,20 @@ png_set_alpha_mode_fixed(png_structrp png_ptr, int mode,
int compose = 0;
png_fixed_point file_gamma;
- png_debug(1, "in png_set_alpha_mode");
+ png_debug(1, "in png_set_alpha_mode_fixed");
if (png_rtran_ok(png_ptr, 0) == 0)
return;
output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/);
- /* Validate the value to ensure it is in a reasonable range. The value
+ /* Validate the value to ensure it is in a reasonable range. The value
* is expected to be 1 or greater, but this range test allows for some
- * viewing correction values. The intent is to weed out users of this API
- * who use the inverse of the gamma value accidentally! Since some of these
- * values are reasonable this may have to be changed:
+ * viewing correction values. The intent is to weed out the API users
+ * who might use the inverse of the gamma value accidentally!
*
- * 1.6.x: changed from 0.07..3 to 0.01..100 (to accommodate the optimal 16-bit
- * gamma of 36, and its reciprocal.)
+ * In libpng 1.6.0, we changed from 0.07..3 to 0.01..100, to accommodate
+ * the optimal 16-bit gamma of 36 and its reciprocal.
*/
if (output_gamma < 1000 || output_gamma > 10000000)
png_error(png_ptr, "output gamma out of expected range");
@@ -441,7 +440,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
int i;
png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,
- (png_alloc_size_t)((png_uint_32)num_palette * (sizeof (png_byte))));
+ (png_alloc_size_t)num_palette);
for (i = 0; i < num_palette; i++)
png_ptr->quantize_index[i] = (png_byte)i;
}
@@ -458,7 +457,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
/* Initialize an array to sort colors */
png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr,
- (png_alloc_size_t)((png_uint_32)num_palette * (sizeof (png_byte))));
+ (png_alloc_size_t)num_palette);
/* Initialize the quantize_sort array */
for (i = 0; i < num_palette; i++)
@@ -592,11 +591,9 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
/* Initialize palette index arrays */
png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,
- (png_alloc_size_t)((png_uint_32)num_palette *
- (sizeof (png_byte))));
+ (png_alloc_size_t)num_palette);
png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,
- (png_alloc_size_t)((png_uint_32)num_palette *
- (sizeof (png_byte))));
+ (png_alloc_size_t)num_palette);
/* Initialize the sort array */
for (i = 0; i < num_palette; i++)
@@ -761,12 +758,11 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
size_t num_entries = ((size_t)1 << total_bits);
png_ptr->palette_lookup = (png_bytep)png_calloc(png_ptr,
- (png_alloc_size_t)(num_entries * (sizeof (png_byte))));
+ (png_alloc_size_t)(num_entries));
- distance = (png_bytep)png_malloc(png_ptr, (png_alloc_size_t)(num_entries *
- (sizeof (png_byte))));
+ distance = (png_bytep)png_malloc(png_ptr, (png_alloc_size_t)num_entries);
- memset(distance, 0xff, num_entries * (sizeof (png_byte)));
+ memset(distance, 0xff, num_entries);
for (i = 0; i < num_palette; i++)
{
@@ -970,7 +966,7 @@ void PNGFAPI
png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action,
png_fixed_point red, png_fixed_point green)
{
- png_debug(1, "in png_set_rgb_to_gray");
+ png_debug(1, "in png_set_rgb_to_gray_fixed");
/* Need the IHDR here because of the check on color_type below. */
/* TODO: fix this */
diff --git a/src/3rdparty/libpng/pngrutil.c b/src/3rdparty/libpng/pngrutil.c
index 068ab193a3..d31dc21dae 100644
--- a/src/3rdparty/libpng/pngrutil.c
+++ b/src/3rdparty/libpng/pngrutil.c
@@ -1,7 +1,7 @@
/* pngrutil.c - utilities to read a PNG file
*
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -26,7 +26,7 @@ png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf)
if (uval > PNG_UINT_31_MAX)
png_error(png_ptr, "PNG unsigned integer out of range");
- return (uval);
+ return uval;
}
#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_READ_cHRM_SUPPORTED)
@@ -140,7 +140,7 @@ png_read_sig(png_structrp png_ptr, png_inforp info_ptr)
if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check) != 0)
{
if (num_checked < 4 &&
- png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))
+ png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4) != 0)
png_error(png_ptr, "Not a PNG file");
else
png_error(png_ptr, "PNG file corrupted by ASCII conversion");
@@ -171,7 +171,7 @@ png_read_chunk_header(png_structrp png_ptr)
/* Put the chunk name into png_ptr->chunk_name. */
png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(buf+4);
- png_debug2(0, "Reading %lx chunk, length = %lu",
+ png_debug2(0, "Reading chunk typeid = 0x%lx, length = %lu",
(unsigned long)png_ptr->chunk_name, (unsigned long)length);
/* Reset the crc and run it over the chunk name. */
@@ -238,10 +238,10 @@ png_crc_finish(png_structrp png_ptr, png_uint_32 skip)
else
png_chunk_error(png_ptr, "CRC error");
- return (1);
+ return 1;
}
- return (0);
+ return 0;
}
/* Compare the CRC stored in the PNG file with that calculated by libpng from
@@ -277,11 +277,11 @@ png_crc_error(png_structrp png_ptr)
if (need_crc != 0)
{
crc = png_get_uint_32(crc_bytes);
- return ((int)(crc != png_ptr->crc));
+ return crc != png_ptr->crc;
}
else
- return (0);
+ return 0;
}
#if defined(PNG_READ_iCCP_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) ||\
@@ -421,8 +421,7 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner)
png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED;
}
-#if ZLIB_VERNUM >= 0x1290 && \
- defined(PNG_SET_OPTION_SUPPORTED) && defined(PNG_IGNORE_ADLER32)
+#ifdef PNG_DISABLE_ADLER32_CHECK_SUPPORTED
if (((png_ptr->options >> PNG_IGNORE_ADLER32) & 3) == PNG_OPTION_ON)
/* Turn off validation of the ADLER32 checksum in IDAT chunks */
ret = inflateValidate(&png_ptr->zstream, 0);
diff --git a/src/3rdparty/libpng/pngset.c b/src/3rdparty/libpng/pngset.c
index 8c372cf415..eb1c8c7a35 100644
--- a/src/3rdparty/libpng/pngset.c
+++ b/src/3rdparty/libpng/pngset.c
@@ -1,7 +1,7 @@
/* pngset.c - storage of image information into info struct
*
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
* Copyright (c) 1998-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -137,46 +137,40 @@ png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X,
#ifdef PNG_eXIf_SUPPORTED
void PNGAPI
png_set_eXIf(png_const_structrp png_ptr, png_inforp info_ptr,
- png_bytep eXIf_buf)
+ png_bytep exif)
{
png_warning(png_ptr, "png_set_eXIf does not work; use png_set_eXIf_1");
PNG_UNUSED(info_ptr)
- PNG_UNUSED(eXIf_buf)
+ PNG_UNUSED(exif)
}
void PNGAPI
png_set_eXIf_1(png_const_structrp png_ptr, png_inforp info_ptr,
- png_uint_32 num_exif, png_bytep eXIf_buf)
+ png_uint_32 num_exif, png_bytep exif)
{
- int i;
+ png_bytep new_exif;
png_debug1(1, "in %s storage function", "eXIf");
- if (png_ptr == NULL || info_ptr == NULL)
+ if (png_ptr == NULL || info_ptr == NULL ||
+ (png_ptr->mode & PNG_WROTE_eXIf) != 0)
return;
- if (info_ptr->exif)
- {
- png_free(png_ptr, info_ptr->exif);
- info_ptr->exif = NULL;
- }
-
- info_ptr->num_exif = num_exif;
-
- info_ptr->exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr,
- info_ptr->num_exif));
+ new_exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr, num_exif));
- if (info_ptr->exif == NULL)
+ if (new_exif == NULL)
{
png_warning(png_ptr, "Insufficient memory for eXIf chunk data");
return;
}
- info_ptr->free_me |= PNG_FREE_EXIF;
+ memcpy(new_exif, exif, (size_t)num_exif);
- for (i = 0; i < (int) info_ptr->num_exif; i++)
- info_ptr->exif[i] = eXIf_buf[i];
+ png_free_data(png_ptr, info_ptr, PNG_FREE_EXIF, 0);
+ info_ptr->num_exif = num_exif;
+ info_ptr->exif = new_exif;
+ info_ptr->free_me |= PNG_FREE_EXIF;
info_ptr->valid |= PNG_INFO_eXIf;
}
#endif /* eXIf */
@@ -237,15 +231,13 @@ png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
if (info_ptr->hist == NULL)
{
png_warning(png_ptr, "Insufficient memory for hIST chunk data");
-
return;
}
- info_ptr->free_me |= PNG_FREE_HIST;
-
for (i = 0; i < info_ptr->num_palette; i++)
info_ptr->hist[i] = hist[i];
+ info_ptr->free_me |= PNG_FREE_HIST;
info_ptr->valid |= PNG_INFO_hIST;
}
#endif
@@ -367,6 +359,8 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
memcpy(info_ptr->pcal_purpose, purpose, length);
+ info_ptr->free_me |= PNG_FREE_PCAL;
+
png_debug(3, "storing X0, X1, type, and nparams in info");
info_ptr->pcal_X0 = X0;
info_ptr->pcal_X1 = X1;
@@ -383,7 +377,6 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
if (info_ptr->pcal_units == NULL)
{
png_warning(png_ptr, "Insufficient memory for pCAL units");
-
return;
}
@@ -395,7 +388,6 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
if (info_ptr->pcal_params == NULL)
{
png_warning(png_ptr, "Insufficient memory for pCAL params");
-
return;
}
@@ -413,7 +405,6 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
if (info_ptr->pcal_params[i] == NULL)
{
png_warning(png_ptr, "Insufficient memory for pCAL parameter");
-
return;
}
@@ -421,7 +412,6 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
}
info_ptr->valid |= PNG_INFO_pCAL;
- info_ptr->free_me |= PNG_FREE_PCAL;
}
#endif
@@ -478,18 +468,17 @@ png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr,
if (info_ptr->scal_s_height == NULL)
{
- png_free (png_ptr, info_ptr->scal_s_width);
+ png_free(png_ptr, info_ptr->scal_s_width);
info_ptr->scal_s_width = NULL;
png_warning(png_ptr, "Memory allocation failed while processing sCAL");
-
return;
}
memcpy(info_ptr->scal_s_height, sheight, lengthh);
- info_ptr->valid |= PNG_INFO_sCAL;
info_ptr->free_me |= PNG_FREE_SCAL;
+ info_ptr->valid |= PNG_INFO_sCAL;
}
# ifdef PNG_FLOATING_POINT_SUPPORTED
@@ -625,11 +614,10 @@ png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
if (num_palette > 0)
memcpy(png_ptr->palette, palette, (unsigned int)num_palette *
(sizeof (png_color)));
+
info_ptr->palette = png_ptr->palette;
info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;
-
info_ptr->free_me |= PNG_FREE_PLTE;
-
info_ptr->valid |= PNG_INFO_PLTE;
}
@@ -775,11 +763,11 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
{
int i;
- png_debug1(1, "in %lx storage function", png_ptr == NULL ? 0xabadca11U :
- (unsigned long)png_ptr->chunk_name);
+ png_debug1(1, "in text storage function, chunk typeid = 0x%lx",
+ png_ptr == NULL ? 0xabadca11UL : (unsigned long)png_ptr->chunk_name);
if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL)
- return(0);
+ return 0;
/* Make sure we have enough space in the "text" array in info_struct
* to hold all of the incoming text_ptr objects. This compare can't overflow
@@ -959,7 +947,7 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
png_debug1(3, "transferred text chunk %d", info_ptr->num_text);
}
- return(0);
+ return 0;
}
#endif
@@ -1020,8 +1008,8 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
- info_ptr->valid |= PNG_INFO_tRNS;
info_ptr->free_me |= PNG_FREE_TRNS;
+ info_ptr->valid |= PNG_INFO_tRNS;
}
png_ptr->trans_alpha = info_ptr->trans_alpha;
}
@@ -1054,8 +1042,8 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
if (num_trans != 0)
{
- info_ptr->valid |= PNG_INFO_tRNS;
info_ptr->free_me |= PNG_FREE_TRNS;
+ info_ptr->valid |= PNG_INFO_tRNS;
}
}
#endif
@@ -1075,6 +1063,8 @@ png_set_sPLT(png_const_structrp png_ptr,
{
png_sPLT_tp np;
+ png_debug1(1, "in %s storage function", "sPLT");
+
if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL)
return;
@@ -1089,11 +1079,11 @@ png_set_sPLT(png_const_structrp png_ptr,
{
/* Out of memory or too many chunks */
png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR);
-
return;
}
png_free(png_ptr, info_ptr->splt_palettes);
+
info_ptr->splt_palettes = np;
info_ptr->free_me |= PNG_FREE_SPLT;
@@ -1247,11 +1237,11 @@ png_set_unknown_chunks(png_const_structrp png_ptr,
{
png_chunk_report(png_ptr, "too many unknown chunks",
PNG_CHUNK_WRITE_ERROR);
-
return;
}
png_free(png_ptr, info_ptr->unknown_chunks);
+
info_ptr->unknown_chunks = np; /* safe because it is initialized */
info_ptr->free_me |= PNG_FREE_UNKN;
@@ -1549,7 +1539,7 @@ void PNGAPI
png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr,
png_bytepp row_pointers)
{
- png_debug1(1, "in %s storage function", "rows");
+ png_debug(1, "in png_set_rows");
if (png_ptr == NULL || info_ptr == NULL)
return;
@@ -1568,6 +1558,8 @@ png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr,
void PNGAPI
png_set_compression_buffer_size(png_structrp png_ptr, size_t size)
{
+ png_debug(1, "in png_set_compression_buffer_size");
+
if (png_ptr == NULL)
return;
@@ -1639,6 +1631,8 @@ void PNGAPI
png_set_user_limits(png_structrp png_ptr, png_uint_32 user_width_max,
png_uint_32 user_height_max)
{
+ png_debug(1, "in png_set_user_limits");
+
/* Images with dimensions larger than these limits will be
* rejected by png_set_IHDR(). To accept any PNG datastream
* regardless of dimensions, set both limits to 0x7fffffff.
@@ -1654,6 +1648,8 @@ png_set_user_limits(png_structrp png_ptr, png_uint_32 user_width_max,
void PNGAPI
png_set_chunk_cache_max(png_structrp png_ptr, png_uint_32 user_chunk_cache_max)
{
+ png_debug(1, "in png_set_chunk_cache_max");
+
if (png_ptr != NULL)
png_ptr->user_chunk_cache_max = user_chunk_cache_max;
}
@@ -1663,6 +1659,8 @@ void PNGAPI
png_set_chunk_malloc_max(png_structrp png_ptr,
png_alloc_size_t user_chunk_malloc_max)
{
+ png_debug(1, "in png_set_chunk_malloc_max");
+
if (png_ptr != NULL)
png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;
}
diff --git a/src/3rdparty/libpng/pngtrans.c b/src/3rdparty/libpng/pngtrans.c
index 1100f46ebe..62cb21edf1 100644
--- a/src/3rdparty/libpng/pngtrans.c
+++ b/src/3rdparty/libpng/pngtrans.c
@@ -1,7 +1,7 @@
/* pngtrans.c - transforms the data in a row (used by both readers and writers)
*
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -103,10 +103,10 @@ png_set_interlace_handling(png_structrp png_ptr)
if (png_ptr != 0 && png_ptr->interlaced != 0)
{
png_ptr->transformations |= PNG_INTERLACE;
- return (7);
+ return 7;
}
- return (1);
+ return 1;
}
#endif
@@ -498,6 +498,8 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
png_bytep dp = row; /* destination pointer */
png_bytep ep = row + row_info->rowbytes; /* One beyond end of row */
+ png_debug(1, "in png_do_strip_channel");
+
/* At the start sp will point to the first byte to copy and dp to where
* it is copied to. ep always points just beyond the end of the row, so
* the loop simply copies (channels-1) channels until sp reaches ep.
@@ -698,6 +700,8 @@ png_do_bgr(png_row_infop row_info, png_bytep row)
void /* PRIVATE */
png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info)
{
+ png_debug(1, "in png_do_check_palette_indexes");
+
if (png_ptr->num_palette < (1 << row_info->bit_depth) &&
png_ptr->num_palette > 0) /* num_palette can be 0 in MNG files */
{
@@ -708,7 +712,7 @@ png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info)
* forms produced on either GCC or MSVC.
*/
int padding = PNG_PADBITS(row_info->pixel_depth, row_info->width);
- png_bytep rp = png_ptr->row_buf + row_info->rowbytes - 1;
+ png_bytep rp = png_ptr->row_buf + row_info->rowbytes;
switch (row_info->bit_depth)
{
@@ -833,7 +837,7 @@ png_voidp PNGAPI
png_get_user_transform_ptr(png_const_structrp png_ptr)
{
if (png_ptr == NULL)
- return (NULL);
+ return NULL;
return png_ptr->user_transform_ptr;
}
diff --git a/src/3rdparty/libpng/pngwrite.c b/src/3rdparty/libpng/pngwrite.c
index 4e58d776a9..77e412f43d 100644
--- a/src/3rdparty/libpng/pngwrite.c
+++ b/src/3rdparty/libpng/pngwrite.c
@@ -1,7 +1,7 @@
/* pngwrite.c - general routines to write a PNG file
*
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -239,7 +239,10 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr)
#ifdef PNG_WRITE_eXIf_SUPPORTED
if ((info_ptr->valid & PNG_INFO_eXIf) != 0)
+ {
png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
+ png_ptr->mode |= PNG_WROTE_eXIf;
+ }
#endif
#ifdef PNG_WRITE_hIST_SUPPORTED
@@ -366,7 +369,8 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr)
png_error(png_ptr, "No IDATs written into file");
#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
- if (png_ptr->num_palette_max > png_ptr->num_palette)
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ png_ptr->num_palette_max >= png_ptr->num_palette)
png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
#endif
@@ -439,8 +443,9 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr)
#endif
#ifdef PNG_WRITE_eXIf_SUPPORTED
- if ((info_ptr->valid & PNG_INFO_eXIf) != 0)
- png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
+ if ((info_ptr->valid & PNG_INFO_eXIf) != 0 &&
+ (png_ptr->mode & PNG_WROTE_eXIf) == 0)
+ png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif);
#endif
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
@@ -710,12 +715,12 @@ png_write_row(png_structrp png_ptr, png_const_bytep row)
/* 1.5.6: moved from png_struct to be a local structure: */
png_row_info row_info;
- if (png_ptr == NULL)
- return;
-
png_debug2(1, "in png_write_row (row %u, pass %d)",
png_ptr->row_number, png_ptr->pass);
+ if (png_ptr == NULL)
+ return;
+
/* Initialize transformations and other stuff if first time */
if (png_ptr->row_number == 0 && png_ptr->pass == 0)
{
@@ -1206,6 +1211,8 @@ png_set_compression_strategy(png_structrp png_ptr, int strategy)
void PNGAPI
png_set_compression_window_bits(png_structrp png_ptr, int window_bits)
{
+ png_debug(1, "in png_set_compression_window_bits");
+
if (png_ptr == NULL)
return;
@@ -1289,6 +1296,8 @@ png_set_text_compression_strategy(png_structrp png_ptr, int strategy)
void PNGAPI
png_set_text_compression_window_bits(png_structrp png_ptr, int window_bits)
{
+ png_debug(1, "in png_set_text_compression_window_bits");
+
if (png_ptr == NULL)
return;
@@ -1326,6 +1335,8 @@ png_set_text_compression_method(png_structrp png_ptr, int method)
void PNGAPI
png_set_write_status_fn(png_structrp png_ptr, png_write_status_ptr write_row_fn)
{
+ png_debug(1, "in png_set_write_status_fn");
+
if (png_ptr == NULL)
return;
@@ -1353,6 +1364,8 @@ void PNGAPI
png_write_png(png_structrp png_ptr, png_inforp info_ptr,
int transforms, voidp params)
{
+ png_debug(1, "in png_write_png");
+
if (png_ptr == NULL || info_ptr == NULL)
return;
diff --git a/src/3rdparty/libpng/pngwutil.c b/src/3rdparty/libpng/pngwutil.c
index 01f0607c70..14cc4ce367 100644
--- a/src/3rdparty/libpng/pngwutil.c
+++ b/src/3rdparty/libpng/pngwutil.c
@@ -1,7 +1,7 @@
/* pngwutil.c - utilities to write a PNG file
*
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2024 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
* Copyright (c) 1996-1997 Andreas Dilger
* Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -2311,7 +2311,7 @@ png_setup_sub_row(png_structrp png_ptr, png_uint_32 bpp,
break;
}
- return (sum);
+ return sum;
}
static void /* PRIVATE */
@@ -2361,7 +2361,7 @@ png_setup_up_row(png_structrp png_ptr, size_t row_bytes, size_t lmins)
break;
}
- return (sum);
+ return sum;
}
static void /* PRIVATE */
png_setup_up_row_only(png_structrp png_ptr, size_t row_bytes)
@@ -2417,7 +2417,7 @@ png_setup_avg_row(png_structrp png_ptr, png_uint_32 bpp,
break;
}
- return (sum);
+ return sum;
}
static void /* PRIVATE */
png_setup_avg_row_only(png_structrp png_ptr, png_uint_32 bpp,
@@ -2500,7 +2500,7 @@ png_setup_paeth_row(png_structrp png_ptr, png_uint_32 bpp,
break;
}
- return (sum);
+ return sum;
}
static void /* PRIVATE */
png_setup_paeth_row_only(png_structrp png_ptr, png_uint_32 bpp,
diff --git a/src/3rdparty/libpng/qt_attribution.json b/src/3rdparty/libpng/qt_attribution.json
index 2c51a05685..d9621193a3 100644
--- a/src/3rdparty/libpng/qt_attribution.json
+++ b/src/3rdparty/libpng/qt_attribution.json
@@ -3,33 +3,36 @@
"Name": "LibPNG",
"QDocModule": "qtgui",
"QtUsage": "Used in the qpng image plugin. Configure with -system-libpng or -no-libpng to avoid.",
+ "SecurityCritical": true,
"Description": "libpng is the official PNG reference library.",
"Homepage": "http://www.libpng.org/pub/png/libpng.html",
- "Version": "1.6.39",
+ "Version": "1.6.43",
+ "DownloadLocation": "https://download.sourceforge.net/libpng/libpng-1.6.43.tar.xz",
+
"License": "libpng License and PNG Reference Library version 2",
"LicenseId": "Libpng AND libpng-2.0",
"LicenseFile": "LICENSE",
- "Copyright": "Copyright (c) 1995-2022 The PNG Reference Library Authors
-Copyright (c) 2000-2022 Cosmin Truta
-Copyright (c) 1998-2018 Glenn Randers-Pehrson
-Copyright (c) 1996-1997 Andreas Dilger
-Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
-Copyright (c) 2000-2017 Simon-Pierre Cadieux
-Copyright (c) 2000-2017 Eric S. Raymond
-Copyright (c) 2000-2017 Mans Rullgard
-Copyright (c) 2000-2017 Gilles Vollant
-Copyright (c) 2000-2017 James Yu
-Copyright (c) 2000-2017 Mandar Sahastrabuddhe
-Copyright (c) 1998-2000 Tom Lane
-Copyright (c) 1998-2000 Willem van Schaik
-Copyright (c) 1996-1997 John Bowler
-Copyright (c) 1996-1997 Kevin Bracey
-Copyright (c) 1996-1997 Sam Bushell
-Copyright (c) 1996-1997 Magnus Holmgren
-Copyright (c) 1996-1997 Greg Roelofs
-Copyright (c) 1996-1997 Tom Tanner
-Copyright (c) 1995-1996 Dave Martindale
-Copyright (c) 1995-1996 Paul Schmidt
-Copyright (c) 1995-1996 Tim Wegner"
+ "Copyright": ["Copyright (c) 1995-2024 The PNG Reference Library Authors",
+ "Copyright (c) 2000-2024 Cosmin Truta",
+ "Copyright (c) 1998-2018 Glenn Randers-Pehrson",
+ "Copyright (c) 1996-1997 Andreas Dilger",
+ "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.",
+ "Copyright (c) 2000-2017 Simon-Pierre Cadieux",
+ "Copyright (c) 2000-2017 Eric S. Raymond",
+ "Copyright (c) 2000-2017 Mans Rullgard",
+ "Copyright (c) 2000-2017 Gilles Vollant",
+ "Copyright (c) 2000-2017 James Yu",
+ "Copyright (c) 2000-2017 Mandar Sahastrabuddhe",
+ "Copyright (c) 1998-2000 Tom Lane",
+ "Copyright (c) 1998-2000 Willem van Schaik",
+ "Copyright (c) 1996-1997 John Bowler",
+ "Copyright (c) 1996-1997 Kevin Bracey",
+ "Copyright (c) 1996-1997 Sam Bushell",
+ "Copyright (c) 1996-1997 Magnus Holmgren",
+ "Copyright (c) 1996-1997 Greg Roelofs",
+ "Copyright (c) 1996-1997 Tom Tanner",
+ "Copyright (c) 1995-1996 Dave Martindale",
+ "Copyright (c) 1995-1996 Paul Schmidt",
+ "Copyright (c) 1995-1996 Tim Wegner"]
}
diff --git a/src/3rdparty/libpsl/psl_data.cpp b/src/3rdparty/libpsl/psl_data.cpp
index 041af7739b..79595282f2 100644
--- a/src/3rdparty/libpsl/psl_data.cpp
+++ b/src/3rdparty/libpsl/psl_data.cpp
@@ -2,4522 +2,4373 @@
The byte array encodes effective tld names. See psl-make-dafsa source for documentation.*/
-static constexpr unsigned char kDafsa[54198] = {
- 0x40, 0x42, 0x4a, 0xd7, 0x40, 0xc1, 0x42, 0xc1, 0x50, 0xc9, 0x43, 0xb7,
- 0x43, 0x9c, 0x43, 0x66, 0x49, 0xa0, 0x51, 0x9a, 0x44, 0xce, 0x40, 0x7b,
- 0x47, 0x14, 0x47, 0x08, 0x49, 0x31, 0x4c, 0x65, 0x45, 0x66, 0x4a, 0xc1,
- 0x42, 0x81, 0x49, 0x51, 0x47, 0xfb, 0x47, 0x1e, 0x48, 0x24, 0x46, 0x14,
- 0x46, 0x61, 0x4d, 0xbf, 0x49, 0xa2, 0x4d, 0x01, 0x0e, 0x03, 0x03, 0x0f,
- 0x0a, 0x0e, 0x12, 0x18, 0xc0, 0xd1, 0x9f, 0x23, 0x08, 0x09, 0x10, 0x40,
+static constexpr unsigned char kDafsa[52406] = {
+ 0x40, 0x42, 0x4a, 0xa4, 0x40, 0xd1, 0x42, 0xb6, 0x50, 0x7d, 0x43, 0x85,
+ 0x43, 0x55, 0x43, 0x1d, 0x49, 0x9a, 0x51, 0x08, 0x44, 0xb0, 0x40, 0x94,
+ 0x46, 0x5c, 0x46, 0xdc, 0x49, 0x83, 0x4b, 0xb1, 0x45, 0x15, 0x4a, 0xad,
+ 0x42, 0x45, 0x49, 0x26, 0x47, 0x77, 0x46, 0xcd, 0x47, 0x7d, 0x46, 0x92,
+ 0x46, 0x33, 0x4c, 0x17, 0x48, 0xec, 0x4d, 0x67, 0x0e, 0x03, 0x03, 0x0f,
+ 0x0a, 0x0e, 0x12, 0x21, 0xc0, 0xd7, 0x9f, 0x23, 0x09, 0x09, 0x10, 0x40,
0x8d, 0x27, 0x40, 0xb2, 0x40, 0xd0, 0x41, 0x65, 0x40, 0x79, 0x40, 0x83,
- 0x0a, 0x41, 0xf6, 0x04, 0x40, 0x88, 0x41, 0x3f, 0x40, 0x65, 0x0a, 0x0a,
- 0x40, 0x55, 0x40, 0xe2, 0x0f, 0x88, 0x6d, 0x55, 0x5c, 0x1f, 0xea, 0xe0,
- 0xd0, 0x95, 0x6c, 0x42, 0x7c, 0x1f, 0x6c, 0xc4, 0xe0, 0xb1, 0xd5, 0x6b,
- 0x4b, 0x77, 0x9f, 0x02, 0x85, 0x6c, 0xfb, 0xe0, 0xd1, 0x7e, 0x6b, 0xc4,
- 0xe0, 0xd0, 0xc7, 0xe9, 0x0a, 0x08, 0x09, 0x05, 0x16, 0x07, 0x14, 0x0f,
- 0x18, 0x8c, 0x79, 0x7f, 0x1f, 0x65, 0x45, 0xd0, 0xc2, 0x49, 0x73, 0x65,
- 0x1f, 0x65, 0x4f, 0xd6, 0xe0, 0xd1, 0x71, 0x6b, 0x58, 0x9f, 0xc2, 0x0c,
- 0x66, 0x59, 0x9f, 0x03, 0xc1, 0x2c, 0xe6, 0x04, 0xe0, 0x40, 0xc5, 0x60,
- 0x7c, 0x1f, 0x69, 0x47, 0x4c, 0x1f, 0x66, 0xcb, 0xc4, 0x43, 0x64, 0x50,
- 0x1f, 0x65, 0xce, 0xc9, 0xdc, 0xe3, 0x02, 0x86, 0x5f, 0x1f, 0x65, 0xd3,
- 0xc8, 0xe7, 0x5e, 0x1f, 0x65, 0x48, 0x69, 0x1f, 0x66, 0xf5, 0xe0, 0xc8,
- 0x14, 0xdd, 0x02, 0x86, 0x59, 0x1f, 0xe5, 0xe0, 0xca, 0xf3, 0x52, 0x1f,
- 0x66, 0xe3, 0xde, 0x44, 0xdb, 0x02, 0x8e, 0x7b, 0x1f, 0x68, 0x68, 0x4a,
- 0x1f, 0x67, 0x5b, 0x48, 0x1f, 0x67, 0xe7, 0xc3, 0x79, 0x46, 0x1f, 0x65,
- 0xdb, 0xe0, 0xc8, 0xc2, 0x55, 0x77, 0x9f, 0x02, 0x84, 0x69, 0xc7, 0xc2,
- 0x2e, 0xe5, 0xc2, 0x28, 0x40, 0x5a, 0x1f, 0x68, 0xf2, 0xe0, 0xd0, 0x91,
- 0xe8, 0x05, 0x08, 0x07, 0x06, 0x85, 0x74, 0x6d, 0x1f, 0x67, 0xc9, 0xe0,
- 0xd0, 0x83, 0x70, 0x77, 0x1f, 0x66, 0xed, 0xc3, 0x68, 0x4c, 0x68, 0x1f,
- 0xe5, 0xc2, 0x07, 0x47, 0x7a, 0x9f, 0xc2, 0x8d, 0x41, 0x54, 0x1f, 0x69,
- 0xc0, 0xc3, 0x0e, 0xe7, 0x0c, 0x07, 0x1d, 0x13, 0x16, 0x14, 0x04, 0x12,
- 0x11, 0x07, 0x09, 0x87, 0x7e, 0x64, 0x1f, 0x69, 0xe6, 0xd2, 0x2d, 0x7d,
- 0x51, 0x9f, 0x02, 0x91, 0xe7, 0x03, 0x07, 0x83, 0x7b, 0xdc, 0x56, 0xa8,
- 0xe0, 0xbb, 0xb2, 0xf5, 0xcf, 0x5b, 0xeb, 0xc1, 0xf2, 0xe5, 0x03, 0xc2,
- 0x3c, 0xdd, 0xc8, 0x09, 0x7b, 0x44, 0x1f, 0xe7, 0x02, 0x89, 0x7b, 0xc7,
- 0x03, 0xd9, 0xce, 0x1f, 0xe6, 0xc0, 0xc2, 0x79, 0xd4, 0xd9, 0xc8, 0x76,
- 0x72, 0x9f, 0x02, 0x86, 0x68, 0x77, 0xef, 0xe0, 0xa5, 0x9d, 0xe7, 0x02,
- 0x84, 0x7b, 0xdc, 0xd9, 0xb6, 0x75, 0xe1, 0xc2, 0x64, 0x75, 0x44, 0x1f,
- 0xe7, 0x02, 0x84, 0x7b, 0xc7, 0xd9, 0xa8, 0x79, 0x54, 0xae, 0x42, 0x77,
- 0x60, 0x91, 0x10, 0xdf, 0x38, 0x6e, 0xc7, 0xc2, 0xda, 0xe7, 0x02, 0x87,
- 0x7b, 0x1f, 0x65, 0xca, 0xe0, 0xd0, 0x62, 0x4b, 0x1f, 0x67, 0x54, 0xf0,
- 0xe0, 0xd0, 0x55, 0x66, 0x4f, 0x9f, 0x02, 0x86, 0xe5, 0x41, 0x1e, 0xe0,
- 0xc8, 0xef, 0x64, 0x7a, 0xd5, 0xe0, 0xd0, 0x44, 0x65, 0x5e, 0x1f, 0x65,
- 0x65, 0xc8, 0x83, 0x5f, 0x73, 0x1f, 0x65, 0x77, 0xdd, 0xe0, 0xd0, 0x34,
- 0x46, 0x4a, 0x1f, 0x66, 0xdc, 0xd1, 0x95, 0x42, 0x79, 0x1f, 0xe7, 0xc2,
- 0x8c, 0xe6, 0x12, 0x0d, 0x04, 0x07, 0x0c, 0x09, 0x07, 0x07, 0x07, 0x06,
- 0x07, 0x19, 0x11, 0x11, 0x09, 0x08, 0x0b, 0x87, 0x7e, 0x73, 0x1f, 0xe9,
- 0x02, 0x84, 0xd7, 0xe0, 0xd0, 0x0f, 0xd6, 0xc7, 0x68, 0x7b, 0xcb, 0xc2,
- 0x2c, 0x78, 0x78, 0x1f, 0x66, 0xc8, 0xc3, 0xcc, 0x77, 0x61, 0x1f, 0x69,
- 0x69, 0x6c, 0x1f, 0x69, 0xd4, 0xe0, 0xcf, 0xfa, 0x72, 0x56, 0x1f, 0x67,
- 0x78, 0xc4, 0xe0, 0xcf, 0xe7, 0x60, 0x43, 0x1f, 0x66, 0xdc, 0xdc, 0x73,
- 0x5d, 0x71, 0x1f, 0x64, 0xfa, 0xd1, 0x41, 0x5c, 0x7a, 0x1f, 0x66, 0xde,
- 0xc7, 0x6c, 0x5b, 0x78, 0x1f, 0xe7, 0xc3, 0xd2, 0x57, 0x76, 0x1f, 0x65,
- 0xf0, 0xc1, 0xfa, 0x56, 0x70, 0x9f, 0x03, 0x04, 0x86, 0x69, 0xd7, 0xc8,
- 0x4d, 0x66, 0x7d, 0xdf, 0xe0, 0xcf, 0xb5, 0x65, 0x4a, 0x60, 0x1f, 0x65,
- 0xdd, 0xe0, 0xcf, 0xb6, 0xd5, 0x02, 0x87, 0x59, 0x1f, 0x68, 0x42, 0xf2,
- 0xc1, 0xa4, 0x4e, 0x1f, 0x68, 0x42, 0xf2, 0xd8, 0xce, 0x54, 0x7f, 0x1f,
- 0xe5, 0x02, 0x87, 0x7a, 0xdc, 0x41, 0x93, 0xe0, 0xcf, 0xa0, 0xca, 0xe0,
- 0xcf, 0x94, 0x4b, 0x5b, 0x1f, 0x68, 0x41, 0xd8, 0xe0, 0xd1, 0x24, 0x49,
- 0x4b, 0x1f, 0x66, 0xdc, 0xe0, 0xce, 0xb0, 0x48, 0x51, 0x1f, 0x67, 0x48,
- 0x71, 0x1f, 0x64, 0xfd, 0xc2, 0x3c, 0x45, 0x48, 0x1f, 0x65, 0xd6, 0xc7,
- 0x01, 0x44, 0x5b, 0x9f, 0x02, 0x85, 0x67, 0xdf, 0xe0, 0xcc, 0x61, 0x65,
- 0x6a, 0xdb, 0xe0, 0xcf, 0x57, 0xe5, 0x16, 0x0b, 0x09, 0x07, 0x07, 0x17,
- 0x14, 0x03, 0x15, 0x09, 0x08, 0x23, 0x07, 0x09, 0x15, 0x1b, 0x0d, 0x0e,
- 0x09, 0x0d, 0x28, 0x88, 0xfe, 0x02, 0x82, 0xf3, 0x89, 0x6e, 0x1f, 0x65,
- 0xcd, 0xc1, 0x6a, 0x7a, 0x43, 0x1f, 0x65, 0x73, 0xf6, 0xe0, 0xcf, 0x2c,
- 0x79, 0x7f, 0x1f, 0x64, 0xf8, 0xc6, 0x5d, 0x73, 0x76, 0x1f, 0x66, 0xe0,
- 0xd7, 0xb6, 0xf2, 0x03, 0x08, 0x83, 0x69, 0x1f, 0x66, 0x49, 0xcb, 0xe0,
- 0xcf, 0x12, 0xe1, 0xc0, 0xb0, 0x50, 0x1f, 0x69, 0x58, 0xdc, 0xe0, 0xcf,
- 0x07, 0x71, 0x71, 0x9f, 0x02, 0x84, 0x66, 0xe2, 0xdb, 0x91, 0xe5, 0x02,
- 0x85, 0x7d, 0xe2, 0xe0, 0xce, 0xf6, 0xcf, 0xda, 0xae, 0xef, 0xc0, 0x90,
- 0xee, 0x02, 0x86, 0x76, 0x1f, 0x69, 0xdb, 0xc7, 0x79, 0x6e, 0x1f, 0xe5,
- 0x02, 0x82, 0xf4, 0x82, 0x5f, 0xce, 0xe0, 0xce, 0xdb, 0x68, 0x71, 0x1f,
- 0x64, 0x79, 0xd0, 0xe0, 0xd0, 0x75, 0x65, 0x48, 0x1f, 0x68, 0xc9, 0xe0,
- 0xce, 0xc9, 0xe4, 0x02, 0x8c, 0x69, 0x1f, 0x64, 0x78, 0x7b, 0x1f, 0x66,
- 0x55, 0xd9, 0xe0, 0xd0, 0x5e, 0x67, 0x9f, 0x03, 0x06, 0x83, 0x69, 0x58,
- 0xea, 0xe0, 0xce, 0xb0, 0x66, 0xcb, 0x93, 0x65, 0x48, 0xc6, 0xe0, 0xce,
- 0xa7, 0x5f, 0x7c, 0x1f, 0x67, 0xce, 0xc0, 0x5b, 0x5c, 0x68, 0x1f, 0x67,
- 0x7a, 0xff, 0xe0, 0xd0, 0x3a, 0x58, 0x49, 0x1f, 0x69, 0x47, 0xcc, 0x04,
- 0xe0, 0xd0, 0x2d, 0x1f, 0x65, 0x64, 0x67, 0x1f, 0x69, 0x45, 0x52, 0x1f,
- 0xe5, 0x94, 0x55, 0x46, 0x9f, 0x02, 0x8b, 0xe6, 0x02, 0x85, 0x65, 0xed,
- 0xe0, 0xa3, 0x88, 0xe0, 0xc4, 0xe4, 0xe5, 0x02, 0x85, 0x7a, 0xd7, 0xe0,
- 0xd0, 0x0d, 0xdf, 0xc6, 0xb1, 0x52, 0x4c, 0x1f, 0x66, 0x6d, 0x4c, 0x1f,
- 0x65, 0x71, 0xf1, 0xe0, 0xce, 0x5a, 0x4f, 0x70, 0x9f, 0x02, 0x85, 0x67,
- 0xc1, 0xe0, 0xc4, 0x0b, 0x66, 0xf9, 0xc3, 0x02, 0x4d, 0x43, 0x1f, 0x68,
- 0x51, 0xc9, 0xe0, 0xce, 0x43, 0x4c, 0x57, 0x1f, 0x66, 0x75, 0x77, 0x1f,
- 0x69, 0x41, 0xd3, 0xe0, 0xce, 0x36, 0xc5, 0x03, 0x06, 0x97, 0x75, 0x1f,
- 0x65, 0xfa, 0xda, 0x3f, 0x6c, 0x9f, 0x02, 0x84, 0x67, 0xdb, 0xc4, 0xf7,
- 0x65, 0x4f, 0xf8, 0x04, 0xe0, 0xcf, 0xbd, 0xae, 0x21, 0x60, 0x91, 0x10,
- 0xe0, 0x3a, 0x09, 0x6b, 0x1f, 0x65, 0xcd, 0xe0, 0xc4, 0xe7, 0x41, 0x65,
- 0x1f, 0x65, 0xfa, 0xe0, 0xcd, 0x40, 0x40, 0x4b, 0x1f, 0x64, 0x7a, 0x7a,
- 0xae, 0x04, 0xe0, 0x91, 0x10, 0x1f, 0x69, 0x66, 0x59, 0x1f, 0xe6, 0xe0,
- 0x3d, 0x59, 0xe4, 0x05, 0x08, 0x12, 0x09, 0x95, 0x7f, 0x61, 0x1f, 0x66,
- 0xc1, 0xe0, 0xce, 0x0a, 0xfd, 0x02, 0x87, 0x5b, 0x1f, 0x65, 0xf1, 0xe0,
- 0xae, 0x12, 0x50, 0x1f, 0x68, 0x73, 0xc0, 0xe0, 0xcd, 0xd2, 0x7c, 0x41,
- 0x1f, 0x64, 0x78, 0xda, 0xe0, 0xcf, 0x6c, 0xfa, 0x02, 0x88, 0x6c, 0x1f,
- 0x69, 0x43, 0xfd, 0xe0, 0xcd, 0xbe, 0x5a, 0x1f, 0x69, 0x69, 0x6c, 0x1f,
- 0x69, 0xc0, 0xc4, 0x87, 0xf8, 0x04, 0x1f, 0x07, 0x88, 0x6d, 0x9f, 0x03,
- 0x0a, 0x8b, 0x66, 0x56, 0x47, 0x1f, 0x67, 0x7d, 0xd1, 0xe0, 0xcf, 0x43,
- 0xe5, 0x02, 0x85, 0x5c, 0xcb, 0xe0, 0xcf, 0x3b, 0xdb, 0xc5, 0x93, 0x64,
- 0xff, 0xe0, 0xcd, 0x9a, 0x6a, 0x1f, 0x64, 0x7a, 0xfa, 0xd6, 0xbc, 0x56,
- 0x1f, 0x67, 0x55, 0xcc, 0xe0, 0xcf, 0x24, 0x49, 0x1f, 0x69, 0x47, 0xcd,
- 0xe0, 0xcd, 0x79, 0xe3, 0x04, 0x24, 0xc0, 0x4e, 0xc3, 0x02, 0x8e, 0x5d,
- 0x1f, 0x63, 0x42, 0x64, 0x1f, 0x63, 0x43, 0x73, 0x1f, 0x63, 0xc3, 0xc4,
- 0x14, 0x55, 0x1f, 0x63, 0x42, 0x61, 0x1f, 0x63, 0x43, 0x43, 0x1f, 0x63,
- 0x42, 0x77, 0x1f, 0x63, 0x43, 0xe7, 0xc0, 0x4a, 0xc2, 0x06, 0x06, 0x0b,
- 0x08, 0x0f, 0x90, 0x7b, 0x1f, 0x63, 0x43, 0xfc, 0x9d, 0x79, 0x1f, 0x63,
- 0x43, 0x48, 0x1f, 0x63, 0xc2, 0xe0, 0xc4, 0xe6, 0x73, 0x1f, 0x63, 0x43,
- 0xe0, 0xe0, 0xce, 0xd3, 0x70, 0x1f, 0x63, 0x43, 0x7c, 0x1f, 0x63, 0x42,
- 0x70, 0x1f, 0x63, 0xc3, 0xe0, 0xcc, 0x65, 0x6f, 0x1f, 0x63, 0x43, 0x69,
- 0x1f, 0x63, 0x42, 0x66, 0x1f, 0x63, 0x43, 0xc9, 0xe0, 0xce, 0xb4, 0x62,
- 0x1f, 0x63, 0x43, 0x5e, 0x1f, 0x63, 0x42, 0x7e, 0x1f, 0x63, 0xc3, 0xe0,
- 0xcc, 0x43, 0x41, 0x7f, 0x1f, 0x63, 0x42, 0x53, 0x1f, 0x63, 0xc1, 0xe0,
- 0xcc, 0x60, 0x61, 0x43, 0x52, 0x1f, 0x61, 0x43, 0xd4, 0xe0, 0xce, 0x8f,
- 0xe0, 0x0f, 0x0c, 0x13, 0x40, 0x7e, 0x11, 0x13, 0x0f, 0x13, 0x40, 0x5b,
- 0x0e, 0x10, 0x0e, 0xaa, 0x7a, 0x65, 0x1f, 0x60, 0x7a, 0x72, 0x1f, 0x60,
- 0xfa, 0xe0, 0xce, 0x72, 0xf9, 0x03, 0xc0, 0x78, 0x40, 0x1f, 0x60, 0x78,
- 0x59, 0x1f, 0x60, 0x79, 0x47, 0x1f, 0x60, 0x78, 0xd5, 0xc0, 0x67, 0xf8,
- 0x06, 0x13, 0x12, 0x16, 0x16, 0x9c, 0x6d, 0x1f, 0x60, 0x78, 0x47, 0x1f,
- 0x60, 0x78, 0x44, 0x1f, 0x60, 0x79, 0x4c, 0x1f, 0x60, 0x78, 0xc1, 0xc0,
- 0x49, 0x68, 0x1f, 0x60, 0x78, 0x76, 0x1f, 0x60, 0x78, 0x41, 0x1f, 0x60,
- 0x78, 0x69, 0x1f, 0x60, 0x78, 0xf2, 0xba, 0x63, 0x1f, 0x60, 0x78, 0x71,
- 0x1f, 0x60, 0x78, 0x50, 0x1f, 0x60, 0x78, 0x5a, 0x1f, 0x60, 0x78, 0x72,
- 0x1f, 0x60, 0x78, 0xe5, 0xa4, 0x58, 0x1f, 0x60, 0x78, 0x78, 0x1f, 0x60,
- 0x78, 0x63, 0x1f, 0x60, 0x78, 0x41, 0x1f, 0x60, 0x78, 0x74, 0x1f, 0x60,
- 0x78, 0xc8, 0x8e, 0x57, 0x1f, 0x60, 0x78, 0x6b, 0x1f, 0x60, 0x78, 0x72,
- 0x1f, 0x60, 0x78, 0x63, 0x2e, 0x1f, 0x60, 0x79, 0x44, 0x1f, 0x60, 0x78,
- 0x57, 0x1f, 0x60, 0xf8, 0xe0, 0xc3, 0xf7, 0x44, 0x1f, 0x60, 0x78, 0x6d,
- 0x1f, 0xe0, 0xe0, 0x6d, 0xb9, 0x76, 0x7d, 0x1f, 0x60, 0x76, 0x42, 0x1f,
- 0x60, 0x76, 0x5a, 0x1f, 0x60, 0x77, 0xcf, 0xe0, 0xcd, 0xd1, 0x74, 0x6d,
- 0x1f, 0x60, 0x74, 0x7e, 0x1f, 0x60, 0x74, 0x70, 0x1f, 0x60, 0x74, 0x64,
- 0x1f, 0x60, 0xf4, 0xc3, 0xac, 0x72, 0x6d, 0x1f, 0x60, 0x72, 0x7e, 0x1f,
- 0x60, 0x72, 0x70, 0x1f, 0xe0, 0xe0, 0xbe, 0x25, 0x70, 0x6d, 0x1f, 0x60,
- 0x70, 0x7e, 0x1f, 0x60, 0x70, 0x70, 0x1f, 0x60, 0x70, 0x64, 0x1f, 0x60,
- 0xf1, 0xc0, 0xeb, 0xee, 0x02, 0xaa, 0x5a, 0x1f, 0x60, 0x6e, 0x7f, 0x1f,
- 0x60, 0x6e, 0x59, 0x1f, 0x60, 0x6f, 0x4d, 0x1f, 0x60, 0x6e, 0x55, 0x1f,
- 0x60, 0x6e, 0x6a, 0x1f, 0x60, 0x6f, 0x4d, 0x1f, 0x60, 0x6e, 0x6a, 0x1f,
- 0x60, 0x6f, 0x42, 0x1f, 0x60, 0x6e, 0x70, 0x1f, 0x60, 0xef, 0xc0, 0xbe,
- 0x47, 0x1f, 0x60, 0xee, 0x02, 0x92, 0x72, 0x1f, 0x60, 0x6e, 0x59, 0x1f,
- 0x60, 0x6f, 0x4d, 0x1f, 0x60, 0x6e, 0x55, 0x1f, 0x60, 0xef, 0xc2, 0x65,
- 0x68, 0x1f, 0x60, 0x6f, 0x4d, 0x1f, 0x60, 0x6e, 0x64, 0x1f, 0x60, 0x6e,
- 0x7f, 0x1f, 0x60, 0x6e, 0x6f, 0x1f, 0x60, 0xee, 0xc0, 0x54, 0x6c, 0x6d,
- 0x1f, 0x60, 0x6c, 0x7e, 0x1f, 0x60, 0x6c, 0x70, 0x1f, 0xe0, 0xd9, 0x74,
- 0x6a, 0x6d, 0x1f, 0x60, 0x6a, 0x7e, 0x1f, 0x60, 0x6a, 0x70, 0x1f, 0x60,
- 0xea, 0xe0, 0xca, 0xde, 0x68, 0x6d, 0x1f, 0x60, 0x68, 0x7e, 0x1f, 0x60,
- 0x68, 0x70, 0x1f, 0xe0, 0xce, 0xa2, 0xe6, 0x02, 0x93, 0x6d, 0x1f, 0x60,
- 0x66, 0x7e, 0x1f, 0xe0, 0x02, 0x82, 0xe7, 0x82, 0x66, 0x70, 0x1f, 0x60,
- 0xe6, 0xe0, 0xca, 0xba, 0x6c, 0x1f, 0x60, 0x66, 0x7e, 0x1f, 0x60, 0x66,
- 0x42, 0x1f, 0x60, 0x66, 0x72, 0x1f, 0x60, 0x66, 0xfe, 0xe0, 0xcc, 0xeb,
- 0xe4, 0x04, 0x11, 0x26, 0x8c, 0x78, 0x1f, 0x60, 0x64, 0x42, 0x1f, 0x60,
- 0x64, 0x57, 0x1f, 0x60, 0x64, 0x60, 0x1f, 0xe0, 0xcc, 0xb0, 0x6d, 0x1f,
- 0x60, 0x64, 0x7e, 0x1f, 0x60, 0x64, 0x70, 0x1f, 0xe0, 0x02, 0x88, 0x65,
- 0x4b, 0x1f, 0x60, 0xe4, 0xe0, 0xca, 0x7b, 0x64, 0xe4, 0x04, 0xe0, 0xcc,
- 0xb7, 0x1f, 0x60, 0x64, 0x6e, 0x1f, 0x60, 0x65, 0xcd, 0xe0, 0xcc, 0xaf,
- 0x68, 0x1f, 0x60, 0x65, 0x47, 0x1f, 0x60, 0x64, 0xdf, 0xe0, 0xcc, 0xa3,
- 0x55, 0x1f, 0x60, 0x65, 0x49, 0x1f, 0xe0, 0xe0, 0xc6, 0xee, 0x5a, 0xc0,
- 0xc0, 0xd9, 0xd9, 0x06, 0x14, 0x0d, 0x34, 0x1a, 0x86, 0x7e, 0x1f, 0x58,
- 0x67, 0x9f, 0x02, 0x83, 0x5a, 0xe9, 0x83, 0x59, 0x43, 0x1f, 0x58, 0x73,
- 0x1f, 0x58, 0xea, 0xc1, 0x27, 0x47, 0x1f, 0x59, 0x45, 0x1f, 0x58, 0x71,
- 0x1f, 0x58, 0x67, 0x9f, 0xc1, 0x3b, 0x45, 0x9f, 0x02, 0xac, 0xd9, 0x02,
- 0x9a, 0x48, 0x9f, 0x02, 0x87, 0x59, 0x42, 0x1f, 0xd8, 0xe0, 0xca, 0x2b,
- 0x58, 0x71, 0x1f, 0x59, 0x4a, 0x1f, 0x58, 0x6a, 0x1f, 0x58, 0x67, 0x1f,
- 0x59, 0xc6, 0x88, 0x44, 0x1f, 0x59, 0x4a, 0x1f, 0x58, 0x73, 0x1f, 0x59,
- 0x4a, 0x1f, 0xd8, 0xe0, 0xcc, 0x3c, 0x58, 0xf5, 0xc1, 0x1a, 0x43, 0x9f,
- 0x02, 0x86, 0x59, 0x48, 0x1f, 0xd9, 0xc3, 0x19, 0x58, 0x67, 0x1f, 0x58,
- 0x6b, 0x1f, 0x59, 0x48, 0x1f, 0x59, 0x44, 0x1f, 0x59, 0xca, 0xc0, 0x6e,
- 0x42, 0x1f, 0x58, 0xf7, 0xc0, 0xfa, 0x41, 0x1f, 0x59, 0x44, 0x1f, 0x58,
- 0x73, 0x1f, 0x58, 0xf7, 0xc0, 0xfa, 0xd8, 0x06, 0x15, 0x0a, 0x16, 0x0c,
- 0xa5, 0x79, 0x9f, 0x02, 0x84, 0x59, 0xc5, 0xc0, 0xab, 0x58, 0x71, 0x1f,
- 0xd8, 0x04, 0xe0, 0xca, 0x55, 0x67, 0x1f, 0xd9, 0xc1, 0xdf, 0x74, 0x1f,
- 0x58, 0x68, 0x1f, 0x59, 0x43, 0x9f, 0xc0, 0xba, 0x73, 0x1f, 0x59, 0x48,
- 0x1f, 0xd8, 0x02, 0x8b, 0x71, 0x1f, 0x59, 0x4a, 0x1f, 0xd8, 0x60, 0xc9,
- 0xc4, 0xc2, 0x11, 0xef, 0xc0, 0x7e, 0x6a, 0x1f, 0x59, 0x48, 0x1f, 0x59,
- 0x46, 0x1f, 0xd8, 0xe0, 0xc9, 0x63, 0x68, 0x9f, 0x03, 0x08, 0x89, 0x5a,
- 0x7e, 0x1f, 0x58, 0x67, 0x1f, 0xd8, 0x96, 0x59, 0x4a, 0x1f, 0x58, 0x6a,
- 0x1f, 0xd9, 0xc0, 0x74, 0x58, 0x67, 0x1f, 0xd8, 0x02, 0x86, 0x72, 0x1f,
- 0x58, 0xe7, 0xc0, 0x84, 0xf1, 0xc0, 0xbf, 0x67, 0x9f, 0x04, 0x03, 0xc0,
- 0x93, 0x5b, 0xcc, 0x86, 0xd9, 0x03, 0x0f, 0x89, 0x4a, 0x1f, 0x58, 0x71,
- 0x1f, 0x58, 0x67, 0x1f, 0x59, 0xc6, 0x4d, 0xd5, 0xe0, 0xbd, 0xb1, 0x45,
- 0x1f, 0x58, 0x67, 0x1f, 0x58, 0xf1, 0xc0, 0x97, 0x44, 0x9f, 0x02, 0x95,
- 0xd9, 0x02, 0x86, 0x4a, 0x1f, 0x59, 0xc5, 0xc0, 0x66, 0x45, 0x1f, 0x58,
- 0x7a, 0x1f, 0x58, 0x71, 0x1f, 0xd8, 0xe0, 0xc9, 0xc4, 0xd8, 0x05, 0x0c,
- 0x25, 0x0f, 0x8b, 0x79, 0x1f, 0x59, 0x44, 0x1f, 0x59, 0x4a, 0x1f, 0x58,
- 0xe7, 0xc0, 0x48, 0x73, 0x1f, 0x58, 0x79, 0x1f, 0x59, 0x48, 0x1f, 0x58,
- 0x6f, 0x9f, 0x02, 0x8a, 0x5b, 0x4c, 0x9f, 0x02, 0x8f, 0x5b, 0xc3, 0xe0,
- 0xcb, 0x39, 0x59, 0x4a, 0x9f, 0x02, 0x85, 0x59, 0xc7, 0xe0, 0xcb, 0x2f,
- 0xd8, 0xe0, 0xc9, 0x19, 0x6c, 0x1f, 0x58, 0x72, 0x1f, 0x58, 0x67, 0x1f,
- 0x58, 0x66, 0x1f, 0xd8, 0xe0, 0xa9, 0xb1, 0x68, 0x1f, 0x58, 0x6d, 0x1f,
- 0x58, 0x71, 0x1f, 0x59, 0xca, 0x88, 0x67, 0x1f, 0x58, 0x71, 0x1f, 0x58,
- 0x6f, 0x1f, 0x59, 0xc6, 0xe0, 0xcb, 0x04, 0xd8, 0x03, 0x10, 0x92, 0x71,
- 0x1f, 0x58, 0x67, 0x1f, 0x59, 0x45, 0x1f, 0x59, 0x43, 0x1f, 0x59, 0xc8,
- 0xe0, 0xca, 0xf0, 0x6a, 0x1f, 0x58, 0x75, 0x1f, 0x58, 0x67, 0x1f, 0x59,
- 0x44, 0x1f, 0x58, 0x67, 0x1f, 0xd8, 0xe0, 0xc8, 0xa5, 0x68, 0x1f, 0x59,
- 0x48, 0x1f, 0x58, 0x78, 0x1f, 0x58, 0x68, 0x1f, 0x59, 0xca, 0xe0, 0xca,
- 0xce, 0xd7, 0x05, 0x0a, 0x05, 0x0b, 0xa2, 0x67, 0x1f, 0x57, 0x55, 0x1f,
- 0x57, 0xdd, 0xe0, 0xca, 0xbe, 0x66, 0x1f, 0x57, 0xd4, 0x88, 0x5e, 0x1f,
- 0x57, 0x5e, 0x1f, 0x57, 0x69, 0x1f, 0x57, 0xdc, 0xb3, 0x59, 0x1f, 0xd7,
- 0x02, 0x8a, 0x69, 0x1f, 0xd7, 0x02, 0xb1, 0x55, 0x1f, 0x57, 0xd1, 0xa4,
- 0x68, 0x1f, 0x57, 0x55, 0x1f, 0x57, 0x69, 0x1f, 0x57, 0x5c, 0x1f, 0x57,
- 0x59, 0x1f, 0x57, 0xdd, 0xe0, 0xc7, 0xd3, 0x50, 0x1f, 0x57, 0x67, 0x1f,
- 0x57, 0x53, 0x1f, 0x57, 0x5e, 0x1f, 0x57, 0x59, 0x1f, 0x57, 0x54, 0x2e,
- 0x1f, 0x57, 0x59, 0x1f, 0x57, 0x69, 0x1f, 0x57, 0x68, 0x1f, 0x57, 0x50,
- 0x1f, 0x57, 0xdc, 0xe0, 0xca, 0x69, 0x55, 0x70, 0x1f, 0x55, 0x61, 0x1f,
- 0xd5, 0xe0, 0xc9, 0x6c, 0x52, 0x5b, 0x1f, 0x50, 0x70, 0x1f, 0xd0, 0xe0,
- 0xc7, 0xec, 0xd1, 0x04, 0x03, 0x0d, 0xb0, 0xcf, 0xc1, 0x10, 0x43, 0x1f,
- 0xd0, 0x03, 0xc0, 0x51, 0x7a, 0x1f, 0x51, 0xc0, 0xe0, 0xca, 0x40, 0x41,
- 0x9f, 0x03, 0xc1, 0x16, 0xd0, 0x03, 0x06, 0x89, 0x7f, 0x1f, 0x50, 0xf1,
- 0xc0, 0xf4, 0x7e, 0x1f, 0x51, 0x47, 0x1f, 0x50, 0xf8, 0xc0, 0xeb, 0x70,
- 0x1f, 0xd0, 0x02, 0x8c, 0x7c, 0x1f, 0x50, 0x70, 0x1f, 0x51, 0x40, 0x1f,
- 0x50, 0xf0, 0xc0, 0xda, 0x79, 0x1f, 0x51, 0xc2, 0xe0, 0xca, 0x10, 0x40,
- 0x1f, 0xd1, 0x02, 0x84, 0xc4, 0xe0, 0xca, 0x07, 0x43, 0x1f, 0x51, 0xc1,
- 0xe0, 0xca, 0x00, 0xd0, 0x09, 0x02, 0x2c, 0x31, 0x2c, 0x0d, 0x07, 0x0c,
- 0x9d, 0xff, 0xa8, 0x7e, 0x9f, 0x02, 0x8f, 0x51, 0x40, 0x1f, 0x50, 0xf3,
- 0x04, 0xe0, 0xc9, 0xe4, 0x2e, 0x1f, 0xd1, 0x40, 0xa8, 0x95, 0xd0, 0x03,
- 0x0c, 0x83, 0x7d, 0x1f, 0x50, 0x7b, 0x1f, 0x50, 0x70, 0x1f, 0x50, 0x79,
- 0x9f, 0xaa, 0xf4, 0xc0, 0xa6, 0x71, 0x1f, 0x51, 0xc0, 0xc0, 0xa0, 0x7c,
- 0x9f, 0x02, 0x87, 0x51, 0x41, 0x1f, 0x50, 0xfa, 0xc0, 0x80, 0xd0, 0x03,
- 0x16, 0x86, 0x7e, 0x9f, 0x02, 0x8d, 0x51, 0x41, 0x1f, 0x50, 0x7a, 0x1f,
- 0x50, 0x72, 0x1f, 0xd0, 0xe0, 0xc8, 0x19, 0x50, 0xfd, 0xe0, 0xc9, 0xa3,
- 0x7a, 0x1f, 0xd0, 0xe0, 0xc7, 0xe6, 0x78, 0x1f, 0x51, 0xc0, 0xc0, 0x5a,
- 0x7a, 0x9f, 0x02, 0x8a, 0x51, 0x40, 0x1f, 0x51, 0x4b, 0x1f, 0x50, 0xfc,
- 0xc0, 0x4c, 0xd0, 0x02, 0x89, 0x7e, 0x1f, 0x50, 0xfc, 0x40, 0x43, 0xe0,
- 0xc9, 0x3c, 0x70, 0x1f, 0x51, 0x42, 0x1f, 0x50, 0x7e, 0x1f, 0x50, 0x7b,
- 0x1f, 0x50, 0x78, 0x1f, 0xd0, 0xe0, 0xc6, 0xff, 0x78, 0x1f, 0x50, 0x7a,
- 0x1f, 0x50, 0x7e, 0x1f, 0x50, 0xfc, 0xe0, 0xc6, 0xa5, 0x75, 0x1f, 0x51,
- 0xce, 0xe0, 0xc9, 0x57, 0x74, 0x1f, 0x50, 0x75, 0x1f, 0x51, 0x42, 0x1f,
- 0xd0, 0xe0, 0xc1, 0xe6, 0x71, 0x1f, 0xd0, 0x05, 0x11, 0xe0, 0xc6, 0xcd,
- 0x78, 0x1f, 0x50, 0x77, 0x2e, 0x1f, 0x51, 0x40, 0x1f, 0x51, 0x43, 0x1f,
- 0x51, 0xc1, 0xe0, 0xc9, 0x2e, 0x75, 0x1f, 0xd0, 0x9c, 0x70, 0x1f, 0x50,
- 0x7a, 0x2e, 0x1f, 0x51, 0x41, 0x1f, 0x51, 0x40, 0x1f, 0xd0, 0xe0, 0xa7,
- 0xb3, 0x4e, 0x75, 0x9f, 0x02, 0x85, 0x4f, 0xc5, 0xe0, 0xc9, 0x14, 0x4e,
- 0xfb, 0xe0, 0xc9, 0x0f, 0x44, 0x4d, 0x1f, 0x43, 0xe1, 0xe0, 0xb0, 0xaa,
- 0xc3, 0x03, 0x28, 0xa8, 0xf8, 0x05, 0x08, 0x04, 0x06, 0x8c, 0xf9, 0x60,
- 0x47, 0x3b, 0x11, 0xe0, 0x76, 0x0f, 0xf6, 0xe0, 0x54, 0x17, 0x73, 0x74,
- 0xf2, 0xe0, 0x48, 0x5c, 0xf2, 0x04, 0xe0, 0xbc, 0x13, 0xf3, 0x60, 0x9a,
- 0x56, 0xe0, 0x28, 0xb5, 0xeb, 0xe0, 0x92, 0xb1, 0xe5, 0x0a, 0x08, 0x05,
- 0x0c, 0x60, 0x99, 0x16, 0xe0, 0x20, 0x73, 0xf3, 0x60, 0xbd, 0x62, 0x47,
- 0x45, 0xc2, 0x9e, 0xed, 0x60, 0xc1, 0x43, 0x84, 0xec, 0x07, 0x60, 0x85,
- 0x80, 0xe0, 0x41, 0xb1, 0xe7, 0xe0, 0x49, 0xe7, 0xeb, 0xe0, 0xc2, 0xcb,
- 0xe1, 0x02, 0x8b, 0xec, 0x02, 0x84, 0xf4, 0xe0, 0x87, 0x8e, 0xe1, 0xe0,
- 0xc2, 0x7c, 0x6b, 0x1f, 0x45, 0xcb, 0xe0, 0xc2, 0xc2, 0xfa, 0x13, 0x0e,
- 0x04, 0x08, 0x0d, 0x04, 0x04, 0x12, 0x0d, 0x0c, 0x53, 0xa7, 0x60, 0x88,
- 0x69, 0x60, 0x29, 0xb4, 0x9e, 0xf5, 0x02, 0x85, 0x73, 0xe8, 0xe0, 0xbb,
- 0xf8, 0x65, 0x72, 0xe9, 0xe0, 0xb3, 0x11, 0xf4, 0xe0, 0xac, 0xe8, 0x70,
- 0xae, 0x60, 0x88, 0xc5, 0xe0, 0x24, 0x1f, 0xef, 0x06, 0x60, 0xb2, 0x50,
- 0xcb, 0xe8, 0x6d, 0x62, 0xe9, 0xe0, 0xb9, 0xeb, 0xec, 0xe0, 0xa8, 0xc2,
- 0xe9, 0xe0, 0xc6, 0xcc, 0xe8, 0x02, 0x86, 0x79, 0x74, 0x6f, 0x6d, 0xf9,
- 0x86, 0x69, 0x74, 0x6f, 0x6d, 0x69, 0xf2, 0xe0, 0xac, 0xb9, 0x67, 0x6f,
- 0xf2, 0x04, 0xe0, 0xb9, 0xd0, 0x7a, 0x65, 0xec, 0xe0, 0xb3, 0x20, 0xe5,
- 0x04, 0xe0, 0xc6, 0xb6, 0x6e, 0x74, 0x73, 0xf5, 0xe0, 0x70, 0xe7, 0xe1,
- 0x0a, 0x06, 0x19, 0x08, 0x08, 0x05, 0x0a, 0xe0, 0x27, 0xa1, 0xf2, 0x60,
- 0xbb, 0x5d, 0xcb, 0x2b, 0xf0, 0x03, 0x05, 0x84, 0x74, 0xef, 0xe0, 0xb4,
- 0x7f, 0xf0, 0xe0, 0xa5, 0x57, 0x6f, 0x72, 0x69, 0x7a, 0x68, 0x7a, 0xe8,
- 0x58, 0xf0, 0xe0, 0x22, 0x52, 0x6d, 0xe1, 0x60, 0x87, 0x3d, 0xe0, 0x3c,
- 0x2c, 0x6b, 0x6f, 0x70, 0x61, 0xee, 0xe0, 0x8b, 0x4a, 0x67, 0xe1, 0xe0,
- 0xb6, 0xab, 0x63, 0x68, 0x70, 0x6f, 0x6d, 0x6f, 0xf2, 0xe0, 0xc3, 0x57,
- 0xae, 0x60, 0x87, 0x75, 0x60, 0x3d, 0x9d, 0x42, 0xae, 0x9c, 0xf9, 0x10,
- 0x40, 0x4d, 0x40, 0xd5, 0x09, 0x04, 0x2a, 0x60, 0x9a, 0x53, 0x60, 0x2a,
- 0x66, 0xc0, 0x49, 0xf5, 0x0d, 0x07, 0x0b, 0x0d, 0x0d, 0x0a, 0x04, 0x60,
- 0x80, 0x88, 0xe0, 0x45, 0xce, 0x7a, 0xe1, 0x60, 0x75, 0xf1, 0xd8, 0x60,
- 0x73, 0xf5, 0x04, 0xe0, 0xc0, 0x93, 0x68, 0xe1, 0xe0, 0x55, 0x1f, 0xf2,
- 0x04, 0xe0, 0xbd, 0x44, 0x69, 0x68, 0x6f, 0x6e, 0xea, 0xe0, 0x8e, 0xca,
- 0xeb, 0x04, 0xe0, 0xab, 0x8a, 0x75, 0x68, 0x61, 0x73, 0xe8, 0xe0, 0x7b,
- 0xcb, 0x67, 0x61, 0x77, 0xe1, 0x60, 0x76, 0xcb, 0xe0, 0x4b, 0x75, 0xe6,
- 0xe0, 0xb5, 0xef, 0x61, 0xf3, 0xe0, 0xbd, 0x1f, 0xef, 0x0d, 0x0e, 0x0a,
- 0x2a, 0x11, 0x16, 0x0c, 0x05, 0x3d, 0x09, 0xe0, 0x78, 0xa0, 0xf5, 0x04,
- 0xe0, 0xc7, 0x69, 0xf4, 0x04, 0xe0, 0x91, 0x60, 0xf5, 0xe0, 0xc5, 0x36,
- 0x74, 0x73, 0x75, 0x6b, 0x61, 0x69, 0xe4, 0xe0, 0xc5, 0x81, 0xf3, 0x02,
- 0xa1, 0x68, 0xe9, 0x08, 0x0b, 0x04, 0x60, 0x70, 0xb2, 0xdd, 0xb6, 0x6e,
- 0xef, 0x04, 0xe0, 0xbf, 0x5e, 0x67, 0xe1, 0xe0, 0x7c, 0x2c, 0xeb, 0xe0,
- 0x4a, 0x90, 0x64, 0x61, 0x2e, 0xf3, 0x60, 0xbd, 0x32, 0x88, 0x65, 0x6d,
- 0xe9, 0xe0, 0xaa, 0x82, 0xf2, 0x05, 0x07, 0xe0, 0x89, 0xb2, 0xeb, 0x60,
- 0x50, 0xf8, 0xe0, 0x73, 0x74, 0xe9, 0xe0, 0x74, 0xe7, 0xee, 0x05, 0x04,
- 0xe0, 0x8e, 0x4e, 0xe5, 0xe0, 0x4b, 0xfc, 0xe1, 0x04, 0xe0, 0x85, 0x5a,
- 0xe7, 0x60, 0x36, 0xeb, 0xe0, 0x8b, 0xab, 0xed, 0x02, 0x85, 0x69, 0xf4,
- 0xe0, 0x8a, 0xf9, 0xe2, 0xe0, 0x63, 0x91, 0x6c, 0xe1, 0xe0, 0x2e, 0xad,
- 0xeb, 0x03, 0x21, 0x88, 0xef, 0x06, 0x04, 0x10, 0xe0, 0x4b, 0x5c, 0xfa,
- 0xe0, 0x6e, 0xce, 0xf3, 0x04, 0xe0, 0x81, 0x0b, 0x68, 0x69, 0x62, 0x61,
- 0x68, 0x69, 0x6b, 0xe1, 0xe0, 0x6e, 0x87, 0x68, 0x61, 0xed, 0xe0, 0x54,
- 0x86, 0x6b, 0x61, 0x69, 0x63, 0xe8, 0xe0, 0x6c, 0x15, 0xe1, 0x07, 0x60,
- 0x7b, 0x11, 0xe0, 0x47, 0x00, 0x69, 0x63, 0x68, 0x69, 0xe2, 0xe0, 0x84,
- 0x51, 0xe9, 0x04, 0xe0, 0x6d, 0x3e, 0xf4, 0xe0, 0x74, 0xea, 0x64, 0x6f,
- 0x62, 0xe1, 0xe0, 0x5a, 0x96, 0xee, 0x04, 0xe0, 0xb3, 0x65, 0xe8, 0xe0,
- 0xc6, 0x0f, 0xeb, 0xe0, 0xc5, 0x02, 0x62, 0x6f, 0xae, 0x05, 0x06, 0x08,
- 0x08, 0x86, 0x74, 0x72, 0xe1, 0xe0, 0xc5, 0xef, 0x73, 0x63, 0x69, 0x65,
- 0xee, 0xe0, 0xa6, 0x4d, 0x72, 0x65, 0x76, 0x69, 0xe5, 0xe0, 0xb2, 0x34,
- 0x70, 0x61, 0xf2, 0xe0, 0x56, 0x10, 0x66, 0x61, 0xe9, 0xe0, 0x7d, 0xd9,
- 0xe1, 0x11, 0x0e, 0x17, 0x20, 0x07, 0x12, 0x40, 0x92, 0x0b, 0x10, 0x09,
- 0x0f, 0x04, 0x16, 0xe0, 0xa8, 0x88, 0x77, 0xe1, 0x04, 0xe0, 0x6e, 0x38,
- 0x74, 0xe1, 0x60, 0x4f, 0x45, 0xe0, 0x69, 0x51, 0xf4, 0x02, 0x8f, 0x73,
- 0xf5, 0x02, 0x87, 0x73, 0x68, 0x69, 0xf2, 0xe0, 0xbc, 0x31, 0xeb, 0xe0,
- 0x84, 0x29, 0x6f, 0xed, 0xe0, 0xc1, 0x13, 0xf3, 0x05, 0x10, 0xe0, 0x7b,
- 0x59, 0xf5, 0x07, 0x04, 0x60, 0xc0, 0x93, 0xc0, 0x63, 0xef, 0xe0, 0x7b,
- 0x61, 0xe4, 0xe0, 0x57, 0xb6, 0x68, 0xe9, 0x04, 0xe0, 0x8d, 0x5a, 0xf2,
- 0xe0, 0xc0, 0x3c, 0xef, 0x60, 0x6e, 0x3b, 0xe0, 0x56, 0x0f, 0xee, 0x02,
- 0x89, 0x64, 0x65, 0xf8, 0x60, 0x72, 0xa0, 0xe0, 0x53, 0x6c, 0xe1, 0x60,
- 0x36, 0x2c, 0xd8, 0x6f, 0xed, 0x04, 0xe0, 0x67, 0x3a, 0xe1, 0x09, 0x05,
- 0x04, 0x25, 0x07, 0x1f, 0x06, 0x06, 0x98, 0x7a, 0xef, 0xe0, 0x59, 0xd5,
- 0xf8, 0xe0, 0x9f, 0xb2, 0xf4, 0x02, 0x85, 0x73, 0xf5, 0xe0, 0x69, 0x0a,
- 0xef, 0x03, 0x07, 0x87, 0x74, 0x61, 0x6b, 0xe1, 0xe0, 0x44, 0xad, 0x6b,
- 0x6f, 0x72, 0xe9, 0xe0, 0x6f, 0x2d, 0xae, 0x04, 0xe0, 0xc0, 0x7f, 0xeb,
- 0x60, 0xbe, 0xb6, 0xc2, 0x7c, 0x73, 0x68, 0x69, 0xee, 0xe0, 0x8c, 0xa9,
- 0xee, 0x02, 0x8b, 0xef, 0x02, 0x84, 0xf5, 0xe0, 0x2e, 0xa1, 0xe2, 0xe0,
- 0x80, 0xac, 0xe1, 0x02, 0x89, 0x73, 0x68, 0x69, 0xae, 0x60, 0xa8, 0x9d,
- 0xdb, 0x68, 0x6b, 0xe1, 0xe0, 0x8c, 0xf2, 0x6d, 0x6f, 0xf4, 0xe0, 0x25,
- 0x57, 0x6b, 0x69, 0xf4, 0xe0, 0xc0, 0xfb, 0xe7, 0x04, 0xe0, 0xc3, 0x83,
- 0xe1, 0x04, 0xe0, 0xbe, 0x73, 0x74, 0x61, 0xae, 0x60, 0xba, 0x66, 0x42,
- 0xb8, 0x40, 0xf2, 0x44, 0x5f, 0xc1, 0x73, 0x64, 0x61, 0xae, 0x60, 0x8c,
- 0xfa, 0x60, 0x2c, 0xf9, 0xc0, 0x6b, 0xec, 0x02, 0x84, 0xf4, 0xe0, 0xa1,
- 0x31, 0xe9, 0xe0, 0xac, 0x55, 0xeb, 0x02, 0x89, 0x75, 0x6d, 0x6f, 0xae,
- 0x60, 0xbf, 0xcb, 0xc3, 0xe6, 0x61, 0xe7, 0xd4, 0x84, 0xe9, 0x04, 0xe0,
- 0x6c, 0x30, 0xf4, 0xe0, 0xb9, 0xd2, 0xe8, 0x05, 0x04, 0xe0, 0x23, 0x38,
- 0xe9, 0xe0, 0x54, 0x82, 0x61, 0xe2, 0xe0, 0x58, 0xaa, 0x65, 0xf3, 0xd9,
- 0xf6, 0x63, 0xe8, 0x04, 0xe0, 0xbc, 0x1a, 0xe9, 0x02, 0x88, 0x79, 0x6f,
- 0xae, 0x60, 0xbd, 0xb7, 0xc5, 0x9e, 0x6d, 0xe1, 0xe0, 0x51, 0x6a, 0x62,
- 0xf5, 0x60, 0x72, 0xb2, 0xe0, 0x4d, 0xbf, 0xf8, 0x0f, 0x06, 0x09, 0x07,
- 0x50, 0x6d, 0x04, 0x09, 0x06, 0x0e, 0x05, 0x08, 0xe0, 0x73, 0x42, 0xf9,
- 0x60, 0xab, 0x6c, 0xd7, 0x30, 0xf8, 0x04, 0xe0, 0xbd, 0x99, 0xae, 0xe0,
- 0xb2, 0x27, 0x73, 0x34, 0x61, 0x6c, 0xec, 0xdb, 0x32, 0xee, 0x03, 0xdb,
- 0x43, 0x2d, 0xad, 0x3a, 0x1f, 0x40, 0x43, 0x21, 0x2e, 0x40, 0xd6, 0x40,
- 0x40, 0x40, 0xab, 0x41, 0x05, 0x40, 0xcc, 0x27, 0x31, 0x40, 0x48, 0x40,
- 0x92, 0x41, 0xba, 0x40, 0xa4, 0x40, 0xd8, 0x40, 0x48, 0x2f, 0x40, 0xda,
- 0x40, 0x91, 0x40, 0xb7, 0x3e, 0x40, 0x50, 0x40, 0xc9, 0x41, 0x08, 0x38,
- 0x3d, 0x40, 0x5e, 0x09, 0x25, 0x40, 0x6a, 0x40, 0x67, 0x3a, 0x13, 0xc0,
- 0x5f, 0xfa, 0x02, 0x96, 0xe6, 0x02, 0x84, 0x72, 0xb1, 0xcb, 0x18, 0x30,
- 0xe1, 0x02, 0x84, 0x76, 0xf8, 0xcc, 0x34, 0x6f, 0x36, 0x34, 0xe1, 0xe0,
- 0x98, 0x0d, 0x62, 0x78, 0x30, 0xb2, 0xce, 0xb7, 0xf9, 0x05, 0x11, 0x14,
- 0x0a, 0x87, 0x73, 0x74, 0x72, 0x65, 0x2d, 0x73, 0x6c, 0x69, 0x64, 0x72,
- 0x65, 0x2d, 0x75, 0xea, 0xe0, 0x33, 0xa8, 0xe7, 0x02, 0x88, 0x62, 0x69,
- 0x32, 0x61, 0xed, 0xe0, 0x87, 0x36, 0x61, 0x72, 0x64, 0x65, 0x6e, 0x2d,
- 0xf0, 0xc9, 0x22, 0x66, 0x72, 0x6f, 0x34, 0x69, 0x36, 0xb7, 0xe0, 0xc2,
- 0xe5, 0x65, 0x72, 0x2d, 0xfa, 0xe0, 0xb9, 0xd9, 0x39, 0x61, 0x33, 0xe1,
- 0xe0, 0xa2, 0xe9, 0xf8, 0x02, 0x98, 0x6b, 0x63, 0xb2, 0x02, 0x8b, 0x64,
- 0x6c, 0x33, 0x61, 0x35, 0x65, 0x65, 0xb0, 0xe0, 0xc2, 0xa3, 0x61, 0x6c,
- 0x33, 0x68, 0x79, 0xe5, 0xcd, 0x79, 0x68, 0x71, 0x35, 0xb2, 0xcf, 0x69,
- 0xf7, 0x03, 0x0a, 0x88, 0x67, 0xe2, 0x02, 0x83, 0xec, 0xc4, 0x66, 0xe8,
- 0xce, 0xc1, 0x63, 0x76, 0x73, 0x32, 0x32, 0xe4, 0xc9, 0x9a, 0x34, 0xf2,
- 0x02, 0x86, 0x73, 0x34, 0xb0, 0xe0, 0xc1, 0xcb, 0x38, 0x35, 0x65, 0x6c,
- 0x38, 0x66, 0x68, 0x75, 0x35, 0x64, 0xee, 0xe0, 0xab, 0x73, 0xf6, 0x07,
- 0x06, 0x19, 0x19, 0x06, 0x1f, 0xb9, 0x75, 0x71, 0x38, 0xb6, 0xcf, 0x2d,
- 0xf2, 0x04, 0x09, 0xc4, 0x55, 0x67, 0x67, 0x74, 0x2d, 0x78, 0xf1, 0xe0,
- 0x8f, 0x43, 0x65, 0x2d, 0x65, 0x69, 0x6b, 0x65, 0x72, 0x2d, 0xeb, 0xc7,
- 0x54, 0x6c, 0x65, 0x72, 0x2d, 0x71, 0x6f, 0x61, 0xae, 0x03, 0xd6, 0x8e,
- 0x78, 0x6e, 0x2d, 0x2d, 0x73, 0x74, 0x66, 0x6f, 0x6c, 0x64, 0x2d, 0xb9,
- 0xcc, 0x65, 0x68, 0x71, 0xf5, 0xe0, 0xc0, 0x19, 0xe7, 0x04, 0x06, 0x09,
- 0x86, 0x75, 0x34, 0x30, 0xb2, 0xcd, 0xcc, 0x73, 0x79, 0x2d, 0x71, 0x6f,
- 0x61, 0xb0, 0xc7, 0x0b, 0x61, 0x6e, 0x2d, 0xf1, 0xcb, 0xb3, 0x2d, 0x79,
- 0xe9, 0xcb, 0xeb, 0xe5, 0x03, 0x0d, 0x9e, 0x73, 0x74, 0x76, 0x67, 0x79,
- 0x2d, 0x69, 0x78, 0x61, 0xb6, 0xe0, 0xbb, 0xb9, 0x72, 0x6d, 0x67, 0x65,
- 0x6e, 0x73, 0x62, 0x65, 0x72, 0x61, 0xf4, 0x02, 0x89, 0x75, 0x6e, 0x67,
- 0x2d, 0x70, 0xf7, 0xe0, 0xb9, 0x84, 0x65, 0x72, 0x2d, 0x63, 0xf4, 0xe0,
- 0xb9, 0x7c, 0x67, 0x72, 0x73, 0x68, 0x65, 0x69, 0x2d, 0xe3, 0xc9, 0x18,
- 0xe1, 0x03, 0x04, 0xac, 0x72, 0xe4, 0xc9, 0x9e, 0x6c, 0x6c, 0xe5, 0x03,
- 0x02, 0x8b, 0xe4, 0x9b, 0x61, 0x6f, 0x73, 0x74, 0x65, 0x2d, 0x65, 0xb7,
- 0xe0, 0xbd, 0x05, 0xad, 0x02, 0x8c, 0x64, 0x2d, 0x61, 0x6f, 0x73, 0x74,
- 0x65, 0x2d, 0x65, 0xe8, 0xd5, 0x87, 0x61, 0x6f, 0x73, 0x74, 0x65, 0x2d,
- 0x65, 0xe2, 0xd5, 0x7d, 0x64, 0xf3, 0xc9, 0x6e, 0xf5, 0x04, 0x08, 0x12,
- 0x8d, 0x75, 0x77, 0x75, 0x35, 0xb8, 0xe0, 0xc1, 0x59, 0xee, 0x02, 0x86,
- 0x75, 0x70, 0xb4, 0xe0, 0xc0, 0xe9, 0x6a, 0x72, 0x67, 0x61, 0x2d, 0xf2,
- 0xe0, 0xbd, 0x39, 0x69, 0xf3, 0x02, 0x84, 0x7a, 0xb3, 0xc3, 0x6a, 0x74,
- 0x32, 0xb2, 0xcd, 0xf3, 0x63, 0x30, 0xe1, 0x02, 0x85, 0x79, 0x34, 0xe1,
- 0xca, 0x89, 0x74, 0x76, 0xae, 0x4d, 0x32, 0x60, 0x77, 0x36, 0xdf, 0x38,
- 0xf4, 0x09, 0x09, 0x40, 0x66, 0x08, 0x0f, 0x05, 0x0a, 0x86, 0x79, 0x73,
- 0x76, 0x72, 0x2d, 0xf6, 0xe0, 0xb6, 0x11, 0xf2, 0x07, 0x07, 0x09, 0x40,
- 0x4b, 0xc8, 0x7e, 0x6f, 0x6d, 0x73, 0x2d, 0xfa, 0xcb, 0xc8, 0x67, 0x73,
- 0x74, 0x61, 0x64, 0x2d, 0xf2, 0xc7, 0x7a, 0x65, 0x6e, 0x74, 0x69, 0xee,
- 0x03, 0x0e, 0x9b, 0x73, 0xe4, 0x03, 0xcb, 0x89, 0x2d, 0x74, 0x69, 0x72,
- 0x6f, 0x6c, 0x2d, 0xb6, 0xa8, 0xef, 0x02, 0x99, 0x2d, 0x73, 0xe4, 0x02,
- 0x88, 0x74, 0x69, 0x72, 0x6f, 0x6c, 0x2d, 0xf3, 0xa3, 0x2d, 0x74, 0x69,
- 0x72, 0x6f, 0x6c, 0x2d, 0x63, 0xb3, 0xd4, 0xdd, 0x2d, 0x73, 0xe4, 0x02,
- 0x8a, 0x74, 0x69, 0x72, 0x6f, 0x6c, 0x2d, 0x37, 0xf6, 0xd4, 0xce, 0x2d,
- 0x74, 0x69, 0x72, 0x6f, 0x6c, 0x2d, 0x72, 0xfa, 0xd4, 0xc3, 0xe1, 0xc8,
- 0xef, 0x6f, 0x72, 0x31, 0x33, 0xb1, 0xe0, 0xc0, 0xca, 0xee, 0x02, 0x87,
- 0x73, 0x62, 0x65, 0x72, 0xe7, 0xc7, 0x18, 0x30, 0x61, 0xe7, 0xc9, 0xef,
- 0x6a, 0x6d, 0xe5, 0xc8, 0x5c, 0x69, 0x71, 0x34, 0x39, 0x78, 0x71, 0xf9,
- 0xe0, 0xc0, 0x17, 0x63, 0x6b, 0xf7, 0xe0, 0xc0, 0xdc, 0x36, 0x30, 0x62,
- 0xb5, 0xc2, 0x82, 0xf3, 0x0d, 0x26, 0x3c, 0x25, 0x07, 0x08, 0x2b, 0x04,
- 0x0f, 0x0c, 0x13, 0xc4, 0x5c, 0xf4, 0x02, 0x8c, 0x72, 0x65, 0x2d, 0x74,
- 0x6f, 0x74, 0x65, 0x6e, 0x2d, 0xfa, 0xc0, 0x6e, 0x6a, 0x72, 0x64, 0x61,
- 0xec, 0x02, 0x8c, 0x73, 0x68, 0x61, 0x6c, 0x73, 0x65, 0x6e, 0x2d, 0xf3,
- 0xe0, 0x31, 0x3b, 0x2d, 0xf3, 0xc6, 0xc6, 0xf2, 0x04, 0x04, 0x07, 0x86,
- 0x75, 0xed, 0xca, 0x48, 0x72, 0x65, 0x69, 0x73, 0xe1, 0xc6, 0xb4, 0x66,
- 0x6f, 0x6c, 0xe4, 0xc6, 0x10, 0xad, 0x04, 0x0c, 0x06, 0x85, 0x76, 0x61,
- 0x72, 0x61, 0x6e, 0x67, 0x65, 0x72, 0x2d, 0xe7, 0xc0, 0xa4, 0x6f, 0x64,
- 0x61, 0xec, 0xc6, 0x97, 0x66, 0x72, 0xef, 0xc4, 0xd8, 0x61, 0x75, 0x72,
- 0x64, 0x61, 0x6c, 0x2d, 0xec, 0xc5, 0x4a, 0xee, 0x04, 0x06, 0x04, 0x8e,
- 0x73, 0x61, 0x2d, 0xf2, 0xc9, 0xd7, 0x65, 0xf3, 0xc1, 0x4d, 0x64, 0x72,
- 0x65, 0x2d, 0x6c, 0x61, 0x6e, 0x64, 0x2d, 0x30, 0xe3, 0xe0, 0x30, 0xdf,
- 0x61, 0x73, 0x65, 0x2d, 0xee, 0xe0, 0xb4, 0xe4, 0xed, 0x03, 0xc8, 0x8c,
- 0xec, 0xc7, 0xa9, 0xec, 0x03, 0xc9, 0xe9, 0x61, 0xf4, 0xc0, 0xd5, 0xeb,
- 0x03, 0x11, 0x8d, 0xee, 0x02, 0x88, 0x6c, 0x61, 0x6e, 0x64, 0x2d, 0xe6,
- 0xca, 0x31, 0x69, 0x74, 0x2d, 0xf9, 0xc9, 0xf7, 0xea, 0x02, 0x85, 0x6b,
- 0x2d, 0xf3, 0xc9, 0x91, 0x65, 0x72, 0xf6, 0xc0, 0xef, 0x69, 0x65, 0x72,
- 0x76, 0x2d, 0xf5, 0xe0, 0xbb, 0x9e, 0x67, 0xee, 0xc7, 0x7f, 0xe5, 0x02,
- 0x87, 0x73, 0x35, 0x35, 0xb4, 0xe0, 0xc1, 0x66, 0x72, 0x61, 0xec, 0xc7,
- 0xb7, 0x64, 0x74, 0x69, 0x72, 0x6f, 0x6c, 0x2d, 0x6e, 0xb2, 0xe0, 0xbb,
- 0x0f, 0x61, 0x6e, 0xe4, 0x03, 0xca, 0x46, 0x6e, 0x65, 0x73, 0x73, 0x6a,
- 0x65, 0x6e, 0x2d, 0x6f, 0xe7, 0xe0, 0x30, 0x6b, 0x39, 0xe2, 0xcc, 0x3f,
- 0xf2, 0x0d, 0x10, 0x0b, 0x16, 0x05, 0x08, 0x06, 0x07, 0x11, 0x0d, 0x32,
- 0x0a, 0x96, 0xf9, 0x02, 0x86, 0x72, 0x76, 0x69, 0xeb, 0xc5, 0x3e, 0x6b,
- 0x65, 0x6e, 0x2d, 0xf6, 0xca, 0x1c, 0x76, 0x63, 0x31, 0x65, 0x30, 0x61,
- 0x6d, 0xb3, 0xe0, 0xbf, 0xa8, 0xf3, 0x02, 0x8e, 0xf4, 0x02, 0x86, 0x61,
- 0x2d, 0xe6, 0xe0, 0xb4, 0x3f, 0x2d, 0xb0, 0xe0, 0xb6, 0x83, 0x6b, 0x6f,
- 0xe7, 0xc4, 0x4b, 0x72, 0x6f, 0xf3, 0xc9, 0x3c, 0x6f, 0x76, 0x75, 0x38,
- 0xb8, 0xe0, 0xb6, 0xfe, 0x6e, 0x79, 0x33, 0xb1, 0xcb, 0xdd, 0x6d, 0x73,
- 0x6b, 0x6f, 0xe7, 0xc4, 0xfc, 0xec, 0x02, 0x89, 0x69, 0x6e, 0x67, 0x65,
- 0x6e, 0x2d, 0xed, 0xc9, 0x7a, 0x61, 0x6e, 0xe4, 0xc4, 0x20, 0x69, 0xf3,
- 0x02, 0x83, 0xf2, 0xc9, 0xf2, 0x61, 0x2d, 0xb5, 0xe0, 0xb6, 0x46, 0xe8,
- 0x04, 0x12, 0x07, 0x88, 0xf4, 0x03, 0x05, 0x83, 0x36, 0xb1, 0xe0, 0xbc,
- 0x1b, 0xb3, 0xcb, 0xda, 0x32, 0x37, 0xfa, 0xe0, 0xbf, 0x0e, 0x71, 0x76,
- 0x39, 0xb6, 0xe0, 0xc0, 0xa9, 0x6f, 0x6c, 0x74, 0x2d, 0xed, 0xe0, 0xb3,
- 0xd7, 0x6b, 0x6b, 0x65, 0x72, 0x76, 0x6a, 0x75, 0x2d, 0x30, 0xb1, 0xc1,
- 0x81, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x79, 0x2d, 0xf6, 0xc5, 0x42, 0xe4,
- 0x03, 0x06, 0x86, 0x79, 0x2d, 0x30, 0xee, 0xc8, 0xcd, 0x65, 0x2d, 0xf5,
- 0xe0, 0x3f, 0x36, 0x61, 0x6c, 0x2d, 0xf0, 0xc8, 0x84, 0xe1, 0xc9, 0x95,
- 0xf1, 0x05, 0x07, 0x07, 0x08, 0x86, 0x78, 0xe1, 0x40, 0xa7, 0xe0, 0xbd,
- 0x76, 0x71, 0x71, 0x74, 0x31, 0xb1, 0xc8, 0x2a, 0x63, 0x6b, 0x61, 0x31,
- 0xf0, 0xe0, 0xb4, 0x6e, 0x39, 0x6a, 0x79, 0xe2, 0xc9, 0x19, 0x37, 0x63,
- 0xe5, 0xc0, 0x8a, 0xf0, 0x04, 0x0e, 0x0e, 0x88, 0x73, 0xf3, 0x02, 0x83,
- 0xf9, 0xc9, 0x77, 0x75, 0x33, 0x33, 0xec, 0xe0, 0xbe, 0x96, 0x6f, 0x72,
- 0x73, 0x67, 0x75, 0x2d, 0x73, 0x74, 0x61, 0x32, 0xb6, 0xe0, 0x7f, 0xf7,
- 0x67, 0x62, 0x73, 0x30, 0xe4, 0xe0, 0xbe, 0x85, 0x31, 0xe1, 0x60, 0x25,
- 0xcc, 0xe0, 0x98, 0x40, 0xef, 0x07, 0x08, 0x0b, 0x0a, 0x05, 0x0e, 0x8a,
- 0x74, 0x75, 0x37, 0x39, 0xb6, 0xe0, 0xbd, 0xc6, 0xf3, 0x02, 0x85, 0x79,
- 0x72, 0xef, 0xc6, 0xe1, 0xf4, 0xc4, 0x56, 0x70, 0x70, 0x65, 0x67, 0x72,
- 0x64, 0x2d, 0xe9, 0xc8, 0x96, 0x67, 0x62, 0xf0, 0xc1, 0x76, 0x64, 0x30,
- 0xe1, 0x02, 0x85, 0x71, 0x33, 0xe2, 0xc7, 0x77, 0x6c, 0xe7, 0xca, 0x19,
- 0x33, 0xe3, 0x03, 0xcb, 0x3c, 0x79, 0x78, 0xb2, 0xcb, 0x20, 0x31, 0x61,
- 0xe3, 0x49, 0x2e, 0xb5, 0xee, 0x0a, 0x08, 0x0c, 0x1f, 0x0a, 0x10, 0x04,
- 0x08, 0x12, 0x87, 0x79, 0x71, 0x79, 0x32, 0xb6, 0xe0, 0xbe, 0x27, 0x76,
- 0x75, 0x6f, 0x74, 0x6e, 0x61, 0x2d, 0x68, 0xf7, 0xe0, 0xb9, 0xde, 0xf4,
- 0x02, 0x8b, 0x74, 0x65, 0x72, 0x79, 0x2d, 0x62, 0x79, 0xe1, 0xe0, 0xbe,
- 0x1e, 0xf3, 0x02, 0x87, 0x71, 0x31, 0x37, 0xe7, 0xe0, 0xbd, 0xf9, 0x6f,
- 0x30, 0x69, 0x71, 0xf8, 0xc6, 0x21, 0x72, 0x79, 0x2d, 0x79, 0x6c, 0x61,
- 0xb5, 0xe0, 0xb8, 0xdc, 0x71, 0x76, 0x37, 0xe6, 0x04, 0xe0, 0xbf, 0x80,
- 0x73, 0x30, 0x30, 0x65, 0xed, 0xe0, 0xbd, 0xe2, 0xef, 0xe0, 0x7e, 0xdc,
- 0x6e, 0x78, 0x33, 0x38, 0xb8, 0xe0, 0xbd, 0xd6, 0x6d, 0x65, 0x73, 0x6a,
- 0x65, 0x76, 0x75, 0x65, 0x6d, 0x69, 0x65, 0x2d, 0x74, 0x63, 0xe2, 0xe0,
- 0xb9, 0x87, 0x69, 0x74, 0x32, 0x32, 0xb5, 0xc9, 0xc6, 0x67, 0xe2, 0x03,
- 0x04, 0x85, 0xf2, 0xe0, 0xb7, 0xe8, 0x65, 0x39, 0xe5, 0xc8, 0x78, 0x63,
- 0x35, 0x61, 0xfa, 0xe0, 0xbc, 0xfc, 0xed, 0x0d, 0x0a, 0x05, 0x11, 0x0a,
- 0x21, 0x1a, 0x16, 0x0b, 0x10, 0x41, 0x00, 0x8e, 0x78, 0x74, 0x71, 0x31,
- 0xed, 0x44, 0xa9, 0xe0, 0xba, 0x82, 0x75, 0x6f, 0xf3, 0xc7, 0x8d, 0x74,
- 0x74, 0x61, 0x2d, 0x76, 0x72, 0x6a, 0x6a, 0x61, 0x74, 0x2d, 0x6b, 0x37,
- 0xe1, 0xe0, 0x7e, 0xdf, 0x73, 0x79, 0x2d, 0x75, 0x6c, 0x61, 0xb0, 0xe0,
- 0x7e, 0xfc, 0xef, 0x03, 0x02, 0x89, 0xf4, 0xa7, 0x73, 0x6a, 0x65, 0x6e,
- 0x2d, 0xe5, 0xe0, 0x86, 0xd3, 0xf2, 0x02, 0x88, 0x69, 0x2d, 0x71, 0x73,
- 0xe1, 0xe0, 0x83, 0xcf, 0x65, 0x6b, 0x65, 0x2d, 0xea, 0xc7, 0xe3, 0xec,
- 0x03, 0x06, 0x86, 0x73, 0x65, 0x6c, 0xf6, 0xc2, 0xb3, 0x69, 0x2d, 0xf4,
- 0xe0, 0x3d, 0x92, 0x61, 0x74, 0x76, 0x75, 0x6f, 0x70, 0x6d, 0xe9, 0xc7,
- 0x61, 0xeb, 0x03, 0x07, 0x86, 0x72, 0x75, 0x34, 0xb5, 0xe0, 0xbc, 0xbd,
- 0x31, 0x62, 0x75, 0xb4, 0xc7, 0x85, 0x30, 0x61, 0xf8, 0xc4, 0x3e, 0x6a,
- 0x6e, 0x64, 0x61, 0x6c, 0x65, 0x6e, 0x2d, 0xb6, 0xc7, 0x5b, 0x69, 0xf8,
- 0x02, 0x86, 0x38, 0x39, 0xb1, 0xe0, 0xb3, 0xd9, 0x30, 0x38, 0xb2, 0xe0,
- 0xb3, 0xd3, 0x67, 0xe2, 0x0d, 0x08, 0x15, 0x14, 0x06, 0x09, 0x05, 0x10,
- 0x1c, 0x0b, 0x40, 0x68, 0x87, 0x78, 0x34, 0x63, 0x64, 0xb0, 0xe0, 0x33,
- 0x4b, 0xf4, 0x03, 0x05, 0x86, 0x78, 0xb2, 0xe0, 0xb4, 0x88, 0x66, 0x38,
- 0xe6, 0xe0, 0xbc, 0x2f, 0x33, 0x64, 0xe8, 0xe0, 0xbc, 0x2c, 0x71, 0x6c,
- 0x79, 0x37, 0xe3, 0x02, 0x85, 0x76, 0xe1, 0xe0, 0xba, 0xa3, 0x30, 0x61,
- 0x36, 0x37, 0xe6, 0xe0, 0x75, 0xaa, 0x70, 0x6c, 0xb2, 0xe0, 0x64, 0x9a,
- 0x69, 0x34, 0x65, 0x63, 0x65, 0xf8, 0xe0, 0xbc, 0xbf, 0x67, 0x75, 0xb8,
- 0xc7, 0x89, 0x65, 0x72, 0x70, 0x34, 0x61, 0x35, 0x64, 0x34, 0xe1, 0x04,
- 0xe0, 0xbc, 0xef, 0xb8, 0xc6, 0x0b, 0xe3, 0x03, 0x08, 0x87, 0x70, 0x71,
- 0x36, 0x67, 0x70, 0xe1, 0xc7, 0xdd, 0x61, 0x37, 0x64, 0xfa, 0xe0, 0xbc,
- 0x33, 0x30, 0x61, 0x39, 0x61, 0x7a, 0xe3, 0xe0, 0xbe, 0x1c, 0x62, 0x68,
- 0x31, 0xe1, 0x04, 0xe0, 0xbe, 0x12, 0xb7, 0xc4, 0x4b, 0xe1, 0x07, 0x07,
- 0x16, 0x0a, 0x06, 0x10, 0x88, 0x79, 0x68, 0x37, 0xe7, 0xe0, 0xbc, 0x14,
- 0x69, 0x39, 0xe1, 0x02, 0x88, 0x7a, 0x67, 0x71, 0x70, 0xb6, 0xe0, 0xbb,
- 0xbd, 0x35, 0x65, 0x76, 0x61, 0x30, 0xb0, 0xe0, 0xb3, 0xf8, 0x68, 0x31,
- 0x61, 0x33, 0x68, 0x6a, 0xeb, 0xe0, 0xae, 0x59, 0x62, 0x32, 0xe2, 0xe0,
- 0xbb, 0x98, 0xe1, 0x02, 0x85, 0x6d, 0x37, 0xe1, 0xc4, 0x8d, 0x6b, 0x63,
- 0x37, 0x64, 0xf6, 0xe0, 0xb3, 0x03, 0x37, 0x63, 0x30, 0x62, 0x62, 0xee,
- 0xc6, 0xf5, 0x33, 0xe1, 0x02, 0x91, 0x34, 0xe6, 0x02, 0x82, 0xf2, 0x83,
- 0x31, 0x36, 0xe1, 0x04, 0xe0, 0xbd, 0xb1, 0xae, 0xe0, 0x73, 0x96, 0x33,
- 0x65, 0xea, 0xe0, 0xbb, 0xf3, 0x39, 0x61, 0x77, 0xe2, 0xe0, 0xb2, 0xd9,
- 0x32, 0x64, 0xe4, 0xe0, 0xb1, 0xa0, 0xe5, 0x02, 0x88, 0x72, 0x6b, 0x65,
- 0x72, 0x2d, 0xeb, 0xc6, 0x8d, 0xec, 0xc6, 0xb2, 0x33, 0x63, 0x68, 0x30,
- 0x6a, 0xb3, 0xc8, 0xce, 0xec, 0x0e, 0x03, 0x0c, 0x13, 0x05, 0x07, 0x09,
- 0x06, 0x15, 0x19, 0x08, 0x08, 0x12, 0x84, 0xf5, 0xc4, 0x4c, 0xf4, 0x02,
- 0x84, 0x65, 0xee, 0xc5, 0xaf, 0x2d, 0x6c, 0xe9, 0xc5, 0xde, 0xf2, 0x02,
- 0x88, 0x65, 0x6e, 0x73, 0x6b, 0x6f, 0xe7, 0xc1, 0xe5, 0x64, 0x61, 0x6c,
- 0x2d, 0xf3, 0xe0, 0xb0, 0x8b, 0x6f, 0x61, 0xe2, 0xc5, 0xba, 0x6e, 0x73,
- 0x2d, 0xf1, 0xe0, 0x87, 0x50, 0x69, 0x6e, 0x64, 0x73, 0x2d, 0xf0, 0xe0,
- 0xb0, 0x76, 0x68, 0x70, 0x70, 0xe9, 0xc2, 0x49, 0xe7, 0x02, 0x87, 0x72,
- 0x64, 0x2d, 0x70, 0xef, 0xc5, 0xa6, 0x62, 0x62, 0x61, 0x74, 0x31, 0x61,
- 0x64, 0xb8, 0xe0, 0xba, 0xed, 0xe5, 0x02, 0x88, 0x73, 0x75, 0x6e, 0x64,
- 0x2d, 0xe8, 0xc6, 0x16, 0x61, 0x67, 0x61, 0x76, 0x69, 0x69, 0x6b, 0x61,
- 0x2d, 0x35, 0xb2, 0xe0, 0x2c, 0x35, 0x64, 0x69, 0x6e, 0x67, 0x65, 0xee,
- 0xc1, 0xb9, 0x63, 0x76, 0x72, 0x33, 0x32, 0xe4, 0xc4, 0x8d, 0xe1, 0x02,
- 0x84, 0x6e, 0xe7, 0xc5, 0x91, 0x68, 0x65, 0x61, 0x64, 0x6a, 0x75, 0x2d,
- 0xb7, 0xe0, 0x84, 0xc4, 0x31, 0xe1, 0xc7, 0x3d, 0x2d, 0xb1, 0xc2, 0x27,
- 0xeb, 0x0b, 0x1c, 0x08, 0x3f, 0x16, 0x0e, 0x1e, 0x09, 0x0c, 0x07, 0x85,
- 0xf6, 0x03, 0x0a, 0x85, 0x6e, 0x61, 0x6e, 0x67, 0x65, 0x6e, 0x2d, 0xeb,
- 0xc2, 0x7a, 0x69, 0x74, 0xf3, 0xc5, 0x22, 0x66, 0x6a, 0x6f, 0x72, 0x64,
- 0x2d, 0xee, 0xc5, 0x5b, 0x73, 0x6e, 0x65, 0x73, 0x2d, 0xf5, 0xc5, 0xae,
- 0xf2, 0x04, 0x10, 0x09, 0x8d, 0x6a, 0x6f, 0x68, 0x6b, 0x61, 0x2d, 0x68,
- 0x77, 0x61, 0x62, 0x34, 0x39, 0xea, 0xe0, 0xbb, 0x17, 0x65, 0x68, 0x61,
- 0x6d, 0x6e, 0x2d, 0xe4, 0xc5, 0x35, 0x64, 0x73, 0x68, 0x65, 0x72, 0x61,
- 0x64, 0x2d, 0x6d, 0xb8, 0xe0, 0xb6, 0xb2, 0xe1, 0x02, 0x89, 0x6e, 0x67,
- 0x68, 0x6b, 0x65, 0x2d, 0xe2, 0xc2, 0x2d, 0x67, 0x65, 0x72, 0x2d, 0xe7,
- 0xe0, 0x84, 0x4d, 0xf0, 0x02, 0x86, 0x75, 0x74, 0xb3, 0xe0, 0xba, 0x59,
- 0xf2, 0x02, 0x86, 0x79, 0x35, 0xb7, 0xe0, 0xba, 0x1d, 0x77, 0xb1, 0xc7,
- 0xc7, 0x6f, 0x6c, 0x75, 0x6f, 0x6b, 0x74, 0x61, 0x2d, 0x37, 0x79, 0x61,
- 0xb5, 0xc2, 0x11, 0xec, 0x02, 0x97, 0xf4, 0x04, 0x06, 0x05, 0x82, 0x79,
- 0x35, 0xf8, 0xe0, 0xba, 0x9f, 0x78, 0xb9, 0xe0, 0xba, 0x74, 0xf0, 0x83,
- 0x37, 0x38, 0xb7, 0xc7, 0x59, 0x62, 0xf5, 0xc2, 0x3b, 0x66, 0x6a, 0x6f,
- 0x72, 0x64, 0x2d, 0xe9, 0xc5, 0x24, 0x63, 0x72, 0x78, 0x37, 0x37, 0x64,
- 0x31, 0x78, 0xb4, 0xe0, 0xba, 0x84, 0x62, 0x72, 0x71, 0xb7, 0xe0, 0xba,
- 0x72, 0x61, 0x72, 0xed, 0xc5, 0x09, 0x37, 0x79, 0x6e, 0xb9, 0xc7, 0x15,
- 0xea, 0x06, 0x08, 0x09, 0x15, 0xc6, 0x1f, 0x76, 0x72, 0x31, 0x38, 0xb9,
- 0xe0, 0xb9, 0xb1, 0x72, 0x70, 0x65, 0x6c, 0x61, 0x6e, 0xe4, 0xc0, 0x7a,
- 0xec, 0x02, 0x89, 0x73, 0x74, 0x65, 0x72, 0x2d, 0xe2, 0xe0, 0x83, 0xc0,
- 0x71, 0x34, 0x38, 0x30, 0x6e, 0xb2, 0xe0, 0xa7, 0x5d, 0x31, 0xe1, 0x03,
- 0x04, 0x8e, 0xed, 0xe0, 0xba, 0x37, 0xe5, 0x02, 0x85, 0x6c, 0x38, 0xe2,
- 0xc6, 0x82, 0xe6, 0x46, 0x7f, 0xe0, 0xb5, 0x4a, 0x64, 0xf0, 0xc6, 0x78,
- 0xe9, 0x04, 0x10, 0x06, 0x88, 0x6f, 0x30, 0x61, 0x37, 0xe9, 0x04, 0xe0,
- 0xbb, 0xb2, 0xae, 0x60, 0x7d, 0x26, 0xe0, 0x3a, 0x09, 0x6e, 0x64, 0x65,
- 0xf2, 0xc4, 0x06, 0x6d, 0x72, 0x35, 0x31, 0xb3, 0xe0, 0xba, 0x75, 0x31,
- 0x62, 0x36, 0x62, 0x31, 0x61, 0x36, 0x61, 0xb2, 0xe0, 0xba, 0x26, 0xe8,
- 0x0f, 0x13, 0x08, 0x05, 0x10, 0x0c, 0x0e, 0x0d, 0x0e, 0x17, 0x10, 0x08,
- 0x0a, 0x14, 0x92, 0xf9, 0x02, 0x8a, 0x6c, 0x61, 0x6e, 0x64, 0x65, 0x74,
- 0x2d, 0xb5, 0xc4, 0x25, 0x61, 0x6e, 0x67, 0x65, 0xf2, 0xa4, 0x78, 0x74,
- 0x38, 0x31, 0xb4, 0xe0, 0xb9, 0xfb, 0x70, 0x6d, 0xe9, 0xc0, 0x71, 0xef,
- 0x02, 0x89, 0x6c, 0x74, 0x6c, 0x65, 0x6e, 0x2d, 0xe8, 0xc3, 0xf8, 0x62,
- 0xec, 0xc4, 0x78, 0x6e, 0x65, 0x66, 0x6f, 0x73, 0x73, 0x2d, 0x71, 0xb1,
- 0xe0, 0xb5, 0x72, 0x6d, 0x6d, 0x72, 0x66, 0x65, 0x61, 0x73, 0x74, 0x61,
- 0x2d, 0x73, 0xb4, 0xc3, 0xaf, 0x6b, 0x6b, 0x69, 0x6e, 0x65, 0x6e, 0x2d,
- 0x35, 0x77, 0xe1, 0xe0, 0xba, 0xd3, 0x67, 0x65, 0x62, 0x6f, 0x73, 0x74,
- 0x61, 0x64, 0x2d, 0x67, 0xb3, 0xe0, 0xb5, 0x49, 0xe5, 0x02, 0x8d, 0x72,
- 0x79, 0x2d, 0x69, 0x72, 0x61, 0xae, 0x60, 0x2a, 0x25, 0xe0, 0x7c, 0x12,
- 0x62, 0x64, 0x61, 0x38, 0xe2, 0xc5, 0x91, 0x63, 0x65, 0x73, 0x75, 0x6f,
- 0x6c, 0x6f, 0x2d, 0x37, 0x79, 0x61, 0x33, 0xb5, 0xe0, 0x2a, 0x20, 0x62,
- 0x6d, 0x65, 0x72, 0x2d, 0xf8, 0xc3, 0x5c, 0x33, 0x63, 0x75, 0x7a, 0x6b,
- 0x31, 0x64, 0xe9, 0xc6, 0x3e, 0x32, 0x62, 0xf2, 0x02, 0x88, 0x6a, 0x39,
- 0xe3, 0x40, 0xb1, 0xe0, 0xba, 0x2a, 0x65, 0x67, 0x33, 0xe5, 0xe0, 0xb0,
- 0x04, 0x31, 0xe1, 0x03, 0x05, 0x84, 0x6c, 0x69, 0xfa, 0xc5, 0x7d, 0x68,
- 0xee, 0xc5, 0x79, 0xe5, 0xe0, 0x35, 0xc4, 0x2d, 0x32, 0xe6, 0xe0, 0xb4,
- 0xe4, 0xe7, 0x0a, 0x23, 0x13, 0x07, 0x06, 0x05, 0x1a, 0x10, 0x03, 0x89,
- 0x6e, 0x73, 0x74, 0x69, 0xe7, 0x02, 0x8d, 0x6c, 0x69, 0x65, 0x66, 0x65,
- 0x72, 0x6e, 0x2d, 0x77, 0xef, 0xe0, 0x6f, 0x42, 0x62, 0x65, 0x73, 0x74,
- 0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x2d, 0x7a, 0xf6, 0xe0, 0x6f, 0x33, 0x6d,
- 0xf1, 0x02, 0x89, 0x77, 0x35, 0x61, 0xae, 0x44, 0xc0, 0xe0, 0x77, 0x36,
- 0x30, 0x35, 0x30, 0xe9, 0xc2, 0x09, 0x6c, 0x73, 0x2d, 0x65, 0xec, 0xc2,
- 0xe7, 0x6b, 0x33, 0x61, 0xf4, 0xc0, 0xa5, 0x6a, 0x76, 0xe9, 0xc1, 0x44,
- 0xe9, 0x02, 0x8b, 0x76, 0x75, 0x6f, 0x74, 0x6e, 0x61, 0x2d, 0xb8, 0xe0,
- 0x82, 0x32, 0x6c, 0x64, 0x65, 0x73, 0x6b, 0x6c, 0x2d, 0x67, 0xb0, 0xe0,
- 0xb4, 0x77, 0x67, 0x61, 0x76, 0x69, 0x69, 0x6b, 0x61, 0x2d, 0x38, 0x79,
- 0x61, 0x34, 0xb7, 0xe0, 0x7a, 0x30, 0xe5, 0xc5, 0x39, 0x63, 0x6b, 0x72,
- 0x33, 0x66, 0xb0, 0xe0, 0xaf, 0x67, 0x32, 0x78, 0x78, 0x34, 0xb8, 0xe0,
- 0xae, 0x41, 0xe6, 0x0a, 0x18, 0x15, 0x07, 0x1a, 0x18, 0x10, 0x22, 0x04,
- 0x88, 0xfa, 0x02, 0x8c, 0x79, 0x73, 0x38, 0x64, 0x36, 0x39, 0x75, 0x76,
- 0xe7, 0xe0, 0xb7, 0xc4, 0x63, 0x32, 0x63, 0x39, 0x65, 0xb2, 0xe0, 0xae,
- 0x1e, 0xf2, 0x03, 0x07, 0x86, 0x79, 0x61, 0x2d, 0xe8, 0xe0, 0xad, 0x30,
- 0x6e, 0x61, 0x2d, 0xf7, 0xc2, 0x03, 0x64, 0xe5, 0xc2, 0x32, 0x70, 0x63,
- 0x72, 0x6a, 0xb9, 0xc5, 0x52, 0x6f, 0x72, 0xec, 0x02, 0x8a, 0x63, 0x65,
- 0x73, 0x65, 0x6e, 0x61, 0x2d, 0xe3, 0xc1, 0x82, 0x2d, 0x63, 0x65, 0x73,
- 0x65, 0x6e, 0x61, 0x2d, 0xe6, 0xc1, 0x82, 0xec, 0x03, 0x07, 0x87, 0x77,
- 0x33, 0x35, 0xb1, 0xe0, 0xb8, 0x57, 0x6f, 0x72, 0x2d, 0xea, 0xe0, 0xac,
- 0xf3, 0x2d, 0x7a, 0xe9, 0xe0, 0xb3, 0xe2, 0xea, 0x02, 0x85, 0x71, 0x37,
- 0xb2, 0xc2, 0xe0, 0x6f, 0x72, 0x64, 0x2d, 0xec, 0xe0, 0xac, 0xdd, 0xe9,
- 0x02, 0x9b, 0xf1, 0x04, 0x05, 0x05, 0x83, 0x7a, 0xb9, 0xe0, 0xb7, 0x39,
- 0x73, 0xb8, 0xe0, 0xb7, 0x34, 0xb6, 0xc0, 0xd5, 0x32, 0x32, 0x38, 0x63,
- 0x35, 0xe8, 0xe0, 0xb7, 0x28, 0x6e, 0xee, 0xc2, 0x7e, 0x68, 0xe2, 0xd9,
- 0x15, 0x63, 0x74, 0x34, 0x32, 0xb9, 0xe0, 0xb7, 0x1b, 0x36, 0x71, 0x78,
- 0x35, 0xb3, 0xe0, 0xb7, 0xa9, 0xe5, 0x06, 0x0d, 0x07, 0x07, 0x0e, 0x8a,
- 0x76, 0x65, 0x6e, 0x69, 0x2d, 0x30, 0x71, 0x61, 0x30, 0xb1, 0xe0, 0x93,
- 0x02, 0x6c, 0x71, 0x71, 0x31, 0xb6, 0xc4, 0x47, 0x68, 0x71, 0x7a, 0x35,
- 0xb6, 0xc4, 0xc5, 0x66, 0xf6, 0x02, 0x86, 0x79, 0x38, 0xb8, 0xe0, 0xb7,
- 0xa8, 0x6e, 0xb9, 0xc3, 0xa7, 0x63, 0x6b, 0x76, 0x64, 0x74, 0x63, 0xb9,
- 0xe0, 0xb6, 0xf3, 0x31, 0xe1, 0xc1, 0xfc, 0xe4, 0x07, 0x04, 0x08, 0x05,
- 0x12, 0x0b, 0x8a, 0x79, 0xf2, 0xc2, 0x4b, 0x72, 0x62, 0x61, 0x6b, 0x2d,
- 0xf7, 0xc2, 0x1b, 0x6e, 0x6e, 0xe1, 0xc1, 0x5c, 0xea, 0x02, 0x84, 0x74,
- 0xf9, 0xc3, 0x26, 0x72, 0x73, 0x37, 0x32, 0x64, 0x36, 0x75, 0xf9, 0xe0,
- 0xb7, 0x66, 0x61, 0x76, 0x76, 0x65, 0x6e, 0x6a, 0x72, 0x67, 0xe1, 0xc1,
- 0xaa, 0x35, 0x71, 0x76, 0x37, 0x7a, 0x38, 0x37, 0xb6, 0xc3, 0x0c, 0x31,
- 0xe1, 0x03, 0x03, 0x84, 0xf4, 0xc2, 0x7b, 0xec, 0xe0, 0xae, 0x1e, 0x63,
- 0xea, 0xc0, 0xa7, 0xe3, 0x0a, 0x1d, 0x33, 0x13, 0x08, 0x06, 0x1b, 0x12,
- 0x08, 0x87, 0x7a, 0xf2, 0x04, 0x07, 0x05, 0x85, 0x77, 0x32, 0x38, 0xe2,
- 0xe0, 0x8c, 0x3c, 0x75, 0xb2, 0xe0, 0xb6, 0x82, 0x73, 0xb0, 0xe0, 0xb7,
- 0x0b, 0x36, 0x39, 0xb4, 0xe0, 0xae, 0xc7, 0xef, 0x02, 0xa0, 0x72, 0x72,
- 0x65, 0x69, 0x6f, 0x73, 0x2d, 0x65, 0x2d, 0x74, 0x65, 0x6c, 0x65, 0x63,
- 0x6f, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x65, 0x73, 0x2d, 0x67, 0x68,
- 0x63, 0x32, 0xb9, 0xe0, 0xb2, 0x7b, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61,
- 0x65, 0x73, 0x2d, 0x76, 0x36, 0x61, 0xb2, 0xe0, 0xad, 0xdb, 0x6c, 0x63,
- 0x68, 0x63, 0x30, 0x65, 0x61, 0x30, 0x62, 0x32, 0x67, 0x32, 0x61, 0x39,
- 0x67, 0xe3, 0xe0, 0xb6, 0x31, 0x69, 0x71, 0x70, 0x6e, 0xae, 0xe0, 0x79,
- 0xe3, 0x67, 0x34, 0xe2, 0xe0, 0xa5, 0x8a, 0x65, 0x73, 0x65, 0x6e, 0xe1,
- 0x02, 0x8a, 0x66, 0x6f, 0x72, 0x6c, 0x2d, 0x69, 0xb8, 0xe0, 0xb2, 0x10,
- 0x2d, 0x66, 0x6f, 0x72, 0x6c, 0x2d, 0x6d, 0xe3, 0xca, 0x97, 0x63, 0xeb,
- 0x02, 0x88, 0x77, 0x63, 0x78, 0x65, 0xf4, 0xe0, 0xb5, 0xfc, 0x32, 0x62,
- 0xb3, 0xe0, 0xae, 0x46, 0x33, 0x73, 0x31, 0x34, 0xed, 0xe0, 0xb6, 0x90,
- 0x32, 0x62, 0x72, 0xb7, 0xe0, 0xb8, 0x2b, 0x31, 0x61, 0x76, 0xe7, 0x04,
- 0xe0, 0xb8, 0x21, 0x2e, 0x78, 0x6e, 0x2d, 0xad, 0x41, 0xb1, 0xc1, 0x26,
- 0xe2, 0x0f, 0x03, 0x0d, 0x1e, 0x19, 0x08, 0x09, 0x15, 0x16, 0x1c, 0x1c,
- 0x0c, 0x0e, 0x12, 0x8a, 0xf5, 0xc0, 0xd5, 0x74, 0x73, 0x66, 0x6a, 0x6f,
- 0x72, 0x64, 0x2d, 0x39, 0xfa, 0xe0, 0xb2, 0x25, 0xf2, 0x02, 0x88, 0x75,
- 0x6d, 0x2d, 0x76, 0xef, 0xe0, 0xb2, 0x1a, 0x6e, 0x6e, 0xf9, 0x02, 0x89,
- 0x73, 0x75, 0x6e, 0x64, 0x2d, 0x6d, 0xb8, 0xc0, 0x57, 0x2d, 0x77, 0xf5,
- 0xc0, 0x52, 0xef, 0x02, 0x90, 0x7a, 0x65, 0x6e, 0x2d, 0x73, 0x64, 0x74,
- 0x69, 0x72, 0x6f, 0x6c, 0x2d, 0x32, 0xef, 0xca, 0x14, 0x64, 0x2d, 0xb2,
- 0xe0, 0xad, 0x42, 0x6d, 0x6c, 0x6f, 0x2d, 0xe7, 0xe0, 0xaa, 0xf1, 0x6c,
- 0x74, 0x2d, 0x65, 0x6c, 0xe1, 0xe0, 0x26, 0xdb, 0xea, 0x02, 0x89, 0x64,
- 0x64, 0x61, 0x72, 0x2d, 0xf0, 0xe0, 0xb1, 0xd0, 0x61, 0x72, 0x6b, 0x79,
- 0x2d, 0xe6, 0xe0, 0x7f, 0x77, 0xe9, 0x02, 0x89, 0x65, 0x76, 0x74, 0x2d,
- 0x30, 0xf1, 0xe0, 0xb1, 0xbc, 0x64, 0x72, 0x2d, 0x35, 0x6e, 0x61, 0xe3,
- 0xe0, 0xb6, 0x01, 0x68, 0xe3, 0x02, 0x8e, 0x63, 0x61, 0x76, 0x75, 0x6f,
- 0x74, 0x6e, 0x61, 0x2d, 0x6b, 0xb7, 0xe0, 0xb1, 0xa0, 0x61, 0x76, 0x75,
- 0x6f, 0x74, 0x6e, 0x61, 0x2d, 0xf3, 0x99, 0xe5, 0x02, 0x8b, 0x72, 0x6c,
- 0x65, 0x76, 0x67, 0x2d, 0x6a, 0xf8, 0xe0, 0xb1, 0x88, 0x61, 0x72, 0x61,
- 0x6c, 0x76, 0x68, 0x6b, 0x69, 0x2d, 0x79, 0xb4, 0xe0, 0xb1, 0x7a, 0x64,
- 0x64, 0x64, 0x6a, 0x2d, 0x6d, 0x72, 0x61, 0xe2, 0xe0, 0xb3, 0x51, 0x63,
- 0x6b, 0x31, 0x62, 0x39, 0x61, 0x35, 0x64, 0x72, 0x65, 0xb4, 0xe0, 0xab,
- 0x4e, 0x61, 0x6c, 0x73, 0x61, 0x6e, 0x2d, 0x73, 0x64, 0x74, 0x69, 0x72,
- 0x6f, 0x6c, 0x2d, 0x6e, 0xf3, 0xc9, 0x6e, 0x34, 0x77, 0x36, 0x30, 0x35,
- 0x66, 0xe5, 0xe0, 0xa7, 0x90, 0x2d, 0x35, 0x67, 0xe1, 0xe0, 0x9f, 0x4c,
- 0xe1, 0x05, 0x0a, 0x12, 0x03, 0x8d, 0x76, 0x65, 0x72, 0x79, 0x2d, 0x79,
- 0xf5, 0xe0, 0xb1, 0x2d, 0x75, 0x72, 0x73, 0x6b, 0x6f, 0x67, 0x2d, 0x68,
- 0x6c, 0x61, 0x6e, 0x64, 0x2d, 0x6a, 0xee, 0xe0, 0x26, 0x19, 0x73, 0xeb,
- 0x90, 0x72, 0x6f, 0x70, 0x6f, 0x72, 0x74, 0x2d, 0x62, 0x79, 0xe1, 0xe0,
- 0xa8, 0xc0, 0x6e, 0x64, 0x79, 0xad, 0xca, 0x42, 0xb9, 0x04, 0x08, 0x07,
- 0x92, 0x6b, 0x72, 0x74, 0x30, 0xb0, 0xe0, 0xb5, 0x35, 0x65, 0x74, 0x35,
- 0xb2, 0xe0, 0xb5, 0xd4, 0x64, 0xe2, 0x02, 0x85, 0x71, 0xb2, 0xe0, 0xb5,
- 0x25, 0x68, 0x62, 0x6c, 0x67, 0x36, 0xe4, 0xe0, 0xaa, 0xe0, 0x30, 0xe1,
- 0x0a, 0x03, 0x03, 0x38, 0x60, 0x76, 0xe7, 0xe0, 0x3e, 0x13, 0x7a, 0xe8,
+ 0x0a, 0x41, 0xf6, 0x04, 0x40, 0x88, 0x41, 0x31, 0x40, 0x50, 0x0a, 0x0a,
+ 0x40, 0x55, 0x40, 0xd2, 0x0f, 0x88, 0x6d, 0x55, 0x5c, 0x1f, 0x6a, 0xf5,
+ 0xe0, 0xc9, 0xf6, 0x6c, 0x42, 0x7c, 0x1f, 0x6c, 0xc4, 0xe0, 0xab, 0xf7,
+ 0x6b, 0x4b, 0x77, 0x9f, 0x02, 0x85, 0x6c, 0xfb, 0xe0, 0xca, 0x76, 0x6b,
+ 0xc4, 0xe0, 0xc9, 0xbf, 0xe9, 0x0a, 0x08, 0x09, 0x05, 0x16, 0x07, 0x14,
+ 0x0f, 0x18, 0x8c, 0x79, 0x7f, 0x1f, 0x65, 0x45, 0xd0, 0xc2, 0x49, 0x73,
+ 0x65, 0x1f, 0x65, 0x4f, 0xd6, 0xe0, 0xca, 0x67, 0x6b, 0x58, 0x9f, 0xc2,
+ 0x0c, 0x66, 0x59, 0x9f, 0x03, 0xc1, 0x2c, 0xe6, 0x04, 0xe0, 0x3e, 0xbf,
+ 0x60, 0x7c, 0x1f, 0x69, 0x47, 0x4c, 0x1f, 0x66, 0xcb, 0xc4, 0x43, 0x64,
+ 0x50, 0x1f, 0x65, 0xce, 0xc9, 0xa9, 0xe3, 0x02, 0x86, 0x5f, 0x1f, 0x65,
+ 0xd3, 0xc8, 0xc4, 0x5e, 0x1f, 0x65, 0x48, 0x69, 0x1f, 0x66, 0xf5, 0xe0,
+ 0xc0, 0xf4, 0xdd, 0x02, 0x86, 0x59, 0x1f, 0xe5, 0xe0, 0xc3, 0x7c, 0x52,
+ 0x1f, 0x66, 0xe3, 0xdd, 0xbf, 0xdb, 0x02, 0x8e, 0x7b, 0x1f, 0x68, 0x68,
+ 0x4a, 0x1f, 0x67, 0x5b, 0x48, 0x1f, 0x67, 0xe7, 0xc3, 0x79, 0x46, 0x1f,
+ 0x65, 0xdb, 0xe0, 0xc1, 0x5d, 0x55, 0x77, 0x9f, 0x02, 0x84, 0x69, 0xc7,
+ 0xc2, 0x2e, 0xe5, 0xc2, 0x28, 0x40, 0x5a, 0x1f, 0x68, 0xf2, 0xe0, 0xc9,
+ 0x89, 0xe8, 0x05, 0x08, 0x07, 0x06, 0x85, 0x74, 0x6d, 0x1f, 0x67, 0xc9,
+ 0xe0, 0xc9, 0x7b, 0x70, 0x77, 0x1f, 0x66, 0xed, 0xc3, 0x68, 0x4c, 0x68,
+ 0x1f, 0xe5, 0xc2, 0x07, 0x47, 0x7a, 0x9f, 0xc2, 0x8d, 0x41, 0x54, 0x1f,
+ 0x69, 0xc0, 0xc3, 0x0e, 0xe7, 0x0c, 0x07, 0x1d, 0x13, 0x16, 0x14, 0x04,
+ 0x12, 0x11, 0x07, 0x09, 0x87, 0x7e, 0x64, 0x1f, 0x69, 0xe6, 0xd1, 0xff,
+ 0x7d, 0x51, 0x9f, 0x02, 0x91, 0xe7, 0x03, 0x07, 0x83, 0x7b, 0xdc, 0x56,
+ 0x67, 0xe0, 0xb4, 0xf2, 0xf5, 0xcf, 0x2d, 0xeb, 0xc1, 0xf2, 0xe5, 0x03,
+ 0xc2, 0x3c, 0xdd, 0xc7, 0xe6, 0x7b, 0x44, 0x1f, 0xe7, 0x02, 0x89, 0x7b,
+ 0xc7, 0x03, 0xd9, 0x54, 0x1f, 0xe6, 0xc0, 0xc2, 0x79, 0xd4, 0xd9, 0x4e,
+ 0x76, 0x72, 0x9f, 0x02, 0x86, 0x68, 0x77, 0xef, 0xe0, 0xa0, 0xc1, 0xe7,
+ 0x02, 0x84, 0x7b, 0xdc, 0xd9, 0x3c, 0x75, 0xe1, 0xc2, 0x64, 0x75, 0x44,
+ 0x1f, 0xe7, 0x02, 0x84, 0x7b, 0xc7, 0xd9, 0x2e, 0x79, 0x54, 0xae, 0x42,
+ 0x77, 0x60, 0x8c, 0x88, 0xdd, 0xbd, 0x6e, 0xc7, 0xc2, 0xda, 0xe7, 0x02,
+ 0x87, 0x7b, 0x1f, 0x65, 0xca, 0xe0, 0xc8, 0x6f, 0x4b, 0x1f, 0x67, 0x54,
+ 0xf0, 0xe0, 0xc9, 0x4b, 0x66, 0x4f, 0x9f, 0x02, 0x86, 0xe5, 0x41, 0x1e,
+ 0xe0, 0xc1, 0x78, 0x64, 0x7a, 0xd5, 0xe0, 0xc9, 0x3a, 0x65, 0x5e, 0x1f,
+ 0x65, 0x65, 0xc8, 0x83, 0x5f, 0x73, 0x1f, 0x65, 0x77, 0xdd, 0xe0, 0xc9,
+ 0x2a, 0x46, 0x4a, 0x1f, 0x66, 0xdc, 0xd1, 0x67, 0x42, 0x79, 0x1f, 0xe7,
+ 0xc2, 0x8c, 0xe6, 0x12, 0x0d, 0x04, 0x07, 0x0c, 0x09, 0x07, 0x07, 0x07,
+ 0x06, 0x07, 0x19, 0x11, 0x11, 0x09, 0x08, 0x0b, 0x87, 0x7e, 0x73, 0x1f,
+ 0xe9, 0x02, 0x84, 0xd7, 0xe0, 0xc8, 0x1c, 0xd6, 0xc7, 0x45, 0x7b, 0xcb,
+ 0xc2, 0x2c, 0x78, 0x78, 0x1f, 0x66, 0xc8, 0xc3, 0xcc, 0x77, 0x61, 0x1f,
+ 0x69, 0x69, 0x6c, 0x1f, 0x69, 0xd4, 0xe0, 0xc8, 0xeb, 0x72, 0x56, 0x1f,
+ 0x67, 0x78, 0xc4, 0xe0, 0xc8, 0xdd, 0x60, 0x43, 0x1f, 0x66, 0xdc, 0xdb,
+ 0xee, 0x5d, 0x71, 0x1f, 0x64, 0xfa, 0xd1, 0x13, 0x5c, 0x7a, 0x1f, 0x66,
+ 0xde, 0xc7, 0x49, 0x5b, 0x78, 0x1f, 0xe7, 0xc3, 0xd2, 0x57, 0x76, 0x1f,
+ 0x65, 0xf0, 0xc1, 0xfa, 0x56, 0x70, 0x9f, 0x03, 0x04, 0x86, 0x69, 0xd7,
+ 0xc8, 0x1a, 0x66, 0x7d, 0xdf, 0xe0, 0xc8, 0xab, 0x65, 0x4a, 0x60, 0x1f,
+ 0x65, 0xdd, 0xe0, 0xc8, 0xa7, 0xd5, 0x02, 0x87, 0x59, 0x1f, 0x68, 0x42,
+ 0xf2, 0xc1, 0xa4, 0x4e, 0x1f, 0x68, 0x42, 0xf2, 0xd8, 0x54, 0x54, 0x7f,
+ 0x1f, 0xe5, 0x02, 0x87, 0x7a, 0xdc, 0x41, 0x93, 0xe0, 0xc8, 0x9f, 0xca,
+ 0xe0, 0xc8, 0x85, 0x4b, 0x5b, 0x1f, 0x68, 0x41, 0xd8, 0xe0, 0xca, 0x23,
+ 0x49, 0x4b, 0x1f, 0x66, 0xdc, 0xe0, 0xc7, 0xa8, 0x48, 0x51, 0x1f, 0x67,
+ 0x48, 0x71, 0x1f, 0x64, 0xfd, 0xc2, 0x3c, 0x45, 0x48, 0x1f, 0x65, 0xd6,
+ 0xc6, 0xde, 0x44, 0x5b, 0x9f, 0x02, 0x85, 0x67, 0xdf, 0xe0, 0xc5, 0x35,
+ 0x65, 0x6a, 0xdb, 0xe0, 0xc8, 0x4d, 0xe5, 0x16, 0x0b, 0x09, 0x07, 0x07,
+ 0x17, 0x14, 0x03, 0x15, 0x09, 0x08, 0x23, 0x07, 0x09, 0x15, 0x1b, 0x0d,
+ 0x0e, 0x09, 0x0d, 0x28, 0x88, 0xfe, 0x02, 0x82, 0xf3, 0x89, 0x6e, 0x1f,
+ 0x65, 0xcd, 0xc1, 0x6a, 0x7a, 0x43, 0x1f, 0x65, 0x73, 0xf6, 0xe0, 0xc8,
+ 0x22, 0x79, 0x7f, 0x1f, 0x64, 0xf8, 0xc6, 0x3a, 0x73, 0x76, 0x1f, 0x66,
+ 0xe0, 0xd7, 0x70, 0xf2, 0x03, 0x08, 0x83, 0x69, 0x1f, 0x66, 0x49, 0xcb,
+ 0xe0, 0xc8, 0x08, 0xe1, 0xc0, 0xb0, 0x50, 0x1f, 0x69, 0x58, 0xdc, 0xe0,
+ 0xc7, 0xfd, 0x71, 0x71, 0x9f, 0x02, 0x84, 0x66, 0xe2, 0xdb, 0x0c, 0xe5,
+ 0x02, 0x85, 0x7d, 0xe2, 0xe0, 0xc7, 0xec, 0xcf, 0xda, 0x29, 0xef, 0xc0,
+ 0x90, 0xee, 0x02, 0x86, 0x76, 0x1f, 0x69, 0xdb, 0xc7, 0x46, 0x6e, 0x1f,
+ 0xe5, 0x02, 0x82, 0xf4, 0x82, 0x5f, 0xce, 0xe0, 0xc7, 0xd1, 0x68, 0x71,
+ 0x1f, 0x64, 0x79, 0xd0, 0xe0, 0xc9, 0x74, 0x65, 0x48, 0x1f, 0x68, 0xc9,
+ 0xe0, 0xc7, 0xbf, 0xe4, 0x02, 0x8c, 0x69, 0x1f, 0x64, 0x78, 0x7b, 0x1f,
+ 0x66, 0x55, 0xd9, 0xe0, 0xc9, 0x5d, 0x67, 0x9f, 0x03, 0x06, 0x83, 0x69,
+ 0x58, 0xea, 0xe0, 0xc7, 0xa6, 0x66, 0xcb, 0x93, 0x65, 0x48, 0xc6, 0xe0,
+ 0xc7, 0x9d, 0x5f, 0x7c, 0x1f, 0x67, 0xce, 0xc0, 0x5b, 0x5c, 0x68, 0x1f,
+ 0x67, 0x7a, 0xff, 0xe0, 0xc9, 0x39, 0x58, 0x49, 0x1f, 0x69, 0x47, 0xcc,
+ 0x04, 0xe0, 0xc9, 0x2c, 0x1f, 0x65, 0x64, 0x67, 0x1f, 0x69, 0x45, 0x52,
+ 0x1f, 0xe5, 0x94, 0x55, 0x46, 0x9f, 0x02, 0x8b, 0xe6, 0x02, 0x85, 0x65,
+ 0xed, 0xe0, 0x9e, 0xac, 0xe0, 0xc4, 0xe9, 0xe5, 0x02, 0x85, 0x7a, 0xd7,
+ 0xe0, 0xc9, 0x0c, 0xdf, 0xc6, 0x7e, 0x52, 0x4c, 0x1f, 0x66, 0x6d, 0x4c,
+ 0x1f, 0x65, 0x71, 0xf1, 0xe0, 0xc7, 0x50, 0x4f, 0x70, 0x9f, 0x02, 0x85,
+ 0x67, 0xc1, 0xe0, 0xbd, 0x0f, 0x66, 0xf9, 0xc3, 0x02, 0x4d, 0x43, 0x1f,
+ 0x68, 0x51, 0xc9, 0xe0, 0xc7, 0x39, 0x4c, 0x57, 0x1f, 0x66, 0x75, 0x77,
+ 0x1f, 0x69, 0x41, 0xd3, 0xe0, 0xc7, 0x2c, 0xc5, 0x03, 0x06, 0x97, 0x75,
+ 0x1f, 0x65, 0xfa, 0xd9, 0xba, 0x6c, 0x9f, 0x02, 0x84, 0x67, 0xdb, 0xc4,
+ 0xe9, 0x65, 0x4f, 0xf8, 0x04, 0xe0, 0xc8, 0xbc, 0xae, 0x21, 0x60, 0x8c,
+ 0x88, 0xe0, 0x37, 0x6a, 0x6b, 0x1f, 0x65, 0xcd, 0xe0, 0xbd, 0xc7, 0x41,
+ 0x65, 0x1f, 0x65, 0xfa, 0xe0, 0xc6, 0x38, 0x40, 0x4b, 0x1f, 0x64, 0x7a,
+ 0x7a, 0xae, 0x04, 0xe0, 0x8c, 0x88, 0x1f, 0x69, 0x66, 0x59, 0x1f, 0xe6,
+ 0xe0, 0x3b, 0x53, 0xe4, 0x05, 0x08, 0x12, 0x09, 0x95, 0x7f, 0x61, 0x1f,
+ 0x66, 0xc1, 0xe0, 0xc6, 0xfb, 0xfd, 0x02, 0x87, 0x5b, 0x1f, 0x65, 0xf1,
+ 0xe0, 0xa8, 0x34, 0x50, 0x1f, 0x68, 0x73, 0xc0, 0xe0, 0xc6, 0xc8, 0x7c,
+ 0x41, 0x1f, 0x64, 0x78, 0xda, 0xe0, 0xc8, 0x6b, 0xfa, 0x02, 0x88, 0x6c,
+ 0x1f, 0x69, 0x43, 0xfd, 0xe0, 0xc6, 0xb4, 0x5a, 0x1f, 0x69, 0x69, 0x6c,
+ 0x1f, 0x69, 0xc0, 0xc4, 0x79, 0xf8, 0x04, 0x1f, 0x07, 0x88, 0x6d, 0x9f,
+ 0x03, 0x0a, 0x8b, 0x66, 0x56, 0x47, 0x1f, 0x67, 0x7d, 0xd1, 0xe0, 0xc8,
+ 0x42, 0xe5, 0x02, 0x85, 0x5c, 0xcb, 0xe0, 0xc8, 0x3a, 0xdb, 0xc5, 0x6f,
+ 0x64, 0xff, 0xe0, 0xc6, 0x8b, 0x6a, 0x1f, 0x64, 0x7a, 0xfa, 0xd6, 0x42,
+ 0x56, 0x1f, 0x67, 0x55, 0xcc, 0xe0, 0xc8, 0x23, 0x49, 0x1f, 0x69, 0x47,
+ 0xcd, 0xe0, 0xc6, 0x6f, 0xe3, 0x04, 0x24, 0xc0, 0x4e, 0xc3, 0x02, 0x8e,
+ 0x5d, 0x1f, 0x63, 0x42, 0x64, 0x1f, 0x63, 0x43, 0x73, 0x1f, 0x63, 0xc3,
+ 0xc4, 0x18, 0x55, 0x1f, 0x63, 0x42, 0x61, 0x1f, 0x63, 0x43, 0x43, 0x1f,
+ 0x63, 0x42, 0x77, 0x1f, 0x63, 0x43, 0xe7, 0xc0, 0x4a, 0xc2, 0x06, 0x06,
+ 0x0b, 0x08, 0x0f, 0x90, 0x7b, 0x1f, 0x63, 0x43, 0xfc, 0x9d, 0x79, 0x1f,
+ 0x63, 0x43, 0x48, 0x1f, 0x63, 0xc2, 0xe0, 0xbd, 0x81, 0x73, 0x1f, 0x63,
+ 0x43, 0xe0, 0xe0, 0xc7, 0xd2, 0x70, 0x1f, 0x63, 0x43, 0x7c, 0x1f, 0x63,
+ 0x42, 0x70, 0x1f, 0x63, 0xc3, 0xe0, 0xc5, 0x5d, 0x6f, 0x1f, 0x63, 0x43,
+ 0x69, 0x1f, 0x63, 0x42, 0x66, 0x1f, 0x63, 0x43, 0xc9, 0xe0, 0xc7, 0xb3,
+ 0x62, 0x1f, 0x63, 0x43, 0x5e, 0x1f, 0x63, 0x42, 0x7e, 0x1f, 0x63, 0xc3,
+ 0xe0, 0xc5, 0x3b, 0x41, 0x7f, 0x1f, 0x63, 0x42, 0x53, 0x1f, 0x63, 0xc1,
+ 0xe0, 0xc5, 0x58, 0x61, 0x43, 0x52, 0x1f, 0x61, 0x43, 0xd4, 0xe0, 0xc7,
+ 0x8e, 0xe0, 0x0f, 0x0c, 0x13, 0x40, 0x7e, 0x11, 0x13, 0x0f, 0x13, 0x40,
+ 0x5b, 0x0e, 0x10, 0x0e, 0xaa, 0x7a, 0x65, 0x1f, 0x60, 0x7a, 0x72, 0x1f,
+ 0x60, 0xfa, 0xe0, 0xc7, 0x71, 0xf9, 0x03, 0xc0, 0x78, 0x40, 0x1f, 0x60,
+ 0x78, 0x59, 0x1f, 0x60, 0x79, 0x47, 0x1f, 0x60, 0x78, 0xd5, 0xc0, 0x67,
+ 0xf8, 0x06, 0x13, 0x12, 0x16, 0x16, 0x9c, 0x6d, 0x1f, 0x60, 0x78, 0x47,
+ 0x1f, 0x60, 0x78, 0x44, 0x1f, 0x60, 0x79, 0x4c, 0x1f, 0x60, 0x78, 0xc1,
+ 0xc0, 0x49, 0x68, 0x1f, 0x60, 0x78, 0x76, 0x1f, 0x60, 0x78, 0x41, 0x1f,
+ 0x60, 0x78, 0x69, 0x1f, 0x60, 0x78, 0xf2, 0xba, 0x63, 0x1f, 0x60, 0x78,
+ 0x71, 0x1f, 0x60, 0x78, 0x50, 0x1f, 0x60, 0x78, 0x5a, 0x1f, 0x60, 0x78,
+ 0x72, 0x1f, 0x60, 0x78, 0xe5, 0xa4, 0x58, 0x1f, 0x60, 0x78, 0x78, 0x1f,
+ 0x60, 0x78, 0x63, 0x1f, 0x60, 0x78, 0x41, 0x1f, 0x60, 0x78, 0x74, 0x1f,
+ 0x60, 0x78, 0xc8, 0x8e, 0x57, 0x1f, 0x60, 0x78, 0x6b, 0x1f, 0x60, 0x78,
+ 0x72, 0x1f, 0x60, 0x78, 0x63, 0x2e, 0x1f, 0x60, 0x79, 0x44, 0x1f, 0x60,
+ 0x78, 0x57, 0x1f, 0x60, 0xf8, 0xe0, 0xbc, 0x92, 0x44, 0x1f, 0x60, 0x78,
+ 0x6d, 0x1f, 0xe0, 0xe0, 0x6a, 0x51, 0x76, 0x7d, 0x1f, 0x60, 0x76, 0x42,
+ 0x1f, 0x60, 0x76, 0x5a, 0x1f, 0x60, 0x77, 0xcf, 0xe0, 0xc6, 0xd0, 0x74,
+ 0x6d, 0x1f, 0x60, 0x74, 0x7e, 0x1f, 0x60, 0x74, 0x70, 0x1f, 0x60, 0x74,
+ 0x64, 0x1f, 0x60, 0xf4, 0xc3, 0x89, 0x72, 0x6d, 0x1f, 0x60, 0x72, 0x7e,
+ 0x1f, 0x60, 0x72, 0x70, 0x1f, 0xe0, 0xe0, 0xb6, 0xc1, 0x70, 0x6d, 0x1f,
+ 0x60, 0x70, 0x7e, 0x1f, 0x60, 0x70, 0x70, 0x1f, 0x60, 0x70, 0x64, 0x1f,
+ 0x60, 0xf1, 0xc0, 0xeb, 0xee, 0x02, 0xaa, 0x5a, 0x1f, 0x60, 0x6e, 0x7f,
+ 0x1f, 0x60, 0x6e, 0x59, 0x1f, 0x60, 0x6f, 0x4d, 0x1f, 0x60, 0x6e, 0x55,
+ 0x1f, 0x60, 0x6e, 0x6a, 0x1f, 0x60, 0x6f, 0x4d, 0x1f, 0x60, 0x6e, 0x6a,
+ 0x1f, 0x60, 0x6f, 0x42, 0x1f, 0x60, 0x6e, 0x70, 0x1f, 0x60, 0xef, 0xc0,
+ 0xbe, 0x47, 0x1f, 0x60, 0xee, 0x02, 0x92, 0x72, 0x1f, 0x60, 0x6e, 0x59,
+ 0x1f, 0x60, 0x6f, 0x4d, 0x1f, 0x60, 0x6e, 0x55, 0x1f, 0x60, 0xef, 0xc2,
+ 0x69, 0x68, 0x1f, 0x60, 0x6f, 0x4d, 0x1f, 0x60, 0x6e, 0x64, 0x1f, 0x60,
+ 0x6e, 0x7f, 0x1f, 0x60, 0x6e, 0x6f, 0x1f, 0x60, 0xee, 0xc0, 0x54, 0x6c,
+ 0x6d, 0x1f, 0x60, 0x6c, 0x7e, 0x1f, 0x60, 0x6c, 0x70, 0x1f, 0xe0, 0xd8,
+ 0xf6, 0x6a, 0x6d, 0x1f, 0x60, 0x6a, 0x7e, 0x1f, 0x60, 0x6a, 0x70, 0x1f,
+ 0x60, 0xea, 0xe0, 0xc3, 0xd6, 0x68, 0x6d, 0x1f, 0x60, 0x68, 0x7e, 0x1f,
+ 0x60, 0x68, 0x70, 0x1f, 0xe0, 0xce, 0x73, 0xe6, 0x02, 0x93, 0x6d, 0x1f,
+ 0x60, 0x66, 0x7e, 0x1f, 0xe0, 0x02, 0x82, 0xe7, 0x82, 0x66, 0x70, 0x1f,
+ 0x60, 0xe6, 0xe0, 0xc3, 0xb2, 0x6c, 0x1f, 0x60, 0x66, 0x7e, 0x1f, 0x60,
+ 0x66, 0x42, 0x1f, 0x60, 0x66, 0x72, 0x1f, 0x60, 0x66, 0xfe, 0xe0, 0xc5,
+ 0xea, 0xe4, 0x04, 0x11, 0x26, 0x8c, 0x78, 0x1f, 0x60, 0x64, 0x42, 0x1f,
+ 0x60, 0x64, 0x57, 0x1f, 0x60, 0x64, 0x60, 0x1f, 0xe0, 0xcc, 0x82, 0x6d,
+ 0x1f, 0x60, 0x64, 0x7e, 0x1f, 0x60, 0x64, 0x70, 0x1f, 0xe0, 0x02, 0x88,
+ 0x65, 0x4b, 0x1f, 0x60, 0xe4, 0xe0, 0xc3, 0x73, 0x64, 0xe4, 0x04, 0xe0,
+ 0xc5, 0xb6, 0x1f, 0x60, 0x64, 0x6e, 0x1f, 0x60, 0x65, 0xcd, 0xe0, 0xc5,
+ 0xae, 0x68, 0x1f, 0x60, 0x65, 0x47, 0x1f, 0x60, 0x64, 0xdf, 0xe0, 0xc5,
+ 0xa2, 0x55, 0x1f, 0x60, 0x65, 0x49, 0x1f, 0xe0, 0xe0, 0xbf, 0x9b, 0x5a,
+ 0xc0, 0xc0, 0xd9, 0xd9, 0x06, 0x14, 0x0d, 0x34, 0x1a, 0x86, 0x7e, 0x1f,
+ 0x58, 0x67, 0x9f, 0x02, 0x83, 0x5a, 0xe9, 0x83, 0x59, 0x43, 0x1f, 0x58,
+ 0x73, 0x1f, 0x58, 0xea, 0xc1, 0x2c, 0x47, 0x1f, 0x59, 0x45, 0x1f, 0x58,
+ 0x71, 0x1f, 0x58, 0x67, 0x9f, 0xc1, 0x40, 0x45, 0x9f, 0x02, 0xac, 0xd9,
+ 0x02, 0x9a, 0x48, 0x9f, 0x02, 0x87, 0x59, 0x42, 0x1f, 0xd8, 0xe0, 0xc3,
+ 0x23, 0x58, 0x71, 0x1f, 0x59, 0x4a, 0x1f, 0x58, 0x6a, 0x1f, 0x58, 0x67,
+ 0x1f, 0x59, 0xc6, 0x88, 0x44, 0x1f, 0x59, 0x4a, 0x1f, 0x58, 0x73, 0x1f,
+ 0x59, 0x4a, 0x1f, 0xd8, 0xe0, 0xc5, 0x3b, 0x58, 0xf5, 0xc1, 0x1f, 0x43,
+ 0x9f, 0x02, 0x86, 0x59, 0x48, 0x1f, 0xd9, 0xc2, 0xe6, 0x58, 0x67, 0x1f,
+ 0x58, 0x6b, 0x1f, 0x59, 0x48, 0x1f, 0x59, 0x44, 0x1f, 0x59, 0xca, 0xc0,
+ 0x6e, 0x42, 0x1f, 0x58, 0xf7, 0xc0, 0xff, 0x41, 0x1f, 0x59, 0x44, 0x1f,
+ 0x58, 0x73, 0x1f, 0x58, 0xf7, 0xc0, 0xff, 0xd8, 0x06, 0x15, 0x0a, 0x16,
+ 0x0c, 0xa4, 0x79, 0x9f, 0x02, 0x84, 0x59, 0xc5, 0xc0, 0xb0, 0x58, 0x71,
+ 0x1f, 0xd8, 0x04, 0xe0, 0xc2, 0x62, 0x67, 0x1f, 0xd9, 0xc1, 0xbc, 0x74,
+ 0x1f, 0x58, 0x68, 0x1f, 0x59, 0x43, 0x9f, 0xc0, 0xbf, 0x73, 0x1f, 0x59,
+ 0x48, 0x1f, 0xd8, 0x02, 0x8b, 0x71, 0x1f, 0x59, 0x4a, 0x1f, 0xd8, 0x60,
+ 0xc2, 0xbc, 0xc2, 0x18, 0xef, 0xc0, 0x83, 0x6a, 0x1f, 0x59, 0x48, 0x1f,
+ 0x59, 0x46, 0x1f, 0xd8, 0xe0, 0xc2, 0x5b, 0x68, 0x9f, 0x03, 0x08, 0x89,
+ 0x5a, 0x7e, 0x1f, 0x58, 0x67, 0x1f, 0xd8, 0x96, 0x59, 0x4a, 0x1f, 0x58,
+ 0x6a, 0x1f, 0xd9, 0xc0, 0x79, 0x58, 0x67, 0x1f, 0xd8, 0x02, 0x86, 0x72,
+ 0x1f, 0x58, 0xe7, 0xc0, 0x89, 0xf1, 0xa7, 0x67, 0x9f, 0x04, 0x03, 0xc0,
+ 0x99, 0x5b, 0xcc, 0x86, 0xd9, 0x03, 0x0f, 0x8f, 0x4a, 0x1f, 0x58, 0x71,
+ 0x1f, 0x58, 0x67, 0x1f, 0x59, 0xc6, 0x4d, 0x9d, 0xe0, 0xb6, 0xe9, 0x45,
+ 0x1f, 0x58, 0x67, 0x1f, 0x58, 0x71, 0x1f, 0x58, 0x67, 0x1f, 0xd8, 0xe0,
+ 0xc2, 0x35, 0x44, 0x9f, 0x02, 0x95, 0xd9, 0x02, 0x86, 0x4a, 0x1f, 0x59,
+ 0xc5, 0xc0, 0x66, 0x45, 0x1f, 0x58, 0x7a, 0x1f, 0x58, 0x71, 0x1f, 0xd8,
+ 0xe0, 0xc1, 0xcc, 0xd8, 0x05, 0x0c, 0x25, 0x0f, 0x8b, 0x79, 0x1f, 0x59,
+ 0x44, 0x1f, 0x59, 0x4a, 0x1f, 0x58, 0xe7, 0xc0, 0x48, 0x73, 0x1f, 0x58,
+ 0x79, 0x1f, 0x59, 0x48, 0x1f, 0x58, 0x6f, 0x9f, 0x02, 0x8a, 0x5b, 0x4c,
+ 0x9f, 0x02, 0x8f, 0x5b, 0xc3, 0xe0, 0xc4, 0x33, 0x59, 0x4a, 0x9f, 0x02,
+ 0x85, 0x59, 0xc7, 0xe0, 0xc4, 0x29, 0xd8, 0xe0, 0xc2, 0x0c, 0x6c, 0x1f,
+ 0x58, 0x72, 0x1f, 0x58, 0x67, 0x1f, 0x58, 0x66, 0x1f, 0xd8, 0xe0, 0xa3,
+ 0xce, 0x68, 0x1f, 0x58, 0x6d, 0x1f, 0x58, 0x71, 0x1f, 0x59, 0xca, 0x88,
+ 0x67, 0x1f, 0x58, 0x71, 0x1f, 0x58, 0x6f, 0x1f, 0x59, 0xc6, 0xe0, 0xc3,
+ 0xfe, 0xd8, 0x02, 0x90, 0x71, 0x1f, 0x58, 0x67, 0x1f, 0x59, 0x45, 0x1f,
+ 0x59, 0x43, 0x1f, 0x59, 0xc8, 0xe0, 0xc3, 0xeb, 0x68, 0x1f, 0x59, 0x48,
+ 0x1f, 0x58, 0x78, 0x1f, 0x58, 0x68, 0x1f, 0x59, 0xca, 0xe0, 0xc3, 0xdb,
+ 0xd7, 0x05, 0x0a, 0x05, 0x0b, 0x8d, 0x67, 0x1f, 0x57, 0x55, 0x1f, 0x57,
+ 0xdd, 0xe0, 0xc3, 0xcb, 0x66, 0x1f, 0x57, 0xd4, 0x88, 0x5e, 0x1f, 0x57,
+ 0x5e, 0x1f, 0x57, 0x69, 0x1f, 0x57, 0xdc, 0x9e, 0x59, 0x1f, 0x57, 0x69,
+ 0x1f, 0xd7, 0x02, 0x9e, 0x55, 0x1f, 0x57, 0xd1, 0x91, 0x50, 0x1f, 0x57,
+ 0x67, 0x1f, 0x57, 0x53, 0x1f, 0x57, 0x5e, 0x1f, 0x57, 0x59, 0x1f, 0x57,
+ 0x54, 0x2e, 0x1f, 0x57, 0x59, 0x1f, 0x57, 0x69, 0x1f, 0x57, 0x68, 0x1f,
+ 0x57, 0x50, 0x1f, 0x57, 0xdc, 0xe0, 0xc3, 0x8b, 0x55, 0x70, 0x1f, 0x55,
+ 0x61, 0x1f, 0xd5, 0xe0, 0xc2, 0x81, 0x52, 0x5b, 0x1f, 0x50, 0x70, 0x1f,
+ 0xd0, 0xe0, 0xc1, 0x07, 0xd1, 0x04, 0x03, 0x0d, 0xb0, 0xcf, 0xc1, 0x00,
+ 0x43, 0x1f, 0xd0, 0x03, 0xc0, 0x50, 0x7a, 0x1f, 0x51, 0xc0, 0xe0, 0xc3,
+ 0x62, 0x41, 0x9f, 0x03, 0xc1, 0x06, 0xd0, 0x03, 0x06, 0x89, 0x7f, 0x1f,
+ 0x50, 0xf1, 0xc0, 0xe4, 0x7e, 0x1f, 0x51, 0x47, 0x1f, 0x50, 0xf8, 0xc0,
+ 0xdb, 0x70, 0x1f, 0xd0, 0x02, 0x8c, 0x7c, 0x1f, 0x50, 0x70, 0x1f, 0x51,
+ 0x40, 0x1f, 0x50, 0xf0, 0xc0, 0xca, 0x79, 0x1f, 0x51, 0xc2, 0xe0, 0xc3,
+ 0x32, 0x40, 0x1f, 0xd1, 0x02, 0x84, 0xc4, 0xe0, 0xc3, 0x29, 0x43, 0x1f,
+ 0x51, 0xc1, 0xe0, 0xc3, 0x22, 0xd0, 0x08, 0x02, 0x2c, 0x31, 0x2a, 0x07,
+ 0x0c, 0x9d, 0xff, 0xa8, 0x7e, 0x9f, 0x02, 0x8f, 0x51, 0x40, 0x1f, 0x50,
+ 0xf3, 0x04, 0xe0, 0xc3, 0x07, 0x2e, 0x1f, 0xd1, 0x40, 0x99, 0x95, 0xd0,
+ 0x03, 0x0c, 0x83, 0x7d, 0x1f, 0x50, 0x7b, 0x1f, 0x50, 0x70, 0x1f, 0x50,
+ 0x79, 0x9f, 0xaa, 0xf4, 0xc0, 0x97, 0x71, 0x1f, 0x51, 0xc0, 0xc0, 0x91,
+ 0x7c, 0x9f, 0x02, 0x87, 0x51, 0x41, 0x1f, 0x50, 0xfa, 0xc0, 0x71, 0xd0,
+ 0x03, 0x16, 0x86, 0x7e, 0x9f, 0x02, 0x8d, 0x51, 0x41, 0x1f, 0x50, 0x7a,
+ 0x1f, 0x50, 0x72, 0x1f, 0xd0, 0xe0, 0xc1, 0x2e, 0x50, 0xfd, 0xe0, 0xc2,
+ 0xc6, 0x7a, 0x1f, 0xd0, 0xe0, 0xc1, 0x02, 0x78, 0x1f, 0x51, 0xc0, 0xc0,
+ 0x4b, 0x7a, 0x9f, 0x02, 0x89, 0x51, 0x40, 0x1f, 0x51, 0x4b, 0x1f, 0x50,
+ 0xfc, 0xbd, 0xd0, 0x02, 0x88, 0x7e, 0x1f, 0x50, 0xfc, 0x35, 0xe0, 0xc2,
+ 0x6e, 0x70, 0x1f, 0x51, 0x42, 0x1f, 0x50, 0x7e, 0x1f, 0x50, 0x7b, 0x1f,
+ 0x50, 0x78, 0x1f, 0xd0, 0xe0, 0xc0, 0x1d, 0x75, 0x1f, 0x51, 0xce, 0xe0,
+ 0xc2, 0x89, 0x74, 0x1f, 0x50, 0x75, 0x1f, 0x51, 0x42, 0x1f, 0xd0, 0xe0,
+ 0xba, 0xfb, 0x71, 0x1f, 0xd0, 0x05, 0x11, 0xe0, 0xbf, 0xf8, 0x78, 0x1f,
+ 0x50, 0x77, 0x2e, 0x1f, 0x51, 0x40, 0x1f, 0x51, 0x43, 0x1f, 0x51, 0xc1,
+ 0xe0, 0xc2, 0x60, 0x75, 0x1f, 0xd0, 0x9c, 0x70, 0x1f, 0x50, 0x7a, 0x2e,
+ 0x1f, 0x51, 0x41, 0x1f, 0x51, 0x40, 0x1f, 0xd0, 0xe0, 0xa2, 0x08, 0x4e,
+ 0x75, 0x9f, 0x02, 0x85, 0x4f, 0xc5, 0xe0, 0xc2, 0x46, 0x4e, 0xfb, 0xe0,
+ 0xc2, 0x41, 0x44, 0x4d, 0x1f, 0x43, 0xe1, 0xe0, 0xaa, 0x21, 0xc3, 0x03,
+ 0x28, 0xa7, 0xf8, 0x05, 0x08, 0x04, 0x06, 0x8c, 0xf9, 0x60, 0x44, 0xdc,
+ 0x11, 0xe0, 0x71, 0x95, 0xf6, 0xe0, 0x52, 0x48, 0x73, 0x74, 0xf2, 0xe0,
+ 0x45, 0xf6, 0xf2, 0x04, 0xe0, 0xb5, 0x5e, 0xf3, 0x60, 0x95, 0xb1, 0xe0,
+ 0x26, 0x3a, 0xeb, 0xe0, 0x8d, 0xdb, 0xe5, 0x09, 0x08, 0x05, 0x0c, 0x60,
+ 0x93, 0xf3, 0xde, 0x4e, 0xf3, 0x60, 0xb6, 0x8a, 0x47, 0x20, 0xc2, 0xc0,
+ 0xed, 0x60, 0xba, 0x59, 0x84, 0xec, 0x07, 0x60, 0x81, 0x42, 0xe0, 0x3f,
+ 0x14, 0xe7, 0xe0, 0x47, 0x77, 0xeb, 0xe0, 0xbb, 0xac, 0xe1, 0x02, 0x8b,
+ 0xec, 0x02, 0x84, 0xf4, 0xe0, 0x83, 0x52, 0xe1, 0xe0, 0xbb, 0x62, 0x6b,
+ 0x1f, 0x45, 0xcb, 0xe0, 0xbb, 0xa3, 0xfa, 0x13, 0x0e, 0x04, 0x10, 0x0b,
+ 0x04, 0x04, 0x12, 0x0d, 0x0c, 0x53, 0x50, 0x60, 0x84, 0x04, 0x60, 0x27,
+ 0x96, 0x9e, 0xf5, 0x02, 0x85, 0x73, 0xe8, 0xe0, 0xb5, 0x46, 0x65, 0x72,
+ 0xe9, 0xe0, 0xac, 0x12, 0xf4, 0xe0, 0xa6, 0xa3, 0xf0, 0x02, 0x86, 0x69,
+ 0x73, 0xe4, 0xe0, 0x33, 0x3d, 0xae, 0x60, 0x84, 0x75, 0xe0, 0x22, 0x22,
+ 0xef, 0x04, 0xe0, 0xab, 0x75, 0x6d, 0x62, 0xe9, 0xe0, 0xb2, 0xa3, 0xec,
+ 0xe0, 0xa2, 0xd2, 0xe9, 0xe0, 0xbf, 0xeb, 0xe8, 0x02, 0x86, 0x79, 0x74,
+ 0x6f, 0x6d, 0xf9, 0x86, 0x69, 0x74, 0x6f, 0x6d, 0x69, 0xf2, 0xe0, 0xa6,
+ 0x6e, 0x67, 0x6f, 0xf2, 0x04, 0xe0, 0xb2, 0x88, 0x7a, 0x65, 0xec, 0xe0,
+ 0xac, 0x1b, 0xe5, 0x04, 0xe0, 0xbf, 0xd5, 0x6e, 0x74, 0x73, 0xf5, 0xe0,
+ 0x6d, 0x8f, 0xe1, 0x0a, 0x06, 0x19, 0x08, 0x12, 0x05, 0x0a, 0xe0, 0x26,
+ 0x82, 0xf2, 0x60, 0xb4, 0xa3, 0xcb, 0x04, 0xf0, 0x03, 0x05, 0x84, 0x74,
+ 0xef, 0xe0, 0xad, 0x7a, 0xf0, 0xe0, 0x9f, 0xe4, 0x6f, 0x72, 0x69, 0x7a,
+ 0x68, 0x7a, 0xe8, 0x58, 0x4f, 0xe0, 0x21, 0x45, 0x6d, 0xe1, 0x60, 0x82,
+ 0xfa, 0xe0, 0x39, 0x71, 0xeb, 0x02, 0x87, 0x6f, 0x70, 0x61, 0xee, 0xe0,
+ 0x86, 0xeb, 0x61, 0x72, 0x70, 0x61, 0x74, 0xf4, 0xd8, 0x32, 0x67, 0xe1,
+ 0xe0, 0xaf, 0x78, 0x63, 0x68, 0x70, 0x6f, 0x6d, 0x6f, 0xf2, 0xe0, 0xbc,
+ 0x4f, 0xae, 0x60, 0x83, 0x1d, 0x60, 0x3b, 0x1a, 0x42, 0xac, 0x9c, 0xf9,
+ 0x0f, 0x40, 0x4d, 0x40, 0xc1, 0x09, 0x04, 0x0a, 0x2a, 0x60, 0x95, 0x98,
+ 0xe0, 0x28, 0x48, 0xf5, 0x0d, 0x07, 0x0b, 0x0d, 0x0d, 0x0a, 0x04, 0x60,
+ 0x7c, 0xaa, 0xe0, 0x42, 0xc1, 0x7a, 0xe1, 0x60, 0x72, 0x5d, 0xd7, 0x4b,
+ 0x73, 0xf5, 0x04, 0xe0, 0xb9, 0x78, 0x68, 0xe1, 0xe0, 0x52, 0xd9, 0xf2,
+ 0x04, 0xe0, 0xb6, 0x1f, 0x69, 0x68, 0x6f, 0x6e, 0xea, 0xe0, 0x8a, 0x20,
+ 0xeb, 0x04, 0xe0, 0xa5, 0x49, 0x75, 0x68, 0x61, 0x73, 0xe8, 0xe0, 0x77,
+ 0xff, 0x67, 0x61, 0x77, 0xe1, 0x60, 0x73, 0x2f, 0xe0, 0x48, 0x14, 0xe6,
+ 0xe0, 0xae, 0xca, 0x61, 0xf3, 0xe0, 0xb5, 0xfa, 0xef, 0x0d, 0x0a, 0x0a,
+ 0x22, 0x09, 0x16, 0x0c, 0x05, 0x3d, 0x09, 0xe0, 0x75, 0x11, 0xf5, 0x04,
+ 0xe0, 0xc0, 0x8d, 0x74, 0xf5, 0xe0, 0xbe, 0x57, 0x74, 0x73, 0x75, 0x6b,
+ 0x61, 0x69, 0xe4, 0xe0, 0xbe, 0xa2, 0x73, 0x68, 0xe9, 0x08, 0x0b, 0x04,
+ 0x60, 0x6d, 0x57, 0xdc, 0x6d, 0x6e, 0xef, 0x04, 0xe0, 0xb8, 0x12, 0x67,
+ 0xe1, 0xe0, 0x78, 0x67, 0xeb, 0xe0, 0x48, 0x04, 0x64, 0x61, 0x2e, 0xf3,
+ 0x60, 0xb5, 0xf8, 0x88, 0xf2, 0x04, 0xe0, 0x85, 0x60, 0xe9, 0xe0, 0x71,
+ 0x61, 0xee, 0x05, 0x04, 0xe0, 0x89, 0xb8, 0xe5, 0xe0, 0x49, 0x71, 0xe1,
+ 0x04, 0xe0, 0x81, 0x23, 0xe7, 0x60, 0x34, 0xe3, 0xe0, 0x86, 0xc5, 0xed,
+ 0x02, 0x85, 0x69, 0xf4, 0xe0, 0x86, 0xa6, 0xe2, 0xe0, 0x60, 0x7e, 0x6c,
+ 0xe1, 0xe0, 0x2d, 0x5c, 0xeb, 0x03, 0x21, 0x88, 0xef, 0x06, 0x04, 0x10,
+ 0xe0, 0x48, 0xe3, 0xfa, 0xe0, 0x6b, 0x8c, 0xf3, 0x04, 0xe0, 0x7d, 0x07,
+ 0x68, 0x69, 0x62, 0x61, 0x68, 0x69, 0x6b, 0xe1, 0xe0, 0x6b, 0x45, 0x68,
+ 0x61, 0xed, 0xe0, 0x52, 0x54, 0x6b, 0x61, 0x69, 0x63, 0xe8, 0xe0, 0x68,
+ 0xc8, 0xe1, 0x07, 0x60, 0x77, 0x59, 0xe0, 0x43, 0xc5, 0x69, 0x63, 0x68,
+ 0x69, 0xe2, 0xe0, 0x80, 0x11, 0xe9, 0x04, 0xe0, 0x69, 0xff, 0xf4, 0xe0,
+ 0x71, 0x6a, 0x64, 0x6f, 0x62, 0xe1, 0xe0, 0x58, 0x2b, 0xee, 0x04, 0xe0,
+ 0xac, 0x6b, 0xe8, 0xe0, 0xbf, 0x47, 0xeb, 0xe0, 0xbe, 0x2c, 0xe5, 0x04,
+ 0xe0, 0xbf, 0xcd, 0x6e, 0xe2, 0xe0, 0x97, 0xd2, 0x62, 0x6f, 0xae, 0x05,
+ 0x06, 0x08, 0x08, 0x86, 0x74, 0x72, 0xe1, 0xe0, 0xbf, 0x1d, 0x73, 0x63,
+ 0x69, 0x65, 0xee, 0xe0, 0xa0, 0x5e, 0x72, 0x65, 0x76, 0x69, 0xe5, 0xe0,
+ 0xab, 0x30, 0x70, 0x61, 0xf2, 0xe0, 0x53, 0xd2, 0x66, 0x61, 0xe9, 0xe0,
+ 0x7a, 0x15, 0xe1, 0x11, 0x0e, 0x17, 0x20, 0x07, 0x12, 0x40, 0x92, 0x0b,
+ 0x10, 0x09, 0x0f, 0x04, 0x16, 0xe0, 0xa2, 0x67, 0x77, 0xe1, 0x04, 0xe0,
+ 0x6a, 0xec, 0x74, 0xe1, 0x60, 0x4d, 0x81, 0xe0, 0x63, 0xce, 0xf4, 0x02,
+ 0x8f, 0x73, 0xf5, 0x02, 0x87, 0x73, 0x68, 0x69, 0xf2, 0xe0, 0xb4, 0xfb,
+ 0xeb, 0xe0, 0x7f, 0xdb, 0x6f, 0xed, 0xe0, 0xba, 0x20, 0xf3, 0x05, 0x10,
+ 0xe0, 0x77, 0x95, 0xf5, 0x07, 0x04, 0x60, 0xb9, 0x9d, 0xc0, 0x66, 0xef,
+ 0xe0, 0x77, 0x9d, 0xe4, 0xe0, 0x55, 0x63, 0x68, 0xe9, 0x04, 0xe0, 0x88,
+ 0xba, 0xf2, 0xe0, 0xb9, 0x18, 0xef, 0x60, 0x6a, 0xef, 0xe0, 0x52, 0x82,
+ 0xee, 0x02, 0x89, 0x64, 0x65, 0xf8, 0x60, 0x6f, 0x14, 0xe0, 0x50, 0x26,
+ 0xe1, 0x60, 0x34, 0x11, 0xd8, 0xbc, 0xed, 0x04, 0xe0, 0x63, 0xf8, 0xe1,
+ 0x09, 0x05, 0x04, 0x25, 0x07, 0x1f, 0x06, 0x06, 0x98, 0x7a, 0xef, 0xe0,
+ 0x57, 0x60, 0xf8, 0xe0, 0x9a, 0xca, 0xf4, 0x02, 0x85, 0x73, 0xf5, 0xe0,
+ 0x65, 0xba, 0xef, 0x03, 0x07, 0x87, 0x74, 0x61, 0x6b, 0xe1, 0xe0, 0x42,
+ 0x44, 0x6b, 0x6f, 0x72, 0xe9, 0xe0, 0x6b, 0xd6, 0xae, 0x04, 0xe0, 0xb9,
+ 0x8c, 0xeb, 0x60, 0xb7, 0xa5, 0xc2, 0x90, 0x73, 0x68, 0x69, 0xee, 0xe0,
+ 0x88, 0x09, 0xee, 0x02, 0x8b, 0xef, 0x02, 0x84, 0xf5, 0xe0, 0x2d, 0x46,
+ 0xe2, 0xe0, 0x7c, 0xa0, 0xe1, 0x02, 0x89, 0x73, 0x68, 0x69, 0xae, 0x60,
+ 0xa2, 0x8f, 0xda, 0x9b, 0x6b, 0xe1, 0xe0, 0x88, 0x52, 0x6d, 0x6f, 0xf4,
+ 0xe0, 0x24, 0x43, 0x6b, 0x69, 0xf4, 0xe0, 0xb9, 0xfe, 0xe7, 0x04, 0xe0,
+ 0xbc, 0xaa, 0xe1, 0x04, 0xe0, 0xb7, 0x62, 0x74, 0x61, 0xae, 0x60, 0xb3,
+ 0x89, 0x42, 0x51, 0x41, 0x47, 0x44, 0x7e, 0xc1, 0x68, 0x64, 0x61, 0xae,
+ 0x60, 0x88, 0x5a, 0x60, 0x2a, 0xbc, 0xc0, 0x6b, 0xec, 0x02, 0x84, 0xf4,
+ 0xe0, 0x9c, 0x2c, 0xe9, 0xe0, 0xa5, 0xcd, 0xeb, 0x02, 0x89, 0x75, 0x6d,
+ 0x6f, 0xae, 0x60, 0xb8, 0xd5, 0xc4, 0x01, 0x61, 0xe7, 0xd4, 0x06, 0xe9,
+ 0x04, 0xe0, 0x68, 0xe5, 0xf4, 0xe0, 0xb2, 0xf5, 0xe8, 0x05, 0x04, 0xe0,
+ 0x22, 0x24, 0xe9, 0xe0, 0x52, 0x44, 0x61, 0xe2, 0xe0, 0x56, 0x36, 0x65,
+ 0xf3, 0xd8, 0xec, 0x63, 0xe8, 0x04, 0xe0, 0xb4, 0xdc, 0xe9, 0x02, 0x88,
+ 0x79, 0x6f, 0xae, 0x60, 0xb6, 0xc8, 0xc5, 0xb4, 0x6d, 0xe1, 0xe0, 0x4f,
+ 0x2a, 0x62, 0xf5, 0x60, 0x6f, 0x1f, 0xe0, 0x4a, 0x55, 0xf8, 0x10, 0x06,
+ 0x09, 0x07, 0x50, 0x16, 0x04, 0x0c, 0x06, 0x0e, 0x05, 0x08, 0x07, 0xe0,
+ 0x6f, 0x4d, 0xf9, 0x60, 0xa5, 0x03, 0xd6, 0xbf, 0xf8, 0x04, 0xe0, 0xb6,
+ 0xa9, 0xae, 0xe0, 0xab, 0x21, 0x73, 0x34, 0x61, 0x6c, 0xec, 0xda, 0x23,
+ 0xee, 0x03, 0xda, 0x34, 0x2d, 0xad, 0x3a, 0x1f, 0x40, 0x43, 0x21, 0x2e,
+ 0x40, 0xd6, 0x40, 0x40, 0x40, 0xab, 0x41, 0x05, 0x40, 0xcc, 0x27, 0x31,
+ 0x40, 0x48, 0x40, 0x91, 0x41, 0xb0, 0x40, 0x9c, 0x40, 0xd8, 0x40, 0x48,
+ 0x2f, 0x40, 0xd5, 0x40, 0x91, 0x40, 0xb7, 0x3e, 0x40, 0x50, 0x40, 0x95,
+ 0x41, 0x08, 0x38, 0x32, 0x40, 0x5e, 0x09, 0x25, 0x40, 0x6a, 0x40, 0x67,
+ 0x3a, 0x13, 0xc0, 0x5f, 0xfa, 0x02, 0x96, 0xe6, 0x02, 0x84, 0x72, 0xb1,
+ 0xcb, 0x00, 0x30, 0xe1, 0x02, 0x84, 0x76, 0xf8, 0xcb, 0xe8, 0x6f, 0x36,
+ 0x34, 0xe1, 0xe0, 0x93, 0x5f, 0x62, 0x78, 0x30, 0xb2, 0xce, 0x60, 0xf9,
+ 0x05, 0x11, 0x14, 0x0a, 0x87, 0x73, 0x74, 0x72, 0x65, 0x2d, 0x73, 0x6c,
+ 0x69, 0x64, 0x72, 0x65, 0x2d, 0x75, 0xea, 0xe0, 0x31, 0x91, 0xe7, 0x02,
+ 0x88, 0x62, 0x69, 0x32, 0x61, 0xed, 0xe0, 0x82, 0xd9, 0x61, 0x72, 0x64,
+ 0x65, 0x6e, 0x2d, 0xf0, 0xc9, 0x0f, 0x66, 0x72, 0x6f, 0x34, 0x69, 0x36,
+ 0xb7, 0xe0, 0xbc, 0x04, 0x65, 0x72, 0x2d, 0xfa, 0xe0, 0xb2, 0xbd, 0x39,
+ 0x61, 0x33, 0xe1, 0xe0, 0x9d, 0x39, 0xf8, 0x02, 0x98, 0x6b, 0x63, 0xb2,
+ 0x02, 0x8b, 0x64, 0x6c, 0x33, 0x61, 0x35, 0x65, 0x65, 0xb0, 0xe0, 0xba,
+ 0xde, 0x61, 0x6c, 0x33, 0x68, 0x79, 0xe5, 0xcd, 0x2b, 0x68, 0x71, 0x35,
+ 0xb2, 0xcf, 0x12, 0xf7, 0x03, 0x0a, 0x88, 0x67, 0xe2, 0x02, 0x83, 0xec,
+ 0xc4, 0x66, 0xe8, 0xce, 0x6a, 0x63, 0x76, 0x73, 0x32, 0x32, 0xe4, 0xc9,
+ 0x82, 0x34, 0xf2, 0x02, 0x86, 0x73, 0x34, 0xb0, 0xe0, 0xba, 0xf1, 0x38,
+ 0x35, 0x65, 0x6c, 0x38, 0x66, 0x68, 0x75, 0x35, 0x64, 0xee, 0xe0, 0xa4,
+ 0xf4, 0xf6, 0x07, 0x06, 0x19, 0x19, 0x06, 0x1f, 0xb9, 0x75, 0x71, 0x38,
+ 0xb6, 0xce, 0xd6, 0xf2, 0x04, 0x09, 0xc4, 0x55, 0x67, 0x67, 0x74, 0x2d,
+ 0x78, 0xf1, 0xe0, 0x8a, 0x3f, 0x65, 0x2d, 0x65, 0x69, 0x6b, 0x65, 0x72,
+ 0x2d, 0xeb, 0xc7, 0x41, 0x6c, 0x65, 0x72, 0x2d, 0x71, 0x6f, 0x61, 0xae,
+ 0x03, 0xd5, 0xc8, 0x78, 0x6e, 0x2d, 0x2d, 0x73, 0x74, 0x66, 0x6f, 0x6c,
+ 0x64, 0x2d, 0xb9, 0xcc, 0x19, 0x68, 0x71, 0xf5, 0xe0, 0xb9, 0x30, 0xe7,
+ 0x04, 0x06, 0x09, 0x86, 0x75, 0x34, 0x30, 0xb2, 0xcd, 0x75, 0x73, 0x79,
+ 0x2d, 0x71, 0x6f, 0x61, 0xb0, 0xc6, 0xf8, 0x61, 0x6e, 0x2d, 0xf1, 0xcb,
+ 0x67, 0x2d, 0x79, 0xe9, 0xcb, 0x9f, 0xe5, 0x03, 0x0d, 0x9e, 0x73, 0x74,
+ 0x76, 0x67, 0x79, 0x2d, 0x69, 0x78, 0x61, 0xb6, 0xe0, 0xb4, 0x70, 0x72,
+ 0x6d, 0x67, 0x65, 0x6e, 0x73, 0x62, 0x65, 0x72, 0x61, 0xf4, 0x02, 0x89,
+ 0x75, 0x6e, 0x67, 0x2d, 0x70, 0xf7, 0xe0, 0xb2, 0x4d, 0x65, 0x72, 0x2d,
+ 0x63, 0xf4, 0xe0, 0xb2, 0x45, 0x67, 0x72, 0x73, 0x68, 0x65, 0x69, 0x2d,
+ 0xe3, 0xc9, 0x00, 0xe1, 0x03, 0x04, 0xac, 0x72, 0xe4, 0xc9, 0x86, 0x6c,
+ 0x6c, 0xe5, 0x03, 0x02, 0x8b, 0xe4, 0x9b, 0x61, 0x6f, 0x73, 0x74, 0x65,
+ 0x2d, 0x65, 0xb7, 0xe0, 0xb5, 0xea, 0xad, 0x02, 0x8c, 0x64, 0x2d, 0x61,
+ 0x6f, 0x73, 0x74, 0x65, 0x2d, 0x65, 0xe8, 0xd4, 0xc9, 0x61, 0x6f, 0x73,
+ 0x74, 0x65, 0x2d, 0x65, 0xe2, 0xd4, 0xbf, 0x64, 0xf3, 0xc9, 0x56, 0xf5,
+ 0x04, 0x08, 0x12, 0x8d, 0x75, 0x77, 0x75, 0x35, 0xb8, 0xe0, 0xba, 0x7f,
+ 0xee, 0x02, 0x86, 0x75, 0x70, 0xb4, 0xe0, 0xba, 0x0f, 0x6a, 0x72, 0x67,
+ 0x61, 0x2d, 0xf2, 0xe0, 0xb6, 0x14, 0x69, 0xf3, 0x02, 0x84, 0x7a, 0xb3,
+ 0xc3, 0x6a, 0x74, 0x32, 0xb2, 0xcd, 0x9c, 0x63, 0x30, 0xe1, 0x02, 0x85,
+ 0x79, 0x34, 0xe1, 0xca, 0x3d, 0x74, 0x76, 0xae, 0x4c, 0xdb, 0x60, 0x73,
+ 0x33, 0xdd, 0xbd, 0xf4, 0x09, 0x09, 0x40, 0x66, 0x08, 0x0f, 0x05, 0x0a,
+ 0x86, 0x79, 0x73, 0x76, 0x72, 0x2d, 0xf6, 0xe0, 0xaf, 0x57, 0xf2, 0x07,
+ 0x07, 0x09, 0x40, 0x4b, 0xc8, 0x66, 0x6f, 0x6d, 0x73, 0x2d, 0xfa, 0xcb,
+ 0x7c, 0x67, 0x73, 0x74, 0x61, 0x64, 0x2d, 0xf2, 0xc7, 0x67, 0x65, 0x6e,
+ 0x74, 0x69, 0xee, 0x03, 0x0e, 0x9b, 0x73, 0xe4, 0x03, 0xcb, 0x3d, 0x2d,
+ 0x74, 0x69, 0x72, 0x6f, 0x6c, 0x2d, 0xb6, 0xa8, 0xef, 0x02, 0x99, 0x2d,
+ 0x73, 0xe4, 0x02, 0x88, 0x74, 0x69, 0x72, 0x6f, 0x6c, 0x2d, 0xf3, 0xa3,
+ 0x2d, 0x74, 0x69, 0x72, 0x6f, 0x6c, 0x2d, 0x63, 0xb3, 0xd4, 0x1f, 0x2d,
+ 0x73, 0xe4, 0x02, 0x8a, 0x74, 0x69, 0x72, 0x6f, 0x6c, 0x2d, 0x37, 0xf6,
+ 0xd4, 0x10, 0x2d, 0x74, 0x69, 0x72, 0x6f, 0x6c, 0x2d, 0x72, 0xfa, 0xd4,
+ 0x05, 0xe1, 0xc8, 0xd7, 0x6f, 0x72, 0x31, 0x33, 0xb1, 0xe0, 0xb9, 0xee,
+ 0xee, 0x02, 0x87, 0x73, 0x62, 0x65, 0x72, 0xe7, 0xc7, 0x05, 0x30, 0x61,
+ 0xe7, 0xc9, 0xa3, 0x6a, 0x6d, 0xe5, 0xc8, 0x44, 0x69, 0x71, 0x34, 0x39,
+ 0x78, 0x71, 0xf9, 0xe0, 0xb9, 0x3d, 0x63, 0x6b, 0xf7, 0xe0, 0xb9, 0xfb,
+ 0x36, 0x30, 0x62, 0xb5, 0xc2, 0x82, 0xf3, 0x0d, 0x26, 0x3c, 0x25, 0x07,
+ 0x08, 0x2b, 0x04, 0x0f, 0x0c, 0x13, 0xc4, 0x49, 0xf4, 0x02, 0x8c, 0x72,
+ 0x65, 0x2d, 0x74, 0x6f, 0x74, 0x65, 0x6e, 0x2d, 0xfa, 0xc0, 0x6e, 0x6a,
+ 0x72, 0x64, 0x61, 0xec, 0x02, 0x8c, 0x73, 0x68, 0x61, 0x6c, 0x73, 0x65,
+ 0x6e, 0x2d, 0xf3, 0xe0, 0x2f, 0x24, 0x2d, 0xf3, 0xc6, 0xb3, 0xf2, 0x04,
+ 0x04, 0x07, 0x86, 0x75, 0xed, 0xc9, 0xfc, 0x72, 0x65, 0x69, 0x73, 0xe1,
+ 0xc6, 0xa1, 0x66, 0x6f, 0x6c, 0xe4, 0xc5, 0xfd, 0xad, 0x04, 0x0c, 0x06,
+ 0x85, 0x76, 0x61, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x72, 0x2d, 0xe7, 0xc0,
+ 0xa4, 0x6f, 0x64, 0x61, 0xec, 0xc6, 0x84, 0x66, 0x72, 0xef, 0xc4, 0xc5,
+ 0x61, 0x75, 0x72, 0x64, 0x61, 0x6c, 0x2d, 0xec, 0xc5, 0x37, 0xee, 0x04,
+ 0x06, 0x04, 0x8e, 0x73, 0x61, 0x2d, 0xf2, 0xc9, 0x8b, 0x65, 0xf3, 0xc1,
+ 0x4d, 0x64, 0x72, 0x65, 0x2d, 0x6c, 0x61, 0x6e, 0x64, 0x2d, 0x30, 0xe3,
+ 0xe0, 0x2e, 0xc8, 0x61, 0x73, 0x65, 0x2d, 0xee, 0xe0, 0xae, 0x2a, 0xed,
+ 0x03, 0xc8, 0x74, 0xec, 0xc7, 0x91, 0xec, 0x03, 0xc9, 0x9d, 0x61, 0xf4,
+ 0xc0, 0xd5, 0xeb, 0x03, 0x11, 0x8d, 0xee, 0x02, 0x88, 0x6c, 0x61, 0x6e,
+ 0x64, 0x2d, 0xe6, 0xc9, 0xe5, 0x69, 0x74, 0x2d, 0xf9, 0xc9, 0xab, 0xea,
+ 0x02, 0x85, 0x6b, 0x2d, 0xf3, 0xc9, 0x45, 0x65, 0x72, 0xf6, 0xc0, 0xef,
+ 0x69, 0x65, 0x72, 0x76, 0x2d, 0xf5, 0xe0, 0xb4, 0x79, 0x67, 0xee, 0xc7,
+ 0x67, 0xe5, 0x02, 0x87, 0x73, 0x35, 0x35, 0xb4, 0xe0, 0xba, 0x93, 0x72,
+ 0x61, 0xec, 0xc7, 0x9f, 0x64, 0x74, 0x69, 0x72, 0x6f, 0x6c, 0x2d, 0x6e,
+ 0xb2, 0xe0, 0xb3, 0xf4, 0x61, 0x6e, 0xe4, 0x03, 0xc9, 0xfa, 0x6e, 0x65,
+ 0x73, 0x73, 0x6a, 0x65, 0x6e, 0x2d, 0x6f, 0xe7, 0xe0, 0x2e, 0x54, 0x39,
+ 0xe2, 0xcb, 0xe8, 0xf2, 0x0d, 0x10, 0x0b, 0x16, 0x05, 0x08, 0x06, 0x07,
+ 0x11, 0x0d, 0x32, 0x0a, 0x96, 0xf9, 0x02, 0x86, 0x72, 0x76, 0x69, 0xeb,
+ 0xc5, 0x2b, 0x6b, 0x65, 0x6e, 0x2d, 0xf6, 0xc9, 0xd0, 0x76, 0x63, 0x31,
+ 0x65, 0x30, 0x61, 0x6d, 0xb3, 0xe0, 0xb8, 0xc7, 0xf3, 0x02, 0x8e, 0xf4,
+ 0x02, 0x86, 0x61, 0x2d, 0xe6, 0xe0, 0xad, 0x85, 0x2d, 0xb0, 0xe0, 0xaf,
+ 0x67, 0x6b, 0x6f, 0xe7, 0xc4, 0x38, 0x72, 0x6f, 0xf3, 0xc8, 0xf0, 0x6f,
+ 0x76, 0x75, 0x38, 0xb8, 0xe0, 0xaf, 0xc7, 0x6e, 0x79, 0x33, 0xb1, 0xcb,
+ 0x86, 0x6d, 0x73, 0x6b, 0x6f, 0xe7, 0xc4, 0xe9, 0xec, 0x02, 0x89, 0x69,
+ 0x6e, 0x67, 0x65, 0x6e, 0x2d, 0xed, 0xc9, 0x2e, 0x61, 0x6e, 0xe4, 0xc4,
+ 0x0d, 0x69, 0xf3, 0x02, 0x83, 0xf2, 0xc9, 0xa6, 0x61, 0x2d, 0xb5, 0xe0,
+ 0xaf, 0x2a, 0xe8, 0x04, 0x12, 0x07, 0x88, 0xf4, 0x03, 0x05, 0x83, 0x36,
+ 0xb1, 0xe0, 0xb5, 0x1d, 0xb3, 0xcb, 0x83, 0x32, 0x37, 0xfa, 0xe0, 0xb8,
+ 0x32, 0x71, 0x76, 0x39, 0xb6, 0xe0, 0xb9, 0xd6, 0x6f, 0x6c, 0x74, 0x2d,
+ 0xed, 0xe0, 0xad, 0x1d, 0x6b, 0x6b, 0x65, 0x72, 0x76, 0x6a, 0x75, 0x2d,
+ 0x30, 0xb1, 0xc1, 0x80, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x79, 0x2d, 0xf6,
+ 0xc5, 0x2f, 0xe4, 0x03, 0x06, 0x86, 0x79, 0x2d, 0x30, 0xee, 0xc8, 0x81,
+ 0x65, 0x2d, 0xf5, 0xe0, 0x3c, 0xcc, 0x61, 0x6c, 0x2d, 0xf0, 0xc8, 0x38,
+ 0xe1, 0xc9, 0x49, 0xf1, 0x05, 0x07, 0x07, 0x08, 0x86, 0x78, 0xe1, 0x40,
+ 0xa7, 0xe0, 0xb6, 0x9c, 0x71, 0x71, 0x74, 0x31, 0xb1, 0xc7, 0xde, 0x63,
+ 0x6b, 0x61, 0x31, 0xf0, 0xe0, 0xad, 0xa0, 0x39, 0x6a, 0x79, 0xe2, 0xc8,
+ 0xcd, 0x37, 0x63, 0xe5, 0xc0, 0x8a, 0xf0, 0x04, 0x0e, 0x0e, 0x88, 0x73,
+ 0xf3, 0x02, 0x83, 0xf9, 0xc9, 0x2b, 0x75, 0x33, 0x33, 0xec, 0xe0, 0xb7,
+ 0xba, 0x6f, 0x72, 0x73, 0x67, 0x75, 0x2d, 0x73, 0x74, 0x61, 0x32, 0xb6,
+ 0xe0, 0x7b, 0xa9, 0x67, 0x62, 0x73, 0x30, 0xe4, 0xe0, 0xb6, 0xc0, 0x31,
+ 0xe1, 0x60, 0x24, 0x89, 0xe0, 0x92, 0xa9, 0xef, 0x07, 0x08, 0x0b, 0x0a,
+ 0x05, 0x0e, 0x8a, 0x74, 0x75, 0x37, 0x39, 0xb6, 0xe0, 0xb6, 0xec, 0xf3,
+ 0x02, 0x85, 0x79, 0x72, 0xef, 0xc6, 0xc9, 0xf4, 0xc4, 0x43, 0x70, 0x70,
+ 0x65, 0x67, 0x72, 0x64, 0x2d, 0xe9, 0xc8, 0x4a, 0x67, 0x62, 0xf0, 0xc1,
+ 0x75, 0x64, 0x30, 0xe1, 0x02, 0x85, 0x71, 0x33, 0xe2, 0xc7, 0x2b, 0x6c,
+ 0xe7, 0xc9, 0xc2, 0x33, 0xe3, 0x03, 0xca, 0xe5, 0x79, 0x78, 0xb2, 0xca,
+ 0xc9, 0x31, 0x61, 0xe3, 0x48, 0xd7, 0xb5, 0xee, 0x0a, 0x08, 0x0c, 0x1f,
+ 0x0a, 0x0f, 0x04, 0x08, 0x12, 0x87, 0x79, 0x71, 0x79, 0x32, 0xb6, 0xe0,
+ 0xb7, 0x46, 0x76, 0x75, 0x6f, 0x74, 0x6e, 0x61, 0x2d, 0x68, 0xf7, 0xe0,
+ 0xb2, 0xb9, 0xf4, 0x02, 0x8b, 0x74, 0x65, 0x72, 0x79, 0x2d, 0x62, 0x79,
+ 0xe1, 0xe0, 0xb7, 0x3d, 0xf3, 0x02, 0x87, 0x71, 0x31, 0x37, 0xe7, 0xe0,
+ 0xb7, 0x1d, 0x6f, 0x30, 0x69, 0x71, 0xf8, 0xc6, 0x09, 0x72, 0x79, 0x2d,
+ 0x79, 0x6c, 0x61, 0xb5, 0xe0, 0xb1, 0xc9, 0x71, 0x76, 0x37, 0xe6, 0x04,
+ 0xe0, 0xb8, 0xad, 0x73, 0x30, 0x30, 0xe5, 0xe0, 0x36, 0xa7, 0xef, 0xe0,
+ 0x7a, 0x96, 0x6e, 0x78, 0x33, 0x38, 0xb8, 0xe0, 0xb6, 0xf6, 0x6d, 0x65,
+ 0x73, 0x6a, 0x65, 0x76, 0x75, 0x65, 0x6d, 0x69, 0x65, 0x2d, 0x74, 0x63,
+ 0xe2, 0xe0, 0xb2, 0x63, 0x69, 0x74, 0x32, 0x32, 0xb5, 0xc9, 0x70, 0x67,
+ 0xe2, 0x03, 0x04, 0x85, 0xf2, 0xe0, 0xb0, 0xf9, 0x65, 0x39, 0xe5, 0xc8,
+ 0x2d, 0x63, 0x35, 0x61, 0xfa, 0xe0, 0xb6, 0x23, 0xed, 0x0d, 0x0a, 0x05,
+ 0x11, 0x0a, 0x21, 0x1a, 0x16, 0x0b, 0x10, 0x40, 0xf6, 0x8e, 0x78, 0x74,
+ 0x71, 0x31, 0xed, 0x44, 0x92, 0xe0, 0xb3, 0xc7, 0x75, 0x6f, 0xf3, 0xc7,
+ 0x42, 0x74, 0x74, 0x61, 0x2d, 0x76, 0x72, 0x6a, 0x6a, 0x61, 0x74, 0x2d,
+ 0x6b, 0x37, 0xe1, 0xe0, 0x7a, 0x92, 0x73, 0x79, 0x2d, 0x75, 0x6c, 0x61,
+ 0xb0, 0xe0, 0x7a, 0xaf, 0xef, 0x03, 0x02, 0x89, 0xf4, 0xa7, 0x73, 0x6a,
+ 0x65, 0x6e, 0x2d, 0xe5, 0xe0, 0x82, 0x32, 0xf2, 0x02, 0x88, 0x69, 0x2d,
+ 0x71, 0x73, 0xe1, 0xe0, 0x7f, 0x45, 0x65, 0x6b, 0x65, 0x2d, 0xea, 0xc7,
+ 0x98, 0xec, 0x03, 0x06, 0x86, 0x73, 0x65, 0x6c, 0xf6, 0xc2, 0xa1, 0x69,
+ 0x2d, 0xf4, 0xe0, 0x3b, 0x29, 0x61, 0x74, 0x76, 0x75, 0x6f, 0x70, 0x6d,
+ 0xe9, 0xc7, 0x16, 0xeb, 0x03, 0x07, 0x86, 0x72, 0x75, 0x34, 0xb5, 0xe0,
+ 0xb5, 0xe4, 0x31, 0x62, 0x75, 0xb4, 0xc7, 0x3a, 0x30, 0x61, 0xf8, 0xc4,
+ 0x27, 0x6a, 0x6e, 0x64, 0x61, 0x6c, 0x65, 0x6e, 0x2d, 0xb6, 0xc7, 0x10,
+ 0x69, 0xf8, 0x02, 0x86, 0x38, 0x39, 0xb1, 0xe0, 0xac, 0xe8, 0x30, 0x38,
+ 0xb2, 0xe0, 0xac, 0xe2, 0x67, 0xe2, 0x0d, 0x08, 0x15, 0x14, 0x06, 0x09,
+ 0x05, 0x10, 0x1c, 0x0b, 0x40, 0x5e, 0x87, 0x78, 0x34, 0x63, 0x64, 0xb0,
+ 0xe0, 0x31, 0x90, 0xf4, 0x03, 0x05, 0x86, 0x78, 0xb2, 0xe0, 0xad, 0x52,
+ 0x66, 0x38, 0xe6, 0xe0, 0xb5, 0x56, 0x33, 0x64, 0xe8, 0xe0, 0xb5, 0x53,
+ 0x71, 0x6c, 0x79, 0x37, 0xe3, 0x02, 0x85, 0x76, 0xe1, 0xe0, 0xab, 0xb6,
+ 0x30, 0x61, 0x36, 0x37, 0xe6, 0xe0, 0x71, 0xe7, 0x70, 0x6c, 0xb2, 0xe0,
+ 0x61, 0x52, 0x69, 0x34, 0x65, 0x63, 0x65, 0xf8, 0xe0, 0xb5, 0xdf, 0x67,
+ 0x75, 0xb8, 0xc7, 0x3c, 0x65, 0x72, 0x70, 0x34, 0x61, 0x35, 0x64, 0x34,
+ 0xe1, 0x04, 0xe0, 0xb6, 0x0e, 0xb8, 0xc5, 0xc0, 0xe3, 0x03, 0x08, 0x87,
+ 0x70, 0x71, 0x36, 0x67, 0x70, 0xe1, 0xc7, 0x87, 0x61, 0x37, 0x64, 0xfa,
+ 0xe0, 0xb5, 0x5a, 0x30, 0x61, 0x39, 0x61, 0x7a, 0xe3, 0xe0, 0xb7, 0x4a,
+ 0x62, 0x68, 0x31, 0xe1, 0x04, 0xe0, 0xb7, 0x40, 0xb7, 0xc4, 0x34, 0xe1,
+ 0x07, 0x07, 0x16, 0x0a, 0x06, 0x06, 0x88, 0x79, 0x68, 0x37, 0xe7, 0xe0,
+ 0xb5, 0x3b, 0x69, 0x39, 0xe1, 0x02, 0x88, 0x7a, 0x67, 0x71, 0x70, 0xb6,
+ 0xe0, 0xb4, 0xe4, 0x35, 0x65, 0x76, 0x61, 0x30, 0xb0, 0xe0, 0xac, 0xc2,
+ 0x68, 0x31, 0x61, 0x33, 0x68, 0x6a, 0xeb, 0xe0, 0xa7, 0x24, 0x62, 0x32,
+ 0xe2, 0xe0, 0xb4, 0xbf, 0x61, 0x6d, 0x37, 0xe1, 0xc4, 0x78, 0x37, 0x63,
+ 0x30, 0x62, 0x62, 0xee, 0xc6, 0xb4, 0x33, 0xe1, 0x02, 0x91, 0x34, 0xe6,
+ 0x02, 0x82, 0xf2, 0x83, 0x31, 0x36, 0xe1, 0x04, 0xe0, 0xb6, 0xe9, 0xae,
+ 0xe0, 0x6f, 0xe3, 0x33, 0x65, 0xea, 0xe0, 0xb5, 0x24, 0x39, 0x61, 0x77,
+ 0xe2, 0xe0, 0xab, 0xf2, 0x32, 0x64, 0xe4, 0xe0, 0xaa, 0xde, 0xe5, 0x02,
+ 0x88, 0x72, 0x6b, 0x65, 0x72, 0x2d, 0xeb, 0xc6, 0x4c, 0xec, 0xc6, 0x71,
+ 0x33, 0x63, 0x68, 0x30, 0x6a, 0xb3, 0xc8, 0x82, 0xec, 0x0d, 0x03, 0x0c,
+ 0x13, 0x05, 0x09, 0x06, 0x15, 0x19, 0x08, 0x08, 0x12, 0x84, 0xf5, 0xc4,
+ 0x40, 0xf4, 0x02, 0x84, 0x65, 0xee, 0xc5, 0x6f, 0x2d, 0x6c, 0xe9, 0xc5,
+ 0x9e, 0xf2, 0x02, 0x88, 0x65, 0x6e, 0x73, 0x6b, 0x6f, 0xe7, 0xc1, 0xde,
+ 0x64, 0x61, 0x6c, 0x2d, 0xf3, 0xe0, 0xa9, 0xdd, 0x6f, 0x61, 0xe2, 0xc5,
+ 0x7a, 0x69, 0x6e, 0x64, 0x73, 0x2d, 0xf0, 0xe0, 0xa9, 0xcf, 0x68, 0x70,
+ 0x70, 0xe9, 0xc2, 0x49, 0xe7, 0x02, 0x87, 0x72, 0x64, 0x2d, 0x70, 0xef,
+ 0xc5, 0x6d, 0x62, 0x62, 0x61, 0x74, 0x31, 0x61, 0x64, 0xb8, 0xe0, 0xb4,
+ 0x26, 0xe5, 0x02, 0x88, 0x73, 0x75, 0x6e, 0x64, 0x2d, 0xe8, 0xc5, 0xdd,
+ 0x61, 0x67, 0x61, 0x76, 0x69, 0x69, 0x6b, 0x61, 0x2d, 0x35, 0xb2, 0xe0,
+ 0x2a, 0x31, 0x64, 0x69, 0x6e, 0x67, 0x65, 0xee, 0xc1, 0xb9, 0x63, 0x76,
+ 0x72, 0x33, 0x32, 0xe4, 0xc4, 0x54, 0xe1, 0x02, 0x84, 0x6e, 0xe7, 0xc5,
+ 0x58, 0x68, 0x65, 0x61, 0x64, 0x6a, 0x75, 0x2d, 0xb7, 0xe0, 0x80, 0x35,
+ 0x31, 0xe1, 0xc6, 0xf9, 0x2d, 0xb1, 0xc2, 0x22, 0xeb, 0x0b, 0x1c, 0x08,
+ 0x3f, 0x16, 0x0e, 0x1e, 0x09, 0x0c, 0x07, 0x85, 0xf6, 0x03, 0x0a, 0x85,
+ 0x6e, 0x61, 0x6e, 0x67, 0x65, 0x6e, 0x2d, 0xeb, 0xc2, 0x75, 0x69, 0x74,
+ 0xf3, 0xc4, 0xe9, 0x66, 0x6a, 0x6f, 0x72, 0x64, 0x2d, 0xee, 0xc5, 0x22,
+ 0x73, 0x6e, 0x65, 0x73, 0x2d, 0xf5, 0xc5, 0x75, 0xf2, 0x04, 0x10, 0x09,
+ 0x8d, 0x6a, 0x6f, 0x68, 0x6b, 0x61, 0x2d, 0x68, 0x77, 0x61, 0x62, 0x34,
+ 0x39, 0xea, 0xe0, 0xb4, 0x49, 0x65, 0x68, 0x61, 0x6d, 0x6e, 0x2d, 0xe4,
+ 0xc4, 0xfc, 0x64, 0x73, 0x68, 0x65, 0x72, 0x61, 0x64, 0x2d, 0x6d, 0xb8,
+ 0xe0, 0xaf, 0xa0, 0xe1, 0x02, 0x89, 0x6e, 0x67, 0x68, 0x6b, 0x65, 0x2d,
+ 0xe2, 0xc2, 0x28, 0x67, 0x65, 0x72, 0x2d, 0xe7, 0xe0, 0x7f, 0xbe, 0xf0,
+ 0x02, 0x86, 0x75, 0x74, 0xb3, 0xe0, 0xb3, 0x92, 0xf2, 0x02, 0x86, 0x79,
+ 0x35, 0xb7, 0xe0, 0xb3, 0x56, 0x77, 0xb1, 0xc7, 0x83, 0x6f, 0x6c, 0x75,
+ 0x6f, 0x6b, 0x74, 0x61, 0x2d, 0x37, 0x79, 0x61, 0xb5, 0xc2, 0x0c, 0xec,
+ 0x02, 0x97, 0xf4, 0x04, 0x06, 0x05, 0x82, 0x79, 0x35, 0xf8, 0xe0, 0xb3,
+ 0xd6, 0x78, 0xb9, 0xe0, 0xb3, 0xad, 0xf0, 0x83, 0x37, 0x38, 0xb7, 0xc7,
+ 0x15, 0x62, 0xf5, 0xc2, 0x36, 0x66, 0x6a, 0x6f, 0x72, 0x64, 0x2d, 0xe9,
+ 0xc4, 0xeb, 0x63, 0x72, 0x78, 0x37, 0x37, 0x64, 0x31, 0x78, 0xb4, 0xe0,
+ 0xb3, 0xb6, 0x62, 0x72, 0x71, 0xb7, 0xe0, 0xb3, 0xa9, 0x61, 0x72, 0xed,
+ 0xc4, 0xd0, 0x37, 0x79, 0x6e, 0xb9, 0xc6, 0xd1, 0xea, 0x06, 0x08, 0x09,
+ 0x15, 0xc5, 0xdb, 0x76, 0x72, 0x31, 0x38, 0xb9, 0xe0, 0xb2, 0xea, 0x72,
+ 0x70, 0x65, 0x6c, 0x61, 0x6e, 0xe4, 0xc0, 0x7a, 0xec, 0x02, 0x89, 0x73,
+ 0x74, 0x65, 0x72, 0x2d, 0xe2, 0xe0, 0x7f, 0x31, 0x71, 0x34, 0x38, 0x30,
+ 0x6e, 0xb2, 0xe0, 0xa0, 0x6b, 0x31, 0xe1, 0x03, 0x04, 0x8e, 0xed, 0xe0,
+ 0xb2, 0x85, 0xe5, 0x02, 0x85, 0x6c, 0x38, 0xe2, 0xc6, 0x3e, 0xe6, 0x46,
+ 0x3b, 0xe0, 0xae, 0xce, 0x64, 0xf0, 0xc6, 0x34, 0xe9, 0x04, 0x10, 0x06,
+ 0x88, 0x6f, 0x30, 0x61, 0x37, 0xe9, 0x04, 0xe0, 0xb4, 0xf2, 0xae, 0x60,
+ 0x78, 0xdf, 0xe0, 0x37, 0x6a, 0x6e, 0x64, 0x65, 0xf2, 0xc3, 0xcd, 0x6d,
+ 0x72, 0x35, 0x31, 0xb3, 0xe0, 0xb3, 0xa6, 0x31, 0x62, 0x36, 0x62, 0x31,
+ 0x61, 0x36, 0x61, 0xb2, 0xe0, 0xb3, 0x58, 0xe8, 0x0f, 0x13, 0x08, 0x05,
+ 0x10, 0x0c, 0x0e, 0x0d, 0x0e, 0x17, 0x10, 0x08, 0x0a, 0x14, 0x8d, 0xf9,
+ 0x02, 0x8a, 0x6c, 0x61, 0x6e, 0x64, 0x65, 0x74, 0x2d, 0xb5, 0xc3, 0xec,
+ 0x61, 0x6e, 0x67, 0x65, 0xf2, 0xa4, 0x78, 0x74, 0x38, 0x31, 0xb4, 0xe0,
+ 0xb3, 0x2d, 0x70, 0x6d, 0xe9, 0xc0, 0x71, 0xef, 0x02, 0x89, 0x6c, 0x74,
+ 0x6c, 0x65, 0x6e, 0x2d, 0xe8, 0xc3, 0xbf, 0x62, 0xec, 0xc4, 0x3f, 0x6e,
+ 0x65, 0x66, 0x6f, 0x73, 0x73, 0x2d, 0x71, 0xb1, 0xe0, 0xae, 0x60, 0x6d,
+ 0x6d, 0x72, 0x66, 0x65, 0x61, 0x73, 0x74, 0x61, 0x2d, 0x73, 0xb4, 0xc3,
+ 0x76, 0x6b, 0x6b, 0x69, 0x6e, 0x65, 0x6e, 0x2d, 0x35, 0x77, 0xe1, 0xe0,
+ 0xb4, 0x13, 0x67, 0x65, 0x62, 0x6f, 0x73, 0x74, 0x61, 0x64, 0x2d, 0x67,
+ 0xb3, 0xe0, 0xae, 0x37, 0xe5, 0x02, 0x8d, 0x72, 0x79, 0x2d, 0x69, 0x72,
+ 0x61, 0xae, 0x60, 0x28, 0x21, 0xe0, 0x77, 0x24, 0x62, 0x64, 0x61, 0x38,
+ 0xe2, 0xc5, 0x4d, 0x63, 0x65, 0x73, 0x75, 0x6f, 0x6c, 0x6f, 0x2d, 0x37,
+ 0x79, 0x61, 0x33, 0xb5, 0xe0, 0x28, 0x1c, 0x62, 0x6d, 0x65, 0x72, 0x2d,
+ 0xf8, 0xc3, 0x23, 0x33, 0x63, 0x75, 0x7a, 0x6b, 0x31, 0x64, 0xe9, 0xc5,
+ 0xfa, 0x32, 0x62, 0xf2, 0x02, 0x88, 0x6a, 0x39, 0xe3, 0x40, 0xac, 0xe0,
+ 0xb3, 0x6f, 0x65, 0x67, 0x33, 0xe5, 0xe0, 0xa9, 0x25, 0x31, 0xe1, 0x02,
+ 0x85, 0x6c, 0x69, 0xfa, 0xc5, 0x3a, 0x68, 0xee, 0xc5, 0x36, 0x2d, 0x32,
+ 0xe6, 0xe0, 0xad, 0xd7, 0xe7, 0x0a, 0x23, 0x13, 0x07, 0x06, 0x05, 0x1a,
+ 0x10, 0x03, 0x89, 0x6e, 0x73, 0x74, 0x69, 0xe7, 0x02, 0x8d, 0x6c, 0x69,
+ 0x65, 0x66, 0x65, 0x72, 0x6e, 0x2d, 0x77, 0xef, 0xe0, 0x6b, 0x98, 0x62,
+ 0x65, 0x73, 0x74, 0x65, 0x6c, 0x6c, 0x65, 0x6e, 0x2d, 0x7a, 0xf6, 0xe0,
+ 0x6b, 0x89, 0x6d, 0xf1, 0x02, 0x89, 0x77, 0x35, 0x61, 0xae, 0x44, 0x81,
+ 0xe0, 0x73, 0x33, 0x30, 0x35, 0x30, 0xe9, 0xc1, 0xd5, 0x6c, 0x73, 0x2d,
+ 0x65, 0xec, 0xc2, 0xb3, 0x6b, 0x33, 0x61, 0xf4, 0xc0, 0xa5, 0x6a, 0x76,
+ 0xe9, 0xc1, 0x44, 0xe9, 0x02, 0x8b, 0x76, 0x75, 0x6f, 0x74, 0x6e, 0x61,
+ 0x2d, 0xb8, 0xe0, 0x7d, 0xa8, 0x6c, 0x64, 0x65, 0x73, 0x6b, 0x6c, 0x2d,
+ 0x67, 0xb0, 0xe0, 0xad, 0x6a, 0x67, 0x61, 0x76, 0x69, 0x69, 0x6b, 0x61,
+ 0x2d, 0x38, 0x79, 0x61, 0x34, 0xb7, 0xe0, 0x75, 0xfa, 0xe5, 0xc4, 0xfa,
+ 0x63, 0x6b, 0x72, 0x33, 0x66, 0xb0, 0xe0, 0xa8, 0x8d, 0x32, 0x78, 0x78,
+ 0x34, 0xb8, 0xe0, 0xa7, 0x8b, 0xe6, 0x0a, 0x18, 0x15, 0x07, 0x1a, 0x18,
+ 0x10, 0x22, 0x04, 0x88, 0xfa, 0x02, 0x8c, 0x79, 0x73, 0x38, 0x64, 0x36,
+ 0x39, 0x75, 0x76, 0xe7, 0xe0, 0xb1, 0x02, 0x63, 0x32, 0x63, 0x39, 0x65,
+ 0xb2, 0xe0, 0xa7, 0x68, 0xf2, 0x03, 0x07, 0x86, 0x79, 0x61, 0x2d, 0xe8,
+ 0xe0, 0xa6, 0x8e, 0x6e, 0x61, 0x2d, 0xf7, 0xc1, 0xcf, 0x64, 0xe5, 0xc1,
+ 0xfe, 0x70, 0x63, 0x72, 0x6a, 0xb9, 0xc5, 0x13, 0x6f, 0x72, 0xec, 0x02,
+ 0x8a, 0x63, 0x65, 0x73, 0x65, 0x6e, 0x61, 0x2d, 0xe3, 0xc1, 0x4e, 0x2d,
+ 0x63, 0x65, 0x73, 0x65, 0x6e, 0x61, 0x2d, 0xe6, 0xc1, 0x4e, 0xec, 0x03,
+ 0x07, 0x87, 0x77, 0x33, 0x35, 0xb1, 0xe0, 0xb1, 0x8e, 0x6f, 0x72, 0x2d,
+ 0xea, 0xe0, 0xa6, 0x51, 0x2d, 0x7a, 0xe9, 0xe0, 0xac, 0xd5, 0xea, 0x02,
+ 0x85, 0x71, 0x37, 0xb2, 0xc2, 0xac, 0x6f, 0x72, 0x64, 0x2d, 0xec, 0xe0,
+ 0xa6, 0x3b, 0xe9, 0x02, 0x9b, 0xf1, 0x04, 0x05, 0x05, 0x83, 0x7a, 0xb9,
+ 0xe0, 0xb0, 0x77, 0x73, 0xb8, 0xe0, 0xb0, 0x72, 0xb6, 0xc0, 0xd4, 0x32,
+ 0x32, 0x38, 0x63, 0x35, 0xe8, 0xe0, 0xb0, 0x66, 0x6e, 0xee, 0xc2, 0x4a,
+ 0x68, 0xe2, 0xd8, 0x18, 0x63, 0x74, 0x34, 0x32, 0xb9, 0xe0, 0xb0, 0x59,
+ 0x36, 0x71, 0x78, 0x35, 0xb3, 0xe0, 0xb0, 0xe7, 0xe5, 0x06, 0x0d, 0x07,
+ 0x07, 0x0e, 0x8a, 0x76, 0x65, 0x6e, 0x69, 0x2d, 0x30, 0x71, 0x61, 0x30,
+ 0xb1, 0xe0, 0x8e, 0x32, 0x6c, 0x71, 0x71, 0x31, 0xb6, 0xc4, 0x08, 0x68,
+ 0x71, 0x7a, 0x35, 0xb6, 0xc4, 0x86, 0x66, 0xf6, 0x02, 0x86, 0x79, 0x38,
+ 0xb8, 0xe0, 0xaf, 0xfb, 0x6e, 0xb9, 0xc3, 0x68, 0x63, 0x6b, 0x76, 0x64,
+ 0x74, 0x63, 0xb9, 0xe0, 0xb0, 0x31, 0x31, 0xe1, 0xc1, 0xc8, 0xe4, 0x07,
+ 0x04, 0x08, 0x05, 0x12, 0x0b, 0x8a, 0x79, 0xf2, 0xc2, 0x17, 0x72, 0x62,
+ 0x61, 0x6b, 0x2d, 0xf7, 0xc1, 0xe7, 0x6e, 0x6e, 0xe1, 0xc1, 0x28, 0xea,
+ 0x02, 0x84, 0x74, 0xf9, 0xc2, 0xe7, 0x72, 0x73, 0x37, 0x32, 0x64, 0x36,
+ 0x75, 0xf9, 0xe0, 0xb0, 0xa2, 0x61, 0x76, 0x76, 0x65, 0x6e, 0x6a, 0x72,
+ 0x67, 0xe1, 0xc1, 0x76, 0x35, 0x71, 0x76, 0x37, 0x7a, 0x38, 0x37, 0xb6,
+ 0xc2, 0xcd, 0x31, 0xe1, 0x03, 0x03, 0x84, 0xf4, 0xc2, 0x3c, 0xec, 0xe0,
+ 0xa7, 0x44, 0x63, 0xea, 0xc0, 0x73, 0xe3, 0x09, 0x1d, 0x13, 0x08, 0x06,
+ 0x1b, 0x12, 0x08, 0x87, 0x7a, 0xf2, 0x04, 0x07, 0x05, 0x85, 0x77, 0x32,
+ 0x38, 0xe2, 0xe0, 0x87, 0xa7, 0x75, 0xb2, 0xe0, 0xaf, 0xc1, 0x73, 0xb0,
+ 0xe0, 0xb0, 0x4a, 0x36, 0x39, 0xb4, 0xe0, 0xa7, 0xa9, 0x6c, 0x63, 0x68,
+ 0x63, 0x30, 0x65, 0x61, 0x30, 0x62, 0x32, 0x67, 0x32, 0x61, 0x39, 0x67,
+ 0xe3, 0xe0, 0xaf, 0xa3, 0x69, 0x71, 0x70, 0x6e, 0xae, 0xe0, 0x75, 0xd5,
+ 0x67, 0x34, 0xe2, 0xe0, 0x9e, 0xd0, 0x65, 0x73, 0x65, 0x6e, 0xe1, 0x02,
+ 0x8a, 0x66, 0x6f, 0x72, 0x6c, 0x2d, 0x69, 0xb8, 0xe0, 0xab, 0x41, 0x2d,
+ 0x66, 0x6f, 0x72, 0x6c, 0x2d, 0x6d, 0xe3, 0xca, 0x25, 0x63, 0xeb, 0x02,
+ 0x88, 0x77, 0x63, 0x78, 0x65, 0xf4, 0xe0, 0xaf, 0x6e, 0x32, 0x62, 0xb3,
+ 0xe0, 0xa7, 0x5b, 0x33, 0x73, 0x31, 0x34, 0xed, 0xe0, 0xb0, 0x00, 0x32,
+ 0x62, 0x72, 0xb7, 0xe0, 0xb1, 0xa4, 0x31, 0x61, 0x76, 0xe7, 0x04, 0xe0,
+ 0xb1, 0x9a, 0x2e, 0x78, 0x6e, 0x2d, 0xad, 0x41, 0xa6, 0xc1, 0x26, 0xe2,
+ 0x0f, 0x03, 0x0d, 0x1e, 0x19, 0x08, 0x09, 0x15, 0x16, 0x1c, 0x1c, 0x0c,
+ 0x0e, 0x12, 0x8a, 0xf5, 0xc0, 0xd5, 0x74, 0x73, 0x66, 0x6a, 0x6f, 0x72,
+ 0x64, 0x2d, 0x39, 0xfa, 0xe0, 0xab, 0x4c, 0xf2, 0x02, 0x88, 0x75, 0x6d,
+ 0x2d, 0x76, 0xef, 0xe0, 0xab, 0x41, 0x6e, 0x6e, 0xf9, 0x02, 0x89, 0x73,
+ 0x75, 0x6e, 0x64, 0x2d, 0x6d, 0xb8, 0xc0, 0x57, 0x2d, 0x77, 0xf5, 0xc0,
+ 0x52, 0xef, 0x02, 0x90, 0x7a, 0x65, 0x6e, 0x2d, 0x73, 0x64, 0x74, 0x69,
+ 0x72, 0x6f, 0x6c, 0x2d, 0x32, 0xef, 0xc9, 0xa2, 0x64, 0x2d, 0xb2, 0xe0,
+ 0xa6, 0x72, 0x6d, 0x6c, 0x6f, 0x2d, 0xe7, 0xe0, 0xa4, 0x83, 0x6c, 0x74,
+ 0x2d, 0x65, 0x6c, 0xe1, 0xe0, 0x25, 0x10, 0xea, 0x02, 0x89, 0x64, 0x64,
+ 0x61, 0x72, 0x2d, 0xf0, 0xe0, 0xaa, 0xf7, 0x61, 0x72, 0x6b, 0x79, 0x2d,
+ 0xe6, 0xe0, 0x7b, 0x21, 0xe9, 0x02, 0x89, 0x65, 0x76, 0x74, 0x2d, 0x30,
+ 0xf1, 0xe0, 0xaa, 0xe3, 0x64, 0x72, 0x2d, 0x35, 0x6e, 0x61, 0xe3, 0xe0,
+ 0xaf, 0x6c, 0x68, 0xe3, 0x02, 0x8e, 0x63, 0x61, 0x76, 0x75, 0x6f, 0x74,
+ 0x6e, 0x61, 0x2d, 0x6b, 0xb7, 0xe0, 0xaa, 0xc7, 0x61, 0x76, 0x75, 0x6f,
+ 0x74, 0x6e, 0x61, 0x2d, 0xf3, 0x99, 0xe5, 0x02, 0x8b, 0x72, 0x6c, 0x65,
+ 0x76, 0x67, 0x2d, 0x6a, 0xf8, 0xe0, 0xaa, 0xaf, 0x61, 0x72, 0x61, 0x6c,
+ 0x76, 0x68, 0x6b, 0x69, 0x2d, 0x79, 0xb4, 0xe0, 0xaa, 0xa1, 0x64, 0x64,
+ 0x64, 0x6a, 0x2d, 0x6d, 0x72, 0x61, 0xe2, 0xe0, 0xac, 0x9b, 0x63, 0x6b,
+ 0x31, 0x62, 0x39, 0x61, 0x35, 0x64, 0x72, 0x65, 0xb4, 0xe0, 0xa4, 0xcc,
+ 0x61, 0x6c, 0x73, 0x61, 0x6e, 0x2d, 0x73, 0x64, 0x74, 0x69, 0x72, 0x6f,
+ 0x6c, 0x2d, 0x6e, 0xf3, 0xc8, 0xfc, 0x34, 0x77, 0x36, 0x30, 0x35, 0x66,
+ 0xe5, 0xe0, 0xa0, 0xa6, 0x2d, 0x35, 0x67, 0xe1, 0xe0, 0x99, 0x06, 0xe1,
+ 0x05, 0x0a, 0x12, 0x03, 0x8d, 0x76, 0x65, 0x72, 0x79, 0x2d, 0x79, 0xf5,
+ 0xe0, 0xaa, 0x54, 0x75, 0x72, 0x73, 0x6b, 0x6f, 0x67, 0x2d, 0x68, 0x6c,
+ 0x61, 0x6e, 0x64, 0x2d, 0x6a, 0xee, 0xe0, 0x24, 0x4e, 0x73, 0xeb, 0x90,
+ 0x72, 0x6f, 0x70, 0x6f, 0x72, 0x74, 0x2d, 0x62, 0x79, 0xe1, 0xe0, 0xa1,
+ 0xc5, 0x6e, 0x64, 0x79, 0xad, 0xc9, 0xc5, 0xb9, 0x04, 0x08, 0x07, 0x87,
+ 0x6b, 0x72, 0x74, 0x30, 0xb0, 0xe0, 0xae, 0xa0, 0x65, 0x74, 0x35, 0xb2,
+ 0xe0, 0xaf, 0x40, 0x64, 0x62, 0x71, 0xb2, 0xe0, 0xae, 0x92, 0x30, 0xe1,
+ 0x0a, 0x03, 0x03, 0x38, 0x60, 0x72, 0xeb, 0xe0, 0x3b, 0x85, 0x7a, 0xe8,
0xb4, 0xed, 0xc0, 0x62, 0x31, 0x61, 0xe6, 0xc1, 0x53, 0xb8, 0x05, 0x07,
0x07, 0x07, 0x87, 0x79, 0x30, 0x61, 0x30, 0xb6, 0xc1, 0xa9, 0x70, 0x76,
- 0x72, 0xb4, 0xe0, 0xae, 0x27, 0x6c, 0x74, 0x72, 0x36, 0xb2, 0xc0, 0xf3,
+ 0x72, 0xb4, 0xe0, 0xa7, 0x39, 0x6c, 0x74, 0x72, 0x36, 0xb2, 0xc0, 0xf3,
0x64, 0x62, 0x71, 0x32, 0xe1, 0xc1, 0x05, 0x30, 0xe1, 0x06, 0x0e, 0x0c,
0x06, 0x06, 0x85, 0x75, 0x2e, 0x78, 0x6e, 0x2d, 0x2d, 0x39, 0x30, 0x61,
- 0x33, 0xe1, 0xe0, 0xaa, 0x7e, 0xf3, 0x02, 0x84, 0xf7, 0xe0, 0xb6, 0x5e,
- 0x65, 0xe8, 0xe0, 0x6b, 0x3b, 0x71, 0x65, 0x63, 0x64, 0xf2, 0x83, 0x6f,
- 0x32, 0xb1, 0xe0, 0xb4, 0xb5, 0x64, 0x78, 0xe8, 0xd8, 0x61, 0x61, 0x61,
+ 0x33, 0xe1, 0xe0, 0xa4, 0x07, 0xf3, 0x02, 0x84, 0xf7, 0xe0, 0xaf, 0xe2,
+ 0x65, 0xe8, 0xe0, 0x67, 0xd1, 0x71, 0x65, 0x63, 0x64, 0xf2, 0x83, 0x6f,
+ 0x32, 0xb1, 0xe0, 0xae, 0x2b, 0x64, 0x78, 0xe8, 0xd7, 0x89, 0x61, 0x61,
0x30, 0x63, 0x76, 0x61, 0xe3, 0xc0, 0xf5, 0x37, 0x74, 0x30, 0x61, 0x32,
0x36, 0xb4, 0xc0, 0x4f, 0xb6, 0x04, 0x0b, 0x08, 0x86, 0x71, 0x71, 0x39,
- 0x38, 0x36, 0x62, 0x33, 0xf8, 0xe0, 0xb3, 0xdf, 0x6f, 0x72, 0x78, 0x32,
- 0xf2, 0xe0, 0xb4, 0x7c, 0x66, 0x72, 0x7a, 0xb8, 0xc0, 0x64, 0x62, 0x74,
- 0x77, 0xb5, 0xe0, 0xb4, 0x49, 0xb5, 0x07, 0x07, 0x0d, 0x10, 0x07, 0x08,
- 0xa4, 0x74, 0x7a, 0x6d, 0xb5, 0xe0, 0xb6, 0x02, 0x73, 0x75, 0x33, 0x34,
- 0x6a, 0x39, 0x33, 0x36, 0x62, 0xe7, 0xe0, 0x32, 0x36, 0x72, 0xf4, 0x02,
- 0x85, 0x71, 0x33, 0xb4, 0xc0, 0x5d, 0x70, 0x34, 0x39, 0xe3, 0xe0, 0xb4,
- 0x43, 0x6a, 0x73, 0x30, 0x34, 0xb5, 0xc1, 0x02, 0x64, 0x62, 0x68, 0x6c,
+ 0x38, 0x36, 0x62, 0x33, 0xf8, 0xe0, 0xad, 0x5c, 0x6f, 0x72, 0x78, 0x32,
+ 0xf2, 0xe0, 0xad, 0xf7, 0x66, 0x72, 0x7a, 0xb8, 0xc0, 0x64, 0x62, 0x74,
+ 0x77, 0xb5, 0xe0, 0xad, 0xc6, 0xb5, 0x07, 0x07, 0x0d, 0x10, 0x07, 0x08,
+ 0xa4, 0x74, 0x7a, 0x6d, 0xb5, 0xe0, 0xaf, 0x86, 0x73, 0x75, 0x33, 0x34,
+ 0x6a, 0x39, 0x33, 0x36, 0x62, 0xe7, 0xe0, 0x30, 0x63, 0x72, 0xf4, 0x02,
+ 0x85, 0x71, 0x33, 0xb4, 0xc0, 0x5d, 0x70, 0x34, 0x39, 0xe3, 0xe0, 0xad,
+ 0xbe, 0x6a, 0x73, 0x30, 0x34, 0xb5, 0xc1, 0x02, 0x64, 0x62, 0x68, 0x6c,
0x38, 0xe4, 0xc0, 0x60, 0x35, 0xf1, 0x02, 0x9a, 0x78, 0x35, 0xe4, 0x04,
- 0xe0, 0xb5, 0xc9, 0xae, 0x07, 0x60, 0x77, 0x36, 0xe0, 0x3a, 0x09, 0x78,
+ 0xe0, 0xaf, 0x4d, 0xae, 0x07, 0x60, 0x73, 0x33, 0xe0, 0x37, 0x6a, 0x78,
0x6e, 0x2d, 0x2d, 0x6a, 0x36, 0x77, 0x31, 0xb9, 0xc0, 0x98, 0x77, 0x34,
- 0xb2, 0xe0, 0xb5, 0xb2, 0x34, 0x62, 0x37, 0x66, 0x74, 0x61, 0x30, 0xe3,
- 0xe0, 0xa9, 0xc0, 0xb4, 0x07, 0x07, 0x10, 0x06, 0x18, 0x14, 0x88, 0x70,
- 0x76, 0x78, 0xf3, 0xe0, 0xb3, 0xf6, 0x69, 0xf4, 0x02, 0x87, 0x37, 0x39,
- 0x37, 0xeb, 0xe0, 0xb3, 0xeb, 0x31, 0x36, 0xb8, 0xc0, 0xac, 0x67, 0x62,
- 0xf2, 0xe0, 0x51, 0x15, 0x64, 0xe2, 0x02, 0x8e, 0x67, 0x64, 0x74, 0x79,
+ 0xb2, 0xe0, 0xaf, 0x36, 0x34, 0x62, 0x37, 0x66, 0x74, 0x61, 0x30, 0xe3,
+ 0xe0, 0xa3, 0x49, 0xb4, 0x07, 0x07, 0x10, 0x06, 0x18, 0x14, 0x88, 0x70,
+ 0x76, 0x78, 0xf3, 0xe0, 0xad, 0x71, 0x69, 0xf4, 0x02, 0x87, 0x37, 0x39,
+ 0x37, 0xeb, 0xe0, 0xad, 0x66, 0x31, 0x36, 0xb8, 0xc0, 0xac, 0x67, 0x62,
+ 0xf2, 0xe0, 0x4e, 0x64, 0x64, 0xe2, 0x02, 0x8e, 0x67, 0x64, 0x74, 0x79,
0x36, 0x63, 0x2e, 0x78, 0x6e, 0x2d, 0x2d, 0x34, 0x64, 0x62, 0x72, 0x6b,
- 0xb0, 0xe0, 0xb0, 0x87, 0xb5, 0x02, 0x86, 0x71, 0x31, 0xb1, 0xe0, 0xa9,
- 0x7a, 0x62, 0xf2, 0x03, 0xc0, 0x5c, 0x35, 0x63, 0xf9, 0xe0, 0xb3, 0x0f,
- 0x32, 0x63, 0x32, 0x64, 0xb9, 0xe0, 0xb3, 0xb6, 0x31, 0x61, 0x2e, 0x78,
- 0x6e, 0x2d, 0x2d, 0x70, 0x31, 0x61, 0xe3, 0xe0, 0xa2, 0x42, 0xb3, 0x07,
- 0x07, 0x02, 0x09, 0x08, 0x08, 0x89, 0x70, 0x78, 0x75, 0xb8, 0xe0, 0xb2,
- 0xd3, 0xe8, 0xae, 0x65, 0x30, 0x62, 0x37, 0x30, 0xb7, 0xe0, 0xb3, 0xb9,
- 0x64, 0x73, 0x34, 0x34, 0xb3, 0xe0, 0xb5, 0x1e, 0x62, 0x73, 0x74, 0x30,
- 0xb0, 0xe0, 0xb2, 0xcc, 0x32, 0x76, 0x70, 0x33, 0x30, 0xe8, 0xe0, 0xb3,
- 0x6b, 0x30, 0x72, 0x72, 0xb7, 0xe0, 0xb2, 0xd7, 0xb2, 0x02, 0x88, 0x73,
- 0x63, 0x72, 0x6a, 0xb9, 0xe0, 0xa9, 0x14, 0x6d, 0x34, 0x61, 0x31, 0xb5,
- 0xe0, 0xb0, 0x55, 0xb1, 0x05, 0x08, 0x0f, 0x0f, 0xab, 0x71, 0x71, 0x77,
- 0x32, 0xb3, 0xe0, 0xb3, 0x4d, 0x6c, 0x71, 0xf3, 0x02, 0x86, 0x37, 0x31,
- 0xe4, 0xe0, 0xb3, 0x38, 0x30, 0xb3, 0xc0, 0x4c, 0xe3, 0x02, 0x85, 0x74,
- 0xf7, 0xe0, 0xb3, 0x2b, 0x6b, 0x32, 0x65, 0xb1, 0xe0, 0xaa, 0xd3, 0x32,
+ 0xb0, 0xe0, 0xa9, 0xe0, 0xb5, 0x02, 0x86, 0x71, 0x31, 0xb1, 0xe0, 0xa3,
+ 0x03, 0x62, 0xf2, 0x03, 0xc0, 0x5c, 0x35, 0x63, 0xf9, 0xe0, 0xac, 0x8c,
+ 0x32, 0x63, 0x32, 0x64, 0xb9, 0xe0, 0xad, 0x2c, 0x31, 0x61, 0x2e, 0x78,
+ 0x6e, 0x2d, 0x2d, 0x70, 0x31, 0x61, 0xe3, 0xe0, 0x9b, 0x93, 0xb3, 0x07,
+ 0x07, 0x02, 0x09, 0x08, 0x08, 0x89, 0x70, 0x78, 0x75, 0xb8, 0xe0, 0xac,
+ 0x50, 0xe8, 0xae, 0x65, 0x30, 0x62, 0x37, 0x30, 0xb7, 0xe0, 0xad, 0x2f,
+ 0x64, 0x73, 0x34, 0x34, 0xb3, 0xe0, 0xae, 0xa2, 0x62, 0x73, 0x74, 0x30,
+ 0xb0, 0xe0, 0xac, 0x49, 0x32, 0x76, 0x70, 0x33, 0x30, 0xe8, 0xe0, 0xac,
+ 0xe6, 0x30, 0x72, 0x72, 0xb7, 0xe0, 0xac, 0x54, 0xb2, 0x02, 0x88, 0x73,
+ 0x63, 0x72, 0x6a, 0xb9, 0xe0, 0xa2, 0x9d, 0x6d, 0x34, 0x61, 0x31, 0xb5,
+ 0xe0, 0xa9, 0xae, 0xb1, 0x05, 0x08, 0x0f, 0x0f, 0xab, 0x71, 0x71, 0x77,
+ 0x32, 0xb3, 0xe0, 0xac, 0xc3, 0x6c, 0x71, 0xf3, 0x02, 0x86, 0x37, 0x31,
+ 0xe4, 0xe0, 0xac, 0xb3, 0x30, 0xb3, 0xc0, 0x4c, 0xe3, 0x02, 0x85, 0x74,
+ 0xf7, 0xe0, 0xac, 0xa6, 0x6b, 0x32, 0x65, 0xb1, 0xe0, 0xa3, 0xf3, 0x32,
0xe3, 0x03, 0x0a, 0x89, 0x6f, 0x30, 0x63, 0x33, 0x62, 0x34, 0x65, 0x76,
0xe1, 0x90, 0x66, 0x69, 0x38, 0x69, 0x78, 0x62, 0x38, 0xec, 0x87, 0x31,
0x66, 0x65, 0x30, 0x62, 0x72, 0x2e, 0x78, 0x6e, 0x2d, 0x2d, 0x6f, 0x33,
- 0x63, 0x77, 0xb4, 0xe0, 0xb2, 0xff, 0x31, 0x62, 0x34, 0x63, 0xb3, 0xe0,
- 0xb2, 0x50, 0x30, 0x74, 0x72, 0x71, 0x37, 0x70, 0x37, 0x6e, 0xee, 0xe0,
- 0xb2, 0xe6, 0xea, 0xe0, 0xa1, 0x48, 0xe9, 0x04, 0xe0, 0xb3, 0x52, 0xe8,
- 0xe0, 0xac, 0x0d, 0x66, 0x69, 0xee, 0xe0, 0x99, 0x13, 0xe5, 0x02, 0x82,
- 0xf2, 0x8b, 0x6e, 0x2e, 0x70, 0x72, 0x67, 0xed, 0xe0, 0xaa, 0xfd, 0x62,
- 0xef, 0xe0, 0xac, 0xfe, 0x34, 0x34, 0x33, 0x2e, 0xf0, 0xe0, 0xa0, 0x10,
- 0xae, 0x60, 0x9b, 0x47, 0x48, 0x07, 0xd1, 0x07, 0xf7, 0x1a, 0x07, 0x0c,
- 0x06, 0x06, 0x12, 0x15, 0x20, 0x40, 0x71, 0x07, 0x0f, 0x0c, 0x40, 0x8b,
- 0x23, 0x41, 0x0c, 0x60, 0x85, 0x65, 0x51, 0xcc, 0x1b, 0xcf, 0x6c, 0x7a,
- 0x6d, 0x69, 0xf5, 0xe0, 0x74, 0x81, 0x77, 0x77, 0xae, 0x04, 0xe0, 0xb2,
- 0xa9, 0x63, 0xeb, 0xe0, 0x96, 0xaf, 0x75, 0x6f, 0xfa, 0xe0, 0x74, 0x70,
- 0xf4, 0x60, 0xa8, 0x33, 0xc1, 0x1e, 0xf3, 0x08, 0x05, 0x60, 0x44, 0x39,
- 0xe0, 0x6f, 0xcf, 0x6b, 0xf2, 0xe0, 0x74, 0x5c, 0xe1, 0xe0, 0x74, 0x58,
- 0xf2, 0x02, 0x87, 0x6f, 0xe3, 0x40, 0x9c, 0xe0, 0xa2, 0x0c, 0x69, 0x74,
- 0x65, 0x73, 0x74, 0x68, 0x69, 0xf3, 0xe0, 0x88, 0x7f, 0xf0, 0x06, 0x0c,
- 0x09, 0xe0, 0x5e, 0xfc, 0x6d, 0xf5, 0x04, 0xe0, 0x68, 0xaf, 0x64, 0x65,
- 0xf6, 0xe0, 0x7c, 0xdb, 0x68, 0x6f, 0x73, 0x74, 0x65, 0xe4, 0xe0, 0x88,
- 0x5d, 0xe4, 0xe0, 0x60, 0x9d, 0xef, 0x07, 0x3a, 0x07, 0x1f, 0xe0, 0xb0,
- 0xfe, 0xf2, 0x03, 0x05, 0x84, 0x73, 0xe5, 0xe0, 0xa1, 0xc3, 0xec, 0xe0,
- 0xb1, 0x78, 0xeb, 0x06, 0x0d, 0x13, 0xe0, 0xb3, 0x93, 0xf3, 0x06, 0x60,
- 0xb0, 0xcd, 0xc2, 0xdf, 0x68, 0x6f, 0xf0, 0xe0, 0xb0, 0xf0, 0xe9, 0x02,
- 0x87, 0x73, 0x62, 0x6f, 0xf2, 0xe0, 0xa6, 0x8d, 0x6e, 0x67, 0x67, 0x72,
- 0x6f, 0xf5, 0xe0, 0x98, 0x50, 0x65, 0x72, 0xf3, 0xe0, 0x8e, 0xcf, 0x6f,
- 0x64, 0x73, 0xe9, 0xe0, 0x72, 0xee, 0xec, 0x02, 0x97, 0xf4, 0x02, 0x8a,
- 0x6c, 0x61, 0x62, 0x2d, 0x64, 0x65, 0xed, 0xe0, 0x7b, 0xdf, 0x65, 0x72,
- 0x73, 0x6b, 0x6c, 0x75, 0xf7, 0xe0, 0xa0, 0x01, 0x6f, 0xed, 0xe0, 0xa2,
- 0x23, 0x64, 0x7a, 0x69, 0x73, 0x6c, 0xe1, 0xe0, 0xa6, 0x9e, 0x6e, 0x65,
- 0x78, 0xf4, 0xe0, 0xb1, 0xf2, 0xed, 0x07, 0x60, 0x80, 0x4f, 0xe0, 0x31,
- 0x92, 0x66, 0x6c, 0x61, 0xe2, 0xe0, 0x9e, 0x9e, 0x6c, 0x6f, 0x63, 0xec,
- 0x04, 0xe0, 0xae, 0xb0, 0x61, 0xf7, 0xca, 0x77, 0xe9, 0x0f, 0x03, 0x1a,
- 0x03, 0x18, 0x16, 0x0a, 0x05, 0x04, 0x60, 0x73, 0x1b, 0xe0, 0x3a, 0x2b,
- 0xf8, 0xda, 0xe1, 0xf4, 0x02, 0x93, 0xe8, 0x02, 0x89, 0x79, 0x6f, 0x75,
- 0x74, 0x75, 0xe2, 0xe0, 0xab, 0x99, 0x67, 0x6f, 0x6f, 0xe7, 0xe0, 0x35,
- 0x84, 0xe4, 0xe0, 0x73, 0x63, 0xef, 0xc6, 0x38, 0xee, 0x0b, 0x60, 0x2e,
- 0x28, 0x41, 0xc3, 0x60, 0x81, 0xa7, 0xc1, 0x6e, 0xe4, 0x02, 0x84, 0xef,
- 0xe0, 0x91, 0x00, 0x6d, 0xe9, 0xe0, 0x84, 0x1d, 0xec, 0x02, 0x8d, 0x6c,
- 0x69, 0x61, 0xed, 0x04, 0xe0, 0x96, 0x12, 0x68, 0xe9, 0xe0, 0xa2, 0x55,
- 0x64, 0x6c, 0xe9, 0xe0, 0x21, 0x86, 0x6b, 0xe9, 0x04, 0xe0, 0xb2, 0xd8,
- 0xae, 0xe0, 0x9f, 0x5f, 0x69, 0xe8, 0xe0, 0x73, 0x23, 0xe6, 0xe0, 0x73,
- 0x1f, 0xe5, 0x02, 0x92, 0xee, 0x04, 0xe0, 0xb2, 0xc3, 0x2e, 0x66, 0x75,
- 0x6e, 0x6b, 0x66, 0x65, 0x75, 0x65, 0xf2, 0xe0, 0x78, 0xcb, 0x6c, 0xf5,
- 0xe0, 0xa1, 0x6e, 0xe8, 0x04, 0x07, 0x08, 0x8a, 0x6f, 0x73, 0x77, 0xe8,
- 0xe0, 0xb1, 0x2b, 0x6d, 0xae, 0x60, 0x5d, 0x0d, 0xe0, 0x20, 0x47, 0x69,
- 0x74, 0x65, 0x73, 0x6e, 0x6f, 0xf7, 0xe0, 0xaa, 0x5d, 0x61, 0xec, 0xe0,
- 0x9b, 0xaa, 0xe5, 0x0a, 0x22, 0x11, 0x06, 0x05, 0x06, 0x14, 0x40, 0x93,
- 0x8b, 0x73, 0xf4, 0x06, 0x06, 0x0d, 0xe0, 0x86, 0x15, 0x66, 0x61, 0xec,
- 0xe0, 0x9c, 0xfe, 0xe5, 0x04, 0xe0, 0xa1, 0xc2, 0x75, 0x72, 0x6f, 0x70,
- 0xe5, 0xe0, 0x97, 0x89, 0x31, 0x2d, 0x75, 0xf3, 0xe0, 0x7b, 0xec, 0x6c,
- 0x6c, 0x62, 0x65, 0x69, 0x6e, 0x67, 0x7a, 0x6f, 0x6e, 0x65, 0xae, 0x60,
- 0xad, 0x60, 0xc1, 0xa2, 0xe9, 0x60, 0xaf, 0xa1, 0xc1, 0x64, 0x67, 0xf2,
- 0xe0, 0xa5, 0x84, 0x65, 0x6b, 0xec, 0xe0, 0xae, 0x57, 0xe4, 0x02, 0x8d,
- 0x65, 0x70, 0x6c, 0x6f, 0x79, 0xae, 0x60, 0x9c, 0x3d, 0x45, 0x16, 0xcf,
- 0xe9, 0xe4, 0xe0, 0x9c, 0xde, 0xe2, 0x0c, 0x0c, 0x08, 0x0e, 0x08, 0x08,
- 0x06, 0x20, 0x04, 0xe0, 0x9e, 0x54, 0x76, 0x69, 0x65, 0x77, 0x2d, 0x61,
- 0x73, 0x73, 0x65, 0xf4, 0xc3, 0x48, 0x74, 0x68, 0x69, 0x6e, 0xe7, 0xe0,
- 0x93, 0xfc, 0xf3, 0x02, 0x87, 0x70, 0x61, 0x63, 0xe5, 0xe0, 0x41, 0xd1,
- 0x69, 0xf4, 0xd4, 0xc0, 0x72, 0x65, 0x64, 0x69, 0xf2, 0xe0, 0xa8, 0xa2,
- 0x70, 0x61, 0x61, 0x73, 0xae, 0xe0, 0x69, 0xc3, 0x6c, 0x69, 0xeb, 0xe0,
- 0xa3, 0x71, 0xe8, 0x02, 0x98, 0xef, 0x02, 0x88, 0x73, 0x74, 0x69, 0x6e,
- 0xe7, 0xe0, 0x93, 0x85, 0x70, 0xae, 0x60, 0x9b, 0xdd, 0x46, 0x39, 0x4c,
- 0x99, 0x40, 0x56, 0xc2, 0xae, 0x61, 0xf2, 0xe0, 0x50, 0xcf, 0xe3, 0xe0,
- 0xaa, 0x5a, 0xae, 0x17, 0x06, 0x06, 0x60, 0x71, 0x22, 0x4e, 0x36, 0x60,
- 0x26, 0x6c, 0x41, 0x0c, 0x40, 0xbe, 0x45, 0xce, 0x41, 0x94, 0x40, 0xbb,
- 0xc0, 0x8c, 0xf4, 0x60, 0xaf, 0x70, 0xc0, 0xef, 0xee, 0x60, 0xa6, 0xd9,
- 0xc8, 0xb8, 0xe9, 0x60, 0x9d, 0x89, 0xd1, 0xcf, 0x61, 0x74, 0x68, 0x65,
- 0xf2, 0x60, 0x8e, 0x73, 0xe0, 0x23, 0x20, 0xae, 0x02, 0x84, 0xf4, 0xe0,
- 0xb1, 0x7a, 0xe2, 0xe0, 0xb1, 0x16, 0xe1, 0x10, 0x05, 0x2b, 0x1e, 0x16,
- 0x12, 0x20, 0x23, 0x0c, 0x09, 0x60, 0x44, 0x74, 0xe0, 0x5f, 0x6c, 0x7a,
- 0xf5, 0xe0, 0x5b, 0x0e, 0xf4, 0x03, 0x05, 0x98, 0x73, 0xef, 0xe0, 0x5d,
- 0xc1, 0x63, 0xe8, 0x07, 0x04, 0x60, 0xa5, 0x59, 0xcb, 0xfd, 0x61, 0x6e,
- 0xe4, 0x86, 0x2d, 0x61, 0x6e, 0x64, 0x2d, 0x63, 0x6c, 0xef, 0xe0, 0x93,
- 0x12, 0x61, 0xf2, 0x04, 0xe0, 0x60, 0x46, 0xe1, 0xe0, 0x56, 0x8f, 0xf3,
- 0x02, 0x86, 0x73, 0x61, 0xed, 0xe0, 0xac, 0xb1, 0xe8, 0x02, 0x88, 0x74,
- 0x65, 0x6e, 0x61, 0xf7, 0xe0, 0xa8, 0xeb, 0x69, 0x6e, 0x67, 0x74, 0x6f,
- 0x6e, 0xe4, 0xe0, 0x96, 0x50, 0xf2, 0x06, 0x05, 0x05, 0xe0, 0xae, 0x59,
- 0x73, 0xfa, 0xe0, 0x9e, 0xc6, 0x6d, 0xe9, 0xe0, 0xa2, 0xa6, 0x61, 0xe2,
- 0xe0, 0x5e, 0xd9, 0xee, 0x02, 0x85, 0x6f, 0xf5, 0xe0, 0xa8, 0x9e, 0xe7,
- 0x04, 0xe0, 0xb1, 0x00, 0x67, 0xef, 0xe0, 0xb0, 0x0b, 0xec, 0x07, 0x05,
- 0x06, 0x04, 0xe0, 0x9d, 0x75, 0x6d, 0xe1, 0xe0, 0x25, 0x56, 0x6c, 0x6f,
- 0xee, 0xe0, 0x41, 0xc9, 0xe5, 0xe0, 0x9a, 0x64, 0x62, 0x72, 0x7a, 0x79,
- 0x63, 0xe8, 0xe0, 0xac, 0x4e, 0xeb, 0x06, 0x03, 0x04, 0xe0, 0x68, 0xe3,
- 0xf5, 0xcb, 0xd8, 0xe5, 0xe0, 0xab, 0x34, 0xe1, 0x02, 0x8a, 0x79, 0x61,
- 0x6d, 0x61, 0xae, 0x60, 0xa6, 0x67, 0xc8, 0xbc, 0x73, 0x61, 0xae, 0x60,
- 0x84, 0x1d, 0xd0, 0x0a, 0x6a, 0xe9, 0x02, 0x84, 0xed, 0xe0, 0x59, 0x9d,
- 0xeb, 0xe0, 0x41, 0xa8, 0x66, 0x66, 0x6c, 0x65, 0x63, 0xe5, 0xe0, 0xaa,
- 0x0e, 0xae, 0x60, 0x27, 0x64, 0x60, 0x84, 0x65, 0x41, 0xba, 0x84, 0xf6,
- 0x1e, 0x26, 0x05, 0x04, 0x11, 0x07, 0x23, 0x40, 0x56, 0x06, 0x04, 0x25,
- 0x40, 0xb4, 0x06, 0x40, 0x44, 0x40, 0xce, 0x04, 0x06, 0x04, 0x40, 0xa6,
- 0x06, 0x60, 0x7d, 0xce, 0xca, 0xac, 0x1f, 0xc3, 0x05, 0x18, 0xe0, 0x35,
- 0x92, 0xe5, 0x02, 0x8c, 0x6c, 0x65, 0x72, 0xae, 0x03, 0xc3, 0x27, 0x1f,
- 0x43, 0xf8, 0xdf, 0x94, 0xe7, 0x60, 0x3d, 0x24, 0x41, 0xac, 0xe0, 0x59,
- 0xe2, 0x61, 0x72, 0x67, 0xe7, 0xe0, 0x9d, 0xf3, 0x78, 0xec, 0xe0, 0x9f,
- 0x6e, 0xf6, 0xe0, 0xae, 0x52, 0xf5, 0x05, 0x06, 0xe0, 0xb0, 0x3f, 0x6c,
- 0x74, 0xf2, 0xe0, 0x4d, 0x80, 0x65, 0xec, 0xe0, 0x8d, 0x82, 0x73, 0xae,
- 0x60, 0x97, 0x28, 0xd7, 0x15, 0xf0, 0x05, 0x0f, 0xe0, 0x66, 0xa4, 0xf3,
- 0x04, 0xe0, 0xa3, 0xbc, 0x2e, 0xed, 0x04, 0xe0, 0x67, 0xfd, 0xe3, 0xe0,
- 0x7e, 0xd0, 0xee, 0x02, 0x87, 0x70, 0x6c, 0x75, 0xf3, 0xe0, 0xae, 0xe1,
- 0xe4, 0xe0, 0x91, 0x22, 0xef, 0x07, 0x04, 0x07, 0x0b, 0x0a, 0x27, 0x84,
- 0xf9, 0xe0, 0x41, 0xde, 0xf4, 0x60, 0x9a, 0xb3, 0x53, 0xd3, 0x8f, 0x73,
- 0xf3, 0x04, 0xe0, 0xae, 0x70, 0x65, 0xf6, 0xe0, 0xa0, 0xf1, 0x6f, 0x72,
- 0x6c, 0x6f, 0x70, 0x65, 0xf2, 0xe0, 0x97, 0xca, 0xec, 0x07, 0x04, 0x04,
- 0x05, 0xe0, 0x89, 0x6b, 0xf9, 0xe0, 0x56, 0x08, 0xf6, 0xe0, 0xae, 0x5e,
- 0x6f, 0xe7, 0xe0, 0x58, 0x61, 0xeb, 0x02, 0x87, 0x73, 0x77, 0x61, 0xe7,
- 0xe0, 0x70, 0x34, 0x65, 0x6e, 0x6b, 0x75, 0xee, 0xe0, 0x46, 0x96, 0xe4,
- 0xe0, 0x82, 0xcf, 0xe1, 0xc2, 0x24, 0xee, 0x60, 0x94, 0x29, 0xdb, 0x90,
- 0xed, 0xe0, 0x87, 0x29, 0xec, 0x02, 0x84, 0xef, 0xe0, 0x90, 0x0f, 0xe1,
- 0x02, 0x93, 0x64, 0xe9, 0x02, 0x86, 0x6d, 0x69, 0xf2, 0xe0, 0xac, 0x14,
- 0x6b, 0x61, 0x76, 0x6b, 0x61, 0xfa, 0xe0, 0xac, 0x0b, 0x61, 0x6e, 0x64,
- 0x65, 0xf2, 0xe0, 0x74, 0xc7, 0xe9, 0x14, 0x04, 0x08, 0x07, 0x06, 0x20,
- 0x19, 0x1a, 0x08, 0x0c, 0x05, 0x07, 0x0e, 0x60, 0x8a, 0x52, 0x60, 0x24,
- 0x89, 0x81, 0xf8, 0xe0, 0xae, 0x29, 0xf6, 0x60, 0x41, 0xe4, 0x60, 0x6b,
- 0xf4, 0x9c, 0x74, 0x65, 0x72, 0xe2, 0xe0, 0xad, 0x69, 0xf3, 0x60, 0xa2,
- 0xb7, 0xcb, 0x12, 0xf2, 0x02, 0x95, 0x74, 0xf5, 0x04, 0xe0, 0x98, 0xd7,
- 0x61, 0xec, 0x07, 0x01, 0x60, 0x9e, 0xc5, 0xcd, 0xcc, 0x2d, 0x75, 0xf3,
- 0xe0, 0x8a, 0x31, 0x67, 0x69, 0xee, 0x60, 0xa2, 0x46, 0xcc, 0xfc, 0xf0,
- 0x05, 0x07, 0xe0, 0xaf, 0x30, 0x73, 0x69, 0x6e, 0xe1, 0xe0, 0xae, 0x4b,
- 0x2e, 0x6a, 0x65, 0x6c, 0x61, 0x73, 0x74, 0x69, 0xe3, 0xe0, 0x97, 0x06,
- 0xee, 0x05, 0x0f, 0xe0, 0xaf, 0x0f, 0xee, 0x02, 0x87, 0x79, 0x74, 0x73,
- 0xe9, 0xe0, 0x8a, 0xde, 0x69, 0xe3, 0xe0, 0x8a, 0xd9, 0x64, 0xe1, 0xe0,
- 0x9f, 0xe2, 0x6c, 0x6c, 0xe1, 0x60, 0x96, 0x81, 0xd6, 0x24, 0xeb, 0x06,
- 0x60, 0xa4, 0x79, 0xc8, 0xfb, 0x69, 0xee, 0xe0, 0x6c, 0xba, 0x64, 0xe5,
- 0xe0, 0x95, 0x6d, 0xe3, 0x60, 0x25, 0xac, 0xe0, 0x65, 0xaa, 0x62, 0xef,
- 0x02, 0x81, 0x2d, 0x76, 0x61, 0x6c, 0x65, 0x6e, 0xf4, 0xe0, 0xa8, 0x97,
- 0x61, 0xea, 0xe0, 0xa2, 0xdd, 0xe7, 0x60, 0xaa, 0xb3, 0xc4, 0x23, 0xe6,
- 0x04, 0xe0, 0xad, 0x45, 0x73, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x39,
- 0xae, 0x07, 0x07, 0x03, 0x0e, 0x5f, 0xa3, 0xa1, 0x75, 0x73, 0xad, 0x5f,
- 0xf8, 0xc0, 0x4e, 0x6d, 0xe5, 0xa3, 0x65, 0x75, 0xad, 0x06, 0x5f, 0xb2,
- 0x40, 0x5f, 0x8a, 0x6e, 0x6f, 0xf2, 0xdf, 0xb2, 0xe1, 0x02, 0x90, 0x70,
- 0xad, 0x05, 0x5f, 0xd0, 0xc0, 0x49, 0x6e, 0x6f, 0x72, 0x74, 0x68, 0x65,
- 0xe1, 0xdf, 0xfd, 0x66, 0xad, 0xdf, 0x98, 0xe5, 0x0e, 0x06, 0x12, 0x21,
- 0x40, 0x4b, 0x1d, 0x04, 0x15, 0x60, 0xab, 0xc8, 0xc1, 0xfc, 0x76, 0x65,
- 0xec, 0xe0, 0x79, 0xd3, 0xf4, 0x06, 0x60, 0xad, 0x25, 0xc1, 0x4c, 0x65,
- 0x72, 0x69, 0x6e, 0x61, 0x69, 0x72, 0xe5, 0xe0, 0x46, 0x27, 0x73, 0xf4,
- 0x08, 0x0f, 0x60, 0x4d, 0x21, 0xe0, 0x5d, 0x07, 0xf6, 0x02, 0x87, 0x1f,
- 0x43, 0x65, 0xe7, 0xe0, 0xa6, 0x28, 0x61, 0xe7, 0xe0, 0xa2, 0xab, 0x72,
- 0x65, 0xad, 0x60, 0x2c, 0x91, 0xc1, 0x2c, 0xf2, 0x0b, 0x15, 0x04, 0x12,
- 0x07, 0x09, 0x60, 0xa6, 0x2c, 0xc0, 0xf6, 0xf3, 0x08, 0x07, 0x60, 0x64,
- 0x39, 0xe0, 0x3b, 0x78, 0x69, 0x63, 0x68, 0x65, 0xf2, 0xdd, 0x83, 0x61,
- 0xe9, 0xe0, 0x97, 0x99, 0xf2, 0xe0, 0x3a, 0xe4, 0x6d, 0x1f, 0x43, 0x76,
- 0x67, 0x65, 0x6e, 0x73, 0x62, 0x65, 0x72, 0x61, 0xf4, 0x5d, 0x6b, 0xe0,
- 0x7d, 0x3a, 0x69, 0x73, 0x69, 0xe7, 0xe0, 0xac, 0xdf, 0x63, 0x65, 0xec,
- 0x60, 0x3a, 0x62, 0xe0, 0x4b, 0xbe, 0xe2, 0xe0, 0x49, 0x51, 0xee, 0x07,
- 0x04, 0x06, 0x04, 0xe0, 0xab, 0xe8, 0xf4, 0xe0, 0x29, 0x53, 0x6e, 0x65,
- 0xf3, 0xe0, 0x2c, 0xa5, 0xe9, 0xe0, 0x78, 0xf8, 0xe5, 0x60, 0x70, 0x09,
- 0xe0, 0x39, 0x89, 0x6c, 0xf6, 0xd9, 0xe0, 0xe7, 0x02, 0x84, 0x1f, 0x43,
- 0xe5, 0x88, 0xe1, 0x06, 0x60, 0xab, 0x69, 0xc0, 0xdb, 0x72, 0x73, 0x68,
- 0xe5, 0xe0, 0xa6, 0x4b, 0x66, 0xf3, 0xe0, 0xa7, 0xdf, 0xe4, 0xe0, 0xa7,
- 0x77, 0xe3, 0x60, 0xab, 0xbe, 0xc1, 0xfc, 0xe2, 0xe0, 0xab, 0xb8, 0xe1,
- 0x0f, 0x11, 0x08, 0x16, 0x3f, 0x04, 0x0b, 0x07, 0x04, 0x06, 0x60, 0xab,
- 0x16, 0xc1, 0xfd, 0xf2, 0x07, 0x05, 0x60, 0x98, 0x9b, 0xc9, 0x54, 0x67,
- 0xe7, 0xe0, 0x9b, 0x35, 0xe5, 0xe0, 0x40, 0x2b, 0x70, 0x6f, 0xf2, 0x60,
- 0x95, 0x6c, 0xce, 0xe3, 0xee, 0x07, 0x05, 0x4e, 0x3e, 0xe0, 0x9d, 0xa4,
- 0x74, 0xe1, 0xe0, 0xa7, 0x60, 0xe7, 0x04, 0xe0, 0xab, 0xef, 0xf5, 0xe0,
- 0x9d, 0xea, 0xec, 0x04, 0x23, 0x0c, 0x81, 0xec, 0x02, 0x84, 0x1f, 0x43,
- 0xe9, 0x8b, 0xe5, 0x09, 0x0f, 0x10, 0x04, 0x60, 0xa4, 0xc6, 0xc6, 0xec,
- 0xe5, 0x03, 0x02, 0x85, 0xe4, 0x86, 0xad, 0x02, 0x82, 0x64, 0x2d, 0x61,
- 0xef, 0xc5, 0xe4, 0xad, 0x0f, 0x84, 0x65, 0x72, 0xae, 0x02, 0x83, 0xef,
- 0xdc, 0x72, 0xe8, 0xe0, 0x2d, 0x12, 0x2d, 0xe4, 0x02, 0x81, 0x2d, 0x61,
- 0x6f, 0xf3, 0xe0, 0xa5, 0x38, 0xeb, 0xe0, 0x73, 0x0f, 0xe7, 0x04, 0xe0,
- 0x55, 0x7b, 0xe1, 0x60, 0xa7, 0x46, 0xc4, 0x5c, 0x64, 0xf3, 0x60, 0x98,
- 0x2d, 0xcd, 0x1f, 0x63, 0xe1, 0xd2, 0x54, 0x61, 0x70, 0xf3, 0xe0, 0xab,
- 0x8d, 0xae, 0x60, 0xa8, 0x39, 0x42, 0xde, 0xc0, 0x75, 0xae, 0x60, 0x9a,
- 0x0e, 0xd2, 0xfa, 0x2d, 0x69, 0x6e, 0x66, 0xef, 0xe0, 0x9d, 0x3f, 0xf5,
- 0x1e, 0x14, 0x05, 0x10, 0x04, 0x2f, 0x40, 0xf5, 0x40, 0x4e, 0x2c, 0x09,
- 0x40, 0x58, 0x1b, 0x1b, 0x31, 0x13, 0x0d, 0x0c, 0x05, 0x10, 0x14, 0x1c,
- 0x1b, 0x07, 0x10, 0xe0, 0x65, 0xe6, 0xfa, 0x07, 0x04, 0x60, 0x91, 0x42,
- 0xdb, 0x90, 0xf3, 0xe0, 0x6d, 0x26, 0x68, 0x67, 0x6f, 0x72, 0xef, 0xe0,
- 0x52, 0x45, 0xf9, 0x60, 0xac, 0xc1, 0x88, 0xf7, 0x05, 0x06, 0xe0, 0x6d,
- 0x0a, 0x75, 0x2e, 0xe1, 0xe0, 0xac, 0x64, 0xe1, 0xe0, 0x56, 0x26, 0xf6,
- 0xe0, 0x91, 0xdd, 0xf4, 0x08, 0x06, 0x0e, 0x60, 0xa2, 0x80, 0xc4, 0x8f,
- 0x77, 0x65, 0xee, 0xe0, 0x98, 0x12, 0xf3, 0x02, 0x87, 0x75, 0x6e, 0x6f,
- 0x6d, 0xe9, 0xd5, 0x0d, 0xe9, 0xe0, 0x9f, 0xcc, 0xe1, 0x05, 0x06, 0xe0,
- 0x76, 0x84, 0xfa, 0x4c, 0x58, 0xe0, 0x3f, 0xf8, 0x73, 0x68, 0xe9, 0xe0,
- 0x64, 0x9d, 0xf3, 0x11, 0x06, 0x04, 0x04, 0x09, 0x10, 0x40, 0x5e, 0x06,
- 0x0e, 0x0d, 0x16, 0x60, 0x96, 0x36, 0xd5, 0x7e, 0xf5, 0x60, 0x4d, 0xf4,
- 0xd2, 0xb4, 0xf4, 0xe0, 0x82, 0xdf, 0xf2, 0xe0, 0x77, 0x4a, 0x6c, 0x69,
- 0x76, 0x69, 0x6e, 0xe7, 0xe0, 0x89, 0xd2, 0xe8, 0x02, 0x85, 0x75, 0xe1,
- 0xe0, 0x9f, 0x58, 0xe9, 0x04, 0xe0, 0x89, 0xc4, 0xeb, 0xce, 0x4d, 0x65,
- 0xf2, 0x03, 0x1b, 0x93, 0x73, 0x2e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x2e,
- 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x63, 0x6c, 0x6f, 0x75, 0x64,
- 0x2e, 0x63, 0x6f, 0xed, 0xe0, 0xa9, 0xd2, 0x63, 0x6f, 0x6e, 0x74, 0x65,
- 0x6e, 0x74, 0xae, 0x04, 0xe0, 0xa3, 0xe5, 0x67, 0x6f, 0x6f, 0xe7, 0xe0,
- 0xac, 0x07, 0xae, 0x06, 0x0a, 0x0c, 0x04, 0xd1, 0x81, 0x70, 0x61, 0x72,
- 0x74, 0x79, 0x2e, 0xe5, 0xe0, 0x8c, 0xf2, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
- 0x63, 0x65, 0x72, 0xf4, 0xe0, 0x4b, 0x03, 0xe6, 0xe0, 0xab, 0xe5, 0x61,
- 0x73, 0x65, 0x69, 0x6e, 0x65, 0xf4, 0xe0, 0x70, 0xb7, 0x64, 0x65, 0xe3,
- 0xe0, 0x84, 0xe6, 0xe3, 0x04, 0xe0, 0xa7, 0x95, 0x6f, 0x75, 0x6e, 0x74,
- 0x72, 0xf9, 0xe0, 0x88, 0x21, 0xe1, 0x06, 0x60, 0x9a, 0x98, 0xc9, 0xf8,
- 0xae, 0x60, 0x9a, 0x3c, 0xce, 0xdb, 0xae, 0x60, 0x6c, 0x1b, 0x60, 0x27,
- 0x86, 0x44, 0xaa, 0x42, 0x6e, 0x24, 0x4a, 0xe1, 0x42, 0x38, 0x41, 0x02,
- 0x41, 0xa5, 0xc1, 0x25, 0xad, 0x09, 0x05, 0x08, 0x60, 0x7a, 0x98, 0x02,
- 0x02, 0x82, 0x77, 0xe5, 0xe0, 0xa2, 0xb5, 0x67, 0x6f, 0x76, 0x2d, 0x77,
- 0xe5, 0xdc, 0x1c, 0x65, 0x61, 0x73, 0x74, 0xad, 0x04, 0xe0, 0xa2, 0xb7,
- 0x31, 0xae, 0x5d, 0x2a, 0xe0, 0x85, 0x8f, 0xf2, 0x0b, 0x04, 0x05, 0x04,
- 0x04, 0x04, 0x07, 0x0d, 0xe0, 0x64, 0x50, 0xf5, 0xe0, 0x4d, 0x28, 0x6f,
- 0xf7, 0xe0, 0x4d, 0x50, 0xee, 0xe0, 0x7f, 0x4f, 0xec, 0xe0, 0x3a, 0xca,
- 0xe9, 0xe0, 0x7f, 0x47, 0x65, 0x73, 0x68, 0xe9, 0xe0, 0x4e, 0xe1, 0x62,
- 0x69, 0x6e, 0xef, 0x02, 0x81, 0x2d, 0x70, 0x65, 0xf3, 0xe0, 0x91, 0xbb,
- 0xe1, 0x09, 0x05, 0x04, 0x60, 0x38, 0x28, 0xe0, 0x67, 0xf0, 0x79, 0xe1,
- 0xe0, 0x71, 0x63, 0xf5, 0xe0, 0xa6, 0xbd, 0x73, 0x6f, 0xe5, 0xe0, 0xa6,
- 0xd0, 0xf0, 0x09, 0x06, 0x04, 0x05, 0x60, 0xa8, 0xc4, 0xc1, 0x35, 0xf0,
- 0x4e, 0xd1, 0xe0, 0x89, 0x9f, 0xef, 0xe0, 0x6b, 0x7e, 0x6c, 0xe9, 0xe0,
- 0xaa, 0x2e, 0x61, 0x61, 0x73, 0x2e, 0x6b, 0x61, 0x7a, 0x74, 0x65, 0x6c,
- 0x65, 0x70, 0x6f, 0x72, 0x74, 0xae, 0xe0, 0x57, 0xf5, 0xef, 0x60, 0x3f,
- 0xf4, 0x5f, 0xfc, 0xe0, 0x48, 0xda, 0xee, 0x0c, 0x06, 0x0b, 0x06, 0x22,
- 0x0b, 0x60, 0x84, 0x56, 0xe0, 0x24, 0xe6, 0x7a, 0x65, 0xee, 0xe0, 0x8f,
- 0x06, 0x75, 0x73, 0x75, 0x61, 0x6c, 0x70, 0x65, 0xf2, 0xe0, 0x7a, 0x65,
- 0x6e, 0x61, 0xee, 0xe0, 0xa5, 0x57, 0xe9, 0x06, 0x11, 0x06, 0xe0, 0xa7,
- 0xe7, 0xf6, 0x02, 0x88, 0x65, 0x72, 0x73, 0x69, 0xf4, 0xe0, 0xa8, 0x1a,
- 0xae, 0x60, 0xa0, 0x43, 0xc6, 0x97, 0xe3, 0x57, 0x02, 0xe0, 0x8d, 0x15,
- 0xb5, 0xe0, 0xaa, 0xa3, 0x64, 0x65, 0xf2, 0x04, 0xe0, 0xa2, 0x84, 0xf3,
- 0xe0, 0x26, 0x81, 0x61, 0x7a, 0x75, 0xeb, 0xe0, 0x71, 0x47, 0xed, 0x06,
- 0x09, 0x06, 0xe0, 0x6a, 0xed, 0xe9, 0x04, 0xe0, 0x93, 0x56, 0xe7, 0xe0,
- 0x6a, 0xf6, 0xe2, 0x60, 0xa4, 0x58, 0xc4, 0x4d, 0x61, 0xea, 0xe0, 0x6f,
- 0x5b, 0xec, 0x08, 0x04, 0x60, 0x6f, 0xdd, 0xe0, 0x30, 0xd5, 0xf3, 0xe0,
- 0x93, 0x63, 0x6c, 0x65, 0x6e, 0xf3, 0x04, 0xe0, 0x56, 0xb6, 0x76, 0x61,
- 0xee, 0xe0, 0xa3, 0xd0, 0xeb, 0x06, 0x09, 0x09, 0xe0, 0xaa, 0x63, 0xe9,
- 0x04, 0xe0, 0xa3, 0x5c, 0xe8, 0xe0, 0x68, 0x9f, 0x30, 0x2e, 0x62, 0x69,
- 0x67, 0xf6, 0xe0, 0xa9, 0x6b, 0xae, 0x0f, 0x46, 0x3e, 0x60, 0x8b, 0xed,
- 0x44, 0xaa, 0x4d, 0x73, 0x44, 0xdf, 0x41, 0x09, 0x9c, 0x70, 0x72, 0x69,
- 0x6d, 0xe5, 0xe0, 0x22, 0xfb, 0x6a, 0xe9, 0x05, 0x08, 0xe0, 0x9c, 0x7c,
- 0x74, 0x61, 0x77, 0x61, 0xf2, 0xe0, 0x71, 0x29, 0xe9, 0xe0, 0x58, 0x2f,
- 0x69, 0x2e, 0x6e, 0x61, 0x62, 0x75, 0x2e, 0x63, 0x61, 0xf3, 0xe0, 0x9a,
- 0x54, 0xe7, 0x07, 0x60, 0x6a, 0x74, 0xe0, 0x3f, 0xaf, 0xe9, 0xe0, 0x2d,
- 0xc7, 0x66, 0xe3, 0xe0, 0x89, 0x49, 0xe5, 0x04, 0xe0, 0x3d, 0xe6, 0x6e,
- 0xef, 0x04, 0xe0, 0xa1, 0xbe, 0x68, 0xe1, 0xe0, 0x32, 0x7b, 0xe4, 0x08,
- 0x04, 0x60, 0x5f, 0x62, 0xe0, 0x48, 0x9f, 0xef, 0xe0, 0x4d, 0x79, 0xe9,
- 0x60, 0x85, 0xba, 0xe0, 0x22, 0xf6, 0x63, 0x68, 0xe9, 0x03, 0x0d, 0x84,
- 0xee, 0x02, 0x85, 0x6f, 0xed, 0xe0, 0x52, 0xa3, 0x61, 0xe4, 0xe0, 0x52,
- 0xd0, 0xeb, 0xe0, 0x57, 0x90, 0x68, 0xe1, 0xe0, 0x51, 0xbd, 0xe2, 0x06,
- 0x60, 0x87, 0xaf, 0xdf, 0xc2, 0xe5, 0x04, 0xe0, 0xa7, 0xbf, 0xf2, 0x02,
- 0x88, 0x73, 0x70, 0x61, 0x63, 0xe5, 0xe0, 0x71, 0x91, 0xae, 0xe0, 0x39,
- 0x65, 0xe1, 0x60, 0x28, 0x3a, 0xe0, 0x81, 0x84, 0xb2, 0x02, 0x86, 0x2d,
- 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2e, 0x78, 0x6e, 0xe2, 0xe0, 0x83, 0x66,
- 0xae, 0x06, 0x60, 0x98, 0x98, 0xd1, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x6e,
- 0x65, 0xec, 0xe0, 0x8e, 0x44, 0xf4, 0x26, 0x07, 0x2c, 0x14, 0x2e, 0x40,
- 0x58, 0x07, 0x40, 0xb7, 0x41, 0x8f, 0x04, 0x42, 0x31, 0x11, 0x22, 0x0a,
- 0x0c, 0x21, 0x3f, 0x39, 0x09, 0x40, 0xe5, 0x06, 0x0f, 0x42, 0x3c, 0x60,
- 0x73, 0xe3, 0x51, 0xae, 0x4f, 0xa5, 0xc8, 0x5e, 0x1f, 0x43, 0x78, 0xee,
- 0xe0, 0x74, 0x9c, 0xf9, 0x07, 0x12, 0x0a, 0x03, 0xe0, 0xa2, 0x66, 0xf3,
- 0x06, 0x60, 0x9a, 0x2f, 0xcb, 0x06, 0xf6, 0x04, 0xe0, 0x9a, 0x7e, 0x1f,
- 0x43, 0xe6, 0xe0, 0x9d, 0xb5, 0x70, 0x65, 0x64, 0x72, 0x65, 0x61, 0xed,
- 0xe0, 0xa7, 0xe0, 0xee, 0xcf, 0xe1, 0x63, 0xe8, 0xe0, 0x97, 0x75, 0xf7,
- 0x06, 0x60, 0x95, 0xf9, 0xd3, 0x3d, 0x6d, 0x61, 0x69, 0x6c, 0xae, 0x60,
- 0x84, 0xb1, 0x60, 0x21, 0xaf, 0xc2, 0xae, 0xf6, 0x07, 0x05, 0x60, 0xa6,
- 0xba, 0xc2, 0x62, 0x65, 0xe4, 0xe0, 0x61, 0xfd, 0xae, 0x0b, 0x06, 0x08,
- 0x60, 0x5c, 0x37, 0x60, 0x39, 0x4d, 0xcf, 0xab, 0xf4, 0x60, 0xa6, 0xa3,
- 0xc1, 0x22, 0xe9, 0x60, 0xa6, 0xbe, 0x40, 0x94, 0xc0, 0x8c, 0xe2, 0x60,
- 0x9f, 0x0c, 0x48, 0x78, 0xb3, 0xf5, 0x0a, 0x0a, 0x04, 0x0b, 0x1a, 0x09,
- 0x60, 0xa6, 0x87, 0x9b, 0x78, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0xf9, 0xe0,
- 0xa6, 0x17, 0xf6, 0xe0, 0xa7, 0x01, 0xf3, 0x04, 0xe0, 0xa7, 0xe9, 0x63,
- 0x61, 0xee, 0xe0, 0xa0, 0x2e, 0xf2, 0x04, 0x07, 0x04, 0x84, 0x79, 0x73,
- 0x74, 0xf9, 0xe0, 0x7f, 0x44, 0xe9, 0xe0, 0x23, 0x0f, 0xe5, 0xe0, 0x96,
- 0x90, 0xae, 0x60, 0x96, 0xe6, 0xd0, 0x91, 0xee, 0x04, 0xe0, 0x9c, 0xbb,
- 0xeb, 0xe0, 0xa5, 0xe5, 0xec, 0x04, 0xe0, 0xa6, 0xcb, 0x65, 0x61, 0x70,
- 0x2d, 0x70, 0x61, 0x72, 0x74, 0xee, 0xe0, 0x7e, 0x2b, 0xf4, 0x60, 0x44,
- 0x33, 0xe0, 0x64, 0x6f, 0xf3, 0x06, 0x40, 0x98, 0x04, 0x04, 0x8a, 0xf5,
- 0x0e, 0x05, 0x06, 0x0b, 0x1e, 0x0b, 0x07, 0x20, 0x04, 0x0b, 0x06, 0xe0,
- 0x5c, 0x62, 0x79, 0xe1, 0xe0, 0x65, 0x37, 0x77, 0x61, 0xee, 0xe0, 0x63,
- 0xbb, 0x73, 0x68, 0x69, 0x6d, 0x61, 0xae, 0x60, 0x8c, 0x82, 0xd6, 0xcc,
- 0x72, 0xf5, 0x06, 0x04, 0x03, 0xe0, 0x7e, 0x31, 0xf4, 0xe0, 0x3c, 0x9b,
- 0xef, 0xd0, 0xaf, 0xe7, 0x04, 0xe0, 0x66, 0x75, 0xe1, 0x04, 0xe0, 0x7b,
- 0xb6, 0x73, 0xe8, 0xe0, 0x4f, 0x94, 0xee, 0x02, 0x84, 0xef, 0xe0, 0x4d,
- 0x63, 0xe1, 0xe0, 0x6a, 0x5e, 0x6d, 0x61, 0x67, 0xef, 0xe0, 0x57, 0x67,
- 0xeb, 0x02, 0x8e, 0xf5, 0x05, 0x04, 0xe0, 0x9b, 0xa9, 0xed, 0xe0, 0x62,
- 0xc5, 0xe2, 0xe0, 0x61, 0xda, 0xe9, 0x02, 0x86, 0x79, 0x6f, 0xee, 0xe0,
- 0x35, 0x85, 0x67, 0x61, 0xf4, 0xe0, 0xa6, 0x48, 0xe9, 0xe0, 0x5c, 0x57,
- 0x67, 0xe1, 0x04, 0xe0, 0x9c, 0x9c, 0x72, 0xf5, 0xe0, 0x6a, 0x6a, 0x63,
- 0x68, 0xe9, 0xe0, 0x4f, 0xed, 0xe2, 0x04, 0xe0, 0xa3, 0x79, 0xe1, 0x04,
- 0xe0, 0x4f, 0x31, 0xed, 0xe0, 0x3b, 0xe2, 0xf4, 0xe0, 0x89, 0x1c, 0xeb,
- 0xe0, 0x97, 0x25, 0x65, 0x6c, 0x69, 0x6e, 0x6f, 0x67, 0xf2, 0xe0, 0x9c,
- 0x80, 0xae, 0x60, 0xa5, 0xef, 0xc1, 0xd8, 0xf2, 0x11, 0x09, 0x1e, 0x0d,
- 0x26, 0x12, 0x40, 0x47, 0x40, 0xc2, 0x60, 0x91, 0xb4, 0x51, 0x04, 0xc3,
- 0xa6, 0x1f, 0xc3, 0x04, 0xe0, 0x6f, 0x90, 0xf8, 0xc0, 0x49, 0xf9, 0x03,
- 0x05, 0x8b, 0x73, 0xe9, 0xe0, 0xa0, 0xea, 0x63, 0x6c, 0x6f, 0x75, 0x64,
- 0x66, 0x6c, 0xe1, 0xe0, 0x8c, 0xe9, 0x2d, 0x73, 0x6e, 0x6f, 0x77, 0x70,
- 0xec, 0xe0, 0x4a, 0x57, 0x75, 0x73, 0xf4, 0x06, 0x60, 0xa4, 0xea, 0xc2,
- 0xb9, 0xe5, 0xe0, 0xa3, 0x5c, 0xef, 0x08, 0x05, 0x09, 0x05, 0x04, 0xe0,
- 0x91, 0x95, 0x6e, 0xe4, 0xe0, 0x9a, 0x92, 0x6d, 0xf3, 0x60, 0x92, 0x9a,
- 0x4d, 0x1f, 0xc2, 0x00, 0x69, 0xf4, 0xe0, 0xa1, 0x9a, 0xe7, 0xe0, 0x72,
- 0xda, 0x61, 0x6e, 0xe4, 0xe0, 0x68, 0x11, 0xe9, 0x02, 0x8a, 0x74, 0x6f,
- 0x6e, 0x2e, 0x7a, 0x6f, 0xee, 0xe0, 0x88, 0x93, 0x65, 0xf3, 0xe0, 0x22,
- 0xb6, 0xe5, 0x05, 0x05, 0xe0, 0xa3, 0x16, 0x76, 0xe9, 0xe0, 0x8e, 0x9e,
- 0x6e, 0xf4, 0x04, 0xe0, 0xa5, 0x59, 0x69, 0xee, 0x03, 0x1c, 0x81, 0xef,
- 0x06, 0x03, 0x07, 0xe0, 0xa5, 0x44, 0xad, 0x02, 0x87, 0xf3, 0x15, 0x04,
- 0x09, 0xe0, 0x98, 0x0e, 0xe1, 0x05, 0x60, 0xa0, 0x6d, 0x81, 0x6c, 0xf4,
- 0xe0, 0xa0, 0x68, 0x2d, 0xf3, 0x02, 0x84, 0x1f, 0x43, 0xfc, 0x85, 0xf5,
- 0x02, 0x81, 0x65, 0xe4, 0x04, 0xe0, 0x98, 0x0e, 0xad, 0xe0, 0x98, 0x0d,
- 0xe1, 0x09, 0x1c, 0x04, 0x40, 0x6c, 0x07, 0x0b, 0x0c, 0x8b, 0x76, 0x65,
- 0xec, 0x08, 0x09, 0x60, 0x83, 0xe2, 0xe0, 0x23, 0x20, 0x65, 0x72, 0xf3,
- 0x60, 0x44, 0xeb, 0xe0, 0x62, 0x1d, 0xae, 0x60, 0xa2, 0xa2, 0x42, 0xa7,
- 0xc0, 0x8c, 0xf0, 0xe0, 0x9f, 0x09, 0xee, 0x0c, 0x30, 0x60, 0x45, 0x8d,
- 0x60, 0x55, 0x87, 0x43, 0x78, 0xc2, 0x57, 0xf3, 0x03, 0x14, 0x8a, 0x75,
- 0x72, 0x6c, 0xae, 0x03, 0x05, 0x84, 0x6e, 0xec, 0xe0, 0xa6, 0xca, 0xe5,
- 0xe0, 0x5e, 0xba, 0xe2, 0xe0, 0x87, 0xf8, 0x70, 0x6f, 0x72, 0xf4, 0x60,
- 0x7f, 0x11, 0xe0, 0x25, 0x03, 0x6c, 0x61, 0x74, 0xe5, 0x02, 0x84, 0xe4,
- 0xe0, 0x86, 0x16, 0xae, 0xe0, 0x88, 0x69, 0xe9, 0x03, 0x0b, 0x89, 0x62,
- 0x61, 0x72, 0x6c, 0x65, 0x74, 0x74, 0xe1, 0xe0, 0xa0, 0x61, 0x61, 0x6e,
- 0x64, 0x72, 0x69, 0xe1, 0xe0, 0x9e, 0xa0, 0xad, 0x02, 0x8b, 0x62, 0x61,
- 0x72, 0x6c, 0x65, 0x74, 0x74, 0xe1, 0xe0, 0x96, 0xef, 0x61, 0x6e, 0x64,
- 0x72, 0x69, 0xe1, 0xe0, 0x9e, 0x88, 0x69, 0xee, 0x60, 0x8b, 0x21, 0xc6,
- 0x17, 0x66, 0x66, 0x69, 0x63, 0x70, 0x6c, 0x65, 0xf8, 0xe0, 0x8e, 0x5a,
- 0x65, 0x75, 0x6d, 0x74, 0x67, 0x65, 0x72, 0x61, 0xe4, 0xe0, 0x7c, 0xb8,
- 0xe4, 0x04, 0xe0, 0x8c, 0xba, 0xe5, 0x60, 0x8b, 0x00, 0xdb, 0x66, 0xae,
- 0xda, 0xdf, 0xae, 0x60, 0xa0, 0x52, 0x44, 0x10, 0xc0, 0x75, 0xf0, 0xe0,
- 0xa4, 0x59, 0xef, 0x19, 0x0b, 0x40, 0x5c, 0x16, 0x18, 0x0f, 0x24, 0x1f,
- 0x06, 0x0c, 0x2c, 0x2b, 0x04, 0x40, 0x50, 0x0e, 0x2a, 0x04, 0x07, 0x0f,
- 0x12, 0xe0, 0xa4, 0x30, 0xfa, 0x04, 0xe0, 0x40, 0x13, 0x73, 0x64, 0xe5,
- 0xe0, 0xa5, 0x3b, 0xf9, 0x06, 0x40, 0x43, 0xe0, 0xa3, 0x81, 0xef, 0x0d,
- 0x18, 0x04, 0x03, 0x08, 0x04, 0x06, 0x60, 0x61, 0x18, 0xe0, 0x3f, 0x1f,
- 0xf4, 0x03, 0x04, 0x85, 0xf3, 0xe0, 0x7f, 0xa0, 0x6f, 0xed, 0xe0, 0xa4,
- 0x61, 0xe1, 0x04, 0xe0, 0xa6, 0x06, 0xae, 0x60, 0xa0, 0xde, 0xc3, 0x19,
- 0x73, 0xe1, 0xd9, 0x3d, 0xef, 0xc5, 0x1b, 0xee, 0x60, 0x8a, 0x14, 0x4f,
- 0xc0, 0xca, 0x55, 0xeb, 0xe0, 0x5a, 0x17, 0x68, 0x61, 0xf3, 0xe0, 0x29,
- 0xd6, 0xe1, 0xe0, 0x99, 0xc1, 0xe1, 0x05, 0x08, 0xe0, 0xa4, 0x29, 0x6d,
- 0x61, 0xae, 0x60, 0x9a, 0xc2, 0xc9, 0x76, 0xeb, 0xe0, 0x9a, 0x43, 0xf7,
- 0x02, 0x8e, 0xee, 0x06, 0x60, 0xa3, 0x0e, 0xc2, 0xb9, 0x6e, 0x65, 0x77,
- 0xf3, 0xe0, 0x98, 0xac, 0x61, 0xe4, 0xe0, 0x39, 0xf2, 0xf5, 0x02, 0x91,
- 0xf2, 0x04, 0xe0, 0xa3, 0x51, 0x69, 0x73, 0x6d, 0xae, 0x60, 0x75, 0xee,
- 0x60, 0x2b, 0x62, 0xc0, 0x66, 0xe3, 0xe0, 0x6f, 0xa2, 0xf4, 0x04, 0xe0,
- 0x7d, 0xf0, 0x74, 0x6f, 0x72, 0x69, 0xae, 0x60, 0x89, 0x03, 0xda, 0xf4,
- 0xf3, 0x09, 0x07, 0x05, 0x60, 0x4d, 0xf2, 0xe0, 0x55, 0x90, 0x68, 0xe9,
- 0x60, 0x9f, 0x24, 0xc0, 0xaa, 0x63, 0xe1, 0xe0, 0x9d, 0xb0, 0xe1, 0x04,
- 0xe0, 0x9f, 0xc9, 0x73, 0x68, 0x69, 0x6d, 0x69, 0xfa, 0xe0, 0x32, 0x0e,
- 0xf2, 0x06, 0x03, 0x0a, 0xe0, 0x22, 0xeb, 0xf3, 0xd8, 0x06, 0xe9, 0x02,
- 0x84, 0x6e, 0xef, 0xd8, 0x3e, 0xe4, 0xce, 0x99, 0xe1, 0x04, 0xe0, 0xa3,
- 0x27, 0x68, 0x69, 0xed, 0xe0, 0x5f, 0xd0, 0xf0, 0x60, 0x9c, 0xd9, 0xc8,
- 0x77, 0xef, 0x04, 0xe0, 0xa0, 0xa1, 0xec, 0x60, 0x61, 0x41, 0xe0, 0x41,
- 0xa2, 0xee, 0x09, 0x0a, 0x06, 0x09, 0x4e, 0x57, 0xe0, 0x61, 0xf5, 0xef,
- 0x04, 0xe0, 0x6c, 0xb3, 0x73, 0xe8, 0xe0, 0x3e, 0xe3, 0x6b, 0x6f, 0x74,
- 0xf3, 0xdc, 0x87, 0x64, 0x61, 0x62, 0x61, 0x79, 0xe1, 0xe0, 0x5f, 0xfe,
- 0xe1, 0x04, 0xe0, 0x54, 0x2d, 0xed, 0xe0, 0x6b, 0xa8, 0xed, 0x05, 0x04,
- 0x16, 0xd0, 0x4c, 0x6f, 0xe2, 0xce, 0x46, 0xe9, 0x0d, 0x04, 0x60, 0x29,
- 0xf9, 0x5f, 0xd7, 0x60, 0x22, 0x55, 0xe0, 0x35, 0xbc, 0xf9, 0xe0, 0x6b,
- 0x3c, 0xeb, 0xe0, 0x75, 0xac, 0xe1, 0x04, 0xe0, 0xa3, 0x40, 0x6b, 0x6f,
- 0xed, 0xe0, 0x92, 0xa5, 0xec, 0xe0, 0x7e, 0x8b, 0xeb, 0x08, 0x04, 0x15,
- 0x0f, 0x07, 0xe0, 0x71, 0xdb, 0xf9, 0xe0, 0x45, 0x35, 0xf5, 0x02, 0x87,
- 0x79, 0x61, 0x6d, 0xe1, 0xe0, 0xa2, 0xc1, 0x73, 0x68, 0x69, 0x6d, 0x61,
- 0xae, 0x60, 0x9f, 0x74, 0xc3, 0xb1, 0xef, 0x02, 0x86, 0x72, 0x6f, 0xfa,
- 0xe0, 0x28, 0x0f, 0x6e, 0x61, 0xed, 0xe0, 0x98, 0x92, 0xe9, 0x60, 0x28,
- 0x04, 0xe0, 0x74, 0x47, 0xe1, 0x03, 0x06, 0x87, 0x73, 0x68, 0xe9, 0xe0,
- 0x53, 0xbb, 0x6d, 0x61, 0x63, 0xe8, 0xe0, 0x52, 0x26, 0x69, 0xae, 0x60,
- 0x9d, 0x25, 0xc2, 0x4d, 0xe8, 0x06, 0x60, 0x88, 0x92, 0xcf, 0x6d, 0x6e,
- 0x6f, 0x73, 0xe8, 0xe0, 0xa2, 0xb1, 0xe7, 0x07, 0x05, 0x08, 0x04, 0xe0,
- 0x9c, 0x2e, 0x75, 0xf2, 0xe0, 0x88, 0x73, 0x6c, 0x69, 0x61, 0x74, 0xf4,
- 0xe0, 0x30, 0x00, 0xe9, 0xe0, 0x46, 0x69, 0xe1, 0x05, 0x05, 0xe0, 0x6b,
- 0x30, 0x6e, 0xe5, 0xe0, 0xa2, 0x8e, 0x6b, 0x75, 0xf3, 0xe0, 0xa1, 0x47,
- 0xe5, 0xe0, 0x9f, 0x32, 0x64, 0xe1, 0x60, 0x99, 0x22, 0xc9, 0x04, 0x63,
- 0x68, 0xe9, 0x04, 0xe0, 0xa0, 0x2f, 0x67, 0x69, 0xae, 0x60, 0x98, 0xce,
- 0xc9, 0xd7, 0xe2, 0x05, 0x07, 0xe0, 0x4d, 0xd0, 0x69, 0x73, 0x68, 0xe9,
- 0xe0, 0x56, 0x81, 0xe5, 0x60, 0x9f, 0x90, 0x98, 0xae, 0x08, 0x60, 0x97,
- 0xdd, 0x46, 0x39, 0xc4, 0x16, 0xe7, 0x60, 0xa1, 0xe8, 0xc2, 0x1d, 0xee,
- 0x04, 0xe0, 0xa4, 0x1c, 0xae, 0x06, 0x60, 0x9f, 0x3c, 0xc2, 0xde, 0x6f,
- 0xf8, 0xe0, 0x52, 0xa2, 0xed, 0x08, 0x60, 0x73, 0x89, 0x5f, 0xeb, 0xd0,
- 0x93, 0xae, 0x12, 0x60, 0x92, 0xeb, 0x45, 0x27, 0x1d, 0x47, 0x66, 0x1d,
- 0x11, 0x40, 0x6f, 0x42, 0x3c, 0x08, 0xc0, 0x8a, 0xed, 0x60, 0x98, 0x0b,
- 0xcb, 0xe7, 0xec, 0x04, 0xe0, 0xa3, 0xe9, 0x6f, 0xee, 0xe0, 0x98, 0xf0,
- 0xeb, 0x05, 0x1b, 0xe0, 0xa3, 0xc3, 0x73, 0x61, 0xf4, 0xe0, 0xa1, 0x2c,
- 0xea, 0x0b, 0x04, 0x05, 0x06, 0x60, 0x90, 0x80, 0x4b, 0xd8, 0xc7, 0x65,
- 0x1f, 0x43, 0xf8, 0x82, 0x6f, 0xed, 0xe0, 0xa2, 0x3e, 0x6d, 0x61, 0xf8,
- 0xe0, 0x9c, 0x5b, 0x65, 0x6c, 0xe4, 0xe0, 0x8d, 0x67, 0xe9, 0x09, 0x07,
- 0x09, 0x0c, 0x06, 0x05, 0x0a, 0xdf, 0x27, 0xf2, 0x60, 0x69, 0xcd, 0xe0,
- 0x2d, 0xe2, 0xee, 0x04, 0xe0, 0x9d, 0xbe, 0xe7, 0xe0, 0x97, 0xf6, 0x6d,
- 0xe5, 0x03, 0xca, 0x23, 0x6b, 0x65, 0x65, 0xf0, 0xe0, 0x8c, 0xad, 0x66,
- 0x66, 0xe1, 0xe0, 0x81, 0x3c, 0x65, 0xee, 0xe0, 0x98, 0x23, 0x63, 0x6b,
- 0x65, 0x74, 0xf3, 0x60, 0xa2, 0x86, 0xc0, 0xfb, 0xe1, 0xe0, 0xa1, 0xe2,
- 0xe8, 0x08, 0x08, 0x11, 0x60, 0xa1, 0x11, 0xc2, 0x45, 0x72, 0x75, 0x68,
- 0x65, 0xf2, 0xe0, 0x95, 0x7c, 0xe9, 0x04, 0xe0, 0x7a, 0xb3, 0x6e, 0x67,
- 0x64, 0x75, 0x73, 0x74, 0x64, 0x61, 0xf4, 0xe0, 0x6b, 0xe6, 0xe5, 0x08,
- 0x07, 0x60, 0x4a, 0x8c, 0xe0, 0x57, 0x6e, 0x77, 0x6f, 0x72, 0xeb, 0xe0,
- 0x5b, 0xd2, 0x61, 0xf4, 0x60, 0x88, 0x65, 0xd8, 0x16, 0xe7, 0x04, 0xe0,
- 0xa3, 0x3a, 0xef, 0xe0, 0x3b, 0x96, 0xe5, 0x0f, 0x09, 0x19, 0x16, 0x18,
- 0x20, 0x2f, 0x27, 0x60, 0x7e, 0x66, 0x53, 0x23, 0xc4, 0x50, 0xf8, 0x04,
- 0xe0, 0x7d, 0x1f, 0xf4, 0xe0, 0x37, 0x38, 0xf3, 0x02, 0x8e, 0xf4, 0x02,
- 0x87, 0xae, 0x60, 0x2c, 0x3e, 0xe0, 0x76, 0x4f, 0xad, 0xe0, 0x3a, 0x6b,
- 0x68, 0x69, 0x6b, 0x61, 0xe7, 0xe0, 0xa1, 0x2c, 0xf2, 0x05, 0x0a, 0xe0,
- 0x91, 0x59, 0xee, 0x04, 0xe0, 0x9b, 0x0b, 0x6f, 0x70, 0xe9, 0xcf, 0x0c,
- 0x6d, 0x65, 0xfa, 0xe0, 0xa1, 0x0e, 0xee, 0x07, 0x04, 0x04, 0x04, 0xe0,
- 0x5f, 0x1f, 0xee, 0xe0, 0x63, 0x64, 0xeb, 0xe0, 0x29, 0x4b, 0xe5, 0xe0,
- 0x93, 0x82, 0xe4, 0xe0, 0x2f, 0x54, 0xed, 0x02, 0x99, 0xf0, 0x03, 0x06,
- 0x8b, 0x75, 0x72, 0xec, 0xe0, 0x6b, 0xc8, 0x69, 0xef, 0x02, 0x81, 0x2d,
- 0x6f, 0x6c, 0xe2, 0xe0, 0x9c, 0x79, 0xad, 0xe0, 0x78, 0x53, 0x61, 0xf3,
- 0xce, 0x9e, 0xec, 0x06, 0x60, 0x91, 0xdc, 0xd0, 0xd3, 0xe5, 0x05, 0x0b,
- 0x0f, 0xc7, 0x61, 0x6b, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0xeb, 0xe0,
- 0x97, 0xeb, 0x62, 0x69, 0x74, 0xae, 0x06, 0x60, 0xa1, 0x2d, 0xc0, 0x6d,
- 0x78, 0xf9, 0xe0, 0x84, 0x14, 0x2e, 0x61, 0x6d, 0x75, 0xee, 0xe0, 0x8d,
- 0x80, 0xe3, 0x03, 0x05, 0x96, 0x6e, 0xef, 0xe0, 0x75, 0xca, 0xe8, 0x05,
- 0x08, 0xe0, 0xa2, 0x70, 0x6e, 0x6f, 0x6c, 0x6f, 0xe7, 0xe0, 0x9f, 0xb6,
- 0x2e, 0x6f, 0x72, 0x61, 0xee, 0xe0, 0x81, 0xc4, 0xae, 0x60, 0x97, 0x99,
- 0x42, 0x8a, 0xc6, 0xf9, 0xe1, 0x04, 0xe0, 0xa0, 0x10, 0x63, 0x68, 0x65,
- 0x73, 0x2d, 0x79, 0xef, 0xe0, 0x6a, 0xd0, 0xe4, 0x60, 0x9f, 0xf1, 0xc2,
- 0x5f, 0xe3, 0x0a, 0x60, 0x98, 0x68, 0x47, 0xc6, 0x40, 0xc6, 0xc1, 0x4c,
- 0xf0, 0xe0, 0x58, 0xc5, 0xe1, 0x18, 0x0b, 0x0a, 0x38, 0x08, 0x25, 0x05,
- 0x1f, 0x29, 0x40, 0xc8, 0x07, 0x3d, 0x03, 0x0e, 0x13, 0x0f, 0x60, 0x94,
- 0x43, 0x45, 0x93, 0xc4, 0x4b, 0xf8, 0x04, 0xe0, 0xa2, 0x1e, 0xe9, 0x60,
- 0xa0, 0xd1, 0xc1, 0x4c, 0x77, 0x61, 0x72, 0x61, 0x6d, 0x6f, 0xf4, 0xe0,
- 0x5c, 0xc4, 0xf4, 0x04, 0x05, 0x0a, 0x9a, 0x74, 0xef, 0xe0, 0xa0, 0x8a,
- 0x73, 0x75, 0x6e, 0x6f, 0xae, 0x60, 0x9d, 0x52, 0xc1, 0x98, 0xe5, 0x03,
- 0x0a, 0x86, 0x79, 0x61, 0x6d, 0x61, 0xae, 0x60, 0x96, 0xd9, 0xc9, 0x42,
- 0x73, 0x68, 0xe9, 0xe0, 0x57, 0x5c, 0x62, 0x61, 0xf9, 0xe0, 0x3c, 0x4a,
- 0xe1, 0x04, 0xe0, 0xa0, 0x91, 0x6d, 0xef, 0xe0, 0x7e, 0xd6, 0xf3, 0x03,
- 0xd8, 0x8e, 0xe8, 0xe0, 0x85, 0x97, 0xf2, 0x04, 0x0c, 0x04, 0x87, 0xf5,
- 0x04, 0xe0, 0x99, 0x5c, 0x6d, 0x69, 0x7a, 0xf5, 0xe0, 0x9b, 0xc7, 0xee,
- 0xe0, 0x45, 0x71, 0xe7, 0x60, 0x2a, 0xc0, 0xe0, 0x64, 0x25, 0xe1, 0x60,
- 0x43, 0x59, 0x60, 0x54, 0x01, 0xc6, 0x05, 0x6f, 0xe2, 0xe0, 0x74, 0xc7,
- 0xee, 0x05, 0x04, 0xe0, 0x99, 0x43, 0x6f, 0xe8, 0xd5, 0x46, 0xe1, 0x07,
- 0x05, 0x60, 0x8b, 0x83, 0xd4, 0x83, 0x67, 0xf5, 0xe0, 0x46, 0x61, 0x62,
- 0x65, 0xae, 0x60, 0x93, 0xcb, 0xc3, 0x61, 0xed, 0x02, 0x84, 0xe2, 0xe0,
- 0x5e, 0xbd, 0xe1, 0x0a, 0x04, 0x09, 0x04, 0x60, 0x4b, 0x9a, 0xe0, 0x52,
- 0x7f, 0xf9, 0xe0, 0x63, 0x54, 0x74, 0x73, 0x75, 0x6b, 0x75, 0xf2, 0xe0,
- 0x85, 0x5c, 0xed, 0xe0, 0x4f, 0xd2, 0xeb, 0x50, 0xc9, 0xe0, 0x35, 0xe3,
- 0xeb, 0x0a, 0x03, 0x12, 0x0f, 0x60, 0x49, 0xa1, 0xe0, 0x55, 0xb4, 0xeb,
- 0xca, 0x2f, 0xe9, 0x07, 0x60, 0x55, 0x9d, 0xe0, 0x40, 0x7c, 0x6e, 0xef,
- 0x04, 0xe0, 0x9c, 0x92, 0xf5, 0xe0, 0x84, 0xbd, 0xe5, 0x02, 0x89, 0xf4,
- 0x04, 0xe0, 0x8a, 0x27, 0xef, 0xe0, 0x60, 0x6f, 0xe8, 0xc9, 0x0d, 0xe1,
- 0x0e, 0x06, 0x0e, 0x14, 0x12, 0x08, 0x05, 0x0d, 0x0f, 0x04, 0x1f, 0xe0,
- 0x9b, 0xea, 0x7a, 0x61, 0xeb, 0xe0, 0x48, 0x3e, 0x79, 0x61, 0x6d, 0x61,
- 0xae, 0x04, 0xe0, 0x9d, 0xfa, 0xe7, 0x60, 0x98, 0xa9, 0x96, 0xf4, 0x05,
- 0x0a, 0xe0, 0x5f, 0x2a, 0x73, 0x75, 0x6b, 0x69, 0xae, 0x60, 0x9b, 0xcf,
- 0xc3, 0x63, 0xef, 0xe0, 0x5d, 0x3e, 0xf3, 0x05, 0x05, 0xe0, 0x9c, 0x61,
- 0x68, 0xe9, 0xe0, 0x32, 0xeb, 0xe1, 0x60, 0x50, 0x0d, 0xe0, 0x45, 0xcd,
- 0x72, 0x61, 0x7a, 0x75, 0xeb, 0xe0, 0x5e, 0x1b, 0x6f, 0xeb, 0xe0, 0x4c,
- 0x88, 0xee, 0x02, 0x85, 0x65, 0xfa, 0xe0, 0x4a, 0x15, 0x61, 0xe2, 0xe0,
- 0x63, 0x47, 0xed, 0x02, 0x89, 0x6f, 0x72, 0x69, 0xae, 0x60, 0x99, 0xb0,
- 0xc3, 0xfe, 0xe1, 0xc0, 0x86, 0xe9, 0xe0, 0x5b, 0x99, 0x68, 0xe1, 0x07,
- 0x04, 0x05, 0x09, 0xe0, 0x67, 0x32, 0xf3, 0xe0, 0x95, 0x6e, 0x72, 0xf5,
- 0xe0, 0x92, 0xed, 0x6d, 0x61, 0xae, 0x60, 0x74, 0x02, 0xe0, 0x27, 0x79,
- 0xe7, 0xe0, 0x84, 0x8e, 0xe7, 0xe0, 0x9d, 0x80, 0x6a, 0xe9, 0x60, 0x34,
- 0x04, 0xce, 0x43, 0xe9, 0x0c, 0x0f, 0x04, 0x05, 0x05, 0x08, 0x05, 0x60,
- 0x5b, 0x1c, 0xcb, 0x7b, 0x73, 0x68, 0xe9, 0x02, 0x84, 0xee, 0xe0, 0x9b,
- 0x2f, 0xae, 0x60, 0x9b, 0xc9, 0xc2, 0xe0, 0xf2, 0xe0, 0x4c, 0x1e, 0x70,
- 0xe5, 0xe0, 0x9e, 0x59, 0x6e, 0xe1, 0xe0, 0x4d, 0xee, 0x6b, 0x69, 0xae,
- 0x60, 0x95, 0x4c, 0xc9, 0x69, 0x6a, 0xe9, 0xe0, 0x95, 0xfa, 0x66, 0x75,
- 0xee, 0xe0, 0x79, 0xc0, 0xe8, 0xc8, 0x5e, 0x67, 0xe1, 0x07, 0x60, 0x31,
- 0x10, 0xe0, 0x29, 0x4a, 0x6a, 0xef, 0xe0, 0x66, 0x85, 0xe4, 0x02, 0x8b,
- 0xef, 0x04, 0xe0, 0x54, 0x8e, 0x74, 0x73, 0xf5, 0xe0, 0x92, 0x6e, 0x61,
- 0xef, 0xe0, 0x84, 0x4c, 0x63, 0x68, 0xe9, 0x02, 0x84, 0xeb, 0xe0, 0x73,
- 0x0e, 0x61, 0x72, 0xe1, 0xe0, 0x54, 0x59, 0xe2, 0x06, 0x06, 0x09, 0xe0,
- 0xa0, 0x07, 0x75, 0x73, 0xe5, 0xe0, 0x9e, 0x04, 0x69, 0x74, 0x6f, 0x72,
- 0x64, 0x65, 0xf2, 0xd5, 0xa2, 0x61, 0x79, 0x61, 0xed, 0xe0, 0x67, 0x11,
- 0x33, 0x6c, 0x33, 0x70, 0x30, 0xf2, 0xe0, 0x93, 0x92, 0xf3, 0x2b, 0x28,
- 0x1e, 0x40, 0x54, 0x06, 0x35, 0x2d, 0x40, 0xf1, 0x41, 0xcc, 0x1d, 0x0f,
- 0x11, 0x40, 0x62, 0x40, 0xfe, 0x2b, 0x3a, 0x22, 0x40, 0x9f, 0x07, 0x40,
- 0x9c, 0x42, 0xc0, 0x09, 0x05, 0x42, 0x02, 0x16, 0x41, 0x51, 0x0a, 0x42,
- 0xe7, 0x05, 0xe0, 0x63, 0x5c, 0x1f, 0xc3, 0x05, 0x1b, 0xe0, 0x90, 0x8c,
- 0xf8, 0x04, 0x09, 0x05, 0x84, 0xf2, 0x44, 0xb1, 0x0a, 0x4a, 0x33, 0xe0,
- 0x79, 0x0f, 0x6e, 0x64, 0xf2, 0xc4, 0xd9, 0xed, 0xe0, 0x95, 0x2e, 0xe7,
- 0xe0, 0x89, 0x11, 0x61, 0xec, 0x60, 0x8d, 0x43, 0x82, 0xfa, 0x06, 0x04,
- 0x05, 0xe0, 0x9f, 0x93, 0xeb, 0xe0, 0x42, 0xea, 0x65, 0xf8, 0xe0, 0x9e,
- 0xa1, 0x63, 0xfa, 0x02, 0x85, 0x79, 0xf4, 0xe0, 0x62, 0x8b, 0x65, 0xe3,
- 0xe0, 0x8e, 0x41, 0xf9, 0x09, 0x0f, 0x2d, 0x08, 0x60, 0x91, 0x31, 0xce,
- 0x06, 0xf3, 0x02, 0x85, 0x74, 0xe5, 0xe0, 0x81, 0x81, 0x2e, 0x71, 0x63,
- 0xf8, 0xe0, 0x91, 0x76, 0xee, 0x02, 0xa2, 0xef, 0x02, 0x9a, 0x6c, 0x6f,
- 0x67, 0xf9, 0x04, 0xe0, 0x89, 0x64, 0x2d, 0xe4, 0x04, 0xe0, 0x78, 0xc8,
- 0x69, 0x73, 0x6b, 0x73, 0x74, 0x61, 0x74, 0x69, 0xef, 0xe0, 0x74, 0x4a,
- 0x2d, 0xe4, 0xe0, 0x78, 0xba, 0x63, 0x6c, 0x6f, 0x75, 0xe4, 0xe0, 0x9e,
- 0xf7, 0x6b, 0x6b, 0x79, 0x6c, 0xf6, 0xe0, 0x90, 0x39, 0x64, 0x6e, 0xe5,
- 0xe0, 0x9c, 0x77, 0xf8, 0x60, 0x8b, 0xf3, 0xd3, 0x3d, 0xf7, 0x03, 0x1e,
- 0x8e, 0xe9, 0x06, 0x08, 0x06, 0xe0, 0x97, 0xc6, 0x6e, 0x6f, 0x75, 0x6a,
- 0x73, 0xe3, 0xd9, 0x43, 0x65, 0x62, 0xef, 0xe0, 0x8d, 0xcc, 0x64, 0x6e,
- 0xe9, 0x60, 0x3d, 0xb3, 0xe0, 0x26, 0x58, 0xe5, 0x04, 0xe0, 0x89, 0x89,
- 0x65, 0x74, 0x70, 0x65, 0x70, 0xf0, 0xe0, 0x4f, 0xe0, 0x61, 0xf4, 0xe0,
- 0x89, 0x8e, 0xf6, 0x0c, 0x05, 0x06, 0x0b, 0x60, 0x5e, 0x8b, 0x60, 0x3e,
- 0x4c, 0xc1, 0xfc, 0x6e, 0xad, 0xe0, 0x62, 0xb8, 0x69, 0x7a, 0x7a, 0xe5,
- 0xcd, 0x94, 0xe5, 0x02, 0x84, 0xec, 0xe0, 0x64, 0x2d, 0xe9, 0xe0, 0x97,
- 0x00, 0x63, 0x2e, 0x66, 0x69, 0x72, 0x65, 0xee, 0xe0, 0x6a, 0xb3, 0xf5,
- 0x12, 0x11, 0x0b, 0x0e, 0x1e, 0x27, 0x13, 0x15, 0x0b, 0x0b, 0x0f, 0x0c,
- 0x06, 0x05, 0x04, 0xe0, 0x9d, 0xdf, 0xfa, 0x04, 0xe0, 0x53, 0xe7, 0xf5,
- 0x04, 0xe0, 0x96, 0xf1, 0xeb, 0x60, 0x48, 0x46, 0xe0, 0x54, 0x53, 0x77,
- 0xe1, 0x04, 0xe0, 0x9b, 0x89, 0x6c, 0xeb, 0xe0, 0x27, 0xa5, 0xf3, 0x02,
- 0x86, 0x6f, 0x6e, 0xef, 0xe0, 0x94, 0x96, 0x61, 0xeb, 0xe0, 0x63, 0x50,
- 0xf2, 0x06, 0x04, 0x05, 0xe0, 0x93, 0xb2, 0xf2, 0xe0, 0x8c, 0xda, 0x6e,
- 0xe1, 0xe0, 0x97, 0xa3, 0x67, 0xe5, 0x04, 0xe0, 0x77, 0x3c, 0x6f, 0x6e,
- 0x73, 0x68, 0xe1, 0xe0, 0x6f, 0x97, 0xf0, 0x03, 0x0b, 0x88, 0xf0, 0x03,
- 0xd2, 0xca, 0xec, 0x60, 0x44, 0xd5, 0xe0, 0x57, 0x60, 0x65, 0x72, 0x73,
- 0x61, 0xec, 0xe0, 0x8f, 0xe2, 0x61, 0x62, 0x61, 0x73, 0x65, 0xae, 0x06,
- 0x60, 0x84, 0xff, 0xd9, 0x29, 0xe9, 0xe0, 0x8a, 0x36, 0xee, 0x07, 0x60,
- 0x47, 0x67, 0xe0, 0x52, 0xe5, 0xee, 0x04, 0xe0, 0x97, 0x5e, 0x79, 0x64,
- 0xe1, 0xe0, 0x95, 0xfd, 0xed, 0x05, 0x09, 0xe0, 0x82, 0x94, 0x6f, 0x74,
- 0x6f, 0xae, 0x60, 0x97, 0x17, 0xc2, 0x66, 0xe9, 0x51, 0xcf, 0xe0, 0x26,
- 0xd9, 0xec, 0x06, 0x60, 0x97, 0x3c, 0xc1, 0x06, 0xe9, 0xe0, 0x9d, 0x22,
- 0xeb, 0x02, 0x85, 0x75, 0xed, 0xe0, 0x58, 0xe2, 0xe1, 0xcd, 0x72, 0xe9,
- 0x05, 0x04, 0xe0, 0x58, 0x38, 0xf3, 0xe0, 0x67, 0x57, 0x66, 0xf5, 0xe0,
- 0x96, 0x88, 0x67, 0xe9, 0x04, 0xe0, 0x47, 0x26, 0x6e, 0x61, 0xed, 0xe0,
- 0x9a, 0xa7, 0xe5, 0x60, 0x86, 0x9d, 0xc8, 0x39, 0x63, 0xeb, 0xe0, 0x9b,
- 0x84, 0xe2, 0xe0, 0x95, 0xa9, 0x2e, 0x70, 0x61, 0xe2, 0xe0, 0x9d, 0x73,
- 0xf4, 0x13, 0x28, 0x1f, 0x08, 0x40, 0x5c, 0x1c, 0x08, 0x0a, 0x16, 0x07,
- 0x60, 0x3a, 0xad, 0x60, 0x60, 0x9a, 0xc1, 0x87, 0xf5, 0x03, 0x06, 0x96,
- 0x74, 0x74, 0xe7, 0xe0, 0x92, 0x09, 0x66, 0xe6, 0x02, 0x88, 0x74, 0x6f,
- 0x72, 0x65, 0xe1, 0xe0, 0x98, 0x78, 0x2d, 0x34, 0x2d, 0x73, 0x61, 0x6c,
- 0xe5, 0xe0, 0x66, 0xc2, 0xe4, 0x59, 0x1c, 0x60, 0x7c, 0xec, 0xc5, 0x6b,
- 0xf2, 0x04, 0x04, 0x03, 0x8b, 0xf9, 0xe0, 0x97, 0xb3, 0xe9, 0xd9, 0xd6,
- 0x65, 0x61, 0xed, 0x04, 0xe0, 0x9d, 0x89, 0x6c, 0xe9, 0xdb, 0x31, 0x61,
- 0x6e, 0xe4, 0x60, 0x97, 0xac, 0xc4, 0x4f, 0x70, 0x65, 0x74, 0x65, 0xf2,
- 0xe0, 0x80, 0xa1, 0xef, 0x05, 0x40, 0x46, 0x04, 0x84, 0xf2, 0x08, 0x08,
- 0x18, 0x06, 0x11, 0xe0, 0x8e, 0x04, 0x6a, 0x2e, 0x66, 0x61, 0xf2, 0xe0,
- 0x9d, 0x5c, 0xe5, 0x05, 0x05, 0xe0, 0x9d, 0x53, 0x62, 0x61, 0xf3, 0xc4,
- 0xfc, 0xae, 0x60, 0x8a, 0x82, 0x45, 0xdf, 0x42, 0x23, 0x03, 0x49, 0x4d,
- 0xc1, 0x45, 0xe4, 0x60, 0x96, 0x6a, 0xc5, 0x54, 0x61, 0x67, 0xe5, 0x04,
- 0xe0, 0x9d, 0x39, 0x2e, 0x79, 0x61, 0x6e, 0x64, 0x65, 0xf8, 0xe0, 0x49,
- 0xc6, 0x2d, 0x65, 0xec, 0xe0, 0x96, 0x4f, 0x6c, 0xef, 0xdf, 0x8a, 0xeb,
- 0xe0, 0x6a, 0x53, 0x63, 0x6b, 0x68, 0x6f, 0xec, 0xe0, 0x95, 0x8d, 0xea,
- 0x02, 0x84, 0x1f, 0x43, 0xf8, 0x86, 0xef, 0x04, 0xe0, 0x6e, 0x68, 0x72,
- 0x64, 0x61, 0xec, 0x04, 0xe0, 0x9b, 0x7e, 0x73, 0x68, 0x61, 0x6c, 0xf3,
- 0xe0, 0x8d, 0xff, 0x68, 0x2e, 0x61, 0x63, 0xae, 0xe0, 0x6c, 0x1d, 0xe7,
- 0x05, 0x60, 0x3b, 0xf1, 0x85, 0xad, 0xe0, 0x74, 0xf4, 0xe5, 0x04, 0xe0,
- 0x81, 0x5f, 0xe9, 0x05, 0x06, 0xe0, 0x8d, 0xd8, 0x6e, 0x6b, 0xea, 0xe0,
- 0x91, 0x3f, 0x65, 0xf2, 0xe0, 0x75, 0x3c, 0xe3, 0x60, 0x3e, 0x20, 0xe0,
- 0x5e, 0xb4, 0xe1, 0x0b, 0x09, 0x40, 0x4a, 0x1f, 0x03, 0x03, 0x0f, 0x18,
- 0x06, 0x8d, 0xf6, 0x04, 0xe0, 0x86, 0xb2, 0xe5, 0xe0, 0x8b, 0x53, 0xf4,
- 0x06, 0x27, 0x06, 0xe0, 0x9a, 0xfe, 0xe9, 0x04, 0xe0, 0x91, 0xfa, 0xe3,
- 0x03, 0x04, 0x91, 0xf3, 0xe0, 0x8d, 0x3c, 0xae, 0x04, 0xe0, 0x74, 0x8c,
- 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x62, 0xec, 0xe0, 0x4e, 0x9d,
- 0x2d, 0x61, 0x63, 0x63, 0x65, 0xf3, 0xe0, 0x9c, 0x69, 0x68, 0x65, 0xec,
- 0xe0, 0x8d, 0x46, 0xe5, 0x07, 0x08, 0x60, 0x7a, 0x50, 0xdf, 0x6c, 0x6f,
- 0x66, 0x64, 0x65, 0xec, 0xe0, 0x75, 0x47, 0x66, 0x61, 0xf2, 0xe0, 0x9a,
- 0x27, 0xf2, 0x07, 0x08, 0x06, 0x06, 0xe0, 0x9c, 0x53, 0x6f, 0x73, 0x74,
- 0x77, 0xef, 0xe0, 0x5c, 0xb3, 0x6e, 0x62, 0xe5, 0xe0, 0x7f, 0x88, 0x67,
- 0x61, 0xf2, 0xe0, 0x97, 0xc5, 0xe1, 0xd4, 0x93, 0xf0, 0xc3, 0x53, 0xee,
- 0xce, 0x75, 0xec, 0x02, 0x87, 0x6f, 0x77, 0x61, 0xad, 0xe0, 0x3f, 0x91,
- 0x62, 0xe1, 0xe0, 0x37, 0x13, 0xe7, 0x02, 0x8a, 0x69, 0x6e, 0x67, 0x2e,
- 0x6f, 0x6e, 0x72, 0xe5, 0xdd, 0xeb, 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65,
- 0x61, 0xf2, 0xe0, 0x89, 0x6d, 0xe4, 0x60, 0x94, 0xdf, 0xc5, 0xaa, 0x63,
- 0x6b, 0x68, 0x65, 0x72, 0x6f, 0x2d, 0x6e, 0x65, 0xf4, 0xe0, 0x70, 0xaa,
- 0xe2, 0xe0, 0x8c, 0xd2, 0xf3, 0x06, 0x60, 0x9a, 0x09, 0xc1, 0xfc, 0x6c,
+ 0x63, 0x77, 0xb4, 0xe0, 0xab, 0x91, 0x31, 0x62, 0x34, 0x63, 0xb3, 0xe0,
+ 0xab, 0xcd, 0x30, 0x74, 0x72, 0x71, 0x37, 0x70, 0x37, 0x6e, 0xee, 0xe0,
+ 0xac, 0x61, 0xea, 0xe0, 0x9a, 0x9a, 0xe9, 0x07, 0x60, 0x88, 0xe6, 0xe0,
+ 0x23, 0xde, 0xe8, 0xe0, 0xa5, 0x1c, 0x66, 0x69, 0xee, 0xe0, 0x93, 0x09,
+ 0xe5, 0x02, 0x82, 0xf2, 0x8b, 0x6e, 0x2e, 0x70, 0x72, 0x67, 0xed, 0xe0,
+ 0xad, 0x03, 0x62, 0xef, 0xe0, 0xa6, 0x62, 0x34, 0x34, 0x33, 0x2e, 0xf0,
+ 0xe0, 0x99, 0x5f, 0x30, 0xae, 0x60, 0xac, 0x93, 0xc1, 0x3d, 0xae, 0x60,
+ 0x95, 0x0b, 0x47, 0x60, 0xd1, 0x64, 0xf7, 0x1b, 0x07, 0x0c, 0x04, 0x06,
+ 0x10, 0x15, 0x20, 0x40, 0x66, 0x07, 0x0f, 0x0c, 0x05, 0x40, 0x86, 0x1c,
+ 0x41, 0x1a, 0x60, 0x80, 0xfd, 0x50, 0x21, 0x1b, 0xce, 0xe1, 0x7a, 0x6d,
+ 0x69, 0xf5, 0xe0, 0x70, 0x7f, 0x77, 0x77, 0xae, 0x04, 0xe0, 0xac, 0x14,
+ 0x63, 0xeb, 0xe0, 0x91, 0x00, 0x75, 0xef, 0xc0, 0xd6, 0xf4, 0x60, 0xa1,
+ 0xb3, 0xc0, 0xfa, 0xf3, 0x0b, 0x60, 0x2a, 0x62, 0x4b, 0x1c, 0x4c, 0xcb,
+ 0xe0, 0x6b, 0x3c, 0xeb, 0xe0, 0x31, 0x8f, 0xf2, 0x02, 0x87, 0x6f, 0xe3,
+ 0x40, 0x91, 0xe0, 0x9b, 0x49, 0x69, 0x74, 0x65, 0x73, 0x74, 0x68, 0x69,
+ 0xf3, 0xe0, 0x84, 0x10, 0xf0, 0x06, 0x0c, 0x09, 0xe0, 0x5b, 0xd6, 0x6d,
+ 0xf5, 0x04, 0xe0, 0x65, 0x3d, 0x64, 0x65, 0xf6, 0xe0, 0x78, 0x76, 0x68,
+ 0x6f, 0x73, 0x74, 0x65, 0xe4, 0xe0, 0x83, 0xee, 0xe4, 0xe0, 0x5d, 0x5f,
+ 0xef, 0x07, 0x2f, 0x07, 0x1f, 0xe0, 0xaa, 0x7f, 0xf2, 0x03, 0x05, 0x84,
+ 0x73, 0xe5, 0xe0, 0x9b, 0x0c, 0xec, 0xe0, 0xaa, 0xee, 0xeb, 0x08, 0x13,
+ 0x60, 0x7c, 0xd3, 0xe0, 0x30, 0x48, 0xe9, 0x02, 0x87, 0x73, 0x62, 0x6f,
+ 0xf2, 0xe0, 0x9f, 0xad, 0x6e, 0x67, 0x67, 0x72, 0x6f, 0xf5, 0xe0, 0x92,
+ 0x4d, 0x65, 0x72, 0xf3, 0xe0, 0x9f, 0x7c, 0x6f, 0x64, 0x73, 0xe9, 0xe0,
+ 0x6f, 0x02, 0xec, 0x02, 0x97, 0xf4, 0x02, 0x8a, 0x6c, 0x61, 0x62, 0x2d,
+ 0x64, 0x65, 0xed, 0xe0, 0xa0, 0x15, 0x65, 0x72, 0x73, 0x6b, 0x6c, 0x75,
+ 0xf7, 0xe0, 0x99, 0x57, 0x6f, 0xed, 0xe0, 0x9b, 0x55, 0x64, 0x7a, 0x69,
+ 0x73, 0x6c, 0xe1, 0xe0, 0xa0, 0x3f, 0x6e, 0x65, 0x78, 0xf4, 0xe0, 0xab,
+ 0x6c, 0xed, 0x07, 0x60, 0x7b, 0x7f, 0xe0, 0x2f, 0xdc, 0x66, 0x6c, 0x61,
+ 0xe2, 0xe0, 0x97, 0xf4, 0x6c, 0x6f, 0x63, 0xec, 0x04, 0xe0, 0xa8, 0x0d,
+ 0x61, 0xf7, 0xc9, 0xcc, 0x6b, 0xfa, 0xe0, 0x6f, 0x98, 0xe9, 0x0f, 0x11,
+ 0x1a, 0x03, 0x11, 0x0a, 0x0a, 0x05, 0x04, 0x60, 0x6f, 0x28, 0xe0, 0x37,
+ 0x86, 0xf8, 0x04, 0xe0, 0x86, 0x84, 0xf3, 0x04, 0xe0, 0x32, 0x4a, 0x74,
+ 0x75, 0x64, 0xe9, 0xe0, 0x28, 0x7e, 0xf4, 0x02, 0x93, 0xe8, 0x02, 0x89,
+ 0x79, 0x6f, 0x75, 0x74, 0x75, 0xe2, 0xe0, 0xa4, 0xe7, 0x67, 0x6f, 0x6f,
+ 0xe7, 0xe0, 0x33, 0x4e, 0xe4, 0xe0, 0x6f, 0x5d, 0xef, 0xc5, 0xb7, 0xee,
+ 0x0b, 0x60, 0x2c, 0x64, 0x41, 0x93, 0x60, 0x7d, 0x02, 0xc1, 0x7c, 0x64,
+ 0xef, 0xe0, 0x8b, 0x9c, 0x6c, 0x6c, 0x69, 0x61, 0x6d, 0x68, 0xe9, 0xe0,
+ 0x9b, 0x8c, 0x6b, 0xe9, 0x04, 0xe0, 0xac, 0x60, 0xae, 0xe0, 0x98, 0xb5,
+ 0x69, 0xe8, 0xe0, 0x6f, 0x30, 0xe6, 0xe0, 0x6f, 0x2c, 0xe5, 0x02, 0x92,
+ 0xee, 0x04, 0xe0, 0xac, 0x4b, 0x2e, 0x66, 0x75, 0x6e, 0x6b, 0x66, 0x65,
+ 0x75, 0x65, 0xf2, 0xe0, 0x74, 0x93, 0x6c, 0xf5, 0xe0, 0x9a, 0xa0, 0xe8,
+ 0x03, 0x07, 0x87, 0x6f, 0x73, 0x77, 0xe8, 0xe0, 0xaa, 0xa6, 0x6d, 0xae,
+ 0x60, 0x5a, 0x0f, 0xde, 0xa2, 0x69, 0x74, 0x65, 0x73, 0x6e, 0x6f, 0xf7,
+ 0xe0, 0xab, 0x25, 0xe5, 0x0a, 0x17, 0x11, 0x06, 0x05, 0x06, 0x17, 0x40,
+ 0xa3, 0x91, 0x73, 0xf4, 0x05, 0x09, 0xe0, 0x81, 0xcf, 0x65, 0x75, 0x72,
+ 0x6f, 0x70, 0xe5, 0xe0, 0x91, 0x99, 0x31, 0x2d, 0x75, 0xf3, 0xe0, 0x77,
+ 0x80, 0x6c, 0x6c, 0x62, 0x65, 0x69, 0x6e, 0x67, 0x7a, 0x6f, 0x6e, 0x65,
+ 0xae, 0x60, 0xa6, 0xd6, 0xc1, 0xc8, 0xe9, 0x60, 0xa9, 0x32, 0xc1, 0x5e,
+ 0x67, 0xf2, 0xe0, 0x9f, 0x37, 0x65, 0x6b, 0xec, 0xe0, 0xa7, 0xc2, 0xe4,
+ 0x05, 0x0d, 0xe0, 0xab, 0xc6, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0xae, 0x60,
+ 0x95, 0xc9, 0x44, 0xc4, 0xd0, 0x39, 0xe4, 0xe0, 0x96, 0x43, 0xe2, 0x0c,
+ 0x15, 0x08, 0x15, 0x08, 0x08, 0x06, 0x20, 0x04, 0xe0, 0x97, 0xa9, 0x76,
+ 0x69, 0x65, 0x77, 0x2d, 0x61, 0x73, 0x73, 0x65, 0x74, 0x73, 0xae, 0x03,
+ 0xc3, 0x14, 0x61, 0x77, 0x73, 0xad, 0xc3, 0x10, 0x74, 0x68, 0x69, 0x6e,
+ 0xe7, 0xe0, 0x8e, 0x78, 0xf3, 0x03, 0x07, 0x86, 0x70, 0x61, 0x63, 0xe5,
+ 0xe0, 0x3f, 0xf1, 0x6f, 0x7a, 0xe1, 0xe0, 0x86, 0x72, 0x69, 0xf4, 0xd4,
+ 0x24, 0x72, 0x65, 0x64, 0x69, 0xf2, 0xe0, 0xa1, 0xbd, 0x70, 0x61, 0x61,
+ 0x73, 0xae, 0xe0, 0x66, 0x56, 0x6c, 0x69, 0xeb, 0xe0, 0x9c, 0x83, 0xe8,
+ 0x02, 0x98, 0xef, 0x02, 0x88, 0x73, 0x74, 0x69, 0x6e, 0xe7, 0xe0, 0x8e,
+ 0x08, 0x70, 0xae, 0x60, 0x95, 0x59, 0x45, 0xd3, 0x4d, 0x0c, 0x40, 0x56,
+ 0xc2, 0xac, 0x61, 0xf2, 0xe0, 0x4d, 0xec, 0xe3, 0xe0, 0xa3, 0xc4, 0xae,
+ 0x17, 0x06, 0x06, 0x60, 0x6d, 0x2e, 0x4d, 0x4a, 0x60, 0x24, 0xdb, 0x40,
+ 0xe5, 0x40, 0x79, 0x46, 0x02, 0x41, 0xbb, 0x40, 0xbd, 0xc0, 0x85, 0xf4,
+ 0x60, 0xa8, 0xf0, 0xc0, 0xe7, 0xee, 0x60, 0xa0, 0x41, 0xc8, 0xd0, 0xe9,
+ 0x60, 0x96, 0xde, 0xd1, 0xfa, 0x61, 0x74, 0x68, 0x65, 0xf2, 0x04, 0xe0,
+ 0xab, 0x16, 0x63, 0x68, 0x61, 0x6e, 0xee, 0xe0, 0xa5, 0xdf, 0xae, 0x02,
+ 0x84, 0xf4, 0xe0, 0xaa, 0xfb, 0xe2, 0xe0, 0xaa, 0x97, 0xe1, 0x10, 0x05,
+ 0x19, 0x12, 0x13, 0x12, 0x16, 0x23, 0x0c, 0x09, 0x60, 0x42, 0x7d, 0xe0,
+ 0x5b, 0x28, 0x7a, 0xf5, 0xe0, 0x58, 0x0a, 0xf4, 0x03, 0x04, 0x87, 0xf3,
+ 0xe0, 0x6b, 0x6e, 0x63, 0xe8, 0x60, 0x9e, 0xec, 0xcb, 0xf7, 0x61, 0xf2,
+ 0x04, 0xe0, 0x5d, 0x19, 0xe1, 0xe0, 0x53, 0x9d, 0xf3, 0x02, 0x86, 0x73,
+ 0x61, 0xed, 0xe0, 0xa6, 0x19, 0x68, 0x74, 0x65, 0x6e, 0x61, 0xf7, 0xe0,
+ 0xa2, 0x05, 0xf2, 0x03, 0x05, 0x85, 0x73, 0xfa, 0xe0, 0x98, 0x39, 0x6d,
+ 0xe9, 0xe0, 0x9b, 0xd3, 0x61, 0xe2, 0xe0, 0x5b, 0xbd, 0xee, 0x02, 0x85,
+ 0x6f, 0xf5, 0xe0, 0xa1, 0xce, 0xe7, 0x04, 0xe0, 0xaa, 0xa2, 0x67, 0xef,
+ 0xe0, 0xa9, 0xa0, 0xec, 0x07, 0x05, 0x60, 0x96, 0xef, 0xc7, 0xaa, 0x6d,
+ 0xe1, 0xe0, 0x24, 0x0f, 0x62, 0x72, 0x7a, 0x79, 0x63, 0xe8, 0xe0, 0xa5,
+ 0xcf, 0xeb, 0x06, 0x03, 0x04, 0xe0, 0x65, 0x97, 0xf5, 0xcb, 0x3b, 0xe5,
+ 0xe0, 0xa4, 0xbc, 0xe1, 0x02, 0x8a, 0x79, 0x61, 0x6d, 0x61, 0xae, 0x60,
+ 0x9f, 0xca, 0xc8, 0xfc, 0x73, 0x61, 0xae, 0x60, 0x7f, 0xee, 0xce, 0x96,
+ 0x6a, 0xe9, 0x02, 0x84, 0xed, 0xe0, 0x56, 0xc4, 0xeb, 0xe0, 0x3f, 0xc2,
+ 0x66, 0x66, 0x6c, 0x65, 0x63, 0xe5, 0xe0, 0xa3, 0x7a, 0xae, 0x60, 0x26,
+ 0x37, 0x60, 0x7f, 0x13, 0x41, 0xe7, 0x84, 0xf6, 0x1c, 0x26, 0x05, 0x04,
+ 0x0b, 0x07, 0x04, 0x21, 0x40, 0x43, 0x06, 0x04, 0x25, 0x40, 0xb1, 0x06,
+ 0x27, 0x40, 0xc8, 0x04, 0x06, 0x04, 0x40, 0x9e, 0x06, 0xe0, 0x84, 0x3a,
+ 0x1f, 0xc3, 0x05, 0x18, 0xe0, 0x33, 0x83, 0xe5, 0x02, 0x8c, 0x6c, 0x65,
+ 0x72, 0xae, 0x03, 0xc2, 0xe2, 0x1f, 0x43, 0xf8, 0xdd, 0xfe, 0xe7, 0x60,
+ 0x3b, 0x64, 0x41, 0xae, 0xe0, 0x55, 0x8f, 0x61, 0x72, 0x67, 0xe7, 0xe0,
+ 0x97, 0x72, 0x78, 0xec, 0xe0, 0x98, 0xbf, 0xf6, 0xe0, 0xa7, 0xf9, 0xf5,
+ 0x04, 0xe0, 0xa9, 0xf4, 0x6c, 0x74, 0xf2, 0xe0, 0x4a, 0xd2, 0x73, 0xae,
+ 0x60, 0x91, 0x26, 0xd6, 0xc4, 0xf2, 0xe0, 0xa7, 0xe3, 0xf0, 0x05, 0x0f,
+ 0xe0, 0x63, 0x69, 0xf3, 0x04, 0xe0, 0x9d, 0x80, 0x2e, 0xed, 0x04, 0xe0,
+ 0x64, 0xb9, 0xe3, 0xe0, 0x7a, 0x63, 0xee, 0x04, 0xe0, 0xa4, 0x1c, 0x70,
+ 0x6c, 0x75, 0xf3, 0xe0, 0xa8, 0x80, 0xef, 0x07, 0x04, 0x07, 0x0b, 0x0a,
+ 0x14, 0x84, 0xf9, 0xe0, 0x40, 0x09, 0xf4, 0x60, 0x94, 0x33, 0x53, 0xf7,
+ 0x8f, 0x73, 0xf3, 0x04, 0xe0, 0xa8, 0x14, 0x65, 0xf6, 0xe0, 0x9a, 0x28,
+ 0x6f, 0x72, 0x6c, 0x6f, 0x70, 0x65, 0xf2, 0xe0, 0x91, 0xbd, 0xec, 0x06,
+ 0x04, 0x04, 0xe0, 0x85, 0x0f, 0xf9, 0xe0, 0x53, 0x3c, 0xf6, 0xe0, 0xa8,
+ 0x03, 0x6f, 0xe7, 0xe0, 0x55, 0x8f, 0xe4, 0xe0, 0x7e, 0xb9, 0xe1, 0xc1,
+ 0xfe, 0xee, 0x60, 0x8e, 0x76, 0xdb, 0x08, 0xed, 0xe0, 0x83, 0x00, 0xec,
+ 0x02, 0x84, 0xef, 0xe0, 0x8a, 0xb7, 0xe1, 0x02, 0x93, 0x64, 0xe9, 0x02,
+ 0x86, 0x6d, 0x69, 0xf2, 0xe0, 0xa5, 0xc3, 0x6b, 0x61, 0x76, 0x6b, 0x61,
+ 0xfa, 0xe0, 0xa5, 0xba, 0x61, 0x6e, 0x64, 0x65, 0xf2, 0xe0, 0x70, 0xd0,
+ 0xe9, 0x14, 0x04, 0x08, 0x07, 0x06, 0x16, 0x19, 0x28, 0x05, 0x08, 0x05,
+ 0x07, 0x0e, 0x60, 0x85, 0xe7, 0x60, 0x22, 0xbc, 0x81, 0xf8, 0xe0, 0xa7,
+ 0xdf, 0xf6, 0x60, 0x40, 0x0a, 0x60, 0x67, 0x85, 0x9c, 0x74, 0x65, 0x72,
+ 0xe2, 0xe0, 0xa7, 0x27, 0xf3, 0x60, 0x9c, 0x95, 0xca, 0xeb, 0xf2, 0x02,
+ 0x8f, 0x74, 0x75, 0x61, 0xec, 0x05, 0x01, 0xe0, 0x98, 0x25, 0x2d, 0x75,
+ 0xf3, 0xe0, 0x85, 0xdc, 0xe7, 0xe0, 0xa7, 0xd4, 0xf0, 0x05, 0x07, 0xe0,
+ 0xa8, 0xff, 0x73, 0x69, 0x6e, 0xe1, 0xe0, 0xa8, 0x15, 0x2e, 0x6a, 0x65,
+ 0x6c, 0x61, 0x73, 0x74, 0x69, 0xe3, 0xe0, 0x91, 0x16, 0xee, 0x06, 0x0f,
+ 0x0d, 0xe0, 0xa8, 0xd0, 0xee, 0x02, 0x87, 0x79, 0x74, 0x73, 0xe9, 0xe0,
+ 0x86, 0x79, 0x69, 0xe3, 0xe0, 0x86, 0x74, 0xe8, 0x02, 0x86, 0x70, 0x68,
+ 0xf5, 0xe0, 0x96, 0x1b, 0xec, 0xe0, 0x96, 0x1f, 0x64, 0xe1, 0xe0, 0x99,
+ 0x28, 0x6c, 0xec, 0xe0, 0x93, 0xd4, 0xeb, 0x60, 0x93, 0x43, 0x4a, 0xb7,
+ 0xc9, 0x36, 0x64, 0xe5, 0xe0, 0x8f, 0x95, 0xe3, 0x60, 0x24, 0x9b, 0xe0,
+ 0x62, 0x2f, 0x62, 0xef, 0x02, 0x81, 0x2d, 0x76, 0x61, 0x6c, 0x65, 0x6e,
+ 0xf4, 0xe0, 0xa2, 0x17, 0x61, 0xea, 0xe0, 0x9c, 0xab, 0xe7, 0x60, 0xa4,
+ 0x4b, 0xc4, 0x53, 0xe6, 0x04, 0xe0, 0xa6, 0xff, 0x73, 0x2e, 0x63, 0x6c,
+ 0x6f, 0x75, 0x64, 0x39, 0xae, 0x0a, 0x09, 0x5e, 0xb2, 0x40, 0x91, 0x60,
+ 0x5b, 0xdd, 0x8d, 0x75, 0x73, 0xad, 0x60, 0x7b, 0x18, 0xe0, 0x25, 0x82,
+ 0xe1, 0x5e, 0xfc, 0xe0, 0x5c, 0x84, 0xe5, 0x0e, 0x06, 0x12, 0x21, 0x40,
+ 0x45, 0x1d, 0x04, 0x15, 0x60, 0xa5, 0xac, 0xc2, 0x03, 0x76, 0x65, 0xec,
+ 0xe0, 0x75, 0x87, 0xf4, 0x06, 0x60, 0xa6, 0xfb, 0xc1, 0x5b, 0x65, 0x72,
+ 0x69, 0x6e, 0x61, 0x69, 0x72, 0xe5, 0xe0, 0x44, 0x23, 0x73, 0xf4, 0x08,
+ 0x0f, 0x60, 0x4a, 0x9a, 0xe0, 0x59, 0x43, 0xf6, 0x02, 0x87, 0x1f, 0x43,
+ 0x65, 0xe7, 0xe0, 0x9f, 0x97, 0x61, 0xe7, 0xe0, 0x9c, 0x85, 0x72, 0x65,
+ 0xad, 0x60, 0x2a, 0xe5, 0xc1, 0x25, 0xf2, 0x0b, 0x0f, 0x04, 0x12, 0x07,
+ 0x09, 0x60, 0x9f, 0xa1, 0xc1, 0x2c, 0xf3, 0x07, 0x60, 0x61, 0x3b, 0xe0,
+ 0x37, 0xee, 0x69, 0x63, 0x68, 0x65, 0xf2, 0xdc, 0x25, 0xf2, 0xe0, 0x39,
+ 0x61, 0x6d, 0x1f, 0x43, 0x76, 0x67, 0x65, 0x6e, 0x73, 0x62, 0x65, 0x72,
+ 0x61, 0xf4, 0x5c, 0x12, 0xe0, 0x78, 0x4c, 0x69, 0x73, 0x69, 0xe7, 0xe0,
+ 0xa6, 0xbb, 0x63, 0x65, 0xec, 0x60, 0x38, 0xdf, 0xe0, 0x49, 0x36, 0xe2,
+ 0xe0, 0x47, 0x07, 0xee, 0x07, 0x04, 0x06, 0x04, 0xe0, 0xa5, 0xcc, 0xf4,
+ 0xe0, 0x28, 0x02, 0x6e, 0x65, 0xf3, 0xe0, 0x2a, 0xf9, 0xe9, 0xe0, 0x74,
+ 0xb6, 0xe5, 0x60, 0x6c, 0x6a, 0xe0, 0x36, 0xed, 0x6c, 0xf6, 0xd9, 0x2c,
+ 0xe7, 0x02, 0x84, 0x1f, 0x43, 0xe5, 0x88, 0xe1, 0x06, 0x60, 0xa5, 0x4d,
+ 0xc0, 0xd4, 0x72, 0x73, 0x68, 0xe5, 0xe0, 0xa0, 0x19, 0x66, 0xf3, 0xe0,
+ 0xa1, 0x78, 0xe4, 0xe0, 0xa1, 0x1a, 0xe3, 0x60, 0xa5, 0xa2, 0xc2, 0x03,
+ 0xe2, 0xe0, 0xa5, 0x9c, 0xe1, 0x0f, 0x11, 0x08, 0x10, 0x3d, 0x04, 0x0b,
+ 0x07, 0x04, 0x06, 0x60, 0xa5, 0x02, 0xc2, 0x04, 0xf2, 0x07, 0x05, 0x60,
+ 0x92, 0x54, 0xc9, 0x7b, 0x67, 0xe7, 0xe0, 0x94, 0xf1, 0xe5, 0xe0, 0x3e,
+ 0x70, 0x70, 0x6f, 0xf2, 0x60, 0x8f, 0x98, 0xce, 0x36, 0xee, 0x06, 0x4d,
+ 0xed, 0xe0, 0x97, 0xd8, 0xe7, 0x04, 0xe0, 0xa5, 0xd2, 0xf5, 0xe0, 0x97,
+ 0x78, 0xec, 0x04, 0x21, 0x0c, 0x81, 0xec, 0x02, 0x84, 0x1f, 0x43, 0xe9,
+ 0x89, 0xe5, 0x07, 0x0f, 0x10, 0x04, 0xe0, 0xa5, 0x97, 0xe5, 0x03, 0x02,
+ 0x85, 0xe4, 0x86, 0xad, 0x02, 0x82, 0x64, 0x2d, 0x61, 0xef, 0xc5, 0x97,
+ 0xad, 0x0f, 0x84, 0x65, 0x72, 0xae, 0x02, 0x83, 0xef, 0xdb, 0x21, 0xe8,
+ 0xe0, 0x2b, 0x73, 0x2d, 0xe4, 0x02, 0x81, 0x2d, 0x61, 0x6f, 0xf3, 0xe0,
+ 0x9e, 0xb5, 0xeb, 0xe0, 0x6f, 0x42, 0xe7, 0x04, 0xe0, 0x52, 0xf4, 0xe1,
+ 0x60, 0xa0, 0xe7, 0xc4, 0xa0, 0x64, 0xf3, 0x60, 0x91, 0xee, 0xcc, 0xdb,
+ 0x63, 0xe1, 0xd1, 0xd7, 0x61, 0x70, 0xf3, 0xe0, 0xa5, 0x72, 0xae, 0x60,
+ 0xa2, 0x01, 0x43, 0x02, 0xc0, 0x6e, 0xae, 0x60, 0x93, 0xce, 0xd3, 0x2d,
+ 0x2d, 0x69, 0x6e, 0x66, 0xef, 0xe0, 0x96, 0xc1, 0xf5, 0x1b, 0x18, 0x05,
+ 0x10, 0x2c, 0x40, 0xb6, 0x40, 0x4e, 0x2c, 0x09, 0x40, 0x51, 0x1b, 0x18,
+ 0x31, 0x13, 0x0d, 0x06, 0x0c, 0x05, 0x10, 0x14, 0x1c, 0x1b, 0x07, 0x90,
+ 0xfa, 0x07, 0x04, 0x60, 0x8b, 0xc0, 0xdb, 0x08, 0xf3, 0xe0, 0x69, 0xa1,
+ 0xe8, 0x02, 0x82, 0xe8, 0x82, 0x67, 0x6f, 0x72, 0xef, 0xe0, 0x4f, 0xb0,
+ 0xf9, 0x60, 0xa6, 0xb3, 0x88, 0xf7, 0x05, 0x06, 0xe0, 0x69, 0x81, 0x75,
+ 0x2e, 0xe1, 0xe0, 0xa6, 0x56, 0xe1, 0xe0, 0x53, 0x93, 0xf4, 0x08, 0x06,
+ 0x0e, 0x60, 0x9c, 0x12, 0xc4, 0xd3, 0x77, 0x65, 0xee, 0xe0, 0x91, 0xd6,
+ 0xf3, 0x02, 0x87, 0x75, 0x6e, 0x6f, 0x6d, 0xe9, 0xd4, 0x7a, 0xe9, 0xe0,
+ 0x99, 0xdb, 0xe1, 0x02, 0x86, 0xfa, 0x4c, 0x0f, 0xe0, 0x3d, 0xcd, 0x73,
+ 0x68, 0xe9, 0xe0, 0x61, 0x9e, 0xf3, 0x0d, 0x06, 0x04, 0x04, 0x05, 0x40,
+ 0x44, 0x1b, 0x60, 0x8f, 0x1e, 0xd6, 0xdd, 0xf5, 0x60, 0x4b, 0x6c, 0xd2,
+ 0x49, 0xf4, 0xe0, 0x7e, 0xf6, 0xf2, 0xe0, 0x73, 0x1c, 0x68, 0x69, 0xeb,
+ 0xce, 0x02, 0x65, 0xf2, 0x02, 0x93, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
+ 0x74, 0xae, 0x04, 0xe0, 0xa5, 0x50, 0x67, 0x6f, 0x6f, 0xe7, 0xe0, 0xa6,
+ 0x34, 0xae, 0x08, 0x0a, 0x0c, 0x04, 0x51, 0x39, 0xcc, 0x8c, 0x70, 0x61,
+ 0x72, 0x74, 0x79, 0x2e, 0xe5, 0xe0, 0x88, 0x1a, 0x6c, 0x6f, 0x63, 0x61,
+ 0x6c, 0x63, 0x65, 0x72, 0xf4, 0xe0, 0x6d, 0x9b, 0xe6, 0xe0, 0xa6, 0x10,
+ 0x61, 0x73, 0x65, 0x69, 0x6e, 0x65, 0xf4, 0xe0, 0x6d, 0x32, 0xae, 0x14,
+ 0x60, 0x68, 0xd8, 0x60, 0x25, 0x42, 0x44, 0x37, 0x42, 0x43, 0x24, 0x4a,
+ 0xeb, 0x43, 0x8f, 0x41, 0x94, 0xc1, 0x34, 0xee, 0x60, 0x9c, 0x8f, 0xc7,
+ 0xca, 0xad, 0x09, 0x0a, 0x0d, 0x60, 0x76, 0xcc, 0x02, 0x02, 0x82, 0x77,
+ 0x65, 0x73, 0x74, 0xad, 0x60, 0x9c, 0xa6, 0xc5, 0x41, 0x67, 0x6f, 0x76,
+ 0xad, 0x04, 0xe0, 0x9c, 0xb3, 0x77, 0xe5, 0xe0, 0x9c, 0xb3, 0x65, 0x61,
+ 0x73, 0x74, 0xad, 0x04, 0xe0, 0x9c, 0x8b, 0x31, 0xae, 0x04, 0xe0, 0xa1,
+ 0xc8, 0xe1, 0x60, 0x9c, 0x8c, 0xc1, 0x66, 0xf2, 0x0b, 0x04, 0x05, 0x04,
+ 0x04, 0x04, 0x07, 0x0d, 0xe0, 0x61, 0x86, 0xf5, 0xe0, 0x4a, 0xdb, 0x6f,
+ 0xf7, 0xe0, 0x4b, 0x03, 0xee, 0xe0, 0x7b, 0x9f, 0xec, 0xe0, 0x39, 0x96,
+ 0xe9, 0xe0, 0x7b, 0x97, 0x65, 0x73, 0x68, 0xe9, 0xe0, 0x4c, 0xa2, 0x62,
+ 0x69, 0x6e, 0xef, 0x02, 0x81, 0x2d, 0x70, 0x65, 0xf3, 0xe0, 0x8c, 0x5d,
+ 0xe1, 0x09, 0x05, 0x04, 0x60, 0x36, 0xf2, 0xe0, 0x63, 0x53, 0x79, 0xe1,
+ 0xe0, 0x6d, 0xdb, 0xf5, 0xe0, 0xa0, 0xca, 0x73, 0x6f, 0xe5, 0xe0, 0xa0,
+ 0xe2, 0xf0, 0x09, 0x06, 0x04, 0x05, 0x60, 0xa2, 0xf5, 0xc1, 0x2d, 0xf0,
+ 0x4e, 0xcb, 0xe0, 0x83, 0xaa, 0xef, 0xe0, 0x68, 0x3b, 0x6c, 0xe9, 0xe0,
+ 0xa4, 0x59, 0x61, 0x61, 0x73, 0x2e, 0x6b, 0x61, 0x7a, 0x74, 0x65, 0x6c,
+ 0x65, 0x70, 0x6f, 0x72, 0x74, 0xae, 0xe0, 0x55, 0x72, 0xef, 0x60, 0x3e,
+ 0x75, 0x5e, 0xc5, 0xe0, 0x45, 0xc1, 0xee, 0x0c, 0x06, 0x0b, 0x06, 0x20,
+ 0x06, 0x60, 0x80, 0x80, 0xe0, 0x22, 0xed, 0x7a, 0x65, 0xee, 0xe0, 0x89,
+ 0xd9, 0x75, 0x73, 0x75, 0x61, 0x6c, 0x70, 0x65, 0xf2, 0xe0, 0x76, 0x80,
+ 0x6e, 0x61, 0xee, 0xe0, 0x9f, 0x6b, 0xe9, 0x06, 0x0f, 0x06, 0xe0, 0xa2,
+ 0x23, 0xf6, 0x02, 0x86, 0x65, 0x72, 0xf3, 0xe0, 0x8a, 0x23, 0xae, 0x60,
+ 0x9a, 0x34, 0xc6, 0xb1, 0xe3, 0x56, 0x9b, 0xe0, 0x87, 0x76, 0xb5, 0xe0,
+ 0xa4, 0xdd, 0xe4, 0x60, 0x8c, 0x4a, 0xc5, 0xbc, 0x61, 0x7a, 0x75, 0xeb,
+ 0xe0, 0x6d, 0xb9, 0xed, 0x06, 0x09, 0x06, 0xe0, 0x67, 0xb1, 0xe9, 0x04,
+ 0xe0, 0x8d, 0xd2, 0xe7, 0xe0, 0x67, 0xba, 0xe2, 0x60, 0x9e, 0x4f, 0xc4,
+ 0x8e, 0x61, 0xea, 0xe0, 0x6b, 0xea, 0xec, 0x05, 0x04, 0xe0, 0x6c, 0x63,
+ 0xf3, 0xe0, 0x8d, 0xdc, 0x6c, 0x65, 0x6e, 0xf3, 0x04, 0xe0, 0x54, 0x49,
+ 0x76, 0x61, 0xee, 0xe0, 0x9d, 0xd2, 0xeb, 0x06, 0x09, 0x09, 0xe0, 0xa4,
+ 0xa5, 0xe9, 0x04, 0xe0, 0x9d, 0x5f, 0xe8, 0xe0, 0x65, 0x65, 0x30, 0x2e,
+ 0x62, 0x69, 0x67, 0xf6, 0xe0, 0xa3, 0xa0, 0xae, 0x0f, 0x46, 0x37, 0x60,
+ 0x86, 0x77, 0x44, 0x37, 0x4d, 0x52, 0x45, 0x23, 0x41, 0x18, 0x9c, 0x70,
+ 0x72, 0x69, 0x6d, 0xe5, 0xe0, 0x22, 0x6c, 0x6a, 0xe9, 0x05, 0x08, 0xe0,
+ 0x96, 0x49, 0x74, 0x61, 0x77, 0x61, 0xf2, 0xe0, 0x6d, 0x9d, 0xe9, 0xe0,
+ 0x55, 0xb3, 0x69, 0x2e, 0x6e, 0x61, 0x62, 0x75, 0x2e, 0x63, 0x61, 0xf3,
+ 0xe0, 0x94, 0x25, 0x68, 0x2d, 0xef, 0xe0, 0x8f, 0x9c, 0xe7, 0x07, 0x60,
+ 0x67, 0x35, 0xe0, 0x3d, 0x2a, 0xe9, 0xe0, 0x2c, 0x4e, 0x66, 0xe3, 0xe0,
+ 0x84, 0x82, 0xe5, 0x04, 0xe0, 0x3c, 0x7f, 0x6e, 0xef, 0x04, 0xe0, 0x9b,
+ 0x7f, 0x68, 0xe1, 0xe0, 0x31, 0xbb, 0xe4, 0x08, 0x04, 0x60, 0x5c, 0xac,
+ 0xe0, 0x45, 0x8a, 0xef, 0xe0, 0x4b, 0x3e, 0xe9, 0x60, 0x81, 0xc3, 0xe0,
+ 0x21, 0x1a, 0x63, 0x68, 0xe9, 0x03, 0x0d, 0x84, 0xee, 0x02, 0x85, 0x6f,
+ 0xed, 0xe0, 0x50, 0x5a, 0x61, 0xe4, 0xe0, 0x50, 0x87, 0xeb, 0xe0, 0x55,
+ 0x0e, 0x68, 0xe1, 0xe0, 0x4f, 0x7f, 0xe2, 0x06, 0x60, 0x83, 0x11, 0xde,
+ 0x95, 0xe5, 0x04, 0xe0, 0xa1, 0xf4, 0xf2, 0x02, 0x88, 0x73, 0x70, 0x61,
+ 0x63, 0xe5, 0xe0, 0x6d, 0xfe, 0xae, 0xe0, 0x38, 0x35, 0xe1, 0x60, 0x26,
+ 0xdf, 0xe0, 0x7d, 0x1b, 0xb2, 0x02, 0x86, 0x2d, 0x6c, 0x6f, 0x63, 0x61,
+ 0x6c, 0x2e, 0x78, 0x6e, 0xe2, 0xe0, 0x7f, 0x8c, 0xae, 0x06, 0x60, 0x92,
+ 0x77, 0xd1, 0x64, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0xec, 0xe0, 0x88,
+ 0xf5, 0xf4, 0x27, 0x07, 0x2c, 0x13, 0x2e, 0x40, 0x61, 0x07, 0x40, 0xb7,
+ 0x41, 0x7a, 0x04, 0x42, 0x30, 0x11, 0x21, 0x0a, 0x0c, 0x1e, 0x32, 0x40,
+ 0x67, 0x09, 0x40, 0xcc, 0x06, 0x0d, 0x42, 0x41, 0x60, 0x70, 0x3c, 0x50,
+ 0x03, 0x4f, 0x1a, 0xc8, 0x76, 0x1f, 0x43, 0x78, 0xee, 0xe0, 0x70, 0xae,
+ 0xf9, 0x07, 0x12, 0x0a, 0x03, 0xe0, 0x9c, 0x61, 0xf3, 0x06, 0x60, 0x93,
+ 0xef, 0xcb, 0x51, 0xf6, 0x04, 0xe0, 0x94, 0x3c, 0x1f, 0x43, 0xe6, 0xe0,
+ 0x97, 0xe5, 0x70, 0x65, 0x64, 0x72, 0x65, 0x61, 0xed, 0xe0, 0xa2, 0x0d,
+ 0xee, 0xcf, 0xa6, 0x63, 0xe8, 0xe0, 0x91, 0x7b, 0xf7, 0x06, 0x60, 0x90,
+ 0x02, 0xd3, 0x6f, 0x6d, 0x61, 0x69, 0x6c, 0xae, 0x60, 0x80, 0xb9, 0x5f,
+ 0xe4, 0xc2, 0xac, 0xf6, 0x07, 0x05, 0x60, 0xa0, 0xef, 0xc2, 0x69, 0x65,
+ 0xe4, 0xe0, 0x5f, 0x37, 0xae, 0x0b, 0x06, 0x08, 0x60, 0x59, 0x9e, 0x60,
+ 0x35, 0xf0, 0xcf, 0xc9, 0xf4, 0x60, 0xa0, 0xd8, 0xc1, 0x1a, 0xe9, 0x60,
+ 0xa0, 0xf3, 0x40, 0x94, 0xc0, 0x84, 0xe2, 0x60, 0x98, 0xe4, 0x48, 0xce,
+ 0xb2, 0xf5, 0x0b, 0x08, 0x0a, 0x04, 0x0b, 0x1a, 0x09, 0x60, 0xa0, 0xb3,
+ 0x9b, 0x79, 0x65, 0x6e, 0x71, 0xf5, 0xe0, 0x9a, 0x77, 0x78, 0x66, 0x61,
+ 0x6d, 0x69, 0x6c, 0xf9, 0xe0, 0xa0, 0x4c, 0xf6, 0xe0, 0xa1, 0x2d, 0xf3,
+ 0x04, 0xe0, 0xa2, 0x0f, 0x63, 0x61, 0xee, 0xe0, 0x9a, 0x02, 0xf2, 0x04,
+ 0x07, 0x04, 0x84, 0x79, 0x73, 0x74, 0xf9, 0xe0, 0x7b, 0x91, 0xe9, 0xe0,
+ 0x22, 0x2f, 0xe5, 0xe0, 0x90, 0x8f, 0xae, 0x60, 0x90, 0xe4, 0xd0, 0xb7,
+ 0xee, 0x04, 0xe0, 0x96, 0xf4, 0xeb, 0xe0, 0xa0, 0x1a, 0xec, 0x04, 0xe0,
+ 0xa0, 0xf7, 0x65, 0x61, 0x70, 0x2d, 0x70, 0x61, 0x72, 0x74, 0xee, 0xe0,
+ 0x7a, 0x6e, 0xf4, 0x60, 0x42, 0x31, 0xe0, 0x60, 0xa4, 0xf3, 0x06, 0x40,
+ 0x98, 0x04, 0x04, 0x8a, 0xf5, 0x0e, 0x05, 0x06, 0x0b, 0x1e, 0x0b, 0x07,
+ 0x20, 0x04, 0x0b, 0x06, 0xe0, 0x59, 0xa5, 0x79, 0xe1, 0xe0, 0x61, 0xfb,
+ 0x77, 0x61, 0xee, 0xe0, 0x60, 0xb4, 0x73, 0x68, 0x69, 0x6d, 0x61, 0xae,
+ 0x60, 0x87, 0x50, 0xd6, 0x10, 0x72, 0xf5, 0x06, 0x04, 0x03, 0xe0, 0x7a,
+ 0x74, 0xf4, 0xe0, 0x3b, 0x21, 0xef, 0xd0, 0x59, 0xe7, 0x04, 0xe0, 0x63,
+ 0x2c, 0xe1, 0x04, 0xe0, 0x78, 0x0e, 0x73, 0xe8, 0xe0, 0x4d, 0x4e, 0xee,
+ 0x02, 0x84, 0xef, 0xe0, 0x4b, 0x11, 0xe1, 0xe0, 0x67, 0x0a, 0x6d, 0x61,
+ 0x67, 0xef, 0xe0, 0x54, 0xda, 0xeb, 0x02, 0x8e, 0xf5, 0x05, 0x04, 0xe0,
+ 0x95, 0xf7, 0xed, 0xe0, 0x5f, 0xbe, 0xe2, 0xe0, 0x5f, 0x0f, 0xe9, 0x02,
+ 0x86, 0x79, 0x6f, 0xee, 0xe0, 0x34, 0x4e, 0x67, 0x61, 0xf4, 0xe0, 0xa0,
+ 0x74, 0xe9, 0xe0, 0x59, 0x9a, 0x67, 0xe1, 0x04, 0xe0, 0x96, 0xc4, 0x72,
+ 0xf5, 0xe0, 0x67, 0x13, 0x63, 0x68, 0xe9, 0xe0, 0x4d, 0xa6, 0xe2, 0x04,
+ 0xe0, 0x9d, 0x81, 0xe1, 0x04, 0xe0, 0x4c, 0xeb, 0xed, 0xe0, 0x3a, 0x72,
+ 0xf4, 0xe0, 0x84, 0x4b, 0xeb, 0xe0, 0x90, 0xfb, 0x65, 0x6c, 0x69, 0x6e,
+ 0x6f, 0x67, 0xf2, 0xe0, 0x96, 0xa8, 0xae, 0x60, 0xa0, 0x1b, 0xc1, 0xdf,
+ 0xf2, 0x11, 0x08, 0x1e, 0x04, 0x23, 0x12, 0x40, 0x44, 0x40, 0xbd, 0x60,
+ 0x8b, 0xca, 0x51, 0x20, 0xc3, 0xbc, 0x1f, 0xc3, 0x04, 0xe0, 0x6b, 0xf4,
+ 0xf8, 0xbc, 0xf9, 0x03, 0x05, 0x8b, 0x73, 0xe9, 0xe0, 0x9a, 0xde, 0x63,
+ 0x6c, 0x6f, 0x75, 0x64, 0x66, 0x6c, 0xe1, 0xe0, 0x87, 0x87, 0x2d, 0x73,
+ 0x6e, 0x6f, 0x77, 0x70, 0xec, 0xe0, 0x48, 0x0d, 0xf5, 0xe0, 0x95, 0x07,
+ 0xef, 0x05, 0x05, 0x09, 0x05, 0x84, 0x6e, 0xe4, 0xe0, 0x94, 0xf3, 0x6d,
+ 0xf3, 0x60, 0x8c, 0xa8, 0x4c, 0xdb, 0xc2, 0x24, 0x69, 0xf4, 0xe0, 0x9b,
+ 0x88, 0xe7, 0xe0, 0x6e, 0xe9, 0x61, 0x6e, 0xe4, 0xe0, 0x64, 0xd3, 0xe9,
+ 0x02, 0x8a, 0x74, 0x6f, 0x6e, 0x2e, 0x7a, 0x6f, 0xee, 0xe0, 0x83, 0xcf,
+ 0x65, 0xf3, 0xe0, 0x21, 0xba, 0xe5, 0x02, 0x85, 0x76, 0xe9, 0xe0, 0x89,
+ 0x35, 0x6e, 0xf4, 0x04, 0xe0, 0x9f, 0x95, 0x69, 0xee, 0x03, 0x1c, 0x81,
+ 0xef, 0x06, 0x03, 0x07, 0xe0, 0x9f, 0x80, 0xad, 0x02, 0x87, 0xf3, 0x15,
+ 0x04, 0x09, 0xe0, 0x91, 0xd6, 0xe1, 0x05, 0x60, 0x9a, 0x70, 0x81, 0x6c,
+ 0xf4, 0xe0, 0x9a, 0x6b, 0x2d, 0xf3, 0x02, 0x84, 0x1f, 0x43, 0xfc, 0x85,
+ 0xf5, 0x02, 0x81, 0x65, 0xe4, 0x04, 0xe0, 0x91, 0xd6, 0xad, 0xe0, 0x91,
+ 0xd5, 0xe1, 0x09, 0x1d, 0x04, 0x40, 0x66, 0x07, 0x0b, 0x0c, 0x8b, 0xf6,
+ 0x04, 0xe0, 0x92, 0x1c, 0x65, 0xec, 0x05, 0x09, 0xe0, 0xa1, 0x44, 0x65,
+ 0x72, 0xf3, 0x60, 0x42, 0xcc, 0xe0, 0x5e, 0x7e, 0xae, 0x60, 0x9c, 0xbe,
+ 0x42, 0xc6, 0xc0, 0x84, 0xf0, 0xe0, 0x98, 0xd5, 0xee, 0x0c, 0x2a, 0x60,
+ 0x43, 0x69, 0x60, 0x51, 0xe8, 0x43, 0x0d, 0xc2, 0x7b, 0xf3, 0x03, 0x14,
+ 0x84, 0x75, 0x72, 0x6c, 0xae, 0x03, 0x05, 0x84, 0x6e, 0xec, 0xe0, 0xa1,
+ 0x0c, 0xe5, 0xe0, 0x5c, 0x08, 0xe2, 0xe0, 0x83, 0x36, 0xf0, 0xe0, 0x7b,
+ 0x58, 0x6c, 0x61, 0x74, 0xe5, 0x02, 0x84, 0xe4, 0xe0, 0x81, 0x51, 0xae,
+ 0xe0, 0x83, 0xad, 0xe9, 0x03, 0x0b, 0x89, 0x62, 0x61, 0x72, 0x6c, 0x65,
+ 0x74, 0x74, 0xe1, 0xe0, 0x9a, 0x61, 0x61, 0x6e, 0x64, 0x72, 0x69, 0xe1,
+ 0xe0, 0x98, 0x72, 0xad, 0x02, 0x8b, 0x62, 0x61, 0x72, 0x6c, 0x65, 0x74,
+ 0x74, 0xe1, 0xe0, 0x90, 0xc6, 0x61, 0x6e, 0x64, 0x72, 0x69, 0xe1, 0xe0,
+ 0x98, 0x5a, 0x69, 0xee, 0x60, 0x85, 0xde, 0xc5, 0x70, 0x66, 0x66, 0x69,
+ 0x63, 0x70, 0x6c, 0x65, 0xf8, 0xe0, 0x88, 0xe3, 0x65, 0x75, 0x6d, 0x74,
+ 0x67, 0x65, 0x72, 0x61, 0xe4, 0xe0, 0x79, 0x1a, 0xe4, 0x04, 0xe0, 0x87,
+ 0x6c, 0xe5, 0x60, 0x85, 0xbd, 0xda, 0xf1, 0xae, 0xda, 0x3e, 0xae, 0x60,
+ 0x9a, 0x47, 0x44, 0x5c, 0xc0, 0x6e, 0xf0, 0xe0, 0x9e, 0x9a, 0xef, 0x19,
+ 0x0b, 0x40, 0x5c, 0x14, 0x12, 0x0f, 0x24, 0x22, 0x0a, 0x0c, 0x2c, 0x2b,
+ 0x04, 0x40, 0x50, 0x0e, 0x2a, 0x04, 0x07, 0x0f, 0x12, 0xe0, 0x9e, 0x79,
+ 0xfa, 0x04, 0xe0, 0x3e, 0x49, 0x73, 0x64, 0xe5, 0xe0, 0x9f, 0x76, 0xf9,
+ 0x06, 0x40, 0x43, 0xe0, 0x9d, 0xc2, 0xef, 0x0d, 0x18, 0x04, 0x03, 0x08,
+ 0x04, 0x06, 0x60, 0x5e, 0x26, 0xe0, 0x3c, 0x07, 0xf4, 0x03, 0x04, 0x85,
+ 0xf3, 0xe0, 0x7b, 0xc9, 0x6f, 0xed, 0xe0, 0x9e, 0xa0, 0xe1, 0x04, 0xe0,
+ 0xa0, 0x4e, 0xae, 0x60, 0x9b, 0x05, 0xc3, 0x33, 0x73, 0xe1, 0xd8, 0xaa,
+ 0xef, 0xc5, 0x21, 0xee, 0x60, 0x84, 0xf7, 0x4f, 0x38, 0xca, 0x3b, 0xeb,
+ 0xe0, 0x57, 0x6f, 0x68, 0x61, 0xf3, 0xe0, 0x28, 0x6d, 0xe1, 0xe0, 0x94,
+ 0x1c, 0xe1, 0x05, 0x08, 0xe0, 0x9e, 0x68, 0x6d, 0x61, 0xae, 0x60, 0x94,
+ 0xff, 0xc9, 0x78, 0xeb, 0xe0, 0x94, 0x80, 0xf7, 0x02, 0x8c, 0xee, 0x04,
+ 0xe0, 0xa0, 0x11, 0x6e, 0x65, 0x77, 0xf3, 0xe0, 0x92, 0x8e, 0x61, 0xe4,
+ 0xe0, 0x38, 0x8f, 0x75, 0xf2, 0x04, 0xe0, 0x9d, 0x96, 0x69, 0x73, 0x6d,
+ 0xae, 0x60, 0x71, 0xeb, 0x60, 0x29, 0x8b, 0xc0, 0x5d, 0xf4, 0x04, 0xe0,
+ 0x7a, 0x44, 0x74, 0x6f, 0x72, 0x69, 0xae, 0x60, 0x84, 0x04, 0xda, 0x3a,
+ 0xf3, 0x09, 0x07, 0x05, 0x60, 0x4b, 0xbd, 0xe0, 0x52, 0x0e, 0x68, 0xe9,
+ 0x60, 0x99, 0x34, 0xc0, 0x98, 0x63, 0xe1, 0xe0, 0x97, 0x8a, 0xe1, 0x04,
+ 0xe0, 0x99, 0xc7, 0x73, 0x68, 0x69, 0x6d, 0x69, 0xfa, 0xe0, 0x30, 0xf0,
+ 0xf2, 0x07, 0x04, 0x03, 0x08, 0xe0, 0x21, 0xb5, 0xf5, 0xe0, 0x3e, 0xe2,
+ 0xf3, 0xd7, 0x85, 0xe9, 0x04, 0xe0, 0x94, 0x49, 0xe4, 0xce, 0x5d, 0xe1,
+ 0x04, 0xe0, 0x9d, 0x6d, 0x68, 0x69, 0xed, 0xe0, 0x5c, 0xe1, 0xf0, 0x04,
+ 0xe0, 0x9f, 0x99, 0x61, 0xfa, 0xe0, 0x66, 0xb0, 0xef, 0x04, 0xe0, 0x9a,
+ 0xbf, 0xec, 0x60, 0x5e, 0x3e, 0xe0, 0x3e, 0xe7, 0xee, 0x09, 0x0a, 0x06,
+ 0x09, 0x4e, 0x17, 0xe0, 0x5e, 0x55, 0xef, 0x04, 0xe0, 0x69, 0x2e, 0x73,
+ 0xe8, 0xe0, 0x3d, 0x21, 0x6b, 0x6f, 0x74, 0xf3, 0xdb, 0xf7, 0x64, 0x61,
+ 0x62, 0x61, 0x79, 0xe1, 0xe0, 0x5d, 0x0d, 0xe1, 0x04, 0xe0, 0x51, 0xb6,
+ 0xed, 0xe0, 0x68, 0x24, 0xed, 0x05, 0x04, 0x16, 0xcf, 0xf6, 0x6f, 0xe2,
+ 0xce, 0x06, 0xe9, 0x0d, 0x04, 0x60, 0x28, 0x7f, 0x5f, 0x15, 0x60, 0x21,
+ 0x0c, 0xe0, 0x33, 0x8c, 0xf9, 0xe0, 0x67, 0xc5, 0xeb, 0xe0, 0x71, 0x95,
+ 0xe1, 0x04, 0xe0, 0x9d, 0x80, 0x6b, 0x6f, 0xed, 0xe0, 0x8c, 0xba, 0xec,
+ 0xe0, 0x7a, 0xbf, 0xeb, 0x08, 0x04, 0x15, 0x0f, 0x07, 0xe0, 0x6d, 0xca,
+ 0xf9, 0xe0, 0x43, 0x0f, 0xf5, 0x02, 0x87, 0x79, 0x61, 0x6d, 0xe1, 0xe0,
+ 0x9d, 0x03, 0x73, 0x68, 0x69, 0x6d, 0x61, 0xae, 0x60, 0x99, 0x9c, 0xc3,
+ 0xc9, 0xef, 0x02, 0x86, 0x72, 0x6f, 0xfa, 0xe0, 0x26, 0xa2, 0x6e, 0x61,
+ 0xed, 0xe0, 0x92, 0xee, 0xe9, 0x60, 0x26, 0x97, 0xe0, 0x6f, 0x8b, 0xe1,
+ 0x03, 0x06, 0x87, 0x73, 0x68, 0xe9, 0xe0, 0x51, 0x44, 0x6d, 0x61, 0x63,
+ 0xe8, 0xe0, 0x4f, 0xae, 0x69, 0xae, 0x60, 0x97, 0x51, 0xc2, 0x49, 0xe8,
+ 0x06, 0x60, 0x83, 0x76, 0xce, 0xed, 0x6e, 0x6f, 0x73, 0xe8, 0xe0, 0x9c,
+ 0xf3, 0xe7, 0x07, 0x05, 0x08, 0x04, 0xe0, 0x95, 0xfc, 0x75, 0xf2, 0xe0,
+ 0x83, 0x57, 0x6c, 0x69, 0x61, 0x74, 0xf4, 0xe0, 0x2f, 0x3e, 0xe9, 0xe0,
+ 0x44, 0x2d, 0xe1, 0x05, 0x05, 0xe0, 0x67, 0xac, 0x6e, 0xe5, 0xe0, 0x9c,
+ 0xd0, 0x6b, 0x75, 0xf3, 0xe0, 0x9b, 0x92, 0xe5, 0xe0, 0x99, 0x5a, 0x64,
+ 0xe1, 0x60, 0x93, 0x60, 0xc9, 0x08, 0x63, 0x68, 0xe9, 0x04, 0xe0, 0x9a,
+ 0x48, 0x67, 0x69, 0xae, 0x60, 0x93, 0x0c, 0xc9, 0xd9, 0xe2, 0x05, 0x07,
+ 0xe0, 0x4b, 0x94, 0x69, 0x73, 0x68, 0xe9, 0xe0, 0x54, 0x05, 0xe5, 0x60,
+ 0x99, 0xae, 0x98, 0xae, 0x08, 0x60, 0x92, 0x3a, 0x45, 0xd2, 0xc4, 0x62,
+ 0xe7, 0x60, 0x9c, 0x2a, 0xc2, 0x24, 0xee, 0x04, 0xe0, 0x9e, 0x65, 0xae,
+ 0x06, 0x60, 0x99, 0x5a, 0xc3, 0x02, 0x6f, 0xf8, 0xe0, 0x50, 0x33, 0xed,
+ 0x08, 0x60, 0x6f, 0xad, 0x5d, 0xc5, 0xd0, 0xde, 0xae, 0x11, 0x60, 0x8c,
+ 0xd8, 0x45, 0x89, 0x03, 0x10, 0x47, 0x45, 0x13, 0x11, 0x42, 0xcd, 0x08,
+ 0xc0, 0x8b, 0xed, 0x60, 0x92, 0x5a, 0xcb, 0xe2, 0xec, 0x04, 0xe0, 0x9e,
+ 0x33, 0x6f, 0xee, 0xe0, 0x93, 0x2d, 0xeb, 0x05, 0x18, 0xe0, 0x9e, 0x10,
+ 0x73, 0x61, 0xf4, 0xe0, 0x9b, 0x6d, 0xea, 0x0b, 0x04, 0x02, 0x06, 0x60,
+ 0x8a, 0x9b, 0x4b, 0xed, 0xc7, 0x82, 0x1f, 0x43, 0xf8, 0xa8, 0xef, 0xa6,
+ 0x6d, 0x61, 0xf8, 0xe0, 0x96, 0x8b, 0x65, 0x6c, 0xe4, 0xe0, 0x87, 0xc9,
+ 0xe9, 0x08, 0x07, 0x09, 0x04, 0x07, 0x0a, 0xde, 0x44, 0xf2, 0x60, 0x66,
+ 0x5b, 0xe0, 0x2b, 0xa8, 0xee, 0x04, 0xe0, 0x97, 0xba, 0xe7, 0xe0, 0x92,
+ 0x39, 0xed, 0xe0, 0x9c, 0x54, 0x65, 0xee, 0x60, 0x8e, 0xe4, 0xc3, 0x90,
+ 0x63, 0x6b, 0x65, 0x74, 0xf3, 0x60, 0x9c, 0xd3, 0xc1, 0x08, 0xe1, 0xe0,
+ 0x9c, 0x2e, 0xe8, 0x0a, 0x0c, 0x08, 0x11, 0x17, 0x60, 0x9b, 0x3f, 0xc2,
+ 0x4c, 0x75, 0x61, 0x74, 0x68, 0x69, 0x65, 0x6e, 0x68, 0xf5, 0xe0, 0x8b,
+ 0xec, 0x72, 0x75, 0x68, 0x65, 0xf2, 0xe0, 0x9a, 0x46, 0xe9, 0x04, 0xe0,
+ 0x77, 0x0b, 0x6e, 0x67, 0x64, 0x75, 0x73, 0x74, 0x64, 0x61, 0xf4, 0xe0,
+ 0x68, 0x5b, 0xe5, 0x08, 0x07, 0x60, 0x48, 0x5f, 0xe0, 0x53, 0xd8, 0x77,
+ 0x6f, 0x72, 0xeb, 0xe0, 0x59, 0x25, 0x61, 0xf4, 0x60, 0x89, 0xf0, 0xd0,
+ 0xd9, 0xe1, 0x02, 0x92, 0x6e, 0xe8, 0x04, 0xe0, 0x47, 0x3c, 0x70, 0x68,
+ 0x6f, 0x68, 0x6f, 0x63, 0x68, 0x69, 0xed, 0xe0, 0x8e, 0x41, 0xe9, 0x04,
+ 0xe0, 0x59, 0x97, 0x6e, 0x67, 0xf5, 0xe0, 0x57, 0x9b, 0xe7, 0x04, 0xe0,
+ 0x9d, 0x66, 0xef, 0xe0, 0x39, 0xd8, 0xe5, 0x0e, 0x19, 0x16, 0x18, 0x20,
+ 0x21, 0x26, 0x60, 0x7a, 0x6c, 0x51, 0x05, 0xc4, 0xc8, 0xf3, 0x02, 0x8e,
+ 0xf4, 0x02, 0x87, 0xae, 0x60, 0x2b, 0x7c, 0xe0, 0x71, 0x47, 0xad, 0xe0,
+ 0x38, 0xd0, 0x68, 0x69, 0x6b, 0x61, 0xe7, 0xe0, 0x9b, 0x5b, 0xf2, 0x05,
+ 0x0a, 0xe0, 0x8b, 0x46, 0xee, 0x04, 0xe0, 0x94, 0xcb, 0x6f, 0x70, 0xe9,
+ 0xce, 0xa3, 0x6d, 0x65, 0xfa, 0xe0, 0x9b, 0x3d, 0xee, 0x07, 0x04, 0x04,
+ 0x04, 0xe0, 0x5b, 0xe9, 0xee, 0xe0, 0x60, 0x1a, 0xeb, 0xe0, 0x28, 0xa3,
+ 0xe5, 0xe0, 0x8d, 0x51, 0xe4, 0xe0, 0x2e, 0x1c, 0xed, 0x02, 0x99, 0xf0,
+ 0x03, 0x06, 0x8b, 0x75, 0x72, 0xec, 0xe0, 0x68, 0x1c, 0x69, 0xef, 0x02,
+ 0x81, 0x2d, 0x6f, 0x6c, 0xe2, 0xe0, 0x96, 0x67, 0xad, 0xe0, 0x74, 0x99,
+ 0x61, 0xf3, 0xce, 0x35, 0xec, 0x06, 0x60, 0x8b, 0xb5, 0xd1, 0x30, 0xe5,
+ 0x02, 0x8f, 0x62, 0x69, 0x74, 0xae, 0x06, 0x60, 0x9b, 0x63, 0xc0, 0x6e,
+ 0x78, 0xf9, 0xe0, 0x7f, 0x54, 0x2e, 0x61, 0x6d, 0x75, 0xee, 0xe0, 0x87,
+ 0x92, 0xe3, 0x03, 0x05, 0x95, 0x6e, 0xef, 0xe0, 0x72, 0x33, 0xe8, 0x05,
+ 0x07, 0xe0, 0x9c, 0xb5, 0x6e, 0x6f, 0x6c, 0xef, 0xe0, 0x6e, 0xd5, 0x2e,
+ 0x6f, 0x72, 0x61, 0xee, 0xe0, 0x7c, 0xfc, 0xae, 0x60, 0x91, 0xbf, 0x42,
+ 0x2e, 0xc7, 0x65, 0xe1, 0x04, 0xe0, 0x9a, 0x4e, 0x63, 0x68, 0x65, 0x73,
+ 0x2d, 0x79, 0xef, 0xe0, 0x67, 0x3e, 0xe4, 0x60, 0x9a, 0x2f, 0xc2, 0x66,
+ 0xe3, 0x08, 0x60, 0x9a, 0x6e, 0x40, 0xbe, 0xc1, 0x5b, 0xf0, 0xe0, 0x56,
+ 0x21, 0xe1, 0x19, 0x04, 0x0b, 0x0a, 0x38, 0x08, 0x25, 0x05, 0x1f, 0x29,
+ 0x40, 0xc8, 0x07, 0x3d, 0x03, 0x0e, 0x13, 0x0f, 0x60, 0x8e, 0x8d, 0x45,
+ 0x43, 0xc4, 0x8c, 0xf9, 0xe0, 0x8d, 0x2f, 0xf8, 0x04, 0xe0, 0x9c, 0x60,
+ 0xe9, 0x60, 0x9b, 0x04, 0xc1, 0x5b, 0x77, 0x61, 0x72, 0x61, 0x6d, 0x6f,
+ 0xf4, 0xe0, 0x59, 0xcc, 0xf4, 0x04, 0x05, 0x0a, 0x9a, 0x74, 0xef, 0xe0,
+ 0x9a, 0xbe, 0x73, 0x75, 0x6e, 0x6f, 0xae, 0x60, 0x97, 0x69, 0xc1, 0xc5,
+ 0xe5, 0x03, 0x0a, 0x86, 0x79, 0x61, 0x6d, 0x61, 0xae, 0x60, 0x91, 0x10,
+ 0xc9, 0x46, 0x73, 0x68, 0xe9, 0xe0, 0x54, 0xac, 0x62, 0x61, 0xf9, 0xe0,
+ 0x3a, 0x7a, 0xe1, 0x04, 0xe0, 0x9a, 0xc4, 0x6d, 0xef, 0xe0, 0x7a, 0x86,
+ 0xf3, 0x03, 0xd7, 0xf7, 0xe8, 0xe0, 0x80, 0x82, 0xf2, 0x04, 0x0c, 0x04,
+ 0x87, 0xf5, 0x04, 0xe0, 0x93, 0x2c, 0x6d, 0x69, 0x7a, 0xf5, 0xe0, 0x95,
+ 0xb7, 0xee, 0xe0, 0x43, 0x3a, 0xe7, 0x60, 0x2a, 0x0e, 0xe0, 0x5e, 0xe6,
+ 0xe1, 0x60, 0x41, 0x16, 0x60, 0x50, 0x3d, 0xc6, 0x28, 0x6f, 0xe2, 0xe0,
+ 0x71, 0x2e, 0xee, 0x05, 0x04, 0xe0, 0x8c, 0xe9, 0x6f, 0xe8, 0xd4, 0xa1,
+ 0xe1, 0x07, 0x05, 0x60, 0x85, 0xbd, 0xd4, 0x7d, 0x67, 0xf5, 0xe0, 0x44,
+ 0x1e, 0x62, 0x65, 0xae, 0x60, 0x8d, 0x98, 0xc3, 0x8d, 0xed, 0x02, 0x84,
+ 0xe2, 0xe0, 0x5b, 0x85, 0xe1, 0x0a, 0x04, 0x09, 0x04, 0x60, 0x49, 0x57,
+ 0xe0, 0x4f, 0x06, 0xf9, 0xe0, 0x60, 0x0f, 0x74, 0x73, 0x75, 0x6b, 0x75,
+ 0xf2, 0xe0, 0x80, 0x39, 0xed, 0xe0, 0x4d, 0x5c, 0xeb, 0x4f, 0xc7, 0xe0,
+ 0x34, 0xa2, 0xeb, 0x0a, 0x03, 0x12, 0x0f, 0x60, 0x47, 0x5e, 0xe0, 0x52,
+ 0x32, 0xeb, 0xc9, 0xe8, 0xe9, 0x07, 0x60, 0x52, 0xef, 0xe0, 0x3d, 0x61,
+ 0x6e, 0xef, 0x04, 0xe0, 0x96, 0xa9, 0xf5, 0xe0, 0x7f, 0xb0, 0xe5, 0x02,
+ 0x89, 0xf4, 0x04, 0xe0, 0x84, 0x99, 0xef, 0xe0, 0x5d, 0x41, 0xe8, 0xc8,
+ 0xc6, 0xe1, 0x0e, 0x06, 0x0e, 0x14, 0x12, 0x08, 0x05, 0x0d, 0x0f, 0x04,
+ 0x1f, 0xe0, 0x96, 0x01, 0x7a, 0x61, 0xeb, 0xe0, 0x46, 0x07, 0x79, 0x61,
+ 0x6d, 0x61, 0xae, 0x04, 0xe0, 0x98, 0x3e, 0xe7, 0x60, 0x92, 0x79, 0x8d,
+ 0xf4, 0x05, 0x0a, 0xe0, 0x5b, 0xf0, 0x73, 0x75, 0x6b, 0x69, 0xae, 0x60,
+ 0x95, 0xf0, 0xc3, 0x7d, 0xef, 0xe0, 0x5a, 0x14, 0xf3, 0x05, 0x05, 0xe0,
+ 0x96, 0x78, 0x68, 0xe9, 0xe0, 0x31, 0xa6, 0xe1, 0x60, 0x4d, 0x8f, 0xe0,
+ 0x42, 0x82, 0x72, 0x61, 0x7a, 0x75, 0xeb, 0xe0, 0x5a, 0xe3, 0x6f, 0xeb,
+ 0xe0, 0x4a, 0x2d, 0xee, 0x02, 0x85, 0x65, 0xfa, 0xe0, 0x47, 0xd2, 0x61,
+ 0xe2, 0xe0, 0x5f, 0xff, 0xed, 0x02, 0x89, 0x6f, 0x72, 0x69, 0xae, 0x60,
+ 0x93, 0xb3, 0xc4, 0x3f, 0xe1, 0xc0, 0x86, 0xe9, 0xe0, 0x58, 0xa1, 0x68,
+ 0xe1, 0x07, 0x04, 0x05, 0x09, 0xe0, 0x63, 0xa7, 0xf3, 0xe0, 0x8f, 0xa5,
+ 0x72, 0xf5, 0xe0, 0x8c, 0xba, 0x6d, 0x61, 0xae, 0x60, 0x70, 0x69, 0xe0,
+ 0x25, 0x33, 0xe7, 0xe0, 0x7f, 0x6b, 0xe7, 0xe0, 0x97, 0xc4, 0x6a, 0xe9,
+ 0x60, 0x32, 0xa4, 0xcd, 0x60, 0xe9, 0x0c, 0x0f, 0x04, 0x05, 0x05, 0x08,
+ 0x05, 0x60, 0x58, 0x24, 0xca, 0xf5, 0x73, 0x68, 0xe9, 0x02, 0x84, 0xee,
+ 0xe0, 0x95, 0x50, 0xae, 0x60, 0x95, 0xe0, 0xc3, 0x04, 0xf2, 0xe0, 0x49,
+ 0xc3, 0x70, 0xe5, 0xe0, 0x98, 0x94, 0x6e, 0xe1, 0xe0, 0x4b, 0x6f, 0x6b,
+ 0x69, 0xae, 0x60, 0x8f, 0x83, 0xc9, 0x6b, 0x6a, 0xe9, 0xe0, 0x8f, 0xf3,
+ 0x66, 0x75, 0xee, 0xe0, 0x75, 0xe3, 0xe8, 0xc8, 0x17, 0x67, 0xe1, 0x07,
+ 0x60, 0x2f, 0xcd, 0xe0, 0x27, 0x93, 0x6a, 0xef, 0xe0, 0x63, 0x07, 0xe4,
+ 0x02, 0x8b, 0xef, 0x04, 0xe0, 0x51, 0xe0, 0x74, 0x73, 0xf5, 0xe0, 0x8c,
+ 0x3b, 0x61, 0xef, 0xe0, 0x7f, 0x29, 0x63, 0x68, 0xe9, 0x02, 0x84, 0xeb,
+ 0xe0, 0x6f, 0x65, 0x61, 0x72, 0xe1, 0xe0, 0x51, 0xab, 0xe2, 0x06, 0x06,
+ 0x09, 0xe0, 0x9a, 0x49, 0x75, 0x73, 0xe5, 0xe0, 0x98, 0x3f, 0x69, 0x74,
+ 0x6f, 0x72, 0x64, 0x65, 0xf2, 0xd4, 0xff, 0x61, 0x79, 0x61, 0xed, 0xe0,
+ 0x63, 0x85, 0x33, 0x6c, 0x33, 0x70, 0x30, 0xf2, 0xe0, 0x8d, 0xe8, 0xf3,
+ 0x2b, 0x28, 0x1e, 0x40, 0x52, 0x06, 0x31, 0x26, 0x40, 0xe4, 0x41, 0xd8,
+ 0x1d, 0x0f, 0x11, 0x40, 0x5c, 0x40, 0xe1, 0x2e, 0x3a, 0x22, 0x40, 0x99,
+ 0x07, 0x40, 0x8f, 0x42, 0xaf, 0x09, 0x05, 0x41, 0xf5, 0x16, 0x40, 0xe8,
+ 0x0f, 0x42, 0xa5, 0x05, 0xe0, 0x60, 0xba, 0x1f, 0xc3, 0x05, 0x1b, 0xe0,
+ 0x8a, 0x53, 0xf8, 0x04, 0x09, 0x05, 0x84, 0xf2, 0x44, 0x7f, 0x0a, 0x49,
+ 0x63, 0xe0, 0x74, 0x94, 0x6e, 0x64, 0xf2, 0xc4, 0xac, 0xed, 0xe0, 0x8f,
+ 0x27, 0xe7, 0xe0, 0x83, 0x7c, 0x61, 0xec, 0x60, 0x87, 0x56, 0x82, 0xfa,
+ 0x06, 0x04, 0x05, 0xe0, 0x99, 0xd5, 0xeb, 0xe0, 0x40, 0xb5, 0x65, 0xf8,
+ 0xe0, 0x98, 0xd6, 0x63, 0xfa, 0x02, 0x85, 0x79, 0xf4, 0xe0, 0x5f, 0x43,
+ 0x65, 0xe3, 0xe0, 0x88, 0x2d, 0xf9, 0x09, 0x0f, 0x2d, 0x08, 0x60, 0x8a,
+ 0xff, 0xce, 0x7a, 0xf3, 0x02, 0x85, 0x74, 0xe5, 0xe0, 0x7c, 0xb1, 0x2e,
+ 0x71, 0x63, 0xf8, 0xe0, 0x8b, 0x44, 0xee, 0x02, 0xa2, 0xef, 0x02, 0x9a,
+ 0x6c, 0x6f, 0x67, 0xf9, 0x04, 0xe0, 0x83, 0x9b, 0x2d, 0xe4, 0x04, 0xe0,
+ 0x74, 0xeb, 0x69, 0x73, 0x6b, 0x73, 0x74, 0x61, 0x74, 0x69, 0xef, 0xe0,
+ 0x70, 0xa1, 0x2d, 0xe4, 0xe0, 0x74, 0xdd, 0x63, 0x6c, 0x6f, 0x75, 0xe4,
+ 0xe0, 0x99, 0x39, 0x6b, 0x6b, 0x79, 0x6c, 0xf6, 0xe0, 0x8a, 0x00, 0xe4,
+ 0xe0, 0x8c, 0xfd, 0xf8, 0x60, 0x86, 0x05, 0xd3, 0x6f, 0xf7, 0x03, 0x1e,
+ 0x8a, 0xe9, 0x06, 0x08, 0x06, 0xe0, 0x91, 0xea, 0x6e, 0x6f, 0x75, 0x6a,
+ 0x73, 0xe3, 0xd8, 0x74, 0x65, 0x62, 0xef, 0xe0, 0x87, 0xba, 0x64, 0x6e,
+ 0xe9, 0x60, 0x3b, 0x8b, 0xe0, 0x25, 0x0c, 0x65, 0x65, 0x74, 0x70, 0x65,
+ 0x70, 0xf0, 0xe0, 0x4d, 0x67, 0x61, 0xf4, 0xe0, 0x83, 0xa4, 0xf6, 0x0b,
+ 0x05, 0x0b, 0x60, 0x5b, 0x5f, 0x60, 0x3b, 0xc0, 0xc2, 0x03, 0x6e, 0xad,
+ 0xe0, 0x5f, 0x76, 0xe5, 0x02, 0x84, 0xec, 0xe0, 0x60, 0xc0, 0xe9, 0xe0,
+ 0x90, 0xd9, 0x63, 0x2e, 0x66, 0x69, 0x72, 0x65, 0xee, 0xe0, 0x66, 0xcd,
+ 0xf5, 0x12, 0x11, 0x0b, 0x0e, 0x0f, 0x27, 0x13, 0x1c, 0x0b, 0x0b, 0x0a,
+ 0x0c, 0x06, 0x05, 0x04, 0xe0, 0x98, 0x3b, 0xfa, 0x04, 0xe0, 0x51, 0x44,
+ 0xf5, 0x04, 0xe0, 0x90, 0xca, 0xeb, 0x60, 0x46, 0x10, 0xe0, 0x50, 0xd1,
+ 0x77, 0xe1, 0x04, 0xe0, 0x95, 0xda, 0x6c, 0xeb, 0xe0, 0x27, 0x00, 0xf3,
+ 0x02, 0x86, 0x6f, 0x6e, 0xef, 0xe0, 0x8e, 0x81, 0x61, 0xeb, 0xe0, 0x5f,
+ 0xef, 0xf2, 0x05, 0x05, 0xe0, 0x8d, 0xe7, 0x6e, 0xe1, 0xe0, 0x91, 0xb7,
+ 0xe7, 0xe0, 0x73, 0x87, 0xf0, 0x03, 0x0b, 0x88, 0xf0, 0x03, 0xd2, 0x3f,
+ 0xec, 0x60, 0x42, 0xbd, 0xe0, 0x53, 0xcf, 0x65, 0x72, 0x73, 0x61, 0xec,
+ 0xe0, 0x89, 0xcb, 0x61, 0x62, 0x61, 0x73, 0x65, 0xae, 0x06, 0x60, 0x7f,
+ 0xa7, 0xd8, 0xdf, 0xe9, 0xe0, 0x84, 0x62, 0xee, 0x07, 0x60, 0x45, 0x40,
+ 0xe0, 0x4f, 0x3b, 0xee, 0x04, 0xe0, 0x91, 0x7c, 0x79, 0x64, 0xe1, 0xe0,
+ 0x8f, 0xe2, 0xed, 0x05, 0x10, 0xe0, 0x7d, 0x73, 0xef, 0x02, 0x88, 0x74,
+ 0x6f, 0xae, 0x60, 0x91, 0x34, 0xc2, 0x7a, 0x6d, 0xef, 0xe0, 0x5f, 0x98,
+ 0xe9, 0x51, 0x3f, 0xe0, 0x25, 0xa1, 0xec, 0x06, 0x60, 0x91, 0x53, 0xc0,
+ 0xf4, 0xe9, 0xe0, 0x97, 0x6c, 0xeb, 0x02, 0x85, 0x75, 0xed, 0xe0, 0x55,
+ 0xff, 0xe1, 0xcc, 0x85, 0xe9, 0x04, 0xe0, 0x55, 0x58, 0x66, 0xf5, 0xe0,
+ 0x90, 0xc7, 0x67, 0xe9, 0x04, 0xe0, 0x44, 0xfd, 0x6e, 0x61, 0xed, 0xe0,
+ 0x95, 0x05, 0xe5, 0x60, 0x81, 0x36, 0xc7, 0x81, 0x63, 0xeb, 0xe0, 0x95,
+ 0xd9, 0xe2, 0xe0, 0x97, 0x43, 0x2e, 0x70, 0x61, 0xe2, 0xe0, 0x97, 0xcf,
+ 0xf4, 0x13, 0x40, 0x5b, 0x23, 0x40, 0x66, 0x18, 0x08, 0x0c, 0x0c, 0x07,
+ 0x60, 0x38, 0x7b, 0x60, 0x5c, 0xed, 0xc1, 0x95, 0xf5, 0x02, 0x96, 0x66,
+ 0xe6, 0x02, 0x88, 0x74, 0x6f, 0x72, 0x65, 0xe1, 0xe0, 0x92, 0xba, 0x2d,
+ 0x34, 0x2d, 0x73, 0x61, 0x6c, 0xe5, 0xe0, 0x63, 0x3a, 0xe4, 0x06, 0x60,
+ 0x90, 0x43, 0xc5, 0x86, 0x69, 0xef, 0x05, 0x28, 0xe0, 0x97, 0xd1, 0xae,
+ 0x09, 0x09, 0x60, 0x22, 0x8b, 0x0b, 0x05, 0x06, 0xa4, 0x65, 0x75, 0xad,
+ 0x60, 0x22, 0xb2, 0x0b, 0x2f, 0xb6, 0xe1, 0x04, 0xe0, 0x23, 0x15, 0x70,
+ 0xad, 0x05, 0x60, 0x22, 0xff, 0xb2, 0x73, 0x6f, 0x75, 0x74, 0xe8, 0x60,
+ 0x22, 0xff, 0xb1, 0x2d, 0x66, 0x69, 0x70, 0x73, 0x2e, 0x75, 0x73, 0xad,
+ 0xe0, 0x23, 0x16, 0xf2, 0x04, 0x04, 0x03, 0x8f, 0xf9, 0xe0, 0x91, 0x8a,
+ 0xe9, 0xd8, 0xa8, 0x65, 0x61, 0xed, 0x04, 0xe0, 0x97, 0xb2, 0x6c, 0x69,
+ 0xf4, 0x60, 0x96, 0x39, 0xc0, 0x89, 0x61, 0x6e, 0xe4, 0x60, 0x91, 0x7f,
+ 0xc4, 0x93, 0xef, 0x05, 0x40, 0x50, 0x04, 0x84, 0xf2, 0x09, 0x08, 0x09,
+ 0x18, 0x06, 0x11, 0xe0, 0x87, 0xac, 0x6a, 0x2e, 0x66, 0x61, 0xf2, 0xe0,
+ 0x97, 0x88, 0x69, 0x70, 0x72, 0x65, 0x73, 0xf3, 0xe0, 0x96, 0x0e, 0xe5,
+ 0x05, 0x05, 0xe0, 0x97, 0x76, 0x62, 0x61, 0xf3, 0xc4, 0x96, 0xae, 0x60,
+ 0x84, 0x72, 0x46, 0x2b, 0x41, 0xeb, 0x03, 0x49, 0x5e, 0xc1, 0x53, 0xe4,
+ 0x60, 0x90, 0x4d, 0xc5, 0x86, 0x61, 0x67, 0xe5, 0x04, 0xe0, 0x97, 0x5c,
+ 0x2e, 0x79, 0x61, 0x6e, 0x64, 0x65, 0xf8, 0xe0, 0x47, 0x2f, 0x2d, 0x65,
+ 0xec, 0xe0, 0x90, 0x32, 0x6c, 0xef, 0xde, 0x02, 0xeb, 0xe0, 0x66, 0x1c,
+ 0x63, 0x6b, 0x68, 0x6f, 0xec, 0xe0, 0x94, 0xed, 0xea, 0x02, 0x84, 0x1f,
+ 0x43, 0xf8, 0x82, 0x6f, 0x72, 0x64, 0x61, 0xec, 0x04, 0xe0, 0x95, 0x97,
+ 0x73, 0x68, 0x61, 0x6c, 0xf3, 0xe0, 0x87, 0xab, 0x68, 0x2e, 0x61, 0x63,
+ 0xae, 0xe0, 0x4f, 0x1f, 0xe7, 0x07, 0x60, 0x39, 0xac, 0xe0, 0x24, 0xdc,
+ 0xad, 0xe0, 0x71, 0x2a, 0x65, 0xe9, 0x04, 0xe0, 0x87, 0x8d, 0x6e, 0x6b,
+ 0xea, 0xe0, 0x8b, 0x5e, 0xe3, 0x60, 0x3b, 0xdf, 0xe0, 0x5b, 0x24, 0xe1,
+ 0x0c, 0x09, 0x3b, 0x18, 0x04, 0x03, 0x08, 0x18, 0x0d, 0xe0, 0x8a, 0xef,
+ 0xf6, 0x04, 0xe0, 0x80, 0xd8, 0xe5, 0xe0, 0x85, 0x37, 0xf4, 0x06, 0x23,
+ 0x06, 0xe0, 0x95, 0x22, 0x69, 0xe3, 0x03, 0x04, 0x91, 0xf3, 0xe0, 0x87,
+ 0x07, 0xae, 0x04, 0xe0, 0x70, 0xd0, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76,
+ 0x61, 0x62, 0xec, 0xe0, 0x4c, 0x08, 0x2d, 0x61, 0x63, 0x63, 0x65, 0xf3,
+ 0xe0, 0x96, 0x9b, 0x68, 0x65, 0xec, 0xe0, 0x87, 0x04, 0xe5, 0x04, 0xe0,
+ 0x75, 0xb3, 0x66, 0x61, 0xf2, 0xe0, 0x94, 0x5d, 0xf2, 0x06, 0x08, 0x06,
+ 0xe0, 0x96, 0x97, 0x6f, 0x73, 0x74, 0x77, 0xef, 0xe0, 0x59, 0x76, 0x67,
+ 0x61, 0xf2, 0xe0, 0x91, 0xde, 0xe1, 0xd3, 0xf2, 0xf0, 0xe0, 0x2c, 0xaa,
+ 0xee, 0xcd, 0xe3, 0x6c, 0x6f, 0x77, 0x61, 0xad, 0xe0, 0x3d, 0x5f, 0xe7,
+ 0x02, 0x8a, 0x69, 0x6e, 0x67, 0x2e, 0x6f, 0x6e, 0x72, 0xe5, 0xdc, 0x8d,
+ 0x65, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x61, 0xf2, 0xe0, 0x83, 0x84, 0x63,
+ 0x6b, 0x68, 0x65, 0x72, 0x6f, 0x2d, 0x6e, 0x65, 0xf4, 0xe0, 0x6d, 0x0e,
+ 0xe2, 0xe0, 0x86, 0xae, 0xf3, 0x06, 0x60, 0x94, 0x52, 0xc2, 0x03, 0x6c,
0x2e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2e, 0x63, 0x64, 0x6e, 0x37,
- 0x37, 0x2d, 0x73, 0x65, 0x63, 0xf5, 0xe0, 0x86, 0xe7, 0xf2, 0x09, 0x56,
- 0x16, 0x60, 0x83, 0x87, 0x0b, 0xc2, 0x3d, 0x68, 0xf4, 0xe0, 0x84, 0x73,
- 0x71, 0x75, 0x61, 0x72, 0xe5, 0x04, 0xe0, 0x99, 0x1e, 0x37, 0xae, 0x60,
- 0x9b, 0x27, 0x0e, 0xc0, 0x7d, 0xf0, 0x0b, 0x0a, 0x0c, 0x08, 0x06, 0x09,
- 0x0b, 0x04, 0xe0, 0x8d, 0x1b, 0xf9, 0x04, 0xe0, 0x99, 0x05, 0x64, 0xe5,
- 0xe0, 0x6d, 0x35, 0xef, 0x04, 0xe0, 0x99, 0xfd, 0x72, 0xf4, 0x60, 0x9a,
- 0xbd, 0xc0, 0xf5, 0x6a, 0x65, 0x6c, 0x6b, 0xe1, 0xe0, 0x60, 0xfb, 0x68,
- 0x69, 0xee, 0xe0, 0x36, 0x86, 0x65, 0x63, 0x74, 0x72, 0x75, 0xed, 0xe0,
- 0x3b, 0x2e, 0x64, 0x6e, 0x73, 0xae, 0x60, 0x96, 0x9d, 0x42, 0x24, 0xc2,
- 0x31, 0xe2, 0xe0, 0x97, 0xff, 0xe1, 0x04, 0xe0, 0x9b, 0x82, 0x63, 0xe5,
- 0x07, 0x04, 0x60, 0x98, 0xbc, 0xc2, 0xb9, 0xeb, 0xe0, 0x6d, 0x36, 0x2d,
- 0x74, 0x6f, 0x2d, 0xf2, 0xe0, 0x91, 0xc9, 0xef, 0x1e, 0x26, 0x0d, 0x25,
- 0x06, 0x1a, 0x06, 0x19, 0x07, 0x04, 0x07, 0x0c, 0x05, 0x07, 0x4a, 0x44,
- 0x4a, 0x7a, 0x60, 0x2b, 0x59, 0x60, 0x55, 0xe8, 0x42, 0x5e, 0x41, 0x3c,
- 0xc0, 0xf4, 0xf5, 0x02, 0x91, 0x74, 0xe8, 0x02, 0x85, 0x77, 0xe5, 0xe0,
- 0x85, 0x07, 0x63, 0x61, 0x72, 0x6f, 0x6c, 0xe9, 0xd8, 0x12, 0x6e, 0xe4,
- 0x02, 0x85, 0x63, 0xe1, 0xe0, 0x22, 0x81, 0x61, 0x6e, 0x64, 0x76, 0x69,
- 0xf3, 0xe0, 0x90, 0x77, 0xf3, 0x07, 0x60, 0x58, 0xb7, 0xe0, 0x3d, 0xd9,
- 0x6e, 0xef, 0xe0, 0x86, 0x00, 0xf2, 0x09, 0x04, 0x05, 0x05, 0x4a, 0x33,
- 0xe0, 0x79, 0x0f, 0xf4, 0xe0, 0x8e, 0x40, 0x72, 0xe5, 0xe0, 0x21, 0xbe,
- 0x6f, 0xe3, 0xe0, 0x76, 0x77, 0xad, 0x06, 0x60, 0x21, 0xcb, 0x04, 0x86,
- 0x76, 0x61, 0xf2, 0xe0, 0x84, 0xee, 0x70, 0x6f, 0xf4, 0xe0, 0x89, 0x9c,
- 0xee, 0x08, 0x07, 0x60, 0x57, 0x26, 0xe0, 0x41, 0x8a, 0xe7, 0x60, 0x2e,
- 0x2c, 0xe0, 0x6c, 0xba, 0x64, 0xf2, 0x04, 0xe0, 0x82, 0x38, 0xe5, 0xe0,
- 0x21, 0x90, 0xed, 0x60, 0x8f, 0x9e, 0xc0, 0xb5, 0xec, 0x03, 0x0b, 0x85,
- 0xf5, 0x04, 0xe0, 0x94, 0x77, 0x74, 0x69, 0xef, 0xe0, 0x8b, 0x23, 0x6f,
- 0xe7, 0xe0, 0x36, 0x0b, 0xe1, 0x60, 0x99, 0x34, 0xbd, 0xeb, 0x60, 0x61,
- 0xa8, 0xe0, 0x2e, 0xc1, 0xea, 0xe0, 0x95, 0x12, 0x67, 0xee, 0x60, 0x93,
- 0xce, 0xc5, 0x54, 0x66, 0xf4, 0x04, 0xe0, 0x78, 0x7a, 0x77, 0x61, 0xf2,
- 0xe0, 0x68, 0xed, 0x65, 0xe4, 0xe0, 0x58, 0xc7, 0x64, 0x65, 0x67, 0xe1,
- 0xe0, 0x42, 0x25, 0xe3, 0x04, 0x06, 0x04, 0x84, 0xe9, 0x60, 0x54, 0x69,
- 0xde, 0x70, 0xe8, 0xe0, 0x26, 0x0d, 0xe3, 0xe0, 0x87, 0x0f, 0xae, 0x05,
- 0x60, 0x8e, 0x92, 0x88, 0x73, 0x72, 0xe3, 0xc1, 0x4f, 0xee, 0x0a, 0x07,
- 0x05, 0x06, 0x04, 0x60, 0x87, 0x11, 0xd3, 0x3d, 0x1f, 0x43, 0xe5, 0x18,
- 0xe0, 0x5f, 0xcd, 0x6f, 0xe1, 0xe0, 0x5f, 0xdf, 0x69, 0x6c, 0xec, 0xe0,
- 0x8b, 0x2a, 0xe3, 0xe0, 0x8f, 0x87, 0xe1, 0x04, 0xe0, 0x5f, 0xcd, 0x61,
- 0xf3, 0xe0, 0x98, 0xbf, 0xed, 0x0a, 0x05, 0x06, 0x03, 0x04, 0x60, 0x7e,
- 0x97, 0xdb, 0x90, 0x1f, 0x43, 0xf8, 0xd8, 0xf0, 0x75, 0x73, 0xe8, 0xe0,
- 0x4e, 0xfe, 0xef, 0xd8, 0xe7, 0xe9, 0xe0, 0x98, 0x3e, 0xe1, 0x02, 0x91,
- 0x72, 0xf4, 0x04, 0xe0, 0x9a, 0x1e, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x69,
- 0x6e, 0xe7, 0xe0, 0x64, 0xcd, 0x6c, 0x6c, 0x2d, 0x77, 0x65, 0xe2, 0xe0,
- 0x97, 0x3b, 0xec, 0x0c, 0x05, 0x06, 0x60, 0x7a, 0x55, 0x4a, 0x4d, 0x43,
- 0x29, 0xd2, 0x27, 0x75, 0xf0, 0xe0, 0x38, 0x46, 0x64, 0xae, 0x60, 0x98,
- 0x03, 0x84, 0xe1, 0x04, 0xe0, 0x38, 0x38, 0x74, 0xf4, 0xe0, 0x82, 0x2a,
- 0xeb, 0x0c, 0x0d, 0x15, 0x10, 0x04, 0x14, 0x22, 0x10, 0x10, 0xe0, 0x99,
- 0x4f, 0x1f, 0xc3, 0x02, 0x85, 0x65, 0xee, 0xe0, 0x8d, 0x05, 0x61, 0xee,
- 0xc0, 0x7d, 0xf9, 0x08, 0x06, 0x60, 0x5a, 0x17, 0xe0, 0x3f, 0xa8, 0x67,
- 0x65, 0xe1, 0xe0, 0x68, 0xa0, 0x64, 0x69, 0xf6, 0xe0, 0x8a, 0xb3, 0xef,
- 0x08, 0x04, 0x60, 0x59, 0xfd, 0xe0, 0x26, 0x23, 0xe4, 0xe0, 0x66, 0xb7,
- 0xe3, 0xcb, 0xac, 0x6c, 0xe5, 0xd9, 0x14, 0xea, 0x05, 0x06, 0xe0, 0x6f,
- 0x10, 0x1f, 0x43, 0xe5, 0xe0, 0x8f, 0x55, 0x65, 0x72, 0xf6, 0x60, 0x8d,
- 0xf1, 0xc3, 0x78, 0xe9, 0x08, 0x06, 0x0d, 0x60, 0x98, 0x4a, 0xc1, 0x2b,
- 0x70, 0x74, 0xf6, 0xe0, 0x51, 0x0b, 0xe5, 0x04, 0xe0, 0x93, 0x9a, 0x72,
- 0xf6, 0x60, 0x58, 0x60, 0xe0, 0x3b, 0x45, 0xae, 0x60, 0x96, 0xbc, 0xc1,
- 0x32, 0x65, 0x64, 0x73, 0x6d, 0xef, 0x04, 0xe0, 0x97, 0xdf, 0x6b, 0x6f,
- 0x72, 0xf3, 0xe0, 0x50, 0xe8, 0xe1, 0x02, 0x84, 0xf5, 0xe0, 0x93, 0x78,
- 0xee, 0x04, 0xe0, 0x8c, 0x83, 0xe9, 0xe0, 0x91, 0xd2, 0xae, 0x60, 0x93,
- 0x43, 0xc4, 0x71, 0xea, 0x60, 0x68, 0x76, 0xe0, 0x30, 0xd2, 0xe9, 0x0f,
- 0x29, 0x09, 0x0e, 0x1b, 0x0d, 0x03, 0x04, 0x0a, 0x0c, 0x60, 0x86, 0x92,
- 0xd2, 0x1b, 0x74, 0xe5, 0x06, 0x05, 0x07, 0xe0, 0x99, 0x1e, 0x73, 0xae,
- 0xe0, 0x71, 0x0d, 0x6c, 0x65, 0x61, 0xe6, 0xe0, 0x98, 0xfd, 0x2e, 0xf4,
- 0x02, 0x88, 0x72, 0x61, 0x6e, 0x73, 0xe9, 0xe0, 0x65, 0x5b, 0x62, 0x2d,
- 0x68, 0x6f, 0x73, 0xf4, 0xe0, 0x8b, 0xfa, 0xf2, 0x04, 0xe0, 0x92, 0x28,
- 0x61, 0xe3, 0xcf, 0x08, 0xee, 0x02, 0x85, 0x67, 0xec, 0xe0, 0x8c, 0xfe,
- 0xe1, 0x60, 0x98, 0x0f, 0xc0, 0xe8, 0x6d, 0x70, 0x6c, 0xe5, 0x04, 0xe0,
- 0x24, 0x20, 0x73, 0x69, 0x74, 0x65, 0xae, 0x06, 0x60, 0x84, 0xd4, 0xc9,
- 0x7e, 0x63, 0x6f, 0xed, 0x60, 0x96, 0x82, 0xc2, 0x56, 0xec, 0x02, 0x86,
- 0xeb, 0x60, 0x96, 0x1a, 0xc2, 0xb9, 0xea, 0xe0, 0x25, 0x8e, 0xe9, 0xd8,
- 0xb8, 0xe7, 0xe0, 0x91, 0xea, 0xe5, 0x04, 0xe0, 0x90, 0xed, 0x6c, 0xec,
- 0xe0, 0x6e, 0x33, 0xe3, 0x04, 0xe0, 0x96, 0xb8, 0x69, 0xec, 0x60, 0x90,
- 0x06, 0xc2, 0x64, 0x62, 0x65, 0x6e, 0xe9, 0xe0, 0x90, 0x52, 0xe8, 0x0d,
- 0x04, 0x07, 0x40, 0x70, 0x42, 0x07, 0x0e, 0x60, 0x82, 0xcb, 0xd3, 0x3d,
- 0xf7, 0xe0, 0x97, 0x9c, 0x75, 0x6e, 0x61, 0xee, 0xe0, 0x96, 0x81, 0xef,
- 0x0b, 0x16, 0x05, 0x3a, 0x09, 0x60, 0x42, 0x5c, 0xe0, 0x49, 0xca, 0xf7,
- 0x07, 0x05, 0x60, 0x95, 0x95, 0xc2, 0xdf, 0x74, 0xe9, 0xe0, 0x7b, 0x92,
- 0x61, 0xae, 0x60, 0x7b, 0x68, 0x54, 0xba, 0xc3, 0x06, 0x75, 0xea, 0xe0,
- 0x96, 0x57, 0xf0, 0x09, 0x06, 0x06, 0x04, 0x05, 0x06, 0xe0, 0x98, 0x41,
- 0x77, 0x61, 0x72, 0xe5, 0xc3, 0xe9, 0x73, 0x65, 0xec, 0xe0, 0x27, 0xfe,
- 0xf0, 0xe0, 0x82, 0xff, 0x69, 0x74, 0xf3, 0xd9, 0x91, 0x61, 0x72, 0xe5,
- 0xe0, 0x36, 0xf7, 0xae, 0x0b, 0x60, 0x4b, 0x84, 0x44, 0x17, 0x60, 0x38,
- 0x93, 0xcb, 0xa8, 0x62, 0x72, 0x65, 0x6e, 0x64, 0x6c, 0xf9, 0xd6, 0xaa,
- 0x6e, 0x61, 0x69, 0xae, 0x60, 0x8c, 0xa5, 0xc0, 0x65, 0x62, 0x61, 0xf2,
- 0xe0, 0x72, 0x27, 0xe9, 0x18, 0x12, 0x05, 0x11, 0x40, 0x4b, 0x13, 0x40,
- 0x6e, 0x40, 0x7a, 0x29, 0x0b, 0x05, 0x16, 0x0f, 0x60, 0x29, 0xa3, 0x60,
- 0x67, 0x68, 0xc3, 0x94, 0x7a, 0xf5, 0x02, 0x89, 0x6f, 0x6b, 0x61, 0xae,
- 0x60, 0x8d, 0xff, 0xc8, 0x5b, 0x6b, 0xf5, 0xe0, 0x41, 0x9f, 0x74, 0xe1,
- 0xe0, 0x52, 0xbb, 0xf3, 0x05, 0x04, 0xe0, 0x92, 0x03, 0xf5, 0xe0, 0x7b,
- 0x29, 0x68, 0x69, 0x6b, 0xf5, 0xe0, 0x28, 0xd8, 0xf2, 0x03, 0x18, 0x84,
- 0xef, 0x02, 0x86, 0x73, 0x61, 0xf4, 0xe0, 0x88, 0x73, 0xe9, 0x04, 0xe0,
- 0x95, 0xf3, 0x73, 0x68, 0x69, 0xae, 0x60, 0x5e, 0x0a, 0xe0, 0x2f, 0x66,
- 0xe9, 0xe0, 0x3e, 0x4a, 0xe1, 0x05, 0x06, 0x09, 0x04, 0x8e, 0x74, 0x61,
- 0xeb, 0xe0, 0x5e, 0x4a, 0xef, 0x04, 0xe0, 0x95, 0xfe, 0xeb, 0xe0, 0x5e,
- 0x9c, 0xee, 0xe0, 0x85, 0x35, 0xeb, 0x04, 0xe0, 0x95, 0xc6, 0x61, 0x77,
- 0x61, 0xae, 0x60, 0x8f, 0x34, 0xc3, 0x1c, 0xe8, 0xe0, 0x3c, 0x56, 0xef,
- 0x03, 0x04, 0x86, 0xf9, 0xe0, 0x8c, 0x11, 0x6a, 0x69, 0xf2, 0xe0, 0x94,
- 0x6f, 0x67, 0xe1, 0xe0, 0x52, 0x9a, 0xee, 0x0b, 0x0b, 0x0d, 0x0e, 0x06,
- 0x08, 0x11, 0x10, 0xe0, 0x53, 0xf8, 0x79, 0x6f, 0x73, 0x68, 0x69, 0x74,
- 0x6f, 0xed, 0xe0, 0x4b, 0xa3, 0x74, 0xef, 0x07, 0x60, 0x3e, 0x80, 0xe0,
- 0x50, 0x8d, 0xeb, 0xe0, 0x92, 0xd3, 0x73, 0x68, 0xe9, 0x02, 0x84, 0xf2,
- 0xe0, 0x8f, 0x15, 0x6e, 0xef, 0xe0, 0x92, 0xc3, 0x6f, 0x6e, 0x73, 0xe5,
- 0xc6, 0x0e, 0x6b, 0x61, 0x6d, 0x69, 0x67, 0xef, 0xd6, 0xdd, 0xea, 0x02,
- 0x85, 0x75, 0xeb, 0xe0, 0x7a, 0x85, 0x6f, 0xae, 0x60, 0x8c, 0x16, 0x43,
- 0x3a, 0xc2, 0x49, 0xe7, 0x02, 0x89, 0x75, 0xae, 0x60, 0x8b, 0xa5, 0x41,
- 0x25, 0xc5, 0xb1, 0xef, 0xe0, 0x59, 0x76, 0xe1, 0x04, 0xe0, 0x69, 0xff,
- 0x6e, 0x6f, 0x6d, 0x61, 0xe3, 0xe0, 0x93, 0xfb, 0xed, 0x04, 0x40, 0x4a,
- 0x89, 0xef, 0x0b, 0x0a, 0x03, 0x0f, 0x07, 0x04, 0x06, 0x06, 0xe0, 0x23,
- 0x6e, 0x74, 0x73, 0xf5, 0x03, 0xd9, 0x98, 0xeb, 0xe0, 0x44, 0xec, 0xf3,
- 0xd8, 0x76, 0xee, 0x02, 0x87, 0x6f, 0x73, 0x65, 0xeb, 0xe0, 0x55, 0x2f,
- 0x69, 0xf4, 0xe0, 0x8e, 0x94, 0xeb, 0x60, 0x40, 0x3b, 0xe0, 0x4b, 0x7b,
- 0xea, 0xe0, 0x92, 0x68, 0x69, 0x63, 0xe8, 0xe0, 0x53, 0x1b, 0x66, 0x75,
- 0xf3, 0xe0, 0x54, 0x66, 0x64, 0xe1, 0x04, 0xe0, 0x8c, 0xc8, 0x74, 0xe5,
- 0xe0, 0x8f, 0x4f, 0x69, 0x7a, 0x75, 0xae, 0x60, 0x8c, 0xc0, 0xc8, 0x52,
- 0xe1, 0x08, 0x08, 0x0c, 0x60, 0x4a, 0xf2, 0xd3, 0x0b, 0x6e, 0x65, 0xae,
- 0x60, 0x91, 0x1b, 0xc3, 0xef, 0xed, 0x02, 0x84, 0xef, 0xe0, 0x70, 0xad,
- 0x61, 0xeb, 0xe0, 0x94, 0xf1, 0x62, 0xe1, 0xe0, 0x2f, 0x40, 0xeb, 0x06,
- 0x05, 0x09, 0xe0, 0x44, 0x4a, 0x73, 0xe8, 0xe0, 0x94, 0xf4, 0x6f, 0x6b,
- 0x75, 0x63, 0x68, 0xf5, 0xe0, 0x44, 0x32, 0xe1, 0x0a, 0x05, 0x60, 0x4e,
- 0x83, 0x43, 0x07, 0xe0, 0x3d, 0x2c, 0x74, 0xf3, 0xe0, 0x79, 0xfd, 0xef,
- 0xe0, 0x94, 0xc3, 0x6a, 0x6f, 0x6e, 0x61, 0x77, 0x61, 0x74, 0xe5, 0xe0,
- 0x94, 0x97, 0x69, 0xe2, 0xe0, 0x4d, 0x54, 0x66, 0xf4, 0x02, 0x85, 0x65,
- 0xe4, 0xe0, 0x68, 0x15, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0xae, 0x60,
- 0x71, 0x8d, 0xe0, 0x23, 0xc6, 0x63, 0x68, 0xe9, 0x04, 0xe0, 0x54, 0xb7,
- 0x6b, 0x61, 0x73, 0x68, 0xf5, 0xe0, 0x2b, 0x2c, 0xe2, 0x03, 0x0a, 0x8a,
- 0xf5, 0x03, 0xc0, 0x9e, 0x6b, 0x61, 0xf7, 0xe0, 0x8d, 0xdb, 0xe5, 0x04,
- 0xe0, 0x91, 0x99, 0x63, 0xe8, 0xe0, 0x94, 0x48, 0x61, 0x74, 0x61, 0xae,
- 0x60, 0x5c, 0x60, 0xe0, 0x35, 0xa3, 0xe5, 0x04, 0xe0, 0x85, 0xa1, 0x72,
- 0x62, 0x72, 0x6f, 0x6f, 0xeb, 0xe0, 0x91, 0xc5, 0xe1, 0x07, 0x05, 0x07,
- 0x06, 0xe0, 0x93, 0x85, 0xf2, 0x60, 0x94, 0x52, 0x9e, 0x6e, 0x67, 0x72,
- 0xe9, 0xe0, 0x71, 0x64, 0x6b, 0x6f, 0xf4, 0xe0, 0x36, 0xc9, 0x63, 0x6b,
- 0x6e, 0x65, 0xf4, 0xe0, 0x66, 0x14, 0xe7, 0x04, 0xe0, 0x95, 0xe1, 0xad,
- 0xe0, 0x5f, 0x88, 0xe6, 0x60, 0x94, 0x55, 0xbd, 0xe5, 0x19, 0x0d, 0x06,
- 0x1d, 0x40, 0xb7, 0x06, 0x25, 0x0f, 0x40, 0x4a, 0x1b, 0x04, 0x1a, 0x04,
- 0x25, 0x0b, 0x08, 0x60, 0x74, 0x41, 0x5d, 0x34, 0xc2, 0x69, 0xf8, 0x06,
- 0x60, 0x93, 0x87, 0xc2, 0x30, 0xae, 0x60, 0x91, 0x57, 0xc3, 0x6b, 0xf6,
- 0x41, 0xc0, 0xe0, 0x54, 0x58, 0xf4, 0x03, 0x0c, 0x86, 0xf4, 0x04, 0xe0,
- 0x43, 0x40, 0x6c, 0xe5, 0x60, 0x60, 0xf3, 0xc2, 0x41, 0xef, 0x60, 0x8a,
- 0x59, 0xc6, 0x19, 0x61, 0x67, 0x61, 0xf9, 0xe0, 0x8f, 0xd8, 0xf2, 0x03,
- 0xc0, 0xa8, 0xf6, 0x02, 0x99, 0x69, 0x63, 0xe5, 0x04, 0xe0, 0x63, 0x9f,
- 0xae, 0x04, 0xe0, 0x76, 0xd5, 0x67, 0x6f, 0x76, 0xae, 0x04, 0xe0, 0x92,
- 0x23, 0x73, 0xe3, 0xe0, 0x67, 0x99, 0xe5, 0x0c, 0x09, 0x05, 0x05, 0x09,
- 0x12, 0x05, 0x18, 0x06, 0x06, 0x0a, 0x8f, 0x73, 0x61, 0x72, 0x63, 0x61,
- 0xf3, 0xe0, 0x8c, 0x0e, 0x72, 0xf3, 0xe0, 0x6d, 0x1e, 0x71, 0x75, 0xe1,
- 0xc0, 0x5b, 0xf0, 0x04, 0xe0, 0x69, 0xc3, 0xb2, 0xe0, 0x94, 0x62, 0xed,
- 0x02, 0x85, 0x70, 0xb3, 0xe0, 0x95, 0x38, 0x69, 0x6e, 0x65, 0x63, 0x72,
- 0x61, 0xe6, 0xe0, 0x88, 0xce, 0x69, 0xf2, 0xe0, 0x6d, 0xb1, 0xe8, 0x03,
- 0x06, 0x85, 0x75, 0x6d, 0xef, 0xe0, 0x6a, 0x13, 0x74, 0xf4, 0xe0, 0x94,
- 0x3c, 0x61, 0x6c, 0x66, 0x6c, 0x69, 0xe6, 0xe0, 0x8d, 0x95, 0x67, 0x61,
- 0xed, 0xe0, 0x4e, 0x37, 0x66, 0x74, 0xf0, 0xe0, 0x81, 0x81, 0x65, 0x78,
- 0x63, 0x68, 0x61, 0x6e, 0xe7, 0xe0, 0x8d, 0x7f, 0x63, 0x6f, 0x75, 0x6e,
- 0x74, 0x65, 0x72, 0x73, 0x74, 0x72, 0x69, 0xeb, 0xe0, 0x8d, 0x70, 0xe2,
- 0x05, 0x05, 0xe0, 0x45, 0x02, 0x6c, 0xef, 0xe0, 0x76, 0xc7, 0xe2, 0xe0,
- 0x81, 0x58, 0xe1, 0x04, 0xe0, 0x89, 0x93, 0x6e, 0x69, 0xf3, 0xe0, 0x51,
- 0xb7, 0x6f, 0x75, 0xec, 0xe0, 0x7d, 0xac, 0xee, 0x07, 0x0d, 0x04, 0x06,
- 0xe0, 0x81, 0x44, 0xf3, 0x02, 0x84, 0xe9, 0xe0, 0x2f, 0x1d, 0x65, 0x65,
- 0xf2, 0xe0, 0x76, 0x9b, 0xee, 0xe0, 0x52, 0x21, 0x64, 0x61, 0xe9, 0xe0,
- 0x39, 0xa5, 0x61, 0x73, 0xe1, 0xe0, 0x82, 0xd2, 0xed, 0x02, 0x86, 0x69,
- 0x6e, 0xe5, 0xe0, 0x5a, 0xe9, 0x62, 0x6f, 0xeb, 0xe0, 0x51, 0xf0, 0xec,
- 0x0a, 0x2b, 0x06, 0x5d, 0xfe, 0x60, 0x6e, 0x85, 0xc6, 0x57, 0xec, 0x02,
- 0x9e, 0xf3, 0x02, 0x8a, 0x79, 0x6f, 0x75, 0x72, 0x68, 0x6f, 0xed, 0xe0,
- 0x7f, 0x7b, 0xad, 0x04, 0xe0, 0x7e, 0x33, 0x66, 0x6f, 0x72, 0xad, 0x04,
- 0xe0, 0x93, 0x52, 0xec, 0xe0, 0x44, 0xa6, 0x66, 0x79, 0x2e, 0x73, 0x74,
- 0x6f, 0xf2, 0xe0, 0x94, 0x05, 0xea, 0x60, 0x90, 0x71, 0xc2, 0x6d, 0x66,
- 0x69, 0x70, 0xae, 0x60, 0x84, 0x9d, 0x4c, 0x99, 0x40, 0x56, 0x42, 0xae,
- 0x9c, 0xeb, 0x02, 0x8c, 0xe9, 0x07, 0x60, 0x3e, 0x2e, 0xe0, 0x4d, 0xb3,
- 0xeb, 0xe0, 0x42, 0x7e, 0x64, 0x31, 0x2e, 0x62, 0x65, 0x65, 0x62, 0x79,
- 0xf4, 0xe0, 0x85, 0xa6, 0xea, 0xe0, 0x3b, 0x01, 0xe9, 0x08, 0x08, 0x04,
- 0x60, 0x3d, 0xbe, 0xc4, 0x0e, 0x72, 0xef, 0x60, 0x3f, 0xe4, 0xe0, 0x50,
- 0x2b, 0xe8, 0xe0, 0x51, 0x46, 0x64, 0xe1, 0xe0, 0x87, 0xb5, 0xe5, 0xe0,
- 0x91, 0xba, 0xe3, 0x05, 0x14, 0x05, 0xce, 0x65, 0x75, 0xf2, 0x04, 0xe0,
- 0x92, 0x9c, 0x69, 0x74, 0xf9, 0x04, 0xe0, 0x94, 0x03, 0x74, 0x61, 0x63,
- 0xf4, 0xe0, 0x68, 0x79, 0x72, 0xe5, 0xe0, 0x7c, 0xbb, 0x61, 0x61, 0xf3,
- 0xe0, 0x48, 0x0c, 0x62, 0x61, 0x73, 0x74, 0x6f, 0x70, 0x6f, 0xec, 0xe0,
- 0x78, 0x59, 0xe1, 0x5d, 0xa2, 0x60, 0x59, 0x2c, 0xdb, 0x60, 0xae, 0x60,
- 0x8d, 0xcc, 0x03, 0x03, 0xc5, 0xe8, 0xe4, 0x08, 0x09, 0x60, 0x4f, 0x4e,
- 0xe0, 0x44, 0x76, 0x73, 0x63, 0x6c, 0x6f, 0x75, 0xe4, 0xe0, 0x82, 0x70,
- 0xee, 0xe0, 0x54, 0x14, 0xe3, 0x0d, 0x1d, 0x08, 0x40, 0x4a, 0x40, 0xb3,
- 0x0e, 0x60, 0x88, 0x8d, 0xc9, 0xf5, 0xf2, 0x02, 0x86, 0x79, 0x73, 0xe5,
- 0xe0, 0x6c, 0x2c, 0x61, 0x70, 0xf0, 0x02, 0x86, 0x69, 0x6e, 0xe7, 0xe0,
- 0x6f, 0x20, 0x65, 0x72, 0x2d, 0x73, 0x69, 0xf4, 0xe0, 0x85, 0xaa, 0x6f,
- 0xf4, 0x60, 0x63, 0xdf, 0xe0, 0x2f, 0xb4, 0xe9, 0x04, 0xe0, 0x62, 0x3e,
- 0x65, 0xee, 0x02, 0x86, 0x74, 0x69, 0xf3, 0xe0, 0x8e, 0xa4, 0x63, 0xe5,
- 0x0b, 0x0d, 0x0b, 0x10, 0x60, 0x70, 0xbf, 0x5f, 0xd1, 0xc2, 0xb9, 0xf3,
- 0x04, 0xe0, 0x90, 0xb3, 0x6e, 0x61, 0x74, 0x75, 0xf2, 0xe0, 0x7c, 0xd8,
- 0x63, 0x65, 0x6e, 0x74, 0x65, 0xf2, 0x60, 0x8c, 0x24, 0xc4, 0x81, 0x61,
- 0x6e, 0xe4, 0x04, 0xe0, 0x70, 0xc8, 0x69, 0x6e, 0x64, 0x75, 0x73, 0xf4,
- 0xe0, 0x88, 0x8a, 0x2d, 0x66, 0xe9, 0xe0, 0x72, 0x77, 0xe8, 0x08, 0x0d,
- 0x15, 0x40, 0x44, 0x06, 0x06, 0x88, 0xf7, 0x02, 0x85, 0x65, 0xe9, 0xe0,
- 0x84, 0x7c, 0x61, 0xf2, 0xe0, 0x90, 0xc4, 0x75, 0xec, 0x07, 0x60, 0x67,
- 0xf2, 0xe0, 0x29, 0xc4, 0x70, 0x6c, 0x61, 0x74, 0x74, 0x66, 0x6f, 0x72,
- 0xed, 0xe0, 0x6e, 0x06, 0xef, 0x04, 0x21, 0x07, 0x8e, 0x6f, 0xec, 0x06,
- 0x08, 0x04, 0xe0, 0x92, 0xff, 0x73, 0x2e, 0x6e, 0x73, 0xf7, 0xe0, 0x79,
- 0x4f, 0xe2, 0xe0, 0x49, 0x12, 0xae, 0x06, 0x60, 0x8e, 0xb6, 0xc1, 0x8a,
- 0xee, 0x60, 0x90, 0x8b, 0xc0, 0xd3, 0x6c, 0x61, 0x72, 0x73, 0xe8, 0xce,
- 0x97, 0x6b, 0xef, 0x02, 0x85, 0x6c, 0xe1, 0xe0, 0x7d, 0x6a, 0x6b, 0xe5,
- 0xe0, 0x60, 0x2e, 0x65, 0x6e, 0x62, 0x72, 0x75, 0xee, 0xe0, 0x88, 0x3a,
- 0x6d, 0x69, 0xe4, 0xe0, 0x91, 0x1a, 0x6c, 0x65, 0xf3, 0xe0, 0x3d, 0xd0,
- 0x61, 0x65, 0x66, 0x66, 0xec, 0xe0, 0x7f, 0x55, 0xae, 0x10, 0x04, 0x04,
- 0x08, 0x05, 0x06, 0x60, 0x70, 0xd5, 0x40, 0x48, 0x4c, 0x28, 0x42, 0x4c,
- 0x83, 0xf5, 0xe0, 0x5e, 0x0c, 0xf4, 0xe0, 0x7f, 0xab, 0xf3, 0x60, 0x90,
- 0x44, 0x40, 0xc9, 0xc1, 0x5e, 0xec, 0x60, 0x90, 0x3f, 0xaf, 0xe9, 0x60,
- 0x90, 0x54, 0xc0, 0xfb, 0xe1, 0xe0, 0x91, 0x25, 0xe1, 0x04, 0xe0, 0x92,
- 0x8b, 0x6c, 0x65, 0x62, 0x6f, 0x6f, 0xeb, 0xe0, 0x5d, 0x3c, 0xae, 0x0d,
- 0x5d, 0xbc, 0x60, 0x2c, 0x6c, 0x60, 0x42, 0x3e, 0x41, 0x8c, 0xc2, 0x2c,
- 0xec, 0x60, 0x90, 0x11, 0x86, 0xe2, 0x60, 0x76, 0xde, 0x59, 0x2e, 0x40,
- 0x50, 0xc2, 0x12, 0xe1, 0x1a, 0x0e, 0x04, 0x20, 0x07, 0x1d, 0x27, 0x26,
- 0x0c, 0x1a, 0x40, 0xca, 0x23, 0x33, 0x40, 0x5f, 0x2d, 0x12, 0x0d, 0x0a,
- 0x06, 0x08, 0x18, 0xe0, 0x8f, 0x86, 0xf9, 0x04, 0xe0, 0x8c, 0x65, 0x61,
- 0x6d, 0x61, 0xae, 0x60, 0x88, 0x3c, 0xc8, 0x38, 0xf8, 0xe0, 0x90, 0xbe,
- 0xf6, 0x05, 0x12, 0xe0, 0x8a, 0x4e, 0xe5, 0x04, 0xe0, 0x92, 0x2d, 0x73,
- 0x2d, 0x74, 0x68, 0x65, 0x2d, 0x77, 0x68, 0x61, 0xec, 0xe0, 0x91, 0x15,
- 0x61, 0x6e, 0x6e, 0x61, 0xe8, 0xe0, 0x76, 0xad, 0xf5, 0x60, 0x34, 0x4c,
- 0xe0, 0x37, 0x63, 0xf4, 0x06, 0x04, 0x0c, 0xe0, 0x61, 0x78, 0xf4, 0xe0,
- 0x39, 0xef, 0x73, 0x75, 0x6d, 0x61, 0x73, 0x65, 0x6e, 0x64, 0xe1, 0xe0,
- 0x8a, 0xe2, 0x6f, 0x73, 0xe8, 0xe0, 0x3c, 0x30, 0xf3, 0x07, 0x04, 0x0a,
- 0x05, 0xe0, 0x91, 0xd9, 0xf3, 0xe0, 0x79, 0x96, 0x6b, 0x61, 0x74, 0x63,
- 0x68, 0x65, 0xf7, 0xe0, 0x63, 0x6b, 0x65, 0xe2, 0xe0, 0x53, 0xca, 0xe1,
- 0x02, 0x85, 0x79, 0xe1, 0xe0, 0x4f, 0x0f, 0x67, 0xf5, 0xd5, 0xc6, 0xf2,
- 0x09, 0x06, 0x07, 0x04, 0x60, 0x8f, 0x6a, 0xc0, 0x4c, 0x75, 0x66, 0xf5,
- 0xe0, 0x8d, 0x34, 0x70, 0x73, 0x62, 0xef, 0xe0, 0x63, 0x34, 0xef, 0xe0,
- 0x85, 0x27, 0xe4, 0x02, 0x84, 0xe9, 0xe0, 0x79, 0x12, 0xe5, 0xe0, 0x7c,
- 0x81, 0xf0, 0x04, 0xe0, 0x91, 0xa2, 0x70, 0x6f, 0x72, 0xef, 0xe0, 0x36,
- 0x8e, 0xef, 0x03, 0x05, 0x87, 0x74, 0x6f, 0xed, 0xca, 0x37, 0x67, 0x6f,
- 0x6e, 0xe3, 0xe0, 0x88, 0x7e, 0x62, 0x65, 0x72, 0x6e, 0x61, 0x72, 0xe4,
- 0xe0, 0x84, 0xfd, 0xee, 0x0a, 0x05, 0x29, 0x08, 0x0a, 0x04, 0x04, 0x0a,
- 0xc0, 0x65, 0x75, 0xeb, 0xe0, 0x3a, 0x2c, 0xf4, 0x02, 0x88, 0x6f, 0x61,
- 0x6e, 0x64, 0xf2, 0xe0, 0x78, 0xba, 0xe1, 0x04, 0x06, 0x04, 0x86, 0x6d,
- 0x61, 0xf2, 0xe0, 0x53, 0xea, 0xe6, 0xe0, 0x8d, 0x14, 0x63, 0x72, 0xf5,
- 0xe0, 0x82, 0x9b, 0x62, 0x61, 0x72, 0x62, 0x61, 0xf2, 0xe0, 0x8b, 0x2d,
- 0xef, 0x60, 0x7f, 0x11, 0x46, 0xbc, 0xc5, 0x4e, 0xee, 0x04, 0xe0, 0x53,
- 0x8e, 0x61, 0xee, 0xe0, 0x8c, 0x8b, 0xea, 0xe0, 0x8d, 0x1a, 0xe7, 0xe0,
- 0x4b, 0xe4, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x69, 0xf3, 0xe0, 0x86, 0x78,
- 0xe4, 0x0d, 0x10, 0x0b, 0x05, 0x31, 0x60, 0x4e, 0x01, 0x60, 0x37, 0x1f,
- 0xc3, 0x78, 0x76, 0x69, 0xeb, 0x04, 0xe0, 0x91, 0x0f, 0x63, 0x6f, 0x72,
- 0x6f, 0x6d, 0xe1, 0xe0, 0x67, 0xfb, 0x6e, 0x65, 0xf3, 0x04, 0xe0, 0x8f,
- 0x78, 0xf3, 0xe0, 0x22, 0xb2, 0x69, 0xe5, 0xe0, 0x75, 0x35, 0xe5, 0x04,
- 0xe0, 0x81, 0xc6, 0xae, 0x03, 0x19, 0x8a, 0x78, 0x6e, 0x2d, 0x2d, 0x6d,
- 0x72, 0x65, 0x2d, 0x6f, 0x67, 0x2d, 0x72, 0x6f, 0x6d, 0x73, 0x64, 0x61,
- 0x6c, 0x2d, 0x71, 0x71, 0xe2, 0xe0, 0x8f, 0x50, 0x76, 0x65, 0x73, 0x74,
- 0x66, 0x6f, 0xec, 0xe0, 0x8c, 0xda, 0xed, 0x60, 0x4c, 0x85, 0x8e, 0x63,
- 0x61, 0xf4, 0xe0, 0x72, 0xb1, 0x61, 0x67, 0x6f, 0x63, 0xe8, 0xe0, 0x21,
- 0xb3, 0xed, 0x07, 0x04, 0x0d, 0x04, 0xe0, 0x5b, 0xa5, 0xf5, 0xe0, 0x8c,
- 0x12, 0xf3, 0x02, 0x84, 0xf5, 0xe0, 0x7b, 0x58, 0x63, 0x6c, 0xf5, 0xe0,
- 0x86, 0xac, 0xee, 0xe0, 0x7a, 0x92, 0x65, 0x67, 0xe1, 0xe0, 0x85, 0x5f,
- 0xec, 0x0b, 0x04, 0x0f, 0x05, 0x09, 0x60, 0x49, 0xcf, 0xe0, 0x3f, 0x79,
- 0xfa, 0xe0, 0x73, 0xb1, 0x76, 0x61, 0x64, 0x6f, 0xf2, 0x04, 0xe0, 0x8f,
- 0x2f, 0x64, 0x61, 0xec, 0xe0, 0x84, 0xa3, 0x75, 0xe4, 0xe0, 0x8d, 0xc4,
- 0xe5, 0x60, 0x2d, 0x85, 0x60, 0x59, 0x12, 0xc9, 0xd8, 0xe1, 0x60, 0x81,
- 0x63, 0xc7, 0x83, 0xeb, 0x05, 0x20, 0x04, 0xde, 0x2f, 0xf5, 0x05, 0x16,
- 0xe0, 0x8d, 0x29, 0x72, 0xe1, 0x08, 0x06, 0x60, 0x4c, 0x8b, 0xe0, 0x43,
- 0xba, 0x67, 0x61, 0xf7, 0xe0, 0x49, 0xf0, 0xae, 0x60, 0x84, 0xcb, 0xc9,
- 0xa3, 0xe8, 0xe0, 0x82, 0x56, 0xe5, 0xe0, 0x2a, 0x19, 0xe1, 0x0e, 0x15,
- 0x06, 0x07, 0x58, 0x01, 0x60, 0x3e, 0x9b, 0x60, 0x2e, 0x20, 0xc2, 0xb0,
- 0xe9, 0x02, 0x89, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0xef, 0xe0, 0x73, 0x88,
- 0xae, 0x60, 0x63, 0x7b, 0x60, 0x25, 0x2c, 0xc5, 0xa7, 0x68, 0x6f, 0xe7,
- 0xe0, 0x87, 0xa8, 0x65, 0xae, 0x60, 0x8c, 0xf6, 0xc1, 0x3f, 0xe4, 0xe0,
- 0x57, 0x42, 0xe9, 0x05, 0x0e, 0x08, 0x09, 0x84, 0xf4, 0x04, 0xe0, 0x63,
- 0x6f, 0x61, 0x6d, 0x61, 0xae, 0x60, 0x85, 0xee, 0xc8, 0x63, 0x6e, 0x74,
- 0x6c, 0x6f, 0xf5, 0xe0, 0x82, 0x3c, 0xeb, 0x04, 0xe0, 0x4a, 0x70, 0xe1,
- 0xe0, 0x4d, 0x04, 0xea, 0xe0, 0x3d, 0x8a, 0xe7, 0xe0, 0x49, 0xed, 0x67,
- 0xe1, 0x05, 0x05, 0xe0, 0x4a, 0xc4, 0x6d, 0xe9, 0xe0, 0x3f, 0x0a, 0xae,
- 0x60, 0x85, 0x72, 0xc8, 0xb4, 0x66, 0xe5, 0x04, 0xe0, 0x8f, 0xbd, 0x74,
- 0xf9, 0x60, 0x8c, 0xdc, 0xc2, 0xdf, 0xe4, 0x04, 0xe0, 0x8b, 0x96, 0x69,
- 0xf3, 0xe0, 0x78, 0x70, 0x62, 0x61, 0xe5, 0xe0, 0x63, 0x08, 0x61, 0x72,
- 0x6c, 0x61, 0xee, 0xe0, 0x8d, 0x5c, 0xae, 0x08, 0x09, 0x60, 0x8c, 0x6d,
- 0x04, 0xc1, 0x20, 0x67, 0x6f, 0x76, 0xae, 0x60, 0x8b, 0x32, 0xc1, 0x44,
- 0xe3, 0x60, 0x8e, 0x41, 0xc1, 0x44, 0x2d, 0x65, 0x61, 0x73, 0xf4, 0xe0,
- 0x86, 0x93, 0x35, 0xf9, 0xe0, 0x81, 0x83, 0xb3, 0x03, 0xc0, 0x44, 0xae,
- 0x0d, 0x09, 0x19, 0x10, 0x21, 0x05, 0x60, 0x39, 0x70, 0x09, 0xe0, 0x20,
- 0x47, 0x74, 0x65, 0x63, 0x6b, 0x69, 0xe4, 0xe0, 0x7a, 0xb4, 0x64, 0x75,
- 0x61, 0x6c, 0x73, 0x74, 0x61, 0x63, 0x6b, 0xae, 0x07, 0x05, 0x40, 0x47,
- 0x21, 0xc0, 0x5a, 0x75, 0x73, 0xad, 0xc0, 0xd7, 0xe5, 0xc0, 0xab, 0xe3,
- 0x03, 0xc0, 0x41, 0x6e, 0x2d, 0x6e, 0x6f, 0x72, 0x74, 0x68, 0x2d, 0xb1,
- 0xe0, 0x6f, 0xba, 0xe1, 0x39, 0xc0, 0x94, 0xad, 0x07, 0x28, 0x21, 0x19,
- 0x11, 0x11, 0x9f, 0x77, 0x65, 0x62, 0x73, 0x69, 0x74, 0xe5, 0x02, 0xb6,
- 0xae, 0x0b, 0x05, 0x0e, 0x05, 0x60, 0x39, 0x5d, 0x09, 0xe0, 0x20, 0x47,
- 0x75, 0x73, 0xad, 0xc0, 0x54, 0x65, 0x75, 0xad, 0x03, 0xc0, 0x7b, 0x77,
- 0x65, 0x73, 0x74, 0xad, 0x40, 0x74, 0xa4, 0x63, 0x61, 0xad, 0xc0, 0x70,
- 0x61, 0x70, 0xad, 0x02, 0x87, 0x73, 0x6f, 0x75, 0x74, 0xe8, 0xc0, 0x78,
- 0x6e, 0x6f, 0x72, 0x74, 0xe8, 0xae, 0xad, 0x04, 0x05, 0x04, 0x83, 0x75,
- 0x73, 0xad, 0x18, 0x89, 0x73, 0x61, 0xad, 0x93, 0x65, 0xf5, 0xaf, 0x61,
- 0x70, 0xad, 0x02, 0x85, 0x73, 0x6f, 0xf5, 0xc0, 0x5c, 0x6e, 0x6f, 0x72,
- 0x74, 0x68, 0x65, 0xe1, 0xa0, 0x75, 0x73, 0xad, 0x03, 0x04, 0x8f, 0x77,
- 0xe5, 0xc0, 0x4e, 0x65, 0x61, 0x73, 0x74, 0xad, 0xc0, 0x4c, 0x66, 0x69,
- 0x70, 0x73, 0x2d, 0x75, 0x73, 0x2d, 0x67, 0x6f, 0x76, 0x2d, 0x77, 0x65,
- 0x73, 0xf4, 0xac, 0xe5, 0x02, 0x86, 0x78, 0x74, 0x65, 0x72, 0xee, 0x94,
- 0x75, 0xad, 0x02, 0x8a, 0x77, 0x65, 0x73, 0x74, 0xad, 0x03, 0x24, 0x82,
- 0xb3, 0xa6, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x61, 0xec, 0x8d, 0x61, 0x70,
- 0xad, 0x02, 0x89, 0x73, 0x6f, 0x75, 0x74, 0xe8, 0x02, 0x87, 0xad, 0x8f,
- 0x6e, 0x6f, 0x72, 0x74, 0x68, 0x65, 0x61, 0x73, 0x74, 0xad, 0x02, 0x82,
- 0xb2, 0x82, 0x31, 0x2e, 0x61, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x61, 0xf7,
- 0xe0, 0x8d, 0x53, 0xf2, 0x1f, 0x35, 0x0d, 0x2e, 0x06, 0x20, 0x24, 0x04,
- 0x40, 0x96, 0x04, 0x04, 0x04, 0x40, 0xb1, 0x04, 0x41, 0x9a, 0x05, 0x40,
- 0xdd, 0x04, 0x60, 0x4f, 0x90, 0x47, 0x2d, 0x57, 0x52, 0xd4, 0xbf, 0x1f,
- 0xc3, 0x04, 0x17, 0x03, 0x88, 0xf8, 0x08, 0x06, 0x04, 0x40, 0xf0, 0xe0,
- 0x4a, 0xe5, 0xf9, 0x40, 0xcb, 0xe0, 0x30, 0x82, 0xed, 0xe0, 0x2a, 0x28,
- 0xe4, 0xe0, 0x85, 0xf6, 0xe6, 0xc3, 0xf2, 0xe5, 0x04, 0xe0, 0x53, 0xe9,
- 0xe8, 0xc4, 0x0c, 0xe1, 0x03, 0xd4, 0xc4, 0x68, 0x6b, 0x6b, 0x65, 0x72,
- 0x1f, 0xc3, 0xc4, 0x08, 0xfa, 0x02, 0x84, 0xe7, 0xe0, 0x4e, 0x54, 0x65,
- 0x73, 0xfa, 0xe0, 0x81, 0x3a, 0xf9, 0x07, 0x15, 0x06, 0x05, 0xe0, 0x3a,
- 0x8f, 0xf5, 0x03, 0x05, 0x85, 0x6f, 0xe8, 0xe0, 0x88, 0xbc, 0x6b, 0xf9,
- 0xe0, 0x8c, 0xf5, 0x67, 0x61, 0x73, 0xe1, 0xe0, 0x42, 0x21, 0x6f, 0x6b,
- 0xe1, 0xe0, 0x37, 0x53, 0x67, 0xe7, 0xe0, 0x8c, 0x4e, 0x62, 0x6e, 0xe9,
- 0xe0, 0x7b, 0x9a, 0xf7, 0x60, 0x8c, 0x5e, 0xc1, 0x6e, 0xf5, 0x0c, 0x05,
- 0x05, 0x06, 0x60, 0x44, 0xe1, 0x50, 0xc0, 0xe0, 0x38, 0x09, 0x73, 0xf3,
- 0xe0, 0x80, 0xbc, 0x6f, 0xf6, 0xe0, 0x7b, 0x51, 0xee, 0x60, 0x8c, 0x47,
- 0xc1, 0x68, 0xe7, 0xd2, 0x11, 0xf3, 0x07, 0x04, 0x09, 0x05, 0xe0, 0x8d,
- 0x8d, 0xf6, 0xe0, 0x8c, 0x0f, 0x73, 0x2e, 0x6d, 0x79, 0x2e, 0xe9, 0xe0,
- 0x7e, 0x2e, 0x63, 0xae, 0xe0, 0x75, 0x91, 0xae, 0x05, 0x60, 0x87, 0x76,
- 0x83, 0xe2, 0xe0, 0x7d, 0xac, 0xf2, 0xe0, 0x65, 0x0b, 0xef, 0x16, 0x10,
- 0x0d, 0x11, 0x06, 0x03, 0x14, 0x05, 0x05, 0x04, 0x06, 0x13, 0x59, 0xb7,
- 0x60, 0x30, 0xf0, 0x60, 0x3b, 0x99, 0xc6, 0xb6, 0xf9, 0x05, 0x04, 0xe0,
- 0x30, 0x7e, 0xeb, 0xe0, 0x7e, 0x60, 0x61, 0x6c, 0xad, 0xe0, 0x41, 0x52,
- 0xf6, 0x02, 0x85, 0x6e, 0xef, 0xe0, 0x71, 0xc3, 0x69, 0xe7, 0xe0, 0x8b,
- 0x51, 0x75, 0x74, 0x65, 0x72, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65,
- 0x6d, 0x65, 0xee, 0xe0, 0x8d, 0x1c, 0x74, 0x6f, 0xf2, 0xe0, 0x88, 0x56,
- 0xf2, 0xd9, 0xf8, 0xed, 0x05, 0x07, 0xe0, 0x86, 0x5c, 0xf3, 0x60, 0x5e,
- 0x9e, 0xe0, 0x28, 0xb6, 0x61, 0xae, 0x60, 0x8a, 0x6a, 0xc0, 0xbd, 0x6c,
- 0xec, 0xe0, 0x7b, 0x6b, 0x6b, 0xf5, 0xe0, 0x4b, 0x8d, 0xe7, 0xe0, 0x58,
- 0x0b, 0xe4, 0x60, 0x81, 0x69, 0xc5, 0x4d, 0xe3, 0x02, 0x88, 0xeb, 0x44,
- 0xdf, 0x60, 0x7c, 0x72, 0xc9, 0x52, 0x68, 0xe5, 0x60, 0x26, 0xc5, 0xe0,
- 0x64, 0xed, 0xae, 0x06, 0x60, 0x86, 0xde, 0x03, 0x83, 0xe9, 0x60, 0x8b,
- 0x37, 0xc1, 0xb2, 0xee, 0xe0, 0x7e, 0x7c, 0xed, 0xe0, 0x8a, 0xe8, 0xea,
- 0xe0, 0x64, 0x69, 0xe9, 0x14, 0x06, 0x05, 0x1f, 0x21, 0x16, 0x05, 0x10,
- 0x05, 0x04, 0x15, 0x60, 0x67, 0xaa, 0x48, 0xb2, 0x59, 0x90, 0xc0, 0xb9,
- 0x76, 0x6e, 0xe5, 0xe0, 0x71, 0x35, 0x74, 0xf4, 0xe0, 0x87, 0x8e, 0xf3,
- 0x06, 0x06, 0x04, 0xe0, 0x52, 0x30, 0x1f, 0x43, 0xf8, 0xe0, 0x81, 0x16,
- 0xef, 0xe0, 0x81, 0x12, 0x68, 0x69, 0x72, 0xe9, 0x04, 0xe0, 0x8a, 0xf8,
- 0x66, 0x75, 0xea, 0xe0, 0x8a, 0xf4, 0xef, 0x08, 0x07, 0x0b, 0x60, 0x8b,
- 0x37, 0xc1, 0x4c, 0x70, 0x72, 0x65, 0xf4, 0xe0, 0x80, 0x0a, 0x64, 0x65,
- 0x6a, 0x61, 0x6e, 0x65, 0x69, 0xf2, 0xe0, 0x81, 0xd8, 0x62, 0x72, 0x61,
- 0xee, 0xcc, 0x24, 0xee, 0x04, 0xe0, 0x85, 0x9c, 0xe7, 0x02, 0x84, 0xf3,
- 0xe0, 0x38, 0xa8, 0xe5, 0x04, 0xe0, 0x84, 0x8e, 0x72, 0xe9, 0xe0, 0x59,
- 0x99, 0x6d, 0xe9, 0xe0, 0x84, 0x76, 0x6b, 0xf5, 0x04, 0xe0, 0x87, 0xce,
- 0x7a, 0x65, 0x6e, 0x74, 0x61, 0x6b, 0x61, 0xf4, 0xdf, 0xc0, 0x69, 0xeb,
- 0xe0, 0x87, 0x9c, 0xe6, 0xe0, 0x21, 0x3e, 0xe3, 0x05, 0x04, 0xe0, 0x7f,
- 0xc6, 0xef, 0xe0, 0x8a, 0xa4, 0xe8, 0x04, 0xe0, 0x8c, 0x3a, 0x61, 0x72,
- 0xe4, 0xe0, 0x3b, 0x1c, 0x62, 0x65, 0x69, 0x72, 0xe1, 0xe0, 0x7f, 0xa8,
- 0xe8, 0xe0, 0x86, 0xee, 0xe5, 0x15, 0x06, 0x10, 0x40, 0x51, 0x2e, 0x19,
- 0x08, 0x0d, 0x07, 0x0c, 0x05, 0x1c, 0x1c, 0x23, 0x05, 0x40, 0x43, 0xe0,
- 0x8a, 0x94, 0x78, 0x72, 0xef, 0xe0, 0x8a, 0x70, 0x76, 0xe9, 0x02, 0x85,
- 0x73, 0xf4, 0xe0, 0x89, 0x56, 0x65, 0xf7, 0x60, 0x89, 0x9f, 0xc2, 0x62,
- 0xf3, 0x04, 0x15, 0x11, 0xa0, 0xf4, 0x05, 0x04, 0xe0, 0x8b, 0xed, 0xef,
- 0xe0, 0x81, 0xbd, 0x61, 0x75, 0x72, 0x61, 0x6e, 0xf4, 0x60, 0x81, 0xb4,
- 0xca, 0x33, 0xe9, 0x02, 0x86, 0x73, 0x74, 0xe1, 0xe0, 0x6b, 0x4d, 0x6e,
- 0x64, 0x65, 0x76, 0xe9, 0xe0, 0x6d, 0x91, 0xe5, 0x02, 0x96, 0x72, 0xf6,
- 0x02, 0x89, 0x65, 0x2d, 0x6f, 0x6e, 0x6c, 0x69, 0xee, 0xc2, 0x13, 0x64,
- 0xae, 0x60, 0x66, 0xcb, 0x19, 0xe0, 0x24, 0xd4, 0x61, 0x72, 0x63, 0xe8,
- 0xe0, 0x84, 0x86, 0xae, 0x60, 0x88, 0xd2, 0xc1, 0xb2, 0xf0, 0x06, 0x08,
- 0x05, 0x07, 0x06, 0x84, 0x75, 0x62, 0x6c, 0x69, 0xe3, 0xe0, 0x87, 0x90,
- 0x6f, 0xf2, 0xe0, 0x89, 0xe3, 0x6c, 0xae, 0x60, 0x63, 0x5e, 0xce, 0xeb,
- 0x62, 0x6f, 0xe4, 0xe0, 0x5c, 0x7a, 0xe1, 0xe0, 0x41, 0x6f, 0xae, 0x04,
- 0xe0, 0x8a, 0x36, 0xeb, 0xe0, 0x89, 0xf1, 0xee, 0x07, 0x09, 0x5e, 0xb2,
- 0xe0, 0x6c, 0xba, 0xf4, 0x04, 0xe0, 0x8b, 0x70, 0xe1, 0xe0, 0x78, 0x8e,
- 0x6e, 0xe5, 0x60, 0x2b, 0xfb, 0xe0, 0x57, 0x91, 0x6d, 0x6f, 0x74, 0x65,
- 0xf7, 0xe0, 0x86, 0x26, 0xec, 0x02, 0x84, 0xe9, 0xe0, 0x29, 0x40, 0xae,
- 0x60, 0x86, 0xf5, 0xc0, 0xf3, 0x6b, 0x6c, 0x61, 0xed, 0xe0, 0x8a, 0x56,
- 0xe9, 0x04, 0xe0, 0x89, 0x8c, 0x73, 0xe5, 0x60, 0x8a, 0x16, 0xc1, 0x2b,
- 0x68, 0xe1, 0xe0, 0x81, 0x45, 0xe7, 0x02, 0x95, 0x67, 0x69, 0xef, 0x03,
- 0x03, 0x86, 0xad, 0x02, 0x86, 0x65, 0x6d, 0xe9, 0xe0, 0x53, 0xed, 0x63,
- 0x61, 0xec, 0xe0, 0x72, 0xc1, 0xae, 0xe0, 0x8a, 0xe5, 0xe4, 0x08, 0x07,
- 0x08, 0x60, 0x74, 0xea, 0xd6, 0x19, 0x75, 0x6d, 0x62, 0xf2, 0xe0, 0x66,
- 0x79, 0x69, 0x72, 0x65, 0x63, 0xf4, 0xe0, 0x75, 0x73, 0xae, 0xe0, 0x4d,
- 0xb8, 0xe3, 0x04, 0x05, 0x0b, 0x84, 0x72, 0xe5, 0xe0, 0x88, 0x14, 0xe9,
- 0x02, 0x84, 0xf0, 0xe0, 0x7e, 0xf4, 0xe6, 0xe0, 0x72, 0x3e, 0xe8, 0xe0,
- 0x87, 0xe0, 0xae, 0x60, 0x80, 0x17, 0x03, 0x40, 0xbb, 0x48, 0x92, 0xb3,
- 0x62, 0xf5, 0xe0, 0x5a, 0x65, 0xe1, 0x02, 0x97, 0xec, 0x05, 0x06, 0xe0,
- 0x65, 0xc9, 0xf4, 0x60, 0x87, 0x9a, 0xc1, 0x03, 0x65, 0x73, 0x74, 0x61,
- 0x74, 0xe5, 0x60, 0x86, 0x32, 0xc4, 0x90, 0xe4, 0x07, 0x07, 0x09, 0x09,
- 0xe0, 0x8a, 0x9c, 0x79, 0x6d, 0x61, 0xe4, 0xe0, 0x7c, 0x39, 0x74, 0x68,
- 0x65, 0x64, 0x6f, 0xe3, 0xe0, 0x6c, 0x97, 0x6d, 0x79, 0x62, 0x6c, 0x6f,
- 0xe7, 0xe0, 0x87, 0xcd, 0x2d, 0x62, 0x6f, 0x6f, 0xeb, 0xe0, 0x75, 0xea,
- 0xae, 0x60, 0x73, 0x6c, 0xd5, 0x2c, 0x64, 0xf6, 0xe0, 0x89, 0x56, 0xe1,
- 0x12, 0x08, 0x21, 0x05, 0x04, 0x17, 0x04, 0x05, 0x16, 0x11, 0x1a, 0x0a,
- 0x20, 0x58, 0x6b, 0xe0, 0x6f, 0x52, 0x77, 0x61, 0x2d, 0x6d, 0xe1, 0xe0,
- 0x73, 0x0b, 0xf6, 0x02, 0x89, 0x70, 0x61, 0x67, 0x65, 0x2e, 0x63, 0xef,
- 0xd9, 0x25, 0x65, 0xee, 0x04, 0xe0, 0x82, 0x8b, 0x64, 0x62, 0xae, 0x06,
- 0x60, 0x62, 0x1c, 0xd2, 0x3e, 0xe3, 0x59, 0xe3, 0xe0, 0x58, 0x50, 0x75,
- 0xed, 0xe0, 0x84, 0x75, 0xf2, 0xe0, 0x5e, 0x26, 0xee, 0x06, 0x06, 0x05,
- 0xe0, 0x84, 0x5c, 0x7a, 0x61, 0xee, 0xe0, 0x7f, 0x06, 0x6b, 0xef, 0xe0,
- 0x84, 0x64, 0x64, 0xe1, 0xe0, 0x5b, 0xa9, 0xec, 0xe0, 0x24, 0xf8, 0x6b,
- 0xeb, 0xe0, 0x41, 0x21, 0xe9, 0x05, 0x04, 0xe0, 0x4f, 0x9e, 0xee, 0xe0,
- 0x7b, 0x8e, 0xec, 0x02, 0x84, 0xf7, 0xe0, 0x6e, 0x62, 0x72, 0xef, 0xe0,
- 0x7b, 0x4f, 0xe8, 0x02, 0x85, 0x6f, 0xec, 0xe0, 0x82, 0x89, 0x6b, 0x6b,
- 0x65, 0x72, 0x61, 0xf6, 0xe0, 0x83, 0xdb, 0xe7, 0x02, 0x84, 0xf5, 0xe0,
- 0x70, 0xb9, 0x2d, 0x63, 0x6c, 0x6f, 0x75, 0xe4, 0x02, 0x83, 0x2d, 0x63,
- 0x68, 0x2e, 0x68, 0x6f, 0x73, 0xf4, 0xe0, 0x59, 0x44, 0x66, 0x66, 0x6c,
- 0x65, 0x65, 0x6e, 0xf4, 0xe0, 0x85, 0xf7, 0xe4, 0x07, 0x06, 0x60, 0x81,
- 0x9e, 0xc6, 0xa5, 0xef, 0x60, 0x7d, 0x4c, 0xc4, 0x9c, 0x69, 0xef, 0x04,
- 0xe0, 0x89, 0xc5, 0xae, 0x07, 0x60, 0x60, 0xa4, 0xe0, 0x27, 0xce, 0xe6,
- 0xe0, 0x89, 0xb7, 0xe3, 0x04, 0xe0, 0x74, 0x64, 0x6b, 0x6d, 0x61, 0x7a,
- 0xe5, 0xe0, 0x86, 0x51, 0xb2, 0xe0, 0x64, 0xea, 0xae, 0x07, 0x08, 0x60,
- 0x78, 0x8f, 0xd1, 0x07, 0x63, 0x64, 0x6e, 0x37, 0xb7, 0xe0, 0x89, 0x77,
- 0x61, 0x70, 0x70, 0x73, 0x70, 0xef, 0xe0, 0x69, 0xeb, 0xf1, 0x0d, 0x2d,
- 0x04, 0x04, 0x06, 0x0e, 0x04, 0x0c, 0x06, 0x09, 0xe0, 0x89, 0x16, 0xf5,
- 0x03, 0x13, 0x8d, 0xe9, 0x02, 0x8a, 0x70, 0x65, 0x6c, 0x65, 0x6d, 0x65,
- 0xee, 0xe0, 0x26, 0xb6, 0x63, 0x6b, 0x73, 0xf9, 0xc9, 0x5c, 0xe5, 0x04,
- 0xe0, 0x7c, 0x74, 0x62, 0x65, 0xe3, 0x60, 0x86, 0xa9, 0xc2, 0xb9, 0x61,
- 0x6c, 0x69, 0x66, 0x69, 0xef, 0xe0, 0x88, 0x6f, 0xf3, 0xe0, 0x53, 0x61,
- 0xf0, 0xe0, 0x82, 0x30, 0x6f, 0x74, 0xef, 0xe0, 0x88, 0x4e, 0x6c, 0x64,
- 0xae, 0x05, 0x60, 0x86, 0x1f, 0x84, 0x67, 0x6f, 0xf6, 0xe0, 0x86, 0x1f,
- 0xe8, 0xe0, 0x75, 0xfa, 0xe3, 0x04, 0xe0, 0x5c, 0x20, 0x2e, 0xe3, 0x60,
- 0x87, 0x94, 0xc1, 0x93, 0x62, 0x75, 0xf3, 0xe0, 0x7f, 0xb9, 0xe1, 0x04,
- 0xe0, 0x89, 0x1d, 0xb2, 0xe0, 0x89, 0x14, 0x2d, 0xe1, 0xe0, 0x7c, 0x6f,
- 0xf0, 0x23, 0x04, 0x1d, 0x06, 0x11, 0x40, 0x60, 0x06, 0x13, 0x41, 0x52,
- 0x0f, 0x41, 0x16, 0x08, 0x09, 0x40, 0x92, 0x40, 0x91, 0x40, 0x71, 0x12,
- 0x0a, 0x40, 0x70, 0x0a, 0x15, 0x09, 0x60, 0x57, 0x52, 0xe0, 0x29, 0xbe,
- 0xfa, 0xe0, 0x86, 0xf3, 0xf9, 0x08, 0x05, 0x60, 0x57, 0xab, 0xe0, 0x31,
- 0x33, 0x6d, 0xee, 0xe0, 0x3c, 0xd4, 0xe1, 0x04, 0xe0, 0x80, 0xa0, 0x74,
- 0x69, 0x67, 0x6f, 0x72, 0x73, 0xeb, 0xe0, 0x88, 0x48, 0xf7, 0x60, 0x7c,
- 0xe6, 0xcb, 0xe8, 0xf6, 0x05, 0x07, 0xe0, 0x86, 0xc0, 0x74, 0xae, 0x60,
- 0x56, 0x91, 0xd5, 0x40, 0xe8, 0xe0, 0x87, 0x6f, 0xf5, 0x0a, 0x06, 0x05,
- 0x06, 0x06, 0x07, 0x05, 0xe0, 0x86, 0x8e, 0x73, 0x73, 0x79, 0xe3, 0xc3,
- 0xeb, 0xf0, 0x06, 0xe0, 0x48, 0xf1, 0x6e, 0x79, 0xf5, 0xe0, 0x80, 0x66,
- 0x6c, 0x61, 0xf7, 0xe0, 0x76, 0xce, 0xe7, 0x60, 0x51, 0x5a, 0xe0, 0x35,
- 0x3f, 0x65, 0x62, 0xec, 0xda, 0x09, 0xe2, 0x08, 0x05, 0x1c, 0x60, 0x72,
- 0x3b, 0xd6, 0x25, 0x74, 0xec, 0xe0, 0x73, 0xd2, 0xec, 0x02, 0x95, 0xe9,
- 0x02, 0x85, 0x73, 0xe8, 0xe0, 0x69, 0xe2, 0xe3, 0x04, 0xe0, 0x85, 0xb3,
- 0x2d, 0x69, 0x6e, 0x71, 0xf5, 0xe0, 0x3c, 0x52, 0xae, 0xe0, 0x3a, 0xfe,
- 0xae, 0x03, 0xc0, 0xf0, 0xf3, 0xe0, 0x86, 0xc2, 0xf4, 0x60, 0x76, 0x3c,
- 0xd2, 0x1b, 0xf3, 0x0d, 0x5b, 0x09, 0x51, 0x8f, 0x60, 0x2a, 0xda, 0x60,
- 0x29, 0x0b, 0xc7, 0xc7, 0x73, 0xe5, 0xe0, 0x48, 0x93, 0xf2, 0x0e, 0x08,
- 0x06, 0x12, 0x40, 0x77, 0x40, 0x4c, 0x3d, 0x0a, 0x10, 0xe0, 0x86, 0xf6,
- 0x7a, 0x65, 0x77, 0x6f, 0xf2, 0xe0, 0x26, 0x76, 0x76, 0x63, 0xf9, 0xe0,
- 0x67, 0x7b, 0xf5, 0x05, 0x05, 0xe0, 0x88, 0x17, 0x73, 0xfa, 0xe0, 0x23,
- 0x4d, 0x64, 0x65, 0x6e, 0xf4, 0xe0, 0x54, 0x28, 0xef, 0x0c, 0x0c, 0x0a,
- 0x04, 0x06, 0x08, 0x0c, 0x10, 0x04, 0xe0, 0x87, 0xbb, 0xf4, 0x02, 0x85,
- 0x6f, 0xee, 0xe0, 0x75, 0x44, 0xe5, 0xe0, 0x7b, 0x4d, 0x70, 0x65, 0x72,
- 0xf4, 0x60, 0x2e, 0x63, 0xe0, 0x57, 0x60, 0xed, 0xe0, 0x86, 0x6f, 0x6a,
- 0x65, 0xe3, 0xe0, 0x80, 0xa3, 0x67, 0x72, 0x65, 0x73, 0xf3, 0xe0, 0x5d,
- 0x59, 0xe6, 0x07, 0x60, 0x57, 0x1f, 0xe0, 0x30, 0xb4, 0x65, 0xf3, 0xc2,
- 0x31, 0xe4, 0x04, 0xe0, 0x87, 0xca, 0x75, 0x63, 0x74, 0x69, 0x6f, 0xee,
- 0x60, 0x84, 0xe5, 0xc0, 0x7d, 0x63, 0xe8, 0xc1, 0x94, 0xae, 0x17, 0x54,
- 0xb1, 0x60, 0x42, 0x3f, 0x4e, 0x16, 0x5b, 0xe7, 0x42, 0x85, 0x40, 0x5e,
- 0x2c, 0x3b, 0x40, 0xda, 0x40, 0x58, 0x40, 0xef, 0x9f, 0xf4, 0x04, 0xe0,
- 0x85, 0xe7, 0x79, 0xf0, 0xe0, 0x44, 0x08, 0xe9, 0x06, 0x31, 0x08, 0xe0,
- 0x82, 0xa5, 0xf6, 0x02, 0x96, 0x61, 0x74, 0x69, 0x7a, 0x65, 0x68, 0x65,
- 0x61, 0x6c, 0x74, 0x68, 0x69, 0x6e, 0x73, 0x75, 0x72, 0x61, 0x6e, 0xe3,
- 0xe0, 0x79, 0x8e, 0xae, 0x0c, 0x60, 0x6a, 0x87, 0x58, 0x86, 0x42, 0xd9,
- 0x40, 0x92, 0xc0, 0x56, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0xe5,
- 0xe0, 0x31, 0xd3, 0x6e, 0x63, 0x69, 0x70, 0xe5, 0xe0, 0x64, 0x86, 0x6d,
- 0xe5, 0x04, 0xe0, 0x87, 0x53, 0x74, 0x65, 0xec, 0xe0, 0x6f, 0x2f, 0xe5,
- 0x02, 0xa9, 0xf3, 0x05, 0x1e, 0xe0, 0x57, 0x29, 0xf3, 0x05, 0x09, 0xe0,
- 0x87, 0x35, 0x65, 0xae, 0x60, 0x49, 0x0a, 0x60, 0x32, 0x53, 0x9a, 0xae,
- 0x08, 0x60, 0x76, 0x23, 0x4c, 0xd8, 0xc1, 0x53, 0xed, 0x60, 0x84, 0x74,
- 0xc1, 0x1e, 0x69, 0xe4, 0xe0, 0x4d, 0x9f, 0x71, 0x75, 0x61, 0x6c, 0x69,
- 0x66, 0x79, 0x6d, 0x65, 0x2e, 0x74, 0x6f, 0x64, 0xe1, 0xe0, 0x76, 0x00,
- 0x64, 0xae, 0x60, 0x29, 0x9b, 0x60, 0x51, 0xae, 0xc8, 0x03, 0xe1, 0x05,
- 0x04, 0xe0, 0x82, 0xab, 0xf8, 0xe0, 0x84, 0xed, 0x6d, 0x65, 0xf2, 0xe0,
- 0x63, 0x6f, 0xae, 0x60, 0x80, 0xe4, 0x03, 0x41, 0x35, 0xc2, 0xde, 0xf0,
- 0x04, 0xe0, 0x67, 0x4b, 0xae, 0x53, 0xf5, 0x60, 0x5f, 0xf6, 0x41, 0xf3,
- 0xd0, 0x80, 0xef, 0x10, 0x06, 0x06, 0x0a, 0x2c, 0x3b, 0x11, 0x0a, 0x29,
- 0x0b, 0x18, 0x04, 0x16, 0xe0, 0x7c, 0xbf, 0x7a, 0x6e, 0xe1, 0xe0, 0x22,
- 0x2a, 0x77, 0x69, 0xe1, 0xe0, 0x61, 0x3f, 0xf4, 0x04, 0xe0, 0x63, 0x22,
- 0x61, 0xe7, 0xe0, 0x37, 0x9c, 0x73, 0xf4, 0x07, 0x19, 0x60, 0x85, 0x68,
- 0xc1, 0x2d, 0x73, 0x2d, 0x61, 0x6e, 0x64, 0x2d, 0x74, 0x65, 0x6c, 0x65,
- 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x69, 0xef,
- 0xe0, 0x21, 0x6d, 0x6d, 0x61, 0x6e, 0x2d, 0x65, 0x63, 0xe8, 0xe0, 0x4e,
- 0xf4, 0xf2, 0x06, 0x13, 0x1c, 0xe0, 0x85, 0x2a, 0xf4, 0x06, 0x60, 0x7c,
- 0x58, 0xc6, 0x62, 0xec, 0x04, 0xe0, 0x56, 0xc5, 0x6c, 0x69, 0x67, 0xe1,
- 0xe0, 0x7f, 0x31, 0xf3, 0x03, 0x09, 0x87, 0x1f, 0x43, 0x61, 0x1f, 0x45,
- 0xcb, 0xe0, 0x34, 0x69, 0x67, 0x72, 0x75, 0xee, 0xe0, 0x80, 0x7d, 0x61,
- 0x6e, 0xe7, 0x60, 0x7a, 0xbc, 0xc5, 0x7a, 0x64, 0xe5, 0xe0, 0x4e, 0x36,
- 0xee, 0x02, 0x86, 0x70, 0x65, 0xf3, 0xe0, 0x5e, 0x7f, 0x69, 0x61, 0x74,
- 0x6f, 0xf7, 0xe0, 0x4b, 0x33, 0x6d, 0x6f, 0xf2, 0x03, 0xde, 0x9d, 0x73,
- 0xeb, 0xc0, 0x60, 0xec, 0x04, 0x06, 0x05, 0x91, 0x74, 0x61, 0xf6, 0xe0,
- 0x61, 0xf4, 0x6b, 0xef, 0xe0, 0x2d, 0xd4, 0xe9, 0x02, 0x8a, 0x74, 0xe9,
- 0x04, 0xe0, 0x84, 0xae, 0xe3, 0xe0, 0x83, 0x6b, 0x63, 0xe5, 0xcf, 0x4c,
- 0xae, 0x60, 0x78, 0xc8, 0x41, 0x69, 0xc8, 0x76, 0xeb, 0x04, 0xe0, 0x72,
- 0x99, 0x72, 0x6f, 0xf6, 0xe0, 0x80, 0x18, 0xe9, 0x02, 0x86, 0x76, 0x72,
- 0xef, 0xe0, 0x65, 0x29, 0x6e, 0xf4, 0x02, 0x85, 0x74, 0xef, 0xe0, 0x48,
- 0x5a, 0x32, 0x74, 0xe8, 0xe0, 0x4a, 0x82, 0xe8, 0xe0, 0x83, 0xa0, 0xe4,
- 0x03, 0x07, 0x87, 0x7a, 0x6f, 0x6e, 0xe5, 0xe0, 0x56, 0x74, 0x6c, 0x61,
- 0x73, 0xe9, 0xe0, 0x47, 0xf7, 0x68, 0xe1, 0xc7, 0x0a, 0xae, 0x60, 0x46,
- 0x20, 0xe0, 0x3d, 0xb3, 0xee, 0x60, 0x79, 0xdf, 0x49, 0xec, 0xc1, 0xfc,
- 0xed, 0x04, 0xe0, 0x85, 0xbb, 0xee, 0xe0, 0x83, 0xbe, 0xec, 0x0b, 0x18,
- 0x04, 0x08, 0x0c, 0x60, 0x20, 0x70, 0xe0, 0x65, 0x0b, 0xf5, 0x05, 0x0d,
- 0xe0, 0x83, 0x36, 0x72, 0x69, 0x6e, 0x61, 0x63, 0x69, 0x6f, 0x6e, 0x61,
- 0xec, 0xe0, 0x82, 0xec, 0x6d, 0xe2, 0xe0, 0x70, 0x46, 0x6f, 0xae, 0xc1,
- 0x3c, 0x65, 0x73, 0xeb, 0x60, 0x5b, 0x23, 0xc9, 0xbf, 0x63, 0xae, 0x06,
- 0x4e, 0xb6, 0xe0, 0x6f, 0x75, 0xe3, 0xe0, 0x21, 0x0e, 0xe1, 0x07, 0x04,
- 0x14, 0x26, 0xe0, 0x80, 0x51, 0xfa, 0xe0, 0x7f, 0x54, 0xf9, 0x04, 0xe0,
- 0x85, 0x6a, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0xee, 0x04, 0xe0, 0x85,
- 0x5f, 0xad, 0xe0, 0x80, 0x21, 0xf4, 0x02, 0x94, 0x74, 0x65, 0xf2, 0x02,
- 0x84, 0xf0, 0xe0, 0x47, 0xba, 0x2d, 0x61, 0x70, 0x70, 0xae, 0x60, 0x60,
- 0x8a, 0xe0, 0x24, 0xb9, 0x66, 0x6f, 0x72, 0xed, 0x02, 0x85, 0x73, 0xe8,
- 0xe0, 0x66, 0x5c, 0xb0, 0xe0, 0x83, 0xd0, 0xee, 0x02, 0x86, 0xf4, 0x60,
- 0x7a, 0x7b, 0xc3, 0x7c, 0x65, 0x74, 0x61, 0xf2, 0xe0, 0x7b, 0x4e, 0xe9,
- 0x16, 0x04, 0x08, 0x0a, 0x0c, 0x06, 0x12, 0x07, 0x0c, 0x07, 0x12, 0x0f,
- 0x60, 0x26, 0x0a, 0x5e, 0xdf, 0x60, 0x31, 0x44, 0xcc, 0x27, 0xfa, 0xe0,
- 0x80, 0xcb, 0x78, 0x6f, 0x6c, 0x69, 0xee, 0xe0, 0x4d, 0x6b, 0x74, 0x74,
- 0x73, 0x62, 0x75, 0x72, 0xe7, 0xe0, 0x4e, 0xf7, 0xf3, 0x06, 0x60, 0x6d,
- 0x8b, 0xd1, 0x1f, 0x74, 0xef, 0xe0, 0x7e, 0xa7, 0x6f, 0x6e, 0xe5, 0xe0,
- 0x71, 0x7b, 0xee, 0x08, 0x05, 0x60, 0x82, 0x79, 0x42, 0x5e, 0x81, 0x6f,
- 0xeb, 0xe0, 0x6b, 0xde, 0xe2, 0xe0, 0x45, 0x28, 0x6d, 0x69, 0x65, 0xee,
- 0xe0, 0x7e, 0x10, 0xec, 0x04, 0xe0, 0x76, 0x59, 0x6f, 0xf4, 0x60, 0x7d,
- 0x8c, 0xc4, 0x5b, 0x67, 0x62, 0x6f, 0xe1, 0xe0, 0x6d, 0x7e, 0xe5, 0x02,
- 0x87, 0x6d, 0x6f, 0x6e, 0xf4, 0xe0, 0x7d, 0xeb, 0x64, 0x6d, 0x6f, 0x6e,
- 0xf4, 0xe0, 0x82, 0xaf, 0xe3, 0x04, 0xe0, 0x82, 0x41, 0xf4, 0x04, 0xe0,
- 0x71, 0xcb, 0x75, 0xf2, 0xe0, 0x78, 0x9f, 0x61, 0xe3, 0xe0, 0x60, 0xfd,
- 0xe8, 0x0a, 0x06, 0x0d, 0x1c, 0x23, 0x60, 0x81, 0xf2, 0xc2, 0x45, 0x79,
- 0x73, 0xe9, 0xe0, 0x83, 0x09, 0x78, 0x2e, 0x65, 0x6e, 0x73, 0x63, 0x61,
- 0x6c, 0x65, 0xe4, 0xe0, 0x46, 0xe1, 0xef, 0x05, 0x10, 0xe0, 0x6e, 0x4a,
- 0x74, 0xef, 0x06, 0x60, 0x82, 0x06, 0xc2, 0x62, 0x67, 0x72, 0x61, 0x70,
- 0xe8, 0xe0, 0x81, 0xa6, 0x65, 0x6e, 0xe9, 0xe0, 0x53, 0xdb, 0x69, 0xec,
- 0x02, 0x85, 0x69, 0xf0, 0xe0, 0x81, 0xf2, 0xe1, 0x02, 0x86, 0x74, 0x65,
- 0xec, 0xe0, 0x7b, 0xd8, 0x64, 0x65, 0x6c, 0x70, 0x68, 0x69, 0xe1, 0x04,
- 0xe0, 0x81, 0x84, 0x61, 0x72, 0xe5, 0xe0, 0x7e, 0x1c, 0x61, 0x72, 0x6d,
- 0x61, 0xe3, 0x04, 0xe0, 0x81, 0x71, 0x69, 0x65, 0xee, 0x04, 0xe0, 0x80,
- 0x64, 0xf3, 0xe0, 0x78, 0x60, 0xe7, 0x06, 0x04, 0x03, 0xe0, 0x73, 0x0f,
- 0xe6, 0xe0, 0x58, 0xaa, 0xe1, 0xcd, 0x53, 0xae, 0xe0, 0x6b, 0xfa, 0xe6,
- 0x04, 0xe0, 0x84, 0x0c, 0x69, 0xfa, 0xe0, 0x70, 0x9c, 0xe5, 0x0c, 0x12,
- 0x2c, 0x05, 0x09, 0x06, 0x06, 0x60, 0x81, 0xeb, 0xc1, 0xb7, 0xf3, 0x02,
- 0x83, 0xe3, 0xdc, 0xf9, 0x61, 0x72, 0xef, 0x02, 0x81, 0x2d, 0x75, 0x72,
- 0xe2, 0xe0, 0x76, 0x99, 0xf2, 0x04, 0x04, 0x14, 0x84, 0xf5, 0xe0, 0x4e,
- 0x83, 0xf3, 0x02, 0x87, 0x70, 0x65, 0x63, 0xf4, 0xe0, 0x32, 0x67, 0x6f,
- 0xae, 0x60, 0x54, 0x12, 0x60, 0x25, 0x31, 0xc7, 0x24, 0xed, 0xe0, 0x74,
- 0x8d, 0xae, 0x06, 0x60, 0x5f, 0x2d, 0xd9, 0xc8, 0xf3, 0xe0, 0x83, 0xbe,
- 0x70, 0xf0, 0xe0, 0x70, 0xf6, 0xee, 0x04, 0xe0, 0x48, 0x7c, 0xfa, 0xe0,
- 0x81, 0xcd, 0x65, 0x77, 0xe5, 0xe0, 0x75, 0x33, 0x63, 0x6f, 0xf2, 0xe0,
- 0x5c, 0xac, 0xae, 0x60, 0x6c, 0x7a, 0x51, 0x16, 0x03, 0x44, 0x13, 0xc0,
- 0x61, 0xe4, 0x04, 0xe0, 0x81, 0x96, 0x6e, 0xf3, 0xe0, 0x62, 0xe6, 0xe3,
- 0x03, 0x07, 0x84, 0x6c, 0x6f, 0x75, 0xe4, 0xe0, 0x4c, 0x81, 0xe3, 0xe0,
- 0x81, 0x18, 0xae, 0x60, 0x7f, 0x1e, 0xc2, 0x64, 0x62, 0xae, 0x60, 0x56,
- 0x96, 0x60, 0x26, 0xcf, 0x83, 0xe1, 0x11, 0x0d, 0x04, 0x05, 0x21, 0x40,
- 0x51, 0x18, 0x1d, 0x40, 0x4e, 0x10, 0x06, 0x32, 0xe0, 0x82, 0x0a, 0xf9,
- 0x04, 0xe0, 0x83, 0x58, 0x77, 0x68, 0x69, 0x72, 0xec, 0xe0, 0x83, 0x3d,
- 0xf6, 0xe0, 0x7d, 0x07, 0x74, 0xf2, 0xe0, 0x80, 0x99, 0xf3, 0x02, 0x97,
- 0xf3, 0x02, 0x8e, 0x65, 0x6e, 0x67, 0x65, 0x72, 0x2d, 0x61, 0x73, 0x73,
- 0x6f, 0xe3, 0xe0, 0x65, 0x6e, 0x61, 0x67, 0xe5, 0xe0, 0x73, 0x8f, 0x61,
- 0x64, 0x65, 0xee, 0xe0, 0x7d, 0x0b, 0xf2, 0x09, 0x0f, 0x06, 0x04, 0x09,
- 0x0c, 0xe0, 0x80, 0x8c, 0xf4, 0x06, 0x04, 0x60, 0x80, 0xaf, 0xb2, 0xee,
- 0xe0, 0x4e, 0x0d, 0xe9, 0xe0, 0x72, 0x06, 0x6f, 0x63, 0xe8, 0xe0, 0x66,
- 0x19, 0xed, 0xe0, 0x7c, 0xbf, 0x6c, 0x69, 0x61, 0x6d, 0x65, 0xee, 0xe0,
- 0x43, 0xc6, 0x69, 0xf3, 0x04, 0xe0, 0x82, 0xf4, 0xae, 0x60, 0x7c, 0xe8,
- 0xc3, 0x53, 0xe1, 0x06, 0x05, 0x06, 0xe0, 0x40, 0x4f, 0x73, 0xe9, 0xe0,
- 0x62, 0x45, 0x6c, 0x6c, 0xe5, 0xe0, 0x5d, 0xab, 0x63, 0x68, 0x75, 0xf4,
- 0xe0, 0x73, 0xcf, 0xee, 0x05, 0x09, 0xe0, 0x5c, 0xf2, 0x74, 0x68, 0x65,
- 0x6f, 0x6e, 0xf3, 0xe0, 0x6e, 0x35, 0xe1, 0x04, 0xe0, 0x7c, 0xa2, 0x73,
- 0xef, 0xc2, 0xcb, 0xec, 0x05, 0x0e, 0xe0, 0x70, 0x04, 0xed, 0x04, 0xe0,
- 0x68, 0xe8, 0x73, 0x70, 0x72, 0x69, 0x6e, 0xe7, 0xe0, 0x7b, 0x72, 0xe5,
- 0x04, 0xe0, 0x77, 0xf6, 0xf2, 0xe0, 0x71, 0x09, 0x67, 0xe5, 0x06, 0x04,
- 0x3a, 0xe0, 0x82, 0x5a, 0xf8, 0xe0, 0x7c, 0x00, 0xf3, 0x02, 0x8e, 0x70,
- 0x65, 0x65, 0x64, 0x6d, 0x6f, 0x62, 0x69, 0x6c, 0x69, 0xfa, 0xe0, 0x79,
- 0x1a, 0xae, 0x06, 0x08, 0x09, 0xe0, 0x5d, 0xab, 0x77, 0x69, 0x61, 0x72,
- 0xe4, 0xe0, 0x5c, 0x2b, 0x74, 0x6f, 0x72, 0x70, 0x72, 0x6f, 0xea, 0xd2,
- 0x18, 0x69, 0x74, 0x2e, 0x68, 0x73, 0x2d, 0x68, 0x65, 0x69, 0x6c, 0x62,
- 0x72, 0x6f, 0xee, 0xe0, 0x57, 0x58, 0x66, 0x72, 0x6f, 0x6e, 0xf4, 0xe0,
- 0x81, 0x6d, 0xe4, 0x04, 0x04, 0xdb, 0xf5, 0xf5, 0xe0, 0x7c, 0x05, 0x65,
- 0x72, 0x62, 0xef, 0xe0, 0x71, 0x97, 0x63, 0x69, 0xe6, 0xe0, 0x67, 0x68,
- 0x61, 0x73, 0xae, 0x04, 0x0d, 0x0f, 0x87, 0x6d, 0x61, 0x73, 0x73, 0x69,
- 0x76, 0x65, 0x67, 0x72, 0xe9, 0xe0, 0x7c, 0xf2, 0x68, 0x6f, 0x73, 0x74,
- 0x65, 0x64, 0x2d, 0x62, 0x79, 0x2d, 0x70, 0x72, 0xe5, 0xc0, 0xb1, 0x64,
- 0x61, 0x74, 0xe1, 0xe0, 0x5a, 0xa6, 0x62, 0x65, 0x65, 0x62, 0xf9, 0xe0,
- 0x6d, 0x7a, 0xae, 0x60, 0x79, 0x02, 0x42, 0xf6, 0x41, 0x38, 0xc2, 0xde,
- 0xef, 0x27, 0x11, 0x38, 0x0f, 0x2e, 0x10, 0x20, 0x40, 0x6b, 0x40, 0x8d,
- 0x41, 0x4b, 0x40, 0x4e, 0x1c, 0x40, 0xee, 0x40, 0x60, 0x40, 0x40, 0x40,
- 0x60, 0x0a, 0x2b, 0x29, 0x40, 0x51, 0x40, 0x44, 0x1f, 0x35, 0x33, 0x60,
- 0x36, 0x08, 0xd8, 0xe8, 0xfa, 0x05, 0x07, 0xe0, 0x7e, 0xaf, 0x75, 0xae,
- 0x60, 0x7a, 0xbd, 0xc2, 0x70, 0xef, 0xe0, 0x7f, 0xee, 0xf9, 0x08, 0x0c,
- 0x05, 0x04, 0x15, 0xe0, 0x75, 0xf6, 0x73, 0x74, 0x72, 0x65, 0x2d, 0x73,
- 0x6c, 0x69, 0xe4, 0xe0, 0x57, 0x7e, 0x6f, 0xe4, 0xe0, 0x3c, 0x63, 0x67,
- 0xe1, 0xda, 0xbf, 0xe1, 0x07, 0x60, 0x22, 0xc9, 0xe0, 0x5d, 0xa2, 0x6d,
- 0xe1, 0x04, 0xe0, 0x76, 0x21, 0x7a, 0x61, 0x6b, 0xe9, 0xe0, 0x73, 0xd7,
- 0x2e, 0xec, 0xe0, 0x81, 0x83, 0xf8, 0x05, 0x05, 0xe0, 0x30, 0x13, 0x66,
- 0xef, 0xe0, 0x7c, 0x9c, 0xae, 0xe0, 0x62, 0x5c, 0xf7, 0x03, 0x09, 0x93,
- 0x6f, 0x2e, 0x63, 0x6f, 0x64, 0xe5, 0xe0, 0x7d, 0xf9, 0xee, 0x05, 0x08,
- 0xe0, 0x4e, 0x25, 0x70, 0x72, 0x6f, 0x76, 0xe9, 0xe0, 0x77, 0xfb, 0x2e,
- 0xf0, 0xe0, 0x81, 0x5e, 0xe1, 0x02, 0x87, 0x72, 0x69, 0x61, 0x73, 0xe1,
- 0xc5, 0x44, 0xee, 0xe0, 0x3e, 0x69, 0xf6, 0x06, 0x4c, 0x71, 0xe0, 0x73,
- 0x3c, 0x65, 0x72, 0x68, 0x61, 0x6c, 0xec, 0xe0, 0x7b, 0x6f, 0xf5, 0x04,
- 0x0b, 0x07, 0x84, 0x74, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0xf3, 0xe0,
- 0x7b, 0xf8, 0xed, 0x60, 0x41, 0x82, 0xe0, 0x3b, 0x25, 0xe4, 0xe0, 0x36,
- 0x8f, 0x63, 0xe8, 0xe0, 0x48, 0x01, 0xf4, 0x0a, 0x17, 0x18, 0x07, 0x04,
- 0x60, 0x7e, 0xe1, 0xc0, 0x45, 0x73, 0xf5, 0x05, 0x0c, 0xe0, 0x7b, 0xd3,
- 0xeb, 0x04, 0xe0, 0x7f, 0x72, 0x69, 0xae, 0x60, 0x63, 0xff, 0xd7, 0x5b,
- 0xe3, 0xe0, 0x2a, 0xaf, 0xef, 0x09, 0x04, 0x04, 0x60, 0x39, 0x00, 0xe0,
- 0x30, 0x9e, 0xf9, 0xe0, 0x3b, 0xc8, 0xe9, 0xe0, 0x22, 0x60, 0x66, 0x75,
- 0xeb, 0xe0, 0x64, 0x69, 0x68, 0x65, 0x72, 0xae, 0xe0, 0x76, 0x19, 0xe5,
- 0xe0, 0x76, 0xad, 0xe1, 0x0b, 0x06, 0x06, 0x60, 0x23, 0xdf, 0x60, 0x40,
- 0x5a, 0xc0, 0xc8, 0xf2, 0x60, 0x7c, 0x46, 0xc1, 0x73, 0x70, 0x2e, 0xe3,
- 0xe0, 0x72, 0xd1, 0xeb, 0x04, 0xe0, 0x21, 0xf7, 0x69, 0xae, 0x60, 0x76,
- 0xb9, 0x46, 0xf0, 0xc1, 0x3f, 0xf3, 0x0a, 0x04, 0x24, 0x06, 0x16, 0x09,
- 0x25, 0xe0, 0x78, 0x63, 0x1f, 0x43, 0xf8, 0xa6, 0xf4, 0x02, 0x9d, 0xf2,
- 0x02, 0x93, 0xef, 0x06, 0x46, 0x9e, 0xe0, 0x50, 0x71, 0xf7, 0x04, 0xe0,
- 0x6b, 0x79, 0x77, 0x6c, 0x6b, 0xf0, 0xe0, 0x7c, 0x02, 0x65, 0x2d, 0x74,
- 0xef, 0xe0, 0x38, 0x91, 0xe5, 0xe0, 0x73, 0x2e, 0x6f, 0x79, 0xf2, 0xe0,
- 0x78, 0xab, 0xe8, 0x02, 0x84, 0xf5, 0xe0, 0x47, 0xfd, 0xe9, 0x02, 0x84,
- 0xee, 0xe0, 0x47, 0xc6, 0x6d, 0x61, 0xae, 0x60, 0x7d, 0x25, 0xc1, 0x3a,
- 0xe5, 0x04, 0xe0, 0x7a, 0x80, 0xf4, 0xe0, 0x42, 0x50, 0xe1, 0x02, 0x85,
- 0x73, 0xe3, 0xe0, 0x73, 0xd3, 0xeb, 0x02, 0x8c, 0xe9, 0x04, 0xe0, 0x46,
- 0x92, 0x6b, 0x61, 0x6d, 0xe9, 0xe0, 0x4f, 0x7e, 0xe1, 0x06, 0x60, 0x7e,
- 0x9e, 0xc1, 0xa3, 0x73, 0x61, 0x79, 0xe1, 0xe0, 0x2a, 0x87, 0x2e, 0xe8,
- 0x02, 0x87, 0x6f, 0x72, 0x64, 0xe1, 0xe0, 0x73, 0x62, 0x65, 0xe4, 0xe0,
- 0x75, 0xe3, 0xf2, 0x0c, 0x04, 0x0d, 0x06, 0x0b, 0x40, 0xd2, 0x0f, 0x1b,
- 0xe0, 0x72, 0x2f, 0xf8, 0xe0, 0x7c, 0xf4, 0xf3, 0x07, 0x60, 0x51, 0x85,
- 0xe0, 0x28, 0xb5, 0x69, 0xf4, 0xe0, 0x7f, 0x01, 0xeb, 0x60, 0x6a, 0x00,
- 0xcf, 0x2f, 0xe9, 0x02, 0x84, 0x73, 0xf4, 0xd7, 0x93, 0xe7, 0xe0, 0x70,
- 0x5c, 0xe7, 0x05, 0x05, 0xe0, 0x7f, 0xf0, 0x61, 0xee, 0xe0, 0x70, 0xa6,
- 0xae, 0x21, 0x06, 0x0a, 0x18, 0x09, 0x0c, 0x17, 0x0e, 0x0b, 0x09, 0x10,
- 0x0d, 0x49, 0xb5, 0x1f, 0x2b, 0x60, 0x47, 0x6e, 0x2d, 0x40, 0x55, 0x4b,
- 0x50, 0x03, 0x12, 0x28, 0x40, 0x73, 0x5a, 0x96, 0xc4, 0x1f, 0xf9, 0x60,
- 0x7e, 0x5f, 0xc1, 0x4d, 0xf5, 0x60, 0x7d, 0x5b, 0x0d, 0x2f, 0x40, 0x97,
- 0xc1, 0x98, 0xf3, 0x60, 0x73, 0xd5, 0x41, 0xf3, 0x46, 0x4f, 0x41, 0x3a,
- 0x0a, 0x1a, 0x03, 0x15, 0x40, 0x79, 0x19, 0x05, 0x1c, 0x0f, 0x40, 0x43,
- 0xc1, 0x2a, 0xf2, 0x60, 0x7d, 0x3c, 0x07, 0x40, 0xe5, 0xc0, 0xf5, 0xee,
- 0x60, 0x7d, 0x30, 0x40, 0x5a, 0x40, 0x79, 0x40, 0x4f, 0xc1, 0x49, 0xed,
- 0x60, 0x78, 0x2b, 0x43, 0xbf, 0x41, 0x3a, 0x03, 0x07, 0x03, 0x17, 0x18,
- 0x40, 0x79, 0x1e, 0x1c, 0x0f, 0x40, 0x43, 0x38, 0xc0, 0xf2, 0xeb, 0x60,
- 0x7d, 0x0d, 0x03, 0x1e, 0x1b, 0x1e, 0x40, 0x83, 0x40, 0x64, 0xc1, 0x2a,
- 0xe9, 0x60, 0x5e, 0x00, 0x5f, 0x09, 0x17, 0x03, 0x40, 0xfe, 0x9f, 0xe8,
- 0x60, 0x7d, 0x01, 0x40, 0xa8, 0x40, 0x8c, 0xb8, 0xe7, 0x60, 0x7d, 0x0f,
- 0x18, 0x1e, 0x40, 0x5b, 0x19, 0x0f, 0x21, 0x24, 0x1f, 0x38, 0xc0, 0xf2,
- 0xe3, 0x60, 0x7b, 0xa1, 0x41, 0x3d, 0x39, 0x1e, 0x40, 0x95, 0x40, 0x52,
- 0xb8, 0xe2, 0x60, 0x75, 0x45, 0x47, 0x89, 0x03, 0x07, 0x17, 0x12, 0x27,
- 0x40, 0x5b, 0x19, 0x05, 0x1c, 0x33, 0x9f, 0x65, 0x67, 0x6f, 0xee, 0x04,
- 0xe0, 0x7c, 0x68, 0x74, 0x72, 0x61, 0xe9, 0xe0, 0x74, 0xf9, 0xe1, 0x05,
- 0x11, 0xe0, 0x76, 0xb2, 0x6e, 0x67, 0xe5, 0x04, 0xe0, 0x7f, 0x0d, 0x63,
- 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0xf4, 0xe0, 0x6a, 0xf2, 0xe3, 0xe0, 0x7d,
- 0x16, 0xae, 0x15, 0x06, 0x4a, 0x2b, 0x60, 0x37, 0xa3, 0x4c, 0x3a, 0x43,
- 0xf5, 0x5b, 0x78, 0x4d, 0x9b, 0x41, 0x7d, 0x40, 0x43, 0xc0, 0x71, 0xf4,
- 0x60, 0x7c, 0x7c, 0xc0, 0xce, 0xed, 0xe0, 0x7d, 0xef, 0xf0, 0x03, 0x11,
- 0x8b, 0xf0, 0x04, 0xe0, 0x77, 0xfa, 0x65, 0xe7, 0x04, 0xe0, 0x78, 0x70,
- 0x1f, 0x43, 0xe5, 0xe0, 0x7a, 0xd9, 0xef, 0x02, 0x84, 0xec, 0xe0, 0x40,
- 0xe7, 0xe3, 0xe0, 0x41, 0xbf, 0xe5, 0x02, 0x88, 0x72, 0x61, 0x75, 0x6e,
- 0xe9, 0xe0, 0x77, 0x32, 0xee, 0x06, 0x09, 0x0e, 0xe0, 0x7e, 0x96, 0x73,
- 0x6f, 0x63, 0x69, 0x61, 0xec, 0xe0, 0x67, 0x37, 0x63, 0x72, 0x61, 0x66,
- 0x74, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0xe9, 0xe0, 0x6a, 0xbc, 0x61, 0xe9,
- 0xe0, 0x77, 0x6b, 0xef, 0x07, 0x06, 0x04, 0x05, 0xe0, 0x7c, 0xfd, 0x73,
- 0x68, 0xe9, 0xe0, 0x33, 0xbd, 0xf0, 0xe0, 0x62, 0x38, 0x6b, 0xf5, 0xe0,
- 0x26, 0xb8, 0x67, 0xf5, 0xe0, 0x5f, 0xea, 0xee, 0x16, 0x03, 0x10, 0x0a,
- 0x09, 0x18, 0x13, 0x06, 0x09, 0x16, 0x0e, 0x08, 0x10, 0x60, 0x2b, 0x6c,
- 0x60, 0x45, 0xab, 0x4b, 0x10, 0xad, 0xfa, 0xc0, 0x87, 0xf4, 0x02, 0x88,
- 0x68, 0x65, 0x77, 0x69, 0xe6, 0xe0, 0x74, 0xda, 0x61, 0xf2, 0xe0, 0x44,
- 0xc9, 0x72, 0xe5, 0x04, 0xe0, 0x74, 0xd7, 0xe4, 0xe0, 0x36, 0xe8, 0x70,
- 0x6f, 0x72, 0x74, 0x65, 0xf2, 0xe0, 0x56, 0x03, 0xef, 0x05, 0x04, 0xe0,
- 0x62, 0x28, 0xed, 0xe0, 0x3b, 0x0c, 0xae, 0x04, 0xe0, 0x79, 0x7c, 0x66,
- 0x75, 0x6b, 0xf5, 0x60, 0x78, 0xdf, 0xc3, 0x40, 0xec, 0x04, 0xe0, 0x7e,
- 0x1b, 0x69, 0x6e, 0xe5, 0x04, 0xe0, 0x7e, 0x14, 0xae, 0x60, 0x35, 0x79,
- 0xe0, 0x45, 0xe2, 0x6a, 0x75, 0xeb, 0xe0, 0x44, 0x22, 0xe7, 0x60, 0x3c,
- 0x36, 0x60, 0x40, 0x84, 0xc1, 0x4c, 0xe6, 0x02, 0x8b, 0x6c, 0x61, 0x73,
- 0x68, 0x64, 0x72, 0x69, 0xf6, 0xe0, 0x68, 0xa0, 0x61, 0x62, 0x72, 0x69,
- 0xe3, 0xe0, 0x46, 0x78, 0x64, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x6f,
- 0x63, 0x65, 0xe1, 0xe0, 0x7c, 0x74, 0x63, 0x69, 0x6c, 0x6c, 0xe1, 0xe0,
- 0x64, 0xc4, 0xe1, 0x02, 0x89, 0x76, 0x73, 0x74, 0x61, 0x63, 0xeb, 0xe0,
- 0x7d, 0xa5, 0xe7, 0xe0, 0x44, 0x05, 0xad, 0x07, 0x0a, 0x11, 0x06, 0xe0,
- 0x7d, 0x04, 0x74, 0x68, 0x65, 0x2d, 0x77, 0x65, 0xe2, 0xe0, 0x6b, 0xba,
- 0xf2, 0x02, 0x85, 0x69, 0xef, 0xe0, 0x6f, 0xb2, 0x61, 0x6e, 0x63, 0x68,
- 0x65, 0xf2, 0xe0, 0x6e, 0x36, 0x6b, 0x33, 0xf3, 0xe0, 0x6f, 0xa3, 0xe1,
- 0x02, 0x88, 0x70, 0x74, 0x69, 0x62, 0xec, 0xe0, 0x76, 0x0d, 0x63, 0x6f,
- 0x72, 0xee, 0xe0, 0x6f, 0x91, 0xed, 0x0a, 0x06, 0x05, 0x05, 0x21, 0x06,
- 0x07, 0xe0, 0x7d, 0x3e, 0xf5, 0x56, 0x22, 0xe0, 0x25, 0x88, 0x6f, 0x74,
- 0xe5, 0xca, 0x15, 0x6e, 0x69, 0xf7, 0xd1, 0xe1, 0xe9, 0x08, 0x06, 0x0b,
- 0x60, 0x3a, 0xe6, 0xc9, 0x5d, 0x74, 0x61, 0xed, 0xe0, 0x37, 0x08, 0x68,
- 0x61, 0x63, 0x68, 0x69, 0x6d, 0x61, 0xee, 0xe0, 0x78, 0x24, 0x2e, 0xee,
- 0x60, 0x79, 0x38, 0xc1, 0x04, 0x67, 0x2e, 0xec, 0xe0, 0x56, 0x7f, 0xe5,
- 0x60, 0x2f, 0x36, 0xe0, 0x4a, 0xc5, 0xe1, 0x06, 0x04, 0x03, 0xe0, 0x53,
- 0xc2, 0xe8, 0xe0, 0x77, 0x18, 0xe5, 0xd5, 0xce, 0x63, 0x68, 0x69, 0xae,
- 0x60, 0x72, 0xd6, 0xc7, 0x41, 0xec, 0x0a, 0x06, 0x04, 0x05, 0x05, 0x07,
- 0x0d, 0xe0, 0x7b, 0x6d, 0x73, 0x7a, 0xf4, 0xe0, 0x5f, 0xe4, 0xec, 0xe0,
- 0x7b, 0x98, 0x6b, 0xf5, 0xe0, 0x26, 0xd4, 0x65, 0xe3, 0xe0, 0x21, 0x70,
- 0x64, 0x6e, 0x61, 0xf6, 0xe0, 0x7a, 0xd4, 0x62, 0x69, 0xe1, 0x02, 0x81,
- 0x2d, 0x74, 0x65, 0x6d, 0xf0, 0xe0, 0x64, 0x55, 0xe1, 0x04, 0xe0, 0x6a,
- 0x9c, 0x79, 0x61, 0xee, 0x5e, 0x38, 0xe0, 0x5e, 0xb4, 0xeb, 0x0c, 0x0f,
- 0x18, 0x09, 0x44, 0xe9, 0x60, 0x41, 0x97, 0xe0, 0x30, 0xa5, 0xf5, 0x04,
- 0x04, 0xdf, 0xeb, 0xf4, 0xe0, 0x37, 0xdf, 0x69, 0x7a, 0xf5, 0xe0, 0x38,
- 0x0a, 0xe9, 0x04, 0xe0, 0x65, 0x76, 0xee, 0x02, 0x83, 0xef, 0xc5, 0x0c,
- 0x61, 0x77, 0xe1, 0x04, 0xe0, 0x7c, 0xb9, 0xae, 0x60, 0x78, 0x47, 0xc2,
- 0xcf, 0xe5, 0x04, 0xe0, 0x21, 0x4d, 0x67, 0xe1, 0xc9, 0x8f, 0xe1, 0x04,
- 0x05, 0x0e, 0x88, 0x7a, 0xe1, 0xe0, 0x2b, 0x81, 0x79, 0xe1, 0x04, 0xe0,
- 0x79, 0x84, 0x6d, 0x61, 0xae, 0x60, 0x76, 0xfc, 0xc3, 0xf9, 0x77, 0x61,
- 0xae, 0x60, 0x71, 0x0c, 0xc5, 0xd4, 0xe7, 0xd0, 0x00, 0x6a, 0xe9, 0x04,
- 0xe0, 0x74, 0x9c, 0xf9, 0xe0, 0x2a, 0xb9, 0xe9, 0x07, 0x04, 0x08, 0x0b,
- 0xe0, 0x77, 0xc6, 0x7a, 0xf5, 0xd1, 0xb3, 0x74, 0x61, 0xae, 0x60, 0x6a,
- 0xdb, 0xcf, 0xf1, 0xf3, 0x04, 0xe0, 0x3a, 0xc1, 0x68, 0x69, 0xe4, 0xe0,
- 0x42, 0xf8, 0xf2, 0x02, 0x84, 0xed, 0xe0, 0x3c, 0xab, 0x61, 0xf3, 0xe0,
- 0x3e, 0xaa, 0xe8, 0x0a, 0x05, 0x06, 0x0e, 0x60, 0x3a, 0x15, 0xe0, 0x3c,
- 0x94, 0x74, 0x61, 0xf7, 0xc8, 0x69, 0x6b, 0x75, 0xf2, 0xe0, 0x42, 0xd6,
- 0xe9, 0x04, 0xe0, 0x4f, 0x96, 0x72, 0x61, 0xae, 0x60, 0x42, 0x78, 0xe0,
- 0x2e, 0x43, 0x61, 0xf2, 0xe0, 0x5f, 0xb5, 0xe7, 0x08, 0x10, 0x0b, 0x07,
- 0x1f, 0xe0, 0x54, 0x99, 0xf5, 0x02, 0x88, 0x6e, 0x69, 0xae, 0x60, 0x70,
- 0xfc, 0xc4, 0x0b, 0x63, 0xe8, 0xe0, 0x76, 0xea, 0xef, 0x02, 0x84, 0xf3,
- 0xe0, 0x23, 0xf2, 0xf2, 0xe0, 0x30, 0x41, 0xe9, 0x60, 0x3b, 0x40, 0xe0,
- 0x36, 0x6d, 0xe1, 0x0a, 0x0a, 0x06, 0x60, 0x3a, 0x51, 0x48, 0xce, 0xd2,
- 0xd5, 0x77, 0xe1, 0x04, 0xe0, 0x30, 0x48, 0xf2, 0xe0, 0x42, 0x2e, 0x73,
- 0x61, 0xf7, 0xe0, 0x36, 0x3e, 0xeb, 0xe0, 0x73, 0x7a, 0xae, 0x60, 0x4e,
- 0xfe, 0xe0, 0x2a, 0xe5, 0xe6, 0x03, 0x08, 0xaa, 0x75, 0x6e, 0x61, 0x74,
- 0xef, 0xe0, 0x43, 0x52, 0xe6, 0x02, 0xa3, 0x69, 0xe3, 0x02, 0x91, 0x69,
- 0x61, 0x6c, 0xae, 0x04, 0xe0, 0x6b, 0x59, 0x61, 0x63, 0x61, 0x64, 0x65,
- 0xed, 0xe0, 0x6a, 0xa4, 0xe5, 0x04, 0xe0, 0x7b, 0xaf, 0x2d, 0x6f, 0x6e,
- 0x2d, 0x74, 0xe8, 0xe0, 0x6d, 0xbb, 0xae, 0xe0, 0x5f, 0x67, 0xae, 0x05,
- 0x04, 0xe0, 0x7a, 0x12, 0xea, 0xe0, 0x7b, 0x36, 0xe2, 0xe0, 0x79, 0x67,
- 0xe4, 0x09, 0x0a, 0x60, 0x55, 0x18, 0x4a, 0xd8, 0xcf, 0x09, 0x65, 0xf3,
- 0x04, 0xe0, 0x57, 0x4b, 0xf3, 0xe0, 0x57, 0x4a, 0xe1, 0x02, 0x84, 0xf7,
- 0xe0, 0x2a, 0xbb, 0xf4, 0xe0, 0x3d, 0xf9, 0xe3, 0x05, 0x02, 0x02, 0x0d,
- 0x84, 0xf3, 0x84, 0xf0, 0x82, 0x69, 0x2e, 0x63, 0x75, 0x73, 0x74, 0x6f,
- 0x6d, 0x65, 0xf2, 0xe0, 0x56, 0x50, 0xe8, 0xe0, 0x40, 0x1e, 0xe5, 0x02,
- 0x86, 0x6c, 0x6f, 0xf4, 0xe0, 0x62, 0x43, 0x61, 0x6e, 0x6f, 0x67, 0x72,
- 0x61, 0x70, 0x68, 0xe9, 0x04, 0xe0, 0x60, 0x6e, 0xf1, 0xe0, 0x69, 0xcc,
- 0xe2, 0x05, 0x08, 0x05, 0x04, 0x8c, 0xf5, 0x04, 0xe0, 0x76, 0x0d, 0xf3,
- 0xde, 0xe4, 0x73, 0x65, 0xf2, 0xda, 0xbd, 0xee, 0xe0, 0x75, 0x3e, 0xe9,
- 0x06, 0x60, 0x79, 0x46, 0xc1, 0xdc, 0x68, 0xe9, 0xe0, 0x6f, 0x8e, 0xe1,
- 0x02, 0x85, 0x6e, 0x61, 0xfa, 0xd4, 0xf7, 0x6d, 0x61, 0xae, 0x60, 0x4e,
- 0x72, 0xd0, 0xad, 0xe1, 0x02, 0x85, 0x72, 0xe1, 0xe0, 0x5e, 0xfb, 0x6d,
- 0x69, 0x73, 0x68, 0x69, 0x72, 0x61, 0x73, 0x61, 0xf4, 0xe0, 0x79, 0x23,
- 0xee, 0x21, 0x18, 0x0b, 0x30, 0x1a, 0x1a, 0x14, 0x08, 0x41, 0xf0, 0x04,
- 0x1b, 0x09, 0x41, 0x47, 0x1c, 0x1d, 0x12, 0x41, 0xd7, 0x0b, 0x05, 0x42,
- 0xd7, 0x58, 0xc4, 0x58, 0x10, 0x54, 0xda, 0x51, 0xcc, 0xa6, 0x1f, 0xc3,
- 0x06, 0x05, 0x05, 0xe0, 0x6b, 0xf8, 0x78, 0x74, 0x74, 0xe5, 0x82, 0x66,
- 0xf2, 0xe0, 0x72, 0x9a, 0x65, 0x1f, 0x43, 0xe5, 0xc8, 0xe9, 0xfa, 0x04,
- 0xe0, 0x7a, 0xb9, 0xae, 0x60, 0x6d, 0xcb, 0xc6, 0xe2, 0xf9, 0x0a, 0x07,
- 0x04, 0x04, 0x0c, 0x56, 0xbb, 0xe0, 0x5e, 0x4d, 0x75, 0x7a, 0x65, 0xee,
- 0xe0, 0x41, 0x72, 0xf3, 0xe0, 0x6c, 0x31, 0xee, 0xe0, 0x72, 0x29, 0xe3,
- 0x04, 0xe0, 0x7a, 0x94, 0x2e, 0xed, 0x60, 0x66, 0x7e, 0xd1, 0x5d, 0xe1,
- 0x02, 0x84, 0xee, 0xe0, 0x79, 0x53, 0xe1, 0xc5, 0xa6, 0xf5, 0x07, 0x04,
- 0x52, 0xb1, 0xe0, 0x67, 0xc6, 0xef, 0xe0, 0x60, 0xdb, 0x6d, 0xe1, 0x04,
- 0xe0, 0x21, 0x53, 0x74, 0x61, 0xae, 0x60, 0x72, 0x1e, 0xc6, 0xa5, 0xf4,
- 0x06, 0x04, 0x06, 0xe0, 0x78, 0xa1, 0xf2, 0xe0, 0x79, 0x15, 0x64, 0x6c,
- 0x6c, 0xae, 0xc0, 0x6c, 0xae, 0x60, 0x77, 0x38, 0x04, 0x41, 0x81, 0x14,
- 0x88, 0xf3, 0x07, 0x04, 0x60, 0x60, 0x15, 0xd8, 0x93, 0xf7, 0xe0, 0x77,
- 0x24, 0x75, 0x70, 0x64, 0x61, 0xf4, 0xe0, 0x6a, 0x7c, 0xf2, 0x4c, 0x02,
- 0x60, 0x6c, 0x9f, 0xc1, 0x99, 0xef, 0x16, 0x0c, 0x26, 0x0c, 0x39, 0x14,
- 0x40, 0x6f, 0x09, 0x08, 0x40, 0x4c, 0x04, 0x08, 0x14, 0x08, 0x2a, 0x14,
- 0x08, 0xe0, 0x78, 0x57, 0x7a, 0x61, 0x77, 0x61, 0x6f, 0x6e, 0x73, 0x65,
- 0xee, 0xe0, 0x76, 0xfd, 0xf7, 0x0a, 0x05, 0x07, 0x60, 0x4f, 0x34, 0x59,
- 0xe1, 0xd0, 0xe4, 0x72, 0xf5, 0xe0, 0x77, 0x97, 0x61, 0x72, 0x75, 0xe4,
- 0xe0, 0x6b, 0x8d, 0x2d, 0x64, 0x6e, 0x73, 0xae, 0x06, 0x60, 0x77, 0x1d,
- 0xc2, 0xae, 0xf4, 0xe0, 0x69, 0xe0, 0xf6, 0x06, 0x52, 0xe6, 0xe0, 0x63,
- 0x72, 0x65, 0x63, 0xef, 0xce, 0x52, 0xf4, 0x07, 0x06, 0x0f, 0x15, 0xe0,
- 0x78, 0x60, 0x74, 0x65, 0xf2, 0xe0, 0x6e, 0x2e, 0xef, 0x05, 0x05, 0xe0,
- 0x72, 0x0a, 0x67, 0x61, 0xf7, 0xdd, 0x93, 0xe4, 0xe0, 0x37, 0xcb, 0x69,
- 0xe3, 0x02, 0x86, 0x69, 0x61, 0xf3, 0xe0, 0x77, 0x0b, 0x65, 0x61, 0x62,
- 0x6c, 0x65, 0x2e, 0x6e, 0xe5, 0xe0, 0x5b, 0x0c, 0x61, 0x69, 0x72, 0x65,
- 0xf3, 0xd1, 0x65, 0xf3, 0x02, 0x86, 0x68, 0x69, 0xf2, 0xe0, 0x40, 0xca,
- 0xe5, 0x04, 0xe0, 0x77, 0xc9, 0x67, 0x61, 0xf7, 0xe0, 0x2e, 0xf9, 0xf2,
- 0x04, 0x24, 0x06, 0x89, 0xf4, 0x04, 0xe0, 0x72, 0x68, 0xe8, 0x08, 0x0e,
- 0x60, 0x4d, 0x35, 0xe0, 0x29, 0x82, 0x77, 0x65, 0x73, 0x74, 0x65, 0x72,
- 0x6e, 0x6d, 0x75, 0x74, 0xf5, 0xe0, 0x51, 0xc5, 0x66, 0x6c, 0x61, 0x6e,
- 0xeb, 0xe0, 0x68, 0x08, 0x66, 0x6f, 0xec, 0xe0, 0x71, 0x0e, 0x65, 0x2d,
- 0x6f, 0x67, 0x2d, 0xf5, 0xe0, 0x72, 0x7f, 0xe4, 0x07, 0x0c, 0x04, 0x0c,
- 0xe0, 0x72, 0x59, 0x72, 0xe5, 0x02, 0x84, 0xe9, 0xe0, 0x3e, 0xd0, 0xad,
- 0xe0, 0x6c, 0x78, 0x6b, 0xe1, 0xdd, 0xac, 0x65, 0x73, 0x74, 0x65, 0x2d,
- 0x69, 0x64, 0x63, 0xae, 0xe0, 0x25, 0xc6, 0xad, 0x03, 0x04, 0x86, 0xef,
- 0xe0, 0x72, 0x54, 0x66, 0x72, 0xef, 0xe0, 0x73, 0x47, 0x61, 0xf5, 0xe0,
- 0x49, 0x87, 0xef, 0x04, 0xe0, 0x66, 0x5a, 0xf0, 0xe0, 0x77, 0xb4, 0x6e,
- 0x6f, 0x69, 0x63, 0xe8, 0xe0, 0x37, 0x2d, 0xed, 0x06, 0x0a, 0x05, 0xe0,
- 0x37, 0x14, 0x65, 0xae, 0x04, 0xe0, 0x2b, 0x9f, 0xe3, 0xe0, 0x75, 0x5d,
- 0x62, 0xf2, 0xe0, 0x51, 0x42, 0xae, 0x14, 0x04, 0x05, 0x07, 0x06, 0x05,
- 0x5b, 0x58, 0x60, 0x51, 0x76, 0x38, 0x40, 0xf7, 0x40, 0xbe, 0x45, 0xce,
- 0xc0, 0x80, 0xf4, 0xe0, 0x76, 0x9a, 0xf2, 0x60, 0x77, 0x64, 0x8f, 0xf0,
- 0x60, 0x76, 0x94, 0x40, 0xaf, 0xab, 0xee, 0x60, 0x6c, 0xed, 0xc9, 0xd6,
- 0x62, 0xf2, 0xe0, 0x67, 0xc8, 0xe1, 0x60, 0x76, 0x85, 0xc2, 0x44, 0xeb,
- 0xe0, 0x6d, 0x2a, 0x69, 0x70, 0xae, 0x60, 0x59, 0xa8, 0xc9, 0x1d, 0xe8,
- 0x02, 0x8c, 0xef, 0x02, 0x85, 0x73, 0xf4, 0xe0, 0x62, 0xb7, 0xae, 0xe0,
- 0x59, 0xfe, 0x65, 0xea, 0xe0, 0x35, 0xbc, 0xe7, 0x48, 0x33, 0x60, 0x26,
- 0xb7, 0xc7, 0xe8, 0xe4, 0x02, 0x9f, 0xe5, 0x02, 0x8d, 0x73, 0x2e, 0x6b,
- 0x38, 0x73, 0xae, 0x60, 0x22, 0xf2, 0x09, 0xe0, 0x20, 0x47, 0x62, 0x61,
- 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x72, 0x2e, 0x6c, 0x69, 0xee, 0xe0, 0x61,
- 0xa3, 0x61, 0xae, 0x60, 0x3f, 0xfd, 0xe0, 0x36, 0xa6, 0xe2, 0x03, 0x06,
- 0x86, 0x75, 0x73, 0xe8, 0xe0, 0x51, 0x73, 0x6f, 0x72, 0xe9, 0xe0, 0x73,
- 0xd8, 0x65, 0xef, 0xca, 0x44, 0xae, 0x60, 0x72, 0x53, 0x44, 0x10, 0xc1,
- 0xf4, 0x2d, 0x69, 0x70, 0xae, 0x0a, 0x60, 0x68, 0x89, 0x4c, 0x99, 0x40,
- 0x56, 0xc2, 0xae, 0xe3, 0x60, 0x68, 0x6e, 0xcc, 0x88, 0xed, 0xe0, 0x33,
- 0xcc, 0xec, 0x05, 0x0d, 0xe0, 0x78, 0x2c, 0xae, 0x06, 0x60, 0x72, 0x27,
- 0xc4, 0x85, 0xe3, 0x60, 0x76, 0x98, 0xc1, 0x41, 0x2d, 0x61, 0x6d, 0x73,
- 0xad, 0xe0, 0x41, 0xc2, 0xea, 0x04, 0xe0, 0x72, 0x9a, 0xf3, 0xe0, 0x6b,
- 0xa5, 0xe9, 0x0f, 0x09, 0x0d, 0x40, 0x96, 0x07, 0x12, 0x23, 0x1f, 0x14,
- 0x60, 0x6d, 0xb6, 0xc9, 0x3a, 0x79, 0x6f, 0x64, 0x6f, 0x67, 0x61, 0xf7,
- 0xc9, 0x94, 0xf4, 0x02, 0x84, 0xf4, 0xe0, 0x4d, 0x9b, 0x65, 0x72, 0xef,
- 0xe0, 0x70, 0x31, 0xf3, 0x05, 0x11, 0xe0, 0x73, 0x9b, 0xf3, 0x05, 0x05,
- 0xe0, 0x4d, 0x81, 0x68, 0xe9, 0xe0, 0x34, 0x19, 0xe1, 0x60, 0x75, 0xb3,
- 0xc1, 0x05, 0x68, 0xe9, 0x0c, 0x04, 0x05, 0x0c, 0x19, 0x04, 0x10, 0x03,
- 0x0a, 0x1c, 0xc4, 0x07, 0xf7, 0xe0, 0x70, 0xc8, 0x74, 0x6f, 0xf3, 0xc9,
- 0x59, 0xef, 0x04, 0xe0, 0x72, 0x9a, 0x6b, 0x6f, 0x70, 0xf0, 0xe0, 0x5b,
- 0x3c, 0x6e, 0xef, 0x03, 0x07, 0x87, 0x73, 0x68, 0x69, 0xed, 0xe0, 0x35,
- 0x9a, 0x6f, 0x6d, 0x6f, 0xf4, 0xe0, 0x71, 0xb1, 0x6d, 0x69, 0xf9, 0xe0,
- 0x34, 0xe1, 0x6d, 0xe5, 0xdc, 0x68, 0x6b, 0xe1, 0x03, 0xd1, 0x7a, 0xf4,
- 0x04, 0xe0, 0x6c, 0x19, 0x73, 0x75, 0xf2, 0xe0, 0x3e, 0x9f, 0xe9, 0xde,
- 0x6f, 0x68, 0x61, 0x72, 0x61, 0xae, 0x60, 0x70, 0x73, 0xc2, 0xa2, 0xe1,
- 0x04, 0x05, 0x08, 0x85, 0x7a, 0xe1, 0xe0, 0x32, 0x6e, 0x77, 0x61, 0x6b,
- 0x75, 0xf2, 0xe0, 0x71, 0xd5, 0x72, 0xe9, 0xe0, 0x6d, 0x03, 0x69, 0xfa,
- 0xe0, 0x72, 0x09, 0xae, 0x60, 0x6b, 0xe1, 0xc9, 0xb6, 0x72, 0x61, 0x73,
- 0xe1, 0xe0, 0x3e, 0xd8, 0xee, 0x02, 0x8b, 0xef, 0x04, 0xe0, 0x2d, 0x7d,
- 0x6d, 0x69, 0xf9, 0xe0, 0x72, 0xb4, 0xea, 0xe0, 0x75, 0xb0, 0xeb, 0x07,
- 0x09, 0x04, 0x09, 0xe0, 0x75, 0xba, 0xef, 0x04, 0xe0, 0x76, 0x0e, 0x6c,
- 0xe1, 0xdd, 0x14, 0xeb, 0xe0, 0x66, 0x90, 0xe9, 0x04, 0xe0, 0x75, 0x80,
- 0xf4, 0xe0, 0x67, 0xee, 0x61, 0xe8, 0xe0, 0x3e, 0x51, 0xe9, 0x05, 0x04,
- 0x04, 0x04, 0x83, 0xfa, 0xe0, 0x3e, 0x0e, 0xed, 0xe0, 0x6b, 0xda, 0x6b,
- 0xe1, 0xd8, 0x84, 0xe8, 0xcf, 0xb3, 0x67, 0x61, 0x74, 0x61, 0xae, 0x60,
- 0x72, 0xf0, 0xc2, 0x77, 0xe5, 0x02, 0x8d, 0x72, 0x75, 0x63, 0x68, 0x6f,
- 0x6d, 0x6f, 0x73, 0x63, 0xe9, 0xe0, 0x72, 0x67, 0xf0, 0xe0, 0x64, 0x4f,
- 0xe3, 0x05, 0x0b, 0xe0, 0x75, 0x62, 0x68, 0x69, 0x6e, 0x61, 0x6e, 0xae,
- 0x60, 0x5a, 0x4e, 0xce, 0xdc, 0xae, 0x06, 0x60, 0x72, 0x96, 0xc3, 0x16,
- 0xf4, 0xe0, 0x74, 0x9e, 0xe8, 0x08, 0x06, 0x05, 0x60, 0x71, 0x3b, 0xc3,
- 0x26, 0x73, 0x2e, 0xf5, 0xe0, 0x74, 0x69, 0x6c, 0xe6, 0xe0, 0x4f, 0xcf,
- 0x2d, 0x73, 0x65, 0x72, 0xf6, 0xe0, 0x73, 0x67, 0xe7, 0x07, 0x05, 0x60,
- 0x6a, 0x03, 0xcc, 0xa8, 0x72, 0xef, 0xe0, 0x60, 0x4d, 0xef, 0x04, 0xe0,
- 0x76, 0xa6, 0xae, 0x60, 0x2d, 0x38, 0x60, 0x35, 0x90, 0x48, 0x03, 0xc7,
- 0x98, 0xe6, 0x07, 0x03, 0x60, 0x74, 0xf5, 0xc1, 0x9b, 0xf3, 0xc5, 0xfe,
- 0xec, 0x60, 0x55, 0xbb, 0xe0, 0x20, 0xd4, 0xe5, 0x13, 0x05, 0x11, 0x35,
- 0x0a, 0x40, 0xfe, 0x2d, 0x0f, 0x05, 0x06, 0x09, 0x06, 0x08, 0x60, 0x68,
- 0xdc, 0xcb, 0xe8, 0x79, 0xe1, 0xe0, 0x31, 0x2c, 0xf8, 0x04, 0xe0, 0x71,
- 0x92, 0xf4, 0x04, 0xe0, 0x76, 0x66, 0x64, 0x69, 0x72, 0xe5, 0xe0, 0x53,
- 0x77, 0xf7, 0x09, 0x05, 0x0d, 0x05, 0x07, 0x06, 0xe0, 0x76, 0x31, 0x79,
- 0xef, 0xe0, 0x4e, 0xb9, 0xf3, 0x06, 0x60, 0x75, 0x54, 0xc0, 0xf5, 0x70,
- 0x61, 0xf0, 0xe0, 0x6f, 0x1c, 0x70, 0xef, 0xe0, 0x6e, 0xfd, 0x6d, 0x65,
- 0x78, 0xe9, 0xe0, 0x6b, 0x8b, 0x6a, 0x65, 0xf2, 0xe0, 0x35, 0xa0, 0x68,
- 0x61, 0x6d, 0x70, 0xf3, 0xd5, 0xd9, 0xf5, 0x04, 0xe0, 0x6e, 0xea, 0x73,
- 0xf4, 0xe0, 0x64, 0x47, 0xf4, 0x0d, 0x07, 0x06, 0x40, 0xdb, 0x60, 0x3f,
- 0xab, 0x53, 0x5a, 0xe0, 0x22, 0x25, 0x6c, 0x69, 0x66, 0xf9, 0xe0, 0x74,
- 0xa6, 0x66, 0x6c, 0xe9, 0xe0, 0x6e, 0xa3, 0xae, 0x1f, 0x08, 0x0c, 0x12,
- 0x0e, 0x0c, 0x14, 0x0b, 0x05, 0x0c, 0x0e, 0x05, 0x0a, 0x0c, 0x10, 0x4a,
- 0xd7, 0x60, 0x3c, 0x55, 0x40, 0x6f, 0x2c, 0x29, 0x4b, 0x4c, 0x04, 0x03,
- 0x3a, 0xdb, 0x09, 0xf5, 0x60, 0x73, 0x78, 0x0d, 0x2f, 0xc0, 0x97, 0xf4,
- 0x60, 0x73, 0x73, 0x1e, 0x12, 0x40, 0x82, 0x19, 0x21, 0x33, 0x9f, 0xf3,
- 0x60, 0x69, 0xe8, 0x41, 0xf3, 0x47, 0x93, 0x1a, 0x03, 0x15, 0x40, 0x79,
- 0x19, 0x05, 0x1c, 0xc1, 0x7c, 0xf0, 0x60, 0x73, 0x5c, 0x03, 0x17, 0x18,
- 0x40, 0x79, 0x19, 0x05, 0x2b, 0x24, 0x9f, 0xee, 0x60, 0x6a, 0xe6, 0x48,
- 0x5e, 0x40, 0x5a, 0x40, 0xc8, 0xc1, 0x49, 0xed, 0x60, 0x6e, 0x3f, 0x43,
- 0xbf, 0x41, 0x3a, 0x03, 0x07, 0x03, 0x17, 0x18, 0x40, 0x79, 0x1e, 0x1c,
- 0x0f, 0xc0, 0x7b, 0xeb, 0x60, 0x73, 0x24, 0x03, 0x39, 0x1e, 0x40, 0xe7,
- 0xc1, 0x2a, 0xea, 0x60, 0x74, 0x08, 0x8f, 0xe9, 0x60, 0x54, 0x15, 0x5f,
- 0x09, 0x17, 0x03, 0x03, 0x40, 0xfb, 0x9f, 0xe7, 0x60, 0x73, 0x2c, 0x18,
- 0x40, 0x79, 0x28, 0x21, 0x24, 0x1f, 0x38, 0xc0, 0xf2, 0xe6, 0x60, 0x73,
- 0x1b, 0x92, 0xe5, 0x60, 0x69, 0x79, 0x45, 0xde, 0x44, 0x53, 0xc1, 0xb6,
- 0xe3, 0x60, 0x72, 0xee, 0x1e, 0x1b, 0x1e, 0x40, 0x95, 0x40, 0x52, 0xb8,
- 0xe2, 0x60, 0x6b, 0x56, 0x47, 0x89, 0x0a, 0x17, 0x12, 0x40, 0x82, 0x19,
- 0x05, 0x1c, 0x33, 0x9f, 0xe1, 0x60, 0x69, 0x53, 0x41, 0x1e, 0x48, 0x5e,
- 0x21, 0x03, 0x36, 0x40, 0xa4, 0x24, 0x40, 0x57, 0xc0, 0xf2, 0x2d, 0x66,
- 0x72, 0x65, 0xe1, 0xe0, 0x3f, 0x69, 0xf3, 0x06, 0x07, 0x0b, 0xe0, 0x6a,
- 0x87, 0x73, 0xe5, 0x53, 0xed, 0xe0, 0x59, 0xac, 0x6f, 0x64, 0xe4, 0x04,
- 0xe0, 0x66, 0x0c, 0xf4, 0xe0, 0x66, 0x08, 0xae, 0x02, 0x8a, 0x62, 0x75,
- 0x73, 0x6b, 0x65, 0x72, 0xf5, 0xe0, 0x71, 0x0c, 0x61, 0x6b, 0x65, 0x72,
- 0xf3, 0xcc, 0x15, 0xf2, 0x04, 0xe0, 0x6f, 0x35, 0x64, 0x70, 0x6f, 0x6c,
- 0x2e, 0x6f, 0xf6, 0xe0, 0x74, 0x3c, 0x6d, 0xf5, 0xe0, 0x69, 0x52, 0x6b,
- 0x6f, 0xae, 0xe0, 0x4b, 0xc5, 0x64, 0x72, 0x65, 0x2d, 0x65, 0xe9, 0xe0,
- 0x21, 0x0a, 0x62, 0x72, 0xe1, 0xe0, 0x6e, 0x9d, 0x61, 0x74, 0x2d, 0x75,
- 0xf2, 0xe0, 0x6e, 0x30, 0xae, 0x0b, 0x60, 0x2c, 0x6c, 0x60, 0x36, 0xde,
- 0x4f, 0x18, 0xc0, 0xb4, 0xf5, 0x60, 0x72, 0x55, 0xc2, 0x61, 0xe3, 0x04,
- 0xe0, 0x74, 0xad, 0xae, 0x60, 0x67, 0x61, 0xc8, 0x72, 0xe2, 0x60, 0x73,
- 0x0b, 0x82, 0xe1, 0x1d, 0x04, 0x10, 0x0b, 0x40, 0x7f, 0x10, 0x30, 0x0d,
- 0x08, 0x40, 0x45, 0x40, 0x68, 0x06, 0x40, 0x7a, 0x04, 0x0a, 0x40, 0x68,
- 0x0d, 0x09, 0x08, 0x60, 0x6f, 0xd4, 0xc1, 0xfc, 0xf9, 0xe0, 0x68, 0xf0,
- 0xf6, 0x0a, 0x60, 0x65, 0xab, 0x44, 0xa5, 0x47, 0x3f, 0xc0, 0xb6, 0x6f,
- 0xe9, 0xe0, 0x72, 0x90, 0xf5, 0x02, 0x84, 0xf3, 0xe0, 0x2d, 0xd4, 0xed,
- 0xe0, 0x57, 0x92, 0xf4, 0x0a, 0x40, 0x4d, 0x4d, 0x4c, 0x60, 0x30, 0xce,
- 0xc6, 0x31, 0xf5, 0x02, 0x90, 0x75, 0x72, 0x77, 0x65, 0x74, 0x65, 0x6e,
- 0x73, 0x63, 0x68, 0x61, 0x70, 0xf0, 0xe0, 0x5e, 0xd0, 0xf2, 0x07, 0x0c,
- 0x4b, 0xb3, 0xe0, 0x64, 0x3a, 0x62, 0x72, 0x75, 0x6b, 0x73, 0x67, 0x79,
- 0x6d, 0xee, 0xe0, 0x63, 0x2c, 0xe1, 0x04, 0xe0, 0x74, 0x2e, 0xec, 0x05,
- 0x09, 0xe0, 0x71, 0x70, 0x73, 0x63, 0x69, 0x65, 0x6e, 0xe3, 0xe0, 0x6c,
- 0xe7, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0xf9, 0x04, 0xe0, 0x71, 0x5b,
- 0x6d, 0x75, 0x73, 0xe5, 0xe0, 0x6a, 0x37, 0xe9, 0x02, 0x8b, 0x76, 0x65,
- 0x61, 0x6d, 0x65, 0x72, 0x69, 0xe3, 0xe0, 0x45, 0x8c, 0x6f, 0x6e, 0x61,
- 0xec, 0x05, 0x06, 0xe0, 0x71, 0x37, 0x68, 0x65, 0xf2, 0xe0, 0x2f, 0xd8,
- 0x66, 0x69, 0x72, 0x65, 0x61, 0x72, 0xed, 0xe0, 0x6c, 0xaf, 0x73, 0xf5,
- 0x04, 0xe0, 0x68, 0x66, 0x73, 0x68, 0x69, 0x6f, 0x62, 0x61, 0xf2, 0xe0,
- 0x68, 0x5e, 0xf2, 0x07, 0x08, 0x0b, 0x05, 0xe0, 0x68, 0x11, 0x76, 0xe9,
- 0x60, 0x39, 0x13, 0xe0, 0x30, 0x72, 0xf5, 0x02, 0x84, 0xf4, 0xe0, 0x22,
- 0x22, 0xf3, 0xe0, 0x30, 0x76, 0x69, 0xf4, 0xe0, 0x31, 0x50, 0xe1, 0x02,
- 0x87, 0x73, 0x68, 0x69, 0xee, 0xe0, 0x71, 0xd7, 0xae, 0x60, 0x6b, 0xc7,
- 0xc6, 0x42, 0xf0, 0x02, 0x85, 0x6f, 0xec, 0xe0, 0x6b, 0xb3, 0x6c, 0xe5,
- 0xe0, 0x5a, 0x7f, 0x6f, 0x73, 0x68, 0x69, 0xed, 0xe0, 0x65, 0xcd, 0xee,
- 0x0a, 0x05, 0x0c, 0x04, 0x04, 0x05, 0x07, 0x03, 0x04, 0x88, 0x79, 0xef,
- 0xe0, 0x3a, 0x1c, 0xf4, 0x02, 0x84, 0xef, 0xe0, 0x3a, 0x4b, 0x61, 0xee,
- 0xe0, 0x65, 0xb8, 0xf0, 0xe0, 0x67, 0xe1, 0xee, 0xe0, 0x2a, 0x6a, 0x6d,
- 0x6f, 0xeb, 0xd8, 0xd8, 0x6b, 0x6f, 0x6b, 0xf5, 0xe0, 0x6d, 0xb4, 0xea,
- 0xd8, 0x87, 0xe7, 0xe0, 0x6e, 0x07, 0x62, 0x75, 0xae, 0x60, 0x56, 0x4d,
- 0xc0, 0x74, 0xe1, 0x40, 0xa8, 0xe0, 0x56, 0x27, 0xed, 0x05, 0x0f, 0x0a,
- 0x3f, 0x85, 0xf3, 0x02, 0x88, 0x73, 0x6b, 0x6f, 0x67, 0xe1, 0xe0, 0x6d,
- 0x5b, 0xef, 0xe0, 0x6f, 0x17, 0xe9, 0x04, 0xe0, 0x6d, 0xe6, 0x6b, 0xe1,
- 0xe0, 0x28, 0x8d, 0xe5, 0x06, 0x03, 0x0a, 0xe0, 0x73, 0x19, 0xf2, 0xc0,
- 0x8b, 0x67, 0xe1, 0x04, 0xe0, 0x2c, 0xbc, 0xf7, 0xe0, 0x3a, 0x0e, 0xae,
- 0x13, 0x06, 0x07, 0x06, 0x45, 0xdd, 0x60, 0x35, 0x0c, 0x56, 0x4a, 0x40,
- 0x48, 0x4e, 0x7e, 0x50, 0x67, 0xc0, 0x58, 0xf0, 0x60, 0x71, 0xba, 0xc1,
- 0x45, 0xed, 0x60, 0x6f, 0x58, 0x41, 0x47, 0xaf, 0xe5, 0x60, 0x71, 0x40,
- 0xc1, 0xb6, 0xe1, 0xe0, 0x70, 0x85, 0x64, 0x61, 0xec, 0xd3, 0x83, 0x61,
- 0xf3, 0xe0, 0x52, 0x47, 0x6c, 0x63, 0x68, 0xe9, 0xc4, 0x01, 0xeb, 0x03,
- 0x04, 0x86, 0xec, 0xe0, 0x35, 0xd8, 0x69, 0x6a, 0xe9, 0xe0, 0x36, 0xcd,
- 0xe1, 0x0c, 0x0f, 0x03, 0x1d, 0x0f, 0x13, 0x08, 0x5b, 0xa7, 0xe0, 0x4a,
- 0x39, 0xf4, 0x04, 0x05, 0xc7, 0xa1, 0x73, 0xf5, 0xe0, 0x29, 0x20, 0x6f,
- 0xed, 0xe0, 0x6e, 0x29, 0xf3, 0xd3, 0xc9, 0xee, 0x02, 0x93, 0xef, 0x03,
- 0x05, 0x85, 0x74, 0xef, 0xe0, 0x6a, 0xed, 0x6a, 0xef, 0xe0, 0x6a, 0x52,
- 0xae, 0x60, 0x6f, 0x57, 0xb3, 0x69, 0x69, 0x6b, 0x61, 0xf7, 0xde, 0x44,
- 0xed, 0x05, 0x04, 0xe0, 0x30, 0xba, 0x75, 0xf2, 0xc4, 0x1c, 0x69, 0xe3,
- 0xe0, 0x48, 0x56, 0xe7, 0x05, 0x40, 0x77, 0xd6, 0xe2, 0x61, 0x77, 0x61,
- 0xae, 0x60, 0x66, 0xf8, 0x46, 0x30, 0x42, 0x3e, 0xc1, 0x6a, 0x64, 0x6f,
- 0x6d, 0x61, 0xf2, 0xe0, 0x2f, 0x81, 0xae, 0x60, 0x67, 0x20, 0xc3, 0xd5,
- 0xe9, 0xe0, 0x55, 0xe1, 0x68, 0xe1, 0x04, 0xe0, 0x6d, 0xe8, 0xf2, 0xe0,
- 0x37, 0x1a, 0xe7, 0x03, 0x0c, 0x89, 0xef, 0x04, 0xe0, 0x6d, 0xdb, 0x79,
- 0xe1, 0x57, 0x3b, 0xe0, 0x5b, 0x10, 0xe9, 0x04, 0xe0, 0x6c, 0xa5, 0xf3,
- 0xe0, 0x64, 0x58, 0xe1, 0x09, 0x07, 0x10, 0x0c, 0x0b, 0x0f, 0x04, 0xda,
- 0x2d, 0x74, 0xef, 0x45, 0xe5, 0xe0, 0x6a, 0x3d, 0xf3, 0x02, 0x84, 0xf5,
- 0xe0, 0x6b, 0x14, 0x61, 0x6b, 0x69, 0xae, 0x60, 0x56, 0x2e, 0xda, 0x51,
- 0xf2, 0x04, 0xe0, 0x2f, 0xae, 0x65, 0x79, 0x61, 0xed, 0xe0, 0x2f, 0xaa,
- 0x6f, 0x6b, 0xe1, 0x04, 0xe0, 0x6d, 0xef, 0x6b, 0xf9, 0xdd, 0x76, 0x6e,
- 0xef, 0x02, 0x85, 0x68, 0xe1, 0xe0, 0x20, 0x6d, 0xae, 0x60, 0x6e, 0xe6,
- 0xc1, 0x73, 0xe9, 0xe0, 0x38, 0x8d, 0x68, 0xe1, 0xc3, 0xed, 0x63, 0x68,
- 0x69, 0x6b, 0x61, 0x74, 0x73, 0x75, 0x75, 0xf2, 0xe0, 0x67, 0x84, 0xe2,
- 0x04, 0xe0, 0x71, 0xdc, 0x61, 0xf2, 0xd7, 0x25, 0x61, 0x6d, 0x65, 0x73,
- 0x6a, 0xe5, 0xd1, 0xbe, 0x34, 0xf5, 0xe0, 0x71, 0x44, 0xb4, 0xe0, 0x3d,
- 0x9d, 0xed, 0x26, 0x23, 0x41, 0xa9, 0x09, 0x07, 0x40, 0xcb, 0x12, 0x17,
- 0x0d, 0x06, 0x41, 0xcf, 0x07, 0x10, 0x0e, 0x06, 0x0d, 0x43, 0x50, 0x07,
- 0x41, 0x61, 0x0b, 0x28, 0x0b, 0x60, 0x3b, 0xa3, 0x4a, 0xb2, 0x5d, 0xc5,
- 0x41, 0x3a, 0xc0, 0xce, 0x9f, 0x02, 0x84, 0x44, 0xc1, 0xcb, 0x31, 0xc3,
- 0x02, 0x8a, 0xe5, 0x02, 0x84, 0xf3, 0xe0, 0x69, 0x65, 0xec, 0xcb, 0x7c,
- 0xe1, 0x02, 0x89, 0x74, 0x74, 0x61, 0x2d, 0x76, 0x1f, 0xc3, 0xca, 0x0b,
- 0xec, 0xcb, 0x85, 0xf9, 0x18, 0x05, 0x05, 0x20, 0x40, 0x57, 0x21, 0x05,
- 0x19, 0x07, 0x07, 0x07, 0x05, 0x32, 0x08, 0x28, 0x0d, 0x1c, 0x06, 0x60,
- 0x69, 0x68, 0xc6, 0x91, 0x77, 0xe9, 0xe0, 0x5c, 0x57, 0x76, 0xee, 0xe0,
- 0x49, 0xdd, 0xf4, 0x03, 0x07, 0x85, 0x75, 0x6c, 0x65, 0xe1, 0xe0, 0x70,
- 0x6c, 0x69, 0xf3, 0xe0, 0x70, 0xc3, 0x61, 0x62, 0x69, 0x74, 0x2e, 0x63,
- 0xef, 0x04, 0xe0, 0x71, 0x3a, 0x2e, 0xe9, 0xe0, 0x70, 0x8a, 0xf3, 0x03,
- 0x37, 0x8c, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73, 0x68, 0x6f, 0x70, 0xae,
- 0x0e, 0x07, 0x06, 0x60, 0x5d, 0x09, 0x04, 0x49, 0x77, 0x49, 0xe3, 0x0c,
- 0x2e, 0x8a, 0xee, 0x60, 0x70, 0x6a, 0x40, 0x78, 0x99, 0xe9, 0x60, 0x70,
- 0xb1, 0xc0, 0x44, 0xe3, 0x06, 0x60, 0x61, 0x30, 0xcf, 0x2d, 0xef, 0x04,
- 0xe0, 0x6d, 0xb4, 0xed, 0x48, 0x3c, 0xe0, 0x68, 0xc4, 0x68, 0x6f, 0xf0,
- 0x04, 0xe0, 0x3b, 0x38, 0x69, 0xe6, 0xe0, 0x52, 0x68, 0x65, 0x63, 0x75,
- 0x72, 0x69, 0x74, 0x79, 0x63, 0x61, 0x6d, 0x65, 0x72, 0xe1, 0xe0, 0x5d,
- 0x5a, 0xf0, 0x04, 0x03, 0x04, 0x87, 0xf3, 0xdc, 0xd5, 0xe9, 0xe0, 0x57,
- 0x8d, 0x68, 0x6f, 0x74, 0xef, 0xe0, 0x38, 0x78, 0xe5, 0x02, 0x86, 0x74,
- 0x73, 0xae, 0xe0, 0x52, 0x27, 0x70, 0xae, 0xe0, 0x4b, 0x5c, 0x6f, 0xeb,
- 0xe0, 0x6c, 0xa5, 0xed, 0x02, 0x88, 0x65, 0x64, 0x69, 0x61, 0xf0, 0xe0,
- 0x44, 0x4b, 0x61, 0x69, 0x6c, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x2e,
- 0xf4, 0xe0, 0x5c, 0x5c, 0x6b, 0x6f, 0x6c, 0xe1, 0xe0, 0x55, 0x03, 0x6a,
- 0x69, 0x6e, 0xef, 0xe0, 0x70, 0x0f, 0x69, 0x70, 0x68, 0xef, 0xe0, 0x22,
- 0x5d, 0x68, 0x6f, 0xed, 0xcf, 0x86, 0xe6, 0x06, 0x08, 0x06, 0x10, 0xc0,
- 0x89, 0x74, 0x70, 0xae, 0x60, 0x6d, 0x59, 0xc0, 0x56, 0x72, 0x69, 0xf4,
- 0xe0, 0x39, 0x12, 0x6f, 0x72, 0x75, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
- 0x75, 0x6e, 0x69, 0xf4, 0xe0, 0x5f, 0x55, 0x61, 0x73, 0x74, 0xae, 0x04,
- 0xe0, 0x51, 0xac, 0x73, 0xf0, 0xe0, 0x50, 0x20, 0x65, 0x66, 0x66, 0x65,
- 0xe3, 0xe0, 0x63, 0xeb, 0xe4, 0x07, 0x06, 0x06, 0x07, 0x06, 0xcc, 0xa3,
- 0x72, 0x6f, 0xe2, 0xe0, 0x38, 0xab, 0x6f, 0x62, 0xe9, 0xe0, 0x20, 0x72,
- 0x69, 0x73, 0x73, 0xe5, 0xe0, 0x51, 0x4c, 0x64, 0x6e, 0x73, 0xae, 0xcd,
- 0xca, 0x61, 0x74, 0x74, 0xef, 0xe0, 0x6c, 0xcd, 0xe3, 0x02, 0x87, 0x6c,
- 0x6f, 0x75, 0x64, 0xae, 0xc7, 0xcd, 0xe4, 0xdc, 0xcb, 0xe1, 0x03, 0x06,
- 0x86, 0x73, 0x75, 0xf3, 0xe0, 0x62, 0x88, 0x6d, 0x61, 0xfa, 0xe0, 0x62,
- 0x20, 0x63, 0x74, 0x69, 0x76, 0x65, 0x64, 0x69, 0x72, 0x65, 0xe3, 0xd2,
- 0x01, 0xae, 0x60, 0x67, 0xda, 0xc2, 0x19, 0xad, 0x06, 0x05, 0x06, 0x0a,
- 0xc7, 0x32, 0x77, 0xe1, 0xe0, 0x44, 0xeb, 0x72, 0x6f, 0xf5, 0xe0, 0x24,
- 0x8c, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0xf9, 0xe0, 0x4a, 0xcb, 0x66,
- 0x69, 0x72, 0x65, 0x77, 0x61, 0xec, 0xdf, 0x7a, 0xf8, 0x04, 0xe0, 0x6f,
- 0xcf, 0xae, 0xe0, 0x6b, 0xfb, 0xf7, 0x60, 0x30, 0x1b, 0xe0, 0x3f, 0xaf,
- 0xf5, 0x10, 0x15, 0x40, 0x4d, 0x20, 0x06, 0x12, 0x07, 0x06, 0x04, 0x05,
- 0x53, 0x57, 0xe0, 0x5b, 0xac, 0xf4, 0x02, 0x88, 0x75, 0x61, 0xec, 0x60,
- 0x5d, 0xd0, 0xd1, 0xdd, 0x73, 0xf5, 0x04, 0xe0, 0x31, 0xf8, 0xfa, 0xe0,
- 0x2d, 0x36, 0xf3, 0x04, 0x15, 0x21, 0x8c, 0x69, 0xe3, 0x07, 0x05, 0x60,
- 0x6c, 0xd2, 0xc2, 0xb9, 0x69, 0xe1, 0xe0, 0x48, 0x7c, 0x61, 0xae, 0x60,
- 0x5d, 0xad, 0xcf, 0x2e, 0xe5, 0x04, 0xe0, 0x23, 0x33, 0x75, 0xed, 0x07,
- 0x0a, 0x60, 0x64, 0xc1, 0xca, 0xab, 0x76, 0x65, 0x72, 0x65, 0x6e, 0x69,
- 0xe7, 0xe0, 0x58, 0x88, 0xae, 0x60, 0x4c, 0x33, 0x5c, 0x82, 0x44, 0xfe,
- 0xb2, 0x61, 0x73, 0x68, 0xe9, 0x04, 0xe0, 0x69, 0xa7, 0xed, 0xe0, 0x2a,
- 0x61, 0xae, 0x60, 0x67, 0x12, 0xc6, 0xf9, 0xf2, 0x03, 0x0a, 0x84, 0xef,
- 0x02, 0x84, 0xf4, 0xe0, 0x2a, 0x1c, 0xf2, 0xd0, 0x1d, 0xed, 0xe0, 0x58,
- 0xaa, 0xe1, 0x04, 0x04, 0xd8, 0x73, 0xf4, 0xe0, 0x35, 0x7b, 0x6b, 0x61,
- 0xed, 0xdc, 0xbb, 0x6f, 0xf3, 0x60, 0x5c, 0xcb, 0x82, 0xee, 0x03, 0x04,
- 0x85, 0xe9, 0xe0, 0x24, 0xf2, 0x63, 0xe9, 0xe0, 0x6a, 0xdb, 0x61, 0xeb,
- 0xe0, 0x2d, 0x4a, 0x6c, 0x68, 0x6f, 0xf5, 0xe0, 0x38, 0x6a, 0xeb, 0x5a,
- 0x80, 0xe0, 0x49, 0x65, 0x69, 0xeb, 0xdd, 0x43, 0x67, 0xe9, 0xe0, 0x69,
- 0xb2, 0x65, 0xee, 0x03, 0xc8, 0xc7, 0x63, 0xe8, 0xe0, 0x59, 0x82, 0xf4,
- 0x07, 0x60, 0x6d, 0xa7, 0x1f, 0xc1, 0x2b, 0xae, 0x60, 0x68, 0xdf, 0x03,
- 0x03, 0x41, 0x32, 0xc2, 0xde, 0xf3, 0x07, 0x04, 0x60, 0x6c, 0x96, 0xc2,
- 0x45, 0xeb, 0xe0, 0x6b, 0x53, 0xae, 0x60, 0x57, 0xb3, 0x51, 0x16, 0x03,
- 0x41, 0x35, 0xc2, 0xde, 0xf2, 0x06, 0x60, 0x6d, 0x42, 0xc1, 0x87, 0x61,
- 0x67, 0xef, 0xe0, 0x2f, 0x6a, 0xf0, 0x60, 0x6d, 0x76, 0xc1, 0x4c, 0xef,
- 0x1a, 0x05, 0x0b, 0x13, 0x27, 0x26, 0x40, 0x4c, 0x11, 0x40, 0x5c, 0x08,
- 0x0d, 0x04, 0x1e, 0x13, 0x20, 0x06, 0x08, 0x60, 0x6a, 0xef, 0x40, 0xa4,
- 0xc1, 0x6e, 0x1f, 0x43, 0xe5, 0xc1, 0x91, 0x7a, 0x69, 0x6c, 0x6c, 0x61,
- 0x2d, 0x69, 0xef, 0xe0, 0x65, 0x42, 0xf6, 0x04, 0xe0, 0x6e, 0x8d, 0xe9,
- 0x04, 0xe0, 0x6d, 0x1a, 0x6d, 0x69, 0x65, 0x6e, 0x74, 0xef, 0xe0, 0x6b,
- 0xd3, 0xf4, 0x02, 0x9f, 0xef, 0x08, 0x07, 0x0b, 0x56, 0x85, 0xe0, 0x57,
- 0xdc, 0x79, 0x61, 0x6d, 0xe1, 0xe0, 0x68, 0xbf, 0x72, 0x63, 0x79, 0x63,
- 0x6c, 0xe5, 0x60, 0x6b, 0xad, 0xc0, 0x57, 0xe2, 0xe0, 0x2c, 0xb1, 0x65,
- 0xe7, 0xe0, 0x24, 0xa1, 0xf3, 0x0b, 0x0d, 0x05, 0x60, 0x33, 0x8d, 0x60,
- 0x28, 0x0c, 0xce, 0x7e, 0xea, 0x02, 0x86, 0x1f, 0x43, 0xf8, 0xe0, 0x5f,
- 0x45, 0xef, 0xe0, 0x5f, 0x41, 0x65, 0xf5, 0xe0, 0x68, 0x6c, 0x63, 0x6f,
- 0xf7, 0x60, 0x6b, 0x7e, 0xc2, 0xb9, 0xf2, 0x06, 0x06, 0x0c, 0x04, 0x26,
- 0x83, 0x74, 0x67, 0xe1, 0xe0, 0x3b, 0xf8, 0xef, 0x04, 0xe0, 0x2b, 0x04,
- 0x74, 0x73, 0x75, 0xeb, 0xe0, 0x25, 0x10, 0xed, 0xe0, 0x66, 0xf9, 0xe9,
- 0x04, 0x10, 0x04, 0x87, 0xf9, 0x02, 0x85, 0x6f, 0x73, 0xe8, 0xd7, 0x5f,
- 0xe1, 0x04, 0xe0, 0x66, 0x8e, 0xed, 0xd1, 0xce, 0x6f, 0xeb, 0xc1, 0x6a,
- 0x6d, 0x61, 0x63, 0xe8, 0xe0, 0x63, 0xf9, 0x67, 0x75, 0xe3, 0xe0, 0x28,
- 0xd2, 0xe5, 0xca, 0x02, 0x64, 0x6f, 0xf6, 0xe0, 0x5d, 0x6f, 0xef, 0x04,
- 0xe0, 0x65, 0xa8, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0xae, 0x60, 0x5f,
- 0xe2, 0xcd, 0xd5, 0xee, 0x0b, 0x23, 0x10, 0x06, 0x06, 0x0c, 0x60, 0x57,
- 0xcd, 0xc2, 0x41, 0x7a, 0xe1, 0x06, 0x09, 0x0b, 0xe0, 0x6b, 0xb1, 0xe5,
- 0x02, 0x91, 0x64, 0x65, 0x6c, 0x6c, 0xe1, 0x8c, 0xad, 0x02, 0x88, 0x65,
- 0x2d, 0x64, 0x65, 0x6c, 0x6c, 0x61, 0x2d, 0x62, 0x72, 0x69, 0xe1, 0xe0,
- 0x4a, 0x10, 0xf4, 0x02, 0x85, 0x72, 0xe5, 0xe0, 0x63, 0x7c, 0x69, 0x63,
- 0x65, 0x6c, 0xec, 0xe0, 0x62, 0xeb, 0x6d, 0x6f, 0xf5, 0xe0, 0x37, 0x8e,
- 0x67, 0x6f, 0x6c, 0xe9, 0xd9, 0xe6, 0x65, 0xf9, 0x04, 0xe0, 0x6d, 0x84,
- 0xae, 0x60, 0x69, 0x8a, 0xc1, 0x41, 0x61, 0xf3, 0xe0, 0x6b, 0xde, 0xed,
- 0x60, 0x67, 0x5a, 0x41, 0x90, 0xc4, 0x8e, 0xec, 0x07, 0x60, 0x33, 0x3a,
- 0xe0, 0x38, 0x33, 0x69, 0xf3, 0xe0, 0x66, 0x9f, 0xeb, 0xe0, 0x61, 0xe8,
- 0xe4, 0x08, 0x0b, 0x07, 0x60, 0x50, 0xfb, 0xc4, 0x89, 0xe5, 0x06, 0x60,
- 0x5c, 0xa2, 0xc8, 0xdd, 0xec, 0xe0, 0x2d, 0x77, 0xe1, 0x60, 0x2c, 0x9a,
- 0xe0, 0x40, 0xb1, 0xae, 0xc8, 0xcb, 0xe3, 0x02, 0x89, 0x6b, 0x2e, 0x70,
- 0x73, 0x74, 0xed, 0xe0, 0x46, 0x27, 0x68, 0x69, 0x7a, 0xf5, 0xe0, 0x64,
- 0x98, 0xe2, 0x04, 0xe0, 0x23, 0x75, 0xe9, 0x06, 0x60, 0x6b, 0x37, 0xc1,
- 0xec, 0xae, 0x07, 0x06, 0x60, 0x5a, 0x98, 0xc6, 0x98, 0xf4, 0x60, 0x6a,
- 0xae, 0xc0, 0xb5, 0xee, 0x60, 0x6b, 0x7b, 0xc1, 0x98, 0x61, 0x72, 0xe5,
- 0xe0, 0x3a, 0x3b, 0xae, 0x60, 0x68, 0x2f, 0x40, 0x57, 0xc2, 0x87, 0xad,
- 0x02, 0x89, 0x73, 0x69, 0x65, 0x6d, 0x65, 0xee, 0xe0, 0x4e, 0xe7, 0x69,
- 0x2d, 0x72, 0xe1, 0xe0, 0x62, 0x6f, 0xee, 0x60, 0x48, 0x63, 0xe0, 0x24,
- 0x8a, 0xed, 0x04, 0xe0, 0x5b, 0xdc, 0xe1, 0x04, 0xe0, 0x6c, 0xdd, 0x66,
- 0x61, 0xee, 0xe0, 0x69, 0xb2, 0xec, 0x06, 0x60, 0x6a, 0x6e, 0xc2, 0x62,
- 0xe2, 0x60, 0x4b, 0xfb, 0xe0, 0x20, 0xd4, 0xeb, 0x47, 0xbd, 0xe0, 0x65,
- 0x0b, 0xea, 0x02, 0x84, 0x1f, 0x43, 0xf8, 0x82, 0x6f, 0x6e, 0xe4, 0xe0,
- 0x25, 0x93, 0xe9, 0x18, 0x1c, 0x40, 0x56, 0x34, 0x40, 0x4d, 0x0e, 0x40,
- 0xdf, 0x0a, 0x40, 0xa7, 0x0d, 0x23, 0x0a, 0x07, 0x0c, 0x22, 0x1a, 0x05,
- 0x10, 0xd3, 0x15, 0x7a, 0xf5, 0x04, 0x07, 0x06, 0x85, 0x73, 0x61, 0x77,
- 0xe1, 0xe0, 0x34, 0x16, 0x6e, 0x61, 0xed, 0xe0, 0x64, 0x25, 0x6d, 0xe1,
- 0xe0, 0x20, 0xc0, 0xe8, 0xe0, 0x66, 0xd1, 0xf9, 0x02, 0x93, 0xef, 0x02,
- 0x84, 0xf4, 0xe0, 0x50, 0x71, 0x73, 0x68, 0x69, 0xae, 0x60, 0x61, 0x2a,
- 0x41, 0x44, 0x44, 0xb2, 0xac, 0xe1, 0x09, 0x0d, 0x05, 0x07, 0x08, 0x11,
- 0xe0, 0x60, 0xbb, 0xfa, 0x03, 0xd0, 0xe7, 0x61, 0x6b, 0x69, 0xae, 0x60,
- 0x5e, 0x9f, 0xcc, 0x18, 0x77, 0xe1, 0xe0, 0x21, 0xc9, 0x73, 0x68, 0x69,
- 0xf2, 0xe0, 0x33, 0x88, 0x6d, 0x61, 0xae, 0x60, 0x60, 0xc2, 0xc0, 0x6f,
- 0xeb, 0x02, 0xa3, 0xef, 0x02, 0x84, 0x6e, 0xef, 0xd2, 0x07, 0xae, 0x60,
- 0x33, 0xb9, 0xe0, 0x2c, 0xf9, 0xe4, 0xe0, 0x50, 0x25, 0xf4, 0x06, 0x15,
- 0x0b, 0xe0, 0x6c, 0x04, 0x73, 0xf5, 0x03, 0x05, 0x84, 0x6b, 0xe5, 0xe0,
- 0x68, 0x03, 0xe5, 0xe0, 0x64, 0x34, 0x62, 0x69, 0x73, 0xe8, 0xe0, 0x6a,
- 0x00, 0xef, 0x07, 0x60, 0x25, 0x0e, 0xe0, 0x3f, 0x84, 0xf9, 0xc5, 0xbb,
- 0xe1, 0x02, 0x84, 0xee, 0xe0, 0x2e, 0x81, 0xeb, 0x52, 0xe2, 0xe0, 0x53,
- 0x61, 0xf3, 0x05, 0x04, 0x09, 0x0a, 0x88, 0x75, 0xe7, 0xd1, 0x3a, 0xf3,
- 0x04, 0xe0, 0x35, 0xec, 0xe9, 0xe0, 0x52, 0x5b, 0x68, 0x69, 0x6d, 0x61,
- 0xae, 0x60, 0x61, 0xe2, 0xc4, 0xb3, 0x63, 0x6f, 0x6e, 0x66, 0x75, 0xf3,
- 0xdb, 0x91, 0xe1, 0x04, 0x05, 0x12, 0x83, 0x77, 0xe1, 0xe0, 0x2e, 0x21,
- 0x74, 0x6f, 0xae, 0x09, 0x60, 0x32, 0x00, 0x60, 0x2f, 0x5e, 0xc4, 0x9c,
- 0xf3, 0x60, 0x61, 0xb7, 0xc4, 0x74, 0xf3, 0xd3, 0x0a, 0x6b, 0x69, 0x2e,
- 0xef, 0x60, 0x66, 0x15, 0xc3, 0xce, 0x72, 0x63, 0x6c, 0x6f, 0x75, 0x64,
- 0xae, 0x60, 0x4c, 0x8d, 0x40, 0x65, 0xde, 0x28, 0xee, 0x07, 0x0b, 0x16,
- 0x07, 0x11, 0x06, 0x86, 0xf4, 0x04, 0xe0, 0x6b, 0x8f, 0x65, 0x72, 0xe5,
- 0xe0, 0x54, 0x1c, 0xef, 0x08, 0x06, 0x04, 0x53, 0xb1, 0xe0, 0x4f, 0x5e,
- 0x6b, 0x61, 0xed, 0xe0, 0x2e, 0x10, 0xe8, 0xe0, 0x69, 0xab, 0xe2, 0xcf,
- 0x5b, 0x6e, 0x65, 0x73, 0xef, 0xe0, 0x5e, 0xf3, 0xe9, 0x06, 0x60, 0x54,
- 0x7f, 0xd6, 0xe6, 0xf3, 0x04, 0xe0, 0x45, 0x54, 0x69, 0x74, 0xe5, 0xcb,
- 0x42, 0xe5, 0x60, 0x36, 0xad, 0xc4, 0xd8, 0x63, 0x6f, 0xed, 0xe0, 0x3b,
- 0x90, 0xe1, 0x07, 0x08, 0x40, 0x7d, 0xe0, 0x31, 0xfe, 0x74, 0x6f, 0xae,
- 0x60, 0x67, 0xfc, 0xc1, 0x7b, 0xed, 0x03, 0xc0, 0x74, 0xe9, 0x10, 0x0a,
- 0x07, 0x05, 0x0a, 0x06, 0x0c, 0x07, 0x05, 0x06, 0x0f, 0x08, 0x4f, 0xf2,
- 0xc4, 0x61, 0x79, 0x61, 0x6d, 0x61, 0x73, 0x68, 0x69, 0xf2, 0xd6, 0x91,
- 0x75, 0x6f, 0x6e, 0x75, 0xed, 0xd9, 0x54, 0x74, 0xe1, 0xe0, 0x65, 0x1c,
- 0x73, 0x61, 0x6e, 0x72, 0x69, 0x6b, 0xf5, 0xe0, 0x31, 0x50, 0x6f, 0x67,
- 0x75, 0xee, 0xd0, 0xc7, 0xed, 0x02, 0x85, 0x69, 0x6e, 0xef, 0xd3, 0x39,
- 0xe1, 0xe0, 0x62, 0x61, 0xe9, 0x03, 0xd1, 0xd6, 0xf3, 0xdf, 0x49, 0x65,
- 0xe3, 0xe0, 0x3e, 0x49, 0x62, 0x6f, 0xf3, 0xe0, 0x69, 0x11, 0xe1, 0x04,
- 0x04, 0xd0, 0x0f, 0xf7, 0xe0, 0x5d, 0x60, 0x73, 0x68, 0x69, 0xe7, 0xda,
- 0x18, 0xae, 0x60, 0x5d, 0x17, 0x42, 0x3c, 0xc6, 0x30, 0x2d, 0x61, 0x6c,
- 0x70, 0xf3, 0xe0, 0x40, 0x9a, 0x61, 0xf4, 0xe0, 0x63, 0xb0, 0x6b, 0x61,
- 0xed, 0xd9, 0xe3, 0x6d, 0xe1, 0x04, 0xe0, 0x65, 0x63, 0xf4, 0xe0, 0x21,
- 0xaa, 0xec, 0x08, 0x06, 0x06, 0x60, 0x60, 0x7a, 0xca, 0x24, 0x69, 0x74,
- 0xe1, 0xe0, 0x5f, 0xe5, 0x61, 0xee, 0x60, 0x68, 0xa5, 0x81, 0xae, 0x21,
- 0x06, 0x0a, 0x07, 0x06, 0x08, 0x0a, 0x09, 0x09, 0x08, 0x06, 0x06, 0x09,
- 0x08, 0x60, 0x2c, 0xdb, 0x5b, 0x3b, 0x40, 0x41, 0x40, 0x48, 0x4f, 0xa6,
- 0x46, 0x17, 0x49, 0x23, 0x40, 0x5d, 0xc0, 0x47, 0xf6, 0x60, 0x5e, 0x93,
- 0xca, 0x7a, 0xf4, 0x60, 0x68, 0x09, 0x03, 0x1e, 0x12, 0x40, 0xbc, 0xb3,
- 0xf3, 0x60, 0x68, 0x3b, 0x40, 0x79, 0x99, 0xf2, 0x60, 0x67, 0xfb, 0xc1,
- 0xe1, 0xf0, 0x60, 0x68, 0x16, 0x18, 0x40, 0x92, 0xb0, 0xee, 0x60, 0x67,
- 0xea, 0x40, 0x5a, 0x40, 0x95, 0xc1, 0x7c, 0xed, 0x60, 0x66, 0xa6, 0x41,
- 0x3a, 0x3c, 0xc2, 0x2f, 0xeb, 0x60, 0x67, 0xd7, 0x21, 0x41, 0x01, 0xc1,
- 0x49, 0xe9, 0x60, 0x48, 0xcf, 0x5f, 0x26, 0xc1, 0x1a, 0xe7, 0x60, 0x68,
- 0x7b, 0x19, 0xb0, 0xe5, 0x60, 0x5e, 0x44, 0xcb, 0xe7, 0xe3, 0x60, 0x67,
- 0xde, 0x18, 0x40, 0xb3, 0xc0, 0x52, 0xe2, 0x60, 0x67, 0xed, 0x40, 0x97,
- 0x1c, 0xb3, 0xe1, 0x60, 0x5e, 0x2d, 0x49, 0x7c, 0x24, 0x40, 0xda, 0xa4,
- 0xeb, 0x04, 0xe0, 0x65, 0x58, 0xe1, 0x03, 0xc3, 0xe4, 0xf3, 0xe0, 0x68,
- 0x27, 0xe8, 0x04, 0xe0, 0x5a, 0x9b, 0xe1, 0x02, 0x8c, 0xf2, 0x04, 0xe0,
- 0x64, 0x93, 0x61, 0xae, 0x60, 0x5e, 0xa7, 0xc5, 0x9a, 0x6d, 0x61, 0xae,
- 0x60, 0x3d, 0x48, 0x60, 0x21, 0x8c, 0x40, 0xb6, 0x45, 0x37, 0xc3, 0x51,
- 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0xee, 0xe0, 0x52, 0xff, 0x66, 0x75,
- 0x6e, 0xe5, 0xe0, 0x62, 0xba, 0xe5, 0x04, 0xe0, 0x68, 0x23, 0xec, 0x60,
- 0x2c, 0xc3, 0xe0, 0x27, 0xe6, 0xe4, 0x06, 0x0a, 0x09, 0xe0, 0x53, 0x52,
- 0x74, 0x72, 0x65, 0x2d, 0x67, 0x61, 0xf5, 0xe0, 0x34, 0x3c, 0x6f, 0x72,
- 0x69, 0xae, 0x60, 0x61, 0x5a, 0xc6, 0x7a, 0x61, 0x74, 0x6c, 0x61, 0xee,
- 0xe0, 0x4e, 0xc8, 0xe3, 0x02, 0x91, 0x72, 0xef, 0x02, 0x86, 0x73, 0x6f,
- 0xe6, 0xe0, 0x67, 0xdc, 0x6c, 0x69, 0x67, 0xe8, 0xe0, 0x64, 0xaf, 0x68,
- 0x69, 0xe7, 0xe0, 0x3b, 0x10, 0x62, 0xf5, 0xe0, 0x5e, 0x07, 0xe1, 0x02,
- 0x89, 0xf3, 0x04, 0xe0, 0x4d, 0x6d, 0xf4, 0xe0, 0x5b, 0x06, 0xed, 0xe0,
- 0x67, 0x5f, 0xae, 0x60, 0x64, 0x94, 0x42, 0xde, 0xc0, 0x5c, 0xe7, 0x60,
- 0x40, 0xee, 0xe0, 0x28, 0x77, 0xe5, 0x13, 0x21, 0x18, 0x06, 0x1d, 0x2c,
- 0x27, 0x06, 0x06, 0x40, 0x74, 0x60, 0x36, 0xf7, 0x60, 0x27, 0x97, 0xc9,
- 0x8e, 0xf3, 0x02, 0x96, 0xf3, 0x03, 0x07, 0x84, 0x77, 0x69, 0x74, 0xe8,
- 0xe0, 0x3e, 0xd6, 0xe9, 0xe0, 0x61, 0x6b, 0x65, 0x72, 0x6c, 0xe9, 0xe0,
- 0x67, 0xcd, 0x61, 0x76, 0x65, 0x72, 0xe4, 0xe0, 0x64, 0xe7, 0xf2, 0x05,
- 0x05, 0x08, 0xd5, 0x4b, 0x1f, 0x43, 0xe5, 0xd5, 0x56, 0x73, 0x65, 0x69,
- 0x6e, 0xe5, 0xe0, 0x39, 0x45, 0x63, 0x6b, 0xed, 0xdc, 0x49, 0xee, 0x60,
- 0x68, 0x1e, 0xc0, 0xf3, 0xed, 0x06, 0x05, 0x07, 0xe0, 0x67, 0x8b, 0x73,
- 0xe5, 0xe0, 0x5c, 0x9b, 0x6f, 0x72, 0x69, 0xe1, 0xe0, 0x58, 0x8d, 0x62,
- 0x65, 0x72, 0x73, 0x2e, 0x6c, 0xe9, 0xe0, 0x37, 0xf9, 0xec, 0x0c, 0x05,
- 0x07, 0x60, 0x5c, 0x07, 0x41, 0x2a, 0x43, 0x78, 0xc1, 0x51, 0x68, 0xf5,
- 0xe0, 0x64, 0xbd, 0x62, 0x6f, 0x75, 0xf2, 0xe0, 0x52, 0xc3, 0x2e, 0x63,
- 0x6c, 0x6f, 0x75, 0x64, 0x6c, 0x65, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d,
- 0x2e, 0xe1, 0xe0, 0x68, 0x3e, 0xe9, 0x02, 0x88, 0x77, 0x61, 0xae, 0x60,
- 0x5d, 0xa9, 0xc2, 0xc4, 0xee, 0x02, 0x87, 0x66, 0x6f, 0x72, 0xf5, 0xe0,
- 0x4f, 0x47, 0xad, 0x02, 0x87, 0x76, 0x69, 0x67, 0xef, 0xe0, 0x43, 0x91,
- 0x69, 0x73, 0x65, 0x72, 0xf6, 0xe0, 0x43, 0x8a, 0x67, 0x75, 0xf2, 0xe0,
- 0x62, 0xe6, 0xe5, 0x60, 0x4f, 0x06, 0xd7, 0xd8, 0xe4, 0x07, 0x40, 0x42,
- 0x0a, 0xe0, 0x68, 0x3c, 0xe9, 0x04, 0x0b, 0x0e, 0x88, 0x7a, 0x69, 0x6e,
- 0x68, 0x69, 0x73, 0x74, 0x6f, 0xf2, 0xd3, 0x7f, 0xef, 0x02, 0x81, 0x2d,
- 0x63, 0x61, 0x6d, 0x70, 0x69, 0x64, 0xe1, 0xe0, 0x5d, 0x15, 0xe3, 0x04,
- 0xe0, 0x5e, 0x40, 0xe9, 0xdc, 0x01, 0xe1, 0x05, 0x0d, 0xe0, 0x68, 0x4f,
- 0x74, 0x65, 0x63, 0x68, 0xae, 0x04, 0xe0, 0x43, 0x93, 0xe2, 0xe0, 0x57,
- 0x3f, 0xae, 0x60, 0x63, 0xef, 0x41, 0x81, 0x26, 0xc1, 0xc4, 0x65, 0x63,
- 0x69, 0x6e, 0xae, 0x60, 0x5c, 0x7c, 0xc8, 0x03, 0xae, 0x0c, 0x06, 0x07,
- 0x60, 0x60, 0xce, 0x40, 0x9e, 0x43, 0x4a, 0xc2, 0x21, 0xf3, 0x60, 0x65,
- 0xe9, 0xc0, 0xac, 0xf0, 0x60, 0x66, 0x8f, 0x1b, 0xc0, 0xcb, 0xe5, 0x60,
- 0x5c, 0x39, 0xca, 0x7a, 0xae, 0x0c, 0x05, 0x06, 0x60, 0x4f, 0xea, 0x44,
- 0x99, 0x41, 0x04, 0xcc, 0x72, 0xf5, 0x60, 0x65, 0xac, 0x83, 0xf4, 0x60,
- 0x65, 0x9d, 0xc2, 0x5d, 0xf3, 0x60, 0x65, 0xa1, 0xc0, 0xe5, 0xe4, 0x04,
- 0xe0, 0x67, 0xf9, 0xae, 0x60, 0x5c, 0x19, 0xc7, 0x06, 0xe3, 0x07, 0x08,
- 0x07, 0x09, 0xe0, 0x67, 0xd3, 0xf0, 0x04, 0xe0, 0x41, 0xd0, 0xf2, 0xc1,
- 0x60, 0x6b, 0x69, 0x6e, 0xf3, 0xe0, 0x5b, 0x4a, 0x64, 0x69, 0x72, 0xae,
- 0x60, 0x51, 0xdf, 0xd5, 0x70, 0xae, 0x60, 0x56, 0xc2, 0x4b, 0x05, 0xc4,
- 0x10, 0xe2, 0x04, 0xe0, 0x66, 0x2d, 0xae, 0x60, 0x65, 0xca, 0xc0, 0x61,
- 0xe1, 0x17, 0x15, 0x0c, 0x40, 0x73, 0x36, 0x40, 0x62, 0x12, 0x04, 0x40,
- 0x41, 0x0a, 0x2b, 0x17, 0x24, 0x1a, 0x07, 0x0d, 0x1e, 0xe0, 0x65, 0x69,
- 0xfa, 0x03, 0x05, 0x87, 0x75, 0xf2, 0xe0, 0x55, 0xd7, 0x6f, 0x77, 0x73,
- 0xfa, 0xe0, 0x29, 0xbc, 0x65, 0xf0, 0xe0, 0x41, 0x50, 0x79, 0x66, 0x69,
- 0x72, 0x73, 0x74, 0xae, 0x60, 0x57, 0xcc, 0xcc, 0xef, 0xf4, 0x07, 0x0f,
- 0x40, 0x58, 0xe0, 0x65, 0xcc, 0xf4, 0x04, 0xe0, 0x62, 0x6c, 0x61, 0x2d,
- 0x76, 0x61, 0x72, 0x6a, 0xea, 0xe0, 0x55, 0x11, 0x73, 0xf5, 0x0a, 0x06,
- 0x04, 0x05, 0x12, 0x03, 0x10, 0x03, 0x04, 0x86, 0x7a, 0x61, 0xeb, 0xe0,
- 0x5d, 0x62, 0x79, 0xe1, 0xd0, 0xcc, 0x75, 0xf2, 0xe0, 0x4b, 0x63, 0xf3,
- 0x02, 0x8b, 0x68, 0xe9, 0x04, 0xe0, 0x22, 0x65, 0x67, 0xe5, 0xe0, 0x61,
- 0xf6, 0x61, 0xeb, 0xd0, 0xe0, 0xee, 0xd4, 0xf0, 0xed, 0x02, 0x89, 0x6f,
- 0x74, 0x6f, 0xae, 0x60, 0x61, 0x41, 0xc2, 0xe3, 0xe1, 0xe0, 0x4a, 0xb1,
- 0xeb, 0xcf, 0x69, 0xe5, 0xe0, 0x61, 0x9a, 0xe4, 0x60, 0x62, 0x8f, 0xc2,
- 0xc1, 0xe2, 0x02, 0x84, 0x75, 0xf3, 0xce, 0x7c, 0xe1, 0xe0, 0x2e, 0x79,
- 0xe5, 0xe0, 0x3f, 0xd6, 0xf3, 0x09, 0x04, 0x0d, 0x0a, 0x07, 0x06, 0xe0,
- 0x5b, 0x3d, 0xf5, 0xe0, 0x24, 0xf0, 0x73, 0xe1, 0x02, 0x81, 0x2d, 0x63,
- 0x61, 0x72, 0x72, 0xe1, 0xe0, 0x3f, 0xbb, 0x68, 0x69, 0xeb, 0x4c, 0xb7,
- 0x60, 0x3d, 0xbd, 0xcb, 0xde, 0x66, 0x6a, 0x6f, 0xf2, 0xe0, 0x24, 0xf2,
- 0x65, 0x72, 0xe1, 0xe0, 0x54, 0xc3, 0x61, 0xeb, 0xdf, 0x37, 0xf2, 0x0d,
- 0x0b, 0x0f, 0x07, 0x05, 0x05, 0x0e, 0x16, 0x60, 0x49, 0xab, 0xda, 0xda,
- 0x79, 0xec, 0x04, 0xe0, 0x37, 0x17, 0x68, 0xf5, 0xe0, 0x3f, 0x76, 0xf5,
- 0x02, 0x85, 0x6d, 0x6f, 0xf2, 0xd5, 0xc0, 0x67, 0x61, 0x6d, 0xe5, 0xe0,
- 0x58, 0xf3, 0x73, 0x68, 0x61, 0xec, 0xe0, 0x53, 0xd1, 0x72, 0xe9, 0xe0,
- 0x64, 0xf4, 0x6e, 0xe1, 0xe0, 0x37, 0x0a, 0x6b, 0xe5, 0x04, 0xe0, 0x5b,
- 0x02, 0xf4, 0x60, 0x51, 0x4e, 0x52, 0xee, 0xc2, 0x62, 0xe9, 0x02, 0x88,
- 0x74, 0x69, 0xed, 0x60, 0x5b, 0xe3, 0xc6, 0x68, 0xee, 0x02, 0x84, 0xe7,
- 0xe0, 0x5d, 0x78, 0xe5, 0xe0, 0x65, 0xfa, 0x63, 0xe8, 0xe0, 0x5f, 0xb7,
- 0xf0, 0x04, 0xe0, 0x66, 0x77, 0x2e, 0x66, 0x61, 0x73, 0x74, 0x6c, 0xf9,
- 0x60, 0x33, 0xc6, 0xe0, 0x32, 0x86, 0x6f, 0xf2, 0xd4, 0x1d, 0xee, 0x10,
- 0x05, 0x04, 0x05, 0x0d, 0x07, 0x60, 0x35, 0xb1, 0x60, 0x29, 0xa6, 0x41,
- 0x3d, 0xc5, 0x9f, 0x74, 0xef, 0xe0, 0x2a, 0xf2, 0xf3, 0xe0, 0x44, 0x1f,
- 0x6e, 0xef, 0xe0, 0x58, 0x84, 0xe7, 0x04, 0xe0, 0x64, 0xc5, 0x79, 0x73,
- 0x68, 0x6c, 0xe1, 0xe0, 0x60, 0x52, 0x63, 0x68, 0x65, 0xf3, 0xe0, 0x5b,
- 0x8e, 0xe1, 0x02, 0x84, 0xf5, 0xe0, 0x4d, 0x78, 0x67, 0x65, 0x6d, 0xe5,
- 0xe0, 0x3d, 0x1a, 0x6d, 0x75, 0x72, 0x6f, 0x67, 0x61, 0xf7, 0xe0, 0x2c,
- 0xb5, 0xec, 0x08, 0x07, 0x08, 0x06, 0x03, 0xe0, 0x2b, 0x4d, 0x73, 0x65,
- 0x6c, 0xf6, 0xe0, 0x64, 0x87, 0x6f, 0x70, 0x6f, 0x6c, 0xf3, 0xe0, 0x3c,
- 0x7c, 0x6c, 0x6f, 0xf2, 0xe0, 0x39, 0xc1, 0xe2, 0xc4, 0xc9, 0x61, 0x74,
- 0x76, 0x75, 0x6f, 0x70, 0xed, 0xe0, 0x5e, 0x77, 0xeb, 0x03, 0x08, 0x87,
- 0x75, 0x72, 0x61, 0x7a, 0xe1, 0xe0, 0x20, 0x35, 0x69, 0x6e, 0x6f, 0xe8,
- 0xe0, 0x24, 0x1a, 0xe5, 0xe0, 0x2b, 0x6a, 0xe9, 0x0a, 0x05, 0x0b, 0x04,
- 0x60, 0x35, 0x8d, 0xe0, 0x25, 0x63, 0x7a, 0x75, 0xf2, 0xca, 0x55, 0xee,
- 0x04, 0xe0, 0x5d, 0x8b, 0x74, 0x65, 0xee, 0xe0, 0x61, 0x07, 0xec, 0xe0,
- 0x61, 0x2d, 0x62, 0x61, 0xf2, 0xc9, 0x83, 0xe7, 0x03, 0x06, 0x8b, 0x6e,
- 0x65, 0xf4, 0xe0, 0x45, 0x04, 0x65, 0x6e, 0x74, 0x6f, 0x73, 0x69, 0x74,
- 0xe5, 0xe0, 0x56, 0x37, 0x61, 0xfa, 0xe0, 0x60, 0x98, 0x65, 0x62, 0x61,
- 0x73, 0xe8, 0xd4, 0xba, 0xe4, 0x04, 0xe0, 0x62, 0xd6, 0x72, 0x69, 0xe4,
- 0x60, 0x62, 0xd3, 0xc2, 0xb9, 0xe3, 0x04, 0x04, 0x06, 0x8b, 0xf9, 0xe0,
- 0x63, 0x1f, 0x68, 0x69, 0xe4, 0xe0, 0x5f, 0xc2, 0xe5, 0x02, 0x84, 0xf2,
- 0xe0, 0x54, 0xeb, 0xe9, 0xe0, 0x58, 0xe9, 0xe1, 0xe0, 0x30, 0x77, 0xae,
- 0x60, 0x5f, 0x57, 0x03, 0xc1, 0x35, 0xec, 0x20, 0x1d, 0x12, 0x0d, 0x40,
- 0x6e, 0x35, 0x15, 0x41, 0x36, 0x04, 0x06, 0x09, 0x41, 0x2a, 0x0d, 0x40,
- 0xbd, 0x1b, 0x40, 0xef, 0x60, 0x33, 0xe9, 0x52, 0xee, 0x4f, 0x3a, 0x47,
- 0x93, 0xc1, 0x18, 0x1f, 0xc3, 0x04, 0x0b, 0x04, 0x85, 0xf8, 0x05, 0x41,
- 0x33, 0xdc, 0x08, 0x64, 0xe9, 0xe0, 0x56, 0x30, 0xe6, 0xe0, 0x35, 0x91,
- 0x64, 0xee, 0xe0, 0x5d, 0xf0, 0xe1, 0xc4, 0xf4, 0xf9, 0x04, 0xe0, 0x65,
- 0x1f, 0xee, 0x02, 0x84, 0xf8, 0xe0, 0x4c, 0x0a, 0xe7, 0x60, 0x56, 0x16,
- 0xc8, 0x25, 0xf6, 0x06, 0x60, 0x49, 0x6e, 0xdb, 0x9d, 0xae, 0x60, 0x49,
- 0x7b, 0xd5, 0x84, 0xf5, 0x12, 0x04, 0x10, 0x11, 0x04, 0x0f, 0x12, 0x50,
- 0x45, 0x60, 0x2a, 0x56, 0x57, 0xf2, 0x44, 0xc2, 0xcd, 0x59, 0xfa, 0xe0,
- 0x54, 0x42, 0xf8, 0x02, 0x84, 0xf5, 0xe0, 0x3d, 0xb0, 0xe5, 0x04, 0xe0,
- 0x64, 0xe2, 0xed, 0xe0, 0x2d, 0xaa, 0xee, 0x02, 0x84, 0xee, 0xe0, 0x59,
- 0x3c, 0xe4, 0x04, 0xe0, 0x63, 0x4b, 0x62, 0xe5, 0xe0, 0x35, 0xc1, 0xeb,
- 0xe0, 0x58, 0x08, 0xe7, 0x05, 0x04, 0xe0, 0x60, 0xdc, 0xf3, 0xe0, 0x60,
- 0xdf, 0x61, 0xee, 0xe0, 0x3b, 0x29, 0xe3, 0x03, 0x06, 0x84, 0x65, 0x72,
- 0xee, 0xe0, 0x60, 0x6d, 0xe3, 0xe0, 0x5e, 0x68, 0xe1, 0xe0, 0x4c, 0x0f,
- 0xe2, 0x05, 0x06, 0xe0, 0x53, 0x55, 0x6c, 0x69, 0xee, 0xe0, 0x53, 0x48,
- 0x61, 0x72, 0xf4, 0xc6, 0xff, 0xf4, 0x05, 0x27, 0xe0, 0x64, 0x6a, 0xe4,
- 0x06, 0x60, 0x62, 0xf1, 0xc1, 0x99, 0xae, 0x0a, 0x06, 0x04, 0x58, 0x8e,
- 0x60, 0x38, 0x0a, 0xc8, 0x03, 0xf5, 0x60, 0x54, 0xa4, 0xcd, 0x7b, 0xe7,
- 0xe0, 0x62, 0x66, 0xe3, 0x04, 0xe0, 0x62, 0x40, 0x6f, 0x2e, 0xe9, 0xe0,
- 0x62, 0x22, 0xae, 0x60, 0x48, 0xda, 0x55, 0x84, 0xc4, 0x10, 0xf0, 0x06,
- 0x43, 0x44, 0xe0, 0x57, 0x68, 0xec, 0x04, 0xe0, 0x64, 0x56, 0x66, 0x69,
- 0x6e, 0x61, 0x6e, 0xe3, 0xe0, 0x30, 0x65, 0xef, 0x14, 0x07, 0x05, 0x0d,
- 0x05, 0x0a, 0x0e, 0x07, 0x05, 0x2d, 0x17, 0x1c, 0x07, 0x07, 0x3c, 0x07,
- 0x24, 0xe0, 0x61, 0x25, 0x79, 0x61, 0x6c, 0xe9, 0xe0, 0x4d, 0xf6, 0x77,
- 0xe9, 0xe0, 0x4c, 0xc8, 0x76, 0xe5, 0x06, 0x60, 0x4b, 0x49, 0xd8, 0xdb,
- 0x73, 0xe9, 0xe0, 0x3b, 0x73, 0x75, 0xf6, 0xe0, 0x5f, 0xd6, 0xf4, 0x04,
- 0xe0, 0x55, 0x14, 0xf4, 0x60, 0x62, 0x97, 0x8f, 0xf3, 0x02, 0x84, 0xe5,
- 0xe0, 0x3a, 0xac, 0x61, 0x6e, 0x67, 0xe5, 0xe0, 0x4d, 0x78, 0x72, 0x65,
- 0x6e, 0xf3, 0xe0, 0x35, 0x72, 0x70, 0xf0, 0xe0, 0x5e, 0x23, 0xee, 0x04,
- 0x1f, 0xd0, 0x8f, 0xe4, 0x02, 0x86, 0x72, 0x69, 0xee, 0xe0, 0x5a, 0xdb,
- 0x6f, 0xee, 0x04, 0xe0, 0x63, 0xe2, 0xae, 0x04, 0xe0, 0x61, 0x25, 0x63,
- 0x6c, 0x6f, 0x75, 0x64, 0x61, 0x70, 0xf0, 0xe0, 0x45, 0x11, 0xad, 0x04,
- 0xe0, 0x2d, 0x75, 0xb2, 0xe0, 0x2d, 0x75, 0xed, 0x07, 0x09, 0x60, 0x4a,
- 0xbb, 0xc6, 0xce, 0x62, 0x61, 0x72, 0xe4, 0x60, 0x5b, 0x11, 0xc2, 0x64,
- 0xae, 0x60, 0x61, 0xbc, 0xc0, 0x75, 0xec, 0x04, 0xe0, 0x63, 0xad, 0xe9,
- 0x02, 0x88, 0x74, 0x61, 0x70, 0x75, 0xee, 0xe0, 0x55, 0x27, 0x70, 0x6f,
- 0xf0, 0x04, 0xe0, 0x62, 0xa0, 0x6d, 0xe3, 0xe0, 0x5b, 0x60, 0x69, 0x73,
- 0x69, 0xf2, 0xe0, 0x59, 0x5e, 0x68, 0x6d, 0x75, 0xf3, 0xe0, 0x4d, 0x91,
- 0xe7, 0x05, 0x09, 0xe0, 0x62, 0x2d, 0x6f, 0x69, 0x70, 0xae, 0x60, 0x62,
- 0xde, 0xc0, 0x99, 0xe9, 0x02, 0x87, 0x73, 0x74, 0x69, 0xe3, 0xe0, 0x5f,
- 0x3e, 0xee, 0x02, 0x85, 0x74, 0xef, 0xe0, 0x4d, 0x70, 0x6c, 0x69, 0x6e,
- 0x65, 0xae, 0x09, 0x60, 0x3e, 0x99, 0x60, 0x23, 0x59, 0xc0, 0x6d, 0xf3,
- 0x04, 0xe0, 0x53, 0x42, 0x65, 0x72, 0x76, 0x69, 0xe3, 0xe0, 0x62, 0xdf,
- 0x64, 0xe9, 0x60, 0x54, 0x47, 0xcd, 0x07, 0xe3, 0x05, 0x04, 0xe0, 0x5e,
- 0x62, 0xeb, 0xe0, 0x4f, 0xd0, 0x61, 0xec, 0x02, 0x87, 0x7a, 0x6f, 0x6e,
- 0xe5, 0xe0, 0x3f, 0x36, 0xe8, 0x04, 0xe0, 0x40, 0xa2, 0x6f, 0x73, 0x74,
- 0x2e, 0x64, 0x61, 0xf0, 0xe0, 0x3d, 0x0c, 0xe1, 0x04, 0xe0, 0x3f, 0x50,
- 0xe2, 0x60, 0x50, 0xb7, 0x82, 0xee, 0xe0, 0x4f, 0xd9, 0xec, 0x60, 0x57,
- 0x2a, 0xca, 0x59, 0xeb, 0x04, 0xe0, 0x63, 0x08, 0xb3, 0xe0, 0x62, 0x7d,
- 0xe9, 0x12, 0x15, 0x0a, 0x05, 0x40, 0x42, 0x2b, 0x13, 0x14, 0x0f, 0x16,
- 0x07, 0x04, 0x60, 0x60, 0x0d, 0xc1, 0xfc, 0xf6, 0x05, 0x05, 0xe0, 0x61,
- 0x78, 0x6f, 0xf2, 0xe0, 0x57, 0x91, 0x69, 0x6e, 0xe7, 0x60, 0x40, 0x59,
- 0x5f, 0xd1, 0xc2, 0xb9, 0x74, 0x74, 0x6c, 0x65, 0x73, 0x74, 0xe1, 0xe0,
- 0x50, 0x12, 0x70, 0xf3, 0xe0, 0x60, 0xa0, 0xee, 0x07, 0x0c, 0x16, 0x14,
- 0xe0, 0x53, 0xd6, 0x6f, 0x64, 0x65, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0xf4,
- 0xe0, 0x40, 0x62, 0xeb, 0x04, 0xe0, 0x62, 0xb4, 0x79, 0x61, 0x72, 0xe4,
- 0x04, 0xe0, 0x4a, 0x8b, 0x2d, 0x63, 0x6c, 0x6f, 0x75, 0xe4, 0xe0, 0x5c,
- 0x24, 0xe4, 0x03, 0x05, 0x87, 0x1f, 0xc3, 0xe0, 0x5e, 0x79, 0xe5, 0x60,
- 0x2c, 0x6f, 0xe0, 0x36, 0x2a, 0xe1, 0xe0, 0x5e, 0x6f, 0x63, 0xef, 0xc6,
- 0x7a, 0xed, 0x05, 0x05, 0xe0, 0x61, 0x03, 0x69, 0xf4, 0xe0, 0x43, 0x29,
- 0xe1, 0x03, 0x05, 0x84, 0x6e, 0xef, 0xe0, 0x50, 0x27, 0xae, 0xe0, 0x43,
- 0xcf, 0x2d, 0x63, 0x69, 0x74, 0x79, 0xae, 0x06, 0x60, 0x61, 0xb9, 0x0e,
- 0x82, 0x72, 0x6f, 0x63, 0xeb, 0xe0, 0x61, 0xf4, 0x6c, 0xec, 0x04, 0xe0,
- 0x60, 0x2a, 0xe5, 0x02, 0x84, 0xf3, 0xe0, 0x55, 0x87, 0x68, 0x61, 0xed,
- 0xe0, 0x20, 0xd8, 0x6b, 0xe5, 0x04, 0xe0, 0x62, 0x47, 0xf3, 0x02, 0x87,
- 0x63, 0x61, 0x6e, 0xe4, 0xe0, 0x43, 0xb2, 0x2d, 0xf0, 0xd2, 0x9b, 0xe7,
- 0x05, 0x04, 0xe0, 0x60, 0x33, 0xf5, 0xe0, 0x5b, 0xe9, 0x68, 0xf4, 0xe0,
- 0x4c, 0xdd, 0x66, 0xe5, 0x05, 0x06, 0xe0, 0x62, 0x1d, 0x73, 0x74, 0xf9,
- 0xe0, 0x60, 0x34, 0x69, 0x6e, 0x73, 0x75, 0x72, 0xe1, 0xe0, 0x3c, 0x04,
- 0x65, 0xf2, 0x60, 0x4b, 0x77, 0xd5, 0x14, 0xe4, 0xe0, 0x5f, 0xc4, 0x62,
- 0xae, 0x18, 0x0b, 0x04, 0x4c, 0x6b, 0x13, 0x60, 0x3a, 0xe4, 0x0b, 0x07,
- 0x04, 0x03, 0x04, 0x1c, 0x0a, 0x02, 0x06, 0x10, 0x06, 0x0b, 0x0d, 0xd5,
- 0x52, 0xee, 0x60, 0x47, 0x9d, 0x03, 0x03, 0x03, 0x12, 0x0b, 0x13, 0x83,
- 0xe8, 0xe0, 0x59, 0xa0, 0xe4, 0x41, 0x7d, 0xe0, 0x46, 0x4d, 0xe7, 0x02,
- 0x84, 0xe2, 0xe0, 0x60, 0x1f, 0xae, 0x60, 0x46, 0x43, 0xd9, 0xed, 0xe5,
- 0x14, 0x07, 0x04, 0x0a, 0x04, 0x04, 0x0a, 0x0a, 0x09, 0x17, 0x0f, 0x06,
- 0x15, 0x15, 0x60, 0x31, 0x8a, 0xe0, 0x2d, 0xa2, 0x7a, 0x61, 0x6a, 0xf3,
- 0xe0, 0x4f, 0x7e, 0xf8, 0xe0, 0x5c, 0xd7, 0x77, 0x69, 0x73, 0x6d, 0x69,
- 0x6c, 0xec, 0xe0, 0x5a, 0x7c, 0xf6, 0xe0, 0x4b, 0x97, 0xf3, 0xe0, 0x52,
- 0xea, 0xee, 0x04, 0xe0, 0x26, 0xe9, 0x75, 0xe7, 0xe0, 0x5f, 0xb1, 0xec,
- 0x04, 0xe0, 0x60, 0x40, 0x75, 0xf8, 0xe0, 0x4a, 0x1a, 0xeb, 0x04, 0xe0,
- 0x5b, 0xac, 0xf3, 0xe0, 0x26, 0xd4, 0xe9, 0x03, 0x08, 0x87, 0x74, 0x75,
- 0x6e, 0x67, 0xf3, 0xe0, 0x20, 0x4a, 0xf2, 0x60, 0x26, 0xc4, 0xe0, 0x2b,
- 0x82, 0xeb, 0xe0, 0x4b, 0x5f, 0xe7, 0x08, 0x60, 0x39, 0xb0, 0x60, 0x26,
- 0x31, 0xb1, 0x6e, 0x69, 0xe3, 0xe0, 0x52, 0xec, 0x66, 0x72, 0xe1, 0xe0,
- 0x5e, 0xf6, 0xe3, 0x03, 0x05, 0x86, 0x7a, 0xee, 0xe0, 0x26, 0x3d, 0x6c,
- 0x65, 0xf2, 0xe0, 0x55, 0x5e, 0xe3, 0x60, 0x5a, 0x7a, 0xc4, 0xcb, 0xe2,
- 0x03, 0x06, 0x85, 0x74, 0x69, 0xed, 0xe0, 0x28, 0xab, 0x6f, 0xf2, 0xe0,
- 0x4e, 0xfb, 0x65, 0x73, 0xe2, 0xe0, 0x59, 0x43, 0xe1, 0x05, 0x06, 0x03,
- 0xdf, 0xf6, 0xf3, 0x60, 0x52, 0x18, 0xcd, 0x9b, 0xee, 0xdf, 0xfb, 0x64,
- 0x70, 0x61, 0x67, 0x65, 0xf3, 0xe0, 0x47, 0xc6, 0xe3, 0x07, 0x07, 0x60,
- 0x5f, 0x05, 0xc1, 0xfc, 0x75, 0x62, 0x65, 0xad, 0xe0, 0x35, 0xd2, 0xec,
- 0x02, 0x85, 0x73, 0x74, 0x61, 0x67, 0x65, 0xae, 0xe0, 0x26, 0x29, 0xe1,
- 0x17, 0x06, 0x10, 0x0b, 0x12, 0x08, 0x0b, 0x05, 0x04, 0x40, 0x42, 0x0e,
- 0x06, 0x06, 0x06, 0x07, 0x0d, 0x0b, 0x60, 0x5a, 0x88, 0xc5, 0x85, 0xfa,
- 0x60, 0x48, 0x3a, 0xd6, 0xa6, 0xf7, 0x05, 0x04, 0xe0, 0x60, 0xcd, 0xf9,
- 0xe0, 0x4d, 0x62, 0xae, 0x60, 0x5c, 0x8a, 0xc2, 0xc3, 0x76, 0xe1, 0x04,
- 0xe0, 0x51, 0xbe, 0x67, 0xe9, 0xe0, 0x5c, 0x9c, 0xf4, 0x05, 0x05, 0xe0,
- 0x60, 0xb1, 0x72, 0xef, 0xe0, 0x5e, 0x87, 0x69, 0xee, 0x60, 0x5a, 0x68,
- 0xc4, 0xca, 0xf3, 0x03, 0xc0, 0x9b, 0xe1, 0xe0, 0x56, 0xd1, 0xf2, 0x07,
- 0x60, 0x25, 0xed, 0xe0, 0x33, 0xd1, 0xf3, 0xde, 0x17, 0x71, 0xf5, 0xe0,
- 0x56, 0xb3, 0xf0, 0xe0, 0x4e, 0xc6, 0xee, 0x08, 0x04, 0x04, 0x1f, 0x0e,
- 0xe0, 0x59, 0x16, 0xf8, 0xe0, 0x59, 0x37, 0xe7, 0xe0, 0x4e, 0xc7, 0xe4,
- 0x08, 0x06, 0x06, 0x60, 0x59, 0x2d, 0xc7, 0x3b, 0x72, 0x6f, 0xf6, 0xe0,
- 0x4d, 0x03, 0x69, 0x6e, 0x67, 0xae, 0xd8, 0x44, 0x2d, 0x34, 0x2d, 0x73,
- 0x61, 0x6c, 0xe5, 0xe0, 0x22, 0xc9, 0xe3, 0x04, 0xe0, 0x54, 0xbf, 0x61,
- 0xf3, 0x04, 0xe0, 0x4c, 0xe4, 0xe8, 0xda, 0x39, 0x62, 0xe9, 0xc3, 0xe1,
- 0xed, 0x04, 0xe0, 0x4c, 0xd9, 0x62, 0x6f, 0x72, 0x67, 0x68, 0xe9, 0xe0,
- 0x42, 0xf6, 0x6b, 0x61, 0xf3, 0xe0, 0x5f, 0x46, 0x6a, 0x6f, 0xec, 0xe0,
- 0x2a, 0x3b, 0x68, 0x70, 0xf0, 0xe0, 0x58, 0xb3, 0x63, 0x61, 0x69, 0xf8,
- 0xe0, 0x5e, 0x8f, 0xe2, 0x02, 0x87, 0xef, 0x60, 0x37, 0x48, 0xe0, 0x21,
- 0xb0, 0xae, 0xc4, 0x61, 0x61, 0x6b, 0x65, 0x73, 0x76, 0x75, 0x65, 0xed,
- 0xe0, 0x5c, 0x6f, 0x2d, 0x73, 0x70, 0xe5, 0xe0, 0x22, 0x2f, 0x2d, 0x6f,
- 0x2d, 0x67, 0x2d, 0x69, 0xad, 0xe0, 0x34, 0xfa, 0xeb, 0x22, 0x12, 0x3a,
- 0x0a, 0x36, 0x41, 0x4a, 0x09, 0x04, 0x40, 0x7a, 0x0d, 0x41, 0x8c, 0x2e,
- 0x0c, 0x1b, 0x41, 0x8c, 0x3f, 0x06, 0x04, 0x40, 0x4e, 0x05, 0x43, 0xbe,
- 0x1b, 0x60, 0x29, 0x70, 0xe0, 0x29, 0xb1, 0x1f, 0xc3, 0x04, 0xe0, 0x2b,
- 0x08, 0x61, 0x72, 0x1f, 0x43, 0x61, 0x1f, 0x45, 0x61, 0x6a, 0xef, 0xc8,
- 0x4e, 0xf9, 0x09, 0x07, 0x60, 0x44, 0x19, 0x56, 0x18, 0xc5, 0x85, 0x75,
- 0x72, 0x61, 0xe7, 0xe0, 0x26, 0x95, 0xef, 0x05, 0x08, 0xe0, 0x42, 0xee,
- 0x77, 0x61, 0xae, 0x60, 0x59, 0xeb, 0xc4, 0x17, 0xf4, 0x02, 0x86, 0xef,
- 0x60, 0x5e, 0x01, 0xc1, 0xa3, 0xe1, 0x02, 0x8a, 0xee, 0x02, 0x83, 0xe7,
- 0xcb, 0x07, 0xe1, 0xe0, 0x51, 0xd3, 0x6d, 0xe2, 0xe0, 0x26, 0x7a, 0xf7,
- 0x04, 0xe0, 0x5f, 0x88, 0xf0, 0x43, 0xda, 0xdb, 0xfe, 0xf6, 0x06, 0x07,
- 0x18, 0xe0, 0x43, 0xcd, 0x1f, 0x43, 0xe6, 0x24, 0xe0, 0x50, 0x2a, 0xe9,
- 0x02, 0x8d, 0xf4, 0x02, 0x86, 0xf3, 0x60, 0x53, 0xc9, 0xc3, 0x78, 0x65,
- 0xf3, 0xdc, 0xa7, 0xee, 0x04, 0xe0, 0x25, 0x3c, 0xee, 0xc1, 0x94, 0xe1,
- 0x07, 0x04, 0x60, 0x50, 0x26, 0xc3, 0x8a, 0xee, 0xe0, 0x50, 0x50, 0xec,
- 0xe0, 0x48, 0xfd, 0xf5, 0x13, 0x05, 0x05, 0x0b, 0x24, 0x40, 0x4a, 0x08,
- 0x40, 0x44, 0x3a, 0x09, 0x0e, 0x0d, 0x4b, 0xd4, 0xe0, 0x46, 0xed, 0x7a,
- 0x75, 0xed, 0xdc, 0xd1, 0x77, 0x61, 0xee, 0xc8, 0xcc, 0xf4, 0x04, 0xe0,
- 0x22, 0x28, 0x63, 0x68, 0xe1, 0xe0, 0x2e, 0xb2, 0xf3, 0x06, 0x08, 0x0b,
- 0xe0, 0x4d, 0x75, 0x74, 0x61, 0x6e, 0x61, 0xe9, 0xe0, 0x5b, 0x8d, 0x68,
- 0xe9, 0x04, 0xe0, 0x53, 0x7d, 0xed, 0x56, 0x02, 0xc6, 0x19, 0x61, 0x74,
- 0x73, 0x75, 0xae, 0x60, 0x56, 0xb5, 0xc3, 0x20, 0xf2, 0x06, 0x03, 0x23,
- 0x06, 0x04, 0x84, 0x75, 0xed, 0xb6, 0xef, 0x07, 0x03, 0x07, 0x09, 0x03,
- 0xcb, 0x33, 0xf4, 0xc7, 0xb1, 0x6d, 0x61, 0x74, 0x73, 0xf5, 0xd6, 0xfe,
- 0x69, 0xf3, 0x04, 0xe0, 0x4e, 0x3a, 0xe8, 0xdb, 0xf1, 0xe7, 0xd3, 0x13,
- 0x62, 0xe5, 0xe0, 0x25, 0xa4, 0x69, 0x79, 0xe1, 0xe0, 0x52, 0x42, 0xe7,
- 0xe0, 0x50, 0xf4, 0xe5, 0xe0, 0x53, 0x7e, 0xe1, 0x02, 0x85, 0x74, 0xe5,
- 0xe0, 0x47, 0x70, 0x73, 0x68, 0x69, 0xeb, 0xe0, 0x53, 0x7b, 0x6f, 0x6b,
- 0x67, 0x72, 0xef, 0xe0, 0x24, 0x3f, 0xee, 0x05, 0x14, 0x03, 0x07, 0x99,
- 0x73, 0xf4, 0x05, 0x04, 0xe0, 0x5b, 0xe4, 0xf5, 0xe0, 0x53, 0xfc, 0x73,
- 0x61, 0x6d, 0x6d, 0x6c, 0xf5, 0xe0, 0x47, 0xb1, 0xef, 0xd4, 0xc0, 0x6e,
- 0x65, 0x70, 0xf0, 0xe0, 0x5a, 0x03, 0xe9, 0x04, 0x08, 0x05, 0x84, 0xf4,
- 0x04, 0xe0, 0x5b, 0x33, 0xef, 0xc5, 0xa1, 0x73, 0x61, 0xeb, 0xd9, 0x09,
- 0xed, 0xe0, 0x4f, 0x1c, 0xe7, 0xdd, 0xae, 0x64, 0x65, 0x6e, 0xae, 0xe0,
- 0x2c, 0xc7, 0xed, 0x03, 0x04, 0x8e, 0xe9, 0xe0, 0x25, 0x4c, 0xe5, 0x02,
- 0x85, 0x6e, 0xe1, 0xe0, 0x4b, 0x3e, 0x6a, 0x69, 0xed, 0xe0, 0x22, 0x4b,
- 0xe1, 0x06, 0x05, 0x07, 0x0a, 0xdb, 0x20, 0x74, 0x6f, 0xf2, 0xd9, 0x2b,
- 0x6e, 0x6f, 0xae, 0x60, 0x52, 0xfc, 0xb5, 0x6d, 0x6f, 0x74, 0x6f, 0xae,
- 0x60, 0x57, 0x29, 0xc5, 0x71, 0x6b, 0x6f, 0x67, 0xe5, 0xe0, 0x59, 0x8e,
- 0x6c, 0x65, 0x75, 0x76, 0x65, 0xee, 0xe0, 0x46, 0x09, 0xea, 0x04, 0xe0,
- 0x25, 0xa4, 0xf5, 0x04, 0xe0, 0x4c, 0x89, 0x6b, 0xf5, 0xc5, 0xca, 0xe4,
- 0x02, 0x83, 0xef, 0xc2, 0xd6, 0x61, 0x6d, 0x61, 0x74, 0xf3, 0xd7, 0x15,
- 0x63, 0x68, 0x69, 0x6e, 0x6f, 0xf4, 0xe0, 0x24, 0x22, 0x74, 0x69, 0x73,
- 0x74, 0x6f, 0xf2, 0xe0, 0x3f, 0x6f, 0x73, 0xae, 0xd2, 0x66, 0xf2, 0x0c,
- 0x09, 0x05, 0x16, 0x0c, 0x0a, 0x29, 0x60, 0x5b, 0x41, 0xc2, 0x45, 0x1f,
- 0xc3, 0x02, 0x82, 0xf8, 0x97, 0xe5, 0xc0, 0x55, 0x79, 0xed, 0xe0, 0x42,
- 0x4e, 0xef, 0x02, 0x8b, 0x6b, 0x73, 0x74, 0x61, 0x64, 0x65, 0x6c, 0xf6,
- 0xe0, 0x57, 0xfa, 0x64, 0x73, 0x68, 0x65, 0xf2, 0xe0, 0x29, 0x22, 0x69,
- 0x73, 0x74, 0x69, 0x61, 0x6e, 0xf3, 0x60, 0x50, 0xef, 0xc6, 0x7e, 0xe5,
- 0x04, 0xe0, 0x5b, 0x6f, 0x6c, 0xec, 0xe0, 0x36, 0xbd, 0xe1, 0x04, 0x0f,
- 0x06, 0x88, 0x73, 0xee, 0x02, 0x87, 0x6f, 0x64, 0x61, 0xf2, 0xe0, 0x5b,
- 0xbf, 0xe9, 0xe0, 0x22, 0x9a, 0x6b, 0x6f, 0xf7, 0xe0, 0x4c, 0x41, 0x67,
- 0x65, 0xf2, 0x60, 0x48, 0x9d, 0xcd, 0x1f, 0x61, 0x6e, 0x67, 0xe8, 0xe0,
- 0x2a, 0xb8, 0xae, 0x60, 0x41, 0xf6, 0x55, 0x84, 0x44, 0x10, 0xc1, 0xf4,
- 0xf0, 0x08, 0x41, 0xc5, 0x60, 0x5a, 0x83, 0xc1, 0x2b, 0xed, 0xe0, 0x5d,
- 0x71, 0xef, 0x13, 0x11, 0x04, 0x1a, 0x18, 0x25, 0x0d, 0x06, 0x0f, 0x33,
- 0x40, 0x4e, 0x09, 0x13, 0x15, 0x05, 0x10, 0x05, 0x89, 0xfa, 0x02, 0x84,
- 0xef, 0xe0, 0x5d, 0x4e, 0xe1, 0x05, 0x60, 0x52, 0xeb, 0x84, 0xeb, 0xe0,
- 0x40, 0x90, 0xf9, 0xe0, 0x52, 0xe9, 0xf5, 0x04, 0x05, 0x05, 0x86, 0x7a,
- 0xf5, 0xe0, 0x57, 0x82, 0x79, 0x61, 0xed, 0xc5, 0xeb, 0x6e, 0x6f, 0xf3,
- 0xe0, 0x41, 0x66, 0x68, 0x6f, 0xeb, 0xc5, 0xa2, 0xf4, 0x04, 0xe0, 0x40,
- 0xa8, 0xef, 0x03, 0x03, 0x86, 0xf5, 0xc4, 0x76, 0x68, 0x69, 0xf2, 0xe0,
- 0x4f, 0x56, 0xae, 0x60, 0x57, 0xe9, 0xc1, 0xe8, 0xf3, 0x04, 0x06, 0x11,
- 0x83, 0x75, 0x67, 0xe5, 0xe0, 0x32, 0xdc, 0xe8, 0x06, 0x40, 0xe8, 0xe0,
- 0x48, 0xac, 0xe9, 0x03, 0xd9, 0xe7, 0x6d, 0x69, 0xfa, 0xe0, 0x58, 0x71,
- 0xe5, 0xd7, 0xeb, 0xe1, 0x46, 0x2a, 0xe0, 0x4c, 0xcb, 0xf2, 0x02, 0x83,
- 0xf9, 0xd7, 0x9e, 0x69, 0x79, 0x61, 0xed, 0xe0, 0x51, 0xae, 0x70, 0x65,
- 0xf2, 0xe0, 0x22, 0x32, 0xef, 0x02, 0x84, 0xf2, 0xe0, 0x4d, 0x7d, 0x62,
- 0x69, 0x6e, 0x2e, 0xe5, 0xe0, 0x3c, 0xdf, 0xee, 0x07, 0x08, 0x11, 0x0b,
- 0xe0, 0x4b, 0x5a, 0x79, 0x76, 0x65, 0x6c, 0xef, 0xe0, 0x5b, 0xcb, 0xf3,
- 0x02, 0x86, 0x75, 0x6c, 0x61, 0xf4, 0xdd, 0x07, 0x6b, 0x6f, 0x77, 0x6f,
- 0xec, 0xe0, 0x4e, 0x40, 0x67, 0xf3, 0x04, 0xe0, 0x2e, 0x1f, 0x76, 0xe9,
- 0xe0, 0x46, 0x9a, 0x61, 0x6e, 0xae, 0x60, 0x57, 0x6e, 0x89, 0xed, 0x05,
- 0x06, 0x0b, 0x13, 0x87, 0x76, 0x75, 0xf8, 0xe0, 0x4b, 0x87, 0xef, 0x02,
- 0x84, 0xf2, 0xe0, 0x4e, 0xa2, 0x6e, 0xef, 0xd0, 0xdc, 0x6d, 0x75, 0xee,
- 0x04, 0xe0, 0x5a, 0xf4, 0x61, 0x6c, 0x66, 0x6f, 0x72, 0x62, 0x75, 0x6e,
- 0xe4, 0xe0, 0x4b, 0x69, 0x66, 0x6f, 0x72, 0xe2, 0xe0, 0x4b, 0x62, 0xe1,
- 0x06, 0x0f, 0x4b, 0x31, 0xcc, 0x45, 0x74, 0x73, 0xf5, 0x06, 0x60, 0x54,
- 0x9e, 0xc7, 0xbb, 0x73, 0x68, 0x69, 0xed, 0xd2, 0xa5, 0x67, 0x61, 0x6e,
- 0xe5, 0xe0, 0x59, 0x39, 0x6c, 0x6f, 0x62, 0x72, 0x7a, 0xe5, 0xe0, 0x2d,
- 0x86, 0xeb, 0x03, 0x06, 0x85, 0x75, 0x62, 0x75, 0xee, 0xda, 0xae, 0x6f,
- 0x6e, 0xef, 0xc5, 0x4a, 0xe1, 0xe0, 0x57, 0x02, 0xe7, 0x02, 0x84, 0xe5,
- 0xe0, 0x3f, 0x95, 0xe1, 0x02, 0x85, 0x6e, 0xe5, 0xe0, 0x58, 0xda, 0xae,
- 0x60, 0x50, 0x9d, 0xc4, 0x0f, 0x66, 0xf5, 0xe0, 0x31, 0xe9, 0xe5, 0x02,
- 0x84, 0xec, 0xe0, 0x4a, 0x54, 0x62, 0x65, 0x6e, 0x68, 0x61, 0xf6, 0xe0,
- 0x51, 0x6c, 0x64, 0x61, 0xe9, 0xd9, 0xa9, 0x63, 0x68, 0x69, 0xae, 0x60,
- 0x56, 0x4e, 0xc4, 0x0d, 0xe2, 0x03, 0x07, 0x83, 0x69, 0x65, 0x72, 0x7a,
- 0xf9, 0xde, 0x0f, 0xe5, 0xc0, 0xdc, 0x61, 0x79, 0x61, 0x73, 0xe8, 0xc3,
- 0x08, 0xee, 0x06, 0x09, 0x0b, 0xe0, 0x5b, 0xc8, 0x78, 0x2d, 0x73, 0x65,
- 0x72, 0xf6, 0xe0, 0x3c, 0xa1, 0x6f, 0x77, 0x73, 0x69, 0x74, 0x61, 0x6c,
- 0xec, 0xe0, 0x4c, 0x0a, 0x69, 0x67, 0x68, 0x74, 0x70, 0x6f, 0x69, 0x6e,
- 0x74, 0x2e, 0x73, 0x79, 0x73, 0x74, 0x65, 0xed, 0xe0, 0x5b, 0x49, 0xed,
- 0x06, 0x60, 0x40, 0x1e, 0xdb, 0x90, 0x70, 0x73, 0xf0, 0xdb, 0xfc, 0xec,
- 0x04, 0x06, 0x06, 0x86, 0x1f, 0x43, 0xe6, 0xe0, 0x53, 0xc3, 0x6f, 0x64,
- 0x7a, 0xeb, 0xde, 0x99, 0x65, 0x70, 0xf0, 0xe0, 0x5a, 0x0e, 0xe1, 0xe0,
- 0x53, 0xb3, 0xe9, 0x16, 0x05, 0x15, 0x0b, 0x40, 0x90, 0x27, 0x17, 0x1c,
- 0x12, 0x0d, 0x18, 0x04, 0x0a, 0x04, 0x0c, 0x0a, 0x60, 0x58, 0x70, 0xc1,
- 0x99, 0x7a, 0xf5, 0xe0, 0x4d, 0xb5, 0xf9, 0x03, 0xd9, 0x42, 0xef, 0x04,
- 0xe0, 0x56, 0xcd, 0xf3, 0x06, 0x56, 0x85, 0xe0, 0x28, 0x66, 0x61, 0xf4,
- 0xe0, 0x4f, 0xcf, 0xf7, 0x03, 0xc4, 0xf4, 0xe9, 0x60, 0x20, 0x38, 0xe0,
- 0x3b, 0x20, 0xf4, 0x02, 0x84, 0x63, 0xe8, 0xdb, 0xb5, 0xe1, 0x0b, 0x06,
- 0x04, 0x0a, 0x0b, 0x08, 0x17, 0x10, 0x14, 0x08, 0x8b, 0x79, 0x61, 0xed,
- 0xe0, 0x50, 0xdc, 0x75, 0xf2, 0xd2, 0x2b, 0x73, 0x68, 0x69, 0x6f, 0x62,
- 0x61, 0xf2, 0xe0, 0x4f, 0xf7, 0x6e, 0x61, 0x6b, 0x61, 0x67, 0x75, 0x73,
- 0x75, 0xeb, 0xd9, 0x73, 0xed, 0x04, 0xe0, 0x59, 0x6e, 0xef, 0xc4, 0x4c,
- 0xeb, 0x02, 0x88, 0x79, 0x75, 0x73, 0x68, 0x75, 0xae, 0xc2, 0x07, 0xe1,
- 0x03, 0xd5, 0x49, 0x74, 0x61, 0xae, 0x60, 0x4d, 0x4c, 0xc8, 0x70, 0xe8,
- 0x02, 0x89, 0x69, 0x72, 0x6f, 0x73, 0x68, 0xe9, 0xe0, 0x4e, 0x6a, 0xe1,
- 0xe0, 0x50, 0x8a, 0x67, 0xe1, 0x02, 0x88, 0x77, 0x61, 0xae, 0x60, 0x4d,
- 0x30, 0xc8, 0x0b, 0x74, 0x61, 0xae, 0x60, 0x50, 0x8c, 0xc1, 0xf0, 0x64,
- 0x61, 0x69, 0x74, 0xef, 0xe0, 0x56, 0x66, 0xe1, 0x02, 0x84, 0x6b, 0xe9,
- 0xd9, 0x3e, 0xe9, 0xe0, 0x52, 0x33, 0xae, 0x60, 0x4d, 0x0a, 0x4a, 0x77,
- 0xc1, 0x7b, 0xf3, 0x03, 0x14, 0x88, 0xef, 0x05, 0x06, 0xe0, 0x57, 0x9c,
- 0x73, 0x61, 0x6b, 0xe9, 0xcf, 0x0b, 0x66, 0x75, 0x6b, 0x75, 0x73, 0xe8,
- 0xd0, 0x32, 0x68, 0x69, 0x77, 0x61, 0xe4, 0xe0, 0x3e, 0xc3, 0x61, 0x72,
- 0x61, 0xfa, 0xe0, 0x20, 0xb6, 0xf2, 0x07, 0x05, 0x60, 0x3e, 0x0f, 0xc9,
- 0xde, 0x79, 0xf5, 0xe0, 0x52, 0x40, 0x6f, 0x76, 0x6f, 0x67, 0x72, 0x61,
- 0xe4, 0xe0, 0x3e, 0xf7, 0xee, 0x07, 0x05, 0x05, 0x04, 0xe0, 0x55, 0xfc,
- 0x6f, 0xeb, 0xe0, 0x50, 0x18, 0x6b, 0xef, 0xe0, 0x54, 0x7c, 0xe7, 0xe0,
- 0x4e, 0x06, 0xe4, 0x60, 0x46, 0xff, 0xd1, 0x82, 0xed, 0x05, 0x04, 0xe0,
- 0x5a, 0x5e, 0xef, 0xe0, 0x55, 0xd3, 0xe9, 0x04, 0xe0, 0x20, 0x6f, 0xee,
- 0xdc, 0xf8, 0xec, 0x06, 0x60, 0x35, 0x1b, 0xcc, 0x37, 0x61, 0x74, 0xe9,
- 0xe0, 0x29, 0xb3, 0xeb, 0x03, 0x0a, 0x83, 0xf5, 0x03, 0xc4, 0x1f, 0x63,
- 0x68, 0xe9, 0xe0, 0x53, 0x2a, 0xef, 0xd2, 0x52, 0x69, 0x72, 0x61, 0xf2,
- 0xe0, 0x4a, 0xf7, 0xea, 0xe0, 0x2d, 0xa8, 0x68, 0xef, 0x03, 0xce, 0x7f,
- 0x6b, 0xf5, 0xe0, 0x55, 0x82, 0xe5, 0xe0, 0x3e, 0x89, 0x64, 0xf3, 0x04,
- 0xe0, 0x5a, 0x19, 0xae, 0x60, 0x55, 0x3f, 0xc2, 0x21, 0x63, 0x6b, 0x73,
- 0x2d, 0x61, 0x73, 0xf3, 0xe0, 0x2a, 0xa3, 0x62, 0x69, 0x63, 0x68, 0xf5,
- 0xc4, 0x3d, 0xe8, 0x09, 0x07, 0x16, 0x08, 0x60, 0x3e, 0x43, 0xca, 0x8a,
- 0x70, 0x6c, 0x61, 0xf9, 0xe0, 0x3c, 0x8f, 0x6d, 0x65, 0x6c, 0xee, 0x02,
- 0x88, 0x79, 0x74, 0x73, 0x6b, 0xf9, 0xe0, 0x3e, 0x46, 0x69, 0x74, 0x73,
- 0x6b, 0xe9, 0xe0, 0x3e, 0x4d, 0x65, 0x72, 0x73, 0x6f, 0xee, 0xe0, 0x3e,
- 0x46, 0xe1, 0x02, 0x86, 0x72, 0xeb, 0x60, 0x3e, 0x31, 0x83, 0x6b, 0x61,
- 0x73, 0xf3, 0xe0, 0x57, 0xe1, 0xe7, 0x60, 0x42, 0x9a, 0xd7, 0x28, 0xe6,
- 0xe0, 0x58, 0x1e, 0xe5, 0x0c, 0x0a, 0x05, 0x20, 0x06, 0x07, 0x60, 0x34,
- 0xfa, 0xe0, 0x24, 0x76, 0x79, 0x6d, 0x61, 0x63, 0x68, 0x69, 0xee, 0xe0,
- 0x2f, 0xee, 0x74, 0xf2, 0xe0, 0x3c, 0x6a, 0x72, 0x72, 0xf9, 0x03, 0x0b,
- 0x88, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0xe9, 0xe0, 0x4d, 0x92,
- 0x6c, 0x6f, 0x67, 0x69, 0xf3, 0xe0, 0x51, 0xd6, 0x68, 0x6f, 0x74, 0xe5,
- 0xe0, 0x46, 0x9f, 0xf0, 0x5c, 0x7a, 0xe0, 0x2c, 0x2f, 0x6d, 0x62, 0x75,
- 0xe3, 0xe0, 0x53, 0xa3, 0x69, 0xf3, 0xe0, 0x42, 0x1c, 0x64, 0xe4, 0xe0,
- 0x57, 0x57, 0xe1, 0x1a, 0x19, 0x04, 0x40, 0xa3, 0x0f, 0x40, 0x41, 0x40,
- 0x64, 0x40, 0x6a, 0x06, 0x40, 0x55, 0x40, 0xc6, 0x14, 0x26, 0x1f, 0x0e,
- 0x28, 0x10, 0xe0, 0x46, 0x82, 0xfa, 0x05, 0x05, 0xe0, 0x20, 0x7d, 0x75,
- 0xee, 0xe0, 0x20, 0x6e, 0x69, 0x6d, 0x69, 0x65, 0x72, 0x7a, 0x2d, 0x64,
- 0x6f, 0x6c, 0xee, 0xe0, 0x47, 0x6a, 0x79, 0xe1, 0xd1, 0x42, 0x77, 0xe1,
- 0x0e, 0x03, 0x05, 0x06, 0x0d, 0x03, 0x1c, 0x10, 0x12, 0x04, 0x10, 0x07,
- 0x10, 0x88, 0xfa, 0xd7, 0x00, 0x75, 0xe5, 0xe0, 0x50, 0xb2, 0x74, 0x61,
- 0xee, 0xe0, 0x3d, 0x1e, 0x73, 0x61, 0x6b, 0x69, 0xae, 0x03, 0xdf, 0x4c,
- 0x6a, 0xf0, 0xe0, 0x48, 0x00, 0xf2, 0xd7, 0x32, 0xee, 0x03, 0x0c, 0x87,
- 0x69, 0x73, 0x68, 0x69, 0xae, 0x60, 0x4d, 0xd9, 0x43, 0x3a, 0xc3, 0x37,
- 0x65, 0x68, 0x6f, 0xee, 0xe0, 0x4e, 0xee, 0x61, 0xe2, 0xe0, 0x52, 0xed,
- 0xed, 0x02, 0x88, 0x69, 0x6e, 0x61, 0x6d, 0xe9, 0xe0, 0x4b, 0x21, 0x61,
- 0xf4, 0xe0, 0x4d, 0xa0, 0xeb, 0x02, 0x84, 0x69, 0xf4, 0xc1, 0xb9, 0x61,
- 0x6d, 0x69, 0x2e, 0x6e, 0xe1, 0x60, 0x50, 0xe5, 0xc4, 0xcf, 0x6a, 0xe9,
- 0xd5, 0xa6, 0xe9, 0x02, 0x86, 0x69, 0x73, 0xe8, 0xe0, 0x4a, 0x2b, 0xae,
- 0x60, 0x20, 0x38, 0xe0, 0x30, 0x98, 0x68, 0x61, 0x72, 0xe1, 0xe0, 0x3c,
- 0x13, 0xe7, 0x02, 0x85, 0x75, 0x63, 0xe8, 0xc6, 0x6a, 0x6f, 0x65, 0xae,
- 0x60, 0x4d, 0x88, 0xc1, 0x0f, 0x63, 0x68, 0x69, 0x6e, 0x61, 0xe7, 0xc6,
- 0x29, 0xe2, 0xe0, 0x50, 0x3c, 0xf5, 0x02, 0x89, 0x74, 0x6f, 0x6b, 0x65,
- 0x69, 0xee, 0xe0, 0x50, 0xac, 0xe6, 0xd8, 0xe6, 0xf4, 0x03, 0x21, 0x8a,
- 0x73, 0xf5, 0x04, 0x07, 0x03, 0x87, 0x79, 0x61, 0x6d, 0xe1, 0xe0, 0x2b,
- 0xcd, 0xf5, 0xce, 0xb6, 0x73, 0x68, 0x69, 0xeb, 0xe0, 0x52, 0xab, 0x72,
- 0x61, 0x67, 0x69, 0xae, 0x60, 0x4d, 0xfe, 0xc2, 0x7a, 0xef, 0x02, 0x83,
- 0xf7, 0xda, 0x72, 0xf2, 0xe0, 0x3b, 0x93, 0xe1, 0x05, 0x07, 0xe0, 0x56,
- 0x70, 0x73, 0x68, 0x69, 0xee, 0xe0, 0x4f, 0xf1, 0x67, 0x61, 0xed, 0xc1,
- 0x92, 0xf3, 0x07, 0x06, 0x1e, 0x1f, 0xe0, 0x31, 0xe3, 0x7a, 0x75, 0xe2,
- 0xe0, 0x46, 0x65, 0xf5, 0x04, 0x03, 0x08, 0x87, 0xf9, 0xd6, 0x57, 0x6d,
- 0x69, 0x67, 0x61, 0x75, 0xf2, 0xd1, 0xc7, 0x6b, 0x61, 0x62, 0xe5, 0xe0,
- 0x4c, 0xe5, 0x67, 0xe1, 0x60, 0x4c, 0x8d, 0xc6, 0x5e, 0x68, 0xe9, 0x04,
- 0x09, 0x08, 0x85, 0x77, 0xe1, 0x45, 0x8c, 0x59, 0xd9, 0xe0, 0x36, 0xcb,
- 0x6d, 0x61, 0xae, 0x60, 0x4d, 0xa7, 0xc2, 0xe2, 0x68, 0x61, 0xf2, 0xcd,
- 0x5a, 0xe2, 0xcd, 0x57, 0xe1, 0x07, 0x05, 0x41, 0xcb, 0xe0, 0x51, 0x69,
- 0x6f, 0xeb, 0xe0, 0x52, 0x49, 0x6d, 0xe1, 0x04, 0xe0, 0x50, 0x68, 0x74,
- 0x73, 0xf5, 0xe0, 0x4f, 0x73, 0xf2, 0x08, 0x0d, 0x06, 0x05, 0x06, 0x05,
- 0x0f, 0x85, 0xf5, 0x02, 0x83, 0xed, 0xdf, 0x4b, 0x69, 0x7a, 0x61, 0xf7,
- 0xe0, 0x3b, 0xbb, 0x74, 0x75, 0xfa, 0xe0, 0x45, 0xf3, 0x70, 0xe1, 0xe0,
- 0x40, 0x52, 0xed, 0x60, 0x4c, 0x10, 0xc3, 0x78, 0x6c, 0xf3, 0xe0, 0x4c,
- 0x09, 0xe9, 0x04, 0x04, 0xc5, 0xda, 0xf9, 0xe0, 0x3b, 0x26, 0x6b, 0x61,
- 0xf4, 0xe0, 0x2e, 0xc6, 0x65, 0xec, 0xe0, 0x55, 0xb5, 0xe1, 0x04, 0x0a,
- 0x10, 0x87, 0xf4, 0x04, 0xe0, 0x53, 0x47, 0x73, 0xf5, 0xe0, 0x4d, 0x34,
- 0xf3, 0x02, 0x84, 0x75, 0x79, 0xe1, 0xac, 0x6a, 0xef, 0x04, 0xe0, 0x4d,
- 0x34, 0xe8, 0xdc, 0xc2, 0x67, 0x61, 0x6e, 0xe4, 0xe0, 0x55, 0x90, 0x63,
- 0xef, 0xc4, 0x82, 0x70, 0x73, 0xe9, 0xe0, 0x57, 0x10, 0xee, 0x0a, 0x05,
- 0x05, 0x0e, 0x07, 0x05, 0x06, 0x12, 0xc5, 0x8e, 0x7a, 0x61, 0xeb, 0xde,
- 0x35, 0x75, 0xed, 0xe0, 0x4b, 0xda, 0xef, 0x02, 0x85, 0x79, 0xe1, 0xe0,
- 0x51, 0x54, 0x6e, 0x6a, 0xe9, 0xe0, 0x49, 0x81, 0x6e, 0xe1, 0x60, 0x4a,
- 0xeb, 0xc4, 0x06, 0x6d, 0x61, 0xeb, 0xd3, 0x80, 0xe9, 0x60, 0x4b, 0x13,
- 0xc3, 0xbd, 0xe5, 0x02, 0x8a, 0x79, 0x61, 0x6d, 0x61, 0xae, 0x60, 0x4c,
- 0x0c, 0xc5, 0xd4, 0x67, 0x61, 0xf3, 0xd4, 0xbd, 0xe1, 0x06, 0x54, 0x80,
- 0xe0, 0x3e, 0x06, 0x7a, 0x61, 0x77, 0xe1, 0xe0, 0x4f, 0x5a, 0xed, 0x05,
- 0x0e, 0x40, 0x93, 0x8d, 0xef, 0x04, 0x03, 0xd4, 0x98, 0xe5, 0xcf, 0x1e,
- 0xae, 0x60, 0x49, 0x44, 0xc9, 0xa6, 0xe9, 0x0c, 0x0f, 0x17, 0x04, 0x0f,
- 0x06, 0x20, 0x05, 0x0b, 0x06, 0x05, 0x86, 0xf4, 0x02, 0x86, 0x73, 0x75,
- 0xe5, 0xe0, 0x45, 0x57, 0x6f, 0x6e, 0xe4, 0xe0, 0x4c, 0x85, 0xf3, 0x03,
- 0x09, 0x86, 0xf5, 0x04, 0xe0, 0x4f, 0x64, 0x6e, 0xe1, 0xdd, 0xcd, 0x68,
- 0x69, 0xe8, 0xe0, 0x4b, 0x3f, 0x61, 0xf4, 0xde, 0x0a, 0x6f, 0xeb, 0xd5,
- 0x38, 0x6e, 0xef, 0x02, 0x85, 0x79, 0x61, 0xed, 0xdd, 0x57, 0x6b, 0x61,
- 0xf7, 0xe0, 0x4b, 0x40, 0x6d, 0x69, 0xee, 0xe0, 0x4c, 0x5d, 0xeb, 0x03,
- 0x07, 0x87, 0x6f, 0x61, 0x6e, 0xe9, 0xe0, 0x30, 0xbb, 0x69, 0x74, 0x61,
- 0x79, 0xe1, 0xcb, 0xde, 0x61, 0x77, 0x61, 0xae, 0x04, 0xe0, 0x4c, 0x93,
- 0xe8, 0x60, 0x51, 0xeb, 0xc3, 0x02, 0x6a, 0x69, 0xed, 0xcb, 0xed, 0xe9,
- 0x02, 0x85, 0x7a, 0x75, 0xed, 0xc4, 0x50, 0xe3, 0xdd, 0x15, 0x67, 0x6f,
- 0xf2, 0xe0, 0x51, 0xd0, 0x66, 0x75, 0xf2, 0xdc, 0xd2, 0x61, 0x6d, 0xe1,
- 0xe0, 0x4f, 0x5c, 0xae, 0x5c, 0xb4, 0xe0, 0x34, 0x0d, 0xe5, 0x02, 0x86,
- 0x79, 0x61, 0x6d, 0xe1, 0xca, 0xbb, 0x6f, 0xeb, 0xdd, 0x4a, 0xe1, 0x03,
- 0x04, 0x85, 0x6b, 0xf5, 0xc5, 0x98, 0x69, 0x73, 0xe8, 0xdd, 0xd5, 0x67,
- 0x61, 0xf9, 0xd3, 0xe5, 0xec, 0x03, 0x05, 0x86, 0x75, 0xe7, 0xe0, 0x54,
- 0x62, 0x6d, 0x79, 0xeb, 0xe0, 0x45, 0xc6, 0x69, 0xf3, 0xe0, 0x3e, 0xd5,
- 0xeb, 0x05, 0x04, 0x04, 0x07, 0x86, 0x75, 0xe4, 0xdc, 0x72, 0x6f, 0xe7,
- 0xca, 0x7d, 0x69, 0x6e, 0x6f, 0xeb, 0xe0, 0x50, 0x93, 0x65, 0x67, 0x61,
- 0xf7, 0xdd, 0x82, 0x61, 0x6d, 0x69, 0x67, 0x61, 0x68, 0x61, 0xf2, 0xe0,
- 0x26, 0xcb, 0xe9, 0x07, 0x05, 0x04, 0x05, 0xe0, 0x2b, 0xcc, 0x7a, 0xf5,
- 0xe0, 0x3a, 0x25, 0xf4, 0xe0, 0x30, 0x0b, 0x73, 0xe5, 0xe0, 0x49, 0x75,
- 0x6e, 0x61, 0x6e, 0xae, 0x60, 0x4b, 0x9a, 0xc5, 0x0b, 0x68, 0xef, 0x04,
- 0xe0, 0x3e, 0x9d, 0x6b, 0x75, 0xae, 0x60, 0x4a, 0xcc, 0xc3, 0x64, 0xe7,
- 0x02, 0x8c, 0x6f, 0x73, 0x68, 0x69, 0x6d, 0x61, 0xae, 0x60, 0x4f, 0xe3,
- 0xc4, 0x56, 0xe1, 0x06, 0x60, 0x4e, 0x14, 0xc3, 0x4f, 0x6d, 0xe9, 0x05,
- 0x05, 0xe0, 0x50, 0x13, 0x6e, 0xef, 0xe0, 0x50, 0x2a, 0x69, 0x73, 0xe8,
- 0xe0, 0x46, 0x65, 0xe4, 0x03, 0xc3, 0x62, 0xef, 0x02, 0x84, 0xed, 0xe0,
- 0x39, 0xd3, 0x67, 0x61, 0xf7, 0xcc, 0xa3, 0x61, 0xf3, 0xe0, 0x30, 0x54,
- 0x38, 0x73, 0xae, 0x06, 0x09, 0x60, 0x20, 0x47, 0x87, 0x70, 0x6c, 0x2d,
- 0x77, 0x61, 0xf7, 0xe0, 0x20, 0x50, 0x6e, 0x6c, 0x2d, 0x61, 0x6d, 0xf3,
- 0xe0, 0x20, 0x47, 0x31, 0x32, 0xae, 0x15, 0x07, 0x0c, 0x04, 0x08, 0x04,
- 0x0a, 0x60, 0x32, 0xab, 0x48, 0x38, 0x04, 0x1c, 0x0a, 0x02, 0x16, 0x06,
- 0x02, 0x09, 0x8d, 0xf7, 0x60, 0x3b, 0x3e, 0x2e, 0xd1, 0xc5, 0xf6, 0x05,
- 0x60, 0x3b, 0x5a, 0x86, 0xe9, 0x60, 0x4f, 0xe2, 0xc5, 0x85, 0xf5, 0xe0,
- 0x3b, 0x53, 0xf4, 0x60, 0x3a, 0xee, 0x40, 0x41, 0xd8, 0xe4, 0xf3, 0xe0,
- 0x3b, 0x40, 0xee, 0x60, 0x3b, 0x00, 0x03, 0x03, 0x03, 0x12, 0x1e, 0x83,
- 0xe9, 0x06, 0x60, 0x3b, 0x13, 0x03, 0xa3, 0xec, 0x60, 0x4f, 0xbb, 0xc5,
- 0x85, 0xea, 0x16, 0x09, 0x3a, 0x18, 0x1c, 0x40, 0x81, 0x04, 0x06, 0x1e,
- 0x12, 0x04, 0x40, 0xb4, 0x0a, 0x29, 0x23, 0x51, 0xed, 0xe0, 0x32, 0x85,
- 0x1f, 0x43, 0xf8, 0x03, 0xc0, 0xba, 0xf2, 0xc0, 0xb6, 0xf5, 0x09, 0x04,
- 0x06, 0x04, 0x0f, 0x0e, 0xe0, 0x3c, 0x2f, 0xf2, 0xe0, 0x53, 0x90, 0x6e,
- 0x69, 0xf0, 0xe0, 0x41, 0x9c, 0xe9, 0xe0, 0x3d, 0xe6, 0xe5, 0x02, 0x84,
- 0xe7, 0xe0, 0x32, 0x44, 0x64, 0x69, 0x73, 0x63, 0xe8, 0xe0, 0x4d, 0xbc,
- 0xe4, 0x02, 0x87, 0x79, 0x67, 0x61, 0xf2, 0xe0, 0x25, 0x39, 0xe1, 0xe0,
- 0x28, 0xa9, 0x2e, 0xed, 0xe0, 0x53, 0x7f, 0x73, 0xae, 0x06, 0x60, 0x50,
- 0x57, 0xc1, 0xb1, 0x77, 0x70, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x70,
- 0x6f, 0x77, 0x65, 0xf2, 0xe0, 0x4b, 0x2e, 0xf0, 0x0a, 0x07, 0x60, 0x24,
- 0x2f, 0x4d, 0x87, 0xe0, 0x23, 0x01, 0x6d, 0x6f, 0x72, 0xe7, 0xe0, 0x50,
- 0xab, 0xae, 0x60, 0x41, 0x38, 0x47, 0x34, 0x46, 0x3f, 0xc5, 0xe8, 0xef,
- 0x11, 0x05, 0x09, 0x10, 0x0d, 0x04, 0x08, 0x06, 0x09, 0x06, 0x07, 0x07,
- 0x60, 0x49, 0xf4, 0xca, 0x4d, 0x7a, 0xe9, 0xe0, 0x51, 0x71, 0xf9, 0x04,
- 0xe0, 0x54, 0x91, 0xef, 0xe0, 0x46, 0xd0, 0x75, 0x72, 0x6e, 0x61, 0xec,
- 0x04, 0xe0, 0x51, 0xa5, 0x69, 0xf3, 0x60, 0x4a, 0xaa, 0xc4, 0xfb, 0xf4,
- 0x04, 0xe0, 0x54, 0x78, 0x65, 0x6c, 0x75, 0x6c, 0xf5, 0xe0, 0x3c, 0x52,
- 0xf3, 0xe0, 0x45, 0x10, 0xf2, 0x04, 0xe0, 0x53, 0x1b, 0xf0, 0xcd, 0xc8,
- 0x6c, 0x73, 0xf4, 0xe0, 0x48, 0xc3, 0x69, 0x6e, 0x76, 0x69, 0x6c, 0xec,
- 0xe0, 0x3b, 0xa9, 0x68, 0x61, 0x6e, 0xe1, 0xdb, 0x1f, 0x67, 0x61, 0x73,
- 0xfa, 0xe0, 0x53, 0x56, 0x65, 0x74, 0x73, 0xf5, 0xe0, 0x50, 0x2a, 0xe2,
- 0x03, 0x04, 0x89, 0xf5, 0xe0, 0x3f, 0xbb, 0xf3, 0x04, 0xe0, 0x54, 0x34,
- 0xae, 0xe0, 0x52, 0x7b, 0x6f, 0xea, 0xdb, 0xb0, 0xee, 0xe0, 0x51, 0xf2,
- 0xed, 0x60, 0x43, 0x21, 0xcf, 0x77, 0xec, 0x06, 0x60, 0x40, 0xde, 0xd0,
- 0xf5, 0x73, 0x2d, 0x73, 0x74, 0xef, 0x03, 0x02, 0x82, 0xb3, 0x84, 0xb2,
- 0x82, 0x31, 0x2e, 0x65, 0x6c, 0x61, 0x73, 0x74, 0xf8, 0xe0, 0x53, 0xe3,
- 0xe9, 0x04, 0xe0, 0x52, 0x82, 0x6e, 0x73, 0x65, 0x6b, 0x69, 0x6b, 0x6f,
- 0x67, 0x65, 0xee, 0xe0, 0x48, 0xab, 0xe6, 0xe0, 0x4b, 0x9a, 0xe5, 0x10,
- 0x0f, 0x07, 0x05, 0x05, 0x09, 0x06, 0x40, 0x60, 0x06, 0x04, 0x52, 0x59,
- 0xe0, 0x40, 0xeb, 0xf7, 0x02, 0x88, 0x69, 0x73, 0xe8, 0x60, 0x48, 0x23,
- 0xc8, 0xfb, 0x65, 0xec, 0xd9, 0x63, 0x76, 0x6e, 0x61, 0xeb, 0xe0, 0x48,
- 0x2c, 0x74, 0xfa, 0xe0, 0x52, 0x0e, 0x73, 0xf3, 0xe0, 0x46, 0xbe, 0x72,
- 0x75, 0x73, 0x61, 0x6c, 0xe5, 0xe0, 0x49, 0xdf, 0x6f, 0xee, 0x60, 0x36,
- 0xb5, 0x85, 0xec, 0x03, 0x09, 0x97, 0x6c, 0x79, 0x62, 0x65, 0x61, 0xee,
- 0xe0, 0x4b, 0x6b, 0xe5, 0x02, 0x84, 0xee, 0xe0, 0x45, 0x28, 0xae, 0x08,
- 0x60, 0x34, 0xe0, 0x47, 0x42, 0xd6, 0x75, 0x63, 0xec, 0x60, 0x3b, 0x71,
- 0xc8, 0x40, 0x61, 0x73, 0x74, 0x69, 0x63, 0xae, 0x04, 0x0e, 0x0c, 0x8e,
- 0xf4, 0x04, 0xe0, 0x2a, 0x61, 0x73, 0x75, 0x6b, 0x61, 0x65, 0xf2, 0xe0,
- 0x27, 0xa1, 0x73, 0x61, 0x76, 0x65, 0x69, 0x6e, 0x63, 0x6c, 0x6f, 0xf5,
- 0xdd, 0x21, 0x72, 0x65, 0x67, 0x72, 0x75, 0x68, 0x6f, 0x73, 0x74, 0x69,
- 0xee, 0xe0, 0x39, 0x77, 0x64, 0x6f, 0x67, 0x61, 0x64, 0x6f, 0xae, 0xe0,
- 0x4e, 0x5c, 0x66, 0x66, 0x65, 0xf2, 0xd0, 0xc8, 0xe5, 0xe0, 0x51, 0xb8,
- 0x64, 0x2e, 0x77, 0x61, 0x66, 0x61, 0xe9, 0xe0, 0x4e, 0x00, 0xe4, 0x04,
- 0xe0, 0x23, 0xa0, 0x65, 0xf6, 0xe0, 0x4d, 0xf6, 0xe3, 0x05, 0x1b, 0xe0,
- 0x49, 0x1a, 0x6c, 0x6f, 0x75, 0xe4, 0x02, 0x87, 0xae, 0x02, 0x8d, 0xeb,
- 0xe0, 0x4f, 0xfb, 0x2d, 0x76, 0x65, 0x72, 0x2d, 0x6a, 0x70, 0x63, 0x2e,
- 0x69, 0xeb, 0xe0, 0x20, 0x59, 0x2e, 0x6e, 0x65, 0x65, 0xee, 0xe0, 0x52,
- 0xbf, 0xe1, 0x0a, 0x05, 0x0e, 0x52, 0xc5, 0x60, 0x29, 0x6e, 0xc5, 0xdf,
- 0x77, 0x6f, 0xf2, 0xd5, 0xf6, 0xed, 0x04, 0x03, 0xdd, 0xfa, 0xe9, 0xd0,
- 0x6f, 0x62, 0x79, 0xec, 0xe0, 0x51, 0x09, 0x67, 0xf5, 0xe0, 0x41, 0x0b,
- 0xae, 0x05, 0x17, 0xe0, 0x52, 0xc5, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x66,
- 0x6f, 0x72, 0x63, 0x65, 0xae, 0x04, 0xe0, 0x52, 0xac, 0x63, 0x6f, 0x6d,
- 0x2e, 0xe3, 0xe0, 0x41, 0xb7, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x68,
- 0x69, 0x66, 0xf4, 0xe0, 0x4f, 0x69, 0xe9, 0x23, 0x40, 0x43, 0x05, 0x40,
- 0x4b, 0x1d, 0x40, 0x80, 0x43, 0x35, 0x19, 0x22, 0x17, 0x42, 0x90, 0x40,
- 0x54, 0x29, 0x3b, 0x27, 0x05, 0x12, 0x06, 0x08, 0x40, 0x4b, 0x40, 0x54,
- 0x23, 0x0d, 0x06, 0xe0, 0x28, 0x0b, 0xfa, 0x04, 0x3a, 0xda, 0x4d, 0xf5,
- 0x05, 0x08, 0xe0, 0x48, 0x85, 0x6e, 0x6f, 0x6b, 0x75, 0xee, 0xe0, 0x48,
- 0x87, 0xed, 0x02, 0x8c, 0xef, 0x04, 0xe0, 0x4c, 0xe9, 0x7a, 0x61, 0x6b,
- 0xe9, 0xe0, 0x4e, 0x5d, 0xe9, 0x04, 0x06, 0x05, 0x87, 0x7a, 0x61, 0xeb,
- 0xe0, 0x43, 0x11, 0x73, 0xe1, 0xe0, 0x50, 0x97, 0x6f, 0x74, 0x73, 0xf5,
- 0xe0, 0x50, 0x92, 0xae, 0x60, 0x4c, 0x64, 0xc4, 0x2b, 0x65, 0xee, 0xd6,
- 0x49, 0x79, 0xef, 0xe0, 0x4d, 0xad, 0xf7, 0x02, 0x83, 0xe9, 0xd7, 0x2a,
- 0xe1, 0x08, 0x13, 0x08, 0x09, 0x0c, 0x07, 0xcc, 0x45, 0xf4, 0x04, 0x07,
- 0xd9, 0x96, 0x73, 0x75, 0x6b, 0xe9, 0xe0, 0x47, 0x02, 0x65, 0xae, 0x59,
- 0xb5, 0xe0, 0x36, 0xda, 0xee, 0x04, 0xe0, 0x3f, 0xe1, 0xf5, 0xcd, 0x3f,
- 0xed, 0x03, 0xcb, 0xc8, 0x69, 0xfa, 0xe0, 0x46, 0xf2, 0xeb, 0x04, 0xe0,
- 0x42, 0xbb, 0xf5, 0x03, 0xcc, 0xdd, 0xee, 0xd0, 0x55, 0x66, 0x75, 0x6e,
- 0xe5, 0xe0, 0x46, 0x91, 0x64, 0xe5, 0xe0, 0x47, 0xa7, 0xf6, 0x04, 0x04,
- 0xcb, 0x5c, 0xe7, 0xe0, 0x4b, 0xd9, 0x61, 0x6e, 0xef, 0x02, 0x85, 0x76,
- 0xef, 0xe0, 0x50, 0x10, 0x2d, 0x66, 0x72, 0x61, 0x6e, 0x6b, 0xe9, 0xe0,
- 0x28, 0x54, 0xf4, 0x0c, 0x05, 0x11, 0x05, 0x0d, 0x29, 0x1b, 0x60, 0x4d,
- 0xc7, 0xc3, 0xa6, 0x73, 0xae, 0xe0, 0x34, 0xf2, 0xef, 0x05, 0x03, 0xe0,
- 0x47, 0xcd, 0xed, 0xd5, 0xc6, 0x69, 0x67, 0x61, 0x77, 0xe1, 0xe0, 0x4d,
- 0xac, 0x69, 0xe7, 0xe0, 0x38, 0xc4, 0x63, 0x6f, 0x75, 0x6c, 0x64, 0x62,
- 0x65, 0x77, 0x6f, 0xf2, 0xe0, 0x51, 0x4d, 0xe1, 0x08, 0x07, 0x05, 0x04,
- 0x0a, 0xe0, 0x50, 0x9b, 0x79, 0x61, 0x6e, 0x61, 0xe7, 0xce, 0xb7, 0x6e,
- 0xef, 0xe0, 0x4c, 0x4b, 0xed, 0xe0, 0x4c, 0xec, 0xeb, 0x04, 0xe0, 0x42,
- 0x34, 0x75, 0xf2, 0xe0, 0x49, 0x3f, 0x62, 0x61, 0xf3, 0xe0, 0x4e, 0x40,
- 0x31, 0xae, 0x02, 0x8a, 0x65, 0x75, 0x72, 0x2e, 0x61, 0x72, 0x75, 0x62,
- 0x61, 0x2e, 0x6a, 0x65, 0x6e, 0x76, 0x2d, 0x61, 0x72, 0x75, 0x62, 0xe1,
- 0xe0, 0x39, 0x4f, 0xae, 0x60, 0x24, 0x8c, 0xe0, 0x26, 0xd5, 0xf3, 0x0d,
- 0x05, 0x1d, 0x18, 0x07, 0x0e, 0x23, 0x2a, 0x1f, 0x08, 0xe0, 0x50, 0x95,
- 0x75, 0xed, 0xe0, 0x34, 0x99, 0xf4, 0x06, 0x05, 0x0a, 0xe0, 0x51, 0x3d,
- 0x6d, 0xe5, 0xe0, 0x26, 0x44, 0x65, 0x69, 0x6e, 0x67, 0x65, 0x65, 0xeb,
- 0xe0, 0x2c, 0x2b, 0x61, 0x6e, 0x62, 0xf5, 0xe0, 0x4e, 0xf1, 0xf3, 0x02,
- 0x8f, 0x6d, 0x61, 0x72, 0x74, 0x65, 0x72, 0x74, 0x68, 0x61, 0x6e, 0x79,
- 0xef, 0xe0, 0x50, 0x04, 0x68, 0x69, 0xeb, 0xe0, 0x4b, 0xf8, 0x6d, 0x61,
- 0x69, 0xec, 0xe0, 0x4f, 0x08, 0xec, 0x02, 0x87, 0x65, 0x6f, 0x66, 0xed,
- 0xe0, 0x22, 0x9a, 0xe1, 0xe0, 0x20, 0x58, 0x68, 0xe9, 0x03, 0x08, 0x90,
- 0x6e, 0x6f, 0x6d, 0x61, 0x6b, 0xe9, 0xd7, 0x41, 0x6b, 0xe1, 0x04, 0xe0,
- 0x4f, 0x48, 0x77, 0x61, 0xae, 0x60, 0x4b, 0xa9, 0x40, 0xd9, 0xc2, 0xcf,
- 0x67, 0x61, 0xeb, 0xe0, 0x4c, 0x76, 0xe5, 0x06, 0x07, 0x12, 0x04, 0xc5,
- 0x19, 0x73, 0x61, 0x6b, 0xe9, 0xe0, 0x48, 0x8a, 0xf2, 0x04, 0xe0, 0x38,
- 0x37, 0xf6, 0x04, 0xe0, 0x2c, 0x0d, 0x73, 0x63, 0x68, 0x75, 0xec, 0xe0,
- 0x27, 0x12, 0xee, 0xe0, 0x4a, 0xcc, 0x68, 0x61, 0xf2, 0xe0, 0x4c, 0x26,
- 0xe1, 0x03, 0x06, 0x86, 0x68, 0x61, 0xf9, 0xe0, 0x34, 0xc0, 0xae, 0x60,
- 0x4a, 0xb9, 0xc1, 0x1f, 0xad, 0x02, 0x89, 0x68, 0x6f, 0x63, 0x6b, 0x65,
- 0x79, 0xee, 0xd8, 0xc2, 0xe7, 0xc1, 0xcb, 0xae, 0x50, 0xee, 0x60, 0x39,
- 0xa3, 0xc4, 0x10, 0xad, 0x0c, 0x0e, 0x26, 0x06, 0x0e, 0x04, 0x0a, 0x09,
+ 0x37, 0x2d, 0x73, 0x65, 0x63, 0xf5, 0xe0, 0x81, 0x05, 0xf2, 0x09, 0x55,
+ 0x53, 0x60, 0x7e, 0x93, 0x0b, 0xc2, 0x44, 0x68, 0xf4, 0xe0, 0x7f, 0x01,
+ 0x71, 0x75, 0x61, 0x72, 0xe5, 0x04, 0xe0, 0x96, 0x02, 0x37, 0xae, 0x60,
+ 0x95, 0x77, 0x0e, 0xc0, 0x7d, 0xf0, 0x0b, 0x06, 0x0c, 0x08, 0x06, 0x09,
+ 0x0b, 0x04, 0xe0, 0x86, 0xfa, 0x79, 0x64, 0xe5, 0xe0, 0x69, 0xb2, 0xef,
+ 0x04, 0xe0, 0x94, 0x4a, 0x72, 0xf4, 0x60, 0x95, 0x04, 0xc1, 0x02, 0x6a,
+ 0x65, 0x6c, 0x6b, 0xe1, 0xe0, 0x5d, 0x93, 0x68, 0x69, 0xee, 0xe0, 0x34,
+ 0xb5, 0x65, 0x63, 0x74, 0x72, 0x75, 0xed, 0xe0, 0x39, 0x19, 0x64, 0x6e,
+ 0x73, 0xae, 0x60, 0x90, 0xcd, 0x42, 0x4a, 0xc2, 0x2f, 0xe2, 0xe0, 0x92,
+ 0x3d, 0xe1, 0x04, 0xe0, 0x95, 0xd6, 0x63, 0xe5, 0x05, 0x04, 0xe0, 0x95,
+ 0xcb, 0xeb, 0xe0, 0x69, 0xad, 0x2d, 0x74, 0x6f, 0x2d, 0xf2, 0xe0, 0x8b,
+ 0xb4, 0xef, 0x1e, 0x08, 0x0d, 0x25, 0x06, 0x1f, 0x06, 0x13, 0x07, 0x04,
+ 0x07, 0x0c, 0x05, 0x07, 0x49, 0x71, 0x4a, 0xaf, 0x60, 0x29, 0xf0, 0x60,
+ 0x52, 0x39, 0x42, 0x82, 0x41, 0x36, 0xc1, 0x01, 0x75, 0x6e, 0x64, 0x63,
+ 0xe1, 0xe0, 0x21, 0xf5, 0xf3, 0x07, 0x60, 0x55, 0xb3, 0xe0, 0x3b, 0x26,
+ 0x6e, 0xef, 0xe0, 0x80, 0x42, 0xf2, 0x09, 0x04, 0x05, 0x05, 0x49, 0x63,
+ 0xe0, 0x74, 0x94, 0xf4, 0xe0, 0x88, 0xcd, 0x72, 0xe5, 0xe0, 0x21, 0x3b,
+ 0x6f, 0xe3, 0xe0, 0x72, 0xb8, 0xad, 0x06, 0x60, 0x21, 0x48, 0x04, 0x86,
+ 0x76, 0x61, 0xf2, 0xe0, 0x7f, 0x5a, 0x70, 0x6f, 0xf4, 0xe0, 0x83, 0xc5,
+ 0xee, 0x09, 0x04, 0x07, 0x60, 0x54, 0x29, 0xe0, 0x3e, 0xef, 0xec, 0xe0,
+ 0x3f, 0x15, 0xe7, 0x60, 0x2c, 0xf9, 0xe0, 0x68, 0x5c, 0x64, 0xf2, 0x04,
+ 0xe0, 0x7c, 0xfb, 0xe5, 0xe0, 0x21, 0x08, 0xed, 0x60, 0x8a, 0x02, 0xc0,
+ 0x77, 0xec, 0x02, 0x8b, 0xf5, 0x04, 0xe0, 0x8e, 0x9f, 0x74, 0x69, 0xef,
+ 0xe0, 0x85, 0x30, 0xe1, 0x60, 0x93, 0x9b, 0xbc, 0xeb, 0x60, 0x5e, 0x4f,
+ 0xe0, 0x2c, 0x46, 0xea, 0xe0, 0x8f, 0x63, 0x67, 0xee, 0x60, 0x8e, 0x03,
+ 0xc5, 0x86, 0x66, 0xf4, 0x04, 0xe0, 0x74, 0x15, 0x77, 0x61, 0xf2, 0xe0,
+ 0x65, 0x45, 0x65, 0xe4, 0xe0, 0x55, 0xc0, 0x64, 0x65, 0x67, 0xe1, 0xe0,
+ 0x40, 0x20, 0xe3, 0x07, 0x05, 0x04, 0x04, 0xe0, 0x62, 0xc1, 0x74, 0xf2,
+ 0xe0, 0x8c, 0x49, 0xe8, 0xe0, 0x25, 0x75, 0xe3, 0xe0, 0x81, 0x50, 0xae,
+ 0x05, 0x60, 0x89, 0x0d, 0x88, 0x73, 0x72, 0xe3, 0xc1, 0x4b, 0xee, 0x0a,
+ 0x07, 0x08, 0x06, 0x04, 0x60, 0x81, 0x4f, 0xd3, 0x6f, 0x1f, 0x43, 0xe5,
+ 0x1b, 0xe0, 0x5c, 0x81, 0xef, 0x03, 0xd2, 0x7a, 0xe1, 0xe0, 0x5c, 0x93,
+ 0x69, 0x6c, 0xec, 0xe0, 0x85, 0x1f, 0xe3, 0xe0, 0x89, 0xd8, 0xe1, 0x04,
+ 0xe0, 0x5c, 0x81, 0x61, 0xf3, 0xe0, 0x93, 0x21, 0xed, 0x0a, 0x05, 0x06,
+ 0x03, 0x04, 0x60, 0x79, 0x8f, 0xdb, 0x08, 0x1f, 0x43, 0xf8, 0xd7, 0xc9,
+ 0x75, 0x73, 0xe8, 0xe0, 0x4c, 0x7f, 0xef, 0xd7, 0xc0, 0xe9, 0xe0, 0x92,
+ 0xa7, 0xe1, 0x02, 0x91, 0x72, 0xf4, 0x04, 0xe0, 0x94, 0x8e, 0x6c, 0x61,
+ 0x62, 0x65, 0x6c, 0x69, 0x6e, 0xe7, 0xe0, 0x61, 0x11, 0x6c, 0x6c, 0x2d,
+ 0x77, 0x65, 0xe2, 0xe0, 0x91, 0xad, 0xec, 0x0c, 0x05, 0x06, 0x60, 0x75,
+ 0xa8, 0x49, 0x38, 0x43, 0x27, 0xd2, 0x5b, 0x75, 0xf0, 0xe0, 0x36, 0x55,
+ 0x64, 0xae, 0x60, 0x92, 0x6c, 0x84, 0xe1, 0x04, 0xe0, 0x36, 0x47, 0x74,
+ 0xf4, 0xe0, 0x7c, 0xdb, 0xeb, 0x0e, 0x0d, 0x15, 0x0d, 0x04, 0x14, 0x1d,
+ 0x10, 0x10, 0x60, 0x80, 0xcf, 0xd2, 0xf6, 0x1f, 0xc3, 0x02, 0x85, 0x65,
+ 0xee, 0xe0, 0x87, 0x8c, 0x61, 0xee, 0xc0, 0x75, 0xf9, 0x08, 0x06, 0x60,
+ 0x57, 0x0a, 0xe0, 0x3d, 0x23, 0x67, 0x65, 0xe1, 0xe0, 0x64, 0xf1, 0x64,
+ 0x69, 0xf6, 0xe0, 0x84, 0xa6, 0xef, 0x05, 0x04, 0xe0, 0x56, 0xf3, 0xe4,
+ 0xe0, 0x62, 0xd0, 0xe3, 0xcb, 0x48, 0x6c, 0xe5, 0xd7, 0xed, 0xea, 0x05,
+ 0x06, 0xe0, 0x6b, 0x92, 0x1f, 0x43, 0xe5, 0xe0, 0x89, 0x7d, 0x65, 0x72,
+ 0xf6, 0x60, 0x88, 0x57, 0xc3, 0x0d, 0xe9, 0x09, 0x06, 0x60, 0x92, 0x5d,
+ 0x40, 0x5b, 0xc1, 0x3a, 0x70, 0x74, 0xf6, 0xe0, 0x4e, 0x8a, 0xe5, 0x04,
+ 0xe0, 0x8d, 0xb8, 0x72, 0xf6, 0x60, 0x55, 0x61, 0xe0, 0x38, 0x62, 0x65,
+ 0x64, 0x73, 0x6d, 0xef, 0x04, 0xe0, 0x92, 0x47, 0x6b, 0x6f, 0x72, 0xf3,
+ 0xe0, 0x4e, 0x6d, 0xe1, 0x02, 0x84, 0xf5, 0xe0, 0x8d, 0x9c, 0xee, 0x04,
+ 0xe0, 0x87, 0x12, 0xe9, 0xe0, 0x8c, 0x2b, 0xae, 0x60, 0x8d, 0x66, 0xc4,
+ 0xb6, 0xea, 0x60, 0x64, 0xd2, 0xe0, 0x2e, 0xec, 0xe9, 0x0e, 0x29, 0x09,
+ 0x0d, 0x1b, 0x09, 0x03, 0x04, 0x0a, 0x60, 0x80, 0xe6, 0xd2, 0x4f, 0x74,
+ 0xe5, 0x06, 0x05, 0x07, 0xe0, 0x93, 0x95, 0x73, 0xae, 0xe0, 0x6d, 0x96,
+ 0x6c, 0x65, 0x61, 0xe6, 0xe0, 0x93, 0x74, 0x2e, 0xf4, 0x02, 0x88, 0x72,
+ 0x61, 0x6e, 0x73, 0xe9, 0xe0, 0x61, 0x8b, 0x62, 0x2d, 0x68, 0x6f, 0x73,
+ 0xf4, 0xe0, 0x86, 0x09, 0xf2, 0x04, 0xe0, 0x8c, 0x5f, 0x61, 0xe3, 0xce,
+ 0x8d, 0xee, 0x02, 0x84, 0xe7, 0xe0, 0x29, 0x8a, 0xe1, 0x60, 0x92, 0x82,
+ 0xc0, 0xed, 0x6d, 0x70, 0x6c, 0xe5, 0x04, 0xe0, 0x23, 0x90, 0x73, 0x69,
+ 0x74, 0x65, 0xae, 0x06, 0x60, 0x7f, 0x1a, 0xc9, 0x67, 0x63, 0x6f, 0xed,
+ 0x60, 0x90, 0xf3, 0xc2, 0x5d, 0xec, 0x04, 0xe0, 0x90, 0xe4, 0xea, 0xe0,
+ 0x24, 0x9c, 0xe9, 0xd7, 0xa1, 0xe7, 0xe0, 0x8c, 0x26, 0xe5, 0x04, 0xe0,
+ 0x8a, 0xf3, 0x6c, 0xec, 0xe0, 0x6a, 0xc0, 0xe3, 0x04, 0xe0, 0x91, 0x2d,
+ 0x69, 0xec, 0x60, 0x8a, 0x23, 0xc2, 0x7b, 0xe8, 0x0d, 0x04, 0x07, 0x40,
+ 0x6a, 0x42, 0x06, 0x04, 0x60, 0x7d, 0x2d, 0xd3, 0x6f, 0xf7, 0xe0, 0x92,
+ 0x12, 0x75, 0x6e, 0x61, 0xee, 0xe0, 0x90, 0xfd, 0xef, 0x0b, 0x10, 0x05,
+ 0x3a, 0x09, 0x60, 0x40, 0x60, 0xe0, 0x46, 0x55, 0xf7, 0x06, 0x60, 0x90,
+ 0x20, 0xc2, 0xdd, 0x61, 0xae, 0x60, 0x76, 0xb5, 0x53, 0x7b, 0xc3, 0x60,
+ 0x75, 0xea, 0xe0, 0x90, 0xd9, 0xf0, 0x09, 0x06, 0x06, 0x04, 0x05, 0x06,
+ 0xe0, 0x92, 0xca, 0x77, 0x61, 0x72, 0xe5, 0xc3, 0xd3, 0x73, 0x65, 0xec,
+ 0xe0, 0x27, 0x1b, 0xf0, 0xe0, 0x7d, 0x56, 0x69, 0x74, 0xf3, 0xd8, 0x77,
+ 0x61, 0x72, 0xe5, 0xe0, 0x35, 0x14, 0xae, 0x0b, 0x60, 0x49, 0x38, 0x43,
+ 0xfa, 0x60, 0x35, 0x14, 0xcb, 0xf3, 0x62, 0x72, 0x65, 0x6e, 0x64, 0x6c,
+ 0xf9, 0xd5, 0x9c, 0x6e, 0x61, 0x69, 0xae, 0x60, 0x87, 0x23, 0xc0, 0x65,
+ 0x62, 0x61, 0xf2, 0xe0, 0x6e, 0x9a, 0xe9, 0x18, 0x12, 0x05, 0x11, 0x40,
+ 0x4b, 0x13, 0x40, 0x6e, 0x40, 0x7a, 0x29, 0x0b, 0x05, 0x15, 0x0f, 0x60,
+ 0x28, 0x8b, 0x60, 0x62, 0xe9, 0xc3, 0xa7, 0x7a, 0xf5, 0x02, 0x89, 0x6f,
+ 0x6b, 0x61, 0xae, 0x60, 0x88, 0x24, 0xc8, 0xb6, 0x6b, 0xf5, 0xe0, 0x3f,
+ 0xa3, 0x74, 0xe1, 0xe0, 0x50, 0x0a, 0xf3, 0x05, 0x04, 0xe0, 0x8c, 0x3a,
+ 0xf5, 0xe0, 0x76, 0x6a, 0x68, 0x69, 0x6b, 0xf5, 0xe0, 0x27, 0xcf, 0xf2,
+ 0x03, 0x18, 0x84, 0xef, 0x02, 0x86, 0x73, 0x61, 0xf4, 0xe0, 0x82, 0x95,
+ 0xe9, 0x04, 0xe0, 0x90, 0x75, 0x73, 0x68, 0x69, 0xae, 0x60, 0x5a, 0xd3,
+ 0xe0, 0x2c, 0xdd, 0xe9, 0xe0, 0x3c, 0x5c, 0xe1, 0x05, 0x06, 0x09, 0x04,
+ 0x8e, 0x74, 0x61, 0xeb, 0xe0, 0x5b, 0x06, 0xef, 0x04, 0xe0, 0x90, 0x7e,
+ 0xeb, 0xe0, 0x5b, 0x57, 0xee, 0xe0, 0x7f, 0x8f, 0xeb, 0x04, 0xe0, 0x90,
+ 0x48, 0x61, 0x77, 0x61, 0xae, 0x60, 0x89, 0x4b, 0xc3, 0x6d, 0xe8, 0xe0,
+ 0x3a, 0x5a, 0xef, 0x03, 0x04, 0x86, 0xf9, 0xe0, 0x86, 0x8f, 0x6a, 0x69,
+ 0xf2, 0xe0, 0x8e, 0xfa, 0x67, 0xe1, 0xe0, 0x4f, 0xe9, 0xee, 0x0b, 0x0b,
+ 0x0d, 0x0e, 0x06, 0x08, 0x11, 0x10, 0xe0, 0x51, 0x13, 0x79, 0x6f, 0x73,
+ 0x68, 0x69, 0x74, 0x6f, 0xed, 0xe0, 0x49, 0x3c, 0x74, 0xef, 0x07, 0x60,
+ 0x3c, 0x90, 0xe0, 0x4c, 0x8b, 0xeb, 0xe0, 0x8d, 0x31, 0x73, 0x68, 0xe9,
+ 0x02, 0x84, 0xf2, 0xe0, 0x89, 0x23, 0x6e, 0xef, 0xe0, 0x8d, 0x21, 0x6f,
+ 0x6e, 0x73, 0xe5, 0xc5, 0x63, 0x6b, 0x61, 0x6d, 0x69, 0x67, 0xef, 0xd5,
+ 0xce, 0xea, 0x02, 0x85, 0x75, 0xeb, 0xe0, 0x75, 0xc6, 0x6f, 0xae, 0x60,
+ 0x86, 0x94, 0x42, 0xcf, 0xc2, 0x9b, 0xe7, 0x02, 0x89, 0x75, 0xae, 0x60,
+ 0x86, 0x23, 0x40, 0xe7, 0xc5, 0xcf, 0xef, 0xe0, 0x56, 0x75, 0xe1, 0x04,
+ 0xe0, 0x66, 0x9d, 0x6e, 0x6f, 0x6d, 0x61, 0xe3, 0xe0, 0x8e, 0x86, 0xed,
+ 0x04, 0x40, 0x4a, 0x89, 0xef, 0x0b, 0x0a, 0x03, 0x0f, 0x07, 0x04, 0x06,
+ 0x06, 0xe0, 0x22, 0x89, 0x74, 0x73, 0xf5, 0x03, 0xd8, 0x76, 0xeb, 0xe0,
+ 0x42, 0xb7, 0xf3, 0xd7, 0x5e, 0xee, 0x02, 0x87, 0x6f, 0x73, 0x65, 0xeb,
+ 0xe0, 0x4e, 0xc4, 0x69, 0xf4, 0xe0, 0x88, 0xa2, 0xeb, 0x60, 0x3e, 0x3f,
+ 0xe0, 0x47, 0xf5, 0xea, 0xe0, 0x8c, 0xcb, 0x69, 0x63, 0xe8, 0xe0, 0x50,
+ 0x38, 0x66, 0x75, 0xf3, 0xe0, 0x51, 0x77, 0x64, 0xe1, 0x04, 0xe0, 0x86,
+ 0xed, 0x74, 0xe5, 0xe0, 0x89, 0xbb, 0x69, 0x7a, 0x75, 0xae, 0x60, 0x86,
+ 0xe5, 0xc8, 0xad, 0xe1, 0x08, 0x08, 0x0c, 0x60, 0x48, 0x8b, 0xd2, 0x2d,
+ 0x6e, 0x65, 0xae, 0x60, 0x8b, 0x80, 0xc4, 0x0a, 0xed, 0x02, 0x84, 0xef,
+ 0xe0, 0x6d, 0x20, 0x61, 0xeb, 0xe0, 0x8f, 0x71, 0x62, 0xe1, 0xe0, 0x2d,
+ 0xe0, 0xeb, 0x06, 0x05, 0x09, 0xe0, 0x42, 0x15, 0x73, 0xe8, 0xe0, 0x8f,
+ 0x6f, 0x6f, 0x6b, 0x75, 0x63, 0x68, 0xf5, 0xe0, 0x41, 0xfd, 0xe1, 0x0a,
+ 0x05, 0x60, 0x4c, 0x14, 0x42, 0xc5, 0xe0, 0x39, 0xf0, 0x74, 0xf3, 0xe0,
+ 0x75, 0x36, 0xef, 0xe0, 0x8f, 0x43, 0x6a, 0x6f, 0x6e, 0x61, 0x77, 0x61,
+ 0x74, 0xe5, 0xe0, 0x8f, 0x19, 0x69, 0xe2, 0xe0, 0x4a, 0xf1, 0x66, 0xf4,
+ 0x02, 0x85, 0x65, 0xe4, 0xe0, 0x64, 0xbf, 0x63, 0x72, 0x79, 0x70, 0x74,
+ 0x6f, 0xae, 0x60, 0x83, 0x3b, 0xcc, 0x94, 0x63, 0x68, 0xe9, 0x04, 0xe0,
+ 0x51, 0xd2, 0x6b, 0x61, 0x73, 0x68, 0xf5, 0xe0, 0x29, 0xff, 0xe2, 0x03,
+ 0x0a, 0x8a, 0xf5, 0x03, 0xc0, 0x8a, 0x6b, 0x61, 0xf7, 0xe0, 0x87, 0xea,
+ 0xe5, 0x04, 0xe0, 0x8b, 0xf8, 0x63, 0xe8, 0xe0, 0x8e, 0xcb, 0x61, 0x74,
+ 0x61, 0xae, 0x60, 0x59, 0x2a, 0xe0, 0x33, 0x33, 0xe5, 0xe0, 0x7f, 0xc2,
+ 0xe1, 0x07, 0x05, 0x07, 0x06, 0xe0, 0x8e, 0x12, 0xf2, 0x60, 0x8e, 0xdd,
+ 0x99, 0x6e, 0x67, 0x72, 0xe9, 0xe0, 0x6d, 0xc5, 0x6b, 0x6f, 0xf4, 0xe0,
+ 0x34, 0xed, 0x63, 0x6b, 0x6e, 0x65, 0xf4, 0xe0, 0x62, 0x59, 0xe7, 0x04,
+ 0xe0, 0x90, 0x75, 0xad, 0xe0, 0x5c, 0x16, 0xe6, 0x60, 0x8e, 0xdb, 0xbc,
+ 0xe5, 0x19, 0x0d, 0x06, 0x13, 0x40, 0xb6, 0x06, 0x25, 0x0f, 0x40, 0x4a,
+ 0x1b, 0x04, 0x1a, 0x04, 0x25, 0x0b, 0x06, 0x60, 0x6f, 0xc5, 0x5c, 0x4a,
+ 0xc2, 0x70, 0xf8, 0x06, 0x60, 0x8e, 0x14, 0xc2, 0x37, 0xae, 0x60, 0x8b,
+ 0xc5, 0xc3, 0x84, 0xf6, 0x41, 0xb5, 0xe0, 0x56, 0x0c, 0xf4, 0x05, 0x06,
+ 0xe0, 0x41, 0x0f, 0xef, 0x60, 0x84, 0xec, 0xc6, 0x03, 0x61, 0x67, 0x61,
+ 0xf9, 0xe0, 0x8a, 0x24, 0xf2, 0x03, 0xc0, 0xa7, 0xf6, 0x02, 0x99, 0x69,
+ 0x63, 0xe5, 0x04, 0xe0, 0x5f, 0xd6, 0xae, 0x04, 0xe0, 0x72, 0x6f, 0x67,
+ 0x6f, 0x76, 0xae, 0x04, 0xe0, 0x8c, 0xc3, 0x73, 0xe3, 0xe0, 0x64, 0x4f,
+ 0xe5, 0x0c, 0x09, 0x05, 0x05, 0x09, 0x12, 0x05, 0x18, 0x06, 0x06, 0x09,
+ 0x8f, 0x73, 0x61, 0x72, 0x63, 0x61, 0xf3, 0xe0, 0x86, 0x40, 0x72, 0xf3,
+ 0xe0, 0x69, 0xce, 0x71, 0x75, 0xe1, 0xc0, 0x5a, 0xf0, 0x04, 0xe0, 0x66,
+ 0x75, 0xb2, 0xe0, 0x8e, 0xfb, 0xed, 0x02, 0x85, 0x70, 0xb3, 0xe0, 0x8f,
+ 0xd6, 0x69, 0x6e, 0x65, 0x63, 0x72, 0x61, 0xe6, 0xe0, 0x83, 0x80, 0x69,
+ 0xf2, 0xe0, 0x6a, 0x4e, 0xe8, 0x03, 0x06, 0x85, 0x75, 0x6d, 0xef, 0xe0,
+ 0x66, 0xc6, 0x74, 0xf4, 0xe0, 0x8e, 0xd5, 0x61, 0x6c, 0x66, 0x6c, 0x69,
+ 0xe6, 0xe0, 0x88, 0x0c, 0x67, 0x61, 0xed, 0xe0, 0x4b, 0xd3, 0x66, 0x74,
+ 0xf0, 0xe0, 0x7b, 0xed, 0x65, 0x78, 0x63, 0x68, 0x61, 0xee, 0xe0, 0x5e,
+ 0xb3, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x74, 0x72, 0x69,
+ 0xeb, 0xe0, 0x87, 0xe8, 0xe2, 0x05, 0x05, 0xe0, 0x42, 0xe0, 0x6c, 0xef,
+ 0xe0, 0x89, 0xc2, 0xe2, 0xe0, 0x7b, 0xc5, 0xe1, 0x04, 0xe0, 0x84, 0x27,
+ 0x6e, 0x69, 0xf3, 0xe0, 0x4e, 0xe8, 0x6f, 0x75, 0xec, 0xe0, 0x78, 0x82,
+ 0xee, 0x07, 0x0d, 0x04, 0x06, 0xe0, 0x7b, 0xb1, 0xf3, 0x02, 0x84, 0xe9,
+ 0xe0, 0x2d, 0xaa, 0x65, 0x65, 0xf2, 0xe0, 0x89, 0x96, 0xee, 0xe0, 0x4f,
+ 0x4a, 0x64, 0x61, 0xe9, 0xe0, 0x37, 0xbf, 0x61, 0x73, 0xe1, 0xe0, 0x7d,
+ 0x3c, 0xed, 0x02, 0x86, 0x69, 0x6e, 0xe5, 0xe0, 0x57, 0xc8, 0x62, 0x6f,
+ 0xeb, 0xe0, 0x4f, 0x15, 0xec, 0x0a, 0x2b, 0x06, 0x5d, 0xc0, 0x60, 0x68,
+ 0xec, 0xc6, 0xbf, 0xec, 0x02, 0x9e, 0xf3, 0x02, 0x8a, 0x79, 0x6f, 0x75,
+ 0x72, 0x68, 0x6f, 0xed, 0xe0, 0x79, 0xe8, 0xad, 0x04, 0xe0, 0x78, 0xe7,
+ 0x66, 0x6f, 0x72, 0xad, 0x04, 0xe0, 0x8d, 0xe2, 0xec, 0xe0, 0x42, 0x84,
+ 0x66, 0x79, 0x2e, 0x73, 0x74, 0x6f, 0xf2, 0xe0, 0x8e, 0xa4, 0xea, 0x60,
+ 0x8a, 0xe1, 0xc2, 0x8e, 0x66, 0x69, 0x70, 0xae, 0x60, 0x7e, 0xcb, 0x4d,
+ 0x0c, 0x40, 0x56, 0x42, 0xac, 0x9c, 0xeb, 0x02, 0x8c, 0xe9, 0x07, 0x60,
+ 0x3c, 0x48, 0xe0, 0x49, 0xc6, 0xeb, 0xe0, 0x40, 0x65, 0x64, 0x31, 0x2e,
+ 0x62, 0x65, 0x65, 0x62, 0x79, 0xf4, 0xe0, 0x7f, 0xc9, 0xea, 0xe0, 0x39,
+ 0x27, 0xe9, 0x08, 0x08, 0x04, 0x60, 0x3b, 0xd8, 0xc3, 0xd5, 0x72, 0xef,
+ 0x60, 0x3d, 0xe6, 0xe0, 0x4c, 0x98, 0xe8, 0xe0, 0x4e, 0x77, 0x64, 0xe1,
+ 0xe0, 0x82, 0x68, 0xe5, 0xe0, 0x8c, 0x52, 0xe3, 0x05, 0x14, 0x05, 0xcd,
+ 0xee, 0x75, 0xf2, 0x04, 0xe0, 0x8d, 0x2d, 0x69, 0x74, 0xf9, 0x04, 0xe0,
+ 0x8e, 0xa2, 0x74, 0x61, 0x63, 0xf4, 0xe0, 0x65, 0x2c, 0x72, 0xe5, 0xe0,
+ 0x77, 0x97, 0x61, 0x61, 0xf3, 0xe0, 0x45, 0xbb, 0x62, 0x61, 0x73, 0x74,
+ 0x6f, 0x70, 0x6f, 0xec, 0xe0, 0x73, 0x80, 0xe1, 0x60, 0x72, 0x31, 0xda,
+ 0x95, 0xae, 0x60, 0x88, 0x1a, 0x03, 0x03, 0xc6, 0x3b, 0xe4, 0x08, 0x09,
+ 0x60, 0x4c, 0xae, 0xe0, 0x41, 0xb7, 0x73, 0x63, 0x6c, 0x6f, 0x75, 0xe4,
+ 0xe0, 0x7c, 0xc6, 0xee, 0xe0, 0x51, 0x3a, 0xe3, 0x0d, 0x1d, 0x0f, 0x40,
+ 0x91, 0x0a, 0x60, 0x7d, 0x8e, 0x45, 0xa5, 0xca, 0x59, 0xf2, 0x02, 0x86,
+ 0x79, 0x73, 0xe5, 0xe0, 0x68, 0xcc, 0x61, 0x70, 0xf0, 0x02, 0x86, 0x69,
+ 0x6e, 0xe7, 0xe0, 0x6b, 0x8e, 0x65, 0x72, 0x2d, 0x73, 0x69, 0xf4, 0xe0,
+ 0x8a, 0xc9, 0xe9, 0x04, 0xe0, 0x5e, 0xca, 0x65, 0xee, 0x04, 0xe0, 0x89,
+ 0x1c, 0xf4, 0xe0, 0x3d, 0x0b, 0xe8, 0x06, 0x06, 0x15, 0x31, 0x06, 0x88,
+ 0x77, 0x61, 0xf2, 0xe0, 0x8b, 0xaa, 0x75, 0xec, 0x07, 0x60, 0x64, 0xf4,
+ 0xe0, 0x27, 0xa1, 0x70, 0x6c, 0x61, 0x74, 0x74, 0x66, 0x6f, 0x72, 0xed,
+ 0xe0, 0x6a, 0xd3, 0xef, 0x03, 0x1f, 0x87, 0x6f, 0xec, 0x06, 0x08, 0x04,
+ 0xe0, 0x8d, 0xed, 0x73, 0x2e, 0x6e, 0x73, 0xf7, 0xe0, 0x74, 0xa7, 0xe2,
+ 0xe0, 0x47, 0x15, 0xae, 0x04, 0xe0, 0x89, 0x76, 0xee, 0x60, 0x8b, 0x74,
+ 0xc0, 0xcc, 0x6c, 0x61, 0x72, 0x73, 0xe8, 0xce, 0x4a, 0x6b, 0x6f, 0x6b,
+ 0xe5, 0xe0, 0x5c, 0xcb, 0x6d, 0x69, 0xe4, 0xe0, 0x8c, 0x13, 0x61, 0x65,
+ 0x66, 0x66, 0xec, 0xe0, 0x7a, 0x29, 0xae, 0x10, 0x04, 0x04, 0x08, 0x05,
+ 0x06, 0x60, 0x6c, 0xff, 0x40, 0x47, 0x4a, 0xd3, 0x42, 0x4b, 0x83, 0xf5,
+ 0xe0, 0x5a, 0xe1, 0xf4, 0xe0, 0x7a, 0x7e, 0xf3, 0x60, 0x8b, 0x43, 0x40,
+ 0xc2, 0xc1, 0x6c, 0xec, 0x60, 0x8b, 0x3e, 0xaf, 0xe9, 0x60, 0x8b, 0x53,
+ 0xc0, 0xf3, 0xe1, 0xe0, 0x8c, 0x1d, 0x61, 0x6c, 0x65, 0x62, 0x6f, 0x6f,
+ 0xeb, 0xe0, 0x5a, 0x1a, 0xae, 0x0d, 0x5d, 0xbe, 0x60, 0x2a, 0x80, 0x60,
+ 0x3e, 0xdf, 0x41, 0xb9, 0xc2, 0x4b, 0xec, 0x60, 0x8b, 0x14, 0x86, 0xe2,
+ 0x0a, 0x60, 0x72, 0x66, 0x58, 0x9f, 0x40, 0x50, 0xc2, 0x19, 0xec, 0xe0,
+ 0x74, 0xba, 0xe1, 0x1a, 0x0e, 0x04, 0x17, 0x07, 0x1a, 0x1c, 0x26, 0x0c,
+ 0x1a, 0x40, 0xa2, 0x23, 0x28, 0x40, 0x6e, 0x24, 0x12, 0x0d, 0x0a, 0x06,
+ 0x08, 0x1a, 0xe0, 0x8a, 0xcd, 0xf9, 0x04, 0xe0, 0x87, 0x18, 0x61, 0x6d,
+ 0x61, 0xae, 0x60, 0x82, 0xdd, 0xc8, 0x95, 0xf8, 0xe0, 0x8b, 0xb5, 0xf6,
+ 0x04, 0xe0, 0x84, 0xf0, 0xe5, 0x04, 0xe0, 0x8d, 0x33, 0x73, 0x2d, 0x74,
+ 0x68, 0x65, 0x2d, 0x77, 0x68, 0x61, 0xec, 0xe0, 0x8c, 0x0c, 0xf5, 0x60,
+ 0x32, 0xdc, 0xe0, 0x35, 0xcd, 0xf4, 0x03, 0x04, 0x8c, 0xf4, 0xe0, 0x38,
+ 0x86, 0x73, 0x75, 0x6d, 0x61, 0x73, 0x65, 0x6e, 0x64, 0xe1, 0xe0, 0x85,
+ 0xb4, 0x6f, 0x73, 0xe8, 0xe0, 0x3a, 0xbc, 0xf3, 0x06, 0x04, 0x05, 0xe0,
+ 0x8c, 0xf5, 0xf3, 0xe0, 0x74, 0xed, 0x65, 0xe2, 0xe0, 0x51, 0x5f, 0xe1,
+ 0x02, 0x85, 0x79, 0xe1, 0xe0, 0x4c, 0xb1, 0x67, 0xf5, 0xd5, 0x31, 0xf2,
+ 0x09, 0x06, 0x07, 0x04, 0x60, 0x8a, 0x7f, 0xc0, 0x4c, 0x75, 0x66, 0xf5,
+ 0xe0, 0x88, 0x25, 0x70, 0x73, 0x62, 0xef, 0xe0, 0x60, 0x79, 0xef, 0xe0,
+ 0x80, 0x5e, 0xe4, 0x02, 0x84, 0xe9, 0xe0, 0x74, 0x82, 0xe5, 0xe0, 0x77,
+ 0x6b, 0xf0, 0x04, 0xe0, 0x8c, 0xbe, 0x70, 0x6f, 0x72, 0xef, 0xe0, 0x35,
+ 0x25, 0xef, 0x03, 0x05, 0x87, 0x74, 0x6f, 0xed, 0xca, 0x82, 0x67, 0x6f,
+ 0x6e, 0xe3, 0xe0, 0x83, 0x2e, 0x62, 0x65, 0x72, 0x6e, 0x61, 0x72, 0xe4,
+ 0xe0, 0x80, 0x34, 0xee, 0x09, 0x05, 0x12, 0x08, 0x0a, 0x04, 0x04, 0xc0,
+ 0x5f, 0x75, 0xeb, 0xe0, 0x38, 0xc4, 0xf4, 0x02, 0x88, 0x6f, 0x61, 0x6e,
+ 0x64, 0xf2, 0xe0, 0x74, 0x2b, 0x61, 0x6d, 0x61, 0xf2, 0xe0, 0x51, 0x81,
+ 0xef, 0x60, 0x7a, 0x11, 0x46, 0xe5, 0xc5, 0x0c, 0xee, 0x04, 0xe0, 0x51,
+ 0x38, 0x61, 0xee, 0xe0, 0x87, 0x94, 0xea, 0xe0, 0x88, 0x1e, 0xe7, 0xe0,
+ 0x49, 0xde, 0xe4, 0x0c, 0x10, 0x0b, 0x31, 0x60, 0x4b, 0xcb, 0x60, 0x34,
+ 0x8e, 0xc3, 0x0d, 0x76, 0x69, 0xeb, 0x04, 0xe0, 0x8c, 0x4e, 0x63, 0x6f,
+ 0x72, 0x6f, 0x6d, 0xe1, 0xe0, 0x65, 0x4e, 0x6e, 0x65, 0xf3, 0x04, 0xe0,
+ 0x8a, 0xa9, 0xf3, 0xe0, 0x22, 0x6d, 0xe5, 0x04, 0xe0, 0x7c, 0x8f, 0xae,
+ 0x03, 0x19, 0x8a, 0x78, 0x6e, 0x2d, 0x2d, 0x6d, 0x72, 0x65, 0x2d, 0x6f,
+ 0x67, 0x2d, 0x72, 0x6f, 0x6d, 0x73, 0x64, 0x61, 0x6c, 0x2d, 0x71, 0x71,
+ 0xe2, 0xe0, 0x8a, 0x86, 0x76, 0x65, 0x73, 0x74, 0x66, 0x6f, 0xec, 0xe0,
+ 0x87, 0xef, 0xed, 0x60, 0x4a, 0x83, 0x8e, 0x63, 0x61, 0xf4, 0xe0, 0x6e,
+ 0xe3, 0x61, 0x67, 0x6f, 0x63, 0xe8, 0xe0, 0x21, 0x65, 0xed, 0x07, 0x04,
+ 0x0d, 0x04, 0xe0, 0x58, 0xbc, 0xf5, 0xe0, 0x87, 0x2b, 0xf3, 0x02, 0x84,
+ 0xf5, 0xe0, 0x76, 0x6a, 0x63, 0x6c, 0xf5, 0xe0, 0x81, 0x8c, 0xee, 0xe0,
+ 0x75, 0xce, 0x65, 0x67, 0xe1, 0xe0, 0x80, 0x98, 0xec, 0x08, 0x06, 0x05,
+ 0x07, 0x07, 0xe0, 0x48, 0x21, 0x76, 0x61, 0x64, 0xef, 0xd5, 0xa7, 0x75,
+ 0xe4, 0xe0, 0x89, 0x0f, 0xef, 0x60, 0x4c, 0x49, 0xe0, 0x3e, 0x40, 0xe5,
+ 0x60, 0x2c, 0x82, 0xe0, 0x5f, 0x3a, 0xe1, 0x60, 0x7c, 0x37, 0xc7, 0xe1,
+ 0xeb, 0x05, 0x2f, 0x04, 0xde, 0x05, 0xf5, 0x05, 0x25, 0xe0, 0x88, 0x6b,
+ 0x72, 0xe1, 0x0b, 0x04, 0x06, 0x60, 0x4a, 0x67, 0x5c, 0xc4, 0xe0, 0x24,
+ 0x62, 0xf4, 0xe0, 0x40, 0x7e, 0x67, 0x61, 0xf7, 0xe0, 0x48, 0x3a, 0xae,
+ 0x07, 0x60, 0x52, 0x9f, 0xe0, 0x37, 0x09, 0xf4, 0x60, 0x7d, 0xeb, 0xc2,
+ 0x16, 0xe8, 0xe0, 0x7d, 0x21, 0xe5, 0xe0, 0x29, 0x47, 0xe1, 0x0e, 0x15,
+ 0x06, 0x07, 0x58, 0x45, 0x60, 0x3b, 0xca, 0x60, 0x2b, 0xe2, 0xc2, 0x5c,
+ 0xe9, 0x02, 0x89, 0x6d, 0x69, 0x6e, 0x61, 0x74, 0xef, 0xe0, 0x6f, 0x79,
+ 0xae, 0x60, 0x60, 0xe0, 0x60, 0x22, 0xea, 0xc5, 0xbd, 0x68, 0x6f, 0xe7,
+ 0xe0, 0x82, 0x76, 0x65, 0xae, 0x60, 0x88, 0x38, 0xc1, 0x36, 0xe4, 0xe0,
+ 0x54, 0xb4, 0xe9, 0x04, 0x0e, 0x09, 0x84, 0xf4, 0x04, 0xe0, 0x60, 0xd5,
+ 0x61, 0x6d, 0x61, 0xae, 0x60, 0x80, 0xcb, 0xc8, 0xbe, 0xeb, 0x04, 0xe0,
+ 0x48, 0x7f, 0xe1, 0xe0, 0x4a, 0xdf, 0xea, 0xe0, 0x3c, 0x15, 0xe7, 0xe0,
+ 0x47, 0xfa, 0x67, 0xe1, 0x05, 0x05, 0xe0, 0x48, 0xd3, 0x6d, 0xe9, 0xe0,
+ 0x3d, 0x93, 0xae, 0x60, 0x80, 0x72, 0xc8, 0xf4, 0x66, 0xe5, 0x04, 0xe0,
+ 0x8b, 0x06, 0x74, 0xf9, 0x60, 0x88, 0x27, 0xc2, 0xdd, 0xe4, 0x04, 0xe0,
+ 0x86, 0xaf, 0x69, 0xf3, 0xe0, 0x73, 0xf6, 0x62, 0x61, 0xe5, 0xe0, 0x60,
+ 0x76, 0x61, 0x72, 0x6c, 0x61, 0xee, 0xe0, 0x88, 0x9e, 0xae, 0x0a, 0x09,
+ 0x60, 0x81, 0x61, 0x46, 0x55, 0x04, 0xc1, 0x17, 0x67, 0x6f, 0x76, 0xae,
+ 0x60, 0x86, 0x53, 0xc1, 0x6c, 0xe3, 0x60, 0x89, 0x79, 0xc1, 0x53, 0x2d,
+ 0x65, 0x61, 0x73, 0xf4, 0xe0, 0x81, 0x70, 0x35, 0xf9, 0xe0, 0x7c, 0x56,
+ 0xb3, 0x03, 0xc0, 0x42, 0xae, 0x12, 0x09, 0x1d, 0x41, 0x29, 0x60, 0x37,
+ 0x35, 0x08, 0x5e, 0xa2, 0x43, 0x6d, 0x42, 0xa0, 0x16, 0x05, 0x9a, 0x74,
+ 0x65, 0x63, 0x6b, 0x69, 0xe4, 0xe0, 0x75, 0xc4, 0xe9, 0x04, 0xe0, 0x5a,
+ 0x8a, 0x73, 0x6b, 0xb0, 0x02, 0x82, 0xb2, 0x82, 0x31, 0x2e, 0x73, 0x61,
+ 0x6b, 0x75, 0x72, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x61, 0xe7, 0xe0, 0x7b,
+ 0x99, 0xe1, 0x60, 0x5a, 0x92, 0x42, 0xf9, 0xe0, 0x25, 0x1f, 0xad, 0x11,
+ 0x40, 0x85, 0x0d, 0x10, 0x05, 0x0e, 0x14, 0x21, 0x40, 0x49, 0x60, 0x5b,
+ 0xdd, 0xe0, 0x25, 0x7d, 0x77, 0x65, 0x62, 0x73, 0x69, 0x74, 0xe5, 0x03,
+ 0xc0, 0x52, 0xae, 0x10, 0x60, 0x38, 0x28, 0x08, 0x5e, 0xa2, 0x43, 0x69,
+ 0x04, 0x1a, 0x42, 0x86, 0x16, 0x05, 0x9a, 0x64, 0x75, 0x61, 0x6c, 0x73,
+ 0x74, 0x61, 0x63, 0x6b, 0xae, 0x07, 0x08, 0x15, 0x06, 0xe0, 0x5c, 0xc1,
+ 0x75, 0x73, 0xad, 0x60, 0x5c, 0xd3, 0xc0, 0x6a, 0x65, 0x75, 0xad, 0x07,
+ 0x60, 0x5d, 0x35, 0xe0, 0x24, 0xf6, 0x77, 0x65, 0x73, 0x74, 0xad, 0x60,
+ 0x5d, 0x25, 0xe0, 0x25, 0x25, 0xe3, 0x40, 0x96, 0xe0, 0x5c, 0x63, 0xe1,
+ 0x04, 0xe0, 0x5d, 0x1d, 0x70, 0xad, 0x60, 0x5d, 0x03, 0xe0, 0x25, 0x1d,
+ 0xad, 0x07, 0x0e, 0x40, 0x67, 0xe0, 0x5c, 0x37, 0x75, 0x73, 0xad, 0x06,
+ 0x60, 0x5c, 0x95, 0xc0, 0x6a, 0x67, 0x6f, 0xf6, 0xc0, 0x6b, 0x61, 0x70,
+ 0xad, 0x02, 0x86, 0x73, 0x6f, 0xf5, 0xe0, 0x82, 0x08, 0x6e, 0x6f, 0x72,
+ 0x74, 0xe8, 0xe0, 0x5c, 0xea, 0x75, 0x73, 0xad, 0x05, 0x60, 0x5c, 0x75,
+ 0x85, 0x65, 0xe1, 0xe0, 0x81, 0xcc, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74,
+ 0x2d, 0x6c, 0x61, 0x6d, 0x62, 0x64, 0xe1, 0xe0, 0x59, 0xae, 0x6d, 0xe5,
+ 0xe0, 0x5c, 0xce, 0x66, 0x69, 0x70, 0xf3, 0x03, 0xc0, 0x71, 0x2d, 0x75,
+ 0x73, 0xad, 0xe0, 0x5c, 0x55, 0xe5, 0x02, 0x88, 0x78, 0x74, 0x65, 0x72,
+ 0xee, 0xe0, 0x81, 0xb1, 0x75, 0xad, 0x60, 0x5c, 0x65, 0x03, 0xe0, 0x25,
+ 0x3f, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0xae,
+ 0x05, 0x06, 0xe0, 0x81, 0x75, 0x65, 0x75, 0xad, 0xe0, 0x81, 0x88, 0x63,
+ 0x6e, 0x2d, 0x6e, 0x6f, 0x72, 0x74, 0xe8, 0xe0, 0x5c, 0x58, 0xe1, 0x02,
+ 0x89, 0x70, 0xad, 0x60, 0x5c, 0x6a, 0x13, 0xe0, 0x25, 0x0a, 0x63, 0x63,
+ 0x65, 0x73, 0x73, 0x70, 0x6f, 0x69, 0x6e, 0xf4, 0x02, 0x98, 0xae, 0x0b,
+ 0x60, 0x59, 0x48, 0x04, 0x1a, 0x42, 0x86, 0x16, 0x05, 0x9a, 0x64, 0x75,
+ 0x61, 0x6c, 0x73, 0x74, 0x61, 0x63, 0xeb, 0xe0, 0x59, 0x36, 0x2d, 0x66,
+ 0x69, 0x70, 0x73, 0xae, 0x05, 0x0e, 0xe0, 0x5b, 0xc7, 0x64, 0x75, 0x61,
+ 0x6c, 0x73, 0x74, 0x61, 0x63, 0x6b, 0xae, 0x04, 0xe0, 0x5b, 0xc7, 0xe3,
+ 0xe0, 0x5c, 0x0f, 0xf2, 0x1e, 0x35, 0x0d, 0x2e, 0x06, 0x20, 0x2d, 0x04,
+ 0x40, 0x87, 0x04, 0x04, 0x04, 0x40, 0xa5, 0x04, 0x06, 0x41, 0x92, 0x09,
+ 0x40, 0xd0, 0x04, 0x60, 0x53, 0x57, 0x56, 0x32, 0xd3, 0xf7, 0x1f, 0xc3,
+ 0x04, 0x17, 0x03, 0x88, 0xf8, 0x08, 0x06, 0x04, 0x40, 0xf9, 0xe0, 0x48,
+ 0x39, 0xf9, 0x40, 0xd4, 0xe0, 0x2e, 0xd0, 0xed, 0xe0, 0x28, 0xb1, 0xe4,
+ 0xe0, 0x80, 0x55, 0xe6, 0xc3, 0xe2, 0xe5, 0x04, 0xe0, 0x50, 0xfe, 0xe8,
+ 0xc3, 0xef, 0xe1, 0x03, 0xd4, 0xa2, 0x68, 0x6b, 0x6b, 0x65, 0x72, 0x1f,
+ 0xc3, 0xc3, 0xeb, 0xfa, 0x02, 0x84, 0xe7, 0xe0, 0x4b, 0xae, 0x65, 0x73,
+ 0xfa, 0xe0, 0x7c, 0x28, 0xf9, 0x07, 0x15, 0x06, 0x05, 0xe0, 0x38, 0xa9,
+ 0xf5, 0x03, 0x05, 0x85, 0x6f, 0xe8, 0xe0, 0x83, 0x70, 0x6b, 0xf9, 0xe0,
+ 0x87, 0xbd, 0x67, 0x61, 0x73, 0xe1, 0xe0, 0x40, 0x06, 0x6f, 0x6b, 0xe1,
+ 0xe0, 0x35, 0xa3, 0x67, 0xe7, 0xe0, 0x87, 0x15, 0x62, 0x6e, 0xe9, 0xe0,
+ 0x76, 0x3b, 0xf7, 0x60, 0x87, 0x25, 0xc1, 0x7c, 0xf5, 0x0c, 0x05, 0x06,
+ 0x05, 0x60, 0x42, 0xc5, 0x4f, 0xdf, 0xe0, 0x35, 0xdb, 0x6f, 0xf6, 0xe0,
+ 0x75, 0xfc, 0xee, 0x60, 0x87, 0x13, 0xc1, 0x76, 0x6c, 0xe5, 0xe0, 0x38,
+ 0x7f, 0xe7, 0xd1, 0x35, 0xf3, 0x07, 0x04, 0x09, 0x05, 0xe0, 0x88, 0x62,
+ 0xf6, 0xe0, 0x86, 0xd6, 0x73, 0x2e, 0x6d, 0x79, 0x2e, 0xe9, 0xe0, 0x78,
+ 0x9c, 0x63, 0xae, 0xe0, 0x70, 0xa7, 0xae, 0x06, 0x08, 0x60, 0x81, 0xef,
+ 0x83, 0x77, 0x65, 0x62, 0x61, 0x63, 0xe3, 0xca, 0x07, 0xe2, 0xe0, 0x78,
+ 0x07, 0xf2, 0xe0, 0x61, 0xe9, 0xef, 0x16, 0x10, 0x0d, 0x11, 0x06, 0x03,
+ 0x0e, 0x05, 0x05, 0x04, 0x09, 0x07, 0x59, 0x24, 0x60, 0x2e, 0xe6, 0x60,
+ 0x38, 0xd1, 0xc6, 0xf6, 0xf9, 0x05, 0x04, 0xe0, 0x2e, 0xcc, 0xeb, 0xe0,
+ 0x78, 0xb1, 0x61, 0x6c, 0xad, 0xe0, 0x3f, 0x2e, 0xf6, 0x02, 0x85, 0x6e,
+ 0xef, 0xe0, 0x6d, 0x17, 0x69, 0xe7, 0xe0, 0x86, 0x16, 0x75, 0x74, 0x65,
+ 0x72, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0xee, 0xe0,
+ 0x87, 0xe8, 0x74, 0x6f, 0xf2, 0xe0, 0x82, 0xf7, 0xf2, 0xd9, 0x56, 0xed,
+ 0x06, 0x60, 0x80, 0xee, 0xc0, 0x79, 0xf3, 0x60, 0x5b, 0x92, 0xe0, 0x26,
+ 0x3b, 0x6c, 0xec, 0xe0, 0x76, 0x00, 0x6b, 0xf5, 0xe0, 0x48, 0xf0, 0xe7,
+ 0xe0, 0x57, 0x13, 0xe4, 0x04, 0xe0, 0x7c, 0x2c, 0xe5, 0xe0, 0x86, 0x50,
+ 0x63, 0xeb, 0x44, 0xd2, 0xe0, 0x80, 0x9b, 0xae, 0x06, 0x60, 0x81, 0x66,
+ 0x03, 0x83, 0xe9, 0x60, 0x86, 0x0b, 0xc1, 0xb9, 0xee, 0xe0, 0x78, 0xe2,
+ 0xed, 0xe0, 0x85, 0xbc, 0xea, 0xe0, 0x61, 0x56, 0xe9, 0x14, 0x06, 0x05,
+ 0x1f, 0x15, 0x16, 0x05, 0x10, 0x05, 0x04, 0x15, 0x60, 0x64, 0x5e, 0x47,
+ 0x80, 0x58, 0xee, 0xc0, 0xb2, 0x76, 0x6e, 0xe5, 0xe0, 0x6c, 0x98, 0x74,
+ 0xf4, 0xe0, 0x82, 0x48, 0xf3, 0x06, 0x06, 0x04, 0xe0, 0x4f, 0x4f, 0x1f,
+ 0x43, 0xf8, 0xe0, 0x7b, 0xe6, 0xef, 0xe0, 0x7b, 0xe2, 0x68, 0x69, 0x72,
+ 0xe9, 0x04, 0xe0, 0x85, 0xca, 0x66, 0x75, 0xea, 0xe0, 0x85, 0xc6, 0xef,
+ 0x07, 0x07, 0x60, 0x86, 0x0f, 0xc1, 0x5b, 0x70, 0x72, 0x65, 0xf4, 0xe0,
+ 0x7b, 0x01, 0x62, 0x72, 0x61, 0xee, 0xcb, 0x79, 0xee, 0x04, 0xe0, 0x80,
+ 0x43, 0xe7, 0x02, 0x84, 0xf3, 0xe0, 0x36, 0xe0, 0xe5, 0x04, 0xe0, 0x7e,
+ 0xff, 0x72, 0xe9, 0xe0, 0x56, 0x26, 0x6d, 0xe9, 0xe0, 0x7e, 0xe7, 0x6b,
+ 0xf5, 0x04, 0xe0, 0x82, 0x8a, 0x7a, 0x65, 0x6e, 0x74, 0x61, 0x6b, 0x61,
+ 0xf4, 0xdf, 0x05, 0x69, 0xeb, 0xe0, 0x82, 0x58, 0xe6, 0xe0, 0x20, 0x6e,
+ 0xe3, 0x05, 0x04, 0xe0, 0x7a, 0xc1, 0xef, 0xe0, 0x84, 0x99, 0xe8, 0x04,
+ 0xe0, 0x87, 0x21, 0x61, 0x72, 0xe4, 0xe0, 0x39, 0x4d, 0x62, 0x65, 0x69,
+ 0x72, 0xe1, 0xe0, 0x7a, 0xaa, 0xe8, 0xe0, 0x81, 0xb4, 0xe7, 0x60, 0x74,
+ 0x18, 0xd0, 0xf3, 0xe5, 0x15, 0x06, 0x10, 0x40, 0x49, 0x2e, 0x19, 0x08,
+ 0x0d, 0x07, 0x0c, 0x05, 0x1c, 0x1c, 0x23, 0x05, 0x40, 0x43, 0xe0, 0x85,
+ 0x7d, 0x78, 0x72, 0xef, 0xe0, 0x5c, 0xd4, 0x76, 0xe9, 0x02, 0x85, 0x73,
+ 0xf4, 0xe0, 0x84, 0x2e, 0x65, 0xf7, 0x60, 0x84, 0x79, 0xc2, 0x69, 0xf3,
+ 0x04, 0x15, 0x09, 0xa0, 0xf4, 0x05, 0x04, 0xe0, 0x86, 0xce, 0xef, 0xe0,
+ 0x7c, 0x50, 0x61, 0x75, 0x72, 0x61, 0x6e, 0xf4, 0x60, 0x7c, 0x47, 0xca,
+ 0x81, 0x69, 0x6e, 0x64, 0x65, 0x76, 0xe9, 0xe0, 0x69, 0x76, 0xe5, 0x02,
+ 0x96, 0x72, 0xf6, 0x02, 0x89, 0x65, 0x2d, 0x6f, 0x6e, 0x6c, 0x69, 0xee,
+ 0xc2, 0x0a, 0x64, 0xae, 0x60, 0x63, 0x93, 0x18, 0xe0, 0x22, 0xf6, 0x61,
+ 0x72, 0x63, 0xe8, 0xe0, 0x83, 0xc0, 0xae, 0x60, 0x83, 0xbd, 0xc1, 0xa1,
+ 0xf0, 0x06, 0x08, 0x05, 0x07, 0x06, 0x84, 0x75, 0x62, 0x6c, 0x69, 0xe3,
+ 0xe0, 0x82, 0x49, 0x6f, 0xf2, 0xe0, 0x84, 0xc5, 0x6c, 0xae, 0x60, 0x60,
+ 0x59, 0xcd, 0x23, 0x62, 0x6f, 0xe4, 0xe0, 0x59, 0xa9, 0xe1, 0xe0, 0x3f,
+ 0x6d, 0xae, 0x04, 0xe0, 0x85, 0x10, 0xeb, 0xe0, 0x84, 0xcc, 0xee, 0x07,
+ 0x09, 0x5d, 0xf9, 0xe0, 0x68, 0x5c, 0xf4, 0x04, 0xe0, 0x86, 0x59, 0xe1,
+ 0xe0, 0x73, 0x44, 0x6e, 0xe5, 0x60, 0x2a, 0x75, 0xe0, 0x53, 0x8a, 0x6d,
+ 0x6f, 0x74, 0x65, 0xf7, 0xe0, 0x80, 0xee, 0xec, 0x02, 0x84, 0xe9, 0xe0,
+ 0x27, 0xc8, 0xae, 0x60, 0x81, 0xb8, 0xc1, 0x03, 0x6b, 0x6c, 0x61, 0xed,
+ 0xe0, 0x85, 0x32, 0xe9, 0x04, 0xe0, 0x84, 0x6e, 0x73, 0xe5, 0x60, 0x84,
+ 0xf0, 0xc1, 0x3a, 0x68, 0xe1, 0xe0, 0x7b, 0xca, 0xe7, 0x02, 0x95, 0x67,
+ 0x69, 0xef, 0x03, 0x03, 0x86, 0xad, 0x02, 0x86, 0x65, 0x6d, 0xe9, 0xe0,
+ 0x50, 0xfb, 0x63, 0x61, 0xec, 0xe0, 0x6d, 0xef, 0xae, 0xe0, 0x85, 0xce,
+ 0xe4, 0x08, 0x07, 0x08, 0x60, 0x6f, 0xcb, 0xd6, 0x21, 0x75, 0x6d, 0x62,
+ 0xf2, 0xe0, 0x63, 0x2f, 0x69, 0x72, 0x65, 0x63, 0xf4, 0xe0, 0x82, 0x7e,
+ 0xae, 0xe0, 0x4b, 0x17, 0xe3, 0x04, 0x05, 0x0b, 0x84, 0x72, 0xe5, 0xe0,
+ 0x82, 0xff, 0xe9, 0x02, 0x84, 0xf0, 0xe0, 0x79, 0xe3, 0xe6, 0xe0, 0x6d,
+ 0x7b, 0xe8, 0xe0, 0x82, 0xcb, 0xae, 0x60, 0x7a, 0xe1, 0x03, 0x40, 0x76,
+ 0x48, 0xe8, 0xb2, 0x62, 0xf5, 0xe0, 0x57, 0x29, 0xe1, 0x02, 0x97, 0xec,
+ 0x05, 0x06, 0xe0, 0x62, 0x92, 0xf4, 0x60, 0x82, 0x85, 0xc0, 0xfa, 0x65,
+ 0x73, 0x74, 0x61, 0x74, 0xe5, 0x60, 0x80, 0xf0, 0xc4, 0xbb, 0xe4, 0x07,
+ 0x07, 0x09, 0x09, 0xe0, 0x85, 0x85, 0x79, 0x6d, 0x61, 0xe4, 0xe0, 0x76,
+ 0xad, 0x74, 0x68, 0x65, 0x64, 0x6f, 0xe3, 0xe0, 0x68, 0x6e, 0x6d, 0x79,
+ 0x62, 0x6c, 0x6f, 0xe7, 0xe0, 0x82, 0xb8, 0x2d, 0x62, 0x6f, 0x6f, 0xeb,
+ 0xe0, 0x70, 0xa1, 0xae, 0x60, 0x6e, 0x8c, 0xd4, 0xee, 0xe4, 0x04, 0xe0,
+ 0x7c, 0xbf, 0xf6, 0xe0, 0x84, 0x2c, 0xe1, 0x12, 0x08, 0x21, 0x05, 0x04,
+ 0x17, 0x04, 0x05, 0x09, 0x11, 0x1a, 0x0a, 0x20, 0x57, 0xf1, 0xe0, 0x6a,
+ 0xb7, 0x77, 0x61, 0x2d, 0x6d, 0xe1, 0xe0, 0x6e, 0x2e, 0xf6, 0x02, 0x89,
+ 0x70, 0x61, 0x67, 0x65, 0x2e, 0x63, 0xef, 0xd8, 0x9e, 0x65, 0xee, 0x04,
+ 0xe0, 0x7c, 0xfa, 0x64, 0x62, 0xae, 0x06, 0x60, 0x5f, 0x13, 0xd0, 0x21,
+ 0xe3, 0x59, 0x5c, 0xe0, 0x53, 0xfd, 0x75, 0xed, 0xe0, 0x7f, 0x08, 0xf2,
+ 0xe0, 0x5b, 0x23, 0xee, 0x06, 0x06, 0x05, 0xe0, 0x7e, 0xef, 0x7a, 0x61,
+ 0xee, 0xe0, 0x79, 0xe0, 0x6b, 0xef, 0xe0, 0x7e, 0xf7, 0x64, 0xe1, 0xe0,
+ 0x58, 0xb7, 0xec, 0xe0, 0x23, 0xbd, 0x6b, 0xeb, 0xe0, 0x3f, 0x1a, 0xe9,
+ 0x04, 0xe0, 0x4c, 0xcc, 0xee, 0xe0, 0x75, 0xf8, 0xe8, 0x02, 0x85, 0x6f,
+ 0xec, 0xe0, 0x7d, 0x5e, 0x6b, 0x6b, 0x65, 0x72, 0x61, 0xf6, 0xe0, 0x7e,
+ 0x80, 0xe7, 0x02, 0x84, 0xf5, 0xe0, 0x6b, 0xf5, 0x2d, 0x63, 0x6c, 0x6f,
+ 0x75, 0xe4, 0x02, 0x83, 0x2d, 0x63, 0x68, 0x2e, 0x68, 0x6f, 0x73, 0xf4,
+ 0xe0, 0x56, 0x19, 0x66, 0x66, 0x6c, 0x65, 0x65, 0x6e, 0xf4, 0xe0, 0x80,
+ 0xba, 0xe4, 0x07, 0x06, 0x60, 0x7c, 0x1a, 0xc7, 0x0d, 0xef, 0x60, 0x78,
+ 0x59, 0xc4, 0x0b, 0x69, 0xef, 0x04, 0xe0, 0x84, 0xb7, 0xae, 0x07, 0x60,
+ 0x5d, 0xaa, 0xe0, 0x25, 0xab, 0xe6, 0xe0, 0x84, 0xa9, 0xe3, 0x04, 0xe0,
+ 0x6f, 0x24, 0x6b, 0x6d, 0x61, 0x7a, 0xe5, 0xe0, 0x81, 0x45, 0xb2, 0xe0,
+ 0x77, 0x01, 0xae, 0x07, 0x08, 0x60, 0x73, 0x24, 0xd1, 0x64, 0x63, 0x64,
+ 0x6e, 0x37, 0xb7, 0xe0, 0x84, 0x69, 0x61, 0x70, 0x70, 0x73, 0x70, 0xef,
+ 0xe0, 0x65, 0xc0, 0xf1, 0x0e, 0x40, 0x45, 0x04, 0x04, 0x06, 0x0e, 0x04,
+ 0x0c, 0x06, 0x09, 0xe0, 0x83, 0xef, 0xf5, 0x03, 0x13, 0x89, 0xe9, 0x02,
+ 0x8a, 0x70, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0xee, 0xe0, 0x25, 0x4a, 0x63,
+ 0x6b, 0x73, 0xf9, 0xc8, 0xba, 0xe5, 0x04, 0xe0, 0x77, 0x7e, 0xe2, 0xe0,
+ 0x63, 0x08, 0xe1, 0x02, 0x9a, 0x6e, 0xe7, 0x05, 0x05, 0xe0, 0x40, 0x69,
+ 0x74, 0xf2, 0xe0, 0x5c, 0x4e, 0xee, 0x05, 0x04, 0xe0, 0x75, 0x01, 0xe7,
+ 0xe0, 0x5c, 0x43, 0xe1, 0xe0, 0x2b, 0x00, 0x6c, 0x69, 0x66, 0x69, 0xef,
+ 0xe0, 0x83, 0x43, 0xf3, 0xe0, 0x50, 0x1c, 0xf0, 0xe0, 0x7c, 0xca, 0x6f,
+ 0x74, 0xef, 0xe0, 0x83, 0x1a, 0x6c, 0x64, 0xae, 0x05, 0x60, 0x80, 0xfa,
+ 0x84, 0x67, 0x6f, 0xf6, 0xe0, 0x80, 0xfa, 0xe8, 0xe0, 0x70, 0xa1, 0xe3,
+ 0x04, 0xe0, 0x59, 0x0e, 0x2e, 0xe3, 0x60, 0x82, 0x5f, 0xc1, 0xa1, 0x62,
+ 0x75, 0xf3, 0xe0, 0x7a, 0x27, 0xe1, 0x04, 0xe0, 0x83, 0xf6, 0xb2, 0xe0,
+ 0x83, 0xed, 0x2d, 0xe1, 0xe0, 0x69, 0xb9, 0xf0, 0x23, 0x04, 0x1d, 0x06,
+ 0x11, 0x40, 0x5a, 0x06, 0x13, 0x41, 0x4a, 0x0f, 0x40, 0xea, 0x08, 0x09,
+ 0x40, 0x77, 0x40, 0x83, 0x40, 0x56, 0x12, 0x0a, 0x40, 0x70, 0x0a, 0x15,
+ 0x09, 0x60, 0x54, 0xc0, 0xe0, 0x27, 0xa0, 0xfa, 0xe0, 0x81, 0xc5, 0xf9,
+ 0x08, 0x05, 0x60, 0x54, 0x67, 0xe0, 0x2f, 0x50, 0x6d, 0xee, 0xe0, 0x3a,
+ 0xbd, 0xe1, 0x04, 0xe0, 0x82, 0xb7, 0x74, 0x69, 0x67, 0x6f, 0x72, 0x73,
+ 0xeb, 0xe0, 0x83, 0x21, 0xf7, 0x60, 0x77, 0xc4, 0xcb, 0xe3, 0xf6, 0x05,
+ 0x07, 0xe0, 0x81, 0x92, 0x74, 0xae, 0x60, 0x53, 0x03, 0xd4, 0x6b, 0xe8,
+ 0xe0, 0x82, 0x39, 0xf5, 0x0a, 0x06, 0x05, 0x06, 0x06, 0x07, 0x05, 0xe0,
+ 0x81, 0x60, 0x73, 0x73, 0x79, 0xe3, 0xc3, 0x88, 0xf0, 0x06, 0xe0, 0x46,
+ 0x4f, 0x6e, 0x79, 0xf5, 0xe0, 0x82, 0x7d, 0x6c, 0x61, 0xf7, 0xe0, 0x71,
+ 0x72, 0xe7, 0x60, 0x4e, 0x58, 0xe0, 0x33, 0x13, 0x65, 0x62, 0xec, 0xd9,
+ 0x61, 0xe2, 0x06, 0x05, 0x18, 0xe0, 0x83, 0x3f, 0x74, 0xec, 0xe0, 0x6e,
+ 0x7b, 0xec, 0x02, 0x91, 0xe9, 0x02, 0x85, 0x73, 0xe8, 0xe0, 0x65, 0xb9,
+ 0x63, 0x2d, 0x69, 0x6e, 0x71, 0xf5, 0xe0, 0x3a, 0x41, 0xae, 0xe0, 0x39,
+ 0x08, 0xae, 0x03, 0xc0, 0xfe, 0xf3, 0xe0, 0x81, 0x93, 0xf4, 0x60, 0x70,
+ 0xe7, 0xd2, 0x4f, 0xf3, 0x0d, 0x5a, 0x47, 0x50, 0xac, 0x60, 0x29, 0x44,
+ 0x60, 0x26, 0xaf, 0xc8, 0x3d, 0x73, 0xe5, 0xe0, 0x45, 0xf7, 0xf2, 0x0f,
+ 0x08, 0x06, 0x12, 0x40, 0x70, 0x40, 0x60, 0x31, 0x09, 0x44, 0x49, 0xe0,
+ 0x7d, 0x9b, 0x7a, 0x65, 0x77, 0x6f, 0xf2, 0xe0, 0x24, 0xf3, 0x76, 0x63,
+ 0xf9, 0xe0, 0x63, 0x4c, 0xf5, 0x05, 0x05, 0xe0, 0x82, 0xf5, 0x73, 0xfa,
+ 0xe0, 0x21, 0xfb, 0x64, 0x65, 0x6e, 0xf4, 0xe0, 0x50, 0xc5, 0xef, 0x0b,
+ 0x0c, 0x0a, 0x04, 0x08, 0x0c, 0x10, 0x04, 0xe0, 0x82, 0xa0, 0xf4, 0x02,
+ 0x85, 0x6f, 0xee, 0xe0, 0x6f, 0xf0, 0xe5, 0xe0, 0x76, 0x45, 0x70, 0x65,
+ 0x72, 0xf4, 0x60, 0x2c, 0xcc, 0xe0, 0x53, 0xcf, 0xed, 0xe0, 0x81, 0x40,
+ 0x67, 0x72, 0x65, 0x73, 0xf3, 0xe0, 0x5a, 0x4e, 0xe6, 0x07, 0x60, 0x53,
+ 0xe7, 0xe0, 0x2e, 0xd1, 0x65, 0xf3, 0xc2, 0x02, 0xe4, 0x04, 0xe0, 0x82,
+ 0xaf, 0x75, 0x63, 0x74, 0x69, 0x6f, 0xee, 0x60, 0x7f, 0xcc, 0xc0, 0x74,
+ 0x63, 0xe8, 0xc1, 0x66, 0xae, 0x17, 0x54, 0x28, 0x60, 0x3f, 0x90, 0x4d,
+ 0x83, 0x5a, 0x57, 0x42, 0x95, 0x40, 0x7a, 0x2a, 0x3b, 0x40, 0xe7, 0x40,
+ 0x5a, 0x40, 0xe7, 0x9f, 0xf4, 0x04, 0xe0, 0x80, 0xc5, 0x79, 0xf0, 0xe0,
+ 0x41, 0x80, 0xe9, 0x07, 0x40, 0x44, 0x08, 0xe0, 0x7d, 0x4b, 0xf6, 0x02,
+ 0xa9, 0x61, 0xf4, 0x02, 0x94, 0x69, 0x7a, 0x65, 0x68, 0x65, 0x61, 0x6c,
+ 0x74, 0x68, 0x69, 0x6e, 0x73, 0x75, 0x72, 0x61, 0x6e, 0xe3, 0xe0, 0x7e,
+ 0xee, 0x65, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x73, 0x6e, 0x6f, 0x77, 0x66,
+ 0x6c, 0x61, 0xeb, 0xe0, 0x6c, 0xc8, 0xae, 0x0c, 0x60, 0x66, 0x1c, 0x57,
+ 0x9c, 0x42, 0xf1, 0x40, 0x93, 0xc0, 0x63, 0x69, 0x6e, 0x73, 0x74, 0x61,
+ 0x6e, 0x63, 0xe5, 0xe0, 0x30, 0x1d, 0x6e, 0x63, 0x69, 0x70, 0xe5, 0xe0,
+ 0x60, 0xb7, 0x6d, 0xe5, 0x04, 0xe0, 0x82, 0x24, 0x74, 0x65, 0xec, 0xe0,
+ 0x6a, 0x41, 0xe5, 0x02, 0x9d, 0x73, 0xf3, 0x05, 0x09, 0xe0, 0x82, 0x0b,
+ 0x65, 0xae, 0x60, 0x46, 0x59, 0x60, 0x2f, 0xe2, 0x8d, 0xae, 0x08, 0x60,
+ 0x70, 0x9c, 0x4d, 0x05, 0xc1, 0x85, 0xed, 0xe0, 0x80, 0x5a, 0x71, 0x75,
+ 0x61, 0x6c, 0x69, 0x66, 0x79, 0x6d, 0x65, 0x2e, 0x74, 0x6f, 0x64, 0xe1,
+ 0xe0, 0x70, 0x80, 0x64, 0xae, 0x60, 0x27, 0xfa, 0x60, 0x4e, 0x14, 0x93,
+ 0xe1, 0x05, 0x04, 0xe0, 0x7d, 0x63, 0xf8, 0xe0, 0x7f, 0xc4, 0x6d, 0x65,
+ 0xf2, 0xe0, 0x5f, 0xf0, 0xf0, 0x04, 0xe0, 0x63, 0x15, 0xae, 0x53, 0x6e,
+ 0x60, 0x5b, 0x31, 0x41, 0xc9, 0xd0, 0xdd, 0xef, 0x10, 0x06, 0x06, 0x0a,
+ 0x12, 0x29, 0x11, 0x0a, 0x29, 0x0b, 0x18, 0x04, 0x16, 0xe0, 0x77, 0x66,
+ 0x7a, 0x6e, 0xe1, 0xe0, 0x20, 0xdc, 0x77, 0x69, 0xe1, 0xe0, 0x5e, 0x0e,
+ 0xf4, 0x04, 0xe0, 0x5f, 0xb5, 0x61, 0xe7, 0xe0, 0x35, 0xc2, 0x73, 0xf4,
+ 0x06, 0x60, 0x80, 0x5a, 0xc1, 0x3c, 0x6d, 0x61, 0x6e, 0x2d, 0x65, 0x63,
+ 0xe8, 0xe0, 0x74, 0xa3, 0xf2, 0x07, 0x1c, 0x60, 0x7d, 0x90, 0xc2, 0x9e,
+ 0xf3, 0x03, 0x09, 0x87, 0x1f, 0x43, 0x61, 0x1f, 0x45, 0xcb, 0xe0, 0x32,
+ 0xc4, 0x67, 0x72, 0x75, 0xee, 0xe0, 0x7b, 0x3e, 0x61, 0x6e, 0xe7, 0x60,
+ 0x75, 0xc4, 0xc5, 0x38, 0x64, 0xe5, 0xe0, 0x4b, 0x7a, 0xee, 0x02, 0x86,
+ 0x70, 0x65, 0xf3, 0xe0, 0x5b, 0x9b, 0x69, 0x61, 0x74, 0x6f, 0xf7, 0xe0,
+ 0x48, 0x8e, 0x6d, 0x6f, 0xf2, 0x03, 0xdd, 0xc6, 0x73, 0xeb, 0xc0, 0x60,
+ 0xec, 0x04, 0x06, 0x05, 0x91, 0x74, 0x61, 0xf6, 0xe0, 0x5e, 0xd4, 0x6b,
+ 0xef, 0xe0, 0x2c, 0x6d, 0xe9, 0x02, 0x8a, 0x74, 0xe9, 0x04, 0xe0, 0x7f,
+ 0xb3, 0xe3, 0xe0, 0x7e, 0x75, 0x63, 0xe5, 0xcf, 0x67, 0xae, 0x60, 0x73,
+ 0x6c, 0x41, 0xe0, 0xc8, 0x58, 0xeb, 0x04, 0xe0, 0x6d, 0x7a, 0x72, 0x6f,
+ 0xf6, 0xe0, 0x7a, 0xd9, 0xe9, 0x02, 0x86, 0x76, 0x72, 0xef, 0xe0, 0x61,
+ 0x39, 0x6e, 0xf4, 0x02, 0x85, 0x74, 0xef, 0xe0, 0x45, 0xe3, 0x32, 0x74,
+ 0xe8, 0xe0, 0x47, 0xed, 0xe8, 0xe0, 0x7e, 0xac, 0xe4, 0x03, 0x07, 0x87,
+ 0x7a, 0x6f, 0x6e, 0xe5, 0xe0, 0x53, 0x31, 0x6c, 0x61, 0x73, 0xe9, 0xe0,
+ 0x45, 0x80, 0x68, 0xe1, 0xc6, 0x7a, 0xae, 0x60, 0x43, 0xb8, 0xe0, 0x3b,
+ 0x27, 0xee, 0x60, 0x74, 0xf7, 0x49, 0xe0, 0xc2, 0x03, 0xed, 0x04, 0xe0,
+ 0x80, 0xce, 0xee, 0xe0, 0x7e, 0xca, 0xec, 0x0a, 0x16, 0x04, 0x08, 0x0b,
+ 0x5f, 0x62, 0xe0, 0x61, 0x30, 0xf5, 0x05, 0x0b, 0xe0, 0x7e, 0x45, 0x72,
+ 0x69, 0x6e, 0x61, 0x63, 0x69, 0x6f, 0x6e, 0xe1, 0xd1, 0x58, 0x6d, 0xe2,
+ 0xe0, 0x6b, 0x2a, 0x6f, 0xae, 0xc1, 0x15, 0x65, 0x73, 0xeb, 0x60, 0x58,
+ 0x49, 0xc8, 0xa2, 0x63, 0xae, 0x06, 0x4e, 0xd4, 0xe0, 0x6a, 0x4d, 0xe3,
+ 0xdf, 0xef, 0xe1, 0x05, 0x14, 0xe0, 0x7b, 0x69, 0xf9, 0x04, 0xe0, 0x80,
+ 0x87, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0xee, 0x04, 0xe0, 0x80, 0x7c,
+ 0xad, 0xe0, 0x7b, 0x1d, 0xf4, 0x02, 0x93, 0x74, 0x65, 0xf2, 0x02, 0x84,
+ 0xf0, 0xe0, 0x45, 0x4d, 0x2d, 0x61, 0x70, 0x70, 0xae, 0x60, 0x72, 0xcc,
+ 0xcd, 0x94, 0x66, 0x6f, 0x72, 0xed, 0x02, 0x85, 0x73, 0xe8, 0xe0, 0x62,
+ 0x76, 0xb0, 0xe0, 0x7e, 0xe0, 0xe9, 0x15, 0x04, 0x08, 0x0c, 0x06, 0x12,
+ 0x07, 0x09, 0x07, 0x12, 0x0f, 0x60, 0x24, 0xc1, 0x5d, 0xe9, 0x60, 0x2e,
+ 0x4a, 0xcc, 0x95, 0xfa, 0xe0, 0x7b, 0xca, 0x78, 0x6f, 0x6c, 0x69, 0xee,
+ 0xe0, 0x73, 0x48, 0xf3, 0x06, 0x60, 0x69, 0x02, 0xd0, 0x99, 0x74, 0xef,
+ 0xe0, 0x79, 0x98, 0x6f, 0x6e, 0xe5, 0xe0, 0x6c, 0x82, 0xee, 0x08, 0x05,
+ 0x60, 0x7d, 0xab, 0x42, 0x65, 0x81, 0x6f, 0xeb, 0xe0, 0x67, 0x61, 0xe2,
+ 0xe0, 0x42, 0xe6, 0x6d, 0x69, 0x65, 0xee, 0xe0, 0x79, 0x09, 0xec, 0x04,
+ 0xe0, 0x71, 0x1d, 0xef, 0xe0, 0x7a, 0xf8, 0x67, 0x62, 0x6f, 0xe1, 0xe0,
+ 0x68, 0xf7, 0xe5, 0x02, 0x87, 0x6d, 0x6f, 0x6e, 0xf4, 0xe0, 0x78, 0xe7,
+ 0x64, 0x6d, 0x6f, 0x6e, 0xf4, 0xe0, 0x7d, 0xe4, 0xe3, 0x04, 0xe0, 0x7d,
+ 0x76, 0xf4, 0x04, 0xe0, 0x6c, 0xd4, 0x75, 0xf2, 0xe0, 0x73, 0xe1, 0x61,
+ 0xe3, 0xe0, 0x5d, 0xe5, 0xe8, 0x0b, 0x06, 0x0d, 0x07, 0x15, 0x07, 0x60,
+ 0x7d, 0x42, 0xc2, 0x4c, 0x79, 0x73, 0xe9, 0xe0, 0x7e, 0x36, 0x78, 0x2e,
+ 0x65, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0xe4, 0xe0, 0x44, 0x92, 0xf5,
+ 0x60, 0x39, 0xdd, 0xe0, 0x2d, 0x48, 0xef, 0x04, 0xe0, 0x69, 0x87, 0x74,
+ 0xef, 0x06, 0x60, 0x7d, 0x34, 0xc2, 0x69, 0x67, 0x72, 0x61, 0x70, 0xe8,
+ 0xe0, 0x7d, 0x61, 0x69, 0x6c, 0x69, 0xf0, 0xe0, 0x7d, 0x28, 0x61, 0x72,
+ 0x6d, 0x61, 0xe3, 0x04, 0xe0, 0x7d, 0x4e, 0x69, 0x65, 0xee, 0x04, 0xe0,
+ 0x7e, 0xec, 0xf3, 0xe0, 0x73, 0xb2, 0xe7, 0x06, 0x04, 0x03, 0xe0, 0x6e,
+ 0x09, 0xe6, 0xe0, 0x56, 0x15, 0xe1, 0xcd, 0xb2, 0xae, 0xe0, 0x67, 0x92,
+ 0xe6, 0x04, 0xe0, 0x7f, 0x63, 0x69, 0xfa, 0xe0, 0x6b, 0xc1, 0xe5, 0x0c,
+ 0x12, 0x2c, 0x05, 0x09, 0x06, 0x06, 0x60, 0x7d, 0x3b, 0xc1, 0xbe, 0xf3,
+ 0x02, 0x83, 0xe3, 0xdc, 0x6c, 0x61, 0x72, 0xef, 0x02, 0x81, 0x2d, 0x75,
+ 0x72, 0xe2, 0xe0, 0x71, 0x81, 0xf2, 0x04, 0x04, 0x14, 0x84, 0xf5, 0xe0,
+ 0x4b, 0xaf, 0xf3, 0x02, 0x87, 0x70, 0x65, 0x63, 0xf4, 0xe0, 0x31, 0x06,
+ 0x6f, 0xae, 0x60, 0x51, 0x1a, 0x60, 0x23, 0x37, 0xc7, 0x57, 0xed, 0xe0,
+ 0x6f, 0x70, 0xae, 0x06, 0x60, 0x5c, 0x51, 0xd7, 0xdc, 0xf3, 0xe0, 0x7f,
+ 0x15, 0x70, 0xf0, 0xe0, 0x6c, 0x1a, 0xee, 0x04, 0xe0, 0x46, 0x23, 0xfa,
+ 0xe0, 0x7d, 0x1d, 0x65, 0x77, 0xe5, 0xe0, 0x70, 0x15, 0x63, 0x6f, 0xf2,
+ 0xe0, 0x59, 0xe4, 0xae, 0x60, 0x68, 0x08, 0x50, 0x8c, 0x03, 0x44, 0x5f,
+ 0xc0, 0x5a, 0xe4, 0x04, 0xe0, 0x7c, 0xe6, 0x6e, 0xf3, 0xe0, 0x5f, 0x30,
+ 0xe3, 0x03, 0x07, 0x84, 0x6c, 0x6f, 0x75, 0xe4, 0xe0, 0x49, 0xf6, 0xe3,
+ 0xe0, 0x7c, 0x68, 0xae, 0x60, 0x7a, 0x4f, 0xc2, 0x83, 0x62, 0xae, 0x60,
+ 0x54, 0x12, 0x60, 0x24, 0x57, 0x83, 0xe1, 0x10, 0x0d, 0x04, 0x05, 0x10,
+ 0x40, 0x4c, 0x14, 0x0c, 0x40, 0x4e, 0x08, 0x32, 0xe0, 0x7d, 0x9b, 0xf9,
+ 0x04, 0xe0, 0x7e, 0xb0, 0x77, 0x68, 0x69, 0x72, 0xec, 0xe0, 0x7e, 0x95,
+ 0xf6, 0xe0, 0x78, 0x17, 0x74, 0xf2, 0xe0, 0x7b, 0xe8, 0x73, 0x73, 0x65,
+ 0x6e, 0x67, 0x65, 0x72, 0x2d, 0x61, 0x73, 0x73, 0x6f, 0xe3, 0xe0, 0x61,
+ 0xa7, 0xf2, 0x09, 0x0f, 0x06, 0x04, 0x09, 0x07, 0xe0, 0x7b, 0xf3, 0xf4,
+ 0x06, 0x04, 0x60, 0x7c, 0x11, 0xb2, 0xee, 0xe0, 0x4d, 0xac, 0xe9, 0xe0,
+ 0x6d, 0x12, 0x6f, 0x63, 0xe8, 0xe0, 0x62, 0x46, 0xed, 0xe0, 0x77, 0xe0,
+ 0x6c, 0x69, 0x61, 0x6d, 0x65, 0xee, 0xe0, 0x41, 0xa8, 0x69, 0xf3, 0x60,
+ 0x64, 0x2a, 0xda, 0x37, 0xe1, 0x06, 0x05, 0x06, 0xe0, 0x3e, 0x47, 0x73,
+ 0xe9, 0xe0, 0x5e, 0xa5, 0x6c, 0x6c, 0xe5, 0xe0, 0x5a, 0xf8, 0x63, 0x68,
+ 0x75, 0xf4, 0xe0, 0x6e, 0xc2, 0xee, 0x05, 0x09, 0xe0, 0x5a, 0x49, 0x74,
+ 0x68, 0x65, 0x6f, 0x6e, 0xf3, 0xe0, 0x69, 0x71, 0x61, 0x73, 0xef, 0xc2,
+ 0xaa, 0xec, 0x02, 0x84, 0xed, 0xe0, 0x64, 0xcb, 0x65, 0xf2, 0xe0, 0x6c,
+ 0x43, 0x67, 0xe5, 0x06, 0x04, 0x3a, 0xe0, 0x7d, 0xdd, 0xf8, 0xe0, 0x77,
+ 0x43, 0xf3, 0x02, 0x8e, 0x70, 0x65, 0x65, 0x64, 0x6d, 0x6f, 0x62, 0x69,
+ 0x6c, 0x69, 0xfa, 0xe0, 0x74, 0x32, 0xae, 0x06, 0x08, 0x09, 0xe0, 0x70,
+ 0x53, 0x77, 0x69, 0x61, 0x72, 0xe4, 0xe0, 0x59, 0x98, 0x74, 0x6f, 0x72,
+ 0x70, 0x72, 0x6f, 0xea, 0xd2, 0x2f, 0x69, 0x74, 0x2e, 0x68, 0x73, 0x2d,
+ 0x68, 0x65, 0x69, 0x6c, 0x62, 0x72, 0x6f, 0xee, 0xe0, 0x54, 0xf0, 0x66,
+ 0x72, 0x6f, 0x6e, 0xf4, 0xe0, 0x7c, 0xeb, 0xe4, 0x03, 0xdb, 0x76, 0xf5,
+ 0xe0, 0x77, 0x41, 0x61, 0x73, 0xae, 0x04, 0x0d, 0x0f, 0x87, 0x6d, 0x61,
+ 0x73, 0x73, 0x69, 0x76, 0x65, 0x67, 0x72, 0xe9, 0xe0, 0x78, 0x62, 0x68,
+ 0x6f, 0x73, 0x74, 0x65, 0x64, 0x2d, 0x62, 0x79, 0x2d, 0x70, 0x72, 0xe5,
+ 0xc0, 0xab, 0x64, 0x61, 0x74, 0xe1, 0xe0, 0x58, 0x36, 0x62, 0x65, 0x65,
+ 0x62, 0xf9, 0xe0, 0x68, 0xd9, 0xae, 0x60, 0x74, 0x2f, 0x43, 0x07, 0x41,
+ 0x60, 0xc3, 0x02, 0xef, 0x27, 0x11, 0x38, 0x09, 0x2e, 0x10, 0x20, 0x40,
+ 0x69, 0x40, 0x94, 0x41, 0x39, 0x40, 0x4e, 0x1f, 0x40, 0xe4, 0x40, 0x5b,
+ 0x38, 0x40, 0x62, 0x0a, 0x30, 0x29, 0x40, 0x51, 0x40, 0x44, 0x1f, 0x22,
+ 0x34, 0x15, 0x60, 0x34, 0x7c, 0xd8, 0x39, 0xfa, 0x05, 0x07, 0xe0, 0x7a,
+ 0x42, 0x75, 0xae, 0x60, 0x76, 0x0f, 0xc2, 0x84, 0xef, 0xe0, 0x7b, 0x78,
+ 0xf9, 0x08, 0x0c, 0x05, 0x04, 0x15, 0xe0, 0x71, 0x7c, 0x73, 0x74, 0x72,
+ 0x65, 0x2d, 0x73, 0x6c, 0x69, 0xe4, 0xe0, 0x55, 0x1f, 0x6f, 0xe4, 0xe0,
+ 0x3a, 0xba, 0x67, 0xe1, 0xda, 0x6c, 0xe1, 0x07, 0x60, 0x21, 0xea, 0xe0,
+ 0x5a, 0x03, 0x6d, 0xe1, 0x04, 0xe0, 0x71, 0xa7, 0x7a, 0x61, 0x6b, 0xe9,
+ 0xe0, 0x6e, 0xf3, 0x2e, 0xec, 0xe0, 0x7d, 0x14, 0xf8, 0x04, 0xe0, 0x2e,
+ 0xf2, 0xae, 0xe0, 0x5e, 0xf0, 0xf7, 0x03, 0x09, 0x93, 0x6f, 0x2e, 0x63,
+ 0x6f, 0x64, 0xe5, 0xe0, 0x79, 0x7a, 0xee, 0x05, 0x08, 0xe0, 0x4b, 0x65,
+ 0x70, 0x72, 0x6f, 0x76, 0xe9, 0xe0, 0x73, 0x27, 0x2e, 0xf0, 0xe0, 0x7c,
+ 0xf5, 0xe1, 0x02, 0x87, 0x72, 0x69, 0x61, 0x73, 0xe1, 0xc5, 0x2a, 0xee,
+ 0xe0, 0x3c, 0x92, 0xf6, 0x06, 0x4d, 0x07, 0xe0, 0x6d, 0x4b, 0x65, 0x72,
+ 0x68, 0x61, 0x6c, 0xec, 0xe0, 0x76, 0xb4, 0xf5, 0x04, 0x0b, 0x07, 0x84,
+ 0x74, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0xf3, 0xe0, 0x77, 0x6e, 0xed,
+ 0x60, 0x3f, 0x9e, 0xe0, 0x38, 0x75, 0xe4, 0xe0, 0x35, 0x34, 0x63, 0xe8,
+ 0xe0, 0x45, 0xcb, 0xf4, 0x0a, 0x17, 0x18, 0x07, 0x04, 0x60, 0x7a, 0x71,
+ 0xc0, 0x45, 0x73, 0xf5, 0x05, 0x0c, 0xe0, 0x77, 0x49, 0xeb, 0x04, 0xe0,
+ 0x7a, 0xfb, 0x69, 0xae, 0x60, 0x60, 0x5a, 0xd6, 0x45, 0xe3, 0xe0, 0x29,
+ 0xc1, 0xef, 0x09, 0x04, 0x04, 0x60, 0x37, 0x9f, 0xe0, 0x2d, 0xd3, 0xf9,
+ 0xe0, 0x3a, 0x25, 0xe9, 0xe0, 0x21, 0x72, 0x66, 0x75, 0xeb, 0xe0, 0x60,
+ 0xb1, 0x68, 0x65, 0x72, 0xae, 0xe0, 0x71, 0x91, 0xe5, 0xe0, 0x71, 0xf6,
+ 0xe1, 0x09, 0x06, 0x06, 0x60, 0x22, 0xfa, 0xe0, 0x3d, 0x89, 0xf2, 0x60,
+ 0x77, 0xb4, 0xc1, 0xa0, 0x70, 0x2e, 0xe3, 0xe0, 0x6d, 0xf6, 0xeb, 0x04,
+ 0xe0, 0x21, 0x20, 0x69, 0xae, 0x60, 0x71, 0xee, 0x47, 0x56, 0xc1, 0x36,
+ 0xf3, 0x0b, 0x04, 0x24, 0x06, 0x16, 0x09, 0x06, 0x25, 0xe0, 0x73, 0x7f,
+ 0x1f, 0x43, 0xf8, 0xa6, 0xf4, 0x02, 0x9d, 0xf2, 0x02, 0x93, 0xef, 0x06,
+ 0x46, 0x75, 0xe0, 0x4e, 0x4c, 0xf7, 0x04, 0xe0, 0x66, 0xdf, 0x77, 0x6c,
+ 0x6b, 0xf0, 0xe0, 0x77, 0x6f, 0x65, 0x2d, 0x74, 0xef, 0xe0, 0x37, 0x34,
+ 0xe5, 0xe0, 0x6e, 0x57, 0x6f, 0x79, 0xf2, 0xe0, 0x73, 0xcd, 0xe8, 0x02,
+ 0x84, 0xf5, 0xe0, 0x45, 0xc7, 0xe9, 0x02, 0x84, 0xee, 0xe0, 0x45, 0x90,
+ 0x6d, 0x61, 0xae, 0x60, 0x78, 0xbf, 0xc1, 0x31, 0xe5, 0x04, 0xe0, 0x75,
+ 0xc6, 0xf4, 0xe0, 0x40, 0x61, 0x63, 0x68, 0xf2, 0xe0, 0x3e, 0xca, 0xe1,
+ 0x02, 0x85, 0x73, 0xe3, 0xe0, 0x6f, 0x80, 0xeb, 0x02, 0x8c, 0xe9, 0x04,
+ 0xe0, 0x44, 0x64, 0x6b, 0x61, 0x6d, 0xe9, 0xe0, 0x4c, 0xf6, 0xe1, 0x06,
+ 0x60, 0x7a, 0x27, 0xc1, 0xac, 0x73, 0x61, 0x79, 0xe1, 0xe0, 0x29, 0x94,
+ 0x2e, 0xe8, 0x02, 0x87, 0x6f, 0x72, 0x64, 0xe1, 0xe0, 0x6f, 0x0d, 0x65,
+ 0xe4, 0xe0, 0x71, 0x2c, 0xf2, 0x0b, 0x04, 0x0d, 0x06, 0x0b, 0x40, 0xd4,
+ 0x18, 0xe0, 0x6d, 0xeb, 0xf8, 0xe0, 0x78, 0x89, 0xf3, 0x07, 0x60, 0x4f,
+ 0x41, 0xe0, 0x26, 0x3a, 0x69, 0xf4, 0xe0, 0x7a, 0x85, 0xeb, 0x60, 0x65,
+ 0x8b, 0xce, 0xf7, 0xe9, 0x02, 0x84, 0x73, 0xf4, 0xd7, 0x42, 0xe7, 0xe0,
+ 0x6b, 0x8c, 0xe7, 0x05, 0x06, 0xe0, 0x7b, 0x82, 0x61, 0x6e, 0xe9, 0xe0,
+ 0x6f, 0xa2, 0xae, 0x21, 0x06, 0x0a, 0x18, 0x09, 0x0c, 0x17, 0x0e, 0x0b,
+ 0x09, 0x11, 0x0d, 0x4a, 0x45, 0x1f, 0x2b, 0x60, 0x44, 0x87, 0x2d, 0x40,
+ 0x53, 0x4a, 0x5f, 0x03, 0x12, 0x27, 0x40, 0x73, 0x59, 0x32, 0xc4, 0x56,
+ 0xf9, 0x60, 0x79, 0xe3, 0xc1, 0x5b, 0xf5, 0x60, 0x78, 0xe6, 0x0d, 0x2f,
+ 0x40, 0x90, 0xc1, 0xa6, 0xf3, 0x60, 0x6f, 0x6c, 0x41, 0x8a, 0x46, 0x9d,
+ 0x41, 0x2c, 0x1d, 0x0a, 0x1a, 0x03, 0x15, 0x40, 0x79, 0x17, 0x1c, 0x0f,
+ 0x40, 0x42, 0xc1, 0x39, 0xf2, 0x60, 0x78, 0xc7, 0x07, 0x40, 0xde, 0xc1,
+ 0x03, 0xee, 0x60, 0x78, 0xbb, 0x40, 0x5a, 0x40, 0x72, 0x40, 0x4e, 0xc1,
+ 0x58, 0xed, 0x60, 0x73, 0xa0, 0x43, 0xc6, 0x41, 0x49, 0x03, 0x07, 0x03,
+ 0x17, 0x18, 0x40, 0x79, 0x17, 0x1c, 0x0f, 0x40, 0x42, 0x3a, 0xc0, 0xff,
+ 0xeb, 0x60, 0x78, 0x98, 0x03, 0x1e, 0x1b, 0x1e, 0x40, 0x7c, 0x40, 0x63,
+ 0xc1, 0x39, 0xe9, 0x60, 0x5a, 0xb5, 0x5d, 0xdf, 0x17, 0x03, 0x40, 0xf6,
+ 0x9f, 0xe8, 0x60, 0x78, 0x8c, 0x40, 0xa8, 0x40, 0x84, 0xba, 0xe7, 0x60,
+ 0x78, 0x59, 0x40, 0x41, 0x18, 0x1e, 0x40, 0x5b, 0x21, 0x21, 0x23, 0x1f,
+ 0x3a, 0xc0, 0xff, 0xe3, 0x60, 0x77, 0x1c, 0x41, 0x4c, 0x39, 0x1e, 0x40,
+ 0x8e, 0x40, 0x51, 0xba, 0xe2, 0x60, 0x70, 0x72, 0x47, 0xc9, 0x1d, 0x03,
+ 0x07, 0x17, 0x12, 0x27, 0x40, 0x5b, 0x17, 0x1c, 0x32, 0x9f, 0xe1, 0x06,
+ 0x60, 0x5e, 0x35, 0xd3, 0xb2, 0x6e, 0x67, 0xe5, 0x04, 0xe0, 0x7a, 0xac,
+ 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0xf4, 0xe0, 0x66, 0x5f, 0xae, 0x15,
+ 0x05, 0x4a, 0xc7, 0x60, 0x27, 0xc0, 0x4d, 0x61, 0x4f, 0xde, 0x59, 0x09,
+ 0x4d, 0xd1, 0x41, 0x8a, 0x40, 0x43, 0xc0, 0x6f, 0xf4, 0x60, 0x77, 0xfb,
+ 0x9d, 0xed, 0xe0, 0x79, 0x86, 0xf0, 0x04, 0x11, 0x0b, 0xa8, 0xf0, 0x04,
+ 0xe0, 0x73, 0x5d, 0x65, 0xe7, 0x04, 0xe0, 0x73, 0xd3, 0x1f, 0x43, 0xe5,
+ 0xe0, 0x76, 0x4d, 0xef, 0x02, 0x84, 0xec, 0xe0, 0x3f, 0x00, 0xe3, 0xe0,
+ 0x3f, 0xd8, 0xe5, 0x02, 0x88, 0x72, 0x61, 0x75, 0x6e, 0xe9, 0xe0, 0x72,
+ 0xae, 0xee, 0x05, 0x09, 0xe0, 0x7a, 0x48, 0x73, 0x6f, 0x63, 0x69, 0x61,
+ 0xec, 0xe0, 0x63, 0x19, 0x63, 0x72, 0x61, 0x66, 0x74, 0x2e, 0x68, 0x6f,
+ 0x73, 0x74, 0xe9, 0xe0, 0x66, 0x2e, 0x61, 0xec, 0xe0, 0x41, 0x51, 0xef,
+ 0x0a, 0x06, 0x04, 0x05, 0x60, 0x3c, 0xf0, 0xe0, 0x3b, 0xa0, 0x73, 0x68,
+ 0xe9, 0xe0, 0x32, 0x6c, 0xf0, 0xe0, 0x5e, 0x82, 0x6b, 0xf5, 0xe0, 0x25,
+ 0xdf, 0x67, 0xf5, 0xe0, 0x5c, 0x87, 0xee, 0x16, 0x03, 0x09, 0x0a, 0x09,
+ 0x18, 0x10, 0x06, 0x09, 0x16, 0x0e, 0x08, 0x10, 0x60, 0x2a, 0x56, 0x60,
+ 0x42, 0x85, 0x4a, 0xe9, 0xad, 0xfa, 0xc0, 0x7d, 0x74, 0x68, 0x65, 0x77,
+ 0x69, 0xe6, 0xe0, 0x70, 0x12, 0x72, 0xe5, 0x04, 0xe0, 0x70, 0x14, 0xe4,
+ 0xe0, 0x35, 0x8e, 0x70, 0x6f, 0x72, 0x74, 0x65, 0xf2, 0xe0, 0x53, 0xbd,
+ 0xef, 0x05, 0x04, 0xe0, 0x5e, 0x6b, 0xed, 0xe0, 0x39, 0x46, 0xae, 0x04,
+ 0xe0, 0x74, 0xf9, 0x66, 0x75, 0x6b, 0xf5, 0x60, 0x74, 0x66, 0xc3, 0x5a,
+ 0xec, 0x04, 0xe0, 0x79, 0xc3, 0x69, 0x6e, 0xe5, 0x04, 0xe0, 0x79, 0xbc,
+ 0xae, 0xe0, 0x34, 0x2f, 0x6a, 0x75, 0xeb, 0xe0, 0x42, 0x0d, 0xe7, 0x60,
+ 0x3a, 0x65, 0x60, 0x3d, 0xf1, 0xc1, 0x5b, 0xe6, 0x02, 0x8b, 0x6c, 0x61,
+ 0x73, 0x68, 0x64, 0x72, 0x69, 0xf6, 0xe0, 0x64, 0x19, 0x61, 0x62, 0x72,
+ 0x69, 0xe3, 0xe0, 0x44, 0x4c, 0x64, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c,
+ 0x6f, 0x63, 0x65, 0xe1, 0xe0, 0x78, 0x11, 0x63, 0x69, 0x6c, 0x6c, 0xe1,
+ 0xe0, 0x60, 0xb9, 0xe1, 0x02, 0x89, 0x76, 0x73, 0x74, 0x61, 0x63, 0xeb,
+ 0xe0, 0x79, 0x50, 0xe7, 0xe0, 0x41, 0xf0, 0xad, 0x07, 0x0a, 0x11, 0x06,
+ 0xe0, 0x78, 0xaf, 0x74, 0x68, 0x65, 0x2d, 0x77, 0x65, 0xe2, 0xe0, 0x67,
+ 0x31, 0xf2, 0x02, 0x85, 0x69, 0xef, 0xe0, 0x6a, 0xe9, 0x61, 0x6e, 0x63,
+ 0x68, 0x65, 0xf2, 0xe0, 0x69, 0x7a, 0x6b, 0x33, 0xf3, 0xe0, 0x6a, 0xda,
+ 0xe1, 0x02, 0x88, 0x70, 0x74, 0x69, 0x62, 0xec, 0xe0, 0x71, 0x91, 0x63,
+ 0x6f, 0x72, 0xee, 0xe0, 0x6a, 0xc8, 0xed, 0x0a, 0x06, 0x05, 0x05, 0x21,
+ 0x06, 0x07, 0xe0, 0x78, 0xe9, 0xf5, 0x55, 0xe4, 0xe0, 0x23, 0xf5, 0x6f,
+ 0x74, 0xe5, 0xca, 0x52, 0x6e, 0x69, 0xf7, 0xd1, 0xe4, 0xe9, 0x08, 0x06,
+ 0x0b, 0x60, 0x39, 0x19, 0xc9, 0x07, 0x74, 0x61, 0xed, 0xe0, 0x35, 0xb5,
+ 0x68, 0x61, 0x63, 0x68, 0x69, 0x6d, 0x61, 0xee, 0xe0, 0x73, 0xae, 0x2e,
+ 0xee, 0x60, 0x74, 0xb3, 0xc1, 0x36, 0x67, 0x2e, 0xec, 0xe0, 0x54, 0x0b,
+ 0xe5, 0x60, 0x2e, 0x1a, 0xe0, 0x47, 0x8e, 0xe1, 0x05, 0x03, 0xe0, 0x51,
+ 0x8b, 0xe5, 0xd5, 0x95, 0x63, 0x68, 0x69, 0xae, 0x60, 0x6e, 0x3d, 0xc7,
+ 0x8c, 0xec, 0x09, 0x06, 0x04, 0x05, 0x05, 0x0d, 0xe0, 0x77, 0x17, 0x73,
+ 0x7a, 0xf4, 0xe0, 0x5c, 0x5b, 0xec, 0xe0, 0x77, 0x3b, 0x6b, 0xf5, 0xe0,
+ 0x26, 0x00, 0x65, 0xe3, 0xe0, 0x20, 0x9d, 0x62, 0x69, 0xe1, 0x02, 0x81,
+ 0x2d, 0x74, 0x65, 0x6d, 0xf0, 0xe0, 0x60, 0x61, 0xe1, 0x04, 0xe0, 0x66,
+ 0x25, 0x79, 0x61, 0xee, 0x5d, 0x80, 0xe0, 0x5b, 0x24, 0xeb, 0x0c, 0x0f,
+ 0x18, 0x0b, 0x45, 0xa3, 0x60, 0x3e, 0x8b, 0xe0, 0x2e, 0x8d, 0xf5, 0x04,
+ 0x04, 0xdf, 0x25, 0xf4, 0xe0, 0x36, 0x5d, 0x69, 0x7a, 0xf5, 0xe0, 0x36,
+ 0x88, 0xe9, 0x04, 0xe0, 0x61, 0x6b, 0xee, 0x02, 0x83, 0xef, 0xc5, 0xc8,
+ 0x61, 0x77, 0xe1, 0x04, 0xe0, 0x78, 0x71, 0xae, 0x60, 0x73, 0xd9, 0xc2,
+ 0xec, 0xe5, 0x06, 0x60, 0x20, 0x7f, 0xda, 0xbb, 0x67, 0xe1, 0xc9, 0xd7,
+ 0xe1, 0x04, 0x05, 0x0e, 0x88, 0x7a, 0xe1, 0xe0, 0x2a, 0x81, 0x79, 0xe1,
+ 0x04, 0xe0, 0x75, 0x3c, 0x6d, 0x61, 0xae, 0x60, 0x72, 0x8e, 0xc4, 0x14,
+ 0x77, 0x61, 0xae, 0x60, 0x6c, 0xb7, 0xc5, 0x8d, 0xe7, 0xd0, 0x14, 0x6a,
+ 0xe9, 0x04, 0xe0, 0x6f, 0xdc, 0xf9, 0xe0, 0x29, 0xb7, 0xe9, 0x08, 0x04,
+ 0x08, 0x0b, 0x0c, 0xe0, 0x73, 0x44, 0x7a, 0xf5, 0xd1, 0xb1, 0x74, 0x61,
+ 0xae, 0x60, 0x66, 0x47, 0xd0, 0x31, 0xf3, 0x04, 0xe0, 0x39, 0x07, 0x68,
+ 0x69, 0xe4, 0xe0, 0x40, 0xe0, 0xf2, 0x02, 0x84, 0xed, 0xe0, 0x3a, 0xe5,
+ 0x61, 0xf3, 0xe0, 0x3c, 0xd5, 0xe1, 0xe0, 0x3a, 0xdc, 0xe8, 0x0a, 0x05,
+ 0x06, 0x0e, 0x60, 0x38, 0x4a, 0xe0, 0x39, 0xf0, 0x74, 0x61, 0xf7, 0xc8,
+ 0xac, 0x6b, 0x75, 0xf2, 0xe0, 0x40, 0xba, 0xe9, 0x04, 0xe0, 0x4d, 0x6c,
+ 0x72, 0x61, 0xae, 0x60, 0x40, 0x69, 0xe0, 0x2b, 0xf8, 0x61, 0xf2, 0xe0,
+ 0x5c, 0x16, 0xe7, 0x08, 0x10, 0x0b, 0x07, 0x1f, 0xe0, 0x52, 0x3e, 0xf5,
+ 0x02, 0x88, 0x6e, 0x69, 0xae, 0x60, 0x6c, 0xa2, 0xc3, 0xd7, 0x63, 0xe8,
+ 0xe0, 0x72, 0x7a, 0xef, 0x02, 0x84, 0xf3, 0xe0, 0x23, 0x29, 0xf2, 0xe0,
+ 0x2f, 0x02, 0xe9, 0x60, 0x39, 0x81, 0xe0, 0x33, 0x94, 0xe1, 0x0a, 0x0a,
+ 0x06, 0x60, 0x38, 0x93, 0x48, 0x6f, 0xd2, 0x8d, 0x77, 0xe1, 0x04, 0xe0,
+ 0x2f, 0x09, 0xf2, 0xe0, 0x40, 0x1f, 0x73, 0x61, 0xf7, 0xe0, 0x34, 0xb3,
+ 0xeb, 0xe0, 0x6e, 0xb9, 0xae, 0x60, 0x4c, 0xd4, 0xe0, 0x28, 0xb9, 0xe6,
+ 0x03, 0x08, 0xaa, 0x75, 0x6e, 0x61, 0x74, 0xef, 0xe0, 0x41, 0x35, 0xe6,
+ 0x02, 0xa3, 0x69, 0xe3, 0x02, 0x91, 0x69, 0x61, 0x6c, 0xae, 0x04, 0xe0,
+ 0x66, 0x9a, 0x61, 0x63, 0x61, 0x64, 0x65, 0xed, 0xe0, 0x65, 0xf8, 0xe5,
+ 0x04, 0xe0, 0x77, 0x60, 0x2d, 0x6f, 0x6e, 0x2d, 0x74, 0xe8, 0xe0, 0x73,
+ 0xea, 0xae, 0xe0, 0x5b, 0xc1, 0xae, 0x05, 0x04, 0xe0, 0x75, 0xb5, 0xea,
+ 0xe0, 0x76, 0xe7, 0xe2, 0xe0, 0x75, 0x11, 0xe4, 0x09, 0x0a, 0x60, 0x52,
+ 0xb5, 0x49, 0x74, 0xce, 0x9c, 0x65, 0xf3, 0x04, 0xe0, 0x54, 0xc9, 0xf3,
+ 0xe0, 0x54, 0xc8, 0xe1, 0x02, 0x84, 0xf7, 0xe0, 0x29, 0xac, 0xf4, 0xe0,
+ 0x3c, 0x20, 0xe3, 0x05, 0x02, 0x02, 0x0d, 0x84, 0xf3, 0x84, 0xf0, 0x82,
+ 0x69, 0x2e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x65, 0xf2, 0xe0, 0x53,
+ 0xe1, 0xe8, 0xe0, 0x3e, 0x1f, 0x65, 0x6c, 0x6f, 0xf4, 0xe0, 0x5e, 0x40,
+ 0xe2, 0x05, 0x08, 0x06, 0x04, 0x8c, 0xf5, 0x04, 0xe0, 0x71, 0xb0, 0xf3,
+ 0xde, 0x2f, 0x73, 0x65, 0xf2, 0xe0, 0x4f, 0xe0, 0xee, 0xe0, 0x70, 0xaf,
+ 0xe9, 0x06, 0x60, 0x75, 0x02, 0xc1, 0xe3, 0x68, 0xe9, 0xe0, 0x6b, 0x46,
+ 0xe1, 0x02, 0x85, 0x6e, 0x61, 0xfa, 0xd4, 0xa8, 0x6d, 0x61, 0xae, 0x60,
+ 0x4c, 0x5a, 0xcf, 0x23, 0xe1, 0x02, 0x85, 0x72, 0xe1, 0xe0, 0x5b, 0x59,
+ 0x6d, 0x69, 0x73, 0x68, 0x69, 0x72, 0x61, 0x73, 0x61, 0xf4, 0xe0, 0x74,
+ 0xdf, 0x30, 0x6f, 0xb0, 0xe0, 0x75, 0xbd, 0xee, 0x21, 0x18, 0x0b, 0x2b,
+ 0x1a, 0x1a, 0x14, 0x08, 0x42, 0xb6, 0x04, 0x1b, 0x09, 0x41, 0x4b, 0x1c,
+ 0x3a, 0x11, 0x41, 0xab, 0x0b, 0x05, 0x42, 0x74, 0x57, 0xb6, 0x57, 0x1a,
+ 0x54, 0x60, 0x50, 0x21, 0xa6, 0x1f, 0xc3, 0x06, 0x05, 0x05, 0xe0, 0x67,
+ 0x35, 0x78, 0x74, 0x74, 0xe5, 0x82, 0x66, 0xf2, 0xe0, 0x6d, 0xe1, 0x65,
+ 0x1f, 0x43, 0xe5, 0xc9, 0x3b, 0xfa, 0x04, 0xe0, 0x76, 0x76, 0xae, 0x60,
+ 0x69, 0xa1, 0xc6, 0x76, 0xf9, 0x09, 0x07, 0x04, 0x0a, 0x56, 0x34, 0xe0,
+ 0x5a, 0x78, 0x75, 0x7a, 0x65, 0xee, 0xe0, 0x3f, 0x63, 0xf3, 0xe0, 0x67,
+ 0x7a, 0xe3, 0x04, 0xe0, 0x76, 0x56, 0x2e, 0xed, 0xe0, 0x62, 0x0e, 0xe1,
+ 0x02, 0x86, 0xee, 0x44, 0x2f, 0xe0, 0x70, 0xd9, 0xe1, 0xc6, 0x67, 0xf5,
+ 0x07, 0x04, 0x52, 0x8a, 0xe0, 0x63, 0xaf, 0xef, 0xe0, 0x5d, 0x07, 0x6d,
+ 0xe1, 0x04, 0xe0, 0x20, 0x9c, 0x74, 0x61, 0xae, 0x60, 0x6d, 0x65, 0xc7,
+ 0x17, 0xf4, 0x06, 0x04, 0x06, 0xe0, 0x74, 0x5c, 0xf2, 0xe0, 0x74, 0xc8,
+ 0x64, 0x6c, 0x6c, 0xae, 0xc0, 0x6d, 0xae, 0x60, 0x72, 0xfc, 0x04, 0x41,
+ 0x71, 0x14, 0x88, 0xf3, 0x07, 0x04, 0x60, 0x5c, 0x43, 0xd8, 0x19, 0xf7,
+ 0xe0, 0x72, 0xe8, 0x75, 0x70, 0x64, 0x61, 0xf4, 0xe0, 0x65, 0xcd, 0xf2,
+ 0x60, 0x73, 0x8c, 0x40, 0xc9, 0xc1, 0xa7, 0xef, 0x17, 0x0c, 0x26, 0x0c,
+ 0x41, 0x1c, 0x14, 0x40, 0x56, 0x09, 0x08, 0x40, 0x4b, 0x04, 0x08, 0x11,
+ 0x08, 0x29, 0x14, 0x08, 0xe0, 0x73, 0x53, 0x7a, 0x61, 0x77, 0x61, 0x6f,
+ 0x6e, 0x73, 0x65, 0xee, 0xe0, 0x72, 0xc0, 0xf7, 0x0a, 0x05, 0x07, 0x60,
+ 0x4d, 0x07, 0x57, 0x72, 0xd1, 0x41, 0x72, 0xf5, 0xe0, 0x73, 0x51, 0x61,
+ 0x72, 0x75, 0xe4, 0xe0, 0x66, 0xd9, 0x2d, 0x64, 0x6e, 0x73, 0xae, 0x06,
+ 0x60, 0x72, 0xe0, 0xc2, 0xac, 0xf4, 0xe0, 0x65, 0x30, 0xf6, 0x06, 0x52,
+ 0xc3, 0xe0, 0x5f, 0x40, 0x65, 0x63, 0xef, 0xce, 0x6b, 0xf4, 0x09, 0x06,
+ 0x0f, 0x15, 0x40, 0xe1, 0xe0, 0x73, 0x2f, 0x74, 0x65, 0xf2, 0xe0, 0x69,
+ 0xe2, 0xef, 0x05, 0x05, 0xe0, 0x6d, 0x53, 0x67, 0x61, 0xf7, 0xdc, 0xd9,
+ 0xe4, 0xe0, 0x36, 0x0e, 0x69, 0xe3, 0x02, 0x86, 0x69, 0x61, 0xf3, 0xe0,
+ 0x72, 0xc1, 0x65, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x6e, 0xe5, 0xe0, 0x57,
+ 0xc7, 0x65, 0x62, 0x6f, 0x6f, 0xeb, 0x03, 0xc0, 0x9f, 0xae, 0x07, 0x0b,
+ 0x05, 0x06, 0x04, 0x20, 0xaa, 0x75, 0x73, 0xad, 0x04, 0x40, 0xa2, 0x8f,
+ 0x77, 0xe5, 0xc0, 0xb1, 0x73, 0x61, 0xad, 0xc0, 0xa4, 0x6d, 0x65, 0xad,
+ 0x40, 0x48, 0xb6, 0x69, 0xec, 0xc0, 0x42, 0x65, 0x75, 0xad, 0x04, 0x04,
+ 0x07, 0x85, 0x77, 0xe5, 0xc0, 0x64, 0x73, 0x6f, 0x75, 0x74, 0xe8, 0xc0,
+ 0x92, 0x6e, 0x6f, 0xf2, 0xc0, 0x65, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x61,
+ 0xec, 0xc0, 0x84, 0xe3, 0x02, 0x9c, 0x6e, 0x2d, 0x6e, 0x6f, 0x72, 0x74,
+ 0xe8, 0x02, 0x84, 0x77, 0x65, 0x73, 0x74, 0x2d, 0x31, 0x2e, 0x73, 0x61,
+ 0x67, 0x65, 0x6d, 0x61, 0x6b, 0x65, 0xf2, 0xe0, 0x56, 0x76, 0x61, 0x2d,
+ 0x63, 0x65, 0x6e, 0x74, 0x72, 0x61, 0xec, 0xc0, 0x54, 0xe1, 0x02, 0xa8,
+ 0x70, 0xad, 0x03, 0x14, 0xb2, 0x73, 0x6f, 0x75, 0x74, 0xe8, 0x03, 0xc0,
+ 0x48, 0x65, 0x61, 0x73, 0x74, 0xad, 0x04, 0x10, 0x32, 0x82, 0xb4, 0xc0,
+ 0x44, 0x6e, 0x6f, 0x72, 0x74, 0x68, 0x65, 0x61, 0x73, 0x74, 0xad, 0x03,
+ 0x32, 0x82, 0xb3, 0xb4, 0x66, 0x2d, 0x73, 0x6f, 0x75, 0x74, 0xe8, 0xa0,
+ 0x2d, 0x66, 0x69, 0x70, 0x73, 0x2e, 0x75, 0x73, 0xad, 0x03, 0x06, 0x8f,
+ 0x77, 0x65, 0x73, 0x74, 0xad, 0x97, 0x67, 0x6f, 0x76, 0xad, 0x02, 0x83,
+ 0x77, 0xe5, 0x83, 0x65, 0x61, 0x73, 0x74, 0xad, 0x8a, 0x65, 0x61, 0x73,
+ 0x74, 0xad, 0x02, 0x82, 0xb2, 0x82, 0x31, 0x2e, 0x73, 0x61, 0x67, 0x65,
+ 0x6d, 0x61, 0x6b, 0x65, 0x72, 0x2e, 0xe1, 0xe0, 0x56, 0xe6, 0x61, 0x69,
+ 0x72, 0x65, 0xf3, 0xd0, 0x5a, 0xf3, 0x02, 0x86, 0x68, 0x69, 0xf2, 0xe0,
+ 0x3d, 0xda, 0xe5, 0x04, 0xe0, 0x72, 0xa0, 0x67, 0x61, 0xf7, 0xe0, 0x2c,
+ 0xe5, 0xf2, 0x03, 0x12, 0x89, 0xf4, 0x04, 0xe0, 0x6d, 0x08, 0xe8, 0x04,
+ 0xe0, 0x4a, 0x39, 0x66, 0x6c, 0x61, 0x6e, 0xeb, 0xe0, 0x62, 0xaf, 0x65,
+ 0x2d, 0x6f, 0x67, 0x2d, 0xf5, 0xe0, 0x6d, 0x36, 0xe4, 0x07, 0x0c, 0x04,
+ 0x0c, 0xe0, 0x6d, 0x10, 0x72, 0xe5, 0x02, 0x84, 0xe9, 0xe0, 0x3c, 0x0b,
+ 0xad, 0xe0, 0x67, 0x88, 0x6b, 0xe1, 0xdc, 0x1f, 0x65, 0x73, 0x74, 0x65,
+ 0x2d, 0x69, 0x64, 0x63, 0xae, 0xe0, 0x24, 0x03, 0xad, 0x03, 0x04, 0x86,
+ 0xef, 0xe0, 0x6d, 0x0b, 0x66, 0x72, 0xef, 0xe0, 0x6d, 0xec, 0x61, 0xf5,
+ 0xe0, 0x46, 0x28, 0xef, 0x04, 0xe0, 0x61, 0x1e, 0xf0, 0xe0, 0x72, 0x9d,
+ 0x6e, 0x6f, 0x69, 0x63, 0xe8, 0xe0, 0x34, 0xa8, 0xed, 0x06, 0x0a, 0x05,
+ 0xe0, 0x34, 0x8f, 0x65, 0xae, 0x04, 0xe0, 0x29, 0xc1, 0xe3, 0xe0, 0x70,
+ 0x3e, 0x62, 0xf2, 0xe0, 0x4e, 0x3e, 0xae, 0x13, 0x04, 0x05, 0x07, 0x06,
+ 0x05, 0x59, 0xd2, 0x60, 0x4d, 0xfa, 0x1a, 0x13, 0x40, 0xdd, 0x40, 0x79,
+ 0xc6, 0x02, 0xf4, 0xe0, 0x71, 0x8b, 0xf2, 0x60, 0x72, 0x4e, 0x8f, 0xf0,
+ 0x60, 0x71, 0x85, 0x40, 0xa8, 0xab, 0xee, 0x60, 0x67, 0xea, 0xc9, 0xca,
+ 0x62, 0xf2, 0xe0, 0x62, 0x63, 0xe1, 0x60, 0x71, 0x76, 0xc2, 0x4b, 0xeb,
+ 0xe0, 0x68, 0x17, 0x69, 0x70, 0xae, 0x60, 0x55, 0x9d, 0xc8, 0x15, 0xe8,
+ 0x02, 0x89, 0xef, 0x03, 0xdc, 0xa6, 0x73, 0xf4, 0xe0, 0x5d, 0xa3, 0x65,
+ 0xea, 0xe0, 0x33, 0x49, 0xe7, 0x47, 0xc2, 0x60, 0x25, 0x38, 0xc7, 0x57,
+ 0xe4, 0x02, 0x9e, 0xe5, 0x02, 0x8c, 0x73, 0x2e, 0x6b, 0x38, 0x73, 0xae,
+ 0x60, 0x21, 0x67, 0x08, 0xde, 0xa2, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x63,
+ 0x65, 0x72, 0x2e, 0x6c, 0x69, 0xee, 0xe0, 0x5c, 0xc9, 0x61, 0xae, 0x60,
+ 0x3d, 0x2b, 0xe0, 0x34, 0x6d, 0xe2, 0x03, 0x06, 0x86, 0x75, 0x73, 0xe8,
+ 0xe0, 0x4e, 0x50, 0x6f, 0x72, 0xe9, 0xe0, 0x6e, 0xa9, 0x65, 0xef, 0xc9,
+ 0xb9, 0xae, 0x60, 0x6c, 0xfc, 0x44, 0x5c, 0xc1, 0xfb, 0x2d, 0x69, 0x70,
+ 0xae, 0x0a, 0x60, 0x63, 0x14, 0x4d, 0x0c, 0x40, 0x56, 0xc2, 0xac, 0xe3,
+ 0x60, 0x62, 0xf9, 0xcc, 0xfb, 0xed, 0xe0, 0x31, 0x87, 0xec, 0x05, 0x0d,
+ 0xe0, 0x73, 0x28, 0xae, 0x06, 0x60, 0x6c, 0xd0, 0xc4, 0xca, 0xe3, 0x60,
+ 0x71, 0x86, 0xc1, 0x4f, 0x2d, 0x61, 0x6d, 0x73, 0xad, 0xe0, 0x3e, 0xb8,
+ 0xea, 0x04, 0xe0, 0x6d, 0x76, 0xf3, 0xe0, 0x66, 0xb5, 0xe9, 0x0f, 0x09,
+ 0x0d, 0x40, 0x96, 0x07, 0x1a, 0x25, 0x1f, 0x0e, 0x60, 0x68, 0x42, 0xc9,
+ 0xa6, 0x79, 0x6f, 0x64, 0x6f, 0x67, 0x61, 0xf7, 0xc9, 0x0f, 0xf4, 0x02,
+ 0x84, 0xf4, 0xe0, 0x4a, 0xa7, 0x65, 0x72, 0xef, 0xe0, 0x6a, 0xb7, 0xf3,
+ 0x05, 0x11, 0xe0, 0x6e, 0x67, 0xf3, 0x05, 0x05, 0xe0, 0x4a, 0x8d, 0x68,
+ 0xe9, 0xe0, 0x31, 0xb6, 0xe1, 0x60, 0x70, 0xa8, 0xc0, 0xfd, 0x68, 0xe9,
+ 0x0c, 0x04, 0x05, 0x0c, 0x19, 0x04, 0x10, 0x03, 0x0a, 0x1c, 0xc3, 0x95,
+ 0xf7, 0xe0, 0x6b, 0x85, 0x74, 0x6f, 0xf3, 0xc8, 0xd4, 0xef, 0x04, 0xe0,
+ 0x6d, 0x75, 0x6b, 0x6f, 0x70, 0xf0, 0xe0, 0x56, 0xe9, 0x6e, 0xef, 0x03,
+ 0x07, 0x87, 0x73, 0x68, 0x69, 0xed, 0xe0, 0x33, 0x1a, 0x6f, 0x6d, 0x6f,
+ 0xf4, 0xe0, 0x6c, 0x5b, 0x6d, 0x69, 0xf9, 0xe0, 0x32, 0x63, 0x6d, 0xe5,
+ 0xda, 0xdf, 0x6b, 0xe1, 0x03, 0xd0, 0x64, 0xf4, 0x04, 0xe0, 0x67, 0x0a,
+ 0x73, 0x75, 0xf2, 0xe0, 0x3b, 0xcd, 0xe9, 0xdc, 0xf2, 0x68, 0x61, 0x72,
+ 0x61, 0xae, 0x60, 0x6b, 0x30, 0xc2, 0xbb, 0xe1, 0x04, 0x05, 0x08, 0x85,
+ 0x7a, 0xe1, 0xe0, 0x30, 0x30, 0x77, 0x61, 0x6b, 0x75, 0xf2, 0xe0, 0x6c,
+ 0xad, 0x72, 0xe9, 0xe0, 0x67, 0xb6, 0x69, 0xfa, 0xe0, 0x6c, 0xe4, 0xae,
+ 0x60, 0x66, 0xd2, 0xc9, 0xba, 0x72, 0x61, 0x73, 0xe1, 0xe0, 0x3c, 0x06,
+ 0xee, 0x03, 0x0b, 0x84, 0xef, 0x04, 0xe0, 0x2b, 0x8d, 0x6d, 0x69, 0xf9,
+ 0xe0, 0x6d, 0x84, 0xea, 0xe0, 0x70, 0x9d, 0xe8, 0x60, 0x2e, 0x66, 0xe0,
+ 0x31, 0x15, 0xeb, 0x07, 0x0b, 0x04, 0x09, 0xe0, 0x70, 0x9e, 0xef, 0x04,
+ 0xe0, 0x70, 0xf3, 0x6c, 0x61, 0xe5, 0xe0, 0x57, 0x19, 0xeb, 0xe0, 0x61,
+ 0x1e, 0xe9, 0x04, 0xe0, 0x70, 0x69, 0xf4, 0xe0, 0x62, 0x6c, 0x61, 0xe8,
+ 0xe0, 0x3b, 0x75, 0xe9, 0x05, 0x04, 0x04, 0x04, 0x83, 0xfa, 0xe0, 0x3b,
+ 0x32, 0xed, 0xe0, 0x66, 0xc1, 0x6b, 0xe1, 0xd6, 0xf1, 0xe8, 0xce, 0xbc,
+ 0x67, 0x61, 0x74, 0x61, 0xae, 0x60, 0x6d, 0xb2, 0xc2, 0x9e, 0x65, 0x72,
+ 0x75, 0x63, 0x68, 0x6f, 0x6d, 0x6f, 0x73, 0x63, 0xe9, 0xe0, 0x6d, 0x30,
+ 0xe3, 0x05, 0x0b, 0xe0, 0x70, 0x4c, 0x68, 0x69, 0x6e, 0x61, 0x6e, 0xae,
+ 0x60, 0x55, 0xf7, 0xcd, 0xb6, 0xae, 0x06, 0x60, 0x6d, 0x5e, 0xc3, 0x37,
+ 0xf4, 0xe0, 0x6f, 0x8f, 0xe8, 0x08, 0x06, 0x05, 0x60, 0x6c, 0x13, 0xc3,
+ 0x3f, 0x73, 0x2e, 0xf5, 0xe0, 0x6f, 0x5a, 0x6c, 0xe6, 0xe0, 0x4c, 0xa9,
+ 0x2d, 0x73, 0x65, 0x72, 0xf6, 0xe0, 0x6e, 0x61, 0xe7, 0x08, 0x1c, 0x10,
+ 0x60, 0x57, 0x44, 0xda, 0x37, 0x72, 0x6f, 0xeb, 0x02, 0x8f, 0xae, 0x08,
+ 0x60, 0x63, 0xfe, 0x4c, 0x26, 0xc0, 0x6e, 0x70, 0x69, 0xfa, 0xe0, 0x5d,
+ 0xaa, 0x2d, 0x66, 0x72, 0x65, 0xe5, 0xe0, 0x4b, 0xb4, 0xef, 0x04, 0xe0,
+ 0x71, 0x86, 0xae, 0x60, 0x2b, 0x2d, 0x60, 0x32, 0x49, 0x48, 0x3d, 0xc7,
+ 0x60, 0x68, 0xe5, 0xe0, 0x62, 0x74, 0xe6, 0x07, 0x03, 0x60, 0x6f, 0xc2,
+ 0xc1, 0xa9, 0xf3, 0xc5, 0x6d, 0xec, 0x60, 0x51, 0x93, 0xdf, 0xd7, 0xe5,
+ 0x12, 0x05, 0x11, 0x07, 0x06, 0x41, 0x0c, 0x2d, 0x0f, 0x05, 0x06, 0x08,
+ 0x08, 0x60, 0x63, 0xe9, 0xcb, 0xe3, 0x79, 0xe1, 0xe0, 0x2e, 0xcf, 0xf8,
+ 0x04, 0xe0, 0x6c, 0x44, 0xf4, 0x04, 0xe0, 0x71, 0x43, 0x64, 0x69, 0x72,
+ 0xe5, 0xe0, 0x4f, 0xb5, 0xf7, 0x60, 0x38, 0xdf, 0xe0, 0x38, 0x5c, 0x75,
+ 0x73, 0xf4, 0xe0, 0x5f, 0x21, 0xf4, 0x0d, 0x06, 0x07, 0x08, 0x06, 0x40,
+ 0xdb, 0x60, 0x4f, 0x2c, 0xe0, 0x20, 0xff, 0x77, 0x6f, 0xf2, 0xe0, 0x6e,
+ 0xb8, 0x6c, 0x69, 0x66, 0xf9, 0xe0, 0x6f, 0xa1, 0x67, 0x61, 0x6d, 0x65,
+ 0xf2, 0xe0, 0x55, 0x6e, 0x66, 0x6c, 0xe9, 0xe0, 0x69, 0x87, 0xae, 0x1f,
+ 0x08, 0x0c, 0x12, 0x0e, 0x0c, 0x14, 0x0b, 0x05, 0x0c, 0x0e, 0x05, 0x0a,
+ 0x0c, 0x10, 0x4a, 0x1f, 0x60, 0x3a, 0x26, 0x40, 0x6f, 0x2a, 0x29, 0x4a,
+ 0x5c, 0x03, 0x03, 0x39, 0xd9, 0xa5, 0xf5, 0x60, 0x6e, 0x72, 0x0d, 0x2f,
+ 0xc0, 0x90, 0xf4, 0x60, 0x6e, 0x4d, 0x20, 0x1e, 0x12, 0x40, 0x82, 0x33,
+ 0x32, 0x9f, 0xf3, 0x60, 0x64, 0xee, 0x41, 0x8a, 0x47, 0xc9, 0x27, 0x1a,
+ 0x03, 0x15, 0x40, 0x79, 0x17, 0x1c, 0xc1, 0x8a, 0xf0, 0x60, 0x6e, 0x2f,
+ 0x27, 0x03, 0x17, 0x18, 0x40, 0x79, 0x17, 0x2b, 0x23, 0x9f, 0xee, 0x60,
+ 0x65, 0xc8, 0x48, 0x76, 0x40, 0x5a, 0x40, 0xc0, 0xc1, 0x58, 0xed, 0x60,
+ 0x69, 0x23, 0x43, 0xc6, 0x41, 0x49, 0x03, 0x07, 0x03, 0x17, 0x18, 0x40,
+ 0x79, 0x17, 0x1c, 0x0f, 0xc0, 0x7c, 0xeb, 0x60, 0x6e, 0x1e, 0x03, 0x39,
+ 0x1e, 0x40, 0xdf, 0xc1, 0x39, 0xea, 0x60, 0x6e, 0xfb, 0x8f, 0xe9, 0x60,
+ 0x50, 0x39, 0x5d, 0xdf, 0x17, 0x03, 0x03, 0x40, 0xf3, 0x9f, 0xe7, 0x60,
+ 0x6e, 0x26, 0x18, 0x40, 0x79, 0x21, 0x21, 0x23, 0x1f, 0x3a, 0xc0, 0xff,
+ 0xe6, 0x60, 0x6e, 0x15, 0x92, 0xe5, 0x60, 0x64, 0x7f, 0x45, 0x86, 0x44,
+ 0x9f, 0xc1, 0xbd, 0xe3, 0x60, 0x6d, 0xe8, 0x1e, 0x1b, 0x1e, 0x40, 0x8e,
+ 0x40, 0x51, 0xba, 0xe2, 0x60, 0x65, 0xf3, 0x47, 0xc9, 0x1d, 0x0a, 0x17,
+ 0x12, 0x40, 0x82, 0x17, 0x1c, 0x32, 0x9f, 0xe1, 0x60, 0x64, 0x59, 0x40,
+ 0xfa, 0x48, 0x76, 0x21, 0x03, 0x36, 0x40, 0x9d, 0x23, 0x40, 0x59, 0xc0,
+ 0xff, 0x2d, 0x66, 0x72, 0x65, 0xe1, 0xe0, 0x3c, 0x4c, 0xf3, 0x06, 0x07,
+ 0x0b, 0xe0, 0x65, 0x3f, 0x73, 0xe5, 0x52, 0x82, 0xe0, 0x55, 0xfb, 0x6f,
+ 0x64, 0xe4, 0x04, 0xe0, 0x60, 0x92, 0xf4, 0xe0, 0x60, 0x8e, 0xae, 0x02,
+ 0x8a, 0x62, 0x75, 0x73, 0x6b, 0x65, 0x72, 0xf5, 0xe0, 0x6b, 0xde, 0x61,
+ 0x6b, 0x65, 0x72, 0xf3, 0xcb, 0x45, 0xf2, 0x04, 0xe0, 0x69, 0xe4, 0x64,
+ 0x70, 0x6f, 0x6c, 0x2e, 0x6f, 0xf6, 0xe0, 0x6f, 0x3d, 0x6d, 0xf5, 0xe0,
+ 0x64, 0x48, 0x6b, 0x6f, 0xae, 0xe0, 0x48, 0xda, 0x64, 0x72, 0x65, 0x2d,
+ 0x65, 0xe9, 0xdf, 0x5c, 0x61, 0x74, 0x2d, 0x75, 0xf2, 0xe0, 0x68, 0xf8,
+ 0xae, 0x0b, 0x60, 0x2a, 0x80, 0x60, 0x33, 0x88, 0x4f, 0x5b, 0xc0, 0xb2,
+ 0xf5, 0x60, 0x6d, 0x56, 0xc2, 0x68, 0xe3, 0x04, 0xe0, 0x6f, 0xb5, 0xae,
+ 0x60, 0x61, 0xfa, 0xc8, 0xb6, 0xe2, 0x60, 0x6e, 0x05, 0x82, 0xe1, 0x1c,
+ 0x04, 0x0e, 0x05, 0x22, 0x10, 0x30, 0x0d, 0x08, 0x40, 0x45, 0x40, 0x6c,
+ 0x06, 0x40, 0x7a, 0x04, 0x0a, 0x40, 0x67, 0x0d, 0x09, 0x08, 0x60, 0x6b,
+ 0x38, 0xc2, 0x03, 0xf9, 0xe0, 0x63, 0xee, 0xf6, 0x08, 0x60, 0x60, 0x36,
+ 0x4c, 0x66, 0xc0, 0xad, 0x6f, 0xe9, 0xe0, 0x6d, 0x94, 0x75, 0xf3, 0xe0,
+ 0x2b, 0xe4, 0xf4, 0x08, 0x4c, 0xb4, 0x60, 0x2e, 0xa8, 0xc6, 0x00, 0x75,
+ 0xf2, 0x02, 0x8c, 0x62, 0x72, 0x75, 0x6b, 0x73, 0x67, 0x79, 0x6d, 0xee,
+ 0xe0, 0x5d, 0xf9, 0xe1, 0x04, 0xe0, 0x6f, 0x58, 0xec, 0xe0, 0x6c, 0x9f,
+ 0x73, 0xf5, 0x04, 0xe0, 0x63, 0xc9, 0x73, 0x68, 0x69, 0x6f, 0x62, 0x61,
+ 0xf2, 0xe0, 0x63, 0xc1, 0xf2, 0x07, 0x08, 0x0b, 0x05, 0xe0, 0x63, 0x74,
+ 0x76, 0xe9, 0x60, 0x36, 0xc5, 0xe0, 0x2d, 0xe5, 0xf5, 0x02, 0x84, 0xf4,
+ 0xe0, 0x20, 0xd8, 0xf3, 0xe0, 0x2e, 0x75, 0x69, 0xf4, 0xe0, 0x2f, 0x46,
+ 0xe1, 0x02, 0x87, 0x73, 0x68, 0x69, 0xee, 0xe0, 0x6d, 0x3e, 0xae, 0x60,
+ 0x66, 0xbf, 0xc6, 0xaf, 0xf0, 0x02, 0x85, 0x6f, 0xec, 0xe0, 0x66, 0xab,
+ 0x6c, 0xe5, 0xe0, 0x56, 0x37, 0x6f, 0x73, 0x68, 0x69, 0xed, 0xe0, 0x60,
+ 0xc6, 0xee, 0x0a, 0x05, 0x0c, 0x04, 0x04, 0x05, 0x07, 0x03, 0x04, 0x88,
+ 0x79, 0xef, 0xe0, 0x37, 0xbd, 0xf4, 0x02, 0x84, 0xef, 0xe0, 0x37, 0xec,
+ 0x61, 0xee, 0xe0, 0x60, 0xb1, 0xf0, 0xe0, 0x63, 0x44, 0xee, 0xe0, 0x28,
+ 0xec, 0x6d, 0x6f, 0xeb, 0xd7, 0xbf, 0x6b, 0x6f, 0x6b, 0xf5, 0xe0, 0x68,
+ 0xd0, 0xea, 0xd7, 0x70, 0xe7, 0xe0, 0x69, 0x54, 0x62, 0x75, 0xae, 0x60,
+ 0x52, 0x7f, 0xc0, 0x61, 0xe1, 0x40, 0xac, 0xe0, 0x52, 0x42, 0xed, 0x05,
+ 0x0f, 0x0a, 0x3f, 0x89, 0xf3, 0x02, 0x88, 0x73, 0x6b, 0x6f, 0x67, 0xe1,
+ 0xe0, 0x68, 0x77, 0xef, 0xe0, 0x6a, 0x55, 0xe9, 0x04, 0xe0, 0x69, 0x33,
+ 0x6b, 0xe1, 0xe0, 0x27, 0x09, 0xe5, 0x06, 0x03, 0x0a, 0xe0, 0x6e, 0x87,
+ 0xf2, 0xc0, 0x8f, 0x67, 0xe1, 0x04, 0xe0, 0x2b, 0x2c, 0xf7, 0xe0, 0x37,
+ 0xae, 0xae, 0x13, 0x06, 0x07, 0x06, 0x45, 0xaa, 0x60, 0x32, 0xdb, 0x55,
+ 0x40, 0x40, 0x47, 0x4d, 0x28, 0x50, 0x91, 0xc0, 0x5a, 0xf0, 0x60, 0x6d,
+ 0x19, 0xc1, 0x54, 0xed, 0x60, 0x6a, 0xb0, 0x41, 0x56, 0xaf, 0xe5, 0x60,
+ 0x6c, 0xa7, 0xc1, 0xbd, 0xe1, 0xe0, 0x6b, 0xec, 0xe4, 0x04, 0xe0, 0x5f,
+ 0x1f, 0x61, 0xec, 0xd2, 0x7e, 0x61, 0xf3, 0xe0, 0x4e, 0xa3, 0x6c, 0x63,
+ 0x68, 0xe9, 0xc3, 0xcf, 0xeb, 0x03, 0x04, 0x86, 0xec, 0xe0, 0x33, 0xb8,
+ 0x69, 0x6a, 0xe9, 0xe0, 0x34, 0xac, 0xe1, 0x0c, 0x0f, 0x03, 0x1d, 0x0f,
+ 0x13, 0x08, 0x5a, 0x8c, 0xe0, 0x46, 0xd9, 0xf4, 0x04, 0x05, 0xc7, 0x54,
+ 0x73, 0xf5, 0xe0, 0x27, 0x9f, 0x6f, 0xed, 0xe0, 0x69, 0x68, 0xf3, 0xd2,
+ 0xc3, 0xee, 0x02, 0x93, 0xef, 0x03, 0x05, 0x85, 0x74, 0xef, 0xe0, 0x65,
+ 0xe1, 0x6a, 0xef, 0xe0, 0x65, 0x41, 0xae, 0x60, 0x6a, 0xc3, 0xb3, 0x69,
+ 0x69, 0x6b, 0x61, 0xf7, 0xdd, 0x11, 0xed, 0x05, 0x04, 0xe0, 0x2e, 0xa8,
+ 0x75, 0xf2, 0xc4, 0x05, 0x69, 0xe3, 0xe0, 0x45, 0xd0, 0xe7, 0x05, 0x40,
+ 0x77, 0xd5, 0xc7, 0x61, 0x77, 0x61, 0xae, 0x60, 0x62, 0x57, 0x46, 0x1a,
+ 0x42, 0x61, 0xc1, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0xf2, 0xe0, 0x2d, 0x7d,
+ 0xae, 0x60, 0x62, 0x7f, 0xc3, 0xc3, 0xe9, 0xe0, 0x51, 0xfc, 0x68, 0xe1,
+ 0x04, 0xe0, 0x69, 0x2c, 0xf2, 0xe0, 0x34, 0xd4, 0xe7, 0x03, 0x0c, 0x89,
+ 0xef, 0x04, 0xe0, 0x69, 0x1f, 0x79, 0xe1, 0x56, 0x20, 0xe0, 0x57, 0x95,
+ 0xe9, 0x04, 0xe0, 0x67, 0xeb, 0xf3, 0xe0, 0x5f, 0x4d, 0xe1, 0x09, 0x07,
+ 0x10, 0x0c, 0x0b, 0x0e, 0x04, 0xd9, 0x1e, 0x74, 0xef, 0x45, 0xac, 0xe0,
+ 0x65, 0xd9, 0xf3, 0x02, 0x84, 0xf5, 0xe0, 0x66, 0x3f, 0x61, 0x6b, 0x69,
+ 0xae, 0x60, 0x52, 0x33, 0xd9, 0xad, 0xf2, 0x04, 0xe0, 0x2d, 0xa0, 0x65,
+ 0x79, 0x61, 0xed, 0xe0, 0x2d, 0x9c, 0x6f, 0x6b, 0xe1, 0x04, 0xe0, 0x69,
+ 0x29, 0x6b, 0xf9, 0xdc, 0x45, 0x6e, 0xef, 0x02, 0x84, 0x68, 0xe1, 0xdf,
+ 0x1f, 0xae, 0x60, 0x6a, 0x53, 0xc1, 0x68, 0xe9, 0xe0, 0x36, 0x2b, 0x68,
+ 0xe1, 0xc3, 0xd1, 0x63, 0x68, 0x69, 0x6b, 0x61, 0x74, 0x73, 0x75, 0x75,
+ 0xf2, 0xe0, 0x62, 0xa6, 0xe2, 0x04, 0xe0, 0x6d, 0x47, 0x61, 0xf2, 0xd6,
+ 0x0b, 0x61, 0x6d, 0x65, 0x73, 0x6a, 0xe5, 0xd0, 0xb9, 0x34, 0xf5, 0xe0,
+ 0x6c, 0xaf, 0xb4, 0xe0, 0x3a, 0xd3, 0xed, 0x25, 0x23, 0x41, 0xa8, 0x09,
+ 0x07, 0x40, 0x9c, 0x12, 0x17, 0x29, 0x06, 0x41, 0xae, 0x07, 0x10, 0x0d,
+ 0x06, 0x0d, 0x43, 0x2b, 0x07, 0x41, 0x3f, 0x0b, 0x28, 0x0b, 0x60, 0x39,
+ 0xa3, 0x49, 0xbe, 0x5c, 0x8c, 0x41, 0x2c, 0x9d, 0x9f, 0x02, 0x84, 0x44,
+ 0xc1, 0xca, 0x9b, 0xc3, 0x02, 0x8a, 0xe5, 0x02, 0x84, 0xf3, 0xe0, 0x64,
+ 0x5b, 0xec, 0xca, 0xd5, 0xe1, 0x02, 0x89, 0x74, 0x74, 0x61, 0x2d, 0x76,
+ 0x1f, 0xc3, 0xc9, 0x8e, 0xec, 0xca, 0xd8, 0xf9, 0x18, 0x05, 0x05, 0x20,
+ 0x40, 0x57, 0x21, 0x05, 0x19, 0x07, 0x07, 0x07, 0x05, 0x32, 0x08, 0x27,
+ 0x0d, 0x1c, 0x06, 0x60, 0x64, 0x95, 0xc6, 0xd1, 0x77, 0xe9, 0xe0, 0x57,
+ 0x91, 0x76, 0xee, 0xe0, 0x47, 0x48, 0xf4, 0x03, 0x07, 0x85, 0x75, 0x6c,
+ 0x65, 0xe1, 0xe0, 0x6b, 0xd3, 0x69, 0xf3, 0xe0, 0x6c, 0x2f, 0x61, 0x62,
+ 0x69, 0x74, 0x2e, 0x63, 0xef, 0x04, 0xe0, 0x6c, 0xa6, 0x2e, 0xe9, 0xe0,
+ 0x6b, 0xf6, 0xf3, 0x03, 0x37, 0x8c, 0x70, 0x72, 0x65, 0x61, 0x64, 0x73,
+ 0x68, 0x6f, 0x70, 0xae, 0x0e, 0x07, 0x06, 0x60, 0x58, 0x43, 0x04, 0x49,
+ 0x60, 0x4a, 0x2c, 0x0c, 0x2e, 0x8a, 0xee, 0x60, 0x6b, 0xd6, 0x40, 0x78,
+ 0x99, 0xe9, 0x60, 0x6c, 0x1d, 0xc0, 0x44, 0xe3, 0x06, 0x60, 0x5c, 0x2b,
+ 0xcf, 0x9e, 0xef, 0x04, 0xe0, 0x69, 0x22, 0xed, 0x47, 0xd7, 0xe0, 0x64,
+ 0x95, 0x68, 0x6f, 0xf0, 0x04, 0xe0, 0x38, 0x86, 0x69, 0xe6, 0xe0, 0x4e,
+ 0xd0, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x63, 0x61, 0x6d, 0x65,
+ 0x72, 0xe1, 0xe0, 0x58, 0x94, 0xf0, 0x04, 0x03, 0x04, 0x87, 0xf3, 0xdb,
+ 0xa1, 0xe9, 0xe0, 0x53, 0x43, 0x68, 0x6f, 0x74, 0xef, 0xe0, 0x36, 0x16,
+ 0xe5, 0x02, 0x86, 0x74, 0x73, 0xae, 0xe0, 0x4e, 0x8f, 0x70, 0xae, 0xe0,
+ 0x48, 0xae, 0x6f, 0xeb, 0xe0, 0x67, 0xe1, 0xed, 0x02, 0x88, 0x65, 0x64,
+ 0x69, 0x61, 0xf0, 0xe0, 0x68, 0xba, 0x61, 0x69, 0x6c, 0x65, 0x72, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x2e, 0xf4, 0xe0, 0x57, 0x96, 0x6b, 0x6f, 0x6c, 0xe1,
+ 0xe0, 0x50, 0xf7, 0x6a, 0x69, 0x6e, 0xef, 0xe0, 0x6b, 0x7b, 0x69, 0x70,
+ 0x68, 0xef, 0xe0, 0x21, 0x0a, 0x68, 0x6f, 0xed, 0xce, 0x86, 0xe6, 0x06,
+ 0x08, 0x06, 0x10, 0xc0, 0x88, 0x74, 0x70, 0xae, 0x60, 0x68, 0xc7, 0xc0,
+ 0x56, 0x72, 0x69, 0xf4, 0xe0, 0x36, 0xa7, 0x6f, 0x72, 0x75, 0x6d, 0x2e,
+ 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0xf4, 0xe0, 0x5a, 0x64, 0x61,
+ 0x73, 0x74, 0xae, 0x04, 0xe0, 0x4e, 0x14, 0x73, 0xf0, 0xe0, 0x4c, 0x6f,
+ 0x65, 0x66, 0x66, 0x65, 0xe3, 0xe0, 0x5f, 0x6b, 0xe4, 0x07, 0x06, 0x05,
+ 0x07, 0x06, 0xcb, 0xc5, 0x72, 0x6f, 0xe2, 0xe0, 0x5e, 0xc5, 0x6f, 0x62,
+ 0xe9, 0xdf, 0x1d, 0x69, 0x73, 0x73, 0xe5, 0xe0, 0x4d, 0xb5, 0x64, 0x6e,
+ 0x73, 0xae, 0xcc, 0xd7, 0x61, 0x74, 0x74, 0xef, 0xe0, 0x68, 0x3c, 0xe3,
+ 0x02, 0x87, 0x6c, 0x6f, 0x75, 0x64, 0xae, 0xc7, 0x52, 0xe4, 0xdb, 0x7e,
+ 0xe1, 0x03, 0x06, 0x86, 0x73, 0x75, 0xf3, 0xe0, 0x5d, 0x7d, 0x6d, 0x61,
+ 0xfa, 0xe0, 0x68, 0x0b, 0x63, 0x74, 0x69, 0x76, 0x65, 0x64, 0x69, 0x72,
+ 0x65, 0xe3, 0xd0, 0xe9, 0xae, 0x60, 0x62, 0xd1, 0xc2, 0x3c, 0xad, 0x06,
+ 0x05, 0x06, 0x0a, 0xc6, 0xce, 0x77, 0xe1, 0xe0, 0x42, 0x6d, 0x72, 0x6f,
+ 0xf5, 0xe0, 0x23, 0x0a, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61, 0xf9, 0xe0,
+ 0x48, 0x18, 0x66, 0x69, 0x72, 0x65, 0x77, 0x61, 0xec, 0xde, 0x26, 0xf8,
+ 0x04, 0xe0, 0x6b, 0x3c, 0xae, 0xe0, 0x67, 0x54, 0xf7, 0x60, 0x2e, 0x0d,
+ 0xe0, 0x3d, 0x2a, 0xf5, 0x0d, 0x13, 0x3a, 0x20, 0x06, 0x0c, 0x06, 0x04,
+ 0x52, 0x6a, 0xe0, 0x58, 0x30, 0xf4, 0x02, 0x86, 0x75, 0x61, 0xec, 0xe0,
+ 0x59, 0x0b, 0x73, 0xf5, 0x04, 0xe0, 0x2f, 0xe0, 0xfa, 0xe0, 0x2b, 0x30,
+ 0xf3, 0x04, 0x13, 0x10, 0x8c, 0x69, 0xe3, 0x05, 0x05, 0xe0, 0x6a, 0xff,
+ 0x69, 0xe1, 0xe0, 0x45, 0xdb, 0x61, 0xae, 0x60, 0x58, 0xec, 0xcf, 0x5a,
+ 0x65, 0x75, 0xed, 0x04, 0xe0, 0x6a, 0xf1, 0xae, 0x60, 0x49, 0x38, 0x5a,
+ 0xc2, 0x45, 0x37, 0xab, 0x61, 0x73, 0x68, 0xe9, 0x04, 0xe0, 0x64, 0xda,
+ 0xed, 0xe0, 0x28, 0xac, 0xae, 0x60, 0x62, 0x1c, 0xc7, 0x65, 0xf2, 0x03,
+ 0x0a, 0x84, 0xef, 0x02, 0x84, 0xf4, 0xe0, 0x28, 0x67, 0xf2, 0xcf, 0x32,
+ 0xed, 0xe0, 0x54, 0x58, 0xe1, 0x04, 0x04, 0xd7, 0x73, 0xf4, 0xe0, 0x33,
+ 0x40, 0x6b, 0x61, 0xed, 0xdb, 0x7f, 0x6f, 0xf3, 0x60, 0x58, 0x21, 0x82,
+ 0xee, 0x02, 0x84, 0xe9, 0xe0, 0x23, 0x8b, 0x61, 0xeb, 0xe0, 0x2b, 0x59,
+ 0xeb, 0x59, 0x77, 0xe0, 0x45, 0xf5, 0x69, 0xeb, 0xdc, 0x1d, 0x67, 0xe9,
+ 0xe0, 0x65, 0x23, 0xf4, 0x07, 0x60, 0x69, 0x34, 0x1f, 0xc1, 0x3a, 0xae,
+ 0x60, 0x64, 0x28, 0x03, 0x03, 0x41, 0x5a, 0xc3, 0x02, 0xf3, 0x07, 0x04,
+ 0x60, 0x68, 0x2b, 0xc2, 0x4c, 0xeb, 0xe0, 0x66, 0xd9, 0xae, 0x60, 0x53,
+ 0x86, 0x50, 0x8c, 0x03, 0x41, 0x5d, 0xc3, 0x02, 0xf2, 0x06, 0x60, 0x68,
+ 0xd0, 0xc1, 0x95, 0xe1, 0x02, 0x9a, 0x70, 0x2e, 0x61, 0x63, 0x63, 0x65,
+ 0x73, 0x73, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2e, 0x73, 0x33, 0x2d, 0x67,
+ 0x6c, 0x6f, 0x62, 0x61, 0xec, 0xe0, 0x62, 0x71, 0x67, 0xef, 0xe0, 0x2d,
+ 0x63, 0xf0, 0x60, 0x68, 0xe7, 0xc1, 0x5b, 0xef, 0x19, 0x05, 0x0b, 0x13,
+ 0x24, 0x23, 0x40, 0x4c, 0x11, 0x3f, 0x06, 0x0d, 0x0b, 0x1c, 0x13, 0x20,
+ 0x06, 0x08, 0x60, 0x66, 0x89, 0x40, 0x9d, 0xc1, 0x7c, 0x1f, 0x43, 0xe5,
+ 0xc1, 0x71, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0x2d, 0x69, 0xef, 0xe0, 0x60,
+ 0x57, 0xf6, 0x04, 0xe0, 0x6a, 0x0e, 0xe9, 0x04, 0xe0, 0x68, 0x8d, 0x6d,
+ 0x69, 0x65, 0x6e, 0x74, 0xef, 0xe0, 0x67, 0x4b, 0xf4, 0x02, 0x9c, 0xef,
+ 0x08, 0x07, 0x08, 0x55, 0x8f, 0xe0, 0x54, 0x56, 0x79, 0x61, 0x6d, 0xe1,
+ 0xe0, 0x63, 0xee, 0x72, 0x63, 0x79, 0x63, 0xec, 0xe0, 0x5d, 0xf1, 0xe2,
+ 0xe0, 0x2a, 0xc6, 0x65, 0xe7, 0xe0, 0x23, 0x3a, 0xf3, 0x0b, 0x0d, 0x05,
+ 0x60, 0x31, 0x55, 0x60, 0x25, 0x8b, 0xce, 0x8b, 0xea, 0x02, 0x86, 0x1f,
+ 0x43, 0xf8, 0xe0, 0x5a, 0x4e, 0xef, 0xe0, 0x5a, 0x4a, 0x65, 0xf5, 0xe0,
+ 0x63, 0x9e, 0x63, 0xef, 0xe0, 0x67, 0x4c, 0xf2, 0x06, 0x06, 0x0c, 0x04,
+ 0x26, 0x83, 0x74, 0x67, 0xe1, 0xe0, 0x39, 0x18, 0xef, 0x04, 0xe0, 0x29,
+ 0x1d, 0x74, 0x73, 0x75, 0xeb, 0xe0, 0x23, 0xab, 0xed, 0xe0, 0x62, 0x41,
+ 0xe9, 0x04, 0x10, 0x04, 0x87, 0xf9, 0x02, 0x85, 0x6f, 0x73, 0xe8, 0xd6,
+ 0x61, 0xe1, 0x04, 0xe0, 0x61, 0xf8, 0xed, 0xd0, 0xdc, 0x6f, 0xeb, 0xc1,
+ 0x4f, 0x6d, 0x61, 0x63, 0xe8, 0xe0, 0x5f, 0x1c, 0x67, 0x75, 0xe3, 0xe0,
+ 0x27, 0x1f, 0xe5, 0xc9, 0x42, 0x64, 0x6f, 0xf6, 0xe0, 0x58, 0x8b, 0xef,
+ 0x04, 0xe0, 0x68, 0x6d, 0x6e, 0x73, 0x63, 0x61, 0x6c, 0x65, 0xae, 0x60,
+ 0x5a, 0xf5, 0xce, 0x49, 0xee, 0x09, 0x23, 0x06, 0x07, 0x60, 0x55, 0x80,
+ 0xd2, 0xa6, 0x7a, 0xe1, 0x06, 0x09, 0x0b, 0xe0, 0x67, 0x33, 0xe5, 0x02,
+ 0x91, 0x64, 0x65, 0x6c, 0x6c, 0xe1, 0x8c, 0xad, 0x02, 0x88, 0x65, 0x2d,
+ 0x64, 0x65, 0x6c, 0x6c, 0x61, 0x2d, 0x62, 0x72, 0x69, 0xe1, 0xe0, 0x47,
+ 0x45, 0x67, 0x6f, 0x6c, 0xe9, 0xd8, 0xcd, 0x65, 0xf9, 0x60, 0x5e, 0xa6,
+ 0xca, 0x81, 0x61, 0xf3, 0xe0, 0x66, 0x90, 0xed, 0x60, 0x64, 0x63, 0xc4,
+ 0xb9, 0xec, 0x07, 0x60, 0x31, 0x20, 0xe0, 0x35, 0xec, 0x69, 0xf3, 0xe0,
+ 0x62, 0x05, 0xeb, 0x04, 0xe0, 0x5d, 0x7f, 0x75, 0x72, 0xe5, 0xe0, 0x30,
+ 0x1a, 0xe4, 0x08, 0x09, 0x07, 0x60, 0x4d, 0x45, 0xc4, 0x21, 0xe5, 0x04,
+ 0xe0, 0x60, 0xaa, 0xec, 0xe0, 0x2b, 0x9d, 0xe1, 0x60, 0x2a, 0xc7, 0xe0,
+ 0x3e, 0x25, 0xae, 0xc8, 0x37, 0xe3, 0x02, 0x89, 0x6b, 0x2e, 0x70, 0x73,
+ 0x74, 0xed, 0xe0, 0x43, 0xb3, 0x68, 0x69, 0x7a, 0xf5, 0xe0, 0x5f, 0xda,
+ 0xe2, 0x04, 0xe0, 0x22, 0x2b, 0xe9, 0x06, 0x60, 0x66, 0xd1, 0xc1, 0xf3,
+ 0xae, 0x07, 0x06, 0x60, 0x56, 0x0a, 0xc6, 0xcc, 0xf4, 0x60, 0x66, 0x48,
+ 0xc0, 0xb5, 0xee, 0x60, 0x67, 0x0e, 0xc1, 0xa6, 0x61, 0x72, 0xe5, 0xe0,
+ 0x37, 0x82, 0xae, 0x60, 0x63, 0xa5, 0x40, 0x5c, 0xc2, 0xa6, 0xad, 0x02,
+ 0x89, 0x73, 0x69, 0x65, 0x6d, 0x65, 0xee, 0xe0, 0x4b, 0x76, 0x69, 0x2d,
+ 0x72, 0xe1, 0xe0, 0x5d, 0xc7, 0xee, 0x60, 0x45, 0xd1, 0xe0, 0x22, 0xbd,
+ 0xed, 0x04, 0xe0, 0x57, 0x20, 0xe1, 0x04, 0xe0, 0x68, 0x7e, 0x66, 0x61,
+ 0xee, 0xe0, 0x65, 0x55, 0xec, 0x06, 0x60, 0x66, 0x08, 0xc2, 0x69, 0xe2,
+ 0x60, 0x48, 0x99, 0xdf, 0xd7, 0xeb, 0x47, 0x3a, 0xe0, 0x61, 0x30, 0xea,
+ 0x02, 0x84, 0x1f, 0x43, 0xf8, 0x82, 0x6f, 0x6e, 0xe4, 0xe0, 0x24, 0x33,
+ 0xe9, 0x18, 0x1b, 0x40, 0x56, 0x34, 0x40, 0x43, 0x0e, 0x40, 0xd5, 0x11,
+ 0x40, 0xa1, 0x0d, 0x22, 0x0a, 0x07, 0x0c, 0x19, 0x12, 0x05, 0x10, 0xd2,
+ 0x58, 0x7a, 0xf5, 0x04, 0x07, 0x06, 0x84, 0x73, 0x61, 0x77, 0xe1, 0xe0,
+ 0x31, 0xea, 0x6e, 0x61, 0xed, 0xe0, 0x5f, 0x55, 0x6d, 0xe1, 0xdf, 0x72,
+ 0xe8, 0xe0, 0x62, 0x22, 0xf9, 0x02, 0x93, 0xef, 0x02, 0x84, 0xf4, 0xe0,
+ 0x4c, 0xaf, 0x73, 0x68, 0x69, 0xae, 0x60, 0x5c, 0xc2, 0x40, 0xeb, 0x44,
+ 0xf5, 0xac, 0xe1, 0x09, 0x0d, 0x05, 0x07, 0x08, 0x11, 0xe0, 0x5c, 0x53,
+ 0xfa, 0x03, 0xd0, 0x06, 0x61, 0x6b, 0x69, 0xae, 0x60, 0x59, 0xcd, 0xcc,
+ 0x84, 0x77, 0xe1, 0xe0, 0x20, 0x7a, 0x73, 0x68, 0x69, 0xf2, 0xe0, 0x31,
+ 0x5d, 0x6d, 0x61, 0xae, 0x60, 0x5c, 0x5a, 0xc0, 0x6f, 0xeb, 0x02, 0xa3,
+ 0xef, 0x02, 0x84, 0x6e, 0xef, 0xd1, 0x2b, 0xae, 0x60, 0x31, 0x8e, 0xe0,
+ 0x2a, 0xbc, 0xe4, 0xe0, 0x4c, 0x63, 0xf4, 0x06, 0x15, 0x0b, 0xe0, 0x67,
+ 0xa7, 0x73, 0xf5, 0x03, 0x05, 0x84, 0x6b, 0xe5, 0xe0, 0x63, 0x76, 0xe5,
+ 0xe0, 0x5f, 0x61, 0x62, 0x69, 0x73, 0xe8, 0xe0, 0x65, 0x9c, 0xef, 0x07,
+ 0x60, 0x23, 0xaf, 0xe0, 0x3c, 0x69, 0xf9, 0xc5, 0x53, 0xe1, 0x02, 0x84,
+ 0xee, 0xe0, 0x2c, 0x9a, 0xeb, 0x52, 0x0c, 0xe0, 0x4f, 0x88, 0xf3, 0x04,
+ 0x04, 0x0a, 0x88, 0x75, 0xe7, 0xd0, 0x59, 0x68, 0x69, 0x6d, 0x61, 0xae,
+ 0x60, 0x5d, 0x2b, 0xc4, 0xf6, 0x63, 0x6f, 0x6e, 0x66, 0x75, 0xf3, 0xda,
+ 0x7d, 0xe1, 0x04, 0x05, 0x12, 0x83, 0x77, 0xe1, 0xe0, 0x2c, 0x44, 0x74,
+ 0x6f, 0xae, 0x09, 0x60, 0x2f, 0xed, 0x60, 0x2c, 0xd5, 0xc4, 0x93, 0xf3,
+ 0x60, 0x5d, 0x00, 0xc4, 0xb4, 0xf3, 0xd2, 0x3d, 0x6b, 0x69, 0x2e, 0xef,
+ 0x60, 0x61, 0x9e, 0xc3, 0xeb, 0x72, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0xae,
+ 0x60, 0x49, 0x37, 0x40, 0x64, 0xdd, 0x2c, 0xee, 0x07, 0x10, 0x16, 0x0f,
+ 0x06, 0xc2, 0x1c, 0xf4, 0x05, 0x04, 0xe0, 0x67, 0x37, 0xf3, 0xe0, 0x2e,
+ 0x53, 0x65, 0x72, 0xe5, 0xe0, 0x50, 0x02, 0xef, 0x08, 0x06, 0x04, 0x52,
+ 0xdf, 0xe0, 0x4b, 0x66, 0x6b, 0x61, 0xed, 0xe0, 0x2c, 0x2e, 0xe8, 0xe0,
+ 0x65, 0x4c, 0xe2, 0xce, 0x8a, 0xe9, 0x04, 0xe0, 0x67, 0x16, 0xf3, 0x04,
+ 0xe0, 0x42, 0xec, 0x69, 0x74, 0xe5, 0xca, 0x83, 0x63, 0x6f, 0xed, 0xe0,
+ 0x38, 0xf8, 0xe1, 0x07, 0x08, 0x40, 0x7d, 0xe0, 0x2f, 0xe7, 0x74, 0x6f,
+ 0xae, 0x60, 0x63, 0xb5, 0xc1, 0x72, 0xed, 0x03, 0xc0, 0x74, 0xe9, 0x10,
+ 0x0a, 0x07, 0x05, 0x0a, 0x06, 0x0c, 0x07, 0x05, 0x06, 0x0f, 0x08, 0x4f,
+ 0x24, 0xc4, 0x61, 0x79, 0x61, 0x6d, 0x61, 0x73, 0x68, 0x69, 0xf2, 0xd5,
+ 0xad, 0x75, 0x6f, 0x6e, 0x75, 0xed, 0xd8, 0x53, 0x74, 0xe1, 0xe0, 0x60,
+ 0x81, 0x73, 0x61, 0x6e, 0x72, 0x69, 0x6b, 0xf5, 0xe0, 0x2f, 0x47, 0x6f,
+ 0x67, 0x75, 0xee, 0xcf, 0xff, 0xed, 0x02, 0x85, 0x69, 0x6e, 0xef, 0xd2,
+ 0x76, 0xe1, 0xe0, 0x5d, 0xb9, 0xe9, 0x03, 0xd1, 0x14, 0xf3, 0xde, 0x10,
+ 0x65, 0xe3, 0xe0, 0x3c, 0x25, 0x62, 0x6f, 0xf3, 0xe0, 0x64, 0xc1, 0xe1,
+ 0x04, 0x04, 0xcf, 0x41, 0xf7, 0xe0, 0x58, 0xaa, 0x73, 0x68, 0x69, 0xe7,
+ 0xd9, 0x0f, 0xae, 0x60, 0x58, 0x59, 0x42, 0xa6, 0xc6, 0x1a, 0x2d, 0x61,
+ 0x6c, 0x70, 0xf3, 0xe0, 0x3e, 0x61, 0x61, 0xf4, 0xe0, 0x5f, 0x28, 0x6b,
+ 0x61, 0xed, 0xd8, 0xda, 0xed, 0x02, 0x85, 0x6f, 0xfa, 0xe0, 0x56, 0xbe,
+ 0xe1, 0x04, 0xe0, 0x60, 0xf2, 0xf4, 0xe0, 0x20, 0x6e, 0xec, 0x05, 0x06,
+ 0xe0, 0x66, 0x57, 0x61, 0xee, 0x60, 0x64, 0x57, 0x81, 0xae, 0x20, 0x06,
+ 0x0a, 0x08, 0x06, 0x09, 0x0a, 0x09, 0x09, 0x08, 0x08, 0x06, 0x09, 0x08,
+ 0x60, 0x2b, 0x07, 0x59, 0xeb, 0x3f, 0x40, 0x47, 0x4e, 0x4e, 0x46, 0x47,
+ 0x49, 0x1f, 0x40, 0x5f, 0xc0, 0x47, 0xf6, 0x60, 0x5a, 0x52, 0xca, 0x67,
+ 0xf4, 0x60, 0x63, 0xbc, 0x03, 0x1e, 0x12, 0x40, 0xb5, 0xb2, 0xf3, 0x60,
+ 0x63, 0x95, 0x40, 0x59, 0xc0, 0x79, 0xf2, 0x60, 0x63, 0xad, 0xc1, 0xe8,
+ 0xf0, 0x60, 0x63, 0x87, 0x40, 0x41, 0x18, 0xc0, 0xbb, 0xee, 0x60, 0x63,
+ 0x9b, 0x40, 0x5a, 0x40, 0x8e, 0xc1, 0x8a, 0xed, 0x60, 0x62, 0x48, 0x41,
+ 0x49, 0x3c, 0xc2, 0x36, 0xeb, 0x60, 0x63, 0x88, 0x21, 0x40, 0xf9, 0xc1,
+ 0x58, 0xe9, 0x60, 0x45, 0xaa, 0x5d, 0xfc, 0xc1, 0x12, 0xe7, 0x60, 0x63,
+ 0x5a, 0x40, 0xd2, 0xc0, 0x42, 0xe5, 0x60, 0x59, 0xff, 0xcb, 0xe2, 0xe3,
+ 0x60, 0x63, 0x8d, 0x18, 0x40, 0xac, 0xc0, 0x51, 0xe2, 0x60, 0x63, 0x9c,
+ 0x40, 0x90, 0x1c, 0xb2, 0xe1, 0x60, 0x59, 0xe8, 0x49, 0x70, 0x24, 0x40,
+ 0xd3, 0xa3, 0xeb, 0x04, 0xe0, 0x60, 0xe3, 0xe1, 0x03, 0xc3, 0x88, 0xf3,
+ 0xe0, 0x63, 0xd6, 0xe8, 0x04, 0xe0, 0x55, 0xea, 0xe1, 0x02, 0x8c, 0xf2,
+ 0x04, 0xe0, 0x60, 0x28, 0x61, 0xae, 0x60, 0x5a, 0x52, 0xc5, 0x53, 0x6d,
+ 0x61, 0xae, 0x60, 0x3b, 0x23, 0x5f, 0x5c, 0x40, 0x78, 0x45, 0x5f, 0xc3,
+ 0x6b, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0xee, 0xe0, 0x4e, 0xe0, 0x66,
+ 0x75, 0x6e, 0xe5, 0xe0, 0x5e, 0x32, 0xe5, 0x04, 0xe0, 0x63, 0xd1, 0xec,
+ 0x60, 0x2a, 0xf0, 0xe0, 0x25, 0x3e, 0xe4, 0x05, 0x0a, 0xe0, 0x4f, 0x28,
+ 0x74, 0x72, 0x65, 0x2d, 0x67, 0x61, 0xf5, 0xe0, 0x31, 0xc9, 0x6f, 0x72,
+ 0x69, 0xae, 0x60, 0x5c, 0x97, 0xc6, 0xee, 0x63, 0x72, 0xef, 0x02, 0x86,
+ 0x73, 0x6f, 0xe6, 0xe0, 0x63, 0x97, 0x6c, 0x69, 0x67, 0xe8, 0xe0, 0x60,
+ 0x46, 0x62, 0xf5, 0xe0, 0x59, 0xc4, 0xe1, 0x02, 0x89, 0xf3, 0x04, 0xe0,
+ 0x49, 0xd0, 0xf4, 0xe0, 0x56, 0x59, 0xed, 0xe0, 0x63, 0x20, 0xae, 0x60,
+ 0x3b, 0x19, 0x60, 0x25, 0x18, 0xc3, 0x02, 0xe7, 0x60, 0x3e, 0xc7, 0xe0,
+ 0x26, 0x65, 0xe5, 0x15, 0x17, 0x18, 0x06, 0x1b, 0x2c, 0x27, 0x06, 0x40,
+ 0x62, 0x60, 0x34, 0xc3, 0x5c, 0x3c, 0x49, 0x0d, 0x45, 0xed, 0xc4, 0x0c,
+ 0x73, 0xf3, 0x03, 0x07, 0x84, 0x77, 0x69, 0x74, 0xe8, 0xe0, 0x3c, 0xad,
+ 0xe9, 0xe0, 0x5c, 0xbc, 0x65, 0x72, 0x6c, 0xe9, 0xe0, 0x63, 0x86, 0xf2,
+ 0x05, 0x05, 0x08, 0xd4, 0x6b, 0x1f, 0x43, 0xe5, 0xd4, 0x76, 0x73, 0x65,
+ 0x69, 0x6e, 0xe5, 0xe0, 0x36, 0xc5, 0x63, 0x6b, 0xed, 0xdb, 0x43, 0xee,
+ 0x60, 0x63, 0xe0, 0xc1, 0x00, 0xed, 0x06, 0x05, 0x05, 0xe0, 0x63, 0x4e,
+ 0x73, 0xe5, 0xe0, 0x58, 0x7e, 0x6f, 0xf2, 0xe0, 0x32, 0xa1, 0x62, 0x65,
+ 0x72, 0x73, 0x2e, 0x6c, 0xe9, 0xe0, 0x35, 0xc1, 0xec, 0x0c, 0x05, 0x07,
+ 0x60, 0x57, 0xf1, 0x41, 0x06, 0x43, 0x0d, 0xc1, 0x87, 0x68, 0xf5, 0xe0,
+ 0x60, 0x5e, 0x62, 0x6f, 0x75, 0xf2, 0xe0, 0x4e, 0x8c, 0x2e, 0x63, 0x6c,
+ 0x6f, 0x75, 0x64, 0x6c, 0x65, 0x74, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2e,
+ 0xe1, 0xe0, 0x64, 0x0f, 0xe9, 0x02, 0x88, 0x77, 0x61, 0xae, 0x60, 0x59,
+ 0x6f, 0xc2, 0x54, 0xee, 0x02, 0x87, 0x66, 0x6f, 0x72, 0xf5, 0xe0, 0x4b,
+ 0x6d, 0xad, 0x02, 0x87, 0x76, 0x69, 0x67, 0xef, 0xe0, 0x41, 0x42, 0x69,
+ 0x73, 0x65, 0x72, 0xf6, 0xe0, 0x41, 0x3b, 0x67, 0x75, 0xf2, 0xe0, 0x5e,
+ 0x65, 0xe4, 0x06, 0x31, 0x0a, 0xe0, 0x64, 0x25, 0xe9, 0x03, 0x0e, 0x84,
+ 0xef, 0x02, 0x81, 0x2d, 0x63, 0x61, 0x6d, 0x70, 0x69, 0x64, 0xe1, 0xe0,
+ 0x58, 0xee, 0x63, 0xe9, 0xdb, 0x13, 0xe1, 0x05, 0x0d, 0xe0, 0x64, 0x37,
+ 0x74, 0x65, 0x63, 0x68, 0xae, 0x04, 0xe0, 0x56, 0xa0, 0xe2, 0xe0, 0x52,
+ 0xca, 0xae, 0x60, 0x5f, 0xb1, 0x41, 0xa9, 0xc1, 0xdb, 0x65, 0x63, 0x69,
+ 0x6e, 0xae, 0x60, 0x58, 0x60, 0xcb, 0x39, 0xae, 0x0c, 0x06, 0x07, 0x60,
+ 0x5c, 0x97, 0x40, 0x7e, 0x43, 0x74, 0xc2, 0x28, 0xf3, 0x60, 0x61, 0xcb,
+ 0xc0, 0xa5, 0xf0, 0x60, 0x62, 0x6a, 0x1b, 0xc0, 0xd9, 0xe5, 0x60, 0x58,
+ 0x27, 0xca, 0x67, 0xae, 0x0c, 0x05, 0x06, 0x60, 0x4c, 0x14, 0x44, 0x26,
+ 0x41, 0x07, 0xcc, 0x4e, 0xf5, 0x60, 0x61, 0x8e, 0x83, 0xf4, 0x60, 0x61,
+ 0x7f, 0xc2, 0x64, 0xf3, 0x60, 0x61, 0x83, 0xc0, 0xde, 0xe4, 0x04, 0xe0,
+ 0x63, 0xe2, 0xae, 0x60, 0x58, 0x0a, 0xc6, 0xd3, 0xe3, 0x07, 0x08, 0x07,
+ 0x09, 0xe0, 0x63, 0xbc, 0xf0, 0x04, 0xe0, 0x3f, 0x9f, 0xf2, 0xc1, 0x47,
+ 0x6b, 0x69, 0x6e, 0xf3, 0xe0, 0x57, 0x4e, 0x64, 0x69, 0x72, 0xae, 0x60,
+ 0x4d, 0xbd, 0xd5, 0x7b, 0xae, 0x60, 0x52, 0x4e, 0x4b, 0x0f, 0xc4, 0x5c,
+ 0xe2, 0x04, 0xe0, 0x62, 0x08, 0xae, 0x60, 0x61, 0xac, 0xc0, 0x5a, 0xe1,
+ 0x16, 0x15, 0x0c, 0x40, 0x7a, 0x2f, 0x40, 0x4a, 0x12, 0x04, 0x31, 0x0a,
+ 0x24, 0x16, 0x2c, 0x1a, 0x07, 0x05, 0x19, 0xe0, 0x61, 0x88, 0xfa, 0x03,
+ 0x05, 0x87, 0x75, 0xf2, 0xe0, 0x51, 0x8c, 0x6f, 0x77, 0x73, 0xfa, 0xe0,
+ 0x28, 0x1c, 0x65, 0xf0, 0xe0, 0x3f, 0x24, 0x79, 0x66, 0x69, 0x72, 0x73,
+ 0x74, 0xae, 0x60, 0x53, 0x45, 0xcd, 0x62, 0xf4, 0x08, 0x0f, 0x40, 0x58,
+ 0x06, 0xe0, 0x61, 0xa0, 0xf4, 0x04, 0xe0, 0x5e, 0x31, 0x61, 0x2d, 0x76,
+ 0x61, 0x72, 0x6a, 0xea, 0xe0, 0x50, 0xcb, 0x73, 0xf5, 0x0a, 0x06, 0x04,
+ 0x05, 0x12, 0x03, 0x10, 0x03, 0x04, 0x86, 0x7a, 0x61, 0xeb, 0xe0, 0x58,
+ 0xe7, 0x79, 0xe1, 0xd0, 0x30, 0x75, 0xf2, 0xe0, 0x47, 0xe7, 0xf3, 0x02,
+ 0x8b, 0x68, 0xe9, 0x04, 0xe0, 0x21, 0x14, 0x67, 0xe5, 0xe0, 0x5d, 0xbe,
+ 0x61, 0xeb, 0xd0, 0x44, 0xee, 0xd4, 0x1b, 0xed, 0x02, 0x89, 0x6f, 0x74,
+ 0x6f, 0xae, 0x60, 0x5c, 0xd8, 0xc3, 0x37, 0xe1, 0xe0, 0x47, 0x4b, 0xeb,
+ 0xce, 0xd8, 0xe5, 0xe0, 0x5d, 0x5f, 0xe4, 0x60, 0x5e, 0x4d, 0xc2, 0xe5,
+ 0xe2, 0x02, 0x84, 0x75, 0xf3, 0xcd, 0xeb, 0xe1, 0xe0, 0x2c, 0x94, 0x72,
+ 0x69, 0xf8, 0xe0, 0x62, 0x03, 0xe5, 0xe0, 0x3d, 0xad, 0xf3, 0x08, 0x04,
+ 0x0d, 0x0a, 0x07, 0xe0, 0x57, 0x1c, 0xf5, 0xe0, 0x23, 0x58, 0x73, 0xe1,
+ 0x02, 0x81, 0x2d, 0x63, 0x61, 0x72, 0x72, 0xe1, 0xe0, 0x3d, 0x93, 0x68,
+ 0x69, 0xeb, 0x4c, 0x1c, 0x60, 0x3a, 0xed, 0xca, 0xc9, 0x66, 0x6a, 0x6f,
+ 0xf2, 0xe0, 0x23, 0x5a, 0x61, 0xeb, 0xde, 0x29, 0xf2, 0x0a, 0x0f, 0x07,
+ 0x05, 0x05, 0x0e, 0x0c, 0xe0, 0x60, 0x80, 0xf5, 0x02, 0x85, 0x6d, 0x6f,
+ 0xf2, 0xd4, 0xf8, 0x67, 0x61, 0x6d, 0xe5, 0xe0, 0x54, 0x76, 0x73, 0x68,
+ 0x61, 0xec, 0xe0, 0x4f, 0x96, 0x72, 0xe9, 0xe0, 0x60, 0xe5, 0x6e, 0xe1,
+ 0xe0, 0x34, 0xac, 0x6b, 0xe5, 0x04, 0xe0, 0x56, 0xef, 0xf4, 0x60, 0x4d,
+ 0x14, 0x53, 0x19, 0xc2, 0x69, 0x69, 0xee, 0x02, 0x84, 0xe7, 0xe0, 0x59,
+ 0x0e, 0xe5, 0xe0, 0x61, 0xfc, 0x63, 0xe8, 0xe0, 0x5b, 0x79, 0xf0, 0x04,
+ 0xe0, 0x62, 0x79, 0x2e, 0x66, 0x61, 0x73, 0x74, 0x6c, 0xf9, 0x60, 0x31,
+ 0x6e, 0xe0, 0x30, 0xe0, 0x6f, 0xf2, 0xd3, 0x61, 0xee, 0x0b, 0x05, 0x05,
+ 0x0d, 0x60, 0x5b, 0x29, 0x41, 0x59, 0xc5, 0xc3, 0x74, 0xef, 0xe0, 0x29,
+ 0x51, 0x6e, 0xef, 0xe0, 0x54, 0x1a, 0xe7, 0x04, 0xe0, 0x60, 0xc2, 0x79,
+ 0x73, 0x68, 0x6c, 0xe1, 0xe0, 0x5c, 0x0b, 0xe1, 0x02, 0x84, 0xf5, 0xe0,
+ 0x49, 0xde, 0x67, 0x65, 0x6d, 0xe5, 0xe0, 0x3b, 0x40, 0x6d, 0x75, 0x72,
+ 0x6f, 0x67, 0x61, 0xf7, 0xe0, 0x2a, 0xfa, 0xec, 0x07, 0x07, 0x08, 0x03,
+ 0xe0, 0x29, 0xaa, 0x73, 0x65, 0x6c, 0xf6, 0xe0, 0x60, 0x8c, 0x6f, 0x70,
+ 0x6f, 0x6c, 0xf3, 0xe0, 0x3a, 0xa9, 0xe2, 0xc4, 0x76, 0x61, 0x74, 0x76,
+ 0x75, 0x6f, 0x70, 0xed, 0xe0, 0x5a, 0x73, 0xeb, 0x03, 0x07, 0x87, 0x75,
+ 0x72, 0x61, 0x7a, 0xe1, 0xdf, 0x12, 0x69, 0x6e, 0x6f, 0xe8, 0xe0, 0x22,
+ 0xc3, 0xe5, 0xe0, 0x29, 0xc9, 0xe9, 0x0a, 0x05, 0x0b, 0x0c, 0x60, 0x33,
+ 0x78, 0xe0, 0x23, 0x6b, 0x7a, 0x75, 0xf2, 0xc9, 0xeb, 0xee, 0x04, 0xe0,
+ 0x60, 0xe3, 0x74, 0x65, 0xee, 0xe0, 0x5c, 0xf6, 0xec, 0x04, 0xe0, 0x5d,
+ 0x18, 0x2d, 0x62, 0x6f, 0xf8, 0xe0, 0x28, 0xe8, 0x62, 0x61, 0xf2, 0xc9,
+ 0x1c, 0xe7, 0x03, 0x06, 0x8b, 0x6e, 0x65, 0xf4, 0xe0, 0x42, 0x09, 0x65,
+ 0x6e, 0x74, 0x6f, 0x73, 0x69, 0x74, 0xe5, 0xe0, 0x51, 0xe2, 0x61, 0xfa,
+ 0xe0, 0x5c, 0x86, 0x65, 0x62, 0x61, 0x73, 0xe8, 0xd4, 0x0c, 0x64, 0xf2,
+ 0xe0, 0x59, 0x0a, 0xe3, 0x03, 0x06, 0x8b, 0x68, 0x69, 0xe4, 0xe0, 0x5b,
+ 0x8f, 0xe5, 0x02, 0x84, 0xf2, 0xe0, 0x50, 0x9f, 0xe9, 0xe0, 0x55, 0x23,
+ 0xe1, 0xe0, 0x2e, 0x69, 0xae, 0x60, 0x5b, 0x23, 0x03, 0xc1, 0x5d, 0xec,
+ 0x20, 0x17, 0x12, 0x0d, 0x40, 0x5e, 0x35, 0x15, 0x41, 0x1b, 0x04, 0x06,
+ 0x09, 0x41, 0x1a, 0x0d, 0x40, 0xb1, 0x1c, 0x40, 0xea, 0x60, 0x32, 0x70,
+ 0x51, 0x21, 0x4e, 0x8c, 0x47, 0xf0, 0xc1, 0x10, 0x1f, 0xc3, 0x03, 0x0b,
+ 0x84, 0xf8, 0x05, 0x41, 0x07, 0xdb, 0x5f, 0x64, 0xe9, 0xe0, 0x51, 0xd5,
+ 0xe6, 0xe0, 0x33, 0x5b, 0xe1, 0xc4, 0xac, 0xf9, 0x04, 0xe0, 0x61, 0x44,
+ 0xee, 0x02, 0x84, 0xf8, 0xe0, 0x48, 0x79, 0xe7, 0x60, 0x51, 0xc0, 0xc8,
+ 0x60, 0xf6, 0x06, 0x60, 0x46, 0x1b, 0xdb, 0x15, 0xae, 0x60, 0x46, 0x28,
+ 0xd4, 0xa9, 0xf5, 0x12, 0x09, 0x11, 0x04, 0x02, 0x0f, 0x0b, 0x4f, 0xdd,
+ 0x60, 0x29, 0x0c, 0x55, 0xa5, 0x44, 0x87, 0xcd, 0xc8, 0xf8, 0x04, 0xe0,
+ 0x5f, 0x96, 0xf5, 0xe0, 0x3f, 0x0d, 0xee, 0x02, 0x84, 0xee, 0xe0, 0x55,
+ 0x61, 0xe4, 0x04, 0xe0, 0x5f, 0x6d, 0x62, 0xe5, 0xe0, 0x34, 0x37, 0xeb,
+ 0xe0, 0x54, 0x51, 0xe8, 0x8b, 0xe7, 0x05, 0x04, 0xe0, 0x5c, 0xdb, 0xf3,
+ 0xe0, 0x5c, 0xde, 0x61, 0xee, 0xe0, 0x39, 0x71, 0xe3, 0x02, 0x84, 0xe3,
+ 0xe0, 0x5a, 0x55, 0xe1, 0xe0, 0x48, 0x98, 0xe2, 0x05, 0x06, 0xe0, 0x4f,
+ 0x34, 0x6c, 0x69, 0xee, 0xe0, 0x4f, 0x32, 0x61, 0x72, 0xf4, 0xc6, 0xb6,
+ 0xf4, 0x05, 0x27, 0xe0, 0x60, 0x9f, 0xe4, 0x06, 0x60, 0x5f, 0x18, 0xc1,
+ 0xa7, 0xae, 0x0a, 0x06, 0x04, 0x57, 0xd3, 0x60, 0x34, 0xc8, 0xc8, 0x3d,
+ 0xf5, 0x60, 0x50, 0x68, 0xcd, 0xe5, 0xe7, 0xe0, 0x5e, 0x94, 0xe3, 0x04,
+ 0xe0, 0x5e, 0x6e, 0x6f, 0x2e, 0xe9, 0xe0, 0x5e, 0x50, 0xae, 0x60, 0x45,
+ 0x97, 0x54, 0xa9, 0xc4, 0x5c, 0xf0, 0x06, 0x43, 0x0d, 0xe0, 0x53, 0x69,
+ 0xec, 0x04, 0xe0, 0x60, 0x8b, 0x66, 0x69, 0x6e, 0x61, 0x6e, 0xe3, 0xe0,
+ 0x2e, 0x59, 0xef, 0x12, 0x05, 0x0d, 0x0a, 0x05, 0x07, 0x05, 0x2e, 0x17,
+ 0x1c, 0x07, 0x07, 0x3b, 0x07, 0x20, 0xe0, 0x5d, 0x6e, 0x77, 0xe9, 0xe0,
+ 0x49, 0x44, 0x76, 0xe5, 0x06, 0x60, 0x47, 0xde, 0xd8, 0x84, 0x73, 0xe9,
+ 0xe0, 0x39, 0xbd, 0xf4, 0x04, 0xe0, 0x50, 0xdc, 0xf4, 0x60, 0x5e, 0xcc,
+ 0x8f, 0x73, 0xe5, 0xe0, 0x39, 0x0a, 0x72, 0x65, 0x6e, 0xf3, 0xe0, 0x33,
+ 0xe7, 0x70, 0xf0, 0xe0, 0x5a, 0x1d, 0xee, 0x05, 0x04, 0x1b, 0xd0, 0x1f,
+ 0xe7, 0xe0, 0x51, 0x36, 0xe4, 0x02, 0x86, 0x72, 0x69, 0xee, 0xe0, 0x56,
+ 0xb6, 0x6f, 0xee, 0x04, 0xe0, 0x60, 0x29, 0x2e, 0x63, 0x6c, 0x6f, 0x75,
+ 0x64, 0x61, 0x70, 0xf0, 0xe0, 0x42, 0x58, 0xad, 0x04, 0xe0, 0x2b, 0xba,
+ 0xb2, 0xe0, 0x2b, 0xba, 0xed, 0x07, 0x09, 0x60, 0x47, 0x50, 0xc6, 0x50,
+ 0x62, 0x61, 0x72, 0xe4, 0x60, 0x56, 0xfd, 0xc2, 0x7b, 0xae, 0x60, 0x5e,
+ 0x00, 0xc0, 0x6e, 0xec, 0x04, 0xe0, 0x5f, 0xf8, 0xe9, 0x02, 0x88, 0x74,
+ 0x61, 0x70, 0x75, 0xee, 0xe0, 0x50, 0xfd, 0x70, 0x6f, 0xf0, 0x04, 0xe0,
+ 0x5e, 0xde, 0x6d, 0xe3, 0xe0, 0x5e, 0xe9, 0x69, 0x73, 0x69, 0xf2, 0xe0,
+ 0x55, 0x5b, 0x68, 0x6d, 0x75, 0xf3, 0xe0, 0x49, 0xd1, 0xe7, 0x05, 0x09,
+ 0xe0, 0x5e, 0x69, 0x6f, 0x69, 0x70, 0xae, 0x60, 0x5f, 0x29, 0xc0, 0x99,
+ 0xe9, 0x02, 0x87, 0x73, 0x74, 0x69, 0xe3, 0xe0, 0x5b, 0x59, 0xee, 0x02,
+ 0x85, 0x74, 0xef, 0xe0, 0x49, 0xb0, 0x6c, 0x69, 0x6e, 0x65, 0xae, 0x08,
+ 0x60, 0x52, 0x0a, 0x4c, 0x26, 0xc0, 0x6e, 0xf3, 0x04, 0xe0, 0x4f, 0x1d,
+ 0x65, 0x72, 0x76, 0x69, 0xe3, 0xe0, 0x5f, 0x2b, 0x64, 0xe9, 0x60, 0x50,
+ 0x18, 0xcd, 0x7b, 0xe3, 0x05, 0x04, 0xe0, 0x5a, 0x83, 0xeb, 0xe0, 0x4b,
+ 0xea, 0x61, 0xec, 0x02, 0x87, 0x7a, 0x6f, 0x6e, 0xe5, 0xe0, 0x3d, 0x43,
+ 0x68, 0x6f, 0x73, 0x74, 0x2e, 0x64, 0x61, 0xf0, 0xe0, 0x3b, 0x42, 0xe1,
+ 0x04, 0xe0, 0x3d, 0x5f, 0xe2, 0x60, 0x4c, 0xd8, 0x82, 0xee, 0xe0, 0x4b,
+ 0xf7, 0xec, 0x60, 0x53, 0x7f, 0xca, 0x46, 0xeb, 0x04, 0xe0, 0x5f, 0x58,
+ 0xb3, 0xe0, 0x5e, 0xcd, 0xe9, 0x11, 0x0c, 0x0a, 0x05, 0x3c, 0x2b, 0x12,
+ 0x14, 0x0f, 0x17, 0x07, 0x04, 0x60, 0x5c, 0x66, 0xc2, 0x03, 0xf6, 0x06,
+ 0x60, 0x49, 0xb9, 0xd4, 0x06, 0x6f, 0xf2, 0xe0, 0x53, 0xd6, 0x74, 0x74,
+ 0x6c, 0x65, 0x73, 0x74, 0xe1, 0xe0, 0x4c, 0x39, 0x70, 0xf3, 0xe0, 0x5c,
+ 0xf3, 0xee, 0x04, 0x0c, 0x16, 0x91, 0x6f, 0x64, 0x65, 0x6f, 0x62, 0x6a,
+ 0x65, 0x63, 0xf4, 0xe0, 0x55, 0xea, 0xeb, 0x04, 0xe0, 0x5f, 0x11, 0x79,
+ 0x61, 0x72, 0xe4, 0x04, 0xe0, 0x47, 0x29, 0x2d, 0x63, 0x6c, 0x6f, 0x75,
+ 0xe4, 0xe0, 0x58, 0x41, 0xe4, 0x03, 0x05, 0x84, 0x1f, 0xc3, 0xe0, 0x5a,
+ 0xa6, 0xe5, 0xe0, 0x2a, 0xc4, 0xe1, 0xe0, 0x5a, 0x9f, 0x63, 0xef, 0xc6,
+ 0x5f, 0xed, 0x05, 0x05, 0xe0, 0x5d, 0x55, 0x69, 0xf4, 0xe0, 0x40, 0x87,
+ 0xe1, 0x03, 0x05, 0x84, 0x6e, 0xef, 0xe0, 0x4c, 0x58, 0xae, 0xe0, 0x41,
+ 0x2b, 0x2d, 0x63, 0x69, 0x74, 0x79, 0xae, 0x06, 0x60, 0x5e, 0x19, 0x0e,
+ 0x82, 0x72, 0x6f, 0x63, 0xeb, 0xe0, 0x5e, 0x54, 0x6c, 0xec, 0x04, 0xe0,
+ 0x5c, 0x83, 0xe5, 0x02, 0x84, 0xf3, 0xe0, 0x52, 0x00, 0x68, 0x61, 0xed,
+ 0xdf, 0xc9, 0x6b, 0xe5, 0x04, 0xe0, 0x5e, 0xa8, 0xf3, 0x02, 0x87, 0x63,
+ 0x61, 0x6e, 0xe4, 0xe0, 0x41, 0x0f, 0x2d, 0xf0, 0xd2, 0x3b, 0xe7, 0x05,
+ 0x04, 0xe0, 0x5c, 0x8d, 0xf5, 0xe0, 0x58, 0x02, 0x68, 0xf4, 0xe0, 0x49,
+ 0x0c, 0x66, 0xe5, 0x05, 0x06, 0xe0, 0x5e, 0x7e, 0x73, 0x74, 0xf9, 0xe0,
+ 0x5c, 0x8e, 0x69, 0x6e, 0x73, 0x75, 0x72, 0x61, 0xee, 0xe0, 0x59, 0x68,
+ 0x65, 0xf2, 0x60, 0x48, 0x00, 0xd4, 0xdd, 0xe4, 0xe0, 0x5c, 0x1d, 0x62,
+ 0xae, 0x18, 0x0b, 0x04, 0x4c, 0x43, 0x13, 0x60, 0x37, 0xd8, 0x0b, 0x07,
+ 0x04, 0x03, 0x04, 0x1c, 0x0a, 0x02, 0x06, 0x10, 0x06, 0x0b, 0x0d, 0xd4,
+ 0xbb, 0xee, 0x60, 0x44, 0x69, 0x03, 0x03, 0x03, 0x12, 0x0b, 0x13, 0x83,
+ 0xe8, 0xe0, 0x55, 0x85, 0xe4, 0x41, 0x74, 0xe0, 0x43, 0x22, 0xe7, 0x02,
+ 0x84, 0xe2, 0xe0, 0x5c, 0x78, 0xae, 0x60, 0x43, 0x2b, 0xd9, 0x5c, 0xe5,
+ 0x13, 0x07, 0x04, 0x04, 0x04, 0x0a, 0x0a, 0x09, 0x16, 0x0f, 0x06, 0x15,
+ 0x15, 0x60, 0x2f, 0xa0, 0xe0, 0x2b, 0xf1, 0x7a, 0x61, 0x6a, 0xf3, 0xe0,
+ 0x4b, 0xab, 0xf8, 0xe0, 0x59, 0x0d, 0xf6, 0xe0, 0x47, 0xfa, 0xf3, 0xe0,
+ 0x4e, 0xc8, 0xee, 0x04, 0xe0, 0x25, 0x98, 0x75, 0xe7, 0xe0, 0x5c, 0x15,
+ 0xec, 0x04, 0xe0, 0x5c, 0x9c, 0x75, 0xf8, 0xe0, 0x46, 0xc3, 0xeb, 0x04,
+ 0xe0, 0x57, 0xc5, 0xf3, 0xe0, 0x25, 0x83, 0xe9, 0x03, 0x07, 0x87, 0x74,
+ 0x75, 0x6e, 0x67, 0xf3, 0xdf, 0x46, 0xf2, 0x60, 0x25, 0x74, 0xe0, 0x28,
+ 0xc3, 0xeb, 0xe0, 0x47, 0xc3, 0xe7, 0x08, 0x60, 0x38, 0x20, 0x60, 0x24,
+ 0x1f, 0xb0, 0x6e, 0x69, 0xe3, 0xe0, 0x4e, 0xe3, 0x66, 0x72, 0xe1, 0xe0,
+ 0x5b, 0x5b, 0xe3, 0x03, 0x05, 0x86, 0x7a, 0xee, 0xe0, 0x24, 0xf1, 0x6c,
+ 0x65, 0xf2, 0xe0, 0x51, 0xcf, 0xe3, 0x60, 0x56, 0xa6, 0xc5, 0x04, 0xe2,
+ 0x03, 0x06, 0x85, 0x74, 0x69, 0xed, 0xe0, 0x27, 0x49, 0x6f, 0xf2, 0xe0,
+ 0x4b, 0x33, 0x65, 0x73, 0xe2, 0xe0, 0x55, 0x39, 0xe1, 0x05, 0x06, 0x03,
+ 0xde, 0xf3, 0xf3, 0x60, 0x4e, 0x09, 0xce, 0x08, 0xee, 0xde, 0xf8, 0x64,
+ 0x70, 0x61, 0x67, 0x65, 0xf3, 0xe0, 0x44, 0x7c, 0xe3, 0x07, 0x07, 0x60,
+ 0x5b, 0x6a, 0xc2, 0x03, 0x75, 0x62, 0x65, 0xad, 0xe0, 0x34, 0x53, 0xec,
+ 0x04, 0xe0, 0x24, 0xdc, 0x73, 0x74, 0x61, 0x67, 0xe5, 0xe0, 0x24, 0xd7,
+ 0xe1, 0x18, 0x06, 0x10, 0x0b, 0x12, 0x08, 0x07, 0x05, 0x04, 0x05, 0x39,
+ 0x13, 0x06, 0x06, 0x06, 0x06, 0x07, 0x04, 0x0b, 0x60, 0x56, 0xd8, 0xc5,
+ 0xa5, 0xfa, 0x60, 0x44, 0xf8, 0xd6, 0x4b, 0xf7, 0x05, 0x04, 0xe0, 0x5d,
+ 0x37, 0xf9, 0xe0, 0x49, 0x9a, 0xae, 0x60, 0x58, 0xc4, 0xc2, 0xe5, 0x76,
+ 0xe1, 0x04, 0xe0, 0x4d, 0xad, 0x67, 0xe9, 0xe0, 0x58, 0xd6, 0xf4, 0x05,
+ 0x05, 0xe0, 0x5d, 0x1b, 0x72, 0xef, 0xe0, 0x5a, 0xea, 0x69, 0xee, 0x60,
+ 0x56, 0x8a, 0xc5, 0x04, 0xf3, 0x03, 0xc0, 0x95, 0xe1, 0xe0, 0x52, 0xd0,
+ 0xf2, 0x60, 0x24, 0xa2, 0xe0, 0x31, 0x4d, 0x71, 0xf5, 0xe0, 0x52, 0xbd,
+ 0xf0, 0xe0, 0x4a, 0xff, 0x6f, 0xe3, 0xe0, 0x35, 0x01, 0xee, 0x05, 0x04,
+ 0x0a, 0x1c, 0x85, 0xf8, 0xe0, 0x55, 0x83, 0xe7, 0x04, 0xe0, 0x4a, 0xf2,
+ 0x73, 0xef, 0xe0, 0x4d, 0xe2, 0xe4, 0x06, 0x05, 0x06, 0xe0, 0x5c, 0xd1,
+ 0x72, 0xef, 0xe0, 0x35, 0xc7, 0x69, 0x6e, 0x67, 0xae, 0xd7, 0xb9, 0x2d,
+ 0x34, 0x2d, 0x73, 0x61, 0x6c, 0xe5, 0xe0, 0x21, 0xa8, 0x63, 0xe1, 0xe0,
+ 0x49, 0x23, 0x62, 0xe9, 0xc3, 0xda, 0xed, 0x05, 0x04, 0xe0, 0x49, 0x14,
+ 0xe4, 0xe0, 0x4a, 0x03, 0x62, 0x6f, 0x72, 0x67, 0x68, 0xe9, 0xe0, 0x40,
+ 0x37, 0x6b, 0x61, 0xf3, 0xe0, 0x5b, 0xa6, 0x69, 0x63, 0xe8, 0xe0, 0x4c,
+ 0x98, 0x68, 0x70, 0xf0, 0xe0, 0x55, 0x03, 0x64, 0x65, 0xf3, 0xe0, 0x58,
+ 0xa2, 0x63, 0x61, 0x69, 0xf8, 0xe0, 0x5a, 0xe8, 0x62, 0xae, 0xc4, 0x4d,
+ 0x61, 0x6b, 0x65, 0x73, 0x76, 0x75, 0x65, 0xed, 0xe0, 0x58, 0xc9, 0x2d,
+ 0x73, 0x70, 0xe5, 0xe0, 0x21, 0x15, 0x2d, 0x6f, 0x2d, 0x67, 0x2d, 0x69,
+ 0xad, 0xe0, 0x33, 0x7f, 0xeb, 0x23, 0x12, 0x3a, 0x0a, 0x36, 0x41, 0x34,
+ 0x09, 0x04, 0x40, 0x81, 0x0d, 0x41, 0x86, 0x2e, 0x0c, 0x1b, 0x41, 0x91,
+ 0x40, 0x48, 0x06, 0x04, 0x40, 0x4d, 0x05, 0x43, 0xb0, 0x18, 0x60, 0x28,
+ 0x0f, 0xe0, 0x27, 0x93, 0x1f, 0xc3, 0x04, 0xe0, 0x29, 0x4e, 0x61, 0x72,
+ 0x1f, 0x43, 0x61, 0x1f, 0x45, 0x61, 0x6a, 0xef, 0xc8, 0x38, 0xf9, 0x09,
+ 0x07, 0x60, 0x41, 0x10, 0x55, 0x70, 0xc5, 0xa5, 0x75, 0x72, 0x61, 0xe7,
+ 0xe0, 0x25, 0x37, 0xef, 0x05, 0x08, 0xe0, 0x40, 0x15, 0x77, 0x61, 0xae,
+ 0x60, 0x56, 0x08, 0xc4, 0x60, 0xf4, 0x02, 0x86, 0xef, 0x60, 0x5a, 0x67,
+ 0xc1, 0xac, 0xe1, 0x02, 0x8a, 0xee, 0x02, 0x83, 0xe7, 0xca, 0xdb, 0xe1,
+ 0xe0, 0x4d, 0xcd, 0x6d, 0xe2, 0xe0, 0x25, 0x1b, 0xf7, 0x04, 0xe0, 0x5b,
+ 0xf7, 0xf0, 0x43, 0xc5, 0xdb, 0x07, 0xf6, 0x06, 0x07, 0x18, 0xe0, 0x40,
+ 0xc4, 0x1f, 0x43, 0xe6, 0x24, 0xe0, 0x4c, 0x1e, 0xe9, 0x02, 0x8d, 0xf4,
+ 0x02, 0x86, 0xf3, 0x60, 0x50, 0x2d, 0xc3, 0x0d, 0x65, 0xf3, 0xdb, 0x9c,
+ 0xee, 0x04, 0xe0, 0x23, 0xeb, 0xee, 0xc1, 0x85, 0xe1, 0x07, 0x04, 0x60,
+ 0x4c, 0x1a, 0xc3, 0xfa, 0xee, 0xe0, 0x4c, 0x44, 0xec, 0xe0, 0x45, 0x81,
+ 0xf5, 0x12, 0x05, 0x05, 0x0b, 0x24, 0x40, 0x4a, 0x08, 0x2f, 0x3a, 0x09,
+ 0x0e, 0x0d, 0x4b, 0x9b, 0xe0, 0x43, 0xa0, 0x7a, 0x75, 0xed, 0xdb, 0xc9,
+ 0x77, 0x61, 0xee, 0xc8, 0xb7, 0xf4, 0x04, 0xe0, 0x21, 0x0e, 0x63, 0x68,
+ 0xe1, 0xe0, 0x2c, 0xfd, 0xf3, 0x06, 0x08, 0x0b, 0xe0, 0x49, 0x9c, 0x74,
+ 0x61, 0x6e, 0x61, 0xe9, 0xe0, 0x57, 0xe7, 0x68, 0xe9, 0x04, 0xe0, 0x4f,
+ 0xe2, 0xed, 0x55, 0x86, 0xc5, 0x97, 0x61, 0x74, 0x73, 0x75, 0xae, 0x60,
+ 0x52, 0xaa, 0xc3, 0x7a, 0xf2, 0x06, 0x03, 0x23, 0x06, 0x04, 0x84, 0x75,
+ 0xed, 0xb6, 0xef, 0x07, 0x03, 0x07, 0x09, 0x03, 0xdb, 0xcf, 0xf4, 0xc7,
+ 0x9c, 0x6d, 0x61, 0x74, 0x73, 0xf5, 0xd6, 0x76, 0x69, 0xf3, 0x04, 0xe0,
+ 0x4a, 0x46, 0xe8, 0xda, 0xf3, 0xe7, 0xd2, 0x93, 0x62, 0xe5, 0xe0, 0x24,
+ 0x47, 0x69, 0x79, 0xe1, 0xe0, 0x4e, 0xcd, 0xe7, 0xe0, 0x4c, 0xef, 0xe5,
+ 0xe0, 0x4f, 0xe3, 0xe1, 0x02, 0x85, 0x74, 0xe5, 0xe0, 0x44, 0x1d, 0x73,
+ 0x68, 0x69, 0xeb, 0xe0, 0x4f, 0xe0, 0x6f, 0x6b, 0x67, 0x72, 0xef, 0xe0,
+ 0x22, 0xf4, 0xee, 0x04, 0x03, 0x07, 0x99, 0xef, 0xd4, 0x5a, 0x6e, 0x65,
+ 0x70, 0xf0, 0xe0, 0x56, 0x5d, 0xe9, 0x04, 0x08, 0x05, 0x84, 0xf4, 0x04,
+ 0xe0, 0x57, 0xba, 0xef, 0xc5, 0xad, 0x73, 0x61, 0xeb, 0xd8, 0x54, 0xed,
+ 0xe0, 0x4b, 0x3a, 0xe7, 0xdc, 0xc3, 0x64, 0x65, 0x6e, 0xae, 0xe0, 0x2b,
+ 0x2f, 0xed, 0x03, 0x04, 0x8e, 0xe9, 0xe0, 0x24, 0x03, 0xe5, 0x02, 0x85,
+ 0x6e, 0xe1, 0xe0, 0x47, 0x90, 0x6a, 0x69, 0xed, 0xe0, 0x21, 0x45, 0xe1,
+ 0x06, 0x05, 0x07, 0x0a, 0xda, 0x37, 0x74, 0x6f, 0xf2, 0xd8, 0x76, 0x6e,
+ 0x6f, 0xae, 0x60, 0x4f, 0x76, 0xb5, 0x6d, 0x6f, 0x74, 0x6f, 0xae, 0x60,
+ 0x53, 0x6f, 0xc5, 0xa7, 0x6b, 0x6f, 0x67, 0xe5, 0xe0, 0x55, 0xe8, 0x6c,
+ 0x65, 0x75, 0x76, 0x65, 0xee, 0xe0, 0x42, 0xcf, 0xea, 0x04, 0xe0, 0x24,
+ 0x5b, 0xf5, 0x04, 0xe0, 0x48, 0xc5, 0x6b, 0xf5, 0xc5, 0xd5, 0xe4, 0x02,
+ 0x83, 0xef, 0xc2, 0xd6, 0x61, 0x6d, 0x61, 0x74, 0xf3, 0xd6, 0x98, 0x63,
+ 0x68, 0x69, 0x6e, 0x6f, 0xf4, 0xe0, 0x22, 0xe7, 0x74, 0x69, 0x73, 0x74,
+ 0x6f, 0xf2, 0xe0, 0x3c, 0xf0, 0x73, 0xae, 0xd1, 0xfb, 0xf2, 0x0c, 0x09,
+ 0x05, 0x1d, 0x0c, 0x0a, 0x29, 0x60, 0x57, 0xb8, 0xc2, 0x4c, 0x1f, 0xc3,
+ 0x02, 0x82, 0xf8, 0x9e, 0xe5, 0xc0, 0x5c, 0x79, 0xed, 0xe0, 0x3f, 0x5b,
+ 0xef, 0x03, 0x06, 0x8b, 0x70, 0x79, 0x76, 0xee, 0xc3, 0xee, 0x6b, 0x73,
+ 0x74, 0x61, 0x64, 0x65, 0x6c, 0xf6, 0xe0, 0x54, 0x26, 0x64, 0x73, 0x68,
+ 0x65, 0xf2, 0xe0, 0x27, 0x6f, 0x69, 0x73, 0x74, 0x69, 0x61, 0x6e, 0xf3,
+ 0x60, 0x4d, 0x86, 0xc6, 0x1d, 0xe5, 0x04, 0xe0, 0x57, 0xe6, 0x6c, 0xec,
+ 0xe0, 0x35, 0x1d, 0xe1, 0x04, 0x0f, 0x06, 0x88, 0x73, 0xee, 0x02, 0x87,
+ 0x6f, 0x64, 0x61, 0xf2, 0xe0, 0x58, 0x36, 0xe9, 0xe0, 0x21, 0x60, 0x6b,
+ 0x6f, 0xf7, 0xe0, 0x48, 0x74, 0x67, 0x65, 0xf2, 0x60, 0x44, 0xe9, 0xcc,
+ 0xdb, 0x61, 0x6e, 0x67, 0xe8, 0xe0, 0x28, 0xdc, 0xae, 0x60, 0x3e, 0xfc,
+ 0x54, 0xa9, 0x44, 0x5c, 0xc1, 0xfb, 0xf0, 0x08, 0x41, 0xbf, 0x60, 0x56,
+ 0xf8, 0xc1, 0x3a, 0xed, 0xe0, 0x59, 0xef, 0xef, 0x13, 0x11, 0x04, 0x1a,
+ 0x18, 0x25, 0x0d, 0x06, 0x0f, 0x3a, 0x40, 0x4c, 0x09, 0x13, 0x15, 0x05,
+ 0x05, 0x05, 0x89, 0xfa, 0x02, 0x84, 0xef, 0xe0, 0x59, 0xcc, 0xe1, 0x05,
+ 0x60, 0x4f, 0x20, 0x84, 0xeb, 0xe0, 0x3d, 0xc6, 0xf9, 0xe0, 0x4f, 0x1e,
+ 0xf5, 0x04, 0x05, 0x05, 0x86, 0x7a, 0xf5, 0xe0, 0x53, 0xae, 0x79, 0x61,
+ 0xed, 0xc5, 0xe4, 0x6e, 0x6f, 0xf3, 0xe0, 0x3e, 0x7e, 0x68, 0x6f, 0xeb,
+ 0xc5, 0x9b, 0xf4, 0x04, 0xe0, 0x3d, 0xd7, 0xef, 0x03, 0x03, 0x86, 0xf5,
+ 0xc4, 0x7a, 0x68, 0x69, 0xf2, 0xe0, 0x4b, 0x5f, 0xae, 0x60, 0x54, 0x46,
+ 0xc2, 0x0b, 0xf3, 0x04, 0x06, 0x11, 0x83, 0x75, 0x67, 0xe5, 0xe0, 0x31,
+ 0x6a, 0xe8, 0x06, 0x40, 0xed, 0xe0, 0x44, 0xf3, 0xe9, 0x03, 0xd8, 0xf7,
+ 0x6d, 0x69, 0xfa, 0xe0, 0x54, 0xc4, 0xe5, 0xd7, 0x2f, 0xe1, 0x46, 0x23,
+ 0xe0, 0x48, 0xec, 0xf2, 0x02, 0x83, 0xf9, 0xd6, 0xe2, 0x69, 0x79, 0x61,
+ 0xed, 0xe0, 0x4e, 0x21, 0x70, 0x65, 0xf2, 0xe0, 0x20, 0xf4, 0xef, 0x02,
+ 0x84, 0xf2, 0xe0, 0x49, 0x94, 0x62, 0x69, 0x6e, 0x2e, 0xe5, 0xe0, 0x3a,
+ 0x40, 0xee, 0x08, 0x08, 0x06, 0x11, 0x0b, 0xe0, 0x47, 0x7b, 0x79, 0x76,
+ 0x65, 0x6c, 0xef, 0xe0, 0x58, 0x3b, 0x74, 0x75, 0xed, 0xe0, 0x50, 0x8b,
+ 0xf3, 0x02, 0x86, 0x75, 0x6c, 0x61, 0xf4, 0xdc, 0x03, 0x6b, 0x6f, 0x77,
+ 0x6f, 0xec, 0xe0, 0x4a, 0x42, 0x67, 0xf3, 0x04, 0xe0, 0x2c, 0xbf, 0x76,
+ 0xe9, 0xe0, 0x43, 0x09, 0x61, 0x6e, 0xae, 0x60, 0x53, 0xc4, 0x89, 0xed,
+ 0x05, 0x06, 0x0b, 0x11, 0x87, 0x76, 0x75, 0xf8, 0xe0, 0x47, 0xa1, 0xef,
+ 0x02, 0x84, 0xf2, 0xe0, 0x4a, 0xa4, 0x6e, 0xef, 0xd0, 0x63, 0x6d, 0x75,
+ 0xee, 0x04, 0xe0, 0x57, 0x5d, 0x61, 0x6c, 0x66, 0x6f, 0x72, 0x62, 0xf5,
+ 0xe0, 0x42, 0xeb, 0x66, 0x6f, 0x72, 0xe2, 0xe0, 0x47, 0x7e, 0xe1, 0x06,
+ 0x0f, 0x4a, 0xf4, 0xcb, 0xc1, 0x74, 0x73, 0xf5, 0x06, 0x60, 0x50, 0xa1,
+ 0xc8, 0x31, 0x73, 0x68, 0x69, 0xed, 0xd2, 0x33, 0x67, 0x61, 0x6e, 0xe5,
+ 0xe0, 0x55, 0xb4, 0x6c, 0x6f, 0x62, 0x72, 0x7a, 0xe5, 0xe0, 0x2c, 0x32,
+ 0xeb, 0x03, 0x06, 0x85, 0x75, 0x62, 0x75, 0xee, 0xd9, 0xb8, 0x6f, 0x6e,
+ 0xef, 0xc5, 0x3e, 0xe1, 0xe0, 0x53, 0x5a, 0xe7, 0x02, 0x84, 0xe5, 0xe0,
+ 0x3c, 0xbf, 0xe1, 0x02, 0x85, 0x6e, 0xe5, 0xe0, 0x55, 0x55, 0xae, 0x60,
+ 0x4d, 0x0b, 0xc3, 0xfd, 0x66, 0xf5, 0xe0, 0x30, 0x72, 0x65, 0xec, 0xe0,
+ 0x57, 0x53, 0x64, 0x61, 0xe9, 0xd8, 0xb5, 0x63, 0x68, 0x69, 0xae, 0x60,
+ 0x52, 0x80, 0xc4, 0x56, 0xe2, 0x03, 0x07, 0x83, 0x69, 0x65, 0x72, 0x7a,
+ 0xf9, 0xdd, 0x09, 0xe5, 0xc0, 0xdb, 0x61, 0x79, 0x61, 0x73, 0xe8, 0xc3,
+ 0x13, 0xee, 0x06, 0x09, 0x0b, 0xe0, 0x58, 0x4c, 0x78, 0x2d, 0x73, 0x65,
+ 0x72, 0xf6, 0xe0, 0x3a, 0x22, 0x6f, 0x77, 0x73, 0x69, 0x74, 0x61, 0x6c,
+ 0xec, 0xe0, 0x48, 0x1d, 0x69, 0x67, 0x68, 0x74, 0x70, 0x6f, 0x69, 0x6e,
+ 0x74, 0x2e, 0x73, 0x79, 0x73, 0x74, 0x65, 0xed, 0xe0, 0x57, 0xcd, 0xed,
+ 0x06, 0x60, 0x3d, 0x2a, 0xdb, 0x08, 0x70, 0x73, 0xf0, 0xdb, 0x05, 0xec,
+ 0x04, 0x06, 0x06, 0x86, 0x1f, 0x43, 0xe6, 0xe0, 0x4f, 0xd1, 0x6f, 0x64,
+ 0x7a, 0xeb, 0xdd, 0x93, 0x65, 0x70, 0xf0, 0xe0, 0x56, 0x84, 0xe1, 0xe0,
+ 0x4f, 0xc1, 0xe9, 0x16, 0x05, 0x15, 0x0a, 0x40, 0x90, 0x26, 0x21, 0x1a,
+ 0x11, 0x0d, 0x18, 0x04, 0x0a, 0x09, 0x07, 0x0a, 0x60, 0x54, 0xe1, 0xc1,
+ 0xa7, 0x7a, 0xf5, 0xe0, 0x49, 0xc4, 0xf9, 0x03, 0xd8, 0x4a, 0xef, 0x04,
+ 0xe0, 0x53, 0x26, 0xf3, 0x06, 0x55, 0xcf, 0xe0, 0x26, 0x50, 0x61, 0xf4,
+ 0xe0, 0x4c, 0x48, 0xf7, 0x03, 0xc4, 0xf3, 0xe9, 0x5f, 0x04, 0xe0, 0x38,
+ 0xd8, 0xf4, 0x02, 0x84, 0x63, 0xe8, 0xdf, 0x4f, 0xe1, 0x0b, 0x06, 0x04,
+ 0x0a, 0x0b, 0x08, 0x17, 0x10, 0x14, 0x08, 0x8b, 0x79, 0x61, 0xed, 0xe0,
+ 0x4d, 0x18, 0x75, 0xf2, 0xd1, 0xc4, 0x73, 0x68, 0x69, 0x6f, 0x62, 0x61,
+ 0xf2, 0xe0, 0x4c, 0x71, 0x6e, 0x61, 0x6b, 0x61, 0x67, 0x75, 0x73, 0x75,
+ 0xeb, 0xd8, 0x89, 0xed, 0x04, 0xe0, 0x55, 0xea, 0xef, 0xc4, 0x4c, 0xeb,
+ 0x02, 0x88, 0x79, 0x75, 0x73, 0x68, 0x75, 0xae, 0xc2, 0x13, 0xe1, 0x03,
+ 0xd4, 0x92, 0x74, 0x61, 0xae, 0x60, 0x49, 0x5c, 0xc8, 0xc4, 0xe8, 0x02,
+ 0x89, 0x69, 0x72, 0x6f, 0x73, 0x68, 0xe9, 0xe0, 0x4b, 0x0a, 0xe1, 0xe0,
+ 0x4c, 0xc6, 0x67, 0xe1, 0x02, 0x88, 0x77, 0x61, 0xae, 0x60, 0x49, 0x40,
+ 0xc8, 0x2e, 0x74, 0x61, 0xae, 0x60, 0x4c, 0xc8, 0xc1, 0xc7, 0x64, 0x61,
+ 0x69, 0x74, 0xef, 0xe0, 0x52, 0xc5, 0xe1, 0x02, 0x84, 0x6b, 0xe9, 0xd8,
+ 0x54, 0xe9, 0xe0, 0x4e, 0x59, 0xae, 0x60, 0x49, 0x1a, 0x4a, 0xee, 0xc1,
+ 0x72, 0xf3, 0x03, 0x14, 0x88, 0xef, 0x05, 0x06, 0xe0, 0x54, 0x23, 0x73,
+ 0x61, 0x6b, 0xe9, 0xce, 0xa0, 0x66, 0x75, 0x6b, 0x75, 0x73, 0xe8, 0xcf,
+ 0xc5, 0x68, 0x69, 0x77, 0x61, 0xe4, 0xe0, 0x3b, 0xe3, 0x61, 0x72, 0x61,
+ 0xfa, 0xdf, 0x7b, 0xf2, 0x06, 0x05, 0x0a, 0xe0, 0x44, 0x2d, 0x79, 0xf5,
+ 0xe0, 0x4e, 0x4c, 0x6f, 0x76, 0x6f, 0x67, 0x72, 0x61, 0xe4, 0xe0, 0x3c,
+ 0x06, 0xe1, 0x04, 0xe0, 0x51, 0xbd, 0x72, 0x61, 0xae, 0xe0, 0x39, 0x50,
+ 0xee, 0x07, 0x05, 0x05, 0x04, 0xe0, 0x52, 0x52, 0x6f, 0xeb, 0xe0, 0x4c,
+ 0x4b, 0x6b, 0xef, 0xe0, 0x50, 0xa6, 0xe7, 0xe0, 0x4a, 0x96, 0xe4, 0xe0,
+ 0x54, 0xf6, 0xed, 0x05, 0x04, 0xe0, 0x56, 0xdc, 0xef, 0xe0, 0x52, 0x26,
+ 0xe9, 0x03, 0xdf, 0x2e, 0xee, 0xdb, 0xed, 0xec, 0x06, 0x60, 0x33, 0x79,
+ 0xca, 0xa2, 0x61, 0x74, 0xe9, 0xe0, 0x28, 0x15, 0xeb, 0x03, 0x0a, 0x83,
+ 0xf5, 0x03, 0xc4, 0x19, 0x63, 0x68, 0xe9, 0xe0, 0x4f, 0x6a, 0xef, 0xd1,
+ 0xd9, 0x69, 0x72, 0x61, 0xf2, 0xe0, 0x47, 0x02, 0xea, 0xe0, 0x2c, 0x4c,
+ 0x68, 0xef, 0x03, 0xce, 0x0e, 0x6b, 0xf5, 0xe0, 0x51, 0xd6, 0xe5, 0x04,
+ 0xe0, 0x3b, 0x8c, 0xee, 0xe0, 0x47, 0x9b, 0x64, 0xf3, 0x60, 0x50, 0xf2,
+ 0xc5, 0xa5, 0x63, 0x6b, 0x73, 0x2d, 0x61, 0x73, 0xf3, 0xe0, 0x28, 0xcc,
+ 0x62, 0x69, 0x63, 0x68, 0xf5, 0xc4, 0x37, 0xe8, 0x09, 0x07, 0x16, 0x08,
+ 0x60, 0x3b, 0x4a, 0xc9, 0xa5, 0x70, 0x6c, 0x61, 0xf9, 0xe0, 0x39, 0xe6,
+ 0x6d, 0x65, 0x6c, 0xee, 0x02, 0x88, 0x79, 0x74, 0x73, 0x6b, 0xf9, 0xe0,
+ 0x3b, 0x4d, 0x69, 0x74, 0x73, 0x6b, 0xe9, 0xe0, 0x3b, 0x54, 0x65, 0x72,
+ 0x73, 0x6f, 0xee, 0xe0, 0x3b, 0x4d, 0xe1, 0x03, 0x06, 0x88, 0x72, 0xeb,
+ 0x60, 0x3b, 0x37, 0x83, 0x6e, 0x68, 0x68, 0x6f, 0xe1, 0xe0, 0x4d, 0x97,
+ 0x6b, 0x61, 0x73, 0xf3, 0xe0, 0x54, 0x50, 0xe7, 0x60, 0x3f, 0x47, 0xd6,
+ 0xf1, 0xe6, 0xe0, 0x53, 0xa2, 0xe5, 0x0c, 0x0a, 0x05, 0x1f, 0x06, 0x07,
+ 0x60, 0x33, 0x3e, 0xe0, 0x22, 0xa9, 0x79, 0x6d, 0x61, 0x63, 0x68, 0x69,
+ 0xee, 0xe0, 0x2e, 0x7e, 0x74, 0xf2, 0xe0, 0x39, 0xa6, 0x72, 0x72, 0xf9,
+ 0x03, 0x0b, 0x88, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0xe9, 0xe0,
+ 0x4a, 0x0e, 0x6c, 0x6f, 0x67, 0x69, 0x73, 0xf4, 0xd9, 0x07, 0x68, 0x6f,
+ 0xf4, 0xe0, 0x3f, 0x90, 0xf0, 0x5b, 0x67, 0xe0, 0x29, 0x5c, 0x6d, 0x62,
+ 0x75, 0xe3, 0xe0, 0x4f, 0xc8, 0x69, 0xf3, 0xe0, 0x3e, 0xd0, 0x64, 0xe4,
+ 0xe0, 0x53, 0xc7, 0xe1, 0x1a, 0x17, 0x04, 0x40, 0xa2, 0x0f, 0x40, 0x41,
+ 0x40, 0x64, 0x40, 0x5f, 0x06, 0x40, 0x55, 0x40, 0xc6, 0x14, 0x26, 0x1f,
+ 0x0e, 0x28, 0x10, 0xe0, 0x42, 0x8c, 0xfa, 0x04, 0x04, 0xdf, 0x28, 0x75,
+ 0xee, 0xdf, 0x18, 0x69, 0x6d, 0x69, 0x65, 0x72, 0x7a, 0x2d, 0x64, 0x6f,
+ 0x6c, 0xee, 0xe0, 0x43, 0xae, 0x79, 0xe1, 0xd0, 0xc3, 0x77, 0xe1, 0x0e,
+ 0x03, 0x05, 0x06, 0x0d, 0x03, 0x1c, 0x10, 0x12, 0x04, 0x0f, 0x07, 0x10,
+ 0x88, 0xfa, 0xd5, 0xfd, 0x75, 0xe5, 0xe0, 0x4c, 0xb9, 0x74, 0x61, 0xee,
+ 0xe0, 0x3a, 0x32, 0x73, 0x61, 0x6b, 0x69, 0xae, 0x03, 0xde, 0x05, 0x6a,
+ 0xf0, 0xe0, 0x44, 0x1c, 0xf2, 0xd6, 0x2f, 0xee, 0x03, 0x0c, 0x87, 0x69,
+ 0x73, 0x68, 0x69, 0xae, 0x60, 0x4a, 0x47, 0x42, 0xcf, 0xc3, 0x82, 0x65,
+ 0x68, 0x6f, 0xee, 0xe0, 0x4b, 0x03, 0x61, 0xe2, 0xe0, 0x4f, 0x14, 0xed,
+ 0x02, 0x88, 0x69, 0x6e, 0x61, 0x6d, 0xe9, 0xe0, 0x47, 0x25, 0x61, 0xf4,
+ 0xe0, 0x4a, 0x0e, 0xeb, 0x02, 0x84, 0x69, 0xf4, 0xc1, 0xad, 0x61, 0x6d,
+ 0x69, 0x2e, 0x6e, 0xe1, 0x60, 0x4c, 0xe8, 0xc5, 0x47, 0x6a, 0xe9, 0xd4,
+ 0xb1, 0xe9, 0x02, 0x86, 0x69, 0x73, 0xe8, 0xe0, 0x46, 0x28, 0xae, 0x5e,
+ 0xe3, 0xe0, 0x2d, 0xf0, 0x68, 0x61, 0x72, 0xe1, 0xe0, 0x39, 0x3e, 0xe7,
+ 0x02, 0x85, 0x75, 0x63, 0xe8, 0xc6, 0x26, 0x6f, 0x65, 0xae, 0x60, 0x49,
+ 0xf7, 0xc0, 0xb6, 0x63, 0x68, 0x69, 0x6e, 0x61, 0xe7, 0xc5, 0xe2, 0xe2,
+ 0xe0, 0x4c, 0x3b, 0xf5, 0x02, 0x89, 0x74, 0x6f, 0x6b, 0x65, 0x69, 0xee,
+ 0xe0, 0x4c, 0xb0, 0xe6, 0xdc, 0x75, 0xf4, 0x03, 0x21, 0x8a, 0x73, 0xf5,
+ 0x04, 0x07, 0x03, 0x87, 0x79, 0x61, 0x6d, 0xe1, 0xe0, 0x2a, 0x6c, 0xf5,
+ 0xce, 0x45, 0x73, 0x68, 0x69, 0xeb, 0xe0, 0x4e, 0xd3, 0x72, 0x61, 0x67,
+ 0x69, 0xae, 0x60, 0x4a, 0x2f, 0xc2, 0x4d, 0xef, 0x02, 0x83, 0xf7, 0xd9,
+ 0x62, 0xf2, 0xe0, 0x38, 0xc5, 0xe1, 0x05, 0x07, 0xe0, 0x52, 0xe3, 0x73,
+ 0x68, 0x69, 0xee, 0xe0, 0x4b, 0xf0, 0x67, 0x61, 0xed, 0xc1, 0x87, 0xf3,
+ 0x07, 0x06, 0x1e, 0x1f, 0xe0, 0x30, 0x44, 0x7a, 0x75, 0xe2, 0xe0, 0x42,
+ 0xaa, 0xf5, 0x04, 0x03, 0x08, 0x87, 0xf9, 0xd5, 0x55, 0x6d, 0x69, 0x67,
+ 0x61, 0x75, 0xf2, 0xd1, 0x43, 0x6b, 0x61, 0x62, 0xe5, 0xe0, 0x49, 0x54,
+ 0x67, 0xe1, 0x60, 0x48, 0xfc, 0xc6, 0x48, 0x68, 0xe9, 0x04, 0x09, 0x08,
+ 0x85, 0x77, 0xe1, 0x45, 0x45, 0x58, 0xcc, 0xe0, 0x34, 0x92, 0x6d, 0x61,
+ 0xae, 0x60, 0x49, 0xd8, 0xc3, 0x0e, 0x68, 0x61, 0xf2, 0xcc, 0xe2, 0xe2,
+ 0xcc, 0xdf, 0xe1, 0x07, 0x05, 0x41, 0xc0, 0xe0, 0x4d, 0xc3, 0x6f, 0xeb,
+ 0xe0, 0x4e, 0x9f, 0x6d, 0xe1, 0x04, 0xe0, 0x4c, 0xc5, 0x74, 0x73, 0xf5,
+ 0xe0, 0x4b, 0x7b, 0xf2, 0x08, 0x0d, 0x06, 0x05, 0x06, 0x05, 0x08, 0x85,
+ 0xf5, 0x02, 0x83, 0xed, 0xdd, 0xf7, 0x69, 0x7a, 0x61, 0xf7, 0xe0, 0x38,
+ 0xd0, 0x74, 0x75, 0xfa, 0xe0, 0x42, 0x38, 0x70, 0xe1, 0xe0, 0x3d, 0x0a,
+ 0xed, 0x60, 0x48, 0x7f, 0xc3, 0x0d, 0x6c, 0xf3, 0xe0, 0x48, 0x78, 0xe9,
+ 0x03, 0xc5, 0xa1, 0xf9, 0xe0, 0x38, 0x52, 0x65, 0xec, 0xe0, 0x52, 0x2f,
+ 0xe1, 0x04, 0x06, 0x10, 0x87, 0x74, 0x73, 0xf5, 0xe0, 0x49, 0x70, 0xf3,
+ 0x02, 0x84, 0x75, 0x79, 0xe1, 0xac, 0x6a, 0xef, 0x04, 0xe0, 0x49, 0x70,
+ 0xe8, 0xdb, 0x8b, 0x67, 0x61, 0x6e, 0xe4, 0xe0, 0x52, 0x0e, 0x63, 0xef,
+ 0xc4, 0x47, 0x70, 0x73, 0xe9, 0xe0, 0x53, 0x95, 0xee, 0x0a, 0x05, 0x05,
+ 0x0e, 0x07, 0x05, 0x06, 0x12, 0xc5, 0x5b, 0x7a, 0x61, 0xeb, 0xdc, 0xed,
+ 0x75, 0xed, 0xe0, 0x48, 0x54, 0xef, 0x02, 0x85, 0x79, 0xe1, 0xe0, 0x4d,
+ 0x87, 0x6e, 0x6a, 0xe9, 0xe0, 0x45, 0x91, 0x6e, 0xe1, 0x60, 0x47, 0x84,
+ 0xc3, 0x77, 0x6d, 0x61, 0xeb, 0xd2, 0x99, 0xe9, 0x60, 0x47, 0xab, 0xc3,
+ 0x38, 0xe5, 0x02, 0x8a, 0x79, 0x61, 0x6d, 0x61, 0xae, 0x60, 0x48, 0x86,
+ 0xc5, 0xbe, 0x67, 0x61, 0xf3, 0xd3, 0xca, 0xe1, 0x06, 0x53, 0x8f, 0xe0,
+ 0x3b, 0x51, 0x7a, 0x61, 0x77, 0xe1, 0xe0, 0x4b, 0x69, 0xed, 0x05, 0x0e,
+ 0x40, 0x93, 0x8d, 0xef, 0x04, 0x03, 0xd3, 0xa5, 0xe5, 0xce, 0xab, 0xae,
+ 0x60, 0x45, 0x54, 0xc9, 0xeb, 0xe9, 0x0c, 0x0f, 0x17, 0x04, 0x0f, 0x06,
+ 0x20, 0x05, 0x0b, 0x06, 0x05, 0x86, 0xf4, 0x02, 0x86, 0x73, 0x75, 0xe5,
+ 0xe0, 0x41, 0x93, 0x6f, 0x6e, 0xe4, 0xe0, 0x48, 0xc1, 0xf3, 0x03, 0x09,
+ 0x86, 0xf5, 0x04, 0xe0, 0x4b, 0xcc, 0x6e, 0xe1, 0xdc, 0x84, 0x68, 0x69,
+ 0xe8, 0xe0, 0x47, 0xb9, 0x61, 0xf4, 0xdc, 0xc1, 0x6f, 0xeb, 0xd4, 0x4e,
+ 0x6e, 0xef, 0x02, 0x85, 0x79, 0x61, 0xed, 0xdc, 0x0f, 0x6b, 0x61, 0xf7,
+ 0xe0, 0x47, 0xba, 0x6d, 0x69, 0xee, 0xe0, 0x48, 0x99, 0xeb, 0x03, 0x07,
+ 0x87, 0x6f, 0x61, 0x6e, 0xe9, 0xe0, 0x2f, 0x2a, 0x69, 0x74, 0x61, 0x79,
+ 0xe1, 0xcb, 0x71, 0x61, 0x77, 0x61, 0xae, 0x04, 0xe0, 0x48, 0xb4, 0xe8,
+ 0x60, 0x4e, 0x45, 0xc3, 0x24, 0x6a, 0x69, 0xed, 0xcb, 0x80, 0xe9, 0x02,
+ 0x85, 0x7a, 0x75, 0xed, 0xc4, 0x17, 0xe3, 0xdb, 0xcd, 0x67, 0x6f, 0xf2,
+ 0xe0, 0x4e, 0x2a, 0x66, 0x75, 0xf2, 0xdb, 0x94, 0x61, 0x6d, 0xe1, 0xe0,
+ 0x4b, 0xa2, 0xae, 0x5b, 0x79, 0xe0, 0x31, 0x7b, 0xe5, 0x02, 0x86, 0x79,
+ 0x61, 0x6d, 0xe1, 0xca, 0x50, 0x6f, 0xeb, 0xdc, 0x01, 0xe1, 0x03, 0x04,
+ 0x85, 0x6b, 0xf5, 0xc5, 0x5d, 0x69, 0x73, 0xe8, 0xdc, 0x8c, 0x67, 0x61,
+ 0xf9, 0xd2, 0xf2, 0xec, 0x03, 0x05, 0x86, 0x75, 0xe7, 0xe0, 0x50, 0xe0,
+ 0x6d, 0x79, 0xeb, 0xe0, 0x41, 0xe0, 0x69, 0xf3, 0xe0, 0x3b, 0x98, 0xeb,
+ 0x05, 0x04, 0x04, 0x07, 0x86, 0x75, 0xe4, 0xdb, 0x37, 0x6f, 0xe7, 0xca,
+ 0x12, 0x69, 0x6e, 0x6f, 0xeb, 0xe0, 0x4c, 0xf4, 0x65, 0x67, 0x61, 0xf7,
+ 0xdc, 0x39, 0x61, 0x6d, 0x69, 0x67, 0x61, 0x68, 0x61, 0xf2, 0xe0, 0x24,
+ 0xf0, 0xe9, 0x07, 0x05, 0x04, 0x05, 0xe0, 0x2a, 0x61, 0x7a, 0xf5, 0xe0,
+ 0x37, 0x45, 0xf4, 0xe0, 0x2e, 0x7a, 0x73, 0xe5, 0xe0, 0x46, 0x15, 0x6e,
+ 0x61, 0x6e, 0xae, 0x60, 0x47, 0xd6, 0xc5, 0x33, 0x68, 0xef, 0x04, 0xe0,
+ 0x3b, 0x5f, 0x6b, 0x75, 0xae, 0x60, 0x47, 0x46, 0xc2, 0xf9, 0xe7, 0x02,
+ 0x8c, 0x6f, 0x73, 0x68, 0x69, 0x6d, 0x61, 0xae, 0x60, 0x4c, 0x16, 0xc4,
+ 0x9f, 0xe1, 0x06, 0x60, 0x4a, 0x23, 0xc3, 0x9f, 0x6d, 0xe9, 0x05, 0x05,
+ 0xe0, 0x4c, 0x46, 0x6e, 0xef, 0xe0, 0x4c, 0x8b, 0x69, 0x73, 0xe8, 0xe0,
+ 0x42, 0x83, 0xe4, 0x03, 0xc3, 0x26, 0xef, 0x02, 0x84, 0xed, 0xe0, 0x36,
+ 0xf3, 0x67, 0x61, 0xf7, 0xcc, 0x3c, 0x61, 0xf3, 0xe0, 0x2e, 0xb9, 0x38,
+ 0x73, 0xae, 0x05, 0x08, 0x5e, 0xa2, 0x87, 0x70, 0x6c, 0x2d, 0x77, 0x61,
+ 0xf7, 0xde, 0xaa, 0x6e, 0x6c, 0x2d, 0x61, 0x6d, 0xf3, 0xde, 0xa2, 0x31,
+ 0x32, 0xae, 0x15, 0x07, 0x0c, 0x04, 0x08, 0x04, 0x0a, 0x0d, 0x60, 0x30,
+ 0x76, 0x47, 0x54, 0x04, 0x1c, 0x0a, 0x02, 0x16, 0x06, 0x0b, 0x8d, 0xf7,
+ 0x60, 0x38, 0x32, 0x2e, 0xd0, 0xde, 0xf6, 0x05, 0x60, 0x38, 0x4e, 0x86,
+ 0xe9, 0x60, 0x4c, 0x4a, 0xc5, 0xa5, 0xf5, 0xe0, 0x38, 0x47, 0xf4, 0x60,
+ 0x37, 0xe2, 0x40, 0x41, 0xd8, 0x69, 0xf3, 0xe0, 0x38, 0x34, 0xee, 0x60,
+ 0x37, 0xf4, 0x03, 0x03, 0x03, 0x12, 0x1e, 0x83, 0xe9, 0x06, 0x60, 0x38,
+ 0x07, 0x03, 0xa3, 0xec, 0x60, 0x4c, 0x23, 0xc5, 0xa5, 0xe4, 0xe0, 0x38,
+ 0x19, 0xea, 0x15, 0x09, 0x1c, 0x18, 0x24, 0x40, 0x7c, 0x04, 0x06, 0x1e,
+ 0x12, 0x40, 0x9d, 0x0a, 0x28, 0x1f, 0x51, 0x3e, 0xe0, 0x2f, 0x7f, 0x1f,
+ 0x43, 0xf8, 0x03, 0xc0, 0xa2, 0xf2, 0xc0, 0x9e, 0xf5, 0x07, 0x04, 0x06,
+ 0x05, 0xe0, 0x39, 0x26, 0xf2, 0xe0, 0x50, 0x09, 0x6e, 0x69, 0xf0, 0xe0,
+ 0x3d, 0xf1, 0x65, 0xe7, 0xe0, 0x30, 0x31, 0x2e, 0xed, 0xe0, 0x50, 0x8e,
+ 0x73, 0xae, 0x06, 0x60, 0x4c, 0xd4, 0xc1, 0xd9, 0x77, 0x70, 0x65, 0x6e,
+ 0x67, 0x69, 0x6e, 0x65, 0x70, 0x6f, 0x77, 0x65, 0xf2, 0xe0, 0x47, 0x66,
+ 0xf0, 0x09, 0x04, 0x07, 0x60, 0x2f, 0xc4, 0xe0, 0x21, 0x93, 0xee, 0xe0,
+ 0x29, 0x85, 0x6d, 0x6f, 0x72, 0xe7, 0xe0, 0x4d, 0x1b, 0xae, 0x08, 0x60,
+ 0x3d, 0x9e, 0x47, 0x7a, 0xc5, 0xd8, 0xee, 0x60, 0x47, 0xdc, 0xc9, 0x4f,
+ 0xef, 0x11, 0x05, 0x09, 0x0e, 0x0d, 0x04, 0x08, 0x06, 0x09, 0x06, 0x07,
+ 0x07, 0x60, 0x46, 0x48, 0xca, 0x96, 0x7a, 0xe9, 0xe0, 0x4e, 0x0e, 0xf9,
+ 0x04, 0xe0, 0x51, 0x2c, 0xef, 0xe0, 0x42, 0xf6, 0x75, 0x72, 0x6e, 0x61,
+ 0xec, 0x04, 0xe0, 0x4e, 0x42, 0x69, 0xf3, 0xe0, 0x4c, 0x15, 0xf4, 0x04,
+ 0xe0, 0x51, 0x15, 0x65, 0x6c, 0x75, 0x6c, 0xf5, 0xe0, 0x39, 0x30, 0xf3,
+ 0xe0, 0x41, 0x46, 0xf2, 0x04, 0xe0, 0x4f, 0xa9, 0xf0, 0xcd, 0x68, 0x6c,
+ 0x73, 0xf4, 0xe0, 0x45, 0x55, 0x69, 0x6e, 0x76, 0x69, 0x6c, 0xec, 0xe0,
+ 0x38, 0x9a, 0x68, 0x61, 0x6e, 0xe1, 0xd9, 0xef, 0x67, 0x61, 0x73, 0xfa,
+ 0xe0, 0x4f, 0xe6, 0x65, 0x74, 0x73, 0xf5, 0xe0, 0x4c, 0x97, 0xe2, 0x04,
+ 0x09, 0xd1, 0x17, 0xf3, 0x04, 0xe0, 0x50, 0xd4, 0xae, 0xe0, 0x4f, 0x14,
+ 0x6f, 0xea, 0xda, 0x82, 0xee, 0xe0, 0x4e, 0x8b, 0xed, 0x60, 0x3f, 0x64,
+ 0xcf, 0xc6, 0xec, 0x06, 0x60, 0x3d, 0x4c, 0xd1, 0x20, 0x73, 0x2d, 0x73,
+ 0x74, 0xef, 0x03, 0x02, 0x82, 0xb3, 0x84, 0xb2, 0x82, 0x31, 0x2e, 0x65,
+ 0x6c, 0x61, 0x73, 0x74, 0xf8, 0xe0, 0x50, 0x83, 0xe9, 0x04, 0xe0, 0x4f,
+ 0x14, 0x6e, 0x73, 0x65, 0x6b, 0x69, 0x6b, 0x6f, 0x67, 0x65, 0xee, 0xe0,
+ 0x45, 0x40, 0xe5, 0x0e, 0x06, 0x07, 0x05, 0x05, 0x06, 0x40, 0x5e, 0x09,
+ 0x51, 0xa5, 0xe0, 0x3e, 0x5a, 0x77, 0x65, 0xec, 0xe0, 0x2e, 0x7c, 0x76,
+ 0x6e, 0x61, 0xeb, 0xe0, 0x44, 0xd0, 0x74, 0xfa, 0xe0, 0x4e, 0xb6, 0x73,
+ 0xf3, 0xe0, 0x43, 0x8e, 0x6f, 0xee, 0x60, 0x34, 0x31, 0x85, 0xec, 0x03,
+ 0x07, 0x97, 0x6c, 0x79, 0x62, 0x65, 0xe1, 0xd0, 0xe4, 0xe5, 0x02, 0x84,
+ 0xee, 0xe0, 0x41, 0x6d, 0xae, 0x08, 0x60, 0x32, 0x96, 0x46, 0x84, 0xd6,
+ 0x2a, 0x63, 0xec, 0x60, 0x38, 0x6c, 0xc7, 0x8e, 0x61, 0x73, 0x74, 0x69,
+ 0x63, 0xae, 0x04, 0x0e, 0x0c, 0x8e, 0xf4, 0x04, 0xe0, 0x29, 0x2f, 0x73,
+ 0x75, 0x6b, 0x61, 0x65, 0xf2, 0xe0, 0x26, 0x71, 0x73, 0x61, 0x76, 0x65,
+ 0x69, 0x6e, 0x63, 0x6c, 0x6f, 0xf5, 0xdb, 0xd5, 0x72, 0x65, 0x67, 0x72,
+ 0x75, 0x68, 0x6f, 0x73, 0x74, 0x69, 0xee, 0xe0, 0x36, 0x9b, 0x64, 0x6f,
+ 0x67, 0x61, 0x64, 0x6f, 0xae, 0xe0, 0x4a, 0xf2, 0xe5, 0x04, 0xe0, 0x4e,
+ 0x66, 0xfa, 0xe0, 0x4f, 0x07, 0x64, 0x2e, 0x77, 0x61, 0x66, 0x61, 0xe9,
+ 0xe0, 0x4a, 0x9a, 0xe4, 0x04, 0xe0, 0x22, 0x05, 0x65, 0xf6, 0xe0, 0x4a,
+ 0x90, 0xe3, 0x05, 0x1a, 0xe0, 0x45, 0x72, 0x6c, 0x6f, 0x75, 0xe4, 0x02,
+ 0x87, 0xae, 0x02, 0x8d, 0xeb, 0xe0, 0x4c, 0xb8, 0x2d, 0x76, 0x65, 0x72,
+ 0x2d, 0x6a, 0x70, 0x63, 0x2e, 0x69, 0xeb, 0xde, 0xba, 0x2e, 0x6e, 0x65,
+ 0x65, 0xee, 0xe0, 0x4f, 0x7b, 0xe1, 0x0a, 0x05, 0x0a, 0x52, 0x0a, 0x60,
+ 0x27, 0x13, 0xc5, 0x58, 0x77, 0x6f, 0xf2, 0xd5, 0x28, 0xed, 0x03, 0xdc,
+ 0x8d, 0x62, 0x79, 0xec, 0xe0, 0x4d, 0xc2, 0x67, 0xf5, 0xe0, 0x3d, 0x96,
+ 0xae, 0x05, 0x17, 0xe0, 0x4f, 0x85, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x66,
+ 0x6f, 0x72, 0x63, 0x65, 0xae, 0x04, 0xe0, 0x4f, 0x6c, 0x63, 0x6f, 0x6d,
+ 0x2e, 0xe3, 0xe0, 0x3e, 0x1a, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x68,
+ 0x69, 0x66, 0xf4, 0xe0, 0x4c, 0x2b, 0xe9, 0x23, 0x40, 0x45, 0x05, 0x40,
+ 0x4b, 0x23, 0x40, 0x82, 0x43, 0x2c, 0x11, 0x22, 0x19, 0x42, 0x66, 0x40,
+ 0x4d, 0x2d, 0x3b, 0x27, 0x05, 0x12, 0x06, 0x0d, 0x40, 0x4d, 0x40, 0x54,
+ 0x23, 0x0d, 0x06, 0xe0, 0x26, 0x19, 0xfa, 0x03, 0x3a, 0x84, 0xf5, 0x05,
+ 0x08, 0xe0, 0x44, 0xe2, 0x6e, 0x6f, 0x6b, 0x75, 0xee, 0xe0, 0x44, 0xe4,
+ 0xed, 0x02, 0x8c, 0xef, 0x04, 0xe0, 0x49, 0x86, 0x7a, 0x61, 0x6b, 0xe9,
+ 0xe0, 0x4a, 0xee, 0xe9, 0x04, 0x06, 0x05, 0x87, 0x7a, 0x61, 0xeb, 0xe0,
+ 0x3f, 0x6b, 0x73, 0xe1, 0xe0, 0x4d, 0x51, 0x6f, 0x74, 0x73, 0xf5, 0xe0,
+ 0x4d, 0x4c, 0xae, 0x60, 0x48, 0xd3, 0xc4, 0x76, 0x65, 0xee, 0xd5, 0x7f,
+ 0xae, 0xd9, 0x38, 0x79, 0xef, 0xe0, 0x4a, 0x40, 0xf7, 0x02, 0x83, 0xe9,
+ 0xd6, 0x30, 0xe1, 0x08, 0x13, 0x08, 0x09, 0x0c, 0x07, 0xcb, 0xc7, 0xf4,
+ 0x04, 0x07, 0xd8, 0x86, 0x73, 0x75, 0x6b, 0xe9, 0xe0, 0x43, 0xb5, 0x65,
+ 0xae, 0x58, 0xa5, 0xe0, 0x34, 0x9f, 0xee, 0x04, 0xe0, 0x3c, 0x6b, 0xf5,
+ 0xcc, 0xc3, 0xed, 0x03, 0xcb, 0x88, 0x69, 0xfa, 0xe0, 0x43, 0xa5, 0xeb,
+ 0x04, 0xe0, 0x3f, 0x12, 0xf5, 0x03, 0xcc, 0x61, 0xee, 0xcc, 0x1f, 0x66,
+ 0x75, 0x6e, 0xe5, 0xe0, 0x43, 0x44, 0x64, 0xe5, 0xe0, 0x44, 0x1c, 0xf6,
+ 0x05, 0x05, 0x04, 0xcb, 0x17, 0x6f, 0x72, 0xf9, 0xd5, 0xd1, 0xe7, 0xe0,
+ 0x48, 0x44, 0x61, 0x6e, 0xef, 0x02, 0x85, 0x76, 0xef, 0xe0, 0x4c, 0xc1,
+ 0x2d, 0x66, 0x72, 0x61, 0x6e, 0x6b, 0xe9, 0xe0, 0x27, 0x26, 0xf4, 0x0c,
+ 0x05, 0x11, 0x05, 0x0d, 0x29, 0x1b, 0x60, 0x4a, 0x69, 0xc3, 0xbc, 0x73,
+ 0xae, 0xe0, 0x32, 0x6e, 0xef, 0x05, 0x03, 0xe0, 0x44, 0x21, 0xed, 0xd4,
+ 0xf3, 0x69, 0x67, 0x61, 0x77, 0xe1, 0xe0, 0x4a, 0x34, 0x69, 0xe7, 0xe0,
+ 0x35, 0xc6, 0x63, 0x6f, 0x75, 0x6c, 0x64, 0x62, 0x65, 0x77, 0x6f, 0xf2,
+ 0xe0, 0x4e, 0x05, 0xe1, 0x08, 0x07, 0x05, 0x04, 0x0a, 0xe0, 0x4d, 0x46,
+ 0x79, 0x61, 0x6e, 0x61, 0xe7, 0xce, 0x01, 0x6e, 0xef, 0xe0, 0x48, 0xe2,
+ 0xed, 0xe0, 0x49, 0x79, 0xeb, 0x04, 0xe0, 0x3e, 0x85, 0x75, 0xf2, 0xe0,
+ 0x45, 0x7c, 0x62, 0x61, 0xf3, 0xe0, 0x4a, 0xfa, 0x31, 0xae, 0x02, 0x8a,
+ 0x65, 0x75, 0x72, 0x2e, 0x61, 0x72, 0x75, 0x62, 0x61, 0x2e, 0x6a, 0x65,
+ 0x6e, 0x76, 0x2d, 0x61, 0x72, 0x75, 0x62, 0xe1, 0xe0, 0x36, 0x48, 0xae,
+ 0x60, 0x23, 0x69, 0x60, 0x24, 0x5d, 0xc6, 0x57, 0xf3, 0x0d, 0x05, 0x1d,
+ 0x18, 0x07, 0x04, 0x23, 0x2a, 0x1f, 0x08, 0xe0, 0x4d, 0x55, 0x75, 0xed,
+ 0xe0, 0x32, 0x07, 0xf4, 0x06, 0x05, 0x0a, 0xe0, 0x4d, 0xf3, 0x6d, 0xe5,
+ 0xe0, 0x25, 0x0f, 0x65, 0x69, 0x6e, 0x67, 0x65, 0x65, 0xeb, 0xe0, 0x2a,
+ 0xc1, 0x61, 0x6e, 0x62, 0xf5, 0xe0, 0x4b, 0xa0, 0xf3, 0x02, 0x8f, 0x6d,
+ 0x61, 0x72, 0x74, 0x65, 0x72, 0x74, 0x68, 0x61, 0x6e, 0x79, 0xef, 0xe0,
+ 0x4c, 0xab, 0x68, 0x69, 0xeb, 0xe0, 0x48, 0x8d, 0x6d, 0x61, 0x69, 0xec,
+ 0xe0, 0x4b, 0xb7, 0x6c, 0xe1, 0xde, 0xfa, 0x68, 0xe9, 0x03, 0x08, 0x90,
+ 0x6e, 0x6f, 0x6d, 0x61, 0x6b, 0xe9, 0xd6, 0x41, 0x6b, 0xe1, 0x04, 0xe0,
+ 0x4b, 0xff, 0x77, 0x61, 0xae, 0x60, 0x48, 0x48, 0x40, 0xd4, 0xc2, 0xec,
+ 0x67, 0x61, 0xeb, 0xe0, 0x49, 0x10, 0xe5, 0x06, 0x07, 0x12, 0x04, 0xc4,
+ 0xe9, 0x73, 0x61, 0x6b, 0xe9, 0xe0, 0x44, 0xcf, 0xf2, 0x04, 0xe0, 0x35,
+ 0x4b, 0xf6, 0x04, 0xe0, 0x3f, 0xf2, 0x73, 0x63, 0x68, 0x75, 0xec, 0xe0,
+ 0x25, 0xec, 0xee, 0xe0, 0x47, 0x3a, 0x68, 0x61, 0xf2, 0xe0, 0x48, 0xbb,
+ 0xe1, 0x03, 0x06, 0x86, 0x68, 0x61, 0xf9, 0xe0, 0x32, 0x1b, 0xae, 0x60,
+ 0x47, 0x27, 0xc1, 0x46, 0xad, 0x02, 0x89, 0x68, 0x6f, 0x63, 0x6b, 0x65,
+ 0x79, 0xee, 0xd7, 0xaf, 0xe7, 0xc1, 0xcb, 0xae, 0x50, 0x33, 0x60, 0x36,
+ 0xcb, 0xc4, 0x5c, 0xad, 0x0c, 0x0e, 0x25, 0x06, 0x0e, 0x04, 0x0a, 0x09,
0x21, 0x06, 0x06, 0x84, 0x77, 0x69, 0x74, 0x68, 0x2d, 0x74, 0x68, 0x65,
- 0x62, 0x61, 0xee, 0xe0, 0x4b, 0x44, 0x76, 0x65, 0x72, 0x79, 0xad, 0x05,
- 0x06, 0x06, 0x05, 0x87, 0x73, 0x77, 0xe5, 0xe0, 0x20, 0xf8, 0x6e, 0x69,
- 0xe3, 0xe0, 0x3b, 0x5d, 0x67, 0x6f, 0xef, 0xdd, 0x65, 0x65, 0x76, 0x69,
- 0xec, 0xe0, 0x4d, 0x89, 0x62, 0xe1, 0xdd, 0x5a, 0x75, 0x62, 0x65, 0x72,
- 0xec, 0xa1, 0xf3, 0x02, 0x86, 0x6c, 0x69, 0xe3, 0xe0, 0x47, 0x7e, 0x61,
- 0x76, 0xe5, 0xdd, 0x46, 0x6e, 0x6f, 0x74, 0x2d, 0x63, 0x65, 0x72, 0x74,
- 0x69, 0x66, 0xe9, 0xe0, 0x46, 0x97, 0xec, 0x03, 0xd5, 0xa0, 0x65, 0xe5,
- 0xe0, 0x46, 0x87, 0x69, 0x6e, 0x74, 0x6f, 0xad, 0x03, 0x06, 0x8d, 0x67,
- 0x61, 0xed, 0xe0, 0x4f, 0x10, 0x63, 0x61, 0xf2, 0x04, 0xe0, 0x4f, 0x07,
- 0x74, 0x6f, 0xef, 0xe0, 0x25, 0xa8, 0x61, 0x6e, 0xe9, 0xe0, 0x24, 0xa8,
- 0x67, 0x6f, 0xee, 0xe0, 0x48, 0x81, 0x66, 0x6f, 0x75, 0xee, 0xdd, 0x02,
- 0x62, 0xf9, 0xd2, 0x62, 0xe1, 0x02, 0xb5, 0x6e, 0xad, 0x02, 0x91, 0x65,
- 0xee, 0x02, 0x86, 0x74, 0x65, 0x72, 0xf4, 0xc0, 0x99, 0x67, 0x69, 0x6e,
- 0xe5, 0xe0, 0x46, 0x77, 0xe1, 0x04, 0x04, 0xc1, 0x9c, 0x72, 0xf4, 0xc1,
- 0xa3, 0xe3, 0x02, 0x8b, 0xf4, 0x04, 0xe0, 0x42, 0x44, 0x72, 0x65, 0xf3,
- 0xe0, 0x4e, 0xbf, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0xe1, 0xe0, 0x46, 0x1d,
- 0xad, 0x10, 0x16, 0x16, 0x15, 0x2c, 0x10, 0x06, 0x30, 0x08, 0x12, 0x14,
- 0x11, 0x1a, 0x40, 0x40, 0xa7, 0xf4, 0x02, 0x87, 0x68, 0x65, 0x72, 0x61,
- 0xf0, 0xc1, 0x71, 0xe5, 0x02, 0x86, 0x63, 0x68, 0xe9, 0xe0, 0x48, 0x1b,
- 0x61, 0xe3, 0xbd, 0xf3, 0x02, 0x86, 0x74, 0x75, 0xe4, 0xe0, 0x45, 0xec,
- 0xef, 0x02, 0x84, 0xf8, 0xe0, 0x2e, 0xb8, 0x63, 0x69, 0x61, 0xec, 0xc1,
- 0x4f, 0xf2, 0x02, 0x89, 0x6f, 0x63, 0x6b, 0x73, 0x74, 0xe1, 0xe0, 0x46,
- 0x0f, 0x65, 0x70, 0x75, 0x62, 0x6c, 0x69, 0xe3, 0xc1, 0x18, 0xf0, 0x04,
- 0x04, 0x0c, 0x8d, 0x6c, 0xe1, 0xc0, 0x60, 0x68, 0x6f, 0x74, 0x6f, 0x67,
- 0x72, 0x61, 0x70, 0xe8, 0xe0, 0x45, 0xf0, 0x65, 0x72, 0x73, 0x6f, 0x6e,
- 0x61, 0x6c, 0x74, 0x72, 0x61, 0xe9, 0xc0, 0x9f, 0xe1, 0x02, 0x83, 0xf4,
- 0xc0, 0xf7, 0xe9, 0xe0, 0x3f, 0x13, 0xee, 0x02, 0x86, 0x75, 0x72, 0xf3,
- 0xe0, 0x47, 0xb8, 0x61, 0x73, 0x63, 0x61, 0xf2, 0xc0, 0xdb, 0x6d, 0x75,
- 0x73, 0x69, 0xe3, 0x9b, 0xec, 0x04, 0x1c, 0xc5, 0x8a, 0xe9, 0x02, 0x8a,
- 0x6e, 0x75, 0x78, 0x2d, 0x75, 0x73, 0xe5, 0xe0, 0x36, 0x90, 0x62, 0x65,
- 0xf2, 0x02, 0x86, 0x74, 0x61, 0x72, 0xe9, 0xc0, 0xb9, 0xe1, 0xe0, 0x48,
- 0x77, 0xe1, 0x02, 0x85, 0x77, 0xf9, 0xe0, 0x45, 0x9a, 0x6e, 0x64, 0x73,
- 0x63, 0xe1, 0xc0, 0xb7, 0x6b, 0x6e, 0x69, 0x67, 0xe8, 0xe0, 0x45, 0xa4,
- 0xe8, 0x02, 0x84, 0xf5, 0xe0, 0x3e, 0xbe, 0x61, 0x72, 0x64, 0x2d, 0x77,
- 0x6f, 0x72, 0xeb, 0xe0, 0x45, 0x79, 0xe7, 0x03, 0x05, 0x85, 0x75, 0xf2,
- 0xe0, 0x4d, 0xb9, 0x72, 0x65, 0xe5, 0xde, 0x4e, 0x65, 0x65, 0xeb, 0xe0,
- 0x3b, 0x45, 0x66, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x69, 0x61, 0x6c, 0x61,
- 0x64, 0x76, 0x69, 0xf3, 0xe0, 0x41, 0x35, 0xe4, 0x02, 0x85, 0x6f, 0xe3,
- 0xe0, 0x41, 0x2c, 0xe5, 0x02, 0x87, 0x73, 0x69, 0x67, 0xee, 0xe0, 0x45,
- 0x42, 0x6d, 0x6f, 0x63, 0x72, 0xe1, 0xe0, 0x45, 0x01, 0xe3, 0x06, 0x0d,
+ 0x62, 0x61, 0xee, 0xe0, 0x47, 0xe3, 0x76, 0x65, 0x72, 0x79, 0xad, 0x05,
+ 0x05, 0x06, 0x05, 0x87, 0x73, 0x77, 0xe5, 0xdf, 0x62, 0x6e, 0x69, 0xe3,
+ 0xe0, 0x37, 0xec, 0x67, 0x6f, 0xef, 0xdb, 0xce, 0x65, 0x76, 0x69, 0xec,
+ 0xe0, 0x4a, 0x4c, 0x62, 0xe1, 0xdb, 0xc3, 0x75, 0x62, 0x65, 0x72, 0xec,
+ 0xa1, 0xf3, 0x02, 0x86, 0x6c, 0x69, 0xe3, 0xe0, 0x49, 0x15, 0x61, 0x76,
+ 0xe5, 0xdb, 0xaf, 0x6e, 0x6f, 0x74, 0x2d, 0x63, 0x65, 0x72, 0x74, 0x69,
+ 0x66, 0xe9, 0xe0, 0x42, 0xed, 0xec, 0x03, 0xd4, 0xa5, 0x65, 0xe5, 0xe0,
+ 0x42, 0xdd, 0x69, 0x6e, 0x74, 0x6f, 0xad, 0x03, 0x06, 0x8d, 0x67, 0x61,
+ 0xed, 0xe0, 0x4b, 0xc2, 0x63, 0x61, 0xf2, 0x04, 0xe0, 0x4b, 0xb9, 0x74,
+ 0x6f, 0xef, 0xe0, 0x24, 0x79, 0x61, 0x6e, 0xe9, 0xe0, 0x23, 0x7d, 0x67,
+ 0x6f, 0xee, 0xe0, 0x45, 0x1b, 0x66, 0x6f, 0x75, 0xee, 0xdb, 0x6b, 0x62,
+ 0xf9, 0xd1, 0x99, 0xe1, 0x02, 0xb5, 0x6e, 0xad, 0x02, 0x91, 0x65, 0xee,
+ 0x02, 0x86, 0x74, 0x65, 0x72, 0xf4, 0xc0, 0x99, 0x67, 0x69, 0x6e, 0xe5,
+ 0xe0, 0x42, 0xcd, 0xe1, 0x04, 0x04, 0xc1, 0x9e, 0x72, 0xf4, 0xc1, 0xa5,
+ 0xe3, 0x02, 0x8b, 0xf4, 0x04, 0xe0, 0x3e, 0x8d, 0x72, 0x65, 0xf3, 0xe0,
+ 0x4b, 0x71, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0xe1, 0xe0, 0x42, 0x73, 0xad,
+ 0x10, 0x16, 0x16, 0x15, 0x2c, 0x10, 0x06, 0x30, 0x08, 0x12, 0x15, 0x11,
+ 0x1a, 0x40, 0x40, 0xa8, 0xf4, 0x02, 0x87, 0x68, 0x65, 0x72, 0x61, 0xf0,
+ 0xc1, 0x73, 0xe5, 0x02, 0x86, 0x63, 0x68, 0xe9, 0xe0, 0x44, 0xb5, 0x61,
+ 0xe3, 0xbd, 0xf3, 0x02, 0x86, 0x74, 0x75, 0xe4, 0xe0, 0x42, 0x42, 0xef,
+ 0x02, 0x84, 0xf8, 0xe0, 0x2c, 0x76, 0x63, 0x69, 0x61, 0xec, 0xc1, 0x51,
+ 0xf2, 0x02, 0x89, 0x6f, 0x63, 0x6b, 0x73, 0x74, 0xe1, 0xe0, 0x4b, 0x55,
+ 0x65, 0x70, 0x75, 0x62, 0x6c, 0x69, 0xe3, 0xc1, 0x19, 0xf0, 0x04, 0x04,
+ 0x0c, 0x8d, 0x6c, 0xe1, 0xc0, 0x60, 0x68, 0x6f, 0x74, 0x6f, 0x67, 0x72,
+ 0x61, 0x70, 0xe8, 0xe0, 0x42, 0x46, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61,
+ 0x6c, 0x74, 0x72, 0x61, 0xe9, 0xc0, 0xa0, 0xe1, 0x02, 0x83, 0xf4, 0xc0,
+ 0xf9, 0xe9, 0xe0, 0x3b, 0x63, 0xee, 0x02, 0x86, 0x75, 0x72, 0xf3, 0xe0,
+ 0x44, 0x52, 0x61, 0x73, 0x63, 0x61, 0xf2, 0xc0, 0xdc, 0x6d, 0x75, 0x73,
+ 0x69, 0xe3, 0x9b, 0xec, 0x04, 0x1c, 0xc5, 0x60, 0xe9, 0x02, 0x8a, 0x6e,
+ 0x75, 0x78, 0x2d, 0x75, 0x73, 0xe5, 0xe0, 0x33, 0xa5, 0x62, 0x65, 0xf2,
+ 0x02, 0x86, 0x74, 0x61, 0x72, 0xe9, 0xc0, 0xba, 0xe1, 0xe0, 0x44, 0xf8,
+ 0xe1, 0x02, 0x85, 0x77, 0xf9, 0xe0, 0x41, 0xf0, 0x6e, 0x64, 0x73, 0x63,
+ 0xe1, 0xc0, 0xb9, 0x6b, 0x6e, 0x69, 0x67, 0xe8, 0xe0, 0x41, 0xf9, 0xe8,
+ 0x02, 0x84, 0xf5, 0xe0, 0x3b, 0x0e, 0x61, 0x72, 0x64, 0x2d, 0x77, 0x6f,
+ 0x72, 0xeb, 0xe0, 0x41, 0xcf, 0xe7, 0x03, 0x05, 0x86, 0x75, 0xf2, 0xe0,
+ 0x4a, 0x6b, 0x72, 0x65, 0xe5, 0xe0, 0x23, 0xab, 0x65, 0x65, 0xeb, 0xe0,
+ 0x37, 0xd3, 0x66, 0x69, 0x6e, 0x61, 0x6e, 0x63, 0x69, 0x61, 0x6c, 0x61,
+ 0x64, 0x76, 0x69, 0xf3, 0xe0, 0x3d, 0x7d, 0xe4, 0x02, 0x85, 0x6f, 0xe3,
+ 0xe0, 0x3d, 0x74, 0xe5, 0x02, 0x87, 0x73, 0x69, 0x67, 0xee, 0xe0, 0x41,
+ 0x97, 0x6d, 0x6f, 0x63, 0x72, 0xe1, 0xe0, 0x41, 0x56, 0xe3, 0x06, 0x0d,
0x03, 0x0b, 0x06, 0x86, 0x75, 0x62, 0x69, 0x63, 0x6c, 0x65, 0x2d, 0x73,
- 0x6c, 0xe1, 0xe0, 0x27, 0xe6, 0xf0, 0xd7, 0x1b, 0x6f, 0x6e, 0x73, 0x65,
- 0x72, 0x76, 0x61, 0xf4, 0xe0, 0x27, 0xd7, 0x68, 0x65, 0xe6, 0xe0, 0x3a,
- 0xf2, 0x65, 0x6c, 0x74, 0x69, 0xe3, 0xa5, 0xe1, 0x02, 0x86, 0x74, 0x65,
- 0xf2, 0xe0, 0x45, 0x03, 0x6e, 0x64, 0x69, 0x64, 0x61, 0xf4, 0xe0, 0x39,
- 0x5c, 0xe2, 0x04, 0x09, 0x08, 0x8a, 0x75, 0x6c, 0x6c, 0x73, 0x2d, 0x66,
- 0xe1, 0xdd, 0xcf, 0x72, 0x75, 0x69, 0x6e, 0xf3, 0xe0, 0x2d, 0x7c, 0x6f,
- 0x6f, 0x6b, 0x6b, 0x65, 0x65, 0xf0, 0xe0, 0x44, 0xda, 0x6c, 0x6f, 0x67,
- 0xe7, 0xe0, 0x44, 0xd3, 0x61, 0x6e, 0x61, 0x72, 0x63, 0x68, 0x69, 0xf3,
- 0xe0, 0x44, 0x8f, 0xf2, 0x08, 0x03, 0x08, 0x60, 0x43, 0x6a, 0xca, 0xb3,
- 0xf5, 0xcb, 0x0d, 0x69, 0xf3, 0x60, 0x21, 0xfb, 0xe0, 0x2a, 0x8a, 0x61,
- 0xf1, 0xe0, 0x4b, 0x62, 0xf0, 0x03, 0x10, 0x84, 0xe9, 0x02, 0x87, 0x72,
- 0x61, 0x6e, 0xe7, 0xe0, 0x4c, 0x74, 0x66, 0x6f, 0xee, 0xe0, 0x4c, 0xaf,
- 0xb6, 0xe0, 0x21, 0xdb, 0x2e, 0x6c, 0x69, 0x6e, 0x6f, 0x64, 0xe5, 0xe0,
- 0x44, 0x4a, 0xef, 0x06, 0x07, 0x03, 0xe0, 0x4d, 0xe5, 0x70, 0x73, 0x79,
- 0xf3, 0xe0, 0x4d, 0x84, 0xe2, 0xdb, 0x3e, 0xae, 0x60, 0x3a, 0x66, 0xd2,
- 0x52, 0xee, 0x19, 0x05, 0x06, 0x07, 0x40, 0x6c, 0x3a, 0x0f, 0x40, 0x85,
- 0x40, 0x87, 0x0f, 0x40, 0x46, 0x19, 0x46, 0x57, 0x60, 0x37, 0x6c, 0x4b,
- 0x62, 0xc2, 0x5f, 0x7a, 0xe1, 0xe0, 0x31, 0x06, 0x76, 0x65, 0xf3, 0xe0,
- 0x44, 0xa2, 0x75, 0x79, 0x61, 0xed, 0xe0, 0x31, 0x37, 0xf4, 0x07, 0x04,
- 0x03, 0x25, 0xe0, 0x4d, 0x7f, 0xf5, 0xe0, 0x4b, 0xaf, 0xec, 0xdd, 0xe4,
- 0xe5, 0x02, 0x9b, 0xf2, 0x02, 0x93, 0xee, 0x02, 0x88, 0x65, 0xf4, 0x60,
- 0x27, 0x06, 0xe0, 0x25, 0x66, 0x61, 0x74, 0x69, 0x6f, 0xee, 0xe0, 0x25,
- 0xe0, 0x61, 0xe3, 0xe0, 0x40, 0x59, 0x6c, 0x6c, 0x69, 0xe7, 0xe0, 0x2c,
- 0xf2, 0xae, 0x13, 0x06, 0x04, 0x06, 0x06, 0x08, 0x40, 0x73, 0x60, 0x29,
- 0xa2, 0x45, 0xed, 0x57, 0x40, 0x43, 0x5d, 0xc2, 0x25, 0xf4, 0x60, 0x4b,
- 0x31, 0xc0, 0x82, 0xf0, 0xe0, 0x4b, 0xad, 0xec, 0x60, 0x4b, 0x01, 0xc0,
- 0xc6, 0xe9, 0x60, 0x4a, 0xf8, 0xc1, 0x37, 0xe3, 0x60, 0x49, 0xae, 0x41,
- 0x94, 0xc0, 0x95, 0xe1, 0x60, 0x4a, 0xe0, 0xc1, 0x22, 0xf3, 0x02, 0x8b,
- 0x75, 0xf2, 0x04, 0xe0, 0x4b, 0xd0, 0x61, 0x6e, 0xe3, 0xdb, 0x8c, 0xf4,
- 0x02, 0x86, 0x69, 0x74, 0xf5, 0xe0, 0x46, 0xbc, 0x61, 0xee, 0x02, 0x89,
- 0x74, 0x63, 0x6c, 0x6f, 0x75, 0xe4, 0xe0, 0x2d, 0xb6, 0x63, 0xe5, 0x02,
- 0x8a, 0x73, 0x2e, 0x73, 0x70, 0x61, 0x77, 0xee, 0xe0, 0x28, 0x97, 0x2e,
- 0x64, 0x61, 0x74, 0xe1, 0xe0, 0x25, 0x9a, 0xe7, 0x06, 0x60, 0x4b, 0x16,
- 0xc1, 0xf0, 0x61, 0x74, 0x6c, 0x61, 0xee, 0xe0, 0x4c, 0x0c, 0xe6, 0x04,
- 0x40, 0x6a, 0x86, 0xef, 0x04, 0xe0, 0x4c, 0xf4, 0xae, 0x19, 0x06, 0x09,
- 0x04, 0x0a, 0x06, 0x06, 0x06, 0x06, 0x06, 0x08, 0x4c, 0x1b, 0x60, 0x2d,
- 0x79, 0x11, 0x4f, 0x4b, 0x41, 0x6d, 0x40, 0xbc, 0xc0, 0x52, 0xf6, 0x60,
- 0x4b, 0x6b, 0xc0, 0x43, 0xf4, 0x60, 0x4a, 0x67, 0x40, 0xb5, 0x40, 0x6d,
- 0x9f, 0xf3, 0xe0, 0x4a, 0x85, 0xee, 0x60, 0x41, 0xfc, 0x48, 0xb8, 0x40,
- 0x79, 0xc0, 0x4f, 0xec, 0x60, 0x4a, 0x5a, 0xc0, 0xc9, 0xeb, 0x60, 0x4a,
- 0xa4, 0xc0, 0xa4, 0xe8, 0x60, 0x4a, 0xf9, 0xc0, 0xc4, 0xe5, 0x60, 0x40,
- 0xc2, 0xca, 0x31, 0xe3, 0x60, 0x40, 0x49, 0xca, 0xde, 0xe2, 0x60, 0x42,
- 0xa9, 0x47, 0xbc, 0xc0, 0xbc, 0xe1, 0x60, 0x4a, 0x2a, 0x41, 0x79, 0xc0,
- 0xd2, 0x69, 0x6e, 0xe9, 0xe0, 0x3a, 0x6a, 0xae, 0x07, 0x04, 0x60, 0x39,
- 0x81, 0xd1, 0xb1, 0xed, 0xe0, 0x4a, 0x21, 0xe3, 0xe0, 0x4b, 0x89, 0xe4,
- 0x05, 0x0a, 0x2c, 0xc0, 0x40, 0x75, 0x73, 0x74, 0x72, 0xe9, 0x60, 0x40,
- 0x71, 0xc9, 0x4d, 0xe9, 0x03, 0x06, 0x88, 0x67, 0x65, 0xee, 0xe0, 0x49,
- 0xb2, 0x65, 0x2e, 0x70, 0x6f, 0xf2, 0xe0, 0x38, 0x46, 0x61, 0xee, 0x05,
- 0x08, 0xe0, 0x49, 0x8f, 0x6d, 0x61, 0x72, 0x6b, 0xe5, 0xe0, 0x45, 0x08,
- 0xe1, 0x04, 0xe0, 0x49, 0x8a, 0x70, 0x6f, 0xec, 0xe0, 0x3e, 0x93, 0xe5,
- 0x04, 0xe0, 0x3e, 0xdf, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0xad,
- 0x04, 0x09, 0x08, 0x92, 0x72, 0x65, 0x76, 0x69, 0x65, 0xf7, 0xe0, 0x48,
- 0xd5, 0x70, 0x61, 0x6e, 0x65, 0xec, 0xe0, 0x48, 0xcd, 0x69, 0x6e, 0x71,
- 0xf5, 0x02, 0x86, 0x69, 0x72, 0xf9, 0xe0, 0x48, 0xc1, 0x65, 0x73, 0xf4,
- 0xe0, 0x48, 0xbb, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0xef,
- 0xe0, 0x29, 0x32, 0xae, 0x4e, 0xc5, 0x4d, 0x76, 0x40, 0xcd, 0x60, 0x2d,
- 0xa9, 0x9f, 0xe3, 0x05, 0x04, 0xe0, 0x4b, 0xe8, 0xe8, 0xe0, 0x26, 0x1c,
- 0x2e, 0xe8, 0xe0, 0x4b, 0xae, 0xe1, 0x08, 0x06, 0x09, 0x08, 0x07, 0x08,
- 0x09, 0x86, 0x7a, 0x61, 0xf7, 0xe0, 0x2f, 0x58, 0x77, 0x61, 0x73, 0x68,
- 0x69, 0xf2, 0xe0, 0x46, 0x78, 0x74, 0x73, 0x75, 0x6b, 0xe9, 0xe0, 0x34,
- 0x76, 0x73, 0x68, 0x69, 0xeb, 0xe0, 0x2f, 0xb2, 0x6d, 0x69, 0xae, 0x60,
- 0x40, 0xa1, 0xc0, 0xba, 0xe7, 0x04, 0xe0, 0x48, 0x65, 0x61, 0xf7, 0xc8,
- 0xe9, 0x62, 0x65, 0xae, 0xe0, 0x40, 0x94, 0xae, 0x60, 0x41, 0x9f, 0x42,
- 0x91, 0xc4, 0x5f, 0xae, 0x0a, 0x06, 0x59, 0xef, 0x4e, 0x9c, 0x5c, 0xf6,
- 0xc4, 0x6c, 0xf5, 0x60, 0x49, 0x2f, 0xc0, 0xc9, 0xee, 0x60, 0x49, 0x79,
- 0x40, 0x79, 0xc1, 0x77, 0xad, 0x05, 0x04, 0x09, 0x0b, 0x91, 0x76, 0x70,
- 0xee, 0x8d, 0x74, 0x68, 0x65, 0x2d, 0x62, 0x61, 0xee, 0xd5, 0x2c, 0x64,
- 0x73, 0x6c, 0xae, 0x60, 0x48, 0x9c, 0x42, 0x31, 0xc0, 0x7d, 0xe2, 0x05,
- 0x06, 0xe0, 0x20, 0x51, 0x75, 0x74, 0xf4, 0xe0, 0x26, 0x46, 0x72, 0xe2,
- 0xe0, 0x26, 0x43, 0x61, 0x64, 0x64, 0xf2, 0xdf, 0x29, 0xed, 0x0c, 0x13,
- 0x0c, 0x04, 0x04, 0x60, 0x34, 0x65, 0x54, 0xba, 0xc1, 0xfc, 0x70, 0x65,
- 0xf2, 0x04, 0xe0, 0x44, 0xf3, 0x74, 0x72, 0x69, 0xf8, 0x04, 0xe0, 0x4b,
- 0x2b, 0x63, 0xe4, 0xda, 0xa9, 0x6d, 0xef, 0x04, 0xe0, 0x4b, 0x29, 0x62,
- 0x69, 0x6c, 0xe9, 0xcb, 0x8d, 0x69, 0xfa, 0xd1, 0xee, 0xe4, 0xe0, 0x41,
- 0x29, 0xe1, 0x05, 0x03, 0x03, 0x06, 0x89, 0xf2, 0xd1, 0xf0, 0xed, 0xda,
- 0x36, 0x6b, 0x61, 0xee, 0xe0, 0x2e, 0x8a, 0x67, 0x65, 0x61, 0x6e, 0x64,
- 0x73, 0xef, 0xc7, 0x1c, 0x62, 0x61, 0xf2, 0xc3, 0x54, 0xec, 0x09, 0x0b,
- 0x07, 0x07, 0x60, 0x38, 0x84, 0xd2, 0x54, 0x6f, 0x76, 0x65, 0x63, 0x6f,
- 0x6c, 0x6c, 0xe5, 0xe0, 0x3b, 0x26, 0x6c, 0x75, 0x73, 0xf4, 0xe0, 0x27,
- 0x6f, 0x69, 0x61, 0x64, 0x62, 0xef, 0xc1, 0x37, 0xae, 0x60, 0x44, 0xcc,
- 0xc1, 0x32, 0xeb, 0x05, 0x07, 0x03, 0x07, 0x8e, 0x75, 0x73, 0x61, 0xeb,
- 0xe0, 0x2e, 0xbf, 0x6f, 0xed, 0xa8, 0x69, 0xae, 0x60, 0x2e, 0xcd, 0xdb,
- 0x9a, 0x65, 0x64, 0x61, 0xae, 0x5e, 0x17, 0x60, 0x24, 0x3a, 0x45, 0x51,
- 0x41, 0x48, 0xa2, 0xe1, 0x06, 0x03, 0x05, 0xe0, 0x49, 0x18, 0xf7, 0xc9,
- 0x14, 0x74, 0xe1, 0xe0, 0x45, 0xfd, 0x72, 0x75, 0x67, 0xe1, 0xe0, 0x42,
- 0xb5, 0xe9, 0x05, 0x0b, 0x05, 0x06, 0x85, 0x7a, 0xf5, 0x02, 0x84, 0xee,
- 0xe0, 0x2e, 0x83, 0xeb, 0xc8, 0xb8, 0x79, 0xe1, 0xe0, 0x2e, 0x7a, 0x74,
- 0x61, 0xf4, 0xe0, 0x45, 0x32, 0x6a, 0xe9, 0xe0, 0x2e, 0x6f, 0xe4, 0x45,
- 0x70, 0xe0, 0x28, 0xfc, 0x68, 0x65, 0xf9, 0xce, 0x61, 0x67, 0x6c, 0x65,
- 0x73, 0x69, 0x61, 0xf3, 0x02, 0x81, 0x2d, 0x63, 0x61, 0x72, 0x62, 0xef,
- 0xe0, 0x31, 0xc0, 0xe6, 0x60, 0x2e, 0xc8, 0xd9, 0x45, 0xe5, 0x60, 0x3d,
- 0xaa, 0x47, 0xf5, 0xc4, 0xb3, 0xe4, 0x09, 0x06, 0x06, 0x04, 0x60, 0x3c,
- 0x70, 0xcd, 0xc1, 0x76, 0xae, 0x4b, 0xb4, 0xdf, 0x38, 0x72, 0x65, 0xf4,
- 0xe0, 0x42, 0xb8, 0x66, 0xae, 0xdb, 0x44, 0xae, 0x09, 0x07, 0x06, 0x04,
- 0x60, 0x45, 0x3d, 0xc1, 0xbe, 0x72, 0x65, 0x70, 0xec, 0xe0, 0x30, 0xd6,
- 0xec, 0x60, 0x46, 0x79, 0xc1, 0x76, 0xe9, 0xe0, 0x48, 0xcf, 0xe6, 0x02,
- 0x8a, 0x6f, 0x72, 0x67, 0x65, 0x72, 0x6f, 0xe3, 0xe0, 0x33, 0xab, 0x69,
- 0x72, 0x65, 0x77, 0x61, 0x6c, 0xec, 0xd5, 0xce, 0xe3, 0x09, 0x0a, 0x41,
- 0x39, 0x49, 0x04, 0xe0, 0x3e, 0x41, 0xf5, 0x04, 0xe0, 0x49, 0xf1, 0x72,
- 0xf5, 0xe0, 0x2d, 0xa5, 0x68, 0xe9, 0x04, 0x17, 0x19, 0x85, 0x6e, 0xef,
- 0x03, 0x04, 0x8a, 0x73, 0xe5, 0xc7, 0x7b, 0x6d, 0x69, 0x79, 0x61, 0xae,
- 0x60, 0x44, 0xb1, 0xc3, 0x51, 0x68, 0xe5, 0xd1, 0x54, 0x6b, 0xe1, 0x02,
- 0x91, 0x77, 0xe1, 0x02, 0x87, 0x6d, 0x69, 0x73, 0x61, 0xf4, 0xd1, 0x15,
- 0xae, 0x60, 0x45, 0x12, 0xc2, 0xd7, 0xe9, 0xe0, 0x3e, 0x3f, 0x68, 0x61,
- 0xf2, 0xc7, 0x4a, 0x62, 0xe1, 0xe0, 0x44, 0x5b, 0xe2, 0x08, 0x06, 0x04,
- 0x40, 0x93, 0xe0, 0x46, 0xbb, 0x78, 0x6f, 0xf3, 0xe0, 0x49, 0x55, 0x69,
- 0xe7, 0xc4, 0x85, 0x61, 0x72, 0xe1, 0x04, 0xe0, 0x43, 0xf6, 0x6b, 0x69,
- 0xae, 0x60, 0x42, 0x1b, 0x45, 0xa7, 0xab, 0xe1, 0x04, 0xe0, 0x43, 0xff,
- 0x6d, 0x61, 0x6c, 0x6c, 0x61, 0xed, 0xd2, 0x0b, 0x32, 0x33, 0xb4, 0xe0,
- 0x33, 0x7f, 0xae, 0x08, 0x60, 0x34, 0x1e, 0x44, 0x46, 0xd1, 0x07, 0xf0,
- 0xe0, 0x47, 0xce, 0xe8, 0x19, 0x2e, 0x05, 0x1d, 0x03, 0x3a, 0x0c, 0x0f,
- 0x11, 0x41, 0xbd, 0x06, 0x06, 0x17, 0x12, 0x10, 0x42, 0x24, 0x03, 0x40,
- 0xe0, 0x09, 0x14, 0xd7, 0x53, 0x1f, 0xc3, 0x07, 0x07, 0x04, 0x0a, 0xe0,
- 0x47, 0xa9, 0xf8, 0x03, 0xc0, 0xbf, 0xee, 0xc1, 0x90, 0x66, 0xe7, 0xc7,
- 0x85, 0x64, 0x6b, 0x6b, 0x69, 0x6e, 0x65, 0xee, 0xe0, 0x48, 0xda, 0xe1,
- 0x03, 0x03, 0x86, 0xf0, 0xc6, 0x7f, 0x6d, 0x6d, 0x1f, 0xc3, 0xc6, 0xdb,
- 0xe2, 0xc7, 0xab, 0x7a, 0xe3, 0xe0, 0x48, 0x24, 0xf9, 0x06, 0x0d, 0x05,
- 0xe0, 0x44, 0x58, 0xf5, 0x02, 0x85, 0x6e, 0xe4, 0xe0, 0x2c, 0xd2, 0x67,
- 0xe1, 0xe0, 0x3b, 0x50, 0x6c, 0x6c, 0xe5, 0xd4, 0x5d, 0xe1, 0xe0, 0x47,
- 0x4a, 0xf6, 0xd4, 0x6c, 0xf5, 0x09, 0x06, 0x04, 0x09, 0x11, 0x05, 0xe0,
- 0x48, 0xc9, 0xf2, 0x60, 0x31, 0x30, 0xd0, 0xe5, 0xee, 0xe0, 0x40, 0xaf,
- 0x6d, 0x61, 0x6e, 0x69, 0x74, 0xe9, 0xe0, 0x41, 0xa7, 0x69, 0x73, 0x73,
- 0x69, 0x65, 0x72, 0x2d, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x63, 0xe5, 0xe0,
- 0x45, 0x0e, 0x67, 0xe8, 0xe0, 0x3c, 0xcf, 0xae, 0x60, 0x42, 0xbd, 0x45,
- 0xe8, 0x9c, 0xf4, 0x04, 0xe0, 0x48, 0xbd, 0x74, 0x70, 0x62, 0xe9, 0xe0,
- 0x27, 0xe7, 0xf3, 0x02, 0x84, 0xe2, 0xe0, 0x3c, 0xca, 0xae, 0x60, 0x20,
- 0x77, 0x49, 0x90, 0xc7, 0x80, 0xf2, 0x06, 0x60, 0x3b, 0xf8, 0xcc, 0xa8,
- 0x61, 0x2e, 0x68, 0x65, 0x61, 0x6c, 0xf4, 0xe0, 0x47, 0xec, 0xef, 0x12,
- 0x0d, 0x05, 0x29, 0x40, 0x47, 0x22, 0x12, 0x28, 0x40, 0x6b, 0x23, 0x19,
- 0x09, 0x05, 0xe0, 0x44, 0x87, 0xf9, 0x04, 0xe0, 0x32, 0x73, 0x6c, 0x61,
- 0x6e, 0x64, 0xe5, 0xe0, 0x40, 0xf9, 0x75, 0xf3, 0xe0, 0x36, 0x29, 0xf4,
- 0x05, 0x03, 0xe0, 0x48, 0x68, 0xed, 0xd9, 0x7a, 0x65, 0xec, 0x07, 0x0c,
- 0x60, 0x3c, 0x56, 0xc9, 0x9b, 0x77, 0x69, 0x74, 0x68, 0x66, 0x6c, 0x69,
- 0x67, 0xe8, 0xe0, 0x3e, 0xb1, 0xae, 0x06, 0x60, 0x3c, 0x72, 0xca, 0xe6,
- 0xf4, 0xe0, 0x45, 0xdf, 0xf3, 0x02, 0xba, 0xf4, 0x06, 0x07, 0x28, 0xe0,
- 0x48, 0x0f, 0x79, 0x68, 0x6f, 0x73, 0xf4, 0xdf, 0xf1, 0x69, 0x6e, 0xe7,
- 0x05, 0x15, 0xe0, 0x48, 0x1a, 0xae, 0x02, 0x86, 0x6f, 0x76, 0xe8, 0xe0,
- 0x23, 0xd1, 0x6d, 0x79, 0x6a, 0x69, 0x6e, 0x6f, 0x2e, 0x72, 0xf5, 0xe0,
- 0x48, 0x0b, 0x2d, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0xf2, 0xe0, 0x2a,
- 0xad, 0x65, 0xe4, 0xd8, 0xbf, 0xf0, 0x04, 0xe0, 0x44, 0xb5, 0x69, 0xf4,
- 0xe0, 0x20, 0x56, 0xf2, 0x06, 0x04, 0x12, 0xe0, 0x36, 0xdb, 0xf4, 0xe0,
- 0x38, 0xf8, 0xef, 0x05, 0x06, 0xe0, 0x3f, 0x74, 0x6e, 0x6f, 0xe2, 0xe0,
- 0x2b, 0x6b, 0x6b, 0x61, 0xee, 0xe0, 0x35, 0xa1, 0x6e, 0xe9, 0xe0, 0x3d,
- 0x95, 0xf0, 0x02, 0x88, 0x74, 0x6f, 0xae, 0x60, 0x31, 0xe0, 0xd3, 0x28,
- 0x6c, 0x69, 0x78, 0xae, 0xe0, 0x37, 0x69, 0xee, 0x09, 0x0d, 0x05, 0x07,
- 0x60, 0x3c, 0x44, 0xc6, 0xd8, 0xea, 0x02, 0x83, 0xf9, 0xce, 0xea, 0x6f,
- 0xae, 0x60, 0x3d, 0xb6, 0xc4, 0x43, 0x67, 0xef, 0xe0, 0x3c, 0x6a, 0x65,
- 0x66, 0x6f, 0xf3, 0xe0, 0x43, 0x8a, 0x61, 0xe9, 0xe0, 0x43, 0x04, 0x6d,
- 0xe5, 0x0d, 0x04, 0x22, 0x09, 0x0f, 0x06, 0x05, 0x09, 0x07, 0x53, 0xfd,
- 0xc8, 0x0a, 0x75, 0x6e, 0xe9, 0xb2, 0xf3, 0x05, 0x06, 0xe0, 0x47, 0x86,
- 0x6b, 0x6c, 0xe5, 0xe0, 0x36, 0x31, 0xe5, 0x02, 0x84, 0xee, 0xe0, 0x36,
- 0x79, 0x63, 0x75, 0x72, 0x69, 0x74, 0xf9, 0x02, 0x83, 0xf0, 0xdf, 0xf6,
- 0x6d, 0xe1, 0xdf, 0xf2, 0x6f, 0x66, 0x66, 0x69, 0x63, 0xe5, 0xe0, 0x2e,
- 0xd4, 0x6c, 0x69, 0xee, 0x02, 0x85, 0x75, 0xf8, 0xe0, 0x33, 0xd4, 0x6b,
- 0xae, 0xe0, 0x28, 0xb5, 0x67, 0x6f, 0xef, 0xe0, 0x2e, 0x26, 0x66, 0x74,
- 0xf0, 0xd7, 0xe6, 0xe4, 0x03, 0xdc, 0x7e, 0x65, 0xf0, 0xe0, 0x37, 0xac,
- 0x62, 0x75, 0x69, 0xec, 0xe0, 0x42, 0x63, 0xae, 0xca, 0x2d, 0xec, 0x0b,
- 0x0b, 0x05, 0x60, 0x33, 0xbc, 0x4b, 0x28, 0x46, 0xb2, 0x81, 0xf4, 0x02,
- 0x85, 0x1f, 0x43, 0xe5, 0xc6, 0x77, 0xe1, 0xc6, 0x74, 0x6d, 0xe5, 0xe0,
- 0x38, 0x28, 0x64, 0x69, 0x6e, 0xe7, 0xe0, 0x44, 0xb8, 0xeb, 0x02, 0x90,
- 0xf5, 0x02, 0x88, 0x74, 0x6f, 0xae, 0x60, 0x2a, 0x04, 0xdb, 0x5f, 0x72,
- 0xf9, 0xe0, 0x42, 0x7d, 0xeb, 0x60, 0x30, 0xb0, 0xd4, 0xac, 0xe6, 0x04,
- 0xe0, 0x45, 0x72, 0xf5, 0xe0, 0x44, 0xe9, 0x63, 0xeb, 0xe0, 0x3a, 0x5e,
- 0xe2, 0x03, 0x06, 0x84, 0x1f, 0x43, 0xf8, 0xe0, 0x40, 0x0f, 0xef, 0xe0,
- 0x40, 0x0b, 0x62, 0x79, 0x2d, 0x73, 0x69, 0x74, 0xe5, 0xdc, 0xe5, 0xee,
- 0x60, 0x33, 0x9b, 0xd3, 0x3d, 0xed, 0x60, 0x45, 0x4b, 0xc1, 0x87, 0xec,
- 0x04, 0xe0, 0x42, 0x42, 0xf8, 0x02, 0x84, 0xb3, 0xe0, 0x26, 0x1a, 0xae,
- 0x04, 0xe0, 0x26, 0x13, 0x6c, 0x69, 0xf6, 0xe0, 0x46, 0x54, 0xeb, 0x06,
- 0x60, 0x44, 0xf8, 0xc1, 0xb7, 0xae, 0x04, 0xe0, 0x43, 0xd9, 0xe3, 0x60,
- 0x45, 0x7e, 0xc1, 0x25, 0xea, 0x02, 0x87, 0x65, 0x6c, 0x6d, 0xe5, 0xe0,
- 0x39, 0xcd, 0x61, 0x72, 0xf4, 0xe0, 0x3f, 0xbb, 0xe9, 0x15, 0x06, 0x24,
- 0x40, 0x4b, 0x40, 0x4f, 0x07, 0x05, 0x14, 0x10, 0x18, 0x05, 0x04, 0x40,
- 0xd1, 0x18, 0x0a, 0xe0, 0x40, 0xd0, 0x7a, 0x65, 0xee, 0xe0, 0x3c, 0x24,
- 0xf4, 0x04, 0xe0, 0x39, 0xa8, 0xe1, 0x04, 0xe0, 0x34, 0xda, 0x63, 0x68,
- 0xe9, 0x07, 0x09, 0x60, 0x3e, 0xe6, 0xc7, 0x75, 0xef, 0x02, 0x82, 0xf4,
- 0x88, 0x6d, 0x69, 0xf9, 0x84, 0x6e, 0x61, 0x6b, 0xe1, 0xe0, 0x3e, 0xe2,
- 0xf3, 0x02, 0xbc, 0x74, 0xef, 0x02, 0xb4, 0xf2, 0x02, 0x8d, 0xf9, 0x04,
- 0xe0, 0x43, 0x8c, 0x6f, 0x66, 0x73, 0x63, 0xe9, 0xe0, 0x25, 0xb0, 0xe9,
- 0x02, 0x88, 0x73, 0x63, 0xe8, 0x60, 0x3e, 0xfc, 0xc4, 0x82, 0xe3, 0x02,
- 0x87, 0x68, 0x6f, 0x75, 0xf3, 0xe0, 0x3e, 0xf0, 0x61, 0xec, 0x04, 0xe0,
- 0x43, 0x69, 0x73, 0x6f, 0x63, 0x69, 0x65, 0xf4, 0xe0, 0x3d, 0xa9, 0xe9,
- 0xe0, 0x41, 0xd1, 0xe1, 0x02, 0x85, 0x79, 0x61, 0xed, 0xc4, 0x3f, 0x6d,
- 0xe9, 0xcd, 0x1c, 0xf2, 0x02, 0x9f, 0xef, 0x08, 0x09, 0x08, 0x60, 0x3a,
- 0x5b, 0xc1, 0x2e, 0xf3, 0x04, 0xe0, 0x40, 0xb3, 0x61, 0xeb, 0xc3, 0x0a,
- 0x6e, 0x6f, 0xae, 0x4d, 0x75, 0xe0, 0x33, 0x32, 0x6b, 0x61, 0xf7, 0xc4,
- 0x19, 0xe1, 0x07, 0x04, 0x0b, 0x03, 0x04, 0x06, 0x86, 0xf9, 0xe0, 0x29,
- 0xd5, 0xf4, 0x04, 0xe0, 0x3a, 0x9f, 0x73, 0x75, 0xeb, 0xe0, 0x41, 0x3a,
- 0xf2, 0xc9, 0xc3, 0x6e, 0xe1, 0xc2, 0xdf, 0x6b, 0x61, 0xf4, 0xe0, 0x29,
- 0xe4, 0x69, 0x7a, 0x75, 0xed, 0xcd, 0x41, 0xe4, 0xc7, 0xaa, 0xf0, 0x03,
- 0xd0, 0xcc, 0xe8, 0xda, 0xe3, 0x6f, 0xeb, 0xe0, 0x3e, 0x96, 0x6e, 0xef,
- 0x03, 0x04, 0x83, 0x68, 0xe1, 0xc3, 0x4d, 0xe4, 0xc0, 0xc7, 0x2e, 0x74,
- 0xef, 0x60, 0x29, 0x0b, 0xd9, 0x4e, 0xed, 0x03, 0xcc, 0x28, 0xe5, 0x04,
- 0xe0, 0x38, 0x12, 0x73, 0x68, 0x69, 0xed, 0xe0, 0x2e, 0x80, 0xeb, 0x03,
- 0x06, 0x85, 0x6f, 0x6e, 0xe5, 0xe0, 0x40, 0x52, 0x69, 0xed, 0xe0, 0x3f,
- 0xeb, 0xe1, 0x02, 0x83, 0xf7, 0xc3, 0x5f, 0xf2, 0xc3, 0xb8, 0x6a, 0xe9,
- 0xe0, 0x33, 0xdc, 0xe8, 0xe0, 0x2c, 0x6f, 0x67, 0x61, 0x73, 0x68, 0xe9,
- 0x0d, 0x21, 0x05, 0x08, 0x17, 0x0a, 0x0c, 0x18, 0x19, 0x0c, 0x08, 0x07,
- 0x8a, 0xf9, 0x02, 0x93, 0xef, 0x02, 0x88, 0x73, 0x68, 0x69, 0x6e, 0xef,
- 0xe0, 0x3d, 0x67, 0x64, 0x6f, 0x67, 0x61, 0xf7, 0xe0, 0x29, 0x62, 0x61,
- 0x6d, 0xe1, 0x04, 0xe0, 0x37, 0x7a, 0xf4, 0xe0, 0x3f, 0x86, 0x75, 0xf2,
- 0xe0, 0x28, 0xb5, 0x74, 0x73, 0x75, 0x6e, 0xef, 0xe0, 0x3f, 0x7c, 0xf3,
- 0x02, 0x8b, 0x75, 0x6d, 0x69, 0x79, 0x6f, 0x73, 0x68, 0xe9, 0xe0, 0x43,
- 0x50, 0x68, 0x69, 0x72, 0x61, 0x6b, 0x61, 0xf7, 0xd5, 0xca, 0xef, 0x04,
- 0xe0, 0x29, 0x28, 0x6d, 0xe9, 0xe0, 0x3f, 0xda, 0xee, 0x02, 0x83, 0xe5,
- 0xcb, 0x9c, 0x61, 0x72, 0x75, 0xf3, 0xc7, 0x7f, 0xed, 0x02, 0x88, 0x75,
- 0x72, 0x61, 0x79, 0xe1, 0xe0, 0x3f, 0x3a, 0x61, 0x74, 0x73, 0xf5, 0x03,
- 0xc1, 0xce, 0x73, 0x68, 0x69, 0xed, 0xcb, 0x28, 0xeb, 0x02, 0x88, 0x75,
- 0x72, 0x75, 0x6d, 0xe5, 0xe0, 0x41, 0x93, 0xe1, 0x04, 0xe0, 0x39, 0xa9,
- 0xe7, 0x04, 0xe0, 0x37, 0x06, 0xf5, 0xe0, 0x42, 0xf2, 0x69, 0x7a, 0xf5,
- 0x04, 0xe0, 0x3a, 0xc6, 0x6d, 0xef, 0xe0, 0x3f, 0x30, 0x68, 0x69, 0x72,
- 0x6f, 0x73, 0xe8, 0xd3, 0xed, 0x63, 0x68, 0x69, 0xe3, 0xe0, 0x28, 0xe2,
- 0x61, 0x67, 0x61, 0x74, 0x73, 0x75, 0xed, 0xe0, 0x3c, 0x57, 0xae, 0x04,
- 0xe0, 0x40, 0x30, 0x66, 0x75, 0x6b, 0xf5, 0x60, 0x3a, 0xa5, 0xc4, 0xb2,
- 0xe4, 0x02, 0x84, 0x6f, 0xf2, 0xcd, 0x20, 0xe1, 0x04, 0xe0, 0x3c, 0x25,
- 0x6b, 0x61, 0xae, 0x60, 0x3a, 0x2b, 0x40, 0x59, 0x44, 0x56, 0xc4, 0x04,
- 0xe3, 0x04, 0xe0, 0x2b, 0x10, 0x68, 0x69, 0xf3, 0xc7, 0x0b, 0xae, 0x60,
- 0x3f, 0x9c, 0xc0, 0x57, 0xe7, 0xd9, 0xaa, 0xe5, 0x0d, 0x06, 0x40, 0x54,
- 0x08, 0x1a, 0x11, 0x08, 0x0d, 0x07, 0xe0, 0x30, 0x79, 0x74, 0x65, 0xed,
- 0xe0, 0x29, 0x9e, 0xf2, 0x0a, 0x0e, 0x21, 0x04, 0x06, 0x4f, 0x6f, 0xe0,
- 0x2c, 0x6d, 0x1f, 0x43, 0x78, 0x79, 0xae, 0x04, 0xe0, 0x2f, 0x6a, 0x6d,
- 0x1f, 0x43, 0xf8, 0x8c, 0xef, 0x02, 0x93, 0x79, 0xae, 0x04, 0xe0, 0x2f,
- 0x5c, 0x6d, 0x6f, 0x72, 0x65, 0x2d, 0x6f, 0x67, 0x2d, 0x72, 0x6f, 0xed,
- 0xca, 0x09, 0x6b, 0xf5, 0x04, 0xe0, 0x43, 0x3c, 0x73, 0xf3, 0xe0, 0x3d,
- 0x8b, 0xed, 0xe0, 0x38, 0x21, 0x69, 0x74, 0xe1, 0xe0, 0x2b, 0x92, 0xe5,
- 0x04, 0xe0, 0x44, 0x10, 0x2d, 0x66, 0x6f, 0x72, 0x2d, 0x6d, 0x6f, 0xf2,
- 0xe0, 0x34, 0x46, 0x70, 0x66, 0x6f, 0x72, 0xe7, 0xe0, 0x2e, 0xf6, 0xed,
- 0x03, 0x03, 0x87, 0xf3, 0xd9, 0x95, 0x6e, 0xe5, 0x60, 0x3f, 0xd1, 0xc2,
- 0x9c, 0x62, 0x79, 0x67, 0x64, 0x73, 0x66, 0x6f, 0x72, 0x62, 0xf5, 0xd4,
- 0x33, 0xec, 0x06, 0x5d, 0xd9, 0xe0, 0x24, 0x74, 0x73, 0x69, 0x6e, 0x6b,
- 0xe9, 0x60, 0x41, 0x1e, 0xc2, 0xb9, 0x6b, 0x69, 0x6e, 0x61, 0xee, 0xe0,
- 0x3e, 0xa5, 0x69, 0x6d, 0x61, 0x74, 0x75, 0x6e, 0x64, 0x75, 0x68, 0xf2,
- 0xe0, 0x2e, 0x46, 0x67, 0x75, 0x72, 0xe9, 0xe0, 0x3b, 0xd4, 0xe1, 0x02,
- 0x84, 0xf6, 0xe0, 0x3b, 0x78, 0x6c, 0x74, 0xe8, 0x06, 0x05, 0x07, 0xe0,
- 0x43, 0x9a, 0x63, 0xe1, 0xe0, 0x40, 0xdb, 0xae, 0x60, 0x3d, 0x30, 0x43,
- 0xb8, 0xa6, 0x2d, 0x63, 0x61, 0x72, 0x65, 0x72, 0x65, 0x66, 0x6f, 0xf2,
- 0xe0, 0x3a, 0x43, 0x64, 0x66, 0xe3, 0x60, 0x21, 0x65, 0xe0, 0x22, 0x25,
- 0xe2, 0x04, 0xe0, 0x42, 0x02, 0x2e, 0xe3, 0x04, 0xe0, 0x42, 0x4e, 0x6c,
- 0x64, 0x6d, 0x61, 0x69, 0xec, 0xe0, 0x42, 0xe9, 0xe1, 0x17, 0x04, 0x10,
- 0x06, 0x0a, 0x21, 0x3b, 0x23, 0x0d, 0x40, 0x47, 0x40, 0x58, 0x14, 0x29,
- 0x0a, 0x0f, 0x08, 0x0c, 0x21, 0xe0, 0x3c, 0xf8, 0xfa, 0xe0, 0x26, 0xe0,
- 0x79, 0xe1, 0x02, 0x87, 0x73, 0x68, 0x69, 0xed, 0xe0, 0x3d, 0xaf, 0x6b,
- 0x61, 0xf7, 0xca, 0x54, 0x77, 0x61, 0xe9, 0xe0, 0x37, 0x6c, 0xf5, 0x04,
- 0xe0, 0x40, 0xd7, 0x67, 0xe5, 0xe0, 0x2c, 0xe4, 0xf4, 0x03, 0x07, 0x8a,
- 0x74, 0x66, 0x6a, 0x65, 0xec, 0xcd, 0xb6, 0x73, 0x75, 0x6b, 0x61, 0x69,
- 0x63, 0xe8, 0xe0, 0x37, 0xd7, 0xef, 0x02, 0x85, 0x79, 0x61, 0xed, 0xca,
- 0x0b, 0x67, 0xe1, 0xca, 0x06, 0xf3, 0x05, 0x10, 0x1b, 0xc8, 0x35, 0xf5,
- 0x02, 0x8a, 0x72, 0xe1, 0x04, 0xe0, 0x41, 0x9c, 0xad, 0xe0, 0x34, 0x6f,
- 0xe4, 0xc9, 0xf1, 0xe8, 0x02, 0x91, 0xe9, 0x02, 0x88, 0xed, 0x03, 0xd3,
- 0xa9, 0x6f, 0xf4, 0xc5, 0x91, 0x6b, 0x61, 0x6d, 0xe9, 0xc5, 0x41, 0x62,
- 0x61, 0x6e, 0xe7, 0xe0, 0x32, 0x01, 0x61, 0xed, 0x04, 0xe0, 0x2b, 0xcf,
- 0xe9, 0xe0, 0x26, 0xe7, 0xf2, 0x06, 0x0b, 0x06, 0x05, 0xce, 0x13, 0x76,
- 0x65, 0x73, 0x74, 0x63, 0x65, 0x6c, 0x65, 0xe2, 0xdf, 0x55, 0x69, 0x6d,
- 0xe1, 0xe0, 0x3e, 0x15, 0x65, 0xe9, 0xe0, 0x3e, 0xcb, 0xe1, 0x60, 0x37,
- 0x19, 0xc8, 0x8b, 0xf0, 0x02, 0x85, 0x70, 0x6f, 0xf5, 0xdc, 0xc0, 0x6d,
- 0xe9, 0xe0, 0x37, 0x0e, 0xee, 0x05, 0x04, 0x09, 0x0d, 0x93, 0xf9, 0xe0,
- 0x26, 0xd3, 0xee, 0x03, 0xc9, 0xd7, 0x61, 0xee, 0xe0, 0x40, 0xca, 0xe7,
- 0x02, 0x85, 0x6f, 0xf5, 0xe0, 0x40, 0xd9, 0x67, 0x6c, 0xe9, 0xc5, 0xe8,
- 0xe4, 0x05, 0x04, 0xe0, 0x25, 0xff, 0xf3, 0xe0, 0x37, 0xce, 0x63, 0x72,
- 0x61, 0x66, 0x74, 0xe5, 0xe0, 0x2c, 0xc7, 0xe1, 0x04, 0xe0, 0x37, 0x38,
- 0xed, 0x02, 0x88, 0x69, 0x67, 0x61, 0x77, 0xe1, 0xe0, 0x40, 0x91, 0x61,
- 0xeb, 0xc9, 0xe5, 0xed, 0x05, 0x05, 0x14, 0x09, 0xa5, 0x75, 0xf2, 0xe0,
- 0x3c, 0xa0, 0xed, 0x02, 0x88, 0x65, 0x72, 0x66, 0x65, 0xf3, 0xe0, 0x3a,
- 0xce, 0x61, 0x72, 0x66, 0x65, 0x61, 0xf3, 0xe0, 0x3c, 0x6e, 0x62, 0x75,
- 0x72, 0xe7, 0x60, 0x3f, 0x85, 0xc2, 0xb9, 0xe1, 0x04, 0x0d, 0x06, 0x88,
- 0xf4, 0x02, 0x85, 0x6f, 0xee, 0xe0, 0x3d, 0xa1, 0x61, 0xed, 0xe0, 0x37,
- 0xc1, 0xf2, 0x60, 0x36, 0x81, 0xca, 0x1e, 0x6d, 0x61, 0x74, 0x73, 0xf5,
- 0xe0, 0x38, 0x1e, 0x64, 0xe1, 0xe0, 0x3c, 0x85, 0x2d, 0x72, 0x61, 0x64,
- 0x69, 0x6f, 0x2d, 0xef, 0xe0, 0x35, 0xcf, 0xec, 0x05, 0x07, 0x03, 0xc7,
- 0x7d, 0x6c, 0x6f, 0x66, 0x66, 0xe1, 0xde, 0x61, 0xe6, 0xca, 0xf7, 0xe4,
- 0xe0, 0x32, 0xf7, 0xeb, 0x03, 0x12, 0x8d, 0xf5, 0x03, 0x06, 0x84, 0x73,
- 0x61, 0xee, 0xe0, 0x3a, 0x2f, 0xe9, 0xe0, 0x3a, 0x2b, 0xe2, 0xe0, 0x25,
- 0xd9, 0xef, 0x02, 0x84, 0xee, 0xe0, 0x34, 0x0e, 0x64, 0x61, 0xf4, 0xe0,
- 0x25, 0x53, 0x61, 0x74, 0xe1, 0xe0, 0x2a, 0x7f, 0xe9, 0x04, 0xe0, 0x40,
- 0x7d, 0x62, 0x61, 0xf2, 0xc9, 0x27, 0xe7, 0x05, 0x04, 0xe0, 0x36, 0x3d,
- 0xe9, 0xe0, 0x3f, 0xac, 0x65, 0x62, 0xef, 0xcd, 0x0d, 0x65, 0x62, 0x61,
- 0x72, 0xf5, 0xe0, 0x3d, 0x3c, 0xe4, 0x02, 0x83, 0xf3, 0xc5, 0xb5, 0x61,
- 0x6e, 0xef, 0xe0, 0x3d, 0x0a, 0xe3, 0x02, 0x9a, 0x68, 0xe9, 0x04, 0x08,
- 0x05, 0x83, 0x72, 0x6f, 0x67, 0x61, 0x74, 0xe1, 0xdb, 0xa1, 0x6f, 0xea,
- 0xe0, 0x3e, 0x42, 0xee, 0xc3, 0xdb, 0xea, 0xe0, 0x3b, 0xd2, 0xe3, 0xe0,
- 0x32, 0x44, 0xe2, 0x05, 0x04, 0xe0, 0x35, 0xe1, 0xed, 0xe0, 0x35, 0xd9,
- 0x69, 0x6b, 0xe9, 0xe0, 0x3f, 0xa1, 0xe7, 0x27, 0x30, 0x04, 0x1b, 0x04,
- 0x0b, 0x0b, 0x40, 0x65, 0x40, 0x6f, 0x40, 0xba, 0x42, 0x45, 0x0d, 0x15,
- 0x40, 0x59, 0x1d, 0x40, 0xa7, 0x08, 0x09, 0x40, 0x9e, 0x1c, 0x04, 0x0a,
- 0x40, 0x8d, 0x05, 0x58, 0xf5, 0x56, 0xa1, 0x49, 0x13, 0xa8, 0x1f, 0xc3,
- 0x02, 0x9a, 0x7c, 0x6e, 0x73, 0x74, 0x69, 0xe7, 0x02, 0x88, 0x6c, 0x69,
- 0x65, 0x66, 0x65, 0xf2, 0xd6, 0x2f, 0x62, 0x65, 0x73, 0x74, 0x65, 0x6c,
- 0x6c, 0xe5, 0xd6, 0x25, 0xe1, 0x04, 0x06, 0xc6, 0xb4, 0x1f, 0x45, 0x4b,
- 0xe7, 0xc6, 0x63, 0x6c, 0x73, 0x1f, 0xc3, 0xe0, 0x3b, 0x43, 0xfa, 0xe0,
- 0x2d, 0xd8, 0xf9, 0x05, 0x07, 0xe0, 0x41, 0x05, 0x6f, 0x6b, 0x75, 0xf4,
- 0xe0, 0x36, 0xf4, 0x65, 0x6f, 0x6e, 0xe7, 0x05, 0x60, 0x23, 0xff, 0x85,
- 0x67, 0xe9, 0xe0, 0x29, 0xd2, 0xf8, 0xe0, 0x2d, 0xb9, 0xf7, 0x04, 0xe0,
- 0x40, 0xee, 0x61, 0x6e, 0x67, 0xea, 0xdb, 0x20, 0x76, 0xae, 0x04, 0xe0,
- 0x40, 0xd2, 0xe1, 0x60, 0x3f, 0x2a, 0xba, 0xf5, 0x13, 0x09, 0x04, 0x0b,
- 0x04, 0x0b, 0x0b, 0x07, 0x04, 0x05, 0x4e, 0x57, 0x60, 0x29, 0xe2, 0x42,
- 0xc9, 0xc5, 0x85, 0x73, 0x68, 0x69, 0x6b, 0x61, 0xed, 0xe0, 0x3c, 0x50,
- 0xf2, 0xe0, 0x3f, 0xcc, 0x6f, 0x76, 0x64, 0x61, 0x67, 0x65, 0x61, 0x69,
- 0xe4, 0xd9, 0xc6, 0xec, 0xe0, 0x31, 0xaf, 0xea, 0x03, 0xc3, 0x3c, 0x61,
- 0x72, 0x61, 0xf4, 0xe0, 0x3f, 0x78, 0xe9, 0x02, 0x84, 0x74, 0xe1, 0xdd,
- 0x9c, 0xe4, 0xe0, 0x3f, 0x2c, 0x65, 0x72, 0x6e, 0xf3, 0xe0, 0x2e, 0xe9,
- 0xe3, 0xe0, 0x34, 0xb0, 0x62, 0xae, 0xe0, 0x2e, 0xb9, 0xe1, 0x02, 0x86,
- 0x72, 0x64, 0xe9, 0xe0, 0x3c, 0x72, 0x6d, 0x2e, 0xe7, 0xe0, 0x3f, 0x88,
- 0xf3, 0x07, 0x06, 0x60, 0x33, 0xe6, 0xcc, 0x84, 0x6a, 0x2e, 0xe2, 0xe0,
- 0x3d, 0x48, 0xae, 0x10, 0x05, 0x05, 0x0d, 0x04, 0x0e, 0x06, 0x04, 0x0a,
- 0x06, 0x04, 0x60, 0x38, 0x34, 0xc3, 0x5c, 0xf6, 0x24, 0xe0, 0x3a, 0x5e,
- 0xf4, 0x60, 0x34, 0xb2, 0x84, 0xf3, 0x05, 0x15, 0xe0, 0x38, 0xb4, 0x76,
- 0x61, 0x6c, 0xe2, 0xe0, 0x39, 0xe5, 0xf2, 0xe0, 0x39, 0x67, 0xef, 0x05,
- 0x04, 0xe0, 0x39, 0x5a, 0xf3, 0xe0, 0x38, 0x60, 0xe6, 0xe0, 0x3e, 0xac,
- 0xee, 0x60, 0x38, 0xaf, 0xc0, 0xa6, 0xed, 0xe0, 0x34, 0x8c, 0x6a, 0x61,
- 0x6e, 0x2d, 0x6d, 0x61, 0xf9, 0xe0, 0x31, 0x1e, 0xe8, 0x60, 0x34, 0x7a,
- 0xc4, 0xc7, 0xe6, 0xe0, 0x34, 0x74, 0xe1, 0x04, 0xe0, 0x3a, 0x37, 0xe8,
- 0xe0, 0x3e, 0x85, 0xf2, 0x0b, 0x05, 0x04, 0x40, 0x40, 0x13, 0x11, 0x37,
- 0xe0, 0x3f, 0x59, 0xf5, 0x60, 0x3e, 0x74, 0xbc, 0xf0, 0xe0, 0x34, 0x1c,
- 0xef, 0x06, 0x06, 0x13, 0x06, 0x0b, 0x8c, 0x7a, 0x6e, 0xf9, 0xe0, 0x3c,
- 0x5f, 0xf5, 0x02, 0x86, 0xf0, 0x60, 0x3d, 0x04, 0xc2, 0xdf, 0x6e, 0x64,
- 0x68, 0x61, 0x6e, 0x64, 0xec, 0xe0, 0x30, 0xce, 0x73, 0x73, 0xe5, 0xe0,
- 0x3b, 0x80, 0xee, 0x04, 0xe0, 0x39, 0x1a, 0x64, 0x61, 0xf2, 0xe0, 0x3b,
- 0x83, 0x6b, 0x73, 0x2d, 0x74, 0xe8, 0x04, 0xe0, 0x2f, 0xf8, 0xe9, 0xd4,
- 0x73, 0xe3, 0xd8, 0x7b, 0xe9, 0x03, 0x08, 0x84, 0x77, 0x2e, 0x67, 0x6f,
- 0xf6, 0xe0, 0x3b, 0x1b, 0xf0, 0xe0, 0x3e, 0x39, 0xed, 0xca, 0xfb, 0xe5,
- 0x03, 0x05, 0x84, 0x74, 0xe1, 0xe0, 0x3b, 0xd8, 0xe5, 0xe0, 0x3e, 0x6c,
- 0xe1, 0xe0, 0x2c, 0xce, 0xe1, 0x09, 0x09, 0x0a, 0x15, 0x60, 0x2a, 0x60,
- 0xc6, 0x45, 0xf4, 0x04, 0xe0, 0x30, 0x7d, 0xe9, 0xe0, 0x3d, 0x1e, 0x70,
- 0xe8, 0x04, 0xe0, 0x37, 0xc7, 0x6f, 0xf8, 0xc1, 0xdd, 0xee, 0x06, 0x05,
- 0x60, 0x3d, 0xdf, 0x81, 0x76, 0xe9, 0xe0, 0x39, 0x87, 0x64, 0x72, 0x61,
- 0x70, 0x69, 0xe4, 0xe0, 0x38, 0x27, 0x6a, 0x65, 0xf7, 0xc2, 0x5a, 0xae,
- 0x60, 0x39, 0x4d, 0x44, 0x10, 0x40, 0x59, 0xc1, 0x9b, 0xef, 0x10, 0x40,
- 0xfc, 0x1a, 0x2d, 0x13, 0x12, 0x06, 0x1c, 0x0e, 0x1a, 0x0a, 0x06, 0x0c,
- 0x0d, 0xba, 0xf6, 0x06, 0x03, 0x04, 0xe0, 0x3f, 0x30, 0xf4, 0xc4, 0x16,
- 0x65, 0xf2, 0xcf, 0x4b, 0xae, 0x1f, 0x08, 0x06, 0x0c, 0x13, 0x0d, 0x0d,
- 0x14, 0x11, 0x0d, 0x0c, 0x04, 0x0c, 0x0a, 0x0e, 0x12, 0x51, 0x05, 0x4b,
- 0x4c, 0x04, 0x3d, 0x40, 0x48, 0x5a, 0xc1, 0x44, 0x1f, 0x15, 0xc0, 0x48,
- 0xf6, 0x60, 0x33, 0x27, 0x4a, 0x7a, 0xc0, 0x43, 0xf5, 0x60, 0x3c, 0xa8,
- 0xc0, 0xc6, 0xf4, 0x60, 0x3c, 0x98, 0x1e, 0x03, 0x0f, 0x40, 0x82, 0x3a,
- 0x33, 0x9f, 0xf3, 0x51, 0x18, 0x60, 0x23, 0xe8, 0x42, 0x90, 0x45, 0x03,
- 0x1a, 0x03, 0x15, 0x40, 0x92, 0x05, 0x1c, 0xc1, 0x7c, 0xf0, 0x60, 0x3c,
- 0x80, 0x03, 0x17, 0x18, 0x40, 0x79, 0x19, 0x40, 0x54, 0x9f, 0xee, 0x08,
- 0x60, 0x3d, 0x83, 0x40, 0x97, 0xc0, 0xb2, 0xe3, 0xe0, 0x2d, 0xf9, 0xed,
- 0x60, 0x3b, 0x22, 0x41, 0x3a, 0x03, 0x07, 0x03, 0x17, 0x18, 0x40, 0x97,
- 0x1c, 0x0f, 0x24, 0x1f, 0x38, 0xc0, 0xf2, 0xec, 0x60, 0x32, 0xcc, 0x41,
- 0xf3, 0x46, 0x4f, 0x41, 0x44, 0x03, 0x2f, 0x40, 0x79, 0x1e, 0xc0, 0x4f,
- 0xeb, 0x60, 0x3c, 0x37, 0x03, 0x1e, 0x39, 0x40, 0x83, 0x40, 0x64, 0xc1,
- 0x2a, 0xe9, 0x5d, 0x2b, 0x5f, 0x09, 0x1a, 0x40, 0x91, 0x40, 0x49, 0x24,
- 0x9f, 0xe8, 0xe0, 0x3c, 0x2b, 0xe7, 0x60, 0x3c, 0x41, 0x15, 0x1e, 0x40,
- 0x74, 0x30, 0x24, 0x1f, 0xb8, 0xe5, 0x60, 0x32, 0x92, 0x4a, 0x31, 0x40,
- 0x49, 0xc1, 0x6d, 0xe3, 0x60, 0x37, 0x0b, 0x45, 0x1a, 0x03, 0x03, 0x15,
- 0x40, 0xb3, 0x40, 0x52, 0xb8, 0xe2, 0x60, 0x33, 0x98, 0x40, 0xd5, 0x47,
- 0x89, 0x0a, 0x17, 0x1b, 0x40, 0x79, 0x19, 0x05, 0x40, 0x4f, 0x9f, 0xe1,
- 0x60, 0x32, 0x68, 0x41, 0x1e, 0x48, 0x5e, 0x0a, 0x1a, 0x40, 0xda, 0x24,
- 0xc0, 0x57, 0xf5, 0x02, 0x91, 0x76, 0xae, 0x0b, 0x60, 0x32, 0x53, 0x1a,
- 0x41, 0x35, 0x46, 0xce, 0xc0, 0x56, 0xed, 0xe0, 0x3b, 0xe9, 0x70, 0x69,
- 0xec, 0xe0, 0x21, 0xd4, 0xf4, 0x08, 0x05, 0x08, 0x04, 0x05, 0xe0, 0x3e,
- 0x09, 0x73, 0xf5, 0xe0, 0x38, 0x8b, 0x70, 0x61, 0x6e, 0x74, 0x68, 0xe5,
- 0xcd, 0x8b, 0xef, 0xe0, 0x22, 0x1d, 0x65, 0x6d, 0xe2, 0xc5, 0x6e, 0x64,
- 0x6e, 0x73, 0xae, 0x04, 0xe0, 0x3b, 0x30, 0xe3, 0x60, 0x3d, 0x53, 0xc0,
- 0xa7, 0xf3, 0x04, 0x05, 0xcb, 0xaa, 0x68, 0xe9, 0xe0, 0x36, 0xee, 0xe5,
- 0x04, 0xe0, 0x36, 0x07, 0xee, 0xe0, 0x39, 0xd1, 0xf2, 0x05, 0x07, 0xe0,
- 0x25, 0x55, 0x6c, 0x69, 0x63, 0xe5, 0xe0, 0x39, 0x4e, 0x69, 0xfa, 0xe0,
- 0x37, 0x91, 0xf0, 0x4b, 0x8e, 0xe0, 0x32, 0x47, 0xef, 0x05, 0x10, 0xe0,
- 0x3d, 0xba, 0xe7, 0x04, 0xe0, 0x3d, 0xc5, 0x6c, 0xe5, 0x06, 0x42, 0x51,
- 0xe0, 0x3b, 0x6c, 0xe3, 0xcc, 0xc4, 0x64, 0x79, 0xe5, 0xe0, 0x2b, 0xdb,
- 0xee, 0x06, 0x4b, 0x66, 0xe0, 0x23, 0x09, 0x6f, 0x68, 0x65, 0xae, 0xe0,
- 0x35, 0x08, 0xec, 0x05, 0x0b, 0xe0, 0x3c, 0x0e, 0xe6, 0x04, 0xe0, 0x3d,
- 0x9b, 0x66, 0x61, 0x6e, 0xae, 0xde, 0x81, 0xe4, 0x04, 0xe0, 0x3d, 0x90,
- 0x70, 0xef, 0xcc, 0x70, 0xeb, 0x03, 0xcb, 0x41, 0x61, 0x73, 0xe5, 0xe0,
- 0x2f, 0xca, 0x6a, 0x6f, 0x6d, 0xe5, 0xd7, 0x8f, 0xe9, 0x02, 0x83, 0xf0,
- 0xd8, 0x63, 0x61, 0x6e, 0xe9, 0xe0, 0x34, 0x63, 0xe4, 0x02, 0x84, 0xef,
- 0xe0, 0x35, 0x05, 0x61, 0x64, 0xe4, 0xe0, 0x3b, 0x36, 0xe2, 0x02, 0x84,
- 0xef, 0xe0, 0x33, 0x00, 0xae, 0x11, 0x04, 0x07, 0x04, 0x04, 0x04, 0x06,
- 0x5f, 0xe2, 0x4b, 0x6f, 0x47, 0x0e, 0x48, 0x20, 0xc0, 0xbb, 0xf3, 0xe0,
- 0x39, 0xa3, 0xf0, 0x60, 0x3a, 0xe6, 0x40, 0xc6, 0xab, 0xed, 0xe0, 0x35,
- 0xd9, 0xe8, 0xe0, 0x3c, 0x0f, 0xe7, 0xe0, 0x3b, 0x7f, 0xe5, 0x60, 0x31,
- 0x4a, 0xc9, 0x86, 0xe3, 0xe0, 0x3a, 0xe4, 0xae, 0x0f, 0x04, 0x06, 0x50,
- 0x29, 0x5b, 0x78, 0x4b, 0x5d, 0x03, 0x43, 0x83, 0x35, 0xc0, 0xb4, 0xf5,
- 0xe0, 0x3d, 0x17, 0xe9, 0x60, 0x3a, 0xcf, 0xc0, 0x8e, 0x64, 0x79, 0xee,
- 0xd2, 0x40, 0xee, 0x04, 0xe0, 0x3d, 0x05, 0x69, 0x65, 0x7a, 0x6e, 0xef,
- 0xe0, 0x38, 0x70, 0xed, 0x0b, 0x05, 0x4d, 0xfc, 0x60, 0x27, 0x8b, 0x45,
- 0xe8, 0xc1, 0x7d, 0x69, 0xee, 0xe0, 0x2e, 0x80, 0xe2, 0xe0, 0x3b, 0x4d,
- 0xec, 0x08, 0x05, 0x27, 0x15, 0x08, 0xe0, 0x3c, 0x96, 0x75, 0xe7, 0xe0,
- 0x38, 0xfa, 0xef, 0x04, 0x05, 0x05, 0x84, 0x70, 0xf0, 0xe0, 0x2d, 0xd2,
- 0x6f, 0xed, 0xe0, 0x34, 0x94, 0xe7, 0xe0, 0x30, 0x06, 0xe2, 0x04, 0xe0,
- 0x3b, 0x45, 0x61, 0xec, 0x04, 0xe0, 0x3c, 0xbc, 0xae, 0x04, 0xe0, 0x3b,
- 0x55, 0xf3, 0xe0, 0x3b, 0x45, 0xe9, 0x03, 0x07, 0x86, 0x77, 0x69, 0x63,
- 0xe5, 0xe0, 0x2b, 0x54, 0x74, 0x63, 0xe8, 0xe0, 0x26, 0xab, 0xe4, 0xe0,
- 0x2d, 0x98, 0xe5, 0x04, 0xe0, 0x3c, 0x99, 0xe5, 0xc0, 0xab, 0x61, 0xf3,
- 0x60, 0x26, 0x11, 0xd3, 0xca, 0xea, 0x03, 0x05, 0x83, 0x1f, 0x43, 0xf8,
- 0xc1, 0xdb, 0xef, 0xc1, 0xd8, 0xe5, 0x04, 0x08, 0xc2, 0x53, 0xf2, 0x03,
- 0xc7, 0xd2, 0xe4, 0xe0, 0x24, 0xb7, 0xed, 0xe0, 0x38, 0x50, 0xe9, 0x0e,
- 0x06, 0x40, 0x43, 0x07, 0x16, 0x0f, 0x05, 0x0c, 0x49, 0x0b, 0xe0, 0x32,
- 0xd2, 0xf6, 0x60, 0x27, 0x12, 0xc9, 0x53, 0xf4, 0x05, 0x05, 0x06, 0x12,
- 0x88, 0x70, 0x61, 0x67, 0xe5, 0x9c, 0x6c, 0x61, 0xe2, 0xe0, 0x3b, 0x54,
- 0x68, 0x75, 0xe2, 0x06, 0x60, 0x32, 0x94, 0xc8, 0xb4, 0x70, 0x72, 0x65,
- 0x76, 0x69, 0x65, 0xf7, 0xd7, 0x7b, 0x61, 0x70, 0x70, 0x2e, 0xf3, 0xe0,
- 0x3b, 0xdd, 0xad, 0x02, 0x86, 0x72, 0x65, 0x70, 0xef, 0xd5, 0x9b, 0x70,
- 0x61, 0x67, 0x65, 0x73, 0x2e, 0x72, 0x69, 0x74, 0x2e, 0x65, 0xe4, 0xe0,
- 0x3b, 0x95, 0x72, 0xec, 0x60, 0x26, 0x62, 0xcd, 0x7c, 0xee, 0x02, 0x8e,
- 0xef, 0x02, 0x85, 0x7a, 0xe1, 0xe0, 0x37, 0x99, 0x77, 0x61, 0xee, 0xe0,
- 0x37, 0x93, 0x61, 0xee, 0xe0, 0x33, 0x99, 0x6c, 0x64, 0x65, 0x73, 0xeb,
- 0x04, 0xe0, 0x35, 0x19, 0x1f, 0x43, 0xe5, 0xe0, 0x35, 0x17, 0x69, 0xfa,
- 0xe0, 0x34, 0x68, 0xe6, 0x04, 0xe0, 0x38, 0xe4, 0x75, 0xae, 0x60, 0x33,
- 0x7c, 0xc6, 0xc4, 0xe5, 0x02, 0x85, 0x73, 0xf3, 0xe0, 0x26, 0x5e, 0x68,
- 0x74, 0x61, 0x76, 0x75, 0x6f, 0xe1, 0xe0, 0x2d, 0x06, 0xe8, 0x04, 0xe0,
- 0x3b, 0xc6, 0xef, 0xd6, 0xfd, 0xe7, 0x4c, 0x2d, 0x55, 0xf9, 0x54, 0xe9,
- 0xc4, 0xb3, 0xe5, 0x0e, 0x0a, 0x23, 0x34, 0x08, 0x07, 0x09, 0x60, 0x39,
- 0x36, 0x40, 0x63, 0xc1, 0x99, 0xf4, 0x02, 0x84, 0xf3, 0xe0, 0x25, 0x5c,
- 0xed, 0xc4, 0xa5, 0xef, 0x07, 0x0e, 0x60, 0x33, 0x15, 0xc7, 0x2a, 0x72,
- 0xe7, 0x04, 0xe0, 0x3a, 0x25, 0x69, 0x61, 0xae, 0x60, 0x38, 0xd8, 0xc0,
- 0xd6, 0x6d, 0x65, 0x74, 0x72, 0x65, 0x2d, 0x65, 0x78, 0x70, 0xe5, 0xe0,
- 0x37, 0xbc, 0xee, 0x04, 0x13, 0x09, 0x84, 0xf4, 0x08, 0x60, 0x26, 0x20,
- 0x48, 0x34, 0xcd, 0x1c, 0x6c, 0x65, 0x6e, 0x74, 0x61, 0x70, 0xe9, 0xe0,
- 0x3a, 0x5c, 0xef, 0x04, 0xe0, 0x35, 0x1a, 0xf6, 0xe0, 0x35, 0x19, 0x6b,
- 0xe1, 0xc2, 0x37, 0xae, 0x08, 0x60, 0x2e, 0x05, 0x45, 0x07, 0xc7, 0x18,
- 0xee, 0x60, 0x38, 0x80, 0xc0, 0x63, 0x6d, 0x6f, 0x6c, 0x6f, 0xe7, 0xe0,
- 0x31, 0x1e, 0x69, 0x73, 0x65, 0xe9, 0xe0, 0x35, 0x8e, 0x68, 0x69, 0x72,
- 0x6e, 0x2e, 0xee, 0xe0, 0x2c, 0xbd, 0xe5, 0x02, 0x86, 0x6c, 0x76, 0x69,
- 0xee, 0xdc, 0xef, 0xeb, 0x02, 0x86, 0x67, 0x61, 0x6c, 0xe1, 0xdc, 0x93,
- 0xae, 0xe0, 0x34, 0xaf, 0xe4, 0x09, 0x07, 0x60, 0x27, 0xce, 0x52, 0x12,
- 0xc1, 0x2b, 0x79, 0x6e, 0x69, 0xe1, 0xe0, 0x29, 0xb7, 0xe1, 0x04, 0xe0,
- 0x29, 0xaf, 0x6e, 0x73, 0xeb, 0xe0, 0x29, 0xac, 0xe3, 0xe0, 0x39, 0x64,
- 0xe2, 0x05, 0x60, 0x3a, 0xd2, 0xa4, 0xe9, 0xe0, 0x38, 0x89, 0xe1, 0x10,
- 0x08, 0x10, 0x06, 0x0f, 0x32, 0x19, 0x60, 0x34, 0xe4, 0x43, 0x55, 0x40,
- 0xa1, 0xc1, 0x8f, 0xf5, 0x03, 0xc0, 0xba, 0xec, 0xe0, 0x2c, 0x05, 0x74,
- 0x65, 0x77, 0x61, 0x79, 0xae, 0x04, 0xe0, 0x38, 0x17, 0x64, 0x65, 0xf6,
- 0xe0, 0x3a, 0xba, 0x72, 0x64, 0xe5, 0xe0, 0x29, 0x08, 0x6e, 0xe7, 0x02,
- 0x83, 0xf7, 0xd4, 0xf0, 0x61, 0x76, 0x69, 0x69, 0xeb, 0xe0, 0x34, 0xe1,
- 0xed, 0x06, 0x05, 0x1f, 0xe0, 0x35, 0x57, 0x76, 0xe9, 0xe0, 0x30, 0x64,
- 0xe5, 0x07, 0x06, 0x4e, 0x0a, 0xe0, 0x2c, 0x90, 0xf3, 0x60, 0x39, 0xaa,
- 0xc0, 0xf5, 0xad, 0x02, 0x88, 0x73, 0x65, 0x72, 0x76, 0x65, 0xf2, 0xd6,
- 0x10, 0x68, 0x6f, 0xf3, 0xe0, 0x31, 0x39, 0x61, 0x67, 0x6f, 0xf2, 0xe0,
- 0x35, 0x5c, 0xec, 0x05, 0x04, 0xe0, 0x3a, 0x78, 0xf3, 0xe0, 0x34, 0xa5,
- 0xec, 0x05, 0x04, 0xe0, 0x38, 0xf1, 0xf5, 0xe0, 0x38, 0xe2, 0x65, 0xf2,
- 0xe0, 0x37, 0xaf, 0xe9, 0xe0, 0x2b, 0x9d, 0x31, 0xb2, 0xe0, 0x39, 0x17,
- 0xae, 0x06, 0x60, 0x29, 0x50, 0xd1, 0x07, 0x76, 0x62, 0x72, 0x70, 0x6c,
- 0x73, 0xe2, 0xcd, 0x43, 0xe6, 0x1c, 0x08, 0x12, 0x01, 0x04, 0x41, 0xae,
- 0x0e, 0x03, 0x42, 0x12, 0x40, 0xe8, 0x18, 0x0c, 0x40, 0x95, 0x04, 0x11,
- 0x41, 0x19, 0x1e, 0x40, 0x6b, 0x04, 0x0a, 0xc6, 0xc0, 0x1f, 0x43, 0x78,
- 0x72, 0xe4, 0xe0, 0x38, 0xa6, 0xf9, 0x05, 0x06, 0xe0, 0x38, 0x0d, 0x72,
- 0x65, 0xf3, 0xe0, 0x33, 0x46, 0x6c, 0x6b, 0x65, 0xf3, 0xc4, 0xac, 0x76,
- 0xe7, 0xe0, 0x38, 0x1b, 0xf5, 0x0c, 0x31, 0x0b, 0x29, 0x0f, 0x34, 0x40,
- 0x59, 0x40, 0x6d, 0x19, 0x8b, 0xf4, 0x05, 0x17, 0x06, 0x04, 0x85, 0x75,
- 0x72, 0xe5, 0x04, 0x05, 0xc8, 0x5e, 0x6d, 0x61, 0x69, 0xec, 0x85, 0x68,
- 0x6f, 0x73, 0x74, 0x69, 0x6e, 0x67, 0xae, 0xe0, 0x39, 0x4f, 0x74, 0x73,
- 0xf5, 0xe0, 0x38, 0x10, 0x73, 0xf5, 0xdd, 0xee, 0x62, 0xef, 0xe0, 0x37,
- 0x96, 0x61, 0xe2, 0xe0, 0x2e, 0xa2, 0xf3, 0x06, 0x60, 0x31, 0x90, 0xc2,
- 0x69, 0xf3, 0xe0, 0x34, 0x15, 0xf2, 0x03, 0x18, 0x88, 0xf5, 0x05, 0x0c,
- 0xe0, 0x34, 0x2c, 0x6b, 0x61, 0x77, 0x61, 0x2e, 0x6d, 0x69, 0x79, 0xe1,
- 0xe0, 0x2e, 0x44, 0x64, 0x6f, 0xee, 0xe0, 0x34, 0x5c, 0x6e, 0x69, 0x74,
- 0x75, 0xf2, 0xe0, 0x27, 0x5f, 0x61, 0xee, 0xe0, 0x2e, 0x14, 0xef, 0x02,
- 0x86, 0x73, 0x73, 0xeb, 0xe0, 0x31, 0xc6, 0x69, 0x73, 0xeb, 0xe0, 0x33,
- 0x72, 0xee, 0x06, 0x0b, 0x0b, 0xe0, 0x39, 0x76, 0xe4, 0x04, 0xe0, 0x39,
- 0x87, 0x61, 0x63, 0xe9, 0xe0, 0x2e, 0xd6, 0x63, 0x74, 0x69, 0x6f, 0x6e,
- 0x73, 0x2e, 0x66, 0xee, 0xc4, 0x27, 0xe1, 0x03, 0x06, 0x88, 0x68, 0x61,
- 0x73, 0x68, 0xe9, 0xbb, 0x67, 0x61, 0x74, 0x61, 0xae, 0xe0, 0x2e, 0x49,
- 0x62, 0x61, 0xf3, 0xdc, 0xa1, 0xeb, 0x03, 0xc0, 0x49, 0xf5, 0x0a, 0x04,
- 0x10, 0x05, 0x09, 0x07, 0x07, 0xe0, 0x2f, 0x28, 0x79, 0xe1, 0xc8, 0x83,
- 0xf3, 0x04, 0xe0, 0x32, 0x40, 0x68, 0x69, 0x6d, 0x61, 0xae, 0x60, 0x33,
- 0xf8, 0x43, 0x9f, 0x89, 0x72, 0xef, 0xe0, 0x2f, 0x3b, 0x6d, 0x69, 0x74,
- 0x73, 0x75, 0xae, 0xe0, 0x2e, 0x19, 0x69, 0xae, 0x4c, 0x8c, 0xe0, 0x2a,
- 0xfe, 0x64, 0x6f, 0x6d, 0xe9, 0xe0, 0x2e, 0xcc, 0x63, 0x68, 0xe9, 0x04,
- 0xe0, 0x21, 0xc9, 0x79, 0x61, 0x6d, 0xe1, 0xe0, 0x2b, 0x55, 0xe1, 0x02,
- 0x85, 0x79, 0xe1, 0xe0, 0x2d, 0xd9, 0xe7, 0xe0, 0x2d, 0xdd, 0x6a, 0xe9,
- 0x0c, 0x09, 0x05, 0x18, 0x04, 0x06, 0x0f, 0x14, 0x06, 0xe0, 0x2e, 0xa1,
- 0x79, 0x6f, 0x73, 0x68, 0x69, 0x64, 0xe1, 0xce, 0xc1, 0x74, 0xf3, 0xe0,
- 0x37, 0xfa, 0xf3, 0x02, 0x86, 0x68, 0x69, 0xf2, 0xe0, 0x29, 0x85, 0xe1,
- 0x02, 0x88, 0x77, 0x61, 0xae, 0x40, 0x5f, 0xe0, 0x33, 0xe5, 0x74, 0xef,
- 0xd2, 0xe5, 0xef, 0xe0, 0x30, 0x7e, 0x6e, 0x6f, 0x6d, 0x69, 0xf9, 0xac,
- 0x6d, 0xe9, 0x02, 0x85, 0x6e, 0xef, 0xe0, 0x2d, 0x8e, 0xae, 0x60, 0x2e,
- 0xb9, 0xc6, 0xf0, 0x6b, 0x61, 0x77, 0xe1, 0x02, 0x89, 0x67, 0x75, 0x63,
- 0x68, 0x69, 0x6b, 0xef, 0xce, 0x7c, 0xae, 0x5b, 0x9f, 0xd3, 0x0d, 0x69,
- 0x64, 0x65, 0xf2, 0xdc, 0xbf, 0x65, 0x64, 0xe1, 0xe0, 0x2e, 0x9e, 0xe5,
- 0x05, 0x0e, 0xe0, 0x33, 0xc0, 0x74, 0x74, 0x65, 0x72, 0x74, 0x64, 0x61,
- 0x73, 0x6e, 0x65, 0x74, 0xfa, 0xd3, 0x72, 0x66, 0x75, 0xeb, 0xce, 0x51,
- 0x64, 0x61, 0x69, 0x2e, 0x69, 0x77, 0x61, 0xf4, 0xe0, 0x33, 0xd9, 0x63,
- 0x68, 0x75, 0xae, 0x04, 0xe0, 0x2d, 0x24, 0x74, 0xef, 0x60, 0x32, 0xd3,
- 0xc2, 0x52, 0xf4, 0x04, 0xe0, 0x37, 0x17, 0x70, 0x61, 0x63, 0x63, 0x65,
- 0x73, 0xf3, 0xd3, 0xd9, 0xf3, 0xd8, 0xa6, 0xf2, 0x11, 0x0a, 0x08, 0x40,
- 0xda, 0x24, 0x40, 0x6b, 0x40, 0x58, 0x60, 0x24, 0x55, 0x4f, 0xd3, 0xc2,
- 0x48, 0x1f, 0xc3, 0x02, 0x82, 0xf8, 0x97, 0xe6, 0xe0, 0x2d, 0xba, 0x75,
- 0x73, 0x6b, 0x79, 0x2e, 0xe4, 0xd9, 0x57, 0xef, 0x09, 0x04, 0x09, 0x0d,
- 0x40, 0xab, 0xe0, 0x2a, 0x92, 0xf9, 0xe0, 0x32, 0x50, 0xf3, 0x04, 0xe0,
- 0x32, 0x47, 0x69, 0xee, 0xd3, 0xd9, 0x6e, 0xf4, 0x02, 0x84, 0xe9, 0xe0,
- 0x24, 0xa7, 0x64, 0xef, 0xe0, 0x34, 0xdd, 0xed, 0x02, 0x85, 0x2e, 0xe8,
- 0xe0, 0x36, 0xbe, 0xad, 0x15, 0x09, 0x06, 0x04, 0x06, 0x06, 0x04, 0x06,
- 0x07, 0x17, 0x12, 0x05, 0x09, 0x04, 0x02, 0x04, 0x05, 0x0a, 0xe0, 0x22,
- 0x0f, 0xf7, 0x40, 0x7b, 0x42, 0xae, 0x56, 0x37, 0xd5, 0x15, 0xf6, 0x40,
- 0x72, 0xe0, 0x2d, 0xce, 0xf5, 0xe0, 0x2e, 0x3a, 0xf4, 0x47, 0x53, 0xe0,
- 0x26, 0xfa, 0xf3, 0x50, 0x55, 0xe0, 0x22, 0x47, 0xf2, 0xe0, 0x2e, 0x56,
- 0xf0, 0x40, 0x58, 0xe0, 0x2e, 0x08, 0xef, 0x19, 0x60, 0x2e, 0x41, 0xc0,
- 0xa1, 0xee, 0x0e, 0x04, 0x42, 0xe7, 0x4d, 0x45, 0x5e, 0x33, 0x41, 0xc9,
- 0x42, 0x4b, 0xc3, 0xe1, 0xea, 0xe0, 0x37, 0xa7, 0xe8, 0xe0, 0x37, 0xa3,
- 0xed, 0x0d, 0x27, 0x46, 0xeb, 0x5b, 0x7e, 0x4b, 0x65, 0x2c, 0x44, 0x40,
- 0xc4, 0x2c, 0xef, 0xe0, 0x37, 0x91, 0xeb, 0x59, 0x07, 0xdd, 0x81, 0xe9,
- 0x1d, 0x46, 0xeb, 0x60, 0x29, 0xf1, 0xc1, 0x5e, 0xe8, 0xe0, 0x2e, 0x0e,
- 0xe7, 0x90, 0xe6, 0xe0, 0x30, 0xea, 0xe4, 0x4f, 0xfd, 0xdf, 0xfc, 0xe3,
- 0x05, 0x60, 0x2d, 0xb4, 0x9a, 0xe1, 0xe0, 0x37, 0x6a, 0xe1, 0x08, 0x60,
- 0x2d, 0xfb, 0x40, 0xa1, 0xc2, 0x33, 0xfa, 0xe0, 0x37, 0x41, 0xe7, 0x06,
- 0x60, 0x31, 0x78, 0xc3, 0x2a, 0xe1, 0xe0, 0x27, 0xb9, 0xe9, 0x02, 0x9d,
- 0x75, 0x6c, 0xe9, 0x02, 0x81, 0x2d, 0xf6, 0x03, 0x0b, 0x81, 0xe5, 0x03,
- 0x07, 0x81, 0x6e, 0x65, 0x7a, 0x69, 0xe1, 0x02, 0x81, 0x2d, 0x67, 0x69,
- 0x75, 0xec, 0xe0, 0x30, 0xf2, 0x62, 0xef, 0xda, 0x60, 0xe5, 0x06, 0x07,
- 0x08, 0x05, 0xc0, 0x4b, 0x73, 0x65, 0x6e, 0xe9, 0xe0, 0x32, 0x4f, 0x6e,
- 0x63, 0x68, 0x6b, 0x69, 0xf3, 0xda, 0xd5, 0xe9, 0x5a, 0x46, 0xdb, 0x4f,
- 0xe5, 0x09, 0x06, 0x07, 0x0d, 0x14, 0x0e, 0xe0, 0x36, 0xd2, 0x74, 0x6c,
- 0xf3, 0xe0, 0x35, 0xad, 0x73, 0x69, 0x74, 0x65, 0xae, 0xd8, 0x52, 0xed,
- 0x02, 0x83, 0xf9, 0xcd, 0xa1, 0x61, 0x73, 0x6f, 0xee, 0xe0, 0x2c, 0x35,
- 0xe4, 0x02, 0x89, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0xf0, 0xe0, 0x34, 0x19,
- 0x64, 0x6e, 0x73, 0xae, 0x57, 0xce, 0xdc, 0x45, 0x62, 0x6f, 0xf8, 0x02,
- 0x81, 0x2d, 0x6f, 0x73, 0xae, 0x60, 0x36, 0x46, 0xc0, 0x8a, 0x2e, 0xe8,
- 0xe0, 0x36, 0x40, 0x64, 0x72, 0xe9, 0xc2, 0x21, 0xe1, 0x03, 0x1d, 0xab,
- 0xee, 0x06, 0x09, 0x06, 0xe0, 0x30, 0xd8, 0x7a, 0x69, 0x73, 0x6b, 0x61,
- 0xee, 0xe0, 0x2f, 0x8d, 0x6b, 0x66, 0xf5, 0xe0, 0x2f, 0x6d, 0x63, 0x61,
- 0x69, 0xf3, 0xe0, 0x32, 0x64, 0x6d, 0x65, 0xf2, 0x02, 0x86, 0x63, 0x61,
- 0x6e, 0xf6, 0xcc, 0x73, 0xae, 0x06, 0x0c, 0x08, 0xe0, 0x35, 0x1a, 0xf7,
- 0x02, 0x85, 0x69, 0xeb, 0xe0, 0x36, 0x38, 0x65, 0xe2, 0xdf, 0x1c, 0x70,
- 0x68, 0x6f, 0x74, 0xef, 0xe0, 0x36, 0x15, 0x6d, 0x65, 0xe4, 0xd7, 0x7a,
- 0x31, 0x2d, 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0xe4, 0xd7, 0x71,
- 0xad, 0x02, 0x95, 0x70, 0x61, 0x72, 0xad, 0x02, 0x82, 0xb2, 0x82, 0x31,
- 0x2e, 0x62, 0x61, 0x72, 0x65, 0x6d, 0x65, 0x74, 0x61, 0xec, 0xc1, 0x11,
- 0x31, 0x2e, 0x70, 0x61, 0x61, 0x73, 0x2e, 0x6d, 0x61, 0x73, 0x73, 0x69,
- 0x76, 0x65, 0x67, 0x72, 0x69, 0xe4, 0xe0, 0x36, 0x22, 0xef, 0x0f, 0x09,
- 0x04, 0x40, 0x97, 0x16, 0x19, 0x55, 0xaf, 0x4d, 0x8a, 0x4a, 0xc2, 0xc7,
- 0x65, 0x75, 0x6e, 0x64, 0x61, 0x74, 0xe9, 0xe0, 0x20, 0xbc, 0xf3, 0xe0,
- 0x32, 0x04, 0xf2, 0x0c, 0x0c, 0x1f, 0x07, 0x13, 0x1c, 0x06, 0x60, 0x23,
- 0x0e, 0xc3, 0x5b, 0x75, 0xed, 0x06, 0x60, 0x35, 0x1c, 0xc0, 0xf5, 0xfa,
- 0xe0, 0x26, 0x4f, 0xf4, 0x04, 0x08, 0x0a, 0x83, 0x77, 0x6f, 0x72, 0x74,
- 0xe8, 0xe0, 0x33, 0x4a, 0x6d, 0x69, 0x73, 0x73, 0x6f, 0x75, 0xec, 0xe0,
- 0x2f, 0xdb, 0xe5, 0xc1, 0x40, 0x61, 0xec, 0xe0, 0x34, 0xa5, 0x73, 0xe1,
- 0x60, 0x2f, 0x9c, 0xc4, 0x64, 0xec, 0x02, 0x85, 0x1f, 0x43, 0xec, 0x05,
- 0x81, 0xe9, 0x02, 0x81, 0x2d, 0x63, 0x65, 0x73, 0xe5, 0xe0, 0x2e, 0x06,
- 0xe7, 0x02, 0x90, 0x6f, 0x74, 0x2e, 0xe8, 0x02, 0x83, 0x69, 0xf3, 0x83,
- 0x65, 0x72, 0x2e, 0x6e, 0xe1, 0xdf, 0xca, 0x65, 0x62, 0x6c, 0x6f, 0x63,
- 0xeb, 0xe0, 0x34, 0xae, 0xe4, 0x60, 0x34, 0x2f, 0xc1, 0x88, 0xad, 0x05,
- 0x03, 0x04, 0x06, 0x87, 0x74, 0xe8, 0x8e, 0x73, 0x6f, 0xed, 0x8a, 0x6f,
- 0x75, 0xf2, 0xe0, 0x25, 0xe1, 0x6d, 0x6f, 0x72, 0xe5, 0xe0, 0x32, 0x73,
- 0x62, 0x65, 0x74, 0x74, 0x65, 0xf2, 0xe0, 0x32, 0x6a, 0xef, 0x07, 0x50,
- 0x53, 0x54, 0x9f, 0xd0, 0x95, 0xe4, 0x04, 0xe0, 0x35, 0x82, 0x6e, 0x65,
- 0x74, 0x77, 0x6f, 0xf2, 0xe0, 0x33, 0x1d, 0xec, 0x03, 0x04, 0x88, 0xec,
- 0xe0, 0x2e, 0x98, 0x6b, 0x65, 0x62, 0x69, 0xe2, 0xe0, 0x2e, 0x92, 0x69,
- 0x6f, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0xf2, 0x8d, 0x67, 0xe7, 0xe0, 0x2f,
- 0x16, 0xee, 0x05, 0x04, 0xe0, 0x20, 0xa7, 0x77, 0xeb, 0xdd, 0xe3, 0x63,
- 0x2e, 0x66, 0x72, 0x2d, 0x70, 0x61, 0x72, 0x2e, 0x73, 0x63, 0xf7, 0xdd,
- 0x24, 0xed, 0x04, 0xe0, 0x35, 0x3e, 0xae, 0x60, 0x33, 0x42, 0x40, 0x75,
- 0xbb, 0xec, 0x0b, 0x0f, 0x0e, 0x28, 0x13, 0x0c, 0x06, 0x5d, 0x10, 0xd2,
- 0x2c, 0xf9, 0x06, 0x50, 0x63, 0xe0, 0x24, 0xc1, 0x6e, 0x6e, 0x68, 0x6f,
- 0x73, 0xf4, 0xd6, 0xfa, 0x74, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e,
- 0x6d, 0x75, 0x6e, 0xe9, 0xd0, 0x12, 0xef, 0x05, 0x04, 0x19, 0xd5, 0x4e,
- 0x77, 0xe5, 0xd2, 0x05, 0xf2, 0x08, 0x0a, 0x5f, 0xfc, 0x4d, 0x1f, 0xc2,
- 0x00, 0xe9, 0x05, 0x5c, 0x1e, 0xcb, 0xe6, 0xf0, 0xe0, 0x2b, 0xe4, 0x65,
- 0x6e, 0xe3, 0xe0, 0x2e, 0x26, 0x70, 0xf0, 0xe0, 0x2c, 0xaf, 0xe9, 0x07,
- 0x08, 0x60, 0x22, 0x12, 0xd1, 0x7a, 0x67, 0x68, 0xf4, 0x60, 0x31, 0xfc,
- 0xc0, 0x7d, 0xe3, 0xdd, 0xae, 0xe5, 0x02, 0x83, 0xf3, 0xc6, 0x48, 0x6b,
- 0x6b, 0xe5, 0xe0, 0x25, 0x9f, 0x64, 0x72, 0xf6, 0xe0, 0x34, 0xbc, 0xe1,
- 0x07, 0x03, 0x06, 0x07, 0xe0, 0x33, 0x22, 0xf4, 0xde, 0xad, 0x70, 0x2e,
- 0xe9, 0xe0, 0x28, 0x6a, 0x6e, 0x64, 0x65, 0xf2, 0xe0, 0x2d, 0x72, 0x6b,
- 0x73, 0x74, 0xe1, 0xe0, 0x30, 0xb2, 0xeb, 0xe0, 0x23, 0x9b, 0xea, 0x07,
- 0x04, 0x60, 0x21, 0x55, 0xd3, 0x3d, 0xe5, 0xe0, 0x28, 0xed, 0x61, 0xec,
- 0xe0, 0x28, 0xf2, 0xe9, 0x0f, 0x0e, 0x06, 0x40, 0x5d, 0x2e, 0x38, 0x05,
- 0x09, 0x09, 0x42, 0xb4, 0xe0, 0x30, 0xdb, 0xf4, 0x05, 0x04, 0xe0, 0x34,
- 0x73, 0xee, 0xe0, 0x2d, 0x29, 0xea, 0xe0, 0x25, 0x9b, 0x73, 0xe8, 0x5f,
- 0x1d, 0xd5, 0x50, 0xf2, 0x02, 0x9d, 0xed, 0x02, 0x85, 0x64, 0xe1, 0xe0,
- 0x32, 0x75, 0xae, 0x0e, 0x60, 0x29, 0x81, 0x40, 0xbe, 0x46, 0xa4, 0x41,
- 0xee, 0x40, 0x52, 0xc0, 0xf3, 0xee, 0x60, 0x29, 0x84, 0xc7, 0xfb, 0xe5,
- 0x07, 0x21, 0x0d, 0x5d, 0xfa, 0xd6, 0x19, 0xf7, 0x02, 0x85, 0x65, 0xe2,
- 0xe0, 0x32, 0xd4, 0x61, 0x6c, 0xec, 0x02, 0x8a, 0x65, 0x64, 0x72, 0x65,
- 0x70, 0x6c, 0x69, 0xf4, 0xda, 0xdf, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77,
- 0x61, 0xf9, 0xde, 0x4b, 0xee, 0x02, 0x84, 0xfa, 0xe0, 0x2d, 0x54, 0x65,
- 0x74, 0x2e, 0xe3, 0xdc, 0x8e, 0x62, 0x61, 0x73, 0xe5, 0xe0, 0x33, 0x27,
- 0xee, 0x06, 0x06, 0x09, 0x0e, 0xc4, 0x34, 0xee, 0x60, 0x28, 0x5f, 0xc3,
- 0x78, 0x65, 0x61, 0x72, 0xf4, 0x60, 0x2c, 0xc1, 0xc4, 0x81, 0xe1, 0x04,
- 0xe0, 0x31, 0xa9, 0x6e, 0xe3, 0x04, 0xe0, 0x32, 0x7d, 0xe9, 0xcc, 0x3c,
- 0xae, 0x05, 0x44, 0x21, 0xcd, 0x24, 0xe3, 0xe0, 0x33, 0x89, 0xec, 0x03,
- 0x0b, 0xa3, 0xed, 0x04, 0xe0, 0x33, 0xd5, 0xae, 0x60, 0x31, 0x1c, 0xc1,
- 0xc4, 0x65, 0x67, 0x65, 0x61, 0xf2, 0x03, 0xdd, 0xcd, 0xad, 0x07, 0x04,
- 0x04, 0x04, 0x03, 0xcd, 0x99, 0x73, 0xe7, 0xdd, 0xc3, 0x6a, 0xf0, 0xdd,
- 0xbf, 0x67, 0xe2, 0xdd, 0xbb, 0xe4, 0xcd, 0x9c, 0x61, 0xf5, 0xdd, 0xb4,
- 0x61, 0x74, 0xe5, 0xe0, 0x26, 0xac, 0x67, 0x75, 0xe5, 0xda, 0x14, 0xe5,
- 0x04, 0xe0, 0x2e, 0xe8, 0xec, 0xe0, 0x2e, 0xb1, 0xe4, 0x04, 0xe0, 0x32,
- 0x16, 0x65, 0xec, 0xd8, 0x2e, 0xae, 0x06, 0x60, 0x2d, 0x7d, 0xc4, 0x10,
- 0xe3, 0x04, 0xe0, 0x32, 0x39, 0x6c, 0x6f, 0x75, 0x64, 0x70, 0x6c, 0x61,
- 0x74, 0x66, 0x6f, 0x72, 0xed, 0xe0, 0x33, 0x1d, 0xe8, 0x06, 0x04, 0x09,
- 0xe0, 0x22, 0x56, 0xf6, 0xe0, 0x22, 0x62, 0xf3, 0x04, 0xe0, 0x31, 0xdd,
- 0xeb, 0xe0, 0x22, 0x59, 0x2d, 0x6d, 0x75, 0x65, 0x6e, 0x73, 0xf4, 0xe0,
- 0x22, 0xd8, 0xe5, 0x0c, 0x05, 0x08, 0x11, 0x08, 0x05, 0x06, 0x44, 0xa9,
- 0xe0, 0x2c, 0x73, 0xf4, 0x5c, 0xf5, 0xd4, 0xcc, 0x73, 0x74, 0x65, 0x2d,
- 0xe9, 0xe0, 0x27, 0x02, 0xf2, 0x04, 0xe0, 0x21, 0x9d, 0xf2, 0x04, 0xe0,
- 0x30, 0x55, 0x61, 0xf2, 0x60, 0x2c, 0xe9, 0xc4, 0x35, 0x6e, 0x74, 0x69,
- 0x67, 0x65, 0xf2, 0xda, 0x14, 0x69, 0xf2, 0xe0, 0x2a, 0x11, 0x65, 0x64,
- 0x62, 0xe1, 0xc4, 0x0b, 0xe4, 0x06, 0x19, 0x04, 0xe0, 0x2d, 0x6f, 0x6f,
- 0x72, 0xe1, 0x02, 0x87, 0x70, 0x65, 0x6f, 0x70, 0xec, 0xdd, 0xfd, 0x69,
- 0x6e, 0x66, 0x72, 0x61, 0x63, 0x6c, 0x6f, 0x75, 0xe4, 0xe0, 0x30, 0x29,
- 0xea, 0xe0, 0x31, 0x6f, 0xe5, 0x04, 0xe0, 0x2b, 0x8a, 0xf2, 0xe0, 0x30,
- 0x0a, 0xe3, 0xe0, 0x30, 0xee, 0x62, 0xf8, 0x02, 0x81, 0x2d, 0x6f, 0xf3,
- 0xe0, 0x32, 0x4e, 0xe1, 0x09, 0x06, 0x40, 0x43, 0x21, 0x13, 0x14, 0x06,
- 0x8c, 0x75, 0x73, 0xeb, 0xe0, 0x31, 0x48, 0xf3, 0x02, 0xb1, 0xf4, 0x06,
- 0x0d, 0x08, 0xe0, 0x32, 0xae, 0x76, 0x70, 0xf3, 0x02, 0x85, 0xae, 0x54,
- 0x0c, 0xc7, 0x42, 0xad, 0xcc, 0xab, 0x73, 0x74, 0x61, 0x63, 0xeb, 0xe0,
- 0x32, 0x8c, 0x6c, 0xf9, 0x02, 0x85, 0x6c, 0xe2, 0xe0, 0x32, 0x84, 0x2d,
- 0x74, 0x65, 0x72, 0x72, 0x61, 0x72, 0x69, 0xf5, 0xe0, 0x29, 0x4f, 0x68,
- 0x69, 0x6f, 0xee, 0x04, 0xe0, 0x32, 0x91, 0x73, 0x74, 0x6f, 0xf2, 0xe0,
- 0x24, 0x15, 0xf2, 0x05, 0x5c, 0x31, 0xd5, 0x07, 0xed, 0x07, 0x06, 0x60,
- 0x2f, 0xbd, 0xc2, 0xb9, 0x73, 0x74, 0xe5, 0xe0, 0x23, 0xb7, 0xe5, 0x02,
- 0x83, 0xf2, 0xdb, 0xef, 0x71, 0x75, 0x69, 0x70, 0xed, 0xcf, 0x5a, 0xee,
- 0x06, 0x60, 0x30, 0x00, 0xc2, 0x62, 0x74, 0x61, 0x73, 0x79, 0x6c, 0x65,
- 0x61, 0x67, 0x75, 0xe5, 0xcd, 0xd7, 0xed, 0x02, 0x8c, 0x69, 0x6c, 0xf9,
- 0x06, 0x60, 0x2f, 0x91, 0xc2, 0xb9, 0xe4, 0xde, 0xbc, 0x2e, 0xf0, 0xe0,
- 0x2f, 0xe6, 0x6b, 0x65, 0x66, 0xf5, 0xdf, 0x7b, 0xe9, 0x06, 0x60, 0x2f,
- 0xed, 0xc0, 0xa9, 0x72, 0x77, 0xe9, 0xc9, 0x9c, 0xe7, 0xe0, 0x30, 0xc1,
- 0xe5, 0x22, 0x11, 0x40, 0x68, 0x2b, 0x40, 0x72, 0x2b, 0x40, 0x6c, 0x1f,
- 0x0d, 0x0f, 0x40, 0xe3, 0x40, 0x53, 0x32, 0x0a, 0x2e, 0x1a, 0x15, 0x41,
- 0x76, 0x40, 0x43, 0x14, 0x40, 0x55, 0x03, 0x10, 0xe0, 0x27, 0x7b, 0x7a,
- 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x6b, 0x75, 0x6c, 0x65, 0x75, 0x76,
- 0x65, 0xee, 0xd3, 0xa4, 0xf8, 0x07, 0x08, 0x25, 0x04, 0x07, 0x04, 0x8b,
- 0x74, 0x72, 0x61, 0x73, 0xf0, 0xe0, 0x2b, 0x3f, 0xf0, 0x03, 0x09, 0x84,
- 0x72, 0x65, 0x73, 0xf3, 0x60, 0x2f, 0x01, 0xc2, 0xdf, 0x6f, 0xf3, 0xd2,
- 0x7f, 0x65, 0x72, 0xf4, 0x04, 0xe0, 0x31, 0xd0, 0x73, 0x2d, 0x63, 0x6f,
- 0x6d, 0x70, 0x74, 0x61, 0x62, 0xec, 0xe0, 0x24, 0x53, 0x6e, 0xe5, 0xd5,
- 0x8a, 0x68, 0x69, 0x62, 0xe9, 0xe0, 0x27, 0x06, 0xe5, 0xe0, 0x27, 0x0f,
- 0x63, 0x68, 0x61, 0x6e, 0x67, 0xe5, 0x60, 0x2e, 0xcf, 0xc2, 0xdf, 0xae,
- 0x02, 0x89, 0x6f, 0x72, 0x74, 0x73, 0x69, 0x6e, 0x66, 0xef, 0x8a, 0x66,
- 0x75, 0x74, 0x75, 0x72, 0x65, 0x63, 0x6d, 0x73, 0x2e, 0xe1, 0xcd, 0x3d,
- 0xf6, 0x02, 0x8d, 0x6a, 0x65, 0x2d, 0x6f, 0x67, 0x2d, 0x68, 0x6f, 0x72,
- 0xee, 0xe0, 0x2d, 0x5e, 0x65, 0xee, 0x07, 0x0c, 0x60, 0x28, 0x54, 0xc4,
- 0xf3, 0x1f, 0x43, 0x61, 0x1f, 0x45, 0x61, 0x1f, 0x45, 0xe1, 0xe0, 0x29,
- 0xf2, 0x61, 0x73, 0xf3, 0xe0, 0x29, 0xec, 0xf5, 0x09, 0x10, 0x06, 0x33,
- 0x60, 0x2e, 0xb0, 0xc2, 0x62, 0x72, 0xef, 0x02, 0x86, 0x76, 0x69, 0xf3,
- 0xe0, 0x24, 0xa9, 0x64, 0x69, 0xf2, 0xe0, 0x30, 0xc4, 0x6e, 0x2e, 0xe5,
- 0xe0, 0x31, 0x47, 0xae, 0x0b, 0x12, 0x09, 0x03, 0x60, 0x20, 0x0b, 0x4e,
- 0x3f, 0xc2, 0xca, 0xf0, 0x04, 0xe0, 0x20, 0x49, 0x79, 0x74, 0x68, 0x6f,
- 0x6e, 0x61, 0x6e, 0x79, 0x77, 0x68, 0xe5, 0xd6, 0x59, 0x6d, 0x65, 0x74,
- 0x65, 0x6f, 0xf2, 0xe0, 0x30, 0x39, 0xe9, 0xc8, 0x0f, 0x65, 0x6e, 0x63,
- 0x6f, 0x77, 0x61, 0xf9, 0xd8, 0xf3, 0xad, 0x07, 0x05, 0x02, 0x02, 0x02,
- 0xd8, 0xeb, 0x77, 0xe5, 0xe0, 0x28, 0x23, 0xb4, 0x86, 0xb3, 0x84, 0xb2,
- 0x82, 0x31, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x6e, 0x6f, 0xe4, 0xe0, 0x29,
- 0x72, 0xf4, 0x08, 0x07, 0x0c, 0x05, 0x04, 0xe0, 0x30, 0xce, 0x6e, 0xe5,
- 0x60, 0x2a, 0x0c, 0xc5, 0x55, 0xe9, 0x04, 0xe0, 0x2f, 0x92, 0x73, 0x61,
- 0x6c, 0xe1, 0xe0, 0x2f, 0x23, 0x68, 0xee, 0xe0, 0x28, 0x5e, 0xe3, 0xe0,
- 0x2f, 0x85, 0x61, 0x6a, 0x69, 0xed, 0xca, 0xd1, 0xf3, 0x0b, 0x38, 0x06,
- 0x04, 0x09, 0x09, 0x4e, 0xfd, 0xe0, 0x21, 0x6b, 0xf4, 0x03, 0x04, 0x85,
- 0x61, 0xf4, 0xde, 0x6b, 0x2e, 0xf0, 0xe0, 0x2f, 0x68, 0xad, 0x03, 0x0c,
- 0x88, 0x6d, 0x6f, 0x6e, 0x2d, 0x62, 0x6c, 0x6f, 0x67, 0x75, 0xe5, 0xc5,
- 0x8d, 0x6c, 0x65, 0x2d, 0x70, 0x61, 0x74, 0xf2, 0x8f, 0x61, 0x2d, 0x6c,
- 0x61, 0x2d, 0x6d, 0xe1, 0x02, 0x83, 0x73, 0xe9, 0x83, 0x69, 0x73, 0x6f,
- 0xee, 0xe0, 0x30, 0x7f, 0x73, 0x65, 0xf8, 0xe0, 0x2d, 0xc8, 0xf0, 0xe0,
- 0x2f, 0x31, 0xe1, 0x04, 0xe0, 0x2a, 0xa4, 0xee, 0xe0, 0x2e, 0xc8, 0xae,
- 0x59, 0x49, 0x46, 0x17, 0x4a, 0xff, 0x03, 0x83, 0x2d, 0x31, 0x2e, 0x61,
- 0x78, 0x61, 0x72, 0x6e, 0x65, 0xf4, 0xd8, 0x3d, 0xf2, 0x08, 0x0c, 0x52,
- 0xfc, 0x4c, 0x45, 0xcf, 0xd9, 0x6f, 0x74, 0xe9, 0x02, 0x82, 0xeb, 0x82,
- 0x63, 0xe1, 0xe0, 0x2f, 0x55, 0xe9, 0x02, 0x84, 0xed, 0xe0, 0x24, 0xb2,
- 0x63, 0xf3, 0x91, 0x71, 0x75, 0x69, 0x70, 0x6d, 0x65, 0x6e, 0xf4, 0x60,
- 0x2d, 0x56, 0xc2, 0xdf, 0xf0, 0x02, 0x84, 0xf3, 0xe0, 0x29, 0x0d, 0x69,
- 0x6c, 0x65, 0x70, 0xf3, 0xe0, 0x27, 0xb1, 0xee, 0x10, 0x19, 0x28, 0x12,
- 0x04, 0x24, 0x04, 0x0e, 0x20, 0x19, 0x04, 0x60, 0x27, 0x75, 0xc5, 0xd5,
- 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0xf4, 0x04, 0xe0, 0x2d,
- 0x4a, 0x61, 0x6c, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x72, 0xf6, 0xe0, 0x25,
- 0x44, 0xf4, 0x03, 0x05, 0x9c, 0x6f, 0xed, 0xe0, 0x27, 0x7a, 0x65, 0xf2,
- 0x02, 0x87, 0x74, 0x61, 0x69, 0xee, 0xe0, 0x28, 0x4a, 0x70, 0x72, 0x69,
- 0x73, 0xe5, 0x04, 0xe0, 0x2d, 0x78, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0xae,
- 0xdf, 0xe5, 0xae, 0xde, 0xe5, 0xf3, 0x02, 0x8a, 0x63, 0x61, 0x6c, 0x65,
- 0x64, 0x2e, 0xf3, 0xe0, 0x2c, 0xf6, 0x2e, 0xf4, 0xe0, 0x2e, 0x95, 0xe9,
- 0xe0, 0x24, 0x91, 0xe7, 0x04, 0x06, 0x0f, 0x85, 0x6c, 0x61, 0xee, 0xe0,
- 0x2a, 0xc7, 0x69, 0x6e, 0xe5, 0x04, 0xe0, 0x2c, 0xc8, 0x65, 0xf2, 0x5a,
- 0x55, 0x52, 0x71, 0xc2, 0xdf, 0x65, 0xf2, 0xe0, 0x28, 0xc1, 0xae, 0x60,
- 0x2e, 0x1a, 0xb4, 0xe6, 0xe0, 0x2e, 0x48, 0xe5, 0x02, 0x85, 0x72, 0xe7,
- 0xe0, 0x2d, 0x5c, 0x62, 0x61, 0xeb, 0xe0, 0x25, 0x3f, 0x64, 0x6f, 0xe6,
- 0x02, 0x8d, 0x74, 0x68, 0x65, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0xe5,
- 0xe0, 0x26, 0x21, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0xae,
- 0x60, 0x2c, 0x97, 0xc2, 0xae, 0xe3, 0x03, 0x09, 0x84, 0x79, 0x63, 0x6c,
- 0x6f, 0x70, 0x65, 0xe4, 0xd4, 0x81, 0xf2, 0xe0, 0x2d, 0xed, 0x6f, 0x72,
- 0x65, 0x61, 0xf0, 0xe0, 0x25, 0xd4, 0xe1, 0xe0, 0x26, 0xe2, 0x2d, 0x72,
- 0x6f, 0x6f, 0xf4, 0xe0, 0x2e, 0xaf, 0xed, 0x06, 0x04, 0x0b, 0x0d, 0x10,
- 0x9b, 0xf2, 0xe0, 0x2d, 0x3a, 0xf0, 0x04, 0xe0, 0x2d, 0xe2, 0x72, 0x65,
- 0xf3, 0xe0, 0x2c, 0x7b, 0x69, 0x6c, 0x69, 0xe1, 0x02, 0x81, 0x2d, 0x72,
- 0x6f, 0x6d, 0xe1, 0xd9, 0xf4, 0x65, 0xf2, 0x02, 0x88, 0x67, 0x65, 0x6e,
- 0x63, 0xf9, 0xe0, 0x2c, 0x33, 0xe3, 0xe0, 0x2c, 0xaf, 0xe2, 0x06, 0x07,
- 0x08, 0xe0, 0x2a, 0x68, 0x72, 0x6f, 0x69, 0xe4, 0xe0, 0x24, 0x3d, 0x61,
- 0x69, 0x78, 0x61, 0x64, 0xe1, 0xcc, 0x21, 0x2e, 0xeb, 0xe0, 0x2c, 0x8a,
- 0x61, 0xe9, 0xe0, 0x2c, 0xa6, 0xec, 0x07, 0x0d, 0x0f, 0x5c, 0x91, 0xc9,
- 0x5f, 0x76, 0xe5, 0x03, 0xd7, 0x1c, 0x6e, 0x64, 0x72, 0x65, 0xec, 0xe0,
- 0x24, 0xb5, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x2e, 0xe3, 0x03,
- 0xd6, 0xab, 0xef, 0xc8, 0x00, 0xe2, 0x04, 0x06, 0xd1, 0xe7, 0x6c, 0x61,
- 0xe7, 0xe0, 0x2a, 0x2f, 0xae, 0xcc, 0x41, 0x6b, 0x6c, 0x6f, 0x67, 0x65,
- 0x73, 0xae, 0xe0, 0x2a, 0x81, 0xe9, 0x04, 0x09, 0x07, 0x82, 0x73, 0x65,
- 0x6e, 0x62, 0x61, 0xe8, 0xe0, 0x24, 0x07, 0x68, 0x65, 0x69, 0x6a, 0xe9,
- 0xc1, 0xfb, 0xe7, 0xae, 0xe4, 0x05, 0x5f, 0x67, 0xcd, 0xa4, 0xf3, 0x05,
- 0x05, 0xe0, 0x22, 0xdd, 0x6b, 0xef, 0xe0, 0x27, 0xdb, 0x62, 0x65, 0xf2,
- 0xe0, 0x27, 0xd5, 0xe7, 0x06, 0x08, 0x07, 0xe0, 0x2e, 0x6b, 0x79, 0x70,
- 0x74, 0x69, 0xe1, 0xe0, 0x23, 0xd8, 0x6f, 0x69, 0x73, 0xed, 0xe0, 0x26,
- 0x35, 0x65, 0xf2, 0xd8, 0x16, 0xe5, 0x06, 0x60, 0x21, 0xb8, 0xcc, 0xa8,
- 0x72, 0xef, 0x02, 0x86, 0x2d, 0x73, 0x74, 0x61, 0x67, 0x65, 0x2e, 0xef,
- 0xde, 0x54, 0xe4, 0x07, 0x41, 0x30, 0x07, 0x08, 0x19, 0x85, 0xf5, 0x06,
- 0x04, 0x12, 0xe0, 0x2e, 0x2d, 0x67, 0xe9, 0xdb, 0x88, 0x63, 0x61, 0xf4,
- 0x02, 0x83, 0xef, 0xd2, 0xd3, 0x69, 0x6f, 0xee, 0x60, 0x24, 0x0f, 0x47,
- 0x6c, 0xc2, 0xb9, 0xae, 0x1c, 0x06, 0x09, 0x06, 0x0a, 0x1d, 0x06, 0x10,
- 0x08, 0x15, 0x10, 0x13, 0x09, 0x08, 0x0f, 0x04, 0x0e, 0x07, 0x0d, 0x11,
- 0x4b, 0x27, 0x04, 0x3d, 0x40, 0x48, 0xda, 0xc1, 0xfa, 0x60, 0x2b, 0xc4,
- 0xc0, 0xb2, 0xf6, 0x60, 0x22, 0x21, 0x4a, 0x7a, 0x40, 0x43, 0xb8, 0xf5,
- 0x60, 0x2b, 0xd0, 0xc0, 0x97, 0xf4, 0x60, 0x2b, 0x91, 0x1e, 0x12, 0x40,
- 0x82, 0x3a, 0xb3, 0xf3, 0x13, 0x60, 0x23, 0xe8, 0x46, 0x4f, 0x41, 0x44,
- 0x1a, 0x03, 0x15, 0x40, 0x79, 0x1e, 0x1c, 0x40, 0x52, 0xc1, 0x2a, 0xe3,
- 0x04, 0xe0, 0x2d, 0xd8, 0xef, 0xe0, 0x2d, 0xb6, 0xf2, 0x60, 0x2b, 0x71,
- 0xc1, 0xda, 0xf0, 0x60, 0x23, 0x03, 0x48, 0x68, 0x03, 0x17, 0x18, 0x40,
- 0x79, 0x19, 0x05, 0x2b, 0x24, 0x9f, 0xee, 0x60, 0x2b, 0xab, 0x40, 0xc8,
- 0xc1, 0x49, 0xed, 0x60, 0x26, 0x50, 0x43, 0xbf, 0x41, 0x3a, 0x03, 0x07,
- 0x03, 0x17, 0x18, 0x40, 0x79, 0x3a, 0x0f, 0x40, 0x43, 0xc1, 0x2a, 0xec,
- 0x60, 0x21, 0xb8, 0x41, 0xf3, 0x46, 0x4f, 0x41, 0x44, 0x03, 0x2f, 0x40,
- 0x97, 0xc0, 0x4f, 0xeb, 0x0e, 0x60, 0x2b, 0x16, 0x03, 0x1e, 0x1b, 0x1e,
- 0x40, 0x83, 0x40, 0x64, 0xc1, 0x2a, 0xf2, 0xe0, 0x21, 0x38, 0xe9, 0x4c,
- 0x12, 0x5f, 0x09, 0x40, 0xab, 0xc0, 0x8c, 0xe8, 0x60, 0x2b, 0x15, 0x40,
- 0xa8, 0xc0, 0x8c, 0xe7, 0x60, 0x2b, 0x24, 0x03, 0x15, 0x1e, 0x40, 0x5b,
- 0x19, 0x0f, 0x21, 0x24, 0x1f, 0xb8, 0xe6, 0xe0, 0x2b, 0x12, 0xe5, 0x60,
- 0x21, 0x71, 0x45, 0xde, 0x43, 0xa8, 0x40, 0xab, 0x40, 0x49, 0xc1, 0x6d,
- 0xe4, 0x60, 0x2a, 0xdf, 0x21, 0xc0, 0xce, 0xe3, 0x60, 0x29, 0x9e, 0x41,
- 0x3d, 0x40, 0x57, 0x40, 0x95, 0x40, 0x52, 0xb8, 0xe2, 0x60, 0x23, 0x42,
- 0x47, 0x89, 0x0a, 0x17, 0x12, 0x27, 0x40, 0x5b, 0x19, 0x05, 0x1c, 0x33,
- 0x9f, 0xe1, 0x60, 0x21, 0x3e, 0x41, 0x1e, 0x48, 0x5e, 0x24, 0x40, 0xfe,
- 0xc0, 0x57, 0x6f, 0x67, 0x61, 0xf7, 0xe0, 0x27, 0x5d, 0x69, 0x74, 0x6f,
- 0x72, 0xf8, 0xe0, 0x2c, 0x13, 0x67, 0xe5, 0x03, 0x07, 0x88, 0x73, 0x74,
- 0x61, 0x63, 0xeb, 0xd7, 0x07, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0xf4, 0xd7,
- 0xa6, 0x61, 0xf0, 0xe0, 0x20, 0xb8, 0x65, 0xeb, 0xe0, 0x2b, 0x57, 0xae,
- 0x06, 0x06, 0x5b, 0x72, 0xcf, 0xcc, 0xe3, 0x60, 0x2a, 0xd3, 0xc0, 0xc8,
- 0xe1, 0xe0, 0x2b, 0x62, 0xe3, 0x06, 0x2b, 0x04, 0xe0, 0x2c, 0xa6, 0xef,
- 0x07, 0x0a, 0x0c, 0x06, 0xe0, 0x2c, 0xb1, 0x6e, 0xef, 0x04, 0xe0, 0x22,
- 0x94, 0xed, 0xe0, 0x2a, 0x15, 0x6d, 0x6d, 0x65, 0x72, 0x63, 0x65, 0x2d,
- 0x73, 0x68, 0xef, 0xdb, 0x61, 0x6c, 0x6f, 0xe7, 0xe0, 0x2a, 0x03, 0x2e,
- 0xe2, 0x60, 0x2a, 0x76, 0xc0, 0xef, 0xee, 0xe0, 0x2b, 0x5d, 0x68, 0x69,
- 0x7a, 0x65, 0x6e, 0x2e, 0x66, 0x75, 0x6b, 0xf5, 0xe0, 0x2a, 0x96, 0xe2,
- 0x04, 0xe0, 0x28, 0x07, 0xe9, 0x02, 0x84, 0x7a, 0xae, 0xcd, 0x3c, 0xee,
- 0x04, 0xe0, 0x27, 0xef, 0xef, 0xde, 0xcc, 0xe1, 0x05, 0x19, 0xe0, 0x2a,
- 0xc6, 0xf4, 0x05, 0x05, 0xe0, 0x2c, 0x74, 0x6f, 0xee, 0xe0, 0x24, 0x32,
- 0x69, 0x6e, 0x67, 0x2d, 0x6f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0xe3, 0xe0,
- 0x2c, 0x45, 0xf3, 0x02, 0x8b, 0x79, 0x70, 0x61, 0x6e, 0x65, 0x6c, 0xae,
- 0x4d, 0xab, 0xdd, 0x4a, 0xf4, 0x04, 0x05, 0x04, 0x8f, 0x75, 0x73, 0xb2,
- 0xd1, 0x6e, 0x63, 0xef, 0xd6, 0x0d, 0xe1, 0x02, 0x85, 0x73, 0x69, 0xe1,
- 0xd1, 0x62, 0x66, 0x72, 0x69, 0xe3, 0xe0, 0x26, 0x20, 0x2d, 0x6b, 0x61,
- 0x7a, 0x61, 0x6b, 0x68, 0x73, 0xf4, 0xde, 0x5a, 0xb4, 0xc7, 0x31, 0xb1,
- 0x02, 0x88, 0x36, 0x34, 0x2e, 0x61, 0xf2, 0xe0, 0x2a, 0x36, 0x32, 0xae,
- 0xe0, 0x21, 0x52, 0xae, 0x5b, 0x13, 0xd1, 0x07, 0xe4, 0x22, 0x07, 0x40,
- 0xec, 0x0a, 0x12, 0x21, 0x04, 0x1c, 0x40, 0x51, 0x03, 0x40, 0x6a, 0x40,
- 0x57, 0x09, 0x05, 0x40, 0xf3, 0x11, 0x06, 0x06, 0x41, 0xad, 0x38, 0x05,
- 0x40, 0xc6, 0x60, 0x23, 0x56, 0x21, 0x92, 0x1f, 0x43, 0x78, 0xee, 0xe0,
- 0x21, 0x6f, 0xf9, 0x05, 0x5e, 0x8f, 0xcc, 0xff, 0xee, 0x0b, 0x08, 0x04,
- 0x07, 0x40, 0x6a, 0x1c, 0x05, 0x1e, 0xc0, 0xb7, 0xf6, 0x03, 0xc0, 0xbe,
- 0xb6, 0xe0, 0x2b, 0xb3, 0xf5, 0xe0, 0x2b, 0xaf, 0x73, 0x65, 0x72, 0xf6,
- 0xe0, 0x28, 0xfa, 0x64, 0x6e, 0xf3, 0x03, 0x03, 0x99, 0xb1, 0xc6, 0xad,
- 0xae, 0x0b, 0x4d, 0x11, 0x4c, 0xab, 0x42, 0x38, 0x4c, 0x99, 0xc0, 0x56,
- 0xe4, 0x03, 0xc0, 0x85, 0x61, 0x70, 0x70, 0x6e, 0x6f, 0xe4, 0xe0, 0x22,
- 0x78, 0xad, 0x0e, 0x0a, 0x07, 0x06, 0x08, 0x06, 0x05, 0x09, 0x42, 0x09,
- 0x42, 0xbb, 0xc0, 0x94, 0xf7, 0x04, 0x2b, 0xc5, 0x1d, 0x69, 0xeb, 0xe0,
- 0x22, 0x18, 0x72, 0x65, 0x6d, 0xef, 0xe0, 0x24, 0x05, 0x70, 0x69, 0xe3,
- 0xe0, 0x2a, 0x77, 0x6f, 0x66, 0x66, 0x69, 0xe3, 0xe0, 0x23, 0xf8, 0x6d,
- 0x61, 0xe9, 0xe0, 0x24, 0xdf, 0x62, 0x6c, 0xef, 0xde, 0x60, 0x61, 0x74,
- 0xad, 0x02, 0x84, 0x77, 0xef, 0xd4, 0x77, 0x68, 0x6f, 0xed, 0xe0, 0x23,
- 0xde, 0xe1, 0x04, 0x05, 0xc1, 0xad, 0x74, 0x68, 0xef, 0xd5, 0xc4, 0x6d,
- 0xe9, 0x02, 0x87, 0x73, 0x63, 0x68, 0x65, 0xf3, 0xc4, 0xb9, 0x63, 0x2d,
- 0x64, 0x6e, 0xf3, 0xdb, 0x84, 0x35, 0xb3, 0xe0, 0x2a, 0x46, 0xae, 0x03,
- 0x0e, 0x86, 0x68, 0x6f, 0x6d, 0x65, 0x2d, 0x77, 0x65, 0x62, 0x73, 0x65,
- 0x72, 0xf6, 0xc6, 0x17, 0x64, 0x64, 0x6e, 0xf3, 0xc4, 0x98, 0x63, 0x6f,
- 0x73, 0xe9, 0xc4, 0x90, 0xad, 0x04, 0x03, 0x08, 0x86, 0x76, 0xf0, 0x94,
- 0x6f, 0x2d, 0x73, 0x61, 0xf5, 0xe0, 0x21, 0xa8, 0x69, 0x70, 0x32, 0xb4,
- 0xc5, 0xf7, 0x62, 0x65, 0x72, 0x6c, 0x69, 0xee, 0xc5, 0xef, 0x77, 0x65,
- 0x62, 0x2e, 0x6c, 0x69, 0xee, 0xe0, 0x24, 0xc1, 0xf6, 0x02, 0x8b, 0xf2,
- 0x05, 0x23, 0xe0, 0x2a, 0xcc, 0x63, 0x61, 0xed, 0xdb, 0x2b, 0xe1, 0xe0,
- 0x2a, 0xe8, 0xf5, 0x05, 0x08, 0x04, 0x06, 0x86, 0xf2, 0x03, 0xcf, 0x54,
- 0xe2, 0xe0, 0x26, 0xcc, 0x70, 0xef, 0xc1, 0xc8, 0x6e, 0x6c, 0xef, 0xe0,
- 0x29, 0x42, 0x63, 0x6b, 0x64, 0xee, 0xd6, 0x1d, 0xe2, 0xce, 0x89, 0xf4,
- 0xe0, 0x27, 0x1e, 0xf3, 0x03, 0x04, 0x85, 0xf4, 0xe0, 0x22, 0x77, 0x6d,
- 0x79, 0xee, 0xc1, 0x10, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0xae, 0x04, 0xe0,
- 0x27, 0x83, 0xed, 0x5a, 0xb2, 0xcf, 0x92, 0xf2, 0x08, 0x04, 0x07, 0x06,
- 0x06, 0x03, 0x0c, 0x9b, 0x1f, 0x43, 0xf8, 0x8f, 0x75, 0x64, 0xae, 0x4b,
- 0x7f, 0xde, 0x1c, 0x72, 0x2e, 0xe1, 0xe0, 0x2a, 0x7f, 0x6f, 0x62, 0xe1,
- 0xe0, 0x20, 0x41, 0xe9, 0xdf, 0xb6, 0x65, 0x61, 0x6d, 0x68, 0x6f, 0x73,
- 0x74, 0x65, 0xf2, 0xe0, 0x29, 0x6c, 0xe1, 0x03, 0x0d, 0x86, 0xf9, 0x03,
- 0xc3, 0xdb, 0xe4, 0x03, 0xc3, 0xd9, 0x64, 0xee, 0xe0, 0x29, 0x5b, 0x6e,
- 0x67, 0xe5, 0xe0, 0x23, 0x86, 0x6d, 0xed, 0xdb, 0x5c, 0xae, 0x5d, 0x0f,
- 0x49, 0x78, 0xc2, 0xa7, 0xf0, 0xce, 0xc3, 0xef, 0x10, 0x08, 0x05, 0x06,
- 0x06, 0x06, 0x17, 0x03, 0x05, 0x12, 0x60, 0x28, 0x39, 0x41, 0xb6, 0x81,
- 0x77, 0x6e, 0x6c, 0x6f, 0xe1, 0xe0, 0x27, 0xf6, 0x76, 0xf2, 0xe0, 0x28,
- 0xae, 0x73, 0x68, 0x69, 0xae, 0xcd, 0x25, 0x70, 0x61, 0xe1, 0xe0, 0x29,
- 0x1d, 0x6f, 0x6d, 0x64, 0x6e, 0xf3, 0xac, 0xee, 0x05, 0x08, 0x05, 0xdf,
- 0x8c, 0x74, 0x65, 0x78, 0x69, 0x73, 0xf4, 0xd6, 0x89, 0x6f, 0x73, 0xf4,
- 0xdd, 0x14, 0x65, 0xf4, 0xc0, 0x78, 0xed, 0xda, 0x66, 0x6c, 0xec, 0xe0,
- 0x22, 0xcb, 0x65, 0xf3, 0x03, 0xd3, 0xb2, 0x6e, 0x74, 0x65, 0x78, 0x69,
- 0x73, 0x74, 0xae, 0x60, 0x27, 0x24, 0xc2, 0xca, 0xe3, 0x04, 0xe0, 0x27,
- 0x89, 0xf4, 0xe0, 0x26, 0xb7, 0xee, 0x07, 0x3c, 0x05, 0x4e, 0x0e, 0xda,
- 0x01, 0xf3, 0x07, 0x0e, 0x07, 0x08, 0x06, 0x05, 0x86, 0x75, 0xf0, 0x04,
- 0xe0, 0x29, 0xad, 0x64, 0x61, 0x74, 0xe5, 0x44, 0xb7, 0xd5, 0x55, 0x6b,
- 0x69, 0x6e, 0xe7, 0xe0, 0x23, 0x43, 0x69, 0x73, 0x6b, 0x69, 0x6e, 0xeb,
- 0xcb, 0x2e, 0x68, 0x6f, 0x6d, 0xe5, 0xc4, 0xa1, 0x66, 0x6f, 0xf2, 0xd3,
- 0xb7, 0x64, 0x6f, 0x6a, 0xef, 0xd6, 0x1f, 0x61, 0x6c, 0x69, 0xe1, 0xd6,
- 0x18, 0xe9, 0x05, 0xe0, 0x24, 0x18, 0x65, 0x70, 0x72, 0x6f, 0x70, 0x65,
- 0x74, 0x72, 0x6f, 0x76, 0x73, 0xeb, 0xce, 0x02, 0x6c, 0x75, 0x67, 0x6f,
- 0x6c, 0x65, 0xeb, 0xdb, 0x1a, 0xeb, 0x5c, 0xde, 0xcc, 0xa8, 0xe9, 0x0d,
- 0x11, 0x0b, 0x40, 0x5d, 0x1e, 0x08, 0x0f, 0x1a, 0x11, 0xe0, 0x26, 0x6b,
- 0x76, 0xf4, 0x02, 0x85, 0x74, 0x61, 0xf3, 0xda, 0xa2, 0x61, 0x73, 0x76,
- 0x75, 0x6f, 0xe4, 0xde, 0xe3, 0x74, 0x63, 0x68, 0x79, 0x6f, 0x75, 0x72,
- 0xe9, 0xe0, 0x28, 0x75, 0xf3, 0x05, 0x21, 0xe0, 0x27, 0x93, 0xeb, 0x02,
- 0x90, 0x75, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x62, 0x65, 0x72, 0x65,
- 0x69, 0x63, 0xe8, 0xc4, 0x2c, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
- 0xae, 0x53, 0x3e, 0x51, 0x04, 0xc2, 0x24, 0x63, 0xef, 0x03, 0x08, 0x9a,
- 0x76, 0x65, 0xf2, 0x60, 0x20, 0xb6, 0xc8, 0x73, 0xf5, 0x02, 0x93, 0x72,
- 0x73, 0x65, 0xae, 0x02, 0x86, 0x74, 0x65, 0xe1, 0xe0, 0x29, 0x13, 0x67,
- 0x72, 0x6f, 0xf5, 0xe0, 0x27, 0xac, 0xee, 0xe0, 0x27, 0x56, 0x72, 0x64,
- 0xf3, 0x02, 0x85, 0x65, 0xfa, 0xe0, 0x28, 0xfb, 0x61, 0xf9, 0xe0, 0x27,
- 0xf1, 0x72, 0x65, 0x63, 0xf4, 0x05, 0x03, 0xe0, 0x28, 0xef, 0xef, 0xc1,
- 0xb7, 0x2e, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
- 0x63, 0x74, 0xae, 0x49, 0x72, 0xde, 0x3a, 0x6e, 0x6f, 0x73, 0x61, 0xf5,
- 0xe0, 0x21, 0xaf, 0x68, 0x65, 0x72, 0x2e, 0x73, 0x6f, 0x6c, 0x75, 0x74,
- 0x69, 0x6f, 0xee, 0xe0, 0x25, 0x4c, 0x67, 0xe9, 0x02, 0x93, 0x74, 0x61,
- 0xec, 0x04, 0xe0, 0x28, 0xbb, 0x6f, 0x63, 0x65, 0x61, 0x6e, 0x73, 0x70,
- 0x61, 0x63, 0xe5, 0xc6, 0x57, 0xe3, 0xda, 0x30, 0xe5, 0x04, 0xe0, 0x26,
- 0xf0, 0x6c, 0x64, 0x64, 0x61, 0x6e, 0x75, 0x6f, 0x72, 0xf2, 0xe0, 0x21,
- 0x22, 0xe1, 0x02, 0x85, 0x6d, 0x6f, 0xee, 0xcf, 0x66, 0x64, 0xe5, 0xd0,
- 0x6f, 0xe8, 0x04, 0xe0, 0x26, 0x42, 0x2e, 0x62, 0x79, 0x74, 0x65, 0x6d,
- 0x61, 0x72, 0xeb, 0xe0, 0x25, 0x2d, 0x67, 0x63, 0xe1, 0xe0, 0x25, 0x9c,
- 0x66, 0xae, 0x60, 0x22, 0x65, 0x83, 0xe5, 0x12, 0x40, 0x6e, 0x13, 0x16,
- 0x10, 0x21, 0x31, 0x3b, 0x05, 0x10, 0x0f, 0x11, 0x05, 0x0f, 0xe0, 0x26,
- 0xe2, 0xf6, 0x08, 0x14, 0x13, 0x0d, 0x23, 0xe0, 0x27, 0xff, 0x69, 0x63,
- 0x65, 0x73, 0x2e, 0x72, 0x65, 0x73, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x67,
- 0x69, 0x6e, 0xe7, 0xe0, 0x27, 0x4a, 0x65, 0x6c, 0x6f, 0xf0, 0x02, 0x89,
- 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x72, 0xf5, 0xd4, 0x21, 0x65, 0xf2, 0xd6,
- 0xce, 0x63, 0x64, 0x6e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0xef, 0xe0,
- 0x28, 0x0f, 0xae, 0x06, 0x0c, 0x54, 0x8e, 0xd2, 0x36, 0x73, 0x74, 0x61,
- 0x74, 0x69, 0x63, 0x2e, 0x6c, 0x61, 0xee, 0xdb, 0xc8, 0x61, 0x64, 0x6f,
- 0x62, 0x65, 0x61, 0x65, 0x6d, 0x63, 0x6c, 0x6f, 0x75, 0xe4, 0xe0, 0x27,
- 0xec, 0xad, 0x04, 0xe0, 0x21, 0x67, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65,
- 0xf2, 0xd1, 0x16, 0xf4, 0x05, 0x06, 0xe0, 0x26, 0x99, 0x72, 0x6f, 0xe9,
- 0xe0, 0x20, 0xa5, 0x61, 0xae, 0x43, 0x23, 0xe0, 0x23, 0x59, 0xf3, 0x05,
- 0x0c, 0xe0, 0x26, 0x80, 0xe9, 0x04, 0xe0, 0x27, 0xd3, 0x67, 0xee, 0x60,
- 0x20, 0xa3, 0xc7, 0x2e, 0x61, 0xae, 0xdf, 0xa6, 0xf0, 0x04, 0xe0, 0x26,
- 0x3c, 0xef, 0x04, 0xe0, 0x20, 0x7b, 0x72, 0x74, 0xe5, 0xe0, 0x25, 0x0c,
- 0xee, 0x03, 0x0a, 0x8e, 0xf4, 0x02, 0x83, 0xe9, 0xda, 0xbf, 0xe1, 0xe0,
- 0x25, 0x65, 0xef, 0x03, 0xc2, 0xe5, 0x2d, 0x73, 0x74, 0x61, 0x67, 0x69,
- 0x6e, 0xe7, 0xc2, 0xdd, 0x6d, 0x61, 0xf2, 0xdf, 0x42, 0x6d, 0xef, 0x04,
- 0x07, 0xca, 0x24, 0x63, 0x72, 0xe1, 0x4a, 0x5d, 0xdb, 0x7a, 0xae, 0x02,
- 0x8b, 0x6a, 0x65, 0x6c, 0x61, 0x73, 0x74, 0x69, 0xe3, 0xe0, 0x27, 0x77,
- 0x64, 0x61, 0x74, 0xe1, 0x02, 0x87, 0x64, 0x65, 0x74, 0x65, 0xe3, 0xdd,
- 0xcc, 0x63, 0x65, 0x6e, 0x74, 0x65, 0xf2, 0xe0, 0x27, 0x0f, 0xec, 0x08,
- 0x06, 0x08, 0x12, 0x07, 0x05, 0xda, 0xd1, 0x6f, 0x69, 0xf4, 0xe0, 0x20,
- 0xe3, 0x6d, 0x65, 0x6e, 0x68, 0x6f, 0xf2, 0xd1, 0x13, 0xec, 0x05, 0x01,
- 0xe0, 0x27, 0x48, 0x2d, 0x6f, 0x67, 0x6c, 0x69, 0x61, 0x73, 0x74, 0xf2,
- 0xe0, 0x20, 0xf9, 0x69, 0x76, 0x65, 0xf2, 0xe0, 0x25, 0x09, 0x68, 0xe9,
- 0xe0, 0x26, 0x07, 0x61, 0x77, 0xe1, 0xe0, 0x22, 0xe7, 0x67, 0xf2, 0xe0,
- 0x22, 0x76, 0xe6, 0x04, 0xe0, 0x25, 0xd5, 0x69, 0x6e, 0x69, 0x6d, 0x61,
- 0xae, 0x60, 0x26, 0x21, 0xc0, 0xd7, 0xe4, 0x02, 0x85, 0x79, 0xee, 0xe0,
- 0x26, 0x16, 0x69, 0x62, 0x6f, 0xf8, 0xe0, 0x26, 0x78, 0xe3, 0x04, 0x09,
- 0xd7, 0xbc, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x76, 0xe5, 0xd5, 0xc2, 0xe9,
- 0xde, 0xbf, 0x62, 0x69, 0xe1, 0xd3, 0x9b, 0xe1, 0x02, 0x85, 0x74, 0xee,
- 0xe0, 0x20, 0xc8, 0xec, 0x53, 0x7a, 0x51, 0x0c, 0xc2, 0x62, 0xae, 0x0b,
- 0x03, 0x04, 0x53, 0x54, 0x47, 0x31, 0x46, 0x3f, 0xc1, 0x32, 0xf4, 0xcb,
- 0xa2, 0xec, 0xe0, 0x26, 0x63, 0x63, 0xef, 0x04, 0xe0, 0x26, 0xc4, 0xef,
- 0xe0, 0x26, 0x15, 0xe4, 0x06, 0x2b, 0x5f, 0x6a, 0xc4, 0xc7, 0x6e, 0xf3,
- 0x07, 0x07, 0x05, 0x03, 0x05, 0x05, 0x84, 0x73, 0xae, 0x60, 0x23, 0xe2,
- 0xc2, 0x31, 0x6c, 0x69, 0xf6, 0xdf, 0x27, 0xeb, 0xd9, 0x96, 0x67, 0x65,
- 0xe5, 0xdd, 0xd9, 0x66, 0x72, 0xe5, 0xdf, 0x1a, 0xb5, 0xe0, 0x26, 0x93,
- 0xae, 0x50, 0x9e, 0xd5, 0xd6, 0x2d, 0x64, 0x6e, 0xf3, 0xc1, 0x7a, 0xe3,
- 0x5a, 0xb2, 0xc6, 0x55, 0xe1, 0x10, 0x07, 0x18, 0x3c, 0x09, 0x04, 0x08,
- 0x08, 0x17, 0x09, 0x18, 0x56, 0x8a, 0x4c, 0xf8, 0x95, 0x7a, 0x61, 0x69,
- 0x66, 0xf5, 0xcf, 0x22, 0x76, 0x76, 0xe5, 0x02, 0x87, 0x73, 0x69, 0x69,
- 0xe4, 0xe0, 0x20, 0x91, 0x6e, 0xea, 0x02, 0x82, 0x1f, 0x43, 0x61, 0x72,
- 0xe7, 0xe0, 0x20, 0x85, 0xf4, 0x06, 0x17, 0x05, 0x0b, 0xd0, 0xda, 0x74,
- 0xef, 0x03, 0x04, 0x86, 0x77, 0xe5, 0xdd, 0x23, 0x72, 0x65, 0x6c, 0xe1,
- 0xc7, 0xb6, 0x6c, 0x6f, 0x63, 0x61, 0xec, 0xe0, 0x22, 0xdf, 0x73, 0xf5,
- 0xe0, 0x25, 0x0d, 0xe5, 0x04, 0xe0, 0x26, 0x30, 0xae, 0x60, 0x20, 0xe5,
- 0xc3, 0x9f, 0xe1, 0x04, 0xe0, 0x26, 0x25, 0x62, 0x61, 0x73, 0x65, 0xae,
- 0x4f, 0x4b, 0xd4, 0x1d, 0xf0, 0x03, 0xce, 0x8a, 0x6c, 0x69, 0xe5, 0xd0,
- 0x1b, 0xee, 0xe0, 0x21, 0x2e, 0x6d, 0x6e, 0x73, 0x65, 0x72, 0xf6, 0xdc,
- 0x9d, 0xec, 0x03, 0xda, 0x2e, 0x6c, 0xe1, 0xde, 0xc7, 0xe9, 0x04, 0x04,
- 0x04, 0x87, 0x77, 0xe1, 0xda, 0xae, 0xf4, 0xe0, 0x24, 0x26, 0x73, 0x65,
- 0x6e, 0xae, 0xe0, 0x20, 0x2c, 0xe7, 0xd6, 0x8b, 0x67, 0x65, 0x73, 0x74,
- 0x61, 0xee, 0xe0, 0x22, 0x57, 0xe5, 0x03, 0x0b, 0x85, 0x6d, 0x6f, 0x6e,
- 0x2e, 0x70, 0x61, 0x6e, 0x65, 0xec, 0xc0, 0x7b, 0x6a, 0x65, 0xef, 0xce,
- 0xa4, 0x67, 0xf5, 0xce, 0xa1, 0x62, 0xf5, 0xe0, 0x24, 0x7b, 0xae, 0x05,
- 0x54, 0xb3, 0xd1, 0x07, 0x67, 0xf6, 0xe0, 0x25, 0xa9, 0xe3, 0x27, 0x13,
- 0x2a, 0x08, 0x05, 0x40, 0xba, 0x06, 0x16, 0x40, 0x7a, 0x03, 0x04, 0x44,
- 0x34, 0x40, 0x4e, 0x41, 0x7a, 0x05, 0x40, 0xc2, 0x42, 0x05, 0x0e, 0x40,
- 0x4b, 0x2d, 0x40, 0xb0, 0x0f, 0x41, 0xd6, 0x04, 0x55, 0x9e, 0x1e, 0xc2,
- 0x4a, 0xfa, 0x05, 0x53, 0x6e, 0xd2, 0x1b, 0xe5, 0x02, 0x85, 0x73, 0xf4,
- 0xe0, 0x20, 0xf4, 0x6c, 0x61, 0xe4, 0xce, 0x18, 0xf9, 0x08, 0x10, 0x08,
- 0x03, 0x58, 0xb0, 0xcc, 0xa8, 0xef, 0x04, 0xe0, 0x24, 0x7b, 0x6e, 0xae,
- 0x03, 0xcd, 0xfa, 0x6c, 0x69, 0xee, 0xe0, 0x25, 0x2e, 0x6d, 0x72, 0xf5,
- 0x60, 0x22, 0xa7, 0xc2, 0xb9, 0xe2, 0xde, 0x30, 0x61, 0x2e, 0xe7, 0xe0,
- 0x22, 0x86, 0xf8, 0x04, 0xe0, 0x25, 0x4d, 0xae, 0xd2, 0x50, 0xf6, 0x49,
- 0xb9, 0xdb, 0x90, 0xf5, 0x0b, 0x08, 0x40, 0x6c, 0x0d, 0x0a, 0x05, 0x0e,
- 0xe0, 0x24, 0x9b, 0x74, 0x65, 0x67, 0x69, 0x72, 0xec, 0xdc, 0xfa, 0x73,
- 0xf4, 0x02, 0xb4, 0x6f, 0xed, 0x02, 0x9f, 0x65, 0xf2, 0x02, 0x94, 0xae,
- 0x03, 0xcc, 0x11, 0x73, 0x70, 0x65, 0x65, 0x64, 0x70, 0x61, 0x72, 0x74,
- 0x6e, 0x65, 0x72, 0xae, 0xe0, 0x24, 0x74, 0x2d, 0x6f, 0x63, 0xe9, 0xe0,
- 0x24, 0xf7, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x72,
- 0x75, 0x6d, 0x2e, 0xe3, 0xe0, 0x21, 0xd7, 0xae, 0x04, 0x08, 0x0c, 0x85,
- 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0xe7, 0x9d, 0x72, 0x65, 0x74, 0x72,
- 0x6f, 0x73, 0x6e, 0x75, 0xe2, 0xe0, 0x21, 0x8f, 0x70, 0x72, 0x6f, 0xe4,
- 0x8c, 0xe4, 0x02, 0x86, 0x69, 0x73, 0x72, 0x65, 0xe3, 0x83, 0x65, 0x76,
- 0x2e, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x64, 0x75, 0xf3, 0xd2, 0x0e, 0xf2,
- 0x02, 0x86, 0x76, 0x2e, 0x64, 0xe5, 0xd2, 0xc7, 0x69, 0x74, 0xe9, 0xab,
- 0x70, 0x63, 0x61, 0x6b, 0x65, 0x2e, 0xe9, 0xe0, 0x24, 0x42, 0x6e, 0xe5,
- 0xe0, 0x22, 0xaf, 0x6c, 0x74, 0x75, 0xf2, 0x04, 0xe0, 0x20, 0x5b, 0x61,
- 0xec, 0x59, 0xf4, 0xc7, 0xf2, 0xe9, 0x02, 0x89, 0x73, 0x69, 0x6e, 0x65,
- 0x6c, 0xec, 0xe0, 0x22, 0xf9, 0x61, 0xe2, 0xdb, 0x7d, 0x74, 0xae, 0x5f,
- 0xb0, 0xc2, 0xde, 0xf3, 0x02, 0x86, 0x78, 0x2e, 0xe3, 0xe0, 0x24, 0x70,
- 0xae, 0x03, 0xcc, 0x5e, 0x6b, 0x65, 0x6c, 0x69, 0x77, 0x65, 0xe2, 0xcc,
- 0x50, 0xf2, 0x0d, 0x10, 0x09, 0x09, 0x12, 0x19, 0x1a, 0x4a, 0xac, 0x56,
- 0xec, 0xc2, 0x62, 0x79, 0x70, 0x74, 0x6f, 0x6e, 0x6f, 0x6d, 0x69, 0x63,
- 0x2e, 0x6e, 0x65, 0xf4, 0xe0, 0x24, 0x42, 0x75, 0x69, 0x73, 0xe5, 0x60,
- 0x21, 0xeb, 0xc2, 0x62, 0xef, 0x03, 0xcb, 0x57, 0x74, 0x6f, 0xee, 0xdd,
- 0x79, 0xe9, 0x03, 0x05, 0x84, 0x6d, 0x65, 0xe1, 0xc8, 0xa8, 0x63, 0xeb,
- 0xd1, 0x61, 0xae, 0x5d, 0xc1, 0xc5, 0x25, 0xe5, 0x05, 0x04, 0x03, 0xd9,
- 0x6a, 0xf7, 0xe0, 0x21, 0x47, 0xed, 0xdc, 0x50, 0x64, 0x69, 0xf4, 0x05,
- 0x54, 0x8c, 0xcf, 0x8c, 0x75, 0xee, 0xd7, 0x6b, 0xe1, 0x02, 0x8c, 0xee,
- 0x02, 0x83, 0xeb, 0xdb, 0xd3, 0x62, 0x72, 0x6f, 0xef, 0xdb, 0xb0, 0x66,
- 0xf4, 0x03, 0xdc, 0xc6, 0x69, 0x6e, 0x67, 0xae, 0xd0, 0x69, 0xae, 0x48,
- 0x6a, 0xd9, 0x94, 0xf1, 0xd0, 0xb7, 0xf0, 0xe0, 0x22, 0x6d, 0xef, 0x16,
- 0x35, 0x0d, 0x25, 0x0e, 0x40, 0x49, 0x40, 0x62, 0x41, 0xad, 0x40, 0x44,
- 0x03, 0x04, 0x1c, 0x06, 0x11, 0x4e, 0x65, 0xd2, 0x27, 0xf5, 0x04, 0x04,
- 0x08, 0x96, 0x72, 0xf3, 0xd7, 0xd3, 0x70, 0x6f, 0xee, 0x60, 0x21, 0x69,
- 0xc2, 0x62, 0xee, 0x02, 0x8f, 0xf4, 0x03, 0xdb, 0x4c, 0x72, 0xf9, 0x04,
- 0xe0, 0x23, 0xb9, 0x65, 0x73, 0xf4, 0xc7, 0x08, 0x63, 0xe9, 0xde, 0xed,
- 0x63, 0x68, 0x70, 0x6f, 0x74, 0x61, 0x74, 0x6f, 0x66, 0x72, 0x69, 0xe5,
- 0xce, 0xf7, 0xf3, 0x02, 0x85, 0x74, 0x75, 0xed, 0xdf, 0x56, 0x65, 0x6e,
- 0xfa, 0xdd, 0x50, 0xf2, 0x04, 0x05, 0x05, 0x91, 0x76, 0x65, 0xf4, 0xc6,
- 0xe0, 0x73, 0xe9, 0xe0, 0x21, 0xef, 0x72, 0x65, 0x69, 0x6f, 0x73, 0x2d,
- 0x65, 0x2d, 0x74, 0x65, 0x6c, 0x65, 0x63, 0x6f, 0xed, 0xc0, 0xcd, 0x70,
- 0x6f, 0xf2, 0xd8, 0xbc, 0xf0, 0x02, 0x84, 0xf2, 0xe0, 0x20, 0x1a, 0x65,
- 0x6e, 0x68, 0x61, 0xe7, 0xcd, 0xea, 0xef, 0x03, 0x2b, 0x8b, 0xf0, 0x05,
- 0x09, 0xe0, 0x23, 0x4f, 0x65, 0x72, 0x61, 0x74, 0x69, 0xf6, 0xe0, 0x20,
- 0xa2, 0xae, 0x0e, 0x04, 0x04, 0x51, 0x5c, 0x46, 0x17, 0x48, 0x59, 0x41,
- 0xb4, 0x40, 0x6d, 0x9f, 0xf2, 0xe0, 0x20, 0xd6, 0xf0, 0xe0, 0x21, 0x0b,
- 0xed, 0x5f, 0x91, 0xc1, 0x3d, 0xec, 0x04, 0xe0, 0x23, 0x2e, 0x62, 0x6c,
- 0x6f, 0xe7, 0xda, 0xf1, 0x6b, 0x69, 0x6e, 0xe7, 0x04, 0xe0, 0x23, 0x20,
- 0x63, 0x68, 0x61, 0x6e, 0xee, 0xde, 0x0d, 0xee, 0x06, 0x05, 0x26, 0x19,
- 0x03, 0x8f, 0x76, 0x65, 0xee, 0xdb, 0xcc, 0xf4, 0x03, 0x0c, 0x8c, 0xf2,
- 0x03, 0xde, 0x3f, 0x61, 0x63, 0x74, 0x6f, 0xf2, 0xe0, 0x20, 0x9e, 0x65,
- 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0xf9, 0x57, 0x41, 0xc8, 0xfb, 0xe1,
- 0x02, 0x83, 0xe7, 0xd1, 0x79, 0xe3, 0xe0, 0x21, 0x33, 0xf3, 0x02, 0x91,
- 0x75, 0xec, 0x02, 0x87, 0xf4, 0x03, 0xc9, 0x2f, 0xe1, 0xdb, 0x41, 0x61,
- 0x64, 0x6f, 0xae, 0xd5, 0xe4, 0x74, 0x72, 0xf5, 0xd6, 0x23, 0xee, 0xdf,
- 0x7c, 0xe6, 0x02, 0x85, 0x65, 0x72, 0xe5, 0xde, 0x0c, 0xae, 0x57, 0x08,
- 0x48, 0x9f, 0xc2, 0xb5, 0x64, 0xef, 0xe0, 0x20, 0x58, 0xed, 0x0c, 0x0c,
- 0x04, 0x40, 0x4c, 0x2e, 0x04, 0x60, 0x20, 0x1f, 0xc1, 0xfd, 0x75, 0x6e,
- 0x69, 0x63, 0x61, 0x1f, 0x43, 0x67, 0x1f, 0xc3, 0xdb, 0x64, 0x73, 0xe5,
- 0xd6, 0xb4, 0xf0, 0x03, 0xc0, 0x40, 0x75, 0x74, 0xe5, 0x03, 0x0d, 0x9e,
- 0xf2, 0x05, 0x5f, 0xd1, 0xc2, 0xb9, 0x68, 0x69, 0x73, 0x74, 0xef, 0xd7,
- 0xc3, 0xae, 0x02, 0x86, 0x65, 0x73, 0x74, 0xe1, 0xc3, 0x9f, 0x61, 0x6d,
- 0x61, 0x7a, 0x6f, 0x6e, 0x61, 0x77, 0x73, 0x2e, 0x63, 0x6f, 0xed, 0x04,
- 0xe0, 0x22, 0x57, 0x2e, 0xe3, 0xcb, 0x94, 0x2d, 0x31, 0x2e, 0x61, 0x6d,
- 0x61, 0x7a, 0x6f, 0x6e, 0x61, 0x77, 0xf3, 0xe0, 0x22, 0x43, 0xe1, 0x03,
- 0xdf, 0x89, 0xee, 0xe0, 0x20, 0x21, 0xed, 0x02, 0xa6, 0x75, 0xee, 0x02,
- 0x9e, 0xe9, 0x02, 0x91, 0x74, 0xf9, 0x05, 0x5f, 0x84, 0xc2, 0xb9, 0x2d,
- 0x70, 0x72, 0x6f, 0xae, 0x60, 0x21, 0x98, 0xc0, 0x7d, 0x63, 0x61, 0x74,
- 0x69, 0x6f, 0xee, 0x5a, 0xf3, 0xc4, 0x81, 0x65, 0xae, 0xda, 0xbc, 0x62,
- 0x61, 0xee, 0xdf, 0xc3, 0x63, 0xe1, 0xd5, 0x2d, 0xae, 0x1b, 0x04, 0x03,
- 0x0a, 0x08, 0x0a, 0x17, 0x07, 0x04, 0x0e, 0x0b, 0x12, 0x0e, 0x0b, 0x03,
- 0x0d, 0x08, 0x0d, 0x06, 0x0b, 0x08, 0x0d, 0x11, 0x4e, 0x18, 0xcc, 0x4d,
- 0xf9, 0xe0, 0x20, 0x91, 0xf7, 0xdf, 0x99, 0xf6, 0x56, 0x10, 0x49, 0xd6,
- 0x40, 0xa4, 0x40, 0x43, 0xb8, 0xf5, 0x5f, 0x82, 0x3c, 0x40, 0x97, 0xc1,
- 0x98, 0xf4, 0x5f, 0x7d, 0x1e, 0x12, 0x40, 0x82, 0x3a, 0x33, 0x9f, 0xf3,
- 0x55, 0xf4, 0x41, 0xf3, 0x46, 0x4f, 0x41, 0x44, 0x1a, 0x03, 0x15, 0x40,
- 0x79, 0x19, 0x05, 0x1c, 0x40, 0x52, 0x40, 0xc6, 0xc0, 0x64, 0xf2, 0x60,
- 0x20, 0x48, 0x0f, 0xc0, 0xe6, 0xf1, 0xe0, 0x20, 0x25, 0xf0, 0x56, 0xf0,
- 0x48, 0x68, 0x03, 0x17, 0x18, 0x40, 0x79, 0x19, 0x05, 0x2b, 0xa4, 0xee,
- 0x56, 0xe2, 0x48, 0xb8, 0x40, 0x79, 0x40, 0x4f, 0xc1, 0x49, 0xed, 0x5a,
- 0x3c, 0x43, 0xbf, 0x41, 0x3d, 0x07, 0x03, 0x17, 0x18, 0x40, 0x79, 0x3a,
- 0x40, 0x8a, 0xc0, 0xf2, 0xec, 0x55, 0xa7, 0x41, 0xf3, 0x46, 0x4f, 0x41,
- 0x47, 0x2f, 0x40, 0x97, 0xc0, 0x4f, 0xeb, 0x5f, 0x15, 0x03, 0x1e, 0x1b,
- 0x1e, 0x40, 0x83, 0xc1, 0x8e, 0xea, 0xdf, 0xf9, 0xe9, 0x08, 0x5f, 0x09,
- 0x17, 0x40, 0xce, 0xc0, 0x52, 0xf1, 0xe0, 0x21, 0x6a, 0xe8, 0x5f, 0x07,
- 0x40, 0xa8, 0x40, 0x6d, 0x9f, 0xe7, 0x5f, 0x16, 0x18, 0x1e, 0x40, 0x5b,
- 0x19, 0x0f, 0x21, 0x24, 0x1f, 0xb8, 0xe6, 0x5f, 0x06, 0x12, 0xc0, 0xef,
- 0xe5, 0x55, 0x63, 0x49, 0x86, 0x40, 0xab, 0x40, 0x49, 0xc1, 0x6d, 0xe4,
- 0x5e, 0xd4, 0x21, 0x40, 0xce, 0xc1, 0x18, 0xe3, 0x5d, 0x92, 0x41, 0x3d,
- 0x1e, 0x1b, 0x1e, 0x40, 0x95, 0x40, 0x52, 0xb8, 0xe2, 0x57, 0x36, 0x47,
- 0x89, 0x0a, 0x17, 0x12, 0x09, 0x1e, 0x40, 0x5b, 0x19, 0x05, 0x1c, 0x33,
- 0x9f, 0xe1, 0x55, 0x32, 0x41, 0x1e, 0x48, 0x5e, 0x03, 0x1e, 0x03, 0x36,
- 0x40, 0xc8, 0x40, 0x57, 0xc0, 0xf2, 0xec, 0x05, 0x07, 0x1f, 0x12, 0x83,
- 0x75, 0x6d, 0xe2, 0x43, 0xaf, 0xd0, 0x56, 0xef, 0x03, 0x0b, 0x8d, 0x72,
- 0x61, 0x64, 0x6f, 0x70, 0x6c, 0x61, 0x74, 0xe5, 0xcf, 0x51, 0x6e, 0x69,
- 0x61, 0x6c, 0x77, 0x69, 0x6c, 0x6c, 0x69, 0x61, 0xed, 0xc4, 0x0c, 0xe7,
- 0xca, 0xca, 0x6c, 0xe5, 0x02, 0x8b, 0x67, 0xe5, 0x04, 0xe0, 0x20, 0xd4,
- 0x66, 0x61, 0xee, 0xdd, 0xff, 0xe3, 0xd6, 0x19, 0xe4, 0xc2, 0xf4, 0xae,
- 0xcc, 0xeb, 0xe7, 0xd8, 0x80, 0x66, 0xe6, 0xdc, 0x0e, 0xe4, 0x03, 0xd8,
- 0x48, 0xe5, 0x04, 0x08, 0xc9, 0xd8, 0xf3, 0x04, 0xe0, 0x20, 0xb1, 0xf0,
- 0xd6, 0xfa, 0x62, 0x65, 0x72, 0x67, 0x2e, 0x70, 0x61, 0xe7, 0xe0, 0x20,
- 0x41, 0x63, 0x6f, 0x74, 0xf4, 0xd2, 0x27, 0xe1, 0x05, 0x4b, 0x2c, 0xcb,
- 0x47, 0x73, 0x74, 0x61, 0x6c, 0x64, 0x65, 0x66, 0x65, 0xee, 0xcd, 0xea,
- 0xae, 0x1a, 0x05, 0x09, 0x12, 0x05, 0x06, 0x0f, 0x0d, 0x0b, 0x05, 0x09,
- 0x04, 0x0a, 0x06, 0x09, 0x12, 0x0d, 0x12, 0x59, 0x0d, 0x44, 0x1f, 0x41,
- 0xa3, 0xc0, 0xbb, 0xf6, 0x5e, 0x5e, 0xc0, 0xa4, 0xf5, 0x50, 0x91, 0x4d,
- 0x6e, 0x0a, 0x03, 0xc2, 0x5e, 0xf4, 0x08, 0x5d, 0xee, 0x21, 0x12, 0x40,
- 0x82, 0x99, 0x65, 0x63, 0x68, 0x6e, 0x6f, 0x6c, 0xef, 0xcf, 0x3f, 0xf3,
- 0x5d, 0xe4, 0xc0, 0xb5, 0xf2, 0x5d, 0xe2, 0x07, 0xc2, 0x27, 0xf0, 0x05,
- 0x5d, 0xd7, 0xc1, 0x3e, 0xec, 0x04, 0xe0, 0x20, 0x37, 0x61, 0xe3, 0xdf,
- 0xd4, 0xee, 0x55, 0x41, 0x48, 0x89, 0x40, 0x5a, 0x40, 0x79, 0x40, 0xe6,
- 0xc0, 0x78, 0xed, 0x5d, 0xbd, 0x03, 0x40, 0xd0, 0x2b, 0x40, 0x7b, 0xc0,
- 0xf2, 0xec, 0x54, 0x36, 0xc9, 0x86, 0xeb, 0x03, 0xde, 0xa8, 0xf2, 0x53,
- 0xcc, 0xcc, 0x49, 0xea, 0x5e, 0x81, 0xa1, 0xe9, 0x5d, 0xc1, 0x03, 0x03,
- 0x40, 0x8e, 0x40, 0x6d, 0x9f, 0xe7, 0x5d, 0xba, 0x18, 0xc2, 0x2f, 0x66,
- 0x69, 0x6e, 0x61, 0x6e, 0x63, 0xe9, 0xc1, 0x39, 0xe5, 0x02, 0x86, 0x76,
- 0x65, 0x6e, 0xf4, 0xdf, 0x7e, 0x64, 0x75, 0x63, 0x61, 0x74, 0x69, 0xef,
- 0xcb, 0xd0, 0xe3, 0x50, 0x07, 0x4c, 0xb5, 0x40, 0xda, 0x03, 0x36, 0x40,
- 0xc8, 0xc1, 0x44, 0xe2, 0x09, 0x4b, 0xb7, 0x4a, 0x1f, 0x47, 0x8c, 0x30,
- 0xa7, 0x75, 0x73, 0x69, 0x6e, 0x65, 0xf3, 0xdf, 0x56, 0xe1, 0x5d, 0x77,
- 0x40, 0x94, 0x3a, 0x0f, 0xc1, 0x6d, 0xee, 0x08, 0x03, 0x0a, 0x07, 0x03,
- 0x0b, 0xdf, 0x8f, 0xf4, 0xde, 0x64, 0x73, 0x2e, 0x6a, 0x6f, 0x79, 0x65,
- 0x6e, 0xf4, 0xdf, 0x90, 0x70, 0x79, 0x2e, 0x67, 0xe4, 0xcb, 0x8b, 0xe7,
- 0xde, 0x50, 0xae, 0x44, 0x0a, 0x43, 0x75, 0x44, 0x99, 0x4d, 0x76, 0xc6,
- 0x04, 0x2d, 0x6e, 0x6f, 0x72, 0x74, 0xe8, 0x02, 0x84, 0x77, 0x65, 0x73,
- 0x74, 0x2d, 0x31, 0x2e, 0x65, 0x62, 0x2e, 0x61, 0x6d, 0x61, 0x7a, 0x6f,
- 0x6e, 0x61, 0x77, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0xe3, 0xcb, 0x5a,
- 0xec, 0x0a, 0x11, 0x41, 0x17, 0x1e, 0x1c, 0x5c, 0x03, 0xc1, 0xfc, 0x75,
- 0xe2, 0x04, 0x04, 0xdf, 0x57, 0x6d, 0xe5, 0xdd, 0x14, 0xae, 0x03, 0xdc,
- 0x75, 0xf4, 0xdc, 0xe9, 0xef, 0x04, 0x41, 0x0b, 0x84, 0x75, 0xe4, 0x0e,
- 0x09, 0x0e, 0x23, 0x06, 0x18, 0x0a, 0x0d, 0x20, 0x0c, 0x40, 0x52, 0xde,
- 0x4e, 0x79, 0x63, 0x6c, 0x75, 0x73, 0x74, 0xe5, 0xc3, 0xe1, 0x73, 0x69,
- 0x74, 0x65, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0xf2, 0xde, 0xb7,
- 0x6e, 0x73, 0xae, 0x0b, 0x03, 0x05, 0x03, 0x05, 0x5a, 0x11, 0x41, 0xce,
- 0xc0, 0x56, 0xf5, 0xde, 0xa6, 0xf0, 0x4a, 0xc7, 0xc4, 0x44, 0xe9, 0xcf,
- 0x25, 0xe3, 0x4f, 0x2b, 0xcf, 0xd0, 0x61, 0x73, 0xe9, 0xcf, 0x29, 0x6a,
- 0x69, 0x66, 0xe6, 0xdd, 0xa5, 0xe6, 0x03, 0x09, 0x85, 0x75, 0x6e, 0x63,
- 0x74, 0x69, 0x6f, 0xee, 0xde, 0xcb, 0x72, 0x6f, 0xee, 0xd2, 0x83, 0x6c,
- 0x61, 0x72, 0xe5, 0xc3, 0xc7, 0x65, 0x72, 0x61, 0x2e, 0x73, 0x69, 0x74,
- 0xe5, 0xde, 0xc9, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0xec, 0x03, 0xdd,
- 0xe7, 0xec, 0xd5, 0x30, 0xe1, 0x02, 0x8f, 0x70, 0xf0, 0x03, 0xde, 0xa0,
- 0x73, 0x2e, 0x64, 0x69, 0x67, 0x69, 0x74, 0xe1, 0xde, 0x09, 0x63, 0x63,
- 0x65, 0x73, 0x73, 0xae, 0x03, 0xde, 0x8e, 0x68, 0x6f, 0xf3, 0xde, 0x8d,
- 0x36, 0x36, 0xae, 0x02, 0x84, 0x7a, 0xef, 0xce, 0xa8, 0xf7, 0xde, 0x33,
- 0xae, 0x07, 0x0d, 0x10, 0x13, 0x15, 0xd4, 0xf4, 0x6e, 0x6f, 0x73, 0x70,
- 0x61, 0x6d, 0x70, 0x72, 0x6f, 0x78, 0xf9, 0xde, 0x85, 0x6d, 0x65, 0x74,
- 0x61, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x6d, 0x2e, 0x63, 0xfa, 0xde,
- 0x6b, 0x6a, 0x65, 0x6c, 0x61, 0x73, 0x74, 0x69, 0x63, 0x2e, 0x6f, 0x70,
- 0x65, 0x6e, 0x2e, 0x74, 0x69, 0xed, 0xde, 0x1f, 0x69, 0x6e, 0x74, 0x65,
- 0x72, 0x68, 0x6f, 0x73, 0x74, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f,
- 0x6e, 0x73, 0xae, 0xdd, 0xab, 0x67, 0x6f, 0xef, 0xdb, 0x81, 0x2d, 0x66,
- 0x72, 0x31, 0x2e, 0x75, 0x6e, 0x69, 0x73, 0x70, 0x61, 0xe3, 0xd5, 0x10,
- 0x74, 0xe8, 0xc8, 0xee, 0xe3, 0xd5, 0xe4, 0xe9, 0x02, 0x89, 0xee, 0x03,
- 0xc5, 0x4b, 0xe9, 0x48, 0x94, 0xc9, 0xb5, 0x63, 0xeb, 0x04, 0x08, 0xde,
- 0x1f, 0x72, 0x69, 0x73, 0x69, 0x6e, 0xe7, 0xdd, 0xfd, 0x65, 0xf4, 0xd8,
- 0xe0, 0xe5, 0x03, 0x09, 0x8b, 0x76, 0x65, 0x72, 0x61, 0x70, 0x70, 0xf3,
- 0xdd, 0x15, 0x72, 0xeb, 0x03, 0xdc, 0xa1, 0x73, 0x74, 0x61, 0xe7, 0xc8,
- 0xb2, 0x61, 0xee, 0xc8, 0xb1, 0xe1, 0x02, 0x86, 0x6e, 0x2e, 0x72, 0xe9,
- 0xdc, 0x93, 0x69, 0xed, 0xdb, 0x92, 0xeb, 0x42, 0x61, 0xca, 0x8a, 0xe9,
- 0x0f, 0x18, 0x40, 0x59, 0x15, 0x08, 0x07, 0x0e, 0x0c, 0x59, 0xd4, 0x41,
- 0x5e, 0xc1, 0xfc, 0x76, 0x69, 0xec, 0x03, 0x04, 0x89, 0x77, 0xe1, 0xd6,
- 0xac, 0xe9, 0x02, 0x83, 0xfa, 0xd3, 0x19, 0xf3, 0xd3, 0x16, 0x61, 0x76,
- 0xe9, 0xda, 0xe3, 0xf4, 0x04, 0x40, 0x4b, 0x85, 0xf9, 0x04, 0x04, 0xdd,
- 0xb7, 0x65, 0xe1, 0xd4, 0xa2, 0xae, 0x06, 0x08, 0x0f, 0x07, 0xdc, 0x9e,
- 0x79, 0x6f, 0x6b, 0x6f, 0x68, 0x61, 0xed, 0x95, 0xf3, 0x02, 0x85, 0x65,
- 0x6e, 0x64, 0xe1, 0xa7, 0x61, 0x70, 0x70, 0x6f, 0x72, 0xef, 0xa1, 0x6e,
- 0x61, 0x67, 0x6f, 0x79, 0xe1, 0x9a, 0xeb, 0x03, 0x04, 0x8a, 0x6f, 0x62,
- 0xe5, 0x92, 0x69, 0x74, 0x61, 0x6b, 0x79, 0x75, 0x73, 0x68, 0xf5, 0x88,
- 0x61, 0x77, 0x61, 0x73, 0x61, 0x6b, 0x69, 0x2e, 0x6a, 0x70, 0x85, 0xe9,
- 0x51, 0x8c, 0xcb, 0xe8, 0x61, 0xe4, 0xd8, 0x60, 0xf3, 0x02, 0x87, 0x74,
- 0x72, 0x6f, 0x6e, 0xae, 0xdc, 0xb0, 0x63, 0xef, 0x03, 0xdd, 0x5d, 0x66,
- 0x72, 0x65, 0xe1, 0xd4, 0x8f, 0x72, 0xe3, 0x03, 0xdb, 0x66, 0xf5, 0xd6,
- 0x17, 0x70, 0x72, 0x69, 0x61, 0xee, 0xdb, 0x38, 0xee, 0x02, 0x83, 0xe5,
- 0xd7, 0x25, 0x63, 0x69, 0x6e, 0x6e, 0x61, 0xf4, 0xd1, 0x67, 0xe5, 0x02,
- 0x85, 0x73, 0x7a, 0xf9, 0xcb, 0xee, 0x6e, 0xe3, 0xda, 0x7f, 0xe1, 0xc4,
- 0x30, 0xe8, 0x0d, 0x2a, 0x0a, 0x18, 0x27, 0x40, 0xe9, 0x40, 0x43, 0x40,
- 0x41, 0xdb, 0x3d, 0xf5, 0x05, 0x03, 0x13, 0xd4, 0xc8, 0xf2, 0xc7, 0xab,
- 0x6f, 0xae, 0x08, 0x51, 0x87, 0x48, 0x3b, 0x41, 0x72, 0x89, 0x79, 0x61,
- 0x6d, 0x61, 0x6e, 0x61, 0xf3, 0xda, 0xfc, 0x6e, 0xe7, 0x02, 0x85, 0x6e,
- 0x61, 0xed, 0xc5, 0xd2, 0x62, 0x75, 0xeb, 0xc5, 0xcd, 0x74, 0x72, 0x2e,
- 0x6b, 0x31, 0x32, 0x2e, 0xed, 0xc2, 0xe3, 0xf2, 0x02, 0x84, 0x6f, 0xed,
- 0xdb, 0x76, 0x69, 0x73, 0xf4, 0x02, 0x83, 0xed, 0xc8, 0x19, 0x69, 0x61,
- 0x6e, 0x73, 0x62, 0x75, 0xf2, 0xc5, 0xee, 0xef, 0x06, 0x03, 0x04, 0x09,
- 0x05, 0x84, 0xf9, 0xd2, 0xb5, 0x77, 0xe4, 0xca, 0x01, 0xf3, 0x02, 0x82,
- 0xe8, 0x82, 0x65, 0xe9, 0xda, 0xe5, 0x6e, 0x61, 0xee, 0xda, 0xe0, 0x66,
- 0xf5, 0xd9, 0x6a, 0x63, 0x6f, 0x6c, 0x61, 0xf4, 0xd8, 0x66, 0xe9, 0x10,
- 0x09, 0x09, 0x0b, 0x2f, 0x0a, 0x08, 0x07, 0x14, 0x28, 0x0c, 0x0d, 0x07,
- 0x04, 0xda, 0x01, 0x7a, 0x75, 0x2e, 0x74, 0x6f, 0x74, 0xf4, 0xd3, 0xf4,
- 0x79, 0x6f, 0x64, 0x61, 0xae, 0x54, 0x3b, 0xc5, 0x08, 0xf4, 0x02, 0x85,
- 0x6f, 0x73, 0xe5, 0xda, 0xd5, 0xe1, 0xd7, 0x56, 0xf2, 0x03, 0x04, 0xa0,
- 0x79, 0xf5, 0xd7, 0x4e, 0x75, 0x72, 0x67, 0x69, 0x65, 0x6e, 0x73, 0x2d,
- 0x64, 0x65, 0x6e, 0x74, 0x69, 0x73, 0x74, 0x65, 0xf3, 0x03, 0xd8, 0x9d,
- 0x2d, 0x65, 0x6e, 0x2d, 0x66, 0x72, 0x61, 0x6e, 0x63, 0xe5, 0xdb, 0xc4,
- 0x6f, 0x70, 0x72, 0x61, 0xe3, 0xc1, 0x77, 0xf0, 0x02, 0x83, 0xf3, 0xd4,
- 0x10, 0x70, 0xf5, 0xd7, 0xb7, 0xee, 0x03, 0xce, 0x57, 0x74, 0xe1, 0xda,
- 0x2b, 0x6d, 0x6b, 0x65, 0x6e, 0xf4, 0xda, 0x53, 0xec, 0x02, 0x85, 0x6c,
- 0x6f, 0xf5, 0xc4, 0xef, 0x64, 0x72, 0x65, 0xee, 0x03, 0xd9, 0x6c, 0xf3,
- 0x46, 0xa6, 0xd2, 0xc5, 0x6b, 0xf5, 0x06, 0x03, 0x0b, 0x04, 0x02, 0x88,
- 0xfa, 0xc4, 0xc5, 0xf3, 0x02, 0x84, 0x68, 0x69, 0xee, 0x94, 0x65, 0xe9,
- 0xd4, 0x97, 0x6d, 0xe1, 0xd8, 0xf2, 0xea, 0x8a, 0x68, 0xef, 0x03, 0xc4,
- 0xaf, 0xeb, 0xd7, 0xd4, 0x67, 0xef, 0xc4, 0xaa, 0x6a, 0x69, 0x77, 0x61,
- 0x2e, 0x6e, 0x61, 0x67, 0x61, 0xf3, 0xd4, 0x7e, 0x68, 0x61, 0x79, 0x61,
- 0x61, 0x6b, 0x61, 0x73, 0x61, 0x6b, 0xe1, 0xda, 0x13, 0x67, 0x61, 0x73,
- 0x61, 0xeb, 0xcf, 0x50, 0x65, 0xf4, 0xd3, 0xe8, 0xe3, 0x02, 0x86, 0x68,
- 0x69, 0x62, 0xf5, 0xd0, 0x99, 0xe1, 0x02, 0x84, 0x70, 0xf0, 0xcc, 0x89,
- 0xe7, 0xd1, 0x15, 0xe5, 0x04, 0x0b, 0x25, 0x88, 0x73, 0x61, 0x70, 0x65,
- 0x61, 0x6b, 0x65, 0x62, 0xe1, 0xd3, 0x40, 0xf2, 0x02, 0x97, 0xee, 0x02,
+ 0x6c, 0xe1, 0xe0, 0x26, 0x86, 0xf0, 0xd6, 0x04, 0x6f, 0x6e, 0x73, 0x65,
+ 0x72, 0x76, 0x61, 0xf4, 0xe0, 0x26, 0x77, 0x68, 0x65, 0xe6, 0xe0, 0x37,
+ 0x80, 0x65, 0x6c, 0x74, 0x69, 0xe3, 0xa6, 0xe1, 0x02, 0x86, 0x74, 0x65,
+ 0xf2, 0xe0, 0x41, 0x58, 0x6e, 0x64, 0x69, 0x64, 0x61, 0xf4, 0xe0, 0x35,
+ 0xea, 0xe2, 0x04, 0x0a, 0x08, 0x8a, 0x75, 0x6c, 0x6c, 0x73, 0x2d, 0x66,
+ 0xe1, 0xe0, 0x23, 0x2b, 0x72, 0x75, 0x69, 0x6e, 0xf3, 0xe0, 0x2b, 0x38,
+ 0x6f, 0x6f, 0x6b, 0x6b, 0x65, 0x65, 0xf0, 0xe0, 0x41, 0x2e, 0x6c, 0x6f,
+ 0x67, 0xe7, 0xe0, 0x41, 0x27, 0x61, 0x6e, 0x61, 0x72, 0x63, 0x68, 0x69,
+ 0xf3, 0xe0, 0x40, 0xe3, 0xf2, 0x05, 0x03, 0xe0, 0x4a, 0xe7, 0xf5, 0xca,
+ 0x61, 0x69, 0xf3, 0x60, 0x20, 0xd5, 0xe0, 0x27, 0x80, 0xf0, 0x03, 0x10,
+ 0x84, 0xe9, 0x02, 0x87, 0x72, 0x61, 0x6e, 0xe7, 0xe0, 0x49, 0x2d, 0x66,
+ 0x6f, 0xee, 0xe0, 0x49, 0x67, 0xb6, 0xe0, 0x20, 0xba, 0x2e, 0x6c, 0x69,
+ 0x6e, 0x6f, 0x64, 0xe5, 0xe0, 0x40, 0xa6, 0xef, 0x06, 0x07, 0x03, 0xe0,
+ 0x4a, 0xac, 0x70, 0x73, 0x79, 0xf3, 0xe0, 0x4a, 0x4b, 0xe2, 0xd9, 0xab,
+ 0xae, 0x60, 0x36, 0xfb, 0x51, 0x15, 0xc1, 0x60, 0xee, 0x19, 0x05, 0x06,
+ 0x07, 0x40, 0x5c, 0x3a, 0x0f, 0x40, 0x85, 0x40, 0x6c, 0x0f, 0x40, 0x46,
+ 0x1b, 0x46, 0x0b, 0x60, 0x34, 0x31, 0x4b, 0xd0, 0xc2, 0x66, 0x7a, 0xe1,
+ 0xe0, 0x2e, 0x83, 0x76, 0x65, 0xf3, 0xe0, 0x40, 0xfb, 0x75, 0x79, 0x61,
+ 0xed, 0xe0, 0x2e, 0xad, 0xf4, 0x07, 0x04, 0x03, 0x15, 0xe0, 0x4a, 0x54,
+ 0xf5, 0xe0, 0x48, 0x6d, 0xec, 0xdc, 0x5a, 0x65, 0x72, 0xee, 0x02, 0x88,
+ 0x65, 0xf4, 0x60, 0x25, 0xb0, 0xe0, 0x23, 0x76, 0x61, 0x74, 0x69, 0x6f,
+ 0xee, 0xe0, 0x24, 0xad, 0xae, 0x13, 0x06, 0x04, 0x06, 0x06, 0x08, 0x40,
+ 0x73, 0x60, 0x27, 0xf7, 0x45, 0x41, 0x56, 0x19, 0x43, 0xa7, 0xc2, 0x2e,
+ 0xf4, 0x60, 0x47, 0xff, 0xc0, 0x82, 0xf0, 0xe0, 0x48, 0x7b, 0xec, 0x60,
+ 0x47, 0xcf, 0xc0, 0xbf, 0xe9, 0x60, 0x47, 0xc6, 0xc1, 0x2f, 0xe3, 0x60,
+ 0x46, 0x6d, 0x41, 0xa3, 0xc0, 0x8e, 0xe1, 0x60, 0x47, 0xae, 0xc1, 0x1a,
+ 0xf3, 0x02, 0x8b, 0x75, 0xf2, 0x04, 0xe0, 0x48, 0x97, 0x61, 0x6e, 0xe3,
+ 0xda, 0x44, 0xf4, 0x02, 0x86, 0x69, 0x74, 0xf5, 0xe0, 0x43, 0x51, 0x61,
+ 0xee, 0x02, 0x89, 0x74, 0x63, 0x6c, 0x6f, 0x75, 0xe4, 0xe0, 0x2b, 0x70,
+ 0x63, 0xe5, 0x02, 0x8a, 0x73, 0x2e, 0x73, 0x70, 0x61, 0x77, 0xee, 0xe0,
+ 0x27, 0x39, 0x2e, 0x64, 0x61, 0x74, 0xe1, 0xe0, 0x24, 0x6e, 0xe7, 0x06,
+ 0x60, 0x47, 0xe4, 0xc1, 0xf7, 0x61, 0x74, 0x6c, 0x61, 0xee, 0xe0, 0x48,
+ 0xd4, 0xe6, 0x04, 0x40, 0x6a, 0x86, 0xef, 0x04, 0xe0, 0x49, 0xc9, 0xae,
+ 0x19, 0x06, 0x09, 0x04, 0x0a, 0x06, 0x06, 0x06, 0x06, 0x06, 0x08, 0x4b,
+ 0x75, 0x60, 0x2a, 0xc1, 0x11, 0x4f, 0x68, 0x41, 0x7c, 0x40, 0xb5, 0xc0,
+ 0x51, 0xf6, 0x60, 0x48, 0x32, 0xc0, 0x42, 0xf4, 0x60, 0x47, 0x35, 0x40,
+ 0xb5, 0x40, 0x65, 0x9f, 0xf3, 0xe0, 0x47, 0x53, 0xee, 0x60, 0x3e, 0xb2,
+ 0x48, 0xd0, 0x40, 0x72, 0xc0, 0x4e, 0xec, 0x60, 0x47, 0x28, 0xc0, 0xc2,
+ 0xeb, 0x60, 0x47, 0x72, 0xc0, 0x9d, 0xe8, 0x60, 0x47, 0xc7, 0xc0, 0xbe,
+ 0xe5, 0x60, 0x3d, 0x9c, 0xca, 0x25, 0xe3, 0x60, 0x3d, 0x32, 0xca, 0xbc,
+ 0xe2, 0x60, 0x3f, 0x1a, 0x48, 0x19, 0xc0, 0xb5, 0xe1, 0x60, 0x46, 0xf8,
+ 0x41, 0x73, 0xc0, 0xdf, 0x69, 0x6e, 0xe9, 0xe0, 0x37, 0x0b, 0xae, 0x07,
+ 0x04, 0x60, 0x36, 0x23, 0xd1, 0xd5, 0xed, 0xe0, 0x46, 0xef, 0xe3, 0xe0,
+ 0x48, 0x51, 0xe4, 0x05, 0x0a, 0x11, 0xc0, 0x40, 0x75, 0x73, 0x74, 0x72,
+ 0xe9, 0x60, 0x3d, 0x4c, 0xc9, 0x3e, 0xe9, 0x02, 0x86, 0x67, 0x65, 0xee,
+ 0xe0, 0x46, 0x7f, 0x65, 0x2e, 0x70, 0x6f, 0xf2, 0xe0, 0x34, 0xea, 0xe5,
+ 0x04, 0xe0, 0x3b, 0x60, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x74, 0xad,
+ 0x04, 0x09, 0x08, 0x92, 0x72, 0x65, 0x76, 0x69, 0x65, 0xf7, 0xe0, 0x45,
+ 0xc7, 0x70, 0x61, 0x6e, 0x65, 0xec, 0xe0, 0x45, 0xbf, 0x69, 0x6e, 0x71,
+ 0xf5, 0x02, 0x86, 0x69, 0x72, 0xf9, 0xe0, 0x45, 0xb3, 0x65, 0x73, 0xf4,
+ 0xe0, 0x45, 0xad, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0xef,
+ 0xe0, 0x27, 0x82, 0xae, 0x4e, 0x2b, 0x4c, 0xb1, 0x41, 0x5a, 0x60, 0x2b,
+ 0x5c, 0x9f, 0xe3, 0x05, 0x04, 0xe0, 0x48, 0xd8, 0xe8, 0xe0, 0x24, 0xf5,
+ 0x2e, 0xe8, 0xe0, 0x48, 0x9e, 0xe1, 0x08, 0x06, 0x09, 0x08, 0x07, 0x08,
+ 0x09, 0x86, 0x7a, 0x61, 0xf7, 0xe0, 0x2c, 0xf9, 0x77, 0x61, 0x73, 0x68,
+ 0x69, 0xf2, 0xe0, 0x43, 0x47, 0x74, 0x73, 0x75, 0x6b, 0xe9, 0xe0, 0x31,
+ 0xa3, 0x73, 0x68, 0x69, 0xeb, 0xe0, 0x2d, 0x3d, 0x6d, 0x69, 0xae, 0x60,
+ 0x3d, 0x86, 0xc0, 0x7c, 0xe7, 0x04, 0xe0, 0x45, 0x57, 0x61, 0xf7, 0xc8,
+ 0x5f, 0x62, 0x65, 0xae, 0xe0, 0x3d, 0x79, 0xae, 0x60, 0x3e, 0x2b, 0x42,
+ 0xd8, 0xc4, 0x7e, 0xae, 0x0a, 0x06, 0x58, 0xc2, 0x45, 0x9e, 0x48, 0x89,
+ 0xdb, 0x35, 0xf5, 0x60, 0x46, 0x18, 0xc0, 0xc2, 0xee, 0x60, 0x3f, 0x0a,
+ 0x47, 0x58, 0x40, 0x72, 0xc1, 0x85, 0xad, 0x05, 0x04, 0x09, 0x0b, 0x90,
+ 0x76, 0x70, 0xee, 0x8d, 0x74, 0x68, 0x65, 0x2d, 0x62, 0x61, 0xee, 0xd4,
+ 0x14, 0x64, 0x73, 0x6c, 0xae, 0x60, 0x45, 0x8c, 0x42, 0x2f, 0xc0, 0x7d,
+ 0xe2, 0x04, 0x06, 0xdf, 0x55, 0x75, 0x74, 0xf4, 0xe0, 0x25, 0x15, 0x72,
+ 0xe2, 0xe0, 0x25, 0x12, 0x61, 0x64, 0x64, 0xf2, 0xde, 0x30, 0xed, 0x0c,
+ 0x14, 0x0c, 0x04, 0x04, 0x60, 0x31, 0x7d, 0x54, 0x89, 0xc2, 0x03, 0x70,
+ 0x65, 0xf2, 0x04, 0xe0, 0x41, 0x9a, 0x74, 0x72, 0x69, 0xf8, 0x04, 0xe0,
+ 0x48, 0x1a, 0x63, 0xe4, 0xe0, 0x20, 0x34, 0x6d, 0xef, 0x04, 0xe0, 0x48,
+ 0x17, 0x62, 0x69, 0x6c, 0xe9, 0xcf, 0x90, 0x69, 0xfa, 0xd1, 0x0f, 0xe4,
+ 0xe0, 0x3d, 0xb3, 0xe1, 0x04, 0x03, 0x05, 0x86, 0xf2, 0xd1, 0x12, 0x6d,
+ 0xe1, 0xe0, 0x46, 0x41, 0x6b, 0x61, 0xee, 0xe0, 0x2c, 0x28, 0x62, 0x61,
+ 0xf2, 0xc3, 0x52, 0xec, 0x09, 0x0b, 0x07, 0x06, 0x60, 0x35, 0x4c, 0xd2,
+ 0x83, 0x6f, 0x76, 0x65, 0x63, 0x6f, 0x6c, 0x6c, 0xe5, 0xe0, 0x37, 0xab,
+ 0x69, 0x61, 0x64, 0x62, 0xef, 0xc1, 0x49, 0xae, 0x60, 0x41, 0x76, 0xc1,
+ 0x5a, 0x2d, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x61, 0xec, 0xe0, 0x43, 0xc1,
+ 0xeb, 0x05, 0x07, 0x03, 0x07, 0x8e, 0x75, 0x73, 0x61, 0xeb, 0xe0, 0x2c,
+ 0x4c, 0x6f, 0xed, 0xa8, 0x69, 0xae, 0x60, 0x2c, 0x5a, 0xda, 0xff, 0x65,
+ 0x64, 0x61, 0xae, 0x5d, 0x2e, 0x60, 0x21, 0xa3, 0x45, 0xc5, 0x41, 0x3f,
+ 0xa0, 0xe1, 0x06, 0x03, 0x05, 0xe0, 0x45, 0xfc, 0xf7, 0xc8, 0x97, 0x74,
+ 0xe1, 0xe0, 0x42, 0xc4, 0x72, 0x75, 0x67, 0xe1, 0xe0, 0x3f, 0x31, 0xe9,
+ 0x05, 0x0b, 0x05, 0x06, 0x85, 0x7a, 0xf5, 0x02, 0x84, 0xee, 0xe0, 0x2c,
+ 0x10, 0xeb, 0xc8, 0x2e, 0x79, 0xe1, 0xe0, 0x2c, 0x07, 0x74, 0x61, 0xf4,
+ 0xe0, 0x42, 0x03, 0x6a, 0xe9, 0xe0, 0x2b, 0xfc, 0xe4, 0x45, 0x28, 0xe0,
+ 0x26, 0xd1, 0x68, 0x65, 0xf9, 0xcd, 0xc8, 0x67, 0x6c, 0x65, 0x73, 0x69,
+ 0x61, 0xf3, 0x02, 0x81, 0x2d, 0x63, 0x61, 0x72, 0x62, 0xef, 0xe0, 0x2f,
+ 0x06, 0xe6, 0x60, 0x2c, 0x42, 0xd8, 0xb6, 0xe5, 0x06, 0x60, 0x42, 0x60,
+ 0xc4, 0xde, 0xae, 0x60, 0x34, 0x0e, 0xcc, 0xd1, 0xe4, 0x09, 0x06, 0x06,
+ 0x04, 0x60, 0x38, 0xe8, 0xce, 0x36, 0x76, 0xae, 0x4b, 0x1a, 0xdd, 0xbd,
+ 0x72, 0x65, 0xf4, 0xe0, 0x3f, 0x88, 0x66, 0xae, 0xda, 0x6f, 0xae, 0x0b,
+ 0x07, 0x06, 0x04, 0x60, 0x41, 0xfd, 0x41, 0xeb, 0xc0, 0x7e, 0x72, 0x65,
+ 0x70, 0xec, 0xe0, 0x2e, 0x0b, 0xec, 0x60, 0x43, 0x4e, 0xc1, 0x85, 0xe9,
+ 0xe0, 0x45, 0xab, 0xe6, 0x02, 0x8a, 0x6f, 0x72, 0x67, 0x65, 0x72, 0x6f,
+ 0xe3, 0xe0, 0x3d, 0x89, 0x69, 0x72, 0x65, 0x77, 0x61, 0x6c, 0xec, 0xd4,
+ 0x84, 0xe3, 0x09, 0x0a, 0x41, 0x33, 0x48, 0x7a, 0xe0, 0x3b, 0xae, 0xf5,
+ 0x04, 0xe0, 0x46, 0xdc, 0x72, 0xf5, 0xe0, 0x2b, 0x39, 0x68, 0xe9, 0x04,
+ 0x17, 0x19, 0x85, 0x6e, 0xef, 0x03, 0x04, 0x8a, 0x73, 0xe5, 0xc6, 0xee,
+ 0x6d, 0x69, 0x79, 0x61, 0xae, 0x60, 0x41, 0x7b, 0xc3, 0x6b, 0x68, 0xe5,
+ 0xd0, 0x71, 0x6b, 0xe1, 0x02, 0x91, 0x77, 0xe1, 0x02, 0x87, 0x6d, 0x69,
+ 0x73, 0x61, 0xf4, 0xd0, 0x32, 0xae, 0x60, 0x41, 0xd2, 0xc2, 0xfb, 0xe9,
+ 0xe0, 0x3b, 0x1f, 0x68, 0x61, 0xf2, 0xc6, 0xbd, 0x62, 0xe1, 0xe0, 0x41,
+ 0x25, 0xe2, 0x08, 0x06, 0x04, 0x40, 0x92, 0xe0, 0x43, 0xa0, 0x78, 0x6f,
+ 0xf3, 0xe0, 0x46, 0x40, 0x69, 0xe7, 0xc4, 0x36, 0x61, 0x72, 0xe1, 0x04,
+ 0xe0, 0x40, 0xbd, 0x6b, 0x69, 0xae, 0x60, 0x3e, 0xe9, 0x45, 0xbd, 0xa9,
+ 0xe1, 0x04, 0xe0, 0x40, 0xca, 0x6d, 0x61, 0x6c, 0x6c, 0x61, 0xed, 0xd1,
+ 0x1f, 0x32, 0x33, 0xb4, 0xe0, 0x30, 0x5f, 0xae, 0x08, 0x60, 0x30, 0xd7,
+ 0x44, 0x1b, 0xd1, 0x64, 0xf0, 0xe0, 0x43, 0xc7, 0xe8, 0x18, 0x2e, 0x05,
+ 0x1d, 0x03, 0x35, 0x0c, 0x0e, 0x11, 0x41, 0xb2, 0x06, 0x06, 0x17, 0x12,
+ 0x10, 0x41, 0xe0, 0x40, 0xb7, 0x08, 0x14, 0xd6, 0xd8, 0x1f, 0xc3, 0x07,
+ 0x07, 0x04, 0x0a, 0xe0, 0x44, 0x87, 0xf8, 0x03, 0xc0, 0xba, 0xee, 0xc1,
+ 0x84, 0x66, 0xe7, 0xc7, 0x02, 0x64, 0x6b, 0x6b, 0x69, 0x6e, 0x65, 0xee,
+ 0xe0, 0x45, 0xc6, 0xe1, 0x03, 0x03, 0x86, 0xf0, 0xc5, 0xf1, 0x6d, 0x6d,
+ 0x1f, 0xc3, 0xc6, 0x4f, 0xe2, 0xc7, 0x28, 0x7a, 0xe3, 0xe0, 0x45, 0x03,
+ 0xf9, 0x06, 0x0d, 0x05, 0xe0, 0x41, 0x19, 0xf5, 0x02, 0x85, 0x6e, 0xe4,
+ 0xe0, 0x2a, 0x67, 0x67, 0xe1, 0xe0, 0x37, 0xc7, 0x6c, 0x6c, 0xe5, 0xd3,
+ 0x18, 0xe1, 0xe0, 0x44, 0x2f, 0xf6, 0xd3, 0x26, 0xf5, 0x08, 0x06, 0x09,
+ 0x11, 0x05, 0xe0, 0x45, 0xba, 0xf2, 0x60, 0x2e, 0x5e, 0xd0, 0x64, 0x6e,
+ 0xe7, 0x04, 0xe0, 0x3d, 0x1f, 0xf9, 0xdf, 0x3b, 0x69, 0x73, 0x73, 0x69,
+ 0x65, 0x72, 0x2d, 0x6a, 0x75, 0x73, 0x74, 0x69, 0x63, 0xe5, 0xe0, 0x37,
+ 0xe4, 0x67, 0xe8, 0xe0, 0x39, 0xc6, 0xae, 0x60, 0x3f, 0x5b, 0x46, 0x3b,
+ 0x9c, 0xf4, 0x04, 0xe0, 0x45, 0xae, 0x74, 0x70, 0x62, 0xe9, 0xe0, 0x25,
+ 0xd5, 0xf3, 0x02, 0x84, 0xe2, 0xe0, 0x39, 0xc0, 0xae, 0x5f, 0x7a, 0x48,
+ 0x7a, 0xc6, 0xbb, 0xf2, 0x06, 0x60, 0x2b, 0x5b, 0xda, 0x37, 0x61, 0x2e,
+ 0x68, 0x65, 0x61, 0x6c, 0xf4, 0xe0, 0x44, 0xde, 0xef, 0x13, 0x0d, 0x04,
+ 0x27, 0x40, 0x46, 0x1f, 0x12, 0x28, 0x40, 0x61, 0x23, 0x19, 0x09, 0x05,
+ 0x17, 0xe0, 0x41, 0x6b, 0xf9, 0x04, 0xe0, 0x2f, 0x5c, 0x6c, 0x61, 0x6e,
+ 0x64, 0xe5, 0xe0, 0x3d, 0xcd, 0xf5, 0xe0, 0x34, 0x00, 0xf4, 0x05, 0x03,
+ 0xe0, 0x45, 0x5a, 0xed, 0xd8, 0xaa, 0x65, 0xec, 0x05, 0x0c, 0xe0, 0x42,
+ 0xde, 0x77, 0x69, 0x74, 0x68, 0x66, 0x6c, 0x69, 0x67, 0xe8, 0xe0, 0x3b,
+ 0x3a, 0xae, 0x06, 0x60, 0x39, 0x6e, 0xca, 0xd1, 0xf4, 0xe0, 0x42, 0xcc,
+ 0xf3, 0x02, 0xba, 0xf4, 0x06, 0x07, 0x28, 0xe0, 0x45, 0x03, 0x79, 0x68,
+ 0x6f, 0x73, 0xf4, 0xde, 0xf7, 0x69, 0x6e, 0xe7, 0x05, 0x15, 0xe0, 0x45,
+ 0x0e, 0xae, 0x02, 0x86, 0x6f, 0x76, 0xe8, 0xe0, 0x22, 0x92, 0x6d, 0x79,
+ 0x6a, 0x69, 0x6e, 0x6f, 0x2e, 0x72, 0xf5, 0xe0, 0x44, 0xff, 0x2d, 0x63,
+ 0x6c, 0x75, 0x73, 0x74, 0x65, 0xf2, 0xe0, 0x28, 0x79, 0x65, 0xe4, 0xd7,
+ 0x53, 0xf0, 0x04, 0xe0, 0x41, 0xab, 0x69, 0xf4, 0xdf, 0x4e, 0xf2, 0x06,
+ 0x04, 0x0f, 0xe0, 0x33, 0x76, 0xf4, 0xe0, 0x35, 0x72, 0xef, 0x02, 0x86,
+ 0x6e, 0x6f, 0xe2, 0xe0, 0x29, 0x14, 0x6b, 0x61, 0xee, 0xe0, 0x32, 0x65,
+ 0x6e, 0xe9, 0xe0, 0x3a, 0x44, 0xf0, 0x02, 0x88, 0x74, 0x6f, 0xae, 0x60,
+ 0x2e, 0xcd, 0xd3, 0x35, 0x6c, 0x69, 0x78, 0xae, 0xe0, 0x33, 0xf1, 0xee,
+ 0x09, 0x0d, 0x05, 0x07, 0x60, 0x39, 0x31, 0xc6, 0xb8, 0xea, 0x02, 0x83,
+ 0xf9, 0xce, 0x14, 0x6f, 0xae, 0x60, 0x3a, 0x4a, 0xc4, 0x55, 0x67, 0xef,
+ 0xe0, 0x39, 0x57, 0x65, 0x66, 0x6f, 0xf3, 0xe0, 0x40, 0x52, 0x61, 0xe9,
+ 0xe0, 0x3f, 0xd1, 0x6d, 0xe5, 0x0c, 0x04, 0x22, 0x0f, 0x06, 0x05, 0x09,
+ 0x07, 0x52, 0xa8, 0xc8, 0x76, 0x75, 0x6e, 0xe9, 0xa9, 0xf3, 0x05, 0x06,
+ 0xe0, 0x44, 0x7f, 0x6b, 0x6c, 0xe5, 0xe0, 0x32, 0xdf, 0xe5, 0x02, 0x84,
+ 0xee, 0xe0, 0x33, 0x15, 0x63, 0x75, 0x72, 0x69, 0x74, 0xf9, 0x02, 0x83,
+ 0xf0, 0xde, 0xee, 0x6d, 0xe1, 0xde, 0xea, 0x6c, 0x69, 0xee, 0x02, 0x85,
+ 0x75, 0xf8, 0xe0, 0x30, 0xa4, 0x6b, 0xae, 0xe0, 0x26, 0xb3, 0x67, 0x6f,
+ 0xef, 0xe0, 0x2b, 0x72, 0x66, 0x74, 0xf0, 0xd6, 0x92, 0xe4, 0x03, 0xdb,
+ 0x92, 0x65, 0xf0, 0xe0, 0x34, 0x4b, 0x62, 0x75, 0x69, 0xec, 0xe0, 0x3f,
+ 0x3a, 0xae, 0xc9, 0xa5, 0xec, 0x0b, 0x0b, 0x05, 0x60, 0x30, 0x8c, 0x4a,
+ 0xe1, 0x47, 0x1d, 0x81, 0xf4, 0x02, 0x85, 0x1f, 0x43, 0xe5, 0xc6, 0x05,
+ 0xe1, 0xc6, 0x02, 0x6d, 0xe5, 0xe0, 0x34, 0xad, 0x64, 0x69, 0x6e, 0xe7,
+ 0xe0, 0x41, 0xb3, 0xeb, 0x02, 0x90, 0xf5, 0x02, 0x88, 0x74, 0x6f, 0xae,
+ 0x60, 0x27, 0xca, 0xda, 0x92, 0x72, 0xf9, 0xe0, 0x3f, 0x54, 0xeb, 0x60,
+ 0x2d, 0xc7, 0xd4, 0x8e, 0xe6, 0x04, 0xe0, 0x42, 0x66, 0xf5, 0xe0, 0x41,
+ 0xe4, 0x63, 0xeb, 0xe0, 0x37, 0x7b, 0xe2, 0x03, 0x06, 0x84, 0x1f, 0x43,
+ 0xf8, 0xe0, 0x3c, 0xd1, 0xef, 0xe0, 0x3c, 0xcd, 0x62, 0x79, 0x2d, 0x73,
+ 0x69, 0x74, 0xe5, 0xdc, 0x01, 0x61, 0xe2, 0xe0, 0x34, 0xa1, 0xee, 0x60,
+ 0x30, 0x66, 0xd3, 0x6f, 0xed, 0x60, 0x42, 0x3a, 0xc1, 0x95, 0xec, 0x04,
+ 0xe0, 0x3f, 0x19, 0xf8, 0x02, 0x84, 0xb3, 0xe0, 0x24, 0x0a, 0xae, 0x04,
+ 0xe0, 0x24, 0x03, 0x6c, 0x69, 0xf6, 0xe0, 0x43, 0x51, 0xeb, 0x06, 0x60,
+ 0x41, 0xee, 0xc1, 0xbe, 0xae, 0x04, 0xe0, 0x40, 0xd8, 0xe3, 0x60, 0x42,
+ 0x6c, 0xc1, 0x34, 0xea, 0x02, 0x87, 0x65, 0x6c, 0x6d, 0xe5, 0xe0, 0x36,
+ 0xe3, 0x61, 0x72, 0xf4, 0xe0, 0x3c, 0x78, 0xe9, 0x14, 0x06, 0x24, 0x0d,
+ 0x40, 0x4f, 0x07, 0x05, 0x14, 0x10, 0x1a, 0x05, 0x04, 0x40, 0xd1, 0x11,
+ 0x0a, 0xe0, 0x3d, 0xfb, 0x7a, 0x65, 0xee, 0xe0, 0x38, 0xd9, 0xf4, 0x04,
+ 0xe0, 0x36, 0xbf, 0xe1, 0x04, 0xe0, 0x31, 0x8f, 0x63, 0x68, 0xe9, 0x07,
+ 0x09, 0x60, 0x3b, 0xc7, 0xc7, 0x92, 0xef, 0x02, 0x82, 0xf4, 0x88, 0x6d,
+ 0x69, 0xf9, 0x84, 0x6e, 0x61, 0x6b, 0xe1, 0xe0, 0x3b, 0xc3, 0x73, 0xe1,
+ 0x02, 0x85, 0x79, 0x61, 0xed, 0xc3, 0xff, 0x6d, 0xe9, 0xcc, 0x8a, 0xf2,
+ 0x02, 0x9f, 0xef, 0x08, 0x09, 0x08, 0x60, 0x37, 0x8c, 0xc0, 0xf0, 0xf3,
+ 0x04, 0xe0, 0x3d, 0xce, 0x61, 0xeb, 0xc2, 0xd8, 0x6e, 0x6f, 0xae, 0x4c,
+ 0xe3, 0xe0, 0x30, 0xdf, 0x6b, 0x61, 0xf7, 0xc3, 0xd9, 0xe1, 0x07, 0x04,
+ 0x0b, 0x03, 0x04, 0x06, 0x86, 0xf9, 0xe0, 0x27, 0xac, 0xf4, 0x04, 0xe0,
+ 0x37, 0xd0, 0x73, 0x75, 0xeb, 0xe0, 0x3e, 0x4b, 0xf2, 0xc9, 0x74, 0x6e,
+ 0xe1, 0xc2, 0xad, 0x6b, 0x61, 0xf4, 0xe0, 0x27, 0xbb, 0x69, 0x7a, 0x75,
+ 0xed, 0xcc, 0xaf, 0xe4, 0xc7, 0x5f, 0xf0, 0x03, 0xcf, 0xdf, 0xe8, 0xda,
+ 0x31, 0x6f, 0xeb, 0xe0, 0x3b, 0x93, 0x6e, 0xef, 0x03, 0x04, 0x83, 0x68,
+ 0xe1, 0xc3, 0x11, 0xe4, 0xc0, 0xc9, 0x2e, 0x74, 0xef, 0x60, 0x26, 0xf8,
+ 0xd8, 0x9f, 0xed, 0x03, 0xcb, 0x97, 0xe5, 0x04, 0xe0, 0x34, 0xe1, 0x73,
+ 0x68, 0x69, 0xed, 0xe0, 0x2b, 0xec, 0xeb, 0x03, 0x06, 0x85, 0x6f, 0x6e,
+ 0xe5, 0xe0, 0x3d, 0x6d, 0x69, 0xed, 0xe0, 0x3d, 0x03, 0xe1, 0x02, 0x83,
+ 0xf7, 0xc3, 0x1f, 0x72, 0xe9, 0xe0, 0x40, 0x99, 0x6a, 0xe9, 0xe0, 0x30,
+ 0xcd, 0xe8, 0xe0, 0x29, 0xf3, 0x67, 0x61, 0x73, 0x68, 0xe9, 0x0d, 0x21,
+ 0x05, 0x08, 0x17, 0x0a, 0x0c, 0x18, 0x19, 0x0c, 0x08, 0x07, 0x8a, 0xf9,
+ 0x02, 0x93, 0xef, 0x02, 0x88, 0x73, 0x68, 0x69, 0x6e, 0xef, 0xe0, 0x3a,
+ 0x2b, 0x64, 0x6f, 0x67, 0x61, 0xf7, 0xe0, 0x27, 0x37, 0x61, 0x6d, 0xe1,
+ 0x04, 0xe0, 0x34, 0x3f, 0xf4, 0xe0, 0x3c, 0x6e, 0x75, 0xf2, 0xe0, 0x26,
+ 0xa0, 0x74, 0x73, 0x75, 0x6e, 0xef, 0xe0, 0x3c, 0x64, 0xf3, 0x02, 0x8b,
+ 0x75, 0x6d, 0x69, 0x79, 0x6f, 0x73, 0x68, 0xe9, 0xe0, 0x40, 0x83, 0x68,
+ 0x69, 0x72, 0x61, 0x6b, 0x61, 0xf7, 0xd4, 0xa4, 0xef, 0x04, 0xe0, 0x26,
+ 0xfd, 0x6d, 0xe9, 0xe0, 0x3c, 0xf3, 0xee, 0x02, 0x83, 0xe5, 0xcb, 0x09,
+ 0x61, 0x72, 0x75, 0xf3, 0xc7, 0x2f, 0xed, 0x02, 0x88, 0x75, 0x72, 0x61,
+ 0x79, 0xe1, 0xe0, 0x3c, 0x22, 0x61, 0x74, 0x73, 0xf5, 0x03, 0xc1, 0x9a,
+ 0x73, 0x68, 0x69, 0xed, 0xca, 0xa2, 0xeb, 0x02, 0x88, 0x75, 0x72, 0x75,
+ 0x6d, 0xe5, 0xe0, 0x3e, 0xcf, 0xe1, 0x04, 0xe0, 0x36, 0xd8, 0xe7, 0x04,
+ 0xe0, 0x33, 0xcb, 0xf5, 0xe0, 0x40, 0x25, 0x69, 0x7a, 0xf5, 0x04, 0xe0,
+ 0x37, 0x9c, 0x6d, 0xef, 0xe0, 0x3c, 0x46, 0x68, 0x69, 0x72, 0x6f, 0x73,
+ 0xe8, 0xd3, 0x0d, 0x63, 0x68, 0x69, 0xe3, 0xe0, 0x26, 0xb6, 0x61, 0x67,
+ 0x61, 0x74, 0x73, 0x75, 0xed, 0xe0, 0x39, 0x16, 0xae, 0x04, 0xe0, 0x3d,
+ 0x44, 0x66, 0x75, 0x6b, 0xf5, 0x60, 0x37, 0x7b, 0xc4, 0xf5, 0x64, 0xe1,
+ 0x04, 0xe0, 0x38, 0xf3, 0x6b, 0x61, 0xae, 0x60, 0x37, 0x22, 0x3e, 0x44,
+ 0x68, 0xc4, 0x4d, 0xe3, 0x04, 0xe0, 0x28, 0xa6, 0x68, 0x69, 0xf3, 0xc6,
+ 0xc2, 0xae, 0x60, 0x3c, 0xb2, 0xc0, 0x5c, 0xe5, 0x0c, 0x06, 0x40, 0x4d,
+ 0x08, 0x0d, 0x0b, 0x08, 0x07, 0xe0, 0x2d, 0xb3, 0x74, 0x65, 0xed, 0xe0,
+ 0x27, 0x4c, 0xf2, 0x09, 0x0e, 0x21, 0x04, 0x4e, 0x8a, 0xe0, 0x31, 0xdc,
+ 0x1f, 0x43, 0x78, 0x79, 0xae, 0x04, 0xe0, 0x2c, 0x7e, 0x6d, 0x1f, 0x43,
+ 0xf8, 0x8c, 0xef, 0x02, 0x93, 0x79, 0xae, 0x04, 0xe0, 0x2c, 0x70, 0x6d,
+ 0x6f, 0x72, 0x65, 0x2d, 0x6f, 0x67, 0x2d, 0x72, 0x6f, 0xed, 0xc9, 0x8f,
+ 0x6b, 0xf5, 0x04, 0xe0, 0x40, 0x7d, 0x73, 0xf3, 0xe0, 0x3a, 0x91, 0xed,
+ 0xe0, 0x35, 0x6d, 0xe5, 0x04, 0xe0, 0x41, 0x5c, 0x2d, 0x66, 0x6f, 0x72,
+ 0x2d, 0x6d, 0x6f, 0xf2, 0xe0, 0x31, 0x21, 0x70, 0x66, 0x6f, 0x72, 0xe7,
+ 0xe0, 0x2c, 0x10, 0xed, 0x02, 0x83, 0xf3, 0xd8, 0xf2, 0x6e, 0xe5, 0x60,
+ 0x3c, 0xee, 0xc2, 0xbe, 0xec, 0x04, 0xe0, 0x3f, 0x9a, 0x73, 0x69, 0xee,
+ 0xe0, 0x2e, 0x23, 0x6b, 0x69, 0x6e, 0x61, 0xee, 0xe0, 0x3b, 0xe3, 0x67,
+ 0x75, 0x72, 0xe9, 0xe0, 0x38, 0xca, 0xe1, 0x02, 0x84, 0xf6, 0xe0, 0x38,
+ 0x6b, 0x6c, 0x74, 0xe8, 0x06, 0x05, 0x06, 0xe0, 0x41, 0x07, 0x63, 0xe1,
+ 0xe0, 0x3e, 0x49, 0xae, 0x60, 0x3a, 0x5c, 0xc4, 0x15, 0x2d, 0x63, 0x61,
+ 0x72, 0x65, 0x72, 0x65, 0x66, 0x6f, 0xf2, 0xe0, 0x37, 0x44, 0x64, 0x66,
+ 0xe3, 0x5f, 0xf8, 0xe0, 0x20, 0xff, 0xe2, 0x04, 0xe0, 0x3f, 0x62, 0x2e,
+ 0xe3, 0x04, 0xe0, 0x3f, 0xad, 0x6c, 0x64, 0x6d, 0x61, 0x69, 0xec, 0xe0,
+ 0x40, 0x57, 0xe1, 0x16, 0x04, 0x10, 0x0e, 0x24, 0x3b, 0x17, 0x0d, 0x40,
+ 0x49, 0x40, 0x54, 0x14, 0x29, 0x15, 0x11, 0x08, 0x0c, 0x21, 0xe0, 0x3a,
+ 0x41, 0xfa, 0xe0, 0x24, 0xff, 0x79, 0xe1, 0x02, 0x87, 0x73, 0x68, 0x69,
+ 0xed, 0xe0, 0x3a, 0xfa, 0x6b, 0x61, 0xf7, 0xc9, 0xf5, 0xf5, 0x04, 0xe0,
+ 0x3e, 0x45, 0xe7, 0x04, 0xe0, 0x37, 0xf9, 0xe5, 0xe0, 0x2a, 0x6a, 0xf4,
+ 0x06, 0x07, 0x0a, 0xe0, 0x31, 0x55, 0x74, 0x66, 0x6a, 0x65, 0xec, 0xcc,
+ 0xf9, 0x73, 0x75, 0x6b, 0x61, 0x69, 0x63, 0xe8, 0xe0, 0x35, 0x3a, 0xef,
+ 0x02, 0x85, 0x79, 0x61, 0xed, 0xc9, 0xab, 0x67, 0xe1, 0xc9, 0xa6, 0xf3,
+ 0x05, 0x10, 0x1b, 0xc7, 0xe7, 0xf5, 0x02, 0x8a, 0x72, 0xe1, 0x04, 0xe0,
+ 0x3e, 0xfc, 0xad, 0xe0, 0x31, 0x61, 0xe4, 0xc9, 0x91, 0xe8, 0x02, 0x91,
+ 0xe9, 0x02, 0x88, 0xed, 0x03, 0xd2, 0xb7, 0x6f, 0xf4, 0xc5, 0x75, 0x6b,
+ 0x61, 0x6d, 0xe9, 0xc5, 0x25, 0x62, 0x61, 0x6e, 0xe7, 0xe0, 0x2f, 0x12,
+ 0x61, 0xed, 0x04, 0xe0, 0x29, 0x6d, 0xe9, 0xe0, 0x24, 0xf0, 0xf2, 0x05,
+ 0x06, 0x05, 0xcd, 0x5c, 0x69, 0x6d, 0xe1, 0xe0, 0x3b, 0x64, 0x65, 0xe9,
+ 0xe0, 0x3c, 0x16, 0xe1, 0x60, 0x34, 0x88, 0xc8, 0x98, 0xf0, 0x02, 0x85,
+ 0x70, 0x6f, 0xf5, 0xdc, 0x24, 0x6d, 0xe9, 0xe0, 0x34, 0x7d, 0xee, 0x06,
+ 0x04, 0x03, 0x09, 0x0d, 0x8e, 0xf9, 0xe0, 0x24, 0xe6, 0xef, 0xd8, 0x1e,
+ 0xee, 0x03, 0xc9, 0x7f, 0x61, 0xee, 0xe0, 0x3e, 0x39, 0xe7, 0x02, 0x85,
+ 0x6f, 0xf5, 0xe0, 0x3e, 0x48, 0x67, 0x6c, 0xe9, 0xc5, 0xd4, 0xe4, 0x04,
+ 0xe0, 0x24, 0x2b, 0x63, 0x72, 0x61, 0x66, 0x74, 0xe5, 0xe0, 0x3e, 0xf7,
+ 0xe1, 0x04, 0xe0, 0x34, 0xa8, 0xed, 0x05, 0x08, 0xe0, 0x37, 0x31, 0x69,
+ 0x67, 0x61, 0x77, 0xe1, 0xe0, 0x3e, 0x02, 0x61, 0xeb, 0xc9, 0x8f, 0xed,
+ 0x05, 0x05, 0x14, 0x05, 0xa5, 0x75, 0xf2, 0xe0, 0x39, 0xc6, 0xed, 0x02,
+ 0x88, 0x65, 0x72, 0x66, 0x65, 0xf3, 0xe0, 0x38, 0x29, 0x61, 0x72, 0x66,
+ 0x65, 0x61, 0xf3, 0xe0, 0x39, 0x94, 0x62, 0xf5, 0xe0, 0x2b, 0x05, 0xe1,
+ 0x04, 0x0d, 0x06, 0x88, 0xf4, 0x02, 0x85, 0x6f, 0xee, 0xe0, 0x3a, 0xf2,
+ 0x61, 0xed, 0xe0, 0x34, 0xf4, 0xf2, 0x60, 0x33, 0xf2, 0xca, 0x1b, 0x6d,
+ 0x61, 0x74, 0x73, 0xf5, 0xe0, 0x35, 0x36, 0x64, 0xe1, 0xe0, 0x39, 0xdd,
+ 0x2d, 0x72, 0x61, 0x64, 0x69, 0x6f, 0x2d, 0xef, 0xe0, 0x33, 0x5f, 0xec,
+ 0x04, 0x0b, 0xc7, 0x3d, 0xe6, 0x03, 0xca, 0x96, 0x6d, 0x6f, 0x6f, 0xee,
+ 0xe0, 0x3e, 0x7d, 0xe4, 0xe0, 0x2f, 0xf8, 0xeb, 0x03, 0x12, 0x8d, 0xf5,
+ 0x03, 0x06, 0x84, 0x73, 0x61, 0xee, 0xe0, 0x37, 0x35, 0xe9, 0xe0, 0x37,
+ 0x31, 0xe2, 0xe0, 0x23, 0xf0, 0xef, 0x02, 0x84, 0xee, 0xe0, 0x31, 0x15,
+ 0x64, 0x61, 0xf4, 0xe0, 0x23, 0x80, 0x61, 0x74, 0xe1, 0xe0, 0x28, 0x38,
+ 0xe9, 0x06, 0x05, 0x04, 0xe0, 0x3d, 0xdf, 0x70, 0xe8, 0xe0, 0x2c, 0x8b,
+ 0xe4, 0xe0, 0x2c, 0x86, 0x62, 0x61, 0xf2, 0xc8, 0xca, 0xe7, 0x05, 0x06,
+ 0xe0, 0x33, 0xa1, 0xe9, 0x60, 0x36, 0x7d, 0xc6, 0x99, 0x65, 0x62, 0xef,
+ 0xcc, 0x4b, 0x65, 0x62, 0x61, 0x72, 0xf5, 0xe0, 0x3a, 0x85, 0xe4, 0x02,
+ 0x83, 0xf3, 0xc5, 0x99, 0x61, 0x6e, 0xef, 0xe0, 0x3a, 0x4e, 0xe3, 0x02,
+ 0x9a, 0x68, 0xe9, 0x04, 0x08, 0x05, 0x83, 0x72, 0x6f, 0x67, 0x61, 0x74,
+ 0xe1, 0xda, 0xfa, 0x6f, 0xea, 0xe0, 0x3b, 0xb3, 0xee, 0xc3, 0xc0, 0xea,
+ 0xe0, 0x38, 0xef, 0xe3, 0xe0, 0x2f, 0x3f, 0xe2, 0x05, 0x04, 0xe0, 0x33,
+ 0x45, 0xed, 0xe0, 0x33, 0x3d, 0x69, 0x6b, 0xe9, 0xe0, 0x3d, 0x09, 0xe7,
+ 0x27, 0x30, 0x04, 0x1b, 0x04, 0x0b, 0x0b, 0x40, 0x59, 0x40, 0x6f, 0x40,
+ 0xae, 0x42, 0x42, 0x0d, 0x15, 0x40, 0x56, 0x1d, 0x40, 0xa6, 0x08, 0x09,
+ 0x40, 0x74, 0x1c, 0x04, 0x0a, 0x40, 0x85, 0x05, 0x57, 0xd8, 0x55, 0x5f,
+ 0x49, 0x2b, 0xa1, 0x1f, 0xc3, 0x02, 0x9a, 0x7c, 0x6e, 0x73, 0x74, 0x69,
+ 0xe7, 0x02, 0x88, 0x6c, 0x69, 0x65, 0x66, 0x65, 0xf2, 0xd5, 0xb3, 0x62,
+ 0x65, 0x73, 0x74, 0x65, 0x6c, 0x6c, 0xe5, 0xd5, 0xa9, 0xe1, 0x04, 0x06,
+ 0xc6, 0x63, 0x1f, 0x45, 0x4b, 0xe7, 0xc6, 0x16, 0x6c, 0x73, 0x1f, 0xc3,
+ 0xe0, 0x38, 0x60, 0xfa, 0xe0, 0x2b, 0x15, 0xf9, 0x05, 0x07, 0xe0, 0x3e,
+ 0x74, 0x6f, 0x6b, 0x75, 0xf4, 0xe0, 0x33, 0xff, 0x65, 0x6f, 0x6e, 0xe7,
+ 0x05, 0x60, 0x22, 0x32, 0x85, 0x67, 0xe9, 0xe0, 0x27, 0x78, 0xf8, 0xe0,
+ 0x2a, 0xf6, 0xf7, 0x04, 0xe0, 0x3e, 0x5d, 0x61, 0x6e, 0x67, 0xea, 0xda,
+ 0x78, 0x76, 0xae, 0x04, 0xe0, 0x3e, 0x41, 0xe1, 0x60, 0x3c, 0x92, 0xb3,
+ 0xf5, 0x12, 0x09, 0x0b, 0x04, 0x0b, 0x0b, 0x04, 0x05, 0x4d, 0x6b, 0x4d,
+ 0x1b, 0x5a, 0xb3, 0x43, 0x24, 0xc5, 0xa5, 0x73, 0x68, 0x69, 0x6b, 0x61,
+ 0xed, 0xe0, 0x39, 0x9a, 0x6f, 0x76, 0x64, 0x61, 0x67, 0x65, 0x61, 0x69,
+ 0xe4, 0xd9, 0x1c, 0xec, 0xe0, 0x2e, 0xa8, 0xea, 0x03, 0xc3, 0x26, 0x61,
+ 0x72, 0x61, 0xf4, 0xe0, 0x3c, 0xdd, 0xe9, 0x02, 0x84, 0x74, 0xe1, 0xdc,
+ 0x7e, 0xe4, 0xe0, 0x3c, 0x92, 0xe3, 0xe0, 0x32, 0x33, 0x62, 0xae, 0xe0,
+ 0x2b, 0xff, 0xe1, 0x02, 0x86, 0x72, 0x64, 0xe9, 0xe0, 0x39, 0xbd, 0x6d,
+ 0x2e, 0xe7, 0xe0, 0x3c, 0xf6, 0xf3, 0x07, 0x06, 0x60, 0x31, 0x7c, 0xcc,
+ 0x69, 0x6a, 0x2e, 0xe2, 0xe0, 0x3a, 0xc5, 0xae, 0x10, 0x05, 0x05, 0x0d,
+ 0x04, 0x0e, 0x06, 0x04, 0x0a, 0x06, 0x04, 0x60, 0x35, 0x39, 0xc3, 0xac,
+ 0xf6, 0x24, 0xe0, 0x37, 0x87, 0xf4, 0x60, 0x32, 0x22, 0x84, 0xf3, 0x05,
+ 0x15, 0xe0, 0x36, 0x12, 0x76, 0x61, 0x6c, 0xe2, 0xe0, 0x37, 0x20, 0xf2,
+ 0xe0, 0x36, 0xa2, 0xef, 0x05, 0x04, 0xe0, 0x36, 0x95, 0xf3, 0xe0, 0x35,
+ 0x65, 0xe6, 0xe0, 0x3c, 0x19, 0xee, 0x60, 0x36, 0x0d, 0xc0, 0x83, 0xed,
+ 0xe0, 0x31, 0xfc, 0x6a, 0x61, 0x6e, 0x2d, 0x6d, 0x61, 0xf9, 0xe0, 0x2e,
+ 0x1e, 0xe8, 0x60, 0x31, 0xea, 0xc4, 0x92, 0xe6, 0xe0, 0x31, 0xe4, 0xe1,
+ 0x04, 0xe0, 0x37, 0x60, 0xe8, 0xe0, 0x3b, 0xf2, 0xf2, 0x0b, 0x05, 0x04,
+ 0x40, 0x40, 0x13, 0x0e, 0x2e, 0xe0, 0x3c, 0xe0, 0xf5, 0x60, 0x3b, 0xe1,
+ 0xbb, 0xf0, 0xe0, 0x31, 0x9f, 0xef, 0x06, 0x06, 0x13, 0x06, 0x0b, 0x8c,
+ 0x7a, 0x6e, 0xf9, 0xe0, 0x39, 0xc4, 0xf5, 0x02, 0x86, 0xf0, 0x60, 0x3a,
+ 0x81, 0xc2, 0xdd, 0x6e, 0x64, 0x68, 0x61, 0x6e, 0x64, 0xec, 0xe0, 0x2d,
+ 0xce, 0x73, 0x73, 0xe5, 0xe0, 0x38, 0xd5, 0xee, 0x04, 0xe0, 0x36, 0x55,
+ 0x64, 0x61, 0xf2, 0xe0, 0x38, 0xce, 0x6b, 0x73, 0x2d, 0x74, 0xe8, 0x04,
+ 0xe0, 0x2d, 0x02, 0xe9, 0xd4, 0x03, 0xe3, 0xd7, 0xe9, 0xe9, 0x03, 0x08,
+ 0x84, 0x77, 0x2e, 0x67, 0x6f, 0xf6, 0xe0, 0x38, 0x6b, 0xf0, 0xe0, 0x3b,
+ 0xa6, 0xed, 0xca, 0x45, 0xe5, 0x04, 0x05, 0xc4, 0x8f, 0x74, 0xe1, 0xe0,
+ 0x2f, 0x37, 0xe1, 0xe0, 0x2a, 0x19, 0xe1, 0x07, 0x09, 0x0d, 0x0b, 0xe0,
+ 0x27, 0xb5, 0xf4, 0x04, 0xe0, 0x2d, 0x82, 0xe9, 0xe0, 0x3a, 0x97, 0x70,
+ 0xe8, 0x02, 0x84, 0x6f, 0xf8, 0xc1, 0xd5, 0x69, 0xe3, 0xe0, 0x3a, 0x8a,
+ 0xee, 0x05, 0x60, 0x3b, 0x54, 0x81, 0x76, 0xe9, 0xe0, 0x36, 0xb3, 0x6a,
+ 0x65, 0xf7, 0xc2, 0x57, 0xae, 0x60, 0x36, 0x81, 0x44, 0x5c, 0x40, 0x57,
+ 0xc1, 0xa4, 0xef, 0x10, 0x40, 0xfd, 0x19, 0x2d, 0x13, 0x0f, 0x06, 0x1c,
+ 0x0e, 0x1a, 0x0a, 0x06, 0x0c, 0x0d, 0xba, 0xf6, 0x06, 0x03, 0x04, 0xe0,
+ 0x3c, 0xb7, 0xf4, 0xc3, 0xe5, 0x65, 0xf2, 0xce, 0x83, 0xae, 0x1f, 0x08,
+ 0x06, 0x0c, 0x13, 0x0d, 0x0d, 0x14, 0x11, 0x0d, 0x0c, 0x04, 0x0d, 0x0a,
+ 0x0e, 0x12, 0x50, 0xa1, 0x4a, 0x5c, 0x03, 0x3c, 0x40, 0x47, 0x59, 0x5e,
+ 0x44, 0x56, 0x17, 0xc0, 0x48, 0xf6, 0x60, 0x30, 0xb3, 0x4a, 0x67, 0xc0,
+ 0x42, 0xf5, 0x60, 0x3a, 0x28, 0xc0, 0xbf, 0xf4, 0x60, 0x3a, 0x18, 0x1e,
+ 0x03, 0x0f, 0x40, 0x82, 0x33, 0x32, 0x9f, 0xf3, 0x50, 0xb7, 0x60, 0x21,
+ 0x6c, 0x42, 0xd7, 0x44, 0xf2, 0x27, 0x1a, 0x03, 0x15, 0x40, 0x90, 0x1c,
+ 0xc1, 0x8a, 0xf0, 0x60, 0x39, 0xd9, 0x27, 0x03, 0x17, 0x18, 0x40, 0x79,
+ 0x40, 0x65, 0x9f, 0xee, 0x08, 0x60, 0x3a, 0xfb, 0x40, 0xa6, 0xc0, 0xb2,
+ 0xe3, 0xe0, 0x2b, 0x23, 0xed, 0x60, 0x38, 0x93, 0x41, 0x49, 0x03, 0x07,
+ 0x03, 0x17, 0x18, 0x40, 0x90, 0x1c, 0x0f, 0x23, 0x1f, 0x3a, 0xc0, 0xff,
+ 0xec, 0x60, 0x30, 0x58, 0x41, 0x8a, 0x46, 0x9d, 0x41, 0x53, 0x03, 0x2f,
+ 0x40, 0x79, 0x17, 0xc0, 0x4e, 0xeb, 0x60, 0x39, 0xb7, 0x03, 0x1e, 0x39,
+ 0x40, 0x7c, 0x40, 0x63, 0xc1, 0x39, 0xe9, 0x5b, 0xd5, 0x5d, 0xdf, 0x1a,
+ 0x40, 0x91, 0x40, 0x42, 0x23, 0x9f, 0xe8, 0xe0, 0x39, 0xab, 0xe7, 0x60,
+ 0x39, 0x7d, 0x40, 0x44, 0x15, 0x1e, 0x40, 0x9d, 0x23, 0x1f, 0xba, 0xe5,
+ 0x60, 0x30, 0x1d, 0x4a, 0x25, 0x40, 0x42, 0xc1, 0x7b, 0xe3, 0x60, 0x34,
+ 0x74, 0x45, 0x30, 0x03, 0x03, 0x15, 0x40, 0xac, 0x40, 0x51, 0xba, 0xe2,
+ 0x60, 0x30, 0xff, 0x40, 0x90, 0x47, 0xc9, 0x1d, 0x0a, 0x17, 0x1b, 0x40,
+ 0x79, 0x17, 0x40, 0x4e, 0x9f, 0xe1, 0x60, 0x2f, 0xf3, 0x40, 0xfa, 0x48,
+ 0x76, 0x0a, 0x1a, 0x40, 0xd3, 0x23, 0xc0, 0x59, 0xf5, 0x02, 0x90, 0x76,
+ 0xae, 0x0a, 0x60, 0x2f, 0xdc, 0x06, 0x0d, 0x40, 0xf1, 0xc7, 0x57, 0xed,
+ 0xe0, 0x39, 0x69, 0x70, 0x69, 0xec, 0xe0, 0x20, 0x0b, 0xf4, 0x08, 0x05,
+ 0x08, 0x04, 0x05, 0xe0, 0x3b, 0x90, 0x73, 0xf5, 0xe0, 0x35, 0xee, 0x70,
+ 0x61, 0x6e, 0x74, 0x68, 0xe5, 0xcc, 0xf5, 0xef, 0xe0, 0x20, 0x3f, 0x65,
+ 0x6d, 0xe2, 0xc5, 0x27, 0x64, 0x6e, 0x73, 0xae, 0x04, 0xe0, 0x38, 0xb9,
+ 0xe3, 0x60, 0x3a, 0xda, 0xc0, 0xa7, 0xf3, 0x04, 0x05, 0xca, 0xca, 0x68,
+ 0xe9, 0xe0, 0x34, 0x36, 0xe5, 0x04, 0xe0, 0x33, 0x18, 0xee, 0xe0, 0x37,
+ 0x28, 0xf2, 0x02, 0x87, 0x6c, 0x69, 0x63, 0xe5, 0xe0, 0x36, 0xad, 0x69,
+ 0xfa, 0xe0, 0x34, 0xd3, 0xf0, 0x4a, 0xb1, 0xe0, 0x30, 0xae, 0xef, 0x05,
+ 0x10, 0xe0, 0x3b, 0x44, 0xe7, 0x04, 0xe0, 0x3b, 0x4f, 0x6c, 0xe5, 0x06,
+ 0x42, 0x33, 0xe0, 0x39, 0x14, 0xe3, 0xcc, 0x45, 0x64, 0x79, 0xe5, 0xe0,
+ 0x29, 0x30, 0xee, 0x06, 0x4a, 0x89, 0xe0, 0x20, 0xfc, 0x6f, 0x68, 0x65,
+ 0xae, 0xe0, 0x32, 0x33, 0xec, 0x05, 0x0b, 0xe0, 0x39, 0x8a, 0xe6, 0x04,
+ 0xe0, 0x3b, 0x25, 0x66, 0x61, 0x6e, 0xae, 0xdd, 0x08, 0xe4, 0x04, 0xe0,
+ 0x3b, 0x1a, 0x70, 0xef, 0xcb, 0xdd, 0xeb, 0x03, 0xca, 0x64, 0x61, 0x73,
+ 0xe5, 0xe0, 0x2c, 0xdf, 0x6a, 0x6f, 0x6d, 0xe5, 0xd7, 0x03, 0xe9, 0x02,
+ 0x83, 0xf0, 0xd7, 0xcd, 0x61, 0x6e, 0xe9, 0xe0, 0x31, 0x81, 0xe4, 0x02,
+ 0x84, 0xef, 0xe0, 0x32, 0x1d, 0x61, 0x64, 0xe4, 0xe0, 0x38, 0xb9, 0xe2,
+ 0x02, 0x84, 0xef, 0xe0, 0x30, 0x41, 0xae, 0x11, 0x04, 0x07, 0x04, 0x04,
+ 0x04, 0x06, 0x5e, 0x40, 0x4a, 0x66, 0x47, 0x24, 0x48, 0x36, 0xc0, 0xbd,
+ 0xf3, 0xe0, 0x37, 0x17, 0xf0, 0x60, 0x38, 0x69, 0x40, 0xbf, 0xab, 0xed,
+ 0xe0, 0x33, 0x46, 0xe8, 0xe0, 0x39, 0x8a, 0xe7, 0xe0, 0x39, 0x02, 0xe5,
+ 0x60, 0x2e, 0xd9, 0xc9, 0x7a, 0xe3, 0xe0, 0x38, 0x67, 0xae, 0x0f, 0x04,
+ 0x06, 0x4f, 0xd8, 0x59, 0x09, 0x4b, 0x54, 0x03, 0x43, 0xcd, 0x37, 0xc0,
+ 0xb2, 0xf5, 0xe0, 0x3a, 0xa1, 0xe9, 0x60, 0x38, 0x52, 0xc0, 0x8e, 0x64,
+ 0x79, 0xee, 0xd1, 0xdc, 0xee, 0x04, 0xe0, 0x3a, 0x8f, 0x69, 0x65, 0x7a,
+ 0x6e, 0xef, 0xe0, 0x35, 0xcf, 0xed, 0x0b, 0x05, 0x4d, 0xc4, 0x60, 0x25,
+ 0x30, 0x45, 0xf7, 0xc1, 0x8b, 0x69, 0xee, 0xe0, 0x2b, 0x95, 0xe2, 0xe0,
+ 0x37, 0xe5, 0xec, 0x08, 0x05, 0x27, 0x15, 0x08, 0xe0, 0x3a, 0x20, 0x75,
+ 0xe7, 0xe0, 0x36, 0x55, 0xef, 0x04, 0x05, 0x05, 0x84, 0x70, 0xf0, 0xe0,
+ 0x2a, 0xe1, 0x6f, 0xed, 0xe0, 0x31, 0xa5, 0xe7, 0xe0, 0x2d, 0xa9, 0xe2,
+ 0x04, 0xe0, 0x38, 0xc1, 0x61, 0xec, 0x04, 0xe0, 0x3a, 0x46, 0xae, 0x04,
+ 0xe0, 0x38, 0xd0, 0xf3, 0xe0, 0x38, 0xc1, 0xe9, 0x03, 0x07, 0x86, 0x77,
+ 0x69, 0x63, 0xe5, 0xe0, 0x28, 0x93, 0x74, 0x63, 0xe8, 0xe0, 0x24, 0x2a,
+ 0xe4, 0xe0, 0x2a, 0xa7, 0xe5, 0x04, 0xe0, 0x3a, 0x23, 0xe5, 0xc0, 0xaa,
+ 0xe1, 0xe0, 0x32, 0xb3, 0xea, 0x03, 0x05, 0x83, 0x1f, 0x43, 0xf8, 0xc1,
+ 0xac, 0xef, 0xc1, 0xa9, 0xe5, 0x04, 0x08, 0xc2, 0x20, 0xf2, 0x03, 0xc7,
+ 0x2e, 0xe4, 0xe0, 0x22, 0x85, 0xed, 0xe0, 0x35, 0xad, 0xe9, 0x0f, 0x06,
+ 0x40, 0x44, 0x07, 0x16, 0x0f, 0x05, 0x0c, 0x0b, 0x48, 0x31, 0xe0, 0x31,
+ 0x2c, 0xf6, 0x60, 0x24, 0x6c, 0xc9, 0x8b, 0xf4, 0x05, 0x05, 0x06, 0x13,
+ 0x88, 0x70, 0x61, 0x67, 0xe5, 0x9d, 0x6c, 0x61, 0xe2, 0xe0, 0x38, 0xd3,
+ 0x68, 0x75, 0xe2, 0x06, 0x60, 0x2f, 0xb5, 0xc9, 0x12, 0x70, 0x72, 0x65,
+ 0x76, 0x69, 0x65, 0xf7, 0xe0, 0x2c, 0x2c, 0x61, 0x70, 0x70, 0x2e, 0xf3,
+ 0xe0, 0x39, 0x68, 0xad, 0x02, 0x86, 0x72, 0x65, 0x70, 0xef, 0xd5, 0x07,
+ 0x70, 0x61, 0x67, 0x65, 0x73, 0x2e, 0x72, 0x69, 0x74, 0x2e, 0x65, 0xe4,
+ 0xe0, 0x39, 0x20, 0x72, 0xec, 0x60, 0x23, 0xd8, 0xcd, 0x18, 0xee, 0x02,
+ 0x8e, 0xef, 0x02, 0x85, 0x7a, 0xe1, 0xe0, 0x34, 0xfe, 0x77, 0x61, 0xee,
+ 0xe0, 0x34, 0xf8, 0x61, 0xee, 0xe0, 0x30, 0xb2, 0x6c, 0x64, 0x65, 0x73,
+ 0xeb, 0x04, 0xe0, 0x32, 0x64, 0x1f, 0x43, 0xe5, 0xe0, 0x32, 0x62, 0x69,
+ 0xfa, 0xe0, 0x31, 0xcc, 0xe6, 0x04, 0xe0, 0x36, 0x71, 0x75, 0xae, 0x60,
+ 0x30, 0x95, 0xc7, 0x2d, 0x65, 0x68, 0x74, 0x61, 0x76, 0x75, 0x6f, 0xe1,
+ 0xe0, 0x2a, 0x18, 0x61, 0xec, 0xd1, 0x62, 0xe8, 0x04, 0xe0, 0x39, 0x54,
+ 0xef, 0xd6, 0x69, 0xe7, 0x4b, 0x65, 0x54, 0xb9, 0x54, 0x54, 0xc4, 0xde,
+ 0xe5, 0x0d, 0x08, 0x0c, 0x34, 0x07, 0x09, 0x60, 0x36, 0xdf, 0x40, 0x5c,
+ 0xc1, 0xa7, 0xf4, 0x03, 0xc4, 0x53, 0xf3, 0xe0, 0x22, 0xff, 0xef, 0x04,
+ 0xe0, 0x37, 0xd2, 0x72, 0xe7, 0x60, 0x37, 0x3f, 0xc0, 0x70, 0xee, 0x04,
+ 0x13, 0x09, 0x84, 0xf4, 0x08, 0x60, 0x23, 0x96, 0x47, 0xfe, 0xcd, 0x84,
+ 0x6c, 0x65, 0x6e, 0x74, 0x61, 0x70, 0xe9, 0xe0, 0x37, 0xf5, 0xef, 0x04,
+ 0xe0, 0x32, 0x7a, 0xf6, 0xe0, 0x32, 0x79, 0x6b, 0xe1, 0xc2, 0x12, 0xae,
+ 0x08, 0x60, 0x2b, 0x3e, 0x44, 0xfb, 0xc7, 0x84, 0xee, 0x60, 0x36, 0x2a,
+ 0xc0, 0x5a, 0x69, 0x73, 0x65, 0xe9, 0xe0, 0x32, 0xec, 0x68, 0x69, 0x72,
+ 0x6e, 0x2e, 0xee, 0xe0, 0x29, 0xf8, 0x65, 0xeb, 0x02, 0x86, 0x67, 0x61,
+ 0x6c, 0xe1, 0xdb, 0x47, 0xae, 0xe0, 0x32, 0x27, 0xe4, 0x09, 0x07, 0x60,
+ 0x25, 0x54, 0x52, 0x35, 0xc1, 0x3a, 0x79, 0x6e, 0x69, 0xe1, 0xe0, 0x27,
+ 0x24, 0xe1, 0x04, 0xe0, 0x27, 0x1c, 0x6e, 0x73, 0xeb, 0xe0, 0x27, 0x19,
+ 0xe3, 0xe0, 0x37, 0x0e, 0xe2, 0x05, 0x60, 0x38, 0x8a, 0xa4, 0xe9, 0xe0,
+ 0x36, 0x3a, 0xe1, 0x10, 0x08, 0x0c, 0x06, 0x0f, 0x32, 0x15, 0x60, 0x32,
+ 0x84, 0x43, 0x6e, 0x40, 0x9a, 0xc1, 0x9d, 0xf5, 0x03, 0xc0, 0xb2, 0xec,
+ 0xe0, 0x29, 0x40, 0x74, 0x65, 0x77, 0x61, 0x79, 0x2e, 0x64, 0x65, 0xf6,
+ 0xe0, 0x38, 0x76, 0x72, 0x64, 0xe5, 0xe0, 0x37, 0x48, 0x6e, 0xe7, 0x02,
+ 0x83, 0xf7, 0xd4, 0x95, 0x61, 0x76, 0x69, 0x69, 0xeb, 0xe0, 0x32, 0x4b,
+ 0xed, 0x06, 0x05, 0x1f, 0xe0, 0x32, 0xf2, 0x76, 0xe9, 0xe0, 0x2d, 0xd7,
+ 0xe5, 0x07, 0x06, 0x4d, 0xeb, 0xe0, 0x2a, 0x6b, 0xf3, 0x60, 0x37, 0x59,
+ 0xc1, 0x02, 0xad, 0x02, 0x88, 0x73, 0x65, 0x72, 0x76, 0x65, 0xf2, 0xd5,
+ 0x99, 0x68, 0x6f, 0xf3, 0xe0, 0x2e, 0x89, 0x61, 0x67, 0x6f, 0xf2, 0xe0,
+ 0x32, 0xf7, 0xec, 0x05, 0x04, 0xe0, 0x38, 0x34, 0xf3, 0xe0, 0x32, 0x0f,
+ 0xec, 0x06, 0x52, 0xe5, 0xe0, 0x23, 0xbd, 0xf5, 0xe0, 0x36, 0x8f, 0xe9,
+ 0xe0, 0x28, 0xdd, 0x31, 0xb2, 0xe0, 0x36, 0xc8, 0xae, 0x06, 0x60, 0x26,
+ 0xb3, 0xd1, 0x64, 0x76, 0x62, 0x72, 0x70, 0x6c, 0x73, 0xe2, 0xcd, 0x18,
+ 0xe6, 0x1c, 0x08, 0x12, 0x01, 0x04, 0x41, 0xa0, 0x0e, 0x03, 0x41, 0xda,
+ 0x40, 0xc3, 0x17, 0x0c, 0x40, 0x90, 0x04, 0x10, 0x40, 0xf4, 0x1e, 0x40,
+ 0x6a, 0x04, 0x08, 0xc7, 0x31, 0x1f, 0x43, 0x78, 0x72, 0xe4, 0xe0, 0x36,
+ 0x58, 0xf9, 0x05, 0x06, 0xe0, 0x35, 0xc6, 0x72, 0x65, 0xf3, 0xe0, 0x30,
+ 0xc6, 0x6c, 0x6b, 0x65, 0xf3, 0xc4, 0x41, 0x76, 0xe7, 0xe0, 0x35, 0xd4,
+ 0xf5, 0x0c, 0x31, 0x0b, 0x26, 0x0f, 0x2a, 0x40, 0x58, 0x40, 0x6d, 0x19,
+ 0x8b, 0xf4, 0x05, 0x17, 0x06, 0x04, 0x85, 0x75, 0x72, 0xe5, 0x04, 0x05,
+ 0xc8, 0x01, 0x6d, 0x61, 0x69, 0xec, 0x85, 0x68, 0x6f, 0x73, 0x74, 0x69,
+ 0x6e, 0x67, 0xae, 0xe0, 0x37, 0x0f, 0x74, 0x73, 0xf5, 0xe0, 0x35, 0xc9,
+ 0x73, 0xf5, 0xdc, 0x49, 0x62, 0xef, 0xe0, 0x35, 0x4f, 0x61, 0xe2, 0xe0,
+ 0x2c, 0x57, 0xf3, 0x06, 0x60, 0x2e, 0xd5, 0xc2, 0x92, 0xf3, 0xe0, 0x31,
+ 0x83, 0xf2, 0x03, 0x18, 0x85, 0xf5, 0x05, 0x0c, 0xe0, 0x31, 0xcc, 0x6b,
+ 0x61, 0x77, 0x61, 0x2e, 0x6d, 0x69, 0x79, 0xe1, 0xe0, 0x2b, 0xf9, 0x64,
+ 0x6f, 0xee, 0xe0, 0x31, 0xfb, 0x6e, 0xe9, 0xe0, 0x34, 0xa4, 0x61, 0xee,
+ 0xe0, 0x2b, 0xcc, 0xef, 0x02, 0x86, 0x73, 0x73, 0xeb, 0xe0, 0x2f, 0x13,
+ 0x69, 0x73, 0xeb, 0xe0, 0x30, 0xe8, 0xee, 0x07, 0x0b, 0x60, 0x34, 0xf7,
+ 0xc2, 0x4c, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x66, 0xee, 0xc3,
+ 0xc8, 0xe1, 0x03, 0x06, 0x88, 0x68, 0x61, 0x73, 0x68, 0xe9, 0xbb, 0x67,
+ 0x61, 0x74, 0x61, 0xae, 0xe0, 0x2c, 0x0b, 0x62, 0x61, 0xf3, 0xdb, 0x26,
+ 0xeb, 0x03, 0xc0, 0x48, 0xf5, 0x0a, 0x04, 0x10, 0x05, 0x09, 0x07, 0x07,
+ 0xe0, 0x2c, 0x91, 0x79, 0xe1, 0xc8, 0x36, 0xf3, 0x04, 0xe0, 0x2f, 0xce,
+ 0x68, 0x69, 0x6d, 0x61, 0xae, 0x60, 0x31, 0xa4, 0x43, 0xb7, 0x89, 0x72,
+ 0xef, 0xe0, 0x2c, 0xa4, 0x6d, 0x69, 0x74, 0x73, 0x75, 0xae, 0xe0, 0x2b,
+ 0xdb, 0x69, 0xae, 0x4c, 0x7e, 0xe0, 0x28, 0xd0, 0x64, 0x6f, 0x6d, 0xe9,
+ 0xe0, 0x2c, 0x50, 0x63, 0x68, 0xe9, 0x03, 0xdf, 0xd4, 0x79, 0x61, 0x6d,
+ 0xe1, 0xe0, 0x28, 0xae, 0xe1, 0x02, 0x85, 0x79, 0xe1, 0xe0, 0x2b, 0x9c,
+ 0xe7, 0xe0, 0x2b, 0xa0, 0x6a, 0xe9, 0x0c, 0x09, 0x05, 0x18, 0x04, 0x06,
+ 0x0f, 0x14, 0x06, 0xe0, 0x2c, 0x0b, 0x79, 0x6f, 0x73, 0x68, 0x69, 0x64,
+ 0xe1, 0xce, 0x9f, 0x74, 0xf3, 0xe0, 0x35, 0xbb, 0xf3, 0x02, 0x86, 0x68,
+ 0x69, 0xf2, 0xe0, 0x26, 0xec, 0xe1, 0x02, 0x88, 0x77, 0x61, 0xae, 0x40,
+ 0x5f, 0xe0, 0x31, 0x88, 0x74, 0xef, 0xd2, 0x9d, 0xef, 0xe0, 0x2d, 0xd1,
+ 0x6e, 0x6f, 0x6d, 0x69, 0xf9, 0xac, 0x6d, 0xe9, 0x02, 0x85, 0x6e, 0xef,
+ 0xe0, 0x2b, 0x51, 0xae, 0x60, 0x2c, 0x23, 0xc7, 0x56, 0x6b, 0x61, 0x77,
+ 0xe1, 0x02, 0x89, 0x67, 0x75, 0x63, 0x68, 0x69, 0x6b, 0xef, 0xce, 0x5a,
+ 0xae, 0x5a, 0x31, 0xd1, 0xe5, 0x69, 0x64, 0x65, 0xf2, 0xdb, 0x28, 0x65,
+ 0x64, 0xe1, 0xe0, 0x2c, 0x08, 0xe5, 0x05, 0x0e, 0xe0, 0x31, 0x63, 0x74,
+ 0x74, 0x65, 0x72, 0x74, 0x64, 0x61, 0x73, 0x6e, 0x65, 0x74, 0xfa, 0xd3,
+ 0x20, 0x66, 0x75, 0xeb, 0xce, 0x2f, 0x64, 0x61, 0x69, 0x2e, 0x69, 0x77,
+ 0x61, 0xf4, 0xe0, 0x31, 0x7c, 0x63, 0x68, 0x75, 0xae, 0x04, 0xe0, 0x2a,
+ 0xe7, 0x74, 0xef, 0x60, 0x30, 0x7d, 0xc2, 0x78, 0xf4, 0x04, 0xe0, 0x34,
+ 0xd6, 0x70, 0x61, 0x63, 0x63, 0x65, 0x73, 0xf3, 0xd3, 0x74, 0xf3, 0xd7,
+ 0x57, 0xf2, 0x10, 0x0a, 0x08, 0x40, 0xd0, 0x1e, 0x40, 0x5f, 0x3d, 0x60,
+ 0x22, 0x27, 0x50, 0x00, 0xc2, 0x4f, 0x1f, 0xc3, 0x02, 0x82, 0xf8, 0x97,
+ 0xe6, 0xe0, 0x2b, 0x40, 0x75, 0x73, 0x6b, 0x79, 0x2e, 0xe4, 0xd8, 0x22,
+ 0xef, 0x09, 0x04, 0x09, 0x06, 0x40, 0xaa, 0xe0, 0x28, 0x82, 0xf9, 0xe0,
+ 0x2f, 0xcd, 0xf3, 0x04, 0xe0, 0x2f, 0xc4, 0x69, 0xee, 0xd3, 0x75, 0x6e,
+ 0x74, 0xe9, 0xe0, 0x22, 0x46, 0xed, 0x02, 0x89, 0xae, 0x04, 0xe0, 0x23,
+ 0xaf, 0xe8, 0xe0, 0x34, 0x81, 0xad, 0x14, 0x09, 0x06, 0x04, 0x05, 0x06,
+ 0x04, 0x06, 0x07, 0x17, 0x0f, 0x05, 0x09, 0x04, 0x02, 0x04, 0x05, 0x0a,
+ 0xdf, 0xb4, 0xf7, 0x40, 0x77, 0x42, 0x5c, 0x55, 0x5c, 0xd3, 0xae, 0xf6,
+ 0x40, 0x6e, 0xe0, 0x2b, 0x3a, 0xf5, 0xe0, 0x2b, 0xa2, 0xf4, 0x4d, 0xc2,
+ 0xdd, 0xf3, 0xf3, 0x50, 0x28, 0xe0, 0x20, 0x27, 0xf2, 0xe0, 0x2b, 0xbf,
+ 0xf0, 0x40, 0x55, 0xe0, 0x34, 0x64, 0xef, 0x19, 0x60, 0x31, 0x8c, 0xc3,
+ 0x0e, 0xee, 0x0e, 0x04, 0x42, 0x92, 0x4d, 0x6d, 0x5b, 0xc8, 0x42, 0x0e,
+ 0x42, 0x51, 0xc3, 0xf3, 0xea, 0xe0, 0x35, 0x7b, 0xe8, 0xe0, 0x35, 0x77,
+ 0xed, 0x31, 0x4d, 0x5e, 0x52, 0xb0, 0x48, 0x50, 0x42, 0xdc, 0x2c, 0x44,
+ 0x8a, 0xc4, 0x3e, 0xeb, 0x57, 0xda, 0xdc, 0x76, 0xe9, 0x1d, 0x4d, 0x5e,
+ 0x60, 0x21, 0x15, 0xc1, 0x7d, 0xe8, 0xe0, 0x2b, 0x7a, 0xe7, 0x90, 0xe6,
+ 0xe0, 0x2e, 0x81, 0xe4, 0x4f, 0xd3, 0xdd, 0xd6, 0xe3, 0x05, 0x60, 0x2b,
+ 0x20, 0x9a, 0xe1, 0xe0, 0x35, 0x41, 0xe1, 0x08, 0x60, 0x2e, 0x66, 0x42,
+ 0xe3, 0xc3, 0x0e, 0xfa, 0xe0, 0x35, 0x18, 0xe7, 0x04, 0xe0, 0x2e, 0xff,
+ 0xe1, 0xe0, 0x25, 0x2f, 0x69, 0x75, 0x6c, 0xe9, 0x02, 0x81, 0x2d, 0xf6,
+ 0x03, 0x0b, 0x81, 0xe5, 0x03, 0x07, 0x81, 0x6e, 0x65, 0x7a, 0x69, 0xe1,
+ 0x02, 0x81, 0x2d, 0x67, 0x69, 0x75, 0xec, 0xe0, 0x2e, 0x85, 0xe5, 0x08,
+ 0x07, 0x08, 0x40, 0x42, 0xe0, 0x2d, 0x1f, 0x73, 0x65, 0x6e, 0xe9, 0xe0,
+ 0x30, 0x01, 0x6e, 0x63, 0x68, 0x6b, 0x69, 0xf3, 0xd9, 0x5b, 0xe5, 0x09,
+ 0x06, 0x07, 0x04, 0x14, 0x0e, 0xe0, 0x34, 0xbd, 0x74, 0x6c, 0xf3, 0xe0,
+ 0x33, 0x80, 0x73, 0x69, 0x74, 0x65, 0xae, 0xd7, 0x30, 0x6d, 0xf9, 0xcd,
+ 0x9e, 0xe4, 0x02, 0x89, 0x65, 0x73, 0x6b, 0x74, 0x6f, 0xf0, 0xe0, 0x32,
+ 0x06, 0x64, 0x6e, 0x73, 0xae, 0x56, 0xb6, 0xdb, 0x4a, 0x62, 0x6f, 0xf8,
+ 0x02, 0x81, 0x2d, 0x6f, 0x73, 0xae, 0x60, 0x34, 0x31, 0xc0, 0x8a, 0x2e,
+ 0xe8, 0xe0, 0x34, 0x2b, 0x64, 0x72, 0xe9, 0xc1, 0xdb, 0xe1, 0x05, 0x2b,
+ 0xe0, 0x29, 0xb7, 0x6d, 0x65, 0xf2, 0x02, 0x86, 0x63, 0x61, 0x6e, 0xf6,
+ 0xcc, 0x89, 0xae, 0x06, 0x0c, 0x08, 0xe0, 0x33, 0x12, 0xf7, 0x02, 0x85,
+ 0x69, 0xeb, 0xe0, 0x34, 0x3e, 0x65, 0xe2, 0xdd, 0x60, 0x70, 0x68, 0x6f,
+ 0x74, 0xef, 0xe0, 0x34, 0x1b, 0x6d, 0x65, 0xe4, 0xd6, 0x7d, 0x31, 0x2d,
+ 0x64, 0x65, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0xe4, 0xd6, 0x74, 0xad, 0x02,
+ 0x95, 0x70, 0x61, 0x72, 0xad, 0x02, 0x82, 0xb2, 0x82, 0x31, 0x2e, 0x62,
+ 0x61, 0x72, 0x65, 0x6d, 0x65, 0x74, 0x61, 0xec, 0xc0, 0xeb, 0x31, 0x2e,
+ 0x70, 0x61, 0x61, 0x73, 0x2e, 0x6d, 0x61, 0x73, 0x73, 0x69, 0x76, 0x65,
+ 0x67, 0x72, 0x69, 0xe4, 0xe0, 0x34, 0x28, 0xef, 0x0f, 0x07, 0x04, 0x40,
+ 0x81, 0x09, 0x19, 0x54, 0xbd, 0x4c, 0x73, 0x4a, 0xd9, 0xc7, 0x82, 0x75,
+ 0x6e, 0x64, 0xe1, 0xe0, 0x27, 0xa2, 0xf3, 0xe0, 0x2f, 0xdc, 0xf2, 0x0a,
+ 0x0c, 0x0b, 0x07, 0x13, 0x1c, 0x06, 0xe0, 0x24, 0x13, 0x75, 0xed, 0x06,
+ 0x60, 0x33, 0x19, 0xc1, 0x02, 0xfa, 0xe0, 0x23, 0xe8, 0xf4, 0x02, 0x83,
+ 0xe5, 0xc1, 0x34, 0x61, 0xec, 0xe0, 0x32, 0xb4, 0x73, 0xe1, 0x60, 0x2d,
+ 0x72, 0xc4, 0xa5, 0xec, 0x02, 0x85, 0x1f, 0x43, 0xec, 0x05, 0x81, 0xe9,
+ 0x02, 0x81, 0x2d, 0x63, 0x65, 0x73, 0xe5, 0xe0, 0x2b, 0xae, 0xe7, 0x02,
+ 0x90, 0x6f, 0x74, 0x2e, 0xe8, 0x02, 0x83, 0x69, 0xf3, 0x83, 0x65, 0x72,
+ 0x2e, 0x6e, 0xe1, 0xdd, 0xdd, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0xeb, 0xe0,
+ 0x32, 0xbd, 0xe4, 0x60, 0x32, 0x3f, 0xc1, 0x96, 0xad, 0x05, 0x03, 0x04,
+ 0x06, 0x87, 0x74, 0xe8, 0x8e, 0x73, 0x6f, 0xed, 0x8a, 0x6f, 0x75, 0xf2,
+ 0xe0, 0x23, 0x8e, 0x6d, 0x6f, 0x72, 0xe5, 0xe0, 0x30, 0x93, 0x62, 0x65,
+ 0x74, 0x74, 0x65, 0xf2, 0xe0, 0x30, 0x8a, 0xef, 0x50, 0x57, 0x52, 0x59,
+ 0x4e, 0xb0, 0xc2, 0x4c, 0xec, 0x03, 0x04, 0x88, 0xec, 0xe0, 0x2c, 0x83,
+ 0x6b, 0x65, 0x62, 0x69, 0xe2, 0xe0, 0x2c, 0x7d, 0x69, 0x6f, 0x6e, 0x65,
+ 0x74, 0x77, 0x6f, 0xf2, 0x8c, 0x67, 0xe7, 0xe0, 0x2c, 0xf9, 0xee, 0x04,
+ 0x04, 0xde, 0xa1, 0x77, 0xeb, 0xdc, 0x4d, 0x63, 0x2e, 0x66, 0x72, 0x2d,
+ 0x70, 0x61, 0x72, 0x2e, 0x73, 0x63, 0xf7, 0xdb, 0x91, 0xed, 0x04, 0xe0,
+ 0x33, 0x6a, 0xae, 0x60, 0x31, 0x67, 0x40, 0x6e, 0xba, 0xec, 0x0b, 0x10,
+ 0x0e, 0x2a, 0x13, 0x0c, 0x06, 0x5b, 0x7a, 0xd1, 0xcb, 0xf9, 0x06, 0x60,
+ 0x25, 0xb4, 0xcd, 0x9c, 0x6e, 0x6e, 0x68, 0x6f, 0x73, 0xf4, 0xe0, 0x2d,
+ 0x82, 0x74, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x6d, 0x75, 0x6e,
+ 0xe9, 0xd0, 0x1d, 0xef, 0x05, 0x03, 0x18, 0xd4, 0x5e, 0xf7, 0xc2, 0x61,
+ 0xf2, 0x08, 0x09, 0x5d, 0xf7, 0x4c, 0xdb, 0xc2, 0x24, 0xe9, 0x04, 0xe0,
+ 0x26, 0x4a, 0xf0, 0xe0, 0x29, 0xa5, 0x65, 0x6e, 0xe3, 0xe0, 0x2c, 0x13,
+ 0xf0, 0x04, 0xe0, 0x32, 0x18, 0xf0, 0xe0, 0x2a, 0x5f, 0xe9, 0x07, 0x08,
+ 0x60, 0x20, 0x08, 0xd1, 0x9e, 0x67, 0x68, 0xf4, 0x60, 0x30, 0x27, 0xc0,
+ 0x74, 0xe3, 0xdc, 0x0e, 0xe5, 0x02, 0x83, 0xf3, 0xc6, 0x9a, 0x6b, 0x6b,
+ 0xe5, 0xe0, 0x23, 0x4d, 0x64, 0x72, 0xf6, 0xe0, 0x32, 0xe5, 0xe1, 0x06,
+ 0x03, 0x06, 0xe0, 0x31, 0x45, 0xf4, 0xdc, 0xcf, 0x70, 0x2e, 0xe9, 0xe0,
+ 0x26, 0xa8, 0x6b, 0x73, 0x74, 0xe1, 0xe0, 0x2e, 0xb4, 0xeb, 0xe0, 0x21,
+ 0x6f, 0xea, 0x06, 0x04, 0x5f, 0x55, 0xd3, 0x6f, 0xe5, 0xe0, 0x27, 0x14,
+ 0x61, 0xec, 0xe0, 0x27, 0x19, 0xe9, 0x0c, 0x0e, 0x06, 0x40, 0x5d, 0x22,
+ 0x2c, 0x04, 0x09, 0xe0, 0x31, 0xe6, 0xf4, 0x05, 0x04, 0xe0, 0x32, 0xa8,
+ 0xee, 0xe0, 0x2b, 0x3e, 0xea, 0xe0, 0x23, 0x53, 0x73, 0xe8, 0x5d, 0x20,
+ 0xd5, 0x82, 0xf2, 0x02, 0x9d, 0xed, 0x02, 0x85, 0x64, 0xe1, 0xe0, 0x30,
+ 0xa3, 0xae, 0x0e, 0x60, 0x27, 0x97, 0x40, 0x79, 0x46, 0xf2, 0x41, 0xf6,
+ 0x40, 0x51, 0xc1, 0x02, 0xee, 0x60, 0x27, 0x9a, 0xc8, 0x1c, 0xe5, 0x07,
+ 0x21, 0x0d, 0x5c, 0x27, 0xd6, 0x21, 0xf7, 0x02, 0x85, 0x65, 0xe2, 0xe0,
+ 0x30, 0xfb, 0x61, 0x6c, 0xec, 0x02, 0x8a, 0x65, 0x64, 0x72, 0x65, 0x70,
+ 0x6c, 0x69, 0xf4, 0xd9, 0x5e, 0x2d, 0x67, 0x61, 0x74, 0x65, 0x77, 0x61,
+ 0xf9, 0xdc, 0x6a, 0xee, 0x02, 0x84, 0xfa, 0xe0, 0x2b, 0x49, 0x65, 0x74,
+ 0x2e, 0xe3, 0xdb, 0x01, 0x62, 0x61, 0x73, 0xe5, 0xe0, 0x31, 0x57, 0xee,
+ 0x03, 0x06, 0x8e, 0xee, 0x60, 0x26, 0x8c, 0xc3, 0x0d, 0xe1, 0x04, 0xe0,
+ 0x2f, 0xe3, 0x6e, 0xe3, 0x04, 0xe0, 0x30, 0xb0, 0xe9, 0xcc, 0x81, 0xae,
+ 0x05, 0x44, 0x13, 0xcc, 0xc3, 0xe3, 0xe0, 0x31, 0xca, 0xec, 0x02, 0x86,
+ 0xed, 0x60, 0x31, 0x19, 0xc1, 0x02, 0x65, 0x67, 0x65, 0x61, 0xf2, 0x03,
+ 0xdc, 0x09, 0xad, 0x07, 0x04, 0x04, 0x04, 0x03, 0xcd, 0xc6, 0x73, 0xe7,
+ 0xdb, 0xff, 0x6a, 0xf0, 0xdb, 0xfb, 0x67, 0xe2, 0xdb, 0xf7, 0xe4, 0xcd,
+ 0xc9, 0x61, 0xf5, 0xdb, 0xf0, 0xe5, 0xe0, 0x2d, 0x13, 0xe4, 0x04, 0xe0,
+ 0x30, 0x5f, 0x65, 0xec, 0xd6, 0xfa, 0xae, 0x06, 0x60, 0x2b, 0x81, 0xc4,
+ 0x5c, 0xe3, 0x04, 0xe0, 0x30, 0x81, 0x6c, 0x6f, 0x75, 0x64, 0x70, 0x6c,
+ 0x61, 0x74, 0x66, 0x6f, 0x72, 0xed, 0xe0, 0x31, 0x74, 0xe8, 0x06, 0x04,
+ 0x09, 0xe0, 0x20, 0x50, 0xf6, 0xe0, 0x20, 0x5c, 0xf3, 0x04, 0xe0, 0x30,
+ 0x26, 0xeb, 0xe0, 0x20, 0x53, 0x2d, 0x6d, 0x75, 0x65, 0x6e, 0x73, 0xf4,
+ 0xe0, 0x20, 0xc4, 0xe5, 0x0c, 0x05, 0x08, 0x10, 0x08, 0x05, 0x06, 0x45,
+ 0x21, 0xe0, 0x2a, 0x4c, 0xf4, 0x5b, 0x61, 0xd4, 0xa9, 0x73, 0x74, 0x65,
+ 0x2d, 0xe9, 0xe0, 0x25, 0x6d, 0xf2, 0x03, 0xdf, 0xac, 0xf2, 0x04, 0xe0,
+ 0x2e, 0xaf, 0x61, 0xf2, 0x60, 0x2a, 0xf9, 0xc4, 0x76, 0x6e, 0x74, 0x69,
+ 0x67, 0x65, 0xf2, 0xd8, 0xb6, 0x69, 0xf2, 0xe0, 0x27, 0xfd, 0x65, 0x64,
+ 0x62, 0xe1, 0xc4, 0xa9, 0xe4, 0x06, 0x19, 0x04, 0xe0, 0x2b, 0xa7, 0x6f,
+ 0x72, 0xe1, 0x02, 0x87, 0x70, 0x65, 0x6f, 0x70, 0xec, 0xdc, 0x23, 0x69,
+ 0x6e, 0x66, 0x72, 0x61, 0x63, 0x6c, 0x6f, 0x75, 0xe4, 0xe0, 0x2e, 0x83,
+ 0xea, 0xe0, 0x2f, 0xb9, 0xe5, 0x04, 0xe0, 0x29, 0xc5, 0xf2, 0xe0, 0x2e,
+ 0x64, 0xe3, 0xe0, 0x2f, 0x3f, 0x62, 0xf8, 0x02, 0x81, 0x2d, 0xef, 0xc1,
+ 0x0d, 0xe1, 0x09, 0x06, 0x40, 0x4b, 0x0e, 0x13, 0x12, 0x06, 0x8c, 0x75,
+ 0x73, 0xeb, 0xe0, 0x2f, 0x94, 0xf3, 0x02, 0xb9, 0xf4, 0x06, 0x0d, 0x08,
+ 0xe0, 0x31, 0x08, 0x76, 0x70, 0xf3, 0x02, 0x85, 0xae, 0x53, 0x62, 0xc6,
+ 0x84, 0xad, 0xcc, 0xec, 0x73, 0x74, 0x61, 0x63, 0xeb, 0xe0, 0x30, 0xe6,
+ 0x6c, 0xf9, 0x02, 0x85, 0x6c, 0xe2, 0xe0, 0x30, 0xde, 0xad, 0x02, 0x8b,
+ 0x74, 0x65, 0x72, 0x72, 0x61, 0x72, 0x69, 0xf5, 0xe0, 0x27, 0x3b, 0x65,
+ 0x64, 0xe7, 0xe0, 0x29, 0x43, 0x68, 0x69, 0x6f, 0xee, 0x04, 0xe0, 0x30,
+ 0xe3, 0x73, 0x74, 0x6f, 0xf2, 0xe0, 0x21, 0xf2, 0xf2, 0x05, 0x5a, 0x98,
+ 0xd4, 0xe3, 0xed, 0x04, 0xe0, 0x30, 0xd1, 0xe5, 0xcf, 0x3d, 0xee, 0x06,
+ 0x60, 0x2e, 0x5e, 0xc2, 0x69, 0x74, 0x61, 0x73, 0x79, 0x6c, 0x65, 0x61,
+ 0x67, 0x75, 0xe5, 0xce, 0x09, 0xed, 0x02, 0x8a, 0x69, 0x6c, 0xf9, 0x04,
+ 0xe0, 0x30, 0xb1, 0xe4, 0xdc, 0xf1, 0x2e, 0xf0, 0xe0, 0x2e, 0x46, 0x6b,
+ 0x65, 0x66, 0xf5, 0xdd, 0xaf, 0xe9, 0x06, 0x46, 0x80, 0xe0, 0x27, 0xcd,
+ 0x72, 0x77, 0xe9, 0xca, 0x15, 0xe7, 0xe0, 0x2f, 0x1a, 0xe5, 0x22, 0x11,
+ 0x40, 0xb2, 0x2b, 0x40, 0x86, 0x1a, 0x40, 0x61, 0x1f, 0x0d, 0x05, 0x40,
+ 0xb1, 0x40, 0xf2, 0x27, 0x0a, 0x24, 0x11, 0x16, 0x41, 0x7a, 0x40, 0x43,
+ 0x14, 0x40, 0x48, 0x03, 0x0f, 0xe0, 0x25, 0x39, 0x7a, 0x70, 0x72, 0x6f,
+ 0x78, 0x79, 0x2e, 0x6b, 0x75, 0x6c, 0x65, 0x75, 0x76, 0x65, 0xee, 0xd3,
+ 0x07, 0xf8, 0x07, 0x08, 0x27, 0x04, 0x40, 0x53, 0x8b, 0x74, 0x72, 0x61,
+ 0x73, 0xf0, 0xe0, 0x29, 0x66, 0xf0, 0x03, 0x09, 0x84, 0x72, 0x65, 0x73,
+ 0xf3, 0x60, 0x2d, 0x6a, 0xc2, 0xdd, 0x6f, 0xf3, 0xd1, 0xe4, 0x65, 0x72,
+ 0xf4, 0x04, 0xe0, 0x30, 0x37, 0x73, 0x2d, 0x63, 0x6f, 0x6d, 0x70, 0x74,
+ 0x61, 0x62, 0x6c, 0x65, 0xf3, 0xe0, 0x2f, 0x99, 0x6e, 0xe5, 0xd4, 0x98,
+ 0x65, 0x63, 0x75, 0x74, 0x65, 0x2d, 0x61, 0x70, 0x69, 0xae, 0x08, 0x04,
+ 0x1a, 0x42, 0x86, 0x16, 0x05, 0x9a, 0x69, 0xec, 0xc2, 0xec, 0x65, 0x75,
+ 0xad, 0x05, 0x08, 0x42, 0xbd, 0x83, 0x73, 0x6f, 0x75, 0x74, 0xe8, 0xe0,
+ 0x28, 0x21, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x61, 0xec, 0xe0, 0x28, 0x17,
+ 0xe1, 0x03, 0xc2, 0xf9, 0x70, 0xad, 0x04, 0x42, 0xdb, 0x93, 0x73, 0x6f,
+ 0x75, 0x74, 0xe8, 0x04, 0xe0, 0x28, 0x01, 0x65, 0x61, 0x73, 0x74, 0xad,
+ 0x07, 0x42, 0xd5, 0x60, 0x25, 0x23, 0x82, 0xb4, 0xe0, 0x27, 0xfa, 0x63,
+ 0x68, 0x61, 0x6e, 0x67, 0xe5, 0x60, 0x2c, 0xee, 0xc2, 0xdd, 0xae, 0x02,
+ 0x89, 0x6f, 0x72, 0x74, 0x73, 0x69, 0x6e, 0x66, 0xef, 0x8a, 0x66, 0x75,
+ 0x74, 0x75, 0x72, 0x65, 0x63, 0x6d, 0x73, 0x2e, 0xe1, 0xcd, 0x27, 0xf6,
+ 0x02, 0x8d, 0x6a, 0x65, 0x2d, 0x6f, 0x67, 0x2d, 0x68, 0x6f, 0x72, 0xee,
+ 0xe0, 0x2b, 0x4b, 0x65, 0xee, 0x07, 0x0c, 0x60, 0x26, 0x05, 0xc5, 0x2f,
+ 0x1f, 0x43, 0x61, 0x1f, 0x45, 0x61, 0x1f, 0x45, 0xe1, 0xe0, 0x27, 0xf2,
+ 0x61, 0x73, 0xf3, 0xe0, 0x27, 0xec, 0xf5, 0x09, 0x10, 0x06, 0x33, 0x60,
+ 0x2c, 0xc6, 0xc2, 0x69, 0x72, 0xef, 0x02, 0x86, 0x76, 0x69, 0xf3, 0xe0,
+ 0x22, 0xdf, 0x64, 0x69, 0xf2, 0xe0, 0x2e, 0xe1, 0x6e, 0x2e, 0xe5, 0xe0,
+ 0x2f, 0x64, 0xae, 0x0c, 0x11, 0x09, 0x03, 0x5d, 0xcb, 0x47, 0xfb, 0x46,
+ 0xa3, 0xc2, 0xc8, 0xf0, 0x03, 0xde, 0x09, 0x79, 0x74, 0x68, 0x6f, 0x6e,
+ 0x61, 0x6e, 0x79, 0x77, 0x68, 0xe5, 0xd4, 0xe0, 0x6d, 0x65, 0x74, 0x65,
+ 0x6f, 0xf2, 0xe0, 0x2e, 0x51, 0xe9, 0xc8, 0x40, 0x65, 0x6e, 0x63, 0x6f,
+ 0x77, 0x61, 0xf9, 0xd7, 0x51, 0xad, 0x0a, 0x0e, 0x08, 0x02, 0x02, 0x02,
+ 0x57, 0x35, 0xd3, 0xc8, 0x77, 0x65, 0x73, 0x74, 0xad, 0x05, 0x60, 0x25,
+ 0xd4, 0x82, 0xb3, 0xe0, 0x25, 0xd6, 0x6e, 0x6f, 0x72, 0x74, 0xe8, 0xe0,
+ 0x25, 0xb9, 0xb4, 0x86, 0xb3, 0x84, 0xb2, 0x82, 0x31, 0x2e, 0x65, 0x76,
+ 0x65, 0x6e, 0x6e, 0x6f, 0xe4, 0xe0, 0x27, 0x54, 0xf4, 0x08, 0x07, 0x04,
+ 0x60, 0x26, 0xab, 0xc8, 0x3d, 0x6e, 0xe5, 0x60, 0x27, 0xd5, 0xc5, 0x87,
+ 0xe3, 0xe0, 0x2d, 0x90, 0x61, 0x6a, 0x69, 0xed, 0xca, 0xd5, 0xf3, 0x0a,
+ 0x34, 0x04, 0x09, 0x09, 0x4e, 0x45, 0xe0, 0x20, 0x48, 0xf4, 0x05, 0x05,
+ 0xe0, 0x28, 0x14, 0x2e, 0xf0, 0xe0, 0x2d, 0x76, 0xad, 0x03, 0x0c, 0x88,
+ 0x6d, 0x6f, 0x6e, 0x2d, 0x62, 0x6c, 0x6f, 0x67, 0x75, 0xe5, 0xc5, 0xbf,
+ 0x6c, 0x65, 0x2d, 0x70, 0x61, 0x74, 0xf2, 0x8f, 0x61, 0x2d, 0x6c, 0x61,
+ 0x2d, 0x6d, 0xe1, 0x02, 0x83, 0x73, 0xe9, 0x83, 0x69, 0x73, 0xef, 0xc6,
+ 0xb9, 0xf0, 0xe0, 0x2d, 0x47, 0xe1, 0x04, 0xe0, 0x28, 0x77, 0xee, 0xe0,
+ 0x2c, 0xe4, 0xae, 0x57, 0xa5, 0x45, 0x83, 0x4b, 0x09, 0x03, 0x83, 0x2d,
+ 0x31, 0x2e, 0x61, 0x78, 0x61, 0x72, 0x6e, 0x65, 0xf4, 0xd6, 0xa3, 0xf2,
+ 0x08, 0x0c, 0x51, 0xf5, 0x4b, 0x14, 0xd0, 0x27, 0x6f, 0x74, 0xe9, 0x02,
+ 0x82, 0xeb, 0x82, 0x63, 0xe1, 0xe0, 0x2d, 0x6d, 0xe9, 0x02, 0x84, 0xed,
+ 0xe0, 0x22, 0xcc, 0x63, 0xf3, 0x8f, 0x71, 0x75, 0x69, 0x70, 0x6d, 0x65,
+ 0x6e, 0xf4, 0x60, 0x2b, 0x7d, 0xc2, 0xdd, 0x70, 0xf3, 0xe0, 0x26, 0xf5,
+ 0xee, 0x0f, 0x22, 0x12, 0x04, 0x1d, 0x04, 0x0e, 0x20, 0x0f, 0x04, 0x60,
+ 0x25, 0x5f, 0xc6, 0x44, 0xf4, 0x02, 0x9c, 0x65, 0xf2, 0x02, 0x87, 0x74,
+ 0x61, 0x69, 0xee, 0xe0, 0x26, 0x77, 0x70, 0x72, 0x69, 0x73, 0xe5, 0x04,
+ 0xe0, 0x2b, 0xc0, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0xae, 0xdd, 0xc3, 0xae,
+ 0xdc, 0xd7, 0xf3, 0x02, 0x8a, 0x63, 0x61, 0x6c, 0x65, 0x64, 0x2e, 0xf3,
+ 0xe0, 0x2b, 0x47, 0x2e, 0xf4, 0xe0, 0x2c, 0xd5, 0xe9, 0xe0, 0x22, 0xd5,
+ 0xe7, 0x03, 0x0f, 0x85, 0x69, 0x6e, 0xe5, 0x04, 0xe0, 0x2b, 0x20, 0x65,
+ 0xf2, 0x58, 0x79, 0x52, 0xa5, 0xc2, 0xdd, 0x65, 0xf2, 0xe0, 0x26, 0xd7,
+ 0xae, 0x60, 0x2c, 0x62, 0xb3, 0xe6, 0xe0, 0x2c, 0x8f, 0xe5, 0x02, 0x85,
+ 0x72, 0xe7, 0xe0, 0x2b, 0xab, 0x62, 0x61, 0xeb, 0xe0, 0x23, 0x4c, 0x64,
+ 0x6f, 0xe6, 0x02, 0x8d, 0x74, 0x68, 0x65, 0x69, 0x6e, 0x74, 0x65, 0x72,
+ 0x6e, 0xe5, 0xe0, 0x24, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65,
+ 0x74, 0xae, 0x60, 0x2a, 0xef, 0xc2, 0xac, 0xe3, 0x02, 0x84, 0xf2, 0xe0,
+ 0x2c, 0x3f, 0x6f, 0x72, 0x65, 0x61, 0xf0, 0xe0, 0x23, 0xc9, 0xe1, 0xe0,
+ 0x24, 0xd0, 0x2d, 0x72, 0x6f, 0xef, 0xe0, 0x29, 0xca, 0xed, 0x07, 0x40,
+ 0xaa, 0x0b, 0x0d, 0x10, 0x93, 0xf2, 0x06, 0x07, 0x0a, 0xe0, 0x2b, 0x7c,
+ 0x73, 0x74, 0x75, 0x64, 0x69, 0xef, 0x90, 0x6e, 0x6f, 0x74, 0x65, 0x62,
+ 0x6f, 0x6f, 0x6b, 0xf3, 0x86, 0x61, 0x70, 0x70, 0x75, 0x69, 0x2d, 0x70,
+ 0x72, 0x6f, 0x64, 0xae, 0x06, 0x16, 0x05, 0x08, 0x12, 0x99, 0x75, 0x73,
+ 0xad, 0x05, 0x05, 0xe0, 0x25, 0x7d, 0x77, 0xe5, 0xe0, 0x25, 0x82, 0x67,
+ 0x6f, 0x76, 0xad, 0x40, 0x61, 0xe0, 0x24, 0xf8, 0x73, 0x61, 0xad, 0xc0,
+ 0x59, 0x6d, 0x65, 0xad, 0x40, 0x5b, 0xe0, 0x24, 0xf6, 0x65, 0x75, 0xad,
+ 0x07, 0x03, 0x40, 0x49, 0xe0, 0x24, 0xf6, 0x77, 0xe5, 0xb7, 0x6e, 0x6f,
+ 0xf2, 0xc0, 0x49, 0xe3, 0x02, 0x91, 0x6e, 0x2d, 0x6e, 0x6f, 0x72, 0x74,
+ 0xe8, 0x02, 0x84, 0x77, 0x65, 0x73, 0x74, 0x2d, 0xb1, 0xce, 0x8e, 0x61,
+ 0xad, 0xe0, 0x25, 0x24, 0xe1, 0x02, 0xa6, 0x70, 0xad, 0x03, 0x09, 0x93,
+ 0x73, 0x6f, 0x75, 0x74, 0xe8, 0x09, 0xe0, 0x25, 0x1f, 0x6e, 0x6f, 0x72,
+ 0x74, 0x68, 0x65, 0x61, 0x73, 0x74, 0xad, 0x05, 0x60, 0x25, 0x23, 0x82,
+ 0xb3, 0xe0, 0x25, 0x25, 0x65, 0xe1, 0xe0, 0x24, 0xf8, 0x66, 0x2d, 0x73,
+ 0x6f, 0x75, 0x74, 0xe8, 0xe0, 0x25, 0x05, 0xf0, 0x04, 0xe0, 0x2b, 0x8d,
+ 0x72, 0x65, 0xf3, 0xe0, 0x2a, 0x2c, 0x69, 0x6c, 0x69, 0xe1, 0x02, 0x81,
+ 0x2d, 0x72, 0x6f, 0x6d, 0xe1, 0xd7, 0x7c, 0x65, 0xf2, 0x02, 0x88, 0x67,
+ 0x65, 0x6e, 0x63, 0xf9, 0xe0, 0x29, 0xef, 0xe3, 0xe0, 0x2a, 0x62, 0xe2,
+ 0x05, 0x08, 0xe0, 0x27, 0xff, 0x61, 0x69, 0x78, 0x61, 0x64, 0xe1, 0xcb,
+ 0x43, 0x2e, 0xeb, 0xe0, 0x2a, 0x45, 0x61, 0xe9, 0xe0, 0x2a, 0x61, 0xec,
+ 0x07, 0x04, 0x0f, 0x5a, 0x28, 0xce, 0x69, 0x76, 0xe5, 0xd5, 0x22, 0x65,
+ 0x6d, 0x65, 0x6e, 0x74, 0x6f, 0x72, 0x2e, 0xe3, 0x03, 0xd4, 0xb7, 0xef,
+ 0xc7, 0xac, 0xe2, 0x02, 0x86, 0x6c, 0x61, 0xe7, 0xe0, 0x27, 0xd1, 0xae,
+ 0xcb, 0x51, 0x6b, 0x6c, 0x6f, 0x67, 0x65, 0x73, 0xae, 0xe0, 0x28, 0x1e,
+ 0xe9, 0x03, 0x07, 0x82, 0x68, 0x65, 0x69, 0x6a, 0xe9, 0xc1, 0xf7, 0xe7,
+ 0xa5, 0xe4, 0x05, 0x5c, 0xc3, 0xce, 0x11, 0xf3, 0x05, 0x05, 0xe0, 0x20,
+ 0xa9, 0x6b, 0xef, 0xe0, 0x25, 0x72, 0x62, 0x65, 0xf2, 0xe0, 0x25, 0x6c,
+ 0xe7, 0x05, 0x07, 0xe0, 0x2c, 0x4b, 0x6f, 0x69, 0x73, 0xed, 0xe0, 0x2b,
+ 0x53, 0x65, 0xf2, 0xd6, 0x0b, 0xe5, 0x07, 0x52, 0x08, 0x4b, 0x44, 0xce,
+ 0xf3, 0x72, 0xef, 0x02, 0x86, 0x2d, 0x73, 0x74, 0x61, 0x67, 0x65, 0x2e,
+ 0xef, 0xdb, 0xc2, 0xe4, 0x07, 0x41, 0x24, 0x07, 0x08, 0x29, 0x85, 0xf5,
+ 0x06, 0x04, 0x09, 0xe0, 0x2c, 0x15, 0x67, 0xe9, 0xd9, 0x34, 0x63, 0x61,
+ 0xf4, 0x03, 0xdf, 0x86, 0xef, 0xd1, 0x26, 0xae, 0x1c, 0x06, 0x09, 0x06,
+ 0x0a, 0x1d, 0x06, 0x10, 0x08, 0x15, 0x0f, 0x12, 0x09, 0x08, 0x10, 0x04,
+ 0x0d, 0x07, 0x0d, 0x11, 0x4a, 0x37, 0x03, 0x3c, 0x40, 0x47, 0xd9, 0x5e,
+ 0xfa, 0x60, 0x29, 0xa5, 0xc0, 0xab, 0xf6, 0x60, 0x20, 0x0e, 0x4a, 0x67,
+ 0x40, 0x42, 0xba, 0xf5, 0x60, 0x29, 0xb1, 0xc0, 0x90, 0xf4, 0x60, 0x29,
+ 0x72, 0x1e, 0x12, 0x40, 0x82, 0x33, 0xb2, 0xf3, 0x13, 0x60, 0x21, 0x6c,
+ 0x46, 0x9d, 0x41, 0x53, 0x1a, 0x03, 0x15, 0x40, 0x79, 0x17, 0x1c, 0x40,
+ 0x51, 0xc1, 0x39, 0xe3, 0x04, 0xe0, 0x2b, 0xc0, 0xef, 0xe0, 0x2b, 0x9e,
+ 0xf2, 0x60, 0x29, 0x52, 0xc1, 0xe1, 0xf0, 0x60, 0x20, 0xcc, 0x48, 0x59,
+ 0x27, 0x03, 0x17, 0x18, 0x40, 0x79, 0x17, 0x2b, 0x23, 0x9f, 0xee, 0x60,
+ 0x29, 0x8c, 0x40, 0xc0, 0xc1, 0x58, 0xed, 0x60, 0x24, 0x1b, 0x43, 0xc6,
+ 0x41, 0x49, 0x03, 0x07, 0x03, 0x17, 0x18, 0x40, 0x79, 0x33, 0x0f, 0x40,
+ 0x42, 0xc1, 0x39, 0xec, 0x5f, 0xa5, 0x41, 0x8a, 0x46, 0x9d, 0x41, 0x53,
+ 0x03, 0x2f, 0x40, 0x90, 0xc0, 0x4e, 0xeb, 0x0e, 0x60, 0x28, 0xf8, 0x03,
+ 0x1e, 0x1b, 0x1e, 0x40, 0x7c, 0x40, 0x63, 0xc1, 0x39, 0xf2, 0xdf, 0x35,
+ 0xe9, 0x4b, 0x1f, 0x5d, 0xdf, 0x40, 0xab, 0xc0, 0x84, 0xe8, 0x60, 0x28,
+ 0xf8, 0x40, 0xa8, 0xc0, 0x84, 0xe7, 0x60, 0x28, 0xc6, 0x40, 0x41, 0x03,
+ 0x15, 0x1e, 0x40, 0x5b, 0x21, 0x21, 0x23, 0x1f, 0xba, 0xe6, 0xe0, 0x28,
+ 0xf4, 0xe5, 0x5f, 0x5f, 0x45, 0x86, 0x43, 0xf4, 0x40, 0xab, 0x40, 0x42,
+ 0xc1, 0x7b, 0xe4, 0x60, 0x28, 0xc2, 0x21, 0xc0, 0xc7, 0xe3, 0x60, 0x27,
+ 0x72, 0x41, 0x4c, 0x40, 0x57, 0x40, 0x8e, 0x40, 0x51, 0xba, 0xe2, 0x60,
+ 0x20, 0xc8, 0x47, 0xc9, 0x1d, 0x0a, 0x17, 0x12, 0x27, 0x40, 0x5b, 0x17,
+ 0x1c, 0x32, 0x9f, 0xe1, 0x5f, 0x2d, 0x40, 0xfa, 0x48, 0x76, 0x24, 0x40,
+ 0xf6, 0xc0, 0x59, 0x6f, 0x67, 0x61, 0xf7, 0xe0, 0x24, 0xf6, 0x69, 0x74,
+ 0x6f, 0x72, 0xf8, 0xe0, 0x29, 0xf1, 0x67, 0xe5, 0x04, 0x0f, 0x08, 0x88,
+ 0xf3, 0x02, 0x86, 0x75, 0x69, 0xf4, 0xe0, 0x25, 0x19, 0x74, 0x61, 0x63,
+ 0xeb, 0xd4, 0xde, 0x6b, 0x65, 0xf9, 0x60, 0x25, 0x11, 0xc5, 0xa9, 0x63,
+ 0x6f, 0x6d, 0x70, 0x75, 0xf4, 0xd5, 0x4e, 0x61, 0xf0, 0xde, 0xa6, 0x65,
+ 0xeb, 0xe0, 0x29, 0x24, 0xae, 0x06, 0x06, 0x59, 0x03, 0xd0, 0x0d, 0xe3,
+ 0x60, 0x28, 0xa7, 0xc0, 0xc0, 0xe1, 0xe0, 0x29, 0x2f, 0xe3, 0x06, 0x2b,
+ 0x04, 0xe0, 0x2a, 0x81, 0xef, 0x07, 0x0a, 0x0c, 0x06, 0xe0, 0x2a, 0x8c,
+ 0x6e, 0xef, 0x04, 0xe0, 0x20, 0x21, 0xed, 0xe0, 0x27, 0xe7, 0x6d, 0x6d,
+ 0x65, 0x72, 0x63, 0x65, 0x2d, 0x73, 0x68, 0xef, 0xd8, 0xf1, 0x6c, 0x6f,
+ 0xe7, 0xe0, 0x27, 0xd5, 0x2e, 0xe2, 0x60, 0x28, 0x4a, 0xc0, 0xe7, 0xee,
+ 0xe0, 0x29, 0x29, 0x68, 0x69, 0x7a, 0x65, 0x6e, 0x2e, 0x66, 0x75, 0x6b,
+ 0xf5, 0xe0, 0x28, 0x6a, 0xe2, 0x04, 0xe0, 0x25, 0xb7, 0xe9, 0x02, 0x84,
+ 0x7a, 0xae, 0xcc, 0x15, 0xee, 0x04, 0xe0, 0x25, 0x9f, 0xef, 0xdc, 0x32,
+ 0xe1, 0x03, 0x17, 0xa8, 0xf4, 0x05, 0x05, 0xe0, 0x2a, 0x51, 0x6f, 0xee,
+ 0xe0, 0x21, 0x94, 0x69, 0x6e, 0x67, 0x2d, 0x6f, 0x72, 0x67, 0x61, 0xee,
+ 0xe0, 0x26, 0xe0, 0xf3, 0x02, 0x8b, 0x79, 0x70, 0x61, 0x6e, 0x65, 0x6c,
+ 0xae, 0x4c, 0x86, 0xdc, 0x40, 0xf4, 0x03, 0x05, 0x86, 0x75, 0x73, 0xb2,
+ 0xcf, 0xc4, 0x61, 0x73, 0x69, 0xe1, 0xcf, 0xbe, 0x2d, 0x6b, 0x61, 0x7a,
+ 0x61, 0x6b, 0x68, 0x73, 0xf4, 0xdb, 0xd2, 0x72, 0xf4, 0xe0, 0x27, 0x8b,
+ 0xb4, 0xc6, 0xf9, 0xb1, 0x02, 0x88, 0x36, 0x34, 0x2e, 0x61, 0xf2, 0xe0,
+ 0x28, 0x17, 0x32, 0xae, 0xdf, 0x1b, 0xae, 0x58, 0x9f, 0xd1, 0x64, 0xe4,
+ 0x22, 0x06, 0x40, 0xeb, 0x0a, 0x12, 0x1e, 0x04, 0x1b, 0x40, 0x50, 0x03,
+ 0x40, 0x74, 0x40, 0x57, 0x09, 0x05, 0x40, 0xeb, 0x11, 0x06, 0x06, 0x41,
+ 0x7c, 0x38, 0x05, 0x40, 0xce, 0x60, 0x21, 0x66, 0x21, 0x92, 0x1f, 0x43,
+ 0x78, 0xee, 0xdf, 0x0f, 0xf9, 0x05, 0x5c, 0x0a, 0xcd, 0x6e, 0xee, 0x0b,
+ 0x08, 0x04, 0x07, 0x40, 0x68, 0x1d, 0x05, 0x1e, 0xc0, 0xb2, 0xf6, 0x03,
+ 0xc0, 0xbd, 0xb6, 0xe0, 0x29, 0x9d, 0xf5, 0xe0, 0x29, 0x99, 0x73, 0x65,
+ 0x72, 0xf6, 0xe0, 0x26, 0xe6, 0x64, 0x6e, 0xf3, 0x03, 0x03, 0x98, 0xb1,
+ 0xc6, 0x77, 0xae, 0x0b, 0x4b, 0xf7, 0x4b, 0x7b, 0x41, 0xfb, 0x4d, 0x0c,
+ 0xc0, 0x56, 0xe4, 0x03, 0xc0, 0x84, 0x61, 0x70, 0x70, 0x6e, 0x6f, 0xe4,
+ 0xdf, 0xf6, 0xad, 0x0e, 0x09, 0x07, 0x06, 0x08, 0x06, 0x05, 0x09, 0x42,
+ 0x0e, 0x42, 0x83, 0xc0, 0x9a, 0xf7, 0x04, 0x2a, 0xc4, 0xf3, 0x69, 0xeb,
+ 0xdf, 0x98, 0x72, 0x65, 0x6d, 0xef, 0xe0, 0x21, 0xca, 0x70, 0x69, 0xe3,
+ 0xe0, 0x28, 0x54, 0x6f, 0x66, 0x66, 0x69, 0xe3, 0xe0, 0x21, 0xbd, 0x6d,
+ 0x61, 0xe9, 0xe0, 0x22, 0x8b, 0x62, 0x6c, 0xef, 0xdb, 0xe4, 0x61, 0x74,
+ 0xad, 0x02, 0x84, 0x77, 0xef, 0xd2, 0x93, 0x68, 0x6f, 0xed, 0xe0, 0x21,
+ 0xa3, 0xe1, 0x04, 0x06, 0xc1, 0xb2, 0x74, 0x68, 0xef, 0xe0, 0x25, 0xd2,
+ 0x6d, 0xe9, 0x02, 0x87, 0x73, 0x63, 0x68, 0x65, 0xf3, 0xc4, 0x85, 0x63,
+ 0x2d, 0x64, 0x6e, 0xf3, 0xd8, 0xfe, 0x35, 0xb3, 0xe0, 0x28, 0x24, 0xae,
+ 0x03, 0x0e, 0x86, 0x68, 0x6f, 0x6d, 0x65, 0x2d, 0x77, 0x65, 0x62, 0x73,
+ 0x65, 0x72, 0xf6, 0xc5, 0xe2, 0x64, 0x64, 0x6e, 0xf3, 0xc4, 0x64, 0x63,
+ 0x6f, 0x73, 0xe9, 0xc4, 0x5c, 0xad, 0x04, 0x03, 0x08, 0x86, 0x76, 0xf0,
+ 0x94, 0x6f, 0x2d, 0x73, 0x61, 0xf5, 0xe0, 0x28, 0x18, 0x69, 0x70, 0x32,
+ 0xb4, 0xc5, 0xc2, 0x62, 0x65, 0x72, 0x6c, 0x69, 0xee, 0xc5, 0xba, 0x77,
+ 0x65, 0x62, 0x2e, 0x6c, 0x69, 0xee, 0xe0, 0x22, 0x64, 0xf6, 0x02, 0x8b,
+ 0xf2, 0x05, 0x20, 0xe0, 0x28, 0xba, 0x63, 0x61, 0xed, 0xd8, 0xa5, 0xe1,
+ 0xe0, 0x28, 0xd3, 0xf5, 0x05, 0x05, 0x04, 0x06, 0x86, 0x72, 0xe2, 0xe0,
+ 0x24, 0x8a, 0x70, 0xef, 0xc1, 0xca, 0x6e, 0x6c, 0xef, 0xe0, 0x27, 0x22,
+ 0x63, 0x6b, 0x64, 0xee, 0xd3, 0xd9, 0xe2, 0xcd, 0x20, 0xf4, 0xe0, 0x24,
+ 0xf6, 0xf3, 0x03, 0x03, 0x85, 0xf4, 0xdf, 0xea, 0x6d, 0x79, 0xee, 0xc1,
+ 0x19, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0xae, 0x04, 0xe0, 0x25, 0x74, 0xed,
+ 0x58, 0x30, 0xd0, 0x03, 0xf2, 0x08, 0x04, 0x07, 0x06, 0x05, 0x03, 0x0c,
+ 0x9b, 0x1f, 0x43, 0xf8, 0x8f, 0x75, 0x64, 0xae, 0x4a, 0x6b, 0xdd, 0x12,
+ 0x72, 0x2e, 0xe1, 0xe0, 0x28, 0x6e, 0x6f, 0x62, 0xe1, 0xdd, 0xe7, 0xe9,
+ 0xdd, 0x87, 0x65, 0x61, 0x6d, 0x68, 0x6f, 0x73, 0x74, 0x65, 0xf2, 0xe0,
+ 0x27, 0x4d, 0xe1, 0x03, 0x0d, 0x86, 0xf9, 0x03, 0xc3, 0xac, 0xe4, 0x03,
+ 0xc3, 0xaa, 0x64, 0xee, 0xe0, 0x27, 0x3c, 0x6e, 0x67, 0xe5, 0xe0, 0x21,
+ 0x36, 0x6d, 0xed, 0xd8, 0xd1, 0xae, 0x5a, 0x90, 0x49, 0xd3, 0xc2, 0xac,
+ 0xf0, 0xcd, 0x3b, 0xef, 0x10, 0x08, 0x05, 0x06, 0x06, 0x06, 0x20, 0x03,
+ 0x06, 0x12, 0x60, 0x26, 0x18, 0x41, 0xbd, 0x81, 0x77, 0x6e, 0x6c, 0x6f,
+ 0xe1, 0xe0, 0x25, 0xdf, 0x76, 0xf2, 0xe0, 0x26, 0x90, 0x73, 0x68, 0x69,
+ 0xae, 0xcb, 0xd9, 0x70, 0x61, 0xe1, 0xe0, 0x26, 0xfe, 0x6f, 0x6d, 0x64,
+ 0x6e, 0xf3, 0xb6, 0xee, 0x05, 0x08, 0x0e, 0xdd, 0x2a, 0x74, 0x65, 0x78,
+ 0x69, 0x73, 0xf4, 0xd4, 0x47, 0xe7, 0x02, 0x86, 0x74, 0x68, 0x61, 0xf0,
+ 0xdf, 0x50, 0x6e, 0x61, 0xe9, 0xdf, 0x4b, 0x65, 0xf4, 0xc0, 0x79, 0xed,
+ 0xd7, 0xea, 0x6a, 0x69, 0xee, 0xe0, 0x27, 0xe3, 0x65, 0xf3, 0x03, 0xd1,
+ 0xad, 0x6e, 0x74, 0x65, 0x78, 0x69, 0x73, 0x74, 0xae, 0x60, 0x25, 0x0c,
+ 0xc2, 0xc8, 0xe3, 0x04, 0xe0, 0x25, 0x68, 0xf4, 0xe0, 0x24, 0x9f, 0xee,
+ 0x07, 0x3c, 0x05, 0x4c, 0x7c, 0xd9, 0x6b, 0xf3, 0x07, 0x0e, 0x07, 0x08,
+ 0x06, 0x05, 0x86, 0x75, 0xf0, 0x04, 0xe0, 0x27, 0x93, 0x64, 0x61, 0x74,
+ 0xe5, 0x44, 0x7d, 0xd3, 0x04, 0x6b, 0x69, 0x6e, 0xe7, 0xe0, 0x20, 0xe9,
+ 0x69, 0x73, 0x6b, 0x69, 0x6e, 0xeb, 0xca, 0x10, 0x68, 0x6f, 0x6d, 0xe5,
+ 0xc4, 0x67, 0x66, 0x6f, 0xf2, 0xd1, 0x92, 0x64, 0x6f, 0x6a, 0xef, 0xd3,
+ 0xd3, 0x61, 0x6c, 0x69, 0xe1, 0xd3, 0xcc, 0xe9, 0x05, 0xe0, 0x21, 0xde,
+ 0x65, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x74, 0x72, 0x6f, 0x76, 0x73, 0xeb,
+ 0xcc, 0x70, 0x6c, 0x75, 0x67, 0x6f, 0x6c, 0x65, 0xeb, 0xd8, 0x8b, 0xeb,
+ 0x4d, 0x35, 0xda, 0x37, 0xe9, 0x0c, 0x11, 0x0b, 0x40, 0x58, 0x1e, 0x0f,
+ 0x1a, 0x17, 0xe0, 0x24, 0x52, 0x76, 0xf4, 0x02, 0x85, 0x74, 0x61, 0xf3,
+ 0xd8, 0x09, 0x61, 0x73, 0x76, 0x75, 0x6f, 0xe4, 0xdc, 0x81, 0x74, 0x63,
+ 0x68, 0x79, 0x6f, 0x75, 0x72, 0xe9, 0xe0, 0x26, 0x57, 0xf3, 0x05, 0x21,
+ 0xe0, 0x24, 0x88, 0xeb, 0x02, 0x90, 0x75, 0x73, 0x73, 0x69, 0x6f, 0x6e,
+ 0x73, 0x62, 0x65, 0x72, 0x65, 0x69, 0x63, 0xe8, 0xc3, 0xf3, 0x73, 0x74,
+ 0x61, 0x74, 0x69, 0x6f, 0x6e, 0xae, 0x51, 0x1a, 0x50, 0xeb, 0xc2, 0x4a,
+ 0x63, 0xef, 0x03, 0x03, 0x9a, 0xf6, 0xd3, 0x72, 0xf5, 0x02, 0x93, 0x72,
+ 0x73, 0x65, 0xae, 0x02, 0x86, 0x74, 0x65, 0xe1, 0xe0, 0x26, 0xff, 0x67,
+ 0x72, 0x6f, 0xf5, 0xe0, 0x26, 0x04, 0xee, 0xe0, 0x25, 0x3b, 0x72, 0x64,
+ 0xf3, 0x02, 0x85, 0x65, 0xfa, 0xe0, 0x26, 0xe7, 0x61, 0xf9, 0xe0, 0x25,
+ 0xce, 0x72, 0x65, 0x63, 0xf4, 0x05, 0x03, 0xe0, 0x26, 0xdb, 0xef, 0xc4,
+ 0xd9, 0x2e, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x63, 0x6f, 0x6e, 0x6e, 0x65,
+ 0x63, 0x74, 0xae, 0x48, 0x43, 0xdd, 0x46, 0x68, 0x65, 0x72, 0x2e, 0x73,
+ 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0xee, 0xe0, 0x23, 0x2a, 0x67, 0xe9,
+ 0x02, 0x93, 0x74, 0x61, 0xec, 0x04, 0xe0, 0x26, 0xaf, 0x6f, 0x63, 0x65,
+ 0x61, 0x6e, 0x73, 0x70, 0x61, 0x63, 0xe5, 0xdd, 0x76, 0xe3, 0xd7, 0xaf,
+ 0xe5, 0x05, 0x06, 0xe0, 0x24, 0xd6, 0x6e, 0x62, 0x69, 0xe5, 0xd7, 0x92,
+ 0x6c, 0x64, 0x64, 0x61, 0x6e, 0x75, 0x6f, 0x72, 0xf2, 0xde, 0xf2, 0xe1,
+ 0x02, 0x85, 0x6d, 0x6f, 0xee, 0xcd, 0x9e, 0x64, 0xe5, 0xce, 0x9e, 0xe8,
+ 0x04, 0xe0, 0x24, 0x29, 0x2e, 0x62, 0x79, 0x74, 0x65, 0x6d, 0x61, 0x72,
+ 0xeb, 0xe0, 0x23, 0x1d, 0x67, 0x63, 0xe1, 0xe0, 0x23, 0x8c, 0x66, 0xae,
+ 0x60, 0x20, 0x00, 0x83, 0xe5, 0x12, 0x40, 0x6d, 0x0b, 0x16, 0x0c, 0x1b,
+ 0x31, 0x27, 0x05, 0x10, 0x0f, 0x08, 0x05, 0x0e, 0xe0, 0x25, 0x01, 0xf6,
+ 0x08, 0x14, 0x13, 0x0d, 0x23, 0xe0, 0x25, 0xed, 0x69, 0x63, 0x65, 0x73,
+ 0x2e, 0x72, 0x65, 0x73, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x67, 0x69, 0x6e,
+ 0xe7, 0xe0, 0x25, 0x2b, 0x65, 0x6c, 0x6f, 0xf0, 0x02, 0x89, 0x6d, 0x65,
+ 0x6e, 0x74, 0x2e, 0x72, 0xf5, 0xd1, 0xdd, 0x65, 0xf2, 0xd4, 0x72, 0x63,
+ 0x64, 0x6e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0xef, 0xe0, 0x25, 0xfd,
+ 0xae, 0x06, 0x0c, 0x52, 0x4a, 0xd2, 0x59, 0x73, 0x74, 0x61, 0x74, 0x69,
+ 0x63, 0x2e, 0x6c, 0x61, 0xee, 0xd9, 0xca, 0x61, 0x64, 0x6f, 0x62, 0x65,
+ 0x61, 0x65, 0x6d, 0x63, 0x6c, 0x6f, 0x75, 0xe4, 0xe0, 0x25, 0xda, 0xad,
+ 0x03, 0xdf, 0x16, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0xf2, 0xcf, 0x2f,
+ 0xf4, 0x04, 0xe0, 0x24, 0x80, 0x61, 0xae, 0x58, 0x3e, 0xcc, 0x26, 0xf3,
+ 0x05, 0x0c, 0xe0, 0x24, 0x68, 0xe9, 0x04, 0xe0, 0x25, 0xca, 0x67, 0xee,
+ 0x60, 0x22, 0xeb, 0xc2, 0xdd, 0x61, 0xae, 0xdd, 0x27, 0xf0, 0x04, 0xe0,
+ 0x24, 0x25, 0x6f, 0x72, 0x74, 0xe5, 0xe0, 0x22, 0xfe, 0xee, 0x02, 0x8a,
+ 0xf4, 0x02, 0x83, 0xe9, 0xd8, 0xd4, 0xe1, 0xe0, 0x23, 0x5a, 0xef, 0x03,
+ 0xd8, 0x06, 0x2d, 0x73, 0x74, 0x61, 0x67, 0x69, 0x6e, 0xe7, 0xd7, 0xfe,
+ 0x6d, 0xef, 0x04, 0x07, 0xc8, 0xfd, 0x63, 0x72, 0xe1, 0x49, 0x24, 0xda,
+ 0xad, 0xae, 0x02, 0x8b, 0x6a, 0x65, 0x6c, 0x61, 0x73, 0x74, 0x69, 0xe3,
+ 0xe0, 0x25, 0x78, 0x64, 0x61, 0x74, 0xe1, 0x02, 0x87, 0x64, 0x65, 0x74,
+ 0x65, 0xe3, 0xdb, 0x62, 0x63, 0x65, 0x6e, 0x74, 0x65, 0xf2, 0xe0, 0x25,
+ 0x10, 0xec, 0x06, 0x05, 0x11, 0x05, 0xd8, 0xf9, 0x6f, 0x69, 0xf4, 0xde,
+ 0xa6, 0xec, 0x05, 0x01, 0xe0, 0x25, 0x54, 0x2d, 0x6f, 0x67, 0x6c, 0x69,
+ 0x61, 0x73, 0x74, 0xf2, 0xde, 0xbd, 0x69, 0x76, 0xe5, 0xc3, 0x43, 0x68,
+ 0xe9, 0xe0, 0x24, 0x07, 0x67, 0xf2, 0xe0, 0x20, 0x60, 0xe6, 0x04, 0xe0,
+ 0x23, 0xdb, 0x69, 0x6e, 0x69, 0x6d, 0x61, 0xae, 0x60, 0x24, 0x29, 0xc0,
+ 0xe4, 0xe4, 0x02, 0x85, 0x79, 0xee, 0xe0, 0x24, 0x1e, 0x69, 0x62, 0x6f,
+ 0xf8, 0xe0, 0x24, 0x8d, 0xe3, 0x03, 0xd5, 0x67, 0xe9, 0xe0, 0x24, 0x1c,
+ 0x62, 0x69, 0xe1, 0xd1, 0x87, 0xe1, 0x02, 0x84, 0x74, 0xee, 0xde, 0x99,
+ 0xec, 0x51, 0x67, 0x51, 0x37, 0xc2, 0x69, 0xae, 0x0b, 0x03, 0x04, 0x51,
+ 0x41, 0x47, 0x77, 0x45, 0xd8, 0xc1, 0x5a, 0xf4, 0xca, 0x37, 0xec, 0xe0,
+ 0x24, 0x82, 0x63, 0xef, 0x04, 0xe0, 0x24, 0xe3, 0xef, 0xe0, 0x24, 0x34,
+ 0xe4, 0x05, 0x2c, 0xe0, 0x22, 0x49, 0x6e, 0xf3, 0x07, 0x07, 0x05, 0x03,
+ 0x06, 0x05, 0x84, 0x73, 0xae, 0x60, 0x22, 0x04, 0xc2, 0x2f, 0x6c, 0x69,
+ 0xf6, 0xdd, 0x20, 0xeb, 0xd7, 0x4e, 0x67, 0x65, 0xe5, 0xe0, 0x20, 0xcf,
+ 0x66, 0x72, 0xe5, 0xdd, 0x12, 0xb5, 0xe0, 0x24, 0xb2, 0xae, 0x4e, 0xb2,
+ 0xd5, 0xe1, 0x2d, 0x64, 0x6e, 0xf3, 0xc1, 0x79, 0xe3, 0x58, 0xd9, 0xc6,
+ 0x2d, 0xe1, 0x10, 0x07, 0x0b, 0x16, 0x38, 0x09, 0x05, 0x08, 0x0b, 0x16,
+ 0x09, 0x18, 0x54, 0x2d, 0xcd, 0x65, 0x7a, 0x61, 0x69, 0x66, 0xf5, 0xcd,
+ 0x7e, 0xf9, 0x04, 0xe0, 0x24, 0x8a, 0x6e, 0x69, 0x67, 0xe8, 0xcd, 0x84,
+ 0x76, 0x76, 0xe5, 0x02, 0x86, 0x73, 0x69, 0x69, 0xe4, 0xde, 0x53, 0x6e,
+ 0xea, 0x02, 0x82, 0x1f, 0x43, 0x61, 0x72, 0xe7, 0xde, 0x48, 0xf4, 0x06,
+ 0x17, 0x05, 0x0a, 0xce, 0xbf, 0x74, 0xef, 0x03, 0x04, 0x86, 0x77, 0xe5,
+ 0xda, 0xcd, 0x72, 0x65, 0x6c, 0xe1, 0xc6, 0xc8, 0x6c, 0x6f, 0x63, 0x61,
+ 0xec, 0xe0, 0x20, 0xf7, 0x73, 0xf5, 0xe0, 0x23, 0x14, 0xe5, 0x04, 0xe0,
+ 0x24, 0x46, 0xae, 0x5e, 0xda, 0xc3, 0xb7, 0xe1, 0x04, 0xe0, 0x24, 0x3c,
+ 0x62, 0x61, 0x73, 0xe5, 0xcd, 0x8c, 0xf0, 0x03, 0xcc, 0xe2, 0x6c, 0x69,
+ 0xe5, 0xce, 0x2a, 0xee, 0x5b, 0x7d, 0xc3, 0xa0, 0x6d, 0x6e, 0x73, 0x65,
+ 0x72, 0xf6, 0xda, 0x4b, 0xeb, 0x02, 0x83, 0xee, 0xd1, 0x68, 0x6c, 0x61,
+ 0xeb, 0xdb, 0x6b, 0xe9, 0x04, 0x04, 0x04, 0x86, 0x77, 0xe1, 0xd8, 0xb9,
+ 0xf4, 0xe0, 0x22, 0x35, 0x73, 0x65, 0x6e, 0xae, 0xdd, 0xf0, 0xe7, 0xd4,
+ 0x3b, 0x67, 0x65, 0x73, 0x74, 0x61, 0xee, 0xe0, 0x20, 0x58, 0xe5, 0x03,
+ 0x0b, 0x85, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x61, 0x6e, 0x65, 0xec, 0xc0,
+ 0x72, 0x6a, 0x65, 0xef, 0xcc, 0xf2, 0x67, 0xf5, 0xcc, 0xef, 0x62, 0xf5,
+ 0xe0, 0x22, 0x83, 0xae, 0x05, 0x52, 0x6d, 0xd1, 0x64, 0x67, 0xf6, 0xe0,
+ 0x23, 0xc0, 0xe3, 0x26, 0x12, 0x23, 0x08, 0x05, 0x40, 0xa7, 0x06, 0x16,
+ 0x40, 0x6e, 0x03, 0x04, 0x43, 0x56, 0x40, 0x69, 0x41, 0x6a, 0x05, 0x40,
+ 0x9a, 0x41, 0xb5, 0x0e, 0x3f, 0x2f, 0x40, 0xb0, 0x0d, 0x41, 0xad, 0x04,
+ 0x55, 0x56, 0x1e, 0xc2, 0x51, 0xfa, 0x05, 0x51, 0x52, 0xd2, 0x4f, 0xe5,
+ 0x02, 0x84, 0x73, 0xf4, 0xde, 0xe1, 0x6c, 0x61, 0xe4, 0xcc, 0x6f, 0xf9,
+ 0x07, 0x10, 0x05, 0x49, 0x41, 0xda, 0x37, 0xef, 0x04, 0xe0, 0x22, 0x88,
+ 0x6e, 0xae, 0x03, 0xcc, 0x52, 0x6c, 0x69, 0xee, 0xe0, 0x23, 0x48, 0x6d,
+ 0xf2, 0xe0, 0x22, 0x7b, 0x61, 0x2e, 0xe7, 0xe0, 0x20, 0xa8, 0xf8, 0x04,
+ 0xe0, 0x23, 0x6d, 0xae, 0xd0, 0x3d, 0xf6, 0x48, 0x61, 0xdb, 0x08, 0xf5,
+ 0x0a, 0x09, 0x40, 0x6a, 0x0a, 0x0a, 0x05, 0xe0, 0x22, 0xce, 0x74, 0x65,
+ 0x67, 0x69, 0x72, 0xec, 0xe0, 0x22, 0x59, 0x73, 0xf4, 0x02, 0xb3, 0x6f,
+ 0xed, 0x02, 0x9f, 0x65, 0xf2, 0x02, 0x94, 0xae, 0x03, 0xca, 0x7b, 0x73,
+ 0x70, 0x65, 0x65, 0x64, 0x70, 0x61, 0x72, 0x74, 0x6e, 0x65, 0x72, 0xae,
+ 0xe0, 0x22, 0x94, 0x2d, 0x6f, 0x63, 0xe9, 0xe0, 0x23, 0x17, 0x2e, 0x6d,
+ 0x65, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x75, 0x6d, 0x2e, 0xe3,
+ 0xdf, 0xf9, 0xae, 0x04, 0x08, 0x0b, 0x85, 0x74, 0x65, 0x73, 0x74, 0x69,
+ 0x6e, 0xe7, 0x9c, 0x72, 0x65, 0x74, 0x72, 0x6f, 0x73, 0x6e, 0x75, 0xe2,
+ 0xdf, 0xb2, 0x70, 0x72, 0x6f, 0xe4, 0x8c, 0xe4, 0x02, 0x86, 0x69, 0x73,
+ 0x72, 0x65, 0xe3, 0x83, 0x65, 0x76, 0x2e, 0x74, 0x68, 0x69, 0x6e, 0x67,
+ 0x64, 0x75, 0xf3, 0xcf, 0xfd, 0xf2, 0x02, 0x83, 0xf6, 0xd5, 0x47, 0x69,
+ 0x74, 0xe9, 0x9d, 0x70, 0x63, 0x61, 0x6b, 0x65, 0x2e, 0xe9, 0xe0, 0x22,
+ 0x67, 0x6e, 0xe5, 0xe0, 0x20, 0xcd, 0xe9, 0x02, 0x89, 0x73, 0x69, 0x6e,
+ 0x65, 0x6c, 0xec, 0xe0, 0x21, 0x1e, 0x61, 0xe2, 0xd9, 0x44, 0x74, 0xae,
+ 0x5d, 0xb8, 0xc3, 0x02, 0xf3, 0x02, 0x86, 0x78, 0x2e, 0xe3, 0xe0, 0x22,
+ 0xa3, 0xae, 0x03, 0xca, 0xd2, 0x6b, 0x65, 0x6c, 0x69, 0x77, 0x65, 0xe2,
+ 0xca, 0xc4, 0xf2, 0x0d, 0x10, 0x09, 0x09, 0x12, 0x16, 0x11, 0x49, 0x35,
+ 0x56, 0x9b, 0xc2, 0x69, 0x79, 0x70, 0x74, 0x6f, 0x6e, 0x6f, 0x6d, 0x69,
+ 0x63, 0x2e, 0x6e, 0x65, 0xf4, 0xe0, 0x22, 0x75, 0x75, 0x69, 0x73, 0xe5,
+ 0x60, 0x20, 0x17, 0xc2, 0x69, 0xef, 0x03, 0xc9, 0xd2, 0x74, 0x6f, 0xee,
+ 0xdb, 0x6c, 0xe9, 0x03, 0x05, 0x84, 0x6d, 0x65, 0xe1, 0xc7, 0x63, 0x63,
+ 0xeb, 0xcf, 0x61, 0xae, 0x5b, 0xb4, 0xc5, 0x56, 0xe5, 0x03, 0x03, 0x83,
+ 0xf7, 0xdf, 0x7e, 0xed, 0xda, 0x10, 0x64, 0x69, 0xf4, 0x05, 0x52, 0x5f,
+ 0xcf, 0xef, 0x75, 0xee, 0xd5, 0xba, 0xe1, 0x04, 0x04, 0xd3, 0x39, 0x6e,
+ 0xeb, 0xd9, 0x90, 0x66, 0x74, 0x69, 0x6e, 0x67, 0xae, 0xce, 0x76, 0xae,
+ 0x47, 0x31, 0xd9, 0x05, 0xf1, 0xce, 0xc4, 0xf0, 0xe0, 0x20, 0x9e, 0xef,
+ 0x14, 0x29, 0x06, 0x06, 0x04, 0x3b, 0x40, 0x4c, 0x41, 0x72, 0x17, 0x03,
+ 0x04, 0x17, 0x06, 0x03, 0x4d, 0x4d, 0xd2, 0x5b, 0xf5, 0x04, 0x04, 0x07,
+ 0x8b, 0x72, 0xf3, 0xd6, 0x1a, 0x70, 0x6f, 0xee, 0x5f, 0xa3, 0xc2, 0x69,
+ 0xee, 0x02, 0x84, 0x74, 0xf2, 0xdf, 0xcc, 0x63, 0xe9, 0xdd, 0x0f, 0x63,
+ 0x68, 0x70, 0x6f, 0x74, 0x61, 0x74, 0x6f, 0x66, 0x72, 0x69, 0xe5, 0xcd,
+ 0x12, 0x73, 0x65, 0x6e, 0xfa, 0xdb, 0x5c, 0x72, 0x73, 0xe9, 0xe0, 0x20,
+ 0x3e, 0x70, 0xf2, 0xde, 0x91, 0xef, 0x03, 0x28, 0x8c, 0xf0, 0x05, 0x08,
+ 0xe0, 0x21, 0xcd, 0x65, 0x72, 0x61, 0x74, 0x69, 0xf6, 0xdf, 0x16, 0xae,
+ 0x0e, 0x03, 0x03, 0x4f, 0xa7, 0x46, 0x47, 0x48, 0x48, 0x41, 0xc3, 0x40,
+ 0x65, 0x9f, 0xf2, 0xdf, 0x4d, 0xf0, 0xdf, 0x83, 0xed, 0x5d, 0xfb, 0xc1,
+ 0x4c, 0xec, 0x04, 0xe0, 0x21, 0xae, 0x62, 0x6c, 0x6f, 0xe7, 0xe0, 0x20,
+ 0xaf, 0xeb, 0xcc, 0x24, 0xee, 0x05, 0x17, 0x19, 0x03, 0x8f, 0xf4, 0x02,
+ 0x8b, 0xf2, 0x03, 0xdc, 0xa6, 0x61, 0x63, 0x74, 0x6f, 0xf2, 0xdf, 0x29,
+ 0xe1, 0x02, 0x83, 0xe7, 0xcf, 0xce, 0xe3, 0xdf, 0xcb, 0xf3, 0x02, 0x91,
+ 0x75, 0xec, 0x02, 0x87, 0xf4, 0x03, 0xc8, 0x39, 0xe1, 0xd9, 0xbf, 0x61,
+ 0x64, 0x6f, 0xae, 0xd4, 0x9d, 0x74, 0x72, 0xf5, 0xd4, 0xdc, 0xee, 0xde,
+ 0x1e, 0xe6, 0x02, 0x85, 0x65, 0x72, 0xe5, 0xdc, 0x81, 0xae, 0x55, 0xa3,
+ 0x48, 0xa6, 0xc2, 0xb3, 0x64, 0xef, 0xde, 0xf1, 0xed, 0x09, 0x04, 0x2f,
+ 0x21, 0x04, 0x5e, 0xf2, 0xc2, 0x04, 0x73, 0xe5, 0xd5, 0x69, 0xf0, 0x02,
+ 0xa5, 0x75, 0x74, 0xe5, 0x04, 0x1a, 0xdf, 0xcd, 0xae, 0x02, 0x86, 0x65,
+ 0x73, 0x74, 0xe1, 0xc3, 0x58, 0x61, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x61,
+ 0x77, 0x73, 0x2e, 0x63, 0x6f, 0xed, 0x42, 0xb8, 0xde, 0x60, 0x2d, 0xb1,
+ 0xd7, 0xec, 0xe1, 0x03, 0xde, 0x57, 0xee, 0xde, 0xe6, 0xed, 0x02, 0x99,
+ 0x75, 0xee, 0x02, 0x91, 0x69, 0x74, 0xf9, 0x04, 0xe0, 0x21, 0x0d, 0x2d,
+ 0x70, 0x72, 0x6f, 0xae, 0x60, 0x20, 0x68, 0xc0, 0x7d, 0x65, 0xae, 0xd9,
+ 0x79, 0x62, 0x61, 0xee, 0xde, 0x96, 0x63, 0xe1, 0xd4, 0x20, 0xae, 0x1b,
+ 0x03, 0x03, 0x0a, 0x08, 0x0a, 0x17, 0x06, 0x03, 0x0e, 0x0b, 0x12, 0x0e,
+ 0x0b, 0x03, 0x0d, 0x08, 0x0e, 0x06, 0x0b, 0x08, 0x0d, 0x11, 0x4c, 0xc1,
+ 0xcc, 0x40, 0xf9, 0xdf, 0x5d, 0xf7, 0xde, 0x6d, 0xf6, 0x54, 0xf0, 0x49,
+ 0xca, 0x40, 0x9d, 0x40, 0x42, 0xba, 0xf5, 0x5e, 0x56, 0x3c, 0x40, 0x90,
+ 0xc1, 0xa6, 0xf4, 0x5e, 0x51, 0x1e, 0x12, 0x40, 0x82, 0x33, 0x32, 0x9f,
+ 0xf3, 0x54, 0xd4, 0x41, 0x8a, 0x46, 0x9d, 0x41, 0x2c, 0x27, 0x1a, 0x03,
+ 0x15, 0x40, 0x79, 0x17, 0x1c, 0x40, 0x51, 0x40, 0xd5, 0xc0, 0x64, 0xf2,
+ 0x5f, 0x15, 0x0f, 0xc0, 0xf4, 0xf1, 0xde, 0xf3, 0xf0, 0x55, 0xae, 0x48,
+ 0x59, 0x27, 0x03, 0x17, 0x18, 0x40, 0x79, 0x17, 0x2b, 0xa3, 0xee, 0x55,
+ 0xa0, 0x48, 0xd0, 0x40, 0x72, 0x40, 0x4e, 0xc1, 0x58, 0xed, 0x58, 0xfc,
+ 0x43, 0xc6, 0x41, 0x4c, 0x07, 0x03, 0x17, 0x18, 0x40, 0x79, 0x33, 0x40,
+ 0x8b, 0xc0, 0xff, 0xec, 0x54, 0x89, 0x41, 0x8a, 0x46, 0x9d, 0x41, 0x56,
+ 0x2f, 0x40, 0x90, 0xc0, 0x4e, 0xeb, 0x5d, 0xeb, 0x03, 0x1e, 0x1b, 0x1e,
+ 0x40, 0x7c, 0xc1, 0x9c, 0xea, 0xde, 0xc8, 0xe9, 0x08, 0x5d, 0xdf, 0x17,
+ 0x40, 0xc7, 0xc0, 0x51, 0xf1, 0xe0, 0x20, 0x47, 0xe8, 0x5d, 0xdd, 0x40,
+ 0xa8, 0x40, 0x65, 0x9f, 0xe7, 0x5d, 0xab, 0x40, 0x41, 0x18, 0x1e, 0x40,
+ 0x5b, 0x21, 0x21, 0x23, 0x1f, 0xba, 0xe6, 0x5d, 0xdb, 0x12, 0xc0, 0xe7,
+ 0xe5, 0x54, 0x44, 0x49, 0x7a, 0x40, 0xab, 0x40, 0x42, 0xc1, 0x7b, 0xe4,
+ 0x5d, 0xa9, 0x21, 0x40, 0xc7, 0xc1, 0x26, 0xe3, 0x5c, 0x58, 0x41, 0x4c,
+ 0x1e, 0x1b, 0x1e, 0x40, 0x8e, 0x40, 0x51, 0xba, 0xe2, 0x55, 0xae, 0x47,
+ 0xc9, 0x1d, 0x0a, 0x17, 0x12, 0x09, 0x1e, 0x40, 0x5b, 0x17, 0x1c, 0x32,
+ 0x9f, 0xe1, 0x54, 0x13, 0x40, 0xfa, 0x48, 0x76, 0x03, 0x1e, 0x03, 0x36,
+ 0x40, 0xc0, 0x40, 0x59, 0xc0, 0xff, 0xec, 0x03, 0x04, 0x8c, 0x6f, 0xe7,
+ 0xc9, 0xc2, 0x6c, 0x65, 0x67, 0xe5, 0x03, 0xdf, 0xd7, 0x66, 0x61, 0xee,
+ 0xdd, 0x04, 0xae, 0xcb, 0xc2, 0xe7, 0xd7, 0x0e, 0x66, 0xe6, 0xda, 0xec,
+ 0x64, 0xe5, 0x04, 0x07, 0xc9, 0x0f, 0xf3, 0x03, 0xdf, 0xbe, 0xf0, 0xd5,
+ 0x9c, 0x62, 0x65, 0x72, 0x67, 0x2e, 0x70, 0x61, 0xe7, 0xdf, 0x4e, 0x63,
+ 0x6f, 0x74, 0xf4, 0xd0, 0xc0, 0xe1, 0xca, 0x0d, 0xae, 0x1a, 0x05, 0x09,
+ 0x12, 0x05, 0x06, 0x0e, 0x0d, 0x0b, 0x05, 0x09, 0x04, 0x0a, 0x06, 0x09,
+ 0x12, 0x0d, 0x12, 0x57, 0xea, 0x44, 0x56, 0x41, 0x9f, 0xc0, 0xc8, 0xf6,
+ 0x5d, 0x73, 0xc0, 0x9d, 0xf5, 0x4f, 0x3c, 0x4d, 0xd8, 0x0a, 0x03, 0xc2,
+ 0x65, 0xf4, 0x08, 0x5c, 0xe6, 0x1d, 0x21, 0x12, 0xc0, 0x82, 0x65, 0x63,
+ 0x68, 0x6e, 0x6f, 0x6c, 0xef, 0xcd, 0xfe, 0xf3, 0x5c, 0xf9, 0xc0, 0xb5,
+ 0xf2, 0x5c, 0xf7, 0x07, 0xc2, 0x2e, 0xf0, 0x05, 0x5c, 0xec, 0xc1, 0x36,
+ 0xec, 0x03, 0xdf, 0x54, 0x61, 0xe3, 0xde, 0xf1, 0xee, 0x54, 0x51, 0x48,
+ 0x8f, 0x40, 0x5a, 0x40, 0x72, 0x40, 0xf4, 0xc0, 0x78, 0xed, 0x5c, 0xd3,
+ 0x03, 0x40, 0xc9, 0x2b, 0x40, 0x7c, 0xc0, 0xff, 0xec, 0x53, 0x58, 0xc9,
+ 0x7a, 0xeb, 0x03, 0xdd, 0xb7, 0xf2, 0x52, 0xfd, 0xcc, 0x35, 0xea, 0x5d,
+ 0x90, 0xa1, 0xe9, 0x5c, 0xd7, 0x03, 0x03, 0x40, 0x8e, 0x40, 0x65, 0x9f,
+ 0xe7, 0x5c, 0xd0, 0x18, 0xc2, 0x36, 0x66, 0x69, 0x6e, 0x61, 0x6e, 0x63,
+ 0xe9, 0xc1, 0x52, 0xe5, 0x02, 0x86, 0x76, 0x65, 0x6e, 0xf4, 0xde, 0x9b,
+ 0x64, 0x75, 0x63, 0x61, 0x74, 0x69, 0xef, 0xca, 0xbb, 0xe3, 0x4e, 0xb3,
+ 0x4d, 0x28, 0x40, 0xd1, 0x03, 0x36, 0x40, 0xc0, 0xc1, 0x53, 0xe2, 0x09,
+ 0x4a, 0xa2, 0x49, 0xed, 0x47, 0xe9, 0x30, 0xa7, 0x75, 0x73, 0x69, 0x6e,
+ 0x65, 0xf3, 0xde, 0x73, 0xe1, 0x5c, 0x8d, 0x40, 0x94, 0x33, 0x0f, 0xc1,
+ 0x7b, 0xee, 0x08, 0x03, 0x0a, 0x07, 0x03, 0x0b, 0xde, 0xac, 0xf4, 0xdd,
+ 0x72, 0x73, 0x2e, 0x6a, 0x6f, 0x79, 0x65, 0x6e, 0xf4, 0xde, 0xad, 0x70,
+ 0x79, 0x2e, 0x67, 0xe4, 0xca, 0x76, 0xe7, 0xdd, 0x5e, 0xae, 0x43, 0xaf,
+ 0x43, 0x2e, 0x44, 0x26, 0x4d, 0x55, 0xc6, 0x57, 0x2d, 0x6e, 0x6f, 0x72,
+ 0x74, 0xe8, 0x02, 0x84, 0x77, 0x65, 0x73, 0x74, 0x2d, 0x31, 0xae, 0x02,
+ 0x94, 0x65, 0x62, 0x2e, 0x61, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x61, 0x77,
+ 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0xe3, 0xca, 0x43, 0x61, 0x69, 0x72,
+ 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x61, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x61,
+ 0x77, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0xe3, 0xc7, 0xc7, 0xec, 0x0a,
+ 0x11, 0x41, 0x12, 0x13, 0x1c, 0x5b, 0x0e, 0xc2, 0x03, 0x75, 0xe2, 0x04,
+ 0x04, 0xde, 0x59, 0x6d, 0xe5, 0xdc, 0x0f, 0xae, 0x03, 0xdb, 0x79, 0xf4,
+ 0xdb, 0xe4, 0xef, 0x03, 0xc1, 0x0a, 0x75, 0xe4, 0x0e, 0x09, 0x0e, 0x23,
+ 0x06, 0x17, 0x0a, 0x0d, 0x20, 0x0c, 0x40, 0x52, 0xdd, 0x52, 0x79, 0x63,
+ 0x6c, 0x75, 0x73, 0x74, 0xe5, 0xc3, 0x59, 0x73, 0x69, 0x74, 0x65, 0x2e,
+ 0x62, 0x75, 0x69, 0x6c, 0x64, 0x65, 0xf2, 0xdd, 0xba, 0x6e, 0x73, 0xae,
+ 0x0b, 0x03, 0x05, 0x03, 0x05, 0x58, 0xf0, 0x41, 0xf4, 0xc0, 0x56, 0xf5,
+ 0xdd, 0xa9, 0xf0, 0x49, 0x98, 0xc4, 0x05, 0xe9, 0xcd, 0xb7, 0xe3, 0x4d,
+ 0xbd, 0xd0, 0x41, 0x61, 0x73, 0xe9, 0xcd, 0xbb, 0x6a, 0x69, 0x66, 0xe6,
+ 0xdc, 0x99, 0xe6, 0x03, 0x08, 0x85, 0x75, 0x6e, 0x63, 0x74, 0x69, 0xef,
+ 0xd8, 0x48, 0x72, 0x6f, 0xee, 0xd1, 0x9b, 0x6c, 0x61, 0x72, 0xe5, 0xc3,
+ 0x41, 0x65, 0x72, 0x61, 0x2e, 0x73, 0x69, 0x74, 0xe5, 0xdd, 0xcd, 0x63,
+ 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0xec, 0x03, 0xdc, 0xe6, 0xec, 0xd3, 0xc9,
+ 0xe1, 0x02, 0x8f, 0x70, 0xf0, 0x03, 0xdd, 0xa4, 0x73, 0x2e, 0x64, 0x69,
+ 0x67, 0x69, 0x74, 0xe1, 0xdd, 0x0d, 0x63, 0x63, 0x65, 0x73, 0x73, 0xae,
+ 0x03, 0xdd, 0x92, 0x68, 0x6f, 0xf3, 0xdd, 0x91, 0x36, 0x36, 0xae, 0x02,
+ 0x84, 0x7a, 0xef, 0xcd, 0x3b, 0xf7, 0xdd, 0x37, 0xae, 0x07, 0x0d, 0x10,
+ 0x13, 0x15, 0xd3, 0x8c, 0x6e, 0x6f, 0x73, 0x70, 0x61, 0x6d, 0x70, 0x72,
+ 0x6f, 0x78, 0xf9, 0xdd, 0x89, 0x6d, 0x65, 0x74, 0x61, 0x63, 0x65, 0x6e,
+ 0x74, 0x72, 0x75, 0x6d, 0x2e, 0x63, 0xfa, 0xdd, 0x6f, 0x6a, 0x65, 0x6c,
+ 0x61, 0x73, 0x74, 0x69, 0x63, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x2e, 0x74,
+ 0x69, 0xed, 0xdd, 0x23, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x68, 0x6f, 0x73,
+ 0x74, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0xae, 0xdc,
+ 0xaf, 0x67, 0x6f, 0xef, 0xda, 0x87, 0x2d, 0x66, 0x72, 0x31, 0x2e, 0x75,
+ 0x6e, 0x69, 0x73, 0x70, 0x61, 0xe3, 0xd3, 0xa8, 0x74, 0xe8, 0xc7, 0xc0,
+ 0xe9, 0x02, 0x86, 0x6e, 0xe9, 0x47, 0x88, 0xc9, 0xd0, 0x63, 0xeb, 0x03,
+ 0xdd, 0x32, 0x72, 0x69, 0xf3, 0xd7, 0x67, 0xe5, 0x03, 0x09, 0x8b, 0x76,
+ 0x65, 0x72, 0x61, 0x70, 0x70, 0xf3, 0xdc, 0x1a, 0x72, 0xeb, 0x03, 0xdb,
+ 0xa5, 0x73, 0x74, 0x61, 0xe7, 0xc7, 0x92, 0x61, 0xee, 0xc7, 0x91, 0xe1,
+ 0x02, 0x86, 0x6e, 0x2e, 0x72, 0xe9, 0xdc, 0x11, 0x69, 0xed, 0xda, 0x9d,
+ 0xeb, 0x41, 0xfb, 0xc9, 0xa5, 0xe9, 0x0e, 0x08, 0x40, 0x54, 0x15, 0x04,
+ 0x07, 0x0c, 0x59, 0x10, 0x41, 0x55, 0xc2, 0x03, 0x76, 0x69, 0x6c, 0x61,
+ 0x76, 0xe9, 0xda, 0x08, 0xf4, 0x04, 0x40, 0x46, 0x85, 0xf9, 0x03, 0xdc,
+ 0xdf, 0xae, 0x06, 0x08, 0x0f, 0x07, 0xdb, 0xb9, 0x79, 0x6f, 0x6b, 0x6f,
+ 0x68, 0x61, 0xed, 0x95, 0xf3, 0x02, 0x85, 0x65, 0x6e, 0x64, 0xe1, 0xa7,
+ 0x61, 0x70, 0x70, 0x6f, 0x72, 0xef, 0xa1, 0x6e, 0x61, 0x67, 0x6f, 0x79,
+ 0xe1, 0x9a, 0xeb, 0x03, 0x04, 0x8a, 0x6f, 0x62, 0xe5, 0x92, 0x69, 0x74,
+ 0x61, 0x6b, 0x79, 0x75, 0x73, 0x68, 0xf5, 0x88, 0x61, 0x77, 0x61, 0x73,
+ 0x61, 0x6b, 0x69, 0x2e, 0x6a, 0x70, 0x85, 0xe9, 0x50, 0xb9, 0xcb, 0xe3,
+ 0x61, 0xe4, 0xd7, 0x64, 0xf3, 0x02, 0x87, 0x74, 0x72, 0x6f, 0x6e, 0xae,
+ 0xdb, 0xd8, 0x63, 0xef, 0x03, 0xdc, 0x85, 0x66, 0x72, 0x65, 0xe1, 0xd8,
+ 0x8d, 0x72, 0xe3, 0xda, 0x8a, 0x70, 0x72, 0x69, 0x61, 0xee, 0xda, 0x5d,
+ 0xe5, 0x02, 0x85, 0x73, 0x7a, 0xf9, 0xca, 0xd2, 0x6e, 0xe3, 0xd9, 0xb0,
+ 0xe1, 0xc3, 0xb4, 0xe8, 0x0b, 0x2a, 0x0a, 0x0d, 0x1f, 0x40, 0xcd, 0x2e,
+ 0x37, 0xda, 0xc7, 0xf5, 0x05, 0x03, 0x13, 0xdb, 0x42, 0xf2, 0xc6, 0xb5,
+ 0x6f, 0xae, 0x08, 0x50, 0xb8, 0x48, 0x48, 0x41, 0x69, 0x89, 0x79, 0x61,
+ 0x6d, 0x61, 0x6e, 0x61, 0xf3, 0xda, 0x31, 0x6e, 0xe7, 0x02, 0x85, 0x6e,
+ 0x61, 0xed, 0xc5, 0x45, 0x62, 0x75, 0xeb, 0xc5, 0x40, 0x74, 0x72, 0x2e,
+ 0x6b, 0x31, 0x32, 0x2e, 0xed, 0xc2, 0x8b, 0xf2, 0x02, 0x84, 0x6f, 0xed,
+ 0xda, 0xa4, 0x69, 0x73, 0x74, 0xed, 0xc7, 0x25, 0xef, 0x05, 0x03, 0x04,
+ 0x09, 0x85, 0xf9, 0xd1, 0x99, 0x77, 0xe4, 0xc9, 0x16, 0xf3, 0x02, 0x82,
+ 0xe8, 0x82, 0x65, 0xe9, 0xda, 0x26, 0x6e, 0x61, 0xee, 0xda, 0x21, 0x66,
+ 0xf5, 0xd8, 0xb4, 0xe9, 0x10, 0x09, 0x09, 0x0b, 0x27, 0x0a, 0x08, 0x07,
+ 0x06, 0x28, 0x0c, 0x0d, 0x07, 0x03, 0xd9, 0x60, 0x7a, 0x75, 0x2e, 0x74,
+ 0x6f, 0x74, 0xf4, 0xd2, 0xe4, 0x79, 0x6f, 0x64, 0x61, 0xae, 0x53, 0x0f,
+ 0xc5, 0x85, 0xf4, 0x02, 0x85, 0x6f, 0x73, 0xe5, 0xda, 0x1b, 0xe1, 0xd6,
+ 0x84, 0xf2, 0x02, 0x84, 0x79, 0xf5, 0xd6, 0x7d, 0x75, 0x72, 0x67, 0x69,
+ 0x65, 0x6e, 0x73, 0x2d, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x73, 0x74, 0x65,
+ 0xf3, 0x03, 0xdb, 0x1e, 0x2d, 0x65, 0x6e, 0x2d, 0x66, 0x72, 0x61, 0x6e,
+ 0x63, 0xe5, 0xdb, 0x14, 0xf0, 0x02, 0x83, 0xf3, 0xda, 0xa5, 0x70, 0xf5,
+ 0xd6, 0xe3, 0xee, 0x03, 0xcd, 0x39, 0x74, 0xe1, 0xd9, 0x7b, 0x6d, 0x6b,
+ 0x65, 0x6e, 0xf4, 0xd9, 0xa3, 0x6c, 0x6c, 0x6f, 0xf5, 0xc4, 0x85, 0x6b,
+ 0xf5, 0x06, 0x03, 0x0b, 0x04, 0x02, 0x88, 0xfa, 0xc4, 0x67, 0xf3, 0x02,
+ 0x84, 0x68, 0x69, 0xee, 0x94, 0x65, 0xe9, 0xd3, 0xdf, 0x6d, 0xe1, 0xd8,
+ 0x59, 0xea, 0x8a, 0x68, 0xef, 0x03, 0xc4, 0x51, 0xeb, 0xd7, 0x09, 0x67,
+ 0xef, 0xc4, 0x4c, 0x6a, 0x69, 0x77, 0x61, 0x2e, 0x6e, 0x61, 0x67, 0x61,
+ 0xf3, 0xd3, 0xc6, 0x68, 0x61, 0x79, 0x61, 0x61, 0x6b, 0x61, 0x73, 0x61,
+ 0x6b, 0xe1, 0xd9, 0x71, 0x67, 0x61, 0x73, 0x61, 0xeb, 0xce, 0xd0, 0xe5,
+ 0xcf, 0x2e, 0xe3, 0x02, 0x86, 0x68, 0x69, 0x62, 0xf5, 0xcf, 0xf4, 0x61,
+ 0x70, 0xf0, 0xcb, 0x7d, 0xe5, 0x02, 0xa5, 0xf2, 0x02, 0x97, 0xee, 0x02,
0x84, 0x6f, 0x76, 0xf4, 0x96, 0xe9, 0x03, 0x05, 0x83, 0x76, 0x74, 0x73,
0xe9, 0x8f, 0x68, 0xe9, 0x83, 0x67, 0x6f, 0xf6, 0x88, 0x6b, 0x61, 0xf3,
- 0x02, 0x81, 0x73, 0x79, 0x2e, 0xf5, 0xd9, 0xf5, 0x6c, 0x74, 0x65, 0x6e,
- 0x68, 0xe1, 0xd1, 0xae, 0x61, 0xf0, 0x53, 0x49, 0xc8, 0x39, 0xe1, 0x06,
- 0x0c, 0x0b, 0x10, 0xca, 0x47, 0xf4, 0x03, 0xdb, 0x73, 0x74, 0x61, 0x6e,
- 0x6f, 0x6f, 0xe7, 0xd5, 0x4f, 0xf2, 0x02, 0x85, 0x74, 0x65, 0xf2, 0xd8,
- 0x86, 0xe9, 0xca, 0x2d, 0xee, 0x03, 0xd6, 0x4e, 0x6e, 0x65, 0xec, 0x03,
- 0xdb, 0x56, 0x73, 0x64, 0x76, 0xf2, 0xdb, 0x2e, 0xed, 0x02, 0x8a, 0x70,
- 0x69, 0x6f, 0x6e, 0x73, 0x68, 0x69, 0xf0, 0xd8, 0x66, 0x62, 0x61, 0x67,
- 0xf2, 0xc0, 0xa4, 0xae, 0x05, 0x55, 0x2c, 0xc4, 0x10, 0xf4, 0x03, 0xdb,
- 0x24, 0x72, 0x65, 0x6e, 0x64, 0x68, 0x6f, 0x73, 0x74, 0x69, 0x6e, 0xe7,
- 0xc3, 0x07, 0xe6, 0x07, 0x58, 0xd9, 0x40, 0xac, 0xc1, 0x99, 0x2d, 0x69,
- 0x70, 0xe6, 0xda, 0x0d, 0xe5, 0x09, 0x12, 0x11, 0x12, 0x06, 0x4c, 0x67,
- 0xcc, 0xef, 0x73, 0x65, 0x6e, 0xe1, 0x02, 0x81, 0x2d, 0x66, 0x6f, 0x72,
- 0xec, 0x03, 0xd3, 0x12, 0x1f, 0xc3, 0xcb, 0xec, 0xf2, 0x03, 0xd9, 0xcd,
- 0xf4, 0x02, 0x84, 0x6d, 0xe7, 0xc2, 0x66, 0x69, 0x66, 0x69, 0xe3, 0xd8,
- 0x09, 0x6e, 0xf4, 0x02, 0x88, 0x72, 0x61, 0x6c, 0x75, 0x73, 0xae, 0xda,
- 0xae, 0x65, 0xf2, 0x58, 0x24, 0xc2, 0xb9, 0x6c, 0x74, 0x69, 0xe3, 0xd8,
- 0x1c, 0x63, 0x68, 0x69, 0xf2, 0xd3, 0x4b, 0xe4, 0x05, 0x4e, 0x1f, 0xcc,
- 0xa8, 0xee, 0x03, 0x08, 0x95, 0x37, 0x37, 0x2d, 0x73, 0x73, 0xec, 0xda,
- 0x99, 0x2e, 0x70, 0x72, 0x6f, 0x64, 0x2e, 0x61, 0x74, 0x6c, 0x61, 0x73,
- 0x73, 0x69, 0x61, 0x6e, 0x2d, 0x64, 0x65, 0xf6, 0xda, 0x84, 0x2d, 0x65,
- 0x64, 0xe7, 0xcc, 0x9d, 0xe3, 0x04, 0x03, 0xda, 0x98, 0xe9, 0xd6, 0xd7,
- 0xae, 0x13, 0x06, 0x06, 0x05, 0x07, 0x04, 0x03, 0x04, 0x05, 0x17, 0x0a,
- 0x02, 0x06, 0x0b, 0x05, 0x06, 0x02, 0x09, 0x8d, 0xf7, 0x32, 0x1b, 0x2e,
- 0xd1, 0xc5, 0xf6, 0x40, 0x6f, 0x06, 0xd1, 0xc5, 0xf5, 0x40, 0x69, 0xca,
- 0x34, 0xf4, 0x03, 0xc0, 0x41, 0xf8, 0xd4, 0xe9, 0xf3, 0x40, 0x40, 0x96,
- 0xf2, 0xd2, 0x24, 0xf0, 0x40, 0x5c, 0x8f, 0xef, 0x18, 0x40, 0x4f, 0x86,
- 0xee, 0x0a, 0x03, 0x03, 0x03, 0x12, 0x0b, 0x13, 0x03, 0xd8, 0x7c, 0xf6,
- 0xd4, 0xcb, 0xed, 0xd4, 0xc8, 0xea, 0xd4, 0xc5, 0xe8, 0xd4, 0xc2, 0xed,
- 0x16, 0x03, 0x13, 0x0a, 0x03, 0x03, 0x0c, 0xd1, 0xb9, 0xec, 0xb2, 0xeb,
- 0x02, 0xba, 0xf9, 0xd4, 0xb0, 0xe9, 0x04, 0x03, 0x23, 0x92, 0xee, 0xd4,
- 0xa8, 0xe4, 0xd4, 0xa5, 0xe8, 0x46, 0x13, 0xcb, 0xd1, 0xe7, 0x02, 0x98,
- 0xf5, 0xd4, 0x9a, 0xe6, 0xa6, 0xe4, 0x02, 0x83, 0xe5, 0xd4, 0x92, 0xe3,
- 0xd4, 0x8f, 0xe3, 0x03, 0x03, 0x83, 0xf4, 0xd4, 0x88, 0xef, 0xd4, 0x85,
- 0xe1, 0xd4, 0x82, 0xe1, 0x05, 0x03, 0x03, 0x03, 0x83, 0xfa, 0xd4, 0x79,
- 0xf3, 0xd4, 0x76, 0xf2, 0xd4, 0x73, 0xec, 0xd4, 0x70, 0xeb, 0xd4, 0x6d,
- 0xe2, 0x0b, 0x57, 0x1b, 0x40, 0x67, 0x40, 0x66, 0x40, 0x63, 0xc0, 0x6e,
- 0xe7, 0xd9, 0x59, 0xe1, 0x14, 0x05, 0x2e, 0x32, 0x40, 0x65, 0x1e, 0x10,
- 0x40, 0x51, 0x26, 0x05, 0x07, 0x07, 0x04, 0x0d, 0x08, 0x1c, 0xd8, 0x15,
- 0x78, 0x69, 0xe1, 0xc1, 0x12, 0xf4, 0x07, 0x0b, 0x05, 0x09, 0x0a, 0xd9,
- 0x9c, 0x68, 0x6f, 0x6c, 0x69, 0xe3, 0x03, 0xd9, 0xb7, 0xae, 0xd6, 0x97,
- 0x66, 0x6f, 0xef, 0xc4, 0x00, 0x65, 0x72, 0x69, 0x6e, 0xe7, 0x56, 0xcb,
- 0xc2, 0xdf, 0x61, 0xee, 0x03, 0xd3, 0x59, 0x7a, 0x61, 0xf2, 0xd7, 0xa1,
- 0xae, 0xc8, 0x8b, 0xf3, 0x06, 0x09, 0x07, 0x07, 0xd7, 0xdd, 0xf4, 0x02,
- 0x83, 0xf2, 0xd2, 0x53, 0xec, 0xd5, 0x45, 0x69, 0x6e, 0xef, 0x58, 0x91,
- 0xc0, 0xf5, 0xe5, 0x03, 0xd9, 0x7e, 0xf2, 0xd1, 0x7f, 0xe1, 0x04, 0x0a,
- 0xd9, 0x6c, 0x64, 0x65, 0x6c, 0x61, 0x6d, 0x6f, 0x6e, 0xe5, 0xc0, 0x97,
- 0x63, 0x61, 0xed, 0xd9, 0x45, 0xf2, 0x0b, 0x06, 0x18, 0x04, 0x0a, 0x03,
- 0x12, 0x56, 0xb8, 0xc2, 0x62, 0x74, 0x6f, 0x6f, 0xee, 0xcd, 0xa3, 0xf2,
- 0x03, 0x03, 0x85, 0xe9, 0xd2, 0x26, 0x64, 0x2e, 0xe3, 0xd9, 0x10, 0x61,
- 0x72, 0xe1, 0x02, 0x81, 0x2d, 0x6d, 0x61, 0x73, 0xf3, 0xd2, 0xf8, 0x67,
- 0xef, 0xd6, 0x5c, 0xe5, 0x03, 0xd9, 0x35, 0x65, 0xf2, 0x56, 0xd1, 0xc2,
- 0x62, 0xe4, 0xd6, 0xcc, 0x62, 0x6f, 0x6e, 0x69, 0xe1, 0x02, 0x81, 0x2d,
- 0x69, 0x67, 0x6c, 0x65, 0x73, 0x69, 0x61, 0xf3, 0xd7, 0x20, 0xe1, 0x02,
- 0x83, 0xf6, 0xd5, 0x07, 0x63, 0x61, 0x6c, 0x2e, 0x6d, 0x79, 0x74, 0x68,
- 0x69, 0x63, 0x2d, 0x62, 0x65, 0x61, 0x73, 0xf4, 0xd7, 0xf7, 0xf0, 0x03,
- 0x04, 0x88, 0x6f, 0xef, 0xd0, 0xc3, 0x69, 0x74, 0x61, 0xec, 0x42, 0xdf,
- 0xd6, 0x17, 0xe5, 0x02, 0x85, 0x74, 0x6f, 0xf7, 0xd7, 0xc1, 0x62, 0x72,
- 0x65, 0xf4, 0xce, 0x33, 0xee, 0x06, 0x05, 0x51, 0xb9, 0xc4, 0x66, 0x64,
- 0x79, 0xf0, 0xca, 0x4d, 0x61, 0xe4, 0xd2, 0xb8, 0xed, 0x08, 0x38, 0x04,
- 0x05, 0x56, 0x8e, 0xc1, 0xfc, 0xf0, 0x05, 0x07, 0x1f, 0xd8, 0x9f, 0x6f,
- 0x62, 0x61, 0x73, 0xf3, 0xd6, 0xc3, 0xe9, 0x02, 0x8f, 0x6e, 0xe1, 0x02,
- 0x83, 0xf3, 0xd7, 0x6a, 0x67, 0x72, 0x61, 0x6e, 0x64, 0xe5, 0xd7, 0x62,
- 0x64, 0x61, 0x6e, 0xef, 0x02, 0x81, 0x2d, 0x6d, 0x65, 0x64, 0xe9, 0xd6,
- 0xa4, 0xe1, 0x02, 0x83, 0xee, 0xd2, 0x53, 0x69, 0x67, 0x6e, 0xae, 0xcf,
- 0x71, 0x65, 0xf2, 0xd6, 0xf8, 0x64, 0x76, 0xf2, 0xd5, 0xba, 0x62, 0x72,
- 0x69, 0x64, 0xe7, 0xd4, 0x3f, 0xec, 0x0a, 0x08, 0x08, 0x07, 0x56, 0x19,
- 0x40, 0x4c, 0xc1, 0xfc, 0x76, 0x69, 0x6e, 0x6b, 0x6c, 0xe5, 0xd7, 0x46,
- 0x74, 0x61, 0x6e, 0x69, 0x73, 0xf3, 0xd0, 0x6a, 0x69, 0x66, 0x6f, 0x72,
- 0xee, 0xcb, 0x67, 0x61, 0xe2, 0xd2, 0x16, 0x68, 0x63, 0xe5, 0xd0, 0x80,
- 0x67, 0x6c, 0x69, 0x61, 0xf2, 0xd0, 0x65, 0xe6, 0x03, 0xd6, 0xdf, 0xea,
- 0xd7, 0x3f, 0x64, 0xe1, 0xd1, 0x0b, 0xe2, 0x03, 0xd8, 0x42, 0x6c, 0x65,
- 0x2d, 0x6d, 0x6f, 0x64, 0xe5, 0xd5, 0x68, 0x61, 0xae, 0x03, 0xd5, 0x56,
- 0xec, 0xd7, 0xdb, 0xae, 0x08, 0x0e, 0x52, 0x0f, 0x41, 0x32, 0xc1, 0x06,
- 0x72, 0x65, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x2e, 0x63, 0x6c, 0x6f, 0xf5,
- 0xcb, 0xd3, 0xe9, 0x56, 0x62, 0xc0, 0x8c, 0x2d, 0x63, 0x65, 0x6e, 0x74,
- 0x72, 0x61, 0xec, 0xcf, 0x1f, 0x36, 0xb6, 0xc2, 0x0f, 0xae, 0x07, 0x43,
- 0x33, 0x43, 0xc3, 0xd1, 0x07, 0x63, 0x64, 0x6e, 0x37, 0xb7, 0xd5, 0x28,
- 0xe2, 0x24, 0x38, 0x17, 0x21, 0x40, 0x98, 0x05, 0x13, 0x40, 0xd6, 0x0c,
- 0x40, 0xfc, 0x15, 0x19, 0x41, 0x52, 0x1b, 0x41, 0x0e, 0x0d, 0x09, 0x41,
- 0x09, 0x08, 0x25, 0x10, 0x42, 0x6a, 0x09, 0x43, 0x93, 0x47, 0x24, 0xc1,
- 0x3d, 0x1f, 0xc3, 0x04, 0x0a, 0x05, 0x91, 0xf8, 0x02, 0x83, 0xed, 0xcf,
- 0xf2, 0xae, 0x42, 0xe5, 0x86, 0x66, 0x72, 0xf5, 0xcc, 0x1f, 0xe5, 0x02,
- 0x83, 0xf4, 0xc7, 0x13, 0x64, 0x1f, 0x43, 0x65, 0x64, 0x64, 0x6a, 0x1f,
- 0xc3, 0xd6, 0x27, 0xe1, 0x05, 0x03, 0x06, 0xc8, 0xbe, 0xec, 0xc5, 0x42,
- 0x69, 0x64, 0x1f, 0xc3, 0xc8, 0xc9, 0xe8, 0xc8, 0xcd, 0xfa, 0x07, 0x55,
- 0x97, 0x40, 0x5e, 0xc1, 0x9e, 0x7a, 0x2e, 0x64, 0x61, 0x70, 0x70, 0x73,
- 0x2e, 0x65, 0x61, 0x72, 0x74, 0xe8, 0xd7, 0x74, 0xf9, 0x07, 0x04, 0x03,
- 0x03, 0x06, 0xd7, 0x6c, 0x74, 0xef, 0xca, 0xf6, 0xeb, 0xc8, 0x35, 0xe7,
- 0xca, 0xa4, 0x65, 0x6e, 0x2e, 0xf3, 0xc7, 0x5c, 0x64, 0x67, 0x6f, 0x73,
- 0x7a, 0x63, 0xfa, 0xd2, 0xd5, 0xf5, 0x0c, 0x09, 0x0e, 0x03, 0x18, 0x07,
- 0x18, 0x04, 0x06, 0x2b, 0xd5, 0x49, 0xfa, 0x03, 0xd4, 0xe6, 0x65, 0x6e,
- 0xae, 0xcb, 0xcc, 0xf9, 0x03, 0xd7, 0x49, 0x73, 0x68, 0xef, 0x03, 0xc8,
- 0xb7, 0x75, 0xf3, 0xc9, 0x3c, 0xf4, 0xcf, 0x05, 0xf3, 0x05, 0x09, 0x03,
- 0xd4, 0x71, 0x69, 0x6e, 0x65, 0x73, 0xf3, 0x56, 0x04, 0xc1, 0x2d, 0xe8,
- 0xc5, 0x82, 0x61, 0x6e, 0x2e, 0xeb, 0xd5, 0xdc, 0x72, 0x67, 0x68, 0x6f,
- 0xe6, 0xd4, 0x66, 0xee, 0x02, 0x84, 0x6b, 0xf9, 0xd1, 0x65, 0x67, 0xef,
- 0x02, 0x88, 0x74, 0x61, 0x6b, 0x61, 0x64, 0xe1, 0xc5, 0x78, 0x6f, 0x6e,
- 0xef, 0xc5, 0x73, 0x6c, 0xf3, 0xc7, 0xdb, 0x6b, 0x68, 0x61, 0xf2, 0xd5,
- 0x19, 0x69, 0xec, 0x02, 0x8a, 0x74, 0x77, 0x69, 0x74, 0x68, 0x64, 0x61,
- 0xf2, 0xce, 0x25, 0xe4, 0x05, 0x05, 0x0c, 0xd6, 0xd6, 0x69, 0x6e, 0xe7,
- 0xd4, 0x2b, 0x65, 0xf2, 0x03, 0xd4, 0x7b, 0x2e, 0x63, 0x6f, 0x64, 0xe5,
- 0xd6, 0xc2, 0x2e, 0x72, 0x75, 0xee, 0xd6, 0xc0, 0x64, 0x65, 0xea, 0xd0,
- 0xa8, 0xf4, 0x54, 0xce, 0xc1, 0xfc, 0xf3, 0x06, 0x09, 0x54, 0xba, 0xc1,
- 0xfc, 0x73, 0x2e, 0x64, 0x65, 0x73, 0x69, 0xe7, 0xc2, 0xa4, 0xe2, 0xd5,
- 0x69, 0xf2, 0x0a, 0x0a, 0x09, 0x21, 0x39, 0x28, 0x0d, 0x24, 0xd5, 0xe2,
- 0x1f, 0x43, 0x78, 0x6e, 0x6e, 0x1f, 0x43, 0xf8, 0xc0, 0x49, 0xf9, 0x02,
- 0x83, 0xee, 0xd5, 0x12, 0xe1, 0xd0, 0xaa, 0xf5, 0x04, 0x06, 0x0c, 0x84,
- 0x78, 0x65, 0x6c, 0xec, 0xcf, 0x51, 0x73, 0x73, 0x65, 0xec, 0x03, 0xd3,
- 0xca, 0xf3, 0x53, 0xc9, 0xc2, 0xb9, 0x6e, 0xe5, 0xcc, 0x58, 0x6d, 0x75,
- 0x6e, 0xe4, 0xcf, 0x9a, 0xef, 0x05, 0x10, 0x04, 0x0a, 0x89, 0x77, 0x73,
- 0x65, 0x72, 0x73, 0x61, 0x66, 0x65, 0x74, 0x79, 0x6d, 0x61, 0x72, 0xeb,
- 0xd5, 0x65, 0x74, 0xe8, 0xc2, 0xee, 0x6e, 0x6e, 0x6f, 0xf9, 0x03, 0xd4,
- 0xcc, 0xf3, 0xd0, 0x01, 0x6b, 0xe5, 0x03, 0xc9, 0x24, 0x2d, 0xe9, 0xc9,
- 0xe1, 0x61, 0xe4, 0x02, 0x83, 0xf7, 0xcf, 0xd9, 0x63, 0x61, 0xf3, 0xce,
- 0xfa, 0xe9, 0x04, 0x0f, 0x05, 0x86, 0x74, 0x69, 0x73, 0xe8, 0x03, 0xd3,
- 0x76, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0xe2, 0xc9, 0x2d, 0x73, 0x74, 0xef,
- 0xcc, 0x00, 0x6e, 0x64, 0x69, 0xf3, 0xce, 0x30, 0x64, 0x67, 0x65, 0x73,
- 0x74, 0x6f, 0xee, 0xd4, 0xa7, 0xe5, 0x02, 0x84, 0x73, 0xe3, 0xcf, 0xc6,
- 0x6d, 0x61, 0x6e, 0xe7, 0xca, 0x6a, 0xe1, 0x03, 0x0c, 0x8f, 0x73, 0x69,
- 0xec, 0x03, 0xd3, 0x43, 0x69, 0x61, 0x2e, 0xed, 0xd5, 0x93, 0x6e, 0xe4,
- 0x03, 0xc4, 0xe7, 0x79, 0x77, 0x69, 0x6e, 0x65, 0x76, 0x61, 0xec, 0xc4,
- 0x3e, 0x64, 0x65, 0xf3, 0xcb, 0xd4, 0xae, 0x53, 0xe6, 0xc1, 0xf4, 0x70,
- 0x6c, 0x61, 0x63, 0x65, 0x64, 0xae, 0x55, 0x36, 0x40, 0x7d, 0x9c, 0xef,
- 0x12, 0x04, 0x0c, 0x09, 0x15, 0x19, 0x0f, 0x1c, 0x05, 0x05, 0x3b, 0x03,
- 0x03, 0x08, 0x09, 0x0a, 0xd4, 0xe6, 0x7a, 0xe5, 0xc6, 0x95, 0xf9, 0x03,
- 0xcd, 0x7d, 0x66, 0x72, 0x69, 0x65, 0x6e, 0xe4, 0xcd, 0x77, 0xf8, 0x03,
- 0xd5, 0xaa, 0x66, 0x75, 0xf3, 0xcc, 0x75, 0xf5, 0x02, 0x89, 0x74, 0xe9,
- 0x03, 0xcc, 0x32, 0x71, 0xf5, 0xd4, 0x2d, 0xee, 0x03, 0xce, 0xf8, 0x63,
- 0x65, 0xed, 0xc7, 0xa4, 0xf4, 0x03, 0xd5, 0x8c, 0x61, 0xee, 0x03, 0xcd,
- 0x14, 0x69, 0xe3, 0x02, 0x85, 0x61, 0xec, 0x03, 0xd2, 0xc5, 0x67, 0x61,
- 0x72, 0x64, 0xe5, 0xca, 0xdc, 0xf3, 0x02, 0x89, 0xf4, 0x02, 0x83, 0xef,
- 0xc3, 0xb2, 0xe9, 0xd3, 0x0e, 0xe3, 0xd3, 0xcc, 0xef, 0x06, 0x04, 0x4d,
- 0x24, 0xc8, 0x39, 0x6d, 0xec, 0xce, 0x7f, 0xeb, 0x04, 0x08, 0xd5, 0x50,
- 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0xe5, 0xd3, 0xea, 0x69, 0xee, 0xd5, 0x4d,
- 0xee, 0x4a, 0xae, 0xc8, 0x58, 0xed, 0x4d, 0x6f, 0xc7, 0xd7, 0xec, 0x06,
- 0x0e, 0x03, 0x04, 0x04, 0x8a, 0x7a, 0x61, 0x6e, 0xef, 0x03, 0xd3, 0x38,
- 0x2d, 0x61, 0x6c, 0x74, 0xef, 0xce, 0x63, 0xf4, 0xd4, 0x37, 0x6f, 0xe7,
- 0xcd, 0x57, 0x69, 0xf6, 0xd2, 0x73, 0x65, 0x73, 0x6c, 0x61, 0x77, 0x69,
- 0x65, 0xe3, 0xd0, 0x8a, 0x64, 0x6c, 0x79, 0x67, 0x6f, 0x69, 0x6e, 0x67,
- 0x6e, 0x6f, 0x77, 0x68, 0x65, 0x72, 0xe5, 0xd2, 0x37, 0xeb, 0xcf, 0x23,
- 0xe6, 0xd3, 0x6a, 0x65, 0x68, 0x72, 0x69, 0x6e, 0xe7, 0xc1, 0x8d, 0xe4,
- 0x03, 0xcd, 0x1f, 0x1f, 0x43, 0xf8, 0xd3, 0x6b, 0xe1, 0x03, 0xcb, 0xd5,
- 0x76, 0x69, 0x73, 0xf4, 0xcb, 0xd8, 0xae, 0x04, 0x06, 0xd2, 0xe0, 0x74,
- 0x65, 0x6c, 0xe5, 0xca, 0x93, 0x6e, 0x6f, 0x72, 0xe4, 0xc8, 0x07, 0xee,
- 0x06, 0x05, 0x52, 0xcd, 0xc1, 0xfc, 0x72, 0x2e, 0xec, 0xc4, 0xf1, 0x70,
- 0x70, 0x61, 0x72, 0x69, 0x62, 0xe1, 0xd2, 0x60, 0xed, 0x07, 0x0e, 0x52,
- 0x41, 0x07, 0xc2, 0x62, 0x6f, 0x61, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d,
- 0x65, 0x6e, 0x74, 0xf3, 0xd1, 0xda, 0xe4, 0xd3, 0x5d, 0xec, 0x06, 0x10,
- 0x41, 0x25, 0xd1, 0x6f, 0xf5, 0x02, 0x84, 0x73, 0xe8, 0xcc, 0x62, 0xe5,
- 0x03, 0xd4, 0x95, 0x62, 0x69, 0xf4, 0xcb, 0x60, 0xef, 0x05, 0x05, 0x07,
- 0xc1, 0x0a, 0x78, 0x63, 0xed, 0xd3, 0x7a, 0x6f, 0x6d, 0x62, 0x65, 0xf2,
- 0xd4, 0x7f, 0xe7, 0x06, 0x40, 0xe8, 0x09, 0xd3, 0x86, 0xf3, 0x04, 0x03,
- 0xc0, 0xd5, 0xf9, 0xcc, 0xec, 0x70, 0x6f, 0x74, 0xae, 0x16, 0x03, 0x03,
- 0x07, 0x08, 0x06, 0x03, 0x05, 0x05, 0x0a, 0x05, 0x03, 0x0a, 0x06, 0x03,
- 0x04, 0x04, 0x40, 0x54, 0x0b, 0xcb, 0x69, 0xf6, 0xc0, 0x40, 0xf5, 0xd1,
- 0x82, 0xf4, 0x03, 0xc8, 0x02, 0xf7, 0xd4, 0x46, 0xf3, 0x33, 0x51, 0x45,
- 0x42, 0x6a, 0x0d, 0xa0, 0xf2, 0x53, 0xb7, 0x19, 0x0a, 0xaa, 0xf1, 0xc4,
- 0x5f, 0xf0, 0x53, 0xd1, 0xc0, 0x44, 0xee, 0x53, 0x7e, 0xc0, 0x78, 0xed,
- 0x43, 0x19, 0x44, 0xb8, 0x12, 0x4b, 0xb9, 0xc0, 0x58, 0xec, 0x53, 0x9a,
- 0x30, 0xb7, 0xeb, 0xd3, 0x8d, 0xe9, 0x06, 0x53, 0xa5, 0x0a, 0xc0, 0x44,
- 0xee, 0xd4, 0x0f, 0xe8, 0x53, 0x80, 0x08, 0xc0, 0x50, 0xe7, 0xd3, 0x7a,
- 0xe6, 0x53, 0x77, 0xb8, 0xe4, 0x53, 0x9e, 0xad, 0xe3, 0x0c, 0x40, 0xf4,
- 0x41, 0x08, 0x42, 0x1d, 0x4c, 0xb5, 0x42, 0x72, 0x86, 0xef, 0x02, 0xad,
- 0xed, 0x03, 0xd3, 0xe8, 0xae, 0x08, 0x03, 0x03, 0x03, 0x03, 0x06, 0x05,
- 0x85, 0xf5, 0xc2, 0xcf, 0xf4, 0xd3, 0x4f, 0xee, 0xd1, 0x0d, 0xed, 0xd3,
- 0xb8, 0xe5, 0x51, 0x07, 0x42, 0x60, 0x8a, 0xe3, 0x42, 0xbd, 0xd0, 0xd8,
- 0xe2, 0x42, 0xb8, 0xd0, 0x83, 0xe1, 0x53, 0x36, 0x88, 0xae, 0x08, 0x03,
- 0x03, 0x03, 0x50, 0x61, 0xc2, 0xb2, 0xfa, 0xc3, 0xdf, 0xee, 0xd0, 0x91,
- 0xeb, 0xd3, 0x4e, 0xe9, 0x47, 0x67, 0xcb, 0x96, 0xe2, 0x07, 0x43, 0xca,
- 0x4d, 0x0b, 0xc2, 0x6a, 0xea, 0xd3, 0x9f, 0xe1, 0x52, 0xed, 0x40, 0x4e,
- 0xc0, 0x60, 0x69, 0x74, 0x65, 0xae, 0x03, 0xd0, 0xc2, 0x78, 0xf9, 0xd0,
- 0x6c, 0x64, 0x6e, 0x73, 0xae, 0x50, 0xba, 0x42, 0xae, 0x9c, 0xae, 0x04,
- 0x03, 0x03, 0x83, 0xf6, 0xd2, 0xf8, 0xeb, 0xd0, 0xae, 0xe7, 0xd3, 0x59,
- 0xe2, 0x51, 0xfa, 0xb3, 0x63, 0x6b, 0x62, 0x75, 0x73, 0x74, 0xe5, 0xd2,
- 0x23, 0x61, 0x63, 0xeb, 0x04, 0x06, 0xd3, 0x5e, 0x66, 0x72, 0x69, 0xe4,
- 0xcc, 0xf7, 0x62, 0x61, 0x75, 0x64, 0x63, 0x64, 0xee, 0xd3, 0x33, 0xea,
- 0x06, 0x04, 0x06, 0x07, 0xd3, 0x3d, 0x75, 0xe7, 0xcd, 0x69, 0x65, 0x72,
- 0x6b, 0xf2, 0xc6, 0x45, 0x61, 0x72, 0xeb, 0x47, 0x9c, 0xc3, 0x78, 0xae,
- 0xce, 0xba, 0xe9, 0x14, 0x40, 0x5d, 0x18, 0x1a, 0x03, 0x05, 0x09, 0x08,
- 0x03, 0x08, 0x05, 0x1d, 0x12, 0x4f, 0xf9, 0x40, 0x49, 0xc1, 0xfc, 0xfa,
- 0x04, 0x04, 0xd3, 0x1c, 0x65, 0xee, 0xcd, 0x82, 0xae, 0x18, 0x03, 0x04,
- 0x03, 0x07, 0x06, 0x05, 0x06, 0x03, 0x03, 0x05, 0x03, 0x03, 0x03, 0x4b,
- 0x81, 0x43, 0x1b, 0x41, 0x9f, 0x40, 0x58, 0xc2, 0x01, 0xfa, 0xd0, 0xb7,
- 0x77, 0xe6, 0xd2, 0xfa, 0xf5, 0xc3, 0x21, 0xf4, 0x50, 0xbf, 0x40, 0x82,
- 0xc0, 0x6d, 0xf0, 0x50, 0x92, 0x17, 0xc0, 0xfe, 0xee, 0x50, 0xd9, 0xc0,
- 0xc8, 0xed, 0x4f, 0x40, 0x41, 0x3d, 0xb9, 0xec, 0xd0, 0x7e, 0xeb, 0xd0,
- 0xcb, 0xe9, 0x50, 0x95, 0xc1, 0x1a, 0xe7, 0xd2, 0x22, 0xe5, 0xd1, 0x1b,
- 0xe2, 0xc8, 0xda, 0xe1, 0x50, 0x60, 0xc2, 0x4b, 0xf4, 0x02, 0x85, 0x74,
- 0x65, 0xf2, 0xca, 0x89, 0xe2, 0x02, 0x87, 0x75, 0x63, 0x6b, 0x65, 0xf4,
- 0xd1, 0xbd, 0x72, 0x69, 0x64, 0xe7, 0xc4, 0xc4, 0xf2, 0x06, 0x08, 0x03,
- 0x03, 0xd2, 0x11, 0x74, 0x68, 0x70, 0x6c, 0x61, 0xe3, 0xce, 0x5d, 0xeb,
- 0xce, 0x7a, 0xe4, 0xc6, 0xe9, 0x61, 0x74, 0xef, 0xd0, 0xea, 0xf0, 0xc1,
- 0xb1, 0xef, 0x51, 0x46, 0xc1, 0x4c, 0xee, 0x03, 0xcb, 0xae, 0xe7, 0x51,
- 0x0c, 0xc1, 0x7d, 0xec, 0x03, 0xc8, 0x5d, 0x62, 0xe1, 0xc7, 0xd1, 0xeb,
- 0xd1, 0x0e, 0xe8, 0x03, 0xc6, 0xe3, 0x61, 0xf2, 0xd1, 0x47, 0x66, 0x75,
- 0xeb, 0xd0, 0x94, 0xe5, 0x05, 0x08, 0x07, 0xd0, 0xab, 0xf6, 0x02, 0x82,
- 0x1f, 0x43, 0xe1, 0xca, 0xe1, 0x73, 0x7a, 0x63, 0x7a, 0xe1, 0xc0, 0x8e,
- 0xec, 0x03, 0xc8, 0x73, 0x61, 0xf7, 0xc3, 0xe3, 0xe2, 0x03, 0x06, 0x83,
- 0x6c, 0xe5, 0x4f, 0x91, 0xc2, 0xb9, 0xe1, 0xd0, 0x98, 0xae, 0x47, 0x74,
- 0xc9, 0x83, 0x61, 0xec, 0x02, 0x87, 0x79, 0x73, 0x74, 0x6f, 0xeb, 0xcd,
- 0xa5, 0x6f, 0x77, 0x69, 0x65, 0xfa, 0xc3, 0xbf, 0xe8, 0x04, 0x03, 0xd2,
- 0x24, 0xfa, 0xd0, 0xda, 0x61, 0x72, 0xf4, 0xd0, 0x0f, 0xe7, 0x03, 0xd2,
- 0x1b, 0xae, 0x4c, 0x0f, 0xc4, 0x10, 0xe5, 0x0e, 0x2e, 0x11, 0x31, 0x07,
- 0x0b, 0x1a, 0x05, 0x09, 0x14, 0x06, 0x2a, 0xd1, 0x19, 0xf4, 0x05, 0x0d,
- 0x17, 0xd1, 0xdd, 0x74, 0x65, 0x72, 0x2d, 0x74, 0x68, 0x61, 0x6e, 0x2e,
- 0x74, 0xf6, 0xd1, 0xf2, 0xe1, 0x02, 0x87, 0x69, 0x6e, 0x61, 0x62, 0xef,
- 0xc8, 0x5e, 0xae, 0x03, 0xcb, 0x45, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x63,
- 0xe1, 0xc3, 0xf0, 0x2e, 0xe1, 0xd0, 0x91, 0xf3, 0x02, 0x88, 0xf4, 0x03,
- 0xd1, 0xd2, 0x62, 0xf5, 0xcf, 0xa0, 0x6b, 0x69, 0x64, 0xf9, 0xcd, 0x3a,
- 0xf2, 0x05, 0x15, 0x06, 0xc7, 0x0a, 0xec, 0x02, 0x86, 0x69, 0xee, 0x4f,
- 0x04, 0xc2, 0xb9, 0x65, 0xf6, 0x02, 0x85, 0x1f, 0x43, 0xe5, 0xcb, 0x03,
- 0xe1, 0xcb, 0x00, 0x6b, 0x65, 0x6c, 0xe5, 0xc9, 0x36, 0xe7, 0x06, 0x05,
- 0x42, 0x9a, 0xcd, 0x7a, 0x62, 0x61, 0xf5, 0xce, 0xe4, 0x61, 0xed, 0xcf,
- 0x9c, 0x70, 0x70, 0x75, 0x2e, 0xef, 0xcb, 0xd2, 0xee, 0x02, 0x84, 0x74,
- 0xec, 0xc4, 0xf6, 0x65, 0xf6, 0xcd, 0x34, 0xec, 0x05, 0x0b, 0x03, 0xc0,
- 0x9e, 0xec, 0x02, 0x83, 0xf5, 0xc6, 0x23, 0x65, 0x76, 0xf5, 0xcd, 0x30,
- 0xe5, 0xce, 0x19, 0x61, 0x75, 0x2e, 0xf0, 0xcf, 0x04, 0x69, 0x61, 0xf2,
- 0xcb, 0x85, 0x67, 0x65, 0x74, 0x2e, 0x61, 0x70, 0xf0, 0xd1, 0x4d, 0xe5,
- 0x04, 0x04, 0xd0, 0x0a, 0x70, 0xae, 0xc6, 0xc9, 0x6c, 0x64, 0x65, 0x6e,
- 0x67, 0x65, 0x6c, 0x75, 0xe9, 0xcc, 0x61, 0x64, 0x7a, 0x69, 0xee, 0xcc,
- 0xb5, 0xe1, 0x05, 0x0b, 0x10, 0xc8, 0x0b, 0xf5, 0x02, 0x85, 0x78, 0x61,
- 0xf2, 0xc6, 0x5d, 0xf4, 0xcf, 0x04, 0xf2, 0x03, 0xc1, 0x96, 0x61, 0x6c,
- 0xf6, 0x02, 0x82, 0x1f, 0x43, 0x61, 0x68, 0xeb, 0xc9, 0xa8, 0x67, 0x6c,
- 0x65, 0x62, 0x6f, 0x61, 0xf2, 0xc7, 0xe1, 0xae, 0x04, 0x04, 0xcb, 0x05,
- 0x67, 0xf9, 0xd1, 0x0e, 0xe1, 0xc4, 0xb4, 0xe4, 0x02, 0x84, 0x2e, 0xf3,
- 0xcf, 0x9a, 0x86, 0xe3, 0x06, 0x0e, 0x4f, 0xc5, 0xc1, 0x2a, 0x69, 0x2e,
- 0x64, 0x6e, 0x73, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0xf0, 0xc0, 0xeb,
- 0xae, 0x03, 0xcf, 0x52, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d,
- 0x2e, 0xf3, 0xd0, 0x35, 0xe2, 0x08, 0x03, 0x44, 0xec, 0x4a, 0x31, 0xc1,
- 0xb7, 0xf6, 0xcf, 0x3d, 0x73, 0xae, 0xc3, 0x87, 0xe1, 0x14, 0x05, 0x0b,
- 0x0d, 0x3d, 0x40, 0xec, 0x2f, 0x0c, 0x40, 0x5a, 0x04, 0x08, 0x0f, 0x06,
- 0x0e, 0x28, 0x1d, 0xce, 0x6c, 0x79, 0x65, 0xf2, 0xcf, 0x8d, 0xf5, 0x02,
- 0x84, 0x68, 0xe1, 0xcb, 0xd8, 0x65, 0xf2, 0xc6, 0x10, 0xf4, 0x03, 0x03,
- 0x83, 0xf3, 0xc1, 0x7b, 0xef, 0xc5, 0x29, 0xe8, 0xc9, 0x66, 0xf3, 0x06,
- 0x08, 0x11, 0x07, 0xce, 0x7b, 0x6b, 0x65, 0x74, 0x62, 0x61, 0xec, 0xce,
- 0x49, 0xe9, 0x02, 0x86, 0x6c, 0x69, 0x63, 0xe1, 0xc8, 0x8a, 0x63, 0x73,
- 0x65, 0x72, 0x76, 0xe5, 0xc6, 0xeb, 0x68, 0x6b, 0x69, 0x72, 0xe9, 0xcc,
- 0xed, 0xe5, 0x04, 0x08, 0xc6, 0x46, 0x62, 0x61, 0x6c, 0xec, 0x4d, 0xb5,
- 0xc2, 0xb9, 0xae, 0x02, 0x83, 0xf3, 0xc0, 0x58, 0xe5, 0xd0, 0x54, 0xf2,
- 0x12, 0x08, 0x40, 0x72, 0x19, 0x17, 0x06, 0x06, 0x03, 0x17, 0x03, 0x03,
- 0x47, 0x8a, 0x46, 0x6e, 0xc1, 0x80, 0xf5, 0x03, 0xc4, 0xa9, 0x65, 0xf2,
- 0xc8, 0x81, 0x73, 0xf9, 0x03, 0x0d, 0x86, 0x6f, 0x6e, 0x6c, 0x69, 0x6e,
- 0x65, 0x2e, 0x63, 0xef, 0x4c, 0xe7, 0xc3, 0x4c, 0x63, 0x65, 0x6e, 0xf4,
- 0xc6, 0xc4, 0xae, 0x10, 0x13, 0x03, 0x03, 0x0a, 0x0e, 0x08, 0x0d, 0x4a,
- 0xe2, 0x41, 0xa5, 0x42, 0xb0, 0xc0, 0x7d, 0xf3, 0x03, 0x07, 0x84, 0x75,
- 0x70, 0x70, 0x6f, 0xf2, 0xcf, 0xf3, 0x69, 0xf4, 0xcf, 0xab, 0x68, 0xef,
- 0xce, 0xa7, 0xf0, 0x02, 0xa9, 0xf2, 0xcf, 0xcb, 0xef, 0x03, 0xcd, 0x30,
- 0x6e, 0x6c, 0x69, 0xee, 0xcf, 0x97, 0xed, 0x02, 0x84, 0x6f, 0xe2, 0xcf,
- 0x9d, 0xe5, 0x03, 0xcf, 0xeb, 0xee, 0xcf, 0x66, 0xe9, 0x03, 0xcf, 0xad,
- 0xee, 0x29, 0xcf, 0xba, 0xe3, 0x04, 0x05, 0xcc, 0x88, 0x6c, 0x75, 0xe2,
- 0xcf, 0xd8, 0xe1, 0xcf, 0xd5, 0xe2, 0xcd, 0x07, 0x72, 0x65, 0xec, 0x02,
- 0x81, 0x6c, 0x2d, 0x6f, 0x66, 0x2d, 0x6b, 0x6e, 0x6f, 0x77, 0x6c, 0x65,
- 0x64, 0x67, 0x65, 0x2e, 0x69, 0x6e, 0xe6, 0xcf, 0x82, 0x6c, 0x65, 0x74,
- 0x74, 0xe1, 0x02, 0x87, 0x74, 0x72, 0x61, 0x6e, 0xe9, 0xc9, 0x63, 0x2d,
- 0x74, 0x72, 0x61, 0x6e, 0x69, 0xad, 0xc9, 0x5a, 0x67, 0x61, 0x69, 0xee,
- 0xcd, 0x3e, 0x65, 0x66, 0x6f, 0xef, 0xcd, 0xe3, 0xe4, 0xc9, 0x73, 0xe3,
- 0x02, 0x8b, 0x6c, 0x61, 0xf9, 0x03, 0xcd, 0x2a, 0x63, 0x61, 0xf2, 0xcd,
- 0x44, 0x65, 0x6c, 0x6f, 0x6e, 0xe1, 0x4c, 0xc9, 0xc2, 0xb9, 0xb2, 0xcf,
- 0x59, 0xb1, 0xcf, 0x56, 0xb0, 0xcf, 0x53, 0xee, 0x05, 0x0b, 0x0c, 0xcc,
- 0xf9, 0x7a, 0x61, 0x69, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0xe4, 0xcf, 0x54,
- 0xe4, 0x04, 0x03, 0xcf, 0x5c, 0xef, 0xc7, 0xe9, 0x61, 0xe9, 0xca, 0x0f,
- 0xe1, 0x02, 0x8b, 0x6e, 0x61, 0x72, 0x65, 0x70, 0x75, 0x62, 0x6c, 0xe9,
- 0xc3, 0x64, 0x6d, 0xe5, 0xc7, 0xe3, 0x6d, 0xe2, 0x02, 0x83, 0xec, 0xcd,
- 0xb9, 0x69, 0x6e, 0xe1, 0xc7, 0x03, 0xec, 0x05, 0x06, 0x1f, 0x11, 0x94,
- 0x74, 0x69, 0x6d, 0xef, 0xca, 0xe9, 0xf3, 0x02, 0x83, 0xe6, 0xcb, 0x34,
- 0x61, 0xee, 0x03, 0xcd, 0x27, 0x2d, 0xf3, 0x02, 0x84, 0x1f, 0x43, 0xfc,
- 0x85, 0xf5, 0x02, 0x81, 0x65, 0x64, 0x74, 0x69, 0x72, 0x6f, 0xec, 0xcd,
- 0x15, 0xec, 0x02, 0x88, 0x6f, 0x6f, 0x6e, 0x69, 0x6e, 0xe7, 0xcc, 0x27,
- 0x61, 0x6e, 0x67, 0xe5, 0xc9, 0x1d, 0xe5, 0x04, 0x05, 0xcc, 0x3b, 0x73,
- 0x74, 0xf2, 0xc2, 0x27, 0x6e, 0x61, 0x2d, 0x64, 0x65, 0x76, 0x69, 0xe3,
- 0xcd, 0xde, 0xe1, 0x03, 0xc7, 0x66, 0x73, 0x68, 0x6f, 0xf6, 0xcc, 0xff,
- 0x6a, 0x64, 0xe4, 0x86, 0x69, 0xe4, 0x03, 0xcd, 0xe4, 0xe1, 0xc3, 0x39,
- 0xe8, 0x03, 0xc4, 0x33, 0xe3, 0x02, 0x81, 0x63, 0x61, 0x76, 0x75, 0x6f,
- 0xf4, 0xc4, 0x45, 0x67, 0x68, 0x64, 0xe1, 0xc9, 0xd7, 0x64, 0xe1, 0x02,
- 0x85, 0x6a, 0x6f, 0xfa, 0xcb, 0xff, 0x64, 0x64, 0xea, 0xc8, 0xdd, 0x63,
- 0xeb, 0x03, 0x13, 0x8a, 0x79, 0x61, 0x72, 0x64, 0x73, 0x2e, 0x62, 0x61,
- 0x6e, 0x7a, 0x61, 0x69, 0x63, 0x6c, 0x6f, 0x75, 0xe4, 0xc0, 0xa2, 0x70,
- 0x6c, 0x61, 0x6e, 0x65, 0x61, 0x70, 0xf0, 0xcd, 0x96, 0x64, 0x72, 0x6f,
- 0xf0, 0xc6, 0x52, 0xe2, 0x02, 0x91, 0xf9, 0x04, 0x06, 0xce, 0x7b, 0x6d,
- 0x69, 0x6c, 0xeb, 0xc6, 0x44, 0x62, 0x6c, 0x75, 0xe5, 0xc6, 0x3e, 0x69,
- 0x61, 0x2d, 0x67, 0x6f, 0x72, 0xe1, 0xc9, 0xde, 0xae, 0x48, 0x5a, 0x03,
- 0xc4, 0x13, 0xae, 0x03, 0xcc, 0xee, 0xe2, 0x4d, 0x17, 0xc1, 0x49, 0x2d,
- 0x64, 0x61, 0x74, 0xe1, 0xcd, 0x5d, 0xe1, 0x2b, 0x0c, 0x40, 0x4a, 0x21,
- 0x09, 0x2e, 0x34, 0x40, 0xa3, 0x40, 0x6b, 0x41, 0x2d, 0x41, 0x22, 0x1a,
- 0x41, 0x0a, 0x36, 0x40, 0xe5, 0x40, 0xb5, 0x40, 0xf0, 0x40, 0x85, 0x03,
- 0x40, 0xf8, 0x08, 0x40, 0x73, 0x2f, 0x3f, 0x40, 0x5c, 0x41, 0x1d, 0x40,
- 0x8f, 0x9c, 0x1f, 0x43, 0x69, 0x72, 0x6f, 0x70, 0x6f, 0x72, 0x74, 0xae,
- 0xc2, 0x41, 0xfa, 0x07, 0x31, 0x07, 0x48, 0x59, 0xc5, 0x85, 0xf5, 0x02,
- 0xa8, 0x72, 0xe5, 0x06, 0x09, 0x0e, 0x4d, 0xc6, 0xae, 0x77, 0x65, 0x62,
- 0x73, 0x69, 0x74, 0xe5, 0xcd, 0xdf, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69,
- 0x6e, 0x65, 0x72, 0x2e, 0x69, 0xef, 0xcd, 0xe4, 0x2d, 0x6d, 0x6f, 0x62,
- 0x69, 0x6c, 0xe5, 0xcd, 0xc9, 0x6d, 0x69, 0x6e, 0xef, 0xca, 0xd1, 0x69,
- 0x6d, 0x75, 0x74, 0xe8, 0xc2, 0xe9, 0x65, 0x72, 0x62, 0x61, 0x69, 0x6a,
- 0x61, 0xee, 0xcb, 0xf3, 0x79, 0xe1, 0x04, 0x04, 0x08, 0x87, 0x73, 0xe5,
- 0xc9, 0x34, 0x67, 0x61, 0x77, 0x61, 0x2e, 0xeb, 0xc9, 0x30, 0x62, 0x65,
- 0x2e, 0x6b, 0xf9, 0xc6, 0xaf, 0x2e, 0x6d, 0x69, 0x79, 0x61, 0xfa, 0xc6,
- 0x45, 0xf8, 0x05, 0x4c, 0x14, 0xc1, 0x99, 0xe9, 0xc6, 0x72, 0xf7, 0x05,
- 0x1c, 0x08, 0xcd, 0x80, 0xf3, 0x04, 0x05, 0xcd, 0x9a, 0x6d, 0x70, 0xf0,
- 0xc7, 0x05, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x61, 0x63, 0x63, 0x65,
- 0x6c, 0x65, 0x72, 0x61, 0x74, 0xef, 0xc4, 0x1f, 0x64, 0x65, 0x76, 0x2e,
- 0x63, 0xe1, 0xcd, 0x70, 0x61, 0xea, 0xc8, 0xcf, 0xf6, 0x04, 0x13, 0x08,
- 0x8d, 0xef, 0x02, 0x85, 0x75, 0x65, 0xf3, 0xc9, 0xae, 0x63, 0x61, 0xf4,
- 0x03, 0xc3, 0x35, 0xae, 0x49, 0xa6, 0xc2, 0x43, 0x69, 0xe1, 0x03, 0xc2,
- 0xaa, 0xee, 0xcb, 0xc4, 0xe5, 0x02, 0x85, 0xf2, 0x41, 0xb3, 0xc3, 0x78,
- 0x6c, 0x6c, 0xe9, 0xc1, 0xf9, 0xae, 0x03, 0xcb, 0x50, 0xf4, 0xcc, 0x00,
- 0xf5, 0x0a, 0x30, 0x2b, 0x16, 0x04, 0x08, 0x13, 0x05, 0xcc, 0xa8, 0xf4,
- 0x02, 0x8f, 0xef, 0x07, 0x48, 0xa2, 0x42, 0x2e, 0xc2, 0x62, 0x6d, 0x6f,
- 0x74, 0x69, 0xf6, 0xc8, 0xe7, 0xe8, 0x02, 0x86, 0x6f, 0xf2, 0x4a, 0x47,
- 0xc2, 0xdf, 0x67, 0x65, 0x61, 0xf2, 0x02, 0x85, 0x61, 0x70, 0xf0, 0xcc,
- 0x0c, 0x2d, 0x73, 0x74, 0x61, 0x67, 0x69, 0x6e, 0xe7, 0xcd, 0x07, 0xf3,
- 0x03, 0x16, 0x85, 0xf4, 0x03, 0x0c, 0x83, 0xf2, 0x02, 0x84, 0x68, 0xe5,
- 0xc1, 0x5e, 0x61, 0x6c, 0xe9, 0xc6, 0xdd, 0xe9, 0xc2, 0x5b, 0xe5, 0xc1,
- 0x4b, 0x70, 0x6f, 0xf3, 0xcb, 0x39, 0x2e, 0x62, 0x61, 0x73, 0x6b, 0x65,
- 0x74, 0x62, 0x61, 0xec, 0xcc, 0x31, 0xf2, 0x04, 0x0d, 0xcb, 0x48, 0x73,
- 0x6b, 0x6f, 0x67, 0x2d, 0xe8, 0x02, 0x84, 0x1f, 0x43, 0xf8, 0x82, 0x6f,
- 0x6c, 0xe1, 0xc6, 0x7e, 0x6b, 0xf2, 0xc6, 0xf4, 0x67, 0x75, 0x73, 0x74,
- 0x6f, 0xf7, 0xc8, 0x32, 0xe4, 0x02, 0x87, 0x6e, 0x65, 0x64, 0x61, 0xec,
- 0xc6, 0xd5, 0xe9, 0x05, 0x4b, 0x33, 0xc1, 0x7d, 0xe2, 0xca, 0xc3, 0x63,
- 0x74, 0xe9, 0xc5, 0x8b, 0xae, 0xc6, 0x9c, 0xf4, 0x0b, 0x07, 0x0b, 0x03,
- 0x03, 0x1c, 0x0d, 0x04, 0x0e, 0xcc, 0x46, 0x74, 0x6f, 0x72, 0x6e, 0xe5,
- 0xca, 0x64, 0x73, 0xf5, 0x02, 0x83, 0xed, 0xca, 0xb2, 0x67, 0xe9, 0xc7,
- 0xf1, 0xef, 0xcb, 0x3a, 0xed, 0xc7, 0xf3, 0xec, 0x02, 0x85, 0x61, 0x6e,
- 0xf4, 0xc6, 0x5d, 0x2e, 0x6a, 0x65, 0x6c, 0x61, 0x73, 0x74, 0x69, 0x63,
- 0x2e, 0x76, 0x70, 0x73, 0x2d, 0x68, 0x6f, 0x73, 0xf4, 0xcc, 0x43, 0xe8,
- 0x02, 0x85, 0x6c, 0x65, 0xf4, 0xca, 0xc6, 0x2e, 0x63, 0xf8, 0xcc, 0x56,
- 0x61, 0xed, 0xc2, 0x57, 0xae, 0x06, 0x03, 0x46, 0x3f, 0xc4, 0x10, 0xf6,
- 0xc9, 0x7d, 0x6d, 0xe4, 0xcc, 0x44, 0x2d, 0x62, 0x61, 0x6e, 0x64, 0x2d,
- 0x63, 0x61, 0x6d, 0xf0, 0xcc, 0x18, 0xf3, 0x13, 0x05, 0x0b, 0x40, 0x54,
- 0x0b, 0x06, 0x17, 0x03, 0x2d, 0x04, 0x03, 0x0e, 0x41, 0x41, 0x44, 0x8f,
- 0xc5, 0x85, 0x75, 0x6b, 0xe5, 0xc6, 0xfb, 0xf4, 0x03, 0xc4, 0x2f, 0x72,
- 0x6f, 0x6e, 0x6f, 0xed, 0xc3, 0xa5, 0xf3, 0x06, 0x04, 0x2f, 0x05, 0x05,
- 0x8c, 0x75, 0xf2, 0xc1, 0xda, 0xef, 0x02, 0x8e, 0x63, 0x69, 0x61, 0xf4,
- 0x02, 0x85, 0x69, 0x6f, 0xee, 0xc4, 0xd1, 0xe5, 0xc9, 0x9a, 0xae, 0x0e,
- 0x02, 0x04, 0x03, 0x03, 0x1a, 0x45, 0xba, 0x42, 0x49, 0x40, 0x56, 0xc0,
- 0xa3, 0xee, 0x82, 0x6d, 0xe3, 0xcb, 0xe7, 0xe7, 0xca, 0x55, 0xe4, 0xc9,
- 0x75, 0xe3, 0xc9, 0xcc, 0x6e, 0x2e, 0xec, 0xc9, 0x7a, 0x69, 0x73, 0xe9,
- 0xc9, 0x1b, 0xe1, 0x02, 0x86, 0x73, 0x73, 0x69, 0xee, 0xc1, 0x15, 0xe2,
- 0xc7, 0x3e, 0x2e, 0xeb, 0xc9, 0x79, 0xee, 0x03, 0xc7, 0x9a, 0xae, 0x03,
- 0xc8, 0x9f, 0xec, 0xc8, 0x13, 0x6d, 0x61, 0x74, 0xe1, 0xc4, 0x6f, 0xeb,
- 0x06, 0x05, 0x03, 0x04, 0xc3, 0x71, 0x76, 0x6f, 0xec, 0xc4, 0xcd, 0xef,
- 0xc3, 0xbc, 0x69, 0xed, 0xca, 0x19, 0x65, 0xf2, 0xca, 0x15, 0xe9, 0xca,
- 0x00, 0xe8, 0x03, 0x05, 0x9d, 0x6f, 0x72, 0xef, 0xc9, 0xe4, 0xe9, 0x04,
- 0x0b, 0xc6, 0xf0, 0x79, 0x61, 0xae, 0x03, 0xc6, 0xd6, 0x66, 0x75, 0xeb,
- 0xc1, 0x87, 0x6b, 0x61, 0x67, 0x61, 0x2e, 0x74, 0x6f, 0x63, 0x68, 0x69,
- 0xe7, 0xc9, 0x6d, 0x67, 0x61, 0x62, 0x61, 0xe4, 0xc9, 0x89, 0x65, 0xf2,
- 0xc4, 0x8d, 0xe4, 0xc9, 0xcc, 0x63, 0x6f, 0x6c, 0xe9, 0x02, 0x81, 0x2d,
- 0x70, 0x69, 0x63, 0x65, 0xee, 0xc9, 0x5a, 0xe1, 0x04, 0x0c, 0x13, 0xa1,
- 0x6d, 0x69, 0x6e, 0x61, 0x6d, 0x69, 0x2e, 0x68, 0x69, 0xf2, 0xc5, 0x51,
- 0xeb, 0x02, 0x86, 0x75, 0x63, 0x68, 0xe9, 0xc5, 0xa1, 0xe1, 0x02, 0x84,
- 0x77, 0xe1, 0xc5, 0xeb, 0xae, 0xc1, 0x2e, 0x68, 0xe9, 0x02, 0x85, 0x6b,
- 0x61, 0xf7, 0xc9, 0x4f, 0xae, 0x09, 0x06, 0x04, 0x43, 0xa0, 0x44, 0x5f,
- 0xc1, 0x3f, 0x79, 0x61, 0x6d, 0xe1, 0xc7, 0x04, 0x74, 0xef, 0xc5, 0x7e,
- 0x6d, 0xe9, 0xc6, 0x73, 0xe7, 0xc5, 0x2f, 0xf2, 0x13, 0x0b, 0x40, 0x69,
- 0x03, 0x03, 0x08, 0x09, 0x1c, 0x0e, 0x23, 0x07, 0x28, 0x43, 0x16, 0x44,
- 0xed, 0xc1, 0xef, 0x76, 0x6f, 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0xf2,
- 0xca, 0xb8, 0xf4, 0x09, 0x1d, 0x08, 0x0e, 0x06, 0x06, 0x0b, 0xca, 0x9a,
- 0xf3, 0x02, 0x8a, 0x61, 0x6e, 0x64, 0x63, 0x72, 0x61, 0x66, 0xf4, 0xc3,
- 0x9f, 0xae, 0x08, 0x03, 0x40, 0xbb, 0x47, 0x58, 0xc1, 0x3a, 0xf6, 0xc9,
- 0x5f, 0x6e, 0xe6, 0xca, 0xc9, 0x67, 0x61, 0x6c, 0x6c, 0x65, 0xf2, 0xc2,
- 0x4e, 0xe5, 0x05, 0x48, 0x0a, 0xc2, 0xaf, 0x64, 0x75, 0x63, 0x61, 0x74,
- 0x69, 0xef, 0x95, 0x64, 0x65, 0x63, 0xef, 0xc7, 0xf4, 0x63, 0x65, 0x6e,
- 0xf4, 0xc3, 0x7d, 0x61, 0x6e, 0x64, 0x64, 0x65, 0x73, 0x69, 0x67, 0xee,
- 0xc7, 0xe3, 0xae, 0x09, 0x03, 0x03, 0x47, 0x1e, 0x40, 0xb4, 0xc1, 0x6d,
- 0xf3, 0xc9, 0x64, 0xf0, 0xc9, 0xd9, 0xe4, 0x48, 0x1d, 0xc0, 0xef, 0xf1,
- 0xc9, 0x38, 0xee, 0xc4, 0xab, 0xed, 0x03, 0xc8, 0x4b, 0x65, 0xee, 0xc8,
- 0x94, 0x6b, 0x68, 0x61, 0x6e, 0x67, 0x65, 0xec, 0xc4, 0x84, 0xe9, 0x03,
- 0x03, 0x8d, 0x74, 0xe1, 0x91, 0x64, 0xe1, 0x02, 0x84, 0x67, 0x61, 0x77,
- 0x61, 0x2e, 0x77, 0xe1, 0xc4, 0xc2, 0x61, 0x6b, 0x65, 0x2e, 0x73, 0xe1,
- 0xc5, 0x27, 0xe5, 0x04, 0x03, 0xc8, 0x4b, 0xee, 0xc3, 0x70, 0x6d, 0x61,
- 0x72, 0xeb, 0xc8, 0xbf, 0x63, 0xe8, 0x02, 0x90, 0xe9, 0x03, 0xca, 0x3c,
- 0x74, 0x65, 0x63, 0xf4, 0x03, 0xc5, 0xed, 0x65, 0x73, 0xae, 0xc6, 0x39,
- 0x61, 0x65, 0x6f, 0x6c, 0x6f, 0xe7, 0x03, 0xc1, 0xb4, 0x69, 0x63, 0x61,
- 0xec, 0xc7, 0x6a, 0x62, 0x6f, 0x72, 0x65, 0xf4, 0xc0, 0x43, 0xe1, 0x05,
- 0x03, 0x04, 0x0e, 0x8a, 0xef, 0xc2, 0xff, 0x6d, 0xe3, 0xc8, 0x92, 0x6b,
- 0x61, 0x77, 0x61, 0xae, 0x03, 0xc6, 0xbd, 0x73, 0x61, 0x69, 0xf4, 0xc4,
- 0x6a, 0x69, 0x2e, 0x73, 0x68, 0x69, 0x7a, 0x75, 0xef, 0xc8, 0x2d, 0xe2,
- 0xc9, 0xf4, 0xae, 0x45, 0x18, 0x42, 0xde, 0xc1, 0xf4, 0xf1, 0x05, 0x47,
- 0xe9, 0xc1, 0xfc, 0xf5, 0x02, 0x84, 0x69, 0xec, 0xc3, 0x99, 0x61, 0xf2,
- 0x02, 0x85, 0x69, 0x75, 0xed, 0xc7, 0x1e, 0x65, 0xec, 0xc7, 0xe7, 0xf0,
- 0x06, 0x40, 0x93, 0x18, 0x12, 0x8e, 0xf0, 0x08, 0x05, 0x31, 0x07, 0x07,
- 0x07, 0xc9, 0x76, 0x75, 0x64, 0xef, 0xc9, 0x9a, 0xf3, 0x02, 0x9e, 0xf0,
- 0x02, 0x82, 0xef, 0x90, 0x61, 0x63, 0xe5, 0x02, 0x8d, 0x75, 0x73, 0x65,
- 0x72, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0xf4, 0xc9, 0x9c, 0x68, 0x6f,
- 0x73, 0x74, 0xe5, 0xc4, 0x64, 0xae, 0x02, 0x86, 0x6c, 0x61, 0x69, 0xf2,
- 0xc8, 0x99, 0x66, 0x62, 0x73, 0x62, 0xf8, 0xc9, 0x85, 0xec, 0x03, 0xc8,
- 0x19, 0x69, 0xee, 0x8b, 0x65, 0x6e, 0x67, 0x69, 0xee, 0xc2, 0xf7, 0x63,
- 0x68, 0x69, 0x7a, 0xe9, 0xc9, 0x70, 0xae, 0x05, 0x08, 0x18, 0x06, 0x83,
- 0x72, 0x65, 0x6e, 0x64, 0x65, 0xf2, 0xc9, 0x62, 0x6f, 0x73, 0xae, 0x02,
- 0x84, 0x73, 0x74, 0x67, 0x2e, 0x66, 0x65, 0x64, 0x6f, 0x72, 0x61, 0x70,
- 0x72, 0x6f, 0x6a, 0x65, 0x63, 0xf4, 0xc6, 0x80, 0x6c, 0x6d, 0x70, 0xed,
- 0xc9, 0x44, 0xe7, 0xc7, 0xe4, 0xe2, 0x03, 0xc7, 0xf9, 0x61, 0x6e, 0x7a,
- 0x61, 0x69, 0x63, 0x6c, 0x6f, 0x75, 0xe4, 0xc8, 0x3e, 0xe9, 0x02, 0x85,
- 0x67, 0x65, 0xe5, 0xc8, 0x36, 0xae, 0x02, 0x88, 0x73, 0x74, 0x64, 0x6c,
- 0x69, 0xe2, 0xc9, 0x1e, 0x67, 0x6f, 0xf6, 0xc5, 0xd0, 0x61, 0xf2, 0x02,
- 0x87, 0x74, 0x6d, 0x65, 0x6e, 0xf4, 0xc6, 0xb4, 0x65, 0x63, 0x69, 0x64,
- 0xe1, 0xc7, 0xc3, 0xae, 0x05, 0x42, 0xf6, 0xc4, 0x16, 0x67, 0x6f, 0x76,
- 0xae, 0x44, 0xa4, 0xc3, 0x14, 0xad, 0x02, 0x90, 0x73, 0x6f, 0x75, 0x74,
- 0xe8, 0x02, 0x87, 0x65, 0x61, 0x73, 0x74, 0xad, 0x13, 0x82, 0xad, 0x92,
- 0x6e, 0x6f, 0x72, 0x74, 0x68, 0x65, 0x61, 0x73, 0x74, 0xad, 0x03, 0x02,
- 0x82, 0xb3, 0x84, 0xb2, 0x82, 0x31, 0x2e, 0x65, 0x6c, 0x61, 0x73, 0x74,
- 0x69, 0x63, 0x62, 0x65, 0x61, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0xeb, 0xc8,
- 0xc1, 0xef, 0x0a, 0x13, 0x0f, 0x03, 0x46, 0x4f, 0x40, 0x4c, 0xc1, 0xfc,
- 0x73, 0xf4, 0x03, 0xc1, 0xef, 0xe1, 0x04, 0x01, 0xc6, 0xb5, 0x2d, 0x76,
- 0x61, 0x6c, 0x6c, 0x65, 0xf9, 0xc6, 0xaf, 0x6d, 0x6f, 0x72, 0x69, 0xae,
- 0x03, 0xc6, 0xff, 0x61, 0x6f, 0x6d, 0x6f, 0xf2, 0xc6, 0x96, 0xeb, 0xc5,
- 0x82, 0x67, 0xe1, 0x41, 0x8f, 0xc1, 0x49, 0xee, 0x0e, 0x12, 0x04, 0x0c,
- 0x20, 0x04, 0x07, 0x40, 0x62, 0x05, 0x45, 0x62, 0xc0, 0x70, 0xf4, 0x03,
- 0xc1, 0x40, 0x68, 0x72, 0xef, 0x03, 0xc5, 0xbf, 0x70, 0x6f, 0x6c, 0x6f,
- 0x67, 0xf9, 0xc5, 0xb9, 0x71, 0xf5, 0xc4, 0x5f, 0x70, 0x61, 0x63, 0x68,
- 0x69, 0x2e, 0x67, 0x69, 0x66, 0xf5, 0xc6, 0xbf, 0xee, 0x03, 0x08, 0x89,
- 0x65, 0x66, 0x72, 0x61, 0x6e, 0xeb, 0xc5, 0x9d, 0x61, 0x6b, 0x61, 0x2e,
- 0x67, 0x75, 0xee, 0xc3, 0x0a, 0x2d, 0x61, 0x72, 0x62, 0x6f, 0x72, 0x2e,
- 0x6d, 0xe9, 0xc2, 0xbd, 0x6a, 0xef, 0xc3, 0x16, 0x67, 0x72, 0x79, 0x2e,
- 0xea, 0xc6, 0xd2, 0xe4, 0x07, 0x05, 0x3d, 0x0c, 0x04, 0xc5, 0x22, 0x1f,
- 0x43, 0xf8, 0xc0, 0x42, 0xf2, 0x02, 0x84, 0x6f, 0xe9, 0xc5, 0xde, 0x69,
- 0xe1, 0x03, 0x06, 0x89, 0x74, 0x72, 0x61, 0x6e, 0xe9, 0x93, 0x62, 0x61,
- 0x72, 0x6c, 0x65, 0x74, 0x74, 0xe1, 0x9c, 0xad, 0x02, 0x8f, 0x74, 0x72,
- 0x61, 0x6e, 0x69, 0x2d, 0x62, 0x61, 0x72, 0x6c, 0x65, 0x74, 0xf4, 0xc1,
- 0xb6, 0x62, 0x61, 0x72, 0x6c, 0x65, 0x74, 0x74, 0x61, 0x2d, 0x74, 0x72,
- 0x61, 0x6e, 0xe9, 0xc5, 0xf1, 0xef, 0x02, 0x83, 0xf9, 0xc6, 0x60, 0x2e,
- 0x6e, 0x61, 0xf2, 0xc6, 0x18, 0x65, 0xe2, 0xc1, 0xb9, 0x61, 0x73, 0x75,
- 0x6f, 0x6c, 0xef, 0xc6, 0x4e, 0x63, 0x6f, 0xee, 0xc1, 0x89, 0xe1, 0x03,
- 0x0b, 0x8c, 0xee, 0x02, 0x83, 0xe9, 0xc6, 0x7a, 0xae, 0x42, 0x70, 0xc2,
- 0x3e, 0x6d, 0x69, 0x7a, 0x75, 0x2e, 0x69, 0x73, 0x68, 0x69, 0xeb, 0xc3,
- 0x48, 0x6c, 0x79, 0x74, 0x69, 0xe3, 0xc5, 0x4c, 0xed, 0x0c, 0x08, 0x16,
- 0x04, 0x04, 0x0d, 0x04, 0x31, 0x11, 0x28, 0xc6, 0xfe, 0x75, 0x73, 0x65,
- 0x6d, 0x65, 0xee, 0xc2, 0xbc, 0xf3, 0x02, 0x8a, 0x74, 0x65, 0x72, 0x64,
- 0x61, 0xed, 0x44, 0xd5, 0xc2, 0xb9, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74,
- 0xe5, 0xc7, 0x7b, 0x6f, 0xf4, 0xc5, 0xf8, 0x6c, 0xe9, 0xc5, 0xf4, 0xe9,
- 0x03, 0xc5, 0xdb, 0x2e, 0x69, 0x62, 0x61, 0x72, 0x61, 0xeb, 0xc5, 0x68,
- 0x66, 0xe1, 0xc5, 0x1f, 0xe5, 0x02, 0x83, 0xf8, 0xc7, 0x64, 0x72, 0x69,
- 0x63, 0x61, 0xee, 0x05, 0x07, 0x08, 0xc4, 0x90, 0x66, 0x61, 0x6d, 0x69,
- 0xec, 0xc5, 0x23, 0x65, 0x78, 0x70, 0x72, 0x65, 0xf3, 0xc4, 0xe9, 0xe1,
- 0x04, 0x04, 0xc4, 0x87, 0x72, 0xf4, 0xc4, 0x89, 0x6e, 0x74, 0x69, 0x71,
- 0x75, 0x65, 0xf3, 0xc4, 0x80, 0xe2, 0x02, 0x8a, 0x75, 0x6c, 0x61, 0x6e,
- 0x63, 0x65, 0xae, 0x44, 0x4f, 0xa6, 0x65, 0xf2, 0xc4, 0x6f, 0xe1, 0x05,
- 0x04, 0x04, 0x0e, 0x87, 0x7a, 0xef, 0xc5, 0xf3, 0x6d, 0xe9, 0xc1, 0x21,
- 0x6b, 0x75, 0x73, 0x61, 0x2e, 0x6b, 0x75, 0x6d, 0x61, 0x6d, 0x6f, 0xf4,
- 0xc5, 0x68, 0x67, 0x61, 0x73, 0x61, 0xeb, 0xc2, 0x56, 0xae, 0x41, 0x71,
- 0xc0, 0x6a, 0xae, 0x40, 0xec, 0x03, 0x44, 0xc3, 0x9f, 0xec, 0x0f, 0x0a,
- 0x06, 0x1b, 0x13, 0x2a, 0x12, 0x0c, 0x04, 0x08, 0x11, 0x0d, 0x1c, 0xc6,
- 0x1b, 0x77, 0x61, 0x79, 0x73, 0x64, 0x61, 0x74, 0xe1, 0xc6, 0xbb, 0x76,
- 0x64, 0x61, 0xec, 0xc5, 0x52, 0xf4, 0x06, 0x0b, 0x40, 0xef, 0xc1, 0x93,
- 0xef, 0x02, 0x81, 0x2d, 0x61, 0x64, 0x69, 0x67, 0xe5, 0xc4, 0xcb, 0x65,
- 0x72, 0x76, 0x69, 0x73, 0x74, 0xe1, 0xc3, 0xec, 0xf3, 0x02, 0x8d, 0xf4,
- 0x02, 0x83, 0xef, 0xc4, 0x6a, 0x61, 0x68, 0x61, 0x75, 0xe7, 0xc5, 0x27,
- 0xe1, 0xc1, 0xc7, 0xf0, 0x02, 0x9b, 0x68, 0xe1, 0x02, 0x8e, 0x2e, 0x62,
- 0x6f, 0x75, 0x6e, 0x74, 0x79, 0x2d, 0x66, 0x75, 0x6c, 0xec, 0xc6, 0x8e,
- 0x2d, 0x6d, 0x79, 0x71, 0x6e, 0x61, 0xf0, 0xc1, 0x50, 0x31, 0x2e, 0x61,
- 0x65, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0xae, 0xc5, 0xd3, 0xec, 0x04, 0x06,
- 0xc4, 0x44, 0x73, 0x74, 0x61, 0xf4, 0xc5, 0x08, 0x66, 0x69, 0x6e, 0x61,
- 0xee, 0xc4, 0x03, 0xe9, 0x02, 0x84, 0x70, 0xe1, 0xc4, 0x38, 0x62, 0x61,
- 0xe2, 0xc4, 0xca, 0x67, 0xe1, 0xc2, 0x6b, 0x66, 0x61, 0x72, 0x6f, 0x6d,
- 0xe5, 0xc4, 0xda, 0x65, 0xf3, 0x02, 0x84, 0x75, 0xee, 0xc2, 0x5c, 0x73,
- 0x61, 0x6e, 0x64, 0x72, 0x69, 0xe1, 0xc4, 0x4a, 0x63, 0x65, 0x73, 0x2e,
- 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0xeb, 0xc6, 0x27, 0xe1, 0x04, 0x03,
- 0x06, 0x88, 0x73, 0xeb, 0x92, 0x6e, 0x64, 0x2e, 0xe6, 0xc4, 0x19, 0x68,
- 0x65, 0x61, 0x64, 0x6a, 0xf5, 0xc4, 0x9c, 0x62, 0x61, 0x6d, 0xe1, 0xc3,
- 0x64, 0xae, 0x09, 0x03, 0x03, 0x41, 0x32, 0x42, 0xde, 0xc0, 0x75, 0xec,
- 0xc3, 0xb4, 0xe7, 0xc3, 0xcf, 0x65, 0xf5, 0xc3, 0x37, 0xeb, 0x0a, 0x0a,
- 0x0a, 0x08, 0x03, 0x0a, 0x06, 0x22, 0x03, 0xa3, 0x75, 0x6e, 0x65, 0x2e,
- 0x6b, 0x61, 0x67, 0xef, 0xc0, 0xae, 0x74, 0x79, 0x75, 0x62, 0x69, 0x6e,
- 0x73, 0xeb, 0xc4, 0x07, 0x72, 0x65, 0x68, 0x61, 0x6d, 0xee, 0xc4, 0x5b,
- 0xef, 0xc1, 0x31, 0x6e, 0x6f, 0x6c, 0x75, 0x6f, 0x6b, 0x74, 0xe1, 0xc4,
- 0x4e, 0x6b, 0x65, 0x73, 0xe8, 0xc4, 0x22, 0xe9, 0x04, 0x0b, 0x07, 0x86,
- 0x74, 0x61, 0xae, 0x03, 0xc4, 0x20, 0x61, 0x6b, 0xe9, 0xc1, 0xab, 0x73,
- 0x68, 0x69, 0x6d, 0xe1, 0xc2, 0x6f, 0x72, 0x75, 0x6e, 0xef, 0xc2, 0x69,
- 0x2e, 0x6b, 0xef, 0xc3, 0xa5, 0xe4, 0xc4, 0x7f, 0xe1, 0x04, 0x04, 0x0b,
- 0x8b, 0x73, 0xe8, 0xc0, 0xf2, 0x69, 0x77, 0x61, 0x2e, 0x6f, 0x6b, 0x61,
- 0x79, 0xe1, 0xc0, 0x53, 0x67, 0x69, 0x2e, 0x73, 0x68, 0x69, 0x6d, 0x61,
- 0xee, 0xc0, 0xec, 0x62, 0xe9, 0xc3, 0xab, 0xae, 0xc0, 0xab, 0xea, 0xc4,
- 0x34, 0xe9, 0x12, 0x2c, 0x0a, 0x13, 0x40, 0x6e, 0x05, 0x09, 0x0b, 0x0b,
- 0x03, 0x42, 0x86, 0x40, 0xdb, 0x41, 0x2c, 0x81, 0x7a, 0xf5, 0x03, 0x0a,
- 0x8d, 0x77, 0x61, 0x6b, 0x61, 0x6d, 0x61, 0x74, 0x73, 0xf5, 0x93, 0x6d,
- 0xe9, 0x02, 0x85, 0x73, 0x61, 0x74, 0xef, 0x8a, 0x2e, 0x74, 0xef, 0x89,
- 0x62, 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x66, 0x75, 0x6b, 0x75, 0x73, 0x68,
- 0x69, 0xed, 0xc3, 0x79, 0x76, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0xe4,
- 0xc5, 0x30, 0xf3, 0x02, 0x89, 0x68, 0x6f, 0x2e, 0x73, 0x68, 0x69, 0xe7,
- 0xc3, 0x63, 0x61, 0x69, 0x2e, 0x61, 0xe9, 0xc3, 0x1d, 0xf2, 0x0b, 0x0c,
- 0x04, 0x05, 0x14, 0x07, 0x06, 0x07, 0x04, 0xc2, 0x1d, 0xf4, 0x02, 0x86,
- 0x72, 0x61, 0x66, 0xe6, 0xc1, 0x61, 0xe5, 0xc2, 0xc5, 0x70, 0x6f, 0xf2,
- 0xab, 0x6c, 0x69, 0xee, 0xc1, 0x49, 0x6b, 0x69, 0x74, 0x61, 0x70, 0x70,
- 0xf3, 0x02, 0x87, 0xae, 0x03, 0xc4, 0xee, 0xe5, 0xc4, 0x6c, 0x2d, 0xe1,
- 0xc3, 0xcd, 0x67, 0x75, 0x61, 0x72, 0xe4, 0xc2, 0x30, 0x66, 0x6f, 0x72,
- 0xe3, 0xc3, 0x75, 0x63, 0x72, 0x61, 0x66, 0xf4, 0xc1, 0xfd, 0x62, 0xf5,
- 0xc2, 0x76, 0xad, 0x02, 0x91, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63,
- 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0xec, 0xc1, 0xe5, 0x73, 0x75,
- 0x72, 0x76, 0x65, 0x69, 0x6c, 0x6c, 0x61, 0x6e, 0xe3, 0xc0, 0xfc, 0x70,
- 0x2e, 0xe5, 0xc3, 0x44, 0x6f, 0x69, 0x2e, 0x68, 0x79, 0x6f, 0xe7, 0xc3,
- 0x05, 0x6e, 0x61, 0x6e, 0x2e, 0x65, 0x68, 0x69, 0x6d, 0xe5, 0xc2, 0xfb,
- 0x6b, 0x61, 0x77, 0x61, 0x2e, 0x6b, 0x61, 0x6e, 0x61, 0xe7, 0xa5, 0x64,
- 0xae, 0xb0, 0x62, 0x65, 0x74, 0x73, 0xf5, 0xc2, 0xdd, 0x68, 0xae, 0x03,
- 0xc2, 0xfc, 0xe3, 0xc3, 0x56, 0xe7, 0x09, 0x0c, 0x2e, 0x14, 0x07, 0x42,
- 0x24, 0xc1, 0xfc, 0x75, 0x6e, 0x69, 0x2e, 0x6f, 0x6b, 0x69, 0x6e, 0x61,
- 0xf7, 0xc2, 0xa2, 0xf2, 0x05, 0x0c, 0x18, 0xc2, 0xf3, 0x6f, 0xae, 0x02,
- 0x83, 0xf0, 0xc2, 0x16, 0xe2, 0x42, 0x22, 0xc0, 0xbc, 0xe9, 0x02, 0x86,
- 0x67, 0x65, 0x6e, 0xf4, 0xc2, 0x53, 0xe3, 0x02, 0x88, 0x75, 0x6c, 0x74,
- 0x75, 0x72, 0xe5, 0xc1, 0x8c, 0x2e, 0xfa, 0xc2, 0xa8, 0x61, 0xf2, 0xc3,
- 0x48, 0xe5, 0x02, 0x8a, 0xee, 0x02, 0x84, 0x74, 0xf3, 0xc1, 0x54, 0xe3,
- 0xc2, 0x00, 0x6d, 0x61, 0x74, 0x73, 0xf5, 0xc1, 0x13, 0x64, 0x65, 0x6e,
- 0x65, 0xf3, 0xc2, 0x9b, 0xe1, 0x03, 0x02, 0x89, 0x6e, 0x6f, 0x2e, 0x6e,
- 0x69, 0x69, 0x67, 0x61, 0xf4, 0xc2, 0x4a, 0x6b, 0x68, 0xe1, 0xc2, 0xe3,
- 0xe6, 0x07, 0x0e, 0x06, 0x41, 0xa8, 0xc2, 0x48, 0x72, 0x69, 0x63, 0xe1,
- 0x03, 0xc3, 0xfd, 0xae, 0x03, 0xc3, 0xf2, 0xe2, 0xc1, 0xbf, 0x6a, 0x6f,
- 0x72, 0xe4, 0xc2, 0x6b, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x79, 0x6c, 0x6f,
- 0x74, 0x74, 0x65, 0x72, 0x79, 0x2e, 0x6f, 0x72, 0xe7, 0xc0, 0x8e, 0xe5,
- 0x08, 0x04, 0x2d, 0x40, 0xd1, 0x42, 0xd1, 0x81, 0x74, 0xee, 0xc2, 0x39,
- 0x72, 0xef, 0x07, 0x08, 0x07, 0x06, 0x07, 0xc3, 0xab, 0x70, 0x6f, 0x72,
- 0x74, 0x2e, 0xe6, 0xc2, 0x77, 0x64, 0x72, 0x6f, 0x6d, 0xe5, 0xc0, 0xdb,
- 0x63, 0x6c, 0x75, 0xe2, 0xc0, 0xd5, 0x62, 0x61, 0x74, 0x69, 0xe3, 0xc0,
- 0xce, 0xae, 0x03, 0xc1, 0xef, 0x6d, 0xf6, 0xc3, 0xa5, 0x6a, 0x72, 0xe9,
- 0xc2, 0x18, 0xe4, 0x0d, 0x0a, 0x13, 0x0a, 0x0f, 0x03, 0x0a, 0x40, 0xeb,
- 0x40, 0xbf, 0xc1, 0xa3, 0x79, 0x67, 0x65, 0x79, 0x61, 0xae, 0x41, 0xa8,
- 0xc1, 0x59, 0xf6, 0x02, 0x89, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x77, 0xf3,
- 0xc3, 0x6a, 0xae, 0x03, 0xc2, 0x2b, 0xed, 0xc1, 0x09, 0x75, 0x6c, 0xf4,
- 0x03, 0xc3, 0x6d, 0x2e, 0xe8, 0xc1, 0xb4, 0x6f, 0x62, 0x65, 0x61, 0x65,
- 0x6d, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0xae, 0x43, 0x3a, 0x9c, 0xed, 0xc2,
- 0x0d, 0x69, 0x6d, 0x6f, 0x2e, 0x63, 0x6f, 0x2e, 0xf5, 0xc3, 0x17, 0x61,
- 0x63, 0x68, 0x69, 0x2e, 0x74, 0x6f, 0x6b, 0xf9, 0xc1, 0xa0, 0xe3, 0x0a,
- 0x1f, 0x0a, 0x40, 0x48, 0x1b, 0x41, 0x2e, 0xc1, 0x7d, 0xf4, 0x03, 0x03,
- 0x8e, 0xef, 0xc1, 0xe8, 0x69, 0x76, 0x65, 0x74, 0x72, 0x61, 0x69, 0x6c,
- 0x2e, 0x62, 0x69, 0xfa, 0xc3, 0x20, 0xae, 0x02, 0x84, 0x65, 0x64, 0x75,
- 0x2e, 0xe1, 0xc2, 0x27, 0x68, 0x69, 0x2e, 0x6e, 0x61, 0x67, 0x61, 0xee,
- 0xc1, 0x6c, 0xe3, 0x04, 0x03, 0x0b, 0xa1, 0xf4, 0xc1, 0x88, 0x6f, 0x75,
- 0x6e, 0x74, 0x61, 0x6e, 0xf4, 0x40, 0x9d, 0xc2, 0x62, 0x69, 0x64, 0x65,
- 0x6e, 0x74, 0xad, 0x02, 0x87, 0x70, 0x72, 0x65, 0x76, 0x65, 0xee, 0x8a,
- 0x69, 0x6e, 0x76, 0x65, 0x73, 0x74, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f,
- 0x6e, 0x2e, 0x61, 0xe5, 0xc1, 0x5e, 0xe5, 0x02, 0x8b, 0x73, 0x73, 0x63,
- 0x61, 0x6d, 0x2e, 0x6f, 0x72, 0xe7, 0xc2, 0xca, 0x6e, 0x74, 0x75, 0xf2,
- 0xc1, 0x5a, 0xe1, 0x03, 0xc1, 0x42, 0x64, 0x65, 0xed, 0x02, 0x8c, 0xf9,
- 0x03, 0xc2, 0xb9, 0x2e, 0x6d, 0x75, 0x73, 0x65, 0xf5, 0xc0, 0x68, 0x69,
- 0x61, 0x2e, 0xe2, 0xc1, 0x30, 0xae, 0x13, 0x05, 0x03, 0x04, 0x05, 0x04,
- 0x05, 0x05, 0x04, 0x0e, 0x10, 0x04, 0x10, 0x08, 0x04, 0x09, 0x03, 0xc0,
- 0x88, 0xfa, 0x2d, 0x1e, 0xc0, 0xb2, 0xf6, 0xc1, 0x66, 0xf5, 0x2f, 0xc2,
- 0x5e, 0xf4, 0x1e, 0x33, 0xc0, 0x9b, 0xf3, 0x19, 0xc0, 0xfe, 0xf2, 0x18,
- 0x07, 0xc1, 0xda, 0xf0, 0x40, 0xe3, 0xc0, 0x4f, 0xee, 0x0b, 0xc0, 0x5a,
- 0xed, 0x07, 0x03, 0x40, 0xd0, 0x2b, 0xc0, 0x7b, 0xfa, 0xc2, 0x6b, 0xf7,
- 0xc2, 0x68, 0xec, 0x03, 0x03, 0x83, 0xf3, 0xc2, 0x61, 0xeb, 0xc2, 0x5e,
- 0x65, 0x67, 0x2e, 0xe2, 0xc1, 0xc8, 0xeb, 0x40, 0xe7, 0xa4, 0xe9, 0x06,
- 0x03, 0x03, 0x40, 0xfb, 0x9f, 0xed, 0xc2, 0x4a, 0xec, 0xc2, 0x47, 0xe4,
- 0xc2, 0x44, 0xe7, 0x03, 0xc1, 0x13, 0x6f, 0xf6, 0xc0, 0xf0, 0x66, 0xea,
- 0xc2, 0x38, 0xe3, 0x05, 0x1e, 0x40, 0xc8, 0x9f, 0xf9, 0xc2, 0x2f, 0xe2,
- 0xc0, 0xbe, 0xe1, 0x40, 0x72, 0xc0, 0x49, 0xe2, 0x0b, 0x16, 0x0b, 0x0c,
- 0x03, 0x0a, 0x0e, 0x0a, 0x05, 0x0e, 0x99, 0xf5, 0x02, 0x87, 0x64, 0x68,
- 0x61, 0x62, 0xe9, 0xc2, 0x11, 0x2e, 0x79, 0x61, 0x6d, 0x61, 0x67, 0x75,
- 0x63, 0x68, 0xe9, 0xc0, 0x62, 0xf2, 0x02, 0x84, 0x75, 0x7a, 0x7a, 0x6f,
- 0x2e, 0xe9, 0xc0, 0x43, 0xef, 0x02, 0x85, 0x67, 0x61, 0xe4, 0xc0, 0x75,
- 0x2e, 0xf0, 0xc0, 0x55, 0xec, 0xc0, 0x7d, 0x6b, 0x68, 0x61, 0x7a, 0x69,
- 0x61, 0x2e, 0xf3, 0xc1, 0x59, 0xe9, 0x02, 0x83, 0x72, 0xe1, 0xae, 0x6b,
- 0x6f, 0x2e, 0x63, 0x68, 0x69, 0xe2, 0x89, 0x65, 0x6e, 0x6f, 0x2e, 0x6f,
- 0x73, 0x61, 0x6b, 0xe1, 0xa5, 0xe3, 0x40, 0x7a, 0xc1, 0x4c, 0xe2, 0x04,
- 0x04, 0xc1, 0xb9, 0x76, 0xe9, 0xc0, 0x4d, 0x6f, 0x74, 0xf4, 0xc1, 0xb6,
- 0xe1, 0x02, 0x91, 0x73, 0x68, 0x69, 0x72, 0x69, 0x2e, 0x68, 0x6f, 0x6b,
- 0x6b, 0x61, 0x69, 0x64, 0x6f, 0x2e, 0xea, 0x92, 0x72, 0x74, 0xe8, 0xc1,
- 0x9d, 0x2e, 0x63, 0xe1, 0xc1, 0x98, 0xe1, 0x03, 0x0b, 0x83, 0xf2, 0x02,
- 0x83, 0xf0, 0xc1, 0x8e, 0x62, 0x6f, 0x72, 0x74, 0x65, 0x2e, 0xee, 0x88,
- 0xe1, 0x03, 0xc1, 0x80, 0x2e, 0x70, 0x72, 0xef, 0xc1, 0x7c, 0xae, 0x05,
- 0x09, 0x09, 0xc1, 0x60, 0xf3, 0x02, 0x83, 0x73, 0xec, 0x91, 0xe5, 0xc1,
- 0x6d, 0x72, 0x75, 0x6e, 0x2e, 0x61, 0x70, 0xf0, 0xc1, 0x60, 0x70, 0x72,
- 0x6f, 0x64, 0x2e, 0x66, 0x61, 0x73, 0x74, 0x6c, 0xf9, 0xc1, 0x33, 0xb9,
- 0x03, 0xc1, 0x4e, 0x67, 0x75, 0x61, 0x63, 0x75, 0x2e, 0x62, 0xf2, 0xc1,
- 0x49, 0xb8, 0xc1, 0x43, 0xb7, 0xc1, 0x40, 0xb6, 0x05, 0x03, 0x0a, 0xc1,
- 0x2b, 0xb4, 0xc0, 0x58, 0x31, 0x31, 0x2e, 0xf4, 0xc0, 0xf9, 0xb5, 0x03,
- 0xc1, 0x2b, 0x67, 0x2e, 0x69, 0xee, 0xc1, 0x2a, 0xb4, 0x04, 0x03, 0xc1,
- 0x1d, 0xf5, 0xc1, 0x1a, 0x6c, 0x69, 0x6d, 0xe1, 0xc0, 0x4f, 0xb3, 0x04,
- 0x0b, 0xc1, 0x07, 0x75, 0x74, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0xf3,
- 0xc1, 0x04, 0xb2, 0xa7, 0xb2, 0x04, 0x03, 0xc0, 0xca, 0x69, 0xf8, 0xb4,
- 0xb0, 0x02, 0x86, 0x33, 0x38, 0x2e, 0xe9, 0xc0, 0xbe, 0x30, 0x30, 0x2e,
- 0x68, 0xf5, 0xc0, 0xf2, 0xb1, 0x06, 0x06, 0x05, 0x0c, 0xc0, 0x9c, 0x6b,
- 0x61, 0x70, 0xf0, 0xc0, 0xdd, 0x36, 0x2d, 0xe2, 0xc0, 0x95, 0x33, 0x33,
- 0x37, 0x2e, 0x70, 0x69, 0x63, 0x74, 0x75, 0xf2, 0xc0, 0x64, 0xb2, 0x02,
- 0x86, 0x68, 0x70, 0xae, 0x1e, 0x0e, 0x82, 0xb3, 0x06, 0x27, 0x16, 0x0d,
- 0x16, 0x8d, 0x77, 0x65, 0x62, 0xf3, 0x02, 0x95, 0x69, 0x74, 0x65, 0xae,
- 0x04, 0x04, 0x02, 0x84, 0x6e, 0xec, 0xc0, 0xae, 0xec, 0xa7, 0x63, 0xe8,
- 0xc0, 0xa8, 0xe2, 0xc0, 0x44, 0x65, 0x69, 0x74, 0x65, 0xae, 0x02, 0x82,
- 0xe4, 0xba, 0xe1, 0xc0, 0x7c, 0xf3, 0x02, 0x8b, 0x69, 0x74, 0x65, 0x77,
- 0x65, 0x62, 0x2e, 0x66, 0xf2, 0xc0, 0x8b, 0x61, 0x69, 0x74, 0x2e, 0x72,
- 0xf5, 0xc0, 0x83, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x77, 0x65, 0x62,
- 0x2e, 0xf0, 0xc0, 0x59, 0x6d, 0xe9, 0x02, 0x88, 0x77, 0x65, 0x62, 0x2e,
- 0x65, 0xf3, 0xc0, 0x6a, 0x6e, 0x73, 0x69, 0x64, 0x61, 0x2e, 0x73, 0xe5,
- 0xc0, 0x60, 0x6b, 0x6f, 0x74, 0x69, 0x73, 0x69, 0x76, 0x75, 0x2e, 0x66,
- 0xe9, 0xc0, 0x53, 0xe8, 0x02, 0x8a, 0x6f, 0x6d, 0x65, 0x70, 0x61, 0x67,
- 0x65, 0x2e, 0xe9, 0xa8, 0x6a, 0x65, 0x6d, 0x6d, 0x65, 0x73, 0x69, 0x64,
- 0x65, 0xae, 0x02, 0x83, 0x6e, 0xef, 0xb6, 0x64, 0xeb, 0xb3, 0xae, 0x02,
- 0xb1, 0x61, 0x7a, 0x75, 0x72, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63,
- 0x61, 0x70, 0x70, 0x73, 0x2e, 0x6e, 0x65, 0xf4, 0x9c, 0xb0, 0x03, 0x0e,
- 0x8a, 0xe5, 0x02, 0x87, 0x6d, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x8a, 0x2e,
- 0x76, 0xe3, 0x8a, 0x30, 0x31, 0x77, 0x77, 0x77, 0x2e, 0x63, 0x6f, 0x6d,
- 0x88, 0x2e, 0x62, 0x67, 0x84, 0x01,
+ 0x02, 0x81, 0x73, 0x79, 0x2e, 0xf5, 0xd9, 0x5f, 0x61, 0xf0, 0x5a, 0x07,
+ 0xc0, 0xfb, 0xe1, 0x07, 0x0b, 0x10, 0x49, 0x75, 0xcf, 0xa8, 0xf2, 0x02,
+ 0x85, 0x74, 0x65, 0xf2, 0xd8, 0x13, 0xe9, 0xc9, 0x5b, 0xee, 0x03, 0xd5,
+ 0xb5, 0x6e, 0x65, 0xec, 0x03, 0xda, 0xe1, 0x73, 0x64, 0x76, 0xf2, 0xda,
+ 0xb9, 0xed, 0x02, 0x8a, 0x70, 0x69, 0x6f, 0x6e, 0x73, 0x68, 0x69, 0xf0,
+ 0xd7, 0xf3, 0x62, 0x61, 0x67, 0x72, 0xe9, 0xda, 0x37, 0xae, 0x05, 0x54,
+ 0x63, 0xc4, 0x5c, 0xf4, 0x03, 0xda, 0xae, 0x72, 0x65, 0x6e, 0x64, 0x68,
+ 0x6f, 0x73, 0x74, 0x69, 0x6e, 0xe7, 0xc2, 0xd2, 0xe6, 0x07, 0x58, 0x5c,
+ 0x40, 0xa5, 0xc1, 0xa7, 0x2d, 0x69, 0x70, 0xe6, 0xd9, 0x88, 0xe5, 0x08,
+ 0x12, 0x11, 0x0d, 0x4b, 0x88, 0xcd, 0x56, 0x73, 0x65, 0x6e, 0xe1, 0x02,
+ 0x81, 0x2d, 0x66, 0x6f, 0x72, 0xec, 0x03, 0xd2, 0x27, 0x1f, 0xc3, 0xca,
+ 0xfc, 0xf2, 0x03, 0xd9, 0x49, 0xf4, 0x02, 0x84, 0x6d, 0xe7, 0xc2, 0x45,
+ 0x69, 0x66, 0x69, 0xe3, 0xd7, 0x96, 0x6e, 0xf4, 0x03, 0xc6, 0xd1, 0x72,
+ 0x61, 0x6c, 0x75, 0x73, 0xae, 0xda, 0x38, 0x63, 0x68, 0x69, 0xf2, 0xd2,
+ 0xba, 0xe4, 0x04, 0x27, 0xda, 0x37, 0xee, 0x03, 0x08, 0x95, 0x37, 0x37,
+ 0x2d, 0x73, 0x73, 0xec, 0xda, 0x30, 0x2e, 0x70, 0x72, 0x6f, 0x64, 0x2e,
+ 0x61, 0x74, 0x6c, 0x61, 0x73, 0x73, 0x69, 0x61, 0x6e, 0x2d, 0x64, 0x65,
+ 0xf6, 0xda, 0x1b, 0x2d, 0x65, 0x64, 0xe7, 0xcb, 0xc0, 0xae, 0xd3, 0xd8,
+ 0xe3, 0x04, 0x03, 0xda, 0x2c, 0xe9, 0xcc, 0x50, 0xae, 0x13, 0x06, 0x06,
+ 0x05, 0x07, 0x04, 0x03, 0x04, 0x05, 0x17, 0x0a, 0x02, 0x06, 0x0b, 0x05,
+ 0x06, 0x02, 0x09, 0x8d, 0xf7, 0x32, 0x1b, 0x2e, 0xd0, 0xde, 0xf6, 0x40,
+ 0x6f, 0x06, 0xd0, 0xde, 0xf5, 0x40, 0x69, 0xc9, 0x57, 0xf4, 0x03, 0xc0,
+ 0x41, 0xf8, 0xd4, 0x5d, 0xf3, 0x40, 0x40, 0x96, 0xf2, 0xd1, 0x3d, 0xf0,
+ 0x40, 0x5c, 0x8f, 0xef, 0x18, 0x40, 0x4f, 0x86, 0xee, 0x0a, 0x03, 0x03,
+ 0x03, 0x12, 0x0b, 0x13, 0x03, 0xd8, 0x02, 0xf6, 0xd4, 0x3f, 0xed, 0xd4,
+ 0x3c, 0xea, 0xd4, 0x39, 0xe8, 0xd4, 0x36, 0xed, 0x16, 0x03, 0x13, 0x0a,
+ 0x03, 0x03, 0x0c, 0xd0, 0xd2, 0xec, 0xb2, 0xeb, 0x02, 0xba, 0xf9, 0xd4,
+ 0x24, 0xe9, 0x04, 0x03, 0x23, 0x92, 0xee, 0xd4, 0x1c, 0xe4, 0xd4, 0x19,
+ 0xe8, 0x45, 0x75, 0xcb, 0x88, 0xe7, 0x02, 0x98, 0xf5, 0xd4, 0x0e, 0xe6,
+ 0xa6, 0xe4, 0x02, 0x83, 0xe5, 0xd4, 0x06, 0xe3, 0xd4, 0x03, 0xe3, 0x03,
+ 0x03, 0x83, 0xf4, 0xd3, 0xfc, 0xef, 0xd3, 0xf9, 0xe1, 0xd3, 0xf6, 0xe1,
+ 0x05, 0x03, 0x03, 0x03, 0x83, 0xfa, 0xd3, 0xed, 0xf3, 0xd3, 0xea, 0xf2,
+ 0xd3, 0xe7, 0xec, 0xd3, 0xe4, 0xeb, 0xd3, 0xe1, 0xe2, 0x09, 0x56, 0xb3,
+ 0x40, 0xc4, 0x40, 0x5c, 0xc0, 0x6d, 0xe7, 0xd8, 0xef, 0xe1, 0x14, 0x05,
+ 0x2e, 0x1d, 0x40, 0x5a, 0x16, 0x04, 0x1d, 0x40, 0x4b, 0x1e, 0x05, 0x07,
+ 0x07, 0x0d, 0x08, 0x1c, 0xd7, 0xd4, 0x78, 0x69, 0xe1, 0xc0, 0xfc, 0xf4,
+ 0x07, 0x0b, 0x05, 0x09, 0x0a, 0xd9, 0x32, 0x68, 0x6f, 0x6c, 0x69, 0xe3,
+ 0x03, 0xd9, 0x4d, 0xae, 0xd6, 0x2f, 0x66, 0x6f, 0xef, 0xd8, 0x4b, 0x65,
+ 0x72, 0x69, 0x6e, 0xe7, 0x56, 0x63, 0xc2, 0xdd, 0x61, 0xee, 0x03, 0xd2,
+ 0xa7, 0x7a, 0x61, 0xf2, 0xd7, 0x30, 0xae, 0xc7, 0xc4, 0xf3, 0x05, 0x07,
+ 0x07, 0xd6, 0x8b, 0x69, 0x6e, 0xef, 0x58, 0x24, 0xc1, 0x02, 0xe5, 0x03,
+ 0xd9, 0x1e, 0xf2, 0xd0, 0xa9, 0xe1, 0x03, 0xd9, 0x17, 0x63, 0x61, 0xed,
+ 0xd8, 0xf0, 0xf2, 0x0a, 0x14, 0x04, 0x0a, 0x03, 0x12, 0x56, 0x67, 0xc2,
+ 0x69, 0xf2, 0x02, 0x85, 0x64, 0x2e, 0xe3, 0xd8, 0xc6, 0x61, 0x72, 0xe1,
+ 0x02, 0x81, 0x2d, 0x6d, 0x61, 0x73, 0xf3, 0xd2, 0x66, 0x67, 0xef, 0xd6,
+ 0x14, 0xe5, 0x03, 0xd8, 0xeb, 0x65, 0xf2, 0x56, 0x80, 0xc2, 0x69, 0xe4,
+ 0xd6, 0x7b, 0x62, 0x6f, 0x6e, 0x69, 0xe1, 0x02, 0x81, 0x2d, 0x69, 0x67,
+ 0x6c, 0x65, 0x73, 0x69, 0x61, 0xf3, 0xd6, 0xcf, 0xe1, 0x02, 0x83, 0xf6,
+ 0xd4, 0x8d, 0x63, 0x61, 0x6c, 0x2e, 0x6d, 0x79, 0x74, 0x68, 0x69, 0x63,
+ 0x2d, 0x62, 0x65, 0x61, 0x73, 0xf4, 0xd7, 0x9e, 0xf0, 0x03, 0x04, 0x88,
+ 0x6f, 0xef, 0xd7, 0xb7, 0x69, 0x74, 0x61, 0xec, 0x42, 0x8d, 0xd6, 0x1f,
+ 0x65, 0x74, 0x6f, 0xf7, 0xd7, 0x6a, 0x6f, 0xe2, 0xcf, 0xf1, 0xee, 0x05,
+ 0x0d, 0x05, 0xd1, 0x28, 0x76, 0x61, 0x2d, 0x61, 0x70, 0x70, 0x73, 0x2e,
+ 0xe3, 0x44, 0x49, 0xd4, 0x40, 0x74, 0x68, 0xef, 0xcf, 0xdc, 0x64, 0x79,
+ 0xf0, 0xc9, 0x7a, 0xed, 0x09, 0x38, 0x04, 0x48, 0x31, 0x4e, 0x07, 0xc2,
+ 0x03, 0xf0, 0x05, 0x07, 0x1f, 0xd8, 0x4b, 0x6f, 0x62, 0x61, 0x73, 0xf3,
+ 0xd6, 0x68, 0xe9, 0x02, 0x8f, 0x6e, 0xe1, 0x02, 0x83, 0xf3, 0xd7, 0x07,
+ 0x67, 0x72, 0x61, 0x6e, 0x64, 0xe5, 0xd6, 0xff, 0x64, 0x61, 0x6e, 0xef,
+ 0x02, 0x81, 0x2d, 0x6d, 0x65, 0x64, 0xe9, 0xd6, 0x49, 0xe1, 0x02, 0x83,
+ 0xee, 0xd1, 0xb7, 0x69, 0x67, 0x6e, 0xae, 0xce, 0xb1, 0x65, 0xf2, 0xd6,
+ 0x96, 0x64, 0x76, 0xf2, 0xd5, 0x68, 0xec, 0x09, 0x08, 0x08, 0x55, 0xcd,
+ 0x40, 0x4c, 0xc2, 0x03, 0x76, 0x69, 0x6e, 0x6b, 0x6c, 0xe5, 0xd6, 0xeb,
+ 0x74, 0x61, 0x6e, 0x69, 0x73, 0xf3, 0xcf, 0xa8, 0x61, 0xe2, 0xd1, 0x89,
+ 0x68, 0x63, 0xe5, 0xcf, 0xc5, 0x67, 0x6c, 0x69, 0x61, 0xf2, 0xcf, 0xaa,
+ 0xe6, 0x03, 0xd6, 0x8c, 0xea, 0xd6, 0xeb, 0xe2, 0x03, 0xd8, 0x01, 0x6c,
+ 0x65, 0x2d, 0x6d, 0x6f, 0x64, 0xe5, 0xd5, 0x29, 0x61, 0xae, 0x03, 0xd5,
+ 0x17, 0xec, 0xd7, 0x9a, 0xae, 0x08, 0x0e, 0x51, 0x7b, 0x41, 0x5a, 0xc1,
+ 0x1d, 0x72, 0x65, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x2e, 0x63, 0x6c, 0x6f,
+ 0xf5, 0xcb, 0xa6, 0xe9, 0x56, 0x1a, 0xc0, 0x84, 0x2d, 0x63, 0x65, 0x6e,
+ 0x74, 0x72, 0x61, 0xec, 0xce, 0x74, 0x36, 0xb6, 0xc1, 0xc3, 0xae, 0x07,
+ 0x42, 0xc0, 0x43, 0x98, 0xd1, 0x64, 0x63, 0x64, 0x6e, 0x37, 0xb7, 0xd4,
+ 0xe9, 0xe2, 0x24, 0x35, 0x17, 0x21, 0x40, 0x84, 0x05, 0x13, 0x40, 0x96,
+ 0x0c, 0x40, 0xe0, 0x15, 0x19, 0x41, 0x52, 0x1b, 0x41, 0x0c, 0x0d, 0x09,
+ 0x40, 0xe0, 0x08, 0x25, 0x10, 0x42, 0x52, 0x09, 0x43, 0xe9, 0x47, 0x2d,
+ 0xc1, 0x4c, 0x1f, 0xc3, 0x04, 0x0a, 0x05, 0x91, 0xf8, 0x02, 0x83, 0xed,
+ 0xcf, 0x3b, 0xae, 0x42, 0x72, 0x86, 0x66, 0x72, 0xf5, 0xcb, 0xd3, 0xe5,
+ 0x02, 0x83, 0xf4, 0xc6, 0x6e, 0x64, 0x1f, 0x43, 0x65, 0x64, 0x64, 0x6a,
+ 0x1f, 0xc3, 0xd5, 0xd8, 0xe1, 0x05, 0x03, 0x48, 0x06, 0x8c, 0xec, 0xc4,
+ 0xd2, 0x69, 0x64, 0x1f, 0xc3, 0xc8, 0x0b, 0xfa, 0x07, 0x54, 0xc5, 0x40,
+ 0x8d, 0xc2, 0x03, 0x7a, 0x2e, 0x64, 0x61, 0x70, 0x70, 0x73, 0x2e, 0x65,
+ 0x61, 0x72, 0x74, 0xe8, 0xd7, 0x36, 0xf9, 0x07, 0x04, 0x03, 0x03, 0x06,
+ 0xd7, 0x2e, 0x74, 0xef, 0xca, 0xd3, 0xeb, 0xc7, 0x83, 0xe7, 0xca, 0x7f,
+ 0x65, 0x6e, 0x2e, 0xf3, 0xc6, 0xad, 0x64, 0x67, 0x6f, 0x73, 0x7a, 0x63,
+ 0xfa, 0xd2, 0x6c, 0xf5, 0x0b, 0x09, 0x0e, 0x03, 0x12, 0x18, 0x04, 0x06,
+ 0x25, 0xd5, 0x11, 0xfa, 0x03, 0xd4, 0xa2, 0x65, 0x6e, 0xae, 0xcb, 0x84,
+ 0xf9, 0x03, 0xd7, 0x0c, 0x73, 0x68, 0xef, 0x03, 0xc7, 0xfe, 0x75, 0xf3,
+ 0xc8, 0x8b, 0xf4, 0xd6, 0x06, 0xf3, 0x02, 0x89, 0x69, 0x6e, 0x65, 0x73,
+ 0xf3, 0x55, 0xbb, 0xc1, 0x3c, 0x61, 0x6e, 0x2e, 0xeb, 0xd5, 0x96, 0xee,
+ 0x02, 0x84, 0x6b, 0xf9, 0xd0, 0xe3, 0x67, 0xef, 0x02, 0x88, 0x74, 0x61,
+ 0x6b, 0x61, 0x64, 0xe1, 0xc4, 0xff, 0x6f, 0x6e, 0xef, 0xc4, 0xfa, 0x6c,
+ 0xf3, 0xc7, 0x30, 0x6b, 0x68, 0x61, 0xf2, 0xd4, 0xe2, 0x69, 0xec, 0x02,
+ 0x8a, 0x74, 0x77, 0x69, 0x74, 0x68, 0x64, 0x61, 0xf2, 0xd2, 0xcb, 0xe4,
+ 0x04, 0x0c, 0xd6, 0xac, 0x65, 0xf2, 0x03, 0xd4, 0x4a, 0x2e, 0x63, 0x6f,
+ 0x64, 0xe5, 0xd6, 0x98, 0x2e, 0x72, 0x75, 0xee, 0xd6, 0x96, 0x64, 0x65,
+ 0xea, 0xd0, 0x31, 0xf4, 0x54, 0x9d, 0xc2, 0x03, 0xf3, 0x06, 0x09, 0x54,
+ 0x89, 0xc2, 0x03, 0x73, 0x2e, 0x64, 0x65, 0x73, 0x69, 0xe7, 0xc2, 0x48,
+ 0xe2, 0xd5, 0x30, 0xf2, 0x0a, 0x09, 0x09, 0x0e, 0x31, 0x12, 0x0d, 0x16,
+ 0xd5, 0xf8, 0x1f, 0x43, 0x78, 0x6e, 0x6e, 0x1f, 0x43, 0xf8, 0xb4, 0xf9,
+ 0x02, 0x83, 0xee, 0xd4, 0xdb, 0xe1, 0xd0, 0x2f, 0xf5, 0x02, 0x85, 0x73,
+ 0x73, 0xe5, 0xc3, 0x52, 0x6d, 0x75, 0x6e, 0xe4, 0xcf, 0x44, 0xef, 0x05,
+ 0x0f, 0x04, 0x0a, 0x89, 0x77, 0x73, 0x65, 0x72, 0x73, 0x61, 0x66, 0x65,
+ 0x74, 0x79, 0x6d, 0x61, 0xf2, 0xcc, 0xdd, 0x74, 0xe8, 0xc2, 0xa7, 0x6e,
+ 0x6e, 0x6f, 0xf9, 0x03, 0xd4, 0xa9, 0xf3, 0xcf, 0xa4, 0x6b, 0xe5, 0x03,
+ 0xc8, 0xa7, 0x2d, 0xe9, 0xc9, 0xe0, 0x61, 0x64, 0xf7, 0xcf, 0x86, 0xe9,
+ 0x02, 0x86, 0x6e, 0x64, 0x69, 0xf3, 0xcd, 0xc2, 0x64, 0x67, 0x65, 0x73,
+ 0x74, 0x6f, 0xee, 0xd4, 0xa1, 0xe5, 0x02, 0x84, 0x73, 0xe3, 0xcf, 0x86,
+ 0x6d, 0x61, 0x6e, 0xe7, 0xca, 0x67, 0xe1, 0x03, 0x09, 0x84, 0x73, 0x69,
+ 0x6c, 0x69, 0x61, 0x2e, 0xed, 0xd5, 0x9e, 0x6e, 0xe4, 0xc4, 0x98, 0x64,
+ 0x65, 0xf3, 0xcb, 0x86, 0xae, 0x53, 0xf5, 0xc1, 0xfb, 0x70, 0x6c, 0x61,
+ 0x63, 0x65, 0x64, 0xae, 0x55, 0x4c, 0x40, 0x7d, 0x9c, 0xef, 0x13, 0x04,
+ 0x0b, 0x09, 0x14, 0x0d, 0x1c, 0x05, 0x05, 0x3b, 0x03, 0x03, 0x08, 0x09,
+ 0x0a, 0x53, 0x5a, 0xc1, 0xbe, 0x7a, 0xe5, 0xc6, 0x2f, 0xf9, 0x03, 0xd4,
+ 0xd0, 0x66, 0x72, 0x69, 0x65, 0xee, 0xd4, 0xca, 0xf8, 0x03, 0xd5, 0xc0,
+ 0x66, 0x75, 0xf3, 0xcc, 0x1f, 0xf5, 0x02, 0x89, 0x74, 0xe9, 0x03, 0xd4,
+ 0xcd, 0x71, 0xf5, 0xd4, 0x35, 0xee, 0x03, 0xce, 0xce, 0x63, 0xe5, 0xd2,
+ 0x38, 0xf3, 0x02, 0x87, 0xf4, 0x03, 0xce, 0x42, 0xe9, 0xd3, 0x39, 0xe3,
+ 0xd3, 0x0c, 0xef, 0x06, 0x04, 0x54, 0x94, 0xc0, 0xfb, 0x6d, 0xec, 0xce,
+ 0x71, 0xeb, 0x04, 0x08, 0xd5, 0x82, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0xe5,
+ 0xd4, 0x0e, 0x69, 0xee, 0xd5, 0x7f, 0xee, 0x45, 0xcc, 0xcd, 0x65, 0xed,
+ 0x4d, 0x2b, 0xc8, 0x4d, 0xec, 0x06, 0x0e, 0x03, 0x04, 0x04, 0x8a, 0x7a,
+ 0x61, 0x6e, 0xef, 0x03, 0xd3, 0x63, 0x2d, 0x61, 0x6c, 0x74, 0xef, 0xce,
+ 0x55, 0xf4, 0xd4, 0x5c, 0x6f, 0xe7, 0xcd, 0x13, 0x69, 0xf6, 0xd2, 0x9c,
+ 0x65, 0x73, 0x6c, 0x61, 0x77, 0x69, 0x65, 0xe3, 0xd0, 0x91, 0x64, 0x6c,
+ 0x79, 0x67, 0x6f, 0x69, 0x6e, 0x67, 0x6e, 0x6f, 0x77, 0x68, 0x65, 0x72,
+ 0xe5, 0xd2, 0x6b, 0xeb, 0xcf, 0x03, 0xe6, 0xd3, 0x8e, 0x65, 0x68, 0x72,
+ 0x69, 0x6e, 0xe7, 0xc1, 0x8d, 0xe4, 0x03, 0xcc, 0xdb, 0x1f, 0x43, 0xf8,
+ 0xd3, 0x8f, 0xe1, 0x03, 0xcb, 0x9b, 0x76, 0x69, 0x73, 0xf4, 0xcb, 0x9e,
+ 0xae, 0x04, 0x06, 0xd3, 0x0b, 0x74, 0x65, 0x6c, 0xe5, 0xca, 0x7c, 0x6e,
+ 0x6f, 0x72, 0xe4, 0xc8, 0x52, 0xee, 0x06, 0x05, 0x52, 0xf8, 0xc2, 0x03,
+ 0x72, 0x2e, 0xec, 0xc4, 0xb2, 0x70, 0x70, 0x61, 0x72, 0x69, 0x62, 0xe1,
+ 0xd2, 0x8b, 0xed, 0x07, 0x0e, 0x52, 0x6c, 0x07, 0xc2, 0x69, 0x6f, 0x61,
+ 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0xf3, 0xd2, 0x0e,
+ 0xe4, 0xd3, 0x80, 0xec, 0x06, 0x10, 0x41, 0x25, 0xd1, 0x9a, 0xf5, 0x02,
+ 0x84, 0x73, 0xe8, 0xd3, 0xd2, 0xe5, 0x03, 0xd4, 0xc7, 0x62, 0x69, 0xf4,
+ 0xcb, 0x26, 0xef, 0x05, 0x05, 0x07, 0xc1, 0x0a, 0x78, 0x63, 0xed, 0xd3,
+ 0x9d, 0x6f, 0x6d, 0x62, 0x65, 0xf2, 0xd4, 0xb1, 0xe7, 0x06, 0x40, 0xe8,
+ 0x09, 0xd3, 0xb8, 0xf3, 0x04, 0x03, 0xc0, 0xd5, 0xf9, 0xcc, 0xf7, 0x70,
+ 0x6f, 0x74, 0xae, 0x16, 0x03, 0x03, 0x07, 0x08, 0x06, 0x03, 0x05, 0x05,
+ 0x0a, 0x05, 0x03, 0x0a, 0x06, 0x03, 0x04, 0x04, 0x40, 0x54, 0x0b, 0xd2,
+ 0xd9, 0xf6, 0xc0, 0x40, 0xf5, 0xd1, 0xb6, 0xf4, 0x03, 0xc8, 0x48, 0xf7,
+ 0xd4, 0x78, 0xf3, 0x33, 0x51, 0x79, 0x42, 0x68, 0x0d, 0xa0, 0xf2, 0x53,
+ 0xe9, 0x19, 0x0a, 0xaa, 0xf1, 0xc4, 0x20, 0xf0, 0x54, 0x03, 0xc0, 0x44,
+ 0xee, 0x53, 0xb0, 0xc0, 0x78, 0xed, 0x42, 0xee, 0x45, 0x29, 0x12, 0x4b,
+ 0xa5, 0xc0, 0x58, 0xec, 0x53, 0xcc, 0x30, 0xb7, 0xeb, 0xd3, 0xbf, 0xe9,
+ 0x06, 0x53, 0xd7, 0x0a, 0xc0, 0x44, 0xee, 0xd4, 0x41, 0xe8, 0x53, 0xb2,
+ 0x08, 0xc0, 0x50, 0xe7, 0xd3, 0xac, 0xe6, 0x53, 0xa9, 0xb8, 0xe4, 0x53,
+ 0xd0, 0xad, 0xe3, 0x0c, 0x40, 0xf3, 0x42, 0xe7, 0x42, 0xb2, 0x4a, 0x76,
+ 0x42, 0x70, 0x86, 0xef, 0x02, 0xad, 0xed, 0x03, 0xd4, 0x1a, 0xae, 0x08,
+ 0x03, 0x03, 0x03, 0x03, 0x06, 0x05, 0x85, 0xf5, 0xc2, 0xa4, 0xf4, 0xd3,
+ 0x81, 0xee, 0xd1, 0x41, 0xed, 0xd3, 0xea, 0xe5, 0x51, 0x3b, 0x42, 0x5e,
+ 0x8a, 0xe3, 0x42, 0x92, 0xd1, 0x35, 0xe2, 0x42, 0x8d, 0xd0, 0xe0, 0xe1,
+ 0x53, 0x68, 0x88, 0xae, 0x08, 0x03, 0x03, 0x03, 0x50, 0x95, 0xc2, 0xb0,
+ 0xfa, 0xc3, 0xa0, 0xee, 0xd0, 0xc5, 0xeb, 0xd3, 0x80, 0xe9, 0x47, 0xad,
+ 0xcb, 0x82, 0xe2, 0x07, 0x43, 0x8b, 0x4d, 0x7e, 0xc2, 0x68, 0xea, 0xd3,
+ 0xd1, 0xe1, 0x53, 0x1f, 0x40, 0x4e, 0xc0, 0x60, 0x69, 0x74, 0x65, 0xae,
+ 0x03, 0xd0, 0xf6, 0x78, 0xf9, 0xd0, 0xa0, 0x64, 0x6e, 0x73, 0xae, 0x50,
+ 0xee, 0x42, 0xac, 0x9c, 0xae, 0x04, 0x03, 0x03, 0x83, 0xf6, 0xd3, 0x2a,
+ 0xeb, 0xd0, 0xe2, 0xe7, 0xd3, 0x8b, 0xe2, 0x52, 0x1e, 0xb2, 0x63, 0x6b,
+ 0x62, 0x75, 0x73, 0x74, 0xe5, 0xd2, 0x46, 0x61, 0x63, 0xeb, 0x04, 0x06,
+ 0xd3, 0x90, 0x66, 0x72, 0x69, 0xe4, 0xcc, 0xe9, 0x62, 0x61, 0x75, 0x64,
+ 0x63, 0x64, 0xee, 0xd3, 0x65, 0xea, 0x06, 0x04, 0x06, 0x07, 0xd3, 0x6f,
+ 0x75, 0xe7, 0xcd, 0x49, 0x65, 0x72, 0x6b, 0xf2, 0xc6, 0x98, 0x61, 0x72,
+ 0xeb, 0x47, 0xc3, 0xc3, 0x0d, 0xae, 0xce, 0xc6, 0xe9, 0x13, 0x40, 0x5d,
+ 0x18, 0x0d, 0x03, 0x05, 0x22, 0x03, 0x08, 0x05, 0x1d, 0x0d, 0x50, 0x26,
+ 0x40, 0x49, 0xc2, 0x03, 0xfa, 0x04, 0x04, 0xd3, 0x4f, 0x65, 0xee, 0xcd,
+ 0x91, 0xae, 0x18, 0x03, 0x04, 0x03, 0x07, 0x06, 0x05, 0x06, 0x03, 0x03,
+ 0x05, 0x03, 0x03, 0x03, 0x4b, 0x94, 0x43, 0x0b, 0x41, 0xc6, 0x40, 0x5a,
+ 0xc2, 0x08, 0xfa, 0xd0, 0xe3, 0x77, 0xe6, 0xd3, 0x2d, 0xf5, 0xc2, 0xe3,
+ 0xf4, 0x50, 0xeb, 0x40, 0x82, 0xc0, 0x65, 0xf0, 0x50, 0xbe, 0x17, 0xc0,
+ 0xf6, 0xee, 0x51, 0x05, 0xc0, 0xc0, 0xed, 0x4f, 0x5d, 0x41, 0x4c, 0xb9,
+ 0xec, 0xd0, 0xaa, 0xeb, 0xd0, 0xf7, 0xe9, 0x50, 0xc1, 0xc1, 0x12, 0xe7,
+ 0xd2, 0x55, 0xe5, 0xd1, 0x47, 0xe2, 0xc8, 0xa9, 0xe1, 0x50, 0x8c, 0xc2,
+ 0x52, 0xf4, 0x02, 0x85, 0x74, 0x65, 0xf2, 0xd1, 0xfa, 0xe2, 0x02, 0x87,
+ 0x75, 0x63, 0x6b, 0x65, 0xf4, 0xd1, 0xe3, 0x72, 0x69, 0x64, 0xe7, 0xcf,
+ 0x75, 0xf2, 0x04, 0x03, 0xd2, 0x51, 0xeb, 0xce, 0x87, 0x61, 0x74, 0xef,
+ 0xd1, 0x21, 0xf0, 0xc1, 0x94, 0xef, 0x51, 0x77, 0xc1, 0x5b, 0xee, 0x04,
+ 0x18, 0xcb, 0x95, 0xe8, 0x03, 0x05, 0x87, 0x74, 0x68, 0xf5, 0xc3, 0xbd,
+ 0x70, 0x68, 0x75, 0x6f, 0xe3, 0xca, 0x0f, 0xe4, 0x03, 0xc3, 0x7d, 0x75,
+ 0xef, 0xca, 0x05, 0xe7, 0x51, 0x25, 0xc1, 0x8b, 0xeb, 0xd1, 0x2f, 0xe8,
+ 0x03, 0xc7, 0x07, 0x61, 0xf2, 0xd1, 0x67, 0x66, 0x75, 0xeb, 0xd0, 0xbc,
+ 0xe5, 0x05, 0x08, 0x07, 0xd0, 0xd1, 0xf6, 0x02, 0x82, 0x1f, 0x43, 0xe1,
+ 0xca, 0xf3, 0x73, 0x7a, 0x63, 0x7a, 0xe1, 0xc0, 0x88, 0xec, 0x03, 0xc8,
+ 0x3e, 0x61, 0xf7, 0xc3, 0x9d, 0xe2, 0x04, 0x03, 0xd0, 0x84, 0xe1, 0xd0,
+ 0xc3, 0xae, 0x47, 0x89, 0xc9, 0x93, 0x61, 0xec, 0x02, 0x87, 0x79, 0x73,
+ 0x74, 0x6f, 0xeb, 0xcd, 0xae, 0x6f, 0x77, 0x69, 0x65, 0xfa, 0xc3, 0x7e,
+ 0xe8, 0x04, 0x03, 0xd2, 0x58, 0xfa, 0xd0, 0xff, 0x61, 0x72, 0xf4, 0xd0,
+ 0x3c, 0xe7, 0x03, 0xd2, 0x4f, 0xae, 0x4b, 0xf0, 0xc4, 0x5c, 0xe5, 0x0e,
+ 0x2d, 0x11, 0x1d, 0x07, 0x11, 0x13, 0x05, 0x09, 0x08, 0x06, 0x23, 0xd1,
+ 0x76, 0xf4, 0x05, 0x0c, 0x17, 0xd2, 0x12, 0x74, 0x65, 0x72, 0x2d, 0x74,
+ 0x68, 0x61, 0x6e, 0x2e, 0xf4, 0xc4, 0x92, 0xe1, 0x02, 0x87, 0x69, 0x6e,
+ 0x61, 0x62, 0xef, 0xc8, 0x28, 0xae, 0x03, 0xcb, 0x3a, 0x74, 0x61, 0x69,
+ 0x6c, 0x73, 0x63, 0xe1, 0xc3, 0xb1, 0x2e, 0xe1, 0xd0, 0xb7, 0xf3, 0x02,
+ 0x88, 0xf4, 0x03, 0xd2, 0x07, 0x62, 0xf5, 0xcf, 0xce, 0x6b, 0x69, 0x64,
+ 0xf9, 0xcd, 0x44, 0xf2, 0x02, 0x90, 0xec, 0x03, 0xd0, 0xbb, 0x65, 0xf6,
+ 0x02, 0x85, 0x1f, 0x43, 0xe5, 0xcb, 0x00, 0xe1, 0xca, 0xfd, 0xe7, 0x05,
+ 0x42, 0x68, 0xcd, 0xe7, 0x61, 0xed, 0xcf, 0xde, 0x70, 0x70, 0x75, 0x2e,
+ 0xef, 0xcb, 0xc9, 0xee, 0x02, 0x8a, 0xf4, 0x02, 0x84, 0x72, 0xe5, 0xc9,
+ 0x25, 0xec, 0xc5, 0x54, 0x65, 0xf6, 0xcd, 0x51, 0xec, 0x05, 0x04, 0x03,
+ 0xc0, 0x8b, 0x6c, 0xf5, 0xc6, 0x5d, 0xe5, 0xce, 0x65, 0x61, 0x75, 0x2e,
+ 0xf0, 0xcf, 0x47, 0x69, 0x61, 0xf2, 0xcb, 0x7d, 0x67, 0x65, 0x74, 0x2e,
+ 0x61, 0x70, 0xf0, 0xd1, 0x97, 0xe5, 0x03, 0xd0, 0x4a, 0x70, 0xae, 0xc6,
+ 0xcb, 0x64, 0x7a, 0x69, 0xee, 0xcc, 0xe0, 0xe1, 0x05, 0x04, 0x10, 0xc7,
+ 0xfc, 0x75, 0xf4, 0xcf, 0x5a, 0xf2, 0x03, 0xc1, 0x90, 0x61, 0x6c, 0xf6,
+ 0x02, 0x82, 0x1f, 0x43, 0x61, 0x68, 0xeb, 0xc9, 0xe8, 0x67, 0x6c, 0x65,
+ 0x62, 0x6f, 0x61, 0xf2, 0xc7, 0xd2, 0xae, 0x04, 0x04, 0xcb, 0x0f, 0x67,
+ 0xf9, 0xd1, 0x6b, 0xe1, 0xc5, 0x25, 0xe4, 0x02, 0x84, 0x2e, 0xf3, 0xcf,
+ 0xe9, 0x86, 0xe3, 0x06, 0x0e, 0x50, 0x13, 0xc1, 0x39, 0x69, 0x2e, 0x64,
+ 0x6e, 0x73, 0x74, 0x72, 0x61, 0x63, 0x65, 0x2e, 0xf0, 0xc0, 0xd7, 0xae,
+ 0x03, 0xcf, 0xa1, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x2e,
+ 0xf3, 0xd0, 0x92, 0xe2, 0x08, 0x03, 0x45, 0x4e, 0x4a, 0x25, 0xc1, 0xbe,
+ 0xf6, 0xcf, 0x8c, 0x73, 0xae, 0xc3, 0x75, 0xe1, 0x14, 0x05, 0x05, 0x09,
+ 0x34, 0x40, 0xf5, 0x22, 0x0c, 0x40, 0x51, 0x04, 0x08, 0x0c, 0x07, 0x40,
+ 0x40, 0x1d, 0xce, 0xe1, 0x79, 0x65, 0xf2, 0xcf, 0xdb, 0x75, 0x68, 0xe1,
+ 0xcc, 0x0c, 0xf4, 0x02, 0x83, 0xf3, 0xc1, 0x64, 0xef, 0xc5, 0x82, 0xf3,
+ 0x06, 0x04, 0x11, 0x07, 0xce, 0xdf, 0x6b, 0x65, 0xf4, 0x9c, 0xe9, 0x02,
+ 0x86, 0x6c, 0x69, 0x63, 0xe1, 0xc8, 0x7f, 0x63, 0x73, 0x65, 0x72, 0x76,
+ 0xe5, 0xc6, 0xeb, 0x68, 0x6b, 0x69, 0x72, 0xe9, 0xcd, 0x42, 0xe5, 0x02,
+ 0x85, 0x62, 0x61, 0xec, 0xce, 0x8d, 0xae, 0x02, 0x83, 0xf3, 0xc0, 0x57,
+ 0xe5, 0xd0, 0xc4, 0xf2, 0x11, 0x08, 0x40, 0x72, 0x19, 0x17, 0x0e, 0x06,
+ 0x06, 0x03, 0x13, 0x03, 0x03, 0x4e, 0x51, 0xc1, 0x8e, 0xf5, 0x03, 0xc5,
+ 0x0f, 0x65, 0xf2, 0xc8, 0x7c, 0x73, 0xf9, 0x03, 0x0d, 0x86, 0x6f, 0x6e,
+ 0x6c, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0xef, 0x4d, 0x5a, 0xc3, 0x4a, 0x63,
+ 0x65, 0x6e, 0xf4, 0xc6, 0xca, 0xae, 0x10, 0x13, 0x03, 0x03, 0x0a, 0x0e,
+ 0x08, 0x0d, 0x4b, 0x2f, 0x41, 0xcb, 0x42, 0xae, 0xc0, 0x7d, 0xf3, 0x03,
+ 0x07, 0x84, 0x75, 0x70, 0x70, 0x6f, 0xf2, 0xd0, 0x64, 0x69, 0xf4, 0xd0,
+ 0x1c, 0x68, 0xef, 0xcf, 0x84, 0xf0, 0x02, 0xa9, 0xf2, 0xd0, 0x3c, 0xef,
+ 0x03, 0xcd, 0xa3, 0x6e, 0x6c, 0x69, 0xee, 0xd0, 0x08, 0xed, 0x02, 0x84,
+ 0x6f, 0xe2, 0xd0, 0x0e, 0xe5, 0x03, 0xd0, 0x5c, 0xee, 0xcf, 0xd7, 0xe9,
+ 0x03, 0xd0, 0x1e, 0xee, 0x29, 0xd0, 0x2b, 0xe3, 0x04, 0x05, 0xcc, 0xfb,
+ 0x6c, 0x75, 0xe2, 0xd0, 0x49, 0xe1, 0xd0, 0x46, 0xe2, 0xcd, 0x7a, 0x72,
+ 0x65, 0xec, 0x02, 0x81, 0x6c, 0x2d, 0x6f, 0x66, 0x2d, 0x6b, 0x6e, 0x6f,
+ 0x77, 0x6c, 0x65, 0x64, 0x67, 0x65, 0x2e, 0x69, 0x6e, 0xe6, 0xcf, 0xf3,
+ 0x6c, 0x65, 0x74, 0x74, 0xe1, 0x02, 0x87, 0x74, 0x72, 0x61, 0x6e, 0xe9,
+ 0xc9, 0x8c, 0x2d, 0x74, 0x72, 0x61, 0x6e, 0x69, 0xad, 0xc9, 0x83, 0xe9,
+ 0x03, 0xce, 0x0e, 0x61, 0x2d, 0x76, 0x75, 0x6e, 0x67, 0x74, 0xe1, 0xc0,
+ 0xd9, 0x67, 0x61, 0x69, 0xee, 0xcd, 0x9a, 0x65, 0x66, 0x6f, 0xef, 0xce,
+ 0x3f, 0xe4, 0xc9, 0x89, 0xe3, 0x02, 0x8b, 0x6c, 0x61, 0xf9, 0x03, 0xcd,
+ 0x86, 0x63, 0x61, 0xf2, 0xcd, 0xa0, 0x65, 0x6c, 0xef, 0xcc, 0x00, 0xb2,
+ 0xcf, 0xc0, 0xb1, 0xcf, 0xbd, 0xb0, 0xcf, 0xba, 0xee, 0x05, 0x0b, 0x0c,
+ 0xcd, 0x59, 0x7a, 0x61, 0x69, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0xe4, 0xcf,
+ 0xbb, 0xe4, 0x04, 0x03, 0xcf, 0xc3, 0xef, 0xc8, 0x33, 0x61, 0xe9, 0xca,
+ 0x55, 0x61, 0x6d, 0xe5, 0xc8, 0x3a, 0x6d, 0xe2, 0x02, 0x83, 0xec, 0xce,
+ 0x1f, 0x69, 0x6e, 0xe1, 0xce, 0xb5, 0xec, 0x04, 0x1f, 0x11, 0x92, 0xf3,
+ 0x02, 0x83, 0xe6, 0xcb, 0x80, 0x61, 0xee, 0x03, 0xcd, 0x9b, 0x2d, 0xf3,
+ 0x02, 0x84, 0x1f, 0x43, 0xfc, 0x85, 0xf5, 0x02, 0x81, 0x65, 0x64, 0x74,
+ 0x69, 0x72, 0x6f, 0xec, 0xcd, 0x89, 0xec, 0x02, 0x88, 0x6f, 0x6f, 0x6e,
+ 0x69, 0x6e, 0xe7, 0xcc, 0xa4, 0x61, 0x6e, 0x67, 0xe5, 0xc9, 0x46, 0xe5,
+ 0x02, 0x85, 0x73, 0x74, 0xf2, 0xc2, 0xbd, 0x6e, 0x61, 0x2d, 0x64, 0x65,
+ 0x76, 0x69, 0xe3, 0xce, 0x4c, 0xe1, 0x03, 0xc7, 0xc6, 0x73, 0x68, 0x6f,
+ 0xf6, 0xcd, 0x75, 0x6a, 0x64, 0xe4, 0x86, 0x69, 0xe4, 0x03, 0xce, 0x54,
+ 0xe1, 0xc3, 0xab, 0x68, 0xe3, 0x02, 0x81, 0x63, 0x61, 0x76, 0x75, 0x6f,
+ 0xf4, 0xc4, 0x7c, 0x64, 0x61, 0x64, 0x64, 0xea, 0xc9, 0x18, 0xe3, 0x04,
+ 0x06, 0x06, 0xac, 0x6e, 0x69, 0x6e, 0xe8, 0xc6, 0x89, 0x6c, 0x69, 0x65,
+ 0xf5, 0xc6, 0x83, 0xeb, 0x04, 0x13, 0x0a, 0x86, 0x79, 0x61, 0x72, 0x64,
+ 0x73, 0x2e, 0x62, 0x61, 0x6e, 0x7a, 0x61, 0x69, 0x63, 0x6c, 0x6f, 0x75,
+ 0xe4, 0xc0, 0xaa, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x61, 0x70, 0xf0, 0xce,
+ 0x05, 0x64, 0x72, 0x6f, 0xf0, 0xce, 0x0c, 0x61, 0xee, 0xc6, 0x57, 0xe7,
+ 0xc6, 0x50, 0xe2, 0x02, 0x91, 0xf9, 0x04, 0x06, 0xce, 0xf0, 0x6d, 0x69,
+ 0x6c, 0xeb, 0xcd, 0xf7, 0x62, 0x6c, 0x75, 0xe5, 0xcd, 0xf1, 0x69, 0x61,
+ 0x2d, 0x67, 0x6f, 0x72, 0xe1, 0xca, 0x28, 0xae, 0x48, 0x7c, 0x03, 0xc4,
+ 0x5f, 0xae, 0x03, 0xcd, 0x55, 0xe2, 0x4d, 0x7d, 0xc1, 0x58, 0x2d, 0x64,
+ 0x61, 0x74, 0xe1, 0xcd, 0xc5, 0xe1, 0x2c, 0x0c, 0x40, 0x49, 0x21, 0x05,
+ 0x3a, 0x32, 0x41, 0x2d, 0x40, 0x64, 0x41, 0x0e, 0x40, 0xc9, 0x13, 0x41,
+ 0x16, 0x36, 0x41, 0x21, 0x40, 0x99, 0x40, 0xdc, 0x40, 0xb8, 0x03, 0x40,
+ 0xf2, 0x08, 0x40, 0x69, 0x40, 0x4b, 0x3d, 0x40, 0x74, 0x41, 0x14, 0x40,
+ 0x88, 0x9c, 0x1f, 0x43, 0x69, 0x72, 0x6f, 0x70, 0x6f, 0x72, 0x74, 0xae,
+ 0xc2, 0xbd, 0xfa, 0x07, 0x30, 0x07, 0x48, 0xae, 0xc5, 0xa5, 0xf5, 0x02,
+ 0xa7, 0x72, 0xe5, 0x06, 0x09, 0x0e, 0x4e, 0x3a, 0xae, 0x77, 0x65, 0x62,
+ 0x73, 0x69, 0x74, 0xe5, 0xce, 0x53, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69,
+ 0x6e, 0x65, 0x72, 0x2e, 0x69, 0xef, 0xce, 0x58, 0x2d, 0x6d, 0x6f, 0x62,
+ 0x69, 0xec, 0xca, 0xf2, 0x6d, 0x69, 0x6e, 0xef, 0xcb, 0x48, 0x69, 0x6d,
+ 0x75, 0x74, 0xe8, 0xc3, 0x51, 0x65, 0x72, 0x62, 0x61, 0x69, 0x6a, 0x61,
+ 0xee, 0xcc, 0x61, 0x79, 0xe1, 0x04, 0x04, 0x08, 0x87, 0x73, 0xe5, 0xc9,
+ 0x7e, 0x67, 0x61, 0x77, 0x61, 0x2e, 0xeb, 0xc9, 0x7a, 0x62, 0x65, 0x2e,
+ 0x6b, 0xf9, 0xc6, 0xe5, 0x2e, 0x6d, 0x69, 0x79, 0x61, 0xfa, 0xc6, 0x9d,
+ 0xf8, 0x4c, 0x80, 0xc1, 0xa7, 0xf7, 0x05, 0x28, 0x08, 0xcd, 0xed, 0xf3,
+ 0x05, 0x05, 0x12, 0xce, 0x00, 0x6d, 0x70, 0xf0, 0xc7, 0x3d, 0x67, 0x6c,
+ 0x6f, 0x62, 0x61, 0x6c, 0x61, 0x63, 0x63, 0x65, 0x6c, 0x65, 0x72, 0x61,
+ 0x74, 0xef, 0xcd, 0x1c, 0x61, 0x70, 0x70, 0x72, 0x75, 0x6e, 0x6e, 0x65,
+ 0xf2, 0xcd, 0xe1, 0x64, 0x65, 0x76, 0x2e, 0x63, 0xe1, 0xcd, 0xdd, 0x61,
+ 0xea, 0xc9, 0x11, 0xf6, 0x04, 0x14, 0x05, 0x8d, 0xef, 0x02, 0x86, 0x75,
+ 0x65, 0x73, 0xae, 0xc2, 0x00, 0x63, 0x61, 0xf4, 0x03, 0xc3, 0x53, 0xae,
+ 0x4c, 0x47, 0xc0, 0xfc, 0x69, 0x61, 0xee, 0xcc, 0x25, 0xe5, 0x02, 0x85,
+ 0xf2, 0x42, 0x17, 0xc3, 0x0d, 0x6c, 0x6c, 0xe9, 0xc2, 0x5d, 0xae, 0x03,
+ 0xcb, 0xb8, 0xf4, 0xcc, 0x60, 0xf5, 0x0b, 0x40, 0xc2, 0x20, 0x16, 0x04,
+ 0x08, 0x13, 0x05, 0xcc, 0x8f, 0xf4, 0x02, 0x92, 0xef, 0x07, 0x48, 0xe5,
+ 0x42, 0x52, 0xc2, 0x69, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x64, 0x65, 0xf6,
+ 0xcd, 0x94, 0xe8, 0x05, 0x06, 0x15, 0xc0, 0x59, 0x6f, 0xf2, 0x4a, 0xb1,
+ 0xc2, 0xdd, 0x67, 0x65, 0x61, 0xf2, 0x02, 0x85, 0x61, 0x70, 0xf0, 0xcc,
+ 0x65, 0x2d, 0x73, 0x74, 0x61, 0x67, 0x69, 0x6e, 0xe7, 0xcd, 0x6f, 0xae,
+ 0x07, 0x06, 0x07, 0x03, 0x03, 0x0e, 0x8b, 0x75, 0x73, 0xad, 0x40, 0x5a,
+ 0x8d, 0x73, 0x61, 0x2d, 0x65, 0xe1, 0xc0, 0x5b, 0x6d, 0xe5, 0xbb, 0x69,
+ 0xec, 0x91, 0x65, 0x75, 0xad, 0x04, 0x03, 0x07, 0xa7, 0x77, 0xe5, 0xa5,
+ 0x6e, 0x6f, 0xf2, 0xae, 0x63, 0x61, 0x2d, 0x63, 0x65, 0x6e, 0x74, 0x72,
+ 0x61, 0xec, 0xbd, 0xe1, 0x02, 0x9a, 0x70, 0xad, 0x02, 0x87, 0x73, 0x6f,
+ 0x75, 0x74, 0xe8, 0x07, 0xa9, 0x6e, 0x6f, 0x72, 0x74, 0x68, 0x65, 0x61,
+ 0x73, 0x74, 0xad, 0x03, 0x2a, 0x82, 0xb3, 0xac, 0x66, 0x2d, 0x73, 0x6f,
+ 0x75, 0x74, 0xe8, 0x98, 0x2d, 0x66, 0x69, 0x70, 0x73, 0x2e, 0x75, 0x73,
+ 0xad, 0x03, 0x03, 0x8a, 0x77, 0xe5, 0x8d, 0x67, 0x6f, 0x76, 0x2d, 0x77,
+ 0x65, 0x73, 0x74, 0xad, 0x8a, 0x65, 0x61, 0x73, 0x74, 0xad, 0x02, 0x82,
+ 0xb2, 0x82, 0x31, 0x2e, 0x61, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x63, 0x6f,
+ 0x67, 0x6e, 0x69, 0x74, 0xef, 0xcc, 0xe3, 0xf3, 0x03, 0x0b, 0x85, 0xf4,
+ 0x02, 0x85, 0x72, 0x68, 0xe5, 0xc1, 0x32, 0xe5, 0xc1, 0x27, 0x70, 0x6f,
+ 0xf3, 0xcb, 0x19, 0x2e, 0x62, 0x61, 0x73, 0x6b, 0x65, 0x74, 0x62, 0x61,
+ 0xec, 0xcc, 0x18, 0xf2, 0x04, 0x0d, 0xcb, 0x21, 0x73, 0x6b, 0x6f, 0x67,
+ 0x2d, 0xe8, 0x02, 0x84, 0x1f, 0x43, 0xf8, 0x82, 0x6f, 0x6c, 0xe1, 0xc6,
+ 0x1d, 0x6b, 0xf2, 0xc6, 0x89, 0x67, 0x75, 0x73, 0x74, 0x6f, 0xf7, 0xc7,
+ 0xee, 0xe4, 0x02, 0x87, 0x6e, 0x65, 0x64, 0x61, 0xec, 0xc6, 0x6a, 0xe9,
+ 0x05, 0x4b, 0x0c, 0xc1, 0x8b, 0xe2, 0xca, 0xa3, 0x63, 0x74, 0xe9, 0xc5,
+ 0x33, 0xae, 0x43, 0x1c, 0xc3, 0x14, 0xf4, 0x0b, 0x07, 0x0b, 0x03, 0x03,
+ 0x15, 0x0d, 0x04, 0x0e, 0xcc, 0x32, 0x74, 0x6f, 0x72, 0x6e, 0xe5, 0xca,
+ 0x42, 0x73, 0xf5, 0x02, 0x83, 0xed, 0xca, 0x90, 0x67, 0xe9, 0xc7, 0xab,
+ 0xef, 0xcb, 0x10, 0xed, 0xc7, 0xad, 0x6c, 0x2e, 0x6a, 0x65, 0x6c, 0x61,
+ 0x73, 0x74, 0x69, 0x63, 0x2e, 0x76, 0x70, 0x73, 0x2d, 0x68, 0x6f, 0x73,
+ 0xf4, 0xcc, 0x2f, 0xe8, 0x02, 0x85, 0x6c, 0x65, 0xf4, 0xca, 0xa4, 0x2e,
+ 0x63, 0xf8, 0xcc, 0x42, 0x61, 0xed, 0xc1, 0xdf, 0xae, 0x06, 0x03, 0x45,
+ 0xd8, 0xc4, 0x5c, 0xf6, 0xc9, 0x6b, 0x6d, 0xe4, 0xcc, 0x30, 0x2d, 0x62,
+ 0x61, 0x6e, 0x64, 0x2d, 0x63, 0x61, 0x6d, 0xf0, 0xcc, 0x04, 0xf3, 0x12,
+ 0x05, 0x03, 0x40, 0x44, 0x0b, 0x17, 0x03, 0x2d, 0x04, 0x03, 0x0e, 0x40,
+ 0xe8, 0x44, 0xd3, 0xc5, 0xa5, 0x75, 0x6b, 0xe5, 0xc6, 0xc7, 0xf4, 0xc3,
+ 0xa9, 0xf3, 0x05, 0x04, 0x2d, 0x05, 0x84, 0x75, 0xf2, 0xc1, 0x82, 0xef,
+ 0x02, 0x8a, 0x63, 0x69, 0x61, 0xf4, 0x03, 0xc9, 0x17, 0xe5, 0xc9, 0x8d,
+ 0xae, 0x0d, 0x02, 0x04, 0x03, 0x03, 0x03, 0x0d, 0x45, 0x6c, 0x42, 0xdc,
+ 0xc0, 0xbb, 0xee, 0x82, 0x6d, 0xe3, 0xcb, 0xe2, 0xe7, 0xca, 0x42, 0xe6,
+ 0xca, 0x83, 0xe4, 0xc9, 0x66, 0xe3, 0xc9, 0xbd, 0x6e, 0x2e, 0xec, 0xc9,
+ 0x6b, 0x61, 0xe2, 0xc7, 0x18, 0x2e, 0xeb, 0xc9, 0x77, 0xee, 0x03, 0xc7,
+ 0x6f, 0xae, 0x03, 0xc8, 0xa6, 0xec, 0xc8, 0x02, 0xeb, 0x06, 0x05, 0x03,
+ 0x04, 0xc3, 0x06, 0x76, 0x6f, 0xec, 0xc4, 0x98, 0xef, 0xc3, 0x51, 0x69,
+ 0xed, 0xca, 0x16, 0x65, 0xf2, 0xca, 0x12, 0xe9, 0xc9, 0xfd, 0xe8, 0x03,
+ 0x05, 0x9d, 0x6f, 0x72, 0xef, 0xc9, 0xe6, 0xe9, 0x04, 0x0b, 0xc6, 0xd0,
+ 0x79, 0x61, 0xae, 0x03, 0xc6, 0xb6, 0x66, 0x75, 0xeb, 0xc1, 0x2e, 0x6b,
+ 0x61, 0x67, 0x61, 0x2e, 0x74, 0x6f, 0x63, 0x68, 0x69, 0xe7, 0xc9, 0x71,
+ 0x67, 0x61, 0x62, 0x61, 0xe4, 0xc9, 0x8d, 0x65, 0xf2, 0xc4, 0x58, 0xe4,
+ 0xc9, 0xc9, 0x63, 0x6f, 0x6c, 0xe9, 0x02, 0x81, 0x2d, 0x70, 0x69, 0x63,
+ 0x65, 0xee, 0xc9, 0x5e, 0xe1, 0x04, 0x0c, 0x13, 0xa1, 0x6d, 0x69, 0x6e,
+ 0x61, 0x6d, 0x69, 0x2e, 0x68, 0x69, 0xf2, 0xc5, 0x0a, 0xeb, 0x02, 0x86,
+ 0x75, 0x63, 0x68, 0xe9, 0xc5, 0x88, 0xe1, 0x02, 0x84, 0x77, 0xe1, 0xc5,
+ 0xd5, 0xae, 0xc0, 0xd5, 0x68, 0xe9, 0x02, 0x85, 0x6b, 0x61, 0xf7, 0xc9,
+ 0x53, 0xae, 0x09, 0x06, 0x04, 0x43, 0x8e, 0x44, 0x7e, 0xc1, 0x36, 0x79,
+ 0x61, 0x6d, 0xe1, 0xc6, 0xdf, 0x74, 0xef, 0xc5, 0x65, 0x6d, 0xe9, 0xc6,
+ 0x53, 0xe7, 0xc4, 0xe8, 0xf2, 0x11, 0x0b, 0x2d, 0x03, 0x03, 0x08, 0x09,
+ 0x1c, 0x0e, 0x0f, 0x28, 0x43, 0x3a, 0x45, 0x26, 0xc1, 0xf6, 0x76, 0x6f,
+ 0x2e, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0xf2, 0xca, 0xc5, 0xf4, 0x05, 0x0f,
+ 0x05, 0xca, 0xe1, 0x73, 0xae, 0x06, 0x03, 0x40, 0x76, 0xc8, 0xe8, 0xf6,
+ 0xc9, 0x70, 0x6e, 0xe6, 0xca, 0xe8, 0xe5, 0x48, 0x2d, 0xc2, 0xb8, 0xae,
+ 0x07, 0x03, 0x03, 0x47, 0x51, 0xc2, 0x28, 0xf3, 0xc9, 0x9e, 0xf0, 0xca,
+ 0x22, 0xe4, 0x48, 0x5f, 0xc0, 0xe8, 0xf1, 0xc9, 0x72, 0xee, 0xc4, 0xa2,
+ 0xed, 0x03, 0xc8, 0x8d, 0x65, 0xee, 0xc8, 0xd6, 0x6b, 0x68, 0x61, 0x6e,
+ 0x67, 0x65, 0xec, 0xc4, 0x7b, 0xe9, 0x03, 0x03, 0x8d, 0x74, 0xe1, 0x91,
+ 0x64, 0xe1, 0x02, 0x84, 0x67, 0x61, 0x77, 0x61, 0x2e, 0x77, 0xe1, 0xc4,
+ 0xe7, 0x61, 0x6b, 0x65, 0x2e, 0x73, 0xe1, 0xc5, 0x4f, 0xe5, 0x04, 0x03,
+ 0xc8, 0x8d, 0xee, 0xc3, 0x79, 0x6d, 0x61, 0x72, 0xeb, 0xc8, 0xfa, 0x63,
+ 0x68, 0xe9, 0x03, 0xca, 0x87, 0x74, 0x65, 0x63, 0x74, 0x65, 0x73, 0xae,
+ 0xc6, 0x58, 0xe1, 0x05, 0x03, 0x04, 0x0e, 0x8a, 0xef, 0xc3, 0x24, 0x6d,
+ 0xe3, 0xc8, 0xe8, 0x6b, 0x61, 0x77, 0x61, 0xae, 0x03, 0xc7, 0x23, 0x73,
+ 0x61, 0x69, 0xf4, 0xc4, 0xaa, 0x69, 0x2e, 0x73, 0x68, 0x69, 0x7a, 0x75,
+ 0xef, 0xc8, 0x8a, 0xe2, 0xca, 0x58, 0xae, 0x45, 0x51, 0x43, 0x02, 0xc1,
+ 0xfb, 0xf1, 0x05, 0x48, 0x46, 0xc2, 0x03, 0xf5, 0x02, 0x84, 0x69, 0xec,
+ 0xc3, 0xb5, 0x61, 0x72, 0x65, 0xec, 0xc8, 0x4b, 0xf0, 0x06, 0x40, 0x92,
+ 0x18, 0x12, 0x96, 0xf0, 0x08, 0x05, 0x31, 0x07, 0x07, 0x07, 0xc9, 0xe1,
+ 0x75, 0x64, 0xef, 0xca, 0x05, 0xf3, 0x02, 0x9e, 0xf0, 0x02, 0x82, 0xef,
+ 0x90, 0x61, 0x63, 0xe5, 0x02, 0x8d, 0x75, 0x73, 0x65, 0x72, 0x63, 0x6f,
+ 0x6e, 0x74, 0x65, 0x6e, 0xf4, 0xca, 0x07, 0x68, 0x6f, 0x73, 0x74, 0xe5,
+ 0xc4, 0xae, 0xae, 0x02, 0x86, 0x6c, 0x61, 0x69, 0xf2, 0xc8, 0xf7, 0x66,
+ 0x62, 0x73, 0x62, 0xf8, 0xc9, 0xf0, 0xec, 0x03, 0xc8, 0x76, 0x69, 0xee,
+ 0x8b, 0x65, 0x6e, 0x67, 0x69, 0xee, 0xc3, 0x22, 0x63, 0x68, 0x69, 0x7a,
+ 0xe9, 0xc9, 0xdb, 0xae, 0x05, 0x07, 0x18, 0x06, 0x83, 0x72, 0x65, 0x6e,
+ 0x64, 0xe5, 0xc8, 0xf0, 0x6f, 0x73, 0xae, 0x02, 0x84, 0x73, 0x74, 0x67,
+ 0x2e, 0x66, 0x65, 0x64, 0x6f, 0x72, 0x61, 0x70, 0x72, 0x6f, 0x6a, 0x65,
+ 0x63, 0xf4, 0xc6, 0xee, 0x6c, 0x6d, 0x70, 0xed, 0xc9, 0xb0, 0xe7, 0xc8,
+ 0xbc, 0xe2, 0x03, 0xc8, 0x56, 0x61, 0x6e, 0x7a, 0x61, 0x69, 0x63, 0x6c,
+ 0x6f, 0x75, 0xe4, 0xc8, 0x9d, 0xe9, 0x02, 0x85, 0x67, 0x65, 0xe5, 0xc8,
+ 0x95, 0xae, 0x02, 0x88, 0x73, 0x74, 0x64, 0x6c, 0x69, 0xe2, 0xc9, 0x8a,
+ 0x67, 0x6f, 0xf6, 0xc6, 0x3e, 0x61, 0xf2, 0x02, 0x87, 0x74, 0x6d, 0x65,
+ 0x6e, 0xf4, 0xc7, 0x19, 0x65, 0x63, 0x69, 0x64, 0xe1, 0xc8, 0x20, 0xae,
+ 0x06, 0x07, 0x43, 0x07, 0xc4, 0x62, 0x6e, 0x67, 0x72, 0x6f, 0xeb, 0xc8,
+ 0x65, 0x67, 0x6f, 0x76, 0xae, 0x44, 0xe2, 0xc3, 0x2b, 0xad, 0x03, 0x09,
+ 0xaa, 0x73, 0x6f, 0x75, 0x74, 0xe8, 0x02, 0x87, 0xad, 0x93, 0x6e, 0x6f,
+ 0x72, 0x74, 0x68, 0x65, 0x61, 0x73, 0x74, 0xad, 0x03, 0x03, 0x82, 0xb3,
+ 0xc5, 0x44, 0xb2, 0x82, 0x31, 0xae, 0x03, 0xc5, 0x3c, 0x61, 0x69, 0x72,
+ 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x61, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x61,
+ 0x77, 0xf3, 0xc9, 0x18, 0x65, 0x61, 0x73, 0xf4, 0xc5, 0x22, 0xef, 0x0a,
+ 0x13, 0x0f, 0x03, 0x46, 0xa7, 0x40, 0x4c, 0xc2, 0x03, 0x73, 0xf4, 0x03,
+ 0xc2, 0x0e, 0xe1, 0x04, 0x01, 0xc7, 0x0d, 0x2d, 0x76, 0x61, 0x6c, 0x6c,
+ 0x65, 0xf9, 0xc7, 0x07, 0x6d, 0x6f, 0x72, 0x69, 0xae, 0x03, 0xc7, 0x55,
+ 0x61, 0x6f, 0x6d, 0x6f, 0xf2, 0xc6, 0xee, 0xeb, 0xc5, 0xe3, 0x67, 0xe1,
+ 0x41, 0xaf, 0xc1, 0x36, 0xee, 0x0d, 0x04, 0x0c, 0x17, 0x04, 0x0e, 0x40,
+ 0x60, 0x05, 0x45, 0xd1, 0xc0, 0x70, 0x71, 0xf5, 0xc4, 0xa1, 0x70, 0x61,
+ 0x63, 0x68, 0x69, 0x2e, 0x67, 0x69, 0x66, 0xf5, 0xc7, 0x28, 0xee, 0x02,
+ 0x89, 0x61, 0x6b, 0x61, 0x2e, 0x67, 0x75, 0xee, 0xc3, 0x64, 0x2d, 0x61,
+ 0x72, 0x62, 0x6f, 0x72, 0x2e, 0x6d, 0xe9, 0xc3, 0x18, 0x6a, 0xef, 0xc3,
+ 0x70, 0xe7, 0x02, 0x84, 0x72, 0xf9, 0xc7, 0xb7, 0x69, 0x61, 0x6e, 0x67,
+ 0xae, 0xc6, 0x10, 0xe4, 0x05, 0x05, 0x3d, 0x0c, 0x84, 0x1f, 0x43, 0xf8,
+ 0xc0, 0x42, 0xf2, 0x02, 0x84, 0x6f, 0xe9, 0xc6, 0x4d, 0x69, 0xe1, 0x03,
+ 0x06, 0x89, 0x74, 0x72, 0x61, 0x6e, 0xe9, 0x93, 0x62, 0x61, 0x72, 0x6c,
+ 0x65, 0x74, 0x74, 0xe1, 0x9c, 0xad, 0x02, 0x8f, 0x74, 0x72, 0x61, 0x6e,
+ 0x69, 0x2d, 0x62, 0x61, 0x72, 0x6c, 0x65, 0x74, 0xf4, 0xc1, 0xe4, 0x62,
+ 0x61, 0x72, 0x6c, 0x65, 0x74, 0x74, 0x61, 0x2d, 0x74, 0x72, 0x61, 0x6e,
+ 0xe9, 0xc6, 0x60, 0xef, 0x02, 0x83, 0xf9, 0xc6, 0xc8, 0x2e, 0x6e, 0x61,
+ 0xf2, 0xc6, 0x87, 0x65, 0xe2, 0xc1, 0xe2, 0x61, 0x73, 0x75, 0x6f, 0x6c,
+ 0xef, 0xc6, 0xb6, 0x63, 0x6f, 0xee, 0xc1, 0xb7, 0xe1, 0x03, 0x0b, 0x8c,
+ 0xee, 0x02, 0x83, 0xe9, 0xc6, 0xe1, 0xae, 0x42, 0xc5, 0xc2, 0x61, 0x6d,
+ 0x69, 0x7a, 0x75, 0x2e, 0x69, 0x73, 0x68, 0x69, 0xeb, 0xc3, 0x98, 0x6c,
+ 0x79, 0x74, 0x69, 0x63, 0xf3, 0x03, 0xc8, 0x20, 0x2d, 0x67, 0x61, 0x74,
+ 0x65, 0x77, 0x61, 0x79, 0xae, 0x03, 0x0b, 0x92, 0x75, 0x73, 0xad, 0x02,
+ 0xab, 0x77, 0x65, 0x73, 0x74, 0xad, 0xad, 0x65, 0x75, 0xad, 0x02, 0x85,
+ 0x77, 0x65, 0x73, 0xf4, 0x95, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x61, 0xec,
+ 0x8d, 0x61, 0x70, 0xad, 0x02, 0x89, 0x73, 0x6f, 0x75, 0x74, 0xe8, 0x02,
+ 0x87, 0xad, 0x8f, 0x6e, 0x6f, 0x72, 0x74, 0x68, 0x65, 0x61, 0x73, 0x74,
+ 0xad, 0x02, 0x82, 0xb2, 0x82, 0x31, 0x2e, 0x61, 0x6d, 0x61, 0x7a, 0x6f,
+ 0x6e, 0x61, 0xf7, 0xc6, 0xb5, 0xed, 0x0d, 0x08, 0x11, 0x0a, 0x04, 0x04,
+ 0x0d, 0x04, 0x1c, 0x04, 0x28, 0xc7, 0x3d, 0x75, 0x73, 0x65, 0x6d, 0x65,
+ 0xee, 0xc2, 0xb3, 0xf3, 0x02, 0x85, 0x74, 0x65, 0x72, 0xe4, 0xaa, 0x63,
+ 0x6f, 0x6d, 0x70, 0x75, 0x74, 0xe5, 0xc7, 0xa2, 0x70, 0x6c, 0x69, 0x66,
+ 0x79, 0x61, 0x70, 0xf0, 0xc7, 0x8a, 0x6f, 0xf4, 0xc6, 0x07, 0x6c, 0xe9,
+ 0xc6, 0x03, 0xe9, 0x03, 0xc5, 0xea, 0x2e, 0x69, 0x62, 0x61, 0x72, 0x61,
+ 0xeb, 0xc5, 0x7e, 0x66, 0xe1, 0xc5, 0x35, 0xe5, 0x02, 0x83, 0xf8, 0xc7,
+ 0x81, 0x72, 0x69, 0x63, 0x61, 0xee, 0x02, 0x87, 0x66, 0x61, 0x6d, 0x69,
+ 0xec, 0xc5, 0x3c, 0x65, 0x78, 0x70, 0x72, 0x65, 0xf3, 0xc5, 0x02, 0x62,
+ 0xf5, 0xc2, 0x81, 0xe1, 0x05, 0x04, 0x04, 0x0e, 0x87, 0x7a, 0xef, 0xc6,
+ 0x23, 0x6d, 0xe9, 0xc1, 0x0e, 0x6b, 0x75, 0x73, 0x61, 0x2e, 0x6b, 0x75,
+ 0x6d, 0x61, 0x6d, 0x6f, 0xf4, 0xc5, 0x9e, 0x67, 0x61, 0x73, 0x61, 0xeb,
+ 0xc2, 0x6a, 0xae, 0x41, 0x8c, 0xc0, 0x6d, 0xae, 0x40, 0xd8, 0x03, 0x45,
+ 0x07, 0x9f, 0xec, 0x0e, 0x0a, 0x06, 0x1b, 0x13, 0x2a, 0x12, 0x0c, 0x04,
+ 0x11, 0x0d, 0x11, 0xc6, 0x6e, 0x77, 0x61, 0x79, 0x73, 0x64, 0x61, 0x74,
+ 0xe1, 0xc6, 0xfb, 0x76, 0x64, 0x61, 0xec, 0xc5, 0x84, 0xf4, 0x06, 0x0b,
+ 0x40, 0xdd, 0xc1, 0xb5, 0xef, 0x02, 0x81, 0x2d, 0x61, 0x64, 0x69, 0x67,
+ 0xe5, 0xc5, 0x04, 0x65, 0x72, 0x76, 0x69, 0x73, 0x74, 0xe1, 0xc4, 0x2e,
+ 0xf3, 0x02, 0x8d, 0xf4, 0x02, 0x83, 0xef, 0xc4, 0xa3, 0x61, 0x68, 0x61,
+ 0x75, 0xe7, 0xc5, 0x59, 0xe1, 0xc1, 0xdc, 0xf0, 0x02, 0x9b, 0x68, 0xe1,
+ 0x02, 0x8e, 0x2e, 0x62, 0x6f, 0x75, 0x6e, 0x74, 0x79, 0x2d, 0x66, 0x75,
+ 0x6c, 0xec, 0xc6, 0xce, 0x2d, 0x6d, 0x79, 0x71, 0x6e, 0x61, 0xf0, 0xc1,
+ 0x6f, 0x31, 0x2e, 0x61, 0x65, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0xae, 0xc6,
+ 0x13, 0xec, 0x04, 0x06, 0xc4, 0x7d, 0x73, 0x74, 0x61, 0xf4, 0xc5, 0x3a,
+ 0x66, 0x69, 0x6e, 0x61, 0xee, 0xc4, 0x3c, 0xe9, 0x02, 0x84, 0x70, 0xe1,
+ 0xc4, 0x71, 0x62, 0x61, 0xe2, 0xc4, 0xfc, 0x67, 0xe1, 0xc2, 0x7c, 0x65,
+ 0xf3, 0x02, 0x84, 0x75, 0xee, 0xc2, 0x75, 0x73, 0x61, 0x6e, 0x64, 0x72,
+ 0x69, 0xe1, 0xc4, 0x8b, 0x63, 0x65, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x77,
+ 0x6f, 0x72, 0xeb, 0xc6, 0x6f, 0xe1, 0x02, 0x86, 0x6e, 0x64, 0x2e, 0xe6,
+ 0xc4, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x6a, 0xf5, 0xc4, 0xdb, 0xae, 0x09,
+ 0x03, 0x03, 0x41, 0x5a, 0x43, 0x02, 0xc0, 0x6e, 0xec, 0xc4, 0x00, 0xe7,
+ 0xc4, 0x1b, 0x65, 0xf5, 0xc3, 0x8c, 0xeb, 0x0b, 0x0a, 0x0a, 0x08, 0x03,
+ 0x0a, 0x06, 0x22, 0x03, 0xc0, 0x55, 0x75, 0x6e, 0x65, 0x2e, 0x6b, 0x61,
+ 0x67, 0xef, 0xc0, 0xdf, 0x74, 0x79, 0x75, 0x62, 0x69, 0x6e, 0x73, 0xeb,
+ 0xc4, 0x52, 0x72, 0x65, 0x68, 0x61, 0x6d, 0xee, 0xc4, 0x9f, 0xef, 0xc1,
+ 0x58, 0x6e, 0x6f, 0x6c, 0x75, 0x6f, 0x6b, 0x74, 0xe1, 0xc4, 0x92, 0x6b,
+ 0x65, 0x73, 0xe8, 0xc4, 0x6b, 0xe9, 0x04, 0x0b, 0x07, 0x86, 0x74, 0x61,
+ 0xae, 0x03, 0xc4, 0x69, 0x61, 0x6b, 0xe9, 0xc1, 0xcd, 0x73, 0x68, 0x69,
+ 0x6d, 0xe1, 0xc2, 0xc3, 0x72, 0x75, 0x6e, 0xef, 0xc2, 0xbd, 0x2e, 0x6b,
+ 0xef, 0xc3, 0xf0, 0xe4, 0xc4, 0xc2, 0xe1, 0x06, 0x04, 0x2c, 0x0b, 0x0b,
+ 0x84, 0x73, 0xe8, 0xc1, 0x17, 0x6d, 0x61, 0xe9, 0x07, 0x03, 0x09, 0x05,
+ 0x07, 0xc5, 0xa9, 0x7a, 0xe5, 0x8b, 0x6f, 0x72, 0x69, 0x67, 0x69, 0xee,
+ 0x0f, 0xc5, 0xa9, 0x68, 0xe4, 0x0a, 0xc5, 0xa9, 0x65, 0x64, 0x67, 0xe5,
+ 0x03, 0xc5, 0xa9, 0x2d, 0x73, 0x74, 0x61, 0x67, 0x69, 0x6e, 0xe7, 0xc5,
+ 0xa1, 0x69, 0x77, 0x61, 0x2e, 0x6f, 0x6b, 0x61, 0x79, 0xe1, 0xc0, 0x56,
+ 0x67, 0x69, 0x2e, 0x73, 0x68, 0x69, 0x6d, 0x61, 0xee, 0xc0, 0xe5, 0x64,
+ 0xee, 0xc5, 0x86, 0x62, 0xe9, 0xc3, 0xc4, 0xae, 0xc0, 0xa0, 0xea, 0xc4,
+ 0x45, 0xe9, 0x11, 0x2c, 0x0a, 0x13, 0x40, 0x64, 0x05, 0x09, 0x0b, 0x0b,
+ 0x03, 0x07, 0x42, 0xa3, 0x42, 0x0e, 0x81, 0x7a, 0xf5, 0x03, 0x0a, 0x8d,
+ 0x77, 0x61, 0x6b, 0x61, 0x6d, 0x61, 0x74, 0x73, 0xf5, 0x93, 0x6d, 0xe9,
+ 0x02, 0x85, 0x73, 0x61, 0x74, 0xef, 0x8a, 0x2e, 0x74, 0xef, 0x89, 0x62,
+ 0x61, 0x6e, 0x67, 0x65, 0x2e, 0x66, 0x75, 0x6b, 0x75, 0x73, 0x68, 0x69,
+ 0xed, 0xc3, 0x93, 0x76, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0xe4, 0xc5,
+ 0x51, 0xf3, 0x02, 0x89, 0x68, 0x6f, 0x2e, 0x73, 0x68, 0x69, 0xe7, 0xc3,
+ 0x7d, 0x61, 0x69, 0x2e, 0x61, 0xe9, 0xc3, 0x37, 0xf2, 0x08, 0x0c, 0x04,
+ 0x05, 0x14, 0x06, 0x07, 0x84, 0xf4, 0x02, 0x86, 0x72, 0x61, 0x66, 0xe6,
+ 0xc1, 0x6f, 0xe5, 0xc2, 0xe2, 0x70, 0x6f, 0xf2, 0xa4, 0x6c, 0x69, 0xee,
+ 0xc1, 0x57, 0x6b, 0x69, 0x74, 0x61, 0x70, 0x70, 0xf3, 0x02, 0x87, 0xae,
+ 0x03, 0xc5, 0x12, 0xe5, 0xc4, 0x90, 0x2d, 0xe1, 0xc3, 0xe2, 0x66, 0x6f,
+ 0x72, 0xe3, 0xc3, 0x92, 0x63, 0x72, 0x61, 0x66, 0xf4, 0xc2, 0x2a, 0x62,
+ 0xf5, 0xc2, 0x9a, 0xad, 0x02, 0x91, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69,
+ 0x63, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0xec, 0xc2, 0x12, 0x73,
+ 0x75, 0x72, 0x76, 0x65, 0x69, 0x6c, 0x6c, 0x61, 0x6e, 0xe3, 0xc1, 0x11,
+ 0x70, 0x2e, 0xe5, 0xc3, 0x61, 0x6f, 0x69, 0x2e, 0x68, 0x79, 0x6f, 0xe7,
+ 0xc3, 0x27, 0x6e, 0x61, 0x6e, 0x2e, 0x65, 0x68, 0x69, 0x6d, 0xe5, 0xc3,
+ 0x1d, 0x6b, 0x61, 0x77, 0x61, 0x2e, 0x6b, 0x61, 0x6e, 0x61, 0xe7, 0xaa,
+ 0x64, 0xae, 0xb5, 0x62, 0x65, 0x74, 0x73, 0xf5, 0xc2, 0xff, 0xae, 0x42,
+ 0x16, 0xc1, 0x60, 0x68, 0xae, 0x03, 0xc3, 0x14, 0xe3, 0xc3, 0x6d, 0xe7,
+ 0x09, 0x0c, 0x24, 0x14, 0x07, 0x42, 0x4d, 0xc2, 0x03, 0x75, 0x6e, 0x69,
+ 0x2e, 0x6f, 0x6b, 0x69, 0x6e, 0x61, 0xf7, 0xc2, 0xc1, 0xf2, 0x05, 0x0c,
+ 0x0e, 0xc3, 0x14, 0x6f, 0xae, 0x02, 0x83, 0xf0, 0xc2, 0x35, 0xe2, 0x42,
+ 0x41, 0xc0, 0xb5, 0xe9, 0x02, 0x86, 0x67, 0x65, 0x6e, 0xf4, 0xc2, 0x72,
+ 0x63, 0x2e, 0xfa, 0xc2, 0xca, 0x61, 0xf2, 0xc3, 0x6b, 0xe5, 0x02, 0x8a,
+ 0xee, 0x02, 0x84, 0x74, 0xf3, 0xc1, 0x86, 0xe3, 0xc2, 0x29, 0x6d, 0x61,
+ 0x74, 0x73, 0xf5, 0xc1, 0x45, 0x64, 0x65, 0x6e, 0x65, 0xf3, 0xc2, 0xbd,
+ 0xe1, 0x03, 0x02, 0x89, 0x6e, 0x6f, 0x2e, 0x6e, 0x69, 0x69, 0x67, 0x61,
+ 0xf4, 0xc2, 0x73, 0x6b, 0x68, 0xe1, 0xc3, 0x04, 0xe6, 0x08, 0x0e, 0x06,
+ 0x13, 0x41, 0xbd, 0xc2, 0x4f, 0x72, 0x69, 0x63, 0xe1, 0x03, 0xc4, 0x2c,
+ 0xae, 0x03, 0xc4, 0x21, 0xe2, 0xc1, 0xe7, 0x6a, 0x6f, 0x72, 0xe4, 0xc2,
+ 0x8c, 0x66, 0x69, 0x6e, 0x69, 0x74, 0x79, 0x6c, 0x6f, 0x74, 0x74, 0x65,
+ 0x72, 0x79, 0x2e, 0x6f, 0x72, 0xe7, 0xc0, 0xbf, 0x2d, 0x73, 0x6f, 0x75,
+ 0x74, 0x68, 0x2d, 0x31, 0x2e, 0x65, 0x6c, 0x61, 0x73, 0x74, 0x69, 0x63,
+ 0x62, 0x65, 0x61, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0xeb, 0xc3, 0xeb, 0xe5,
+ 0x08, 0x04, 0x2b, 0x40, 0xe9, 0x42, 0xcf, 0x81, 0x74, 0xee, 0xc2, 0x3f,
+ 0x72, 0xef, 0x07, 0x06, 0x07, 0x06, 0x07, 0xc3, 0xc1, 0x70, 0x6f, 0x72,
+ 0xf4, 0xc3, 0x45, 0x64, 0x72, 0x6f, 0x6d, 0xe5, 0xc0, 0xf3, 0x63, 0x6c,
+ 0x75, 0xe2, 0xc0, 0xed, 0x62, 0x61, 0x74, 0x69, 0xe3, 0xc0, 0xe6, 0xae,
+ 0x03, 0xc1, 0xfe, 0x6d, 0xf6, 0xc3, 0xbb, 0x6a, 0x72, 0xe9, 0xc2, 0x20,
+ 0xe4, 0x0d, 0x0a, 0x13, 0x0a, 0x27, 0x03, 0x0a, 0x40, 0xe2, 0x40, 0xbd,
+ 0xc1, 0xac, 0x79, 0x67, 0x65, 0x79, 0x61, 0xae, 0x41, 0xb7, 0xc1, 0x60,
+ 0xf6, 0x02, 0x89, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x77, 0xf3, 0xc3, 0x80,
+ 0xae, 0x03, 0xc2, 0x32, 0xed, 0xc1, 0x18, 0x75, 0x6c, 0xf4, 0x03, 0xc3,
+ 0x83, 0x2e, 0xe8, 0xc1, 0xc3, 0x6f, 0x62, 0xe5, 0x02, 0x96, 0x69, 0xef,
+ 0x02, 0x89, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0xe5, 0xc3, 0x4b, 0x2d,
+ 0x73, 0x74, 0x61, 0x74, 0x69, 0xe3, 0xc3, 0x42, 0x61, 0x65, 0x6d, 0x63,
+ 0x6c, 0x6f, 0x75, 0x64, 0xae, 0x43, 0x38, 0x9c, 0xed, 0xc1, 0xfc, 0x69,
+ 0x6d, 0x6f, 0x2e, 0x63, 0x6f, 0x2e, 0xf5, 0xc3, 0x15, 0x61, 0x63, 0x68,
+ 0x69, 0x2e, 0x74, 0x6f, 0x6b, 0xf9, 0xc1, 0x95, 0xe3, 0x0a, 0x1f, 0x0a,
+ 0x40, 0x48, 0x10, 0x41, 0x29, 0xc1, 0x8b, 0xf4, 0x03, 0x03, 0x8e, 0xef,
+ 0xc1, 0xd7, 0x69, 0x76, 0x65, 0x74, 0x72, 0x61, 0x69, 0x6c, 0x2e, 0x62,
+ 0x69, 0xfa, 0xc3, 0x1e, 0xae, 0x02, 0x84, 0x65, 0x64, 0x75, 0x2e, 0xe1,
+ 0xc2, 0x18, 0x68, 0x69, 0x2e, 0x6e, 0x61, 0x67, 0x61, 0xee, 0xc1, 0x61,
+ 0xe3, 0x04, 0x03, 0x0b, 0xa1, 0xf4, 0xc1, 0x78, 0x6f, 0x75, 0x6e, 0x74,
+ 0x61, 0x6e, 0xf4, 0x40, 0x94, 0xc2, 0x69, 0x69, 0x64, 0x65, 0x6e, 0x74,
+ 0xad, 0x02, 0x87, 0x70, 0x72, 0x65, 0x76, 0x65, 0xee, 0x8a, 0x69, 0x6e,
+ 0x76, 0x65, 0x73, 0x74, 0x69, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e,
+ 0x61, 0xe5, 0xc1, 0x4e, 0xe5, 0x02, 0x8b, 0x73, 0x73, 0x63, 0x61, 0x6d,
+ 0x2e, 0x6f, 0x72, 0xe7, 0xc2, 0xc8, 0x6e, 0x74, 0x75, 0xf2, 0xc1, 0x4a,
+ 0xe1, 0x03, 0xc1, 0x32, 0x64, 0x65, 0xed, 0x03, 0xc0, 0x83, 0x69, 0x61,
+ 0x2e, 0xe2, 0xc1, 0x2b, 0xae, 0x13, 0x05, 0x03, 0x04, 0x07, 0x04, 0x05,
+ 0x05, 0x04, 0x0e, 0x10, 0x04, 0x10, 0x08, 0x04, 0x09, 0x03, 0xc0, 0x86,
+ 0xfa, 0x2f, 0x1e, 0xc0, 0xab, 0xf6, 0xc1, 0x60, 0xf5, 0x31, 0xc2, 0x65,
+ 0xf4, 0x03, 0x1d, 0xb3, 0xe8, 0xc2, 0x8f, 0xf3, 0x19, 0xc0, 0xf7, 0xf2,
+ 0x18, 0x07, 0xc1, 0xe1, 0xf0, 0x40, 0xdc, 0xc0, 0x4e, 0xee, 0x0b, 0xc0,
+ 0x5a, 0xed, 0x07, 0x03, 0x40, 0xc9, 0x2b, 0xc0, 0x7c, 0xfa, 0xc2, 0x72,
+ 0xf7, 0xc2, 0x6f, 0xec, 0x03, 0x03, 0x83, 0xf3, 0xc2, 0x68, 0xeb, 0xc2,
+ 0x65, 0x65, 0x67, 0x2e, 0xe2, 0xc1, 0xcf, 0xeb, 0x40, 0xe0, 0xa3, 0xe9,
+ 0x06, 0x03, 0x03, 0x40, 0xf3, 0x9f, 0xed, 0xc2, 0x51, 0xec, 0xc2, 0x4e,
+ 0xe4, 0xc2, 0x4b, 0xe7, 0x03, 0xc1, 0x0b, 0x6f, 0xf6, 0xc0, 0xe8, 0x66,
+ 0xea, 0xc2, 0x3f, 0xe3, 0x05, 0x1e, 0x40, 0xc0, 0x9f, 0xf9, 0xc2, 0x36,
+ 0xe2, 0xc0, 0xb7, 0xe1, 0x40, 0x72, 0xc0, 0x42, 0xe2, 0x0b, 0x16, 0x0b,
+ 0x0c, 0x03, 0x0a, 0x0e, 0x0a, 0x05, 0x0e, 0x92, 0xf5, 0x02, 0x87, 0x64,
+ 0x68, 0x61, 0x62, 0xe9, 0xc2, 0x18, 0x2e, 0x79, 0x61, 0x6d, 0x61, 0x67,
+ 0x75, 0x63, 0x68, 0xe9, 0xc0, 0x60, 0xf2, 0x02, 0x84, 0x75, 0x7a, 0x7a,
+ 0x6f, 0x2e, 0xe9, 0xc0, 0x43, 0xef, 0x02, 0x85, 0x67, 0x61, 0xe4, 0xc0,
+ 0x6e, 0x2e, 0xf0, 0xc0, 0x4e, 0xec, 0xc0, 0x76, 0x6b, 0x68, 0x61, 0x7a,
+ 0x69, 0x61, 0x2e, 0xf3, 0xc1, 0x60, 0xe9, 0x02, 0x83, 0x72, 0xe1, 0xac,
+ 0x6b, 0x6f, 0x2e, 0x63, 0x68, 0x69, 0xe2, 0x89, 0x65, 0x6e, 0x6f, 0x2e,
+ 0x6f, 0x73, 0x61, 0x6b, 0xe1, 0xa3, 0xe3, 0x40, 0x72, 0xc1, 0x5b, 0xe2,
+ 0x04, 0x04, 0xc1, 0xc0, 0x76, 0xe9, 0xc0, 0x46, 0x6f, 0x74, 0xf4, 0xc1,
+ 0xbd, 0x61, 0x73, 0x68, 0x69, 0x72, 0x69, 0x2e, 0x68, 0x6f, 0x6b, 0x6b,
+ 0x61, 0x69, 0x64, 0x6f, 0x2e, 0xea, 0x8d, 0x2e, 0x63, 0xe1, 0xc1, 0xa6,
+ 0xe1, 0x03, 0x0b, 0x83, 0xf2, 0x02, 0x83, 0xf0, 0xc1, 0x9c, 0x62, 0x6f,
+ 0x72, 0x74, 0x65, 0x2e, 0xee, 0x88, 0xe1, 0x03, 0xc1, 0x8e, 0x2e, 0x70,
+ 0x72, 0xef, 0xc1, 0x8a, 0xae, 0x05, 0x09, 0x08, 0xc1, 0x6f, 0xf3, 0x02,
+ 0x83, 0x73, 0xec, 0x90, 0xe5, 0xc1, 0x7b, 0x72, 0x75, 0x6e, 0x2e, 0x61,
+ 0xf0, 0xc0, 0x7a, 0x70, 0x72, 0x6f, 0x64, 0x2e, 0x66, 0x61, 0x73, 0x74,
+ 0x6c, 0xf9, 0xc1, 0x42, 0xb9, 0x03, 0xc1, 0x5d, 0x67, 0x75, 0x61, 0x63,
+ 0x75, 0x2e, 0x62, 0xf2, 0xc1, 0x58, 0xb8, 0xc1, 0x52, 0xb7, 0xc1, 0x1c,
+ 0xb6, 0x05, 0x03, 0x0a, 0xc1, 0x07, 0xb4, 0xc0, 0x67, 0x31, 0x31, 0x2e,
+ 0xf4, 0xc1, 0x08, 0xb5, 0x03, 0xc1, 0x07, 0x67, 0x2e, 0x69, 0xee, 0xc1,
+ 0x39, 0xb4, 0x04, 0x03, 0xc0, 0xf9, 0xf5, 0xc1, 0x29, 0x6c, 0x69, 0x6d,
+ 0xe1, 0xc0, 0x5e, 0xb3, 0x04, 0x0b, 0xc0, 0xe3, 0x75, 0x74, 0x69, 0x6c,
+ 0x69, 0x74, 0x69, 0x65, 0xf3, 0xc1, 0x13, 0xb2, 0xb6, 0xb2, 0x05, 0x04,
+ 0x10, 0xc0, 0xc7, 0x69, 0xf8, 0xc0, 0x42, 0xb0, 0x02, 0x86, 0x33, 0x38,
+ 0x2e, 0xe9, 0xc0, 0xcb, 0x30, 0x30, 0x2e, 0x68, 0xf5, 0xc0, 0xff, 0x2d,
+ 0x64, 0x2e, 0x6a, 0xf0, 0xc0, 0xf4, 0xb1, 0x07, 0x06, 0x05, 0x05, 0x0c,
+ 0xc0, 0x9c, 0x6b, 0x61, 0x70, 0xf0, 0xc0, 0xe2, 0x38, 0x30, 0xf2, 0xc0,
+ 0xdd, 0x36, 0x2d, 0xe2, 0xc0, 0x95, 0x33, 0x33, 0x37, 0x2e, 0x70, 0x69,
+ 0x63, 0x74, 0x75, 0xf2, 0xc0, 0x64, 0xb2, 0x02, 0x86, 0x68, 0x70, 0xae,
+ 0x1e, 0x0e, 0x82, 0xb3, 0x06, 0x27, 0x16, 0x0d, 0x16, 0x8d, 0x77, 0x65,
+ 0x62, 0xf3, 0x02, 0x95, 0x69, 0x74, 0x65, 0xae, 0x04, 0x04, 0x02, 0x84,
+ 0x6e, 0xec, 0xc0, 0xae, 0xec, 0xa7, 0x63, 0xe8, 0xc0, 0xa8, 0xe2, 0xc0,
+ 0x44, 0x65, 0x69, 0x74, 0x65, 0xae, 0x02, 0x82, 0xe4, 0xba, 0xe1, 0xc0,
+ 0x7c, 0xf3, 0x02, 0x8b, 0x69, 0x74, 0x65, 0x77, 0x65, 0x62, 0x2e, 0x66,
+ 0xf2, 0xc0, 0x8b, 0x61, 0x69, 0x74, 0x2e, 0x72, 0xf5, 0xc0, 0x83, 0x70,
+ 0x61, 0x67, 0x69, 0x6e, 0x61, 0x77, 0x65, 0x62, 0x2e, 0xf0, 0xc0, 0x59,
+ 0x6d, 0xe9, 0x02, 0x88, 0x77, 0x65, 0x62, 0x2e, 0x65, 0xf3, 0xc0, 0x6a,
+ 0x6e, 0x73, 0x69, 0x64, 0x61, 0x2e, 0x73, 0xe5, 0xc0, 0x60, 0x6b, 0x6f,
+ 0x74, 0x69, 0x73, 0x69, 0x76, 0x75, 0x2e, 0x66, 0xe9, 0xc0, 0x53, 0xe8,
+ 0x02, 0x8a, 0x6f, 0x6d, 0x65, 0x70, 0x61, 0x67, 0x65, 0x2e, 0xe9, 0xa8,
+ 0x6a, 0x65, 0x6d, 0x6d, 0x65, 0x73, 0x69, 0x64, 0x65, 0xae, 0x02, 0x83,
+ 0x6e, 0xef, 0xb6, 0x64, 0xeb, 0xb3, 0xae, 0x02, 0xb1, 0x61, 0x7a, 0x75,
+ 0x72, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x61, 0x70, 0x70, 0x73,
+ 0x2e, 0x6e, 0x65, 0xf4, 0x9c, 0xb0, 0x03, 0x0e, 0x8a, 0xe5, 0x02, 0x87,
+ 0x6d, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x8a, 0x2e, 0x76, 0xe3, 0x8a, 0x30,
+ 0x31, 0x77, 0x77, 0x77, 0x2e, 0x63, 0x6f, 0x6d, 0x88, 0x2e, 0x62, 0x67,
+ 0x84, 0x01,
};
diff --git a/src/3rdparty/libpsl/qt_attribution.json b/src/3rdparty/libpsl/qt_attribution.json
index ebaa4cab04..016203387a 100644
--- a/src/3rdparty/libpsl/qt_attribution.json
+++ b/src/3rdparty/libpsl/qt_attribution.json
@@ -13,26 +13,27 @@ It allows browsers to, for example:
- Highlight the most important part of a domain name in the user interface
- Accurately sort history entries by site",
-
"Files": "psl_data.cpp",
"QtUsage": "Used in Qt Network to avoid setting \"supercookies\" in the cookie jar
supported by Qt (by the QNetworkCookieJar class).",
- "Homepage": "Consult https://github.com/publicsuffix/list for the sha1 but download from ...",
+ "Comment": "Consult https://github.com/publicsuffix/list for the sha1 but download from ...",
"Homepage": "http://publicsuffix.org/",
- "Version": "f15705582ed13f390c59541300dea7288acf4137, fetched on 2023-02-02",
+ "Comment": "Suggested update schedule: twice per year (before a 6.x.0 release)",
+ "Version": "883ced078a83f9d79a98933145425c221a5e51f0, fetched on 2024-01-25",
+ "DownloadLocation": "https://publicsuffix.org/list/public_suffix_list.dat",
+
"License": "Mozilla Public License 2.0",
"LicenseFile": "PSL-LICENSE.txt",
"LicenseId": "MPL-2.0",
- "Copyright": "The list was originally provided by Jo Hermans <jo.hermans@gmail.com>.
-It is now maintained on github (https://github.com/publicsuffix/list)."
+ "Copyright": "The list was originally provided by Jo Hermans <jo.hermans@gmail.com>.\nIt is now maintained on github (https://github.com/publicsuffix/list)."
},
{
"Id": "libpsl",
"Name": "libpsl - C library to handle the Public Suffix List",
"QDocModule": "qtnetwork",
"Description": "Libpsl allows checking domains against the Public Suffix List.",
- "Files": "src/lookup_string_in_fixed_set.c src/psl-make-dafsa",
+ "Files": [ "src/lookup_string_in_fixed_set.c", "src/psl-make-dafsa" ],
"QtUsage": "Used to compress the embedded copy of publicsuffix list and
to lookup entries in it.",
"Homepage": "https://github.com/rockdaboot/libpsl",
diff --git a/src/3rdparty/md4/qt_attribution.json b/src/3rdparty/md4/qt_attribution.json
index 27455d9b80..f61d6b97c8 100644
--- a/src/3rdparty/md4/qt_attribution.json
+++ b/src/3rdparty/md4/qt_attribution.json
@@ -4,7 +4,7 @@
"QDocModule": "qtcore",
"QtUsage": "Used in Qt Core (QCryptographicHash).",
- "Description": "Treat as final version; no upstream known",
+ "Comment": "Treat as final version; no upstream known",
"Description": "An OpenSSL-compatible implementation of the RSA Data Security, Inc. MD4 Message-Digest Algorithm.",
"License": "Public Domain",
"LicenseId": "CC0-1.0",
diff --git a/src/3rdparty/md4c/0001-md4c-Fix-MSVC-compiler-level-3-warnings.patch b/src/3rdparty/md4c/0001-md4c-Fix-MSVC-compiler-level-3-warnings.patch
deleted file mode 100644
index 5f2cf8401b..0000000000
--- a/src/3rdparty/md4c/0001-md4c-Fix-MSVC-compiler-level-3-warnings.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-diff --git a/src/3rdparty/md4c/md4c.c b/src/3rdparty/md4c/md4c.c
-index 6aeef112e5..9d0d1b7d7b 100644
---- a/src/3rdparty/md4c/md4c.c
-+++ b/src/3rdparty/md4c/md4c.c
-@@ -916,7 +916,7 @@ md_merge_lines(MD_CTX* ctx, OFF beg, OFF end, const MD_LINE* lines, int n_lines,
- }
-
- if(off >= end) {
-- *p_size = ptr - buffer;
-+ *p_size = (MD_SIZE)(ptr - buffer);
- return;
- }
-
-@@ -2229,7 +2229,7 @@ md_is_link_reference(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
-
- if(beg_line != end_line) {
- MD_CHECK(md_merge_lines_alloc(ctx, beg, end, beg_line,
-- n_lines - (beg_line - lines), _T(' '), &label, &label_size));
-+ (int)(n_lines - (beg_line - lines)), _T(' '), &label, &label_size));
- } else {
- label = (CHAR*) STR(beg);
- label_size = end - beg;
-@@ -4265,7 +4265,7 @@ md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
- MD_CHECK(md_enter_leave_span_a(ctx, (mark->ch != ']'),
- (opener->ch == '!' ? MD_SPAN_IMG : MD_SPAN_A),
- STR(dest_mark->beg), dest_mark->end - dest_mark->beg, FALSE,
-- md_mark_get_ptr(ctx, title_mark - ctx->marks), title_mark->prev));
-+ md_mark_get_ptr(ctx, (int)(title_mark - ctx->marks)), title_mark->prev));
-
- /* link/image closer may span multiple lines. */
- if(mark->ch == ']') {
-@@ -4908,7 +4908,7 @@ md_push_block_bytes(MD_CTX* ctx, int n_bytes)
-
- /* Fix the ->current_block after the reallocation. */
- if(ctx->current_block != NULL) {
-- OFF off_current_block = (char*) ctx->current_block - (char*) ctx->block_bytes;
-+ OFF off_current_block = (OFF)((char*) ctx->current_block - (char*) ctx->block_bytes);
- ctx->current_block = (MD_BLOCK*) ((char*) new_block_bytes + off_current_block);
- }
-
diff --git a/src/3rdparty/md4c/LICENSE.md b/src/3rdparty/md4c/LICENSE.md
index 2088ba453e..c80b3a95ce 100644
--- a/src/3rdparty/md4c/LICENSE.md
+++ b/src/3rdparty/md4c/LICENSE.md
@@ -1,7 +1,7 @@
# The MIT License (MIT)
-Copyright © 2016-2020 Martin Mitáš
+Copyright © 2016-2024 Martin Mitáš
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the “Software”),
diff --git a/src/3rdparty/md4c/md4c.c b/src/3rdparty/md4c/md4c.c
index 9d0d1b7d7b..812bde5358 100644
--- a/src/3rdparty/md4c/md4c.c
+++ b/src/3rdparty/md4c/md4c.c
@@ -2,7 +2,7 @@
* MD4C: Markdown parser for C
* (http://github.com/mity/md4c)
*
- * Copyright (c) 2016-2020 Martin Mitas
+ * Copyright (c) 2016-2024 Martin Mitáš
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -67,6 +67,9 @@
#define STRINGIZE_(x) #x
#define STRINGIZE(x) STRINGIZE_(x)
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
#ifndef TRUE
#define TRUE 1
#define FALSE 0
@@ -115,6 +118,22 @@
#define MD_UNUSED(x) ((void)x)
+/******************************
+ *** Some internal limits ***
+ ******************************/
+
+/* We limit code span marks to lower than 32 backticks. This solves the
+ * pathologic case of too many openers, each of different length: Their
+ * resolving would be then O(n^2). */
+#define CODESPAN_MARK_MAXLEN 32
+
+/* We limit column count of tables to prevent quadratic explosion of output
+ * from pathological input of a table thousands of columns and thousands
+ * of rows where rows are requested with as little as single character
+ * per-line, relying on us to "helpfully" fill all the missing "<td></td>". */
+#define TABLE_MAXCOLCOUNT 128
+
+
/************************
*** Internal Types ***
************************/
@@ -130,14 +149,13 @@ typedef struct MD_CONTAINER_tag MD_CONTAINER;
typedef struct MD_REF_DEF_tag MD_REF_DEF;
-/* During analyzes of inline marks, we need to manage some "mark chains",
- * of (yet unresolved) openers. This structure holds start/end of the chain.
- * The chain internals are then realized through MD_MARK::prev and ::next.
+/* During analyzes of inline marks, we need to manage stacks of unresolved
+ * openers of the given type.
+ * The stack connects the marks via MD_MARK::next;
*/
-typedef struct MD_MARKCHAIN_tag MD_MARKCHAIN;
-struct MD_MARKCHAIN_tag {
- int head; /* Index of first mark in the chain, or -1 if empty. */
- int tail; /* Index of last mark in the chain, or -1 if empty. */
+typedef struct MD_MARKSTACK_tag MD_MARKSTACK;
+struct MD_MARKSTACK_tag {
+ int top; /* -1 if empty. */
};
/* Context propagated through all the parsing. */
@@ -178,24 +196,33 @@ struct MD_CTX_tag {
#endif
/* For resolving of inline spans. */
- MD_MARKCHAIN mark_chains[13];
-#define PTR_CHAIN (ctx->mark_chains[0])
-#define TABLECELLBOUNDARIES (ctx->mark_chains[1])
-#define ASTERISK_OPENERS_extraword_mod3_0 (ctx->mark_chains[2])
-#define ASTERISK_OPENERS_extraword_mod3_1 (ctx->mark_chains[3])
-#define ASTERISK_OPENERS_extraword_mod3_2 (ctx->mark_chains[4])
-#define ASTERISK_OPENERS_intraword_mod3_0 (ctx->mark_chains[5])
-#define ASTERISK_OPENERS_intraword_mod3_1 (ctx->mark_chains[6])
-#define ASTERISK_OPENERS_intraword_mod3_2 (ctx->mark_chains[7])
-#define UNDERSCORE_OPENERS (ctx->mark_chains[8])
-#define TILDE_OPENERS_1 (ctx->mark_chains[9])
-#define TILDE_OPENERS_2 (ctx->mark_chains[10])
-#define BRACKET_OPENERS (ctx->mark_chains[11])
-#define DOLLAR_OPENERS (ctx->mark_chains[12])
-#define OPENERS_CHAIN_FIRST 2
-#define OPENERS_CHAIN_LAST 12
-
+ MD_MARKSTACK opener_stacks[16];
+#define ASTERISK_OPENERS_oo_mod3_0 (ctx->opener_stacks[0]) /* Opener-only */
+#define ASTERISK_OPENERS_oo_mod3_1 (ctx->opener_stacks[1])
+#define ASTERISK_OPENERS_oo_mod3_2 (ctx->opener_stacks[2])
+#define ASTERISK_OPENERS_oc_mod3_0 (ctx->opener_stacks[3]) /* Both opener and closer candidate */
+#define ASTERISK_OPENERS_oc_mod3_1 (ctx->opener_stacks[4])
+#define ASTERISK_OPENERS_oc_mod3_2 (ctx->opener_stacks[5])
+#define UNDERSCORE_OPENERS_oo_mod3_0 (ctx->opener_stacks[6]) /* Opener-only */
+#define UNDERSCORE_OPENERS_oo_mod3_1 (ctx->opener_stacks[7])
+#define UNDERSCORE_OPENERS_oo_mod3_2 (ctx->opener_stacks[8])
+#define UNDERSCORE_OPENERS_oc_mod3_0 (ctx->opener_stacks[9]) /* Both opener and closer candidate */
+#define UNDERSCORE_OPENERS_oc_mod3_1 (ctx->opener_stacks[10])
+#define UNDERSCORE_OPENERS_oc_mod3_2 (ctx->opener_stacks[11])
+#define TILDE_OPENERS_1 (ctx->opener_stacks[12])
+#define TILDE_OPENERS_2 (ctx->opener_stacks[13])
+#define BRACKET_OPENERS (ctx->opener_stacks[14])
+#define DOLLAR_OPENERS (ctx->opener_stacks[15])
+
+ /* Stack of dummies which need to call free() for pointers stored in them.
+ * These are constructed during inline parsing and freed after all the block
+ * is processed (i.e. all callbacks referring those strings are called). */
+ MD_MARKSTACK ptr_stack;
+
+ /* For resolving table rows. */
int n_table_cell_boundaries;
+ int table_cell_boundaries_head;
+ int table_cell_boundaries_tail;
/* For resolving links. */
int unresolved_link_head;
@@ -251,8 +278,9 @@ typedef enum MD_LINETYPE_tag MD_LINETYPE;
typedef struct MD_LINE_ANALYSIS_tag MD_LINE_ANALYSIS;
struct MD_LINE_ANALYSIS_tag {
- MD_LINETYPE type : 16;
- unsigned data : 16;
+ MD_LINETYPE type;
+ unsigned data;
+ int enforce_new_block;
OFF beg;
OFF end;
unsigned indent; /* Indentation level. */
@@ -465,6 +493,40 @@ md_text_with_null_replacement(MD_CTX* ctx, MD_TEXTTYPE type, const CHAR* str, SZ
} while(0)
+/* If the offset falls into a gap between line, we return the following
+ * line. */
+static const MD_LINE*
+md_lookup_line(OFF off, const MD_LINE* lines, MD_SIZE n_lines, MD_SIZE* p_line_index)
+{
+ MD_SIZE lo, hi;
+ MD_SIZE pivot;
+ const MD_LINE* line;
+
+ lo = 0;
+ hi = n_lines - 1;
+ while(lo <= hi) {
+ pivot = (lo + hi) / 2;
+ line = &lines[pivot];
+
+ if(off < line->beg) {
+ if(hi == 0 || lines[hi-1].end < off) {
+ if(p_line_index != NULL)
+ *p_line_index = pivot;
+ return line;
+ }
+ hi = pivot - 1;
+ } else if(off > line->end) {
+ lo = pivot + 1;
+ } else {
+ if(p_line_index != NULL)
+ *p_line_index = pivot;
+ return line;
+ }
+ }
+
+ return NULL;
+}
+
/*************************
*** Unicode Support ***
@@ -537,39 +599,67 @@ struct MD_UNICODE_FOLD_INFO_tag {
{
#define R(cp_min, cp_max) ((cp_min) | 0x40000000), ((cp_max) | 0x80000000)
#define S(cp) (cp)
- /* Unicode "Pc", "Pd", "Pe", "Pf", "Pi", "Po", "Ps" categories.
+ /* Unicode general "P" and "S" categories.
* (generated by scripts/build_punct_map.py) */
static const unsigned PUNCT_MAP[] = {
- R(0x0021,0x0023), R(0x0025,0x002a), R(0x002c,0x002f), R(0x003a,0x003b), R(0x003f,0x0040),
- R(0x005b,0x005d), S(0x005f), S(0x007b), S(0x007d), S(0x00a1), S(0x00a7), S(0x00ab), R(0x00b6,0x00b7),
- S(0x00bb), S(0x00bf), S(0x037e), S(0x0387), R(0x055a,0x055f), R(0x0589,0x058a), S(0x05be), S(0x05c0),
- S(0x05c3), S(0x05c6), R(0x05f3,0x05f4), R(0x0609,0x060a), R(0x060c,0x060d), S(0x061b), R(0x061e,0x061f),
- R(0x066a,0x066d), S(0x06d4), R(0x0700,0x070d), R(0x07f7,0x07f9), R(0x0830,0x083e), S(0x085e),
- R(0x0964,0x0965), S(0x0970), S(0x09fd), S(0x0a76), S(0x0af0), S(0x0c77), S(0x0c84), S(0x0df4), S(0x0e4f),
- R(0x0e5a,0x0e5b), R(0x0f04,0x0f12), S(0x0f14), R(0x0f3a,0x0f3d), S(0x0f85), R(0x0fd0,0x0fd4),
- R(0x0fd9,0x0fda), R(0x104a,0x104f), S(0x10fb), R(0x1360,0x1368), S(0x1400), S(0x166e), R(0x169b,0x169c),
- R(0x16eb,0x16ed), R(0x1735,0x1736), R(0x17d4,0x17d6), R(0x17d8,0x17da), R(0x1800,0x180a),
- R(0x1944,0x1945), R(0x1a1e,0x1a1f), R(0x1aa0,0x1aa6), R(0x1aa8,0x1aad), R(0x1b5a,0x1b60),
- R(0x1bfc,0x1bff), R(0x1c3b,0x1c3f), R(0x1c7e,0x1c7f), R(0x1cc0,0x1cc7), S(0x1cd3), R(0x2010,0x2027),
- R(0x2030,0x2043), R(0x2045,0x2051), R(0x2053,0x205e), R(0x207d,0x207e), R(0x208d,0x208e),
- R(0x2308,0x230b), R(0x2329,0x232a), R(0x2768,0x2775), R(0x27c5,0x27c6), R(0x27e6,0x27ef),
- R(0x2983,0x2998), R(0x29d8,0x29db), R(0x29fc,0x29fd), R(0x2cf9,0x2cfc), R(0x2cfe,0x2cff), S(0x2d70),
- R(0x2e00,0x2e2e), R(0x2e30,0x2e4f), S(0x2e52), R(0x3001,0x3003), R(0x3008,0x3011), R(0x3014,0x301f),
- S(0x3030), S(0x303d), S(0x30a0), S(0x30fb), R(0xa4fe,0xa4ff), R(0xa60d,0xa60f), S(0xa673), S(0xa67e),
- R(0xa6f2,0xa6f7), R(0xa874,0xa877), R(0xa8ce,0xa8cf), R(0xa8f8,0xa8fa), S(0xa8fc), R(0xa92e,0xa92f),
- S(0xa95f), R(0xa9c1,0xa9cd), R(0xa9de,0xa9df), R(0xaa5c,0xaa5f), R(0xaade,0xaadf), R(0xaaf0,0xaaf1),
- S(0xabeb), R(0xfd3e,0xfd3f), R(0xfe10,0xfe19), R(0xfe30,0xfe52), R(0xfe54,0xfe61), S(0xfe63), S(0xfe68),
- R(0xfe6a,0xfe6b), R(0xff01,0xff03), R(0xff05,0xff0a), R(0xff0c,0xff0f), R(0xff1a,0xff1b),
- R(0xff1f,0xff20), R(0xff3b,0xff3d), S(0xff3f), S(0xff5b), S(0xff5d), R(0xff5f,0xff65), R(0x10100,0x10102),
- S(0x1039f), S(0x103d0), S(0x1056f), S(0x10857), S(0x1091f), S(0x1093f), R(0x10a50,0x10a58), S(0x10a7f),
- R(0x10af0,0x10af6), R(0x10b39,0x10b3f), R(0x10b99,0x10b9c), S(0x10ead), R(0x10f55,0x10f59),
- R(0x11047,0x1104d), R(0x110bb,0x110bc), R(0x110be,0x110c1), R(0x11140,0x11143), R(0x11174,0x11175),
- R(0x111c5,0x111c8), S(0x111cd), S(0x111db), R(0x111dd,0x111df), R(0x11238,0x1123d), S(0x112a9),
- R(0x1144b,0x1144f), R(0x1145a,0x1145b), S(0x1145d), S(0x114c6), R(0x115c1,0x115d7), R(0x11641,0x11643),
- R(0x11660,0x1166c), R(0x1173c,0x1173e), S(0x1183b), R(0x11944,0x11946), S(0x119e2), R(0x11a3f,0x11a46),
- R(0x11a9a,0x11a9c), R(0x11a9e,0x11aa2), R(0x11c41,0x11c45), R(0x11c70,0x11c71), R(0x11ef7,0x11ef8),
- S(0x11fff), R(0x12470,0x12474), R(0x16a6e,0x16a6f), S(0x16af5), R(0x16b37,0x16b3b), S(0x16b44),
- R(0x16e97,0x16e9a), S(0x16fe2), S(0x1bc9f), R(0x1da87,0x1da8b), R(0x1e95e,0x1e95f)
+ R(0x0021,0x002f), R(0x003a,0x0040), R(0x005b,0x0060), R(0x007b,0x007e), R(0x00a1,0x00a9),
+ R(0x00ab,0x00ac), R(0x00ae,0x00b1), S(0x00b4), R(0x00b6,0x00b8), S(0x00bb), S(0x00bf), S(0x00d7),
+ S(0x00f7), R(0x02c2,0x02c5), R(0x02d2,0x02df), R(0x02e5,0x02eb), S(0x02ed), R(0x02ef,0x02ff), S(0x0375),
+ S(0x037e), R(0x0384,0x0385), S(0x0387), S(0x03f6), S(0x0482), R(0x055a,0x055f), R(0x0589,0x058a),
+ R(0x058d,0x058f), S(0x05be), S(0x05c0), S(0x05c3), S(0x05c6), R(0x05f3,0x05f4), R(0x0606,0x060f),
+ S(0x061b), R(0x061d,0x061f), R(0x066a,0x066d), S(0x06d4), S(0x06de), S(0x06e9), R(0x06fd,0x06fe),
+ R(0x0700,0x070d), R(0x07f6,0x07f9), R(0x07fe,0x07ff), R(0x0830,0x083e), S(0x085e), S(0x0888),
+ R(0x0964,0x0965), S(0x0970), R(0x09f2,0x09f3), R(0x09fa,0x09fb), S(0x09fd), S(0x0a76), R(0x0af0,0x0af1),
+ S(0x0b70), R(0x0bf3,0x0bfa), S(0x0c77), S(0x0c7f), S(0x0c84), S(0x0d4f), S(0x0d79), S(0x0df4), S(0x0e3f),
+ S(0x0e4f), R(0x0e5a,0x0e5b), R(0x0f01,0x0f17), R(0x0f1a,0x0f1f), S(0x0f34), S(0x0f36), S(0x0f38),
+ R(0x0f3a,0x0f3d), S(0x0f85), R(0x0fbe,0x0fc5), R(0x0fc7,0x0fcc), R(0x0fce,0x0fda), R(0x104a,0x104f),
+ R(0x109e,0x109f), S(0x10fb), R(0x1360,0x1368), R(0x1390,0x1399), S(0x1400), R(0x166d,0x166e),
+ R(0x169b,0x169c), R(0x16eb,0x16ed), R(0x1735,0x1736), R(0x17d4,0x17d6), R(0x17d8,0x17db),
+ R(0x1800,0x180a), S(0x1940), R(0x1944,0x1945), R(0x19de,0x19ff), R(0x1a1e,0x1a1f), R(0x1aa0,0x1aa6),
+ R(0x1aa8,0x1aad), R(0x1b5a,0x1b6a), R(0x1b74,0x1b7e), R(0x1bfc,0x1bff), R(0x1c3b,0x1c3f),
+ R(0x1c7e,0x1c7f), R(0x1cc0,0x1cc7), S(0x1cd3), S(0x1fbd), R(0x1fbf,0x1fc1), R(0x1fcd,0x1fcf),
+ R(0x1fdd,0x1fdf), R(0x1fed,0x1fef), R(0x1ffd,0x1ffe), R(0x2010,0x2027), R(0x2030,0x205e),
+ R(0x207a,0x207e), R(0x208a,0x208e), R(0x20a0,0x20c0), R(0x2100,0x2101), R(0x2103,0x2106),
+ R(0x2108,0x2109), S(0x2114), R(0x2116,0x2118), R(0x211e,0x2123), S(0x2125), S(0x2127), S(0x2129),
+ S(0x212e), R(0x213a,0x213b), R(0x2140,0x2144), R(0x214a,0x214d), S(0x214f), R(0x218a,0x218b),
+ R(0x2190,0x2426), R(0x2440,0x244a), R(0x249c,0x24e9), R(0x2500,0x2775), R(0x2794,0x2b73),
+ R(0x2b76,0x2b95), R(0x2b97,0x2bff), R(0x2ce5,0x2cea), R(0x2cf9,0x2cfc), R(0x2cfe,0x2cff), S(0x2d70),
+ R(0x2e00,0x2e2e), R(0x2e30,0x2e5d), R(0x2e80,0x2e99), R(0x2e9b,0x2ef3), R(0x2f00,0x2fd5),
+ R(0x2ff0,0x2fff), R(0x3001,0x3004), R(0x3008,0x3020), S(0x3030), R(0x3036,0x3037), R(0x303d,0x303f),
+ R(0x309b,0x309c), S(0x30a0), S(0x30fb), R(0x3190,0x3191), R(0x3196,0x319f), R(0x31c0,0x31e3), S(0x31ef),
+ R(0x3200,0x321e), R(0x322a,0x3247), S(0x3250), R(0x3260,0x327f), R(0x328a,0x32b0), R(0x32c0,0x33ff),
+ R(0x4dc0,0x4dff), R(0xa490,0xa4c6), R(0xa4fe,0xa4ff), R(0xa60d,0xa60f), S(0xa673), S(0xa67e),
+ R(0xa6f2,0xa6f7), R(0xa700,0xa716), R(0xa720,0xa721), R(0xa789,0xa78a), R(0xa828,0xa82b),
+ R(0xa836,0xa839), R(0xa874,0xa877), R(0xa8ce,0xa8cf), R(0xa8f8,0xa8fa), S(0xa8fc), R(0xa92e,0xa92f),
+ S(0xa95f), R(0xa9c1,0xa9cd), R(0xa9de,0xa9df), R(0xaa5c,0xaa5f), R(0xaa77,0xaa79), R(0xaade,0xaadf),
+ R(0xaaf0,0xaaf1), S(0xab5b), R(0xab6a,0xab6b), S(0xabeb), S(0xfb29), R(0xfbb2,0xfbc2), R(0xfd3e,0xfd4f),
+ S(0xfdcf), R(0xfdfc,0xfdff), R(0xfe10,0xfe19), R(0xfe30,0xfe52), R(0xfe54,0xfe66), R(0xfe68,0xfe6b),
+ R(0xff01,0xff0f), R(0xff1a,0xff20), R(0xff3b,0xff40), R(0xff5b,0xff65), R(0xffe0,0xffe6),
+ R(0xffe8,0xffee), R(0xfffc,0xfffd), R(0x10100,0x10102), R(0x10137,0x1013f), R(0x10179,0x10189),
+ R(0x1018c,0x1018e), R(0x10190,0x1019c), S(0x101a0), R(0x101d0,0x101fc), S(0x1039f), S(0x103d0),
+ S(0x1056f), S(0x10857), R(0x10877,0x10878), S(0x1091f), S(0x1093f), R(0x10a50,0x10a58), S(0x10a7f),
+ S(0x10ac8), R(0x10af0,0x10af6), R(0x10b39,0x10b3f), R(0x10b99,0x10b9c), S(0x10ead), R(0x10f55,0x10f59),
+ R(0x10f86,0x10f89), R(0x11047,0x1104d), R(0x110bb,0x110bc), R(0x110be,0x110c1), R(0x11140,0x11143),
+ R(0x11174,0x11175), R(0x111c5,0x111c8), S(0x111cd), S(0x111db), R(0x111dd,0x111df), R(0x11238,0x1123d),
+ S(0x112a9), R(0x1144b,0x1144f), R(0x1145a,0x1145b), S(0x1145d), S(0x114c6), R(0x115c1,0x115d7),
+ R(0x11641,0x11643), R(0x11660,0x1166c), S(0x116b9), R(0x1173c,0x1173f), S(0x1183b), R(0x11944,0x11946),
+ S(0x119e2), R(0x11a3f,0x11a46), R(0x11a9a,0x11a9c), R(0x11a9e,0x11aa2), R(0x11b00,0x11b09),
+ R(0x11c41,0x11c45), R(0x11c70,0x11c71), R(0x11ef7,0x11ef8), R(0x11f43,0x11f4f), R(0x11fd5,0x11ff1),
+ S(0x11fff), R(0x12470,0x12474), R(0x12ff1,0x12ff2), R(0x16a6e,0x16a6f), S(0x16af5), R(0x16b37,0x16b3f),
+ R(0x16b44,0x16b45), R(0x16e97,0x16e9a), S(0x16fe2), S(0x1bc9c), S(0x1bc9f), R(0x1cf50,0x1cfc3),
+ R(0x1d000,0x1d0f5), R(0x1d100,0x1d126), R(0x1d129,0x1d164), R(0x1d16a,0x1d16c), R(0x1d183,0x1d184),
+ R(0x1d18c,0x1d1a9), R(0x1d1ae,0x1d1ea), R(0x1d200,0x1d241), S(0x1d245), R(0x1d300,0x1d356), S(0x1d6c1),
+ S(0x1d6db), S(0x1d6fb), S(0x1d715), S(0x1d735), S(0x1d74f), S(0x1d76f), S(0x1d789), S(0x1d7a9),
+ S(0x1d7c3), R(0x1d800,0x1d9ff), R(0x1da37,0x1da3a), R(0x1da6d,0x1da74), R(0x1da76,0x1da83),
+ R(0x1da85,0x1da8b), S(0x1e14f), S(0x1e2ff), R(0x1e95e,0x1e95f), S(0x1ecac), S(0x1ecb0), S(0x1ed2e),
+ R(0x1eef0,0x1eef1), R(0x1f000,0x1f02b), R(0x1f030,0x1f093), R(0x1f0a0,0x1f0ae), R(0x1f0b1,0x1f0bf),
+ R(0x1f0c1,0x1f0cf), R(0x1f0d1,0x1f0f5), R(0x1f10d,0x1f1ad), R(0x1f1e6,0x1f202), R(0x1f210,0x1f23b),
+ R(0x1f240,0x1f248), R(0x1f250,0x1f251), R(0x1f260,0x1f265), R(0x1f300,0x1f6d7), R(0x1f6dc,0x1f6ec),
+ R(0x1f6f0,0x1f6fc), R(0x1f700,0x1f776), R(0x1f77b,0x1f7d9), R(0x1f7e0,0x1f7eb), S(0x1f7f0),
+ R(0x1f800,0x1f80b), R(0x1f810,0x1f847), R(0x1f850,0x1f859), R(0x1f860,0x1f887), R(0x1f890,0x1f8ad),
+ R(0x1f8b0,0x1f8b1), R(0x1f900,0x1fa53), R(0x1fa60,0x1fa6d), R(0x1fa70,0x1fa7c), R(0x1fa80,0x1fa88),
+ R(0x1fa90,0x1fabd), R(0x1fabf,0x1fac5), R(0x1face,0x1fadb), R(0x1fae0,0x1fae8), R(0x1faf0,0x1faf8),
+ R(0x1fb00,0x1fb92), R(0x1fb94,0x1fbca)
};
#undef R
#undef S
@@ -610,13 +700,14 @@ struct MD_UNICODE_FOLD_INFO_tag {
R(0x1f68,0x1f6f), S(0x1fb8), S(0x1fb9), S(0x1fba), S(0x1fbb), S(0x1fbe), R(0x1fc8,0x1fcb), S(0x1fd8),
S(0x1fd9), S(0x1fda), S(0x1fdb), S(0x1fe8), S(0x1fe9), S(0x1fea), S(0x1feb), S(0x1fec), S(0x1ff8),
S(0x1ff9), S(0x1ffa), S(0x1ffb), S(0x2126), S(0x212a), S(0x212b), S(0x2132), R(0x2160,0x216f), S(0x2183),
- R(0x24b6,0x24cf), R(0x2c00,0x2c2e), S(0x2c60), S(0x2c62), S(0x2c63), S(0x2c64), R(0x2c67,0x2c6b),
+ R(0x24b6,0x24cf), R(0x2c00,0x2c2f), S(0x2c60), S(0x2c62), S(0x2c63), S(0x2c64), R(0x2c67,0x2c6b),
S(0x2c6d), S(0x2c6e), S(0x2c6f), S(0x2c70), S(0x2c72), S(0x2c75), S(0x2c7e), S(0x2c7f), R(0x2c80,0x2ce2),
S(0x2ceb), S(0x2ced), S(0x2cf2), R(0xa640,0xa66c), R(0xa680,0xa69a), R(0xa722,0xa72e), R(0xa732,0xa76e),
S(0xa779), S(0xa77b), S(0xa77d), R(0xa77e,0xa786), S(0xa78b), S(0xa78d), S(0xa790), S(0xa792),
R(0xa796,0xa7a8), S(0xa7aa), S(0xa7ab), S(0xa7ac), S(0xa7ad), S(0xa7ae), S(0xa7b0), S(0xa7b1), S(0xa7b2),
- S(0xa7b3), R(0xa7b4,0xa7be), S(0xa7c2), S(0xa7c4), S(0xa7c5), S(0xa7c6), S(0xa7c7), S(0xa7c9), S(0xa7f5),
- R(0xab70,0xabbf), R(0xff21,0xff3a), R(0x10400,0x10427), R(0x104b0,0x104d3), R(0x10c80,0x10cb2),
+ S(0xa7b3), R(0xa7b4,0xa7c2), S(0xa7c4), S(0xa7c5), S(0xa7c6), S(0xa7c7), S(0xa7c9), S(0xa7d0), S(0xa7d6),
+ S(0xa7d8), S(0xa7f5), R(0xab70,0xabbf), R(0xff21,0xff3a), R(0x10400,0x10427), R(0x104b0,0x104d3),
+ R(0x10570,0x1057a), R(0x1057c,0x1058a), R(0x1058c,0x10592), S(0x10594), S(0x10595), R(0x10c80,0x10cb2),
R(0x118a0,0x118bf), R(0x16e40,0x16e5f), R(0x1e900,0x1e921)
};
static const unsigned FOLD_MAP_1_DATA[] = {
@@ -635,13 +726,13 @@ struct MD_UNICODE_FOLD_INFO_tag {
0x1f10, 0x1f15, 0x1f20, 0x1f27, 0x1f30, 0x1f37, 0x1f40, 0x1f45, 0x1f51, 0x1f53, 0x1f55, 0x1f57, 0x1f60,
0x1f67, 0x1fb0, 0x1fb1, 0x1f70, 0x1f71, 0x03b9, 0x1f72, 0x1f75, 0x1fd0, 0x1fd1, 0x1f76, 0x1f77, 0x1fe0,
0x1fe1, 0x1f7a, 0x1f7b, 0x1fe5, 0x1f78, 0x1f79, 0x1f7c, 0x1f7d, 0x03c9, 0x006b, 0x00e5, 0x214e, 0x2170,
- 0x217f, 0x2184, 0x24d0, 0x24e9, 0x2c30, 0x2c5e, 0x2c61, 0x026b, 0x1d7d, 0x027d, 0x2c68, 0x2c6c, 0x0251,
+ 0x217f, 0x2184, 0x24d0, 0x24e9, 0x2c30, 0x2c5f, 0x2c61, 0x026b, 0x1d7d, 0x027d, 0x2c68, 0x2c6c, 0x0251,
0x0271, 0x0250, 0x0252, 0x2c73, 0x2c76, 0x023f, 0x0240, 0x2c81, 0x2ce3, 0x2cec, 0x2cee, 0x2cf3, 0xa641,
0xa66d, 0xa681, 0xa69b, 0xa723, 0xa72f, 0xa733, 0xa76f, 0xa77a, 0xa77c, 0x1d79, 0xa77f, 0xa787, 0xa78c,
0x0265, 0xa791, 0xa793, 0xa797, 0xa7a9, 0x0266, 0x025c, 0x0261, 0x026c, 0x026a, 0x029e, 0x0287, 0x029d,
- 0xab53, 0xa7b5, 0xa7bf, 0xa7c3, 0xa794, 0x0282, 0x1d8e, 0xa7c8, 0xa7ca, 0xa7f6, 0x13a0, 0x13ef, 0xff41,
- 0xff5a, 0x10428, 0x1044f, 0x104d8, 0x104fb, 0x10cc0, 0x10cf2, 0x118c0, 0x118df, 0x16e60, 0x16e7f, 0x1e922,
- 0x1e943
+ 0xab53, 0xa7b5, 0xa7c3, 0xa794, 0x0282, 0x1d8e, 0xa7c8, 0xa7ca, 0xa7d1, 0xa7d7, 0xa7d9, 0xa7f6, 0x13a0,
+ 0x13ef, 0xff41, 0xff5a, 0x10428, 0x1044f, 0x104d8, 0x104fb, 0x10597, 0x105a1, 0x105a3, 0x105b1, 0x105b3,
+ 0x105b9, 0x105bb, 0x105bc, 0x10cc0, 0x10cf2, 0x118c0, 0x118df, 0x16e60, 0x16e7f, 0x1e922, 0x1e943
};
static const unsigned FOLD_MAP_2[] = {
S(0x00df), S(0x0130), S(0x0149), S(0x01f0), S(0x0587), S(0x1e96), S(0x1e97), S(0x1e98), S(0x1e99),
@@ -894,7 +985,7 @@ struct MD_UNICODE_FOLD_INFO_tag {
* what the caller should allocate.)
*/
static void
-md_merge_lines(MD_CTX* ctx, OFF beg, OFF end, const MD_LINE* lines, int n_lines,
+md_merge_lines(MD_CTX* ctx, OFF beg, OFF end, const MD_LINE* lines, MD_SIZE n_lines,
CHAR line_break_replacement_char, CHAR* buffer, SZ* p_size)
{
CHAR* ptr = buffer;
@@ -931,7 +1022,7 @@ md_merge_lines(MD_CTX* ctx, OFF beg, OFF end, const MD_LINE* lines, int n_lines,
/* Wrapper of md_merge_lines() which allocates new buffer for the output string.
*/
static int
-md_merge_lines_alloc(MD_CTX* ctx, OFF beg, OFF end, const MD_LINE* lines, int n_lines,
+md_merge_lines_alloc(MD_CTX* ctx, OFF beg, OFF end, const MD_LINE* lines, MD_SIZE n_lines,
CHAR line_break_replacement_char, CHAR** p_str, SZ* p_size)
{
CHAR* buffer;
@@ -978,12 +1069,12 @@ md_skip_unicode_whitespace(const CHAR* label, OFF off, SZ size)
* by n_lines == 0.
*/
static int
-md_is_html_tag(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF max_end, OFF* p_end)
+md_is_html_tag(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end)
{
int attr_state;
OFF off = beg;
OFF line_end = (n_lines > 0) ? lines[0].end : ctx->size;
- int i = 0;
+ MD_SIZE line_index = 0;
MD_ASSERT(CH(beg) == _T('<'));
@@ -1073,12 +1164,12 @@ md_is_html_tag(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF max_
if(n_lines == 0)
return FALSE;
- i++;
- if(i >= n_lines)
+ line_index++;
+ if(line_index >= n_lines)
return FALSE;
- off = lines[i].beg;
- line_end = lines[i].end;
+ off = lines[line_index].beg;
+ line_end = lines[line_index].end;
if(attr_state == 0 || attr_state == 41)
attr_state = 1;
@@ -1097,12 +1188,12 @@ done:
static int
md_scan_for_html_closer(MD_CTX* ctx, const MD_CHAR* str, MD_SIZE len,
- const MD_LINE* lines, int n_lines,
+ const MD_LINE* lines, MD_SIZE n_lines,
OFF beg, OFF max_end, OFF* p_end,
OFF* p_scan_horizon)
{
OFF off = beg;
- int i = 0;
+ MD_SIZE line_index = 0;
if(off < *p_scan_horizon && *p_scan_horizon >= max_end - len) {
/* We have already scanned the range up to the max_end so we know
@@ -1111,7 +1202,7 @@ md_scan_for_html_closer(MD_CTX* ctx, const MD_CHAR* str, MD_SIZE len,
}
while(TRUE) {
- while(off + len <= lines[i].end && off + len <= max_end) {
+ while(off + len <= lines[line_index].end && off + len <= max_end) {
if(md_ascii_eq(STR(off), str, len)) {
/* Success. */
*p_end = off + len;
@@ -1120,19 +1211,19 @@ md_scan_for_html_closer(MD_CTX* ctx, const MD_CHAR* str, MD_SIZE len,
off++;
}
- i++;
- if(off >= max_end || i >= n_lines) {
+ line_index++;
+ if(off >= max_end || line_index >= n_lines) {
/* Failure. */
*p_scan_horizon = off;
return FALSE;
}
- off = lines[i].beg;
+ off = lines[line_index].beg;
}
}
static int
-md_is_html_comment(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF max_end, OFF* p_end)
+md_is_html_comment(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end)
{
OFF off = beg;
@@ -1142,30 +1233,17 @@ md_is_html_comment(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF
return FALSE;
if(CH(off+1) != _T('!') || CH(off+2) != _T('-') || CH(off+3) != _T('-'))
return FALSE;
- off += 4;
-
- /* ">" and "->" must not follow the opening. */
- if(off < lines[0].end && CH(off) == _T('>'))
- return FALSE;
- if(off+1 < lines[0].end && CH(off) == _T('-') && CH(off+1) == _T('>'))
- return FALSE;
- /* HTML comment must not contain "--", so we scan just for "--" instead
- * of "-->" and verify manually that '>' follows. */
- if(md_scan_for_html_closer(ctx, _T("--"), 2,
- lines, n_lines, off, max_end, p_end, &ctx->html_comment_horizon))
- {
- if(*p_end < max_end && CH(*p_end) == _T('>')) {
- *p_end = *p_end + 1;
- return TRUE;
- }
- }
+ /* Skip only "<!" so that we accept also "<!-->" or "<!--->" */
+ off += 2;
- return FALSE;
+ /* Scan for ordinary comment closer "-->". */
+ return md_scan_for_html_closer(ctx, _T("-->"), 3,
+ lines, n_lines, off, max_end, p_end, &ctx->html_comment_horizon);
}
static int
-md_is_html_processing_instruction(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF max_end, OFF* p_end)
+md_is_html_processing_instruction(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end)
{
OFF off = beg;
@@ -1180,7 +1258,7 @@ md_is_html_processing_instruction(MD_CTX* ctx, const MD_LINE* lines, int n_lines
}
static int
-md_is_html_declaration(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF max_end, OFF* p_end)
+md_is_html_declaration(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end)
{
OFF off = beg;
@@ -1196,15 +1274,13 @@ md_is_html_declaration(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg,
off++;
while(off < lines[0].end && ISALPHA(off))
off++;
- if(off < lines[0].end && !ISWHITESPACE(off))
- return FALSE;
return md_scan_for_html_closer(ctx, _T(">"), 1,
lines, n_lines, off, max_end, p_end, &ctx->html_decl_horizon);
}
static int
-md_is_html_cdata(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF max_end, OFF* p_end)
+md_is_html_cdata(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end)
{
static const CHAR open_str[] = _T("<![CDATA[");
static const SZ open_size = SIZEOF_ARRAY(open_str) - 1;
@@ -1217,15 +1293,12 @@ md_is_html_cdata(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF ma
return FALSE;
off += open_size;
- if(lines[n_lines-1].end < max_end)
- max_end = lines[n_lines-1].end - 2;
-
return md_scan_for_html_closer(ctx, _T("]]>"), 3,
lines, n_lines, off, max_end, p_end, &ctx->html_cdata_horizon);
}
static int
-md_is_html_any(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg, OFF max_end, OFF* p_end)
+md_is_html_any(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg, OFF max_end, OFF* p_end)
{
MD_ASSERT(CH(beg) == _T('<'));
return (md_is_html_tag(ctx, lines, n_lines, beg, max_end, p_end) ||
@@ -1853,14 +1926,14 @@ struct MD_LINK_ATTR_tag {
static int
-md_is_link_label(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg,
- OFF* p_end, int* p_beg_line_index, int* p_end_line_index,
+md_is_link_label(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg,
+ OFF* p_end, MD_SIZE* p_beg_line_index, MD_SIZE* p_end_line_index,
OFF* p_contents_beg, OFF* p_contents_end)
{
OFF off = beg;
OFF contents_beg = 0;
OFF contents_end = 0;
- int line_index = 0;
+ MD_SIZE line_index = 0;
int len = 0;
if(CH(off) != _T('['))
@@ -2010,13 +2083,13 @@ md_is_link_destination(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end,
}
static int
-md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg,
- OFF* p_end, int* p_beg_line_index, int* p_end_line_index,
+md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg,
+ OFF* p_end, MD_SIZE* p_beg_line_index, MD_SIZE* p_end_line_index,
OFF* p_contents_beg, OFF* p_contents_end)
{
OFF off = beg;
CHAR closer_char;
- int line_index = 0;
+ MD_SIZE line_index = 0;
/* White space with up to one line break. */
while(off < lines[line_index].end && ISWHITESPACE(off))
@@ -2078,21 +2151,21 @@ md_is_link_title(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg,
* Returns -1 in case of an error (out of memory).
*/
static int
-md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
+md_is_link_reference_definition(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines)
{
OFF label_contents_beg;
OFF label_contents_end;
- int label_contents_line_index = -1;
+ MD_SIZE label_contents_line_index;
int label_is_multiline = FALSE;
OFF dest_contents_beg;
OFF dest_contents_end;
OFF title_contents_beg;
OFF title_contents_end;
- int title_contents_line_index;
+ MD_SIZE title_contents_line_index;
int title_is_multiline = FALSE;
OFF off;
- int line_index = 0;
- int tmp_line_index;
+ MD_SIZE line_index = 0;
+ MD_SIZE tmp_line_index;
MD_REF_DEF* def = NULL;
int ret = 0;
@@ -2200,12 +2273,12 @@ abort:
}
static int
-md_is_link_reference(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
+md_is_link_reference(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines,
OFF beg, OFF end, MD_LINK_ATTR* attr)
{
const MD_REF_DEF* def;
const MD_LINE* beg_line;
- const MD_LINE* end_line;
+ int is_multiline;
CHAR* label;
SZ label_size;
int ret;
@@ -2217,17 +2290,10 @@ md_is_link_reference(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
end--;
/* Find lines corresponding to the beg and end positions. */
- MD_ASSERT(lines[0].beg <= beg);
- beg_line = lines;
- while(beg >= beg_line->end)
- beg_line++;
-
- MD_ASSERT(end <= lines[n_lines-1].end);
- end_line = beg_line;
- while(end >= end_line->end)
- end_line++;
+ beg_line = md_lookup_line(beg, lines, n_lines, NULL);
+ is_multiline = (end > beg_line->end);
- if(beg_line != end_line) {
+ if(is_multiline) {
MD_CHECK(md_merge_lines_alloc(ctx, beg, end, beg_line,
(int)(n_lines - (beg_line - lines)), _T(' '), &label, &label_size));
} else {
@@ -2244,7 +2310,7 @@ md_is_link_reference(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
attr->title_needs_free = FALSE;
}
- if(beg_line != end_line)
+ if(is_multiline)
free(label);
ret = (def != NULL);
@@ -2254,14 +2320,14 @@ abort:
}
static int
-md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
+md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines,
OFF beg, OFF* p_end, MD_LINK_ATTR* attr)
{
- int line_index = 0;
- int tmp_line_index;
+ MD_SIZE line_index = 0;
+ MD_SIZE tmp_line_index;
OFF title_contents_beg;
OFF title_contents_end;
- int title_contents_line_index;
+ MD_SIZE title_contents_line_index;
int title_is_multiline;
OFF off = beg;
int ret = FALSE;
@@ -2275,7 +2341,7 @@ md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
/* Optional white space with up to one line break. */
while(off < lines[line_index].end && ISWHITESPACE(off))
off++;
- if(off >= lines[line_index].end && ISNEWLINE(off)) {
+ if(off >= lines[line_index].end && (off >= ctx->size || ISNEWLINE(off))) {
line_index++;
if(line_index >= n_lines)
return FALSE;
@@ -2318,7 +2384,7 @@ md_is_inline_link_spec(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
/* Optional whitespace followed with final ')'. */
while(off < lines[line_index].end && ISWHITESPACE(off))
off++;
- if(off >= lines[line_index].end && ISNEWLINE(off)) {
+ if(off >= lines[line_index].end) {
line_index++;
if(line_index >= n_lines)
return FALSE;
@@ -2438,11 +2504,11 @@ struct MD_MARK_tag {
OFF beg;
OFF end;
- /* For unresolved openers, 'prev' and 'next' form the chain of open openers
- * of given type 'ch'.
+ /* For unresolved openers, 'next' may be used to form a stack of
+ * unresolved open openers.
*
- * During resolving, we disconnect from the chain and point to the
- * corresponding counterpart so opener points to its closer and vice versa.
+ * When resolved with MD_MARK_OPENER/CLOSER flag, next/prev is index of the
+ * respective closer/opener.
*/
int prev;
int next;
@@ -2458,46 +2524,60 @@ struct MD_MARK_tag {
#define MD_MARK_RESOLVED 0x10 /* Resolved in any definite way. */
/* Mark flags specific for various mark types (so they can share bits). */
-#define MD_MARK_EMPH_INTRAWORD 0x20 /* Helper for the "rule of 3". */
+#define MD_MARK_EMPH_OC 0x20 /* Opener/closer mixed candidate. Helper for the "rule of 3". */
#define MD_MARK_EMPH_MOD3_0 0x40
#define MD_MARK_EMPH_MOD3_1 0x80
#define MD_MARK_EMPH_MOD3_2 (0x40 | 0x80)
#define MD_MARK_EMPH_MOD3_MASK (0x40 | 0x80)
#define MD_MARK_AUTOLINK 0x20 /* Distinguisher for '<', '>'. */
+#define MD_MARK_AUTOLINK_MISSING_MAILTO 0x40
#define MD_MARK_VALIDPERMISSIVEAUTOLINK 0x20 /* For permissive autolinks. */
+#define MD_MARK_HASNESTEDBRACKETS 0x20 /* For '[' to rule out invalid link labels early */
-static MD_MARKCHAIN*
-md_asterisk_chain(MD_CTX* ctx, unsigned flags)
+static MD_MARKSTACK*
+md_emph_stack(MD_CTX* ctx, MD_CHAR ch, unsigned flags)
{
- switch(flags & (MD_MARK_EMPH_INTRAWORD | MD_MARK_EMPH_MOD3_MASK)) {
- case MD_MARK_EMPH_INTRAWORD | MD_MARK_EMPH_MOD3_0: return &ASTERISK_OPENERS_intraword_mod3_0;
- case MD_MARK_EMPH_INTRAWORD | MD_MARK_EMPH_MOD3_1: return &ASTERISK_OPENERS_intraword_mod3_1;
- case MD_MARK_EMPH_INTRAWORD | MD_MARK_EMPH_MOD3_2: return &ASTERISK_OPENERS_intraword_mod3_2;
- case MD_MARK_EMPH_MOD3_0: return &ASTERISK_OPENERS_extraword_mod3_0;
- case MD_MARK_EMPH_MOD3_1: return &ASTERISK_OPENERS_extraword_mod3_1;
- case MD_MARK_EMPH_MOD3_2: return &ASTERISK_OPENERS_extraword_mod3_2;
- default: MD_UNREACHABLE();
+ MD_MARKSTACK* stack;
+
+ switch(ch) {
+ case '*': stack = &ASTERISK_OPENERS_oo_mod3_0; break;
+ case '_': stack = &UNDERSCORE_OPENERS_oo_mod3_0; break;
+ default: MD_UNREACHABLE();
}
- return NULL;
+
+ if(flags & MD_MARK_EMPH_OC)
+ stack += 3;
+
+ switch(flags & MD_MARK_EMPH_MOD3_MASK) {
+ case MD_MARK_EMPH_MOD3_0: stack += 0; break;
+ case MD_MARK_EMPH_MOD3_1: stack += 1; break;
+ case MD_MARK_EMPH_MOD3_2: stack += 2; break;
+ default: MD_UNREACHABLE();
+ }
+
+ return stack;
}
-static MD_MARKCHAIN*
-md_mark_chain(MD_CTX* ctx, int mark_index)
+static MD_MARKSTACK*
+md_opener_stack(MD_CTX* ctx, int mark_index)
{
MD_MARK* mark = &ctx->marks[mark_index];
switch(mark->ch) {
- case _T('*'): return md_asterisk_chain(ctx, mark->flags);
- case _T('_'): return &UNDERSCORE_OPENERS;
+ case _T('*'):
+ case _T('_'): return md_emph_stack(ctx, mark->ch, mark->flags);
+
case _T('~'): return (mark->end - mark->beg == 1) ? &TILDE_OPENERS_1 : &TILDE_OPENERS_2;
+
+ case _T('!'):
case _T('['): return &BRACKET_OPENERS;
- case _T('|'): return &TABLECELLBOUNDARIES;
- default: return NULL;
+
+ default: MD_UNREACHABLE();
}
}
static MD_MARK*
-md_push_mark(MD_CTX* ctx)
+md_add_mark(MD_CTX* ctx)
{
if(ctx->n_marks >= ctx->alloc_marks) {
MD_MARK* new_marks;
@@ -2517,18 +2597,18 @@ md_push_mark(MD_CTX* ctx)
return &ctx->marks[ctx->n_marks++];
}
-#define PUSH_MARK_() \
+#define ADD_MARK_() \
do { \
- mark = md_push_mark(ctx); \
+ mark = md_add_mark(ctx); \
if(mark == NULL) { \
ret = -1; \
goto abort; \
} \
} while(0)
-#define PUSH_MARK(ch_, beg_, end_, flags_) \
+#define ADD_MARK(ch_, beg_, end_, flags_) \
do { \
- PUSH_MARK_(); \
+ ADD_MARK_(); \
mark->beg = (beg_); \
mark->end = (end_); \
mark->prev = -1; \
@@ -2538,17 +2618,20 @@ md_push_mark(MD_CTX* ctx)
} while(0)
-static void
-md_mark_chain_append(MD_CTX* ctx, MD_MARKCHAIN* chain, int mark_index)
+static inline void
+md_mark_stack_push(MD_CTX* ctx, MD_MARKSTACK* stack, int mark_index)
{
- if(chain->tail >= 0)
- ctx->marks[chain->tail].next = mark_index;
- else
- chain->head = mark_index;
+ ctx->marks[mark_index].next = stack->top;
+ stack->top = mark_index;
+}
- ctx->marks[mark_index].prev = chain->tail;
- ctx->marks[mark_index].next = -1;
- chain->tail = mark_index;
+static inline int
+md_mark_stack_pop(MD_CTX* ctx, MD_MARKSTACK* stack)
+{
+ int top = stack->top;
+ if(top >= 0)
+ stack->top = ctx->marks[top].next;
+ return top;
}
/* Sometimes, we need to store a pointer into the mark. It is quite rare
@@ -2575,112 +2658,52 @@ md_mark_get_ptr(MD_CTX* ctx, int mark_index)
return ptr;
}
-static void
-md_resolve_range(MD_CTX* ctx, MD_MARKCHAIN* chain, int opener_index, int closer_index)
+static inline void
+md_resolve_range(MD_CTX* ctx, int opener_index, int closer_index)
{
MD_MARK* opener = &ctx->marks[opener_index];
MD_MARK* closer = &ctx->marks[closer_index];
- /* Remove opener from the list of openers. */
- if(chain != NULL) {
- if(opener->prev >= 0)
- ctx->marks[opener->prev].next = opener->next;
- else
- chain->head = opener->next;
-
- if(opener->next >= 0)
- ctx->marks[opener->next].prev = opener->prev;
- else
- chain->tail = opener->prev;
- }
-
/* Interconnect opener and closer and mark both as resolved. */
opener->next = closer_index;
- opener->flags |= MD_MARK_OPENER | MD_MARK_RESOLVED;
closer->prev = opener_index;
+
+ opener->flags |= MD_MARK_OPENER | MD_MARK_RESOLVED;
closer->flags |= MD_MARK_CLOSER | MD_MARK_RESOLVED;
}
-#define MD_ROLLBACK_ALL 0
-#define MD_ROLLBACK_CROSSING 1
+#define MD_ROLLBACK_CROSSING 0
+#define MD_ROLLBACK_ALL 1
/* In the range ctx->marks[opener_index] ... [closer_index], undo some or all
* resolvings accordingly to these rules:
*
- * (1) All openers BEFORE the range corresponding to any closer inside the
- * range are un-resolved and they are re-added to their respective chains
- * of unresolved openers. This ensures we can reuse the opener for closers
- * AFTER the range.
+ * (1) All stacks of openers are cut so that any pending potential openers
+ * are discarded from future consideration.
*
* (2) If 'how' is MD_ROLLBACK_ALL, then ALL resolved marks inside the range
- * are discarded.
+ * are thrown away and turned into dummy marks ('D').
*
- * (3) If 'how' is MD_ROLLBACK_CROSSING, only closers with openers handled
- * in (1) are discarded. I.e. pairs of openers and closers which are both
- * inside the range are retained as well as any unpaired marks.
+ * WARNING: Do not call for arbitrary range of opener and closer.
+ * This must form (potentially) valid range not crossing nesting boundaries
+ * of already resolved ranges.
*/
static void
md_rollback(MD_CTX* ctx, int opener_index, int closer_index, int how)
{
int i;
- int mark_index;
-
- /* Cut all unresolved openers at the mark index. */
- for(i = OPENERS_CHAIN_FIRST; i < OPENERS_CHAIN_LAST+1; i++) {
- MD_MARKCHAIN* chain = &ctx->mark_chains[i];
-
- while(chain->tail >= opener_index)
- chain->tail = ctx->marks[chain->tail].prev;
- if(chain->tail >= 0)
- ctx->marks[chain->tail].next = -1;
- else
- chain->head = -1;
- }
-
- /* Go backwards so that unresolved openers are re-added into their
- * respective chains, in the right order. */
- mark_index = closer_index - 1;
- while(mark_index > opener_index) {
- MD_MARK* mark = &ctx->marks[mark_index];
- int mark_flags = mark->flags;
- int discard_flag = (how == MD_ROLLBACK_ALL);
-
- if(mark->flags & MD_MARK_CLOSER) {
- int mark_opener_index = mark->prev;
-
- /* Undo opener BEFORE the range. */
- if(mark_opener_index < opener_index) {
- MD_MARK* mark_opener = &ctx->marks[mark_opener_index];
- MD_MARKCHAIN* chain;
-
- mark_opener->flags &= ~(MD_MARK_OPENER | MD_MARK_CLOSER | MD_MARK_RESOLVED);
- chain = md_mark_chain(ctx, opener_index);
- if(chain != NULL) {
- md_mark_chain_append(ctx, chain, mark_opener_index);
- discard_flag = 1;
- }
- }
- }
+ for(i = 0; i < (int) SIZEOF_ARRAY(ctx->opener_stacks); i++) {
+ MD_MARKSTACK* stack = &ctx->opener_stacks[i];
+ while(stack->top >= opener_index)
+ md_mark_stack_pop(ctx, stack);
+ }
- /* And reset our flags. */
- if(discard_flag)
- mark->flags &= ~(MD_MARK_OPENER | MD_MARK_CLOSER | MD_MARK_RESOLVED);
-
- /* Jump as far as we can over unresolved or non-interesting marks. */
- switch(how) {
- case MD_ROLLBACK_CROSSING:
- if((mark_flags & MD_MARK_CLOSER) && mark->prev > opener_index) {
- /* If we are closer with opener INSIDE the range, there may
- * not be any other crosser inside the subrange. */
- mark_index = mark->prev;
- break;
- }
- MD_FALLTHROUGH();
- default:
- mark_index--;
- break;
+ if(how == MD_ROLLBACK_ALL) {
+ for(i = opener_index + 1; i < closer_index; i++) {
+ ctx->marks[i].ch = 'D';
+ ctx->marks[i].flags = 0;
}
}
}
@@ -2731,15 +2754,9 @@ md_build_mark_char_map(MD_CTX* ctx)
}
}
-/* We limit code span marks to lower than 32 backticks. This solves the
- * pathologic case of too many openers, each of different length: Their
- * resolving would be then O(n^2). */
-#define CODESPAN_MARK_MAXLEN 32
-
static int
-md_is_code_span(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg,
- OFF* p_opener_beg, OFF* p_opener_end,
- OFF* p_closer_beg, OFF* p_closer_end,
+md_is_code_span(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, OFF beg,
+ MD_MARK* opener, MD_MARK* closer,
OFF last_potential_closers[CODESPAN_MARK_MAXLEN],
int* p_reached_paragraph_end)
{
@@ -2754,7 +2771,7 @@ md_is_code_span(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg,
int has_space_before_closer = FALSE;
int has_eol_before_closer = FALSE;
int has_only_space = TRUE;
- int line_index = 0;
+ MD_SIZE line_index = 0;
line_end = lines[0].end;
opener_end = opener_beg;
@@ -2764,7 +2781,7 @@ md_is_code_span(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg,
has_eol_after_opener = (opener_end == line_end);
/* The caller needs to know end of the opening mark even if we fail. */
- *p_opener_end = opener_end;
+ opener->end = opener_end;
mark_len = opener_end - opener_beg;
if(mark_len > CODESPAN_MARK_MAXLEN)
@@ -2840,18 +2857,22 @@ md_is_code_span(MD_CTX* ctx, const MD_LINE* lines, int n_lines, OFF beg,
if(has_space_before_closer)
closer_beg--;
else {
+ /* Go back to the end of prev line */
closer_beg = lines[line_index-1].end;
- /* We need to eat the preceding "\r\n" but not any line trailing
- * spaces. */
+ /* But restore any trailing whitespace */
while(closer_beg < ctx->size && ISBLANK(closer_beg))
closer_beg++;
}
}
- *p_opener_beg = opener_beg;
- *p_opener_end = opener_end;
- *p_closer_beg = closer_beg;
- *p_closer_end = closer_end;
+ opener->ch = _T('`');
+ opener->beg = opener_beg;
+ opener->end = opener_end;
+ opener->flags = MD_MARK_POTENTIAL_OPENER;
+ closer->ch = _T('`');
+ closer->beg = closer_beg;
+ closer->end = closer_end;
+ closer->flags = MD_MARK_POTENTIAL_CLOSER;
return TRUE;
}
@@ -2961,18 +2982,17 @@ md_is_autolink(MD_CTX* ctx, OFF beg, OFF max_end, OFF* p_end, int* p_missing_mai
}
static int
-md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
+md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, int table_mode)
{
- int i;
+ MD_SIZE line_index;
int ret = 0;
MD_MARK* mark;
OFF codespan_last_potential_closers[CODESPAN_MARK_MAXLEN] = { 0 };
int codespan_scanned_till_paragraph_end = FALSE;
- for(i = 0; i < n_lines; i++) {
- const MD_LINE* line = &lines[i];
+ for(line_index = 0; line_index < n_lines; line_index++) {
+ const MD_LINE* line = &lines[line_index];
OFF off = line->beg;
- OFF line_end = line->end;
while(TRUE) {
CHAR ch;
@@ -2987,13 +3007,13 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
#endif
/* Optimization: Use some loop unrolling. */
- while(off + 3 < line_end && !IS_MARK_CHAR(off+0) && !IS_MARK_CHAR(off+1)
- && !IS_MARK_CHAR(off+2) && !IS_MARK_CHAR(off+3))
+ while(off + 3 < line->end && !IS_MARK_CHAR(off+0) && !IS_MARK_CHAR(off+1)
+ && !IS_MARK_CHAR(off+2) && !IS_MARK_CHAR(off+3))
off += 4;
- while(off < line_end && !IS_MARK_CHAR(off+0))
+ while(off < line->end && !IS_MARK_CHAR(off+0))
off++;
- if(off >= line_end)
+ if(off >= line->end)
break;
ch = CH(off);
@@ -3003,8 +3023,8 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
* line to form a hard break. */
if(ch == _T('\\') && off+1 < ctx->size && (ISPUNCT(off+1) || ISNEWLINE(off+1))) {
/* Hard-break cannot be on the last line of the block. */
- if(!ISNEWLINE(off+1) || i+1 < n_lines)
- PUSH_MARK(ch, off, off+2, MD_MARK_RESOLVED);
+ if(!ISNEWLINE(off+1) || line_index+1 < n_lines)
+ ADD_MARK(ch, off, off+2, MD_MARK_RESOLVED);
off += 2;
continue;
}
@@ -3015,7 +3035,7 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
int left_level; /* What precedes: 0 = whitespace; 1 = punctuation; 2 = other char. */
int right_level; /* What follows: 0 = whitespace; 1 = punctuation; 2 = other char. */
- while(tmp < line_end && CH(tmp) == ch)
+ while(tmp < line->end && CH(tmp) == ch)
tmp++;
if(off == line->beg || ISUNICODEWHITESPACEBEFORE(off))
@@ -3025,7 +3045,7 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
else
left_level = 2;
- if(tmp == line_end || ISUNICODEWHITESPACE(tmp))
+ if(tmp == line->end || ISUNICODEWHITESPACE(tmp))
right_level = 0;
else if(ISUNICODEPUNCT(tmp))
right_level = 1;
@@ -3045,8 +3065,8 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
flags |= MD_MARK_POTENTIAL_CLOSER;
if(right_level > 0 && right_level >= left_level)
flags |= MD_MARK_POTENTIAL_OPENER;
- if(left_level == 2 && right_level == 2)
- flags |= MD_MARK_EMPH_INTRAWORD;
+ if(flags == (MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER))
+ flags |= MD_MARK_EMPH_OC;
/* For "the rule of three" we need to remember the original
* size of the mark (modulo three), before we potentially
@@ -3058,7 +3078,7 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
case 2: flags |= MD_MARK_EMPH_MOD3_2; break;
}
- PUSH_MARK(ch, off, tmp, flags);
+ ADD_MARK(ch, off, tmp, flags);
/* During resolving, multiple asterisks may have to be
* split into independent span start/ends. Consider e.g.
@@ -3066,7 +3086,7 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
* marks to have enough space for that. */
off++;
while(off < tmp) {
- PUSH_MARK('D', off, off, 0);
+ ADD_MARK('D', off, off, 0);
off++;
}
continue;
@@ -3078,38 +3098,32 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
/* A potential code span start/end. */
if(ch == _T('`')) {
- OFF opener_beg, opener_end;
- OFF closer_beg, closer_end;
+ MD_MARK opener;
+ MD_MARK closer;
int is_code_span;
- is_code_span = md_is_code_span(ctx, lines + i, n_lines - i, off,
- &opener_beg, &opener_end, &closer_beg, &closer_end,
- codespan_last_potential_closers,
- &codespan_scanned_till_paragraph_end);
+ is_code_span = md_is_code_span(ctx, line, n_lines - line_index, off,
+ &opener, &closer, codespan_last_potential_closers,
+ &codespan_scanned_till_paragraph_end);
if(is_code_span) {
- PUSH_MARK(_T('`'), opener_beg, opener_end, MD_MARK_OPENER | MD_MARK_RESOLVED);
- PUSH_MARK(_T('`'), closer_beg, closer_end, MD_MARK_CLOSER | MD_MARK_RESOLVED);
- ctx->marks[ctx->n_marks-2].next = ctx->n_marks-1;
- ctx->marks[ctx->n_marks-1].prev = ctx->n_marks-2;
-
- off = closer_end;
+ ADD_MARK(opener.ch, opener.beg, opener.end, opener.flags);
+ ADD_MARK(closer.ch, closer.beg, closer.end, closer.flags);
+ md_resolve_range(ctx, ctx->n_marks-2, ctx->n_marks-1);
+ off = closer.end;
/* Advance the current line accordingly. */
- while(off > line_end) {
- i++;
- line++;
- line_end = line->end;
- }
+ if(off > line->end)
+ line = md_lookup_line(off, lines, n_lines, &line_index);
continue;
}
- off = opener_end;
+ off = opener.end;
continue;
}
/* A potential entity start. */
if(ch == _T('&')) {
- PUSH_MARK(ch, off, off+1, MD_MARK_POTENTIAL_OPENER);
+ ADD_MARK(ch, off, off+1, MD_MARK_POTENTIAL_OPENER);
off++;
continue;
}
@@ -3118,7 +3132,7 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
if(ch == _T(';')) {
/* We surely cannot be entity unless the previous mark is '&'. */
if(ctx->n_marks > 0 && ctx->marks[ctx->n_marks-1].ch == _T('&'))
- PUSH_MARK(ch, off, off+1, MD_MARK_POTENTIAL_CLOSER);
+ ADD_MARK(ch, off, off+1, MD_MARK_POTENTIAL_CLOSER);
off++;
continue;
@@ -3137,21 +3151,18 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
/* Given the nature of the raw HTML, we have to recognize
* it here. Doing so later in md_analyze_lt_gt() could
* open can of worms of quadratic complexity. */
- is_html = md_is_html_any(ctx, lines + i, n_lines - i, off,
+ is_html = md_is_html_any(ctx, line, n_lines - line_index, off,
lines[n_lines-1].end, &html_end);
if(is_html) {
- PUSH_MARK(_T('<'), off, off, MD_MARK_OPENER | MD_MARK_RESOLVED);
- PUSH_MARK(_T('>'), html_end, html_end, MD_MARK_CLOSER | MD_MARK_RESOLVED);
+ ADD_MARK(_T('<'), off, off, MD_MARK_OPENER | MD_MARK_RESOLVED);
+ ADD_MARK(_T('>'), html_end, html_end, MD_MARK_CLOSER | MD_MARK_RESOLVED);
ctx->marks[ctx->n_marks-2].next = ctx->n_marks-1;
ctx->marks[ctx->n_marks-1].prev = ctx->n_marks-2;
off = html_end;
/* Advance the current line accordingly. */
- while(off > line_end) {
- i++;
- line++;
- line_end = line->end;
- }
+ if(off > line->end)
+ line = md_lookup_line(off, lines, n_lines, &line_index);
continue;
}
}
@@ -3159,10 +3170,12 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
is_autolink = md_is_autolink(ctx, off, lines[n_lines-1].end,
&autolink_end, &missing_mailto);
if(is_autolink) {
- PUSH_MARK((missing_mailto ? _T('@') : _T('<')), off, off+1,
- MD_MARK_OPENER | MD_MARK_RESOLVED | MD_MARK_AUTOLINK);
- PUSH_MARK(_T('>'), autolink_end-1, autolink_end,
- MD_MARK_CLOSER | MD_MARK_RESOLVED | MD_MARK_AUTOLINK);
+ unsigned flags = MD_MARK_RESOLVED | MD_MARK_AUTOLINK;
+ if(missing_mailto)
+ flags |= MD_MARK_AUTOLINK_MISSING_MAILTO;
+
+ ADD_MARK(_T('<'), off, off+1, MD_MARK_OPENER | flags);
+ ADD_MARK(_T('>'), autolink_end-1, autolink_end, MD_MARK_CLOSER | flags);
ctx->marks[ctx->n_marks-2].next = ctx->n_marks-1;
ctx->marks[ctx->n_marks-1].prev = ctx->n_marks-2;
off = autolink_end;
@@ -3174,18 +3187,18 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
}
/* A potential link or its part. */
- if(ch == _T('[') || (ch == _T('!') && off+1 < line_end && CH(off+1) == _T('['))) {
+ if(ch == _T('[') || (ch == _T('!') && off+1 < line->end && CH(off+1) == _T('['))) {
OFF tmp = (ch == _T('[') ? off+1 : off+2);
- PUSH_MARK(ch, off, tmp, MD_MARK_POTENTIAL_OPENER);
+ ADD_MARK(ch, off, tmp, MD_MARK_POTENTIAL_OPENER);
off = tmp;
/* Two dummies to make enough place for data we need if it is
* a link. */
- PUSH_MARK('D', off, off, 0);
- PUSH_MARK('D', off, off, 0);
+ ADD_MARK('D', off, off, 0);
+ ADD_MARK('D', off, off, 0);
continue;
}
if(ch == _T(']')) {
- PUSH_MARK(ch, off, off+1, MD_MARK_POTENTIAL_CLOSER);
+ ADD_MARK(ch, off, off+1, MD_MARK_POTENTIAL_CLOSER);
off++;
continue;
}
@@ -3195,9 +3208,9 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
if(line->beg + 1 <= off && ISALNUM(off-1) &&
off + 3 < line->end && ISALNUM(off+1))
{
- PUSH_MARK(ch, off, off+1, MD_MARK_POTENTIAL_OPENER);
+ ADD_MARK(ch, off, off+1, MD_MARK_POTENTIAL_OPENER);
/* Push a dummy as a reserve for a closer. */
- PUSH_MARK('D', off, off, 0);
+ ADD_MARK('D', line->beg, line->end, 0);
}
off++;
@@ -3226,12 +3239,11 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
const SZ suffix_size = scheme_map[scheme_index].suffix_size;
if(line->beg + scheme_size <= off && md_ascii_eq(STR(off-scheme_size), scheme, scheme_size) &&
- (line->beg + scheme_size == off || ISWHITESPACE(off-scheme_size-1) || ISANYOF(off-scheme_size-1, _T("*_~(["))) &&
off + 1 + suffix_size < line->end && md_ascii_eq(STR(off+1), suffix, suffix_size))
{
- PUSH_MARK(ch, off-scheme_size, off+1+suffix_size, MD_MARK_POTENTIAL_OPENER);
+ ADD_MARK(ch, off-scheme_size, off+1+suffix_size, MD_MARK_POTENTIAL_OPENER);
/* Push a dummy as a reserve for a closer. */
- PUSH_MARK('D', off, off, 0);
+ ADD_MARK('D', line->beg, line->end, 0);
off += 1 + suffix_size;
break;
}
@@ -3244,12 +3256,11 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
/* A potential permissive WWW autolink. */
if(ch == _T('.')) {
if(line->beg + 3 <= off && md_ascii_eq(STR(off-3), _T("www"), 3) &&
- (line->beg + 3 == off || ISWHITESPACE(off-4) || ISANYOF(off-4, _T("*_~(["))) &&
- off + 1 < line_end)
+ (off-3 == line->beg || ISUNICODEWHITESPACEBEFORE(off-3) || ISUNICODEPUNCTBEFORE(off-3)))
{
- PUSH_MARK(ch, off-3, off+1, MD_MARK_POTENTIAL_OPENER);
+ ADD_MARK(ch, off-3, off+1, MD_MARK_POTENTIAL_OPENER);
/* Push a dummy as a reserve for a closer. */
- PUSH_MARK('D', off, off, 0);
+ ADD_MARK('D', line->beg, line->end, 0);
off++;
continue;
}
@@ -3260,7 +3271,7 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
/* A potential table cell boundary or wiki link label delimiter. */
if((table_mode || ctx->parser.flags & MD_FLAG_WIKILINKS) && ch == _T('|')) {
- PUSH_MARK(ch, off, off+1, 0);
+ ADD_MARK(ch, off, off+1, 0);
off++;
continue;
}
@@ -3269,18 +3280,18 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
if(ch == _T('~')) {
OFF tmp = off+1;
- while(tmp < line_end && CH(tmp) == _T('~'))
+ while(tmp < line->end && CH(tmp) == _T('~'))
tmp++;
if(tmp - off < 3) {
unsigned flags = 0;
- if(tmp < line_end && !ISUNICODEWHITESPACE(tmp))
+ if(tmp < line->end && !ISUNICODEWHITESPACE(tmp))
flags |= MD_MARK_POTENTIAL_OPENER;
if(off > line->beg && !ISUNICODEWHITESPACEBEFORE(off))
flags |= MD_MARK_POTENTIAL_CLOSER;
if(flags != 0)
- PUSH_MARK(ch, off, tmp, flags);
+ ADD_MARK(ch, off, tmp, flags);
}
off = tmp;
@@ -3293,11 +3304,20 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
* where two dollar signs signify a display equation. */
OFF tmp = off+1;
- while(tmp < line_end && CH(tmp) == _T('$'))
+ while(tmp < line->end && CH(tmp) == _T('$'))
tmp++;
- if (tmp - off <= 2)
- PUSH_MARK(ch, off, tmp, MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER);
+ if(tmp - off <= 2) {
+ unsigned flags = MD_MARK_POTENTIAL_OPENER | MD_MARK_POTENTIAL_CLOSER;
+
+ if(off > line->beg && !ISUNICODEWHITESPACEBEFORE(off) && !ISUNICODEPUNCTBEFORE(off))
+ flags &= ~MD_MARK_POTENTIAL_OPENER;
+ if(tmp < line->end && !ISUNICODEWHITESPACE(tmp) && !ISUNICODEPUNCT(tmp))
+ flags &= ~MD_MARK_POTENTIAL_CLOSER;
+ if(flags != 0)
+ ADD_MARK(ch, off, tmp, flags);
+ }
+
off = tmp;
continue;
}
@@ -3306,11 +3326,11 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
if(ISWHITESPACE_(ch)) {
OFF tmp = off+1;
- while(tmp < line_end && ISWHITESPACE(tmp))
+ while(tmp < line->end && ISWHITESPACE(tmp))
tmp++;
if(tmp - off > 1 || ch != _T(' '))
- PUSH_MARK(ch, off, tmp, MD_MARK_RESOLVED);
+ ADD_MARK(ch, off, tmp, MD_MARK_RESOLVED);
off = tmp;
continue;
@@ -3318,7 +3338,7 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
/* NULL character. */
if(ch == _T('\0')) {
- PUSH_MARK(ch, off, off+1, MD_MARK_RESOLVED);
+ ADD_MARK(ch, off, off+1, MD_MARK_RESOLVED);
off++;
continue;
}
@@ -3329,7 +3349,7 @@ md_collect_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
/* Add a dummy mark at the end of the mark vector to simplify
* process_inlines(). */
- PUSH_MARK(127, ctx->size, ctx->size, MD_MARK_RESOLVED);
+ ADD_MARK(127, ctx->size, ctx->size, MD_MARK_RESOLVED);
abort:
return ret;
@@ -3343,36 +3363,33 @@ md_analyze_bracket(MD_CTX* ctx, int mark_index)
* or enclosing pair of brackets (if the inner is the link, the outer
* one cannot be.)
*
- * Therefore we here only construct a list of resolved '[' ']' pairs
- * ordered by position of the closer. This allows ur to analyze what is
- * or is not link in the right order, from inside to outside in case
- * of nested brackets.
+ * Therefore we here only construct a list of '[' ']' pairs ordered by
+ * position of the closer. This allows us to analyze what is or is not
+ * link in the right order, from inside to outside in case of nested
+ * brackets.
*
- * The resolving itself is deferred into md_resolve_links().
+ * The resolving itself is deferred to md_resolve_links().
*/
MD_MARK* mark = &ctx->marks[mark_index];
if(mark->flags & MD_MARK_POTENTIAL_OPENER) {
- md_mark_chain_append(ctx, &BRACKET_OPENERS, mark_index);
+ if(BRACKET_OPENERS.top >= 0)
+ ctx->marks[BRACKET_OPENERS.top].flags |= MD_MARK_HASNESTEDBRACKETS;
+
+ md_mark_stack_push(ctx, &BRACKET_OPENERS, mark_index);
return;
}
- if(BRACKET_OPENERS.tail >= 0) {
- /* Pop the opener from the chain. */
- int opener_index = BRACKET_OPENERS.tail;
+ if(BRACKET_OPENERS.top >= 0) {
+ int opener_index = md_mark_stack_pop(ctx, &BRACKET_OPENERS);
MD_MARK* opener = &ctx->marks[opener_index];
- if(opener->prev >= 0)
- ctx->marks[opener->prev].next = -1;
- else
- BRACKET_OPENERS.head = -1;
- BRACKET_OPENERS.tail = opener->prev;
/* Interconnect the opener and closer. */
opener->next = mark_index;
mark->prev = opener_index;
- /* Add the pair into chain of potential links for md_resolve_links().
+ /* Add the pair into a list of potential links for md_resolve_links().
* Note we misuse opener->prev for this as opener->next points to its
* closer. */
if(ctx->unresolved_link_tail >= 0)
@@ -3385,11 +3402,11 @@ md_analyze_bracket(MD_CTX* ctx, int mark_index)
}
/* Forward declaration. */
-static void md_analyze_link_contents(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
+static void md_analyze_link_contents(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines,
int mark_beg, int mark_end);
static int
-md_resolve_links(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
+md_resolve_links(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines)
{
int opener_index = ctx->unresolved_link_head;
OFF last_link_beg = 0;
@@ -3460,10 +3477,15 @@ md_resolve_links(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
delim = m;
break;
}
- if(m->ch != 'D' && m->beg - opener->end > 100)
- break;
+ if(m->ch != 'D') {
+ if(m->beg - opener->end > 100)
+ break;
+ if(m->ch != 'D' && (m->flags & MD_MARK_OPENER))
+ delim_index = m->next;
+ }
delim_index++;
}
+
dest_beg = opener->end;
dest_end = (delim != NULL) ? delim->beg : closer->beg;
if(dest_end - dest_beg == 0 || dest_end - dest_beg > 100)
@@ -3483,9 +3505,13 @@ md_resolve_links(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
if(is_link) {
if(delim != NULL) {
if(delim->end < closer->beg) {
+ md_rollback(ctx, opener_index, delim_index, MD_ROLLBACK_ALL);
+ md_rollback(ctx, delim_index, closer_index, MD_ROLLBACK_CROSSING);
+ delim->flags |= MD_MARK_RESOLVED;
opener->end = delim->beg;
} else {
/* The pipe is just before the closer: [[foo|]] */
+ md_rollback(ctx, opener_index, closer_index, MD_ROLLBACK_ALL);
closer->beg = delim->beg;
delim = NULL;
}
@@ -3502,13 +3528,8 @@ md_resolve_links(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
last_link_beg = opener->beg;
last_link_end = closer->end;
- if(delim != NULL) {
- delim->flags |= MD_MARK_RESOLVED;
- md_rollback(ctx, opener_index, delim_index, MD_ROLLBACK_ALL);
- md_analyze_link_contents(ctx, lines, n_lines, opener_index+1, closer_index);
- } else {
- md_rollback(ctx, opener_index, closer_index, MD_ROLLBACK_ALL);
- }
+ if(delim != NULL)
+ md_analyze_link_contents(ctx, lines, n_lines, delim_index+1, closer_index);
opener_index = next_opener->prev;
continue;
@@ -3518,10 +3539,12 @@ md_resolve_links(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
if(next_opener != NULL && next_opener->beg == closer->end) {
if(next_closer->beg > closer->end + 1) {
/* Might be full reference link. */
- is_link = md_is_link_reference(ctx, lines, n_lines, next_opener->beg, next_closer->end, &attr);
+ if(!(next_opener->flags & MD_MARK_HASNESTEDBRACKETS))
+ is_link = md_is_link_reference(ctx, lines, n_lines, next_opener->beg, next_closer->end, &attr);
} else {
/* Might be shortcut reference link. */
- is_link = md_is_link_reference(ctx, lines, n_lines, opener->beg, closer->end, &attr);
+ if(!(opener->flags & MD_MARK_HASNESTEDBRACKETS))
+ is_link = md_is_link_reference(ctx, lines, n_lines, opener->beg, closer->end, &attr);
}
if(is_link < 0)
@@ -3578,7 +3601,8 @@ md_resolve_links(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
if(!is_link) {
/* Might be collapsed reference link. */
- is_link = md_is_link_reference(ctx, lines, n_lines, opener->beg, closer->end, &attr);
+ if(!(opener->flags & MD_MARK_HASNESTEDBRACKETS))
+ is_link = md_is_link_reference(ctx, lines, n_lines, opener->beg, closer->end, &attr);
if(is_link < 0)
return -1;
}
@@ -3599,7 +3623,7 @@ md_resolve_links(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
md_mark_store_ptr(ctx, opener_index+2, attr.title);
/* The title might or might not have been allocated for us. */
if(attr.title_needs_free)
- md_mark_chain_append(ctx, &PTR_CHAIN, opener_index+2);
+ md_mark_stack_push(ctx, &ctx->ptr_stack, opener_index+2);
ctx->marks[opener_index+2].prev = attr.title_size;
if(opener->ch == '[') {
@@ -3672,7 +3696,7 @@ md_analyze_entity(MD_CTX* ctx, int mark_index)
if(md_is_entity(ctx, opener->beg, closer->end, &off)) {
MD_ASSERT(off == closer->end);
- md_resolve_range(ctx, NULL, mark_index, mark_index+1);
+ md_resolve_range(ctx, mark_index, mark_index+1);
opener->end = closer->end;
}
}
@@ -3682,8 +3706,13 @@ md_analyze_table_cell_boundary(MD_CTX* ctx, int mark_index)
{
MD_MARK* mark = &ctx->marks[mark_index];
mark->flags |= MD_MARK_RESOLVED;
+ mark->next = -1;
- md_mark_chain_append(ctx, &TABLECELLBOUNDARIES, mark_index);
+ if(ctx->table_cell_boundaries_head < 0)
+ ctx->table_cell_boundaries_head = mark_index;
+ else
+ ctx->marks[ctx->table_cell_boundaries_tail].next = mark_index;
+ ctx->table_cell_boundaries_tail = mark_index;
ctx->n_table_cell_boundaries++;
}
@@ -3712,262 +3741,312 @@ static void
md_analyze_emph(MD_CTX* ctx, int mark_index)
{
MD_MARK* mark = &ctx->marks[mark_index];
- MD_MARKCHAIN* chain = md_mark_chain(ctx, mark_index);
/* If we can be a closer, try to resolve with the preceding opener. */
if(mark->flags & MD_MARK_POTENTIAL_CLOSER) {
MD_MARK* opener = NULL;
int opener_index = 0;
-
- if(mark->ch == _T('*')) {
- MD_MARKCHAIN* opener_chains[6];
- int i, n_opener_chains;
- unsigned flags = mark->flags;
-
- /* Apply the "rule of three". */
- n_opener_chains = 0;
- opener_chains[n_opener_chains++] = &ASTERISK_OPENERS_intraword_mod3_0;
- if((flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_2)
- opener_chains[n_opener_chains++] = &ASTERISK_OPENERS_intraword_mod3_1;
- if((flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_1)
- opener_chains[n_opener_chains++] = &ASTERISK_OPENERS_intraword_mod3_2;
- opener_chains[n_opener_chains++] = &ASTERISK_OPENERS_extraword_mod3_0;
- if(!(flags & MD_MARK_EMPH_INTRAWORD) || (flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_2)
- opener_chains[n_opener_chains++] = &ASTERISK_OPENERS_extraword_mod3_1;
- if(!(flags & MD_MARK_EMPH_INTRAWORD) || (flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_1)
- opener_chains[n_opener_chains++] = &ASTERISK_OPENERS_extraword_mod3_2;
-
- /* Opener is the most recent mark from the allowed chains. */
- for(i = 0; i < n_opener_chains; i++) {
- if(opener_chains[i]->tail >= 0) {
- int tmp_index = opener_chains[i]->tail;
- MD_MARK* tmp_mark = &ctx->marks[tmp_index];
- if(opener == NULL || tmp_mark->end > opener->end) {
- opener_index = tmp_index;
- opener = tmp_mark;
- }
+ MD_MARKSTACK* opener_stacks[6];
+ int i, n_opener_stacks;
+ unsigned flags = mark->flags;
+
+ n_opener_stacks = 0;
+
+ /* Apply the rule of 3 */
+ opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_0 | MD_MARK_EMPH_OC);
+ if((flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_2)
+ opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_1 | MD_MARK_EMPH_OC);
+ if((flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_1)
+ opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_2 | MD_MARK_EMPH_OC);
+ opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_0);
+ if(!(flags & MD_MARK_EMPH_OC) || (flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_2)
+ opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_1);
+ if(!(flags & MD_MARK_EMPH_OC) || (flags & MD_MARK_EMPH_MOD3_MASK) != MD_MARK_EMPH_MOD3_1)
+ opener_stacks[n_opener_stacks++] = md_emph_stack(ctx, mark->ch, MD_MARK_EMPH_MOD3_2);
+
+ /* Opener is the most recent mark from the allowed stacks. */
+ for(i = 0; i < n_opener_stacks; i++) {
+ if(opener_stacks[i]->top >= 0) {
+ int m_index = opener_stacks[i]->top;
+ MD_MARK* m = &ctx->marks[m_index];
+
+ if(opener == NULL || m->end > opener->end) {
+ opener_index = m_index;
+ opener = m;
}
}
- } else {
- /* Simple emph. mark */
- if(chain->tail >= 0) {
- opener_index = chain->tail;
- opener = &ctx->marks[opener_index];
- }
}
/* Resolve, if we have found matching opener. */
if(opener != NULL) {
SZ opener_size = opener->end - opener->beg;
SZ closer_size = mark->end - mark->beg;
- MD_MARKCHAIN* opener_chain = md_mark_chain(ctx, opener_index);
+ MD_MARKSTACK* stack = md_opener_stack(ctx, opener_index);
if(opener_size > closer_size) {
opener_index = md_split_emph_mark(ctx, opener_index, closer_size);
- md_mark_chain_append(ctx, opener_chain, opener_index);
+ md_mark_stack_push(ctx, stack, opener_index);
} else if(opener_size < closer_size) {
md_split_emph_mark(ctx, mark_index, closer_size - opener_size);
}
+ /* Above we were only peeking. */
+ md_mark_stack_pop(ctx, stack);
+
md_rollback(ctx, opener_index, mark_index, MD_ROLLBACK_CROSSING);
- md_resolve_range(ctx, opener_chain, opener_index, mark_index);
+ md_resolve_range(ctx, opener_index, mark_index);
return;
}
}
/* If we could not resolve as closer, we may be yet be an opener. */
if(mark->flags & MD_MARK_POTENTIAL_OPENER)
- md_mark_chain_append(ctx, chain, mark_index);
+ md_mark_stack_push(ctx, md_emph_stack(ctx, mark->ch, mark->flags), mark_index);
}
static void
md_analyze_tilde(MD_CTX* ctx, int mark_index)
{
MD_MARK* mark = &ctx->marks[mark_index];
- MD_MARKCHAIN* chain = md_mark_chain(ctx, mark_index);
+ MD_MARKSTACK* stack = md_opener_stack(ctx, mark_index);
/* We attempt to be Github Flavored Markdown compatible here. GFM accepts
* only tildes sequences of length 1 and 2, and the length of the opener
* and closer has to match. */
- if((mark->flags & MD_MARK_POTENTIAL_CLOSER) && chain->head >= 0) {
- int opener_index = chain->head;
+ if((mark->flags & MD_MARK_POTENTIAL_CLOSER) && stack->top >= 0) {
+ int opener_index = stack->top;
+ md_mark_stack_pop(ctx, stack);
md_rollback(ctx, opener_index, mark_index, MD_ROLLBACK_CROSSING);
- md_resolve_range(ctx, chain, opener_index, mark_index);
+ md_resolve_range(ctx, opener_index, mark_index);
return;
}
if(mark->flags & MD_MARK_POTENTIAL_OPENER)
- md_mark_chain_append(ctx, chain, mark_index);
+ md_mark_stack_push(ctx, stack, mark_index);
}
static void
md_analyze_dollar(MD_CTX* ctx, int mark_index)
{
- /* This should mimic the way inline equations work in LaTeX, so there
- * can only ever be one item in the chain (i.e. the dollars can't be
- * nested). This is basically the same as the md_analyze_tilde function,
- * except that we require matching openers and closers to be of the same
- * length.
- *
- * E.g.: $abc$$def$$ => abc (display equation) def (end equation) */
- if(DOLLAR_OPENERS.head >= 0) {
+ MD_MARK* mark = &ctx->marks[mark_index];
+
+ if((mark->flags & MD_MARK_POTENTIAL_CLOSER) && DOLLAR_OPENERS.top >= 0) {
/* If the potential closer has a non-matching number of $, discard */
- MD_MARK* open = &ctx->marks[DOLLAR_OPENERS.head];
- MD_MARK* close = &ctx->marks[mark_index];
+ MD_MARK* opener = &ctx->marks[DOLLAR_OPENERS.top];
+ int opener_index = DOLLAR_OPENERS.top;
+ MD_MARK* closer = mark;
+ int closer_index = mark_index;
- int opener_index = DOLLAR_OPENERS.head;
- md_rollback(ctx, opener_index, mark_index, MD_ROLLBACK_ALL);
- if (open->end - open->beg == close->end - close->beg) {
+ if(opener->end - opener->beg == closer->end - closer->beg) {
/* We are the matching closer */
- md_resolve_range(ctx, &DOLLAR_OPENERS, opener_index, mark_index);
- } else {
- /* We don't match the opener, so discard old opener and insert as opener */
- md_mark_chain_append(ctx, &DOLLAR_OPENERS, mark_index);
+ md_mark_stack_pop(ctx, &DOLLAR_OPENERS);
+ md_rollback(ctx, opener_index, closer_index, MD_ROLLBACK_ALL);
+ md_resolve_range(ctx, opener_index, closer_index);
+
+ /* Discard all pending openers: Latex math span do not allow
+ * nesting. */
+ DOLLAR_OPENERS.top = -1;
+ return;
}
- } else {
- /* No unmatched openers, so we are opener */
- md_mark_chain_append(ctx, &DOLLAR_OPENERS, mark_index);
}
+
+ if(mark->flags & MD_MARK_POTENTIAL_OPENER)
+ md_mark_stack_push(ctx, &DOLLAR_OPENERS, mark_index);
}
-static void
-md_analyze_permissive_url_autolink(MD_CTX* ctx, int mark_index)
+static MD_MARK*
+md_scan_left_for_resolved_mark(MD_CTX* ctx, MD_MARK* mark_from, OFF off, MD_MARK** p_cursor)
{
- MD_MARK* opener = &ctx->marks[mark_index];
- int closer_index = mark_index + 1;
- MD_MARK* closer = &ctx->marks[closer_index];
- MD_MARK* next_resolved_mark;
- OFF off = opener->end;
- int n_dots = FALSE;
- int has_underscore_in_last_seg = FALSE;
- int has_underscore_in_next_to_last_seg = FALSE;
- int n_opened_parenthesis = 0;
- int n_excess_parenthesis = 0;
-
- /* Check for domain. */
- while(off < ctx->size) {
- if(ISALNUM(off) || CH(off) == _T('-')) {
- off++;
- } else if(CH(off) == _T('.')) {
- /* We must see at least one period. */
- n_dots++;
- has_underscore_in_next_to_last_seg = has_underscore_in_last_seg;
- has_underscore_in_last_seg = FALSE;
- off++;
- } else if(CH(off) == _T('_')) {
- /* No underscore may be present in the last two domain segments. */
- has_underscore_in_last_seg = TRUE;
- off++;
- } else {
- break;
+ MD_MARK* mark;
+
+ for(mark = mark_from; mark >= ctx->marks; mark--) {
+ if(mark->ch == 'D' || mark->beg > off)
+ continue;
+ if(mark->beg <= off && off < mark->end && (mark->flags & MD_MARK_RESOLVED)) {
+ if(p_cursor != NULL)
+ *p_cursor = mark;
+ return mark;
}
+ if(mark->end <= off)
+ break;
}
- if(off > opener->end && CH(off-1) == _T('.')) {
- off--;
- n_dots--;
- }
- if(off <= opener->end || n_dots == 0 || has_underscore_in_next_to_last_seg || has_underscore_in_last_seg)
- return;
- /* Check for path. */
- next_resolved_mark = closer + 1;
- while(next_resolved_mark->ch == 'D' || !(next_resolved_mark->flags & MD_MARK_RESOLVED))
- next_resolved_mark++;
- while(off < next_resolved_mark->beg && CH(off) != _T('<') && !ISWHITESPACE(off) && !ISNEWLINE(off)) {
- /* Parenthesis must be balanced. */
- if(CH(off) == _T('(')) {
- n_opened_parenthesis++;
- } else if(CH(off) == _T(')')) {
- if(n_opened_parenthesis > 0)
- n_opened_parenthesis--;
- else
- n_excess_parenthesis++;
- }
+ if(p_cursor != NULL)
+ *p_cursor = mark;
+ return NULL;
+}
- off++;
- }
+static MD_MARK*
+md_scan_right_for_resolved_mark(MD_CTX* ctx, MD_MARK* mark_from, OFF off, MD_MARK** p_cursor)
+{
+ MD_MARK* mark;
- /* Trim a trailing punctuation from the end. */
- while(TRUE) {
- if(ISANYOF(off-1, _T("?!.,:*_~"))) {
- off--;
- } else if(CH(off-1) == ')' && n_excess_parenthesis > 0) {
- /* Unmatched ')' can be in an interior of the path but not at the
- * of it, so the auto-link may be safely nested in a parenthesis
- * pair. */
- off--;
- n_excess_parenthesis--;
- } else {
- break;
+ for(mark = mark_from; mark < ctx->marks + ctx->n_marks; mark++) {
+ if(mark->ch == 'D' || mark->end <= off)
+ continue;
+ if(mark->beg <= off && off < mark->end && (mark->flags & MD_MARK_RESOLVED)) {
+ if(p_cursor != NULL)
+ *p_cursor = mark;
+ return mark;
}
+ if(mark->beg > off)
+ break;
}
- /* Ok. Lets call it an auto-link. Adapt opener and create closer to zero
- * length so all the contents becomes the link text. */
- MD_ASSERT(closer->ch == 'D');
- opener->end = opener->beg;
- closer->ch = opener->ch;
- closer->beg = off;
- closer->end = off;
- md_resolve_range(ctx, NULL, mark_index, closer_index);
+ if(p_cursor != NULL)
+ *p_cursor = mark;
+ return NULL;
}
-/* The permissive autolinks do not have to be enclosed in '<' '>' but we
- * instead impose stricter rules what is understood as an e-mail address
- * here. Actually any non-alphanumeric characters with exception of '.'
- * are prohibited both in username and after '@'. */
static void
-md_analyze_permissive_email_autolink(MD_CTX* ctx, int mark_index)
+md_analyze_permissive_autolink(MD_CTX* ctx, int mark_index)
{
+ static const struct {
+ const MD_CHAR start_char;
+ const MD_CHAR delim_char;
+ const MD_CHAR* allowed_nonalnum_chars;
+ int min_components;
+ const MD_CHAR optional_end_char;
+ } URL_MAP[] = {
+ { _T('\0'), _T('.'), _T(".-_"), 2, _T('\0') }, /* host, mandatory */
+ { _T('/'), _T('/'), _T("/.-_"), 0, _T('/') }, /* path */
+ { _T('?'), _T('&'), _T("&.-+_=()"), 1, _T('\0') }, /* query */
+ { _T('#'), _T('\0'), _T(".-+_") , 1, _T('\0') } /* fragment */
+ };
+
MD_MARK* opener = &ctx->marks[mark_index];
- int closer_index;
- MD_MARK* closer;
+ MD_MARK* closer = &ctx->marks[mark_index + 1]; /* The dummy. */
+ OFF line_beg = closer->beg; /* md_collect_mark() set this for us */
+ OFF line_end = closer->end; /* ditto */
OFF beg = opener->beg;
OFF end = opener->end;
- int dot_count = 0;
+ MD_MARK* left_cursor = opener;
+ int left_boundary_ok = FALSE;
+ MD_MARK* right_cursor = opener;
+ int right_boundary_ok = FALSE;
+ unsigned i;
- MD_ASSERT(CH(beg) == _T('@'));
-
- /* Scan for name before '@'. */
- while(beg > 0 && (ISALNUM(beg-1) || ISANYOF(beg-1, _T(".-_+"))))
- beg--;
+ MD_ASSERT(closer->ch == 'D');
- /* Scan for domain after '@'. */
- while(end < ctx->size && (ISALNUM(end) || ISANYOF(end, _T(".-_")))) {
- if(CH(end) == _T('.'))
- dot_count++;
- end++;
+ if(opener->ch == '@') {
+ MD_ASSERT(CH(opener->beg) == _T('@'));
+
+ /* Scan backwards for the user name (before '@'). */
+ while(beg > line_beg) {
+ if(ISALNUM(beg-1))
+ beg--;
+ else if(beg >= line_beg+2 && ISALNUM(beg-2) &&
+ ISANYOF(beg-1, _T(".-_+")) &&
+ md_scan_left_for_resolved_mark(ctx, left_cursor, beg-1, &left_cursor) == NULL &&
+ ISALNUM(beg))
+ beg--;
+ else
+ break;
+ }
+ if(beg == opener->beg) /* empty user name */
+ return;
}
- if(CH(end-1) == _T('.')) { /* Final '.' not part of it. */
- dot_count--;
- end--;
+
+ /* Verify there's line boundary, whitespace, allowed punctuation or
+ * resolved emphasis mark just before the suspected autolink. */
+ if(beg == line_beg || ISUNICODEWHITESPACEBEFORE(beg) || ISANYOF(beg-1, _T("({["))) {
+ left_boundary_ok = TRUE;
+ } else if(ISANYOF(beg-1, _T("*_~"))) {
+ MD_MARK* left_mark;
+
+ left_mark = md_scan_left_for_resolved_mark(ctx, left_cursor, beg-1, &left_cursor);
+ if(left_mark != NULL && (left_mark->flags & MD_MARK_OPENER))
+ left_boundary_ok = TRUE;
}
- else if(ISANYOF2(end-1, _T('-'), _T('_'))) /* These are forbidden at the end. */
- return;
- if(CH(end-1) == _T('@') || dot_count == 0)
+ if(!left_boundary_ok)
return;
- /* Ok. Lets call it auto-link. Adapt opener and create closer to zero
- * length so all the contents becomes the link text. */
- closer_index = mark_index + 1;
- closer = &ctx->marks[closer_index];
- MD_ASSERT(closer->ch == 'D');
+ for(i = 0; i < SIZEOF_ARRAY(URL_MAP); i++) {
+ int n_components = 0;
+ int n_open_brackets = 0;
+
+ if(URL_MAP[i].start_char != _T('\0')) {
+ if(end >= line_end || CH(end) != URL_MAP[i].start_char)
+ continue;
+ if(URL_MAP[i].min_components > 0 && (end+1 >= line_end || !ISALNUM(end+1)))
+ continue;
+ end++;
+ }
+
+ while(end < line_end) {
+ if(ISALNUM(end)) {
+ if(n_components == 0)
+ n_components++;
+ end++;
+ } else if(end < line_end &&
+ ISANYOF(end, URL_MAP[i].allowed_nonalnum_chars) &&
+ md_scan_right_for_resolved_mark(ctx, right_cursor, end, &right_cursor) == NULL &&
+ ((end > line_beg && (ISALNUM(end-1) || CH(end-1) == _T(')'))) || CH(end) == _T('(')) &&
+ ((end+1 < line_end && (ISALNUM(end+1) || CH(end+1) == _T('('))) || CH(end) == _T(')')))
+ {
+ if(CH(end) == URL_MAP[i].delim_char)
+ n_components++;
+
+ /* brackets have to be balanced. */
+ if(CH(end) == _T('(')) {
+ n_open_brackets++;
+ } else if(CH(end) == _T(')')) {
+ if(n_open_brackets <= 0)
+ break;
+ n_open_brackets--;
+ }
+
+ end++;
+ } else {
+ break;
+ }
+ }
+
+ if(end < line_end && URL_MAP[i].optional_end_char != _T('\0') &&
+ CH(end) == URL_MAP[i].optional_end_char)
+ end++;
+
+ if(n_components < URL_MAP[i].min_components || n_open_brackets != 0)
+ return;
+
+ if(opener->ch == '@') /* E-mail autolinks wants only the host. */
+ break;
+ }
+
+ /* Verify there's line boundary, whitespace, allowed punctuation or
+ * resolved emphasis mark just after the suspected autolink. */
+ if(end == line_end || ISUNICODEWHITESPACE(end) || ISANYOF(end, _T(")}].!?,;"))) {
+ right_boundary_ok = TRUE;
+ } else {
+ MD_MARK* right_mark;
+ right_mark = md_scan_right_for_resolved_mark(ctx, right_cursor, end, &right_cursor);
+ if(right_mark != NULL && (right_mark->flags & MD_MARK_CLOSER))
+ right_boundary_ok = TRUE;
+ }
+ if(!right_boundary_ok)
+ return;
+
+ /* Success, we are an autolink. */
opener->beg = beg;
opener->end = beg;
- closer->ch = opener->ch;
closer->beg = end;
closer->end = end;
- md_resolve_range(ctx, NULL, mark_index, closer_index);
+ closer->ch = opener->ch;
+ md_resolve_range(ctx, mark_index, mark_index + 1);
}
+#define MD_ANALYZE_NOSKIP_EMPH 0x01
+
static inline void
-md_analyze_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
- int mark_beg, int mark_end, const CHAR* mark_chars)
+md_analyze_marks(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines,
+ int mark_beg, int mark_end, const CHAR* mark_chars, unsigned flags)
{
int i = mark_beg;
+ OFF last_end = lines[0].beg;
+
MD_UNUSED(lines);
MD_UNUSED(n_lines);
@@ -3976,7 +4055,9 @@ md_analyze_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
/* Skip resolved spans. */
if(mark->flags & MD_MARK_RESOLVED) {
- if(mark->flags & MD_MARK_OPENER) {
+ if((mark->flags & MD_MARK_OPENER) &&
+ !((flags & MD_ANALYZE_NOSKIP_EMPH) && ISANYOF_(mark->ch, "*_~")))
+ {
MD_ASSERT(i < mark->next);
i = mark->next + 1;
} else {
@@ -3991,6 +4072,12 @@ md_analyze_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
continue;
}
+ /* The resolving in previous step could have expanded a mark. */
+ if(mark->beg < last_end) {
+ i++;
+ continue;
+ }
+
/* Analyze the mark. */
switch(mark->ch) {
case '[': /* Pass through. */
@@ -4003,8 +4090,15 @@ md_analyze_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
case '~': md_analyze_tilde(ctx, i); break;
case '$': md_analyze_dollar(ctx, i); break;
case '.': /* Pass through. */
- case ':': md_analyze_permissive_url_autolink(ctx, i); break;
- case '@': md_analyze_permissive_email_autolink(ctx, i); break;
+ case ':': /* Pass through. */
+ case '@': md_analyze_permissive_autolink(ctx, i); break;
+ }
+
+ if(mark->flags & MD_MARK_RESOLVED) {
+ if(mark->flags & MD_MARK_OPENER)
+ last_end = ctx->marks[mark->next].end;
+ else
+ last_end = mark->end;
}
i++;
@@ -4013,7 +4107,7 @@ md_analyze_marks(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
/* Analyze marks (build ctx->marks). */
static int
-md_analyze_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mode)
+md_analyze_inlines(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines, int table_mode)
{
int ret;
@@ -4023,31 +4117,22 @@ md_analyze_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines, int table_mod
/* Collect all marks. */
MD_CHECK(md_collect_marks(ctx, lines, n_lines, table_mode));
- /* We analyze marks in few groups to handle their precedence. */
- /* (1) Entities; code spans; autolinks; raw HTML. */
- md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("&"));
-
- /* (2) Links. */
- md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("[]!"));
+ /* (1) Links. */
+ md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("[]!"), 0);
MD_CHECK(md_resolve_links(ctx, lines, n_lines));
- BRACKET_OPENERS.head = -1;
- BRACKET_OPENERS.tail = -1;
+ BRACKET_OPENERS.top = -1;
ctx->unresolved_link_head = -1;
ctx->unresolved_link_tail = -1;
if(table_mode) {
- /* (3) Analyze table cell boundaries.
- * Note we reset TABLECELLBOUNDARIES chain prior to the call md_analyze_marks(),
- * not after, because caller may need it. */
+ /* (2) Analyze table cell boundaries. */
MD_ASSERT(n_lines == 1);
- TABLECELLBOUNDARIES.head = -1;
- TABLECELLBOUNDARIES.tail = -1;
ctx->n_table_cell_boundaries = 0;
- md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("|"));
+ md_analyze_marks(ctx, lines, n_lines, 0, ctx->n_marks, _T("|"), 0);
return ret;
}
- /* (4) Emphasis and strong emphasis; permissive autolinks. */
+ /* (3) Emphasis and strong emphasis; permissive autolinks. */
md_analyze_link_contents(ctx, lines, n_lines, 0, ctx->n_marks);
abort:
@@ -4055,22 +4140,28 @@ abort:
}
static void
-md_analyze_link_contents(MD_CTX* ctx, const MD_LINE* lines, int n_lines,
+md_analyze_link_contents(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines,
int mark_beg, int mark_end)
{
int i;
- md_analyze_marks(ctx, lines, n_lines, mark_beg, mark_end, _T("*_~$@:."));
+ md_analyze_marks(ctx, lines, n_lines, mark_beg, mark_end, _T("&"), 0);
+ md_analyze_marks(ctx, lines, n_lines, mark_beg, mark_end, _T("*_~$"), 0);
- for(i = OPENERS_CHAIN_FIRST; i <= OPENERS_CHAIN_LAST; i++) {
- ctx->mark_chains[i].head = -1;
- ctx->mark_chains[i].tail = -1;
+ if((ctx->parser.flags & MD_FLAG_PERMISSIVEAUTOLINKS) != 0) {
+ /* These have to be processed last, as they may be greedy and expand
+ * from their original mark. Also their implementation must be careful
+ * not to cross any (previously) resolved marks when doing so. */
+ md_analyze_marks(ctx, lines, n_lines, mark_beg, mark_end, _T("@:."), MD_ANALYZE_NOSKIP_EMPH);
}
+
+ for(i = 0; i < (int) SIZEOF_ARRAY(ctx->opener_stacks); i++)
+ ctx->opener_stacks[i].top = -1;
}
static int
md_enter_leave_span_a(MD_CTX* ctx, int enter, MD_SPANTYPE type,
- const CHAR* dest, SZ dest_size, int prohibit_escapes_in_dest,
+ const CHAR* dest, SZ dest_size, int is_autolink,
const CHAR* title, SZ title_size)
{
MD_ATTRIBUTE_BUILD href_build = { 0 };
@@ -4082,10 +4173,10 @@ md_enter_leave_span_a(MD_CTX* ctx, int enter, MD_SPANTYPE type,
* MD_SPAN_IMG_DETAIL are binary-compatible. */
memset(&det, 0, sizeof(MD_SPAN_A_DETAIL));
MD_CHECK(md_build_attribute(ctx, dest, dest_size,
- (prohibit_escapes_in_dest ? MD_BUILD_ATTR_NO_ESCAPES : 0),
+ (is_autolink ? MD_BUILD_ATTR_NO_ESCAPES : 0),
&det.href, &href_build));
MD_CHECK(md_build_attribute(ctx, title, title_size, 0, &det.title, &title_build));
-
+ det.is_autolink = is_autolink;
if(enter)
MD_ENTER_SPAN(type, &det);
else
@@ -4120,7 +4211,7 @@ abort:
/* Render the output, accordingly to the analyzed ctx->marks. */
static int
-md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
+md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines)
{
MD_TEXTTYPE text_type;
const MD_LINE* line = lines;
@@ -4128,6 +4219,7 @@ md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
MD_MARK* mark;
OFF off = lines[0].beg;
OFF end = lines[n_lines-1].end;
+ OFF tmp;
int enforce_hardbreak = 0;
int ret = 0;
@@ -4143,7 +4235,7 @@ md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
while(1) {
/* Process the text up to the next mark or end-of-line. */
- OFF tmp = (line->end < mark->beg ? line->end : mark->beg);
+ tmp = (line->end < mark->beg ? line->end : mark->beg);
if(tmp > off) {
MD_TEXT(text_type, STR(off), tmp - off);
off = tmp;
@@ -4265,7 +4357,8 @@ md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
MD_CHECK(md_enter_leave_span_a(ctx, (mark->ch != ']'),
(opener->ch == '!' ? MD_SPAN_IMG : MD_SPAN_A),
STR(dest_mark->beg), dest_mark->end - dest_mark->beg, FALSE,
- md_mark_get_ptr(ctx, (int)(title_mark - ctx->marks)), title_mark->prev));
+ md_mark_get_ptr(ctx, (int)(title_mark - ctx->marks)),
+ title_mark->prev));
/* link/image closer may span multiple lines. */
if(mark->ch == ']') {
@@ -4307,11 +4400,13 @@ md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
if(mark->flags & MD_MARK_OPENER)
closer->flags |= MD_MARK_VALIDPERMISSIVEAUTOLINK;
- if(opener->ch == '@' || opener->ch == '.') {
+ if(opener->ch == '@' || opener->ch == '.' ||
+ (opener->ch == '<' && (opener->flags & MD_MARK_AUTOLINK_MISSING_MAILTO)))
+ {
dest_size += 7;
MD_TEMP_BUFFER(dest_size * sizeof(CHAR));
memcpy(ctx->buffer,
- (opener->ch == '@' ? _T("mailto:") : _T("http://")),
+ (opener->ch == '.' ? _T("http://") : _T("mailto:")),
7 * sizeof(CHAR));
memcpy(ctx->buffer + 7, dest, (dest_size-7) * sizeof(CHAR));
dest = ctx->buffer;
@@ -4351,8 +4446,6 @@ md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
break;
if(text_type == MD_TEXT_CODE || text_type == MD_TEXT_LATEXMATH) {
- OFF tmp;
-
MD_ASSERT(prev_mark != NULL);
MD_ASSERT(ISANYOF2_(prev_mark->ch, '`', '$') && (prev_mark->flags & MD_MARK_OPENER));
MD_ASSERT(ISANYOF2_(mark->ch, '`', '$') && (mark->flags & MD_MARK_CLOSER));
@@ -4366,13 +4459,12 @@ md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
MD_TEXT(text_type, STR(tmp), off-tmp);
/* and new lines are transformed into single spaces. */
- if(prev_mark->end < off && off < mark->beg)
+ if(off == line->end)
MD_TEXT(text_type, _T(" "), 1);
} else if(text_type == MD_TEXT_HTML) {
/* Inside raw HTML, we output the new line verbatim, including
* any trailing spaces. */
- OFF tmp = off;
-
+ tmp = off;
while(tmp < end && ISBLANK(tmp))
tmp++;
if(tmp > off)
@@ -4383,7 +4475,9 @@ md_process_inlines(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
MD_TEXTTYPE break_type = MD_TEXT_SOFTBR;
if(text_type == MD_TEXT_NORMAL) {
- if(enforce_hardbreak)
+ if(ctx->parser.flags & MD_FLAG_HARD_SOFT_BREAKS)
+ break_type = MD_TEXT_BR;
+ else if(enforce_hardbreak)
break_type = MD_TEXT_BR;
else if((CH(line->end) == _T(' ') && CH(line->end+1) == _T(' ')))
break_type = MD_TEXT_BR;
@@ -4435,7 +4529,7 @@ md_analyze_table_alignment(MD_CTX* ctx, OFF beg, OFF end, MD_ALIGN* align, int n
}
/* Forward declaration. */
-static int md_process_normal_block_contents(MD_CTX* ctx, const MD_LINE* lines, int n_lines);
+static int md_process_normal_block_contents(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines);
static int
md_process_table_cell(MD_CTX* ctx, MD_BLOCKTYPE cell_type, MD_ALIGN align, OFF beg, OFF end)
@@ -4488,7 +4582,7 @@ md_process_table_row(MD_CTX* ctx, MD_BLOCKTYPE cell_type, OFF beg, OFF end,
}
j = 0;
pipe_offs[j++] = beg;
- for(i = TABLECELLBOUNDARIES.head; i >= 0; i = ctx->marks[i].next) {
+ for(i = ctx->table_cell_boundaries_head; i >= 0; i = ctx->marks[i].next) {
MD_MARK* mark = &ctx->marks[i];
pipe_offs[j++] = mark->end;
}
@@ -4510,20 +4604,17 @@ md_process_table_row(MD_CTX* ctx, MD_BLOCKTYPE cell_type, OFF beg, OFF end,
abort:
free(pipe_offs);
- /* Free any temporary memory blocks stored within some dummy marks. */
- for(i = PTR_CHAIN.head; i >= 0; i = ctx->marks[i].next)
- free(md_mark_get_ptr(ctx, i));
- PTR_CHAIN.head = -1;
- PTR_CHAIN.tail = -1;
+ ctx->table_cell_boundaries_head = -1;
+ ctx->table_cell_boundaries_tail = -1;
return ret;
}
static int
-md_process_table_block_contents(MD_CTX* ctx, int col_count, const MD_LINE* lines, int n_lines)
+md_process_table_block_contents(MD_CTX* ctx, int col_count, const MD_LINE* lines, MD_SIZE n_lines)
{
MD_ALIGN* align;
- int i;
+ MD_SIZE line_index;
int ret = 0;
/* At least two lines have to be present: The column headers and the line
@@ -4546,9 +4637,9 @@ md_process_table_block_contents(MD_CTX* ctx, int col_count, const MD_LINE* lines
if(n_lines > 2) {
MD_ENTER_BLOCK(MD_BLOCK_TBODY, NULL);
- for(i = 2; i < n_lines; i++) {
+ for(line_index = 2; line_index < n_lines; line_index++) {
MD_CHECK(md_process_table_row(ctx, MD_BLOCK_TD,
- lines[i].beg, lines[i].end, align, col_count));
+ lines[line_index].beg, lines[line_index].end, align, col_count));
}
MD_LEAVE_BLOCK(MD_BLOCK_TBODY, NULL);
}
@@ -4584,7 +4675,7 @@ struct MD_BLOCK_tag {
* MD_BLOCK_LI: Task mark offset in the input doc.
* MD_BLOCK_OL: Start item number.
*/
- unsigned n_lines;
+ MD_SIZE n_lines;
};
struct MD_CONTAINER_tag {
@@ -4600,7 +4691,7 @@ struct MD_CONTAINER_tag {
static int
-md_process_normal_block_contents(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
+md_process_normal_block_contents(MD_CTX* ctx, const MD_LINE* lines, MD_SIZE n_lines)
{
int i;
int ret;
@@ -4610,25 +4701,24 @@ md_process_normal_block_contents(MD_CTX* ctx, const MD_LINE* lines, int n_lines)
abort:
/* Free any temporary memory blocks stored within some dummy marks. */
- for(i = PTR_CHAIN.head; i >= 0; i = ctx->marks[i].next)
+ for(i = ctx->ptr_stack.top; i >= 0; i = ctx->marks[i].next)
free(md_mark_get_ptr(ctx, i));
- PTR_CHAIN.head = -1;
- PTR_CHAIN.tail = -1;
+ ctx->ptr_stack.top = -1;
return ret;
}
static int
-md_process_verbatim_block_contents(MD_CTX* ctx, MD_TEXTTYPE text_type, const MD_VERBATIMLINE* lines, int n_lines)
+md_process_verbatim_block_contents(MD_CTX* ctx, MD_TEXTTYPE text_type, const MD_VERBATIMLINE* lines, MD_SIZE n_lines)
{
static const CHAR indent_chunk_str[] = _T(" ");
static const SZ indent_chunk_size = SIZEOF_ARRAY(indent_chunk_str) - 1;
- int i;
+ MD_SIZE line_index;
int ret = 0;
- for(i = 0; i < n_lines; i++) {
- const MD_VERBATIMLINE* line = &lines[i];
+ for(line_index = 0; line_index < n_lines; line_index++) {
+ const MD_VERBATIMLINE* line = &lines[line_index];
int indent = line->indent;
MD_ASSERT(indent >= 0);
@@ -4653,7 +4743,7 @@ abort:
}
static int
-md_process_code_block_contents(MD_CTX* ctx, int is_fenced, const MD_VERBATIMLINE* lines, int n_lines)
+md_process_code_block_contents(MD_CTX* ctx, int is_fenced, const MD_VERBATIMLINE* lines, MD_SIZE n_lines)
{
if(is_fenced) {
/* Skip the first line in case of fenced code: It is the fence.
@@ -4908,7 +4998,7 @@ md_push_block_bytes(MD_CTX* ctx, int n_bytes)
/* Fix the ->current_block after the reallocation. */
if(ctx->current_block != NULL) {
- OFF off_current_block = (OFF)((char*) ctx->current_block - (char*) ctx->block_bytes);
+ OFF off_current_block = (OFF) ((char*) ctx->current_block - (char*) ctx->block_bytes);
ctx->current_block = (MD_BLOCK*) ((char*) new_block_bytes + off_current_block);
}
@@ -4980,8 +5070,8 @@ static int
md_consume_link_reference_definitions(MD_CTX* ctx)
{
MD_LINE* lines = (MD_LINE*) (ctx->current_block + 1);
- int n_lines = ctx->current_block->n_lines;
- int n = 0;
+ MD_SIZE n_lines = ctx->current_block->n_lines;
+ MD_SIZE n = 0;
/* Compute how many lines at the start of the block form one or more
* reference definitions. */
@@ -5036,7 +5126,7 @@ md_end_current_block(MD_CTX* ctx)
(ctx->current_block->type == MD_BLOCK_H && (ctx->current_block->flags & MD_BLOCK_SETEXT_HEADER)))
{
MD_LINE* lines = (MD_LINE*) (ctx->current_block + 1);
- if(CH(lines[0].beg) == _T('[')) {
+ if(lines[0].beg < ctx->size && CH(lines[0].beg) == _T('[')) {
MD_CHECK(md_consume_link_reference_definitions(ctx));
if(ctx->current_block == NULL)
return ret;
@@ -5044,7 +5134,7 @@ md_end_current_block(MD_CTX* ctx)
}
if(ctx->current_block->type == MD_BLOCK_H && (ctx->current_block->flags & MD_BLOCK_SETEXT_HEADER)) {
- int n_lines = ctx->current_block->n_lines;
+ MD_SIZE n_lines = ctx->current_block->n_lines;
if(n_lines > 1) {
/* Get rid of the underline. */
@@ -5183,8 +5273,8 @@ md_is_setext_underline(MD_CTX* ctx, OFF beg, OFF* p_end, unsigned* p_level)
while(off < ctx->size && CH(off) == CH(beg))
off++;
- /* Optionally, space(s) can follow. */
- while(off < ctx->size && CH(off) == _T(' '))
+ /* Optionally, space(s) or tabs can follow. */
+ while(off < ctx->size && ISBLANK(off))
off++;
/* But nothing more is allowed on the line. */
@@ -5211,21 +5301,23 @@ md_is_table_underline(MD_CTX* ctx, OFF beg, OFF* p_end, unsigned* p_col_count)
}
while(1) {
- OFF cell_beg;
int delimited = FALSE;
/* Cell underline ("-----", ":----", "----:" or ":----:") */
- cell_beg = off;
if(off < ctx->size && CH(off) == _T(':'))
off++;
+ if(off >= ctx->size || CH(off) != _T('-'))
+ return FALSE;
while(off < ctx->size && CH(off) == _T('-'))
off++;
if(off < ctx->size && CH(off) == _T(':'))
off++;
- if(off - cell_beg < 3)
- return FALSE;
col_count++;
+ if(col_count > TABLE_MAXCOLCOUNT) {
+ MD_LOG("Suppressing table (column_count >" STRINGIZE(TABLE_MAXCOLCOUNT) ")");
+ return FALSE;
+ }
/* Pipe delimiter (optional at the end of line). */
while(off < ctx->size && ISWHITESPACE(off))
@@ -5314,48 +5406,55 @@ out:
return ret;
}
-/* Returns type of the raw HTML block, or FALSE if it is not HTML block.
- * (Refer to CommonMark specification for details about the types.)
- */
-static int
-md_is_html_block_start_condition(MD_CTX* ctx, OFF beg)
-{
- typedef struct TAG_tag TAG;
- struct TAG_tag {
- const CHAR* name;
- unsigned len : 8;
- };
- /* Type 6 is started by a long list of allowed tags. We use two-level
- * tree to speed-up the search. */
+/* Helper data for md_is_html_block_start_condition() and
+ * md_is_html_block_end_condition() */
+typedef struct TAG_tag TAG;
+struct TAG_tag {
+ const CHAR* name;
+ unsigned len : 8;
+};
+
#ifdef X
#undef X
#endif
#define X(name) { _T(name), (sizeof(name)-1) / sizeof(CHAR) }
#define Xend { NULL, 0 }
- static const TAG t1[] = { X("script"), X("pre"), X("style"), Xend };
-
- static const TAG a6[] = { X("address"), X("article"), X("aside"), Xend };
- static const TAG b6[] = { X("base"), X("basefont"), X("blockquote"), X("body"), Xend };
- static const TAG c6[] = { X("caption"), X("center"), X("col"), X("colgroup"), Xend };
- static const TAG d6[] = { X("dd"), X("details"), X("dialog"), X("dir"),
- X("div"), X("dl"), X("dt"), Xend };
- static const TAG f6[] = { X("fieldset"), X("figcaption"), X("figure"), X("footer"),
- X("form"), X("frame"), X("frameset"), Xend };
- static const TAG h6[] = { X("h1"), X("head"), X("header"), X("hr"), X("html"), Xend };
- static const TAG i6[] = { X("iframe"), Xend };
- static const TAG l6[] = { X("legend"), X("li"), X("link"), Xend };
- static const TAG m6[] = { X("main"), X("menu"), X("menuitem"), Xend };
- static const TAG n6[] = { X("nav"), X("noframes"), Xend };
- static const TAG o6[] = { X("ol"), X("optgroup"), X("option"), Xend };
- static const TAG p6[] = { X("p"), X("param"), Xend };
- static const TAG s6[] = { X("section"), X("source"), X("summary"), Xend };
- static const TAG t6[] = { X("table"), X("tbody"), X("td"), X("tfoot"), X("th"),
- X("thead"), X("title"), X("tr"), X("track"), Xend };
- static const TAG u6[] = { X("ul"), Xend };
- static const TAG xx[] = { Xend };
+
+static const TAG t1[] = { X("pre"), X("script"), X("style"), X("textarea"), Xend };
+
+static const TAG a6[] = { X("address"), X("article"), X("aside"), Xend };
+static const TAG b6[] = { X("base"), X("basefont"), X("blockquote"), X("body"), Xend };
+static const TAG c6[] = { X("caption"), X("center"), X("col"), X("colgroup"), Xend };
+static const TAG d6[] = { X("dd"), X("details"), X("dialog"), X("dir"),
+ X("div"), X("dl"), X("dt"), Xend };
+static const TAG f6[] = { X("fieldset"), X("figcaption"), X("figure"), X("footer"),
+ X("form"), X("frame"), X("frameset"), Xend };
+static const TAG h6[] = { X("h1"), X("h2"), X("h3"), X("h4"), X("h5"), X("h6"),
+ X("head"), X("header"), X("hr"), X("html"), Xend };
+static const TAG i6[] = { X("iframe"), Xend };
+static const TAG l6[] = { X("legend"), X("li"), X("link"), Xend };
+static const TAG m6[] = { X("main"), X("menu"), X("menuitem"), Xend };
+static const TAG n6[] = { X("nav"), X("noframes"), Xend };
+static const TAG o6[] = { X("ol"), X("optgroup"), X("option"), Xend };
+static const TAG p6[] = { X("p"), X("param"), Xend };
+static const TAG s6[] = { X("search"), X("section"), X("summary"), Xend };
+static const TAG t6[] = { X("table"), X("tbody"), X("td"), X("tfoot"), X("th"),
+ X("thead"), X("title"), X("tr"), X("track"), Xend };
+static const TAG u6[] = { X("ul"), Xend };
+static const TAG xx[] = { Xend };
+
#undef X
+#undef Xend
+/* Returns type of the raw HTML block, or FALSE if it is not HTML block.
+ * (Refer to CommonMark specification for details about the types.)
+ */
+static int
+md_is_html_block_start_condition(MD_CTX* ctx, OFF beg)
+{
+ /* Type 6 is started by a long list of allowed tags. We use two-level
+ * tree to speed-up the search. */
static const TAG* map6[26] = {
a6, b6, c6, d6, xx, f6, xx, h6, i6, xx, xx, l6, m6,
n6, o6, p6, xx, xx, s6, t6, u6, xx, xx, xx, xx, xx
@@ -5382,7 +5481,7 @@ md_is_html_block_start_condition(MD_CTX* ctx, OFF beg)
/* Check for type 4 or 5: <! */
if(off < ctx->size && CH(off) == _T('!')) {
/* Check for type 4: <! followed by uppercase letter. */
- if(off + 1 < ctx->size && ISUPPER(off+1))
+ if(off + 1 < ctx->size && ISASCII(off+1))
return 4;
/* Check for type 5: <![CDATA[ */
@@ -5466,25 +5565,21 @@ md_is_html_block_end_condition(MD_CTX* ctx, OFF beg, OFF* p_end)
case 1:
{
OFF off = beg;
-
- while(off < ctx->size && !ISNEWLINE(off)) {
- if(CH(off) == _T('<')) {
- if(md_ascii_case_eq(STR(off), _T("</script>"), 9)) {
- *p_end = off + 9;
- return TRUE;
- }
-
- if(md_ascii_case_eq(STR(off), _T("</style>"), 8)) {
- *p_end = off + 8;
- return TRUE;
- }
-
- if(md_ascii_case_eq(STR(off), _T("</pre>"), 6)) {
- *p_end = off + 6;
- return TRUE;
+ int i;
+
+ while(off+1 < ctx->size && !ISNEWLINE(off)) {
+ if(CH(off) == _T('<') && CH(off+1) == _T('/')) {
+ for(i = 0; t1[i].name != NULL; i++) {
+ if(off + 2 + t1[i].len < ctx->size) {
+ if(md_ascii_case_eq(STR(off+2), t1[i].name, t1[i].len) &&
+ CH(off+2+t1[i].len) == _T('>'))
+ {
+ *p_end = off+2+t1[i].len+1;
+ return TRUE;
+ }
+ }
}
}
-
off++;
}
*p_end = off;
@@ -5505,8 +5600,12 @@ md_is_html_block_end_condition(MD_CTX* ctx, OFF beg, OFF* p_end)
case 6: /* Pass through */
case 7:
- *p_end = beg;
- return (ISNEWLINE(beg) ? ctx->html_block_type : FALSE);
+ if(beg >= ctx->size || ISNEWLINE(beg)) {
+ /* Blank line ends types 6 and 7. */
+ *p_end = beg;
+ return ctx->html_block_type;
+ }
+ return FALSE;
default:
MD_UNREACHABLE();
@@ -5684,6 +5783,7 @@ md_is_container_mark(MD_CTX* ctx, unsigned indent, OFF beg, OFF* p_end, MD_CONTA
off++;
}
if(off > beg &&
+ off < ctx->size &&
(CH(off) == _T('.') || CH(off) == _T(')')) &&
(off+1 >= ctx->size || ISBLANK(off+1) || ISNEWLINE(off+1)))
{
@@ -5717,7 +5817,7 @@ md_line_indentation(MD_CTX* ctx, unsigned total_indent, OFF beg, OFF* p_end)
return indent - total_indent;
}
-static const MD_LINE_ANALYSIS md_dummy_blank_line = { MD_LINE_BLANK, 0, 0, 0, 0 };
+static const MD_LINE_ANALYSIS md_dummy_blank_line = { MD_LINE_BLANK, 0, 0, 0, 0, 0 };
/* Analyze type of the line and find some its properties. This serves as a
* main input for determining type and boundaries of a block. */
@@ -5738,6 +5838,7 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end,
line->indent = md_line_indentation(ctx, total_indent, off, &off);
total_indent += line->indent;
line->beg = off;
+ line->enforce_new_block = FALSE;
/* Given the indentation and block quote marks '>', determine how many of
* the current containers are our parents. */
@@ -5879,20 +5980,26 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end,
* was a 2nd blank line at the beginning of the list item) and if
* we would otherwise still belong to the list item, we enforce
* the end of the list. */
- ctx->last_line_has_list_loosening_effect = FALSE;
if(ctx->last_list_item_starts_with_two_blank_lines) {
- if(n_parents > 0 && ctx->containers[n_parents-1].ch != _T('>') &&
+ if(n_parents > 0 && n_parents == ctx->n_containers &&
+ ctx->containers[n_parents-1].ch != _T('>') &&
n_brothers + n_children == 0 && ctx->current_block == NULL &&
ctx->n_block_bytes > (int) sizeof(MD_BLOCK))
{
MD_BLOCK* top_block = (MD_BLOCK*) ((char*)ctx->block_bytes + ctx->n_block_bytes - sizeof(MD_BLOCK));
- if(top_block->type == MD_BLOCK_LI)
+ if(top_block->type == MD_BLOCK_LI) {
n_parents--;
+
+ line->indent = total_indent;
+ if(n_parents > 0)
+ line->indent -= MIN(line->indent, ctx->containers[n_parents-1].contents_indent);
+ }
}
ctx->last_list_item_starts_with_two_blank_lines = FALSE;
}
#endif
+ ctx->last_line_has_list_loosening_effect = FALSE;
}
/* Check whether we are Setext underline. */
@@ -5958,11 +6065,8 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end,
/* Check for indented code.
* Note indented code block cannot interrupt a paragraph. */
- if(line->indent >= ctx->code_indent_offset &&
- (pivot_line->type == MD_LINE_BLANK || pivot_line->type == MD_LINE_INDENTEDCODE))
- {
+ if(line->indent >= ctx->code_indent_offset && (pivot_line->type != MD_LINE_TEXT)) {
line->type = MD_LINE_INDENTEDCODE;
- MD_ASSERT(line->indent >= ctx->code_indent_offset);
line->indent -= ctx->code_indent_offset;
line->data = 0;
break;
@@ -6031,10 +6135,13 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end,
}
/* Check whether we are starting code fence. */
- if(off < ctx->size && ISANYOF2(off, _T('`'), _T('~'))) {
+ if(line->indent < ctx->code_indent_offset &&
+ off < ctx->size && ISANYOF2(off, _T('`'), _T('~')))
+ {
if(md_is_opening_code_fence(ctx, off, &off)) {
line->type = MD_LINE_FENCEDCODE;
line->data = 1;
+ line->enforce_new_block = TRUE;
break;
}
}
@@ -6056,6 +6163,7 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end,
ctx->html_block_type = 0;
}
+ line->enforce_new_block = TRUE;
line->type = MD_LINE_HTML;
break;
}
@@ -6100,7 +6208,7 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end,
task_container->is_task = TRUE;
task_container->task_mark_off = tmp + 1;
off = tmp + 3;
- while(ISWHITESPACE(off))
+ while(off < ctx->size && ISWHITESPACE(off))
off++;
line->beg = off;
}
@@ -6154,7 +6262,7 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end,
}
/* Trim trailing spaces. */
- if(line->type != MD_LINE_INDENTEDCODE && line->type != MD_LINE_FENCEDCODE) {
+ if(line->type != MD_LINE_INDENTEDCODE && line->type != MD_LINE_FENCEDCODE && line->type != MD_LINE_HTML) {
while(line->end > line->beg && CH(line->end-1) == _T(' '))
line->end--;
}
@@ -6215,6 +6323,9 @@ md_process_line(MD_CTX* ctx, const MD_LINE_ANALYSIS** p_pivot_line, MD_LINE_ANAL
return 0;
}
+ if(line->enforce_new_block)
+ MD_CHECK(md_end_current_block(ctx));
+
/* Some line types form block on their own. */
if(line->type == MD_LINE_HR || line->type == MD_LINE_ATXHEADER) {
MD_CHECK(md_end_current_block(ctx));
@@ -6359,13 +6470,14 @@ md_parse(const MD_CHAR* text, MD_SIZE size, const MD_PARSER* parser, void* userd
md_build_mark_char_map(&ctx);
ctx.doc_ends_with_newline = (size > 0 && ISNEWLINE_(text[size-1]));
- /* Reset all unresolved opener mark chains. */
- for(i = 0; i < (int) SIZEOF_ARRAY(ctx.mark_chains); i++) {
- ctx.mark_chains[i].head = -1;
- ctx.mark_chains[i].tail = -1;
- }
+ /* Reset all mark stacks and lists. */
+ for(i = 0; i < (int) SIZEOF_ARRAY(ctx.opener_stacks); i++)
+ ctx.opener_stacks[i].top = -1;
+ ctx.ptr_stack.top = -1;
ctx.unresolved_link_head = -1;
ctx.unresolved_link_tail = -1;
+ ctx.table_cell_boundaries_head = -1;
+ ctx.table_cell_boundaries_tail = -1;
/* All the work. */
ret = md_process_doc(&ctx);
diff --git a/src/3rdparty/md4c/md4c.h b/src/3rdparty/md4c/md4c.h
index 95f78f9b9b..8d6be1cb46 100644
--- a/src/3rdparty/md4c/md4c.h
+++ b/src/3rdparty/md4c/md4c.h
@@ -2,7 +2,7 @@
* MD4C: Markdown parser for C
* (http://github.com/mity/md4c)
*
- * Copyright (c) 2016-2020 Martin Mitas
+ * Copyright (c) 2016-2024 Martin Mitáš
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -284,6 +284,7 @@ typedef struct MD_BLOCK_TD_DETAIL {
typedef struct MD_SPAN_A_DETAIL {
MD_ATTRIBUTE href;
MD_ATTRIBUTE title;
+ int is_autolink; /* nonzero if this is an autolink */
} MD_SPAN_A_DETAIL;
/* Detailed info for MD_SPAN_IMG. */
@@ -316,6 +317,7 @@ typedef struct MD_SPAN_WIKILINK {
#define MD_FLAG_LATEXMATHSPANS 0x1000 /* Enable $ and $$ containing LaTeX equations. */
#define MD_FLAG_WIKILINKS 0x2000 /* Enable wiki links extension. */
#define MD_FLAG_UNDERLINE 0x4000 /* Enable underline extension (and disables '_' for normal emphasis). */
+#define MD_FLAG_HARD_SOFT_BREAKS 0x8000 /* Force all soft breaks to act as hard breaks. */
#define MD_FLAG_PERMISSIVEAUTOLINKS (MD_FLAG_PERMISSIVEEMAILAUTOLINKS | MD_FLAG_PERMISSIVEURLAUTOLINKS | MD_FLAG_PERMISSIVEWWWAUTOLINKS)
#define MD_FLAG_NOHTML (MD_FLAG_NOHTMLBLOCKS | MD_FLAG_NOHTMLSPANS)
diff --git a/src/3rdparty/md4c/qt_attribution.json b/src/3rdparty/md4c/qt_attribution.json
index 29c0666f2d..db53e2d12e 100644
--- a/src/3rdparty/md4c/qt_attribution.json
+++ b/src/3rdparty/md4c/qt_attribution.json
@@ -3,13 +3,14 @@
"Name": "MD4C",
"QDocModule": "qtgui",
"QtUsage": "Optionally used in QTextDocument if configured with textmarkdownreader.",
+ "SecurityCritical": true,
"Description": "A CommonMark-compliant Markdown parser.",
"Homepage": "https://github.com/mity/md4c",
"License": "MIT License",
"LicenseId": "MIT",
"LicenseFile": "LICENSE.md",
- "Version": "0.4.8",
- "DownloadLocation": "https://github.com/mity/md4c/releases/tag/release-0.4.8",
- "Copyright": "Copyright © 2016-2020 Martin Mitáš"
+ "Version": "0.5.2",
+ "DownloadLocation": "https://github.com/mity/md4c/releases/tag/release-0.5.2",
+ "Copyright": "Copyright © 2016-2024 Martin Mitáš"
}
diff --git a/src/3rdparty/md5/qt_attribution.json b/src/3rdparty/md5/qt_attribution.json
index 63fc403041..22165a6a0d 100644
--- a/src/3rdparty/md5/qt_attribution.json
+++ b/src/3rdparty/md5/qt_attribution.json
@@ -4,10 +4,9 @@
"QDocModule": "qtcore",
"QtUsage": "Used in Qt Core (QCryptographicHash).",
- "Description": "Treat as final version; no upstream known",
+ "Comment": "Treat as final version; no upstream known",
"Description": "MD5 message-digest algorithm.",
"License": "Public Domain",
"LicenseId": "CC0-1.0",
- "Copyright": "Written by Colin Plumb in 1993, no copyright is claimed.
-Ian Jackson <ian@chiark.greenend.org.uk>."
+ "Copyright": "Written by Colin Plumb in 1993, no copyright is claimed. Ian Jackson <ian@chiark.greenend.org.uk>."
}
diff --git a/src/3rdparty/pcre2/AUTHORS b/src/3rdparty/pcre2/AUTHORS
index 11ef898b25..9669f7755a 100644
--- a/src/3rdparty/pcre2/AUTHORS
+++ b/src/3rdparty/pcre2/AUTHORS
@@ -8,7 +8,7 @@ Email domain: gmail.com
Retired from University of Cambridge Computing Service,
Cambridge, England.
-Copyright (c) 1997-2022 University of Cambridge
+Copyright (c) 1997-2024 University of Cambridge
All rights reserved
@@ -19,7 +19,7 @@ Written by: Zoltan Herczeg
Email local part: hzmester
Emain domain: freemail.hu
-Copyright(c) 2010-2022 Zoltan Herczeg
+Copyright(c) 2010-2024 Zoltan Herczeg
All rights reserved.
@@ -30,7 +30,7 @@ Written by: Zoltan Herczeg
Email local part: hzmester
Emain domain: freemail.hu
-Copyright(c) 2009-2022 Zoltan Herczeg
+Copyright(c) 2009-2024 Zoltan Herczeg
All rights reserved.
####
diff --git a/src/3rdparty/pcre2/CMakeLists.txt b/src/3rdparty/pcre2/CMakeLists.txt
index a688cf608a..22b90a57e1 100644
--- a/src/3rdparty/pcre2/CMakeLists.txt
+++ b/src/3rdparty/pcre2/CMakeLists.txt
@@ -11,6 +11,7 @@ qt_internal_add_3rdparty_library(BundledPcre2
src/pcre2.h
src/pcre2_auto_possess.c
src/pcre2_chartables.c
+ src/pcre2_chkdint.c
src/pcre2_compile.c
src/pcre2_config.c
src/pcre2_context.c
diff --git a/src/3rdparty/pcre2/LICENCE b/src/3rdparty/pcre2/LICENCE
index 2f3cd5cac5..3c1ef032de 100644
--- a/src/3rdparty/pcre2/LICENCE
+++ b/src/3rdparty/pcre2/LICENCE
@@ -26,7 +26,7 @@ Email domain: gmail.com
Retired from University of Cambridge Computing Service,
Cambridge, England.
-Copyright (c) 1997-2022 University of Cambridge
+Copyright (c) 1997-2024 University of Cambridge
All rights reserved.
@@ -37,7 +37,7 @@ Written by: Zoltan Herczeg
Email local part: hzmester
Email domain: freemail.hu
-Copyright(c) 2010-2022 Zoltan Herczeg
+Copyright(c) 2010-2024 Zoltan Herczeg
All rights reserved.
@@ -48,7 +48,7 @@ Written by: Zoltan Herczeg
Email local part: hzmester
Email domain: freemail.hu
-Copyright(c) 2009-2022 Zoltan Herczeg
+Copyright(c) 2009-2024 Zoltan Herczeg
All rights reserved.
diff --git a/src/3rdparty/pcre2/import_from_pcre2_tarball.sh b/src/3rdparty/pcre2/import_from_pcre2_tarball.sh
index 4a454b059b..7f97ef8f63 100755
--- a/src/3rdparty/pcre2/import_from_pcre2_tarball.sh
+++ b/src/3rdparty/pcre2/import_from_pcre2_tarball.sh
@@ -1,43 +1,8 @@
#! /bin/sh
-#############################################################################
-##
-## Copyright (C) 2020 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.
-##
-## $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$
-##
-#############################################################################
+# Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+#
# 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.
@@ -83,6 +48,7 @@ FILES="
LICENCE
src/pcre2_auto_possess.c
+ src/pcre2_chkdint.c
src/pcre2_compile.c
src/pcre2_config.c
src/pcre2_context.c
@@ -115,9 +81,9 @@ FILES="
src/pcre2_ucptables.c
src/pcre2_valid_utf.c
src/pcre2_xclass.c
+ src/sljit/sljitConfigCPU.h
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
@@ -136,9 +102,15 @@ FILES="
src/sljit/sljitNativeX86_32.c
src/sljit/sljitNativeX86_64.c
src/sljit/sljitNativeX86_common.c
- src/sljit/sljitProtExecAllocator.c
- src/sljit/sljitUtils.c
- src/sljit/sljitWXExecAllocator.c
+ src/sljit/allocator_src/sljitExecAllocatorPosix.c
+ src/sljit/allocator_src/sljitProtExecAllocatorPosix.c
+ src/sljit/allocator_src/sljitWXExecAllocatorPosix.c
+ src/sljit/allocator_src/sljitProtExecAllocatorNetBSD.c
+ src/sljit/allocator_src/sljitExecAllocatorWindows.c
+ src/sljit/allocator_src/sljitExecAllocatorFreeBSD.c
+ src/sljit/allocator_src/sljitExecAllocatorApple.c
+ src/sljit/allocator_src/sljitWXExecAllocatorWindows.c
+ src/sljit/allocator_src/sljitExecAllocatorCore.c
"
for i in $FILES; do
diff --git a/src/3rdparty/pcre2/qt_attribution.json b/src/3rdparty/pcre2/qt_attribution.json
index fce44138cb..b8862bd163 100644
--- a/src/3rdparty/pcre2/qt_attribution.json
+++ b/src/3rdparty/pcre2/qt_attribution.json
@@ -4,16 +4,17 @@
"Name": "PCRE2",
"QDocModule": "qtcore",
"QtUsage": "Optionally used in Qt Core (QRegularExpression). Configure with -system-pcre or -no-pcre to avoid.",
+ "SecurityCritical": true,
"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": "10.42",
- "DownloadLocation": "https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.42/pcre2-10.42.tar.bz2",
+ "Version": "10.43",
+ "DownloadLocation": "https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.43/pcre2-10.43.tar.bz2",
"License": "BSD 3-clause \"New\" or \"Revised\" License with PCRE2 binary-like Packages Exception",
"LicenseId": "LicenseRef-BSD-3-Clause-with-PCRE2-Binary-Like-Packages-Exception",
"LicenseFile": "LICENCE",
- "Copyright": "Copyright (c) 1997-2022 University of Cambridge
-Copyright (c) 2010-2022 Zoltan Herczeg"
+ "Copyright": ["Copyright (c) 1997-2024 University of Cambridge",
+ "Copyright (c) 2010-2024 Zoltan Herczeg"]
},
{
"Id": "pcre2-sljit",
@@ -24,11 +25,11 @@ Copyright (c) 2010-2022 Zoltan Herczeg"
"Path": "src/sljit",
"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": "10.42",
- "DownloadLocation": "https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.42/pcre2-10.42.tar.bz2",
+ "Version": "10.43",
+ "DownloadLocation": "https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.43/pcre2-10.43.tar.bz2",
"License": "BSD 2-clause \"Simplified\" License",
"LicenseId": "BSD-2-Clause",
"LicenseFile": "LICENCE-SLJIT",
- "Copyright": "Copyright (c) 2009-2022 Zoltan Herczeg"
+ "Copyright": "Copyright (c) 2009-2024 Zoltan Herczeg"
}
]
diff --git a/src/3rdparty/pcre2/src/config.h b/src/3rdparty/pcre2/src/config.h
index eeade9d9ce..72518dca5f 100644
--- a/src/3rdparty/pcre2/src/config.h
+++ b/src/3rdparty/pcre2/src/config.h
@@ -14,13 +14,15 @@
#define MAX_NAME_SIZE 32
#define NEWLINE_DEFAULT 2
#define PARENS_NEST_LIMIT 250
+#define MAX_VARLOOKBEHIND 255
#define SUPPORT_UNICODE
+#define PCRE2_EXPORT
/*
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)
+ as PCRE2 10.43, stable JIT support is available for:
+ - ARM 32-bit (v7 and Thumb2)
- ARM 64-bit
- Intel x86 32-bit and 64-bit
- MIPS 32-bit and 64-bit
@@ -32,7 +34,7 @@
#if !defined(PCRE2_DISABLE_JIT) && (\
/* ARM */ \
(defined(__GNUC__) \
- && (defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_M_ARM) || defined(__aarch64__))) \
+ && (defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__aarch64__))) \
/* x86 32/64 */ \
|| defined(__i386) || defined(__i386__) || defined(_M_IX86) \
|| defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64) \
diff --git a/src/3rdparty/pcre2/src/pcre2.h b/src/3rdparty/pcre2/src/pcre2.h
index 1cbecd0e86..d7a8ff5201 100644
--- a/src/3rdparty/pcre2/src/pcre2.h
+++ b/src/3rdparty/pcre2/src/pcre2.h
@@ -5,7 +5,7 @@
/* This is the public header file for the PCRE library, second API, to be
#included by applications that call PCRE2 functions.
- Copyright (c) 2016-2021 University of Cambridge
+ Copyright (c) 2016-2024 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -42,9 +42,9 @@ POSSIBILITY OF SUCH DAMAGE.
/* The current PCRE version information. */
#define PCRE2_MAJOR 10
-#define PCRE2_MINOR 42
+#define PCRE2_MINOR 43
#define PCRE2_PRERELEASE
-#define PCRE2_DATE 2022-12-11
+#define PCRE2_DATE 2024-02-16
/* 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
@@ -153,6 +153,12 @@ D is inspected during pcre2_dfa_match() execution
#define PCRE2_EXTRA_ESCAPED_CR_IS_LF 0x00000010u /* C */
#define PCRE2_EXTRA_ALT_BSUX 0x00000020u /* C */
#define PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK 0x00000040u /* C */
+#define PCRE2_EXTRA_CASELESS_RESTRICT 0x00000080u /* C */
+#define PCRE2_EXTRA_ASCII_BSD 0x00000100u /* C */
+#define PCRE2_EXTRA_ASCII_BSS 0x00000200u /* C */
+#define PCRE2_EXTRA_ASCII_BSW 0x00000400u /* C */
+#define PCRE2_EXTRA_ASCII_POSIX 0x00000800u /* C */
+#define PCRE2_EXTRA_ASCII_DIGIT 0x00001000u /* C */
/* These are for pcre2_jit_compile(). */
@@ -180,11 +186,12 @@ pcre2_jit_match() ignores the latter since it bypasses all sanity checks). */
#define PCRE2_SUBSTITUTE_UNSET_EMPTY 0x00000400u /* pcre2_substitute() only */
#define PCRE2_SUBSTITUTE_UNKNOWN_UNSET 0x00000800u /* pcre2_substitute() only */
#define PCRE2_SUBSTITUTE_OVERFLOW_LENGTH 0x00001000u /* pcre2_substitute() only */
-#define PCRE2_NO_JIT 0x00002000u /* Not for pcre2_dfa_match() */
+#define PCRE2_NO_JIT 0x00002000u /* not for pcre2_dfa_match() */
#define PCRE2_COPY_MATCHED_SUBJECT 0x00004000u
#define PCRE2_SUBSTITUTE_LITERAL 0x00008000u /* pcre2_substitute() only */
#define PCRE2_SUBSTITUTE_MATCHED 0x00010000u /* pcre2_substitute() only */
#define PCRE2_SUBSTITUTE_REPLACEMENT_ONLY 0x00020000u /* pcre2_substitute() only */
+#define PCRE2_DISABLE_RECURSELOOP_CHECK 0x00040000u /* not for pcre2_dfa_match() or pcre2_jit_match() */
/* Options for pcre2_pattern_convert(). */
@@ -399,6 +406,7 @@ released, the numbers must not be changed. */
#define PCRE2_ERROR_CONVERT_SYNTAX (-64)
#define PCRE2_ERROR_INTERNAL_DUPMATCH (-65)
#define PCRE2_ERROR_DFA_UINVALID_UTF (-66)
+#define PCRE2_ERROR_INVALIDOFFSET (-67)
/* Request types for pcre2_pattern_info() */
@@ -575,7 +583,7 @@ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION pcre2_config(uint32_t, void *);
PCRE2_EXP_DECL pcre2_general_context *PCRE2_CALL_CONVENTION \
pcre2_general_context_copy(pcre2_general_context *); \
PCRE2_EXP_DECL pcre2_general_context *PCRE2_CALL_CONVENTION \
- pcre2_general_context_create(void *(*)(PCRE2_SIZE, void *), \
+ pcre2_general_context_create(void *(*)(size_t, void *), \
void (*)(void *, void *), void *); \
PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
pcre2_general_context_free(pcre2_general_context *);
@@ -596,6 +604,8 @@ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
pcre2_set_max_pattern_length(pcre2_compile_context *, PCRE2_SIZE); \
PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_set_max_varlookbehind(pcre2_compile_context *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
pcre2_set_newline(pcre2_compile_context *, uint32_t); \
PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
pcre2_set_parens_nest_limit(pcre2_compile_context *, uint32_t); \
@@ -628,7 +638,7 @@ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
pcre2_set_recursion_limit(pcre2_match_context *, uint32_t); \
PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
pcre2_set_recursion_memory_management(pcre2_match_context *, \
- void *(*)(PCRE2_SIZE, void *), void (*)(void *, void *), void *);
+ void *(*)(size_t, void *), void (*)(void *, void *), void *);
#define PCRE2_CONVERT_CONTEXT_FUNCTIONS \
PCRE2_EXP_DECL pcre2_convert_context *PCRE2_CALL_CONVENTION \
@@ -687,6 +697,8 @@ PCRE2_EXP_DECL PCRE2_SPTR PCRE2_CALL_CONVENTION \
pcre2_get_mark(pcre2_match_data *); \
PCRE2_EXP_DECL PCRE2_SIZE PCRE2_CALL_CONVENTION \
pcre2_get_match_data_size(pcre2_match_data *); \
+PCRE2_EXP_DECL PCRE2_SIZE PCRE2_CALL_CONVENTION \
+ pcre2_get_match_data_heapframes_size(pcre2_match_data *); \
PCRE2_EXP_DECL uint32_t PCRE2_CALL_CONVENTION \
pcre2_get_ovector_count(pcre2_match_data *); \
PCRE2_EXP_DECL PCRE2_SIZE *PCRE2_CALL_CONVENTION \
@@ -722,7 +734,7 @@ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
pcre2_substring_number_from_name(const pcre2_code *, PCRE2_SPTR); \
PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
- pcre2_substring_list_free(PCRE2_SPTR *); \
+ pcre2_substring_list_free(PCRE2_UCHAR **); \
PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
pcre2_substring_list_get(pcre2_match_data *, PCRE2_UCHAR ***, PCRE2_SIZE **);
@@ -771,7 +783,7 @@ PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
pcre2_jit_free_unused_memory(pcre2_general_context *); \
PCRE2_EXP_DECL pcre2_jit_stack *PCRE2_CALL_CONVENTION \
- pcre2_jit_stack_create(PCRE2_SIZE, PCRE2_SIZE, pcre2_general_context *); \
+ pcre2_jit_stack_create(size_t, size_t, pcre2_general_context *); \
PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
pcre2_jit_stack_assign(pcre2_match_context *, pcre2_jit_callback, void *); \
PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
@@ -851,6 +863,7 @@ pcre2_compile are called by application code. */
#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_match_data_heapframes_size PCRE2_SUFFIX(pcre2_get_match_data_heapframes_size_)
#define pcre2_get_match_data_size PCRE2_SUFFIX(pcre2_get_match_data_size_)
#define pcre2_get_ovector_pointer PCRE2_SUFFIX(pcre2_get_ovector_pointer_)
#define pcre2_get_ovector_count PCRE2_SUFFIX(pcre2_get_ovector_count_)
@@ -886,6 +899,7 @@ pcre2_compile are called by application code. */
#define pcre2_set_glob_separator PCRE2_SUFFIX(pcre2_set_glob_separator_)
#define pcre2_set_heap_limit PCRE2_SUFFIX(pcre2_set_heap_limit_)
#define pcre2_set_match_limit PCRE2_SUFFIX(pcre2_set_match_limit_)
+#define pcre2_set_max_varlookbehind PCRE2_SUFFIX(pcre2_set_max_varlookbehind_)
#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_)
diff --git a/src/3rdparty/pcre2/src/pcre2_auto_possess.c b/src/3rdparty/pcre2/src/pcre2_auto_possess.c
index 419fd49001..210d13d37a 100644
--- a/src/3rdparty/pcre2/src/pcre2_auto_possess.c
+++ b/src/3rdparty/pcre2/src/pcre2_auto_possess.c
@@ -560,6 +560,8 @@ matches to an empty string (also represented by a non-zero value). */
for(;;)
{
+ PCRE2_SPTR bracode;
+
/* All operations move the code pointer forward.
Therefore infinite recursions are not possible. */
@@ -617,7 +619,8 @@ for(;;)
recursions. (This could be improved by keeping a list of group numbers that
are called by recursion.) */
- switch(*(code - GET(code, 1)))
+ bracode = code - GET(code, 1);
+ switch(*bracode)
{
case OP_CBRA:
case OP_SCBRA:
@@ -636,16 +639,19 @@ for(;;)
break;
/* 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. */
+ last iterator except for variable length lookbehinds. However, if the
+ group was entered as a result of checking a previous iterator, this is
+ not possible. */
case OP_ASSERT:
case OP_ASSERT_NOT:
- case OP_ASSERTBACK:
- case OP_ASSERTBACK_NOT:
case OP_ONCE:
return !entered_a_group;
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ return (bracode[1+LINK_SIZE] == OP_VREVERSE)? FALSE : !entered_a_group;
+
/* Non-atomic assertions - don't possessify last iterator. This needs
more thought. */
diff --git a/src/3rdparty/pcre2/src/pcre2_chartables.c b/src/3rdparty/pcre2/src/pcre2_chartables.c
index 861914d1ac..7362c3f234 100644
--- a/src/3rdparty/pcre2/src/pcre2_chartables.c
+++ b/src/3rdparty/pcre2/src/pcre2_chartables.c
@@ -5,7 +5,8 @@
/* This file was automatically written by the pcre2_dftables auxiliary
program. It contains character tables that are used when no external
tables are passed to PCRE2 by the application that calls it. The tables
-are used only for characters whose code values are less than 256. */
+are used only for characters whose code values are less than 256, and
+only relevant if not in UCP mode. */
/* This set of tables was written in the C locale. */
@@ -18,13 +19,6 @@ PCRE2 is configured with --enable-rebuild-chartables. However, you can run
pcre2_dftables manually with the -L option to build tables using the LC_ALL
locale. */
-/* The following #include is present because without it gcc 4.x may remove
-the 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. */
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -163,7 +157,7 @@ graph, print, punct, and cntrl. Other classes are built from combinations. */
0x02 letter
0x04 lower case letter
0x08 decimal digit
- 0x10 alphanumeric or '_'
+ 0x10 word (alphanumeric or '_')
*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */
diff --git a/src/3rdparty/pcre2/src/pcre2_chkdint.c b/src/3rdparty/pcre2/src/pcre2_chkdint.c
new file mode 100644
index 0000000000..d04f6f8cf1
--- /dev/null
+++ b/src/3rdparty/pcre2/src/pcre2_chkdint.c
@@ -0,0 +1,96 @@
+/*************************************************
+* 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) 2023 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 functions to implement checked integer operation */
+
+#ifndef PCRE2_PCRE2TEST
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+#endif
+
+/*************************************************
+* Checked Integer Multiplication *
+*************************************************/
+
+/*
+Arguments:
+ r A pointer to PCRE2_SIZE to store the answer
+ a, b Two integers
+
+Returns: Bool indicating if the operation overflows
+
+It is modeled after C23's <stdckdint.h> interface
+The INT64_OR_DOUBLE type is a 64-bit integer type when available,
+otherwise double. */
+
+BOOL
+PRIV(ckd_smul)(PCRE2_SIZE *r, int a, int b)
+{
+#ifdef HAVE_BUILTIN_MUL_OVERFLOW
+PCRE2_SIZE m;
+
+if (__builtin_mul_overflow(a, b, &m)) return TRUE;
+
+*r = m;
+#else
+INT64_OR_DOUBLE m;
+
+#ifdef PCRE2_DEBUG
+if (a < 0 || b < 0) abort();
+#endif
+
+m = (INT64_OR_DOUBLE)a * (INT64_OR_DOUBLE)b;
+
+#if defined INT64_MAX || defined int64_t
+if (sizeof(m) > sizeof(*r) && m > (INT64_OR_DOUBLE)PCRE2_SIZE_MAX) return TRUE;
+*r = (PCRE2_SIZE)m;
+#else
+if (m > PCRE2_SIZE_MAX) return TRUE;
+*r = m;
+#endif
+
+#endif
+
+return FALSE;
+}
+
+/* End of pcre_chkdint.c */
diff --git a/src/3rdparty/pcre2/src/pcre2_compile.c b/src/3rdparty/pcre2/src/pcre2_compile.c
index edf7e82e6e..8b364977c4 100644
--- a/src/3rdparty/pcre2/src/pcre2_compile.c
+++ b/src/3rdparty/pcre2/src/pcre2_compile.c
@@ -7,7 +7,7 @@ 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-2022 University of Cambridge
+ New API code Copyright (c) 2016-2023 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -118,17 +118,17 @@ them will be able to (i.e. assume a 64-bit world). */
#ifdef SUPPORT_UNICODE
static unsigned int
- add_list_to_class_internal(uint8_t *, PCRE2_UCHAR **, uint32_t,
+ add_list_to_class_internal(uint8_t *, PCRE2_UCHAR **, uint32_t, uint32_t,
compile_block *, const uint32_t *, unsigned int);
#endif
static int
- compile_regex(uint32_t, PCRE2_UCHAR **, uint32_t **, int *, uint32_t,
- uint32_t *, uint32_t *, uint32_t *, uint32_t *, branch_chain *,
- compile_block *, PCRE2_SIZE *);
+ compile_regex(uint32_t, uint32_t, PCRE2_UCHAR **, uint32_t **, int *,
+ uint32_t, uint32_t *, uint32_t *, uint32_t *, uint32_t *, branch_chain *,
+ open_capitem *, compile_block *, PCRE2_SIZE *);
static int
- get_branchlength(uint32_t **, int *, int *, parsed_recurse_check *,
+ get_branchlength(uint32_t **, int *, int *, int *, parsed_recurse_check *,
compile_block *);
static BOOL
@@ -694,8 +694,8 @@ static uint32_t chartypeoffset[] = {
now all in a single string, to reduce the number of relocations when a shared
library is dynamically loaded. The list of lengths is terminated by a zero
length entry. The first three must be alpha, lower, upper, as this is assumed
-for handling case independence. The indices for graph, print, and punct are
-needed, so identify them. */
+for handling case independence. The indices for several classes are needed, so
+identify them. */
static const char posix_names[] =
STRING_alpha0 STRING_lower0 STRING_upper0 STRING_alnum0
@@ -706,9 +706,11 @@ static const char posix_names[] =
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
-#define PC_PRINT 9
-#define PC_PUNCT 10
+#define PC_DIGIT 7
+#define PC_GRAPH 8
+#define PC_PRINT 9
+#define PC_PUNCT 10
+#define PC_XDIGIT 13
/* Table of class bit maps for each POSIX class. Each class is formed from a
base map, with an optional addition or removal of another map. Then, for some
@@ -721,20 +723,20 @@ absolute value of the third field has these meanings: 0 => no tweaking, 1 =>
remove vertical space characters, 2 => remove underscore. */
static const int posix_class_maps[] = {
- cbit_word, cbit_digit, -2, /* alpha */
- cbit_lower, -1, 0, /* lower */
- cbit_upper, -1, 0, /* upper */
- cbit_word, -1, 2, /* alnum - word without underscore */
- cbit_print, cbit_cntrl, 0, /* ascii */
- cbit_space, -1, 1, /* blank - a GNU extension */
- cbit_cntrl, -1, 0, /* cntrl */
- cbit_digit, -1, 0, /* digit */
- cbit_graph, -1, 0, /* graph */
- cbit_print, -1, 0, /* print */
- cbit_punct, -1, 0, /* punct */
- cbit_space, -1, 0, /* space */
- cbit_word, -1, 0, /* word - a Perl extension */
- cbit_xdigit,-1, 0 /* xdigit */
+ cbit_word, cbit_digit, -2, /* alpha */
+ cbit_lower, -1, 0, /* lower */
+ cbit_upper, -1, 0, /* upper */
+ cbit_word, -1, 2, /* alnum - word without underscore */
+ cbit_print, cbit_cntrl, 0, /* ascii */
+ cbit_space, -1, 1, /* blank - a GNU extension */
+ cbit_cntrl, -1, 0, /* cntrl */
+ cbit_digit, -1, 0, /* digit */
+ cbit_graph, -1, 0, /* graph */
+ cbit_print, -1, 0, /* print */
+ cbit_punct, -1, 0, /* punct */
+ cbit_space, -1, 0, /* space */
+ cbit_word, -1, 0, /* word - a Perl extension */
+ cbit_xdigit, -1, 0 /* xdigit */
};
#ifdef SUPPORT_UNICODE
@@ -756,7 +758,7 @@ static int posix_substitutes[] = {
PT_PXPUNCT, 0, /* punct */
PT_PXSPACE, 0, /* space */ /* Xps is POSIX space, but from 8.34 */
PT_WORD, 0, /* word */ /* Perl and POSIX space are the same */
- -1, 0 /* xdigit, treat as non-UCP */
+ PT_PXXDIGIT, 0 /* xdigit */ /* Perl has additional hex digits */
};
#define POSIX_SUBSIZE (sizeof(posix_substitutes) / (2*sizeof(uint32_t)))
#endif /* SUPPORT_UNICODE */
@@ -779,13 +781,15 @@ are allowed. */
PCRE2_NO_DOTSTAR_ANCHOR|PCRE2_UCP|PCRE2_UNGREEDY)
#define PUBLIC_LITERAL_COMPILE_EXTRA_OPTIONS \
- (PCRE2_EXTRA_MATCH_LINE|PCRE2_EXTRA_MATCH_WORD)
+ (PCRE2_EXTRA_MATCH_LINE|PCRE2_EXTRA_MATCH_WORD|PCRE2_EXTRA_CASELESS_RESTRICT)
#define PUBLIC_COMPILE_EXTRA_OPTIONS \
(PUBLIC_LITERAL_COMPILE_EXTRA_OPTIONS| \
PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES|PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL| \
PCRE2_EXTRA_ESCAPED_CR_IS_LF|PCRE2_EXTRA_ALT_BSUX| \
- PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK)
+ PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK|PCRE2_EXTRA_ASCII_BSD| \
+ PCRE2_EXTRA_ASCII_BSS|PCRE2_EXTRA_ASCII_BSW|PCRE2_EXTRA_ASCII_POSIX| \
+ PCRE2_EXTRA_ASCII_DIGIT)
/* 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
@@ -804,7 +808,7 @@ enum { ERR0 = COMPILE_ERROR_BASE,
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, ERR89, ERR90,
- ERR91, ERR92, ERR93, ERR94, ERR95, ERR96, ERR97, ERR98, ERR99 };
+ ERR91, ERR92, ERR93, ERR94, ERR95, ERR96, ERR97, ERR98, ERR99, ERR100 };
/* 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
@@ -817,7 +821,8 @@ enum { PSO_OPT, /* Value is an option bit */
PSO_BSR, /* Value is a \R type */
PSO_LIMH, /* Read integer value for heap limit */
PSO_LIMM, /* Read integer value for match limit */
- PSO_LIMD }; /* Read integer value for depth limit */
+ PSO_LIMD /* Read integer value for depth limit */
+ };
typedef struct pso {
const uint8_t *name;
@@ -828,7 +833,7 @@ typedef struct pso {
/* NB: STRING_UTFn_RIGHTPAR contains the length as well */
-static pso pso_list[] = {
+static const 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 },
@@ -1059,24 +1064,24 @@ for (;;)
case META_SKIP: fprintf(stderr, "META (*SKIP)"); break;
case META_THEN: fprintf(stderr, "META (*THEN)"); break;
- case META_OPTIONS: fprintf(stderr, "META_OPTIONS 0x%02x", *pptr++); break;
+ case META_OPTIONS:
+ fprintf(stderr, "META_OPTIONS 0x%08x 0x%08x", pptr[0], pptr[1]);
+ pptr += 2;
+ break;
case META_LOOKBEHIND:
- fprintf(stderr, "META (?<= %d offset=", meta_arg);
- GETOFFSET(offset, pptr);
- fprintf(stderr, "%zd", offset);
+ fprintf(stderr, "META (?<= %d %d", meta_arg, *pptr);
+ pptr += 2;
break;
case META_LOOKBEHIND_NA:
- fprintf(stderr, "META (*naplb: %d offset=", meta_arg);
- GETOFFSET(offset, pptr);
- fprintf(stderr, "%zd", offset);
+ fprintf(stderr, "META (*naplb: %d %d", meta_arg, *pptr);
+ pptr += 2;
break;
case META_LOOKBEHINDNOT:
- fprintf(stderr, "META (?<! %d offset=", meta_arg);
- GETOFFSET(offset, pptr);
- fprintf(stderr, "%zd", offset);
+ fprintf(stderr, "META (?<! %d %d", meta_arg, *pptr);
+ pptr += 2;
break;
case META_CALLOUT_NUMBER:
@@ -1297,9 +1302,9 @@ if (code != NULL)
*************************************************/
/* This function is used to read numbers in the pattern. The initial pointer
-must be the sign or first digit of the number. When relative values (introduced
-by + or -) are allowed, they are relative group numbers, and the result must be
-greater than zero.
+must be at the sign or first digit of the number. When relative values
+(introduced by + or -) are allowed, they are relative group numbers, and the
+result must be greater than zero.
Arguments:
ptrptr points to the character pointer variable
@@ -1383,17 +1388,18 @@ return yield;
* Read repeat counts *
*************************************************/
-/* Read an item of the form {n,m} and return the values if non-NULL pointers
+/* Read an item of the form {n,m} and return the values when non-NULL pointers
are supplied. Repeat counts must be less than 65536 (MAX_REPEAT_COUNT); a
larger value is used for "unlimited". We have to use signed arguments for
-read_number() because it is capable of returning a signed value.
+read_number() because it is capable of returning a signed value. As of Perl
+5.34.0 either n or m may be absent, but not both. Perl also allows spaces and
+tabs after { and before } and between the numbers and the comma, so we do too.
Arguments:
- ptrptr points to pointer to character after'{'
+ ptrptr points to pointer to character after '{'
ptrend pointer to end of input
minp if not NULL, pointer to int for min
- maxp if not NULL, pointer to int for max (-1 if no max)
- returned as -1 if no max
+ maxp if not NULL, pointer to int for max
errorcodeptr points to error code variable
Returns: FALSE if not a repeat quantifier, errorcode set zero
@@ -1405,57 +1411,96 @@ static BOOL
read_repeat_counts(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, uint32_t *minp,
uint32_t *maxp, int *errorcodeptr)
{
-PCRE2_SPTR p;
+PCRE2_SPTR p = *ptrptr;
+PCRE2_SPTR pp;
BOOL yield = FALSE;
-BOOL had_comma = FALSE;
+BOOL had_minimum = FALSE;
int32_t min = 0;
int32_t max = REPEAT_UNLIMITED; /* This value is larger than MAX_REPEAT_COUNT */
-/* Check the syntax */
-
*errorcodeptr = 0;
-for (p = *ptrptr;; p++)
+while (p < ptrend && (*p == CHAR_SPACE || *p == CHAR_HT)) p++;
+
+/* Check the syntax before interpreting. Otherwise, a non-quantifier sequence
+such as "X{123456ABC" would incorrectly give a "number too big in quantifier"
+error. */
+
+pp = p;
+if (pp < ptrend && IS_DIGIT(*pp))
{
- uint32_t c;
- if (p >= ptrend) return FALSE;
- c = *p;
- if (IS_DIGIT(c)) continue;
- if (c == CHAR_RIGHT_CURLY_BRACKET) break;
- if (c == CHAR_COMMA)
+ had_minimum = TRUE;
+ while (++pp < ptrend && IS_DIGIT(*pp)) {}
+ }
+
+while (pp < ptrend && (*pp == CHAR_SPACE || *pp == CHAR_HT)) pp++;
+if (pp >= ptrend) return FALSE;
+
+if (*pp == CHAR_RIGHT_CURLY_BRACKET)
+ {
+ if (!had_minimum) return FALSE;
+ }
+else
+ {
+ if (*pp++ != CHAR_COMMA) return FALSE;
+ while (pp < ptrend && (*pp == CHAR_SPACE || *pp == CHAR_HT)) pp++;
+ if (pp >= ptrend) return FALSE;
+ if (IS_DIGIT(*pp))
{
- if (had_comma) return FALSE;
- had_comma = TRUE;
+ while (++pp < ptrend && IS_DIGIT(*pp)) {}
}
- else return FALSE;
+ else if (!had_minimum) return FALSE;
+ while (pp < ptrend && (*pp == CHAR_SPACE || *pp == CHAR_HT)) pp++;
+ if (pp >= ptrend || *pp != CHAR_RIGHT_CURLY_BRACKET) return FALSE;
}
-/* The only error from read_number() is for a number that is too big. */
+/* Now process the quantifier for real. We know it must be {n} or (n,} or {,m}
+or {n,m}. The only error that read_number() can return is for a number that is
+too big. If *errorcodeptr is returned as zero it means no number was found. */
-p = *ptrptr;
-if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &min, errorcodeptr))
- goto EXIT;
+/* Deal with {,m} or n too big. If we successfully read m there is no need to
+check m >= n because n defaults to zero. */
-if (*p == CHAR_RIGHT_CURLY_BRACKET)
+if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &min, errorcodeptr))
{
- p++;
- max = min;
+ if (*errorcodeptr != 0) goto EXIT; /* n too big */
+ p++; /* Skip comma and subsequent spaces */
+ while (p < ptrend && (*p == CHAR_SPACE || *p == CHAR_HT)) p++;
+ if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &max, errorcodeptr))
+ {
+ if (*errorcodeptr != 0) goto EXIT; /* m too big */
+ }
}
+
+/* Have read one number. Deal with {n} or {n,} or {n,m} */
+
else
{
- if (*(++p) != CHAR_RIGHT_CURLY_BRACKET)
+ while (p < ptrend && (*p == CHAR_SPACE || *p == CHAR_HT)) p++;
+ if (*p == CHAR_RIGHT_CURLY_BRACKET)
{
- if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &max,
- errorcodeptr))
- goto EXIT;
+ max = min;
+ }
+ else /* Handle {n,} or {n,m} */
+ {
+ p++; /* Skip comma and subsequent spaces */
+ while (p < ptrend && (*p == CHAR_SPACE || *p == CHAR_HT)) p++;
+ if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &max, errorcodeptr))
+ {
+ if (*errorcodeptr != 0) goto EXIT; /* m too big */
+ }
+
if (max < min)
{
*errorcodeptr = ERR4;
goto EXIT;
}
}
- p++;
}
+/* Valid quantifier exists */
+
+while (p < ptrend && (*p == CHAR_SPACE || *p == CHAR_HT)) p++;
+p++;
yield = TRUE;
if (minp != NULL) *minp = (uint32_t)min;
if (maxp != NULL) *maxp = (uint32_t)max;
@@ -1491,6 +1536,7 @@ Arguments:
chptr points to a returned data character
errorcodeptr points to the errorcode variable (containing zero)
options the current options bits
+ xoptions the current extra options bits
isclass TRUE if inside a character class
cb compile data block or NULL when called from pcre2_substitute()
@@ -1502,10 +1548,12 @@ Returns: zero => a data character
int
PRIV(check_escape)(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, uint32_t *chptr,
- int *errorcodeptr, uint32_t options, uint32_t extra_options, BOOL isclass,
+ int *errorcodeptr, uint32_t options, uint32_t xoptions, BOOL isclass,
compile_block *cb)
{
BOOL utf = (options & PCRE2_UTF) != 0;
+BOOL alt_bsux =
+ ((options & PCRE2_ALT_BSUX) | (xoptions & PCRE2_EXTRA_ALT_BSUX)) != 0;
PCRE2_SPTR ptr = *ptrptr;
uint32_t c, cc;
int escape = 0;
@@ -1539,7 +1587,7 @@ else if ((i = escapes[c - ESCAPES_FIRST]) != 0)
if (i > 0)
{
c = (uint32_t)i;
- if (c == CHAR_CR && (extra_options & PCRE2_EXTRA_ESCAPED_CR_IS_LF) != 0)
+ if (c == CHAR_CR && (xoptions & PCRE2_EXTRA_ESCAPED_CR_IS_LF) != 0)
c = CHAR_LF;
}
else /* Negative table entry */
@@ -1557,6 +1605,10 @@ else if ((i = escapes[c - ESCAPES_FIRST]) != 0)
{
PCRE2_SPTR p = ptr + 1;
+ /* Perl ignores spaces and tabs after { */
+
+ while (p < ptrend && (*p == CHAR_SPACE || *p == CHAR_HT)) p++;
+
/* \N{U+ can be handled by the \x{ code. However, this construction is
not valid in EBCDIC environments because it specifies a Unicode
character, not a codepoint in the local code. For example \N{U+0041}
@@ -1571,7 +1623,7 @@ else if ((i = escapes[c - ESCAPES_FIRST]) != 0)
#else
if (utf)
{
- ptr = p + 1;
+ ptr = p + 2;
escape = 0; /* Not a fancy escape after all */
goto COME_FROM_NU;
}
@@ -1602,8 +1654,6 @@ else
int s;
PCRE2_SPTR oldptr;
BOOL overflow;
- BOOL alt_bsux =
- ((options & PCRE2_ALT_BSUX) | (extra_options & PCRE2_EXTRA_ALT_BSUX)) != 0;
/* Filter calls from pcre2_substitute(). */
@@ -1632,7 +1682,9 @@ else
is set. Otherwise, \u must be followed by exactly four hex digits or, if
PCRE2_EXTRA_ALT_BSUX is set, by any number of hex digits in braces.
Otherwise it is a lowercase u letter. This gives some compatibility with
- ECMAScript (aka JavaScript). */
+ ECMAScript (aka JavaScript). Unlike other braced items, white space is NOT
+ allowed. When \u{ is not followed by hex digits, a special return is given
+ because otherwise \u{ 12} (for example) would be treated as u{12}. */
case CHAR_u:
if (!alt_bsux) *errorcodeptr = ERR37; else
@@ -1641,11 +1693,11 @@ else
if (ptr >= ptrend) break;
if (*ptr == CHAR_LEFT_CURLY_BRACKET &&
- (extra_options & PCRE2_EXTRA_ALT_BSUX) != 0)
+ (xoptions & PCRE2_EXTRA_ALT_BSUX) != 0)
{
PCRE2_SPTR hptr = ptr + 1;
- cc = 0;
+ cc = 0;
while (hptr < ptrend && (xc = XDIGIT(*hptr)) != 0xff)
{
if ((cc & 0xf0000000) != 0) /* Test for 32-bit overflow */
@@ -1661,7 +1713,11 @@ else
if (hptr == ptr + 1 || /* No hex digits */
hptr >= ptrend || /* Hit end of input */
*hptr != CHAR_RIGHT_CURLY_BRACKET) /* No } terminator */
- break; /* Hex escape not recognized */
+ {
+ escape = ESC_ub; /* Special return */
+ ptr++; /* Skip { */
+ break; /* Hex escape not recognized */
+ }
c = cc; /* Accept the code point */
ptr = hptr + 1;
@@ -1685,7 +1741,7 @@ else
if (c > 0x10ffffU) *errorcodeptr = ERR77;
else
if (c >= 0xd800 && c <= 0xdfff &&
- (extra_options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) == 0)
+ (xoptions & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) == 0)
*errorcodeptr = ERR73;
}
else if (c > MAX_NON_UTF_CHAR) *errorcodeptr = ERR77;
@@ -1741,12 +1797,16 @@ else
if (*ptr == CHAR_LEFT_CURLY_BRACKET)
{
PCRE2_SPTR p = ptr + 1;
+
+ while (p < ptrend && (*p == CHAR_SPACE || *p == CHAR_HT)) p++;
if (!read_number(&p, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &s,
errorcodeptr))
{
if (*errorcodeptr == 0) escape = ESC_k; /* No number found */
break;
}
+ while (p < ptrend && (*p == CHAR_SPACE || *p == CHAR_HT)) p++;
+
if (p >= ptrend || *p != CHAR_RIGHT_CURLY_BRACKET)
{
*errorcodeptr = ERR57;
@@ -1842,56 +1902,64 @@ else
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}. */
+ specifying character codes in octal. The only supported form is \o{ddd},
+ with optional spaces or tabs after { and before }. */
case CHAR_o:
if (ptr >= ptrend || *ptr++ != CHAR_LEFT_CURLY_BRACKET)
{
ptr--;
*errorcodeptr = ERR55;
+ break;
}
- else if (ptr >= ptrend || *ptr == CHAR_RIGHT_CURLY_BRACKET)
+
+ while (ptr < ptrend && (*ptr == CHAR_SPACE || *ptr == CHAR_HT)) ptr++;
+ if (ptr >= ptrend || *ptr == CHAR_RIGHT_CURLY_BRACKET)
+ {
*errorcodeptr = ERR78;
- else
+ break;
+ }
+
+ c = 0;
+ overflow = FALSE;
+ while (ptr < ptrend && *ptr >= CHAR_0 && *ptr <= CHAR_7)
{
- c = 0;
- overflow = FALSE;
- while (ptr < ptrend && *ptr >= CHAR_0 && *ptr <= CHAR_7)
- {
- cc = *ptr++;
- if (c == 0 && cc == CHAR_0) continue; /* Leading zeroes */
+ cc = *ptr++;
+ if (c == 0 && cc == CHAR_0) continue; /* Leading zeroes */
#if PCRE2_CODE_UNIT_WIDTH == 32
- if (c >= 0x20000000l) { overflow = TRUE; break; }
+ if (c >= 0x20000000l) { overflow = TRUE; break; }
#endif
- c = (c << 3) + (cc - CHAR_0);
+ c = (c << 3) + (cc - CHAR_0);
#if PCRE2_CODE_UNIT_WIDTH == 8
- if (c > (utf ? 0x10ffffU : 0xffU)) { overflow = TRUE; break; }
+ if (c > (utf ? 0x10ffffU : 0xffU)) { overflow = TRUE; break; }
#elif PCRE2_CODE_UNIT_WIDTH == 16
- if (c > (utf ? 0x10ffffU : 0xffffU)) { overflow = TRUE; break; }
+ if (c > (utf ? 0x10ffffU : 0xffffU)) { overflow = TRUE; break; }
#elif PCRE2_CODE_UNIT_WIDTH == 32
- if (utf && c > 0x10ffffU) { overflow = TRUE; break; }
+ if (utf && c > 0x10ffffU) { overflow = TRUE; break; }
#endif
- }
- if (overflow)
- {
- while (ptr < ptrend && *ptr >= CHAR_0 && *ptr <= CHAR_7) ptr++;
- *errorcodeptr = ERR34;
- }
- else if (ptr < ptrend && *ptr++ == CHAR_RIGHT_CURLY_BRACKET)
- {
- if (utf && c >= 0xd800 && c <= 0xdfff &&
- (extra_options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) == 0)
- {
- ptr--;
- *errorcodeptr = ERR73;
- }
- }
- else
+ }
+
+ while (ptr < ptrend && (*ptr == CHAR_SPACE || *ptr == CHAR_HT)) ptr++;
+
+ if (overflow)
+ {
+ while (ptr < ptrend && *ptr >= CHAR_0 && *ptr <= CHAR_7) ptr++;
+ *errorcodeptr = ERR34;
+ }
+ else if (ptr < ptrend && *ptr++ == CHAR_RIGHT_CURLY_BRACKET)
+ {
+ if (utf && c >= 0xd800 && c <= 0xdfff &&
+ (xoptions & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) == 0)
{
ptr--;
- *errorcodeptr = ERR64;
+ *errorcodeptr = ERR73;
}
}
+ else
+ {
+ ptr--;
+ *errorcodeptr = ERR64;
+ }
break;
/* When PCRE2_ALT_BSUX or PCRE2_EXTRA_ALT_BSUX is set, \x must be followed
@@ -1919,10 +1987,13 @@ else
{
if (ptr < ptrend && *ptr == CHAR_LEFT_CURLY_BRACKET)
{
+ ptr++;
+ while (ptr < ptrend && (*ptr == CHAR_SPACE || *ptr == CHAR_HT)) ptr++;
+
#ifndef EBCDIC
COME_FROM_NU:
#endif
- if (++ptr >= ptrend || *ptr == CHAR_RIGHT_CURLY_BRACKET)
+ if (ptr >= ptrend || *ptr == CHAR_RIGHT_CURLY_BRACKET)
{
*errorcodeptr = ERR78;
break;
@@ -1945,6 +2016,12 @@ else
}
}
+ /* Perl ignores spaces and tabs before } */
+
+ while (ptr < ptrend && (*ptr == CHAR_SPACE || *ptr == CHAR_HT)) ptr++;
+
+ /* On overflow, skip remaining hex digits */
+
if (overflow)
{
while (ptr < ptrend && XDIGIT(*ptr) != 0xff) ptr++;
@@ -1953,17 +2030,17 @@ else
else if (ptr < ptrend && *ptr++ == CHAR_RIGHT_CURLY_BRACKET)
{
if (utf && c >= 0xd800 && c <= 0xdfff &&
- (extra_options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) == 0)
+ (xoptions & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) == 0)
{
ptr--;
*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. */
+ /* If the sequence of hex digits (followed by optional space) 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
{
@@ -2117,7 +2194,11 @@ if (c == CHAR_LEFT_CURLY_BRACKET)
{
if (ptr >= cb->end_pattern) goto ERROR_RETURN;
c = *ptr++;
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ while (c == '_' || c == '-' || (c <= 0xff && isspace(c)))
+#else
while (c == '_' || c == '-' || isspace(c))
+#endif
{
if (ptr >= cb->end_pattern) goto ERROR_RETURN;
c = *ptr++;
@@ -2355,12 +2436,13 @@ return -1;
/* This function is called from parse_regex() below whenever it needs to read
the name of a subpattern or a (*VERB) or an (*alpha_assertion). The initial
-pointer must be to the character before the name. If that character is '*' we
-are reading a verb or alpha assertion name. The pointer is updated to point
-after the name, for a VERB or alpha assertion name, or after tha name's
-terminator for a subpattern name. Returning both the offset and the name
-pointer is redundant information, but some callers use one and some the other,
-so it is simplest just to return both.
+pointer must be to the preceding character. If that character is '*' we are
+reading a verb or alpha assertion name. The pointer is updated to point after
+the name, for a VERB or alpha assertion name, or after tha name's terminator
+for a subpattern name. Returning both the offset and the name pointer is
+redundant information, but some callers use one and some the other, so it is
+simplest just to return both. When the name is in braces, spaces and tabs are
+allowed (and ignored) at either end.
Arguments:
ptrptr points to the character pointer variable
@@ -2383,9 +2465,13 @@ read_name(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, BOOL utf, uint32_t terminator,
int *errorcodeptr, compile_block *cb)
{
PCRE2_SPTR ptr = *ptrptr;
-BOOL is_group = (*ptr != CHAR_ASTERISK);
+BOOL is_group = (*ptr++ != CHAR_ASTERISK);
+BOOL is_braced = terminator == CHAR_RIGHT_CURLY_BRACKET;
+
+if (is_braced)
+ while (ptr < ptrend && (*ptr == CHAR_SPACE || *ptr == CHAR_HT)) ptr++;
-if (++ptr >= ptrend) /* No characters in name */
+if (ptr >= ptrend) /* No characters in name */
{
*errorcodeptr = is_group? ERR62: /* Subpattern name expected */
ERR60; /* Verb not recognized or malformed */
@@ -2464,6 +2550,8 @@ if (is_group)
*errorcodeptr = ERR62; /* Subpattern name expected */
goto FAILED;
}
+ if (is_braced)
+ while (ptr < ptrend && (*ptr == CHAR_SPACE || *ptr == CHAR_HT)) ptr++;
if (ptr >= ptrend || *ptr != (PCRE2_UCHAR)terminator)
{
*errorcodeptr = ERR42;
@@ -2533,6 +2621,85 @@ return parsed_pattern;
/*************************************************
+* Handle \d, \D, \s, \S, \w, \W *
+*************************************************/
+
+/* This function is called from parse_regex() below, both for freestanding
+escapes, and those within classes, to handle those escapes that may change when
+Unicode property support is requested. Note that PCRE2_UCP will never be set
+without Unicode support because that is checked when pcre2_compile() is called.
+
+Arguments:
+ escape the ESC_... value
+ parsed_pattern where to add the code
+ options options bits
+ xoptions extra options bits
+
+Returns: updated value of parsed_pattern
+*/
+static uint32_t *
+handle_escdsw(int escape, uint32_t *parsed_pattern, uint32_t options,
+ uint32_t xoptions)
+{
+uint32_t ascii_option = 0;
+uint32_t prop = ESC_p;
+
+switch(escape)
+ {
+ case ESC_D:
+ prop = ESC_P;
+ /* Fall through */
+ case ESC_d:
+ ascii_option = PCRE2_EXTRA_ASCII_BSD;
+ break;
+
+ case ESC_S:
+ prop = ESC_P;
+ /* Fall through */
+ case ESC_s:
+ ascii_option = PCRE2_EXTRA_ASCII_BSS;
+ break;
+
+ case ESC_W:
+ prop = ESC_P;
+ /* Fall through */
+ case ESC_w:
+ ascii_option = PCRE2_EXTRA_ASCII_BSW;
+ break;
+ }
+
+if ((options & PCRE2_UCP) == 0 || (xoptions & ascii_option) != 0)
+ {
+ *parsed_pattern++ = META_ESCAPE + escape;
+ }
+else
+ {
+ *parsed_pattern++ = META_ESCAPE + prop;
+ switch(escape)
+ {
+ case ESC_d:
+ case ESC_D:
+ *parsed_pattern++ = (PT_PC << 16) | ucp_Nd;
+ break;
+
+ case ESC_s:
+ case ESC_S:
+ *parsed_pattern++ = PT_SPACE << 16;
+ break;
+
+ case ESC_w:
+ case ESC_W:
+ *parsed_pattern++ = PT_WORD << 16;
+ break;
+ }
+ }
+
+return parsed_pattern;
+}
+
+
+
+/*************************************************
* Parse regex and identify named groups *
*************************************************/
@@ -2560,6 +2727,7 @@ typedef struct nest_save {
uint16_t max_group;
uint16_t flags;
uint32_t options;
+ uint32_t xoptions;
} nest_save;
#define NSF_RESET 0x0001u
@@ -2575,6 +2743,10 @@ the main compiling phase. */
PCRE2_EXTENDED|PCRE2_EXTENDED_MORE|PCRE2_MULTILINE|PCRE2_NO_AUTO_CAPTURE| \
PCRE2_UNGREEDY)
+#define PARSE_TRACKED_EXTRA_OPTIONS (PCRE2_EXTRA_CASELESS_RESTRICT| \
+ PCRE2_EXTRA_ASCII_BSD|PCRE2_EXTRA_ASCII_BSS|PCRE2_EXTRA_ASCII_BSW| \
+ PCRE2_EXTRA_ASCII_DIGIT|PCRE2_EXTRA_ASCII_POSIX)
+
/* States used for analyzing ranges in character classes. The two OK values
must be last. */
@@ -2609,9 +2781,11 @@ uint32_t *verbstartptr = NULL;
uint32_t *previous_callout = NULL;
uint32_t *parsed_pattern = cb->parsed_pattern;
uint32_t *parsed_pattern_end = cb->parsed_pattern_end;
+uint32_t *this_parsed_item = NULL;
+uint32_t *prev_parsed_item = NULL;
uint32_t meta_quantifier = 0;
uint32_t add_after_mark = 0;
-uint32_t extra_options = cb->cx->extra_options;
+uint32_t xoptions = cb->cx->extra_options;
uint16_t nest_depth = 0;
int after_manual_callout = 0;
int expect_cond_assert = 0;
@@ -2635,12 +2809,12 @@ nest_save *top_nest, *end_nests;
/* Insert leading items for word and line matching (features provided for the
benefit of pcre2grep). */
-if ((extra_options & PCRE2_EXTRA_MATCH_LINE) != 0)
+if ((xoptions & PCRE2_EXTRA_MATCH_LINE) != 0)
{
*parsed_pattern++ = META_CIRCUMFLEX;
*parsed_pattern++ = META_NOCAPTURE;
}
-else if ((extra_options & PCRE2_EXTRA_MATCH_WORD) != 0)
+else if ((xoptions & PCRE2_EXTRA_MATCH_WORD) != 0)
{
*parsed_pattern++ = META_ESCAPE + ESC_b;
*parsed_pattern++ = META_NOCAPTURE;
@@ -2691,6 +2865,7 @@ while (ptr < ptrend)
int prev_expect_cond_assert;
uint32_t min_repeat = 0, max_repeat = 0;
uint32_t set, unset, *optset;
+ uint32_t xset, xunset, *xoptset;
uint32_t terminator;
uint32_t prev_meta_quantifier;
BOOL prev_okquantifier;
@@ -2709,6 +2884,17 @@ while (ptr < ptrend)
goto FAILED; /* Parentheses too deeply nested */
}
+ /* If the last time round this loop something was added, parsed_pattern will
+ no longer be equal to this_parsed_item. Remember where the previous item
+ started and reset for the next item. Note that sometimes round the loop,
+ nothing gets added (e.g. for ignored white space). */
+
+ if (this_parsed_item != parsed_pattern)
+ {
+ prev_parsed_item = this_parsed_item;
+ this_parsed_item = parsed_pattern;
+ }
+
/* Get next input character, save its position for callout handling. */
thisptr = ptr;
@@ -2817,7 +3003,7 @@ while (ptr < ptrend)
if ((options & PCRE2_ALT_VERBNAMES) != 0)
{
escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode, options,
- cb->cx->extra_options, FALSE, cb);
+ xoptions, FALSE, cb);
if (errorcode != 0) goto FAILED;
}
else escape = 0; /* Treat all as literal */
@@ -2831,6 +3017,11 @@ while (ptr < ptrend)
*parsed_pattern++ = c;
break;
+ case ESC_ub:
+ *parsed_pattern++ = CHAR_u;
+ PARSED_LITERAL(CHAR_LEFT_CURLY_BRACKET, parsed_pattern);
+ break;
+
case ESC_Q:
inescq = TRUE;
break;
@@ -2917,8 +3108,11 @@ while (ptr < ptrend)
!read_repeat_counts(&tempptr, ptrend, NULL, NULL, &errorcode))))
{
if (after_manual_callout-- <= 0)
+ {
parsed_pattern = manage_callouts(thisptr, &previous_callout, auto_callout,
parsed_pattern, cb);
+ this_parsed_item = parsed_pattern; /* New start for current item */
+ }
}
/* If expect_cond_assert is 2, we have just passed (?( and are expecting an
@@ -2995,7 +3189,6 @@ while (ptr < ptrend)
continue; /* Next character in pattern */
}
-
/* Process the next item in the main part of a pattern. */
switch(c)
@@ -3010,11 +3203,11 @@ while (ptr < ptrend)
case CHAR_BACKSLASH:
tempptr = ptr;
escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode, options,
- cb->cx->extra_options, FALSE, cb);
+ xoptions, FALSE, cb);
if (errorcode != 0)
{
ESCAPE_FAILED:
- if ((extra_options & PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL) == 0)
+ if ((xoptions & PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL) == 0)
goto FAILED;
ptr = tempptr;
if (ptr >= ptrend) c = CHAR_BACKSLASH; else
@@ -3088,6 +3281,16 @@ while (ptr < ptrend)
*parsed_pattern++ = META_ESCAPE + escape;
break;
+ /* This is a special return that happens only in EXTRA_ALT_BSUX mode,
+ when \u{ is not followed by hex digits and }. It requests two literal
+ characters, u and { and we need this, as otherwise \u{ 12} (for example)
+ would be treated as u{12} now that spaces are allowed in quantifiers. */
+
+ case ESC_ub:
+ *parsed_pattern++ = CHAR_u;
+ PARSED_LITERAL(CHAR_LEFT_CURLY_BRACKET, parsed_pattern);
+ break;
+
case ESC_X:
#ifndef SUPPORT_UNICODE
errorcode = ERR45; /* Supported only with Unicode support */
@@ -3107,9 +3310,7 @@ while (ptr < ptrend)
*parsed_pattern++ = META_ESCAPE + escape;
break;
- /* Escapes that change in UCP mode. Note that PCRE2_UCP will never be set
- without Unicode support because it is checked when pcre2_compile() is
- called. */
+ /* Escapes that may change in UCP mode. */
case ESC_d:
case ESC_D:
@@ -3118,33 +3319,8 @@ while (ptr < ptrend)
case ESC_w:
case ESC_W:
okquantifier = TRUE;
- if ((options & PCRE2_UCP) == 0)
- {
- *parsed_pattern++ = META_ESCAPE + escape;
- }
- else
- {
- *parsed_pattern++ = META_ESCAPE +
- ((escape == ESC_d || escape == ESC_s || escape == ESC_w)?
- ESC_p : ESC_P);
- switch(escape)
- {
- case ESC_d:
- case ESC_D:
- *parsed_pattern++ = (PT_PC << 16) | ucp_Nd;
- break;
-
- case ESC_s:
- case ESC_S:
- *parsed_pattern++ = PT_SPACE << 16;
- break;
-
- case ESC_w:
- case ESC_W:
- *parsed_pattern++ = PT_WORD << 16;
- break;
- }
- }
+ parsed_pattern = handle_escdsw(escape, parsed_pattern, options,
+ xoptions);
break;
/* Unicode property matching */
@@ -3206,7 +3382,8 @@ while (ptr < ptrend)
if (errorcode != 0) goto ESCAPE_FAILED;
}
- /* Not a numerical recursion */
+ /* Not a numerical recursion. Perl allows spaces and tabs after { and
+ before } but not for other delimiters. */
if (!read_name(&ptr, ptrend, utf, terminator, &offset, &name, &namelen,
&errorcode, cb)) goto ESCAPE_FAILED;
@@ -3273,7 +3450,8 @@ while (ptr < ptrend)
/* ---- Quantifier post-processing ---- */
- /* Check that a quantifier is allowed after the previous item. */
+ /* Check that a quantifier is allowed after the previous item. This
+ guarantees that there is a previous item. */
CHECK_QUANTIFIER:
if (!prev_okquantifier)
@@ -3288,7 +3466,7 @@ while (ptr < ptrend)
wrapping it in non-capturing brackets, but we have to allow for a preceding
(*MARK) for when (*ACCEPT) has an argument. */
- if (parsed_pattern[-1] == META_ACCEPT)
+ if (*prev_parsed_item == META_ACCEPT)
{
uint32_t *p;
for (p = parsed_pattern - 1; p >= verbstartptr; p--) p[1] = p[0];
@@ -3507,18 +3685,24 @@ while (ptr < ptrend)
class_range_state = RANGE_NO;
- /* When PCRE2_UCP is set, some of the POSIX classes are converted to
- use Unicode properties \p or \P or, in one case, \h or \H. The
- substitutes table has two values per class, containing the type and
- value of a \p or \P item. The special cases are specified with a
- negative type: a non-zero value causes \h or \H to be used, and a zero
- value falls through to behave like a non-UCP POSIX class. */
+ /* When PCRE2_UCP is set, unless PCRE2_EXTRA_ASCII_POSIX is set, some
+ of the POSIX classes are converted to use Unicode properties \p or \P
+ or, in one case, \h or \H. The substitutes table has two values per
+ class, containing the type and value of a \p or \P item. The special
+ cases are specified with a negative type: a non-zero value causes \h or
+ \H to be used, and a zero value falls through to behave like a non-UCP
+ POSIX class. There are now also some extra options that force ASCII for
+ some classes. */
#ifdef SUPPORT_UNICODE
- if ((options & PCRE2_UCP) != 0)
+ if ((options & PCRE2_UCP) != 0 &&
+ (xoptions & PCRE2_EXTRA_ASCII_POSIX) == 0 &&
+ !((xoptions & PCRE2_EXTRA_ASCII_DIGIT) != 0 &&
+ (posix_class == PC_DIGIT || posix_class == PC_XDIGIT)))
{
int ptype = posix_substitutes[2*posix_class];
int pvalue = posix_substitutes[2*posix_class + 1];
+
if (ptype >= 0)
{
*parsed_pattern++ = META_ESCAPE + (posix_negate? ESC_P : ESC_p);
@@ -3587,11 +3771,11 @@ while (ptr < ptrend)
{
tempptr = ptr;
escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode, options,
- cb->cx->extra_options, TRUE, cb);
+ xoptions, TRUE, cb);
if (errorcode != 0)
{
- if ((extra_options & PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL) == 0)
+ if ((xoptions & PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL) == 0)
goto FAILED;
ptr = tempptr;
if (ptr >= ptrend) c = CHAR_BACKSLASH; else
@@ -3605,7 +3789,7 @@ while (ptr < ptrend)
{
case 0: /* Escaped character code point is in c */
char_is_literal = FALSE;
- goto CLASS_LITERAL;
+ goto CLASS_LITERAL; /* (a few lines above) */
case ESC_b:
c = CHAR_BS; /* \b is backspace in a class */
@@ -3656,7 +3840,7 @@ while (ptr < ptrend)
*parsed_pattern++ = META_ESCAPE + escape;
break;
- /* These escapes are converted to Unicode property tests when
+ /* These escapes may be converted to Unicode property tests when
PCRE2_UCP is set. */
case ESC_d:
@@ -3665,33 +3849,8 @@ while (ptr < ptrend)
case ESC_S:
case ESC_w:
case ESC_W:
- if ((options & PCRE2_UCP) == 0)
- {
- *parsed_pattern++ = META_ESCAPE + escape;
- }
- else
- {
- *parsed_pattern++ = META_ESCAPE +
- ((escape == ESC_d || escape == ESC_s || escape == ESC_w)?
- ESC_p : ESC_P);
- switch(escape)
- {
- case ESC_d:
- case ESC_D:
- *parsed_pattern++ = (PT_PC << 16) | ucp_Nd;
- break;
-
- case ESC_s:
- case ESC_S:
- *parsed_pattern++ = PT_SPACE << 16;
- break;
-
- case ESC_w:
- case ESC_W:
- *parsed_pattern++ = PT_WORD << 16;
- break;
- }
- }
+ parsed_pattern = handle_escdsw(escape, parsed_pattern, options,
+ xoptions);
break;
/* Explicit Unicode property matching */
@@ -3890,6 +4049,7 @@ while (ptr < ptrend)
top_nest->nest_depth = nest_depth;
top_nest->flags = NSF_ATOMICSR;
top_nest->options = options & PARSE_TRACKED_OPTIONS;
+ top_nest->xoptions = xoptions & PARSE_TRACKED_EXTRA_OPTIONS;
}
break;
#else /* SUPPORT_UNICODE */
@@ -4022,6 +4182,7 @@ while (ptr < ptrend)
top_nest->nest_depth = nest_depth;
top_nest->flags = 0;
top_nest->options = options & PARSE_TRACKED_OPTIONS;
+ top_nest->xoptions = xoptions & PARSE_TRACKED_EXTRA_OPTIONS;
/* Start of non-capturing group that resets the capture count for each
branch. */
@@ -4036,24 +4197,28 @@ while (ptr < ptrend)
ptr++;
}
- /* Scan for options imnsxJU to be set or unset. */
+ /* Scan for options imnrsxJU to be set or unset. */
else
{
BOOL hyphenok = TRUE;
uint32_t oldoptions = options;
+ uint32_t oldxoptions = xoptions;
top_nest->reset_group = 0;
top_nest->max_group = 0;
set = unset = 0;
optset = &set;
+ xset = xunset = 0;
+ xoptset = &xset;
- /* ^ at the start unsets imnsx and disables the subsequent use of - */
+ /* ^ at the start unsets irmnsx and disables the subsequent use of - */
if (ptr < ptrend && *ptr == CHAR_CIRCUMFLEX_ACCENT)
{
options &= ~(PCRE2_CASELESS|PCRE2_MULTILINE|PCRE2_NO_AUTO_CAPTURE|
PCRE2_DOTALL|PCRE2_EXTENDED|PCRE2_EXTENDED_MORE);
+ xoptions &= ~(PCRE2_EXTRA_CASELESS_RESTRICT);
hyphenok = FALSE;
ptr++;
}
@@ -4071,9 +4236,51 @@ while (ptr < ptrend)
goto FAILED;
}
optset = &unset;
+ xoptset = &xunset;
hyphenok = FALSE;
break;
+ /* There are some two-character sequences that start with 'a'. */
+
+ case CHAR_a:
+ if (ptr < ptrend)
+ {
+ if (*ptr == CHAR_D)
+ {
+ *xoptset |= PCRE2_EXTRA_ASCII_BSD;
+ ptr++;
+ break;
+ }
+ if (*ptr == CHAR_P)
+ {
+ *xoptset |= (PCRE2_EXTRA_ASCII_POSIX|PCRE2_EXTRA_ASCII_DIGIT);
+ ptr++;
+ break;
+ }
+ if (*ptr == CHAR_S)
+ {
+ *xoptset |= PCRE2_EXTRA_ASCII_BSS;
+ ptr++;
+ break;
+ }
+ if (*ptr == CHAR_T)
+ {
+ *xoptset |= PCRE2_EXTRA_ASCII_DIGIT;
+ ptr++;
+ break;
+ }
+ if (*ptr == CHAR_W)
+ {
+ *xoptset |= PCRE2_EXTRA_ASCII_BSW;
+ ptr++;
+ break;
+ }
+ }
+ *xoptset |= PCRE2_EXTRA_ASCII_BSD|PCRE2_EXTRA_ASCII_BSS|
+ PCRE2_EXTRA_ASCII_BSW|
+ PCRE2_EXTRA_ASCII_DIGIT|PCRE2_EXTRA_ASCII_POSIX;
+ break;
+
case CHAR_J: /* Record that it changed in the external options */
*optset |= PCRE2_DUPNAMES;
cb->external_flags |= PCRE2_JCHANGED;
@@ -4082,6 +4289,7 @@ while (ptr < ptrend)
case CHAR_i: *optset |= PCRE2_CASELESS; break;
case CHAR_m: *optset |= PCRE2_MULTILINE; break;
case CHAR_n: *optset |= PCRE2_NO_AUTO_CAPTURE; break;
+ case CHAR_r: *xoptset|= PCRE2_EXTRA_CASELESS_RESTRICT; break;
case CHAR_s: *optset |= PCRE2_DOTALL; break;
case CHAR_U: *optset |= PCRE2_UNGREEDY; break;
@@ -4112,6 +4320,7 @@ while (ptr < ptrend)
unset |= PCRE2_EXTENDED_MORE;
options = (options | set) & (~unset);
+ xoptions = (xoptions | xset) & (~xunset);
/* If the options ended with ')' this is not the start of a nested
group with option changes, so the options change at this level.
@@ -4132,10 +4341,11 @@ while (ptr < ptrend)
/* If nothing changed, no need to record. */
- if (options != oldoptions)
+ if (options != oldoptions || xoptions != oldxoptions)
{
*parsed_pattern++ = META_OPTIONS;
*parsed_pattern++ = options;
+ *parsed_pattern++ = xoptions;
}
} /* End options processing */
break; /* End default case after (? */
@@ -4605,6 +4815,7 @@ while (ptr < ptrend)
top_nest->nest_depth = nest_depth;
top_nest->flags = NSF_CONDASSERT;
top_nest->options = options & PARSE_TRACKED_OPTIONS;
+ top_nest->xoptions = xoptions & PARSE_TRACKED_EXTRA_OPTIONS;
}
break;
@@ -4738,6 +4949,7 @@ while (ptr < ptrend)
if (top_nest != NULL && top_nest->nest_depth == nest_depth)
{
options = (options & ~PARSE_TRACKED_OPTIONS) | top_nest->options;
+ xoptions = (xoptions & ~PARSE_TRACKED_EXTRA_OPTIONS) | top_nest->xoptions;
if ((top_nest->flags & NSF_RESET) != 0 &&
top_nest->max_group > cb->bracount)
cb->bracount = top_nest->max_group;
@@ -4780,12 +4992,12 @@ parsed_pattern = manage_callouts(ptr, &previous_callout, auto_callout,
/* Insert trailing items for word and line matching (features provided for the
benefit of pcre2grep). */
-if ((extra_options & PCRE2_EXTRA_MATCH_LINE) != 0)
+if ((xoptions & PCRE2_EXTRA_MATCH_LINE) != 0)
{
*parsed_pattern++ = META_KET;
*parsed_pattern++ = META_DOLLAR;
}
-else if ((extra_options & PCRE2_EXTRA_MATCH_WORD) != 0)
+else if ((xoptions & PCRE2_EXTRA_MATCH_WORD) != 0)
{
*parsed_pattern++ = META_KET;
*parsed_pattern++ = META_ESCAPE + ESC_b;
@@ -4862,6 +5074,8 @@ for (;;)
case OP_WORD_BOUNDARY:
case OP_NOT_WORD_BOUNDARY:
+ case OP_UCP_WORD_BOUNDARY:
+ case OP_NOT_UCP_WORD_BOUNDARY:
if (!skipassert) return code;
/* Fall through */
@@ -4913,7 +5127,8 @@ for (;;)
* Get othercase range *
*************************************************/
-/* This function is passed the start and end of a class range in UCP mode. It
+/* This function is passed the start and end of a class range in UCP mode. For
+single characters the range may be just one character long. The function
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.
@@ -4923,31 +5138,44 @@ Arguments:
d end value
ocptr where to put start of othercase range
odptr where to put end of othercase range
+ restricted TRUE if caseless restriction applies
Yield: -1 when no more
0 when a range is returned
- >0 the CASESET offset for char with multiple other cases
- in this case, ocptr contains the original
+ >0 the CASESET offset for char with multiple other cases;
+ for this return, *ocptr contains the original
*/
static int
get_othercase_range(uint32_t *cptr, uint32_t d, uint32_t *ocptr,
- uint32_t *odptr)
+ uint32_t *odptr, BOOL restricted)
{
uint32_t c, othercase, next;
unsigned int co;
/* Find the first character that has an other case. If it has multiple other
-cases, return its case offset value. */
+cases, return its case offset value. When CASELESS_RESTRICT is set, ignore the
+multi-case entries that begin with ASCII values. In 32-bit mode, a value
+greater than the Unicode maximum ends the range. */
for (c = *cptr; c <= d; c++)
{
- if ((co = UCD_CASESET(c)) != 0)
+#if PCRE2_CODE_UNIT_WIDTH == 32
+ if (c > MAX_UTF_CODE_POINT) return -1;
+#endif
+ if ((co = UCD_CASESET(c)) != 0 &&
+ (!restricted || PRIV(ucd_caseless_sets)[co] > 127))
{
*ocptr = c++; /* Character that has the set */
*cptr = c; /* Rest of input range */
return (int)co;
}
+
+ /* This is not a valid multiple-case character. Check that the single other
+ case is different to the original. We don't need to check "restricted" here
+ because the non-ASCII characters with multiple cases that include an ASCII
+ character don't have a different "othercase". */
+
if ((othercase = UCD_OTHERCASE(c)) != c) break;
}
@@ -4988,7 +5216,8 @@ add_to_class().
Arguments:
classbits the bit map for characters < 256
uchardptr points to the pointer for extra data
- options the options word
+ options the options bits
+ xoptions the extra options bits
cb compile data
start start of range character
end end of range character
@@ -4999,7 +5228,8 @@ Returns: the number of < 256 characters added
static unsigned int
add_to_class_internal(uint8_t *classbits, PCRE2_UCHAR **uchardptr,
- uint32_t options, compile_block *cb, uint32_t start, uint32_t end)
+ uint32_t options, uint32_t xoptions, compile_block *cb, uint32_t start,
+ uint32_t end)
{
uint32_t c;
uint32_t classbits_end = (end <= 0xff ? end : 0xff);
@@ -5007,8 +5237,8 @@ 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. */
+are greater than 255 and vice-versa (though these may be ignored if caseless
+restriction is in force). Sometimes we can just extend the original range. */
if ((options & PCRE2_CASELESS) != 0)
{
@@ -5021,20 +5251,23 @@ if ((options & PCRE2_CASELESS) != 0)
options &= ~PCRE2_CASELESS; /* Remove for recursive calls */
c = start;
- while ((rc = get_othercase_range(&c, end, &oc, &od)) >= 0)
+ while ((rc = get_othercase_range(&c, end, &oc, &od,
+ (xoptions & PCRE2_EXTRA_CASELESS_RESTRICT) != 0)) >= 0)
{
/* Handle a single character that has more than one other case. */
- if (rc > 0) n8 += add_list_to_class_internal(classbits, uchardptr, options, cb,
- PRIV(ucd_caseless_sets) + rc, oc);
+ if (rc > 0) n8 += add_list_to_class_internal(classbits, uchardptr,
+ options, xoptions, cb, PRIV(ucd_caseless_sets) + rc, oc);
/* Do nothing if the other case range is within the original range. */
- else if (oc >= cb->class_range_start && od <= cb->class_range_end) continue;
+ else if (oc >= cb->class_range_start && od <= cb->class_range_end)
+ continue;
- /* Extend the original range if there is overlap, noting that if oc < c, we
- can't have od > end because a subrange is always shorter than the basic
- range. Otherwise, use a recursive call to add the additional range. */
+ /* Extend the original range if there is overlap, noting that if oc < c,
+ we can't have od > end because a subrange is always shorter than the
+ basic range. Otherwise, use a recursive call to add the additional range.
+ */
else if (oc < start && od >= start - 1) start = oc; /* Extend downwards */
else if (od > end && oc <= end + 1)
@@ -5042,10 +5275,13 @@ if ((options & PCRE2_CASELESS) != 0)
end = od; /* Extend upwards */
if (end > classbits_end) classbits_end = (end <= 0xff ? end : 0xff);
}
- else n8 += add_to_class_internal(classbits, uchardptr, options, cb, oc, od);
+ else n8 += add_to_class_internal(classbits, uchardptr, options, xoptions,
+ cb, oc, od);
}
}
else
+#else
+ (void)xoptions; /* Avoid compiler warning */
#endif /* SUPPORT_UNICODE */
/* Not UTF mode */
@@ -5141,7 +5377,8 @@ add_to_class_internal(), with which it is mutually recursive.
Arguments:
classbits the bit map for characters < 256
uchardptr points to the pointer for extra data
- options the options word
+ options the options bits
+ xoptions the extra options bits
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
@@ -5154,7 +5391,8 @@ Returns: the number of < 256 characters added
static unsigned int
add_list_to_class_internal(uint8_t *classbits, PCRE2_UCHAR **uchardptr,
- uint32_t options, compile_block *cb, const uint32_t *p, unsigned int except)
+ uint32_t options, uint32_t xoptions, compile_block *cb, const uint32_t *p,
+ unsigned int except)
{
unsigned int n8 = 0;
while (p[0] < NOTACHAR)
@@ -5163,7 +5401,8 @@ while (p[0] < NOTACHAR)
if (p[0] != except)
{
while(p[n+1] == p[0] + n + 1) n++;
- n8 += add_to_class_internal(classbits, uchardptr, options, cb, p[0], p[n]);
+ n8 += add_to_class_internal(classbits, uchardptr, options, xoptions, cb,
+ p[0], p[n]);
}
p += n + 1;
}
@@ -5183,7 +5422,8 @@ to avoid duplication when handling case-independence.
Arguments:
classbits the bit map for characters < 256
uchardptr points to the pointer for extra data
- options the options word
+ options the options bits
+ xoptions the extra options bits
cb compile data
start start of range character
end end of range character
@@ -5194,11 +5434,12 @@ Returns: the number of < 256 characters added
static unsigned int
add_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options,
- compile_block *cb, uint32_t start, uint32_t end)
+ uint32_t xoptions, compile_block *cb, uint32_t start, uint32_t end)
{
cb->class_range_start = start;
cb->class_range_end = end;
-return add_to_class_internal(classbits, uchardptr, options, cb, start, end);
+return add_to_class_internal(classbits, uchardptr, options, xoptions, cb,
+ start, end);
}
@@ -5215,7 +5456,8 @@ case-independence.
Arguments:
classbits the bit map for characters < 256
uchardptr points to the pointer for extra data
- options the options word
+ options the options bits
+ xoptions the extra options bits
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
@@ -5228,7 +5470,7 @@ Returns: the number of < 256 characters added
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)
+ uint32_t xoptions, compile_block *cb, const uint32_t *p, unsigned int except)
{
unsigned int n8 = 0;
while (p[0] < NOTACHAR)
@@ -5239,7 +5481,8 @@ while (p[0] < NOTACHAR)
while(p[n+1] == p[0] + n + 1) n++;
cb->class_range_start = p[0];
cb->class_range_end = p[n];
- n8 += add_to_class_internal(classbits, uchardptr, options, cb, p[0], p[n]);
+ n8 += add_to_class_internal(classbits, uchardptr, options, xoptions, cb,
+ p[0], p[n]);
}
p += n + 1;
}
@@ -5258,7 +5501,8 @@ vertical whitespace to a class. The list must be in order.
Arguments:
classbits the bit map for characters < 256
uchardptr points to the pointer for extra data
- options the options word
+ options the options bits
+ xoptions the extra options bits
cb contains pointers to tables etc.
p points to row of 32-bit values, terminated by NOTACHAR
@@ -5268,16 +5512,16 @@ Returns: the number of < 256 characters added
static unsigned int
add_not_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr,
- uint32_t options, compile_block *cb, const uint32_t *p)
+ uint32_t options, uint32_t xoptions, compile_block *cb, const uint32_t *p)
{
BOOL utf = (options & PCRE2_UTF) != 0;
unsigned int n8 = 0;
if (p[0] > 0)
- n8 += add_to_class(classbits, uchardptr, options, cb, 0, p[0] - 1);
+ n8 += add_to_class(classbits, uchardptr, options, xoptions, cb, 0, p[0] - 1);
while (p[0] < NOTACHAR)
{
while (p[1] == p[0] + 1) p++;
- n8 += add_to_class(classbits, uchardptr, options, cb, p[0] + 1,
+ n8 += add_to_class(classbits, uchardptr, options, xoptions, cb, p[0] + 1,
(p[1] == NOTACHAR) ? (utf ? 0x10ffffu : 0xffffffffu) : p[1] - 1);
p++;
}
@@ -5368,6 +5612,7 @@ real compile phase. The value of lengthptr distinguishes the two phases.
Arguments:
optionsptr pointer to the option bits
+ xoptionsptr pointer to the extra option bits
codeptr points to the pointer to the current code point
pptrptr points to the current parsed pattern pointer
errorcodeptr points to error code variable
@@ -5376,6 +5621,7 @@ Arguments:
reqcuptr place to put the last required code unit
reqcuflagsptr place to put the last required code unit flags
bcptr points to current branch chain
+ open_caps points to current capitem
cb contains pointers to tables etc.
lengthptr NULL during the real compile phase
points to length accumulator during pre-compile phase
@@ -5386,9 +5632,10 @@ Returns: 0 There's been an error, *errorcodeptr is non-zero
*/
static int
-compile_branch(uint32_t *optionsptr, PCRE2_UCHAR **codeptr, uint32_t **pptrptr,
- int *errorcodeptr, uint32_t *firstcuptr, uint32_t *firstcuflagsptr,
- uint32_t *reqcuptr, uint32_t *reqcuflagsptr, branch_chain *bcptr,
+compile_branch(uint32_t *optionsptr, uint32_t *xoptionsptr,
+ PCRE2_UCHAR **codeptr, uint32_t **pptrptr, int *errorcodeptr,
+ uint32_t *firstcuptr, uint32_t *firstcuflagsptr, uint32_t *reqcuptr,
+ uint32_t *reqcuflagsptr, branch_chain *bcptr, open_capitem *open_caps,
compile_block *cb, PCRE2_SIZE *lengthptr)
{
int bravalue = 0;
@@ -5398,6 +5645,7 @@ uint32_t repeat_min = 0, repeat_max = 0; /* To please picky compilers */
uint32_t greedy_default, greedy_non_default;
uint32_t repeat_type, op_type;
uint32_t options = *optionsptr; /* May change dynamically */
+uint32_t xoptions = *xoptionsptr; /* May change dynamically */
uint32_t firstcu, reqcu;
uint32_t zeroreqcu, zerofirstcu;
uint32_t escape;
@@ -5423,8 +5671,8 @@ const uint8_t *cbits = cb->cbits;
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. */
+not do this for other options (e.g. PCRE2_EXTENDED) that may change dynamically
+as we process the pattern. */
#ifdef SUPPORT_UNICODE
BOOL utf = (options & PCRE2_UTF) != 0;
@@ -5633,8 +5881,8 @@ for (;; pptr++)
If the class contains characters outside the 0-255 range, a different
opcode is compiled. It may optionally have a bit map for characters < 256,
- but those above are are explicitly listed afterwards. A flag code unit
- tells whether the bitmap is present, and whether this is a negated class or
+ but those above are explicitly listed afterwards. A flag code unit tells
+ whether the bitmap is present, and whether this is a negated class or
not. */
case META_CLASS_NOT:
@@ -5675,11 +5923,14 @@ for (;; pptr++)
/* For caseless UTF or UCP mode, check whether this character has more
than one other case. If so, generate a special OP_NOTPROP item instead of
- OP_NOTI. */
+ OP_NOTI. When restricted by PCRE2_EXTRA_CASELESS_RESTRICT, ignore any
+ caseless set that starts with an ASCII character. */
#ifdef SUPPORT_UNICODE
if ((utf||ucp) && (options & PCRE2_CASELESS) != 0 &&
- (d = UCD_CASESET(c)) != 0)
+ (d = UCD_CASESET(c)) != 0 &&
+ ((xoptions & PCRE2_EXTRA_CASELESS_RESTRICT) == 0 ||
+ PRIV(ucd_caseless_sets)[d] > 127))
{
*code++ = OP_NOTPROP;
*code++ = PT_CLIST;
@@ -5687,7 +5938,7 @@ for (;; pptr++)
break; /* We are finished with this class */
}
#endif
- /* Char has only one other case, or UCP not available */
+ /* Char has only one other (usable) case, or UCP not available */
*code++ = ((options & PCRE2_CASELESS) != 0)? OP_NOTI: OP_NOT;
code += PUTCHAR(c, code);
@@ -5697,7 +5948,9 @@ for (;; pptr++)
/* Handle character classes that contain more than just one literal
character. If there are exactly two characters in a positive class, see if
they are case partners. This can be optimized to generate a caseless single
- character match (which also sets first/required code units if relevant). */
+ character match (which also sets first/required code units if relevant).
+ When casing restrictions apply, ignore a caseless set if both characters
+ are ASCII. */
if (meta == META_CLASS && pptr[1] < META_END && pptr[2] < META_END &&
pptr[3] == META_CLASS_END)
@@ -5705,7 +5958,9 @@ for (;; pptr++)
uint32_t c = pptr[1];
#ifdef SUPPORT_UNICODE
- if (UCD_CASESET(c) == 0)
+ if (UCD_CASESET(c) == 0 ||
+ ((xoptions & PCRE2_EXTRA_CASELESS_RESTRICT) != 0 &&
+ c < 128 && pptr[2] < 128))
#endif
{
uint32_t d;
@@ -5797,41 +6052,45 @@ for (;; pptr++)
XCL_PROP/XCL_NOTPROP directly, which is done here. */
#ifdef SUPPORT_UNICODE
- if ((options & PCRE2_UCP) != 0) switch(posix_class)
+ if ((options & PCRE2_UCP) != 0 &&
+ (xoptions & PCRE2_EXTRA_ASCII_POSIX) == 0)
{
- case PC_GRAPH:
- case PC_PRINT:
- case PC_PUNCT:
- *class_uchardata++ = local_negate? XCL_NOTPROP : XCL_PROP;
- *class_uchardata++ = (PCRE2_UCHAR)
- ((posix_class == PC_GRAPH)? PT_PXGRAPH :
- (posix_class == PC_PRINT)? PT_PXPRINT : PT_PXPUNCT);
- *class_uchardata++ = 0;
- xclass_has_prop = TRUE;
- 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. In the 8-bit library this is relevant only in
- utf mode, since no wide characters can exist otherwise. */
+ switch(posix_class)
+ {
+ case PC_GRAPH:
+ case PC_PRINT:
+ case PC_PUNCT:
+ *class_uchardata++ = local_negate? XCL_NOTPROP : XCL_PROP;
+ *class_uchardata++ = (PCRE2_UCHAR)
+ ((posix_class == PC_GRAPH)? PT_PXGRAPH :
+ (posix_class == PC_PRINT)? PT_PXPRINT : PT_PXPUNCT);
+ *class_uchardata++ = 0;
+ xclass_has_prop = TRUE;
+ goto CONTINUE_CLASS;
+
+ /* For the other POSIX classes (ex: ascii) 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 [^[:^ascii:]...
+ 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. In the 8-bit library this is relevant only in
+ utf mode, since no wide characters can exist otherwise. */
- default:
+ default:
#if PCRE2_CODE_UNIT_WIDTH == 8
- if (utf)
+ if (utf)
#endif
- match_all_or_no_wide_chars |= local_negate;
- break;
+ match_all_or_no_wide_chars |= local_negate;
+ break;
+ }
}
#endif /* SUPPORT_UNICODE */
@@ -5957,22 +6216,24 @@ for (;; pptr++)
case ESC_h:
(void)add_list_to_class(classbits, &class_uchardata,
- options & ~PCRE2_CASELESS, cb, PRIV(hspace_list), NOTACHAR);
+ options & ~PCRE2_CASELESS, xoptions, cb, PRIV(hspace_list),
+ NOTACHAR);
break;
case ESC_H:
(void)add_not_list_to_class(classbits, &class_uchardata,
- options & ~PCRE2_CASELESS, cb, PRIV(hspace_list));
+ options & ~PCRE2_CASELESS, xoptions, cb, PRIV(hspace_list));
break;
case ESC_v:
(void)add_list_to_class(classbits, &class_uchardata,
- options & ~PCRE2_CASELESS, cb, PRIV(vspace_list), NOTACHAR);
+ options & ~PCRE2_CASELESS, xoptions, cb, PRIV(vspace_list),
+ NOTACHAR);
break;
case ESC_V:
(void)add_not_list_to_class(classbits, &class_uchardata,
- options & ~PCRE2_CASELESS, cb, PRIV(vspace_list));
+ options & ~PCRE2_CASELESS, xoptions, cb, PRIV(vspace_list));
break;
/* If Unicode is not supported, \P and \p are not allowed and are
@@ -6046,32 +6307,32 @@ for (;; pptr++)
if (C <= CHAR_i)
{
class_has_8bitchar +=
- add_to_class(classbits, &class_uchardata, options, cb, C + uc,
- ((D < CHAR_i)? D : CHAR_i) + uc);
+ add_to_class(classbits, &class_uchardata, options, xoptions,
+ cb, C + uc, ((D < CHAR_i)? D : CHAR_i) + uc);
C = CHAR_j;
}
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);
+ add_to_class(classbits, &class_uchardata, options, xoptions,
+ 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);
+ add_to_class(classbits, &class_uchardata, options, xoptions,
+ cb, C + uc, D + uc);
}
}
else
#endif
/* Not an EBCDIC special range */
- class_has_8bitchar +=
- add_to_class(classbits, &class_uchardata, options, cb, c, d);
+ class_has_8bitchar += add_to_class(classbits, &class_uchardata,
+ options, xoptions, cb, c, d);
goto CONTINUE_CLASS; /* Go get the next char in the class */
} /* End of range handling */
@@ -6079,7 +6340,8 @@ for (;; pptr++)
/* Handle a single character. */
class_has_8bitchar +=
- add_to_class(classbits, &class_uchardata, options, cb, meta, meta);
+ add_to_class(classbits, &class_uchardata, options, xoptions, cb,
+ meta, meta);
}
/* Continue to the next item in the class. */
@@ -6124,11 +6386,11 @@ for (;; pptr++)
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.
+ In the UCP case, if certain negated POSIX classes (ex: [:^ascii:]) were
+ 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.
This applies only in UTF and 16-bit and 32-bit non-UTF modes, since there
cannot be any wide characters in 8-bit non-UTF mode.
@@ -6232,7 +6494,7 @@ for (;; pptr++)
case META_ACCEPT:
cb->had_accept = had_accept = TRUE;
- for (oc = cb->open_caps;
+ for (oc = open_caps;
oc != NULL && oc->assert_depth >= cb->assert_depth;
oc = oc->next)
{
@@ -6317,6 +6579,7 @@ for (;; pptr++)
case META_OPTIONS:
*optionsptr = options = *(++pptr);
+ *xoptionsptr = xoptions = *(++pptr);
greedy_default = ((options & PCRE2_UNGREEDY) != 0);
greedy_non_default = greedy_default ^ 1;
req_caseopt = ((options & PCRE2_CASELESS) != 0)? REQ_CASELESS : 0;
@@ -6562,7 +6825,8 @@ for (;; pptr++)
if ((group_return =
compile_regex(
- options, /* The option state */
+ options, /* The options state */
+ xoptions, /* The extra options state */
&tempcode, /* Where to put code (updated) */
&pptr, /* Input pointer (updated) */
errorcodeptr, /* Where to put an error message */
@@ -6572,6 +6836,7 @@ for (;; pptr++)
&subreqcu, /* For possible last char */
&subreqcuflags,
bcptr, /* Current branch chain */
+ open_caps, /* Pointer to capture stack */
cb, /* Compile data block */
(lengthptr == NULL)? NULL : /* Actual compile phase */
&length_prevgroup /* Pre-compile phase */
@@ -7112,15 +7377,12 @@ for (;; pptr++)
/* In the pre-compile phase, we don't actually do the replication. We
just adjust the length as if we had. Do some paranoid checks for
- potential integer overflow. The INT64_OR_DOUBLE type is a 64-bit
- integer type when available, otherwise double. */
+ potential integer overflow. */
if (lengthptr != NULL)
{
- PCRE2_SIZE delta = replicate*(1 + LINK_SIZE);
- if ((INT64_OR_DOUBLE)replicate*
- (INT64_OR_DOUBLE)(1 + LINK_SIZE) >
- (INT64_OR_DOUBLE)INT_MAX ||
+ PCRE2_SIZE delta;
+ if (PRIV(ckd_smul)(&delta, replicate, 1 + LINK_SIZE) ||
OFLOW_MAX - *lengthptr < delta)
{
*errorcodeptr = ERR20;
@@ -7282,15 +7544,12 @@ for (;; pptr++)
{
/* In the pre-compile phase, we don't actually do the replication.
We just adjust the length as if we had. Do some paranoid checks for
- potential integer overflow. The INT64_OR_DOUBLE type is a 64-bit
- integer type when available, otherwise double. */
+ potential integer overflow. */
if (lengthptr != NULL)
{
- PCRE2_SIZE delta = (repeat_min - 1)*length_prevgroup;
- if ((INT64_OR_DOUBLE)(repeat_min - 1)*
- (INT64_OR_DOUBLE)length_prevgroup >
- (INT64_OR_DOUBLE)INT_MAX ||
+ PCRE2_SIZE delta;
+ if (PRIV(ckd_smul)(&delta, repeat_min - 1, length_prevgroup) ||
OFLOW_MAX - *lengthptr < delta)
{
*errorcodeptr = ERR20;
@@ -7334,21 +7593,19 @@ for (;; pptr++)
just adjust the length as if we had. For each repetition we must add
1 to the length for BRAZERO and for all but the last repetition we
must add 2 + 2*LINKSIZE to allow for the nesting that occurs. Do some
- paranoid checks to avoid integer overflow. The INT64_OR_DOUBLE type
- is a 64-bit integer type when available, otherwise double. */
+ paranoid checks to avoid integer overflow. */
if (lengthptr != NULL && repeat_max > 0)
{
- PCRE2_SIZE 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)
- > (INT64_OR_DOUBLE)INT_MAX ||
- OFLOW_MAX - *lengthptr < delta)
+ PCRE2_SIZE delta;
+ if (PRIV(ckd_smul)(&delta, repeat_max,
+ length_prevgroup + 1 + 2 + 2*LINK_SIZE) ||
+ OFLOW_MAX + (2 + 2*LINK_SIZE) - *lengthptr < delta)
{
*errorcodeptr = ERR20;
return 0;
}
+ delta -= (2 + 2*LINK_SIZE); /* Last one doesn't nest */
*lengthptr += delta;
}
@@ -7901,7 +8158,7 @@ for (;; pptr++)
done. However, there's an option, in case anyone was relying on it. */
if (cb->assert_depth > 0 && meta_arg == ESC_K &&
- (cb->cx->extra_options & PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK) == 0)
+ (xoptions & PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK) == 0)
{
*errorcodeptr = ERR99;
return 0;
@@ -7909,23 +8166,41 @@ for (;; pptr++)
/* For the rest (including \X when Unicode is supported - if not it's
faulted at parse time), the OP value is the escape value when PCRE2_UCP is
- not set; if it is set, these escapes do not show up here because they are
- converted into Unicode property tests in parse_regex(). Note that \b and \B
- do a one-character lookbehind, and \A also behaves as if it does. */
+ not set; if it is set, most of them do not show up here because they are
+ converted into Unicode property tests in parse_regex().
- if (meta_arg == ESC_C) cb->external_flags |= PCRE2_HASBKC; /* Record */
- if ((meta_arg == ESC_b || meta_arg == ESC_B || meta_arg == ESC_A) &&
- cb->max_lookbehind == 0)
- cb->max_lookbehind = 1;
+ 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.
+ There are special UCP codes for \B and \b which are used in UCP mode unless
+ "word" matching is being forced to ASCII.
- /* 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. */
+ Note that \b and \B do a one-character lookbehind, and \A also behaves as
+ if it does. */
+ switch(meta_arg)
+ {
+ case ESC_C:
+ cb->external_flags |= PCRE2_HASBKC; /* Record */
#if PCRE2_CODE_UNIT_WIDTH == 32
- *code++ = (meta_arg == ESC_C)? OP_ALLANY : meta_arg;
+ meta_arg = OP_ALLANY;
#else
- *code++ = (!utf && meta_arg == ESC_C)? OP_ALLANY : meta_arg;
+ if (!utf) meta_arg = OP_ALLANY;
#endif
+ break;
+
+ case ESC_B:
+ case ESC_b:
+ if ((options & PCRE2_UCP) != 0 && (xoptions & PCRE2_EXTRA_ASCII_BSW) == 0)
+ meta_arg = (meta_arg == ESC_B)? OP_NOT_UCP_WORD_BOUNDARY :
+ OP_UCP_WORD_BOUNDARY;
+ /* Fall through */
+
+ case ESC_A:
+ if (cb->max_lookbehind == 0) cb->max_lookbehind = 1;
+ break;
+ }
+
+ *code++ = meta_arg;
break; /* End META_ESCAPE */
@@ -7953,13 +8228,16 @@ for (;; pptr++)
/* For caseless UTF or UCP mode, check whether this character has more than
one other case. If so, generate a special OP_PROP item instead of OP_CHARI.
- */
+ When casing restrictions apply, ignore caseless sets that start with an
+ ASCII character. */
#ifdef SUPPORT_UNICODE
if ((utf||ucp) && (options & PCRE2_CASELESS) != 0)
{
uint32_t caseset = UCD_CASESET(meta);
- if (caseset != 0)
+ if (caseset != 0 &&
+ ((xoptions & PCRE2_EXTRA_CASELESS_RESTRICT) == 0 ||
+ PRIV(ucd_caseless_sets)[caseset] > 127))
{
*code++ = OP_PROP;
*code++ = PT_CLIST;
@@ -8075,6 +8353,7 @@ the two phases.
Arguments:
options option bits, including any changes for this subpattern
+ xoptions extra option bits, ditto
codeptr -> the address of the current code pointer
pptrptr -> the address of the current parsed pattern pointer
errorcodeptr -> pointer to error code variable
@@ -8094,10 +8373,11 @@ Returns: 0 There has been an error
*/
static int
-compile_regex(uint32_t options, PCRE2_UCHAR **codeptr, uint32_t **pptrptr,
- int *errorcodeptr, uint32_t skipunits, uint32_t *firstcuptr,
- uint32_t *firstcuflagsptr, uint32_t *reqcuptr, uint32_t *reqcuflagsptr,
- branch_chain *bcptr, compile_block *cb, PCRE2_SIZE *lengthptr)
+compile_regex(uint32_t options, uint32_t xoptions, PCRE2_UCHAR **codeptr,
+ uint32_t **pptrptr, int *errorcodeptr, uint32_t skipunits,
+ uint32_t *firstcuptr, uint32_t *firstcuflagsptr, uint32_t *reqcuptr,
+ uint32_t *reqcuflagsptr, branch_chain *bcptr, open_capitem *open_caps,
+ compile_block *cb, PCRE2_SIZE *lengthptr)
{
PCRE2_UCHAR *code = *codeptr;
PCRE2_UCHAR *last_branch = code;
@@ -8109,6 +8389,7 @@ int okreturn = 1;
uint32_t *pptr = *pptrptr;
uint32_t firstcu, reqcu;
uint32_t lookbehindlength;
+uint32_t lookbehindminlength;
uint32_t firstcuflags, reqcuflags;
uint32_t branchfirstcu, branchreqcu;
uint32_t branchfirstcuflags, branchreqcuflags;
@@ -8151,9 +8432,10 @@ lookbehind = *code == OP_ASSERTBACK ||
if (lookbehind)
{
lookbehindlength = META_DATA(pptr[-1]);
+ lookbehindminlength = *pptr;
pptr += SIZEOFFSET;
}
-else lookbehindlength = 0;
+else lookbehindlength = lookbehindminlength = 0;
/* If this is a capturing subpattern, add to the chain of open capturing items
so that we can detect them if (*ACCEPT) is encountered. Note that only OP_CBRA
@@ -8164,9 +8446,9 @@ if (*code == OP_CBRA)
{
capnumber = GET2(code, 1 + LINK_SIZE);
capitem.number = capnumber;
- capitem.next = cb->open_caps;
+ capitem.next = open_caps;
capitem.assert_depth = cb->assert_depth;
- cb->open_caps = &capitem;
+ open_caps = &capitem;
}
/* Offset is set zero to mark that this bracket is still open */
@@ -8180,22 +8462,39 @@ for (;;)
{
int branch_return;
- /* Insert OP_REVERSE if this is as lookbehind assertion. */
+ /* Insert OP_REVERSE or OP_VREVERSE if this is a lookbehind assertion. There
+ is only a single mimimum length for the whole assertion. When the mimimum
+ length is LOOKBEHIND_MAX it means that all branches are of fixed length,
+ though not necessarily the same length. In this case, the original OP_REVERSE
+ can be used. It can also be used if a branch in a variable length lookbehind
+ has the same maximum and minimum. Otherwise, use OP_VREVERSE, which has both
+ maximum and minimum values. */
if (lookbehind && lookbehindlength > 0)
{
- *code++ = OP_REVERSE;
- PUTINC(code, 0, lookbehindlength);
- length += 1 + LINK_SIZE;
+ if (lookbehindminlength == LOOKBEHIND_MAX ||
+ lookbehindminlength == lookbehindlength)
+ {
+ *code++ = OP_REVERSE;
+ PUT2INC(code, 0, lookbehindlength);
+ length += 1 + IMM2_SIZE;
+ }
+ else
+ {
+ *code++ = OP_VREVERSE;
+ PUT2INC(code, 0, lookbehindminlength);
+ PUT2INC(code, 0, lookbehindlength);
+ length += 1 + 2*IMM2_SIZE;
+ }
}
/* Now compile the branch; in the pre-compile phase its length gets added
into the length. */
if ((branch_return =
- compile_branch(&options, &code, &pptr, errorcodeptr, &branchfirstcu,
- &branchfirstcuflags, &branchreqcu, &branchreqcuflags, &bc,
- cb, (lengthptr == NULL)? NULL : &length)) == 0)
+ compile_branch(&options, &xoptions, &code, &pptr, errorcodeptr,
+ &branchfirstcu, &branchfirstcuflags, &branchreqcu, &branchreqcuflags,
+ &bc, open_caps, cb, (lengthptr == NULL)? NULL : &length)) == 0)
return 0;
/* If a branch can match an empty string, so can the whole group. */
@@ -8293,10 +8592,6 @@ for (;;)
PUT(code, 1, (int)(code - start_bracket));
code += 1 + LINK_SIZE;
- /* If it was a capturing subpattern, remove the block from the chain. */
-
- if (capnumber > 0) cb->open_caps = cb->open_caps->next;
-
/* Set values to pass back */
*codeptr = code;
@@ -8339,8 +8634,8 @@ for (;;)
code += 1 + LINK_SIZE;
}
- /* Set the lookbehind length (if not in a lookbehind the value will be zero)
- and then advance past the vertical bar. */
+ /* Set the maximum lookbehind length for the next branch (if not in a
+ lookbehind the value will be zero) and then advance past the vertical bar. */
lookbehindlength = META_DATA(*pptr);
pptr++;
@@ -9051,13 +9346,13 @@ return pptr;
*************************************************/
/* This is called for nested groups within a branch of a lookbehind whose
-length is being computed. If all the branches in the nested group have the same
-length, that is OK. On entry, the pointer must be at the first element after
-the group initializing code. On exit it points to OP_KET. Caching is used to
-improve processing speed when the same capturing group occurs many times.
+length is being computed. On entry, the pointer must be at the first element
+after the group initializing code. On exit it points to OP_KET. Caching is used
+to improve processing speed when the same capturing group occurs many times.
Arguments:
pptrptr pointer to pointer in the parsed pattern
+ minptr where to return the minimum length
isinline FALSE if a reference or recursion; TRUE for inline group
errcodeptr pointer to the errorcode
lcptr pointer to the loop counter
@@ -9065,15 +9360,17 @@ Arguments:
recurses chain of recurse_check to catch mutual recursion
cb pointer to the compile data
-Returns: the group length or a negative number
+Returns: the maximum group length or a negative number
*/
static int
-get_grouplength(uint32_t **pptrptr, BOOL isinline, int *errcodeptr, int *lcptr,
- int group, parsed_recurse_check *recurses, compile_block *cb)
+get_grouplength(uint32_t **pptrptr, int *minptr, BOOL isinline, int *errcodeptr,
+ int *lcptr, int group, parsed_recurse_check *recurses, compile_block *cb)
{
-int branchlength;
+uint32_t *gi = cb->groupinfo + 2 * group;
+int branchlength, branchminlength;
int grouplength = -1;
+int groupminlength = INT_MAX;
/* The cache can be used only if there is no possibility of there being two
groups with the same number. We do not need to set the end pointer for a group
@@ -9082,11 +9379,12 @@ an inline group. */
if (group > 0 && (cb->external_flags & PCRE2_DUPCAPUSED) == 0)
{
- uint32_t groupinfo = cb->groupinfo[group];
+ uint32_t groupinfo = gi[0];
if ((groupinfo & GI_NOT_FIXED_LENGTH) != 0) return -1;
if ((groupinfo & GI_SET_FIXED_LENGTH) != 0)
{
if (isinline) *pptrptr = parsed_skip(*pptrptr, PSKIP_KET);
+ *minptr = gi[1];
return groupinfo & GI_FIXED_LENGTH_MASK;
}
}
@@ -9095,20 +9393,26 @@ if (group > 0 && (cb->external_flags & PCRE2_DUPCAPUSED) == 0)
for(;;)
{
- branchlength = get_branchlength(pptrptr, errcodeptr, lcptr, recurses, cb);
+ branchlength = get_branchlength(pptrptr, &branchminlength, errcodeptr, lcptr,
+ recurses, cb);
if (branchlength < 0) goto ISNOTFIXED;
- if (grouplength == -1) grouplength = branchlength;
- else if (grouplength != branchlength) goto ISNOTFIXED;
+ if (branchlength > grouplength) grouplength = branchlength;
+ if (branchminlength < groupminlength) groupminlength = branchminlength;
if (**pptrptr == META_KET) break;
*pptrptr += 1; /* Skip META_ALT */
}
if (group > 0)
- cb->groupinfo[group] |= (uint32_t)(GI_SET_FIXED_LENGTH | grouplength);
+ {
+ gi[0] |= (uint32_t)(GI_SET_FIXED_LENGTH | grouplength);
+ gi[1] = groupminlength;
+ }
+
+*minptr = groupminlength;
return grouplength;
ISNOTFIXED:
-if (group > 0) cb->groupinfo[group] |= GI_NOT_FIXED_LENGTH;
+if (group > 0) gi[0] |= GI_NOT_FIXED_LENGTH;
return -1;
}
@@ -9118,27 +9422,30 @@ return -1;
* Find length of a parsed branch *
*************************************************/
-/* Return a fixed length for a branch in a lookbehind, giving an error if the
-length is not fixed. On entry, *pptrptr points to the first element inside the
-branch. On exit it is set to point to the ALT or KET.
+/* Return fixed maximum and minimum lengths for a branch in a lookbehind,
+giving an error if the length is not limited. On entry, *pptrptr points to the
+first element inside the branch. On exit it is set to point to the ALT or KET.
Arguments:
pptrptr pointer to pointer in the parsed pattern
+ minptr where to return the minimum length
errcodeptr pointer to error code
lcptr pointer to loop counter
recurses chain of recurse_check to catch mutual recursion
cb pointer to compile block
-Returns: the length, or a negative value on error
+Returns: the maximum length, or a negative value on error
*/
static int
-get_branchlength(uint32_t **pptrptr, int *errcodeptr, int *lcptr,
+get_branchlength(uint32_t **pptrptr, int *minptr, int *errcodeptr, int *lcptr,
parsed_recurse_check *recurses, compile_block *cb)
{
int branchlength = 0;
-int grouplength;
+int branchminlength = 0;
+int grouplength, groupminlength;
uint32_t lastitemlength = 0;
+uint32_t lastitemminlength = 0;
uint32_t *pptr = *pptrptr;
PCRE2_SIZE offset;
parsed_recurse_check this_recurse;
@@ -9162,10 +9469,12 @@ for (;; pptr++)
uint32_t escape;
uint32_t group = 0;
uint32_t itemlength = 0;
+ uint32_t itemminlength = 0;
+ uint32_t min, max;
if (*pptr < META_END)
{
- itemlength = 1;
+ itemlength = itemminlength = 1;
}
else switch (META_CODE(*pptr))
@@ -9200,24 +9509,24 @@ for (;; pptr++)
break;
case META_OPTIONS:
- pptr += 1;
+ pptr += 2;
break;
case META_BIGVALUE:
- itemlength = 1;
+ itemlength = itemminlength = 1;
pptr += 1;
break;
case META_CLASS:
case META_CLASS_NOT:
- itemlength = 1;
+ itemlength = itemminlength = 1;
pptr = parsed_skip(pptr, PSKIP_CLASS);
if (pptr == NULL) goto PARSED_SKIP_FAILED;
break;
case META_CLASS_EMPTY_NOT:
case META_DOT:
- itemlength = 1;
+ itemlength = itemminlength = 1;
break;
case META_CALLOUT_NUMBER:
@@ -9228,14 +9537,19 @@ for (;; pptr++)
pptr += 3 + SIZEOFFSET;
break;
- /* Only some escapes consume a character. Of those, \R and \X are never
- allowed because they might match more than character. \C is allowed only in
- 32-bit and non-UTF 8/16-bit modes. */
+ /* Only some escapes consume a character. Of those, \R can match one or two
+ characters, but \X is never allowed because it matches an unknown number of
+ characters. \C is allowed only in 32-bit and non-UTF 8/16-bit modes. */
case META_ESCAPE:
escape = META_DATA(*pptr);
- if (escape == ESC_R || escape == ESC_X) return -1;
- if (escape > ESC_b && escape < ESC_Z)
+ if (escape == ESC_X) return -1;
+ if (escape == ESC_R)
+ {
+ itemminlength = 1;
+ itemlength = 2;
+ }
+ else if (escape > ESC_b && escape < ESC_Z)
{
#if PCRE2_CODE_UNIT_WIDTH != 32
if ((cb->external_options & PCRE2_UTF) != 0 && escape == ESC_C)
@@ -9244,7 +9558,7 @@ for (;; pptr++)
return -1;
}
#endif
- itemlength = 1;
+ itemlength = itemminlength = 1;
if (escape == ESC_p || escape == ESC_P) pptr++; /* Skip prop data */
}
break;
@@ -9400,14 +9714,15 @@ for (;; pptr++)
in the cache. */
gptr++;
- grouplength = get_grouplength(&gptr, FALSE, errcodeptr, lcptr, group,
- &this_recurse, cb);
+ grouplength = get_grouplength(&gptr, &groupminlength, FALSE, errcodeptr,
+ lcptr, group, &this_recurse, cb);
if (grouplength < 0)
{
if (*errcodeptr == 0) goto ISNOTFIXED;
return -1; /* Error already set */
}
itemlength = grouplength;
+ itemminlength = groupminlength;
break;
/* A (DEFINE) group is never obeyed inline and so it does not contribute to
@@ -9445,41 +9760,44 @@ for (;; pptr++)
case META_SCRIPT_RUN:
pptr++;
CHECK_GROUP:
- grouplength = get_grouplength(&pptr, TRUE, errcodeptr, lcptr, group,
- recurses, cb);
+ grouplength = get_grouplength(&pptr, &groupminlength, TRUE, errcodeptr,
+ lcptr, group, recurses, cb);
if (grouplength < 0) return -1;
itemlength = grouplength;
+ itemminlength = groupminlength;
break;
+ case META_QUERY:
+ case META_QUERY_PLUS:
+ case META_QUERY_QUERY:
+ min = 0;
+ max = 1;
+ goto REPETITION;
+
/* Exact repetition is OK; variable repetition is not. A repetition of zero
must subtract the length that has already been added. */
case META_MINMAX:
case META_MINMAX_PLUS:
case META_MINMAX_QUERY:
- if (pptr[1] == pptr[2])
+ min = pptr[1];
+ max = pptr[2];
+ pptr += 2;
+
+ REPETITION:
+ if (max != REPEAT_UNLIMITED)
{
- switch(pptr[1])
+ if (lastitemlength != 0 && /* Should not occur, but just in case */
+ max != 0 &&
+ (INT_MAX - branchlength)/lastitemlength < max - 1)
{
- case 0:
- branchlength -= lastitemlength;
- break;
-
- case 1:
- itemlength = 0;
- break;
-
- default: /* Check for integer overflow */
- if (lastitemlength != 0 && /* Should not occur, but just in case */
- INT_MAX/lastitemlength < pptr[1] - 1)
- {
- *errcodeptr = ERR87; /* Integer overflow; lookbehind too big */
- return -1;
- }
- itemlength = (pptr[1] - 1) * lastitemlength;
- break;
+ *errcodeptr = ERR87; /* Integer overflow; lookbehind too big */
+ return -1;
}
- pptr += 2;
+ if (min == 0) branchminlength -= lastitemminlength;
+ else itemminlength = (min - 1) * lastitemminlength;
+ if (max == 0) branchlength -= lastitemlength;
+ else itemlength = (max - 1) * lastitemlength;
break;
}
/* Fall through */
@@ -9493,7 +9811,9 @@ for (;; pptr++)
}
/* Add the item length to the branchlength, checking for integer overflow and
- for the branch length exceeding the limit. */
+ for the branch length exceeding the overall limit. Later, if there is at
+ least one variable-length branch in the group, there is a test for the
+ (smaller) variable-length branch length limit. */
if (INT_MAX - branchlength < (int)itemlength ||
(branchlength += itemlength) > LOOKBEHIND_MAX)
@@ -9502,13 +9822,17 @@ for (;; pptr++)
return -1;
}
+ branchminlength += itemminlength;
+
/* Save this item length for use if the next item is a quantifier. */
lastitemlength = itemlength;
+ lastitemminlength = itemminlength;
}
EXIT:
*pptrptr = pptr;
+*minptr = branchminlength;
return branchlength;
PARSED_SKIP_FAILED:
@@ -9523,9 +9847,9 @@ return -1;
*************************************************/
/* This function is called for each lookbehind, to set the lengths in its
-branches. An error occurs if any branch does not have a fixed length that is
-less than the maximum (65535). On exit, the pointer must be left on the final
-ket.
+branches. An error occurs if any branch does not have a limited maximum length
+that is less than the limit (65535). On exit, the pointer must be left on the
+final ket.
The function also maintains the max_lookbehind value. Any lookbehind branch
that contains a nested lookbehind may actually look further back than the
@@ -9548,16 +9872,27 @@ set_lookbehind_lengths(uint32_t **pptrptr, int *errcodeptr, int *lcptr,
parsed_recurse_check *recurses, compile_block *cb)
{
PCRE2_SIZE offset;
-int branchlength;
uint32_t *bptr = *pptrptr;
+uint32_t *gbptr = bptr;
+int maxlength = 0;
+int minlength = INT_MAX;
+BOOL variable = FALSE;
READPLUSOFFSET(offset, bptr); /* Offset for error messages */
*pptrptr += SIZEOFFSET;
+/* Each branch can have a different maximum length, but we can keep only a
+single minimum for the whole group, because there's nowhere to save individual
+values in the META_ALT item. */
+
do
{
+ int branchlength, branchminlength;
+
*pptrptr += 1;
- branchlength = get_branchlength(pptrptr, errcodeptr, lcptr, recurses, cb);
+ branchlength = get_branchlength(pptrptr, &branchminlength, errcodeptr, lcptr,
+ recurses, cb);
+
if (branchlength < 0)
{
/* The errorcode and offset may already be set from a nested lookbehind. */
@@ -9565,12 +9900,37 @@ do
if (cb->erroroffset == PCRE2_UNSET) cb->erroroffset = offset;
return FALSE;
}
+
+ if (branchlength != branchminlength) variable = TRUE;
+ if (branchminlength < minlength) minlength = branchminlength;
+ if (branchlength > maxlength) maxlength = branchlength;
if (branchlength > cb->max_lookbehind) cb->max_lookbehind = branchlength;
*bptr |= branchlength; /* branchlength never more than 65535 */
bptr = *pptrptr;
}
while (*bptr == META_ALT);
+/* If any branch is of variable length, the whole lookbehind is of variable
+length. If the maximum length of any branch exceeds the maximum for variable
+lookbehinds, give an error. Otherwise, the minimum length is set in the word
+that follows the original group META value. For a fixed-length lookbehind, this
+is set to LOOKBEHIND_MAX, to indicate that each branch is of a fixed (but
+possibly different) length. */
+
+if (variable)
+ {
+ gbptr[1] = minlength;
+ if ((uint32_t)maxlength > cb->max_varlookbehind)
+ {
+ *errcodeptr = ERR100;
+ cb->erroroffset = offset;
+ return FALSE;
+ }
+ }
+else gbptr[1] = LOOKBEHIND_MAX;
+
+
+gbptr[1] = variable? minlength : LOOKBEHIND_MAX;
return TRUE;
}
@@ -9703,7 +10063,6 @@ for (; *pptr != META_END; pptr++)
break;
case META_BIGVALUE:
- case META_OPTIONS:
case META_POSIX:
case META_POSIX_NEG:
pptr += 1;
@@ -9712,6 +10071,7 @@ for (; *pptr != META_END; pptr++)
case META_MINMAX:
case META_MINMAX_QUERY:
case META_MINMAX_PLUS:
+ case META_OPTIONS:
pptr += 2;
break;
@@ -9820,12 +10180,15 @@ if (errorptr == NULL || erroroffset == NULL) return NULL;
*errorptr = ERR0;
*erroroffset = 0;
-/* There must be a pattern! */
+/* There must be a pattern, but NULL is allowed with zero length. */
if (pattern == NULL)
{
- *errorptr = ERR16;
- return NULL;
+ if (patlen == 0) pattern = (PCRE2_SPTR)""; else
+ {
+ *errorptr = ERR16;
+ return NULL;
+ }
}
/* A NULL compile context means "use a default context" */
@@ -9890,13 +10253,13 @@ cb.external_options = options;
cb.groupinfo = stack_groupinfo;
cb.had_recurse = FALSE;
cb.lastcapture = 0;
-cb.max_lookbehind = 0;
+cb.max_lookbehind = 0; /* Max encountered */
+cb.max_varlookbehind = ccontext->max_varlookbehind; /* Limit */
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.parsed_pattern = stack_parsed_pattern;
cb.req_varyopt = 0;
@@ -9949,7 +10312,7 @@ if ((options & PCRE2_LITERAL) == 0)
for (i = 0; i < sizeof(pso_list)/sizeof(pso); i++)
{
uint32_t c, pp;
- pso *p = pso_list + i;
+ const pso *p = pso_list + i;
if (patlen - skipatstart - 2 >= p->length &&
PRIV(strncmp_c8)(ptr + skipatstart + 2, (char *)(p->name),
@@ -10158,39 +10521,36 @@ cb.parsed_pattern_end = cb.parsed_pattern + parsed_size_needed + 1;
errorcode = parse_regex(ptr, cb.external_options, &has_lookbehind, &cb);
if (errorcode != 0) goto HAD_CB_ERROR;
-/* 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, the default vector on the stack, as set up above,
-can be used. Otherwise we have to get/free a special vector. The vector must be
-initialized to zero. */
-
-if (cb.bracount >= GROUPINFO_DEFAULT_SIZE)
- {
- cb.groupinfo = ccontext->memctl.malloc(
- (cb.bracount + 1)*sizeof(uint32_t), ccontext->memctl.memory_data);
- if (cb.groupinfo == NULL)
- {
- errorcode = ERR21;
- cb.erroroffset = 0;
- goto HAD_CB_ERROR;
- }
- }
-memset(cb.groupinfo, 0, (cb.bracount + 1) * sizeof(uint32_t));
-
-/* If there were any lookbehinds, scan the parsed pattern to figure out their
-lengths. */
+/* If there are any lookbehinds, scan the parsed pattern to figure out their
+lengths. Workspace is needed to remember whether numbered groups are or are not
+of limited length, and if limited, what the minimum and maximum lengths are.
+This caching saves re-computing the length of any group that is referenced more
+than once, which is particularly relevant when recursion is involved.
+Unnumbered groups do not have this exposure because they cannot be referenced.
+If there are sufficiently few groups, the default index vector on the stack, as
+set up above, can be used. Otherwise we have to get/free some heap memory. The
+vector must be initialized to zero. */
if (has_lookbehind)
{
int loopcount = 0;
+ if (cb.bracount >= GROUPINFO_DEFAULT_SIZE/2)
+ {
+ cb.groupinfo = ccontext->memctl.malloc(
+ (2 * (cb.bracount + 1))*sizeof(uint32_t), ccontext->memctl.memory_data);
+ if (cb.groupinfo == NULL)
+ {
+ errorcode = ERR21;
+ cb.erroroffset = 0;
+ goto HAD_CB_ERROR;
+ }
+ }
+ memset(cb.groupinfo, 0, (2 * cb.bracount + 1) * sizeof(uint32_t));
errorcode = check_lookbehinds(cb.parsed_pattern, NULL, NULL, &cb, &loopcount);
if (errorcode != 0) goto HAD_CB_ERROR;
}
-/* For debugging, there is a function that shows the parsed data vector. */
+/* For debugging, there is a function that shows the parsed pattern vector. */
#ifdef DEBUG_SHOW_PARSED
fprintf(stderr, "+++ Pre-scan complete:\n");
@@ -10227,8 +10587,9 @@ pptr = cb.parsed_pattern;
code = cworkspace;
*code = OP_BRA;
-(void)compile_regex(cb.external_options, &code, &pptr, &errorcode, 0, &firstcu,
- &firstcuflags, &reqcu, &reqcuflags, NULL, &cb, &length);
+(void)compile_regex(cb.external_options, ccontext->extra_options, &code, &pptr,
+ &errorcode, 0, &firstcu, &firstcuflags, &reqcu, &reqcuflags, NULL, NULL,
+ &cb, &length);
if (errorcode != 0) goto HAD_CB_ERROR; /* Offset is in cb.erroroffset */
@@ -10306,7 +10667,6 @@ cb.start_code = codestart;
cb.req_varyopt = 0;
cb.had_accept = FALSE;
cb.had_pruneorskip = FALSE;
-cb.open_caps = NULL;
/* If any named groups were found, create the name/number table from the list
created in the pre-pass. */
@@ -10325,8 +10685,9 @@ of the function here. */
pptr = cb.parsed_pattern;
code = (PCRE2_UCHAR *)codestart;
*code = OP_BRA;
-regexrc = compile_regex(re->overall_options, &code, &pptr, &errorcode, 0,
- &firstcu, &firstcuflags, &reqcu, &reqcuflags, NULL, &cb, NULL);
+regexrc = compile_regex(re->overall_options, ccontext->extra_options, &code,
+ &pptr, &errorcode, 0, &firstcu, &firstcuflags, &reqcu, &reqcuflags, NULL,
+ NULL, &cb, NULL);
if (regexrc < 0) re->flags |= PCRE2_MATCH_EMPTY;
re->top_bracket = cb.bracount;
re->top_backref = cb.top_backref;
diff --git a/src/3rdparty/pcre2/src/pcre2_context.c b/src/3rdparty/pcre2/src/pcre2_context.c
index 8e05ede50c..0bc2ea0b04 100644
--- a/src/3rdparty/pcre2/src/pcre2_context.c
+++ b/src/3rdparty/pcre2/src/pcre2_context.c
@@ -7,7 +7,7 @@ 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-2022 University of Cambridge
+ New API code Copyright (c) 2016-2023 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -139,7 +139,9 @@ const pcre2_compile_context PRIV(default_compile_context) = {
BSR_DEFAULT, /* Backslash R default */
NEWLINE_DEFAULT, /* Newline convention */
PARENS_NEST_LIMIT, /* As it says */
- 0 }; /* Extra options */
+ 0, /* Extra options */
+ MAX_VARLOOKBEHIND /* 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. */
@@ -228,49 +230,48 @@ return ccontext;
PCRE2_EXP_DEFN pcre2_general_context * PCRE2_CALL_CONVENTION
pcre2_general_context_copy(pcre2_general_context *gcontext)
{
-pcre2_general_context *new =
+pcre2_general_context *newcontext =
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;
+if (newcontext == NULL) return NULL;
+memcpy(newcontext, gcontext, sizeof(pcre2_real_general_context));
+return newcontext;
}
PCRE2_EXP_DEFN pcre2_compile_context * PCRE2_CALL_CONVENTION
pcre2_compile_context_copy(pcre2_compile_context *ccontext)
{
-pcre2_compile_context *new =
+pcre2_compile_context *newcontext =
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;
+if (newcontext == NULL) return NULL;
+memcpy(newcontext, ccontext, sizeof(pcre2_real_compile_context));
+return newcontext;
}
PCRE2_EXP_DEFN pcre2_match_context * PCRE2_CALL_CONVENTION
pcre2_match_context_copy(pcre2_match_context *mcontext)
{
-pcre2_match_context *new =
+pcre2_match_context *newcontext =
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;
+if (newcontext == NULL) return NULL;
+memcpy(newcontext, mcontext, sizeof(pcre2_real_match_context));
+return newcontext;
}
-
PCRE2_EXP_DEFN pcre2_convert_context * PCRE2_CALL_CONVENTION
pcre2_convert_context_copy(pcre2_convert_context *ccontext)
{
-pcre2_convert_context *new =
+pcre2_convert_context *newcontext =
ccontext->memctl.malloc(sizeof(pcre2_real_convert_context),
ccontext->memctl.memory_data);
-if (new == NULL) return NULL;
-memcpy(new, ccontext, sizeof(pcre2_real_convert_context));
-return new;
+if (newcontext == NULL) return NULL;
+memcpy(newcontext, ccontext, sizeof(pcre2_real_convert_context));
+return newcontext;
}
@@ -371,6 +372,13 @@ switch(newline)
}
PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_max_varlookbehind(pcre2_compile_context *ccontext, uint32_t limit)
+{
+ccontext->max_varlookbehind = limit;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
pcre2_set_parens_nest_limit(pcre2_compile_context *ccontext, uint32_t limit)
{
ccontext->parens_nest_limit = limit;
diff --git a/src/3rdparty/pcre2/src/pcre2_dfa_match.c b/src/3rdparty/pcre2/src/pcre2_dfa_match.c
index b16e594cc0..caae65248f 100644
--- a/src/3rdparty/pcre2/src/pcre2_dfa_match.c
+++ b/src/3rdparty/pcre2/src/pcre2_dfa_match.c
@@ -7,7 +7,7 @@ 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-2022 University of Cambridge
+ New API code Copyright (c) 2016-2023 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -168,7 +168,7 @@ static const uint8_t coptable[] = {
0, /* KetRmax */
0, /* KetRmin */
0, /* KetRpos */
- 0, /* Reverse */
+ 0, 0, /* Reverse, Vreverse */
0, /* Assert */
0, /* Assert not */
0, /* Assert behind */
@@ -187,7 +187,8 @@ static const uint8_t coptable[] = {
0, 0, 0, 0, /* SKIP, SKIP_ARG, THEN, THEN_ARG */
0, 0, /* COMMIT, COMMIT_ARG */
0, 0, 0, /* FAIL, ACCEPT, ASSERT_ACCEPT */
- 0, 0, 0 /* CLOSE, SKIPZERO, DEFINE */
+ 0, 0, 0, /* CLOSE, SKIPZERO, DEFINE */
+ 0, 0 /* \B and \b in UCP mode */
};
/* This table identifies those opcodes that inspect a character. It is used to
@@ -245,7 +246,7 @@ static const uint8_t poptable[] = {
0, /* KetRmax */
0, /* KetRmin */
0, /* KetRpos */
- 0, /* Reverse */
+ 0, 0, /* Reverse, Vreverse */
0, /* Assert */
0, /* Assert not */
0, /* Assert behind */
@@ -264,7 +265,8 @@ static const uint8_t poptable[] = {
0, 0, 0, 0, /* SKIP, SKIP_ARG, THEN, THEN_ARG */
0, 0, /* COMMIT, COMMIT_ARG */
0, 0, 0, /* FAIL, ACCEPT, ASSERT_ACCEPT */
- 0, 0, 0 /* CLOSE, SKIPZERO, DEFINE */
+ 0, 0, 0, /* CLOSE, SKIPZERO, DEFINE */
+ 1, 1 /* \B and \b in UCP mode */
};
/* These 2 tables allow for compact code for testing for \D, \d, \S, \s, \W,
@@ -426,7 +428,7 @@ overflow. */
else
{
- uint32_t newsize = (rws->size >= UINT32_MAX/2)? UINT32_MAX/2 : rws->size * 2;
+ uint32_t newsize = (rws->size >= UINT32_MAX/(sizeof(int)*2))? UINT32_MAX/sizeof(int) : rws->size * 2;
uint32_t newsizeK = newsize/(1024/sizeof(int));
if (newsizeK + mb->heap_used > mb->heap_limit)
@@ -589,7 +591,7 @@ if (*this_start_code == OP_ASSERTBACK || *this_start_code == OP_ASSERTBACK_NOT)
end_code = this_start_code;
do
{
- size_t back = (size_t)GET(end_code, 2+LINK_SIZE);
+ size_t back = (size_t)GET2(end_code, 2+LINK_SIZE);
if (back > max_back) max_back = back;
end_code += GET(end_code, 1);
}
@@ -633,8 +635,8 @@ if (*this_start_code == OP_ASSERTBACK || *this_start_code == OP_ASSERTBACK_NOT)
end_code = this_start_code;
do
{
- uint32_t revlen = (end_code[1+LINK_SIZE] == OP_REVERSE)? 1 + LINK_SIZE : 0;
- size_t back = (revlen == 0)? 0 : (size_t)GET(end_code, 2+LINK_SIZE);
+ uint32_t revlen = (end_code[1+LINK_SIZE] == OP_REVERSE)? 1 + IMM2_SIZE : 0;
+ size_t back = (revlen == 0)? 0 : (size_t)GET2(end_code, 2+LINK_SIZE);
if (back <= gone_back)
{
int bstate = (int)(end_code - start_code + 1 + LINK_SIZE + revlen);
@@ -1100,6 +1102,8 @@ for (;;)
/*-----------------------------------------------------------------*/
case OP_WORD_BOUNDARY:
case OP_NOT_WORD_BOUNDARY:
+ case OP_NOT_UCP_WORD_BOUNDARY:
+ case OP_UCP_WORD_BOUNDARY:
{
int left_word, right_word;
@@ -1112,13 +1116,13 @@ for (;;)
#endif
GETCHARTEST(d, temp);
#ifdef SUPPORT_UNICODE
- if ((mb->poptions & PCRE2_UCP) != 0)
+ if (codevalue == OP_UCP_WORD_BOUNDARY ||
+ codevalue == OP_NOT_UCP_WORD_BOUNDARY)
{
- if (d == '_') left_word = TRUE; else
- {
- uint32_t cat = UCD_CATEGORY(d);
- left_word = (cat == ucp_L || cat == ucp_N);
- }
+ int chartype = UCD_CHARTYPE(d);
+ int category = PRIV(ucp_gentype)[chartype];
+ left_word = (category == ucp_L || category == ucp_N ||
+ chartype == ucp_Mn || chartype == ucp_Pc);
}
else
#endif
@@ -1137,13 +1141,13 @@ for (;;)
mb->last_used_ptr = temp;
}
#ifdef SUPPORT_UNICODE
- if ((mb->poptions & PCRE2_UCP) != 0)
+ if (codevalue == OP_UCP_WORD_BOUNDARY ||
+ codevalue == OP_NOT_UCP_WORD_BOUNDARY)
{
- if (c == '_') right_word = TRUE; else
- {
- uint32_t cat = UCD_CATEGORY(c);
- right_word = (cat == ucp_L || cat == ucp_N);
- }
+ int chartype = UCD_CHARTYPE(c);
+ int category = PRIV(ucp_gentype)[chartype];
+ right_word = (category == ucp_L || category == ucp_N ||
+ chartype == ucp_Mn || chartype == ucp_Pc);
}
else
#endif
@@ -1151,7 +1155,9 @@ for (;;)
}
else right_word = FALSE;
- if ((left_word == right_word) == (codevalue == OP_NOT_WORD_BOUNDARY))
+ if ((left_word == right_word) ==
+ (codevalue == OP_NOT_WORD_BOUNDARY ||
+ codevalue == OP_NOT_UCP_WORD_BOUNDARY))
{ ADD_ACTIVE(state_offset + 1, 0); }
}
break;
@@ -1168,6 +1174,7 @@ for (;;)
if (clen > 0)
{
BOOL OK;
+ int chartype;
const uint32_t *cp;
const ucd_record * prop = GET_UCD(c);
switch(code[1])
@@ -1177,8 +1184,9 @@ for (;;)
break;
case PT_LAMP:
- OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
- prop->chartype == ucp_Lt;
+ chartype = prop->chartype;
+ OK = chartype == ucp_Lu || chartype == ucp_Ll ||
+ chartype == ucp_Lt;
break;
case PT_GC:
@@ -1201,8 +1209,9 @@ for (;;)
/* These are specials for combination cases. */
case PT_ALNUM:
- OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
- PRIV(ucp_gentype)[prop->chartype] == ucp_N;
+ chartype = prop->chartype;
+ OK = PRIV(ucp_gentype)[chartype] == ucp_L ||
+ PRIV(ucp_gentype)[chartype] == ucp_N;
break;
/* Perl space used to exclude VT, but from Perl 5.18 it is included,
@@ -1225,12 +1234,20 @@ for (;;)
break;
case PT_WORD:
- OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
- PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
- c == CHAR_UNDERSCORE;
+ chartype = prop->chartype;
+ OK = PRIV(ucp_gentype)[chartype] == ucp_L ||
+ PRIV(ucp_gentype)[chartype] == ucp_N ||
+ chartype == ucp_Mn || chartype == ucp_Pc;
break;
case PT_CLIST:
+#if PCRE2_CODE_UNIT_WIDTH == 32
+ if (c > MAX_UTF_CODE_POINT)
+ {
+ OK = FALSE;
+ break;
+ }
+#endif
cp = PRIV(ucd_caseless_sets) + code[2];
for (;;)
{
@@ -1440,6 +1457,7 @@ for (;;)
if (clen > 0)
{
BOOL OK;
+ int chartype;
const uint32_t *cp;
const ucd_record * prop = GET_UCD(c);
switch(code[2])
@@ -1449,8 +1467,8 @@ for (;;)
break;
case PT_LAMP:
- OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
- prop->chartype == ucp_Lt;
+ chartype = prop->chartype;
+ OK = chartype == ucp_Lu || chartype == ucp_Ll || chartype == ucp_Lt;
break;
case PT_GC:
@@ -1473,8 +1491,9 @@ for (;;)
/* These are specials for combination cases. */
case PT_ALNUM:
- OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
- PRIV(ucp_gentype)[prop->chartype] == ucp_N;
+ chartype = prop->chartype;
+ OK = PRIV(ucp_gentype)[chartype] == ucp_L ||
+ PRIV(ucp_gentype)[chartype] == ucp_N;
break;
/* Perl space used to exclude VT, but from Perl 5.18 it is included,
@@ -1497,12 +1516,20 @@ for (;;)
break;
case PT_WORD:
- OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
- PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
- c == CHAR_UNDERSCORE;
+ chartype = prop->chartype;
+ OK = PRIV(ucp_gentype)[chartype] == ucp_L ||
+ PRIV(ucp_gentype)[chartype] == ucp_N ||
+ chartype == ucp_Mn || chartype == ucp_Pc;
break;
case PT_CLIST:
+#if PCRE2_CODE_UNIT_WIDTH == 32
+ if (c > MAX_UTF_CODE_POINT)
+ {
+ OK = FALSE;
+ break;
+ }
+#endif
cp = PRIV(ucd_caseless_sets) + code[3];
for (;;)
{
@@ -1695,6 +1722,7 @@ for (;;)
if (clen > 0)
{
BOOL OK;
+ int chartype;
const uint32_t *cp;
const ucd_record * prop = GET_UCD(c);
switch(code[2])
@@ -1704,8 +1732,8 @@ for (;;)
break;
case PT_LAMP:
- OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
- prop->chartype == ucp_Lt;
+ chartype = prop->chartype;
+ OK = chartype == ucp_Lu || chartype == ucp_Ll || chartype == ucp_Lt;
break;
case PT_GC:
@@ -1728,8 +1756,9 @@ for (;;)
/* These are specials for combination cases. */
case PT_ALNUM:
- OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
- PRIV(ucp_gentype)[prop->chartype] == ucp_N;
+ chartype = prop->chartype;
+ OK = PRIV(ucp_gentype)[chartype] == ucp_L ||
+ PRIV(ucp_gentype)[chartype] == ucp_N;
break;
/* Perl space used to exclude VT, but from Perl 5.18 it is included,
@@ -1752,12 +1781,20 @@ for (;;)
break;
case PT_WORD:
- OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
- PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
- c == CHAR_UNDERSCORE;
+ chartype = prop->chartype;
+ OK = PRIV(ucp_gentype)[chartype] == ucp_L ||
+ PRIV(ucp_gentype)[chartype] == ucp_N ||
+ chartype == ucp_Mn || chartype == ucp_Pc;
break;
case PT_CLIST:
+#if PCRE2_CODE_UNIT_WIDTH == 32
+ if (c > MAX_UTF_CODE_POINT)
+ {
+ OK = FALSE;
+ break;
+ }
+#endif
cp = PRIV(ucd_caseless_sets) + code[3];
for (;;)
{
@@ -1975,6 +2012,7 @@ for (;;)
if (clen > 0)
{
BOOL OK;
+ int chartype;
const uint32_t *cp;
const ucd_record * prop = GET_UCD(c);
switch(code[1 + IMM2_SIZE + 1])
@@ -1984,8 +2022,8 @@ for (;;)
break;
case PT_LAMP:
- OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
- prop->chartype == ucp_Lt;
+ chartype = prop->chartype;
+ OK = chartype == ucp_Lu || chartype == ucp_Ll || chartype == ucp_Lt;
break;
case PT_GC:
@@ -2009,8 +2047,9 @@ for (;;)
/* These are specials for combination cases. */
case PT_ALNUM:
- OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
- PRIV(ucp_gentype)[prop->chartype] == ucp_N;
+ chartype = prop->chartype;
+ OK = PRIV(ucp_gentype)[chartype] == ucp_L ||
+ PRIV(ucp_gentype)[chartype] == ucp_N;
break;
/* Perl space used to exclude VT, but from Perl 5.18 it is included,
@@ -2033,12 +2072,20 @@ for (;;)
break;
case PT_WORD:
- OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
- PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
- c == CHAR_UNDERSCORE;
+ chartype = prop->chartype;
+ OK = PRIV(ucp_gentype)[chartype] == ucp_L ||
+ PRIV(ucp_gentype)[chartype] == ucp_N ||
+ chartype == ucp_Mn || chartype == ucp_Pc;
break;
case PT_CLIST:
+#if PCRE2_CODE_UNIT_WIDTH == 32
+ if (c > MAX_UTF_CODE_POINT)
+ {
+ OK = FALSE;
+ break;
+ }
+#endif
cp = PRIV(ucd_caseless_sets) + code[1 + IMM2_SIZE + 2];
for (;;)
{
@@ -2894,7 +2941,6 @@ for (;;)
int *local_workspace;
PCRE2_SIZE *local_offsets;
RWS_anchor *rws = (RWS_anchor *)RWS;
- dfa_recursion_info *ri;
PCRE2_SPTR callpat = start_code + GET(code, 1);
uint32_t recno = (callpat == mb->start_code)? 0 :
GET2(callpat, 1 + LINK_SIZE);
@@ -2911,18 +2957,24 @@ for (;;)
rws->free -= RWS_RSIZE + RWS_OVEC_RSIZE;
/* Check for repeating a recursion without advancing the subject
- pointer. This should catch convoluted mutual recursions. (Some simple
- cases are caught at compile time.) */
+ pointer or last used character. This should catch convoluted mutual
+ recursions. (Some simple cases are caught at compile time.) */
- for (ri = mb->recursive; ri != NULL; ri = ri->prevrec)
- if (recno == ri->group_num && ptr == ri->subject_position)
+ for (dfa_recursion_info *ri = mb->recursive;
+ ri != NULL;
+ ri = ri->prevrec)
+ {
+ if (recno == ri->group_num && ptr == ri->subject_position &&
+ mb->last_used_ptr == ri->last_used_ptr)
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.last_used_ptr = mb->last_used_ptr;
new_recursive.prevrec = mb->recursive;
mb->recursive = &new_recursive;
@@ -3424,7 +3476,7 @@ anchored = (options & (PCRE2_ANCHORED|PCRE2_DFA_RESTART)) != 0 ||
where to start. */
startline = (re->flags & PCRE2_STARTLINE) != 0;
-firstline = (re->overall_options & PCRE2_FIRSTLINE) != 0;
+firstline = !anchored && (re->overall_options & PCRE2_FIRSTLINE) != 0;
bumpalong_limit = end_subject;
/* Initialize and set up the fixed fields in the callout block, with a pointer
@@ -3994,8 +4046,9 @@ for (;;)
match_data->ovector[0] = (PCRE2_SIZE)(start_match - subject);
match_data->ovector[1] = (PCRE2_SIZE)(end_subject - subject);
}
+ match_data->subject_length = length;
match_data->leftchar = (PCRE2_SIZE)(mb->start_used_ptr - subject);
- match_data->rightchar = (PCRE2_SIZE)( mb->last_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;
diff --git a/src/3rdparty/pcre2/src/pcre2_error.c b/src/3rdparty/pcre2/src/pcre2_error.c
index 09904c03e3..1569f6315f 100644
--- a/src/3rdparty/pcre2/src/pcre2_error.c
+++ b/src/3rdparty/pcre2/src/pcre2_error.c
@@ -7,7 +7,7 @@ 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-2021 University of Cambridge
+ New API code Copyright (c) 2016-2023 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -82,7 +82,7 @@ static const unsigned char compile_error_texts[] =
"missing closing parenthesis\0"
/* 15 */
"reference to non-existent subpattern\0"
- "pattern passed as NULL\0"
+ "pattern passed as NULL with non-zero length\0"
"unrecognised compile-time option bit(s)\0"
"missing ) after (?# comment\0"
"parentheses are too deeply nested\0"
@@ -93,7 +93,7 @@ static const unsigned char compile_error_texts[] =
"internal error: code overflow\0"
"missing closing parenthesis for condition\0"
/* 25 */
- "lookbehind assertion is not fixed length\0"
+ "length of lookbehind assertion is not limited\0"
"a relative value of zero is not allowed\0"
"conditional subpattern contains more than two branches\0"
"assertion expected after (?( or (?(?C)\0"
@@ -187,6 +187,8 @@ static const unsigned char compile_error_texts[] =
"too many capturing groups (maximum 65535)\0"
"atomic assertion expected after (?( or (?(?C)\0"
"\\K is not allowed in lookarounds (but see PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK)\0"
+ /* 100 */
+ "branch too long in variable-length lookbehind assertion\0"
;
/* Match-time and UTF error texts are in the same format. */
@@ -272,6 +274,7 @@ static const unsigned char match_error_texts[] =
/* 65 */
"internal error - duplicate substitution match\0"
"PCRE2_MATCH_INVALID_UTF is not supported for DFA matching\0"
+ "INTERNAL ERROR: invalid substring offset\0"
;
diff --git a/src/3rdparty/pcre2/src/pcre2_find_bracket.c b/src/3rdparty/pcre2/src/pcre2_find_bracket.c
index 70baa1394f..1290c5e9de 100644
--- a/src/3rdparty/pcre2/src/pcre2_find_bracket.c
+++ b/src/3rdparty/pcre2/src/pcre2_find_bracket.c
@@ -7,7 +7,7 @@ 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-2018 University of Cambridge
+ New API code Copyright (c) 2016-2023 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -41,9 +41,9 @@ 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. */
+negative, an instance of OP_REVERSE or OP_VREVERSE 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
@@ -85,7 +85,7 @@ for (;;)
/* Handle lookbehind */
- else if (c == OP_REVERSE)
+ else if (c == OP_REVERSE || c == OP_VREVERSE)
{
if (number < 0) return (PCRE2_UCHAR *)code;
code += PRIV(OP_lengths)[c];
diff --git a/src/3rdparty/pcre2/src/pcre2_internal.h b/src/3rdparty/pcre2/src/pcre2_internal.h
index 92dd3138d4..e5808182e6 100644
--- a/src/3rdparty/pcre2/src/pcre2_internal.h
+++ b/src/3rdparty/pcre2/src/pcre2_internal.h
@@ -7,7 +7,7 @@ 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-2022 University of Cambridge
+ New API code Copyright (c) 2016-2023 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -51,6 +51,24 @@ pcre2test.c with CODE_UNIT_WIDTH == 0. */
#error The use of both EBCDIC and SUPPORT_UNICODE is not supported.
#endif
+/* When compiling one of the libraries, the value of PCRE2_CODE_UNIT_WIDTH must
+be 8, 16, or 32. AutoTools and CMake ensure that this is always the case, but
+other other building methods may not, so here is a check. It is cut out when
+building pcre2test, bcause that sets the value to zero. No other source should
+be including this file. There is no explicit way of forcing a compile to be
+abandoned, but trying to include a non-existent file seems cleanest. Otherwise
+there will be many irrelevant consequential errors. */
+
+#if (!defined PCRE2_BUILDING_PCRE2TEST && !defined PCRE2_DFTABLES) && \
+ (!defined PCRE2_CODE_UNIT_WIDTH || \
+ (PCRE2_CODE_UNIT_WIDTH != 8 && \
+ PCRE2_CODE_UNIT_WIDTH != 16 && \
+ PCRE2_CODE_UNIT_WIDTH != 32))
+#error PCRE2_CODE_UNIT_WIDTH must be defined as 8, 16, or 32.
+#include <AbandonCompile>
+#endif
+
+
/* Standard C headers */
#include <ctype.h>
@@ -119,20 +137,20 @@ only if it is not already set. */
#ifndef PCRE2_EXP_DECL
# ifdef _WIN32
# ifndef PCRE2_STATIC
-# define PCRE2_EXP_DECL extern __declspec(dllexport)
-# define PCRE2_EXP_DEFN __declspec(dllexport)
+# define PCRE2_EXP_DECL extern __declspec(dllexport)
+# define PCRE2_EXP_DEFN __declspec(dllexport)
# else
-# define PCRE2_EXP_DECL extern
+# define PCRE2_EXP_DECL extern PCRE2_EXPORT
# define PCRE2_EXP_DEFN
# endif
# else
# ifdef __cplusplus
-# define PCRE2_EXP_DECL extern "C"
+# define PCRE2_EXP_DECL extern "C" PCRE2_EXPORT
# else
-# define PCRE2_EXP_DECL extern
+# define PCRE2_EXP_DECL extern PCRE2_EXPORT
# endif
# ifndef PCRE2_EXP_DEFN
-# define PCRE2_EXP_DEFN PCRE2_EXP_DECL
+# define PCRE2_EXP_DEFN PCRE2_EXP_DECL
# endif
# endif
#endif
@@ -156,8 +174,8 @@ pcre2_match() because of the way it backtracks. */
#define PCRE2_SPTR CUSTOM_SUBJECT_PTR
#endif
-/* 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.
+/* When checking for integer overflow, 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. */
@@ -1281,7 +1299,7 @@ match. */
#define PT_ALNUM 6 /* Alphanumeric - the union of L and N */
#define PT_SPACE 7 /* Perl space - general category Z plus 9,10,12,13 */
#define PT_PXSPACE 8 /* POSIX space - Z plus 9,10,11,12,13 */
-#define PT_WORD 9 /* Word - L plus N plus underscore */
+#define PT_WORD 9 /* Word - L, N, Mn, or Pc */
#define PT_CLIST 10 /* Pseudo-property: match character list */
#define PT_UCNC 11 /* Universal Character nameable character */
#define PT_BIDICL 12 /* Specified bidi class */
@@ -1297,6 +1315,7 @@ table. */
#define PT_PXGRAPH 14 /* [:graph:] - characters that mark the paper */
#define PT_PXPRINT 15 /* [:print:] - [:graph:] plus non-control spaces */
#define PT_PXPUNCT 16 /* [:punct:] - punctuation characters */
+#define PT_PXXDIGIT 17 /* [:xdigit:] - hex digits */
/* This value is used when parsing \p and \P escapes to indicate that neither
\p{script:...} nor \p{scx:...} has been encountered. */
@@ -1327,6 +1346,12 @@ 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.
+ESC_ub is a special return from check_escape() when, in BSUX mode, \u{ is not
+followed by hex digits and }, in which case it should mean a literal "u"
+followed by a literal "{". This hack is necessary for cases like \u{ 12}
+because without it, this is interpreted as u{12} now that spaces are allowed in
+quantifiers.
+
Negative numbers are used to encode a backreference (\1, \2, \3, etc.) in
check_escape(). There are tests in the code for an escape greater than ESC_b
and less than ESC_Z to detect the types that may be repeated. These are the
@@ -1336,7 +1361,7 @@ consume a character, that code will have to change. */
enum { ESC_A = 1, ESC_G, ESC_K, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s,
ESC_W, ESC_w, ESC_N, ESC_dum, ESC_C, ESC_P, ESC_p, ESC_R, ESC_H,
ESC_h, ESC_V, ESC_v, ESC_X, ESC_Z, ESC_z,
- ESC_E, ESC_Q, ESC_g, ESC_k };
+ ESC_E, ESC_Q, ESC_g, ESC_k, ESC_ub };
/********************** Opcode definitions ******************/
@@ -1372,8 +1397,8 @@ enum {
OP_SOD, /* 1 Start of data: \A */
OP_SOM, /* 2 Start of match (subject + offset): \G */
OP_SET_SOM, /* 3 Set start of match (\K) */
- OP_NOT_WORD_BOUNDARY, /* 4 \B */
- OP_WORD_BOUNDARY, /* 5 \b */
+ OP_NOT_WORD_BOUNDARY, /* 4 \B -- see also OP_NOT_UCP_WORD_BOUNDARY */
+ OP_WORD_BOUNDARY, /* 5 \b -- see also OP_UCP_WORD_BOUNDARY */
OP_NOT_DIGIT, /* 6 \D */
OP_DIGIT, /* 7 \d */
OP_NOT_WHITESPACE, /* 8 \S */
@@ -1547,78 +1572,85 @@ enum {
/* The assertions must come before BRA, CBRA, ONCE, and COND. */
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 */
- OP_ASSERT_NA, /* 130 Positive non-atomic lookahead */
- OP_ASSERTBACK_NA, /* 131 Positive non-atomic lookbehind */
+ OP_VREVERSE, /* 126 Move pointer back - variable */
+ OP_ASSERT, /* 127 Positive lookahead */
+ OP_ASSERT_NOT, /* 128 Negative lookahead */
+ OP_ASSERTBACK, /* 129 Positive lookbehind */
+ OP_ASSERTBACK_NOT, /* 130 Negative lookbehind */
+ OP_ASSERT_NA, /* 131 Positive non-atomic lookahead */
+ OP_ASSERTBACK_NA, /* 132 Positive non-atomic lookbehind */
/* ONCE, SCRIPT_RUN, 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, /* 132 Atomic group, contains captures */
- OP_SCRIPT_RUN, /* 133 Non-capture, but check characters' scripts */
- OP_BRA, /* 134 Start of non-capturing bracket */
- OP_BRAPOS, /* 135 Ditto, with unlimited, possessive repeat */
- OP_CBRA, /* 136 Start of capturing bracket */
- OP_CBRAPOS, /* 137 Ditto, with unlimited, possessive repeat */
- OP_COND, /* 138 Conditional group */
+ OP_ONCE, /* 133 Atomic group, contains captures */
+ OP_SCRIPT_RUN, /* 134 Non-capture, but check characters' scripts */
+ OP_BRA, /* 135 Start of non-capturing bracket */
+ OP_BRAPOS, /* 136 Ditto, with unlimited, possessive repeat */
+ OP_CBRA, /* 137 Start of capturing bracket */
+ OP_CBRAPOS, /* 138 Ditto, with unlimited, possessive repeat */
+ OP_COND, /* 139 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, /* 139 Start of non-capturing bracket, check empty */
- OP_SBRAPOS, /* 149 Ditto, with unlimited, possessive repeat */
- OP_SCBRA, /* 141 Start of capturing bracket, check empty */
- OP_SCBRAPOS, /* 142 Ditto, with unlimited, possessive repeat */
- OP_SCOND, /* 143 Conditional group, check empty */
+ OP_SBRA, /* 140 Start of non-capturing bracket, check empty */
+ OP_SBRAPOS, /* 141 Ditto, with unlimited, possessive repeat */
+ OP_SCBRA, /* 142 Start of capturing bracket, check empty */
+ OP_SCBRAPOS, /* 143 Ditto, with unlimited, possessive repeat */
+ OP_SCOND, /* 144 Conditional group, check empty */
/* The next two pairs must (respectively) be kept together. */
- OP_CREF, /* 144 Used to hold a capture number as condition */
- OP_DNCREF, /* 145 Used to point to duplicate names as a condition */
- OP_RREF, /* 146 Used to hold a recursion number as condition */
- OP_DNRREF, /* 147 Used to point to duplicate names as a condition */
- OP_FALSE, /* 148 Always false (used by DEFINE and VERSION) */
- OP_TRUE, /* 149 Always true (used by VERSION) */
+ OP_CREF, /* 145 Used to hold a capture number as condition */
+ OP_DNCREF, /* 146 Used to point to duplicate names as a condition */
+ OP_RREF, /* 147 Used to hold a recursion number as condition */
+ OP_DNRREF, /* 148 Used to point to duplicate names as a condition */
+ OP_FALSE, /* 149 Always false (used by DEFINE and VERSION) */
+ OP_TRUE, /* 150 Always true (used by VERSION) */
- OP_BRAZERO, /* 150 These two must remain together and in this */
- OP_BRAMINZERO, /* 151 order. */
- OP_BRAPOSZERO, /* 152 */
+ OP_BRAZERO, /* 151 These two must remain together and in this */
+ OP_BRAMINZERO, /* 152 order. */
+ OP_BRAPOSZERO, /* 153 */
/* These are backtracking control verbs */
- OP_MARK, /* 153 always has an argument */
- OP_PRUNE, /* 154 */
- OP_PRUNE_ARG, /* 155 same, but with argument */
- OP_SKIP, /* 156 */
- OP_SKIP_ARG, /* 157 same, but with argument */
- OP_THEN, /* 158 */
- OP_THEN_ARG, /* 159 same, but with argument */
- OP_COMMIT, /* 160 */
- OP_COMMIT_ARG, /* 161 same, but with argument */
+ OP_MARK, /* 154 always has an argument */
+ OP_PRUNE, /* 155 */
+ OP_PRUNE_ARG, /* 156 same, but with argument */
+ OP_SKIP, /* 157 */
+ OP_SKIP_ARG, /* 158 same, but with argument */
+ OP_THEN, /* 159 */
+ OP_THEN_ARG, /* 160 same, but with argument */
+ OP_COMMIT, /* 161 */
+ OP_COMMIT_ARG, /* 162 same, but with argument */
/* These are forced failure and success verbs. FAIL and ACCEPT do accept an
argument, but these cases can be compiled as, for example, (*MARK:X)(*FAIL)
without the need for a special opcode. */
- OP_FAIL, /* 162 */
- OP_ACCEPT, /* 163 */
- OP_ASSERT_ACCEPT, /* 164 Used inside assertions */
- OP_CLOSE, /* 165 Used before OP_ACCEPT to close open captures */
+ OP_FAIL, /* 163 */
+ OP_ACCEPT, /* 164 */
+ OP_ASSERT_ACCEPT, /* 165 Used inside assertions */
+ OP_CLOSE, /* 166 Used before OP_ACCEPT to close open captures */
/* This is used to skip a subpattern with a {0} quantifier */
- OP_SKIPZERO, /* 166 */
+ OP_SKIPZERO, /* 167 */
/* 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, /* 167 */
+ OP_DEFINE, /* 168 */
+
+ /* These opcodes replace their normal counterparts in UCP mode when
+ PCRE2_EXTRA_ASCII_BSW is not set. */
+
+ OP_NOT_UCP_WORD_BOUNDARY, /* 169 */
+ OP_UCP_WORD_BOUNDARY, /* 170 */
/* 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
@@ -1664,7 +1696,7 @@ some cases doesn't actually use these names at all). */
"class", "nclass", "xclass", "Ref", "Refi", "DnRef", "DnRefi", \
"Recurse", "Callout", "CalloutStr", \
"Alt", "Ket", "KetRmax", "KetRmin", "KetRpos", \
- "Reverse", "Assert", "Assert not", \
+ "Reverse", "VReverse", "Assert", "Assert not", \
"Assert back", "Assert back not", \
"Non-atomic assert", "Non-atomic assert back", \
"Once", \
@@ -1679,7 +1711,7 @@ some cases doesn't actually use these names at all). */
"*MARK", "*PRUNE", "*PRUNE", "*SKIP", "*SKIP", \
"*THEN", "*THEN", "*COMMIT", "*COMMIT", "*FAIL", \
"*ACCEPT", "*ASSERT_ACCEPT", \
- "Close", "Skip zero", "Define"
+ "Close", "Skip zero", "Define", "\\B (ucp)", "\\b (ucp)"
/* This macro defines the length of fixed length operations in the compiled
@@ -1746,7 +1778,8 @@ in UTF-8 mode. The code that uses this table must know about such things. */
1+LINK_SIZE, /* KetRmax */ \
1+LINK_SIZE, /* KetRmin */ \
1+LINK_SIZE, /* KetRpos */ \
- 1+LINK_SIZE, /* Reverse */ \
+ 1+IMM2_SIZE, /* Reverse */ \
+ 1+2*IMM2_SIZE, /* VReverse */ \
1+LINK_SIZE, /* Assert */ \
1+LINK_SIZE, /* Assert not */ \
1+LINK_SIZE, /* Assert behind */ \
@@ -1775,7 +1808,8 @@ in UTF-8 mode. The code that uses this table must know about such things. */
1, 3, /* COMMIT, COMMIT_ARG */ \
1, 1, 1, /* FAIL, ACCEPT, ASSERT_ACCEPT */ \
1+IMM2_SIZE, 1, /* CLOSE, SKIPZERO */ \
- 1 /* DEFINE */
+ 1, /* DEFINE */ \
+ 1, 1 /* \B and \b in UCP mode */
/* A magic value for OP_RREF to indicate the "any recursion" condition. */
@@ -2042,6 +2076,9 @@ extern void * _pcre2_memmove(void *, const void *, size_t);
#endif
#endif /* PCRE2_CODE_UNIT_WIDTH */
+
+extern BOOL PRIV(ckd_smul)(PCRE2_SIZE *, int, int);
+
#endif /* PCRE2_INTERNAL_H_IDEMPOTENT_GUARD */
/* End of pcre2_internal.h */
diff --git a/src/3rdparty/pcre2/src/pcre2_intmodedep.h b/src/3rdparty/pcre2/src/pcre2_intmodedep.h
index 390e737a6e..5fcddce5fe 100644
--- a/src/3rdparty/pcre2/src/pcre2_intmodedep.h
+++ b/src/3rdparty/pcre2/src/pcre2_intmodedep.h
@@ -7,7 +7,7 @@ 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-2022 University of Cambridge
+ New API code Copyright (c) 2016-2023 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -572,6 +572,7 @@ typedef struct pcre2_real_compile_context {
uint16_t newline_convention;
uint32_t parens_nest_limit;
uint32_t extra_options;
+ uint32_t max_varlookbehind;
} pcre2_real_compile_context;
/* The real match context structure. */
@@ -605,12 +606,12 @@ 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.) */
+largest lookbehind that is supported. (OP_REVERSE and OP_VREVERSE in a pattern
+have 16-bit arguments 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
+#define CODE_BLOCKSIZE_TYPE PCRE2_SIZE
#undef LOOKBEHIND_MAX
#define LOOKBEHIND_MAX UINT16_MAX
@@ -658,6 +659,7 @@ typedef struct pcre2_real_match_data {
PCRE2_SPTR mark; /* Pointer to last mark */
struct heapframe *heapframes; /* Backtracking frames heap memory */
PCRE2_SIZE heapframes_size; /* Malloc-ed size */
+ PCRE2_SIZE subject_length; /* Subject length */
PCRE2_SIZE leftchar; /* Offset to leftmost code unit */
PCRE2_SIZE rightchar; /* Offset to rightmost code unit */
PCRE2_SIZE startchar; /* Offset to starting code unit */
@@ -675,8 +677,8 @@ typedef struct pcre2_real_match_data {
#ifndef PCRE2_PCRE2TEST
-/* Structures for checking for mutual recursion when scanning compiled or
-parsed code. */
+/* Structures for checking for mutual function recursion when scanning compiled
+or parsed code. */
typedef struct recurse_check {
struct recurse_check *prev;
@@ -688,7 +690,7 @@ typedef struct parsed_recurse_check {
uint32_t *groupptr;
} parsed_recurse_check;
-/* Structure for building a cache when filling in recursion offsets. */
+/* Structure for building a cache when filling in pattern recursion offsets. */
typedef struct recurse_cache {
PCRE2_SPTR group;
@@ -734,7 +736,6 @@ typedef struct compile_block {
uint16_t name_entry_size; /* Size of each entry */
uint16_t parens_depth; /* Depth of nested parentheses */
uint16_t assert_depth; /* Depth of nested assertions */
- 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 */
@@ -752,10 +753,11 @@ typedef struct compile_block {
uint32_t class_range_end; /* Overall class range end */
PCRE2_UCHAR nl[4]; /* Newline string when fixed length */
uint32_t req_varyopt; /* "After variable item" flag for reqbyte */
- int max_lookbehind; /* Maximum lookbehind (characters) */
+ uint32_t max_varlookbehind; /* Limit for variable lookbehinds */
+ int max_lookbehind; /* Maximum lookbehind encountered (characters) */
BOOL had_accept; /* (*ACCEPT) encountered */
BOOL had_pruneorskip; /* (*PRUNE) or (*SKIP) encountered */
- BOOL had_recurse; /* Had a recursion or subroutine call */
+ BOOL had_recurse; /* Had a pattern recursion or subroutine call */
BOOL dupnames; /* Duplicate names exist */
} compile_block;
@@ -773,6 +775,7 @@ call within the pattern when running pcre2_dfa_match(). */
typedef struct dfa_recursion_info {
struct dfa_recursion_info *prevrec;
PCRE2_SPTR subject_position;
+ PCRE2_SPTR last_used_ptr;
uint32_t group_num;
} dfa_recursion_info;
@@ -793,7 +796,7 @@ typedef struct heapframe {
PCRE2_SIZE length; /* Used for character, string, or code lengths */
PCRE2_SIZE back_frame; /* Amount to subtract on RRETURN */
PCRE2_SIZE temp_size; /* Used for short-term PCRE2_SIZE values */
- uint32_t rdepth; /* "Recursion" depth */
+ uint32_t rdepth; /* Function "recursion" depth within pcre2_match() */
uint32_t group_frame_type; /* Type information for group frames */
uint32_t temp_32[4]; /* Used for short-term 32-bit or BOOL values */
uint8_t return_id; /* Where to go on in internal "return" */
@@ -826,14 +829,15 @@ typedef struct heapframe {
allows for exactly the right size ovector for the number of capturing
parentheses. (See also the comment for pcre2_real_match_data above.) */
- PCRE2_SPTR eptr; /* MUST BE FIRST */
- PCRE2_SPTR start_match; /* Can be adjusted by \K */
- PCRE2_SPTR mark; /* Most recent mark on the success path */
- uint32_t current_recurse; /* Current (deepest) recursion number */
- uint32_t capture_last; /* Most recent capture */
- PCRE2_SIZE last_group_offset; /* Saved offset to most recent group frame */
- PCRE2_SIZE offset_top; /* Offset after highest capture */
- PCRE2_SIZE ovector[131072]; /* Must be last in the structure */
+ PCRE2_SPTR eptr; /* MUST BE FIRST */
+ PCRE2_SPTR start_match; /* Can be adjusted by \K */
+ PCRE2_SPTR mark; /* Most recent mark on the success path */
+ PCRE2_SPTR recurse_last_used; /* Last character used at time of pattern recursion */
+ uint32_t current_recurse; /* Group number of current (deepest) pattern recursion */
+ uint32_t capture_last; /* Most recent capture */
+ PCRE2_SIZE last_group_offset; /* Saved offset to most recent group frame */
+ PCRE2_SIZE offset_top; /* Offset after highest capture */
+ PCRE2_SIZE ovector[131072]; /* Must be last in the structure */
} heapframe;
/* This typedef is a check that the size of the heapframe structure is a
@@ -858,7 +862,7 @@ doing traditional NFA matching (pcre2_match() and friends). */
typedef struct match_block {
pcre2_memctl memctl; /* For general use */
- PCRE2_SIZE heap_limit; /* As it says */
+ uint32_t heap_limit; /* As it says */
uint32_t match_limit; /* As it says */
uint32_t match_limit_depth; /* As it says */
uint32_t match_call_count; /* Number of times a new frame is created */
@@ -875,10 +879,11 @@ typedef struct match_block {
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_code; /* For use in pattern recursion */
PCRE2_SPTR start_subject; /* Start of the subject string */
PCRE2_SPTR check_subject; /* Where UTF-checked from */
- PCRE2_SPTR end_subject; /* End of the subject string */
+ PCRE2_SPTR end_subject; /* Usable end of the subject string */
+ PCRE2_SPTR true_end_subject; /* Actual end of the subject 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 */
@@ -886,7 +891,7 @@ typedef struct match_block {
PCRE2_SPTR nomatch_mark; /* Mark pointer to pass back on failure */
PCRE2_SPTR verb_ecode_ptr; /* For passing back info */
PCRE2_SPTR verb_skip_ptr; /* For passing back a (*SKIP) name */
- uint32_t verb_current_recurse; /* Current recurse when (*VERB) happens */
+ uint32_t verb_current_recurse; /* Current recursion group when (*VERB) happens */
uint32_t moptions; /* Match options */
uint32_t poptions; /* Pattern options */
uint32_t skip_arg_count; /* For counting SKIP_ARGs */
@@ -911,7 +916,7 @@ typedef struct dfa_match_block {
PCRE2_SPTR last_used_ptr; /* Latest consulted character */
const uint8_t *tables; /* Character tables */
PCRE2_SIZE start_offset; /* The start offset value */
- PCRE2_SIZE heap_limit; /* As it says */
+ uint32_t heap_limit; /* As it says */
PCRE2_SIZE heap_used; /* As it says */
uint32_t match_limit; /* As it says */
uint32_t match_limit_depth; /* As it says */
@@ -926,7 +931,7 @@ typedef struct dfa_match_block {
pcre2_callout_block *cb; /* Points to a callout block */
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_recursion_info *recursive; /* Linked list of pattern recursion data */
} dfa_match_block;
#endif /* PCRE2_PCRE2TEST */
diff --git a/src/3rdparty/pcre2/src/pcre2_jit_compile.c b/src/3rdparty/pcre2/src/pcre2_jit_compile.c
index 0afd27c5ee..050063ec6d 100644
--- a/src/3rdparty/pcre2/src/pcre2_jit_compile.c
+++ b/src/3rdparty/pcre2/src/pcre2_jit_compile.c
@@ -43,6 +43,12 @@ POSSIBILITY OF SUCH DAMAGE.
#include "config.h"
#endif
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+#include <sanitizer/msan_interface.h>
+#endif /* __has_feature(memory_sanitizer) */
+#endif /* defined(__has_feature) */
+
#include "pcre2_internal.h"
#ifdef SUPPORT_JIT
@@ -236,12 +242,21 @@ code generator. It is allocated by compile_matchingpath, and contains
the arguments for compile_backtrackingpath. Must be the first member
of its descendants. */
typedef struct backtrack_common {
- /* Concatenation stack. */
+ /* Backtracking path of an opcode, which falls back
+ to our opcode, if it cannot resume matching. */
struct backtrack_common *prev;
- jump_list *nextbacktracks;
- /* Internal stack (for component operators). */
+ /* Backtracks for opcodes without backtracking path.
+ These opcodes are between 'prev' and the current
+ opcode, and they never resume the match. */
+ jump_list *simple_backtracks;
+ /* Internal backtracking list for block constructs
+ which contains other opcodes, such as brackets,
+ asserts, conditionals, etc. */
struct backtrack_common *top;
- jump_list *topbacktracks;
+ /* Backtracks used internally by the opcode. For component
+ opcodes, this list is also used by those opcodes without
+ backtracking path which follows the 'top' backtrack. */
+ jump_list *own_backtracks;
/* Opcode pointer. */
PCRE2_SPTR cc;
} backtrack_common;
@@ -338,6 +353,12 @@ typedef struct recurse_backtrack {
BOOL inlined_pattern;
} recurse_backtrack;
+typedef struct vreverse_backtrack {
+ backtrack_common common;
+ /* Return to the matching path. */
+ struct sljit_label *matchingpath;
+} vreverse_backtrack;
+
#define OP_THEN_TRAP OP_TABLE_LENGTH
typedef struct then_trap_backtrack {
@@ -404,7 +425,9 @@ typedef struct compiler_common {
sljit_s32 match_end_ptr;
/* Points to the marked string. */
sljit_s32 mark_ptr;
- /* Recursive control verb management chain. */
+ /* Head of the recursive control verb management chain.
+ Each item must have a previous offset and type
+ (see control_types) values. See do_search_mark. */
sljit_s32 control_head_ptr;
/* Points to the last matched capture block index. */
sljit_s32 capture_last_ptr;
@@ -474,12 +497,15 @@ typedef struct compiler_common {
jump_list *stackalloc;
jump_list *revertframes;
jump_list *wordboundary;
+ jump_list *ucp_wordboundary;
jump_list *anynewline;
jump_list *hspace;
jump_list *vspace;
jump_list *casefulcmp;
jump_list *caselesscmp;
jump_list *reset_match;
+ /* Same as reset_match, but resets the STR_PTR as well. */
+ jump_list *restart_match;
BOOL unset_backref;
BOOL alt_circumflex;
#ifdef SUPPORT_UNICODE
@@ -636,8 +662,8 @@ the start pointers when the end of the capturing group has not yet reached. */
sljit_set_label(sljit_emit_cmp(compiler, (type), (src1), (src1w), (src2), (src2w)), (label))
#define OP_FLAGS(op, dst, dstw, type) \
sljit_emit_op_flags(compiler, (op), (dst), (dstw), (type))
-#define CMOV(type, dst_reg, src, srcw) \
- sljit_emit_cmov(compiler, (type), (dst_reg), (src), (srcw))
+#define SELECT(type, dst_reg, src1, src1w, src2_reg) \
+ sljit_emit_select(compiler, (type), (dst_reg), (src1), (src1w), (src2_reg))
#define GET_LOCAL_BASE(dst, dstw, offset) \
sljit_get_local_base(compiler, (dst), (dstw), (offset))
@@ -857,6 +883,21 @@ SLJIT_ASSERT(*cc >= OP_KET && *cc <= OP_KETRPOS);
return count;
}
+static BOOL find_vreverse(PCRE2_SPTR cc)
+{
+ SLJIT_ASSERT(*cc == OP_ASSERTBACK || *cc == OP_ASSERTBACK_NOT || *cc == OP_ASSERTBACK_NA);
+
+ do
+ {
+ if (cc[1 + LINK_SIZE] == OP_VREVERSE)
+ return TRUE;
+ cc += GET(cc, 1);
+ }
+ while (*cc == OP_ALT);
+
+ return FALSE;
+}
+
/* Functions whose might need modification for all new supported opcodes:
next_opcode
check_opcode_types
@@ -927,6 +968,7 @@ switch(*cc)
case OP_KETRMIN:
case OP_KETRPOS:
case OP_REVERSE:
+ case OP_VREVERSE:
case OP_ASSERT:
case OP_ASSERT_NOT:
case OP_ASSERTBACK:
@@ -963,6 +1005,8 @@ switch(*cc)
case OP_ASSERT_ACCEPT:
case OP_CLOSE:
case OP_SKIPZERO:
+ case OP_NOT_UCP_WORD_BOUNDARY:
+ case OP_UCP_WORD_BOUNDARY:
return cc + PRIV(OP_lengths)[*cc];
case OP_CHAR:
@@ -1231,34 +1275,37 @@ while (cc < ccend)
return TRUE;
}
-#define EARLY_FAIL_ENHANCE_MAX (1 + 3)
+#define EARLY_FAIL_ENHANCE_MAX (3 + 3)
/*
-start:
- 0 - skip / early fail allowed
- 1 - only early fail with range allowed
- >1 - (start - 1) early fail is processed
+ Start represent the number of allowed early fail enhancements
-return: current number of iterators enhanced with fast fail
+ The 0-2 values has a special meaning:
+ 0 - skip is allowed for all iterators
+ 1 - fail is allowed for all iterators
+ 2 - fail is allowed for greedy iterators
+ 3 - only ranged early fail is allowed
+ >3 - (start - 3) number of remaining ranged early fails allowed
+
+return: the updated value of start
*/
-static int detect_early_fail(compiler_common *common, PCRE2_SPTR cc, int *private_data_start,
- sljit_s32 depth, int start, BOOL fast_forward_allowed)
+static int detect_early_fail(compiler_common *common, PCRE2_SPTR cc,
+ int *private_data_start, sljit_s32 depth, int start)
{
PCRE2_SPTR begin = cc;
PCRE2_SPTR next_alt;
PCRE2_SPTR end;
PCRE2_SPTR accelerated_start;
-BOOL prev_fast_forward_allowed;
int result = 0;
-int count;
+int count, prev_count;
SLJIT_ASSERT(*cc == OP_ONCE || *cc == OP_BRA || *cc == OP_CBRA);
SLJIT_ASSERT(*cc != OP_CBRA || common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] != 0);
SLJIT_ASSERT(start < EARLY_FAIL_ENHANCE_MAX);
next_alt = cc + GET(cc, 1);
-if (*next_alt == OP_ALT)
- fast_forward_allowed = FALSE;
+if (*next_alt == OP_ALT && start < 1)
+ start = 1;
do
{
@@ -1282,6 +1329,8 @@ do
case OP_CIRCM:
case OP_DOLL:
case OP_DOLLM:
+ case OP_NOT_UCP_WORD_BOUNDARY:
+ case OP_UCP_WORD_BOUNDARY:
/* Zero width assertions. */
cc++;
continue;
@@ -1299,21 +1348,22 @@ do
case OP_HSPACE:
case OP_NOT_VSPACE:
case OP_VSPACE:
- fast_forward_allowed = FALSE;
+ if (count < 1)
+ count = 1;
cc++;
continue;
case OP_ANYNL:
case OP_EXTUNI:
- fast_forward_allowed = FALSE;
- if (count == 0)
- count = 1;
+ if (count < 3)
+ count = 3;
cc++;
continue;
case OP_NOTPROP:
case OP_PROP:
- fast_forward_allowed = FALSE;
+ if (count < 1)
+ count = 1;
cc += 1 + 2;
continue;
@@ -1321,17 +1371,22 @@ do
case OP_CHARI:
case OP_NOT:
case OP_NOTI:
- fast_forward_allowed = FALSE;
+ if (count < 1)
+ count = 1;
cc += 2;
#ifdef SUPPORT_UNICODE
if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
#endif
continue;
- case OP_TYPESTAR:
case OP_TYPEMINSTAR:
- case OP_TYPEPLUS:
case OP_TYPEMINPLUS:
+ if (count == 2)
+ count = 3;
+ /* Fall through */
+
+ case OP_TYPESTAR:
+ case OP_TYPEPLUS:
case OP_TYPEPOSSTAR:
case OP_TYPEPOSPLUS:
/* The type or prop opcode is skipped in the next iteration. */
@@ -1343,14 +1398,18 @@ do
break;
}
- if (count == 0)
+ if (count < 3)
+ count = 3;
+ continue;
+
+ case OP_TYPEEXACT:
+ if (count < 1)
count = 1;
- fast_forward_allowed = FALSE;
+ cc += 1 + IMM2_SIZE;
continue;
case OP_TYPEUPTO:
case OP_TYPEMINUPTO:
- case OP_TYPEEXACT:
case OP_TYPEPOSUPTO:
cc += IMM2_SIZE;
/* Fall through */
@@ -1359,37 +1418,40 @@ do
case OP_TYPEMINQUERY:
case OP_TYPEPOSQUERY:
/* The type or prop opcode is skipped in the next iteration. */
- fast_forward_allowed = FALSE;
- if (count == 0)
- count = 1;
+ if (count < 3)
+ count = 3;
cc += 1;
continue;
- case OP_STAR:
case OP_MINSTAR:
- case OP_PLUS:
case OP_MINPLUS:
+ case OP_MINSTARI:
+ case OP_MINPLUSI:
+ case OP_NOTMINSTAR:
+ case OP_NOTMINPLUS:
+ case OP_NOTMINSTARI:
+ case OP_NOTMINPLUSI:
+ if (count == 2)
+ count = 3;
+ /* Fall through */
+
+ case OP_STAR:
+ case OP_PLUS:
case OP_POSSTAR:
case OP_POSPLUS:
case OP_STARI:
- case OP_MINSTARI:
case OP_PLUSI:
- case OP_MINPLUSI:
case OP_POSSTARI:
case OP_POSPLUSI:
case OP_NOTSTAR:
- case OP_NOTMINSTAR:
case OP_NOTPLUS:
- case OP_NOTMINPLUS:
case OP_NOTPOSSTAR:
case OP_NOTPOSPLUS:
case OP_NOTSTARI:
- case OP_NOTMINSTARI:
case OP_NOTPLUSI:
- case OP_NOTMINPLUSI:
case OP_NOTPOSSTARI:
case OP_NOTPOSPLUSI:
accelerated_start = cc;
@@ -1399,9 +1461,17 @@ do
#endif
break;
+ case OP_EXACT:
+ if (count < 1)
+ count = 1;
+ cc += 2 + IMM2_SIZE;
+#ifdef SUPPORT_UNICODE
+ if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+ continue;
+
case OP_UPTO:
case OP_MINUPTO:
- case OP_EXACT:
case OP_POSUPTO:
case OP_UPTOI:
case OP_MINUPTOI:
@@ -1430,9 +1500,8 @@ do
case OP_NOTQUERYI:
case OP_NOTMINQUERYI:
case OP_NOTPOSQUERYI:
- fast_forward_allowed = FALSE;
- if (count == 0)
- count = 1;
+ if (count < 3)
+ count = 3;
cc += 2;
#ifdef SUPPORT_UNICODE
if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
@@ -1452,10 +1521,14 @@ do
switch (*cc)
{
- case OP_CRSTAR:
case OP_CRMINSTAR:
- case OP_CRPLUS:
case OP_CRMINPLUS:
+ if (count == 2)
+ count = 3;
+ /* Fall through */
+
+ case OP_CRSTAR:
+ case OP_CRPLUS:
case OP_CRPOSSTAR:
case OP_CRPOSPLUS:
cc++;
@@ -1464,44 +1537,60 @@ do
case OP_CRRANGE:
case OP_CRMINRANGE:
case OP_CRPOSRANGE:
+ if (GET2(cc, 1) == GET2(cc, 1 + IMM2_SIZE))
+ {
+ /* Exact repeat. */
+ cc += 1 + 2 * IMM2_SIZE;
+ if (count < 1)
+ count = 1;
+ continue;
+ }
+
cc += 2 * IMM2_SIZE;
/* Fall through */
case OP_CRQUERY:
case OP_CRMINQUERY:
case OP_CRPOSQUERY:
cc++;
- if (count == 0)
- count = 1;
- /* Fall through */
+ if (count < 3)
+ count = 3;
+ continue;
+
default:
- accelerated_start = NULL;
- fast_forward_allowed = FALSE;
+ /* No repeat. */
+ if (count < 1)
+ count = 1;
continue;
}
break;
- case OP_ONCE:
case OP_BRA:
case OP_CBRA:
- end = cc + GET(cc, 1);
+ prev_count = count;
+ if (count < 1)
+ count = 1;
- prev_fast_forward_allowed = fast_forward_allowed;
- fast_forward_allowed = FALSE;
if (depth >= 4)
break;
- end = bracketend(cc) - (1 + LINK_SIZE);
- if (*end != OP_KET || (*cc == OP_CBRA && common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0))
+ if (count < 3 && cc[GET(cc, 1)] == OP_ALT)
+ count = 3;
+
+ end = bracketend(cc);
+ if (end[-1 - LINK_SIZE] != OP_KET || (*cc == OP_CBRA && common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0))
break;
- count = detect_early_fail(common, cc, private_data_start, depth + 1, count, prev_fast_forward_allowed);
+ prev_count = detect_early_fail(common, cc, private_data_start, depth + 1, prev_count);
+
+ if (prev_count > count)
+ count = prev_count;
if (PRIVATE_DATA(cc) != 0)
common->private_data_ptrs[begin - common->start] = 1;
if (count < EARLY_FAIL_ENHANCE_MAX)
{
- cc = end + (1 + LINK_SIZE);
+ cc = end;
continue;
}
break;
@@ -1514,55 +1603,52 @@ do
continue;
}
- if (accelerated_start != NULL)
+ if (accelerated_start == NULL)
+ break;
+
+ if (count == 0)
{
- if (count == 0)
- {
- count++;
+ common->fast_forward_bc_ptr = accelerated_start;
+ common->private_data_ptrs[(accelerated_start + 1) - common->start] = ((*private_data_start) << 3) | type_skip;
+ *private_data_start += sizeof(sljit_sw);
+ count = 4;
+ }
+ else if (count < 3)
+ {
+ common->private_data_ptrs[(accelerated_start + 1) - common->start] = ((*private_data_start) << 3) | type_fail;
- if (fast_forward_allowed)
- {
- common->fast_forward_bc_ptr = accelerated_start;
- common->private_data_ptrs[(accelerated_start + 1) - common->start] = ((*private_data_start) << 3) | type_skip;
- *private_data_start += sizeof(sljit_sw);
- }
- else
- {
- common->private_data_ptrs[(accelerated_start + 1) - common->start] = ((*private_data_start) << 3) | type_fail;
+ if (common->early_fail_start_ptr == 0)
+ common->early_fail_start_ptr = *private_data_start;
- if (common->early_fail_start_ptr == 0)
- common->early_fail_start_ptr = *private_data_start;
+ *private_data_start += sizeof(sljit_sw);
+ common->early_fail_end_ptr = *private_data_start;
- *private_data_start += sizeof(sljit_sw);
- common->early_fail_end_ptr = *private_data_start;
+ if (*private_data_start > SLJIT_MAX_LOCAL_SIZE)
+ return EARLY_FAIL_ENHANCE_MAX;
- if (*private_data_start > SLJIT_MAX_LOCAL_SIZE)
- return EARLY_FAIL_ENHANCE_MAX;
- }
- }
- else
- {
- common->private_data_ptrs[(accelerated_start + 1) - common->start] = ((*private_data_start) << 3) | type_fail_range;
+ count = 4;
+ }
+ else
+ {
+ common->private_data_ptrs[(accelerated_start + 1) - common->start] = ((*private_data_start) << 3) | type_fail_range;
- if (common->early_fail_start_ptr == 0)
- common->early_fail_start_ptr = *private_data_start;
+ if (common->early_fail_start_ptr == 0)
+ common->early_fail_start_ptr = *private_data_start;
- *private_data_start += 2 * sizeof(sljit_sw);
- common->early_fail_end_ptr = *private_data_start;
+ *private_data_start += 2 * sizeof(sljit_sw);
+ common->early_fail_end_ptr = *private_data_start;
- if (*private_data_start > SLJIT_MAX_LOCAL_SIZE)
- return EARLY_FAIL_ENHANCE_MAX;
- }
+ if (*private_data_start > SLJIT_MAX_LOCAL_SIZE)
+ return EARLY_FAIL_ENHANCE_MAX;
- /* Cannot be part of a repeat. */
- common->private_data_ptrs[begin - common->start] = 1;
count++;
-
- if (count < EARLY_FAIL_ENHANCE_MAX)
- continue;
}
- break;
+ /* Cannot be part of a repeat. */
+ common->private_data_ptrs[begin - common->start] = 1;
+
+ if (count >= EARLY_FAIL_ENHANCE_MAX)
+ break;
}
if (*cc != OP_ALT && *cc != OP_KET)
@@ -1795,7 +1881,6 @@ while (cc < ccend)
case OP_ASSERTBACK:
case OP_ASSERTBACK_NOT:
case OP_ASSERT_NA:
- case OP_ASSERTBACK_NA:
case OP_ONCE:
case OP_SCRIPT_RUN:
case OP_BRAPOS:
@@ -1807,6 +1892,19 @@ while (cc < ccend)
bracketlen = 1 + LINK_SIZE;
break;
+ case OP_ASSERTBACK_NA:
+ common->private_data_ptrs[cc - common->start] = private_data_ptr;
+ private_data_ptr += sizeof(sljit_sw);
+
+ if (find_vreverse(cc))
+ {
+ common->private_data_ptrs[cc + 1 - common->start] = 1;
+ private_data_ptr += sizeof(sljit_sw);
+ }
+
+ bracketlen = 1 + LINK_SIZE;
+ break;
+
case OP_CBRAPOS:
case OP_SCBRAPOS:
common->private_data_ptrs[cc - common->start] = private_data_ptr;
@@ -2106,6 +2204,9 @@ while (cc < ccend)
case OP_CALLOUT:
case OP_CALLOUT_STR:
+ case OP_NOT_UCP_WORD_BOUNDARY:
+ case OP_UCP_WORD_BOUNDARY:
+
cc = next_opcode(common, cc);
SLJIT_ASSERT(cc != NULL);
break;
@@ -2261,7 +2362,7 @@ int i;
for (i = 0; i < RECURSE_TMP_REG_COUNT; i++)
{
SLJIT_ASSERT(status->tmp_regs[i] >= 0);
- SLJIT_ASSERT(sljit_get_register_index(status->saved_tmp_regs[i]) < 0 || status->tmp_regs[i] == status->saved_tmp_regs[i]);
+ SLJIT_ASSERT(sljit_get_register_index(SLJIT_GP_REGISTER, status->saved_tmp_regs[i]) < 0 || status->tmp_regs[i] == status->saved_tmp_regs[i]);
status->store_bases[i] = -1;
}
@@ -2281,7 +2382,7 @@ SLJIT_ASSERT(load_base > 0 && store_base > 0);
if (status->store_bases[next_tmp_reg] == -1)
{
/* Preserve virtual registers. */
- if (sljit_get_register_index(status->saved_tmp_regs[next_tmp_reg]) < 0)
+ if (sljit_get_register_index(SLJIT_GP_REGISTER, status->saved_tmp_regs[next_tmp_reg]) < 0)
OP1(SLJIT_MOV, status->saved_tmp_regs[next_tmp_reg], 0, tmp_reg, 0);
}
else
@@ -2310,7 +2411,7 @@ for (i = 0; i < RECURSE_TMP_REG_COUNT; i++)
OP1(SLJIT_MOV, SLJIT_MEM1(status->store_bases[next_tmp_reg]), status->store_offsets[next_tmp_reg], tmp_reg, 0);
/* Restore virtual registers. */
- if (sljit_get_register_index(saved_tmp_reg) < 0)
+ if (sljit_get_register_index(SLJIT_GP_REGISTER, saved_tmp_reg) < 0)
OP1(SLJIT_MOV, tmp_reg, 0, saved_tmp_reg, 0);
}
@@ -3047,8 +3148,16 @@ if (*cc == OP_COND || *cc == OP_SCOND)
has_alternatives = FALSE;
cc = next_opcode(common, cc);
+
if (has_alternatives)
+ {
+ if (*cc == OP_REVERSE)
+ cc += 1 + IMM2_SIZE;
+ else if (*cc == OP_VREVERSE)
+ cc += 1 + 2 * IMM2_SIZE;
+
current_offset = common->then_offsets + (cc - common->start);
+ }
while (cc < end)
{
@@ -3057,7 +3166,18 @@ while (cc < end)
else
{
if (*cc == OP_ALT && has_alternatives)
- current_offset = common->then_offsets + (cc + 1 + LINK_SIZE - common->start);
+ {
+ cc += 1 + LINK_SIZE;
+
+ if (*cc == OP_REVERSE)
+ cc += 1 + IMM2_SIZE;
+ else if (*cc == OP_VREVERSE)
+ cc += 1 + 2 * IMM2_SIZE;
+
+ current_offset = common->then_offsets + (cc - common->start);
+ continue;
+ }
+
if (*cc >= OP_THEN && *cc <= OP_THEN_ARG && current_offset != NULL)
*current_offset = 1;
cc = next_opcode(common, cc);
@@ -3081,7 +3201,7 @@ return (value & (value - 1)) == 0;
static SLJIT_INLINE void set_jumps(jump_list *list, struct sljit_label *label)
{
-while (list)
+while (list != NULL)
{
/* sljit_set_label is clever enough to do nothing
if either the jump or the label is NULL. */
@@ -3239,7 +3359,7 @@ if (size == sizeof(sljit_sw))
return;
}
-if (sljit_get_register_index(TMP3) >= 0 && !sljit_has_cpu_feature(SLJIT_HAS_ZERO_REGISTER))
+if (sljit_get_register_index(SLJIT_GP_REGISTER, TMP3) >= 0 && !sljit_has_cpu_feature(SLJIT_HAS_ZERO_REGISTER))
{
OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, 0);
src = TMP3;
@@ -3818,9 +3938,9 @@ if (common->invalid_utf)
{
OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800);
OP2U(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x110000);
- CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, INVALID_UTF_CHAR);
+ SELECT(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, INVALID_UTF_CHAR, TMP1);
OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP2, 0, SLJIT_IMM, 0xe000 - 0xd800);
- CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, INVALID_UTF_CHAR);
+ SELECT(SLJIT_LESS, TMP1, SLJIT_IMM, INVALID_UTF_CHAR, TMP1);
}
}
#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */
@@ -4058,9 +4178,9 @@ if (common->utf)
OP2(SLJIT_ADD, RETURN_ADDR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP2, 0, SLJIT_IMM, 0x400);
if (options & READ_CHAR_UPDATE_STR_PTR)
- CMOV(SLJIT_LESS, STR_PTR, RETURN_ADDR, 0);
+ SELECT(SLJIT_LESS, STR_PTR, RETURN_ADDR, 0, STR_PTR);
if (max >= 0xd800)
- CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, 0x10000);
+ SELECT(SLJIT_LESS, TMP1, SLJIT_IMM, 0x10000, TMP1);
}
else
{
@@ -4085,15 +4205,46 @@ if (common->invalid_utf)
{
OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800);
OP2U(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x110000);
- CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, INVALID_UTF_CHAR);
+ SELECT(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, INVALID_UTF_CHAR, TMP1);
OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP2, 0, SLJIT_IMM, 0xe000 - 0xd800);
- CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, INVALID_UTF_CHAR);
+ SELECT(SLJIT_LESS, TMP1, SLJIT_IMM, INVALID_UTF_CHAR, TMP1);
}
}
#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */
#endif /* SUPPORT_UNICODE */
}
+static void skip_valid_char(compiler_common *common)
+{
+DEFINE_COMPILER;
+#if (defined SUPPORT_UNICODE) && (PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16)
+struct sljit_jump *jump;
+#endif
+
+#if (defined SUPPORT_UNICODE) && (PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16)
+ 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 PCRE2_CODE_UNIT_WIDTH == 8
+ jump = 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 PCRE2_CODE_UNIT_WIDTH == 16
+ jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xd800);
+ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00);
+ OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0xd800);
+ OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+ JUMPHERE(jump);
+ return;
+ }
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == [8|16] */
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+}
+
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
static BOOL is_char7_bitset(const sljit_u8 *bitset, BOOL nclass)
@@ -4135,6 +4286,7 @@ if (negated)
if (common->invalid_utf)
{
+ OP1(SLJIT_MOV, TMP1, 0, TMP2, 0);
add_jump(compiler, &common->utfreadchar_invalid, JUMP(SLJIT_FAST_CALL));
add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR));
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
@@ -4242,7 +4394,7 @@ if (common->utf && negated)
{
OP2(SLJIT_ADD, RETURN_ADDR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP2, 0, SLJIT_IMM, 0x400);
- CMOV(SLJIT_LESS, STR_PTR, RETURN_ADDR, 0);
+ SELECT(SLJIT_LESS, STR_PTR, RETURN_ADDR, 0, STR_PTR);
}
else
{
@@ -4399,7 +4551,7 @@ of the character (>= 0xc0). Return char value in TMP1. */
DEFINE_COMPILER;
struct sljit_jump *jump;
-sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, RETURN_ADDR, 0);
OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
@@ -4445,7 +4597,7 @@ DEFINE_COMPILER;
struct sljit_jump *jump;
struct sljit_jump *compare;
-sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, RETURN_ADDR, 0);
OP2U(SLJIT_AND | SLJIT_SET_Z, TMP2, 0, SLJIT_IMM, 0x20);
jump = JUMP(SLJIT_NOT_ZERO);
@@ -4487,7 +4639,7 @@ struct sljit_label *three_byte_entry;
struct sljit_label *exit_invalid_label;
struct sljit_jump *exit_invalid[11];
-sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, RETURN_ADDR, 0);
OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc2);
@@ -4522,7 +4674,7 @@ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
if (has_cmov)
{
OP2U(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40);
- CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, 0x20000);
+ SELECT(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, 0x20000, TMP1);
exit_invalid[2] = NULL;
}
else
@@ -4537,7 +4689,7 @@ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x2d800);
if (has_cmov)
{
OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP1, 0, SLJIT_IMM, 0x800);
- CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, INVALID_UTF_CHAR - 0xd800);
+ SELECT(SLJIT_LESS, TMP1, SLJIT_IMM, INVALID_UTF_CHAR - 0xd800, TMP1);
exit_invalid[3] = NULL;
}
else
@@ -4548,7 +4700,7 @@ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
if (has_cmov)
{
OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP1, 0, SLJIT_IMM, 0x800);
- CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, INVALID_UTF_CHAR);
+ SELECT(SLJIT_LESS, TMP1, SLJIT_IMM, INVALID_UTF_CHAR, TMP1);
exit_invalid[4] = NULL;
}
else
@@ -4565,7 +4717,7 @@ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
if (has_cmov)
{
OP2U(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40);
- CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, 0);
+ SELECT(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, 0, TMP1);
exit_invalid[5] = NULL;
}
else
@@ -4575,7 +4727,7 @@ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc10000);
if (has_cmov)
{
OP2U(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x100000);
- CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, INVALID_UTF_CHAR - 0x10000);
+ SELECT(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, INVALID_UTF_CHAR - 0x10000, TMP1);
exit_invalid[6] = NULL;
}
else
@@ -4612,7 +4764,7 @@ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
if (has_cmov)
{
OP2U(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, TMP2, 0, SLJIT_IMM, 0x40);
- CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, INVALID_UTF_CHAR);
+ SELECT(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, INVALID_UTF_CHAR, TMP1);
exit_invalid[10] = NULL;
}
else
@@ -4643,7 +4795,7 @@ struct sljit_label *skip_start;
struct sljit_label *three_byte_exit;
struct sljit_jump *jump[5];
-sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, RETURN_ADDR, 0);
if (common->nltype != NLTYPE_ANY)
{
@@ -4734,7 +4886,7 @@ struct sljit_label *exit_ok_label;
struct sljit_label *exit_invalid_label;
struct sljit_jump *exit_invalid[7];
-sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, RETURN_ADDR, 0);
OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(3));
exit_invalid[0] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0xc0);
@@ -4825,7 +4977,7 @@ static void do_utfpeakcharback(compiler_common *common)
DEFINE_COMPILER;
struct sljit_jump *jump[2];
-sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, RETURN_ADDR, 0);
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2));
OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0);
@@ -4868,7 +5020,7 @@ struct sljit_label *three_byte_entry;
struct sljit_label *exit_invalid_label;
struct sljit_jump *exit_invalid[8];
-sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, RETURN_ADDR, 0);
OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(3));
exit_invalid[0] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0xc0);
@@ -4905,7 +5057,7 @@ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xd800);
if (has_cmov)
{
OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP1, 0, SLJIT_IMM, 0x800);
- CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, -0xd800);
+ SELECT(SLJIT_LESS, TMP1, SLJIT_IMM, -0xd800, TMP1);
exit_invalid[2] = NULL;
}
else
@@ -4915,7 +5067,7 @@ OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xd800);
if (has_cmov)
{
OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP1, 0, SLJIT_IMM, 0x800);
- CMOV(SLJIT_LESS, TMP1, SLJIT_IMM, INVALID_UTF_CHAR);
+ SELECT(SLJIT_LESS, TMP1, SLJIT_IMM, INVALID_UTF_CHAR, TMP1);
exit_invalid[3] = NULL;
}
else
@@ -4940,7 +5092,7 @@ OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
if (has_cmov)
{
OP2U(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0x100000);
- CMOV(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, INVALID_UTF_CHAR - 0x10000);
+ SELECT(SLJIT_GREATER_EQUAL, TMP1, SLJIT_IMM, INVALID_UTF_CHAR - 0x10000, TMP1);
exit_invalid[5] = NULL;
}
else
@@ -5000,7 +5152,7 @@ undefined for invalid characters. */
DEFINE_COMPILER;
struct sljit_jump *exit_invalid[3];
-sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, RETURN_ADDR, 0);
/* TMP2 contains the high surrogate. */
exit_invalid[0] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0xdc00);
@@ -5033,7 +5185,7 @@ char value in TMP1. */
DEFINE_COMPILER;
struct sljit_jump *exit_invalid[2];
-sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, RETURN_ADDR, 0);
/* TMP2 contains the high surrogate. */
exit_invalid[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
@@ -5062,7 +5214,7 @@ static void do_utfmoveback_invalid(compiler_common *common)
DEFINE_COMPILER;
struct sljit_jump *exit_invalid[3];
-sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, RETURN_ADDR, 0);
exit_invalid[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0x400);
exit_invalid[1] = CMP(SLJIT_GREATER_EQUAL, TMP2, 0, STR_PTR, 0);
@@ -5091,7 +5243,7 @@ DEFINE_COMPILER;
struct sljit_jump *jump;
struct sljit_jump *exit_invalid[3];
-sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, RETURN_ADDR, 0);
jump = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 0xe000);
OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1));
@@ -5140,7 +5292,7 @@ SLJIT_ASSERT(record->caseset == 0 && record->other_case == 0);
SLJIT_ASSERT(UCD_BLOCK_SIZE == 128 && sizeof(ucd_record) == 12);
-sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, RETURN_ADDR, 0);
#if PCRE2_CODE_UNIT_WIDTH == 32
if (!common->utf)
@@ -5180,7 +5332,7 @@ SLJIT_ASSERT(record->caseset == 0 && record->other_case == 0);
SLJIT_ASSERT(UCD_BLOCK_SIZE == 128 && sizeof(ucd_record) == 12);
-sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, RETURN_ADDR, 0);
#if PCRE2_CODE_UNIT_WIDTH == 32
if (!common->utf)
@@ -5379,7 +5531,7 @@ else if (common->utf)
{
OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP1, 0, SLJIT_IMM, 0x400);
- CMOV(SLJIT_LESS, STR_PTR, TMP2, 0);
+ SELECT(SLJIT_LESS, STR_PTR, TMP2, 0, STR_PTR);
}
else
{
@@ -5486,6 +5638,8 @@ while (TRUE)
case OP_CIRCM:
case OP_DOLL:
case OP_DOLLM:
+ case OP_NOT_UCP_WORD_BOUNDARY:
+ case OP_UCP_WORD_BOUNDARY:
/* Zero width assertions. */
cc++;
continue;
@@ -5869,6 +6023,7 @@ static BOOL check_fast_forward_char_pair_simd(compiler_common *common, fast_forw
{
sljit_s32 i, j, max_i = 0, max_j = 0;
sljit_u32 max_pri = 0;
+ sljit_s32 max_offset = max_fast_forward_char_pair_offset();
PCRE2_UCHAR a1, a2, a_pri, b1, b2, b_pri;
for (i = max - 1; i >= 1; i--)
@@ -5879,7 +6034,7 @@ static BOOL check_fast_forward_char_pair_simd(compiler_common *common, fast_forw
a2 = chars[i].chars[1];
a_pri = chars[i].last_count;
- j = i - max_fast_forward_char_pair_offset();
+ j = i - max_offset;
if (j < 0)
j = 0;
@@ -5935,7 +6090,7 @@ if (has_match_end)
OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(offset + 1));
OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_END, 0, TMP1, 0);
- CMOV(SLJIT_GREATER, STR_END, TMP1, 0);
+ SELECT(SLJIT_GREATER, STR_END, TMP1, 0, STR_END);
}
#ifdef JIT_HAS_FAST_FORWARD_CHAR_SIMD
@@ -6138,7 +6293,7 @@ if (common->match_end_ptr != 0)
OP2(SLJIT_SUB | SLJIT_SET_LESS, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max));
add_jump(compiler, &common->failed_match, JUMP(SLJIT_LESS));
OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_END, 0, TMP1, 0);
- CMOV(SLJIT_GREATER, STR_END, TMP1, 0);
+ SELECT(SLJIT_GREATER, STR_END, TMP1, 0, STR_END);
}
else
{
@@ -6368,7 +6523,7 @@ if (JIT_HAS_FAST_FORWARD_CHAR_SIMD && (common->nltype == NLTYPE_FIXED || common-
if (common->mode != PCRE2_JIT_COMPLETE)
{
OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_PTR, 0, STR_END, 0);
- CMOV(SLJIT_GREATER, STR_PTR, STR_END, 0);
+ SELECT(SLJIT_GREATER, STR_PTR, STR_END, 0, STR_PTR);
}
}
}
@@ -6430,7 +6585,7 @@ if (common->match_end_ptr != 0)
OP1(SLJIT_MOV, RETURN_ADDR, 0, STR_END, 0);
OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1));
OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_END, 0, TMP1, 0);
- CMOV(SLJIT_GREATER, STR_END, TMP1, 0);
+ SELECT(SLJIT_GREATER, STR_END, TMP1, 0, STR_END);
}
start = LABEL();
@@ -6567,13 +6722,14 @@ DEFINE_COMPILER;
struct sljit_jump *jump;
struct sljit_label *mainloop;
-sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, RETURN_ADDR, 0);
GET_LOCAL_BASE(TMP1, 0, 0);
/* Drop frames until we reach STACK_TOP. */
mainloop = LABEL();
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), -SSIZE_OF(sw));
-jump = CMP(SLJIT_SIG_LESS_EQUAL, TMP2, 0, SLJIT_IMM, 0);
+OP2U(SLJIT_SUB | SLJIT_SET_SIG_LESS_EQUAL | SLJIT_SET_Z, TMP2, 0, SLJIT_IMM, 0);
+jump = JUMP(SLJIT_SIG_LESS_EQUAL);
OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0);
if (HAS_VIRTUAL_REGISTERS)
@@ -6594,7 +6750,8 @@ else
JUMPTO(SLJIT_JUMP, mainloop);
JUMPHERE(jump);
-jump = CMP(SLJIT_NOT_ZERO /* SIG_LESS */, TMP2, 0, SLJIT_IMM, 0);
+sljit_set_current_flags(compiler, SLJIT_CURRENT_FLAGS_SUB | SLJIT_CURRENT_FLAGS_COMPARE | SLJIT_SET_SIG_LESS_EQUAL | SLJIT_SET_Z);
+jump = JUMP(SLJIT_NOT_ZERO /* SIG_LESS */);
/* End of reverting values. */
OP_SRC(SLJIT_FAST_RETURN, RETURN_ADDR, 0);
@@ -6615,7 +6772,17 @@ else
JUMPTO(SLJIT_JUMP, mainloop);
}
-static void check_wordboundary(compiler_common *common)
+#ifdef SUPPORT_UNICODE
+#define UCPCAT(bit) (1 << (bit))
+#define UCPCAT2(bit1, bit2) (UCPCAT(bit1) | UCPCAT(bit2))
+#define UCPCAT3(bit1, bit2, bit3) (UCPCAT(bit1) | UCPCAT(bit2) | UCPCAT(bit3))
+#define UCPCAT_RANGE(start, end) (((1 << ((end) + 1)) - 1) - ((1 << (start)) - 1))
+#define UCPCAT_L UCPCAT_RANGE(ucp_Ll, ucp_Lu)
+#define UCPCAT_N UCPCAT_RANGE(ucp_Nd, ucp_No)
+#define UCPCAT_ALL ((1 << (ucp_Zs + 1)) - 1)
+#endif
+
+static void check_wordboundary(compiler_common *common, BOOL ucp)
{
DEFINE_COMPILER;
struct sljit_jump *skipread;
@@ -6629,9 +6796,10 @@ jump_list *invalid_utf2 = NULL;
struct sljit_jump *jump;
#endif /* PCRE2_CODE_UNIT_WIDTH != 8 || SUPPORT_UNICODE */
+SLJIT_UNUSED_ARG(ucp);
SLJIT_COMPILE_ASSERT(ctype_word == 0x10, ctype_word_must_be_16);
-sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, SLJIT_MEM1(SLJIT_SP), LOCALS0);
/* Get type of the previous char, and put it to TMP3. */
OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
@@ -6668,19 +6836,12 @@ else
/* Testing char type. */
#ifdef SUPPORT_UNICODE
-if (common->ucp)
+if (ucp)
{
- OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 1);
- jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_UNDERSCORE);
add_jump(compiler, &common->getucdtype, JUMP(SLJIT_FAST_CALL));
- OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Ll);
- OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll);
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
- OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Nd - ucp_Ll);
- OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd);
- OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
- JUMPHERE(jump);
- OP1(SLJIT_MOV, TMP3, 0, TMP2, 0);
+ OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP1, 0);
+ OP2U(SLJIT_AND | SLJIT_SET_Z, TMP2, 0, SLJIT_IMM, UCPCAT2(ucp_Mn, ucp_Pc) | UCPCAT_L | UCPCAT_N);
+ OP_FLAGS(SLJIT_MOV, TMP3, 0, SLJIT_NOT_ZERO);
}
else
#endif /* SUPPORT_UNICODE */
@@ -6714,18 +6875,12 @@ peek_char(common, READ_CHAR_MAX, SLJIT_MEM1(SLJIT_SP), LOCALS1, &invalid_utf2);
valid_utf = LABEL();
-if (common->ucp)
+if (ucp)
{
- OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 1);
- jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_UNDERSCORE);
add_jump(compiler, &common->getucdtype, JUMP(SLJIT_FAST_CALL));
- OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Ll);
- OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll);
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
- OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Nd - ucp_Ll);
- OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd);
- OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
- JUMPHERE(jump);
+ OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP1, 0);
+ OP2U(SLJIT_AND | SLJIT_SET_Z, TMP2, 0, SLJIT_IMM, UCPCAT2(ucp_Mn, ucp_Pc) | UCPCAT_L | UCPCAT_N);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_NOT_ZERO);
}
else
#endif /* SUPPORT_UNICODE */
@@ -7003,7 +7158,7 @@ while (i < len)
else
{
OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, char_list[i]);
- CMOV(SLJIT_ZERO, TMP2, TMP1, 0);
+ SELECT(SLJIT_ZERO, TMP2, TMP1, 0, TMP2);
}
i++;
}
@@ -7017,7 +7172,7 @@ if (j != 0)
{
j--;
OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, char_list[i] & 0xff);
- CMOV(SLJIT_ZERO, TMP2, TMP1, 0);
+ SELECT(SLJIT_ZERO, TMP2, TMP1, 0, TMP2);
}
}
@@ -7042,7 +7197,7 @@ static void check_anynewline(compiler_common *common)
/* Check whether TMP1 contains a newline character. TMP2 destroyed. */
DEFINE_COMPILER;
-sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, RETURN_ADDR, 0);
OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0a);
OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a);
@@ -7069,7 +7224,7 @@ static void check_hspace(compiler_common *common)
/* Check whether TMP1 contains a newline character. TMP2 destroyed. */
DEFINE_COMPILER;
-sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, RETURN_ADDR, 0);
OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x09);
OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
@@ -7108,7 +7263,7 @@ static void check_vspace(compiler_common *common)
/* Check whether TMP1 contains a newline character. TMP2 destroyed. */
DEFINE_COMPILER;
-sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, RETURN_ADDR, 0);
OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0a);
OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a);
@@ -7150,7 +7305,7 @@ else
char2_reg = RETURN_ADDR;
}
-sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, SLJIT_MEM1(SLJIT_SP), LOCALS0);
OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
if (char1_reg == STR_END)
@@ -7237,7 +7392,7 @@ if (sljit_emit_mem_update(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_POST,
else if (sljit_emit_mem_update(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS)
opt_type = 2;
-sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, SLJIT_MEM1(SLJIT_SP), LOCALS0);
OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, char1_reg, 0);
@@ -7464,16 +7619,6 @@ return cc;
#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
-#define SET_TYPE_OFFSET(value) \
- if ((value) != typeoffset) \
- { \
- if ((value) < typeoffset) \
- OP2(SLJIT_ADD, typereg, 0, typereg, 0, SLJIT_IMM, typeoffset - (value)); \
- else \
- OP2(SLJIT_SUB, typereg, 0, typereg, 0, SLJIT_IMM, (value) - typeoffset); \
- } \
- typeoffset = (value);
-
#define SET_CHAR_OFFSET(value) \
if ((value) != charoffset) \
{ \
@@ -7498,7 +7643,6 @@ static PCRE2_SPTR compile_char1_matchingpath(compiler_common *common, PCRE2_UCHA
#define XCLASS_SCRIPT_EXTENSION_NOTPROP 0x080
#define XCLASS_SCRIPT_EXTENSION_RESTORE_RETURN_ADDR 0x100
#define XCLASS_SCRIPT_EXTENSION_RESTORE_LOCALS0 0x200
-
#endif /* SUPPORT_UNICODE */
static void compile_xclass_matchingpath(compiler_common *common, PCRE2_SPTR cc, jump_list **backtracks)
@@ -7516,9 +7660,10 @@ BOOL utf = common->utf;
#ifdef SUPPORT_UNICODE
sljit_u32 unicode_status = 0;
+sljit_u32 category_list = 0;
+sljit_u32 items;
int typereg = TMP1;
const sljit_u32 *other_cases;
-sljit_uw typeoffset;
#endif /* SUPPORT_UNICODE */
/* Scanning the necessary info. */
@@ -7535,6 +7680,7 @@ if (cc[-1] & XCL_MAP)
while (*cc != XCL_END)
{
compares++;
+
if (*cc == XCL_SINGLE)
{
cc ++;
@@ -7561,6 +7707,7 @@ while (*cc != XCL_END)
{
SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP);
cc++;
+
if (*cc == PT_CLIST && cc[-1] == XCL_PROP)
{
other_cases = PRIV(ucd_caseless_sets) + cc[1];
@@ -7577,24 +7724,36 @@ while (*cc != XCL_END)
min = 0;
}
+ items = 0;
+
switch(*cc)
{
case PT_ANY:
/* Any either accepts everything or ignored. */
if (cc[-1] == XCL_PROP)
- {
- compile_char1_matchingpath(common, OP_ALLANY, cc, backtracks, FALSE);
- if (list == backtracks)
- add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
- return;
- }
+ items = UCPCAT_ALL;
+ else
+ compares--;
break;
case PT_LAMP:
+ items = UCPCAT3(ucp_Lu, ucp_Ll, ucp_Lt);
+ break;
+
case PT_GC:
+ items = UCPCAT_RANGE(PRIV(ucp_typerange)[(int)cc[1] * 2], PRIV(ucp_typerange)[(int)cc[1] * 2 + 1]);
+ break;
+
case PT_PC:
+ items = UCPCAT(cc[1]);
+ break;
+
+ case PT_WORD:
+ items = UCPCAT2(ucp_Mn, ucp_Pc) | UCPCAT_L | UCPCAT_N;
+ break;
+
case PT_ALNUM:
- unicode_status |= XCLASS_HAS_TYPE;
+ items = UCPCAT_L | UCPCAT_N;
break;
case PT_SCX:
@@ -7613,7 +7772,6 @@ while (*cc != XCL_END)
case PT_SPACE:
case PT_PXSPACE:
- case PT_WORD:
case PT_PXGRAPH:
case PT_PXPRINT:
case PT_PXPUNCT:
@@ -7622,6 +7780,7 @@ while (*cc != XCL_END)
case PT_CLIST:
case PT_UCNC:
+ case PT_PXXDIGIT:
unicode_status |= XCLASS_SAVE_CHAR;
break;
@@ -7637,11 +7796,42 @@ while (*cc != XCL_END)
SLJIT_UNREACHABLE();
break;
}
+
+ if (items > 0)
+ {
+ if (cc[-1] == XCL_NOTPROP)
+ items ^= UCPCAT_ALL;
+ category_list |= items;
+ unicode_status |= XCLASS_HAS_TYPE;
+ compares--;
+ }
+
cc += 2;
}
#endif /* SUPPORT_UNICODE */
}
+
+#ifdef SUPPORT_UNICODE
+if (category_list == UCPCAT_ALL)
+ {
+ /* All characters are accepted, same as dotall. */
+ compile_char1_matchingpath(common, OP_ALLANY, cc, backtracks, FALSE);
+ if (list == backtracks)
+ add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+ return;
+ }
+
+if (compares == 0 && category_list == 0)
+ {
+ /* No characters are accepted, same as (*F) or dotall. */
+ compile_char1_matchingpath(common, OP_ALLANY, cc, backtracks, FALSE);
+ if (list != backtracks)
+ add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+ return;
+ }
+#else /* !SUPPORT_UNICODE */
SLJIT_ASSERT(compares > 0);
+#endif /* SUPPORT_UNICODE */
/* We are not necessary in utf mode even in 8 bit mode. */
cc = ccbegin;
@@ -7742,6 +7932,9 @@ if (unicode_status & XCLASS_NEEDS_UCD)
ccbegin = cc;
+ if (category_list != 0)
+ compares++;
+
if (unicode_status & XCLASS_HAS_BIDICL)
{
OP1(SLJIT_MOV_U16, TMP1, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, scriptx_bidiclass));
@@ -7946,7 +8139,16 @@ if (unicode_status & XCLASS_NEEDS_UCD)
if (unicode_status & XCLASS_SAVE_CHAR)
typereg = RETURN_ADDR;
- OP1(SLJIT_MOV_U8, typereg, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, chartype));
+ OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, chartype));
+ OP2(SLJIT_SHL, typereg, 0, SLJIT_IMM, 1, TMP2, 0);
+
+ if (category_list > 0)
+ {
+ compares--;
+ invertcmp = (compares == 0 && list != backtracks);
+ OP2U(SLJIT_AND | SLJIT_SET_Z, typereg, 0, SLJIT_IMM, category_list);
+ add_jump(compiler, compares > 0 ? list : backtracks, JUMP(SLJIT_NOT_ZERO ^ invertcmp));
+ }
}
}
#endif /* SUPPORT_UNICODE */
@@ -7954,9 +8156,6 @@ if (unicode_status & XCLASS_NEEDS_UCD)
/* Generating code. */
charoffset = 0;
numberofcmps = 0;
-#ifdef SUPPORT_UNICODE
-typeoffset = 0;
-#endif /* SUPPORT_UNICODE */
while (*cc != XCL_END)
{
@@ -8024,36 +8223,17 @@ while (*cc != XCL_END)
switch(*cc)
{
case PT_ANY:
- if (!invertcmp)
- jump = JUMP(SLJIT_JUMP);
- break;
-
case PT_LAMP:
- OP2U(SLJIT_SUB | SLJIT_SET_Z, typereg, 0, SLJIT_IMM, ucp_Lu - typeoffset);
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
- OP2U(SLJIT_SUB | SLJIT_SET_Z, typereg, 0, SLJIT_IMM, ucp_Ll - typeoffset);
- OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
- OP2U(SLJIT_SUB | SLJIT_SET_Z, typereg, 0, SLJIT_IMM, ucp_Lt - typeoffset);
- OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL);
- jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
- break;
-
case PT_GC:
- c = PRIV(ucp_typerange)[(int)cc[1] * 2];
- SET_TYPE_OFFSET(c);
- jump = CMP(SLJIT_LESS_EQUAL ^ invertcmp, typereg, 0, SLJIT_IMM, PRIV(ucp_typerange)[(int)cc[1] * 2 + 1] - c);
- break;
-
case PT_PC:
- jump = CMP(SLJIT_EQUAL ^ invertcmp, typereg, 0, SLJIT_IMM, (int)cc[1] - typeoffset);
- break;
-
case PT_SC:
case PT_SCX:
case PT_BOOL:
case PT_BIDICL:
+ case PT_WORD:
+ case PT_ALNUM:
compares++;
- /* Do nothing. */
+ /* Already handled. */
break;
case PT_SPACE:
@@ -8068,24 +8248,8 @@ while (*cc != XCL_END)
OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x180e - 0x9);
OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
- SET_TYPE_OFFSET(ucp_Zl);
- OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Zl);
- OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL);
- jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
- break;
-
- case PT_WORD:
- OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_UNDERSCORE - charoffset));
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
- /* Fall through. */
-
- case PT_ALNUM:
- SET_TYPE_OFFSET(ucp_Ll);
- OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, typereg, 0, SLJIT_IMM, ucp_Lu - ucp_Ll);
- OP_FLAGS((*cc == PT_ALNUM) ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
- SET_TYPE_OFFSET(ucp_Nd);
- OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, typereg, 0, SLJIT_IMM, ucp_No - ucp_Nd);
- OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL);
+ OP2U(SLJIT_AND | SLJIT_SET_Z, typereg, 0, SLJIT_IMM, UCPCAT_RANGE(ucp_Zl, ucp_Zs));
+ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_NOT_ZERO);
jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
break;
@@ -8160,13 +8324,13 @@ while (*cc != XCL_END)
break;
case PT_PXGRAPH:
- /* C and Z groups are the farthest two groups. */
- SET_TYPE_OFFSET(ucp_Ll);
- OP2U(SLJIT_SUB | SLJIT_SET_GREATER, typereg, 0, SLJIT_IMM, ucp_So - ucp_Ll);
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_GREATER);
+ OP2U(SLJIT_AND | SLJIT_SET_Z, typereg, 0, SLJIT_IMM, UCPCAT_RANGE(ucp_Cc, ucp_Cs) | UCPCAT_RANGE(ucp_Zl, ucp_Zs));
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_NOT_ZERO);
- jump = CMP(SLJIT_NOT_EQUAL, typereg, 0, SLJIT_IMM, ucp_Cf - ucp_Ll);
+ OP2U(SLJIT_AND | SLJIT_SET_Z, typereg, 0, SLJIT_IMM, UCPCAT(ucp_Cf));
+ jump = JUMP(SLJIT_ZERO);
+ c = charoffset;
/* In case of ucp_Cf, we overwrite the result. */
SET_CHAR_OFFSET(0x2066);
OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, 0x2069 - 0x2066);
@@ -8178,21 +8342,21 @@ while (*cc != XCL_END)
OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x180e - 0x2066);
OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+ /* Restore charoffset. */
+ SET_CHAR_OFFSET(c);
+
JUMPHERE(jump);
jump = CMP(SLJIT_ZERO ^ invertcmp, TMP2, 0, SLJIT_IMM, 0);
break;
case PT_PXPRINT:
- /* C and Z groups are the farthest two groups. */
- SET_TYPE_OFFSET(ucp_Ll);
- OP2U(SLJIT_SUB | SLJIT_SET_GREATER, typereg, 0, SLJIT_IMM, ucp_So - ucp_Ll);
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_GREATER);
+ OP2U(SLJIT_AND | SLJIT_SET_Z, typereg, 0, SLJIT_IMM, UCPCAT_RANGE(ucp_Cc, ucp_Cs) | UCPCAT2(ucp_Zl, ucp_Zp));
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_NOT_ZERO);
- OP2U(SLJIT_SUB | SLJIT_SET_Z, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Ll);
- OP_FLAGS(SLJIT_AND, TMP2, 0, SLJIT_NOT_EQUAL);
-
- jump = CMP(SLJIT_NOT_EQUAL, typereg, 0, SLJIT_IMM, ucp_Cf - ucp_Ll);
+ OP2U(SLJIT_AND | SLJIT_SET_Z, typereg, 0, SLJIT_IMM, UCPCAT(ucp_Cf));
+ jump = JUMP(SLJIT_ZERO);
+ c = charoffset;
/* In case of ucp_Cf, we overwrite the result. */
SET_CHAR_OFFSET(0x2066);
OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, 0x2069 - 0x2066);
@@ -8201,22 +8365,54 @@ while (*cc != XCL_END)
OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0x061c - 0x2066);
OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+ /* Restore charoffset. */
+ SET_CHAR_OFFSET(c);
+
JUMPHERE(jump);
jump = CMP(SLJIT_ZERO ^ invertcmp, TMP2, 0, SLJIT_IMM, 0);
break;
case PT_PXPUNCT:
- SET_TYPE_OFFSET(ucp_Sc);
- OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, typereg, 0, SLJIT_IMM, ucp_So - ucp_Sc);
- OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+ OP2U(SLJIT_AND | SLJIT_SET_Z, typereg, 0, SLJIT_IMM, UCPCAT_RANGE(ucp_Sc, ucp_So));
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_NOT_ZERO);
SET_CHAR_OFFSET(0);
OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, 0x7f);
OP_FLAGS(SLJIT_AND, TMP2, 0, SLJIT_LESS_EQUAL);
- SET_TYPE_OFFSET(ucp_Pc);
- OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, typereg, 0, SLJIT_IMM, ucp_Ps - ucp_Pc);
- OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL);
+ OP2U(SLJIT_AND | SLJIT_SET_Z, typereg, 0, SLJIT_IMM, UCPCAT_RANGE(ucp_Pc, ucp_Ps));
+ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_NOT_ZERO);
+ jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
+ break;
+
+ case PT_PXXDIGIT:
+ SET_CHAR_OFFSET(CHAR_A);
+ OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, ~0x20);
+ OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP2, 0, SLJIT_IMM, CHAR_F - CHAR_A);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+
+ SET_CHAR_OFFSET(CHAR_0);
+ OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_9 - CHAR_0);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
+
+ SET_CHAR_OFFSET(0xff10);
+ jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 0xff46 - 0xff10);
+
+ OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, 0xff19 - 0xff10);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
+
+ SET_CHAR_OFFSET(0xff21);
+ OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, 0xff26 - 0xff21);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
+
+ SET_CHAR_OFFSET(0xff41);
+ OP2U(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, TMP1, 0, SLJIT_IMM, 0xff46 - 0xff41);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
+
+ SET_CHAR_OFFSET(0xff10);
+
+ JUMPHERE(jump);
+ OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_IMM, 0);
jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
break;
@@ -8232,6 +8428,7 @@ while (*cc != XCL_END)
add_jump(compiler, compares > 0 ? list : backtracks, jump);
}
+SLJIT_ASSERT(compares == 0);
if (found != NULL)
set_jumps(found, LABEL());
}
@@ -8244,11 +8441,7 @@ if (found != NULL)
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_UNICODE
-struct sljit_label *label;
-#endif /* SUPPORT_UNICODE */
switch(type)
{
@@ -8276,16 +8469,18 @@ switch(type)
case OP_NOT_WORD_BOUNDARY:
case OP_WORD_BOUNDARY:
- add_jump(compiler, &common->wordboundary, JUMP(SLJIT_FAST_CALL));
+ case OP_NOT_UCP_WORD_BOUNDARY:
+ case OP_UCP_WORD_BOUNDARY:
+ add_jump(compiler, (type == OP_NOT_WORD_BOUNDARY || type == OP_WORD_BOUNDARY) ? &common->wordboundary : &common->ucp_wordboundary, JUMP(SLJIT_FAST_CALL));
#ifdef SUPPORT_UNICODE
if (common->invalid_utf)
{
- add_jump(compiler, backtracks, CMP((type == OP_NOT_WORD_BOUNDARY) ? SLJIT_NOT_EQUAL : SLJIT_SIG_LESS_EQUAL, TMP2, 0, SLJIT_IMM, 0));
+ add_jump(compiler, backtracks, CMP((type == OP_NOT_WORD_BOUNDARY || type == OP_NOT_UCP_WORD_BOUNDARY) ? SLJIT_NOT_EQUAL : SLJIT_SIG_LESS_EQUAL, TMP2, 0, SLJIT_IMM, 0));
return cc;
}
#endif /* SUPPORT_UNICODE */
sljit_set_current_flags(compiler, SLJIT_SET_Z);
- add_jump(compiler, backtracks, JUMP(type == OP_NOT_WORD_BOUNDARY ? SLJIT_NOT_ZERO : SLJIT_ZERO));
+ add_jump(compiler, backtracks, JUMP((type == OP_NOT_WORD_BOUNDARY || type == OP_NOT_UCP_WORD_BOUNDARY) ? SLJIT_NOT_ZERO : SLJIT_ZERO));
return cc;
case OP_EODN:
@@ -8481,36 +8676,6 @@ switch(type)
}
JUMPHERE(jump[0]);
return cc;
-
- case OP_REVERSE:
- length = GET(cc, 0);
- if (length == 0)
- return cc + LINK_SIZE;
- if (HAS_VIRTUAL_REGISTERS)
- {
- OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
- OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
- }
- else
- OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin));
-#ifdef SUPPORT_UNICODE
- if (common->utf)
- {
- OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, length);
- label = LABEL();
- add_jump(compiler, backtracks, CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0));
- move_back(common, backtracks, FALSE);
- OP2(SLJIT_SUB | SLJIT_SET_Z, TMP3, 0, TMP3, 0, SLJIT_IMM, 1);
- JUMPTO(SLJIT_NOT_ZERO, label);
- }
- else
-#endif
- {
- OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(length));
- add_jump(compiler, backtracks, CMP(SLJIT_LESS, STR_PTR, 0, TMP2, 0));
- }
- check_start_used_ptr(common);
- return cc + LINK_SIZE;
}
SLJIT_UNREACHABLE();
return cc;
@@ -8667,7 +8832,7 @@ c = *cc++;
#if PCRE2_CODE_UNIT_WIDTH == 32
if (c >= 0x110000)
- return NULL;
+ return cc;
#endif /* PCRE2_CODE_UNIT_WIDTH == 32 */
lgb = UCD_GRAPHBREAK(c);
@@ -8809,35 +8974,14 @@ switch(type)
if (check_str_ptr)
detect_partial_match(common, backtracks);
#ifdef SUPPORT_UNICODE
- if (common->utf)
+ if (common->utf && common->invalid_utf)
{
- if (common->invalid_utf)
- {
- read_char(common, 0, READ_CHAR_MAX, backtracks, READ_CHAR_UPDATE_STR_PTR);
- return cc;
- }
-
-#if PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16
- 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 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 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);
- OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, 0xd800);
- OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL);
- OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
- OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
-#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
- JUMPHERE(jump[0]);
+ read_char(common, 0, READ_CHAR_MAX, backtracks, READ_CHAR_UPDATE_STR_PTR);
return cc;
-#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16] */
}
#endif /* SUPPORT_UNICODE */
- OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+ skip_valid_char(common);
return cc;
case OP_ANYBYTE:
@@ -8928,7 +9072,7 @@ switch(type)
#else
sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS2(W, W, W), SLJIT_IMM,
common->invalid_utf ? SLJIT_FUNC_ADDR(do_extuni_utf_invalid) : SLJIT_FUNC_ADDR(do_extuni_no_utf));
- if (!common->utf || common->invalid_utf)
+ if (common->invalid_utf)
add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0));
#endif
@@ -8990,7 +9134,7 @@ switch(type)
if (sljit_has_cpu_feature(SLJIT_HAS_CMOV))
{
OP2U(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, SLJIT_IMM, oc);
- CMOV(SLJIT_EQUAL, TMP1, SLJIT_IMM, c);
+ SELECT(SLJIT_EQUAL, TMP1, SLJIT_IMM, c, TMP1);
add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, c));
}
else
@@ -9509,14 +9653,16 @@ if (!minimize)
if (ref)
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+
if (ref)
{
- add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)));
+ if (!common->unset_backref)
+ add_jump(compiler, &backtrack->own_backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)));
zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
}
else
{
- compile_dnref_search(common, ccbegin, &backtrack->topbacktracks);
+ compile_dnref_search(common, ccbegin, &backtrack->own_backtracks);
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, TMP2, 0);
zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw));
@@ -9529,7 +9675,7 @@ if (!minimize)
label = LABEL();
if (!ref)
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1);
- compile_ref_matchingpath(common, ccbegin, &backtrack->topbacktracks, FALSE, FALSE);
+ compile_ref_matchingpath(common, ccbegin, &backtrack->own_backtracks, FALSE, FALSE);
if (min > 1 || max > 1)
{
@@ -9591,12 +9737,13 @@ else
{
if (ref)
{
- add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)));
+ if (!common->unset_backref)
+ add_jump(compiler, &backtrack->own_backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)));
zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
}
else
{
- compile_dnref_search(common, ccbegin, &backtrack->topbacktracks);
+ compile_dnref_search(common, ccbegin, &backtrack->own_backtracks);
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP2, 0);
zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw));
@@ -9605,11 +9752,11 @@ else
BACKTRACK_AS(ref_iterator_backtrack)->matchingpath = LABEL();
if (max > 0)
- add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, max));
+ add_jump(compiler, &backtrack->own_backtracks, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, max));
if (!ref)
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(2));
-compile_ref_matchingpath(common, ccbegin, &backtrack->topbacktracks, TRUE, TRUE);
+compile_ref_matchingpath(common, ccbegin, &backtrack->own_backtracks, TRUE, TRUE);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
if (min > 1)
@@ -9684,12 +9831,12 @@ if (entry->entry_label == NULL)
else
JUMPTO(SLJIT_FAST_CALL, entry->entry_label);
/* Leave if the match is failed. */
-add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0));
+add_jump(compiler, &backtrack->own_backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0));
BACKTRACK_AS(recurse_backtrack)->matchingpath = LABEL();
return cc + 1 + LINK_SIZE;
}
-static sljit_s32 SLJIT_FUNC do_callout_jit(struct jit_arguments *arguments, pcre2_callout_block *callout_block, PCRE2_SPTR *jit_ovector)
+static sljit_s32 SLJIT_FUNC SLJIT_FUNC_ATTRIBUTE do_callout_jit(struct jit_arguments *arguments, pcre2_callout_block *callout_block, PCRE2_SPTR *jit_ovector)
{
PCRE2_SPTR begin;
PCRE2_SIZE *ovector;
@@ -9812,7 +9959,7 @@ free_stack(common, callout_arg_size);
/* Check return value. */
OP2U(SLJIT_SUB32 | SLJIT_SET_Z | SLJIT_SET_SIG_GREATER, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
-add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_SIG_GREATER));
+add_jump(compiler, &backtrack->own_backtracks, JUMP(SLJIT_SIG_GREATER));
if (common->abort_label == NULL)
add_jump(compiler, &common->abort, JUMP(SLJIT_NOT_EQUAL) /* SIG_LESS */);
else
@@ -9823,6 +9970,106 @@ return cc + callout_length;
#undef CALLOUT_ARG_SIZE
#undef CALLOUT_ARG_OFFSET
+static PCRE2_SPTR compile_reverse_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+backtrack_common *backtrack = NULL;
+jump_list **reverse_failed;
+unsigned int lmin, lmax;
+#ifdef SUPPORT_UNICODE
+struct sljit_jump *jump;
+struct sljit_label *label;
+#endif
+
+SLJIT_ASSERT(parent->top == NULL);
+
+if (*cc == OP_REVERSE)
+ {
+ reverse_failed = &parent->own_backtracks;
+ lmin = GET2(cc, 1);
+ lmax = lmin;
+ cc += 1 + IMM2_SIZE;
+
+ SLJIT_ASSERT(lmin > 0);
+ }
+else
+ {
+ SLJIT_ASSERT(*cc == OP_VREVERSE);
+ PUSH_BACKTRACK(sizeof(vreverse_backtrack), cc, NULL);
+
+ reverse_failed = &backtrack->own_backtracks;
+ lmin = GET2(cc, 1);
+ lmax = GET2(cc, 1 + IMM2_SIZE);
+ cc += 1 + 2 * IMM2_SIZE;
+
+ SLJIT_ASSERT(lmin < lmax);
+ }
+
+if (HAS_VIRTUAL_REGISTERS)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
+ }
+else
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, begin));
+
+#ifdef SUPPORT_UNICODE
+if (common->utf)
+ {
+ if (lmin > 0)
+ {
+ OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, lmin);
+ label = LABEL();
+ add_jump(compiler, reverse_failed, CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0));
+ move_back(common, reverse_failed, FALSE);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, TMP3, 0, TMP3, 0, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, label);
+ }
+
+ if (lmin < lmax)
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(3), STR_PTR, 0);
+
+ OP1(SLJIT_MOV, TMP3, 0, SLJIT_IMM, lmax - lmin);
+ label = LABEL();
+ jump = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0);
+ move_back(common, reverse_failed, FALSE);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, TMP3, 0, TMP3, 0, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, label);
+
+ JUMPHERE(jump);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), STR_PTR, 0);
+ }
+ }
+else
+#endif
+ {
+ if (lmin > 0)
+ {
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(lmin));
+ add_jump(compiler, reverse_failed, CMP(SLJIT_LESS, STR_PTR, 0, TMP2, 0));
+ }
+
+ if (lmin < lmax)
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(3), STR_PTR, 0);
+
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(lmax - lmin));
+ OP2U(SLJIT_SUB | SLJIT_SET_LESS, STR_PTR, 0, TMP2, 0);
+ SELECT(SLJIT_LESS, STR_PTR, TMP2, 0, STR_PTR);
+
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), STR_PTR, 0);
+ }
+ }
+
+check_start_used_ptr(common);
+
+if (lmin < lmax)
+ BACKTRACK_AS(vreverse_backtrack)->matchingpath = LABEL();
+
+return cc;
+}
+
static SLJIT_INLINE BOOL assert_needs_str_ptr_saving(PCRE2_SPTR cc)
{
while (TRUE)
@@ -9841,6 +10088,8 @@ while (TRUE)
case OP_DOLLM:
case OP_CALLOUT:
case OP_ALT:
+ case OP_NOT_UCP_WORD_BOUNDARY:
+ case OP_UCP_WORD_BOUNDARY:
cc += PRIV(OP_lengths)[*cc];
break;
@@ -9860,13 +10109,15 @@ int framesize;
int extrasize;
BOOL local_quit_available = FALSE;
BOOL needs_control_head;
+BOOL end_block_size = 0;
+BOOL has_vreverse;
int private_data_ptr;
backtrack_common altbacktrack;
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 **target = (conditional) ? &backtrack->condfailed : &backtrack->common.own_backtracks;
jump_list **found;
/* Saving previous accept variables. */
BOOL save_local_quit_available = common->local_quit_available;
@@ -9889,6 +10140,7 @@ if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO)
bra = *cc;
cc++;
}
+
private_data_ptr = PRIVATE_DATA(cc);
SLJIT_ASSERT(private_data_ptr != 0);
framesize = get_framesize(common, cc, NULL, FALSE, &needs_control_head);
@@ -9908,12 +10160,17 @@ if (bra == OP_BRAMINZERO)
brajump = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0);
}
+if ((opcode == OP_ASSERTBACK || opcode == OP_ASSERTBACK_NOT) && find_vreverse(ccbegin))
+ end_block_size = 3;
+
if (framesize < 0)
{
extrasize = 1;
if (bra == OP_BRA && !assert_needs_str_ptr_saving(ccbegin + 1 + LINK_SIZE))
extrasize = 0;
+ extrasize += end_block_size;
+
if (needs_control_head)
extrasize++;
@@ -9931,18 +10188,19 @@ if (framesize < 0)
if (needs_control_head)
{
- SLJIT_ASSERT(extrasize == 2);
+ SLJIT_ASSERT(extrasize == end_block_size + 2);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0);
- OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(end_block_size + 1), TMP1, 0);
}
}
else
{
- extrasize = needs_control_head ? 3 : 2;
+ extrasize = (needs_control_head ? 3 : 2) + end_block_size;
+
+ OP1(SLJIT_MOV, TMP2, 0, STACK_TOP, 0);
allocate_stack(common, framesize + extrasize);
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
- OP2(SLJIT_ADD, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + extrasize) * sizeof(sljit_sw));
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP2, 0);
if (needs_control_head)
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
@@ -9950,16 +10208,22 @@ else
if (needs_control_head)
{
- OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP1, 0);
- OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(end_block_size + 2), TMP1, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(end_block_size + 1), TMP2, 0);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0);
}
else
- OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(end_block_size + 1), TMP1, 0);
init_frame(common, ccbegin, NULL, framesize + extrasize - 1, extrasize);
}
+if (end_block_size > 0)
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), STR_END, 0);
+ OP1(SLJIT_MOV, STR_END, 0, STR_PTR, 0);
+ }
+
memset(&altbacktrack, 0, sizeof(backtrack_common));
if (conditional || (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT))
{
@@ -9978,13 +10242,19 @@ while (1)
common->accept_label = NULL;
common->accept = NULL;
altbacktrack.top = NULL;
- altbacktrack.topbacktracks = NULL;
+ altbacktrack.own_backtracks = NULL;
if (*ccbegin == OP_ALT && extrasize > 0)
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
altbacktrack.cc = ccbegin;
- compile_matchingpath(common, ccbegin + 1 + LINK_SIZE, cc, &altbacktrack);
+ ccbegin += 1 + LINK_SIZE;
+
+ has_vreverse = (*ccbegin == OP_VREVERSE);
+ if (*ccbegin == OP_REVERSE || has_vreverse)
+ ccbegin = compile_reverse_matchingpath(common, ccbegin, &altbacktrack);
+
+ compile_matchingpath(common, ccbegin, cc, &altbacktrack);
if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
{
if (local_quit_available)
@@ -10000,6 +10270,13 @@ while (1)
common->accept = save_accept;
return NULL;
}
+
+ if (has_vreverse)
+ {
+ SLJIT_ASSERT(altbacktrack.top != NULL);
+ add_jump(compiler, &altbacktrack.top->simple_backtracks, CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0));
+ }
+
common->accept_label = LABEL();
if (common->accept != NULL)
set_jumps(common->accept, common->accept_label);
@@ -10012,6 +10289,9 @@ while (1)
else if (extrasize > 0)
free_stack(common, extrasize);
+ if (end_block_size > 0)
+ OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(STACK_TOP), STACK(-extrasize + 1));
+
if (needs_control_head)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-1));
}
@@ -10021,12 +10301,20 @@ while (1)
{
/* We don't need to keep the STR_PTR, only the previous private_data_ptr. */
OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_sw));
+
+ if (end_block_size > 0)
+ OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(STACK_TOP), STACK(-extrasize + 2));
+
if (needs_control_head)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-1));
}
else
{
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+
+ if (end_block_size > 0)
+ OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(STACK_TOP), STACK(-framesize - extrasize + 1));
+
if (needs_control_head)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 2));
add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
@@ -10040,7 +10328,7 @@ while (1)
if (conditional)
{
if (extrasize > 0)
- OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), needs_control_head ? STACK(-2) : STACK(-1));
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-end_block_size - (needs_control_head ? 2 : 1)));
}
else if (bra == OP_BRAZERO)
{
@@ -10079,7 +10367,7 @@ while (1)
common->accept = save_accept;
return NULL;
}
- set_jumps(altbacktrack.topbacktracks, LABEL());
+ set_jumps(altbacktrack.own_backtracks, LABEL());
if (*cc != OP_ALT)
break;
@@ -10112,8 +10400,11 @@ if (common->positive_assertion_quit != NULL)
JUMPHERE(jump);
}
+if (end_block_size > 0)
+ OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+
if (needs_control_head)
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(1));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(end_block_size + 1));
if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK)
{
@@ -10126,8 +10417,8 @@ if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK)
/* The topmost item should be 0. */
if (bra == OP_BRAZERO)
{
- if (extrasize == 2)
- free_stack(common, 1);
+ if (extrasize >= 2)
+ free_stack(common, extrasize - 1);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
}
else if (extrasize > 0)
@@ -10161,8 +10452,9 @@ if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK)
/* Keep the STR_PTR on the top of the stack. */
if (bra == OP_BRAZERO)
{
+ /* This allocation is always successful. */
OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
- if (extrasize == 2)
+ if (extrasize >= 2)
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
}
else if (bra == OP_BRAMINZERO)
@@ -10182,8 +10474,9 @@ if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK)
else
{
/* We don't need to keep the STR_PTR, only the previous private_data_ptr. */
- OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 2) * sizeof(sljit_sw));
- if (extrasize == 2)
+ OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + end_block_size + 2) * sizeof(sljit_sw));
+
+ if (extrasize == 2 + end_block_size)
{
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
if (bra == OP_BRAMINZERO)
@@ -10191,7 +10484,7 @@ if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK)
}
else
{
- SLJIT_ASSERT(extrasize == 3);
+ SLJIT_ASSERT(extrasize == 3 + end_block_size);
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-1));
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), bra == OP_BRAZERO ? STR_PTR : SLJIT_IMM, 0);
}
@@ -10215,7 +10508,7 @@ if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK)
OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize - 1) * sizeof(sljit_sw));
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0);
}
- set_jumps(backtrack->common.topbacktracks, LABEL());
+ set_jumps(backtrack->common.own_backtracks, LABEL());
}
}
else
@@ -10228,8 +10521,8 @@ else
if (bra != OP_BRA)
{
- if (extrasize == 2)
- free_stack(common, 1);
+ if (extrasize >= 2)
+ free_stack(common, extrasize - 1);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
}
else if (extrasize > 0)
@@ -10260,9 +10553,9 @@ else
if (bra != OP_BRA)
{
- SLJIT_ASSERT(found == &backtrack->common.topbacktracks);
- set_jumps(backtrack->common.topbacktracks, LABEL());
- backtrack->common.topbacktracks = NULL;
+ SLJIT_ASSERT(found == &backtrack->common.own_backtracks);
+ set_jumps(backtrack->common.own_backtracks, LABEL());
+ backtrack->common.own_backtracks = NULL;
}
}
@@ -10371,7 +10664,7 @@ static PCRE2_SPTR SLJIT_FUNC do_script_run_utf(PCRE2_SPTR ptr, PCRE2_SPTR endptr
#endif /* SUPPORT_UNICODE */
-static SLJIT_INLINE void match_script_run_common(compiler_common *common, int private_data_ptr, backtrack_common *parent)
+static void match_script_run_common(compiler_common *common, int private_data_ptr, backtrack_common *parent)
{
DEFINE_COMPILER;
@@ -10386,7 +10679,7 @@ sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_ARGS2(W, W, W), SLJIT_IMM, SLJIT_FU
#endif
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0);
-add_jump(compiler, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0));
+add_jump(compiler, parent->top != NULL ? &parent->top->simple_backtracks : &parent->own_backtracks, CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0));
}
/*
@@ -10460,6 +10753,7 @@ PCRE2_UCHAR ket;
assert_backtrack *assert;
BOOL has_alternatives;
BOOL needs_control_head = FALSE;
+BOOL has_vreverse = FALSE;
struct sljit_jump *jump;
struct sljit_jump *skip;
struct sljit_label *rmax_label = NULL;
@@ -10709,6 +11003,21 @@ else if (opcode == OP_CBRA || opcode == OP_SCBRA)
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0);
}
}
+else if (opcode == OP_ASSERTBACK_NA && PRIVATE_DATA(ccbegin + 1))
+ {
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ allocate_stack(common, 4);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr + sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr + sizeof(sljit_sw), STR_END, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0);
+ OP1(SLJIT_MOV, STR_END, 0, STR_PTR, 0);
+
+ has_vreverse = (*matchingpath == OP_VREVERSE);
+ if (*matchingpath == OP_REVERSE || has_vreverse)
+ matchingpath = compile_reverse_matchingpath(common, matchingpath, backtrack);
+ }
else if (opcode == OP_ASSERT_NA || opcode == OP_ASSERTBACK_NA || opcode == OP_SCRIPT_RUN || opcode == OP_SBRA || opcode == OP_SCOND)
{
/* Saving the previous value. */
@@ -10716,6 +11025,9 @@ else if (opcode == OP_ASSERT_NA || opcode == OP_ASSERTBACK_NA || opcode == OP_SC
allocate_stack(common, 1);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STR_PTR, 0);
OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0);
+
+ if (*matchingpath == OP_REVERSE)
+ matchingpath = compile_reverse_matchingpath(common, matchingpath, backtrack);
}
else if (has_alternatives)
{
@@ -10835,14 +11147,28 @@ compile_matchingpath(common, matchingpath, cc, backtrack);
if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
return NULL;
-if (opcode == OP_ASSERT_NA || opcode == OP_ASSERTBACK_NA)
- OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
-
-if (opcode == OP_ONCE)
- match_once_common(common, ket, BACKTRACK_AS(bracket_backtrack)->u.framesize, private_data_ptr, has_alternatives, needs_control_head);
+switch (opcode)
+ {
+ case OP_ASSERTBACK_NA:
+ if (has_vreverse)
+ {
+ SLJIT_ASSERT(backtrack->top != NULL && PRIVATE_DATA(ccbegin + 1));
+ add_jump(compiler, &backtrack->top->simple_backtracks, CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0));
+ }
-if (opcode == OP_SCRIPT_RUN)
- match_script_run_common(common, private_data_ptr, backtrack);
+ if (PRIVATE_DATA(ccbegin + 1))
+ OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr + sizeof(sljit_sw));
+ break;
+ case OP_ASSERT_NA:
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ break;
+ case OP_ONCE:
+ match_once_common(common, ket, BACKTRACK_AS(bracket_backtrack)->u.framesize, private_data_ptr, has_alternatives, needs_control_head);
+ break;
+ case OP_SCRIPT_RUN:
+ match_script_run_common(common, private_data_ptr, backtrack);
+ break;
+ }
stacksize = 0;
if (repeat_type == OP_MINUPTO)
@@ -11041,7 +11367,7 @@ switch(opcode)
case OP_CBRAPOS:
case OP_SCBRAPOS:
offset = GET2(cc, 1 + LINK_SIZE);
- /* This case cannot be optimized in the same was as
+ /* This case cannot be optimized in the same way as
normal capturing brackets. */
SLJIT_ASSERT(common->optimized_cbracket[offset] == 0);
cbraprivptr = OVECTOR_PRIV(offset);
@@ -11158,7 +11484,7 @@ loop = LABEL();
while (*cc != OP_KETRPOS)
{
backtrack->top = NULL;
- backtrack->topbacktracks = NULL;
+ backtrack->own_backtracks = NULL;
cc += GET(cc, 1);
compile_matchingpath(common, ccbegin, cc, backtrack);
@@ -11239,7 +11565,7 @@ while (*cc != OP_KETRPOS)
compile_backtrackingpath(common, backtrack->top);
if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
return NULL;
- set_jumps(backtrack->topbacktracks, LABEL());
+ set_jumps(backtrack->own_backtracks, LABEL());
if (framesize < 0)
{
@@ -11271,13 +11597,13 @@ while (*cc != OP_KETRPOS)
/* We don't have to restore the control head in case of a failed match. */
-backtrack->topbacktracks = NULL;
+backtrack->own_backtracks = NULL;
if (!zero)
{
if (framesize < 0)
- add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0));
+ add_jump(compiler, &backtrack->own_backtracks, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0));
else /* TMP2 is set to [private_data_ptr] above. */
- add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(TMP2), STACK(-stacksize), SLJIT_IMM, 0));
+ add_jump(compiler, &backtrack->own_backtracks, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(TMP2), STACK(-stacksize), SLJIT_IMM, 0));
}
/* None of them matched. */
@@ -11473,7 +11799,7 @@ SLJIT_ASSERT(common->fast_forward_bc_ptr != NULL || early_fail_ptr == 0
|| (early_fail_ptr >= common->early_fail_start_ptr && early_fail_ptr <= common->early_fail_end_ptr));
if (early_fail_type == type_fail)
- add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), early_fail_ptr));
+ add_jump(compiler, &backtrack->own_backtracks, CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), early_fail_ptr));
cc = get_iterator_parameters(common, cc, &opcode, &type, &max, &exact, &end);
@@ -11500,10 +11826,10 @@ if (exact > 1)
&& type != OP_ANYNL && type != OP_EXTUNI)
{
OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(exact));
- add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_GREATER, TMP1, 0, STR_END, 0));
+ add_jump(compiler, &backtrack->own_backtracks, CMP(SLJIT_GREATER, TMP1, 0, STR_END, 0));
OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, exact);
label = LABEL();
- compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, FALSE);
+ compile_char1_matchingpath(common, type, cc, &backtrack->own_backtracks, FALSE);
OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
JUMPTO(SLJIT_NOT_ZERO, label);
}
@@ -11511,13 +11837,13 @@ if (exact > 1)
{
OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, exact);
label = LABEL();
- compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, TRUE);
+ compile_char1_matchingpath(common, type, cc, &backtrack->own_backtracks, TRUE);
OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
JUMPTO(SLJIT_NOT_ZERO, label);
}
}
else if (exact == 1)
- compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, TRUE);
+ compile_char1_matchingpath(common, type, cc, &backtrack->own_backtracks, TRUE);
if (early_fail_type == type_fail_range)
{
@@ -11526,7 +11852,7 @@ if (early_fail_type == type_fail_range)
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), early_fail_ptr + SSIZE_OF(sw));
OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, TMP2, 0);
OP2(SLJIT_SUB, TMP2, 0, STR_PTR, 0, TMP2, 0);
- add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_LESS_EQUAL, TMP2, 0, TMP1, 0));
+ add_jump(compiler, &backtrack->own_backtracks, CMP(SLJIT_LESS_EQUAL, TMP2, 0, TMP1, 0));
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_PTR, 0);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr + SSIZE_OF(sw), STR_PTR, 0);
@@ -11606,7 +11932,7 @@ switch(opcode)
if (common->mode == PCRE2_JIT_COMPLETE)
{
OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_PTR, 0, STR_END, 0);
- CMOV(SLJIT_GREATER, STR_PTR, STR_END, 0);
+ SELECT(SLJIT_GREATER, STR_PTR, STR_END, 0, STR_PTR);
}
else
{
@@ -11674,14 +12000,14 @@ switch(opcode)
if (opcode == OP_UPTO)
{
OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
- add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_ZERO));
+ add_jump(compiler, &backtrack->own_backtracks, JUMP(SLJIT_ZERO));
}
- compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, FALSE);
+ compile_char1_matchingpath(common, type, cc, &backtrack->own_backtracks, FALSE);
if (early_fail_ptr != 0)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), early_fail_ptr, STR_PTR, 0);
JUMPHERE(jump);
- detect_partial_match(common, &backtrack->topbacktracks);
+ detect_partial_match(common, &backtrack->own_backtracks);
OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
if (charpos_othercasebit != 0)
OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, charpos_othercasebit);
@@ -11835,7 +12161,7 @@ switch(opcode)
}
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
- if (common->utf)
+ if (type == OP_EXTUNI || common->utf)
{
OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
detect_partial_match(common, &no_match);
@@ -11899,7 +12225,7 @@ switch(opcode)
if (common->mode == PCRE2_JIT_COMPLETE)
{
OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_PTR, 0, STR_END, 0);
- CMOV(SLJIT_GREATER, STR_PTR, STR_END, 0);
+ SELECT(SLJIT_GREATER, STR_PTR, STR_END, 0, STR_PTR);
}
else
{
@@ -11952,12 +12278,12 @@ PUSH_BACKTRACK(sizeof(backtrack_common), cc, NULL);
if (*cc == OP_FAIL)
{
- add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_JUMP));
+ add_jump(compiler, &backtrack->own_backtracks, JUMP(SLJIT_JUMP));
return cc + 1;
}
if (*cc == OP_ACCEPT && common->currententry == NULL && (common->re->overall_options & PCRE2_ENDANCHORED) != 0)
- add_jump(compiler, &common->reset_match, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, STR_END, 0));
+ add_jump(compiler, &common->restart_match, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, STR_END, 0));
if (*cc == OP_ASSERT_ACCEPT || common->currententry != NULL || !common->might_be_empty)
{
@@ -11983,7 +12309,7 @@ else
OP1(SLJIT_MOV_U32, TMP2, 0, SLJIT_MEM1(ARGUMENTS), SLJIT_OFFSETOF(jit_arguments, options));
OP2U(SLJIT_AND | SLJIT_SET_Z, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY);
-add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_NOT_ZERO));
+add_jump(compiler, &backtrack->own_backtracks, JUMP(SLJIT_NOT_ZERO));
OP2U(SLJIT_AND | SLJIT_SET_Z, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY_ATSTART);
if (common->accept_label == NULL)
add_jump(compiler, &common->accept, JUMP(SLJIT_ZERO));
@@ -11995,7 +12321,7 @@ if (common->accept_label == NULL)
add_jump(compiler, &common->accept, CMP(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0));
else
CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0, common->accept_label);
-add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_JUMP));
+add_jump(compiler, &backtrack->own_backtracks, JUMP(SLJIT_JUMP));
return cc + 1;
}
@@ -12115,8 +12441,9 @@ while (cc < ccend)
case OP_DOLLM:
case OP_CIRC:
case OP_CIRCM:
- case OP_REVERSE:
- cc = compile_simple_assertion_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks);
+ case OP_NOT_UCP_WORD_BOUNDARY:
+ case OP_UCP_WORD_BOUNDARY:
+ cc = compile_simple_assertion_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->simple_backtracks : &parent->own_backtracks);
break;
case OP_NOT_DIGIT:
@@ -12138,7 +12465,7 @@ while (cc < ccend)
case OP_EXTUNI:
case OP_NOT:
case OP_NOTI:
- cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE);
+ cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->simple_backtracks : &parent->own_backtracks, TRUE);
break;
case OP_SET_SOM:
@@ -12153,9 +12480,9 @@ while (cc < ccend)
case OP_CHAR:
case OP_CHARI:
if (common->mode == PCRE2_JIT_COMPLETE)
- cc = compile_charn_matchingpath(common, cc, ccend, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks);
+ cc = compile_charn_matchingpath(common, cc, ccend, parent->top != NULL ? &parent->top->simple_backtracks : &parent->own_backtracks);
else
- cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE);
+ cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->simple_backtracks : &parent->own_backtracks, TRUE);
break;
case OP_STAR:
@@ -12231,7 +12558,7 @@ while (cc < ccend)
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);
+ cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->simple_backtracks : &parent->own_backtracks, TRUE);
break;
#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
@@ -12239,7 +12566,7 @@ while (cc < ccend)
if (*(cc + GET(cc, 1)) >= OP_CRSTAR && *(cc + GET(cc, 1)) <= 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);
+ cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->simple_backtracks : &parent->own_backtracks, TRUE);
break;
#endif
@@ -12249,7 +12576,7 @@ while (cc < ccend)
cc = compile_ref_iterator_matchingpath(common, cc, parent);
else
{
- compile_ref_matchingpath(common, cc, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE, FALSE);
+ compile_ref_matchingpath(common, cc, parent->top != NULL ? &parent->top->simple_backtracks : &parent->own_backtracks, TRUE, FALSE);
cc += 1 + IMM2_SIZE;
}
break;
@@ -12260,8 +12587,8 @@ while (cc < ccend)
cc = compile_ref_iterator_matchingpath(common, cc, parent);
else
{
- compile_dnref_search(common, cc, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks);
- compile_ref_matchingpath(common, cc, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE, FALSE);
+ compile_dnref_search(common, cc, parent->top != NULL ? &parent->top->simple_backtracks : &parent->own_backtracks);
+ compile_ref_matchingpath(common, cc, parent->top != NULL ? &parent->top->simple_backtracks : &parent->own_backtracks, TRUE, FALSE);
cc += 1 + 2 * IMM2_SIZE;
}
break;
@@ -12539,7 +12866,7 @@ switch(opcode)
break;
}
-set_jumps(current->topbacktracks, LABEL());
+set_jumps(current->own_backtracks, LABEL());
}
static SLJIT_INLINE void compile_ref_iterator_backtrackingpath(compiler_common *common, struct backtrack_common *current)
@@ -12554,7 +12881,7 @@ type = cc[ref ? 1 + IMM2_SIZE : 1 + 2 * IMM2_SIZE];
if ((type & 0x1) == 0)
{
/* Maximize case. */
- set_jumps(current->topbacktracks, LABEL());
+ set_jumps(current->own_backtracks, LABEL());
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
free_stack(common, 1);
CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(ref_iterator_backtrack)->matchingpath);
@@ -12563,7 +12890,7 @@ if ((type & 0x1) == 0)
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(ref_iterator_backtrack)->matchingpath);
-set_jumps(current->topbacktracks, LABEL());
+set_jumps(current->own_backtracks, LABEL());
free_stack(common, ref ? 2 : 3);
}
@@ -12584,7 +12911,7 @@ if (!CURRENT_AS(recurse_backtrack)->inlined_pattern)
else
compile_backtrackingpath(common, current->top);
-set_jumps(current->topbacktracks, LABEL());
+set_jumps(current->own_backtracks, LABEL());
}
static void compile_assert_backtrackingpath(compiler_common *common, struct backtrack_common *current)
@@ -12603,13 +12930,13 @@ if (*cc == OP_BRAZERO)
if (bra == OP_BRAZERO)
{
- SLJIT_ASSERT(current->topbacktracks == NULL);
+ SLJIT_ASSERT(current->own_backtracks == NULL);
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
}
if (CURRENT_AS(assert_backtrack)->framesize < 0)
{
- set_jumps(current->topbacktracks, LABEL());
+ set_jumps(current->own_backtracks, LABEL());
if (bra == OP_BRAZERO)
{
@@ -12641,10 +12968,10 @@ if (*cc == OP_ASSERT || *cc == OP_ASSERTBACK)
OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (CURRENT_AS(assert_backtrack)->framesize - 1) * sizeof(sljit_sw));
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(assert_backtrack)->private_data_ptr, TMP1, 0);
- set_jumps(current->topbacktracks, LABEL());
+ set_jumps(current->own_backtracks, LABEL());
}
else
- set_jumps(current->topbacktracks, LABEL());
+ set_jumps(current->own_backtracks, LABEL());
if (bra == OP_BRAZERO)
{
@@ -12671,6 +12998,7 @@ PCRE2_UCHAR ket;
assert_backtrack *assert;
BOOL has_alternatives;
BOOL needs_control_head = FALSE;
+BOOL has_vreverse;
struct sljit_jump *brazero = NULL;
struct sljit_jump *next_alt = NULL;
struct sljit_jump *once = NULL;
@@ -12847,8 +13175,8 @@ else if (has_alternatives)
}
COMPILE_BACKTRACKINGPATH(current->top);
-if (current->topbacktracks)
- set_jumps(current->topbacktracks, LABEL());
+if (current->own_backtracks)
+ set_jumps(current->own_backtracks, LABEL());
if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND))
{
@@ -12884,14 +13212,25 @@ if (has_alternatives)
do
{
current->top = NULL;
- current->topbacktracks = NULL;
- current->nextbacktracks = NULL;
+ current->own_backtracks = NULL;
+ current->simple_backtracks = NULL;
/* Conditional blocks always have an additional alternative, even if it is empty. */
if (*cc == OP_ALT)
{
ccprev = cc + 1 + LINK_SIZE;
cc += GET(cc, 1);
- if (opcode != OP_COND && opcode != OP_SCOND)
+
+ has_vreverse = FALSE;
+ if (opcode == OP_ASSERTBACK || opcode == OP_ASSERTBACK_NA)
+ {
+ SLJIT_ASSERT(private_data_ptr != 0);
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+
+ has_vreverse = (*ccprev == OP_VREVERSE);
+ if (*ccprev == OP_REVERSE || has_vreverse)
+ ccprev = compile_reverse_matchingpath(common, ccprev, current);
+ }
+ else if (opcode != OP_COND && opcode != OP_SCOND)
{
if (opcode != OP_ONCE)
{
@@ -12903,15 +13242,30 @@ if (has_alternatives)
else
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(needs_control_head ? 1 : 0));
}
+
compile_matchingpath(common, ccprev, cc, current);
if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
return;
- if (opcode == OP_ASSERT_NA || opcode == OP_ASSERTBACK_NA)
- OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ switch (opcode)
+ {
+ case OP_ASSERTBACK_NA:
+ if (has_vreverse)
+ {
+ SLJIT_ASSERT(current->top != NULL && PRIVATE_DATA(ccbegin + 1));
+ add_jump(compiler, &current->top->simple_backtracks, CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0));
+ }
- if (opcode == OP_SCRIPT_RUN)
- match_script_run_common(common, private_data_ptr, current);
+ if (PRIVATE_DATA(ccbegin + 1))
+ OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr + sizeof(sljit_sw));
+ break;
+ case OP_ASSERT_NA:
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ break;
+ case OP_SCRIPT_RUN:
+ match_script_run_common(common, private_data_ptr, current);
+ break;
+ }
}
/* Instructions after the current alternative is successfully matched. */
@@ -12998,9 +13352,9 @@ if (has_alternatives)
}
COMPILE_BACKTRACKINGPATH(current->top);
- if (current->topbacktracks)
- set_jumps(current->topbacktracks, LABEL());
- SLJIT_ASSERT(!current->nextbacktracks);
+ if (current->own_backtracks)
+ set_jumps(current->own_backtracks, LABEL());
+ SLJIT_ASSERT(!current->simple_backtracks);
}
while (*cc == OP_ALT);
@@ -13042,6 +13396,15 @@ if (offset != 0)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0);
}
}
+else if (opcode == OP_ASSERTBACK_NA && PRIVATE_DATA(ccbegin + 1))
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+ OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr + sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr + sizeof(sljit_sw), TMP2, 0);
+ free_stack(common, 4);
+ }
else if (opcode == OP_ASSERT_NA || opcode == OP_ASSERTBACK_NA || opcode == OP_SCRIPT_RUN || opcode == OP_SBRA || opcode == OP_SCOND)
{
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(0));
@@ -13128,12 +13491,19 @@ static SLJIT_INLINE void compile_bracketpos_backtrackingpath(compiler_common *co
DEFINE_COMPILER;
int offset;
struct sljit_jump *jump;
+PCRE2_SPTR cc;
+/* No retry on backtrack, just drop everything. */
if (CURRENT_AS(bracketpos_backtrack)->framesize < 0)
{
- if (*current->cc == OP_CBRAPOS || *current->cc == OP_SCBRAPOS)
+ cc = current->cc;
+
+ if (*cc == OP_BRAPOSZERO)
+ cc++;
+
+ if (*cc == OP_CBRAPOS || *cc == OP_SCBRAPOS)
{
- offset = (GET2(current->cc, 1 + LINK_SIZE)) << 1;
+ offset = (GET2(cc, 1 + LINK_SIZE)) << 1;
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0);
@@ -13143,7 +13513,7 @@ if (CURRENT_AS(bracketpos_backtrack)->framesize < 0)
if (common->capture_last_ptr != 0)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, TMP1, 0);
}
- set_jumps(current->topbacktracks, LABEL());
+ set_jumps(current->own_backtracks, LABEL());
free_stack(common, CURRENT_AS(bracketpos_backtrack)->stacksize);
return;
}
@@ -13152,10 +13522,10 @@ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(bracketpos_backtra
add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (CURRENT_AS(bracketpos_backtrack)->framesize - 1) * sizeof(sljit_sw));
-if (current->topbacktracks)
+if (current->own_backtracks)
{
jump = JUMP(SLJIT_JUMP);
- set_jumps(current->topbacktracks, LABEL());
+ set_jumps(current->own_backtracks, LABEL());
/* Drop the stack frame. */
free_stack(common, CURRENT_AS(bracketpos_backtrack)->stacksize);
JUMPHERE(jump);
@@ -13168,8 +13538,8 @@ static SLJIT_INLINE void compile_braminzero_backtrackingpath(compiler_common *co
assert_backtrack backtrack;
current->top = NULL;
-current->topbacktracks = NULL;
-current->nextbacktracks = NULL;
+current->own_backtracks = NULL;
+current->simple_backtracks = NULL;
if (current->cc[1] > OP_ASSERTBACK_NOT)
{
/* Manual call of compile_bracket_matchingpath and compile_bracket_backtrackingpath. */
@@ -13184,7 +13554,7 @@ else
/* Manual call of compile_assert_matchingpath. */
compile_assert_matchingpath(common, current->cc, &backtrack, FALSE);
}
-SLJIT_ASSERT(!current->nextbacktracks && !current->topbacktracks);
+SLJIT_ASSERT(!current->simple_backtracks && !current->own_backtracks);
}
static SLJIT_INLINE void compile_control_verb_backtrackingpath(compiler_common *common, struct backtrack_common *current)
@@ -13249,6 +13619,23 @@ else
add_jump(compiler, &common->reset_match, JUMP(SLJIT_JUMP));
}
+static SLJIT_INLINE void compile_vreverse_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+struct sljit_label *label;
+
+OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(2));
+jump = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(3));
+skip_valid_char(common);
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), STR_PTR, 0);
+JUMPTO(SLJIT_JUMP, CURRENT_AS(vreverse_backtrack)->matchingpath);
+
+label = LABEL();
+sljit_set_label(jump, label);
+set_jumps(current->own_backtracks, label);
+}
+
static SLJIT_INLINE void compile_then_trap_backtrackingpath(compiler_common *common, struct backtrack_common *current)
{
DEFINE_COMPILER;
@@ -13289,8 +13676,8 @@ then_trap_backtrack *save_then_trap = common->then_trap;
while (current)
{
- if (current->nextbacktracks != NULL)
- set_jumps(current->nextbacktracks, LABEL());
+ if (current->simple_backtracks != NULL)
+ set_jumps(current->simple_backtracks, LABEL());
switch(*current->cc)
{
case OP_SET_SOM:
@@ -13456,7 +13843,11 @@ while (current)
case OP_FAIL:
case OP_ACCEPT:
case OP_ASSERT_ACCEPT:
- set_jumps(current->topbacktracks, LABEL());
+ set_jumps(current->own_backtracks, LABEL());
+ break;
+
+ case OP_VREVERSE:
+ compile_vreverse_backtrackingpath(common, current);
break;
case OP_THEN_TRAP:
@@ -13502,7 +13893,7 @@ SLJIT_ASSERT(common->currententry->entry_label == NULL && common->recursive_head
common->currententry->entry_label = LABEL();
set_jumps(common->currententry->entry_calls, common->currententry->entry_label);
-sljit_emit_fast_enter(compiler, TMP2, 0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, TMP2, 0);
count_match(common);
local_size = (alt_max > 1) ? 2 : 1;
@@ -13535,7 +13926,7 @@ cc += GET(cc, 1);
while (1)
{
altbacktrack.top = NULL;
- altbacktrack.topbacktracks = NULL;
+ altbacktrack.own_backtracks = NULL;
if (altbacktrack.cc != ccbegin)
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
@@ -13564,7 +13955,7 @@ while (1)
common->currententry->backtrack_label = LABEL();
set_jumps(common->currententry->backtrack_calls, common->currententry->backtrack_label);
- sljit_emit_fast_enter(compiler, TMP1, 0);
+ sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, TMP1, 0);
if (recurse_flags & recurse_flag_accept_found)
accept_exit = CMP(SLJIT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, -1);
@@ -13612,7 +14003,7 @@ while (1)
compile_backtrackingpath(common, altbacktrack.top);
if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
return;
- set_jumps(altbacktrack.topbacktracks, LABEL());
+ set_jumps(altbacktrack.own_backtracks, LABEL());
if (*cc != OP_ALT)
break;
@@ -13718,9 +14109,9 @@ jump_list *reqcu_not_found = NULL;
SLJIT_ASSERT(tables);
#if HAS_VIRTUAL_REGISTERS == 1
-SLJIT_ASSERT(sljit_get_register_index(TMP3) < 0 && sljit_get_register_index(ARGUMENTS) < 0 && sljit_get_register_index(RETURN_ADDR) < 0);
+SLJIT_ASSERT(sljit_get_register_index(SLJIT_GP_REGISTER, TMP3) < 0 && sljit_get_register_index(SLJIT_GP_REGISTER, ARGUMENTS) < 0 && sljit_get_register_index(SLJIT_GP_REGISTER, RETURN_ADDR) < 0);
#elif HAS_VIRTUAL_REGISTERS == 0
-SLJIT_ASSERT(sljit_get_register_index(TMP3) >= 0 && sljit_get_register_index(ARGUMENTS) >= 0 && sljit_get_register_index(RETURN_ADDR) >= 0);
+SLJIT_ASSERT(sljit_get_register_index(SLJIT_GP_REGISTER, TMP3) >= 0 && sljit_get_register_index(SLJIT_GP_REGISTER, ARGUMENTS) >= 0 && sljit_get_register_index(SLJIT_GP_REGISTER, RETURN_ADDR) >= 0);
#else
#error "Invalid value for HAS_VIRTUAL_REGISTERS"
#endif
@@ -13892,13 +14283,13 @@ memset(common->private_data_ptrs, 0, total_length * sizeof(sljit_s32));
private_data_size = common->cbra_ptr + (re->top_bracket + 1) * sizeof(sljit_sw);
if ((re->overall_options & PCRE2_ANCHORED) == 0 && (re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0 && !common->has_skip_in_assert_back)
- detect_early_fail(common, common->start, &private_data_size, 0, 0, TRUE);
+ detect_early_fail(common, common->start, &private_data_size, 0, 0);
set_private_data_ptrs(common, &private_data_size, ccend);
SLJIT_ASSERT(common->early_fail_start_ptr <= common->early_fail_end_ptr);
-if (private_data_size > SLJIT_MAX_LOCAL_SIZE)
+if (private_data_size > 65536)
{
SLJIT_FREE(common->private_data_ptrs, allocator_data);
SLJIT_FREE(common->optimized_cbracket, allocator_data);
@@ -13923,7 +14314,7 @@ common->compiler = compiler;
/* Main pcre2_jit_exec entry. */
SLJIT_ASSERT((private_data_size & (sizeof(sljit_sw) - 1)) == 0);
-sljit_emit_enter(compiler, 0, SLJIT_ARGS1(W, W), 5, 5, 0, 0, private_data_size);
+sljit_emit_enter(compiler, 0, SLJIT_ARGS1(W, W), 5, 5, SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS, 0, private_data_size);
/* Register init. */
reset_ovector(common, (re->top_bracket + 1) * 2);
@@ -14187,7 +14578,7 @@ common->quit_label = quit_label;
/* This is a (really) rare case. */
set_jumps(common->stackalloc, LABEL());
/* RETURN_ADDR is not a saved register. */
-sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+sljit_emit_op_dst(compiler, SLJIT_FAST_ENTER, SLJIT_MEM1(SLJIT_SP), LOCALS0);
SLJIT_ASSERT(TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1);
@@ -14225,7 +14616,12 @@ if (common->revertframes != NULL)
if (common->wordboundary != NULL)
{
set_jumps(common->wordboundary, LABEL());
- check_wordboundary(common);
+ check_wordboundary(common, FALSE);
+ }
+if (common->ucp_wordboundary != NULL)
+ {
+ set_jumps(common->ucp_wordboundary, LABEL());
+ check_wordboundary(common, TRUE);
}
if (common->anynewline != NULL)
{
@@ -14252,10 +14648,17 @@ if (common->caselesscmp != NULL)
set_jumps(common->caselesscmp, LABEL());
do_caselesscmp(common);
}
-if (common->reset_match != NULL)
+if (common->reset_match != NULL || common->restart_match != NULL)
{
+ if (common->restart_match != NULL)
+ {
+ set_jumps(common->restart_match, LABEL());
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), common->start_ptr);
+ }
+
set_jumps(common->reset_match, LABEL());
do_reset_match(common, (re->top_bracket + 1) * 2);
+ /* The value of restart_match is in TMP1. */
CMPTO(SLJIT_GREATER, STR_PTR, 0, TMP1, 0, continue_match_label);
OP1(SLJIT_MOV, STR_PTR, 0, TMP1, 0);
JUMPTO(SLJIT_JUMP, reset_match_label);
diff --git a/src/3rdparty/pcre2/src/pcre2_jit_match.c b/src/3rdparty/pcre2/src/pcre2_jit_match.c
index 1ab3af073e..ae5903e202 100644
--- a/src/3rdparty/pcre2/src/pcre2_jit_match.c
+++ b/src/3rdparty/pcre2/src/pcre2_jit_match.c
@@ -7,7 +7,7 @@ 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-2018 University of Cambridge
+ New API code Copyright (c) 2016-2023 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -42,6 +42,12 @@ POSSIBILITY OF SUCH DAMAGE.
#error This file must be included from pcre2_jit_compile.c.
#endif
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+#include <sanitizer/msan_interface.h>
+#endif /* __has_feature(memory_sanitizer) */
+#endif /* defined(__has_feature) */
+
#ifdef SUPPORT_JIT
static SLJIT_NOINLINE int jit_machine_stack_exec(jit_arguments *arguments, jit_function executable_func)
@@ -171,6 +177,7 @@ if (rc > (int)oveccount)
rc = 0;
match_data->code = re;
match_data->subject = (rc >= 0 || rc == PCRE2_ERROR_PARTIAL)? subject : NULL;
+match_data->subject_length = length;
match_data->rc = rc;
match_data->startchar = arguments.startchar_ptr - subject;
match_data->leftchar = 0;
@@ -178,6 +185,13 @@ match_data->rightchar = 0;
match_data->mark = arguments.mark_ptr;
match_data->matchedby = PCRE2_MATCHEDBY_JIT;
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+if (rc > 0)
+ __msan_unpoison(match_data->ovector, 2 * rc * sizeof(match_data->ovector[0]));
+#endif /* __has_feature(memory_sanitizer) */
+#endif /* defined(__has_feature) */
+
return match_data->rc;
#endif /* SUPPORT_JIT */
diff --git a/src/3rdparty/pcre2/src/pcre2_jit_neon_inc.h b/src/3rdparty/pcre2/src/pcre2_jit_neon_inc.h
index 165602edc0..4a718b67b7 100644
--- a/src/3rdparty/pcre2/src/pcre2_jit_neon_inc.h
+++ b/src/3rdparty/pcre2/src/pcre2_jit_neon_inc.h
@@ -82,7 +82,12 @@ POSSIBILITY OF SUCH DAMAGE.
# endif
# endif
-static sljit_u8* SLJIT_FUNC FF_FUN(sljit_u8 *str_end, sljit_u8 *str_ptr, sljit_uw offs1, sljit_uw offs2, sljit_uw chars)
+#if (defined(__GNUC__) && __SANITIZE_ADDRESS__) \
+ || (defined(__clang__) \
+ && ((__clang_major__ == 3 && __clang_minor__ >= 3) || (__clang_major__ > 3)))
+__attribute__((no_sanitize_address))
+#endif
+static sljit_u8* SLJIT_FUNC FF_FUN(sljit_u8 *str_end, sljit_u8 **str_ptr, sljit_uw offs1, sljit_uw offs2, sljit_uw chars)
#undef FF_FUN
{
quad_word qw;
@@ -171,7 +176,7 @@ else
}
# endif
-str_ptr += IN_UCHARS(offs1);
+*str_ptr += IN_UCHARS(offs1);
#endif
#if PCRE2_CODE_UNIT_WIDTH != 8
@@ -183,13 +188,13 @@ restart:;
#endif
#if defined(FFCPS)
-if (str_ptr >= str_end)
+if (*str_ptr >= str_end)
return NULL;
-sljit_u8 *p1 = str_ptr - diff;
+sljit_u8 *p1 = *str_ptr - diff;
#endif
-sljit_s32 align_offset = ((uint64_t)str_ptr & 0xf);
-str_ptr = (sljit_u8 *) ((uint64_t)str_ptr & ~0xf);
-vect_t data = VLD1Q(str_ptr);
+sljit_s32 align_offset = ((uint64_t)*str_ptr & 0xf);
+*str_ptr = (sljit_u8 *) ((uint64_t)*str_ptr & ~0xf);
+vect_t data = VLD1Q(*str_ptr);
#if PCRE2_CODE_UNIT_WIDTH != 8
data = VANDQ(data, char_mask);
#endif
@@ -212,9 +217,9 @@ vect_t prev_data = data;
# endif
vect_t data2;
-if (p1 < str_ptr)
+if (p1 < *str_ptr)
{
- data2 = VLD1Q(str_ptr - diff);
+ data2 = VLD1Q(*str_ptr - diff);
#if PCRE2_CODE_UNIT_WIDTH != 8
data2 = VANDQ(data2, char_mask);
#endif
@@ -242,12 +247,12 @@ if (align_offset < 8)
qw.dw[0] >>= align_offset * 8;
if (qw.dw[0])
{
- str_ptr += align_offset + __builtin_ctzll(qw.dw[0]) / 8;
+ *str_ptr += align_offset + __builtin_ctzll(qw.dw[0]) / 8;
goto match;
}
if (qw.dw[1])
{
- str_ptr += 8 + __builtin_ctzll(qw.dw[1]) / 8;
+ *str_ptr += 8 + __builtin_ctzll(qw.dw[1]) / 8;
goto match;
}
}
@@ -256,15 +261,15 @@ else
qw.dw[1] >>= (align_offset - 8) * 8;
if (qw.dw[1])
{
- str_ptr += align_offset + __builtin_ctzll(qw.dw[1]) / 8;
+ *str_ptr += align_offset + __builtin_ctzll(qw.dw[1]) / 8;
goto match;
}
}
-str_ptr += 16;
+*str_ptr += 16;
-while (str_ptr < str_end)
+while (*str_ptr < str_end)
{
- vect_t orig_data = VLD1Q(str_ptr);
+ vect_t orig_data = VLD1Q(*str_ptr);
#if PCRE2_CODE_UNIT_WIDTH != 8
orig_data = VANDQ(orig_data, char_mask);
#endif
@@ -287,7 +292,7 @@ while (str_ptr < str_end)
# if defined (FFCPS_DIFF1)
data2 = VEXTQ(prev_data, data, VECTOR_FACTOR - 1);
# else
- data2 = VLD1Q(str_ptr - diff);
+ data2 = VLD1Q(*str_ptr - diff);
# if PCRE2_CODE_UNIT_WIDTH != 8
data2 = VANDQ(data2, char_mask);
# endif
@@ -312,11 +317,11 @@ while (str_ptr < str_end)
VST1Q(qw.mem, eq);
if (qw.dw[0])
- str_ptr += __builtin_ctzll(qw.dw[0]) / 8;
+ *str_ptr += __builtin_ctzll(qw.dw[0]) / 8;
else if (qw.dw[1])
- str_ptr += 8 + __builtin_ctzll(qw.dw[1]) / 8;
+ *str_ptr += 8 + __builtin_ctzll(qw.dw[1]) / 8;
else {
- str_ptr += 16;
+ *str_ptr += 16;
#if defined (FFCPS_DIFF1)
prev_data = orig_data;
#endif
@@ -324,24 +329,24 @@ while (str_ptr < str_end)
}
match:;
- if (str_ptr >= str_end)
+ if (*str_ptr >= str_end)
/* Failed match. */
return NULL;
#if defined(FF_UTF)
- if (utf_continue((PCRE2_SPTR)str_ptr - offs1))
+ if (utf_continue((PCRE2_SPTR)*str_ptr - offs1))
{
/* Not a match. */
- str_ptr += IN_UCHARS(1);
+ *str_ptr += IN_UCHARS(1);
goto restart;
}
#endif
/* Match. */
#if defined (FFCPS)
- str_ptr -= IN_UCHARS(offs1);
+ *str_ptr -= IN_UCHARS(offs1);
#endif
- return str_ptr;
+ return *str_ptr;
}
/* Failed match. */
diff --git a/src/3rdparty/pcre2/src/pcre2_jit_simd_inc.h b/src/3rdparty/pcre2/src/pcre2_jit_simd_inc.h
index 1a5ce4ed09..783a85f50e 100644
--- a/src/3rdparty/pcre2/src/pcre2_jit_simd_inc.h
+++ b/src/3rdparty/pcre2/src/pcre2_jit_simd_inc.h
@@ -42,7 +42,8 @@ POSSIBILITY OF SUCH DAMAGE.
#if !(defined SUPPORT_VALGRIND)
#if ((defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \
- || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X))
+ || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \
+ || (defined SLJIT_CONFIG_LOONGARCH_64 && SLJIT_CONFIG_LOONGARCH_64))
typedef enum {
vector_compare_match1,
@@ -50,18 +51,39 @@ typedef enum {
vector_compare_match2,
} vector_compare_type;
-static SLJIT_INLINE sljit_u32 max_fast_forward_char_pair_offset(void)
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
+static SLJIT_INLINE sljit_s32 max_fast_forward_char_pair_offset(void)
{
#if PCRE2_CODE_UNIT_WIDTH == 8
+/* The AVX2 code path is currently disabled. */
+/* return sljit_has_cpu_feature(SLJIT_HAS_AVX2) ? 31 : 15; */
return 15;
#elif PCRE2_CODE_UNIT_WIDTH == 16
+/* The AVX2 code path is currently disabled. */
+/* return sljit_has_cpu_feature(SLJIT_HAS_AVX2) ? 15 : 7; */
return 7;
#elif PCRE2_CODE_UNIT_WIDTH == 32
+/* The AVX2 code path is currently disabled. */
+/* return sljit_has_cpu_feature(SLJIT_HAS_AVX2) ? 7 : 3; */
return 3;
#else
#error "Unsupported unit width"
#endif
}
+#else /* !SLJIT_CONFIG_X86 */
+static SLJIT_INLINE sljit_s32 max_fast_forward_char_pair_offset(void)
+{
+#if PCRE2_CODE_UNIT_WIDTH == 8
+return 15;
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+return 7;
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+return 3;
+#else
+#error "Unsupported unit width"
+#endif
+}
+#endif /* SLJIT_CONFIG_X86 */
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
static struct sljit_jump *jump_if_utf_char_start(struct sljit_compiler *compiler, sljit_s32 reg)
@@ -86,49 +108,35 @@ static sljit_s32 character_to_int32(PCRE2_UCHAR chr)
{
sljit_u32 value = chr;
#if PCRE2_CODE_UNIT_WIDTH == 8
-#define SSE2_COMPARE_TYPE_INDEX 0
+#define SIMD_COMPARE_TYPE_INDEX 0
return (sljit_s32)((value << 24) | (value << 16) | (value << 8) | value);
#elif PCRE2_CODE_UNIT_WIDTH == 16
-#define SSE2_COMPARE_TYPE_INDEX 1
+#define SIMD_COMPARE_TYPE_INDEX 1
return (sljit_s32)((value << 16) | value);
#elif PCRE2_CODE_UNIT_WIDTH == 32
-#define SSE2_COMPARE_TYPE_INDEX 2
+#define SIMD_COMPARE_TYPE_INDEX 2
return (sljit_s32)(value);
#else
#error "Unsupported unit width"
#endif
}
-static void load_from_mem_sse2(struct sljit_compiler *compiler, sljit_s32 dst_xmm_reg, sljit_s32 src_general_reg, sljit_s8 offset)
+static void fast_forward_char_pair_sse2_compare(struct sljit_compiler *compiler, vector_compare_type compare_type,
+ sljit_s32 reg_type, int step, sljit_s32 dst_ind, sljit_s32 cmp1_ind, sljit_s32 cmp2_ind, sljit_s32 tmp_ind)
{
-sljit_u8 instruction[5];
-
-SLJIT_ASSERT(dst_xmm_reg < 8);
-SLJIT_ASSERT(src_general_reg < 8);
-
-/* MOVDQA xmm1, xmm2/m128 */
-instruction[0] = ((sljit_u8)offset & 0xf) == 0 ? 0x66 : 0xf3;
-instruction[1] = 0x0f;
-instruction[2] = 0x6f;
+sljit_u8 instruction[4];
-if (offset == 0)
+if (reg_type == SLJIT_SIMD_REG_128)
{
- instruction[3] = (dst_xmm_reg << 3) | src_general_reg;
- sljit_emit_op_custom(compiler, instruction, 4);
- return;
+ instruction[0] = 0x66;
+ instruction[1] = 0x0f;
+ }
+else
+ {
+ /* Two byte VEX prefix. */
+ instruction[0] = 0xc5;
+ instruction[1] = 0xfd;
}
-
-instruction[3] = 0x40 | (dst_xmm_reg << 3) | src_general_reg;
-instruction[4] = (sljit_u8)offset;
-sljit_emit_op_custom(compiler, instruction, 5);
-}
-
-static void fast_forward_char_pair_sse2_compare(struct sljit_compiler *compiler, vector_compare_type compare_type,
- int step, sljit_s32 dst_ind, sljit_s32 cmp1_ind, sljit_s32 cmp2_ind, sljit_s32 tmp_ind)
-{
-sljit_u8 instruction[4];
-instruction[0] = 0x66;
-instruction[1] = 0x0f;
SLJIT_ASSERT(step >= 0 && step <= 3);
@@ -139,8 +147,10 @@ if (compare_type != vector_compare_match2)
if (compare_type == vector_compare_match1i)
{
/* POR xmm1, xmm2/m128 */
- /* instruction[0] = 0x66; */
- /* instruction[1] = 0x0f; */
+ if (reg_type == SLJIT_SIMD_REG_256)
+ instruction[1] ^= (dst_ind << 3);
+
+ /* Prefix is filled. */
instruction[2] = 0xeb;
instruction[3] = 0xc0 | (dst_ind << 3) | cmp2_ind;
sljit_emit_op_custom(compiler, instruction, 4);
@@ -152,20 +162,35 @@ if (compare_type != vector_compare_match2)
return;
/* PCMPEQB/W/D xmm1, xmm2/m128 */
- /* instruction[0] = 0x66; */
- /* instruction[1] = 0x0f; */
- instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX;
+ if (reg_type == SLJIT_SIMD_REG_256)
+ instruction[1] ^= (dst_ind << 3);
+
+ /* Prefix is filled. */
+ instruction[2] = 0x74 + SIMD_COMPARE_TYPE_INDEX;
instruction[3] = 0xc0 | (dst_ind << 3) | cmp1_ind;
sljit_emit_op_custom(compiler, instruction, 4);
return;
}
+if (reg_type == SLJIT_SIMD_REG_256)
+ {
+ if (step == 2)
+ return;
+
+ if (step == 0)
+ {
+ step = 2;
+ instruction[1] ^= (dst_ind << 3);
+ }
+ }
+
switch (step)
{
case 0:
+ SLJIT_ASSERT(reg_type == SLJIT_SIMD_REG_128);
+
/* MOVDQA xmm1, xmm2/m128 */
- /* instruction[0] = 0x66; */
- /* instruction[1] = 0x0f; */
+ /* Prefix is filled. */
instruction[2] = 0x6f;
instruction[3] = 0xc0 | (tmp_ind << 3) | dst_ind;
sljit_emit_op_custom(compiler, instruction, 4);
@@ -173,26 +198,29 @@ switch (step)
case 1:
/* PCMPEQB/W/D xmm1, xmm2/m128 */
- /* instruction[0] = 0x66; */
- /* instruction[1] = 0x0f; */
- instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX;
+ if (reg_type == SLJIT_SIMD_REG_256)
+ instruction[1] ^= (dst_ind << 3);
+
+ /* Prefix is filled. */
+ instruction[2] = 0x74 + SIMD_COMPARE_TYPE_INDEX;
instruction[3] = 0xc0 | (dst_ind << 3) | cmp1_ind;
sljit_emit_op_custom(compiler, instruction, 4);
return;
case 2:
/* PCMPEQB/W/D xmm1, xmm2/m128 */
- /* instruction[0] = 0x66; */
- /* instruction[1] = 0x0f; */
- instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX;
+ /* Prefix is filled. */
+ instruction[2] = 0x74 + SIMD_COMPARE_TYPE_INDEX;
instruction[3] = 0xc0 | (tmp_ind << 3) | cmp2_ind;
sljit_emit_op_custom(compiler, instruction, 4);
return;
case 3:
/* POR xmm1, xmm2/m128 */
- /* instruction[0] = 0x66; */
- /* instruction[1] = 0x0f; */
+ if (reg_type == SLJIT_SIMD_REG_256)
+ instruction[1] ^= (dst_ind << 3);
+
+ /* Prefix is filled. */
instruction[2] = 0xeb;
instruction[3] = 0xc0 | (dst_ind << 3) | tmp_ind;
sljit_emit_op_custom(compiler, instruction, 4);
@@ -200,12 +228,16 @@ switch (step)
}
}
-#define JIT_HAS_FAST_FORWARD_CHAR_SIMD (sljit_has_cpu_feature(SLJIT_HAS_SSE2))
+#define JIT_HAS_FAST_FORWARD_CHAR_SIMD (sljit_has_cpu_feature(SLJIT_HAS_SIMD))
static void fast_forward_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2, sljit_s32 offset)
{
DEFINE_COMPILER;
sljit_u8 instruction[8];
+/* The AVX2 code path is currently disabled. */
+/* sljit_s32 reg_type = sljit_has_cpu_feature(SLJIT_HAS_AVX2) ? SLJIT_SIMD_REG_256 : SLJIT_SIMD_REG_128; */
+sljit_s32 reg_type = SLJIT_SIMD_REG_128;
+sljit_s32 value;
struct sljit_label *start;
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
struct sljit_label *restart;
@@ -213,12 +245,11 @@ struct sljit_label *restart;
struct sljit_jump *quit;
struct sljit_jump *partial_quit[2];
vector_compare_type compare_type = vector_compare_match1;
-sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1);
-sljit_s32 str_ptr_reg_ind = sljit_get_register_index(STR_PTR);
-sljit_s32 data_ind = 0;
-sljit_s32 tmp_ind = 1;
-sljit_s32 cmp1_ind = 2;
-sljit_s32 cmp2_ind = 3;
+sljit_s32 tmp1_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP1);
+sljit_s32 data_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR0);
+sljit_s32 cmp1_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR1);
+sljit_s32 cmp2_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR2);
+sljit_s32 tmp_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR3);
sljit_u32 bit = 0;
int i;
@@ -241,61 +272,34 @@ if (common->mode == PCRE2_JIT_COMPLETE)
add_jump(compiler, &common->failed_match, partial_quit[0]);
/* First part (unaligned start) */
-
-OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1 | bit));
-
-SLJIT_ASSERT(tmp1_reg_ind < 8);
-
-/* MOVD xmm, r/m32 */
-instruction[0] = 0x66;
-instruction[1] = 0x0f;
-instruction[2] = 0x6e;
-instruction[3] = 0xc0 | (cmp1_ind << 3) | tmp1_reg_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
+value = SLJIT_SIMD_REG_128 | SLJIT_SIMD_ELEM_32 | SLJIT_SIMD_LANE_ZERO;
+sljit_emit_simd_lane_mov(compiler, value, SLJIT_FR1, 0, SLJIT_IMM, character_to_int32(char1 | bit));
if (char1 != char2)
- {
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(bit != 0 ? bit : char2));
-
- /* MOVD xmm, r/m32 */
- instruction[3] = 0xc0 | (cmp2_ind << 3) | tmp1_reg_ind;
- sljit_emit_op_custom(compiler, instruction, 4);
- }
+ sljit_emit_simd_lane_mov(compiler, value, SLJIT_FR2, 0, SLJIT_IMM, character_to_int32(bit != 0 ? bit : char2));
OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0);
-/* PSHUFD xmm1, xmm2/m128, imm8 */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0x70;
-instruction[3] = 0xc0 | (cmp1_ind << 3) | cmp1_ind;
-instruction[4] = 0;
-sljit_emit_op_custom(compiler, instruction, 5);
+sljit_emit_simd_lane_replicate(compiler, reg_type | SLJIT_SIMD_ELEM_32, SLJIT_FR1, SLJIT_FR1, 0);
if (char1 != char2)
- {
- /* PSHUFD xmm1, xmm2/m128, imm8 */
- instruction[3] = 0xc0 | (cmp2_ind << 3) | cmp2_ind;
- sljit_emit_op_custom(compiler, instruction, 5);
- }
+ sljit_emit_simd_lane_replicate(compiler, reg_type | SLJIT_SIMD_ELEM_32, SLJIT_FR2, SLJIT_FR2, 0);
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
restart = LABEL();
#endif
-OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~0xf);
-OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf);
-load_from_mem_sse2(compiler, data_ind, str_ptr_reg_ind, 0);
-for (i = 0; i < 4; i++)
- fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+value = (reg_type == SLJIT_SIMD_REG_256) ? 0x1f : 0xf;
+OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~value);
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, value);
-/* PMOVMSKB reg, xmm */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0xd7;
-instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | data_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
+value = (reg_type == SLJIT_SIMD_REG_256) ? SLJIT_SIMD_MEM_ALIGNED_256 : SLJIT_SIMD_MEM_ALIGNED_128;
+sljit_emit_simd_mov(compiler, reg_type | value, SLJIT_FR0, SLJIT_MEM1(STR_PTR), 0);
+for (i = 0; i < 4; i++)
+ fast_forward_char_pair_sse2_compare(compiler, compare_type, reg_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+sljit_emit_simd_sign(compiler, SLJIT_SIMD_STORE | reg_type | SLJIT_SIMD_ELEM_8, SLJIT_FR0, TMP1, 0);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, TMP2, 0);
@@ -306,27 +310,24 @@ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
/* Second part (aligned) */
start = LABEL();
-OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16);
+value = (reg_type == SLJIT_SIMD_REG_256) ? 32 : 16;
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, value);
partial_quit[1] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
if (common->mode == PCRE2_JIT_COMPLETE)
add_jump(compiler, &common->failed_match, partial_quit[1]);
-load_from_mem_sse2(compiler, data_ind, str_ptr_reg_ind, 0);
+value = (reg_type == SLJIT_SIMD_REG_256) ? SLJIT_SIMD_MEM_ALIGNED_256 : SLJIT_SIMD_MEM_ALIGNED_128;
+sljit_emit_simd_mov(compiler, reg_type | value, SLJIT_FR0, SLJIT_MEM1(STR_PTR), 0);
for (i = 0; i < 4; i++)
- fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
-
-/* PMOVMSKB reg, xmm */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0xd7;
-instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | data_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
+ fast_forward_char_pair_sse2_compare(compiler, compare_type, reg_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+sljit_emit_simd_sign(compiler, SLJIT_SIMD_STORE | reg_type | SLJIT_SIMD_ELEM_8, SLJIT_FR0, TMP1, 0);
CMPTO(SLJIT_ZERO, TMP1, 0, SLJIT_IMM, 0, start);
JUMPHERE(quit);
+SLJIT_ASSERT(tmp1_reg_ind < 8);
/* BSF r32, r/m32 */
instruction[0] = 0x0f;
instruction[1] = 0xbc;
@@ -340,7 +341,7 @@ if (common->mode != PCRE2_JIT_COMPLETE)
JUMPHERE(partial_quit[0]);
JUMPHERE(partial_quit[1]);
OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_PTR, 0, STR_END, 0);
- CMOV(SLJIT_GREATER, STR_PTR, STR_END, 0);
+ SELECT(SLJIT_GREATER, STR_PTR, STR_END, 0, STR_PTR);
}
else
add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
@@ -364,22 +365,25 @@ if (common->utf && offset > 0)
#endif
}
-#define JIT_HAS_FAST_REQUESTED_CHAR_SIMD (sljit_has_cpu_feature(SLJIT_HAS_SSE2))
+#define JIT_HAS_FAST_REQUESTED_CHAR_SIMD (sljit_has_cpu_feature(SLJIT_HAS_SIMD))
static jump_list *fast_requested_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2)
{
DEFINE_COMPILER;
sljit_u8 instruction[8];
+/* The AVX2 code path is currently disabled. */
+/* sljit_s32 reg_type = sljit_has_cpu_feature(SLJIT_HAS_AVX2) ? SLJIT_SIMD_REG_256 : SLJIT_SIMD_REG_128; */
+sljit_s32 reg_type = SLJIT_SIMD_REG_128;
+sljit_s32 value;
struct sljit_label *start;
struct sljit_jump *quit;
jump_list *not_found = NULL;
vector_compare_type compare_type = vector_compare_match1;
-sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1);
-sljit_s32 str_ptr_reg_ind = sljit_get_register_index(STR_PTR);
-sljit_s32 data_ind = 0;
-sljit_s32 tmp_ind = 1;
-sljit_s32 cmp1_ind = 2;
-sljit_s32 cmp2_ind = 3;
+sljit_s32 tmp1_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP1);
+sljit_s32 data_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR0);
+sljit_s32 cmp1_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR1);
+sljit_s32 cmp2_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR2);
+sljit_s32 tmp_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR3);
sljit_u32 bit = 0;
int i;
@@ -401,57 +405,30 @@ OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0);
/* First part (unaligned start) */
-OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1 | bit));
-
-SLJIT_ASSERT(tmp1_reg_ind < 8);
-
-/* MOVD xmm, r/m32 */
-instruction[0] = 0x66;
-instruction[1] = 0x0f;
-instruction[2] = 0x6e;
-instruction[3] = 0xc0 | (cmp1_ind << 3) | tmp1_reg_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
+value = SLJIT_SIMD_REG_128 | SLJIT_SIMD_ELEM_32 | SLJIT_SIMD_LANE_ZERO;
+sljit_emit_simd_lane_mov(compiler, value, SLJIT_FR1, 0, SLJIT_IMM, character_to_int32(char1 | bit));
if (char1 != char2)
- {
- OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(bit != 0 ? bit : char2));
-
- /* MOVD xmm, r/m32 */
- instruction[3] = 0xc0 | (cmp2_ind << 3) | tmp1_reg_ind;
- sljit_emit_op_custom(compiler, instruction, 4);
- }
+ sljit_emit_simd_lane_mov(compiler, value, SLJIT_FR2, 0, SLJIT_IMM, character_to_int32(bit != 0 ? bit : char2));
OP1(SLJIT_MOV, STR_PTR, 0, TMP2, 0);
-/* PSHUFD xmm1, xmm2/m128, imm8 */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0x70;
-instruction[3] = 0xc0 | (cmp1_ind << 3) | cmp1_ind;
-instruction[4] = 0;
-sljit_emit_op_custom(compiler, instruction, 5);
+sljit_emit_simd_lane_replicate(compiler, reg_type | SLJIT_SIMD_ELEM_32, SLJIT_FR1, SLJIT_FR1, 0);
if (char1 != char2)
- {
- /* PSHUFD xmm1, xmm2/m128, imm8 */
- instruction[3] = 0xc0 | (cmp2_ind << 3) | cmp2_ind;
- sljit_emit_op_custom(compiler, instruction, 5);
- }
+ sljit_emit_simd_lane_replicate(compiler, reg_type | SLJIT_SIMD_ELEM_32, SLJIT_FR2, SLJIT_FR2, 0);
-OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~0xf);
-OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf);
+value = (reg_type == SLJIT_SIMD_REG_256) ? 0x1f : 0xf;
+OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~value);
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, value);
-load_from_mem_sse2(compiler, data_ind, str_ptr_reg_ind, 0);
-for (i = 0; i < 4; i++)
- fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+value = (reg_type == SLJIT_SIMD_REG_256) ? SLJIT_SIMD_MEM_ALIGNED_256 : SLJIT_SIMD_MEM_ALIGNED_128;
+sljit_emit_simd_mov(compiler, reg_type | value, SLJIT_FR0, SLJIT_MEM1(STR_PTR), 0);
-/* PMOVMSKB reg, xmm */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0xd7;
-instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | data_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
+for (i = 0; i < 4; i++)
+ fast_forward_char_pair_sse2_compare(compiler, compare_type, reg_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+sljit_emit_simd_sign(compiler, SLJIT_SIMD_STORE | reg_type | SLJIT_SIMD_ELEM_8, SLJIT_FR0, TMP1, 0);
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, TMP2, 0);
@@ -462,25 +439,23 @@ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
/* Second part (aligned) */
start = LABEL();
-OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16);
+value = (reg_type == SLJIT_SIMD_REG_256) ? 32 : 16;
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, value);
add_jump(compiler, &not_found, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
-load_from_mem_sse2(compiler, data_ind, str_ptr_reg_ind, 0);
-for (i = 0; i < 4; i++)
- fast_forward_char_pair_sse2_compare(compiler, compare_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+value = (reg_type == SLJIT_SIMD_REG_256) ? SLJIT_SIMD_MEM_ALIGNED_256 : SLJIT_SIMD_MEM_ALIGNED_128;
+sljit_emit_simd_mov(compiler, reg_type | value, SLJIT_FR0, SLJIT_MEM1(STR_PTR), 0);
-/* PMOVMSKB reg, xmm */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0xd7;
-instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | data_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
+for (i = 0; i < 4; i++)
+ fast_forward_char_pair_sse2_compare(compiler, compare_type, reg_type, i, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+sljit_emit_simd_sign(compiler, SLJIT_SIMD_STORE | reg_type | SLJIT_SIMD_ELEM_8, SLJIT_FR0, TMP1, 0);
CMPTO(SLJIT_ZERO, TMP1, 0, SLJIT_IMM, 0, start);
JUMPHERE(quit);
+SLJIT_ASSERT(tmp1_reg_ind < 8);
/* BSF r32, r/m32 */
instruction[0] = 0x0f;
instruction[1] = 0xbc;
@@ -496,29 +471,31 @@ return not_found;
#ifndef _WIN64
-#define JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD (sljit_has_cpu_feature(SLJIT_HAS_SSE2))
+#define JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD (sljit_has_cpu_feature(SLJIT_HAS_SIMD))
static void fast_forward_char_pair_simd(compiler_common *common, sljit_s32 offs1,
PCRE2_UCHAR char1a, PCRE2_UCHAR char1b, sljit_s32 offs2, PCRE2_UCHAR char2a, PCRE2_UCHAR char2b)
{
DEFINE_COMPILER;
sljit_u8 instruction[8];
+/* The AVX2 code path is currently disabled. */
+/* sljit_s32 reg_type = sljit_has_cpu_feature(SLJIT_HAS_AVX2) ? SLJIT_SIMD_REG_256 : SLJIT_SIMD_REG_128; */
+sljit_s32 reg_type = SLJIT_SIMD_REG_128;
+sljit_s32 value;
vector_compare_type compare1_type = vector_compare_match1;
vector_compare_type compare2_type = vector_compare_match1;
sljit_u32 bit1 = 0;
sljit_u32 bit2 = 0;
sljit_u32 diff = IN_UCHARS(offs1 - offs2);
-sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1);
-sljit_s32 tmp2_reg_ind = sljit_get_register_index(TMP2);
-sljit_s32 str_ptr_reg_ind = sljit_get_register_index(STR_PTR);
-sljit_s32 data1_ind = 0;
-sljit_s32 data2_ind = 1;
-sljit_s32 tmp1_ind = 2;
-sljit_s32 tmp2_ind = 3;
-sljit_s32 cmp1a_ind = 4;
-sljit_s32 cmp1b_ind = 5;
-sljit_s32 cmp2a_ind = 6;
-sljit_s32 cmp2b_ind = 7;
+sljit_s32 tmp1_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP1);
+sljit_s32 data1_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR0);
+sljit_s32 data2_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR1);
+sljit_s32 cmp1a_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR2);
+sljit_s32 cmp2a_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR3);
+sljit_s32 cmp1b_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR4);
+sljit_s32 cmp2b_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR5);
+sljit_s32 tmp1_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_FR6);
+sljit_s32 tmp2_ind = sljit_get_register_index(SLJIT_FLOAT_REGISTER, SLJIT_TMP_FR0);
struct sljit_label *start;
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
struct sljit_label *restart;
@@ -526,9 +503,8 @@ struct sljit_label *restart;
struct sljit_jump *jump[2];
int i;
-SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE && offs1 > offs2);
-SLJIT_ASSERT(diff <= IN_UCHARS(max_fast_forward_char_pair_offset()));
-SLJIT_ASSERT(tmp1_reg_ind < 8 && tmp2_reg_ind == 1);
+SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE && offs1 > offs2 && offs2 >= 0);
+SLJIT_ASSERT(diff <= (unsigned)IN_UCHARS(max_fast_forward_char_pair_offset()));
/* Initialize. */
if (common->match_end_ptr != 0)
@@ -538,17 +514,12 @@ if (common->match_end_ptr != 0)
OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(offs1 + 1));
OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP1, 0, STR_END, 0);
- CMOV(SLJIT_LESS, STR_END, TMP1, 0);
+ SELECT(SLJIT_LESS, STR_END, TMP1, 0, STR_END);
}
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offs1));
add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
-/* MOVD xmm, r/m32 */
-instruction[0] = 0x66;
-instruction[1] = 0x0f;
-instruction[2] = 0x6e;
-
if (char1a == char1b)
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1a));
else
@@ -569,14 +540,11 @@ else
}
}
-instruction[3] = 0xc0 | (cmp1a_ind << 3) | tmp1_reg_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
+value = SLJIT_SIMD_REG_128 | SLJIT_SIMD_ELEM_32 | SLJIT_SIMD_LANE_ZERO;
+sljit_emit_simd_lane_mov(compiler, value, SLJIT_FR2, 0, TMP1, 0);
if (char1a != char1b)
- {
- instruction[3] = 0xc0 | (cmp1b_ind << 3) | tmp2_reg_ind;
- sljit_emit_op_custom(compiler, instruction, 4);
- }
+ sljit_emit_simd_lane_mov(compiler, value, SLJIT_FR4, 0, TMP2, 0);
if (char2a == char2b)
OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char2a));
@@ -598,38 +566,18 @@ else
}
}
-instruction[3] = 0xc0 | (cmp2a_ind << 3) | tmp1_reg_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
+sljit_emit_simd_lane_mov(compiler, value, SLJIT_FR3, 0, TMP1, 0);
if (char2a != char2b)
- {
- instruction[3] = 0xc0 | (cmp2b_ind << 3) | tmp2_reg_ind;
- sljit_emit_op_custom(compiler, instruction, 4);
- }
-
-/* PSHUFD xmm1, xmm2/m128, imm8 */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0x70;
-instruction[4] = 0;
-
-instruction[3] = 0xc0 | (cmp1a_ind << 3) | cmp1a_ind;
-sljit_emit_op_custom(compiler, instruction, 5);
+ sljit_emit_simd_lane_mov(compiler, value, SLJIT_FR5, 0, TMP2, 0);
+sljit_emit_simd_lane_replicate(compiler, reg_type | SLJIT_SIMD_ELEM_32, SLJIT_FR2, SLJIT_FR2, 0);
if (char1a != char1b)
- {
- instruction[3] = 0xc0 | (cmp1b_ind << 3) | cmp1b_ind;
- sljit_emit_op_custom(compiler, instruction, 5);
- }
-
-instruction[3] = 0xc0 | (cmp2a_ind << 3) | cmp2a_ind;
-sljit_emit_op_custom(compiler, instruction, 5);
+ sljit_emit_simd_lane_replicate(compiler, reg_type | SLJIT_SIMD_ELEM_32, SLJIT_FR4, SLJIT_FR4, 0);
+sljit_emit_simd_lane_replicate(compiler, reg_type | SLJIT_SIMD_ELEM_32, SLJIT_FR3, SLJIT_FR3, 0);
if (char2a != char2b)
- {
- instruction[3] = 0xc0 | (cmp2b_ind << 3) | cmp2b_ind;
- sljit_emit_op_custom(compiler, instruction, 5);
- }
+ sljit_emit_simd_lane_replicate(compiler, reg_type | SLJIT_SIMD_ELEM_32, SLJIT_FR5, SLJIT_FR5, 0);
#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
restart = LABEL();
@@ -637,55 +585,91 @@ restart = LABEL();
OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, diff);
OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0);
-OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~0xf);
+value = (reg_type == SLJIT_SIMD_REG_256) ? ~0x1f : ~0xf;
+OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, value);
-load_from_mem_sse2(compiler, data1_ind, str_ptr_reg_ind, 0);
+value = (reg_type == SLJIT_SIMD_REG_256) ? SLJIT_SIMD_MEM_ALIGNED_256 : SLJIT_SIMD_MEM_ALIGNED_128;
+sljit_emit_simd_mov(compiler, reg_type | value, SLJIT_FR0, SLJIT_MEM1(STR_PTR), 0);
jump[0] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_PTR, 0);
-load_from_mem_sse2(compiler, data2_ind, str_ptr_reg_ind, -(sljit_s8)diff);
+sljit_emit_simd_mov(compiler, reg_type, SLJIT_FR1, SLJIT_MEM1(STR_PTR), -(sljit_sw)diff);
jump[1] = JUMP(SLJIT_JUMP);
JUMPHERE(jump[0]);
-/* MOVDQA xmm1, xmm2/m128 */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0x6f;
-instruction[3] = 0xc0 | (data2_ind << 3) | data1_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
-
-/* PSLLDQ xmm1, imm8 */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0x73;
-instruction[3] = 0xc0 | (7 << 3) | data2_ind;
-instruction[4] = diff;
-sljit_emit_op_custom(compiler, instruction, 5);
+if (reg_type == SLJIT_SIMD_REG_256)
+ {
+ if (diff != 16)
+ {
+ /* PSLLDQ ymm1, ymm2, imm8 */
+ instruction[0] = 0xc5;
+ instruction[1] = (sljit_u8)(0xf9 ^ (data2_ind << 3));
+ instruction[2] = 0x73;
+ instruction[3] = 0xc0 | (7 << 3) | data1_ind;
+ instruction[4] = diff & 0xf;
+ sljit_emit_op_custom(compiler, instruction, 5);
+ }
+
+ instruction[0] = 0xc4;
+ instruction[1] = 0xe3;
+ if (diff < 16)
+ {
+ /* VINSERTI128 xmm1, xmm2, xmm3/m128 */
+ /* instruction[0] = 0xc4; */
+ /* instruction[1] = 0xe3; */
+ instruction[2] = (sljit_u8)(0x7d ^ (data2_ind << 3));
+ instruction[3] = 0x38;
+ SLJIT_ASSERT(sljit_get_register_index(SLJIT_GP_REGISTER, STR_PTR) <= 7);
+ instruction[4] = 0x40 | (data2_ind << 3) | sljit_get_register_index(SLJIT_GP_REGISTER, STR_PTR);
+ instruction[5] = (sljit_u8)(16 - diff);
+ instruction[6] = 1;
+ sljit_emit_op_custom(compiler, instruction, 7);
+ }
+ else
+ {
+ /* VPERM2I128 xmm1, xmm2, xmm3/m128 */
+ /* instruction[0] = 0xc4; */
+ /* instruction[1] = 0xe3; */
+ value = (diff == 16) ? data1_ind : data2_ind;
+ instruction[2] = (sljit_u8)(0x7d ^ (value << 3));
+ instruction[3] = 0x46;
+ instruction[4] = 0xc0 | (data2_ind << 3) | value;
+ instruction[5] = 0x08;
+ sljit_emit_op_custom(compiler, instruction, 6);
+ }
+ }
+else
+ {
+ /* MOVDQA xmm1, xmm2/m128 */
+ instruction[0] = 0x66;
+ instruction[1] = 0x0f;
+ instruction[2] = 0x6f;
+ instruction[3] = 0xc0 | (data2_ind << 3) | data1_ind;
+ sljit_emit_op_custom(compiler, instruction, 4);
+
+ /* PSLLDQ xmm1, imm8 */
+ /* instruction[0] = 0x66; */
+ /* instruction[1] = 0x0f; */
+ instruction[2] = 0x73;
+ instruction[3] = 0xc0 | (7 << 3) | data2_ind;
+ instruction[4] = diff;
+ sljit_emit_op_custom(compiler, instruction, 5);
+ }
JUMPHERE(jump[1]);
-OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf);
+value = (reg_type == SLJIT_SIMD_REG_256) ? 0x1f : 0xf;
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, value);
for (i = 0; i < 4; i++)
{
- fast_forward_char_pair_sse2_compare(compiler, compare2_type, i, data2_ind, cmp2a_ind, cmp2b_ind, tmp2_ind);
- fast_forward_char_pair_sse2_compare(compiler, compare1_type, i, data1_ind, cmp1a_ind, cmp1b_ind, tmp1_ind);
+ fast_forward_char_pair_sse2_compare(compiler, compare2_type, reg_type, i, data2_ind, cmp2a_ind, cmp2b_ind, tmp2_ind);
+ fast_forward_char_pair_sse2_compare(compiler, compare1_type, reg_type, i, data1_ind, cmp1a_ind, cmp1b_ind, tmp1_ind);
}
-/* PAND xmm1, xmm2/m128 */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0xdb;
-instruction[3] = 0xc0 | (data1_ind << 3) | data2_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
-
-/* PMOVMSKB reg, xmm */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0xd7;
-instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | 0;
-sljit_emit_op_custom(compiler, instruction, 4);
+sljit_emit_simd_op2(compiler, SLJIT_SIMD_OP2_AND | reg_type, SLJIT_FR0, SLJIT_FR0, SLJIT_FR1);
+sljit_emit_simd_sign(compiler, SLJIT_SIMD_STORE | reg_type | SLJIT_SIMD_ELEM_8, SLJIT_FR0, TMP1, 0);
/* Ignore matches before the first STR_PTR. */
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
@@ -698,36 +682,28 @@ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
/* Main loop. */
start = LABEL();
-OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16);
+value = (reg_type == SLJIT_SIMD_REG_256) ? 32 : 16;
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, value);
add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
-load_from_mem_sse2(compiler, data1_ind, str_ptr_reg_ind, 0);
-load_from_mem_sse2(compiler, data2_ind, str_ptr_reg_ind, -(sljit_s8)diff);
+value = (reg_type == SLJIT_SIMD_REG_256) ? SLJIT_SIMD_MEM_ALIGNED_256 : SLJIT_SIMD_MEM_ALIGNED_128;
+sljit_emit_simd_mov(compiler, reg_type | value, SLJIT_FR0, SLJIT_MEM1(STR_PTR), 0);
+sljit_emit_simd_mov(compiler, reg_type, SLJIT_FR1, SLJIT_MEM1(STR_PTR), -(sljit_sw)diff);
for (i = 0; i < 4; i++)
{
- fast_forward_char_pair_sse2_compare(compiler, compare1_type, i, data1_ind, cmp1a_ind, cmp1b_ind, tmp2_ind);
- fast_forward_char_pair_sse2_compare(compiler, compare2_type, i, data2_ind, cmp2a_ind, cmp2b_ind, tmp1_ind);
+ fast_forward_char_pair_sse2_compare(compiler, compare1_type, reg_type, i, data1_ind, cmp1a_ind, cmp1b_ind, tmp2_ind);
+ fast_forward_char_pair_sse2_compare(compiler, compare2_type, reg_type, i, data2_ind, cmp2a_ind, cmp2b_ind, tmp1_ind);
}
-/* PAND xmm1, xmm2/m128 */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0xdb;
-instruction[3] = 0xc0 | (data1_ind << 3) | data2_ind;
-sljit_emit_op_custom(compiler, instruction, 4);
-
-/* PMOVMSKB reg, xmm */
-/* instruction[0] = 0x66; */
-/* instruction[1] = 0x0f; */
-instruction[2] = 0xd7;
-instruction[3] = 0xc0 | (tmp1_reg_ind << 3) | 0;
-sljit_emit_op_custom(compiler, instruction, 4);
+sljit_emit_simd_op2(compiler, SLJIT_SIMD_OP2_AND | reg_type, SLJIT_FR0, SLJIT_FR0, SLJIT_FR1);
+sljit_emit_simd_sign(compiler, SLJIT_SIMD_STORE | reg_type | SLJIT_SIMD_ELEM_8, SLJIT_FR0, TMP1, 0);
CMPTO(SLJIT_ZERO, TMP1, 0, SLJIT_IMM, 0, start);
JUMPHERE(jump[0]);
+SLJIT_ASSERT(tmp1_reg_ind < 8);
/* BSF r32, r/m32 */
instruction[0] = 0x0f;
instruction[1] = 0xbc;
@@ -762,7 +738,7 @@ if (common->match_end_ptr != 0)
#endif /* !_WIN64 */
-#undef SSE2_COMPARE_TYPE_INDEX
+#undef SIMD_COMPARE_TYPE_INDEX
#endif /* SLJIT_CONFIG_X86 */
@@ -865,14 +841,14 @@ static void fast_forward_char_simd(compiler_common *common, PCRE2_UCHAR char1, P
{
DEFINE_COMPILER;
int_char ic;
-struct sljit_jump *partial_quit;
+struct sljit_jump *partial_quit, *quit;
/* Save temporary registers. */
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STR_PTR, 0);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP3, 0);
/* Prepare function arguments */
OP1(SLJIT_MOV, SLJIT_R0, 0, STR_END, 0);
-OP1(SLJIT_MOV, SLJIT_R1, 0, STR_PTR, 0);
+GET_LOCAL_BASE(SLJIT_R1, 0, LOCALS0);
OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, offset);
if (char1 == char2)
@@ -944,9 +920,14 @@ if (common->mode == PCRE2_JIT_COMPLETE)
/* Fast forward STR_PTR to the result of memchr. */
OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0);
-
if (common->mode != PCRE2_JIT_COMPLETE)
+ {
+ quit = CMP(SLJIT_NOT_ZERO, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
JUMPHERE(partial_quit);
+ OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_PTR, 0, STR_END, 0);
+ SELECT(SLJIT_GREATER, STR_PTR, STR_END, 0, STR_PTR);
+ JUMPHERE(quit);
+ }
}
typedef enum {
@@ -1068,10 +1049,10 @@ else
OP2(SLJIT_ADD, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_IMM, IN_UCHARS(offs1 + 1));
OP2U(SLJIT_SUB | SLJIT_SET_LESS, STR_END, 0, SLJIT_R0, 0);
- CMOV(SLJIT_LESS, SLJIT_R0, STR_END, 0);
+ SELECT(SLJIT_LESS, SLJIT_R0, STR_END, 0, SLJIT_R0);
}
-OP1(SLJIT_MOV, SLJIT_R1, 0, STR_PTR, 0);
+GET_LOCAL_BASE(SLJIT_R1, 0, LOCALS0);
OP1(SLJIT_MOV_S32, SLJIT_R2, 0, SLJIT_IMM, offs1);
OP1(SLJIT_MOV_S32, SLJIT_R3, 0, SLJIT_IMM, offs2);
ic.c.c1 = char1a;
@@ -1177,7 +1158,7 @@ if (step == 0)
OP1(SLJIT_MOV, tmp_general_reg, 0, SLJIT_IMM, chr);
/* VLVG */
- instruction[0] = (sljit_u16)(0xe700 | (dst_vreg << 4) | sljit_get_register_index(tmp_general_reg));
+ instruction[0] = (sljit_u16)(0xe700 | (dst_vreg << 4) | sljit_get_register_index(SLJIT_GP_REGISTER, tmp_general_reg));
instruction[1] = 0;
instruction[2] = (sljit_u16)((VECTOR_ELEMENT_SIZE << 12) | (0x8 << 8) | 0x22);
sljit_emit_op_custom(compiler, instruction, 6);
@@ -1256,8 +1237,8 @@ struct sljit_label *restart;
struct sljit_jump *quit;
struct sljit_jump *partial_quit[2];
vector_compare_type compare_type = vector_compare_match1;
-sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1);
-sljit_s32 str_ptr_reg_ind = sljit_get_register_index(STR_PTR);
+sljit_s32 tmp1_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP1);
+sljit_s32 str_ptr_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, STR_PTR);
sljit_s32 data_ind = 0;
sljit_s32 tmp_ind = 1;
sljit_s32 cmp1_ind = 2;
@@ -1419,7 +1400,7 @@ if (common->mode != PCRE2_JIT_COMPLETE)
JUMPHERE(partial_quit[0]);
JUMPHERE(partial_quit[1]);
OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_PTR, 0, STR_END, 0);
- CMOV(SLJIT_GREATER, STR_PTR, STR_END, 0);
+ SELECT(SLJIT_GREATER, STR_PTR, STR_END, 0, STR_PTR);
}
else
add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
@@ -1454,8 +1435,8 @@ struct sljit_label *start;
struct sljit_jump *quit;
jump_list *not_found = NULL;
vector_compare_type compare_type = vector_compare_match1;
-sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1);
-sljit_s32 tmp3_reg_ind = sljit_get_register_index(TMP3);
+sljit_s32 tmp1_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP1);
+sljit_s32 tmp3_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP3);
sljit_s32 data_ind = 0;
sljit_s32 tmp_ind = 1;
sljit_s32 cmp1_ind = 2;
@@ -1624,9 +1605,9 @@ vector_compare_type compare2_type = vector_compare_match1;
sljit_u32 bit1 = 0;
sljit_u32 bit2 = 0;
sljit_s32 diff = IN_UCHARS(offs2 - offs1);
-sljit_s32 tmp1_reg_ind = sljit_get_register_index(TMP1);
-sljit_s32 tmp2_reg_ind = sljit_get_register_index(TMP2);
-sljit_s32 str_ptr_reg_ind = sljit_get_register_index(STR_PTR);
+sljit_s32 tmp1_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP1);
+sljit_s32 tmp2_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP2);
+sljit_s32 str_ptr_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, STR_PTR);
sljit_s32 data1_ind = 0;
sljit_s32 data2_ind = 1;
sljit_s32 tmp1_ind = 2;
@@ -1674,7 +1655,7 @@ if (common->match_end_ptr != 0)
OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(offs1 + 1));
OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP1, 0, STR_END, 0);
- CMOV(SLJIT_LESS, STR_END, TMP1, 0);
+ SELECT(SLJIT_LESS, STR_END, TMP1, 0, STR_END);
}
OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offs1));
@@ -1855,4 +1836,520 @@ if (common->match_end_ptr != 0)
#endif /* SLJIT_CONFIG_S390X */
+#if (defined SLJIT_CONFIG_LOONGARCH_64 && SLJIT_CONFIG_LOONGARCH_64)
+
+#ifdef __linux__
+/* Using getauxval(AT_HWCAP) under Linux for detecting whether LSX is available */
+#include <sys/auxv.h>
+#define LOONGARCH_HWCAP_LSX (1 << 4)
+#define HAS_LSX_SUPPORT ((getauxval(AT_HWCAP) & LOONGARCH_HWCAP_LSX) != 0)
+#else
+#define HAS_LSX_SUPPORT 0
+#endif
+
+typedef sljit_ins sljit_u32;
+
+#define SI12_IMM_MASK 0x003ffc00
+#define UI5_IMM_MASK 0x00007c00
+#define UI2_IMM_MASK 0x00000c00
+
+#define VD(vd) ((sljit_ins)vd << 0)
+#define VJ(vj) ((sljit_ins)vj << 5)
+#define VK(vk) ((sljit_ins)vk << 10)
+#define RD_V(rd) ((sljit_ins)rd << 0)
+#define RJ_V(rj) ((sljit_ins)rj << 5)
+
+#define IMM_SI12(imm) (((sljit_ins)(imm) << 10) & SI12_IMM_MASK)
+#define IMM_UI5(imm) (((sljit_ins)(imm) << 10) & UI5_IMM_MASK)
+#define IMM_UI2(imm) (((sljit_ins)(imm) << 10) & UI2_IMM_MASK)
+
+// LSX OPCODES:
+#define VLD 0x2c000000
+#define VOR_V 0x71268000
+#define VAND_V 0x71260000
+#define VBSLL_V 0x728e0000
+#define VMSKLTZ_B 0x729c4000
+#define VPICKVE2GR_WU 0x72f3e000
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define VREPLGR2VR 0x729f0000
+#define VSEQ 0x70000000
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+#define VREPLGR2VR 0x729f0400
+#define VSEQ 0x70008000
+#else
+#define VREPLGR2VR 0x729f0800
+#define VSEQ 0x70010000
+#endif
+
+static void fast_forward_char_pair_lsx_compare(struct sljit_compiler *compiler, vector_compare_type compare_type,
+ sljit_s32 dst_ind, sljit_s32 cmp1_ind, sljit_s32 cmp2_ind, sljit_s32 tmp_ind)
+{
+if (compare_type != vector_compare_match2)
+ {
+ if (compare_type == vector_compare_match1i)
+ {
+ /* VOR.V vd, vj, vk */
+ push_inst(compiler, VOR_V | VD(dst_ind) | VJ(cmp2_ind) | VK(dst_ind));
+ }
+
+ /* VSEQ.B/H/W vd, vj, vk */
+ push_inst(compiler, VSEQ | VD(dst_ind) | VJ(dst_ind) | VK(cmp1_ind));
+ return;
+ }
+
+/* VBSLL.V vd, vj, ui5 */
+push_inst(compiler, VBSLL_V | VD(tmp_ind) | VJ(dst_ind) | IMM_UI5(0));
+
+/* VSEQ.B/H/W vd, vj, vk */
+push_inst(compiler, VSEQ | VD(dst_ind) | VJ(dst_ind) | VK(cmp1_ind));
+
+/* VSEQ.B/H/W vd, vj, vk */
+push_inst(compiler, VSEQ | VD(tmp_ind) | VJ(tmp_ind) | VK(cmp2_ind));
+
+/* VOR vd, vj, vk */
+push_inst(compiler, VOR_V | VD(dst_ind) | VJ(tmp_ind) | VK(dst_ind));
+return;
+}
+
+#define JIT_HAS_FAST_FORWARD_CHAR_SIMD HAS_LSX_SUPPORT
+
+static void fast_forward_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2, sljit_s32 offset)
+{
+DEFINE_COMPILER;
+struct sljit_label *start;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+struct sljit_label *restart;
+#endif
+struct sljit_jump *quit;
+struct sljit_jump *partial_quit[2];
+vector_compare_type compare_type = vector_compare_match1;
+sljit_s32 tmp1_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP1);
+sljit_s32 str_ptr_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, STR_PTR);
+sljit_s32 data_ind = 0;
+sljit_s32 tmp_ind = 1;
+sljit_s32 cmp1_ind = 2;
+sljit_s32 cmp2_ind = 3;
+sljit_u32 bit = 0;
+
+SLJIT_UNUSED_ARG(offset);
+
+if (char1 != char2)
+ {
+ bit = char1 ^ char2;
+ compare_type = vector_compare_match1i;
+
+ if (!is_powerof2(bit))
+ {
+ bit = 0;
+ compare_type = vector_compare_match2;
+ }
+ }
+
+partial_quit[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+if (common->mode == PCRE2_JIT_COMPLETE)
+ add_jump(compiler, &common->failed_match, partial_quit[0]);
+
+/* First part (unaligned start) */
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, char1 | bit);
+
+/* VREPLGR2VR.B/H/W vd, rj */
+push_inst(compiler, VREPLGR2VR | VD(cmp1_ind) | RJ_V(tmp1_reg_ind));
+
+if (char1 != char2)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, bit != 0 ? bit : char2);
+
+ /* VREPLGR2VR.B/H/W vd, rj */
+ push_inst(compiler, VREPLGR2VR | VD(cmp2_ind) | RJ_V(tmp1_reg_ind));
+ }
+
+OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0);
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+restart = LABEL();
+#endif
+
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf);
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+/* VLD vd, rj, si12 */
+push_inst(compiler, VLD | VD(data_ind) | RJ_V(str_ptr_reg_ind) | IMM_SI12(0));
+fast_forward_char_pair_lsx_compare(compiler, compare_type, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+/* VMSKLTZ.B vd, vj */
+push_inst(compiler, VMSKLTZ_B | VD(tmp_ind) | VJ(data_ind));
+
+/* VPICKVE2GR.WU rd, vj, ui2 */
+push_inst(compiler, VPICKVE2GR_WU | RD_V(tmp1_reg_ind) | VJ(tmp_ind) | IMM_UI2(0));
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+quit = CMP(SLJIT_NOT_ZERO, TMP1, 0, SLJIT_IMM, 0);
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+/* Second part (aligned) */
+start = LABEL();
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16);
+
+partial_quit[1] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+if (common->mode == PCRE2_JIT_COMPLETE)
+ add_jump(compiler, &common->failed_match, partial_quit[1]);
+
+/* VLD vd, rj, si12 */
+push_inst(compiler, VLD | VD(data_ind) | RJ_V(str_ptr_reg_ind) | IMM_SI12(0));
+fast_forward_char_pair_lsx_compare(compiler, compare_type, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+/* VMSKLTZ.B vd, vj */
+push_inst(compiler, VMSKLTZ_B | VD(tmp_ind) | VJ(data_ind));
+
+/* VPICKVE2GR.WU rd, vj, ui2 */
+push_inst(compiler, VPICKVE2GR_WU | RD_V(tmp1_reg_ind) | VJ(tmp_ind) | IMM_UI2(0));
+
+CMPTO(SLJIT_ZERO, TMP1, 0, SLJIT_IMM, 0, start);
+
+JUMPHERE(quit);
+
+/* CTZ.W rd, rj */
+push_inst(compiler, CTZ_W | RD_V(tmp1_reg_ind) | RJ_V(tmp1_reg_ind));
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+
+if (common->mode != PCRE2_JIT_COMPLETE)
+ {
+ JUMPHERE(partial_quit[0]);
+ JUMPHERE(partial_quit[1]);
+ OP2U(SLJIT_SUB | SLJIT_SET_GREATER, STR_PTR, 0, STR_END, 0);
+ SELECT(SLJIT_GREATER, STR_PTR, STR_END, 0, STR_PTR);
+ }
+else
+ add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+if (common->utf && offset > 0)
+ {
+ SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE);
+
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offset));
+
+ quit = jump_if_utf_char_start(compiler, TMP1);
+
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+ OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0);
+ JUMPTO(SLJIT_JUMP, restart);
+
+ JUMPHERE(quit);
+ }
+#endif
+}
+
+#define JIT_HAS_FAST_REQUESTED_CHAR_SIMD HAS_LSX_SUPPORT
+
+static jump_list *fast_requested_char_simd(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2)
+{
+DEFINE_COMPILER;
+struct sljit_label *start;
+struct sljit_jump *quit;
+jump_list *not_found = NULL;
+vector_compare_type compare_type = vector_compare_match1;
+sljit_s32 tmp1_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP1);
+sljit_s32 str_ptr_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, STR_PTR);
+sljit_s32 data_ind = 0;
+sljit_s32 tmp_ind = 1;
+sljit_s32 cmp1_ind = 2;
+sljit_s32 cmp2_ind = 3;
+sljit_u32 bit = 0;
+
+if (char1 != char2)
+ {
+ bit = char1 ^ char2;
+ compare_type = vector_compare_match1i;
+
+ if (!is_powerof2(bit))
+ {
+ bit = 0;
+ compare_type = vector_compare_match2;
+ }
+ }
+
+add_jump(compiler, &not_found, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_END, 0));
+OP1(SLJIT_MOV, TMP2, 0, TMP1, 0);
+OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0);
+
+/* First part (unaligned start) */
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, char1 | bit);
+
+/* VREPLGR2VR vd, rj */
+push_inst(compiler, VREPLGR2VR | VD(cmp1_ind) | RJ_V(tmp1_reg_ind));
+
+if (char1 != char2)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, bit != 0 ? bit : char2);
+ /* VREPLGR2VR vd, rj */
+ push_inst(compiler, VREPLGR2VR | VD(cmp2_ind) | RJ_V(tmp1_reg_ind));
+ }
+
+OP1(SLJIT_MOV, STR_PTR, 0, TMP2, 0);
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf);
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+/* VLD vd, rj, si12 */
+push_inst(compiler, VLD | VD(data_ind) | RJ_V(str_ptr_reg_ind) | IMM_SI12(0));
+fast_forward_char_pair_lsx_compare(compiler, compare_type, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+/* VMSKLTZ.B vd, vj */
+push_inst(compiler, VMSKLTZ_B | VD(tmp_ind) | VJ(data_ind));
+
+/* VPICKVE2GR.WU rd, vj, ui2 */
+push_inst(compiler, VPICKVE2GR_WU | RD_V(tmp1_reg_ind) | VJ(tmp_ind) | IMM_UI2(0));
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+quit = CMP(SLJIT_NOT_ZERO, TMP1, 0, SLJIT_IMM, 0);
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+/* Second part (aligned) */
+start = LABEL();
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16);
+
+add_jump(compiler, &not_found, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+/* VLD vd, rj, si12 */
+push_inst(compiler, VLD | VD(data_ind) | RJ_V(str_ptr_reg_ind) | IMM_SI12(0));
+fast_forward_char_pair_lsx_compare(compiler, compare_type, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+/* VMSKLTZ.B vd, vj */
+push_inst(compiler, VMSKLTZ_B | VD(tmp_ind) | VJ(data_ind));
+
+/* VPICKVE2GR.WU rd, vj, ui2 */
+push_inst(compiler, VPICKVE2GR_WU | RD_V(tmp1_reg_ind) | VJ(tmp_ind) | IMM_UI2(0));
+
+CMPTO(SLJIT_ZERO, TMP1, 0, SLJIT_IMM, 0, start);
+
+JUMPHERE(quit);
+
+/* CTZ.W rd, rj */
+push_inst(compiler, CTZ_W | RD_V(tmp1_reg_ind) | RJ_V(tmp1_reg_ind));
+
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, STR_PTR, 0);
+add_jump(compiler, &not_found, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_END, 0));
+
+OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0);
+return not_found;
+}
+
+#define JIT_HAS_FAST_FORWARD_CHAR_PAIR_SIMD HAS_LSX_SUPPORT
+
+static void fast_forward_char_pair_simd(compiler_common *common, sljit_s32 offs1,
+ PCRE2_UCHAR char1a, PCRE2_UCHAR char1b, sljit_s32 offs2, PCRE2_UCHAR char2a, PCRE2_UCHAR char2b)
+{
+DEFINE_COMPILER;
+vector_compare_type compare1_type = vector_compare_match1;
+vector_compare_type compare2_type = vector_compare_match1;
+sljit_u32 bit1 = 0;
+sljit_u32 bit2 = 0;
+sljit_u32 diff = IN_UCHARS(offs1 - offs2);
+sljit_s32 tmp1_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP1);
+sljit_s32 tmp2_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, TMP2);
+sljit_s32 str_ptr_reg_ind = sljit_get_register_index(SLJIT_GP_REGISTER, STR_PTR);
+sljit_s32 data1_ind = 0;
+sljit_s32 data2_ind = 1;
+sljit_s32 tmp1_ind = 2;
+sljit_s32 tmp2_ind = 3;
+sljit_s32 cmp1a_ind = 4;
+sljit_s32 cmp1b_ind = 5;
+sljit_s32 cmp2a_ind = 6;
+sljit_s32 cmp2b_ind = 7;
+struct sljit_label *start;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+struct sljit_label *restart;
+#endif
+struct sljit_jump *jump[2];
+
+SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE && offs1 > offs2);
+SLJIT_ASSERT(diff <= IN_UCHARS(max_fast_forward_char_pair_offset()));
+
+/* Initialize. */
+if (common->match_end_ptr != 0)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
+ OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(offs1 + 1));
+ OP1(SLJIT_MOV, TMP3, 0, STR_END, 0);
+
+ OP2U(SLJIT_SUB | SLJIT_SET_LESS, TMP1, 0, STR_END, 0);
+ SELECT(SLJIT_LESS, STR_END, TMP1, 0, STR_END);
+ }
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offs1));
+add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+if (char1a == char1b)
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, char1a);
+else
+ {
+ bit1 = char1a ^ char1b;
+ if (is_powerof2(bit1))
+ {
+ compare1_type = vector_compare_match1i;
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, char1a | bit1);
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, bit1);
+ }
+ else
+ {
+ compare1_type = vector_compare_match2;
+ bit1 = 0;
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, char1a);
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, char1b);
+ }
+ }
+
+/* VREPLGR2VR vd, rj */
+push_inst(compiler, VREPLGR2VR | VD(cmp1a_ind) | RJ_V(tmp1_reg_ind));
+
+if (char1a != char1b)
+ {
+ /* VREPLGR2VR vd, rj */
+ push_inst(compiler, VREPLGR2VR | VD(cmp1b_ind) | RJ_V(tmp2_reg_ind));
+ }
+
+if (char2a == char2b)
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, char2a);
+else
+ {
+ bit2 = char2a ^ char2b;
+ if (is_powerof2(bit2))
+ {
+ compare2_type = vector_compare_match1i;
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, char2a | bit2);
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, bit2);
+ }
+ else
+ {
+ compare2_type = vector_compare_match2;
+ bit2 = 0;
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, char2a);
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, char2b);
+ }
+ }
+
+/* VREPLGR2VR vd, rj */
+push_inst(compiler, VREPLGR2VR | VD(cmp2a_ind) | RJ_V(tmp1_reg_ind));
+
+if (char2a != char2b)
+ {
+ /* VREPLGR2VR vd, rj */
+ push_inst(compiler, VREPLGR2VR | VD(cmp2b_ind) | RJ_V(tmp2_reg_ind));
+ }
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+restart = LABEL();
+#endif
+
+OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, diff);
+OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0);
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf);
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+/* VLD vd, rj, si12 */
+push_inst(compiler, VLD | VD(data1_ind) | RJ_V(str_ptr_reg_ind) | IMM_SI12(0));
+
+jump[0] = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_PTR, 0);
+
+/* VLD vd, rj, si12 */
+push_inst(compiler, VLD | VD(data2_ind) | RJ_V(str_ptr_reg_ind) | IMM_SI12(-(sljit_s8)diff));
+jump[1] = JUMP(SLJIT_JUMP);
+
+JUMPHERE(jump[0]);
+
+/* VBSLL.V vd, vj, ui5 */
+push_inst(compiler, VBSLL_V | VD(data2_ind) | VJ(data1_ind) | IMM_UI5(diff));
+
+JUMPHERE(jump[1]);
+
+fast_forward_char_pair_lsx_compare(compiler, compare2_type, data2_ind, cmp2a_ind, cmp2b_ind, tmp2_ind);
+fast_forward_char_pair_lsx_compare(compiler, compare1_type, data1_ind, cmp1a_ind, cmp1b_ind, tmp1_ind);
+
+/* VAND vd, vj, vk */
+push_inst(compiler, VOR_V | VD(data1_ind) | VJ(data1_ind) | VK(data2_ind));
+
+/* VMSKLTZ.B vd, vj */
+push_inst(compiler, VMSKLTZ_B | VD(tmp1_ind) | VJ(data1_ind));
+
+/* VPICKVE2GR.WU rd, vj, ui2 */
+push_inst(compiler, VPICKVE2GR_WU | RD_V(tmp1_reg_ind) | VJ(tmp1_ind) | IMM_UI2(0));
+
+/* Ignore matches before the first STR_PTR. */
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+jump[0] = CMP(SLJIT_NOT_ZERO, TMP1, 0, SLJIT_IMM, 0);
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+/* Main loop. */
+start = LABEL();
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16);
+add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+/* VLD vd, rj, si12 */
+push_inst(compiler, VLD | VD(data1_ind) | RJ_V(str_ptr_reg_ind) | IMM_SI12(0));
+push_inst(compiler, VLD | VD(data2_ind) | RJ_V(str_ptr_reg_ind) | IMM_SI12(-(sljit_s8)diff));
+
+fast_forward_char_pair_lsx_compare(compiler, compare1_type, data1_ind, cmp1a_ind, cmp1b_ind, tmp2_ind);
+fast_forward_char_pair_lsx_compare(compiler, compare2_type, data2_ind, cmp2a_ind, cmp2b_ind, tmp1_ind);
+
+/* VAND.V vd, vj, vk */
+push_inst(compiler, VAND_V | VD(data1_ind) | VJ(data1_ind) | VK(data2_ind));
+
+/* VMSKLTZ.B vd, vj */
+push_inst(compiler, VMSKLTZ_B | VD(tmp1_ind) | VJ(data1_ind));
+
+/* VPICKVE2GR.WU rd, vj, ui2 */
+push_inst(compiler, VPICKVE2GR_WU | RD_V(tmp1_reg_ind) | VJ(tmp1_ind) | IMM_UI2(0));
+
+CMPTO(SLJIT_ZERO, TMP1, 0, SLJIT_IMM, 0, start);
+
+JUMPHERE(jump[0]);
+
+/* CTZ.W rd, rj */
+push_inst(compiler, CTZ_W | RD_V(tmp1_reg_ind) | RJ_V(tmp1_reg_ind));
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+
+add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+if (common->utf)
+ {
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offs1));
+
+ jump[0] = jump_if_utf_char_start(compiler, TMP1);
+
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, restart);
+
+ add_jump(compiler, &common->failed_match, JUMP(SLJIT_JUMP));
+
+ JUMPHERE(jump[0]);
+ }
+#endif
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offs1));
+
+if (common->match_end_ptr != 0)
+ OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
+}
+
+#endif /* SLJIT_CONFIG_LOONGARCH_64 */
+
#endif /* !SUPPORT_VALGRIND */
diff --git a/src/3rdparty/pcre2/src/pcre2_maketables.c b/src/3rdparty/pcre2/src/pcre2_maketables.c
index 56d2494023..ac8b63b809 100644
--- a/src/3rdparty/pcre2/src/pcre2_maketables.c
+++ b/src/3rdparty/pcre2/src/pcre2_maketables.c
@@ -52,8 +52,6 @@ PCRE2_DFTABLES is defined. */
# include "pcre2_internal.h"
#endif
-
-
/*************************************************
* Create PCRE2 character tables *
*************************************************/
@@ -98,7 +96,11 @@ for (i = 0; i < 256; i++) *p++ = tolower(i);
/* Next the case-flipping table */
-for (i = 0; i < 256; i++) *p++ = islower(i)? toupper(i) : tolower(i);
+for (i = 0; i < 256; i++)
+ {
+ int c = islower(i)? toupper(i) : tolower(i);
+ *p++ = (c < 256)? c : i;
+ }
/* Then the character class tables. Don't try to be clever and save effort on
exclusive ones - in some locales things may be different.
diff --git a/src/3rdparty/pcre2/src/pcre2_match.c b/src/3rdparty/pcre2/src/pcre2_match.c
index 168b9fad01..b4a970313d 100644
--- a/src/3rdparty/pcre2/src/pcre2_match.c
+++ b/src/3rdparty/pcre2/src/pcre2_match.c
@@ -7,7 +7,7 @@ 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) 2015-2022 University of Cambridge
+ New API code Copyright (c) 2015-2024 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -43,6 +43,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include "config.h"
#endif
+#include "pcre2_internal.h"
+
/* These defines enable debugging code */
/* #define DEBUG_FRAMES_DISPLAY */
@@ -53,6 +55,10 @@ POSSIBILITY OF SUCH DAMAGE.
#include <stdarg.h>
#endif
+#ifdef DEBUG_SHOW_OPS
+static const char *OP_names[] = { OP_NAME_LIST };
+#endif
+
/* These defines identify the name of the block containing "static"
information, and fields within it. */
@@ -60,8 +66,6 @@ information, and fields within it. */
#define PSSTART start_subject /* Field containing processed string start */
#define PSEND end_subject /* Field containing processed string end */
-#include "pcre2_internal.h"
-
#define RECURSE_UNSET 0xffffffffu /* Bigger than max group number */
/* Masks for identifying the public options that are permitted at match time. */
@@ -69,7 +73,8 @@ information, and fields within it. */
#define PUBLIC_MATCH_OPTIONS \
(PCRE2_ANCHORED|PCRE2_ENDANCHORED|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY| \
PCRE2_NOTEMPTY_ATSTART|PCRE2_NO_UTF_CHECK|PCRE2_PARTIAL_HARD| \
- PCRE2_PARTIAL_SOFT|PCRE2_NO_JIT|PCRE2_COPY_MATCHED_SUBJECT)
+ PCRE2_PARTIAL_SOFT|PCRE2_NO_JIT|PCRE2_COPY_MATCHED_SUBJECT| \
+ PCRE2_DISABLE_RECURSELOOP_CHECK)
#define PUBLIC_JIT_MATCH_OPTIONS \
(PCRE2_NO_UTF_CHECK|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY|\
@@ -150,7 +155,7 @@ changed, the code at RETURN_SWITCH below must be updated in sync. */
enum { RM1=1, RM2, RM3, RM4, RM5, RM6, RM7, RM8, RM9, RM10,
RM11, RM12, RM13, RM14, RM15, RM16, RM17, RM18, RM19, RM20,
RM21, RM22, RM23, RM24, RM25, RM26, RM27, RM28, RM29, RM30,
- RM31, RM32, RM33, RM34, RM35, RM36 };
+ RM31, RM32, RM33, RM34, RM35, RM36, RM37 };
#ifdef SUPPORT_WIDE_CHARS
enum { RM100=100, RM101 };
@@ -597,11 +602,12 @@ heapframe *P = NULL;
heapframe *frames_top; /* End of frames vector */
heapframe *assert_accept_frame = NULL; /* For passing back a frame with captures */
-PCRE2_SIZE heapframes_size; /* Usable size of frames vector */
PCRE2_SIZE frame_copy_size; /* Amount to copy when creating a new frame */
/* Local variables that do not need to be preserved over calls to RRMATCH(). */
+PCRE2_SPTR branch_end = NULL;
+PCRE2_SPTR branch_start;
PCRE2_SPTR bracode; /* Temp pointer to start of group */
PCRE2_SIZE offset; /* Used for group offsets */
PCRE2_SIZE length; /* Used for various length calculations */
@@ -635,13 +641,10 @@ copied when a new frame is created. */
frame_copy_size = frame_size - offsetof(heapframe, eptr);
-/* Set up the first frame and the end of the frames vector. We set the local
-heapframes_size to the usuable amount of the vector, that is, a whole number of
-frames. */
+/* Set up the first frame and the end of the frames vector. */
F = match_data->heapframes;
-heapframes_size = (match_data->heapframes_size / frame_size) * frame_size;
-frames_top = (heapframe *)((char *)F + heapframes_size);
+frames_top = (heapframe *)((char *)F + match_data->heapframes_size);
Frdepth = 0; /* "Recursion" depth */
Fcapture_last = 0; /* Number of most recent capture */
@@ -662,35 +665,54 @@ MATCH_RECURSE:
doubling the size, but constrained by the heap limit (which is in KiB). */
N = (heapframe *)((char *)F + frame_size);
-if (N >= frames_top)
+if ((heapframe *)((char *)N + frame_size) >= frames_top)
{
heapframe *new;
- PCRE2_SIZE newsize = match_data->heapframes_size * 2;
+ PCRE2_SIZE newsize;
+ PCRE2_SIZE usedsize = (char *)N - (char *)(match_data->heapframes);
- if (newsize > mb->heap_limit)
+ if (match_data->heapframes_size >= PCRE2_SIZE_MAX / 2)
{
- PCRE2_SIZE maxsize = (mb->heap_limit/frame_size) * frame_size;
- if (match_data->heapframes_size >= maxsize) return PCRE2_ERROR_HEAPLIMIT;
- newsize = maxsize;
+ if (match_data->heapframes_size == PCRE2_SIZE_MAX - 1)
+ return PCRE2_ERROR_NOMEMORY;
+ newsize = PCRE2_SIZE_MAX - 1;
}
+ else
+ newsize = match_data->heapframes_size * 2;
+ if (newsize / 1024 >= mb->heap_limit)
+ {
+ PCRE2_SIZE old_size = match_data->heapframes_size / 1024;
+ if (mb->heap_limit <= old_size)
+ return PCRE2_ERROR_HEAPLIMIT;
+ else
+ {
+ PCRE2_SIZE max_delta = 1024 * (mb->heap_limit - old_size);
+ int over_bytes = match_data->heapframes_size % 1024;
+ if (over_bytes) max_delta -= (1024 - over_bytes);
+ newsize = match_data->heapframes_size + max_delta;
+ }
+ }
+
+ /* With a heap limit set, the permitted additional size may not be enough for
+ another frame, so do a final check. */
+
+ if (newsize - usedsize < frame_size) return PCRE2_ERROR_HEAPLIMIT;
new = match_data->memctl.malloc(newsize, match_data->memctl.memory_data);
if (new == NULL) return PCRE2_ERROR_NOMEMORY;
- memcpy(new, match_data->heapframes, heapframes_size);
+ memcpy(new, match_data->heapframes, usedsize);
- F = (heapframe *)((char *)new + ((char *)F - (char *)match_data->heapframes));
- N = (heapframe *)((char *)F + frame_size);
+ N = (heapframe *)((char *)new + usedsize);
+ F = (heapframe *)((char *)N - frame_size);
match_data->memctl.free(match_data->heapframes, match_data->memctl.memory_data);
match_data->heapframes = new;
match_data->heapframes_size = newsize;
-
- heapframes_size = (newsize / frame_size) * frame_size;
- frames_top = (heapframe *)((char *)new + heapframes_size);
+ frames_top = (heapframe *)((char *)new + newsize);
}
#ifdef DEBUG_SHOW_RMATCH
-fprintf(stderr, "++ RMATCH %2d frame=%d", Freturn_id, Frdepth + 1);
+fprintf(stderr, "++ RMATCH %d frame=%d", Freturn_id, Frdepth + 1);
if (group_frame_type != 0)
{
fprintf(stderr, " type=%x ", group_frame_type);
@@ -760,10 +782,16 @@ opcodes. */
if (mb->match_call_count++ >= mb->match_limit) return PCRE2_ERROR_MATCHLIMIT;
if (Frdepth >= mb->match_limit_depth) return PCRE2_ERROR_DEPTHLIMIT;
+#ifdef DEBUG_SHOW_OPS
+fprintf(stderr, "\n++ New frame: type=0x%x subject offset %ld\n",
+ GF_IDMASK(Fgroup_frame_type), Feptr - mb->start_subject);
+#endif
+
for (;;)
{
#ifdef DEBUG_SHOW_OPS
-fprintf(stderr, "++ op=%d\n", *Fecode);
+fprintf(stderr, "++ %2ld op=%3d %s\n", Fecode - mb->start_code, *Fecode,
+ OP_names[*Fecode]);
#endif
Fop = (uint8_t)(*Fecode); /* Cast needed for 16-bit and 32-bit modes */
@@ -811,15 +839,16 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
assert_accept_frame = F;
RRETURN(MATCH_ACCEPT);
- /* If recursing, we have to find the most recent recursion. */
+ /* For ACCEPT within a recursion, we have to find the most recent
+ recursion. If not in a recursion, fall through to code that is common with
+ OP_END. */
case OP_ACCEPT:
- case OP_END:
-
- /* Handle end of a recursion. */
-
if (Fcurrent_recurse != RECURSE_UNSET)
{
+#ifdef DEBUG_SHOW_OPS
+ fprintf(stderr, "++ Accept within recursion\n");
+#endif
offset = Flast_group_offset;
for(;;)
{
@@ -842,27 +871,49 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
Fecode += 1 + LINK_SIZE;
continue;
}
+ /* Fall through */
+
+ /* OP_END itself can never be reached within a recursion because that is
+ picked up when the OP_KET that always precedes OP_END is reached. */
+
+ case OP_END:
- /* Not a recursion. Fail for an empty string match 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. */
+ /* Fail for an empty string match 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 (Feptr == Fstart_match &&
((mb->moptions & PCRE2_NOTEMPTY) != 0 ||
((mb->moptions & PCRE2_NOTEMPTY_ATSTART) != 0 &&
Fstart_match == mb->start_subject + mb->start_offset)))
+ {
+#ifdef DEBUG_SHOW_OPS
+ fprintf(stderr, "++ Backtrack because empty string\n");
+#endif
RRETURN(MATCH_NOMATCH);
+ }
- /* Also fail if PCRE2_ENDANCHORED is set and the end of the match is not
+ /* Fail if PCRE2_ENDANCHORED is set and the end of the match is not
the end of the subject. After (*ACCEPT) we fail the entire match (at this
- position) but backtrack on reaching the end of the pattern. */
+ position) but backtrack if we've reached the end of the pattern. This
+ applies whether or not we are in a recursion. */
if (Feptr < mb->end_subject &&
((mb->moptions | mb->poptions) & PCRE2_ENDANCHORED) != 0)
{
- if (Fop == OP_END) RRETURN(MATCH_NOMATCH);
- return MATCH_NOMATCH;
+ if (Fop == OP_END)
+ {
+#ifdef DEBUG_SHOW_OPS
+ fprintf(stderr, "++ Backtrack because not at end (endanchored set)\n");
+#endif
+ RRETURN(MATCH_NOMATCH);
+ }
+
+#ifdef DEBUG_SHOW_OPS
+ fprintf(stderr, "++ Failed ACCEPT not at end (endanchnored set)\n");
+#endif
+ return MATCH_NOMATCH; /* (*ACCEPT) */
}
/* We have a successful match of the whole pattern. Record the result and
@@ -2435,6 +2486,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
GETCHARINCTEST(fc, Feptr);
{
const uint32_t *cp;
+ uint32_t chartype;
const ucd_record *prop = GET_UCD(fc);
BOOL notmatch = Fop == OP_NOTPROP;
@@ -2445,9 +2497,10 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
break;
case PT_LAMP:
- if ((prop->chartype == ucp_Lu ||
- prop->chartype == ucp_Ll ||
- prop->chartype == ucp_Lt) == notmatch)
+ chartype = prop->chartype;
+ if ((chartype == ucp_Lu ||
+ chartype == ucp_Ll ||
+ chartype == ucp_Lt) == notmatch)
RRETURN(MATCH_NOMATCH);
break;
@@ -2477,8 +2530,9 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
/* These are specials */
case PT_ALNUM:
- if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
- PRIV(ucp_gentype)[prop->chartype] == ucp_N) == notmatch)
+ chartype = prop->chartype;
+ if ((PRIV(ucp_gentype)[chartype] == ucp_L ||
+ PRIV(ucp_gentype)[chartype] == ucp_N) == notmatch)
RRETURN(MATCH_NOMATCH);
break;
@@ -2503,13 +2557,22 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
break;
case PT_WORD:
- if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
- PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
- fc == CHAR_UNDERSCORE) == notmatch)
+ chartype = prop->chartype;
+ if ((PRIV(ucp_gentype)[chartype] == ucp_L ||
+ PRIV(ucp_gentype)[chartype] == ucp_N ||
+ chartype == ucp_Mn ||
+ chartype == ucp_Pc) == notmatch)
RRETURN(MATCH_NOMATCH);
break;
case PT_CLIST:
+#if PCRE2_CODE_UNIT_WIDTH == 32
+ if (fc > MAX_UTF_CODE_POINT)
+ {
+ if (notmatch) break;;
+ RRETURN(MATCH_NOMATCH);
+ }
+#endif
cp = PRIV(ucd_caseless_sets) + Fecode[2];
for (;;)
{
@@ -2805,16 +2868,17 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
case PT_WORD:
for (i = 1; i <= Lmin; i++)
{
- int category;
+ int chartype, category;
if (Feptr >= mb->end_subject)
{
SCHECK_PARTIAL();
RRETURN(MATCH_NOMATCH);
}
GETCHARINCTEST(fc, Feptr);
- category = UCD_CATEGORY(fc);
+ chartype = UCD_CHARTYPE(fc);
+ category = PRIV(ucp_gentype)[chartype];
if ((category == ucp_L || category == ucp_N ||
- fc == CHAR_UNDERSCORE) == notmatch)
+ chartype == ucp_Mn || chartype == ucp_Pc) == notmatch)
RRETURN(MATCH_NOMATCH);
}
break;
@@ -2829,6 +2893,13 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
RRETURN(MATCH_NOMATCH);
}
GETCHARINCTEST(fc, Feptr);
+#if PCRE2_CODE_UNIT_WIDTH == 32
+ if (fc > MAX_UTF_CODE_POINT)
+ {
+ if (notmatch) continue;
+ RRETURN(MATCH_NOMATCH);
+ }
+#endif
cp = PRIV(ucd_caseless_sets) + Lpropvalue;
for (;;)
{
@@ -3609,7 +3680,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
case PT_WORD:
for (;;)
{
- int category;
+ int chartype, category;
RMATCH(Fecode, RM215);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
@@ -3619,10 +3690,12 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
RRETURN(MATCH_NOMATCH);
}
GETCHARINCTEST(fc, Feptr);
- category = UCD_CATEGORY(fc);
+ chartype = UCD_CHARTYPE(fc);
+ category = PRIV(ucp_gentype)[chartype];
if ((category == ucp_L ||
category == ucp_N ||
- fc == CHAR_UNDERSCORE) == (Lctype == OP_NOTPROP))
+ chartype == ucp_Mn ||
+ chartype == ucp_Pc) == (Lctype == OP_NOTPROP))
RRETURN(MATCH_NOMATCH);
}
/* Control never gets here */
@@ -3640,6 +3713,13 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
RRETURN(MATCH_NOMATCH);
}
GETCHARINCTEST(fc, Feptr);
+#if PCRE2_CODE_UNIT_WIDTH == 32
+ if (fc > MAX_UTF_CODE_POINT)
+ {
+ if (Lctype == OP_NOTPROP) continue;
+ RRETURN(MATCH_NOMATCH);
+ }
+#endif
cp = PRIV(ucd_caseless_sets) + Lpropvalue;
for (;;)
{
@@ -4190,7 +4270,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
case PT_WORD:
for (i = Lmin; i < Lmax; i++)
{
- int category;
+ int chartype, category;
int len = 1;
if (Feptr >= mb->end_subject)
{
@@ -4198,9 +4278,12 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
break;
}
GETCHARLENTEST(fc, Feptr, len);
- category = UCD_CATEGORY(fc);
- if ((category == ucp_L || category == ucp_N ||
- fc == CHAR_UNDERSCORE) == notmatch)
+ chartype = UCD_CHARTYPE(fc);
+ category = PRIV(ucp_gentype)[chartype];
+ if ((category == ucp_L ||
+ category == ucp_N ||
+ chartype == ucp_Mn ||
+ chartype == ucp_Pc) == notmatch)
break;
Feptr+= len;
}
@@ -4217,14 +4300,24 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
break;
}
GETCHARLENTEST(fc, Feptr, len);
- cp = PRIV(ucd_caseless_sets) + Lpropvalue;
- for (;;)
+#if PCRE2_CODE_UNIT_WIDTH == 32
+ if (fc > MAX_UTF_CODE_POINT)
{
- if (fc < *cp)
- { if (notmatch) break; else goto GOT_MAX; }
- if (fc == *cp++)
- { if (notmatch) goto GOT_MAX; else break; }
+ if (!notmatch) goto GOT_MAX;
+ }
+ else
+#endif
+ {
+ cp = PRIV(ucd_caseless_sets) + Lpropvalue;
+ for (;;)
+ {
+ if (fc < *cp)
+ { if (notmatch) break; else goto GOT_MAX; }
+ if (fc == *cp++)
+ { if (notmatch) goto GOT_MAX; else break; }
+ }
}
+
Feptr += len;
}
GOT_MAX:
@@ -5322,9 +5415,11 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
/* ===================================================================== */
- /* Recursion either matches the current regex, or some subexpression. The
- offset data is the offset to the starting bracket from the start of the
- whole pattern. (This is so that it works from duplicated subpatterns.) */
+ /* Pattern recursion either matches the current regex, or some
+ subexpression. The offset data is the offset to the starting bracket from
+ the start of the whole pattern. This is so that it works from duplicated
+ subpatterns. For a whole-pattern recursion, we have to infer the number
+ zero. */
#define Lframe_type F->temp_32[0]
#define Lstart_branch F->temp_sptr[0]
@@ -5333,9 +5428,12 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
bracode = mb->start_code + GET(Fecode, 1);
number = (bracode == mb->start_code)? 0 : GET2(bracode, 1 + LINK_SIZE);
- /* If we are already in a recursion, check for repeating the same one
- without advancing the subject pointer. This should catch convoluted mutual
- recursions. (Some simple cases are caught at compile time.) */
+ /* If we are already in a pattern recursion, check for repeating the same
+ one without changing the subject pointer or the last referenced character
+ in the subject. This should catch convoluted mutual recursions; some
+ simple cases are caught at compile time. However, there are rare cases when
+ this check needs to be turned off. In this case, actual recursion loops
+ will be caught by the match or heap limits. */
if (Fcurrent_recurse != RECURSE_UNSET)
{
@@ -5346,15 +5444,19 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
P = (heapframe *)((char *)N - frame_size);
if (N->group_frame_type == (GF_RECURSE | number))
{
- if (Feptr == P->eptr) return PCRE2_ERROR_RECURSELOOP;
+ if (Feptr == P->eptr && mb->last_used_ptr == P->recurse_last_used &&
+ (mb->moptions & PCRE2_DISABLE_RECURSELOOP_CHECK) == 0)
+ return PCRE2_ERROR_RECURSELOOP;
break;
}
offset = P->last_group_offset;
}
}
- /* Now run the recursion, branch by branch. */
+ /* Remember the current last referenced character and then run the
+ recursion branch by branch. */
+ F->recurse_last_used = mb->last_used_ptr;
Lstart_branch = bracode;
Lframe_type = GF_RECURSE | number;
@@ -5683,13 +5785,13 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
/* ===================================================================== */
- /* Move the subject pointer back. This occurs only at the start of each
- branch of a lookbehind assertion. If we are too close to the start to move
- back, fail. When working with UTF-8 we move back a number of characters,
- not bytes. */
+ /* Move the subject pointer back by one fixed amount. This occurs at the
+ start of each branch that has a fixed length in a lookbehind assertion. If
+ we are too close to the start to move back, fail. When working with UTF-8
+ we move back a number of characters, not bytes. */
case OP_REVERSE:
- number = GET(Fecode, 1);
+ number = GET2(Fecode, 1);
#ifdef SUPPORT_UNICODE
if (utf)
{
@@ -5703,7 +5805,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
else
#endif
- /* No UTF-8 support, or not in UTF-8 mode: count is code unit count */
+ /* No UTF support, or not in UTF mode: count is code unit count */
{
if ((ptrdiff_t)number > Feptr - mb->start_subject) RRETURN(MATCH_NOMATCH);
@@ -5713,15 +5815,84 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
/* Save the earliest consulted character, then skip to next opcode */
if (Feptr < mb->start_used_ptr) mb->start_used_ptr = Feptr;
- Fecode += 1 + LINK_SIZE;
+ Fecode += 1 + IMM2_SIZE;
break;
/* ===================================================================== */
+ /* Move the subject pointer back by a variable amount. This occurs at the
+ start of each branch of a lookbehind assertion when the branch has a
+ variable, but limited, length. A loop is needed to try matching the branch
+ after moving back different numbers of characters. If we are too close to
+ the start to move back even the minimum amount, fail. When working with
+ UTF-8 we move back a number of characters, not bytes. */
+
+#define Lmin F->temp_32[0]
+#define Lmax F->temp_32[1]
+#define Leptr F->temp_sptr[0]
+
+ case OP_VREVERSE:
+ Lmin = GET2(Fecode, 1);
+ Lmax = GET2(Fecode, 1 + IMM2_SIZE);
+ Leptr = Feptr;
+
+ /* Move back by the maximum branch length and then work forwards. This
+ ensures that items such as \d{3,5} get the maximum length, which is
+ relevant for captures, and makes for Perl compatibility. */
+
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ for (i = 0; i < Lmax; i++)
+ {
+ if (Feptr == mb->start_subject)
+ {
+ if (i < Lmin) RRETURN(MATCH_NOMATCH);
+ Lmax = i;
+ break;
+ }
+ Feptr--;
+ BACKCHAR(Feptr);
+ }
+ }
+ else
+#endif
+
+ /* No UTF support or not in UTF mode */
+
+ {
+ ptrdiff_t diff = Feptr - mb->start_subject;
+ uint32_t available = (diff > 65535)? 65535 : ((diff > 0)? diff : 0);
+ if (Lmin > available) RRETURN(MATCH_NOMATCH);
+ if (Lmax > available) Lmax = available;
+ Feptr -= Lmax;
+ }
+
+ /* Now try matching, moving forward one character on failure, until we
+ reach the mimimum back length. */
+
+ for (;;)
+ {
+ RMATCH(Fecode + 1 + 2 * IMM2_SIZE, RM37);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmax-- <= Lmin) RRETURN(MATCH_NOMATCH);
+ Feptr++;
+#ifdef SUPPORT_UNICODE
+ if (utf) { FORWARDCHARTEST(Feptr, mb->end_subject); }
+#endif
+ }
+ /* Control never reaches here */
+
+#undef Lmin
+#undef Lmax
+#undef Leptr
+
+ /* ===================================================================== */
/* An alternation is the end of a branch; scan along to find the end of the
bracketed group. */
case OP_ALT:
+ branch_end = Fecode;
do Fecode += GET(Fecode,1); while (*Fecode == OP_ALT);
break;
@@ -5729,7 +5900,8 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
/* ===================================================================== */
/* The end of a parenthesized group. For all but OP_BRA and OP_COND, the
starting frame was added to the chained frames in order to remember the
- starting subject position for the group. */
+ starting subject position for the group. (Not true for OP_BRA when it's a
+ whole pattern recursion, but that is handled separately below.)*/
case OP_KET:
case OP_KETRMIN:
@@ -5738,8 +5910,14 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
bracode = Fecode - GET(Fecode, 1);
- /* Point N to the frame at the start of the most recent group.
- Remember the subject pointer at the start of the group. */
+ if (branch_end == NULL) branch_end = Fecode;
+ branch_start = bracode;
+ while (branch_start + GET(branch_start, 1) != branch_end)
+ branch_start += GET(branch_start, 1);
+ branch_end = NULL;
+
+ /* Point N to the frame at the start of the most recent group, and P to its
+ predecessor. Remember the subject pointer at the start of the group. */
if (*bracode != OP_BRA && *bracode != OP_COND)
{
@@ -5775,27 +5953,64 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
switch (*bracode)
{
- case OP_BRA: /* No need to do anything for these */
- case OP_COND:
+ /* Whole pattern recursion is handled as a recursion into group 0, but
+ the entire pattern is wrapped in OP_BRA/OP_KET rather than a capturing
+ group - a design mistake: it should perhaps have been capture group 0.
+ Anyway, that means the end of such recursion must be handled here. It is
+ detected by checking for an immediately following OP_END when we are
+ recursing in group 0. If this is not the end of a whole-pattern
+ recursion, there is nothing to be done. */
+
+ case OP_BRA:
+ if (Fcurrent_recurse != 0 || Fecode[1+LINK_SIZE] != OP_END) break;
+
+ /* It is the end of whole-pattern recursion. */
+
+ offset = Flast_group_offset;
+ if (offset == PCRE2_UNSET) return PCRE2_ERROR_INTERNAL;
+ N = (heapframe *)((char *)match_data->heapframes + offset);
+ P = (heapframe *)((char *)N - frame_size);
+ Flast_group_offset = P->last_group_offset;
+
+ /* Reinstate the previous set of captures and then carry on after the
+ recursion call. */
+
+ memcpy((char *)F + offsetof(heapframe, ovector), P->ovector,
+ Foffset_top * sizeof(PCRE2_SIZE));
+ Foffset_top = P->offset_top;
+ Fcapture_last = P->capture_last;
+ Fcurrent_recurse = P->current_recurse;
+ Fecode = P->ecode + 1 + LINK_SIZE;
+ continue; /* With next opcode */
+
+ case OP_COND: /* No need to do anything for these */
case OP_SCOND:
break;
/* Non-atomic positive assertions are like OP_BRA, except that the
subject pointer must be put back to where it was at the start of the
- assertion. */
+ assertion. For a variable lookbehind, check its end point. */
- case OP_ASSERT_NA:
case OP_ASSERTBACK_NA:
+ if (branch_start[1 + LINK_SIZE] == OP_VREVERSE && Feptr != P->eptr)
+ RRETURN(MATCH_NOMATCH);
+ /* Fall through */
+
+ case OP_ASSERT_NA:
if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr;
Feptr = P->eptr;
break;
/* Atomic positive assertions are like OP_ONCE, except that in addition
the subject pointer must be put back to where it was at the start of the
- assertion. */
+ assertion. For a variable lookbehind, check its end point. */
- case OP_ASSERT:
case OP_ASSERTBACK:
+ if (branch_start[1 + LINK_SIZE] == OP_VREVERSE && Feptr != P->eptr)
+ RRETURN(MATCH_NOMATCH);
+ /* Fall through */
+
+ case OP_ASSERT:
if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr;
Feptr = P->eptr;
/* Fall through */
@@ -5816,10 +6031,15 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
break;
/* A matching negative assertion returns MATCH, which is turned into
- NOMATCH at the assertion level. */
+ NOMATCH at the assertion level. For a variable lookbehind, check its end
+ point. */
- case OP_ASSERT_NOT:
case OP_ASSERTBACK_NOT:
+ if (branch_start[1 + LINK_SIZE] == OP_VREVERSE && Feptr != P->eptr)
+ RRETURN(MATCH_NOMATCH);
+ /* Fall through */
+
+ case OP_ASSERT_NOT:
RRETURN(MATCH_MATCH);
/* At the end of a script run, apply the script-checking rules. This code
@@ -5830,9 +6050,8 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
if (!PRIV(script_run)(P->eptr, Feptr, utf)) RRETURN(MATCH_NOMATCH);
break;
- /* Whole-pattern recursion is coded as a recurse into group 0, so it
- won't be picked up here. Instead, we catch it when the OP_END is reached.
- Other recursion is handled here. */
+ /* Whole-pattern recursion is coded as a recurse into group 0, and is
+ handled with OP_BRA above. Other recursion is handled here. */
case OP_CBRA:
case OP_CBRAPOS:
@@ -5847,7 +6066,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
{
P = (heapframe *)((char *)N - frame_size);
memcpy((char *)F + offsetof(heapframe, ovector), P->ovector,
- P->offset_top * sizeof(PCRE2_SIZE));
+ Foffset_top * sizeof(PCRE2_SIZE));
Foffset_top = P->offset_top;
Fcapture_last = P->capture_last;
Fcurrent_recurse = P->current_recurse;
@@ -5930,10 +6149,10 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
if ((mb->poptions & PCRE2_DOLLAR_ENDONLY) == 0) goto ASSERT_NL_OR_EOS;
/* Fall through */
- /* Unconditional end of subject assertion (\z) */
+ /* Unconditional end of subject assertion (\z). */
case OP_EOD:
- if (Feptr < mb->end_subject) RRETURN(MATCH_NOMATCH);
+ if (Feptr < mb->true_end_subject) RRETURN(MATCH_NOMATCH);
if (mb->partial != 0)
{
mb->hitend = TRUE;
@@ -6045,6 +6264,8 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
case OP_NOT_WORD_BOUNDARY:
case OP_WORD_BOUNDARY:
+ case OP_NOT_UCP_WORD_BOUNDARY:
+ case OP_UCP_WORD_BOUNDARY:
if (Feptr == mb->check_subject) prev_is_word = FALSE; else
{
PCRE2_SPTR lastptr = Feptr - 1;
@@ -6059,13 +6280,12 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
fc = *lastptr;
if (lastptr < mb->start_used_ptr) mb->start_used_ptr = lastptr;
#ifdef SUPPORT_UNICODE
- if ((mb->poptions & PCRE2_UCP) != 0)
+ if (Fop == OP_UCP_WORD_BOUNDARY || Fop == OP_NOT_UCP_WORD_BOUNDARY)
{
- if (fc == '_') prev_is_word = TRUE; else
- {
- int cat = UCD_CATEGORY(fc);
- prev_is_word = (cat == ucp_L || cat == ucp_N);
- }
+ int chartype = UCD_CHARTYPE(fc);
+ int category = PRIV(ucp_gentype)[chartype];
+ prev_is_word = (category == ucp_L || category == ucp_N ||
+ chartype == ucp_Mn || chartype == ucp_Pc);
}
else
#endif /* SUPPORT_UNICODE */
@@ -6093,13 +6313,12 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
fc = *Feptr;
if (nextptr > mb->last_used_ptr) mb->last_used_ptr = nextptr;
#ifdef SUPPORT_UNICODE
- if ((mb->poptions & PCRE2_UCP) != 0)
+ if (Fop == OP_UCP_WORD_BOUNDARY || Fop == OP_NOT_UCP_WORD_BOUNDARY)
{
- if (fc == '_') cur_is_word = TRUE; else
- {
- int cat = UCD_CATEGORY(fc);
- cur_is_word = (cat == ucp_L || cat == ucp_N);
- }
+ int chartype = UCD_CHARTYPE(fc);
+ int category = PRIV(ucp_gentype)[chartype];
+ cur_is_word = (category == ucp_L || category == ucp_N ||
+ chartype == ucp_Mn || chartype == ucp_Pc);
}
else
#endif /* SUPPORT_UNICODE */
@@ -6108,7 +6327,7 @@ fprintf(stderr, "++ op=%d\n", *Fecode);
/* Now see if the situation is what we want */
- if ((*Fecode++ == OP_WORD_BOUNDARY)?
+ if ((*Fecode++ == OP_WORD_BOUNDARY || Fop == OP_UCP_WORD_BOUNDARY)?
cur_is_word == prev_is_word : cur_is_word != prev_is_word)
RRETURN(MATCH_NOMATCH);
break;
@@ -6254,7 +6473,7 @@ F = (heapframe *)((char *)F - Fback_frame); /* Backtrack */
mb->cb->callout_flags |= PCRE2_CALLOUT_BACKTRACK; /* Note for callouts */
#ifdef DEBUG_SHOW_RMATCH
-fprintf(stderr, "++ RETURN %d to %d\n", rrc, Freturn_id);
+fprintf(stderr, "++ RETURN %d to RM%d\n", rrc, Freturn_id);
#endif
switch (Freturn_id)
@@ -6263,7 +6482,7 @@ switch (Freturn_id)
LBL( 9) LBL(10) LBL(11) LBL(12) LBL(13) LBL(14) LBL(15) LBL(16)
LBL(17) LBL(18) LBL(19) LBL(20) LBL(21) LBL(22) LBL(23) LBL(24)
LBL(25) LBL(26) LBL(27) LBL(28) LBL(29) LBL(30) LBL(31) LBL(32)
- LBL(33) LBL(34) LBL(35) LBL(36)
+ LBL(33) LBL(34) LBL(35) LBL(36) LBL(37)
#ifdef SUPPORT_WIDE_CHARS
LBL(100) LBL(101)
@@ -6551,6 +6770,7 @@ if (use_jit)
match_data, mcontext);
if (rc != PCRE2_ERROR_JIT_BADOPTION)
{
+ match_data->subject_length = length;
if (rc >= 0 && (options & PCRE2_COPY_MATCHED_SUBJECT) != 0)
{
length = CU2BYTES(length + was_zero_terminated);
@@ -6719,7 +6939,7 @@ if (mcontext == NULL)
else mb->memctl = mcontext->memctl;
anchored = ((re->overall_options | options) & PCRE2_ANCHORED) != 0;
-firstline = (re->overall_options & PCRE2_FIRSTLINE) != 0;
+firstline = !anchored && (re->overall_options & PCRE2_FIRSTLINE) != 0;
startline = (re->flags & PCRE2_STARTLINE) != 0;
bumpalong_limit = (mcontext->offset_limit == PCRE2_UNSET)?
true_end_subject : subject + mcontext->offset_limit;
@@ -6742,6 +6962,7 @@ mb->callout_data = mcontext->callout_data;
mb->start_subject = subject;
mb->start_offset = start_offset;
mb->end_subject = end_subject;
+mb->true_end_subject = true_end_subject;
mb->hasthen = (re->flags & PCRE2_HASTHEN) != 0;
mb->allowemptypartial = (re->max_lookbehind > 0) ||
(re->flags & PCRE2_MATCH_EMPTY) != 0;
@@ -6801,7 +7022,7 @@ the pattern. It is not used at all if there are no capturing parentheses.
frame_size is the total size of each frame
match_data->heapframes is the pointer to the frames vector
- match_data->heapframes_size is the total size of the vector
+ match_data->heapframes_size is the allocated size of the vector
We must pad the frame_size for alignment to ensure subsequent frames are as
aligned as heapframe. Whilst ovector is word-aligned due to being a PCRE2_SIZE
@@ -6816,7 +7037,7 @@ frame_size = (offsetof(heapframe, ovector) +
smaller. */
mb->heap_limit = ((mcontext->heap_limit < re->limit_heap)?
- mcontext->heap_limit : re->limit_heap) * 1024;
+ mcontext->heap_limit : re->limit_heap);
mb->match_limit = (mcontext->match_limit < re->limit_match)?
mcontext->match_limit : re->limit_match;
@@ -6827,19 +7048,19 @@ mb->match_limit_depth = (mcontext->depth_limit < re->limit_depth)?
/* If a pattern has very many capturing parentheses, the frame size may be very
large. Set the initial frame vector size to ensure that there are at least 10
available frames, but enforce a minimum of START_FRAMES_SIZE. If this is
-greater than the heap limit, get as large a vector as possible. Always round
-the size to a multiple of the frame size. */
+greater than the heap limit, get as large a vector as possible. */
heapframes_size = frame_size * 10;
if (heapframes_size < START_FRAMES_SIZE) heapframes_size = START_FRAMES_SIZE;
-if (heapframes_size > mb->heap_limit)
+if (heapframes_size / 1024 > mb->heap_limit)
{
- if (frame_size > mb->heap_limit ) return PCRE2_ERROR_HEAPLIMIT;
- heapframes_size = mb->heap_limit;
+ PCRE2_SIZE max_size = 1024 * mb->heap_limit;
+ if (max_size < frame_size) return PCRE2_ERROR_HEAPLIMIT;
+ heapframes_size = max_size;
}
/* If an existing frame vector in the match_data block is large enough, we can
-use it.Otherwise, free any pre-existing vector and get a new one. */
+use it. Otherwise, free any pre-existing vector and get a new one. */
if (match_data->heapframes_size < heapframes_size)
{
@@ -7286,9 +7507,17 @@ for(;;)
mb->end_offset_top = 0;
mb->skip_arg_count = 0;
+#ifdef DEBUG_SHOW_OPS
+ fprintf(stderr, "++ Calling match()\n");
+#endif
+
rc = match(start_match, mb->start_code, re->top_bracket, frame_size,
match_data, mb);
+#ifdef DEBUG_SHOW_OPS
+ fprintf(stderr, "++ match() returned %d\n\n", rc);
+#endif
+
if (mb->hitend && start_partial == NULL)
{
start_partial = mb->start_used_ptr;
@@ -7436,6 +7665,7 @@ if (utf && end_subject != true_end_subject &&
if (start_match >= true_end_subject)
{
rc = MATCH_NOMATCH; /* In case it was partial */
+ match_partial = NULL;
break;
}
@@ -7485,6 +7715,7 @@ if (rc == MATCH_MATCH)
{
match_data->rc = ((int)mb->end_offset_top >= 2 * match_data->oveccount)?
0 : (int)mb->end_offset_top/2 + 1;
+ match_data->subject_length = length;
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)?
@@ -7499,6 +7730,7 @@ if (rc == MATCH_MATCH)
match_data->flags |= PCRE2_MD_COPIED_SUBJECT;
}
else match_data->subject = subject;
+
return match_data->rc;
}
@@ -7520,6 +7752,7 @@ PCRE2_ERROR_PARTIAL. */
else if (match_partial != NULL)
{
match_data->subject = subject;
+ match_data->subject_length = length;
match_data->ovector[0] = match_partial - subject;
match_data->ovector[1] = end_subject - subject;
match_data->startchar = match_partial - subject;
diff --git a/src/3rdparty/pcre2/src/pcre2_match_data.c b/src/3rdparty/pcre2/src/pcre2_match_data.c
index fa129b8bc5..757dab9df5 100644
--- a/src/3rdparty/pcre2/src/pcre2_match_data.c
+++ b/src/3rdparty/pcre2/src/pcre2_match_data.c
@@ -170,4 +170,16 @@ return offsetof(pcre2_match_data, ovector) +
2 * (match_data->oveccount) * sizeof(PCRE2_SIZE);
}
+
+
+/*************************************************
+* Get heapframes size *
+*************************************************/
+
+PCRE2_EXP_DEFN PCRE2_SIZE PCRE2_CALL_CONVENTION
+pcre2_get_match_data_heapframes_size(pcre2_match_data *match_data)
+{
+return match_data->heapframes_size;
+}
+
/* End of pcre2_match_data.c */
diff --git a/src/3rdparty/pcre2/src/pcre2_study.c b/src/3rdparty/pcre2/src/pcre2_study.c
index 4db3ad1184..792e696dad 100644
--- a/src/3rdparty/pcre2/src/pcre2_study.c
+++ b/src/3rdparty/pcre2/src/pcre2_study.c
@@ -7,7 +7,7 @@ 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-2021 University of Cambridge
+ New API code Copyright (c) 2016-2023 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -256,6 +256,7 @@ for (;;)
/* Skip over things that don't match chars */
case OP_REVERSE:
+ case OP_VREVERSE:
case OP_CREF:
case OP_DNCREF:
case OP_RREF:
@@ -273,6 +274,8 @@ for (;;)
case OP_DOLLM:
case OP_NOT_WORD_BOUNDARY:
case OP_WORD_BOUNDARY:
+ case OP_NOT_UCP_WORD_BOUNDARY:
+ case OP_UCP_WORD_BOUNDARY:
cc += PRIV(OP_lengths)[*cc];
break;
@@ -976,6 +979,7 @@ do
while (try_next) /* Loop for items in this branch */
{
int rc;
+ PCRE2_SPTR ncode;
uint8_t *classmap = NULL;
#ifdef SUPPORT_WIDE_CHARS
PCRE2_UCHAR xclassflags;
@@ -1054,6 +1058,7 @@ do
case OP_REF:
case OP_REFI:
case OP_REVERSE:
+ case OP_VREVERSE:
case OP_RREF:
case OP_SCOND:
case OP_SET_SOM:
@@ -1101,13 +1106,100 @@ do
case OP_WORD_BOUNDARY:
case OP_NOT_WORD_BOUNDARY:
+ case OP_UCP_WORD_BOUNDARY:
+ case OP_NOT_UCP_WORD_BOUNDARY:
tcode++;
break;
- /* If we hit a bracket or a positive lookahead assertion, recurse to set
- bits from within the subpattern. If it can't find anything, we have to
- give up. If it finds some mandatory character(s), we are done for this
- branch. Otherwise, carry on scanning after the subpattern. */
+ /* For a positive lookahead assertion, inspect what immediately follows,
+ ignoring intermediate assertions and callouts. If the next item is one
+ that sets a mandatory character, skip this assertion. Otherwise, treat it
+ the same as other bracket groups. */
+
+ case OP_ASSERT:
+ case OP_ASSERT_NA:
+ ncode = tcode + GET(tcode, 1);
+ while (*ncode == OP_ALT) ncode += GET(ncode, 1);
+ ncode += 1 + LINK_SIZE;
+
+ /* Skip irrelevant items */
+
+ for (BOOL done = FALSE; !done;)
+ {
+ switch (*ncode)
+ {
+ case OP_ASSERT:
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ case OP_ASSERT_NA:
+ case OP_ASSERTBACK_NA:
+ ncode += GET(ncode, 1);
+ while (*ncode == OP_ALT) ncode += GET(ncode, 1);
+ ncode += 1 + LINK_SIZE;
+ break;
+
+ case OP_WORD_BOUNDARY:
+ case OP_NOT_WORD_BOUNDARY:
+ case OP_UCP_WORD_BOUNDARY:
+ case OP_NOT_UCP_WORD_BOUNDARY:
+ ncode++;
+ break;
+
+ case OP_CALLOUT:
+ ncode += PRIV(OP_lengths)[OP_CALLOUT];
+ break;
+
+ case OP_CALLOUT_STR:
+ ncode += GET(ncode, 1 + 2*LINK_SIZE);
+ break;
+
+ default:
+ done = TRUE;
+ break;
+ }
+ }
+
+ /* Now check the next significant item. */
+
+ switch(*ncode)
+ {
+ default:
+ break;
+
+ case OP_PROP:
+ if (ncode[1] != PT_CLIST) break;
+ /* Fall through */
+ case OP_ANYNL:
+ case OP_CHAR:
+ case OP_CHARI:
+ case OP_EXACT:
+ case OP_EXACTI:
+ case OP_HSPACE:
+ case OP_MINPLUS:
+ case OP_MINPLUSI:
+ case OP_PLUS:
+ case OP_PLUSI:
+ case OP_POSPLUS:
+ case OP_POSPLUSI:
+ case OP_VSPACE:
+ /* Note that these types will only be present in non-UCP mode. */
+ case OP_DIGIT:
+ case OP_NOT_DIGIT:
+ case OP_WORDCHAR:
+ case OP_NOT_WORDCHAR:
+ case OP_WHITESPACE:
+ case OP_NOT_WHITESPACE:
+ tcode = ncode;
+ continue; /* With the following significant opcode */
+ }
+ /* Fall through */
+
+ /* For a group bracket or a positive assertion without an immediately
+ following mandatory setting, recurse to set bits from within the
+ subpattern. If it can't find anything, we have to give up. If it finds
+ some mandatory character(s), we are done for this branch. Otherwise,
+ carry on scanning after the subpattern. */
case OP_BRA:
case OP_SBRA:
@@ -1119,8 +1211,6 @@ do
case OP_SCBRAPOS:
case OP_ONCE:
case OP_SCRIPT_RUN:
- case OP_ASSERT:
- case OP_ASSERT_NA:
rc = set_start_bits(re, tcode, utf, ucp, depthptr);
if (rc == SSB_DONE)
{
diff --git a/src/3rdparty/pcre2/src/pcre2_substring.c b/src/3rdparty/pcre2/src/pcre2_substring.c
index ddf5774e15..14e919dce9 100644
--- a/src/3rdparty/pcre2/src/pcre2_substring.c
+++ b/src/3rdparty/pcre2/src/pcre2_substring.c
@@ -7,7 +7,7 @@ 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-2018 University of Cambridge
+ New API code Copyright (c) 2016-2023 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -309,6 +309,7 @@ Returns: if successful: 0
PCRE2_ERROR_NOSUBSTRING: no such substring
PCRE2_ERROR_UNAVAILABLE: ovector is too small
PCRE2_ERROR_UNSET: substring is not set
+ PCRE2_ERROR_INVALIDOFFSET: internal error, should not occur
*/
PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
@@ -341,6 +342,8 @@ else /* Matched using pcre2_dfa_match() */
left = match_data->ovector[stringnumber*2];
right = match_data->ovector[stringnumber*2+1];
+if (left > match_data->subject_length || right > match_data->subject_length)
+ return PCRE2_ERROR_INVALIDOFFSET;
if (sizeptr != NULL) *sizeptr = (left > right)? 0 : right - left;
return 0;
}
@@ -442,7 +445,7 @@ Returns: nothing
*/
PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
-pcre2_substring_list_free(PCRE2_SPTR *list)
+pcre2_substring_list_free(PCRE2_UCHAR **list)
{
if (list != NULL)
{
diff --git a/src/3rdparty/pcre2/src/pcre2_ucd.c b/src/3rdparty/pcre2/src/pcre2_ucd.c
index 5e0fc37c35..97dbc8b26f 100644
--- a/src/3rdparty/pcre2/src/pcre2_ucd.c
+++ b/src/3rdparty/pcre2/src/pcre2_ucd.c
@@ -68,15 +68,15 @@ the tables when not needed. But don't leave a totally empty module because some
compilers barf at that. Instead, just supply some small dummy tables. */
#ifndef SUPPORT_UNICODE
-const ucd_record PRIV(ucd_records)[] = {{0,0,0,0,0,0,0 }};
+const ucd_record PRIV(ucd_records)[] = {{0,0,0,0,0,0,0}};
const uint16_t PRIV(ucd_stage1)[] = {0};
const uint16_t PRIV(ucd_stage2)[] = {0};
const uint32_t PRIV(ucd_caseless_sets)[] = {0};
#else
-/* Total size: 111116 bytes, block size: 128. */
+/* Total size: 112564 bytes, block size: 128. */
-const char *PRIV(unicode_version) = "14.0.0";
+const char *PRIV(unicode_version) = "15.0.0";
/* When recompiling tables with a new Unicode version, please check the types
in this structure definition with those in pcre2_internal.h (the actual field
@@ -152,16 +152,16 @@ decimal digits. It is used to ensure that all the digits in a script run come
from the same set. */
const uint32_t PRIV(ucd_digit_sets)[] = {
- 66, /* Number of subsequent values */
+ 68, /* Number of subsequent values */
0x00039, 0x00669, 0x006f9, 0x007c9, 0x0096f, 0x009ef, 0x00a6f, 0x00aef,
0x00b6f, 0x00bef, 0x00c6f, 0x00cef, 0x00d6f, 0x00def, 0x00e59, 0x00ed9,
0x00f29, 0x01049, 0x01099, 0x017e9, 0x01819, 0x0194f, 0x019d9, 0x01a89,
0x01a99, 0x01b59, 0x01bb9, 0x01c49, 0x01c59, 0x0a629, 0x0a8d9, 0x0a909,
0x0a9d9, 0x0a9f9, 0x0aa59, 0x0abf9, 0x0ff19, 0x104a9, 0x10d39, 0x1106f,
0x110f9, 0x1113f, 0x111d9, 0x112f9, 0x11459, 0x114d9, 0x11659, 0x116c9,
- 0x11739, 0x118e9, 0x11959, 0x11c59, 0x11d59, 0x11da9, 0x16a69, 0x16ac9,
- 0x16b59, 0x1d7d7, 0x1d7e1, 0x1d7eb, 0x1d7f5, 0x1d7ff, 0x1e149, 0x1e2f9,
- 0x1e959, 0x1fbf9,
+ 0x11739, 0x118e9, 0x11959, 0x11c59, 0x11d59, 0x11da9, 0x11f59, 0x16a69,
+ 0x16ac9, 0x16b59, 0x1d7d7, 0x1d7e1, 0x1d7eb, 0x1d7f5, 0x1d7ff, 0x1e149,
+ 0x1e2f9, 0x1e4f9, 0x1e959, 0x1fbf9,
};
/* This vector is a list of script bitsets for the Script Extension property.
@@ -323,6 +323,7 @@ const uint32_t PRIV(ucd_boolprop_sets)[] = {
0x21004024u, 0x00040000u,
0x20808004u, 0x00040000u,
0x60800944u, 0x000c0004u,
+ 0x60800064u, 0x000c0004u,
0x60802004u, 0x000c0000u,
0x60800344u, 0x000c8000u,
0x22808000u, 0x00040000u,
@@ -334,7 +335,6 @@ const uint32_t PRIV(ucd_boolprop_sets)[] = {
0x01008020u, 0x00000000u,
0x21408024u, 0x00040000u,
0x00808000u, 0x00000000u,
- 0x60800064u, 0x000c0004u,
0x60800044u, 0x000c1004u,
0x60800064u, 0x000c1004u,
0x01002020u, 0x00000001u,
@@ -424,7 +424,7 @@ offset to multichar other cases or zero (8 bits), offset to other case or zero
(32 bits, signed), bidi class (5 bits) and script extension (11 bits) packed
into a 16-bit field, and offset in binary properties table (16 bits). */
-const ucd_record PRIV(ucd_records)[] = { /* 16908 bytes, record size 12 */
+const ucd_record PRIV(ucd_records)[] = { /* 17076 bytes, record size 12 */
{ 69, 0, 2, 0, 0, 6144, 2, }, /* 0 */
{ 69, 0, 2, 0, 0, 43008, 4, }, /* 1 */
{ 69, 0, 1, 0, 0, 4096, 4, }, /* 2 */
@@ -498,7 +498,7 @@ const ucd_record PRIV(ucd_records)[] = { /* 16908 bytes, record size 12 */
{ 0, 5, 12, 0, 0, 18432, 60, }, /* 70 */
{ 0, 5, 12, 0, 0, 18432, 80, }, /* 71 */
{ 0, 9, 12, 0, -121, 18432, 74, }, /* 72 */
- { 0, 5, 12, 1, -268, 18432, 70, }, /* 73 */
+ { 0, 5, 12, 1, 0, 18432, 70, }, /* 73 */
{ 0, 5, 12, 0, 195, 18432, 76, }, /* 74 */
{ 0, 9, 12, 0, 210, 18432, 74, }, /* 75 */
{ 0, 9, 12, 0, 206, 18432, 74, }, /* 76 */
@@ -819,57 +819,57 @@ const ucd_record PRIV(ucd_records)[] = { /* 16908 bytes, record size 12 */
{ 11, 23, 12, 0, 0, 14336, 68, }, /* 391 */
{ 12, 12, 3, 0, 0, 26624, 130, }, /* 392 */
{ 12, 10, 5, 0, 0, 18432, 144, }, /* 393 */
- { 12, 12, 3, 0, 0, 26624, 102, }, /* 394 */
- { 12, 7, 12, 0, 0, 18432, 82, }, /* 395 */
- { 12, 12, 3, 0, 0, 26624, 96, }, /* 396 */
- { 12, 12, 3, 0, 0, 26624, 146, }, /* 397 */
- { 12, 13, 12, 0, 0, 18432, 138, }, /* 398 */
- { 12, 21, 12, 0, 0, 18432, 68, }, /* 399 */
- { 12, 15, 12, 0, 0, 28672, 68, }, /* 400 */
- { 12, 26, 12, 0, 0, 18432, 68, }, /* 401 */
- { 13, 7, 12, 0, 0, 18432, 82, }, /* 402 */
- { 13, 12, 3, 0, 0, 26624, 130, }, /* 403 */
- { 13, 10, 5, 0, 0, 18432, 144, }, /* 404 */
- { 13, 21, 12, 0, 0, 18432, 68, }, /* 405 */
- { 13, 12, 3, 0, 0, 26624, 96, }, /* 406 */
- { 13, 12, 3, 0, 0, 18432, 130, }, /* 407 */
- { 13, 10, 3, 0, 0, 18432, 148, }, /* 408 */
- { 13, 12, 3, 0, 0, 26624, 146, }, /* 409 */
- { 13, 13, 12, 0, 0, 18528, 138, }, /* 410 */
- { 14, 12, 3, 0, 0, 26624, 130, }, /* 411 */
- { 14, 10, 5, 0, 0, 18432, 144, }, /* 412 */
- { 14, 7, 12, 0, 0, 18432, 82, }, /* 413 */
- { 14, 12, 3, 0, 0, 26624, 146, }, /* 414 */
- { 14, 10, 3, 0, 0, 18432, 148, }, /* 415 */
- { 14, 7, 4, 0, 0, 18432, 82, }, /* 416 */
- { 14, 26, 12, 0, 0, 18432, 68, }, /* 417 */
- { 14, 15, 12, 0, 0, 18432, 68, }, /* 418 */
- { 14, 13, 12, 0, 0, 18432, 138, }, /* 419 */
- { 15, 12, 3, 0, 0, 26624, 130, }, /* 420 */
- { 15, 10, 5, 0, 0, 18432, 144, }, /* 421 */
- { 15, 7, 12, 0, 0, 18432, 82, }, /* 422 */
- { 15, 12, 3, 0, 0, 26624, 146, }, /* 423 */
- { 15, 10, 3, 0, 0, 18432, 148, }, /* 424 */
- { 15, 13, 12, 0, 0, 18432, 138, }, /* 425 */
- { 15, 21, 12, 0, 0, 18432, 68, }, /* 426 */
- { 72, 7, 12, 0, 0, 18432, 82, }, /* 427 */
- { 72, 12, 3, 0, 0, 26624, 130, }, /* 428 */
- { 72, 7, 5, 0, 0, 18432, 152, }, /* 429 */
- { 72, 12, 3, 0, 0, 26624, 154, }, /* 430 */
- { 69, 23, 12, 0, 0, 14336, 68, }, /* 431 */
- { 72, 7, 12, 0, 0, 18432, 156, }, /* 432 */
- { 72, 6, 12, 0, 0, 18432, 136, }, /* 433 */
- { 72, 12, 3, 0, 0, 26624, 96, }, /* 434 */
- { 72, 21, 12, 0, 0, 18432, 68, }, /* 435 */
- { 72, 13, 12, 0, 0, 18432, 138, }, /* 436 */
- { 72, 21, 12, 0, 0, 18432, 106, }, /* 437 */
- { 73, 7, 12, 0, 0, 18432, 82, }, /* 438 */
- { 73, 12, 3, 0, 0, 26624, 130, }, /* 439 */
- { 73, 7, 5, 0, 0, 18432, 152, }, /* 440 */
- { 73, 12, 3, 0, 0, 26624, 146, }, /* 441 */
- { 73, 7, 12, 0, 0, 18432, 156, }, /* 442 */
- { 73, 6, 12, 0, 0, 18432, 136, }, /* 443 */
- { 73, 12, 3, 0, 0, 26624, 96, }, /* 444 */
+ { 12, 7, 12, 0, 0, 18432, 82, }, /* 394 */
+ { 12, 12, 3, 0, 0, 26624, 96, }, /* 395 */
+ { 12, 12, 3, 0, 0, 26624, 146, }, /* 396 */
+ { 12, 13, 12, 0, 0, 18432, 138, }, /* 397 */
+ { 12, 21, 12, 0, 0, 18432, 68, }, /* 398 */
+ { 12, 15, 12, 0, 0, 28672, 68, }, /* 399 */
+ { 12, 26, 12, 0, 0, 18432, 68, }, /* 400 */
+ { 13, 7, 12, 0, 0, 18432, 82, }, /* 401 */
+ { 13, 12, 3, 0, 0, 26624, 130, }, /* 402 */
+ { 13, 10, 5, 0, 0, 18432, 144, }, /* 403 */
+ { 13, 21, 12, 0, 0, 18432, 68, }, /* 404 */
+ { 13, 12, 3, 0, 0, 26624, 96, }, /* 405 */
+ { 13, 12, 3, 0, 0, 18432, 130, }, /* 406 */
+ { 13, 10, 3, 0, 0, 18432, 148, }, /* 407 */
+ { 13, 12, 3, 0, 0, 26624, 146, }, /* 408 */
+ { 13, 13, 12, 0, 0, 18528, 138, }, /* 409 */
+ { 14, 12, 3, 0, 0, 26624, 130, }, /* 410 */
+ { 14, 10, 5, 0, 0, 18432, 144, }, /* 411 */
+ { 14, 7, 12, 0, 0, 18432, 82, }, /* 412 */
+ { 14, 12, 3, 0, 0, 26624, 146, }, /* 413 */
+ { 14, 10, 3, 0, 0, 18432, 148, }, /* 414 */
+ { 14, 7, 4, 0, 0, 18432, 82, }, /* 415 */
+ { 14, 26, 12, 0, 0, 18432, 68, }, /* 416 */
+ { 14, 15, 12, 0, 0, 18432, 68, }, /* 417 */
+ { 14, 13, 12, 0, 0, 18432, 138, }, /* 418 */
+ { 15, 12, 3, 0, 0, 26624, 130, }, /* 419 */
+ { 15, 10, 5, 0, 0, 18432, 144, }, /* 420 */
+ { 15, 7, 12, 0, 0, 18432, 82, }, /* 421 */
+ { 15, 12, 3, 0, 0, 26624, 146, }, /* 422 */
+ { 15, 10, 3, 0, 0, 18432, 148, }, /* 423 */
+ { 15, 13, 12, 0, 0, 18432, 138, }, /* 424 */
+ { 15, 21, 12, 0, 0, 18432, 68, }, /* 425 */
+ { 72, 7, 12, 0, 0, 18432, 82, }, /* 426 */
+ { 72, 12, 3, 0, 0, 26624, 130, }, /* 427 */
+ { 72, 7, 5, 0, 0, 18432, 152, }, /* 428 */
+ { 72, 12, 3, 0, 0, 26624, 154, }, /* 429 */
+ { 69, 23, 12, 0, 0, 14336, 68, }, /* 430 */
+ { 72, 7, 12, 0, 0, 18432, 156, }, /* 431 */
+ { 72, 6, 12, 0, 0, 18432, 136, }, /* 432 */
+ { 72, 12, 3, 0, 0, 26624, 96, }, /* 433 */
+ { 72, 21, 12, 0, 0, 18432, 68, }, /* 434 */
+ { 72, 13, 12, 0, 0, 18432, 138, }, /* 435 */
+ { 72, 21, 12, 0, 0, 18432, 106, }, /* 436 */
+ { 73, 7, 12, 0, 0, 18432, 82, }, /* 437 */
+ { 73, 12, 3, 0, 0, 26624, 130, }, /* 438 */
+ { 73, 7, 5, 0, 0, 18432, 152, }, /* 439 */
+ { 73, 12, 3, 0, 0, 26624, 146, }, /* 440 */
+ { 73, 7, 12, 0, 0, 18432, 156, }, /* 441 */
+ { 73, 6, 12, 0, 0, 18432, 136, }, /* 442 */
+ { 73, 12, 3, 0, 0, 26624, 96, }, /* 443 */
+ { 73, 12, 3, 0, 0, 26624, 102, }, /* 444 */
{ 73, 13, 12, 0, 0, 18432, 138, }, /* 445 */
{ 74, 7, 12, 0, 0, 18432, 82, }, /* 446 */
{ 74, 26, 12, 0, 0, 18432, 68, }, /* 447 */
@@ -884,431 +884,431 @@ const ucd_record PRIV(ucd_records)[] = { /* 16908 bytes, record size 12 */
{ 74, 12, 3, 0, 0, 26624, 130, }, /* 456 */
{ 74, 12, 3, 0, 0, 26624, 162, }, /* 457 */
{ 74, 10, 5, 0, 0, 18432, 144, }, /* 458 */
- { 74, 12, 3, 0, 0, 26624, 146, }, /* 459 */
- { 69, 26, 12, 0, 0, 18432, 68, }, /* 460 */
- { 16, 7, 12, 0, 0, 18432, 82, }, /* 461 */
- { 16, 10, 12, 0, 0, 18432, 144, }, /* 462 */
- { 16, 12, 3, 0, 0, 26624, 130, }, /* 463 */
- { 16, 10, 5, 0, 0, 18432, 144, }, /* 464 */
- { 16, 12, 3, 0, 0, 26624, 96, }, /* 465 */
- { 16, 12, 3, 0, 0, 26624, 146, }, /* 466 */
- { 16, 13, 12, 0, 0, 18549, 138, }, /* 467 */
- { 16, 21, 12, 0, 0, 18432, 124, }, /* 468 */
- { 16, 21, 12, 0, 0, 18432, 68, }, /* 469 */
- { 16, 10, 12, 0, 0, 18432, 164, }, /* 470 */
- { 16, 12, 3, 0, 0, 26624, 128, }, /* 471 */
- { 16, 13, 12, 0, 0, 18432, 138, }, /* 472 */
- { 16, 26, 12, 0, 0, 18432, 68, }, /* 473 */
- { 17, 9, 12, 0, 7264, 18432, 74, }, /* 474 */
- { 17, 5, 12, 0, 3008, 18432, 166, }, /* 475 */
- { 69, 21, 12, 0, 0, 18510, 68, }, /* 476 */
- { 17, 6, 12, 0, 0, 18432, 142, }, /* 477 */
- { 18, 7, 6, 0, 0, 18432, 82, }, /* 478 */
- { 18, 7, 6, 0, 0, 18432, 168, }, /* 479 */
- { 18, 7, 7, 0, 0, 18432, 168, }, /* 480 */
- { 18, 7, 7, 0, 0, 18432, 82, }, /* 481 */
- { 18, 7, 8, 0, 0, 18432, 82, }, /* 482 */
- { 75, 7, 12, 0, 0, 18432, 82, }, /* 483 */
- { 75, 12, 3, 0, 0, 26624, 96, }, /* 484 */
- { 75, 21, 12, 0, 0, 18432, 68, }, /* 485 */
- { 75, 21, 12, 0, 0, 18432, 106, }, /* 486 */
- { 75, 21, 12, 0, 0, 18432, 124, }, /* 487 */
- { 75, 15, 12, 0, 0, 18432, 138, }, /* 488 */
- { 75, 15, 12, 0, 0, 18432, 68, }, /* 489 */
- { 75, 26, 12, 0, 0, 28672, 68, }, /* 490 */
- { 76, 9, 12, 0, 38864, 18432, 170, }, /* 491 */
- { 76, 9, 12, 0, 8, 18432, 170, }, /* 492 */
- { 76, 5, 12, 0, -8, 18432, 70, }, /* 493 */
- { 77, 17, 12, 0, 0, 28672, 126, }, /* 494 */
- { 77, 7, 12, 0, 0, 18432, 82, }, /* 495 */
- { 77, 26, 12, 0, 0, 18432, 68, }, /* 496 */
- { 77, 21, 12, 0, 0, 18432, 124, }, /* 497 */
- { 78, 29, 12, 0, 0, 45056, 52, }, /* 498 */
- { 78, 7, 12, 0, 0, 18432, 82, }, /* 499 */
- { 78, 22, 12, 0, 0, 28672, 158, }, /* 500 */
- { 78, 18, 12, 0, 0, 28672, 158, }, /* 501 */
- { 79, 7, 12, 0, 0, 18432, 82, }, /* 502 */
- { 69, 21, 12, 0, 0, 18432, 106, }, /* 503 */
- { 79, 14, 12, 0, 0, 18432, 82, }, /* 504 */
- { 25, 7, 12, 0, 0, 18432, 82, }, /* 505 */
- { 25, 12, 3, 0, 0, 26624, 130, }, /* 506 */
- { 25, 12, 3, 0, 0, 26624, 146, }, /* 507 */
- { 25, 10, 5, 0, 0, 18432, 172, }, /* 508 */
- { 26, 7, 12, 0, 0, 18432, 82, }, /* 509 */
- { 26, 12, 3, 0, 0, 26624, 130, }, /* 510 */
- { 26, 10, 5, 0, 0, 18432, 174, }, /* 511 */
- { 69, 21, 12, 0, 0, 18573, 124, }, /* 512 */
- { 27, 7, 12, 0, 0, 18432, 82, }, /* 513 */
- { 27, 12, 3, 0, 0, 26624, 130, }, /* 514 */
- { 28, 7, 12, 0, 0, 18432, 82, }, /* 515 */
- { 28, 12, 3, 0, 0, 26624, 130, }, /* 516 */
- { 80, 7, 12, 0, 0, 18432, 82, }, /* 517 */
- { 80, 7, 12, 0, 0, 18432, 140, }, /* 518 */
- { 80, 12, 3, 0, 0, 26624, 100, }, /* 519 */
- { 80, 10, 5, 0, 0, 18432, 144, }, /* 520 */
- { 80, 12, 3, 0, 0, 26624, 130, }, /* 521 */
- { 80, 12, 3, 0, 0, 26624, 96, }, /* 522 */
- { 80, 12, 3, 0, 0, 26624, 146, }, /* 523 */
- { 80, 21, 12, 0, 0, 18432, 106, }, /* 524 */
- { 80, 6, 12, 0, 0, 18432, 142, }, /* 525 */
- { 80, 21, 12, 0, 0, 18432, 68, }, /* 526 */
- { 80, 23, 12, 0, 0, 14336, 68, }, /* 527 */
- { 80, 13, 12, 0, 0, 18432, 138, }, /* 528 */
- { 80, 15, 12, 0, 0, 28672, 68, }, /* 529 */
- { 19, 21, 12, 0, 0, 28672, 68, }, /* 530 */
- { 69, 21, 12, 0, 0, 28777, 106, }, /* 531 */
- { 69, 21, 12, 0, 0, 28777, 124, }, /* 532 */
- { 19, 21, 12, 0, 0, 28672, 106, }, /* 533 */
- { 19, 17, 12, 0, 0, 28672, 126, }, /* 534 */
- { 19, 21, 12, 0, 0, 28672, 124, }, /* 535 */
- { 19, 21, 12, 0, 0, 28672, 176, }, /* 536 */
- { 19, 12, 3, 0, 0, 26624, 178, }, /* 537 */
- { 19, 1, 2, 0, 0, 6144, 66, }, /* 538 */
- { 19, 13, 12, 0, 0, 18432, 138, }, /* 539 */
- { 19, 7, 12, 0, 0, 18432, 82, }, /* 540 */
- { 19, 6, 12, 0, 0, 18432, 136, }, /* 541 */
- { 19, 12, 3, 0, 0, 26624, 180, }, /* 542 */
- { 19, 12, 3, 0, 0, 26624, 130, }, /* 543 */
- { 29, 7, 12, 0, 0, 18432, 82, }, /* 544 */
- { 29, 12, 3, 0, 0, 26624, 130, }, /* 545 */
- { 29, 10, 5, 0, 0, 18432, 144, }, /* 546 */
- { 29, 12, 3, 0, 0, 26624, 96, }, /* 547 */
- { 29, 26, 12, 0, 0, 28672, 68, }, /* 548 */
- { 29, 21, 12, 0, 0, 28672, 124, }, /* 549 */
- { 29, 13, 12, 0, 0, 18432, 138, }, /* 550 */
- { 30, 7, 12, 0, 0, 18432, 82, }, /* 551 */
- { 89, 7, 12, 0, 0, 18432, 82, }, /* 552 */
- { 89, 7, 12, 0, 0, 18432, 156, }, /* 553 */
- { 89, 13, 12, 0, 0, 18432, 138, }, /* 554 */
- { 89, 15, 12, 0, 0, 18432, 138, }, /* 555 */
- { 89, 26, 12, 0, 0, 28672, 68, }, /* 556 */
- { 80, 26, 12, 0, 0, 28672, 68, }, /* 557 */
- { 33, 7, 12, 0, 0, 18432, 82, }, /* 558 */
- { 33, 12, 3, 0, 0, 26624, 130, }, /* 559 */
- { 33, 10, 5, 0, 0, 18432, 144, }, /* 560 */
- { 33, 21, 12, 0, 0, 18432, 68, }, /* 561 */
- { 106, 7, 12, 0, 0, 18432, 82, }, /* 562 */
- { 106, 10, 5, 0, 0, 18432, 144, }, /* 563 */
- { 106, 12, 3, 0, 0, 26624, 130, }, /* 564 */
- { 106, 12, 3, 0, 0, 26624, 182, }, /* 565 */
- { 106, 10, 12, 0, 0, 18432, 144, }, /* 566 */
- { 106, 12, 3, 0, 0, 26624, 96, }, /* 567 */
- { 106, 13, 12, 0, 0, 18432, 138, }, /* 568 */
- { 106, 21, 12, 0, 0, 18432, 68, }, /* 569 */
- { 106, 6, 12, 0, 0, 18432, 136, }, /* 570 */
- { 106, 21, 12, 0, 0, 18432, 124, }, /* 571 */
- { 84, 11, 3, 0, 0, 26624, 184, }, /* 572 */
- { 84, 12, 3, 0, 0, 26624, 130, }, /* 573 */
- { 93, 12, 3, 0, 0, 26624, 130, }, /* 574 */
- { 93, 10, 5, 0, 0, 18432, 144, }, /* 575 */
- { 93, 7, 12, 0, 0, 18432, 82, }, /* 576 */
- { 93, 12, 3, 0, 0, 26624, 96, }, /* 577 */
- { 93, 10, 3, 0, 0, 18432, 148, }, /* 578 */
- { 93, 10, 5, 0, 0, 18432, 172, }, /* 579 */
- { 93, 13, 12, 0, 0, 18432, 138, }, /* 580 */
- { 93, 21, 12, 0, 0, 18432, 124, }, /* 581 */
- { 93, 21, 12, 0, 0, 18432, 68, }, /* 582 */
- { 93, 21, 12, 0, 0, 18432, 106, }, /* 583 */
- { 93, 26, 12, 0, 0, 18432, 68, }, /* 584 */
- { 96, 12, 3, 0, 0, 26624, 130, }, /* 585 */
- { 96, 10, 5, 0, 0, 18432, 144, }, /* 586 */
- { 96, 7, 12, 0, 0, 18432, 82, }, /* 587 */
- { 96, 10, 5, 0, 0, 18432, 172, }, /* 588 */
- { 96, 12, 3, 0, 0, 26624, 146, }, /* 589 */
- { 96, 13, 12, 0, 0, 18432, 138, }, /* 590 */
- { 119, 7, 12, 0, 0, 18432, 82, }, /* 591 */
- { 119, 12, 3, 0, 0, 26624, 102, }, /* 592 */
- { 119, 10, 5, 0, 0, 18432, 144, }, /* 593 */
- { 119, 12, 3, 0, 0, 26624, 130, }, /* 594 */
- { 119, 10, 5, 0, 0, 18432, 174, }, /* 595 */
- { 119, 21, 12, 0, 0, 18432, 68, }, /* 596 */
- { 97, 7, 12, 0, 0, 18432, 82, }, /* 597 */
- { 97, 10, 5, 0, 0, 18432, 144, }, /* 598 */
- { 97, 12, 3, 0, 0, 26624, 130, }, /* 599 */
- { 97, 12, 3, 0, 0, 26624, 186, }, /* 600 */
- { 97, 12, 3, 0, 0, 26624, 96, }, /* 601 */
- { 97, 21, 12, 0, 0, 18432, 124, }, /* 602 */
- { 97, 21, 12, 0, 0, 18432, 106, }, /* 603 */
- { 97, 13, 12, 0, 0, 18432, 138, }, /* 604 */
- { 98, 13, 12, 0, 0, 18432, 138, }, /* 605 */
- { 98, 7, 12, 0, 0, 18432, 82, }, /* 606 */
- { 98, 6, 12, 0, 0, 18432, 92, }, /* 607 */
- { 98, 6, 12, 0, 0, 18432, 94, }, /* 608 */
- { 98, 21, 12, 0, 0, 18432, 124, }, /* 609 */
- { 2, 5, 12, 63, -6222, 18432, 70, }, /* 610 */
- { 2, 5, 12, 67, -6221, 18432, 70, }, /* 611 */
- { 2, 5, 12, 71, -6212, 18432, 70, }, /* 612 */
- { 2, 5, 12, 75, -6210, 18432, 70, }, /* 613 */
- { 2, 5, 12, 79, -6210, 18432, 70, }, /* 614 */
- { 2, 5, 12, 79, -6211, 18432, 70, }, /* 615 */
- { 2, 5, 12, 84, -6204, 18432, 70, }, /* 616 */
- { 2, 5, 12, 88, -6180, 18432, 70, }, /* 617 */
- { 2, 5, 12, 108, 35267, 18432, 70, }, /* 618 */
- { 17, 9, 12, 0, -3008, 18432, 74, }, /* 619 */
- { 96, 21, 12, 0, 0, 18432, 68, }, /* 620 */
- { 84, 12, 3, 0, 0, 26762, 96, }, /* 621 */
- { 84, 12, 3, 0, 0, 26630, 96, }, /* 622 */
- { 69, 21, 12, 0, 0, 18498, 188, }, /* 623 */
- { 84, 12, 3, 0, 0, 26666, 96, }, /* 624 */
- { 84, 12, 3, 0, 0, 26696, 96, }, /* 625 */
- { 84, 12, 3, 0, 0, 26780, 96, }, /* 626 */
- { 69, 10, 5, 0, 0, 18474, 160, }, /* 627 */
- { 69, 7, 12, 0, 0, 18501, 82, }, /* 628 */
- { 69, 7, 12, 0, 0, 18474, 82, }, /* 629 */
- { 69, 7, 12, 0, 0, 18438, 82, }, /* 630 */
- { 69, 7, 12, 0, 0, 18594, 82, }, /* 631 */
- { 69, 7, 12, 0, 0, 18498, 82, }, /* 632 */
- { 84, 12, 3, 0, 0, 26750, 96, }, /* 633 */
- { 69, 10, 5, 0, 0, 18435, 160, }, /* 634 */
- { 84, 12, 3, 0, 0, 26690, 96, }, /* 635 */
- { 69, 7, 12, 0, 0, 18453, 82, }, /* 636 */
- { 2, 5, 12, 0, 0, 18432, 60, }, /* 637 */
- { 1, 6, 12, 0, 0, 18432, 88, }, /* 638 */
- { 2, 6, 12, 0, 0, 18432, 190, }, /* 639 */
- { 0, 5, 12, 0, 35332, 18432, 76, }, /* 640 */
- { 0, 5, 12, 0, 3814, 18432, 76, }, /* 641 */
- { 0, 5, 12, 0, 35384, 18432, 76, }, /* 642 */
- { 0, 5, 12, 0, 0, 18432, 192, }, /* 643 */
- { 0, 6, 12, 0, 0, 18432, 190, }, /* 644 */
- { 0, 6, 12, 0, 0, 18432, 194, }, /* 645 */
- { 1, 6, 12, 0, 0, 18432, 190, }, /* 646 */
- { 84, 12, 3, 0, 0, 26636, 102, }, /* 647 */
- { 84, 12, 3, 0, 0, 26687, 96, }, /* 648 */
- { 84, 12, 3, 0, 0, 26648, 96, }, /* 649 */
- { 0, 9, 12, 92, 1, 18432, 74, }, /* 650 */
- { 0, 5, 12, 92, -1, 18432, 76, }, /* 651 */
- { 0, 5, 12, 0, 0, 18432, 70, }, /* 652 */
- { 0, 5, 12, 92, -58, 18432, 70, }, /* 653 */
- { 0, 9, 12, 0, -7615, 18432, 74, }, /* 654 */
- { 1, 5, 12, 0, 8, 18432, 76, }, /* 655 */
- { 1, 9, 12, 0, -8, 18432, 74, }, /* 656 */
- { 1, 5, 12, 0, 74, 18432, 76, }, /* 657 */
- { 1, 5, 12, 0, 86, 18432, 76, }, /* 658 */
- { 1, 5, 12, 0, 100, 18432, 76, }, /* 659 */
- { 1, 5, 12, 0, 128, 18432, 76, }, /* 660 */
- { 1, 5, 12, 0, 112, 18432, 76, }, /* 661 */
- { 1, 5, 12, 0, 126, 18432, 76, }, /* 662 */
- { 1, 5, 12, 0, 8, 18432, 70, }, /* 663 */
- { 1, 8, 12, 0, -8, 18432, 86, }, /* 664 */
- { 1, 5, 12, 0, 0, 18432, 70, }, /* 665 */
- { 1, 5, 12, 0, 9, 18432, 70, }, /* 666 */
- { 1, 9, 12, 0, -74, 18432, 74, }, /* 667 */
- { 1, 8, 12, 0, -9, 18432, 86, }, /* 668 */
- { 1, 5, 12, 21, -7173, 18432, 76, }, /* 669 */
- { 1, 9, 12, 0, -86, 18432, 74, }, /* 670 */
- { 1, 9, 12, 0, -100, 18432, 74, }, /* 671 */
- { 1, 9, 12, 0, -112, 18432, 74, }, /* 672 */
- { 1, 9, 12, 0, -128, 18432, 74, }, /* 673 */
- { 1, 9, 12, 0, -126, 18432, 74, }, /* 674 */
- { 69, 29, 12, 0, 0, 45056, 52, }, /* 675 */
- { 84, 1, 3, 0, 0, 6144, 196, }, /* 676 */
- { 84, 1, 13, 0, 0, 6144, 198, }, /* 677 */
- { 69, 1, 2, 0, 0, 18432, 200, }, /* 678 */
- { 69, 1, 2, 0, 0, 34816, 200, }, /* 679 */
- { 69, 17, 12, 0, 0, 28672, 202, }, /* 680 */
- { 69, 21, 12, 0, 0, 28672, 64, }, /* 681 */
- { 69, 20, 12, 0, 0, 28672, 204, }, /* 682 */
- { 69, 19, 12, 0, 0, 28672, 204, }, /* 683 */
- { 69, 22, 12, 0, 0, 28672, 206, }, /* 684 */
- { 69, 20, 12, 0, 0, 28672, 206, }, /* 685 */
- { 69, 19, 12, 0, 0, 28672, 206, }, /* 686 */
- { 69, 21, 12, 0, 0, 28672, 208, }, /* 687 */
- { 69, 27, 2, 0, 0, 45056, 50, }, /* 688 */
- { 69, 28, 2, 0, 0, 4096, 50, }, /* 689 */
- { 69, 1, 2, 0, 0, 20480, 134, }, /* 690 */
- { 69, 1, 2, 0, 0, 36864, 134, }, /* 691 */
- { 69, 1, 2, 0, 0, 30720, 134, }, /* 692 */
- { 69, 1, 2, 0, 0, 24576, 134, }, /* 693 */
- { 69, 1, 2, 0, 0, 40960, 134, }, /* 694 */
- { 69, 29, 12, 0, 0, 8291, 52, }, /* 695 */
- { 69, 21, 12, 0, 0, 14336, 54, }, /* 696 */
- { 69, 21, 12, 0, 0, 14336, 64, }, /* 697 */
- { 69, 21, 14, 0, 0, 28672, 210, }, /* 698 */
- { 69, 21, 12, 0, 0, 28672, 212, }, /* 699 */
- { 69, 16, 12, 0, 0, 28672, 138, }, /* 700 */
- { 69, 16, 12, 0, 0, 28672, 214, }, /* 701 */
- { 69, 25, 12, 0, 0, 8192, 64, }, /* 702 */
- { 69, 22, 12, 0, 0, 28672, 216, }, /* 703 */
- { 69, 18, 12, 0, 0, 28672, 216, }, /* 704 */
- { 69, 21, 12, 0, 0, 28672, 202, }, /* 705 */
- { 69, 1, 2, 0, 0, 6144, 218, }, /* 706 */
- { 68, 2, 2, 0, 0, 6144, 220, }, /* 707 */
- { 69, 1, 2, 0, 0, 22528, 134, }, /* 708 */
- { 69, 1, 2, 0, 0, 38912, 134, }, /* 709 */
- { 69, 1, 2, 0, 0, 16384, 134, }, /* 710 */
- { 69, 1, 2, 0, 0, 32768, 134, }, /* 711 */
- { 69, 1, 2, 0, 0, 6144, 222, }, /* 712 */
- { 69, 25, 12, 0, 0, 12288, 118, }, /* 713 */
- { 69, 25, 12, 0, 0, 12288, 224, }, /* 714 */
- { 69, 25, 12, 0, 0, 28672, 118, }, /* 715 */
- { 69, 22, 12, 0, 0, 28672, 226, }, /* 716 */
- { 69, 18, 12, 0, 0, 28672, 226, }, /* 717 */
- { 68, 2, 12, 0, 0, 14336, 0, }, /* 718 */
- { 84, 12, 3, 0, 0, 26624, 228, }, /* 719 */
- { 84, 11, 3, 0, 0, 26624, 120, }, /* 720 */
- { 84, 11, 3, 0, 0, 26624, 230, }, /* 721 */
- { 84, 12, 3, 0, 0, 26753, 102, }, /* 722 */
- { 69, 26, 12, 0, 0, 28672, 68, }, /* 723 */
- { 69, 9, 12, 0, 0, 18432, 112, }, /* 724 */
- { 69, 5, 12, 0, 0, 18432, 232, }, /* 725 */
- { 69, 25, 12, 0, 0, 28672, 234, }, /* 726 */
- { 69, 26, 14, 0, 0, 28672, 236, }, /* 727 */
- { 1, 9, 12, 96, -7517, 18432, 74, }, /* 728 */
- { 69, 26, 12, 0, 0, 28672, 118, }, /* 729 */
- { 0, 9, 12, 100, -8383, 18432, 74, }, /* 730 */
- { 0, 9, 12, 104, -8262, 18432, 74, }, /* 731 */
- { 69, 26, 12, 0, 0, 14336, 238, }, /* 732 */
- { 0, 9, 12, 0, 28, 18432, 74, }, /* 733 */
- { 69, 7, 12, 0, 0, 18432, 240, }, /* 734 */
- { 69, 5, 14, 0, 0, 18432, 242, }, /* 735 */
- { 69, 5, 12, 0, 0, 18432, 244, }, /* 736 */
- { 0, 5, 12, 0, -28, 18432, 76, }, /* 737 */
- { 0, 14, 12, 0, 16, 18432, 74, }, /* 738 */
- { 0, 14, 12, 0, -16, 18432, 76, }, /* 739 */
- { 0, 14, 12, 0, 0, 18432, 82, }, /* 740 */
- { 69, 25, 14, 0, 0, 28672, 246, }, /* 741 */
- { 69, 26, 14, 0, 0, 28672, 246, }, /* 742 */
- { 69, 26, 12, 0, 0, 28672, 64, }, /* 743 */
- { 69, 25, 12, 0, 0, 28672, 248, }, /* 744 */
- { 69, 25, 12, 0, 0, 12288, 250, }, /* 745 */
- { 69, 22, 12, 0, 0, 28672, 248, }, /* 746 */
- { 69, 18, 12, 0, 0, 28672, 248, }, /* 747 */
- { 69, 26, 14, 0, 0, 28672, 252, }, /* 748 */
- { 69, 22, 12, 0, 0, 28672, 254, }, /* 749 */
- { 69, 18, 12, 0, 0, 28672, 254, }, /* 750 */
- { 69, 26, 12, 0, 0, 18432, 54, }, /* 751 */
- { 69, 26, 14, 0, 0, 28672, 256, }, /* 752 */
- { 68, 2, 12, 0, 0, 18432, 258, }, /* 753 */
- { 69, 26, 12, 0, 26, 18432, 260, }, /* 754 */
- { 69, 26, 14, 0, 26, 18432, 262, }, /* 755 */
- { 69, 26, 12, 0, -26, 18432, 264, }, /* 756 */
- { 69, 25, 14, 0, 0, 28672, 266, }, /* 757 */
- { 69, 26, 14, 0, 0, 28672, 268, }, /* 758 */
- { 69, 26, 14, 0, 0, 28672, 270, }, /* 759 */
- { 69, 25, 14, 0, 0, 28672, 268, }, /* 760 */
- { 69, 26, 14, 0, 0, 18432, 256, }, /* 761 */
- { 69, 26, 14, 0, 0, 28672, 272, }, /* 762 */
- { 88, 26, 12, 0, 0, 18432, 54, }, /* 763 */
- { 69, 26, 12, 0, 0, 28672, 216, }, /* 764 */
- { 35, 9, 12, 0, 48, 18432, 74, }, /* 765 */
- { 35, 5, 12, 0, -48, 18432, 76, }, /* 766 */
- { 0, 9, 12, 0, -10743, 18432, 74, }, /* 767 */
- { 0, 9, 12, 0, -3814, 18432, 74, }, /* 768 */
- { 0, 9, 12, 0, -10727, 18432, 74, }, /* 769 */
- { 0, 5, 12, 0, -10795, 18432, 76, }, /* 770 */
- { 0, 5, 12, 0, -10792, 18432, 76, }, /* 771 */
- { 0, 9, 12, 0, -10780, 18432, 74, }, /* 772 */
- { 0, 9, 12, 0, -10749, 18432, 74, }, /* 773 */
- { 0, 9, 12, 0, -10783, 18432, 74, }, /* 774 */
- { 0, 9, 12, 0, -10782, 18432, 74, }, /* 775 */
- { 0, 9, 12, 0, -10815, 18432, 74, }, /* 776 */
- { 34, 5, 12, 0, 0, 18432, 60, }, /* 777 */
- { 34, 26, 12, 0, 0, 28672, 68, }, /* 778 */
- { 34, 12, 3, 0, 0, 26624, 96, }, /* 779 */
- { 34, 21, 12, 0, 0, 28672, 68, }, /* 780 */
- { 34, 15, 12, 0, 0, 28672, 68, }, /* 781 */
- { 17, 5, 12, 0, -7264, 18432, 76, }, /* 782 */
- { 90, 7, 12, 0, 0, 18432, 82, }, /* 783 */
- { 90, 6, 12, 0, 0, 18432, 142, }, /* 784 */
- { 90, 21, 12, 0, 0, 18432, 68, }, /* 785 */
- { 90, 12, 3, 0, 0, 26624, 182, }, /* 786 */
- { 2, 12, 3, 0, 0, 26624, 130, }, /* 787 */
- { 69, 20, 12, 0, 0, 28672, 216, }, /* 788 */
- { 69, 19, 12, 0, 0, 28672, 216, }, /* 789 */
- { 69, 6, 12, 0, 0, 28672, 274, }, /* 790 */
- { 69, 21, 12, 0, 0, 28672, 276, }, /* 791 */
- { 69, 21, 12, 0, 0, 28726, 54, }, /* 792 */
- { 23, 26, 12, 0, 0, 28672, 278, }, /* 793 */
- { 69, 26, 12, 0, 0, 28672, 280, }, /* 794 */
- { 69, 26, 12, 0, 0, 28672, 282, }, /* 795 */
- { 69, 21, 12, 0, 0, 28825, 276, }, /* 796 */
- { 69, 21, 12, 0, 0, 28825, 212, }, /* 797 */
- { 69, 21, 12, 0, 0, 28819, 54, }, /* 798 */
- { 23, 6, 12, 0, 0, 18432, 136, }, /* 799 */
- { 69, 7, 12, 0, 0, 18447, 284, }, /* 800 */
- { 23, 14, 12, 0, 0, 18432, 284, }, /* 801 */
- { 69, 22, 12, 0, 0, 28825, 216, }, /* 802 */
- { 69, 18, 12, 0, 0, 28825, 216, }, /* 803 */
- { 69, 22, 12, 0, 0, 28825, 62, }, /* 804 */
- { 69, 18, 12, 0, 0, 28825, 62, }, /* 805 */
- { 69, 26, 12, 0, 0, 28819, 54, }, /* 806 */
- { 69, 17, 12, 0, 0, 28819, 202, }, /* 807 */
- { 69, 22, 12, 0, 0, 28819, 206, }, /* 808 */
- { 69, 18, 12, 0, 0, 28819, 206, }, /* 809 */
- { 84, 12, 3, 0, 0, 26669, 96, }, /* 810 */
- { 18, 10, 3, 0, 0, 18432, 286, }, /* 811 */
- { 69, 17, 14, 0, 0, 28819, 288, }, /* 812 */
- { 69, 6, 12, 0, 0, 18525, 136, }, /* 813 */
- { 69, 26, 12, 0, 0, 28819, 68, }, /* 814 */
- { 23, 6, 12, 0, 0, 18432, 142, }, /* 815 */
- { 69, 7, 12, 0, 0, 18564, 82, }, /* 816 */
- { 69, 21, 14, 0, 0, 28804, 236, }, /* 817 */
- { 69, 26, 12, 0, 0, 28687, 68, }, /* 818 */
- { 20, 7, 12, 0, 0, 18432, 82, }, /* 819 */
- { 84, 12, 3, 0, 0, 26717, 96, }, /* 820 */
- { 69, 24, 12, 0, 0, 28765, 290, }, /* 821 */
- { 20, 6, 12, 0, 0, 18432, 136, }, /* 822 */
- { 69, 17, 12, 0, 0, 28765, 126, }, /* 823 */
- { 21, 7, 12, 0, 0, 18432, 82, }, /* 824 */
- { 69, 21, 12, 0, 0, 28825, 68, }, /* 825 */
- { 69, 6, 12, 0, 0, 18525, 94, }, /* 826 */
- { 21, 6, 12, 0, 0, 18432, 136, }, /* 827 */
- { 22, 7, 12, 0, 0, 18432, 82, }, /* 828 */
- { 18, 7, 12, 0, 0, 18432, 82, }, /* 829 */
- { 18, 7, 12, 0, 0, 18432, 168, }, /* 830 */
- { 69, 26, 12, 0, 0, 18447, 68, }, /* 831 */
- { 69, 15, 12, 0, 0, 18447, 68, }, /* 832 */
- { 18, 26, 12, 0, 0, 18432, 68, }, /* 833 */
- { 18, 26, 12, 0, 0, 28672, 68, }, /* 834 */
- { 69, 15, 12, 0, 0, 18432, 68, }, /* 835 */
- { 69, 26, 14, 0, 0, 18447, 236, }, /* 836 */
- { 21, 26, 12, 0, 0, 18432, 68, }, /* 837 */
- { 23, 7, 12, 0, 0, 18432, 292, }, /* 838 */
- { 24, 7, 12, 0, 0, 18432, 82, }, /* 839 */
- { 24, 6, 12, 0, 0, 18432, 136, }, /* 840 */
- { 24, 26, 12, 0, 0, 28672, 68, }, /* 841 */
- { 111, 7, 12, 0, 0, 18432, 82, }, /* 842 */
- { 111, 6, 12, 0, 0, 18432, 142, }, /* 843 */
- { 111, 21, 12, 0, 0, 18432, 106, }, /* 844 */
- { 111, 21, 12, 0, 0, 18432, 124, }, /* 845 */
- { 99, 7, 12, 0, 0, 18432, 82, }, /* 846 */
- { 99, 6, 12, 0, 0, 18432, 136, }, /* 847 */
- { 99, 21, 12, 0, 0, 28672, 106, }, /* 848 */
- { 99, 21, 12, 0, 0, 28672, 124, }, /* 849 */
- { 99, 13, 12, 0, 0, 18432, 138, }, /* 850 */
- { 2, 9, 12, 108, 1, 18432, 74, }, /* 851 */
- { 2, 5, 12, 108, -35267, 18432, 76, }, /* 852 */
- { 2, 7, 12, 0, 0, 18432, 82, }, /* 853 */
- { 2, 21, 12, 0, 0, 28672, 68, }, /* 854 */
- { 2, 12, 3, 0, 0, 26624, 96, }, /* 855 */
- { 2, 6, 12, 0, 0, 28672, 92, }, /* 856 */
- { 2, 6, 12, 0, 0, 18432, 88, }, /* 857 */
- { 112, 7, 12, 0, 0, 18432, 82, }, /* 858 */
- { 112, 14, 12, 0, 0, 18432, 82, }, /* 859 */
- { 112, 12, 3, 0, 0, 26624, 96, }, /* 860 */
- { 112, 21, 12, 0, 0, 18432, 68, }, /* 861 */
- { 112, 21, 12, 0, 0, 18432, 124, }, /* 862 */
- { 112, 21, 12, 0, 0, 18432, 106, }, /* 863 */
- { 69, 24, 12, 0, 0, 28762, 56, }, /* 864 */
- { 0, 9, 12, 0, -35332, 18432, 74, }, /* 865 */
- { 69, 24, 12, 0, 0, 18432, 56, }, /* 866 */
- { 0, 9, 12, 0, -42280, 18432, 74, }, /* 867 */
- { 0, 5, 12, 0, 48, 18432, 76, }, /* 868 */
- { 0, 9, 12, 0, -42308, 18432, 74, }, /* 869 */
- { 0, 9, 12, 0, -42319, 18432, 74, }, /* 870 */
- { 0, 9, 12, 0, -42315, 18432, 74, }, /* 871 */
- { 0, 9, 12, 0, -42305, 18432, 74, }, /* 872 */
- { 0, 9, 12, 0, -42258, 18432, 74, }, /* 873 */
- { 0, 9, 12, 0, -42282, 18432, 74, }, /* 874 */
- { 0, 9, 12, 0, -42261, 18432, 74, }, /* 875 */
- { 0, 9, 12, 0, 928, 18432, 74, }, /* 876 */
- { 0, 9, 12, 0, -48, 18432, 74, }, /* 877 */
- { 0, 9, 12, 0, -42307, 18432, 74, }, /* 878 */
- { 0, 9, 12, 0, -35384, 18432, 74, }, /* 879 */
- { 0, 6, 12, 0, 0, 18432, 142, }, /* 880 */
+ { 74, 12, 3, 0, 0, 26624, 128, }, /* 459 */
+ { 74, 12, 3, 0, 0, 26624, 146, }, /* 460 */
+ { 69, 26, 12, 0, 0, 18432, 68, }, /* 461 */
+ { 16, 7, 12, 0, 0, 18432, 82, }, /* 462 */
+ { 16, 10, 12, 0, 0, 18432, 144, }, /* 463 */
+ { 16, 12, 3, 0, 0, 26624, 130, }, /* 464 */
+ { 16, 10, 5, 0, 0, 18432, 144, }, /* 465 */
+ { 16, 12, 3, 0, 0, 26624, 96, }, /* 466 */
+ { 16, 12, 3, 0, 0, 26624, 146, }, /* 467 */
+ { 16, 13, 12, 0, 0, 18549, 138, }, /* 468 */
+ { 16, 21, 12, 0, 0, 18432, 124, }, /* 469 */
+ { 16, 21, 12, 0, 0, 18432, 68, }, /* 470 */
+ { 16, 10, 12, 0, 0, 18432, 164, }, /* 471 */
+ { 16, 12, 3, 0, 0, 26624, 128, }, /* 472 */
+ { 16, 13, 12, 0, 0, 18432, 138, }, /* 473 */
+ { 16, 26, 12, 0, 0, 18432, 68, }, /* 474 */
+ { 17, 9, 12, 0, 7264, 18432, 74, }, /* 475 */
+ { 17, 5, 12, 0, 3008, 18432, 166, }, /* 476 */
+ { 69, 21, 12, 0, 0, 18510, 68, }, /* 477 */
+ { 17, 6, 12, 0, 0, 18432, 168, }, /* 478 */
+ { 18, 7, 6, 0, 0, 18432, 82, }, /* 479 */
+ { 18, 7, 6, 0, 0, 18432, 170, }, /* 480 */
+ { 18, 7, 7, 0, 0, 18432, 170, }, /* 481 */
+ { 18, 7, 7, 0, 0, 18432, 82, }, /* 482 */
+ { 18, 7, 8, 0, 0, 18432, 82, }, /* 483 */
+ { 75, 7, 12, 0, 0, 18432, 82, }, /* 484 */
+ { 75, 12, 3, 0, 0, 26624, 96, }, /* 485 */
+ { 75, 21, 12, 0, 0, 18432, 68, }, /* 486 */
+ { 75, 21, 12, 0, 0, 18432, 106, }, /* 487 */
+ { 75, 21, 12, 0, 0, 18432, 124, }, /* 488 */
+ { 75, 15, 12, 0, 0, 18432, 138, }, /* 489 */
+ { 75, 15, 12, 0, 0, 18432, 68, }, /* 490 */
+ { 75, 26, 12, 0, 0, 28672, 68, }, /* 491 */
+ { 76, 9, 12, 0, 38864, 18432, 172, }, /* 492 */
+ { 76, 9, 12, 0, 8, 18432, 172, }, /* 493 */
+ { 76, 5, 12, 0, -8, 18432, 70, }, /* 494 */
+ { 77, 17, 12, 0, 0, 28672, 126, }, /* 495 */
+ { 77, 7, 12, 0, 0, 18432, 82, }, /* 496 */
+ { 77, 26, 12, 0, 0, 18432, 68, }, /* 497 */
+ { 77, 21, 12, 0, 0, 18432, 124, }, /* 498 */
+ { 78, 29, 12, 0, 0, 45056, 52, }, /* 499 */
+ { 78, 7, 12, 0, 0, 18432, 82, }, /* 500 */
+ { 78, 22, 12, 0, 0, 28672, 158, }, /* 501 */
+ { 78, 18, 12, 0, 0, 28672, 158, }, /* 502 */
+ { 79, 7, 12, 0, 0, 18432, 82, }, /* 503 */
+ { 69, 21, 12, 0, 0, 18432, 106, }, /* 504 */
+ { 79, 14, 12, 0, 0, 18432, 82, }, /* 505 */
+ { 25, 7, 12, 0, 0, 18432, 82, }, /* 506 */
+ { 25, 12, 3, 0, 0, 26624, 130, }, /* 507 */
+ { 25, 12, 3, 0, 0, 26624, 146, }, /* 508 */
+ { 25, 10, 5, 0, 0, 18432, 174, }, /* 509 */
+ { 26, 7, 12, 0, 0, 18432, 82, }, /* 510 */
+ { 26, 12, 3, 0, 0, 26624, 130, }, /* 511 */
+ { 26, 10, 5, 0, 0, 18432, 176, }, /* 512 */
+ { 69, 21, 12, 0, 0, 18573, 124, }, /* 513 */
+ { 27, 7, 12, 0, 0, 18432, 82, }, /* 514 */
+ { 27, 12, 3, 0, 0, 26624, 130, }, /* 515 */
+ { 28, 7, 12, 0, 0, 18432, 82, }, /* 516 */
+ { 28, 12, 3, 0, 0, 26624, 130, }, /* 517 */
+ { 80, 7, 12, 0, 0, 18432, 82, }, /* 518 */
+ { 80, 7, 12, 0, 0, 18432, 140, }, /* 519 */
+ { 80, 12, 3, 0, 0, 26624, 100, }, /* 520 */
+ { 80, 10, 5, 0, 0, 18432, 144, }, /* 521 */
+ { 80, 12, 3, 0, 0, 26624, 130, }, /* 522 */
+ { 80, 12, 3, 0, 0, 26624, 96, }, /* 523 */
+ { 80, 12, 3, 0, 0, 26624, 146, }, /* 524 */
+ { 80, 21, 12, 0, 0, 18432, 106, }, /* 525 */
+ { 80, 6, 12, 0, 0, 18432, 142, }, /* 526 */
+ { 80, 21, 12, 0, 0, 18432, 68, }, /* 527 */
+ { 80, 23, 12, 0, 0, 14336, 68, }, /* 528 */
+ { 80, 13, 12, 0, 0, 18432, 138, }, /* 529 */
+ { 80, 15, 12, 0, 0, 28672, 68, }, /* 530 */
+ { 19, 21, 12, 0, 0, 28672, 68, }, /* 531 */
+ { 69, 21, 12, 0, 0, 28777, 106, }, /* 532 */
+ { 69, 21, 12, 0, 0, 28777, 124, }, /* 533 */
+ { 19, 21, 12, 0, 0, 28672, 106, }, /* 534 */
+ { 19, 17, 12, 0, 0, 28672, 126, }, /* 535 */
+ { 19, 21, 12, 0, 0, 28672, 124, }, /* 536 */
+ { 19, 21, 12, 0, 0, 28672, 178, }, /* 537 */
+ { 19, 12, 3, 0, 0, 26624, 180, }, /* 538 */
+ { 19, 1, 2, 0, 0, 6144, 66, }, /* 539 */
+ { 19, 13, 12, 0, 0, 18432, 138, }, /* 540 */
+ { 19, 7, 12, 0, 0, 18432, 82, }, /* 541 */
+ { 19, 6, 12, 0, 0, 18432, 136, }, /* 542 */
+ { 19, 12, 3, 0, 0, 26624, 182, }, /* 543 */
+ { 19, 12, 3, 0, 0, 26624, 130, }, /* 544 */
+ { 29, 7, 12, 0, 0, 18432, 82, }, /* 545 */
+ { 29, 12, 3, 0, 0, 26624, 130, }, /* 546 */
+ { 29, 10, 5, 0, 0, 18432, 144, }, /* 547 */
+ { 29, 12, 3, 0, 0, 26624, 96, }, /* 548 */
+ { 29, 26, 12, 0, 0, 28672, 68, }, /* 549 */
+ { 29, 21, 12, 0, 0, 28672, 124, }, /* 550 */
+ { 29, 13, 12, 0, 0, 18432, 138, }, /* 551 */
+ { 30, 7, 12, 0, 0, 18432, 82, }, /* 552 */
+ { 89, 7, 12, 0, 0, 18432, 82, }, /* 553 */
+ { 89, 7, 12, 0, 0, 18432, 156, }, /* 554 */
+ { 89, 13, 12, 0, 0, 18432, 138, }, /* 555 */
+ { 89, 15, 12, 0, 0, 18432, 138, }, /* 556 */
+ { 89, 26, 12, 0, 0, 28672, 68, }, /* 557 */
+ { 80, 26, 12, 0, 0, 28672, 68, }, /* 558 */
+ { 33, 7, 12, 0, 0, 18432, 82, }, /* 559 */
+ { 33, 12, 3, 0, 0, 26624, 130, }, /* 560 */
+ { 33, 10, 5, 0, 0, 18432, 144, }, /* 561 */
+ { 33, 21, 12, 0, 0, 18432, 68, }, /* 562 */
+ { 106, 7, 12, 0, 0, 18432, 82, }, /* 563 */
+ { 106, 10, 5, 0, 0, 18432, 144, }, /* 564 */
+ { 106, 12, 3, 0, 0, 26624, 130, }, /* 565 */
+ { 106, 12, 3, 0, 0, 26624, 184, }, /* 566 */
+ { 106, 10, 12, 0, 0, 18432, 144, }, /* 567 */
+ { 106, 12, 3, 0, 0, 26624, 96, }, /* 568 */
+ { 106, 13, 12, 0, 0, 18432, 138, }, /* 569 */
+ { 106, 21, 12, 0, 0, 18432, 68, }, /* 570 */
+ { 106, 6, 12, 0, 0, 18432, 136, }, /* 571 */
+ { 106, 21, 12, 0, 0, 18432, 124, }, /* 572 */
+ { 84, 11, 3, 0, 0, 26624, 186, }, /* 573 */
+ { 84, 12, 3, 0, 0, 26624, 130, }, /* 574 */
+ { 93, 12, 3, 0, 0, 26624, 130, }, /* 575 */
+ { 93, 10, 5, 0, 0, 18432, 144, }, /* 576 */
+ { 93, 7, 12, 0, 0, 18432, 82, }, /* 577 */
+ { 93, 12, 3, 0, 0, 26624, 96, }, /* 578 */
+ { 93, 10, 3, 0, 0, 18432, 148, }, /* 579 */
+ { 93, 10, 5, 0, 0, 18432, 174, }, /* 580 */
+ { 93, 13, 12, 0, 0, 18432, 138, }, /* 581 */
+ { 93, 21, 12, 0, 0, 18432, 124, }, /* 582 */
+ { 93, 21, 12, 0, 0, 18432, 68, }, /* 583 */
+ { 93, 21, 12, 0, 0, 18432, 106, }, /* 584 */
+ { 93, 26, 12, 0, 0, 18432, 68, }, /* 585 */
+ { 96, 12, 3, 0, 0, 26624, 130, }, /* 586 */
+ { 96, 10, 5, 0, 0, 18432, 144, }, /* 587 */
+ { 96, 7, 12, 0, 0, 18432, 82, }, /* 588 */
+ { 96, 10, 5, 0, 0, 18432, 174, }, /* 589 */
+ { 96, 12, 3, 0, 0, 26624, 146, }, /* 590 */
+ { 96, 13, 12, 0, 0, 18432, 138, }, /* 591 */
+ { 119, 7, 12, 0, 0, 18432, 82, }, /* 592 */
+ { 119, 12, 3, 0, 0, 26624, 102, }, /* 593 */
+ { 119, 10, 5, 0, 0, 18432, 144, }, /* 594 */
+ { 119, 12, 3, 0, 0, 26624, 130, }, /* 595 */
+ { 119, 10, 5, 0, 0, 18432, 176, }, /* 596 */
+ { 119, 21, 12, 0, 0, 18432, 68, }, /* 597 */
+ { 97, 7, 12, 0, 0, 18432, 82, }, /* 598 */
+ { 97, 10, 5, 0, 0, 18432, 144, }, /* 599 */
+ { 97, 12, 3, 0, 0, 26624, 130, }, /* 600 */
+ { 97, 12, 3, 0, 0, 26624, 188, }, /* 601 */
+ { 97, 12, 3, 0, 0, 26624, 96, }, /* 602 */
+ { 97, 21, 12, 0, 0, 18432, 124, }, /* 603 */
+ { 97, 21, 12, 0, 0, 18432, 106, }, /* 604 */
+ { 97, 13, 12, 0, 0, 18432, 138, }, /* 605 */
+ { 98, 13, 12, 0, 0, 18432, 138, }, /* 606 */
+ { 98, 7, 12, 0, 0, 18432, 82, }, /* 607 */
+ { 98, 6, 12, 0, 0, 18432, 92, }, /* 608 */
+ { 98, 6, 12, 0, 0, 18432, 94, }, /* 609 */
+ { 98, 21, 12, 0, 0, 18432, 124, }, /* 610 */
+ { 2, 5, 12, 63, -6222, 18432, 70, }, /* 611 */
+ { 2, 5, 12, 67, -6221, 18432, 70, }, /* 612 */
+ { 2, 5, 12, 71, -6212, 18432, 70, }, /* 613 */
+ { 2, 5, 12, 75, -6210, 18432, 70, }, /* 614 */
+ { 2, 5, 12, 79, -6210, 18432, 70, }, /* 615 */
+ { 2, 5, 12, 79, -6211, 18432, 70, }, /* 616 */
+ { 2, 5, 12, 84, -6204, 18432, 70, }, /* 617 */
+ { 2, 5, 12, 88, -6180, 18432, 70, }, /* 618 */
+ { 2, 5, 12, 108, 35267, 18432, 70, }, /* 619 */
+ { 17, 9, 12, 0, -3008, 18432, 74, }, /* 620 */
+ { 96, 21, 12, 0, 0, 18432, 68, }, /* 621 */
+ { 84, 12, 3, 0, 0, 26762, 96, }, /* 622 */
+ { 84, 12, 3, 0, 0, 26630, 96, }, /* 623 */
+ { 69, 21, 12, 0, 0, 18498, 190, }, /* 624 */
+ { 84, 12, 3, 0, 0, 26666, 96, }, /* 625 */
+ { 84, 12, 3, 0, 0, 26696, 96, }, /* 626 */
+ { 84, 12, 3, 0, 0, 26780, 96, }, /* 627 */
+ { 69, 10, 5, 0, 0, 18474, 160, }, /* 628 */
+ { 69, 7, 12, 0, 0, 18501, 82, }, /* 629 */
+ { 69, 7, 12, 0, 0, 18474, 82, }, /* 630 */
+ { 69, 7, 12, 0, 0, 18438, 82, }, /* 631 */
+ { 69, 7, 12, 0, 0, 18594, 82, }, /* 632 */
+ { 69, 7, 12, 0, 0, 18498, 82, }, /* 633 */
+ { 84, 12, 3, 0, 0, 26750, 96, }, /* 634 */
+ { 69, 10, 5, 0, 0, 18435, 160, }, /* 635 */
+ { 84, 12, 3, 0, 0, 26690, 96, }, /* 636 */
+ { 69, 7, 12, 0, 0, 18453, 82, }, /* 637 */
+ { 2, 5, 12, 0, 0, 18432, 60, }, /* 638 */
+ { 1, 6, 12, 0, 0, 18432, 88, }, /* 639 */
+ { 2, 6, 12, 0, 0, 18432, 168, }, /* 640 */
+ { 0, 5, 12, 0, 35332, 18432, 76, }, /* 641 */
+ { 0, 5, 12, 0, 3814, 18432, 76, }, /* 642 */
+ { 0, 5, 12, 0, 35384, 18432, 76, }, /* 643 */
+ { 0, 5, 12, 0, 0, 18432, 192, }, /* 644 */
+ { 0, 6, 12, 0, 0, 18432, 168, }, /* 645 */
+ { 0, 6, 12, 0, 0, 18432, 194, }, /* 646 */
+ { 1, 6, 12, 0, 0, 18432, 168, }, /* 647 */
+ { 84, 12, 3, 0, 0, 26636, 102, }, /* 648 */
+ { 84, 12, 3, 0, 0, 26687, 96, }, /* 649 */
+ { 84, 12, 3, 0, 0, 26648, 96, }, /* 650 */
+ { 0, 9, 12, 92, 1, 18432, 74, }, /* 651 */
+ { 0, 5, 12, 92, -1, 18432, 76, }, /* 652 */
+ { 0, 5, 12, 0, 0, 18432, 70, }, /* 653 */
+ { 0, 5, 12, 92, -58, 18432, 70, }, /* 654 */
+ { 0, 9, 12, 0, -7615, 18432, 74, }, /* 655 */
+ { 1, 5, 12, 0, 8, 18432, 76, }, /* 656 */
+ { 1, 9, 12, 0, -8, 18432, 74, }, /* 657 */
+ { 1, 5, 12, 0, 74, 18432, 76, }, /* 658 */
+ { 1, 5, 12, 0, 86, 18432, 76, }, /* 659 */
+ { 1, 5, 12, 0, 100, 18432, 76, }, /* 660 */
+ { 1, 5, 12, 0, 128, 18432, 76, }, /* 661 */
+ { 1, 5, 12, 0, 112, 18432, 76, }, /* 662 */
+ { 1, 5, 12, 0, 126, 18432, 76, }, /* 663 */
+ { 1, 5, 12, 0, 8, 18432, 70, }, /* 664 */
+ { 1, 8, 12, 0, -8, 18432, 86, }, /* 665 */
+ { 1, 5, 12, 0, 0, 18432, 70, }, /* 666 */
+ { 1, 5, 12, 0, 9, 18432, 70, }, /* 667 */
+ { 1, 9, 12, 0, -74, 18432, 74, }, /* 668 */
+ { 1, 8, 12, 0, -9, 18432, 86, }, /* 669 */
+ { 1, 5, 12, 21, -7173, 18432, 76, }, /* 670 */
+ { 1, 9, 12, 0, -86, 18432, 74, }, /* 671 */
+ { 1, 9, 12, 0, -100, 18432, 74, }, /* 672 */
+ { 1, 9, 12, 0, -112, 18432, 74, }, /* 673 */
+ { 1, 9, 12, 0, -128, 18432, 74, }, /* 674 */
+ { 1, 9, 12, 0, -126, 18432, 74, }, /* 675 */
+ { 69, 29, 12, 0, 0, 45056, 52, }, /* 676 */
+ { 84, 1, 3, 0, 0, 6144, 196, }, /* 677 */
+ { 84, 1, 13, 0, 0, 6144, 198, }, /* 678 */
+ { 69, 1, 2, 0, 0, 18432, 200, }, /* 679 */
+ { 69, 1, 2, 0, 0, 34816, 200, }, /* 680 */
+ { 69, 17, 12, 0, 0, 28672, 202, }, /* 681 */
+ { 69, 21, 12, 0, 0, 28672, 64, }, /* 682 */
+ { 69, 20, 12, 0, 0, 28672, 204, }, /* 683 */
+ { 69, 19, 12, 0, 0, 28672, 204, }, /* 684 */
+ { 69, 22, 12, 0, 0, 28672, 206, }, /* 685 */
+ { 69, 20, 12, 0, 0, 28672, 206, }, /* 686 */
+ { 69, 19, 12, 0, 0, 28672, 206, }, /* 687 */
+ { 69, 21, 12, 0, 0, 28672, 208, }, /* 688 */
+ { 69, 27, 2, 0, 0, 45056, 50, }, /* 689 */
+ { 69, 28, 2, 0, 0, 4096, 50, }, /* 690 */
+ { 69, 1, 2, 0, 0, 20480, 134, }, /* 691 */
+ { 69, 1, 2, 0, 0, 36864, 134, }, /* 692 */
+ { 69, 1, 2, 0, 0, 30720, 134, }, /* 693 */
+ { 69, 1, 2, 0, 0, 24576, 134, }, /* 694 */
+ { 69, 1, 2, 0, 0, 40960, 134, }, /* 695 */
+ { 69, 29, 12, 0, 0, 8291, 52, }, /* 696 */
+ { 69, 21, 12, 0, 0, 14336, 54, }, /* 697 */
+ { 69, 21, 12, 0, 0, 14336, 64, }, /* 698 */
+ { 69, 21, 14, 0, 0, 28672, 210, }, /* 699 */
+ { 69, 21, 12, 0, 0, 28672, 212, }, /* 700 */
+ { 69, 16, 12, 0, 0, 28672, 138, }, /* 701 */
+ { 69, 16, 12, 0, 0, 28672, 214, }, /* 702 */
+ { 69, 25, 12, 0, 0, 8192, 64, }, /* 703 */
+ { 69, 22, 12, 0, 0, 28672, 216, }, /* 704 */
+ { 69, 18, 12, 0, 0, 28672, 216, }, /* 705 */
+ { 69, 21, 12, 0, 0, 28672, 202, }, /* 706 */
+ { 69, 1, 2, 0, 0, 6144, 218, }, /* 707 */
+ { 68, 2, 2, 0, 0, 6144, 220, }, /* 708 */
+ { 69, 1, 2, 0, 0, 22528, 134, }, /* 709 */
+ { 69, 1, 2, 0, 0, 38912, 134, }, /* 710 */
+ { 69, 1, 2, 0, 0, 16384, 134, }, /* 711 */
+ { 69, 1, 2, 0, 0, 32768, 134, }, /* 712 */
+ { 69, 1, 2, 0, 0, 6144, 222, }, /* 713 */
+ { 69, 25, 12, 0, 0, 12288, 118, }, /* 714 */
+ { 69, 25, 12, 0, 0, 12288, 224, }, /* 715 */
+ { 69, 25, 12, 0, 0, 28672, 118, }, /* 716 */
+ { 69, 22, 12, 0, 0, 28672, 226, }, /* 717 */
+ { 69, 18, 12, 0, 0, 28672, 226, }, /* 718 */
+ { 68, 2, 12, 0, 0, 14336, 0, }, /* 719 */
+ { 84, 12, 3, 0, 0, 26624, 228, }, /* 720 */
+ { 84, 11, 3, 0, 0, 26624, 120, }, /* 721 */
+ { 84, 11, 3, 0, 0, 26624, 230, }, /* 722 */
+ { 84, 12, 3, 0, 0, 26753, 102, }, /* 723 */
+ { 69, 26, 12, 0, 0, 28672, 68, }, /* 724 */
+ { 69, 9, 12, 0, 0, 18432, 112, }, /* 725 */
+ { 69, 5, 12, 0, 0, 18432, 232, }, /* 726 */
+ { 69, 25, 12, 0, 0, 28672, 234, }, /* 727 */
+ { 69, 26, 14, 0, 0, 28672, 236, }, /* 728 */
+ { 1, 9, 12, 96, -7517, 18432, 74, }, /* 729 */
+ { 69, 26, 12, 0, 0, 28672, 118, }, /* 730 */
+ { 0, 9, 12, 100, 0, 18432, 74, }, /* 731 */
+ { 0, 9, 12, 104, -8262, 18432, 74, }, /* 732 */
+ { 69, 26, 12, 0, 0, 14336, 238, }, /* 733 */
+ { 0, 9, 12, 0, 28, 18432, 74, }, /* 734 */
+ { 69, 7, 12, 0, 0, 18432, 240, }, /* 735 */
+ { 69, 5, 14, 0, 0, 18432, 242, }, /* 736 */
+ { 69, 5, 12, 0, 0, 18432, 244, }, /* 737 */
+ { 0, 5, 12, 0, -28, 18432, 76, }, /* 738 */
+ { 0, 14, 12, 0, 16, 18432, 74, }, /* 739 */
+ { 0, 14, 12, 0, -16, 18432, 76, }, /* 740 */
+ { 0, 14, 12, 0, 0, 18432, 82, }, /* 741 */
+ { 69, 25, 14, 0, 0, 28672, 246, }, /* 742 */
+ { 69, 26, 14, 0, 0, 28672, 246, }, /* 743 */
+ { 69, 26, 12, 0, 0, 28672, 64, }, /* 744 */
+ { 69, 25, 12, 0, 0, 28672, 248, }, /* 745 */
+ { 69, 25, 12, 0, 0, 12288, 250, }, /* 746 */
+ { 69, 22, 12, 0, 0, 28672, 248, }, /* 747 */
+ { 69, 18, 12, 0, 0, 28672, 248, }, /* 748 */
+ { 69, 26, 14, 0, 0, 28672, 252, }, /* 749 */
+ { 69, 22, 12, 0, 0, 28672, 254, }, /* 750 */
+ { 69, 18, 12, 0, 0, 28672, 254, }, /* 751 */
+ { 69, 26, 12, 0, 0, 18432, 54, }, /* 752 */
+ { 69, 26, 14, 0, 0, 28672, 256, }, /* 753 */
+ { 68, 2, 12, 0, 0, 18432, 258, }, /* 754 */
+ { 69, 26, 12, 0, 26, 18432, 260, }, /* 755 */
+ { 69, 26, 14, 0, 26, 18432, 262, }, /* 756 */
+ { 69, 26, 12, 0, -26, 18432, 264, }, /* 757 */
+ { 69, 25, 14, 0, 0, 28672, 266, }, /* 758 */
+ { 69, 26, 14, 0, 0, 28672, 268, }, /* 759 */
+ { 69, 26, 14, 0, 0, 28672, 270, }, /* 760 */
+ { 69, 25, 14, 0, 0, 28672, 268, }, /* 761 */
+ { 69, 26, 14, 0, 0, 18432, 256, }, /* 762 */
+ { 69, 26, 14, 0, 0, 28672, 272, }, /* 763 */
+ { 88, 26, 12, 0, 0, 18432, 54, }, /* 764 */
+ { 69, 26, 12, 0, 0, 28672, 216, }, /* 765 */
+ { 35, 9, 12, 0, 48, 18432, 74, }, /* 766 */
+ { 35, 5, 12, 0, -48, 18432, 76, }, /* 767 */
+ { 0, 9, 12, 0, -10743, 18432, 74, }, /* 768 */
+ { 0, 9, 12, 0, -3814, 18432, 74, }, /* 769 */
+ { 0, 9, 12, 0, -10727, 18432, 74, }, /* 770 */
+ { 0, 5, 12, 0, -10795, 18432, 76, }, /* 771 */
+ { 0, 5, 12, 0, -10792, 18432, 76, }, /* 772 */
+ { 0, 9, 12, 0, -10780, 18432, 74, }, /* 773 */
+ { 0, 9, 12, 0, -10749, 18432, 74, }, /* 774 */
+ { 0, 9, 12, 0, -10783, 18432, 74, }, /* 775 */
+ { 0, 9, 12, 0, -10782, 18432, 74, }, /* 776 */
+ { 0, 9, 12, 0, -10815, 18432, 74, }, /* 777 */
+ { 34, 5, 12, 0, 0, 18432, 60, }, /* 778 */
+ { 34, 26, 12, 0, 0, 28672, 68, }, /* 779 */
+ { 34, 12, 3, 0, 0, 26624, 96, }, /* 780 */
+ { 34, 21, 12, 0, 0, 28672, 68, }, /* 781 */
+ { 34, 15, 12, 0, 0, 28672, 68, }, /* 782 */
+ { 17, 5, 12, 0, -7264, 18432, 76, }, /* 783 */
+ { 90, 7, 12, 0, 0, 18432, 82, }, /* 784 */
+ { 90, 6, 12, 0, 0, 18432, 142, }, /* 785 */
+ { 90, 21, 12, 0, 0, 18432, 68, }, /* 786 */
+ { 90, 12, 3, 0, 0, 26624, 184, }, /* 787 */
+ { 2, 12, 3, 0, 0, 26624, 130, }, /* 788 */
+ { 69, 20, 12, 0, 0, 28672, 216, }, /* 789 */
+ { 69, 19, 12, 0, 0, 28672, 216, }, /* 790 */
+ { 69, 6, 12, 0, 0, 28672, 274, }, /* 791 */
+ { 69, 21, 12, 0, 0, 28672, 276, }, /* 792 */
+ { 69, 21, 12, 0, 0, 28726, 54, }, /* 793 */
+ { 23, 26, 12, 0, 0, 28672, 278, }, /* 794 */
+ { 69, 26, 12, 0, 0, 28672, 280, }, /* 795 */
+ { 69, 26, 12, 0, 0, 28672, 282, }, /* 796 */
+ { 69, 21, 12, 0, 0, 28825, 276, }, /* 797 */
+ { 69, 21, 12, 0, 0, 28825, 212, }, /* 798 */
+ { 69, 21, 12, 0, 0, 28819, 54, }, /* 799 */
+ { 23, 6, 12, 0, 0, 18432, 136, }, /* 800 */
+ { 69, 7, 12, 0, 0, 18447, 284, }, /* 801 */
+ { 23, 14, 12, 0, 0, 18432, 284, }, /* 802 */
+ { 69, 22, 12, 0, 0, 28825, 216, }, /* 803 */
+ { 69, 18, 12, 0, 0, 28825, 216, }, /* 804 */
+ { 69, 22, 12, 0, 0, 28825, 62, }, /* 805 */
+ { 69, 18, 12, 0, 0, 28825, 62, }, /* 806 */
+ { 69, 26, 12, 0, 0, 28819, 54, }, /* 807 */
+ { 69, 17, 12, 0, 0, 28819, 202, }, /* 808 */
+ { 69, 22, 12, 0, 0, 28819, 206, }, /* 809 */
+ { 69, 18, 12, 0, 0, 28819, 206, }, /* 810 */
+ { 84, 12, 3, 0, 0, 26669, 96, }, /* 811 */
+ { 18, 10, 3, 0, 0, 18432, 286, }, /* 812 */
+ { 69, 17, 14, 0, 0, 28819, 288, }, /* 813 */
+ { 69, 6, 12, 0, 0, 18525, 136, }, /* 814 */
+ { 69, 26, 12, 0, 0, 28819, 68, }, /* 815 */
+ { 23, 6, 12, 0, 0, 18432, 142, }, /* 816 */
+ { 69, 7, 12, 0, 0, 18564, 82, }, /* 817 */
+ { 69, 21, 14, 0, 0, 28804, 236, }, /* 818 */
+ { 69, 26, 12, 0, 0, 28687, 68, }, /* 819 */
+ { 20, 7, 12, 0, 0, 18432, 82, }, /* 820 */
+ { 84, 12, 3, 0, 0, 26717, 96, }, /* 821 */
+ { 69, 24, 12, 0, 0, 28765, 290, }, /* 822 */
+ { 20, 6, 12, 0, 0, 18432, 136, }, /* 823 */
+ { 69, 17, 12, 0, 0, 28765, 126, }, /* 824 */
+ { 21, 7, 12, 0, 0, 18432, 82, }, /* 825 */
+ { 69, 21, 12, 0, 0, 28825, 68, }, /* 826 */
+ { 69, 6, 12, 0, 0, 18525, 94, }, /* 827 */
+ { 21, 6, 12, 0, 0, 18432, 136, }, /* 828 */
+ { 22, 7, 12, 0, 0, 18432, 82, }, /* 829 */
+ { 18, 7, 12, 0, 0, 18432, 82, }, /* 830 */
+ { 18, 7, 12, 0, 0, 18432, 170, }, /* 831 */
+ { 69, 26, 12, 0, 0, 18447, 68, }, /* 832 */
+ { 69, 15, 12, 0, 0, 18447, 68, }, /* 833 */
+ { 18, 26, 12, 0, 0, 18432, 68, }, /* 834 */
+ { 18, 26, 12, 0, 0, 28672, 68, }, /* 835 */
+ { 69, 15, 12, 0, 0, 18432, 68, }, /* 836 */
+ { 69, 26, 14, 0, 0, 18447, 236, }, /* 837 */
+ { 21, 26, 12, 0, 0, 18432, 68, }, /* 838 */
+ { 23, 7, 12, 0, 0, 18432, 292, }, /* 839 */
+ { 24, 7, 12, 0, 0, 18432, 82, }, /* 840 */
+ { 24, 6, 12, 0, 0, 18432, 136, }, /* 841 */
+ { 24, 26, 12, 0, 0, 28672, 68, }, /* 842 */
+ { 111, 7, 12, 0, 0, 18432, 82, }, /* 843 */
+ { 111, 6, 12, 0, 0, 18432, 142, }, /* 844 */
+ { 111, 21, 12, 0, 0, 18432, 106, }, /* 845 */
+ { 111, 21, 12, 0, 0, 18432, 124, }, /* 846 */
+ { 99, 7, 12, 0, 0, 18432, 82, }, /* 847 */
+ { 99, 6, 12, 0, 0, 18432, 136, }, /* 848 */
+ { 99, 21, 12, 0, 0, 28672, 106, }, /* 849 */
+ { 99, 21, 12, 0, 0, 28672, 124, }, /* 850 */
+ { 99, 13, 12, 0, 0, 18432, 138, }, /* 851 */
+ { 2, 9, 12, 108, 1, 18432, 74, }, /* 852 */
+ { 2, 5, 12, 108, -35267, 18432, 76, }, /* 853 */
+ { 2, 7, 12, 0, 0, 18432, 82, }, /* 854 */
+ { 2, 21, 12, 0, 0, 28672, 68, }, /* 855 */
+ { 2, 12, 3, 0, 0, 26624, 96, }, /* 856 */
+ { 2, 6, 12, 0, 0, 28672, 92, }, /* 857 */
+ { 2, 6, 12, 0, 0, 18432, 88, }, /* 858 */
+ { 112, 7, 12, 0, 0, 18432, 82, }, /* 859 */
+ { 112, 14, 12, 0, 0, 18432, 82, }, /* 860 */
+ { 112, 12, 3, 0, 0, 26624, 96, }, /* 861 */
+ { 112, 21, 12, 0, 0, 18432, 68, }, /* 862 */
+ { 112, 21, 12, 0, 0, 18432, 124, }, /* 863 */
+ { 112, 21, 12, 0, 0, 18432, 106, }, /* 864 */
+ { 69, 24, 12, 0, 0, 28762, 56, }, /* 865 */
+ { 0, 9, 12, 0, -35332, 18432, 74, }, /* 866 */
+ { 69, 24, 12, 0, 0, 18432, 56, }, /* 867 */
+ { 0, 9, 12, 0, -42280, 18432, 74, }, /* 868 */
+ { 0, 5, 12, 0, 48, 18432, 76, }, /* 869 */
+ { 0, 9, 12, 0, -42308, 18432, 74, }, /* 870 */
+ { 0, 9, 12, 0, -42319, 18432, 74, }, /* 871 */
+ { 0, 9, 12, 0, -42315, 18432, 74, }, /* 872 */
+ { 0, 9, 12, 0, -42305, 18432, 74, }, /* 873 */
+ { 0, 9, 12, 0, -42258, 18432, 74, }, /* 874 */
+ { 0, 9, 12, 0, -42282, 18432, 74, }, /* 875 */
+ { 0, 9, 12, 0, -42261, 18432, 74, }, /* 876 */
+ { 0, 9, 12, 0, 928, 18432, 74, }, /* 877 */
+ { 0, 9, 12, 0, -48, 18432, 74, }, /* 878 */
+ { 0, 9, 12, 0, -42307, 18432, 74, }, /* 879 */
+ { 0, 9, 12, 0, -35384, 18432, 74, }, /* 880 */
{ 36, 7, 12, 0, 0, 18432, 82, }, /* 881 */
{ 36, 12, 3, 0, 0, 26624, 130, }, /* 882 */
- { 36, 12, 3, 0, 0, 26624, 182, }, /* 883 */
+ { 36, 12, 3, 0, 0, 26624, 184, }, /* 883 */
{ 36, 10, 5, 0, 0, 18432, 144, }, /* 884 */
{ 36, 26, 12, 0, 0, 28672, 68, }, /* 885 */
{ 69, 15, 12, 0, 0, 18612, 68, }, /* 886 */
@@ -1331,18 +1331,18 @@ const ucd_record PRIV(ucd_records)[] = { /* 16908 bytes, record size 12 */
{ 39, 7, 12, 0, 0, 18432, 82, }, /* 903 */
{ 39, 12, 3, 0, 0, 26624, 130, }, /* 904 */
{ 39, 12, 3, 0, 0, 26624, 96, }, /* 905 */
- { 69, 21, 12, 0, 0, 18567, 188, }, /* 906 */
+ { 69, 21, 12, 0, 0, 18567, 190, }, /* 906 */
{ 39, 21, 12, 0, 0, 18432, 124, }, /* 907 */
{ 101, 7, 12, 0, 0, 18432, 82, }, /* 908 */
{ 101, 12, 3, 0, 0, 26624, 130, }, /* 909 */
{ 101, 10, 5, 0, 0, 18432, 144, }, /* 910 */
- { 101, 10, 5, 0, 0, 18432, 172, }, /* 911 */
+ { 101, 10, 5, 0, 0, 18432, 174, }, /* 911 */
{ 101, 21, 12, 0, 0, 18432, 68, }, /* 912 */
{ 40, 12, 3, 0, 0, 26624, 130, }, /* 913 */
{ 40, 10, 5, 0, 0, 18432, 144, }, /* 914 */
{ 40, 7, 12, 0, 0, 18432, 82, }, /* 915 */
{ 40, 12, 3, 0, 0, 26624, 96, }, /* 916 */
- { 40, 10, 5, 0, 0, 18432, 172, }, /* 917 */
+ { 40, 10, 5, 0, 0, 18432, 174, }, /* 917 */
{ 40, 21, 12, 0, 0, 18432, 68, }, /* 918 */
{ 40, 21, 12, 0, 0, 18432, 106, }, /* 919 */
{ 40, 21, 12, 0, 0, 18432, 124, }, /* 920 */
@@ -1370,470 +1370,484 @@ const ucd_record PRIV(ucd_records)[] = { /* 16908 bytes, record size 12 */
{ 113, 6, 12, 0, 0, 18432, 136, }, /* 942 */
{ 113, 12, 3, 0, 0, 26624, 146, }, /* 943 */
{ 0, 5, 12, 0, -928, 18432, 76, }, /* 944 */
- { 0, 6, 12, 0, 0, 18432, 92, }, /* 945 */
- { 76, 5, 12, 0, -38864, 18432, 70, }, /* 946 */
- { 113, 10, 5, 0, 0, 18432, 160, }, /* 947 */
- { 113, 13, 12, 0, 0, 18432, 138, }, /* 948 */
- { 18, 7, 9, 0, 0, 18432, 82, }, /* 949 */
- { 18, 7, 10, 0, 0, 18432, 82, }, /* 950 */
- { 68, 4, 12, 0, 0, 18432, 0, }, /* 951 */
- { 68, 3, 12, 0, 0, 18432, 0, }, /* 952 */
- { 23, 7, 12, 0, 0, 18432, 284, }, /* 953 */
- { 71, 25, 12, 0, 0, 12288, 118, }, /* 954 */
- { 3, 7, 12, 0, 0, 0, 296, }, /* 955 */
- { 69, 18, 12, 0, 0, 28705, 54, }, /* 956 */
- { 69, 22, 12, 0, 0, 28705, 54, }, /* 957 */
- { 68, 2, 12, 0, 0, 6144, 298, }, /* 958 */
- { 3, 7, 12, 0, 0, 39, 82, }, /* 959 */
- { 3, 26, 12, 0, 0, 28711, 68, }, /* 960 */
- { 84, 12, 3, 0, 0, 26624, 178, }, /* 961 */
- { 84, 12, 3, 0, 0, 26624, 300, }, /* 962 */
- { 69, 21, 12, 0, 0, 28672, 68, }, /* 963 */
- { 69, 21, 12, 0, 0, 28672, 122, }, /* 964 */
- { 69, 22, 12, 0, 0, 28672, 68, }, /* 965 */
- { 69, 18, 12, 0, 0, 28672, 68, }, /* 966 */
- { 69, 17, 12, 0, 0, 28672, 126, }, /* 967 */
- { 69, 22, 12, 0, 0, 28672, 302, }, /* 968 */
- { 69, 18, 12, 0, 0, 28672, 302, }, /* 969 */
- { 69, 21, 12, 0, 0, 8192, 106, }, /* 970 */
- { 69, 21, 12, 0, 0, 8192, 304, }, /* 971 */
- { 69, 21, 12, 0, 0, 8192, 306, }, /* 972 */
- { 69, 21, 12, 0, 0, 28672, 124, }, /* 973 */
- { 69, 22, 12, 0, 0, 28672, 158, }, /* 974 */
- { 69, 18, 12, 0, 0, 28672, 158, }, /* 975 */
- { 69, 21, 12, 0, 0, 14336, 68, }, /* 976 */
- { 69, 21, 12, 0, 0, 28672, 118, }, /* 977 */
- { 69, 17, 12, 0, 0, 12288, 224, }, /* 978 */
- { 69, 25, 12, 0, 0, 28672, 226, }, /* 979 */
- { 69, 21, 12, 0, 0, 28672, 302, }, /* 980 */
- { 69, 21, 12, 0, 0, 28672, 308, }, /* 981 */
- { 69, 17, 12, 0, 0, 12288, 126, }, /* 982 */
- { 69, 21, 12, 0, 0, 8192, 68, }, /* 983 */
- { 69, 13, 12, 0, 0, 10240, 310, }, /* 984 */
- { 0, 9, 12, 0, 32, 18432, 312, }, /* 985 */
- { 69, 24, 12, 0, 0, 28672, 314, }, /* 986 */
- { 0, 5, 12, 0, -32, 18432, 316, }, /* 987 */
- { 69, 21, 12, 0, 0, 28825, 124, }, /* 988 */
- { 69, 22, 12, 0, 0, 28825, 318, }, /* 989 */
- { 69, 18, 12, 0, 0, 28825, 318, }, /* 990 */
- { 69, 21, 12, 0, 0, 28825, 106, }, /* 991 */
- { 69, 6, 3, 0, 0, 18525, 320, }, /* 992 */
- { 69, 1, 2, 0, 0, 28672, 322, }, /* 993 */
- { 31, 7, 12, 0, 0, 18432, 82, }, /* 994 */
- { 69, 21, 12, 0, 0, 18552, 68, }, /* 995 */
- { 69, 21, 12, 0, 0, 28792, 68, }, /* 996 */
- { 69, 21, 12, 0, 0, 18483, 68, }, /* 997 */
- { 69, 15, 12, 0, 0, 18555, 68, }, /* 998 */
- { 69, 26, 12, 0, 0, 18483, 68, }, /* 999 */
- { 1, 14, 12, 0, 0, 28672, 82, }, /* 1000 */
- { 1, 15, 12, 0, 0, 28672, 68, }, /* 1001 */
- { 1, 26, 12, 0, 0, 28672, 68, }, /* 1002 */
- { 1, 26, 12, 0, 0, 18432, 68, }, /* 1003 */
- { 102, 7, 12, 0, 0, 18432, 82, }, /* 1004 */
- { 103, 7, 12, 0, 0, 18432, 82, }, /* 1005 */
- { 84, 12, 3, 0, 0, 26651, 96, }, /* 1006 */
- { 69, 15, 12, 0, 0, 10267, 68, }, /* 1007 */
- { 81, 7, 12, 0, 0, 18432, 82, }, /* 1008 */
- { 81, 15, 12, 0, 0, 18432, 68, }, /* 1009 */
- { 82, 7, 12, 0, 0, 18432, 82, }, /* 1010 */
- { 82, 14, 12, 0, 0, 18432, 82, }, /* 1011 */
- { 53, 7, 12, 0, 0, 18432, 82, }, /* 1012 */
- { 53, 12, 3, 0, 0, 26624, 130, }, /* 1013 */
- { 85, 7, 12, 0, 0, 18432, 82, }, /* 1014 */
- { 85, 21, 12, 0, 0, 18432, 106, }, /* 1015 */
- { 91, 7, 12, 0, 0, 18432, 82, }, /* 1016 */
- { 91, 21, 12, 0, 0, 18432, 106, }, /* 1017 */
- { 91, 14, 12, 0, 0, 18432, 82, }, /* 1018 */
- { 83, 9, 12, 0, 40, 18432, 74, }, /* 1019 */
- { 83, 5, 12, 0, -40, 18432, 76, }, /* 1020 */
- { 86, 7, 12, 0, 0, 18432, 82, }, /* 1021 */
- { 87, 7, 12, 0, 0, 18432, 82, }, /* 1022 */
- { 87, 13, 12, 0, 0, 18432, 138, }, /* 1023 */
- { 145, 9, 12, 0, 40, 18432, 74, }, /* 1024 */
- { 145, 5, 12, 0, -40, 18432, 76, }, /* 1025 */
- { 127, 7, 12, 0, 0, 18432, 82, }, /* 1026 */
- { 125, 7, 12, 0, 0, 18432, 82, }, /* 1027 */
- { 125, 21, 12, 0, 0, 18432, 68, }, /* 1028 */
- { 161, 9, 12, 0, 39, 18432, 74, }, /* 1029 */
- { 161, 5, 12, 0, -39, 18432, 76, }, /* 1030 */
- { 49, 7, 12, 0, 0, 18432, 82, }, /* 1031 */
- { 0, 6, 12, 0, 0, 18432, 94, }, /* 1032 */
- { 32, 7, 12, 0, 0, 34816, 82, }, /* 1033 */
- { 114, 7, 12, 0, 0, 34816, 82, }, /* 1034 */
- { 114, 21, 12, 0, 0, 34816, 106, }, /* 1035 */
- { 114, 15, 12, 0, 0, 34816, 68, }, /* 1036 */
- { 133, 7, 12, 0, 0, 34816, 82, }, /* 1037 */
- { 133, 26, 12, 0, 0, 34816, 68, }, /* 1038 */
- { 133, 15, 12, 0, 0, 34816, 68, }, /* 1039 */
- { 132, 7, 12, 0, 0, 34816, 82, }, /* 1040 */
- { 132, 15, 12, 0, 0, 34816, 68, }, /* 1041 */
- { 139, 7, 12, 0, 0, 34816, 82, }, /* 1042 */
- { 139, 15, 12, 0, 0, 34816, 68, }, /* 1043 */
- { 95, 7, 12, 0, 0, 34816, 82, }, /* 1044 */
- { 95, 15, 12, 0, 0, 34816, 68, }, /* 1045 */
- { 95, 21, 12, 0, 0, 28672, 106, }, /* 1046 */
- { 104, 7, 12, 0, 0, 34816, 82, }, /* 1047 */
- { 104, 21, 12, 0, 0, 34816, 68, }, /* 1048 */
- { 122, 7, 12, 0, 0, 34816, 82, }, /* 1049 */
- { 121, 7, 12, 0, 0, 34816, 82, }, /* 1050 */
- { 121, 15, 12, 0, 0, 34816, 68, }, /* 1051 */
- { 92, 7, 12, 0, 0, 34816, 82, }, /* 1052 */
- { 92, 12, 3, 0, 0, 26624, 130, }, /* 1053 */
- { 92, 12, 3, 0, 0, 26624, 102, }, /* 1054 */
- { 92, 12, 3, 0, 0, 26624, 182, }, /* 1055 */
- { 92, 15, 12, 0, 0, 34816, 68, }, /* 1056 */
- { 92, 21, 12, 0, 0, 34816, 68, }, /* 1057 */
- { 92, 21, 12, 0, 0, 34816, 124, }, /* 1058 */
- { 115, 7, 12, 0, 0, 34816, 82, }, /* 1059 */
- { 115, 15, 12, 0, 0, 34816, 68, }, /* 1060 */
- { 115, 21, 12, 0, 0, 34816, 68, }, /* 1061 */
- { 131, 7, 12, 0, 0, 34816, 82, }, /* 1062 */
- { 131, 15, 12, 0, 0, 34816, 68, }, /* 1063 */
- { 51, 7, 12, 0, 0, 34816, 82, }, /* 1064 */
- { 51, 26, 12, 0, 0, 34816, 68, }, /* 1065 */
- { 51, 12, 3, 0, 0, 26624, 96, }, /* 1066 */
- { 51, 15, 12, 0, 0, 34816, 68, }, /* 1067 */
- { 51, 21, 12, 0, 0, 34816, 106, }, /* 1068 */
- { 51, 21, 12, 0, 0, 34918, 106, }, /* 1069 */
- { 51, 21, 12, 0, 0, 34816, 68, }, /* 1070 */
- { 108, 7, 12, 0, 0, 34816, 82, }, /* 1071 */
- { 108, 21, 12, 0, 0, 28672, 68, }, /* 1072 */
- { 108, 21, 12, 0, 0, 28672, 106, }, /* 1073 */
- { 116, 7, 12, 0, 0, 34816, 82, }, /* 1074 */
- { 116, 15, 12, 0, 0, 34816, 68, }, /* 1075 */
- { 117, 7, 12, 0, 0, 34816, 82, }, /* 1076 */
- { 117, 15, 12, 0, 0, 34816, 68, }, /* 1077 */
- { 54, 7, 12, 0, 0, 34816, 82, }, /* 1078 */
- { 54, 21, 12, 0, 0, 34816, 106, }, /* 1079 */
- { 54, 15, 12, 0, 0, 34816, 68, }, /* 1080 */
- { 118, 7, 12, 0, 0, 34816, 82, }, /* 1081 */
- { 140, 9, 12, 0, 64, 34816, 74, }, /* 1082 */
- { 140, 5, 12, 0, -64, 34816, 76, }, /* 1083 */
- { 140, 15, 12, 0, 0, 34816, 68, }, /* 1084 */
- { 62, 7, 12, 0, 0, 0, 82, }, /* 1085 */
- { 62, 7, 12, 0, 0, 0, 294, }, /* 1086 */
- { 62, 12, 3, 0, 0, 26624, 128, }, /* 1087 */
- { 62, 13, 12, 0, 0, 2048, 138, }, /* 1088 */
- { 3, 15, 12, 0, 0, 2048, 68, }, /* 1089 */
- { 65, 7, 12, 0, 0, 34816, 82, }, /* 1090 */
- { 65, 12, 3, 0, 0, 26624, 130, }, /* 1091 */
- { 65, 17, 12, 0, 0, 34816, 126, }, /* 1092 */
- { 152, 7, 12, 0, 0, 34816, 82, }, /* 1093 */
- { 152, 15, 12, 0, 0, 34816, 68, }, /* 1094 */
- { 63, 7, 12, 0, 0, 0, 82, }, /* 1095 */
- { 63, 12, 3, 0, 0, 26624, 96, }, /* 1096 */
- { 63, 15, 12, 0, 0, 0, 68, }, /* 1097 */
- { 63, 21, 12, 0, 0, 0, 124, }, /* 1098 */
- { 67, 7, 12, 0, 0, 34816, 82, }, /* 1099 */
- { 67, 12, 3, 0, 0, 26624, 96, }, /* 1100 */
- { 67, 21, 12, 0, 0, 34816, 124, }, /* 1101 */
- { 156, 7, 12, 0, 0, 34816, 82, }, /* 1102 */
- { 156, 15, 12, 0, 0, 34816, 68, }, /* 1103 */
- { 153, 7, 12, 0, 0, 34816, 82, }, /* 1104 */
- { 120, 10, 5, 0, 0, 18432, 144, }, /* 1105 */
- { 120, 12, 3, 0, 0, 26624, 130, }, /* 1106 */
- { 120, 7, 12, 0, 0, 18432, 82, }, /* 1107 */
- { 120, 12, 3, 0, 0, 26624, 146, }, /* 1108 */
- { 120, 21, 12, 0, 0, 18432, 124, }, /* 1109 */
- { 120, 21, 12, 0, 0, 18432, 106, }, /* 1110 */
- { 120, 15, 12, 0, 0, 28672, 68, }, /* 1111 */
- { 120, 13, 12, 0, 0, 18432, 138, }, /* 1112 */
- { 120, 12, 3, 0, 0, 26624, 182, }, /* 1113 */
- { 41, 12, 3, 0, 0, 26624, 102, }, /* 1114 */
- { 41, 10, 5, 0, 0, 18432, 144, }, /* 1115 */
- { 41, 7, 12, 0, 0, 18432, 82, }, /* 1116 */
- { 41, 12, 3, 0, 0, 26624, 130, }, /* 1117 */
- { 41, 12, 3, 0, 0, 26624, 146, }, /* 1118 */
- { 41, 12, 3, 0, 0, 26624, 96, }, /* 1119 */
- { 41, 21, 12, 0, 0, 18432, 68, }, /* 1120 */
- { 41, 1, 4, 0, 0, 18432, 132, }, /* 1121 */
- { 41, 21, 12, 0, 0, 18432, 124, }, /* 1122 */
- { 124, 7, 12, 0, 0, 18432, 82, }, /* 1123 */
- { 124, 13, 12, 0, 0, 18432, 138, }, /* 1124 */
- { 43, 12, 3, 0, 0, 26624, 130, }, /* 1125 */
- { 43, 7, 12, 0, 0, 18432, 82, }, /* 1126 */
- { 43, 10, 5, 0, 0, 18432, 144, }, /* 1127 */
- { 43, 12, 3, 0, 0, 26624, 146, }, /* 1128 */
- { 43, 13, 12, 0, 0, 18432, 138, }, /* 1129 */
- { 43, 21, 12, 0, 0, 18432, 68, }, /* 1130 */
- { 43, 21, 12, 0, 0, 18432, 124, }, /* 1131 */
- { 50, 7, 12, 0, 0, 18432, 82, }, /* 1132 */
- { 50, 12, 3, 0, 0, 26624, 96, }, /* 1133 */
- { 50, 21, 12, 0, 0, 18432, 68, }, /* 1134 */
- { 44, 12, 3, 0, 0, 26624, 130, }, /* 1135 */
- { 44, 10, 5, 0, 0, 18432, 144, }, /* 1136 */
- { 44, 7, 12, 0, 0, 18432, 82, }, /* 1137 */
- { 44, 10, 5, 0, 0, 18432, 172, }, /* 1138 */
- { 44, 7, 4, 0, 0, 18432, 82, }, /* 1139 */
- { 44, 21, 12, 0, 0, 18432, 124, }, /* 1140 */
- { 44, 21, 12, 0, 0, 18432, 68, }, /* 1141 */
- { 44, 12, 3, 0, 0, 26624, 102, }, /* 1142 */
- { 44, 12, 3, 0, 0, 26624, 96, }, /* 1143 */
- { 44, 13, 12, 0, 0, 18432, 138, }, /* 1144 */
- { 15, 15, 12, 0, 0, 18432, 68, }, /* 1145 */
- { 48, 7, 12, 0, 0, 18432, 82, }, /* 1146 */
- { 48, 10, 5, 0, 0, 18432, 144, }, /* 1147 */
- { 48, 12, 3, 0, 0, 26624, 130, }, /* 1148 */
- { 48, 10, 5, 0, 0, 18432, 172, }, /* 1149 */
- { 48, 12, 3, 0, 0, 26624, 96, }, /* 1150 */
- { 48, 21, 12, 0, 0, 18432, 124, }, /* 1151 */
- { 48, 21, 12, 0, 0, 18432, 106, }, /* 1152 */
- { 48, 21, 12, 0, 0, 18432, 68, }, /* 1153 */
- { 57, 7, 12, 0, 0, 18432, 82, }, /* 1154 */
- { 57, 21, 12, 0, 0, 18432, 124, }, /* 1155 */
- { 55, 7, 12, 0, 0, 18432, 82, }, /* 1156 */
- { 55, 12, 3, 0, 0, 26624, 130, }, /* 1157 */
- { 55, 10, 5, 0, 0, 18432, 144, }, /* 1158 */
- { 55, 12, 3, 0, 0, 26624, 96, }, /* 1159 */
- { 55, 12, 3, 0, 0, 26624, 146, }, /* 1160 */
- { 55, 13, 12, 0, 0, 18432, 138, }, /* 1161 */
- { 47, 12, 3, 0, 0, 26624, 130, }, /* 1162 */
- { 47, 12, 3, 0, 0, 26705, 130, }, /* 1163 */
- { 47, 10, 5, 0, 0, 18432, 144, }, /* 1164 */
- { 47, 10, 5, 0, 0, 18513, 144, }, /* 1165 */
- { 47, 7, 12, 0, 0, 18432, 82, }, /* 1166 */
- { 84, 12, 3, 0, 0, 26705, 102, }, /* 1167 */
- { 47, 12, 3, 0, 0, 26705, 96, }, /* 1168 */
- { 47, 10, 3, 0, 0, 18432, 148, }, /* 1169 */
- { 47, 10, 5, 0, 0, 18432, 172, }, /* 1170 */
- { 47, 7, 12, 0, 0, 18432, 324, }, /* 1171 */
- { 47, 12, 3, 0, 0, 26624, 96, }, /* 1172 */
- { 144, 7, 12, 0, 0, 18432, 82, }, /* 1173 */
- { 144, 10, 5, 0, 0, 18432, 144, }, /* 1174 */
- { 144, 12, 3, 0, 0, 26624, 130, }, /* 1175 */
- { 144, 12, 3, 0, 0, 26624, 146, }, /* 1176 */
- { 144, 12, 3, 0, 0, 26624, 96, }, /* 1177 */
- { 144, 21, 12, 0, 0, 18432, 124, }, /* 1178 */
- { 144, 21, 12, 0, 0, 18432, 106, }, /* 1179 */
- { 144, 21, 12, 0, 0, 18432, 68, }, /* 1180 */
- { 144, 13, 12, 0, 0, 18432, 138, }, /* 1181 */
- { 144, 12, 3, 0, 0, 26624, 102, }, /* 1182 */
- { 56, 7, 12, 0, 0, 18432, 82, }, /* 1183 */
- { 56, 10, 3, 0, 0, 18432, 148, }, /* 1184 */
- { 56, 10, 5, 0, 0, 18432, 144, }, /* 1185 */
- { 56, 12, 3, 0, 0, 26624, 130, }, /* 1186 */
- { 56, 12, 3, 0, 0, 26624, 146, }, /* 1187 */
- { 56, 12, 3, 0, 0, 26624, 96, }, /* 1188 */
- { 56, 21, 12, 0, 0, 18432, 68, }, /* 1189 */
- { 56, 13, 12, 0, 0, 18432, 138, }, /* 1190 */
- { 135, 7, 12, 0, 0, 18432, 82, }, /* 1191 */
- { 135, 10, 3, 0, 0, 18432, 148, }, /* 1192 */
- { 135, 10, 5, 0, 0, 18432, 144, }, /* 1193 */
- { 135, 12, 3, 0, 0, 26624, 130, }, /* 1194 */
- { 135, 12, 3, 0, 0, 26624, 146, }, /* 1195 */
- { 135, 12, 3, 0, 0, 26624, 96, }, /* 1196 */
- { 135, 21, 12, 0, 0, 18432, 68, }, /* 1197 */
- { 135, 21, 12, 0, 0, 18432, 124, }, /* 1198 */
- { 135, 21, 12, 0, 0, 18432, 106, }, /* 1199 */
- { 135, 21, 12, 0, 0, 18432, 176, }, /* 1200 */
- { 52, 7, 12, 0, 0, 18432, 82, }, /* 1201 */
- { 52, 10, 5, 0, 0, 18432, 144, }, /* 1202 */
- { 52, 12, 3, 0, 0, 26624, 130, }, /* 1203 */
- { 52, 12, 3, 0, 0, 26624, 146, }, /* 1204 */
- { 52, 21, 12, 0, 0, 18432, 124, }, /* 1205 */
- { 52, 21, 12, 0, 0, 18432, 68, }, /* 1206 */
- { 52, 13, 12, 0, 0, 18432, 138, }, /* 1207 */
- { 45, 7, 12, 0, 0, 18432, 82, }, /* 1208 */
- { 45, 12, 3, 0, 0, 26624, 130, }, /* 1209 */
- { 45, 10, 5, 0, 0, 18432, 144, }, /* 1210 */
- { 45, 10, 5, 0, 0, 18432, 172, }, /* 1211 */
- { 45, 12, 3, 0, 0, 26624, 96, }, /* 1212 */
- { 45, 21, 12, 0, 0, 18432, 68, }, /* 1213 */
- { 45, 13, 12, 0, 0, 18432, 138, }, /* 1214 */
- { 137, 7, 12, 0, 0, 18432, 82, }, /* 1215 */
- { 137, 12, 3, 0, 0, 26624, 130, }, /* 1216 */
- { 137, 10, 12, 0, 0, 18432, 144, }, /* 1217 */
- { 137, 10, 5, 0, 0, 18432, 144, }, /* 1218 */
- { 137, 12, 3, 0, 0, 26624, 146, }, /* 1219 */
- { 137, 13, 12, 0, 0, 18432, 138, }, /* 1220 */
- { 137, 15, 12, 0, 0, 18432, 68, }, /* 1221 */
- { 137, 21, 12, 0, 0, 18432, 124, }, /* 1222 */
- { 137, 26, 12, 0, 0, 18432, 68, }, /* 1223 */
- { 60, 7, 12, 0, 0, 18432, 82, }, /* 1224 */
- { 60, 10, 5, 0, 0, 18432, 144, }, /* 1225 */
- { 60, 12, 3, 0, 0, 26624, 130, }, /* 1226 */
- { 60, 12, 3, 0, 0, 26624, 146, }, /* 1227 */
- { 60, 12, 3, 0, 0, 26624, 96, }, /* 1228 */
- { 60, 21, 12, 0, 0, 18432, 68, }, /* 1229 */
- { 136, 9, 12, 0, 32, 18432, 74, }, /* 1230 */
- { 136, 5, 12, 0, -32, 18432, 76, }, /* 1231 */
- { 136, 13, 12, 0, 0, 18432, 138, }, /* 1232 */
- { 136, 15, 12, 0, 0, 18432, 68, }, /* 1233 */
- { 136, 7, 12, 0, 0, 18432, 82, }, /* 1234 */
- { 157, 7, 12, 0, 0, 18432, 82, }, /* 1235 */
- { 157, 10, 3, 0, 0, 18432, 148, }, /* 1236 */
- { 157, 10, 5, 0, 0, 18432, 144, }, /* 1237 */
- { 157, 12, 3, 0, 0, 26624, 130, }, /* 1238 */
- { 157, 10, 5, 0, 0, 18432, 172, }, /* 1239 */
- { 157, 12, 3, 0, 0, 26624, 146, }, /* 1240 */
- { 157, 7, 4, 0, 0, 18432, 82, }, /* 1241 */
- { 157, 12, 3, 0, 0, 26624, 96, }, /* 1242 */
- { 157, 21, 12, 0, 0, 18432, 124, }, /* 1243 */
- { 157, 21, 12, 0, 0, 18432, 68, }, /* 1244 */
- { 157, 13, 12, 0, 0, 18432, 138, }, /* 1245 */
- { 64, 7, 12, 0, 0, 18432, 82, }, /* 1246 */
- { 64, 10, 5, 0, 0, 18432, 144, }, /* 1247 */
- { 64, 12, 3, 0, 0, 26624, 130, }, /* 1248 */
- { 64, 12, 3, 0, 0, 26624, 146, }, /* 1249 */
- { 64, 21, 12, 0, 0, 18432, 68, }, /* 1250 */
- { 149, 7, 12, 0, 0, 18432, 82, }, /* 1251 */
- { 149, 12, 3, 0, 0, 26624, 130, }, /* 1252 */
- { 149, 12, 3, 0, 0, 18432, 130, }, /* 1253 */
- { 149, 12, 3, 0, 0, 26624, 102, }, /* 1254 */
- { 149, 12, 3, 0, 0, 26624, 146, }, /* 1255 */
- { 149, 10, 5, 0, 0, 18432, 144, }, /* 1256 */
- { 149, 7, 4, 0, 0, 18432, 82, }, /* 1257 */
- { 149, 21, 12, 0, 0, 18432, 68, }, /* 1258 */
- { 149, 21, 12, 0, 0, 18432, 124, }, /* 1259 */
- { 148, 7, 12, 0, 0, 18432, 82, }, /* 1260 */
- { 148, 12, 3, 0, 0, 26624, 130, }, /* 1261 */
- { 148, 10, 5, 0, 0, 18432, 144, }, /* 1262 */
- { 148, 7, 4, 0, 0, 18432, 82, }, /* 1263 */
- { 148, 12, 3, 0, 0, 26624, 326, }, /* 1264 */
- { 148, 12, 3, 0, 0, 26624, 146, }, /* 1265 */
- { 148, 21, 12, 0, 0, 18432, 68, }, /* 1266 */
- { 148, 21, 12, 0, 0, 18432, 124, }, /* 1267 */
- { 148, 21, 12, 0, 0, 18432, 106, }, /* 1268 */
- { 134, 7, 12, 0, 0, 18432, 82, }, /* 1269 */
- { 142, 7, 12, 0, 0, 18432, 82, }, /* 1270 */
- { 142, 10, 5, 0, 0, 18432, 144, }, /* 1271 */
- { 142, 12, 3, 0, 0, 26624, 130, }, /* 1272 */
- { 142, 12, 3, 0, 0, 18432, 146, }, /* 1273 */
- { 142, 21, 12, 0, 0, 18432, 124, }, /* 1274 */
- { 142, 21, 12, 0, 0, 18432, 106, }, /* 1275 */
- { 142, 21, 12, 0, 0, 18432, 68, }, /* 1276 */
- { 142, 13, 12, 0, 0, 18432, 138, }, /* 1277 */
- { 142, 15, 12, 0, 0, 18432, 68, }, /* 1278 */
- { 143, 21, 12, 0, 0, 18432, 68, }, /* 1279 */
- { 143, 21, 12, 0, 0, 18432, 106, }, /* 1280 */
- { 143, 7, 12, 0, 0, 18432, 82, }, /* 1281 */
- { 143, 12, 3, 0, 0, 26624, 130, }, /* 1282 */
- { 143, 10, 5, 0, 0, 18432, 144, }, /* 1283 */
- { 59, 7, 12, 0, 0, 18432, 82, }, /* 1284 */
- { 59, 12, 3, 0, 0, 26624, 130, }, /* 1285 */
- { 59, 12, 3, 0, 0, 26624, 96, }, /* 1286 */
- { 59, 12, 3, 0, 0, 26624, 146, }, /* 1287 */
- { 59, 7, 4, 0, 0, 18432, 82, }, /* 1288 */
- { 59, 13, 12, 0, 0, 18432, 138, }, /* 1289 */
- { 61, 7, 12, 0, 0, 18432, 82, }, /* 1290 */
- { 61, 10, 5, 0, 0, 18432, 144, }, /* 1291 */
- { 61, 12, 3, 0, 0, 26624, 130, }, /* 1292 */
- { 61, 12, 3, 0, 0, 26624, 146, }, /* 1293 */
- { 61, 13, 12, 0, 0, 18432, 138, }, /* 1294 */
- { 150, 7, 12, 0, 0, 18432, 82, }, /* 1295 */
- { 150, 12, 3, 0, 0, 26624, 130, }, /* 1296 */
- { 150, 10, 5, 0, 0, 18432, 144, }, /* 1297 */
- { 150, 21, 12, 0, 0, 18432, 124, }, /* 1298 */
- { 11, 15, 12, 0, 0, 18432, 68, }, /* 1299 */
- { 11, 21, 12, 0, 0, 18432, 68, }, /* 1300 */
- { 94, 7, 12, 0, 0, 18432, 82, }, /* 1301 */
- { 94, 14, 12, 0, 0, 18432, 82, }, /* 1302 */
- { 94, 21, 12, 0, 0, 18432, 106, }, /* 1303 */
- { 66, 7, 12, 0, 0, 18432, 82, }, /* 1304 */
- { 66, 21, 12, 0, 0, 18432, 68, }, /* 1305 */
- { 109, 7, 12, 0, 0, 18432, 82, }, /* 1306 */
- { 109, 1, 2, 0, 0, 18432, 322, }, /* 1307 */
- { 138, 7, 12, 0, 0, 18432, 82, }, /* 1308 */
- { 130, 7, 12, 0, 0, 18432, 82, }, /* 1309 */
- { 130, 13, 12, 0, 0, 18432, 138, }, /* 1310 */
- { 130, 21, 12, 0, 0, 18432, 124, }, /* 1311 */
- { 159, 7, 12, 0, 0, 18432, 82, }, /* 1312 */
- { 159, 13, 12, 0, 0, 18432, 138, }, /* 1313 */
- { 126, 7, 12, 0, 0, 18432, 82, }, /* 1314 */
- { 126, 12, 3, 0, 0, 26624, 96, }, /* 1315 */
- { 126, 21, 12, 0, 0, 18432, 124, }, /* 1316 */
- { 128, 7, 12, 0, 0, 18432, 82, }, /* 1317 */
- { 128, 12, 3, 0, 0, 26624, 96, }, /* 1318 */
- { 128, 21, 12, 0, 0, 18432, 124, }, /* 1319 */
- { 128, 21, 12, 0, 0, 18432, 106, }, /* 1320 */
- { 128, 21, 12, 0, 0, 18432, 68, }, /* 1321 */
- { 128, 26, 12, 0, 0, 18432, 68, }, /* 1322 */
- { 128, 6, 12, 0, 0, 18432, 142, }, /* 1323 */
- { 128, 6, 12, 0, 0, 18432, 136, }, /* 1324 */
- { 128, 13, 12, 0, 0, 18432, 138, }, /* 1325 */
- { 128, 15, 12, 0, 0, 18432, 68, }, /* 1326 */
- { 151, 9, 12, 0, 32, 18432, 74, }, /* 1327 */
- { 151, 5, 12, 0, -32, 18432, 76, }, /* 1328 */
- { 151, 15, 12, 0, 0, 18432, 68, }, /* 1329 */
- { 151, 21, 12, 0, 0, 18432, 106, }, /* 1330 */
- { 151, 21, 12, 0, 0, 18432, 124, }, /* 1331 */
- { 151, 21, 12, 0, 0, 18432, 68, }, /* 1332 */
- { 123, 7, 12, 0, 0, 18432, 82, }, /* 1333 */
- { 123, 12, 3, 0, 0, 26624, 130, }, /* 1334 */
- { 123, 10, 5, 0, 0, 18432, 144, }, /* 1335 */
- { 123, 12, 3, 0, 0, 26624, 128, }, /* 1336 */
- { 123, 6, 12, 0, 0, 18432, 92, }, /* 1337 */
- { 146, 6, 12, 0, 0, 18432, 136, }, /* 1338 */
- { 147, 6, 12, 0, 0, 18432, 136, }, /* 1339 */
- { 23, 21, 12, 0, 0, 28672, 68, }, /* 1340 */
- { 158, 12, 3, 0, 0, 26624, 328, }, /* 1341 */
- { 23, 10, 5, 0, 0, 18432, 164, }, /* 1342 */
- { 146, 7, 12, 0, 0, 18432, 284, }, /* 1343 */
- { 158, 7, 12, 0, 0, 18432, 284, }, /* 1344 */
- { 21, 6, 12, 0, 0, 18432, 92, }, /* 1345 */
- { 147, 7, 12, 0, 0, 18432, 284, }, /* 1346 */
- { 46, 7, 12, 0, 0, 18432, 82, }, /* 1347 */
- { 46, 26, 12, 0, 0, 18432, 68, }, /* 1348 */
- { 46, 12, 3, 0, 0, 26624, 102, }, /* 1349 */
- { 46, 12, 3, 0, 0, 26624, 130, }, /* 1350 */
- { 46, 21, 12, 0, 0, 18432, 124, }, /* 1351 */
- { 69, 1, 2, 0, 0, 6153, 66, }, /* 1352 */
- { 69, 10, 3, 0, 0, 18432, 330, }, /* 1353 */
- { 69, 10, 5, 0, 0, 18432, 138, }, /* 1354 */
- { 69, 10, 5, 0, 0, 18432, 160, }, /* 1355 */
- { 69, 10, 3, 0, 0, 18432, 286, }, /* 1356 */
- { 1, 12, 3, 0, 0, 26624, 102, }, /* 1357 */
- { 69, 25, 12, 0, 0, 18432, 118, }, /* 1358 */
- { 69, 13, 12, 0, 0, 10240, 214, }, /* 1359 */
- { 141, 26, 12, 0, 0, 18432, 68, }, /* 1360 */
- { 141, 12, 3, 0, 0, 26624, 102, }, /* 1361 */
- { 141, 21, 12, 0, 0, 18432, 106, }, /* 1362 */
- { 141, 21, 12, 0, 0, 18432, 124, }, /* 1363 */
- { 141, 21, 12, 0, 0, 18432, 68, }, /* 1364 */
- { 35, 12, 3, 0, 0, 26624, 130, }, /* 1365 */
- { 154, 7, 12, 0, 0, 18432, 82, }, /* 1366 */
- { 154, 12, 3, 0, 0, 26624, 96, }, /* 1367 */
- { 154, 6, 12, 0, 0, 18432, 142, }, /* 1368 */
- { 154, 6, 12, 0, 0, 18432, 136, }, /* 1369 */
- { 154, 13, 12, 0, 0, 18432, 138, }, /* 1370 */
- { 154, 26, 12, 0, 0, 18432, 68, }, /* 1371 */
- { 160, 7, 12, 0, 0, 18432, 82, }, /* 1372 */
- { 160, 12, 3, 0, 0, 26624, 96, }, /* 1373 */
- { 155, 7, 12, 0, 0, 18432, 82, }, /* 1374 */
- { 155, 12, 3, 0, 0, 26624, 96, }, /* 1375 */
- { 155, 13, 12, 0, 0, 18432, 138, }, /* 1376 */
- { 155, 23, 12, 0, 0, 14336, 68, }, /* 1377 */
- { 129, 7, 12, 0, 0, 34816, 82, }, /* 1378 */
- { 129, 15, 12, 0, 0, 34816, 68, }, /* 1379 */
- { 129, 12, 3, 0, 0, 26624, 96, }, /* 1380 */
- { 58, 9, 12, 0, 34, 34816, 74, }, /* 1381 */
- { 58, 5, 12, 0, -34, 34816, 76, }, /* 1382 */
- { 58, 12, 3, 0, 0, 26624, 150, }, /* 1383 */
- { 58, 12, 3, 0, 0, 26624, 130, }, /* 1384 */
- { 58, 12, 3, 0, 0, 26624, 96, }, /* 1385 */
- { 58, 6, 12, 0, 0, 34816, 142, }, /* 1386 */
- { 58, 13, 12, 0, 0, 34816, 138, }, /* 1387 */
- { 58, 21, 12, 0, 0, 34816, 68, }, /* 1388 */
- { 69, 15, 12, 0, 0, 0, 68, }, /* 1389 */
- { 69, 26, 12, 0, 0, 0, 68, }, /* 1390 */
- { 69, 23, 12, 0, 0, 0, 68, }, /* 1391 */
- { 3, 7, 12, 0, 0, 0, 240, }, /* 1392 */
- { 69, 26, 14, 0, 0, 28672, 332, }, /* 1393 */
- { 69, 26, 14, 0, 0, 28672, 334, }, /* 1394 */
- { 68, 2, 14, 0, 0, 18432, 336, }, /* 1395 */
- { 69, 26, 12, 0, 0, 18432, 338, }, /* 1396 */
- { 69, 26, 14, 0, 0, 18432, 340, }, /* 1397 */
- { 69, 26, 14, 0, 0, 18432, 334, }, /* 1398 */
- { 69, 26, 11, 0, 0, 18432, 342, }, /* 1399 */
- { 20, 26, 12, 0, 0, 18432, 68, }, /* 1400 */
- { 69, 26, 14, 0, 0, 18432, 236, }, /* 1401 */
- { 69, 26, 14, 0, 0, 18447, 334, }, /* 1402 */
- { 69, 26, 14, 0, 0, 28672, 344, }, /* 1403 */
- { 69, 26, 14, 0, 0, 28672, 346, }, /* 1404 */
- { 69, 24, 3, 0, 0, 28672, 348, }, /* 1405 */
- { 69, 26, 14, 0, 0, 28672, 350, }, /* 1406 */
- { 69, 13, 12, 0, 0, 10240, 138, }, /* 1407 */
- { 69, 1, 3, 0, 0, 6144, 352, }, /* 1408 */
+ { 76, 5, 12, 0, -38864, 18432, 70, }, /* 945 */
+ { 113, 10, 5, 0, 0, 18432, 160, }, /* 946 */
+ { 113, 13, 12, 0, 0, 18432, 138, }, /* 947 */
+ { 18, 7, 9, 0, 0, 18432, 82, }, /* 948 */
+ { 18, 7, 10, 0, 0, 18432, 82, }, /* 949 */
+ { 68, 4, 12, 0, 0, 18432, 0, }, /* 950 */
+ { 68, 3, 12, 0, 0, 18432, 0, }, /* 951 */
+ { 23, 7, 12, 0, 0, 18432, 284, }, /* 952 */
+ { 71, 25, 12, 0, 0, 12288, 118, }, /* 953 */
+ { 3, 7, 12, 0, 0, 0, 296, }, /* 954 */
+ { 69, 18, 12, 0, 0, 28705, 54, }, /* 955 */
+ { 69, 22, 12, 0, 0, 28705, 54, }, /* 956 */
+ { 68, 2, 12, 0, 0, 6144, 298, }, /* 957 */
+ { 3, 7, 12, 0, 0, 39, 82, }, /* 958 */
+ { 3, 26, 12, 0, 0, 28711, 68, }, /* 959 */
+ { 84, 12, 3, 0, 0, 26624, 180, }, /* 960 */
+ { 84, 12, 3, 0, 0, 26624, 300, }, /* 961 */
+ { 69, 21, 12, 0, 0, 28672, 68, }, /* 962 */
+ { 69, 21, 12, 0, 0, 28672, 122, }, /* 963 */
+ { 69, 22, 12, 0, 0, 28672, 68, }, /* 964 */
+ { 69, 18, 12, 0, 0, 28672, 68, }, /* 965 */
+ { 69, 17, 12, 0, 0, 28672, 126, }, /* 966 */
+ { 69, 22, 12, 0, 0, 28672, 302, }, /* 967 */
+ { 69, 18, 12, 0, 0, 28672, 302, }, /* 968 */
+ { 69, 21, 12, 0, 0, 8192, 106, }, /* 969 */
+ { 69, 21, 12, 0, 0, 8192, 304, }, /* 970 */
+ { 69, 21, 12, 0, 0, 8192, 306, }, /* 971 */
+ { 69, 21, 12, 0, 0, 28672, 124, }, /* 972 */
+ { 69, 22, 12, 0, 0, 28672, 158, }, /* 973 */
+ { 69, 18, 12, 0, 0, 28672, 158, }, /* 974 */
+ { 69, 21, 12, 0, 0, 14336, 68, }, /* 975 */
+ { 69, 21, 12, 0, 0, 28672, 118, }, /* 976 */
+ { 69, 17, 12, 0, 0, 12288, 224, }, /* 977 */
+ { 69, 25, 12, 0, 0, 28672, 226, }, /* 978 */
+ { 69, 21, 12, 0, 0, 28672, 302, }, /* 979 */
+ { 69, 21, 12, 0, 0, 28672, 308, }, /* 980 */
+ { 69, 17, 12, 0, 0, 12288, 126, }, /* 981 */
+ { 69, 21, 12, 0, 0, 8192, 68, }, /* 982 */
+ { 69, 13, 12, 0, 0, 10240, 310, }, /* 983 */
+ { 0, 9, 12, 0, 32, 18432, 312, }, /* 984 */
+ { 69, 24, 12, 0, 0, 28672, 314, }, /* 985 */
+ { 0, 5, 12, 0, -32, 18432, 316, }, /* 986 */
+ { 69, 21, 12, 0, 0, 28825, 124, }, /* 987 */
+ { 69, 22, 12, 0, 0, 28825, 318, }, /* 988 */
+ { 69, 18, 12, 0, 0, 28825, 318, }, /* 989 */
+ { 69, 21, 12, 0, 0, 28825, 106, }, /* 990 */
+ { 69, 6, 3, 0, 0, 18525, 320, }, /* 991 */
+ { 69, 1, 2, 0, 0, 28672, 322, }, /* 992 */
+ { 31, 7, 12, 0, 0, 18432, 82, }, /* 993 */
+ { 69, 21, 12, 0, 0, 18552, 68, }, /* 994 */
+ { 69, 21, 12, 0, 0, 28792, 68, }, /* 995 */
+ { 69, 21, 12, 0, 0, 18483, 68, }, /* 996 */
+ { 69, 15, 12, 0, 0, 18555, 68, }, /* 997 */
+ { 69, 26, 12, 0, 0, 18483, 68, }, /* 998 */
+ { 1, 14, 12, 0, 0, 28672, 82, }, /* 999 */
+ { 1, 15, 12, 0, 0, 28672, 68, }, /* 1000 */
+ { 1, 26, 12, 0, 0, 28672, 68, }, /* 1001 */
+ { 1, 26, 12, 0, 0, 18432, 68, }, /* 1002 */
+ { 102, 7, 12, 0, 0, 18432, 82, }, /* 1003 */
+ { 103, 7, 12, 0, 0, 18432, 82, }, /* 1004 */
+ { 84, 12, 3, 0, 0, 26651, 96, }, /* 1005 */
+ { 69, 15, 12, 0, 0, 10267, 68, }, /* 1006 */
+ { 81, 7, 12, 0, 0, 18432, 82, }, /* 1007 */
+ { 81, 15, 12, 0, 0, 18432, 68, }, /* 1008 */
+ { 82, 7, 12, 0, 0, 18432, 82, }, /* 1009 */
+ { 82, 14, 12, 0, 0, 18432, 82, }, /* 1010 */
+ { 53, 7, 12, 0, 0, 18432, 82, }, /* 1011 */
+ { 53, 12, 3, 0, 0, 26624, 130, }, /* 1012 */
+ { 85, 7, 12, 0, 0, 18432, 82, }, /* 1013 */
+ { 85, 21, 12, 0, 0, 18432, 106, }, /* 1014 */
+ { 91, 7, 12, 0, 0, 18432, 82, }, /* 1015 */
+ { 91, 21, 12, 0, 0, 18432, 106, }, /* 1016 */
+ { 91, 14, 12, 0, 0, 18432, 82, }, /* 1017 */
+ { 83, 9, 12, 0, 40, 18432, 74, }, /* 1018 */
+ { 83, 5, 12, 0, -40, 18432, 76, }, /* 1019 */
+ { 86, 7, 12, 0, 0, 18432, 82, }, /* 1020 */
+ { 87, 7, 12, 0, 0, 18432, 82, }, /* 1021 */
+ { 87, 13, 12, 0, 0, 18432, 138, }, /* 1022 */
+ { 145, 9, 12, 0, 40, 18432, 74, }, /* 1023 */
+ { 145, 5, 12, 0, -40, 18432, 76, }, /* 1024 */
+ { 127, 7, 12, 0, 0, 18432, 82, }, /* 1025 */
+ { 125, 7, 12, 0, 0, 18432, 82, }, /* 1026 */
+ { 125, 21, 12, 0, 0, 18432, 68, }, /* 1027 */
+ { 161, 9, 12, 0, 39, 18432, 74, }, /* 1028 */
+ { 161, 5, 12, 0, -39, 18432, 76, }, /* 1029 */
+ { 49, 7, 12, 0, 0, 18432, 82, }, /* 1030 */
+ { 0, 6, 12, 0, 0, 18432, 94, }, /* 1031 */
+ { 32, 7, 12, 0, 0, 34816, 82, }, /* 1032 */
+ { 114, 7, 12, 0, 0, 34816, 82, }, /* 1033 */
+ { 114, 21, 12, 0, 0, 34816, 106, }, /* 1034 */
+ { 114, 15, 12, 0, 0, 34816, 68, }, /* 1035 */
+ { 133, 7, 12, 0, 0, 34816, 82, }, /* 1036 */
+ { 133, 26, 12, 0, 0, 34816, 68, }, /* 1037 */
+ { 133, 15, 12, 0, 0, 34816, 68, }, /* 1038 */
+ { 132, 7, 12, 0, 0, 34816, 82, }, /* 1039 */
+ { 132, 15, 12, 0, 0, 34816, 68, }, /* 1040 */
+ { 139, 7, 12, 0, 0, 34816, 82, }, /* 1041 */
+ { 139, 15, 12, 0, 0, 34816, 68, }, /* 1042 */
+ { 95, 7, 12, 0, 0, 34816, 82, }, /* 1043 */
+ { 95, 15, 12, 0, 0, 34816, 68, }, /* 1044 */
+ { 95, 21, 12, 0, 0, 28672, 106, }, /* 1045 */
+ { 104, 7, 12, 0, 0, 34816, 82, }, /* 1046 */
+ { 104, 21, 12, 0, 0, 34816, 68, }, /* 1047 */
+ { 122, 7, 12, 0, 0, 34816, 82, }, /* 1048 */
+ { 121, 7, 12, 0, 0, 34816, 82, }, /* 1049 */
+ { 121, 15, 12, 0, 0, 34816, 68, }, /* 1050 */
+ { 92, 7, 12, 0, 0, 34816, 82, }, /* 1051 */
+ { 92, 12, 3, 0, 0, 26624, 130, }, /* 1052 */
+ { 92, 12, 3, 0, 0, 26624, 102, }, /* 1053 */
+ { 92, 12, 3, 0, 0, 26624, 184, }, /* 1054 */
+ { 92, 15, 12, 0, 0, 34816, 68, }, /* 1055 */
+ { 92, 21, 12, 0, 0, 34816, 68, }, /* 1056 */
+ { 92, 21, 12, 0, 0, 34816, 124, }, /* 1057 */
+ { 115, 7, 12, 0, 0, 34816, 82, }, /* 1058 */
+ { 115, 15, 12, 0, 0, 34816, 68, }, /* 1059 */
+ { 115, 21, 12, 0, 0, 34816, 68, }, /* 1060 */
+ { 131, 7, 12, 0, 0, 34816, 82, }, /* 1061 */
+ { 131, 15, 12, 0, 0, 34816, 68, }, /* 1062 */
+ { 51, 7, 12, 0, 0, 34816, 82, }, /* 1063 */
+ { 51, 26, 12, 0, 0, 34816, 68, }, /* 1064 */
+ { 51, 12, 3, 0, 0, 26624, 96, }, /* 1065 */
+ { 51, 15, 12, 0, 0, 34816, 68, }, /* 1066 */
+ { 51, 21, 12, 0, 0, 34816, 106, }, /* 1067 */
+ { 51, 21, 12, 0, 0, 34918, 106, }, /* 1068 */
+ { 51, 21, 12, 0, 0, 34816, 68, }, /* 1069 */
+ { 108, 7, 12, 0, 0, 34816, 82, }, /* 1070 */
+ { 108, 21, 12, 0, 0, 28672, 68, }, /* 1071 */
+ { 108, 21, 12, 0, 0, 28672, 106, }, /* 1072 */
+ { 116, 7, 12, 0, 0, 34816, 82, }, /* 1073 */
+ { 116, 15, 12, 0, 0, 34816, 68, }, /* 1074 */
+ { 117, 7, 12, 0, 0, 34816, 82, }, /* 1075 */
+ { 117, 15, 12, 0, 0, 34816, 68, }, /* 1076 */
+ { 54, 7, 12, 0, 0, 34816, 82, }, /* 1077 */
+ { 54, 21, 12, 0, 0, 34816, 106, }, /* 1078 */
+ { 54, 15, 12, 0, 0, 34816, 68, }, /* 1079 */
+ { 118, 7, 12, 0, 0, 34816, 82, }, /* 1080 */
+ { 140, 9, 12, 0, 64, 34816, 74, }, /* 1081 */
+ { 140, 5, 12, 0, -64, 34816, 76, }, /* 1082 */
+ { 140, 15, 12, 0, 0, 34816, 68, }, /* 1083 */
+ { 62, 7, 12, 0, 0, 0, 82, }, /* 1084 */
+ { 62, 7, 12, 0, 0, 0, 294, }, /* 1085 */
+ { 62, 12, 3, 0, 0, 26624, 128, }, /* 1086 */
+ { 62, 13, 12, 0, 0, 2048, 138, }, /* 1087 */
+ { 3, 15, 12, 0, 0, 2048, 68, }, /* 1088 */
+ { 65, 7, 12, 0, 0, 34816, 82, }, /* 1089 */
+ { 65, 12, 3, 0, 0, 26624, 130, }, /* 1090 */
+ { 65, 17, 12, 0, 0, 34816, 126, }, /* 1091 */
+ { 152, 7, 12, 0, 0, 34816, 82, }, /* 1092 */
+ { 152, 15, 12, 0, 0, 34816, 68, }, /* 1093 */
+ { 63, 7, 12, 0, 0, 0, 82, }, /* 1094 */
+ { 63, 12, 3, 0, 0, 26624, 96, }, /* 1095 */
+ { 63, 15, 12, 0, 0, 0, 68, }, /* 1096 */
+ { 63, 21, 12, 0, 0, 0, 124, }, /* 1097 */
+ { 67, 7, 12, 0, 0, 34816, 82, }, /* 1098 */
+ { 67, 12, 3, 0, 0, 26624, 96, }, /* 1099 */
+ { 67, 21, 12, 0, 0, 34816, 124, }, /* 1100 */
+ { 156, 7, 12, 0, 0, 34816, 82, }, /* 1101 */
+ { 156, 15, 12, 0, 0, 34816, 68, }, /* 1102 */
+ { 153, 7, 12, 0, 0, 34816, 82, }, /* 1103 */
+ { 120, 10, 5, 0, 0, 18432, 144, }, /* 1104 */
+ { 120, 12, 3, 0, 0, 26624, 130, }, /* 1105 */
+ { 120, 7, 12, 0, 0, 18432, 82, }, /* 1106 */
+ { 120, 12, 3, 0, 0, 26624, 146, }, /* 1107 */
+ { 120, 21, 12, 0, 0, 18432, 124, }, /* 1108 */
+ { 120, 21, 12, 0, 0, 18432, 106, }, /* 1109 */
+ { 120, 15, 12, 0, 0, 28672, 68, }, /* 1110 */
+ { 120, 13, 12, 0, 0, 18432, 138, }, /* 1111 */
+ { 120, 12, 3, 0, 0, 26624, 184, }, /* 1112 */
+ { 41, 12, 3, 0, 0, 26624, 130, }, /* 1113 */
+ { 41, 10, 5, 0, 0, 18432, 144, }, /* 1114 */
+ { 41, 7, 12, 0, 0, 18432, 82, }, /* 1115 */
+ { 41, 12, 3, 0, 0, 26624, 146, }, /* 1116 */
+ { 41, 12, 3, 0, 0, 26624, 96, }, /* 1117 */
+ { 41, 21, 12, 0, 0, 18432, 68, }, /* 1118 */
+ { 41, 1, 4, 0, 0, 18432, 132, }, /* 1119 */
+ { 41, 21, 12, 0, 0, 18432, 124, }, /* 1120 */
+ { 124, 7, 12, 0, 0, 18432, 82, }, /* 1121 */
+ { 124, 13, 12, 0, 0, 18432, 138, }, /* 1122 */
+ { 43, 12, 3, 0, 0, 26624, 130, }, /* 1123 */
+ { 43, 7, 12, 0, 0, 18432, 82, }, /* 1124 */
+ { 43, 10, 5, 0, 0, 18432, 144, }, /* 1125 */
+ { 43, 12, 3, 0, 0, 26624, 146, }, /* 1126 */
+ { 43, 13, 12, 0, 0, 18432, 138, }, /* 1127 */
+ { 43, 21, 12, 0, 0, 18432, 68, }, /* 1128 */
+ { 43, 21, 12, 0, 0, 18432, 124, }, /* 1129 */
+ { 50, 7, 12, 0, 0, 18432, 82, }, /* 1130 */
+ { 50, 12, 3, 0, 0, 26624, 96, }, /* 1131 */
+ { 50, 21, 12, 0, 0, 18432, 68, }, /* 1132 */
+ { 44, 12, 3, 0, 0, 26624, 130, }, /* 1133 */
+ { 44, 10, 5, 0, 0, 18432, 144, }, /* 1134 */
+ { 44, 7, 12, 0, 0, 18432, 82, }, /* 1135 */
+ { 44, 10, 5, 0, 0, 18432, 174, }, /* 1136 */
+ { 44, 7, 4, 0, 0, 18432, 82, }, /* 1137 */
+ { 44, 21, 12, 0, 0, 18432, 124, }, /* 1138 */
+ { 44, 21, 12, 0, 0, 18432, 68, }, /* 1139 */
+ { 44, 12, 3, 0, 0, 26624, 102, }, /* 1140 */
+ { 44, 12, 3, 0, 0, 26624, 96, }, /* 1141 */
+ { 44, 13, 12, 0, 0, 18432, 138, }, /* 1142 */
+ { 15, 15, 12, 0, 0, 18432, 68, }, /* 1143 */
+ { 48, 7, 12, 0, 0, 18432, 82, }, /* 1144 */
+ { 48, 10, 5, 0, 0, 18432, 144, }, /* 1145 */
+ { 48, 12, 3, 0, 0, 26624, 130, }, /* 1146 */
+ { 48, 10, 5, 0, 0, 18432, 174, }, /* 1147 */
+ { 48, 12, 3, 0, 0, 26624, 96, }, /* 1148 */
+ { 48, 21, 12, 0, 0, 18432, 124, }, /* 1149 */
+ { 48, 21, 12, 0, 0, 18432, 106, }, /* 1150 */
+ { 48, 21, 12, 0, 0, 18432, 68, }, /* 1151 */
+ { 57, 7, 12, 0, 0, 18432, 82, }, /* 1152 */
+ { 57, 21, 12, 0, 0, 18432, 124, }, /* 1153 */
+ { 55, 7, 12, 0, 0, 18432, 82, }, /* 1154 */
+ { 55, 12, 3, 0, 0, 26624, 130, }, /* 1155 */
+ { 55, 10, 5, 0, 0, 18432, 144, }, /* 1156 */
+ { 55, 12, 3, 0, 0, 26624, 96, }, /* 1157 */
+ { 55, 12, 3, 0, 0, 26624, 146, }, /* 1158 */
+ { 55, 13, 12, 0, 0, 18432, 138, }, /* 1159 */
+ { 47, 12, 3, 0, 0, 26624, 130, }, /* 1160 */
+ { 47, 12, 3, 0, 0, 26705, 130, }, /* 1161 */
+ { 47, 10, 5, 0, 0, 18432, 144, }, /* 1162 */
+ { 47, 10, 5, 0, 0, 18513, 144, }, /* 1163 */
+ { 47, 7, 12, 0, 0, 18432, 82, }, /* 1164 */
+ { 84, 12, 3, 0, 0, 26705, 102, }, /* 1165 */
+ { 47, 12, 3, 0, 0, 26705, 96, }, /* 1166 */
+ { 47, 10, 3, 0, 0, 18432, 148, }, /* 1167 */
+ { 47, 10, 5, 0, 0, 18432, 174, }, /* 1168 */
+ { 47, 7, 12, 0, 0, 18432, 324, }, /* 1169 */
+ { 47, 12, 3, 0, 0, 26624, 96, }, /* 1170 */
+ { 144, 7, 12, 0, 0, 18432, 82, }, /* 1171 */
+ { 144, 10, 5, 0, 0, 18432, 144, }, /* 1172 */
+ { 144, 12, 3, 0, 0, 26624, 130, }, /* 1173 */
+ { 144, 12, 3, 0, 0, 26624, 146, }, /* 1174 */
+ { 144, 12, 3, 0, 0, 26624, 96, }, /* 1175 */
+ { 144, 21, 12, 0, 0, 18432, 124, }, /* 1176 */
+ { 144, 21, 12, 0, 0, 18432, 106, }, /* 1177 */
+ { 144, 21, 12, 0, 0, 18432, 68, }, /* 1178 */
+ { 144, 13, 12, 0, 0, 18432, 138, }, /* 1179 */
+ { 144, 12, 3, 0, 0, 26624, 102, }, /* 1180 */
+ { 56, 7, 12, 0, 0, 18432, 82, }, /* 1181 */
+ { 56, 10, 3, 0, 0, 18432, 148, }, /* 1182 */
+ { 56, 10, 5, 0, 0, 18432, 144, }, /* 1183 */
+ { 56, 12, 3, 0, 0, 26624, 130, }, /* 1184 */
+ { 56, 12, 3, 0, 0, 26624, 146, }, /* 1185 */
+ { 56, 12, 3, 0, 0, 26624, 96, }, /* 1186 */
+ { 56, 21, 12, 0, 0, 18432, 68, }, /* 1187 */
+ { 56, 13, 12, 0, 0, 18432, 138, }, /* 1188 */
+ { 135, 7, 12, 0, 0, 18432, 82, }, /* 1189 */
+ { 135, 10, 3, 0, 0, 18432, 148, }, /* 1190 */
+ { 135, 10, 5, 0, 0, 18432, 144, }, /* 1191 */
+ { 135, 12, 3, 0, 0, 26624, 130, }, /* 1192 */
+ { 135, 12, 3, 0, 0, 26624, 146, }, /* 1193 */
+ { 135, 12, 3, 0, 0, 26624, 96, }, /* 1194 */
+ { 135, 21, 12, 0, 0, 18432, 68, }, /* 1195 */
+ { 135, 21, 12, 0, 0, 18432, 124, }, /* 1196 */
+ { 135, 21, 12, 0, 0, 18432, 106, }, /* 1197 */
+ { 135, 21, 12, 0, 0, 18432, 178, }, /* 1198 */
+ { 52, 7, 12, 0, 0, 18432, 82, }, /* 1199 */
+ { 52, 10, 5, 0, 0, 18432, 144, }, /* 1200 */
+ { 52, 12, 3, 0, 0, 26624, 130, }, /* 1201 */
+ { 52, 12, 3, 0, 0, 26624, 146, }, /* 1202 */
+ { 52, 21, 12, 0, 0, 18432, 124, }, /* 1203 */
+ { 52, 21, 12, 0, 0, 18432, 68, }, /* 1204 */
+ { 52, 13, 12, 0, 0, 18432, 138, }, /* 1205 */
+ { 45, 7, 12, 0, 0, 18432, 82, }, /* 1206 */
+ { 45, 12, 3, 0, 0, 26624, 130, }, /* 1207 */
+ { 45, 10, 5, 0, 0, 18432, 144, }, /* 1208 */
+ { 45, 10, 5, 0, 0, 18432, 174, }, /* 1209 */
+ { 45, 12, 3, 0, 0, 26624, 96, }, /* 1210 */
+ { 45, 21, 12, 0, 0, 18432, 68, }, /* 1211 */
+ { 45, 13, 12, 0, 0, 18432, 138, }, /* 1212 */
+ { 137, 7, 12, 0, 0, 18432, 82, }, /* 1213 */
+ { 137, 12, 3, 0, 0, 26624, 130, }, /* 1214 */
+ { 137, 10, 12, 0, 0, 18432, 144, }, /* 1215 */
+ { 137, 10, 5, 0, 0, 18432, 144, }, /* 1216 */
+ { 137, 12, 3, 0, 0, 26624, 146, }, /* 1217 */
+ { 137, 13, 12, 0, 0, 18432, 138, }, /* 1218 */
+ { 137, 15, 12, 0, 0, 18432, 68, }, /* 1219 */
+ { 137, 21, 12, 0, 0, 18432, 124, }, /* 1220 */
+ { 137, 26, 12, 0, 0, 18432, 68, }, /* 1221 */
+ { 60, 7, 12, 0, 0, 18432, 82, }, /* 1222 */
+ { 60, 10, 5, 0, 0, 18432, 144, }, /* 1223 */
+ { 60, 12, 3, 0, 0, 26624, 130, }, /* 1224 */
+ { 60, 12, 3, 0, 0, 26624, 146, }, /* 1225 */
+ { 60, 12, 3, 0, 0, 26624, 96, }, /* 1226 */
+ { 60, 21, 12, 0, 0, 18432, 68, }, /* 1227 */
+ { 136, 9, 12, 0, 32, 18432, 74, }, /* 1228 */
+ { 136, 5, 12, 0, -32, 18432, 76, }, /* 1229 */
+ { 136, 13, 12, 0, 0, 18432, 138, }, /* 1230 */
+ { 136, 15, 12, 0, 0, 18432, 68, }, /* 1231 */
+ { 136, 7, 12, 0, 0, 18432, 82, }, /* 1232 */
+ { 157, 7, 12, 0, 0, 18432, 82, }, /* 1233 */
+ { 157, 10, 3, 0, 0, 18432, 148, }, /* 1234 */
+ { 157, 10, 5, 0, 0, 18432, 144, }, /* 1235 */
+ { 157, 12, 3, 0, 0, 26624, 130, }, /* 1236 */
+ { 157, 10, 5, 0, 0, 18432, 174, }, /* 1237 */
+ { 157, 12, 3, 0, 0, 26624, 146, }, /* 1238 */
+ { 157, 7, 4, 0, 0, 18432, 82, }, /* 1239 */
+ { 157, 12, 3, 0, 0, 26624, 96, }, /* 1240 */
+ { 157, 21, 12, 0, 0, 18432, 124, }, /* 1241 */
+ { 157, 21, 12, 0, 0, 18432, 68, }, /* 1242 */
+ { 157, 13, 12, 0, 0, 18432, 138, }, /* 1243 */
+ { 64, 7, 12, 0, 0, 18432, 82, }, /* 1244 */
+ { 64, 10, 5, 0, 0, 18432, 144, }, /* 1245 */
+ { 64, 12, 3, 0, 0, 26624, 130, }, /* 1246 */
+ { 64, 12, 3, 0, 0, 26624, 146, }, /* 1247 */
+ { 64, 21, 12, 0, 0, 18432, 68, }, /* 1248 */
+ { 149, 7, 12, 0, 0, 18432, 82, }, /* 1249 */
+ { 149, 12, 3, 0, 0, 26624, 130, }, /* 1250 */
+ { 149, 12, 3, 0, 0, 18432, 130, }, /* 1251 */
+ { 149, 12, 3, 0, 0, 26624, 102, }, /* 1252 */
+ { 149, 12, 3, 0, 0, 26624, 146, }, /* 1253 */
+ { 149, 10, 5, 0, 0, 18432, 144, }, /* 1254 */
+ { 149, 7, 4, 0, 0, 18432, 82, }, /* 1255 */
+ { 149, 21, 12, 0, 0, 18432, 68, }, /* 1256 */
+ { 149, 21, 12, 0, 0, 18432, 124, }, /* 1257 */
+ { 148, 7, 12, 0, 0, 18432, 82, }, /* 1258 */
+ { 148, 12, 3, 0, 0, 26624, 130, }, /* 1259 */
+ { 148, 10, 5, 0, 0, 18432, 144, }, /* 1260 */
+ { 148, 7, 4, 0, 0, 18432, 82, }, /* 1261 */
+ { 148, 12, 3, 0, 0, 26624, 326, }, /* 1262 */
+ { 148, 12, 3, 0, 0, 26624, 146, }, /* 1263 */
+ { 148, 21, 12, 0, 0, 18432, 68, }, /* 1264 */
+ { 148, 21, 12, 0, 0, 18432, 124, }, /* 1265 */
+ { 148, 21, 12, 0, 0, 18432, 106, }, /* 1266 */
+ { 134, 7, 12, 0, 0, 18432, 82, }, /* 1267 */
+ { 142, 7, 12, 0, 0, 18432, 82, }, /* 1268 */
+ { 142, 10, 5, 0, 0, 18432, 144, }, /* 1269 */
+ { 142, 12, 3, 0, 0, 26624, 130, }, /* 1270 */
+ { 142, 12, 3, 0, 0, 18432, 146, }, /* 1271 */
+ { 142, 21, 12, 0, 0, 18432, 124, }, /* 1272 */
+ { 142, 21, 12, 0, 0, 18432, 106, }, /* 1273 */
+ { 142, 21, 12, 0, 0, 18432, 68, }, /* 1274 */
+ { 142, 13, 12, 0, 0, 18432, 138, }, /* 1275 */
+ { 142, 15, 12, 0, 0, 18432, 68, }, /* 1276 */
+ { 143, 21, 12, 0, 0, 18432, 68, }, /* 1277 */
+ { 143, 21, 12, 0, 0, 18432, 106, }, /* 1278 */
+ { 143, 7, 12, 0, 0, 18432, 82, }, /* 1279 */
+ { 143, 12, 3, 0, 0, 26624, 130, }, /* 1280 */
+ { 143, 10, 5, 0, 0, 18432, 144, }, /* 1281 */
+ { 59, 7, 12, 0, 0, 18432, 82, }, /* 1282 */
+ { 59, 12, 3, 0, 0, 26624, 130, }, /* 1283 */
+ { 59, 12, 3, 0, 0, 26624, 96, }, /* 1284 */
+ { 59, 12, 3, 0, 0, 26624, 146, }, /* 1285 */
+ { 59, 7, 4, 0, 0, 18432, 82, }, /* 1286 */
+ { 59, 13, 12, 0, 0, 18432, 138, }, /* 1287 */
+ { 61, 7, 12, 0, 0, 18432, 82, }, /* 1288 */
+ { 61, 10, 5, 0, 0, 18432, 144, }, /* 1289 */
+ { 61, 12, 3, 0, 0, 26624, 130, }, /* 1290 */
+ { 61, 12, 3, 0, 0, 26624, 146, }, /* 1291 */
+ { 61, 13, 12, 0, 0, 18432, 138, }, /* 1292 */
+ { 150, 7, 12, 0, 0, 18432, 82, }, /* 1293 */
+ { 150, 12, 3, 0, 0, 26624, 130, }, /* 1294 */
+ { 150, 10, 5, 0, 0, 18432, 144, }, /* 1295 */
+ { 150, 21, 12, 0, 0, 18432, 124, }, /* 1296 */
+ { 162, 12, 3, 0, 0, 26624, 130, }, /* 1297 */
+ { 162, 7, 4, 0, 0, 18432, 82, }, /* 1298 */
+ { 162, 10, 5, 0, 0, 18432, 144, }, /* 1299 */
+ { 162, 7, 12, 0, 0, 18432, 82, }, /* 1300 */
+ { 162, 10, 5, 0, 0, 18432, 176, }, /* 1301 */
+ { 162, 12, 3, 0, 0, 26624, 184, }, /* 1302 */
+ { 162, 21, 12, 0, 0, 18432, 124, }, /* 1303 */
+ { 162, 21, 12, 0, 0, 18432, 68, }, /* 1304 */
+ { 162, 13, 12, 0, 0, 18432, 138, }, /* 1305 */
+ { 11, 15, 12, 0, 0, 18432, 68, }, /* 1306 */
+ { 11, 21, 12, 0, 0, 18432, 68, }, /* 1307 */
+ { 94, 7, 12, 0, 0, 18432, 82, }, /* 1308 */
+ { 94, 14, 12, 0, 0, 18432, 82, }, /* 1309 */
+ { 94, 21, 12, 0, 0, 18432, 106, }, /* 1310 */
+ { 66, 7, 12, 0, 0, 18432, 82, }, /* 1311 */
+ { 66, 21, 12, 0, 0, 18432, 68, }, /* 1312 */
+ { 109, 7, 12, 0, 0, 18432, 82, }, /* 1313 */
+ { 109, 1, 2, 0, 0, 18432, 322, }, /* 1314 */
+ { 109, 12, 3, 0, 0, 26624, 102, }, /* 1315 */
+ { 109, 12, 3, 0, 0, 26624, 96, }, /* 1316 */
+ { 138, 7, 12, 0, 0, 18432, 82, }, /* 1317 */
+ { 130, 7, 12, 0, 0, 18432, 82, }, /* 1318 */
+ { 130, 13, 12, 0, 0, 18432, 138, }, /* 1319 */
+ { 130, 21, 12, 0, 0, 18432, 124, }, /* 1320 */
+ { 159, 7, 12, 0, 0, 18432, 82, }, /* 1321 */
+ { 159, 13, 12, 0, 0, 18432, 138, }, /* 1322 */
+ { 126, 7, 12, 0, 0, 18432, 82, }, /* 1323 */
+ { 126, 12, 3, 0, 0, 26624, 96, }, /* 1324 */
+ { 126, 21, 12, 0, 0, 18432, 124, }, /* 1325 */
+ { 128, 7, 12, 0, 0, 18432, 82, }, /* 1326 */
+ { 128, 12, 3, 0, 0, 26624, 96, }, /* 1327 */
+ { 128, 21, 12, 0, 0, 18432, 124, }, /* 1328 */
+ { 128, 21, 12, 0, 0, 18432, 106, }, /* 1329 */
+ { 128, 21, 12, 0, 0, 18432, 68, }, /* 1330 */
+ { 128, 26, 12, 0, 0, 18432, 68, }, /* 1331 */
+ { 128, 6, 12, 0, 0, 18432, 142, }, /* 1332 */
+ { 128, 6, 12, 0, 0, 18432, 136, }, /* 1333 */
+ { 128, 13, 12, 0, 0, 18432, 138, }, /* 1334 */
+ { 128, 15, 12, 0, 0, 18432, 68, }, /* 1335 */
+ { 151, 9, 12, 0, 32, 18432, 74, }, /* 1336 */
+ { 151, 5, 12, 0, -32, 18432, 76, }, /* 1337 */
+ { 151, 15, 12, 0, 0, 18432, 68, }, /* 1338 */
+ { 151, 21, 12, 0, 0, 18432, 106, }, /* 1339 */
+ { 151, 21, 12, 0, 0, 18432, 124, }, /* 1340 */
+ { 151, 21, 12, 0, 0, 18432, 68, }, /* 1341 */
+ { 123, 7, 12, 0, 0, 18432, 82, }, /* 1342 */
+ { 123, 12, 3, 0, 0, 26624, 130, }, /* 1343 */
+ { 123, 10, 5, 0, 0, 18432, 144, }, /* 1344 */
+ { 123, 12, 3, 0, 0, 26624, 128, }, /* 1345 */
+ { 123, 6, 12, 0, 0, 18432, 92, }, /* 1346 */
+ { 146, 6, 12, 0, 0, 18432, 136, }, /* 1347 */
+ { 147, 6, 12, 0, 0, 18432, 136, }, /* 1348 */
+ { 23, 21, 12, 0, 0, 28672, 68, }, /* 1349 */
+ { 158, 12, 3, 0, 0, 26624, 328, }, /* 1350 */
+ { 23, 10, 5, 0, 0, 18432, 164, }, /* 1351 */
+ { 146, 7, 12, 0, 0, 18432, 284, }, /* 1352 */
+ { 158, 7, 12, 0, 0, 18432, 284, }, /* 1353 */
+ { 21, 6, 12, 0, 0, 18432, 92, }, /* 1354 */
+ { 147, 7, 12, 0, 0, 18432, 284, }, /* 1355 */
+ { 46, 7, 12, 0, 0, 18432, 82, }, /* 1356 */
+ { 46, 26, 12, 0, 0, 18432, 68, }, /* 1357 */
+ { 46, 12, 3, 0, 0, 26624, 102, }, /* 1358 */
+ { 46, 12, 3, 0, 0, 26624, 130, }, /* 1359 */
+ { 46, 21, 12, 0, 0, 18432, 124, }, /* 1360 */
+ { 69, 1, 2, 0, 0, 6153, 66, }, /* 1361 */
+ { 69, 10, 3, 0, 0, 18432, 330, }, /* 1362 */
+ { 69, 10, 5, 0, 0, 18432, 138, }, /* 1363 */
+ { 69, 10, 5, 0, 0, 18432, 160, }, /* 1364 */
+ { 69, 10, 3, 0, 0, 18432, 286, }, /* 1365 */
+ { 1, 12, 3, 0, 0, 26624, 102, }, /* 1366 */
+ { 69, 25, 12, 0, 0, 18432, 118, }, /* 1367 */
+ { 69, 13, 12, 0, 0, 10240, 214, }, /* 1368 */
+ { 141, 26, 12, 0, 0, 18432, 68, }, /* 1369 */
+ { 141, 12, 3, 0, 0, 26624, 102, }, /* 1370 */
+ { 141, 21, 12, 0, 0, 18432, 106, }, /* 1371 */
+ { 141, 21, 12, 0, 0, 18432, 124, }, /* 1372 */
+ { 141, 21, 12, 0, 0, 18432, 68, }, /* 1373 */
+ { 35, 12, 3, 0, 0, 26624, 130, }, /* 1374 */
+ { 2, 6, 12, 0, 0, 18432, 90, }, /* 1375 */
+ { 154, 7, 12, 0, 0, 18432, 82, }, /* 1376 */
+ { 154, 12, 3, 0, 0, 26624, 96, }, /* 1377 */
+ { 154, 6, 12, 0, 0, 18432, 142, }, /* 1378 */
+ { 154, 6, 12, 0, 0, 18432, 136, }, /* 1379 */
+ { 154, 13, 12, 0, 0, 18432, 138, }, /* 1380 */
+ { 154, 26, 12, 0, 0, 18432, 68, }, /* 1381 */
+ { 160, 7, 12, 0, 0, 18432, 82, }, /* 1382 */
+ { 160, 12, 3, 0, 0, 26624, 96, }, /* 1383 */
+ { 155, 7, 12, 0, 0, 18432, 82, }, /* 1384 */
+ { 155, 12, 3, 0, 0, 26624, 96, }, /* 1385 */
+ { 155, 13, 12, 0, 0, 18432, 138, }, /* 1386 */
+ { 155, 23, 12, 0, 0, 14336, 68, }, /* 1387 */
+ { 163, 7, 12, 0, 0, 18432, 82, }, /* 1388 */
+ { 163, 6, 12, 0, 0, 18432, 142, }, /* 1389 */
+ { 163, 12, 3, 0, 0, 26624, 102, }, /* 1390 */
+ { 163, 13, 12, 0, 0, 18432, 138, }, /* 1391 */
+ { 129, 7, 12, 0, 0, 34816, 82, }, /* 1392 */
+ { 129, 15, 12, 0, 0, 34816, 68, }, /* 1393 */
+ { 129, 12, 3, 0, 0, 26624, 96, }, /* 1394 */
+ { 58, 9, 12, 0, 34, 34816, 74, }, /* 1395 */
+ { 58, 5, 12, 0, -34, 34816, 76, }, /* 1396 */
+ { 58, 12, 3, 0, 0, 26624, 150, }, /* 1397 */
+ { 58, 12, 3, 0, 0, 26624, 130, }, /* 1398 */
+ { 58, 12, 3, 0, 0, 26624, 96, }, /* 1399 */
+ { 58, 6, 12, 0, 0, 34816, 142, }, /* 1400 */
+ { 58, 13, 12, 0, 0, 34816, 138, }, /* 1401 */
+ { 58, 21, 12, 0, 0, 34816, 68, }, /* 1402 */
+ { 69, 15, 12, 0, 0, 0, 68, }, /* 1403 */
+ { 69, 26, 12, 0, 0, 0, 68, }, /* 1404 */
+ { 69, 23, 12, 0, 0, 0, 68, }, /* 1405 */
+ { 3, 7, 12, 0, 0, 0, 240, }, /* 1406 */
+ { 69, 26, 14, 0, 0, 28672, 332, }, /* 1407 */
+ { 69, 26, 14, 0, 0, 28672, 334, }, /* 1408 */
+ { 68, 2, 14, 0, 0, 18432, 336, }, /* 1409 */
+ { 69, 26, 12, 0, 0, 18432, 338, }, /* 1410 */
+ { 69, 26, 14, 0, 0, 18432, 340, }, /* 1411 */
+ { 69, 26, 14, 0, 0, 18432, 334, }, /* 1412 */
+ { 69, 26, 11, 0, 0, 18432, 342, }, /* 1413 */
+ { 20, 26, 12, 0, 0, 18432, 68, }, /* 1414 */
+ { 69, 26, 14, 0, 0, 18432, 236, }, /* 1415 */
+ { 69, 26, 14, 0, 0, 18447, 334, }, /* 1416 */
+ { 69, 26, 14, 0, 0, 28672, 344, }, /* 1417 */
+ { 69, 26, 14, 0, 0, 28672, 346, }, /* 1418 */
+ { 69, 24, 3, 0, 0, 28672, 348, }, /* 1419 */
+ { 69, 26, 14, 0, 0, 28672, 350, }, /* 1420 */
+ { 69, 13, 12, 0, 0, 10240, 138, }, /* 1421 */
+ { 69, 1, 3, 0, 0, 6144, 352, }, /* 1422 */
};
const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
@@ -1872,35 +1886,35 @@ const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
142,143,144,145,146,147,148,149,150,151,152,153,154,154,155,156, /* U+10000 */
157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172, /* U+10800 */
173,174,175,176,177,178,179,146,180,181,146,182,183,184,185,146, /* U+11000 */
-186,187,188,189,190,191,146,146,192,193,194,195,146,196,146,197, /* U+11800 */
-198,198,198,198,198,198,198,199,200,198,201,146,146,146,146,146, /* U+12000 */
-146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,202, /* U+12800 */
-203,203,203,203,203,203,203,203,204,146,146,146,146,146,146,146, /* U+13000 */
+186,187,188,189,190,191,192,146,193,194,195,196,146,197,198,199, /* U+11800 */
+200,200,200,200,200,200,200,201,202,200,203,146,146,146,146,146, /* U+12000 */
+146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,204, /* U+12800 */
+205,205,205,205,205,205,205,205,206,146,146,146,146,146,146,146, /* U+13000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+13800 */
-146,146,146,146,146,146,146,146,205,205,205,205,206,146,146,146, /* U+14000 */
+146,146,146,146,146,146,146,146,207,207,207,207,208,146,146,146, /* U+14000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+14800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+15000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+15800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+16000 */
-207,207,207,207,208,209,210,211,146,146,146,146,212,213,214,215, /* U+16800 */
-216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, /* U+17000 */
-216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, /* U+17800 */
-216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,217, /* U+18000 */
-216,216,216,216,216,216,218,218,218,219,220,146,146,146,146,146, /* U+18800 */
+209,209,209,209,210,211,212,213,146,146,146,146,214,215,216,217, /* U+16800 */
+218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, /* U+17000 */
+218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, /* U+17800 */
+218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,219, /* U+18000 */
+218,218,218,218,218,218,220,220,220,221,222,146,146,146,146,146, /* U+18800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+19000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+19800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+1A000 */
-146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,221, /* U+1A800 */
-222,223,224,225,225,226,146,146,146,146,146,146,146,146,146,146, /* U+1B000 */
-146,146,146,146,146,146,146,146,227,228,146,146,146,146,146,146, /* U+1B800 */
+146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,223, /* U+1A800 */
+224,225,226,227,227,228,146,146,146,146,146,146,146,146,146,146, /* U+1B000 */
+146,146,146,146,146,146,146,146,229,230,146,146,146,146,146,146, /* U+1B800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+1C000 */
-146,146,146,146,146,146,146,146,146,146,146,146,146,146,229,230, /* U+1C800 */
-231,232,233,234,235,236,237,146,238,239,240,241,242,243,244,245, /* U+1D000 */
-246,246,246,246,247,248,146,146,146,146,146,146,146,146,249,146, /* U+1D800 */
-250,146,251,146,146,252,146,146,146,146,146,146,146,146,146,253, /* U+1E000 */
-254,255,256,168,168,168,168,168,257,258,259,168,260,261,168,168, /* U+1E800 */
-262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277, /* U+1F000 */
-278,279,280,281,282,283,284,285,267,267,267,267,267,267,267,286, /* U+1F800 */
+146,146,146,146,146,146,146,146,146,146,146,146,146,146,231,232, /* U+1C800 */
+233,234,235,236,237,238,239,146,240,241,242,243,244,245,246,247, /* U+1D000 */
+248,248,248,248,249,250,146,146,146,146,146,146,146,146,251,146, /* U+1D800 */
+252,253,254,146,146,255,146,146,146,256,146,146,146,146,146,257, /* U+1E000 */
+258,259,260,168,168,168,168,168,261,262,263,168,264,265,168,168, /* U+1E800 */
+266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281, /* U+1F000 */
+282,283,284,285,286,287,288,289,271,271,271,271,271,271,271,290, /* U+1F800 */
101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, /* U+20000 */
101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, /* U+20800 */
101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, /* U+21000 */
@@ -1921,23 +1935,23 @@ const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, /* U+28800 */
101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, /* U+29000 */
101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, /* U+29800 */
-101,101,101,101,101,101,101,101,101,101,101,101,101,287,101,101, /* U+2A000 */
+101,101,101,101,101,101,101,101,101,101,101,101,101,291,101,101, /* U+2A000 */
101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, /* U+2A800 */
-101,101,101,101,101,101,101,101,101,101,101,101,101,101,288,101, /* U+2B000 */
-289,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, /* U+2B800 */
+101,101,101,101,101,101,101,101,101,101,101,101,101,101,292,101, /* U+2B000 */
+293,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, /* U+2B800 */
101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, /* U+2C000 */
-101,101,101,101,101,101,101,101,101,101,101,101,101,290,101,101, /* U+2C800 */
+101,101,101,101,101,101,101,101,101,101,101,101,101,294,101,101, /* U+2C800 */
101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, /* U+2D000 */
101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, /* U+2D800 */
101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, /* U+2E000 */
-101,101,101,101,101,101,101,291,146,146,146,146,146,146,146,146, /* U+2E800 */
+101,101,101,101,101,101,101,295,146,146,146,146,146,146,146,146, /* U+2E800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+2F000 */
-129,129,129,129,292,146,146,146,146,146,146,146,146,146,146,293, /* U+2F800 */
+129,129,129,129,296,146,146,146,146,146,146,146,146,146,146,297, /* U+2F800 */
101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, /* U+30000 */
101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, /* U+30800 */
-101,101,101,101,101,101,294,146,146,146,146,146,146,146,146,146, /* U+31000 */
-146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+31800 */
-146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+32000 */
+101,101,101,101,101,101,298,101,101,101,101,101,101,101,101,101, /* U+31000 */
+101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, /* U+31800 */
+101,101,101,101,101,101,101,299,146,146,146,146,146,146,146,146, /* U+32000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+32800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+33000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+33800 */
@@ -1964,7 +1978,7 @@ const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+3E000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+3E800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+3F000 */
-146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,293, /* U+3F800 */
+146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,297, /* U+3F800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+40000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+40800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+41000 */
@@ -1996,7 +2010,7 @@ const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+4E000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+4E800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+4F000 */
-146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,293, /* U+4F800 */
+146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,297, /* U+4F800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+50000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+50800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+51000 */
@@ -2028,7 +2042,7 @@ const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+5E000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+5E800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+5F000 */
-146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,293, /* U+5F800 */
+146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,297, /* U+5F800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+60000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+60800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+61000 */
@@ -2060,7 +2074,7 @@ const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+6E000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+6E800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+6F000 */
-146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,293, /* U+6F800 */
+146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,297, /* U+6F800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+70000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+70800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+71000 */
@@ -2092,7 +2106,7 @@ const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+7E000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+7E800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+7F000 */
-146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,293, /* U+7F800 */
+146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,297, /* U+7F800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+80000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+80800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+81000 */
@@ -2124,7 +2138,7 @@ const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+8E000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+8E800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+8F000 */
-146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,293, /* U+8F800 */
+146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,297, /* U+8F800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+90000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+90800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+91000 */
@@ -2156,7 +2170,7 @@ const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+9E000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+9E800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+9F000 */
-146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,293, /* U+9F800 */
+146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,297, /* U+9F800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+A0000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+A0800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+A1000 */
@@ -2188,7 +2202,7 @@ const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+AE000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+AE800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+AF000 */
-146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,293, /* U+AF800 */
+146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,297, /* U+AF800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+B0000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+B0800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+B1000 */
@@ -2220,7 +2234,7 @@ const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+BE000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+BE800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+BF000 */
-146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,293, /* U+BF800 */
+146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,297, /* U+BF800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+C0000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+C0800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+C1000 */
@@ -2252,7 +2266,7 @@ const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+CE000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+CE800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+CF000 */
-146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,293, /* U+CF800 */
+146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,297, /* U+CF800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+D0000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+D0800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+D1000 */
@@ -2284,9 +2298,9 @@ const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+DE000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+DE800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+DF000 */
-146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,293, /* U+DF800 */
-295,296,297,298,296,296,296,296,296,296,296,296,296,296,296,296, /* U+E0000 */
-296,296,296,296,296,296,296,296,296,296,296,296,296,296,296,296, /* U+E0800 */
+146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,297, /* U+DF800 */
+300,301,302,303,301,301,301,301,301,301,301,301,301,301,301,301, /* U+E0000 */
+301,301,301,301,301,301,301,301,301,301,301,301,301,301,301,301, /* U+E0800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+E1000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+E1800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+E2000 */
@@ -2316,7 +2330,7 @@ const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+EE000 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+EE800 */
146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, /* U+EF000 */
-146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,293, /* U+EF800 */
+146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,297, /* U+EF800 */
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, /* U+F0000 */
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, /* U+F0800 */
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, /* U+F1000 */
@@ -2348,7 +2362,7 @@ const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, /* U+FE000 */
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, /* U+FE800 */
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, /* U+FF000 */
-128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,299, /* U+FF800 */
+128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,304, /* U+FF800 */
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, /* U+100000 */
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, /* U+100800 */
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, /* U+101000 */
@@ -2380,10 +2394,10 @@ const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, /* U+10E000 */
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, /* U+10E800 */
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, /* U+10F000 */
-128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,299, /* U+10F800 */
+128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,304, /* U+10F800 */
};
-const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
+const uint16_t PRIV(ucd_stage2)[] = { /* 78080 bytes, block = 128 */
/* block 0 */
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 3, 4, 0, 0,
@@ -2626,62 +2640,62 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
388,388,388,389,390,390,390,390,390,391,390,163,163,163,163,163,
/* block 24 */
-392,393,393,393,394,395,395,395,395,395,395,395,395,163,395,395,
-395,163,395,395,395,395,395,395,395,395,395,395,395,395,395,395,
-395,395,395,395,395,395,395,395,395,163,395,395,395,395,395,395,
-395,395,395,395,395,395,395,395,395,395,163,163,396,395,392,392,
-392,393,393,393,393,163,392,392,392,163,392,392,392,397,163,163,
-163,163,163,163,163,392,392,163,395,395,395,163,163,395,163,163,
-395,395,392,392,163,163,398,398,398,398,398,398,398,398,398,398,
-163,163,163,163,163,163,163,399,400,400,400,400,400,400,400,401,
+392,393,393,393,392,394,394,394,394,394,394,394,394,163,394,394,
+394,163,394,394,394,394,394,394,394,394,394,394,394,394,394,394,
+394,394,394,394,394,394,394,394,394,163,394,394,394,394,394,394,
+394,394,394,394,394,394,394,394,394,394,163,163,395,394,392,392,
+392,393,393,393,393,163,392,392,392,163,392,392,392,396,163,163,
+163,163,163,163,163,392,392,163,394,394,394,163,163,394,163,163,
+394,394,392,392,163,163,397,397,397,397,397,397,397,397,397,397,
+163,163,163,163,163,163,163,398,399,399,399,399,399,399,399,400,
/* block 25 */
-402,403,404,404,405,402,402,402,402,402,402,402,402,163,402,402,
-402,163,402,402,402,402,402,402,402,402,402,402,402,402,402,402,
-402,402,402,402,402,402,402,402,402,163,402,402,402,402,402,402,
-402,402,402,402,163,402,402,402,402,402,163,163,406,402,404,407,
-404,404,408,404,404,163,407,404,404,163,404,404,403,409,163,163,
-163,163,163,163,163,408,408,163,163,163,163,163,163,402,402,163,
-402,402,403,403,163,163,410,410,410,410,410,410,410,410,410,410,
-163,402,402,163,163,163,163,163,163,163,163,163,163,163,163,163,
+401,402,403,403,404,401,401,401,401,401,401,401,401,163,401,401,
+401,163,401,401,401,401,401,401,401,401,401,401,401,401,401,401,
+401,401,401,401,401,401,401,401,401,163,401,401,401,401,401,401,
+401,401,401,401,163,401,401,401,401,401,163,163,405,401,403,406,
+403,403,407,403,403,163,406,403,403,163,403,403,402,408,163,163,
+163,163,163,163,163,407,407,163,163,163,163,163,163,401,401,163,
+401,401,402,402,163,163,409,409,409,409,409,409,409,409,409,409,
+163,401,401,403,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 26 */
-411,411,412,412,413,413,413,413,413,413,413,413,413,163,413,413,
-413,163,413,413,413,413,413,413,413,413,413,413,413,413,413,413,
-413,413,413,413,413,413,413,413,413,413,413,413,413,413,413,413,
-413,413,413,413,413,413,413,413,413,413,413,414,414,413,415,412,
-412,411,411,411,411,163,412,412,412,163,412,412,412,414,416,417,
-163,163,163,163,413,413,413,415,418,418,418,418,418,418,418,413,
-413,413,411,411,163,163,419,419,419,419,419,419,419,419,419,419,
-418,418,418,418,418,418,418,418,418,417,413,413,413,413,413,413,
+410,410,411,411,412,412,412,412,412,412,412,412,412,163,412,412,
+412,163,412,412,412,412,412,412,412,412,412,412,412,412,412,412,
+412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,
+412,412,412,412,412,412,412,412,412,412,412,413,413,412,414,411,
+411,410,410,410,410,163,411,411,411,163,411,411,411,413,415,416,
+163,163,163,163,412,412,412,414,417,417,417,417,417,417,417,412,
+412,412,410,410,163,163,418,418,418,418,418,418,418,418,418,418,
+417,417,417,417,417,417,417,417,417,416,412,412,412,412,412,412,
/* block 27 */
-163,420,421,421,163,422,422,422,422,422,422,422,422,422,422,422,
-422,422,422,422,422,422,422,163,163,163,422,422,422,422,422,422,
-422,422,422,422,422,422,422,422,422,422,422,422,422,422,422,422,
-422,422,163,422,422,422,422,422,422,422,422,422,163,422,163,163,
-422,422,422,422,422,422,422,163,163,163,423,163,163,163,163,424,
-421,421,420,420,420,163,420,163,421,421,421,421,421,421,421,424,
-163,163,163,163,163,163,425,425,425,425,425,425,425,425,425,425,
-163,163,421,421,426,163,163,163,163,163,163,163,163,163,163,163,
+163,419,420,420,163,421,421,421,421,421,421,421,421,421,421,421,
+421,421,421,421,421,421,421,163,163,163,421,421,421,421,421,421,
+421,421,421,421,421,421,421,421,421,421,421,421,421,421,421,421,
+421,421,163,421,421,421,421,421,421,421,421,421,163,421,163,163,
+421,421,421,421,421,421,421,163,163,163,422,163,163,163,163,423,
+420,420,419,419,419,163,419,163,420,420,420,420,420,420,420,423,
+163,163,163,163,163,163,424,424,424,424,424,424,424,424,424,424,
+163,163,420,420,425,163,163,163,163,163,163,163,163,163,163,163,
/* block 28 */
-163,427,427,427,427,427,427,427,427,427,427,427,427,427,427,427,
-427,427,427,427,427,427,427,427,427,427,427,427,427,427,427,427,
-427,427,427,427,427,427,427,427,427,427,427,427,427,427,427,427,
-427,428,427,429,428,428,428,428,428,428,430,163,163,163,163,431,
-432,432,432,432,432,427,433,434,434,434,434,434,434,428,434,435,
-436,436,436,436,436,436,436,436,436,436,437,437,163,163,163,163,
+163,426,426,426,426,426,426,426,426,426,426,426,426,426,426,426,
+426,426,426,426,426,426,426,426,426,426,426,426,426,426,426,426,
+426,426,426,426,426,426,426,426,426,426,426,426,426,426,426,426,
+426,427,426,428,427,427,427,427,427,427,429,163,163,163,163,430,
+431,431,431,431,431,426,432,433,433,433,433,433,433,427,433,434,
+435,435,435,435,435,435,435,435,435,435,436,436,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 29 */
-163,438,438,163,438,163,438,438,438,438,438,163,438,438,438,438,
-438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,438,
-438,438,438,438,163,438,163,438,438,438,438,438,438,438,438,438,
-438,439,438,440,439,439,439,439,439,439,441,439,439,438,163,163,
-442,442,442,442,442,163,443,163,444,444,444,444,444,439,163,163,
-445,445,445,445,445,445,445,445,445,445,163,163,438,438,438,438,
+163,437,437,163,437,163,437,437,437,437,437,163,437,437,437,437,
+437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,437,
+437,437,437,437,163,437,163,437,437,437,437,437,437,437,437,437,
+437,438,437,439,438,438,438,438,438,438,440,438,438,437,163,163,
+441,441,441,441,441,163,442,163,443,443,443,443,443,438,444,163,
+445,445,445,445,445,445,445,445,445,445,163,163,437,437,437,437,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
@@ -2696,274 +2710,274 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
163,456,456,456,456,456,456,457,456,457,456,456,456,456,456,458,
/* block 31 */
-456,456,450,450,459,448,450,450,446,446,446,446,446,456,456,456,
+456,456,459,459,460,448,450,450,446,446,446,446,446,456,456,456,
456,456,456,456,456,456,456,456,163,456,456,456,456,456,456,456,
456,456,456,456,456,456,456,456,456,456,456,456,456,456,456,456,
456,456,456,456,456,456,456,456,456,456,456,456,456,163,447,447,
447,447,447,447,447,447,450,447,447,447,447,447,447,163,447,447,
-448,448,448,448,448,460,460,460,460,448,448,163,163,163,163,163,
+448,448,448,448,448,461,461,461,461,448,448,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 32 */
-461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
-461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
-461,461,461,461,461,461,461,461,461,461,461,462,462,463,463,463,
-463,464,463,463,463,463,463,465,462,466,466,464,464,463,463,461,
-467,467,467,467,467,467,467,467,467,467,468,468,469,469,469,469,
-461,461,461,461,461,461,464,464,463,463,461,461,461,461,463,463,
-463,461,462,470,470,461,461,462,462,470,470,470,470,470,461,461,
-461,463,463,463,463,461,461,461,461,461,461,461,461,461,461,461,
+462,462,462,462,462,462,462,462,462,462,462,462,462,462,462,462,
+462,462,462,462,462,462,462,462,462,462,462,462,462,462,462,462,
+462,462,462,462,462,462,462,462,462,462,462,463,463,464,464,464,
+464,465,464,464,464,464,464,466,463,467,467,465,465,464,464,462,
+468,468,468,468,468,468,468,468,468,468,469,469,470,470,470,470,
+462,462,462,462,462,462,465,465,464,464,462,462,462,462,464,464,
+464,462,463,471,471,462,462,463,463,471,471,471,471,471,462,462,
+462,464,464,464,464,462,462,462,462,462,462,462,462,462,462,462,
/* block 33 */
-461,461,463,462,464,463,463,470,470,470,470,470,470,471,461,470,
-472,472,472,472,472,472,472,472,472,472,470,470,462,463,473,473,
-474,474,474,474,474,474,474,474,474,474,474,474,474,474,474,474,
-474,474,474,474,474,474,474,474,474,474,474,474,474,474,474,474,
-474,474,474,474,474,474,163,474,163,163,163,163,163,474,163,163,
+462,462,464,463,465,464,464,471,471,471,471,471,471,472,462,471,
+473,473,473,473,473,473,473,473,473,473,471,471,463,464,474,474,
475,475,475,475,475,475,475,475,475,475,475,475,475,475,475,475,
475,475,475,475,475,475,475,475,475,475,475,475,475,475,475,475,
-475,475,475,475,475,475,475,475,475,475,475,476,477,475,475,475,
+475,475,475,475,475,475,163,475,163,163,163,163,163,475,163,163,
+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,477,478,476,476,476,
/* block 34 */
-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,478,478,478,478,478,479,
-480,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,
+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,479,479,479,479,479,480,
+481,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 35 */
-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,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,482,482,482,482,482,482,482,482,482,
-
-/* block 36 */
-483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,
+482,482,482,482,482,482,482,482,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,163,483,483,483,483,163,163,
-483,483,483,483,483,483,483,163,483,163,483,483,483,483,163,163,
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,
+/* block 36 */
+484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
+484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
+484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
+484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
+484,484,484,484,484,484,484,484,484,163,484,484,484,484,163,163,
+484,484,484,484,484,484,484,163,484,163,484,484,484,484,163,163,
+484,484,484,484,484,484,484,484,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 37 */
-483,483,483,483,483,483,483,483,483,163,483,483,483,483,163,163,
-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,163,483,483,483,483,163,163,483,483,483,483,483,483,483,163,
-483,163,483,483,483,483,163,163,483,483,483,483,483,483,483,483,
-483,483,483,483,483,483,483,163,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,
+484,484,484,484,484,484,484,484,484,163,484,484,484,484,163,163,
+484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
+484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
+484,163,484,484,484,484,163,163,484,484,484,484,484,484,484,163,
+484,163,484,484,484,484,163,163,484,484,484,484,484,484,484,484,
+484,484,484,484,484,484,484,163,484,484,484,484,484,484,484,484,
+484,484,484,484,484,484,484,484,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 38 */
-483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,
-483,163,483,483,483,483,163,163,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,163,163,484,484,484,
-485,486,487,486,486,486,486,487,487,488,488,488,488,488,488,488,
-488,488,489,489,489,489,489,489,489,489,489,489,489,163,163,163,
+484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
+484,163,484,484,484,484,163,163,484,484,484,484,484,484,484,484,
+484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
+484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
+484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
+484,484,484,484,484,484,484,484,484,484,484,163,163,485,485,485,
+486,487,488,487,487,487,487,488,488,489,489,489,489,489,489,489,
+489,489,490,490,490,490,490,490,490,490,490,490,490,163,163,163,
/* block 39 */
-483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,
-490,490,490,490,490,490,490,490,490,490,163,163,163,163,163,163,
-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,163,163,493,493,493,493,493,493,163,163,
+484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
+491,491,491,491,491,491,491,491,491,491,163,163,163,163,163,163,
+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,
+493,493,493,493,493,493,163,163,494,494,494,494,494,494,163,163,
/* block 40 */
-494,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
+495,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
/* block 41 */
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
/* block 42 */
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,496,497,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,497,498,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
/* block 43 */
-498,499,499,499,499,499,499,499,499,499,499,499,499,499,499,499,
-499,499,499,499,499,499,499,499,499,499,499,500,501,163,163,163,
-502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,
-502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,
-502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,
-502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,502,
-502,502,502,502,502,502,502,502,502,502,502,503,503,503,504,504,
-504,502,502,502,502,502,502,502,502,163,163,163,163,163,163,163,
+499,500,500,500,500,500,500,500,500,500,500,500,500,500,500,500,
+500,500,500,500,500,500,500,500,500,500,500,501,502,163,163,163,
+503,503,503,503,503,503,503,503,503,503,503,503,503,503,503,503,
+503,503,503,503,503,503,503,503,503,503,503,503,503,503,503,503,
+503,503,503,503,503,503,503,503,503,503,503,503,503,503,503,503,
+503,503,503,503,503,503,503,503,503,503,503,503,503,503,503,503,
+503,503,503,503,503,503,503,503,503,503,503,504,504,504,505,505,
+505,503,503,503,503,503,503,503,503,163,163,163,163,163,163,163,
/* block 44 */
-505,505,505,505,505,505,505,505,505,505,505,505,505,505,505,505,
-505,505,506,506,507,508,163,163,163,163,163,163,163,163,163,505,
-509,509,509,509,509,509,509,509,509,509,509,509,509,509,509,509,
-509,509,510,510,511,512,512,163,163,163,163,163,163,163,163,163,
-513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,
-513,513,514,514,163,163,163,163,163,163,163,163,163,163,163,163,
-515,515,515,515,515,515,515,515,515,515,515,515,515,163,515,515,
-515,163,516,516,163,163,163,163,163,163,163,163,163,163,163,163,
+506,506,506,506,506,506,506,506,506,506,506,506,506,506,506,506,
+506,506,507,507,508,509,163,163,163,163,163,163,163,163,163,506,
+510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,
+510,510,511,511,512,513,513,163,163,163,163,163,163,163,163,163,
+514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,
+514,514,515,515,163,163,163,163,163,163,163,163,163,163,163,163,
+516,516,516,516,516,516,516,516,516,516,516,516,516,163,516,516,
+516,163,517,517,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 45 */
-517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,
-517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,
-517,517,517,518,518,517,517,517,517,517,517,517,517,517,517,517,
-517,517,517,517,519,519,520,521,521,521,521,521,521,521,520,520,
-520,520,520,520,520,520,521,520,520,522,522,522,522,522,522,522,
-522,522,523,522,524,524,524,525,526,526,524,527,517,522,163,163,
-528,528,528,528,528,528,528,528,528,528,163,163,163,163,163,163,
+518,518,518,518,518,518,518,518,518,518,518,518,518,518,518,518,
+518,518,518,518,518,518,518,518,518,518,518,518,518,518,518,518,
+518,518,518,519,519,518,518,518,518,518,518,518,518,518,518,518,
+518,518,518,518,520,520,521,522,522,522,522,522,522,522,521,521,
+521,521,521,521,521,521,522,521,521,523,523,523,523,523,523,523,
+523,523,524,523,525,525,525,526,527,527,525,528,518,523,163,163,
529,529,529,529,529,529,529,529,529,529,163,163,163,163,163,163,
+530,530,530,530,530,530,530,530,530,530,163,163,163,163,163,163,
/* block 46 */
-530,530,531,532,533,531,534,530,533,535,536,537,537,537,538,537,
-539,539,539,539,539,539,539,539,539,539,163,163,163,163,163,163,
-540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,
-540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,
-540,540,540,541,540,540,540,540,540,540,540,540,540,540,540,540,
-540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,
-540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,
-540,540,540,540,540,540,540,540,540,163,163,163,163,163,163,163,
+531,531,532,533,534,532,535,531,534,536,537,538,538,538,539,538,
+540,540,540,540,540,540,540,540,540,540,163,163,163,163,163,163,
+541,541,541,541,541,541,541,541,541,541,541,541,541,541,541,541,
+541,541,541,541,541,541,541,541,541,541,541,541,541,541,541,541,
+541,541,541,542,541,541,541,541,541,541,541,541,541,541,541,541,
+541,541,541,541,541,541,541,541,541,541,541,541,541,541,541,541,
+541,541,541,541,541,541,541,541,541,541,541,541,541,541,541,541,
+541,541,541,541,541,541,541,541,541,163,163,163,163,163,163,163,
/* block 47 */
-540,540,540,540,540,542,542,540,540,540,540,540,540,540,540,540,
-540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,
-540,540,540,540,540,540,540,540,540,543,540,163,163,163,163,163,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-495,495,495,495,495,495,163,163,163,163,163,163,163,163,163,163,
+541,541,541,541,541,543,543,541,541,541,541,541,541,541,541,541,
+541,541,541,541,541,541,541,541,541,541,541,541,541,541,541,541,
+541,541,541,541,541,541,541,541,541,544,541,163,163,163,163,163,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+496,496,496,496,496,496,163,163,163,163,163,163,163,163,163,163,
/* block 48 */
-544,544,544,544,544,544,544,544,544,544,544,544,544,544,544,544,
-544,544,544,544,544,544,544,544,544,544,544,544,544,544,544,163,
-545,545,545,546,546,546,546,545,545,546,546,546,163,163,163,163,
-546,546,545,546,546,546,546,546,546,547,547,547,163,163,163,163,
-548,163,163,163,549,549,550,550,550,550,550,550,550,550,550,550,
-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,163,163,
-551,551,551,551,551,163,163,163,163,163,163,163,163,163,163,163,
+545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,
+545,545,545,545,545,545,545,545,545,545,545,545,545,545,545,163,
+546,546,546,547,547,547,547,546,546,547,547,547,163,163,163,163,
+547,547,546,547,547,547,547,547,547,548,548,548,163,163,163,163,
+549,163,163,163,550,550,551,551,551,551,551,551,551,551,551,551,
+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,163,163,
+552,552,552,552,552,163,163,163,163,163,163,163,163,163,163,163,
/* block 49 */
-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,163,163,163,163,
-552,552,552,552,552,553,553,553,552,552,553,552,552,552,552,552,
-552,552,552,552,552,552,552,552,552,552,163,163,163,163,163,163,
-554,554,554,554,554,554,554,554,554,554,555,163,163,163,556,556,
-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,
+553,553,553,553,553,553,553,553,553,553,553,553,553,553,553,553,
+553,553,553,553,553,553,553,553,553,553,553,553,553,553,553,553,
+553,553,553,553,553,553,553,553,553,553,553,553,163,163,163,163,
+553,553,553,553,553,554,554,554,553,553,554,553,553,553,553,553,
+553,553,553,553,553,553,553,553,553,553,163,163,163,163,163,163,
+555,555,555,555,555,555,555,555,555,555,556,163,163,163,557,557,
+558,558,558,558,558,558,558,558,558,558,558,558,558,558,558,558,
+558,558,558,558,558,558,558,558,558,558,558,558,558,558,558,558,
/* block 50 */
-558,558,558,558,558,558,558,558,558,558,558,558,558,558,558,558,
-558,558,558,558,558,558,558,559,559,560,560,559,163,163,561,561,
-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,564,563,564,564,564,564,564,564,564,163,
-565,566,564,566,566,564,564,564,564,564,564,564,564,563,563,563,
-563,563,563,564,564,567,567,567,567,567,567,567,567,163,163,567,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,559,559,559,560,560,561,561,560,163,163,562,562,
+563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,
+563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,
+563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,
+563,563,563,563,563,564,565,564,565,565,565,565,565,565,565,163,
+566,567,565,567,567,565,565,565,565,565,565,565,565,564,564,564,
+564,564,564,565,565,568,568,568,568,568,568,568,568,163,163,568,
/* block 51 */
-568,568,568,568,568,568,568,568,568,568,163,163,163,163,163,163,
-568,568,568,568,568,568,568,568,568,568,163,163,163,163,163,163,
-569,569,569,569,569,569,569,570,571,571,571,571,569,569,163,163,
-154,154,154,154,154,154,154,154,154,154,154,154,154,154,572,573,
-573,154,154,154,154,154,154,154,154,154,154,154,573,573,573,163,
+569,569,569,569,569,569,569,569,569,569,163,163,163,163,163,163,
+569,569,569,569,569,569,569,569,569,569,163,163,163,163,163,163,
+570,570,570,570,570,570,570,571,572,572,572,572,570,570,163,163,
+154,154,154,154,154,154,154,154,154,154,154,154,154,154,573,574,
+574,154,154,154,154,154,154,154,154,154,154,154,574,574,574,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 52 */
-574,574,574,574,575,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,576,576,576,576,576,576,576,576,576,576,576,576,576,
-576,576,576,576,577,578,574,574,574,574,574,575,574,575,575,575,
-575,575,574,575,579,576,576,576,576,576,576,576,576,163,163,163,
-580,580,580,580,580,580,580,580,580,580,581,581,582,583,581,581,
-582,584,584,584,584,584,584,584,584,584,584,577,577,577,577,577,
-577,577,577,577,584,584,584,584,584,584,584,584,584,581,581,163,
+575,575,575,575,576,577,577,577,577,577,577,577,577,577,577,577,
+577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,
+577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,
+577,577,577,577,578,579,575,575,575,575,575,576,575,576,576,576,
+576,576,575,576,580,577,577,577,577,577,577,577,577,163,163,163,
+581,581,581,581,581,581,581,581,581,581,582,582,583,584,582,582,
+583,585,585,585,585,585,585,585,585,585,585,578,578,578,578,578,
+578,578,578,578,585,585,585,585,585,585,585,585,585,582,582,163,
/* block 53 */
-585,585,586,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,586,585,585,585,585,586,586,585,585,588,589,585,585,587,587,
-590,590,590,590,590,590,590,590,590,590,587,587,587,587,587,587,
-591,591,591,591,591,591,591,591,591,591,591,591,591,591,591,591,
-591,591,591,591,591,591,591,591,591,591,591,591,591,591,591,591,
-591,591,591,591,591,591,592,593,594,594,593,593,593,594,593,594,
-594,594,595,595,163,163,163,163,163,163,163,163,596,596,596,596,
+586,586,587,588,588,588,588,588,588,588,588,588,588,588,588,588,
+588,588,588,588,588,588,588,588,588,588,588,588,588,588,588,588,
+588,587,586,586,586,586,587,587,586,586,589,590,586,586,588,588,
+591,591,591,591,591,591,591,591,591,591,588,588,588,588,588,588,
+592,592,592,592,592,592,592,592,592,592,592,592,592,592,592,592,
+592,592,592,592,592,592,592,592,592,592,592,592,592,592,592,592,
+592,592,592,592,592,592,593,594,595,595,594,594,594,595,594,595,
+595,595,596,596,163,163,163,163,163,163,163,163,597,597,597,597,
/* block 54 */
-597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,
-597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,
-597,597,597,597,598,598,598,598,598,598,598,598,599,599,599,599,
-599,599,599,599,598,598,600,601,163,163,163,602,602,603,603,603,
-604,604,604,604,604,604,604,604,604,604,163,163,163,597,597,597,
-605,605,605,605,605,605,605,605,605,605,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,606,606,606,607,607,607,608,607,607,609,609,
+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,598,598,598,598,598,
+598,598,598,598,599,599,599,599,599,599,599,599,600,600,600,600,
+600,600,600,600,599,599,601,602,163,163,163,603,603,604,604,604,
+605,605,605,605,605,605,605,605,605,605,163,163,163,598,598,598,
+606,606,606,606,606,606,606,606,606,606,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,607,607,608,608,608,609,608,608,610,610,
/* block 55 */
-610,611,612,613,614,615,616,617,618,163,163,163,163,163,163,163,
-619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,
-619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,
-619,619,619,619,619,619,619,619,619,619,619,163,163,619,619,619,
-620,620,620,620,620,620,620,620,163,163,163,163,163,163,163,163,
-621,622,621,623,622,624,624,625,624,625,626,622,625,625,622,622,
-625,627,622,622,622,622,622,622,622,628,629,630,630,624,630,630,
-630,630,631,632,633,629,629,634,635,635,636,163,163,163,163,163,
+611,612,613,614,615,616,617,618,619,163,163,163,163,163,163,163,
+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,163,163,620,620,620,
+621,621,621,621,621,621,621,621,163,163,163,163,163,163,163,163,
+622,623,622,624,623,625,625,626,625,626,627,623,626,626,623,623,
+626,628,623,623,623,623,623,623,623,629,630,631,631,625,631,631,
+631,631,632,633,634,630,630,635,636,636,637,163,163,163,163,163,
/* block 56 */
70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70,221,221,221,221,221,637,147,147,147,147,
+ 70, 70, 70, 70, 70, 70,221,221,221,221,221,638,147,147,147,147,
147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,
147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,
-147,147,147,147,147,147,147,147,147,147,147,147,147,638,638,638,
-638,638,148,147,147,147,638,638,638,638,638, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70,639,640, 70, 70, 70,641, 70, 70,
+147,147,147,147,147,147,147,147,147,147,147,147,147,639,639,639,
+639,639,148,147,147,147,639,639,639,639,639, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70,640,641, 70, 70, 70,642, 70, 70,
/* block 57 */
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,642, 70,
- 70, 70, 70, 70, 70, 70,643, 70, 70, 70, 70,644,644,644,644,644,
-644,644,644,644,645,644,644,644,645,644,644,644,644,644,644,644,
-644,644,644,644,644,644,644,644,644,644,644,644,644,644,644,646,
-647,647,158,158,154,154,154,154,154,154,154,154,154,154,154,154,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,643, 70,
+ 70, 70, 70, 70, 70, 70,644, 70, 70, 70, 70,645,645,645,645,645,
+645,645,645,645,646,645,645,645,646,645,645,645,645,645,645,645,
+645,645,645,645,645,645,645,645,645,645,645,645,645,645,645,647,
+648,648,158,158,154,154,154,154,154,154,154,154,154,154,154,154,
158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,
-158,158,158,158,158,158,158,573,573,573,573,573,573,573,573,573,
-573,573,573,573,573,154,154,154,648,154,649,154,154,154,154,154,
+158,158,158,158,158,158,158,574,574,574,574,574,574,574,574,574,
+574,574,574,574,574,154,154,154,649,154,650,154,154,154,154,154,
/* block 58 */
65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,
@@ -2972,12 +2986,12 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,
65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,
65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,
-650,651, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,
+651,652, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,
65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,
/* block 59 */
65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,
- 65, 66, 65, 66, 65, 66, 69, 69, 69, 69,652,653, 70, 70,654, 70,
+ 65, 66, 65, 66, 65, 66, 69, 69, 69, 69,653,654, 70, 70,655, 70,
65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,
65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,
65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 67, 65, 66, 65, 66,
@@ -2986,123 +3000,123 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,
/* block 60 */
-655,655,655,655,655,655,655,655,656,656,656,656,656,656,656,656,
-655,655,655,655,655,655,163,163,656,656,656,656,656,656,163,163,
-655,655,655,655,655,655,655,655,656,656,656,656,656,656,656,656,
-655,655,655,655,655,655,655,655,656,656,656,656,656,656,656,656,
-655,655,655,655,655,655,163,163,656,656,656,656,656,656,163,163,
-173,655,173,655,173,655,173,655,163,656,163,656,163,656,163,656,
-655,655,655,655,655,655,655,655,656,656,656,656,656,656,656,656,
-657,657,658,658,658,658,659,659,660,660,661,661,662,662,163,163,
+656,656,656,656,656,656,656,656,657,657,657,657,657,657,657,657,
+656,656,656,656,656,656,163,163,657,657,657,657,657,657,163,163,
+656,656,656,656,656,656,656,656,657,657,657,657,657,657,657,657,
+656,656,656,656,656,656,656,656,657,657,657,657,657,657,657,657,
+656,656,656,656,656,656,163,163,657,657,657,657,657,657,163,163,
+173,656,173,656,173,656,173,656,163,657,163,657,163,657,163,657,
+656,656,656,656,656,656,656,656,657,657,657,657,657,657,657,657,
+658,658,659,659,659,659,660,660,661,661,662,662,663,663,163,163,
/* block 61 */
-663,663,663,663,663,663,663,663,664,664,664,664,664,664,664,664,
-663,663,663,663,663,663,663,663,664,664,664,664,664,664,664,664,
-663,663,663,663,663,663,663,663,664,664,664,664,664,664,664,664,
-655,655,665,666,665,163,173,665,656,656,667,667,668,162,669,162,
-162,162,665,666,665,163,173,665,670,670,670,670,668,162,162,162,
-655,655,173,173,163,163,173,173,656,656,671,671,163,162,162,162,
-655,655,173,173,173,215,173,173,656,656,672,672,220,162,162,162,
-163,163,665,666,665,163,173,665,673,673,674,674,668,162,162,163,
+664,664,664,664,664,664,664,664,665,665,665,665,665,665,665,665,
+664,664,664,664,664,664,664,664,665,665,665,665,665,665,665,665,
+664,664,664,664,664,664,664,664,665,665,665,665,665,665,665,665,
+656,656,666,667,666,163,173,666,657,657,668,668,669,162,670,162,
+162,162,666,667,666,163,173,666,671,671,671,671,669,162,162,162,
+656,656,173,173,163,163,173,173,657,657,672,672,163,162,162,162,
+656,656,173,173,173,215,173,173,657,657,673,673,220,162,162,162,
+163,163,666,667,666,163,173,666,674,674,675,675,669,162,162,163,
/* block 62 */
-675,675,675,675,675,675,675,675,675,675,675, 51,676,677,678,679,
-680,680,680,680,680,680,681, 43,682,683,684,685,685,686,684,685,
- 43, 43, 43, 43,687, 43, 43,687,688,689,690,691,692,693,694,695,
-696,696,697,697,697, 43, 43, 43, 43, 49, 57, 43,698,699, 43,700,
-701, 43, 43, 43,702,703,704,699,699,698, 43, 43, 43, 43, 43, 43,
- 43, 43, 50,705,700, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,675,
- 51,706,706,706,706,707,708,709,710,711,712,712,712,712,712,712,
- 54,645,163,163, 54, 54, 54, 54, 54, 54,713,714,715,716,717,644,
+676,676,676,676,676,676,676,676,676,676,676, 51,677,678,679,680,
+681,681,681,681,681,681,682, 43,683,684,685,686,686,687,685,686,
+ 43, 43, 43, 43,688, 43, 43,688,689,690,691,692,693,694,695,696,
+697,697,698,698,698, 43, 43, 43, 43, 49, 57, 43,699,700, 43,701,
+702, 43, 43, 43,703,704,705,700,700,699, 43, 43, 43, 43, 43, 43,
+ 43, 43, 50,706,701, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,676,
+ 51,707,707,707,707,708,709,710,711,712,713,713,713,713,713,713,
+ 54,646,163,163, 54, 54, 54, 54, 54, 54,714,715,716,717,718,645,
/* block 63 */
- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,713,714,715,716,717,163,
-644,644,644,644,644,644,644,644,644,644,644,644,644,163,163,163,
-431,431,431,431,431,431,431,431,431,431,431,431,431,431,431,431,
-431,431,431,431,431,431,431,431,431,431,431,431,431,431,431,431,
-431,718,718,718,718,718,718,718,718,718,718,718,718,718,718,718,
-719,719,719,719,719,719,719,719,719,719,719,719,719,720,720,720,
-720,719,720,721,720,719,719,158,158,158,158,719,719,719,719,719,
-722,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+ 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,714,715,716,717,718,163,
+645,645,645,645,645,645,645,645,645,645,645,645,645,163,163,163,
+430,430,430,430,430,430,430,430,430,430,430,430,430,430,430,430,
+430,430,430,430,430,430,430,430,430,430,430,430,430,430,430,430,
+430,719,719,719,719,719,719,719,719,719,719,719,719,719,719,719,
+720,720,720,720,720,720,720,720,720,720,720,720,720,721,721,721,
+721,720,721,722,721,720,720,158,158,158,158,720,720,720,720,720,
+723,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 64 */
-723,723,724,723,723,723,723,724,723,723,725,724,724,724,725,725,
-724,724,724,725,723,724,723,723,726,724,724,724,724,724,723,723,
-723,723,727,723,724,723,728,723,724,729,730,731,724,724,732,725,
-724,724,733,724,725,734,734,734,734,735,723,723,725,725,724,724,
-715,715,715,715,715,724,725,725,736,736,723,715,723,723,737,460,
+724,724,725,724,724,724,724,725,724,724,726,725,725,725,726,726,
+725,725,725,726,724,725,724,724,727,725,725,725,725,725,724,724,
+724,724,728,724,725,724,729,724,725,730,731,732,725,725,733,726,
+725,725,734,725,726,735,735,735,735,736,724,724,726,726,725,725,
+716,716,716,716,716,725,726,726,737,737,724,716,724,724,738,461,
58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-738,738,738,738,738,738,738,738,738,738,738,738,738,738,738,738,
739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,739,
+740,740,740,740,740,740,740,740,740,740,740,740,740,740,740,740,
/* block 65 */
-740,740,740, 65, 66,740,740,740,740, 58,723,723,163,163,163,163,
- 50, 50, 50, 50,741,742,742,742,742,742, 50, 50,743,743,743,743,
- 50,743,743, 50,743,743, 50,743, 45,742,742,743,743,743, 50, 45,
-743,743, 45, 45, 45, 45,743,743, 45, 45, 45, 45,743,743,743,743,
-743,743,743,743,743,743,743,743,743,743,743,743,743,743, 50, 50,
-743,743, 50,743, 50,743,743,743,743,743,743,743, 45,743, 45, 45,
- 45, 45, 45, 45,743,743, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+741,741,741, 65, 66,741,741,741,741, 58,724,724,163,163,163,163,
+ 50, 50, 50, 50,742,743,743,743,743,743, 50, 50,744,744,744,744,
+ 50,744,744, 50,744,744, 50,744, 45,743,743,744,744,744, 50, 45,
+744,744, 45, 45, 45, 45,744,744, 45, 45, 45, 45,744,744,744,744,
+744,744,744,744,744,744,744,744,744,744,744,744,744,744, 50, 50,
+744,744, 50,744, 50,744,744,744,744,744,744,744, 45,744, 45, 45,
+ 45, 45, 45, 45,744,744, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
45, 45, 45, 45, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
/* block 66 */
- 50, 50, 50, 50, 50, 50, 50, 50,744,744,744,744,744,744, 50, 50,
- 50, 50,745, 53, 50,744, 50, 50, 50, 50, 50, 50, 50, 50, 50,744,
-744,744,744, 50,744, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
- 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,744,744, 50, 50,
- 50, 50, 50,744, 50,744, 50, 50, 50, 50, 50, 50,744, 50, 50, 50,
- 50, 50,744,744,744,744, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
- 50, 50, 50, 50,744,744,744,744,744,744,744,744, 50, 50,744,744,
-744,744,744,744,744,744,744,744,744,744,744,744,744,744,744,744,
+ 50, 50, 50, 50, 50, 50, 50, 50,745,745,745,745,745,745, 50, 50,
+ 50, 50,746, 53, 50,745, 50, 50, 50, 50, 50, 50, 50, 50, 50,745,
+745,745,745, 50,745, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,745,745, 50, 50,
+ 50, 50, 50,745, 50,745, 50, 50, 50, 50, 50, 50,745, 50, 50, 50,
+ 50, 50,745,745,745,745, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50,745,745,745,745,745,745,745,745, 50, 50,745,745,
+745,745,745,745,745,745,745,745,745,745,745,745,745,745,745,745,
/* block 67 */
-744,744,744,744,744,744,744,744,744,744,744,744, 50, 50, 50,744,
-744,744,744, 50, 50, 50, 50, 50,744, 50, 50, 50, 50, 50, 50, 50,
- 50, 50,744,744, 50, 50,744, 50,744,744, 50,744, 50, 50, 50, 50,
-744,744,744,744,744,744,744,744,744, 50, 50, 50, 50, 50, 50, 50,
- 50, 50, 50, 50, 50, 50, 50, 50, 50,744,744,744,744,744, 50, 50,
-744,744, 50, 50, 50, 50,744,744,744,744,744,744,744,744,744,744,
-744,744,744,744,744,744,744,744,744,744,744,744,744,744, 50, 50,
-744,744,744,744,744, 50,744,744, 50, 50,744,744,744,744,744, 50,
+745,745,745,745,745,745,745,745,745,745,745,745, 50, 50, 50,745,
+745,745,745, 50, 50, 50, 50, 50,745, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50,745,745, 50, 50,745, 50,745,745, 50,745, 50, 50, 50, 50,
+745,745,745,745,745,745,745,745,745, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50,745,745,745,745,745, 50, 50,
+745,745, 50, 50, 50, 50,745,745,745,745,745,745,745,745,745,745,
+745,745,745,745,745,745,745,745,745,745,745,745,745,745, 50, 50,
+745,745,745,745,745, 50,745,745, 50, 50,745,745,745,745,745, 50,
/* block 68 */
- 45, 45, 45, 45, 45, 45, 45, 45,746,747,746,747, 45, 45, 45, 45,
- 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,748,748, 45, 45, 45, 45,
- 50, 50, 45, 45, 45, 45, 45, 45, 47,749,750, 45, 45, 45, 45, 45,
- 45, 45, 45, 45, 45, 45,751,751,751,751,751,751,751,751,751,751,
-751,751,751,751,751,751,751,751,751,751,751,751,751,751,751,751,
-751,751,751,751,751,751,751,751,751,751,751,751,751,751,751,751,
-751,751,751,751,751,751,751,751,751,751,751,751,751,751,751,751,
-751,751,751,751,751,751,751,751,751,751,751, 45, 50, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45,747,748,747,748, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,749,749, 45, 45, 45, 45,
+ 50, 50, 45, 45, 45, 45, 45, 45, 47,750,751, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45,752,752,752,752,752,752,752,752,752,752,
+752,752,752,752,752,752,752,752,752,752,752,752,752,752,752,752,
+752,752,752,752,752,752,752,752,752,752,752,752,752,752,752,752,
+752,752,752,752,752,752,752,752,752,752,752,752,752,752,752,752,
+752,752,752,752,752,752,752,752,752,752,752, 45, 50, 45, 45, 45,
/* block 69 */
- 45, 45, 45, 45, 45, 45, 45, 45,752, 45, 45, 45, 45, 45, 45, 45,
- 45, 45, 45, 45, 45,751, 45, 45, 45, 45, 45, 50, 50, 50, 50, 50,
+ 45, 45, 45, 45, 45, 45, 45, 45,753, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45,752, 45, 45, 45, 45, 45, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
- 50, 50, 50, 50,743,743, 45,743, 45, 45, 45, 45, 45, 45, 45, 45,
+ 50, 50, 50, 50,744,744, 45,744, 45, 45, 45, 45, 45, 45, 45, 45,
45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 47,
-743, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 50, 50, 50, 50,
- 50, 50,743, 45, 45, 45, 45, 45, 45,748,748,748,748, 47, 47, 47,
-748, 47, 47,748, 45, 45, 45, 45, 47, 47, 47, 45, 45, 45, 45, 45,
+744, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 50, 50, 50, 50,
+ 50, 50,744, 45, 45, 45, 45, 45, 45,749,749,749,749, 47, 47, 47,
+749, 47, 47,749, 45, 45, 45, 45, 47, 47, 47, 45, 45, 45, 45, 45,
/* block 70 */
45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
- 45, 45, 45, 45, 45, 45, 45,753,753,753,753,753,753,753,753,753,
-753,753,753,753,753,753,753,753,753,753,753,753,753,753,753,753,
- 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,753,753,753,753,753,
-753,753,753,753,753,753,753,753,753,753,753,753,753,753,753,753,
+ 45, 45, 45, 45, 45, 45, 45,754,754,754,754,754,754,754,754,754,
+754,754,754,754,754,754,754,754,754,754,754,754,754,754,754,754,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,754,754,754,754,754,
+754,754,754,754,754,754,754,754,754,754,754,754,754,754,754,754,
58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
/* block 71 */
58, 58, 58, 58, 58, 58, 58, 58, 54, 54, 54, 54, 54, 54, 54, 54,
- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,754,754,754,754,754,754,754,754,754,754,
-754,754,755,754,754,754,754,754,754,754,754,754,754,754,754,754,
-756,756,756,756,756,756,756,756,756,756,756,756,756,756,756,756,
-756,756,756,756,756,756,756,756,756,756, 58, 58, 58, 58, 58, 58,
+ 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,755,755,755,755,755,755,755,755,755,755,
+755,755,756,755,755,755,755,755,755,755,755,755,755,755,755,755,
+757,757,757,757,757,757,757,757,757,757,757,757,757,757,757,757,
+757,757,757,757,757,757,757,757,757,757, 58, 58, 58, 58, 58, 58,
58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
/* block 72 */
@@ -3118,132 +3132,132 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
/* block 73 */
45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
-743,743, 45, 45, 45, 45, 45, 45, 45, 45, 47, 47, 45, 45,743,743,
-743,743,743,743,743,743,742, 50, 45, 45, 45, 45,743,743,743,743,
-742, 50, 45, 45, 45, 45,743,743, 45, 45,743,743, 45, 45, 45,743,
-743,743,743,743, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
- 45, 45,743, 45,743, 45, 45,743,743,743,743,743,743, 45, 45, 45,
- 45, 45, 45, 45, 45, 45, 45, 45, 50, 50, 50,741,741,757,757, 50,
+744,744, 45, 45, 45, 45, 45, 45, 45, 45, 47, 47, 45, 45,744,744,
+744,744,744,744,744,744,743, 50, 45, 45, 45, 45,744,744,744,744,
+743, 50, 45, 45, 45, 45,744,744, 45, 45,744,744, 45, 45, 45,744,
+744,744,744,744, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45,744, 45,744, 45, 45,744,744,744,744,744,744, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 50, 50, 50,742,742,758,758, 50,
/* block 74 */
- 47, 47, 47, 47, 47,758,743,752,752,752,752,752,752,752, 47,752,
-752, 47,752, 45,748,748,752,752, 47,752,752,752,752,759,752,752,
- 47,752, 47, 47,752,752, 47,752,752,752, 47,752,752,752, 47, 47,
-752,752,752,752,752,752,752,752, 47, 47, 47,752,752,752,752,752,
-742,752,742,752,752,752,752,752,748,748,748,748,748,748,748,748,
-748,748,748,748,752,752,752,752,752,752,752,752,752,752,752, 47,
-742,758,758,742,752, 47, 47,752, 47,752,752,752,752,758,758,760,
-752,752,752,752,752,752,752,752,752,752,752, 47,752,752, 47,748,
+ 47, 47, 47, 47, 47,759,744,753,753,753,753,753,753,753, 47,753,
+753, 47,753, 45,749,749,753,753, 47,753,753,753,753,760,753,753,
+ 47,753, 47, 47,753,753, 47,753,753,753, 47,753,753,753, 47, 47,
+753,753,753,753,753,753,753,753, 47, 47, 47,753,753,753,753,753,
+743,753,743,753,753,753,753,753,749,749,749,749,749,749,749,749,
+749,749,749,749,753,753,753,753,753,753,753,753,753,753,753, 47,
+743,759,759,743,753, 47, 47,753, 47,753,753,753,753,759,759,761,
+753,753,753,753,753,753,753,753,753,753,753, 47,753,753, 47,749,
/* block 75 */
-752,752,752,752,752,752, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
-752,752, 47,748, 47, 47, 47, 47,752, 47,752, 47, 47,752,752,752,
- 47,748,752,752,752,752,752, 47,752,752,748,748,761,752,752,752,
- 47, 47,752,752,752,752,752,752,752,752,752,752,752,748,748,752,
-752,752,752,752,748,748,752,752, 47,752,752,752,752,752,748, 47,
-752, 47,752, 47,748,752,752,752,752,752,752,752,752,752,752,752,
-752,752,752,752,752,752,752,752,752, 47,748,752,752,752,752,752,
- 47, 47,748,748, 47,748,752, 47, 47,759,748,752,752,748,752,752,
+753,753,753,753,753,753, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+753,753, 47,749, 47, 47, 47, 47,753, 47,753, 47, 47,753,753,753,
+ 47,749,753,753,753,753,753, 47,753,753,749,749,762,753,753,753,
+ 47, 47,753,753,753,753,753,753,753,753,753,753,753,749,749,753,
+753,753,753,753,749,749,753,753, 47,753,753,753,753,753,749, 47,
+753, 47,753, 47,749,753,753,753,753,753,753,753,753,753,753,753,
+753,753,753,753,753,753,753,753,753, 47,749,753,753,753,753,753,
+ 47, 47,749,749, 47,749,753, 47, 47,760,749,753,753,749,753,753,
/* block 76 */
-752,752, 47,752,752,748, 45, 45, 47, 47,762,762,759,759,752, 47,
-752,752, 47, 45, 47, 45, 47, 45, 45, 45, 45, 45, 45, 47, 45, 45,
- 45, 47, 45, 45, 45, 45, 45, 45,748, 45, 45, 45, 45, 45, 45, 45,
+753,753, 47,753,753,749, 45, 45, 47, 47,763,763,760,760,753, 47,
+753,753, 47, 45, 47, 45, 47, 45, 45, 45, 45, 45, 45, 47, 45, 45,
+ 45, 47, 45, 45, 45, 45, 45, 45,749, 45, 45, 45, 45, 45, 45, 45,
45, 45, 45, 47, 47, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
- 45, 45, 45, 45, 47, 45, 45, 47, 45, 45, 45, 45,748, 45,748, 45,
- 45, 45, 45,748,748,748, 45,748, 45, 45, 45, 45, 45, 45, 45, 45,
- 45, 45, 45, 47, 47,752,752,752,703,704,703,704,703,704,703,704,
-703,704,703,704,703,704, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 45, 45, 45, 45, 47, 45, 45, 47, 45, 45, 45, 45,749, 45,749, 45,
+ 45, 45, 45,749,749,749, 45,749, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 47, 47,753,753,753,704,705,704,705,704,705,704,705,
+704,705,704,705,704,705, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
/* block 77 */
58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 45,748,748,748, 45, 45, 45, 45, 45, 45, 45, 45,
+ 58, 58, 58, 58, 45,749,749,749, 45, 45, 45, 45, 45, 45, 45, 45,
45, 47, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
-748, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,748,
- 50, 50, 50,744,744,746,747, 50,744,744, 50,744, 50,744, 50, 50,
- 50, 50, 50, 50, 50,744,744, 50, 50, 50, 50, 50,744,744,744, 50,
- 50, 50,744,744,744,744,746,747,746,747,746,747,746,747,746,747,
+749, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,749,
+ 50, 50, 50,745,745,747,748, 50,745,745, 50,745, 50,745, 50, 50,
+ 50, 50, 50, 50, 50,745,745, 50, 50, 50, 50, 50,745,745,745, 50,
+ 50, 50,745,745,745,745,747,748,747,748,747,748,747,748,747,748,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
/* block 78 */
-763,763,763,763,763,763,763,763,763,763,763,763,763,763,763,763,
-763,763,763,763,763,763,763,763,763,763,763,763,763,763,763,763,
-763,763,763,763,763,763,763,763,763,763,763,763,763,763,763,763,
-763,763,763,763,763,763,763,763,763,763,763,763,763,763,763,763,
-763,763,763,763,763,763,763,763,763,763,763,763,763,763,763,763,
-763,763,763,763,763,763,763,763,763,763,763,763,763,763,763,763,
-763,763,763,763,763,763,763,763,763,763,763,763,763,763,763,763,
-763,763,763,763,763,763,763,763,763,763,763,763,763,763,763,763,
+764,764,764,764,764,764,764,764,764,764,764,764,764,764,764,764,
+764,764,764,764,764,764,764,764,764,764,764,764,764,764,764,764,
+764,764,764,764,764,764,764,764,764,764,764,764,764,764,764,764,
+764,764,764,764,764,764,764,764,764,764,764,764,764,764,764,764,
+764,764,764,764,764,764,764,764,764,764,764,764,764,764,764,764,
+764,764,764,764,764,764,764,764,764,764,764,764,764,764,764,764,
+764,764,764,764,764,764,764,764,764,764,764,764,764,764,764,764,
+764,764,764,764,764,764,764,764,764,764,764,764,764,764,764,764,
/* block 79 */
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
- 50, 50, 50, 50,741,741, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50,742,742, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
/* block 80 */
- 50, 50, 50,746,747,746,747,746,747,746,747,746,747,746,747,746,
-747,746,747,746,747,746,747,746,747, 50, 50,744, 50, 50, 50, 50,
-744, 50, 50,744,744,744, 50, 50,744,744,744,744,744,744,744,744,
- 50, 50, 50, 50, 50, 50, 50, 50,744, 50, 50, 50, 50, 50, 50, 50,
-744,744, 50, 50,744,744, 50, 50, 50, 50, 50, 50, 50, 50, 50,744,
-744,744,744, 50,744,744, 50, 50,746,747,746,747, 50, 50, 50, 50,
- 50, 50, 50, 50, 50, 50, 50, 50,744,744, 50, 50, 50, 50, 50, 50,
- 50, 50, 50, 50, 50,744, 50, 50,744,744, 50, 50,746,747, 50, 50,
+ 50, 50, 50,747,748,747,748,747,748,747,748,747,748,747,748,747,
+748,747,748,747,748,747,748,747,748, 50, 50,745, 50, 50, 50, 50,
+745, 50, 50,745,745,745, 50, 50,745,745,745,745,745,745,745,745,
+ 50, 50, 50, 50, 50, 50, 50, 50,745, 50, 50, 50, 50, 50, 50, 50,
+745,745, 50, 50,745,745, 50, 50, 50, 50, 50, 50, 50, 50, 50,745,
+745,745,745, 50,745,745, 50, 50,747,748,747,748, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50,745,745, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50,745, 50, 50,745,745, 50, 50,747,748, 50, 50,
/* block 81 */
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
- 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,744,744,744,744, 50,
- 50, 50, 50, 50,744,744, 50, 50, 50, 50, 50, 50,744,744, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,745,745,745,745, 50,
+ 50, 50, 50, 50,745,745, 50, 50, 50, 50, 50, 50,745,745, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
- 50, 50, 50, 50,744,744, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
- 50, 50, 50, 50, 50, 50, 50, 50, 50,744,744,744,744,744,744,744,
+ 50, 50, 50, 50,745,745, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50,745,745,745,745,745,745,745,
/* block 82 */
-744,744,744,744,744,744,744,744,744,744,744,744,744,744,744,744,
-744,744,744,744,744,744,744,744,744,744,744,744,744,744,744,744,
-744,744,744, 50, 50, 50,744,744,744,744,744,744,744,744, 50,744,
-744,744,744,744,744,744,744,744,744,744,744,744,744,744,744,744,
-744,744,744,744,744,744,744,744,744,744,744,744,744,744,744,744,
-744,744,744,744,744,744,744, 50, 50, 50, 50, 50, 50, 50,744, 50,
- 50, 50, 50,744,744,744, 50, 50, 50, 50, 50, 50,744,744,744, 50,
- 50, 50, 50, 50, 50, 50, 50,744,744,744,744, 50, 50, 50, 50, 50,
+745,745,745,745,745,745,745,745,745,745,745,745,745,745,745,745,
+745,745,745,745,745,745,745,745,745,745,745,745,745,745,745,745,
+745,745,745, 50, 50, 50,745,745,745,745,745,745,745,745, 50,745,
+745,745,745,745,745,745,745,745,745,745,745,745,745,745,745,745,
+745,745,745,745,745,745,745,745,745,745,745,745,745,745,745,745,
+745,745,745,745,745,745,745, 50, 50, 50, 50, 50, 50, 50,745, 50,
+ 50, 50, 50,745,745,745, 50, 50, 50, 50, 50, 50,745,745,745, 50,
+ 50, 50, 50, 50, 50, 50, 50,745,745,745,745, 50, 50, 50, 50, 50,
/* block 83 */
45, 45, 45, 45, 45, 47, 47, 47, 45, 45, 45, 45, 45, 45, 45, 45,
- 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,748,748, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,749,749, 45, 45, 45,
45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
50, 50, 50, 50, 50, 45, 45, 50, 50, 50, 50, 50, 50, 45, 45, 45,
-748, 45, 45, 45, 45,748, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+749, 45, 45, 45, 45,749, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
- 45, 45, 45, 45,753,753, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45,754,754, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
/* block 84 */
45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
- 45, 45, 45, 45, 45, 45,753, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45,754, 45, 45, 45, 45, 45, 45, 45, 45, 45,
45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
- 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,764, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,765, 45,
/* block 85 */
-765,765,765,765,765,765,765,765,765,765,765,765,765,765,765,765,
-765,765,765,765,765,765,765,765,765,765,765,765,765,765,765,765,
-765,765,765,765,765,765,765,765,765,765,765,765,765,765,765,765,
766,766,766,766,766,766,766,766,766,766,766,766,766,766,766,766,
766,766,766,766,766,766,766,766,766,766,766,766,766,766,766,766,
766,766,766,766,766,766,766,766,766,766,766,766,766,766,766,766,
- 65, 66,767,768,769,770,771, 65, 66, 65, 66, 65, 66,772,773,774,
-775, 70, 65, 66, 70, 65, 66, 70, 70, 70, 70, 70,645,644,776,776,
+767,767,767,767,767,767,767,767,767,767,767,767,767,767,767,767,
+767,767,767,767,767,767,767,767,767,767,767,767,767,767,767,767,
+767,767,767,767,767,767,767,767,767,767,767,767,767,767,767,767,
+ 65, 66,768,769,770,771,772, 65, 66, 65, 66, 65, 66,773,774,775,
+776, 70, 65, 66, 70, 65, 66, 70, 70, 70, 70, 70,646,645,777,777,
/* block 86 */
211,212,211,212,211,212,211,212,211,212,211,212,211,212,211,212,
@@ -3252,248 +3266,248 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
211,212,211,212,211,212,211,212,211,212,211,212,211,212,211,212,
211,212,211,212,211,212,211,212,211,212,211,212,211,212,211,212,
211,212,211,212,211,212,211,212,211,212,211,212,211,212,211,212,
-211,212,211,212,777,778,778,778,778,778,778,211,212,211,212,779,
-779,779,211,212,163,163,163,163,163,780,780,780,780,781,780,780,
+211,212,211,212,778,779,779,779,779,779,779,211,212,211,212,780,
+780,780,211,212,163,163,163,163,163,781,781,781,781,782,781,781,
/* block 87 */
-782,782,782,782,782,782,782,782,782,782,782,782,782,782,782,782,
-782,782,782,782,782,782,782,782,782,782,782,782,782,782,782,782,
-782,782,782,782,782,782,163,782,163,163,163,163,163,782,163,163,
-783,783,783,783,783,783,783,783,783,783,783,783,783,783,783,783,
783,783,783,783,783,783,783,783,783,783,783,783,783,783,783,783,
783,783,783,783,783,783,783,783,783,783,783,783,783,783,783,783,
-783,783,783,783,783,783,783,783,163,163,163,163,163,163,163,784,
-785,163,163,163,163,163,163,163,163,163,163,163,163,163,163,786,
+783,783,783,783,783,783,163,783,163,163,163,163,163,783,163,163,
+784,784,784,784,784,784,784,784,784,784,784,784,784,784,784,784,
+784,784,784,784,784,784,784,784,784,784,784,784,784,784,784,784,
+784,784,784,784,784,784,784,784,784,784,784,784,784,784,784,784,
+784,784,784,784,784,784,784,784,163,163,163,163,163,163,163,785,
+786,163,163,163,163,163,163,163,163,163,163,163,163,163,163,787,
/* block 88 */
-483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,
-483,483,483,483,483,483,483,163,163,163,163,163,163,163,163,163,
-483,483,483,483,483,483,483,163,483,483,483,483,483,483,483,163,
-483,483,483,483,483,483,483,163,483,483,483,483,483,483,483,163,
-483,483,483,483,483,483,483,163,483,483,483,483,483,483,483,163,
-483,483,483,483,483,483,483,163,483,483,483,483,483,483,483,163,
-787,787,787,787,787,787,787,787,787,787,787,787,787,787,787,787,
-787,787,787,787,787,787,787,787,787,787,787,787,787,787,787,787,
+484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,
+484,484,484,484,484,484,484,163,163,163,163,163,163,163,163,163,
+484,484,484,484,484,484,484,163,484,484,484,484,484,484,484,163,
+484,484,484,484,484,484,484,163,484,484,484,484,484,484,484,163,
+484,484,484,484,484,484,484,163,484,484,484,484,484,484,484,163,
+484,484,484,484,484,484,484,163,484,484,484,484,484,484,484,163,
+788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,
+788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,
/* block 89 */
- 43, 43,788,789,788,789, 43, 43, 43,788,789, 43,788,789, 43, 43,
- 43, 43, 43, 43, 43, 43, 43,680, 43, 43,680, 43,788,789, 43, 43,
-788,789,703,704,703,704,703,704,703,704, 43, 43, 43, 43,699,790,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,680,680,699, 43, 43, 43,
-680,791,684,792, 43, 43, 43, 43, 43, 43, 43, 43,791, 43,791,791,
- 45, 45, 43,699,699,703,704,703,704,703,704,703,704,680,753,753,
-753,753,753,753,753,753,753,753,753,753,753,753,753,753,753,753,
-753,753,753,753,753,753,753,753,753,753,753,753,753,753,753,753,
+ 43, 43,789,790,789,790, 43, 43, 43,789,790, 43,789,790, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43,681, 43, 43,681, 43,789,790, 43, 43,
+789,790,704,705,704,705,704,705,704,705, 43, 43, 43, 43,700,791,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,681,681,700, 43, 43, 43,
+681,792,685,793, 43, 43, 43, 43, 43, 43, 43, 43,792, 43,792,792,
+ 45, 45, 43,700,700,704,705,704,705,704,705,704,705,681,754,754,
+754,754,754,754,754,754,754,754,754,754,754,754,754,754,754,754,
+754,754,754,754,754,754,754,754,754,754,754,754,754,754,754,754,
/* block 90 */
-793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,
-793,793,793,793,793,793,793,793,793,793,163,793,793,793,793,793,
-793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,
-793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,
-793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,
-793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,
-793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,
-793,793,793,793,163,163,163,163,163,163,163,163,163,163,163,163,
+794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,
+794,794,794,794,794,794,794,794,794,794,163,794,794,794,794,794,
+794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,
+794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,
+794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,
+794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,
+794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,
+794,794,794,794,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 91 */
-793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,
-793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,
-793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,
-793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,
-793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,
-793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,
-793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,
-793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,
+794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,
+794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,
+794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,
+794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,
+794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,
+794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,
+794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,
+794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,
/* block 92 */
-793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,
-793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,
-793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,
-793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,
-793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,
-793,793,793,793,793,793,163,163,163,163,163,163,163,163,163,163,
+794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,
+794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,
+794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,
+794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,
+794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,794,
+794,794,794,794,794,794,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-794,794,795,795,794,794,794,794,794,794,794,794,163,163,163,163,
+795,795,796,796,795,795,795,795,795,795,795,795,163,163,163,163,
/* block 93 */
-675,796,797,798,723,799,800,801,802,803,802,803,804,805,804,805,
-802,803, 45,806,802,803,802,803,802,803,802,803,807,808,809,809,
- 45,801,801,801,801,801,801,801,801,801,810,810,810,810,811,811,
-812,813,813,813,813,813,723,814,801,801,801,815,816,817,818,818,
-163,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
+676,797,798,799,724,800,801,802,803,804,803,804,805,806,805,806,
+803,804, 45,807,803,804,803,804,803,804,803,804,808,809,810,810,
+ 45,802,802,802,802,802,802,802,802,802,811,811,811,811,812,812,
+813,814,814,814,814,814,724,815,802,802,802,816,817,818,819,819,
+163,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
/* block 94 */
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,163,163,820,820,821,821,822,822,819,
-823,824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,
-824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,
-824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,
-824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,
-824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,
-824,824,824,824,824,824,824,824,824,824,824,825,826,827,827,824,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+820,820,820,820,820,820,820,163,163,821,821,822,822,823,823,820,
+824,825,825,825,825,825,825,825,825,825,825,825,825,825,825,825,
+825,825,825,825,825,825,825,825,825,825,825,825,825,825,825,825,
+825,825,825,825,825,825,825,825,825,825,825,825,825,825,825,825,
+825,825,825,825,825,825,825,825,825,825,825,825,825,825,825,825,
+825,825,825,825,825,825,825,825,825,825,825,825,825,825,825,825,
+825,825,825,825,825,825,825,825,825,825,825,826,827,828,828,825,
/* block 95 */
-163,163,163,163,163,828,828,828,828,828,828,828,828,828,828,828,
-828,828,828,828,828,828,828,828,828,828,828,828,828,828,828,828,
-828,828,828,828,828,828,828,828,828,828,828,828,828,828,828,828,
-163,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
-829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+163,163,163,163,163,829,829,829,829,829,829,829,829,829,829,829,
829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
-829,829,829,829,830,829,829,829,829,829,829,829,829,829,829,829,
829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+163,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,831,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
/* block 96 */
-829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,163,
-831,831,832,832,832,832,831,831,831,831,831,831,831,831,831,831,
-828,828,828,828,828,828,828,828,828,828,828,828,828,828,828,828,
-828,828,828,828,828,828,828,828,828,828,828,828,828,828,828,828,
-818,818,818,818,818,818,818,818,818,818,818,818,818,818,818,818,
-818,818,818,818,818,818,818,818,818,818,818,818,818,818,818,818,
-818,818,818,818,163,163,163,163,163,163,163,163,163,163,163,163,
-824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,163,
+832,832,833,833,833,833,832,832,832,832,832,832,832,832,832,832,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
+819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
+819,819,819,819,163,163,163,163,163,163,163,163,163,163,163,163,
+825,825,825,825,825,825,825,825,825,825,825,825,825,825,825,825,
/* block 97 */
-833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,
-833,833,833,833,833,833,833,833,833,833,833,833,833,834,834,163,
-832,832,832,832,832,832,832,832,832,832,831,831,831,831,831,831,
-831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,
-831,831,831,831,831,831,831,831,835,835,835,835,835,835,835,835,
-723, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,
-833,833,833,833,833,833,833,833,833,833,833,833,834,834,834,460,
+834,834,834,834,834,834,834,834,834,834,834,834,834,834,834,834,
+834,834,834,834,834,834,834,834,834,834,834,834,834,835,835,163,
+833,833,833,833,833,833,833,833,833,833,832,832,832,832,832,832,
+832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,
+832,832,832,832,832,832,832,832,836,836,836,836,836,836,836,836,
+724, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+834,834,834,834,834,834,834,834,834,834,834,834,834,834,834,834,
+834,834,834,834,834,834,834,834,834,834,834,834,835,835,835,461,
/* block 98 */
-832,832,832,832,832,832,832,832,832,832,831,831,831,831,831,831,
-831,831,831,831,831,831,831,836,831,836,831,831,831,831,831,831,
-831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,
-831, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
-831,831,831,831,831,831,831,831,831,831,831,831,723,723,723,723,
-837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,
-837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,
-837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,831,
-
-/* block 99 */
-837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,
-837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,
-837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,
-837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,
-837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,
-837,837,837,837,837,837,837,837,831,831,831,831,831,831,831,831,
-831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,
-831,460,460,460,460,460,460,723,723,723,723,831,831,831,831,831,
-
-/* block 100 */
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,723,723,
-831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,
-831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,723,
-
-/* block 101 */
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
+833,833,833,833,833,833,833,833,833,833,832,832,832,832,832,832,
+832,832,832,832,832,832,832,837,832,837,832,832,832,832,832,832,
+832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,
+832, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+832,832,832,832,832,832,832,832,832,832,832,832,724,724,724,724,
838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
+838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,832,
+
+/* block 99 */
838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
+838,838,838,838,838,838,838,838,832,832,832,832,832,832,832,832,
+832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,
+832,461,461,461,461,461,461,724,724,724,724,832,832,832,832,832,
-/* block 102 */
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
+/* block 100 */
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,724,724,
+832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,
+832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,724,
-/* block 103 */
-839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
-839,839,839,839,839,840,839,839,839,839,839,839,839,839,839,839,
-839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
-839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+/* block 101 */
839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
-
-/* block 104 */
839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+
+/* block 102 */
839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+
+/* block 103 */
+840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,
+840,840,840,840,840,841,840,840,840,840,840,840,840,840,840,840,
+840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,
+840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,
+840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,
+840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,
+840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,
+840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,
+
+/* block 104 */
+840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,
+840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,
+840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,
+840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,
+840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,
+840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,
+840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,
+840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,840,
/* block 105 */
-839,839,839,839,839,839,839,839,839,839,839,839,839,163,163,163,
-841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,
-841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,
-841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,
-841,841,841,841,841,841,841,163,163,163,163,163,163,163,163,163,
+840,840,840,840,840,840,840,840,840,840,840,840,840,163,163,163,
+842,842,842,842,842,842,842,842,842,842,842,842,842,842,842,842,
842,842,842,842,842,842,842,842,842,842,842,842,842,842,842,842,
842,842,842,842,842,842,842,842,842,842,842,842,842,842,842,842,
-842,842,842,842,842,842,842,842,843,843,843,843,843,843,844,845,
+842,842,842,842,842,842,842,163,163,163,163,163,163,163,163,163,
+843,843,843,843,843,843,843,843,843,843,843,843,843,843,843,843,
+843,843,843,843,843,843,843,843,843,843,843,843,843,843,843,843,
+843,843,843,843,843,843,843,843,844,844,844,844,844,844,845,846,
/* block 106 */
-846,846,846,846,846,846,846,846,846,846,846,846,846,846,846,846,
-846,846,846,846,846,846,846,846,846,846,846,846,846,846,846,846,
-846,846,846,846,846,846,846,846,846,846,846,846,846,846,846,846,
-846,846,846,846,846,846,846,846,846,846,846,846,846,846,846,846,
-846,846,846,846,846,846,846,846,846,846,846,846,846,846,846,846,
-846,846,846,846,846,846,846,846,846,846,846,846,846,846,846,846,
-846,846,846,846,846,846,846,846,846,846,846,846,846,846,846,846,
-846,846,846,846,846,846,846,846,846,846,846,846,846,846,846,846,
+847,847,847,847,847,847,847,847,847,847,847,847,847,847,847,847,
+847,847,847,847,847,847,847,847,847,847,847,847,847,847,847,847,
+847,847,847,847,847,847,847,847,847,847,847,847,847,847,847,847,
+847,847,847,847,847,847,847,847,847,847,847,847,847,847,847,847,
+847,847,847,847,847,847,847,847,847,847,847,847,847,847,847,847,
+847,847,847,847,847,847,847,847,847,847,847,847,847,847,847,847,
+847,847,847,847,847,847,847,847,847,847,847,847,847,847,847,847,
+847,847,847,847,847,847,847,847,847,847,847,847,847,847,847,847,
/* block 107 */
-846,846,846,846,846,846,846,846,846,846,846,846,847,848,849,849,
-846,846,846,846,846,846,846,846,846,846,846,846,846,846,846,846,
-850,850,850,850,850,850,850,850,850,850,846,846,163,163,163,163,
+847,847,847,847,847,847,847,847,847,847,847,847,848,849,850,850,
+847,847,847,847,847,847,847,847,847,847,847,847,847,847,847,847,
+851,851,851,851,851,851,851,851,851,851,847,847,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-240,241,240,241,240,241,240,241,240,241,851,852,240,241,240,241,
+240,241,240,241,240,241,240,241,240,241,852,853,240,241,240,241,
240,241,240,241,240,241,240,241,240,241,240,241,240,241,240,241,
-240,241,240,241,240,241,240,241,240,241,240,241,240,241,853,246,
-248,248,248,854,787,787,787,787,787,787,787,787,855,855,854,856,
+240,241,240,241,240,241,240,241,240,241,240,241,240,241,854,246,
+248,248,248,855,788,788,788,788,788,788,788,788,856,856,855,857,
/* block 108 */
240,241,240,241,240,241,240,241,240,241,240,241,240,241,240,241,
-240,241,240,241,240,241,240,241,240,241,240,241,857,857,787,787,
-858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,
-858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,
-858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,
-858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,
-858,858,858,858,858,858,859,859,859,859,859,859,859,859,859,859,
-860,860,861,862,863,863,863,862,163,163,163,163,163,163,163,163,
+240,241,240,241,240,241,240,241,240,241,240,241,858,858,788,788,
+859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,
+859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,
+859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,
+859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,
+859,859,859,859,859,859,860,860,860,860,860,860,860,860,860,860,
+861,861,862,863,864,864,864,863,163,163,163,163,163,163,163,163,
/* block 109 */
-864,864,864,864,864,864,864,864, 46, 46, 46, 46, 46, 46, 46, 46,
+865,865,865,865,865,865,865,865, 46, 46, 46, 46, 46, 46, 46, 46,
46, 46, 46, 46, 46, 46, 46,149,149,149,149,149,149,149,149,149,
46, 46, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,
70, 70, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,
65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,
65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,
65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,
-644, 70, 70, 70, 70, 70, 70, 70, 70, 65, 66, 65, 66,865, 65, 66,
+645, 70, 70, 70, 70, 70, 70, 70, 70, 65, 66, 65, 66,866, 65, 66,
/* block 110 */
- 65, 66, 65, 66, 65, 66, 65, 66,149,866,866, 65, 66,867, 70, 92,
- 65, 66, 65, 66,868, 70, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,
- 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,869,870,871,872,869, 70,
-873,874,875,876, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,
- 65, 66, 65, 66,877,878,879, 65, 66, 65, 66,163,163,163,163,163,
+ 65, 66, 65, 66, 65, 66, 65, 66,149,867,867, 65, 66,868, 70, 92,
+ 65, 66, 65, 66,869, 70, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,
+ 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,870,871,872,873,870, 70,
+874,875,876,877, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66, 65, 66,
+ 65, 66, 65, 66,878,879,880, 65, 66, 65, 66,163,163,163,163,163,
65, 66,163, 70,163, 70, 65, 66, 65, 66,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-163,163,880,880,880, 65, 66, 92,147,147, 70, 92, 92, 92, 92, 92,
+163,163,645,645,645, 65, 66, 92,147,147, 70, 92, 92, 92, 92, 92,
/* block 111 */
881,881,882,881,881,881,883,881,881,881,881,882,881,881,881,881,
@@ -3522,8 +3536,8 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
908,908,908,908,908,908,908,908,908,908,908,908,908,908,908,908,
908,908,908,908,908,908,908,909,909,909,909,909,909,909,909,909,
909,909,910,911,163,163,163,163,163,163,163,163,163,163,163,912,
-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,163,163,163,
+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,163,163,163,
/* block 114 */
913,913,913,914,915,915,915,915,915,915,915,915,915,915,915,915,
@@ -3532,8 +3546,8 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
915,915,915,916,914,914,913,913,913,913,914,914,913,913,914,914,
917,918,918,918,918,918,918,919,920,920,918,918,918,918,163,921,
922,922,922,922,922,922,922,922,922,922,163,163,163,163,918,918,
-461,461,461,461,461,471,923,461,461,461,461,461,461,461,461,461,
-472,472,472,472,472,472,472,472,472,472,461,461,461,461,461,163,
+462,462,462,462,462,472,923,462,462,462,462,462,462,462,462,462,
+473,473,473,473,473,473,473,473,473,473,462,462,462,462,462,163,
/* block 115 */
924,924,924,924,924,924,924,924,924,924,924,924,924,924,924,924,
@@ -3542,8 +3556,8 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
926,925,925,926,926,925,925,163,163,163,163,163,163,163,163,163,
924,924,924,925,924,924,924,924,924,924,924,924,925,926,163,163,
927,927,927,927,927,927,927,927,927,927,163,163,928,929,929,929,
-461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
-923,461,461,461,461,461,461,473,473,473,461,470,471,470,461,461,
+462,462,462,462,462,462,462,462,462,462,462,462,462,462,462,462,
+923,462,462,462,462,462,462,474,474,474,462,471,472,471,462,462,
/* block 116 */
930,930,930,930,930,930,930,930,930,930,930,930,930,930,930,930,
@@ -3556,106 +3570,116 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
941,941,938,942,942,939,943,163,163,163,163,163,163,163,163,163,
/* block 117 */
-163,483,483,483,483,483,483,163,163,483,483,483,483,483,483,163,
-163,483,483,483,483,483,483,163,163,163,163,163,163,163,163,163,
-483,483,483,483,483,483,483,163,483,483,483,483,483,483,483,163,
+163,484,484,484,484,484,484,163,163,484,484,484,484,484,484,163,
+163,484,484,484,484,484,484,163,163,163,163,163,163,163,163,163,
+484,484,484,484,484,484,484,163,484,484,484,484,484,484,484,163,
70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70,944, 70, 70, 70, 70, 70, 70, 70,866,147,147,147,147,
- 70, 70, 70, 70, 70,221, 70, 70, 70,945, 46, 46,163,163,163,163,
-946,946,946,946,946,946,946,946,946,946,946,946,946,946,946,946,
+ 70, 70, 70,944, 70, 70, 70, 70, 70, 70, 70,867,147,147,147,147,
+ 70, 70, 70, 70, 70,221, 70, 70, 70,147, 46, 46,163,163,163,163,
+945,945,945,945,945,945,945,945,945,945,945,945,945,945,945,945,
/* block 118 */
-946,946,946,946,946,946,946,946,946,946,946,946,946,946,946,946,
-946,946,946,946,946,946,946,946,946,946,946,946,946,946,946,946,
-946,946,946,946,946,946,946,946,946,946,946,946,946,946,946,946,
-946,946,946,946,946,946,946,946,946,946,946,946,946,946,946,946,
+945,945,945,945,945,945,945,945,945,945,945,945,945,945,945,945,
+945,945,945,945,945,945,945,945,945,945,945,945,945,945,945,945,
+945,945,945,945,945,945,945,945,945,945,945,945,945,945,945,945,
+945,945,945,945,945,945,945,945,945,945,945,945,945,945,945,945,
938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,
938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,938,
-938,938,938,939,939,940,939,939,940,939,939,941,947,943,163,163,
-948,948,948,948,948,948,948,948,948,948,163,163,163,163,163,163,
+938,938,938,939,939,940,939,939,940,939,939,941,946,943,163,163,
+947,947,947,947,947,947,947,947,947,947,163,163,163,163,163,163,
/* block 119 */
-949,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,949,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,949,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,949,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-949,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
+948,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,948,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,948,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,948,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+948,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
/* block 120 */
-950,950,950,950,950,950,950,950,950,950,950,950,949,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,949,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,949,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-949,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,949,950,950,950,
+949,949,949,949,949,949,949,949,949,949,949,949,948,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,948,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,948,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+948,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,948,949,949,949,
/* block 121 */
-950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,949,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,949,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-949,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,949,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,948,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,948,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+948,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,948,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
/* block 122 */
-950,950,950,950,950,950,950,950,949,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,949,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-949,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,949,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,949,950,950,950,950,950,950,950,
+949,949,949,949,949,949,949,949,948,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,948,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+948,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,948,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,948,949,949,949,949,949,949,949,
/* block 123 */
-950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,949,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-949,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,949,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,949,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,948,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+948,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,948,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,948,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
/* block 124 */
-950,950,950,950,949,950,950,950,950,950,950,950,950,950,950,950,
+949,949,949,949,948,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+948,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,948,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,948,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,948,949,949,949,949,949,949,949,949,949,949,949,
+
+/* block 125 */
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+948,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,948,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,948,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,948,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+
+/* block 126 */
+949,949,949,949,949,949,949,949,948,949,949,949,949,949,949,949,
+949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,949,
+949,949,949,949,163,163,163,163,163,163,163,163,163,163,163,163,
+482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,482,
+482,482,482,482,482,482,482,163,163,163,163,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,163,163,163,163,
+
+/* block 127 */
950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-949,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,949,950,950,950,
950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,949,950,950,950,950,950,950,950,
950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,949,950,950,950,950,950,950,950,950,950,950,950,
-
-/* block 125 */
950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-949,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,950,950,950,950,949,950,950,950,
950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,950,950,950,950,949,950,950,950,950,950,950,950,
950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,949,950,950,950,950,950,950,950,950,950,950,950,
950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-
-/* block 126 */
-950,950,950,950,950,950,950,950,949,950,950,950,950,950,950,950,
950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,950,
-950,950,950,950,163,163,163,163,163,163,163,163,163,163,163,163,
-481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,
-481,481,481,481,481,481,481,163,163,163,163,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,163,163,163,163,
-/* block 127 */
+/* block 128 */
951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,
951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,
951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,
@@ -3665,7 +3689,7 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,
951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,
-/* block 128 */
+/* block 129 */
952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
@@ -3675,40 +3699,30 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
-/* block 129 */
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,
-
/* block 130 */
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,838,838,
-953,838,953,838,838,953,953,953,953,953,953,953,953,953,953,838,
-953,838,953,838,838,953,953,838,838,838,953,953,953,953,953,953,
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,163,163,
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,
+952,952,952,952,952,952,952,952,952,952,952,952,952,952,839,839,
+952,839,952,839,839,952,952,952,952,952,952,952,952,952,952,839,
+952,839,952,839,839,952,952,839,839,839,952,952,952,952,952,952,
+952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
+952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
+952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
+952,952,952,952,952,952,952,952,952,952,952,952,952,952,163,163,
+952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
/* block 131 */
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,
-953,953,953,953,953,953,953,953,953,953,163,163,163,163,163,163,
+952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
+952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
+952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
+952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
+952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
+952,952,952,952,952,952,952,952,952,952,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 132 */
-652,652,652,652,652,652,652,163,163,163,163,163,163,163,163,163,
+653,653,653,653,653,653,653,163,163,163,163,163,163,163,163,163,
163,163,163,257,257,257,257,257,163,163,163,163,163,270,265,270,
-270,270,270,270,270,270,270,270,270,954,270,270,270,270,270,270,
+270,270,270,270,270,270,270,270,270,953,270,270,270,270,270,270,
270,270,270,270,270,270,270,262,270,270,270,270,270,262,270,262,
270,270,262,270,270,262,270,270,270,270,270,270,270,270,270,270,
286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,
@@ -3731,8 +3745,8 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,
286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,
286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,
-286,286,286,286,286,286,286,286,286,286,286,286,286,286,955,955,
-955,955,955,955,286,286,286,286,286,286,286,286,286,286,286,286,
+286,286,286,286,286,286,286,286,286,286,286,286,286,286,954,954,
+954,954,954,954,286,286,286,286,286,286,286,286,286,286,286,286,
286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,
/* block 135 */
@@ -3749,7 +3763,7 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,
286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,
286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,
-286,286,286,286,286,286,286,286,286,286,286,286,286,286,956,957,
+286,286,286,286,286,286,286,286,286,286,286,286,286,286,955,956,
280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,
286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,
286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,
@@ -3761,19 +3775,19 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,
286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,
286,286,286,286,286,286,286,286,302,302,302,302,302,302,302,280,
-958,958,958,958,958,958,958,958,958,958,958,958,958,958,958,958,
-958,958,958,958,958,958,958,958,958,958,958,958,958,958,958,958,
-286,286,959,286,286,286,286,286,286,286,955,955,277,960,280,280,
+957,957,957,957,957,957,957,957,957,957,957,957,957,957,957,957,
+957,957,957,957,957,957,957,957,957,957,957,957,957,957,957,957,
+286,286,958,286,286,286,286,286,286,286,954,954,277,959,280,280,
/* block 138 */
-961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,962,
-963,963,963,964,963,963,963,965,966,963,163,163,163,163,163,163,
-154,154,154,154,154,154,154,154,154,154,154,154,154,154,855,855,
-963,967,967,700,700,965,966,965,966,965,966,965,966,965,966,965,
-966,968,969,968,969,798,798,965,966,963,963,963,963,700,700,700,
-970,166,971,163,166,972,973,973,967,974,975,974,975,974,975,976,
-963,977,713,978,979,979,715,163,977,431,976,963,163,163,163,163,
-955,286,955,286,955,302,955,286,955,286,955,286,955,286,955,286,
+960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,961,
+962,962,962,963,962,962,962,964,965,962,163,163,163,163,163,163,
+154,154,154,154,154,154,154,154,154,154,154,154,154,154,856,856,
+962,966,966,701,701,964,965,964,965,964,965,964,965,964,965,964,
+965,967,968,967,968,799,799,964,965,962,962,962,962,701,701,701,
+969,166,970,163,166,971,972,972,966,973,974,973,974,973,974,975,
+962,976,714,977,978,978,716,163,976,430,975,962,163,163,163,163,
+954,286,954,286,954,302,954,286,954,286,954,286,954,286,954,286,
/* block 139 */
286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,286,
@@ -3786,64 +3800,64 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
286,286,286,286,286,286,286,286,286,286,286,286,286,302,302, 51,
/* block 140 */
-163,973,980,976,431,976,963,981,974,975,963,713,970,982,971,983,
-984,984,984,984,984,984,984,984,984,984,972,166,979,715,979,973,
-963,985,985,985,985,985,985, 59, 59, 59, 59, 59, 59, 59, 59, 59,
- 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,974,977,975,986,700,
- 46,987,987,987,987,987,987, 62, 62, 62, 62, 62, 62, 62, 62, 62,
- 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,974,715,975,715,974,
-975,988,989,990,991,825,824,824,824,824,824,824,824,824,824,824,
-826,824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,
+163,972,979,975,430,975,962,980,973,974,962,714,969,981,970,982,
+983,983,983,983,983,983,983,983,983,983,971,166,978,716,978,972,
+962,984,984,984,984,984,984, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,973,976,974,985,701,
+ 46,986,986,986,986,986,986, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+ 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,973,716,974,716,973,
+974,987,988,989,990,826,825,825,825,825,825,825,825,825,825,825,
+827,825,825,825,825,825,825,825,825,825,825,825,825,825,825,825,
/* block 141 */
-824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,
-824,824,824,824,824,824,824,824,824,824,824,824,824,824,992,992,
-830,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
-829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,163,
-163,163,829,829,829,829,829,829,163,163,829,829,829,829,829,829,
-163,163,829,829,829,829,829,829,163,163,829,829,829,163,163,163,
-431,431,715, 46,723,431,431,163,723,715,715,715,715,723,723,163,
-707,707,707,707,707,707,707,707,707,993,993,993,723,723,958,958,
+825,825,825,825,825,825,825,825,825,825,825,825,825,825,825,825,
+825,825,825,825,825,825,825,825,825,825,825,825,825,825,991,991,
+831,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,163,
+163,163,830,830,830,830,830,830,163,163,830,830,830,830,830,830,
+163,163,830,830,830,830,830,830,163,163,830,830,830,163,163,163,
+430,430,716, 46,724,430,430,163,724,716,716,716,716,724,724,163,
+708,708,708,708,708,708,708,708,708,992,992,992,724,724,957,957,
/* block 142 */
-994,994,994,994,994,994,994,994,994,994,994,994,163,994,994,994,
-994,994,994,994,994,994,994,994,994,994,994,994,994,994,994,994,
-994,994,994,994,994,994,994,163,994,994,994,994,994,994,994,994,
-994,994,994,994,994,994,994,994,994,994,994,163,994,994,163,994,
-994,994,994,994,994,994,994,994,994,994,994,994,994,994,163,163,
-994,994,994,994,994,994,994,994,994,994,994,994,994,994,163,163,
+993,993,993,993,993,993,993,993,993,993,993,993,163,993,993,993,
+993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,
+993,993,993,993,993,993,993,163,993,993,993,993,993,993,993,993,
+993,993,993,993,993,993,993,993,993,993,993,163,993,993,163,993,
+993,993,993,993,993,993,993,993,993,993,993,993,993,993,163,163,
+993,993,993,993,993,993,993,993,993,993,993,993,993,993,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 143 */
-994,994,994,994,994,994,994,994,994,994,994,994,994,994,994,994,
-994,994,994,994,994,994,994,994,994,994,994,994,994,994,994,994,
-994,994,994,994,994,994,994,994,994,994,994,994,994,994,994,994,
-994,994,994,994,994,994,994,994,994,994,994,994,994,994,994,994,
-994,994,994,994,994,994,994,994,994,994,994,994,994,994,994,994,
-994,994,994,994,994,994,994,994,994,994,994,994,994,994,994,994,
-994,994,994,994,994,994,994,994,994,994,994,994,994,994,994,994,
-994,994,994,994,994,994,994,994,994,994,994,163,163,163,163,163,
+993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,
+993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,
+993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,
+993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,
+993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,
+993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,
+993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,993,
+993,993,993,993,993,993,993,993,993,993,993,163,163,163,163,163,
/* block 144 */
-995,996,997,163,163,163,163,998,998,998,998,998,998,998,998,998,
-998,998,998,998,998,998,998,998,998,998,998,998,998,998,998,998,
-998,998,998,998,998,998,998,998,998,998,998,998,998,998,998,998,
-998,998,998,998,163,163,163,999,999,999,999,999,999,999,999,999,
-1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,
-1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,
-1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,
-1000,1000,1000,1000,1000,1001,1001,1001,1001,1002,1002,1002,1002,1002,1002,1002,
+994,995,996,163,163,163,163,997,997,997,997,997,997,997,997,997,
+997,997,997,997,997,997,997,997,997,997,997,997,997,997,997,997,
+997,997,997,997,997,997,997,997,997,997,997,997,997,997,997,997,
+997,997,997,997,163,163,163,998,998,998,998,998,998,998,998,998,
+999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,
+999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,
+999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,999,
+999,999,999,999,999,1000,1000,1000,1000,1001,1001,1001,1001,1001,1001,1001,
/* block 145 */
-1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1001,1001,1002,1003,1003,163,
-723,723,723,723,723,723,723,723,723,723,723,723,723,163,163,163,
-1002,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1000,1000,1001,1002,1002,163,
+724,724,724,724,724,724,724,724,724,724,724,724,724,163,163,163,
+1001,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,158,163,163,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,158,163,163,
/* block 146 */
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
@@ -3856,97 +3870,97 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 147 */
+1003,1003,1003,1003,1003,1003,1003,1003,1003,1003,1003,1003,1003,1003,1003,1003,
+1003,1003,1003,1003,1003,1003,1003,1003,1003,1003,1003,1003,1003,163,163,163,
+1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,
+1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,
1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,
-1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,1004,163,163,163,
-1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,
-1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,
-1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,1005,
-1005,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-1006,1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,
-1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,163,163,163,163,
+1004,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+1005,1006,1006,1006,1006,1006,1006,1006,1006,1006,1006,1006,1006,1006,1006,1006,
+1006,1006,1006,1006,1006,1006,1006,1006,1006,1006,1006,1006,163,163,163,163,
/* block 148 */
-1008,1008,1008,1008,1008,1008,1008,1008,1008,1008,1008,1008,1008,1008,1008,1008,
-1008,1008,1008,1008,1008,1008,1008,1008,1008,1008,1008,1008,1008,1008,1008,1008,
-1009,1009,1009,1009,163,163,163,163,163,163,163,163,163,1008,1008,1008,
-1010,1010,1010,1010,1010,1010,1010,1010,1010,1010,1010,1010,1010,1010,1010,1010,
-1010,1011,1010,1010,1010,1010,1010,1010,1010,1010,1011,163,163,163,163,163,
-1012,1012,1012,1012,1012,1012,1012,1012,1012,1012,1012,1012,1012,1012,1012,1012,
-1012,1012,1012,1012,1012,1012,1012,1012,1012,1012,1012,1012,1012,1012,1012,1012,
-1012,1012,1012,1012,1012,1012,1013,1013,1013,1013,1013,163,163,163,163,163,
+1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,
+1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,1007,
+1008,1008,1008,1008,163,163,163,163,163,163,163,163,163,1007,1007,1007,
+1009,1009,1009,1009,1009,1009,1009,1009,1009,1009,1009,1009,1009,1009,1009,1009,
+1009,1010,1009,1009,1009,1009,1009,1009,1009,1009,1010,163,163,163,163,163,
+1011,1011,1011,1011,1011,1011,1011,1011,1011,1011,1011,1011,1011,1011,1011,1011,
+1011,1011,1011,1011,1011,1011,1011,1011,1011,1011,1011,1011,1011,1011,1011,1011,
+1011,1011,1011,1011,1011,1011,1012,1012,1012,1012,1012,163,163,163,163,163,
/* block 149 */
-1014,1014,1014,1014,1014,1014,1014,1014,1014,1014,1014,1014,1014,1014,1014,1014,
-1014,1014,1014,1014,1014,1014,1014,1014,1014,1014,1014,1014,1014,1014,163,1015,
-1016,1016,1016,1016,1016,1016,1016,1016,1016,1016,1016,1016,1016,1016,1016,1016,
-1016,1016,1016,1016,1016,1016,1016,1016,1016,1016,1016,1016,1016,1016,1016,1016,
-1016,1016,1016,1016,163,163,163,163,1016,1016,1016,1016,1016,1016,1016,1016,
-1017,1018,1018,1018,1018,1018,163,163,163,163,163,163,163,163,163,163,
+1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,
+1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,1013,163,1014,
+1015,1015,1015,1015,1015,1015,1015,1015,1015,1015,1015,1015,1015,1015,1015,1015,
+1015,1015,1015,1015,1015,1015,1015,1015,1015,1015,1015,1015,1015,1015,1015,1015,
+1015,1015,1015,1015,163,163,163,163,1015,1015,1015,1015,1015,1015,1015,1015,
+1016,1017,1017,1017,1017,1017,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 150 */
+1018,1018,1018,1018,1018,1018,1018,1018,1018,1018,1018,1018,1018,1018,1018,1018,
+1018,1018,1018,1018,1018,1018,1018,1018,1018,1018,1018,1018,1018,1018,1018,1018,
+1018,1018,1018,1018,1018,1018,1018,1018,1019,1019,1019,1019,1019,1019,1019,1019,
1019,1019,1019,1019,1019,1019,1019,1019,1019,1019,1019,1019,1019,1019,1019,1019,
1019,1019,1019,1019,1019,1019,1019,1019,1019,1019,1019,1019,1019,1019,1019,1019,
-1019,1019,1019,1019,1019,1019,1019,1019,1020,1020,1020,1020,1020,1020,1020,1020,
1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,
1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,
-1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,
-1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,
-1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,
+1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,1020,
/* block 151 */
-1022,1022,1022,1022,1022,1022,1022,1022,1022,1022,1022,1022,1022,1022,1022,1022,
-1022,1022,1022,1022,1022,1022,1022,1022,1022,1022,1022,1022,1022,1022,163,163,
-1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,163,163,163,163,163,163,
-1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,
+1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,
+1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,1021,163,163,
+1022,1022,1022,1022,1022,1022,1022,1022,1022,1022,163,163,163,163,163,163,
+1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,
+1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,
+1023,1023,1023,1023,163,163,163,163,1024,1024,1024,1024,1024,1024,1024,1024,
1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,
-1024,1024,1024,1024,163,163,163,163,1025,1025,1025,1025,1025,1025,1025,1025,
-1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,
-1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,163,163,163,163,
+1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,1024,163,163,163,163,
/* block 152 */
+1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,
+1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,1025,
+1025,1025,1025,1025,1025,1025,1025,1025,163,163,163,163,163,163,163,163,
1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,
1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,
-1026,1026,1026,1026,1026,1026,1026,1026,163,163,163,163,163,163,163,163,
-1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,
-1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,
-1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,1027,
-1027,1027,1027,1027,163,163,163,163,163,163,163,163,163,163,163,1028,
-1029,1029,1029,1029,1029,1029,1029,1029,1029,1029,1029,163,1029,1029,1029,1029,
+1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,1026,
+1026,1026,1026,1026,163,163,163,163,163,163,163,163,163,163,163,1027,
+1028,1028,1028,1028,1028,1028,1028,1028,1028,1028,1028,163,1028,1028,1028,1028,
/* block 153 */
-1029,1029,1029,1029,1029,1029,1029,1029,1029,1029,1029,163,1029,1029,1029,1029,
-1029,1029,1029,163,1029,1029,163,1030,1030,1030,1030,1030,1030,1030,1030,1030,
-1030,1030,163,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,
-1030,1030,163,1030,1030,1030,1030,1030,1030,1030,163,1030,1030,163,163,163,
+1028,1028,1028,1028,1028,1028,1028,1028,1028,1028,1028,163,1028,1028,1028,1028,
+1028,1028,1028,163,1028,1028,163,1029,1029,1029,1029,1029,1029,1029,1029,1029,
+1029,1029,163,1029,1029,1029,1029,1029,1029,1029,1029,1029,1029,1029,1029,1029,
+1029,1029,163,1029,1029,1029,1029,1029,1029,1029,163,1029,1029,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 154 */
-1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,
-1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,
-1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,
-1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,
-1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,
-1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,
-1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,
-1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,
+1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,
+1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,
+1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,
+1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,
+1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,
+1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,
+1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,
+1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,
/* block 155 */
-1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,
-1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,
-1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,
-1031,1031,1031,1031,1031,1031,1031,163,163,163,163,163,163,163,163,163,
-1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,1031,
-1031,1031,1031,1031,1031,1031,163,163,163,163,163,163,163,163,163,163,
-1031,1031,1031,1031,1031,1031,1031,1031,163,163,163,163,163,163,163,163,
+1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,
+1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,
+1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,
+1030,1030,1030,1030,1030,1030,1030,163,163,163,163,163,163,163,163,163,
+1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,1030,
+1030,1030,1030,1030,1030,1030,163,163,163,163,163,163,163,163,163,163,
+1030,1030,1030,1030,1030,1030,1030,1030,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 156 */
-147,1032,1032,147,147,147,163,147,147,147,147,147,147,147,147,147,
+147,1031,1031,147,147,147,163,147,147,147,147,147,147,147,147,147,
147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,
147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,
147,163,147,147,147,147,147,147,147,147,147,163,163,163,163,163,
@@ -3956,79 +3970,79 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 157 */
-1033,1033,1033,1033,1033,1033,262,262,1033,262,1033,1033,1033,1033,1033,1033,
-1033,1033,1033,1033,1033,1033,1033,1033,1033,1033,1033,1033,1033,1033,1033,1033,
+1032,1032,1032,1032,1032,1032,262,262,1032,262,1032,1032,1032,1032,1032,1032,
+1032,1032,1032,1032,1032,1032,1032,1032,1032,1032,1032,1032,1032,1032,1032,1032,
+1032,1032,1032,1032,1032,1032,1032,1032,1032,1032,1032,1032,1032,1032,1032,1032,
+1032,1032,1032,1032,1032,1032,262,1032,1032,262,262,262,1032,262,262,1032,
1033,1033,1033,1033,1033,1033,1033,1033,1033,1033,1033,1033,1033,1033,1033,1033,
-1033,1033,1033,1033,1033,1033,262,1033,1033,262,262,262,1033,262,262,1033,
-1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,1034,
-1034,1034,1034,1034,1034,1034,262,1035,1036,1036,1036,1036,1036,1036,1036,1036,
-1037,1037,1037,1037,1037,1037,1037,1037,1037,1037,1037,1037,1037,1037,1037,1037,
-1037,1037,1037,1037,1037,1037,1037,1038,1038,1039,1039,1039,1039,1039,1039,1039,
+1033,1033,1033,1033,1033,1033,262,1034,1035,1035,1035,1035,1035,1035,1035,1035,
+1036,1036,1036,1036,1036,1036,1036,1036,1036,1036,1036,1036,1036,1036,1036,1036,
+1036,1036,1036,1036,1036,1036,1036,1037,1037,1038,1038,1038,1038,1038,1038,1038,
/* block 158 */
-1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,
-1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,1040,262,
-262,262,262,262,262,262,262,1041,1041,1041,1041,1041,1041,1041,1041,1041,
+1039,1039,1039,1039,1039,1039,1039,1039,1039,1039,1039,1039,1039,1039,1039,1039,
+1039,1039,1039,1039,1039,1039,1039,1039,1039,1039,1039,1039,1039,1039,1039,262,
+262,262,262,262,262,262,262,1040,1040,1040,1040,1040,1040,1040,1040,1040,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
-1042,1042,1042,1042,1042,1042,1042,1042,1042,1042,1042,1042,1042,1042,1042,1042,
-1042,1042,1042,262,1042,1042,262,262,262,262,262,1043,1043,1043,1043,1043,
+1041,1041,1041,1041,1041,1041,1041,1041,1041,1041,1041,1041,1041,1041,1041,1041,
+1041,1041,1041,262,1041,1041,262,262,262,262,262,1042,1042,1042,1042,1042,
/* block 159 */
-1044,1044,1044,1044,1044,1044,1044,1044,1044,1044,1044,1044,1044,1044,1044,1044,
-1044,1044,1044,1044,1044,1044,1045,1045,1045,1045,1045,1045,262,262,262,1046,
-1047,1047,1047,1047,1047,1047,1047,1047,1047,1047,1047,1047,1047,1047,1047,1047,
-1047,1047,1047,1047,1047,1047,1047,1047,1047,1047,262,262,262,262,262,1048,
+1043,1043,1043,1043,1043,1043,1043,1043,1043,1043,1043,1043,1043,1043,1043,1043,
+1043,1043,1043,1043,1043,1043,1044,1044,1044,1044,1044,1044,262,262,262,1045,
+1046,1046,1046,1046,1046,1046,1046,1046,1046,1046,1046,1046,1046,1046,1046,1046,
+1046,1046,1046,1046,1046,1046,1046,1046,1046,1046,262,262,262,262,262,1047,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
/* block 160 */
+1048,1048,1048,1048,1048,1048,1048,1048,1048,1048,1048,1048,1048,1048,1048,1048,
+1048,1048,1048,1048,1048,1048,1048,1048,1048,1048,1048,1048,1048,1048,1048,1048,
1049,1049,1049,1049,1049,1049,1049,1049,1049,1049,1049,1049,1049,1049,1049,1049,
-1049,1049,1049,1049,1049,1049,1049,1049,1049,1049,1049,1049,1049,1049,1049,1049,
+1049,1049,1049,1049,1049,1049,1049,1049,262,262,262,262,1050,1050,1049,1049,
+1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,
+262,262,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,
+1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,
1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,1050,
-1050,1050,1050,1050,1050,1050,1050,1050,262,262,262,262,1051,1051,1050,1050,
-1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,
-262,262,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,
-1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,
-1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,
/* block 161 */
-1052,1053,1053,1053,262,1053,1053,262,262,262,262,262,1053,1053,1053,1053,
-1052,1052,1052,1052,262,1052,1052,1052,262,1052,1052,1052,1052,1052,1052,1052,
-1052,1052,1052,1052,1052,1052,1052,1052,1052,1052,1052,1052,1052,1052,1052,1052,
-1052,1052,1052,1052,1052,1052,262,262,1054,1054,1054,262,262,262,262,1055,
-1056,1056,1056,1056,1056,1056,1056,1056,1056,262,262,262,262,262,262,262,
-1057,1057,1057,1057,1057,1057,1058,1058,1057,262,262,262,262,262,262,262,
-1059,1059,1059,1059,1059,1059,1059,1059,1059,1059,1059,1059,1059,1059,1059,1059,
-1059,1059,1059,1059,1059,1059,1059,1059,1059,1059,1059,1059,1059,1060,1060,1061,
+1051,1052,1052,1052,262,1052,1052,262,262,262,262,262,1052,1052,1052,1052,
+1051,1051,1051,1051,262,1051,1051,1051,262,1051,1051,1051,1051,1051,1051,1051,
+1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,1051,
+1051,1051,1051,1051,1051,1051,262,262,1053,1053,1053,262,262,262,262,1054,
+1055,1055,1055,1055,1055,1055,1055,1055,1055,262,262,262,262,262,262,262,
+1056,1056,1056,1056,1056,1056,1057,1057,1056,262,262,262,262,262,262,262,
+1058,1058,1058,1058,1058,1058,1058,1058,1058,1058,1058,1058,1058,1058,1058,1058,
+1058,1058,1058,1058,1058,1058,1058,1058,1058,1058,1058,1058,1058,1059,1059,1060,
/* block 162 */
-1062,1062,1062,1062,1062,1062,1062,1062,1062,1062,1062,1062,1062,1062,1062,1062,
-1062,1062,1062,1062,1062,1062,1062,1062,1062,1062,1062,1062,1062,1063,1063,1063,
+1061,1061,1061,1061,1061,1061,1061,1061,1061,1061,1061,1061,1061,1061,1061,1061,
+1061,1061,1061,1061,1061,1061,1061,1061,1061,1061,1061,1061,1061,1062,1062,1062,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
-1064,1064,1064,1064,1064,1064,1064,1064,1065,1064,1064,1064,1064,1064,1064,1064,
-1064,1064,1064,1064,1064,1064,1064,1064,1064,1064,1064,1064,1064,1064,1064,1064,
-1064,1064,1064,1064,1064,1066,1066,262,262,262,262,1067,1067,1067,1067,1067,
-1068,1068,1069,1068,1068,1068,1070,262,262,262,262,262,262,262,262,262,
+1063,1063,1063,1063,1063,1063,1063,1063,1064,1063,1063,1063,1063,1063,1063,1063,
+1063,1063,1063,1063,1063,1063,1063,1063,1063,1063,1063,1063,1063,1063,1063,1063,
+1063,1063,1063,1063,1063,1065,1065,262,262,262,262,1066,1066,1066,1066,1066,
+1067,1067,1068,1067,1067,1067,1069,262,262,262,262,262,262,262,262,262,
/* block 163 */
-1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,
-1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,
-1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,1071,
-1071,1071,1071,1071,1071,1071,262,262,262,1072,1073,1073,1073,1073,1073,1073,
-1074,1074,1074,1074,1074,1074,1074,1074,1074,1074,1074,1074,1074,1074,1074,1074,
-1074,1074,1074,1074,1074,1074,262,262,1075,1075,1075,1075,1075,1075,1075,1075,
-1076,1076,1076,1076,1076,1076,1076,1076,1076,1076,1076,1076,1076,1076,1076,1076,
-1076,1076,1076,262,262,262,262,262,1077,1077,1077,1077,1077,1077,1077,1077,
+1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,
+1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,
+1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,1070,
+1070,1070,1070,1070,1070,1070,262,262,262,1071,1072,1072,1072,1072,1072,1072,
+1073,1073,1073,1073,1073,1073,1073,1073,1073,1073,1073,1073,1073,1073,1073,1073,
+1073,1073,1073,1073,1073,1073,262,262,1074,1074,1074,1074,1074,1074,1074,1074,
+1075,1075,1075,1075,1075,1075,1075,1075,1075,1075,1075,1075,1075,1075,1075,1075,
+1075,1075,1075,262,262,262,262,262,1076,1076,1076,1076,1076,1076,1076,1076,
/* block 164 */
-1078,1078,1078,1078,1078,1078,1078,1078,1078,1078,1078,1078,1078,1078,1078,1078,
-1078,1078,262,262,262,262,262,262,262,1079,1079,1079,1079,262,262,262,
-262,262,262,262,262,262,262,262,262,1080,1080,1080,1080,1080,1080,1080,
+1077,1077,1077,1077,1077,1077,1077,1077,1077,1077,1077,1077,1077,1077,1077,1077,
+1077,1077,262,262,262,262,262,262,262,1078,1078,1078,1078,262,262,262,
+262,262,262,262,262,262,262,262,262,1079,1079,1079,1079,1079,1079,1079,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
@@ -4036,30 +4050,30 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
/* block 165 */
-1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,
-1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,
-1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,
-1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,
-1081,1081,1081,1081,1081,1081,1081,1081,1081,262,262,262,262,262,262,262,
+1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,
+1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,
+1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,
+1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,1080,
+1080,1080,1080,1080,1080,1080,1080,1080,1080,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
/* block 166 */
+1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,
+1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,
+1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,1081,
+1081,1081,1081,262,262,262,262,262,262,262,262,262,262,262,262,262,
1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,
1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,
1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,1082,
-1082,1082,1082,262,262,262,262,262,262,262,262,262,262,262,262,262,
-1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,
-1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,
-1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,1083,
-1083,1083,1083,262,262,262,262,262,262,262,1084,1084,1084,1084,1084,1084,
+1082,1082,1082,262,262,262,262,262,262,262,1083,1083,1083,1083,1083,1083,
/* block 167 */
-1085,1085,1085,1085,1085,1085,1085,1085,1085,1085,1085,1085,1085,1085,1085,1085,
-1085,1085,1085,1085,1085,1085,1085,1085,1085,1085,1085,1085,1085,1085,1085,1085,
-1085,1085,1086,1086,1087,1087,1087,1087,302,302,302,302,302,302,302,302,
-1088,1088,1088,1088,1088,1088,1088,1088,1088,1088,302,302,302,302,302,302,
+1084,1084,1084,1084,1084,1084,1084,1084,1084,1084,1084,1084,1084,1084,1084,1084,
+1084,1084,1084,1084,1084,1084,1084,1084,1084,1084,1084,1084,1084,1084,1084,1084,
+1084,1084,1085,1085,1086,1086,1086,1086,302,302,302,302,302,302,302,302,
+1087,1087,1087,1087,1087,1087,1087,1087,1087,1087,302,302,302,302,302,302,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
@@ -4082,174 +4096,174 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
-1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,
-1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,262,
+1088,1088,1088,1088,1088,1088,1088,1088,1088,1088,1088,1088,1088,1088,1088,1088,
+1088,1088,1088,1088,1088,1088,1088,1088,1088,1088,1088,1088,1088,1088,1088,262,
/* block 170 */
-1090,1090,1090,1090,1090,1090,1090,1090,1090,1090,1090,1090,1090,1090,1090,1090,
-1090,1090,1090,1090,1090,1090,1090,1090,1090,1090,1090,1090,1090,1090,1090,1090,
-1090,1090,1090,1090,1090,1090,1090,1090,1090,1090,262,1091,1091,1092,262,262,
-1090,1090,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
-262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
-262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
-262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
-262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
+1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,
+1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,
+1089,1089,1089,1089,1089,1089,1089,1089,1089,1089,262,1090,1090,1091,262,262,
+1089,1089,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
+302,302,302,302,302,302,302,302,302,302,302,302,302,302,302,302,
+302,302,302,302,302,302,302,302,302,302,302,302,302,302,302,302,
+302,302,302,302,302,302,302,302,302,302,302,302,302,302,302,302,
+302,302,302,302,302,302,302,302,302,302,302,302,302,291,291,291,
/* block 171 */
-1093,1093,1093,1093,1093,1093,1093,1093,1093,1093,1093,1093,1093,1093,1093,1093,
-1093,1093,1093,1093,1093,1093,1093,1093,1093,1093,1093,1093,1093,1094,1094,1094,
-1094,1094,1094,1094,1094,1094,1094,1093,262,262,262,262,262,262,262,262,
-1095,1095,1095,1095,1095,1095,1095,1095,1095,1095,1095,1095,1095,1095,1095,1095,
-1095,1095,1095,1095,1095,1095,1096,1096,1096,1096,1096,1096,1096,1096,1096,1096,
-1096,1097,1097,1097,1097,1098,1098,1098,1098,1098,302,302,302,302,302,302,
+1092,1092,1092,1092,1092,1092,1092,1092,1092,1092,1092,1092,1092,1092,1092,1092,
+1092,1092,1092,1092,1092,1092,1092,1092,1092,1092,1092,1092,1092,1093,1093,1093,
+1093,1093,1093,1093,1093,1093,1093,1092,262,262,262,262,262,262,262,262,
+1094,1094,1094,1094,1094,1094,1094,1094,1094,1094,1094,1094,1094,1094,1094,1094,
+1094,1094,1094,1094,1094,1094,1095,1095,1095,1095,1095,1095,1095,1095,1095,1095,
+1095,1096,1096,1096,1096,1097,1097,1097,1097,1097,302,302,302,302,302,302,
302,302,302,302,302,302,302,302,302,302,302,302,302,302,302,302,
-1099,1099,1099,1099,1099,1099,1099,1099,1099,1099,1099,1099,1099,1099,1099,1099,
+1098,1098,1098,1098,1098,1098,1098,1098,1098,1098,1098,1098,1098,1098,1098,1098,
/* block 172 */
-1099,1099,1100,1100,1100,1100,1101,1101,1101,1101,262,262,262,262,262,262,
+1098,1098,1099,1099,1099,1099,1100,1100,1100,1100,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
-1102,1102,1102,1102,1102,1102,1102,1102,1102,1102,1102,1102,1102,1102,1102,1102,
-1102,1102,1102,1102,1102,1103,1103,1103,1103,1103,1103,1103,262,262,262,262,
+1101,1101,1101,1101,1101,1101,1101,1101,1101,1101,1101,1101,1101,1101,1101,1101,
+1101,1101,1101,1101,1101,1102,1102,1102,1102,1102,1102,1102,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
-1104,1104,1104,1104,1104,1104,1104,1104,1104,1104,1104,1104,1104,1104,1104,1104,
-1104,1104,1104,1104,1104,1104,1104,262,262,262,262,262,262,262,262,262,
+1103,1103,1103,1103,1103,1103,1103,1103,1103,1103,1103,1103,1103,1103,1103,1103,
+1103,1103,1103,1103,1103,1103,1103,262,262,262,262,262,262,262,262,262,
/* block 173 */
-1105,1106,1105,1107,1107,1107,1107,1107,1107,1107,1107,1107,1107,1107,1107,1107,
-1107,1107,1107,1107,1107,1107,1107,1107,1107,1107,1107,1107,1107,1107,1107,1107,
-1107,1107,1107,1107,1107,1107,1107,1107,1107,1107,1107,1107,1107,1107,1107,1107,
-1107,1107,1107,1107,1107,1107,1107,1107,1106,1106,1106,1106,1106,1106,1106,1106,
-1106,1106,1106,1106,1106,1106,1108,1109,1109,1110,1110,1110,1110,1110,163,163,
-163,163,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,
-1111,1111,1111,1111,1111,1111,1112,1112,1112,1112,1112,1112,1112,1112,1112,1112,
-1108,1107,1107,1106,1106,1107,163,163,163,163,163,163,163,163,163,1113,
+1104,1105,1104,1106,1106,1106,1106,1106,1106,1106,1106,1106,1106,1106,1106,1106,
+1106,1106,1106,1106,1106,1106,1106,1106,1106,1106,1106,1106,1106,1106,1106,1106,
+1106,1106,1106,1106,1106,1106,1106,1106,1106,1106,1106,1106,1106,1106,1106,1106,
+1106,1106,1106,1106,1106,1106,1106,1106,1105,1105,1105,1105,1105,1105,1105,1105,
+1105,1105,1105,1105,1105,1105,1107,1108,1108,1109,1109,1109,1109,1109,163,163,
+163,163,1110,1110,1110,1110,1110,1110,1110,1110,1110,1110,1110,1110,1110,1110,
+1110,1110,1110,1110,1110,1110,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,
+1107,1106,1106,1105,1105,1106,163,163,163,163,163,163,163,163,163,1112,
/* block 174 */
-1114,1114,1115,1116,1116,1116,1116,1116,1116,1116,1116,1116,1116,1116,1116,1116,
-1116,1116,1116,1116,1116,1116,1116,1116,1116,1116,1116,1116,1116,1116,1116,1116,
-1116,1116,1116,1116,1116,1116,1116,1116,1116,1116,1116,1116,1116,1116,1116,1116,
-1115,1115,1115,1117,1117,1117,1117,1115,1115,1118,1119,1120,1120,1121,1122,1122,
-1122,1122,1117,163,163,163,163,163,163,163,163,163,163,1121,163,163,
-1123,1123,1123,1123,1123,1123,1123,1123,1123,1123,1123,1123,1123,1123,1123,1123,
-1123,1123,1123,1123,1123,1123,1123,1123,1123,163,163,163,163,163,163,163,
-1124,1124,1124,1124,1124,1124,1124,1124,1124,1124,163,163,163,163,163,163,
+1113,1113,1114,1115,1115,1115,1115,1115,1115,1115,1115,1115,1115,1115,1115,1115,
+1115,1115,1115,1115,1115,1115,1115,1115,1115,1115,1115,1115,1115,1115,1115,1115,
+1115,1115,1115,1115,1115,1115,1115,1115,1115,1115,1115,1115,1115,1115,1115,1115,
+1114,1114,1114,1113,1113,1113,1113,1114,1114,1116,1117,1118,1118,1119,1120,1120,
+1120,1120,1113,163,163,163,163,163,163,163,163,163,163,1119,163,163,
+1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,1121,
+1121,1121,1121,1121,1121,1121,1121,1121,1121,163,163,163,163,163,163,163,
+1122,1122,1122,1122,1122,1122,1122,1122,1122,1122,163,163,163,163,163,163,
/* block 175 */
-1125,1125,1125,1126,1126,1126,1126,1126,1126,1126,1126,1126,1126,1126,1126,1126,
-1126,1126,1126,1126,1126,1126,1126,1126,1126,1126,1126,1126,1126,1126,1126,1126,
-1126,1126,1126,1126,1126,1126,1126,1125,1125,1125,1125,1125,1127,1125,1125,1125,
-1125,1125,1125,1128,1128,163,1129,1129,1129,1129,1129,1129,1129,1129,1129,1129,
-1130,1131,1131,1131,1126,1127,1127,1126,163,163,163,163,163,163,163,163,
-1132,1132,1132,1132,1132,1132,1132,1132,1132,1132,1132,1132,1132,1132,1132,1132,
-1132,1132,1132,1132,1132,1132,1132,1132,1132,1132,1132,1132,1132,1132,1132,1132,
-1132,1132,1132,1133,1134,1134,1132,163,163,163,163,163,163,163,163,163,
+1123,1123,1123,1124,1124,1124,1124,1124,1124,1124,1124,1124,1124,1124,1124,1124,
+1124,1124,1124,1124,1124,1124,1124,1124,1124,1124,1124,1124,1124,1124,1124,1124,
+1124,1124,1124,1124,1124,1124,1124,1123,1123,1123,1123,1123,1125,1123,1123,1123,
+1123,1123,1123,1126,1126,163,1127,1127,1127,1127,1127,1127,1127,1127,1127,1127,
+1128,1129,1129,1129,1124,1125,1125,1124,163,163,163,163,163,163,163,163,
+1130,1130,1130,1130,1130,1130,1130,1130,1130,1130,1130,1130,1130,1130,1130,1130,
+1130,1130,1130,1130,1130,1130,1130,1130,1130,1130,1130,1130,1130,1130,1130,1130,
+1130,1130,1130,1131,1132,1132,1130,163,163,163,163,163,163,163,163,163,
/* block 176 */
-1135,1135,1136,1137,1137,1137,1137,1137,1137,1137,1137,1137,1137,1137,1137,1137,
-1137,1137,1137,1137,1137,1137,1137,1137,1137,1137,1137,1137,1137,1137,1137,1137,
-1137,1137,1137,1137,1137,1137,1137,1137,1137,1137,1137,1137,1137,1137,1137,1137,
-1137,1137,1137,1136,1136,1136,1135,1135,1135,1135,1135,1135,1135,1135,1135,1136,
-1138,1137,1139,1139,1137,1140,1140,1141,1141,1142,1143,1143,1143,1140,1136,1135,
-1144,1144,1144,1144,1144,1144,1144,1144,1144,1144,1137,1141,1137,1141,1140,1140,
-163,1145,1145,1145,1145,1145,1145,1145,1145,1145,1145,1145,1145,1145,1145,1145,
-1145,1145,1145,1145,1145,163,163,163,163,163,163,163,163,163,163,163,
+1133,1133,1134,1135,1135,1135,1135,1135,1135,1135,1135,1135,1135,1135,1135,1135,
+1135,1135,1135,1135,1135,1135,1135,1135,1135,1135,1135,1135,1135,1135,1135,1135,
+1135,1135,1135,1135,1135,1135,1135,1135,1135,1135,1135,1135,1135,1135,1135,1135,
+1135,1135,1135,1134,1134,1134,1133,1133,1133,1133,1133,1133,1133,1133,1133,1134,
+1136,1135,1137,1137,1135,1138,1138,1139,1139,1140,1141,1141,1141,1138,1134,1133,
+1142,1142,1142,1142,1142,1142,1142,1142,1142,1142,1135,1139,1135,1139,1138,1138,
+163,1143,1143,1143,1143,1143,1143,1143,1143,1143,1143,1143,1143,1143,1143,1143,
+1143,1143,1143,1143,1143,163,163,163,163,163,163,163,163,163,163,163,
/* block 177 */
-1146,1146,1146,1146,1146,1146,1146,1146,1146,1146,1146,1146,1146,1146,1146,1146,
-1146,1146,163,1146,1146,1146,1146,1146,1146,1146,1146,1146,1146,1146,1146,1146,
-1146,1146,1146,1146,1146,1146,1146,1146,1146,1146,1146,1146,1147,1147,1147,1148,
-1148,1148,1147,1147,1148,1149,1150,1148,1151,1151,1152,1151,1151,1153,1148,163,
-163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+1144,1144,1144,1144,1144,1144,1144,1144,1144,1144,1144,1144,1144,1144,1144,1144,
+1144,1144,163,1144,1144,1144,1144,1144,1144,1144,1144,1144,1144,1144,1144,1144,
+1144,1144,1144,1144,1144,1144,1144,1144,1144,1144,1144,1144,1145,1145,1145,1146,
+1146,1146,1145,1145,1146,1147,1148,1146,1149,1149,1150,1149,1149,1151,1146,1144,
+1144,1146,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 178 */
-1154,1154,1154,1154,1154,1154,1154,163,1154,163,1154,1154,1154,1154,163,1154,
-1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,163,1154,
-1154,1154,1154,1154,1154,1154,1154,1154,1154,1155,163,163,163,163,163,163,
-1156,1156,1156,1156,1156,1156,1156,1156,1156,1156,1156,1156,1156,1156,1156,1156,
-1156,1156,1156,1156,1156,1156,1156,1156,1156,1156,1156,1156,1156,1156,1156,1156,
-1156,1156,1156,1156,1156,1156,1156,1156,1156,1156,1156,1156,1156,1156,1156,1157,
-1158,1158,1158,1157,1157,1157,1157,1157,1157,1159,1160,163,163,163,163,163,
-1161,1161,1161,1161,1161,1161,1161,1161,1161,1161,163,163,163,163,163,163,
+1152,1152,1152,1152,1152,1152,1152,163,1152,163,1152,1152,1152,1152,163,1152,
+1152,1152,1152,1152,1152,1152,1152,1152,1152,1152,1152,1152,1152,1152,163,1152,
+1152,1152,1152,1152,1152,1152,1152,1152,1152,1153,163,163,163,163,163,163,
+1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,
+1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,
+1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1154,1155,
+1156,1156,1156,1155,1155,1155,1155,1155,1155,1157,1158,163,163,163,163,163,
+1159,1159,1159,1159,1159,1159,1159,1159,1159,1159,163,163,163,163,163,163,
/* block 179 */
-1162,1163,1164,1165,163,1166,1166,1166,1166,1166,1166,1166,1166,163,163,1166,
-1166,163,163,1166,1166,1166,1166,1166,1166,1166,1166,1166,1166,1166,1166,1166,
-1166,1166,1166,1166,1166,1166,1166,1166,1166,163,1166,1166,1166,1166,1166,1166,
-1166,163,1166,1166,163,1166,1166,1166,1166,1166,163,1167,1168,1166,1169,1164,
-1162,1164,1164,1164,1164,163,163,1164,1164,163,163,1164,1164,1170,163,163,
-1166,163,163,163,163,163,163,1169,163,163,163,163,163,1171,1166,1166,
-1166,1166,1164,1164,163,163,1172,1172,1172,1172,1172,1172,1172,163,163,163,
-1172,1172,1172,1172,1172,163,163,163,163,163,163,163,163,163,163,163,
+1160,1161,1162,1163,163,1164,1164,1164,1164,1164,1164,1164,1164,163,163,1164,
+1164,163,163,1164,1164,1164,1164,1164,1164,1164,1164,1164,1164,1164,1164,1164,
+1164,1164,1164,1164,1164,1164,1164,1164,1164,163,1164,1164,1164,1164,1164,1164,
+1164,163,1164,1164,163,1164,1164,1164,1164,1164,163,1165,1166,1164,1167,1162,
+1160,1162,1162,1162,1162,163,163,1162,1162,163,163,1162,1162,1168,163,163,
+1164,163,163,163,163,163,163,1167,163,163,163,163,163,1169,1164,1164,
+1164,1164,1162,1162,163,163,1170,1170,1170,1170,1170,1170,1170,163,163,163,
+1170,1170,1170,1170,1170,163,163,163,163,163,163,163,163,163,163,163,
/* block 180 */
-1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,
-1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,
-1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,1173,
-1173,1173,1173,1173,1173,1174,1174,1174,1175,1175,1175,1175,1175,1175,1175,1175,
-1174,1174,1176,1175,1175,1174,1177,1173,1173,1173,1173,1178,1178,1179,1180,1180,
-1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,1179,1179,163,1180,1182,1173,
-1173,1173,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,
+1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,
+1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,1171,
+1171,1171,1171,1171,1171,1172,1172,1172,1173,1173,1173,1173,1173,1173,1173,1173,
+1172,1172,1174,1173,1173,1172,1175,1171,1171,1171,1171,1176,1176,1177,1178,1178,
+1179,1179,1179,1179,1179,1179,1179,1179,1179,1179,1177,1177,163,1178,1180,1171,
+1171,1171,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 181 */
-1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,
-1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,
-1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,1183,
-1184,1185,1185,1186,1186,1186,1186,1186,1186,1185,1186,1185,1185,1184,1185,1186,
-1186,1185,1187,1188,1183,1183,1189,1183,163,163,163,163,163,163,163,163,
-1190,1190,1190,1190,1190,1190,1190,1190,1190,1190,163,163,163,163,163,163,
+1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,
+1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,
+1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,1181,
+1182,1183,1183,1184,1184,1184,1184,1184,1184,1183,1184,1183,1183,1182,1183,1184,
+1184,1183,1185,1186,1181,1181,1187,1181,163,163,163,163,163,163,163,163,
+1188,1188,1188,1188,1188,1188,1188,1188,1188,1188,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 182 */
-1191,1191,1191,1191,1191,1191,1191,1191,1191,1191,1191,1191,1191,1191,1191,1191,
-1191,1191,1191,1191,1191,1191,1191,1191,1191,1191,1191,1191,1191,1191,1191,1191,
-1191,1191,1191,1191,1191,1191,1191,1191,1191,1191,1191,1191,1191,1191,1191,1192,
-1193,1193,1194,1194,1194,1194,163,163,1193,1193,1193,1193,1194,1194,1193,1195,
-1196,1197,1198,1198,1199,1199,1200,1200,1200,1198,1198,1198,1198,1198,1198,1198,
-1198,1198,1198,1198,1198,1198,1198,1198,1191,1191,1191,1191,1194,1194,163,163,
+1189,1189,1189,1189,1189,1189,1189,1189,1189,1189,1189,1189,1189,1189,1189,1189,
+1189,1189,1189,1189,1189,1189,1189,1189,1189,1189,1189,1189,1189,1189,1189,1189,
+1189,1189,1189,1189,1189,1189,1189,1189,1189,1189,1189,1189,1189,1189,1189,1190,
+1191,1191,1192,1192,1192,1192,163,163,1191,1191,1191,1191,1192,1192,1191,1193,
+1194,1195,1196,1196,1197,1197,1198,1198,1198,1196,1196,1196,1196,1196,1196,1196,
+1196,1196,1196,1196,1196,1196,1196,1196,1189,1189,1189,1189,1192,1192,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 183 */
-1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,
-1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,
-1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,1201,
-1202,1202,1202,1203,1203,1203,1203,1203,1203,1203,1203,1202,1202,1203,1202,1204,
-1203,1205,1205,1206,1201,163,163,163,163,163,163,163,163,163,163,163,
-1207,1207,1207,1207,1207,1207,1207,1207,1207,1207,163,163,163,163,163,163,
-530,530,530,530,530,530,530,530,530,530,530,530,530,163,163,163,
+1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,
+1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,
+1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,1199,
+1200,1200,1200,1201,1201,1201,1201,1201,1201,1201,1201,1200,1200,1201,1200,1202,
+1201,1203,1203,1204,1199,163,163,163,163,163,163,163,163,163,163,163,
+1205,1205,1205,1205,1205,1205,1205,1205,1205,1205,163,163,163,163,163,163,
+531,531,531,531,531,531,531,531,531,531,531,531,531,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 184 */
-1208,1208,1208,1208,1208,1208,1208,1208,1208,1208,1208,1208,1208,1208,1208,1208,
-1208,1208,1208,1208,1208,1208,1208,1208,1208,1208,1208,1208,1208,1208,1208,1208,
-1208,1208,1208,1208,1208,1208,1208,1208,1208,1208,1208,1209,1210,1209,1210,1210,
-1209,1209,1209,1209,1209,1209,1211,1212,1208,1213,163,163,163,163,163,163,
-1214,1214,1214,1214,1214,1214,1214,1214,1214,1214,163,163,163,163,163,163,
+1206,1206,1206,1206,1206,1206,1206,1206,1206,1206,1206,1206,1206,1206,1206,1206,
+1206,1206,1206,1206,1206,1206,1206,1206,1206,1206,1206,1206,1206,1206,1206,1206,
+1206,1206,1206,1206,1206,1206,1206,1206,1206,1206,1206,1207,1208,1207,1208,1208,
+1207,1207,1207,1207,1207,1207,1209,1210,1206,1211,163,163,163,163,163,163,
+1212,1212,1212,1212,1212,1212,1212,1212,1212,1212,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 185 */
-1215,1215,1215,1215,1215,1215,1215,1215,1215,1215,1215,1215,1215,1215,1215,1215,
-1215,1215,1215,1215,1215,1215,1215,1215,1215,1215,1215,163,163,1216,1216,1216,
-1217,1217,1216,1216,1216,1216,1218,1216,1216,1216,1216,1219,163,163,163,163,
-1220,1220,1220,1220,1220,1220,1220,1220,1220,1220,1221,1221,1222,1222,1222,1223,
-1215,1215,1215,1215,1215,1215,1215,163,163,163,163,163,163,163,163,163,
+1213,1213,1213,1213,1213,1213,1213,1213,1213,1213,1213,1213,1213,1213,1213,1213,
+1213,1213,1213,1213,1213,1213,1213,1213,1213,1213,1213,163,163,1214,1214,1214,
+1215,1215,1214,1214,1214,1214,1216,1214,1214,1214,1214,1217,163,163,163,163,
+1218,1218,1218,1218,1218,1218,1218,1218,1218,1218,1219,1219,1220,1220,1220,1221,
+1213,1213,1213,1213,1213,1213,1213,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 186 */
-1224,1224,1224,1224,1224,1224,1224,1224,1224,1224,1224,1224,1224,1224,1224,1224,
-1224,1224,1224,1224,1224,1224,1224,1224,1224,1224,1224,1224,1224,1224,1224,1224,
-1224,1224,1224,1224,1224,1224,1224,1224,1224,1224,1224,1224,1225,1225,1225,1226,
-1226,1226,1226,1226,1226,1226,1226,1226,1225,1227,1228,1229,163,163,163,163,
+1222,1222,1222,1222,1222,1222,1222,1222,1222,1222,1222,1222,1222,1222,1222,1222,
+1222,1222,1222,1222,1222,1222,1222,1222,1222,1222,1222,1222,1222,1222,1222,1222,
+1222,1222,1222,1222,1222,1222,1222,1222,1222,1222,1222,1222,1223,1223,1223,1224,
+1224,1224,1224,1224,1224,1224,1224,1224,1223,1225,1226,1227,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
@@ -4258,245 +4272,265 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
/* block 187 */
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-1230,1230,1230,1230,1230,1230,1230,1230,1230,1230,1230,1230,1230,1230,1230,1230,
-1230,1230,1230,1230,1230,1230,1230,1230,1230,1230,1230,1230,1230,1230,1230,1230,
-1231,1231,1231,1231,1231,1231,1231,1231,1231,1231,1231,1231,1231,1231,1231,1231,
-1231,1231,1231,1231,1231,1231,1231,1231,1231,1231,1231,1231,1231,1231,1231,1231,
-1232,1232,1232,1232,1232,1232,1232,1232,1232,1232,1233,1233,1233,1233,1233,1233,
-1233,1233,1233,163,163,163,163,163,163,163,163,163,163,163,163,1234,
+1228,1228,1228,1228,1228,1228,1228,1228,1228,1228,1228,1228,1228,1228,1228,1228,
+1228,1228,1228,1228,1228,1228,1228,1228,1228,1228,1228,1228,1228,1228,1228,1228,
+1229,1229,1229,1229,1229,1229,1229,1229,1229,1229,1229,1229,1229,1229,1229,1229,
+1229,1229,1229,1229,1229,1229,1229,1229,1229,1229,1229,1229,1229,1229,1229,1229,
+1230,1230,1230,1230,1230,1230,1230,1230,1230,1230,1231,1231,1231,1231,1231,1231,
+1231,1231,1231,163,163,163,163,163,163,163,163,163,163,163,163,1232,
/* block 188 */
-1235,1235,1235,1235,1235,1235,1235,163,163,1235,163,163,1235,1235,1235,1235,
-1235,1235,1235,1235,163,1235,1235,163,1235,1235,1235,1235,1235,1235,1235,1235,
-1235,1235,1235,1235,1235,1235,1235,1235,1235,1235,1235,1235,1235,1235,1235,1235,
-1236,1237,1237,1237,1237,1237,163,1237,1237,163,163,1238,1238,1239,1240,1241,
-1237,1241,1237,1242,1243,1244,1243,163,163,163,163,163,163,163,163,163,
-1245,1245,1245,1245,1245,1245,1245,1245,1245,1245,163,163,163,163,163,163,
+1233,1233,1233,1233,1233,1233,1233,163,163,1233,163,163,1233,1233,1233,1233,
+1233,1233,1233,1233,163,1233,1233,163,1233,1233,1233,1233,1233,1233,1233,1233,
+1233,1233,1233,1233,1233,1233,1233,1233,1233,1233,1233,1233,1233,1233,1233,1233,
+1234,1235,1235,1235,1235,1235,163,1235,1235,163,163,1236,1236,1237,1238,1239,
+1235,1239,1235,1240,1241,1242,1241,163,163,163,163,163,163,163,163,163,
+1243,1243,1243,1243,1243,1243,1243,1243,1243,1243,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 189 */
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-1246,1246,1246,1246,1246,1246,1246,1246,163,163,1246,1246,1246,1246,1246,1246,
-1246,1246,1246,1246,1246,1246,1246,1246,1246,1246,1246,1246,1246,1246,1246,1246,
-1246,1246,1246,1246,1246,1246,1246,1246,1246,1246,1246,1246,1246,1246,1246,1246,
-1246,1247,1247,1247,1248,1248,1248,1248,163,163,1248,1248,1247,1247,1247,1247,
-1249,1246,1250,1246,1247,163,163,163,163,163,163,163,163,163,163,163,
+1244,1244,1244,1244,1244,1244,1244,1244,163,163,1244,1244,1244,1244,1244,1244,
+1244,1244,1244,1244,1244,1244,1244,1244,1244,1244,1244,1244,1244,1244,1244,1244,
+1244,1244,1244,1244,1244,1244,1244,1244,1244,1244,1244,1244,1244,1244,1244,1244,
+1244,1245,1245,1245,1246,1246,1246,1246,163,163,1246,1246,1245,1245,1245,1245,
+1247,1244,1248,1244,1245,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 190 */
-1251,1252,1252,1252,1252,1252,1252,1253,1253,1252,1252,1251,1251,1251,1251,1251,
-1251,1251,1251,1251,1251,1251,1251,1251,1251,1251,1251,1251,1251,1251,1251,1251,
-1251,1251,1251,1251,1251,1251,1251,1251,1251,1251,1251,1251,1251,1251,1251,1251,
-1251,1251,1251,1254,1255,1252,1252,1252,1252,1256,1257,1252,1252,1252,1252,1258,
-1258,1258,1259,1259,1258,1258,1258,1255,163,163,163,163,163,163,163,163,
-1260,1261,1261,1261,1261,1261,1261,1262,1262,1261,1261,1261,1260,1260,1260,1260,
-1260,1260,1260,1260,1260,1260,1260,1260,1260,1260,1260,1260,1260,1260,1260,1260,
-1260,1260,1260,1260,1260,1260,1260,1260,1260,1260,1260,1260,1260,1260,1260,1260,
+1249,1250,1250,1250,1250,1250,1250,1251,1251,1250,1250,1249,1249,1249,1249,1249,
+1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,
+1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,1249,
+1249,1249,1249,1252,1253,1250,1250,1250,1250,1254,1255,1250,1250,1250,1250,1256,
+1256,1256,1257,1257,1256,1256,1256,1253,163,163,163,163,163,163,163,163,
+1258,1259,1259,1259,1259,1259,1259,1260,1260,1259,1259,1259,1258,1258,1258,1258,
+1258,1258,1258,1258,1258,1258,1258,1258,1258,1258,1258,1258,1258,1258,1258,1258,
+1258,1258,1258,1258,1258,1258,1258,1258,1258,1258,1258,1258,1258,1258,1258,1258,
/* block 191 */
-1260,1260,1260,1260,1263,1263,1263,1263,1263,1263,1261,1261,1261,1261,1261,1261,
-1261,1261,1261,1261,1261,1261,1261,1262,1264,1265,1266,1267,1267,1260,1266,1266,
-1266,1268,1268,163,163,163,163,163,163,163,163,163,163,163,163,163,
-495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,
-1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,
-1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,
-1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,1269,
-1269,1269,1269,1269,1269,1269,1269,1269,1269,163,163,163,163,163,163,163,
+1258,1258,1258,1258,1261,1261,1261,1261,1261,1261,1259,1259,1259,1259,1259,1259,
+1259,1259,1259,1259,1259,1259,1259,1260,1262,1263,1264,1265,1265,1258,1264,1264,
+1264,1266,1266,163,163,163,163,163,163,163,163,163,163,163,163,163,
+496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,496,
+1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,
+1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,
+1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,1267,
+1267,1267,1267,1267,1267,1267,1267,1267,1267,163,163,163,163,163,163,163,
/* block 192 */
-1270,1270,1270,1270,1270,1270,1270,1270,1270,163,1270,1270,1270,1270,1270,1270,
-1270,1270,1270,1270,1270,1270,1270,1270,1270,1270,1270,1270,1270,1270,1270,1270,
-1270,1270,1270,1270,1270,1270,1270,1270,1270,1270,1270,1270,1270,1270,1270,1271,
-1272,1272,1272,1272,1272,1272,1272,163,1272,1272,1272,1272,1272,1272,1271,1273,
-1270,1274,1274,1275,1276,1276,163,163,163,163,163,163,163,163,163,163,
-1277,1277,1277,1277,1277,1277,1277,1277,1277,1277,1278,1278,1278,1278,1278,1278,
-1278,1278,1278,1278,1278,1278,1278,1278,1278,1278,1278,1278,1278,163,163,163,
-1279,1280,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,
-
-/* block 193 */
-1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,1281,
-163,163,1282,1282,1282,1282,1282,1282,1282,1282,1282,1282,1282,1282,1282,1282,
-1282,1282,1282,1282,1282,1282,1282,1282,163,1283,1282,1282,1282,1282,1282,1282,
-1282,1283,1282,1282,1283,1282,1282,163,163,163,163,163,163,163,163,163,
+343,343,343,343,343,343,343,343,343,343,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-/* block 194 */
-1284,1284,1284,1284,1284,1284,1284,163,1284,1284,163,1284,1284,1284,1284,1284,
-1284,1284,1284,1284,1284,1284,1284,1284,1284,1284,1284,1284,1284,1284,1284,1284,
-1284,1284,1284,1284,1284,1284,1284,1284,1284,1284,1284,1284,1284,1284,1284,1284,
-1284,1285,1285,1285,1285,1285,1285,163,163,163,1285,163,1285,1285,163,1285,
-1285,1285,1286,1285,1287,1287,1288,1285,163,163,163,163,163,163,163,163,
-1289,1289,1289,1289,1289,1289,1289,1289,1289,1289,163,163,163,163,163,163,
-1290,1290,1290,1290,1290,1290,163,1290,1290,163,1290,1290,1290,1290,1290,1290,
-1290,1290,1290,1290,1290,1290,1290,1290,1290,1290,1290,1290,1290,1290,1290,1290,
+/* block 193 */
+1268,1268,1268,1268,1268,1268,1268,1268,1268,163,1268,1268,1268,1268,1268,1268,
+1268,1268,1268,1268,1268,1268,1268,1268,1268,1268,1268,1268,1268,1268,1268,1268,
+1268,1268,1268,1268,1268,1268,1268,1268,1268,1268,1268,1268,1268,1268,1268,1269,
+1270,1270,1270,1270,1270,1270,1270,163,1270,1270,1270,1270,1270,1270,1269,1271,
+1268,1272,1272,1273,1274,1274,163,163,163,163,163,163,163,163,163,163,
+1275,1275,1275,1275,1275,1275,1275,1275,1275,1275,1276,1276,1276,1276,1276,1276,
+1276,1276,1276,1276,1276,1276,1276,1276,1276,1276,1276,1276,1276,163,163,163,
+1277,1278,1279,1279,1279,1279,1279,1279,1279,1279,1279,1279,1279,1279,1279,1279,
-/* block 195 */
-1290,1290,1290,1290,1290,1290,1290,1290,1290,1290,1291,1291,1291,1291,1291,163,
-1292,1292,163,1291,1291,1292,1291,1293,1290,163,163,163,163,163,163,163,
-1294,1294,1294,1294,1294,1294,1294,1294,1294,1294,163,163,163,163,163,163,
-163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+/* block 194 */
+1279,1279,1279,1279,1279,1279,1279,1279,1279,1279,1279,1279,1279,1279,1279,1279,
+163,163,1280,1280,1280,1280,1280,1280,1280,1280,1280,1280,1280,1280,1280,1280,
+1280,1280,1280,1280,1280,1280,1280,1280,163,1281,1280,1280,1280,1280,1280,1280,
+1280,1281,1280,1280,1281,1280,1280,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+/* block 195 */
+1282,1282,1282,1282,1282,1282,1282,163,1282,1282,163,1282,1282,1282,1282,1282,
+1282,1282,1282,1282,1282,1282,1282,1282,1282,1282,1282,1282,1282,1282,1282,1282,
+1282,1282,1282,1282,1282,1282,1282,1282,1282,1282,1282,1282,1282,1282,1282,1282,
+1282,1283,1283,1283,1283,1283,1283,163,163,163,1283,163,1283,1283,163,1283,
+1283,1283,1284,1283,1285,1285,1286,1283,163,163,163,163,163,163,163,163,
+1287,1287,1287,1287,1287,1287,1287,1287,1287,1287,163,163,163,163,163,163,
+1288,1288,1288,1288,1288,1288,163,1288,1288,163,1288,1288,1288,1288,1288,1288,
+1288,1288,1288,1288,1288,1288,1288,1288,1288,1288,1288,1288,1288,1288,1288,1288,
+
/* block 196 */
+1288,1288,1288,1288,1288,1288,1288,1288,1288,1288,1289,1289,1289,1289,1289,163,
+1290,1290,163,1289,1289,1290,1289,1291,1288,163,163,163,163,163,163,163,
+1292,1292,1292,1292,1292,1292,1292,1292,1292,1292,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-1295,1295,1295,1295,1295,1295,1295,1295,1295,1295,1295,1295,1295,1295,1295,1295,
-1295,1295,1295,1296,1296,1297,1297,1298,1298,163,163,163,163,163,163,163,
/* block 197 */
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-842,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-1299,1299,1299,1299,1299,1299,1299,1299,1299,1299,1299,1299,1299,1299,1299,1299,
-388,388,1299,388,1299,390,390,390,390,390,390,390,390,391,391,391,
-391,390,390,390,390,390,390,390,390,390,390,390,390,390,390,390,
-390,390,163,163,163,163,163,163,163,163,163,163,163,163,163,1300,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+1293,1293,1293,1293,1293,1293,1293,1293,1293,1293,1293,1293,1293,1293,1293,1293,
+1293,1293,1293,1294,1294,1295,1295,1296,1296,163,163,163,163,163,163,163,
/* block 198 */
-1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,
-1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,
-1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,
-1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,
-1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,
-1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,
-1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,
-1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,
-
-/* block 199 */
-1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,
-1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,163,163,163,163,163,163,
-163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+1297,1297,1298,1299,1300,1300,1300,1300,1300,1300,1300,1300,1300,1300,1300,1300,
+1300,163,1300,1300,1300,1300,1300,1300,1300,1300,1300,1300,1300,1300,1300,1300,
+1300,1300,1300,1300,1300,1300,1300,1300,1300,1300,1300,1300,1300,1300,1300,1300,
+1300,1300,1300,1300,1299,1299,1297,1297,1297,1297,1297,163,163,163,1299,1299,
+1297,1301,1302,1303,1303,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,
+1305,1305,1305,1305,1305,1305,1305,1305,1305,1305,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+
+/* block 199 */
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+843,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,
+388,388,1306,388,1306,390,390,390,390,390,390,390,390,391,391,391,
+391,390,390,390,390,390,390,390,390,390,390,390,390,390,390,390,
+390,390,163,163,163,163,163,163,163,163,163,163,163,163,163,1307,
/* block 200 */
-1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,
-1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,
-1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,
-1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,
-1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,
-1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,
-1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,1302,163,
-1303,1303,1303,1303,1303,163,163,163,163,163,163,163,163,163,163,163,
+1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
+1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
+1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
+1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
+1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
+1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
+1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
+1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
/* block 201 */
-1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,
-1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,
-1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,
-1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,1301,
-1301,1301,1301,1301,163,163,163,163,163,163,163,163,163,163,163,163,
+1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
+1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 202 */
-163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,
-1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,
-1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,
-1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,
-1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,
-1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,1304,
-1304,1305,1305,163,163,163,163,163,163,163,163,163,163,163,163,163,
+1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,
+1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,
+1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,
+1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,
+1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,
+1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,
+1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,163,
+1310,1310,1310,1310,1310,163,163,163,163,163,163,163,163,163,163,163,
/* block 203 */
-1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,
-1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,
-1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,
-1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,
-1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,
-1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,
-1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,
-1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,
-
-/* block 204 */
-1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,
-1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,
-1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,1306,163,
-1307,1307,1307,1307,1307,1307,1307,1307,1307,163,163,163,163,163,163,163,
+1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
+1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
+1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
+1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
+1308,1308,1308,1308,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+
+/* block 204 */
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,
+1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,
+1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,
+1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,
+1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,
+1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,1311,
+1311,1312,1312,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 205 */
-1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
-1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
-1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
-1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
-1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
-1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
-1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
-1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
+1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,
+1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,
+1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,
+1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,
+1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,
+1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,
+1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,
+1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,
/* block 206 */
-1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
-1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
-1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
-1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,1308,
-1308,1308,1308,1308,1308,1308,1308,163,163,163,163,163,163,163,163,163,
-163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,
+1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,
+1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,
+1314,1314,1314,1314,1314,1314,1314,1314,1314,1314,1314,1314,1314,1314,1314,1314,
+1315,1313,1313,1313,1313,1313,1313,1316,1316,1316,1316,1316,1316,1316,1316,1316,
+1316,1316,1316,1316,1316,1316,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 207 */
-858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,
-858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,
-858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,
-858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,
-858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,
-858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,
-858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,
-858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,
+1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,
+1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,
+1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,
+1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,
+1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,
+1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,
+1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,
+1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,
/* block 208 */
-858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,
-858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,
-858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,
-858,858,858,858,858,858,858,858,858,163,163,163,163,163,163,163,
-1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,
-1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,1309,163,
-1310,1310,1310,1310,1310,1310,1310,1310,1310,1310,163,163,163,163,1311,1311,
-1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,
+1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,
+1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,
+1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,
+1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,
+1317,1317,1317,1317,1317,1317,1317,163,163,163,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 209 */
-1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,
-1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,
-1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,
-1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,1312,163,
-1313,1313,1313,1313,1313,1313,1313,1313,1313,1313,163,163,163,163,163,163,
-1314,1314,1314,1314,1314,1314,1314,1314,1314,1314,1314,1314,1314,1314,1314,1314,
-1314,1314,1314,1314,1314,1314,1314,1314,1314,1314,1314,1314,1314,1314,163,163,
-1315,1315,1315,1315,1315,1316,163,163,163,163,163,163,163,163,163,163,
+859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,
+859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,
+859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,
+859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,
+859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,
+859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,
+859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,
+859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,
/* block 210 */
-1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,
-1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,
-1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,
-1318,1318,1318,1318,1318,1318,1318,1319,1319,1320,1321,1321,1322,1322,1322,1322,
-1323,1323,1324,1324,1319,1322,163,163,163,163,163,163,163,163,163,163,
-1325,1325,1325,1325,1325,1325,1325,1325,1325,1325,163,1326,1326,1326,1326,1326,
-1326,1326,163,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,
-1317,1317,1317,1317,1317,1317,1317,1317,163,163,163,163,163,1317,1317,1317,
+859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,
+859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,
+859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,859,
+859,859,859,859,859,859,859,859,859,163,163,163,163,163,163,163,
+1318,1318,1318,1318,1318,1318,1318,1318,1318,1318,1318,1318,1318,1318,1318,1318,
+1318,1318,1318,1318,1318,1318,1318,1318,1318,1318,1318,1318,1318,1318,1318,163,
+1319,1319,1319,1319,1319,1319,1319,1319,1319,1319,163,163,163,163,1320,1320,
+1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,
/* block 211 */
-1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,1317,
+1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,
+1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,
+1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,
+1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,1321,163,
+1322,1322,1322,1322,1322,1322,1322,1322,1322,1322,163,163,163,163,163,163,
+1323,1323,1323,1323,1323,1323,1323,1323,1323,1323,1323,1323,1323,1323,1323,1323,
+1323,1323,1323,1323,1323,1323,1323,1323,1323,1323,1323,1323,1323,1323,163,163,
+1324,1324,1324,1324,1324,1325,163,163,163,163,163,163,163,163,163,163,
+
+/* block 212 */
+1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,
+1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,
+1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,
+1327,1327,1327,1327,1327,1327,1327,1328,1328,1329,1330,1330,1331,1331,1331,1331,
+1332,1332,1333,1333,1328,1331,163,163,163,163,163,163,163,163,163,163,
+1334,1334,1334,1334,1334,1334,1334,1334,1334,1334,163,1335,1335,1335,1335,1335,
+1335,1335,163,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,
+1326,1326,1326,1326,1326,1326,1326,1326,163,163,163,163,163,1326,1326,1326,
+
+/* block 213 */
+1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,1326,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
@@ -4505,19 +4539,19 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-/* block 212 */
+/* block 214 */
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-1327,1327,1327,1327,1327,1327,1327,1327,1327,1327,1327,1327,1327,1327,1327,1327,
-1327,1327,1327,1327,1327,1327,1327,1327,1327,1327,1327,1327,1327,1327,1327,1327,
-1328,1328,1328,1328,1328,1328,1328,1328,1328,1328,1328,1328,1328,1328,1328,1328,
-1328,1328,1328,1328,1328,1328,1328,1328,1328,1328,1328,1328,1328,1328,1328,1328,
+1336,1336,1336,1336,1336,1336,1336,1336,1336,1336,1336,1336,1336,1336,1336,1336,
+1336,1336,1336,1336,1336,1336,1336,1336,1336,1336,1336,1336,1336,1336,1336,1336,
+1337,1337,1337,1337,1337,1337,1337,1337,1337,1337,1337,1337,1337,1337,1337,1337,
+1337,1337,1337,1337,1337,1337,1337,1337,1337,1337,1337,1337,1337,1337,1337,1337,
-/* block 213 */
-1329,1329,1329,1329,1329,1329,1329,1329,1329,1329,1329,1329,1329,1329,1329,1329,
-1329,1329,1329,1329,1329,1329,1329,1330,1331,1332,1332,163,163,163,163,163,
+/* block 215 */
+1338,1338,1338,1338,1338,1338,1338,1338,1338,1338,1338,1338,1338,1338,1338,1338,
+1338,1338,1338,1338,1338,1338,1338,1339,1340,1341,1341,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
@@ -4525,68 +4559,68 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-/* block 214 */
-1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,
-1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,
-1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,
-1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,
-1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,1333,163,163,163,163,1334,
-1333,1335,1335,1335,1335,1335,1335,1335,1335,1335,1335,1335,1335,1335,1335,1335,
-1335,1335,1335,1335,1335,1335,1335,1335,1335,1335,1335,1335,1335,1335,1335,1335,
-1335,1335,1335,1335,1335,1335,1335,1335,1335,1335,1335,1335,1335,1335,1335,1335,
+/* block 216 */
+1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,
+1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,
+1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,
+1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,
+1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,1342,163,163,163,163,1343,
+1342,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,
+1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,
+1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,
-/* block 215 */
-1335,1335,1335,1335,1335,1335,1335,1335,163,163,163,163,163,163,163,1336,
-1336,1336,1336,1337,1337,1337,1337,1337,1337,1337,1337,1337,1337,1337,1337,1337,
+/* block 217 */
+1344,1344,1344,1344,1344,1344,1344,1344,163,163,163,163,163,163,163,1345,
+1345,1345,1345,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-1338,1339,1340,799,1341,163,163,163,163,163,163,163,163,163,163,163,
-1342,1342,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-
-/* block 216 */
-1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,
-1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,
-1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,
-1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,
-1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,
-1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,
-1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,
-1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,
-
-/* block 217 */
-1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,
-1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,
-1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,
-1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,
-1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,
-1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,
-1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,1343,
-1343,1343,1343,1343,1343,1343,1343,1343,163,163,163,163,163,163,163,163,
+1347,1348,1349,800,1350,163,163,163,163,163,163,163,163,163,163,163,
+1351,1351,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 218 */
-1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,
-1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,
-1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,
-1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,
-1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,
-1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,
-1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,
-1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,
+1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,
+1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,
+1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,
+1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,
+1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,
+1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,
+1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,
+1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,
/* block 219 */
-1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,
-1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,
-1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,
-1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,
-1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,1344,
-1344,1344,1344,1344,1344,1344,163,163,163,163,163,163,163,163,163,163,
+1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,
+1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,
+1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,
+1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,
+1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,
+1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,
+1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,1352,
+1352,1352,1352,1352,1352,1352,1352,1352,163,163,163,163,163,163,163,163,
+
+/* block 220 */
+1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,
+1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,
+1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,
+1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,
+1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,
+1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,
+1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,
+1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,
+
+/* block 221 */
+1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,
+1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,
+1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,
+1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,
+1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,1353,
+1353,1353,1353,1353,1353,1353,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-/* block 220 */
-1343,1343,1343,1343,1343,1343,1343,1343,1343,163,163,163,163,163,163,163,
+/* block 222 */
+1352,1352,1352,1352,1352,1352,1352,1352,1352,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
@@ -4595,7 +4629,7 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-/* block 221 */
+/* block 223 */
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
@@ -4603,359 +4637,379 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-1345,1345,1345,1345,163,1345,1345,1345,1345,1345,1345,1345,163,1345,1345,163,
-
-/* block 222 */
-824,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-
-/* block 223 */
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
+1354,1354,1354,1354,163,1354,1354,1354,1354,1354,1354,1354,163,1354,1354,163,
/* block 224 */
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
-824,824,824,163,163,163,163,163,163,163,163,163,163,163,163,163,
-163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-819,819,819,163,163,163,163,163,163,163,163,163,163,163,163,163,
-163,163,163,163,824,824,824,824,163,163,163,163,163,163,163,163,
-1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,
+825,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
/* block 225 */
-1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,
-1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,
-1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,
-1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,
-1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,
-1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,
-1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,
-1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
/* block 226 */
-1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,
-1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,
-1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,
-1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,
-1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,
-1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,
-1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,
-1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,1346,163,163,163,163,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+825,825,825,163,163,163,163,163,163,163,163,163,163,163,163,163,
+163,163,820,163,163,163,163,163,163,163,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+820,820,820,163,163,825,163,163,163,163,163,163,163,163,163,163,
+163,163,163,163,825,825,825,825,163,163,163,163,163,163,163,163,
+1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,
/* block 227 */
-1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,
-1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,
-1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,
-1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,
-1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,
-1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,
-1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,163,163,163,163,163,
-1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,163,163,163,
+1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,
+1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,
+1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,
+1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,
+1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,
+1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,
+1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,
+1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,
/* block 228 */
-1347,1347,1347,1347,1347,1347,1347,1347,1347,163,163,163,163,163,163,163,
-1347,1347,1347,1347,1347,1347,1347,1347,1347,1347,163,163,1348,1349,1350,1351,
-1352,1352,1352,1352,163,163,163,163,163,163,163,163,163,163,163,163,
+1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,
+1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,
+1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,
+1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,
+1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,
+1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,
+1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,
+1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,1355,163,163,163,163,
+
+/* block 229 */
+1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,
+1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,
+1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,
+1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,
+1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,
+1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,
+1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,163,163,163,163,163,
+1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,163,163,163,
+
+/* block 230 */
+1356,1356,1356,1356,1356,1356,1356,1356,1356,163,163,163,163,163,163,163,
+1356,1356,1356,1356,1356,1356,1356,1356,1356,1356,163,163,1357,1358,1359,1360,
+1361,1361,1361,1361,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-/* block 229 */
+/* block 231 */
154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,
154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,
154,154,154,154,154,154,154,154,154,154,154,154,154,154,163,163,
154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,
154,154,154,154,154,154,154,163,163,163,163,163,163,163,163,163,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
-/* block 230 */
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,163,163,163,163,163,163,163,163,163,163,163,163,
+/* block 232 */
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-/* block 231 */
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-
-/* block 232 */
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,163,163,163,163,163,163,163,163,163,163,
-
/* block 233 */
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,163,163,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,1353,1354,154,154,154,460,460,460,1355,1356,1356,
-1356,1356,1356, 51, 51, 51, 51, 51, 51, 51, 51,154,154,154,154,154,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
/* block 234 */
-154,154,154,460,460,154,154,154,154,154,154,154,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,154,154,154,154,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,723,723,163,163,163,163,163,
-163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,163,163,163,163,163,163,163,163,163,163,
/* block 235 */
-1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,
-1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,
-1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,
-1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,1002,
-1002,1002,1357,1357,1357,1002,163,163,163,163,163,163,163,163,163,163,
-163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,163,163,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,1362,1363,154,154,154,461,461,461,1364,1365,1365,
+1365,1365,1365, 51, 51, 51, 51, 51, 51, 51, 51,154,154,154,154,154,
/* block 236 */
+154,154,154,461,461,154,154,154,154,154,154,154,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,154,154,154,154,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,724,724,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+
+/* block 237 */
+1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,
+1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,
+1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,
+1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,1001,
+1001,1001,1366,1366,1366,1001,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+
+/* block 238 */
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-835,835,835,835,835,835,835,835,835,835,835,835,835,835,835,835,
-835,835,835,835,163,163,163,163,163,163,163,163,163,163,163,163,
-
-/* block 237 */
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,163,163,163,163,163,163,163,163,163,
-832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,832,
-832,832,835,835,835,835,835,835,835,163,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+836,836,836,836,836,836,836,836,836,836,836,836,836,836,836,836,
+836,836,836,836,163,163,163,163,163,163,163,163,163,163,163,163,
+836,836,836,836,836,836,836,836,836,836,836,836,836,836,836,836,
+836,836,836,836,163,163,163,163,163,163,163,163,163,163,163,163,
-/* block 238 */
+/* block 239 */
724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
-724,724,724,724,724,724,724,724,724,724,725,725,725,725,725,725,
-725,725,736,736,725,725,725,725,725,725,725,725,725,725,725,725,
-725,725,725,725,724,724,724,724,724,724,724,724,724,724,724,724,
-724,724,724,724,724,724,724,724,724,724,724,724,724,724,725,725,
-725,725,725,725,725,163,736,736,725,725,725,725,725,725,725,725,
-725,725,725,725,725,725,725,725,724,724,724,724,724,724,724,724,
724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
-
-/* block 239 */
-724,724,725,725,725,725,725,725,725,725,736,736,725,725,725,725,
-725,725,725,725,725,725,725,725,725,725,725,725,724,163,724,724,
-163,163,724,163,163,724,724,163,163,724,724,724,724,163,724,724,
-724,724,724,724,724,724,725,725,725,725,163,725,163,725,736,736,
-725,725,725,725,163,725,725,725,725,725,725,725,725,725,725,725,
724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
-724,724,724,724,724,724,724,724,724,724,725,725,725,725,725,725,
-725,725,736,736,725,725,725,725,725,725,725,725,725,725,725,725,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,163,163,163,163,163,163,163,163,163,
+833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,833,
+833,833,836,836,836,836,836,836,836,163,163,163,163,163,163,163,
/* block 240 */
-725,725,725,725,724,724,163,724,724,724,724,163,163,724,724,724,
-724,724,724,724,724,163,724,724,724,724,724,724,724,163,725,725,
-725,725,725,725,725,725,736,736,725,725,725,725,725,725,725,725,
-725,725,725,725,725,725,725,725,724,724,163,724,724,724,724,163,
-724,724,724,724,724,163,724,163,163,163,724,724,724,724,724,724,
-724,163,725,725,725,725,725,725,725,725,736,736,725,725,725,725,
-725,725,725,725,725,725,725,725,725,725,725,725,724,724,724,724,
-724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,
+725,725,725,725,725,725,725,725,725,725,726,726,726,726,726,726,
+726,726,737,737,726,726,726,726,726,726,726,726,726,726,726,726,
+726,726,726,726,725,725,725,725,725,725,725,725,725,725,725,725,
+725,725,725,725,725,725,725,725,725,725,725,725,725,725,726,726,
+726,726,726,726,726,163,737,737,726,726,726,726,726,726,726,726,
+726,726,726,726,726,726,726,726,725,725,725,725,725,725,725,725,
+725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,
/* block 241 */
-724,724,724,724,724,724,725,725,725,725,725,725,725,725,736,736,
+725,725,726,726,726,726,726,726,726,726,737,737,726,726,726,726,
+726,726,726,726,726,726,726,726,726,726,726,726,725,163,725,725,
+163,163,725,163,163,725,725,163,163,725,725,725,725,163,725,725,
+725,725,725,725,725,725,726,726,726,726,163,726,163,726,737,737,
+726,726,726,726,163,726,726,726,726,726,726,726,726,726,726,726,
725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,
-724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
-724,724,724,724,724,724,724,724,724,724,725,725,725,725,725,725,
-725,725,736,736,725,725,725,725,725,725,725,725,725,725,725,725,
-725,725,725,725,724,724,724,724,724,724,724,724,724,724,724,724,
-724,724,724,724,724,724,724,724,724,724,724,724,724,724,725,725,
-725,725,725,725,725,725,736,736,725,725,725,725,725,725,725,725,
+725,725,725,725,725,725,725,725,725,725,726,726,726,726,726,726,
+726,726,737,737,726,726,726,726,726,726,726,726,726,726,726,726,
/* block 242 */
-725,725,725,725,725,725,725,725,724,724,724,724,724,724,724,724,
-724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
-724,724,725,725,725,725,725,725,725,725,736,736,725,725,725,725,
-725,725,725,725,725,725,725,725,725,725,725,725,724,724,724,724,
-724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
-724,724,724,724,724,724,725,725,725,725,725,725,725,725,736,736,
+726,726,726,726,725,725,163,725,725,725,725,163,163,725,725,725,
+725,725,725,725,725,163,725,725,725,725,725,725,725,163,726,726,
+726,726,726,726,726,726,737,737,726,726,726,726,726,726,726,726,
+726,726,726,726,726,726,726,726,725,725,163,725,725,725,725,163,
+725,725,725,725,725,163,725,163,163,163,725,725,725,725,725,725,
+725,163,726,726,726,726,726,726,726,726,737,737,726,726,726,726,
+726,726,726,726,726,726,726,726,726,726,726,726,725,725,725,725,
725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,
-724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
/* block 243 */
-724,724,724,724,724,724,724,724,724,724,725,725,725,725,725,725,
-725,725,736,736,725,725,725,725,725,725,725,725,725,725,725,725,
-725,725,725,725,725,725,163,163,724,724,724,724,724,724,724,724,
-724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
-724,1358,725,725,725,725,725,725,725,725,725,725,725,725,725,725,
-725,725,725,725,725,725,725,725,725,725,725,715,725,725,725,725,
-725,725,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
-724,724,724,724,724,724,724,724,724,724,724,1358,725,725,725,725,
+725,725,725,725,725,725,726,726,726,726,726,726,726,726,737,737,
+726,726,726,726,726,726,726,726,726,726,726,726,726,726,726,726,
+725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,
+725,725,725,725,725,725,725,725,725,725,726,726,726,726,726,726,
+726,726,737,737,726,726,726,726,726,726,726,726,726,726,726,726,
+726,726,726,726,725,725,725,725,725,725,725,725,725,725,725,725,
+725,725,725,725,725,725,725,725,725,725,725,725,725,725,726,726,
+726,726,726,726,726,726,737,737,726,726,726,726,726,726,726,726,
/* block 244 */
+726,726,726,726,726,726,726,726,725,725,725,725,725,725,725,725,
725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,
-725,725,725,725,725,715,725,725,725,725,725,725,724,724,724,724,
-724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
-724,724,724,724,724,1358,725,725,725,725,725,725,725,725,725,725,
-725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,715,
-725,725,725,725,725,725,724,724,724,724,724,724,724,724,724,724,
-724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,1358,
+725,725,726,726,726,726,726,726,726,726,737,737,726,726,726,726,
+726,726,726,726,726,726,726,726,726,726,726,726,725,725,725,725,
+725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,
+725,725,725,725,725,725,726,726,726,726,726,726,726,726,737,737,
+726,726,726,726,726,726,726,726,726,726,726,726,726,726,726,726,
725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,
/* block 245 */
-725,725,725,725,725,725,725,725,725,715,725,725,725,725,725,725,
-724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
-724,724,724,724,724,724,724,724,724,1358,725,725,725,725,725,725,
+725,725,725,725,725,725,725,725,725,725,726,726,726,726,726,726,
+726,726,737,737,726,726,726,726,726,726,726,726,726,726,726,726,
+726,726,726,726,726,726,163,163,725,725,725,725,725,725,725,725,
725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,
-725,725,725,715,725,725,725,725,725,725,724,725,163,163,1359,1359,
-1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,
-1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,
-1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,1359,
+725,1367,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,716,726,726,726,726,
+726,726,725,725,725,725,725,725,725,725,725,725,725,725,725,725,
+725,725,725,725,725,725,725,725,725,725,725,1367,726,726,726,726,
/* block 246 */
-1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,
-1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,
-1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,
-1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,
-1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,
-1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,
-1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,
-1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,
+726,726,726,726,726,726,726,726,726,726,726,726,726,726,726,726,
+726,726,726,726,726,716,726,726,726,726,726,726,725,725,725,725,
+725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,
+725,725,725,725,725,1367,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,716,
+726,726,726,726,726,726,725,725,725,725,725,725,725,725,725,725,
+725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,1367,
+726,726,726,726,726,726,726,726,726,726,726,726,726,726,726,726,
/* block 247 */
-1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,
-1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,
-1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,
-1361,1361,1361,1361,1361,1361,1361,1360,1360,1360,1360,1361,1361,1361,1361,1361,
-1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,
-1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,
-1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1360,1360,1360,
-1360,1360,1360,1360,1360,1361,1360,1360,1360,1360,1360,1360,1360,1360,1360,1360,
+726,726,726,726,726,726,726,726,726,716,726,726,726,726,726,726,
+725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,725,
+725,725,725,725,725,725,725,725,725,1367,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,716,726,726,726,726,726,726,725,726,163,163,1368,1368,
+1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,
+1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,
+1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,1368,
/* block 248 */
-1360,1360,1360,1360,1361,1360,1360,1362,1363,1362,1362,1364,163,163,163,163,
-163,163,163,163,163,163,163,163,163,163,163,1361,1361,1361,1361,1361,
-163,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,1361,
+1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,
+1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,
+1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,
+1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,
+1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,
+1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,
+1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,
+1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,
+
+/* block 249 */
+1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,
+1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,
+1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,
+1370,1370,1370,1370,1370,1370,1370,1369,1369,1369,1369,1370,1370,1370,1370,1370,
+1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,
+1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,
+1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1369,1369,1369,
+1369,1369,1369,1369,1369,1370,1369,1369,1369,1369,1369,1369,1369,1369,1369,1369,
+
+/* block 250 */
+1369,1369,1369,1369,1370,1369,1369,1371,1372,1371,1371,1373,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,1370,1370,1370,1370,1370,
+163,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-/* block 249 */
+/* block 251 */
70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 92, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,643, 70, 70, 70, 70,163,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,644, 70, 70, 70, 70,163,
+163,163,163,163,163, 70, 70, 70, 70, 70, 70,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+
+/* block 252 */
+1374,1374,1374,1374,1374,1374,1374,163,1374,1374,1374,1374,1374,1374,1374,1374,
+1374,1374,1374,1374,1374,1374,1374,1374,1374,163,163,1374,1374,1374,1374,1374,
+1374,1374,163,1374,1374,163,1374,1374,1374,1374,1374,163,163,163,163,163,
+858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,
+858,858,858,858,858,858,858,858,858,858,858,858,1375,1375,858,858,
+858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,858,
+858,858,858,858,858,858,858,858,1375,858,858,858,858,858,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-/* block 250 */
-1365,1365,1365,1365,1365,1365,1365,163,1365,1365,1365,1365,1365,1365,1365,1365,
-1365,1365,1365,1365,1365,1365,1365,1365,1365,163,163,1365,1365,1365,1365,1365,
-1365,1365,163,1365,1365,163,1365,1365,1365,1365,1365,163,163,163,163,163,
+/* block 253 */
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,788,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-/* block 251 */
-1366,1366,1366,1366,1366,1366,1366,1366,1366,1366,1366,1366,1366,1366,1366,1366,
-1366,1366,1366,1366,1366,1366,1366,1366,1366,1366,1366,1366,1366,1366,1366,1366,
-1366,1366,1366,1366,1366,1366,1366,1366,1366,1366,1366,1366,1366,163,163,163,
-1367,1367,1367,1367,1367,1367,1367,1368,1368,1368,1368,1368,1369,1369,163,163,
-1370,1370,1370,1370,1370,1370,1370,1370,1370,1370,163,163,163,163,1366,1371,
+/* block 254 */
+1376,1376,1376,1376,1376,1376,1376,1376,1376,1376,1376,1376,1376,1376,1376,1376,
+1376,1376,1376,1376,1376,1376,1376,1376,1376,1376,1376,1376,1376,1376,1376,1376,
+1376,1376,1376,1376,1376,1376,1376,1376,1376,1376,1376,1376,1376,163,163,163,
+1377,1377,1377,1377,1377,1377,1377,1378,1378,1378,1378,1378,1379,1379,163,163,
+1380,1380,1380,1380,1380,1380,1380,1380,1380,1380,163,163,163,163,1376,1381,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-/* block 252 */
+/* block 255 */
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-1372,1372,1372,1372,1372,1372,1372,1372,1372,1372,1372,1372,1372,1372,1372,1372,
-1372,1372,1372,1372,1372,1372,1372,1372,1372,1372,1372,1372,1372,1372,1373,163,
+1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,
+1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1383,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-1374,1374,1374,1374,1374,1374,1374,1374,1374,1374,1374,1374,1374,1374,1374,1374,
-1374,1374,1374,1374,1374,1374,1374,1374,1374,1374,1374,1374,1374,1374,1374,1374,
-1374,1374,1374,1374,1374,1374,1374,1374,1374,1374,1374,1374,1375,1375,1375,1375,
-1376,1376,1376,1376,1376,1376,1376,1376,1376,1376,163,163,163,163,163,1377,
+1384,1384,1384,1384,1384,1384,1384,1384,1384,1384,1384,1384,1384,1384,1384,1384,
+1384,1384,1384,1384,1384,1384,1384,1384,1384,1384,1384,1384,1384,1384,1384,1384,
+1384,1384,1384,1384,1384,1384,1384,1384,1384,1384,1384,1384,1385,1385,1385,1385,
+1386,1386,1386,1386,1386,1386,1386,1386,1386,1386,163,163,163,163,163,1387,
-/* block 253 */
+/* block 256 */
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+1388,1388,1388,1388,1388,1388,1388,1388,1388,1388,1388,1388,1388,1388,1388,1388,
+1388,1388,1388,1388,1388,1388,1388,1388,1388,1388,1388,1389,1390,1390,1390,1390,
+1391,1391,1391,1391,1391,1391,1391,1391,1391,1391,163,163,163,163,163,163,
+
+/* block 257 */
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-483,483,483,483,483,483,483,163,483,483,483,483,163,483,483,163,
-483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+484,484,484,484,484,484,484,163,484,484,484,484,163,484,484,163,
+484,484,484,484,484,484,484,484,484,484,484,484,484,484,484,163,
-/* block 254 */
-1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,
-1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,
-1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,
-1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,
-1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,
-1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,
-1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,
-1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,
+/* block 258 */
+1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,
+1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,
+1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,
+1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,
+1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,
+1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,
+1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,
+1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,
-/* block 255 */
-1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,
-1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,
-1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,
-1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,1378,
-1378,1378,1378,1378,1378,262,262,1379,1379,1379,1379,1379,1379,1379,1379,1379,
-1380,1380,1380,1380,1380,1380,1380,262,262,262,262,262,262,262,262,262,
+/* block 259 */
+1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,
+1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,
+1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,
+1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,
+1392,1392,1392,1392,1392,262,262,1393,1393,1393,1393,1393,1393,1393,1393,1393,
+1394,1394,1394,1394,1394,1394,1394,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
-/* block 256 */
-1381,1381,1381,1381,1381,1381,1381,1381,1381,1381,1381,1381,1381,1381,1381,1381,
-1381,1381,1381,1381,1381,1381,1381,1381,1381,1381,1381,1381,1381,1381,1381,1381,
-1381,1381,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,
-1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,1382,
-1382,1382,1382,1382,1383,1383,1383,1384,1385,1385,1385,1386,262,262,262,262,
-1387,1387,1387,1387,1387,1387,1387,1387,1387,1387,262,262,262,262,1388,1388,
+/* block 260 */
+1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
+1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
+1395,1395,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,
+1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,
+1396,1396,1396,1396,1397,1397,1397,1398,1399,1399,1399,1400,262,262,262,262,
+1401,1401,1401,1401,1401,1401,1401,1401,1401,1401,262,262,262,262,1402,1402,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
-/* block 257 */
+/* block 261 */
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
@@ -4963,351 +5017,351 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
-302,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,
+302,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,
-/* block 258 */
-1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,
-1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,
-1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1390,1389,1389,1389,
-1391,1389,1389,1389,1389,302,302,302,302,302,302,302,302,302,302,302,
+/* block 262 */
+1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,
+1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,
+1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1404,1403,1403,1403,
+1405,1403,1403,1403,1403,302,302,302,302,302,302,302,302,302,302,302,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
-/* block 259 */
-302,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,
-1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,
-1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1390,1389,
-1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,1389,302,302,
+/* block 263 */
+302,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,
+1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,
+1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1404,1403,
+1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,302,302,
302,302,302,302,302,302,302,302,302,302,302,302,302,302,302,302,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,
-/* block 260 */
-1392,1392,1392,1392,302,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,
-1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,
-302,1392,1392,302,1392,302,302,1392,302,1392,1392,1392,1392,1392,1392,1392,
-1392,1392,1392,302,1392,1392,1392,1392,302,1392,302,1392,302,302,302,302,
-302,302,1392,302,302,302,302,1392,302,1392,302,1392,302,1392,1392,1392,
-302,1392,1392,302,1392,302,302,1392,302,1392,302,1392,302,1392,302,1392,
-302,1392,1392,302,1392,302,302,1392,1392,1392,1392,302,1392,1392,1392,1392,
-1392,1392,1392,302,1392,1392,1392,1392,302,1392,1392,1392,1392,302,1392,302,
+/* block 264 */
+1406,1406,1406,1406,302,1406,1406,1406,1406,1406,1406,1406,1406,1406,1406,1406,
+1406,1406,1406,1406,1406,1406,1406,1406,1406,1406,1406,1406,1406,1406,1406,1406,
+302,1406,1406,302,1406,302,302,1406,302,1406,1406,1406,1406,1406,1406,1406,
+1406,1406,1406,302,1406,1406,1406,1406,302,1406,302,1406,302,302,302,302,
+302,302,1406,302,302,302,302,1406,302,1406,302,1406,302,1406,1406,1406,
+302,1406,1406,302,1406,302,302,1406,302,1406,302,1406,302,1406,302,1406,
+302,1406,1406,302,1406,302,302,1406,1406,1406,1406,302,1406,1406,1406,1406,
+1406,1406,1406,302,1406,1406,1406,1406,302,1406,1406,1406,1406,302,1406,302,
-/* block 261 */
-1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,302,1392,1392,1392,1392,1392,
-1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,302,302,302,302,
-302,1392,1392,1392,302,1392,1392,1392,1392,1392,302,1392,1392,1392,1392,1392,
-1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,1392,302,302,302,302,
+/* block 265 */
+1406,1406,1406,1406,1406,1406,1406,1406,1406,1406,302,1406,1406,1406,1406,1406,
+1406,1406,1406,1406,1406,1406,1406,1406,1406,1406,1406,1406,302,302,302,302,
+302,1406,1406,1406,302,1406,1406,1406,1406,1406,302,1406,1406,1406,1406,1406,
+1406,1406,1406,1406,1406,1406,1406,1406,1406,1406,1406,1406,302,302,302,302,
302,302,302,302,302,302,302,302,302,302,302,302,302,302,302,302,
302,302,302,302,302,302,302,302,302,302,302,302,302,302,302,302,
302,302,302,302,302,302,302,302,302,302,302,302,302,302,302,302,
274,274,302,302,302,302,302,302,302,302,302,302,302,302,302,302,
-/* block 262 */
-1393,1393,1393,1393,1394,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,
-1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,
-1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1395,1395,1395,1395,
-1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,
-1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,
-1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,
-1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,
-1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,
-
-/* block 263 */
-1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,
-1393,1393,1393,1393,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1395,
-1395,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,
-1395,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1394,
-1395,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,
-1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,
-1393,1393,1393,1393,1393,1393,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-
-/* block 264 */
- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 58, 58,1393,1393,1393,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,1393,
-1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,
-1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,460,460,460,460,460,460,
-1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,
-1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,723,723,1393,1393,1393,1393,
-1397,1397,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,1397,1397,
-
-/* block 265 */
-1396,1396,1396,1396,1396,1396,1396,1396,1396,1396,460,460,460,460,1398,460,
-460,1398,1398,1398,1398,1398,1398,1398,1398,1398,1398,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,1393,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1399,1399,1399,1399,1399,1399,1399,1399,1399,1399,
-1399,1399,1399,1399,1399,1399,1399,1399,1399,1399,1399,1399,1399,1399,1399,1399,
-
/* block 266 */
-1400,1398,1401,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-460,460,460,460,460,460,460,460,460,460,1398,460,460,460,460,460,
-460,460,460,460,460,460,460,460,460,460,460,460,460,460,460,1398,
-460,460,1398,1398,1398,1398,1398,1401,1398,1398,1398,460,1395,1395,1395,1395,
-460,460,460,460,460,460,460,460,460,1395,1395,1395,1395,1395,1395,1395,
-1402,1402,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1393,1393,1393,1393,1393,1393,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
+1407,1407,1407,1407,1408,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,
+1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,
+1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1409,1409,1409,1409,
+1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,
+1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,
+1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,
+1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,
+1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,
/* block 267 */
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
+1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,
+1407,1407,1407,1407,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1409,
+1409,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,
+1409,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1408,
+1409,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,
+1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,
+1407,1407,1407,1407,1407,1407,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
/* block 268 */
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,727,1393,1393,727,727,727,727,727,727,727,727,727,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,727,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,727,1394,1394,
+ 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 58, 58,1407,1407,1407,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,1407,
+1410,1410,1410,1410,1410,1410,1410,1410,1410,1410,1410,1410,1410,1410,1410,1410,
+1410,1410,1410,1410,1410,1410,1410,1410,1410,1410,461,461,461,461,461,461,
+1410,1410,1410,1410,1410,1410,1410,1410,1410,1410,1410,1410,1410,1410,1410,1410,
+1410,1410,1410,1410,1410,1410,1410,1410,1410,1410,724,724,1407,1407,1407,1407,
+1411,1411,1410,1410,1410,1410,1410,1410,1410,1410,1410,1410,1410,1410,1411,1411,
/* block 269 */
-1394,1394,1394,1394,1394,1403,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1393,1393,727,727,1393,727,727,727,1393,1393,727,727,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1403,1403,1403,1394,1394,1403,1394,1394,1403,1404,1404,727,727,1394,
-1394,1394,1394,1394,727,727,727,727,727,727,727,727,727,727,727,727,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1393,1393,727,1394,727,1393,727,1394,1394,1394,1405,1405,1405,1405,1405,
+1410,1410,1410,1410,1410,1410,1410,1410,1410,1410,461,461,461,461,1412,461,
+461,1412,1412,1412,1412,1412,1412,1412,1412,1412,1412,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,1407,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1413,1413,1413,1413,1413,1413,1413,1413,1413,1413,
+1413,1413,1413,1413,1413,1413,1413,1413,1413,1413,1413,1413,1413,1413,1413,1413,
/* block 270 */
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,727,
-1394,727,1403,1403,1394,1394,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,
-1403,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,
-1403,1403,1403,1403,1403,1403,1403,1403,1403,1394,1394,1394,1403,1394,1394,1394,
+1414,1412,1415,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+461,461,461,461,461,461,461,461,461,461,1412,461,461,461,461,461,
+461,461,461,461,461,461,461,461,461,461,461,461,461,461,461,1412,
+461,461,1412,1412,1412,1412,1412,1415,1412,1412,1412,461,1409,1409,1409,1409,
+461,461,461,461,461,461,461,461,461,1409,1409,1409,1409,1409,1409,1409,
+1416,1416,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1407,1407,1407,1407,1407,1407,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
/* block 271 */
-1394,1403,1403,1403,1394,1403,1403,1403,1394,1394,1394,1394,1394,1394,1394,1403,
-1394,1403,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1403,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,727,1393,1394,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
/* block 272 */
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,723,723,
-723,723,723,723,723,723,1393,1393,1393,727,727,1394,1394,1394,1394,1393,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1393,1393,1393,1393,1393,1393,1393,727,
-727,1393,1393,727,1404,1404,727,727,727,727,1403,1393,1393,1393,1393,1393,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,728,1407,1407,728,728,728,728,728,728,728,728,728,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,728,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,728,1408,1408,
/* block 273 */
-1393,1393,1393,1393,1393,1393,1393,727,1393,1393,727,727,727,727,1393,1393,
-1404,1393,1393,1393,1393,1403,1403,1393,1393,1393,1393,1393,1393,1393,1393,1393,
-1393,1393,1393,1393,1394,727,1393,1393,727,1393,1393,1393,1393,1393,1393,1393,
-1393,727,727,1393,1393,1393,1393,1393,1393,1393,1393,1393,727,1393,1393,1393,
-1393,1393,727,727,727,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,
-1393,727,727,727,1393,1393,1393,1393,1393,1393,1393,1393,727,727,727,1393,
-1393,727,1393,727,1393,1393,1393,1393,727,1393,1393,1393,1393,1393,1393,727,
-1393,1393,1393,727,1393,1393,1393,1393,1393,1393,727,1394,1394,1394,1394,1394,
+1408,1408,1408,1408,1408,1417,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1407,1407,728,728,1407,728,728,728,1407,1407,728,728,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1417,1417,1417,1408,1408,1417,1408,1408,1417,1418,1418,728,728,1408,
+1408,1408,1408,1408,728,728,728,728,728,728,728,728,728,728,728,728,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1407,1407,728,1408,728,1407,728,1408,1408,1408,1419,1419,1419,1419,1419,
/* block 274 */
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1403,1403,1403,1394,1394,1394,1403,1403,1403,1403,1403,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,728,
+1408,728,1417,1417,1408,1408,1417,1417,1417,1417,1417,1417,1417,1417,1417,1417,
+1417,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1417,1417,1417,1417,1417,1417,1417,1417,1417,1417,
+1417,1417,1417,1417,1417,1417,1417,1417,1417,1408,1408,1408,1417,1408,1408,1408,
/* block 275 */
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1403,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1403,1403,1403,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1403,1394,1394,1394,1394,1394,1393,1393,1393,1393,1393,727,1403,727,727,727,
-1394,1394,1394,1393,1393,1394,1394,1394,1395,1395,1395,1395,1395,1394,1394,1394,
-727,727,727,727,727,727,1393,1393,1393,727,1393,1394,1394,1395,1395,1395,
-727,1393,1393,727,1394,1394,1394,1394,1394,1394,1394,1394,1394,1395,1395,1395,
+1408,1417,1417,1417,1408,1417,1417,1417,1408,1408,1408,1408,1408,1408,1408,1417,
+1408,1417,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1417,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,728,1407,1408,
/* block 276 */
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,724,724,
+724,724,724,724,724,724,1407,1407,1407,728,728,1408,1408,1408,1408,1407,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1407,1407,1407,1407,1407,1407,1407,728,
+728,1407,1407,728,1418,1418,728,728,728,728,1417,1407,1407,1407,1407,1407,
/* block 277 */
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,1393,1393,1393,1393,1395,1395,1395,1395,1395,1395,1395,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1395,1395,1395,1395,
-1394,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
+1407,1407,1407,1407,1407,1407,1407,728,1407,1407,728,728,728,728,1407,1407,
+1418,1407,1407,1407,1407,1417,1417,1407,1407,1407,1407,1407,1407,1407,1407,1407,
+1407,1407,1407,1407,1408,728,1407,1407,728,1407,1407,1407,1407,1407,1407,1407,
+1407,728,728,1407,1407,1407,1407,1407,1407,1407,1407,1407,728,1407,1407,1407,
+1407,1407,728,728,728,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,
+1407,728,728,728,1407,1407,1407,1407,1407,1407,1407,1407,728,728,728,1407,
+1407,728,1407,728,1407,1407,1407,1407,728,1407,1407,1407,1407,1407,1407,728,
+1407,1407,1407,728,1407,1407,1407,1407,1407,1407,728,1408,1408,1408,1408,1408,
/* block 278 */
-723,723,723,723,723,723,723,723,723,723,723,723,1395,1395,1395,1395,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,1395,1395,1395,1395,1395,1395,1395,1395,
-723,723,723,723,723,723,723,723,723,723,1395,1395,1395,1395,1395,1395,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1417,1417,1417,1408,1408,1408,1417,1417,1417,1417,1417,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
/* block 279 */
-723,723,723,723,723,723,723,723,1395,1395,1395,1395,1395,1395,1395,1395,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,1395,1395,
-1393,1393,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1417,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1417,1417,1417,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1417,1408,1408,1408,1408,1408,1407,1407,1407,1407,1407,728,1417,728,728,728,
+1408,1408,1408,1407,1407,1408,1408,1408,1409,1409,1409,1409,1408,1408,1408,1408,
+728,728,728,728,728,728,1407,1407,1407,728,1407,1408,1408,1409,1409,1409,
+728,1407,1407,728,1408,1408,1408,1408,1408,1408,1408,1408,1408,1409,1409,1409,
/* block 280 */
-723,723,723,723,723,723,723,723,723,723,723,723,1403,1394,1394,1403,
-1394,1394,1394,1394,1394,1394,1394,1394,1403,1403,1403,1403,1403,1403,1403,1403,
-1394,1394,1394,1394,1394,1394,1403,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1394,723,1403,1403,1403,1394,
-1394,1394,1394,1394,1394,1394,723,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1403,1394,1394,1394,1394,1394,1394,1394,1394,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,1407,1407,1407,1409,1409,1409,1409,1407,1407,1407,1407,1407,
/* block 281 */
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1406,1406,1406,1406,1394,1403,1403,1394,1403,1403,1394,1403,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1403,1403,1403,
-1394,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1403,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,1407,1407,1407,1407,1407,1409,1409,1409,1409,1409,1409,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1409,1409,1409,1409,
+1408,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
/* block 282 */
-1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,
-1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,
-1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,
-1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,
-1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,
-1393,1393,1393,1393,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1393,1395,1395,
-1394,1394,1394,1394,1394,1395,1395,1395,1394,1394,1394,1394,1394,1395,1395,1395,
+724,724,724,724,724,724,724,724,724,724,724,724,1409,1409,1409,1409,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,1409,1409,1409,1409,1409,1409,1409,1409,
+724,724,724,724,724,724,724,724,724,724,1409,1409,1409,1409,1409,1409,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
/* block 283 */
-1394,1394,1394,1394,1394,1394,1394,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1395,1395,1395,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1395,1395,1395,1395,1395,
-1394,1394,1394,1403,1403,1403,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1394,1394,1394,1394,1394,1394,1394,1394,1394,1394,1395,1395,1395,1395,1395,1395,
-1394,1394,1394,1394,1394,1394,1394,1394,1395,1395,1395,1395,1395,1395,1395,1395,
-1403,1403,1403,1403,1403,1403,1403,1395,1395,1395,1395,1395,1395,1395,1395,1395,
+724,724,724,724,724,724,724,724,1409,1409,1409,1409,1409,1409,1409,1409,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,1409,1409,
+1407,1407,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
/* block 284 */
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
+724,724,724,724,724,724,724,724,724,724,724,724,1417,1408,1408,1417,
+1408,1408,1408,1408,1408,1408,1408,1408,1417,1417,1417,1417,1417,1417,1417,1417,
+1408,1408,1408,1408,1408,1408,1417,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1417,1417,1417,1417,1417,1417,1417,1417,1417,1417,1408,724,1417,1417,1417,1408,
+1408,1408,1408,1408,1408,1408,724,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1417,1408,1408,1408,1408,1408,1408,1408,1408,
/* block 285 */
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,163,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,723,
-723,723,723,723,723,723,723,723,723,723,723,163,163,163,163,163,
-163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,163,163,163,163,163,163,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1420,1420,1420,1420,1408,1417,1417,1408,1417,1417,1408,1417,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1417,1417,1417,
+1408,1417,1417,1417,1417,1417,1417,1417,1417,1417,1417,1417,1417,1417,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
/* block 286 */
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,
-1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,1395,958,958,
+1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,
+1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,
+1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,
+1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,
+1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,
+1407,1407,1407,1407,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1407,1409,1409,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1409,1409,1409,
/* block 287 */
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1409,1409,1409,1409,1409,1409,1409,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1409,1408,
+1408,1408,1408,1417,1417,1417,1409,1409,1409,1409,1409,1409,1409,1409,1408,1408,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1409,1409,1409,1409,
+1408,1408,1408,1408,1408,1408,1408,1408,1408,1409,1409,1409,1409,1409,1409,1409,
+1417,1417,1417,1417,1417,1417,1417,1417,1417,1409,1409,1409,1409,1409,1409,1409,
/* block 288 */
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,163,163,163,163,163,163,163,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
/* block 289 */
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,163,163,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,163,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,724,
+724,724,724,724,724,724,724,724,724,724,724,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+1421,1421,1421,1421,1421,1421,1421,1421,1421,1421,163,163,163,163,163,163,
/* block 290 */
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,
+1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,1409,957,957,
/* block 291 */
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
/* block 292 */
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,953,
-953,953,953,953,953,953,953,953,953,953,953,953,953,953,163,163,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,163,163,163,163,163,163,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+
+/* block 293 */
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,163,163,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+
+/* block 294 */
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+
+/* block 295 */
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+
+/* block 296 */
+952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
+952,952,952,952,952,952,952,952,952,952,952,952,952,952,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
@@ -5315,7 +5369,7 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-/* block 293 */
+/* block 297 */
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
@@ -5323,67 +5377,77 @@ const uint16_t PRIV(ucd_stage2)[] = { /* 76800 bytes, block = 128 */
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-163,163,163,163,163,163,163,163,163,163,163,163,163,163,958,958,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,957,957,
-/* block 294 */
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
-838,838,838,838,838,838,838,838,838,838,838,163,163,163,163,163,
+/* block 298 */
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,163,163,163,163,163,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+
+/* block 299 */
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,839,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
-/* block 295 */
-707,712,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,
-1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
-1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
-1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
-1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
-1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
-1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,1408,
-
-/* block 296 */
-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,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,707,707,707,707,707,707,707,707,707,707,707,707,707,707,
-
-/* block 297 */
-961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
-961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
-961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
-961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
-961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
-961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
-961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
-961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
-
-/* block 298 */
-961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
-961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
-961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
-961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
-961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
-961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
-961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,961,
-707,707,707,707,707,707,707,707,707,707,707,707,707,707,707,707,
-
-/* block 299 */
-952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
-952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
-952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
-952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
-952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
-952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
-952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,952,
-952,952,952,952,952,952,952,952,952,952,952,952,952,952,958,958,
+/* block 300 */
+708,713,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,
+1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,
+1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,
+1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,
+1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,
+1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,
+1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,1422,
+
+/* block 301 */
+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 302 */
+960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,
+960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,
+960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,
+960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,
+960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,
+960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,
+960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,
+960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,
+
+/* block 303 */
+960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,
+960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,
+960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,
+960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,
+960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,
+960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,
+960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,960,
+708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,
+
+/* block 304 */
+951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,
+951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,
+951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,
+951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,
+951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,
+951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,
+951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,951,
+951,951,951,951,951,951,951,951,951,951,951,951,951,951,957,957,
};
#if UCD_BLOCK_SIZE != 128
diff --git a/src/3rdparty/pcre2/src/pcre2_ucp.h b/src/3rdparty/pcre2/src/pcre2_ucp.h
index 282238982d..9ccc829750 100644
--- a/src/3rdparty/pcre2/src/pcre2_ucp.h
+++ b/src/3rdparty/pcre2/src/pcre2_ucp.h
@@ -166,29 +166,29 @@ enum {
/* These are the bidi class values. */
enum {
- ucp_bidiAL, /* Arabic letter */
- ucp_bidiAN, /* Arabic number */
- ucp_bidiB, /* Paragraph separator */
- ucp_bidiBN, /* Boundary neutral */
- ucp_bidiCS, /* Common separator */
- ucp_bidiEN, /* European number */
- ucp_bidiES, /* European separator */
- ucp_bidiET, /* European terminator */
- ucp_bidiFSI, /* First strong isolate */
- ucp_bidiL, /* Left to right */
- ucp_bidiLRE, /* Left to right embedding */
- ucp_bidiLRI, /* Left to right isolate */
- ucp_bidiLRO, /* Left to right override */
- ucp_bidiNSM, /* Non-spacing mark */
- ucp_bidiON, /* Other neutral */
- ucp_bidiPDF, /* Pop directional format */
- ucp_bidiPDI, /* Pop directional isolate */
- ucp_bidiR, /* Right to left */
- ucp_bidiRLE, /* Right to left embedding */
- ucp_bidiRLI, /* Right to left isolate */
- ucp_bidiRLO, /* Right to left override */
- ucp_bidiS, /* Segment separator */
- ucp_bidiWS, /* White space */
+ ucp_bidiAL, /* Arabic_Letter */
+ ucp_bidiAN, /* Arabic_Number */
+ ucp_bidiB, /* Paragraph_Separator */
+ ucp_bidiBN, /* Boundary_Neutral */
+ ucp_bidiCS, /* Common_Separator */
+ ucp_bidiEN, /* European_Number */
+ ucp_bidiES, /* European_Separator */
+ ucp_bidiET, /* European_Terminator */
+ ucp_bidiFSI, /* First_Strong_Isolate */
+ ucp_bidiL, /* Left_To_Right */
+ ucp_bidiLRE, /* Left_To_Right_Embedding */
+ ucp_bidiLRI, /* Left_To_Right_Isolate */
+ ucp_bidiLRO, /* Left_To_Right_Override */
+ ucp_bidiNSM, /* Nonspacing_Mark */
+ ucp_bidiON, /* Other_Neutral */
+ ucp_bidiPDF, /* Pop_Directional_Format */
+ ucp_bidiPDI, /* Pop_Directional_Isolate */
+ ucp_bidiR, /* Right_To_Left */
+ ucp_bidiRLE, /* Right_To_Left_Embedding */
+ ucp_bidiRLI, /* Right_To_Left_Isolate */
+ ucp_bidiRLO, /* Right_To_Left_Override */
+ ucp_bidiS, /* Segment_Separator */
+ ucp_bidiWS, /* White_Space */
};
/* These are grapheme break properties. The Extended Pictographic property
@@ -380,6 +380,8 @@ enum {
ucp_Tangsa,
ucp_Toto,
ucp_Vithkuqi,
+ ucp_Kawi,
+ ucp_Nag_Mundari,
/* This must be last */
ucp_Script_Count
diff --git a/src/3rdparty/pcre2/src/pcre2_ucptables.c b/src/3rdparty/pcre2/src/pcre2_ucptables.c
index bd1b67a9f1..2110014c29 100644
--- a/src/3rdparty/pcre2/src/pcre2_ucptables.c
+++ b/src/3rdparty/pcre2/src/pcre2_ucptables.c
@@ -265,6 +265,7 @@ the "loose matching" rules that Unicode advises and Perl uses. */
#define STRING_kana0 STR_k STR_a STR_n STR_a "\0"
#define STRING_kannada0 STR_k STR_a STR_n STR_n STR_a STR_d STR_a "\0"
#define STRING_katakana0 STR_k STR_a STR_t STR_a STR_k STR_a STR_n STR_a "\0"
+#define STRING_kawi0 STR_k STR_a STR_w STR_i "\0"
#define STRING_kayahli0 STR_k STR_a STR_y STR_a STR_h STR_l STR_i "\0"
#define STRING_khar0 STR_k STR_h STR_a STR_r "\0"
#define STRING_kharoshthi0 STR_k STR_h STR_a STR_r STR_o STR_s STR_h STR_t STR_h STR_i "\0"
@@ -347,6 +348,8 @@ the "loose matching" rules that Unicode advises and Perl uses. */
#define STRING_mymr0 STR_m STR_y STR_m 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"
+#define STRING_nagm0 STR_n STR_a STR_g STR_m "\0"
+#define STRING_nagmundari0 STR_n STR_a STR_g STR_m STR_u STR_n STR_d STR_a STR_r STR_i "\0"
#define STRING_nand0 STR_n STR_a STR_n STR_d "\0"
#define STRING_nandinagari0 STR_n STR_a STR_n STR_d STR_i STR_n STR_a STR_g STR_a STR_r STR_i "\0"
#define STRING_narb0 STR_n STR_a STR_r STR_b "\0"
@@ -753,6 +756,7 @@ const char PRIV(utt_names)[] =
STRING_kana0
STRING_kannada0
STRING_katakana0
+ STRING_kawi0
STRING_kayahli0
STRING_khar0
STRING_kharoshthi0
@@ -835,6 +839,8 @@ const char PRIV(utt_names)[] =
STRING_mymr0
STRING_n0
STRING_nabataean0
+ STRING_nagm0
+ STRING_nagmundari0
STRING_nand0
STRING_nandinagari0
STRING_narb0
@@ -1241,280 +1247,283 @@ const ucp_type_table PRIV(utt)[] = {
{ 1665, PT_SCX, ucp_Katakana },
{ 1670, PT_SCX, ucp_Kannada },
{ 1678, PT_SCX, ucp_Katakana },
- { 1687, PT_SCX, ucp_Kayah_Li },
- { 1695, PT_SC, ucp_Kharoshthi },
+ { 1687, PT_SC, ucp_Kawi },
+ { 1692, PT_SCX, ucp_Kayah_Li },
{ 1700, PT_SC, ucp_Kharoshthi },
- { 1711, PT_SC, ucp_Khitan_Small_Script },
- { 1729, PT_SC, ucp_Khmer },
- { 1735, PT_SC, ucp_Khmer },
- { 1740, PT_SCX, ucp_Khojki },
+ { 1705, PT_SC, ucp_Kharoshthi },
+ { 1716, PT_SC, ucp_Khitan_Small_Script },
+ { 1734, PT_SC, ucp_Khmer },
+ { 1740, PT_SC, ucp_Khmer },
{ 1745, PT_SCX, ucp_Khojki },
- { 1752, PT_SCX, ucp_Khudawadi },
- { 1762, PT_SC, ucp_Khitan_Small_Script },
- { 1767, PT_SCX, ucp_Kannada },
- { 1772, PT_SCX, ucp_Kaithi },
- { 1777, PT_GC, ucp_L },
- { 1779, PT_LAMP, 0 },
- { 1782, PT_SC, ucp_Tai_Tham },
- { 1787, PT_SC, ucp_Lao },
- { 1791, PT_SC, ucp_Lao },
- { 1796, PT_SCX, ucp_Latin },
- { 1802, PT_SCX, ucp_Latin },
- { 1807, PT_LAMP, 0 },
- { 1810, PT_SC, ucp_Lepcha },
+ { 1750, PT_SCX, ucp_Khojki },
+ { 1757, PT_SCX, ucp_Khudawadi },
+ { 1767, PT_SC, ucp_Khitan_Small_Script },
+ { 1772, PT_SCX, ucp_Kannada },
+ { 1777, PT_SCX, ucp_Kaithi },
+ { 1782, PT_GC, ucp_L },
+ { 1784, PT_LAMP, 0 },
+ { 1787, PT_SC, ucp_Tai_Tham },
+ { 1792, PT_SC, ucp_Lao },
+ { 1796, PT_SC, ucp_Lao },
+ { 1801, PT_SCX, ucp_Latin },
+ { 1807, PT_SCX, ucp_Latin },
+ { 1812, PT_LAMP, 0 },
{ 1815, PT_SC, ucp_Lepcha },
- { 1822, PT_SCX, ucp_Limbu },
+ { 1820, PT_SC, ucp_Lepcha },
{ 1827, PT_SCX, ucp_Limbu },
- { 1833, PT_SCX, ucp_Linear_A },
- { 1838, PT_SCX, ucp_Linear_B },
- { 1843, PT_SCX, ucp_Linear_A },
- { 1851, PT_SCX, ucp_Linear_B },
- { 1859, PT_SC, ucp_Lisu },
- { 1864, PT_PC, ucp_Ll },
- { 1867, PT_PC, ucp_Lm },
- { 1870, PT_PC, ucp_Lo },
- { 1873, PT_BOOL, ucp_Logical_Order_Exception },
- { 1877, PT_BOOL, ucp_Logical_Order_Exception },
- { 1899, PT_BOOL, ucp_Lowercase },
- { 1905, PT_BOOL, ucp_Lowercase },
- { 1915, PT_PC, ucp_Lt },
- { 1918, PT_PC, ucp_Lu },
- { 1921, PT_SC, ucp_Lycian },
+ { 1832, PT_SCX, ucp_Limbu },
+ { 1838, PT_SCX, ucp_Linear_A },
+ { 1843, PT_SCX, ucp_Linear_B },
+ { 1848, PT_SCX, ucp_Linear_A },
+ { 1856, PT_SCX, ucp_Linear_B },
+ { 1864, PT_SC, ucp_Lisu },
+ { 1869, PT_PC, ucp_Ll },
+ { 1872, PT_PC, ucp_Lm },
+ { 1875, PT_PC, ucp_Lo },
+ { 1878, PT_BOOL, ucp_Logical_Order_Exception },
+ { 1882, PT_BOOL, ucp_Logical_Order_Exception },
+ { 1904, PT_BOOL, ucp_Lowercase },
+ { 1910, PT_BOOL, ucp_Lowercase },
+ { 1920, PT_PC, ucp_Lt },
+ { 1923, PT_PC, ucp_Lu },
{ 1926, PT_SC, ucp_Lycian },
- { 1933, PT_SC, ucp_Lydian },
+ { 1931, PT_SC, ucp_Lycian },
{ 1938, PT_SC, ucp_Lydian },
- { 1945, PT_GC, ucp_M },
- { 1947, PT_SCX, ucp_Mahajani },
- { 1956, PT_SCX, ucp_Mahajani },
- { 1961, PT_SC, ucp_Makasar },
+ { 1943, PT_SC, ucp_Lydian },
+ { 1950, PT_GC, ucp_M },
+ { 1952, PT_SCX, ucp_Mahajani },
+ { 1961, PT_SCX, ucp_Mahajani },
{ 1966, PT_SC, ucp_Makasar },
- { 1974, PT_SCX, ucp_Malayalam },
- { 1984, PT_SCX, ucp_Mandaic },
+ { 1971, PT_SC, ucp_Makasar },
+ { 1979, PT_SCX, ucp_Malayalam },
{ 1989, PT_SCX, ucp_Mandaic },
- { 1997, PT_SCX, ucp_Manichaean },
+ { 1994, PT_SCX, ucp_Mandaic },
{ 2002, PT_SCX, ucp_Manichaean },
- { 2013, PT_SC, ucp_Marchen },
+ { 2007, PT_SCX, ucp_Manichaean },
{ 2018, PT_SC, ucp_Marchen },
- { 2026, PT_SCX, ucp_Masaram_Gondi },
- { 2039, PT_BOOL, ucp_Math },
- { 2044, PT_PC, ucp_Mc },
- { 2047, PT_PC, ucp_Me },
- { 2050, PT_SC, ucp_Medefaidrin },
- { 2062, PT_SC, ucp_Medefaidrin },
- { 2067, PT_SC, ucp_Meetei_Mayek },
- { 2079, PT_SC, ucp_Mende_Kikakui },
+ { 2023, PT_SC, ucp_Marchen },
+ { 2031, PT_SCX, ucp_Masaram_Gondi },
+ { 2044, PT_BOOL, ucp_Math },
+ { 2049, PT_PC, ucp_Mc },
+ { 2052, PT_PC, ucp_Me },
+ { 2055, PT_SC, ucp_Medefaidrin },
+ { 2067, PT_SC, ucp_Medefaidrin },
+ { 2072, PT_SC, ucp_Meetei_Mayek },
{ 2084, PT_SC, ucp_Mende_Kikakui },
- { 2097, PT_SC, ucp_Meroitic_Cursive },
- { 2102, PT_SC, ucp_Meroitic_Hieroglyphs },
- { 2107, PT_SC, ucp_Meroitic_Cursive },
- { 2123, PT_SC, ucp_Meroitic_Hieroglyphs },
- { 2143, PT_SC, ucp_Miao },
- { 2148, PT_SCX, ucp_Malayalam },
- { 2153, PT_PC, ucp_Mn },
- { 2156, PT_SCX, ucp_Modi },
- { 2161, PT_SCX, ucp_Mongolian },
+ { 2089, PT_SC, ucp_Mende_Kikakui },
+ { 2102, PT_SC, ucp_Meroitic_Cursive },
+ { 2107, PT_SC, ucp_Meroitic_Hieroglyphs },
+ { 2112, PT_SC, ucp_Meroitic_Cursive },
+ { 2128, PT_SC, ucp_Meroitic_Hieroglyphs },
+ { 2148, PT_SC, ucp_Miao },
+ { 2153, PT_SCX, ucp_Malayalam },
+ { 2158, PT_PC, ucp_Mn },
+ { 2161, PT_SCX, ucp_Modi },
{ 2166, PT_SCX, ucp_Mongolian },
- { 2176, PT_SC, ucp_Mro },
- { 2180, PT_SC, ucp_Mro },
- { 2185, PT_SC, ucp_Meetei_Mayek },
- { 2190, PT_SCX, ucp_Multani },
+ { 2171, PT_SCX, ucp_Mongolian },
+ { 2181, PT_SC, ucp_Mro },
+ { 2185, PT_SC, ucp_Mro },
+ { 2190, PT_SC, ucp_Meetei_Mayek },
{ 2195, PT_SCX, ucp_Multani },
- { 2203, PT_SCX, ucp_Myanmar },
- { 2211, PT_SCX, ucp_Myanmar },
- { 2216, PT_GC, ucp_N },
- { 2218, PT_SC, ucp_Nabataean },
- { 2228, PT_SCX, ucp_Nandinagari },
- { 2233, PT_SCX, ucp_Nandinagari },
- { 2245, PT_SC, ucp_Old_North_Arabian },
- { 2250, PT_SC, ucp_Nabataean },
- { 2255, PT_BOOL, ucp_Noncharacter_Code_Point },
- { 2261, PT_PC, ucp_Nd },
- { 2264, PT_SC, ucp_Newa },
- { 2269, PT_SC, ucp_New_Tai_Lue },
- { 2279, PT_SCX, ucp_Nko },
- { 2283, PT_SCX, ucp_Nko },
- { 2288, PT_PC, ucp_Nl },
- { 2291, PT_PC, ucp_No },
- { 2294, PT_BOOL, ucp_Noncharacter_Code_Point },
- { 2316, PT_SC, ucp_Nushu },
- { 2321, PT_SC, ucp_Nushu },
- { 2327, PT_SC, ucp_Nyiakeng_Puachue_Hmong },
- { 2348, PT_SC, ucp_Ogham },
- { 2353, PT_SC, ucp_Ogham },
- { 2359, PT_SC, ucp_Ol_Chiki },
- { 2367, PT_SC, ucp_Ol_Chiki },
- { 2372, PT_SC, ucp_Old_Hungarian },
- { 2385, PT_SC, ucp_Old_Italic },
- { 2395, PT_SC, ucp_Old_North_Arabian },
- { 2411, PT_SCX, ucp_Old_Permic },
- { 2421, PT_SC, ucp_Old_Persian },
- { 2432, PT_SC, ucp_Old_Sogdian },
- { 2443, PT_SC, ucp_Old_South_Arabian },
- { 2459, PT_SC, ucp_Old_Turkic },
- { 2469, PT_SCX, ucp_Old_Uyghur },
- { 2479, PT_SCX, ucp_Oriya },
- { 2485, PT_SC, ucp_Old_Turkic },
- { 2490, PT_SCX, ucp_Oriya },
- { 2495, PT_SC, ucp_Osage },
- { 2501, PT_SC, ucp_Osage },
- { 2506, PT_SC, ucp_Osmanya },
- { 2511, PT_SC, ucp_Osmanya },
- { 2519, PT_SCX, ucp_Old_Uyghur },
- { 2524, PT_GC, ucp_P },
- { 2526, PT_SC, ucp_Pahawh_Hmong },
- { 2538, PT_SC, ucp_Palmyrene },
- { 2543, PT_SC, ucp_Palmyrene },
- { 2553, PT_BOOL, ucp_Pattern_Syntax },
- { 2560, PT_BOOL, ucp_Pattern_Syntax },
- { 2574, PT_BOOL, ucp_Pattern_White_Space },
- { 2592, PT_BOOL, ucp_Pattern_White_Space },
- { 2598, PT_SC, ucp_Pau_Cin_Hau },
- { 2603, PT_SC, ucp_Pau_Cin_Hau },
- { 2613, PT_PC, ucp_Pc },
- { 2616, PT_BOOL, ucp_Prepended_Concatenation_Mark },
- { 2620, PT_PC, ucp_Pd },
- { 2623, PT_PC, ucp_Pe },
- { 2626, PT_SCX, ucp_Old_Permic },
- { 2631, PT_PC, ucp_Pf },
- { 2634, PT_SCX, ucp_Phags_Pa },
- { 2639, PT_SCX, ucp_Phags_Pa },
- { 2647, PT_SC, ucp_Inscriptional_Pahlavi },
- { 2652, PT_SCX, ucp_Psalter_Pahlavi },
- { 2657, PT_SC, ucp_Phoenician },
- { 2662, PT_SC, ucp_Phoenician },
- { 2673, PT_PC, ucp_Pi },
- { 2676, PT_SC, ucp_Miao },
- { 2681, PT_PC, ucp_Po },
- { 2684, PT_BOOL, ucp_Prepended_Concatenation_Mark },
- { 2711, PT_SC, ucp_Inscriptional_Parthian },
- { 2716, PT_PC, ucp_Ps },
- { 2719, PT_SCX, ucp_Psalter_Pahlavi },
- { 2734, PT_SCX, ucp_Coptic },
- { 2739, PT_SC, ucp_Inherited },
- { 2744, PT_BOOL, ucp_Quotation_Mark },
- { 2750, PT_BOOL, ucp_Quotation_Mark },
- { 2764, PT_BOOL, ucp_Radical },
- { 2772, PT_BOOL, ucp_Regional_Indicator },
- { 2790, PT_SC, ucp_Rejang },
- { 2797, PT_BOOL, ucp_Regional_Indicator },
- { 2800, PT_SC, ucp_Rejang },
- { 2805, PT_SCX, ucp_Hanifi_Rohingya },
- { 2810, PT_SC, ucp_Runic },
- { 2816, PT_SC, ucp_Runic },
- { 2821, PT_GC, ucp_S },
- { 2823, PT_SC, ucp_Samaritan },
- { 2833, PT_SC, ucp_Samaritan },
- { 2838, PT_SC, ucp_Old_South_Arabian },
- { 2843, PT_SC, ucp_Saurashtra },
- { 2848, PT_SC, ucp_Saurashtra },
- { 2859, PT_PC, ucp_Sc },
- { 2862, PT_BOOL, ucp_Soft_Dotted },
- { 2865, PT_BOOL, ucp_Sentence_Terminal },
- { 2882, PT_SC, ucp_SignWriting },
- { 2887, PT_SCX, ucp_Sharada },
- { 2895, PT_SC, ucp_Shavian },
- { 2903, PT_SC, ucp_Shavian },
+ { 2200, PT_SCX, ucp_Multani },
+ { 2208, PT_SCX, ucp_Myanmar },
+ { 2216, PT_SCX, ucp_Myanmar },
+ { 2221, PT_GC, ucp_N },
+ { 2223, PT_SC, ucp_Nabataean },
+ { 2233, PT_SC, ucp_Nag_Mundari },
+ { 2238, PT_SC, ucp_Nag_Mundari },
+ { 2249, PT_SCX, ucp_Nandinagari },
+ { 2254, PT_SCX, ucp_Nandinagari },
+ { 2266, PT_SC, ucp_Old_North_Arabian },
+ { 2271, PT_SC, ucp_Nabataean },
+ { 2276, PT_BOOL, ucp_Noncharacter_Code_Point },
+ { 2282, PT_PC, ucp_Nd },
+ { 2285, PT_SC, ucp_Newa },
+ { 2290, PT_SC, ucp_New_Tai_Lue },
+ { 2300, PT_SCX, ucp_Nko },
+ { 2304, PT_SCX, ucp_Nko },
+ { 2309, PT_PC, ucp_Nl },
+ { 2312, PT_PC, ucp_No },
+ { 2315, PT_BOOL, ucp_Noncharacter_Code_Point },
+ { 2337, PT_SC, ucp_Nushu },
+ { 2342, PT_SC, ucp_Nushu },
+ { 2348, PT_SC, ucp_Nyiakeng_Puachue_Hmong },
+ { 2369, PT_SC, ucp_Ogham },
+ { 2374, PT_SC, ucp_Ogham },
+ { 2380, PT_SC, ucp_Ol_Chiki },
+ { 2388, PT_SC, ucp_Ol_Chiki },
+ { 2393, PT_SC, ucp_Old_Hungarian },
+ { 2406, PT_SC, ucp_Old_Italic },
+ { 2416, PT_SC, ucp_Old_North_Arabian },
+ { 2432, PT_SCX, ucp_Old_Permic },
+ { 2442, PT_SC, ucp_Old_Persian },
+ { 2453, PT_SC, ucp_Old_Sogdian },
+ { 2464, PT_SC, ucp_Old_South_Arabian },
+ { 2480, PT_SC, ucp_Old_Turkic },
+ { 2490, PT_SCX, ucp_Old_Uyghur },
+ { 2500, PT_SCX, ucp_Oriya },
+ { 2506, PT_SC, ucp_Old_Turkic },
+ { 2511, PT_SCX, ucp_Oriya },
+ { 2516, PT_SC, ucp_Osage },
+ { 2522, PT_SC, ucp_Osage },
+ { 2527, PT_SC, ucp_Osmanya },
+ { 2532, PT_SC, ucp_Osmanya },
+ { 2540, PT_SCX, ucp_Old_Uyghur },
+ { 2545, PT_GC, ucp_P },
+ { 2547, PT_SC, ucp_Pahawh_Hmong },
+ { 2559, PT_SC, ucp_Palmyrene },
+ { 2564, PT_SC, ucp_Palmyrene },
+ { 2574, PT_BOOL, ucp_Pattern_Syntax },
+ { 2581, PT_BOOL, ucp_Pattern_Syntax },
+ { 2595, PT_BOOL, ucp_Pattern_White_Space },
+ { 2613, PT_BOOL, ucp_Pattern_White_Space },
+ { 2619, PT_SC, ucp_Pau_Cin_Hau },
+ { 2624, PT_SC, ucp_Pau_Cin_Hau },
+ { 2634, PT_PC, ucp_Pc },
+ { 2637, PT_BOOL, ucp_Prepended_Concatenation_Mark },
+ { 2641, PT_PC, ucp_Pd },
+ { 2644, PT_PC, ucp_Pe },
+ { 2647, PT_SCX, ucp_Old_Permic },
+ { 2652, PT_PC, ucp_Pf },
+ { 2655, PT_SCX, ucp_Phags_Pa },
+ { 2660, PT_SCX, ucp_Phags_Pa },
+ { 2668, PT_SC, ucp_Inscriptional_Pahlavi },
+ { 2673, PT_SCX, ucp_Psalter_Pahlavi },
+ { 2678, PT_SC, ucp_Phoenician },
+ { 2683, PT_SC, ucp_Phoenician },
+ { 2694, PT_PC, ucp_Pi },
+ { 2697, PT_SC, ucp_Miao },
+ { 2702, PT_PC, ucp_Po },
+ { 2705, PT_BOOL, ucp_Prepended_Concatenation_Mark },
+ { 2732, PT_SC, ucp_Inscriptional_Parthian },
+ { 2737, PT_PC, ucp_Ps },
+ { 2740, PT_SCX, ucp_Psalter_Pahlavi },
+ { 2755, PT_SCX, ucp_Coptic },
+ { 2760, PT_SC, ucp_Inherited },
+ { 2765, PT_BOOL, ucp_Quotation_Mark },
+ { 2771, PT_BOOL, ucp_Quotation_Mark },
+ { 2785, PT_BOOL, ucp_Radical },
+ { 2793, PT_BOOL, ucp_Regional_Indicator },
+ { 2811, PT_SC, ucp_Rejang },
+ { 2818, PT_BOOL, ucp_Regional_Indicator },
+ { 2821, PT_SC, ucp_Rejang },
+ { 2826, PT_SCX, ucp_Hanifi_Rohingya },
+ { 2831, PT_SC, ucp_Runic },
+ { 2837, PT_SC, ucp_Runic },
+ { 2842, PT_GC, ucp_S },
+ { 2844, PT_SC, ucp_Samaritan },
+ { 2854, PT_SC, ucp_Samaritan },
+ { 2859, PT_SC, ucp_Old_South_Arabian },
+ { 2864, PT_SC, ucp_Saurashtra },
+ { 2869, PT_SC, ucp_Saurashtra },
+ { 2880, PT_PC, ucp_Sc },
+ { 2883, PT_BOOL, ucp_Soft_Dotted },
+ { 2886, PT_BOOL, ucp_Sentence_Terminal },
+ { 2903, PT_SC, ucp_SignWriting },
{ 2908, PT_SCX, ucp_Sharada },
- { 2913, PT_SC, ucp_Siddham },
- { 2918, PT_SC, ucp_Siddham },
- { 2926, PT_SC, ucp_SignWriting },
- { 2938, PT_SCX, ucp_Khudawadi },
- { 2943, PT_SCX, ucp_Sinhala },
- { 2948, PT_SCX, ucp_Sinhala },
- { 2956, PT_PC, ucp_Sk },
- { 2959, PT_PC, ucp_Sm },
- { 2962, PT_PC, ucp_So },
- { 2965, PT_BOOL, ucp_Soft_Dotted },
- { 2976, PT_SCX, ucp_Sogdian },
- { 2981, PT_SCX, ucp_Sogdian },
- { 2989, PT_SC, ucp_Old_Sogdian },
- { 2994, PT_SC, ucp_Sora_Sompeng },
- { 2999, PT_SC, ucp_Sora_Sompeng },
- { 3011, PT_SC, ucp_Soyombo },
- { 3016, PT_SC, ucp_Soyombo },
- { 3024, PT_BOOL, ucp_White_Space },
- { 3030, PT_BOOL, ucp_Sentence_Terminal },
- { 3036, PT_SC, ucp_Sundanese },
- { 3041, PT_SC, ucp_Sundanese },
- { 3051, PT_SCX, ucp_Syloti_Nagri },
- { 3056, PT_SCX, ucp_Syloti_Nagri },
- { 3068, PT_SCX, ucp_Syriac },
- { 3073, PT_SCX, ucp_Syriac },
- { 3080, PT_SCX, ucp_Tagalog },
- { 3088, PT_SCX, ucp_Tagbanwa },
- { 3093, PT_SCX, ucp_Tagbanwa },
- { 3102, PT_SCX, ucp_Tai_Le },
- { 3108, PT_SC, ucp_Tai_Tham },
- { 3116, PT_SC, ucp_Tai_Viet },
- { 3124, PT_SCX, ucp_Takri },
- { 3129, PT_SCX, ucp_Takri },
- { 3135, PT_SCX, ucp_Tai_Le },
- { 3140, PT_SC, ucp_New_Tai_Lue },
- { 3145, PT_SCX, ucp_Tamil },
- { 3151, PT_SCX, ucp_Tamil },
- { 3156, PT_SC, ucp_Tangut },
- { 3161, PT_SC, ucp_Tangsa },
- { 3168, PT_SC, ucp_Tangut },
- { 3175, PT_SC, ucp_Tai_Viet },
- { 3180, PT_SCX, ucp_Telugu },
- { 3185, PT_SCX, ucp_Telugu },
- { 3192, PT_BOOL, ucp_Terminal_Punctuation },
- { 3197, PT_BOOL, ucp_Terminal_Punctuation },
- { 3217, PT_SC, ucp_Tifinagh },
- { 3222, PT_SCX, ucp_Tagalog },
- { 3227, PT_SCX, ucp_Thaana },
- { 3232, PT_SCX, ucp_Thaana },
- { 3239, PT_SC, ucp_Thai },
- { 3244, PT_SC, ucp_Tibetan },
- { 3252, PT_SC, ucp_Tibetan },
- { 3257, PT_SC, ucp_Tifinagh },
- { 3266, PT_SCX, ucp_Tirhuta },
- { 3271, PT_SCX, ucp_Tirhuta },
- { 3279, PT_SC, ucp_Tangsa },
- { 3284, PT_SC, ucp_Toto },
- { 3289, PT_SC, ucp_Ugaritic },
- { 3294, PT_SC, ucp_Ugaritic },
- { 3303, PT_BOOL, ucp_Unified_Ideograph },
- { 3309, PT_BOOL, ucp_Unified_Ideograph },
- { 3326, PT_SC, ucp_Unknown },
- { 3334, PT_BOOL, ucp_Uppercase },
- { 3340, PT_BOOL, ucp_Uppercase },
- { 3350, PT_SC, ucp_Vai },
- { 3354, PT_SC, ucp_Vai },
- { 3359, PT_BOOL, ucp_Variation_Selector },
- { 3377, PT_SC, ucp_Vithkuqi },
- { 3382, PT_SC, ucp_Vithkuqi },
- { 3391, PT_BOOL, ucp_Variation_Selector },
- { 3394, PT_SC, ucp_Wancho },
- { 3401, PT_SC, ucp_Warang_Citi },
- { 3406, PT_SC, ucp_Warang_Citi },
- { 3417, PT_SC, ucp_Wancho },
- { 3422, PT_BOOL, ucp_White_Space },
- { 3433, PT_BOOL, ucp_White_Space },
- { 3440, PT_ALNUM, 0 },
- { 3444, PT_BOOL, ucp_XID_Continue },
- { 3449, PT_BOOL, ucp_XID_Continue },
- { 3461, PT_BOOL, ucp_XID_Start },
- { 3466, PT_BOOL, ucp_XID_Start },
- { 3475, PT_SC, ucp_Old_Persian },
- { 3480, PT_PXSPACE, 0 },
- { 3484, PT_SPACE, 0 },
- { 3488, PT_SC, ucp_Cuneiform },
- { 3493, PT_UCNC, 0 },
- { 3497, PT_WORD, 0 },
- { 3501, PT_SCX, ucp_Yezidi },
- { 3506, PT_SCX, ucp_Yezidi },
- { 3513, PT_SCX, ucp_Yi },
- { 3516, PT_SCX, ucp_Yi },
- { 3521, PT_GC, ucp_Z },
- { 3523, PT_SC, ucp_Zanabazar_Square },
- { 3539, PT_SC, ucp_Zanabazar_Square },
- { 3544, PT_SC, ucp_Inherited },
- { 3549, PT_PC, ucp_Zl },
- { 3552, PT_PC, ucp_Zp },
- { 3555, PT_PC, ucp_Zs },
- { 3558, PT_SC, ucp_Common },
- { 3563, PT_SC, ucp_Unknown }
+ { 2916, PT_SC, ucp_Shavian },
+ { 2924, PT_SC, ucp_Shavian },
+ { 2929, PT_SCX, ucp_Sharada },
+ { 2934, PT_SC, ucp_Siddham },
+ { 2939, PT_SC, ucp_Siddham },
+ { 2947, PT_SC, ucp_SignWriting },
+ { 2959, PT_SCX, ucp_Khudawadi },
+ { 2964, PT_SCX, ucp_Sinhala },
+ { 2969, PT_SCX, ucp_Sinhala },
+ { 2977, PT_PC, ucp_Sk },
+ { 2980, PT_PC, ucp_Sm },
+ { 2983, PT_PC, ucp_So },
+ { 2986, PT_BOOL, ucp_Soft_Dotted },
+ { 2997, PT_SCX, ucp_Sogdian },
+ { 3002, PT_SCX, ucp_Sogdian },
+ { 3010, PT_SC, ucp_Old_Sogdian },
+ { 3015, PT_SC, ucp_Sora_Sompeng },
+ { 3020, PT_SC, ucp_Sora_Sompeng },
+ { 3032, PT_SC, ucp_Soyombo },
+ { 3037, PT_SC, ucp_Soyombo },
+ { 3045, PT_BOOL, ucp_White_Space },
+ { 3051, PT_BOOL, ucp_Sentence_Terminal },
+ { 3057, PT_SC, ucp_Sundanese },
+ { 3062, PT_SC, ucp_Sundanese },
+ { 3072, PT_SCX, ucp_Syloti_Nagri },
+ { 3077, PT_SCX, ucp_Syloti_Nagri },
+ { 3089, PT_SCX, ucp_Syriac },
+ { 3094, PT_SCX, ucp_Syriac },
+ { 3101, PT_SCX, ucp_Tagalog },
+ { 3109, PT_SCX, ucp_Tagbanwa },
+ { 3114, PT_SCX, ucp_Tagbanwa },
+ { 3123, PT_SCX, ucp_Tai_Le },
+ { 3129, PT_SC, ucp_Tai_Tham },
+ { 3137, PT_SC, ucp_Tai_Viet },
+ { 3145, PT_SCX, ucp_Takri },
+ { 3150, PT_SCX, ucp_Takri },
+ { 3156, PT_SCX, ucp_Tai_Le },
+ { 3161, PT_SC, ucp_New_Tai_Lue },
+ { 3166, PT_SCX, ucp_Tamil },
+ { 3172, PT_SCX, ucp_Tamil },
+ { 3177, PT_SC, ucp_Tangut },
+ { 3182, PT_SC, ucp_Tangsa },
+ { 3189, PT_SC, ucp_Tangut },
+ { 3196, PT_SC, ucp_Tai_Viet },
+ { 3201, PT_SCX, ucp_Telugu },
+ { 3206, PT_SCX, ucp_Telugu },
+ { 3213, PT_BOOL, ucp_Terminal_Punctuation },
+ { 3218, PT_BOOL, ucp_Terminal_Punctuation },
+ { 3238, PT_SC, ucp_Tifinagh },
+ { 3243, PT_SCX, ucp_Tagalog },
+ { 3248, PT_SCX, ucp_Thaana },
+ { 3253, PT_SCX, ucp_Thaana },
+ { 3260, PT_SC, ucp_Thai },
+ { 3265, PT_SC, ucp_Tibetan },
+ { 3273, PT_SC, ucp_Tibetan },
+ { 3278, PT_SC, ucp_Tifinagh },
+ { 3287, PT_SCX, ucp_Tirhuta },
+ { 3292, PT_SCX, ucp_Tirhuta },
+ { 3300, PT_SC, ucp_Tangsa },
+ { 3305, PT_SC, ucp_Toto },
+ { 3310, PT_SC, ucp_Ugaritic },
+ { 3315, PT_SC, ucp_Ugaritic },
+ { 3324, PT_BOOL, ucp_Unified_Ideograph },
+ { 3330, PT_BOOL, ucp_Unified_Ideograph },
+ { 3347, PT_SC, ucp_Unknown },
+ { 3355, PT_BOOL, ucp_Uppercase },
+ { 3361, PT_BOOL, ucp_Uppercase },
+ { 3371, PT_SC, ucp_Vai },
+ { 3375, PT_SC, ucp_Vai },
+ { 3380, PT_BOOL, ucp_Variation_Selector },
+ { 3398, PT_SC, ucp_Vithkuqi },
+ { 3403, PT_SC, ucp_Vithkuqi },
+ { 3412, PT_BOOL, ucp_Variation_Selector },
+ { 3415, PT_SC, ucp_Wancho },
+ { 3422, PT_SC, ucp_Warang_Citi },
+ { 3427, PT_SC, ucp_Warang_Citi },
+ { 3438, PT_SC, ucp_Wancho },
+ { 3443, PT_BOOL, ucp_White_Space },
+ { 3454, PT_BOOL, ucp_White_Space },
+ { 3461, PT_ALNUM, 0 },
+ { 3465, PT_BOOL, ucp_XID_Continue },
+ { 3470, PT_BOOL, ucp_XID_Continue },
+ { 3482, PT_BOOL, ucp_XID_Start },
+ { 3487, PT_BOOL, ucp_XID_Start },
+ { 3496, PT_SC, ucp_Old_Persian },
+ { 3501, PT_PXSPACE, 0 },
+ { 3505, PT_SPACE, 0 },
+ { 3509, PT_SC, ucp_Cuneiform },
+ { 3514, PT_UCNC, 0 },
+ { 3518, PT_WORD, 0 },
+ { 3522, PT_SCX, ucp_Yezidi },
+ { 3527, PT_SCX, ucp_Yezidi },
+ { 3534, PT_SCX, ucp_Yi },
+ { 3537, PT_SCX, ucp_Yi },
+ { 3542, PT_GC, ucp_Z },
+ { 3544, PT_SC, ucp_Zanabazar_Square },
+ { 3560, PT_SC, ucp_Zanabazar_Square },
+ { 3565, PT_SC, ucp_Inherited },
+ { 3570, PT_PC, ucp_Zl },
+ { 3573, PT_PC, ucp_Zp },
+ { 3576, PT_PC, ucp_Zs },
+ { 3579, PT_SC, ucp_Common },
+ { 3584, PT_SC, ucp_Unknown }
};
const size_t PRIV(utt_size) = sizeof(PRIV(utt)) / sizeof(ucp_type_table);
diff --git a/src/3rdparty/pcre2/src/pcre2_valid_utf.c b/src/3rdparty/pcre2/src/pcre2_valid_utf.c
index e47ea78f16..de411b919e 100644
--- a/src/3rdparty/pcre2/src/pcre2_valid_utf.c
+++ b/src/3rdparty/pcre2/src/pcre2_valid_utf.c
@@ -171,7 +171,7 @@ for (p = string; length > 0; p++)
if (((d = *(++p)) & 0xc0) != 0x80)
{
- *erroroffset = (int)(p - string) - 1;
+ *erroroffset = (PCRE2_SIZE)(p - string) - 1;
return PCRE2_ERROR_UTF8_ERR6;
}
@@ -186,7 +186,7 @@ for (p = string; length > 0; p++)
case 1: if ((c & 0x3e) == 0)
{
- *erroroffset = (int)(p - string) - 1;
+ *erroroffset = (PCRE2_SIZE)(p - string) - 1;
return PCRE2_ERROR_UTF8_ERR15;
}
break;
@@ -198,17 +198,17 @@ for (p = string; length > 0; p++)
case 2:
if ((*(++p) & 0xc0) != 0x80) /* Third byte */
{
- *erroroffset = (int)(p - string) - 2;
+ *erroroffset = (PCRE2_SIZE)(p - string) - 2;
return PCRE2_ERROR_UTF8_ERR7;
}
if (c == 0xe0 && (d & 0x20) == 0)
{
- *erroroffset = (int)(p - string) - 2;
+ *erroroffset = (PCRE2_SIZE)(p - string) - 2;
return PCRE2_ERROR_UTF8_ERR16;
}
if (c == 0xed && d >= 0xa0)
{
- *erroroffset = (int)(p - string) - 2;
+ *erroroffset = (PCRE2_SIZE)(p - string) - 2;
return PCRE2_ERROR_UTF8_ERR14;
}
break;
@@ -220,22 +220,22 @@ for (p = string; length > 0; p++)
case 3:
if ((*(++p) & 0xc0) != 0x80) /* Third byte */
{
- *erroroffset = (int)(p - string) - 2;
+ *erroroffset = (PCRE2_SIZE)(p - string) - 2;
return PCRE2_ERROR_UTF8_ERR7;
}
if ((*(++p) & 0xc0) != 0x80) /* Fourth byte */
{
- *erroroffset = (int)(p - string) - 3;
+ *erroroffset = (PCRE2_SIZE)(p - string) - 3;
return PCRE2_ERROR_UTF8_ERR8;
}
if (c == 0xf0 && (d & 0x30) == 0)
{
- *erroroffset = (int)(p - string) - 3;
+ *erroroffset = (PCRE2_SIZE)(p - string) - 3;
return PCRE2_ERROR_UTF8_ERR17;
}
if (c > 0xf4 || (c == 0xf4 && d > 0x8f))
{
- *erroroffset = (int)(p - string) - 3;
+ *erroroffset = (PCRE2_SIZE)(p - string) - 3;
return PCRE2_ERROR_UTF8_ERR13;
}
break;
@@ -251,22 +251,22 @@ for (p = string; length > 0; p++)
case 4:
if ((*(++p) & 0xc0) != 0x80) /* Third byte */
{
- *erroroffset = (int)(p - string) - 2;
+ *erroroffset = (PCRE2_SIZE)(p - string) - 2;
return PCRE2_ERROR_UTF8_ERR7;
}
if ((*(++p) & 0xc0) != 0x80) /* Fourth byte */
{
- *erroroffset = (int)(p - string) - 3;
+ *erroroffset = (PCRE2_SIZE)(p - string) - 3;
return PCRE2_ERROR_UTF8_ERR8;
}
if ((*(++p) & 0xc0) != 0x80) /* Fifth byte */
{
- *erroroffset = (int)(p - string) - 4;
+ *erroroffset = (PCRE2_SIZE)(p - string) - 4;
return PCRE2_ERROR_UTF8_ERR9;
}
if (c == 0xf8 && (d & 0x38) == 0)
{
- *erroroffset = (int)(p - string) - 4;
+ *erroroffset = (PCRE2_SIZE)(p - string) - 4;
return PCRE2_ERROR_UTF8_ERR18;
}
break;
@@ -277,27 +277,27 @@ for (p = string; length > 0; p++)
case 5:
if ((*(++p) & 0xc0) != 0x80) /* Third byte */
{
- *erroroffset = (int)(p - string) - 2;
+ *erroroffset = (PCRE2_SIZE)(p - string) - 2;
return PCRE2_ERROR_UTF8_ERR7;
}
if ((*(++p) & 0xc0) != 0x80) /* Fourth byte */
{
- *erroroffset = (int)(p - string) - 3;
+ *erroroffset = (PCRE2_SIZE)(p - string) - 3;
return PCRE2_ERROR_UTF8_ERR8;
}
if ((*(++p) & 0xc0) != 0x80) /* Fifth byte */
{
- *erroroffset = (int)(p - string) - 4;
+ *erroroffset = (PCRE2_SIZE)(p - string) - 4;
return PCRE2_ERROR_UTF8_ERR9;
}
if ((*(++p) & 0xc0) != 0x80) /* Sixth byte */
{
- *erroroffset = (int)(p - string) - 5;
+ *erroroffset = (PCRE2_SIZE)(p - string) - 5;
return PCRE2_ERROR_UTF8_ERR10;
}
if (c == 0xfc && (d & 0x3c) == 0)
{
- *erroroffset = (int)(p - string) - 5;
+ *erroroffset = (PCRE2_SIZE)(p - string) - 5;
return PCRE2_ERROR_UTF8_ERR19;
}
break;
@@ -309,7 +309,7 @@ for (p = string; length > 0; p++)
if (ab > 3)
{
- *erroroffset = (int)(p - string) - ab;
+ *erroroffset = (PCRE2_SIZE)(p - string) - ab;
return (ab == 4)? PCRE2_ERROR_UTF8_ERR11 : PCRE2_ERROR_UTF8_ERR12;
}
}
@@ -340,21 +340,21 @@ for (p = string; length > 0; p++)
/* High surrogate. Must be a followed by a low surrogate. */
if (length == 0)
{
- *erroroffset = p - string;
+ *erroroffset = (PCRE2_SIZE)(p - string);
return PCRE2_ERROR_UTF16_ERR1;
}
p++;
length--;
if ((*p & 0xfc00) != 0xdc00)
{
- *erroroffset = p - string - 1;
+ *erroroffset = (PCRE2_SIZE)(p - string) - 1;
return PCRE2_ERROR_UTF16_ERR2;
}
}
else
{
/* Isolated low surrogate. Always an error. */
- *erroroffset = p - string;
+ *erroroffset = (PCRE2_SIZE)(p - string);
return PCRE2_ERROR_UTF16_ERR3;
}
}
@@ -379,14 +379,14 @@ for (p = string; length > 0; length--, p++)
/* Normal UTF-32 code point. Neither high nor low surrogate. */
if (c > 0x10ffffu)
{
- *erroroffset = p - string;
+ *erroroffset = (PCRE2_SIZE)(p - string);
return PCRE2_ERROR_UTF32_ERR2;
}
}
else
{
/* A surrogate */
- *erroroffset = p - string;
+ *erroroffset = (PCRE2_SIZE)(p - string);
return PCRE2_ERROR_UTF32_ERR1;
}
}
diff --git a/src/3rdparty/pcre2/src/pcre2_xclass.c b/src/3rdparty/pcre2/src/pcre2_xclass.c
index bb57196449..5df25d2c8d 100644
--- a/src/3rdparty/pcre2/src/pcre2_xclass.c
+++ b/src/3rdparty/pcre2/src/pcre2_xclass.c
@@ -7,7 +7,7 @@ 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-2022 University of Cambridge
+ New API code Copyright (c) 2016-2023 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -133,6 +133,7 @@ while ((t = *data++) != XCL_END)
#ifdef SUPPORT_UNICODE
else /* XCL_PROP & XCL_NOTPROP */
{
+ int chartype;
const ucd_record *prop = GET_UCD(c);
BOOL isprop = t == XCL_PROP;
BOOL ok;
@@ -144,8 +145,9 @@ while ((t = *data++) != XCL_END)
break;
case PT_LAMP:
- if ((prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
- prop->chartype == ucp_Lt) == isprop) return !negated;
+ chartype = prop->chartype;
+ if ((chartype == ucp_Lu || chartype == ucp_Ll ||
+ chartype == ucp_Lt) == isprop) return !negated;
break;
case PT_GC:
@@ -168,8 +170,9 @@ while ((t = *data++) != XCL_END)
break;
case PT_ALNUM:
- if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
- PRIV(ucp_gentype)[prop->chartype] == ucp_N) == isprop)
+ chartype = prop->chartype;
+ if ((PRIV(ucp_gentype)[chartype] == ucp_L ||
+ PRIV(ucp_gentype)[chartype] == ucp_N) == isprop)
return !negated;
break;
@@ -194,9 +197,10 @@ while ((t = *data++) != XCL_END)
break;
case PT_WORD:
- if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
- PRIV(ucp_gentype)[prop->chartype] == ucp_N || c == CHAR_UNDERSCORE)
- == isprop)
+ chartype = prop->chartype;
+ if ((PRIV(ucp_gentype)[chartype] == ucp_L ||
+ PRIV(ucp_gentype)[chartype] == ucp_N ||
+ chartype == ucp_Mn || chartype == ucp_Pc) == isprop)
return !negated;
break;
@@ -238,9 +242,10 @@ while ((t = *data++) != XCL_END)
*/
case PT_PXGRAPH:
- if ((PRIV(ucp_gentype)[prop->chartype] != ucp_Z &&
- (PRIV(ucp_gentype)[prop->chartype] != ucp_C ||
- (prop->chartype == ucp_Cf &&
+ chartype = prop->chartype;
+ if ((PRIV(ucp_gentype)[chartype] != ucp_Z &&
+ (PRIV(ucp_gentype)[chartype] != ucp_C ||
+ (chartype == ucp_Cf &&
c != 0x061c && c != 0x180e && (c < 0x2066 || c > 0x2069))
)) == isprop)
return !negated;
@@ -250,10 +255,11 @@ while ((t = *data++) != XCL_END)
not Zl and not Zp, and U+180E. */
case PT_PXPRINT:
- if ((prop->chartype != ucp_Zl &&
- prop->chartype != ucp_Zp &&
- (PRIV(ucp_gentype)[prop->chartype] != ucp_C ||
- (prop->chartype == ucp_Cf &&
+ chartype = prop->chartype;
+ if ((chartype != ucp_Zl &&
+ chartype != ucp_Zp &&
+ (PRIV(ucp_gentype)[chartype] != ucp_C ||
+ (chartype == ucp_Cf &&
c != 0x061c && (c < 0x2066 || c > 0x2069))
)) == isprop)
return !negated;
@@ -264,8 +270,21 @@ while ((t = *data++) != XCL_END)
compatibility (these are $+<=>^`|~). */
case PT_PXPUNCT:
- if ((PRIV(ucp_gentype)[prop->chartype] == ucp_P ||
- (c < 128 && PRIV(ucp_gentype)[prop->chartype] == ucp_S)) == isprop)
+ chartype = prop->chartype;
+ if ((PRIV(ucp_gentype)[chartype] == ucp_P ||
+ (c < 128 && PRIV(ucp_gentype)[chartype] == ucp_S)) == isprop)
+ return !negated;
+ break;
+
+ /* Perl has two sets of hex digits */
+
+ case PT_PXXDIGIT:
+ if (((c >= CHAR_0 && c <= CHAR_9) ||
+ (c >= CHAR_A && c <= CHAR_F) ||
+ (c >= CHAR_a && c <= CHAR_f) ||
+ (c >= 0xff10 && c <= 0xff19) || /* Fullwidth digits */
+ (c >= 0xff21 && c <= 0xff26) || /* Fullwidth letters */
+ (c >= 0xff41 && c <= 0xff46)) == isprop)
return !negated;
break;
diff --git a/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorApple.c b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorApple.c
new file mode 100644
index 0000000000..95b9842fa9
--- /dev/null
+++ b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorApple.c
@@ -0,0 +1,133 @@
+/*
+ * Stack-less Just-In-Time compiler
+ *
+ * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+/*
+ On macOS systems, returns MAP_JIT if it is defined _and_ we're running on a
+ version where it's OK to have more than one JIT block or where MAP_JIT is
+ required.
+ On non-macOS systems, returns MAP_JIT if it is defined.
+*/
+#include <TargetConditionals.h>
+
+#if (defined(TARGET_OS_OSX) && TARGET_OS_OSX) || (TARGET_OS_MAC && !TARGET_OS_IPHONE)
+
+#if defined(SLJIT_CONFIG_X86) && SLJIT_CONFIG_X86
+
+#include <sys/utsname.h>
+#include <stdlib.h>
+
+#define SLJIT_MAP_JIT (get_map_jit_flag())
+#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec)
+
+static SLJIT_INLINE int get_map_jit_flag(void)
+{
+ size_t page_size;
+ void *ptr;
+ struct utsname name;
+ static int map_jit_flag = -1;
+
+ if (map_jit_flag < 0) {
+ map_jit_flag = 0;
+ uname(&name);
+
+ /* Kernel version for 10.14.0 (Mojave) or later */
+ if (atoi(name.release) >= 18) {
+ page_size = get_page_alignment() + 1;
+ /* Only use MAP_JIT if a hardened runtime is used */
+ ptr = mmap(NULL, page_size, PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+
+ if (ptr != MAP_FAILED)
+ munmap(ptr, page_size);
+ else
+ map_jit_flag = MAP_JIT;
+ }
+ }
+ return map_jit_flag;
+}
+
+#elif defined(SLJIT_CONFIG_ARM) && SLJIT_CONFIG_ARM
+
+#include <AvailabilityMacros.h>
+#include <pthread.h>
+
+#define SLJIT_MAP_JIT (MAP_JIT)
+#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) \
+ apple_update_wx_flags(enable_exec)
+
+static SLJIT_INLINE void apple_update_wx_flags(sljit_s32 enable_exec)
+{
+#if MAC_OS_X_VERSION_MIN_REQUIRED < 110000
+ if (__builtin_available(macos 11, *))
+#endif /* BigSur */
+ pthread_jit_write_protect_np(enable_exec);
+}
+
+#elif defined(SLJIT_CONFIG_PPC) && SLJIT_CONFIG_PPC
+
+#define SLJIT_MAP_JIT (0)
+#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec)
+
+#else
+#error "Unsupported architecture"
+#endif /* SLJIT_CONFIG */
+
+#else /* !TARGET_OS_OSX */
+
+#ifdef MAP_JIT
+#define SLJIT_MAP_JIT (MAP_JIT)
+#else
+#define SLJIT_MAP_JIT (0)
+#endif
+
+#endif /* TARGET_OS_OSX */
+
+static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
+{
+ void *retval;
+ int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+ int flags = MAP_PRIVATE;
+ int fd = -1;
+
+ flags |= MAP_ANON | SLJIT_MAP_JIT;
+
+ retval = mmap(NULL, size, prot, flags, fd, 0);
+ if (retval == MAP_FAILED)
+ return NULL;
+
+ SLJIT_UPDATE_WX_FLAGS(retval, (uint8_t *)retval + size, 0);
+
+ return retval;
+}
+
+static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
+{
+ munmap(chunk, size);
+}
+
+#include "sljitExecAllocatorCore.c"
diff --git a/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorCore.c b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorCore.c
new file mode 100644
index 0000000000..6cd391104c
--- /dev/null
+++ b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorCore.c
@@ -0,0 +1,330 @@
+/*
+ * Stack-less Just-In-Time compiler
+ *
+ * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) 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 simple executable memory allocator
+
+ It is assumed, that executable code blocks are usually medium (or sometimes
+ large) memory blocks, and the allocator is not too frequently called (less
+ optimized than other allocators). Thus, using it as a generic allocator is
+ not suggested.
+
+ How does it work:
+ Memory is allocated in continuous memory areas called chunks by alloc_chunk()
+ Chunk format:
+ [ block ][ block ] ... [ block ][ block terminator ]
+
+ All blocks and the block terminator is started with block_header. The block
+ header contains the size of the previous and the next block. These sizes
+ can also contain special values.
+ Block size:
+ 0 - The block is a free_block, with a different size member.
+ 1 - The block is a block terminator.
+ n - The block is used at the moment, and the value contains its size.
+ Previous block size:
+ 0 - This is the first block of the memory chunk.
+ n - The size of the previous block.
+
+ Using these size values we can go forward or backward on the block chain.
+ The unused blocks are stored in a chain list pointed by free_blocks. This
+ list is useful if we need to find a suitable memory area when the allocator
+ is called.
+
+ When a block is freed, the new free block is connected to its adjacent free
+ blocks if possible.
+
+ [ free block ][ used block ][ free block ]
+ and "used block" is freed, the three blocks are connected together:
+ [ one big free block ]
+*/
+
+/* Expected functions:
+ alloc_chunk / free_chunk :
+ * allocate executable system memory chunks
+ * the size is always divisible by CHUNK_SIZE
+ SLJIT_ALLOCATOR_LOCK / SLJIT_ALLOCATOR_UNLOCK :
+ * provided as part of sljitUtils
+ * only the allocator requires this lock, sljit is fully thread safe
+ as it only uses local variables
+
+ Supported defines:
+ SLJIT_HAS_CHUNK_HEADER - (optional) sljit_chunk_header is defined
+ SLJIT_HAS_EXECUTABLE_OFFSET - (optional) has executable offset data
+ SLJIT_UPDATE_WX_FLAGS - (optional) update WX flags
+*/
+
+#ifdef SLJIT_HAS_CHUNK_HEADER
+#define CHUNK_HEADER_SIZE (sizeof(struct sljit_chunk_header))
+#else /* !SLJIT_HAS_CHUNK_HEADER */
+#define CHUNK_HEADER_SIZE 0
+#endif /* SLJIT_HAS_CHUNK_HEADER */
+
+#ifndef SLJIT_UPDATE_WX_FLAGS
+#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec)
+#endif /* SLJIT_UPDATE_WX_FLAGS */
+
+#ifndef CHUNK_SIZE
+/* 64 KByte if not specified. */
+#define CHUNK_SIZE (sljit_uw)0x10000
+#endif /* CHUNK_SIZE */
+
+struct block_header {
+ sljit_uw size;
+ sljit_uw prev_size;
+#ifdef SLJIT_HAS_EXECUTABLE_OFFSET
+ sljit_sw executable_offset;
+#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
+};
+
+struct free_block {
+ struct block_header header;
+ struct free_block *next;
+ struct free_block *prev;
+ sljit_uw size;
+};
+
+#define AS_BLOCK_HEADER(base, offset) \
+ ((struct block_header*)(((sljit_u8*)base) + offset))
+#define AS_FREE_BLOCK(base, offset) \
+ ((struct free_block*)(((sljit_u8*)base) + offset))
+#define MEM_START(base) ((void*)((base) + 1))
+#define CHUNK_MASK (~(CHUNK_SIZE - 1))
+#define ALIGN_SIZE(size) (((size) + sizeof(struct block_header) + 7u) & ~(sljit_uw)7)
+#define CHUNK_EXTRA_SIZE (sizeof(struct block_header) + CHUNK_HEADER_SIZE)
+
+static struct free_block* free_blocks;
+static sljit_uw allocated_size;
+static sljit_uw total_size;
+
+static SLJIT_INLINE void sljit_insert_free_block(struct free_block *free_block, sljit_uw size)
+{
+ free_block->header.size = 0;
+ free_block->size = size;
+
+ free_block->next = free_blocks;
+ free_block->prev = NULL;
+ if (free_blocks)
+ free_blocks->prev = free_block;
+ free_blocks = free_block;
+}
+
+static SLJIT_INLINE void sljit_remove_free_block(struct free_block *free_block)
+{
+ if (free_block->next)
+ free_block->next->prev = free_block->prev;
+
+ if (free_block->prev)
+ free_block->prev->next = free_block->next;
+ else {
+ SLJIT_ASSERT(free_blocks == free_block);
+ free_blocks = free_block->next;
+ }
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
+{
+ struct block_header *header;
+ struct block_header *next_header;
+ struct free_block *free_block;
+ sljit_uw chunk_size;
+
+#ifdef SLJIT_HAS_CHUNK_HEADER
+ struct sljit_chunk_header *chunk_header;
+#else /* !SLJIT_HAS_CHUNK_HEADER */
+ void *chunk_header;
+#endif /* SLJIT_HAS_CHUNK_HEADER */
+
+#ifdef SLJIT_HAS_EXECUTABLE_OFFSET
+ sljit_sw executable_offset;
+#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
+
+ if (size < (64 - sizeof(struct block_header)))
+ size = (64 - sizeof(struct block_header));
+ size = ALIGN_SIZE(size);
+
+ SLJIT_ALLOCATOR_LOCK();
+ free_block = free_blocks;
+ while (free_block) {
+ if (free_block->size >= size) {
+ chunk_size = free_block->size;
+ SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0);
+ if (chunk_size > size + 64) {
+ /* We just cut a block from the end of the free block. */
+ chunk_size -= size;
+ free_block->size = chunk_size;
+ header = AS_BLOCK_HEADER(free_block, chunk_size);
+ header->prev_size = chunk_size;
+#ifdef SLJIT_HAS_EXECUTABLE_OFFSET
+ header->executable_offset = free_block->header.executable_offset;
+#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
+ AS_BLOCK_HEADER(header, size)->prev_size = size;
+ }
+ else {
+ sljit_remove_free_block(free_block);
+ header = (struct block_header*)free_block;
+ size = chunk_size;
+ }
+ allocated_size += size;
+ header->size = size;
+ SLJIT_ALLOCATOR_UNLOCK();
+ return MEM_START(header);
+ }
+ free_block = free_block->next;
+ }
+
+ chunk_size = (size + CHUNK_EXTRA_SIZE + CHUNK_SIZE - 1) & CHUNK_MASK;
+
+ chunk_header = alloc_chunk(chunk_size);
+ if (!chunk_header) {
+ SLJIT_ALLOCATOR_UNLOCK();
+ return NULL;
+ }
+
+#ifdef SLJIT_HAS_EXECUTABLE_OFFSET
+ executable_offset = (sljit_sw)((sljit_u8*)chunk_header->executable - (sljit_u8*)chunk_header);
+#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
+
+ chunk_size -= CHUNK_EXTRA_SIZE;
+ total_size += chunk_size;
+
+ header = (struct block_header*)(((sljit_u8*)chunk_header) + CHUNK_HEADER_SIZE);
+
+ header->prev_size = 0;
+#ifdef SLJIT_HAS_EXECUTABLE_OFFSET
+ header->executable_offset = executable_offset;
+#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
+
+ if (chunk_size > size + 64) {
+ /* Cut the allocated space into a free and a used block. */
+ allocated_size += size;
+ header->size = size;
+ chunk_size -= size;
+
+ free_block = AS_FREE_BLOCK(header, size);
+ free_block->header.prev_size = size;
+#ifdef SLJIT_HAS_EXECUTABLE_OFFSET
+ free_block->header.executable_offset = executable_offset;
+#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
+ sljit_insert_free_block(free_block, chunk_size);
+ next_header = AS_BLOCK_HEADER(free_block, chunk_size);
+ }
+ else {
+ /* All space belongs to this allocation. */
+ allocated_size += chunk_size;
+ header->size = chunk_size;
+ next_header = AS_BLOCK_HEADER(header, chunk_size);
+ }
+ SLJIT_ALLOCATOR_UNLOCK();
+ next_header->size = 1;
+ next_header->prev_size = chunk_size;
+#ifdef SLJIT_HAS_EXECUTABLE_OFFSET
+ next_header->executable_offset = executable_offset;
+#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
+ return MEM_START(header);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
+{
+ struct block_header *header;
+ struct free_block* free_block;
+
+ SLJIT_ALLOCATOR_LOCK();
+ header = AS_BLOCK_HEADER(ptr, -(sljit_sw)sizeof(struct block_header));
+#ifdef SLJIT_HAS_EXECUTABLE_OFFSET
+ header = AS_BLOCK_HEADER(header, -header->executable_offset);
+#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
+ allocated_size -= header->size;
+
+ SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0);
+
+ /* Connecting free blocks together if possible. */
+
+ /* If header->prev_size == 0, free_block will equal to header.
+ In this case, free_block->header.size will be > 0. */
+ free_block = AS_FREE_BLOCK(header, -(sljit_sw)header->prev_size);
+ if (SLJIT_UNLIKELY(!free_block->header.size)) {
+ free_block->size += header->size;
+ header = AS_BLOCK_HEADER(free_block, free_block->size);
+ header->prev_size = free_block->size;
+ }
+ else {
+ free_block = (struct free_block*)header;
+ sljit_insert_free_block(free_block, header->size);
+ }
+
+ header = AS_BLOCK_HEADER(free_block, free_block->size);
+ if (SLJIT_UNLIKELY(!header->size)) {
+ free_block->size += ((struct free_block*)header)->size;
+ sljit_remove_free_block((struct free_block*)header);
+ header = AS_BLOCK_HEADER(free_block, free_block->size);
+ header->prev_size = free_block->size;
+ }
+
+ /* The whole chunk is free. */
+ if (SLJIT_UNLIKELY(!free_block->header.prev_size && header->size == 1)) {
+ /* If this block is freed, we still have (allocated_size / 2) free space. */
+ if (total_size - free_block->size > (allocated_size * 3 / 2)) {
+ total_size -= free_block->size;
+ sljit_remove_free_block(free_block);
+ free_chunk(free_block, free_block->size + CHUNK_EXTRA_SIZE);
+ }
+ }
+
+ SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 1);
+ SLJIT_ALLOCATOR_UNLOCK();
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
+{
+ struct free_block* free_block;
+ struct free_block* next_free_block;
+
+ SLJIT_ALLOCATOR_LOCK();
+ SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 0);
+
+ free_block = free_blocks;
+ while (free_block) {
+ next_free_block = free_block->next;
+ if (!free_block->header.prev_size &&
+ AS_BLOCK_HEADER(free_block, free_block->size)->size == 1) {
+ total_size -= free_block->size;
+ sljit_remove_free_block(free_block);
+ free_chunk(free_block, free_block->size + CHUNK_EXTRA_SIZE);
+ }
+ free_block = next_free_block;
+ }
+
+ SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks));
+ SLJIT_UPDATE_WX_FLAGS(NULL, NULL, 1);
+ SLJIT_ALLOCATOR_UNLOCK();
+}
+
+#ifdef SLJIT_HAS_EXECUTABLE_OFFSET
+SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr)
+{
+ return ((struct block_header *)(ptr))[-1].executable_offset;
+}
+#endif /* SLJIT_HAS_EXECUTABLE_OFFSET */
diff --git a/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorFreeBSD.c b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorFreeBSD.c
new file mode 100644
index 0000000000..3b93a4df76
--- /dev/null
+++ b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorFreeBSD.c
@@ -0,0 +1,89 @@
+/*
+ * Stack-less Just-In-Time compiler
+ *
+ * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/mman.h>
+#include <sys/procctl.h>
+
+#ifdef PROC_WXMAP_CTL
+static SLJIT_INLINE int sljit_is_wx_block(void)
+{
+ static int wx_block = -1;
+ if (wx_block < 0) {
+ int sljit_wx_enable = PROC_WX_MAPPINGS_PERMIT;
+ wx_block = !!procctl(P_PID, 0, PROC_WXMAP_CTL, &sljit_wx_enable);
+ }
+ return wx_block;
+}
+
+#define SLJIT_IS_WX_BLOCK sljit_is_wx_block()
+#else /* !PROC_WXMAP_CTL */
+#define SLJIT_IS_WX_BLOCK (1)
+#endif /* PROC_WXMAP_CTL */
+
+static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
+{
+ void *retval;
+ int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+ int flags = MAP_PRIVATE;
+ int fd = -1;
+
+#ifdef PROT_MAX
+ prot |= PROT_MAX(prot);
+#endif
+
+#ifdef MAP_ANON
+ flags |= MAP_ANON;
+#else /* !MAP_ANON */
+ if (SLJIT_UNLIKELY((dev_zero < 0) && open_dev_zero()))
+ return NULL;
+
+ fd = dev_zero;
+#endif /* MAP_ANON */
+
+retry:
+ retval = mmap(NULL, size, prot, flags, fd, 0);
+ if (retval == MAP_FAILED) {
+ if (!SLJIT_IS_WX_BLOCK)
+ goto retry;
+
+ return NULL;
+ }
+
+ /* HardenedBSD's mmap lies, so check permissions again. */
+ if (mprotect(retval, size, PROT_READ | PROT_WRITE | PROT_EXEC) < 0) {
+ munmap(retval, size);
+ return NULL;
+ }
+
+ return retval;
+}
+
+static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
+{
+ munmap(chunk, size);
+}
+
+#include "sljitExecAllocatorCore.c"
diff --git a/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorPosix.c b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorPosix.c
new file mode 100644
index 0000000000..a775f5629a
--- /dev/null
+++ b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorPosix.c
@@ -0,0 +1,62 @@
+/*
+ * Stack-less Just-In-Time compiler
+ *
+ * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
+{
+ void *retval;
+ int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+ int flags = MAP_PRIVATE;
+ int fd = -1;
+
+#ifdef PROT_MAX
+ prot |= PROT_MAX(prot);
+#endif
+
+#ifdef MAP_ANON
+ flags |= MAP_ANON;
+#else /* !MAP_ANON */
+ if (SLJIT_UNLIKELY((dev_zero < 0) && open_dev_zero()))
+ return NULL;
+
+ fd = dev_zero;
+#endif /* MAP_ANON */
+
+ retval = mmap(NULL, size, prot, flags, fd, 0);
+ if (retval == MAP_FAILED)
+ return NULL;
+
+ return retval;
+}
+
+static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
+{
+ munmap(chunk, size);
+}
+
+#include "sljitExecAllocatorCore.c"
diff --git a/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorWindows.c b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorWindows.c
new file mode 100644
index 0000000000..f152a5a2cd
--- /dev/null
+++ b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitExecAllocatorWindows.c
@@ -0,0 +1,40 @@
+/*
+ * Stack-less Just-In-Time compiler
+ *
+ * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) 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.
+ */
+
+#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec)
+
+static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
+{
+ return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+}
+
+static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
+{
+ SLJIT_UNUSED_ARG(size);
+ VirtualFree(chunk, 0, MEM_RELEASE);
+}
+
+#include "sljitExecAllocatorCore.c"
diff --git a/src/3rdparty/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorNetBSD.c b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorNetBSD.c
new file mode 100644
index 0000000000..0b7fd57787
--- /dev/null
+++ b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorNetBSD.c
@@ -0,0 +1,72 @@
+/*
+ * Stack-less Just-In-Time compiler
+ *
+ * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) 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.
+ */
+
+#define SLJIT_HAS_CHUNK_HEADER
+#define SLJIT_HAS_EXECUTABLE_OFFSET
+
+struct sljit_chunk_header {
+ void *executable;
+};
+
+/*
+ * MAP_REMAPDUP is a NetBSD extension available sinde 8.0, make sure to
+ * adjust your feature macros (ex: -D_NETBSD_SOURCE) as needed
+ */
+static SLJIT_INLINE struct sljit_chunk_header* alloc_chunk(sljit_uw size)
+{
+ struct sljit_chunk_header *retval;
+
+ retval = (struct sljit_chunk_header *)mmap(NULL, size,
+ PROT_READ | PROT_WRITE | PROT_MPROTECT(PROT_EXEC),
+ MAP_ANON | MAP_SHARED, -1, 0);
+
+ if (retval == MAP_FAILED)
+ return NULL;
+
+ retval->executable = mremap(retval, size, NULL, size, MAP_REMAPDUP);
+ if (retval->executable == MAP_FAILED) {
+ munmap((void *)retval, size);
+ return NULL;
+ }
+
+ if (mprotect(retval->executable, size, PROT_READ | PROT_EXEC) == -1) {
+ munmap(retval->executable, size);
+ munmap((void *)retval, size);
+ return NULL;
+ }
+
+ return retval;
+}
+
+static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
+{
+ struct sljit_chunk_header *header = ((struct sljit_chunk_header *)chunk) - 1;
+
+ munmap(header->executable, size);
+ munmap((void *)header, size);
+}
+
+#include "sljitExecAllocatorCore.c"
diff --git a/src/3rdparty/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorPosix.c b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorPosix.c
new file mode 100644
index 0000000000..f7cb6c5670
--- /dev/null
+++ b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitProtExecAllocatorPosix.c
@@ -0,0 +1,172 @@
+/*
+ * Stack-less Just-In-Time compiler
+ *
+ * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) 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.
+ */
+
+#define SLJIT_HAS_CHUNK_HEADER
+#define SLJIT_HAS_EXECUTABLE_OFFSET
+
+struct sljit_chunk_header {
+ void *executable;
+};
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifndef O_NOATIME
+#define O_NOATIME 0
+#endif
+
+/* this is a linux extension available since kernel 3.11 */
+#ifndef O_TMPFILE
+#define O_TMPFILE 0x404000
+#endif
+
+#ifndef _GNU_SOURCE
+char *secure_getenv(const char *name);
+int mkostemp(char *template, int flags);
+#endif
+
+static SLJIT_INLINE int create_tempfile(void)
+{
+ int fd;
+ char tmp_name[256];
+ size_t tmp_name_len = 0;
+ char *dir;
+ struct stat st;
+#if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED
+ mode_t mode;
+#endif
+
+#ifdef HAVE_MEMFD_CREATE
+ /* this is a GNU extension, make sure to use -D_GNU_SOURCE */
+ fd = memfd_create("sljit", MFD_CLOEXEC);
+ if (fd != -1) {
+ fchmod(fd, 0);
+ return fd;
+ }
+#endif
+
+ dir = secure_getenv("TMPDIR");
+
+ if (dir) {
+ size_t len = strlen(dir);
+ if (len > 0 && len < sizeof(tmp_name)) {
+ if ((stat(dir, &st) == 0) && S_ISDIR(st.st_mode)) {
+ memcpy(tmp_name, dir, len + 1);
+ tmp_name_len = len;
+ }
+ }
+ }
+
+#ifdef P_tmpdir
+ if (!tmp_name_len) {
+ tmp_name_len = strlen(P_tmpdir);
+ if (tmp_name_len > 0 && tmp_name_len < sizeof(tmp_name))
+ strcpy(tmp_name, P_tmpdir);
+ }
+#endif
+ if (!tmp_name_len) {
+ strcpy(tmp_name, "/tmp");
+ tmp_name_len = 4;
+ }
+
+ SLJIT_ASSERT(tmp_name_len > 0 && tmp_name_len < sizeof(tmp_name));
+
+ if (tmp_name_len > 1 && tmp_name[tmp_name_len - 1] == '/')
+ tmp_name[--tmp_name_len] = '\0';
+
+ fd = open(tmp_name, O_TMPFILE | O_EXCL | O_RDWR | O_NOATIME | O_CLOEXEC, 0);
+ if (fd != -1)
+ return fd;
+
+ if (tmp_name_len >= sizeof(tmp_name) - 7)
+ return -1;
+
+ strcpy(tmp_name + tmp_name_len, "/XXXXXX");
+#if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED
+ mode = umask(0777);
+#endif
+ fd = mkostemp(tmp_name, O_CLOEXEC | O_NOATIME);
+#if defined(SLJIT_SINGLE_THREADED) && SLJIT_SINGLE_THREADED
+ umask(mode);
+#else
+ fchmod(fd, 0);
+#endif
+
+ if (fd == -1)
+ return -1;
+
+ if (unlink(tmp_name)) {
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+static SLJIT_INLINE struct sljit_chunk_header* alloc_chunk(sljit_uw size)
+{
+ struct sljit_chunk_header *retval;
+ int fd;
+
+ fd = create_tempfile();
+ if (fd == -1)
+ return NULL;
+
+ if (ftruncate(fd, (off_t)size)) {
+ close(fd);
+ return NULL;
+ }
+
+ retval = (struct sljit_chunk_header *)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+ if (retval == MAP_FAILED) {
+ close(fd);
+ return NULL;
+ }
+
+ retval->executable = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_SHARED, fd, 0);
+
+ if (retval->executable == MAP_FAILED) {
+ munmap((void *)retval, size);
+ close(fd);
+ return NULL;
+ }
+
+ close(fd);
+ return retval;
+}
+
+static SLJIT_INLINE void free_chunk(void *chunk, sljit_uw size)
+{
+ struct sljit_chunk_header *header = ((struct sljit_chunk_header *)chunk) - 1;
+
+ munmap(header->executable, size);
+ munmap((void *)header, size);
+}
+
+#include "sljitExecAllocatorCore.c"
diff --git a/src/3rdparty/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorPosix.c b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorPosix.c
new file mode 100644
index 0000000000..36d301434a
--- /dev/null
+++ b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorPosix.c
@@ -0,0 +1,141 @@
+/*
+ * Stack-less Just-In-Time compiler
+ *
+ * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) 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 simple W^X executable memory allocator
+
+ In *NIX, MAP_ANON is required (that is considered a feature) so make
+ sure to set the right availability macros for your system or the code
+ will fail to build.
+
+ If your system doesn't support mapping of anonymous pages (ex: IRIX) it
+ is also likely that it doesn't need this allocator and should be using
+ the standard one instead.
+
+ It allocates a separate map for each code block and may waste a lot of
+ memory, because whatever was requested, will be rounded up to the page
+ size (minimum 4KB, but could be even bigger).
+
+ It changes the page permissions (RW <-> RX) as needed and therefore, if you
+ will be updating the code after it has been generated, need to make sure to
+ block any concurrent execution, or could result in a SIGBUS, that could
+ even manifest itself at a different address than the one that was being
+ modified.
+
+ Only use if you are unable to use the regular allocator because of security
+ restrictions and adding exceptions to your application or the system are
+ not possible.
+*/
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) \
+ sljit_update_wx_flags((from), (to), (enable_exec))
+
+#if !(defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
+#include <pthread.h>
+#define SLJIT_SE_LOCK() pthread_mutex_lock(&se_lock)
+#define SLJIT_SE_UNLOCK() pthread_mutex_unlock(&se_lock)
+#else
+#define SLJIT_SE_LOCK()
+#define SLJIT_SE_UNLOCK()
+#endif /* !SLJIT_SINGLE_THREADED */
+
+#define SLJIT_WX_IS_BLOCK(ptr, size) generic_check_is_wx_block(ptr, size)
+
+static SLJIT_INLINE int generic_check_is_wx_block(void *ptr, sljit_uw size)
+{
+ if (SLJIT_LIKELY(!mprotect(ptr, size, PROT_EXEC)))
+ return !!mprotect(ptr, size, PROT_READ | PROT_WRITE);
+
+ return 1;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
+{
+#if !(defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
+ static pthread_mutex_t se_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif
+ static int wx_block = -1;
+ int prot = PROT_READ | PROT_WRITE;
+ sljit_uw* ptr;
+
+ if (SLJIT_UNLIKELY(wx_block > 0))
+ return NULL;
+
+#ifdef PROT_MAX
+ prot |= PROT_MAX(PROT_READ | PROT_WRITE | PROT_EXEC);
+#endif
+
+ size += sizeof(sljit_uw);
+ ptr = (sljit_uw*)mmap(NULL, size, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
+
+ if (ptr == MAP_FAILED)
+ return NULL;
+
+ if (SLJIT_UNLIKELY(wx_block < 0)) {
+ SLJIT_SE_LOCK();
+ wx_block = SLJIT_WX_IS_BLOCK(ptr, size);
+ SLJIT_SE_UNLOCK();
+ if (SLJIT_UNLIKELY(wx_block)) {
+ munmap((void *)ptr, size);
+ return NULL;
+ }
+ }
+
+ *ptr++ = size;
+ return ptr;
+}
+
+#undef SLJIT_SE_UNLOCK
+#undef SLJIT_SE_LOCK
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
+{
+ sljit_uw *start_ptr = ((sljit_uw*)ptr) - 1;
+ munmap((void*)start_ptr, *start_ptr);
+}
+
+static void sljit_update_wx_flags(void *from, void *to, int enable_exec)
+{
+ sljit_uw page_mask = (sljit_uw)get_page_alignment();
+ sljit_uw start = (sljit_uw)from;
+ sljit_uw end = (sljit_uw)to;
+ int prot = PROT_READ | (enable_exec ? PROT_EXEC : PROT_WRITE);
+
+ SLJIT_ASSERT(start < end);
+
+ start &= ~page_mask;
+ end = (end + page_mask) & ~page_mask;
+
+ mprotect((void*)start, end - start, prot);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
+{
+ /* This allocator does not keep unused memory for future allocations. */
+}
diff --git a/src/3rdparty/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorWindows.c b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorWindows.c
new file mode 100644
index 0000000000..a9553bd7da
--- /dev/null
+++ b/src/3rdparty/pcre2/src/sljit/allocator_src/sljitWXExecAllocatorWindows.c
@@ -0,0 +1,102 @@
+/*
+ * Stack-less Just-In-Time compiler
+ *
+ * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) 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 simple W^X executable memory allocator
+
+ In *NIX, MAP_ANON is required (that is considered a feature) so make
+ sure to set the right availability macros for your system or the code
+ will fail to build.
+
+ If your system doesn't support mapping of anonymous pages (ex: IRIX) it
+ is also likely that it doesn't need this allocator and should be using
+ the standard one instead.
+
+ It allocates a separate map for each code block and may waste a lot of
+ memory, because whatever was requested, will be rounded up to the page
+ size (minimum 4KB, but could be even bigger).
+
+ It changes the page permissions (RW <-> RX) as needed and therefore, if you
+ will be updating the code after it has been generated, need to make sure to
+ block any concurrent execution, or could result in a SIGBUS, that could
+ even manifest itself at a different address than the one that was being
+ modified.
+
+ Only use if you are unable to use the regular allocator because of security
+ restrictions and adding exceptions to your application or the system are
+ not possible.
+*/
+
+#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec) \
+ sljit_update_wx_flags((from), (to), (enable_exec))
+
+SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
+{
+ sljit_uw *ptr;
+
+ size += sizeof(sljit_uw);
+ ptr = (sljit_uw*)VirtualAlloc(NULL, size,
+ MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+
+ if (!ptr)
+ return NULL;
+
+ *ptr++ = size;
+
+ return ptr;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
+{
+ sljit_uw start = (sljit_uw)ptr - sizeof(sljit_uw);
+#if defined(SLJIT_DEBUG) && SLJIT_DEBUG
+ sljit_uw page_mask = (sljit_uw)get_page_alignment();
+
+ SLJIT_ASSERT(!(start & page_mask));
+#endif
+ VirtualFree((void*)start, 0, MEM_RELEASE);
+}
+
+static void sljit_update_wx_flags(void *from, void *to, sljit_s32 enable_exec)
+{
+ DWORD oldprot;
+ sljit_uw page_mask = (sljit_uw)get_page_alignment();
+ sljit_uw start = (sljit_uw)from;
+ sljit_uw end = (sljit_uw)to;
+ DWORD prot = enable_exec ? PAGE_EXECUTE : PAGE_READWRITE;
+
+ SLJIT_ASSERT(start < end);
+
+ start &= ~page_mask;
+ end = (end + page_mask) & ~page_mask;
+
+ VirtualProtect((void*)start, end - start, prot, &oldprot);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
+{
+ /* This allocator does not keep unused memory for future allocations. */
+}
diff --git a/src/3rdparty/pcre2/src/sljit/sljitConfig.h b/src/3rdparty/pcre2/src/sljit/sljitConfig.h
index 5fba7aa638..364c8bb788 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitConfig.h
+++ b/src/3rdparty/pcre2/src/sljit/sljitConfig.h
@@ -39,28 +39,6 @@ extern "C" {
*/
/* --------------------------------------------------------------------- */
-/* Architecture */
-/* --------------------------------------------------------------------- */
-
-/* Architecture selection. */
-/* #define SLJIT_CONFIG_X86_32 1 */
-/* #define SLJIT_CONFIG_X86_64 1 */
-/* #define SLJIT_CONFIG_ARM_V5 1 */
-/* #define SLJIT_CONFIG_ARM_V7 1 */
-/* #define SLJIT_CONFIG_ARM_THUMB2 1 */
-/* #define SLJIT_CONFIG_ARM_64 1 */
-/* #define SLJIT_CONFIG_PPC_32 1 */
-/* #define SLJIT_CONFIG_PPC_64 1 */
-/* #define SLJIT_CONFIG_MIPS_32 1 */
-/* #define SLJIT_CONFIG_MIPS_64 1 */
-/* #define SLJIT_CONFIG_RISCV_32 1 */
-/* #define SLJIT_CONFIG_RISCV_64 1 */
-/* #define SLJIT_CONFIG_S390X 1 */
-
-/* #define SLJIT_CONFIG_AUTO 1 */
-/* #define SLJIT_CONFIG_UNSUPPORTED 1 */
-
-/* --------------------------------------------------------------------- */
/* Utilities */
/* --------------------------------------------------------------------- */
@@ -96,7 +74,9 @@ extern "C" {
/* Executable code allocation:
If SLJIT_EXECUTABLE_ALLOCATOR is not defined, the application should
- define SLJIT_MALLOC_EXEC, SLJIT_FREE_EXEC, and SLJIT_EXEC_OFFSET. */
+ define SLJIT_MALLOC_EXEC and SLJIT_FREE_EXEC.
+ Optionally, depending on the implementation used for the allocator,
+ SLJIT_EXEC_OFFSET and SLJIT_UPDATE_WX_FLAGS might also be needed. */
#ifndef SLJIT_EXECUTABLE_ALLOCATOR
/* Enabled by default. */
#define SLJIT_EXECUTABLE_ALLOCATOR 1
diff --git a/src/3rdparty/pcre2/src/sljit/sljitConfigCPU.h b/src/3rdparty/pcre2/src/sljit/sljitConfigCPU.h
new file mode 100644
index 0000000000..2720bdab0b
--- /dev/null
+++ b/src/3rdparty/pcre2/src/sljit/sljitConfigCPU.h
@@ -0,0 +1,188 @@
+/*
+ * Stack-less Just-In-Time compiler
+ *
+ * Copyright Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDER(S) 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 SLJIT_CONFIG_CPU_H_
+#define SLJIT_CONFIG_CPU_H_
+
+/* --------------------------------------------------------------------- */
+/* Architecture */
+/* --------------------------------------------------------------------- */
+
+/* Architecture selection. */
+/* #define SLJIT_CONFIG_X86_32 1 */
+/* #define SLJIT_CONFIG_X86_64 1 */
+/* #define SLJIT_CONFIG_ARM_V6 1 */
+/* #define SLJIT_CONFIG_ARM_V7 1 */
+/* #define SLJIT_CONFIG_ARM_THUMB2 1 */
+/* #define SLJIT_CONFIG_ARM_64 1 */
+/* #define SLJIT_CONFIG_PPC_32 1 */
+/* #define SLJIT_CONFIG_PPC_64 1 */
+/* #define SLJIT_CONFIG_MIPS_32 1 */
+/* #define SLJIT_CONFIG_MIPS_64 1 */
+/* #define SLJIT_CONFIG_RISCV_32 1 */
+/* #define SLJIT_CONFIG_RISCV_64 1 */
+/* #define SLJIT_CONFIG_S390X 1 */
+/* #define SLJIT_CONFIG_LOONGARCH_64 */
+
+/* #define SLJIT_CONFIG_AUTO 1 */
+/* #define SLJIT_CONFIG_UNSUPPORTED 1 */
+
+/*****************/
+/* Sanity check. */
+/*****************/
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
+ + (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
+ + (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) \
+ + (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
+ + (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
+ + (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
+ + (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
+ + (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
+ + (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
+ + (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
+ + (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) \
+ + (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) \
+ + (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \
+ + (defined SLJIT_CONFIG_LOONGARCH_64 && SLJIT_CONFIG_LOONGARCH_64) \
+ + (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) \
+ + (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) >= 2
+#error "Multiple architectures are selected"
+#endif
+
+#if !(defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
+ && !(defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
+ && !(defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) \
+ && !(defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
+ && !(defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
+ && !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
+ && !(defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
+ && !(defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
+ && !(defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
+ && !(defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
+ && !(defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) \
+ && !(defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) \
+ && !(defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \
+ && !(defined SLJIT_CONFIG_LOONGARCH_64 && SLJIT_CONFIG_LOONGARCH_64) \
+ && !(defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) \
+ && !(defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO)
+#if defined SLJIT_CONFIG_AUTO && !SLJIT_CONFIG_AUTO
+#error "An architecture must be selected"
+#else /* SLJIT_CONFIG_AUTO */
+#define SLJIT_CONFIG_AUTO 1
+#endif /* !SLJIT_CONFIG_AUTO */
+#endif /* !SLJIT_CONFIG */
+
+/********************************************************/
+/* Automatic CPU detection (requires compiler support). */
+/********************************************************/
+
+#if (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO)
+#ifndef _WIN32
+
+#if defined(__i386__) || defined(__i386)
+#define SLJIT_CONFIG_X86_32 1
+#elif defined(__x86_64__)
+#define SLJIT_CONFIG_X86_64 1
+#elif defined(__aarch64__)
+#define SLJIT_CONFIG_ARM_64 1
+#elif defined(__thumb2__)
+#define SLJIT_CONFIG_ARM_THUMB2 1
+#elif (defined(__ARM_ARCH) && __ARM_ARCH >= 7) || \
+ ((defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7S__)) \
+ || (defined(__ARM_ARCH_8A__) || defined(__ARM_ARCH_8R__)) \
+ || (defined(__ARM_ARCH_9A__)))
+#define SLJIT_CONFIG_ARM_V7 1
+#elif defined(__arm__) || defined (__ARM__)
+#define SLJIT_CONFIG_ARM_V6 1
+#elif defined(__ppc64__) || defined(__powerpc64__) || (defined(_ARCH_PPC64) && defined(__64BIT__)) || (defined(_POWER) && defined(__64BIT__))
+#define SLJIT_CONFIG_PPC_64 1
+#elif defined(__ppc__) || defined(__powerpc__) || defined(_ARCH_PPC) || defined(_ARCH_PWR) || defined(_ARCH_PWR2) || defined(_POWER)
+#define SLJIT_CONFIG_PPC_32 1
+#elif defined(__mips__) && !defined(_LP64)
+#define SLJIT_CONFIG_MIPS_32 1
+#elif defined(__mips64)
+#define SLJIT_CONFIG_MIPS_64 1
+#elif defined (__riscv_xlen) && (__riscv_xlen == 32)
+#define SLJIT_CONFIG_RISCV_32 1
+#elif defined (__riscv_xlen) && (__riscv_xlen == 64)
+#define SLJIT_CONFIG_RISCV_64 1
+#elif defined (__loongarch_lp64)
+#define SLJIT_CONFIG_LOONGARCH_64 1
+#elif defined(__s390x__)
+#define SLJIT_CONFIG_S390X 1
+#else
+/* Unsupported architecture */
+#define SLJIT_CONFIG_UNSUPPORTED 1
+#endif
+
+#else /* _WIN32 */
+
+#if defined(_M_X64) || defined(__x86_64__)
+#define SLJIT_CONFIG_X86_64 1
+#elif (defined(_M_ARM) && _M_ARM >= 7 && defined(_M_ARMT)) || defined(__thumb2__)
+#define SLJIT_CONFIG_ARM_THUMB2 1
+#elif (defined(_M_ARM) && _M_ARM >= 7)
+#define SLJIT_CONFIG_ARM_V7 1
+#elif defined(_ARM_)
+#define SLJIT_CONFIG_ARM_V6 1
+#elif defined(_M_ARM64) || defined(__aarch64__)
+#define SLJIT_CONFIG_ARM_64 1
+#else
+#define SLJIT_CONFIG_X86_32 1
+#endif
+
+#endif /* !_WIN32 */
+#endif /* SLJIT_CONFIG_AUTO */
+
+#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
+#undef SLJIT_EXECUTABLE_ALLOCATOR
+#endif /* SLJIT_CONFIG_UNSUPPORTED */
+
+/******************************/
+/* CPU family type detection. */
+/******************************/
+
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
+ || (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
+#define SLJIT_CONFIG_ARM_32 1
+#endif
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+#define SLJIT_CONFIG_X86 1
+#elif (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) || (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
+#define SLJIT_CONFIG_ARM 1
+#elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+#define SLJIT_CONFIG_PPC 1
+#elif (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) || (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+#define SLJIT_CONFIG_MIPS 1
+#elif (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) || (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
+#define SLJIT_CONFIG_RISCV 1
+#elif (defined SLJIT_CONFIG_LOONGARCH_64 && SLJIT_CONFIG_LOONGARCH_64)
+#define SLJIT_CONFIG_LOONGARCH 1
+#endif
+
+#endif /* SLJIT_CONFIG_CPU_H_ */
diff --git a/src/3rdparty/pcre2/src/sljit/sljitConfigInternal.h b/src/3rdparty/pcre2/src/sljit/sljitConfigInternal.h
index cd3ce69734..ce4e7b04ec 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitConfigInternal.h
+++ b/src/3rdparty/pcre2/src/sljit/sljitConfigInternal.h
@@ -61,6 +61,8 @@ extern "C" {
SLJIT_BIG_ENDIAN : big endian architecture
SLJIT_UNALIGNED : unaligned memory accesses for non-fpu operations are supported
SLJIT_FPU_UNALIGNED : unaligned memory accesses for fpu operations are supported
+ SLJIT_MASKED_SHIFT : all word shifts are always masked
+ SLJIT_MASKED_SHIFT32 : all 32 bit shifts are always masked
SLJIT_INDIRECT_CALL : see SLJIT_FUNC_ADDR() for more information
Constants:
@@ -70,6 +72,8 @@ extern "C" {
SLJIT_NUMBER_OF_FLOAT_REGISTERS : number of available floating point registers
SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS : number of available floating point scratch registers
SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS : number of available floating point saved registers
+ SLJIT_NUMBER_OF_TEMPORARY_REGISTERS : number of available temporary registers
+ SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS : number of available temporary floating point registers
SLJIT_WORD_SHIFT : the shift required to apply when accessing a sljit_sw/sljit_uw array by index
SLJIT_F32_SHIFT : the shift required to apply when accessing
a single precision floating point array by index
@@ -79,141 +83,27 @@ extern "C" {
the scratch register index of ecx is stored in this variable
SLJIT_LOCALS_OFFSET : local space starting offset (SLJIT_SP + SLJIT_LOCALS_OFFSET)
SLJIT_RETURN_ADDRESS_OFFSET : a return instruction always adds this offset to the return address
+ SLJIT_CONV_MAX_FLOAT : result when a floating point value is converted to integer
+ and the floating point value is higher than the maximum integer value
+ (possible values: SLJIT_CONV_RESULT_MAX_INT or SLJIT_CONV_RESULT_MIN_INT)
+ SLJIT_CONV_MIN_FLOAT : result when a floating point value is converted to integer
+ and the floating point value is lower than the minimum integer value
+ (possible values: SLJIT_CONV_RESULT_MAX_INT or SLJIT_CONV_RESULT_MIN_INT)
+ SLJIT_CONV_NAN_FLOAT : result when a NaN floating point value is converted to integer
+ (possible values: SLJIT_CONV_RESULT_MAX_INT, SLJIT_CONV_RESULT_MIN_INT,
+ or SLJIT_CONV_RESULT_ZERO)
Other macros:
+ SLJIT_TMP_R0 .. R9 : accessing temporary registers
+ SLJIT_TMP_R(i) : accessing temporary registers
+ SLJIT_TMP_FR0 .. FR9 : accessing temporary floating point registers
+ SLJIT_TMP_FR(i) : accessing temporary floating point registers
SLJIT_FUNC : calling convention attribute for both calling JIT from C and C calling back from JIT
SLJIT_W(number) : defining 64 bit constants on 64 bit architectures (platform independent helper)
+ SLJIT_F64_SECOND(reg) : provides the register index of the second 32 bit part of a 64 bit
+ floating point register when SLJIT_HAS_F64_AS_F32_PAIR returns non-zero
*/
-/*****************/
-/* Sanity check. */
-/*****************/
-
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
- + (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
- + (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) \
- + (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
- + (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
- + (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
- + (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
- + (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
- + (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
- + (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
- + (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) \
- + (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) \
- + (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \
- + (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) \
- + (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) >= 2
-#error "Multiple architectures are selected"
-#endif
-
-#if !(defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
- && !(defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
- && !(defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) \
- && !(defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
- && !(defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
- && !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
- && !(defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
- && !(defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
- && !(defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
- && !(defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
- && !(defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) \
- && !(defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) \
- && !(defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \
- && !(defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) \
- && !(defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO)
-#if defined SLJIT_CONFIG_AUTO && !SLJIT_CONFIG_AUTO
-#error "An architecture must be selected"
-#else /* SLJIT_CONFIG_AUTO */
-#define SLJIT_CONFIG_AUTO 1
-#endif /* !SLJIT_CONFIG_AUTO */
-#endif /* !SLJIT_CONFIG */
-
-/********************************************************/
-/* Automatic CPU detection (requires compiler support). */
-/********************************************************/
-
-#if (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO)
-
-#ifndef _WIN32
-
-#if defined(__i386__) || defined(__i386)
-#define SLJIT_CONFIG_X86_32 1
-#elif defined(__x86_64__)
-#define SLJIT_CONFIG_X86_64 1
-#elif defined(__arm__) || defined(__ARM__)
-#ifdef __thumb2__
-#define SLJIT_CONFIG_ARM_THUMB2 1
-#elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__)
-#define SLJIT_CONFIG_ARM_V7 1
-#else
-#define SLJIT_CONFIG_ARM_V5 1
-#endif
-#elif defined (__aarch64__)
-#define SLJIT_CONFIG_ARM_64 1
-#elif defined(__ppc64__) || defined(__powerpc64__) || (defined(_ARCH_PPC64) && defined(__64BIT__)) || (defined(_POWER) && defined(__64BIT__))
-#define SLJIT_CONFIG_PPC_64 1
-#elif defined(__ppc__) || defined(__powerpc__) || defined(_ARCH_PPC) || defined(_ARCH_PWR) || defined(_ARCH_PWR2) || defined(_POWER)
-#define SLJIT_CONFIG_PPC_32 1
-#elif defined(__mips__) && !defined(_LP64)
-#define SLJIT_CONFIG_MIPS_32 1
-#elif defined(__mips64)
-#define SLJIT_CONFIG_MIPS_64 1
-#elif defined (__riscv_xlen) && (__riscv_xlen == 32)
-#define SLJIT_CONFIG_RISCV_32 1
-#elif defined (__riscv_xlen) && (__riscv_xlen == 64)
-#define SLJIT_CONFIG_RISCV_64 1
-#elif defined(__s390x__)
-#define SLJIT_CONFIG_S390X 1
-#else
-/* Unsupported architecture */
-#define SLJIT_CONFIG_UNSUPPORTED 1
-#endif
-
-#else /* _WIN32 */
-
-#if defined(_M_X64) || defined(__x86_64__)
-#define SLJIT_CONFIG_X86_64 1
-#elif (defined(_M_ARM) && _M_ARM >= 7 && defined(_M_ARMT)) || defined(__thumb2__)
-#define SLJIT_CONFIG_ARM_THUMB2 1
-#elif (defined(_M_ARM) && _M_ARM >= 7)
-#define SLJIT_CONFIG_ARM_V7 1
-#elif defined(_ARM_)
-#define SLJIT_CONFIG_ARM_V5 1
-#elif defined(_M_ARM64) || defined(__aarch64__)
-#define SLJIT_CONFIG_ARM_64 1
-#else
-#define SLJIT_CONFIG_X86_32 1
-#endif
-
-#endif /* !_WIN32 */
-#endif /* SLJIT_CONFIG_AUTO */
-
-#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
-#undef SLJIT_EXECUTABLE_ALLOCATOR
-#endif
-
-/******************************/
-/* CPU family type detection. */
-/******************************/
-
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
- || (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
-#define SLJIT_CONFIG_ARM_32 1
-#endif
-
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
-#define SLJIT_CONFIG_X86 1
-#elif (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) || (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
-#define SLJIT_CONFIG_ARM 1
-#elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
-#define SLJIT_CONFIG_PPC 1
-#elif (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) || (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
-#define SLJIT_CONFIG_MIPS 1
-#elif (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32) || (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
-#define SLJIT_CONFIG_RISCV 1
-#endif
-
/***********************************************************/
/* Intel Control-flow Enforcement Technology (CET) spport. */
/***********************************************************/
@@ -328,6 +218,10 @@ extern "C" {
/* Instruction cache flush. */
/****************************/
+#ifdef __APPLE__
+#include <AvailabilityMacros.h>
+#endif
+
/*
* TODO:
*
@@ -368,7 +262,7 @@ extern "C" {
/* Not required to implement on archs with unified caches. */
#define SLJIT_CACHE_FLUSH(from, to)
-#elif defined __APPLE__
+#elif defined(__APPLE__) && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
/* Supported by all macs since Mac OS 10.5.
However, it does not work on non-jailbroken iOS devices,
@@ -433,14 +327,15 @@ typedef signed int sljit_s32;
#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
/* Just to have something. */
#define SLJIT_WORD_SHIFT 0
-typedef unsigned long int sljit_uw;
-typedef long int sljit_sw;
+typedef unsigned int sljit_uw;
+typedef int sljit_sw;
#elif !(defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
&& !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
&& !(defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
&& !(defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
&& !(defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64) \
- && !(defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
+ && !(defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \
+ && !(defined SLJIT_CONFIG_LOONGARCH_64 && SLJIT_CONFIG_LOONGARCH_64)
#define SLJIT_32BIT_ARCHITECTURE 1
#define SLJIT_WORD_SHIFT 2
typedef unsigned int sljit_uw;
@@ -476,12 +371,42 @@ typedef double sljit_f64;
#define SLJIT_F32_SHIFT 2
#define SLJIT_F64_SHIFT 3
+#define SLJIT_CONV_RESULT_MAX_INT 0
+#define SLJIT_CONV_RESULT_MIN_INT 1
+#define SLJIT_CONV_RESULT_ZERO 2
+
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
+#define SLJIT_CONV_MAX_FLOAT SLJIT_CONV_RESULT_MIN_INT
+#define SLJIT_CONV_MIN_FLOAT SLJIT_CONV_RESULT_MIN_INT
+#define SLJIT_CONV_NAN_FLOAT SLJIT_CONV_RESULT_MIN_INT
+#elif (defined SLJIT_CONFIG_ARM && SLJIT_CONFIG_ARM)
+#define SLJIT_CONV_MAX_FLOAT SLJIT_CONV_RESULT_MAX_INT
+#define SLJIT_CONV_MIN_FLOAT SLJIT_CONV_RESULT_MIN_INT
+#define SLJIT_CONV_NAN_FLOAT SLJIT_CONV_RESULT_ZERO
+#elif (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
+#define SLJIT_CONV_MAX_FLOAT SLJIT_CONV_RESULT_MAX_INT
+#define SLJIT_CONV_MIN_FLOAT SLJIT_CONV_RESULT_MAX_INT
+#define SLJIT_CONV_NAN_FLOAT SLJIT_CONV_RESULT_MAX_INT
+#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
+#define SLJIT_CONV_MAX_FLOAT SLJIT_CONV_RESULT_MAX_INT
+#define SLJIT_CONV_MIN_FLOAT SLJIT_CONV_RESULT_MIN_INT
+#define SLJIT_CONV_NAN_FLOAT SLJIT_CONV_RESULT_MIN_INT
+#elif (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV)
+#define SLJIT_CONV_MAX_FLOAT SLJIT_CONV_RESULT_MAX_INT
+#define SLJIT_CONV_MIN_FLOAT SLJIT_CONV_RESULT_MIN_INT
+#define SLJIT_CONV_NAN_FLOAT SLJIT_CONV_RESULT_MAX_INT
+#elif (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
+#define SLJIT_CONV_MAX_FLOAT SLJIT_CONV_RESULT_MAX_INT
+#define SLJIT_CONV_MIN_FLOAT SLJIT_CONV_RESULT_MIN_INT
+#define SLJIT_CONV_NAN_FLOAT SLJIT_CONV_RESULT_MIN_INT
+#else
+#error "Result for float to integer conversion is not defined"
+#endif
+
#ifndef SLJIT_W
/* Defining long constants. */
-#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
-#define SLJIT_W(w) (w##l)
-#elif (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE)
+#if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE)
#ifdef _WIN64
#define SLJIT_W(w) (w##ll)
#else /* !windows */
@@ -521,9 +446,10 @@ typedef double sljit_f64;
/* Auto detecting mips revision. */
#if (defined __mips_isa_rev) && (__mips_isa_rev >= 6)
#define SLJIT_MIPS_REV 6
-#elif (defined __mips_isa_rev && __mips_isa_rev >= 1) \
- || (defined __clang__ && defined _MIPS_ARCH_OCTEON) \
- || (defined __clang__ && defined _MIPS_ARCH_P5600)
+#elif defined(__mips_isa_rev) && __mips_isa_rev >= 1
+#define SLJIT_MIPS_REV __mips_isa_rev
+#elif defined(__clang__) \
+ && (defined(_MIPS_ARCH_OCTEON) || defined(_MIPS_ARCH_P5600))
/* clang either forgets to define (clang-7) __mips_isa_rev at all
* or sets it to zero (clang-8,-9) for -march=octeon (MIPS64 R2+)
* and -march=p5600 (MIPS32 R5).
@@ -562,7 +488,8 @@ typedef double sljit_f64;
|| (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
|| (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) \
|| (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV) \
- || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
+ || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \
+ || (defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH)
#define SLJIT_UNALIGNED 1
#endif
@@ -574,7 +501,8 @@ typedef double sljit_f64;
|| (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
|| (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) \
|| (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV) \
- || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
+ || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \
+ || (defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH)
#define SLJIT_FPU_UNALIGNED 1
#endif
@@ -594,6 +522,19 @@ typedef double sljit_f64;
#define SLJIT_FUNC
#endif /* !SLJIT_FUNC */
+/* Disable instrumentation for these functions as they may not be sound */
+#ifndef SLJIT_FUNC_ATTRIBUTE
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+#define SLJIT_FUNC_ATTRIBUTE __attribute__((no_sanitize("memory")))
+#endif /* __has_feature(memory_sanitizer) */
+#endif /* defined(__has_feature) */
+#endif
+
+#ifndef SLJIT_FUNC_ATTRIBUTE
+#define SLJIT_FUNC_ATTRIBUTE
+#endif
+
#ifndef SLJIT_INDIRECT_CALL
#if ((defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) && (!defined _CALL_ELF || _CALL_ELF == 1)) \
|| ((defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) && defined _AIX)
@@ -631,12 +572,14 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void);
#if (defined SLJIT_PROT_EXECUTABLE_ALLOCATOR && SLJIT_PROT_EXECUTABLE_ALLOCATOR)
SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
#define SLJIT_EXEC_OFFSET(ptr) sljit_exec_offset(ptr)
-#else
-#define SLJIT_EXEC_OFFSET(ptr) 0
#endif
#endif /* SLJIT_EXECUTABLE_ALLOCATOR */
+#ifndef SLJIT_EXEC_OFFSET
+#define SLJIT_EXEC_OFFSET(ptr) 0
+#endif
+
/**********************************************/
/* Registers and locals offset determination. */
/**********************************************/
@@ -645,15 +588,21 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
#define SLJIT_NUMBER_OF_REGISTERS 12
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 7
+#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 1
#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 7
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 0
+#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 1
#define SLJIT_LOCALS_OFFSET_BASE (8 * SSIZE_OF(sw))
#define SLJIT_PREF_SHIFT_REG SLJIT_R2
+#define SLJIT_MASKED_SHIFT 1
+#define SLJIT_MASKED_SHIFT32 1
#elif (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
#define SLJIT_NUMBER_OF_REGISTERS 13
+#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 2
#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 15
+#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 1
#ifndef _WIN64
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 6
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 0
@@ -664,37 +613,39 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
#define SLJIT_LOCALS_OFFSET_BASE (4 * SSIZE_OF(sw))
#endif /* !_WIN64 */
#define SLJIT_PREF_SHIFT_REG SLJIT_R3
+#define SLJIT_MASKED_SHIFT 1
+#define SLJIT_MASKED_SHIFT32 1
-#elif (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
-
-#define SLJIT_NUMBER_OF_REGISTERS 12
-#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
-#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 14
-#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8
-#define SLJIT_LOCALS_OFFSET_BASE 0
-
-#elif (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
+#elif (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32)
#define SLJIT_NUMBER_OF_REGISTERS 12
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
+#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 2
#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 14
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8
+#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 2
#define SLJIT_LOCALS_OFFSET_BASE 0
#elif (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
#define SLJIT_NUMBER_OF_REGISTERS 26
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 10
+#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 3
#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 30
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8
+#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 2
#define SLJIT_LOCALS_OFFSET_BASE (2 * (sljit_s32)sizeof(sljit_sw))
+#define SLJIT_MASKED_SHIFT 1
+#define SLJIT_MASKED_SHIFT32 1
#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
#define SLJIT_NUMBER_OF_REGISTERS 23
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 17
+#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 3
#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 30
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 18
+#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 2
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) || (defined _AIX)
#define SLJIT_LOCALS_OFFSET_BASE ((6 + 8) * (sljit_s32)sizeof(sljit_sw))
#elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
@@ -717,14 +668,22 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 29
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8
#endif
+#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 5
+#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 3
+#define SLJIT_MASKED_SHIFT 1
+#define SLJIT_MASKED_SHIFT32 1
#elif (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV)
#define SLJIT_NUMBER_OF_REGISTERS 23
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 12
-#define SLJIT_LOCALS_OFFSET_BASE 0
+#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 5
#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 30
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 12
+#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 2
+#define SLJIT_LOCALS_OFFSET_BASE 0
+#define SLJIT_MASKED_SHIFT 1
+#define SLJIT_MASKED_SHIFT32 1
#elif (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
@@ -751,16 +710,34 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
#define SLJIT_NUMBER_OF_REGISTERS 12
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
+#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 3
#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 15
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 8
+#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 1
#define SLJIT_LOCALS_OFFSET_BASE SLJIT_S390X_DEFAULT_STACK_FRAME_SIZE
+#define SLJIT_MASKED_SHIFT 1
+
+#elif (defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH)
+
+#define SLJIT_NUMBER_OF_REGISTERS 23
+#define SLJIT_NUMBER_OF_SAVED_REGISTERS 10
+#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 5
+#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 30
+#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 12
+#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 2
+#define SLJIT_LOCALS_OFFSET_BASE 0
+#define SLJIT_MASKED_SHIFT 1
+#define SLJIT_MASKED_SHIFT32 1
#elif (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
+/* Just to have something. */
#define SLJIT_NUMBER_OF_REGISTERS 0
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 0
+#define SLJIT_NUMBER_OF_TEMPORARY_REGISTERS 0
#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 0
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 0
+#define SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS 0
#define SLJIT_LOCALS_OFFSET_BASE 0
#endif
@@ -773,6 +750,45 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
#define SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS \
(SLJIT_NUMBER_OF_FLOAT_REGISTERS - SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS)
+/**********************************/
+/* Temporary register management. */
+/**********************************/
+
+#define SLJIT_TMP_REGISTER_BASE (SLJIT_NUMBER_OF_REGISTERS + 2)
+#define SLJIT_TMP_FREGISTER_BASE (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
+
+/* WARNING: Accessing temporary registers is not recommended, because they
+ are also used by the JIT compiler for various computations. Using them
+ might have any side effects including incorrect operations and crashes,
+ so use them at your own risk. The machine registers themselves might have
+ limitations, e.g. the r0 register on s390x / ppc cannot be used as
+ base address for memory operations. */
+
+/* Temporary registers */
+#define SLJIT_TMP_R0 (SLJIT_TMP_REGISTER_BASE + 0)
+#define SLJIT_TMP_R1 (SLJIT_TMP_REGISTER_BASE + 1)
+#define SLJIT_TMP_R2 (SLJIT_TMP_REGISTER_BASE + 2)
+#define SLJIT_TMP_R3 (SLJIT_TMP_REGISTER_BASE + 3)
+#define SLJIT_TMP_R4 (SLJIT_TMP_REGISTER_BASE + 4)
+#define SLJIT_TMP_R5 (SLJIT_TMP_REGISTER_BASE + 5)
+#define SLJIT_TMP_R6 (SLJIT_TMP_REGISTER_BASE + 6)
+#define SLJIT_TMP_R7 (SLJIT_TMP_REGISTER_BASE + 7)
+#define SLJIT_TMP_R8 (SLJIT_TMP_REGISTER_BASE + 8)
+#define SLJIT_TMP_R9 (SLJIT_TMP_REGISTER_BASE + 9)
+#define SLJIT_TMP_R(i) (SLJIT_TMP_REGISTER_BASE + (i))
+
+#define SLJIT_TMP_FR0 (SLJIT_TMP_FREGISTER_BASE + 0)
+#define SLJIT_TMP_FR1 (SLJIT_TMP_FREGISTER_BASE + 1)
+#define SLJIT_TMP_FR2 (SLJIT_TMP_FREGISTER_BASE + 2)
+#define SLJIT_TMP_FR3 (SLJIT_TMP_FREGISTER_BASE + 3)
+#define SLJIT_TMP_FR4 (SLJIT_TMP_FREGISTER_BASE + 4)
+#define SLJIT_TMP_FR5 (SLJIT_TMP_FREGISTER_BASE + 5)
+#define SLJIT_TMP_FR6 (SLJIT_TMP_FREGISTER_BASE + 6)
+#define SLJIT_TMP_FR7 (SLJIT_TMP_FREGISTER_BASE + 7)
+#define SLJIT_TMP_FR8 (SLJIT_TMP_FREGISTER_BASE + 8)
+#define SLJIT_TMP_FR9 (SLJIT_TMP_FREGISTER_BASE + 9)
+#define SLJIT_TMP_FR(i) (SLJIT_TMP_FREGISTER_BASE + (i))
+
/********************************/
/* CPU status flags management. */
/********************************/
@@ -781,10 +797,24 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_sw sljit_exec_offset(void* ptr);
|| (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) \
|| (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) \
|| (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV) \
- || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
+ || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \
+ || (defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH)
#define SLJIT_HAS_STATUS_FLAGS_STATE 1
#endif
+/***************************************/
+/* Floating point register management. */
+/***************************************/
+
+#if (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) \
+ || (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+#define SLJIT_F64_SECOND(reg) \
+ ((reg) + SLJIT_FS0 + SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS)
+#else /* !SLJIT_CONFIG_ARM_32 && !SLJIT_CONFIG_MIPS_32 */
+#define SLJIT_F64_SECOND(reg) \
+ (reg)
+#endif /* SLJIT_CONFIG_ARM_32 || SLJIT_CONFIG_MIPS_32 */
+
/*************************************/
/* Debug and verbose related macros. */
/*************************************/
diff --git a/src/3rdparty/pcre2/src/sljit/sljitLir.c b/src/3rdparty/pcre2/src/sljit/sljitLir.c
index abafe1add9..6f19300081 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitLir.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitLir.c
@@ -93,7 +93,8 @@
#define SSIZE_OF(type) ((sljit_s32)sizeof(sljit_ ## type))
#define VARIABLE_FLAG_SHIFT (10)
-#define VARIABLE_FLAG_MASK (0x3f << VARIABLE_FLAG_SHIFT)
+/* All variable flags are even. */
+#define VARIABLE_FLAG_MASK (0x3e << VARIABLE_FLAG_SHIFT)
#define GET_FLAG_TYPE(op) ((op) >> VARIABLE_FLAG_SHIFT)
#define GET_OPCODE(op) \
@@ -122,25 +123,34 @@
#endif
/* Parameter parsing. */
-#define REG_MASK 0x3f
+#define REG_MASK 0x7f
#define OFFS_REG(reg) (((reg) >> 8) & REG_MASK)
#define OFFS_REG_MASK (REG_MASK << 8)
#define TO_OFFS_REG(reg) ((reg) << 8)
-/* When reg cannot be unused. */
-#define FAST_IS_REG(reg) ((reg) <= REG_MASK)
+#define FAST_IS_REG(reg) ((reg) < REG_MASK)
/* Mask for argument types. */
#define SLJIT_ARG_MASK 0x7
#define SLJIT_ARG_FULL_MASK (SLJIT_ARG_MASK | SLJIT_ARG_TYPE_SCRATCH_REG)
-/* Mask for sljit_emit_mem. */
-#define REG_PAIR_MASK 0xff00
-#define REG_PAIR_FIRST(reg) ((reg) & 0xff)
+/* Mask for register pairs. */
+#define REG_PAIR_MASK 0x7f00
+#define REG_PAIR_FIRST(reg) ((reg) & 0x7f)
#define REG_PAIR_SECOND(reg) ((reg) >> 8)
/* Mask for sljit_emit_enter. */
#define SLJIT_KEPT_SAVEDS_COUNT(options) ((options) & 0x3)
+/* Getters for simd operations, which returns with log2(size). */
+#define SLJIT_SIMD_GET_OPCODE(type) ((type) & 0xff)
+#define SLJIT_SIMD_GET_REG_SIZE(type) (((type) >> 12) & 0x3f)
+#define SLJIT_SIMD_GET_ELEM_SIZE(type) (((type) >> 18) & 0x3f)
+#define SLJIT_SIMD_GET_ELEM2_SIZE(type) (((type) >> 24) & 0x3f)
+
+#define SLJIT_SIMD_CHECK_REG(type) (((type) & 0x3f000) >= SLJIT_SIMD_REG_64 && ((type) & 0x3f000) <= SLJIT_SIMD_REG_512)
+#define SLJIT_SIMD_TYPE_MASK(m) ((sljit_s32)0xff000fff & ~(SLJIT_SIMD_FLOAT | SLJIT_SIMD_TEST | (m)))
+#define SLJIT_SIMD_TYPE_MASK2(m) ((sljit_s32)0xc0000fff & ~(SLJIT_SIMD_FLOAT | SLJIT_SIMD_TEST | (m)))
+
/* Jump flags. */
#define JUMP_LABEL 0x1
#define JUMP_ADDR 0x2
@@ -155,14 +165,14 @@
# define TYPE_SHIFT 13
#endif /* SLJIT_CONFIG_X86 */
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
# define IS_BL 0x4
# define PATCH_B 0x8
-#endif /* SLJIT_CONFIG_ARM_V5 || SLJIT_CONFIG_ARM_V7 */
+#endif /* SLJIT_CONFIG_ARM_V6 || SLJIT_CONFIG_ARM_V6 */
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
# define CPOOL_SIZE 512
-#endif /* SLJIT_CONFIG_ARM_V5 */
+#endif /* SLJIT_CONFIG_ARM_V6 */
#if (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
# define IS_COND 0x04
@@ -248,15 +258,27 @@
#endif /* SLJIT_CONFIG_RISCV_64 */
#endif /* SLJIT_CONFIG_RISCV */
+#if (defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH)
+# define IS_COND 0x004
+# define IS_CALL 0x008
+
+# define PATCH_B 0x010
+# define PATCH_J 0x020
+
+# define PATCH_REL32 0x040
+# define PATCH_ABS32 0x080
+# define PATCH_ABS52 0x100
+
+#endif /* SLJIT_CONFIG_LOONGARCH */
/* Stack management. */
#define GET_SAVED_REGISTERS_SIZE(scratches, saveds, extra) \
(((scratches < SLJIT_NUMBER_OF_SCRATCH_REGISTERS ? 0 : (scratches - SLJIT_NUMBER_OF_SCRATCH_REGISTERS)) + \
(saveds) + (sljit_s32)(extra)) * (sljit_s32)sizeof(sljit_sw))
-#define GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, size) \
+#define GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, type) \
(((fscratches < SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS ? 0 : (fscratches - SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS)) + \
- (fsaveds)) * (sljit_s32)(size))
+ (fsaveds)) * SSIZE_OF(type))
#define ADJUST_LOCAL_OFFSET(p, i) \
if ((p) == (SLJIT_MEM1(SLJIT_SP))) \
@@ -272,25 +294,49 @@
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
#if (defined SLJIT_PROT_EXECUTABLE_ALLOCATOR && SLJIT_PROT_EXECUTABLE_ALLOCATOR)
-#include "sljitProtExecAllocator.c"
-#elif (defined SLJIT_WX_EXECUTABLE_ALLOCATOR && SLJIT_WX_EXECUTABLE_ALLOCATOR)
-#include "sljitWXExecAllocator.c"
+
+#if defined(__NetBSD__)
+#include "allocator_src/sljitProtExecAllocatorNetBSD.c"
#else
-#include "sljitExecAllocator.c"
+#include "allocator_src/sljitProtExecAllocatorPosix.c"
#endif
+#elif (defined SLJIT_WX_EXECUTABLE_ALLOCATOR && SLJIT_WX_EXECUTABLE_ALLOCATOR)
+
+#if defined(_WIN32)
+#include "allocator_src/sljitWXExecAllocatorWindows.c"
+#else
+#include "allocator_src/sljitWXExecAllocatorPosix.c"
#endif
-#if (defined SLJIT_PROT_EXECUTABLE_ALLOCATOR && SLJIT_PROT_EXECUTABLE_ALLOCATOR)
-#define SLJIT_ADD_EXEC_OFFSET(ptr, exec_offset) ((sljit_u8 *)(ptr) + (exec_offset))
#else
-#define SLJIT_ADD_EXEC_OFFSET(ptr, exec_offset) ((sljit_u8 *)(ptr))
+
+#if defined(_WIN32)
+#include "allocator_src/sljitExecAllocatorWindows.c"
+#elif defined(__APPLE__)
+#include "allocator_src/sljitExecAllocatorApple.c"
+#elif defined(__FreeBSD__)
+#include "allocator_src/sljitExecAllocatorFreeBSD.c"
+#else
+#include "allocator_src/sljitExecAllocatorPosix.c"
+#endif
+
#endif
+#else /* !SLJIT_EXECUTABLE_ALLOCATOR */
+
#ifndef SLJIT_UPDATE_WX_FLAGS
#define SLJIT_UPDATE_WX_FLAGS(from, to, enable_exec)
#endif
+#endif /* SLJIT_EXECUTABLE_ALLOCATOR */
+
+#if (defined SLJIT_PROT_EXECUTABLE_ALLOCATOR && SLJIT_PROT_EXECUTABLE_ALLOCATOR)
+#define SLJIT_ADD_EXEC_OFFSET(ptr, exec_offset) ((sljit_u8 *)(ptr) + (exec_offset))
+#else
+#define SLJIT_ADD_EXEC_OFFSET(ptr, exec_offset) ((sljit_u8 *)(ptr))
+#endif
+
/* Argument checking features. */
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
@@ -422,9 +468,9 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allo
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
compiler->args_size = -1;
-#endif
+#endif /* SLJIT_CONFIG_X86_32 */
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
compiler->cpool = (sljit_uw*)SLJIT_MALLOC(CPOOL_SIZE * sizeof(sljit_uw)
+ CPOOL_SIZE * sizeof(sljit_u8), allocator_data);
if (!compiler->cpool) {
@@ -435,18 +481,18 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allo
}
compiler->cpool_unique = (sljit_u8*)(compiler->cpool + CPOOL_SIZE);
compiler->cpool_diff = 0xffffffff;
-#endif
+#endif /* SLJIT_CONFIG_ARM_V6 */
#if (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
compiler->delay_slot = UNMOVABLE_INS;
-#endif
+#endif /* SLJIT_CONFIG_MIPS */
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS) \
|| (defined SLJIT_DEBUG && SLJIT_DEBUG)
compiler->last_flags = 0;
compiler->last_return = -1;
compiler->logical_local_size = 0;
-#endif
+#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_DEBUG */
#if (defined SLJIT_NEEDS_COMPILER_INIT && SLJIT_NEEDS_COMPILER_INIT)
if (!compiler_initialized) {
@@ -479,7 +525,7 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_compiler(struct sljit_compiler *compile
SLJIT_FREE(curr, allocator_data);
}
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
SLJIT_FREE(compiler->cpool, allocator_data);
#endif
SLJIT_FREE(compiler, allocator_data);
@@ -802,11 +848,8 @@ static sljit_s32 function_check_arguments(sljit_s32 arg_types, sljit_s32 scratch
#define FUNCTION_CHECK_IS_REG(r) \
(((r) >= SLJIT_R0 && (r) < (SLJIT_R0 + compiler->scratches)) \
- || ((r) > (SLJIT_S0 - compiler->saveds) && (r) <= SLJIT_S0))
-
-#define FUNCTION_CHECK_IS_FREG(fr) \
- (((fr) >= SLJIT_FR0 && (fr) < (SLJIT_FR0 + compiler->fscratches)) \
- || ((fr) > (SLJIT_FS0 - compiler->fsaveds) && (fr) <= SLJIT_FS0))
+ || ((r) > (SLJIT_S0 - compiler->saveds) && (r) <= SLJIT_S0) \
+ || ((r) >= SLJIT_TMP_REGISTER_BASE && (r) < (SLJIT_TMP_REGISTER_BASE + SLJIT_NUMBER_OF_TEMPORARY_REGISTERS)))
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
#define CHECK_IF_VIRTUAL_REGISTER(p) ((p) <= SLJIT_S3 && (p) >= SLJIT_S8)
@@ -816,7 +859,7 @@ static sljit_s32 function_check_arguments(sljit_s32 arg_types, sljit_s32 scratch
static sljit_s32 function_check_src_mem(struct sljit_compiler *compiler, sljit_s32 p, sljit_sw i)
{
- if (compiler->scratches == -1 || compiler->saveds == -1)
+ if (compiler->scratches == -1)
return 0;
if (!(p & SLJIT_MEM))
@@ -853,7 +896,7 @@ static sljit_s32 function_check_src_mem(struct sljit_compiler *compiler, sljit_s
static sljit_s32 function_check_src(struct sljit_compiler *compiler, sljit_s32 p, sljit_sw i)
{
- if (compiler->scratches == -1 || compiler->saveds == -1)
+ if (compiler->scratches == -1)
return 0;
if (FUNCTION_CHECK_IS_REG(p))
@@ -870,7 +913,7 @@ static sljit_s32 function_check_src(struct sljit_compiler *compiler, sljit_s32 p
static sljit_s32 function_check_dst(struct sljit_compiler *compiler, sljit_s32 p, sljit_sw i)
{
- if (compiler->scratches == -1 || compiler->saveds == -1)
+ if (compiler->scratches == -1)
return 0;
if (FUNCTION_CHECK_IS_REG(p))
@@ -882,19 +925,59 @@ static sljit_s32 function_check_dst(struct sljit_compiler *compiler, sljit_s32 p
#define FUNCTION_CHECK_DST(p, i) \
CHECK_ARGUMENT(function_check_dst(compiler, p, i));
+#if (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) \
+ || (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+
+#define FUNCTION_CHECK_IS_FREG(fr, is_32) \
+ function_check_is_freg(compiler, (fr), (is_32))
+
+static sljit_s32 function_check_is_freg(struct sljit_compiler *compiler, sljit_s32 fr, sljit_s32 is_32);
+
+#define FUNCTION_FCHECK(p, i, is_32) \
+ CHECK_ARGUMENT(function_fcheck(compiler, (p), (i), (is_32)));
+
+static sljit_s32 function_fcheck(struct sljit_compiler *compiler, sljit_s32 p, sljit_sw i, sljit_s32 is_32)
+{
+ if (compiler->scratches == -1)
+ return 0;
+
+ if (FUNCTION_CHECK_IS_FREG(p, is_32))
+ return (i == 0);
+
+ return function_check_src_mem(compiler, p, i);
+}
+
+#else /* !SLJIT_CONFIG_ARM_32 && !SLJIT_CONFIG_MIPS_32 */
+#define FUNCTION_CHECK_IS_FREG(fr, is_32) \
+ function_check_is_freg(compiler, (fr))
+
+static sljit_s32 function_check_is_freg(struct sljit_compiler *compiler, sljit_s32 fr)
+{
+ if (compiler->scratches == -1)
+ return 0;
+
+ return (fr >= SLJIT_FR0 && fr < (SLJIT_FR0 + compiler->fscratches))
+ || (fr > (SLJIT_FS0 - compiler->fsaveds) && fr <= SLJIT_FS0)
+ || (fr >= SLJIT_TMP_FREGISTER_BASE && fr < (SLJIT_TMP_FREGISTER_BASE + SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS));
+}
+
+#define FUNCTION_FCHECK(p, i, is_32) \
+ CHECK_ARGUMENT(function_fcheck(compiler, (p), (i)));
+
static sljit_s32 function_fcheck(struct sljit_compiler *compiler, sljit_s32 p, sljit_sw i)
{
- if (compiler->scratches == -1 || compiler->saveds == -1)
+ if (compiler->scratches == -1)
return 0;
- if (FUNCTION_CHECK_IS_FREG(p))
+ if ((p >= SLJIT_FR0 && p < (SLJIT_FR0 + compiler->fscratches))
+ || (p > (SLJIT_FS0 - compiler->fsaveds) && p <= SLJIT_FS0)
+ || (p >= SLJIT_TMP_FREGISTER_BASE && p < (SLJIT_TMP_FREGISTER_BASE + SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS)))
return (i == 0);
return function_check_src_mem(compiler, p, i);
}
-#define FUNCTION_FCHECK(p, i) \
- CHECK_ARGUMENT(function_fcheck(compiler, p, i));
+#endif /* SLJIT_CONFIG_ARM_32 || SLJIT_CONFIG_MIPS_32 */
#endif /* SLJIT_ARGUMENT_CHECKS */
@@ -923,23 +1006,35 @@ static void sljit_verbose_reg(struct sljit_compiler *compiler, sljit_s32 r)
{
if (r < (SLJIT_R0 + compiler->scratches))
fprintf(compiler->verbose, "r%d", r - SLJIT_R0);
- else if (r != SLJIT_SP)
+ else if (r < SLJIT_SP)
fprintf(compiler->verbose, "s%d", SLJIT_NUMBER_OF_REGISTERS - r);
- else
+ else if (r == SLJIT_SP)
fprintf(compiler->verbose, "sp");
+ else
+ fprintf(compiler->verbose, "t%d", r - SLJIT_TMP_REGISTER_BASE);
}
static void sljit_verbose_freg(struct sljit_compiler *compiler, sljit_s32 r)
{
+#if (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) \
+ || (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+ if (r >= SLJIT_F64_SECOND(SLJIT_FR0)) {
+ fprintf(compiler->verbose, "^");
+ r -= SLJIT_F64_SECOND(0);
+ }
+#endif /* SLJIT_CONFIG_ARM_32 || SLJIT_CONFIG_MIPS_32 */
+
if (r < (SLJIT_FR0 + compiler->fscratches))
fprintf(compiler->verbose, "fr%d", r - SLJIT_FR0);
- else
+ else if (r < SLJIT_TMP_FREGISTER_BASE)
fprintf(compiler->verbose, "fs%d", SLJIT_NUMBER_OF_FLOAT_REGISTERS - r);
+ else
+ fprintf(compiler->verbose, "ft%d", r - SLJIT_TMP_FREGISTER_BASE);
}
static void sljit_verbose_param(struct sljit_compiler *compiler, sljit_s32 p, sljit_sw i)
{
- if ((p) & SLJIT_IMM)
+ if ((p) == SLJIT_IMM)
fprintf(compiler->verbose, "#%" SLJIT_PRINT_D "d", (i));
else if ((p) & SLJIT_MEM) {
if ((p) & REG_MASK) {
@@ -991,9 +1086,17 @@ static const char* op0_names[] = {
};
static const char* op1_names[] = {
+ "mov", "mov", "mov", "mov",
+ "mov", "mov", "mov", "mov",
+ "mov", "clz", "ctz", "rev",
+ "rev", "rev", "rev", "rev"
+};
+
+static const char* op1_types[] = {
"", ".u8", ".s8", ".u16",
".s16", ".u32", ".s32", "32",
- ".p", "not", "clz", "ctz"
+ ".p", "", "", "",
+ ".u16", ".s16", ".u32", ".s32"
};
static const char* op2_names[] = {
@@ -1003,22 +1106,36 @@ static const char* op2_names[] = {
"ashr", "mashr", "rotl", "rotr"
};
-static const char* op_src_names[] = {
+static const char* op_src_dst_names[] = {
"fast_return", "skip_frames_before_fast_return",
"prefetch_l1", "prefetch_l2",
"prefetch_l3", "prefetch_once",
+ "fast_enter", "get_return_address"
};
static const char* fop1_names[] = {
"mov", "conv", "conv", "conv",
- "conv", "conv", "cmp", "neg",
- "abs",
+ "conv", "conv", "conv", "conv",
+ "cmp", "neg", "abs",
+};
+
+static const char* fop1_conv_types[] = {
+ "sw", "s32", "sw", "s32",
+ "uw", "u32"
};
static const char* fop2_names[] = {
"add", "sub", "mul", "div"
};
+static const char* fop2r_names[] = {
+ "copysign"
+};
+
+static const char* simd_op2_names[] = {
+ "and", "or", "xor"
+};
+
static const char* jump_names[] = {
"equal", "not_equal",
"less", "greater_equal",
@@ -1026,7 +1143,8 @@ static const char* jump_names[] = {
"sig_less", "sig_greater_equal",
"sig_greater", "sig_less_equal",
"overflow", "not_overflow",
- "carry", "",
+ "carry", "not_carry",
+ "atomic_stored", "atomic_not_stored",
"f_equal", "f_not_equal",
"f_less", "f_greater_equal",
"f_greater", "f_less_equal",
@@ -1126,7 +1244,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_enter(struct sljit_compil
fprintf(compiler->verbose, " keep:%d,", SLJIT_KEPT_SAVEDS_COUNT(options));
}
- fprintf(compiler->verbose, "scratches:%d, saveds:%d, fscratches:%d, fsaveds:%d, local_size:%d\n",
+ fprintf(compiler->verbose, " scratches:%d, saveds:%d, fscratches:%d, fsaveds:%d, local_size:%d\n",
scratches, saveds, fscratches, fsaveds, local_size);
}
#endif
@@ -1198,7 +1316,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_return_void(struct sljit_
}
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- CHECK_ARGUMENT(compiler->last_return == SLJIT_ARG_TYPE_VOID);
+ CHECK_ARGUMENT(compiler->last_return == SLJIT_ARG_TYPE_RET_VOID);
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
@@ -1241,7 +1359,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_return(struct sljit_compi
if (GET_OPCODE(op) < SLJIT_MOV_F64) {
FUNCTION_CHECK_SRC(src, srcw);
} else {
- FUNCTION_FCHECK(src, srcw);
+ FUNCTION_FCHECK(src, srcw, op & SLJIT_32);
}
compiler->last_flags = 0;
#endif
@@ -1249,7 +1367,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_return(struct sljit_compi
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
if (GET_OPCODE(op) < SLJIT_MOV_F64) {
fprintf(compiler->verbose, " return%s%s ", !(op & SLJIT_32) ? "" : "32",
- op1_names[GET_OPCODE(op) - SLJIT_OP1_BASE]);
+ op1_types[GET_OPCODE(op) - SLJIT_OP1_BASE]);
sljit_verbose_param(compiler, src, srcw);
} else {
fprintf(compiler->verbose, " return%s ", !(op & SLJIT_32) ? ".f64" : ".f32");
@@ -1277,22 +1395,6 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_return_to(struct sljit_co
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
-{
-#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- FUNCTION_CHECK_DST(dst, dstw);
- compiler->last_flags = 0;
-#endif
-#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
- if (SLJIT_UNLIKELY(!!compiler->verbose)) {
- fprintf(compiler->verbose, " fast_enter ");
- sljit_verbose_param(compiler, dst, dstw);
- fprintf(compiler->verbose, "\n");
- }
-#endif
- CHECK_RETURN_OK;
-}
-
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
{
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
@@ -1326,16 +1428,16 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op1(struct sljit_compiler
}
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_MOV && GET_OPCODE(op) <= SLJIT_CTZ);
+ CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_MOV && GET_OPCODE(op) <= SLJIT_REV_S32);
switch (GET_OPCODE(op)) {
- case SLJIT_NOT:
- /* Only SLJIT_32 and SLJIT_SET_Z are allowed. */
- CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK));
- break;
case SLJIT_MOV:
case SLJIT_MOV_U32:
+ case SLJIT_MOV_S32:
+ case SLJIT_MOV32:
case SLJIT_MOV_P:
+ case SLJIT_REV_U32:
+ case SLJIT_REV_S32:
/* Nothing allowed */
CHECK_ARGUMENT(!(op & (SLJIT_32 | SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
break;
@@ -1347,25 +1449,11 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op1(struct sljit_compiler
FUNCTION_CHECK_DST(dst, dstw);
FUNCTION_CHECK_SRC(src, srcw);
-
- if (GET_OPCODE(op) >= SLJIT_NOT) {
- CHECK_ARGUMENT(src != SLJIT_IMM);
- compiler->last_flags = GET_FLAG_TYPE(op) | (op & (SLJIT_32 | SLJIT_SET_Z));
- }
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
- if (GET_OPCODE(op) <= SLJIT_MOV_P)
- {
- fprintf(compiler->verbose, " mov%s%s ", !(op & SLJIT_32) ? "" : "32",
- op1_names[GET_OPCODE(op) - SLJIT_OP1_BASE]);
- }
- else
- {
- fprintf(compiler->verbose, " %s%s%s%s%s ", op1_names[GET_OPCODE(op) - SLJIT_OP1_BASE], !(op & SLJIT_32) ? "" : "32",
- !(op & SLJIT_SET_Z) ? "" : ".z", !(op & VARIABLE_FLAG_MASK) ? "" : ".",
- !(op & VARIABLE_FLAG_MASK) ? "" : jump_names[GET_FLAG_TYPE(op)]);
- }
+ fprintf(compiler->verbose, " %s%s%s ", op1_names[GET_OPCODE(op) - SLJIT_OP1_BASE],
+ !(op & SLJIT_32) ? "" : "32", op1_types[GET_OPCODE(op) - SLJIT_OP1_BASE]);
sljit_verbose_param(compiler, dst, dstw);
fprintf(compiler->verbose, ", ");
@@ -1376,6 +1464,94 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op1(struct sljit_compiler
CHECK_RETURN_OK;
}
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_atomic_load(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_reg,
+ sljit_s32 mem_reg)
+{
+ if (SLJIT_UNLIKELY(compiler->skip_checks)) {
+ compiler->skip_checks = 0;
+ CHECK_RETURN_OK;
+ }
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_ATOMIC));
+ CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_MOV && GET_OPCODE(op) <= SLJIT_MOV_P);
+ CHECK_ARGUMENT(GET_OPCODE(op) != SLJIT_MOV_S8 && GET_OPCODE(op) != SLJIT_MOV_S16 && GET_OPCODE(op) != SLJIT_MOV_S32);
+
+ /* All arguments must be valid registers. */
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(dst_reg));
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(mem_reg) && !CHECK_IF_VIRTUAL_REGISTER(mem_reg));
+
+ if (op == SLJIT_MOV32_U8 || op == SLJIT_MOV32_U16) {
+ /* Only SLJIT_32 is allowed. */
+ CHECK_ARGUMENT(!(op & (VARIABLE_FLAG_MASK | SLJIT_SET_Z)));
+ } else {
+ /* Nothing allowed. */
+ CHECK_ARGUMENT(!(op & (SLJIT_32 | SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
+ }
+
+ compiler->last_flags = 0;
+#endif /* SLJIT_ARGUMENT_CHECKS */
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+ if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+ fprintf(compiler->verbose, " atomic_load%s%s ", !(op & SLJIT_32) ? "" : "32",
+ op1_types[GET_OPCODE(op) - SLJIT_OP1_BASE]);
+ sljit_verbose_reg(compiler, dst_reg);
+ fprintf(compiler->verbose, ", [");
+ sljit_verbose_reg(compiler, mem_reg);
+ fprintf(compiler->verbose, "]\n");
+ }
+#endif /* SLJIT_VERBOSE */
+ CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_atomic_store(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src_reg,
+ sljit_s32 mem_reg,
+ sljit_s32 temp_reg)
+{
+ if (SLJIT_UNLIKELY(compiler->skip_checks)) {
+ compiler->skip_checks = 0;
+ CHECK_RETURN_OK;
+ }
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_ATOMIC));
+ CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_MOV && GET_OPCODE(op) <= SLJIT_MOV_P);
+ CHECK_ARGUMENT(GET_OPCODE(op) != SLJIT_MOV_S8 && GET_OPCODE(op) != SLJIT_MOV_S16 && GET_OPCODE(op) != SLJIT_MOV_S32);
+
+ /* All arguments must be valid registers. */
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(src_reg));
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(mem_reg) && !CHECK_IF_VIRTUAL_REGISTER(mem_reg));
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(temp_reg) && src_reg != temp_reg);
+
+ CHECK_ARGUMENT(!(op & VARIABLE_FLAG_MASK) || GET_FLAG_TYPE(op) == SLJIT_ATOMIC_STORED);
+
+ if (GET_OPCODE(op) == SLJIT_MOV_U8 || GET_OPCODE(op) == SLJIT_MOV_U16) {
+ /* Only SLJIT_32, SLJIT_ATOMIC_STORED are allowed. */
+ CHECK_ARGUMENT(!(op & SLJIT_SET_Z));
+ } else {
+ /* Only SLJIT_ATOMIC_STORED is allowed. */
+ CHECK_ARGUMENT(!(op & (SLJIT_32 | SLJIT_SET_Z)));
+ }
+
+ compiler->last_flags = GET_FLAG_TYPE(op) | (op & SLJIT_32);
+#endif /* SLJIT_ARGUMENT_CHECKS */
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+ if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+ fprintf(compiler->verbose, " atomic_store%s%s%s ", !(op & SLJIT_32) ? "" : "32",
+ op1_types[GET_OPCODE(op) - SLJIT_OP1_BASE], !(op & VARIABLE_FLAG_MASK) ? "" : ".stored");
+ sljit_verbose_reg(compiler, src_reg);
+ fprintf(compiler->verbose, ", [");
+ sljit_verbose_reg(compiler, mem_reg);
+ fprintf(compiler->verbose, "], ");
+ sljit_verbose_reg(compiler, temp_reg);
+ fprintf(compiler->verbose, "\n");
+ }
+#endif /* SLJIT_VERBOSE */
+ CHECK_RETURN_OK;
+}
+
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 unset,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 src1, sljit_sw src1w,
@@ -1461,28 +1637,33 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op2(struct sljit_compiler
}
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 src_dst,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w)
+ sljit_s32 dst_reg,
+ sljit_s32 src1_reg,
+ sljit_s32 src2_reg,
+ sljit_s32 src3, sljit_sw src3w)
{
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
CHECK_ARGUMENT(GET_OPCODE(op) == SLJIT_SHL || GET_OPCODE(op) == SLJIT_LSHR
|| GET_OPCODE(op) == SLJIT_MSHL || GET_OPCODE(op) == SLJIT_MLSHR);
CHECK_ARGUMENT((op & ~(0xff | SLJIT_32 | SLJIT_SHIFT_INTO_NON_ZERO)) == 0);
- CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(src_dst));
- FUNCTION_CHECK_SRC(src1, src1w);
- FUNCTION_CHECK_SRC(src2, src2w);
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(dst_reg));
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(src1_reg));
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(src2_reg));
+ FUNCTION_CHECK_SRC(src3, src3w);
+ CHECK_ARGUMENT(dst_reg != src2_reg);
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
fprintf(compiler->verbose, " %s%s.into%s ", op2_names[GET_OPCODE(op) - SLJIT_OP2_BASE], !(op & SLJIT_32) ? "" : "32",
(op & SLJIT_SHIFT_INTO_NON_ZERO) ? ".nz" : "");
- sljit_verbose_reg(compiler, src_dst);
+ sljit_verbose_reg(compiler, dst_reg);
fprintf(compiler->verbose, ", ");
- sljit_verbose_param(compiler, src1, src1w);
+ sljit_verbose_reg(compiler, src1_reg);
fprintf(compiler->verbose, ", ");
- sljit_verbose_param(compiler, src2, src2w);
+ sljit_verbose_reg(compiler, src2_reg);
+ fprintf(compiler->verbose, ", ");
+ sljit_verbose_param(compiler, src3, src3w);
fprintf(compiler->verbose, "\n");
}
#endif
@@ -1496,19 +1677,16 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op_src(struct sljit_compi
CHECK_ARGUMENT(op >= SLJIT_FAST_RETURN && op <= SLJIT_PREFETCH_ONCE);
FUNCTION_CHECK_SRC(src, srcw);
- if (op == SLJIT_FAST_RETURN || op == SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN)
- {
+ if (op == SLJIT_FAST_RETURN || op == SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN) {
CHECK_ARGUMENT(src != SLJIT_IMM);
compiler->last_flags = 0;
- }
- else if (op >= SLJIT_PREFETCH_L1 && op <= SLJIT_PREFETCH_ONCE)
- {
+ } else if (op >= SLJIT_PREFETCH_L1 && op <= SLJIT_PREFETCH_ONCE) {
CHECK_ARGUMENT(src & SLJIT_MEM);
}
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
- fprintf(compiler->verbose, " %s ", op_src_names[op - SLJIT_OP_SRC_BASE]);
+ fprintf(compiler->verbose, " %s ", op_src_dst_names[op - SLJIT_OP_SRC_DST_BASE]);
sljit_verbose_param(compiler, src, srcw);
fprintf(compiler->verbose, "\n");
}
@@ -1516,20 +1694,39 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op_src(struct sljit_compi
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_register_index(sljit_s32 reg)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op_dst(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw)
{
- SLJIT_UNUSED_ARG(reg);
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- CHECK_ARGUMENT(reg > 0 && reg <= SLJIT_NUMBER_OF_REGISTERS);
+ CHECK_ARGUMENT(op >= SLJIT_FAST_ENTER && op <= SLJIT_GET_RETURN_ADDRESS);
+ FUNCTION_CHECK_DST(dst, dstw);
+
+ if (op == SLJIT_FAST_ENTER)
+ compiler->last_flags = 0;
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+ if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+ fprintf(compiler->verbose, " %s ", op_src_dst_names[op - SLJIT_OP_SRC_DST_BASE]);
+ sljit_verbose_param(compiler, dst, dstw);
+ fprintf(compiler->verbose, "\n");
+ }
#endif
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_float_register_index(sljit_s32 reg)
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_register_index(sljit_s32 type, sljit_s32 reg)
{
+ SLJIT_UNUSED_ARG(type);
SLJIT_UNUSED_ARG(reg);
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- CHECK_ARGUMENT(reg > 0 && reg <= SLJIT_NUMBER_OF_FLOAT_REGISTERS);
+ if (type == SLJIT_GP_REGISTER) {
+ CHECK_ARGUMENT((reg > 0 && reg <= SLJIT_NUMBER_OF_REGISTERS)
+ || (reg >= SLJIT_TMP_REGISTER_BASE && reg <= (SLJIT_TMP_REGISTER_BASE + SLJIT_NUMBER_OF_TEMPORARY_REGISTERS)));
+ } else {
+ CHECK_ARGUMENT(type == SLJIT_FLOAT_REGISTER || ((type >> 12) == 0 || ((type >> 12) >= 3 && (type >> 12) <= 6)));
+ CHECK_ARGUMENT((reg > 0 && reg <= SLJIT_NUMBER_OF_FLOAT_REGISTERS)
+ || (reg >= SLJIT_TMP_FREGISTER_BASE && reg <= (SLJIT_TMP_FREGISTER_BASE + SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS)));
+ }
#endif
CHECK_RETURN_OK;
}
@@ -1583,8 +1780,8 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1(struct sljit_compile
CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_MOV_F64 && GET_OPCODE(op) <= SLJIT_ABS_F64);
CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
- FUNCTION_FCHECK(src, srcw);
- FUNCTION_FCHECK(dst, dstw);
+ FUNCTION_FCHECK(src, srcw, op & SLJIT_32);
+ FUNCTION_FCHECK(dst, dstw, op & SLJIT_32);
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
@@ -1623,8 +1820,8 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1_cmp(struct sljit_com
CHECK_ARGUMENT(!(op & SLJIT_SET_Z));
CHECK_ARGUMENT((op & VARIABLE_FLAG_MASK)
|| (GET_FLAG_TYPE(op) >= SLJIT_F_EQUAL && GET_FLAG_TYPE(op) <= SLJIT_ORDERED_LESS_EQUAL));
- FUNCTION_FCHECK(src1, src1w);
- FUNCTION_FCHECK(src2, src2w);
+ FUNCTION_FCHECK(src1, src1w, op & SLJIT_32);
+ FUNCTION_FCHECK(src2, src2w, op & SLJIT_32);
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
@@ -1653,15 +1850,14 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1_conv_sw_from_f64(str
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
- CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_CONV_SW_FROM_F64 && GET_OPCODE(op) <= SLJIT_CONV_S32_FROM_F64);
CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
- FUNCTION_FCHECK(src, srcw);
+ FUNCTION_FCHECK(src, srcw, op & SLJIT_32);
FUNCTION_CHECK_DST(dst, dstw);
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
fprintf(compiler->verbose, " %s%s.from%s ", fop1_names[GET_OPCODE(op) - SLJIT_FOP1_BASE],
- (GET_OPCODE(op) == SLJIT_CONV_S32_FROM_F64) ? ".s32" : ".sw",
+ fop1_conv_types[GET_OPCODE(op) - SLJIT_CONV_SW_FROM_F64],
(op & SLJIT_32) ? ".f32" : ".f64");
sljit_verbose_param(compiler, dst, dstw);
fprintf(compiler->verbose, ", ");
@@ -1672,7 +1868,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1_conv_sw_from_f64(str
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1_conv_f64_from_w(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 src, sljit_sw srcw)
{
@@ -1683,16 +1879,15 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop1_conv_f64_from_sw(str
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
- CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_CONV_F64_FROM_SW && GET_OPCODE(op) <= SLJIT_CONV_F64_FROM_S32);
CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
FUNCTION_CHECK_SRC(src, srcw);
- FUNCTION_FCHECK(dst, dstw);
+ FUNCTION_FCHECK(dst, dstw, op & SLJIT_32);
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
- fprintf(compiler->verbose, " %s%s.from%s ", fop1_names[GET_OPCODE(op) - SLJIT_FOP1_BASE],
+ fprintf(compiler->verbose, " %s%s.from.%s ", fop1_names[GET_OPCODE(op) - SLJIT_FOP1_BASE],
(op & SLJIT_32) ? ".f32" : ".f64",
- (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) ? ".s32" : ".sw");
+ fop1_conv_types[GET_OPCODE(op) - SLJIT_CONV_SW_FROM_F64]);
sljit_verbose_fparam(compiler, dst, dstw);
fprintf(compiler->verbose, ", ");
sljit_verbose_param(compiler, src, srcw);
@@ -1707,13 +1902,18 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop2(struct sljit_compile
sljit_s32 src1, sljit_sw src1w,
sljit_s32 src2, sljit_sw src2w)
{
+ if (SLJIT_UNLIKELY(compiler->skip_checks)) {
+ compiler->skip_checks = 0;
+ CHECK_RETURN_OK;
+ }
+
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_ADD_F64 && GET_OPCODE(op) <= SLJIT_DIV_F64);
CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
- FUNCTION_FCHECK(src1, src1w);
- FUNCTION_FCHECK(src2, src2w);
- FUNCTION_FCHECK(dst, dstw);
+ FUNCTION_FCHECK(src1, src1w, op & SLJIT_32);
+ FUNCTION_FCHECK(src2, src2w, op & SLJIT_32);
+ FUNCTION_FCHECK(dst, dstw, op & SLJIT_32);
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
@@ -1729,6 +1929,138 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop2(struct sljit_compile
CHECK_RETURN_OK;
}
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fop2r(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_freg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
+ CHECK_ARGUMENT(GET_OPCODE(op) == SLJIT_COPYSIGN_F64);
+ FUNCTION_FCHECK(src1, src1w, op & SLJIT_32);
+ FUNCTION_FCHECK(src2, src2w, op & SLJIT_32);
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(dst_freg, op & SLJIT_32));
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+ if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+ fprintf(compiler->verbose, " %s%s ", fop2r_names[GET_OPCODE(op) - SLJIT_FOP2R_BASE], (op & SLJIT_32) ? ".f32" : ".f64");
+ sljit_verbose_freg(compiler, dst_freg);
+ fprintf(compiler->verbose, ", ");
+ sljit_verbose_fparam(compiler, src1, src1w);
+ fprintf(compiler->verbose, ", ");
+ sljit_verbose_fparam(compiler, src2, src2w);
+ fprintf(compiler->verbose, "\n");
+ }
+#endif
+ CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fset32(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f32 value)
+{
+ SLJIT_UNUSED_ARG(value);
+
+ if (SLJIT_UNLIKELY(compiler->skip_checks)) {
+ compiler->skip_checks = 0;
+ CHECK_RETURN_OK;
+ }
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(freg, 1));
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+ if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+ fprintf(compiler->verbose, " fset32 ");
+ sljit_verbose_freg(compiler, freg);
+ fprintf(compiler->verbose, ", %f\n", value);
+ }
+#endif
+ CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fset64(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f64 value)
+{
+ SLJIT_UNUSED_ARG(value);
+
+ if (SLJIT_UNLIKELY(compiler->skip_checks)) {
+ compiler->skip_checks = 0;
+ CHECK_RETURN_OK;
+ }
+
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(freg, 0));
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+ if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+ fprintf(compiler->verbose, " fset64 ");
+ sljit_verbose_freg(compiler, freg);
+ fprintf(compiler->verbose, ", %f\n", value);
+ }
+#endif
+ CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 freg, sljit_s32 reg)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
+ CHECK_ARGUMENT(GET_OPCODE(op) >= SLJIT_COPY_TO_F64 && GET_OPCODE(op) <= SLJIT_COPY_FROM_F64);
+ CHECK_ARGUMENT(!(op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)));
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(freg, op & SLJIT_32));
+
+#if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE)
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(reg));
+#else /* !SLJIT_64BIT_ARCHITECTURE */
+ switch (op) {
+ case SLJIT_COPY32_TO_F32:
+ case SLJIT_COPY32_FROM_F32:
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(reg));
+ break;
+ case SLJIT_COPY_TO_F64:
+ case SLJIT_COPY_FROM_F64:
+ if (reg & REG_PAIR_MASK) {
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(REG_PAIR_FIRST(reg)));
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(REG_PAIR_SECOND(reg)));
+
+ if (op == SLJIT_COPY_TO_F64)
+ break;
+
+ CHECK_ARGUMENT(REG_PAIR_FIRST(reg) != REG_PAIR_SECOND(reg));
+ break;
+ }
+
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(reg));
+ break;
+ }
+#endif /* SLJIT_64BIT_ARCHITECTURE */
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+ if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+ fprintf(compiler->verbose, " copy%s_%s_f%s ", (op & SLJIT_32) ? "32" : "",
+ GET_OPCODE(op) == SLJIT_COPY_TO_F64 ? "to" : "from", (op & SLJIT_32) ? "32" : "64");
+
+ sljit_verbose_freg(compiler, freg);
+
+ if (reg & REG_PAIR_MASK) {
+ fprintf(compiler->verbose, ", {");
+ sljit_verbose_reg(compiler, REG_PAIR_FIRST(reg));
+ fprintf(compiler->verbose, ", ");
+ sljit_verbose_reg(compiler, REG_PAIR_SECOND(reg));
+ fprintf(compiler->verbose, "}\n");
+ } else {
+ fprintf(compiler->verbose, ", ");
+ sljit_verbose_reg(compiler, reg);
+ fprintf(compiler->verbose, "\n");
+ }
+ }
+#endif
+ CHECK_RETURN_OK;
+}
+
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_label(struct sljit_compiler *compiler)
{
SLJIT_UNUSED_ARG(compiler);
@@ -1753,7 +2085,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_label(struct sljit_compil
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \
|| (defined SLJIT_CONFIG_ARM && SLJIT_CONFIG_ARM)
#define CHECK_UNORDERED(type, last_flags) \
- ((((type) & 0xff) == SLJIT_UNORDERED || ((type) & 0xff) == SLJIT_ORDERED) && \
+ ((((type) & 0xfe) == SLJIT_ORDERED) && \
((last_flags) & 0xff) >= SLJIT_UNORDERED && ((last_flags) & 0xff) <= SLJIT_ORDERED_LESS_EQUAL)
#else
#define CHECK_UNORDERED(type, last_flags) 0
@@ -1775,11 +2107,10 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_jump(struct sljit_compile
if ((type & 0xff) <= SLJIT_NOT_ZERO)
CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z);
else if ((compiler->last_flags & 0xff) == SLJIT_CARRY) {
- CHECK_ARGUMENT((type & 0xff) == SLJIT_CARRY || (type & 0xff) == SLJIT_NOT_CARRY);
+ CHECK_ARGUMENT((type & 0xfe) == SLJIT_CARRY);
compiler->last_flags = 0;
} else
- CHECK_ARGUMENT((type & 0xff) == (compiler->last_flags & 0xff)
- || ((type & 0xff) == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW)
+ CHECK_ARGUMENT((type & 0xfe) == (compiler->last_flags & 0xff)
|| CHECK_UNORDERED(type, compiler->last_flags));
}
#endif
@@ -1863,10 +2194,9 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fcmp(struct sljit_compile
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_REWRITABLE_JUMP | SLJIT_32)));
- CHECK_ARGUMENT((type & 0xff) >= SLJIT_F_EQUAL && (type & 0xff) <= SLJIT_ORDERED_LESS_EQUAL
- && ((type & 0xff) <= SLJIT_ORDERED || sljit_cmp_info(type & 0xff)));
- FUNCTION_FCHECK(src1, src1w);
- FUNCTION_FCHECK(src2, src2w);
+ CHECK_ARGUMENT((type & 0xff) >= SLJIT_F_EQUAL && (type & 0xff) <= SLJIT_ORDERED_LESS_EQUAL);
+ FUNCTION_FCHECK(src1, src1w, type & SLJIT_32);
+ FUNCTION_FCHECK(src2, src2w, type & SLJIT_32);
compiler->last_flags = 0;
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
@@ -1961,9 +2291,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op_flags(struct sljit_com
if (type <= SLJIT_NOT_ZERO)
CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z);
else
- CHECK_ARGUMENT(type == (compiler->last_flags & 0xff)
- || (type == SLJIT_NOT_CARRY && (compiler->last_flags & 0xff) == SLJIT_CARRY)
- || (type == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW)
+ CHECK_ARGUMENT((type & 0xfe) == (compiler->last_flags & 0xff)
|| CHECK_UNORDERED(type, compiler->last_flags));
FUNCTION_CHECK_DST(dst, dstw);
@@ -1975,7 +2303,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op_flags(struct sljit_com
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
fprintf(compiler->verbose, " flags.%s%s%s ",
GET_OPCODE(op) < SLJIT_OP2_BASE ? "mov" : op2_names[GET_OPCODE(op) - SLJIT_OP2_BASE],
- GET_OPCODE(op) < SLJIT_OP2_BASE ? op1_names[GET_OPCODE(op) - SLJIT_OP1_BASE] : ((op & SLJIT_32) ? "32" : ""),
+ GET_OPCODE(op) < SLJIT_OP2_BASE ? op1_types[GET_OPCODE(op) - SLJIT_OP1_BASE] : ((op & SLJIT_32) ? "32" : ""),
!(op & SLJIT_SET_Z) ? "" : ".z");
sljit_verbose_param(compiler, dst, dstw);
fprintf(compiler->verbose, ", %s\n", jump_names[type]);
@@ -1984,9 +2312,10 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_op_flags(struct sljit_com
CHECK_RETURN_OK;
}
-static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_select(struct sljit_compiler *compiler, sljit_s32 type,
sljit_s32 dst_reg,
- sljit_s32 src, sljit_sw srcw)
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_reg)
{
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
sljit_s32 cond = type & ~SLJIT_32;
@@ -1995,27 +2324,68 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_cmov(struct sljit_compile
CHECK_ARGUMENT(compiler->scratches != -1 && compiler->saveds != -1);
CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(dst_reg));
- if (src != SLJIT_IMM) {
- CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(src));
- CHECK_ARGUMENT(srcw == 0);
- }
+ FUNCTION_CHECK_SRC(src1, src1w);
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_REG(src2_reg));
if (cond <= SLJIT_NOT_ZERO)
CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z);
- else
- CHECK_ARGUMENT(cond == (compiler->last_flags & 0xff)
- || (cond == SLJIT_NOT_CARRY && (compiler->last_flags & 0xff) == SLJIT_CARRY)
- || (cond == SLJIT_NOT_OVERFLOW && (compiler->last_flags & 0xff) == SLJIT_OVERFLOW)
+ else if ((compiler->last_flags & 0xff) == SLJIT_CARRY) {
+ CHECK_ARGUMENT((type & 0xfe) == SLJIT_CARRY);
+ compiler->last_flags = 0;
+ } else
+ CHECK_ARGUMENT((cond & 0xfe) == (compiler->last_flags & 0xff)
|| CHECK_UNORDERED(cond, compiler->last_flags));
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
- fprintf(compiler->verbose, " cmov%s %s, ",
+ fprintf(compiler->verbose, " select%s %s, ",
!(type & SLJIT_32) ? "" : "32",
jump_names[type & ~SLJIT_32]);
sljit_verbose_reg(compiler, dst_reg);
fprintf(compiler->verbose, ", ");
- sljit_verbose_param(compiler, src, srcw);
+ sljit_verbose_param(compiler, src1, src1w);
+ fprintf(compiler->verbose, ", ");
+ sljit_verbose_reg(compiler, src2_reg);
+ fprintf(compiler->verbose, "\n");
+ }
+#endif
+ CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fselect(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_freg)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ sljit_s32 cond = type & ~SLJIT_32;
+
+ CHECK_ARGUMENT(cond >= SLJIT_EQUAL && cond <= SLJIT_ORDERED_LESS_EQUAL);
+
+ CHECK_ARGUMENT(compiler->fscratches != -1 && compiler->fsaveds != -1);
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(dst_freg, type & SLJIT_32));
+ FUNCTION_FCHECK(src1, src1w, type & SLJIT_32);
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(src2_freg, type & SLJIT_32));
+
+ if (cond <= SLJIT_NOT_ZERO)
+ CHECK_ARGUMENT(compiler->last_flags & SLJIT_SET_Z);
+ else if ((compiler->last_flags & 0xff) == SLJIT_CARRY) {
+ CHECK_ARGUMENT((type & 0xfe) == SLJIT_CARRY);
+ compiler->last_flags = 0;
+ } else
+ CHECK_ARGUMENT((cond & 0xfe) == (compiler->last_flags & 0xff)
+ || CHECK_UNORDERED(cond, compiler->last_flags));
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+ if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+ fprintf(compiler->verbose, " fselect%s %s, ",
+ !(type & SLJIT_32) ? "" : "32",
+ jump_names[type & ~SLJIT_32]);
+ sljit_verbose_freg(compiler, dst_freg);
+ fprintf(compiler->verbose, ", ");
+ sljit_verbose_fparam(compiler, src1, src1w);
+ fprintf(compiler->verbose, ", ");
+ sljit_verbose_freg(compiler, src2_freg);
fprintf(compiler->verbose, "\n");
}
#endif
@@ -2026,33 +2396,35 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_mem(struct sljit_compiler
sljit_s32 reg,
sljit_s32 mem, sljit_sw memw)
{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ sljit_s32 allowed_flags;
+#endif /* SLJIT_ARGUMENT_CHECKS */
+
if (SLJIT_UNLIKELY(compiler->skip_checks)) {
compiler->skip_checks = 0;
CHECK_RETURN_OK;
}
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
- sljit_s32 allowed_flags;
-
if (type & SLJIT_MEM_UNALIGNED) {
- CHECK_ARGUMENT(!(type & (SLJIT_MEM_UNALIGNED_16 | SLJIT_MEM_UNALIGNED_32)));
- } else if (type & SLJIT_MEM_UNALIGNED_16) {
- CHECK_ARGUMENT(!(type & SLJIT_MEM_UNALIGNED_32));
+ CHECK_ARGUMENT(!(type & (SLJIT_MEM_ALIGNED_16 | SLJIT_MEM_ALIGNED_32)));
+ } else if (type & SLJIT_MEM_ALIGNED_16) {
+ CHECK_ARGUMENT(!(type & SLJIT_MEM_ALIGNED_32));
} else {
- CHECK_ARGUMENT((reg & REG_PAIR_MASK) || (type & SLJIT_MEM_UNALIGNED_32));
+ CHECK_ARGUMENT((reg & REG_PAIR_MASK) || (type & SLJIT_MEM_ALIGNED_32));
}
allowed_flags = SLJIT_MEM_UNALIGNED;
switch (type & 0xff) {
+ case SLJIT_MOV_P:
+ case SLJIT_MOV:
+ allowed_flags |= SLJIT_MEM_ALIGNED_32;
+ /* fallthrough */
case SLJIT_MOV_U32:
case SLJIT_MOV_S32:
case SLJIT_MOV32:
- allowed_flags = SLJIT_MEM_UNALIGNED | SLJIT_MEM_UNALIGNED_16;
- break;
- case SLJIT_MOV:
- case SLJIT_MOV_P:
- allowed_flags = SLJIT_MEM_UNALIGNED | SLJIT_MEM_UNALIGNED_16 | SLJIT_MEM_UNALIGNED_32;
+ allowed_flags |= SLJIT_MEM_ALIGNED_16;
break;
}
@@ -2079,15 +2451,14 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_mem(struct sljit_compiler
else
fprintf(compiler->verbose, " %s%s%s",
(type & SLJIT_MEM_STORE) ? "store" : "load",
- !(type & SLJIT_32) ? "" : "32",
- op1_names[(type & 0xff) - SLJIT_OP1_BASE]);
+ !(type & SLJIT_32) ? "" : "32", op1_types[(type & 0xff) - SLJIT_OP1_BASE]);
if (type & SLJIT_MEM_UNALIGNED)
- printf(".un");
- else if (type & SLJIT_MEM_UNALIGNED_16)
- printf(".un16");
- else if (type & SLJIT_MEM_UNALIGNED_32)
- printf(".un32");
+ printf(".unal");
+ else if (type & SLJIT_MEM_ALIGNED_16)
+ printf(".al16");
+ else if (type & SLJIT_MEM_ALIGNED_32)
+ printf(".al32");
if (reg & REG_PAIR_MASK) {
fprintf(compiler->verbose, " {");
@@ -2140,7 +2511,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_mem_update(struct sljit_c
fprintf(compiler->verbose, " %s%s%s.%s ",
(type & SLJIT_MEM_STORE) ? "store" : "load",
!(type & SLJIT_32) ? "" : "32",
- op1_names[(type & 0xff) - SLJIT_OP1_BASE],
+ op1_types[(type & 0xff) - SLJIT_OP1_BASE],
(type & SLJIT_MEM_POST) ? "post" : "pre");
sljit_verbose_reg(compiler, reg);
@@ -2157,19 +2528,20 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fmem(struct sljit_compile
sljit_s32 mem, sljit_sw memw)
{
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
CHECK_ARGUMENT((type & 0xff) == SLJIT_MOV_F64);
if (type & SLJIT_MEM_UNALIGNED) {
- CHECK_ARGUMENT(!(type & (SLJIT_MEM_UNALIGNED_16 | SLJIT_MEM_UNALIGNED_32)));
- } else if (type & SLJIT_MEM_UNALIGNED_16) {
- CHECK_ARGUMENT(!(type & SLJIT_MEM_UNALIGNED_32));
+ CHECK_ARGUMENT(!(type & (SLJIT_MEM_ALIGNED_16 | SLJIT_MEM_ALIGNED_32)));
+ } else if (type & SLJIT_MEM_ALIGNED_16) {
+ CHECK_ARGUMENT(!(type & SLJIT_MEM_ALIGNED_32));
} else {
- CHECK_ARGUMENT(type & SLJIT_MEM_UNALIGNED_32);
+ CHECK_ARGUMENT(type & SLJIT_MEM_ALIGNED_32);
CHECK_ARGUMENT(!(type & SLJIT_32));
}
- CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_32 | SLJIT_MEM_STORE | SLJIT_MEM_UNALIGNED | SLJIT_MEM_UNALIGNED_16 | SLJIT_MEM_UNALIGNED_32)));
- CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(freg));
+ CHECK_ARGUMENT(!(type & ~(0xff | SLJIT_32 | SLJIT_MEM_STORE | SLJIT_MEM_UNALIGNED | SLJIT_MEM_ALIGNED_16 | SLJIT_MEM_ALIGNED_32)));
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(freg, type & SLJIT_32));
FUNCTION_CHECK_SRC_MEM(mem, memw);
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
@@ -2179,11 +2551,11 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fmem(struct sljit_compile
!(type & SLJIT_32) ? "f64" : "f32");
if (type & SLJIT_MEM_UNALIGNED)
- printf(".un");
- else if (type & SLJIT_MEM_UNALIGNED_16)
- printf(".un16");
- else if (type & SLJIT_MEM_UNALIGNED_32)
- printf(".un32");
+ printf(".unal");
+ else if (type & SLJIT_MEM_ALIGNED_16)
+ printf(".al16");
+ else if (type & SLJIT_MEM_ALIGNED_32)
+ printf(".al32");
fprintf(compiler->verbose, " ");
sljit_verbose_freg(compiler, freg);
@@ -2200,10 +2572,11 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fmem_update(struct sljit_
sljit_s32 mem, sljit_sw memw)
{
#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_FPU));
CHECK_ARGUMENT((type & 0xff) == SLJIT_MOV_F64);
CHECK_ARGUMENT((type & ~(0xff | SLJIT_32 | SLJIT_MEM_STORE | SLJIT_MEM_SUPP | SLJIT_MEM_POST)) == 0);
FUNCTION_CHECK_SRC_MEM(mem, memw);
- CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(freg));
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(freg, type & SLJIT_32));
#endif
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
if (SLJIT_UNLIKELY(!!compiler->verbose)) {
@@ -2226,7 +2599,297 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_fmem_update(struct sljit_
}
#endif
CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_simd_mov(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 srcdst, sljit_sw srcdstw)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_SIMD));
+ CHECK_ARGUMENT((type & SLJIT_SIMD_TYPE_MASK2(SLJIT_SIMD_STORE)) == 0);
+ CHECK_ARGUMENT(SLJIT_SIMD_CHECK_REG(type));
+ CHECK_ARGUMENT(SLJIT_SIMD_GET_ELEM_SIZE(type) <= SLJIT_SIMD_GET_REG_SIZE(type));
+ CHECK_ARGUMENT(SLJIT_SIMD_GET_ELEM2_SIZE(type) <= (srcdst & SLJIT_MEM) ? SLJIT_SIMD_GET_REG_SIZE(type) : 0);
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(freg, 0));
+ FUNCTION_FCHECK(srcdst, srcdstw, 0);
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+ if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+ if (type & SLJIT_SIMD_TEST)
+ CHECK_RETURN_OK;
+ if (sljit_emit_simd_mov(compiler, type | SLJIT_SIMD_TEST, freg, srcdst, srcdstw) == SLJIT_ERR_UNSUPPORTED) {
+ fprintf(compiler->verbose, " # simd_mem: unsupported form, no instructions are emitted\n");
+ CHECK_RETURN_OK;
+ }
+
+ fprintf(compiler->verbose, " simd_%s.%d.%s%d",
+ (type & SLJIT_SIMD_STORE) ? "store" : "load",
+ (8 << SLJIT_SIMD_GET_REG_SIZE(type)),
+ (type & SLJIT_SIMD_FLOAT) ? "f" : "",
+ (8 << SLJIT_SIMD_GET_ELEM_SIZE(type)));
+
+ if ((type & 0x3f000000) == SLJIT_SIMD_MEM_UNALIGNED)
+ fprintf(compiler->verbose, ".unal ");
+ else
+ fprintf(compiler->verbose, ".al%d ", (8 << SLJIT_SIMD_GET_ELEM2_SIZE(type)));
+
+ sljit_verbose_freg(compiler, freg);
+ fprintf(compiler->verbose, ", ");
+ sljit_verbose_fparam(compiler, srcdst, srcdstw);
+ fprintf(compiler->verbose, "\n");
+ }
+#endif
+ CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_simd_replicate(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_sw srcw)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_SIMD));
+ CHECK_ARGUMENT((type & SLJIT_SIMD_TYPE_MASK(0)) == 0);
+ CHECK_ARGUMENT(SLJIT_SIMD_CHECK_REG(type));
+ CHECK_ARGUMENT(SLJIT_SIMD_GET_ELEM_SIZE(type) < SLJIT_SIMD_GET_REG_SIZE(type));
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(freg, 0));
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ if (src == SLJIT_IMM) {
+ CHECK_ARGUMENT(srcw == 0);
+ } else {
+ FUNCTION_FCHECK(src, srcw, SLJIT_SIMD_GET_ELEM_SIZE(type) == 2);
+ }
+ } else if (src != SLJIT_IMM) {
+ FUNCTION_CHECK_DST(src, srcw);
+ }
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+ if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+ if (type & SLJIT_SIMD_TEST)
+ CHECK_RETURN_OK;
+ if (sljit_emit_simd_replicate(compiler, type | SLJIT_SIMD_TEST, freg, src, srcw) == SLJIT_ERR_UNSUPPORTED) {
+ fprintf(compiler->verbose, " # simd_dup: unsupported form, no instructions are emitted\n");
+ CHECK_RETURN_OK;
+ }
+
+ fprintf(compiler->verbose, " simd_replicate.%d.%s%d ",
+ (8 << SLJIT_SIMD_GET_REG_SIZE(type)),
+ (type & SLJIT_SIMD_FLOAT) ? "f" : "",
+ (8 << SLJIT_SIMD_GET_ELEM_SIZE(type)));
+
+ sljit_verbose_freg(compiler, freg);
+ fprintf(compiler->verbose, ", ");
+ if (type & SLJIT_SIMD_FLOAT)
+ sljit_verbose_fparam(compiler, src, srcw);
+ else
+ sljit_verbose_param(compiler, src, srcw);
+ fprintf(compiler->verbose, "\n");
+ }
+#endif
+ CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_simd_lane_mov(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg, sljit_s32 lane_index,
+ sljit_s32 srcdst, sljit_sw srcdstw)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_SIMD));
+ CHECK_ARGUMENT((type & SLJIT_SIMD_TYPE_MASK(SLJIT_SIMD_STORE | SLJIT_SIMD_LANE_ZERO | SLJIT_SIMD_LANE_SIGNED | SLJIT_32)) == 0);
+ CHECK_ARGUMENT((type & (SLJIT_SIMD_STORE | SLJIT_SIMD_LANE_ZERO)) != (SLJIT_SIMD_STORE | SLJIT_SIMD_LANE_ZERO));
+ CHECK_ARGUMENT((type & (SLJIT_SIMD_STORE | SLJIT_SIMD_LANE_SIGNED)) != SLJIT_SIMD_LANE_SIGNED);
+ CHECK_ARGUMENT(!(type & SLJIT_SIMD_FLOAT) || !(type & (SLJIT_SIMD_LANE_SIGNED | SLJIT_32)));
+ CHECK_ARGUMENT(SLJIT_SIMD_CHECK_REG(type));
+ CHECK_ARGUMENT(SLJIT_SIMD_GET_ELEM_SIZE(type) < SLJIT_SIMD_GET_REG_SIZE(type));
+ CHECK_ARGUMENT(!(type & SLJIT_32) || SLJIT_SIMD_GET_ELEM_SIZE(type) <= 2);
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(freg, 0));
+ CHECK_ARGUMENT(lane_index >= 0 && lane_index < (1 << (SLJIT_SIMD_GET_REG_SIZE(type) - SLJIT_SIMD_GET_ELEM_SIZE(type))));
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ FUNCTION_FCHECK(srcdst, srcdstw, SLJIT_SIMD_GET_ELEM_SIZE(type) == 2);
+ } else if ((type & SLJIT_SIMD_STORE) || srcdst != SLJIT_IMM) {
+ FUNCTION_CHECK_DST(srcdst, srcdstw);
+ }
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+ if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+ if (type & SLJIT_SIMD_TEST)
+ CHECK_RETURN_OK;
+ if (sljit_emit_simd_lane_mov(compiler, type | SLJIT_SIMD_TEST, freg, lane_index, srcdst, srcdstw) == SLJIT_ERR_UNSUPPORTED) {
+ fprintf(compiler->verbose, " # simd_move_lane: unsupported form, no instructions are emitted\n");
+ CHECK_RETURN_OK;
+ }
+
+ fprintf(compiler->verbose, " simd_%s_lane%s%s%s.%d.%s%d ",
+ (type & SLJIT_SIMD_STORE) ? "store" : "load",
+ (type & SLJIT_32) ? "32" : "",
+ (type & SLJIT_SIMD_LANE_ZERO) ? "_z" : "",
+ (type & SLJIT_SIMD_LANE_SIGNED) ? "_s" : "",
+ (8 << SLJIT_SIMD_GET_REG_SIZE(type)),
+ (type & SLJIT_SIMD_FLOAT) ? "f" : "",
+ (8 << SLJIT_SIMD_GET_ELEM_SIZE(type)));
+
+ sljit_verbose_freg(compiler, freg);
+ fprintf(compiler->verbose, "[%d], ", lane_index);
+ if (type & SLJIT_SIMD_FLOAT)
+ sljit_verbose_fparam(compiler, srcdst, srcdstw);
+ else
+ sljit_verbose_param(compiler, srcdst, srcdstw);
+ fprintf(compiler->verbose, "\n");
+ }
+#endif
+ CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_simd_lane_replicate(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_s32 src_lane_index)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_SIMD));
+ CHECK_ARGUMENT((type & SLJIT_SIMD_TYPE_MASK(0)) == 0);
+ CHECK_ARGUMENT(SLJIT_SIMD_CHECK_REG(type));
+ CHECK_ARGUMENT(SLJIT_SIMD_GET_ELEM_SIZE(type) < SLJIT_SIMD_GET_REG_SIZE(type));
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(freg, 0));
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(src, 0));
+ CHECK_ARGUMENT(src_lane_index >= 0 && src_lane_index < (1 << (SLJIT_SIMD_GET_REG_SIZE(type) - SLJIT_SIMD_GET_ELEM_SIZE(type))));
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+ if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+ if (type & SLJIT_SIMD_TEST)
+ CHECK_RETURN_OK;
+ if (sljit_emit_simd_lane_replicate(compiler, type | SLJIT_SIMD_TEST, freg, src, src_lane_index) == SLJIT_ERR_UNSUPPORTED) {
+ fprintf(compiler->verbose, " # simd_lane_replicate: unsupported form, no instructions are emitted\n");
+ CHECK_RETURN_OK;
+ }
+
+ fprintf(compiler->verbose, " simd_lane_replicate.%d.%s%d ",
+ (8 << SLJIT_SIMD_GET_REG_SIZE(type)),
+ (type & SLJIT_SIMD_FLOAT) ? "f" : "",
+ (8 << SLJIT_SIMD_GET_ELEM_SIZE(type)));
+
+ sljit_verbose_freg(compiler, freg);
+ fprintf(compiler->verbose, ", ");
+ sljit_verbose_freg(compiler, src);
+ fprintf(compiler->verbose, "[%d]\n", src_lane_index);
+ }
+#endif
+ CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_simd_extend(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_sw srcw)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_SIMD));
+ CHECK_ARGUMENT((type & SLJIT_SIMD_TYPE_MASK2(SLJIT_SIMD_EXTEND_SIGNED)) == 0);
+ CHECK_ARGUMENT((type & (SLJIT_SIMD_EXTEND_SIGNED | SLJIT_SIMD_FLOAT)) != (SLJIT_SIMD_EXTEND_SIGNED | SLJIT_SIMD_FLOAT));
+ CHECK_ARGUMENT(SLJIT_SIMD_CHECK_REG(type));
+ CHECK_ARGUMENT(SLJIT_SIMD_GET_ELEM2_SIZE(type) < SLJIT_SIMD_GET_REG_SIZE(type));
+ CHECK_ARGUMENT(SLJIT_SIMD_GET_ELEM_SIZE(type) < SLJIT_SIMD_GET_ELEM2_SIZE(type));
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(freg, 0));
+ FUNCTION_FCHECK(src, srcw, SLJIT_SIMD_GET_ELEM_SIZE(type) == 2);
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+ if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+ if (type & SLJIT_SIMD_TEST)
+ CHECK_RETURN_OK;
+ if (sljit_emit_simd_extend(compiler, type | SLJIT_SIMD_TEST, freg, src, srcw) == SLJIT_ERR_UNSUPPORTED) {
+ fprintf(compiler->verbose, " # simd_extend: unsupported form, no instructions are emitted\n");
+ CHECK_RETURN_OK;
+ }
+
+ fprintf(compiler->verbose, " simd_load_extend%s.%d.%s%d.%s%d ",
+ (type & SLJIT_SIMD_EXTEND_SIGNED) ? "_s" : "",
+ (8 << SLJIT_SIMD_GET_REG_SIZE(type)),
+ (type & SLJIT_SIMD_FLOAT) ? "f" : "",
+ (8 << SLJIT_SIMD_GET_ELEM2_SIZE(type)),
+ (type & SLJIT_SIMD_FLOAT) ? "f" : "",
+ (8 << SLJIT_SIMD_GET_ELEM_SIZE(type)));
+
+ sljit_verbose_freg(compiler, freg);
+ fprintf(compiler->verbose, ", ");
+ sljit_verbose_fparam(compiler, src, srcw);
+ fprintf(compiler->verbose, "\n");
+ }
+#endif
+ CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_simd_sign(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 dst, sljit_sw dstw)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_SIMD));
+ CHECK_ARGUMENT((type & SLJIT_SIMD_TYPE_MASK(SLJIT_32)) == SLJIT_SIMD_STORE);
+ CHECK_ARGUMENT(SLJIT_SIMD_CHECK_REG(type));
+ CHECK_ARGUMENT(SLJIT_SIMD_GET_ELEM_SIZE(type) < SLJIT_SIMD_GET_REG_SIZE(type));
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(freg, 0));
+ FUNCTION_CHECK_DST(dst, dstw);
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+ if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+ if (type & SLJIT_SIMD_TEST)
+ CHECK_RETURN_OK;
+ if (sljit_emit_simd_sign(compiler, type | SLJIT_SIMD_TEST, freg, dst, dstw) == SLJIT_ERR_UNSUPPORTED) {
+ fprintf(compiler->verbose, " # simd_sign: unsupported form, no instructions are emitted\n");
+ CHECK_RETURN_OK;
+ }
+
+ fprintf(compiler->verbose, " simd_store_sign%s.%d.%s%d ",
+ (type & SLJIT_32) ? "32" : "",
+ (8 << SLJIT_SIMD_GET_REG_SIZE(type)),
+ (type & SLJIT_SIMD_FLOAT) ? "f" : "",
+ (8 << SLJIT_SIMD_GET_ELEM_SIZE(type)));
+
+ sljit_verbose_freg(compiler, freg);
+ fprintf(compiler->verbose, ", ");
+ sljit_verbose_param(compiler, dst, dstw);
+ fprintf(compiler->verbose, "\n");
+ }
+#endif
+ CHECK_RETURN_OK;
+}
+
+static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_simd_op2(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg, sljit_s32 src1_freg, sljit_s32 src2_freg)
+{
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+ CHECK_ARGUMENT(sljit_has_cpu_feature(SLJIT_HAS_SIMD));
+ CHECK_ARGUMENT((type & SLJIT_SIMD_TYPE_MASK(0)) >= SLJIT_SIMD_OP2_AND && (type & SLJIT_SIMD_TYPE_MASK(0)) <= SLJIT_SIMD_OP2_XOR);
+ CHECK_ARGUMENT(SLJIT_SIMD_CHECK_REG(type));
+ CHECK_ARGUMENT(SLJIT_SIMD_GET_ELEM_SIZE(type) <= SLJIT_SIMD_GET_REG_SIZE(type));
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(dst_freg, 0));
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(src1_freg, 0));
+ CHECK_ARGUMENT(FUNCTION_CHECK_IS_FREG(src2_freg, 0));
+#endif
+#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
+ if (SLJIT_UNLIKELY(!!compiler->verbose)) {
+ if (type & SLJIT_SIMD_TEST)
+ CHECK_RETURN_OK;
+ if (sljit_emit_simd_op2(compiler, type | SLJIT_SIMD_TEST, dst_freg, src1_freg, src2_freg) == SLJIT_ERR_UNSUPPORTED) {
+ fprintf(compiler->verbose, " # simd_op2: unsupported form, no instructions are emitted\n");
+ CHECK_RETURN_OK;
+ }
+ fprintf(compiler->verbose, " simd_%s.%d.%s%d ",
+ simd_op2_names[SLJIT_SIMD_GET_OPCODE(type) - 1],
+ (8 << SLJIT_SIMD_GET_REG_SIZE(type)),
+ (type & SLJIT_SIMD_FLOAT) ? "f" : "",
+ (8 << SLJIT_SIMD_GET_ELEM_SIZE(type)));
+
+ sljit_verbose_freg(compiler, dst_freg);
+ fprintf(compiler->verbose, ", ");
+ sljit_verbose_freg(compiler, src1_freg);
+ fprintf(compiler->verbose, ", ");
+ sljit_verbose_freg(compiler, src2_freg);
+ fprintf(compiler->verbose, "\n");
+ }
+#endif
+ CHECK_RETURN_OK;
}
static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset)
@@ -2286,7 +2949,7 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_put_label(struct sljit_co
#endif /* SLJIT_ARGUMENT_CHECKS || SLJIT_VERBOSE */
#define SELECT_FOP1_OPERATION_WITH_CHECKS(compiler, op, dst, dstw, src, srcw) \
- SLJIT_COMPILE_ASSERT(!(SLJIT_CONV_SW_FROM_F64 & 0x1) && !(SLJIT_CONV_F64_FROM_SW & 0x1), \
+ SLJIT_COMPILE_ASSERT(!(SLJIT_CONV_SW_FROM_F64 & 0x1) && !(SLJIT_CONV_F64_FROM_SW & 0x1) && !(SLJIT_CONV_F64_FROM_UW & 0x1), \
invalid_float_opcodes); \
if (GET_OPCODE(op) >= SLJIT_CONV_SW_FROM_F64 && GET_OPCODE(op) <= SLJIT_CMP_F64) { \
if (GET_OPCODE(op) == SLJIT_CMP_F64) { \
@@ -2301,48 +2964,22 @@ static SLJIT_INLINE CHECK_RETURN_TYPE check_sljit_emit_put_label(struct sljit_co
ADJUST_LOCAL_OFFSET(src, srcw); \
return sljit_emit_fop1_conv_sw_from_f64(compiler, op, dst, dstw, src, srcw); \
} \
- CHECK(check_sljit_emit_fop1_conv_f64_from_sw(compiler, op, dst, dstw, src, srcw)); \
+ if ((GET_OPCODE(op) | 0x1) == SLJIT_CONV_F64_FROM_S32) { \
+ CHECK(check_sljit_emit_fop1_conv_f64_from_w(compiler, op, dst, dstw, src, srcw)); \
+ ADJUST_LOCAL_OFFSET(dst, dstw); \
+ ADJUST_LOCAL_OFFSET(src, srcw); \
+ return sljit_emit_fop1_conv_f64_from_sw(compiler, op, dst, dstw, src, srcw); \
+ } \
+ CHECK(check_sljit_emit_fop1_conv_f64_from_w(compiler, op, dst, dstw, src, srcw)); \
ADJUST_LOCAL_OFFSET(dst, dstw); \
ADJUST_LOCAL_OFFSET(src, srcw); \
- return sljit_emit_fop1_conv_f64_from_sw(compiler, op, dst, dstw, src, srcw); \
+ return sljit_emit_fop1_conv_f64_from_uw(compiler, op, dst, dstw, src, srcw); \
} \
CHECK(check_sljit_emit_fop1(compiler, op, dst, dstw, src, srcw)); \
ADJUST_LOCAL_OFFSET(dst, dstw); \
ADJUST_LOCAL_OFFSET(src, srcw);
-#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \
- || (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC) \
- || ((defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) && !(defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1 && SLJIT_MIPS_REV < 6)) \
- || (defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV) \
- || (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
-
-static SLJIT_INLINE sljit_s32 sljit_emit_cmov_generic(struct sljit_compiler *compiler, sljit_s32 type,
- sljit_s32 dst_reg,
- sljit_s32 src, sljit_sw srcw)
-{
- struct sljit_label *label;
- struct sljit_jump *jump;
- sljit_s32 op = (type & SLJIT_32) ? SLJIT_MOV32 : SLJIT_MOV;
-
- SLJIT_SKIP_CHECKS(compiler);
- jump = sljit_emit_jump(compiler, (type & ~SLJIT_32) ^ 0x1);
- FAIL_IF(!jump);
-
- SLJIT_SKIP_CHECKS(compiler);
- FAIL_IF(sljit_emit_op1(compiler, op, dst_reg, 0, src, srcw));
-
- SLJIT_SKIP_CHECKS(compiler);
- label = sljit_emit_label(compiler);
- FAIL_IF(!label);
-
- sljit_set_label(jump, label);
- return SLJIT_SUCCESS;
-}
-
-#endif
-
-#if (!(defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) || (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)) \
- && !(defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (!(defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) || (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6))
static sljit_s32 sljit_emit_mem_unaligned(struct sljit_compiler *compiler, sljit_s32 type,
sljit_s32 reg,
@@ -2355,7 +2992,7 @@ static sljit_s32 sljit_emit_mem_unaligned(struct sljit_compiler *compiler, sljit
return sljit_emit_op1(compiler, type & (0xff | SLJIT_32), reg, 0, mem, memw);
}
-#endif /* (!SLJIT_CONFIG_MIPS || SLJIT_MIPS_REV >= 6) && !SLJIT_CONFIG_ARM_V5 */
+#endif /* (!SLJIT_CONFIG_MIPS || SLJIT_MIPS_REV >= 6) */
#if (!(defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) || (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)) \
&& !(defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32)
@@ -2401,7 +3038,7 @@ static sljit_s32 sljit_emit_fmem_unaligned(struct sljit_compiler *compiler, slji
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
# include "sljitNativeX86_common.c"
-#elif (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#elif (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
# include "sljitNativeARM_32.c"
#elif (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
# include "sljitNativeARM_32.c"
@@ -2417,6 +3054,8 @@ static sljit_s32 sljit_emit_fmem_unaligned(struct sljit_compiler *compiler, slji
# include "sljitNativeRISCV_common.c"
#elif (defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
# include "sljitNativeS390X.c"
+#elif (defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH)
+# include "sljitNativeLOONGARCH_64.c"
#endif
static SLJIT_INLINE sljit_s32 emit_mov_before_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
@@ -2463,8 +3102,29 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *comp
return sljit_emit_return_void(compiler);
}
+#if !(defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \
+ && !(defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X) \
+ && !(defined(SLJIT_CONFIG_LOONGARCH_64) && SLJIT_CONFIG_LOONGARCH_64)
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2r(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_freg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fop2r(compiler, op, dst_freg, src1, src1w, src2, src2w));
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+ ADJUST_LOCAL_OFFSET(src2, src2w);
+
+ SLJIT_SKIP_CHECKS(compiler);
+ return sljit_emit_fop2(compiler, op, dst_freg, 0, src1, src1w, src2, src2w);
+}
+
+#endif /* !SLJIT_CONFIG_X86 && !SLJIT_CONFIG_S390X && !SLJIT_CONFIG_LOONGARCH_64 */
+
#if !(defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS) \
- && !(defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV)
+ && !(defined SLJIT_CONFIG_RISCV && SLJIT_CONFIG_RISCV) \
+ && !(defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH)
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_s32 type,
sljit_s32 src1, sljit_sw src1w,
@@ -2480,18 +3140,18 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler
condition = type & 0xff;
#if (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
if ((condition == SLJIT_EQUAL || condition == SLJIT_NOT_EQUAL)) {
- if ((src1 & SLJIT_IMM) && !src1w) {
+ if (src1 == SLJIT_IMM && !src1w) {
src1 = src2;
src1w = src2w;
src2 = SLJIT_IMM;
src2w = 0;
}
- if ((src2 & SLJIT_IMM) && !src2w)
+ if (src2 == SLJIT_IMM && !src2w)
return emit_cmp_to0(compiler, type, src1, src1w);
}
#endif
- if (SLJIT_UNLIKELY((src1 & SLJIT_IMM) && !(src2 & SLJIT_IMM))) {
+ if (SLJIT_UNLIKELY(src1 == SLJIT_IMM && src2 != SLJIT_IMM)) {
/* Immediate is preferred as second argument by most architectures. */
switch (condition) {
case SLJIT_LESS:
@@ -2532,7 +3192,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler
if (condition <= SLJIT_NOT_ZERO)
flags = SLJIT_SET_Z;
else
- flags = condition << VARIABLE_FLAG_SHIFT;
+ flags = (condition & 0xfe) << VARIABLE_FLAG_SHIFT;
SLJIT_SKIP_CHECKS(compiler);
PTR_FAIL_IF(sljit_emit_op2u(compiler,
@@ -2544,20 +3204,17 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler
#endif /* !SLJIT_CONFIG_MIPS */
-#if (defined SLJIT_CONFIG_ARM && SLJIT_CONFIG_ARM)
+#if (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32)
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type)
{
- if (type < SLJIT_UNORDERED || type > SLJIT_ORDERED_LESS_EQUAL)
- return 0;
-
switch (type) {
case SLJIT_UNORDERED_OR_EQUAL:
case SLJIT_ORDERED_NOT_EQUAL:
- return 0;
+ return 1;
}
- return 1;
+ return 0;
}
#endif /* SLJIT_CONFIG_ARM */
@@ -2570,7 +3227,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compile
CHECK_PTR(check_sljit_emit_fcmp(compiler, type, src1, src1w, src2, src2w));
SLJIT_SKIP_CHECKS(compiler);
- sljit_emit_fop1(compiler, SLJIT_CMP_F64 | ((type & 0xff) << VARIABLE_FLAG_SHIFT) | (type & SLJIT_32), src1, src1w, src2, src2w);
+ sljit_emit_fop1(compiler, SLJIT_CMP_F64 | ((type & 0xfe) << VARIABLE_FLAG_SHIFT) | (type & SLJIT_32), src1, src1w, src2, src2w);
SLJIT_SKIP_CHECKS(compiler);
return sljit_emit_jump(compiler, type);
@@ -2630,507 +3287,174 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem_update(struct sljit_compiler
#endif /* !SLJIT_CONFIG_ARM_64 && !SLJIT_CONFIG_PPC */
#if !(defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \
- && !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
+ && !(defined SLJIT_CONFIG_ARM && SLJIT_CONFIG_ARM) \
+ && !(defined SLJIT_CONFIG_S390X && SLJIT_CONFIG_S390X)
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_mov(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 srcdst, sljit_sw srcdstw)
{
CHECK_ERROR();
- CHECK(check_sljit_get_local_base(compiler, dst, dstw, offset));
-
- ADJUST_LOCAL_OFFSET(SLJIT_MEM1(SLJIT_SP), offset);
-
- SLJIT_SKIP_CHECKS(compiler);
-
- if (offset != 0)
- return sljit_emit_op2(compiler, SLJIT_ADD, dst, dstw, SLJIT_SP, 0, SLJIT_IMM, offset);
- return sljit_emit_op1(compiler, SLJIT_MOV, dst, dstw, SLJIT_SP, 0);
-}
-
-#endif
-
-#else /* SLJIT_CONFIG_UNSUPPORTED */
-
-/* Empty function bodies for those machines, which are not (yet) supported. */
-
-SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
-{
- return "unsupported";
-}
-
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_compiler* sljit_create_compiler(void *allocator_data, void *exec_allocator_data)
-{
- SLJIT_UNUSED_ARG(allocator_data);
- SLJIT_UNUSED_ARG(exec_allocator_data);
- SLJIT_UNREACHABLE();
- return NULL;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE void sljit_free_compiler(struct sljit_compiler *compiler)
-{
+ CHECK(check_sljit_emit_simd_mov(compiler, type, freg, srcdst, srcdstw));
SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNREACHABLE();
-}
-
-SLJIT_API_FUNC_ATTRIBUTE void sljit_set_compiler_memory_error(struct sljit_compiler *compiler)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNREACHABLE();
-}
-
-SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, sljit_s32 size)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(size);
- SLJIT_UNREACHABLE();
- return NULL;
-}
-
-#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
-SLJIT_API_FUNC_ATTRIBUTE void sljit_compiler_verbose(struct sljit_compiler *compiler, FILE* verbose)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(verbose);
- SLJIT_UNREACHABLE();
-}
-#endif
-
-SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNREACHABLE();
- return NULL;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
-{
- SLJIT_UNUSED_ARG(feature_type);
- SLJIT_UNREACHABLE();
- return 0;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type)
-{
SLJIT_UNUSED_ARG(type);
- SLJIT_UNREACHABLE();
- return 0;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code, void *exec_allocator_data)
-{
- SLJIT_UNUSED_ARG(code);
- SLJIT_UNUSED_ARG(exec_allocator_data);
- SLJIT_UNREACHABLE();
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
- sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
- sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(options);
- SLJIT_UNUSED_ARG(arg_types);
- SLJIT_UNUSED_ARG(scratches);
- SLJIT_UNUSED_ARG(saveds);
- SLJIT_UNUSED_ARG(fscratches);
- SLJIT_UNUSED_ARG(fsaveds);
- SLJIT_UNUSED_ARG(local_size);
- SLJIT_UNREACHABLE();
- return SLJIT_ERR_UNSUPPORTED;
-}
+ SLJIT_UNUSED_ARG(freg);
+ SLJIT_UNUSED_ARG(srcdst);
+ SLJIT_UNUSED_ARG(srcdstw);
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *compiler,
- sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
- sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(options);
- SLJIT_UNUSED_ARG(arg_types);
- SLJIT_UNUSED_ARG(scratches);
- SLJIT_UNUSED_ARG(saveds);
- SLJIT_UNUSED_ARG(fscratches);
- SLJIT_UNUSED_ARG(fsaveds);
- SLJIT_UNUSED_ARG(local_size);
- SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNREACHABLE();
- return SLJIT_ERR_UNSUPPORTED;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_sw srcw)
{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_replicate(compiler, type, freg, src, srcw));
SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(op);
+ SLJIT_UNUSED_ARG(type);
+ SLJIT_UNUSED_ARG(freg);
SLJIT_UNUSED_ARG(src);
SLJIT_UNUSED_ARG(srcw);
- SLJIT_UNREACHABLE();
- return SLJIT_ERR_UNSUPPORTED;
-}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler, sljit_s32 src, sljit_sw srcw)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(src);
- SLJIT_UNUSED_ARG(srcw);
- SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg, sljit_s32 lane_index,
+ sljit_s32 srcdst, sljit_sw srcdstw)
{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_lane_mov(compiler, type, freg, lane_index, srcdst, srcdstw));
SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(dst);
- SLJIT_UNUSED_ARG(dstw);
- SLJIT_UNREACHABLE();
- return SLJIT_ERR_UNSUPPORTED;
-}
+ SLJIT_UNUSED_ARG(type);
+ SLJIT_UNUSED_ARG(freg);
+ SLJIT_UNUSED_ARG(lane_index);
+ SLJIT_UNUSED_ARG(srcdst);
+ SLJIT_UNUSED_ARG(srcdstw);
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(op);
- SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 dst, sljit_sw dstw,
- sljit_s32 src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_s32 src_lane_index)
{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_lane_replicate(compiler, type, freg, src, src_lane_index));
SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(op);
- SLJIT_UNUSED_ARG(dst);
- SLJIT_UNUSED_ARG(dstw);
+ SLJIT_UNUSED_ARG(type);
+ SLJIT_UNUSED_ARG(freg);
SLJIT_UNUSED_ARG(src);
- SLJIT_UNUSED_ARG(srcw);
- SLJIT_UNREACHABLE();
- return SLJIT_ERR_UNSUPPORTED;
-}
+ SLJIT_UNUSED_ARG(src_lane_index);
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 dst, sljit_sw dstw,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(op);
- SLJIT_UNUSED_ARG(dst);
- SLJIT_UNUSED_ARG(dstw);
- SLJIT_UNUSED_ARG(src1);
- SLJIT_UNUSED_ARG(src1w);
- SLJIT_UNUSED_ARG(src2);
- SLJIT_UNUSED_ARG(src2w);
- SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(op);
- SLJIT_UNUSED_ARG(src1);
- SLJIT_UNUSED_ARG(src1w);
- SLJIT_UNUSED_ARG(src2);
- SLJIT_UNUSED_ARG(src2w);
- SLJIT_UNREACHABLE();
- return SLJIT_ERR_UNSUPPORTED;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 src_dst,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(op);
- SLJIT_UNUSED_ARG(src_dst);
- SLJIT_UNUSED_ARG(src1);
- SLJIT_UNUSED_ARG(src1w);
- SLJIT_UNUSED_ARG(src2);
- SLJIT_UNUSED_ARG(src2w);
- SLJIT_UNREACHABLE();
- return SLJIT_ERR_UNSUPPORTED;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_extend(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
sljit_s32 src, sljit_sw srcw)
{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_extend(compiler, type, freg, src, srcw));
SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(op);
+ SLJIT_UNUSED_ARG(type);
+ SLJIT_UNUSED_ARG(freg);
SLJIT_UNUSED_ARG(src);
SLJIT_UNUSED_ARG(srcw);
- SLJIT_UNREACHABLE();
- return SLJIT_ERR_UNSUPPORTED;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
-{
- SLJIT_UNREACHABLE();
- return reg;
-}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
- void *instruction, sljit_u32 size)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(instruction);
- SLJIT_UNUSED_ARG(size);
- SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *compiler, sljit_s32 current_flags)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(current_flags);
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 dst, sljit_sw dstw,
- sljit_s32 src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 dst, sljit_sw dstw)
{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_sign(compiler, type, freg, dst, dstw));
SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(op);
+ SLJIT_UNUSED_ARG(type);
+ SLJIT_UNUSED_ARG(freg);
SLJIT_UNUSED_ARG(dst);
SLJIT_UNUSED_ARG(dstw);
- SLJIT_UNUSED_ARG(src);
- SLJIT_UNUSED_ARG(srcw);
- SLJIT_UNREACHABLE();
- return SLJIT_ERR_UNSUPPORTED;
-}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 dst, sljit_sw dstw,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(op);
- SLJIT_UNUSED_ARG(dst);
- SLJIT_UNUSED_ARG(dstw);
- SLJIT_UNUSED_ARG(src1);
- SLJIT_UNUSED_ARG(src1w);
- SLJIT_UNUSED_ARG(src2);
- SLJIT_UNUSED_ARG(src2w);
- SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNREACHABLE();
- return NULL;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(type);
- SLJIT_UNREACHABLE();
- return NULL;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
- sljit_s32 arg_types)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(type);
- SLJIT_UNUSED_ARG(arg_types);
- SLJIT_UNREACHABLE();
- return NULL;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler *compiler, sljit_s32 type,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(type);
- SLJIT_UNUSED_ARG(src1);
- SLJIT_UNUSED_ARG(src1w);
- SLJIT_UNUSED_ARG(src2);
- SLJIT_UNUSED_ARG(src2w);
- SLJIT_UNREACHABLE();
- return NULL;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_fcmp(struct sljit_compiler *compiler, sljit_s32 type,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_op2(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg, sljit_s32 src1_freg, sljit_s32 src2_freg)
{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_op2(compiler, type, dst_freg, src1_freg, src2_freg));
SLJIT_UNUSED_ARG(compiler);
SLJIT_UNUSED_ARG(type);
- SLJIT_UNUSED_ARG(src1);
- SLJIT_UNUSED_ARG(src1w);
- SLJIT_UNUSED_ARG(src2);
- SLJIT_UNUSED_ARG(src2w);
- SLJIT_UNREACHABLE();
- return NULL;
-}
-
-SLJIT_API_FUNC_ATTRIBUTE void sljit_set_label(struct sljit_jump *jump, struct sljit_label* label)
-{
- SLJIT_UNUSED_ARG(jump);
- SLJIT_UNUSED_ARG(label);
- SLJIT_UNREACHABLE();
-}
-
-SLJIT_API_FUNC_ATTRIBUTE void sljit_set_target(struct sljit_jump *jump, sljit_uw target)
-{
- SLJIT_UNUSED_ARG(jump);
- SLJIT_UNUSED_ARG(target);
- SLJIT_UNREACHABLE();
-}
+ SLJIT_UNUSED_ARG(dst_freg);
+ SLJIT_UNUSED_ARG(src1_freg);
+ SLJIT_UNUSED_ARG(src2_freg);
-SLJIT_API_FUNC_ATTRIBUTE void sljit_set_put_label(struct sljit_put_label *put_label, struct sljit_label *label)
-{
- SLJIT_UNUSED_ARG(put_label);
- SLJIT_UNUSED_ARG(label);
- SLJIT_UNREACHABLE();
-}
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(type);
- SLJIT_UNUSED_ARG(src);
- SLJIT_UNUSED_ARG(srcw);
- SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compiler, sljit_s32 type,
- sljit_s32 arg_types,
- sljit_s32 src, sljit_sw srcw)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(type);
- SLJIT_UNUSED_ARG(arg_types);
- SLJIT_UNUSED_ARG(src);
- SLJIT_UNUSED_ARG(srcw);
- SLJIT_UNREACHABLE();
- return SLJIT_ERR_UNSUPPORTED;
-}
+#endif /* !SLJIT_CONFIG_X86 && !SLJIT_CONFIG_ARM */
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 dst, sljit_sw dstw,
- sljit_s32 type)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(op);
- SLJIT_UNUSED_ARG(dst);
- SLJIT_UNUSED_ARG(dstw);
- SLJIT_UNUSED_ARG(type);
- SLJIT_UNREACHABLE();
- return SLJIT_ERR_UNSUPPORTED;
-}
+#if !(defined(SLJIT_CONFIG_X86) && SLJIT_CONFIG_X86) \
+ && !(defined(SLJIT_CONFIG_ARM) && SLJIT_CONFIG_ARM) \
+ && !(defined(SLJIT_CONFIG_S390X) && SLJIT_CONFIG_S390X) \
+ && !(defined(SLJIT_CONFIG_LOONGARCH) && SLJIT_CONFIG_LOONGARCH)
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_load(struct sljit_compiler *compiler,
+ sljit_s32 op,
sljit_s32 dst_reg,
- sljit_s32 src, sljit_sw srcw)
+ sljit_s32 mem_reg)
{
SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(type);
+ SLJIT_UNUSED_ARG(op);
SLJIT_UNUSED_ARG(dst_reg);
- SLJIT_UNUSED_ARG(src);
- SLJIT_UNUSED_ARG(srcw);
- SLJIT_UNREACHABLE();
- return SLJIT_ERR_UNSUPPORTED;
-}
+ SLJIT_UNUSED_ARG(mem_reg);
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 reg, sljit_s32 mem, sljit_sw memw)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(type);
- SLJIT_UNUSED_ARG(reg);
- SLJIT_UNUSED_ARG(mem);
- SLJIT_UNUSED_ARG(memw);
- SLJIT_UNREACHABLE();
- return SLJIT_ERR_UNSUPPORTED;
-}
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_atomic_load(compiler, op, dst_reg, mem_reg));
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem_update(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 reg, sljit_s32 mem, sljit_sw memw)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(type);
- SLJIT_UNUSED_ARG(reg);
- SLJIT_UNUSED_ARG(mem);
- SLJIT_UNUSED_ARG(memw);
- SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 freg, sljit_s32 mem, sljit_sw memw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler *compiler,
+ sljit_s32 op,
+ sljit_s32 src_reg,
+ sljit_s32 mem_reg,
+ sljit_s32 temp_reg)
{
SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(type);
- SLJIT_UNUSED_ARG(freg);
- SLJIT_UNUSED_ARG(mem);
- SLJIT_UNUSED_ARG(memw);
- SLJIT_UNREACHABLE();
- return SLJIT_ERR_UNSUPPORTED;
-}
+ SLJIT_UNUSED_ARG(op);
+ SLJIT_UNUSED_ARG(src_reg);
+ SLJIT_UNUSED_ARG(mem_reg);
+ SLJIT_UNUSED_ARG(temp_reg);
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_atomic_store(compiler, op, src_reg, mem_reg, temp_reg));
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem_update(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 freg, sljit_s32 mem, sljit_sw memw)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(type);
- SLJIT_UNUSED_ARG(freg);
- SLJIT_UNUSED_ARG(mem);
- SLJIT_UNUSED_ARG(memw);
- SLJIT_UNREACHABLE();
return SLJIT_ERR_UNSUPPORTED;
}
+#endif /* !SLJIT_CONFIG_X86 && !SLJIT_CONFIG_ARM && !SLJIT_CONFIG_S390X && !SLJIT_CONFIG_LOONGARCH */
+
+#if !(defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) \
+ && !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
+
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset)
{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(dst);
- SLJIT_UNUSED_ARG(dstw);
- SLJIT_UNUSED_ARG(offset);
- SLJIT_UNREACHABLE();
- return SLJIT_ERR_UNSUPPORTED;
-}
+ CHECK_ERROR();
+ CHECK(check_sljit_get_local_base(compiler, dst, dstw, offset));
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw initval)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(dst);
- SLJIT_UNUSED_ARG(dstw);
- SLJIT_UNUSED_ARG(initval);
- SLJIT_UNREACHABLE();
- return NULL;
-}
+ ADJUST_LOCAL_OFFSET(SLJIT_MEM1(SLJIT_SP), offset);
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
-{
- SLJIT_UNUSED_ARG(compiler);
- SLJIT_UNUSED_ARG(dst);
- SLJIT_UNUSED_ARG(dstw);
- return NULL;
-}
+ SLJIT_SKIP_CHECKS(compiler);
-SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
-{
- SLJIT_UNUSED_ARG(addr);
- SLJIT_UNUSED_ARG(new_target);
- SLJIT_UNUSED_ARG(executable_offset);
- SLJIT_UNREACHABLE();
+ if (offset != 0)
+ return sljit_emit_op2(compiler, SLJIT_ADD, dst, dstw, SLJIT_SP, 0, SLJIT_IMM, offset);
+ return sljit_emit_op1(compiler, SLJIT_MOV, dst, dstw, SLJIT_SP, 0);
}
-SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant, sljit_sw executable_offset)
-{
- SLJIT_UNUSED_ARG(addr);
- SLJIT_UNUSED_ARG(new_constant);
- SLJIT_UNUSED_ARG(executable_offset);
- SLJIT_UNREACHABLE();
-}
+#endif /* !SLJIT_CONFIG_X86 && !SLJIT_CONFIG_ARM_64 */
#endif /* !SLJIT_CONFIG_UNSUPPORTED */
diff --git a/src/3rdparty/pcre2/src/sljit/sljitLir.h b/src/3rdparty/pcre2/src/sljit/sljitLir.h
index c6a0832ef8..2ba6683c74 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitLir.h
+++ b/src/3rdparty/pcre2/src/sljit/sljitLir.h
@@ -72,6 +72,7 @@
#include "sljitConfigPre.h"
#endif /* SLJIT_HAVE_CONFIG_PRE */
+#include "sljitConfigCPU.h"
#include "sljitConfig.h"
/* The following header file defines useful macros for fine tuning
@@ -107,9 +108,9 @@ extern "C" {
/* Cannot allocate executable memory.
Only sljit_generate_code() returns with this error code. */
#define SLJIT_ERR_EX_ALLOC_FAILED 3
-/* Return value for SLJIT_CONFIG_UNSUPPORTED placeholder architecture. */
+/* Unsupported instruction form. */
#define SLJIT_ERR_UNSUPPORTED 4
-/* An ivalid argument is passed to any SLJIT function. */
+/* An invalid argument is passed to any SLJIT function. */
#define SLJIT_ERR_BAD_ARGUMENT 5
/* --------------------------------------------------------------------- */
@@ -127,40 +128,40 @@ extern "C" {
is the first saved register, the one before the last is the second saved
register, and so on.
- If an architecture provides two scratch and three saved registers,
- its scratch and saved register sets are the following:
+ For example, in an architecture with only five registers (A-E), if two
+ are scratch and three saved registers, they will be defined as follows:
- R0 | | R0 is always a scratch register
- R1 | | R1 is always a scratch register
- [R2] | S2 | R2 and S2 represent the same physical register
- [R3] | S1 | R3 and S1 represent the same physical register
- [R4] | S0 | R4 and S0 represent the same physical register
+ A | R0 | | R0 always represent scratch register A
+ B | R1 | | R1 always represent scratch register B
+ C | [R2] | S2 | R2 and S2 represent the same physical register C
+ D | [R3] | S1 | R3 and S1 represent the same physical register D
+ E | [R4] | S0 | R4 and S0 represent the same physical register E
- Note: SLJIT_NUMBER_OF_SCRATCH_REGISTERS would be 2 and
- SLJIT_NUMBER_OF_SAVED_REGISTERS would be 3 for this architecture.
+ Note: SLJIT_NUMBER_OF_SCRATCH_REGISTERS will be 2 and
+ SLJIT_NUMBER_OF_SAVED_REGISTERS will be 3.
- Note: On all supported architectures SLJIT_NUMBER_OF_REGISTERS >= 12
+ Note: For all supported architectures SLJIT_NUMBER_OF_REGISTERS >= 12
and SLJIT_NUMBER_OF_SAVED_REGISTERS >= 6. However, 6 registers
are virtual on x86-32. See below.
The purpose of this definition is convenience: saved registers can
- be used as extra scratch registers. For example four registers can
- be specified as scratch registers and the fifth one as saved register
- on the CPU above and any user code which requires four scratch
- registers can run unmodified. The SLJIT compiler automatically saves
- the content of the two extra scratch register on the stack. Scratch
- registers can also be preserved by saving their value on the stack
- but this needs to be done manually.
+ be used as extra scratch registers. For example, building in the
+ previous example, four registers can be specified as scratch registers
+ and the fifth one as saved register, allowing any user code which requires
+ four scratch registers to run unmodified. The SLJIT compiler automatically
+ saves the content of the two extra scratch register on the stack. Scratch
+ registers can also be preserved by saving their value on the stack but
+ that needs to be done manually.
Note: To emphasize that registers assigned to R2-R4 are saved
registers, they are enclosed by square brackets.
- Note: sljit_emit_enter and sljit_set_context defines whether a register
- is S or R register. E.g: when 3 scratches and 1 saved is mapped
- by sljit_emit_enter, the allowed register set will be: R0-R2 and
- S0. Although S2 is mapped to the same position as R2, it does not
- available in the current configuration. Furthermore the S1 register
- is not available at all.
+ Note: sljit_emit_enter and sljit_set_context define whether a register
+ is S or R register. E.g: if in the previous example 3 scratches and
+ 1 saved are mapped by sljit_emit_enter, the allowed register set
+ will be: R0-R2 and S0. Although S2 is mapped to the same register
+ than R2, it is not available in that configuration. Furthermore
+ the S1 register cannot be used at all.
*/
/* Scratch registers. */
@@ -209,7 +210,7 @@ extern "C" {
/* The SLJIT_SP provides direct access to the linear stack space allocated by
sljit_emit_enter. It can only be used in the following form: SLJIT_MEM1(SLJIT_SP).
The immediate offset is extended by the relative stack offset automatically.
- The sljit_get_local_base can be used to obtain the real address of a value. */
+ sljit_get_local_base can be used to obtain the real address of a value. */
#define SLJIT_SP (SLJIT_NUMBER_OF_REGISTERS + 1)
/* Return with machine word. */
@@ -221,7 +222,7 @@ extern "C" {
/* --------------------------------------------------------------------- */
/* Each floating point register can store a 32 or a 64 bit precision
- value. The FR and FS register sets are overlap in the same way as R
+ value. The FR and FS register sets overlap in the same way as R
and S register sets. See above. */
/* Floating point scratch registers. */
@@ -231,6 +232,10 @@ extern "C" {
#define SLJIT_FR3 4
#define SLJIT_FR4 5
#define SLJIT_FR5 6
+#define SLJIT_FR6 7
+#define SLJIT_FR7 8
+#define SLJIT_FR8 9
+#define SLJIT_FR9 10
/* All FR registers provided by the architecture can be accessed by SLJIT_FR(i)
The i parameter must be >= 0 and < SLJIT_NUMBER_OF_FLOAT_REGISTERS. */
#define SLJIT_FR(i) (1 + (i))
@@ -242,6 +247,10 @@ extern "C" {
#define SLJIT_FS3 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 3)
#define SLJIT_FS4 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 4)
#define SLJIT_FS5 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 5)
+#define SLJIT_FS6 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 6)
+#define SLJIT_FS7 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 7)
+#define SLJIT_FS8 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 8)
+#define SLJIT_FS9 (SLJIT_NUMBER_OF_FLOAT_REGISTERS - 9)
/* All S registers provided by the architecture can be accessed by SLJIT_FS(i)
The i parameter must be >= 0 and < SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS. */
#define SLJIT_FS(i) (SLJIT_NUMBER_OF_FLOAT_REGISTERS - (i))
@@ -260,23 +269,39 @@ extern "C" {
/* The following argument type definitions are used by sljit_emit_enter,
sljit_set_context, sljit_emit_call, and sljit_emit_icall functions.
- As for sljit_emit_call and sljit_emit_icall, the first integer argument
+ For sljit_emit_call and sljit_emit_icall, the first integer argument
must be placed into SLJIT_R0, the second one into SLJIT_R1, and so on.
Similarly the first floating point argument must be placed into SLJIT_FR0,
the second one into SLJIT_FR1, and so on.
- As for sljit_emit_enter, the integer arguments can be stored in scratch
- or saved registers. The first integer argument without _R postfix is
- stored in SLJIT_S0, the next one in SLJIT_S1, and so on. The integer
- arguments with _R postfix are placed into scratch registers. The index
- of the scratch register is the count of the previous integer arguments
- starting from SLJIT_R0. The floating point arguments are always placed
- into SLJIT_FR0, SLJIT_FR1, and so on.
+ For sljit_emit_enter, the integer arguments can be stored in scratch
+ or saved registers. Scratch registers are identified by a _R suffix.
- Note: if a function is called by sljit_emit_call/sljit_emit_icall and
- an argument is stored in a scratch register by sljit_emit_enter,
- that argument uses the same scratch register index for both
- integer and floating point arguments.
+ If only saved registers are used, then the allocation mirrors what is
+ done for the "call" functions but using saved registers, meaning that
+ the first integer argument goes to SLJIT_S0, the second one goes into
+ SLJIT_S1, and so on.
+
+ If scratch registers are used, then the way the integer registers are
+ allocated changes so that SLJIT_S0, SLJIT_S1, etc; will be assigned
+ only for the arguments not using scratch registers, while SLJIT_R<n>
+ will be used for the ones using scratch registers.
+
+ Furthermore, the index (shown as "n" above) that will be used for the
+ scratch register depends on how many previous integer registers
+ (scratch or saved) were used already, starting with SLJIT_R0.
+ Eventhough some indexes will be likely skipped, they still need to be
+ accounted for in the scratches parameter of sljit_emit_enter. See below
+ for some examples.
+
+ The floating point arguments always use scratch registers (but not the
+ _R suffix like the integer arguments) and must use SLJIT_FR0, SLJIT_FR1,
+ just like in the "call" functions.
+
+ Note: the mapping for scratch registers is part of the compiler context
+ and therefore a new context after sljit_emit_call/sljit_emit_icall
+ could remove access to some scratch registers that were used as
+ arguments.
Example function definition:
sljit_f32 SLJIT_FUNC example_c_callback(void *arg_a,
@@ -288,29 +313,33 @@ extern "C" {
| SLJIT_ARG_VALUE(SLJIT_ARG_TYPE_32, 3) | SLJIT_ARG_VALUE(SLJIT_ARG_TYPE_F32, 4)
Short form of argument type definition:
- SLJIT_ARGS4(32, P, F64, 32, F32)
+ SLJIT_ARGS4(F32, P, F64, 32, F32)
Argument passing:
arg_a must be placed in SLJIT_R0
- arg_c must be placed in SLJIT_R1
arg_b must be placed in SLJIT_FR0
+ arg_c must be placed in SLJIT_R1
arg_d must be placed in SLJIT_FR1
Examples for argument processing by sljit_emit_enter:
- SLJIT_ARGS4(VOID, P, 32_R, F32, W)
+ SLJIT_ARGS4V(P, 32_R, F32, W)
Arguments are placed into: SLJIT_S0, SLJIT_R1, SLJIT_FR0, SLJIT_S1
+ The type of the result is void.
- SLJIT_ARGS4(VOID, W, W_R, W, W_R)
+ SLJIT_ARGS4(F32, W, W_R, W, W_R)
Arguments are placed into: SLJIT_S0, SLJIT_R1, SLJIT_S1, SLJIT_R3
+ The type of the result is sljit_f32.
- SLJIT_ARGS4(VOID, F64, W, F32, W_R)
+ SLJIT_ARGS4(P, W, F32, P_R)
Arguments are placed into: SLJIT_FR0, SLJIT_S0, SLJIT_FR1, SLJIT_R1
+ The type of the result is pointer.
Note: it is recommended to pass the scratch arguments first
followed by the saved arguments:
- SLJIT_ARGS4(VOID, W_R, W_R, W, W)
+ SLJIT_ARGS4(W, W_R, W_R, W, W)
Arguments are placed into: SLJIT_R0, SLJIT_R1, SLJIT_S0, SLJIT_S1
+ The type of the result is sljit_sw / sljit_uw.
*/
/* The following flag is only allowed for the integer arguments of
@@ -318,21 +347,21 @@ extern "C" {
stored in a scratch register instead of a saved register. */
#define SLJIT_ARG_TYPE_SCRATCH_REG 0x8
-/* Void result, can only be used by SLJIT_ARG_RETURN. */
-#define SLJIT_ARG_TYPE_VOID 0
+/* No return value, only supported by SLJIT_ARG_RETURN. */
+#define SLJIT_ARG_TYPE_RET_VOID 0
/* Machine word sized integer argument or result. */
-#define SLJIT_ARG_TYPE_W 1
+#define SLJIT_ARG_TYPE_W 1
#define SLJIT_ARG_TYPE_W_R (SLJIT_ARG_TYPE_W | SLJIT_ARG_TYPE_SCRATCH_REG)
/* 32 bit integer argument or result. */
-#define SLJIT_ARG_TYPE_32 2
+#define SLJIT_ARG_TYPE_32 2
#define SLJIT_ARG_TYPE_32_R (SLJIT_ARG_TYPE_32 | SLJIT_ARG_TYPE_SCRATCH_REG)
/* Pointer sized integer argument or result. */
-#define SLJIT_ARG_TYPE_P 3
+#define SLJIT_ARG_TYPE_P 3
#define SLJIT_ARG_TYPE_P_R (SLJIT_ARG_TYPE_P | SLJIT_ARG_TYPE_SCRATCH_REG)
/* 64 bit floating point argument or result. */
-#define SLJIT_ARG_TYPE_F64 4
+#define SLJIT_ARG_TYPE_F64 4
/* 32 bit floating point argument or result. */
-#define SLJIT_ARG_TYPE_F32 5
+#define SLJIT_ARG_TYPE_F32 5
#define SLJIT_ARG_SHIFT 4
#define SLJIT_ARG_RETURN(type) (type)
@@ -345,24 +374,40 @@ extern "C" {
can be shortened to:
SLJIT_ARGS1(W, F32)
+
+ Another example where no value is returned:
+ SLJIT_ARG_RETURN(SLJIT_ARG_TYPE_RET_VOID) | SLJIT_ARG_VALUE(SLJIT_ARG_TYPE_W_R, 1)
+
+ can be shortened to:
+ SLJIT_ARGS1V(W_R)
*/
#define SLJIT_ARG_TO_TYPE(type) SLJIT_ARG_TYPE_ ## type
#define SLJIT_ARGS0(ret) \
SLJIT_ARG_RETURN(SLJIT_ARG_TO_TYPE(ret))
+#define SLJIT_ARGS0V() \
+ SLJIT_ARG_RETURN(SLJIT_ARG_TYPE_RET_VOID)
#define SLJIT_ARGS1(ret, arg1) \
(SLJIT_ARGS0(ret) | SLJIT_ARG_VALUE(SLJIT_ARG_TO_TYPE(arg1), 1))
+#define SLJIT_ARGS1V(arg1) \
+ (SLJIT_ARGS0V() | SLJIT_ARG_VALUE(SLJIT_ARG_TO_TYPE(arg1), 1))
#define SLJIT_ARGS2(ret, arg1, arg2) \
(SLJIT_ARGS1(ret, arg1) | SLJIT_ARG_VALUE(SLJIT_ARG_TO_TYPE(arg2), 2))
+#define SLJIT_ARGS2V(arg1, arg2) \
+ (SLJIT_ARGS1V(arg1) | SLJIT_ARG_VALUE(SLJIT_ARG_TO_TYPE(arg2), 2))
#define SLJIT_ARGS3(ret, arg1, arg2, arg3) \
(SLJIT_ARGS2(ret, arg1, arg2) | SLJIT_ARG_VALUE(SLJIT_ARG_TO_TYPE(arg3), 3))
+#define SLJIT_ARGS3V(arg1, arg2, arg3) \
+ (SLJIT_ARGS2V(arg1, arg2) | SLJIT_ARG_VALUE(SLJIT_ARG_TO_TYPE(arg3), 3))
#define SLJIT_ARGS4(ret, arg1, arg2, arg3, arg4) \
(SLJIT_ARGS3(ret, arg1, arg2, arg3) | SLJIT_ARG_VALUE(SLJIT_ARG_TO_TYPE(arg4), 4))
+#define SLJIT_ARGS4V(arg1, arg2, arg3, arg4) \
+ (SLJIT_ARGS3V(arg1, arg2, arg3) | SLJIT_ARG_VALUE(SLJIT_ARG_TO_TYPE(arg4), 4))
/* --------------------------------------------------------------------- */
/* Main structures and functions */
@@ -457,7 +502,7 @@ struct sljit_compiler {
sljit_s32 mode32;
#endif
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
/* Constant pool handling. */
sljit_uw *cpool;
sljit_u8 *cpool_unique;
@@ -468,10 +513,10 @@ struct sljit_compiler {
sljit_uw patches;
#endif
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
/* Temporary fields. */
sljit_uw shift_imm;
-#endif /* SLJIT_CONFIG_ARM_V5 || SLJIT_CONFIG_ARM_V7 */
+#endif /* SLJIT_CONFIG_ARM_V6 || SLJIT_CONFIG_ARM_V6 */
#if (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) && (defined __SOFTFP__)
sljit_uw args_size;
@@ -501,6 +546,11 @@ struct sljit_compiler {
sljit_s32 mode;
#endif
+#if (defined SLJIT_CONFIG_LOONGARCH && SLJIT_CONFIG_LOONGARCH)
+ sljit_s32 cache_arg;
+ sljit_sw cache_argw;
+#endif
+
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
FILE* verbose;
#endif
@@ -558,8 +608,7 @@ static SLJIT_INLINE sljit_s32 sljit_get_compiler_error(struct sljit_compiler *co
after the code is compiled. */
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_compiler_memory_error(struct sljit_compiler *compiler);
-/*
- Allocate a small amount of memory. The size must be <= 64 bytes on 32 bit,
+/* Allocate a small amount of memory. The size must be <= 64 bytes on 32 bit,
and <= 128 bytes on 64 bit architectures. The memory area is owned by the
compiler, and freed by sljit_free_compiler. The returned pointer is
sizeof(sljit_sw) aligned. Excellent for allocating small blocks during
@@ -567,19 +616,21 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_compiler_memory_error(struct sljit_compi
to contain at most 16 pointers. If the size is outside of the range,
the function will return with NULL. However, this return value does not
indicate that there is no more memory (does not set the current error code
- of the compiler to out-of-memory status).
-*/
+ of the compiler to out-of-memory status). */
SLJIT_API_FUNC_ATTRIBUTE void* sljit_alloc_memory(struct sljit_compiler *compiler, sljit_s32 size);
+/* Returns the allocator data passed to sljit_create_compiler. These pointers
+ may contain context data even if the normal/exec allocator ignores it. */
+static SLJIT_INLINE void* sljit_get_allocator_data(struct sljit_compiler *compiler) { return compiler->allocator_data; }
+static SLJIT_INLINE void* sljit_get_exec_allocator_data(struct sljit_compiler *compiler) { return compiler->exec_allocator_data; }
+
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
/* Passing NULL disables verbose. */
SLJIT_API_FUNC_ATTRIBUTE void sljit_compiler_verbose(struct sljit_compiler *compiler, FILE* verbose);
#endif
-/*
- Create executable code from the instruction stream. This is the final step
- of the code generation so no more instructions can be emitted after this call.
-*/
+/* Create executable code from the instruction stream. This is the final step
+ of the code generation so no more instructions can be emitted after this call. */
SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler);
@@ -587,8 +638,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code, void *exec_allocator_data);
-/*
- When the protected executable allocator is used the JIT code is mapped
+/* When the protected executable allocator is used the JIT code is mapped
twice. The first mapping has read/write and the second mapping has read/exec
permissions. This function returns with the relative offset of the executable
mapping using the writable mapping as the base after the machine code is
@@ -596,16 +646,13 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_free_code(void* code, void *exec_allocator_d
allocator, since it uses only one mapping with read/write/exec permissions.
Dynamic code modifications requires this value.
- Before a successful code generation, this function returns with 0.
-*/
+ Before a successful code generation, this function returns with 0. */
static SLJIT_INLINE sljit_sw sljit_get_executable_offset(struct sljit_compiler *compiler) { return compiler->executable_offset; }
-/*
- The executable memory consumption of the generated code can be retrieved by
+/* The executable memory consumption of the generated code can be retrieved by
this function. The returned value can be used for statistical purposes.
- Before a successful code generation, this function returns with 0.
-*/
+ Before a successful code generation, this function returns with 0. */
static SLJIT_INLINE sljit_uw sljit_get_generated_code_size(struct sljit_compiler *compiler) { return compiler->executable_size; }
/* Returns with non-zero if the feature or limitation type passed as its
@@ -628,30 +675,49 @@ static SLJIT_INLINE sljit_uw sljit_get_generated_code_size(struct sljit_compiler
#define SLJIT_HAS_CLZ 3
/* [Emulated] Count trailing zero is supported. */
#define SLJIT_HAS_CTZ 4
+/* [Emulated] Reverse the order of bytes is supported. */
+#define SLJIT_HAS_REV 5
/* [Emulated] Rotate left/right is supported. */
-#define SLJIT_HAS_ROT 5
+#define SLJIT_HAS_ROT 6
/* [Emulated] Conditional move is supported. */
-#define SLJIT_HAS_CMOV 6
+#define SLJIT_HAS_CMOV 7
/* [Emulated] Prefetch instruction is available (emulated as a nop). */
-#define SLJIT_HAS_PREFETCH 7
+#define SLJIT_HAS_PREFETCH 8
+/* [Emulated] Copy from/to f32 operation is available (see sljit_emit_fcopy). */
+#define SLJIT_HAS_COPY_F32 9
+/* [Emulated] Copy from/to f64 operation is available (see sljit_emit_fcopy). */
+#define SLJIT_HAS_COPY_F64 10
+/* [Not emulated] The 64 bit floating point registers can be used as
+ two separate 32 bit floating point registers (e.g. ARM32). The
+ second 32 bit part can be accessed by SLJIT_F64_SECOND. */
+#define SLJIT_HAS_F64_AS_F32_PAIR 11
+/* [Not emulated] Some SIMD operations are supported by the compiler. */
+#define SLJIT_HAS_SIMD 12
+/* [Not emulated] SIMD registers are mapped to a pair of double precision
+ floating point registers. E.g. passing either SLJIT_FR0 or SLJIT_FR1 to
+ a simd operation represents the same 128 bit register, and both SLJIT_FR0
+ and SLJIT_FR1 are overwritten. */
+#define SLJIT_SIMD_REGS_ARE_PAIRS 13
+/* [Not emulated] Atomic support is available (fine-grained). */
+#define SLJIT_HAS_ATOMIC 14
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
-/* [Not emulated] SSE2 support is available on x86. */
-#define SLJIT_HAS_SSE2 100
+/* [Not emulated] AVX support is available on x86. */
+#define SLJIT_HAS_AVX 100
+/* [Not emulated] AVX2 support is available on x86. */
+#define SLJIT_HAS_AVX2 101
#endif
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type);
/* If type is between SLJIT_ORDERED_EQUAL and SLJIT_ORDERED_LESS_EQUAL,
- sljit_cmp_info returns one, if the cpu supports the passed floating
- point comparison type.
+ sljit_cmp_info returns with:
+ zero - if the cpu supports the floating point comparison type
+ one - if the comparison requires two machine instructions
+ two - if the comparison requires more than two machine instructions
- If type is SLJIT_UNORDERED or SLJIT_ORDERED, sljit_cmp_info returns
- one, if the cpu supports checking the unordered comparison result
- regardless of the comparison type passed to the comparison instruction.
- The returned value is always one, if there is at least one type between
- SLJIT_ORDERED_EQUAL and SLJIT_ORDERED_LESS_EQUAL where sljit_cmp_info
- returns with a zero value.
+ When the result is non-zero, it is recommended to avoid
+ using the specified comparison type if it is easy to do so.
Otherwise it returns zero. */
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type);
@@ -662,7 +728,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type);
/*
The executable code is a function from the viewpoint of the C
- language. The function calls must obey to the ABI (Application
+ language. The function calls must conform to the ABI (Application
Binary Interface) of the platform, which specify the purpose of
machine registers and stack handling among other things. The
sljit_emit_enter function emits the necessary instructions for
@@ -721,7 +787,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type);
#define SLJIT_ENTER_REG_ARG 0x00000004
/* The local_size must be >= 0 and <= SLJIT_MAX_LOCAL_SIZE. */
-#define SLJIT_MAX_LOCAL_SIZE 65536
+#define SLJIT_MAX_LOCAL_SIZE 1048576
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
@@ -732,9 +798,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
by sljit_emit_enter. Several functions (such as sljit_emit_return)
requires this context to be able to generate the appropriate code.
However, some code fragments (compiled separately) may have no
- normal entry point so their context is unknown for the compiler.
+ normal entry point so their context is unknown to the compiler.
- The sljit_set_context and sljit_emit_enter have the same arguments,
+ sljit_set_context and sljit_emit_enter have the same arguments,
but sljit_set_context does not generate any machine code.
Note: every call of sljit_emit_enter and sljit_set_context overwrites
@@ -767,28 +833,6 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return(struct sljit_compiler *comp
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler,
sljit_s32 src, sljit_sw srcw);
-/* Generating entry and exit points for fast call functions (see SLJIT_FAST_CALL).
- Both sljit_emit_fast_enter and SLJIT_FAST_RETURN operations preserve the
- values of all registers and stack frame. The return address is stored in the
- dst argument of sljit_emit_fast_enter, and this return address can be passed
- to SLJIT_FAST_RETURN to continue the execution after the fast call.
-
- Fast calls are cheap operations (usually only a single call instruction is
- emitted) but they do not preserve any registers. However the callee function
- can freely use / update any registers and the local area which can be
- efficiently exploited by various optimizations. Registers can be saved
- and restored manually if needed.
-
- Although returning to different address by SLJIT_FAST_RETURN is possible,
- this address usually cannot be predicted by the return address predictor of
- modern CPUs which may reduce performance. Furthermore certain security
- enhancement technologies such as Intel Control-flow Enforcement Technology
- (CET) may disallow returning to a different address.
-
- Flags: - (does not modify flags). */
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw);
-
/*
Source and destination operands for arithmetical instructions
imm - a simple immediate value (cannot be used as a destination)
@@ -816,7 +860,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *
Note: Different architectures have different addressing limitations.
A single instruction is enough for the following addressing
- modes. Other adrressing modes are emulated by instruction
+ modes. Other addressing modes are emulated by instruction
sequences. This information could help to improve those code
generators which focuses only a few architectures.
@@ -847,6 +891,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *
s390x: [reg+imm], -2^19 <= imm < 2^19
[reg+reg] is supported
Write-back is not supported
+ loongarch: [reg+imm], -2048 <= imm <= 2047
+ [reg+reg] is supported
+ Write-back is not supported
*/
/* Macros for specifying operand types. */
@@ -854,9 +901,18 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *
#define SLJIT_MEM0() (SLJIT_MEM)
#define SLJIT_MEM1(r1) (SLJIT_MEM | (r1))
#define SLJIT_MEM2(r1, r2) (SLJIT_MEM | (r1) | ((r2) << 8))
-#define SLJIT_IMM 0x40
+#define SLJIT_IMM 0x7f
#define SLJIT_REG_PAIR(r1, r2) ((r1) | ((r2) << 8))
+/* Macros for checking operand types (only for valid arguments). */
+#define SLJIT_IS_REG(arg) ((arg) > 0 && (arg) < SLJIT_IMM)
+#define SLJIT_IS_MEM(arg) ((arg) & SLJIT_MEM)
+#define SLJIT_IS_MEM0(arg) ((arg) == SLJIT_MEM)
+#define SLJIT_IS_MEM1(arg) ((arg) > SLJIT_MEM && (arg) < (SLJIT_MEM << 1))
+#define SLJIT_IS_MEM2(arg) (((arg) & SLJIT_MEM) && (arg) >= (SLJIT_MEM << 1))
+#define SLJIT_IS_IMM(arg) ((arg) == SLJIT_IMM)
+#define SLJIT_IS_REG_PAIR(arg) (!((arg) & SLJIT_MEM) && (arg) >= (SLJIT_MEM << 1))
+
/* Sets 32 bit operation mode on 64 bit CPUs. This option is ignored on
32 bit CPUs. When this option is set for an arithmetic operation, only
the lower 32 bits of the input registers are used, and the CPU status
@@ -1057,27 +1113,57 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compile
Note: loads a pointer sized data, useful on x32 mode (a 64 bit mode
on x86-64 which uses 32 bit pointers) or similar compiling modes */
#define SLJIT_MOV_P (SLJIT_OP1_BASE + 8)
-/* Flags: Z
- Note: immediate source argument is not supported */
-#define SLJIT_NOT (SLJIT_OP1_BASE + 9)
-#define SLJIT_NOT32 (SLJIT_NOT | SLJIT_32)
/* Count leading zeroes
Flags: - (may destroy flags)
Note: immediate source argument is not supported */
-#define SLJIT_CLZ (SLJIT_OP1_BASE + 10)
+#define SLJIT_CLZ (SLJIT_OP1_BASE + 9)
#define SLJIT_CLZ32 (SLJIT_CLZ | SLJIT_32)
/* Count trailing zeroes
Flags: - (may destroy flags)
Note: immediate source argument is not supported */
-#define SLJIT_CTZ (SLJIT_OP1_BASE + 11)
+#define SLJIT_CTZ (SLJIT_OP1_BASE + 10)
#define SLJIT_CTZ32 (SLJIT_CTZ | SLJIT_32)
+/* Reverse the order of bytes
+ Flags: - (may destroy flags)
+ Note: converts between little and big endian formats
+ Note: immediate source argument is not supported */
+#define SLJIT_REV (SLJIT_OP1_BASE + 11)
+#define SLJIT_REV32 (SLJIT_REV | SLJIT_32)
+/* Reverse the order of bytes in the lower 16 bit and extend as unsigned
+ Flags: - (may destroy flags)
+ Note: converts between little and big endian formats
+ Note: immediate source argument is not supported */
+#define SLJIT_REV_U16 (SLJIT_OP1_BASE + 12)
+#define SLJIT_REV32_U16 (SLJIT_REV_U16 | SLJIT_32)
+/* Reverse the order of bytes in the lower 16 bit and extend as signed
+ Flags: - (may destroy flags)
+ Note: converts between little and big endian formats
+ Note: immediate source argument is not supported */
+#define SLJIT_REV_S16 (SLJIT_OP1_BASE + 13)
+#define SLJIT_REV32_S16 (SLJIT_REV_S16 | SLJIT_32)
+/* Reverse the order of bytes in the lower 32 bit and extend as unsigned
+ Flags: - (may destroy flags)
+ Note: converts between little and big endian formats
+ Note: immediate source argument is not supported */
+#define SLJIT_REV_U32 (SLJIT_OP1_BASE + 14)
+/* Reverse the order of bytes in the lower 32 bit and extend as signed
+ Flags: - (may destroy flags)
+ Note: converts between little and big endian formats
+ Note: immediate source argument is not supported */
+#define SLJIT_REV_S32 (SLJIT_OP1_BASE + 15)
+
+/* The following unary operations are supported by using sljit_emit_op2:
+ - binary not: SLJIT_XOR with immedate -1 as src1 or src2
+ - negate: SLJIT_SUB with immedate 0 as src1
+ Note: these operations are optimized by the compiler if the
+ target CPU has specialized instruction forms for them. */
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 src, sljit_sw srcw);
/* Starting index of opcodes for sljit_emit_op2. */
-#define SLJIT_OP2_BASE 96
+#define SLJIT_OP2_BASE 64
/* Flags: Z | OVERFLOW | CARRY */
#define SLJIT_ADD (SLJIT_OP2_BASE + 0)
@@ -1174,80 +1260,97 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil
op must be one of the following operations:
SLJIT_SHL or SLJIT_SHL32:
- src_dst <<= src2
- src_dst |= ((src1 >> 1) >> (src2 ^ value_mask))
+ dst_reg = src1_reg << src3_reg
+ dst_reg |= ((src2_reg >> 1) >> (src3 ^ value_mask))
SLJIT_MSHL or SLJIT_MSHL32:
- src2 &= value_mask
+ src3 &= value_mask
perform the SLJIT_SHL or SLJIT_SHL32 operation
SLJIT_LSHR or SLJIT_LSHR32:
- src_dst >>= src2
- src_dst |= ((src1 << 1) << (src2 ^ value_mask))
+ dst_reg = src1_reg >> src3_reg
+ dst_reg |= ((src2_reg << 1) << (src3 ^ value_mask))
SLJIT_MLSHR or SLJIT_MLSHR32:
- src2 &= value_mask
+ src3 &= value_mask
perform the SLJIT_LSHR or SLJIT_LSHR32 operation
op can be combined (or'ed) with SLJIT_SHIFT_INTO_NON_ZERO
- src_dst must be a register which content is updated after
- the operation is completed
- src1 / src1w contains the bits which shifted into src_dst
- src2 / src2w contains the shift amount
+ dst_reg specifies the destination register, where dst_reg
+ and src2_reg cannot be the same registers
+ src1_reg specifies the source register
+ src2_reg specifies the register which is shifted into src1_reg
+ src3 / src3w contains the shift amount
- Note: a rotate operation can be performed if src_dst and
- src1 are set to the same register
+ Note: a rotate operation is performed if src1_reg and
+ src2_reg are the same registers
Flags: - (may destroy flags) */
-/* The src2 contains a non-zero value. Improves the generated
- code on certain architectures, which provides a small
- performance improvement. */
+/* The src3 operand contains a non-zero value. Improves
+ the generated code on certain architectures, which
+ provides a small performance improvement. */
#define SLJIT_SHIFT_INTO_NON_ZERO 0x200
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 src_dst,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w);
+ sljit_s32 dst_reg,
+ sljit_s32 src1_reg,
+ sljit_s32 src2_reg,
+ sljit_s32 src3, sljit_sw src3w);
-/* Starting index of opcodes for sljit_emit_op2. */
-#define SLJIT_OP_SRC_BASE 128
+/* Starting index of opcodes for sljit_emit_op_src
+ and sljit_emit_op_dst. */
+#define SLJIT_OP_SRC_DST_BASE 96
-/* Note: src cannot be an immedate value
+/* Fast return, see SLJIT_FAST_CALL for more details.
+ Note: src cannot be an immedate value
Flags: - (does not modify flags) */
-#define SLJIT_FAST_RETURN (SLJIT_OP_SRC_BASE + 0)
+#define SLJIT_FAST_RETURN (SLJIT_OP_SRC_DST_BASE + 0)
/* Skip stack frames before fast return.
Note: src cannot be an immedate value
Flags: may destroy flags. */
-#define SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN (SLJIT_OP_SRC_BASE + 1)
+#define SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN (SLJIT_OP_SRC_DST_BASE + 1)
/* Prefetch value into the level 1 data cache
Note: if the target CPU does not support data prefetch,
no instructions are emitted.
Note: this instruction never fails, even if the memory address is invalid.
Flags: - (does not modify flags) */
-#define SLJIT_PREFETCH_L1 (SLJIT_OP_SRC_BASE + 2)
+#define SLJIT_PREFETCH_L1 (SLJIT_OP_SRC_DST_BASE + 2)
/* Prefetch value into the level 2 data cache
Note: same as SLJIT_PREFETCH_L1 if the target CPU
does not support this instruction form.
Note: this instruction never fails, even if the memory address is invalid.
Flags: - (does not modify flags) */
-#define SLJIT_PREFETCH_L2 (SLJIT_OP_SRC_BASE + 3)
+#define SLJIT_PREFETCH_L2 (SLJIT_OP_SRC_DST_BASE + 3)
/* Prefetch value into the level 3 data cache
Note: same as SLJIT_PREFETCH_L2 if the target CPU
does not support this instruction form.
Note: this instruction never fails, even if the memory address is invalid.
Flags: - (does not modify flags) */
-#define SLJIT_PREFETCH_L3 (SLJIT_OP_SRC_BASE + 4)
+#define SLJIT_PREFETCH_L3 (SLJIT_OP_SRC_DST_BASE + 4)
/* Prefetch a value which is only used once (and can be discarded afterwards)
Note: same as SLJIT_PREFETCH_L1 if the target CPU
does not support this instruction form.
Note: this instruction never fails, even if the memory address is invalid.
Flags: - (does not modify flags) */
-#define SLJIT_PREFETCH_ONCE (SLJIT_OP_SRC_BASE + 5)
+#define SLJIT_PREFETCH_ONCE (SLJIT_OP_SRC_DST_BASE + 5)
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 src, sljit_sw srcw);
+/* Fast enter, see SLJIT_FAST_CALL for more details.
+ Flags: - (does not modify flags) */
+#define SLJIT_FAST_ENTER (SLJIT_OP_SRC_DST_BASE + 6)
+
+/* Copies the return address into dst. The return address is the
+ address where the execution continues after the called function
+ returns (see: sljit_emit_return / sljit_emit_return_void).
+ Flags: - (does not modify flags) */
+#define SLJIT_GET_RETURN_ADDRESS (SLJIT_OP_SRC_DST_BASE + 7)
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw);
+
/* Starting index of opcodes for sljit_emit_fop1. */
-#define SLJIT_FOP1_BASE 160
+#define SLJIT_FOP1_BASE 128
/* Flags: - (does not modify flags) */
#define SLJIT_MOV_F64 (SLJIT_FOP1_BASE + 0)
@@ -1270,15 +1373,21 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *comp
/* Flags: - (may destroy flags) */
#define SLJIT_CONV_F64_FROM_S32 (SLJIT_FOP1_BASE + 5)
#define SLJIT_CONV_F32_FROM_S32 (SLJIT_CONV_F64_FROM_S32 | SLJIT_32)
+/* Flags: - (may destroy flags) */
+#define SLJIT_CONV_F64_FROM_UW (SLJIT_FOP1_BASE + 6)
+#define SLJIT_CONV_F32_FROM_UW (SLJIT_CONV_F64_FROM_UW | SLJIT_32)
+/* Flags: - (may destroy flags) */
+#define SLJIT_CONV_F64_FROM_U32 (SLJIT_FOP1_BASE + 7)
+#define SLJIT_CONV_F32_FROM_U32 (SLJIT_CONV_F64_FROM_U32 | SLJIT_32)
/* Note: dst is the left and src is the right operand for SLJIT_CMP_F32/64.
Flags: EQUAL_F | LESS_F | GREATER_EQUAL_F | GREATER_F | LESS_EQUAL_F */
-#define SLJIT_CMP_F64 (SLJIT_FOP1_BASE + 6)
+#define SLJIT_CMP_F64 (SLJIT_FOP1_BASE + 8)
#define SLJIT_CMP_F32 (SLJIT_CMP_F64 | SLJIT_32)
/* Flags: - (may destroy flags) */
-#define SLJIT_NEG_F64 (SLJIT_FOP1_BASE + 7)
+#define SLJIT_NEG_F64 (SLJIT_FOP1_BASE + 9)
#define SLJIT_NEG_F32 (SLJIT_NEG_F64 | SLJIT_32)
/* Flags: - (may destroy flags) */
-#define SLJIT_ABS_F64 (SLJIT_FOP1_BASE + 8)
+#define SLJIT_ABS_F64 (SLJIT_FOP1_BASE + 10)
#define SLJIT_ABS_F32 (SLJIT_ABS_F64 | SLJIT_32)
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
@@ -1286,7 +1395,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil
sljit_s32 src, sljit_sw srcw);
/* Starting index of opcodes for sljit_emit_fop2. */
-#define SLJIT_FOP2_BASE 192
+#define SLJIT_FOP2_BASE 160
/* Flags: - (may destroy flags) */
#define SLJIT_ADD_F64 (SLJIT_FOP2_BASE + 0)
@@ -1306,10 +1415,90 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
sljit_s32 src1, sljit_sw src1w,
sljit_s32 src2, sljit_sw src2w);
+/* Starting index of opcodes for sljit_emit_fop2r. */
+#define SLJIT_FOP2R_BASE 168
+
+/* Flags: - (may destroy flags) */
+#define SLJIT_COPYSIGN_F64 (SLJIT_FOP2R_BASE + 0)
+#define SLJIT_COPYSIGN_F32 (SLJIT_COPYSIGN_F64 | SLJIT_32)
+
+/* Similar to sljit_emit_fop2, except the destination is always a register. */
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2r(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_freg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w);
+
+/* Sets a floating point register to an immediate value. */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset32(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f32 value);
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f64 value);
+
+/* The following opcodes are used by sljit_emit_fcopy(). */
+
+/* 64 bit: copy a 64 bit value from an integer register into a
+ 64 bit floating point register without any modifications.
+ 32 bit: copy a 32 bit register or register pair into a 64 bit
+ floating point register without any modifications. The
+ register, or the first register of the register pair
+ replaces the high order 32 bit of the floating point
+ register. If a register pair is passed, the low
+ order 32 bit is replaced by the second register.
+ Otherwise, the low order 32 bit is unchanged. */
+#define SLJIT_COPY_TO_F64 1
+/* Copy a 32 bit value from an integer register into a 32 bit
+ floating point register without any modifications. */
+#define SLJIT_COPY32_TO_F32 (SLJIT_COPY_TO_F64 | SLJIT_32)
+/* 64 bit: copy the value of a 64 bit floating point register into
+ an integer register without any modifications.
+ 32 bit: copy a 64 bit floating point register into a 32 bit register
+ or a 32 bit register pair without any modifications. The
+ high order 32 bit of the floating point register is copied
+ into the register, or the first register of the register
+ pair. If a register pair is passed, the low order 32 bit
+ is copied into the second register. */
+#define SLJIT_COPY_FROM_F64 2
+/* Copy the value of a 32 bit floating point register into an integer
+ register without any modifications. The register should be processed
+ with 32 bit operations later. */
+#define SLJIT_COPY32_FROM_F32 (SLJIT_COPY_FROM_F64 | SLJIT_32)
+
+/* Special data copy which involves floating point registers.
+
+ op must be between SLJIT_COPY_TO_F64 and SLJIT_COPY32_FROM_F32
+ freg must be a floating point register
+ reg must be a register or register pair */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 freg, sljit_s32 reg);
+
/* Label and jump instructions. */
SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compiler *compiler);
+/* The SLJIT_FAST_CALL is a calling method for creating lightweight function
+ calls. This type of calls preserve the values of all registers and stack
+ frame. Unlike normal function calls, the enter and return operations must
+ be performed by the SLJIT_FAST_ENTER and SLJIT_FAST_RETURN operations
+ respectively. The return address is stored in the dst argument of the
+ SLJIT_FAST_ENTER operation, and this return address should be passed as
+ the src argument for the SLJIT_FAST_RETURN operation to return from the
+ called function.
+
+ Fast calls are cheap operations (usually only a single call instruction is
+ emitted) but they do not preserve any registers. However the callee function
+ can freely use / update any registers and the locals area which can be
+ efficiently exploited by various optimizations. Registers can be saved
+ and restored manually if needed.
+
+ Although returning to different address by SLJIT_FAST_RETURN is possible,
+ this address usually cannot be predicted by the return address predictor of
+ modern CPUs which may reduce performance. Furthermore certain security
+ enhancement technologies such as Intel Control-flow Enforcement Technology
+ (CET) may disallow returning to a different address (indirect jumps
+ can be used instead, see SLJIT_SKIP_FRAMES_BEFORE_FAST_RETURN). */
+
/* Invert (negate) conditional type: xor (^) with 0x1 */
/* Integer comparison types. */
@@ -1321,19 +1510,19 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
#define SLJIT_LESS 2
#define SLJIT_SET_LESS SLJIT_SET(SLJIT_LESS)
#define SLJIT_GREATER_EQUAL 3
-#define SLJIT_SET_GREATER_EQUAL SLJIT_SET(SLJIT_GREATER_EQUAL)
+#define SLJIT_SET_GREATER_EQUAL SLJIT_SET(SLJIT_LESS)
#define SLJIT_GREATER 4
#define SLJIT_SET_GREATER SLJIT_SET(SLJIT_GREATER)
#define SLJIT_LESS_EQUAL 5
-#define SLJIT_SET_LESS_EQUAL SLJIT_SET(SLJIT_LESS_EQUAL)
+#define SLJIT_SET_LESS_EQUAL SLJIT_SET(SLJIT_GREATER)
#define SLJIT_SIG_LESS 6
#define SLJIT_SET_SIG_LESS SLJIT_SET(SLJIT_SIG_LESS)
#define SLJIT_SIG_GREATER_EQUAL 7
-#define SLJIT_SET_SIG_GREATER_EQUAL SLJIT_SET(SLJIT_SIG_GREATER_EQUAL)
+#define SLJIT_SET_SIG_GREATER_EQUAL SLJIT_SET(SLJIT_SIG_LESS)
#define SLJIT_SIG_GREATER 8
#define SLJIT_SET_SIG_GREATER SLJIT_SET(SLJIT_SIG_GREATER)
#define SLJIT_SIG_LESS_EQUAL 9
-#define SLJIT_SET_SIG_LESS_EQUAL SLJIT_SET(SLJIT_SIG_LESS_EQUAL)
+#define SLJIT_SET_SIG_LESS_EQUAL SLJIT_SET(SLJIT_SIG_GREATER)
#define SLJIT_OVERFLOW 10
#define SLJIT_SET_OVERFLOW SLJIT_SET(SLJIT_OVERFLOW)
@@ -1344,70 +1533,74 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
#define SLJIT_SET_CARRY SLJIT_SET(SLJIT_CARRY)
#define SLJIT_NOT_CARRY 13
+#define SLJIT_ATOMIC_STORED 14
+#define SLJIT_SET_ATOMIC_STORED SLJIT_SET(SLJIT_ATOMIC_STORED)
+#define SLJIT_ATOMIC_NOT_STORED 15
+
/* Basic floating point comparison types.
Note: when the comparison result is unordered, their behaviour is unspecified. */
-#define SLJIT_F_EQUAL 14
+#define SLJIT_F_EQUAL 16
#define SLJIT_SET_F_EQUAL SLJIT_SET(SLJIT_F_EQUAL)
-#define SLJIT_F_NOT_EQUAL 15
-#define SLJIT_SET_F_NOT_EQUAL SLJIT_SET(SLJIT_F_NOT_EQUAL)
-#define SLJIT_F_LESS 16
+#define SLJIT_F_NOT_EQUAL 17
+#define SLJIT_SET_F_NOT_EQUAL SLJIT_SET(SLJIT_F_EQUAL)
+#define SLJIT_F_LESS 18
#define SLJIT_SET_F_LESS SLJIT_SET(SLJIT_F_LESS)
-#define SLJIT_F_GREATER_EQUAL 17
-#define SLJIT_SET_F_GREATER_EQUAL SLJIT_SET(SLJIT_F_GREATER_EQUAL)
-#define SLJIT_F_GREATER 18
+#define SLJIT_F_GREATER_EQUAL 19
+#define SLJIT_SET_F_GREATER_EQUAL SLJIT_SET(SLJIT_F_LESS)
+#define SLJIT_F_GREATER 20
#define SLJIT_SET_F_GREATER SLJIT_SET(SLJIT_F_GREATER)
-#define SLJIT_F_LESS_EQUAL 19
-#define SLJIT_SET_F_LESS_EQUAL SLJIT_SET(SLJIT_F_LESS_EQUAL)
+#define SLJIT_F_LESS_EQUAL 21
+#define SLJIT_SET_F_LESS_EQUAL SLJIT_SET(SLJIT_F_GREATER)
/* Jumps when either argument contains a NaN value. */
-#define SLJIT_UNORDERED 20
+#define SLJIT_UNORDERED 22
#define SLJIT_SET_UNORDERED SLJIT_SET(SLJIT_UNORDERED)
/* Jumps when neither argument contains a NaN value. */
-#define SLJIT_ORDERED 21
-#define SLJIT_SET_ORDERED SLJIT_SET(SLJIT_ORDERED)
+#define SLJIT_ORDERED 23
+#define SLJIT_SET_ORDERED SLJIT_SET(SLJIT_UNORDERED)
/* Ordered / unordered floating point comparison types.
Note: each comparison type has an ordered and unordered form. Some
architectures supports only either of them (see: sljit_cmp_info). */
-#define SLJIT_ORDERED_EQUAL 22
+#define SLJIT_ORDERED_EQUAL 24
#define SLJIT_SET_ORDERED_EQUAL SLJIT_SET(SLJIT_ORDERED_EQUAL)
-#define SLJIT_UNORDERED_OR_NOT_EQUAL 23
-#define SLJIT_SET_UNORDERED_OR_NOT_EQUAL SLJIT_SET(SLJIT_UNORDERED_OR_NOT_EQUAL)
-#define SLJIT_ORDERED_LESS 24
+#define SLJIT_UNORDERED_OR_NOT_EQUAL 25
+#define SLJIT_SET_UNORDERED_OR_NOT_EQUAL SLJIT_SET(SLJIT_ORDERED_EQUAL)
+#define SLJIT_ORDERED_LESS 26
#define SLJIT_SET_ORDERED_LESS SLJIT_SET(SLJIT_ORDERED_LESS)
-#define SLJIT_UNORDERED_OR_GREATER_EQUAL 25
-#define SLJIT_SET_UNORDERED_OR_GREATER_EQUAL SLJIT_SET(SLJIT_UNORDERED_OR_GREATER_EQUAL)
-#define SLJIT_ORDERED_GREATER 26
+#define SLJIT_UNORDERED_OR_GREATER_EQUAL 27
+#define SLJIT_SET_UNORDERED_OR_GREATER_EQUAL SLJIT_SET(SLJIT_ORDERED_LESS)
+#define SLJIT_ORDERED_GREATER 28
#define SLJIT_SET_ORDERED_GREATER SLJIT_SET(SLJIT_ORDERED_GREATER)
-#define SLJIT_UNORDERED_OR_LESS_EQUAL 27
-#define SLJIT_SET_UNORDERED_OR_LESS_EQUAL SLJIT_SET(SLJIT_UNORDERED_OR_LESS_EQUAL)
+#define SLJIT_UNORDERED_OR_LESS_EQUAL 29
+#define SLJIT_SET_UNORDERED_OR_LESS_EQUAL SLJIT_SET(SLJIT_ORDERED_GREATER)
-#define SLJIT_UNORDERED_OR_EQUAL 28
+#define SLJIT_UNORDERED_OR_EQUAL 30
#define SLJIT_SET_UNORDERED_OR_EQUAL SLJIT_SET(SLJIT_UNORDERED_OR_EQUAL)
-#define SLJIT_ORDERED_NOT_EQUAL 29
-#define SLJIT_SET_ORDERED_NOT_EQUAL SLJIT_SET(SLJIT_ORDERED_NOT_EQUAL)
-#define SLJIT_UNORDERED_OR_LESS 30
+#define SLJIT_ORDERED_NOT_EQUAL 31
+#define SLJIT_SET_ORDERED_NOT_EQUAL SLJIT_SET(SLJIT_UNORDERED_OR_EQUAL)
+#define SLJIT_UNORDERED_OR_LESS 32
#define SLJIT_SET_UNORDERED_OR_LESS SLJIT_SET(SLJIT_UNORDERED_OR_LESS)
-#define SLJIT_ORDERED_GREATER_EQUAL 31
-#define SLJIT_SET_ORDERED_GREATER_EQUAL SLJIT_SET(SLJIT_ORDERED_GREATER_EQUAL)
-#define SLJIT_UNORDERED_OR_GREATER 32
+#define SLJIT_ORDERED_GREATER_EQUAL 33
+#define SLJIT_SET_ORDERED_GREATER_EQUAL SLJIT_SET(SLJIT_UNORDERED_OR_LESS)
+#define SLJIT_UNORDERED_OR_GREATER 34
#define SLJIT_SET_UNORDERED_OR_GREATER SLJIT_SET(SLJIT_UNORDERED_OR_GREATER)
-#define SLJIT_ORDERED_LESS_EQUAL 33
-#define SLJIT_SET_ORDERED_LESS_EQUAL SLJIT_SET(SLJIT_ORDERED_LESS_EQUAL)
+#define SLJIT_ORDERED_LESS_EQUAL 35
+#define SLJIT_SET_ORDERED_LESS_EQUAL SLJIT_SET(SLJIT_UNORDERED_OR_GREATER)
/* Unconditional jump types. */
-#define SLJIT_JUMP 34
-/* Fast calling method. See sljit_emit_fast_enter / SLJIT_FAST_RETURN. */
-#define SLJIT_FAST_CALL 35
+#define SLJIT_JUMP 36
+/* Fast calling method. See the description above. */
+#define SLJIT_FAST_CALL 37
/* Default C calling convention. */
-#define SLJIT_CALL 36
+#define SLJIT_CALL 38
/* Called function must be compiled by SLJIT.
See SLJIT_ENTER_REG_ARG option. */
-#define SLJIT_CALL_REG_ARG 37
+#define SLJIT_CALL_REG_ARG 39
/* The target can be changed during runtime (see: sljit_set_jump_addr). */
#define SLJIT_REWRITABLE_JUMP 0x1000
@@ -1497,19 +1690,42 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
sljit_s32 dst, sljit_sw dstw,
sljit_s32 type);
-/* Emit a conditional mov instruction which moves source to destination,
- if the condition is satisfied. Unlike other arithmetic operations this
- instruction does not support memory access.
+/* Emit a conditional select instruction which moves src1 to dst_reg,
+ if the condition is satisfied, or src2_reg to dst_reg otherwise.
type must be between SLJIT_EQUAL and SLJIT_ORDERED_LESS_EQUAL
- type can be combined (or'ed) with SLJIT_32
- dst_reg must be a valid register
- src must be a valid register or immediate (SLJIT_IMM)
+ type can be combined (or'ed) with SLJIT_32 to move 32 bit
+ register values instead of word sized ones
+ dst_reg and src2_reg must be valid registers
+ src1 must be valid operand
+
+ Note: if src1 is a memory operand, its value
+ might be loaded even if the condition is false.
Flags: - (does not modify flags) */
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *compiler, sljit_s32 type,
sljit_s32 dst_reg,
- sljit_s32 src, sljit_sw srcw);
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_reg);
+
+/* Emit a conditional floating point select instruction which moves
+ src1 to dst_reg, if the condition is satisfied, or src2_reg to
+ dst_reg otherwise.
+
+ type must be between SLJIT_EQUAL and SLJIT_ORDERED_LESS_EQUAL
+ type can be combined (or'ed) with SLJIT_32 to move 32 bit
+ floating point values instead of 64 bit ones
+ dst_freg and src2_freg must be valid floating point registers
+ src1 must be valid operand
+
+ Note: if src1 is a memory operand, its value
+ might be loaded even if the condition is false.
+
+ Flags: - (does not modify flags) */
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_freg);
/* The following flags are used by sljit_emit_mem(), sljit_emit_mem_update(),
sljit_emit_fmem(), and sljit_emit_fmem_update(). */
@@ -1524,9 +1740,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil
/* Load or stora data from an unaligned (byte aligned) address. */
#define SLJIT_MEM_UNALIGNED 0x000400
/* Load or stora data from a 16 bit aligned address. */
-#define SLJIT_MEM_UNALIGNED_16 0x000800
+#define SLJIT_MEM_ALIGNED_16 0x000800
/* Load or stora data from a 32 bit aligned address. */
-#define SLJIT_MEM_UNALIGNED_32 0x001000
+#define SLJIT_MEM_ALIGNED_32 0x001000
/* The following flags are used by sljit_emit_mem_update(),
and sljit_emit_fmem_update(). */
@@ -1544,8 +1760,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil
/* The sljit_emit_mem emits instructions for various memory operations:
- When SLJIT_MEM_UNALIGNED / SLJIT_MEM_UNALIGNED_16 /
- SLJIT_MEM_UNALIGNED_32 is set in type argument:
+ When SLJIT_MEM_UNALIGNED / SLJIT_MEM_ALIGNED_16 /
+ SLJIT_MEM_ALIGNED_32 is set in type argument:
Emit instructions for unaligned memory loads or stores. When
SLJIT_UNALIGNED is not defined, the only way to access unaligned
memory data is using sljit_emit_mem. Otherwise all operations (e.g.
@@ -1560,8 +1776,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil
location specified by the mem/memw arguments, and the end address
of this operation is the starting address of the data transfer
between the second register and memory. The type argument must
- be SLJIT_MOV. The SLJIT_MEM_UNALIGNED* options are allowed for
- this operation.
+ be SLJIT_MOV. The SLJIT_MEM_UNALIGNED / SLJIT_MEM_ALIGNED_*
+ options are allowed for this operation.
type must be between SLJIT_MOV and SLJIT_MOV_P and can be
combined (or'ed) with SLJIT_MEM_* flags
@@ -1625,6 +1841,286 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem_update(struct sljit_compiler
sljit_s32 freg,
sljit_s32 mem, sljit_sw memw);
+/* The following options are used by several simd operations. */
+
+/* Load data into a simd register, this is the default */
+#define SLJIT_SIMD_LOAD 0x000000
+/* Store data from a simd register */
+#define SLJIT_SIMD_STORE 0x000001
+/* The simd register contains floating point values */
+#define SLJIT_SIMD_FLOAT 0x000400
+/* Tests whether the operation is available */
+#define SLJIT_SIMD_TEST 0x000800
+/* Move data to/from a 64 bit (8 byte) long SIMD register */
+#define SLJIT_SIMD_REG_64 (3 << 12)
+/* Move data to/from a 128 bit (16 byte) long SIMD register */
+#define SLJIT_SIMD_REG_128 (4 << 12)
+/* Move data to/from a 256 bit (32 byte) long SIMD register */
+#define SLJIT_SIMD_REG_256 (5 << 12)
+/* Move data to/from a 512 bit (64 byte) long SIMD register */
+#define SLJIT_SIMD_REG_512 (6 << 12)
+/* Element size is 8 bit long (this is the default), usually cannot be combined with SLJIT_SIMD_FLOAT */
+#define SLJIT_SIMD_ELEM_8 (0 << 18)
+/* Element size is 16 bit long, usually cannot be combined with SLJIT_SIMD_FLOAT */
+#define SLJIT_SIMD_ELEM_16 (1 << 18)
+/* Element size is 32 bit long */
+#define SLJIT_SIMD_ELEM_32 (2 << 18)
+/* Element size is 64 bit long */
+#define SLJIT_SIMD_ELEM_64 (3 << 18)
+/* Element size is 128 bit long */
+#define SLJIT_SIMD_ELEM_128 (4 << 18)
+/* Element size is 256 bit long */
+#define SLJIT_SIMD_ELEM_256 (5 << 18)
+
+/* The following options are used by sljit_emit_simd_mov(). */
+
+/* Memory address is unaligned (this is the default) */
+#define SLJIT_SIMD_MEM_UNALIGNED (0 << 24)
+/* Memory address is 16 bit aligned */
+#define SLJIT_SIMD_MEM_ALIGNED_16 (1 << 24)
+/* Memory address is 32 bit aligned */
+#define SLJIT_SIMD_MEM_ALIGNED_32 (2 << 24)
+/* Memory address is 64 bit aligned */
+#define SLJIT_SIMD_MEM_ALIGNED_64 (3 << 24)
+/* Memory address is 128 bit aligned */
+#define SLJIT_SIMD_MEM_ALIGNED_128 (4 << 24)
+/* Memory address is 256 bit aligned */
+#define SLJIT_SIMD_MEM_ALIGNED_256 (5 << 24)
+/* Memory address is 512 bit aligned */
+#define SLJIT_SIMD_MEM_ALIGNED_512 (6 << 24)
+
+/* Moves data between a simd register and memory.
+
+ If the operation is not supported, it returns with
+ SLJIT_ERR_UNSUPPORTED. If SLJIT_SIMD_TEST is passed,
+ it does not emit any instructions.
+
+ type must be a combination of SLJIT_SIMD_* and
+ SLJIT_SIMD_MEM_* options
+ freg is the source or destination simd register
+ of the operation
+ srcdst must be a memory operand or a simd register
+
+ Note:
+ The alignment and element size must be
+ less or equal than simd register size.
+
+ Flags: - (does not modify flags) */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_mov(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 srcdst, sljit_sw srcdstw);
+
+/* Replicates a scalar value to all lanes of a simd
+ register.
+
+ If the operation is not supported, it returns with
+ SLJIT_ERR_UNSUPPORTED. If SLJIT_SIMD_TEST is passed,
+ it does not emit any instructions.
+
+ type must be a combination of SLJIT_SIMD_* options
+ except SLJIT_SIMD_STORE.
+ freg is the destination simd register of the operation
+ src is the value which is replicated
+
+ Note:
+ The src == SLJIT_IMM and srcw == 0 can be used to
+ clear a register even when SLJIT_SIMD_FLOAT is set.
+
+ Flags: - (does not modify flags) */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_sw srcw);
+
+/* The following options are used by sljit_emit_simd_lane_mov(). */
+
+/* Clear all bits of the simd register before loading the lane. */
+#define SLJIT_SIMD_LANE_ZERO 0x000002
+/* Sign extend the integer value stored from the lane. */
+#define SLJIT_SIMD_LANE_SIGNED 0x000004
+
+/* Moves data between a simd register lane and a register or
+ memory. If the srcdst argument is a register, it must be
+ a floating point register when SLJIT_SIMD_FLOAT is specified,
+ or a general purpose register otherwise.
+
+ If the operation is not supported, it returns with
+ SLJIT_ERR_UNSUPPORTED. If SLJIT_SIMD_TEST is passed,
+ it does not emit any instructions.
+
+ type must be a combination of SLJIT_SIMD_* options
+ Further options:
+ SLJIT_32 - when SLJIT_SIMD_FLOAT is not set
+ SLJIT_SIMD_LANE_SIGNED - when SLJIT_SIMD_STORE
+ is set and SLJIT_SIMD_FLOAT is not set
+ SLJIT_SIMD_LANE_ZERO - when SLJIT_SIMD_LOAD
+ is specified
+ freg is the source or destination simd register
+ of the operation
+ lane_index is the index of the lane
+ srcdst is the destination operand for loads, and
+ source operand for stores
+
+ Note:
+ The elem size must be lower than register size.
+
+ Flags: - (does not modify flags) */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg, sljit_s32 lane_index,
+ sljit_s32 srcdst, sljit_sw srcdstw);
+
+/* Replicates a scalar value from a lane to all lanes
+ of a simd register.
+
+ If the operation is not supported, it returns with
+ SLJIT_ERR_UNSUPPORTED. If SLJIT_SIMD_TEST is passed,
+ it does not emit any instructions.
+
+ type must be a combination of SLJIT_SIMD_* options
+ except SLJIT_SIMD_STORE.
+ freg is the destination simd register of the operation
+ src is the simd register which lane is replicated
+ src_lane_index is the lane index of the src register
+
+ Flags: - (does not modify flags) */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_s32 src_lane_index);
+
+/* The following options are used by sljit_emit_simd_load_extend(). */
+
+/* Sign extend the integer elements */
+#define SLJIT_SIMD_EXTEND_SIGNED 0x000002
+/* Extend data to 16 bit */
+#define SLJIT_SIMD_EXTEND_16 (1 << 24)
+/* Extend data to 32 bit */
+#define SLJIT_SIMD_EXTEND_32 (2 << 24)
+/* Extend data to 64 bit */
+#define SLJIT_SIMD_EXTEND_64 (3 << 24)
+
+/* Extend elements and stores them in a simd register.
+ The extension operation increases the size of the
+ elements (e.g. from 16 bit to 64 bit). For integer
+ values, the extension can be signed or unsigned.
+
+ If the operation is not supported, it returns with
+ SLJIT_ERR_UNSUPPORTED. If SLJIT_SIMD_TEST is passed,
+ it does not emit any instructions.
+
+ type must be a combination of SLJIT_SIMD_*, and
+ SLJIT_SIMD_EXTEND_* options except SLJIT_SIMD_STORE
+ freg is the destination simd register of the operation
+ src must be a memory operand or a simd register.
+ In the latter case, the source elements are stored
+ in the lower half of the register.
+
+ Flags: - (does not modify flags) */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_extend(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_sw srcw);
+
+/* Extract the highest bit (usually the sign bit) from
+ each elements of a vector.
+
+ If the operation is not supported, it returns with
+ SLJIT_ERR_UNSUPPORTED. If SLJIT_SIMD_TEST is passed,
+ it does not emit any instructions.
+
+ type must be a combination of SLJIT_SIMD_* and SLJIT_32
+ options except SLJIT_SIMD_LOAD
+ freg is the source simd register of the operation
+ dst is the destination operand
+
+ Flags: - (does not modify flags) */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 dst, sljit_sw dstw);
+
+/* The following options are used by sljit_emit_simd_op2(). */
+
+/* Binary 'and' operation */
+#define SLJIT_SIMD_OP2_AND 0x000001
+/* Binary 'or' operation */
+#define SLJIT_SIMD_OP2_OR 0x000002
+/* Binary 'xor' operation */
+#define SLJIT_SIMD_OP2_XOR 0x000003
+
+/* Perform simd operations using simd registers.
+
+ If the operation is not supported, it returns with
+ SLJIT_ERR_UNSUPPORTED. If SLJIT_SIMD_TEST is passed,
+ it does not emit any instructions.
+
+ type must be a combination of SLJIT_SIMD_* and SLJIT_SIMD_OP2_
+ options except SLJIT_SIMD_LOAD and SLJIT_SIMD_STORE
+ dst_freg is the destination register of the operation
+ src1_freg is the first source register of the operation
+ src1_freg is the second source register of the operation
+
+ Flags: - (does not modify flags) */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_op2(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg, sljit_s32 src1_freg, sljit_s32 src2_freg);
+
+/* The sljit_emit_atomic_load and sljit_emit_atomic_store operation pair
+ can perform an atomic read-modify-write operation. First, an unsigned
+ value must be loaded from memory using sljit_emit_atomic_load. Then,
+ the updated value must be written back to the same memory location by
+ sljit_emit_atomic_store. A thread can only perform a single atomic
+ operation at a time.
+
+ Note: atomic operations are experimental, and not implemented
+ for all cpus.
+
+ The following conditions must be satisfied, or the operation
+ is undefined:
+ - the address provided in mem_reg must be divisible by the size of
+ the value (only naturally aligned updates are supported)
+ - no memory writes are allowed between the load and store operations
+ regardless of its target address (currently read operations are
+ allowed, but this might change in the future)
+ - the memory operation (op) and the base address (stored in mem_reg)
+ passed to the load/store operations must be the same (the mem_reg
+ can be a different register, only its value must be the same)
+ - an store must always follow a load for the same transaction.
+
+ op must be between SLJIT_MOV and SLJIT_MOV_P, excluding all
+ signed loads such as SLJIT_MOV32_S16
+ dst_reg is the register where the data will be loaded into
+ mem_reg is the base address of the memory load (it cannot be
+ SLJIT_SP or a virtual register on x86-32)
+
+ Flags: - (does not modify flags) */
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_load(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_reg,
+ sljit_s32 mem_reg);
+
+/* The sljit_emit_atomic_load and sljit_emit_atomic_store operations
+ allows performing an atomic read-modify-write operation. See the
+ description of sljit_emit_atomic_load.
+
+ op must be between SLJIT_MOV and SLJIT_MOV_P, excluding all signed
+ loads such as SLJIT_MOV32_S16
+ src_reg is the register which value is stored into the memory
+ mem_reg is the base address of the memory store (it cannot be
+ SLJIT_SP or a virtual register on x86-32)
+ temp_reg is a not preserved scratch register, which must be
+ initialized with the value loaded into the dst_reg during the
+ corresponding sljit_emit_atomic_load operation, or the operation
+ is undefined
+
+ Flags: ATOMIC_STORED is set if the operation is successful,
+ otherwise the memory remains unchanged. */
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src_reg,
+ sljit_s32 mem_reg,
+ sljit_s32 temp_reg);
+
/* Copies the base address of SLJIT_SP + offset to dst. The offset can
represent the starting address of a value in the local data (stack).
The offset is not limited by the local data limits, it can be any value.
@@ -1665,30 +2161,39 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_consta
/* CPU specific functions */
/* --------------------------------------------------------------------- */
+/* Types for sljit_get_register_index */
+
+/* General purpose (integer) registers. */
+#define SLJIT_GP_REGISTER 0
+/* Floating point registers. */
+#define SLJIT_FLOAT_REGISTER 1
+
/* The following function is a helper function for sljit_emit_op_custom.
- It returns with the real machine register index ( >=0 ) of any SLJIT_R,
- SLJIT_S and SLJIT_SP registers.
+ It returns with the real machine register index ( >=0 ) of any registers.
- Note: it returns with -1 for virtual registers (only on x86-32). */
+ When type is SLJIT_GP_REGISTER:
+ reg must be an SLJIT_R(i), SLJIT_S(i), or SLJIT_SP register
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg);
+ When type is SLJIT_FLOAT_REGISTER:
+ reg must be an SLJIT_FR(i) or SLJIT_FS(i) register
-/* The following function is a helper function for sljit_emit_op_custom.
- It returns with the real machine register ( >= 0 ) index of any SLJIT_FR,
- and SLJIT_FS register.
+ When type is SLJIT_SIMD_REG_64 / 128 / 256 / 512 :
+ reg must be an SLJIT_FR(i) or SLJIT_FS(i) register
- Note: the index is always an even number on ARM-32, MIPS. */
+ Note: it returns with -1 for unknown registers, such as virtual
+ registers on x86-32 or unsupported simd registers. */
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg);
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 type, sljit_s32 reg);
/* Any instruction can be inserted into the instruction stream by
sljit_emit_op_custom. It has a similar purpose as inline assembly.
The size parameter must match to the instruction size of the target
architecture:
- x86: 0 < size <= 15. The instruction argument can be byte aligned.
+ x86: 0 < size <= 15, the instruction argument can be byte aligned.
Thumb2: if size == 2, the instruction argument must be 2 byte aligned.
if size == 4, the instruction argument must be 4 byte aligned.
+ s390x: size can be 2, 4, or 6, the instruction argument can be byte aligned.
Otherwise: size must be 4 and instruction argument must be 4 byte aligned. */
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
@@ -1725,7 +2230,8 @@ SLJIT_API_FUNC_ATTRIBUTE void sljit_set_current_flags(struct sljit_compiler *com
to know the type of the code generator. */
SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void);
-/* Portable helper function to get an offset of a member. */
+/* Portable helper function to get an offset of a member.
+ Same as offsetof() macro defined in stddef.h */
#define SLJIT_OFFSETOF(base, member) ((sljit_sw)(&((base*)0x10)->member) - 0x10)
#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK)
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeARM_32.c b/src/3rdparty/pcre2/src/sljit/sljitNativeARM_32.c
index 54b8ade063..d44616d800 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeARM_32.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeARM_32.c
@@ -34,13 +34,16 @@ SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
{
#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
return "ARMv7" SLJIT_CPUINFO ARM_ABI_INFO;
-#elif (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
- return "ARMv5" SLJIT_CPUINFO ARM_ABI_INFO;
+#elif (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
+ return "ARMv6" SLJIT_CPUINFO ARM_ABI_INFO;
#else
#error "Internal error: Unknown ARM architecture"
#endif
}
+/* Length of an instruction word. */
+typedef sljit_u32 sljit_ins;
+
/* Last register + 1. */
#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)
#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3)
@@ -55,27 +58,39 @@ SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
#define CONST_POOL_EMPTY 0xffffffff
#define ALIGN_INSTRUCTION(ptr) \
- (sljit_uw*)(((sljit_uw)(ptr) + (CONST_POOL_ALIGNMENT * sizeof(sljit_uw)) - 1) & ~((CONST_POOL_ALIGNMENT * sizeof(sljit_uw)) - 1))
+ (sljit_ins*)(((sljit_ins)(ptr) + (CONST_POOL_ALIGNMENT * sizeof(sljit_ins)) - 1) & ~((CONST_POOL_ALIGNMENT * sizeof(sljit_ins)) - 1))
#define MAX_DIFFERENCE(max_diff) \
- (((max_diff) / (sljit_s32)sizeof(sljit_uw)) - (CONST_POOL_ALIGNMENT - 1))
+ (((max_diff) / (sljit_s32)sizeof(sljit_ins)) - (CONST_POOL_ALIGNMENT - 1))
/* See sljit_emit_enter and sljit_emit_op0 if you want to change them. */
static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 5] = {
0, 0, 1, 2, 3, 11, 10, 9, 8, 7, 6, 5, 4, 13, 12, 14, 15
};
-static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
- 0, 0, 1, 2, 3, 4, 5, 15, 14, 13, 12, 11, 10, 9, 8, 6, 7
+static const sljit_u8 freg_map[((SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2) << 1) + 1] = {
+ 0,
+ 0, 1, 2, 3, 4, 5, 15, 14, 13, 12, 11, 10, 9, 8,
+ 7, 6,
+ 0, 1, 2, 3, 4, 5, 15, 14, 13, 12, 11, 10, 9, 8,
+ 7, 6
+};
+
+static const sljit_u8 freg_ebit_map[((SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2) << 1) + 1] = {
+ 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1
};
-#define RM(rm) ((sljit_uw)reg_map[rm])
-#define RM8(rm) ((sljit_uw)reg_map[rm] << 8)
-#define RD(rd) ((sljit_uw)reg_map[rd] << 12)
-#define RN(rn) ((sljit_uw)reg_map[rn] << 16)
+#define RM(rm) ((sljit_ins)reg_map[rm])
+#define RM8(rm) ((sljit_ins)reg_map[rm] << 8)
+#define RD(rd) ((sljit_ins)reg_map[rd] << 12)
+#define RN(rn) ((sljit_ins)reg_map[rn] << 16)
-#define VM(rm) ((sljit_uw)freg_map[rm])
-#define VD(rd) ((sljit_uw)freg_map[rd] << 12)
-#define VN(rn) ((sljit_uw)freg_map[rn] << 16)
+#define VM(vm) (((sljit_ins)freg_map[vm]) | ((sljit_ins)freg_ebit_map[vm] << 5))
+#define VD(vd) (((sljit_ins)freg_map[vd] << 12) | ((sljit_ins)freg_ebit_map[vd] << 22))
+#define VN(vn) (((sljit_ins)freg_map[vn] << 16) | ((sljit_ins)freg_ebit_map[vn] << 7))
/* --------------------------------------------------------------------- */
/* Instrucion forms */
@@ -92,16 +107,19 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
#define AND 0xe0000000
#define B 0xea000000
#define BIC 0xe1c00000
+#define BKPT 0xe1200070
#define BL 0xeb000000
#define BLX 0xe12fff30
#define BX 0xe12fff10
#define CLZ 0xe16f0f10
#define CMN 0xe1600000
#define CMP 0xe1400000
-#define BKPT 0xe1200070
#define EOR 0xe0200000
#define LDR 0xe5100000
#define LDR_POST 0xe4100000
+#define LDREX 0xe1900f9f
+#define LDREXB 0xe1d00f9f
+#define LDREXH 0xe1f00f9f
#define MOV 0xe1a00000
#define MUL 0xe0000090
#define MVN 0xe1e00000
@@ -109,50 +127,89 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
#define ORR 0xe1800000
#define PUSH 0xe92d0000
#define POP 0xe8bd0000
-#define RBIT 0xe6ff0f30
+#define REV 0xe6bf0f30
+#define REV16 0xe6bf0fb0
#define RSB 0xe0600000
#define RSC 0xe0e00000
#define SBC 0xe0c00000
#define SMULL 0xe0c00090
#define STR 0xe5000000
+#define STREX 0xe1800f90
+#define STREXB 0xe1c00f90
+#define STREXH 0xe1e00f90
#define SUB 0xe0400000
+#define SXTB 0xe6af0070
+#define SXTH 0xe6bf0070
#define TST 0xe1000000
#define UMULL 0xe0800090
+#define UXTB 0xe6ef0070
+#define UXTH 0xe6ff0070
#define VABS_F32 0xeeb00ac0
#define VADD_F32 0xee300a00
+#define VAND 0xf2000110
#define VCMP_F32 0xeeb40a40
#define VCVT_F32_S32 0xeeb80ac0
+#define VCVT_F32_U32 0xeeb80a40
#define VCVT_F64_F32 0xeeb70ac0
#define VCVT_S32_F32 0xeebd0ac0
#define VDIV_F32 0xee800a00
+#define VDUP 0xee800b10
+#define VDUP_s 0xf3b00c00
+#define VEOR 0xf3000110
+#define VLD1 0xf4200000
+#define VLD1_r 0xf4a00c00
+#define VLD1_s 0xf4a00000
#define VLDR_F32 0xed100a00
#define VMOV_F32 0xeeb00a40
#define VMOV 0xee000a10
#define VMOV2 0xec400a10
+#define VMOV_i 0xf2800010
+#define VMOV_s 0xee000b10
+#define VMOVN 0xf3b20200
#define VMRS 0xeef1fa10
#define VMUL_F32 0xee200a00
#define VNEG_F32 0xeeb10a40
+#define VORR 0xf2200110
#define VPOP 0xecbd0b00
#define VPUSH 0xed2d0b00
+#define VSHLL 0xf2800a10
+#define VSHR 0xf2800010
+#define VSRA 0xf2800110
+#define VST1 0xf4000000
+#define VST1_s 0xf4800000
#define VSTR_F32 0xed000a00
#define VSUB_F32 0xee300a40
#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
/* Arm v7 specific instructions. */
-#define MOVW 0xe3000000
#define MOVT 0xe3400000
-#define SXTB 0xe6af0070
-#define SXTH 0xe6bf0070
-#define UXTB 0xe6ef0070
-#define UXTH 0xe6ff0070
+#define MOVW 0xe3000000
+#define RBIT 0xe6ff0f30
#endif
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+
+static sljit_s32 function_check_is_freg(struct sljit_compiler *compiler, sljit_s32 fr, sljit_s32 is_32)
+{
+ if (compiler->scratches == -1)
+ return 0;
+
+ if (is_32 && fr >= SLJIT_F64_SECOND(SLJIT_FR0))
+ fr -= SLJIT_F64_SECOND(0);
+
+ return (fr >= SLJIT_FR0 && fr < (SLJIT_FR0 + compiler->fscratches))
+ || (fr > (SLJIT_FS0 - compiler->fsaveds) && fr <= SLJIT_FS0)
+ || (fr >= SLJIT_TMP_FREGISTER_BASE && fr < (SLJIT_TMP_FREGISTER_BASE + SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS));
+}
+
+#endif /* SLJIT_ARGUMENT_CHECKS */
+
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
static sljit_s32 push_cpool(struct sljit_compiler *compiler)
{
/* Pushing the constant pool into the instruction stream. */
- sljit_uw* inst;
+ sljit_ins* inst;
sljit_uw* cpool_ptr;
sljit_uw* cpool_end;
sljit_s32 i;
@@ -162,13 +219,13 @@ static sljit_s32 push_cpool(struct sljit_compiler *compiler)
compiler->last_label->size += compiler->cpool_fill + (CONST_POOL_ALIGNMENT - 1) + 1;
SLJIT_ASSERT(compiler->cpool_fill > 0 && compiler->cpool_fill <= CPOOL_SIZE);
- inst = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
+ inst = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
FAIL_IF(!inst);
compiler->size++;
*inst = 0xff000000 | compiler->cpool_fill;
for (i = 0; i < CONST_POOL_ALIGNMENT - 1; i++) {
- inst = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
+ inst = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
FAIL_IF(!inst);
compiler->size++;
*inst = 0;
@@ -177,7 +234,7 @@ static sljit_s32 push_cpool(struct sljit_compiler *compiler)
cpool_ptr = compiler->cpool;
cpool_end = cpool_ptr + compiler->cpool_fill;
while (cpool_ptr < cpool_end) {
- inst = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
+ inst = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
FAIL_IF(!inst);
compiler->size++;
*inst = *cpool_ptr++;
@@ -187,23 +244,23 @@ static sljit_s32 push_cpool(struct sljit_compiler *compiler)
return SLJIT_SUCCESS;
}
-static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_uw inst)
+static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins inst)
{
- sljit_uw* ptr;
+ sljit_ins* ptr;
if (SLJIT_UNLIKELY(compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4092)))
FAIL_IF(push_cpool(compiler));
- ptr = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
+ ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
FAIL_IF(!ptr);
compiler->size++;
*ptr = inst;
return SLJIT_SUCCESS;
}
-static sljit_s32 push_inst_with_literal(struct sljit_compiler *compiler, sljit_uw inst, sljit_uw literal)
+static sljit_s32 push_inst_with_literal(struct sljit_compiler *compiler, sljit_ins inst, sljit_uw literal)
{
- sljit_uw* ptr;
+ sljit_ins* ptr;
sljit_uw cpool_index = CPOOL_SIZE;
sljit_uw* cpool_ptr;
sljit_uw* cpool_end;
@@ -239,7 +296,7 @@ static sljit_s32 push_inst_with_literal(struct sljit_compiler *compiler, sljit_u
}
SLJIT_ASSERT((inst & 0xfff) == 0);
- ptr = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
+ ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
FAIL_IF(!ptr);
compiler->size++;
*ptr = inst | cpool_index;
@@ -251,14 +308,15 @@ static sljit_s32 push_inst_with_literal(struct sljit_compiler *compiler, sljit_u
return SLJIT_SUCCESS;
}
-static sljit_s32 push_inst_with_unique_literal(struct sljit_compiler *compiler, sljit_uw inst, sljit_uw literal)
+static sljit_s32 push_inst_with_unique_literal(struct sljit_compiler *compiler, sljit_ins inst, sljit_uw literal)
{
- sljit_uw* ptr;
+ sljit_ins* ptr;
+
if (SLJIT_UNLIKELY((compiler->cpool_diff != CONST_POOL_EMPTY && compiler->size - compiler->cpool_diff >= MAX_DIFFERENCE(4092)) || compiler->cpool_fill >= CPOOL_SIZE))
FAIL_IF(push_cpool(compiler));
SLJIT_ASSERT(compiler->cpool_fill < CPOOL_SIZE && (inst & 0xfff) == 0);
- ptr = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
+ ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
FAIL_IF(!ptr);
compiler->size++;
*ptr = inst | compiler->cpool_fill;
@@ -305,7 +363,7 @@ static sljit_uw patch_pc_relative_loads(sljit_uw *last_pc_patch, sljit_uw *code_
while (last_pc_patch < code_ptr) {
/* Data transfer instruction with Rn == r15. */
- if ((*last_pc_patch & 0x0c0f0000) == 0x040f0000) {
+ if ((*last_pc_patch & 0x0e0f0000) == 0x040f0000) {
diff = (sljit_uw)(const_pool - last_pc_patch);
ind = (*last_pc_patch) & 0xfff;
@@ -395,11 +453,11 @@ static sljit_s32 resolve_const_pool_index(struct sljit_compiler *compiler, struc
#else
-static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_uw inst)
+static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins inst)
{
- sljit_uw* ptr;
+ sljit_ins* ptr;
- ptr = (sljit_uw*)ensure_buf(compiler, sizeof(sljit_uw));
+ ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
FAIL_IF(!ptr);
compiler->size++;
*ptr = inst;
@@ -421,7 +479,7 @@ static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_uw
if (jump->flags & SLJIT_REWRITABLE_JUMP)
return 0;
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
if (jump->flags & IS_BL)
code_ptr--;
@@ -449,7 +507,7 @@ static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_uw
jump->flags |= PATCH_B;
}
}
-#else
+#else /* !SLJIT_CONFIG_ARM_V6 */
if (jump->flags & JUMP_ADDR)
diff = ((sljit_sw)jump->u.target - (sljit_sw)code_ptr - executable_offset);
else {
@@ -467,16 +525,16 @@ static SLJIT_INLINE sljit_s32 detect_jump_type(struct sljit_jump *jump, sljit_uw
jump->flags |= PATCH_B;
return 1;
}
-#endif
+#endif /* SLJIT_CONFIG_ARM_V6 */
return 0;
}
static SLJIT_INLINE void inline_set_jump_addr(sljit_uw jump_ptr, sljit_sw executable_offset, sljit_uw new_addr, sljit_s32 flush_cache)
{
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
- sljit_uw *ptr = (sljit_uw *)jump_ptr;
- sljit_uw *inst = (sljit_uw *)ptr[0];
- sljit_uw mov_pc = ptr[1];
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
+ sljit_ins *ptr = (sljit_ins*)jump_ptr;
+ sljit_ins *inst = (sljit_ins*)ptr[0];
+ sljit_ins mov_pc = ptr[1];
sljit_s32 bl = (mov_pc & 0x0000f000) != RD(TMP_PC);
sljit_sw diff = (sljit_sw)(((sljit_sw)new_addr - (sljit_sw)(inst + 2) - executable_offset) >> 2);
@@ -491,7 +549,7 @@ static SLJIT_INLINE void inline_set_jump_addr(sljit_uw jump_ptr, sljit_sw execut
inst[0] = (mov_pc & COND_MASK) | (B - CONDITIONAL) | (diff & 0xffffff);
if (flush_cache) {
SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);
- inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+ inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 1);
}
} else {
@@ -502,7 +560,7 @@ static SLJIT_INLINE void inline_set_jump_addr(sljit_uw jump_ptr, sljit_sw execut
inst[1] = NOP;
if (flush_cache) {
SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
- inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+ inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 2);
}
}
@@ -521,14 +579,14 @@ static SLJIT_INLINE void inline_set_jump_addr(sljit_uw jump_ptr, sljit_sw execut
if (!bl) {
if (flush_cache) {
SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);
- inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+ inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 1);
}
} else {
inst[1] = BLX | RM(TMP_REG1);
if (flush_cache) {
SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
- inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+ inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 2);
}
}
@@ -544,8 +602,8 @@ static SLJIT_INLINE void inline_set_jump_addr(sljit_uw jump_ptr, sljit_sw execut
SLJIT_UPDATE_WX_FLAGS(ptr, ptr + 1, 1);
}
}
-#else
- sljit_uw *inst = (sljit_uw*)jump_ptr;
+#else /* !SLJIT_CONFIG_ARM_V6 */
+ sljit_ins *inst = (sljit_ins*)jump_ptr;
SLJIT_UNUSED_ARG(executable_offset);
@@ -560,10 +618,10 @@ static SLJIT_INLINE void inline_set_jump_addr(sljit_uw jump_ptr, sljit_sw execut
if (flush_cache) {
SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
- inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+ inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 2);
}
-#endif
+#endif /* SLJIT_CONFIG_ARM_V6 */
}
static sljit_uw get_imm(sljit_uw imm);
@@ -572,9 +630,9 @@ static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, s
static SLJIT_INLINE void inline_set_const(sljit_uw addr, sljit_sw executable_offset, sljit_uw new_constant, sljit_s32 flush_cache)
{
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
- sljit_uw *ptr = (sljit_uw*)addr;
- sljit_uw *inst = (sljit_uw*)ptr[0];
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
+ sljit_ins *ptr = (sljit_ins*)addr;
+ sljit_ins *inst = (sljit_ins*)ptr[0];
sljit_uw ldr_literal = ptr[1];
sljit_uw src2;
@@ -590,7 +648,7 @@ static SLJIT_INLINE void inline_set_const(sljit_uw addr, sljit_sw executable_off
if (flush_cache) {
SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);
- inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+ inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 1);
}
return;
@@ -606,7 +664,7 @@ static SLJIT_INLINE void inline_set_const(sljit_uw addr, sljit_sw executable_off
if (flush_cache) {
SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);
- inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+ inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 1);
}
return;
@@ -626,7 +684,7 @@ static SLJIT_INLINE void inline_set_const(sljit_uw addr, sljit_sw executable_off
if (flush_cache) {
SLJIT_UPDATE_WX_FLAGS(inst, inst + 1, 1);
- inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+ inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 1);
}
}
@@ -640,8 +698,8 @@ static SLJIT_INLINE void inline_set_const(sljit_uw addr, sljit_sw executable_off
if (flush_cache) {
SLJIT_UPDATE_WX_FLAGS(ptr, ptr + 1, 1);
}
-#else
- sljit_uw *inst = (sljit_uw*)addr;
+#else /* !SLJIT_CONFIG_ARM_V6 */
+ sljit_ins *inst = (sljit_ins*)addr;
SLJIT_UNUSED_ARG(executable_offset);
@@ -656,30 +714,30 @@ static SLJIT_INLINE void inline_set_const(sljit_uw addr, sljit_sw executable_off
if (flush_cache) {
SLJIT_UPDATE_WX_FLAGS(inst, inst + 2, 1);
- inst = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
+ inst = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(inst, executable_offset);
SLJIT_CACHE_FLUSH(inst, inst + 2);
}
-#endif
+#endif /* SLJIT_CONFIG_ARM_V6 */
}
SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compiler)
{
struct sljit_memory_fragment *buf;
- sljit_uw *code;
- sljit_uw *code_ptr;
- sljit_uw *buf_ptr;
- sljit_uw *buf_end;
+ sljit_ins *code;
+ sljit_ins *code_ptr;
+ sljit_ins *buf_ptr;
+ sljit_ins *buf_end;
sljit_uw size;
sljit_uw word_count;
sljit_uw next_addr;
sljit_sw executable_offset;
sljit_uw addr;
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
sljit_uw cpool_size;
sljit_uw cpool_skip_alignment;
sljit_uw cpool_current_index;
- sljit_uw *cpool_start_address;
- sljit_uw *last_pc_patch;
+ sljit_ins *cpool_start_address;
+ sljit_ins *last_pc_patch;
struct future_patch *first_patch;
#endif
@@ -693,25 +751,25 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
reverse_buf(compiler);
/* Second code generation pass. */
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
size = compiler->size + (compiler->patches << 1);
if (compiler->cpool_fill > 0)
size += compiler->cpool_fill + CONST_POOL_ALIGNMENT - 1;
-#else
+#else /* !SLJIT_CONFIG_ARM_V6 */
size = compiler->size;
-#endif
- code = (sljit_uw*)SLJIT_MALLOC_EXEC(size * sizeof(sljit_uw), compiler->exec_allocator_data);
+#endif /* SLJIT_CONFIG_ARM_V6 */
+ code = (sljit_ins*)SLJIT_MALLOC_EXEC(size * sizeof(sljit_ins), compiler->exec_allocator_data);
PTR_FAIL_WITH_EXEC_IF(code);
buf = compiler->buf;
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
cpool_size = 0;
cpool_skip_alignment = 0;
cpool_current_index = 0;
cpool_start_address = NULL;
first_patch = NULL;
last_pc_patch = code;
-#endif
+#endif /* SLJIT_CONFIG_ARM_V6 */
code_ptr = code;
word_count = 0;
@@ -729,11 +787,11 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
}
do {
- buf_ptr = (sljit_uw*)buf->memory;
+ buf_ptr = (sljit_ins*)buf->memory;
buf_end = buf_ptr + (buf->used_size >> 2);
do {
word_count++;
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
if (cpool_size > 0) {
if (cpool_skip_alignment > 0) {
buf_ptr++;
@@ -761,7 +819,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
}
}
else if ((*buf_ptr & 0xff000000) != PUSH_POOL) {
-#endif
+#endif /* SLJIT_CONFIG_ARM_V6 */
*code_ptr = *buf_ptr++;
if (next_addr == word_count) {
SLJIT_ASSERT(!label || label->size >= word_count);
@@ -771,15 +829,15 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
/* These structures are ordered by their address. */
if (jump && jump->addr == word_count) {
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
if (detect_jump_type(jump, code_ptr, code, executable_offset))
code_ptr--;
jump->addr = (sljit_uw)code_ptr;
-#else
+#else /* !SLJIT_CONFIG_ARM_V6 */
jump->addr = (sljit_uw)(code_ptr - 2);
if (detect_jump_type(jump, code_ptr, code, executable_offset))
code_ptr -= 2;
-#endif
+#endif /* SLJIT_CONFIG_ARM_V6 */
jump = jump->next;
}
if (label && label->size == word_count) {
@@ -789,11 +847,11 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
label = label->next;
}
if (const_ && const_->addr == word_count) {
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
const_->addr = (sljit_uw)code_ptr;
-#else
+#else /* !SLJIT_CONFIG_ARM_V6 */
const_->addr = (sljit_uw)(code_ptr - 1);
-#endif
+#endif /* SLJIT_CONFIG_ARM_V6 */
const_ = const_->next;
}
if (put_label && put_label->addr == word_count) {
@@ -804,9 +862,8 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
next_addr = compute_next_addr(label, jump, const_, put_label);
}
code_ptr++;
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
- }
- else {
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
+ } else {
/* Fortunately, no need to shift. */
cpool_size = *buf_ptr++ & ~PUSH_POOL;
SLJIT_ASSERT(cpool_size > 0);
@@ -814,14 +871,14 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
cpool_current_index = patch_pc_relative_loads(last_pc_patch, code_ptr, cpool_start_address, cpool_size);
if (cpool_current_index > 0) {
/* Unconditional branch. */
- *code_ptr = B | (((sljit_uw)(cpool_start_address - code_ptr) + cpool_current_index - 2) & ~PUSH_POOL);
- code_ptr = (sljit_uw*)(cpool_start_address + cpool_current_index);
+ *code_ptr = B | (((sljit_ins)(cpool_start_address - code_ptr) + cpool_current_index - 2) & ~PUSH_POOL);
+ code_ptr = (sljit_ins*)(cpool_start_address + cpool_current_index);
}
cpool_skip_alignment = CONST_POOL_ALIGNMENT - 1;
cpool_current_index = 0;
last_pc_patch = code_ptr;
}
-#endif
+#endif /* SLJIT_CONFIG_ARM_V6 */
} while (buf_ptr < buf_end);
buf = buf->next;
} while (buf);
@@ -831,13 +888,13 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
SLJIT_ASSERT(!const_);
SLJIT_ASSERT(!put_label);
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
SLJIT_ASSERT(cpool_size == 0);
if (compiler->cpool_fill > 0) {
cpool_start_address = ALIGN_INSTRUCTION(code_ptr);
cpool_current_index = patch_pc_relative_loads(last_pc_patch, code_ptr, cpool_start_address, compiler->cpool_fill);
if (cpool_current_index > 0)
- code_ptr = (sljit_uw*)(cpool_start_address + cpool_current_index);
+ code_ptr = (sljit_ins*)(cpool_start_address + cpool_current_index);
buf_ptr = compiler->cpool;
buf_end = buf_ptr + compiler->cpool_fill;
@@ -857,7 +914,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
jump = compiler->jumps;
while (jump) {
- buf_ptr = (sljit_uw *)jump->addr;
+ buf_ptr = (sljit_ins*)jump->addr;
if (jump->flags & PATCH_B) {
addr = (sljit_uw)SLJIT_ADD_EXEC_OFFSET(buf_ptr + 2, executable_offset);
@@ -872,18 +929,17 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
}
}
else if (jump->flags & SLJIT_REWRITABLE_JUMP) {
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
jump->addr = (sljit_uw)code_ptr;
- code_ptr[0] = (sljit_uw)buf_ptr;
+ code_ptr[0] = (sljit_ins)buf_ptr;
code_ptr[1] = *buf_ptr;
inline_set_jump_addr((sljit_uw)code_ptr, executable_offset, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0);
code_ptr += 2;
-#else
+#else /* !SLJIT_CONFIG_ARM_V6 */
inline_set_jump_addr((sljit_uw)buf_ptr, executable_offset, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0);
-#endif
- }
- else {
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#endif /* SLJIT_CONFIG_ARM_V6 */
+ } else {
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
if (jump->flags & IS_BL)
buf_ptr--;
if (*buf_ptr & (1 << 23))
@@ -891,20 +947,20 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
else
buf_ptr += 1;
*buf_ptr = (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target;
-#else
+#else /* !SLJIT_CONFIG_ARM_V6 */
inline_set_jump_addr((sljit_uw)buf_ptr, executable_offset, (jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target, 0);
-#endif
+#endif /* SLJIT_CONFIG_ARM_V6 */
}
jump = jump->next;
}
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
const_ = compiler->consts;
while (const_) {
- buf_ptr = (sljit_uw*)const_->addr;
+ buf_ptr = (sljit_ins*)const_->addr;
const_->addr = (sljit_uw)code_ptr;
- code_ptr[0] = (sljit_uw)buf_ptr;
+ code_ptr[0] = (sljit_ins)buf_ptr;
code_ptr[1] = *buf_ptr;
if (*buf_ptr & (1 << 23))
buf_ptr += ((*buf_ptr & 0xfff) >> 2) + 2;
@@ -916,21 +972,21 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
const_ = const_->next;
}
-#endif
+#endif /* SLJIT_CONFIG_ARM_V6 */
put_label = compiler->put_labels;
while (put_label) {
addr = put_label->label->addr;
- buf_ptr = (sljit_uw*)put_label->addr;
+ buf_ptr = (sljit_ins*)put_label->addr;
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
SLJIT_ASSERT((buf_ptr[0] & 0xffff0000) == 0xe59f0000);
buf_ptr[((buf_ptr[0] & 0xfff) >> 2) + 2] = addr;
-#else
+#else /* !SLJIT_CONFIG_ARM_V6 */
SLJIT_ASSERT((buf_ptr[-1] & 0xfff00000) == MOVW && (buf_ptr[0] & 0xfff00000) == MOVT);
buf_ptr[-1] |= ((addr << 4) & 0xf0000) | (addr & 0xfff);
buf_ptr[0] |= ((addr >> 12) & 0xf0000) | ((addr >> 16) & 0xfff);
-#endif
+#endif /* SLJIT_CONFIG_ARM_V6 */
put_label = put_label->next;
}
@@ -940,8 +996,8 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
compiler->executable_offset = executable_offset;
compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_uw);
- code = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
- code_ptr = (sljit_uw *)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
+ code = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
+ code_ptr = (sljit_ins*)SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
SLJIT_CACHE_FLUSH(code, code_ptr);
SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1);
@@ -952,26 +1008,42 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
{
switch (feature_type) {
case SLJIT_HAS_FPU:
+ case SLJIT_HAS_F64_AS_F32_PAIR:
#ifdef SLJIT_IS_FPU_AVAILABLE
- return SLJIT_IS_FPU_AVAILABLE;
+ return (SLJIT_IS_FPU_AVAILABLE) != 0;
#else
/* Available by default. */
return 1;
-#endif
+#endif /* SLJIT_IS_FPU_AVAILABLE */
+ case SLJIT_HAS_SIMD:
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
+ return 0;
+#else
+#ifdef SLJIT_IS_FPU_AVAILABLE
+ return (SLJIT_IS_FPU_AVAILABLE) != 0;
+#else
+ /* Available by default. */
+ return 1;
+#endif /* SLJIT_IS_FPU_AVAILABLE */
+#endif /* SLJIT_CONFIG_ARM_V6 */
+ case SLJIT_SIMD_REGS_ARE_PAIRS:
case SLJIT_HAS_CLZ:
case SLJIT_HAS_ROT:
case SLJIT_HAS_CMOV:
-#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
- case SLJIT_HAS_CTZ:
+ case SLJIT_HAS_REV:
case SLJIT_HAS_PREFETCH:
-#endif
+ case SLJIT_HAS_COPY_F32:
+ case SLJIT_HAS_COPY_F64:
+ case SLJIT_HAS_ATOMIC:
return 1;
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
case SLJIT_HAS_CTZ:
+#if defined(SLJIT_CONFIG_ARM_V6) && SLJIT_CONFIG_ARM_V6
return 2;
-#endif
+#else
+ return 1;
+#endif /* SLJIT_CONFIG_ARM_V6 */
default:
return 0;
@@ -991,17 +1063,18 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
#define LOAD_DATA 0x08
/* Flag bits for emit_op. */
-#define ALLOW_IMM 0x10
-#define ALLOW_INV_IMM 0x20
-#define ALLOW_ANY_IMM (ALLOW_IMM | ALLOW_INV_IMM)
-#define ALLOW_NEG_IMM 0x40
+#define ALLOW_IMM 0x10
+#define ALLOW_INV_IMM 0x20
+#define ALLOW_ANY_IMM (ALLOW_IMM | ALLOW_INV_IMM)
+#define ALLOW_NEG_IMM 0x40
+#define ALLOW_DOUBLE_IMM 0x80
/* s/l - store/load (1 bit)
u/s - signed/unsigned (1 bit)
w/b/h/N - word/byte/half/NOT allowed (2 bit)
Storing signed and unsigned values are the same operations. */
-static const sljit_uw data_transfer_insts[16] = {
+static const sljit_ins data_transfer_insts[16] = {
/* s u w */ 0xe5000000 /* str */,
/* s u b */ 0xe5400000 /* strb */,
/* s u h */ 0xe10000b0 /* strh */,
@@ -1022,7 +1095,7 @@ static const sljit_uw data_transfer_insts[16] = {
};
#define EMIT_DATA_TRANSFER(type, add, target_reg, base_reg, arg) \
- (data_transfer_insts[(type) & 0xf] | ((add) << 23) | RD(target_reg) | RN(base_reg) | (sljit_uw)(arg))
+ (data_transfer_insts[(type) & 0xf] | ((add) << 23) | RD(target_reg) | RN(base_reg) | (sljit_ins)(arg))
/* Normal ldr/str instruction.
Type2: ldrsb, ldrh, ldrsh */
@@ -1032,7 +1105,7 @@ static const sljit_uw data_transfer_insts[16] = {
(((imm) & 0xf) | (((imm) & 0xf0) << 4) | (1 << 22))
#define EMIT_FPU_OPERATION(opcode, mode, dst, src1, src2) \
- ((sljit_uw)(opcode) | (sljit_uw)(mode) | VD(dst) | VM(src1) | VN(src2))
+ ((sljit_ins)(opcode) | (sljit_ins)(mode) | VD(dst) | VM(src1) | VN(src2))
/* Flags for emit_op: */
/* Arguments are swapped. */
@@ -1104,12 +1177,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
}
if (fsaveds + fscratches >= SLJIT_NUMBER_OF_FLOAT_REGISTERS) {
- FAIL_IF(push_inst(compiler, VPUSH | VD(SLJIT_FS0) | ((sljit_uw)SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS << 1)));
+ FAIL_IF(push_inst(compiler, VPUSH | VD(SLJIT_FS0) | ((sljit_ins)SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS << 1)));
} else {
if (fsaveds > 0)
- FAIL_IF(push_inst(compiler, VPUSH | VD(SLJIT_FS0) | ((sljit_uw)fsaveds << 1)));
+ FAIL_IF(push_inst(compiler, VPUSH | VD(SLJIT_FS0) | ((sljit_ins)fsaveds << 1)));
if (fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG)
- FAIL_IF(push_inst(compiler, VPUSH | VD(fscratches) | ((sljit_uw)(fscratches - (SLJIT_FIRST_SAVED_FLOAT_REG - 1)) << 1)));
+ FAIL_IF(push_inst(compiler, VPUSH | VD(fscratches) | ((sljit_ins)(fscratches - (SLJIT_FIRST_SAVED_FLOAT_REG - 1)) << 1)));
}
}
@@ -1138,7 +1211,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
FAIL_IF(push_inst(compiler, VMOV2 | (offset << 10) | ((offset + sizeof(sljit_sw)) << 14) | float_arg_count));
else
FAIL_IF(push_inst(compiler, VLDR_F32 | 0x800100 | RN(SLJIT_SP)
- | (float_arg_count << 12) | ((offset + (sljit_uw)size - 4 * sizeof(sljit_sw)) >> 2)));
+ | (float_arg_count << 12) | ((offset + (sljit_ins)size - 4 * sizeof(sljit_sw)) >> 2)));
float_arg_count++;
offset += sizeof(sljit_f64) - sizeof(sljit_sw);
break;
@@ -1147,7 +1220,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
FAIL_IF(push_inst(compiler, VMOV | (float_arg_count << 16) | (offset << 10)));
else
FAIL_IF(push_inst(compiler, VLDR_F32 | 0x800000 | RN(SLJIT_SP)
- | (float_arg_count << 12) | ((offset + (sljit_uw)size - 4 * sizeof(sljit_sw)) >> 2)));
+ | (float_arg_count << 12) | ((offset + (sljit_ins)size - 4 * sizeof(sljit_sw)) >> 2)));
float_arg_count++;
break;
default:
@@ -1164,7 +1237,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
if (offset < 4 * sizeof(sljit_sw))
FAIL_IF(push_inst(compiler, MOV | RD(tmp) | (offset >> 2)));
else
- FAIL_IF(push_inst(compiler, LDR | 0x800000 | RN(SLJIT_SP) | RD(tmp) | (offset + (sljit_uw)size - 4 * sizeof(sljit_sw))));
+ FAIL_IF(push_inst(compiler, LDR | 0x800000 | RN(SLJIT_SP) | RD(tmp) | (offset + (sljit_ins)size - 4 * sizeof(sljit_sw))));
break;
}
@@ -1217,7 +1290,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
#endif
if (local_size > 0)
- FAIL_IF(emit_op(compiler, SLJIT_SUB, ALLOW_IMM, SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, local_size));
+ FAIL_IF(emit_op(compiler, SLJIT_SUB, ALLOW_IMM | ALLOW_DOUBLE_IMM, SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, local_size));
return SLJIT_SUCCESS;
}
@@ -1234,6 +1307,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *comp
size = GET_SAVED_REGISTERS_SIZE(scratches, saveds - SLJIT_KEPT_SAVEDS_COUNT(options), 1);
+ /* Doubles are saved, so alignment is unaffected. */
if ((size & SSIZE_OF(sw)) != 0 && (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG))
size += SSIZE_OF(sw);
@@ -1245,13 +1319,8 @@ static sljit_s32 emit_add_sp(struct sljit_compiler *compiler, sljit_uw imm)
{
sljit_uw imm2 = get_imm(imm);
- if (imm2 == 0) {
- imm2 = (imm & ~(sljit_uw)0x3ff) >> 10;
- imm = (imm & 0x3ff) >> 2;
-
- FAIL_IF(push_inst(compiler, ADD | SRC2_IMM | RD(SLJIT_SP) | RN(SLJIT_SP) | 0xb00 | imm2));
- return push_inst(compiler, ADD | SRC2_IMM | RD(SLJIT_SP) | RN(SLJIT_SP) | 0xf00 | (imm & 0xff));
- }
+ if (imm2 == 0)
+ return emit_op(compiler, SLJIT_ADD, ALLOW_IMM | ALLOW_DOUBLE_IMM, SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, (sljit_sw)imm);
return push_inst(compiler, ADD | RD(SLJIT_SP) | RN(SLJIT_SP) | imm2);
}
@@ -1274,12 +1343,12 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit
FAIL_IF(emit_add_sp(compiler, (sljit_uw)local_size));
if (fsaveds + fscratches >= SLJIT_NUMBER_OF_FLOAT_REGISTERS) {
- FAIL_IF(push_inst(compiler, VPOP | VD(SLJIT_FS0) | ((sljit_uw)SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS << 1)));
+ FAIL_IF(push_inst(compiler, VPOP | VD(SLJIT_FS0) | ((sljit_ins)SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS << 1)));
} else {
if (fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG)
- FAIL_IF(push_inst(compiler, VPOP | VD(fscratches) | ((sljit_uw)(fscratches - (SLJIT_FIRST_SAVED_FLOAT_REG - 1)) << 1)));
+ FAIL_IF(push_inst(compiler, VPOP | VD(fscratches) | ((sljit_ins)(fscratches - (SLJIT_FIRST_SAVED_FLOAT_REG - 1)) << 1)));
if (fsaveds > 0)
- FAIL_IF(push_inst(compiler, VPOP | VD(SLJIT_FS0) | ((sljit_uw)fsaveds << 1)));
+ FAIL_IF(push_inst(compiler, VPOP | VD(SLJIT_FS0) | ((sljit_ins)fsaveds << 1)));
}
local_size = GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds, 1) & 0x7;
@@ -1330,10 +1399,10 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit
if (frame_size == 0)
return push_inst(compiler, LDR_POST | RN(SLJIT_SP) | RD(restored_reg) | 0x800008);
if (frame_size > 2 * SSIZE_OF(sw))
- return push_inst(compiler, LDR_POST | RN(SLJIT_SP) | RD(restored_reg) | (sljit_uw)(frame_size - (2 * SSIZE_OF(sw))));
+ return push_inst(compiler, LDR_POST | RN(SLJIT_SP) | RD(restored_reg) | (sljit_ins)(frame_size - (2 * SSIZE_OF(sw))));
}
- FAIL_IF(push_inst(compiler, LDR | 0x800000 | RN(SLJIT_SP) | RD(restored_reg) | (sljit_uw)local_size));
+ FAIL_IF(push_inst(compiler, LDR | 0x800000 | RN(SLJIT_SP) | RD(restored_reg) | (sljit_ins)local_size));
tmp = 1;
} else if (frame_size == 0) {
frame_size = (restored_reg == TMP_REG2) ? SSIZE_OF(sw) : 2 * SSIZE_OF(sw);
@@ -1349,7 +1418,7 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit
local_size += SSIZE_OF(sw);
if (frame_size > local_size)
- FAIL_IF(push_inst(compiler, SUB | RD(SLJIT_SP) | RN(SLJIT_SP) | (1 << 25) | (sljit_uw)(frame_size - local_size)));
+ FAIL_IF(push_inst(compiler, SUB | RD(SLJIT_SP) | RN(SLJIT_SP) | (1 << 25) | (sljit_ins)(frame_size - local_size)));
else if (frame_size < local_size)
FAIL_IF(emit_add_sp(compiler, (sljit_uw)(local_size - frame_size)));
@@ -1361,11 +1430,11 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit
if (restored_reg != TMP_REG2)
frame_size -= SSIZE_OF(sw);
- return push_inst(compiler, LDR | 0x800000 | RN(SLJIT_SP) | RD(restored_reg) | (sljit_uw)frame_size);
+ return push_inst(compiler, LDR | 0x800000 | RN(SLJIT_SP) | RD(restored_reg) | (sljit_ins)frame_size);
}
tmp = (restored_reg == TMP_REG2) ? 0x800004 : 0x800008;
- return push_inst(compiler, LDR_POST | RN(SLJIT_SP) | RD(restored_reg) | (sljit_uw)tmp);
+ return push_inst(compiler, LDR_POST | RN(SLJIT_SP) | RD(restored_reg) | (sljit_ins)tmp);
}
if (local_size > 0)
@@ -1384,7 +1453,7 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit
FAIL_IF(push_inst(compiler, POP | reg_list));
if (frame_size > 0)
- return push_inst(compiler, SUB | RD(SLJIT_SP) | RN(SLJIT_SP) | (1 << 25) | ((sljit_uw)frame_size - sizeof(sljit_sw)));
+ return push_inst(compiler, SUB | RD(SLJIT_SP) | RN(SLJIT_SP) | (1 << 25) | ((sljit_ins)frame_size - sizeof(sljit_sw)));
if (lr_dst != 0)
return SLJIT_SUCCESS;
@@ -1432,7 +1501,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
sljit_s32 is_masked;
sljit_uw shift_type;
- switch (GET_OPCODE(op)) {
+ switch (op) {
case SLJIT_MOV:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));
if (dst != src2) {
@@ -1446,17 +1515,10 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
case SLJIT_MOV_U8:
case SLJIT_MOV_S8:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));
- if (flags & MOVE_REG_CONV) {
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
- if (op == SLJIT_MOV_U8)
- return push_inst(compiler, AND | RD(dst) | RN(src2) | SRC2_IMM | 0xff);
- FAIL_IF(push_inst(compiler, MOV | RD(dst) | (24 << 7) | RM(src2)));
- return push_inst(compiler, MOV | RD(dst) | (24 << 7) | (op == SLJIT_MOV_U8 ? 0x20 : 0x40) | RM(dst));
-#else
+ if (flags & MOVE_REG_CONV)
return push_inst(compiler, (op == SLJIT_MOV_U8 ? UXTB : SXTB) | RD(dst) | RM(src2));
-#endif
- }
- else if (dst != src2) {
+
+ if (dst != src2) {
SLJIT_ASSERT(src2 & SRC2_IMM);
return push_inst(compiler, ((flags & INV_IMM) ? MVN : MOV) | RD(dst) | src2);
}
@@ -1465,26 +1527,15 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
case SLJIT_MOV_U16:
case SLJIT_MOV_S16:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));
- if (flags & MOVE_REG_CONV) {
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
- FAIL_IF(push_inst(compiler, MOV | RD(dst) | (16 << 7) | RM(src2)));
- return push_inst(compiler, MOV | RD(dst) | (16 << 7) | (op == SLJIT_MOV_U16 ? 0x20 : 0x40) | RM(dst));
-#else
+ if (flags & MOVE_REG_CONV)
return push_inst(compiler, (op == SLJIT_MOV_U16 ? UXTH : SXTH) | RD(dst) | RM(src2));
-#endif
- }
- else if (dst != src2) {
+
+ if (dst != src2) {
SLJIT_ASSERT(src2 & SRC2_IMM);
return push_inst(compiler, ((flags & INV_IMM) ? MVN : MOV) | RD(dst) | src2);
}
return SLJIT_SUCCESS;
- case SLJIT_NOT:
- if (src2 & SRC2_IMM)
- return push_inst(compiler, ((flags & INV_IMM) ? MOV : MVN) | (flags & SET_FLAGS) | RD(dst) | src2);
-
- return push_inst(compiler, MVN | (flags & SET_FLAGS) | RD(dst) | RM(src2));
-
case SLJIT_CLZ:
SLJIT_ASSERT(!(flags & INV_IMM) && !(src2 & SRC2_IMM));
FAIL_IF(push_inst(compiler, CLZ | RD(dst) | RM(src2)));
@@ -1493,17 +1544,30 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
case SLJIT_CTZ:
SLJIT_ASSERT(!(flags & INV_IMM) && !(src2 & SRC2_IMM));
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
FAIL_IF(push_inst(compiler, RSB | SRC2_IMM | RD(TMP_REG1) | RN(src2) | 0));
FAIL_IF(push_inst(compiler, AND | RD(TMP_REG2) | RN(src2) | RM(TMP_REG1)));
FAIL_IF(push_inst(compiler, CLZ | RD(dst) | RM(TMP_REG2)));
FAIL_IF(push_inst(compiler, CMP | SET_FLAGS | SRC2_IMM | RN(dst) | 32));
return push_inst(compiler, (EOR ^ 0xf0000000) | SRC2_IMM | RD(dst) | RN(dst) | 0x1f);
-#else /* !SLJIT_CONFIG_ARM_V5 */
+#else /* !SLJIT_CONFIG_ARM_V6 */
FAIL_IF(push_inst(compiler, RBIT | RD(dst) | RM(src2)));
return push_inst(compiler, CLZ | RD(dst) | RM(dst));
-#endif /* SLJIT_CONFIG_ARM_V5 */
+#endif /* SLJIT_CONFIG_ARM_V6 */
+ case SLJIT_REV:
+ case SLJIT_REV_U32:
+ case SLJIT_REV_S32:
+ SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED));
+ return push_inst(compiler, REV | RD(dst) | RM(src2));
+
+ case SLJIT_REV_U16:
+ case SLJIT_REV_S16:
+ SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & ARGS_SWAPPED) && src2 != TMP_REG1 && dst != TMP_REG1);
+ FAIL_IF(push_inst(compiler, REV16 | RD(dst) | RM(src2)));
+ if (dst == TMP_REG2 || (src2 == TMP_REG2 && op == SLJIT_REV_U16))
+ return SLJIT_SUCCESS;
+ return push_inst(compiler, (op == SLJIT_REV_U16 ? UXTH : SXTH) | RD(dst) | RM(dst));
case SLJIT_ADD:
SLJIT_ASSERT(!(flags & INV_IMM));
@@ -1534,7 +1598,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
SLJIT_ASSERT(!(src2 & SRC2_IMM));
compiler->status_flags_state = 0;
- if (!HAS_FLAGS(op))
+ if (!(flags & SET_FLAGS))
return push_inst(compiler, MUL | RN(dst) | RM8(src2) | RM(src1));
FAIL_IF(push_inst(compiler, SMULL | RN(TMP_REG1) | RD(dst) | RM8(src2) | RM(src1)));
@@ -1553,25 +1617,28 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
return push_inst(compiler, ORR | (flags & SET_FLAGS) | RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));
case SLJIT_XOR:
- SLJIT_ASSERT(!(flags & INV_IMM));
+ if (flags & INV_IMM) {
+ SLJIT_ASSERT(src2 == SRC2_IMM);
+ return push_inst(compiler, MVN | (flags & SET_FLAGS) | RD(dst) | RM(src1));
+ }
return push_inst(compiler, EOR | (flags & SET_FLAGS) | RD(dst) | RN(src1) | ((src2 & SRC2_IMM) ? src2 : RM(src2)));
case SLJIT_SHL:
case SLJIT_MSHL:
shift_type = 0;
- is_masked = GET_OPCODE(op) == SLJIT_MSHL;
+ is_masked = op == SLJIT_MSHL;
break;
case SLJIT_LSHR:
case SLJIT_MLSHR:
shift_type = 1;
- is_masked = GET_OPCODE(op) == SLJIT_MLSHR;
+ is_masked = op == SLJIT_MLSHR;
break;
case SLJIT_ASHR:
case SLJIT_MASHR:
shift_type = 2;
- is_masked = GET_OPCODE(op) == SLJIT_MASHR;
+ is_masked = op == SLJIT_MASHR;
break;
case SLJIT_ROTL:
@@ -1611,7 +1678,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
}
return push_inst(compiler, MOV | (flags & SET_FLAGS) | RD(dst)
- | RM8(src2) | (sljit_uw)(shift_type << 5) | 0x10 | RM(src1));
+ | RM8(src2) | (sljit_ins)(shift_type << 5) | 0x10 | RM(src1));
}
#undef EMIT_SHIFT_INS_AND_RETURN
@@ -1628,8 +1695,7 @@ static sljit_uw get_imm(sljit_uw imm)
if (!(imm & 0xff000000)) {
imm <<= 8;
rol = 8;
- }
- else {
+ } else {
imm = (imm << 24) | (imm >> 8);
rol = 0;
}
@@ -1651,22 +1717,19 @@ static sljit_uw get_imm(sljit_uw imm)
if (!(imm & 0x00ffffff))
return SRC2_IMM | (imm >> 24) | (rol << 8);
- else
- return 0;
+ return 0;
}
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
-static sljit_s32 generate_int(struct sljit_compiler *compiler, sljit_s32 reg, sljit_uw imm, sljit_s32 positive)
+static sljit_uw compute_imm(sljit_uw imm, sljit_uw* imm2)
{
sljit_uw mask;
sljit_uw imm1;
- sljit_uw imm2;
sljit_uw rol;
/* Step1: Search a zero byte (8 continous zero bit). */
mask = 0xff000000;
rol = 8;
- while(1) {
+ while (1) {
if (!(imm & mask)) {
/* Rol imm by rol. */
imm = (imm << rol) | (imm >> (32 - rol));
@@ -1674,6 +1737,7 @@ static sljit_s32 generate_int(struct sljit_compiler *compiler, sljit_s32 reg, sl
rol = 4 + (rol >> 1);
break;
}
+
rol += 2;
mask >>= 2;
if (mask & 0x3) {
@@ -1703,9 +1767,8 @@ static sljit_s32 generate_int(struct sljit_compiler *compiler, sljit_s32 reg, sl
if (!(imm & 0xff000000)) {
imm1 = SRC2_IMM | ((imm >> 16) & 0xff) | (((rol + 4) & 0xf) << 8);
- imm2 = SRC2_IMM | ((imm >> 8) & 0xff) | (((rol + 8) & 0xf) << 8);
- }
- else if (imm & 0xc0000000) {
+ *imm2 = SRC2_IMM | ((imm >> 8) & 0xff) | (((rol + 8) & 0xf) << 8);
+ } else if (imm & 0xc0000000) {
imm1 = SRC2_IMM | ((imm >> 24) & 0xff) | ((rol & 0xf) << 8);
imm <<= 8;
rol += 4;
@@ -1726,11 +1789,10 @@ static sljit_s32 generate_int(struct sljit_compiler *compiler, sljit_s32 reg, sl
}
if (!(imm & 0x00ffffff))
- imm2 = SRC2_IMM | (imm >> 24) | ((rol & 0xf) << 8);
+ *imm2 = SRC2_IMM | (imm >> 24) | ((rol & 0xf) << 8);
else
return 0;
- }
- else {
+ } else {
if (!(imm & 0xf0000000)) {
imm <<= 4;
rol += 2;
@@ -1756,25 +1818,23 @@ static sljit_s32 generate_int(struct sljit_compiler *compiler, sljit_s32 reg, sl
}
if (!(imm & 0x00ffffff))
- imm2 = SRC2_IMM | (imm >> 24) | ((rol & 0xf) << 8);
+ *imm2 = SRC2_IMM | (imm >> 24) | ((rol & 0xf) << 8);
else
return 0;
}
- FAIL_IF(push_inst(compiler, (positive ? MOV : MVN) | RD(reg) | imm1));
- FAIL_IF(push_inst(compiler, (positive ? ORR : BIC) | RD(reg) | RN(reg) | imm2));
- return 1;
+ return imm1;
}
-#endif
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg, sljit_uw imm)
{
sljit_uw tmp;
-
-#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
+ sljit_uw imm1, imm2;
+#else /* !SLJIT_CONFIG_ARM_V6 */
if (!(imm & ~(sljit_uw)0xffff))
return push_inst(compiler, MOVW | RD(reg) | ((imm << 4) & 0xf0000) | (imm & 0xfff));
-#endif
+#endif /* SLJIT_CONFIG_ARM_V6 */
/* Create imm by 1 inst. */
tmp = get_imm(imm);
@@ -1785,19 +1845,28 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg,
if (tmp)
return push_inst(compiler, MVN | RD(reg) | tmp);
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
/* Create imm by 2 inst. */
- FAIL_IF(generate_int(compiler, reg, imm, 1));
- FAIL_IF(generate_int(compiler, reg, ~imm, 0));
+ imm1 = compute_imm(imm, &imm2);
+ if (imm1 != 0) {
+ FAIL_IF(push_inst(compiler, MOV | RD(reg) | imm1));
+ return push_inst(compiler, ORR | RD(reg) | RN(reg) | imm2);
+ }
+
+ imm1 = compute_imm(~imm, &imm2);
+ if (imm1 != 0) {
+ FAIL_IF(push_inst(compiler, MVN | RD(reg) | imm1));
+ return push_inst(compiler, BIC | RD(reg) | RN(reg) | imm2);
+ }
/* Load integer. */
return push_inst_with_literal(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, reg, TMP_PC, 0), imm);
-#else
+#else /* !SLJIT_CONFIG_ARM_V6 */
FAIL_IF(push_inst(compiler, MOVW | RD(reg) | ((imm << 4) & 0xf0000) | (imm & 0xfff)));
if (imm <= 0xffff)
return SLJIT_SUCCESS;
return push_inst(compiler, MOVT | RD(reg) | ((imm >> 12) & 0xf0000) | ((imm >> 16) & 0xfff));
-#endif
+#endif /* SLJIT_CONFIG_ARM_V6 */
}
static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg,
@@ -1834,13 +1903,13 @@ static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, s
argw &= 0x3;
if (argw != 0 && (mask == 0xff)) {
- FAIL_IF(push_inst(compiler, ADD | RD(tmp_reg) | RN(arg) | RM(offset_reg) | ((sljit_uw)argw << 7)));
+ FAIL_IF(push_inst(compiler, ADD | RD(tmp_reg) | RN(arg) | RM(offset_reg) | ((sljit_ins)argw << 7)));
return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, reg, tmp_reg, TYPE2_TRANSFER_IMM(0)));
}
/* Bit 25: RM is offset. */
return push_inst(compiler, EMIT_DATA_TRANSFER(flags, 1, reg, arg,
- RM(offset_reg) | (mask == 0xff ? 0 : (1 << 25)) | ((sljit_uw)argw << 7)));
+ RM(offset_reg) | (mask == 0xff ? 0 : (1 << 25)) | ((sljit_ins)argw << 7)));
}
arg &= REG_MASK;
@@ -1902,10 +1971,16 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
/* We prefers register and simple consts. */
sljit_s32 dst_reg;
- sljit_s32 src1_reg;
+ sljit_s32 src1_reg = 0;
sljit_s32 src2_reg = 0;
sljit_s32 flags = HAS_FLAGS(op) ? SET_FLAGS : 0;
sljit_s32 neg_op = 0;
+ sljit_u32 imm2;
+
+ op = GET_OPCODE(op);
+
+ if (flags & SET_FLAGS)
+ inp_flags &= ~ALLOW_DOUBLE_IMM;
if (dst == TMP_REG2)
flags |= UNUSED_RETURN;
@@ -1913,7 +1988,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
SLJIT_ASSERT(!(inp_flags & ALLOW_INV_IMM) || (inp_flags & ALLOW_IMM));
if (inp_flags & ALLOW_NEG_IMM) {
- switch (GET_OPCODE(op)) {
+ switch (op) {
case SLJIT_ADD:
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD;
neg_op = SLJIT_SUB;
@@ -1937,10 +2012,11 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
if (!(inp_flags & ALLOW_IMM))
break;
- if (src2 & SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
src2_reg = (sljit_s32)get_imm((sljit_uw)src2w);
if (src2_reg)
break;
+
if (inp_flags & ALLOW_INV_IMM) {
src2_reg = (sljit_s32)get_imm(~(sljit_uw)src2w);
if (src2_reg) {
@@ -1948,8 +2024,9 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
break;
}
}
+
if (neg_op != 0) {
- src2_reg = (sljit_s32)get_imm((sljit_uw)-src2w);
+ src2_reg = (sljit_s32)get_imm((neg_op == SLJIT_ADD || neg_op == SLJIT_SUB) ? (sljit_uw)-src2w : ~(sljit_uw)src2w);
if (src2_reg) {
op = neg_op | GET_ALL_FLAGS(op);
break;
@@ -1957,7 +2034,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
}
}
- if (src1 & SLJIT_IMM) {
+ if (src1 == SLJIT_IMM) {
src2_reg = (sljit_s32)get_imm((sljit_uw)src1w);
if (src2_reg) {
flags |= ARGS_SWAPPED;
@@ -1965,6 +2042,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
src1w = src2w;
break;
}
+
if (inp_flags & ALLOW_INV_IMM) {
src2_reg = (sljit_s32)get_imm(~(sljit_uw)src1w);
if (src2_reg) {
@@ -1974,8 +2052,11 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
break;
}
}
+
if (neg_op >= SLJIT_SUB) {
/* Note: additive operation (commutative). */
+ SLJIT_ASSERT(op == SLJIT_ADD || op == SLJIT_ADDC);
+
src2_reg = (sljit_s32)get_imm((sljit_uw)-src1w);
if (src2_reg) {
src1 = src2;
@@ -1993,8 +2074,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
else if (src1 & SLJIT_MEM) {
FAIL_IF(emit_op_mem(compiler, inp_flags | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1));
src1_reg = TMP_REG1;
- }
- else {
+ } else if (!(inp_flags & ALLOW_DOUBLE_IMM) || src2_reg != 0 || op == SLJIT_SUB || op == SLJIT_SUBC) {
FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w));
src1_reg = TMP_REG1;
}
@@ -2023,8 +2103,62 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
src2_reg = src2;
else if (src2 & SLJIT_MEM)
FAIL_IF(emit_op_mem(compiler, inp_flags | LOAD_DATA, src2_reg, src2, src2w, TMP_REG2));
- else
+ else if (!(inp_flags & ALLOW_DOUBLE_IMM))
FAIL_IF(load_immediate(compiler, src2_reg, (sljit_uw)src2w));
+ else {
+ SLJIT_ASSERT(!(flags & SET_FLAGS));
+
+ if (src1_reg == 0) {
+ FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w));
+ src1_reg = TMP_REG1;
+ }
+
+ src2_reg = (sljit_s32)compute_imm((sljit_uw)src2w, &imm2);
+
+ if (src2_reg == 0 && neg_op != 0) {
+ src2_reg = (sljit_s32)compute_imm((sljit_uw)-src2w, &imm2);
+ if (src2_reg != 0)
+ op = neg_op;
+ }
+
+ if (src2_reg == 0) {
+ FAIL_IF(load_immediate(compiler, TMP_REG2, (sljit_uw)src2w));
+ src2_reg = TMP_REG2;
+ } else {
+ FAIL_IF(emit_single_op(compiler, op, flags, (sljit_uw)dst_reg, (sljit_uw)src1_reg, (sljit_uw)src2_reg));
+ src1_reg = dst_reg;
+ src2_reg = (sljit_s32)imm2;
+
+ if (op == SLJIT_ADDC)
+ op = SLJIT_ADD;
+ else if (op == SLJIT_SUBC)
+ op = SLJIT_SUB;
+ }
+ }
+ }
+
+ if (src1_reg == 0) {
+ SLJIT_ASSERT((inp_flags & ALLOW_DOUBLE_IMM) && !(flags & SET_FLAGS));
+
+ src1_reg = (sljit_s32)compute_imm((sljit_uw)src1w, &imm2);
+
+ if (src1_reg == 0 && neg_op != 0) {
+ src1_reg = (sljit_s32)compute_imm((sljit_uw)-src1w, &imm2);
+ if (src1_reg != 0)
+ op = neg_op;
+ }
+
+ if (src1_reg == 0) {
+ FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w));
+ src1_reg = TMP_REG1;
+ } else {
+ FAIL_IF(emit_single_op(compiler, op, flags, (sljit_uw)dst_reg, (sljit_uw)src2_reg, (sljit_uw)src1_reg));
+ src1_reg = dst_reg;
+ src2_reg = (sljit_s32)imm2;
+
+ if (op == SLJIT_ADDC)
+ op = SLJIT_ADD;
+ }
}
FAIL_IF(emit_single_op(compiler, op, flags, (sljit_uw)dst_reg, (sljit_uw)src1_reg, (sljit_uw)src2_reg));
@@ -2114,7 +2248,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compile
SLJIT_ASSERT(saved_reg_list[1] < 8);
FAIL_IF(push_inst(compiler, LDR | 0x8d0004 | (saved_reg_list[1] << 12) /* ldr rX, [sp, #4] */));
}
- return push_inst(compiler, (LDR ^ (1 << 24)) | 0x8d0000 | (sljit_uw)(saved_reg_count >= 3 ? 16 : 8)
+ return push_inst(compiler, (LDR ^ (1 << 24)) | 0x8d0000 | (sljit_ins)(saved_reg_count >= 3 ? 16 : 8)
| (saved_reg_list[0] << 12) /* ldr rX, [sp], #8/16 */);
}
return SLJIT_SUCCESS;
@@ -2144,23 +2278,27 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
return emit_op(compiler, SLJIT_MOV, ALLOW_ANY_IMM, dst, dstw, TMP_REG1, 0, src, srcw);
case SLJIT_MOV_U8:
- return emit_op(compiler, SLJIT_MOV_U8, ALLOW_ANY_IMM | BYTE_SIZE, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u8)srcw : srcw);
+ return emit_op(compiler, SLJIT_MOV_U8, ALLOW_ANY_IMM | BYTE_SIZE, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u8)srcw : srcw);
case SLJIT_MOV_S8:
- return emit_op(compiler, SLJIT_MOV_S8, ALLOW_ANY_IMM | SIGNED | BYTE_SIZE, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s8)srcw : srcw);
+ return emit_op(compiler, SLJIT_MOV_S8, ALLOW_ANY_IMM | SIGNED | BYTE_SIZE, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s8)srcw : srcw);
case SLJIT_MOV_U16:
- return emit_op(compiler, SLJIT_MOV_U16, ALLOW_ANY_IMM | HALF_SIZE, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u16)srcw : srcw);
+ return emit_op(compiler, SLJIT_MOV_U16, ALLOW_ANY_IMM | HALF_SIZE, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u16)srcw : srcw);
case SLJIT_MOV_S16:
- return emit_op(compiler, SLJIT_MOV_S16, ALLOW_ANY_IMM | SIGNED | HALF_SIZE, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s16)srcw : srcw);
-
- case SLJIT_NOT:
- return emit_op(compiler, op, ALLOW_ANY_IMM, dst, dstw, TMP_REG1, 0, src, srcw);
+ return emit_op(compiler, SLJIT_MOV_S16, ALLOW_ANY_IMM | SIGNED | HALF_SIZE, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s16)srcw : srcw);
case SLJIT_CLZ:
case SLJIT_CTZ:
+ case SLJIT_REV:
+ case SLJIT_REV_U32:
+ case SLJIT_REV_S32:
return emit_op(compiler, op, 0, dst, dstw, TMP_REG1, 0, src, srcw);
+
+ case SLJIT_REV_U16:
+ case SLJIT_REV_S16:
+ return emit_op(compiler, op, HALF_SIZE, dst, dstw, TMP_REG1, 0, src, srcw);
}
return SLJIT_SUCCESS;
@@ -2171,6 +2309,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
sljit_s32 src1, sljit_sw src1w,
sljit_s32 src2, sljit_sw src2w)
{
+ sljit_s32 inp_flags;
+
CHECK_ERROR();
CHECK(check_sljit_emit_op2(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w));
ADJUST_LOCAL_OFFSET(dst, dstw);
@@ -2182,11 +2322,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
case SLJIT_ADDC:
case SLJIT_SUB:
case SLJIT_SUBC:
- return emit_op(compiler, op, ALLOW_IMM | ALLOW_NEG_IMM, dst, dstw, src1, src1w, src2, src2w);
+ return emit_op(compiler, op, ALLOW_IMM | ALLOW_NEG_IMM | ALLOW_DOUBLE_IMM, dst, dstw, src1, src1w, src2, src2w);
case SLJIT_OR:
+ return emit_op(compiler, op, ALLOW_IMM | ALLOW_DOUBLE_IMM, dst, dstw, src1, src1w, src2, src2w);
+
case SLJIT_XOR:
- return emit_op(compiler, op, ALLOW_IMM, dst, dstw, src1, src1w, src2, src2w);
+ inp_flags = ALLOW_IMM | ALLOW_DOUBLE_IMM;
+ if ((src1 == SLJIT_IMM && src1w == -1) || (src2 == SLJIT_IMM && src2w == -1)) {
+ inp_flags |= ALLOW_INV_IMM;
+ }
+ return emit_op(compiler, op, inp_flags, dst, dstw, src1, src1w, src2, src2w);
case SLJIT_MUL:
return emit_op(compiler, op, 0, dst, dstw, src1, src1w, src2, src2w);
@@ -2202,7 +2348,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
case SLJIT_MASHR:
case SLJIT_ROTL:
case SLJIT_ROTR:
- if (src2 & SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
compiler->shift_imm = src2w & 0x1f;
return emit_op(compiler, op, 0, dst, dstw, TMP_REG1, 0, src1, src1w);
} else {
@@ -2226,60 +2372,52 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 src_dst,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w)
+ sljit_s32 dst_reg,
+ sljit_s32 src1_reg,
+ sljit_s32 src2_reg,
+ sljit_s32 src3, sljit_sw src3w)
{
sljit_s32 is_left;
CHECK_ERROR();
- CHECK(check_sljit_emit_shift_into(compiler, op, src_dst, src1, src1w, src2, src2w));
+ CHECK(check_sljit_emit_shift_into(compiler, op, dst_reg, src1_reg, src2_reg, src3, src3w));
op = GET_OPCODE(op);
is_left = (op == SLJIT_SHL || op == SLJIT_MSHL);
- if (src_dst == src1) {
+ if (src1_reg == src2_reg) {
SLJIT_SKIP_CHECKS(compiler);
- return sljit_emit_op2(compiler, is_left ? SLJIT_ROTL : SLJIT_ROTR, src_dst, 0, src_dst, 0, src2, src2w);
+ return sljit_emit_op2(compiler, is_left ? SLJIT_ROTL : SLJIT_ROTR, dst_reg, 0, src1_reg, 0, src3, src3w);
}
- ADJUST_LOCAL_OFFSET(src1, src1w);
- ADJUST_LOCAL_OFFSET(src2, src2w);
+ ADJUST_LOCAL_OFFSET(src3, src3w);
/* Shift type of ROR is 3. */
- if (src2 & SLJIT_IMM) {
- src2w &= 0x1f;
+ if (src3 == SLJIT_IMM) {
+ src3w &= 0x1f;
- if (src2w == 0)
+ if (src3w == 0)
return SLJIT_SUCCESS;
- } else if (src2 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG2, src2, src2w, TMP_REG2));
- src2 = TMP_REG2;
- }
- if (src1 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG1, src1, src1w, TMP_REG1));
- src1 = TMP_REG1;
- } else if (src1 & SLJIT_IMM) {
- FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w));
- src1 = TMP_REG1;
+ FAIL_IF(push_inst(compiler, MOV | RD(dst_reg) | RM(src1_reg) | ((sljit_ins)(is_left ? 0 : 1) << 5) | ((sljit_ins)src3w << 7)));
+ src3w = (src3w ^ 0x1f) + 1;
+ return push_inst(compiler, ORR | RD(dst_reg) | RN(dst_reg) | RM(src2_reg) | ((sljit_ins)(is_left ? 1 : 0) << 5) | ((sljit_ins)src3w << 7));
}
- if (src2 & SLJIT_IMM) {
- FAIL_IF(push_inst(compiler, MOV | RD(src_dst) | RM(src_dst) | ((sljit_uw)(is_left ? 0 : 1) << 5) | ((sljit_uw)src2w << 7)));
- src2w = (src2w ^ 0x1f) + 1;
- return push_inst(compiler, ORR | RD(src_dst) | RN(src_dst) | RM(src1) | ((sljit_uw)(is_left ? 1 : 0) << 5) | ((sljit_uw)src2w << 7));
+ if (src3 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG2, src3, src3w, TMP_REG2));
+ src3 = TMP_REG2;
}
- if (op == SLJIT_MSHL || op == SLJIT_MLSHR) {
- FAIL_IF(push_inst(compiler, AND | SRC2_IMM | RD(TMP_REG2) | RN(src2) | 0x1f));
- src2 = TMP_REG2;
+ if (op == SLJIT_MSHL || op == SLJIT_MLSHR || dst_reg == src3) {
+ FAIL_IF(push_inst(compiler, AND | SRC2_IMM | RD(TMP_REG2) | RN(src3) | 0x1f));
+ src3 = TMP_REG2;
}
- FAIL_IF(push_inst(compiler, MOV | RD(src_dst) | RM8(src2) | ((sljit_uw)(is_left ? 0 : 1) << 5) | 0x10 | RM(src_dst)));
- FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG1) | RM(src1) | ((sljit_uw)(is_left ? 1 : 0) << 5) | (1 << 7)));
- FAIL_IF(push_inst(compiler, EOR | SRC2_IMM | RD(TMP_REG2) | RN(src2) | 0x1f));
- return push_inst(compiler, ORR | RD(src_dst) | RN(src_dst) | RM(TMP_REG1) | ((sljit_uw)(is_left ? 1 : 0) << 5) | 0x10 | RM8(TMP_REG2));
+ FAIL_IF(push_inst(compiler, MOV | RD(dst_reg) | RM8(src3) | ((sljit_ins)(is_left ? 0 : 1) << 5) | 0x10 | RM(src1_reg)));
+ FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG1) | RM(src2_reg) | ((sljit_ins)(is_left ? 1 : 0) << 5) | (1 << 7)));
+ FAIL_IF(push_inst(compiler, EOR | SRC2_IMM | RD(TMP_REG2) | RN(src3) | 0x1f));
+ return push_inst(compiler, ORR | RD(dst_reg) | RN(dst_reg) | RM8(TMP_REG2) | ((sljit_ins)(is_left ? 1 : 0) << 5) | 0x10 | RM(TMP_REG1));
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
@@ -2305,27 +2443,67 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *comp
case SLJIT_PREFETCH_L2:
case SLJIT_PREFETCH_L3:
case SLJIT_PREFETCH_ONCE:
-#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
SLJIT_ASSERT(src & SLJIT_MEM);
return emit_op_mem(compiler, PRELOAD | LOAD_DATA, TMP_PC, src, srcw, TMP_REG1);
-#else /* !SLJIT_CONFIG_ARM_V7 */
- return SLJIT_SUCCESS;
-#endif /* SLJIT_CONFIG_ARM_V7 */
}
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw)
{
- CHECK_REG_INDEX(check_sljit_get_register_index(reg));
- return reg_map[reg];
+ sljit_s32 size, dst_r;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op_dst(compiler, op, dst, dstw));
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+
+ switch (op) {
+ case SLJIT_FAST_ENTER:
+ SLJIT_ASSERT(reg_map[TMP_REG2] == 14);
+
+ if (FAST_IS_REG(dst))
+ return push_inst(compiler, MOV | RD(dst) | RM(TMP_REG2));
+ break;
+ case SLJIT_GET_RETURN_ADDRESS:
+ size = GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds - SLJIT_KEPT_SAVEDS_COUNT(compiler->options), 0);
+
+ if (compiler->fsaveds > 0 || compiler->fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) {
+ /* The size of pc is not added above. */
+ if ((size & SSIZE_OF(sw)) == 0)
+ size += SSIZE_OF(sw);
+
+ size += GET_SAVED_FLOAT_REGISTERS_SIZE(compiler->fscratches, compiler->fsaveds, f64);
+ }
+
+ SLJIT_ASSERT(((compiler->local_size + size + SSIZE_OF(sw)) & 0x7) == 0);
+
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, dst_r, SLJIT_MEM1(SLJIT_SP), compiler->local_size + size, TMP_REG1));
+ break;
+ }
+
+ if (dst & SLJIT_MEM)
+ return emit_op_mem(compiler, WORD_SIZE, TMP_REG2, dst, dstw, TMP_REG1);
+
+ return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 type, sljit_s32 reg)
{
- CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
- return (freg_map[reg] << 1);
+ CHECK_REG_INDEX(check_sljit_get_register_index(type, reg));
+
+ if (type == SLJIT_GP_REGISTER)
+ return reg_map[reg];
+
+ if (type == SLJIT_FLOAT_REGISTER || type == SLJIT_SIMD_REG_64)
+ return freg_map[reg];
+
+ if (type != SLJIT_SIMD_REG_128)
+ return freg_map[reg] & ~0x1;
+
+ return -1;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
@@ -2335,7 +2513,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *c
CHECK_ERROR();
CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
- return push_inst(compiler, *(sljit_uw*)instruction);
+ return push_inst(compiler, *(sljit_ins*)instruction);
}
/* --------------------------------------------------------------------- */
@@ -2344,18 +2522,18 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *c
#define FPU_LOAD (1 << 20)
#define EMIT_FPU_DATA_TRANSFER(inst, add, base, freg, offs) \
- ((inst) | (sljit_uw)((add) << 23) | RN(base) | VD(freg) | (sljit_uw)(offs))
+ ((inst) | (sljit_ins)((add) << 23) | RN(base) | VD(freg) | (sljit_ins)(offs))
static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags, sljit_s32 reg, sljit_s32 arg, sljit_sw argw)
{
sljit_uw imm;
- sljit_uw inst = VSTR_F32 | (flags & (SLJIT_32 | FPU_LOAD));
+ sljit_ins inst = VSTR_F32 | (flags & (SLJIT_32 | FPU_LOAD));
SLJIT_ASSERT(arg & SLJIT_MEM);
arg &= ~SLJIT_MEM;
if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
- FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG2) | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | (((sljit_uw)argw & 0x3) << 7)));
+ FAIL_IF(push_inst(compiler, ADD | RD(TMP_REG2) | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | (((sljit_ins)argw & 0x3) << 7)));
arg = TMP_REG2;
argw = 0;
}
@@ -2410,14 +2588,12 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_comp
return emit_fop_mem(compiler, 0, TMP_FREG1, dst, dstw);
}
-static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+static sljit_s32 sljit_emit_fop1_conv_f64_from_w(struct sljit_compiler *compiler, sljit_ins ins,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 src, sljit_sw srcw)
{
sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
- op ^= SLJIT_32;
-
if (FAST_IS_REG(src))
FAIL_IF(push_inst(compiler, VMOV | RD(src) | VN(TMP_FREG1)));
else if (src & SLJIT_MEM) {
@@ -2429,13 +2605,27 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_comp
FAIL_IF(push_inst(compiler, VMOV | RD(TMP_REG1) | VN(TMP_FREG1)));
}
- FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCVT_F32_S32, op & SLJIT_32, dst_r, TMP_FREG1, 0)));
+ FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(ins, ins & SLJIT_32, dst_r, TMP_FREG1, 0)));
if (dst & SLJIT_MEM)
- return emit_fop_mem(compiler, (op & SLJIT_32), TMP_FREG1, dst, dstw);
+ return emit_fop_mem(compiler, (ins & SLJIT_32), TMP_FREG1, dst, dstw);
return SLJIT_SUCCESS;
}
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ return sljit_emit_fop1_conv_f64_from_w(compiler, VCVT_F32_S32 | (~op & SLJIT_32), dst, dstw, src, srcw);
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_uw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ return sljit_emit_fop1_conv_f64_from_w(compiler, VCVT_F32_U32 | (~op & SLJIT_32), dst, dstw, src, srcw);
+}
+
static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 src1, sljit_sw src1w,
sljit_s32 src2, sljit_sw src2w)
@@ -2453,7 +2643,12 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compile
}
FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VCMP_F32, op & SLJIT_32, src1, src2, 0)));
- return push_inst(compiler, VMRS);
+ FAIL_IF(push_inst(compiler, VMRS));
+
+ if (GET_FLAG_TYPE(op) != SLJIT_UNORDERED_OR_EQUAL)
+ return SLJIT_SUCCESS;
+
+ return push_inst(compiler, (CMP - CONDITIONAL) | (0x60000000 /* VS */) | SET_FLAGS | RN(TMP_REG1) | RM(TMP_REG1));
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
@@ -2534,18 +2729,20 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
case SLJIT_ADD_F64:
FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VADD_F32, op & SLJIT_32, dst_r, src2, src1)));
break;
-
case SLJIT_SUB_F64:
FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VSUB_F32, op & SLJIT_32, dst_r, src2, src1)));
break;
-
case SLJIT_MUL_F64:
FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMUL_F32, op & SLJIT_32, dst_r, src2, src1)));
break;
-
case SLJIT_DIV_F64:
FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VDIV_F32, op & SLJIT_32, dst_r, src2, src1)));
break;
+ case SLJIT_COPYSIGN_F64:
+ FAIL_IF(push_inst(compiler, VMOV | (1 << 20) | VN(src2) | RD(TMP_REG1) | ((op & SLJIT_32) ? (1 << 7) : 0)));
+ FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VABS_F32, op & SLJIT_32, dst_r, src1, 0)));
+ FAIL_IF(push_inst(compiler, CMP | SET_FLAGS | RN(TMP_REG1) | SRC2_IMM | 0));
+ return push_inst(compiler, EMIT_FPU_OPERATION((VNEG_F32 & ~COND_MASK) | 0xb0000000, op & SLJIT_32, dst_r, dst_r, 0));
}
if (dst_r == TMP_FREG1)
@@ -2556,42 +2753,120 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
#undef EMIT_FPU_DATA_TRANSFER
-/* --------------------------------------------------------------------- */
-/* Other instructions */
-/* --------------------------------------------------------------------- */
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset32(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f32 value)
+{
+#if defined(__ARM_NEON) && __ARM_NEON
+ sljit_u32 exp;
+ sljit_ins ins;
+#endif /* NEON */
+ union {
+ sljit_u32 imm;
+ sljit_f32 value;
+ } u;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fset32(compiler, freg, value));
+
+ u.value = value;
+
+#if defined(__ARM_NEON) && __ARM_NEON
+ if ((u.imm << (32 - 19)) == 0) {
+ exp = (u.imm >> (23 + 2)) & 0x3f;
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+ if (exp == 0x20 || exp == 0x1f) {
+ ins = ((u.imm >> 24) & 0x80) | ((u.imm >> 19) & 0x7f);
+ return push_inst(compiler, (VMOV_F32 ^ (1 << 6)) | ((ins & 0xf0) << 12) | VD(freg) | (ins & 0xf));
+ }
+ }
+#endif /* NEON */
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm));
+ return push_inst(compiler, VMOV | VN(freg) | RD(TMP_REG1));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f64 value)
{
+#if defined(__ARM_NEON) && __ARM_NEON
+ sljit_u32 exp;
+ sljit_ins ins;
+#endif /* NEON */
+ union {
+ sljit_u32 imm[2];
+ sljit_f64 value;
+ } u;
+
CHECK_ERROR();
- CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
- ADJUST_LOCAL_OFFSET(dst, dstw);
+ CHECK(check_sljit_emit_fset64(compiler, freg, value));
- SLJIT_ASSERT(reg_map[TMP_REG2] == 14);
+ u.value = value;
- if (FAST_IS_REG(dst))
- return push_inst(compiler, MOV | RD(dst) | RM(TMP_REG2));
+#if defined(__ARM_NEON) && __ARM_NEON
+ if (u.imm[0] == 0 && (u.imm[1] << (64 - 48)) == 0) {
+ exp = (u.imm[1] >> ((52 - 32) + 2)) & 0x1ff;
+
+ if (exp == 0x100 || exp == 0xff) {
+ ins = ((u.imm[1] >> (56 - 32)) & 0x80) | ((u.imm[1] >> (48 - 32)) & 0x7f);
+ return push_inst(compiler, (VMOV_F32 ^ (1 << 6)) | (1 << 8) | ((ins & 0xf0) << 12) | VD(freg) | (ins & 0xf));
+ }
+ }
+#endif /* NEON */
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm[0]));
+ if (u.imm[0] == u.imm[1])
+ return push_inst(compiler, VMOV2 | RN(TMP_REG1) | RD(TMP_REG1) | VM(freg));
+
+ FAIL_IF(load_immediate(compiler, TMP_REG2, u.imm[1]));
+ return push_inst(compiler, VMOV2 | RN(TMP_REG2) | RD(TMP_REG1) | VM(freg));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 freg, sljit_s32 reg)
+{
+ sljit_s32 reg2;
+ sljit_ins inst;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+ if (reg & REG_PAIR_MASK) {
+ reg2 = REG_PAIR_SECOND(reg);
+ reg = REG_PAIR_FIRST(reg);
+
+ inst = VMOV2 | RN(reg) | RD(reg2) | VM(freg);
+ } else {
+ inst = VMOV | VN(freg) | RD(reg);
- /* Memory. */
- return emit_op_mem(compiler, WORD_SIZE, TMP_REG2, dst, dstw, TMP_REG1);
+ if (!(op & SLJIT_32))
+ inst |= 1 << 7;
+ }
+
+ if (GET_OPCODE(op) == SLJIT_COPY_FROM_F64)
+ inst |= 1 << 20;
+
+ return push_inst(compiler, inst);
}
/* --------------------------------------------------------------------- */
/* Conditional instructions */
/* --------------------------------------------------------------------- */
-static sljit_uw get_cc(struct sljit_compiler *compiler, sljit_s32 type)
+static sljit_ins get_cc(struct sljit_compiler *compiler, sljit_s32 type)
{
switch (type) {
case SLJIT_EQUAL:
+ case SLJIT_ATOMIC_STORED:
case SLJIT_F_EQUAL:
case SLJIT_ORDERED_EQUAL:
- case SLJIT_UNORDERED_OR_EQUAL: /* Not supported. */
+ case SLJIT_UNORDERED_OR_EQUAL:
return 0x00000000;
case SLJIT_NOT_EQUAL:
+ case SLJIT_ATOMIC_NOT_STORED:
case SLJIT_F_NOT_EQUAL:
case SLJIT_UNORDERED_OR_NOT_EQUAL:
- case SLJIT_ORDERED_NOT_EQUAL: /* Not supported. */
+ case SLJIT_ORDERED_NOT_EQUAL:
return 0x10000000;
case SLJIT_CARRY:
@@ -2696,7 +2971,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
SLJIT_ASSERT(reg_map[TMP_REG1] != 14);
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
if (type >= SLJIT_FAST_CALL)
PTR_FAIL_IF(prepare_blx(compiler));
PTR_FAIL_IF(push_inst_with_unique_literal(compiler, ((EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1,
@@ -2714,13 +2989,13 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
if (!(jump->flags & SLJIT_REWRITABLE_JUMP))
jump->addr = compiler->size;
-#else
+#else /* !SLJIT_CONFIG_ARM_V6 */
if (type >= SLJIT_FAST_CALL)
jump->flags |= IS_BL;
PTR_FAIL_IF(emit_imm(compiler, TMP_REG1, 0));
PTR_FAIL_IF(push_inst(compiler, (((type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG1)) & ~COND_MASK) | get_cc(compiler, type)));
jump->addr = compiler->size;
-#endif
+#endif /* SLJIT_CONFIG_ARM_V6 */
return jump;
}
@@ -2738,7 +3013,7 @@ static sljit_s32 softfloat_call_with_args(struct sljit_compiler *compiler, sljit
sljit_u8 *offset_ptr = offsets;
if (src && FAST_IS_REG(*src))
- src_offset = (sljit_uw)reg_map[*src] * sizeof(sljit_sw);
+ src_offset = (sljit_u32)reg_map[*src] * sizeof(sljit_sw);
arg_types >>= SLJIT_ARG_SHIFT;
@@ -2773,7 +3048,7 @@ static sljit_s32 softfloat_call_with_args(struct sljit_compiler *compiler, sljit
if (is_tail_call)
offset += sizeof(sljit_sw);
- offset = ((offset - 4 * sizeof(sljit_sw)) + 0x7) & ~(sljit_uw)0x7;
+ offset = ((offset - 4 * sizeof(sljit_sw)) + 0x7) & ~(sljit_u32)0x7;
*extra_space = offset;
@@ -2903,8 +3178,6 @@ static sljit_s32 hardfloat_call_with_args(struct sljit_compiler *compiler, sljit
#endif /* __SOFTFP__ */
-#undef EMIT_FPU_OPERATION
-
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
sljit_s32 arg_types)
{
@@ -2971,7 +3244,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
SLJIT_ASSERT(reg_map[TMP_REG1] != 14);
- if (!(src & SLJIT_IMM)) {
+ if (src != SLJIT_IMM) {
if (FAST_IS_REG(src)) {
SLJIT_ASSERT(reg_map[src] != 14);
return push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(src));
@@ -2988,16 +3261,16 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
set_jump(jump, compiler, JUMP_ADDR | ((type >= SLJIT_FAST_CALL) ? IS_BL : 0));
jump->u.target = (sljit_uw)srcw;
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
if (type >= SLJIT_FAST_CALL)
FAIL_IF(prepare_blx(compiler));
FAIL_IF(push_inst_with_unique_literal(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, type <= SLJIT_JUMP ? TMP_PC : TMP_REG1, TMP_PC, 0), 0));
if (type >= SLJIT_FAST_CALL)
FAIL_IF(emit_blx(compiler));
-#else
+#else /* !SLJIT_CONFIG_ARM_V6 */
FAIL_IF(emit_imm(compiler, TMP_REG1, 0));
FAIL_IF(push_inst(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RM(TMP_REG1)));
-#endif
+#endif /* SLJIT_CONFIG_ARM_V6 */
jump->addr = compiler->size;
return SLJIT_SUCCESS;
}
@@ -3096,7 +3369,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
sljit_s32 type)
{
sljit_s32 dst_reg, flags = GET_ALL_FLAGS(op);
- sljit_uw cc, ins;
+ sljit_ins cc, ins;
CHECK_ERROR();
CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
@@ -3132,61 +3405,114 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *compiler, sljit_s32 type,
sljit_s32 dst_reg,
- sljit_s32 src, sljit_sw srcw)
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_reg)
{
- sljit_uw cc, tmp;
+ sljit_ins cc, tmp;
CHECK_ERROR();
- CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
+ CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));
+
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+
+ if (src2_reg != dst_reg && src1 == dst_reg) {
+ src1 = src2_reg;
+ src1w = 0;
+ src2_reg = dst_reg;
+ type ^= 0x1;
+ }
+
+ if (src1 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, (src2_reg != dst_reg) ? dst_reg : TMP_REG1, src1, src1w, TMP_REG2));
+
+ if (src2_reg != dst_reg) {
+ src1 = src2_reg;
+ src1w = 0;
+ type ^= 0x1;
+ } else {
+ src1 = TMP_REG1;
+ src1w = 0;
+ }
+ } else if (dst_reg != src2_reg)
+ FAIL_IF(push_inst(compiler, MOV | RD(dst_reg) | RM(src2_reg)));
cc = get_cc(compiler, type & ~SLJIT_32);
- if (SLJIT_UNLIKELY(src & SLJIT_IMM)) {
- tmp = get_imm((sljit_uw)srcw);
+ if (SLJIT_UNLIKELY(src1 == SLJIT_IMM)) {
+ tmp = get_imm((sljit_uw)src1w);
if (tmp)
return push_inst(compiler, ((MOV | RD(dst_reg) | tmp) & ~COND_MASK) | cc);
- tmp = get_imm(~(sljit_uw)srcw);
+ tmp = get_imm(~(sljit_uw)src1w);
if (tmp)
return push_inst(compiler, ((MVN | RD(dst_reg) | tmp) & ~COND_MASK) | cc);
#if (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
- tmp = (sljit_uw)srcw;
+ tmp = (sljit_ins)src1w;
FAIL_IF(push_inst(compiler, (MOVW & ~COND_MASK) | cc | RD(dst_reg) | ((tmp << 4) & 0xf0000) | (tmp & 0xfff)));
if (tmp <= 0xffff)
return SLJIT_SUCCESS;
return push_inst(compiler, (MOVT & ~COND_MASK) | cc | RD(dst_reg) | ((tmp >> 12) & 0xf0000) | ((tmp >> 16) & 0xfff));
-#else
- FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)srcw));
- src = TMP_REG1;
-#endif
+#else /* !SLJIT_CONFIG_ARM_V7 */
+ FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w));
+ src1 = TMP_REG1;
+#endif /* SLJIT_CONFIG_ARM_V7 */
+ }
+
+ return push_inst(compiler, ((MOV | RD(dst_reg) | RM(src1)) & ~COND_MASK) | cc);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_freg)
+{
+ sljit_ins cc;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fselect(compiler, type, dst_freg, src1, src1w, src2_freg));
+
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+
+ type ^= SLJIT_32;
+
+ if (dst_freg != src2_freg) {
+ if (dst_freg == src1) {
+ src1 = src2_freg;
+ src1w = 0;
+ type ^= 0x1;
+ } else
+ FAIL_IF(push_inst(compiler, EMIT_FPU_OPERATION(VMOV_F32, (type & SLJIT_32), dst_freg, src2_freg, 0)));
+ }
+
+ if (src1 & SLJIT_MEM) {
+ FAIL_IF(emit_fop_mem(compiler, (type & SLJIT_32) | FPU_LOAD, TMP_FREG1, src1, src1w));
+ src1 = TMP_FREG1;
}
- return push_inst(compiler, ((MOV | RD(dst_reg) | RM(src)) & ~COND_MASK) | cc);
+ cc = get_cc(compiler, type & ~SLJIT_32);
+ return push_inst(compiler, EMIT_FPU_OPERATION((VMOV_F32 & ~COND_MASK) | cc, (type & SLJIT_32), dst_freg, src1, 0));
}
+#undef EMIT_FPU_OPERATION
+
static sljit_s32 update_mem_addr(struct sljit_compiler *compiler, sljit_s32 *mem, sljit_sw *memw, sljit_s32 max_offset)
{
sljit_s32 arg = *mem;
sljit_sw argw = *memw;
sljit_uw imm, tmp;
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
- sljit_sw mask = max_offset >= 0xf00 ? 0xfff : 0xff;
- sljit_sw sign = max_offset >= 0xf00 ? 0x1000 : 0x100;
-#else /* !SLJIT_CONFIG_ARM_V5 */
sljit_sw mask = 0xfff;
sljit_sw sign = 0x1000;
SLJIT_ASSERT(max_offset >= 0xf00);
-#endif /* SLJIT_CONFIG_ARM_V5 */
*mem = TMP_REG1;
if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
*memw = 0;
- return push_inst(compiler, ADD | RD(TMP_REG1) | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | ((sljit_uw)(argw & 0x3) << 7));
+ return push_inst(compiler, ADD | RD(TMP_REG1) | RN(arg & REG_MASK) | RM(OFFS_REG(arg)) | ((sljit_ins)(argw & 0x3) << 7));
}
arg &= REG_MASK;
@@ -3234,158 +3560,6 @@ static sljit_s32 update_mem_addr(struct sljit_compiler *compiler, sljit_s32 *mem
return push_inst(compiler, ADD | RD(TMP_REG1) | RN(TMP_REG1) | RM(arg));
}
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
-
-static sljit_s32 sljit_emit_mem_unaligned(struct sljit_compiler *compiler, sljit_s32 type,
- sljit_s32 reg,
- sljit_s32 mem, sljit_sw memw)
-{
- sljit_s32 flags, steps, tmp_reg;
- sljit_uw add, shift;
-
- switch (type & 0xff) {
- case SLJIT_MOV_U8:
- case SLJIT_MOV_S8:
- flags = BYTE_SIZE;
- if (!(type & SLJIT_MEM_STORE))
- flags |= LOAD_DATA;
- if ((type & 0xff) == SLJIT_MOV_S8)
- flags |= SIGNED;
-
- return emit_op_mem(compiler, flags, reg, mem, memw, TMP_REG1);
-
- case SLJIT_MOV_U16:
- FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xfff - 1));
- flags = BYTE_SIZE;
- steps = 1;
- break;
-
- case SLJIT_MOV_S16:
- FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xff - 1));
- flags = BYTE_SIZE | SIGNED;
- steps = 1;
- break;
-
- default:
- if (type & SLJIT_MEM_UNALIGNED_32) {
- flags = WORD_SIZE;
- if (!(type & SLJIT_MEM_STORE))
- flags |= LOAD_DATA;
-
- return emit_op_mem(compiler, flags, reg, mem, memw, TMP_REG1);
- }
-
- if (!(type & SLJIT_MEM_UNALIGNED_16)) {
- FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xfff - 3));
- flags = BYTE_SIZE;
- steps = 3;
- break;
- }
-
- FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xff - 2));
-
- add = 1;
- if (memw < 0) {
- add = 0;
- memw = -memw;
- }
-
- tmp_reg = reg;
-
- if (type & SLJIT_MEM_STORE) {
- FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(HALF_SIZE, add, reg, mem, TYPE2_TRANSFER_IMM(memw))));
- FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG2) | RM(reg) | (16 << 7) | (2 << 4)));
- } else {
- if (reg == mem) {
- SLJIT_ASSERT(reg != TMP_REG1);
- tmp_reg = TMP_REG1;
- }
-
- FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(HALF_SIZE | LOAD_DATA, add, tmp_reg, mem, TYPE2_TRANSFER_IMM(memw))));
- }
-
- if (!add) {
- memw -= 2;
- if (memw <= 0) {
- memw = -memw;
- add = 1;
- }
- } else
- memw += 2;
-
- if (type & SLJIT_MEM_STORE)
- return push_inst(compiler, EMIT_DATA_TRANSFER(HALF_SIZE, add, TMP_REG2, mem, TYPE2_TRANSFER_IMM(memw)));
-
- FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(HALF_SIZE | LOAD_DATA, add, TMP_REG2, mem, TYPE2_TRANSFER_IMM(memw))));
- return push_inst(compiler, ORR | RD(reg) | RN(tmp_reg) | RM(TMP_REG2) | (16 << 7));
- }
-
- SLJIT_ASSERT(steps > 0);
-
- add = 1;
- if (memw < 0) {
- add = 0;
- memw = -memw;
- }
-
- if (type & SLJIT_MEM_STORE) {
- FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(BYTE_SIZE, add, reg, mem, memw)));
- FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG2) | RM(reg) | (8 << 7) | (2 << 4)));
-
- while (1) {
- if (!add) {
- memw -= 1;
- if (memw == 0)
- add = 1;
- } else
- memw += 1;
-
- FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(BYTE_SIZE, add, TMP_REG2, mem, memw)));
-
- if (--steps == 0)
- return SLJIT_SUCCESS;
-
- FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG2) | RM(TMP_REG2) | (8 << 7) | (2 << 4)));
- }
- }
-
- tmp_reg = reg;
-
- if (reg == mem) {
- SLJIT_ASSERT(reg != TMP_REG1);
- tmp_reg = TMP_REG1;
- }
-
- shift = 8;
- FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(BYTE_SIZE | LOAD_DATA, add, tmp_reg, mem, memw)));
-
- do {
- if (!add) {
- memw -= 1;
- if (memw == 0)
- add = 1;
- } else
- memw += 1;
-
- if (steps > 1) {
- FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(BYTE_SIZE | LOAD_DATA, add, TMP_REG2, mem, memw)));
- FAIL_IF(push_inst(compiler, ORR | RD(tmp_reg) | RN(tmp_reg) | RM(TMP_REG2) | (shift << 7)));
- shift += 8;
- }
- } while (--steps != 0);
-
- flags |= LOAD_DATA;
-
- if (flags & SIGNED)
- FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(flags, add, TMP_REG2, mem, TYPE2_TRANSFER_IMM(memw))));
- else
- FAIL_IF(push_inst(compiler, EMIT_DATA_TRANSFER(flags, add, TMP_REG2, mem, memw)));
-
- return push_inst(compiler, ORR | RD(reg) | RN(tmp_reg) | RM(TMP_REG2) | (shift << 7));
-}
-
-#endif /* SLJIT_CONFIG_ARM_V5 */
-
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type,
sljit_s32 reg,
sljit_s32 mem, sljit_sw memw)
@@ -3395,30 +3569,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compile
CHECK_ERROR();
CHECK(check_sljit_emit_mem(compiler, type, reg, mem, memw));
- if (!(reg & REG_PAIR_MASK)) {
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
- ADJUST_LOCAL_OFFSET(mem, memw);
-#endif /* SLJIT_CONFIG_ARM_V5 */
-
+ if (!(reg & REG_PAIR_MASK))
return sljit_emit_mem_unaligned(compiler, type, reg, mem, memw);
- }
ADJUST_LOCAL_OFFSET(mem, memw);
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
- if (type & (SLJIT_MEM_UNALIGNED | SLJIT_MEM_UNALIGNED_16)) {
- FAIL_IF(update_mem_addr(compiler, &mem, &memw, (type & SLJIT_MEM_UNALIGNED_16) ? 0xfff - 6 : 0xfff - 7));
-
- if (!(type & SLJIT_MEM_STORE) && REG_PAIR_FIRST(reg) == (mem & REG_MASK)) {
- FAIL_IF(sljit_emit_mem_unaligned(compiler, type, REG_PAIR_SECOND(reg), SLJIT_MEM1(mem), memw + SSIZE_OF(sw)));
- return sljit_emit_mem_unaligned(compiler, type, REG_PAIR_FIRST(reg), SLJIT_MEM1(mem), memw);
- }
-
- FAIL_IF(sljit_emit_mem_unaligned(compiler, type, REG_PAIR_FIRST(reg), SLJIT_MEM1(mem), memw));
- return sljit_emit_mem_unaligned(compiler, type, REG_PAIR_SECOND(reg), SLJIT_MEM1(mem), memw + SSIZE_OF(sw));
- }
-#endif /* SLJIT_CONFIG_ARM_V5 */
-
FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xfff - 4));
flags = WORD_SIZE;
@@ -3441,7 +3596,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem_update(struct sljit_compiler *
sljit_s32 mem, sljit_sw memw)
{
sljit_s32 flags;
- sljit_uw is_type1_transfer, inst;
+ sljit_ins is_type1_transfer, inst;
CHECK_ERROR();
CHECK(check_sljit_emit_mem_update(compiler, type, reg, mem, memw));
@@ -3500,7 +3655,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem_update(struct sljit_compiler *
if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {
memw &= 0x3;
- inst = EMIT_DATA_TRANSFER(flags, 1, reg, mem & REG_MASK, RM(OFFS_REG(mem)) | ((sljit_uw)memw << 7));
+ inst = EMIT_DATA_TRANSFER(flags, 1, reg, mem & REG_MASK, RM(OFFS_REG(mem)) | ((sljit_ins)memw << 7));
if (is_type1_transfer)
inst |= (1 << 25);
@@ -3526,7 +3681,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem_update(struct sljit_compiler *
else
memw = -memw;
- return push_inst(compiler, inst | (sljit_uw)memw);
+ return push_inst(compiler, inst | (sljit_ins)memw);
}
if (memw >= 0)
@@ -3534,106 +3689,752 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem_update(struct sljit_compiler *
else
memw = -memw;
- return push_inst(compiler, inst | TYPE2_TRANSFER_IMM((sljit_uw)memw));
+ return push_inst(compiler, inst | TYPE2_TRANSFER_IMM((sljit_ins)memw));
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem(struct sljit_compiler *compiler, sljit_s32 type,
sljit_s32 freg,
sljit_s32 mem, sljit_sw memw)
{
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
- sljit_s32 max_offset;
- sljit_s32 dst;
-#endif /* SLJIT_CONFIG_ARM_V5 */
-
CHECK_ERROR();
CHECK(check_sljit_emit_fmem(compiler, type, freg, mem, memw));
- if (type & SLJIT_MEM_UNALIGNED_32)
+ if (type & SLJIT_MEM_ALIGNED_32)
return emit_fop_mem(compiler, ((type ^ SLJIT_32) & SLJIT_32) | ((type & SLJIT_MEM_STORE) ? 0 : FPU_LOAD), freg, mem, memw);
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
if (type & SLJIT_MEM_STORE) {
FAIL_IF(push_inst(compiler, VMOV | (1 << 20) | VN(freg) | RD(TMP_REG2)));
if (type & SLJIT_32)
- return sljit_emit_mem_unaligned(compiler, SLJIT_MOV | SLJIT_MEM_STORE | (type & SLJIT_MEM_UNALIGNED_16), TMP_REG2, mem, memw);
-
- max_offset = 0xfff - 7;
- if (type & SLJIT_MEM_UNALIGNED_16)
- max_offset++;
+ return emit_op_mem(compiler, WORD_SIZE, TMP_REG2, mem, memw, TMP_REG1);
- FAIL_IF(update_mem_addr(compiler, &mem, &memw, max_offset));
+ FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xfff - 4));
mem |= SLJIT_MEM;
- FAIL_IF(sljit_emit_mem_unaligned(compiler, SLJIT_MOV | SLJIT_MEM_STORE | (type & SLJIT_MEM_UNALIGNED_16), TMP_REG2, mem, memw));
-
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, mem, memw, TMP_REG1));
FAIL_IF(push_inst(compiler, VMOV | (1 << 20) | VN(freg) | 0x80 | RD(TMP_REG2)));
- return sljit_emit_mem_unaligned(compiler, SLJIT_MOV | SLJIT_MEM_STORE | (type & SLJIT_MEM_UNALIGNED_16), TMP_REG2, mem, memw + 4);
+ return emit_op_mem(compiler, WORD_SIZE, TMP_REG2, mem, memw + 4, TMP_REG1);
}
- max_offset = (type & SLJIT_32) ? 0xfff - 3 : 0xfff - 7;
- if (type & SLJIT_MEM_UNALIGNED_16)
- max_offset++;
+ if (type & SLJIT_32) {
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG2, mem, memw, TMP_REG1));
+ return push_inst(compiler, VMOV | VN(freg) | RD(TMP_REG2));
+ }
+
+ FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xfff - 4));
+ mem |= SLJIT_MEM;
+
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG2, mem, memw, TMP_REG1));
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG1, mem, memw + 4, TMP_REG1));
+ return push_inst(compiler, VMOV2 | VM(freg) | RD(TMP_REG2) | RN(TMP_REG1));
+}
- FAIL_IF(update_mem_addr(compiler, &mem, &memw, max_offset));
+static sljit_s32 sljit_emit_simd_mem_offset(struct sljit_compiler *compiler, sljit_s32 *mem_ptr, sljit_sw memw)
+{
+ sljit_s32 mem = *mem_ptr;
+ sljit_uw imm;
- dst = TMP_REG1;
+ if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {
+ *mem_ptr = TMP_REG1;
+ return push_inst(compiler, ADD | RD(TMP_REG1) | RN(mem & REG_MASK) | RM(OFFS_REG(mem)) | ((sljit_ins)(memw & 0x3) << 7));
+ }
- /* Stack offset adjustment is not needed because dst
- is not stored on the stack when mem is SLJIT_SP. */
+ if (SLJIT_UNLIKELY(!(mem & REG_MASK))) {
+ *mem_ptr = TMP_REG1;
+ return load_immediate(compiler, TMP_REG1, (sljit_uw)memw);
+ }
- if (mem == TMP_REG1) {
- dst = SLJIT_R3;
+ mem &= REG_MASK;
- if (compiler->scratches >= 4)
- FAIL_IF(push_inst(compiler, STR | (1 << 21) | RN(SLJIT_SP) | RD(SLJIT_R3) | 8));
+ if (memw == 0) {
+ *mem_ptr = mem;
+ return SLJIT_SUCCESS;
}
- mem |= SLJIT_MEM;
+ *mem_ptr = TMP_REG1;
+ imm = get_imm((sljit_uw)(memw < 0 ? -memw : memw));
+
+ if (imm != 0)
+ return push_inst(compiler, ((memw < 0) ? SUB : ADD) | RD(TMP_REG1) | RN(mem) | imm);
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)memw));
+ return push_inst(compiler, ADD | RD(TMP_REG1) | RN(TMP_REG1) | RM(mem));
+}
+
+static SLJIT_INLINE sljit_s32 simd_get_quad_reg_index(sljit_s32 freg)
+{
+ freg += freg & 0x1;
+
+ SLJIT_ASSERT((freg_map[freg] & 0x1) == (freg <= SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS));
+
+ if (freg <= SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS)
+ freg--;
+
+ return freg;
+}
+
+#define SLJIT_QUAD_OTHER_HALF(freg) ((((freg) & 0x1) << 1) - 1)
- FAIL_IF(sljit_emit_mem_unaligned(compiler, SLJIT_MOV | (type & SLJIT_MEM_UNALIGNED_16), dst, mem, memw));
- FAIL_IF(push_inst(compiler, VMOV | VN(freg) | RD(dst)));
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_mov(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 srcdst, sljit_sw srcdstw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_s32 alignment = SLJIT_SIMD_GET_ELEM2_SIZE(type);
+ sljit_ins ins;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_mov(compiler, type, freg, srcdst, srcdstw));
+
+ ADJUST_LOCAL_OFFSET(srcdst, srcdstw);
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (reg_size == 4)
+ freg = simd_get_quad_reg_index(freg);
+
+ if (!(srcdst & SLJIT_MEM)) {
+ if (reg_size == 4)
+ srcdst = simd_get_quad_reg_index(srcdst);
- if (!(type & SLJIT_32)) {
- FAIL_IF(sljit_emit_mem_unaligned(compiler, SLJIT_MOV | (type & SLJIT_MEM_UNALIGNED_16), dst, mem, memw + 4));
- FAIL_IF(push_inst(compiler, VMOV | VN(freg) | 0x80 | RD(dst)));
+ if (type & SLJIT_SIMD_STORE)
+ ins = VD(srcdst) | VN(freg) | VM(freg);
+ else
+ ins = VD(freg) | VN(srcdst) | VM(srcdst);
+
+ if (reg_size == 4)
+ ins |= (sljit_ins)1 << 6;
+
+ return push_inst(compiler, VORR | ins);
}
- if (dst == SLJIT_R3 && compiler->scratches >= 4)
- FAIL_IF(push_inst(compiler, (LDR ^ (0x1 << 24)) | (0x1 << 23) | RN(SLJIT_SP) | RD(SLJIT_R3) | 8));
- return SLJIT_SUCCESS;
-#else /* !SLJIT_CONFIG_ARM_V5 */
- if (type & SLJIT_MEM_STORE) {
- FAIL_IF(push_inst(compiler, VMOV | (1 << 20) | VN(freg) | RD(TMP_REG2)));
+ FAIL_IF(sljit_emit_simd_mem_offset(compiler, &srcdst, srcdstw));
- if (type & SLJIT_32)
- return emit_op_mem(compiler, WORD_SIZE, TMP_REG2, mem, memw, TMP_REG1);
+ if (elem_size > 3)
+ elem_size = 3;
- FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xfff - 4));
- mem |= SLJIT_MEM;
+ ins = ((type & SLJIT_SIMD_STORE) ? VST1 : VLD1) | VD(freg)
+ | (sljit_ins)((reg_size == 3) ? (0x7 << 8) : (0xa << 8));
- FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, mem, memw, TMP_REG1));
- FAIL_IF(push_inst(compiler, VMOV | (1 << 20) | VN(freg) | 0x80 | RD(TMP_REG2)));
- return emit_op_mem(compiler, WORD_SIZE, TMP_REG2, mem, memw + 4, TMP_REG1);
+ SLJIT_ASSERT(reg_size >= alignment);
+
+ if (alignment == 3)
+ ins |= 0x10;
+ else if (alignment >= 3)
+ ins |= 0x20;
+
+ return push_inst(compiler, ins | RN(srcdst) | ((sljit_ins)elem_size) << 6 | 0xf);
+}
+
+static sljit_ins simd_get_imm(sljit_s32 elem_size, sljit_uw value)
+{
+ sljit_ins result;
+
+ if (elem_size > 1 && (sljit_u16)value == (value >> 16)) {
+ elem_size = 1;
+ value = (sljit_u16)value;
}
- if (type & SLJIT_32) {
- FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG2, mem, memw, TMP_REG1));
- return push_inst(compiler, VMOV | VN(freg) | RD(TMP_REG2));
+ if (elem_size == 1 && (sljit_u8)value == (value >> 8)) {
+ elem_size = 0;
+ value = (sljit_u8)value;
}
- FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xfff - 4));
- mem |= SLJIT_MEM;
+ switch (elem_size) {
+ case 0:
+ SLJIT_ASSERT(value <= 0xff);
+ result = 0xe00;
+ break;
+ case 1:
+ SLJIT_ASSERT(value <= 0xffff);
+ result = 0;
- FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG2, mem, memw, TMP_REG1));
- FAIL_IF(emit_op_mem(compiler, WORD_SIZE | LOAD_DATA, TMP_REG1, mem, memw + 4, TMP_REG1));
- return push_inst(compiler, VMOV2 | VM(freg) | RD(TMP_REG2) | RN(TMP_REG1));
-#endif /* SLJIT_CONFIG_ARM_V5 */
+ while (1) {
+ if (value <= 0xff) {
+ result |= 0x800;
+ break;
+ }
+
+ if ((value & 0xff) == 0) {
+ value >>= 8;
+ result |= 0xa00;
+ break;
+ }
+
+ if (result != 0)
+ return ~(sljit_ins)0;
+
+ value ^= (sljit_uw)0xffff;
+ result = (1 << 5);
+ }
+ break;
+ default:
+ SLJIT_ASSERT(value <= 0xffffffff);
+ result = 0;
+
+ while (1) {
+ if (value <= 0xff) {
+ result |= 0x000;
+ break;
+ }
+
+ if ((value & ~(sljit_uw)0xff00) == 0) {
+ value >>= 8;
+ result |= 0x200;
+ break;
+ }
+
+ if ((value & ~(sljit_uw)0xff0000) == 0) {
+ value >>= 16;
+ result |= 0x400;
+ break;
+ }
+
+ if ((value & ~(sljit_uw)0xff000000) == 0) {
+ value >>= 24;
+ result |= 0x600;
+ break;
+ }
+
+ if ((value & (sljit_uw)0xff) == 0xff && (value >> 16) == 0) {
+ value >>= 8;
+ result |= 0xc00;
+ break;
+ }
+
+ if ((value & (sljit_uw)0xffff) == 0xffff && (value >> 24) == 0) {
+ value >>= 16;
+ result |= 0xd00;
+ break;
+ }
+
+ if (result != 0)
+ return ~(sljit_ins)0;
+
+ value = ~value;
+ result = (1 << 5);
+ }
+ break;
+ }
+
+ return ((sljit_ins)value & 0xf) | (((sljit_ins)value & 0x70) << 12) | (((sljit_ins)value & 0x80) << 17) | result;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins, imm;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_replicate(compiler, type, freg, src, srcw));
+
+ ADJUST_LOCAL_OFFSET(src, srcw);
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) ? (elem_size < 2 || elem_size > 3) : (elem_size > 2))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (reg_size == 4)
+ freg = simd_get_quad_reg_index(freg);
+
+ if (src == SLJIT_IMM && srcw == 0)
+ return push_inst(compiler, VMOV_i | ((reg_size == 4) ? (1 << 6) : 0) | VD(freg));
+
+ if (SLJIT_UNLIKELY(elem_size == 3)) {
+ SLJIT_ASSERT(type & SLJIT_SIMD_FLOAT);
+
+ if (src & SLJIT_MEM) {
+ FAIL_IF(emit_fop_mem(compiler, FPU_LOAD | SLJIT_32, freg, src, srcw));
+ src = freg;
+ } else if (freg != src)
+ FAIL_IF(push_inst(compiler, VORR | VD(freg) | VN(src) | VM(src)));
+
+ freg += SLJIT_QUAD_OTHER_HALF(freg);
+
+ if (freg != src)
+ return push_inst(compiler, VORR | VD(freg) | VN(src) | VM(src));
+ return SLJIT_SUCCESS;
+ }
+
+ if (src & SLJIT_MEM) {
+ FAIL_IF(sljit_emit_simd_mem_offset(compiler, &src, srcw));
+
+ ins = (sljit_ins)(elem_size << 6);
+
+ if (reg_size == 4)
+ ins |= (sljit_ins)1 << 5;
+
+ return push_inst(compiler, VLD1_r | ins | VD(freg) | RN(src) | 0xf);
+ }
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ SLJIT_ASSERT(elem_size == 2);
+ ins = ((sljit_ins)freg_ebit_map[src] << (16 + 2 + 1)) | ((sljit_ins)1 << (16 + 2));
+
+ if (reg_size == 4)
+ ins |= (sljit_ins)1 << 6;
+
+ return push_inst(compiler, VDUP_s | ins | VD(freg) | (sljit_ins)freg_map[src]);
+ }
+
+ if (src == SLJIT_IMM) {
+ if (elem_size < 2)
+ srcw &= ((sljit_sw)1 << (((sljit_sw)1 << elem_size) << 3)) - 1;
+
+ imm = simd_get_imm(elem_size, (sljit_uw)srcw);
+
+ if (imm != ~(sljit_ins)0) {
+ if (reg_size == 4)
+ imm |= (sljit_ins)1 << 6;
+
+ return push_inst(compiler, VMOV_i | imm | VD(freg));
+ }
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)srcw));
+ src = TMP_REG1;
+ }
+
+ switch (elem_size) {
+ case 0:
+ ins = 1 << 22;
+ break;
+ case 1:
+ ins = 1 << 5;
+ break;
+ default:
+ ins = 0;
+ break;
+ }
+
+ if (reg_size == 4)
+ ins |= (sljit_ins)1 << 21;
+
+ return push_inst(compiler, VDUP | ins | VN(freg) | RD(src));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg, sljit_s32 lane_index,
+ sljit_s32 srcdst, sljit_sw srcdstw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_lane_mov(compiler, type, freg, lane_index, srcdst, srcdstw));
+
+ ADJUST_LOCAL_OFFSET(srcdst, srcdstw);
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) ? (elem_size < 2 || elem_size > 3) : (elem_size > 2))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (reg_size == 4)
+ freg = simd_get_quad_reg_index(freg);
+
+ if (type & SLJIT_SIMD_LANE_ZERO) {
+ ins = (reg_size == 3) ? 0 : ((sljit_ins)1 << 6);
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ if (elem_size == 3 && !(srcdst & SLJIT_MEM)) {
+ if (lane_index == 1)
+ freg += SLJIT_QUAD_OTHER_HALF(freg);
+
+ if (srcdst != freg)
+ FAIL_IF(push_inst(compiler, VORR | VD(freg) | VN(srcdst) | VM(srcdst)));
+
+ freg += SLJIT_QUAD_OTHER_HALF(freg);
+ return push_inst(compiler, VMOV_i | VD(freg));
+ }
+
+ if (srcdst == freg || (elem_size == 3 && srcdst == (freg + SLJIT_QUAD_OTHER_HALF(freg)))) {
+ FAIL_IF(push_inst(compiler, VORR | ins | VD(TMP_FREG2) | VN(freg) | VM(freg)));
+ srcdst = TMP_FREG2;
+ srcdstw = 0;
+ }
+ }
+
+ FAIL_IF(push_inst(compiler, VMOV_i | ins | VD(freg)));
+ }
+
+ if (reg_size == 4 && lane_index >= (0x8 >> elem_size)) {
+ lane_index -= (0x8 >> elem_size);
+ freg += SLJIT_QUAD_OTHER_HALF(freg);
+ }
+
+ if (srcdst & SLJIT_MEM) {
+ if (elem_size == 3)
+ return emit_fop_mem(compiler, ((type & SLJIT_SIMD_STORE) ? 0 : FPU_LOAD) | SLJIT_32, freg, srcdst, srcdstw);
+
+ FAIL_IF(sljit_emit_simd_mem_offset(compiler, &srcdst, srcdstw));
+
+ lane_index = lane_index << elem_size;
+ ins = (sljit_ins)((elem_size << 10) | (lane_index << 5));
+ return push_inst(compiler, ((type & SLJIT_SIMD_STORE) ? VST1_s : VLD1_s) | ins | VD(freg) | RN(srcdst) | 0xf);
+ }
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ if (elem_size == 3) {
+ if (type & SLJIT_SIMD_STORE)
+ return push_inst(compiler, VORR | VD(srcdst) | VN(freg) | VM(freg));
+ return push_inst(compiler, VMOV_F32 | SLJIT_32 | VD(freg) | VM(srcdst));
+ }
+
+ if (type & SLJIT_SIMD_STORE) {
+ if (freg_ebit_map[freg] == 0) {
+ if (lane_index == 1)
+ freg = SLJIT_F64_SECOND(freg);
+
+ return push_inst(compiler, VMOV_F32 | VD(srcdst) | VM(freg));
+ }
+
+ FAIL_IF(push_inst(compiler, VMOV_s | (1 << 20) | ((sljit_ins)lane_index << 21) | VN(freg) | RD(TMP_REG1)));
+ return push_inst(compiler, VMOV | VN(srcdst) | RD(TMP_REG1));
+ }
+
+ FAIL_IF(push_inst(compiler, VMOV | (1 << 20) | VN(srcdst) | RD(TMP_REG1)));
+ return push_inst(compiler, VMOV_s | ((sljit_ins)lane_index << 21) | VN(freg) | RD(TMP_REG1));
+ }
+
+ if (srcdst == SLJIT_IMM) {
+ if (elem_size < 2)
+ srcdstw &= ((sljit_sw)1 << (((sljit_sw)1 << elem_size) << 3)) - 1;
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)srcdstw));
+ srcdst = TMP_REG1;
+ }
+
+ if (elem_size == 0)
+ ins = 0x400000;
+ else if (elem_size == 1)
+ ins = 0x20;
+ else
+ ins = 0;
+
+ lane_index = lane_index << elem_size;
+ ins |= (sljit_ins)(((lane_index & 0x4) << 19) | ((lane_index & 0x3) << 5));
+
+ if (type & SLJIT_SIMD_STORE) {
+ ins |= (1 << 20);
+
+ if (elem_size < 2 && !(type & SLJIT_SIMD_LANE_SIGNED))
+ ins |= (1 << 23);
+ }
+
+ return push_inst(compiler, VMOV_s | ins | VN(freg) | RD(srcdst));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_s32 src_lane_index)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_lane_replicate(compiler, type, freg, src, src_lane_index));
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (reg_size == 4) {
+ freg = simd_get_quad_reg_index(freg);
+ src = simd_get_quad_reg_index(src);
+
+ if (src_lane_index >= (0x8 >> elem_size)) {
+ src_lane_index -= (0x8 >> elem_size);
+ src += SLJIT_QUAD_OTHER_HALF(src);
+ }
+ }
+
+ if (elem_size == 3) {
+ if (freg != src)
+ FAIL_IF(push_inst(compiler, VORR | VD(freg) | VN(src) | VM(src)));
+
+ freg += SLJIT_QUAD_OTHER_HALF(freg);
+
+ if (freg != src)
+ return push_inst(compiler, VORR | VD(freg) | VN(src) | VM(src));
+ return SLJIT_SUCCESS;
+ }
+
+ ins = ((((sljit_ins)src_lane_index << 1) | 1) << (16 + elem_size));
+
+ if (reg_size == 4)
+ ins |= (sljit_ins)1 << 6;
+
+ return push_inst(compiler, VDUP_s | ins | VD(freg) | VM(src));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_extend(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_s32 elem2_size = SLJIT_SIMD_GET_ELEM2_SIZE(type);
+ sljit_s32 dst_reg;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_extend(compiler, type, freg, src, srcw));
+
+ ADJUST_LOCAL_OFFSET(src, srcw);
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size != 2 || elem2_size != 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (reg_size == 4)
+ freg = simd_get_quad_reg_index(freg);
+
+ if (src & SLJIT_MEM) {
+ FAIL_IF(sljit_emit_simd_mem_offset(compiler, &src, srcw));
+ if (reg_size == 4 && elem2_size - elem_size == 1)
+ FAIL_IF(push_inst(compiler, VLD1 | (0x7 << 8) | VD(freg) | RN(src) | 0xf));
+ else
+ FAIL_IF(push_inst(compiler, VLD1_s | (sljit_ins)((reg_size - elem2_size + elem_size) << 10) | VD(freg) | RN(src) | 0xf));
+ src = freg;
+ } else if (reg_size == 4)
+ src = simd_get_quad_reg_index(src);
+
+ if (!(type & SLJIT_SIMD_FLOAT)) {
+ dst_reg = (reg_size == 4) ? freg : TMP_FREG2;
+
+ do {
+ FAIL_IF(push_inst(compiler, VSHLL | ((type & SLJIT_SIMD_EXTEND_SIGNED) ? 0 : (1 << 24))
+ | ((sljit_ins)1 << (19 + elem_size)) | VD(dst_reg) | VM(src)));
+ src = dst_reg;
+ } while (++elem_size < elem2_size);
+
+ if (dst_reg == TMP_FREG2)
+ return push_inst(compiler, VORR | VD(freg) | VN(TMP_FREG2) | VM(TMP_FREG2));
+ return SLJIT_SUCCESS;
+ }
+
+ /* No SIMD variant, must use VFP instead. */
+ SLJIT_ASSERT(reg_size == 4);
+
+ if (freg == src) {
+ freg += SLJIT_QUAD_OTHER_HALF(freg);
+ FAIL_IF(push_inst(compiler, VCVT_F64_F32 | VD(freg) | VM(src) | 0x20));
+ freg += SLJIT_QUAD_OTHER_HALF(freg);
+ return push_inst(compiler, VCVT_F64_F32 | VD(freg) | VM(src));
+ }
+
+ FAIL_IF(push_inst(compiler, VCVT_F64_F32 | VD(freg) | VM(src)));
+ freg += SLJIT_QUAD_OTHER_HALF(freg);
+ return push_inst(compiler, VCVT_F64_F32 | VD(freg) | VM(src) | 0x20);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 dst, sljit_sw dstw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins, imms;
+ sljit_s32 dst_r;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_sign(compiler, type, freg, dst, dstw));
+
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ switch (elem_size) {
+ case 0:
+ imms = 0x243219;
+ ins = VSHR | (1 << 24) | (0x9 << 16);
+ break;
+ case 1:
+ imms = (reg_size == 4) ? 0x243219 : 0x2231;
+ ins = VSHR | (1 << 24) | (0x11 << 16);
+ break;
+ case 2:
+ imms = (reg_size == 4) ? 0x2231 : 0x21;
+ ins = VSHR | (1 << 24) | (0x21 << 16);
+ break;
+ default:
+ imms = 0x21;
+ ins = VSHR | (1 << 24) | (0x1 << 16) | (1 << 7);
+ break;
+ }
+
+ if (reg_size == 4) {
+ freg = simd_get_quad_reg_index(freg);
+ ins |= (sljit_ins)1 << 6;
+ }
+
+ SLJIT_ASSERT((freg_map[TMP_FREG2] & 0x1) == 0);
+ FAIL_IF(push_inst(compiler, ins | VD(TMP_FREG2) | VM(freg)));
+
+ if (reg_size == 4 && elem_size > 0)
+ FAIL_IF(push_inst(compiler, VMOVN | ((sljit_ins)(elem_size - 1) << 18) | VD(TMP_FREG2) | VM(TMP_FREG2)));
+
+ ins = (reg_size == 4 && elem_size == 0) ? (1 << 6) : 0;
+
+ while (imms >= 0x100) {
+ FAIL_IF(push_inst(compiler, VSRA | (1 << 24) | ins | ((imms & 0xff) << 16) | VD(TMP_FREG2) | VM(TMP_FREG2)));
+ imms >>= 8;
+ }
+
+ FAIL_IF(push_inst(compiler, VSRA | (1 << 24) | ins | (1 << 7) | (imms << 16) | VD(TMP_FREG2) | VM(TMP_FREG2)));
+
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+ FAIL_IF(push_inst(compiler, VMOV_s | (1 << 20) | (1 << 23) | (0x2 << 21) | RD(dst_r) | VN(TMP_FREG2)));
+
+ if (reg_size == 4 && elem_size == 0) {
+ SLJIT_ASSERT(freg_map[TMP_FREG2] + 1 == freg_map[TMP_FREG1]);
+ FAIL_IF(push_inst(compiler, VMOV_s | (1 << 20) | (1 << 23) | (0x2 << 21) | RD(TMP_REG2) | VN(TMP_FREG1)));
+ FAIL_IF(push_inst(compiler, ORR | RD(dst_r) | RN(dst_r) | RM(TMP_REG2) | (0x8 << 7)));
+ }
+
+ if (dst_r == TMP_REG1)
+ return emit_op_mem(compiler, WORD_SIZE, TMP_REG1, dst, dstw, TMP_REG2);
+
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_op2(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg, sljit_s32 src1_freg, sljit_s32 src2_freg)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_op2(compiler, type, dst_freg, src1_freg, src2_freg));
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ switch (SLJIT_SIMD_GET_OPCODE(type)) {
+ case SLJIT_SIMD_OP2_AND:
+ ins = VAND;
+ break;
+ case SLJIT_SIMD_OP2_OR:
+ ins = VORR;
+ break;
+ case SLJIT_SIMD_OP2_XOR:
+ ins = VEOR;
+ break;
+ }
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (reg_size == 4) {
+ dst_freg = simd_get_quad_reg_index(dst_freg);
+ src1_freg = simd_get_quad_reg_index(src1_freg);
+ src2_freg = simd_get_quad_reg_index(src2_freg);
+ ins |= (sljit_ins)1 << 6;
+ }
+
+ return push_inst(compiler, ins | VD(dst_freg) | VN(src1_freg) | VM(src2_freg));
}
#undef FPU_LOAD
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_load(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_reg,
+ sljit_s32 mem_reg)
+{
+ sljit_u32 ins;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_atomic_load(compiler, op, dst_reg, mem_reg));
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MOV_U8:
+ ins = LDREXB;
+ break;
+ case SLJIT_MOV_U16:
+ ins = LDREXH;
+ break;
+ default:
+ ins = LDREX;
+ break;
+ }
+
+ return push_inst(compiler, ins | RN(mem_reg) | RD(dst_reg));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src_reg,
+ sljit_s32 mem_reg,
+ sljit_s32 temp_reg)
+{
+ sljit_u32 ins;
+
+ /* temp_reg == mem_reg is undefined so use another temp register */
+ SLJIT_UNUSED_ARG(temp_reg);
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_atomic_store(compiler, op, src_reg, mem_reg, temp_reg));
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MOV_U8:
+ ins = STREXB;
+ break;
+ case SLJIT_MOV_U16:
+ ins = STREXH;
+ break;
+ default:
+ ins = STREX;
+ break;
+ }
+
+ FAIL_IF(push_inst(compiler, ins | RN(mem_reg) | RD(TMP_REG1) | RM(src_reg)));
+ if (op & SLJIT_SET_ATOMIC_STORED)
+ return push_inst(compiler, CMP | SET_FLAGS | SRC2_IMM | RN(TMP_REG1));
+
+ return SLJIT_SUCCESS;
+}
+
SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
{
struct sljit_const *const_;
@@ -3645,13 +4446,13 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
PTR_FAIL_IF(push_inst_with_unique_literal(compiler,
- EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, dst_r, TMP_PC, 0), (sljit_uw)init_value));
+ EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, dst_r, TMP_PC, 0), (sljit_ins)init_value));
compiler->patches++;
-#else
+#else /* !SLJIT_CONFIG_ARM_V6 */
PTR_FAIL_IF(emit_imm(compiler, dst_r, init_value));
-#endif
+#endif /* SLJIT_CONFIG_ARM_V6 */
const_ = (struct sljit_const*)ensure_abuf(compiler, sizeof(struct sljit_const));
PTR_FAIL_IF(!const_);
@@ -3673,12 +4474,12 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct slj
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
-#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5)
+#if (defined SLJIT_CONFIG_ARM_V6 && SLJIT_CONFIG_ARM_V6)
PTR_FAIL_IF(push_inst_with_unique_literal(compiler, EMIT_DATA_TRANSFER(WORD_SIZE | LOAD_DATA, 1, dst_r, TMP_PC, 0), 0));
compiler->patches++;
-#else
+#else /* !SLJIT_CONFIG_ARM_V6 */
PTR_FAIL_IF(emit_imm(compiler, dst_r, 0));
-#endif
+#endif /* SLJIT_CONFIG_ARM_V6 */
put_label = (struct sljit_put_label*)ensure_abuf(compiler, sizeof(struct sljit_put_label));
PTR_FAIL_IF(!put_label);
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeARM_64.c b/src/3rdparty/pcre2/src/sljit/sljitNativeARM_64.c
index 89f747e7c8..b268582f42 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeARM_64.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeARM_64.c
@@ -67,79 +67,123 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
/* Instrucion forms */
/* --------------------------------------------------------------------- */
-#define ADC 0x9a000000
-#define ADD 0x8b000000
-#define ADDE 0x8b200000
-#define ADDI 0x91000000
-#define AND 0x8a000000
-#define ANDI 0x92000000
-#define ASRV 0x9ac02800
-#define B 0x14000000
-#define B_CC 0x54000000
-#define BL 0x94000000
-#define BLR 0xd63f0000
-#define BR 0xd61f0000
-#define BRK 0xd4200000
-#define CBZ 0xb4000000
-#define CLZ 0xdac01000
-#define CSEL 0x9a800000
-#define CSINC 0x9a800400
-#define EOR 0xca000000
-#define EORI 0xd2000000
-#define EXTR 0x93c00000
-#define FABS 0x1e60c000
-#define FADD 0x1e602800
-#define FCMP 0x1e602000
-#define FCVT 0x1e224000
-#define FCVTZS 0x9e780000
-#define FDIV 0x1e601800
-#define FMOV 0x1e604000
-#define FMUL 0x1e600800
-#define FNEG 0x1e614000
-#define FSUB 0x1e603800
-#define LDRI 0xf9400000
-#define LDRI_F64 0xfd400000
-#define LDRI_POST 0xf8400400
-#define LDP 0xa9400000
-#define LDP_F64 0x6d400000
-#define LDP_POST 0xa8c00000
-#define LDR_PRE 0xf8400c00
-#define LSLV 0x9ac02000
-#define LSRV 0x9ac02400
-#define MADD 0x9b000000
-#define MOVK 0xf2800000
-#define MOVN 0x92800000
-#define MOVZ 0xd2800000
-#define NOP 0xd503201f
-#define ORN 0xaa200000
-#define ORR 0xaa000000
-#define ORRI 0xb2000000
-#define RBIT 0xdac00000
-#define RET 0xd65f0000
-#define RORV 0x9ac02c00
-#define SBC 0xda000000
-#define SBFM 0x93000000
-#define SCVTF 0x9e620000
-#define SDIV 0x9ac00c00
-#define SMADDL 0x9b200000
-#define SMULH 0x9b403c00
-#define STP 0xa9000000
-#define STP_F64 0x6d000000
-#define STP_PRE 0xa9800000
-#define STRB 0x38206800
-#define STRBI 0x39000000
-#define STRI 0xf9000000
-#define STRI_F64 0xfd000000
-#define STR_FI 0x3d000000
-#define STR_FR 0x3c206800
-#define STUR_FI 0x3c000000
-#define STURBI 0x38000000
-#define SUB 0xcb000000
-#define SUBI 0xd1000000
-#define SUBS 0xeb000000
-#define UBFM 0xd3000000
-#define UDIV 0x9ac00800
-#define UMULH 0x9bc03c00
+#define ADC 0x9a000000
+#define ADD 0x8b000000
+#define ADDE 0x8b200000
+#define ADDI 0x91000000
+#define AND 0x8a000000
+#define ANDI 0x92000000
+#define AND_v 0x0e201c00
+#define ASRV 0x9ac02800
+#define B 0x14000000
+#define B_CC 0x54000000
+#define BL 0x94000000
+#define BLR 0xd63f0000
+#define BR 0xd61f0000
+#define BRK 0xd4200000
+#define CAS 0xc8a07c00
+#define CASB 0x08a07c00
+#define CASH 0x48a07c00
+#define CBZ 0xb4000000
+#define CCMPI 0xfa400800
+#define CLZ 0xdac01000
+#define CSEL 0x9a800000
+#define CSINC 0x9a800400
+#define DUP_e 0x0e000400
+#define DUP_g 0x0e000c00
+#define EOR 0xca000000
+#define EOR_v 0x2e201c00
+#define EORI 0xd2000000
+#define EXTR 0x93c00000
+#define FABS 0x1e60c000
+#define FADD 0x1e602800
+#define FCMP 0x1e602000
+#define FCSEL 0x1e600c00
+#define FCVT 0x1e224000
+#define FCVTL 0x0e217800
+#define FCVTZS 0x9e780000
+#define FDIV 0x1e601800
+#define FMOV 0x1e604000
+#define FMOV_R 0x9e660000
+#define FMOV_I 0x1e601000
+#define FMUL 0x1e600800
+#define FNEG 0x1e614000
+#define FSUB 0x1e603800
+#define INS 0x4e001c00
+#define INS_e 0x6e000400
+#define LD1 0x0c407000
+#define LD1_s 0x0d400000
+#define LD1R 0x0d40c000
+#define LDRI 0xf9400000
+#define LDRI_F64 0xfd400000
+#define LDRI_POST 0xf8400400
+#define LDP 0xa9400000
+#define LDP_F64 0x6d400000
+#define LDP_POST 0xa8c00000
+#define LDR_PRE 0xf8400c00
+#define LDXR 0xc85f7c00
+#define LDXRB 0x085f7c00
+#define LDXRH 0x485f7c00
+#define LSLV 0x9ac02000
+#define LSRV 0x9ac02400
+#define MADD 0x9b000000
+#define MOVI 0x0f000400
+#define MOVK 0xf2800000
+#define MOVN 0x92800000
+#define MOVZ 0xd2800000
+#define NOP 0xd503201f
+#define ORN 0xaa200000
+#define ORR 0xaa000000
+#define ORR_v 0x0ea01c00
+#define ORRI 0xb2000000
+#define RBIT 0xdac00000
+#define RET 0xd65f0000
+#define REV 0xdac00c00
+#define REV16 0xdac00400
+#define RORV 0x9ac02c00
+#define SBC 0xda000000
+#define SBFM 0x93400000
+#define SCVTF 0x9e620000
+#define SDIV 0x9ac00c00
+#define SMADDL 0x9b200000
+#define SMOV 0x0e002c00
+#define SMULH 0x9b403c00
+#define SSHLL 0x0f00a400
+#define ST1 0x0c007000
+#define ST1_s 0x0d000000
+#define STP 0xa9000000
+#define STP_F64 0x6d000000
+#define STP_PRE 0xa9800000
+#define STRB 0x38206800
+#define STRBI 0x39000000
+#define STRI 0xf9000000
+#define STRI_F64 0xfd000000
+#define STR_FI 0x3d000000
+#define STR_FR 0x3c206800
+#define STUR_FI 0x3c000000
+#define STURBI 0x38000000
+#define STXR 0xc8007c00
+#define STXRB 0x8007c00
+#define STXRH 0x48007c00
+#define SUB 0xcb000000
+#define SUBI 0xd1000000
+#define SUBS 0xeb000000
+#define TBZ 0x36000000
+#define UBFM 0xd3400000
+#define UCVTF 0x9e630000
+#define UDIV 0x9ac00800
+#define UMOV 0x0e003c00
+#define UMULH 0x9bc03c00
+#define USHLL 0x2f00a400
+#define USHR 0x2f000400
+#define USRA 0x2f001400
+#define XTN 0x0e212800
+
+#define CSET (CSINC | RM(TMP_ZERO) | RN(TMP_ZERO))
+#define LDR (STRI | (1 << 22))
+#define LDRB (STRBI | (1 << 22))
+#define LDRH (LDRB | (1 << 30))
+#define MOV (ORR | RN(TMP_ZERO))
static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins)
{
@@ -175,7 +219,7 @@ static SLJIT_INLINE sljit_sw detect_jump_type(struct sljit_jump *jump, sljit_ins
target_addr = (sljit_uw)(code + jump->u.label->size) + (sljit_uw)executable_offset;
}
- diff = (sljit_sw)target_addr - (sljit_sw)(code_ptr + 4) - executable_offset;
+ diff = (sljit_sw)target_addr - (sljit_sw)(code_ptr - 4) - executable_offset;
if (jump->flags & IS_COND) {
diff += SSIZE_OF(ins);
@@ -385,8 +429,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
{
switch (feature_type) {
case SLJIT_HAS_FPU:
+ case SLJIT_HAS_SIMD:
#ifdef SLJIT_IS_FPU_AVAILABLE
- return SLJIT_IS_FPU_AVAILABLE;
+ return (SLJIT_IS_FPU_AVAILABLE) != 0;
#else
/* Available by default. */
return 1;
@@ -394,9 +439,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
case SLJIT_HAS_CLZ:
case SLJIT_HAS_CTZ:
+ case SLJIT_HAS_REV:
case SLJIT_HAS_ROT:
case SLJIT_HAS_CMOV:
case SLJIT_HAS_PREFETCH:
+ case SLJIT_HAS_COPY_F32:
+ case SLJIT_HAS_COPY_F64:
+ case SLJIT_HAS_ATOMIC:
return 1;
default:
@@ -404,6 +453,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
}
}
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type)
+{
+ switch (type) {
+ case SLJIT_UNORDERED_OR_EQUAL:
+ case SLJIT_ORDERED_NOT_EQUAL:
+ return 2;
+ }
+
+ return 0;
+}
+
/* --------------------------------------------------------------------- */
/* Core code generator functions. */
/* --------------------------------------------------------------------- */
@@ -636,6 +696,11 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
case SLJIT_MUL:
case SLJIT_CLZ:
case SLJIT_CTZ:
+ case SLJIT_REV:
+ case SLJIT_REV_U16:
+ case SLJIT_REV_S16:
+ case SLJIT_REV_U32:
+ case SLJIT_REV_S32:
case SLJIT_ADDC:
case SLJIT_SUBC:
/* No form with immediate operand (except imm 0, which
@@ -644,10 +709,6 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
case SLJIT_MOV:
SLJIT_ASSERT(!(flags & SET_FLAGS) && (flags & ARG2_IMM) && arg1 == TMP_REG1);
return load_immediate(compiler, dst, imm);
- case SLJIT_NOT:
- SLJIT_ASSERT(flags & ARG2_IMM);
- FAIL_IF(load_immediate(compiler, dst, (flags & INT_OP) ? (~imm & 0xffffffff) : ~imm));
- goto set_flags;
case SLJIT_SUB:
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB;
if (flags & ARG1_IMM)
@@ -694,8 +755,13 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
break;
CHECK_FLAGS(3 << 29);
return push_inst(compiler, (ANDI ^ inv_bits) | RD(dst) | RN(reg) | inst_bits);
- case SLJIT_OR:
case SLJIT_XOR:
+ if (imm == -1) {
+ FAIL_IF(push_inst(compiler, (ORN ^ inv_bits) | RD(dst) | RN(TMP_ZERO) | RM(reg)));
+ goto set_flags;
+ }
+ /* fallthrough */
+ case SLJIT_OR:
inst_bits = logical_imm(imm, LOGICAL_IMM_CHECK | ((flags & INT_OP) ? 16 : 32));
if (!inst_bits)
break;
@@ -718,6 +784,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
inst_bits = ((sljit_ins)1 << 22) | (((sljit_ins)-imm & 0x3f) << 16) | ((63 - (sljit_ins)imm) << 10);
}
+ inv_bits |= inv_bits >> 9;
FAIL_IF(push_inst(compiler, (UBFM ^ inv_bits) | RD(dst) | RN(arg1) | inst_bits));
goto set_flags;
case SLJIT_LSHR:
@@ -727,6 +794,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
if (flags & ARG1_IMM)
break;
+ inv_bits |= inv_bits >> 9;
if (op >= SLJIT_ASHR)
inv_bits |= 1 << 30;
@@ -780,22 +848,22 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
if (dst == arg2)
return SLJIT_SUCCESS;
- return push_inst(compiler, ORR | RD(dst) | RN(TMP_ZERO) | RM(arg2));
+ return push_inst(compiler, MOV | RD(dst) | RM(arg2));
case SLJIT_MOV_U8:
SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
- return push_inst(compiler, (UBFM ^ W_OP) | RD(dst) | RN(arg2) | (7 << 10));
+ inv_bits |= inv_bits >> 9;
+ return push_inst(compiler, (UBFM ^ inv_bits) | RD(dst) | RN(arg2) | (7 << 10));
case SLJIT_MOV_S8:
SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
- if (!(flags & INT_OP))
- inv_bits |= 1 << 22;
+ inv_bits |= inv_bits >> 9;
return push_inst(compiler, (SBFM ^ inv_bits) | RD(dst) | RN(arg2) | (7 << 10));
case SLJIT_MOV_U16:
SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
- return push_inst(compiler, (UBFM ^ W_OP) | RD(dst) | RN(arg2) | (15 << 10));
+ inv_bits |= inv_bits >> 9;
+ return push_inst(compiler, (UBFM ^ inv_bits) | RD(dst) | RN(arg2) | (15 << 10));
case SLJIT_MOV_S16:
SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
- if (!(flags & INT_OP))
- inv_bits |= 1 << 22;
+ inv_bits |= inv_bits >> 9;
return push_inst(compiler, (SBFM ^ inv_bits) | RD(dst) | RN(arg2) | (15 << 10));
case SLJIT_MOV32:
SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
@@ -804,14 +872,10 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
/* fallthrough */
case SLJIT_MOV_U32:
SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
- return push_inst(compiler, (ORR ^ W_OP) | RD(dst) | RN(TMP_ZERO) | RM(arg2));
+ return push_inst(compiler, (MOV ^ W_OP) | RD(dst) | RM(arg2));
case SLJIT_MOV_S32:
SLJIT_ASSERT(!(flags & SET_FLAGS) && arg1 == TMP_REG1);
return push_inst(compiler, SBFM | (1 << 22) | RD(dst) | RN(arg2) | (31 << 10));
- case SLJIT_NOT:
- SLJIT_ASSERT(arg1 == TMP_REG1);
- FAIL_IF(push_inst(compiler, (ORN ^ inv_bits) | RD(dst) | RN(TMP_ZERO) | RM(arg2)));
- break; /* Set flags. */
case SLJIT_CLZ:
SLJIT_ASSERT(arg1 == TMP_REG1);
return push_inst(compiler, (CLZ ^ inv_bits) | RD(dst) | RN(arg2));
@@ -819,6 +883,25 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
SLJIT_ASSERT(arg1 == TMP_REG1);
FAIL_IF(push_inst(compiler, (RBIT ^ inv_bits) | RD(dst) | RN(arg2)));
return push_inst(compiler, (CLZ ^ inv_bits) | RD(dst) | RN(dst));
+ case SLJIT_REV:
+ SLJIT_ASSERT(arg1 == TMP_REG1);
+ inv_bits |= inv_bits >> 21;
+ return push_inst(compiler, (REV ^ inv_bits) | RD(dst) | RN(arg2));
+ case SLJIT_REV_U16:
+ case SLJIT_REV_S16:
+ SLJIT_ASSERT(arg1 == TMP_REG1 && dst != TMP_REG2);
+ FAIL_IF(push_inst(compiler, (REV16 ^ (sljit_ins)0x80000000) | RD(dst) | RN(arg2)));
+ if (dst == TMP_REG1 || (arg2 == TMP_REG2 && op == SLJIT_REV_U16))
+ return SLJIT_SUCCESS;
+ inv_bits |= inv_bits >> 9;
+ return push_inst(compiler, ((op == SLJIT_REV_U16 ? UBFM : SBFM) ^ inv_bits) | RD(dst) | RN(dst) | (15 << 10));
+ case SLJIT_REV_U32:
+ case SLJIT_REV_S32:
+ SLJIT_ASSERT(arg1 == TMP_REG1 && dst != TMP_REG2);
+ FAIL_IF(push_inst(compiler, (REV ^ (sljit_ins)0x80000400) | RD(dst) | RN(arg2)));
+ if (op == SLJIT_REV_U32 || dst == TMP_REG1)
+ return SLJIT_SUCCESS;
+ return push_inst(compiler, SBFM | (1 << 22) | RD(dst) | RN(dst) | (31 << 10));
case SLJIT_ADD:
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD;
CHECK_FLAGS(1 << 29);
@@ -980,7 +1063,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
saved_regs_size = GET_SAVED_REGISTERS_SIZE(scratches, saveds - saved_arg_count, 2);
- saved_regs_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, SSIZE_OF(f64));
+ saved_regs_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
local_size = (local_size + saved_regs_size + 0xf) & ~0xf;
compiler->local_size = local_size;
@@ -1065,7 +1148,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
while (arg_types) {
if ((arg_types & SLJIT_ARG_MASK) < SLJIT_ARG_TYPE_F64) {
if (!(arg_types & SLJIT_ARG_TYPE_SCRATCH_REG)) {
- FAIL_IF(push_inst(compiler, ORR | RD(SLJIT_S0 - saved_arg_count) | RN(TMP_ZERO) | RM(tmp)));
+ FAIL_IF(push_inst(compiler, MOV | RD(SLJIT_S0 - saved_arg_count) | RM(tmp)));
saved_arg_count++;
}
tmp++;
@@ -1153,7 +1236,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *comp
set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
saved_regs_size = GET_SAVED_REGISTERS_SIZE(scratches, saveds - SLJIT_KEPT_SAVEDS_COUNT(options), 2);
- saved_regs_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, SSIZE_OF(f64));
+ saved_regs_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
compiler->local_size = (local_size + saved_regs_size + 0xf) & ~0xf;
return SLJIT_SUCCESS;
@@ -1272,7 +1355,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *c
src = TMP_REG1;
srcw = 0;
} else if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) {
- FAIL_IF(push_inst(compiler, ORR | RD(TMP_REG1) | RN(TMP_ZERO) | RM(src)));
+ FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG1) | RM(src)));
src = TMP_REG1;
srcw = 0;
}
@@ -1302,12 +1385,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compile
return push_inst(compiler, NOP);
case SLJIT_LMUL_UW:
case SLJIT_LMUL_SW:
- FAIL_IF(push_inst(compiler, ORR | RD(TMP_REG1) | RN(TMP_ZERO) | RM(SLJIT_R0)));
+ FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG1) | RM(SLJIT_R0)));
FAIL_IF(push_inst(compiler, MADD | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1) | RT2(TMP_ZERO)));
return push_inst(compiler, (op == SLJIT_LMUL_UW ? UMULH : SMULH) | RD(SLJIT_R1) | RN(TMP_REG1) | RM(SLJIT_R1));
case SLJIT_DIVMOD_UW:
case SLJIT_DIVMOD_SW:
- FAIL_IF(push_inst(compiler, (ORR ^ inv_bits) | RD(TMP_REG1) | RN(TMP_ZERO) | RM(SLJIT_R0)));
+ FAIL_IF(push_inst(compiler, (MOV ^ inv_bits) | RD(TMP_REG1) | RM(SLJIT_R0)));
FAIL_IF(push_inst(compiler, ((op == SLJIT_DIVMOD_UW ? UDIV : SDIV) ^ inv_bits) | RD(SLJIT_R0) | RN(SLJIT_R0) | RM(SLJIT_R1)));
FAIL_IF(push_inst(compiler, (MADD ^ inv_bits) | RD(SLJIT_R1) | RN(SLJIT_R0) | RM(SLJIT_R1) | RT2(TMP_ZERO)));
return push_inst(compiler, (SUB ^ inv_bits) | RD(SLJIT_R1) | RN(TMP_REG1) | RM(SLJIT_R1));
@@ -1349,33 +1432,33 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
break;
case SLJIT_MOV_U8:
mem_flags = BYTE_SIZE;
- if (src & SLJIT_IMM)
+ if (src == SLJIT_IMM)
srcw = (sljit_u8)srcw;
break;
case SLJIT_MOV_S8:
mem_flags = BYTE_SIZE | SIGNED;
- if (src & SLJIT_IMM)
+ if (src == SLJIT_IMM)
srcw = (sljit_s8)srcw;
break;
case SLJIT_MOV_U16:
mem_flags = HALF_SIZE;
- if (src & SLJIT_IMM)
+ if (src == SLJIT_IMM)
srcw = (sljit_u16)srcw;
break;
case SLJIT_MOV_S16:
mem_flags = HALF_SIZE | SIGNED;
- if (src & SLJIT_IMM)
+ if (src == SLJIT_IMM)
srcw = (sljit_s16)srcw;
break;
case SLJIT_MOV_U32:
mem_flags = INT_SIZE;
- if (src & SLJIT_IMM)
+ if (src == SLJIT_IMM)
srcw = (sljit_u32)srcw;
break;
case SLJIT_MOV_S32:
case SLJIT_MOV32:
mem_flags = INT_SIZE | SIGNED;
- if (src & SLJIT_IMM)
+ if (src == SLJIT_IMM)
srcw = (sljit_s32)srcw;
break;
default:
@@ -1384,7 +1467,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
break;
}
- if (src & SLJIT_IMM)
+ if (src == SLJIT_IMM)
FAIL_IF(emit_op_imm(compiler, SLJIT_MOV | ARG2_IMM, dst_r, TMP_REG1, srcw));
else if (!(src & SLJIT_MEM))
dst_r = src;
@@ -1397,11 +1480,24 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
}
flags = HAS_FLAGS(op_flags) ? SET_FLAGS : 0;
- mem_flags = WORD_SIZE;
- if (op_flags & SLJIT_32) {
- flags |= INT_OP;
+ switch (op) {
+ case SLJIT_REV_U16:
+ case SLJIT_REV_S16:
+ mem_flags = HALF_SIZE;
+ break;
+ case SLJIT_REV_U32:
+ case SLJIT_REV_S32:
mem_flags = INT_SIZE;
+ break;
+ default:
+ mem_flags = WORD_SIZE;
+
+ if (op_flags & SLJIT_32) {
+ flags |= INT_OP;
+ mem_flags = INT_SIZE;
+ }
+ break;
}
if (src & SLJIT_MEM) {
@@ -1451,12 +1547,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
src2 = TMP_REG2;
}
- if (src1 & SLJIT_IMM)
+ if (src1 == SLJIT_IMM)
flags |= ARG1_IMM;
else
src1w = src1;
- if (src2 & SLJIT_IMM)
+ if (src2 == SLJIT_IMM)
flags |= ARG2_IMM;
else
src2w = src2;
@@ -1480,57 +1576,52 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 src_dst,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w)
+ sljit_s32 dst_reg,
+ sljit_s32 src1_reg,
+ sljit_s32 src2_reg,
+ sljit_s32 src3, sljit_sw src3w)
{
sljit_ins inv_bits, imm;
sljit_s32 is_left;
sljit_sw mask;
CHECK_ERROR();
- CHECK(check_sljit_emit_shift_into(compiler, op, src_dst, src1, src1w, src2, src2w));
+ CHECK(check_sljit_emit_shift_into(compiler, op, dst_reg, src1_reg, src2_reg, src3, src3w));
is_left = (GET_OPCODE(op) == SLJIT_SHL || GET_OPCODE(op) == SLJIT_MSHL);
- if (src_dst == src1) {
+ if (src1_reg == src2_reg) {
SLJIT_SKIP_CHECKS(compiler);
- return sljit_emit_op2(compiler, (is_left ? SLJIT_ROTL : SLJIT_ROTR) | (op & SLJIT_32), src_dst, 0, src_dst, 0, src2, src2w);
+ return sljit_emit_op2(compiler, (is_left ? SLJIT_ROTL : SLJIT_ROTR) | (op & SLJIT_32), dst_reg, 0, src1_reg, 0, src3, src3w);
}
- ADJUST_LOCAL_OFFSET(src1, src1w);
- ADJUST_LOCAL_OFFSET(src2, src2w);
+ ADJUST_LOCAL_OFFSET(src3, src3w);
inv_bits = (op & SLJIT_32) ? W_OP : 0;
- mask = inv_bits ? 0x1f : 0x3f;
- if (src2 & SLJIT_IMM) {
- src2w &= mask;
+ if (src3 == SLJIT_IMM) {
+ mask = inv_bits ? 0x1f : 0x3f;
+ src3w &= mask;
- if (src2w == 0)
+ if (src3w == 0)
return SLJIT_SUCCESS;
- } else if (src2 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem(compiler, inv_bits ? INT_SIZE : WORD_SIZE, TMP_REG2, src2, src2w, TMP_REG2));
- src2 = TMP_REG2;
- }
- if (src1 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem(compiler, inv_bits ? INT_SIZE : WORD_SIZE, TMP_REG1, src1, src1w, TMP_REG1));
- src1 = TMP_REG1;
- } else if (src1 & SLJIT_IMM) {
- FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
- src1 = TMP_REG1;
- }
-
- if (src2 & SLJIT_IMM) {
if (is_left)
- src2w = (src2w ^ mask) + 1;
+ src3w = (src3w ^ mask) + 1;
+
+ return push_inst(compiler, (EXTR ^ (inv_bits | (inv_bits >> 9))) | RD(dst_reg)
+ | RN(is_left ? src1_reg : src2_reg) | RM(is_left ? src2_reg : src1_reg) | ((sljit_ins)src3w << 10));
+ }
- return push_inst(compiler, (EXTR ^ (inv_bits | (inv_bits >> 9))) | RD(src_dst)
- | RN(is_left ? src_dst : src1) | RM(is_left ? src1 : src_dst) | ((sljit_ins)src2w << 10));
+ if (src3 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, inv_bits ? INT_SIZE : WORD_SIZE, TMP_REG2, src3, src3w, TMP_REG2));
+ src3 = TMP_REG2;
+ } else if (dst_reg == src3) {
+ FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG2) | RM(src3)));
+ src3 = TMP_REG2;
}
- FAIL_IF(push_inst(compiler, ((is_left ? LSLV : LSRV) ^ inv_bits) | RD(src_dst) | RN(src_dst) | RM(src2)));
+ FAIL_IF(push_inst(compiler, ((is_left ? LSLV : LSRV) ^ inv_bits) | RD(dst_reg) | RN(src1_reg) | RM(src3)));
if (!(op & SLJIT_SHIFT_INTO_NON_ZERO)) {
/* Shift left/right by 1. */
@@ -1539,18 +1630,18 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *
else
imm = (sljit_ins)(inv_bits ? ((31 << 16) | (30 << 10)) : ((63 << 16) | (62 << 10) | (1 << 22)));
- FAIL_IF(push_inst(compiler, (UBFM ^ inv_bits) | RD(TMP_REG1) | RN(src1) | imm));
+ FAIL_IF(push_inst(compiler, (UBFM ^ (inv_bits | (inv_bits >> 9))) | RD(TMP_REG1) | RN(src2_reg) | imm));
/* Set imm to mask. */
imm = (sljit_ins)(inv_bits ? (4 << 10) : ((5 << 10) | (1 << 22)));
- FAIL_IF(push_inst(compiler, (EORI ^ inv_bits) | RD(TMP_REG2) | RN(src2) | imm));
+ FAIL_IF(push_inst(compiler, (EORI ^ inv_bits) | RD(TMP_REG2) | RN(src3) | imm));
- src1 = TMP_REG1;
+ src2_reg = TMP_REG1;
} else
- FAIL_IF(push_inst(compiler, (SUB ^ inv_bits) | RD(TMP_REG2) | RN(TMP_ZERO) | RM(src2)));
+ FAIL_IF(push_inst(compiler, (SUB ^ inv_bits) | RD(TMP_REG2) | RN(TMP_ZERO) | RM(src3)));
- FAIL_IF(push_inst(compiler, ((is_left ? LSRV : LSLV) ^ inv_bits) | RD(TMP_REG1) | RN(src1) | RM(TMP_REG2)));
- return push_inst(compiler, (ORR ^ inv_bits) | RD(src_dst) | RN(src_dst) | RM(TMP_REG1));
+ FAIL_IF(push_inst(compiler, ((is_left ? LSRV : LSLV) ^ inv_bits) | RD(TMP_REG1) | RN(src2_reg) | RM(TMP_REG2)));
+ return push_inst(compiler, (ORR ^ inv_bits) | RD(dst_reg) | RN(dst_reg) | RM(TMP_REG1));
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
@@ -1563,7 +1654,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *comp
switch (op) {
case SLJIT_FAST_RETURN:
if (FAST_IS_REG(src))
- FAIL_IF(push_inst(compiler, ORR | RD(TMP_LR) | RN(TMP_ZERO) | RM(src)));
+ FAIL_IF(push_inst(compiler, MOV | RD(TMP_LR) | RM(src)));
else
FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_LR, src, srcw, TMP_REG1));
@@ -1593,15 +1684,42 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *comp
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw)
{
- CHECK_REG_INDEX(check_sljit_get_register_index(reg));
- return reg_map[reg];
+ sljit_s32 dst_r = TMP_LR;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op_dst(compiler, op, dst, dstw));
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+
+ switch (op) {
+ case SLJIT_FAST_ENTER:
+ if (FAST_IS_REG(dst))
+ return push_inst(compiler, MOV | RD(dst) | RM(TMP_LR));
+ break;
+ case SLJIT_GET_RETURN_ADDRESS:
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE, dst_r, SLJIT_MEM1(SLJIT_SP), 0x8, TMP_REG2));
+ break;
+ }
+
+ if (dst & SLJIT_MEM)
+ return emit_op_mem(compiler, WORD_SIZE | STORE, dst_r, dst, dstw, TMP_REG2);
+
+ return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 type, sljit_s32 reg)
{
- CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
+ CHECK_REG_INDEX(check_sljit_get_register_index(type, reg));
+
+ if (type == SLJIT_GP_REGISTER)
+ return reg_map[reg];
+
+ if (type != SLJIT_FLOAT_REGISTER && type != SLJIT_SIMD_REG_64 && type != SLJIT_SIMD_REG_128)
+ return -1;
+
return freg_map[reg];
}
@@ -1679,7 +1797,7 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_comp
inv_bits |= W_OP;
if (src & SLJIT_MEM) {
- emit_fop_mem(compiler, (op & SLJIT_32) ? INT_SIZE : WORD_SIZE, TMP_FREG1, src, srcw);
+ FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32) ? INT_SIZE : WORD_SIZE, TMP_FREG1, src, srcw));
src = TMP_FREG1;
}
@@ -1690,34 +1808,59 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_comp
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+static sljit_s32 sljit_emit_fop1_conv_f64_from_w(struct sljit_compiler *compiler, sljit_ins ins,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 src, sljit_sw srcw)
{
sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
- sljit_ins inv_bits = (op & SLJIT_32) ? (1 << 22) : 0;
-
- if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
- inv_bits |= W_OP;
if (src & SLJIT_MEM) {
- emit_op_mem(compiler, ((GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) ? INT_SIZE : WORD_SIZE), TMP_REG1, src, srcw, TMP_REG1);
+ emit_op_mem(compiler, (ins & W_OP) ? WORD_SIZE : INT_SIZE, TMP_REG1, src, srcw, TMP_REG1);
src = TMP_REG1;
- } else if (src & SLJIT_IMM) {
- if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
- srcw = (sljit_s32)srcw;
-
+ } else if (src == SLJIT_IMM) {
FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
src = TMP_REG1;
}
- FAIL_IF(push_inst(compiler, (SCVTF ^ inv_bits) | VD(dst_r) | RN(src)));
+ FAIL_IF(push_inst(compiler, ins | VD(dst_r) | RN(src)));
if (dst & SLJIT_MEM)
- return emit_fop_mem(compiler, ((op & SLJIT_32) ? INT_SIZE : WORD_SIZE) | STORE, TMP_FREG1, dst, dstw);
+ return emit_fop_mem(compiler, ((ins & (1 << 22)) ? WORD_SIZE : INT_SIZE) | STORE, TMP_FREG1, dst, dstw);
return SLJIT_SUCCESS;
}
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_ins inv_bits = (op & SLJIT_32) ? (1 << 22) : 0;
+
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) {
+ inv_bits |= W_OP;
+
+ if (src == SLJIT_IMM)
+ srcw = (sljit_s32)srcw;
+ }
+
+ return sljit_emit_fop1_conv_f64_from_w(compiler, SCVTF ^ inv_bits, dst, dstw, src, srcw);
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_uw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_ins inv_bits = (op & SLJIT_32) ? (1 << 22) : 0;
+
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_U32) {
+ inv_bits |= W_OP;
+
+ if (src == SLJIT_IMM)
+ srcw = (sljit_u32)srcw;
+ }
+
+ return sljit_emit_fop1_conv_f64_from_w(compiler, UCVTF ^ inv_bits, dst, dstw, src, srcw);
+}
+
static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 src1, sljit_sw src1w,
sljit_s32 src2, sljit_sw src2w)
@@ -1726,16 +1869,22 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compile
sljit_ins inv_bits = (op & SLJIT_32) ? (1 << 22) : 0;
if (src1 & SLJIT_MEM) {
- emit_fop_mem(compiler, mem_flags, TMP_FREG1, src1, src1w);
+ FAIL_IF(emit_fop_mem(compiler, mem_flags, TMP_FREG1, src1, src1w));
src1 = TMP_FREG1;
}
if (src2 & SLJIT_MEM) {
- emit_fop_mem(compiler, mem_flags, TMP_FREG2, src2, src2w);
+ FAIL_IF(emit_fop_mem(compiler, mem_flags, TMP_FREG2, src2, src2w));
src2 = TMP_FREG2;
}
- return push_inst(compiler, (FCMP ^ inv_bits) | VN(src1) | VM(src2));
+ FAIL_IF(push_inst(compiler, (FCMP ^ inv_bits) | VN(src1) | VM(src2)));
+
+ if (GET_FLAG_TYPE(op) != SLJIT_UNORDERED_OR_EQUAL)
+ return SLJIT_SUCCESS;
+
+ FAIL_IF(push_inst(compiler, CSINC | (0x0 << 12) | RD(TMP_REG1) | RN(TMP_ZERO) | RM(TMP_ZERO)));
+ return push_inst(compiler, CCMPI | (0x0 << 16) | (0x7 << 12) | RN(TMP_REG1) | 0x4);
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
@@ -1754,7 +1903,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil
dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
if (src & SLJIT_MEM) {
- emit_fop_mem(compiler, (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32) ? (mem_flags ^ 0x1) : mem_flags, dst_r, src, srcw);
+ FAIL_IF(emit_fop_mem(compiler, (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_F32) ? (mem_flags ^ 0x1) : mem_flags, dst_r, src, srcw));
src = dst_r;
}
@@ -1799,11 +1948,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
if (src1 & SLJIT_MEM) {
- emit_fop_mem(compiler, mem_flags, TMP_FREG1, src1, src1w);
+ FAIL_IF(emit_fop_mem(compiler, mem_flags, TMP_FREG1, src1, src1w));
src1 = TMP_FREG1;
}
if (src2 & SLJIT_MEM) {
- emit_fop_mem(compiler, mem_flags, TMP_FREG2, src2, src2w);
+ FAIL_IF(emit_fop_mem(compiler, mem_flags, TMP_FREG2, src2, src2w));
src2 = TMP_FREG2;
}
@@ -1820,6 +1969,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
case SLJIT_DIV_F64:
FAIL_IF(push_inst(compiler, (FDIV ^ inv_bits) | VD(dst_r) | VN(src1) | VM(src2)));
break;
+ case SLJIT_COPYSIGN_F64:
+ FAIL_IF(push_inst(compiler, (FMOV_R ^ ((op & SLJIT_32) ? (W_OP | (1 << 22)) : 0)) | VN(src2) | RD(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, (FABS ^ inv_bits) | VD(dst_r) | VN(src1)));
+ FAIL_IF(push_inst(compiler, TBZ | ((op & SLJIT_32) ? 0 : ((sljit_ins)1 << 31)) | (0x1f << 19) | (2 << 5) | RT(TMP_REG1)));
+ return push_inst(compiler, (FNEG ^ inv_bits) | VD(dst_r) | VN(dst_r));
}
if (!(dst & SLJIT_MEM))
@@ -1827,21 +1981,79 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
return emit_fop_mem(compiler, mem_flags | STORE, TMP_FREG1, dst, dstw);
}
-/* --------------------------------------------------------------------- */
-/* Other instructions */
-/* --------------------------------------------------------------------- */
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset32(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f32 value)
+{
+ sljit_u32 exp;
+ union {
+ sljit_u32 imm;
+ sljit_f32 value;
+ } u;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fset32(compiler, freg, value));
+
+ u.value = value;
+
+ if (u.imm == 0)
+ return push_inst(compiler, (FMOV_R ^ (W_OP | (1 << 22))) | RN(TMP_ZERO) | VD(freg) | (1 << 16));
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+ if ((u.imm << (32 - 19)) == 0) {
+ exp = (u.imm >> (23 + 2)) & 0x3f;
+
+ if (exp == 0x20 || exp == 0x1f)
+ return push_inst(compiler, (FMOV_I ^ (1 << 22)) | (sljit_ins)((((u.imm >> 24) & 0x80) | ((u.imm >> 19) & 0x7f)) << 13) | VD(freg));
+ }
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_s32)u.imm));
+ return push_inst(compiler, (FMOV_R ^ (W_OP | (1 << 22))) | RN(TMP_REG1) | VD(freg) | (1 << 16));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f64 value)
{
+ sljit_uw exp;
+ union {
+ sljit_uw imm;
+ sljit_f64 value;
+ } u;
+
CHECK_ERROR();
- CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
- ADJUST_LOCAL_OFFSET(dst, dstw);
+ CHECK(check_sljit_emit_fset64(compiler, freg, value));
- if (FAST_IS_REG(dst))
- return push_inst(compiler, ORR | RD(dst) | RN(TMP_ZERO) | RM(TMP_LR));
+ u.value = value;
- /* Memory. */
- return emit_op_mem(compiler, WORD_SIZE | STORE, TMP_LR, dst, dstw, TMP_REG1);
+ if (u.imm == 0)
+ return push_inst(compiler, FMOV_R | RN(TMP_ZERO) | VD(freg) | (sljit_ins)1 << 16);
+
+ if ((u.imm << (64 - 48)) == 0) {
+ exp = (u.imm >> (52 + 2)) & 0x1ff;
+
+ if (exp == 0x100 || exp == 0xff)
+ return push_inst(compiler, FMOV_I | (sljit_ins)((((u.imm >> 56) & 0x80) | ((u.imm >> 48) & 0x7f)) << 13) | VD(freg));
+ }
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_sw)u.imm));
+ return push_inst(compiler, FMOV_R | RN(TMP_REG1) | VD(freg) | (1 << 16));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 freg, sljit_s32 reg)
+{
+ sljit_ins inst;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+ if (GET_OPCODE(op) == SLJIT_COPY_TO_F64)
+ inst = FMOV_R | RN(reg) | VD(freg) | (1 << 16);
+ else
+ inst = FMOV_R | VN(freg) | RD(reg);
+
+ if (op & SLJIT_32)
+ inst ^= W_OP | (1 << 22);
+
+ return push_inst(compiler, inst);
}
/* --------------------------------------------------------------------- */
@@ -1852,15 +2064,17 @@ static sljit_ins get_cc(struct sljit_compiler *compiler, sljit_s32 type)
{
switch (type) {
case SLJIT_EQUAL:
+ case SLJIT_ATOMIC_STORED:
case SLJIT_F_EQUAL:
case SLJIT_ORDERED_EQUAL:
- case SLJIT_UNORDERED_OR_EQUAL: /* Not supported. */
+ case SLJIT_UNORDERED_OR_EQUAL:
return 0x1;
case SLJIT_NOT_EQUAL:
+ case SLJIT_ATOMIC_NOT_STORED:
case SLJIT_F_NOT_EQUAL:
case SLJIT_UNORDERED_OR_NOT_EQUAL:
- case SLJIT_ORDERED_NOT_EQUAL: /* Not supported. */
+ case SLJIT_ORDERED_NOT_EQUAL:
return 0x0;
case SLJIT_CARRY:
@@ -2011,7 +2225,7 @@ static SLJIT_INLINE struct sljit_jump* emit_cmp_to0(struct sljit_compiler *compi
PTR_FAIL_IF(emit_op_mem(compiler, inv_bits ? INT_SIZE : WORD_SIZE, TMP_REG1, src, srcw, TMP_REG1));
src = TMP_REG1;
}
- else if (src & SLJIT_IMM) {
+ else if (src == SLJIT_IMM) {
PTR_FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
src = TMP_REG1;
}
@@ -2035,7 +2249,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
CHECK_ERROR();
CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
- if (!(src & SLJIT_IMM)) {
+ if (src != SLJIT_IMM) {
if (src & SLJIT_MEM) {
ADJUST_LOCAL_OFFSET(src, srcw);
FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src, srcw, TMP_REG1));
@@ -2071,7 +2285,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compi
if (type & SLJIT_CALL_RETURN) {
if (src >= SLJIT_FIRST_SAVED_REG && src <= (SLJIT_S0 - SLJIT_KEPT_SAVEDS_COUNT(compiler->options))) {
- FAIL_IF(push_inst(compiler, ORR | RD(TMP_REG1) | RN(TMP_ZERO) | RM(src)));
+ FAIL_IF(push_inst(compiler, MOV | RD(TMP_REG1) | RM(src)));
src = TMP_REG1;
}
@@ -2131,27 +2345,53 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *compiler, sljit_s32 type,
sljit_s32 dst_reg,
- sljit_s32 src, sljit_sw srcw)
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_reg)
{
sljit_ins inv_bits = (type & SLJIT_32) ? W_OP : 0;
sljit_ins cc;
CHECK_ERROR();
- CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
+ CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));
- if (SLJIT_UNLIKELY(src & SLJIT_IMM)) {
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+
+ if (src1 == SLJIT_IMM) {
if (type & SLJIT_32)
- srcw = (sljit_s32)srcw;
- FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
- src = TMP_REG1;
- srcw = 0;
+ src1w = (sljit_s32)src1w;
+ FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
+ src1 = TMP_REG1;
+ } else if (src1 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src1, src1w, TMP_REG2));
+ src1 = TMP_REG1;
}
cc = get_cc(compiler, type & ~SLJIT_32);
+ return push_inst(compiler, (CSEL ^ inv_bits) | (cc << 12) | RD(dst_reg) | RN(src2_reg) | RM(src1));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_freg)
+{
+ sljit_ins inv_bits = (type & SLJIT_32) ? (1 << 22) : 0;
+ sljit_ins cc;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fselect(compiler, type, dst_freg, src1, src1w, src2_freg));
+
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+
+ if (src1 & SLJIT_MEM) {
+ FAIL_IF(emit_fop_mem(compiler, (type & SLJIT_32) ? INT_SIZE : WORD_SIZE, TMP_FREG1, src1, src1w));
+ src1 = TMP_FREG1;
+ }
- return push_inst(compiler, (CSEL ^ inv_bits) | (cc << 12) | RD(dst_reg) | RN(dst_reg) | RM(src));
+ cc = get_cc(compiler, type & ~SLJIT_32);
+ return push_inst(compiler, (FCSEL ^ inv_bits) | (cc << 12) | VD(dst_freg) | VN(src2_freg) | VM(src1));
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type,
@@ -2308,6 +2548,661 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem_update(struct sljit_compiler
return push_inst(compiler, inst | VT(freg) | RN(mem & REG_MASK) | (sljit_ins)((memw & 0x1ff) << 12));
}
+static sljit_s32 sljit_emit_simd_mem_offset(struct sljit_compiler *compiler, sljit_s32 *mem_ptr, sljit_sw memw)
+{
+ sljit_ins ins;
+ sljit_s32 mem = *mem_ptr;
+
+ if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {
+ *mem_ptr = TMP_REG1;
+ return push_inst(compiler, ADD | RD(TMP_REG1) | RN(mem & REG_MASK) | RM(OFFS_REG(mem)) | ((sljit_ins)(memw & 0x3) << 10));
+ }
+
+ if (!(mem & REG_MASK)) {
+ *mem_ptr = TMP_REG1;
+ return load_immediate(compiler, TMP_REG1, memw);
+ }
+
+ mem &= REG_MASK;
+
+ if (memw == 0) {
+ *mem_ptr = mem;
+ return SLJIT_SUCCESS;
+ }
+
+ *mem_ptr = TMP_REG1;
+
+ if (memw < -0xffffff || memw > 0xffffff) {
+ FAIL_IF(load_immediate(compiler, TMP_REG1, memw));
+ return push_inst(compiler, ADD | RD(TMP_REG1) | RN(TMP_REG1) | RM(mem));
+ }
+
+ ins = ADDI;
+
+ if (memw < 0) {
+ memw = -memw;
+ ins = SUBI;
+ }
+
+ if (memw > 0xfff) {
+ FAIL_IF(push_inst(compiler, ins | (1 << 22) | RD(TMP_REG1) | RN(mem) | ((sljit_ins)(memw >> 12) << 10)));
+
+ memw &= 0xfff;
+ if (memw == 0)
+ return SLJIT_SUCCESS;
+
+ mem = TMP_REG1;
+ }
+
+ return push_inst(compiler, ins | RD(TMP_REG1) | RN(mem) | ((sljit_ins)memw << 10));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_mov(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 srcdst, sljit_sw srcdstw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_mov(compiler, type, freg, srcdst, srcdstw));
+
+ ADJUST_LOCAL_OFFSET(srcdst, srcdstw);
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (!(srcdst & SLJIT_MEM)) {
+ if (type & SLJIT_SIMD_STORE)
+ ins = VD(srcdst) | VN(freg) | VM(freg);
+ else
+ ins = VD(freg) | VN(srcdst) | VM(srcdst);
+
+ if (reg_size == 4)
+ ins |= (1 << 30);
+
+ return push_inst(compiler, ORR_v | ins);
+ }
+
+ FAIL_IF(sljit_emit_simd_mem_offset(compiler, &srcdst, srcdstw));
+
+ if (elem_size > 3)
+ elem_size = 3;
+
+ ins = (type & SLJIT_SIMD_STORE) ? ST1 : LD1;
+
+ if (reg_size == 4)
+ ins |= (1 << 30);
+
+ return push_inst(compiler, ins | ((sljit_ins)elem_size << 10) | RN(srcdst) | VT(freg));
+}
+
+static sljit_ins simd_get_imm(sljit_s32 elem_size, sljit_uw value)
+{
+ sljit_ins result;
+
+ if (elem_size > 2 && (sljit_u32)value == (value >> 32)) {
+ elem_size = 2;
+ value = (sljit_u32)value;
+ }
+
+ if (elem_size == 2 && (sljit_u16)value == (value >> 16)) {
+ elem_size = 1;
+ value = (sljit_u16)value;
+ }
+
+ if (elem_size == 1 && (sljit_u8)value == (value >> 8)) {
+ elem_size = 0;
+ value = (sljit_u8)value;
+ }
+
+ switch (elem_size) {
+ case 0:
+ SLJIT_ASSERT(value <= 0xff);
+ result = 0xe000;
+ break;
+ case 1:
+ SLJIT_ASSERT(value <= 0xffff);
+ result = 0;
+
+ while (1) {
+ if (value <= 0xff) {
+ result |= 0x8000;
+ break;
+ }
+
+ if ((value & 0xff) == 0) {
+ value >>= 8;
+ result |= 0xa000;
+ break;
+ }
+
+ if (result != 0)
+ return ~(sljit_ins)0;
+
+ value ^= (sljit_uw)0xffff;
+ result = (1 << 29);
+ }
+ break;
+ case 2:
+ SLJIT_ASSERT(value <= 0xffffffff);
+ result = 0;
+
+ while (1) {
+ if (value <= 0xff) {
+ result |= 0x0000;
+ break;
+ }
+
+ if ((value & ~(sljit_uw)0xff00) == 0) {
+ value >>= 8;
+ result |= 0x2000;
+ break;
+ }
+
+ if ((value & ~(sljit_uw)0xff0000) == 0) {
+ value >>= 16;
+ result |= 0x4000;
+ break;
+ }
+
+ if ((value & ~(sljit_uw)0xff000000) == 0) {
+ value >>= 24;
+ result |= 0x6000;
+ break;
+ }
+
+ if ((value & (sljit_uw)0xff) == 0xff && (value >> 16) == 0) {
+ value >>= 8;
+ result |= 0xc000;
+ break;
+ }
+
+ if ((value & (sljit_uw)0xffff) == 0xffff && (value >> 24) == 0) {
+ value >>= 16;
+ result |= 0xd000;
+ break;
+ }
+
+ if (result != 0)
+ return ~(sljit_ins)0;
+
+ value ^= (sljit_uw)0xffffffff;
+ result = (1 << 29);
+ }
+ break;
+ default:
+ return ~(sljit_ins)0;
+ }
+
+ return (((sljit_ins)value & 0x1f) << 5) | (((sljit_ins)value & 0xe0) << 11) | result;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins, imm;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_replicate(compiler, type, freg, src, srcw));
+
+ ADJUST_LOCAL_OFFSET(src, srcw);
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (src & SLJIT_MEM) {
+ FAIL_IF(sljit_emit_simd_mem_offset(compiler, &src, srcw));
+
+ ins = (sljit_ins)elem_size << 10;
+
+ if (reg_size == 4)
+ ins |= (sljit_ins)1 << 30;
+
+ return push_inst(compiler, LD1R | ins | RN(src) | VT(freg));
+ }
+
+ ins = (sljit_ins)1 << (16 + elem_size);
+
+ if (reg_size == 4)
+ ins |= (sljit_ins)1 << 30;
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ if (src == SLJIT_IMM)
+ return push_inst(compiler, MOVI | (ins & ((sljit_ins)1 << 30)) | VD(freg));
+
+ return push_inst(compiler, DUP_e | ins | VD(freg) | VN(src));
+ }
+
+ if (src == SLJIT_IMM) {
+ if (elem_size < 3)
+ srcw &= ((sljit_sw)1 << (((sljit_sw)1 << elem_size) << 3)) - 1;
+
+ imm = simd_get_imm(elem_size, (sljit_uw)srcw);
+
+ if (imm != ~(sljit_ins)0) {
+ imm |= ins & ((sljit_ins)1 << 30);
+
+ return push_inst(compiler, MOVI | imm | VD(freg));
+ }
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+ src = TMP_REG1;
+ }
+
+ return push_inst(compiler, DUP_g | ins | VD(freg) | RN(src));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg, sljit_s32 lane_index,
+ sljit_s32 srcdst, sljit_sw srcdstw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_lane_mov(compiler, type, freg, lane_index, srcdst, srcdstw));
+
+ ADJUST_LOCAL_OFFSET(srcdst, srcdstw);
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (type & SLJIT_SIMD_LANE_ZERO) {
+ ins = (reg_size == 3) ? 0 : ((sljit_ins)1 << 30);
+
+ if ((type & SLJIT_SIMD_FLOAT) && freg == srcdst) {
+ FAIL_IF(push_inst(compiler, ORR_v | ins | VD(TMP_FREG1) | VN(freg) | VM(freg)));
+ srcdst = TMP_FREG1;
+ srcdstw = 0;
+ }
+
+ FAIL_IF(push_inst(compiler, MOVI | ins | VD(freg)));
+ }
+
+ if (srcdst & SLJIT_MEM) {
+ FAIL_IF(sljit_emit_simd_mem_offset(compiler, &srcdst, srcdstw));
+
+ if (elem_size == 3)
+ ins = 0x8400;
+ else if (elem_size == 0)
+ ins = 0;
+ else
+ ins = (sljit_ins)0x2000 << elem_size;
+
+ lane_index = lane_index << elem_size;
+ ins |= (sljit_ins)(((lane_index & 0x8) << 27) | ((lane_index & 0x7) << 10));
+
+ return push_inst(compiler, ((type & SLJIT_SIMD_STORE) ? ST1_s : LD1_s) | ins | RN(srcdst) | VT(freg));
+ }
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ if (type & SLJIT_SIMD_STORE)
+ ins = INS_e | ((sljit_ins)1 << (16 + elem_size)) | ((sljit_ins)lane_index << (11 + elem_size)) | VD(srcdst) | VN(freg);
+ else
+ ins = INS_e | ((((sljit_ins)lane_index << 1) | 1) << (16 + elem_size)) | VD(freg) | VN(srcdst);
+
+ return push_inst(compiler, ins);
+ }
+
+ if (srcdst == SLJIT_IMM) {
+ if (elem_size < 3)
+ srcdstw &= ((sljit_sw)1 << (((sljit_sw)1 << elem_size) << 3)) - 1;
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, srcdstw));
+ srcdst = TMP_REG1;
+ }
+
+ if (type & SLJIT_SIMD_STORE) {
+ ins = RD(srcdst) | VN(freg);
+
+ if ((type & SLJIT_SIMD_LANE_SIGNED) && (elem_size < 2 || (elem_size == 2 && !(type & SLJIT_32)))) {
+ ins |= SMOV;
+
+ if (!(type & SLJIT_32))
+ ins |= (sljit_ins)1 << 30;
+ } else
+ ins |= UMOV;
+ } else
+ ins = INS | VD(freg) | RN(srcdst);
+
+ if (elem_size == 3)
+ ins |= (sljit_ins)1 << 30;
+
+ return push_inst(compiler, ins | ((((sljit_ins)lane_index << 1) | 1) << (16 + elem_size)));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_s32 src_lane_index)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_lane_replicate(compiler, type, freg, src, src_lane_index));
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ ins = (((sljit_ins)src_lane_index << 1) | 1) << (16 + elem_size);
+
+ if (reg_size == 4)
+ ins |= (sljit_ins)1 << 30;
+
+ return push_inst(compiler, DUP_e | ins | VD(freg) | VN(src));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_extend(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_s32 elem2_size = SLJIT_SIMD_GET_ELEM2_SIZE(type);
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_extend(compiler, type, freg, src, srcw));
+
+ ADJUST_LOCAL_OFFSET(src, srcw);
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size != 2 || elem2_size != 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (src & SLJIT_MEM) {
+ FAIL_IF(sljit_emit_simd_mem_offset(compiler, &src, srcw));
+
+ if (reg_size == 4 && elem2_size - elem_size == 1)
+ FAIL_IF(push_inst(compiler, LD1 | ((sljit_ins)elem_size << 10) | RN(src) | VT(freg)));
+ else
+ FAIL_IF(push_inst(compiler, LD1_s | ((sljit_ins)0x2000 << (reg_size - elem2_size + elem_size)) | RN(src) | VT(freg)));
+ src = freg;
+ }
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ SLJIT_ASSERT(reg_size == 4);
+ return push_inst(compiler, FCVTL | (1 << 22) | VD(freg) | VN(src));
+ }
+
+ do {
+ FAIL_IF(push_inst(compiler, ((type & SLJIT_SIMD_EXTEND_SIGNED) ? SSHLL : USHLL)
+ | ((sljit_ins)1 << (19 + elem_size)) | VD(freg) | VN(src)));
+ src = freg;
+ } while (++elem_size < elem2_size);
+
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 dst, sljit_sw dstw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins, imms;
+ sljit_s32 dst_r;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_sign(compiler, type, freg, dst, dstw));
+
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ switch (elem_size) {
+ case 0:
+ imms = 0x643219;
+ ins = USHR | (0x9 << 16);
+ break;
+ case 1:
+ imms = (reg_size == 4) ? 0x643219 : 0x6231;
+ ins = USHR | (0x11 << 16);
+ break;
+ case 2:
+ imms = (reg_size == 4) ? 0x6231 : 0x61;
+ ins = USHR | (0x21 << 16);
+ break;
+ default:
+ imms = 0x61;
+ ins = USHR | (0x41 << 16);
+ break;
+ }
+
+ if (reg_size == 4)
+ ins |= (1 << 30);
+
+ FAIL_IF(push_inst(compiler, ins | VD(TMP_FREG1) | VN(freg)));
+
+ if (reg_size == 4 && elem_size > 0)
+ FAIL_IF(push_inst(compiler, XTN | ((sljit_ins)(elem_size - 1) << 22) | VD(TMP_FREG1) | VN(TMP_FREG1)));
+
+ if (imms >= 0x100) {
+ ins = (reg_size == 4 && elem_size == 0) ? (1 << 30) : 0;
+
+ do {
+ FAIL_IF(push_inst(compiler, USRA | ins | ((imms & 0xff) << 16) | VD(TMP_FREG1) | VN(TMP_FREG1)));
+ imms >>= 8;
+ } while (imms >= 0x100);
+ }
+
+ FAIL_IF(push_inst(compiler, USRA | (1 << 30) | (imms << 16) | VD(TMP_FREG1) | VN(TMP_FREG1)));
+
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+ ins = (0x1 << 16);
+
+ if (reg_size == 4 && elem_size == 0) {
+ FAIL_IF(push_inst(compiler, INS_e | (0x3 << 16) | (0x8 << 11) | VD(TMP_FREG1) | VN(TMP_FREG1)));
+ ins = (0x2 << 16);
+ }
+
+ FAIL_IF(push_inst(compiler, UMOV | ins | RD(dst_r) | VN(TMP_FREG1)));
+
+ if (dst_r == TMP_REG1)
+ return emit_op_mem(compiler, STORE | ((type & SLJIT_32) ? INT_SIZE : WORD_SIZE), TMP_REG1, dst, dstw, TMP_REG2);
+
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_op2(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg, sljit_s32 src1_freg, sljit_s32 src2_freg)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_op2(compiler, type, dst_freg, src1_freg, src2_freg));
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ switch (SLJIT_SIMD_GET_OPCODE(type)) {
+ case SLJIT_SIMD_OP2_AND:
+ ins = AND_v;
+ break;
+ case SLJIT_SIMD_OP2_OR:
+ ins = ORR_v;
+ break;
+ case SLJIT_SIMD_OP2_XOR:
+ ins = EOR_v;
+ break;
+ }
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (reg_size == 4)
+ ins |= (sljit_ins)1 << 30;
+
+ return push_inst(compiler, ins | VD(dst_freg) | VN(src1_freg) | VM(src2_freg));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_load(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_reg,
+ sljit_s32 mem_reg)
+{
+ sljit_ins ins;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_atomic_load(compiler, op, dst_reg, mem_reg));
+
+#ifdef __ARM_FEATURE_ATOMICS
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MOV32:
+ case SLJIT_MOV_U32:
+ ins = LDR ^ (1 << 30);
+ break;
+ case SLJIT_MOV_U16:
+ ins = LDRH;
+ break;
+ case SLJIT_MOV_U8:
+ ins = LDRB;
+ break;
+ default:
+ ins = LDR;
+ break;
+ }
+#else /* !__ARM_FEATURE_ATOMICS */
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MOV32:
+ case SLJIT_MOV_U32:
+ ins = LDXR ^ (1 << 30);
+ break;
+ case SLJIT_MOV_U8:
+ ins = LDXRB;
+ break;
+ case SLJIT_MOV_U16:
+ ins = LDXRH;
+ break;
+ default:
+ ins = LDXR;
+ break;
+ }
+#endif /* ARM_FEATURE_ATOMICS */
+ return push_inst(compiler, ins | RN(mem_reg) | RT(dst_reg));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src_reg,
+ sljit_s32 mem_reg,
+ sljit_s32 temp_reg)
+{
+ sljit_ins ins;
+ sljit_s32 tmp = temp_reg;
+ sljit_ins cmp = 0;
+ sljit_ins inv_bits = W_OP;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_atomic_store(compiler, op, src_reg, mem_reg, temp_reg));
+
+#ifdef __ARM_FEATURE_ATOMICS
+ if (op & SLJIT_SET_ATOMIC_STORED)
+ cmp = (SUBS ^ W_OP) | RD(TMP_ZERO);
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MOV32:
+ case SLJIT_MOV_U32:
+ ins = CAS ^ (1 << 30);
+ break;
+ case SLJIT_MOV_U16:
+ ins = CASH;
+ break;
+ case SLJIT_MOV_U8:
+ ins = CASB;
+ break;
+ default:
+ ins = CAS;
+ inv_bits = 0;
+ if (cmp)
+ cmp ^= W_OP;
+ break;
+ }
+
+ if (cmp) {
+ FAIL_IF(push_inst(compiler, (MOV ^ inv_bits) | RM(temp_reg) | RD(TMP_REG1)));
+ tmp = TMP_REG1;
+ }
+ FAIL_IF(push_inst(compiler, ins | RM(tmp) | RN(mem_reg) | RD(src_reg)));
+ if (!cmp)
+ return SLJIT_SUCCESS;
+
+ FAIL_IF(push_inst(compiler, cmp | RM(tmp) | RN(temp_reg)));
+ FAIL_IF(push_inst(compiler, (CSET ^ inv_bits) | RD(tmp)));
+ return push_inst(compiler, cmp | RM(tmp) | RN(TMP_ZERO));
+#else /* !__ARM_FEATURE_ATOMICS */
+ SLJIT_UNUSED_ARG(tmp);
+ SLJIT_UNUSED_ARG(inv_bits);
+
+ if (op & SLJIT_SET_ATOMIC_STORED)
+ cmp = (SUBI ^ W_OP) | (1 << 29);
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MOV32:
+ case SLJIT_MOV_U32:
+ ins = STXR ^ (1 << 30);
+ break;
+ case SLJIT_MOV_U8:
+ ins = STXRB;
+ break;
+ case SLJIT_MOV_U16:
+ ins = STXRH;
+ break;
+ default:
+ ins = STXR;
+ break;
+ }
+
+ FAIL_IF(push_inst(compiler, ins | RM(TMP_REG1) | RN(mem_reg) | RT(src_reg)));
+ return cmp ? push_inst(compiler, cmp | RD(TMP_ZERO) | RN(TMP_REG1)) : SLJIT_SUCCESS;
+#endif /* __ARM_FEATURE_ATOMICS */
+}
+
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_local_base(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw offset)
{
sljit_s32 dst_reg;
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeARM_T2_32.c b/src/3rdparty/pcre2/src/sljit/sljitNativeARM_T2_32.c
index 7d6bac077e..c27c50ddb3 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeARM_T2_32.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeARM_T2_32.c
@@ -49,8 +49,20 @@ static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 5] = {
0, 0, 1, 2, 3, 11, 10, 9, 8, 7, 6, 5, 4, 13, 12, 14, 15
};
-static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
- 0, 0, 1, 2, 3, 4, 5, 15, 14, 13, 12, 11, 10, 9, 8, 6, 7
+static const sljit_u8 freg_map[((SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2) << 1) + 1] = {
+ 0,
+ 0, 1, 2, 3, 4, 5, 15, 14, 13, 12, 11, 10, 9, 8,
+ 7, 6,
+ 0, 1, 2, 3, 4, 5, 15, 14, 13, 12, 11, 10, 9, 8,
+ 7, 6
+};
+
+static const sljit_u8 freg_ebit_map[((SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2) << 1) + 1] = {
+ 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1
};
#define COPY_BITS(src, from, to, bits) \
@@ -75,13 +87,15 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
(reg_map[reg1] <= 7 && reg_map[reg2] <= 7 && reg_map[reg3] <= 7)
/* Thumb32 encodings. */
-#define RD4(rd) ((sljit_ins)reg_map[rd] << 8)
-#define RN4(rn) ((sljit_ins)reg_map[rn] << 16)
#define RM4(rm) ((sljit_ins)reg_map[rm])
+#define RD4(rd) ((sljit_ins)reg_map[rd] << 8)
#define RT4(rt) ((sljit_ins)reg_map[rt] << 12)
-#define DD4(dd) ((sljit_ins)freg_map[dd] << 12)
-#define DN4(dn) ((sljit_ins)freg_map[dn] << 16)
-#define DM4(dm) ((sljit_ins)freg_map[dm])
+#define RN4(rn) ((sljit_ins)reg_map[rn] << 16)
+
+#define VM4(vm) (((sljit_ins)freg_map[vm]) | ((sljit_ins)freg_ebit_map[vm] << 5))
+#define VD4(vd) (((sljit_ins)freg_map[vd] << 12) | ((sljit_ins)freg_ebit_map[vd] << 22))
+#define VN4(vn) (((sljit_ins)freg_map[vn] << 16) | ((sljit_ins)freg_ebit_map[vn] << 7))
+
#define IMM5(imm) \
(COPY_BITS(imm, 2, 12, 3) | (((sljit_ins)imm & 0x3) << 6))
#define IMM12(imm) \
@@ -128,9 +142,12 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
#define EORS 0x4040
#define EOR_W 0xea800000
#define IT 0xbf00
-#define LDR_SP 0x9800
#define LDR 0xf8d00000
+#define LDR_SP 0x9800
#define LDRD 0xe9500000
+#define LDREX 0xe8500f00
+#define LDREXB 0xe8d00f4f
+#define LDREXH 0xe8d00f5f
#define LDRI 0xf8500800
#define LSLS 0x4080
#define LSLSI 0x0000
@@ -160,6 +177,10 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
#define POP_W 0xe8bd0000
#define PUSH 0xb400
#define PUSH_W 0xe92d0000
+#define REV 0xba00
+#define REV_W 0xfa90f080
+#define REV16 0xba40
+#define REV16_W 0xfa90f090
#define RBIT 0xfa90f0a0
#define RORS 0x41c0
#define ROR_W 0xfa60f000
@@ -171,8 +192,11 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
#define SBC_W 0xeb600000
#define SDIV 0xfb90f0f0
#define SMULL 0xfb800000
-#define STRD 0xe9400000
#define STR_SP 0x9000
+#define STRD 0xe9400000
+#define STREX 0xe8400000
+#define STREXB 0xe8c00f40
+#define STREXH 0xe8c00f50
#define SUBS 0x1a00
#define SUBSI3 0x1e00
#define SUBSI8 0x3800
@@ -195,23 +219,57 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
#define UXTH_W 0xfa1ff080
#define VABS_F32 0xeeb00ac0
#define VADD_F32 0xee300a00
+#define VAND 0xef000110
#define VCMP_F32 0xeeb40a40
#define VCVT_F32_S32 0xeeb80ac0
+#define VCVT_F32_U32 0xeeb80a40
#define VCVT_F64_F32 0xeeb70ac0
#define VCVT_S32_F32 0xeebd0ac0
#define VDIV_F32 0xee800a00
+#define VDUP 0xee800b10
+#define VDUP_s 0xffb00c00
+#define VEOR 0xff000110
+#define VLD1 0xf9200000
+#define VLD1_r 0xf9a00c00
+#define VLD1_s 0xf9a00000
#define VLDR_F32 0xed100a00
#define VMOV_F32 0xeeb00a40
#define VMOV 0xee000a10
#define VMOV2 0xec400a10
+#define VMOV_i 0xef800010
+#define VMOV_s 0xee000b10
+#define VMOVN 0xffb20200
#define VMRS 0xeef1fa10
#define VMUL_F32 0xee200a00
#define VNEG_F32 0xeeb10a40
+#define VORR 0xef200110
#define VPOP 0xecbd0b00
#define VPUSH 0xed2d0b00
+#define VSHLL 0xef800a10
+#define VSHR 0xef800010
+#define VSRA 0xef800110
+#define VST1 0xf9000000
+#define VST1_s 0xf9800000
#define VSTR_F32 0xed000a00
#define VSUB_F32 0xee300a40
+#if (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+
+static sljit_s32 function_check_is_freg(struct sljit_compiler *compiler, sljit_s32 fr, sljit_s32 is_32)
+{
+ if (compiler->scratches == -1)
+ return 0;
+
+ if (is_32 && fr >= SLJIT_F64_SECOND(SLJIT_FR0))
+ fr -= SLJIT_F64_SECOND(0);
+
+ return (fr >= SLJIT_FR0 && fr < (SLJIT_FR0 + compiler->fscratches))
+ || (fr > (SLJIT_FS0 - compiler->fsaveds) && fr <= SLJIT_FS0)
+ || (fr >= SLJIT_TMP_FREGISTER_BASE && fr < (SLJIT_TMP_FREGISTER_BASE + SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS));
+}
+
+#endif /* SLJIT_ARGUMENT_CHECKS */
+
static sljit_s32 push_inst16(struct sljit_compiler *compiler, sljit_ins inst)
{
sljit_u16 *ptr;
@@ -488,18 +546,25 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
{
switch (feature_type) {
case SLJIT_HAS_FPU:
+ case SLJIT_HAS_F64_AS_F32_PAIR:
+ case SLJIT_HAS_SIMD:
#ifdef SLJIT_IS_FPU_AVAILABLE
- return SLJIT_IS_FPU_AVAILABLE;
+ return (SLJIT_IS_FPU_AVAILABLE) != 0;
#else
/* Available by default. */
return 1;
#endif
+ case SLJIT_SIMD_REGS_ARE_PAIRS:
case SLJIT_HAS_CLZ:
case SLJIT_HAS_CTZ:
+ case SLJIT_HAS_REV:
case SLJIT_HAS_ROT:
case SLJIT_HAS_CMOV:
case SLJIT_HAS_PREFETCH:
+ case SLJIT_HAS_COPY_F32:
+ case SLJIT_HAS_COPY_F64:
+ case SLJIT_HAS_ATOMIC:
return 1;
default:
@@ -615,18 +680,17 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
switch (flags & 0xffff) {
case SLJIT_CLZ:
case SLJIT_CTZ:
+ case SLJIT_REV:
+ case SLJIT_REV_U16:
+ case SLJIT_REV_S16:
+ case SLJIT_REV_U32:
+ case SLJIT_REV_S32:
case SLJIT_MUL:
/* No form with immediate operand. */
break;
case SLJIT_MOV:
SLJIT_ASSERT(!(flags & SET_FLAGS) && (flags & ARG2_IMM) && arg1 == TMP_REG2);
return load_immediate(compiler, dst, imm);
- case SLJIT_NOT:
- if (!(flags & SET_FLAGS))
- return load_immediate(compiler, dst, ~imm);
- /* Since the flags should be set, we just fallback to the register mode.
- Although some clever things could be done here, "NOT IMM" does not worth the efforts. */
- break;
case SLJIT_ADD:
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD;
imm2 = NEGATE(imm);
@@ -657,9 +721,14 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
break;
case SLJIT_ADDC:
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD;
- imm = get_imm(imm);
- if (imm != INVALID_IMM)
- return push_inst32(compiler, ADCI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm);
+ imm2 = get_imm(imm);
+ if (imm2 != INVALID_IMM)
+ return push_inst32(compiler, ADCI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm2);
+ if (flags & ARG2_IMM) {
+ imm = get_imm(~imm);
+ if (imm != INVALID_IMM)
+ return push_inst32(compiler, SBCI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm);
+ }
break;
case SLJIT_SUB:
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB;
@@ -712,9 +781,12 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB;
if (flags & ARG1_IMM)
break;
- imm = get_imm(imm);
+ imm2 = get_imm(imm);
+ if (imm2 != INVALID_IMM)
+ return push_inst32(compiler, SBCI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm2);
+ imm = get_imm(~imm);
if (imm != INVALID_IMM)
- return push_inst32(compiler, SBCI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm);
+ return push_inst32(compiler, ADCI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm);
break;
case SLJIT_AND:
imm2 = get_imm(imm);
@@ -733,6 +805,11 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
return push_inst32(compiler, ORNI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm);
break;
case SLJIT_XOR:
+ if (imm == (sljit_uw)-1) {
+ if (IS_2_LO_REGS(dst, reg))
+ return push_inst16(compiler, MVNS | RD3(dst) | RN3(reg));
+ return push_inst32(compiler, MVN_W | (flags & SET_FLAGS) | RD4(dst) | RM4(reg));
+ }
imm = get_imm(imm);
if (imm != INVALID_IMM)
return push_inst32(compiler, EORI | (flags & SET_FLAGS) | RD4(dst) | RN4(reg) | imm);
@@ -788,8 +865,7 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
imm = arg2;
arg2 = (arg1 == TMP_REG1) ? TMP_REG2 : TMP_REG1;
FAIL_IF(load_immediate(compiler, (sljit_s32)arg2, imm));
- }
- else {
+ } else {
imm = arg1;
arg1 = (arg2 == TMP_REG1) ? TMP_REG2 : TMP_REG1;
FAIL_IF(load_immediate(compiler, (sljit_s32)arg1, imm));
@@ -829,11 +905,6 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
if (IS_2_LO_REGS(dst, arg2))
return push_inst16(compiler, SXTH | RD3(dst) | RN3(arg2));
return push_inst32(compiler, SXTH_W | RD4(dst) | RM4(arg2));
- case SLJIT_NOT:
- SLJIT_ASSERT(arg1 == TMP_REG2);
- if (IS_2_LO_REGS(dst, arg2))
- return push_inst16(compiler, MVNS | RD3(dst) | RN3(arg2));
- return push_inst32(compiler, MVN_W | (flags & SET_FLAGS) | RD4(dst) | RM4(arg2));
case SLJIT_CLZ:
SLJIT_ASSERT(arg1 == TMP_REG2);
return push_inst32(compiler, CLZ | RN4(arg2) | RD4(dst) | RM4(arg2));
@@ -841,6 +912,29 @@ static sljit_s32 emit_op_imm(struct sljit_compiler *compiler, sljit_s32 flags, s
SLJIT_ASSERT(arg1 == TMP_REG2);
FAIL_IF(push_inst32(compiler, RBIT | RN4(arg2) | RD4(dst) | RM4(arg2)));
return push_inst32(compiler, CLZ | RN4(dst) | RD4(dst) | RM4(dst));
+ case SLJIT_REV:
+ case SLJIT_REV_U32:
+ case SLJIT_REV_S32:
+ SLJIT_ASSERT(arg1 == TMP_REG2);
+ if (IS_2_LO_REGS(dst, arg2))
+ return push_inst16(compiler, REV | RD3(dst) | RN3(arg2));
+ return push_inst32(compiler, REV_W | RN4(arg2) | RD4(dst) | RM4(arg2));
+ case SLJIT_REV_U16:
+ case SLJIT_REV_S16:
+ SLJIT_ASSERT(arg1 == TMP_REG2 && dst != TMP_REG2);
+
+ flags &= 0xffff;
+ if (IS_2_LO_REGS(dst, arg2))
+ FAIL_IF(push_inst16(compiler, REV16 | RD3(dst) | RN3(arg2)));
+ else
+ FAIL_IF(push_inst32(compiler, REV16_W | RN4(arg2) | RD4(dst) | RM4(arg2)));
+
+ if (dst == TMP_REG1 || (arg2 == TMP_REG1 && flags == SLJIT_REV_U16))
+ return SLJIT_SUCCESS;
+
+ if (reg_map[dst] <= 7)
+ return push_inst16(compiler, (flags == SLJIT_REV_U16 ? UXTH : SXTH) | RD3(dst) | RN3(dst));
+ return push_inst32(compiler, (flags == SLJIT_REV_U16 ? UXTH_W : SXTH_W) | RD4(dst) | RM4(dst));
case SLJIT_ADD:
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD;
if (IS_3_LO_REGS(dst, arg1, arg2))
@@ -1176,12 +1270,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
}
if (fsaveds + fscratches >= SLJIT_NUMBER_OF_FLOAT_REGISTERS) {
- FAIL_IF(push_inst32(compiler, VPUSH | DD4(SLJIT_FS0) | ((sljit_uw)SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS << 1)));
+ FAIL_IF(push_inst32(compiler, VPUSH | VD4(SLJIT_FS0) | ((sljit_uw)SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS << 1)));
} else {
if (fsaveds > 0)
- FAIL_IF(push_inst32(compiler, VPUSH | DD4(SLJIT_FS0) | ((sljit_uw)fsaveds << 1)));
+ FAIL_IF(push_inst32(compiler, VPUSH | VD4(SLJIT_FS0) | ((sljit_uw)fsaveds << 1)));
if (fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG)
- FAIL_IF(push_inst32(compiler, VPUSH | DD4(fscratches) | ((sljit_uw)(fscratches - (SLJIT_FIRST_SAVED_FLOAT_REG - 1)) << 1)));
+ FAIL_IF(push_inst32(compiler, VPUSH | VD4(fscratches) | ((sljit_uw)(fscratches - (SLJIT_FIRST_SAVED_FLOAT_REG - 1)) << 1)));
}
}
@@ -1258,17 +1352,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
switch (arg_types & SLJIT_ARG_MASK) {
case SLJIT_ARG_TYPE_F64:
if (offset != old_offset)
- *remap_ptr++ = VMOV_F32 | SLJIT_32 | DD4(offset) | DM4(old_offset);
+ *remap_ptr++ = VMOV_F32 | SLJIT_32 | VD4(offset) | VM4(old_offset);
old_offset++;
offset++;
break;
case SLJIT_ARG_TYPE_F32:
if (f32_offset != 0) {
- *remap_ptr++ = VMOV_F32 | 0x20 | DD4(offset) | DM4(f32_offset);
+ *remap_ptr++ = VMOV_F32 | 0x20 | VD4(offset) | VM4(f32_offset);
f32_offset = 0;
} else {
if (offset != old_offset)
- *remap_ptr++ = VMOV_F32 | DD4(offset) | DM4(old_offset);
+ *remap_ptr++ = VMOV_F32 | VD4(offset) | VM4(old_offset);
f32_offset = old_offset;
old_offset++;
}
@@ -1356,6 +1450,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *comp
size = GET_SAVED_REGISTERS_SIZE(scratches, saveds - SLJIT_KEPT_SAVEDS_COUNT(options), 1);
+ /* Doubles are saved, so alignment is unaffected. */
if ((size & SSIZE_OF(sw)) != 0 && (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG))
size += SSIZE_OF(sw);
@@ -1401,12 +1496,12 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit
FAIL_IF(emit_add_sp(compiler, (sljit_uw)local_size));
if (fsaveds + fscratches >= SLJIT_NUMBER_OF_FLOAT_REGISTERS) {
- FAIL_IF(push_inst32(compiler, VPOP | DD4(SLJIT_FS0) | ((sljit_uw)SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS << 1)));
+ FAIL_IF(push_inst32(compiler, VPOP | VD4(SLJIT_FS0) | ((sljit_uw)SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS << 1)));
} else {
if (fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG)
- FAIL_IF(push_inst32(compiler, VPOP | DD4(fscratches) | ((sljit_uw)(fscratches - (SLJIT_FIRST_SAVED_FLOAT_REG - 1)) << 1)));
+ FAIL_IF(push_inst32(compiler, VPOP | VD4(fscratches) | ((sljit_uw)(fscratches - (SLJIT_FIRST_SAVED_FLOAT_REG - 1)) << 1)));
if (fsaveds > 0)
- FAIL_IF(push_inst32(compiler, VPOP | DD4(SLJIT_FS0) | ((sljit_uw)fsaveds << 1)));
+ FAIL_IF(push_inst32(compiler, VPOP | VD4(SLJIT_FS0) | ((sljit_uw)fsaveds << 1)));
}
local_size = GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds, 1) & 0x7;
@@ -1705,22 +1800,22 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
break;
case SLJIT_MOV_U8:
flags = BYTE_SIZE;
- if (src & SLJIT_IMM)
+ if (src == SLJIT_IMM)
srcw = (sljit_u8)srcw;
break;
case SLJIT_MOV_S8:
flags = BYTE_SIZE | SIGNED;
- if (src & SLJIT_IMM)
+ if (src == SLJIT_IMM)
srcw = (sljit_s8)srcw;
break;
case SLJIT_MOV_U16:
flags = HALF_SIZE;
- if (src & SLJIT_IMM)
+ if (src == SLJIT_IMM)
srcw = (sljit_u16)srcw;
break;
case SLJIT_MOV_S16:
flags = HALF_SIZE | SIGNED;
- if (src & SLJIT_IMM)
+ if (src == SLJIT_IMM)
srcw = (sljit_s16)srcw;
break;
default:
@@ -1729,7 +1824,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
break;
}
- if (src & SLJIT_IMM)
+ if (src == SLJIT_IMM)
FAIL_IF(emit_op_imm(compiler, SLJIT_MOV | ARG2_IMM, dst_r, TMP_REG2, (sljit_uw)srcw));
else if (src & SLJIT_MEM) {
FAIL_IF(emit_op_mem(compiler, flags, dst_r, src, srcw, TMP_REG1));
@@ -1745,10 +1840,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
return emit_op_mem(compiler, flags | STORE, dst_r, dst, dstw, TMP_REG2);
}
+ SLJIT_COMPILE_ASSERT(WORD_SIZE == 0, word_size_must_be_0);
flags = HAS_FLAGS(op_flags) ? SET_FLAGS : 0;
+ if (op == SLJIT_REV_U16 || op == SLJIT_REV_S16)
+ flags |= HALF_SIZE;
+
if (src & SLJIT_MEM) {
- FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src, srcw, TMP_REG1));
+ FAIL_IF(emit_op_mem(compiler, flags, TMP_REG1, src, srcw, TMP_REG1));
src = TMP_REG1;
}
@@ -1778,7 +1877,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
if (dst == TMP_REG1)
flags |= UNUSED_RETURN;
- if (src1 & SLJIT_IMM)
+ if (src1 == SLJIT_IMM)
flags |= ARG1_IMM;
else if (src1 & SLJIT_MEM) {
emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src1, src1w, TMP_REG1);
@@ -1787,7 +1886,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
else
src1w = src1;
- if (src2 & SLJIT_IMM)
+ if (src2 == SLJIT_IMM)
flags |= ARG2_IMM;
else if (src2 & SLJIT_MEM) {
src2_reg = (!(flags & ARG1_IMM) && (src1w == TMP_REG1)) ? TMP_REG2 : TMP_REG1;
@@ -1816,68 +1915,60 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 src_dst,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w)
+ sljit_s32 dst_reg,
+ sljit_s32 src1_reg,
+ sljit_s32 src2_reg,
+ sljit_s32 src3, sljit_sw src3w)
{
sljit_s32 is_left;
CHECK_ERROR();
- CHECK(check_sljit_emit_shift_into(compiler, op, src_dst, src1, src1w, src2, src2w));
+ CHECK(check_sljit_emit_shift_into(compiler, op, dst_reg, src1_reg, src2_reg, src3, src3w));
op = GET_OPCODE(op);
is_left = (op == SLJIT_SHL || op == SLJIT_MSHL);
- if (src_dst == src1) {
+ if (src1_reg == src2_reg) {
SLJIT_SKIP_CHECKS(compiler);
- return sljit_emit_op2(compiler, is_left ? SLJIT_ROTL : SLJIT_ROTR, src_dst, 0, src_dst, 0, src2, src2w);
+ return sljit_emit_op2(compiler, is_left ? SLJIT_ROTL : SLJIT_ROTR, dst_reg, 0, src1_reg, 0, src3, src3w);
}
- ADJUST_LOCAL_OFFSET(src1, src1w);
- ADJUST_LOCAL_OFFSET(src2, src2w);
+ ADJUST_LOCAL_OFFSET(src3, src3w);
- if (src2 & SLJIT_IMM) {
- src2w &= 0x1f;
+ if (src3 == SLJIT_IMM) {
+ src3w &= 0x1f;
- if (src2w == 0)
+ if (src3w == 0)
return SLJIT_SUCCESS;
- } else if (src2 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, src2, src2w, TMP_REG2));
- src2 = TMP_REG2;
- }
- if (src1 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, src1, src1w, TMP_REG1));
- src1 = TMP_REG1;
- } else if (src1 & SLJIT_IMM) {
- FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)src1w));
- src1 = TMP_REG1;
- }
-
- if (src2 & SLJIT_IMM) {
- if (reg_map[src_dst] <= 7)
- FAIL_IF(push_inst16(compiler, (is_left ? LSLSI : LSRSI) | RD3(src_dst) | RN3(src_dst) | ((sljit_ins)src2w << 6)));
+ if (IS_2_LO_REGS(dst_reg, src1_reg))
+ FAIL_IF(push_inst16(compiler, (is_left ? LSLSI : LSRSI) | RD3(dst_reg) | RN3(src1_reg) | ((sljit_ins)src3w << 6)));
else
- FAIL_IF(push_inst32(compiler, (is_left ? LSL_WI : LSR_WI) | RD4(src_dst) | RM4(src_dst) | IMM5(src2w)));
+ FAIL_IF(push_inst32(compiler, (is_left ? LSL_WI : LSR_WI) | RD4(dst_reg) | RM4(src1_reg) | IMM5(src3w)));
- src2w = (src2w ^ 0x1f) + 1;
- return push_inst32(compiler, ORR_W | RD4(src_dst) | RN4(src_dst) | RM4(src1) | (is_left ? 0x10 : 0x0) | IMM5(src2w));
+ src3w = (src3w ^ 0x1f) + 1;
+ return push_inst32(compiler, ORR_W | RD4(dst_reg) | RN4(dst_reg) | RM4(src2_reg) | (is_left ? 0x10 : 0x0) | IMM5(src3w));
}
- if (op == SLJIT_MSHL || op == SLJIT_MLSHR) {
- FAIL_IF(push_inst32(compiler, ANDI | RD4(TMP_REG2) | RN4(src2) | 0x1f));
- src2 = TMP_REG2;
+ if (src3 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, src3, src3w, TMP_REG2));
+ src3 = TMP_REG2;
}
- if (IS_2_LO_REGS(src_dst, src2))
- FAIL_IF(push_inst16(compiler, (is_left ? LSLS : LSRS) | RD3(src_dst) | RN3(src2)));
+ if (op == SLJIT_MSHL || op == SLJIT_MLSHR || dst_reg == src3) {
+ FAIL_IF(push_inst32(compiler, ANDI | RD4(TMP_REG2) | RN4(src3) | 0x1f));
+ src3 = TMP_REG2;
+ }
+
+ if (dst_reg == src1_reg && IS_2_LO_REGS(dst_reg, src3))
+ FAIL_IF(push_inst16(compiler, (is_left ? LSLS : LSRS) | RD3(dst_reg) | RN3(src3)));
else
- FAIL_IF(push_inst32(compiler, (is_left ? LSL_W : LSR_W) | RD4(src_dst) | RN4(src_dst) | RM4(src2)));
+ FAIL_IF(push_inst32(compiler, (is_left ? LSL_W : LSR_W) | RD4(dst_reg) | RN4(src1_reg) | RM4(src3)));
- FAIL_IF(push_inst32(compiler, (is_left ? LSR_WI : LSL_WI) | RD4(TMP_REG1) | RM4(src1) | (1 << 6)));
- FAIL_IF(push_inst32(compiler, EORI | RD4(TMP_REG2) | RN4(src2) | 0x1f));
+ FAIL_IF(push_inst32(compiler, (is_left ? LSR_WI : LSL_WI) | RD4(TMP_REG1) | RM4(src2_reg) | (1 << 6)));
+ FAIL_IF(push_inst32(compiler, EORI | RD4(TMP_REG2) | RN4(src3) | 0x1f));
FAIL_IF(push_inst32(compiler, (is_left ? LSR_W : LSL_W) | RD4(TMP_REG1) | RN4(TMP_REG1) | RM4(TMP_REG2)));
- return push_inst32(compiler, ORR_W | RD4(src_dst) | RN4(src_dst) | RM4(TMP_REG1));
+ return push_inst32(compiler, ORR_W | RD4(dst_reg) | RN4(dst_reg) | RM4(TMP_REG1));
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
@@ -1909,16 +2000,60 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *comp
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw)
{
- CHECK_REG_INDEX(check_sljit_get_register_index(reg));
- return reg_map[reg];
+ sljit_s32 size, dst_r;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op_dst(compiler, op, dst, dstw));
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+
+ switch (op) {
+ case SLJIT_FAST_ENTER:
+ SLJIT_ASSERT(reg_map[TMP_REG2] == 14);
+
+ if (FAST_IS_REG(dst))
+ return push_inst16(compiler, MOV | SET_REGS44(dst, TMP_REG2));
+ break;
+ case SLJIT_GET_RETURN_ADDRESS:
+ size = GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds - SLJIT_KEPT_SAVEDS_COUNT(compiler->options), 0);
+
+ if (compiler->fsaveds > 0 || compiler->fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) {
+ /* The size of pc is not added above. */
+ if ((size & SSIZE_OF(sw)) == 0)
+ size += SSIZE_OF(sw);
+
+ size += GET_SAVED_FLOAT_REGISTERS_SIZE(compiler->fscratches, compiler->fsaveds, f64);
+ }
+
+ SLJIT_ASSERT(((compiler->local_size + size + SSIZE_OF(sw)) & 0x7) == 0);
+
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE, dst_r, SLJIT_MEM1(SLJIT_SP), compiler->local_size + size, TMP_REG1));
+ break;
+ }
+
+ if (dst & SLJIT_MEM)
+ return emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG2, dst, dstw, TMP_REG1);
+
+ return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 type, sljit_s32 reg)
{
- CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
- return (freg_map[reg] << 1);
+ CHECK_REG_INDEX(check_sljit_get_register_index(type, reg));
+
+ if (type == SLJIT_GP_REGISTER)
+ return reg_map[reg];
+
+ if (type == SLJIT_FLOAT_REGISTER || type == SLJIT_SIMD_REG_64)
+ return freg_map[reg];
+
+ if (type != SLJIT_SIMD_REG_128)
+ return freg_map[reg] & ~0x1;
+
+ return -1;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
@@ -1954,35 +2089,35 @@ static sljit_s32 emit_fop_mem(struct sljit_compiler *compiler, sljit_s32 flags,
if ((arg & REG_MASK) && (argw & 0x3) == 0) {
if (!(argw & ~0x3fc))
- return push_inst32(compiler, inst | 0x800000 | RN4(arg & REG_MASK) | DD4(reg) | ((sljit_uw)argw >> 2));
+ return push_inst32(compiler, inst | 0x800000 | RN4(arg & REG_MASK) | VD4(reg) | ((sljit_uw)argw >> 2));
if (!(-argw & ~0x3fc))
- return push_inst32(compiler, inst | RN4(arg & REG_MASK) | DD4(reg) | ((sljit_uw)-argw >> 2));
+ return push_inst32(compiler, inst | RN4(arg & REG_MASK) | VD4(reg) | ((sljit_uw)-argw >> 2));
}
if (arg & REG_MASK) {
if (emit_set_delta(compiler, TMP_REG1, arg & REG_MASK, argw) != SLJIT_ERR_UNSUPPORTED) {
FAIL_IF(compiler->error);
- return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG1) | DD4(reg));
+ return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG1) | VD4(reg));
}
imm = get_imm((sljit_uw)argw & ~(sljit_uw)0x3fc);
if (imm != INVALID_IMM) {
FAIL_IF(push_inst32(compiler, ADD_WI | RD4(TMP_REG1) | RN4(arg & REG_MASK) | imm));
- return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG1) | DD4(reg) | (((sljit_uw)argw & 0x3fc) >> 2));
+ return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG1) | VD4(reg) | (((sljit_uw)argw & 0x3fc) >> 2));
}
imm = get_imm((sljit_uw)-argw & ~(sljit_uw)0x3fc);
if (imm != INVALID_IMM) {
argw = -argw;
FAIL_IF(push_inst32(compiler, SUB_WI | RD4(TMP_REG1) | RN4(arg & REG_MASK) | imm));
- return push_inst32(compiler, inst | RN4(TMP_REG1) | DD4(reg) | (((sljit_uw)argw & 0x3fc) >> 2));
+ return push_inst32(compiler, inst | RN4(TMP_REG1) | VD4(reg) | (((sljit_uw)argw & 0x3fc) >> 2));
}
}
FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)argw));
if (arg & REG_MASK)
FAIL_IF(push_inst16(compiler, ADD | SET_REGS44(TMP_REG1, (arg & REG_MASK))));
- return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG1) | DD4(reg));
+ return push_inst32(compiler, inst | 0x800000 | RN4(TMP_REG1) | VD4(reg));
}
static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
@@ -1996,41 +2131,53 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_comp
src = TMP_FREG1;
}
- FAIL_IF(push_inst32(compiler, VCVT_S32_F32 | (op & SLJIT_32) | DD4(TMP_FREG1) | DM4(src)));
+ FAIL_IF(push_inst32(compiler, VCVT_S32_F32 | (op & SLJIT_32) | VD4(TMP_FREG1) | VM4(src)));
if (FAST_IS_REG(dst))
- return push_inst32(compiler, VMOV | (1 << 20) | RT4(dst) | DN4(TMP_FREG1));
+ return push_inst32(compiler, VMOV | (1 << 20) | RT4(dst) | VN4(TMP_FREG1));
/* Store the integer value from a VFP register. */
return emit_fop_mem(compiler, 0, TMP_FREG1, dst, dstw);
}
-static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+static sljit_s32 sljit_emit_fop1_conv_f64_from_w(struct sljit_compiler *compiler, sljit_ins ins,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 src, sljit_sw srcw)
{
sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
- op ^= SLJIT_32;
-
if (FAST_IS_REG(src))
- FAIL_IF(push_inst32(compiler, VMOV | RT4(src) | DN4(TMP_FREG1)));
+ FAIL_IF(push_inst32(compiler, VMOV | RT4(src) | VN4(TMP_FREG1)));
else if (src & SLJIT_MEM) {
/* Load the integer value into a VFP register. */
FAIL_IF(emit_fop_mem(compiler, FPU_LOAD, TMP_FREG1, src, srcw));
}
else {
FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)srcw));
- FAIL_IF(push_inst32(compiler, VMOV | RT4(TMP_REG1) | DN4(TMP_FREG1)));
+ FAIL_IF(push_inst32(compiler, VMOV | RT4(TMP_REG1) | VN4(TMP_FREG1)));
}
- FAIL_IF(push_inst32(compiler, VCVT_F32_S32 | (op & SLJIT_32) | DD4(dst_r) | DM4(TMP_FREG1)));
+ FAIL_IF(push_inst32(compiler, ins | VD4(dst_r) | VM4(TMP_FREG1)));
if (dst & SLJIT_MEM)
- return emit_fop_mem(compiler, (op & SLJIT_32), TMP_FREG1, dst, dstw);
+ return emit_fop_mem(compiler, (ins & SLJIT_32), TMP_FREG1, dst, dstw);
return SLJIT_SUCCESS;
}
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ return sljit_emit_fop1_conv_f64_from_w(compiler, VCVT_F32_S32 | (~op & SLJIT_32), dst, dstw, src, srcw);
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_uw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ return sljit_emit_fop1_conv_f64_from_w(compiler, VCVT_F32_U32 | (~op & SLJIT_32), dst, dstw, src, srcw);
+}
+
static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 src1, sljit_sw src1w,
sljit_s32 src2, sljit_sw src2w)
@@ -2038,17 +2185,23 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compile
op ^= SLJIT_32;
if (src1 & SLJIT_MEM) {
- emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG1, src1, src1w);
+ FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG1, src1, src1w));
src1 = TMP_FREG1;
}
if (src2 & SLJIT_MEM) {
- emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG2, src2, src2w);
+ FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG2, src2, src2w));
src2 = TMP_FREG2;
}
- FAIL_IF(push_inst32(compiler, VCMP_F32 | (op & SLJIT_32) | DD4(src1) | DM4(src2)));
- return push_inst32(compiler, VMRS);
+ FAIL_IF(push_inst32(compiler, VCMP_F32 | (op & SLJIT_32) | VD4(src1) | VM4(src2)));
+ FAIL_IF(push_inst32(compiler, VMRS));
+
+ if (GET_FLAG_TYPE(op) != SLJIT_UNORDERED_OR_EQUAL)
+ return SLJIT_SUCCESS;
+
+ FAIL_IF(push_inst16(compiler, IT | (0x6 << 4) | 0x8));
+ return push_inst16(compiler, CMP /* Rm, Rn = r0 */);
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
@@ -2068,7 +2221,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil
op ^= SLJIT_32;
if (src & SLJIT_MEM) {
- emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, dst_r, src, srcw);
+ FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, dst_r, src, srcw));
src = dst_r;
}
@@ -2076,19 +2229,19 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil
case SLJIT_MOV_F64:
if (src != dst_r) {
if (dst_r != TMP_FREG1)
- FAIL_IF(push_inst32(compiler, VMOV_F32 | (op & SLJIT_32) | DD4(dst_r) | DM4(src)));
+ FAIL_IF(push_inst32(compiler, VMOV_F32 | (op & SLJIT_32) | VD4(dst_r) | VM4(src)));
else
dst_r = src;
}
break;
case SLJIT_NEG_F64:
- FAIL_IF(push_inst32(compiler, VNEG_F32 | (op & SLJIT_32) | DD4(dst_r) | DM4(src)));
+ FAIL_IF(push_inst32(compiler, VNEG_F32 | (op & SLJIT_32) | VD4(dst_r) | VM4(src)));
break;
case SLJIT_ABS_F64:
- FAIL_IF(push_inst32(compiler, VABS_F32 | (op & SLJIT_32) | DD4(dst_r) | DM4(src)));
+ FAIL_IF(push_inst32(compiler, VABS_F32 | (op & SLJIT_32) | VD4(dst_r) | VM4(src)));
break;
case SLJIT_CONV_F64_FROM_F32:
- FAIL_IF(push_inst32(compiler, VCVT_F64_F32 | (op & SLJIT_32) | DD4(dst_r) | DM4(src)));
+ FAIL_IF(push_inst32(compiler, VCVT_F64_F32 | (op & SLJIT_32) | VD4(dst_r) | VM4(src)));
op ^= SLJIT_32;
break;
}
@@ -2115,27 +2268,33 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
if (src1 & SLJIT_MEM) {
- emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG1, src1, src1w);
+ FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG1, src1, src1w));
src1 = TMP_FREG1;
}
if (src2 & SLJIT_MEM) {
- emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG2, src2, src2w);
+ FAIL_IF(emit_fop_mem(compiler, (op & SLJIT_32) | FPU_LOAD, TMP_FREG2, src2, src2w));
src2 = TMP_FREG2;
}
switch (GET_OPCODE(op)) {
case SLJIT_ADD_F64:
- FAIL_IF(push_inst32(compiler, VADD_F32 | (op & SLJIT_32) | DD4(dst_r) | DN4(src1) | DM4(src2)));
+ FAIL_IF(push_inst32(compiler, VADD_F32 | (op & SLJIT_32) | VD4(dst_r) | VN4(src1) | VM4(src2)));
break;
case SLJIT_SUB_F64:
- FAIL_IF(push_inst32(compiler, VSUB_F32 | (op & SLJIT_32) | DD4(dst_r) | DN4(src1) | DM4(src2)));
+ FAIL_IF(push_inst32(compiler, VSUB_F32 | (op & SLJIT_32) | VD4(dst_r) | VN4(src1) | VM4(src2)));
break;
case SLJIT_MUL_F64:
- FAIL_IF(push_inst32(compiler, VMUL_F32 | (op & SLJIT_32) | DD4(dst_r) | DN4(src1) | DM4(src2)));
+ FAIL_IF(push_inst32(compiler, VMUL_F32 | (op & SLJIT_32) | VD4(dst_r) | VN4(src1) | VM4(src2)));
break;
case SLJIT_DIV_F64:
- FAIL_IF(push_inst32(compiler, VDIV_F32 | (op & SLJIT_32) | DD4(dst_r) | DN4(src1) | DM4(src2)));
+ FAIL_IF(push_inst32(compiler, VDIV_F32 | (op & SLJIT_32) | VD4(dst_r) | VN4(src1) | VM4(src2)));
break;
+ case SLJIT_COPYSIGN_F64:
+ FAIL_IF(push_inst32(compiler, VMOV | (1 << 20) | VN4(src2) | RT4(TMP_REG1) | ((op & SLJIT_32) ? (1 << 7) : 0)));
+ FAIL_IF(push_inst32(compiler, VABS_F32 | (op & SLJIT_32) | VD4(dst_r) | VM4(src1)));
+ FAIL_IF(push_inst32(compiler, CMPI_W | RN4(TMP_REG1) | 0));
+ FAIL_IF(push_inst16(compiler, IT | (0xb << 4) | 0x8));
+ return push_inst32(compiler, VNEG_F32 | (op & SLJIT_32) | VD4(dst_r) | VM4(dst_r));
}
if (!(dst & SLJIT_MEM))
@@ -2143,23 +2302,99 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
return emit_fop_mem(compiler, (op & SLJIT_32), TMP_FREG1, dst, dstw);
}
-/* --------------------------------------------------------------------- */
-/* Other instructions */
-/* --------------------------------------------------------------------- */
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset32(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f32 value)
+{
+#if defined(__ARM_NEON) && __ARM_NEON
+ sljit_u32 exp;
+ sljit_ins ins;
+#endif /* NEON */
+ union {
+ sljit_u32 imm;
+ sljit_f32 value;
+ } u;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fset32(compiler, freg, value));
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+ u.value = value;
+
+#if defined(__ARM_NEON) && __ARM_NEON
+ if ((u.imm << (32 - 19)) == 0) {
+ exp = (u.imm >> (23 + 2)) & 0x3f;
+
+ if (exp == 0x20 || exp == 0x1f) {
+ ins = ((u.imm >> 24) & 0x80) | ((u.imm >> 19) & 0x7f);
+ return push_inst32(compiler, (VMOV_F32 ^ (1 << 6)) | ((ins & 0xf0) << 12) | VD4(freg) | (ins & 0xf));
+ }
+ }
+#endif /* NEON */
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm));
+ return push_inst32(compiler, VMOV | VN4(freg) | RT4(TMP_REG1));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f64 value)
{
+#if defined(__ARM_NEON) && __ARM_NEON
+ sljit_u32 exp;
+ sljit_ins ins;
+#endif /* NEON */
+ union {
+ sljit_u32 imm[2];
+ sljit_f64 value;
+ } u;
+
CHECK_ERROR();
- CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
- ADJUST_LOCAL_OFFSET(dst, dstw);
+ CHECK(check_sljit_emit_fset64(compiler, freg, value));
- SLJIT_ASSERT(reg_map[TMP_REG2] == 14);
+ u.value = value;
- if (FAST_IS_REG(dst))
- return push_inst16(compiler, MOV | SET_REGS44(dst, TMP_REG2));
+#if defined(__ARM_NEON) && __ARM_NEON
+ if (u.imm[0] == 0 && (u.imm[1] << (64 - 48)) == 0) {
+ exp = (u.imm[1] >> ((52 - 32) + 2)) & 0x1ff;
- /* Memory. */
- return emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG2, dst, dstw, TMP_REG1);
+ if (exp == 0x100 || exp == 0xff) {
+ ins = ((u.imm[1] >> (56 - 32)) & 0x80) | ((u.imm[1] >> (48 - 32)) & 0x7f);
+ return push_inst32(compiler, (VMOV_F32 ^ (1 << 6)) | (1 << 8) | ((ins & 0xf0) << 12) | VD4(freg) | (ins & 0xf));
+ }
+ }
+#endif /* NEON */
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm[0]));
+ if (u.imm[0] == u.imm[1])
+ return push_inst32(compiler, VMOV2 | RN4(TMP_REG1) | RT4(TMP_REG1) | VM4(freg));
+
+ FAIL_IF(load_immediate(compiler, TMP_REG2, u.imm[1]));
+ return push_inst32(compiler, VMOV2 | RN4(TMP_REG2) | RT4(TMP_REG1) | VM4(freg));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 freg, sljit_s32 reg)
+{
+ sljit_s32 reg2;
+ sljit_ins inst;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+ if (reg & REG_PAIR_MASK) {
+ reg2 = REG_PAIR_SECOND(reg);
+ reg = REG_PAIR_FIRST(reg);
+
+ inst = VMOV2 | RN4(reg) | RT4(reg2) | VM4(freg);
+ } else {
+ inst = VMOV | VN4(freg) | RT4(reg);
+
+ if (!(op & SLJIT_32))
+ inst |= 1 << 7;
+ }
+
+ if (GET_OPCODE(op) == SLJIT_COPY_FROM_F64)
+ inst |= 1 << 20;
+
+ return push_inst32(compiler, inst);
}
/* --------------------------------------------------------------------- */
@@ -2170,15 +2405,17 @@ static sljit_uw get_cc(struct sljit_compiler *compiler, sljit_s32 type)
{
switch (type) {
case SLJIT_EQUAL:
+ case SLJIT_ATOMIC_STORED:
case SLJIT_F_EQUAL:
case SLJIT_ORDERED_EQUAL:
- case SLJIT_UNORDERED_OR_EQUAL: /* Not supported. */
+ case SLJIT_UNORDERED_OR_EQUAL:
return 0x0;
case SLJIT_NOT_EQUAL:
+ case SLJIT_ATOMIC_NOT_STORED:
case SLJIT_F_NOT_EQUAL:
case SLJIT_UNORDERED_OR_NOT_EQUAL:
- case SLJIT_ORDERED_NOT_EQUAL: /* Not supported. */
+ case SLJIT_ORDERED_NOT_EQUAL:
return 0x1;
case SLJIT_CARRY:
@@ -2453,18 +2690,18 @@ static sljit_s32 hardfloat_call_with_args(struct sljit_compiler *compiler, sljit
switch (arg_types & SLJIT_ARG_MASK) {
case SLJIT_ARG_TYPE_F64:
if (offset != new_offset)
- FAIL_IF(push_inst32(compiler, VMOV_F32 | SLJIT_32 | DD4(new_offset) | DM4(offset)));
+ FAIL_IF(push_inst32(compiler, VMOV_F32 | SLJIT_32 | VD4(new_offset) | VM4(offset)));
new_offset++;
offset++;
break;
case SLJIT_ARG_TYPE_F32:
if (f32_offset != 0) {
- FAIL_IF(push_inst32(compiler, VMOV_F32 | 0x400000 | DD4(f32_offset) | DM4(offset)));
+ FAIL_IF(push_inst32(compiler, VMOV_F32 | 0x400000 | VD4(f32_offset) | VM4(offset)));
f32_offset = 0;
} else {
if (offset != new_offset)
- FAIL_IF(push_inst32(compiler, VMOV_F32 | 0x400000 | DD4(new_offset) | DM4(offset)));
+ FAIL_IF(push_inst32(compiler, VMOV_F32 | 0x400000 | VD4(new_offset) | VM4(offset)));
f32_offset = new_offset;
new_offset++;
}
@@ -2546,7 +2783,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
SLJIT_ASSERT(reg_map[TMP_REG1] != 14);
- if (!(src & SLJIT_IMM)) {
+ if (src != SLJIT_IMM) {
if (FAST_IS_REG(src)) {
SLJIT_ASSERT(reg_map[src] != 14);
return push_inst16(compiler, (type <= SLJIT_JUMP ? BX : BLX) | RN3(src));
@@ -2645,8 +2882,8 @@ static SLJIT_INLINE sljit_s32 emit_fmov_before_return(struct sljit_compiler *com
if (FAST_IS_REG(src)) {
if (op & SLJIT_32)
- return push_inst32(compiler, VMOV | (1 << 20) | DN4(src) | RT4(SLJIT_R0));
- return push_inst32(compiler, VMOV2 | (1 << 20) | DM4(src) | RT4(SLJIT_R0) | RN4(SLJIT_R1));
+ return push_inst32(compiler, VMOV | (1 << 20) | VN4(src) | RT4(SLJIT_R0));
+ return push_inst32(compiler, VMOV2 | (1 << 20) | VM4(src) | RT4(SLJIT_R0) | RN4(SLJIT_R1));
}
SLJIT_SKIP_CHECKS(compiler);
@@ -2711,23 +2948,47 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
return push_inst32(compiler, MOV_W | SET_FLAGS | RD4(TMP_REG1) | RM4(dst_r));
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *compiler, sljit_s32 type,
sljit_s32 dst_reg,
- sljit_s32 src, sljit_sw srcw)
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_reg)
{
sljit_uw cc, tmp;
CHECK_ERROR();
- CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
+ CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));
+
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+
+ if (src2_reg != dst_reg && src1 == dst_reg) {
+ src1 = src2_reg;
+ src1w = 0;
+ src2_reg = dst_reg;
+ type ^= 0x1;
+ }
+
+ if (src1 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, WORD_SIZE, (src2_reg != dst_reg) ? dst_reg : TMP_REG1, src1, src1w, TMP_REG2));
+
+ if (src2_reg != dst_reg) {
+ src1 = src2_reg;
+ src1w = 0;
+ type ^= 0x1;
+ } else {
+ src1 = TMP_REG1;
+ src1w = 0;
+ }
+ } else if (dst_reg != src2_reg)
+ FAIL_IF(push_inst16(compiler, MOV | SET_REGS44(dst_reg, src2_reg)));
cc = get_cc(compiler, type & ~SLJIT_32);
- if (!(src & SLJIT_IMM)) {
+ if (src1 != SLJIT_IMM) {
FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
- return push_inst16(compiler, MOV | SET_REGS44(dst_reg, src));
+ return push_inst16(compiler, MOV | SET_REGS44(dst_reg, src1));
}
- tmp = (sljit_uw) srcw;
+ tmp = (sljit_uw)src1w;
if (tmp < 0x10000) {
/* set low 16 bits, set hi 16 bits to 0. */
@@ -2736,13 +2997,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil
| COPY_BITS(tmp, 12, 16, 4) | COPY_BITS(tmp, 11, 26, 1) | COPY_BITS(tmp, 8, 12, 3) | (tmp & 0xff));
}
- tmp = get_imm((sljit_uw)srcw);
+ tmp = get_imm((sljit_uw)src1w);
if (tmp != INVALID_IMM) {
FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
return push_inst32(compiler, MOV_WI | RD4(dst_reg) | tmp);
}
- tmp = get_imm(~(sljit_uw)srcw);
+ tmp = get_imm(~(sljit_uw)src1w);
if (tmp != INVALID_IMM) {
FAIL_IF(push_inst16(compiler, IT | (cc << 4) | 0x8));
return push_inst32(compiler, MVN_WI | RD4(dst_reg) | tmp);
@@ -2750,13 +3011,43 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil
FAIL_IF(push_inst16(compiler, IT | (cc << 4) | ((cc & 0x1) << 3) | 0x4));
- tmp = (sljit_uw) srcw;
+ tmp = (sljit_uw)src1w;
FAIL_IF(push_inst32(compiler, MOVW | RD4(dst_reg)
| COPY_BITS(tmp, 12, 16, 4) | COPY_BITS(tmp, 11, 26, 1) | COPY_BITS(tmp, 8, 12, 3) | (tmp & 0xff)));
return push_inst32(compiler, MOVT | RD4(dst_reg)
| COPY_BITS(tmp, 12 + 16, 16, 4) | COPY_BITS(tmp, 11 + 16, 26, 1) | COPY_BITS(tmp, 8 + 16, 12, 3) | ((tmp & 0xff0000) >> 16));
}
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_freg)
+{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fselect(compiler, type, dst_freg, src1, src1w, src2_freg));
+
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+
+ type ^= SLJIT_32;
+
+ if (dst_freg != src2_freg) {
+ if (dst_freg == src1) {
+ src1 = src2_freg;
+ src1w = 0;
+ type ^= 0x1;
+ } else
+ FAIL_IF(push_inst32(compiler, VMOV_F32 | (type & SLJIT_32) | VD4(dst_freg) | VM4(src2_freg)));
+ }
+
+ if (src1 & SLJIT_MEM) {
+ FAIL_IF(emit_fop_mem(compiler, (type & SLJIT_32) | FPU_LOAD, TMP_FREG1, src1, src1w));
+ src1 = TMP_FREG1;
+ }
+
+ FAIL_IF(push_inst16(compiler, IT | (get_cc(compiler, type & ~SLJIT_32) << 4) | 0x8));
+ return push_inst32(compiler, VMOV_F32 | (type & SLJIT_32) | VD4(dst_freg) | VM4(src1));
+}
+
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type,
sljit_s32 reg,
sljit_s32 mem, sljit_sw memw)
@@ -2770,7 +3061,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compile
if (!(reg & REG_PAIR_MASK))
return sljit_emit_mem_unaligned(compiler, type, reg, mem, memw);
- if (type & (SLJIT_MEM_UNALIGNED | SLJIT_MEM_UNALIGNED_16 | SLJIT_MEM_UNALIGNED_32)) {
+ if (type & (SLJIT_MEM_UNALIGNED | SLJIT_MEM_ALIGNED_16 | SLJIT_MEM_ALIGNED_32)) {
if ((mem & REG_MASK) == 0) {
if ((memw & 0xfff) >= (0x1000 - SSIZE_OF(sw))) {
imm = get_imm((sljit_uw)((memw + 0x1000) & ~0xfff));
@@ -2781,7 +3072,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compile
imm = get_imm((sljit_uw)(memw & ~0xfff));
if (imm != INVALID_IMM)
- memw &= 0xff;
+ memw &= 0xfff;
}
if (imm == INVALID_IMM) {
@@ -3058,11 +3349,11 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem(struct sljit_compiler *compil
CHECK_ERROR();
CHECK(check_sljit_emit_fmem(compiler, type, freg, mem, memw));
- if (type & SLJIT_MEM_UNALIGNED_32)
+ if (type & SLJIT_MEM_ALIGNED_32)
return emit_fop_mem(compiler, ((type ^ SLJIT_32) & SLJIT_32) | ((type & SLJIT_MEM_STORE) ? 0 : FPU_LOAD), freg, mem, memw);
if (type & SLJIT_MEM_STORE) {
- FAIL_IF(push_inst32(compiler, VMOV | (1 << 20) | DN4(freg) | RT4(TMP_REG2)));
+ FAIL_IF(push_inst32(compiler, VMOV | (1 << 20) | VN4(freg) | RT4(TMP_REG2)));
if (type & SLJIT_32)
return emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG2, mem, memw, TMP_REG1);
@@ -3071,13 +3362,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem(struct sljit_compiler *compil
mem |= SLJIT_MEM;
FAIL_IF(emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG2, mem, memw, TMP_REG1));
- FAIL_IF(push_inst32(compiler, VMOV | (1 << 20) | DN4(freg) | 0x80 | RT4(TMP_REG2)));
+ FAIL_IF(push_inst32(compiler, VMOV | (1 << 20) | VN4(freg) | 0x80 | RT4(TMP_REG2)));
return emit_op_mem(compiler, WORD_SIZE | STORE, TMP_REG2, mem, memw + 4, TMP_REG1);
}
if (type & SLJIT_32) {
FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, mem, memw, TMP_REG1));
- return push_inst32(compiler, VMOV | DN4(freg) | RT4(TMP_REG2));
+ return push_inst32(compiler, VMOV | VN4(freg) | RT4(TMP_REG2));
}
FAIL_IF(update_mem_addr(compiler, &mem, &memw, 0xfff - 4));
@@ -3085,11 +3376,715 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem(struct sljit_compiler *compil
FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG2, mem, memw, TMP_REG1));
FAIL_IF(emit_op_mem(compiler, WORD_SIZE, TMP_REG1, mem, memw + 4, TMP_REG1));
- return push_inst32(compiler, VMOV2 | DM4(freg) | RT4(TMP_REG2) | RN4(TMP_REG1));
+ return push_inst32(compiler, VMOV2 | VM4(freg) | RT4(TMP_REG2) | RN4(TMP_REG1));
+}
+
+static sljit_s32 sljit_emit_simd_mem_offset(struct sljit_compiler *compiler, sljit_s32 *mem_ptr, sljit_sw memw)
+{
+ sljit_uw imm;
+ sljit_s32 mem = *mem_ptr;
+
+ if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {
+ *mem_ptr = TMP_REG1;
+ return push_inst32(compiler, ADD_W | RD4(TMP_REG1) | RN4(mem & REG_MASK) | RM4(OFFS_REG(mem)) | ((sljit_uw)(memw & 0x3) << 6));
+ }
+
+ if (SLJIT_UNLIKELY(!(mem & REG_MASK))) {
+ *mem_ptr = TMP_REG1;
+ return load_immediate(compiler, TMP_REG1, (sljit_uw)memw);
+ }
+
+ mem &= REG_MASK;
+
+ if (memw == 0) {
+ *mem_ptr = mem;
+ return SLJIT_SUCCESS;
+ }
+
+ *mem_ptr = TMP_REG1;
+ imm = get_imm((sljit_uw)(memw < 0 ? -memw : memw));
+
+ if (imm != INVALID_IMM)
+ return push_inst32(compiler, ((memw < 0) ? SUB_WI : ADD_WI) | RD4(TMP_REG1) | RN4(mem) | imm);
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)memw));
+ return push_inst16(compiler, ADD | SET_REGS44(TMP_REG1, mem));
+}
+
+static SLJIT_INLINE sljit_s32 simd_get_quad_reg_index(sljit_s32 freg)
+{
+ freg += freg & 0x1;
+
+ SLJIT_ASSERT((freg_map[freg] & 0x1) == (freg <= SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS));
+
+ if (freg <= SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS)
+ freg--;
+
+ return freg;
+}
+
+#define SLJIT_QUAD_OTHER_HALF(freg) ((((freg) & 0x1) << 1) - 1)
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_mov(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 srcdst, sljit_sw srcdstw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_s32 alignment = SLJIT_SIMD_GET_ELEM2_SIZE(type);
+ sljit_ins ins;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_mov(compiler, type, freg, srcdst, srcdstw));
+
+ ADJUST_LOCAL_OFFSET(srcdst, srcdstw);
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (reg_size == 4)
+ freg = simd_get_quad_reg_index(freg);
+
+ if (!(srcdst & SLJIT_MEM)) {
+ if (reg_size == 4)
+ srcdst = simd_get_quad_reg_index(srcdst);
+
+ if (type & SLJIT_SIMD_STORE)
+ ins = VD4(srcdst) | VN4(freg) | VM4(freg);
+ else
+ ins = VD4(freg) | VN4(srcdst) | VM4(srcdst);
+
+ if (reg_size == 4)
+ ins |= (sljit_ins)1 << 6;
+
+ return push_inst32(compiler, VORR | ins);
+ }
+
+ FAIL_IF(sljit_emit_simd_mem_offset(compiler, &srcdst, srcdstw));
+
+ if (elem_size > 3)
+ elem_size = 3;
+
+ ins = ((type & SLJIT_SIMD_STORE) ? VST1 : VLD1) | VD4(freg)
+ | (sljit_ins)((reg_size == 3) ? (0x7 << 8) : (0xa << 8));
+
+ SLJIT_ASSERT(reg_size >= alignment);
+
+ if (alignment == 3)
+ ins |= 0x10;
+ else if (alignment >= 4)
+ ins |= 0x20;
+
+ return push_inst32(compiler, ins | RN4(srcdst) | ((sljit_ins)elem_size) << 6 | 0xf);
+}
+
+static sljit_ins simd_get_imm(sljit_s32 elem_size, sljit_uw value)
+{
+ sljit_ins result;
+
+ if (elem_size > 1 && (sljit_u16)value == (value >> 16)) {
+ elem_size = 1;
+ value = (sljit_u16)value;
+ }
+
+ if (elem_size == 1 && (sljit_u8)value == (value >> 8)) {
+ elem_size = 0;
+ value = (sljit_u8)value;
+ }
+
+ switch (elem_size) {
+ case 0:
+ SLJIT_ASSERT(value <= 0xff);
+ result = 0xe00;
+ break;
+ case 1:
+ SLJIT_ASSERT(value <= 0xffff);
+ result = 0;
+
+ while (1) {
+ if (value <= 0xff) {
+ result |= 0x800;
+ break;
+ }
+
+ if ((value & 0xff) == 0) {
+ value >>= 8;
+ result |= 0xa00;
+ break;
+ }
+
+ if (result != 0)
+ return ~(sljit_ins)0;
+
+ value ^= (sljit_uw)0xffff;
+ result = (1 << 5);
+ }
+ break;
+ default:
+ SLJIT_ASSERT(value <= 0xffffffff);
+ result = 0;
+
+ while (1) {
+ if (value <= 0xff) {
+ result |= 0x000;
+ break;
+ }
+
+ if ((value & ~(sljit_uw)0xff00) == 0) {
+ value >>= 8;
+ result |= 0x200;
+ break;
+ }
+
+ if ((value & ~(sljit_uw)0xff0000) == 0) {
+ value >>= 16;
+ result |= 0x400;
+ break;
+ }
+
+ if ((value & ~(sljit_uw)0xff000000) == 0) {
+ value >>= 24;
+ result |= 0x600;
+ break;
+ }
+
+ if ((value & (sljit_uw)0xff) == 0xff && (value >> 16) == 0) {
+ value >>= 8;
+ result |= 0xc00;
+ break;
+ }
+
+ if ((value & (sljit_uw)0xffff) == 0xffff && (value >> 24) == 0) {
+ value >>= 16;
+ result |= 0xd00;
+ break;
+ }
+
+ if (result != 0)
+ return ~(sljit_ins)0;
+
+ value = ~value;
+ result = (1 << 5);
+ }
+ break;
+ }
+
+ return ((sljit_ins)value & 0xf) | (((sljit_ins)value & 0x70) << 12) | (((sljit_ins)value & 0x80) << 21) | result;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins, imm;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_replicate(compiler, type, freg, src, srcw));
+
+ ADJUST_LOCAL_OFFSET(src, srcw);
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) ? (elem_size < 2 || elem_size > 3) : (elem_size > 2))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (reg_size == 4)
+ freg = simd_get_quad_reg_index(freg);
+
+ if (src == SLJIT_IMM && srcw == 0)
+ return push_inst32(compiler, VMOV_i | ((reg_size == 4) ? (1 << 6) : 0) | VD4(freg));
+
+ if (SLJIT_UNLIKELY(elem_size == 3)) {
+ SLJIT_ASSERT(type & SLJIT_SIMD_FLOAT);
+
+ if (src & SLJIT_MEM) {
+ FAIL_IF(emit_fop_mem(compiler, FPU_LOAD | SLJIT_32, freg, src, srcw));
+ src = freg;
+ } else if (freg != src)
+ FAIL_IF(push_inst32(compiler, VORR | VD4(freg) | VN4(src) | VM4(src)));
+
+ freg += SLJIT_QUAD_OTHER_HALF(freg);
+
+ if (freg != src)
+ return push_inst32(compiler, VORR | VD4(freg) | VN4(src) | VM4(src));
+ return SLJIT_SUCCESS;
+ }
+
+ if (src & SLJIT_MEM) {
+ FAIL_IF(sljit_emit_simd_mem_offset(compiler, &src, srcw));
+
+ ins = (sljit_ins)(elem_size << 6);
+
+ if (reg_size == 4)
+ ins |= 1 << 5;
+
+ return push_inst32(compiler, VLD1_r | ins | VD4(freg) | RN4(src) | 0xf);
+ }
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ SLJIT_ASSERT(elem_size == 2);
+ ins = ((sljit_ins)freg_ebit_map[src] << (16 + 2 + 1)) | ((sljit_ins)1 << (16 + 2));
+
+ if (reg_size == 4)
+ ins |= (sljit_ins)1 << 6;
+
+ return push_inst32(compiler, VDUP_s | ins | VD4(freg) | (sljit_ins)freg_map[src]);
+ }
+
+ if (src == SLJIT_IMM) {
+ if (elem_size < 2)
+ srcw &= ((sljit_sw)1 << (((sljit_sw)1 << elem_size) << 3)) - 1;
+
+ imm = simd_get_imm(elem_size, (sljit_uw)srcw);
+
+ if (imm != ~(sljit_ins)0) {
+ if (reg_size == 4)
+ imm |= (sljit_ins)1 << 6;
+
+ return push_inst32(compiler, VMOV_i | imm | VD4(freg));
+ }
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)srcw));
+ src = TMP_REG1;
+ }
+
+ switch (elem_size) {
+ case 0:
+ ins = 1 << 22;
+ break;
+ case 1:
+ ins = 1 << 5;
+ break;
+ default:
+ ins = 0;
+ break;
+ }
+
+ if (reg_size == 4)
+ ins |= (sljit_ins)1 << 21;
+
+ return push_inst32(compiler, VDUP | ins | VN4(freg) | RT4(src));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg, sljit_s32 lane_index,
+ sljit_s32 srcdst, sljit_sw srcdstw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_lane_mov(compiler, type, freg, lane_index, srcdst, srcdstw));
+
+ ADJUST_LOCAL_OFFSET(srcdst, srcdstw);
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) ? (elem_size < 2 || elem_size > 3) : (elem_size > 2))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (reg_size == 4)
+ freg = simd_get_quad_reg_index(freg);
+
+ if (type & SLJIT_SIMD_LANE_ZERO) {
+ ins = (reg_size == 3) ? 0 : ((sljit_ins)1 << 6);
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ if (elem_size == 3 && !(srcdst & SLJIT_MEM)) {
+ if (lane_index == 1)
+ freg += SLJIT_QUAD_OTHER_HALF(freg);
+
+ if (srcdst != freg)
+ FAIL_IF(push_inst32(compiler, VORR | VD4(freg) | VN4(srcdst) | VM4(srcdst)));
+
+ freg += SLJIT_QUAD_OTHER_HALF(freg);
+ return push_inst32(compiler, VMOV_i | VD4(freg));
+ }
+
+ if (srcdst == freg || (elem_size == 3 && srcdst == (freg + SLJIT_QUAD_OTHER_HALF(freg)))) {
+ FAIL_IF(push_inst32(compiler, VORR | ins | VD4(TMP_FREG2) | VN4(freg) | VM4(freg)));
+ srcdst = TMP_FREG2;
+ srcdstw = 0;
+ }
+ }
+
+ FAIL_IF(push_inst32(compiler, VMOV_i | ins | VD4(freg)));
+ }
+
+ if (reg_size == 4 && lane_index >= (0x8 >> elem_size)) {
+ lane_index -= (0x8 >> elem_size);
+ freg += SLJIT_QUAD_OTHER_HALF(freg);
+ }
+
+ if (srcdst & SLJIT_MEM) {
+ if (elem_size == 3)
+ return emit_fop_mem(compiler, ((type & SLJIT_SIMD_STORE) ? 0 : FPU_LOAD) | SLJIT_32, freg, srcdst, srcdstw);
+
+ FAIL_IF(sljit_emit_simd_mem_offset(compiler, &srcdst, srcdstw));
+
+ lane_index = lane_index << elem_size;
+ ins = (sljit_ins)((elem_size << 10) | (lane_index << 5));
+ return push_inst32(compiler, ((type & SLJIT_SIMD_STORE) ? VST1_s : VLD1_s) | ins | VD4(freg) | RN4(srcdst) | 0xf);
+ }
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ if (elem_size == 3) {
+ if (type & SLJIT_SIMD_STORE)
+ return push_inst32(compiler, VORR | VD4(srcdst) | VN4(freg) | VM4(freg));
+ return push_inst32(compiler, VMOV_F32 | SLJIT_32 | VD4(freg) | VM4(srcdst));
+ }
+
+ if (type & SLJIT_SIMD_STORE) {
+ if (freg_ebit_map[freg] == 0) {
+ if (lane_index == 1)
+ freg = SLJIT_F64_SECOND(freg);
+
+ return push_inst32(compiler, VMOV_F32 | VD4(srcdst) | VM4(freg));
+ }
+
+ FAIL_IF(push_inst32(compiler, VMOV_s | (1 << 20) | ((sljit_ins)lane_index << 21) | VN4(freg) | RT4(TMP_REG1)));
+ return push_inst32(compiler, VMOV | VN4(srcdst) | RT4(TMP_REG1));
+ }
+
+ FAIL_IF(push_inst32(compiler, VMOV | (1 << 20) | VN4(srcdst) | RT4(TMP_REG1)));
+ return push_inst32(compiler, VMOV_s | ((sljit_ins)lane_index << 21) | VN4(freg) | RT4(TMP_REG1));
+ }
+
+ if (srcdst == SLJIT_IMM) {
+ if (elem_size < 2)
+ srcdstw &= ((sljit_sw)1 << (((sljit_sw)1 << elem_size) << 3)) - 1;
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_uw)srcdstw));
+ srcdst = TMP_REG1;
+ }
+
+ if (elem_size == 0)
+ ins = 0x400000;
+ else if (elem_size == 1)
+ ins = 0x20;
+ else
+ ins = 0;
+
+ lane_index = lane_index << elem_size;
+ ins |= (sljit_ins)(((lane_index & 0x4) << 19) | ((lane_index & 0x3) << 5));
+
+ if (type & SLJIT_SIMD_STORE) {
+ ins |= (1 << 20);
+
+ if (elem_size < 2 && !(type & SLJIT_SIMD_LANE_SIGNED))
+ ins |= (1 << 23);
+ }
+
+ return push_inst32(compiler, VMOV_s | ins | VN4(freg) | RT4(srcdst));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_s32 src_lane_index)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_lane_replicate(compiler, type, freg, src, src_lane_index));
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (reg_size == 4) {
+ freg = simd_get_quad_reg_index(freg);
+ src = simd_get_quad_reg_index(src);
+
+ if (src_lane_index >= (0x8 >> elem_size)) {
+ src_lane_index -= (0x8 >> elem_size);
+ src += SLJIT_QUAD_OTHER_HALF(src);
+ }
+ }
+
+ if (elem_size == 3) {
+ if (freg != src)
+ FAIL_IF(push_inst32(compiler, VORR | VD4(freg) | VN4(src) | VM4(src)));
+
+ freg += SLJIT_QUAD_OTHER_HALF(freg);
+
+ if (freg != src)
+ return push_inst32(compiler, VORR | VD4(freg) | VN4(src) | VM4(src));
+ return SLJIT_SUCCESS;
+ }
+
+ ins = ((((sljit_ins)src_lane_index << 1) | 1) << (16 + elem_size));
+
+ if (reg_size == 4)
+ ins |= (sljit_ins)1 << 6;
+
+ return push_inst32(compiler, VDUP_s | ins | VD4(freg) | VM4(src));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_extend(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_s32 elem2_size = SLJIT_SIMD_GET_ELEM2_SIZE(type);
+ sljit_s32 dst_reg;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_extend(compiler, type, freg, src, srcw));
+
+ ADJUST_LOCAL_OFFSET(src, srcw);
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size != 2 || elem2_size != 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (reg_size == 4)
+ freg = simd_get_quad_reg_index(freg);
+
+ if (src & SLJIT_MEM) {
+ FAIL_IF(sljit_emit_simd_mem_offset(compiler, &src, srcw));
+ if (reg_size == 4 && elem2_size - elem_size == 1)
+ FAIL_IF(push_inst32(compiler, VLD1 | (0x7 << 8) | VD4(freg) | RN4(src) | 0xf));
+ else
+ FAIL_IF(push_inst32(compiler, VLD1_s | (sljit_ins)((reg_size - elem2_size + elem_size) << 10) | VD4(freg) | RN4(src) | 0xf));
+ src = freg;
+ } else if (reg_size == 4)
+ src = simd_get_quad_reg_index(src);
+
+ if (!(type & SLJIT_SIMD_FLOAT)) {
+ dst_reg = (reg_size == 4) ? freg : TMP_FREG2;
+
+ do {
+ FAIL_IF(push_inst32(compiler, VSHLL | ((type & SLJIT_SIMD_EXTEND_SIGNED) ? 0 : (1 << 28))
+ | ((sljit_ins)1 << (19 + elem_size)) | VD4(dst_reg) | VM4(src)));
+ src = dst_reg;
+ } while (++elem_size < elem2_size);
+
+ if (dst_reg == TMP_FREG2)
+ return push_inst32(compiler, VORR | VD4(freg) | VN4(TMP_FREG2) | VM4(TMP_FREG2));
+ return SLJIT_SUCCESS;
+ }
+
+ /* No SIMD variant, must use VFP instead. */
+ SLJIT_ASSERT(reg_size == 4);
+
+ if (freg == src) {
+ freg += SLJIT_QUAD_OTHER_HALF(freg);
+ FAIL_IF(push_inst32(compiler, VCVT_F64_F32 | VD4(freg) | VM4(src) | 0x20));
+ freg += SLJIT_QUAD_OTHER_HALF(freg);
+ return push_inst32(compiler, VCVT_F64_F32 | VD4(freg) | VM4(src));
+ }
+
+ FAIL_IF(push_inst32(compiler, VCVT_F64_F32 | VD4(freg) | VM4(src)));
+ freg += SLJIT_QUAD_OTHER_HALF(freg);
+ return push_inst32(compiler, VCVT_F64_F32 | VD4(freg) | VM4(src) | 0x20);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 dst, sljit_sw dstw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins, imms;
+ sljit_s32 dst_r;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_sign(compiler, type, freg, dst, dstw));
+
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ switch (elem_size) {
+ case 0:
+ imms = 0x243219;
+ ins = VSHR | (1 << 28) | (0x9 << 16);
+ break;
+ case 1:
+ imms = (reg_size == 4) ? 0x243219 : 0x2231;
+ ins = VSHR | (1 << 28) | (0x11 << 16);
+ break;
+ case 2:
+ imms = (reg_size == 4) ? 0x2231 : 0x21;
+ ins = VSHR | (1 << 28) | (0x21 << 16);
+ break;
+ default:
+ imms = 0x21;
+ ins = VSHR | (1 << 28) | (0x1 << 16) | (1 << 7);
+ break;
+ }
+
+ if (reg_size == 4) {
+ freg = simd_get_quad_reg_index(freg);
+ ins |= (sljit_ins)1 << 6;
+ }
+
+ SLJIT_ASSERT((freg_map[TMP_FREG2] & 0x1) == 0);
+ FAIL_IF(push_inst32(compiler, ins | VD4(TMP_FREG2) | VM4(freg)));
+
+ if (reg_size == 4 && elem_size > 0)
+ FAIL_IF(push_inst32(compiler, VMOVN | ((sljit_ins)(elem_size - 1) << 18) | VD4(TMP_FREG2) | VM4(TMP_FREG2)));
+
+ ins = (reg_size == 4 && elem_size == 0) ? (1 << 6) : 0;
+
+ while (imms >= 0x100) {
+ FAIL_IF(push_inst32(compiler, VSRA | (1 << 28) | ins | ((imms & 0xff) << 16) | VD4(TMP_FREG2) | VM4(TMP_FREG2)));
+ imms >>= 8;
+ }
+
+ FAIL_IF(push_inst32(compiler, VSRA | (1 << 28) | ins | (1 << 7) | (imms << 16) | VD4(TMP_FREG2) | VM4(TMP_FREG2)));
+
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+ FAIL_IF(push_inst32(compiler, VMOV_s | (1 << 20) | (1 << 23) | (0x2 << 21) | RT4(dst_r) | VN4(TMP_FREG2)));
+
+ if (reg_size == 4 && elem_size == 0) {
+ SLJIT_ASSERT(freg_map[TMP_FREG2] + 1 == freg_map[TMP_FREG1]);
+ FAIL_IF(push_inst32(compiler, VMOV_s | (1 << 20) | (1 << 23) | (0x2 << 21) | RT4(TMP_REG2)| VN4(TMP_FREG1)));
+ FAIL_IF(push_inst32(compiler, ORR_W | RD4(dst_r) | RN4(dst_r) | RM4(TMP_REG2) | (0x2 << 12)));
+ }
+
+ if (dst_r == TMP_REG1)
+ return emit_op_mem(compiler, STORE | WORD_SIZE, TMP_REG1, dst, dstw, TMP_REG2);
+
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_op2(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg, sljit_s32 src1_freg, sljit_s32 src2_freg)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_op2(compiler, type, dst_freg, src1_freg, src2_freg));
+
+ if (reg_size != 3 && reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ switch (SLJIT_SIMD_GET_OPCODE(type)) {
+ case SLJIT_SIMD_OP2_AND:
+ ins = VAND;
+ break;
+ case SLJIT_SIMD_OP2_OR:
+ ins = VORR;
+ break;
+ case SLJIT_SIMD_OP2_XOR:
+ ins = VEOR;
+ break;
+ }
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (reg_size == 4) {
+ dst_freg = simd_get_quad_reg_index(dst_freg);
+ src1_freg = simd_get_quad_reg_index(src1_freg);
+ src2_freg = simd_get_quad_reg_index(src2_freg);
+ ins |= (sljit_ins)1 << 6;
+ }
+
+ return push_inst32(compiler, ins | VD4(dst_freg) | VN4(src1_freg) | VM4(src2_freg));
}
#undef FPU_LOAD
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_load(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_reg,
+ sljit_s32 mem_reg)
+{
+ sljit_ins ins;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_atomic_load(compiler, op, dst_reg, mem_reg));
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MOV_U8:
+ ins = LDREXB;
+ break;
+ case SLJIT_MOV_U16:
+ ins = LDREXH;
+ break;
+ default:
+ ins = LDREX;
+ break;
+ }
+
+ return push_inst32(compiler, ins | RN4(mem_reg) | RT4(dst_reg));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src_reg,
+ sljit_s32 mem_reg,
+ sljit_s32 temp_reg)
+{
+ sljit_ins ins;
+
+ /* temp_reg == mem_reg is undefined so use another temp register */
+ SLJIT_UNUSED_ARG(temp_reg);
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_atomic_store(compiler, op, src_reg, mem_reg, temp_reg));
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MOV_U8:
+ ins = STREXB | RM4(TMP_REG1);
+ break;
+ case SLJIT_MOV_U16:
+ ins = STREXH | RM4(TMP_REG1);
+ break;
+ default:
+ ins = STREX | RD4(TMP_REG1);
+ break;
+ }
+
+ FAIL_IF(push_inst32(compiler, ins | RN4(mem_reg) | RT4(src_reg)));
+ if (op & SLJIT_SET_ATOMIC_STORED)
+ return push_inst32(compiler, CMPI_W | RN4(TMP_REG1));
+
+ return SLJIT_SUCCESS;
+}
+
SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw, sljit_sw init_value)
{
struct sljit_const *const_;
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_32.c b/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_32.c
index e6853c98f6..9620b945f6 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_32.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_32.c
@@ -26,6 +26,49 @@
/* mips 32-bit arch dependent functions. */
+static sljit_s32 emit_copysign(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_sw src1, sljit_sw src2, sljit_sw dst)
+{
+ int is_32 = (op & SLJIT_32);
+ sljit_ins mfhc = MFC1, mthc = MTC1;
+ sljit_ins src1_r = FS(src1), src2_r = FS(src2), dst_r = FS(dst);
+
+ if (!is_32) {
+ switch (cpu_feature_list & CPU_FEATURE_FR) {
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
+ case CPU_FEATURE_FR:
+ mfhc = MFHC1;
+ mthc = MTHC1;
+ break;
+#endif /* SLJIT_MIPS_REV >= 2 */
+ default:
+ src1_r |= (1 << 11);
+ src2_r |= (1 << 11);
+ dst_r |= (1 << 11);
+ break;
+ }
+ }
+
+ FAIL_IF(push_inst(compiler, mfhc | T(TMP_REG1) | src1_r, DR(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, mfhc | T(TMP_REG2) | src2_r, DR(TMP_REG2)));
+ if (!is_32 && src1 != dst)
+ FAIL_IF(push_inst(compiler, MOV_fmt(FMT_S) | FS(src1) | FD(dst), MOVABLE_INS));
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
+ else
+ FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+#endif /* MIPS III */
+ FAIL_IF(push_inst(compiler, XOR | T(TMP_REG1) | D(TMP_REG2) | S(TMP_REG2), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, SRL | T(TMP_REG2) | D(TMP_REG2) | SH_IMM(31), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, SLL | T(TMP_REG2) | D(TMP_REG2) | SH_IMM(31), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, XOR | T(TMP_REG2) | D(TMP_REG1) | S(TMP_REG1), DR(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, mthc | T(TMP_REG1) | dst_r, MOVABLE_INS));
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
+ if (mthc == MTC1)
+ return push_inst(compiler, NOP, UNMOVABLE_INS);
+#endif /* MIPS III */
+ return SLJIT_SUCCESS;
+}
+
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm)
{
if (!(imm & ~0xffff))
@@ -44,6 +87,108 @@ static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_
return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
}
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f64 value)
+{
+ union {
+ struct {
+#if defined(SLJIT_LITTLE_ENDIAN) && SLJIT_LITTLE_ENDIAN
+ sljit_s32 lo;
+ sljit_s32 hi;
+#else /* !SLJIT_LITTLE_ENDIAN */
+ sljit_s32 hi;
+ sljit_s32 lo;
+#endif /* SLJIT_LITTLE_ENDIAN */
+ } bin;
+ sljit_f64 value;
+ } u;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fset64(compiler, freg, value));
+
+ u.value = value;
+
+ if (u.bin.lo != 0)
+ FAIL_IF(load_immediate(compiler, DR(TMP_REG1), u.bin.lo));
+ if (u.bin.hi != 0)
+ FAIL_IF(load_immediate(compiler, DR(TMP_REG2), u.bin.hi));
+
+ FAIL_IF(push_inst(compiler, MTC1 | (u.bin.lo != 0 ? T(TMP_REG1) : TA(0)) | FS(freg), MOVABLE_INS));
+ switch (cpu_feature_list & CPU_FEATURE_FR) {
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
+ case CPU_FEATURE_FR:
+ return push_inst(compiler, MTHC1 | (u.bin.hi != 0 ? T(TMP_REG2) : TA(0)) | FS(freg), MOVABLE_INS);
+#endif /* SLJIT_MIPS_REV >= 2 */
+ default:
+ FAIL_IF(push_inst(compiler, MTC1 | (u.bin.hi != 0 ? T(TMP_REG2) : TA(0)) | FS(freg) | (1 << 11), MOVABLE_INS));
+ break;
+ }
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
+ FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+#endif /* MIPS III */
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 freg, sljit_s32 reg)
+{
+ sljit_s32 reg2 = 0;
+ sljit_ins inst = FS(freg);
+ sljit_ins mthc = MTC1, mfhc = MFC1;
+ int is_32 = (op & SLJIT_32);
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+ op = GET_OPCODE(op);
+ if (reg & REG_PAIR_MASK) {
+ reg2 = REG_PAIR_SECOND(reg);
+ reg = REG_PAIR_FIRST(reg);
+
+ inst |= T(reg2);
+
+ if (op == SLJIT_COPY_TO_F64)
+ FAIL_IF(push_inst(compiler, MTC1 | inst, MOVABLE_INS));
+ else
+ FAIL_IF(push_inst(compiler, MFC1 | inst, DR(reg2)));
+
+ inst = FS(freg) | (1 << 11);
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
+ if (cpu_feature_list & CPU_FEATURE_FR) {
+ mthc = MTHC1;
+ mfhc = MFHC1;
+ inst = FS(freg);
+ }
+#endif /* SLJIT_MIPS_REV >= 2 */
+ }
+
+ inst |= T(reg);
+ if (!is_32 && !reg2) {
+ switch (cpu_feature_list & CPU_FEATURE_FR) {
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
+ case CPU_FEATURE_FR:
+ mthc = MTHC1;
+ mfhc = MFHC1;
+ break;
+#endif /* SLJIT_MIPS_REV >= 2 */
+ default:
+ inst |= (1 << 11);
+ break;
+ }
+ }
+
+ if (op == SLJIT_COPY_TO_F64)
+ FAIL_IF(push_inst(compiler, mthc | inst, MOVABLE_INS));
+ else
+ FAIL_IF(push_inst(compiler, mfhc | inst, DR(reg)));
+
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
+ if (mthc == MTC1 || mfhc == MFC1)
+ return push_inst(compiler, NOP, UNMOVABLE_INS);
+#endif /* MIPS III */
+ return SLJIT_SUCCESS;
+}
+
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
{
sljit_ins *inst = (sljit_ins *)addr;
@@ -74,6 +219,11 @@ static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_t
sljit_ins ins = NOP;
sljit_u8 offsets[4];
sljit_u8 *offsets_ptr = offsets;
+#if defined(SLJIT_LITTLE_ENDIAN) && SLJIT_LITTLE_ENDIAN
+ sljit_ins f64_hi = TA(7), f64_lo = TA(6);
+#else
+ sljit_ins f64_hi = TA(6), f64_lo = TA(7);
+#endif /* SLJIT_LITTLE_ENDIAN */
SLJIT_ASSERT(reg_map[TMP_REG1] == 4 && freg_map[TMP_FREG1] == 12);
@@ -138,20 +288,28 @@ static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_t
switch (types & SLJIT_ARG_MASK) {
case SLJIT_ARG_TYPE_F64:
- if (*offsets_ptr < 4 * sizeof (sljit_sw)) {
+ if (*offsets_ptr < 4 * sizeof(sljit_sw)) {
if (prev_ins != NOP)
FAIL_IF(push_inst(compiler, prev_ins, MOVABLE_INS));
/* Must be preceded by at least one other argument,
* and its starting offset must be 8 because of alignment. */
SLJIT_ASSERT((*offsets_ptr >> 2) == 2);
-
- prev_ins = MFC1 | TA(6) | FS(float_arg_count) | (1 << 11);
- ins = MFC1 | TA(7) | FS(float_arg_count);
+ switch (cpu_feature_list & CPU_FEATURE_FR) {
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
+ case CPU_FEATURE_FR:
+ prev_ins = MFHC1 | f64_hi | FS(float_arg_count);
+ break;
+#endif /* SLJIT_MIPS_REV >= 2 */
+ default:
+ prev_ins = MFC1 | f64_hi | FS(float_arg_count) | (1 << 11);
+ break;
+ }
+ ins = MFC1 | f64_lo | FS(float_arg_count);
} else if (*offsets_ptr < 254)
ins = SDC1 | S(SLJIT_SP) | FT(float_arg_count) | IMM(*offsets_ptr);
else if (*offsets_ptr == 254)
- ins = MOV_S | FMT_D | FS(SLJIT_FR0) | FD(TMP_FREG1);
+ ins = MOV_fmt(FMT_D) | FS(SLJIT_FR0) | FD(TMP_FREG1);
float_arg_count--;
break;
@@ -161,7 +319,7 @@ static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_t
else if (*offsets_ptr < 254)
ins = SWC1 | S(SLJIT_SP) | FT(float_arg_count) | IMM(*offsets_ptr);
else if (*offsets_ptr == 254)
- ins = MOV_S | FMT_S | FS(SLJIT_FR0) | FD(TMP_FREG1);
+ ins = MOV_fmt(FMT_S) | FS(SLJIT_FR0) | FD(TMP_FREG1);
float_arg_count--;
break;
@@ -285,7 +443,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compi
SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2);
- if (src & SLJIT_IMM)
+ if (src == SLJIT_IMM)
FAIL_IF(load_immediate(compiler, DR(PIC_ADDR_REG), srcw));
else if (src != PIC_ADDR_REG)
FAIL_IF(push_inst(compiler, ADDU | S(src) | TA(0) | D(PIC_ADDR_REG), DR(PIC_ADDR_REG)));
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_64.c b/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_64.c
index d2a5924f8e..52a0d3fb7a 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_64.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_64.c
@@ -26,6 +26,23 @@
/* mips 64-bit arch dependent functions. */
+static sljit_s32 emit_copysign(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src1, sljit_s32 src2, sljit_s32 dst)
+{
+ FAIL_IF(push_inst(compiler, SELECT_OP(DMFC1, MFC1) | T(TMP_REG1) | FS(src1), DR(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, SELECT_OP(DMFC1, MFC1) | T(TMP_REG2) | FS(src2), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, XOR | S(TMP_REG2) | T(TMP_REG1) | D(TMP_REG2), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, SELECT_OP(DSRL32, SRL) | T(TMP_REG2) | D(TMP_REG2) | SH_IMM(31), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, SELECT_OP(DSLL32, SLL) | T(TMP_REG2) | D(TMP_REG2) | SH_IMM(31), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | T(TMP_REG2) | D(TMP_REG1), DR(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, SELECT_OP(DMTC1, MTC1) | T(TMP_REG1) | FS(dst), MOVABLE_INS));
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
+ if (!(op & SLJIT_32))
+ return push_inst(compiler, NOP, UNMOVABLE_INS);
+#endif /* MIPS III */
+ return SLJIT_SUCCESS;
+}
+
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_ar, sljit_sw imm)
{
sljit_s32 shift = 32;
@@ -128,6 +145,57 @@ static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_
return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
}
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f64 value)
+{
+ union {
+ sljit_sw imm;
+ sljit_f64 value;
+ } u;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fset64(compiler, freg, value));
+
+ u.value = value;
+
+ if (u.imm == 0) {
+ FAIL_IF(push_inst(compiler, DMTC1 | TA(0) | FS(freg), MOVABLE_INS));
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
+ FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+#endif /* MIPS III */
+ return SLJIT_SUCCESS;
+ }
+
+ FAIL_IF(load_immediate(compiler, DR(TMP_REG1), u.imm));
+ FAIL_IF(push_inst(compiler, DMTC1 | T(TMP_REG1) | FS(freg), MOVABLE_INS));
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
+ FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+#endif /* MIPS III */
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 freg, sljit_s32 reg)
+{
+ sljit_ins inst;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+ inst = T(reg) | FS(freg);
+
+ if (GET_OPCODE(op) == SLJIT_COPY_TO_F64)
+ FAIL_IF(push_inst(compiler, SELECT_OP(DMTC1, MTC1) | inst, MOVABLE_INS));
+ else
+ FAIL_IF(push_inst(compiler, SELECT_OP(DMFC1, MFC1) | inst, DR(reg)));
+
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
+ if (!(op & SLJIT_32))
+ return push_inst(compiler, NOP, UNMOVABLE_INS);
+#endif /* MIPS III */
+ return SLJIT_SUCCESS;
+}
+
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
{
sljit_ins *inst = (sljit_ins *)addr;
@@ -183,17 +251,17 @@ static sljit_s32 call_with_args(struct sljit_compiler *compiler, sljit_s32 arg_t
switch (types & SLJIT_ARG_MASK) {
case SLJIT_ARG_TYPE_F64:
if (arg_count != float_arg_count)
- ins = MOV_S | FMT_D | FS(float_arg_count) | FD(arg_count);
+ ins = MOV_fmt(FMT_D) | FS(float_arg_count) | FD(arg_count);
else if (arg_count == 1)
- ins = MOV_S | FMT_D | FS(SLJIT_FR0) | FD(TMP_FREG1);
+ ins = MOV_fmt(FMT_D) | FS(SLJIT_FR0) | FD(TMP_FREG1);
arg_count--;
float_arg_count--;
break;
case SLJIT_ARG_TYPE_F32:
if (arg_count != float_arg_count)
- ins = MOV_S | FMT_S | FS(float_arg_count) | FD(arg_count);
+ ins = MOV_fmt(FMT_S) | FS(float_arg_count) | FD(arg_count);
else if (arg_count == 1)
- ins = MOV_S | FMT_S | FS(SLJIT_FR0) | FD(TMP_FREG1);
+ ins = MOV_fmt(FMT_S) | FS(SLJIT_FR0) | FD(TMP_FREG1);
arg_count--;
float_arg_count--;
break;
@@ -300,7 +368,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compi
SLJIT_ASSERT(DR(PIC_ADDR_REG) == 25 && PIC_ADDR_REG == TMP_REG2);
- if (src & SLJIT_IMM)
+ if (src == SLJIT_IMM)
FAIL_IF(load_immediate(compiler, DR(PIC_ADDR_REG), srcw));
else if (src != PIC_ADDR_REG)
FAIL_IF(push_inst(compiler, DADDU | S(src) | TA(0) | D(PIC_ADDR_REG), DR(PIC_ADDR_REG)));
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_common.c b/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_common.c
index 9afe901c38..807b3474ea 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_common.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeMIPS_common.c
@@ -26,9 +26,12 @@
/* Latest MIPS architecture. */
-#ifndef __mips_hard_float
+#ifdef HAVE_PRCTL
+#include <sys/prctl.h>
+#endif
+
+#if !defined(__mips_hard_float) || defined(__mips_single_float)
/* Disable automatic detection, covers both -msoft-float and -mno-float */
-#undef SLJIT_IS_FPU_AVAILABLE
#define SLJIT_IS_FPU_AVAILABLE 0
#endif
@@ -42,6 +45,14 @@ SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
return "MIPS64-R6" SLJIT_CPUINFO;
#endif /* SLJIT_CONFIG_MIPS_32 */
+#elif (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 5)
+
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+ return "MIPS32-R5" SLJIT_CPUINFO;
+#else /* !SLJIT_CONFIG_MIPS_32 */
+ return "MIPS64-R5" SLJIT_CPUINFO;
+#endif /* SLJIT_CONFIG_MIPS_32 */
+
#elif (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 2)
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
@@ -83,27 +94,31 @@ typedef sljit_u32 sljit_ins;
#define EQUAL_FLAG 3
#define OTHER_FLAG 1
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 7] = {
+ 0, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 24, 23, 22, 21, 20, 19, 18, 17, 16, 29, 4, 25, 31, 3, 1
+};
+
#define TMP_FREG1 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
#define TMP_FREG2 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2)
#define TMP_FREG3 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3)
-static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 5] = {
- 0, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 24, 23, 22, 21, 20, 19, 18, 17, 16, 29, 4, 25, 31
-};
-
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
-static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 4] = {
- 0, 0, 14, 2, 4, 6, 8, 18, 30, 28, 26, 24, 22, 20, 12, 10, 16
+static const sljit_u8 freg_map[((SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3) << 1) + 1] = {
+ 0,
+ 0, 14, 2, 4, 6, 8, 18, 30, 28, 26, 24, 22, 20,
+ 12, 10, 16,
+ 1, 15, 3, 5, 7, 9, 19, 31, 29, 27, 25, 23, 21,
+ 13, 11, 17
};
-#else
+#else /* !SLJIT_CONFIG_MIPS_32 */
static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 4] = {
0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 1, 2, 3, 4, 5, 6, 7, 8, 9, 31, 30, 29, 28, 27, 26, 25, 24, 12, 11, 10
};
-#endif
+#endif /* SLJIT_CONFIG_MIPS_32 */
/* --------------------------------------------------------------------- */
/* Instrucion forms */
@@ -200,10 +215,18 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 4] = {
#define DMULTU (HI(0) | LO(29))
#endif /* SLJIT_MIPS_REV >= 6 */
#define DIV_S (HI(17) | FMT_S | LO(3))
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
#define DINSU (HI(31) | LO(6))
+#endif /* SLJIT_MIPS_REV >= 2 */
+#define DMFC1 (HI(17) | (1 << 21))
+#define DMTC1 (HI(17) | (5 << 21))
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
#define DROTR (HI(0) | (1 << 21) | LO(58))
#define DROTR32 (HI(0) | (1 << 21) | LO(62))
#define DROTRV (HI(0) | (1 << 6) | LO(22))
+#define DSBH (HI(31) | (2 << 6) | LO(36))
+#define DSHD (HI(31) | (5 << 6) | LO(36))
+#endif /* SLJIT_MIPS_REV >= 2 */
#define DSLL (HI(0) | LO(56))
#define DSLL32 (HI(0) | LO(60))
#define DSLLV (HI(0) | LO(20))
@@ -232,6 +255,9 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 4] = {
#define LWR (HI(38))
#define LWC1 (HI(49))
#define MFC1 (HI(17))
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
+#define MFHC1 (HI(17) | (3 << 21))
+#endif /* SLJIT_MIPS_REV >= 2 */
#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
#define MOD (HI(0) | (3 << 6) | LO(26))
#define MODU (HI(0) | (3 << 6) | LO(27))
@@ -239,8 +265,10 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 4] = {
#define MFHI (HI(0) | LO(16))
#define MFLO (HI(0) | LO(18))
#endif /* SLJIT_MIPS_REV >= 6 */
-#define MOV_S (HI(17) | FMT_S | LO(6))
#define MTC1 (HI(17) | (4 << 21))
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
+#define MTHC1 (HI(17) | (7 << 21))
+#endif /* SLJIT_MIPS_REV >= 2 */
#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 6)
#define MUH (HI(0) | (3 << 6) | LO(24))
#define MUHU (HI(0) | (3 << 6) | LO(25))
@@ -256,8 +284,10 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 4] = {
#define NOR (HI(0) | LO(39))
#define OR (HI(0) | LO(37))
#define ORI (HI(13))
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
#define ROTR (HI(0) | (1 << 21) | LO(2))
#define ROTRV (HI(0) | (1 << 6) | LO(6))
+#endif /* SLJIT_MIPS_REV >= 2 */
#define SD (HI(63))
#define SDL (HI(44))
#define SDR (HI(45))
@@ -279,6 +309,9 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 4] = {
#define SWR (HI(46))
#define SWC1 (HI(57))
#define TRUNC_W_S (HI(17) | FMT_S | LO(13))
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
+#define WSBH (HI(31) | (2 << 6) | LO(32))
+#endif /* SLJIT_MIPS_REV >= 2 */
#define XOR (HI(0) | LO(38))
#define XORI (HI(14))
@@ -289,15 +322,21 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 4] = {
#else /* SLJIT_MIPS_REV < 6 */
#define DCLZ (HI(28) | LO(36))
#define MOVF (HI(0) | (0 << 16) | LO(1))
+#define MOVF_S (HI(17) | FMT_S | (0 << 16) | LO(17))
#define MOVN (HI(0) | LO(11))
+#define MOVN_S (HI(17) | FMT_S | LO(19))
#define MOVT (HI(0) | (1 << 16) | LO(1))
+#define MOVT_S (HI(17) | FMT_S | (1 << 16) | LO(17))
#define MOVZ (HI(0) | LO(10))
+#define MOVZ_S (HI(17) | FMT_S | LO(18))
#define MUL (HI(28) | LO(2))
#endif /* SLJIT_MIPS_REV >= 6 */
#define PREF (HI(51))
#define PREFX (HI(19) | LO(15))
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
#define SEB (HI(31) | (16 << 6) | LO(32))
#define SEH (HI(31) | (24 << 6) | LO(32))
+#endif /* SLJIT_MIPS_REV >= 2 */
#endif /* SLJIT_MIPS_REV >= 1 */
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
@@ -318,10 +357,107 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 4] = {
#define LOAD_W LD
#endif
+#define MOV_fmt(f) (HI(17) | f | LO(6))
+
#define SIMM_MAX (0x7fff)
#define SIMM_MIN (-0x8000)
#define UIMM_MAX (0xffff)
+#define CPU_FEATURE_DETECTED (1 << 0)
+#define CPU_FEATURE_FPU (1 << 1)
+#define CPU_FEATURE_FP64 (1 << 2)
+#define CPU_FEATURE_FR (1 << 3)
+
+static sljit_u32 cpu_feature_list = 0;
+
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
+ && (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
+
+static sljit_s32 function_check_is_freg(struct sljit_compiler *compiler, sljit_s32 fr, sljit_s32 is_32)
+{
+ if (compiler->scratches == -1)
+ return 0;
+
+ if (is_32 && fr >= SLJIT_F64_SECOND(SLJIT_FR0))
+ fr -= SLJIT_F64_SECOND(0);
+
+ return (fr >= SLJIT_FR0 && fr < (SLJIT_FR0 + compiler->fscratches))
+ || (fr > (SLJIT_FS0 - compiler->fsaveds) && fr <= SLJIT_FS0)
+ || (fr >= SLJIT_TMP_FREGISTER_BASE && fr < (SLJIT_TMP_FREGISTER_BASE + SLJIT_NUMBER_OF_TEMPORARY_FLOAT_REGISTERS));
+}
+
+#endif /* SLJIT_CONFIG_MIPS_32 && SLJIT_ARGUMENT_CHECKS */
+
+static void get_cpu_features(void)
+{
+#if !defined(SLJIT_IS_FPU_AVAILABLE) && defined(__GNUC__)
+ sljit_u32 fir = 0;
+#endif /* !SLJIT_IS_FPU_AVAILABLE && __GNUC__ */
+ sljit_u32 feature_list = CPU_FEATURE_DETECTED;
+
+#if defined(SLJIT_IS_FPU_AVAILABLE)
+#if SLJIT_IS_FPU_AVAILABLE
+ feature_list |= CPU_FEATURE_FPU;
+#if SLJIT_IS_FPU_AVAILABLE == 64
+ feature_list |= CPU_FEATURE_FP64;
+#endif /* SLJIT_IS_FPU_AVAILABLE == 64 */
+#endif /* SLJIT_IS_FPU_AVAILABLE */
+#elif defined(__GNUC__)
+ __asm__ ("cfc1 %0, $0" : "=r"(fir));
+ if ((fir & (0x3 << 16)) == (0x3 << 16))
+ feature_list |= CPU_FEATURE_FPU;
+
+#if (defined(SLJIT_CONFIG_MIPS_64) && SLJIT_CONFIG_MIPS_64) \
+ && (!defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV < 2)
+ if ((feature_list & CPU_FEATURE_FPU))
+ feature_list |= CPU_FEATURE_FP64;
+#else /* SLJIT_CONFIG_MIPS32 || SLJIT_MIPS_REV >= 2 */
+ if ((fir & (1 << 22)))
+ feature_list |= CPU_FEATURE_FP64;
+#endif /* SLJIT_CONFIG_MIPS_64 && SLJIT_MIPS_REV < 2 */
+#endif /* SLJIT_IS_FPU_AVAILABLE */
+
+ if ((feature_list & CPU_FEATURE_FPU) && (feature_list & CPU_FEATURE_FP64)) {
+#if defined(SLJIT_CONFIG_MIPS_32) && SLJIT_CONFIG_MIPS_32
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 6
+ feature_list |= CPU_FEATURE_FR;
+#elif defined(SLJIT_DETECT_FR) && SLJIT_DETECT_FR == 0
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 5
+ feature_list |= CPU_FEATURE_FR;
+#endif /* SLJIT_MIPS_REV >= 5 */
+#else
+ sljit_s32 flag = -1;
+#ifndef FR_GET_FP_MODE
+ sljit_f64 zero = 0.0;
+#else /* PR_GET_FP_MODE */
+ flag = prctl(PR_GET_FP_MODE);
+
+ if (flag > 0)
+ feature_list |= CPU_FEATURE_FR;
+#endif /* FP_GET_PR_MODE */
+#if ((defined(SLJIT_DETECT_FR) && SLJIT_DETECT_FR == 2) \
+ || (!defined(PR_GET_FP_MODE) && (!defined(SLJIT_DETECT_FR) || SLJIT_DETECT_FR >= 1))) \
+ && (defined(__GNUC__) && (defined(__mips) && __mips >= 2))
+ if (flag < 0) {
+ __asm__ (".set oddspreg\n"
+ "lwc1 $f17, %0\n"
+ "ldc1 $f16, %1\n"
+ "swc1 $f17, %0\n"
+ : "+m" (flag) : "m" (zero) : "$f16", "$f17");
+ if (flag)
+ feature_list |= CPU_FEATURE_FR;
+ }
+#endif /* (!PR_GET_FP_MODE || (PR_GET_FP_MODE && SLJIT_DETECT_FR == 2)) && __GNUC__ */
+#endif /* SLJIT_MIPS_REV >= 6 */
+#else /* !SLJIT_CONFIG_MIPS_32 */
+ /* StatusFR=1 is the only mode supported by the code in MIPS64 */
+ feature_list |= CPU_FEATURE_FR;
+#endif /* SLJIT_CONFIG_MIPS_32 */
+ }
+
+ cpu_feature_list = feature_list;
+}
+
/* dest_reg is the absolute name of the register
Useful for reordering instructions in the delay slot. */
static sljit_s32 push_inst(struct sljit_compiler *compiler, sljit_ins ins, sljit_s32 delay_slot)
@@ -715,21 +851,23 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
{
-#if defined(__GNUC__) && !defined(SLJIT_IS_FPU_AVAILABLE)
- sljit_sw fir = 0;
-#endif /* __GNUC__ && !SLJIT_IS_FPU_AVAILABLE */
-
switch (feature_type) {
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
+ && (!defined(SLJIT_IS_FPU_AVAILABLE) || SLJIT_IS_FPU_AVAILABLE)
+ case SLJIT_HAS_F64_AS_F32_PAIR:
+ if (!cpu_feature_list)
+ get_cpu_features();
+
+ return (cpu_feature_list & CPU_FEATURE_FR) != 0;
+#endif /* SLJIT_CONFIG_MIPS_32 && SLJIT_IS_FPU_AVAILABLE */
case SLJIT_HAS_FPU:
-#ifdef SLJIT_IS_FPU_AVAILABLE
- return SLJIT_IS_FPU_AVAILABLE;
-#elif defined(__GNUC__)
- __asm__ ("cfc1 %0, $0" : "=r"(fir));
- return (fir >> 22) & 0x1;
-#else
-#error "FIR check is not implemented for this architecture"
-#endif
+ if (!cpu_feature_list)
+ get_cpu_features();
+
+ return (cpu_feature_list & CPU_FEATURE_FPU) != 0;
case SLJIT_HAS_ZERO_REGISTER:
+ case SLJIT_HAS_COPY_F32:
+ case SLJIT_HAS_COPY_F64:
return 1;
#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
case SLJIT_HAS_CLZ:
@@ -741,6 +879,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
return 2;
#endif /* SLJIT_MIPS_REV >= 1 */
#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 2)
+ case SLJIT_HAS_REV:
case SLJIT_HAS_ROT:
return 1;
#endif /* SLJIT_MIPS_REV >= 2 */
@@ -751,7 +890,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type)
{
- return (type >= SLJIT_ORDERED_EQUAL && type <= SLJIT_ORDERED_LESS_EQUAL);
+ SLJIT_UNUSED_ARG(type);
+ return 0;
}
/* --------------------------------------------------------------------- */
@@ -792,6 +932,12 @@ static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 flags, s
static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit_s32 frame_size, sljit_ins *ins_ptr);
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
+#define SELECT_OP(a, b) (b)
+#else
+#define SELECT_OP(a, b) (!(op & SLJIT_32) ? a : b)
+#endif
+
+#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
#include "sljitNativeMIPS_32.c"
#else
#include "sljitNativeMIPS_64.c"
@@ -815,12 +961,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
if (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) {
if ((local_size & SSIZE_OF(sw)) != 0)
local_size += SSIZE_OF(sw);
- local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64));
+ local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
}
local_size = (local_size + SLJIT_LOCALS_OFFSET + 15) & ~0xf;
#else
- local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64));
+ local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
local_size = (local_size + SLJIT_LOCALS_OFFSET + 31) & ~0x1f;
#endif
compiler->local_size = local_size;
@@ -918,10 +1064,19 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
if (word_arg_count == 0 && float_arg_count <= 2) {
if (float_arg_count == 1)
- FAIL_IF(push_inst(compiler, MOV_S | FMT_D | FS(TMP_FREG1) | FD(SLJIT_FR0), MOVABLE_INS));
+ FAIL_IF(push_inst(compiler, MOV_fmt(FMT_D) | FS(TMP_FREG1) | FD(SLJIT_FR0), MOVABLE_INS));
} else if (arg_count < 4) {
FAIL_IF(push_inst(compiler, MTC1 | TA(4 + arg_count) | FS(float_arg_count), MOVABLE_INS));
- FAIL_IF(push_inst(compiler, MTC1 | TA(5 + arg_count) | FS(float_arg_count) | (1 << 11), MOVABLE_INS));
+ switch (cpu_feature_list & CPU_FEATURE_FR) {
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
+ case CPU_FEATURE_FR:
+ FAIL_IF(push_inst(compiler, MTHC1 | TA(5 + arg_count) | FS(float_arg_count), MOVABLE_INS));
+ break;
+#endif /* SLJIT_MIPS_REV >= 2 */
+ default:
+ FAIL_IF(push_inst(compiler, MTC1 | TA(5 + arg_count) | FS(float_arg_count) | (1 << 11), MOVABLE_INS));
+ break;
+ }
} else
FAIL_IF(push_inst(compiler, LDC1 | base | FT(float_arg_count) | IMM(local_size + (arg_count << 2)), MOVABLE_INS));
arg_count++;
@@ -931,7 +1086,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
if (word_arg_count == 0 && float_arg_count <= 2) {
if (float_arg_count == 1)
- FAIL_IF(push_inst(compiler, MOV_S | FMT_S | FS(TMP_FREG1) | FD(SLJIT_FR0), MOVABLE_INS));
+ FAIL_IF(push_inst(compiler, MOV_fmt(FMT_S) | FS(TMP_FREG1) | FD(SLJIT_FR0), MOVABLE_INS));
} else if (arg_count < 4)
FAIL_IF(push_inst(compiler, MTC1 | TA(4 + arg_count) | FS(float_arg_count), MOVABLE_INS));
else
@@ -966,16 +1121,16 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
case SLJIT_ARG_TYPE_F64:
float_arg_count++;
if (arg_count != float_arg_count)
- FAIL_IF(push_inst(compiler, MOV_S | FMT_D | FS(arg_count) | FD(float_arg_count), MOVABLE_INS));
+ FAIL_IF(push_inst(compiler, MOV_fmt(FMT_D) | FS(arg_count) | FD(float_arg_count), MOVABLE_INS));
else if (arg_count == 1)
- FAIL_IF(push_inst(compiler, MOV_S | FMT_D | FS(TMP_FREG1) | FD(SLJIT_FR0), MOVABLE_INS));
+ FAIL_IF(push_inst(compiler, MOV_fmt(FMT_D) | FS(TMP_FREG1) | FD(SLJIT_FR0), MOVABLE_INS));
break;
case SLJIT_ARG_TYPE_F32:
float_arg_count++;
if (arg_count != float_arg_count)
- FAIL_IF(push_inst(compiler, MOV_S | FMT_S | FS(arg_count) | FD(float_arg_count), MOVABLE_INS));
+ FAIL_IF(push_inst(compiler, MOV_fmt(FMT_S) | FS(arg_count) | FD(float_arg_count), MOVABLE_INS));
else if (arg_count == 1)
- FAIL_IF(push_inst(compiler, MOV_S | FMT_S | FS(TMP_FREG1) | FD(SLJIT_FR0), MOVABLE_INS));
+ FAIL_IF(push_inst(compiler, MOV_fmt(FMT_S) | FS(TMP_FREG1) | FD(SLJIT_FR0), MOVABLE_INS));
break;
default:
word_arg_count++;
@@ -1011,12 +1166,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *comp
if (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) {
if ((local_size & SSIZE_OF(sw)) != 0)
local_size += SSIZE_OF(sw);
- local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64));
+ local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
}
compiler->local_size = (local_size + SLJIT_LOCALS_OFFSET + 15) & ~0xf;
#else
- local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64));
+ local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
compiler->local_size = (local_size + SLJIT_LOCALS_OFFSET + 31) & ~0x1f;
#endif
return SLJIT_SUCCESS;
@@ -1042,10 +1197,10 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit
if (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) {
if ((tmp & SSIZE_OF(sw)) != 0)
tmp += SSIZE_OF(sw);
- tmp += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64));
+ tmp += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
}
#else
- tmp += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64));
+ tmp += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
#endif
if (local_size <= SIMM_MAX) {
@@ -1138,7 +1293,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *c
FAIL_IF(emit_stack_frame_release(compiler, 1, &ins));
- if (!(src & SLJIT_IMM)) {
+ if (src != SLJIT_IMM) {
FAIL_IF(push_inst(compiler, JR | S(src), UNMOVABLE_INS));
return push_inst(compiler, ins, UNMOVABLE_INS);
}
@@ -1388,16 +1543,12 @@ static SLJIT_INLINE sljit_s32 emit_op_mem2(struct sljit_compiler *compiler, slji
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
-#define SELECT_OP(a, b) (b)
-
#define EMIT_SHIFT(dimm, dimm32, imm, dv, v) \
op_imm = (imm); \
op_v = (v);
#else /* !SLJIT_CONFIG_MIPS_32 */
-#define SELECT_OP(a, b) \
- (!(op & SLJIT_32) ? a : b)
#define EMIT_SHIFT(dimm, dimm32, imm, dv, v) \
op_dimm = (dimm); \
@@ -1414,10 +1565,10 @@ static sljit_s32 emit_clz_ctz(struct sljit_compiler *compiler, sljit_s32 op, slj
{
sljit_s32 is_clz = (GET_OPCODE(op) == SLJIT_CLZ);
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
- sljit_ins max = (op & SLJIT_32) ? 32 : 64;
-#else /* !SLJIT_CONFIG_RISCV_64 */
- sljit_ins max = 32;
-#endif /* SLJIT_CONFIG_RISCV_64 */
+ sljit_ins word_size = (op & SLJIT_32) ? 32 : 64;
+#else /* !SLJIT_CONFIG_MIPS_64 */
+ sljit_ins word_size = 32;
+#endif /* SLJIT_CONFIG_MIPS_64 */
/* The TMP_REG2 is the next value. */
if (src != TMP_REG2)
@@ -1425,7 +1576,7 @@ static sljit_s32 emit_clz_ctz(struct sljit_compiler *compiler, sljit_s32 op, slj
FAIL_IF(push_inst(compiler, BEQ | S(TMP_REG2) | TA(0) | IMM(is_clz ? 13 : 14), UNMOVABLE_INS));
/* The OTHER_FLAG is the counter. Delay slot. */
- FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(OTHER_FLAG) | IMM(max), OTHER_FLAG));
+ FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(OTHER_FLAG) | IMM(word_size), OTHER_FLAG));
if (!is_clz) {
FAIL_IF(push_inst(compiler, ANDI | S(TMP_REG2) | T(TMP_REG1) | IMM(1), DR(TMP_REG1)));
@@ -1437,7 +1588,7 @@ static sljit_s32 emit_clz_ctz(struct sljit_compiler *compiler, sljit_s32 op, slj
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(OTHER_FLAG) | IMM(0), OTHER_FLAG));
/* The TMP_REG1 is the next shift. */
- FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | T(TMP_REG1) | IMM(max), DR(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | T(TMP_REG1) | IMM(word_size), DR(TMP_REG1)));
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(TMP_REG2) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG));
FAIL_IF(push_inst(compiler, SELECT_OP(DSRL, SRL) | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(1), DR(TMP_REG1)));
@@ -1459,6 +1610,104 @@ static sljit_s32 emit_clz_ctz(struct sljit_compiler *compiler, sljit_s32 op, slj
#endif /* SLJIT_MIPS_REV < 1 */
+static sljit_s32 emit_rev(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst, sljit_sw src)
+{
+#if defined(SLJIT_CONFIG_MIPS_64) && SLJIT_CONFIG_MIPS_64
+ int is_32 = (op & SLJIT_32);
+#endif /* SLJIT_CONFIG_MIPS_64 */
+
+ op = GET_OPCODE(op);
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
+#if defined(SLJIT_CONFIG_MIPS_64) && SLJIT_CONFIG_MIPS_64
+ if (!is_32 && (op == SLJIT_REV)) {
+ FAIL_IF(push_inst(compiler, DSBH | T(src) | D(dst), DR(dst)));
+ return push_inst(compiler, DSHD | T(dst) | D(dst), DR(dst));
+ }
+ if (op != SLJIT_REV && src != TMP_REG2) {
+ FAIL_IF(push_inst(compiler, SLL | T(src) | D(TMP_REG1), DR(TMP_REG1)));
+ src = TMP_REG1;
+ }
+#endif /* SLJIT_CONFIG_MIPS_64 */
+ FAIL_IF(push_inst(compiler, WSBH | T(src) | D(dst), DR(dst)));
+ FAIL_IF(push_inst(compiler, ROTR | T(dst) | D(dst) | SH_IMM(16), DR(dst)));
+#if defined(SLJIT_CONFIG_MIPS_64) && SLJIT_CONFIG_MIPS_64
+ if (op == SLJIT_REV_U32 && dst != TMP_REG2 && dst != TMP_REG3)
+ FAIL_IF(push_inst(compiler, DINSU | T(dst) | SA(0) | (31 << 11), DR(dst)));
+#endif /* SLJIT_CONFIG_MIPS_64 */
+#else /* SLJIT_MIPS_REV < 2 */
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+ if (!is_32) {
+ FAIL_IF(push_inst(compiler, DSRL32 | T(src) | D(TMP_REG1) | SH_IMM(0), DR(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, ORI | SA(0) | TA(OTHER_FLAG) | 0xffff, OTHER_FLAG));
+ FAIL_IF(push_inst(compiler, DSLL32 | T(src) | D(dst) | SH_IMM(0), DR(dst)));
+ FAIL_IF(push_inst(compiler, DSLL32 | TA(OTHER_FLAG) | DA(OTHER_FLAG) | SH_IMM(0), OTHER_FLAG));
+ FAIL_IF(push_inst(compiler, OR | S(dst) | T(TMP_REG1) | D(dst), DR(dst)));
+
+ FAIL_IF(push_inst(compiler, DSRL | T(dst) | D(TMP_REG1) | SH_IMM(16), DR(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, ORI | SA(OTHER_FLAG) | TA(OTHER_FLAG) | 0xffff, OTHER_FLAG));
+ FAIL_IF(push_inst(compiler, AND | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
+ FAIL_IF(push_inst(compiler, AND | S(TMP_REG1) | TA(OTHER_FLAG) | D(TMP_REG1), DR(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, DSLL | TA(OTHER_FLAG) | DA(EQUAL_FLAG) | SH_IMM(8), EQUAL_FLAG));
+ FAIL_IF(push_inst(compiler, DSLL | T(dst) | D(dst) | SH_IMM(16), DR(dst)));
+ FAIL_IF(push_inst(compiler, XOR | SA(OTHER_FLAG) | TA(EQUAL_FLAG) | DA(OTHER_FLAG), OTHER_FLAG));
+ FAIL_IF(push_inst(compiler, OR | S(dst) | T(TMP_REG1) | D(dst), DR(dst)));
+
+ FAIL_IF(push_inst(compiler, DSRL | T(dst) | D(TMP_REG1) | SH_IMM(8), DR(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, AND | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
+ FAIL_IF(push_inst(compiler, AND | S(TMP_REG1) | TA(OTHER_FLAG) | D(TMP_REG1), DR(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, DSLL | T(dst) | D(dst) | SH_IMM(8), DR(dst)));
+ return push_inst(compiler, OR | S(dst) | T(TMP_REG1) | D(dst), DR(dst));
+ }
+
+ if (op != SLJIT_REV && src != TMP_REG2) {
+ FAIL_IF(push_inst(compiler, SLL | T(src) | D(TMP_REG2) | SH_IMM(0), DR(TMP_REG2)));
+ src = TMP_REG2;
+ }
+#endif /* SLJIT_CONFIG_MIPS_64 */
+
+ FAIL_IF(push_inst(compiler, SRL | T(src) | D(TMP_REG1) | SH_IMM(16), DR(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, LUI | TA(OTHER_FLAG) | 0xff, OTHER_FLAG));
+ FAIL_IF(push_inst(compiler, SLL | T(src) | D(dst) | SH_IMM(16), DR(dst)));
+ FAIL_IF(push_inst(compiler, ORI | SA(OTHER_FLAG) | TA(OTHER_FLAG) | 0xff, OTHER_FLAG));
+ FAIL_IF(push_inst(compiler, OR | S(dst) | T(TMP_REG1) | D(dst), DR(dst)));
+
+ FAIL_IF(push_inst(compiler, SRL | T(dst) | D(TMP_REG1) | SH_IMM(8), DR(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, AND | S(dst) | TA(OTHER_FLAG) | D(dst), DR(dst)));
+ FAIL_IF(push_inst(compiler, AND | S(TMP_REG1) | TA(OTHER_FLAG) | D(TMP_REG1), DR(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, SLL | T(dst) | D(dst) | SH_IMM(8), DR(dst)));
+ FAIL_IF(push_inst(compiler, OR | S(dst) | T(TMP_REG1) | D(dst), DR(dst)));
+
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+ if (op == SLJIT_REV_U32 && dst != TMP_REG2 && dst != TMP_REG3) {
+ FAIL_IF(push_inst(compiler, DSLL32 | T(dst) | D(dst) | SH_IMM(0), DR(dst)));
+ FAIL_IF(push_inst(compiler, DSRL32 | T(dst) | D(dst) | SH_IMM(0), DR(dst)));
+ }
+#endif /* SLJIT_CONFIG_MIPS_64 */
+#endif /* SLJIT_MIPR_REV >= 2 */
+ return SLJIT_SUCCESS;
+}
+
+static sljit_s32 emit_rev16(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst, sljit_sw src)
+{
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
+#if defined(SLJIT_CONFIG_MIPS_32) && SLJIT_CONFIG_MIPS_32
+ FAIL_IF(push_inst(compiler, WSBH | T(src) | D(dst), DR(dst)));
+#else /* !SLJIT_CONFIG_MIPS_32 */
+ FAIL_IF(push_inst(compiler, DSBH | T(src) | D(dst), DR(dst)));
+#endif /* SLJIT_CONFIG_MIPS_32 */
+ if (GET_OPCODE(op) == SLJIT_REV_U16)
+ return push_inst(compiler, ANDI | S(dst) | T(dst) | 0xffff, DR(dst));
+ else
+ return push_inst(compiler, SEH | T(dst) | D(dst), DR(dst));
+#else /* SLJIT_MIPS_REV < 2 */
+ FAIL_IF(push_inst(compiler, SELECT_OP(DSRL, SRL) | T(src) | D(TMP_REG1) | SH_IMM(8), DR(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, SELECT_OP(DSLL32, SLL) | T(src) | D(dst) | SH_IMM(24), DR(dst)));
+ FAIL_IF(push_inst(compiler, ANDI | S(TMP_REG1) | T(TMP_REG1) | 0xff, DR(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, (GET_OPCODE(op) == SLJIT_REV_U16 ? SELECT_OP(DSRL32, SRL) : SELECT_OP(DSRA32, SRA)) | T(dst) | D(dst) | SH_IMM(16), DR(dst)));
+ return push_inst(compiler, OR | S(dst) | T(TMP_REG1) | D(dst), DR(dst));
+#endif /* SLJIT_MIPS_REV >= 2 */
+}
+
static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 flags,
sljit_s32 dst, sljit_s32 src1, sljit_sw src2)
{
@@ -1486,17 +1735,17 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
-#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 2)
return push_inst(compiler, SEB | T(src2) | D(dst), DR(dst));
-#else /* SLJIT_MIPS_REV < 1 */
+#else /* SLJIT_MIPS_REV < 2 */
FAIL_IF(push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(24), DR(dst)));
return push_inst(compiler, SRA | T(dst) | D(dst) | SH_IMM(24), DR(dst));
-#endif /* SLJIT_MIPS_REV >= 1 */
+#endif /* SLJIT_MIPS_REV >= 2 */
#else /* !SLJIT_CONFIG_MIPS_32 */
-#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 2)
if (op & SLJIT_32)
return push_inst(compiler, SEB | T(src2) | D(dst), DR(dst));
-#endif /* SLJIT_MIPS_REV >= 1 */
+#endif /* SLJIT_MIPS_REV >= 2 */
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(24), DR(dst)));
return push_inst(compiler, DSRA32 | T(dst) | D(dst) | SH_IMM(24), DR(dst));
#endif /* SLJIT_CONFIG_MIPS_32 */
@@ -1515,17 +1764,17 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
-#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 2)
return push_inst(compiler, SEH | T(src2) | D(dst), DR(dst));
-#else /* SLJIT_MIPS_REV < 1 */
+#else /* SLJIT_MIPS_REV < 2 */
FAIL_IF(push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(16), DR(dst)));
return push_inst(compiler, SRA | T(dst) | D(dst) | SH_IMM(16), DR(dst));
-#endif /* SLJIT_MIPS_REV >= 1 */
+#endif /* SLJIT_MIPS_REV >= 2 */
#else /* !SLJIT_CONFIG_MIPS_32 */
-#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 2)
if (op & SLJIT_32)
return push_inst(compiler, SEH | T(src2) | D(dst), DR(dst));
-#endif /* SLJIT_MIPS_REV >= 1 */
+#endif /* SLJIT_MIPS_REV >= 2 */
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(16), DR(dst)));
return push_inst(compiler, DSRA32 | T(dst) | D(dst) | SH_IMM(16), DR(dst));
#endif /* SLJIT_CONFIG_MIPS_32 */
@@ -1539,7 +1788,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 2)
if (dst == src2)
- return push_inst(compiler, DINSU | T(src2) | SA(0) | (31 << 11) | (0 << 11), DR(dst));
+ return push_inst(compiler, DINSU | T(src2) | SA(0) | (31 << 11), DR(dst));
#endif /* SLJIT_MIPS_REV >= 2 */
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(0), DR(dst)));
return push_inst(compiler, DSRL32 | T(dst) | D(dst) | SH_IMM(0), DR(dst));
@@ -1556,14 +1805,6 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
return SLJIT_SUCCESS;
#endif /* SLJIT_CONFIG_MIPS_64 */
- case SLJIT_NOT:
- SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
- if (op & SLJIT_SET_Z)
- FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
- if (!(flags & UNUSED_DEST))
- FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | D(dst), DR(dst)));
- return SLJIT_SUCCESS;
-
#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1)
case SLJIT_CLZ:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
@@ -1591,10 +1832,21 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
return emit_clz_ctz(compiler, op, dst, src2);
#endif /* SLJIT_MIPS_REV >= 1 */
+ case SLJIT_REV:
+ case SLJIT_REV_U32:
+ case SLJIT_REV_S32:
+ SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM) && src2 != TMP_REG1 && dst != TMP_REG1);
+ return emit_rev(compiler, op, dst, src2);
+
+ case SLJIT_REV_U16:
+ case SLJIT_REV_S16:
+ SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+ return emit_rev16(compiler, op, dst, src2);
+
case SLJIT_ADD:
/* Overflow computation (both add and sub): overflow = src1_sign ^ src2_sign ^ result_sign ^ carry_flag */
is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
- carry_src_ar = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
+ carry_src_ar = GET_FLAG_TYPE(op) == SLJIT_CARRY;
if (flags & SRC2_IMM) {
if (is_overflow) {
@@ -1650,7 +1902,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
return push_inst(compiler, XOR | S(TMP_REG1) | TA(OTHER_FLAG) | DA(OTHER_FLAG), OTHER_FLAG);
case SLJIT_ADDC:
- carry_src_ar = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
+ carry_src_ar = GET_FLAG_TYPE(op) == SLJIT_CARRY;
if (flags & SRC2_IMM) {
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(src2), DR(dst)));
@@ -1697,11 +1949,11 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
is_handled = 0;
if (flags & SRC2_IMM) {
- if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
+ if (GET_FLAG_TYPE(op) == SLJIT_LESS) {
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
is_handled = 1;
}
- else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
+ else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS) {
FAIL_IF(push_inst(compiler, SLTI | S(src1) | TA(OTHER_FLAG) | IMM(src2), OTHER_FLAG));
is_handled = 1;
}
@@ -1718,19 +1970,15 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
switch (GET_FLAG_TYPE(op)) {
case SLJIT_LESS:
- case SLJIT_GREATER_EQUAL:
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
break;
case SLJIT_GREATER:
- case SLJIT_LESS_EQUAL:
FAIL_IF(push_inst(compiler, SLTU | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
break;
case SLJIT_SIG_LESS:
- case SLJIT_SIG_GREATER_EQUAL:
FAIL_IF(push_inst(compiler, SLT | S(src1) | T(src2) | DA(OTHER_FLAG), OTHER_FLAG));
break;
case SLJIT_SIG_GREATER:
- case SLJIT_SIG_LESS_EQUAL:
FAIL_IF(push_inst(compiler, SLT | S(src2) | T(src1) | DA(OTHER_FLAG), OTHER_FLAG));
break;
}
@@ -1753,7 +2001,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
}
is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
- is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
+ is_carry = GET_FLAG_TYPE(op) == SLJIT_CARRY;
if (flags & SRC2_IMM) {
if (is_overflow) {
@@ -1802,7 +2050,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
flags &= ~SRC2_IMM;
}
- is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
+ is_carry = GET_FLAG_TYPE(op) == SLJIT_CARRY;
if (flags & SRC2_IMM) {
if (is_carry)
@@ -1868,6 +2116,14 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
return SLJIT_SUCCESS;
case SLJIT_XOR:
+ if (!(flags & LOGICAL_OP)) {
+ SLJIT_ASSERT((flags & SRC2_IMM) && src2 == -1);
+ if (op & SLJIT_SET_Z)
+ FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG));
+ if (!(flags & UNUSED_DEST))
+ FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | D(dst), DR(dst)));
+ return SLJIT_SUCCESS;
+ }
EMIT_LOGICAL(XORI, XOR);
return SLJIT_SUCCESS;
@@ -2034,9 +2290,10 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
compiler->cache_argw = 0;
}
- if (dst == TMP_REG2) {
+ if (dst == 0) {
SLJIT_ASSERT(HAS_FLAGS(op));
flags |= UNUSED_DEST;
+ dst = TMP_REG2;
}
else if (FAST_IS_REG(dst)) {
dst_r = dst;
@@ -2048,10 +2305,10 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
flags |= SLOW_DEST;
if (flags & IMM_OP) {
- if ((src2 & SLJIT_IMM) && src2w != 0 && CHECK_IMM(flags, src2w)) {
+ if (src2 == SLJIT_IMM && src2w != 0 && CHECK_IMM(flags, src2w)) {
flags |= SRC2_IMM;
src2_r = src2w;
- } else if ((flags & CUMULATIVE_OP) && (src1 & SLJIT_IMM) && src1w != 0 && CHECK_IMM(flags, src1w)) {
+ } else if ((flags & CUMULATIVE_OP) && src1 == SLJIT_IMM && src1w != 0 && CHECK_IMM(flags, src1w)) {
flags |= SRC2_IMM;
src2_r = src1w;
@@ -2068,7 +2325,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
src1_r = src1;
flags |= REG1_SOURCE;
}
- else if (src1 & SLJIT_IMM) {
+ else if (src1 == SLJIT_IMM) {
if (src1w) {
FAIL_IF(load_immediate(compiler, DR(TMP_REG1), src1w));
src1_r = TMP_REG1;
@@ -2091,7 +2348,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
if ((flags & (REG_DEST | MOVE_OP)) == MOVE_OP)
dst_r = (sljit_s32)src2_r;
}
- else if (src2 & SLJIT_IMM) {
+ else if (src2 == SLJIT_IMM) {
if (!(flags & SRC2_IMM)) {
if (src2w) {
FAIL_IF(load_immediate(compiler, DR(sugg_src2_r), src2w));
@@ -2279,31 +2536,37 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
case SLJIT_MOV_U32:
- return emit_op(compiler, SLJIT_MOV_U32, INT_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u32)srcw : srcw);
+ return emit_op(compiler, SLJIT_MOV_U32, INT_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u32)srcw : srcw);
case SLJIT_MOV_S32:
case SLJIT_MOV32:
- return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s32)srcw : srcw);
+ return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s32)srcw : srcw);
#endif
case SLJIT_MOV_U8:
- return emit_op(compiler, op, BYTE_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u8)srcw : srcw);
+ return emit_op(compiler, op, BYTE_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u8)srcw : srcw);
case SLJIT_MOV_S8:
- return emit_op(compiler, op, BYTE_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s8)srcw : srcw);
+ return emit_op(compiler, op, BYTE_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s8)srcw : srcw);
case SLJIT_MOV_U16:
- return emit_op(compiler, op, HALF_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u16)srcw : srcw);
+ return emit_op(compiler, op, HALF_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u16)srcw : srcw);
case SLJIT_MOV_S16:
- return emit_op(compiler, op, HALF_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s16)srcw : srcw);
-
- case SLJIT_NOT:
- return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw);
+ return emit_op(compiler, op, HALF_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s16)srcw : srcw);
case SLJIT_CLZ:
case SLJIT_CTZ:
+ case SLJIT_REV:
return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw);
+
+ case SLJIT_REV_U16:
+ case SLJIT_REV_S16:
+ return emit_op(compiler, op, HALF_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+
+ case SLJIT_REV_U32:
+ case SLJIT_REV_S32:
+ return emit_op(compiler, op | SLJIT_32, INT_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
}
SLJIT_UNREACHABLE();
@@ -2326,9 +2589,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
if (op & SLJIT_32) {
flags |= INT_DATA | SIGNED_DATA;
- if (src1 & SLJIT_IMM)
+ if (src1 == SLJIT_IMM)
src1w = (sljit_s32)src1w;
- if (src2 & SLJIT_IMM)
+ if (src2 == SLJIT_IMM)
src2w = (sljit_s32)src2w;
}
#endif
@@ -2348,9 +2611,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
compiler->status_flags_state = 0;
return emit_op(compiler, op, flags | CUMULATIVE_OP, dst, dstw, src1, src1w, src2, src2w);
+ case SLJIT_XOR:
+ if ((src1 == SLJIT_IMM && src1w == -1) || (src2 == SLJIT_IMM && src2w == -1)) {
+ return emit_op(compiler, op, flags | CUMULATIVE_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
+ }
+ /* fallthrough */
case SLJIT_AND:
case SLJIT_OR:
- case SLJIT_XOR:
return emit_op(compiler, op, flags | CUMULATIVE_OP | LOGICAL_OP | IMM_OP, dst, dstw, src1, src1w, src2, src2w);
case SLJIT_SHL:
@@ -2362,10 +2629,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
case SLJIT_ROTL:
case SLJIT_ROTR:
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
- if (src2 & SLJIT_IMM)
+ if (src2 == SLJIT_IMM)
src2w &= 0x1f;
#else
- if (src2 & SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
if (op & SLJIT_32)
src2w &= 0x1f;
else
@@ -2387,7 +2654,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil
CHECK(check_sljit_emit_op2(compiler, op, 1, 0, 0, src1, src1w, src2, src2w));
SLJIT_SKIP_CHECKS(compiler);
- return sljit_emit_op2(compiler, op, TMP_REG2, 0, src1, src1w, src2, src2w);
+ return sljit_emit_op2(compiler, op, 0, 0, src1, src1w, src2, src2w);
}
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
@@ -2399,9 +2666,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil
#endif /* SLJIT_CONFIG_MIPS_64 */
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 src_dst,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w)
+ sljit_s32 dst_reg,
+ sljit_s32 src1_reg,
+ sljit_s32 src2_reg,
+ sljit_s32 src3, sljit_sw src3w)
{
sljit_s32 is_left;
sljit_ins ins1, ins2, ins3;
@@ -2414,50 +2682,44 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *
#endif /* SLJIT_CONFIG_MIPS_64 */
CHECK_ERROR();
- CHECK(check_sljit_emit_shift_into(compiler, op, src_dst, src1, src1w, src2, src2w));
+ CHECK(check_sljit_emit_shift_into(compiler, op, dst_reg, src1_reg, src2_reg, src3, src3w));
is_left = (GET_OPCODE(op) == SLJIT_SHL || GET_OPCODE(op) == SLJIT_MSHL);
- if (src_dst == src1) {
+ if (src1_reg == src2_reg) {
SLJIT_SKIP_CHECKS(compiler);
- return sljit_emit_op2(compiler, (is_left ? SLJIT_ROTL : SLJIT_ROTR) | (op & SLJIT_32), src_dst, 0, src_dst, 0, src2, src2w);
+ return sljit_emit_op2(compiler, (is_left ? SLJIT_ROTL : SLJIT_ROTR) | (op & SLJIT_32), dst_reg, 0, src1_reg, 0, src3, src3w);
}
- ADJUST_LOCAL_OFFSET(src1, src1w);
- ADJUST_LOCAL_OFFSET(src2, src2w);
+ ADJUST_LOCAL_OFFSET(src3, src3w);
- if (src2 & SLJIT_IMM) {
- src2w &= bit_length - 1;
+ if (src3 == SLJIT_IMM) {
+ src3w &= bit_length - 1;
- if (src2w == 0)
+ if (src3w == 0)
return SLJIT_SUCCESS;
- } else if (src2 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem(compiler, inp_flags, DR(TMP_REG2), src2, src2w));
- src2 = TMP_REG2;
- }
- if (src1 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem(compiler, inp_flags, DR(TMP_REG1), src1, src1w));
- src1 = TMP_REG1;
- } else if (src1 & SLJIT_IMM) {
- FAIL_IF(load_immediate(compiler, DR(TMP_REG1), src1w));
- src1 = TMP_REG1;
- }
-
- if (src2 & SLJIT_IMM) {
if (is_left) {
- ins1 = SELECT_OP3(op, src2w, DSLL, DSLL32, SLL);
- src2w = bit_length - src2w;
- ins2 = SELECT_OP3(op, src2w, DSRL, DSRL32, SRL);
+ ins1 = SELECT_OP3(op, src3w, DSLL, DSLL32, SLL);
+ src3w = bit_length - src3w;
+ ins2 = SELECT_OP3(op, src3w, DSRL, DSRL32, SRL);
} else {
- ins1 = SELECT_OP3(op, src2w, DSRL, DSRL32, SRL);
- src2w = bit_length - src2w;
- ins2 = SELECT_OP3(op, src2w, DSLL, DSLL32, SLL);
+ ins1 = SELECT_OP3(op, src3w, DSRL, DSRL32, SRL);
+ src3w = bit_length - src3w;
+ ins2 = SELECT_OP3(op, src3w, DSLL, DSLL32, SLL);
}
- FAIL_IF(push_inst(compiler, ins1 | T(src_dst) | D(src_dst), DR(src_dst)));
- FAIL_IF(push_inst(compiler, ins2 | T(src1) | D(TMP_REG1), DR(TMP_REG1)));
- return push_inst(compiler, OR | S(src_dst) | T(TMP_REG1) | D(src_dst), DR(src_dst));
+ FAIL_IF(push_inst(compiler, ins1 | T(src1_reg) | D(dst_reg), DR(dst_reg)));
+ FAIL_IF(push_inst(compiler, ins2 | T(src2_reg) | D(TMP_REG1), DR(TMP_REG1)));
+ return push_inst(compiler, OR | S(dst_reg) | T(TMP_REG1) | D(dst_reg), DR(dst_reg));
+ }
+
+ if (src3 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, inp_flags, DR(TMP_REG2), src3, src3w));
+ src3 = TMP_REG2;
+ } else if (dst_reg == src3) {
+ FAIL_IF(push_inst(compiler, SELECT_OP2(op, DADDU, ADDU) | S(src3) | TA(0) | D(TMP_REG2), DR(TMP_REG2)));
+ src3 = TMP_REG2;
}
if (is_left) {
@@ -2470,17 +2732,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *
ins3 = SELECT_OP2(op, DSLLV, SLLV);
}
- FAIL_IF(push_inst(compiler, ins2 | S(src2) | T(src_dst) | D(src_dst), DR(src_dst)));
+ FAIL_IF(push_inst(compiler, ins2 | S(src3) | T(src1_reg) | D(dst_reg), DR(dst_reg)));
if (!(op & SLJIT_SHIFT_INTO_NON_ZERO)) {
- FAIL_IF(push_inst(compiler, ins1 | T(src1) | D(TMP_REG1) | (1 << 6), DR(TMP_REG1)));
- FAIL_IF(push_inst(compiler, XORI | S(src2) | T(TMP_REG2) | ((sljit_ins)bit_length - 1), DR(TMP_REG2)));
- src1 = TMP_REG1;
+ FAIL_IF(push_inst(compiler, ins1 | T(src2_reg) | D(TMP_REG1) | (1 << 6), DR(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, XORI | S(src3) | T(TMP_REG2) | ((sljit_ins)bit_length - 1), DR(TMP_REG2)));
+ src2_reg = TMP_REG1;
} else
- FAIL_IF(push_inst(compiler, SELECT_OP2(op, DSUBU, SUBU) | SA(0) | T(src2) | D(TMP_REG2), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, SELECT_OP2(op, DSUBU, SUBU) | SA(0) | T(src3) | D(TMP_REG2), DR(TMP_REG2)));
- FAIL_IF(push_inst(compiler, ins3 | S(TMP_REG2) | T(src1) | D(TMP_REG1), DR(TMP_REG1)));
- return push_inst(compiler, OR | S(src_dst) | T(TMP_REG1) | D(src_dst), DR(src_dst));
+ FAIL_IF(push_inst(compiler, ins3 | S(TMP_REG2) | T(src2_reg) | D(TMP_REG1), DR(TMP_REG1)));
+ return push_inst(compiler, OR | S(dst_reg) | T(TMP_REG1) | D(dst_reg), DR(dst_reg));
}
#undef SELECT_OP3
@@ -2518,21 +2780,54 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *comp
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw)
{
- CHECK_REG_INDEX(check_sljit_get_register_index(reg));
- return reg_map[reg];
+ sljit_s32 dst_ar = RETURN_ADDR_REG;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op_dst(compiler, op, dst, dstw));
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+
+ switch (op) {
+ case SLJIT_FAST_ENTER:
+ if (FAST_IS_REG(dst))
+ return push_inst(compiler, ADDU_W | SA(RETURN_ADDR_REG) | TA(0) | D(dst), UNMOVABLE_INS);
+ break;
+ case SLJIT_GET_RETURN_ADDRESS:
+ dst_ar = DR(FAST_IS_REG(dst) ? dst : TMP_REG2);
+ FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, dst_ar, SLJIT_MEM1(SLJIT_SP), compiler->local_size - SSIZE_OF(sw)));
+ break;
+ }
+
+ if (dst & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, WORD_DATA, dst_ar, dst, dstw));
+
+ if (op == SLJIT_FAST_ENTER)
+ compiler->delay_slot = UNMOVABLE_INS;
+ }
+
+ return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 type, sljit_s32 reg)
{
- CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
+ CHECK_REG_INDEX(check_sljit_get_register_index(type, reg));
+
+ if (type == SLJIT_GP_REGISTER)
+ return reg_map[reg];
+
+ if (type != SLJIT_FLOAT_REGISTER)
+ return -1;
+
return FR(reg);
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
void *instruction, sljit_u32 size)
{
+ SLJIT_UNUSED_ARG(size);
+
CHECK_ERROR();
CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
@@ -2544,14 +2839,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *c
/* --------------------------------------------------------------------- */
#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_32) >> 7))
-#define FMT(op) ((((sljit_ins)op & SLJIT_32) ^ SLJIT_32) << (21 - 8))
+#define FMT(op) (FMT_S | (~(sljit_ins)op & SLJIT_32) << (21 - (5 + 3)))
static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 src, sljit_sw srcw)
{
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
-# define flags (sljit_u32)0
+ sljit_u32 flags = 0;
#else
sljit_u32 flags = ((sljit_u32)(GET_OPCODE(op) == SLJIT_CONV_SW_FROM_F64)) << 21;
#endif
@@ -2565,18 +2860,13 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_comp
if (FAST_IS_REG(dst)) {
FAIL_IF(push_inst(compiler, MFC1 | flags | T(dst) | FS(TMP_FREG1), MOVABLE_INS));
-#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 3)
+#if !defined(SLJIT_MIPS_REV) || (SLJIT_CONFIG_MIPS_32 && SLJIT_MIPS_REV <= 1)
FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
-#endif
+#endif /* MIPS III */
return SLJIT_SUCCESS;
}
- /* Store the integer value from a VFP register. */
return emit_op_mem2(compiler, flags ? DOUBLE_DATA : SINGLE_DATA, FR(TMP_FREG1), dst, dstw, 0, 0);
-
-#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
-# undef flags
-#endif
}
static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
@@ -2584,43 +2874,158 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_comp
sljit_s32 src, sljit_sw srcw)
{
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
-# define flags (sljit_u32)0
+ sljit_u32 flags = 0;
#else
sljit_u32 flags = ((sljit_u32)(GET_OPCODE(op) == SLJIT_CONV_F64_FROM_SW)) << 21;
#endif
-
sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
- if (FAST_IS_REG(src)) {
- FAIL_IF(push_inst(compiler, MTC1 | flags | T(src) | FS(TMP_FREG1), MOVABLE_INS));
-#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 3)
- FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
-#endif
- } else if (src & SLJIT_MEM) {
- /* Load the integer value into a VFP register. */
+ if (src & SLJIT_MEM)
FAIL_IF(emit_op_mem2(compiler, (flags ? DOUBLE_DATA : SINGLE_DATA) | LOAD_DATA, FR(TMP_FREG1), src, srcw, dst, dstw));
- }
else {
+ if (src == SLJIT_IMM) {
#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
- if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
- srcw = (sljit_s32)srcw;
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
+ srcw = (sljit_s32)srcw;
#endif
- FAIL_IF(load_immediate(compiler, DR(TMP_REG1), srcw));
- FAIL_IF(push_inst(compiler, MTC1 | flags | T(TMP_REG1) | FS(TMP_FREG1), MOVABLE_INS));
-#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 3)
+ FAIL_IF(load_immediate(compiler, DR(TMP_REG1), srcw));
+ src = TMP_REG1;
+ }
+
+ FAIL_IF(push_inst(compiler, MTC1 | flags | T(src) | FS(TMP_FREG1), MOVABLE_INS));
+#if !defined(SLJIT_MIPS_REV) || (SLJIT_CONFIG_MIPS_32 && SLJIT_MIPS_REV <= 1)
FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
-#endif
+#endif /* MIPS III */
}
- FAIL_IF(push_inst(compiler, CVT_S_S | flags | (4 << 21) | ((((sljit_ins)op & SLJIT_32) ^ SLJIT_32) >> 8) | FS(TMP_FREG1) | FD(dst_r), MOVABLE_INS));
+ FAIL_IF(push_inst(compiler, CVT_S_S | flags | (4 << 21) | ((~(sljit_ins)op & SLJIT_32) >> 8) | FS(TMP_FREG1) | FD(dst_r), MOVABLE_INS));
if (dst & SLJIT_MEM)
return emit_op_mem2(compiler, FLOAT_DATA(op), FR(TMP_FREG1), dst, dstw, 0, 0);
return SLJIT_SUCCESS;
+}
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_uw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
-# undef flags
+ sljit_u32 flags = 0;
+#else
+ sljit_u32 flags = 1 << 21;
+#endif
+ sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+ if (src & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem2(compiler, (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_UW ? WORD_DATA : INT_DATA) | LOAD_DATA, DR(TMP_REG1), src, srcw, dst, dstw));
+ src = TMP_REG1;
+ } else if (src == SLJIT_IMM) {
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_U32)
+ srcw = (sljit_u32)srcw;
#endif
+ FAIL_IF(load_immediate(compiler, DR(TMP_REG1), srcw));
+ src = TMP_REG1;
+ }
+
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_U32) {
+ if (src != TMP_REG1) {
+ FAIL_IF(push_inst(compiler, DSLL32 | T(src) | D(TMP_REG1) | SH_IMM(0), DR(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, DSRL32 | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(0), DR(TMP_REG1)));
+ }
+
+ FAIL_IF(push_inst(compiler, MTC1 | flags | T(TMP_REG1) | FS(TMP_FREG1), MOVABLE_INS));
+#if !defined(SLJIT_MIPS_REV)
+ FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+#endif /* MIPS III */
+
+ FAIL_IF(push_inst(compiler, CVT_S_S | flags | (4 << 21) | ((~(sljit_ins)op & SLJIT_32) >> 8) | FS(TMP_FREG1) | FD(dst_r), MOVABLE_INS));
+
+ if (dst & SLJIT_MEM)
+ return emit_op_mem2(compiler, FLOAT_DATA(op), FR(TMP_FREG1), dst, dstw, 0, 0);
+ return SLJIT_SUCCESS;
+ }
+#else /* !SLJIT_CONFIG_MIPS_64 */
+ if (!(op & SLJIT_32)) {
+ FAIL_IF(push_inst(compiler, SLL | T(src) | D(TMP_REG2) | SH_IMM(1), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, SRL | T(TMP_REG2) | D(TMP_REG2) | SH_IMM(1), DR(TMP_REG2)));
+
+ FAIL_IF(push_inst(compiler, MTC1 | flags | T(TMP_REG2) | FS(TMP_FREG1), MOVABLE_INS));
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
+ FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+#endif /* MIPS III */
+
+ FAIL_IF(push_inst(compiler, CVT_S_S | flags | (4 << 21) | 1 | FS(TMP_FREG1) | FD(dst_r), MOVABLE_INS));
+
+#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 1)
+ FAIL_IF(push_inst(compiler, BGEZ | S(src) | 5, UNMOVABLE_INS));
+#else /* SLJIT_MIPS_REV >= 1 */
+ FAIL_IF(push_inst(compiler, BGEZ | S(src) | 4, UNMOVABLE_INS));
+#endif /* SLJIT_MIPS_REV < 1 */
+
+ FAIL_IF(push_inst(compiler, LUI | T(TMP_REG2) | IMM(0x41e0), UNMOVABLE_INS));
+ FAIL_IF(push_inst(compiler, MTC1 | TA(0) | FS(TMP_FREG2), UNMOVABLE_INS));
+ switch (cpu_feature_list & CPU_FEATURE_FR) {
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
+ case CPU_FEATURE_FR:
+ FAIL_IF(push_inst(compiler, MTHC1 | T(TMP_REG2) | FS(TMP_FREG2), UNMOVABLE_INS));
+ break;
+#endif /* SLJIT_MIPS_REV >= 2 */
+ default:
+ FAIL_IF(push_inst(compiler, MTC1 | T(TMP_REG2) | FS(TMP_FREG2) | (1 << 11), UNMOVABLE_INS));
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
+ FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+#endif /* MIPS III */
+ break;
+ }
+ FAIL_IF(push_inst(compiler, ADD_S | FMT(op) | FT(TMP_FREG2) | FS(dst_r) | FD(dst_r), UNMOVABLE_INS));
+
+ if (dst & SLJIT_MEM)
+ return emit_op_mem2(compiler, FLOAT_DATA(op), FR(TMP_FREG1), dst, dstw, 0, 0);
+ return SLJIT_SUCCESS;
+ }
+#endif /* SLJIT_CONFIG_MIPS_64 */
+
+#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 1)
+ FAIL_IF(push_inst(compiler, BLTZ | S(src) | 5, UNMOVABLE_INS));
+#else /* SLJIT_MIPS_REV >= 1 */
+ FAIL_IF(push_inst(compiler, BLTZ | S(src) | 4, UNMOVABLE_INS));
+#endif /* SLJIT_MIPS_REV < 1 */
+ FAIL_IF(push_inst(compiler, ANDI | S(src) | T(TMP_REG2) | IMM(1), DR(TMP_REG2)));
+
+ FAIL_IF(push_inst(compiler, MTC1 | flags | T(src) | FS(TMP_FREG1), MOVABLE_INS));
+#if !defined(SLJIT_MIPS_REV)
+ FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+#endif /* !SLJIT_MIPS_REV */
+
+ FAIL_IF(push_inst(compiler, CVT_S_S | flags | (4 << 21) | ((~(sljit_ins)op & SLJIT_32) >> 8) | FS(TMP_FREG1) | FD(dst_r), MOVABLE_INS));
+
+#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 1)
+ FAIL_IF(push_inst(compiler, BEQ | 6, UNMOVABLE_INS));
+#else /* SLJIT_MIPS_REV >= 1 */
+ FAIL_IF(push_inst(compiler, BEQ | 5, UNMOVABLE_INS));
+#endif /* SLJIT_MIPS_REV < 1 */
+
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+ FAIL_IF(push_inst(compiler, DSRL | T(src) | D(TMP_REG1) | SH_IMM(1), DR(TMP_REG1)));
+#else /* !SLJIT_CONFIG_MIPS_64 */
+ FAIL_IF(push_inst(compiler, SRL | T(src) | D(TMP_REG1) | SH_IMM(1), DR(TMP_REG1)));
+#endif /* SLJIT_CONFIG_MIPS_64 */
+
+ FAIL_IF(push_inst(compiler, OR | S(TMP_REG1) | T(TMP_REG2) | D(TMP_REG1), DR(TMP_REG1)));
+
+ FAIL_IF(push_inst(compiler, MTC1 | flags | T(TMP_REG1) | FS(TMP_FREG1), MOVABLE_INS));
+#if !defined(SLJIT_MIPS_REV)
+ FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+#endif /* !SLJIT_MIPS_REV */
+
+ FAIL_IF(push_inst(compiler, CVT_S_S | flags | (4 << 21) | ((~(sljit_ins)op & SLJIT_32) >> 8) | FS(TMP_FREG1) | FD(dst_r), MOVABLE_INS));
+ FAIL_IF(push_inst(compiler, ADD_S | FMT(op) | FT(dst_r) | FS(dst_r) | FD(dst_r), UNMOVABLE_INS));
+
+ if (dst & SLJIT_MEM)
+ return emit_op_mem2(compiler, FLOAT_DATA(op), FR(TMP_FREG1), dst, dstw, 0, 0);
+ return SLJIT_SUCCESS;
}
static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
@@ -2642,36 +3047,30 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compile
switch (GET_FLAG_TYPE(op)) {
case SLJIT_F_EQUAL:
case SLJIT_ORDERED_EQUAL:
- case SLJIT_UNORDERED_OR_NOT_EQUAL:
inst = C_EQ_S;
break;
case SLJIT_F_NOT_EQUAL:
case SLJIT_UNORDERED_OR_EQUAL:
- case SLJIT_ORDERED_NOT_EQUAL:
inst = C_UEQ_S;
break;
case SLJIT_F_LESS:
case SLJIT_ORDERED_LESS:
- case SLJIT_UNORDERED_OR_GREATER_EQUAL:
inst = C_OLT_S;
break;
case SLJIT_F_GREATER_EQUAL:
case SLJIT_UNORDERED_OR_LESS:
- case SLJIT_ORDERED_GREATER_EQUAL:
inst = C_ULT_S;
break;
case SLJIT_F_GREATER:
case SLJIT_ORDERED_GREATER:
- case SLJIT_UNORDERED_OR_LESS_EQUAL:
inst = C_ULE_S;
break;
case SLJIT_F_LESS_EQUAL:
case SLJIT_UNORDERED_OR_GREATER:
- case SLJIT_ORDERED_LESS_EQUAL:
inst = C_OLE_S;
break;
default:
- SLJIT_ASSERT(GET_FLAG_TYPE(op) == SLJIT_UNORDERED || GET_FLAG_TYPE(op) == SLJIT_ORDERED);
+ SLJIT_ASSERT(GET_FLAG_TYPE(op) == SLJIT_UNORDERED);
inst = C_UN_S;
break;
}
@@ -2705,7 +3104,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil
case SLJIT_MOV_F64:
if (src != dst_r) {
if (dst_r != TMP_FREG1)
- FAIL_IF(push_inst(compiler, MOV_S | FMT(op) | FS(src) | FD(dst_r), MOVABLE_INS));
+ FAIL_IF(push_inst(compiler, MOV_fmt(FMT(op)) | FS(src) | FD(dst_r), MOVABLE_INS));
else
dst_r = src;
}
@@ -2786,18 +3185,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
case SLJIT_ADD_F64:
FAIL_IF(push_inst(compiler, ADD_S | FMT(op) | FT(src2) | FS(src1) | FD(dst_r), MOVABLE_INS));
break;
-
case SLJIT_SUB_F64:
FAIL_IF(push_inst(compiler, SUB_S | FMT(op) | FT(src2) | FS(src1) | FD(dst_r), MOVABLE_INS));
break;
-
case SLJIT_MUL_F64:
FAIL_IF(push_inst(compiler, MUL_S | FMT(op) | FT(src2) | FS(src1) | FD(dst_r), MOVABLE_INS));
break;
-
case SLJIT_DIV_F64:
FAIL_IF(push_inst(compiler, DIV_S | FMT(op) | FT(src2) | FS(src1) | FD(dst_r), MOVABLE_INS));
break;
+ case SLJIT_COPYSIGN_F64:
+ return emit_copysign(compiler, op, src1, src2, dst_r);
}
if (dst_r == TMP_FREG2)
@@ -2806,26 +3204,24 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
return SLJIT_SUCCESS;
}
-#undef FLOAT_DATA
-#undef FMT
-
-/* --------------------------------------------------------------------- */
-/* Other instructions */
-/* --------------------------------------------------------------------- */
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset32(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f32 value)
{
+ union {
+ sljit_s32 imm;
+ sljit_f32 value;
+ } u;
+
CHECK_ERROR();
- CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
- ADJUST_LOCAL_OFFSET(dst, dstw);
+ CHECK(check_sljit_emit_fset32(compiler, freg, value));
- if (FAST_IS_REG(dst))
- return push_inst(compiler, ADDU_W | SA(RETURN_ADDR_REG) | TA(0) | D(dst), UNMOVABLE_INS);
+ u.value = value;
- /* Memory. */
- FAIL_IF(emit_op_mem(compiler, WORD_DATA, RETURN_ADDR_REG, dst, dstw));
- compiler->delay_slot = UNMOVABLE_INS;
- return SLJIT_SUCCESS;
+ if (u.imm == 0)
+ return push_inst(compiler, MTC1 | TA(0) | FS(freg), MOVABLE_INS);
+
+ FAIL_IF(load_immediate(compiler, DR(TMP_REG1), u.imm));
+ return push_inst(compiler, MTC1 | T(TMP_REG1) | FS(freg), MOVABLE_INS);
}
/* --------------------------------------------------------------------- */
@@ -2984,7 +3380,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
}
#define RESOLVE_IMM1() \
- if (src1 & SLJIT_IMM) { \
+ if (src1 == SLJIT_IMM) { \
if (src1w) { \
PTR_FAIL_IF(load_immediate(compiler, DR(TMP_REG1), src1w)); \
src1 = TMP_REG1; \
@@ -2994,7 +3390,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
}
#define RESOLVE_IMM2() \
- if (src2 & SLJIT_IMM) { \
+ if (src2 == SLJIT_IMM) { \
if (src2w) { \
PTR_FAIL_IF(load_immediate(compiler, DR(TMP_REG2), src2w)); \
src2 = TMP_REG2; \
@@ -3046,10 +3442,9 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler
if (compiler->delay_slot == MOVABLE_INS || (compiler->delay_slot != UNMOVABLE_INS && compiler->delay_slot != DR(src1) && compiler->delay_slot != DR(src2)))
jump->flags |= IS_MOVABLE;
PTR_FAIL_IF(push_inst(compiler, (type == SLJIT_EQUAL ? BNE : BEQ) | S(src1) | T(src2) | BRANCH_LENGTH, UNMOVABLE_INS));
- }
- else if (type >= SLJIT_SIG_LESS && (((src1 & SLJIT_IMM) && (src1w == 0)) || ((src2 & SLJIT_IMM) && (src2w == 0)))) {
+ } else if (type >= SLJIT_SIG_LESS && ((src1 == SLJIT_IMM && src1w == 0) || (src2 == SLJIT_IMM && src2w == 0))) {
inst = NOP;
- if ((src1 & SLJIT_IMM) && (src1w == 0)) {
+ if (src1 == SLJIT_IMM && src1w == 0) {
RESOLVE_IMM2();
switch (type) {
case SLJIT_SIG_LESS:
@@ -3097,7 +3492,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler
else {
if (type == SLJIT_LESS || type == SLJIT_GREATER_EQUAL || type == SLJIT_SIG_LESS || type == SLJIT_SIG_GREATER_EQUAL) {
RESOLVE_IMM1();
- if ((src2 & SLJIT_IMM) && src2w <= SIMM_MAX && src2w >= SIMM_MIN)
+ if (src2 == SLJIT_IMM && src2w <= SIMM_MAX && src2w >= SIMM_MIN)
PTR_FAIL_IF(push_inst(compiler, (type <= SLJIT_LESS_EQUAL ? SLTIU : SLTI) | S(src1) | T(TMP_REG1) | IMM(src2w), DR(TMP_REG1)));
else {
RESOLVE_IMM2();
@@ -3107,7 +3502,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler
}
else {
RESOLVE_IMM2();
- if ((src1 & SLJIT_IMM) && src1w <= SIMM_MAX && src1w >= SIMM_MIN)
+ if (src1 == SLJIT_IMM && src1w <= SIMM_MAX && src1w >= SIMM_MIN)
PTR_FAIL_IF(push_inst(compiler, (type <= SLJIT_LESS_EQUAL ? SLTIU : SLTI) | S(src2) | T(TMP_REG1) | IMM(src1w), DR(TMP_REG1)));
else {
RESOLVE_IMM1();
@@ -3142,9 +3537,6 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler
#undef BR_T
#undef BR_F
-#undef FLOAT_DATA
-#undef FMT
-
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compiler, sljit_s32 type, sljit_s32 src, sljit_sw srcw)
{
struct sljit_jump *jump = NULL;
@@ -3152,7 +3544,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
CHECK_ERROR();
CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
- if (src & SLJIT_IMM) {
+ if (src == SLJIT_IMM) {
jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
FAIL_IF(!jump);
set_jump(jump, compiler, JUMP_ADDR | ((type >= SLJIT_FAST_CALL) ? IS_JAL : 0));
@@ -3184,8 +3576,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
#endif
}
- FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
- return SLJIT_SUCCESS;
+ return push_inst(compiler, NOP, UNMOVABLE_INS);
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *compiler, sljit_s32 op,
@@ -3287,50 +3678,29 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
return emit_op(compiler, saved_op, mem_type, dst, dstw, dst, dstw, TMP_REG2, 0);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
- sljit_s32 dst_reg,
- sljit_s32 src, sljit_sw srcw)
-{
#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1 && SLJIT_MIPS_REV < 6)
- sljit_ins ins;
-#endif /* SLJIT_MIPS_REV >= 1 && SLJIT_MIPS_REV < 6 */
-
- CHECK_ERROR();
- CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
-
-#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1 && SLJIT_MIPS_REV < 6)
-
- if (SLJIT_UNLIKELY(src & SLJIT_IMM)) {
-#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
- if (type & SLJIT_32)
- srcw = (sljit_s32)srcw;
-#endif
- FAIL_IF(load_immediate(compiler, DR(TMP_REG1), srcw));
- src = TMP_REG1;
- srcw = 0;
- }
+static sljit_ins get_select_cc(sljit_s32 type, sljit_s32 is_float)
+{
switch (type & ~SLJIT_32) {
case SLJIT_EQUAL:
- ins = MOVZ | TA(EQUAL_FLAG);
- break;
+ return (is_float ? MOVZ_S : MOVZ) | TA(EQUAL_FLAG);
case SLJIT_NOT_EQUAL:
- ins = MOVN | TA(EQUAL_FLAG);
- break;
+ return (is_float ? MOVN_S : MOVN) | TA(EQUAL_FLAG);
case SLJIT_LESS:
case SLJIT_GREATER:
case SLJIT_SIG_LESS:
case SLJIT_SIG_GREATER:
case SLJIT_OVERFLOW:
- ins = MOVN | TA(OTHER_FLAG);
- break;
+ case SLJIT_CARRY:
+ return (is_float ? MOVN_S : MOVN) | TA(OTHER_FLAG);
case SLJIT_GREATER_EQUAL:
case SLJIT_LESS_EQUAL:
case SLJIT_SIG_GREATER_EQUAL:
case SLJIT_SIG_LESS_EQUAL:
case SLJIT_NOT_OVERFLOW:
- ins = MOVZ | TA(OTHER_FLAG);
- break;
+ case SLJIT_NOT_CARRY:
+ return (is_float ? MOVZ_S : MOVZ) | TA(OTHER_FLAG);
case SLJIT_F_EQUAL:
case SLJIT_F_LESS:
case SLJIT_F_LESS_EQUAL:
@@ -3341,8 +3711,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil
case SLJIT_UNORDERED_OR_LESS_EQUAL:
case SLJIT_ORDERED_LESS_EQUAL:
case SLJIT_UNORDERED:
- ins = MOVT;
- break;
+ return is_float ? MOVT_S : MOVT;
case SLJIT_F_NOT_EQUAL:
case SLJIT_F_GREATER_EQUAL:
case SLJIT_F_GREATER:
@@ -3353,21 +3722,159 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compil
case SLJIT_ORDERED_GREATER:
case SLJIT_UNORDERED_OR_GREATER:
case SLJIT_ORDERED:
- ins = MOVF;
- break;
+ return is_float ? MOVF_S : MOVF;
default:
- ins = MOVZ | TA(OTHER_FLAG);
SLJIT_UNREACHABLE();
- break;
+ return (is_float ? MOVZ_S : MOVZ) | TA(OTHER_FLAG);
}
+}
- return push_inst(compiler, ins | S(src) | D(dst_reg), DR(dst_reg));
+#endif /* SLJIT_MIPS_REV >= 1 */
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_reg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_reg)
+{
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+ sljit_s32 inp_flags = ((type & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA;
+ sljit_ins mov_ins = (type & SLJIT_32) ? ADDU : DADDU;
+#else /* !SLJIT_CONFIG_MIPS_64 */
+ sljit_s32 inp_flags = WORD_DATA | LOAD_DATA;
+ sljit_ins mov_ins = ADDU;
+#endif /* SLJIT_CONFIG_MIPS_64 */
+
+#if !(defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1 && SLJIT_MIPS_REV < 6)
+ struct sljit_label *label;
+ struct sljit_jump *jump;
+#endif /* !(SLJIT_MIPS_REV >= 1 && SLJIT_MIPS_REV < 6) */
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1 && SLJIT_MIPS_REV < 6)
+ if (src1 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, inp_flags, DR(TMP_REG2), src1, src1w));
+ src1 = TMP_REG2;
+ } else if (src1 == SLJIT_IMM) {
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+ if (type & SLJIT_32)
+ src1w = (sljit_s32)src1w;
+#endif
+ FAIL_IF(load_immediate(compiler, DR(TMP_REG1), src1w));
+ src1 = TMP_REG1;
+ }
+
+ if (dst_reg != src2_reg) {
+ if (dst_reg == src1) {
+ src1 = src2_reg;
+ type ^= 0x1;
+ } else
+ FAIL_IF(push_inst(compiler, mov_ins | S(src2_reg) | TA(0) | D(dst_reg), DR(dst_reg)));
+ }
+
+ return push_inst(compiler, get_select_cc(type, 0) | S(src1) | D(dst_reg), DR(dst_reg));
+
+#else /* SLJIT_MIPS_REV < 1 || SLJIT_MIPS_REV >= 6 */
+ if (dst_reg != src2_reg) {
+ if (dst_reg == src1) {
+ src1 = src2_reg;
+ src1w = 0;
+ type ^= 0x1;
+ } else {
+ if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) {
+ FAIL_IF(push_inst(compiler, ADDU_W | S(dst_reg) | TA(0) | D(TMP_REG2), DR(TMP_REG2)));
+
+ if ((src1 & REG_MASK) == dst_reg)
+ src1 = (src1 & ~REG_MASK) | TMP_REG2;
+
+ if (OFFS_REG(src1) == dst_reg)
+ src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG2);
+ }
+
+ FAIL_IF(push_inst(compiler, mov_ins | S(src2_reg) | TA(0) | D(dst_reg), DR(dst_reg)));
+ }
+ }
+
+ SLJIT_SKIP_CHECKS(compiler);
+ jump = sljit_emit_jump(compiler, (type & ~SLJIT_32) ^ 0x1);
+ FAIL_IF(!jump);
+
+ if (src1 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, inp_flags, DR(dst_reg), src1, src1w));
+ } else if (src1 == SLJIT_IMM) {
+#if (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
+ if (type & SLJIT_32)
+ src1w = (sljit_s32)src1w;
+#endif /* SLJIT_CONFIG_MIPS_64 */
+ FAIL_IF(load_immediate(compiler, DR(dst_reg), src1w));
+ } else
+ FAIL_IF(push_inst(compiler, mov_ins | S(src1) | TA(0) | D(dst_reg), DR(dst_reg)));
+
+ SLJIT_SKIP_CHECKS(compiler);
+ label = sljit_emit_label(compiler);
+ FAIL_IF(!label);
+
+ sljit_set_label(jump, label);
+ return SLJIT_SUCCESS;
+#endif /* SLJIT_MIPS_REV >= 1 */
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_freg)
+{
+#if !(defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1 && SLJIT_MIPS_REV < 6)
+ struct sljit_label *label;
+ struct sljit_jump *jump;
+#endif /* !(SLJIT_MIPS_REV >= 1 && SLJIT_MIPS_REV < 6) */
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fselect(compiler, type, dst_freg, src1, src1w, src2_freg));
+
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+
+ if (dst_freg != src2_freg) {
+ if (dst_freg == src1) {
+ src1 = src2_freg;
+ src1w = 0;
+ type ^= 0x1;
+ } else
+ FAIL_IF(push_inst(compiler, MOV_fmt(FMT(type)) | FS(src2_freg) | FD(dst_freg), MOVABLE_INS));
+ }
+
+#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 1 && SLJIT_MIPS_REV < 6)
+ if (src1 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(type) | LOAD_DATA, FR(TMP_FREG1), src1, src1w));
+ src1 = TMP_FREG1;
+ }
+
+ return push_inst(compiler, get_select_cc(type, 1) | FMT(type) | FS(src1) | FD(dst_freg), MOVABLE_INS);
#else /* SLJIT_MIPS_REV < 1 || SLJIT_MIPS_REV >= 6 */
- return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);
+ SLJIT_SKIP_CHECKS(compiler);
+ jump = sljit_emit_jump(compiler, (type & ~SLJIT_32) ^ 0x1);
+ FAIL_IF(!jump);
+
+ if (src1 & SLJIT_MEM)
+ FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(type) | LOAD_DATA, FR(dst_freg), src1, src1w));
+ else
+ FAIL_IF(push_inst(compiler, MOV_fmt(FMT(type)) | FS(src1) | FD(dst_freg), MOVABLE_INS));
+
+ SLJIT_SKIP_CHECKS(compiler);
+ label = sljit_emit_label(compiler);
+ FAIL_IF(!label);
+
+ sljit_set_label(jump, label);
+ return SLJIT_SUCCESS;
#endif /* SLJIT_MIPS_REV >= 1 */
}
+#undef FLOAT_DATA
+#undef FMT
+
static sljit_s32 update_mem_addr(struct sljit_compiler *compiler, sljit_s32 *mem, sljit_sw *memw, sljit_s16 max_offset)
{
sljit_s32 arg = *mem;
@@ -3410,21 +3917,33 @@ static sljit_s32 update_mem_addr(struct sljit_compiler *compiler, sljit_s32 *mem
}
#if (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
-#define MEM16_IMM_FIRST(memw) IMM((memw) + 1)
-#define MEM16_IMM_SECOND(memw) IMM(memw)
-#define MEMF64_FS_FIRST(freg) FS(freg)
-#define MEMF64_FS_SECOND(freg) (FS(freg) | ((sljit_ins)1 << 11))
+#define IMM_LEFT(memw) IMM((memw) + SSIZE_OF(sw) - 1)
+#define IMM_RIGHT(memw) IMM(memw)
+#define IMM_32_LEFT(memw) IMM((memw) + SSIZE_OF(s32) - 1)
+#define IMM_32_RIGHT(memw) IMM(memw)
+#define IMM_F64_FIRST_LEFT(memw) IMM((memw) + SSIZE_OF(s32) - 1)
+#define IMM_F64_FIRST_RIGHT(memw) IMM(memw)
+#define IMM_F64_SECOND_LEFT(memw) IMM((memw) + SSIZE_OF(f64) - 1)
+#define IMM_F64_SECOND_RIGHT(memw) IMM((memw) + SSIZE_OF(s32))
+#define IMM_16_FIRST(memw) IMM((memw) + 1)
+#define IMM_16_SECOND(memw) IMM(memw)
#else /* !SLJIT_LITTLE_ENDIAN */
-#define MEM16_IMM_FIRST(memw) IMM(memw)
-#define MEM16_IMM_SECOND(memw) IMM((memw) + 1)
-#define MEMF64_FS_FIRST(freg) (FS(freg) | ((sljit_ins)1 << 11))
-#define MEMF64_FS_SECOND(freg) FS(freg)
+#define IMM_LEFT(memw) IMM(memw)
+#define IMM_RIGHT(memw) IMM((memw) + SSIZE_OF(sw) - 1)
+#define IMM_32_LEFT(memw) IMM(memw)
+#define IMM_32_RIGHT(memw) IMM((memw) + SSIZE_OF(s32) - 1)
+#define IMM_F64_FIRST_LEFT(memw) IMM((memw) + SSIZE_OF(s32))
+#define IMM_F64_FIRST_RIGHT(memw) IMM((memw) + SSIZE_OF(f64) - 1)
+#define IMM_F64_SECOND_LEFT(memw) IMM(memw)
+#define IMM_F64_SECOND_RIGHT(memw) IMM((memw) + SSIZE_OF(s32) - 1)
+#define IMM_16_FIRST(memw) IMM(memw)
+#define IMM_16_SECOND(memw) IMM((memw) + 1)
#endif /* SLJIT_LITTLE_ENDIAN */
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
-#define MEM_CHECK_UNALIGNED(type) ((type) & (SLJIT_MEM_UNALIGNED | SLJIT_MEM_UNALIGNED_16))
+#define MEM_CHECK_UNALIGNED(type) ((type) & (SLJIT_MEM_UNALIGNED | SLJIT_MEM_ALIGNED_16))
#else /* !SLJIT_CONFIG_MIPS_32 */
-#define MEM_CHECK_UNALIGNED(type) ((type) & (SLJIT_MEM_UNALIGNED | SLJIT_MEM_UNALIGNED_16 | SLJIT_MEM_UNALIGNED_32))
+#define MEM_CHECK_UNALIGNED(type) ((type) & (SLJIT_MEM_UNALIGNED | SLJIT_MEM_ALIGNED_16 | SLJIT_MEM_ALIGNED_32))
#endif /* SLJIT_CONFIG_MIPS_32 */
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type,
@@ -3461,10 +3980,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compile
ins_right = ((type & SLJIT_MEM_STORE) ? SDR : LDR) | S(mem);
#endif /* SLJIT_CONFIG_MIPS_32 */
- FAIL_IF(push_inst(compiler, ins | T(REG_PAIR_FIRST(reg)) | IMM(memw), DR(REG_PAIR_FIRST(reg))));
- FAIL_IF(push_inst(compiler, ins_right | T(REG_PAIR_FIRST(reg)) | IMM(memw + (SSIZE_OF(sw) - 1)), DR(REG_PAIR_FIRST(reg))));
- FAIL_IF(push_inst(compiler, ins | T(REG_PAIR_SECOND(reg)) | IMM(memw + SSIZE_OF(sw)), DR(REG_PAIR_SECOND(reg))));
- return push_inst(compiler, ins_right | T(REG_PAIR_SECOND(reg)) | IMM((memw + 2 * SSIZE_OF(sw) - 1)), DR(REG_PAIR_SECOND(reg)));
+ FAIL_IF(push_inst(compiler, ins | T(REG_PAIR_FIRST(reg)) | IMM_LEFT(memw), DR(REG_PAIR_FIRST(reg))));
+ FAIL_IF(push_inst(compiler, ins_right | T(REG_PAIR_FIRST(reg)) | IMM_RIGHT(memw), DR(REG_PAIR_FIRST(reg))));
+ FAIL_IF(push_inst(compiler, ins | T(REG_PAIR_SECOND(reg)) | IMM_LEFT(memw + SSIZE_OF(sw)), DR(REG_PAIR_SECOND(reg))));
+ return push_inst(compiler, ins_right | T(REG_PAIR_SECOND(reg)) | IMM_RIGHT(memw + SSIZE_OF(sw)), DR(REG_PAIR_SECOND(reg)));
}
#endif /* !(SLJIT_MIPS_REV >= 6) */
@@ -3505,8 +4024,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compile
if (type & SLJIT_MEM_STORE) {
FAIL_IF(push_inst(compiler, SRA_W | T(reg) | D(TMP_REG2) | SH_IMM(8), DR(TMP_REG2)));
- FAIL_IF(push_inst(compiler, data_transfer_insts[BYTE_DATA] | S(mem) | T(TMP_REG2) | MEM16_IMM_FIRST(memw), MOVABLE_INS));
- return push_inst(compiler, data_transfer_insts[BYTE_DATA] | S(mem) | T(reg) | MEM16_IMM_SECOND(memw), MOVABLE_INS);
+ FAIL_IF(push_inst(compiler, data_transfer_insts[BYTE_DATA] | S(mem) | T(TMP_REG2) | IMM_16_FIRST(memw), MOVABLE_INS));
+ return push_inst(compiler, data_transfer_insts[BYTE_DATA] | S(mem) | T(reg) | IMM_16_SECOND(memw), MOVABLE_INS);
}
flags = BYTE_DATA | LOAD_DATA;
@@ -3514,15 +4033,15 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compile
if (op == SLJIT_MOV_S16)
flags |= SIGNED_DATA;
- FAIL_IF(push_inst(compiler, data_transfer_insts[flags] | S(mem) | T(TMP_REG2) | MEM16_IMM_FIRST(memw), DR(TMP_REG2)));
- FAIL_IF(push_inst(compiler, data_transfer_insts[BYTE_DATA | LOAD_DATA] | S(mem) | T(reg) | MEM16_IMM_SECOND(memw), DR(reg)));
+ FAIL_IF(push_inst(compiler, data_transfer_insts[flags] | S(mem) | T(TMP_REG2) | IMM_16_FIRST(memw), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, data_transfer_insts[BYTE_DATA | LOAD_DATA] | S(mem) | T(reg) | IMM_16_SECOND(memw), DR(reg)));
FAIL_IF(push_inst(compiler, SLL_W | T(TMP_REG2) | D(TMP_REG2) | SH_IMM(8), DR(TMP_REG2)));
return push_inst(compiler, OR | S(reg) | T(TMP_REG2) | D(reg), DR(reg));
case SLJIT_MOV:
case SLJIT_MOV_P:
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
- if (type & SLJIT_MEM_UNALIGNED_32) {
+ if (type & SLJIT_MEM_ALIGNED_32) {
flags = WORD_DATA;
if (!(type & SLJIT_MEM_STORE))
flags |= LOAD_DATA;
@@ -3534,8 +4053,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compile
SLJIT_ASSERT(FAST_IS_REG(mem) && mem != TMP_REG2);
if (type & SLJIT_MEM_STORE) {
- FAIL_IF(push_inst(compiler, SDL | S(mem) | T(reg) | IMM(memw), MOVABLE_INS));
- return push_inst(compiler, SDR | S(mem) | T(reg) | IMM(memw + 7), MOVABLE_INS);
+ FAIL_IF(push_inst(compiler, SDL | S(mem) | T(reg) | IMM_LEFT(memw), MOVABLE_INS));
+ return push_inst(compiler, SDR | S(mem) | T(reg) | IMM_RIGHT(memw), MOVABLE_INS);
}
if (mem == reg) {
@@ -3543,8 +4062,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compile
mem = TMP_REG1;
}
- FAIL_IF(push_inst(compiler, LDL | S(mem) | T(reg) | IMM(memw), DR(reg)));
- return push_inst(compiler, LDR | S(mem) | T(reg) | IMM(memw + 7), DR(reg));
+ FAIL_IF(push_inst(compiler, LDL | S(mem) | T(reg) | IMM_LEFT(memw), DR(reg)));
+ return push_inst(compiler, LDR | S(mem) | T(reg) | IMM_RIGHT(memw), DR(reg));
#endif /* SLJIT_CONFIG_MIPS_32 */
}
@@ -3552,8 +4071,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compile
SLJIT_ASSERT(FAST_IS_REG(mem) && mem != TMP_REG2);
if (type & SLJIT_MEM_STORE) {
- FAIL_IF(push_inst(compiler, SWL | S(mem) | T(reg) | IMM(memw), MOVABLE_INS));
- return push_inst(compiler, SWR | S(mem) | T(reg) | IMM(memw + 3), MOVABLE_INS);
+ FAIL_IF(push_inst(compiler, SWL | S(mem) | T(reg) | IMM_32_LEFT(memw), MOVABLE_INS));
+ return push_inst(compiler, SWR | S(mem) | T(reg) | IMM_32_RIGHT(memw), MOVABLE_INS);
}
if (mem == reg) {
@@ -3561,18 +4080,18 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compile
mem = TMP_REG1;
}
- FAIL_IF(push_inst(compiler, LWL | S(mem) | T(reg) | IMM(memw), DR(reg)));
+ FAIL_IF(push_inst(compiler, LWL | S(mem) | T(reg) | IMM_32_LEFT(memw), DR(reg)));
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
- return push_inst(compiler, LWR | S(mem) | T(reg) | IMM(memw + 3), DR(reg));
+ return push_inst(compiler, LWR | S(mem) | T(reg) | IMM_32_RIGHT(memw), DR(reg));
#else /* !SLJIT_CONFIG_MIPS_32 */
- FAIL_IF(push_inst(compiler, LWR | S(mem) | T(reg) | IMM(memw + 3), DR(reg)));
+ FAIL_IF(push_inst(compiler, LWR | S(mem) | T(reg) | IMM_32_RIGHT(memw), DR(reg)));
if (op != SLJIT_MOV_U32)
return SLJIT_SUCCESS;
#if (defined SLJIT_MIPS_REV && SLJIT_MIPS_REV >= 2)
- return push_inst(compiler, DINSU | T(reg) | SA(0) | (31 << 11) | (0 << 11), DR(reg));
-#else /* SLJIT_MIPS_REV < 1 */
+ return push_inst(compiler, DINSU | T(reg) | SA(0) | (31 << 11), DR(reg));
+#else /* SLJIT_MIPS_REV < 2 */
FAIL_IF(push_inst(compiler, DSLL32 | T(reg) | D(reg) | SH_IMM(0), DR(reg)));
return push_inst(compiler, DSRL32 | T(reg) | D(reg) | SH_IMM(0), DR(reg));
#endif /* SLJIT_MIPS_REV >= 2 */
@@ -3595,77 +4114,97 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fmem(struct sljit_compiler *compil
if (type & SLJIT_MEM_STORE) {
if (type & SLJIT_32) {
FAIL_IF(push_inst(compiler, MFC1 | T(TMP_REG2) | FS(freg), DR(TMP_REG2)));
-#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 3)
+#if !defined(SLJIT_MIPS_REV) || (SLJIT_CONFIG_MIPS_32 && SLJIT_MIPS_REV <= 1)
FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
-#endif
- FAIL_IF(push_inst(compiler, SWL | S(mem) | T(TMP_REG2) | IMM(memw), MOVABLE_INS));
- return push_inst(compiler, SWR | S(mem) | T(TMP_REG2) | IMM(memw + 3), MOVABLE_INS);
+#endif /* MIPS III */
+ FAIL_IF(push_inst(compiler, SWL | S(mem) | T(TMP_REG2) | IMM_32_LEFT(memw), MOVABLE_INS));
+ return push_inst(compiler, SWR | S(mem) | T(TMP_REG2) | IMM_32_RIGHT(memw), MOVABLE_INS);
}
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
- FAIL_IF(push_inst(compiler, MFC1 | T(TMP_REG2) | MEMF64_FS_FIRST(freg), DR(TMP_REG2)));
-#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 3)
+ FAIL_IF(push_inst(compiler, MFC1 | T(TMP_REG2) | FS(freg), DR(TMP_REG2)));
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+#endif /* MIPS III */
+ FAIL_IF(push_inst(compiler, SWL | S(mem) | T(TMP_REG2) | IMM_F64_FIRST_LEFT(memw), MOVABLE_INS));
+ FAIL_IF(push_inst(compiler, SWR | S(mem) | T(TMP_REG2) | IMM_F64_FIRST_RIGHT(memw), MOVABLE_INS));
+ switch (cpu_feature_list & CPU_FEATURE_FR) {
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
+ case CPU_FEATURE_FR:
+ FAIL_IF(push_inst(compiler, MFHC1 | T(TMP_REG2) | FS(freg), DR(TMP_REG2)));
+ break;
+#endif /* SLJIT_MIPS_REV >= 2 */
+ default:
+ FAIL_IF(push_inst(compiler, MFC1 | T(TMP_REG2) | FS(freg) | (1 << 11), DR(TMP_REG2)));
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
+ FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
#endif
- FAIL_IF(push_inst(compiler, SWL | S(mem) | T(TMP_REG2) | IMM(memw), MOVABLE_INS));
- FAIL_IF(push_inst(compiler, SWR | S(mem) | T(TMP_REG2) | IMM(memw + 3), MOVABLE_INS));
+ break;
+ }
- FAIL_IF(push_inst(compiler, MFC1 | T(TMP_REG2) | MEMF64_FS_SECOND(freg), DR(TMP_REG2)));
-#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 3)
- FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
-#endif
- FAIL_IF(push_inst(compiler, SWL | S(mem) | T(TMP_REG2) | IMM(memw + 4), MOVABLE_INS));
- return push_inst(compiler, SWR | S(mem) | T(TMP_REG2) | IMM(memw + 7), MOVABLE_INS);
+ FAIL_IF(push_inst(compiler, SWL | S(mem) | T(TMP_REG2) | IMM_F64_SECOND_LEFT(memw), MOVABLE_INS));
+ return push_inst(compiler, SWR | S(mem) | T(TMP_REG2) | IMM_F64_SECOND_RIGHT(memw), MOVABLE_INS);
#else /* !SLJIT_CONFIG_MIPS_32 */
- FAIL_IF(push_inst(compiler, MFC1 | (1 << 21) | T(TMP_REG2) | FS(freg), DR(TMP_REG2)));
-#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 3)
+ FAIL_IF(push_inst(compiler, DMFC1 | T(TMP_REG2) | FS(freg), DR(TMP_REG2)));
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
-#endif
- FAIL_IF(push_inst(compiler, SDL | S(mem) | T(TMP_REG2) | IMM(memw), MOVABLE_INS));
- return push_inst(compiler, SDR | S(mem) | T(TMP_REG2) | IMM(memw + 7), MOVABLE_INS);
+#endif /* MIPS III */
+ FAIL_IF(push_inst(compiler, SDL | S(mem) | T(TMP_REG2) | IMM_LEFT(memw), MOVABLE_INS));
+ return push_inst(compiler, SDR | S(mem) | T(TMP_REG2) | IMM_RIGHT(memw), MOVABLE_INS);
#endif /* SLJIT_CONFIG_MIPS_32 */
}
if (type & SLJIT_32) {
- FAIL_IF(push_inst(compiler, LWL | S(mem) | T(TMP_REG2) | IMM(memw), DR(TMP_REG2)));
- FAIL_IF(push_inst(compiler, LWR | S(mem) | T(TMP_REG2) | IMM(memw + 3), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, LWL | S(mem) | T(TMP_REG2) | IMM_32_LEFT(memw), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, LWR | S(mem) | T(TMP_REG2) | IMM_32_RIGHT(memw), DR(TMP_REG2)));
FAIL_IF(push_inst(compiler, MTC1 | T(TMP_REG2) | FS(freg), MOVABLE_INS));
-#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 3)
+#if !defined(SLJIT_MIPS_REV) || (SLJIT_CONFIG_MIPS_32 && SLJIT_MIPS_REV <= 1)
FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
-#endif
+#endif /* MIPS III */
return SLJIT_SUCCESS;
}
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
- FAIL_IF(push_inst(compiler, LWL | S(mem) | T(TMP_REG2) | IMM(memw), DR(TMP_REG2)));
- FAIL_IF(push_inst(compiler, LWR | S(mem) | T(TMP_REG2) | IMM(memw + 3), DR(TMP_REG2)));
- FAIL_IF(push_inst(compiler, MTC1 | T(TMP_REG2) | MEMF64_FS_FIRST(freg), MOVABLE_INS));
-
- FAIL_IF(push_inst(compiler, LWL | S(mem) | T(TMP_REG2) | IMM(memw + 4), DR(TMP_REG2)));
- FAIL_IF(push_inst(compiler, LWR | S(mem) | T(TMP_REG2) | IMM(memw + 7), DR(TMP_REG2)));
- FAIL_IF(push_inst(compiler, MTC1 | T(TMP_REG2) | MEMF64_FS_SECOND(freg), MOVABLE_INS));
-#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 3)
- FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
-#endif
+ FAIL_IF(push_inst(compiler, LWL | S(mem) | T(TMP_REG2) | IMM_F64_FIRST_LEFT(memw), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, LWR | S(mem) | T(TMP_REG2) | IMM_F64_FIRST_RIGHT(memw), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, MTC1 | T(TMP_REG2) | FS(freg), MOVABLE_INS));
+
+ FAIL_IF(push_inst(compiler, LWL | S(mem) | T(TMP_REG2) | IMM_F64_SECOND_LEFT(memw), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, LWR | S(mem) | T(TMP_REG2) | IMM_F64_SECOND_RIGHT(memw), DR(TMP_REG2)));
+ switch (cpu_feature_list & CPU_FEATURE_FR) {
+#if defined(SLJIT_MIPS_REV) && SLJIT_MIPS_REV >= 2
+ case CPU_FEATURE_FR:
+ return push_inst(compiler, MTHC1 | T(TMP_REG2) | FS(freg), MOVABLE_INS);
+#endif /* SLJIT_MIPS_REV >= 2 */
+ default:
+ FAIL_IF(push_inst(compiler, MTC1 | T(TMP_REG2) | FS(freg) | (1 << 11), MOVABLE_INS));
+ break;
+ }
#else /* !SLJIT_CONFIG_MIPS_32 */
- FAIL_IF(push_inst(compiler, LDL | S(mem) | T(TMP_REG2) | IMM(memw), DR(TMP_REG2)));
- FAIL_IF(push_inst(compiler, LDR | S(mem) | T(TMP_REG2) | IMM(memw + 7), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, LDL | S(mem) | T(TMP_REG2) | IMM_LEFT(memw), DR(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, LDR | S(mem) | T(TMP_REG2) | IMM_RIGHT(memw), DR(TMP_REG2)));
- FAIL_IF(push_inst(compiler, MTC1 | (1 << 21) | T(TMP_REG2) | FS(freg), MOVABLE_INS));
-#if (!defined SLJIT_MIPS_REV || SLJIT_MIPS_REV <= 3)
- FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
-#endif
+ FAIL_IF(push_inst(compiler, DMTC1 | T(TMP_REG2) | FS(freg), MOVABLE_INS));
#endif /* SLJIT_CONFIG_MIPS_32 */
+#if !defined(SLJIT_MIPS_REV) || SLJIT_MIPS_REV <= 1
+ FAIL_IF(push_inst(compiler, NOP, UNMOVABLE_INS));
+#endif /* MIPS III */
return SLJIT_SUCCESS;
}
#endif /* !SLJIT_MIPS_REV || SLJIT_MIPS_REV < 6 */
-#undef MEM16_IMM_FIRST
-#undef MEM16_IMM_SECOND
-#undef MEMF64_FS_FIRST
-#undef MEMF64_FS_SECOND
+#undef IMM_16_SECOND
+#undef IMM_16_FIRST
+#undef IMM_F64_SECOND_RIGHT
+#undef IMM_F64_SECOND_LEFT
+#undef IMM_F64_FIRST_RIGHT
+#undef IMM_F64_FIRST_LEFT
+#undef IMM_32_RIGHT
+#undef IMM_32_LEFT
+#undef IMM_RIGHT
+#undef IMM_LEFT
#undef MEM_CHECK_UNALIGNED
#undef TO_ARGW_HI
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativePPC_32.c b/src/3rdparty/pcre2/src/sljit/sljitNativePPC_32.c
index 9449e4b9d7..2352fad5d4 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativePPC_32.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativePPC_32.c
@@ -85,10 +85,6 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
}
return SLJIT_SUCCESS;
- case SLJIT_NOT:
- SLJIT_ASSERT(src1 == TMP_REG1);
- return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2));
-
case SLJIT_CLZ:
SLJIT_ASSERT(src1 == TMP_REG1);
return push_inst(compiler, CNTLZW | S(src2) | A(dst));
@@ -246,6 +242,10 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
FAIL_IF(push_inst(compiler, XORI | S(src1) | A(dst) | IMM(imm)));
return push_inst(compiler, XORIS | S(dst) | A(dst) | IMM(imm >> 16));
}
+ if (flags & ALT_FORM4) {
+ SLJIT_ASSERT(src1 == TMP_REG1);
+ return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2));
+ }
return push_inst(compiler, XOR | RC(flags) | S(src1) | A(dst) | B(src2));
case SLJIT_SHL:
@@ -325,6 +325,151 @@ static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_
return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value));
}
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+ sljit_s32 invert_sign = 1;
+
+ if (src == SLJIT_IMM) {
+ FAIL_IF(load_immediate(compiler, TMP_REG1, srcw ^ (sljit_sw)0x80000000));
+ src = TMP_REG1;
+ invert_sign = 0;
+ } else if (!FAST_IS_REG(src)) {
+ FAIL_IF(emit_op_mem(compiler, WORD_DATA | SIGNED_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));
+ src = TMP_REG1;
+ }
+
+ /* First, a special double precision floating point value is constructed:
+ (2^53 + (src xor (2^31)))
+ The upper 32 bits of this number is a constant, and the lower 32 bits
+ is simply the value of the source argument. The xor 2^31 operation adds
+ 0x80000000 to the source argument, which moves it into the 0 - 0xffffffff
+ range. Finally we substract 2^53 + 2^31 to get the converted value. */
+ FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG2) | A(0) | 0x4330));
+ if (invert_sign)
+ FAIL_IF(push_inst(compiler, XORIS | S(src) | A(TMP_REG1) | 0x8000));
+ FAIL_IF(push_inst(compiler, STW | S(TMP_REG2) | A(SLJIT_SP) | TMP_MEM_OFFSET_HI));
+ FAIL_IF(push_inst(compiler, STW | S(TMP_REG1) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
+ FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG1) | A(0) | 0x8000));
+ FAIL_IF(push_inst(compiler, LFD | FS(TMP_FREG1) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+ FAIL_IF(push_inst(compiler, STW | S(TMP_REG1) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
+ FAIL_IF(push_inst(compiler, LFD | FS(TMP_FREG2) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+
+ FAIL_IF(push_inst(compiler, FSUB | FD(dst_r) | FA(TMP_FREG1) | FB(TMP_FREG2)));
+
+ if (op & SLJIT_32)
+ FAIL_IF(push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r)));
+
+ if (dst & SLJIT_MEM)
+ return emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, TMP_REG1);
+ return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_uw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+ if (src == SLJIT_IMM) {
+ FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+ src = TMP_REG1;
+ } else if (!FAST_IS_REG(src)) {
+ FAIL_IF(emit_op_mem(compiler, WORD_DATA | SIGNED_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));
+ src = TMP_REG1;
+ }
+
+ /* First, a special double precision floating point value is constructed:
+ (2^53 + src)
+ The upper 32 bits of this number is a constant, and the lower 32 bits
+ is simply the value of the source argument. Finally we substract 2^53
+ to get the converted value. */
+ FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG2) | A(0) | 0x4330));
+ FAIL_IF(push_inst(compiler, STW | S(src) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
+ FAIL_IF(push_inst(compiler, STW | S(TMP_REG2) | A(SLJIT_SP) | TMP_MEM_OFFSET_HI));
+
+ FAIL_IF(push_inst(compiler, LFD | FS(TMP_FREG1) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+ FAIL_IF(push_inst(compiler, STW | S(TMP_ZERO) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
+ FAIL_IF(push_inst(compiler, LFD | FS(TMP_FREG2) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+
+ FAIL_IF(push_inst(compiler, FSUB | FD(dst_r) | FA(TMP_FREG1) | FB(TMP_FREG2)));
+
+ if (op & SLJIT_32)
+ FAIL_IF(push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r)));
+
+ if (dst & SLJIT_MEM)
+ return emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, TMP_REG1);
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f64 value)
+{
+ union {
+ sljit_s32 imm[2];
+ sljit_f64 value;
+ } u;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fset64(compiler, freg, value));
+
+ u.value = value;
+
+ if (u.imm[0] != 0)
+ FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm[0]));
+ if (u.imm[1] != 0)
+ FAIL_IF(load_immediate(compiler, TMP_REG2, u.imm[1]));
+
+ /* Saved in the same endianness. */
+ FAIL_IF(push_inst(compiler, STW | S(u.imm[0] != 0 ? TMP_REG1 : TMP_ZERO) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+ FAIL_IF(push_inst(compiler, STW | S(u.imm[1] != 0 ? TMP_REG2 : TMP_ZERO) | A(SLJIT_SP) | (TMP_MEM_OFFSET + sizeof(sljit_s32))));
+ return push_inst(compiler, LFD | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 freg, sljit_s32 reg)
+{
+ sljit_s32 reg2 = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+ if (op & SLJIT_32) {
+ if (op == SLJIT_COPY32_TO_F32) {
+ FAIL_IF(push_inst(compiler, STW | S(reg) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+ return push_inst(compiler, LFS | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET);
+ }
+
+ FAIL_IF(push_inst(compiler, STFS | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+ return push_inst(compiler, LWZ | S(reg) | A(SLJIT_SP) | TMP_MEM_OFFSET);
+ }
+
+ if (reg & REG_PAIR_MASK) {
+ reg2 = REG_PAIR_SECOND(reg);
+ reg = REG_PAIR_FIRST(reg);
+ }
+
+ if (op == SLJIT_COPY_TO_F64) {
+ FAIL_IF(push_inst(compiler, STW | S(reg) | A(SLJIT_SP) | TMP_MEM_OFFSET_HI));
+
+ if (reg2 != 0)
+ FAIL_IF(push_inst(compiler, STW | S(reg2) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
+ else
+ FAIL_IF(push_inst(compiler, STFD | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
+
+ return push_inst(compiler, LFD | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET);
+ }
+
+ FAIL_IF(push_inst(compiler, STFD | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+
+ if (reg2 != 0)
+ FAIL_IF(push_inst(compiler, LWZ | S(reg2) | A(SLJIT_SP) | TMP_MEM_OFFSET_LO));
+
+ return push_inst(compiler, LWZ | S(reg) | A(SLJIT_SP) | TMP_MEM_OFFSET_HI);
+}
+
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
{
sljit_ins *inst = (sljit_ins *)addr;
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativePPC_64.c b/src/3rdparty/pcre2/src/sljit/sljitNativePPC_64.c
index 80549108bf..b3cf9d074d 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativePPC_64.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativePPC_64.c
@@ -49,7 +49,7 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg,
if (imm <= SIMM_MAX && imm >= SIMM_MIN)
return push_inst(compiler, ADDI | D(reg) | A(0) | IMM(imm));
- if (!(imm & ~0xffff))
+ if (((sljit_uw)imm >> 16) == 0)
return push_inst(compiler, ORI | S(TMP_ZERO) | A(reg) | IMM(imm));
if (imm <= 0x7fffffffl && imm >= -0x80000000l) {
@@ -57,6 +57,11 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 reg,
return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm)) : SLJIT_SUCCESS;
}
+ if (((sljit_uw)imm >> 32) == 0) {
+ FAIL_IF(push_inst(compiler, ORIS | S(TMP_ZERO) | A(reg) | IMM(imm >> 16)));
+ return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm)) : SLJIT_SUCCESS;
+ }
+
/* Count leading zeroes. */
tmp = (sljit_uw)((imm >= 0) ? imm : ~imm);
ASM_SLJIT_CLZ(tmp, shift);
@@ -198,11 +203,6 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
}
return SLJIT_SUCCESS;
- case SLJIT_NOT:
- SLJIT_ASSERT(src1 == TMP_REG1);
- UN_EXTS();
- return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2));
-
case SLJIT_CLZ:
SLJIT_ASSERT(src1 == TMP_REG1);
return push_inst(compiler, ((flags & ALT_FORM1) ? CNTLZW : CNTLZD) | S(src2) | A(dst));
@@ -399,6 +399,11 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
FAIL_IF(push_inst(compiler, XORI | S(src1) | A(dst) | IMM(imm)));
return push_inst(compiler, XORIS | S(dst) | A(dst) | IMM(imm >> 16));
}
+ if (flags & ALT_FORM4) {
+ SLJIT_ASSERT(src1 == TMP_REG1);
+ UN_EXTS();
+ return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2));
+ }
return push_inst(compiler, XOR | RC(flags) | S(src1) | A(dst) | B(src2));
case SLJIT_SHL:
@@ -563,6 +568,141 @@ static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_
return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value));
}
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+ if (src == SLJIT_IMM) {
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
+ srcw = (sljit_s32)srcw;
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+ src = TMP_REG1;
+ } else if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) {
+ if (FAST_IS_REG(src))
+ FAIL_IF(push_inst(compiler, EXTSW | S(src) | A(TMP_REG1)));
+ else
+ FAIL_IF(emit_op_mem(compiler, INT_DATA | SIGNED_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));
+ src = TMP_REG1;
+ }
+
+ if (FAST_IS_REG(src)) {
+ FAIL_IF(push_inst(compiler, STD | S(src) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+ FAIL_IF(push_inst(compiler, LFD | FS(TMP_FREG1) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+ } else
+ FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, src, srcw, TMP_REG1));
+
+ FAIL_IF(push_inst(compiler, FCFID | FD(dst_r) | FB(TMP_FREG1)));
+
+ if (op & SLJIT_32)
+ FAIL_IF(push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r)));
+
+ if (dst & SLJIT_MEM)
+ return emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, TMP_REG1);
+ return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_uw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
+
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_U32) {
+ if (src == SLJIT_IMM) {
+ FAIL_IF(load_immediate(compiler, TMP_REG1, (sljit_u32)srcw));
+ src = TMP_REG1;
+ } else {
+ if (FAST_IS_REG(src))
+ FAIL_IF(push_inst(compiler, CLRLDI(TMP_REG1, src, 32)));
+ else
+ FAIL_IF(emit_op_mem(compiler, INT_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));
+ src = TMP_REG1;
+ }
+
+ FAIL_IF(push_inst(compiler, STD | S(src) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+ FAIL_IF(push_inst(compiler, LFD | FS(TMP_FREG1) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+ FAIL_IF(push_inst(compiler, FCFID | FD(dst_r) | FB(TMP_FREG1)));
+ } else {
+ if (src == SLJIT_IMM) {
+ FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+ src = TMP_REG1;
+ } else if (src & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));
+ src = TMP_REG1;
+ }
+
+ FAIL_IF(push_inst(compiler, CMPI | CRD(0 | 1) | A(src) | 0));
+ FAIL_IF(push_inst(compiler, BCx | (12 << 21) | (0 << 16) | 20));
+ FAIL_IF(push_inst(compiler, STD | S(src) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+ FAIL_IF(push_inst(compiler, LFD | FS(TMP_FREG1) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+ FAIL_IF(push_inst(compiler, FCFID | FD(dst_r) | FB(TMP_FREG1)));
+ FAIL_IF(push_inst(compiler, Bx | ((op & SLJIT_32) ? 36 : 32)));
+
+ if (op & SLJIT_32)
+ FAIL_IF(push_inst(compiler, RLWINM | S(src) | A(TMP_REG2) | RLWI_SH(10) | RLWI_MBE(10, 21)));
+ else
+ FAIL_IF(push_inst(compiler, ANDI | S(src) | A(TMP_REG2) | 0x1));
+
+ /* Shift right. */
+ FAIL_IF(push_inst(compiler, RLDICL | S(src) | A(TMP_REG1) | RLDI_SH(63) | RLDI_MB(1)));
+
+ if (op & SLJIT_32)
+ FAIL_IF(push_inst(compiler, RLDICR | S(TMP_REG1) | A(TMP_REG1) | RLDI_SH(0) | RLDI_ME(53)));
+
+ FAIL_IF(push_inst(compiler, OR | S(TMP_REG1) | A(TMP_REG1) | B(TMP_REG2)));
+
+ FAIL_IF(push_inst(compiler, STD | S(TMP_REG1) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+ FAIL_IF(push_inst(compiler, LFD | FS(TMP_FREG1) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+ FAIL_IF(push_inst(compiler, FCFID | FD(dst_r) | FB(TMP_FREG1)));
+ FAIL_IF(push_inst(compiler, FADD | FD(dst_r) | FA(dst_r) | FB(dst_r)));
+ }
+
+ if (op & SLJIT_32)
+ FAIL_IF(push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r)));
+
+ if (dst & SLJIT_MEM)
+ return emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, TMP_REG1);
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f64 value)
+{
+ union {
+ sljit_sw imm;
+ sljit_f64 value;
+ } u;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fset64(compiler, freg, value));
+
+ u.value = value;
+
+ if (u.imm != 0)
+ FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm));
+
+ FAIL_IF(push_inst(compiler, STD | S(u.imm != 0 ? TMP_REG1 : TMP_ZERO) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+ return push_inst(compiler, LFD | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 freg, sljit_s32 reg)
+{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+ if (GET_OPCODE(op) == SLJIT_COPY_TO_F64) {
+ FAIL_IF(push_inst(compiler, ((op & SLJIT_32) ? STW : STD) | S(reg) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+ return push_inst(compiler, ((op & SLJIT_32) ? LFS : LFD) | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET);
+ }
+
+ FAIL_IF(push_inst(compiler, ((op & SLJIT_32) ? STFS : STFD) | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+ return push_inst(compiler, ((op & SLJIT_32) ? LWZ : LD) | S(reg) | A(SLJIT_SP) | TMP_MEM_OFFSET);
+}
+
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_target, sljit_sw executable_offset)
{
sljit_ins *inst = (sljit_ins*)addr;
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativePPC_common.c b/src/3rdparty/pcre2/src/sljit/sljitNativePPC_common.c
index f387114733..54977f02e3 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativePPC_common.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativePPC_common.c
@@ -132,7 +132,7 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
OE and Rc flag (see ALT_SET_FLAGS). */
#define OE(flags) ((flags) & ALT_SET_FLAGS)
/* Rc flag (see ALT_SET_FLAGS). */
-#define RC(flags) (((flags) & ALT_SET_FLAGS) >> 10)
+#define RC(flags) ((sljit_ins)((flags) & ALT_SET_FLAGS) >> 10)
#define HI(opcode) ((sljit_ins)(opcode) << 26)
#define LO(opcode) ((sljit_ins)(opcode) << 1)
@@ -150,6 +150,9 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
#define BCx (HI(16))
#define BCCTR (HI(19) | LO(528) | (3 << 11))
#define BLR (HI(19) | LO(16) | (0x14 << 21))
+#if defined(_ARCH_PWR10) && _ARCH_PWR10
+#define BRD (HI(31) | LO(187))
+#endif /* POWER10 */
#define CNTLZD (HI(31) | LO(58))
#define CNTLZW (HI(31) | LO(26))
#define CMP (HI(31) | LO(0))
@@ -183,6 +186,12 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
#define FSUBS (HI(59) | LO(20))
#define LD (HI(58) | 0)
#define LFD (HI(50))
+#define LFS (HI(48))
+#if defined(_ARCH_PWR7) && _ARCH_PWR7
+#define LDBRX (HI(31) | LO(532))
+#endif /* POWER7 */
+#define LHBRX (HI(31) | LO(790))
+#define LWBRX (HI(31) | LO(534))
#define LWZ (HI(32))
#define MFCR (HI(31) | LO(19))
#define MFLR (HI(31) | LO(339) | 0x80000)
@@ -219,11 +228,17 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
#define SRD (HI(31) | LO(539))
#define SRW (HI(31) | LO(536))
#define STD (HI(62) | 0)
+#if defined(_ARCH_PWR7) && _ARCH_PWR7
+#define STDBRX (HI(31) | LO(660))
+#endif /* POWER7 */
#define STDU (HI(62) | 1)
#define STDUX (HI(31) | LO(181))
#define STFD (HI(54))
#define STFIWX (HI(31) | LO(983))
+#define STFS (HI(52))
+#define STHBRX (HI(31) | LO(918))
#define STW (HI(36))
+#define STWBRX (HI(31) | LO(662))
#define STWU (HI(37))
#define STWUX (HI(31) | LO(183))
#define SUBF (HI(31) | LO(40))
@@ -253,10 +268,24 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
#define SLWI_W(shift) SLWI(shift)
+#define TMP_MEM_OFFSET (2 * sizeof(sljit_sw))
#else /* !SLJIT_CONFIG_PPC_32 */
#define SLWI_W(shift) SLDI(shift)
+#define TMP_MEM_OFFSET (6 * sizeof(sljit_sw))
#endif /* SLJIT_CONFIG_PPC_32 */
+#if (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
+#define TMP_MEM_OFFSET_LO (TMP_MEM_OFFSET)
+#define TMP_MEM_OFFSET_HI (TMP_MEM_OFFSET + sizeof(sljit_s32))
+#define LWBRX_FIRST_REG S(TMP_REG1)
+#define LWBRX_SECOND_REG S(dst)
+#else /* !SLJIT_LITTLE_ENDIAN */
+#define TMP_MEM_OFFSET_LO (TMP_MEM_OFFSET + sizeof(sljit_s32))
+#define TMP_MEM_OFFSET_HI (TMP_MEM_OFFSET)
+#define LWBRX_FIRST_REG S(dst)
+#define LWBRX_SECOND_REG S(TMP_REG1)
+#endif /* SLJIT_LITTLE_ENDIAN */
+
#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_function_context(void** func_ptr, struct sljit_function_context* context, sljit_uw addr, void* func)
{
@@ -423,6 +452,7 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
reverse_buf(compiler);
#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
+ /* add to compiler->size additional instruction space to hold the trampoline and padding */
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
compiler->size += (compiler->size & 0x1) + (sizeof(struct sljit_function_context) / sizeof(sljit_ins));
#else
@@ -623,7 +653,6 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
compiler->error = SLJIT_ERR_COMPILED;
compiler->executable_offset = executable_offset;
- compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins);
code = (sljit_ins *)SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
@@ -641,8 +670,12 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
SLJIT_UPDATE_WX_FLAGS(code, code_ptr, 1);
#if (defined SLJIT_INDIRECT_CALL && SLJIT_INDIRECT_CALL)
+ compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins) + sizeof(struct sljit_function_context);
+
return code_ptr;
#else
+ compiler->executable_size = (sljit_uw)(code_ptr - code) * sizeof(sljit_ins);
+
return code;
#endif
}
@@ -652,12 +685,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
switch (feature_type) {
case SLJIT_HAS_FPU:
#ifdef SLJIT_IS_FPU_AVAILABLE
- return SLJIT_IS_FPU_AVAILABLE;
+ return (SLJIT_IS_FPU_AVAILABLE) != 0;
#else
/* Available by default. */
return 1;
#endif
-
+ case SLJIT_HAS_REV:
+#if defined(_ARCH_PWR10) && _ARCH_PWR10
+ return 1;
+#else /* !POWER10 */
+ return 2;
+#endif /* POWER10 */
/* A saved register is set to a zero value. */
case SLJIT_HAS_ZERO_REGISTER:
case SLJIT_HAS_CLZ:
@@ -675,7 +713,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type)
{
- return (type >= SLJIT_UNORDERED && type <= SLJIT_ORDERED_LESS_EQUAL);
+ switch (type) {
+ case SLJIT_UNORDERED_OR_EQUAL:
+ case SLJIT_ORDERED_NOT_EQUAL:
+ case SLJIT_UNORDERED_OR_LESS:
+ case SLJIT_ORDERED_GREATER_EQUAL:
+ case SLJIT_UNORDERED_OR_GREATER:
+ case SLJIT_ORDERED_LESS_EQUAL:
+ return 1;
+ }
+
+ return 0;
}
/* --------------------------------------------------------------------- */
@@ -699,6 +747,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type)
#define MEM_MASK 0x7f
+#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_32) >> 6))
+
/* Other inp_flags. */
/* Integer opertion and set flags -> requires exts on 64 bit systems. */
@@ -722,6 +772,9 @@ ALT_FORM1 0x001000
...
ALT_FORM5 0x010000 */
+static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 inp_flags, sljit_s32 reg,
+ sljit_s32 arg, sljit_sw argw, sljit_s32 tmp_reg);
+
#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
#include "sljitNativePPC_32.c"
#else
@@ -737,16 +790,13 @@ ALT_FORM5 0x010000 */
#endif
#if (defined SLJIT_PPC_STACK_FRAME_V2 && SLJIT_PPC_STACK_FRAME_V2)
-#define LR_SAVE_OFFSET 2 * SSIZE_OF(sw)
+#define LR_SAVE_OFFSET (2 * SSIZE_OF(sw))
#else
#define LR_SAVE_OFFSET SSIZE_OF(sw)
#endif
#define STACK_MAX_DISTANCE (0x8000 - SSIZE_OF(sw) - LR_SAVE_OFFSET)
-static sljit_s32 emit_op_mem(struct sljit_compiler *compiler, sljit_s32 inp_flags, sljit_s32 reg,
- sljit_s32 arg, sljit_sw argw, sljit_s32 tmp_reg);
-
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
@@ -763,7 +813,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
set_emit_enter(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds - saved_arg_count, 0)
- + GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64));
+ + GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
if (!(options & SLJIT_ENTER_REG_ARG))
local_size += SSIZE_OF(sw);
@@ -873,7 +923,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *comp
set_set_context(compiler, options, arg_types, scratches, saveds, fscratches, fsaveds, local_size);
local_size += GET_SAVED_REGISTERS_SIZE(scratches, saveds - SLJIT_KEPT_SAVEDS_COUNT(options), 0)
- + GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64));
+ + GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
if (!(options & SLJIT_ENTER_REG_ARG))
local_size += SSIZE_OF(sw);
@@ -1222,7 +1272,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
src1_r = src1;
flags |= REG1_SOURCE;
}
- else if (src1 & SLJIT_IMM) {
+ else if (src1 == SLJIT_IMM) {
src1_r = TMP_ZERO;
if (src1w != 0) {
FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
@@ -1242,7 +1292,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
if (!(flags & REG_DEST) && op >= SLJIT_MOV && op <= SLJIT_MOV_P)
dst_r = src2_r;
}
- else if (src2 & SLJIT_IMM) {
+ else if (src2 == SLJIT_IMM) {
src2_r = TMP_ZERO;
if (src2w != 0) {
FAIL_IF(load_immediate(compiler, sugg_src2_r, src2w));
@@ -1312,29 +1362,161 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compile
return SLJIT_SUCCESS;
}
-static sljit_s32 emit_prefetch(struct sljit_compiler *compiler,
- sljit_s32 src, sljit_sw srcw)
+static sljit_s32 emit_rev(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
- if (!(src & OFFS_REG_MASK)) {
- if (srcw == 0 && (src & REG_MASK))
- return push_inst(compiler, DCBT | A(0) | B(src & REG_MASK));
+ sljit_s32 mem, offs_reg, inp_flags;
+ sljit_sw memw;
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+ sljit_s32 is_32 = op & SLJIT_32;
- FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
- /* Works with SLJIT_MEM0() case as well. */
- return push_inst(compiler, DCBT | A(src & REG_MASK) | B(TMP_REG1));
+ op = GET_OPCODE(op);
+#endif /* SLJIT_CONFIG_PPC_64 */
+
+ if (!((dst | src) & SLJIT_MEM)) {
+ /* Both are registers. */
+ if (op == SLJIT_REV_U16 || op == SLJIT_REV_S16) {
+ if (src == dst) {
+ FAIL_IF(push_inst(compiler, RLWIMI | S(dst) | A(dst) | RLWI_SH(16) | RLWI_MBE(8, 15)));
+ FAIL_IF(push_inst(compiler, RLWINM | S(dst) | A(dst) | RLWI_SH(24) | RLWI_MBE(16, 31)));
+ } else {
+ FAIL_IF(push_inst(compiler, RLWINM | S(src) | A(dst) | RLWI_SH(8) | RLWI_MBE(16, 23)));
+ FAIL_IF(push_inst(compiler, RLWIMI | S(src) | A(dst) | RLWI_SH(24) | RLWI_MBE(24, 31)));
+ }
+
+ if (op == SLJIT_REV_U16)
+ return SLJIT_SUCCESS;
+ return push_inst(compiler, EXTSH | S(dst) | A(dst));
+ }
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+ if (!is_32) {
+#if defined(_ARCH_PWR10) && _ARCH_PWR10
+ return push_inst(compiler, BRD | S(src) | A(dst));
+#else /* !POWER10 */
+ FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG2) | A(0) | IMM(TMP_MEM_OFFSET_HI)));
+ FAIL_IF(push_inst(compiler, RLDICL | S(src) | A(TMP_REG1) | RLDI_SH(32) | RLDI_MB(32)));
+ FAIL_IF(push_inst(compiler, STWBRX | S(src) | A(SLJIT_SP) | B(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG2) | A(0) | IMM(TMP_MEM_OFFSET_LO)));
+ FAIL_IF(push_inst(compiler, STWBRX | S(TMP_REG1) | A(SLJIT_SP) | B(TMP_REG2)));
+ return push_inst(compiler, LD | D(dst) | A(SLJIT_SP) | TMP_MEM_OFFSET);
+#endif /* POWER10 */
+ }
+#endif /* SLJIT_CONFIG_PPC_64 */
+
+ FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG2) | A(0) | IMM(TMP_MEM_OFFSET)));
+ FAIL_IF(push_inst(compiler, STWBRX | S(src) | A(SLJIT_SP) | B(TMP_REG2)));
+ FAIL_IF(push_inst(compiler, LWZ | D(dst) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+ if (op == SLJIT_REV_S32)
+ return push_inst(compiler, EXTSW | S(dst) | A(dst));
+#endif /* SLJIT_CONFIG_PPC_64 */
+ return SLJIT_SUCCESS;
}
- srcw &= 0x3;
+ mem = src;
+ memw = srcw;
- if (srcw == 0)
- return push_inst(compiler, DCBT | A(src & REG_MASK) | B(OFFS_REG(src)));
+ if (dst & SLJIT_MEM) {
+ mem = dst;
+ memw = dstw;
- FAIL_IF(push_inst(compiler, SLWI_W(srcw) | S(OFFS_REG(src)) | A(TMP_REG1)));
- return push_inst(compiler, DCBT | A(src & REG_MASK) | B(TMP_REG1));
+ if (src & SLJIT_MEM) {
+ inp_flags = HALF_DATA | LOAD_DATA;
+
+ if (op != SLJIT_REV_U16 && op != SLJIT_REV_S16) {
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+ inp_flags = (is_32 ? INT_DATA : WORD_DATA) | LOAD_DATA;
+#else /* !SLJIT_CONFIG_PPC_64 */
+ inp_flags = WORD_DATA | LOAD_DATA;
+#endif /* SLJIT_CONFIG_PPC_64 */
+ }
+
+ FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG1, src, srcw, TMP_REG2));
+ src = TMP_REG1;
+ }
+ }
+
+ if (SLJIT_UNLIKELY(mem & OFFS_REG_MASK)) {
+ offs_reg = OFFS_REG(mem);
+ mem &= REG_MASK;
+ memw &= 0x3;
+
+ if (memw != 0) {
+ FAIL_IF(push_inst(compiler, SLWI_W(memw) | S(offs_reg) | A(TMP_REG2)));
+ offs_reg = TMP_REG2;
+ }
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+ } else if (memw > 0x7fff7fffl || memw < -0x80000000l) {
+ FAIL_IF(load_immediate(compiler, TMP_REG2, memw));
+ offs_reg = TMP_REG2;
+ mem &= REG_MASK;
+#endif /* SLJIT_CONFIG_PPC_64 */
+ } else {
+ FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG2) | A(mem & REG_MASK) | IMM(memw)));
+ if (memw > SIMM_MAX || memw < SIMM_MIN)
+ FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG2) | A(TMP_REG2) | IMM((memw + 0x8000) >> 16)));
+
+ mem = 0;
+ offs_reg = TMP_REG2;
+ }
+
+ if (op == SLJIT_REV_U16 || op == SLJIT_REV_S16) {
+ if (dst & SLJIT_MEM)
+ return push_inst(compiler, STHBRX | S(src) | A(mem) | B(offs_reg));
+
+ FAIL_IF(push_inst(compiler, LHBRX | S(dst) | A(mem) | B(offs_reg)));
+
+ if (op == SLJIT_REV_U16)
+ return SLJIT_SUCCESS;
+ return push_inst(compiler, EXTSH | S(dst) | A(dst));
+ }
+
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+ if (!is_32) {
+ if (dst & SLJIT_MEM) {
+#if defined(_ARCH_PWR7) && _ARCH_PWR7
+ return push_inst(compiler, STDBRX | S(src) | A(mem) | B(offs_reg));
+#else /* !POWER7 */
+#if defined(SLJIT_LITTLE_ENDIAN) && SLJIT_LITTLE_ENDIAN
+ FAIL_IF(push_inst(compiler, RLDICL | S(src) | A(TMP_REG1) | RLDI_SH(32) | RLDI_MB(32)));
+ FAIL_IF(push_inst(compiler, STWBRX | S(TMP_REG1) | A(mem) | B(offs_reg)));
+ FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG2) | A(offs_reg) | IMM(SSIZE_OF(s32))));
+ return push_inst(compiler, STWBRX | S(src) | A(mem) | B(TMP_REG2));
+#else /* !SLJIT_LITTLE_ENDIAN */
+ FAIL_IF(push_inst(compiler, STWBRX | S(src) | A(mem) | B(offs_reg)));
+ FAIL_IF(push_inst(compiler, RLDICL | S(src) | A(TMP_REG1) | RLDI_SH(32) | RLDI_MB(32)));
+ FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG2) | A(offs_reg) | IMM(SSIZE_OF(s32))));
+ return push_inst(compiler, STWBRX | S(TMP_REG1) | A(mem) | B(TMP_REG2));
+#endif /* SLJIT_LITTLE_ENDIAN */
+#endif /* POWER7 */
+ }
+#if defined(_ARCH_PWR7) && _ARCH_PWR7
+ return push_inst(compiler, LDBRX | S(dst) | A(mem) | B(offs_reg));
+#else /* !POWER7 */
+ FAIL_IF(push_inst(compiler, LWBRX | LWBRX_FIRST_REG | A(mem) | B(offs_reg)));
+ FAIL_IF(push_inst(compiler, ADDI | D(TMP_REG2) | A(offs_reg) | IMM(SSIZE_OF(s32))));
+ FAIL_IF(push_inst(compiler, LWBRX | LWBRX_SECOND_REG | A(mem) | B(TMP_REG2)));
+ return push_inst(compiler, RLDIMI | S(TMP_REG1) | A(dst) | RLDI_SH(32) | RLDI_MB(0));
+#endif /* POWER7 */
+ }
+#endif /* SLJIT_CONFIG_PPC_64 */
+
+ if (dst & SLJIT_MEM)
+ return push_inst(compiler, STWBRX | S(src) | A(mem) | B(offs_reg));
+
+ FAIL_IF(push_inst(compiler, LWBRX | S(dst) | A(mem) | B(offs_reg)));
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+ if (op == SLJIT_REV_S32)
+ return push_inst(compiler, EXTSW | S(dst) | A(dst));
+#endif /* SLJIT_CONFIG_PPC_64 */
+ return SLJIT_SUCCESS;
}
#define EMIT_MOV(type, type_flags, type_cast) \
- emit_op(compiler, (src & SLJIT_IMM) ? SLJIT_MOV : type, flags | (type_flags), dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? type_cast srcw : srcw)
+ emit_op(compiler, (src == SLJIT_IMM) ? SLJIT_MOV : type, flags | (type_flags), dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? type_cast srcw : srcw)
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst, sljit_sw dstw,
@@ -1353,19 +1535,19 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
if (GET_FLAG_TYPE(op_flags) == SLJIT_OVERFLOW)
FAIL_IF(push_inst(compiler, MTXER | S(TMP_ZERO)));
- if (op < SLJIT_NOT && FAST_IS_REG(src) && src == dst) {
+ if (op <= SLJIT_MOV_P && FAST_IS_REG(src) && src == dst) {
if (!TYPE_CAST_NEEDED(op))
return SLJIT_SUCCESS;
}
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
if (op_flags & SLJIT_32) {
- if (op < SLJIT_NOT) {
+ if (op <= SLJIT_MOV_P) {
if (src & SLJIT_MEM) {
if (op == SLJIT_MOV_S32)
op = SLJIT_MOV_U32;
}
- else if (src & SLJIT_IMM) {
+ else if (src == SLJIT_IMM) {
if (op == SLJIT_MOV_U32)
op = SLJIT_MOV_S32;
}
@@ -1410,16 +1592,26 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
case SLJIT_MOV_S16:
return EMIT_MOV(SLJIT_MOV_S16, HALF_DATA | SIGNED_DATA, (sljit_s16));
- case SLJIT_NOT:
- return emit_op(compiler, SLJIT_NOT, flags, dst, dstw, TMP_REG1, 0, src, srcw);
-
case SLJIT_CLZ:
case SLJIT_CTZ:
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
- return emit_op(compiler, op, flags | (!(op_flags & SLJIT_32) ? 0 : ALT_FORM1), dst, dstw, TMP_REG1, 0, src, srcw);
-#else
+ if (op_flags & SLJIT_32)
+ flags |= ALT_FORM1;
+#endif /* SLJIT_CONFIG_PPC_64 */
return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw);
-#endif
+ case SLJIT_REV_U32:
+ case SLJIT_REV_S32:
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+ op |= SLJIT_32;
+#endif /* SLJIT_CONFIG_PPC_64 */
+ /* fallthrough */
+ case SLJIT_REV:
+ case SLJIT_REV_U16:
+ case SLJIT_REV_S16:
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+ op |= (op_flags & SLJIT_32);
+#endif /* SLJIT_CONFIG_PPC_64 */
+ return emit_rev(compiler, op, dst, dstw, src, srcw);
}
return SLJIT_SUCCESS;
@@ -1427,40 +1619,22 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
#undef EMIT_MOV
+/* Macros for checking different operand types / values. */
#define TEST_SL_IMM(src, srcw) \
- (((src) & SLJIT_IMM) && (srcw) <= SIMM_MAX && (srcw) >= SIMM_MIN)
-
+ ((src) == SLJIT_IMM && (srcw) <= SIMM_MAX && (srcw) >= SIMM_MIN)
#define TEST_UL_IMM(src, srcw) \
- (((src) & SLJIT_IMM) && !((srcw) & ~0xffff))
-
-#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
-#define TEST_SH_IMM(src, srcw) \
- (((src) & SLJIT_IMM) && !((srcw) & 0xffff) && (srcw) <= 0x7fffffffl && (srcw) >= -0x80000000l)
-#else
-#define TEST_SH_IMM(src, srcw) \
- (((src) & SLJIT_IMM) && !((srcw) & 0xffff))
-#endif
-
+ ((src) == SLJIT_IMM && !((srcw) & ~0xffff))
#define TEST_UH_IMM(src, srcw) \
- (((src) & SLJIT_IMM) && !((srcw) & ~(sljit_sw)0xffff0000))
+ ((src) == SLJIT_IMM && !((srcw) & ~(sljit_sw)0xffff0000))
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+#define TEST_SH_IMM(src, srcw) \
+ ((src) == SLJIT_IMM && !((srcw) & 0xffff) && (srcw) <= 0x7fffffffl && (srcw) >= -0x80000000l)
#define TEST_ADD_IMM(src, srcw) \
- (((src) & SLJIT_IMM) && (srcw) <= 0x7fff7fffl && (srcw) >= -0x80000000l)
-#else
-#define TEST_ADD_IMM(src, srcw) \
- ((src) & SLJIT_IMM)
-#endif
-
-#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
-#define TEST_UI_IMM(src, srcw) \
- (((src) & SLJIT_IMM) && !((srcw) & ~0xffffffff))
-#else
+ ((src) == SLJIT_IMM && (srcw) <= 0x7fff7fffl && (srcw) >= -0x80000000l)
#define TEST_UI_IMM(src, srcw) \
- ((src) & SLJIT_IMM)
-#endif
+ ((src) == SLJIT_IMM && !((srcw) & ~0xffffffff))
-#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
#define TEST_ADD_FORM1(op) \
(GET_FLAG_TYPE(op) == SLJIT_OVERFLOW \
|| (op & (SLJIT_32 | SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == (SLJIT_32 | SLJIT_SET_Z | SLJIT_SET_CARRY))
@@ -1470,14 +1644,22 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
#define TEST_SUB_FORM3(op) \
(GET_FLAG_TYPE(op) == SLJIT_OVERFLOW \
|| (op & (SLJIT_32 | SLJIT_SET_Z)) == (SLJIT_32 | SLJIT_SET_Z))
-#else
+
+#else /* !SLJIT_CONFIG_PPC_64 */
+#define TEST_SH_IMM(src, srcw) \
+ ((src) == SLJIT_IMM && !((srcw) & 0xffff))
+#define TEST_ADD_IMM(src, srcw) \
+ ((src) == SLJIT_IMM)
+#define TEST_UI_IMM(src, srcw) \
+ ((src) == SLJIT_IMM)
+
#define TEST_ADD_FORM1(op) \
(GET_FLAG_TYPE(op) == SLJIT_OVERFLOW)
#define TEST_SUB_FORM2(op) \
(GET_FLAG_TYPE(op) >= SLJIT_SIG_LESS && GET_FLAG_TYPE(op) <= SLJIT_SIG_LESS_EQUAL)
#define TEST_SUB_FORM3(op) \
(GET_FLAG_TYPE(op) == SLJIT_OVERFLOW)
-#endif
+#endif /* SLJIT_CONFIG_PPC_64 */
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst, sljit_sw dstw,
@@ -1496,9 +1678,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
if (op & SLJIT_32) {
/* Most operations expect sign extended arguments. */
flags |= INT_DATA | SIGNED_DATA;
- if (src1 & SLJIT_IMM)
+ if (src1 == SLJIT_IMM)
src1w = (sljit_s32)(src1w);
- if (src2 & SLJIT_IMM)
+ if (src2 == SLJIT_IMM)
src2w = (sljit_s32)(src2w);
if (HAS_FLAGS(op))
flags |= ALT_SIGN_EXT;
@@ -1514,7 +1696,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
if (TEST_ADD_FORM1(op))
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM1, dst, dstw, src1, src1w, src2, src2w);
- if (!HAS_FLAGS(op) && ((src1 | src2) & SLJIT_IMM)) {
+ if (!HAS_FLAGS(op) && (src1 == SLJIT_IMM || src2 == SLJIT_IMM)) {
if (TEST_SL_IMM(src2, src2w)) {
compiler->imm = (sljit_ins)src2w & 0xffff;
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM2, dst, dstw, src1, src1w, TMP_REG2, 0);
@@ -1565,7 +1747,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
return emit_op(compiler, SLJIT_ADD, flags | ALT_FORM3, dst, dstw, src2, src2w, TMP_REG2, 0);
}
}
- return emit_op(compiler, SLJIT_ADD, flags | ((GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY)) ? ALT_FORM5 : 0), dst, dstw, src1, src1w, src2, src2w);
+ return emit_op(compiler, SLJIT_ADD, flags | ((GET_FLAG_TYPE(op) == SLJIT_CARRY) ? ALT_FORM5 : 0), dst, dstw, src1, src1w, src2, src2w);
case SLJIT_ADDC:
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_ADD;
@@ -1583,7 +1765,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1, dst, dstw, src1, src1w, src2, src2w);
}
- if ((src2 & SLJIT_IMM) && src2w >= 0 && src2w <= (SIMM_MAX + 1)) {
+ if (src2 == SLJIT_IMM && src2w >= 0 && src2w <= (SIMM_MAX + 1)) {
compiler->imm = (sljit_ins)src2w;
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM1 | ALT_FORM2 | ALT_FORM3, dst, dstw, src1, src1w, TMP_REG2, 0);
}
@@ -1599,7 +1781,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
}
if (TEST_SUB_FORM2(op)) {
- if ((src2 & SLJIT_IMM) && src2w >= -SIMM_MAX && src2w <= SIMM_MAX) {
+ if (src2 == SLJIT_IMM && src2w >= -SIMM_MAX && src2w <= SIMM_MAX) {
compiler->imm = (sljit_ins)src2w & 0xffff;
return emit_op(compiler, SLJIT_SUB, flags | ALT_FORM2 | ALT_FORM3 | ALT_FORM4, dst, dstw, src1, src1w, TMP_REG2, 0);
}
@@ -1632,7 +1814,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
}
/* We know ALT_SIGN_EXT is set if it is an SLJIT_32 on 64 bit systems. */
- return emit_op(compiler, SLJIT_SUB, flags | ((GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY)) ? ALT_FORM5 : 0), dst, dstw, src1, src1w, src2, src2w);
+ return emit_op(compiler, SLJIT_SUB, flags | ((GET_FLAG_TYPE(op) == SLJIT_CARRY) ? ALT_FORM5 : 0), dst, dstw, src1, src1w, src2, src2w);
case SLJIT_SUBC:
compiler->status_flags_state = SLJIT_CURRENT_FLAGS_SUB;
@@ -1657,9 +1839,16 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
FAIL_IF(push_inst(compiler, MTXER | S(TMP_ZERO)));
return emit_op(compiler, SLJIT_MUL, flags, dst, dstw, src1, src1w, src2, src2w);
+ case SLJIT_XOR:
+ if (src2 == SLJIT_IMM && src2w == -1) {
+ return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM4, dst, dstw, TMP_REG1, 0, src1, src1w);
+ }
+ if (src1 == SLJIT_IMM && src1w == -1) {
+ return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM4, dst, dstw, TMP_REG1, 0, src2, src2w);
+ }
+ /* fallthrough */
case SLJIT_AND:
case SLJIT_OR:
- case SLJIT_XOR:
/* Commutative unsigned operations. */
if (!HAS_FLAGS(op) || GET_OPCODE(op) == SLJIT_AND) {
if (TEST_UL_IMM(src2, src2w)) {
@@ -1704,7 +1893,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
if (op & SLJIT_32)
flags |= ALT_FORM2;
#endif
- if (src2 & SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
compiler->imm = (sljit_ins)src2w;
return emit_op(compiler, GET_OPCODE(op), flags | ALT_FORM1, dst, dstw, src1, src1w, TMP_REG2, 0);
}
@@ -1730,9 +1919,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil
#undef TEST_SUB_FORM3
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 src_dst,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w)
+ sljit_s32 dst_reg,
+ sljit_s32 src1_reg,
+ sljit_s32 src2_reg,
+ sljit_s32 src3, sljit_sw src3w)
{
sljit_s32 is_right;
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
@@ -1744,85 +1934,97 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *
#endif /* SLJIT_CONFIG_PPC_64 */
CHECK_ERROR();
- CHECK(check_sljit_emit_shift_into(compiler, op, src_dst, src1, src1w, src2, src2w));
+ CHECK(check_sljit_emit_shift_into(compiler, op, dst_reg, src1_reg, src2_reg, src3, src3w));
is_right = (GET_OPCODE(op) == SLJIT_LSHR || GET_OPCODE(op) == SLJIT_MLSHR);
- if (src_dst == src1) {
+ if (src1_reg == src2_reg) {
SLJIT_SKIP_CHECKS(compiler);
- return sljit_emit_op2(compiler, (is_right ? SLJIT_ROTR : SLJIT_ROTL) | (op & SLJIT_32), src_dst, 0, src_dst, 0, src2, src2w);
+ return sljit_emit_op2(compiler, (is_right ? SLJIT_ROTR : SLJIT_ROTL) | (op & SLJIT_32), dst_reg, 0, src1_reg, 0, src3, src3w);
}
- ADJUST_LOCAL_OFFSET(src1, src1w);
- ADJUST_LOCAL_OFFSET(src2, src2w);
+ ADJUST_LOCAL_OFFSET(src3, src3w);
- if (src2 & SLJIT_IMM) {
- src2w &= bit_length - 1;
+ if (src3 == SLJIT_IMM) {
+ src3w &= bit_length - 1;
- if (src2w == 0)
+ if (src3w == 0)
return SLJIT_SUCCESS;
- } else if (src2 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG2, src2, src2w, TMP_REG2));
- src2 = TMP_REG2;
- }
- if (src1 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG1, src1, src1w, TMP_REG1));
- src1 = TMP_REG1;
- } else if (src1 & SLJIT_IMM) {
- FAIL_IF(load_immediate(compiler, TMP_REG1, src1w));
- src1 = TMP_REG1;
- }
-
- if (src2 & SLJIT_IMM) {
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
if (!(op & SLJIT_32)) {
if (is_right) {
- FAIL_IF(push_inst(compiler, SRDI(src2w) | S(src_dst) | A(src_dst)));
- return push_inst(compiler, RLDIMI | S(src1) | A(src_dst) | RLDI_SH(64 - src2w) | RLDI_MB(0));
+ FAIL_IF(push_inst(compiler, SRDI(src3w) | S(src1_reg) | A(dst_reg)));
+ return push_inst(compiler, RLDIMI | S(src2_reg) | A(dst_reg) | RLDI_SH(64 - src3w) | RLDI_MB(0));
}
- FAIL_IF(push_inst(compiler, SLDI(src2w) | S(src_dst) | A(src_dst)));
+ FAIL_IF(push_inst(compiler, SLDI(src3w) | S(src1_reg) | A(dst_reg)));
/* Computes SRDI(64 - src2w). */
- FAIL_IF(push_inst(compiler, RLDICL | S(src1) | A(TMP_REG1) | RLDI_SH(src2w) | RLDI_MB(64 - src2w)));
- return push_inst(compiler, OR | S(src_dst) | A(src_dst) | B(TMP_REG1));
+ FAIL_IF(push_inst(compiler, RLDICL | S(src2_reg) | A(TMP_REG1) | RLDI_SH(src3w) | RLDI_MB(64 - src3w)));
+ return push_inst(compiler, OR | S(dst_reg) | A(dst_reg) | B(TMP_REG1));
}
#endif /* SLJIT_CONFIG_PPC_64 */
if (is_right) {
- FAIL_IF(push_inst(compiler, SRWI(src2w) | S(src_dst) | A(src_dst)));
- return push_inst(compiler, RLWIMI | S(src1) | A(src_dst) | RLWI_SH(32 - src2w) | RLWI_MBE(0, src2w - 1));
+ FAIL_IF(push_inst(compiler, SRWI(src3w) | S(src1_reg) | A(dst_reg)));
+ return push_inst(compiler, RLWIMI | S(src2_reg) | A(dst_reg) | RLWI_SH(32 - src3w) | RLWI_MBE(0, src3w - 1));
}
- FAIL_IF(push_inst(compiler, SLWI(src2w) | S(src_dst) | A(src_dst)));
- return push_inst(compiler, RLWIMI | S(src1) | A(src_dst) | RLWI_SH(src2w) | RLWI_MBE(32 - src2w, 31));
+ FAIL_IF(push_inst(compiler, SLWI(src3w) | S(src1_reg) | A(dst_reg)));
+ return push_inst(compiler, RLWIMI | S(src2_reg) | A(dst_reg) | RLWI_SH(src3w) | RLWI_MBE(32 - src3w, 31));
+ }
+
+ if (src3 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG2, src3, src3w, TMP_REG2));
+ src3 = TMP_REG2;
}
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
if (!(op & SLJIT_32)) {
- if (GET_OPCODE(op) == SLJIT_MSHL || GET_OPCODE(op) == SLJIT_MLSHR) {
- FAIL_IF(push_inst(compiler, ANDI | S(src2) | A(TMP_REG2) | 0x3f));
- src2 = TMP_REG2;
+ if (GET_OPCODE(op) == SLJIT_MSHL || GET_OPCODE(op) == SLJIT_MLSHR || dst_reg == src3) {
+ FAIL_IF(push_inst(compiler, ANDI | S(src3) | A(TMP_REG2) | 0x3f));
+ src3 = TMP_REG2;
}
- FAIL_IF(push_inst(compiler, (is_right ? SRD : SLD) | S(src_dst) | A(src_dst) | B(src2)));
- FAIL_IF(push_inst(compiler, (is_right ? SLDI(1) : SRDI(1)) | S(src1) | A(TMP_REG1)));
- FAIL_IF(push_inst(compiler, XORI | S(src2) | A(TMP_REG2) | 0x3f));
+ FAIL_IF(push_inst(compiler, (is_right ? SRD : SLD) | S(src1_reg) | A(dst_reg) | B(src3)));
+ FAIL_IF(push_inst(compiler, (is_right ? SLDI(1) : SRDI(1)) | S(src2_reg) | A(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, XORI | S(src3) | A(TMP_REG2) | 0x3f));
FAIL_IF(push_inst(compiler, (is_right ? SLD : SRD) | S(TMP_REG1) | A(TMP_REG1) | B(TMP_REG2)));
- return push_inst(compiler, OR | S(src_dst) | A(src_dst) | B(TMP_REG1));
+ return push_inst(compiler, OR | S(dst_reg) | A(dst_reg) | B(TMP_REG1));
}
#endif /* SLJIT_CONFIG_PPC_64 */
- if (GET_OPCODE(op) == SLJIT_MSHL || GET_OPCODE(op) == SLJIT_MLSHR) {
- FAIL_IF(push_inst(compiler, ANDI | S(src2) | A(TMP_REG2) | 0x1f));
- src2 = TMP_REG2;
+ if (GET_OPCODE(op) == SLJIT_MSHL || GET_OPCODE(op) == SLJIT_MLSHR || dst_reg == src3) {
+ FAIL_IF(push_inst(compiler, ANDI | S(src3) | A(TMP_REG2) | 0x1f));
+ src3 = TMP_REG2;
}
- FAIL_IF(push_inst(compiler, (is_right ? SRW : SLW) | S(src_dst) | A(src_dst) | B(src2)));
- FAIL_IF(push_inst(compiler, (is_right ? SLWI(1) : SRWI(1)) | S(src1) | A(TMP_REG1)));
- FAIL_IF(push_inst(compiler, XORI | S(src2) | A(TMP_REG2) | 0x1f));
+ FAIL_IF(push_inst(compiler, (is_right ? SRW : SLW) | S(src1_reg) | A(dst_reg) | B(src3)));
+ FAIL_IF(push_inst(compiler, (is_right ? SLWI(1) : SRWI(1)) | S(src2_reg) | A(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, XORI | S(src3) | A(TMP_REG2) | 0x1f));
FAIL_IF(push_inst(compiler, (is_right ? SLW : SRW) | S(TMP_REG1) | A(TMP_REG1) | B(TMP_REG2)));
- return push_inst(compiler, OR | S(src_dst) | A(src_dst) | B(TMP_REG1));
+ return push_inst(compiler, OR | S(dst_reg) | A(dst_reg) | B(TMP_REG1));
+}
+
+static sljit_s32 emit_prefetch(struct sljit_compiler *compiler,
+ sljit_s32 src, sljit_sw srcw)
+{
+ if (!(src & OFFS_REG_MASK)) {
+ if (srcw == 0 && (src & REG_MASK))
+ return push_inst(compiler, DCBT | A(0) | B(src & REG_MASK));
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
+ /* Works with SLJIT_MEM0() case as well. */
+ return push_inst(compiler, DCBT | A(src & REG_MASK) | B(TMP_REG1));
+ }
+
+ srcw &= 0x3;
+
+ if (srcw == 0)
+ return push_inst(compiler, DCBT | A(src & REG_MASK) | B(OFFS_REG(src)));
+
+ FAIL_IF(push_inst(compiler, SLWI_W(srcw) | S(OFFS_REG(src)) | A(TMP_REG1)));
+ return push_inst(compiler, DCBT | A(src & REG_MASK) | B(TMP_REG1));
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
@@ -1854,21 +2056,52 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *comp
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw)
{
- CHECK_REG_INDEX(check_sljit_get_register_index(reg));
- return reg_map[reg];
+ sljit_s32 dst_r;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op_dst(compiler, op, dst, dstw));
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+
+ switch (op) {
+ case SLJIT_FAST_ENTER:
+ if (FAST_IS_REG(dst))
+ return push_inst(compiler, MFLR | D(dst));
+
+ FAIL_IF(push_inst(compiler, MFLR | D(TMP_REG1)));
+ break;
+ case SLJIT_GET_RETURN_ADDRESS:
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+ FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, dst_r, SLJIT_MEM1(SLJIT_SP), compiler->local_size + LR_SAVE_OFFSET, TMP_REG2));
+ break;
+ }
+
+ if (dst & SLJIT_MEM)
+ return emit_op_mem(compiler, WORD_DATA, TMP_REG1, dst, dstw, TMP_REG2);
+
+ return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 type, sljit_s32 reg)
{
- CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
+ CHECK_REG_INDEX(check_sljit_get_register_index(type, reg));
+
+ if (type == SLJIT_GP_REGISTER)
+ return reg_map[reg];
+
+ if (type != SLJIT_FLOAT_REGISTER)
+ return -1;
+
return freg_map[reg];
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
void *instruction, sljit_u32 size)
{
+ SLJIT_UNUSED_ARG(size);
+
CHECK_ERROR();
CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
@@ -1879,24 +2112,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *c
/* Floating point operators */
/* --------------------------------------------------------------------- */
-#define FLOAT_DATA(op) (DOUBLE_DATA | ((op & SLJIT_32) >> 6))
#define SELECT_FOP(op, single, double) ((sljit_ins)((op & SLJIT_32) ? single : double))
-#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
-#define FLOAT_TMP_MEM_OFFSET (6 * sizeof(sljit_sw))
-#else
-#define FLOAT_TMP_MEM_OFFSET (2 * sizeof(sljit_sw))
-
-#if (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
-#define FLOAT_TMP_MEM_OFFSET_LOW (2 * sizeof(sljit_sw))
-#define FLOAT_TMP_MEM_OFFSET_HI (3 * sizeof(sljit_sw))
-#else
-#define FLOAT_TMP_MEM_OFFSET_LOW (3 * sizeof(sljit_sw))
-#define FLOAT_TMP_MEM_OFFSET_HI (2 * sizeof(sljit_sw))
-#endif
-
-#endif /* SLJIT_CONFIG_PPC_64 */
-
static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 src, sljit_sw srcw)
@@ -1913,19 +2130,19 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_comp
if (op == SLJIT_CONV_SW_FROM_F64) {
if (FAST_IS_REG(dst)) {
- FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA, TMP_FREG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1));
- return emit_op_mem(compiler, WORD_DATA | LOAD_DATA, dst, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1);
+ FAIL_IF(push_inst(compiler, STFD | FS(TMP_FREG1) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+ return push_inst(compiler, LD | S(dst) | A(SLJIT_SP) | TMP_MEM_OFFSET);
}
return emit_op_mem(compiler, DOUBLE_DATA, TMP_FREG1, dst, dstw, TMP_REG1);
}
-#else
+#else /* !SLJIT_CONFIG_PPC_64 */
FAIL_IF(push_inst(compiler, FCTIWZ | FD(TMP_FREG1) | FB(src)));
-#endif
+#endif /* SLJIT_CONFIG_PPC_64 */
if (FAST_IS_REG(dst)) {
- FAIL_IF(load_immediate(compiler, TMP_REG1, FLOAT_TMP_MEM_OFFSET));
+ FAIL_IF(load_immediate(compiler, TMP_REG1, TMP_MEM_OFFSET));
FAIL_IF(push_inst(compiler, STFIWX | FS(TMP_FREG1) | A(SLJIT_SP) | B(TMP_REG1)));
- return emit_op_mem(compiler, INT_DATA | LOAD_DATA, dst, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1);
+ return push_inst(compiler, LWZ | S(dst) | A(SLJIT_SP) | TMP_MEM_OFFSET);
}
SLJIT_ASSERT(dst & SLJIT_MEM);
@@ -1935,16 +2152,14 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_comp
if (dstw) {
FAIL_IF(push_inst(compiler, SLWI_W(dstw) | S(OFFS_REG(dst)) | A(TMP_REG1)));
dstw = TMP_REG1;
- }
- else
+ } else
dstw = OFFS_REG(dst);
}
else {
if ((dst & REG_MASK) && !dstw) {
dstw = dst & REG_MASK;
dst = 0;
- }
- else {
+ } else {
/* This works regardless we have SLJIT_MEM1 or SLJIT_MEM0. */
FAIL_IF(load_immediate(compiler, TMP_REG1, dstw));
dstw = TMP_REG1;
@@ -1954,85 +2169,6 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_comp
return push_inst(compiler, STFIWX | FS(TMP_FREG1) | A(dst & REG_MASK) | B(dstw));
}
-static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 dst, sljit_sw dstw,
- sljit_s32 src, sljit_sw srcw)
-{
-#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
-
- sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
-
- if (src & SLJIT_IMM) {
- if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
- srcw = (sljit_s32)srcw;
-
- FAIL_IF(load_immediate(compiler, TMP_REG1, srcw));
- src = TMP_REG1;
- }
- else if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32) {
- if (FAST_IS_REG(src))
- FAIL_IF(push_inst(compiler, EXTSW | S(src) | A(TMP_REG1)));
- else
- FAIL_IF(emit_op_mem(compiler, INT_DATA | SIGNED_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));
- src = TMP_REG1;
- }
-
- if (FAST_IS_REG(src)) {
- FAIL_IF(emit_op_mem(compiler, WORD_DATA, src, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1));
- FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1));
- }
- else
- FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, src, srcw, TMP_REG1));
-
- FAIL_IF(push_inst(compiler, FCFID | FD(dst_r) | FB(TMP_FREG1)));
-
- if (dst & SLJIT_MEM)
- return emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, TMP_REG1);
- if (op & SLJIT_32)
- return push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r));
- return SLJIT_SUCCESS;
-
-#else
-
- sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
- sljit_s32 invert_sign = 1;
-
- if (src & SLJIT_IMM) {
- FAIL_IF(load_immediate(compiler, TMP_REG1, srcw ^ (sljit_sw)0x80000000));
- src = TMP_REG1;
- invert_sign = 0;
- }
- else if (!FAST_IS_REG(src)) {
- FAIL_IF(emit_op_mem(compiler, WORD_DATA | SIGNED_DATA | LOAD_DATA, TMP_REG1, src, srcw, TMP_REG1));
- src = TMP_REG1;
- }
-
- /* First, a special double floating point value is constructed: (2^53 + (input xor (2^31)))
- The double precision format has exactly 53 bit precision, so the lower 32 bit represents
- the lower 32 bit of such value. The result of xor 2^31 is the same as adding 0x80000000
- to the input, which shifts it into the 0 - 0xffffffff range. To get the converted floating
- point value, we need to subtract 2^53 + 2^31 from the constructed value. */
- FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG2) | A(0) | 0x4330));
- if (invert_sign)
- FAIL_IF(push_inst(compiler, XORIS | S(src) | A(TMP_REG1) | 0x8000));
- FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG2, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET_HI, TMP_REG1));
- FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET_LOW, TMP_REG2));
- FAIL_IF(push_inst(compiler, ADDIS | D(TMP_REG1) | A(0) | 0x8000));
- FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1));
- FAIL_IF(emit_op_mem(compiler, WORD_DATA, TMP_REG1, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET_LOW, TMP_REG2));
- FAIL_IF(emit_op_mem(compiler, DOUBLE_DATA | LOAD_DATA, TMP_FREG2, SLJIT_MEM1(SLJIT_SP), FLOAT_TMP_MEM_OFFSET, TMP_REG1));
-
- FAIL_IF(push_inst(compiler, FSUB | FD(dst_r) | FA(TMP_FREG1) | FB(TMP_FREG2)));
-
- if (dst & SLJIT_MEM)
- return emit_op_mem(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, TMP_REG1);
- if (op & SLJIT_32)
- return push_inst(compiler, FRSP | FD(dst_r) | FB(dst_r));
- return SLJIT_SUCCESS;
-
-#endif
-}
-
static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 src1, sljit_sw src1w,
sljit_s32 src2, sljit_sw src2w)
@@ -2051,13 +2187,10 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compile
switch (GET_FLAG_TYPE(op)) {
case SLJIT_UNORDERED_OR_EQUAL:
- case SLJIT_ORDERED_NOT_EQUAL:
return push_inst(compiler, CROR | ((4 + 2) << 21) | ((4 + 2) << 16) | ((4 + 3) << 11));
case SLJIT_UNORDERED_OR_LESS:
- case SLJIT_ORDERED_GREATER_EQUAL:
return push_inst(compiler, CROR | ((4 + 0) << 21) | ((4 + 0) << 16) | ((4 + 3) << 11));
case SLJIT_UNORDERED_OR_GREATER:
- case SLJIT_ORDERED_LESS_EQUAL:
return push_inst(compiler, CROR | ((4 + 1) << 21) | ((4 + 1) << 16) | ((4 + 3) << 11));
}
@@ -2143,18 +2276,30 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
case SLJIT_ADD_F64:
FAIL_IF(push_inst(compiler, SELECT_FOP(op, FADDS, FADD) | FD(dst_r) | FA(src1) | FB(src2)));
break;
-
case SLJIT_SUB_F64:
FAIL_IF(push_inst(compiler, SELECT_FOP(op, FSUBS, FSUB) | FD(dst_r) | FA(src1) | FB(src2)));
break;
-
case SLJIT_MUL_F64:
FAIL_IF(push_inst(compiler, SELECT_FOP(op, FMULS, FMUL) | FD(dst_r) | FA(src1) | FC(src2) /* FMUL use FC as src2 */));
break;
-
case SLJIT_DIV_F64:
FAIL_IF(push_inst(compiler, SELECT_FOP(op, FDIVS, FDIV) | FD(dst_r) | FA(src1) | FB(src2)));
break;
+ case SLJIT_COPYSIGN_F64:
+ FAIL_IF(push_inst(compiler, ((op & SLJIT_32) ? STFS : STFD) | FS(src2) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
+ FAIL_IF(push_inst(compiler, LWZ | S(TMP_REG1) | A(SLJIT_SP) | ((op & SLJIT_32) ? TMP_MEM_OFFSET : TMP_MEM_OFFSET_HI)));
+#else /* !SLJIT_CONFIG_PPC_32 */
+ FAIL_IF(push_inst(compiler, ((op & SLJIT_32) ? LWZ : LD) | S(TMP_REG1) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+#endif /* SLJIT_CONFIG_PPC_32 */
+ FAIL_IF(push_inst(compiler, FABS | FD(dst_r) | FB(src1)));
+#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
+ FAIL_IF(push_inst(compiler, CMPI | CRD(0) | A(TMP_REG1) | 0));
+#else /* !SLJIT_CONFIG_PPC_32 */
+ FAIL_IF(push_inst(compiler, CMPI | CRD(0 | ((op & SLJIT_32) ? 0 : 1)) | A(TMP_REG1) | 0));
+#endif /* SLJIT_CONFIG_PPC_32 */
+ FAIL_IF(push_inst(compiler, BCx | (4 << 21) | (0 << 16) | 8));
+ return push_inst(compiler, FNEG | FD(dst_r) | FB(dst_r));
}
if (dst & SLJIT_MEM)
@@ -2165,22 +2310,24 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
#undef SELECT_FOP
-/* --------------------------------------------------------------------- */
-/* Other instructions */
-/* --------------------------------------------------------------------- */
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset32(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f32 value)
{
+ union {
+ sljit_s32 imm;
+ sljit_f32 value;
+ } u;
+
CHECK_ERROR();
- CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
- ADJUST_LOCAL_OFFSET(dst, dstw);
+ CHECK(check_sljit_emit_fset32(compiler, freg, value));
- if (FAST_IS_REG(dst))
- return push_inst(compiler, MFLR | D(dst));
+ u.value = value;
- /* Memory. */
- FAIL_IF(push_inst(compiler, MFLR | D(TMP_REG2)));
- return emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0);
+ if (u.imm != 0)
+ FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm));
+
+ FAIL_IF(push_inst(compiler, STW | S(u.imm != 0 ? TMP_REG1 : TMP_ZERO) | A(SLJIT_SP) | TMP_MEM_OFFSET));
+ return push_inst(compiler, LFS | FS(freg) | A(SLJIT_SP) | TMP_MEM_OFFSET);
}
/* --------------------------------------------------------------------- */
@@ -2303,7 +2450,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
set_jump(jump, compiler, (sljit_u32)type & SLJIT_REWRITABLE_JUMP);
type &= 0xff;
- if (type == SLJIT_CARRY || type == SLJIT_NOT_CARRY)
+ if ((type | 0x1) == SLJIT_NOT_CARRY)
PTR_FAIL_IF(push_inst(compiler, ADDE | RC(ALT_SET_FLAGS) | D(TMP_REG1) | A(TMP_ZERO) | B(TMP_ZERO)));
/* In PPC, we don't need to touch the arguments. */
@@ -2324,6 +2471,8 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_call(struct sljit_compiler *compiler, sljit_s32 type,
sljit_s32 arg_types)
{
+ SLJIT_UNUSED_ARG(arg_types);
+
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_call(compiler, type, arg_types));
@@ -2360,7 +2509,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
#else /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */
src_r = src;
#endif /* SLJIT_PASS_ENTRY_ADDR_TO_CALL */
- } else if (src & SLJIT_IMM) {
+ } else if (src == SLJIT_IMM) {
/* These jumps are converted to jump/call instructions when possible. */
jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
FAIL_IF(!jump);
@@ -2390,6 +2539,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compi
sljit_s32 arg_types,
sljit_s32 src, sljit_sw srcw)
{
+ SLJIT_UNUSED_ARG(arg_types);
+
CHECK_ERROR();
CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
@@ -2572,14 +2723,106 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
return sljit_emit_op2(compiler, saved_op, dst, 0, dst, 0, TMP_REG2, 0);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *compiler, sljit_s32 type,
sljit_s32 dst_reg,
- sljit_s32 src, sljit_sw srcw)
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_reg)
+{
+ sljit_ins *ptr;
+ sljit_uw size;
+#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
+ sljit_s32 inp_flags = ((type & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA;
+#else /* !SLJIT_CONFIG_PPC_64 */
+ sljit_s32 inp_flags = WORD_DATA | LOAD_DATA;
+#endif /* SLJIT_CONFIG_PPC_64 */
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));
+
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+
+ if (dst_reg != src2_reg) {
+ if (dst_reg == src1) {
+ src1 = src2_reg;
+ src1w = 0;
+ type ^= 0x1;
+ } else {
+ if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) {
+ FAIL_IF(push_inst(compiler, OR | S(dst_reg) | A(TMP_REG2) | B(dst_reg)));
+
+ if ((src1 & REG_MASK) == dst_reg)
+ src1 = (src1 & ~REG_MASK) | TMP_REG2;
+
+ if (OFFS_REG(src1) == dst_reg)
+ src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG2);
+ }
+
+ FAIL_IF(push_inst(compiler, OR | S(src2_reg) | A(dst_reg) | B(src2_reg)));
+ }
+ }
+
+ if (((type & ~SLJIT_32) | 0x1) == SLJIT_NOT_CARRY)
+ FAIL_IF(push_inst(compiler, ADDE | RC(ALT_SET_FLAGS) | D(TMP_REG1) | A(TMP_ZERO) | B(TMP_ZERO)));
+
+ size = compiler->size;
+
+ ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
+ FAIL_IF(!ptr);
+ compiler->size++;
+
+ if (src1 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, inp_flags, dst_reg, src1, src1w, TMP_REG1));
+ } else if (src1 == SLJIT_IMM) {
+#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
+ if (type & SLJIT_32)
+ src1w = (sljit_s32)src1w;
+#endif /* SLJIT_CONFIG_RISCV_64 */
+ FAIL_IF(load_immediate(compiler, dst_reg, src1w));
+ } else
+ FAIL_IF(push_inst(compiler, OR | S(src1) | A(dst_reg) | B(src1)));
+
+ *ptr = BCx | get_bo_bi_flags(compiler, (type ^ 0x1) & ~SLJIT_32) | (sljit_ins)((compiler->size - size) << 2);
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_freg)
{
+ sljit_ins *ptr;
+ sljit_uw size;
+
CHECK_ERROR();
- CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
+ CHECK(check_sljit_emit_fselect(compiler, type, dst_freg, src1, src1w, src2_freg));
+
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+
+ if (dst_freg != src2_freg) {
+ if (dst_freg == src1) {
+ src1 = src2_freg;
+ src1w = 0;
+ type ^= 0x1;
+ } else
+ FAIL_IF(push_inst(compiler, FMR | FD(dst_freg) | FB(src2_freg)));
+ }
- return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);;
+ if (((type & ~SLJIT_32) | 0x1) == SLJIT_NOT_CARRY)
+ FAIL_IF(push_inst(compiler, ADDE | RC(ALT_SET_FLAGS) | D(TMP_REG1) | A(TMP_ZERO) | B(TMP_ZERO)));
+
+ size = compiler->size;
+
+ ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
+ FAIL_IF(!ptr);
+ compiler->size++;
+
+ if (src1 & SLJIT_MEM)
+ FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(type) | LOAD_DATA, dst_freg, src1, src1w, TMP_REG1));
+ else
+ FAIL_IF(push_inst(compiler, FMR | FD(dst_freg) | FB(src1)));
+
+ *ptr = BCx | get_bo_bi_flags(compiler, (type ^ 0x1) & ~SLJIT_32) | (sljit_ins)((compiler->size - size) << 2);
+ return SLJIT_SUCCESS;
}
#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
@@ -2813,7 +3056,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
PTR_FAIL_IF(emit_const(compiler, dst_r, init_value));
if (dst & SLJIT_MEM)
- PTR_FAIL_IF(emit_op(compiler, SLJIT_MOV, WORD_DATA, dst, dstw, TMP_REG1, 0, TMP_REG2, 0));
+ PTR_FAIL_IF(emit_op_mem(compiler, WORD_DATA, dst_r, dst, dstw, TMP_REG1));
return const_;
}
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeRISCV_32.c b/src/3rdparty/pcre2/src/sljit/sljitNativeRISCV_32.c
index b38e6924c8..396c956c19 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeRISCV_32.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeRISCV_32.c
@@ -27,7 +27,6 @@
static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r, sljit_sw imm, sljit_s32 tmp_r)
{
SLJIT_UNUSED_ARG(tmp_r);
- SLJIT_ASSERT(dst_r != tmp_r);
if (imm <= SIMM_MAX && imm >= SIMM_MIN)
return push_inst(compiler, ADDI | RD(dst_r) | RS1(TMP_ZERO) | IMM_I(imm));
@@ -43,6 +42,76 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r
return push_inst(compiler, ADDI | RD(dst_r) | RS1(dst_r) | IMM_I(imm));
}
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f64 value)
+{
+ union {
+ sljit_s32 imm[2];
+ sljit_f64 value;
+ } u;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fset64(compiler, freg, value));
+
+ u.value = value;
+
+ if (u.imm[0] != 0)
+ FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm[0], TMP_REG3));
+ if (u.imm[1] != 0)
+ FAIL_IF(load_immediate(compiler, TMP_REG2, u.imm[1], TMP_REG3));
+
+ FAIL_IF(push_inst(compiler, ADDI | RD(SLJIT_SP) | RS1(SLJIT_SP) | IMM_I(-16)));
+ FAIL_IF(push_inst(compiler, SW | RS1(SLJIT_SP) | RS2(u.imm[0] != 0 ? TMP_REG1 : TMP_ZERO) | (8 << 7)));
+ FAIL_IF(push_inst(compiler, SW | RS1(SLJIT_SP) | RS2(u.imm[1] != 0 ? TMP_REG2 : TMP_ZERO) | (12 << 7)));
+ FAIL_IF(push_inst(compiler, FLD | FRD(freg) | RS1(SLJIT_SP) | IMM_I(8)));
+ return push_inst(compiler, ADDI | RD(SLJIT_SP) | RS1(SLJIT_SP) | IMM_I(16));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 freg, sljit_s32 reg)
+{
+ sljit_ins inst;
+ sljit_s32 reg2 = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+ if (op & SLJIT_32) {
+ if (op == SLJIT_COPY32_TO_F32)
+ inst = FMV_W_X | RS1(reg) | FRD(freg);
+ else
+ inst = FMV_X_W | FRS1(freg) | RD(reg);
+
+ return push_inst(compiler, inst);
+ }
+
+ FAIL_IF(push_inst(compiler, ADDI | RD(SLJIT_SP) | RS1(SLJIT_SP) | IMM_I(-16)));
+
+ if (reg & REG_PAIR_MASK) {
+ reg2 = REG_PAIR_SECOND(reg);
+ reg = REG_PAIR_FIRST(reg);
+ }
+
+ if (op == SLJIT_COPY_TO_F64) {
+ if (reg2 != 0)
+ FAIL_IF(push_inst(compiler, SW | RS1(SLJIT_SP) | RS2(reg2) | (8 << 7)));
+ else
+ FAIL_IF(push_inst(compiler, FSW | RS1(SLJIT_SP) | FRS2(freg) | (8 << 7)));
+
+ FAIL_IF(push_inst(compiler, SW | RS1(SLJIT_SP) | RS2(reg) | (12 << 7)));
+ FAIL_IF(push_inst(compiler, FLD | FRD(freg) | RS1(SLJIT_SP) | IMM_I(8)));
+ } else {
+ FAIL_IF(push_inst(compiler, FSD | RS1(SLJIT_SP) | FRS2(freg) | (8 << 7)));
+
+ if (reg2 != 0)
+ FAIL_IF(push_inst(compiler, FMV_X_W | FRS1(freg) | RD(reg2)));
+
+ FAIL_IF(push_inst(compiler, LW | RD(reg) | RS1(SLJIT_SP) | IMM_I(12)));
+ }
+
+ return push_inst(compiler, ADDI | RD(SLJIT_SP) | RS1(SLJIT_SP) | IMM_I(16));
+}
+
static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value, sljit_ins last_ins)
{
if ((init_value & 0x800) != 0)
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeRISCV_64.c b/src/3rdparty/pcre2/src/sljit/sljitNativeRISCV_64.c
index 32cec7848d..7fcf2c5273 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeRISCV_64.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeRISCV_64.c
@@ -28,8 +28,6 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r
{
sljit_sw high;
- SLJIT_ASSERT(dst_r != tmp_r);
-
if (imm <= SIMM_MAX && imm >= SIMM_MIN)
return push_inst(compiler, ADDI | RD(dst_r) | RS1(TMP_ZERO) | IMM_I(imm));
@@ -81,6 +79,8 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r
return SLJIT_SUCCESS;
}
+ SLJIT_ASSERT(dst_r != tmp_r);
+
high = imm >> 32;
imm = (sljit_s32)imm;
@@ -126,6 +126,45 @@ static sljit_s32 load_immediate(struct sljit_compiler *compiler, sljit_s32 dst_r
return push_inst(compiler, XOR | RD(dst_r) | RS1(dst_r) | RS2(tmp_r));
}
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f64 value)
+{
+ union {
+ sljit_sw imm;
+ sljit_f64 value;
+ } u;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fset64(compiler, freg, value));
+
+ u.value = value;
+
+ if (u.imm == 0)
+ return push_inst(compiler, FMV_W_X | (1 << 25) | RS1(TMP_ZERO) | FRD(freg));
+
+ FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm, TMP_REG3));
+ return push_inst(compiler, FMV_W_X | (1 << 25) | RS1(TMP_REG1) | FRD(freg));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 freg, sljit_s32 reg)
+{
+ sljit_ins inst;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+ if (GET_OPCODE(op) == SLJIT_COPY_TO_F64)
+ inst = FMV_W_X | RS1(reg) | FRD(freg);
+ else
+ inst = FMV_X_W | FRS1(freg) | RD(reg);
+
+ if (!(op & SLJIT_32))
+ inst |= (sljit_ins)1 << 25;
+
+ return push_inst(compiler, inst);
+}
+
static SLJIT_INLINE sljit_s32 emit_const(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw init_value, sljit_ins last_ins)
{
sljit_sw high;
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeRISCV_common.c b/src/3rdparty/pcre2/src/sljit/sljitNativeRISCV_common.c
index 58a48c649c..64bd411d9d 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeRISCV_common.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeRISCV_common.c
@@ -97,16 +97,20 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 3] = {
#define FLD (F3(0x3) | OPC(0x7))
#define FLE_S (F7(0x50) | F3(0x0) | OPC(0x53))
#define FLT_S (F7(0x50) | F3(0x1) | OPC(0x53))
-#define FSD (F3(0x3) | OPC(0x27))
/* These conversion opcodes are partly defined. */
#define FCVT_S_D (F7(0x20) | OPC(0x53))
#define FCVT_S_W (F7(0x68) | OPC(0x53))
+#define FCVT_S_WU (F7(0x68) | F12(0x1) | OPC(0x53))
#define FCVT_W_S (F7(0x60) | F3(0x1) | OPC(0x53))
#define FMUL_S (F7(0x8) | F3(0x7) | OPC(0x53))
+#define FMV_X_W (F7(0x70) | F3(0x0) | OPC(0x53))
+#define FMV_W_X (F7(0x78) | F3(0x0) | OPC(0x53))
+#define FSD (F3(0x3) | OPC(0x27))
#define FSGNJ_S (F7(0x10) | F3(0x0) | OPC(0x53))
#define FSGNJN_S (F7(0x10) | F3(0x1) | OPC(0x53))
#define FSGNJX_S (F7(0x10) | F3(0x2) | OPC(0x53))
#define FSUB_S (F7(0x4) | F3(0x7) | OPC(0x53))
+#define FSW (F3(0x2) | OPC(0x27))
#define JAL (OPC(0x6f))
#define JALR (F3(0x0) | OPC(0x67))
#define LD (F3(0x3) | OPC(0x3))
@@ -344,13 +348,12 @@ static SLJIT_INLINE void load_addr_to_reg(void *dst, sljit_u32 reg)
if ((addr & 0x80000000l) != 0)
high = ~high;
- if ((high & 0x800) != 0)
- high += 0x1000;
-
if (flags & PATCH_ABS52) {
SLJIT_ASSERT(addr <= S52_MAX);
inst[0] = LUI | RD(TMP_REG3) | (sljit_ins)(high << 12);
} else {
+ if ((high & 0x800) != 0)
+ high += 0x1000;
inst[0] = LUI | RD(TMP_REG3) | (sljit_ins)(high & ~0xfff);
inst[1] = ADDI | RD(TMP_REG3) | RS1(TMP_REG3) | IMM_I(high);
inst++;
@@ -531,7 +534,18 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
{
switch (feature_type) {
case SLJIT_HAS_FPU:
+#ifdef SLJIT_IS_FPU_AVAILABLE
+ return (SLJIT_IS_FPU_AVAILABLE) != 0;
+#elif defined(__riscv_float_abi_soft)
+ return 0;
+#else
+ return 1;
+#endif /* SLJIT_IS_FPU_AVAILABLE */
case SLJIT_HAS_ZERO_REGISTER:
+ case SLJIT_HAS_COPY_F32:
+#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
+ case SLJIT_HAS_COPY_F64:
+#endif /* !SLJIT_CONFIG_RISCV_64 */
return 1;
default:
return 0;
@@ -540,7 +554,17 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type)
{
- return (type >= SLJIT_ORDERED_EQUAL && type <= SLJIT_ORDERED_LESS_EQUAL);
+ switch (type) {
+ case SLJIT_UNORDERED_OR_EQUAL:
+ case SLJIT_ORDERED_NOT_EQUAL:
+ return 2;
+
+ case SLJIT_UNORDERED:
+ case SLJIT_ORDERED:
+ return 1;
+ }
+
+ return 0;
}
/* --------------------------------------------------------------------- */
@@ -610,10 +634,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
if (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) {
if ((local_size & SSIZE_OF(sw)) != 0)
local_size += SSIZE_OF(sw);
- local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64));
+ local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
}
#else
- local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64));
+ local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
#endif
local_size = (local_size + SLJIT_LOCALS_OFFSET + 15) & ~0xf;
compiler->local_size = local_size;
@@ -704,10 +728,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *comp
if (fsaveds > 0 || fscratches >= SLJIT_FIRST_SAVED_FLOAT_REG) {
if ((local_size & SSIZE_OF(sw)) != 0)
local_size += SSIZE_OF(sw);
- local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64));
+ local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
}
#else
- local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sizeof(sljit_f64));
+ local_size += GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, f64);
#endif
compiler->local_size = (local_size + SLJIT_LOCALS_OFFSET + 15) & ~0xf;
@@ -915,7 +939,7 @@ static sljit_s32 getput_arg(struct sljit_compiler *compiler, sljit_s32 flags, sl
/* Since tmp can be the same as base or offset registers,
* these might be unavailable after modifying tmp. */
- if ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA))
+ if ((flags & MEM_MASK) <= GPR_REG && (flags & LOAD_DATA) && reg == TMP_REG2)
tmp_r = reg;
if (SLJIT_UNLIKELY(arg & OFFS_REG_MASK)) {
@@ -1031,9 +1055,11 @@ static SLJIT_INLINE sljit_s32 emit_op_mem2(struct sljit_compiler *compiler, slji
#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32)
#define WORD 0
+#define WORD_32 0
#define IMM_EXTEND(v) (IMM_I(v))
#else /* !SLJIT_CONFIG_RISCV_32 */
#define WORD word
+#define WORD_32 0x08
#define IMM_EXTEND(v) (IMM_I((op & SLJIT_32) ? (v) : (32 + (v))))
#endif /* SLJIT_CONFIG_RISCV_32 */
@@ -1041,16 +1067,16 @@ static sljit_s32 emit_clz_ctz(struct sljit_compiler *compiler, sljit_s32 op, slj
{
sljit_s32 is_clz = (GET_OPCODE(op) == SLJIT_CLZ);
#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
- sljit_ins word = (op & SLJIT_32) >> 5;
- sljit_ins max = (op & SLJIT_32) ? 32 : 64;
+ sljit_ins word = (sljit_ins)(op & SLJIT_32) >> 5;
+ sljit_ins word_size = (op & SLJIT_32) ? 32 : 64;
#else /* !SLJIT_CONFIG_RISCV_64 */
- sljit_ins max = 32;
+ sljit_ins word_size = 32;
#endif /* SLJIT_CONFIG_RISCV_64 */
SLJIT_ASSERT(WORD == 0 || WORD == 0x8);
/* The OTHER_FLAG is the counter. */
- FAIL_IF(push_inst(compiler, ADDI | WORD | RD(OTHER_FLAG) | RS1(TMP_ZERO) | IMM_I(max)));
+ FAIL_IF(push_inst(compiler, ADDI | WORD | RD(OTHER_FLAG) | RS1(TMP_ZERO) | IMM_I(word_size)));
/* The TMP_REG2 is the next value. */
if (src != TMP_REG2)
@@ -1066,7 +1092,7 @@ static sljit_s32 emit_clz_ctz(struct sljit_compiler *compiler, sljit_s32 op, slj
FAIL_IF(push_inst(compiler, BLT | RS1(TMP_REG2) | RS2(TMP_ZERO) | ((sljit_ins)(2 * SSIZE_OF(ins)) << 7) | ((sljit_ins)(8 * SSIZE_OF(ins)) << 20)));
/* The TMP_REG1 is the next shift. */
- FAIL_IF(push_inst(compiler, ADDI | WORD | RD(TMP_REG1) | RS1(TMP_ZERO) | IMM_I(max)));
+ FAIL_IF(push_inst(compiler, ADDI | WORD | RD(TMP_REG1) | RS1(TMP_ZERO) | IMM_I(word_size)));
FAIL_IF(push_inst(compiler, ADDI | WORD | RD(EQUAL_FLAG) | RS1(TMP_REG2) | IMM_I(0)));
FAIL_IF(push_inst(compiler, SRLI | WORD | RD(TMP_REG1) | RS1(TMP_REG1) | IMM_I(1)));
@@ -1081,6 +1107,65 @@ static sljit_s32 emit_clz_ctz(struct sljit_compiler *compiler, sljit_s32 op, slj
return push_inst(compiler, ADDI | WORD | RD(dst) | RS1(OTHER_FLAG) | IMM_I(0));
}
+static sljit_s32 emit_rev(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst, sljit_sw src)
+{
+ SLJIT_UNUSED_ARG(op);
+
+#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
+ if (!(op & SLJIT_32)) {
+ FAIL_IF(push_inst(compiler, LUI | RD(OTHER_FLAG) | 0x10000));
+ FAIL_IF(push_inst(compiler, SRLI | RD(TMP_REG1) | RS1(src) | IMM_I(32)));
+ FAIL_IF(push_inst(compiler, ADDI | RD(OTHER_FLAG) | RS1(OTHER_FLAG) | IMM_I(0xfff)));
+ FAIL_IF(push_inst(compiler, SLLI | RD(dst) | RS1(src) | IMM_I(32)));
+ FAIL_IF(push_inst(compiler, SLLI | RD(EQUAL_FLAG) | RS1(OTHER_FLAG) | IMM_I(32)));
+ FAIL_IF(push_inst(compiler, OR | RD(dst) | RS1(dst) | RS2(TMP_REG1)));
+ FAIL_IF(push_inst(compiler, OR | RD(OTHER_FLAG) | RS1(OTHER_FLAG) | RS2(EQUAL_FLAG)));
+
+ FAIL_IF(push_inst(compiler, SRLI | RD(TMP_REG1) | RS1(dst) | IMM_I(16)));
+ FAIL_IF(push_inst(compiler, AND | RD(dst) | RS1(dst) | RS2(OTHER_FLAG)));
+ FAIL_IF(push_inst(compiler, AND | RD(TMP_REG1) | RS1(TMP_REG1) | RS2(OTHER_FLAG)));
+ FAIL_IF(push_inst(compiler, SLLI | RD(EQUAL_FLAG) | RS1(OTHER_FLAG) | IMM_I(8)));
+ FAIL_IF(push_inst(compiler, SLLI | RD(dst) | RS1(dst) | IMM_I(16)));
+ FAIL_IF(push_inst(compiler, XOR | RD(OTHER_FLAG) | RS1(OTHER_FLAG) | RS2(EQUAL_FLAG)));
+ FAIL_IF(push_inst(compiler, OR | RD(dst) | RS1(dst) | RS2(TMP_REG1)));
+
+ FAIL_IF(push_inst(compiler, SRLI | RD(TMP_REG1) | RS1(dst) | IMM_I(8)));
+ FAIL_IF(push_inst(compiler, AND | RD(dst) | RS1(dst) | RS2(OTHER_FLAG)));
+ FAIL_IF(push_inst(compiler, AND | RD(TMP_REG1) | RS1(TMP_REG1) | RS2(OTHER_FLAG)));
+ FAIL_IF(push_inst(compiler, SLLI | RD(dst) | RS1(dst) | IMM_I(8)));
+ return push_inst(compiler, OR | RD(dst) | RS1(dst) | RS2(TMP_REG1));
+ }
+#endif /* SLJIT_CONFIG_RISCV_64 */
+
+ FAIL_IF(push_inst(compiler, SRLI | WORD_32 | RD(TMP_REG1) | RS1(src) | IMM_I(16)));
+ FAIL_IF(push_inst(compiler, LUI | RD(OTHER_FLAG) | 0xff0000));
+ FAIL_IF(push_inst(compiler, SLLI | WORD_32 | RD(dst) | RS1(src) | IMM_I(16)));
+ FAIL_IF(push_inst(compiler, ORI | RD(OTHER_FLAG) | RS1(OTHER_FLAG) | IMM_I(0xff)));
+ FAIL_IF(push_inst(compiler, OR | RD(dst) | RS1(dst) | RS2(TMP_REG1)));
+
+ FAIL_IF(push_inst(compiler, SRLI | WORD_32 | RD(TMP_REG1) | RS1(dst) | IMM_I(8)));
+ FAIL_IF(push_inst(compiler, AND | RD(dst) | RS1(dst) | RS2(OTHER_FLAG)));
+ FAIL_IF(push_inst(compiler, AND | RD(TMP_REG1) | RS1(TMP_REG1) | RS2(OTHER_FLAG)));
+ FAIL_IF(push_inst(compiler, SLLI | WORD_32 | RD(dst) | RS1(dst) | IMM_I(8)));
+ return push_inst(compiler, OR | RD(dst) | RS1(dst) | RS2(TMP_REG1));
+}
+
+static sljit_s32 emit_rev16(struct sljit_compiler *compiler, sljit_s32 op, sljit_s32 dst, sljit_sw src)
+{
+#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
+ sljit_ins word = (sljit_ins)(op & SLJIT_32) >> 5;
+ sljit_ins word_size = (op & SLJIT_32) ? 32 : 64;
+#else /* !SLJIT_CONFIG_RISCV_64 */
+ sljit_ins word_size = 32;
+#endif /* SLJIT_CONFIG_RISCV_64 */
+
+ FAIL_IF(push_inst(compiler, SRLI | WORD | RD(TMP_REG1) | RS1(src) | IMM_I(8)));
+ FAIL_IF(push_inst(compiler, SLLI | WORD | RD(dst) | RS1(src) | IMM_I(word_size - 8)));
+ FAIL_IF(push_inst(compiler, ANDI | RD(TMP_REG1) | RS1(TMP_REG1) | IMM_I(0xff)));
+ FAIL_IF(push_inst(compiler, (GET_OPCODE(op) == SLJIT_REV_U16 ? SRLI : SRAI) | WORD | RD(dst) | RS1(dst) | IMM_I(word_size - 16)));
+ return push_inst(compiler, OR | RD(dst) | RS1(dst) | RS2(TMP_REG1));
+}
+
#define EMIT_LOGICAL(op_imm, op_reg) \
if (flags & SRC2_IMM) { \
if (op & SLJIT_SET_Z) \
@@ -1105,7 +1190,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
sljit_s32 is_overflow, is_carry, carry_src_r, is_handled;
sljit_ins op_imm, op_reg;
#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
- sljit_ins word = (op & SLJIT_32) >> 5;
+ sljit_ins word = (sljit_ins)(op & SLJIT_32) >> 5;
#endif /* SLJIT_CONFIG_RISCV_64 */
SLJIT_ASSERT(WORD == 0 || WORD == 0x8);
@@ -1174,10 +1259,33 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
return emit_clz_ctz(compiler, op, dst, src2);
+ case SLJIT_REV:
+ case SLJIT_REV_S32:
+#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32)
+ case SLJIT_REV_U32:
+#endif /* SLJIT_CONFIG_RISCV_32 */
+ SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+ return emit_rev(compiler, op, dst, src2);
+
+ case SLJIT_REV_U16:
+ case SLJIT_REV_S16:
+ SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
+ return emit_rev16(compiler, op, dst, src2);
+
+#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
+ case SLJIT_REV_U32:
+ SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM) && dst != TMP_REG1);
+ FAIL_IF(emit_rev(compiler, op, dst, src2));
+ if (dst == TMP_REG2)
+ return SLJIT_SUCCESS;
+ FAIL_IF(push_inst(compiler, SLLI | RD(dst) | RS1(dst) | IMM_I(32)));
+ return push_inst(compiler, SRLI | RD(dst) | RS1(dst) | IMM_I(32));
+#endif /* SLJIT_CONFIG_RISCV_32 */
+
case SLJIT_ADD:
/* Overflow computation (both add and sub): overflow = src1_sign ^ src2_sign ^ result_sign ^ carry_flag */
is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
- carry_src_r = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
+ carry_src_r = GET_FLAG_TYPE(op) == SLJIT_CARRY;
if (flags & SRC2_IMM) {
if (is_overflow) {
@@ -1233,7 +1341,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
return push_inst(compiler, XOR | RD(OTHER_FLAG) | RS1(TMP_REG1) | RS2(OTHER_FLAG));
case SLJIT_ADDC:
- carry_src_r = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
+ carry_src_r = GET_FLAG_TYPE(op) == SLJIT_CARRY;
if (flags & SRC2_IMM) {
FAIL_IF(push_inst(compiler, ADDI | WORD | RD(dst) | RS1(src1) | IMM_I(src2)));
@@ -1280,11 +1388,11 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
is_handled = 0;
if (flags & SRC2_IMM) {
- if (GET_FLAG_TYPE(op) == SLJIT_LESS || GET_FLAG_TYPE(op) == SLJIT_GREATER_EQUAL) {
+ if (GET_FLAG_TYPE(op) == SLJIT_LESS) {
FAIL_IF(push_inst(compiler, SLTUI | RD(OTHER_FLAG) | RS1(src1) | IMM_I(src2)));
is_handled = 1;
}
- else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS || GET_FLAG_TYPE(op) == SLJIT_SIG_GREATER_EQUAL) {
+ else if (GET_FLAG_TYPE(op) == SLJIT_SIG_LESS) {
FAIL_IF(push_inst(compiler, SLTI | RD(OTHER_FLAG) | RS1(src1) | IMM_I(src2)));
is_handled = 1;
}
@@ -1301,19 +1409,15 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
switch (GET_FLAG_TYPE(op)) {
case SLJIT_LESS:
- case SLJIT_GREATER_EQUAL:
FAIL_IF(push_inst(compiler, SLTU | RD(OTHER_FLAG) | RS1(src1) | RS2(src2)));
break;
case SLJIT_GREATER:
- case SLJIT_LESS_EQUAL:
FAIL_IF(push_inst(compiler, SLTU | RD(OTHER_FLAG) | RS1(src2) | RS2(src1)));
break;
case SLJIT_SIG_LESS:
- case SLJIT_SIG_GREATER_EQUAL:
FAIL_IF(push_inst(compiler, SLT | RD(OTHER_FLAG) | RS1(src1) | RS2(src2)));
break;
case SLJIT_SIG_GREATER:
- case SLJIT_SIG_LESS_EQUAL:
FAIL_IF(push_inst(compiler, SLT | RD(OTHER_FLAG) | RS1(src2) | RS2(src1)));
break;
}
@@ -1336,7 +1440,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
}
is_overflow = GET_FLAG_TYPE(op) == SLJIT_OVERFLOW;
- is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
+ is_carry = GET_FLAG_TYPE(op) == SLJIT_CARRY;
if (flags & SRC2_IMM) {
if (is_overflow) {
@@ -1385,7 +1489,7 @@ static SLJIT_INLINE sljit_s32 emit_single_op(struct sljit_compiler *compiler, sl
flags &= ~SRC2_IMM;
}
- is_carry = GET_FLAG_TYPE(op) == GET_FLAG_TYPE(SLJIT_SET_CARRY);
+ is_carry = GET_FLAG_TYPE(op) == SLJIT_CARRY;
if (flags & SRC2_IMM) {
if (is_carry)
@@ -1534,9 +1638,10 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
compiler->cache_argw = 0;
}
- if (dst == TMP_REG2) {
+ if (dst == 0) {
SLJIT_ASSERT(HAS_FLAGS(op));
flags |= UNUSED_DEST;
+ dst = TMP_REG2;
}
else if (FAST_IS_REG(dst)) {
dst_r = dst;
@@ -1548,11 +1653,11 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
flags |= SLOW_DEST;
if (flags & IMM_OP) {
- if ((src2 & SLJIT_IMM) && src2w != 0 && src2w <= SIMM_MAX && src2w >= SIMM_MIN) {
+ if (src2 == SLJIT_IMM && src2w != 0 && src2w <= SIMM_MAX && src2w >= SIMM_MIN) {
flags |= SRC2_IMM;
src2_r = src2w;
}
- else if ((flags & CUMULATIVE_OP) && (src1 & SLJIT_IMM) && src1w != 0 && src1w <= SIMM_MAX && src1w >= SIMM_MIN) {
+ else if ((flags & CUMULATIVE_OP) && src1 == SLJIT_IMM && src1w != 0 && src1w <= SIMM_MAX && src1w >= SIMM_MIN) {
flags |= SRC2_IMM;
src2_r = src1w;
@@ -1569,7 +1674,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
src1_r = src1;
flags |= REG1_SOURCE;
}
- else if (src1 & SLJIT_IMM) {
+ else if (src1 == SLJIT_IMM) {
if (src1w) {
FAIL_IF(load_immediate(compiler, TMP_REG1, src1w, TMP_REG3));
src1_r = TMP_REG1;
@@ -1592,7 +1697,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
if ((flags & (REG_DEST | MOVE_OP)) == MOVE_OP)
dst_r = (sljit_s32)src2_r;
}
- else if (src2 & SLJIT_IMM) {
+ else if (src2 == SLJIT_IMM) {
if (!(flags & SRC2_IMM)) {
if (src2w) {
FAIL_IF(load_immediate(compiler, sugg_src2_r, src2w, TMP_REG3));
@@ -1649,7 +1754,7 @@ static sljit_s32 emit_op(struct sljit_compiler *compiler, sljit_s32 op, sljit_s3
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
{
#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
- sljit_ins word = (op & SLJIT_32) >> 5;
+ sljit_ins word = (sljit_ins)(op & SLJIT_32) >> 5;
SLJIT_ASSERT(word == 0 || word == 0x8);
#endif /* SLJIT_CONFIG_RISCV_64 */
@@ -1718,32 +1823,38 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
case SLJIT_MOV_U32:
- return emit_op(compiler, SLJIT_MOV_U32, INT_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u32)srcw : srcw);
+ return emit_op(compiler, SLJIT_MOV_U32, INT_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u32)srcw : srcw);
case SLJIT_MOV_S32:
/* Logical operators have no W variant, so sign extended input is necessary for them. */
case SLJIT_MOV32:
- return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s32)srcw : srcw);
+ return emit_op(compiler, SLJIT_MOV_S32, INT_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s32)srcw : srcw);
#endif
case SLJIT_MOV_U8:
- return emit_op(compiler, op, BYTE_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u8)srcw : srcw);
+ return emit_op(compiler, op, BYTE_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u8)srcw : srcw);
case SLJIT_MOV_S8:
- return emit_op(compiler, op, BYTE_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s8)srcw : srcw);
+ return emit_op(compiler, op, BYTE_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s8)srcw : srcw);
case SLJIT_MOV_U16:
- return emit_op(compiler, op, HALF_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_u16)srcw : srcw);
+ return emit_op(compiler, op, HALF_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_u16)srcw : srcw);
case SLJIT_MOV_S16:
- return emit_op(compiler, op, HALF_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src & SLJIT_IMM) ? (sljit_s16)srcw : srcw);
-
- case SLJIT_NOT:
- return emit_op(compiler, SLJIT_XOR | (op & (SLJIT_32 | SLJIT_SET_Z)), flags, dst, dstw, src, srcw, SLJIT_IMM, -1);
+ return emit_op(compiler, op, HALF_DATA | SIGNED_DATA | MOVE_OP, dst, dstw, TMP_REG1, 0, src, (src == SLJIT_IMM) ? (sljit_s16)srcw : srcw);
case SLJIT_CLZ:
case SLJIT_CTZ:
+ case SLJIT_REV:
return emit_op(compiler, op, flags, dst, dstw, TMP_REG1, 0, src, srcw);
+
+ case SLJIT_REV_U16:
+ case SLJIT_REV_S16:
+ return emit_op(compiler, op, HALF_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
+
+ case SLJIT_REV_U32:
+ case SLJIT_REV_S32:
+ return emit_op(compiler, op | SLJIT_32, INT_DATA, dst, dstw, TMP_REG1, 0, src, srcw);
}
SLJIT_UNREACHABLE();
@@ -1766,9 +1877,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
if (op & SLJIT_32) {
flags |= INT_DATA | SIGNED_DATA;
- if (src1 & SLJIT_IMM)
+ if (src1 == SLJIT_IMM)
src1w = (sljit_s32)src1w;
- if (src2 & SLJIT_IMM)
+ if (src2 == SLJIT_IMM)
src2w = (sljit_s32)src2w;
}
#endif
@@ -1801,7 +1912,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
case SLJIT_MASHR:
case SLJIT_ROTL:
case SLJIT_ROTR:
- if (src2 & SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32)
src2w &= 0x1f;
#else /* !SLJIT_CONFIG_RISCV_32 */
@@ -1827,18 +1938,19 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil
CHECK(check_sljit_emit_op2(compiler, op, 1, 0, 0, src1, src1w, src2, src2w));
SLJIT_SKIP_CHECKS(compiler);
- return sljit_emit_op2(compiler, op, TMP_REG2, 0, src1, src1w, src2, src2w);
+ return sljit_emit_op2(compiler, op, 0, 0, src1, src1w, src2, src2w);
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 src_dst,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w)
+ sljit_s32 dst_reg,
+ sljit_s32 src1_reg,
+ sljit_s32 src2_reg,
+ sljit_s32 src3, sljit_sw src3w)
{
sljit_s32 is_left;
sljit_ins ins1, ins2, ins3;
#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
- sljit_ins word = (op & SLJIT_32) >> 5;
+ sljit_ins word = (sljit_ins)(op & SLJIT_32) >> 5;
sljit_s32 inp_flags = ((op & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA;
sljit_sw bit_length = (op & SLJIT_32) ? 32 : 64;
#else /* !SLJIT_CONFIG_RISCV_64 */
@@ -1849,50 +1961,44 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *
SLJIT_ASSERT(WORD == 0 || WORD == 0x8);
CHECK_ERROR();
- CHECK(check_sljit_emit_shift_into(compiler, op, src_dst, src1, src1w, src2, src2w));
+ CHECK(check_sljit_emit_shift_into(compiler, op, dst_reg, src1_reg, src2_reg, src3, src3w));
is_left = (GET_OPCODE(op) == SLJIT_SHL || GET_OPCODE(op) == SLJIT_MSHL);
- if (src_dst == src1) {
+ if (src1_reg == src2_reg) {
SLJIT_SKIP_CHECKS(compiler);
- return sljit_emit_op2(compiler, (is_left ? SLJIT_ROTL : SLJIT_ROTR) | (op & SLJIT_32), src_dst, 0, src_dst, 0, src2, src2w);
+ return sljit_emit_op2(compiler, (is_left ? SLJIT_ROTL : SLJIT_ROTR) | (op & SLJIT_32), dst_reg, 0, src1_reg, 0, src3, src3w);
}
- ADJUST_LOCAL_OFFSET(src1, src1w);
- ADJUST_LOCAL_OFFSET(src2, src2w);
+ ADJUST_LOCAL_OFFSET(src3, src3w);
- if (src2 & SLJIT_IMM) {
- src2w &= bit_length - 1;
+ if (src3 == SLJIT_IMM) {
+ src3w &= bit_length - 1;
- if (src2w == 0)
+ if (src3w == 0)
return SLJIT_SUCCESS;
- } else if (src2 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG2, src2, src2w));
- src2 = TMP_REG2;
- }
- if (src1 & SLJIT_MEM) {
- FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG1, src1, src1w));
- src1 = TMP_REG1;
- } else if (src1 & SLJIT_IMM) {
- FAIL_IF(load_immediate(compiler, TMP_REG1, src1w, TMP_REG3));
- src1 = TMP_REG1;
- }
-
- if (src2 & SLJIT_IMM) {
if (is_left) {
- ins1 = SLLI | WORD | IMM_I(src2w);
- src2w = bit_length - src2w;
- ins2 = SRLI | WORD | IMM_I(src2w);
+ ins1 = SLLI | WORD | IMM_I(src3w);
+ src3w = bit_length - src3w;
+ ins2 = SRLI | WORD | IMM_I(src3w);
} else {
- ins1 = SRLI | WORD | IMM_I(src2w);
- src2w = bit_length - src2w;
- ins2 = SLLI | WORD | IMM_I(src2w);
+ ins1 = SRLI | WORD | IMM_I(src3w);
+ src3w = bit_length - src3w;
+ ins2 = SLLI | WORD | IMM_I(src3w);
}
- FAIL_IF(push_inst(compiler, ins1 | RD(src_dst) | RS1(src_dst)));
- FAIL_IF(push_inst(compiler, ins2 | RD(TMP_REG1) | RS1(src1)));
- return push_inst(compiler, OR | RD(src_dst) | RS1(src_dst) | RS2(TMP_REG1));
+ FAIL_IF(push_inst(compiler, ins1 | RD(dst_reg) | RS1(src1_reg)));
+ FAIL_IF(push_inst(compiler, ins2 | RD(TMP_REG1) | RS1(src2_reg)));
+ return push_inst(compiler, OR | RD(dst_reg) | RS1(dst_reg) | RS2(TMP_REG1));
+ }
+
+ if (src3 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, inp_flags, TMP_REG2, src3, src3w));
+ src3 = TMP_REG2;
+ } else if (dst_reg == src3) {
+ push_inst(compiler, ADDI | WORD | RD(TMP_REG2) | RS1(src3) | IMM_I(0));
+ src3 = TMP_REG2;
}
if (is_left) {
@@ -1905,21 +2011,19 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *
ins3 = SLL;
}
- FAIL_IF(push_inst(compiler, ins1 | WORD | RD(src_dst) | RS1(src_dst) | RS2(src2)));
+ FAIL_IF(push_inst(compiler, ins1 | WORD | RD(dst_reg) | RS1(src1_reg) | RS2(src3)));
if (!(op & SLJIT_SHIFT_INTO_NON_ZERO)) {
- FAIL_IF(push_inst(compiler, ins2 | WORD | RD(TMP_REG1) | RS1(src1) | IMM_I(1)));
- FAIL_IF(push_inst(compiler, XORI | RD(TMP_REG2) | RS1(src2) | IMM_I((sljit_ins)bit_length - 1)));
- src1 = TMP_REG1;
+ FAIL_IF(push_inst(compiler, ins2 | WORD | RD(TMP_REG1) | RS1(src2_reg) | IMM_I(1)));
+ FAIL_IF(push_inst(compiler, XORI | RD(TMP_REG2) | RS1(src3) | IMM_I((sljit_ins)bit_length - 1)));
+ src2_reg = TMP_REG1;
} else
- FAIL_IF(push_inst(compiler, SUB | WORD | RD(TMP_REG2) | RS1(TMP_ZERO) | RS2(src2)));
+ FAIL_IF(push_inst(compiler, SUB | WORD | RD(TMP_REG2) | RS1(TMP_ZERO) | RS2(src3)));
- FAIL_IF(push_inst(compiler, ins3 | WORD | RD(TMP_REG1) | RS1(src1) | RS2(TMP_REG2)));
- return push_inst(compiler, OR | RD(src_dst) | RS1(src_dst) | RS2(TMP_REG1));
+ FAIL_IF(push_inst(compiler, ins3 | WORD | RD(TMP_REG1) | RS1(src2_reg) | RS2(TMP_REG2)));
+ return push_inst(compiler, OR | RD(dst_reg) | RS1(dst_reg) | RS2(TMP_REG1));
}
-#undef WORD
-
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 src, sljit_sw srcw)
{
@@ -1947,21 +2051,52 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *comp
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw)
{
- CHECK_REG_INDEX(check_sljit_get_register_index(reg));
- return reg_map[reg];
+ sljit_s32 dst_r;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op_dst(compiler, op, dst, dstw));
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+
+ switch (op) {
+ case SLJIT_FAST_ENTER:
+ if (FAST_IS_REG(dst))
+ return push_inst(compiler, ADDI | RD(dst) | RS1(RETURN_ADDR_REG) | IMM_I(0));
+
+ SLJIT_ASSERT(RETURN_ADDR_REG == TMP_REG2);
+ break;
+ case SLJIT_GET_RETURN_ADDRESS:
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_REG2;
+ FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, dst_r, SLJIT_MEM1(SLJIT_SP), compiler->local_size - SSIZE_OF(sw)));
+ break;
+ }
+
+ if (dst & SLJIT_MEM)
+ return emit_op_mem(compiler, WORD_DATA, TMP_REG2, dst, dstw);
+
+ return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 type, sljit_s32 reg)
{
- CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
+ CHECK_REG_INDEX(check_sljit_get_register_index(type, reg));
+
+ if (type == SLJIT_GP_REGISTER)
+ return reg_map[reg];
+
+ if (type != SLJIT_FLOAT_REGISTER)
+ return -1;
+
return freg_map[reg];
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
void *instruction, sljit_u32 size)
{
+ SLJIT_UNUSED_ARG(size);
+
CHECK_ERROR();
CHECK(check_sljit_emit_op_custom(compiler, instruction, size));
@@ -2008,51 +2143,73 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_comp
#endif
}
-static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+static sljit_s32 sljit_emit_fop1_conv_f64_from_w(struct sljit_compiler *compiler, sljit_ins ins,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 src, sljit_sw srcw)
{
- sljit_ins inst;
-#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
- sljit_u32 flags = ((sljit_u32)(GET_OPCODE(op) == SLJIT_CONV_F64_FROM_SW)) << 21;
-#endif
-
sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
if (src & SLJIT_MEM) {
#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32)
FAIL_IF(emit_op_mem2(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw, dst, dstw));
-#else
- FAIL_IF(emit_op_mem2(compiler, (flags ? WORD_DATA : INT_DATA) | LOAD_DATA, TMP_REG1, src, srcw, dst, dstw));
-#endif
+#else /* SLJIT_CONFIG_RISCV_32 */
+ FAIL_IF(emit_op_mem2(compiler, ((ins & (1 << 21)) ? WORD_DATA : INT_DATA) | LOAD_DATA, TMP_REG1, src, srcw, dst, dstw));
+#endif /* !SLJIT_CONFIG_RISCV_32 */
src = TMP_REG1;
- } else if (src & SLJIT_IMM) {
-#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
- if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
- srcw = (sljit_s32)srcw;
-#endif
-
+ } else if (src == SLJIT_IMM) {
FAIL_IF(load_immediate(compiler, TMP_REG1, srcw, TMP_REG3));
src = TMP_REG1;
}
- inst = FCVT_S_W | FMT(op) | FRD(dst_r) | RS1(src);
+ FAIL_IF(push_inst(compiler, ins | FRD(dst_r) | RS1(src)));
+
+ if (dst & SLJIT_MEM)
+ return emit_op_mem2(compiler, DOUBLE_DATA | ((sljit_s32)(~ins >> 24) & 0x2), TMP_FREG1, dst, dstw, 0, 0);
+ return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_ins ins = FCVT_S_W | FMT(op);
#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32)
if (op & SLJIT_32)
- inst |= F3(0x7);
-#else
- inst |= flags;
+ ins |= F3(0x7);
+#else /* !SLJIT_CONFIG_RISCV_32 */
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_SW)
+ ins |= (1 << 21);
+ else if (src == SLJIT_IMM)
+ srcw = (sljit_s32)srcw;
if (op != SLJIT_CONV_F64_FROM_S32)
- inst |= F3(0x7);
-#endif
+ ins |= F3(0x7);
+#endif /* SLJIT_CONFIG_RISCV_32 */
- FAIL_IF(push_inst(compiler, inst));
+ return sljit_emit_fop1_conv_f64_from_w(compiler, ins, dst, dstw, src, srcw);
+}
- if (dst & SLJIT_MEM)
- return emit_op_mem2(compiler, FLOAT_DATA(op), TMP_FREG1, dst, dstw, 0, 0);
- return SLJIT_SUCCESS;
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_uw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_ins ins = FCVT_S_WU | FMT(op);
+
+#if (defined SLJIT_CONFIG_RISCV_32 && SLJIT_CONFIG_RISCV_32)
+ if (op & SLJIT_32)
+ ins |= F3(0x7);
+#else /* !SLJIT_CONFIG_RISCV_32 */
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_UW)
+ ins |= (1 << 21);
+ else if (src == SLJIT_IMM)
+ srcw = (sljit_u32)srcw;
+
+ if (op != SLJIT_CONV_F64_FROM_S32)
+ ins |= F3(0x7);
+#endif /* SLJIT_CONFIG_RISCV_32 */
+
+ return sljit_emit_fop1_conv_f64_from_w(compiler, ins, dst, dstw, src, srcw);
}
static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
@@ -2073,40 +2230,36 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compile
switch (GET_FLAG_TYPE(op)) {
case SLJIT_F_EQUAL:
- case SLJIT_F_NOT_EQUAL:
case SLJIT_ORDERED_EQUAL:
- case SLJIT_UNORDERED_OR_NOT_EQUAL:
inst = FEQ_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src1) | FRS2(src2);
break;
case SLJIT_F_LESS:
- case SLJIT_F_GREATER_EQUAL:
case SLJIT_ORDERED_LESS:
- case SLJIT_UNORDERED_OR_GREATER_EQUAL:
inst = FLT_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src1) | FRS2(src2);
break;
case SLJIT_ORDERED_GREATER:
- case SLJIT_UNORDERED_OR_LESS_EQUAL:
inst = FLT_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src2) | FRS2(src1);
break;
case SLJIT_F_GREATER:
- case SLJIT_F_LESS_EQUAL:
case SLJIT_UNORDERED_OR_GREATER:
- case SLJIT_ORDERED_LESS_EQUAL:
inst = FLE_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src1) | FRS2(src2);
break;
case SLJIT_UNORDERED_OR_LESS:
- case SLJIT_ORDERED_GREATER_EQUAL:
inst = FLE_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src2) | FRS2(src1);
break;
- case SLJIT_UNORDERED_OR_EQUAL: /* Not supported. */
- case SLJIT_ORDERED_NOT_EQUAL: /* Not supported. */
+ case SLJIT_UNORDERED_OR_EQUAL:
FAIL_IF(push_inst(compiler, FLT_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src1) | FRS2(src2)));
FAIL_IF(push_inst(compiler, FLT_S | FMT(op) | RD(TMP_REG1) | FRS1(src2) | FRS2(src1)));
inst = OR | RD(OTHER_FLAG) | RS1(OTHER_FLAG) | RS2(TMP_REG1);
break;
- default: /* SLJIT_UNORDERED, SLJIT_ORDERED */
- FAIL_IF(push_inst(compiler, FADD_S | FMT(op) | FRD(TMP_FREG1) | FRS1(src1) | FRS2(src2)));
- inst = FEQ_S | FMT(op) | RD(OTHER_FLAG) | FRS1(TMP_FREG1) | FRS2(TMP_FREG1);
+ default: /* SLJIT_UNORDERED */
+ if (src1 == src2) {
+ inst = FEQ_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src1) | FRS2(src1);
+ break;
+ }
+ FAIL_IF(push_inst(compiler, FEQ_S | FMT(op) | RD(OTHER_FLAG) | FRS1(src1) | FRS2(src1)));
+ FAIL_IF(push_inst(compiler, FEQ_S | FMT(op) | RD(TMP_REG1) | FRS1(src2) | FRS2(src2)));
+ inst = AND | RD(OTHER_FLAG) | RS1(OTHER_FLAG) | RS2(TMP_REG1);
break;
}
@@ -2233,6 +2386,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
case SLJIT_DIV_F64:
FAIL_IF(push_inst(compiler, FDIV_S | FMT(op) | FRD(dst_r) | FRS1(src1) | FRS2(src2)));
break;
+
+ case SLJIT_COPYSIGN_F64:
+ return push_inst(compiler, FSGNJ_S | FMT(op) | FRD(dst_r) | FRS1(src1) | FRS2(src2));
}
if (dst_r == TMP_FREG2)
@@ -2241,24 +2397,24 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
return SLJIT_SUCCESS;
}
-#undef FLOAT_DATA
-#undef FMT
-
-/* --------------------------------------------------------------------- */
-/* Other instructions */
-/* --------------------------------------------------------------------- */
-
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset32(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f32 value)
{
+ union {
+ sljit_s32 imm;
+ sljit_f32 value;
+ } u;
+
CHECK_ERROR();
- CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
- ADJUST_LOCAL_OFFSET(dst, dstw);
+ CHECK(check_sljit_emit_fset32(compiler, freg, value));
+
+ u.value = value;
- if (FAST_IS_REG(dst))
- return push_inst(compiler, ADDI | RD(dst) | RS1(RETURN_ADDR_REG) | IMM_I(0));
+ if (u.imm == 0)
+ return push_inst(compiler, FMV_W_X | RS1(TMP_ZERO) | FRD(freg));
- /* Memory. */
- return emit_op_mem(compiler, WORD_DATA, RETURN_ADDR_REG, dst, dstw);
+ FAIL_IF(load_immediate(compiler, TMP_REG1, u.imm, TMP_REG3));
+ return push_inst(compiler, FMV_W_X | RS1(TMP_REG1) | FRD(freg));
}
/* --------------------------------------------------------------------- */
@@ -2287,26 +2443,13 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
#define BRANCH_LENGTH ((sljit_ins)(7 * sizeof(sljit_ins)) << 7)
#endif
-SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
+static sljit_ins get_jump_instruction(sljit_s32 type)
{
- struct sljit_jump *jump;
- sljit_ins inst;
-
- CHECK_ERROR_PTR();
- CHECK_PTR(check_sljit_emit_jump(compiler, type));
-
- jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
- PTR_FAIL_IF(!jump);
- set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
- type &= 0xff;
-
switch (type) {
case SLJIT_EQUAL:
- inst = BNE | RS1(EQUAL_FLAG) | RS2(TMP_ZERO) | BRANCH_LENGTH;
- break;
+ return BNE | RS1(EQUAL_FLAG) | RS2(TMP_ZERO);
case SLJIT_NOT_EQUAL:
- inst = BEQ | RS1(EQUAL_FLAG) | RS2(TMP_ZERO) | BRANCH_LENGTH;
- break;
+ return BEQ | RS1(EQUAL_FLAG) | RS2(TMP_ZERO);
case SLJIT_LESS:
case SLJIT_GREATER:
case SLJIT_SIG_LESS:
@@ -2315,7 +2458,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
case SLJIT_CARRY:
case SLJIT_F_EQUAL:
case SLJIT_ORDERED_EQUAL:
- case SLJIT_ORDERED_NOT_EQUAL: /* Not supported. */
+ case SLJIT_ORDERED_NOT_EQUAL:
case SLJIT_F_LESS:
case SLJIT_ORDERED_LESS:
case SLJIT_ORDERED_GREATER:
@@ -2323,7 +2466,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
case SLJIT_ORDERED_LESS_EQUAL:
case SLJIT_ORDERED_GREATER_EQUAL:
case SLJIT_ORDERED:
- inst = BEQ | RS1(OTHER_FLAG) | RS2(TMP_ZERO) | BRANCH_LENGTH;
+ return BEQ | RS1(OTHER_FLAG) | RS2(TMP_ZERO);
break;
case SLJIT_GREATER_EQUAL:
case SLJIT_LESS_EQUAL:
@@ -2333,7 +2476,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
case SLJIT_NOT_CARRY:
case SLJIT_F_NOT_EQUAL:
case SLJIT_UNORDERED_OR_NOT_EQUAL:
- case SLJIT_UNORDERED_OR_EQUAL: /* Not supported. */
+ case SLJIT_UNORDERED_OR_EQUAL:
case SLJIT_F_GREATER_EQUAL:
case SLJIT_UNORDERED_OR_GREATER_EQUAL:
case SLJIT_UNORDERED_OR_LESS_EQUAL:
@@ -2341,16 +2484,30 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
case SLJIT_UNORDERED_OR_GREATER:
case SLJIT_UNORDERED_OR_LESS:
case SLJIT_UNORDERED:
- inst = BNE | RS1(OTHER_FLAG) | RS2(TMP_ZERO) | BRANCH_LENGTH;
- break;
+ return BNE | RS1(OTHER_FLAG) | RS2(TMP_ZERO);
default:
/* Not conditional branch. */
- inst = 0;
- break;
+ return 0;
}
+}
+
+SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
+{
+ struct sljit_jump *jump;
+ sljit_ins inst;
+
+ CHECK_ERROR_PTR();
+ CHECK_PTR(check_sljit_emit_jump(compiler, type));
+
+ jump = (struct sljit_jump*)ensure_abuf(compiler, sizeof(struct sljit_jump));
+ PTR_FAIL_IF(!jump);
+ set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
+ type &= 0xff;
+
+ inst = get_jump_instruction(type);
if (inst != 0) {
- PTR_FAIL_IF(push_inst(compiler, inst));
+ PTR_FAIL_IF(push_inst(compiler, inst | BRANCH_LENGTH));
jump->flags |= IS_COND;
}
@@ -2420,7 +2577,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler
src2 = TMP_REG2;
}
- if (src1 & SLJIT_IMM) {
+ if (src1 == SLJIT_IMM) {
if (src1w != 0) {
PTR_FAIL_IF(load_immediate(compiler, TMP_REG1, src1w, TMP_REG3));
src1 = TMP_REG1;
@@ -2429,7 +2586,7 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_cmp(struct sljit_compiler
src1 = TMP_ZERO;
}
- if (src2 & SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
if (src2w != 0) {
PTR_FAIL_IF(load_immediate(compiler, TMP_REG2, src2w, TMP_REG3));
src2 = TMP_REG2;
@@ -2499,7 +2656,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
CHECK_ERROR();
CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
- if (!(src & SLJIT_IMM)) {
+ if (src != SLJIT_IMM) {
if (src & SLJIT_MEM) {
ADJUST_LOCAL_OFFSET(src, srcw);
FAIL_IF(emit_op_mem(compiler, WORD_DATA | LOAD_DATA, TMP_REG1, src, srcw));
@@ -2641,16 +2798,110 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
return emit_op(compiler, saved_op, mem_type, dst, dstw, dst, dstw, src_r, 0);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *compiler, sljit_s32 type,
sljit_s32 dst_reg,
- sljit_s32 src, sljit_sw srcw)
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_reg)
+{
+ sljit_ins *ptr;
+ sljit_uw size;
+#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
+ sljit_ins word = (sljit_ins)(type & SLJIT_32) >> 5;
+ sljit_s32 inp_flags = ((type & SLJIT_32) ? INT_DATA : WORD_DATA) | LOAD_DATA;
+#else /* !SLJIT_CONFIG_RISCV_64 */
+ sljit_s32 inp_flags = WORD_DATA | LOAD_DATA;
+#endif /* SLJIT_CONFIG_RISCV_64 */
+
+ SLJIT_ASSERT(WORD == 0 || WORD == 0x8);
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));
+
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+
+ if (dst_reg != src2_reg) {
+ if (dst_reg == src1) {
+ src1 = src2_reg;
+ src1w = 0;
+ type ^= 0x1;
+ } else {
+ if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) {
+ FAIL_IF(push_inst(compiler, ADDI | RD(TMP_REG2) | RS1(dst_reg) | IMM_I(0)));
+
+ if ((src1 & REG_MASK) == dst_reg)
+ src1 = (src1 & ~REG_MASK) | TMP_REG2;
+
+ if (OFFS_REG(src1) == dst_reg)
+ src1 = (src1 & ~OFFS_REG_MASK) | TO_OFFS_REG(TMP_REG2);
+ }
+
+ FAIL_IF(push_inst(compiler, ADDI | WORD | RD(dst_reg) | RS1(src2_reg) | IMM_I(0)));
+ }
+ }
+
+ size = compiler->size;
+
+ ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
+ FAIL_IF(!ptr);
+ compiler->size++;
+
+ if (src1 & SLJIT_MEM) {
+ FAIL_IF(emit_op_mem(compiler, inp_flags, dst_reg, src1, src1w));
+ } else if (src1 == SLJIT_IMM) {
+#if (defined SLJIT_CONFIG_RISCV_64 && SLJIT_CONFIG_RISCV_64)
+ if (word)
+ src1w = (sljit_s32)src1w;
+#endif /* SLJIT_CONFIG_RISCV_64 */
+ FAIL_IF(load_immediate(compiler, dst_reg, src1w, TMP_REG1));
+ } else
+ FAIL_IF(push_inst(compiler, ADDI | WORD | RD(dst_reg) | RS1(src1) | IMM_I(0)));
+
+ *ptr = get_jump_instruction(type & ~SLJIT_32) | (sljit_ins)((compiler->size - size) << 9);
+ return SLJIT_SUCCESS;
+}
+
+#undef WORD
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_freg)
{
+ sljit_ins *ptr;
+ sljit_uw size;
+
CHECK_ERROR();
- CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
+ CHECK(check_sljit_emit_fselect(compiler, type, dst_freg, src1, src1w, src2_freg));
+
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+
+ if (dst_freg != src2_freg) {
+ if (dst_freg == src1) {
+ src1 = src2_freg;
+ src1w = 0;
+ type ^= 0x1;
+ } else
+ FAIL_IF(push_inst(compiler, FSGNJ_S | FMT(type) | FRD(dst_freg) | FRS1(src2_freg) | FRS2(src2_freg)));
+ }
+
+ size = compiler->size;
+
+ ptr = (sljit_ins*)ensure_buf(compiler, sizeof(sljit_ins));
+ FAIL_IF(!ptr);
+ compiler->size++;
+
+ if (src1 & SLJIT_MEM)
+ FAIL_IF(emit_op_mem(compiler, FLOAT_DATA(type) | LOAD_DATA, dst_freg, src1, src1w));
+ else
+ FAIL_IF(push_inst(compiler, FSGNJ_S | FMT(type) | FRD(dst_freg) | FRS1(src1) | FRS2(src1)));
- return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);;
+ *ptr = get_jump_instruction(type & ~SLJIT_32) | (sljit_ins)((compiler->size - size) << 9);
+ return SLJIT_SUCCESS;
}
+#undef FLOAT_DATA
+#undef FMT
+
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type,
sljit_s32 reg,
sljit_s32 mem, sljit_sw memw)
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeS390X.c b/src/3rdparty/pcre2/src/sljit/sljitNativeS390X.c
index 8b51bad9bc..67516f9b32 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeS390X.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeS390X.c
@@ -47,8 +47,8 @@ static const sljit_ins sljit_ins_const = (sljit_ins)1 << 48;
#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)
#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3)
-static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 4] = {
- 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 0, 1
+static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 5] = {
+ 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 0, 1, 14
};
/* there are also a[2-15] available, but they are slower to access and
@@ -83,7 +83,7 @@ static const sljit_gpr r10 = 10; /* reg_map[9] */
static const sljit_gpr r11 = 11; /* reg_map[10] */
static const sljit_gpr r12 = 12; /* reg_map[11]: GOT */
static const sljit_gpr r13 = 13; /* reg_map[12]: Literal Pool pointer */
-static const sljit_gpr r14 = 14; /* reg_map[0]: return address and flag register */
+static const sljit_gpr r14 = 14; /* reg_map[0]: return address */
static const sljit_gpr r15 = 15; /* reg_map[SLJIT_NUMBER_OF_REGISTERS + 1]: stack pointer */
/* WARNING: r12 and r13 shouldn't be used as per ABI recommendation */
@@ -96,20 +96,16 @@ static const sljit_gpr r15 = 15; /* reg_map[SLJIT_NUMBER_OF_REGISTERS + 1]: stac
#define tmp0 r0
#define tmp1 r1
-/* TODO(carenas): flags should move to a different register so that
- * link register doesn't need to change
- */
-
/* When reg cannot be unused. */
#define IS_GPR_REG(reg) ((reg > 0) && (reg) <= SLJIT_SP)
/* Link register. */
static const sljit_gpr link_r = 14; /* r14 */
-#define TMP_FREG1 (0)
+#define TMP_FREG1 (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
-static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1] = {
- 1, 0, 2, 4, 6, 3, 5, 7, 15, 14, 13, 12, 11, 10, 9, 8,
+static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2] = {
+ 0, 0, 2, 4, 6, 3, 5, 7, 15, 14, 13, 12, 11, 10, 9, 8, 1
};
#define R0A(r) (r)
@@ -126,7 +122,10 @@ static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1] = {
#define F0(r) ((sljit_ins)freg_map[r])
#define F4(r) (R4A((sljit_ins)freg_map[r]))
+#define F12(r) (R12A((sljit_ins)freg_map[r]))
#define F20(r) (R20A((sljit_ins)freg_map[r]))
+#define F28(r) (R28A((sljit_ins)freg_map[r]))
+#define F32(r) (R32A((sljit_ins)freg_map[r]))
#define F36(r) (R36A((sljit_ins)freg_map[r]))
struct sljit_s390x_const {
@@ -141,12 +140,6 @@ static SLJIT_INLINE sljit_gpr gpr(sljit_s32 r)
return reg_map[r];
}
-static SLJIT_INLINE sljit_gpr fgpr(sljit_s32 r)
-{
- SLJIT_ASSERT(r >= 0 && r < (sljit_s32)(sizeof(freg_map) / sizeof(freg_map[0])));
- return freg_map[r];
-}
-
/* Size of instruction in bytes. Tags must already be cleared. */
static SLJIT_INLINE sljit_uw sizeof_ins(sljit_ins ins)
{
@@ -217,6 +210,7 @@ static SLJIT_INLINE sljit_u8 get_cc(struct sljit_compiler *compiler, sljit_s32 t
}
/* fallthrough */
+ case SLJIT_ATOMIC_STORED:
case SLJIT_F_EQUAL:
case SLJIT_ORDERED_EQUAL:
return cc0;
@@ -236,6 +230,7 @@ static SLJIT_INLINE sljit_u8 get_cc(struct sljit_compiler *compiler, sljit_s32 t
return (cc1 | cc2 | cc3);
case SLJIT_LESS:
+ case SLJIT_ATOMIC_NOT_STORED:
return cc1;
case SLJIT_GREATER_EQUAL:
@@ -454,10 +449,12 @@ HAVE_FACILITY(have_misc2, MISCELLANEOUS_INSTRUCTION_EXTENSIONS_2_FACILITY)
static SLJIT_INLINE sljit_ins disp_s20(sljit_s32 d)
{
+ sljit_uw dh, dl;
+
SLJIT_ASSERT(is_s20(d));
- sljit_uw dh = (d >> 12) & 0xff;
- sljit_uw dl = (d << 8) & 0xfff00;
+ dh = (d >> 12) & 0xff;
+ dl = ((sljit_uw)d << 8) & 0xfff00;
return (dh | dl) << 8;
}
@@ -899,23 +896,17 @@ static sljit_s32 push_load_imm_inst(struct sljit_compiler *compiler, sljit_gpr t
if (((sljit_uw)v & ~(sljit_uw)0xffff000000000000) == 0)
return push_inst(compiler, llihh(target, (sljit_u16)(v >> 48)));
- /* 6 byte instructions (requires extended immediate facility) */
- if (have_eimm()) {
- if (is_s32(v))
- return push_inst(compiler, lgfi(target, (sljit_s32)v));
+ if (is_s32(v))
+ return push_inst(compiler, lgfi(target, (sljit_s32)v));
- if (((sljit_uw)v >> 32) == 0)
- return push_inst(compiler, llilf(target, (sljit_u32)v));
+ if (((sljit_uw)v >> 32) == 0)
+ return push_inst(compiler, llilf(target, (sljit_u32)v));
- if (((sljit_uw)v << 32) == 0)
- return push_inst(compiler, llihf(target, (sljit_u32)((sljit_uw)v >> 32)));
-
- FAIL_IF(push_inst(compiler, llilf(target, (sljit_u32)v)));
- return push_inst(compiler, iihf(target, (sljit_u32)(v >> 32)));
- }
+ if (((sljit_uw)v << 32) == 0)
+ return push_inst(compiler, llihf(target, (sljit_u32)((sljit_uw)v >> 32)));
- /* TODO(mundaym): instruction sequences that don't use extended immediates */
- abort();
+ FAIL_IF(push_inst(compiler, llilf(target, (sljit_u32)v)));
+ return push_inst(compiler, iihf(target, (sljit_u32)(v >> 32)));
}
struct addr {
@@ -995,24 +986,47 @@ static sljit_s32 make_addr_bx(struct sljit_compiler *compiler,
(cond) ? EVAL(i1, r, addr) : EVAL(i2, r, addr)
/* May clobber tmp1. */
-static sljit_s32 load_word(struct sljit_compiler *compiler, sljit_gpr dst_r,
- sljit_s32 src, sljit_sw srcw,
- sljit_s32 is_32bit)
+static sljit_s32 load_store_op(struct sljit_compiler *compiler, sljit_gpr reg,
+ sljit_s32 mem, sljit_sw memw,
+ sljit_s32 is_32bit, const sljit_ins* forms)
{
struct addr addr;
- sljit_ins ins;
- SLJIT_ASSERT(src & SLJIT_MEM);
+ SLJIT_ASSERT(mem & SLJIT_MEM);
- if (is_32bit && ((src & OFFS_REG_MASK) || is_u12(srcw) || !is_s20(srcw))) {
- FAIL_IF(make_addr_bx(compiler, &addr, src, srcw, tmp1));
- return push_inst(compiler, 0x58000000 /* l */ | R20A(dst_r) | R16A(addr.index) | R12A(addr.base) | (sljit_ins)addr.offset);
+ if (is_32bit && ((mem & OFFS_REG_MASK) || is_u12(memw) || !is_s20(memw))) {
+ FAIL_IF(make_addr_bx(compiler, &addr, mem, memw, tmp1));
+ return push_inst(compiler, forms[0] | R20A(reg) | R16A(addr.index) | R12A(addr.base) | (sljit_ins)addr.offset);
}
- FAIL_IF(make_addr_bxy(compiler, &addr, src, srcw, tmp1));
+ FAIL_IF(make_addr_bxy(compiler, &addr, mem, memw, tmp1));
+ return push_inst(compiler, (is_32bit ? forms[1] : forms[2]) | R36A(reg) | R32A(addr.index) | R28A(addr.base) | disp_s20(addr.offset));
+}
- ins = is_32bit ? 0xe30000000058 /* ly */ : 0xe30000000004 /* lg */;
- return push_inst(compiler, ins | R36A(dst_r) | R32A(addr.index) | R28A(addr.base) | disp_s20(addr.offset));
+static const sljit_ins load_forms[3] = {
+ 0x58000000 /* l */,
+ 0xe30000000058 /* ly */,
+ 0xe30000000004 /* lg */
+};
+
+static const sljit_ins store_forms[3] = {
+ 0x50000000 /* st */,
+ 0xe30000000050 /* sty */,
+ 0xe30000000024 /* stg */
+};
+
+static const sljit_ins load_halfword_forms[3] = {
+ 0x48000000 /* lh */,
+ 0xe30000000078 /* lhy */,
+ 0xe30000000015 /* lgh */
+};
+
+/* May clobber tmp1. */
+static SLJIT_INLINE sljit_s32 load_word(struct sljit_compiler *compiler, sljit_gpr dst_r,
+ sljit_s32 src, sljit_sw srcw,
+ sljit_s32 is_32bit)
+{
+ return load_store_op(compiler, dst_r, src, srcw, is_32bit, load_forms);
}
/* May clobber tmp1. */
@@ -1032,24 +1046,11 @@ static sljit_s32 load_unsigned_word(struct sljit_compiler *compiler, sljit_gpr d
}
/* May clobber tmp1. */
-static sljit_s32 store_word(struct sljit_compiler *compiler, sljit_gpr src_r,
+static SLJIT_INLINE sljit_s32 store_word(struct sljit_compiler *compiler, sljit_gpr src_r,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 is_32bit)
{
- struct addr addr;
- sljit_ins ins;
-
- SLJIT_ASSERT(dst & SLJIT_MEM);
-
- if (is_32bit && ((dst & OFFS_REG_MASK) || is_u12(dstw) || !is_s20(dstw))) {
- FAIL_IF(make_addr_bx(compiler, &addr, dst, dstw, tmp1));
- return push_inst(compiler, 0x50000000 /* st */ | R20A(src_r) | R16A(addr.index) | R12A(addr.base) | (sljit_ins)addr.offset);
- }
-
- FAIL_IF(make_addr_bxy(compiler, &addr, dst, dstw, tmp1));
-
- ins = is_32bit ? 0xe30000000050 /* sty */ : 0xe30000000024 /* stg */;
- return push_inst(compiler, ins | R36A(src_r) | R32A(addr.index) | R28A(addr.base) | disp_s20(addr.offset));
+ return load_store_op(compiler, src_r, dst, dstw, is_32bit, store_forms);
}
#undef WHEN
@@ -1058,15 +1059,17 @@ static sljit_s32 emit_move(struct sljit_compiler *compiler,
sljit_gpr dst_r,
sljit_s32 src, sljit_sw srcw)
{
+ sljit_gpr src_r;
+
SLJIT_ASSERT(!IS_GPR_REG(src) || dst_r != gpr(src & REG_MASK));
- if (src & SLJIT_IMM)
+ if (src == SLJIT_IMM)
return push_load_imm_inst(compiler, dst_r, srcw);
if (src & SLJIT_MEM)
return load_word(compiler, dst_r, src, srcw, (compiler->mode & SLJIT_32) != 0);
- sljit_gpr src_r = gpr(src & REG_MASK);
+ src_r = gpr(src & REG_MASK);
return push_inst(compiler, (compiler->mode & SLJIT_32) ? lr(dst_r, src_r) : lgr(dst_r, src_r));
}
@@ -1259,10 +1262,10 @@ static sljit_s32 emit_siy(struct sljit_compiler *compiler, sljit_ins ins,
sljit_s32 dst, sljit_sw dstw,
sljit_sw srcw)
{
- SLJIT_ASSERT(dst & SLJIT_MEM);
-
sljit_gpr dst_r = tmp1;
+ SLJIT_ASSERT(dst & SLJIT_MEM);
+
if (dst & OFFS_REG_MASK) {
sljit_gpr index = tmp1;
@@ -1567,6 +1570,8 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
if (jump && jump->addr == j) {
sljit_sw target = (sljit_sw)((jump->flags & JUMP_LABEL) ? jump->u.label->addr : jump->u.target);
if ((jump->flags & SLJIT_REWRITABLE_JUMP) || (jump->flags & JUMP_ADDR)) {
+ sljit_ins op, arg;
+
jump->addr = (sljit_uw)pool_ptr;
/* load address into tmp1 */
@@ -1583,8 +1588,8 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
*(pool_ptr++) = (sljit_uw)target;
/* branch to tmp1 */
- sljit_ins op = (ins >> 32) & 0xf;
- sljit_ins arg = (ins >> 36) & 0xf;
+ op = (ins >> 32) & 0xf;
+ arg = (ins >> 36) & 0xf;
switch (op) {
case 4: /* brcl -> bcr */
ins = bcr(arg, tmp1);
@@ -1638,6 +1643,8 @@ SLJIT_API_FUNC_ATTRIBUTE void* sljit_generate_code(struct sljit_compiler *compil
compiler->error = SLJIT_ERR_COMPILED;
compiler->executable_offset = executable_offset;
compiler->executable_size = ins_size;
+ if (pool_size)
+ compiler->executable_size += (pad_size + pool_size);
code = SLJIT_ADD_EXEC_OFFSET(code, executable_offset);
code_ptr = SLJIT_ADD_EXEC_OFFSET(code_ptr, executable_offset);
SLJIT_CACHE_FLUSH(code, code_ptr);
@@ -1650,12 +1657,25 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
/* TODO(mundaym): implement all */
switch (feature_type) {
case SLJIT_HAS_FPU:
+#ifdef SLJIT_IS_FPU_AVAILABLE
+ return (SLJIT_IS_FPU_AVAILABLE) != 0;
+#else
+ return 1;
+#endif /* SLJIT_IS_FPU_AVAILABLE */
+
case SLJIT_HAS_CLZ:
+ case SLJIT_HAS_REV:
case SLJIT_HAS_ROT:
case SLJIT_HAS_PREFETCH:
+ case SLJIT_HAS_COPY_F32:
+ case SLJIT_HAS_COPY_F64:
+ case SLJIT_HAS_SIMD:
+ case SLJIT_HAS_ATOMIC:
return 1;
+
case SLJIT_HAS_CTZ:
return 2;
+
case SLJIT_HAS_CMOV:
return have_lscond1() ? 1 : 0;
}
@@ -1664,7 +1684,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type)
{
- return (type >= SLJIT_UNORDERED && type <= SLJIT_ORDERED_LESS_EQUAL);
+ SLJIT_UNUSED_ARG(type);
+ return 0;
}
/* --------------------------------------------------------------------- */
@@ -1741,7 +1762,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
local_size = (local_size + SLJIT_S390X_DEFAULT_STACK_FRAME_SIZE + 0xf) & ~0xf;
compiler->local_size = local_size;
- FAIL_IF(push_inst(compiler, 0xe30000000071 /* lay */ | R36A(r15) | R28A(r15) | disp_s20(-local_size)));
+ if (is_s20(-local_size))
+ FAIL_IF(push_inst(compiler, 0xe30000000071 /* lay */ | R36A(r15) | R28A(r15) | disp_s20(-local_size)));
+ else
+ FAIL_IF(push_inst(compiler, 0xc20400000000 /* slgfi */ | R36A(r15) | (sljit_ins)local_size));
if (options & SLJIT_ENTER_REG_ARG)
return SLJIT_SUCCESS;
@@ -1786,8 +1810,10 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit
if (is_u12(local_size))
FAIL_IF(push_inst(compiler, 0x41000000 /* ly */ | R20A(r15) | R12A(r15) | (sljit_ins)local_size));
- else
+ else if (is_s20(local_size))
FAIL_IF(push_inst(compiler, 0xe30000000071 /* lay */ | R36A(r15) | R28A(r15) | disp_s20(local_size)));
+ else
+ FAIL_IF(push_inst(compiler, 0xc20a00000000 /* algfi */ | R36A(r15) | (sljit_ins)local_size));
offset = 2 * SSIZE_OF(sw);
if (saveds + scratches >= SLJIT_NUMBER_OF_REGISTERS) {
@@ -2011,12 +2037,85 @@ static sljit_s32 sljit_emit_clz_ctz(struct sljit_compiler *compiler, sljit_s32 o
return push_inst(compiler, ((op & SLJIT_32) ? 0x1800 /* lr */ : 0xb9040000 /* lgr */) | R4A(dst_r) | R0A(tmp0));
}
+static sljit_s32 sljit_emit_rev(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ struct addr addr;
+ sljit_gpr reg;
+ sljit_ins ins;
+ sljit_s32 opcode = GET_OPCODE(op);
+ sljit_s32 is_16bit = (opcode == SLJIT_REV_U16 || opcode == SLJIT_REV_S16);
+
+ if (dst & SLJIT_MEM) {
+ if (src & SLJIT_MEM) {
+ FAIL_IF(load_store_op(compiler, tmp0, src, srcw, op & SLJIT_32, is_16bit ? load_halfword_forms : load_forms));
+ reg = tmp0;
+ } else
+ reg = gpr(src);
+
+ FAIL_IF(make_addr_bxy(compiler, &addr, dst, dstw, tmp1));
+
+ if (is_16bit)
+ ins = 0xe3000000003f /* strvh */;
+ else
+ ins = (op & SLJIT_32) ? 0xe3000000003e /* strv */ : 0xe3000000002f /* strvg */;
+
+ return push_inst(compiler, ins | R36A(reg) | R32A(addr.index) | R28A(addr.base) | disp_s20(addr.offset));
+ }
+
+ reg = gpr(dst);
+
+ if (src & SLJIT_MEM) {
+ FAIL_IF(make_addr_bxy(compiler, &addr, src, srcw, tmp1));
+
+ if (is_16bit)
+ ins = 0xe3000000001f /* lrvh */;
+ else
+ ins = (op & SLJIT_32) ? 0xe3000000001e /* lrv */ : 0xe3000000000f /* lrvg */;
+
+ FAIL_IF(push_inst(compiler, ins | R36A(reg) | R32A(addr.index) | R28A(addr.base) | disp_s20(addr.offset)));
+
+ if (opcode == SLJIT_REV)
+ return SLJIT_SUCCESS;
+
+ if (is_16bit) {
+ if (op & SLJIT_32)
+ ins = (opcode == SLJIT_REV_U16) ? 0xb9950000 /* llhr */ : 0xb9270000 /* lhr */;
+ else
+ ins = (opcode == SLJIT_REV_U16) ? 0xb9850000 /* llghr */ : 0xb9070000 /* lghr */;
+ } else
+ ins = (opcode == SLJIT_REV_U32) ? 0xb9160000 /* llgfr */ : 0xb9140000 /* lgfr */;
+
+ return push_inst(compiler, ins | R4A(reg) | R0A(reg));
+ }
+
+ ins = (op & SLJIT_32) ? 0xb91f0000 /* lrvr */ : 0xb90f0000 /* lrvgr */;
+ FAIL_IF(push_inst(compiler, ins | R4A(reg) | R0A(gpr(src))));
+
+ if (opcode == SLJIT_REV)
+ return SLJIT_SUCCESS;
+
+ if (!is_16bit) {
+ ins = (opcode == SLJIT_REV_U32) ? 0xb9160000 /* llgfr */ : 0xb9140000 /* lgfr */;
+ return push_inst(compiler, ins | R4A(reg) | R0A(reg));
+ }
+
+ if (op & SLJIT_32) {
+ ins = (opcode == SLJIT_REV_U16) ? 0x88000000 /* srl */ : 0x8a000000 /* sra */;
+ return push_inst(compiler, ins | R20A(reg) | 16);
+ }
+
+ ins = (opcode == SLJIT_REV_U16) ? 0xeb000000000c /* srlg */ : 0xeb000000000a /* srag */;
+ return push_inst(compiler, ins | R36A(reg) | R32A(reg) | (48 << 16));
+}
+
/* LEVAL will be defined later with different parameters as needed */
#define WHEN2(cond, i1, i2) (cond) ? LEVAL(i1) : LEVAL(i2)
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 dst, sljit_sw dstw,
- sljit_s32 src, sljit_sw srcw)
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
{
sljit_ins ins;
struct addr mem;
@@ -2087,7 +2186,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
return SLJIT_SUCCESS;
}
/* LOAD IMMEDIATE */
- if (FAST_IS_REG(dst) && (src & SLJIT_IMM)) {
+ if (FAST_IS_REG(dst) && src == SLJIT_IMM) {
switch (opcode) {
case SLJIT_MOV_U8:
srcw = (sljit_sw)((sljit_u8)(srcw));
@@ -2166,14 +2265,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
return SLJIT_SUCCESS;
}
/* STORE and STORE IMMEDIATE */
- if ((dst & SLJIT_MEM)
- && (FAST_IS_REG(src) || (src & SLJIT_IMM))) {
+ if ((dst & SLJIT_MEM) && (FAST_IS_REG(src) || src == SLJIT_IMM)) {
+ struct addr mem;
sljit_gpr reg = FAST_IS_REG(src) ? gpr(src) : tmp0;
- if (src & SLJIT_IMM) {
+
+ if (src == SLJIT_IMM) {
/* TODO(mundaym): MOVE IMMEDIATE? */
FAIL_IF(push_load_imm_inst(compiler, reg, srcw));
}
- struct addr mem;
FAIL_IF(make_addr_bxy(compiler, &mem, dst, dstw, tmp1));
switch (opcode) {
case SLJIT_MOV_U8:
@@ -2240,39 +2339,15 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
SLJIT_UNREACHABLE();
}
- SLJIT_ASSERT((src & SLJIT_IMM) == 0); /* no immediates */
+ SLJIT_ASSERT(src != SLJIT_IMM);
- dst_r = FAST_IS_REG(dst) ? gpr(REG_MASK & dst) : tmp0;
- src_r = FAST_IS_REG(src) ? gpr(REG_MASK & src) : tmp0;
+ dst_r = FAST_IS_REG(dst) ? gpr(dst) : tmp0;
+ src_r = FAST_IS_REG(src) ? gpr(src) : tmp0;
compiler->status_flags_state = op & (VARIABLE_FLAG_MASK | SLJIT_SET_Z);
/* TODO(mundaym): optimize loads and stores */
switch (opcode) {
- case SLJIT_NOT:
- if (src & SLJIT_MEM)
- FAIL_IF(load_word(compiler, src_r, src, srcw, op & SLJIT_32));
-
- /* emulate ~x with x^-1 */
- if (!(op & SLJIT_32)) {
- FAIL_IF(push_load_imm_inst(compiler, tmp1, -1));
- if (src_r != dst_r)
- FAIL_IF(push_inst(compiler, lgr(dst_r, src_r)));
-
- FAIL_IF(push_inst(compiler, xgr(dst_r, tmp1)));
- break;
- }
-
- if (have_eimm())
- FAIL_IF(push_inst(compiler, xilf(dst_r, 0xffffffff)));
- else {
- FAIL_IF(push_load_imm_inst(compiler, tmp1, -1));
- if (src_r != dst_r)
- FAIL_IF(push_inst(compiler, lr(dst_r, src_r)));
-
- FAIL_IF(push_inst(compiler, xr(dst_r, tmp1)));
- }
- break;
case SLJIT_CLZ:
case SLJIT_CTZ:
if (src & SLJIT_MEM)
@@ -2280,13 +2355,18 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
FAIL_IF(sljit_emit_clz_ctz(compiler, op, dst_r, src_r));
break;
+ case SLJIT_REV_U32:
+ case SLJIT_REV_S32:
+ op |= SLJIT_32;
+ /* fallthrough */
+ case SLJIT_REV:
+ case SLJIT_REV_U16:
+ case SLJIT_REV_S16:
+ return sljit_emit_rev(compiler, op, dst, dstw, src, srcw);
default:
SLJIT_UNREACHABLE();
}
- if ((op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == (SLJIT_SET_Z | SLJIT_SET_OVERFLOW))
- FAIL_IF(update_zero_overflow(compiler, op, dst_r));
-
if (dst & SLJIT_MEM)
return store_word(compiler, dst_r, dst, dstw, op & SLJIT_32);
@@ -2337,7 +2417,7 @@ static sljit_s32 sljit_emit_add(struct sljit_compiler *compiler, sljit_s32 op,
const struct ins_forms *forms;
sljit_ins ins;
- if (src2 & SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
if (!sets_zero_overflow && is_s8(src2w) && (src1 & SLJIT_MEM) && (dst == src1 && dstw == src1w)) {
if (sets_overflow)
ins = (op & SLJIT_32) ? 0xeb000000006a /* asi */ : 0xeb000000007a /* agsi */;
@@ -2422,9 +2502,8 @@ static sljit_s32 sljit_emit_sub(struct sljit_compiler *compiler, sljit_s32 op,
compiler->status_flags_state |= SLJIT_CURRENT_FLAGS_COMPARE;
- if (src2 & SLJIT_IMM) {
- if (compare_signed || ((op & VARIABLE_FLAG_MASK) == 0 && is_s32(src2w)))
- {
+ if (src2 == SLJIT_IMM) {
+ if (compare_signed || ((op & VARIABLE_FLAG_MASK) == 0 && is_s32(src2w))) {
if ((op & SLJIT_32) || is_s32(src2w)) {
ins = (op & SLJIT_32) ? 0xc20d00000000 /* cfi */ : 0xc20c00000000 /* cgfi */;
return emit_ri(compiler, ins, src1, src1, src1w, src2w, RIL_A);
@@ -2465,7 +2544,7 @@ static sljit_s32 sljit_emit_sub(struct sljit_compiler *compiler, sljit_s32 op,
goto done;
}
- if (src2 & SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
sljit_sw neg_src2w = -src2w;
if (sets_signed || neg_src2w != 0 || (op & (SLJIT_SET_Z | VARIABLE_FLAG_MASK)) == 0) {
@@ -2573,7 +2652,7 @@ static sljit_s32 sljit_emit_multiply(struct sljit_compiler *compiler, sljit_s32
return emit_commutative(compiler, &multiply_overflow_forms, dst, src1, src1w, src2, src2w);
}
- if (src2 & SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
if (is_s16(src2w)) {
ins = (op & SLJIT_32) ? 0xa70c0000 /* mhi */ : 0xa70d0000 /* mghi */;
return emit_ri(compiler, ins, dst, src1, src1w, src2w, RI_A);
@@ -2680,7 +2759,7 @@ static sljit_s32 sljit_emit_bitwise(struct sljit_compiler *compiler, sljit_s32 o
sljit_s32 type = GET_OPCODE(op);
const struct ins_forms *forms;
- if ((src2 & SLJIT_IMM) && (!(op & SLJIT_SET_Z) || (type == SLJIT_AND && dst == (sljit_s32)tmp0))) {
+ if (src2 == SLJIT_IMM && (!(op & SLJIT_SET_Z) || (type == SLJIT_AND && dst == (sljit_s32)tmp0))) {
sljit_s32 count16 = 0;
sljit_uw imm = (sljit_uw)src2w;
@@ -2705,12 +2784,12 @@ static sljit_s32 sljit_emit_bitwise(struct sljit_compiler *compiler, sljit_s32 o
FAIL_IF(emit_move(compiler, tmp0, src1, src1w));
if ((imm & 0x000000000000ffffull) != 0 || imm == 0)
- return push_inst(compiler, 0xa7010000 | R20A(src_r) | imm);
+ return push_inst(compiler, 0xa7010000 /* tmll */ | R20A(src_r) | imm);
if ((imm & 0x00000000ffff0000ull) != 0)
- return push_inst(compiler, 0xa7000000 | R20A(src_r) | (imm >> 16));
+ return push_inst(compiler, 0xa7000000 /* tmlh */ | R20A(src_r) | (imm >> 16));
if ((imm & 0x0000ffff00000000ull) != 0)
- return push_inst(compiler, 0xa7030000 | R20A(src_r) | (imm >> 32));
- return push_inst(compiler, 0xa7020000 | R20A(src_r) | (imm >> 48));
+ return push_inst(compiler, 0xa7030000 /* tmhl */ | R20A(src_r) | (imm >> 32));
+ return push_inst(compiler, 0xa7020000 /* tmhh */ | R20A(src_r) | (imm >> 48));
}
if (!(op & SLJIT_SET_Z))
@@ -2744,7 +2823,7 @@ static sljit_s32 sljit_emit_shift(struct sljit_compiler *compiler, sljit_s32 op,
else
FAIL_IF(emit_move(compiler, tmp0, src1, src1w));
- if (!(src2 & SLJIT_IMM)) {
+ if (src2 != SLJIT_IMM) {
if (FAST_IS_REG(src2))
base_r = gpr(src2);
else {
@@ -2804,7 +2883,7 @@ static sljit_s32 sljit_emit_rotate(struct sljit_compiler *compiler, sljit_s32 op
else
FAIL_IF(emit_move(compiler, tmp0, src1, src1w));
- if (!(src2 & SLJIT_IMM)) {
+ if (src2 != SLJIT_IMM) {
if (FAST_IS_REG(src2))
base_r = gpr(src2);
else {
@@ -2814,7 +2893,7 @@ static sljit_s32 sljit_emit_rotate(struct sljit_compiler *compiler, sljit_s32 op
}
if (GET_OPCODE(op) == SLJIT_ROTR) {
- if (!(src2 & SLJIT_IMM)) {
+ if (src2 != SLJIT_IMM) {
ins = (op & SLJIT_32) ? 0x1300 /* lcr */ : 0xb9030000 /* lcgr */;
FAIL_IF(push_inst(compiler, ins | R4A(tmp1) | R0A(base_r)));
base_r = tmp1;
@@ -2822,7 +2901,7 @@ static sljit_s32 sljit_emit_rotate(struct sljit_compiler *compiler, sljit_s32 op
src2w = -src2w;
}
- if (src2 & SLJIT_IMM)
+ if (src2 == SLJIT_IMM)
imm = (sljit_ins)(src2w & ((op & SLJIT_32) ? 0x1f : 0x3f));
ins = (op & SLJIT_32) ? 0xeb000000001d /* rll */ : 0xeb000000001c /* rllg */;
@@ -2863,7 +2942,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
compiler->mode = op & SLJIT_32;
compiler->status_flags_state = op & (VARIABLE_FLAG_MASK | SLJIT_SET_Z);
- if (is_commutative(op) && (src1 & SLJIT_IMM) && !(src2 & SLJIT_IMM)) {
+ if (is_commutative(op) && src1 == SLJIT_IMM && src2 != SLJIT_IMM) {
src1 ^= src2;
src2 ^= src1;
src1 ^= src2;
@@ -2931,122 +3010,125 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 src_dst,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w)
+ sljit_s32 dst_reg,
+ sljit_s32 src1_reg,
+ sljit_s32 src2_reg,
+ sljit_s32 src3, sljit_sw src3w)
{
sljit_s32 is_right;
sljit_sw bit_length = (op & SLJIT_32) ? 32 : 64;
- sljit_gpr src_dst_r = gpr(src_dst);
- sljit_gpr src1_r = tmp0;
- sljit_gpr src2_r = tmp1;
+ sljit_gpr dst_r = gpr(dst_reg);
+ sljit_gpr src1_r = gpr(src1_reg);
+ sljit_gpr src2_r = gpr(src2_reg);
+ sljit_gpr src3_r = tmp1;
sljit_ins ins;
CHECK_ERROR();
- CHECK(check_sljit_emit_shift_into(compiler, op, src_dst, src1, src1w, src2, src2w));
+ CHECK(check_sljit_emit_shift_into(compiler, op, dst_reg, src1_reg, src2_reg, src3, src3w));
is_right = (GET_OPCODE(op) == SLJIT_LSHR || GET_OPCODE(op) == SLJIT_MLSHR);
- if (src_dst == src1) {
+ if (src1_reg == src2_reg) {
SLJIT_SKIP_CHECKS(compiler);
- return sljit_emit_op2(compiler, (is_right ? SLJIT_ROTR : SLJIT_ROTL) | (op & SLJIT_32), src_dst, 0, src_dst, 0, src2, src2w);
+ return sljit_emit_op2(compiler, (is_right ? SLJIT_ROTR : SLJIT_ROTL) | (op & SLJIT_32), dst_reg, 0, src1_reg, 0, src3, src3w);
}
- ADJUST_LOCAL_OFFSET(src1, src1w);
- ADJUST_LOCAL_OFFSET(src2, src2w);
+ ADJUST_LOCAL_OFFSET(src3, src3w);
- if (src1 & SLJIT_MEM)
- FAIL_IF(load_word(compiler, tmp0, src1, src1w, op & SLJIT_32));
- else if (src1 & SLJIT_IMM)
- FAIL_IF(push_load_imm_inst(compiler, tmp0, src1w));
- else
- src1_r = gpr(src1);
-
- if (src2 & SLJIT_IMM) {
- src2w &= bit_length - 1;
+ if (src3 == SLJIT_IMM) {
+ src3w &= bit_length - 1;
- if (src2w == 0)
+ if (src3w == 0)
return SLJIT_SUCCESS;
- } else if (!(src2 & SLJIT_MEM))
- src2_r = gpr(src2);
- else
- FAIL_IF(load_word(compiler, tmp1, src2, src2w, op & SLJIT_32));
- if (src2 & SLJIT_IMM) {
if (op & SLJIT_32) {
- ins = is_right ? 0x88000000 /* srl */ : 0x89000000 /* sll */;
- FAIL_IF(push_inst(compiler, ins | R20A(src_dst_r) | (sljit_ins)src2w));
+ if (dst_r == src1_r) {
+ ins = is_right ? 0x88000000 /* srl */ : 0x89000000 /* sll */;
+ FAIL_IF(push_inst(compiler, ins | R20A(dst_r) | (sljit_ins)src3w));
+ } else {
+ ins = is_right ? 0xeb00000000de /* srlk */ : 0xeb00000000df /* sllk */;
+ FAIL_IF(push_inst(compiler, ins | R36A(dst_r) | R32A(src1_r) | ((sljit_ins)src3w << 16)));
+ }
} else {
ins = is_right ? 0xeb000000000c /* srlg */ : 0xeb000000000d /* sllg */;
- FAIL_IF(push_inst(compiler, ins | R36A(src_dst_r) | R32A(src_dst_r) | ((sljit_ins)src2w << 16)));
+ FAIL_IF(push_inst(compiler, ins | R36A(dst_r) | R32A(src1_r) | ((sljit_ins)src3w << 16)));
}
ins = 0xec0000000055 /* risbg */;
if (is_right) {
- src2w = bit_length - src2w;
- ins |= ((sljit_ins)(64 - bit_length) << 24) | ((sljit_ins)(63 - src2w) << 16) | ((sljit_ins)src2w << 8);
+ src3w = bit_length - src3w;
+ ins |= ((sljit_ins)(64 - bit_length) << 24) | ((sljit_ins)(63 - src3w) << 16) | ((sljit_ins)src3w << 8);
} else
- ins |= ((sljit_ins)(64 - src2w) << 24) | ((sljit_ins)63 << 16) | ((sljit_ins)src2w << 8);
+ ins |= ((sljit_ins)(64 - src3w) << 24) | ((sljit_ins)63 << 16) | ((sljit_ins)(src3w + 64 - bit_length) << 8);
- return push_inst(compiler, ins | R36A(src_dst_r) | R32A(src1_r));
+ return push_inst(compiler, ins | R36A(dst_r) | R32A(src2_r));
}
+ if (!(src3 & SLJIT_MEM)) {
+ src3_r = gpr(src3);
+
+ if (dst_r == src3_r) {
+ FAIL_IF(push_inst(compiler, 0x1800 /* lr */ | R4A(tmp1) | R0A(src3_r)));
+ src3_r = tmp1;
+ }
+ } else
+ FAIL_IF(load_word(compiler, tmp1, src3, src3w, op & SLJIT_32));
+
if (op & SLJIT_32) {
if (GET_OPCODE(op) == SLJIT_MSHL || GET_OPCODE(op) == SLJIT_MLSHR) {
- if (src2_r != tmp1) {
- FAIL_IF(push_inst(compiler, 0xec0000000055 /* risbg */ | R36A(tmp1) | R32A(src2_r) | (59 << 24) | (1 << 23) | (63 << 16)));
- src2_r = tmp1;
+ if (src3_r != tmp1) {
+ FAIL_IF(push_inst(compiler, 0xec0000000055 /* risbg */ | R36A(tmp1) | R32A(src3_r) | (59 << 24) | (1 << 23) | (63 << 16)));
+ src3_r = tmp1;
} else
FAIL_IF(push_inst(compiler, 0xa5070000 /* nill */ | R20A(tmp1) | 0x1f));
}
- ins = is_right ? 0x88000000 /* srl */ : 0x89000000 /* sll */;
- FAIL_IF(push_inst(compiler, ins | R20A(src_dst_r) | R12A(src2_r)));
+ if (dst_r == src1_r) {
+ ins = is_right ? 0x88000000 /* srl */ : 0x89000000 /* sll */;
+ FAIL_IF(push_inst(compiler, ins | R20A(dst_r) | R12A(src3_r)));
+ } else {
+ ins = is_right ? 0xeb00000000de /* srlk */ : 0xeb00000000df /* sllk */;
+ FAIL_IF(push_inst(compiler, ins | R36A(dst_r) | R32A(src1_r) | R28A(src3_r)));
+ }
- if (src2_r != tmp1) {
+ if (src3_r != tmp1) {
FAIL_IF(push_inst(compiler, 0xa50f0000 /* llill */ | R20A(tmp1) | 0x1f));
- FAIL_IF(push_inst(compiler, 0x1700 /* xr */ | R4A(tmp1) | R0A(src2_r)));
+ FAIL_IF(push_inst(compiler, 0x1700 /* xr */ | R4A(tmp1) | R0A(src3_r)));
} else
FAIL_IF(push_inst(compiler, 0xc00700000000 /* xilf */ | R36A(tmp1) | 0x1f));
- if (src1_r == tmp0) {
- ins = is_right ? 0x89000000 /* sll */ : 0x88000000 /* srl */;
- FAIL_IF(push_inst(compiler, ins | R20A(tmp0) | R12A(tmp1) | 0x1));
- } else {
- ins = is_right ? 0xeb00000000df /* sllk */ : 0xeb00000000de /* srlk */;
- FAIL_IF(push_inst(compiler, ins | R36A(tmp0) | R32A(src1_r) | R28A(tmp1) | (0x1 << 16)));
- }
+ ins = is_right ? 0xeb00000000df /* sllk */ : 0xeb00000000de /* srlk */;
+ FAIL_IF(push_inst(compiler, ins | R36A(tmp0) | R32A(src2_r) | R28A(tmp1) | (0x1 << 16)));
- return push_inst(compiler, 0x1600 /* or */ | R4A(src_dst_r) | R0A(tmp0));
+ return push_inst(compiler, 0x1600 /* or */ | R4A(dst_r) | R0A(tmp0));
}
ins = is_right ? 0xeb000000000c /* srlg */ : 0xeb000000000d /* sllg */;
- FAIL_IF(push_inst(compiler, ins | R36A(src_dst_r) | R32A(src_dst_r) | R28A(src2_r)));
+ FAIL_IF(push_inst(compiler, ins | R36A(dst_r) | R32A(src1_r) | R28A(src3_r)));
ins = is_right ? 0xeb000000000d /* sllg */ : 0xeb000000000c /* srlg */;
if (!(op & SLJIT_SHIFT_INTO_NON_ZERO)) {
- if (src2_r != tmp1)
+ if (src3_r != tmp1)
FAIL_IF(push_inst(compiler, 0xa50f0000 /* llill */ | R20A(tmp1) | 0x3f));
- FAIL_IF(push_inst(compiler, ins | R36A(tmp0) | R32A(src1_r) | (0x1 << 16)));
- src1_r = tmp0;
+ FAIL_IF(push_inst(compiler, ins | R36A(tmp0) | R32A(src2_r) | (0x1 << 16)));
+ src2_r = tmp0;
- if (src2_r != tmp1)
- FAIL_IF(push_inst(compiler, 0xb9820000 /* xgr */ | R4A(tmp1) | R0A(src2_r)));
+ if (src3_r != tmp1)
+ FAIL_IF(push_inst(compiler, 0xb9820000 /* xgr */ | R4A(tmp1) | R0A(src3_r)));
else
FAIL_IF(push_inst(compiler, 0xc00700000000 /* xilf */ | R36A(tmp1) | 0x3f));
} else
- FAIL_IF(push_inst(compiler, 0xb9030000 /* lcgr */ | R4A(tmp1) | R0A(src2_r)));
+ FAIL_IF(push_inst(compiler, 0xb9030000 /* lcgr */ | R4A(tmp1) | R0A(src3_r)));
- FAIL_IF(push_inst(compiler, ins | R36A(tmp0) | R32A(src1_r) | R28A(tmp1)));
- return push_inst(compiler, 0xb9810000 /* ogr */ | R4A(src_dst_r) | R0A(tmp0));
+ FAIL_IF(push_inst(compiler, ins | R36A(tmp0) | R32A(src2_r) | R28A(tmp1)));
+ return push_inst(compiler, 0xb9810000 /* ogr */ | R4A(dst_r) | R0A(tmp0));
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(
- struct sljit_compiler *compiler,
- sljit_s32 op, sljit_s32 src, sljit_sw srcw)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src, sljit_sw srcw)
{
sljit_gpr src_r;
struct addr addr;
@@ -3077,16 +3159,46 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw)
{
- CHECK_REG_INDEX(check_sljit_get_register_index(reg));
- return (sljit_s32)gpr(reg);
+ sljit_gpr dst_r = link_r;
+ sljit_s32 size;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op_dst(compiler, op, dst, dstw));
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+
+ switch (op) {
+ case SLJIT_FAST_ENTER:
+ if (FAST_IS_REG(dst))
+ return push_inst(compiler, lgr(gpr(dst), link_r));
+ break;
+ case SLJIT_GET_RETURN_ADDRESS:
+ dst_r = FAST_IS_REG(dst) ? gpr(dst) : tmp0;
+
+ size = GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds - SLJIT_KEPT_SAVEDS_COUNT(compiler->options), 2);
+ FAIL_IF(load_word(compiler, dst_r, SLJIT_MEM1(SLJIT_SP), compiler->local_size + size, 0));
+ break;
+ }
+
+ if (dst & SLJIT_MEM)
+ return store_word(compiler, dst_r, dst, dstw, 0);
+
+ return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 type, sljit_s32 reg)
{
- CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
- return (sljit_s32)fgpr(reg);
+ CHECK_REG_INDEX(check_sljit_get_register_index(type, reg));
+
+ if (type == SLJIT_GP_REGISTER)
+ return (sljit_s32)gpr(reg);
+
+ if (type != SLJIT_FLOAT_REGISTER)
+ return -1;
+
+ return (sljit_s32)freg_map[reg];
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
@@ -3177,33 +3289,61 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_comp
return SLJIT_SUCCESS;
}
-static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+static sljit_s32 sljit_emit_fop1_conv_f64_from_w(struct sljit_compiler *compiler, sljit_ins ins,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 src, sljit_sw srcw)
{
sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG1;
- sljit_ins ins;
- if (src & SLJIT_IMM) {
+ if (src == SLJIT_IMM) {
FAIL_IF(push_load_imm_inst(compiler, tmp0, srcw));
src = (sljit_s32)tmp0;
}
else if (src & SLJIT_MEM) {
- FAIL_IF(load_word(compiler, tmp0, src, srcw, GET_OPCODE(op) >= SLJIT_CONV_F64_FROM_S32));
+ FAIL_IF(load_word(compiler, tmp0, src, srcw, ins & 0x100000));
src = (sljit_s32)tmp0;
}
+ FAIL_IF(push_inst(compiler, ins | F4(dst_r) | R0(src)));
+
+ if (dst & SLJIT_MEM)
+ return float_mem(compiler, FLOAT_STORE | ((ins & 0x10000) ? 0 : SLJIT_32), TMP_FREG1, dst, dstw);
+
+ return SLJIT_SUCCESS;
+}
+
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_ins ins;
+
+ if (src == SLJIT_IMM && GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
+ srcw = (sljit_s32)srcw;
+
if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_SW)
ins = (op & SLJIT_32) ? 0xb3a40000 /* cegbr */ : 0xb3a50000 /* cdgbr */;
else
ins = (op & SLJIT_32) ? 0xb3940000 /* cefbr */ : 0xb3950000 /* cdfbr */;
- FAIL_IF(push_inst(compiler, ins | F4(dst_r) | R0(src)));
+ return sljit_emit_fop1_conv_f64_from_w(compiler, ins, dst, dstw, src, srcw);
+}
- if (dst & SLJIT_MEM)
- return float_mem(compiler, FLOAT_STORE | (op & SLJIT_32), TMP_FREG1, dst, dstw);
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_uw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_ins ins;
- return SLJIT_SUCCESS;
+ if (src == SLJIT_IMM && GET_OPCODE(op) == SLJIT_CONV_F64_FROM_U32)
+ srcw = (sljit_u32)srcw;
+
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_UW)
+ ins = (op & SLJIT_32) ? 0xb3a00000 /* celgbr */ : 0xb3a10000 /* cdlgbr */;
+ else
+ ins = (op & SLJIT_32) ? 0xb3900000 /* celfbr */ : 0xb3910000 /* cdlfbr */;
+
+ return sljit_emit_fop1_conv_f64_from_w(compiler, ins, dst, dstw, src, srcw);
}
static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compiler, sljit_s32 op,
@@ -3355,21 +3495,91 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
return SLJIT_SUCCESS;
}
-/* --------------------------------------------------------------------- */
-/* Other instructions */
-/* --------------------------------------------------------------------- */
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2r(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_freg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ sljit_s32 reg;
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fop2r(compiler, op, dst_freg, src1, src1w, src2, src2w));
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+ ADJUST_LOCAL_OFFSET(src2, src2w);
+
+ if (src2 & SLJIT_MEM) {
+ FAIL_IF(float_mem(compiler, FLOAT_LOAD | (op & SLJIT_32), TMP_FREG1, src2, src2w));
+ src2 = TMP_FREG1;
+ }
+
+ if (src1 & SLJIT_MEM) {
+ reg = (dst_freg == src2) ? TMP_FREG1 : dst_freg;
+ FAIL_IF(float_mem(compiler, FLOAT_LOAD | (op & SLJIT_32), reg, src1, src1w));
+ src1 = reg;
+ }
+
+ return push_inst(compiler, 0xb3720000 /* cpsdr */ | F12(src2) | F4(dst_freg) | F0(src1));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset32(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f32 value)
{
+ union {
+ sljit_s32 imm;
+ sljit_f32 value;
+ } u;
+
CHECK_ERROR();
- CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
- ADJUST_LOCAL_OFFSET(dst, dstw);
+ CHECK(check_sljit_emit_fset32(compiler, freg, value));
+
+ u.value = value;
+
+ FAIL_IF(push_load_imm_inst(compiler, tmp1, (sljit_sw)(((sljit_uw)u.imm << 32))));
+ return push_inst(compiler, 0xb3c10000 /* ldgr */ | F4(freg) | R0A(tmp1));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f64 value)
+{
+ union {
+ sljit_sw imm;
+ sljit_f64 value;
+ } u;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fset64(compiler, freg, value));
- if (FAST_IS_REG(dst))
- return push_inst(compiler, lgr(gpr(dst), link_r));
+ u.value = value;
- /* memory */
- return store_word(compiler, link_r, dst, dstw, 0);
+ FAIL_IF(push_load_imm_inst(compiler, tmp1, (sljit_sw)u.imm));
+ return push_inst(compiler, 0xb3c10000 /* ldgr */ | F4(freg) | R0A(tmp1));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 freg, sljit_s32 reg)
+{
+ sljit_gpr gen_r;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+ gen_r = gpr(reg);
+
+ if (GET_OPCODE(op) == SLJIT_COPY_TO_F64) {
+ if (op & SLJIT_32) {
+ FAIL_IF(push_inst(compiler, 0xeb000000000d /* sllg */ | R36A(tmp0) | R32A(gen_r) | (32 << 16)));
+ gen_r = tmp0;
+ }
+
+ return push_inst(compiler, 0xb3c10000 /* ldgr */ | F4(freg) | R0A(gen_r));
+ }
+
+ FAIL_IF(push_inst(compiler, 0xb3cd0000 /* lgdr */ | R4A(gen_r) | F0(freg)));
+
+ if (!(op & SLJIT_32))
+ return SLJIT_SUCCESS;
+
+ return push_inst(compiler, 0xeb000000000c /* srlg */ | R36A(gen_r) | R32A(gen_r) | (32 << 16));
}
/* --------------------------------------------------------------------- */
@@ -3394,14 +3604,14 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compiler *compiler, sljit_s32 type)
{
+ struct sljit_jump *jump;
sljit_u8 mask = ((type & 0xff) < SLJIT_JUMP) ? get_cc(compiler, type & 0xff) : 0xf;
CHECK_ERROR_PTR();
CHECK_PTR(check_sljit_emit_jump(compiler, type));
/* record jump */
- struct sljit_jump *jump = (struct sljit_jump *)
- ensure_abuf(compiler, sizeof(struct sljit_jump));
+ jump = (struct sljit_jump *)ensure_abuf(compiler, sizeof(struct sljit_jump));
PTR_FAIL_IF(!jump);
set_jump(jump, compiler, type & SLJIT_REWRITABLE_JUMP);
jump->addr = compiler->size;
@@ -3439,7 +3649,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
CHECK_ERROR();
CHECK(check_sljit_emit_ijump(compiler, type, src, srcw));
- if (src & SLJIT_IMM) {
+ if (src == SLJIT_IMM) {
SLJIT_ASSERT(!(srcw & 1)); /* target address must be even */
FAIL_IF(push_load_imm_inst(compiler, src_r, srcw));
}
@@ -3459,6 +3669,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compi
sljit_s32 arg_types,
sljit_s32 src, sljit_sw srcw)
{
+ SLJIT_UNUSED_ARG(arg_types);
+
CHECK_ERROR();
CHECK(check_sljit_emit_icall(compiler, type, arg_types, src, srcw));
@@ -3490,13 +3702,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
sljit_s32 dst, sljit_sw dstw,
sljit_s32 type)
{
+ sljit_gpr dst_r = FAST_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0;
+ sljit_gpr loc_r = tmp1;
sljit_u8 mask = get_cc(compiler, type);
CHECK_ERROR();
CHECK(check_sljit_emit_op_flags(compiler, op, dst, dstw, type));
- sljit_gpr dst_r = FAST_IS_REG(dst) ? gpr(dst & REG_MASK) : tmp0;
- sljit_gpr loc_r = tmp1;
switch (GET_OPCODE(op)) {
case SLJIT_AND:
case SLJIT_OR:
@@ -3556,37 +3768,125 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *compiler, sljit_s32 type,
sljit_s32 dst_reg,
- sljit_s32 src, sljit_sw srcw)
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_reg)
{
- sljit_ins mask = get_cc(compiler, type & ~SLJIT_32);
+ sljit_ins mask;
sljit_gpr src_r;
+ sljit_gpr dst_r = gpr(dst_reg);
sljit_ins ins;
CHECK_ERROR();
- CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
+ CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));
- if (type & SLJIT_32)
- srcw = (sljit_s32)srcw;
+ ADJUST_LOCAL_OFFSET(src1, src1w);
- if (have_lscond2() && (src & SLJIT_IMM) && is_s16(srcw)) {
- ins = (type & SLJIT_32) ? 0xec0000000042 /* lochi */ : 0xec0000000046 /* locghi */;
- return push_inst(compiler, ins | R36A(gpr(dst_reg)) | (mask << 32) | (sljit_ins)(srcw & 0xffff) << 16);
+ if (dst_reg != src2_reg) {
+ if (src1 == dst_reg) {
+ src1 = src2_reg;
+ src1w = 0;
+ type ^= 0x1;
+ } else {
+ if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) {
+ FAIL_IF(load_word(compiler, dst_r, src1, src1w, type & SLJIT_32));
+ src1 = src2_reg;
+ src1w = 0;
+ type ^= 0x1;
+ } else
+ FAIL_IF(push_inst(compiler, ((type & SLJIT_32) ? 0x1800 /* lr */ : 0xb9040000 /* lgr */) | R4A(dst_r) | R0A(gpr(src2_reg))));
+ }
}
- if (src & SLJIT_IMM) {
- FAIL_IF(push_load_imm_inst(compiler, tmp0, srcw));
+ mask = get_cc(compiler, type & ~SLJIT_32);
+
+ if (src1 & SLJIT_MEM) {
+ if (src1 & OFFS_REG_MASK) {
+ src_r = gpr(OFFS_REG(src1));
+
+ if (src1w != 0) {
+ FAIL_IF(push_inst(compiler, 0xeb000000000d /* sllg */ | R36A(tmp1) | R32A(src_r) | ((sljit_ins)(src1w & 0x3) << 16)));
+ src_r = tmp1;
+ }
+
+ FAIL_IF(push_inst(compiler, 0xb9e80000 /* agrk */ | R12A(src_r) | R4A(tmp1) | R0A(gpr(src1 & REG_MASK))));
+ src_r = tmp1;
+ src1w = 0;
+ } else if (!is_s20(src1w)) {
+ FAIL_IF(push_load_imm_inst(compiler, tmp1, src1w));
+
+ if (src1 & REG_MASK)
+ FAIL_IF(push_inst(compiler, 0xb9e80000 /* agrk */ | R12A(tmp1) | R4A(tmp1) | R0A(gpr(src1 & REG_MASK))));
+
+ src_r = tmp1;
+ src1w = 0;
+ } else
+ src_r = gpr(src1 & REG_MASK);
+
+ ins = (type & SLJIT_32) ? 0xeb00000000f2 /* loc */ : 0xeb00000000e2 /* locg */;
+ return push_inst(compiler, ins | R36A(dst_r) | (mask << 32) | R28A(src_r) | disp_s20((sljit_s32)src1w));
+ }
+
+ if (src1 == SLJIT_IMM) {
+ if (type & SLJIT_32)
+ src1w = (sljit_s32)src1w;
+
+ if (have_lscond2() && is_s16(src1w)) {
+ ins = (type & SLJIT_32) ? 0xec0000000042 /* lochi */ : 0xec0000000046 /* locghi */;
+ return push_inst(compiler, ins | R36A(dst_r) | (mask << 32) | (sljit_ins)(src1w & 0xffff) << 16);
+ }
+
+ FAIL_IF(push_load_imm_inst(compiler, tmp0, src1w));
src_r = tmp0;
} else
- src_r = gpr(src);
+ src_r = gpr(src1);
+
+ ins = (type & SLJIT_32) ? 0xb9f20000 /* locr */ : 0xb9e20000 /* locgr */;
+ return push_inst(compiler, ins | (mask << 12) | R4A(dst_r) | R0A(src_r));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_freg)
+{
+ sljit_ins ins;
+ struct sljit_label *label;
+ struct sljit_jump *jump;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fselect(compiler, type, dst_freg, src1, src1w, src2_freg));
+
+ ADJUST_LOCAL_OFFSET(src1, src1w);
- if (have_lscond1()) {
- ins = (type & SLJIT_32) ? 0xb9f20000 /* locr */ : 0xb9e20000 /* locgr */;
- return push_inst(compiler, ins | (mask << 12) | R4A(gpr(dst_reg)) | R0A(src_r));
+ if (dst_freg != src2_freg) {
+ if (dst_freg == src1) {
+ src1 = src2_freg;
+ src1w = 0;
+ type ^= 0x1;
+ } else {
+ ins = (type & SLJIT_32) ? 0x3800 /* ler */ : 0x2800 /* ldr */;
+ FAIL_IF(push_inst(compiler, ins | F4(dst_freg) | F0(src2_freg)));
+ }
}
- return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);
+ SLJIT_SKIP_CHECKS(compiler);
+ jump = sljit_emit_jump(compiler, (type & ~SLJIT_32) ^ 0x1);
+ FAIL_IF(!jump);
+
+ if (!(src1 & SLJIT_MEM)) {
+ ins = (type & SLJIT_32) ? 0x3800 /* ler */ : 0x2800 /* ldr */;
+ FAIL_IF(push_inst(compiler, ins | F4(dst_freg) | F0(src1)));
+ } else
+ FAIL_IF(float_mem(compiler, FLOAT_LOAD | (type & SLJIT_32), dst_freg, src1, src1w));
+
+ SLJIT_SKIP_CHECKS(compiler);
+ label = sljit_emit_label(compiler);
+ FAIL_IF(!label);
+
+ sljit_set_label(jump, label);
+ return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compiler, sljit_s32 type,
@@ -3648,6 +3948,502 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compile
return push_inst(compiler, ins | R36A(reg2) | disp_s20((sljit_s32)memw + SSIZE_OF(sw)));
}
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_mov(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 srcdst, sljit_sw srcdstw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_s32 alignment = SLJIT_SIMD_GET_ELEM2_SIZE(type);
+ struct addr addr;
+ sljit_ins ins;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_mov(compiler, type, freg, srcdst, srcdstw));
+
+ ADJUST_LOCAL_OFFSET(srcdst, srcdstw);
+
+ if (reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (!(srcdst & SLJIT_MEM)) {
+ if (type & SLJIT_SIMD_STORE)
+ ins = F36(srcdst) | F32(freg);
+ else
+ ins = F36(freg) | F32(srcdst);
+
+ return push_inst(compiler, 0xe70000000056 /* vlr */ | ins);
+ }
+
+ FAIL_IF(make_addr_bx(compiler, &addr, srcdst, srcdstw, tmp1));
+ ins = F36(freg) | R32A(addr.index) | R28A(addr.base) | disp_s20(addr.offset);
+
+ if (alignment >= 4)
+ ins |= 4 << 12;
+ else if (alignment == 3)
+ ins |= 3 << 12;
+
+ return push_inst(compiler, ((type & SLJIT_SIMD_STORE) ? 0xe7000000000e /* vst */ : 0xe70000000006 /* vl */) | ins);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ struct addr addr;
+ sljit_gpr reg;
+ sljit_sw sign_ext;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_replicate(compiler, type, freg, src, srcw));
+
+ ADJUST_LOCAL_OFFSET(src, srcw);
+
+ if (reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && elem_size < 2)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (src & SLJIT_MEM) {
+ FAIL_IF(make_addr_bx(compiler, &addr, src, srcw, tmp1));
+ return push_inst(compiler, 0xe70000000005 /* vlrep */ | F36(freg)
+ | R32A(addr.index) | R28A(addr.base) | disp_s20(addr.offset) | ((sljit_ins)elem_size << 12));
+ }
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ if (src == SLJIT_IMM)
+ return push_inst(compiler, 0xe70000000044 /* vgbm */ | F36(freg));
+
+ return push_inst(compiler, 0xe7000000004d /* vrep */ | F36(freg) | F32(src) | ((sljit_ins)elem_size << 12));
+ }
+
+ if (src == SLJIT_IMM) {
+ sign_ext = 0x10000;
+
+ switch (elem_size) {
+ case 0:
+ srcw &= 0xff;
+ sign_ext = (sljit_s8)srcw;
+ break;
+ case 1:
+ srcw &= 0xffff;
+ sign_ext = (sljit_s16)srcw;
+ break;
+ case 2:
+ if ((sljit_s32)srcw == (sljit_s16)srcw) {
+ srcw &= 0xffff;
+ sign_ext = (sljit_s16)srcw;
+ } else
+ srcw &= 0xffffffff;
+ break;
+ default:
+ if (srcw == (sljit_s16)srcw) {
+ srcw &= 0xffff;
+ sign_ext = (sljit_s16)srcw;
+ }
+ break;
+ }
+
+ if (sign_ext != 0x10000) {
+ if (sign_ext == 0 || sign_ext == -1)
+ return push_inst(compiler, 0xe70000000044 /* vgbm */ | F36(freg)
+ | (sign_ext == 0 ? 0 : ((sljit_ins)0xffff << 16)));
+
+ return push_inst(compiler, 0xe70000000045 /* vrepi */ | F36(freg)
+ | ((sljit_ins)srcw << 16) | ((sljit_ins)elem_size << 12));
+ }
+
+ push_load_imm_inst(compiler, tmp0, srcw);
+ reg = tmp0;
+ } else
+ reg = gpr(src);
+
+ FAIL_IF(push_inst(compiler, 0xe70000000022 /* vlvg */ | F36(freg) | R32A(reg) | ((sljit_ins)elem_size << 12)));
+ return push_inst(compiler, 0xe7000000004d /* vrep */ | F36(freg) | F32(freg) | ((sljit_ins)elem_size << 12));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg, sljit_s32 lane_index,
+ sljit_s32 srcdst, sljit_sw srcdstw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ struct addr addr;
+ sljit_gpr reg;
+ sljit_ins ins = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_lane_mov(compiler, type, freg, lane_index, srcdst, srcdstw));
+
+ ADJUST_LOCAL_OFFSET(srcdst, srcdstw);
+
+ if (reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && elem_size < 2)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (srcdst & SLJIT_MEM) {
+ FAIL_IF(make_addr_bx(compiler, &addr, srcdst, srcdstw, tmp1));
+ ins = F36(freg) | R32A(addr.index) | R28A(addr.base) | disp_s20(addr.offset);
+ }
+
+ if (type & SLJIT_SIMD_LANE_ZERO) {
+ if ((srcdst & SLJIT_MEM) && lane_index == ((1 << (3 - elem_size)) - 1))
+ return push_inst(compiler, 0xe70000000004 /* vllez */ | ins | ((sljit_ins)elem_size << 12));
+
+ if ((type & SLJIT_SIMD_FLOAT) && freg == srcdst) {
+ FAIL_IF(push_inst(compiler, 0xe70000000056 /* vlr */ | F36(TMP_FREG1) | F32(freg)));
+ srcdst = TMP_FREG1;
+ srcdstw = 0;
+ }
+
+ FAIL_IF(push_inst(compiler, 0xe70000000044 /* vgbm */ | F36(freg)));
+ }
+
+ if (srcdst & SLJIT_MEM) {
+ switch (elem_size) {
+ case 0:
+ ins |= 0xe70000000000 /* vleb */;
+ break;
+ case 1:
+ ins |= 0xe70000000001 /* vleh */;
+ break;
+ case 2:
+ ins |= 0xe70000000003 /* vlef */;
+ break;
+ default:
+ ins |= 0xe70000000002 /* vleg */;
+ break;
+ }
+
+ /* Convert to vsteb - vsteg */
+ if (type & SLJIT_SIMD_STORE)
+ ins |= 0x8;
+
+ return push_inst(compiler, ins | ((sljit_ins)lane_index << 12));
+ }
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ if (type & SLJIT_SIMD_STORE)
+ return push_inst(compiler, 0xe7000000004d /* vrep */ | F36(srcdst) | F32(freg) | ((sljit_ins)lane_index << 16) | ((sljit_ins)elem_size << 12));
+
+ if (elem_size == 3) {
+ if (lane_index == 0)
+ ins = F32(srcdst) | F28(freg) | (1 << 12);
+ else
+ ins = F32(freg) | F28(srcdst);
+
+ return push_inst(compiler, 0xe70000000084 /* vpdi */ | F36(freg) | ins);
+ }
+
+ FAIL_IF(push_inst(compiler, 0xe70000000021 /* vlgv */ | R36A(tmp0) | F32(srcdst) | ((sljit_ins)2 << 12)));
+ return push_inst(compiler, 0xe70000000022 /* vlvg */ | F36(freg) | R32A(tmp0) | ((sljit_ins)lane_index << 16) | ((sljit_ins)2 << 12));
+ }
+
+ if (srcdst == SLJIT_IMM) {
+ switch (elem_size) {
+ case 0:
+ ins = 0xe70000000040 /* vleib */;
+ srcdstw &= 0xff;
+ break;
+ case 1:
+ ins = 0xe70000000041 /* vleih */;
+ srcdstw &= 0xffff;
+ break;
+ case 2:
+ if ((sljit_s32)srcdstw == (sljit_s16)srcdstw) {
+ srcdstw &= 0xffff;
+ ins = 0xe70000000043 /* vleif */;
+ } else
+ srcdstw &= 0xffffffff;
+ break;
+ default:
+ if (srcdstw == (sljit_s16)srcdstw) {
+ srcdstw &= 0xffff;
+ ins = 0xe70000000042 /* vleig */;
+ }
+ break;
+ }
+
+ if (ins != 0)
+ return push_inst(compiler, ins | F36(freg) | ((sljit_ins)srcdstw << 16) | ((sljit_ins)lane_index << 12));
+
+ push_load_imm_inst(compiler, tmp0, srcdstw);
+ reg = tmp0;
+ } else
+ reg = gpr(srcdst);
+
+ ins = ((sljit_ins)lane_index << 16) | ((sljit_ins)elem_size << 12);
+
+ if (!(type & SLJIT_SIMD_STORE))
+ return push_inst(compiler, 0xe70000000022 /* vlvg */ | F36(freg) | R32A(reg) | ins);
+
+ FAIL_IF(push_inst(compiler, 0xe70000000021 /* vlgv */ | R36A(reg) | F32(freg) | ins));
+
+ if (!(type & SLJIT_SIMD_LANE_SIGNED) || elem_size >= 3)
+ return SLJIT_SUCCESS;
+
+ switch (elem_size) {
+ case 0:
+ ins = 0xb9060000 /* lgbr */;
+ break;
+ case 1:
+ ins = 0xb9070000 /* lghr */;
+ break;
+ default:
+ ins = 0xb9140000 /* lgfr */;
+ break;
+ }
+
+ return push_inst(compiler, ins | R4A(reg) | R0A(reg));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_s32 src_lane_index)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_lane_replicate(compiler, type, freg, src, src_lane_index));
+
+ if (reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && elem_size < 2)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ return push_inst(compiler, 0xe7000000004d /* vrep */ | F36(freg) | F32(src)
+ | ((sljit_ins)src_lane_index << 16) | ((sljit_ins)elem_size << 12));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_extend(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_s32 elem2_size = SLJIT_SIMD_GET_ELEM2_SIZE(type);
+ struct addr addr;
+ sljit_ins ins;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_extend(compiler, type, freg, src, srcw));
+
+ ADJUST_LOCAL_OFFSET(src, srcw);
+
+ if (reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && elem_size < 2)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (src & SLJIT_MEM) {
+ FAIL_IF(make_addr_bx(compiler, &addr, src, srcw, tmp1));
+ ins = F36(freg) | R32A(addr.index) | R28A(addr.base) | disp_s20(addr.offset);
+
+ switch (elem2_size - elem_size) {
+ case 1:
+ ins |= 0xe70000000002 /* vleg */;
+ break;
+ case 2:
+ ins |= 0xe70000000003 /* vlef */;
+ break;
+ default:
+ ins |= 0xe70000000001 /* vleh */;
+ break;
+ }
+
+ FAIL_IF(push_inst(compiler, ins));
+ src = freg;
+ }
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ FAIL_IF(push_inst(compiler, 0xe700000000d5 /* vuplh */ | F36(freg) | F32(src) | (2 << 12)));
+ FAIL_IF(push_inst(compiler, 0xe70000000030 /* vesl */ | F36(freg) | F32(freg) | (32 << 16) | (3 << 12)));
+ return push_inst(compiler, 0xe700000000c4 /* vfll */ | F36(freg) | F32(freg) | (2 << 12));
+ }
+
+ ins = ((type & SLJIT_SIMD_EXTEND_SIGNED) ? 0xe700000000d7 /* vuph */ : 0xe700000000d5 /* vuplh */) | F36(freg);
+
+ do {
+ FAIL_IF(push_inst(compiler, ins | F32(src) | ((sljit_ins)elem_size << 12)));
+ src = freg;
+ } while (++elem_size < elem2_size);
+
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 dst, sljit_sw dstw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_gpr dst_r;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_sign(compiler, type, freg, dst, dstw));
+
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+
+ if (reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && elem_size < 2)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ switch (elem_size) {
+ case 0:
+ push_load_imm_inst(compiler, tmp0, (sljit_sw)0x4048505860687078);
+ push_load_imm_inst(compiler, tmp1, (sljit_sw)0x0008101820283038);
+ FAIL_IF(push_inst(compiler, 0xe70000000062 /* vlvgp */ | F36(TMP_FREG1) | R32A(tmp1) | R28A(tmp0)));
+ break;
+ case 1:
+ push_load_imm_inst(compiler, tmp0, (sljit_sw)0x0010203040506070);
+ break;
+ case 2:
+ push_load_imm_inst(compiler, tmp0, (sljit_sw)0x8080808000204060);
+ break;
+ default:
+ push_load_imm_inst(compiler, tmp0, (sljit_sw)0x8080808080800040);
+ break;
+ }
+
+ if (elem_size != 0)
+ FAIL_IF(push_inst(compiler, 0xe70000000022 /* vlvg */ | F36(TMP_FREG1) | R32A(tmp0) | (1 << 16) | (3 << 12)));
+
+ FAIL_IF(push_inst(compiler, 0xe70000000085 /* vbperm */ | F36(TMP_FREG1) | F32(freg) | F28(TMP_FREG1)));
+
+ dst_r = FAST_IS_REG(dst) ? gpr(dst) : tmp0;
+ FAIL_IF(push_inst(compiler, 0xe70000000021 /* vlgv */ | R36A(dst_r) | F32(TMP_FREG1)
+ | (elem_size == 0 ? ((3 << 16) | (1 << 12)) : (7 << 16))));
+
+ if (dst_r == tmp0)
+ return store_word(compiler, tmp0, dst, dstw, type & SLJIT_32);
+
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_op2(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg, sljit_s32 src1_freg, sljit_s32 src2_freg)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_ins ins = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_op2(compiler, type, dst_freg, src1_freg, src2_freg));
+
+ if (reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ switch (SLJIT_SIMD_GET_OPCODE(type)) {
+ case SLJIT_SIMD_OP2_AND:
+ ins = 0xe70000000068 /* vn */;
+ break;
+ case SLJIT_SIMD_OP2_OR:
+ ins = 0xe7000000006a /* vo */;
+ break;
+ case SLJIT_SIMD_OP2_XOR:
+ ins = 0xe7000000006d /* vx */;
+ break;
+ }
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ return push_inst(compiler, ins | F36(dst_freg) | F32(src1_freg) | F28(src2_freg));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_load(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_reg,
+ sljit_s32 mem_reg)
+{
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_atomic_load(compiler, op, dst_reg, mem_reg));
+
+ SLJIT_SKIP_CHECKS(compiler);
+ return sljit_emit_op1(compiler, op, dst_reg, 0, SLJIT_MEM1(mem_reg), 0);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src_reg,
+ sljit_s32 mem_reg,
+ sljit_s32 temp_reg)
+{
+ sljit_ins mask;
+ sljit_gpr tmp_r = gpr(temp_reg);
+ sljit_gpr mem_r = gpr(mem_reg);
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_atomic_store(compiler, op, src_reg, mem_reg, temp_reg));
+
+ switch (GET_OPCODE(op)) {
+ case SLJIT_MOV32:
+ case SLJIT_MOV_U32:
+ return push_inst(compiler, 0xba000000 /* cs */ | R20A(tmp_r) | R16A(gpr(src_reg)) | R12A(mem_r));
+ case SLJIT_MOV_U8:
+ mask = 0xff;
+ break;
+ case SLJIT_MOV_U16:
+ mask = 0xffff;
+ break;
+ default:
+ return push_inst(compiler, 0xeb0000000030 /* csg */ | R36A(tmp_r) | R32A(gpr(src_reg)) | R28A(mem_r));
+ }
+
+ /* tmp0 = (src_reg ^ tmp_r) & mask */
+ FAIL_IF(push_inst(compiler, 0xa50f0000 /* llill */ | R20A(tmp1) | mask));
+ FAIL_IF(push_inst(compiler, 0xb9e70000 /* xgrk */ | R4A(tmp0) | R0A(gpr(src_reg)) | R12A(tmp_r)));
+ FAIL_IF(push_inst(compiler, 0xa7090000 /* lghi */ | R20A(tmp_r) | 0xfffc));
+ FAIL_IF(push_inst(compiler, 0xb9800000 /* ngr */ | R4A(tmp0) | R0A(tmp1)));
+
+ /* tmp0 = tmp0 << (((mem_r ^ 0x3) & 0x3) << 3) */
+ FAIL_IF(push_inst(compiler, 0xa50f0000 /* llill */ | R20A(tmp1) | (sljit_ins)((mask == 0xff) ? 0x18 : 0x10)));
+ FAIL_IF(push_inst(compiler, 0xb9800000 /* ngr */ | R4A(tmp_r) | R0A(mem_r)));
+ FAIL_IF(push_inst(compiler, 0xec0000000057 /* rxsbg */ | R36A(tmp1) | R32A(mem_r) | (59 << 24) | (60 << 16) | (3 << 8)));
+ FAIL_IF(push_inst(compiler, 0xeb000000000d /* sllg */ | R36A(tmp0) | R32A(tmp0) | R28A(tmp1)));
+
+ /* Already computed: tmp_r = mem_r & ~0x3 */
+
+ FAIL_IF(push_inst(compiler, 0x58000000 /* l */ | R20A(tmp1) | R12A(tmp_r)));
+ FAIL_IF(push_inst(compiler, 0x1700 /* x */ | R4A(tmp0) | R0A(tmp1)));
+ return push_inst(compiler, 0xba000000 /* cs */ | R20A(tmp1) | R16A(tmp0) | R12A(tmp_r));
+}
+
/* --------------------------------------------------------------------- */
/* Other instructions */
/* --------------------------------------------------------------------- */
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeX86_32.c b/src/3rdparty/pcre2/src/sljit/sljitNativeX86_32.c
index 08da03026d..ba4a1ebbc2 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeX86_32.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeX86_32.c
@@ -62,21 +62,19 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
/* Both size flags cannot be switched on. */
SLJIT_ASSERT((flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) != (EX86_BYTE_ARG | EX86_HALF_ARG));
/* SSE2 and immediate is not possible. */
- SLJIT_ASSERT(!(a & SLJIT_IMM) || !(flags & EX86_SSE2));
- SLJIT_ASSERT((flags & (EX86_PREF_F2 | EX86_PREF_F3)) != (EX86_PREF_F2 | EX86_PREF_F3)
- && (flags & (EX86_PREF_F2 | EX86_PREF_66)) != (EX86_PREF_F2 | EX86_PREF_66)
- && (flags & (EX86_PREF_F3 | EX86_PREF_66)) != (EX86_PREF_F3 | EX86_PREF_66));
+ SLJIT_ASSERT(a != SLJIT_IMM || !(flags & EX86_SSE2));
+ SLJIT_ASSERT(((flags & (EX86_PREF_F2 | EX86_PREF_F3 | EX86_PREF_66))
+ & ((flags & (EX86_PREF_F2 | EX86_PREF_F3 | EX86_PREF_66)) - 1)) == 0);
+ SLJIT_ASSERT((flags & (EX86_VEX_EXT | EX86_REX)) != EX86_VEX_EXT);
size &= 0xf;
- inst_size = size;
+ /* The mod r/m byte is always present. */
+ inst_size = size + 1;
- if (flags & (EX86_PREF_F2 | EX86_PREF_F3))
- inst_size++;
- if (flags & EX86_PREF_66)
+ if (flags & (EX86_PREF_F2 | EX86_PREF_F3 | EX86_PREF_66))
inst_size++;
/* Calculate size of b. */
- inst_size += 1; /* mod r/m byte. */
if (b & SLJIT_MEM) {
if (!(b & REG_MASK))
inst_size += sizeof(sljit_sw);
@@ -87,8 +85,7 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
inst_size += sizeof(sljit_s8);
else
inst_size += sizeof(sljit_sw);
- }
- else if (reg_map[b & REG_MASK] == 5) {
+ } else if (reg_map[b & REG_MASK] == 5) {
/* Swap registers if possible. */
if ((b & OFFS_REG_MASK) && (immb & 0x3) == 0 && reg_map[OFFS_REG(b)] != 5)
b = SLJIT_MEM | OFFS_REG(b) | TO_OFFS_REG(b & REG_MASK);
@@ -105,15 +102,14 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
}
/* Calculate size of a. */
- if (a & SLJIT_IMM) {
+ if (a == SLJIT_IMM) {
if (flags & EX86_BIN_INS) {
if (imma <= 127 && imma >= -128) {
inst_size += 1;
flags |= EX86_BYTE_ARG;
} else
inst_size += 4;
- }
- else if (flags & EX86_SHIFT_INS) {
+ } else if (flags & EX86_SHIFT_INS) {
SLJIT_ASSERT(imma <= 0x1f);
if (imma != 1) {
inst_size++;
@@ -125,8 +121,7 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
inst_size += sizeof(short);
else
inst_size += sizeof(sljit_sw);
- }
- else
+ } else
SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG);
inst = (sljit_u8*)ensure_buf(compiler, 1 + inst_size);
@@ -136,27 +131,26 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
INC_SIZE(inst_size);
if (flags & EX86_PREF_F2)
*inst++ = 0xf2;
- if (flags & EX86_PREF_F3)
+ else if (flags & EX86_PREF_F3)
*inst++ = 0xf3;
- if (flags & EX86_PREF_66)
+ else if (flags & EX86_PREF_66)
*inst++ = 0x66;
buf_ptr = inst + size;
/* Encode mod/rm byte. */
if (!(flags & EX86_SHIFT_INS)) {
- if ((flags & EX86_BIN_INS) && (a & SLJIT_IMM))
+ if ((flags & EX86_BIN_INS) && a == SLJIT_IMM)
*inst = (flags & EX86_BYTE_ARG) ? GROUP_BINARY_83 : GROUP_BINARY_81;
- if (a & SLJIT_IMM)
+ if (a == SLJIT_IMM)
*buf_ptr = 0;
else if (!(flags & EX86_SSE2_OP1))
*buf_ptr = U8(reg_map[a] << 3);
else
- *buf_ptr = U8(a << 3);
- }
- else {
- if (a & SLJIT_IMM) {
+ *buf_ptr = U8(freg_map[a] << 3);
+ } else {
+ if (a == SLJIT_IMM) {
if (imma == 1)
*inst = GROUP_SHIFT_1;
else
@@ -167,7 +161,7 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
}
if (!(b & SLJIT_MEM)) {
- *buf_ptr = U8(*buf_ptr | MOD_REG | (!(flags & EX86_SSE2_OP2) ? reg_map[b] : b));
+ *buf_ptr = U8(*buf_ptr | MOD_REG | (!(flags & EX86_SSE2_OP2) ? reg_map[b] : freg_map[b]));
buf_ptr++;
} else if (b & REG_MASK) {
reg_map_b = reg_map[b & REG_MASK];
@@ -183,8 +177,9 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
if (!(b & OFFS_REG_MASK))
*buf_ptr++ |= reg_map_b;
else {
- *buf_ptr++ |= 0x04;
- *buf_ptr++ = U8(reg_map_b | (reg_map[OFFS_REG(b)] << 3));
+ buf_ptr[0] |= 0x04;
+ buf_ptr[1] = U8(reg_map_b | (reg_map[OFFS_REG(b)] << 3));
+ buf_ptr += 2;
}
if (immb != 0 || reg_map_b == 5) {
@@ -195,25 +190,24 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
buf_ptr += sizeof(sljit_sw);
}
}
- }
- else {
+ } else {
if (reg_map_b == 5)
*buf_ptr |= 0x40;
- *buf_ptr++ |= 0x04;
- *buf_ptr++ = U8(reg_map_b | (reg_map[OFFS_REG(b)] << 3) | (immb << 6));
+ buf_ptr[0] |= 0x04;
+ buf_ptr[1] = U8(reg_map_b | (reg_map[OFFS_REG(b)] << 3) | (immb << 6));
+ buf_ptr += 2;
if (reg_map_b == 5)
*buf_ptr++ = 0;
}
- }
- else {
+ } else {
*buf_ptr++ |= 0x05;
sljit_unaligned_store_sw(buf_ptr, immb); /* 32 bit displacement. */
buf_ptr += sizeof(sljit_sw);
}
- if (a & SLJIT_IMM) {
+ if (a == SLJIT_IMM) {
if (flags & EX86_BYTE_ARG)
*buf_ptr = U8(imma);
else if (flags & EX86_HALF_ARG)
@@ -222,7 +216,67 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
sljit_unaligned_store_sw(buf_ptr, imma);
}
- return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1);
+ return inst;
+}
+
+static sljit_s32 emit_vex_instruction(struct sljit_compiler *compiler, sljit_uw op,
+ /* The first and second register operand. */
+ sljit_s32 a, sljit_s32 v,
+ /* The general operand (not immediate). */
+ sljit_s32 b, sljit_sw immb)
+{
+ sljit_u8 *inst;
+ sljit_u8 vex = 0;
+ sljit_u8 vex_m = 0;
+ sljit_uw size;
+
+ SLJIT_ASSERT(((op & (EX86_PREF_F2 | EX86_PREF_F3 | EX86_PREF_66))
+ & ((op & (EX86_PREF_F2 | EX86_PREF_F3 | EX86_PREF_66)) - 1)) == 0);
+
+ if (op & VEX_OP_0F38)
+ vex_m = 0x2;
+ else if (op & VEX_OP_0F3A)
+ vex_m = 0x3;
+
+ if (op & VEX_W) {
+ if (vex_m == 0)
+ vex_m = 0x1;
+
+ vex |= 0x80;
+ }
+
+ if (op & EX86_PREF_66)
+ vex |= 0x1;
+ else if (op & EX86_PREF_F2)
+ vex |= 0x3;
+ else if (op & EX86_PREF_F3)
+ vex |= 0x2;
+
+ op &= ~(EX86_PREF_66 | EX86_PREF_F2 | EX86_PREF_F3);
+
+ if (op & VEX_256)
+ vex |= 0x4;
+
+ vex = U8(vex | ((((op & VEX_SSE2_OPV) ? freg_map[v] : reg_map[v]) ^ 0xf) << 3));
+
+ size = op & ~(sljit_uw)0xff;
+ size |= (vex_m == 0) ? 3 : 4;
+
+ inst = emit_x86_instruction(compiler, size, a, 0, b, immb);
+ FAIL_IF(!inst);
+
+ if (vex_m == 0) {
+ inst[0] = 0xc5;
+ inst[1] = U8(vex | 0x80);
+ inst[2] = U8(op);
+ return SLJIT_SUCCESS;
+ }
+
+ inst[0] = 0xc4;
+ inst[1] = U8(vex_m | 0xe0);
+ inst[2] = vex;
+ inst[3] = U8(op);
+ return SLJIT_SUCCESS;
}
/* --------------------------------------------------------------------- */
@@ -578,8 +632,6 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler)
{
- sljit_u8 *inst;
-
CHECK_ERROR();
CHECK(check_sljit_emit_return_void(compiler));
@@ -588,11 +640,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler
FAIL_IF(emit_stack_frame_release(compiler, 0));
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
- FAIL_IF(!inst);
- INC_SIZE(1);
- RET();
- return SLJIT_SUCCESS;
+ return emit_byte(compiler, RET_near);
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler,
@@ -782,7 +830,7 @@ static sljit_s32 tail_call_with_args(struct sljit_compiler *compiler,
offset = stack_size + compiler->local_size;
- if (!(src & SLJIT_IMM) && src != SLJIT_R0) {
+ if (src != SLJIT_IMM && src != SLJIT_R0) {
if (word_arg_count >= 1) {
EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), 0, SLJIT_R0, 0);
r2_offset = sizeof(sljit_sw);
@@ -836,7 +884,7 @@ static sljit_s32 tail_call_with_args(struct sljit_compiler *compiler,
stack_size = args_size + SSIZE_OF(sw);
- if (word_arg_count >= 1 && !(src & SLJIT_IMM) && src != SLJIT_R0) {
+ if (word_arg_count >= 1 && src != SLJIT_IMM && src != SLJIT_R0) {
r2_offset = SSIZE_OF(sw);
stack_size += SSIZE_OF(sw);
}
@@ -865,7 +913,7 @@ static sljit_s32 tail_call_with_args(struct sljit_compiler *compiler,
EMIT_MOV(compiler, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), word_arg4_offset);
}
- if (!(src & SLJIT_IMM) && src != SLJIT_R0) {
+ if (src != SLJIT_IMM && src != SLJIT_R0) {
if (word_arg_count >= 1) {
SLJIT_ASSERT(r2_offset == sizeof(sljit_sw));
EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), 0, SLJIT_R0, 0);
@@ -952,13 +1000,7 @@ static sljit_s32 emit_tail_call_end(struct sljit_compiler *compiler, sljit_s32 e
sljit_u8 *inst;
BINARY_IMM32(ADD, extra_space, SLJIT_SP, 0);
-
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
- FAIL_IF(!inst);
- INC_SIZE(1);
- RET();
-
- return SLJIT_SUCCESS;
+ return emit_byte(compiler, RET_near);
}
static sljit_s32 tail_call_reg_arg_with_args(struct sljit_compiler *compiler, sljit_s32 arg_types)
@@ -1075,7 +1117,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compi
stack_size = type;
FAIL_IF(tail_call_with_args(compiler, &stack_size, arg_types, src, srcw));
- if (!(src & SLJIT_IMM)) {
+ if (src != SLJIT_IMM) {
src = SLJIT_R0;
srcw = 0;
}
@@ -1142,30 +1184,20 @@ static SLJIT_INLINE sljit_s32 emit_fmov_before_return(struct sljit_compiler *com
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+static sljit_s32 emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
sljit_u8 *inst;
- CHECK_ERROR();
- CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
- ADJUST_LOCAL_OFFSET(dst, dstw);
-
CHECK_EXTRA_REGS(dst, dstw, (void)0);
- if (FAST_IS_REG(dst)) {
- /* Unused dest is possible here. */
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
- FAIL_IF(!inst);
-
- INC_SIZE(1);
- POP_REG(reg_map[dst]);
- return SLJIT_SUCCESS;
- }
+ /* Unused dest is possible here. */
+ if (FAST_IS_REG(dst))
+ return emit_byte(compiler, U8(POP_r + reg_map[dst]));
/* Memory. */
inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
FAIL_IF(!inst);
- *inst++ = POP_rm;
+ *inst = POP_rm;
return SLJIT_SUCCESS;
}
@@ -1185,8 +1217,8 @@ static sljit_s32 emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src
else {
inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw);
FAIL_IF(!inst);
- *inst++ = GROUP_FF;
- *inst |= PUSH_rm;
+ inst[0] = GROUP_FF;
+ inst[1] |= PUSH_rm;
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!inst);
@@ -1197,6 +1229,22 @@ static sljit_s32 emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src
return SLJIT_SUCCESS;
}
+static sljit_s32 sljit_emit_get_return_address(struct sljit_compiler *compiler,
+ sljit_s32 dst, sljit_sw dstw)
+{
+ sljit_s32 options = compiler->options;
+ sljit_s32 saveds = compiler->saveds;
+ sljit_s32 scratches = compiler->scratches;
+
+ saveds = ((scratches > 9 ? (scratches - 9) : 0) + (saveds <= 3 ? saveds : 3) - SLJIT_KEPT_SAVEDS_COUNT(options)) * SSIZE_OF(sw);
+
+ /* Saving ebp. */
+ if (!(options & SLJIT_ENTER_REG_ARG))
+ saveds += SSIZE_OF(sw);
+
+ return emit_mov(compiler, dst, dstw, SLJIT_MEM1(SLJIT_SP), compiler->local_size + saveds);
+}
+
/* --------------------------------------------------------------------- */
/* Other operations */
/* --------------------------------------------------------------------- */
@@ -1279,6 +1327,283 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_mem(struct sljit_compiler *compile
return SLJIT_SUCCESS;
}
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_uw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG;
+ sljit_u8 *inst, *jump_inst1, *jump_inst2;
+ sljit_uw size1, size2;
+
+ /* Binary representation of 0x80000000. */
+ static const sljit_f64 f64_high_bit = (sljit_f64)0x80000000ul;
+
+ CHECK_EXTRA_REGS(src, srcw, (void)0);
+
+ if (!(op & SLJIT_32)) {
+ EMIT_MOV(compiler, TMP_REG1, 0, src, srcw);
+
+ inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 1, TMP_REG1, 0);
+ FAIL_IF(!inst);
+ inst[1] |= ROL;
+
+ inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 1, TMP_REG1, 0);
+ FAIL_IF(!inst);
+ inst[1] |= SHR;
+
+ FAIL_IF(emit_groupf(compiler, CVTSI2SD_x_rm | EX86_PREF_F2 | EX86_SSE2_OP1, dst_r, TMP_REG1, 0));
+
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+ FAIL_IF(!inst);
+ INC_SIZE(2);
+ inst[0] = U8(get_jump_code(SLJIT_NOT_CARRY) - 0x10);
+
+ size1 = compiler->size;
+ FAIL_IF(emit_groupf(compiler, ADDSD_x_xm | EX86_PREF_F2 | EX86_SSE2, dst_r, SLJIT_MEM0(), (sljit_sw)&f64_high_bit));
+
+ inst[1] = U8(compiler->size - size1);
+
+ if (dst_r == TMP_FREG)
+ return emit_sse2_store(compiler, 0, dst, dstw, TMP_FREG);
+ return SLJIT_SUCCESS;
+ }
+
+ if (!FAST_IS_REG(src)) {
+ EMIT_MOV(compiler, TMP_REG1, 0, src, srcw);
+ src = TMP_REG1;
+ }
+
+ BINARY_IMM32(CMP, 0, src, 0);
+
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+ FAIL_IF(!inst);
+ INC_SIZE(2);
+ inst[0] = JL_i8;
+ jump_inst1 = inst;
+
+ size1 = compiler->size;
+
+ FAIL_IF(emit_groupf(compiler, CVTSI2SD_x_rm | EX86_SELECT_F2_F3(op) | EX86_SSE2_OP1, dst_r, src, 0));
+
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+ FAIL_IF(!inst);
+ INC_SIZE(2);
+ inst[0] = JMP_i8;
+ jump_inst2 = inst;
+
+ size2 = compiler->size;
+
+ jump_inst1[1] = U8(size2 - size1);
+
+ if (src != TMP_REG1)
+ EMIT_MOV(compiler, TMP_REG1, 0, src, 0);
+
+ inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 1, TMP_REG1, 0);
+ FAIL_IF(!inst);
+ inst[1] |= SHR;
+
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+ FAIL_IF(!inst);
+ INC_SIZE(2);
+ inst[0] = JNC_i8;
+ jump_inst1 = inst;
+
+ size1 = compiler->size;
+
+ BINARY_IMM32(OR, 1, TMP_REG1, 0);
+ jump_inst1[1] = U8(compiler->size - size1);
+
+ FAIL_IF(emit_groupf(compiler, CVTSI2SD_x_rm | EX86_SELECT_F2_F3(op) | EX86_SSE2_OP1, dst_r, TMP_REG1, 0));
+ FAIL_IF(emit_groupf(compiler, ADDSD_x_xm | EX86_SELECT_F2_F3(op) | EX86_SSE2, dst_r, dst_r, 0));
+
+ jump_inst2[1] = U8(compiler->size - size2);
+
+ if (dst_r == TMP_FREG)
+ return emit_sse2_store(compiler, op & SLJIT_32, dst, dstw, TMP_FREG);
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset32(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f32 value)
+{
+ sljit_u8 *inst;
+ union {
+ sljit_s32 imm;
+ sljit_f32 value;
+ } u;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fset32(compiler, freg, value));
+
+ u.value = value;
+
+ if (u.imm != 0)
+ EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, u.imm);
+
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
+ FAIL_IF(!inst);
+ INC_SIZE(4);
+
+ inst[0] = GROUP_66;
+ inst[1] = GROUP_0F;
+
+ if (u.imm == 0) {
+ inst[2] = PXOR_x_xm;
+ inst[3] = U8(freg | (freg << 3) | MOD_REG);
+ } else {
+ inst[2] = MOVD_x_rm;
+ inst[3] = U8(reg_map[TMP_REG1] | (freg << 3) | MOD_REG);
+ }
+
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f64 value)
+{
+ sljit_u8 *inst;
+ sljit_s32 tmp_freg = freg;
+ union {
+ sljit_s32 imm[2];
+ sljit_f64 value;
+ } u;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fset64(compiler, freg, value));
+
+ u.value = value;
+
+ if (u.imm[0] == 0) {
+ if (u.imm[1] == 0)
+ return emit_groupf(compiler, PXOR_x_xm | EX86_PREF_66 | EX86_SSE2, freg, freg, 0);
+
+ EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, u.imm[1]);
+ } else
+ EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, u.imm[0]);
+
+ FAIL_IF(emit_groupf(compiler, MOVD_x_rm | EX86_PREF_66 | EX86_SSE2_OP1, freg, TMP_REG1, 0));
+
+ if (u.imm[1] == 0)
+ return SLJIT_SUCCESS;
+
+ if (u.imm[0] == 0) {
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
+ FAIL_IF(!inst);
+ INC_SIZE(4);
+
+ inst[0] = GROUP_0F;
+ inst[1] = SHUFPS_x_xm;
+ inst[2] = U8(MOD_REG | (freg << 3) | freg);
+ inst[3] = 0x51;
+ return SLJIT_SUCCESS;
+ }
+
+ if (u.imm[0] != u.imm[1]) {
+ SLJIT_ASSERT(u.imm[1] != 0 && cpu_feature_list != 0);
+
+ EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, u.imm[1]);
+
+ if (cpu_feature_list & CPU_FEATURE_SSE41) {
+ FAIL_IF(emit_groupf_ext(compiler, PINSRD_x_rm_i8 | EX86_PREF_66 | VEX_OP_0F3A | EX86_SSE2_OP1, freg, TMP_REG1, 0));
+ return emit_byte(compiler, 1);
+ }
+
+ FAIL_IF(emit_groupf(compiler, MOVD_x_rm | EX86_PREF_66 | EX86_SSE2_OP1, TMP_FREG, TMP_REG1, 0));
+ tmp_freg = TMP_FREG;
+ }
+
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 3);
+ FAIL_IF(!inst);
+ INC_SIZE(3);
+
+ inst[0] = GROUP_0F;
+ inst[1] = UNPCKLPS_x_xm;
+ inst[2] = U8(MOD_REG | (freg << 3) | tmp_freg);
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 freg, sljit_s32 reg)
+{
+ sljit_u8 *inst;
+ sljit_s32 reg2;
+ sljit_sw regw, reg2w;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+ regw = 0;
+ reg2 = 0;
+ reg2w = 0;
+
+ SLJIT_ASSERT(cpu_feature_list != 0);
+
+ if (!(op & SLJIT_32) && (cpu_feature_list & CPU_FEATURE_SSE41)) {
+ if (reg & REG_PAIR_MASK) {
+ reg2 = REG_PAIR_FIRST(reg);
+ reg = REG_PAIR_SECOND(reg);
+
+ CHECK_EXTRA_REGS(reg, regw, (void)0);
+
+ FAIL_IF(emit_groupf(compiler, (GET_OPCODE(op) == SLJIT_COPY_TO_F64 ? MOVD_x_rm : MOVD_rm_x)
+ | EX86_PREF_66 | EX86_SSE2_OP1, freg, reg, regw));
+ } else
+ reg2 = reg;
+
+ CHECK_EXTRA_REGS(reg2, reg2w, (void)0);
+
+ FAIL_IF(emit_groupf_ext(compiler, (GET_OPCODE(op) == SLJIT_COPY_TO_F64 ? PINSRD_x_rm_i8 : PEXTRD_rm_x_i8)
+ | EX86_PREF_66 | VEX_OP_0F3A | EX86_SSE2_OP1, freg, reg2, reg2w));
+ return emit_byte(compiler, 1);
+ }
+
+ if (reg & REG_PAIR_MASK) {
+ reg2 = REG_PAIR_SECOND(reg);
+ reg = REG_PAIR_FIRST(reg);
+
+ if (reg == reg2)
+ reg = 0;
+
+ CHECK_EXTRA_REGS(reg2, reg2w, (void)0);
+ }
+
+ CHECK_EXTRA_REGS(reg, regw, (void)0);
+
+ if (op & SLJIT_32)
+ return emit_groupf(compiler, (GET_OPCODE(op) == SLJIT_COPY_TO_F64 ? MOVD_x_rm : MOVD_rm_x)
+ | EX86_PREF_66 | EX86_SSE2_OP1, freg, reg, regw);
+
+ if (op == SLJIT_COPY_FROM_F64) {
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 5);
+ FAIL_IF(!inst);
+ INC_SIZE(5);
+
+ inst[0] = GROUP_66;
+ inst[1] = GROUP_0F;
+ inst[2] = PSHUFD_x_xm;
+ inst[3] = U8(MOD_REG | (TMP_FREG << 3) | freg);
+ inst[4] = 1;
+ } else if (reg != 0)
+ FAIL_IF(emit_groupf(compiler, MOVD_x_rm | EX86_PREF_66 | EX86_SSE2_OP1, TMP_FREG, reg, regw));
+
+ if (reg2 != 0)
+ FAIL_IF(emit_groupf(compiler, (GET_OPCODE(op) == SLJIT_COPY_TO_F64 ? MOVD_x_rm : MOVD_rm_x)
+ | EX86_PREF_66 | EX86_SSE2_OP1, freg, reg2, reg2w));
+
+ if (GET_OPCODE(op) == SLJIT_COPY_TO_F64) {
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 3);
+ FAIL_IF(!inst);
+ INC_SIZE(3);
+
+ inst[0] = GROUP_0F;
+ inst[1] = UNPCKLPS_x_xm;
+ inst[2] = U8(MOD_REG | (freg << 3) | (reg == 0 ? freg : TMP_FREG));
+ } else
+ FAIL_IF(emit_groupf(compiler, MOVD_rm_x | EX86_PREF_66 | EX86_SSE2_OP1, TMP_FREG, reg, regw));
+
+ return SLJIT_SUCCESS;
+}
+
static sljit_s32 skip_frames_before_return(struct sljit_compiler *compiler)
{
sljit_sw size;
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeX86_64.c b/src/3rdparty/pcre2/src/sljit/sljitNativeX86_64.c
index 4e938ffcf3..f313f3f038 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeX86_64.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeX86_64.c
@@ -37,9 +37,9 @@ static sljit_s32 emit_load_imm64(struct sljit_compiler *compiler, sljit_s32 reg,
inst = (sljit_u8*)ensure_buf(compiler, 1 + 2 + sizeof(sljit_sw));
FAIL_IF(!inst);
INC_SIZE(2 + sizeof(sljit_sw));
- *inst++ = REX_W | ((reg_map[reg] <= 7) ? 0 : REX_B);
- *inst++ = U8(MOV_r_i32 | (reg_map[reg] & 0x7));
- sljit_unaligned_store_sw(inst, imm);
+ inst[0] = REX_W | ((reg_map[reg] <= 7) ? 0 : REX_B);
+ inst[1] = U8(MOV_r_i32 | reg_lmap[reg]);
+ sljit_unaligned_store_sw(inst + 2, imm);
return SLJIT_SUCCESS;
}
@@ -72,7 +72,7 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
sljit_uw inst_size;
/* The immediate operand must be 32 bit. */
- SLJIT_ASSERT(!(a & SLJIT_IMM) || compiler->mode32 || IS_HALFWORD(imma));
+ SLJIT_ASSERT(a != SLJIT_IMM || compiler->mode32 || IS_HALFWORD(imma));
/* Both cannot be switched on. */
SLJIT_ASSERT((flags & (EX86_BIN_INS | EX86_SHIFT_INS)) != (EX86_BIN_INS | EX86_SHIFT_INS));
/* Size flags not allowed for typed instructions. */
@@ -80,26 +80,24 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
/* Both size flags cannot be switched on. */
SLJIT_ASSERT((flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) != (EX86_BYTE_ARG | EX86_HALF_ARG));
/* SSE2 and immediate is not possible. */
- SLJIT_ASSERT(!(a & SLJIT_IMM) || !(flags & EX86_SSE2));
- SLJIT_ASSERT((flags & (EX86_PREF_F2 | EX86_PREF_F3)) != (EX86_PREF_F2 | EX86_PREF_F3)
- && (flags & (EX86_PREF_F2 | EX86_PREF_66)) != (EX86_PREF_F2 | EX86_PREF_66)
- && (flags & (EX86_PREF_F3 | EX86_PREF_66)) != (EX86_PREF_F3 | EX86_PREF_66));
+ SLJIT_ASSERT(a != SLJIT_IMM || !(flags & EX86_SSE2));
+ SLJIT_ASSERT(((flags & (EX86_PREF_F2 | EX86_PREF_F3 | EX86_PREF_66))
+ & ((flags & (EX86_PREF_F2 | EX86_PREF_F3 | EX86_PREF_66)) - 1)) == 0);
+ SLJIT_ASSERT((flags & (EX86_VEX_EXT | EX86_REX)) != EX86_VEX_EXT);
size &= 0xf;
- inst_size = size;
+ /* The mod r/m byte is always present. */
+ inst_size = size + 1;
if (!compiler->mode32 && !(flags & EX86_NO_REXW))
rex |= REX_W;
else if (flags & EX86_REX)
rex |= REX;
- if (flags & (EX86_PREF_F2 | EX86_PREF_F3))
- inst_size++;
- if (flags & EX86_PREF_66)
+ if (flags & (EX86_PREF_F2 | EX86_PREF_F3 | EX86_PREF_66))
inst_size++;
/* Calculate size of b. */
- inst_size += 1; /* mod r/m byte. */
if (b & SLJIT_MEM) {
if (!(b & OFFS_REG_MASK) && NOT_HALFWORD(immb)) {
PTR_FAIL_IF(emit_load_imm64(compiler, TMP_REG2, immb));
@@ -119,8 +117,7 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
inst_size += sizeof(sljit_s8);
else
inst_size += sizeof(sljit_s32);
- }
- else if (reg_lmap[b & REG_MASK] == 5) {
+ } else if (reg_lmap[b & REG_MASK] == 5) {
/* Swap registers if possible. */
if ((b & OFFS_REG_MASK) && (immb & 0x3) == 0 && reg_lmap[OFFS_REG(b)] != 5)
b = SLJIT_MEM | OFFS_REG(b) | TO_OFFS_REG(b & REG_MASK);
@@ -140,23 +137,26 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
rex |= REX_X;
}
}
- }
- else if (!(flags & EX86_SSE2_OP2)) {
+ } else if (!(flags & EX86_SSE2_OP2)) {
if (reg_map[b] >= 8)
rex |= REX_B;
- }
- else if (freg_map[b] >= 8)
+ } else if (freg_map[b] >= 8)
rex |= REX_B;
- if (a & SLJIT_IMM) {
+ if ((flags & EX86_VEX_EXT) && (rex & 0x3)) {
+ SLJIT_ASSERT(size == 2);
+ size++;
+ inst_size++;
+ }
+
+ if (a == SLJIT_IMM) {
if (flags & EX86_BIN_INS) {
if (imma <= 127 && imma >= -128) {
inst_size += 1;
flags |= EX86_BYTE_ARG;
} else
inst_size += 4;
- }
- else if (flags & EX86_SHIFT_INS) {
+ } else if (flags & EX86_SHIFT_INS) {
SLJIT_ASSERT(imma <= (compiler->mode32 ? 0x1f : 0x3f));
if (imma != 1) {
inst_size++;
@@ -168,8 +168,7 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
inst_size += sizeof(short);
else
inst_size += sizeof(sljit_s32);
- }
- else {
+ } else {
SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG);
/* reg_map[SLJIT_PREF_SHIFT_REG] is less than 8. */
if (!(flags & EX86_SSE2_OP1)) {
@@ -186,32 +185,34 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
inst = (sljit_u8*)ensure_buf(compiler, 1 + inst_size);
PTR_FAIL_IF(!inst);
- /* Encoding the byte. */
+ /* Encoding prefixes. */
INC_SIZE(inst_size);
if (flags & EX86_PREF_F2)
*inst++ = 0xf2;
- if (flags & EX86_PREF_F3)
+ else if (flags & EX86_PREF_F3)
*inst++ = 0xf3;
- if (flags & EX86_PREF_66)
+ else if (flags & EX86_PREF_66)
*inst++ = 0x66;
+
+ /* Rex is always the last prefix. */
if (rex)
*inst++ = rex;
+
buf_ptr = inst + size;
/* Encode mod/rm byte. */
if (!(flags & EX86_SHIFT_INS)) {
- if ((flags & EX86_BIN_INS) && (a & SLJIT_IMM))
+ if ((flags & EX86_BIN_INS) && a == SLJIT_IMM)
*inst = (flags & EX86_BYTE_ARG) ? GROUP_BINARY_83 : GROUP_BINARY_81;
- if (a & SLJIT_IMM)
+ if (a == SLJIT_IMM)
*buf_ptr = 0;
else if (!(flags & EX86_SSE2_OP1))
*buf_ptr = U8(reg_lmap[a] << 3);
else
*buf_ptr = U8(freg_lmap[a] << 3);
- }
- else {
- if (a & SLJIT_IMM) {
+ } else {
+ if (a == SLJIT_IMM) {
if (imma == 1)
*inst = GROUP_SHIFT_1;
else
@@ -238,8 +239,9 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
if (!(b & OFFS_REG_MASK))
*buf_ptr++ |= reg_lmap_b;
else {
- *buf_ptr++ |= 0x04;
- *buf_ptr++ = U8(reg_lmap_b | (reg_lmap[OFFS_REG(b)] << 3));
+ buf_ptr[0] |= 0x04;
+ buf_ptr[1] = U8(reg_lmap_b | (reg_lmap[OFFS_REG(b)] << 3));
+ buf_ptr += 2;
}
if (immb != 0 || reg_lmap_b == 5) {
@@ -250,26 +252,26 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
buf_ptr += sizeof(sljit_s32);
}
}
- }
- else {
+ } else {
if (reg_lmap_b == 5)
*buf_ptr |= 0x40;
- *buf_ptr++ |= 0x04;
- *buf_ptr++ = U8(reg_lmap_b | (reg_lmap[OFFS_REG(b)] << 3) | (immb << 6));
+ buf_ptr[0] |= 0x04;
+ buf_ptr[1] = U8(reg_lmap_b | (reg_lmap[OFFS_REG(b)] << 3) | (immb << 6));
+ buf_ptr += 2;
if (reg_lmap_b == 5)
*buf_ptr++ = 0;
}
- }
- else {
- *buf_ptr++ |= 0x04;
- *buf_ptr++ = 0x25;
+ } else {
+ buf_ptr[0] |= 0x04;
+ buf_ptr[1] = 0x25;
+ buf_ptr += 2;
sljit_unaligned_store_s32(buf_ptr, (sljit_s32)immb); /* 32 bit displacement. */
buf_ptr += sizeof(sljit_s32);
}
- if (a & SLJIT_IMM) {
+ if (a == SLJIT_IMM) {
if (flags & EX86_BYTE_ARG)
*buf_ptr = U8(imma);
else if (flags & EX86_HALF_ARG)
@@ -278,7 +280,78 @@ static sljit_u8* emit_x86_instruction(struct sljit_compiler *compiler, sljit_uw
sljit_unaligned_store_s32(buf_ptr, (sljit_s32)imma);
}
- return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1);
+ return inst;
+}
+
+static sljit_s32 emit_vex_instruction(struct sljit_compiler *compiler, sljit_uw op,
+ /* The first and second register operand. */
+ sljit_s32 a, sljit_s32 v,
+ /* The general operand (not immediate). */
+ sljit_s32 b, sljit_sw immb)
+{
+ sljit_u8 *inst;
+ sljit_u8 vex = 0;
+ sljit_u8 vex_m = 0;
+ sljit_uw size;
+
+ SLJIT_ASSERT(((op & (EX86_PREF_F2 | EX86_PREF_F3 | EX86_PREF_66))
+ & ((op & (EX86_PREF_F2 | EX86_PREF_F3 | EX86_PREF_66)) - 1)) == 0);
+
+ op |= EX86_REX;
+
+ if (op & VEX_OP_0F38)
+ vex_m = 0x2;
+ else if (op & VEX_OP_0F3A)
+ vex_m = 0x3;
+
+ if ((op & VEX_W) || ((op & VEX_AUTO_W) && !compiler->mode32)) {
+ if (vex_m == 0)
+ vex_m = 0x1;
+
+ vex |= 0x80;
+ }
+
+ if (op & EX86_PREF_66)
+ vex |= 0x1;
+ else if (op & EX86_PREF_F2)
+ vex |= 0x3;
+ else if (op & EX86_PREF_F3)
+ vex |= 0x2;
+
+ op &= ~(EX86_PREF_66 | EX86_PREF_F2 | EX86_PREF_F3);
+
+ if (op & VEX_256)
+ vex |= 0x4;
+
+ vex = U8(vex | ((((op & VEX_SSE2_OPV) ? freg_map[v] : reg_map[v]) ^ 0xf) << 3));
+
+ size = op & ~(sljit_uw)0xff;
+ size |= (vex_m == 0) ? (EX86_VEX_EXT | 2) : 3;
+
+ inst = emit_x86_instruction(compiler, size, a, 0, b, immb);
+ FAIL_IF(!inst);
+
+ SLJIT_ASSERT((inst[-1] & 0xf0) == REX);
+
+ /* If X or B is present in REX prefix. */
+ if (vex_m == 0 && inst[-1] & 0x3)
+ vex_m = 0x1;
+
+ if (vex_m == 0) {
+ vex |= U8(((inst[-1] >> 2) ^ 0x1) << 7);
+
+ inst[-1] = 0xc5;
+ inst[0] = vex;
+ inst[1] = U8(op);
+ return SLJIT_SUCCESS;
+ }
+
+ vex_m |= U8((inst[-1] ^ 0x7) << 5);
+ inst[-1] = 0xc4;
+ inst[0] = vex_m;
+ inst[1] = vex;
+ inst[2] = U8(op);
+ return SLJIT_SUCCESS;
}
/* --------------------------------------------------------------------- */
@@ -370,6 +443,12 @@ static sljit_u8* generate_put_label_code(struct sljit_put_label *put_label, slji
return code_ptr;
}
+#ifdef _WIN64
+typedef struct {
+ sljit_sw regs[2];
+} sljit_sse2_reg;
+#endif /* _WIN64 */
+
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compiler,
sljit_s32 options, sljit_s32 arg_types, sljit_s32 scratches, sljit_s32 saveds,
sljit_s32 fscratches, sljit_s32 fsaveds, sljit_s32 local_size)
@@ -423,7 +502,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
#ifdef _WIN64
local_size += SLJIT_LOCALS_OFFSET;
- saved_float_regs_size = GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, 16);
+ saved_float_regs_size = GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sse2_reg);
if (saved_float_regs_size > 0) {
saved_float_regs_offset = ((local_size + 0xf) & ~0xf);
@@ -532,16 +611,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_enter(struct sljit_compiler *compi
tmp = SLJIT_FS0 - fsaveds;
for (i = SLJIT_FS0; i > tmp; i--) {
- inst = emit_x86_instruction(compiler, 2 | EX86_SSE2, i, 0, SLJIT_MEM1(SLJIT_SP), saved_float_regs_offset);
- *inst++ = GROUP_0F;
- *inst = MOVAPS_xm_x;
+ FAIL_IF(emit_groupf(compiler, MOVAPS_xm_x | EX86_SSE2, i, SLJIT_MEM1(SLJIT_SP), saved_float_regs_offset));
saved_float_regs_offset += 16;
}
for (i = fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) {
- inst = emit_x86_instruction(compiler, 2 | EX86_SSE2, i, 0, SLJIT_MEM1(SLJIT_SP), saved_float_regs_offset);
- *inst++ = GROUP_0F;
- *inst = MOVAPS_xm_x;
+ FAIL_IF(emit_groupf(compiler, MOVAPS_xm_x | EX86_SSE2, i, SLJIT_MEM1(SLJIT_SP), saved_float_regs_offset));
saved_float_regs_offset += 16;
}
}
@@ -565,7 +640,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_set_context(struct sljit_compiler *comp
#ifdef _WIN64
local_size += SLJIT_LOCALS_OFFSET;
- saved_float_regs_size = GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, 16);
+ saved_float_regs_size = GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sse2_reg);
if (saved_float_regs_size > 0)
local_size = ((local_size + 0xf) & ~0xf) + saved_float_regs_size;
@@ -591,7 +666,7 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit
#endif /* _WIN64 */
#ifdef _WIN64
- saved_float_regs_offset = GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, 16);
+ saved_float_regs_offset = GET_SAVED_FLOAT_REGISTERS_SIZE(fscratches, fsaveds, sse2_reg);
if (saved_float_regs_offset > 0) {
compiler->mode32 = 1;
@@ -599,16 +674,12 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit
tmp = SLJIT_FS0 - fsaveds;
for (i = SLJIT_FS0; i > tmp; i--) {
- inst = emit_x86_instruction(compiler, 2 | EX86_SSE2, i, 0, SLJIT_MEM1(SLJIT_SP), saved_float_regs_offset);
- *inst++ = GROUP_0F;
- *inst = MOVAPS_x_xm;
+ FAIL_IF(emit_groupf(compiler, MOVAPS_x_xm | EX86_SSE2, i, SLJIT_MEM1(SLJIT_SP), saved_float_regs_offset));
saved_float_regs_offset += 16;
}
for (i = fscratches; i >= SLJIT_FIRST_SAVED_FLOAT_REG; i--) {
- inst = emit_x86_instruction(compiler, 2 | EX86_SSE2, i, 0, SLJIT_MEM1(SLJIT_SP), saved_float_regs_offset);
- *inst++ = GROUP_0F;
- *inst = MOVAPS_x_xm;
+ FAIL_IF(emit_groupf(compiler, MOVAPS_x_xm | EX86_SSE2, i, SLJIT_MEM1(SLJIT_SP), saved_float_regs_offset));
saved_float_regs_offset += 16;
}
@@ -656,20 +727,13 @@ static sljit_s32 emit_stack_frame_release(struct sljit_compiler *compiler, sljit
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_void(struct sljit_compiler *compiler)
{
- sljit_u8 *inst;
-
CHECK_ERROR();
CHECK(check_sljit_emit_return_void(compiler));
compiler->mode32 = 0;
FAIL_IF(emit_stack_frame_release(compiler, 0));
-
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
- FAIL_IF(!inst);
- INC_SIZE(1);
- RET();
- return SLJIT_SUCCESS;
+ return emit_byte(compiler, RET_near);
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_return_to(struct sljit_compiler *compiler,
@@ -863,22 +927,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_icall(struct sljit_compiler *compi
return sljit_emit_ijump(compiler, type, src, srcw);
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
+static sljit_s32 emit_fast_enter(struct sljit_compiler *compiler, sljit_s32 dst, sljit_sw dstw)
{
sljit_u8 *inst;
- CHECK_ERROR();
- CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
- ADJUST_LOCAL_OFFSET(dst, dstw);
-
if (FAST_IS_REG(dst)) {
- if (reg_map[dst] < 8) {
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
- FAIL_IF(!inst);
- INC_SIZE(1);
- POP_REG(reg_lmap[dst]);
- return SLJIT_SUCCESS;
- }
+ if (reg_map[dst] < 8)
+ return emit_byte(compiler, U8(POP_r + reg_lmap[dst]));
inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
FAIL_IF(!inst);
@@ -892,7 +947,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fast_enter(struct sljit_compiler *
compiler->mode32 = 1;
inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
FAIL_IF(!inst);
- *inst++ = POP_rm;
+ *inst = POP_rm;
return SLJIT_SUCCESS;
}
@@ -922,8 +977,8 @@ static sljit_s32 emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src
compiler->mode32 = 1;
inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw);
FAIL_IF(!inst);
- *inst++ = GROUP_FF;
- *inst |= PUSH_rm;
+ inst[0] = GROUP_FF;
+ inst[1] |= PUSH_rm;
inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!inst);
@@ -934,6 +989,16 @@ static sljit_s32 emit_fast_return(struct sljit_compiler *compiler, sljit_s32 src
return SLJIT_SUCCESS;
}
+static sljit_s32 sljit_emit_get_return_address(struct sljit_compiler *compiler,
+ sljit_s32 dst, sljit_sw dstw)
+{
+ sljit_s32 saved_regs_size;
+
+ compiler->mode32 = 0;
+ saved_regs_size = GET_SAVED_REGISTERS_SIZE(compiler->scratches, compiler->saveds - SLJIT_KEPT_SAVEDS_COUNT(compiler->options), 0);
+ return emit_mov(compiler, dst, dstw, SLJIT_MEM1(SLJIT_SP), compiler->local_size + saved_regs_size);
+}
+
/* --------------------------------------------------------------------- */
/* Other operations */
/* --------------------------------------------------------------------- */
@@ -1027,15 +1092,15 @@ static sljit_s32 emit_mov_int(struct sljit_compiler *compiler, sljit_s32 sign,
compiler->mode32 = 0;
- if (src & SLJIT_IMM) {
+ if (src == SLJIT_IMM) {
if (FAST_IS_REG(dst)) {
- if (sign || ((sljit_uw)srcw <= 0x7fffffff)) {
- inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_s32)srcw, dst, dstw);
- FAIL_IF(!inst);
- *inst = MOV_rm_i32;
- return SLJIT_SUCCESS;
- }
- return emit_load_imm64(compiler, dst, srcw);
+ if (!sign || ((sljit_u32)srcw <= 0x7fffffff))
+ return emit_do_imm32(compiler, reg_map[dst] <= 7 ? 0 : REX_B, U8(MOV_r_i32 | reg_lmap[dst]), srcw);
+
+ inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_s32)srcw, dst, dstw);
+ FAIL_IF(!inst);
+ *inst = MOV_rm_i32;
+ return SLJIT_SUCCESS;
}
compiler->mode32 = 1;
inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_s32)srcw, dst, dstw);
@@ -1053,10 +1118,10 @@ static sljit_s32 emit_mov_int(struct sljit_compiler *compiler, sljit_s32 sign,
if (sign) {
inst = emit_x86_instruction(compiler, 1, dst_r, 0, src, srcw);
FAIL_IF(!inst);
- *inst++ = MOVSXD_r_rm;
+ *inst = MOVSXD_r_rm;
} else {
compiler->mode32 = 1;
- FAIL_IF(emit_mov(compiler, dst_r, 0, src, srcw));
+ EMIT_MOV(compiler, dst_r, 0, src, srcw);
compiler->mode32 = 0;
}
}
@@ -1072,6 +1137,203 @@ static sljit_s32 emit_mov_int(struct sljit_compiler *compiler, sljit_s32 sign,
return SLJIT_SUCCESS;
}
+static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_uw(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG;
+ sljit_u8 *inst, *jump_inst1, *jump_inst2;
+ sljit_uw size1, size2;
+
+ compiler->mode32 = 0;
+
+ if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_U32) {
+ if (src != SLJIT_IMM) {
+ compiler->mode32 = 1;
+ EMIT_MOV(compiler, TMP_REG1, 0, src, srcw);
+ compiler->mode32 = 0;
+ } else
+ FAIL_IF(emit_do_imm32(compiler, reg_map[TMP_REG1] <= 7 ? 0 : REX_B, U8(MOV_r_i32 | reg_lmap[TMP_REG1]), srcw));
+
+ FAIL_IF(emit_groupf(compiler, CVTSI2SD_x_rm | EX86_SELECT_F2_F3(op) | EX86_SSE2_OP1, dst_r, TMP_REG1, 0));
+
+ compiler->mode32 = 1;
+
+ if (dst_r == TMP_FREG)
+ return emit_sse2_store(compiler, op & SLJIT_32, dst, dstw, TMP_FREG);
+ return SLJIT_SUCCESS;
+ }
+
+ if (!FAST_IS_REG(src)) {
+ EMIT_MOV(compiler, TMP_REG1, 0, src, srcw);
+ src = TMP_REG1;
+ }
+
+ BINARY_IMM32(CMP, 0, src, 0);
+
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+ FAIL_IF(!inst);
+ INC_SIZE(2);
+ inst[0] = JL_i8;
+ jump_inst1 = inst;
+
+ size1 = compiler->size;
+
+ compiler->mode32 = 0;
+ FAIL_IF(emit_groupf(compiler, CVTSI2SD_x_rm | EX86_SELECT_F2_F3(op) | EX86_SSE2_OP1, dst_r, src, 0));
+
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+ FAIL_IF(!inst);
+ INC_SIZE(2);
+ inst[0] = JMP_i8;
+ jump_inst2 = inst;
+
+ size2 = compiler->size;
+
+ jump_inst1[1] = U8(size2 - size1);
+
+ if (src != TMP_REG1)
+ EMIT_MOV(compiler, TMP_REG1, 0, src, 0);
+
+ EMIT_MOV(compiler, TMP_REG2, 0, src, 0);
+
+ inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 1, TMP_REG1, 0);
+ FAIL_IF(!inst);
+ inst[1] |= SHR;
+
+ compiler->mode32 = 1;
+ BINARY_IMM32(AND, 1, TMP_REG2, 0);
+
+ compiler->mode32 = 0;
+ inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, TMP_REG2, 0);
+ FAIL_IF(!inst);
+ inst[0] = OR_r_rm;
+
+ FAIL_IF(emit_groupf(compiler, CVTSI2SD_x_rm | EX86_SELECT_F2_F3(op) | EX86_SSE2_OP1, dst_r, TMP_REG1, 0));
+ compiler->mode32 = 1;
+ FAIL_IF(emit_groupf(compiler, ADDSD_x_xm | EX86_SELECT_F2_F3(op) | EX86_SSE2, dst_r, dst_r, 0));
+
+ jump_inst2[1] = U8(compiler->size - size2);
+
+ if (dst_r == TMP_FREG)
+ return emit_sse2_store(compiler, op & SLJIT_32, dst, dstw, TMP_FREG);
+ return SLJIT_SUCCESS;
+}
+
+static sljit_s32 sljit_emit_fset(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_u8 rex, sljit_s32 is_zero)
+{
+ sljit_u8 *inst;
+ sljit_u32 size;
+
+ if (is_zero) {
+ rex = freg_map[freg] >= 8 ? (REX_R | REX_B) : 0;
+ } else {
+ if (freg_map[freg] >= 8)
+ rex |= REX_R;
+ if (reg_map[TMP_REG1] >= 8)
+ rex |= REX_B;
+ }
+
+ size = (rex != 0) ? 5 : 4;
+
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
+ FAIL_IF(!inst);
+ INC_SIZE(size);
+
+ *inst++ = GROUP_66;
+ if (rex != 0)
+ *inst++ = rex;
+ inst[0] = GROUP_0F;
+
+ if (is_zero) {
+ inst[1] = PXOR_x_xm;
+ inst[2] = U8(freg_lmap[freg] | (freg_lmap[freg] << 3) | MOD_REG);
+ } else {
+ inst[1] = MOVD_x_rm;
+ inst[2] = U8(reg_lmap[TMP_REG1] | (freg_lmap[freg] << 3) | MOD_REG);
+ }
+
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset32(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f32 value)
+{
+ union {
+ sljit_s32 imm;
+ sljit_f32 value;
+ } u;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fset32(compiler, freg, value));
+
+ u.value = value;
+
+ if (u.imm != 0) {
+ compiler->mode32 = 1;
+ EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, u.imm);
+ }
+
+ return sljit_emit_fset(compiler, freg, 0, u.imm == 0);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fset64(struct sljit_compiler *compiler,
+ sljit_s32 freg, sljit_f64 value)
+{
+ union {
+ sljit_sw imm;
+ sljit_f64 value;
+ } u;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fset64(compiler, freg, value));
+
+ u.value = value;
+
+ if (u.imm != 0) {
+ compiler->mode32 = 0;
+ EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, u.imm);
+ }
+
+ return sljit_emit_fset(compiler, freg, REX_W, u.imm == 0);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fcopy(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 freg, sljit_s32 reg)
+{
+ sljit_u8 *inst;
+ sljit_u32 size;
+ sljit_u8 rex = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fcopy(compiler, op, freg, reg));
+
+ if (!(op & SLJIT_32))
+ rex = REX_W;
+
+ if (freg_map[freg] >= 8)
+ rex |= REX_R;
+
+ if (reg_map[reg] >= 8)
+ rex |= REX_B;
+
+ size = (rex != 0) ? 5 : 4;
+
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
+ FAIL_IF(!inst);
+ INC_SIZE(size);
+
+ *inst++ = GROUP_66;
+ if (rex != 0)
+ *inst++ = rex;
+ inst[0] = GROUP_0F;
+ inst[1] = GET_OPCODE(op) == SLJIT_COPY_TO_F64 ? MOVD_x_rm : MOVD_rm_x;
+ inst[2] = U8(reg_lmap[reg] | (freg_lmap[freg] << 3) | MOD_REG);
+
+ return SLJIT_SUCCESS;
+}
+
static sljit_s32 skip_frames_before_return(struct sljit_compiler *compiler)
{
sljit_s32 tmp, size;
diff --git a/src/3rdparty/pcre2/src/sljit/sljitNativeX86_common.c b/src/3rdparty/pcre2/src/sljit/sljitNativeX86_common.c
index 651942be80..c2c0421349 100644
--- a/src/3rdparty/pcre2/src/sljit/sljitNativeX86_common.c
+++ b/src/3rdparty/pcre2/src/sljit/sljitNativeX86_common.c
@@ -24,6 +24,12 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+#include <sanitizer/msan_interface.h>
+#endif /* __has_feature(memory_sanitizer) */
+#endif /* defined(__has_feature) */
+
SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
{
return "x86" SLJIT_CPUINFO;
@@ -61,15 +67,18 @@ SLJIT_API_FUNC_ATTRIBUTE const char* sljit_get_platform_name(void)
15 - R15
*/
-#define TMP_FREG (0)
+#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)
+#define TMP_FREG (SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1)
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
-/* Last register + 1. */
-#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)
static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 3] = {
- 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 7, 6, 3, 4, 5
+ 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 5, 7, 6, 4, 3
+};
+
+static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 0
};
#define CHECK_EXTRA_REGS(p, w, do) \
@@ -81,12 +90,10 @@ static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 3] = {
#else /* SLJIT_CONFIG_X86_32 */
-/* Last register + 1. */
-#define TMP_REG1 (SLJIT_NUMBER_OF_REGISTERS + 2)
#define TMP_REG2 (SLJIT_NUMBER_OF_REGISTERS + 3)
/* Note: r12 & 0x7 == 0b100, which decoded as SIB byte present
- Note: avoid to use r12 and r13 for memory addessing
+ Note: avoid to use r12 and r13 for memory addressing
therefore r12 is better to be a higher saved register. */
#ifndef _WIN64
/* Args: rdi(=7), rsi(=6), rdx(=2), rcx(=1), r8, r9. Scratches: rax(=0), r10, r11 */
@@ -95,7 +102,7 @@ static const sljit_u8 reg_map[SLJIT_NUMBER_OF_REGISTERS + 4] = {
};
/* low-map. reg_map & 0x7. */
static const sljit_u8 reg_lmap[SLJIT_NUMBER_OF_REGISTERS + 4] = {
- 0, 0, 6, 7, 1, 0, 3, 2, 4, 5, 5, 6, 7, 3, 4, 2, 1
+ 0, 0, 6, 7, 1, 0, 3, 2, 4, 5, 5, 6, 7, 3, 4, 2, 1
};
#else
/* Args: rcx(=1), rdx(=2), r8, r9. Scratches: rax(=0), r10, r11 */
@@ -109,12 +116,12 @@ static const sljit_u8 reg_lmap[SLJIT_NUMBER_OF_REGISTERS + 4] = {
#endif
/* Args: xmm0-xmm3 */
-static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1] = {
- 4, 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+static const sljit_u8 freg_map[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2] = {
+ 0, 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 4
};
/* low-map. freg_map & 0x7. */
-static const sljit_u8 freg_lmap[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1] = {
- 4, 0, 1, 2, 3, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7
+static const sljit_u8 freg_lmap[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 2] = {
+ 0, 0, 1, 2, 3, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 4
};
#define REX_W 0x48
@@ -140,155 +147,237 @@ static const sljit_u8 freg_lmap[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1] = {
#define U8(v) ((sljit_u8)(v))
-
/* Size flags for emit_x86_instruction: */
-#define EX86_BIN_INS 0x0010
-#define EX86_SHIFT_INS 0x0020
-#define EX86_REX 0x0040
-#define EX86_NO_REXW 0x0080
-#define EX86_BYTE_ARG 0x0100
-#define EX86_HALF_ARG 0x0200
-#define EX86_PREF_66 0x0400
-#define EX86_PREF_F2 0x0800
-#define EX86_PREF_F3 0x1000
-#define EX86_SSE2_OP1 0x2000
-#define EX86_SSE2_OP2 0x4000
+#define EX86_BIN_INS ((sljit_uw)0x000010)
+#define EX86_SHIFT_INS ((sljit_uw)0x000020)
+#define EX86_BYTE_ARG ((sljit_uw)0x000040)
+#define EX86_HALF_ARG ((sljit_uw)0x000080)
+/* Size flags for both emit_x86_instruction and emit_vex_instruction: */
+#define EX86_REX ((sljit_uw)0x000100)
+#define EX86_NO_REXW ((sljit_uw)0x000200)
+#define EX86_PREF_66 ((sljit_uw)0x000400)
+#define EX86_PREF_F2 ((sljit_uw)0x000800)
+#define EX86_PREF_F3 ((sljit_uw)0x001000)
+#define EX86_SSE2_OP1 ((sljit_uw)0x002000)
+#define EX86_SSE2_OP2 ((sljit_uw)0x004000)
#define EX86_SSE2 (EX86_SSE2_OP1 | EX86_SSE2_OP2)
+#define EX86_VEX_EXT ((sljit_uw)0x008000)
+/* Op flags for emit_vex_instruction: */
+#define VEX_OP_0F38 ((sljit_uw)0x010000)
+#define VEX_OP_0F3A ((sljit_uw)0x020000)
+#define VEX_SSE2_OPV ((sljit_uw)0x040000)
+#define VEX_AUTO_W ((sljit_uw)0x080000)
+#define VEX_W ((sljit_uw)0x100000)
+#define VEX_256 ((sljit_uw)0x200000)
+
+#define EX86_SELECT_66(op) (((op) & SLJIT_32) ? 0 : EX86_PREF_66)
+#define EX86_SELECT_F2_F3(op) (((op) & SLJIT_32) ? EX86_PREF_F3 : EX86_PREF_F2)
/* --------------------------------------------------------------------- */
-/* Instrucion forms */
+/* Instruction forms */
/* --------------------------------------------------------------------- */
-#define ADD (/* BINARY */ 0 << 3)
-#define ADD_EAX_i32 0x05
-#define ADD_r_rm 0x03
-#define ADD_rm_r 0x01
-#define ADDSD_x_xm 0x58
-#define ADC (/* BINARY */ 2 << 3)
-#define ADC_EAX_i32 0x15
-#define ADC_r_rm 0x13
-#define ADC_rm_r 0x11
-#define AND (/* BINARY */ 4 << 3)
-#define AND_EAX_i32 0x25
-#define AND_r_rm 0x23
-#define AND_rm_r 0x21
-#define ANDPD_x_xm 0x54
-#define BSR_r_rm (/* GROUP_0F */ 0xbd)
-#define BSF_r_rm (/* GROUP_0F */ 0xbc)
-#define CALL_i32 0xe8
-#define CALL_rm (/* GROUP_FF */ 2 << 3)
-#define CDQ 0x99
-#define CMOVE_r_rm (/* GROUP_0F */ 0x44)
-#define CMP (/* BINARY */ 7 << 3)
-#define CMP_EAX_i32 0x3d
-#define CMP_r_rm 0x3b
-#define CMP_rm_r 0x39
-#define CVTPD2PS_x_xm 0x5a
-#define CVTSI2SD_x_rm 0x2a
-#define CVTTSD2SI_r_xm 0x2c
-#define DIV (/* GROUP_F7 */ 6 << 3)
-#define DIVSD_x_xm 0x5e
-#define FLDS 0xd9
-#define FLDL 0xdd
-#define FSTPS 0xd9
-#define FSTPD 0xdd
-#define INT3 0xcc
-#define IDIV (/* GROUP_F7 */ 7 << 3)
-#define IMUL (/* GROUP_F7 */ 5 << 3)
-#define IMUL_r_rm (/* GROUP_0F */ 0xaf)
-#define IMUL_r_rm_i8 0x6b
-#define IMUL_r_rm_i32 0x69
-#define JE_i8 0x74
-#define JNE_i8 0x75
-#define JMP_i8 0xeb
-#define JMP_i32 0xe9
-#define JMP_rm (/* GROUP_FF */ 4 << 3)
-#define LEA_r_m 0x8d
-#define LOOP_i8 0xe2
-#define LZCNT_r_rm (/* GROUP_F3 */ /* GROUP_0F */ 0xbd)
-#define MOV_r_rm 0x8b
-#define MOV_r_i32 0xb8
-#define MOV_rm_r 0x89
-#define MOV_rm_i32 0xc7
-#define MOV_rm8_i8 0xc6
-#define MOV_rm8_r8 0x88
-#define MOVAPS_x_xm 0x28
-#define MOVAPS_xm_x 0x29
-#define MOVSD_x_xm 0x10
-#define MOVSD_xm_x 0x11
-#define MOVSXD_r_rm 0x63
-#define MOVSX_r_rm8 (/* GROUP_0F */ 0xbe)
-#define MOVSX_r_rm16 (/* GROUP_0F */ 0xbf)
-#define MOVZX_r_rm8 (/* GROUP_0F */ 0xb6)
-#define MOVZX_r_rm16 (/* GROUP_0F */ 0xb7)
-#define MUL (/* GROUP_F7 */ 4 << 3)
-#define MULSD_x_xm 0x59
-#define NEG_rm (/* GROUP_F7 */ 3 << 3)
-#define NOP 0x90
-#define NOT_rm (/* GROUP_F7 */ 2 << 3)
-#define OR (/* BINARY */ 1 << 3)
-#define OR_r_rm 0x0b
-#define OR_EAX_i32 0x0d
-#define OR_rm_r 0x09
-#define OR_rm8_r8 0x08
-#define POP_r 0x58
-#define POP_rm 0x8f
-#define POPF 0x9d
-#define PREFETCH 0x18
-#define PUSH_i32 0x68
-#define PUSH_r 0x50
-#define PUSH_rm (/* GROUP_FF */ 6 << 3)
-#define PUSHF 0x9c
-#define ROL (/* SHIFT */ 0 << 3)
-#define ROR (/* SHIFT */ 1 << 3)
-#define RET_near 0xc3
-#define RET_i16 0xc2
-#define SBB (/* BINARY */ 3 << 3)
-#define SBB_EAX_i32 0x1d
-#define SBB_r_rm 0x1b
-#define SBB_rm_r 0x19
-#define SAR (/* SHIFT */ 7 << 3)
-#define SHL (/* SHIFT */ 4 << 3)
-#define SHLD (/* GROUP_0F */ 0xa5)
-#define SHRD (/* GROUP_0F */ 0xad)
-#define SHR (/* SHIFT */ 5 << 3)
-#define SUB (/* BINARY */ 5 << 3)
-#define SUB_EAX_i32 0x2d
-#define SUB_r_rm 0x2b
-#define SUB_rm_r 0x29
-#define SUBSD_x_xm 0x5c
-#define TEST_EAX_i32 0xa9
-#define TEST_rm_r 0x85
-#define TZCNT_r_rm (/* GROUP_F3 */ /* GROUP_0F */ 0xbc)
-#define UCOMISD_x_xm 0x2e
-#define UNPCKLPD_x_xm 0x14
-#define XCHG_EAX_r 0x90
-#define XCHG_r_rm 0x87
-#define XOR (/* BINARY */ 6 << 3)
-#define XOR_EAX_i32 0x35
-#define XOR_r_rm 0x33
-#define XOR_rm_r 0x31
-#define XORPD_x_xm 0x57
-
-#define GROUP_0F 0x0f
-#define GROUP_F3 0xf3
-#define GROUP_F7 0xf7
-#define GROUP_FF 0xff
-#define GROUP_BINARY_81 0x81
-#define GROUP_BINARY_83 0x83
-#define GROUP_SHIFT_1 0xd1
-#define GROUP_SHIFT_N 0xc1
-#define GROUP_SHIFT_CL 0xd3
-
-#define MOD_REG 0xc0
-#define MOD_DISP8 0x40
-
-#define INC_SIZE(s) (*inst++ = U8(s), compiler->size += (s))
-
-#define PUSH_REG(r) (*inst++ = U8(PUSH_r + (r)))
-#define POP_REG(r) (*inst++ = U8(POP_r + (r)))
-#define RET() (*inst++ = RET_near)
-#define RET_I16(n) (*inst++ = RET_i16, *inst++ = U8(n), *inst++ = 0)
+#define ADD (/* BINARY */ 0 << 3)
+#define ADD_EAX_i32 0x05
+#define ADD_r_rm 0x03
+#define ADD_rm_r 0x01
+#define ADDSD_x_xm 0x58
+#define ADC (/* BINARY */ 2 << 3)
+#define ADC_EAX_i32 0x15
+#define ADC_r_rm 0x13
+#define ADC_rm_r 0x11
+#define AND (/* BINARY */ 4 << 3)
+#define AND_EAX_i32 0x25
+#define AND_r_rm 0x23
+#define AND_rm_r 0x21
+#define ANDPD_x_xm 0x54
+#define BSR_r_rm (/* GROUP_0F */ 0xbd)
+#define BSF_r_rm (/* GROUP_0F */ 0xbc)
+#define BSWAP_r (/* GROUP_0F */ 0xc8)
+#define CALL_i32 0xe8
+#define CALL_rm (/* GROUP_FF */ 2 << 3)
+#define CDQ 0x99
+#define CMOVE_r_rm (/* GROUP_0F */ 0x44)
+#define CMP (/* BINARY */ 7 << 3)
+#define CMP_EAX_i32 0x3d
+#define CMP_r_rm 0x3b
+#define CMP_rm_r 0x39
+#define CMPS_x_xm 0xc2
+#define CMPXCHG_rm_r 0xb1
+#define CMPXCHG_rm8_r 0xb0
+#define CVTPD2PS_x_xm 0x5a
+#define CVTPS2PD_x_xm 0x5a
+#define CVTSI2SD_x_rm 0x2a
+#define CVTTSD2SI_r_xm 0x2c
+#define DIV (/* GROUP_F7 */ 6 << 3)
+#define DIVSD_x_xm 0x5e
+#define EXTRACTPS_x_xm 0x17
+#define FLDS 0xd9
+#define FLDL 0xdd
+#define FSTPS 0xd9
+#define FSTPD 0xdd
+#define INSERTPS_x_xm 0x21
+#define INT3 0xcc
+#define IDIV (/* GROUP_F7 */ 7 << 3)
+#define IMUL (/* GROUP_F7 */ 5 << 3)
+#define IMUL_r_rm (/* GROUP_0F */ 0xaf)
+#define IMUL_r_rm_i8 0x6b
+#define IMUL_r_rm_i32 0x69
+#define JL_i8 0x7c
+#define JE_i8 0x74
+#define JNC_i8 0x73
+#define JNE_i8 0x75
+#define JMP_i8 0xeb
+#define JMP_i32 0xe9
+#define JMP_rm (/* GROUP_FF */ 4 << 3)
+#define LEA_r_m 0x8d
+#define LOOP_i8 0xe2
+#define LZCNT_r_rm (/* GROUP_F3 */ /* GROUP_0F */ 0xbd)
+#define MOV_r_rm 0x8b
+#define MOV_r_i32 0xb8
+#define MOV_rm_r 0x89
+#define MOV_rm_i32 0xc7
+#define MOV_rm8_i8 0xc6
+#define MOV_rm8_r8 0x88
+#define MOVAPS_x_xm 0x28
+#define MOVAPS_xm_x 0x29
+#define MOVD_x_rm 0x6e
+#define MOVD_rm_x 0x7e
+#define MOVDDUP_x_xm 0x12
+#define MOVDQA_x_xm 0x6f
+#define MOVDQA_xm_x 0x7f
+#define MOVHLPS_x_x 0x12
+#define MOVHPD_m_x 0x17
+#define MOVHPD_x_m 0x16
+#define MOVLHPS_x_x 0x16
+#define MOVLPD_m_x 0x13
+#define MOVLPD_x_m 0x12
+#define MOVMSKPS_r_x (/* GROUP_0F */ 0x50)
+#define MOVQ_x_xm (/* GROUP_0F */ 0x7e)
+#define MOVSD_x_xm 0x10
+#define MOVSD_xm_x 0x11
+#define MOVSHDUP_x_xm 0x16
+#define MOVSXD_r_rm 0x63
+#define MOVSX_r_rm8 (/* GROUP_0F */ 0xbe)
+#define MOVSX_r_rm16 (/* GROUP_0F */ 0xbf)
+#define MOVUPS_x_xm 0x10
+#define MOVZX_r_rm8 (/* GROUP_0F */ 0xb6)
+#define MOVZX_r_rm16 (/* GROUP_0F */ 0xb7)
+#define MUL (/* GROUP_F7 */ 4 << 3)
+#define MULSD_x_xm 0x59
+#define NEG_rm (/* GROUP_F7 */ 3 << 3)
+#define NOP 0x90
+#define NOT_rm (/* GROUP_F7 */ 2 << 3)
+#define OR (/* BINARY */ 1 << 3)
+#define OR_r_rm 0x0b
+#define OR_EAX_i32 0x0d
+#define OR_rm_r 0x09
+#define OR_rm8_r8 0x08
+#define ORPD_x_xm 0x56
+#define PACKSSWB_x_xm (/* GROUP_0F */ 0x63)
+#define PAND_x_xm 0xdb
+#define PCMPEQD_x_xm 0x76
+#define PINSRB_x_rm_i8 0x20
+#define PINSRW_x_rm_i8 0xc4
+#define PINSRD_x_rm_i8 0x22
+#define PEXTRB_rm_x_i8 0x14
+#define PEXTRW_rm_x_i8 0x15
+#define PEXTRD_rm_x_i8 0x16
+#define PMOVMSKB_r_x (/* GROUP_0F */ 0xd7)
+#define PMOVSXBD_x_xm 0x21
+#define PMOVSXBQ_x_xm 0x22
+#define PMOVSXBW_x_xm 0x20
+#define PMOVSXDQ_x_xm 0x25
+#define PMOVSXWD_x_xm 0x23
+#define PMOVSXWQ_x_xm 0x24
+#define PMOVZXBD_x_xm 0x31
+#define PMOVZXBQ_x_xm 0x32
+#define PMOVZXBW_x_xm 0x30
+#define PMOVZXDQ_x_xm 0x35
+#define PMOVZXWD_x_xm 0x33
+#define PMOVZXWQ_x_xm 0x34
+#define POP_r 0x58
+#define POP_rm 0x8f
+#define POPF 0x9d
+#define POR_x_xm 0xeb
+#define PREFETCH 0x18
+#define PSHUFB_x_xm 0x00
+#define PSHUFD_x_xm 0x70
+#define PSHUFLW_x_xm 0x70
+#define PSRLDQ_x 0x73
+#define PSLLD_x_i8 0x72
+#define PSLLQ_x_i8 0x73
+#define PUSH_i32 0x68
+#define PUSH_r 0x50
+#define PUSH_rm (/* GROUP_FF */ 6 << 3)
+#define PUSHF 0x9c
+#define PXOR_x_xm 0xef
+#define ROL (/* SHIFT */ 0 << 3)
+#define ROR (/* SHIFT */ 1 << 3)
+#define RET_near 0xc3
+#define RET_i16 0xc2
+#define SBB (/* BINARY */ 3 << 3)
+#define SBB_EAX_i32 0x1d
+#define SBB_r_rm 0x1b
+#define SBB_rm_r 0x19
+#define SAR (/* SHIFT */ 7 << 3)
+#define SHL (/* SHIFT */ 4 << 3)
+#define SHLD (/* GROUP_0F */ 0xa5)
+#define SHRD (/* GROUP_0F */ 0xad)
+#define SHR (/* SHIFT */ 5 << 3)
+#define SHUFPS_x_xm 0xc6
+#define SUB (/* BINARY */ 5 << 3)
+#define SUB_EAX_i32 0x2d
+#define SUB_r_rm 0x2b
+#define SUB_rm_r 0x29
+#define SUBSD_x_xm 0x5c
+#define TEST_EAX_i32 0xa9
+#define TEST_rm_r 0x85
+#define TZCNT_r_rm (/* GROUP_F3 */ /* GROUP_0F */ 0xbc)
+#define UCOMISD_x_xm 0x2e
+#define UNPCKLPD_x_xm 0x14
+#define UNPCKLPS_x_xm 0x14
+#define VBROADCASTSD_x_xm 0x19
+#define VBROADCASTSS_x_xm 0x18
+#define VEXTRACTF128_x_ym 0x19
+#define VEXTRACTI128_x_ym 0x39
+#define VINSERTF128_y_y_xm 0x18
+#define VINSERTI128_y_y_xm 0x38
+#define VPBROADCASTB_x_xm 0x78
+#define VPBROADCASTD_x_xm 0x58
+#define VPBROADCASTQ_x_xm 0x59
+#define VPBROADCASTW_x_xm 0x79
+#define VPERMPD_y_ym 0x01
+#define VPERMQ_y_ym 0x00
+#define XCHG_EAX_r 0x90
+#define XCHG_r_rm 0x87
+#define XOR (/* BINARY */ 6 << 3)
+#define XOR_EAX_i32 0x35
+#define XOR_r_rm 0x33
+#define XOR_rm_r 0x31
+#define XORPD_x_xm 0x57
+
+#define GROUP_0F 0x0f
+#define GROUP_66 0x66
+#define GROUP_F3 0xf3
+#define GROUP_F7 0xf7
+#define GROUP_FF 0xff
+#define GROUP_BINARY_81 0x81
+#define GROUP_BINARY_83 0x83
+#define GROUP_SHIFT_1 0xd1
+#define GROUP_SHIFT_N 0xc1
+#define GROUP_SHIFT_CL 0xd3
+#define GROUP_LOCK 0xf0
+
+#define MOD_REG 0xc0
+#define MOD_DISP8 0x40
+
+#define INC_SIZE(s) (*inst++ = U8(s), compiler->size += (s))
+
+#define PUSH_REG(r) (*inst++ = U8(PUSH_r + (r)))
+#define POP_REG(r) (*inst++ = U8(POP_r + (r)))
+#define RET() (*inst++ = RET_near)
+#define RET_I16(n) (*inst++ = RET_i16, *inst++ = U8(n), *inst++ = 0)
/* Multithreading does not affect these static variables, since they store
built-in CPU features. Therefore they can be overwritten by different threads
@@ -297,9 +386,12 @@ static const sljit_u8 freg_lmap[SLJIT_NUMBER_OF_FLOAT_REGISTERS + 1] = {
#if (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2)
#define CPU_FEATURE_SSE2 0x002
#endif
-#define CPU_FEATURE_LZCNT 0x004
-#define CPU_FEATURE_TZCNT 0x008
-#define CPU_FEATURE_CMOV 0x010
+#define CPU_FEATURE_SSE41 0x004
+#define CPU_FEATURE_LZCNT 0x008
+#define CPU_FEATURE_TZCNT 0x010
+#define CPU_FEATURE_CMOV 0x020
+#define CPU_FEATURE_AVX 0x040
+#define CPU_FEATURE_AVX2 0x080
static sljit_u32 cpu_feature_list = 0;
@@ -332,124 +424,124 @@ static SLJIT_INLINE void sljit_unaligned_store_sw(void *addr, sljit_sw value)
/* Utility functions */
/******************************************************/
-static void get_cpu_features(void)
+static void execute_cpu_id(sljit_u32 info[4])
{
- sljit_u32 feature_list = CPU_FEATURE_DETECTED;
- sljit_u32 value;
-
#if defined(_MSC_VER) && _MSC_VER >= 1400
- int CPUInfo[4];
-
- __cpuid(CPUInfo, 0);
- if (CPUInfo[0] >= 7) {
- __cpuidex(CPUInfo, 7, 0);
- if (CPUInfo[1] & 0x8)
- feature_list |= CPU_FEATURE_TZCNT;
- }
-
- __cpuid(CPUInfo, (int)0x80000001);
- if (CPUInfo[2] & 0x20)
- feature_list |= CPU_FEATURE_LZCNT;
-
- __cpuid(CPUInfo, 1);
- value = (sljit_u32)CPUInfo[3];
+ __cpuidex((int*)info, (int)info[0], (int)info[2]);
-#elif defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_C)
+#elif defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_C) || defined(__TINYC__)
/* AT&T syntax. */
__asm__ (
- "movl $0x0, %%eax\n"
- "lzcnt %%eax, %%eax\n"
- "setnz %%al\n"
- "movl %%eax, %0\n"
- : "=g" (value)
- :
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- : "eax"
-#else
- : "rax"
-#endif
- );
-
- if (value & 0x1)
- feature_list |= CPU_FEATURE_LZCNT;
-
- __asm__ (
- "movl $0x0, %%eax\n"
- "tzcnt %%eax, %%eax\n"
- "setnz %%al\n"
- "movl %%eax, %0\n"
- : "=g" (value)
- :
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- : "eax"
-#else
- : "rax"
-#endif
- );
-
- if (value & 0x1)
- feature_list |= CPU_FEATURE_TZCNT;
-
- __asm__ (
- "movl $0x1, %%eax\n"
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- /* On x86-32, there is no red zone, so this
- should work (no need for a local variable). */
- "push %%ebx\n"
-#endif
+ "movl %0, %%esi\n"
+ "movl (%%esi), %%eax\n"
+ "movl 8(%%esi), %%ecx\n"
+ "pushl %%ebx\n"
"cpuid\n"
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- "pop %%ebx\n"
-#endif
- "movl %%edx, %0\n"
- : "=g" (value)
+ "movl %%eax, (%%esi)\n"
+ "movl %%ebx, 4(%%esi)\n"
+ "popl %%ebx\n"
+ "movl %%ecx, 8(%%esi)\n"
+ "movl %%edx, 12(%%esi)\n"
+#else /* !SLJIT_CONFIG_X86_32 */
+ "movq %0, %%rsi\n"
+ "movl (%%rsi), %%eax\n"
+ "movl 8(%%rsi), %%ecx\n"
+ "cpuid\n"
+ "movl %%eax, (%%rsi)\n"
+ "movl %%ebx, 4(%%rsi)\n"
+ "movl %%ecx, 8(%%rsi)\n"
+ "movl %%edx, 12(%%rsi)\n"
+#endif /* SLJIT_CONFIG_X86_32 */
:
+ : "r" (info)
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- : "%eax", "%ecx", "%edx"
-#else
- : "%rax", "%rbx", "%rcx", "%rdx"
-#endif
+ : "memory", "eax", "ecx", "edx", "esi"
+#else /* !SLJIT_CONFIG_X86_32 */
+ : "memory", "rax", "rbx", "rcx", "rdx", "rsi"
+#endif /* SLJIT_CONFIG_X86_32 */
);
-#else /* _MSC_VER && _MSC_VER >= 1400 */
+#else /* _MSC_VER < 1400 */
/* Intel syntax. */
__asm {
- mov eax, 0
- lzcnt eax, eax
- setnz al
- mov value, eax
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ mov esi, info
+ mov eax, [esi]
+ mov ecx, [esi + 8]
+ cpuid
+ mov [esi], eax
+ mov [esi + 4], ebx
+ mov [esi + 8], ecx
+ mov [esi + 12], edx
+#else /* !SLJIT_CONFIG_X86_32 */
+ mov rsi, info
+ mov eax, [rsi]
+ mov ecx, [rsi + 8]
+ cpuid
+ mov [rsi], eax
+ mov [rsi + 4], ebx
+ mov [rsi + 8], ecx
+ mov [rsi + 12], edx
+#endif /* SLJIT_CONFIG_X86_32 */
}
- if (value & 0x1)
- feature_list |= CPU_FEATURE_LZCNT;
+#endif /* _MSC_VER && _MSC_VER >= 1400 */
- __asm {
- mov eax, 0
- tzcnt eax, eax
- setnz al
- mov value, eax
- }
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+__msan_unpoison(info, 4 * sizeof(sljit_u32));
+#endif /* __has_feature(memory_sanitizer) */
+#endif /* defined(__has_feature) */
- if (value & 0x1)
- feature_list |= CPU_FEATURE_TZCNT;
+}
- __asm {
- mov eax, 1
- cpuid
- mov value, edx
+static void get_cpu_features(void)
+{
+ sljit_u32 feature_list = CPU_FEATURE_DETECTED;
+ sljit_u32 info[4];
+ sljit_u32 max_id;
+
+ info[0] = 0;
+ execute_cpu_id(info);
+ max_id = info[0];
+
+ if (max_id >= 7) {
+ info[0] = 7;
+ info[2] = 0;
+ execute_cpu_id(info);
+
+ if (info[1] & 0x8)
+ feature_list |= CPU_FEATURE_TZCNT;
+ if (info[1] & 0x20)
+ feature_list |= CPU_FEATURE_AVX2;
}
-#endif /* _MSC_VER && _MSC_VER >= 1400 */
+ if (max_id >= 1) {
+ info[0] = 1;
+ execute_cpu_id(info);
+ if (info[2] & 0x80000)
+ feature_list |= CPU_FEATURE_SSE41;
+ if (info[2] & 0x10000000)
+ feature_list |= CPU_FEATURE_AVX;
#if (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2)
- if (value & 0x4000000)
- feature_list |= CPU_FEATURE_SSE2;
+ if (info[3] & 0x4000000)
+ feature_list |= CPU_FEATURE_SSE2;
#endif
- if (value & 0x8000)
- feature_list |= CPU_FEATURE_CMOV;
+ if (info[3] & 0x8000)
+ feature_list |= CPU_FEATURE_CMOV;
+ }
+
+ info[0] = 0x80000001;
+ info[2] = 0; /* Silences an incorrect compiler warning. */
+ execute_cpu_id(info);
+
+ if (info[2] & 0x20)
+ feature_list |= CPU_FEATURE_LZCNT;
cpu_feature_list = feature_list;
}
@@ -458,15 +550,15 @@ static sljit_u8 get_jump_code(sljit_uw type)
{
switch (type) {
case SLJIT_EQUAL:
+ case SLJIT_ATOMIC_STORED:
case SLJIT_F_EQUAL:
case SLJIT_UNORDERED_OR_EQUAL:
- case SLJIT_ORDERED_EQUAL: /* Not supported. */
return 0x84 /* je */;
case SLJIT_NOT_EQUAL:
+ case SLJIT_ATOMIC_NOT_STORED:
case SLJIT_F_NOT_EQUAL:
case SLJIT_ORDERED_NOT_EQUAL:
- case SLJIT_UNORDERED_OR_NOT_EQUAL: /* Not supported. */
return 0x85 /* jne */;
case SLJIT_LESS:
@@ -514,9 +606,11 @@ static sljit_u8 get_jump_code(sljit_uw type)
return 0x81 /* jno */;
case SLJIT_UNORDERED:
+ case SLJIT_ORDERED_EQUAL: /* NaN. */
return 0x8a /* jp */;
case SLJIT_ORDERED:
+ case SLJIT_UNORDERED_OR_NOT_EQUAL: /* Not NaN. */
return 0x8b /* jpo */;
}
return 0;
@@ -541,7 +635,7 @@ static sljit_u8* generate_near_jump_code(struct sljit_jump *jump, sljit_u8 *code
label_addr = jump->u.target - (sljit_uw)executable_offset;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- if ((sljit_sw)(label_addr - (jump->addr + 1)) > HALFWORD_MAX || (sljit_sw)(label_addr - (jump->addr + 1)) < HALFWORD_MIN)
+ if ((sljit_sw)(label_addr - (jump->addr + 2)) > HALFWORD_MAX || (sljit_sw)(label_addr - (jump->addr + 6)) < HALFWORD_MIN)
return generate_far_jump_code(jump, code_ptr);
#endif
@@ -737,7 +831,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
switch (feature_type) {
case SLJIT_HAS_FPU:
#ifdef SLJIT_IS_FPU_AVAILABLE
- return SLJIT_IS_FPU_AVAILABLE;
+ return (SLJIT_IS_FPU_AVAILABLE) != 0;
#elif (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2)
if (cpu_feature_list == 0)
get_cpu_features();
@@ -768,19 +862,28 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
get_cpu_features();
return (cpu_feature_list & CPU_FEATURE_CMOV) != 0;
+ case SLJIT_HAS_REV:
case SLJIT_HAS_ROT:
case SLJIT_HAS_PREFETCH:
+ case SLJIT_HAS_COPY_F32:
+ case SLJIT_HAS_COPY_F64:
+ case SLJIT_HAS_ATOMIC:
return 1;
- case SLJIT_HAS_SSE2:
-#if (defined SLJIT_DETECT_SSE2 && SLJIT_DETECT_SSE2)
+#if !(defined SLJIT_IS_FPU_AVAILABLE) || SLJIT_IS_FPU_AVAILABLE
+ case SLJIT_HAS_AVX:
if (cpu_feature_list == 0)
get_cpu_features();
- return (cpu_feature_list & CPU_FEATURE_SSE2) != 0;
-#else /* !SLJIT_DETECT_SSE2 */
- return 1;
-#endif /* SLJIT_DETECT_SSE2 */
-
+ return (cpu_feature_list & CPU_FEATURE_AVX) != 0;
+ case SLJIT_HAS_AVX2:
+ if (cpu_feature_list == 0)
+ get_cpu_features();
+ return (cpu_feature_list & CPU_FEATURE_AVX2) != 0;
+ case SLJIT_HAS_SIMD:
+ if (cpu_feature_list == 0)
+ get_cpu_features();
+ return (cpu_feature_list & CPU_FEATURE_SSE41) != 0;
+#endif /* SLJIT_IS_FPU_AVAILABLE */
default:
return 0;
}
@@ -788,16 +891,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_has_cpu_feature(sljit_s32 feature_type)
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type)
{
- if (type < SLJIT_UNORDERED || type > SLJIT_ORDERED_LESS_EQUAL)
- return 0;
-
switch (type) {
case SLJIT_ORDERED_EQUAL:
case SLJIT_UNORDERED_OR_NOT_EQUAL:
- return 0;
+ return 2;
}
- return 1;
+ return 0;
}
/* --------------------------------------------------------------------- */
@@ -841,6 +941,15 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_cmp_info(sljit_s32 type)
#endif /* SLJIT_CONFIG_X86_64 */
+static sljit_s32 emit_byte(struct sljit_compiler *compiler, sljit_u8 byte)
+{
+ sljit_u8 *inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
+ FAIL_IF(!inst);
+ INC_SIZE(1);
+ *inst = byte;
+ return SLJIT_SUCCESS;
+}
+
static sljit_s32 emit_mov(struct sljit_compiler *compiler,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 src, sljit_sw srcw);
@@ -848,6 +957,14 @@ static sljit_s32 emit_mov(struct sljit_compiler *compiler,
#define EMIT_MOV(compiler, dst, dstw, src, srcw) \
FAIL_IF(emit_mov(compiler, dst, dstw, src, srcw));
+static sljit_s32 emit_groupf(struct sljit_compiler *compiler,
+ sljit_uw op,
+ sljit_s32 dst, sljit_s32 src, sljit_sw srcw);
+
+static sljit_s32 emit_groupf_ext(struct sljit_compiler *compiler,
+ sljit_uw op,
+ sljit_s32 dst, sljit_s32 src, sljit_sw srcw);
+
static SLJIT_INLINE sljit_s32 emit_sse2_store(struct sljit_compiler *compiler,
sljit_s32 single, sljit_s32 dst, sljit_sw dstw, sljit_s32 src);
@@ -858,6 +975,10 @@ static sljit_s32 emit_cmp_binary(struct sljit_compiler *compiler,
sljit_s32 src1, sljit_sw src1w,
sljit_s32 src2, sljit_sw src2w);
+static sljit_s32 emit_cmov_generic(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_reg,
+ sljit_s32 src, sljit_sw srcw);
+
static SLJIT_INLINE sljit_s32 emit_endbranch(struct sljit_compiler *compiler)
{
#if (defined SLJIT_CONFIG_X86_CET && SLJIT_CONFIG_X86_CET)
@@ -866,14 +987,14 @@ static SLJIT_INLINE sljit_s32 emit_endbranch(struct sljit_compiler *compiler)
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
FAIL_IF(!inst);
INC_SIZE(4);
- *inst++ = 0xf3;
- *inst++ = 0x0f;
- *inst++ = 0x1e;
+ inst[0] = GROUP_F3;
+ inst[1] = GROUP_0F;
+ inst[2] = 0x1e;
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- *inst = 0xfb;
-#else
- *inst = 0xfa;
-#endif
+ inst[3] = 0xfb;
+#else /* !SLJIT_CONFIG_X86_32 */
+ inst[3] = 0xfa;
+#endif /* SLJIT_CONFIG_X86_32 */
#else /* !SLJIT_CONFIG_X86_CET */
SLJIT_UNUSED_ARG(compiler);
#endif /* SLJIT_CONFIG_X86_CET */
@@ -896,13 +1017,17 @@ static SLJIT_INLINE sljit_s32 emit_rdssp(struct sljit_compiler *compiler, sljit_
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
- *inst++ = 0xf3;
+ *inst++ = GROUP_F3;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
*inst++ = REX_W | (reg_map[reg] <= 7 ? 0 : REX_B);
#endif
- *inst++ = 0x0f;
- *inst++ = 0x1e;
- *inst = (0x3 << 6) | (0x1 << 3) | (reg_map[reg] & 0x7);
+ inst[0] = GROUP_0F;
+ inst[1] = 0x1e;
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ inst[2] = U8(MOD_REG | (0x1 << 3) | reg_lmap[reg]);
+#else
+ inst[2] = U8(MOD_REG | (0x1 << 3) | reg_map[reg]);
+#endif
return SLJIT_SUCCESS;
}
@@ -920,13 +1045,13 @@ static SLJIT_INLINE sljit_s32 emit_incssp(struct sljit_compiler *compiler, sljit
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
- *inst++ = 0xf3;
+ *inst++ = GROUP_F3;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
*inst++ = REX_W | (reg_map[reg] <= 7 ? 0 : REX_B);
#endif
- *inst++ = 0x0f;
- *inst++ = 0xae;
- *inst = (0x3 << 6) | (0x5 << 3) | (reg_map[reg] & 0x7);
+ inst[0] = GROUP_0F;
+ inst[1] = 0xae;
+ inst[2] = (0x3 << 6) | (0x5 << 3) | (reg_map[reg] & 0x7);
return SLJIT_SUCCESS;
}
@@ -954,19 +1079,7 @@ static SLJIT_INLINE sljit_s32 adjust_shadow_stack(struct sljit_compiler *compile
FAIL_IF(emit_rdssp(compiler, TMP_REG1));
/* Load return address on shadow stack into TMP_REG1. */
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- SLJIT_ASSERT(reg_map[TMP_REG1] == 5);
-
- /* Hand code unsupported "mov 0x0(%ebp),%ebp". */
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 3);
- FAIL_IF(!inst);
- INC_SIZE(3);
- *inst++ = 0x8b;
- *inst++ = 0x6d;
- *inst = 0;
-#else /* !SLJIT_CONFIG_X86_32 */
EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_MEM1(TMP_REG1), 0);
-#endif /* SLJIT_CONFIG_X86_32 */
/* Compare return address against TMP_REG1. */
FAIL_IF(emit_cmp_binary (compiler, TMP_REG1, 0, src, srcw));
@@ -994,8 +1107,8 @@ static SLJIT_INLINE sljit_s32 adjust_shadow_stack(struct sljit_compiler *compile
inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
FAIL_IF(!inst);
INC_SIZE(2);
- *inst++ = JMP_i8;
- *inst = size_before_rdssp_inst - compiler->size;
+ inst[0] = JMP_i8;
+ inst[1] = size_before_rdssp_inst - compiler->size;
*jz_after_cmp_inst = compiler->size - size_jz_after_cmp_inst;
#else /* !SLJIT_CONFIG_X86_CET || !__SHSTK__ */
@@ -1024,7 +1137,8 @@ static sljit_s32 emit_mov(struct sljit_compiler *compiler,
*inst = MOV_rm_r;
return SLJIT_SUCCESS;
}
- if (src & SLJIT_IMM) {
+
+ if (src == SLJIT_IMM) {
if (FAST_IS_REG(dst)) {
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
return emit_do_imm(compiler, MOV_r_i32 | reg_map[dst], srcw);
@@ -1071,6 +1185,27 @@ static sljit_s32 emit_mov(struct sljit_compiler *compiler,
return SLJIT_SUCCESS;
}
+static sljit_s32 emit_cmov_generic(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_reg,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_u8* inst;
+ sljit_uw size;
+
+ SLJIT_ASSERT(type >= SLJIT_EQUAL && type <= SLJIT_ORDERED_LESS_EQUAL);
+
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+ FAIL_IF(!inst);
+ INC_SIZE(2);
+ inst[0] = U8(get_jump_code((sljit_uw)type ^ 0x1) - 0x10);
+
+ size = compiler->size;
+ EMIT_MOV(compiler, dst_reg, 0, src, srcw);
+
+ inst[1] = U8(compiler->size - size);
+ return SLJIT_SUCCESS;
+}
+
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compiler, sljit_s32 op)
{
sljit_u8 *inst;
@@ -1083,17 +1218,9 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compile
switch (GET_OPCODE(op)) {
case SLJIT_BREAKPOINT:
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
- FAIL_IF(!inst);
- INC_SIZE(1);
- *inst = INT3;
- break;
+ return emit_byte(compiler, INT3);
case SLJIT_NOP:
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
- FAIL_IF(!inst);
- INC_SIZE(1);
- *inst = NOP;
- break;
+ return emit_byte(compiler, NOP);
case SLJIT_LMUL_UW:
case SLJIT_LMUL_SW:
case SLJIT_DIVMOD_UW:
@@ -1134,23 +1261,16 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compile
#endif
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
- FAIL_IF(!inst);
- INC_SIZE(1);
- *inst = CDQ;
+ FAIL_IF(emit_byte(compiler, CDQ));
#else
- if (compiler->mode32) {
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
- FAIL_IF(!inst);
- INC_SIZE(1);
- *inst = CDQ;
- } else {
+ if (!compiler->mode32) {
inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
FAIL_IF(!inst);
INC_SIZE(2);
- *inst++ = REX_W;
- *inst = CDQ;
- }
+ inst[0] = REX_W;
+ inst[1] = CDQ;
+ } else
+ FAIL_IF(emit_byte(compiler, CDQ));
#endif
}
@@ -1158,14 +1278,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compile
inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
FAIL_IF(!inst);
INC_SIZE(2);
- *inst++ = GROUP_F7;
- *inst = MOD_REG | ((op >= SLJIT_DIVMOD_UW) ? reg_map[TMP_REG1] : reg_map[SLJIT_R1]);
-#else
+ inst[0] = GROUP_F7;
+ inst[1] = MOD_REG | ((op >= SLJIT_DIVMOD_UW) ? reg_map[TMP_REG1] : reg_map[SLJIT_R1]);
+#else /* !SLJIT_CONFIG_X86_32 */
#ifdef _WIN64
size = (!compiler->mode32 || op >= SLJIT_DIVMOD_UW) ? 3 : 2;
-#else
+#else /* !_WIN64 */
size = (!compiler->mode32) ? 3 : 2;
-#endif
+#endif /* _WIN64 */
inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
@@ -1174,29 +1294,29 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compile
*inst++ = REX_W | ((op >= SLJIT_DIVMOD_UW) ? REX_B : 0);
else if (op >= SLJIT_DIVMOD_UW)
*inst++ = REX_B;
- *inst++ = GROUP_F7;
- *inst = MOD_REG | ((op >= SLJIT_DIVMOD_UW) ? reg_lmap[TMP_REG1] : reg_lmap[SLJIT_R1]);
-#else
+ inst[0] = GROUP_F7;
+ inst[1] = MOD_REG | ((op >= SLJIT_DIVMOD_UW) ? reg_lmap[TMP_REG1] : reg_lmap[SLJIT_R1]);
+#else /* !_WIN64 */
if (!compiler->mode32)
*inst++ = REX_W;
- *inst++ = GROUP_F7;
- *inst = MOD_REG | reg_map[SLJIT_R1];
-#endif
-#endif
+ inst[0] = GROUP_F7;
+ inst[1] = MOD_REG | reg_map[SLJIT_R1];
+#endif /* _WIN64 */
+#endif /* SLJIT_CONFIG_X86_32 */
switch (op) {
case SLJIT_LMUL_UW:
- *inst |= MUL;
+ inst[1] |= MUL;
break;
case SLJIT_LMUL_SW:
- *inst |= IMUL;
+ inst[1] |= IMUL;
break;
case SLJIT_DIVMOD_UW:
case SLJIT_DIV_UW:
- *inst |= DIV;
+ inst[1] |= DIV;
break;
case SLJIT_DIVMOD_SW:
case SLJIT_DIV_SW:
- *inst |= IDIV;
+ inst[1] |= IDIV;
break;
}
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && !defined(_WIN64)
@@ -1216,29 +1336,18 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op0(struct sljit_compiler *compile
return SLJIT_SUCCESS;
}
-#define ENCODE_PREFIX(prefix) \
- do { \
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 1); \
- FAIL_IF(!inst); \
- INC_SIZE(1); \
- *inst = U8(prefix); \
- } while (0)
-
static sljit_s32 emit_mov_byte(struct sljit_compiler *compiler, sljit_s32 sign,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 src, sljit_sw srcw)
{
sljit_u8* inst;
sljit_s32 dst_r;
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- sljit_s32 work_r;
-#endif
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
compiler->mode32 = 0;
#endif
- if (src & SLJIT_IMM) {
+ if (src == SLJIT_IMM) {
if (FAST_IS_REG(dst)) {
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
return emit_do_imm(compiler, MOV_r_i32 | reg_map[dst], srcw);
@@ -1267,100 +1376,33 @@ static sljit_s32 emit_mov_byte(struct sljit_compiler *compiler, sljit_s32 sign,
#else
dst_r = src;
#endif
- }
+ } else {
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- else if (FAST_IS_REG(src) && reg_map[src] >= 4) {
- /* src, dst are registers. */
- SLJIT_ASSERT(FAST_IS_REG(dst));
- if (reg_map[dst] < 4) {
- if (dst != src)
- EMIT_MOV(compiler, dst, 0, src, 0);
- inst = emit_x86_instruction(compiler, 2, dst, 0, dst, 0);
- FAIL_IF(!inst);
- *inst++ = GROUP_0F;
- *inst = sign ? MOVSX_r_rm8 : MOVZX_r_rm8;
- }
- else {
- if (dst != src)
- EMIT_MOV(compiler, dst, 0, src, 0);
- if (sign) {
- /* shl reg, 24 */
- inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 24, dst, 0);
- FAIL_IF(!inst);
- *inst |= SHL;
- /* sar reg, 24 */
- inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 24, dst, 0);
- FAIL_IF(!inst);
- *inst |= SAR;
- }
- else {
+ if (FAST_IS_REG(src) && reg_map[src] >= 4) {
+ /* Both src and dst are registers. */
+ SLJIT_ASSERT(FAST_IS_REG(dst));
+
+ if (src == dst && !sign) {
inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, 0xff, dst, 0);
FAIL_IF(!inst);
*(inst + 1) |= AND;
+ return SLJIT_SUCCESS;
}
+
+ EMIT_MOV(compiler, TMP_REG1, 0, src, 0);
+ src = TMP_REG1;
+ srcw = 0;
}
- return SLJIT_SUCCESS;
- }
-#endif
- else {
+#endif /* !SLJIT_CONFIG_X86_32 */
+
/* src can be memory addr or reg_map[src] < 4 on x86_32 architectures. */
- inst = emit_x86_instruction(compiler, 2, dst_r, 0, src, srcw);
- FAIL_IF(!inst);
- *inst++ = GROUP_0F;
- *inst = sign ? MOVSX_r_rm8 : MOVZX_r_rm8;
+ FAIL_IF(emit_groupf(compiler, sign ? MOVSX_r_rm8 : MOVZX_r_rm8, dst_r, src, srcw));
}
if (dst & SLJIT_MEM) {
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- if (dst_r == TMP_REG1) {
- /* Find a non-used register, whose reg_map[src] < 4. */
- if ((dst & REG_MASK) == SLJIT_R0) {
- if ((dst & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_R1))
- work_r = SLJIT_R2;
- else
- work_r = SLJIT_R1;
- }
- else {
- if ((dst & OFFS_REG_MASK) != TO_OFFS_REG(SLJIT_R0))
- work_r = SLJIT_R0;
- else if ((dst & REG_MASK) == SLJIT_R1)
- work_r = SLJIT_R2;
- else
- work_r = SLJIT_R1;
- }
-
- if (work_r == SLJIT_R0) {
- ENCODE_PREFIX(XCHG_EAX_r | reg_map[TMP_REG1]);
- }
- else {
- inst = emit_x86_instruction(compiler, 1, work_r, 0, dst_r, 0);
- FAIL_IF(!inst);
- *inst = XCHG_r_rm;
- }
-
- inst = emit_x86_instruction(compiler, 1, work_r, 0, dst, dstw);
- FAIL_IF(!inst);
- *inst = MOV_rm8_r8;
-
- if (work_r == SLJIT_R0) {
- ENCODE_PREFIX(XCHG_EAX_r | reg_map[TMP_REG1]);
- }
- else {
- inst = emit_x86_instruction(compiler, 1, work_r, 0, dst_r, 0);
- FAIL_IF(!inst);
- *inst = XCHG_r_rm;
- }
- }
- else {
- inst = emit_x86_instruction(compiler, 1, dst_r, 0, dst, dstw);
- FAIL_IF(!inst);
- *inst = MOV_rm8_r8;
- }
-#else
inst = emit_x86_instruction(compiler, 1 | EX86_REX | EX86_NO_REXW, dst_r, 0, dst, dstw);
FAIL_IF(!inst);
*inst = MOV_rm8_r8;
-#endif
}
return SLJIT_SUCCESS;
@@ -1377,15 +1419,15 @@ static sljit_s32 emit_prefetch(struct sljit_compiler *compiler, sljit_s32 op,
inst = emit_x86_instruction(compiler, 2, 0, 0, src, srcw);
FAIL_IF(!inst);
- *inst++ = GROUP_0F;
- *inst++ = PREFETCH;
+ inst[0] = GROUP_0F;
+ inst[1] = PREFETCH;
if (op == SLJIT_PREFETCH_L1)
- *inst |= (1 << 3);
+ inst[2] |= (1 << 3);
else if (op == SLJIT_PREFETCH_L2)
- *inst |= (2 << 3);
+ inst[2] |= (2 << 3);
else if (op == SLJIT_PREFETCH_L3)
- *inst |= (3 << 3);
+ inst[2] |= (3 << 3);
return SLJIT_SUCCESS;
}
@@ -1401,7 +1443,7 @@ static sljit_s32 emit_mov_half(struct sljit_compiler *compiler, sljit_s32 sign,
compiler->mode32 = 0;
#endif
- if (src & SLJIT_IMM) {
+ if (src == SLJIT_IMM) {
if (FAST_IS_REG(dst)) {
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
return emit_do_imm(compiler, MOV_r_i32 | reg_map[dst], srcw);
@@ -1422,12 +1464,8 @@ static sljit_s32 emit_mov_half(struct sljit_compiler *compiler, sljit_s32 sign,
if ((dst & SLJIT_MEM) && FAST_IS_REG(src))
dst_r = src;
- else {
- inst = emit_x86_instruction(compiler, 2, dst_r, 0, src, srcw);
- FAIL_IF(!inst);
- *inst++ = GROUP_0F;
- *inst = sign ? MOVSX_r_rm16 : MOVZX_r_rm16;
- }
+ else
+ FAIL_IF(emit_groupf(compiler, sign ? MOVSX_r_rm16 : MOVZX_r_rm16, dst_r, src, srcw));
if (dst & SLJIT_MEM) {
inst = emit_x86_instruction(compiler, 1 | EX86_NO_REXW | EX86_PREF_66, dst_r, 0, dst, dstw);
@@ -1448,8 +1486,8 @@ static sljit_s32 emit_unary(struct sljit_compiler *compiler, sljit_u8 opcode,
/* Same input and output */
inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
FAIL_IF(!inst);
- *inst++ = GROUP_F7;
- *inst |= opcode;
+ inst[0] = GROUP_F7;
+ inst[1] |= opcode;
return SLJIT_SUCCESS;
}
@@ -1457,46 +1495,16 @@ static sljit_s32 emit_unary(struct sljit_compiler *compiler, sljit_u8 opcode,
EMIT_MOV(compiler, dst, 0, src, srcw);
inst = emit_x86_instruction(compiler, 1, 0, 0, dst, 0);
FAIL_IF(!inst);
- *inst++ = GROUP_F7;
- *inst |= opcode;
+ inst[0] = GROUP_F7;
+ inst[1] |= opcode;
return SLJIT_SUCCESS;
}
EMIT_MOV(compiler, TMP_REG1, 0, src, srcw);
inst = emit_x86_instruction(compiler, 1, 0, 0, TMP_REG1, 0);
FAIL_IF(!inst);
- *inst++ = GROUP_F7;
- *inst |= opcode;
- EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0);
- return SLJIT_SUCCESS;
-}
-
-static sljit_s32 emit_not_with_flags(struct sljit_compiler *compiler,
- sljit_s32 dst, sljit_sw dstw,
- sljit_s32 src, sljit_sw srcw)
-{
- sljit_u8* inst;
-
- if (FAST_IS_REG(dst)) {
- EMIT_MOV(compiler, dst, 0, src, srcw);
- inst = emit_x86_instruction(compiler, 1, 0, 0, dst, 0);
- FAIL_IF(!inst);
- *inst++ = GROUP_F7;
- *inst |= NOT_rm;
- inst = emit_x86_instruction(compiler, 1, dst, 0, dst, 0);
- FAIL_IF(!inst);
- *inst = OR_r_rm;
- return SLJIT_SUCCESS;
- }
-
- EMIT_MOV(compiler, TMP_REG1, 0, src, srcw);
- inst = emit_x86_instruction(compiler, 1, 0, 0, TMP_REG1, 0);
- FAIL_IF(!inst);
- *inst++ = GROUP_F7;
- *inst |= NOT_rm;
- inst = emit_x86_instruction(compiler, 1, TMP_REG1, 0, TMP_REG1, 0);
- FAIL_IF(!inst);
- *inst = OR_r_rm;
+ inst[0] = GROUP_F7;
+ inst[1] |= opcode;
EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0);
return SLJIT_SUCCESS;
}
@@ -1514,32 +1522,19 @@ static sljit_s32 emit_clz_ctz(struct sljit_compiler *compiler, sljit_s32 is_clz,
sljit_s32 dst_r;
sljit_sw max;
- if (cpu_feature_list == 0)
- get_cpu_features();
+ SLJIT_ASSERT(cpu_feature_list != 0);
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
if (is_clz ? (cpu_feature_list & CPU_FEATURE_LZCNT) : (cpu_feature_list & CPU_FEATURE_TZCNT)) {
- /* Group prefix added separately. */
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
- FAIL_IF(!inst);
- INC_SIZE(1);
- *inst++ = GROUP_F3;
-
- inst = emit_x86_instruction(compiler, 2, dst_r, 0, src, srcw);
- FAIL_IF(!inst);
- *inst++ = GROUP_0F;
- *inst = is_clz ? LZCNT_r_rm : TZCNT_r_rm;
+ FAIL_IF(emit_groupf(compiler, (is_clz ? LZCNT_r_rm : TZCNT_r_rm) | EX86_PREF_F3, dst_r, src, srcw));
if (dst & SLJIT_MEM)
EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0);
return SLJIT_SUCCESS;
}
- inst = emit_x86_instruction(compiler, 2, dst_r, 0, src, srcw);
- FAIL_IF(!inst);
- *inst++ = GROUP_0F;
- *inst = is_clz ? BSR_r_rm : BSF_r_rm;
+ FAIL_IF(emit_groupf(compiler, is_clz ? BSR_r_rm : BSF_r_rm, dst_r, src, srcw));
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
max = is_clz ? (32 + 31) : 32;
@@ -1553,11 +1548,11 @@ static sljit_s32 emit_clz_ctz(struct sljit_compiler *compiler, sljit_s32 is_clz,
inst = emit_x86_instruction(compiler, 2, dst_r, 0, SLJIT_MEM0(), is_clz ? (sljit_sw)&emit_clz_arg : (sljit_sw)&emit_ctz_arg);
FAIL_IF(!inst);
- *inst++ = GROUP_0F;
- *inst = CMOVE_r_rm;
+ inst[0] = GROUP_0F;
+ inst[1] = CMOVE_r_rm;
}
else
- FAIL_IF(sljit_emit_cmov_generic(compiler, SLJIT_EQUAL, dst_r, SLJIT_IMM, max));
+ FAIL_IF(emit_cmov_generic(compiler, SLJIT_EQUAL, dst_r, SLJIT_IMM, max));
if (is_clz) {
inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, 31, dst_r, 0);
@@ -1572,14 +1567,9 @@ static sljit_s32 emit_clz_ctz(struct sljit_compiler *compiler, sljit_s32 is_clz,
if (cpu_feature_list & CPU_FEATURE_CMOV) {
EMIT_MOV(compiler, TMP_REG2, 0, SLJIT_IMM, max);
-
- inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG2, 0);
- FAIL_IF(!inst);
- *inst++ = GROUP_0F;
- *inst = CMOVE_r_rm;
- }
- else
- FAIL_IF(sljit_emit_cmov_generic(compiler, SLJIT_EQUAL, dst_r, SLJIT_IMM, max));
+ FAIL_IF(emit_groupf(compiler, CMOVE_r_rm, dst_r, TMP_REG2, 0));
+ } else
+ FAIL_IF(emit_cmov_generic(compiler, SLJIT_EQUAL, dst_r, SLJIT_IMM, max));
if (is_clz) {
inst = emit_x86_instruction(compiler, 1 | EX86_BIN_INS, SLJIT_IMM, max >> 1, dst_r, 0);
@@ -1593,14 +1583,109 @@ static sljit_s32 emit_clz_ctz(struct sljit_compiler *compiler, sljit_s32 is_clz,
return SLJIT_SUCCESS;
}
+static sljit_s32 emit_bswap(struct sljit_compiler *compiler,
+ sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_u8 *inst;
+ sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+ sljit_uw size;
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ sljit_u8 rex = 0;
+#else /* !SLJIT_CONFIG_X86_64 */
+ sljit_s32 dst_is_ereg = op & SLJIT_32;
+#endif /* SLJIT_CONFIG_X86_64 */
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ if (op == SLJIT_REV_U32 || op == SLJIT_REV_S32)
+ compiler->mode32 = 1;
+#else /* !SLJIT_CONFIG_X86_64 */
+ op &= ~SLJIT_32;
+#endif /* SLJIT_CONFIG_X86_64 */
+
+ if (src != dst_r) {
+ /* Only the lower 16 bit is read for eregs. */
+ if (op == SLJIT_REV_U16 || op == SLJIT_REV_S16)
+ FAIL_IF(emit_mov_half(compiler, 0, dst_r, 0, src, srcw));
+ else
+ EMIT_MOV(compiler, dst_r, 0, src, srcw);
+ }
+
+ size = 2;
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ if (!compiler->mode32)
+ rex = REX_W;
+
+ if (reg_map[dst_r] >= 8)
+ rex |= REX_B;
+
+ if (rex != 0)
+ size++;
+#endif /* SLJIT_CONFIG_X86_64 */
+
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + size);
+ FAIL_IF(!inst);
+ INC_SIZE(size);
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ if (rex != 0)
+ *inst++ = rex;
+
+ inst[0] = GROUP_0F;
+ inst[1] = BSWAP_r | reg_lmap[dst_r];
+#else /* !SLJIT_CONFIG_X86_64 */
+ inst[0] = GROUP_0F;
+ inst[1] = BSWAP_r | reg_map[dst_r];
+#endif /* SLJIT_CONFIG_X86_64 */
+
+ if (op == SLJIT_REV_U16 || op == SLJIT_REV_S16) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ size = compiler->mode32 ? 16 : 48;
+#else /* !SLJIT_CONFIG_X86_64 */
+ size = 16;
+#endif /* SLJIT_CONFIG_X86_64 */
+
+ inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, (sljit_sw)size, dst_r, 0);
+ FAIL_IF(!inst);
+ if (op == SLJIT_REV_U16)
+ inst[1] |= SHR;
+ else
+ inst[1] |= SAR;
+ }
+
+ if (dst & SLJIT_MEM) {
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ if (dst_is_ereg)
+ op = SLJIT_REV;
+#endif /* SLJIT_CONFIG_X86_32 */
+ if (op == SLJIT_REV_U16 || op == SLJIT_REV_S16)
+ return emit_mov_half(compiler, 0, dst, dstw, TMP_REG1, 0);
+
+ return emit_mov(compiler, dst, dstw, TMP_REG1, 0);
+ }
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ if (op == SLJIT_REV_S32) {
+ compiler->mode32 = 0;
+ inst = emit_x86_instruction(compiler, 1, dst, 0, dst, 0);
+ FAIL_IF(!inst);
+ *inst = MOVSXD_r_rm;
+ }
+#endif /* SLJIT_CONFIG_X86_64 */
+
+ return SLJIT_SUCCESS;
+}
+
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 src, sljit_sw srcw)
{
- sljit_s32 op_flags = GET_ALL_FLAGS(op);
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
sljit_s32 dst_is_ereg = 0;
-#endif
+#else /* !SLJIT_CONFIG_X86_32 */
+ sljit_s32 op_flags = GET_ALL_FLAGS(op);
+#endif /* SLJIT_CONFIG_X86_32 */
CHECK_ERROR();
CHECK(check_sljit_emit_op1(compiler, op, dst, dstw, src, srcw));
@@ -1611,14 +1696,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
CHECK_EXTRA_REGS(src, srcw, (void)0);
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
compiler->mode32 = op_flags & SLJIT_32;
-#endif
+#endif /* SLJIT_CONFIG_X86_64 */
op = GET_OPCODE(op);
if (op >= SLJIT_MOV && op <= SLJIT_MOV_P) {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
compiler->mode32 = 0;
-#endif
+#endif /* SLJIT_CONFIG_X86_64 */
if (FAST_IS_REG(src) && src == dst) {
if (!TYPE_CAST_NEEDED(op))
@@ -1631,14 +1716,14 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
if (op == SLJIT_MOV_S32)
op = SLJIT_MOV_U32;
}
- else if (src & SLJIT_IMM) {
+ else if (src == SLJIT_IMM) {
if (op == SLJIT_MOV_U32)
op = SLJIT_MOV_S32;
}
}
-#endif
+#endif /* SLJIT_CONFIG_X86_64 */
- if (src & SLJIT_IMM) {
+ if (src == SLJIT_IMM) {
switch (op) {
case SLJIT_MOV_U8:
srcw = (sljit_u8)srcw;
@@ -1659,12 +1744,12 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
case SLJIT_MOV_S32:
srcw = (sljit_s32)srcw;
break;
-#endif
+#endif /* SLJIT_CONFIG_X86_64 */
}
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
if (SLJIT_UNLIKELY(dst_is_ereg))
return emit_mov(compiler, dst, dstw, src, srcw);
-#endif
+#endif /* SLJIT_CONFIG_X86_32 */
}
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
@@ -1672,7 +1757,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
SLJIT_ASSERT(dst == SLJIT_MEM1(SLJIT_SP));
dst = TMP_REG1;
}
-#endif
+#endif /* SLJIT_CONFIG_X86_32 */
switch (op) {
case SLJIT_MOV:
@@ -1681,7 +1766,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
case SLJIT_MOV_U32:
case SLJIT_MOV_S32:
case SLJIT_MOV32:
-#endif
+#endif /* SLJIT_CONFIG_X86_32 */
EMIT_MOV(compiler, dst, dstw, src, srcw);
break;
case SLJIT_MOV_U8:
@@ -1708,25 +1793,30 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op1(struct sljit_compiler *compile
EMIT_MOV(compiler, dst, dstw, src, srcw);
compiler->mode32 = 0;
break;
-#endif
+#endif /* SLJIT_CONFIG_X86_64 */
}
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
if (SLJIT_UNLIKELY(dst_is_ereg) && dst == TMP_REG1)
return emit_mov(compiler, SLJIT_MEM1(SLJIT_SP), dstw, TMP_REG1, 0);
-#endif
+#endif /* SLJIT_CONFIG_X86_32 */
return SLJIT_SUCCESS;
}
switch (op) {
- case SLJIT_NOT:
- if (SLJIT_UNLIKELY(op_flags & SLJIT_SET_Z))
- return emit_not_with_flags(compiler, dst, dstw, src, srcw);
- return emit_unary(compiler, NOT_rm, dst, dstw, src, srcw);
-
case SLJIT_CLZ:
case SLJIT_CTZ:
return emit_clz_ctz(compiler, (op == SLJIT_CLZ), dst, dstw, src, srcw);
+ case SLJIT_REV:
+ case SLJIT_REV_U16:
+ case SLJIT_REV_S16:
+ case SLJIT_REV_U32:
+ case SLJIT_REV_S32:
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ if (dst_is_ereg)
+ op |= SLJIT_32;
+#endif /* SLJIT_CONFIG_X86_32 */
+ return emit_bswap(compiler, op, dst, dstw, src, srcw);
}
return SLJIT_SUCCESS;
@@ -1745,7 +1835,7 @@ static sljit_s32 emit_cum_binary(struct sljit_compiler *compiler,
sljit_u8 op_imm = U8(op_types & 0xff);
if (dst == src1 && dstw == src1w) {
- if (src2 & SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if ((dst == SLJIT_R0) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) {
#else
@@ -1779,7 +1869,7 @@ static sljit_s32 emit_cum_binary(struct sljit_compiler *compiler,
/* Only for cumulative operations. */
if (dst == src2 && dstw == src2w) {
- if (src1 & SLJIT_IMM) {
+ if (src1 == SLJIT_IMM) {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if ((dst == SLJIT_R0) && (src1w > 127 || src1w < -128) && (compiler->mode32 || IS_HALFWORD(src1w))) {
#else
@@ -1813,7 +1903,7 @@ static sljit_s32 emit_cum_binary(struct sljit_compiler *compiler,
/* General version. */
if (FAST_IS_REG(dst)) {
EMIT_MOV(compiler, dst, 0, src1, src1w);
- if (src2 & SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
BINARY_IMM(op_imm, op_mr, src2w, dst, 0);
}
else {
@@ -1825,7 +1915,7 @@ static sljit_s32 emit_cum_binary(struct sljit_compiler *compiler,
else {
/* This version requires less memory writing. */
EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
- if (src2 & SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
BINARY_IMM(op_imm, op_mr, src2w, TMP_REG1, 0);
}
else {
@@ -1852,7 +1942,7 @@ static sljit_s32 emit_non_cum_binary(struct sljit_compiler *compiler,
sljit_u8 op_imm = U8(op_types & 0xff);
if (dst == src1 && dstw == src1w) {
- if (src2 & SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if ((dst == SLJIT_R0) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) {
#else
@@ -1886,7 +1976,7 @@ static sljit_s32 emit_non_cum_binary(struct sljit_compiler *compiler,
/* General version. */
if (FAST_IS_REG(dst) && dst != src2) {
EMIT_MOV(compiler, dst, 0, src1, src1w);
- if (src2 & SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
BINARY_IMM(op_imm, op_mr, src2w, dst, 0);
}
else {
@@ -1898,7 +1988,7 @@ static sljit_s32 emit_non_cum_binary(struct sljit_compiler *compiler,
else {
/* This version requires less memory writing. */
EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
- if (src2 & SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
BINARY_IMM(op_imm, op_mr, src2w, TMP_REG1, 0);
}
else {
@@ -1921,20 +2011,12 @@ static sljit_s32 emit_mul(struct sljit_compiler *compiler,
sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
/* Register destination. */
- if (dst_r == src1 && !(src2 & SLJIT_IMM)) {
- inst = emit_x86_instruction(compiler, 2, dst_r, 0, src2, src2w);
- FAIL_IF(!inst);
- *inst++ = GROUP_0F;
- *inst = IMUL_r_rm;
- }
- else if (dst_r == src2 && !(src1 & SLJIT_IMM)) {
- inst = emit_x86_instruction(compiler, 2, dst_r, 0, src1, src1w);
- FAIL_IF(!inst);
- *inst++ = GROUP_0F;
- *inst = IMUL_r_rm;
- }
- else if (src1 & SLJIT_IMM) {
- if (src2 & SLJIT_IMM) {
+ if (dst_r == src1 && src2 != SLJIT_IMM) {
+ FAIL_IF(emit_groupf(compiler, IMUL_r_rm, dst_r, src2, src2w));
+ } else if (dst_r == src2 && src1 != SLJIT_IMM) {
+ FAIL_IF(emit_groupf(compiler, IMUL_r_rm, dst_r, src1, src1w));
+ } else if (src1 == SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
EMIT_MOV(compiler, dst_r, 0, SLJIT_IMM, src2w);
src2 = dst_r;
src2w = 0;
@@ -1944,10 +2026,8 @@ static sljit_s32 emit_mul(struct sljit_compiler *compiler,
inst = emit_x86_instruction(compiler, 1, dst_r, 0, src2, src2w);
FAIL_IF(!inst);
*inst = IMUL_r_rm_i8;
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
- FAIL_IF(!inst);
- INC_SIZE(1);
- *inst = U8(src1w);
+
+ FAIL_IF(emit_byte(compiler, U8(src1w)));
}
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
else {
@@ -1973,30 +2053,26 @@ static sljit_s32 emit_mul(struct sljit_compiler *compiler,
if (dst_r != src2)
EMIT_MOV(compiler, dst_r, 0, src2, src2w);
FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src1w));
- inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG2, 0);
- FAIL_IF(!inst);
- *inst++ = GROUP_0F;
- *inst = IMUL_r_rm;
+ FAIL_IF(emit_groupf(compiler, IMUL_r_rm, dst_r, TMP_REG2, 0));
}
#endif
}
- else if (src2 & SLJIT_IMM) {
+ else if (src2 == SLJIT_IMM) {
/* Note: src1 is NOT immediate. */
if (src2w <= 127 && src2w >= -128) {
inst = emit_x86_instruction(compiler, 1, dst_r, 0, src1, src1w);
FAIL_IF(!inst);
*inst = IMUL_r_rm_i8;
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
- FAIL_IF(!inst);
- INC_SIZE(1);
- *inst = U8(src2w);
+
+ FAIL_IF(emit_byte(compiler, U8(src2w)));
}
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
else {
inst = emit_x86_instruction(compiler, 1, dst_r, 0, src1, src1w);
FAIL_IF(!inst);
*inst = IMUL_r_rm_i32;
+
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
FAIL_IF(!inst);
INC_SIZE(4);
@@ -2007,31 +2083,24 @@ static sljit_s32 emit_mul(struct sljit_compiler *compiler,
inst = emit_x86_instruction(compiler, 1, dst_r, 0, src1, src1w);
FAIL_IF(!inst);
*inst = IMUL_r_rm_i32;
+
inst = (sljit_u8*)ensure_buf(compiler, 1 + 4);
FAIL_IF(!inst);
INC_SIZE(4);
sljit_unaligned_store_s32(inst, (sljit_s32)src2w);
- }
- else {
+ } else {
if (dst_r != src1)
EMIT_MOV(compiler, dst_r, 0, src1, src1w);
FAIL_IF(emit_load_imm64(compiler, TMP_REG2, src2w));
- inst = emit_x86_instruction(compiler, 2, dst_r, 0, TMP_REG2, 0);
- FAIL_IF(!inst);
- *inst++ = GROUP_0F;
- *inst = IMUL_r_rm;
+ FAIL_IF(emit_groupf(compiler, IMUL_r_rm, dst_r, TMP_REG2, 0));
}
#endif
- }
- else {
+ } else {
/* Neither argument is immediate. */
if (ADDRESSING_DEPENDS_ON(src2, dst_r))
dst_r = TMP_REG1;
EMIT_MOV(compiler, dst_r, 0, src1, src1w);
- inst = emit_x86_instruction(compiler, 2, dst_r, 0, src2, src2w);
- FAIL_IF(!inst);
- *inst++ = GROUP_0F;
- *inst = IMUL_r_rm;
+ FAIL_IF(emit_groupf(compiler, IMUL_r_rm, dst_r, src2, src2w));
}
if (dst & SLJIT_MEM)
@@ -2064,10 +2133,10 @@ static sljit_s32 emit_lea_binary(struct sljit_compiler *compiler,
done = 1;
}
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- if ((src2 & SLJIT_IMM) && (compiler->mode32 || IS_HALFWORD(src2w))) {
+ if (src2 == SLJIT_IMM && (compiler->mode32 || IS_HALFWORD(src2w))) {
inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src1), (sljit_s32)src2w);
#else
- if (src2 & SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src1), src2w);
#endif
FAIL_IF(!inst);
@@ -2077,10 +2146,10 @@ static sljit_s32 emit_lea_binary(struct sljit_compiler *compiler,
}
else if (FAST_IS_REG(src2)) {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- if ((src1 & SLJIT_IMM) && (compiler->mode32 || IS_HALFWORD(src1w))) {
+ if (src1 == SLJIT_IMM && (compiler->mode32 || IS_HALFWORD(src1w))) {
inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src2), (sljit_s32)src1w);
#else
- if (src1 & SLJIT_IMM) {
+ if (src1 == SLJIT_IMM) {
inst = emit_x86_instruction(compiler, 1, dst_r, 0, SLJIT_MEM1(src2), src1w);
#endif
FAIL_IF(!inst);
@@ -2104,16 +2173,16 @@ static sljit_s32 emit_cmp_binary(struct sljit_compiler *compiler,
sljit_u8* inst;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- if (src1 == SLJIT_R0 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) {
+ if (src1 == SLJIT_R0 && src2 == SLJIT_IMM && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) {
#else
- if (src1 == SLJIT_R0 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128)) {
+ if (src1 == SLJIT_R0 && src2 == SLJIT_IMM && (src2w > 127 || src2w < -128)) {
#endif
BINARY_EAX_IMM(CMP_EAX_i32, src2w);
return SLJIT_SUCCESS;
}
if (FAST_IS_REG(src1)) {
- if (src2 & SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
BINARY_IMM(CMP, CMP_rm_r, src2w, src1, 0);
}
else {
@@ -2124,15 +2193,15 @@ static sljit_s32 emit_cmp_binary(struct sljit_compiler *compiler,
return SLJIT_SUCCESS;
}
- if (FAST_IS_REG(src2) && !(src1 & SLJIT_IMM)) {
+ if (FAST_IS_REG(src2) && src1 != SLJIT_IMM) {
inst = emit_x86_instruction(compiler, 1, src2, 0, src1, src1w);
FAIL_IF(!inst);
*inst = CMP_rm_r;
return SLJIT_SUCCESS;
}
- if (src2 & SLJIT_IMM) {
- if (src1 & SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
+ if (src1 == SLJIT_IMM) {
EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
src1 = TMP_REG1;
src1w = 0;
@@ -2155,25 +2224,25 @@ static sljit_s32 emit_test_binary(struct sljit_compiler *compiler,
sljit_u8* inst;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- if (src1 == SLJIT_R0 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) {
+ if (src1 == SLJIT_R0 && src2 == SLJIT_IMM && (src2w > 127 || src2w < -128) && (compiler->mode32 || IS_HALFWORD(src2w))) {
#else
- if (src1 == SLJIT_R0 && (src2 & SLJIT_IMM) && (src2w > 127 || src2w < -128)) {
+ if (src1 == SLJIT_R0 && src2 == SLJIT_IMM && (src2w > 127 || src2w < -128)) {
#endif
BINARY_EAX_IMM(TEST_EAX_i32, src2w);
return SLJIT_SUCCESS;
}
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- if (src2 == SLJIT_R0 && (src1 & SLJIT_IMM) && (src1w > 127 || src1w < -128) && (compiler->mode32 || IS_HALFWORD(src1w))) {
+ if (src2 == SLJIT_R0 && src1 == SLJIT_IMM && (src1w > 127 || src1w < -128) && (compiler->mode32 || IS_HALFWORD(src1w))) {
#else
- if (src2 == SLJIT_R0 && (src1 & SLJIT_IMM) && (src1w > 127 || src1w < -128)) {
+ if (src2 == SLJIT_R0 && src1 == SLJIT_IMM && (src1w > 127 || src1w < -128)) {
#endif
BINARY_EAX_IMM(TEST_EAX_i32, src1w);
return SLJIT_SUCCESS;
}
- if (!(src1 & SLJIT_IMM)) {
- if (src2 & SLJIT_IMM) {
+ if (src1 != SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if (IS_HALFWORD(src2w) || compiler->mode32) {
inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, src1, src1w);
@@ -2201,8 +2270,8 @@ static sljit_s32 emit_test_binary(struct sljit_compiler *compiler,
}
}
- if (!(src2 & SLJIT_IMM)) {
- if (src1 & SLJIT_IMM) {
+ if (src2 != SLJIT_IMM) {
+ if (src1 == SLJIT_IMM) {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if (IS_HALFWORD(src1w) || compiler->mode32) {
inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src1w, src2, src2w);
@@ -2231,7 +2300,7 @@ static sljit_s32 emit_test_binary(struct sljit_compiler *compiler,
}
EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
- if (src2 & SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if (IS_HALFWORD(src2w) || compiler->mode32) {
inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, src2w, TMP_REG1, 0);
@@ -2269,18 +2338,18 @@ static sljit_s32 emit_shift(struct sljit_compiler *compiler,
#endif
sljit_u8* inst;
- if ((src2 & SLJIT_IMM) || (src2 == SLJIT_PREF_SHIFT_REG)) {
+ if (src2 == SLJIT_IMM || src2 == SLJIT_PREF_SHIFT_REG) {
if (dst == src1 && dstw == src1w) {
inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, src2, src2w, dst, dstw);
FAIL_IF(!inst);
- *inst |= mode;
+ inst[1] |= mode;
return SLJIT_SUCCESS;
}
if (dst == SLJIT_PREF_SHIFT_REG && src2 == SLJIT_PREF_SHIFT_REG) {
EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0);
FAIL_IF(!inst);
- *inst |= mode;
+ inst[1] |= mode;
EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0);
return SLJIT_SUCCESS;
}
@@ -2288,14 +2357,14 @@ static sljit_s32 emit_shift(struct sljit_compiler *compiler,
EMIT_MOV(compiler, dst, 0, src1, src1w);
inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, src2, src2w, dst, 0);
FAIL_IF(!inst);
- *inst |= mode;
+ inst[1] |= mode;
return SLJIT_SUCCESS;
}
EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, src2, src2w, TMP_REG1, 0);
FAIL_IF(!inst);
- *inst |= mode;
+ inst[1] |= mode;
EMIT_MOV(compiler, dst, dstw, TMP_REG1, 0);
return SLJIT_SUCCESS;
}
@@ -2305,7 +2374,7 @@ static sljit_s32 emit_shift(struct sljit_compiler *compiler,
EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w);
inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0);
FAIL_IF(!inst);
- *inst |= mode;
+ inst[1] |= mode;
return emit_mov(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0);
}
@@ -2323,7 +2392,7 @@ static sljit_s32 emit_shift(struct sljit_compiler *compiler,
EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w);
inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, dst, 0);
FAIL_IF(!inst);
- *inst |= mode;
+ inst[1] |= mode;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
compiler->mode32 = 0;
#endif
@@ -2349,7 +2418,7 @@ static sljit_s32 emit_shift(struct sljit_compiler *compiler,
EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w);
inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0);
FAIL_IF(!inst);
- *inst |= mode;
+ inst[1] |= mode;
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, SLJIT_MEM1(SLJIT_SP), 0);
@@ -2372,7 +2441,7 @@ static sljit_s32 emit_shift_with_flags(struct sljit_compiler *compiler,
sljit_s32 src2, sljit_sw src2w)
{
/* The CPU does not set flags if the shift count is 0. */
- if (src2 & SLJIT_IMM) {
+ if (src2 == SLJIT_IMM) {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
src2w &= compiler->mode32 ? 0x1f : 0x3f;
#else /* !SLJIT_CONFIG_X86_64 */
@@ -2437,7 +2506,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
return emit_unary(compiler, NEG_rm, dst, dstw, src2, src2w);
if (!HAS_FLAGS(op)) {
- if ((src2 & SLJIT_IMM) && emit_lea_binary(compiler, dst, dstw, src1, src1w, SLJIT_IMM, -src2w) != SLJIT_ERR_UNSUPPORTED)
+ if (src2 == SLJIT_IMM && emit_lea_binary(compiler, dst, dstw, src1, src1w, SLJIT_IMM, -src2w) != SLJIT_ERR_UNSUPPORTED)
return compiler->error;
if (FAST_IS_REG(dst) && src2 == dst) {
FAIL_IF(emit_non_cum_binary(compiler, BINARY_OPCODE(SUB), dst, 0, dst, 0, src1, src1w));
@@ -2459,6 +2528,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2(struct sljit_compiler *compile
return emit_cum_binary(compiler, BINARY_OPCODE(OR),
dst, dstw, src1, src1w, src2, src2w);
case SLJIT_XOR:
+ if (!HAS_FLAGS(op)) {
+ if (src2 == SLJIT_IMM && src2w == -1)
+ return emit_unary(compiler, NOT_rm, dst, dstw, src1, src1w);
+ if (src1 == SLJIT_IMM && src1w == -1)
+ return emit_unary(compiler, NOT_rm, dst, dstw, src2, src2w);
+ }
+
return emit_cum_binary(compiler, BINARY_OPCODE(XOR),
dst, dstw, src1, src1w, src2, src2w);
case SLJIT_SHL:
@@ -2514,117 +2590,192 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op2u(struct sljit_compiler *compil
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_shift_into(struct sljit_compiler *compiler, sljit_s32 op,
- sljit_s32 src_dst,
- sljit_s32 src1, sljit_sw src1w,
- sljit_s32 src2, sljit_sw src2w)
+ sljit_s32 dst_reg,
+ sljit_s32 src1_reg,
+ sljit_s32 src2_reg,
+ sljit_s32 src3, sljit_sw src3w)
{
- sljit_s32 restore_ecx = 0;
- sljit_s32 is_rotate, is_left;
+ sljit_s32 is_rotate, is_left, move_src1;
sljit_u8* inst;
+ sljit_sw src1w = 0;
sljit_sw dstw = 0;
+ /* The whole register must be saved even for 32 bit operations. */
+ sljit_u8 restore_ecx = 0;
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- sljit_s32 tmp2 = SLJIT_MEM1(SLJIT_SP);
-#else /* !SLJIT_CONFIG_X86_32 */
- sljit_s32 tmp2 = TMP_REG2;
+ sljit_sw src2w = 0;
+ sljit_s32 restore_sp4 = 0;
#endif /* SLJIT_CONFIG_X86_32 */
CHECK_ERROR();
- CHECK(check_sljit_emit_shift_into(compiler, op, src_dst, src1, src1w, src2, src2w));
- ADJUST_LOCAL_OFFSET(src1, src1w);
- ADJUST_LOCAL_OFFSET(src2, src2w);
+ CHECK(check_sljit_emit_shift_into(compiler, op, dst_reg, src1_reg, src2_reg, src3, src3w));
+ ADJUST_LOCAL_OFFSET(src3, src3w);
- CHECK_EXTRA_REGS(src1, src1w, (void)0);
- CHECK_EXTRA_REGS(src2, src2w, (void)0);
+ CHECK_EXTRA_REGS(dst_reg, dstw, (void)0);
+ CHECK_EXTRA_REGS(src3, src3w, (void)0);
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
compiler->mode32 = op & SLJIT_32;
-#endif
+#endif /* SLJIT_CONFIG_X86_64 */
- if (src2 & SLJIT_IMM) {
+ if (src3 == SLJIT_IMM) {
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- src2w &= 0x1f;
+ src3w &= 0x1f;
#else /* !SLJIT_CONFIG_X86_32 */
- src2w &= (op & SLJIT_32) ? 0x1f : 0x3f;
+ src3w &= (op & SLJIT_32) ? 0x1f : 0x3f;
#endif /* SLJIT_CONFIG_X86_32 */
- if (src2w == 0)
+ if (src3w == 0)
return SLJIT_SUCCESS;
}
is_left = (GET_OPCODE(op) == SLJIT_SHL || GET_OPCODE(op) == SLJIT_MSHL);
- is_rotate = (src_dst == src1);
- CHECK_EXTRA_REGS(src_dst, dstw, (void)0);
+ is_rotate = (src1_reg == src2_reg);
+ CHECK_EXTRA_REGS(src1_reg, src1w, (void)0);
+ CHECK_EXTRA_REGS(src2_reg, src2w, (void)0);
if (is_rotate)
- return emit_shift(compiler, is_left ? ROL : ROR, src_dst, dstw, src1, src1w, src2, src2w);
+ return emit_shift(compiler, is_left ? ROL : ROR, dst_reg, dstw, src1_reg, src1w, src3, src3w);
- if ((src2 & SLJIT_IMM) || src2 == SLJIT_PREF_SHIFT_REG) {
- if (!FAST_IS_REG(src1)) {
- EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
- src1 = TMP_REG1;
- }
- } else if (FAST_IS_REG(src1)) {
-#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- compiler->mode32 = 0;
-#endif
- EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_PREF_SHIFT_REG, 0);
-#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- compiler->mode32 = op & SLJIT_32;
-#endif
- EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w);
-
- if (src1 == SLJIT_PREF_SHIFT_REG)
- src1 = TMP_REG1;
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ if (src2_reg & SLJIT_MEM) {
+ EMIT_MOV(compiler, TMP_REG1, 0, src2_reg, src2w);
+ src2_reg = TMP_REG1;
+ }
+#endif /* SLJIT_CONFIG_X86_32 */
- if (src_dst == SLJIT_PREF_SHIFT_REG)
- src_dst = TMP_REG1;
+ if (dst_reg == SLJIT_PREF_SHIFT_REG && src3 != SLJIT_IMM && (src3 != SLJIT_PREF_SHIFT_REG || src1_reg != SLJIT_PREF_SHIFT_REG)) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ EMIT_MOV(compiler, TMP_REG1, 0, src1_reg, src1w);
+ src1_reg = TMP_REG1;
+ src1w = 0;
+#else /* !SLJIT_CONFIG_X86_64 */
+ if (src2_reg != TMP_REG1) {
+ EMIT_MOV(compiler, TMP_REG1, 0, src1_reg, src1w);
+ src1_reg = TMP_REG1;
+ src1w = 0;
+ } else if ((src1_reg & SLJIT_MEM) || src1_reg == SLJIT_PREF_SHIFT_REG) {
+ restore_sp4 = (src3 == SLJIT_R0) ? SLJIT_R1 : SLJIT_R0;
+ EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), sizeof(sljit_s32), restore_sp4, 0);
+ EMIT_MOV(compiler, restore_sp4, 0, src1_reg, src1w);
+ src1_reg = restore_sp4;
+ src1w = 0;
+ } else {
+ EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), sizeof(sljit_s32), src1_reg, 0);
+ restore_sp4 = src1_reg;
+ }
+#endif /* SLJIT_CONFIG_X86_64 */
- restore_ecx = 1;
+ if (src3 != SLJIT_PREF_SHIFT_REG)
+ EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src3, src3w);
} else {
- EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
+ if (src2_reg == SLJIT_PREF_SHIFT_REG && src3 != SLJIT_IMM && src3 != SLJIT_PREF_SHIFT_REG) {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- compiler->mode32 = 0;
-#endif
- EMIT_MOV(compiler, tmp2, 0, SLJIT_PREF_SHIFT_REG, 0);
+ compiler->mode32 = 0;
+#endif /* SLJIT_CONFIG_X86_64 */
+ EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_PREF_SHIFT_REG, 0);
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- compiler->mode32 = op & SLJIT_32;
-#endif
- EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src2, src2w);
+ compiler->mode32 = op & SLJIT_32;
+#endif /* SLJIT_CONFIG_X86_64 */
+ src2_reg = TMP_REG1;
+ restore_ecx = 1;
+ }
- src1 = TMP_REG1;
+ move_src1 = 0;
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ if (dst_reg != src1_reg) {
+ if (dst_reg != src3) {
+ EMIT_MOV(compiler, dst_reg, 0, src1_reg, src1w);
+ src1_reg = dst_reg;
+ src1w = 0;
+ } else
+ move_src1 = 1;
+ }
+#else /* !SLJIT_CONFIG_X86_64 */
+ if (dst_reg & SLJIT_MEM) {
+ if (src2_reg != TMP_REG1) {
+ EMIT_MOV(compiler, TMP_REG1, 0, src1_reg, src1w);
+ src1_reg = TMP_REG1;
+ src1w = 0;
+ } else if ((src1_reg & SLJIT_MEM) || src1_reg == SLJIT_PREF_SHIFT_REG) {
+ restore_sp4 = (src3 == SLJIT_R0) ? SLJIT_R1 : SLJIT_R0;
+ EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), sizeof(sljit_s32), restore_sp4, 0);
+ EMIT_MOV(compiler, restore_sp4, 0, src1_reg, src1w);
+ src1_reg = restore_sp4;
+ src1w = 0;
+ } else {
+ EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), sizeof(sljit_s32), src1_reg, 0);
+ restore_sp4 = src1_reg;
+ }
+ } else if (dst_reg != src1_reg) {
+ if (dst_reg != src3) {
+ EMIT_MOV(compiler, dst_reg, 0, src1_reg, src1w);
+ src1_reg = dst_reg;
+ src1w = 0;
+ } else
+ move_src1 = 1;
+ }
+#endif /* SLJIT_CONFIG_X86_64 */
- if (src_dst == SLJIT_PREF_SHIFT_REG) {
- src_dst = tmp2;
- SLJIT_ASSERT(dstw == 0);
+ if (src3 != SLJIT_IMM && src3 != SLJIT_PREF_SHIFT_REG) {
+ if (!restore_ecx) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ compiler->mode32 = 0;
+ EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_PREF_SHIFT_REG, 0);
+ compiler->mode32 = op & SLJIT_32;
+ restore_ecx = 1;
+#else /* !SLJIT_CONFIG_X86_64 */
+ if (src1_reg != TMP_REG1 && src2_reg != TMP_REG1) {
+ EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_PREF_SHIFT_REG, 0);
+ restore_ecx = 1;
+ } else {
+ EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), 0, SLJIT_PREF_SHIFT_REG, 0);
+ restore_ecx = 2;
+ }
+#endif /* SLJIT_CONFIG_X86_64 */
+ }
+ EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, src3, src3w);
}
- restore_ecx = 2;
+ if (move_src1) {
+ EMIT_MOV(compiler, dst_reg, 0, src1_reg, src1w);
+ src1_reg = dst_reg;
+ src1w = 0;
+ }
}
- inst = emit_x86_instruction(compiler, 2, src1, 0, src_dst, dstw);
+ inst = emit_x86_instruction(compiler, 2, src2_reg, 0, src1_reg, src1w);
FAIL_IF(!inst);
inst[0] = GROUP_0F;
- if (src2 & SLJIT_IMM) {
+ if (src3 == SLJIT_IMM) {
inst[1] = U8((is_left ? SHLD : SHRD) - 1);
- /* Immedate argument is added separately. */
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 1);
- FAIL_IF(!inst);
- INC_SIZE(1);
- *inst = U8(src2w);
+ /* Immediate argument is added separately. */
+ FAIL_IF(emit_byte(compiler, U8(src3w)));
} else
inst[1] = U8(is_left ? SHLD : SHRD);
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- compiler->mode32 = 0;
-#endif
+ if (restore_ecx) {
+ compiler->mode32 = 0;
+ EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0);
+ }
- if (restore_ecx == 1)
- return emit_mov(compiler, SLJIT_PREF_SHIFT_REG, 0, TMP_REG1, 0);
- if (restore_ecx == 2)
- return emit_mov(compiler, SLJIT_PREF_SHIFT_REG, 0, tmp2, 0);
+ if (src1_reg != dst_reg) {
+ compiler->mode32 = op & SLJIT_32;
+ return emit_mov(compiler, dst_reg, dstw, src1_reg, 0);
+ }
+#else /* !SLJIT_CONFIG_X86_64 */
+ if (restore_ecx)
+ EMIT_MOV(compiler, SLJIT_PREF_SHIFT_REG, 0, restore_ecx == 1 ? TMP_REG1 : SLJIT_MEM1(SLJIT_SP), 0);
+
+ if (src1_reg != dst_reg)
+ EMIT_MOV(compiler, dst_reg, dstw, src1_reg, 0);
+
+ if (restore_sp4)
+ return emit_mov(compiler, restore_sp4, 0, SLJIT_MEM1(SLJIT_SP), sizeof(sljit_s32));
+#endif /* SLJIT_CONFIG_X86_32 */
return SLJIT_SUCCESS;
}
@@ -2656,24 +2807,41 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_src(struct sljit_compiler *comp
return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_dst(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst, sljit_sw dstw)
{
- CHECK_REG_INDEX(check_sljit_get_register_index(reg));
-#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- if (reg >= SLJIT_R3 && reg <= SLJIT_R8)
- return -1;
-#endif
- return reg_map[reg];
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_op_dst(compiler, op, dst, dstw));
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+
+ CHECK_EXTRA_REGS(dst, dstw, (void)0);
+
+ switch (op) {
+ case SLJIT_FAST_ENTER:
+ return emit_fast_enter(compiler, dst, dstw);
+ case SLJIT_GET_RETURN_ADDRESS:
+ return sljit_emit_get_return_address(compiler, dst, dstw);
+ }
+
+ return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_float_register_index(sljit_s32 reg)
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_get_register_index(sljit_s32 type, sljit_s32 reg)
{
- CHECK_REG_INDEX(check_sljit_get_float_register_index(reg));
+ CHECK_REG_INDEX(check_sljit_get_register_index(type, reg));
+
+ if (type == SLJIT_GP_REGISTER) {
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- return reg;
-#else
+ if (reg >= SLJIT_R3 && reg <= SLJIT_R8)
+ return -1;
+#endif /* SLJIT_CONFIG_X86_32 */
+ return reg_map[reg];
+ }
+
+ if (type != SLJIT_FLOAT_REGISTER && type != SLJIT_SIMD_REG_128 && type != SLJIT_SIMD_REG_256 && type != SLJIT_SIMD_REG_512)
+ return -1;
+
return freg_map[reg];
-#endif
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_custom(struct sljit_compiler *compiler,
@@ -2701,6 +2869,8 @@ static sljit_u32 *sse2_buffer;
static void init_compiler(void)
{
+ get_cpu_features();
+
/* Align to 16 bytes. */
sse2_buffer = (sljit_u32*)(((sljit_uw)sse2_data + 15) & ~(sljit_uw)0xf);
@@ -2714,58 +2884,60 @@ static void init_compiler(void)
sse2_buffer[13] = 0x7fffffff;
}
-static sljit_s32 emit_sse2(struct sljit_compiler *compiler, sljit_u8 opcode,
- sljit_s32 single, sljit_s32 xmm1, sljit_s32 xmm2, sljit_sw xmm2w)
+static sljit_s32 emit_groupf(struct sljit_compiler *compiler,
+ sljit_uw op,
+ sljit_s32 dst, sljit_s32 src, sljit_sw srcw)
{
- sljit_u8 *inst;
-
- inst = emit_x86_instruction(compiler, 2 | (single ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2, xmm1, 0, xmm2, xmm2w);
+ sljit_u8 *inst = emit_x86_instruction(compiler, 2 | (op & ~(sljit_uw)0xff), dst, 0, src, srcw);
FAIL_IF(!inst);
- *inst++ = GROUP_0F;
- *inst = opcode;
+ inst[0] = GROUP_0F;
+ inst[1] = op & 0xff;
return SLJIT_SUCCESS;
}
-static sljit_s32 emit_sse2_logic(struct sljit_compiler *compiler, sljit_u8 opcode,
- sljit_s32 pref66, sljit_s32 xmm1, sljit_s32 xmm2, sljit_sw xmm2w)
+static sljit_s32 emit_groupf_ext(struct sljit_compiler *compiler,
+ sljit_uw op,
+ sljit_s32 dst, sljit_s32 src, sljit_sw srcw)
{
sljit_u8 *inst;
- inst = emit_x86_instruction(compiler, 2 | (pref66 ? EX86_PREF_66 : 0) | EX86_SSE2, xmm1, 0, xmm2, xmm2w);
+ SLJIT_ASSERT((op & EX86_SSE2) && ((op & VEX_OP_0F38) || (op & VEX_OP_0F3A)));
+
+ inst = emit_x86_instruction(compiler, 3 | (op & ~((sljit_uw)0xff | VEX_OP_0F38 | VEX_OP_0F3A)), dst, 0, src, srcw);
FAIL_IF(!inst);
- *inst++ = GROUP_0F;
- *inst = opcode;
+ inst[0] = GROUP_0F;
+ inst[1] = U8((op & VEX_OP_0F38) ? 0x38 : 0x3A);
+ inst[2] = op & 0xff;
return SLJIT_SUCCESS;
}
static SLJIT_INLINE sljit_s32 emit_sse2_load(struct sljit_compiler *compiler,
sljit_s32 single, sljit_s32 dst, sljit_s32 src, sljit_sw srcw)
{
- return emit_sse2(compiler, MOVSD_x_xm, single, dst, src, srcw);
+ return emit_groupf(compiler, MOVSD_x_xm | (single ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2, dst, src, srcw);
}
static SLJIT_INLINE sljit_s32 emit_sse2_store(struct sljit_compiler *compiler,
sljit_s32 single, sljit_s32 dst, sljit_sw dstw, sljit_s32 src)
{
- return emit_sse2(compiler, MOVSD_xm_x, single, src, dst, dstw);
+ return emit_groupf(compiler, MOVSD_xm_x | (single ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2, src, dst, dstw);
}
static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_sw_from_f64(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst, sljit_sw dstw,
sljit_s32 src, sljit_sw srcw)
{
- sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
- sljit_u8 *inst;
+ sljit_s32 dst_r;
+
+ CHECK_EXTRA_REGS(dst, dstw, (void)0);
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if (GET_OPCODE(op) == SLJIT_CONV_SW_FROM_F64)
compiler->mode32 = 0;
#endif
- inst = emit_x86_instruction(compiler, 2 | ((op & SLJIT_32) ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2_OP2, dst_r, 0, src, srcw);
- FAIL_IF(!inst);
- *inst++ = GROUP_0F;
- *inst = CVTTSD2SI_r_xm;
+ FAIL_IF(emit_groupf(compiler, CVTTSD2SI_r_xm | EX86_SELECT_F2_F3(op) | EX86_SSE2_OP2, dst_r, src, srcw));
if (dst & SLJIT_MEM)
return emit_mov(compiler, dst, dstw, TMP_REG1, 0);
@@ -2777,14 +2949,15 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_comp
sljit_s32 src, sljit_sw srcw)
{
sljit_s32 dst_r = FAST_IS_REG(dst) ? dst : TMP_FREG;
- sljit_u8 *inst;
+
+ CHECK_EXTRA_REGS(src, srcw, (void)0);
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_SW)
compiler->mode32 = 0;
#endif
- if (src & SLJIT_IMM) {
+ if (src == SLJIT_IMM) {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if (GET_OPCODE(op) == SLJIT_CONV_F64_FROM_S32)
srcw = (sljit_s32)srcw;
@@ -2794,10 +2967,7 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_conv_f64_from_sw(struct sljit_comp
srcw = 0;
}
- inst = emit_x86_instruction(compiler, 2 | ((op & SLJIT_32) ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2_OP1, dst_r, 0, src, srcw);
- FAIL_IF(!inst);
- *inst++ = GROUP_0F;
- *inst = CVTSI2SD_x_rm;
+ FAIL_IF(emit_groupf(compiler, CVTSI2SD_x_rm | EX86_SELECT_F2_F3(op) | EX86_SSE2_OP1, dst_r, src, srcw));
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
compiler->mode32 = 1;
@@ -2812,16 +2982,28 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compile
sljit_s32 src2, sljit_sw src2w)
{
switch (GET_FLAG_TYPE(op)) {
+ case SLJIT_ORDERED_EQUAL:
+ /* Also: SLJIT_UNORDERED_OR_NOT_EQUAL */
+ FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, TMP_FREG, src1, src1w));
+ FAIL_IF(emit_groupf(compiler, CMPS_x_xm | EX86_SELECT_F2_F3(op) | EX86_SSE2, TMP_FREG, src2, src2w));
+
+ /* EQ */
+ FAIL_IF(emit_byte(compiler, 0));
+
+ src1 = TMP_FREG;
+ src2 = TMP_FREG;
+ src2w = 0;
+ break;
+
case SLJIT_ORDERED_LESS:
- case SLJIT_UNORDERED_OR_GREATER_EQUAL:
case SLJIT_UNORDERED_OR_GREATER:
- case SLJIT_ORDERED_LESS_EQUAL:
+ /* Also: SLJIT_UNORDERED_OR_GREATER_EQUAL, SLJIT_ORDERED_LESS_EQUAL */
if (!FAST_IS_REG(src2)) {
FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, TMP_FREG, src2, src2w));
src2 = TMP_FREG;
}
- return emit_sse2_logic(compiler, UCOMISD_x_xm, !(op & SLJIT_32), src2, src1, src1w);
+ return emit_groupf(compiler, UCOMISD_x_xm | EX86_SELECT_66(op) | EX86_SSE2, src2, src1, src1w);
}
if (!FAST_IS_REG(src1)) {
@@ -2829,7 +3011,7 @@ static SLJIT_INLINE sljit_s32 sljit_emit_fop1_cmp(struct sljit_compiler *compile
src1 = TMP_FREG;
}
- return emit_sse2_logic(compiler, UCOMISD_x_xm, !(op & SLJIT_32), src1, src2, src2w);
+ return emit_groupf(compiler, UCOMISD_x_xm | EX86_SELECT_66(op) | EX86_SSE2, src1, src2, src2w);
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compiler, sljit_s32 op,
@@ -2837,6 +3019,7 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil
sljit_s32 src, sljit_sw srcw)
{
sljit_s32 dst_r;
+ sljit_u8 *inst;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
compiler->mode32 = 1;
@@ -2860,42 +3043,57 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop1(struct sljit_compiler *compil
/* We overwrite the high bits of source. From SLJIT point of view,
this is not an issue.
Note: In SSE3, we could also use MOVDDUP and MOVSLDUP. */
- FAIL_IF(emit_sse2_logic(compiler, UNPCKLPD_x_xm, op & SLJIT_32, src, src, 0));
- }
- else {
+ FAIL_IF(emit_groupf(compiler, UNPCKLPD_x_xm | ((op & SLJIT_32) ? EX86_PREF_66 : 0) | EX86_SSE2, src, src, 0));
+ } else {
FAIL_IF(emit_sse2_load(compiler, !(op & SLJIT_32), TMP_FREG, src, srcw));
src = TMP_FREG;
}
- FAIL_IF(emit_sse2_logic(compiler, CVTPD2PS_x_xm, op & SLJIT_32, dst_r, src, 0));
+ FAIL_IF(emit_groupf(compiler, CVTPD2PS_x_xm | ((op & SLJIT_32) ? EX86_PREF_66 : 0) | EX86_SSE2, dst_r, src, 0));
if (dst_r == TMP_FREG)
return emit_sse2_store(compiler, op & SLJIT_32, dst, dstw, TMP_FREG);
return SLJIT_SUCCESS;
}
if (FAST_IS_REG(dst)) {
- dst_r = dst;
- if (dst != src)
- FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, dst_r, src, srcw));
- }
- else {
- dst_r = TMP_FREG;
- FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, dst_r, src, srcw));
+ dst_r = (dst == src) ? TMP_FREG : dst;
+
+ if (src & SLJIT_MEM)
+ FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, TMP_FREG, src, srcw));
+
+ FAIL_IF(emit_groupf(compiler, PCMPEQD_x_xm | EX86_PREF_66 | EX86_SSE2, dst_r, dst_r, 0));
+
+ inst = emit_x86_instruction(compiler, 2 | EX86_PREF_66 | EX86_SSE2_OP2, 0, 0, dst_r, 0);
+ inst[0] = GROUP_0F;
+ /* Same as PSRLD_x / PSRLQ_x */
+ inst[1] = (op & SLJIT_32) ? PSLLD_x_i8 : PSLLQ_x_i8;
+
+ if (GET_OPCODE(op) == SLJIT_ABS_F64) {
+ inst[2] |= 2 << 3;
+ FAIL_IF(emit_byte(compiler, 1));
+ } else {
+ inst[2] |= 6 << 3;
+ FAIL_IF(emit_byte(compiler, ((op & SLJIT_32) ? 31 : 63)));
+ }
+
+ if (dst_r != TMP_FREG)
+ dst_r = (src & SLJIT_MEM) ? TMP_FREG : src;
+ return emit_groupf(compiler, (GET_OPCODE(op) == SLJIT_NEG_F64 ? XORPD_x_xm : ANDPD_x_xm) | EX86_SSE2, dst, dst_r, 0);
}
+ FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, TMP_FREG, src, srcw));
+
switch (GET_OPCODE(op)) {
case SLJIT_NEG_F64:
- FAIL_IF(emit_sse2_logic(compiler, XORPD_x_xm, 1, dst_r, SLJIT_MEM0(), (sljit_sw)(op & SLJIT_32 ? sse2_buffer : sse2_buffer + 8)));
+ FAIL_IF(emit_groupf(compiler, XORPD_x_xm | EX86_SELECT_66(op) | EX86_SSE2, TMP_FREG, SLJIT_MEM0(), (sljit_sw)((op & SLJIT_32) ? sse2_buffer : sse2_buffer + 8)));
break;
case SLJIT_ABS_F64:
- FAIL_IF(emit_sse2_logic(compiler, ANDPD_x_xm, 1, dst_r, SLJIT_MEM0(), (sljit_sw)(op & SLJIT_32 ? sse2_buffer + 4 : sse2_buffer + 12)));
+ FAIL_IF(emit_groupf(compiler, ANDPD_x_xm | EX86_SELECT_66(op) | EX86_SSE2, TMP_FREG, SLJIT_MEM0(), (sljit_sw)((op & SLJIT_32) ? sse2_buffer + 4 : sse2_buffer + 12)));
break;
}
- if (dst_r == TMP_FREG)
- return emit_sse2_store(compiler, op & SLJIT_32, dst, dstw, TMP_FREG);
- return SLJIT_SUCCESS;
+ return emit_sse2_store(compiler, op & SLJIT_32, dst, dstw, TMP_FREG);
}
SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compiler, sljit_s32 op,
@@ -2938,19 +3136,19 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
switch (GET_OPCODE(op)) {
case SLJIT_ADD_F64:
- FAIL_IF(emit_sse2(compiler, ADDSD_x_xm, op & SLJIT_32, dst_r, src2, src2w));
+ FAIL_IF(emit_groupf(compiler, ADDSD_x_xm | EX86_SELECT_F2_F3(op) | EX86_SSE2, dst_r, src2, src2w));
break;
case SLJIT_SUB_F64:
- FAIL_IF(emit_sse2(compiler, SUBSD_x_xm, op & SLJIT_32, dst_r, src2, src2w));
+ FAIL_IF(emit_groupf(compiler, SUBSD_x_xm | EX86_SELECT_F2_F3(op) | EX86_SSE2, dst_r, src2, src2w));
break;
case SLJIT_MUL_F64:
- FAIL_IF(emit_sse2(compiler, MULSD_x_xm, op & SLJIT_32, dst_r, src2, src2w));
+ FAIL_IF(emit_groupf(compiler, MULSD_x_xm | EX86_SELECT_F2_F3(op) | EX86_SSE2, dst_r, src2, src2w));
break;
case SLJIT_DIV_F64:
- FAIL_IF(emit_sse2(compiler, DIVSD_x_xm, op & SLJIT_32, dst_r, src2, src2w));
+ FAIL_IF(emit_groupf(compiler, DIVSD_x_xm | EX86_SELECT_F2_F3(op) | EX86_SSE2, dst_r, src2, src2w));
break;
}
@@ -2959,6 +3157,45 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2(struct sljit_compiler *compil
return SLJIT_SUCCESS;
}
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fop2r(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 dst_freg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2, sljit_sw src2w)
+{
+ sljit_uw pref;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fop2r(compiler, op, dst_freg, src1, src1w, src2, src2w));
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+ ADJUST_LOCAL_OFFSET(src2, src2w);
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ compiler->mode32 = 1;
+#endif
+
+ if (dst_freg == src1) {
+ FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, TMP_FREG, src2, src2w));
+ pref = EX86_SELECT_66(op) | EX86_SSE2;
+ FAIL_IF(emit_groupf(compiler, XORPD_x_xm | pref, TMP_FREG, src1, src1w));
+ FAIL_IF(emit_groupf(compiler, ANDPD_x_xm | pref, TMP_FREG, SLJIT_MEM0(), (sljit_sw)((op & SLJIT_32) ? sse2_buffer : sse2_buffer + 8)));
+ return emit_groupf(compiler, XORPD_x_xm | pref, dst_freg, TMP_FREG, 0);
+ }
+
+ if (src1 & SLJIT_MEM) {
+ FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, TMP_FREG, src1, src1w));
+ src1 = TMP_FREG;
+ src1w = 0;
+ }
+
+ if (dst_freg != src2)
+ FAIL_IF(emit_sse2_load(compiler, op & SLJIT_32, dst_freg, src2, src2w));
+
+ pref = EX86_SELECT_66(op) | EX86_SSE2;
+ FAIL_IF(emit_groupf(compiler, XORPD_x_xm | pref, dst_freg, src1, src1w));
+ FAIL_IF(emit_groupf(compiler, ANDPD_x_xm | pref, dst_freg, SLJIT_MEM0(), (sljit_sw)((op & SLJIT_32) ? sse2_buffer : sse2_buffer + 8)));
+ return emit_groupf(compiler, XORPD_x_xm | pref, dst_freg, src1, src1w);
+}
+
/* --------------------------------------------------------------------- */
/* Conditional instructions */
/* --------------------------------------------------------------------- */
@@ -2980,9 +3217,8 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_label* sljit_emit_label(struct sljit_compi
inst = (sljit_u8*)ensure_buf(compiler, 2);
PTR_FAIL_IF(!inst);
-
- *inst++ = 0;
- *inst++ = 0;
+ inst[0] = 0;
+ inst[1] = 0;
return label;
}
@@ -3010,8 +3246,8 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_jump* sljit_emit_jump(struct sljit_compile
inst = (sljit_u8*)ensure_buf(compiler, 2);
PTR_FAIL_IF_NULL(inst);
- *inst++ = 0;
- *inst++ = 1;
+ inst[0] = 0;
+ inst[1] = 1;
return jump;
}
@@ -3042,8 +3278,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
inst = (sljit_u8*)ensure_buf(compiler, 2);
FAIL_IF_NULL(inst);
- *inst++ = 0;
- *inst++ = 1;
+ inst[0] = 0;
+ inst[1] = 1;
}
else {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
@@ -3052,8 +3288,8 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_ijump(struct sljit_compiler *compi
#endif
inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw);
FAIL_IF(!inst);
- *inst++ = GROUP_FF;
- *inst = U8(*inst | ((type >= SLJIT_FAST_CALL) ? CALL_rm : JMP_rm));
+ inst[0] = GROUP_FF;
+ inst[1] = U8(inst[1] | ((type >= SLJIT_FAST_CALL) ? CALL_rm : JMP_rm));
}
return SLJIT_SUCCESS;
}
@@ -3063,10 +3299,10 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
sljit_s32 type)
{
sljit_u8 *inst;
- sljit_u8 cond_set = 0;
+ sljit_u8 cond_set;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
sljit_s32 reg;
-#endif
+#endif /* !SLJIT_CONFIG_X86_64 */
/* ADJUST_LOCAL_OFFSET and CHECK_EXTRA_REGS might overwrite these values. */
sljit_s32 dst_save = dst;
sljit_sw dstw_save = dstw;
@@ -3086,13 +3322,13 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
FAIL_IF(!inst);
INC_SIZE(4 + 3);
/* Set low register to conditional flag. */
- *inst++ = (reg_map[TMP_REG1] <= 7) ? REX : REX_B;
- *inst++ = GROUP_0F;
- *inst++ = cond_set;
- *inst++ = MOD_REG | reg_lmap[TMP_REG1];
- *inst++ = U8(REX | (reg_map[TMP_REG1] <= 7 ? 0 : REX_R) | (reg_map[dst] <= 7 ? 0 : REX_B));
- *inst++ = OR_rm8_r8;
- *inst++ = U8(MOD_REG | (reg_lmap[TMP_REG1] << 3) | reg_lmap[dst]);
+ inst[0] = (reg_map[TMP_REG1] <= 7) ? REX : REX_B;
+ inst[1] = GROUP_0F;
+ inst[2] = cond_set;
+ inst[3] = MOD_REG | reg_lmap[TMP_REG1];
+ inst[4] = U8(REX | (reg_map[TMP_REG1] <= 7 ? 0 : REX_R) | (reg_map[dst] <= 7 ? 0 : REX_B));
+ inst[5] = OR_rm8_r8;
+ inst[6] = U8(MOD_REG | (reg_lmap[TMP_REG1] << 3) | reg_lmap[dst]);
return SLJIT_SUCCESS;
}
@@ -3102,15 +3338,15 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
FAIL_IF(!inst);
INC_SIZE(4 + 4);
/* Set low register to conditional flag. */
- *inst++ = (reg_map[reg] <= 7) ? REX : REX_B;
- *inst++ = GROUP_0F;
- *inst++ = cond_set;
- *inst++ = MOD_REG | reg_lmap[reg];
- *inst++ = REX_W | (reg_map[reg] <= 7 ? 0 : (REX_B | REX_R));
+ inst[0] = (reg_map[reg] <= 7) ? REX : REX_B;
+ inst[1] = GROUP_0F;
+ inst[2] = cond_set;
+ inst[3] = MOD_REG | reg_lmap[reg];
+ inst[4] = REX_W | (reg_map[reg] <= 7 ? 0 : (REX_B | REX_R));
/* The movzx instruction does not affect flags. */
- *inst++ = GROUP_0F;
- *inst++ = MOVZX_r_rm8;
- *inst = U8(MOD_REG | (reg_lmap[reg] << 3) | reg_lmap[reg]);
+ inst[5] = GROUP_0F;
+ inst[6] = MOVZX_r_rm8;
+ inst[7] = U8(MOD_REG | (reg_lmap[reg] << 3) | reg_lmap[reg]);
if (reg != TMP_REG1)
return SLJIT_SUCCESS;
@@ -3123,156 +3359,1311 @@ SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_op_flags(struct sljit_compiler *co
SLJIT_SKIP_CHECKS(compiler);
return sljit_emit_op2(compiler, op, dst_save, dstw_save, dst_save, dstw_save, TMP_REG1, 0);
-#else
+#else /* !SLJIT_CONFIG_X86_64 */
+ SLJIT_ASSERT(reg_map[TMP_REG1] < 4);
+
/* The SLJIT_CONFIG_X86_32 code path starts here. */
- if (GET_OPCODE(op) < SLJIT_ADD && FAST_IS_REG(dst)) {
- if (reg_map[dst] <= 4) {
- /* Low byte is accessible. */
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 3 + 3);
- FAIL_IF(!inst);
- INC_SIZE(3 + 3);
- /* Set low byte to conditional flag. */
- *inst++ = GROUP_0F;
- *inst++ = cond_set;
- *inst++ = U8(MOD_REG | reg_map[dst]);
-
- *inst++ = GROUP_0F;
- *inst++ = MOVZX_r_rm8;
- *inst = U8(MOD_REG | (reg_map[dst] << 3) | reg_map[dst]);
+ if (GET_OPCODE(op) < SLJIT_ADD && FAST_IS_REG(dst) && reg_map[dst] <= 4) {
+ /* Low byte is accessible. */
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 3 + 3);
+ FAIL_IF(!inst);
+ INC_SIZE(3 + 3);
+ /* Set low byte to conditional flag. */
+ inst[0] = GROUP_0F;
+ inst[1] = cond_set;
+ inst[2] = U8(MOD_REG | reg_map[dst]);
+
+ inst[3] = GROUP_0F;
+ inst[4] = MOVZX_r_rm8;
+ inst[5] = U8(MOD_REG | (reg_map[dst] << 3) | reg_map[dst]);
+ return SLJIT_SUCCESS;
+ }
+
+ if (GET_OPCODE(op) == SLJIT_OR && !GET_ALL_FLAGS(op) && FAST_IS_REG(dst) && reg_map[dst] <= 4) {
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 3 + 2);
+ FAIL_IF(!inst);
+ INC_SIZE(3 + 2);
+
+ /* Set low byte to conditional flag. */
+ inst[0] = GROUP_0F;
+ inst[1] = cond_set;
+ inst[2] = U8(MOD_REG | reg_map[TMP_REG1]);
+
+ inst[3] = OR_rm8_r8;
+ inst[4] = U8(MOD_REG | (reg_map[TMP_REG1] << 3) | reg_map[dst]);
+ return SLJIT_SUCCESS;
+ }
+
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 3 + 3);
+ FAIL_IF(!inst);
+ INC_SIZE(3 + 3);
+ /* Set low byte to conditional flag. */
+ inst[0] = GROUP_0F;
+ inst[1] = cond_set;
+ inst[2] = U8(MOD_REG | reg_map[TMP_REG1]);
+
+ inst[3] = GROUP_0F;
+ inst[4] = MOVZX_r_rm8;
+ inst[5] = U8(MOD_REG | (reg_map[TMP_REG1] << 3) | reg_map[TMP_REG1]);
+
+ if (GET_OPCODE(op) < SLJIT_ADD)
+ return emit_mov(compiler, dst, dstw, TMP_REG1, 0);
+
+ SLJIT_SKIP_CHECKS(compiler);
+ return sljit_emit_op2(compiler, op, dst_save, dstw_save, dst_save, dstw_save, TMP_REG1, 0);
+#endif /* SLJIT_CONFIG_X86_64 */
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_select(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_reg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_reg)
+{
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ sljit_s32 dst = dst_reg;
+ sljit_sw dstw = 0;
+#endif /* SLJIT_CONFIG_X86_32 */
+ sljit_sw src2w = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_select(compiler, type, dst_reg, src1, src1w, src2_reg));
+
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+
+ CHECK_EXTRA_REGS(dst, dstw, (void)0);
+ CHECK_EXTRA_REGS(src1, src1w, (void)0);
+ CHECK_EXTRA_REGS(src2_reg, src2w, (void)0);
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ compiler->mode32 = type & SLJIT_32;
+#endif /* SLJIT_CONFIG_X86_64 */
+ type &= ~SLJIT_32;
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ if (dst & SLJIT_MEM) {
+ if (src1 == SLJIT_IMM || (!(src1 & SLJIT_MEM) && (src2_reg & SLJIT_MEM))) {
+ EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
+ src1 = src2_reg;
+ src1w = src2w;
+ type ^= 0x1;
+ } else
+ EMIT_MOV(compiler, TMP_REG1, 0, src2_reg, src2w);
+
+ dst_reg = TMP_REG1;
+ } else {
+#endif /* SLJIT_CONFIG_X86_32 */
+ if (dst_reg != src2_reg) {
+ if (dst_reg == src1) {
+ src1 = src2_reg;
+ src1w = src2w;
+ type ^= 0x1;
+ } else {
+ if (ADDRESSING_DEPENDS_ON(src1, dst_reg)) {
+ EMIT_MOV(compiler, dst_reg, 0, src1, src1w);
+ src1 = src2_reg;
+ src1w = src2w;
+ type ^= 0x1;
+ } else
+ EMIT_MOV(compiler, dst_reg, 0, src2_reg, src2w);
+ }
+ }
+
+ if (SLJIT_UNLIKELY(src1 == SLJIT_IMM)) {
+ SLJIT_ASSERT(dst_reg != TMP_REG1);
+ EMIT_MOV(compiler, TMP_REG1, 0, src1, src1w);
+ src1 = TMP_REG1;
+ src1w = 0;
+ }
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ }
+#endif /* SLJIT_CONFIG_X86_32 */
+
+ if (sljit_has_cpu_feature(SLJIT_HAS_CMOV))
+ FAIL_IF(emit_groupf(compiler, U8(get_jump_code((sljit_uw)type) - 0x40), dst_reg, src1, src1w));
+ else
+ FAIL_IF(emit_cmov_generic(compiler, type, dst_reg, src1, src1w));
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ if (dst_reg == TMP_REG1)
+ return emit_mov(compiler, dst, dstw, TMP_REG1, 0);
+#endif /* SLJIT_CONFIG_X86_32 */
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_fselect(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg,
+ sljit_s32 src1, sljit_sw src1w,
+ sljit_s32 src2_freg)
+{
+ sljit_u8* inst;
+ sljit_uw size;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_fselect(compiler, type, dst_freg, src1, src1w, src2_freg));
+
+ ADJUST_LOCAL_OFFSET(src1, src1w);
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ compiler->mode32 = 1;
+#endif /* SLJIT_CONFIG_X86_64 */
+
+ if (dst_freg != src2_freg) {
+ if (dst_freg == src1) {
+ src1 = src2_freg;
+ src1w = 0;
+ type ^= 0x1;
+ } else
+ FAIL_IF(emit_sse2_load(compiler, type & SLJIT_32, dst_freg, src2_freg, 0));
+ }
+
+ inst = (sljit_u8*)ensure_buf(compiler, 1 + 2);
+ FAIL_IF(!inst);
+ INC_SIZE(2);
+ inst[0] = U8(get_jump_code((sljit_uw)(type & ~SLJIT_32) ^ 0x1) - 0x10);
+
+ size = compiler->size;
+ FAIL_IF(emit_sse2_load(compiler, type & SLJIT_32, dst_freg, src1, src1w));
+
+ inst[1] = U8(compiler->size - size);
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_mov(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 srcdst, sljit_sw srcdstw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_s32 alignment = SLJIT_SIMD_GET_ELEM2_SIZE(type);
+ sljit_uw op;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_mov(compiler, type, freg, srcdst, srcdstw));
+
+ ADJUST_LOCAL_OFFSET(srcdst, srcdstw);
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ compiler->mode32 = 1;
+#endif /* SLJIT_CONFIG_X86_64 */
+
+ switch (reg_size) {
+ case 4:
+ op = EX86_SSE2;
+ break;
+ case 5:
+ if (!(cpu_feature_list & CPU_FEATURE_AVX2))
+ return SLJIT_ERR_UNSUPPORTED;
+ op = EX86_SSE2 | VEX_256;
+ break;
+ default:
+ return SLJIT_ERR_UNSUPPORTED;
+ }
+
+ if (!(srcdst & SLJIT_MEM))
+ alignment = reg_size;
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ if (elem_size == 2 || elem_size == 3) {
+ op |= alignment >= reg_size ? MOVAPS_x_xm : MOVUPS_x_xm;
+
+ if (elem_size == 3)
+ op |= EX86_PREF_66;
+
+ if (type & SLJIT_SIMD_STORE)
+ op += 1;
+ } else
+ return SLJIT_ERR_UNSUPPORTED;
+ } else {
+ op |= ((type & SLJIT_SIMD_STORE) ? MOVDQA_xm_x : MOVDQA_x_xm)
+ | (alignment >= reg_size ? EX86_PREF_66 : EX86_PREF_F3);
+ }
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (op & VEX_256)
+ return emit_vex_instruction(compiler, op, freg, 0, srcdst, srcdstw);
+
+ return emit_groupf(compiler, op, freg, srcdst, srcdstw);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_replicate(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_u8 *inst;
+ sljit_u8 opcode = 0;
+ sljit_uw size;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_replicate(compiler, type, freg, src, srcw));
+
+ ADJUST_LOCAL_OFFSET(src, srcw);
+
+ if (!(type & SLJIT_SIMD_FLOAT)) {
+ CHECK_EXTRA_REGS(src, srcw, (void)0);
+ }
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ if ((type & SLJIT_SIMD_FLOAT) ? (elem_size < 2 || elem_size > 3) : (elem_size > 2))
+ return SLJIT_ERR_UNSUPPORTED;
+#else /* !SLJIT_CONFIG_X86_32 */
+ compiler->mode32 = 1;
+
+ if (elem_size > 3 || ((type & SLJIT_SIMD_FLOAT) && elem_size < 2))
+ return SLJIT_ERR_UNSUPPORTED;
+#endif /* SLJIT_CONFIG_X86_32 */
+
+ if (cpu_feature_list & CPU_FEATURE_AVX2) {
+ if (reg_size < 4 || reg_size > 5)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (src != SLJIT_IMM && (reg_size == 5 || elem_size < 3 || !(type & SLJIT_SIMD_FLOAT))) {
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (!(src & SLJIT_MEM) && !(type & SLJIT_SIMD_FLOAT)) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ if (elem_size >= 3)
+ compiler->mode32 = 0;
+#endif /* SLJIT_CONFIG_X86_64 */
+ FAIL_IF(emit_groupf(compiler, MOVD_x_rm | EX86_PREF_66 | EX86_SSE2_OP1, freg, src, srcw));
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ compiler->mode32 = 1;
+#endif /* SLJIT_CONFIG_X86_64 */
+ src = freg;
+ srcw = 0;
+ }
+
+ switch (elem_size) {
+ case 0:
+ size = VPBROADCASTB_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2;
+ break;
+ case 1:
+ size = VPBROADCASTW_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2;
+ break;
+ case 2:
+ size = ((type & SLJIT_SIMD_FLOAT) ? VBROADCASTSS_x_xm : VPBROADCASTD_x_xm) | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2;
+ break;
+ default:
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ size = VBROADCASTSD_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2;
+#else /* !SLJIT_CONFIG_X86_32 */
+ size = ((type & SLJIT_SIMD_FLOAT) ? VBROADCASTSD_x_xm : VPBROADCASTQ_x_xm) | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2;
+#endif /* SLJIT_CONFIG_X86_32 */
+ break;
+ }
+
+ if (reg_size == 5)
+ size |= VEX_256;
+
+ return emit_vex_instruction(compiler, size, freg, 0, src, srcw);
+ }
+ } else if (reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ if (src == SLJIT_IMM) {
+ if (reg_size == 5)
+ return emit_vex_instruction(compiler, XORPD_x_xm | VEX_256 | (elem_size == 3 ? EX86_PREF_66 : 0) | EX86_SSE2 | VEX_SSE2_OPV, freg, freg, freg, 0);
+
+ return emit_groupf(compiler, XORPD_x_xm | (elem_size == 3 ? EX86_PREF_66 : 0) | EX86_SSE2, freg, freg, 0);
+ }
+
+ if (elem_size == 2 && freg != src) {
+ FAIL_IF(emit_sse2_load(compiler, 1, freg, src, srcw));
+ src = freg;
+ srcw = 0;
+ }
+
+ FAIL_IF(emit_groupf(compiler, (elem_size == 2 ? SHUFPS_x_xm : MOVDDUP_x_xm) | (elem_size == 2 ? 0 : EX86_PREF_F2) | EX86_SSE2, freg, src, srcw));
+
+ if (elem_size == 2)
+ return emit_byte(compiler, 0);
+ return SLJIT_SUCCESS;
+ }
+
+ if (src == SLJIT_IMM) {
+ if (elem_size == 0) {
+ srcw = (sljit_u8)srcw;
+ srcw |= srcw << 8;
+ srcw |= srcw << 16;
+ elem_size = 2;
+ } else if (elem_size == 1) {
+ srcw = (sljit_u16)srcw;
+ srcw |= srcw << 16;
+ elem_size = 2;
+ }
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ if (elem_size == 2 && (sljit_s32)srcw == -1)
+ srcw = -1;
+#endif /* SLJIT_CONFIG_X86_64 */
+
+ if (srcw == 0 || srcw == -1) {
+ if (reg_size == 5)
+ return emit_vex_instruction(compiler, (srcw == 0 ? PXOR_x_xm : PCMPEQD_x_xm) | VEX_256 | EX86_PREF_66 | EX86_SSE2 | VEX_SSE2_OPV, freg, freg, freg, 0);
+
+ return emit_groupf(compiler, (srcw == 0 ? PXOR_x_xm : PCMPEQD_x_xm) | EX86_PREF_66 | EX86_SSE2, freg, freg, 0);
+ }
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ if (elem_size == 3)
+ FAIL_IF(emit_load_imm64(compiler, TMP_REG1, srcw));
+ else
+#endif /* SLJIT_CONFIG_X86_64 */
+ EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, srcw);
+
+ src = TMP_REG1;
+ srcw = 0;
+ }
+
+ size = 2;
+ opcode = MOVD_x_rm;
+
+ switch (elem_size) {
+ case 0:
+ if (!FAST_IS_REG(src)) {
+ opcode = 0x3a /* Prefix of PINSRB_x_rm_i8. */;
+ size = 3;
+ }
+ break;
+ case 1:
+ if (!FAST_IS_REG(src))
+ opcode = PINSRW_x_rm_i8;
+ break;
+ case 2:
+ break;
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ case 3:
+ /* MOVQ */
+ compiler->mode32 = 0;
+ break;
+#endif /* SLJIT_CONFIG_X86_64 */
+ }
+
+ inst = emit_x86_instruction(compiler, size | EX86_PREF_66 | EX86_SSE2_OP1, freg, 0, src, srcw);
+ FAIL_IF(!inst);
+ inst[0] = GROUP_0F;
+ inst[1] = opcode;
+
+ if (reg_size == 5) {
+ SLJIT_ASSERT(opcode == MOVD_x_rm);
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ size = VPBROADCASTD_x_xm;
+#else /* !SLJIT_CONFIG_X86_32 */
+ size = (elem_size == 3) ? VPBROADCASTQ_x_xm : VPBROADCASTD_x_xm;
+#endif /* SLJIT_CONFIG_X86_32 */
+ return emit_vex_instruction(compiler, size | VEX_256 | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, 0, freg, 0);
+ }
+
+ if (size == 3) {
+ SLJIT_ASSERT(opcode == 0x3a);
+ inst[2] = PINSRB_x_rm_i8;
+ }
+
+ if (opcode != MOVD_x_rm)
+ FAIL_IF(emit_byte(compiler, 0));
+
+ switch (elem_size) {
+ case 0:
+ FAIL_IF(emit_groupf(compiler, PXOR_x_xm | EX86_PREF_66 | EX86_SSE2, TMP_FREG, TMP_FREG, 0));
+ return emit_groupf_ext(compiler, PSHUFB_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, TMP_FREG, 0);
+ case 1:
+ FAIL_IF(emit_groupf(compiler, PSHUFLW_x_xm | EX86_PREF_F2 | EX86_SSE2, freg, freg, 0));
+ FAIL_IF(emit_byte(compiler, 0));
+ /* fallthrough */
+ default:
+ FAIL_IF(emit_groupf(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, freg, 0));
+ return emit_byte(compiler, 0);
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ case 3:
+ compiler->mode32 = 1;
+ FAIL_IF(emit_groupf(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, freg, 0));
+ return emit_byte(compiler, 0x44);
+#endif /* SLJIT_CONFIG_X86_64 */
+ }
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_mov(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg, sljit_s32 lane_index,
+ sljit_s32 srcdst, sljit_sw srcdstw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_u8 *inst;
+ sljit_u8 opcode = 0;
+ sljit_uw size;
+ sljit_s32 freg_orig = freg;
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ sljit_s32 srcdst_is_ereg = 0;
+ sljit_s32 srcdst_orig = 0;
+ sljit_sw srcdstw_orig = 0;
+#endif /* SLJIT_CONFIG_X86_32 */
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_lane_mov(compiler, type, freg, lane_index, srcdst, srcdstw));
+
+ ADJUST_LOCAL_OFFSET(srcdst, srcdstw);
+
+ if (reg_size == 5) {
+ if (!(cpu_feature_list & CPU_FEATURE_AVX2))
+ return SLJIT_ERR_UNSUPPORTED;
+ } else if (reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ if ((type & SLJIT_SIMD_FLOAT) ? (elem_size < 2 || elem_size > 3) : elem_size > 2)
+ return SLJIT_ERR_UNSUPPORTED;
+#else /* SLJIT_CONFIG_X86_32 */
+ if (elem_size > 3 || ((type & SLJIT_SIMD_FLOAT) && elem_size < 2))
+ return SLJIT_ERR_UNSUPPORTED;
+#endif /* SLJIT_CONFIG_X86_32 */
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ compiler->mode32 = 1;
+#else /* !SLJIT_CONFIG_X86_64 */
+ if (!(type & SLJIT_SIMD_FLOAT)) {
+ CHECK_EXTRA_REGS(srcdst, srcdstw, srcdst_is_ereg = 1);
+
+ if ((type & SLJIT_SIMD_STORE) && ((srcdst_is_ereg && elem_size < 2) || (elem_size == 0 && (type & SLJIT_SIMD_LANE_SIGNED) && FAST_IS_REG(srcdst) && reg_map[srcdst] >= 4))) {
+ srcdst_orig = srcdst;
+ srcdstw_orig = srcdstw;
+ srcdst = TMP_REG1;
+ srcdstw = 0;
+ }
+ }
+#endif /* SLJIT_CONFIG_X86_64 */
+
+ if (type & SLJIT_SIMD_LANE_ZERO) {
+ if (lane_index == 0) {
+ if (!(type & SLJIT_SIMD_FLOAT)) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ if (elem_size == 3) {
+ compiler->mode32 = 0;
+ elem_size = 2;
+ }
+#endif /* SLJIT_CONFIG_X86_64 */
+ if (srcdst == SLJIT_IMM) {
+ if (elem_size == 0)
+ srcdstw = (sljit_u8)srcdstw;
+ else if (elem_size == 1)
+ srcdstw = (sljit_u16)srcdstw;
+
+ EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, srcdstw);
+ srcdst = TMP_REG1;
+ srcdstw = 0;
+ elem_size = 2;
+ }
+
+ if (elem_size == 2) {
+ if (reg_size == 4)
+ return emit_groupf(compiler, MOVD_x_rm | EX86_PREF_66 | EX86_SSE2_OP1, freg, srcdst, srcdstw);
+ return emit_vex_instruction(compiler, MOVD_x_rm | VEX_AUTO_W | EX86_PREF_66 | EX86_SSE2_OP1, freg, 0, srcdst, srcdstw);
+ }
+ } else if (srcdst & SLJIT_MEM) {
+ SLJIT_ASSERT(elem_size == 2 || elem_size == 3);
+
+ if (reg_size == 4)
+ return emit_groupf(compiler, MOVSD_x_xm | (elem_size == 2 ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2, freg, srcdst, srcdstw);
+ return emit_vex_instruction(compiler, MOVSD_x_xm | (elem_size == 2 ? EX86_PREF_F3 : EX86_PREF_F2) | EX86_SSE2, freg, 0, srcdst, srcdstw);
+ } else if (elem_size == 3) {
+ if (reg_size == 4)
+ return emit_groupf(compiler, MOVQ_x_xm | EX86_PREF_F3 | EX86_SSE2, freg, srcdst, 0);
+ return emit_vex_instruction(compiler, MOVQ_x_xm | EX86_PREF_F3 | EX86_SSE2, freg, 0, srcdst, 0);
+ }
+ }
+
+ if (reg_size == 5 && lane_index >= (1 << (4 - elem_size))) {
+ freg = TMP_FREG;
+ lane_index -= (1 << (4 - elem_size));
+ } else if ((type & SLJIT_SIMD_FLOAT) && freg == srcdst) {
+ FAIL_IF(emit_sse2_load(compiler, elem_size == 2, TMP_FREG, srcdst, srcdstw));
+ srcdst = TMP_FREG;
+ srcdstw = 0;
+ }
+
+ size = ((!(type & SLJIT_SIMD_FLOAT) || elem_size != 2) ? EX86_PREF_66 : 0)
+ | ((type & SLJIT_SIMD_FLOAT) ? XORPD_x_xm : PXOR_x_xm) | EX86_SSE2;
+
+ if (reg_size == 5)
+ FAIL_IF(emit_vex_instruction(compiler, size | VEX_256 | VEX_SSE2_OPV, freg, freg, freg, 0));
+ else
+ FAIL_IF(emit_groupf(compiler, size, freg, freg, 0));
+ } else if (reg_size == 5 && lane_index >= (1 << (4 - elem_size))) {
+ FAIL_IF(emit_vex_instruction(compiler, ((type & SLJIT_SIMD_FLOAT) ? VEXTRACTF128_x_ym : VEXTRACTI128_x_ym) | VEX_256 | EX86_PREF_66 | VEX_OP_0F3A | EX86_SSE2, freg, 0, TMP_FREG, 0));
+ FAIL_IF(emit_byte(compiler, 1));
+
+ freg = TMP_FREG;
+ lane_index -= (1 << (4 - elem_size));
+ }
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ if (elem_size == 3) {
+ if (srcdst & SLJIT_MEM) {
+ if (type & SLJIT_SIMD_STORE)
+ size = lane_index == 0 ? MOVLPD_m_x : MOVHPD_m_x;
+ else
+ size = lane_index == 0 ? MOVLPD_x_m : MOVHPD_x_m;
+
+ FAIL_IF(emit_groupf(compiler, size | EX86_PREF_66 | EX86_SSE2, freg, srcdst, srcdstw));
+
+ /* In case of store, freg is not TMP_FREG. */
+ } else if (type & SLJIT_SIMD_STORE) {
+ if (lane_index == 1)
+ return emit_groupf(compiler, MOVHLPS_x_x | EX86_SSE2, srcdst, freg, 0);
+ return emit_sse2_load(compiler, 0, srcdst, freg, 0);
+ } else {
+ if (lane_index == 1)
+ FAIL_IF(emit_groupf(compiler, MOVLHPS_x_x | EX86_SSE2, freg, srcdst, 0));
+ else
+ FAIL_IF(emit_sse2_store(compiler, 0, freg, 0, srcdst));
+ }
+ } else if (type & SLJIT_SIMD_STORE) {
+ if (lane_index == 0)
+ return emit_sse2_store(compiler, 1, srcdst, srcdstw, freg);
+
+ if (srcdst & SLJIT_MEM) {
+ FAIL_IF(emit_groupf_ext(compiler, EXTRACTPS_x_xm | EX86_PREF_66 | VEX_OP_0F3A | EX86_SSE2, freg, srcdst, srcdstw));
+ return emit_byte(compiler, U8(lane_index));
+ }
+
+ if (srcdst == freg)
+ size = SHUFPS_x_xm | EX86_SSE2;
+ else {
+ if (cpu_feature_list & CPU_FEATURE_AVX) {
+ FAIL_IF(emit_vex_instruction(compiler, SHUFPS_x_xm | EX86_SSE2 | VEX_SSE2_OPV, srcdst, freg, freg, 0));
+ return emit_byte(compiler, U8(lane_index));
+ }
+
+ switch (lane_index) {
+ case 1:
+ size = MOVSHDUP_x_xm | EX86_PREF_F3 | EX86_SSE2;
+ break;
+ case 2:
+ size = MOVHLPS_x_x | EX86_SSE2;
+ break;
+ default:
+ SLJIT_ASSERT(lane_index == 3);
+ size = PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2;
+ break;
+ }
+ }
+
+ FAIL_IF(emit_groupf(compiler, size, srcdst, freg, 0));
+
+ size &= 0xff;
+ if (size == SHUFPS_x_xm || size == PSHUFD_x_xm)
+ return emit_byte(compiler, U8(lane_index));
+
return SLJIT_SUCCESS;
+ } else {
+ if (lane_index != 0 || (srcdst & SLJIT_MEM)) {
+ FAIL_IF(emit_groupf_ext(compiler, INSERTPS_x_xm | EX86_PREF_66 | VEX_OP_0F3A | EX86_SSE2, freg, srcdst, srcdstw));
+ FAIL_IF(emit_byte(compiler, U8(lane_index << 4)));
+ } else
+ FAIL_IF(emit_sse2_store(compiler, 1, freg, 0, srcdst));
}
- /* Low byte is not accessible. */
- if (cpu_feature_list == 0)
- get_cpu_features();
+ if (freg != TMP_FREG || (type & SLJIT_SIMD_STORE))
+ return SLJIT_SUCCESS;
- if (cpu_feature_list & CPU_FEATURE_CMOV) {
- EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, 1);
- /* a xor reg, reg operation would overwrite the flags. */
- EMIT_MOV(compiler, dst, 0, SLJIT_IMM, 0);
+ SLJIT_ASSERT(reg_size == 5);
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 3);
- FAIL_IF(!inst);
- INC_SIZE(3);
+ if (type & SLJIT_SIMD_LANE_ZERO) {
+ FAIL_IF(emit_vex_instruction(compiler, VPERMPD_y_ym | VEX_256 | EX86_PREF_66 | VEX_OP_0F3A | VEX_W | EX86_SSE2, freg_orig, 0, TMP_FREG, 0));
+ return emit_byte(compiler, 0x4e);
+ }
+
+ FAIL_IF(emit_vex_instruction(compiler, VINSERTF128_y_y_xm | VEX_256 | EX86_PREF_66 | VEX_OP_0F3A | EX86_SSE2 | VEX_SSE2_OPV, freg_orig, freg_orig, TMP_FREG, 0));
+ return emit_byte(compiler, 1);
+ }
- *inst++ = GROUP_0F;
- /* cmovcc = setcc - 0x50. */
- *inst++ = U8(cond_set - 0x50);
- *inst++ = U8(MOD_REG | (reg_map[dst] << 3) | reg_map[TMP_REG1]);
+ if (srcdst == SLJIT_IMM) {
+ EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, srcdstw);
+ srcdst = TMP_REG1;
+ srcdstw = 0;
+ }
+
+ size = 3;
+
+ switch (elem_size) {
+ case 0:
+ opcode = (type & SLJIT_SIMD_STORE) ? PEXTRB_rm_x_i8 : PINSRB_x_rm_i8;
+ break;
+ case 1:
+ if (!(type & SLJIT_SIMD_STORE)) {
+ size = 2;
+ opcode = PINSRW_x_rm_i8;
+ } else
+ opcode = PEXTRW_rm_x_i8;
+ break;
+ case 2:
+ opcode = (type & SLJIT_SIMD_STORE) ? PEXTRD_rm_x_i8 : PINSRD_x_rm_i8;
+ break;
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ case 3:
+ /* PINSRQ / PEXTRQ */
+ opcode = (type & SLJIT_SIMD_STORE) ? PEXTRD_rm_x_i8 : PINSRD_x_rm_i8;
+ compiler->mode32 = 0;
+ break;
+#endif /* SLJIT_CONFIG_X86_64 */
+ }
+
+ inst = emit_x86_instruction(compiler, size | EX86_PREF_66 | EX86_SSE2_OP1, freg, 0, srcdst, srcdstw);
+ FAIL_IF(!inst);
+ inst[0] = GROUP_0F;
+
+ if (size == 3) {
+ inst[1] = 0x3a;
+ inst[2] = opcode;
+ } else
+ inst[1] = opcode;
+
+ FAIL_IF(emit_byte(compiler, U8(lane_index)));
+
+ if (!(type & SLJIT_SIMD_LANE_SIGNED) || (srcdst & SLJIT_MEM)) {
+ if (freg == TMP_FREG && !(type & SLJIT_SIMD_STORE)) {
+ SLJIT_ASSERT(reg_size == 5);
+
+ if (type & SLJIT_SIMD_LANE_ZERO) {
+ FAIL_IF(emit_vex_instruction(compiler, VPERMQ_y_ym | VEX_256 | EX86_PREF_66 | VEX_OP_0F3A | VEX_W | EX86_SSE2, freg_orig, 0, TMP_FREG, 0));
+ return emit_byte(compiler, 0x4e);
+ }
+
+ FAIL_IF(emit_vex_instruction(compiler, VINSERTI128_y_y_xm | VEX_256 | EX86_PREF_66 | VEX_OP_0F3A | EX86_SSE2 | VEX_SSE2_OPV, freg_orig, freg_orig, TMP_FREG, 0));
+ return emit_byte(compiler, 1);
+ }
+
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ if (srcdst_orig & SLJIT_MEM)
+ return emit_mov(compiler, srcdst_orig, srcdstw_orig, TMP_REG1, 0);
+#endif /* SLJIT_CONFIG_X86_32 */
+ return SLJIT_SUCCESS;
+ }
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ if (elem_size >= 3)
+ return SLJIT_SUCCESS;
+
+ compiler->mode32 = (type & SLJIT_32);
+
+ size = 2;
+
+ if (elem_size == 0)
+ size |= EX86_REX;
+
+ if (elem_size == 2) {
+ if (type & SLJIT_32)
return SLJIT_SUCCESS;
+
+ SLJIT_ASSERT(!(compiler->mode32));
+ size = 1;
+ }
+
+ inst = emit_x86_instruction(compiler, size, srcdst, 0, srcdst, 0);
+ FAIL_IF(!inst);
+
+ if (size != 1) {
+ inst[0] = GROUP_0F;
+ inst[1] = U8((elem_size == 0) ? MOVSX_r_rm8 : MOVSX_r_rm16);
+ } else
+ inst[0] = MOVSXD_r_rm;
+#else /* !SLJIT_CONFIG_X86_64 */
+ if (elem_size >= 2)
+ return SLJIT_SUCCESS;
+
+ FAIL_IF(emit_groupf(compiler, (elem_size == 0) ? MOVSX_r_rm8 : MOVSX_r_rm16,
+ (srcdst_orig != 0 && FAST_IS_REG(srcdst_orig)) ? srcdst_orig : srcdst, srcdst, 0));
+
+ if (srcdst_orig & SLJIT_MEM)
+ return emit_mov(compiler, srcdst_orig, srcdstw_orig, TMP_REG1, 0);
+#endif /* SLJIT_CONFIG_X86_64 */
+ return SLJIT_SUCCESS;
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_lane_replicate(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_s32 src_lane_index)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_uw pref;
+ sljit_u8 byte;
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ sljit_s32 opcode3 = TMP_REG1;
+#else /* !SLJIT_CONFIG_X86_32 */
+ sljit_s32 opcode3 = SLJIT_S0;
+#endif /* SLJIT_CONFIG_X86_32 */
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_lane_replicate(compiler, type, freg, src, src_lane_index));
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ compiler->mode32 = 1;
+#endif /* SLJIT_CONFIG_X86_64 */
+ SLJIT_ASSERT(reg_map[opcode3] == 3);
+
+ if (reg_size == 5) {
+ if (!(cpu_feature_list & CPU_FEATURE_AVX2))
+ return SLJIT_ERR_UNSUPPORTED;
+ } else if (reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ pref = 0;
+ byte = U8(src_lane_index);
+
+ if (elem_size == 3) {
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (reg_size == 5) {
+ if (src_lane_index == 0)
+ return emit_vex_instruction(compiler, VBROADCASTSD_x_xm | VEX_256 | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, 0, src, 0);
+
+ FAIL_IF(emit_vex_instruction(compiler, VPERMPD_y_ym | VEX_256 | EX86_PREF_66 | VEX_OP_0F3A | VEX_W | EX86_SSE2, freg, 0, src, 0));
+
+ byte = U8(byte | (byte << 2));
+ return emit_byte(compiler, U8(byte | (byte << 4)));
+ }
+
+ if (src_lane_index == 0)
+ return emit_groupf(compiler, MOVDDUP_x_xm | EX86_PREF_F2 | EX86_SSE2, freg, src, 0);
+
+ /* Changes it to SHUFPD_x_xm. */
+ pref = EX86_PREF_66;
+ } else if (elem_size != 2)
+ return SLJIT_ERR_UNSUPPORTED;
+ else if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (reg_size == 5) {
+ SLJIT_ASSERT(elem_size == 2);
+
+ if (src_lane_index == 0)
+ return emit_vex_instruction(compiler, VBROADCASTSS_x_xm | VEX_256 | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, 0, src, 0);
+
+ FAIL_IF(emit_vex_instruction(compiler, VPERMPD_y_ym | VEX_256 | EX86_PREF_66 | VEX_OP_0F3A | VEX_W | EX86_SSE2, freg, 0, src, 0));
+
+ byte = 0x44;
+ if (src_lane_index >= 4) {
+ byte = 0xee;
+ src_lane_index -= 4;
+ }
+
+ FAIL_IF(emit_byte(compiler, byte));
+ FAIL_IF(emit_vex_instruction(compiler, SHUFPS_x_xm | VEX_256 | pref | EX86_SSE2 | VEX_SSE2_OPV, freg, freg, freg, 0));
+ byte = U8(src_lane_index);
+ } else if (freg != src && (cpu_feature_list & CPU_FEATURE_AVX)) {
+ FAIL_IF(emit_vex_instruction(compiler, SHUFPS_x_xm | pref | EX86_SSE2 | VEX_SSE2_OPV, freg, src, src, 0));
+ } else {
+ if (freg != src)
+ FAIL_IF(emit_groupf(compiler, MOVAPS_x_xm | pref | EX86_SSE2, freg, src, 0));
+
+ FAIL_IF(emit_groupf(compiler, SHUFPS_x_xm | pref | EX86_SSE2, freg, freg, 0));
}
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 3 + 3 + 1);
- FAIL_IF(!inst);
- INC_SIZE(1 + 3 + 3 + 1);
- *inst++ = U8(XCHG_EAX_r | reg_map[TMP_REG1]);
- /* Set al to conditional flag. */
- *inst++ = GROUP_0F;
- *inst++ = cond_set;
- *inst++ = MOD_REG | 0 /* eax */;
-
- *inst++ = GROUP_0F;
- *inst++ = MOVZX_r_rm8;
- *inst++ = U8(MOD_REG | (reg_map[dst] << 3) | 0 /* eax */);
- *inst++ = U8(XCHG_EAX_r | reg_map[TMP_REG1]);
+ if (elem_size == 2) {
+ byte = U8(byte | (byte << 2));
+ byte = U8(byte | (byte << 4));
+ } else
+ byte = U8(byte | (byte << 1));
+
+ return emit_byte(compiler, U8(byte));
+ }
+
+ if (type & SLJIT_SIMD_TEST)
return SLJIT_SUCCESS;
+
+ if (elem_size == 0) {
+ if (reg_size == 5 && src_lane_index >= 16) {
+ FAIL_IF(emit_vex_instruction(compiler, VPERMQ_y_ym | VEX_256 | EX86_PREF_66 | VEX_OP_0F3A | VEX_W | EX86_SSE2, freg, 0, src, 0));
+ FAIL_IF(emit_byte(compiler, src_lane_index >= 24 ? 0xff : 0xaa));
+ src_lane_index &= 0x7;
+ src = freg;
+ }
+
+ if ((freg != src && !(cpu_feature_list & CPU_FEATURE_AVX2)) || src_lane_index != 0) {
+ pref = 0;
+
+ if ((src_lane_index & 0x3) == 0) {
+ pref = EX86_PREF_66;
+ byte = U8(src_lane_index >> 2);
+ } else if (src_lane_index < 8 && (src_lane_index & 0x1) == 0) {
+ pref = EX86_PREF_F2;
+ byte = U8(src_lane_index >> 1);
+ } else {
+ if (freg == src || !(cpu_feature_list & CPU_FEATURE_AVX2)) {
+ if (freg != src)
+ FAIL_IF(emit_groupf(compiler, MOVDQA_x_xm | EX86_PREF_66 | EX86_SSE2, freg, src, 0));
+
+ FAIL_IF(emit_groupf(compiler, PSRLDQ_x | EX86_PREF_66 | EX86_SSE2_OP2, opcode3, freg, 0));
+ } else
+ FAIL_IF(emit_vex_instruction(compiler, PSRLDQ_x | EX86_PREF_66 | EX86_SSE2_OP2 | VEX_SSE2_OPV, opcode3, freg, src, 0));
+
+ FAIL_IF(emit_byte(compiler, U8(src_lane_index)));
+ }
+
+ if (pref != 0) {
+ FAIL_IF(emit_groupf(compiler, PSHUFLW_x_xm | pref | EX86_SSE2, freg, src, 0));
+ FAIL_IF(emit_byte(compiler, byte));
+ }
+
+ src = freg;
+ }
+
+ if (cpu_feature_list & CPU_FEATURE_AVX2)
+ return emit_vex_instruction(compiler, VPBROADCASTB_x_xm | (reg_size == 5 ? VEX_256 : 0) | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, 0, src, 0);
+
+ SLJIT_ASSERT(reg_size == 4);
+ FAIL_IF(emit_groupf(compiler, PXOR_x_xm | EX86_PREF_66 | EX86_SSE2, TMP_FREG, TMP_FREG, 0));
+ return emit_groupf_ext(compiler, PSHUFB_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, TMP_FREG, 0);
}
- if (GET_OPCODE(op) == SLJIT_OR && !GET_ALL_FLAGS(op) && FAST_IS_REG(dst) && reg_map[dst] <= 4) {
- SLJIT_ASSERT(reg_map[SLJIT_R0] == 0);
+ if ((cpu_feature_list & CPU_FEATURE_AVX2) && src_lane_index == 0 && elem_size <= 3) {
+ switch (elem_size) {
+ case 1:
+ pref = VPBROADCASTW_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2;
+ break;
+ case 2:
+ pref = VPBROADCASTD_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2;
+ break;
+ default:
+ pref = VPBROADCASTQ_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2;
+ break;
+ }
- if (dst != SLJIT_R0) {
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 3 + 2 + 1);
- FAIL_IF(!inst);
- INC_SIZE(1 + 3 + 2 + 1);
- /* Set low register to conditional flag. */
- *inst++ = U8(XCHG_EAX_r | reg_map[TMP_REG1]);
- *inst++ = GROUP_0F;
- *inst++ = cond_set;
- *inst++ = MOD_REG | 0 /* eax */;
- *inst++ = OR_rm8_r8;
- *inst++ = MOD_REG | (0 /* eax */ << 3) | reg_map[dst];
- *inst++ = U8(XCHG_EAX_r | reg_map[TMP_REG1]);
+ if (reg_size == 5)
+ pref |= VEX_256;
+
+ return emit_vex_instruction(compiler, pref, freg, 0, src, 0);
+ }
+
+ if (reg_size == 5) {
+ switch (elem_size) {
+ case 1:
+ byte = U8(src_lane_index & 0x3);
+ src_lane_index >>= 2;
+ pref = PSHUFLW_x_xm | VEX_256 | ((src_lane_index & 1) == 0 ? EX86_PREF_F2 : EX86_PREF_F3) | EX86_SSE2;
+ break;
+ case 2:
+ byte = U8(src_lane_index & 0x3);
+ src_lane_index >>= 1;
+ pref = PSHUFD_x_xm | VEX_256 | EX86_PREF_66 | EX86_SSE2;
+ break;
+ case 3:
+ pref = 0;
+ break;
+ default:
+ FAIL_IF(emit_vex_instruction(compiler, VPERMQ_y_ym | VEX_256 | EX86_PREF_66 | VEX_OP_0F3A | VEX_W | EX86_SSE2, freg, 0, src, 0));
+ return emit_byte(compiler, U8(src_lane_index == 0 ? 0x44 : 0xee));
}
- else {
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 2 + 3 + 2 + 2);
+
+ if (pref != 0) {
+ FAIL_IF(emit_vex_instruction(compiler, pref, freg, 0, src, 0));
+ byte = U8(byte | (byte << 2));
+ FAIL_IF(emit_byte(compiler, U8(byte | (byte << 4))));
+
+ if (src_lane_index == 0)
+ return emit_vex_instruction(compiler, VPBROADCASTQ_x_xm | VEX_256 | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, 0, freg, 0);
+
+ src = freg;
+ }
+
+ FAIL_IF(emit_vex_instruction(compiler, VPERMQ_y_ym | VEX_256 | EX86_PREF_66 | VEX_OP_0F3A | VEX_W | EX86_SSE2, freg, 0, src, 0));
+ byte = U8(src_lane_index);
+ byte = U8(byte | (byte << 2));
+ return emit_byte(compiler, U8(byte | (byte << 4)));
+ }
+
+ switch (elem_size) {
+ case 1:
+ byte = U8(src_lane_index & 0x3);
+ src_lane_index >>= 1;
+ pref = (src_lane_index & 2) == 0 ? EX86_PREF_F2 : EX86_PREF_F3;
+
+ FAIL_IF(emit_groupf(compiler, PSHUFLW_x_xm | pref | EX86_SSE2, freg, src, 0));
+ byte = U8(byte | (byte << 2));
+ FAIL_IF(emit_byte(compiler, U8(byte | (byte << 4))));
+
+ if ((cpu_feature_list & CPU_FEATURE_AVX2) && pref == EX86_PREF_F2)
+ return emit_vex_instruction(compiler, VPBROADCASTD_x_xm | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, 0, freg, 0);
+
+ src = freg;
+ /* fallthrough */
+ case 2:
+ byte = U8(src_lane_index);
+ byte = U8(byte | (byte << 2));
+ break;
+ default:
+ byte = U8(src_lane_index << 1);
+ byte = U8(byte | (byte << 2) | 0x4);
+ break;
+ }
+
+ FAIL_IF(emit_groupf(compiler, PSHUFD_x_xm | EX86_PREF_66 | EX86_SSE2, freg, src, 0));
+ return emit_byte(compiler, U8(byte | (byte << 4)));
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_extend(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 src, sljit_sw srcw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_s32 elem2_size = SLJIT_SIMD_GET_ELEM2_SIZE(type);
+ sljit_u8 opcode;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_extend(compiler, type, freg, src, srcw));
+
+ ADJUST_LOCAL_OFFSET(src, srcw);
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ compiler->mode32 = 1;
+#endif /* SLJIT_CONFIG_X86_64 */
+
+ if (reg_size == 5) {
+ if (!(cpu_feature_list & CPU_FEATURE_AVX2))
+ return SLJIT_ERR_UNSUPPORTED;
+ } else if (reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_FLOAT) {
+ if (elem_size != 2 || elem2_size != 3)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (reg_size == 4)
+ return emit_groupf(compiler, CVTPS2PD_x_xm | EX86_SSE2, freg, src, srcw);
+ return emit_vex_instruction(compiler, CVTPS2PD_x_xm | VEX_256 | EX86_SSE2, freg, 0, src, srcw);
+ }
+
+ switch (elem_size) {
+ case 0:
+ if (elem2_size == 1)
+ opcode = (type & SLJIT_SIMD_EXTEND_SIGNED) ? PMOVSXBW_x_xm : PMOVZXBW_x_xm;
+ else if (elem2_size == 2)
+ opcode = (type & SLJIT_SIMD_EXTEND_SIGNED) ? PMOVSXBD_x_xm : PMOVZXBD_x_xm;
+ else if (elem2_size == 3)
+ opcode = (type & SLJIT_SIMD_EXTEND_SIGNED) ? PMOVSXBQ_x_xm : PMOVZXBQ_x_xm;
+ else
+ return SLJIT_ERR_UNSUPPORTED;
+ break;
+ case 1:
+ if (elem2_size == 2)
+ opcode = (type & SLJIT_SIMD_EXTEND_SIGNED) ? PMOVSXWD_x_xm : PMOVZXWD_x_xm;
+ else if (elem2_size == 3)
+ opcode = (type & SLJIT_SIMD_EXTEND_SIGNED) ? PMOVSXWQ_x_xm : PMOVZXWQ_x_xm;
+ else
+ return SLJIT_ERR_UNSUPPORTED;
+ break;
+ case 2:
+ if (elem2_size == 3)
+ opcode = (type & SLJIT_SIMD_EXTEND_SIGNED) ? PMOVSXDQ_x_xm : PMOVZXDQ_x_xm;
+ else
+ return SLJIT_ERR_UNSUPPORTED;
+ break;
+ default:
+ return SLJIT_ERR_UNSUPPORTED;
+ }
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ if (reg_size == 4)
+ return emit_groupf_ext(compiler, opcode | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, src, srcw);
+ return emit_vex_instruction(compiler, opcode | VEX_256 | EX86_PREF_66 | VEX_OP_0F38 | EX86_SSE2, freg, 0, src, srcw);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_sign(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 freg,
+ sljit_s32 dst, sljit_sw dstw)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_s32 dst_r;
+ sljit_uw pref;
+ sljit_u8 *inst;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_sign(compiler, type, freg, dst, dstw));
+
+ ADJUST_LOCAL_OFFSET(dst, dstw);
+
+ CHECK_EXTRA_REGS(dst, dstw, (void)0);
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ compiler->mode32 = 1;
+#endif /* SLJIT_CONFIG_X86_64 */
+
+ if (elem_size > 3 || ((type & SLJIT_SIMD_FLOAT) && elem_size < 2))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if (reg_size == 4) {
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ pref = EX86_PREF_66 | EX86_SSE2_OP2;
+
+ switch (elem_size) {
+ case 1:
+ FAIL_IF(emit_groupf(compiler, PACKSSWB_x_xm | EX86_PREF_66 | EX86_SSE2, TMP_FREG, freg, 0));
+ freg = TMP_FREG;
+ break;
+ case 2:
+ pref = EX86_SSE2_OP2;
+ break;
+ }
+
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
+ FAIL_IF(emit_groupf(compiler, (elem_size < 2 ? PMOVMSKB_r_x : MOVMSKPS_r_x) | pref, dst_r, freg, 0));
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ compiler->mode32 = type & SLJIT_32;
+#endif /* SLJIT_CONFIG_X86_64 */
+
+ if (elem_size == 1) {
+ inst = emit_x86_instruction(compiler, 1 | EX86_SHIFT_INS, SLJIT_IMM, 8, dst_r, 0);
FAIL_IF(!inst);
- INC_SIZE(2 + 3 + 2 + 2);
- /* Set low register to conditional flag. */
- *inst++ = XCHG_r_rm;
- *inst++ = U8(MOD_REG | (1 /* ecx */ << 3) | reg_map[TMP_REG1]);
- *inst++ = GROUP_0F;
- *inst++ = cond_set;
- *inst++ = MOD_REG | 1 /* ecx */;
- *inst++ = OR_rm8_r8;
- *inst++ = MOD_REG | (1 /* ecx */ << 3) | 0 /* eax */;
- *inst++ = XCHG_r_rm;
- *inst++ = U8(MOD_REG | (1 /* ecx */ << 3) | reg_map[TMP_REG1]);
+ inst[1] |= SHR;
}
+
+ if (dst_r == TMP_REG1)
+ return emit_mov(compiler, dst, dstw, TMP_REG1, 0);
+
return SLJIT_SUCCESS;
}
- /* Set TMP_REG1 to the bit. */
- inst = (sljit_u8*)ensure_buf(compiler, 1 + 1 + 3 + 3 + 1);
- FAIL_IF(!inst);
- INC_SIZE(1 + 3 + 3 + 1);
- *inst++ = U8(XCHG_EAX_r | reg_map[TMP_REG1]);
- /* Set al to conditional flag. */
- *inst++ = GROUP_0F;
- *inst++ = cond_set;
- *inst++ = MOD_REG | 0 /* eax */;
+ if (reg_size != 5 || !(cpu_feature_list & CPU_FEATURE_AVX2))
+ return SLJIT_ERR_UNSUPPORTED;
- *inst++ = GROUP_0F;
- *inst++ = MOVZX_r_rm8;
- *inst++ = MOD_REG | (0 << 3) /* eax */ | 0 /* eax */;
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
- *inst++ = U8(XCHG_EAX_r | reg_map[TMP_REG1]);
+ dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
- if (GET_OPCODE(op) < SLJIT_ADD)
+ if (elem_size == 1) {
+ FAIL_IF(emit_vex_instruction(compiler, VEXTRACTI128_x_ym | VEX_256 | EX86_PREF_66 | VEX_OP_0F3A | EX86_SSE2, freg, 0, TMP_FREG, 0));
+ FAIL_IF(emit_byte(compiler, 1));
+ FAIL_IF(emit_vex_instruction(compiler, PACKSSWB_x_xm | VEX_256 | EX86_PREF_66 | EX86_SSE2 | VEX_SSE2_OPV, TMP_FREG, freg, TMP_FREG, 0));
+ FAIL_IF(emit_groupf(compiler, PMOVMSKB_r_x | EX86_PREF_66 | EX86_SSE2_OP2, dst_r, TMP_FREG, 0));
+ } else {
+ pref = MOVMSKPS_r_x | VEX_256 | EX86_SSE2_OP2;
+
+ if (elem_size == 0)
+ pref = PMOVMSKB_r_x | VEX_256 | EX86_PREF_66 | EX86_SSE2_OP2;
+ else if (elem_size == 3)
+ pref |= EX86_PREF_66;
+
+ FAIL_IF(emit_vex_instruction(compiler, pref, dst_r, 0, freg, 0));
+ }
+
+ if (dst_r == TMP_REG1) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ compiler->mode32 = type & SLJIT_32;
+#endif /* SLJIT_CONFIG_X86_64 */
return emit_mov(compiler, dst, dstw, TMP_REG1, 0);
+ }
- SLJIT_SKIP_CHECKS(compiler);
- return sljit_emit_op2(compiler, op, dst_save, dstw_save, dst_save, dstw_save, TMP_REG1, 0);
+ return SLJIT_SUCCESS;
+}
+
+static sljit_s32 emit_simd_mov(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg, sljit_s32 src_freg)
+{
+ sljit_uw op = ((type & SLJIT_SIMD_FLOAT) ? MOVAPS_x_xm : MOVDQA_x_xm) | EX86_SSE2;
+
+ SLJIT_ASSERT(SLJIT_SIMD_GET_REG_SIZE(type) == 4);
+
+ if (!(type & SLJIT_SIMD_FLOAT) || SLJIT_SIMD_GET_ELEM_SIZE(type) == 3)
+ op |= EX86_PREF_66;
+
+ return emit_groupf(compiler, op, dst_freg, src_freg, 0);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_simd_op2(struct sljit_compiler *compiler, sljit_s32 type,
+ sljit_s32 dst_freg, sljit_s32 src1_freg, sljit_s32 src2_freg)
+{
+ sljit_s32 reg_size = SLJIT_SIMD_GET_REG_SIZE(type);
+ sljit_s32 elem_size = SLJIT_SIMD_GET_ELEM_SIZE(type);
+ sljit_s32 needs_move = 0;
+ sljit_uw op = 0;
+
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_simd_op2(compiler, type, dst_freg, src1_freg, src2_freg));
+
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ compiler->mode32 = 1;
#endif /* SLJIT_CONFIG_X86_64 */
+
+ if (reg_size == 5) {
+ if (!(cpu_feature_list & CPU_FEATURE_AVX2))
+ return SLJIT_ERR_UNSUPPORTED;
+ } else if (reg_size != 4)
+ return SLJIT_ERR_UNSUPPORTED;
+
+ if ((type & SLJIT_SIMD_FLOAT) && (elem_size < 2 || elem_size > 3))
+ return SLJIT_ERR_UNSUPPORTED;
+
+ switch (SLJIT_SIMD_GET_OPCODE(type)) {
+ case SLJIT_SIMD_OP2_AND:
+ op = (type & SLJIT_SIMD_FLOAT) ? ANDPD_x_xm : PAND_x_xm;
+
+ if (!(type & SLJIT_SIMD_FLOAT) || elem_size == 3)
+ op |= EX86_PREF_66;
+ break;
+ case SLJIT_SIMD_OP2_OR:
+ op = (type & SLJIT_SIMD_FLOAT) ? ORPD_x_xm : POR_x_xm;
+
+ if (!(type & SLJIT_SIMD_FLOAT) || elem_size == 3)
+ op |= EX86_PREF_66;
+ break;
+ case SLJIT_SIMD_OP2_XOR:
+ op = (type & SLJIT_SIMD_FLOAT) ? XORPD_x_xm : PXOR_x_xm;
+
+ if (!(type & SLJIT_SIMD_FLOAT) || elem_size == 3)
+ op |= EX86_PREF_66;
+ break;
+ }
+
+ if (type & SLJIT_SIMD_TEST)
+ return SLJIT_SUCCESS;
+
+ needs_move = dst_freg != src1_freg && dst_freg != src2_freg;
+
+ if (reg_size == 5 || (needs_move && (cpu_feature_list & CPU_FEATURE_AVX2))) {
+ if (reg_size == 5)
+ op |= VEX_256;
+
+ return emit_vex_instruction(compiler, op | EX86_SSE2 | VEX_SSE2_OPV, dst_freg, src1_freg, src2_freg, 0);
+ }
+
+ if (needs_move) {
+ FAIL_IF(emit_simd_mov(compiler, type, dst_freg, src1_freg));
+ } else if (dst_freg != src1_freg) {
+ SLJIT_ASSERT(dst_freg == src2_freg);
+ src2_freg = src1_freg;
+ }
+
+ FAIL_IF(emit_groupf(compiler, op | EX86_SSE2, dst_freg, src2_freg, 0));
+ return SLJIT_SUCCESS;
}
-SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_cmov(struct sljit_compiler *compiler, sljit_s32 type,
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_load(struct sljit_compiler *compiler, sljit_s32 op,
sljit_s32 dst_reg,
- sljit_s32 src, sljit_sw srcw)
+ sljit_s32 mem_reg)
{
- sljit_u8* inst;
+ CHECK_ERROR();
+ CHECK(check_sljit_emit_atomic_load(compiler, op, dst_reg, mem_reg));
+
+ SLJIT_SKIP_CHECKS(compiler);
+ return sljit_emit_op1(compiler, op, dst_reg, 0, SLJIT_MEM1(mem_reg), 0);
+}
+
+SLJIT_API_FUNC_ATTRIBUTE sljit_s32 sljit_emit_atomic_store(struct sljit_compiler *compiler, sljit_s32 op,
+ sljit_s32 src_reg,
+ sljit_s32 mem_reg,
+ sljit_s32 temp_reg)
+{
+ sljit_uw pref;
+ sljit_s32 free_reg = TMP_REG1;
+#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+ sljit_sw srcw = 0;
+ sljit_sw tempw = 0;
+#endif /* SLJIT_CONFIG_X86_32 */
CHECK_ERROR();
- CHECK(check_sljit_emit_cmov(compiler, type, dst_reg, src, srcw));
+ CHECK(check_sljit_emit_atomic_store(compiler, op, src_reg, mem_reg, temp_reg));
+ CHECK_EXTRA_REGS(src_reg, srcw, (void)0);
+ CHECK_EXTRA_REGS(temp_reg, tempw, (void)0);
+
+ SLJIT_ASSERT(FAST_IS_REG(src_reg) || src_reg == SLJIT_MEM1(SLJIT_SP));
+ SLJIT_ASSERT(FAST_IS_REG(temp_reg) || temp_reg == SLJIT_MEM1(SLJIT_SP));
+ op = GET_OPCODE(op);
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
- type &= ~SLJIT_32;
+ if ((src_reg & SLJIT_MEM) || (op == SLJIT_MOV_U8 && reg_map[src_reg] >= 4)) {
+ /* Src is virtual register or its low byte is not accessible. */
+ SLJIT_ASSERT(src_reg != SLJIT_R1);
+ free_reg = src_reg;
- if (!sljit_has_cpu_feature(SLJIT_HAS_CMOV) || (dst_reg >= SLJIT_R3 && dst_reg <= SLJIT_S3))
- return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);
-#else
- if (!sljit_has_cpu_feature(SLJIT_HAS_CMOV))
- return sljit_emit_cmov_generic(compiler, type, dst_reg, src, srcw);
-#endif
+ EMIT_MOV(compiler, TMP_REG1, 0, src_reg, srcw);
+ src_reg = TMP_REG1;
- /* ADJUST_LOCAL_OFFSET is not needed. */
- CHECK_EXTRA_REGS(src, srcw, (void)0);
+ if (mem_reg == src_reg)
+ mem_reg = TMP_REG1;
+ }
+#endif /* SLJIT_CONFIG_X86_32 */
+ if (temp_reg != SLJIT_R0) {
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
- compiler->mode32 = type & SLJIT_32;
- type &= ~SLJIT_32;
-#endif
+ compiler->mode32 = 0;
- if (SLJIT_UNLIKELY(src & SLJIT_IMM)) {
- EMIT_MOV(compiler, TMP_REG1, 0, SLJIT_IMM, srcw);
- src = TMP_REG1;
- srcw = 0;
+ EMIT_MOV(compiler, free_reg, 0, SLJIT_R0, 0);
+ EMIT_MOV(compiler, SLJIT_R0, 0, temp_reg, 0);
+
+ if (src_reg == SLJIT_R0)
+ src_reg = free_reg;
+ if (mem_reg == SLJIT_R0)
+ mem_reg = free_reg;
+#else /* !SLJIT_CONFIG_X86_64 */
+ if (src_reg == TMP_REG1 && mem_reg == SLJIT_R0 && (free_reg & SLJIT_MEM)) {
+ EMIT_MOV(compiler, SLJIT_MEM1(SLJIT_SP), 0, SLJIT_R1, 0);
+ EMIT_MOV(compiler, SLJIT_R1, 0, SLJIT_R0, 0);
+ EMIT_MOV(compiler, SLJIT_R0, 0, temp_reg, tempw);
+
+ mem_reg = SLJIT_R1;
+ free_reg = SLJIT_R1;
+ } else {
+ EMIT_MOV(compiler, free_reg, 0, SLJIT_R0, 0);
+ EMIT_MOV(compiler, SLJIT_R0, 0, temp_reg, tempw);
+
+ if (src_reg == SLJIT_R0)
+ src_reg = free_reg;
+ if (mem_reg == SLJIT_R0)
+ mem_reg = free_reg;
+ }
+#endif /* SLJIT_CONFIG_X86_64 */
}
- inst = emit_x86_instruction(compiler, 2, dst_reg, 0, src, srcw);
- FAIL_IF(!inst);
- *inst++ = GROUP_0F;
- *inst = U8(get_jump_code((sljit_uw)type) - 0x40);
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ compiler->mode32 = op != SLJIT_MOV && op != SLJIT_MOV_P;
+#endif /* SLJIT_CONFIG_X86_64 */
+
+ /* Lock prefix. */
+ FAIL_IF(emit_byte(compiler, GROUP_LOCK));
+
+ pref = 0;
+ if (op == SLJIT_MOV_U16)
+ pref = EX86_HALF_ARG | EX86_PREF_66;
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ if (op == SLJIT_MOV_U8)
+ pref = EX86_REX;
+#endif /* SLJIT_CONFIG_X86_64 */
+
+ FAIL_IF(emit_groupf(compiler, (op == SLJIT_MOV_U8 ? CMPXCHG_rm8_r : CMPXCHG_rm_r) | pref, src_reg, SLJIT_MEM1(mem_reg), 0));
+
+ if (temp_reg != SLJIT_R0) {
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+ compiler->mode32 = 0;
+ return emit_mov(compiler, SLJIT_R0, 0, TMP_REG1, 0);
+#else /* !SLJIT_CONFIG_X86_64 */
+ EMIT_MOV(compiler, SLJIT_R0, 0, free_reg, 0);
+ if (free_reg != TMP_REG1)
+ return emit_mov(compiler, free_reg, 0, (free_reg == SLJIT_R1) ? SLJIT_MEM1(SLJIT_SP) : TMP_REG1, 0);
+#endif /* SLJIT_CONFIG_X86_64 */
+ }
return SLJIT_SUCCESS;
}
@@ -3339,8 +4730,8 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_const* sljit_emit_const(struct sljit_compi
inst = (sljit_u8*)ensure_buf(compiler, 2);
PTR_FAIL_IF(!inst);
- *inst++ = 0;
- *inst++ = 2;
+ inst[0] = 0;
+ inst[1] = 2;
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
if (dst & SLJIT_MEM)
@@ -3393,8 +4784,8 @@ SLJIT_API_FUNC_ATTRIBUTE struct sljit_put_label* sljit_emit_put_label(struct slj
inst = (sljit_u8*)ensure_buf(compiler, 2);
PTR_FAIL_IF(!inst);
- *inst++ = 0;
- *inst++ = 3;
+ inst[0] = 0;
+ inst[1] = 3;
return put_label;
}
diff --git a/src/3rdparty/rfc6234/qt_attribution.json b/src/3rdparty/rfc6234/qt_attribution.json
index 1cce430cf6..3876dc00b4 100644
--- a/src/3rdparty/rfc6234/qt_attribution.json
+++ b/src/3rdparty/rfc6234/qt_attribution.json
@@ -4,7 +4,7 @@
"QDocModule": "qtcore",
"QtUsage": "Used in Qt Core (QCryptographicHash and QMessageAuthenticationCode)",
- "Description": "The RFC actually contains the code, embedded in RFC-boilerplate; presumably we extracted it; treat as final",
+ "Comment": "The RFC actually contains the code, embedded in RFC-boilerplate; presumably we extracted it; treat as final",
"Description": "Implements the Secure Hash Algorithms SHA 384 and SHA-521",
"License": "BSD 3-clause \"New\" or \"Revised\" License",
"LicenseFile": "LICENSE",
diff --git a/src/3rdparty/sha1/qt_attribution.json b/src/3rdparty/sha1/qt_attribution.json
index 8aaf5f08cb..4530add814 100644
--- a/src/3rdparty/sha1/qt_attribution.json
+++ b/src/3rdparty/sha1/qt_attribution.json
@@ -7,7 +7,7 @@
"Description": "Implements the Secure Hash Algorithms SHA 1",
"Homepage": "http://www.dominik-reichl.de/projects/csha1/",
"License": "Public Domain",
- "LicenseId": "CC0-1.0",
- "Copyright": "Copyright (C) Dominik Reichl <dominik.reichl@t-online.de>
-Copyright (C) 2016 The Qt Company Ltd"
+ "LicenseId": "LicenseRef-SHA1-Public-Domain",
+ "Copyright": ["Copyright (C) Dominik Reichl <dominik.reichl@t-online.de>",
+ "Copyright (C) 2016 The Qt Company Ltd"]
}
diff --git a/src/3rdparty/sha1/sha1.cpp b/src/3rdparty/sha1/sha1.cpp
index c42819def5..6dd25e3c15 100644
--- a/src/3rdparty/sha1/sha1.cpp
+++ b/src/3rdparty/sha1/sha1.cpp
@@ -1,46 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part 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$
-**
-****************************************************************************/
-
-/*
- Based on the public domain implementation of the SHA-1 algorithm
- Copyright (C) Dominik Reichl <dominik.reichl@t-online.de>
-*/
+// Based on the public domain implementation of the SHA-1 algorithm by Dominik Reichl
+//
+// Copyright (C) Dominik Reichl <dominik.reichl@t-online.de>
+// Copyright (C) 2016 The Qt Company Ltd.
+//
+// SPDX-License-Identifier: LicenseRef-SHA1-Public-Domain
+
#include <QtCore/qendian.h>
#ifdef Q_CC_MSVC
diff --git a/src/3rdparty/sha3/brg_endian.h b/src/3rdparty/sha3/brg_endian.h
index 9bb306e678..0baac93dc9 100644
--- a/src/3rdparty/sha3/brg_endian.h
+++ b/src/3rdparty/sha3/brg_endian.h
@@ -42,7 +42,7 @@ Changes for ARM 9/9/2010 [Downstream relative to Gladman's GitHub, upstream to Q
#elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ )
# if !defined( __MINGW32__ ) && !defined( _AIX ) && !defined(Q_OS_QNX)
# include <endian.h>
-# if !defined( __BEOS__ ) && !defined(Q_OS_RTEMS)
+# if !defined( __BEOS__ ) && !defined(Q_OS_RTEMS) && !defined(Q_OS_VXWORKS)
# include <byteswap.h>
# endif
# endif
diff --git a/src/3rdparty/sha3/brg_endian.h.patch b/src/3rdparty/sha3/brg_endian.h.patch
index 395133ad2a..41807bdbbf 100644
--- a/src/3rdparty/sha3/brg_endian.h.patch
+++ b/src/3rdparty/sha3/brg_endian.h.patch
@@ -1,6 +1,5 @@
-diff -ub /home/eddy/.sys/tmp/sha/brg_endian.h /home/eddy/work/Qt-5.12/qtbase/src/3rdparty/sha3/brg_endian.h
---- upstream/sha/brg_endian.h 2018-10-22 16:27:04.106128670 +0200
-+++ qtbase/src/3rdparty/sha3/brg_endian.h 2018-10-22 16:30:35.098891562 +0200
+--- /home/jacek/git/sha/brg_endian.h 2023-07-25 23:20:58.157487162 +0200
++++ brg_endian.h 2023-07-25 23:27:20.889797352 +0200
@@ -16,6 +16,7 @@
and fitness for purpose.
---------------------------------------------------------------------------
@@ -9,6 +8,18 @@ diff -ub /home/eddy/.sys/tmp/sha/brg_endian.h /home/eddy/work/Qt-5.12/qtbase/src
*/
#ifndef _BRG_ENDIAN_H
+@@ -39,9 +40,9 @@
+ defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ )
+ # include <machine/endian.h>
+ #elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ )
+-# if !defined( __MINGW32__ ) && !defined( _AIX )
++# if !defined( __MINGW32__ ) && !defined( _AIX ) && !defined(Q_OS_QNX)
+ # include <endian.h>
+-# if !defined( __BEOS__ )
++# if !defined( __BEOS__ ) && !defined(Q_OS_RTEMS) && !defined(Q_OS_VXWORKS)
+ # include <byteswap.h>
+ # endif
+ # endif
@@ -119,12 +120,18 @@
defined( THINK_C ) || defined( __VMCMS__ ) || defined( _AIX )
# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN
@@ -30,5 +41,3 @@ diff -ub /home/eddy/.sys/tmp/sha/brg_endian.h /home/eddy/work/Qt-5.12/qtbase/src
#endif
#endif
-
-Diff finished. Mon Oct 22 16:31:46 2018
diff --git a/src/3rdparty/sha3/qt_attribution.json b/src/3rdparty/sha3/qt_attribution.json
index 3e847aba20..1bd974144b 100644
--- a/src/3rdparty/sha3/qt_attribution.json
+++ b/src/3rdparty/sha3/qt_attribution.json
@@ -4,7 +4,7 @@
"Name": "Secure Hash Algorithm SHA-3 - brg_endian",
"QDocModule": "qtcore",
"QtUsage": "Used in Qt Core (QCryptographicHash).",
- "Files": "apply brg_endian.h.patch to upstream from https://github.com/BrianGladman/sha/",
+ "Comment": "apply brg_endian.h.patch to upstream from https://github.com/BrianGladman/sha/",
"Files": "brg_endian.h",
"Description": "SHA-3, originally known as Keccak, is a cryptographic hash function.",
@@ -19,18 +19,27 @@
"Name": "Secure Hash Algorithm SHA-3 - Keccak",
"QDocModule": "qtcore",
"QtUsage": "Used in Qt Core (QCryptographicHash).",
- "Files": "https://keccak.team/obsolete/KeccakReferenceAndOptimized-3.2.zip - but it's obsolete",
- "Files": "With overflow.patch applied",
- "Files": "KeccakF-1600-32-rvk.macros KeccakF-1600-32.macros KeccakF-1600-64.macros KeccakF-1600-interface.h KeccakF-1600-opt32.c KeccakF-1600-opt64.c KeccakF-1600-unrolling.macros KeccakNISTInterface.c KeccakNISTInterface.h KeccakSponge.c KeccakSponge.h",
+ "Comment": { "ObsoleteSource":
+ "https://keccak.team/obsolete/KeccakReferenceAndOptimized-3.2.zip",
+ "PatchApplied": "overflow.patch" },
+ "Files": [ "KeccakF-1600-32-rvk.macros",
+ "KeccakF-1600-32.macros",
+ "KeccakF-1600-64.macros",
+ "KeccakF-1600-interface.h",
+ "KeccakF-1600-opt32.c",
+ "KeccakF-1600-opt64.c",
+ "KeccakF-1600-unrolling.macros",
+ "KeccakNISTInterface.c",
+ "KeccakNISTInterface.h",
+ "KeccakSponge.c",
+ "KeccakSponge.h" ],
"Description": "SHA-3, originally known as Keccak, is a cryptographic hash function.",
"Version": "3.2",
"License": "Creative Commons Zero v1.0 Universal",
"LicenseId": "CC0-1.0",
"LicenseFile": "CC0_LICENSE",
- "Copyright": "Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche.
-
-To the extent possible under law, the implementers have waived all copyright
+ "Copyright": "Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche.\nTo the extent possible under law, the implementers have waived all copyright
and related or neighboring rights to the source code in this file."
}
]
diff --git a/src/3rdparty/sqlite/qt_attribution.json b/src/3rdparty/sqlite/qt_attribution.json
index 7d6c542eed..c5a5b12062 100644
--- a/src/3rdparty/sqlite/qt_attribution.json
+++ b/src/3rdparty/sqlite/qt_attribution.json
@@ -3,12 +3,13 @@
"Name": "SQLite",
"QDocModule": "qtsql",
"QtUsage": "Used in Qt SQL Lite plugin. Configure Qt with -system-sqlite or -no-sqlite to avoid.",
+ "SecurityCritical": true,
"Description": "SQLite is a small C library that implements a self-contained, embeddable, zero-configuration SQL database engine.",
"Homepage": "https://www.sqlite.org/",
- "Version": "3.41.1",
- "DownloadLocation": "https://sqlite.org/2023/sqlite-amalgamation-3410100.zip",
- "License": "Public Domain",
- "LicenseId": "CC0-1.0",
+ "Version": "3.45.3",
+ "DownloadLocation": "https://www.sqlite.org/2024/sqlite-amalgamation-3450300.zip",
+ "License": "SQLite Blessing",
+ "LicenseId": "blessing",
"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 e4d8860e19..08c593e55c 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.41.1. By combining all the individual C code files into this
+** version 3.45.3. 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
@@ -16,6 +16,9 @@
** if you want a wrapper to interface SQLite with your choice of programming
** language. The code for the "sqlite3" command-line shell is also in a
** separate file. This file contains only code for the core SQLite library.
+**
+** The content in this amalgamation comes from Fossil check-in
+** 8653b758870e6ef0c98d46b3ace27849054a.
*/
#define SQLITE_CORE 1
#define SQLITE_AMALGAMATION 1
@@ -50,11 +53,11 @@
** used on lines of code that actually
** implement parts of coverage testing.
**
-** OPTIMIZATION-IF-TRUE - This branch is allowed to alway be false
+** OPTIMIZATION-IF-TRUE - This branch is allowed to always be false
** and the correct answer is still obtained,
** though perhaps more slowly.
**
-** OPTIMIZATION-IF-FALSE - This branch is allowed to alway be true
+** OPTIMIZATION-IF-FALSE - This branch is allowed to always be true
** and the correct answer is still obtained,
** though perhaps more slowly.
**
@@ -123,6 +126,10 @@
#define SQLITE_4_BYTE_ALIGNED_MALLOC
#endif /* defined(_MSC_VER) && !defined(_WIN64) */
+#if !defined(HAVE_LOG2) && defined(_MSC_VER) && _MSC_VER<1800
+#define HAVE_LOG2 0
+#endif /* !defined(HAVE_LOG2) && defined(_MSC_VER) && _MSC_VER<1800 */
+
#endif /* SQLITE_MSVC_H */
/************** End of msvc.h ************************************************/
@@ -452,9 +459,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.41.1"
-#define SQLITE_VERSION_NUMBER 3041001
-#define SQLITE_SOURCE_ID "2023-03-10 12:13:52 20399f3eda5ec249d147ba9e48da6e87f969d7966a9a896764ca437ff7e737ff"
+#define SQLITE_VERSION "3.45.3"
+#define SQLITE_VERSION_NUMBER 3045003
+#define SQLITE_SOURCE_ID "2024-04-15 13:34:05 8653b758870e6ef0c98d46b3ace27849054af85da891eb121e9aaa537f1e8355"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -726,6 +733,8 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
** <li> The application must not modify the SQL statement text passed into
** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
+** <li> The application must not dereference the arrays or string pointers
+** passed as the 3rd and 4th callback parameters after it returns.
** </ul>
*/
SQLITE_API int sqlite3_exec(
@@ -834,6 +843,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8))
+#define SQLITE_IOERR_IN_PAGE (SQLITE_IOERR | (34<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
@@ -1496,7 +1506,7 @@ struct sqlite3_io_methods {
** by clients within the current process, only within other processes.
**
** <li>[[SQLITE_FCNTL_CKSM_FILE]]
-** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use interally by the
+** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use internally by the
** [checksum VFS shim] only.
**
** <li>[[SQLITE_FCNTL_RESET_CACHE]]
@@ -1961,20 +1971,23 @@ SQLITE_API int sqlite3_os_end(void);
** must ensure that no other SQLite interfaces are invoked by other
** threads while sqlite3_config() is running.</b>
**
-** The sqlite3_config() interface
-** may only be invoked prior to library initialization using
-** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()].
-** ^If sqlite3_config() is called after [sqlite3_initialize()] and before
-** [sqlite3_shutdown()] then it will return SQLITE_MISUSE.
-** Note, however, that ^sqlite3_config() can be called as part of the
-** implementation of an application-defined [sqlite3_os_init()].
-**
** The first argument to sqlite3_config() is an integer
** [configuration option] that determines
** what property of SQLite is to be configured. Subsequent arguments
** vary depending on the [configuration option]
** in the first argument.
**
+** For most configuration options, the sqlite3_config() interface
+** may only be invoked prior to library initialization using
+** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()].
+** The exceptional configuration options that may be invoked at any time
+** are called "anytime configuration options".
+** ^If sqlite3_config() is called after [sqlite3_initialize()] and before
+** [sqlite3_shutdown()] with a first argument that is not an anytime
+** configuration option, then the sqlite3_config() call will return SQLITE_MISUSE.
+** Note, however, that ^sqlite3_config() can be called as part of the
+** implementation of an application-defined [sqlite3_os_init()].
+**
** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK].
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
@@ -2082,6 +2095,23 @@ struct sqlite3_mem_methods {
** These constants are the available integer configuration options that
** can be passed as the first argument to the [sqlite3_config()] interface.
**
+** Most of the configuration options for sqlite3_config()
+** will only work if invoked prior to [sqlite3_initialize()] or after
+** [sqlite3_shutdown()]. The few exceptions to this rule are called
+** "anytime configuration options".
+** ^Calling [sqlite3_config()] with a first argument that is not an
+** anytime configuration option in between calls to [sqlite3_initialize()] and
+** [sqlite3_shutdown()] is a no-op that returns SQLITE_MISUSE.
+**
+** The set of anytime configuration options can change (by insertions
+** and/or deletions) from one release of SQLite to the next.
+** As of SQLite version 3.42.0, the complete set of anytime configuration
+** options is:
+** <ul>
+** <li> SQLITE_CONFIG_LOG
+** <li> SQLITE_CONFIG_PCACHE_HDRSZ
+** </ul>
+**
** New configuration options may be added in future releases of SQLite.
** Existing configuration options might be discontinued. Applications
** should check the return code from [sqlite3_config()] to make sure that
@@ -2412,7 +2442,7 @@ struct sqlite3_mem_methods {
** is stored in each sorted record and the required column values loaded
** from the database as records are returned in sorted order. The default
** value for this option is to never use this optimization. Specifying a
-** negative value for this option restores the default behaviour.
+** negative value for this option restores the default behavior.
** This option is only available if SQLite is compiled with the
** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option.
**
@@ -2426,30 +2456,46 @@ struct sqlite3_mem_methods {
** configuration setting is never used, then the default maximum is determined
** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that
** compile-time option is not set, then the default maximum is 1073741824.
+**
+** [[SQLITE_CONFIG_ROWID_IN_VIEW]]
+** <dt>SQLITE_CONFIG_ROWID_IN_VIEW
+** <dd>The SQLITE_CONFIG_ROWID_IN_VIEW option enables or disables the ability
+** for VIEWs to have a ROWID. The capability can only be enabled if SQLite is
+** compiled with -DSQLITE_ALLOW_ROWID_IN_VIEW, in which case the capability
+** defaults to on. This configuration option queries the current setting or
+** changes the setting to off or on. The argument is a pointer to an integer.
+** If that integer initially holds a value of 1, then the ability for VIEWs to
+** have ROWIDs is activated. If the integer initially holds zero, then the
+** ability is deactivated. Any other initial value for the integer leaves the
+** setting unchanged. After changes, if any, the integer is written with
+** a 1 or 0, if the ability for VIEWs to have ROWIDs is on or off. If SQLite
+** is compiled without -DSQLITE_ALLOW_ROWID_IN_VIEW (which is the usual and
+** recommended case) then the integer is always filled with zero, regardless
+** if its initial value.
** </dl>
*/
-#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
-#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
-#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
-#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */
-#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */
-#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
-#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
-#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
-#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
-#define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */
-#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */
-/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
-#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
-#define SQLITE_CONFIG_PCACHE 14 /* no-op */
-#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */
-#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
-#define SQLITE_CONFIG_URI 17 /* int */
-#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */
-#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
+#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
+#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
+#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */
+#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */
+#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
+#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
+#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
+#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
+#define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */
+#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */
+/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
+#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
+#define SQLITE_CONFIG_PCACHE 14 /* no-op */
+#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */
+#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
+#define SQLITE_CONFIG_URI 17 /* int */
+#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
-#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
-#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
+#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
+#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
@@ -2457,6 +2503,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */
#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */
#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */
+#define SQLITE_CONFIG_ROWID_IN_VIEW 30 /* int* */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -2587,7 +2634,7 @@ struct sqlite3_mem_methods {
** 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
+** override this behavior. The first parameter passed to this operation
** is an integer - positive to disable checkpoints-on-close, or zero (the
** default) to enable them, and negative to leave the setting unchanged.
** The second parameter is a pointer to an integer
@@ -2684,7 +2731,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DML]]
-** <dt>SQLITE_DBCONFIG_DQS_DML</td>
+** <dt>SQLITE_DBCONFIG_DQS_DML</dt>
** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DML statements
** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
@@ -2693,7 +2740,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DDL]]
-** <dt>SQLITE_DBCONFIG_DQS_DDL</td>
+** <dt>SQLITE_DBCONFIG_DQS_DDL</dt>
** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DDL statements,
** such as CREATE TABLE and CREATE INDEX. The
@@ -2702,7 +2749,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
-** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td>
+** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</dt>
** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
** assume that database schemas are untainted by malicious content.
** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
@@ -2722,7 +2769,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]]
-** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</td>
+** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</dt>
** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
** the legacy file format flag. When activated, this flag causes all newly
** created database file to have a schema format version number (the 4-byte
@@ -2731,7 +2778,7 @@ struct sqlite3_mem_methods {
** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting,
** newly created databases are generally not understandable by SQLite versions
** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there
-** is now scarcely any need to generated database files that are compatible
+** is now scarcely any need to generate database files that are compatible
** all the way back to version 3.0.0, and so this setting is of little
** practical use, but is provided so that SQLite can continue to claim the
** ability to generate new database files that are compatible with version
@@ -2740,8 +2787,40 @@ struct sqlite3_mem_methods {
** the [VACUUM] command will fail with an obscure error when attempting to
** process a table with generated columns and a descending index. This is
** not considered a bug since SQLite versions 3.3.0 and earlier do not support
-** either generated columns or decending indexes.
+** either generated columns or descending indexes.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]]
+** <dt>SQLITE_DBCONFIG_STMT_SCANSTATUS</dt>
+** <dd>The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in
+** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears
+** a flag that enables collection of the sqlite3_stmt_scanstatus_v2()
+** statistics. For statistics to be collected, the flag must be set on
+** the database handle both when the SQL statement is prepared and when it
+** is stepped. The flag is set (collection of statistics is enabled)
+** by default. This option takes two arguments: an integer and a pointer to
+** an integer.. The first argument is 1, 0, or -1 to enable, disable, or
+** leave unchanged the statement scanstatus option. If the second argument
+** is not NULL, then the value of the statement scanstatus setting after
+** processing the first argument is written into the integer that the second
+** argument points to.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_REVERSE_SCANORDER]]
+** <dt>SQLITE_DBCONFIG_REVERSE_SCANORDER</dt>
+** <dd>The SQLITE_DBCONFIG_REVERSE_SCANORDER option changes the default order
+** in which tables and indexes are scanned so that the scans start at the end
+** and work toward the beginning rather than starting at the beginning and
+** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the
+** same as setting [PRAGMA reverse_unordered_selects]. This option takes
+** two arguments which are an integer and a pointer to an integer. The first
+** argument is 1, 0, or -1 to enable, disable, or leave unchanged the
+** reverse scan order flag, respectively. If the second argument is not NULL,
+** then 0 or 1 is written into the integer that the second argument points to
+** depending on if the reverse scan order flag is set after processing the
+** first argument.
** </dd>
+**
** </dl>
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
@@ -2762,7 +2841,9 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */
#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */
-#define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */
+#define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */
+#define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */
+#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@@ -2987,6 +3068,7 @@ SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3*);
**
** ^The [sqlite3_is_interrupted(D)] interface can be used to determine whether
** or not an interrupt is currently in effect for [database connection] D.
+** It returns 1 if an interrupt is currently in effect, or 0 otherwise.
*/
SQLITE_API void sqlite3_interrupt(sqlite3*);
SQLITE_API int sqlite3_is_interrupted(sqlite3*);
@@ -3640,8 +3722,10 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
** 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().
+** ^Each call to either sqlite3_trace(D,X,P) or sqlite3_trace_v2(D,M,X,P)
+** overrides (cancels) all prior calls to sqlite3_trace(D,X,P) or
+** sqlite3_trace_v2(D,M,X,P) for the [database connection] D. Each
+** database connection may have at most one trace callback.
**
** ^The X callback is invoked whenever any of the events identified by
** mask M occur. ^The integer return value from the callback is currently
@@ -4010,7 +4094,7 @@ SQLITE_API int sqlite3_open_v2(
** as F) must be one of:
** <ul>
** <li> A database filename pointer created by the SQLite core and
-** passed into the xOpen() method of a VFS implemention, or
+** passed into the xOpen() method of a VFS implementation, or
** <li> A filename obtained from [sqlite3_db_filename()], or
** <li> A new filename constructed using [sqlite3_create_filename()].
** </ul>
@@ -4123,7 +4207,7 @@ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*);
/*
** CAPI3REF: Create and Destroy VFS Filenames
**
-** These interfces are provided for use by [VFS shim] implementations and
+** These interfaces are provided for use by [VFS shim] implementations and
** are not useful outside of that context.
**
** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of
@@ -4202,14 +4286,17 @@ SQLITE_API void sqlite3_free_filename(sqlite3_filename);
** </ul>
**
** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
-** text that describes the error, as either UTF-8 or UTF-16 respectively.
+** text that describes the error, as either UTF-8 or UTF-16 respectively,
+** or NULL if no error message is available.
+** (See how SQLite handles [invalid UTF] for exceptions to this rule.)
** ^(Memory to hold the error message string is managed internally.
** The application does not need to worry about freeing the result.
** However, the error string might be overwritten or deallocated by
** subsequent calls to other SQLite interface functions.)^
**
-** ^The sqlite3_errstr() interface returns the English-language text
-** that describes the [result code], as UTF-8.
+** ^The sqlite3_errstr(E) interface returns the English-language text
+** that describes the [result code] E, as UTF-8, or NULL if E is not an
+** result code for which a text error message is available.
** ^(Memory to hold the error message string is managed internally
** and must not be freed by the application)^.
**
@@ -4671,6 +4758,41 @@ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt);
/*
+** CAPI3REF: Change The EXPLAIN Setting For A Prepared Statement
+** METHOD: sqlite3_stmt
+**
+** The sqlite3_stmt_explain(S,E) interface changes the EXPLAIN
+** setting for [prepared statement] S. If E is zero, then S becomes
+** a normal prepared statement. If E is 1, then S behaves as if
+** its SQL text began with "[EXPLAIN]". If E is 2, then S behaves as if
+** its SQL text began with "[EXPLAIN QUERY PLAN]".
+**
+** Calling sqlite3_stmt_explain(S,E) might cause S to be reprepared.
+** SQLite tries to avoid a reprepare, but a reprepare might be necessary
+** on the first transition into EXPLAIN or EXPLAIN QUERY PLAN mode.
+**
+** Because of the potential need to reprepare, a call to
+** sqlite3_stmt_explain(S,E) will fail with SQLITE_ERROR if S cannot be
+** reprepared because it was created using [sqlite3_prepare()] instead of
+** the newer [sqlite3_prepare_v2()] or [sqlite3_prepare_v3()] interfaces and
+** hence has no saved SQL text with which to reprepare.
+**
+** Changing the explain setting for a prepared statement does not change
+** the original SQL text for the statement. Hence, if the SQL text originally
+** began with EXPLAIN or EXPLAIN QUERY PLAN, but sqlite3_stmt_explain(S,0)
+** is called to convert the statement into an ordinary statement, the EXPLAIN
+** or EXPLAIN QUERY PLAN keywords will still appear in the sqlite3_sql(S)
+** output, even though the statement now acts like a normal SQL statement.
+**
+** This routine returns SQLITE_OK if the explain mode is successfully
+** changed, or an error code if the explain mode could not be changed.
+** The explain mode cannot be changed while a statement is active.
+** Hence, it is good practice to call [sqlite3_reset(S)]
+** immediately prior to calling sqlite3_stmt_explain(S,E).
+*/
+SQLITE_API int sqlite3_stmt_explain(sqlite3_stmt *pStmt, int eMode);
+
+/*
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
** METHOD: sqlite3_stmt
**
@@ -4833,7 +4955,7 @@ typedef struct sqlite3_context sqlite3_context;
** with it may be passed. ^It is called to dispose of the BLOB or string even
** if the call to the bind API fails, except the destructor is not called if
** the third parameter is a NULL pointer or the fourth parameter is negative.
-** ^ (2) The special constant, [SQLITE_STATIC], may be passsed to indicate that
+** ^ (2) The special constant, [SQLITE_STATIC], may be passed to indicate that
** the application remains responsible for disposing of the object. ^In this
** case, the object and the provided pointer to it must remain valid until
** either the prepared statement is finalized or the same SQL parameter is
@@ -5512,20 +5634,33 @@ SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
** ^The [sqlite3_reset(S)] interface resets the [prepared statement] S
** back to the beginning of its program.
**
-** ^If the most recent call to [sqlite3_step(S)] for the
-** [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE],
-** or if [sqlite3_step(S)] has never before been called on S,
-** then [sqlite3_reset(S)] returns [SQLITE_OK].
+** ^The return code from [sqlite3_reset(S)] indicates whether or not
+** the previous evaluation of prepared statement S completed successfully.
+** ^If [sqlite3_step(S)] has never before been called on S or if
+** [sqlite3_step(S)] has not been called since the previous call
+** to [sqlite3_reset(S)], then [sqlite3_reset(S)] will return
+** [SQLITE_OK].
**
** ^If the most recent call to [sqlite3_step(S)] for the
** [prepared statement] S indicated an error, then
** [sqlite3_reset(S)] returns an appropriate [error code].
+** ^The [sqlite3_reset(S)] interface might also return an [error code]
+** if there were no prior errors but the process of resetting
+** the prepared statement caused a new error. ^For example, if an
+** [INSERT] statement with a [RETURNING] clause is only stepped one time,
+** that one call to [sqlite3_step(S)] might return SQLITE_ROW but
+** the overall statement might still fail and the [sqlite3_reset(S)] call
+** might return SQLITE_BUSY if locking constraints prevent the
+** database change from committing. Therefore, it is important that
+** applications check the return code from [sqlite3_reset(S)] even if
+** no prior call to [sqlite3_step(S)] indicated a problem.
**
** ^The [sqlite3_reset(S)] interface does not change the values
** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S.
*/
SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
+
/*
** CAPI3REF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}
@@ -5736,7 +5871,7 @@ SQLITE_API int sqlite3_create_window_function(
** [application-defined SQL function]
** that has side-effects or that could potentially leak sensitive information.
** This will prevent attacks in which an application is tricked
-** into using a database file that has had its schema surreptiously
+** into using a database file that has had its schema surreptitiously
** modified to invoke the application-defined function in ways that are
** harmful.
** <p>
@@ -5772,13 +5907,27 @@ SQLITE_API int sqlite3_create_window_function(
** </dd>
**
** [[SQLITE_SUBTYPE]] <dt>SQLITE_SUBTYPE</dt><dd>
-** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call
+** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call
** [sqlite3_value_subtype()] to inspect the sub-types of its arguments.
-** Specifying this flag makes no difference for scalar or aggregate user
-** functions. However, if it is not specified for a user-defined window
-** function, then any sub-types belonging to arguments passed to the window
-** function may be discarded before the window function is called (i.e.
-** sqlite3_value_subtype() will always return 0).
+** This flag instructs SQLite to omit some corner-case optimizations that
+** might disrupt the operation of the [sqlite3_value_subtype()] function,
+** causing it to return zero rather than the correct subtype().
+** SQL functions that invokes [sqlite3_value_subtype()] should have this
+** property. If the SQLITE_SUBTYPE property is omitted, then the return
+** value from [sqlite3_value_subtype()] might sometimes be zero even though
+** a non-zero subtype was specified by the function argument expression.
+**
+** [[SQLITE_RESULT_SUBTYPE]] <dt>SQLITE_RESULT_SUBTYPE</dt><dd>
+** The SQLITE_RESULT_SUBTYPE flag indicates to SQLite that a function might call
+** [sqlite3_result_subtype()] to cause a sub-type to be associated with its
+** result.
+** Every function that invokes [sqlite3_result_subtype()] should have this
+** property. If it does not, then the call to [sqlite3_result_subtype()]
+** might become a no-op if the function is used as term in an
+** [expression index]. On the other hand, SQL functions that never invoke
+** [sqlite3_result_subtype()] should avoid setting this property, as the
+** purpose of this property is to disable certain optimizations that are
+** incompatible with subtypes.
** </dd>
** </dl>
*/
@@ -5786,6 +5935,7 @@ SQLITE_API int sqlite3_create_window_function(
#define SQLITE_DIRECTONLY 0x000080000
#define SQLITE_SUBTYPE 0x000100000
#define SQLITE_INNOCUOUS 0x000200000
+#define SQLITE_RESULT_SUBTYPE 0x001000000
/*
** CAPI3REF: Deprecated Functions
@@ -5982,6 +6132,12 @@ SQLITE_API int sqlite3_value_encoding(sqlite3_value*);
** information can be used to pass a limited amount of context from
** one SQL function to another. Use the [sqlite3_result_subtype()]
** routine to set the subtype for the return value of an SQL function.
+**
+** Every [application-defined SQL function] that invoke this interface
+** should include the [SQLITE_SUBTYPE] property in the text
+** encoding argument when the function is [sqlite3_create_function|registered].
+** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype()
+** might return zero instead of the upstream subtype in some corner cases.
*/
SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*);
@@ -6080,48 +6236,56 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** METHOD: sqlite3_context
**
** These functions may be used by (non-aggregate) SQL functions to
-** associate metadata with argument values. If the same value is passed to
-** multiple invocations of the same SQL function during query execution, under
-** some circumstances the associated metadata may be preserved. An example
-** of where this might be useful is in a regular-expression matching
-** function. The compiled version of the regular expression can be stored as
-** metadata associated with the pattern string.
+** associate auxiliary data with argument values. If the same argument
+** value is passed to multiple invocations of the same SQL function during
+** query execution, under some circumstances the associated auxiliary data
+** might be preserved. An example of where this might be useful is in a
+** regular-expression matching function. The compiled version of the regular
+** expression can be stored as auxiliary data associated with the pattern string.
** Then as long as the pattern string remains the same,
** the compiled regular expression can be reused on multiple
** invocations of the same function.
**
-** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata
+** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data
** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
** value to the application-defined function. ^N is zero for the left-most
-** function argument. ^If there is no metadata
+** function argument. ^If there is no auxiliary data
** associated with the function argument, the sqlite3_get_auxdata(C,N) interface
** returns a NULL pointer.
**
-** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
-** argument of the application-defined function. ^Subsequent
+** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the
+** N-th argument of the application-defined function. ^Subsequent
** calls to sqlite3_get_auxdata(C,N) return P from the most recent
-** sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or
-** NULL if the metadata has been discarded.
+** sqlite3_set_auxdata(C,N,P,X) call if the auxiliary data is still valid or
+** NULL if the auxiliary data has been discarded.
** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL,
** 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>
+** once, when the auxiliary data is discarded.
+** SQLite is free to discard the auxiliary data 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>
+** allocation error occurs.)^
+** <li> ^(during the original sqlite3_set_auxdata() call if the function
+** is evaluated during query planning instead of during query execution,
+** as sometimes happens with [SQLITE_ENABLE_STAT4].)^ </ul>
**
-** Note the last bullet in particular. The destructor X in
+** Note the last two bullets in particular. The destructor X in
** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the
** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata()
** should be called near the end of the function implementation and the
** function implementation should not make any use of P after
-** sqlite3_set_auxdata() has been called.
-**
-** ^(In practice, metadata is preserved between function calls for
+** sqlite3_set_auxdata() has been called. Furthermore, a call to
+** sqlite3_get_auxdata() that occurs immediately after a corresponding call
+** to sqlite3_set_auxdata() might still return NULL if an out-of-memory
+** condition occurred during the sqlite3_set_auxdata() call or if the
+** function is being evaluated during query planning rather than during
+** query execution.
+**
+** ^(In practice, auxiliary data is preserved between function calls for
** function parameters that are compile-time constants, including literal
** values and [parameters] and expressions composed from the same.)^
**
@@ -6131,10 +6295,67 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
**
** These routines must be called from the same thread in which
** the SQL function is running.
+**
+** See also: [sqlite3_get_clientdata()] and [sqlite3_set_clientdata()].
*/
SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
+/*
+** CAPI3REF: Database Connection Client Data
+** METHOD: sqlite3
+**
+** These functions are used to associate one or more named pointers
+** with a [database connection].
+** A call to sqlite3_set_clientdata(D,N,P,X) causes the pointer P
+** to be attached to [database connection] D using name N. Subsequent
+** calls to sqlite3_get_clientdata(D,N) will return a copy of pointer P
+** or a NULL pointer if there were no prior calls to
+** sqlite3_set_clientdata() with the same values of D and N.
+** Names are compared using strcmp() and are thus case sensitive.
+**
+** If P and X are both non-NULL, then the destructor X is invoked with
+** argument P on the first of the following occurrences:
+** <ul>
+** <li> An out-of-memory error occurs during the call to
+** sqlite3_set_clientdata() which attempts to register pointer P.
+** <li> A subsequent call to sqlite3_set_clientdata(D,N,P,X) is made
+** with the same D and N parameters.
+** <li> The database connection closes. SQLite does not make any guarantees
+** about the order in which destructors are called, only that all
+** destructors will be called exactly once at some point during the
+** database connection closing process.
+** </ul>
+**
+** SQLite does not do anything with client data other than invoke
+** destructors on the client data at the appropriate time. The intended
+** use for client data is to provide a mechanism for wrapper libraries
+** to store additional information about an SQLite database connection.
+**
+** There is no limit (other than available memory) on the number of different
+** client data pointers (with different names) that can be attached to a
+** single database connection. However, the implementation is optimized
+** for the case of having only one or two different client data names.
+** Applications and wrapper libraries are discouraged from using more than
+** one client data name each.
+**
+** There is no way to enumerate the client data pointers
+** associated with a database connection. The N parameter can be thought
+** of as a secret key such that only code that knows the secret key is able
+** to access the associated data.
+**
+** Security Warning: These interfaces should not be exposed in scripting
+** languages or in other circumstances where it might be possible for an
+** an attacker to invoke them. Any agent that can invoke these interfaces
+** can probably also take control of the process.
+**
+** Database connection client data is only available for SQLite
+** version 3.44.0 ([dateof:3.44.0]) and later.
+**
+** See also: [sqlite3_set_auxdata()] and [sqlite3_get_auxdata()].
+*/
+SQLITE_API void *sqlite3_get_clientdata(sqlite3*,const char*);
+SQLITE_API int sqlite3_set_clientdata(sqlite3*, const char*, void*, void(*)(void*));
/*
** CAPI3REF: Constants Defining Special Destructor Behavior
@@ -6336,6 +6557,20 @@ SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
** higher order bits are discarded.
** The number of subtype bytes preserved by SQLite might increase
** in future releases of SQLite.
+**
+** Every [application-defined SQL function] that invokes this interface
+** should include the [SQLITE_RESULT_SUBTYPE] property in its
+** text encoding argument when the SQL function is
+** [sqlite3_create_function|registered]. If the [SQLITE_RESULT_SUBTYPE]
+** property is omitted from the function that invokes sqlite3_result_subtype(),
+** then in some cases the sqlite3_result_subtype() might fail to set
+** the result subtype.
+**
+** If SQLite is compiled with -DSQLITE_STRICT_SUBTYPE=1, then any
+** SQL function that invokes the sqlite3_result_subtype() interface
+** and that does not have the SQLITE_RESULT_SUBTYPE property will raise
+** an error. Future versions of SQLite might enable -DSQLITE_STRICT_SUBTYPE=1
+** by default.
*/
SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int);
@@ -6507,6 +6742,13 @@ SQLITE_API void sqlite3_activate_cerod(
** of the default VFS is not implemented correctly, or not implemented at
** all, then the behavior of sqlite3_sleep() may deviate from the description
** in the previous paragraphs.
+**
+** If a negative argument is passed to sqlite3_sleep() the results vary by
+** VFS and operating system. Some system treat a negative argument as an
+** instruction to sleep forever. Others understand it to mean do not sleep
+** at all. ^In SQLite version 3.42.0 and later, a negative
+** argument passed into sqlite3_sleep() is changed to zero before it is relayed
+** down into the xSleep method of the VFS.
*/
SQLITE_API int sqlite3_sleep(int);
@@ -6760,7 +7002,7 @@ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema);
/*
-** CAPI3REF: Allowed return values from [sqlite3_txn_state()]
+** CAPI3REF: Allowed return values from sqlite3_txn_state()
** KEYWORDS: {transaction state}
**
** These constants define the current transaction state of a database file.
@@ -6892,7 +7134,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** ^Each call to the sqlite3_autovacuum_pages() interface overrides all
** previous invocations for that database connection. ^If the callback
** argument (C) to sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer,
-** then the autovacuum steps callback is cancelled. The return value
+** then the autovacuum steps callback is canceled. The return value
** from sqlite3_autovacuum_pages() is normally SQLITE_OK, but might
** be some other error code if something goes wrong. The current
** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other
@@ -7411,6 +7653,10 @@ struct sqlite3_module {
/* The methods above are in versions 1 and 2 of the sqlite_module object.
** Those below are for version 3 and greater. */
int (*xShadowName)(const char*);
+ /* The methods above are in versions 1 through 3 of the sqlite_module object.
+ ** Those below are for version 4 and greater. */
+ int (*xIntegrity)(sqlite3_vtab *pVTab, const char *zSchema,
+ const char *zTabName, int mFlags, char **pzErr);
};
/*
@@ -7898,7 +8144,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
** code is returned and the transaction rolled back.
**
** Calling this function with an argument that is not a NULL pointer or an
-** open blob handle results in undefined behaviour. ^Calling this routine
+** open blob handle results in undefined behavior. ^Calling this routine
** with a null pointer (such as would be returned by a failed call to
** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function
** is passed a valid open blob handle, the values returned by the
@@ -8125,18 +8371,20 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
**
** ^(Some systems (for example, Windows 95) do not support the operation
** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try()
-** will always return SQLITE_BUSY. The SQLite core only ever uses
-** sqlite3_mutex_try() as an optimization so this is acceptable
-** behavior.)^
+** will always return SQLITE_BUSY. In most cases the SQLite core only uses
+** sqlite3_mutex_try() as an optimization, so this is acceptable
+** behavior. The exceptions are unix builds that set the
+** SQLITE_ENABLE_SETLK_TIMEOUT build option. In that case a working
+** sqlite3_mutex_try() is required.)^
**
** ^The sqlite3_mutex_leave() routine exits a mutex that was
** previously entered by the same thread. The behavior
** is undefined if the mutex is not currently entered by the
** calling thread or is not currently allocated.
**
-** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or
-** sqlite3_mutex_leave() is a NULL pointer, then all three routines
-** behave as no-ops.
+** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(),
+** sqlite3_mutex_leave(), or sqlite3_mutex_free() is a NULL pointer,
+** then any of the four routines behaves as a no-op.
**
** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
*/
@@ -8378,6 +8626,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_PRNG_SAVE 5
#define SQLITE_TESTCTRL_PRNG_RESTORE 6
#define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */
+#define SQLITE_TESTCTRL_FK_NO_ACTION 7
#define SQLITE_TESTCTRL_BITVEC_TEST 8
#define SQLITE_TESTCTRL_FAULT_INSTALL 9
#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10
@@ -8385,6 +8634,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_ASSERT 12
#define SQLITE_TESTCTRL_ALWAYS 13
#define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */
+#define SQLITE_TESTCTRL_JSON_SELFCHECK 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
@@ -8406,7 +8656,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_TRACEFLAGS 31
#define SQLITE_TESTCTRL_TUNE 32
#define SQLITE_TESTCTRL_LOGEST 33
-#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */
+#define SQLITE_TESTCTRL_USELONGDOUBLE 34
+#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
/*
** CAPI3REF: SQL Keyword Checking
@@ -9862,7 +10113,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
** [[SQLITE_VTAB_DIRECTONLY]]<dt>SQLITE_VTAB_DIRECTONLY</dt>
** <dd>Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the
-** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** prohibits that virtual table from being used from within triggers and
** views.
** </dd>
@@ -9870,18 +10121,28 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt>
** <dd>Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
-** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** identify that virtual table as being safe to use from within triggers
** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
** virtual table can do no serious harm even if it is controlled by a
** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS
** flag unless absolutely necessary.
** </dd>
+**
+** [[SQLITE_VTAB_USES_ALL_SCHEMAS]]<dt>SQLITE_VTAB_USES_ALL_SCHEMAS</dt>
+** <dd>Calls of the form
+** [sqlite3_vtab_config](db,SQLITE_VTAB_USES_ALL_SCHEMA) from within the
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
+** instruct the query planner to begin at least a read transaction on
+** all schemas ("main", "temp", and any ATTACH-ed databases) whenever the
+** virtual table is used.
+** </dd>
** </dl>
*/
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
#define SQLITE_VTAB_INNOCUOUS 2
#define SQLITE_VTAB_DIRECTONLY 3
+#define SQLITE_VTAB_USES_ALL_SCHEMAS 4
/*
** CAPI3REF: Determine The Virtual Table Conflict Policy
@@ -10042,7 +10303,7 @@ SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info*);
** communicated to the xBestIndex method as a
** [SQLITE_INDEX_CONSTRAINT_EQ] constraint.)^ If xBestIndex wants to use
** this constraint, it must set the corresponding
-** aConstraintUsage[].argvIndex to a postive integer. ^(Then, under
+** aConstraintUsage[].argvIndex to a positive integer. ^(Then, under
** the usual mode of handling IN operators, SQLite generates [bytecode]
** that invokes the [xFilter|xFilter() method] once for each value
** on the right-hand side of the IN operator.)^ Thus the virtual table
@@ -10471,7 +10732,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
** When the [sqlite3_blob_write()] API is used to update a blob column,
** the pre-update hook is invoked with SQLITE_DELETE. This is because the
** in this case the new values are not available. In this case, when a
-** callback made with op==SQLITE_DELETE is actuall a write using the
+** callback made with op==SQLITE_DELETE is actually a write using the
** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns
** the index of the column being written. In other cases, where the
** pre-update hook is being invoked for some other reason, including a
@@ -10732,6 +10993,13 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c
** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy
** of the database exists.
**
+** After the call, if the SQLITE_SERIALIZE_NOCOPY bit had been set,
+** the returned buffer content will remain accessible and unchanged
+** until either the next write operation on the connection or when
+** the connection is closed, and applications must not modify the
+** buffer. If the bit had been clear, the returned buffer will not
+** be accessed by SQLite after the call.
+**
** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the
** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory
** allocation error occurs.
@@ -10780,6 +11048,9 @@ SQLITE_API unsigned char *sqlite3_serialize(
** SQLite will try to increase the buffer size using sqlite3_realloc64()
** if writes on the database cause it to grow larger than M bytes.
**
+** Applications must not modify the buffer P or invalidate it before
+** the database connection D is closed.
+**
** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the
** database is currently in a read transaction or is involved in a backup
** operation.
@@ -10788,6 +11059,13 @@ SQLITE_API unsigned char *sqlite3_serialize(
** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the
** function returns SQLITE_ERROR.
**
+** The deserialized database should not be in [WAL mode]. If the database
+** is in WAL mode, then any attempt to use the database file will result
+** in an [SQLITE_CANTOPEN] error. The application can set the
+** [file format version numbers] (bytes 18 and 19) of the input database P
+** to 0x01 prior to invoking sqlite3_deserialize(D,S,P,N,M,F) to force the
+** database file into rollback mode and work around this limitation.
+**
** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the
** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then
** [sqlite3_free()] is invoked on argument P prior to returning.
@@ -11056,16 +11334,20 @@ SQLITE_API int sqlite3session_create(
SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
/*
-** CAPIREF: Conigure a Session Object
+** CAPI3REF: Configure a Session Object
** METHOD: sqlite3_session
**
** This method is used to configure a session object after it has been
-** created. At present the only valid value for the second parameter is
-** [SQLITE_SESSION_OBJCONFIG_SIZE].
+** created. At present the only valid values for the second parameter are
+** [SQLITE_SESSION_OBJCONFIG_SIZE] and [SQLITE_SESSION_OBJCONFIG_ROWID].
**
-** Arguments for sqlite3session_object_config()
+*/
+SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg);
+
+/*
+** CAPI3REF: Options for sqlite3session_object_config
**
-** The following values may passed as the the 4th parameter to
+** The following values may passed as the the 2nd parameter to
** sqlite3session_object_config().
**
** <dt>SQLITE_SESSION_OBJCONFIG_SIZE <dd>
@@ -11081,12 +11363,21 @@ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
**
** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
** the first table has been attached to the session object.
+**
+** <dt>SQLITE_SESSION_OBJCONFIG_ROWID <dd>
+** This option is used to set, clear or query the flag that enables
+** collection of data for tables with no explicit PRIMARY KEY.
+**
+** Normally, tables with no explicit PRIMARY KEY are simply ignored
+** by the sessions module. However, if this flag is set, it behaves
+** as if such tables have a column "_rowid_ INTEGER PRIMARY KEY" inserted
+** as their leftmost columns.
+**
+** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
+** the first table has been attached to the session object.
*/
-SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg);
-
-/*
-*/
-#define SQLITE_SESSION_OBJCONFIG_SIZE 1
+#define SQLITE_SESSION_OBJCONFIG_SIZE 1
+#define SQLITE_SESSION_OBJCONFIG_ROWID 2
/*
** CAPI3REF: Enable Or Disable A Session Object
@@ -11848,6 +12139,18 @@ SQLITE_API int sqlite3changeset_concat(
/*
+** CAPI3REF: Upgrade the Schema of a Changeset/Patchset
+*/
+SQLITE_API int sqlite3changeset_upgrade(
+ sqlite3 *db,
+ const char *zDb,
+ int nIn, const void *pIn, /* Input changeset */
+ int *pnOut, void **ppOut /* OUT: Inverse of input */
+);
+
+
+
+/*
** CAPI3REF: Changegroup Handle
**
** A changegroup is an object used to combine two or more
@@ -11894,6 +12197,38 @@ typedef struct sqlite3_changegroup sqlite3_changegroup;
SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
/*
+** CAPI3REF: Add a Schema to a Changegroup
+** METHOD: sqlite3_changegroup_schema
+**
+** This method may be used to optionally enforce the rule that the changesets
+** added to the changegroup handle must match the schema of database zDb
+** ("main", "temp", or the name of an attached database). If
+** sqlite3changegroup_add() is called to add a changeset that is not compatible
+** with the configured schema, SQLITE_SCHEMA is returned and the changegroup
+** object is left in an undefined state.
+**
+** A changeset schema is considered compatible with the database schema in
+** the same way as for sqlite3changeset_apply(). Specifically, for each
+** table in the changeset, there exists a database table with:
+**
+** <ul>
+** <li> The name identified by the changeset, and
+** <li> at least as many columns as recorded in the changeset, and
+** <li> the primary key columns in the same position as recorded in
+** the changeset.
+** </ul>
+**
+** The output of the changegroup object always has the same schema as the
+** database nominated using this function. In cases where changesets passed
+** to sqlite3changegroup_add() have fewer columns than the corresponding table
+** in the database schema, these are filled in using the default column
+** values from the database schema. This makes it possible to combined
+** changesets that have different numbers of columns for a single table
+** within a changegroup, provided that they are otherwise compatible.
+*/
+SQLITE_API int sqlite3changegroup_schema(sqlite3_changegroup*, sqlite3*, const char *zDb);
+
+/*
** CAPI3REF: Add A Changeset To A Changegroup
** METHOD: sqlite3_changegroup
**
@@ -11961,13 +12296,18 @@ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
** 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 state
-** of the final contents of the changegroup is undefined.
+** case, this function fails with SQLITE_SCHEMA. Except, if the changegroup
+** object has been configured with a database schema using the
+** sqlite3changegroup_schema() API, then it is possible to combine changesets
+** with different numbers of columns for a single table, provided that
+** they are otherwise compatible.
**
-** If no error occurs, SQLITE_OK is returned.
+** 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 state of the final contents of the
+** changegroup is undefined. If no error occurs, SQLITE_OK is returned.
*/
SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
@@ -12219,9 +12559,30 @@ SQLITE_API int sqlite3changeset_apply_v2(
** Invert the changeset before applying it. This is equivalent to inverting
** a changeset using sqlite3changeset_invert() before applying it. It is
** an error to specify this flag with a patchset.
+**
+** <dt>SQLITE_CHANGESETAPPLY_IGNORENOOP <dd>
+** Do not invoke the conflict handler callback for any changes that
+** would not actually modify the database even if they were applied.
+** Specifically, this means that the conflict handler is not invoked
+** for:
+** <ul>
+** <li>a delete change if the row being deleted cannot be found,
+** <li>an update change if the modified fields are already set to
+** their new values in the conflicting row, or
+** <li>an insert change if all fields of the conflicting row match
+** the row being inserted.
+** </ul>
+**
+** <dt>SQLITE_CHANGESETAPPLY_FKNOACTION <dd>
+** If this flag it set, then all foreign key constraints in the target
+** database behave as if they were declared with "ON UPDATE NO ACTION ON
+** DELETE NO ACTION", even if they are actually CASCADE, RESTRICT, SET NULL
+** or SET DEFAULT.
*/
#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
#define SQLITE_CHANGESETAPPLY_INVERT 0x0002
+#define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004
+#define SQLITE_CHANGESETAPPLY_FKNOACTION 0x0008
/*
** CAPI3REF: Constants Passed To The Conflict Handler
@@ -12787,8 +13148,11 @@ struct Fts5PhraseIter {
** created with the "columnsize=0" option.
**
** xColumnText:
-** This function attempts to retrieve the text of column iCol of the
-** current document. If successful, (*pz) is set to point to a buffer
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of columns in the table, SQLITE_RANGE is returned.
+**
+** Otherwise, this function attempts to retrieve the text of column iCol of
+** the current document. If successful, (*pz) is set to point to a buffer
** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
** if an error occurs, an SQLite error code is returned and the final values
@@ -12798,8 +13162,10 @@ struct Fts5PhraseIter {
** Returns the number of phrases in the current query expression.
**
** xPhraseSize:
-** Returns the number of tokens in phrase iPhrase of the query. Phrases
-** are numbered starting from zero.
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of phrases in the current query, as returned by xPhraseCount,
+** 0 is returned. Otherwise, this function returns the number of tokens in
+** phrase iPhrase of the query. Phrases are numbered starting from zero.
**
** xInstCount:
** Set *pnInst to the total number of occurrences of all phrases within
@@ -12815,12 +13181,13 @@ struct Fts5PhraseIter {
** Query for the details of phrase match iIdx within the current row.
** Phrase matches are numbered starting from zero, so the iIdx argument
** should be greater than or equal to zero and smaller than the value
-** output by xInstCount().
+** output by xInstCount(). If iIdx is less than zero or greater than
+** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned.
**
-** Usually, output parameter *piPhrase is set to the phrase number, *piCol
+** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol
** to the column in which it occurs and *piOff the token offset of the
-** first token of the phrase. Returns SQLITE_OK if successful, or an error
-** code (i.e. SQLITE_NOMEM) if an error occurs.
+** first token of the phrase. SQLITE_OK is returned if successful, or an
+** error code (i.e. SQLITE_NOMEM) if an error occurs.
**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option.
@@ -12846,6 +13213,10 @@ struct Fts5PhraseIter {
** Invoking Api.xUserData() returns a copy of the pointer passed as
** the third argument to pUserData.
**
+** If parameter iPhrase is less than zero, or greater than or equal to
+** the number of phrases in the query, as returned by xPhraseCount(),
+** this function returns SQLITE_RANGE.
+**
** If the callback function returns any value other than SQLITE_OK, the
** query is abandoned and the xQueryPhrase function returns immediately.
** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
@@ -12960,6 +13331,39 @@ struct Fts5PhraseIter {
**
** xPhraseNextColumn()
** See xPhraseFirstColumn above.
+**
+** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase iPhrase of the current
+** query. Before returning, output parameter *ppToken is set to point
+** to a buffer containing the requested token, and *pnToken to the
+** size of this buffer in bytes.
+**
+** If iPhrase or iToken are less than zero, or if iPhrase is greater than
+** or equal to the number of phrases in the query as reported by
+** xPhraseCount(), or if iToken is equal to or greater than the number of
+** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken
+ are both zeroed.
+**
+** The output text is not a copy of the query text that specified the
+** token. It is the output of the tokenizer module. For tokendata=1
+** tables, this includes any embedded 0x00 and trailing data.
+**
+** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase hit iIdx within the
+** current row. If iIdx is less than zero or greater than or equal to the
+** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
+** output variable (*ppToken) is set to point to a buffer containing the
+** matching document token, and (*pnToken) to the size of that buffer in
+** bytes. This API is not available if the specified token matches a
+** prefix query term. In that case both output variables are always set
+** to 0.
+**
+** The output text is not a copy of the document text that was tokenized.
+** It is the output of the tokenizer module. For tokendata=1 tables, this
+** includes any embedded 0x00 and trailing data.
+**
+** This API can be quite slow if used with an FTS5 table created with the
+** "detail=none" or "detail=column" option.
*/
struct Fts5ExtensionApi {
int iVersion; /* Currently always set to 3 */
@@ -12997,6 +13401,13 @@ struct Fts5ExtensionApi {
int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
+
+ /* Below this point are iVersion>=3 only */
+ int (*xQueryToken)(Fts5Context*,
+ int iPhrase, int iToken,
+ const char **ppToken, int *pnToken
+ );
+ int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
};
/*
@@ -13191,8 +13602,8 @@ struct Fts5ExtensionApi {
** as separate queries of the FTS index are required for each synonym.
**
** When using methods (2) or (3), it is important that the tokenizer only
-** provide synonyms when tokenizing document text (method (2)) or query
-** text (method (3)), not both. Doing so will not cause any errors, but is
+** provide synonyms when tokenizing document text (method (3)) or query
+** text (method (2)), not both. Doing so will not cause any errors, but is
** inefficient.
*/
typedef struct Fts5Tokenizer Fts5Tokenizer;
@@ -13240,7 +13651,7 @@ struct fts5_api {
int (*xCreateTokenizer)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_tokenizer *pTokenizer,
void (*xDestroy)(void*)
);
@@ -13249,7 +13660,7 @@ struct fts5_api {
int (*xFindTokenizer)(
fts5_api *pApi,
const char *zName,
- void **ppContext,
+ void **ppUserData,
fts5_tokenizer *pTokenizer
);
@@ -13257,7 +13668,7 @@ struct fts5_api {
int (*xCreateFunction)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_extension_function xFunction,
void (*xDestroy)(void*)
);
@@ -13368,7 +13779,7 @@ struct fts5_api {
** level of recursion for each term. A stack overflow can result
** if the number of terms is too large. In practice, most SQL
** never has more than 3 or 4 terms. Use a value of 0 to disable
-** any limit on the number of terms in a compount SELECT.
+** any limit on the number of terms in a compound SELECT.
*/
#ifndef SQLITE_MAX_COMPOUND_SELECT
# define SQLITE_MAX_COMPOUND_SELECT 500
@@ -13483,7 +13894,7 @@ struct fts5_api {
** max_page_count macro.
*/
#ifndef SQLITE_MAX_PAGE_COUNT
-# define SQLITE_MAX_PAGE_COUNT 1073741823
+# define SQLITE_MAX_PAGE_COUNT 0xfffffffe /* 4294967294 */
#endif
/*
@@ -13518,8 +13929,8 @@ struct fts5_api {
#endif
/*
-** WAL mode depends on atomic aligned 32-bit loads and stores in a few
-** places. The following macros try to make this explicit.
+** A few places in the code require atomic load/store of aligned
+** integer values.
*/
#ifndef __has_extension
# define __has_extension(x) 0 /* compatibility with non-clang compilers */
@@ -13575,15 +13986,22 @@ struct fts5_api {
#endif
/*
-** A macro to hint to the compiler that a function should not be
+** Macros to hint to the compiler that a function should or should not be
** inlined.
*/
#if defined(__GNUC__)
# define SQLITE_NOINLINE __attribute__((noinline))
+# define SQLITE_INLINE __attribute__((always_inline)) inline
#elif defined(_MSC_VER) && _MSC_VER>=1310
# define SQLITE_NOINLINE __declspec(noinline)
+# define SQLITE_INLINE __forceinline
#else
# define SQLITE_NOINLINE
+# define SQLITE_INLINE
+#endif
+#if defined(SQLITE_COVERAGE_TEST) || defined(__STRICT_ANSI__)
+# undef SQLITE_INLINE
+# define SQLITE_INLINE
#endif
/*
@@ -13606,6 +14024,29 @@ struct fts5_api {
#endif
/*
+** Enable SQLITE_USE_SEH by default on MSVC builds. Only omit
+** SEH support if the -DSQLITE_OMIT_SEH option is given.
+*/
+#if defined(_MSC_VER) && !defined(SQLITE_OMIT_SEH)
+# define SQLITE_USE_SEH 1
+#else
+# undef SQLITE_USE_SEH
+#endif
+
+/*
+** Enable SQLITE_DIRECT_OVERFLOW_READ, unless the build explicitly
+** disables it using -DSQLITE_DIRECT_OVERFLOW_READ=0
+*/
+#if defined(SQLITE_DIRECT_OVERFLOW_READ) && SQLITE_DIRECT_OVERFLOW_READ+1==1
+ /* Disable if -DSQLITE_DIRECT_OVERFLOW_READ=0 */
+# undef SQLITE_DIRECT_OVERFLOW_READ
+#else
+ /* In all other cases, enable */
+# define SQLITE_DIRECT_OVERFLOW_READ 1
+#endif
+
+
+/*
** The SQLITE_THREADSAFE macro must be defined as 0, 1, or 2.
** 0 means mutexes are permanently disable and the library is never
** threadsafe. 1 means the library is serialized which is the highest
@@ -14464,8 +14905,31 @@ typedef INT16_TYPE LogEst;
** 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)))
+#define SQLITE_WITHIN(P,S,E) (((uptr)(P)>=(uptr)(S))&&((uptr)(P)<(uptr)(E)))
+/*
+** P is one byte past the end of a large buffer. Return true if a span of bytes
+** between S..E crosses the end of that buffer. In other words, return true
+** if the sub-buffer S..E-1 overflows the buffer whose last byte is P-1.
+**
+** S is the start of the span. E is one byte past the end of end of span.
+**
+** P
+** |-----------------| FALSE
+** |-------|
+** S E
+**
+** P
+** |-----------------|
+** |-------| TRUE
+** S E
+**
+** P
+** |-----------------|
+** |-------| FALSE
+** S E
+*/
+#define SQLITE_OVERFLOW(P,S,E) (((uptr)(S)<(uptr)(P))&&((uptr)(E)>(uptr)(P)))
/*
** Macros to determine whether the machine is big or little endian,
@@ -14475,16 +14939,33 @@ typedef INT16_TYPE LogEst;
** using C-preprocessor macros. If that is unsuccessful, or if
** -DSQLITE_BYTEORDER=0 is set, then byte-order is determined
** at run-time.
+**
+** If you are building SQLite on some obscure platform for which the
+** following ifdef magic does not work, you can always include either:
+**
+** -DSQLITE_BYTEORDER=1234
+**
+** or
+**
+** -DSQLITE_BYTEORDER=4321
+**
+** to cause the build to work for little-endian or big-endian processors,
+** respectively.
*/
-#ifndef SQLITE_BYTEORDER
-# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \
+#ifndef SQLITE_BYTEORDER /* Replicate changes at tag-20230904a */
+# if defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
+# define SQLITE_BYTEORDER 4321
+# elif defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
+# define SQLITE_BYTEORDER 1234
+# elif defined(__BIG_ENDIAN__) && __BIG_ENDIAN__==1
+# define SQLITE_BYTEORDER 4321
+# elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \
defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
defined(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64)
-# define SQLITE_BYTEORDER 1234
-# elif defined(sparc) || defined(__ppc__) || \
- defined(__ARMEB__) || defined(__AARCH64EB__)
-# define SQLITE_BYTEORDER 4321
+# define SQLITE_BYTEORDER 1234
+# elif defined(sparc) || defined(__ARMEB__) || defined(__AARCH64EB__)
+# define SQLITE_BYTEORDER 4321
# else
# define SQLITE_BYTEORDER 0
# endif
@@ -14635,6 +15116,7 @@ SQLITE_PRIVATE u32 sqlite3TreeTrace;
** 0x00010000 Beginning of DELETE/INSERT/UPDATE processing
** 0x00020000 Transform DISTINCT into GROUP BY
** 0x00040000 SELECT tree dump after all code has been generated
+** 0x00080000 NOT NULL strength reduction
*/
/*
@@ -14699,7 +15181,7 @@ struct BusyHandler {
/*
** Name of table that holds the database schema.
**
-** The PREFERRED names are used whereever possible. But LEGACY is also
+** The PREFERRED names are used wherever possible. But LEGACY is also
** used for backwards compatibility.
**
** 1. Queries can use either the PREFERRED or the LEGACY names
@@ -14808,11 +15290,13 @@ typedef struct Column Column;
typedef struct Cte Cte;
typedef struct CteUse CteUse;
typedef struct Db Db;
+typedef struct DbClientData DbClientData;
typedef struct DbFixer DbFixer;
typedef struct Schema Schema;
typedef struct Expr Expr;
typedef struct ExprList ExprList;
typedef struct FKey FKey;
+typedef struct FpDecode FpDecode;
typedef struct FuncDestructor FuncDestructor;
typedef struct FuncDef FuncDef;
typedef struct FuncDefHash FuncDefHash;
@@ -14831,6 +15315,7 @@ typedef struct Parse Parse;
typedef struct ParseCleanup ParseCleanup;
typedef struct PreUpdate PreUpdate;
typedef struct PrintfArguments PrintfArguments;
+typedef struct RCStr RCStr;
typedef struct RenameToken RenameToken;
typedef struct Returning Returning;
typedef struct RowSet RowSet;
@@ -15444,7 +15929,7 @@ SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager*);
SQLITE_PRIVATE const char *sqlite3PagerJournalname(Pager*);
SQLITE_PRIVATE void *sqlite3PagerTempSpace(Pager*);
SQLITE_PRIVATE int sqlite3PagerIsMemdb(Pager*);
-SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, int *);
+SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *, int, int, u64*);
SQLITE_PRIVATE void sqlite3PagerClearCache(Pager*);
SQLITE_PRIVATE int sqlite3SectorSize(sqlite3_file *);
@@ -15468,6 +15953,10 @@ SQLITE_PRIVATE void sqlite3PagerRefdump(Pager*);
# define enable_simulated_io_errors()
#endif
+#if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL)
+SQLITE_PRIVATE int sqlite3PagerWalSystemErrno(Pager*);
+#endif
+
#endif /* SQLITE_PAGER_H */
/************** End of pager.h ***********************************************/
@@ -15797,9 +16286,7 @@ SQLITE_PRIVATE int sqlite3BtreePrevious(BtCursor*, int flags);
SQLITE_PRIVATE i64 sqlite3BtreeIntegerKey(BtCursor*);
SQLITE_PRIVATE void sqlite3BtreeCursorPin(BtCursor*);
SQLITE_PRIVATE void sqlite3BtreeCursorUnpin(BtCursor*);
-#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
SQLITE_PRIVATE i64 sqlite3BtreeOffset(BtCursor*);
-#endif
SQLITE_PRIVATE int sqlite3BtreePayload(BtCursor*, u32 offset, u32 amt, void*);
SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor*, u32 *pAmt);
SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor*);
@@ -16029,6 +16516,7 @@ typedef struct VdbeOpList VdbeOpList;
#define P4_INT64 (-13) /* P4 is a 64-bit signed integer */
#define P4_INTARRAY (-14) /* P4 is a vector of 32-bit integers */
#define P4_FUNCCTX (-15) /* P4 is a pointer to an sqlite3_context object */
+#define P4_TABLEREF (-16) /* Like P4_TABLE, but reference counted */
/* Error message codes for OP_Halt */
#define P5_ConstraintNotNull 1
@@ -16244,19 +16732,22 @@ typedef struct VdbeOpList VdbeOpList;
#define OP_VCreate 171
#define OP_VDestroy 172
#define OP_VOpen 173
-#define OP_VInitIn 174 /* synopsis: r[P2]=ValueList(P1,P3) */
-#define OP_VColumn 175 /* synopsis: r[P3]=vcolumn(P2) */
-#define OP_VRename 176
-#define OP_Pagecount 177
-#define OP_MaxPgcnt 178
-#define OP_ClrSubtype 179 /* synopsis: r[P1].subtype = 0 */
-#define OP_FilterAdd 180 /* synopsis: filter(P1) += key(P3@P4) */
-#define OP_Trace 181
-#define OP_CursorHint 182
-#define OP_ReleaseReg 183 /* synopsis: release r[P1@P2] mask P3 */
-#define OP_Noop 184
-#define OP_Explain 185
-#define OP_Abortable 186
+#define OP_VCheck 174
+#define OP_VInitIn 175 /* synopsis: r[P2]=ValueList(P1,P3) */
+#define OP_VColumn 176 /* synopsis: r[P3]=vcolumn(P2) */
+#define OP_VRename 177
+#define OP_Pagecount 178
+#define OP_MaxPgcnt 179
+#define OP_ClrSubtype 180 /* synopsis: r[P1].subtype = 0 */
+#define OP_GetSubtype 181 /* synopsis: r[P2] = r[P1].subtype */
+#define OP_SetSubtype 182 /* synopsis: r[P2].subtype = r[P1] */
+#define OP_FilterAdd 183 /* synopsis: filter(P1) += key(P3@P4) */
+#define OP_Trace 184
+#define OP_CursorHint 185
+#define OP_ReleaseReg 186 /* synopsis: release r[P1@P2] mask P3 */
+#define OP_Noop 187
+#define OP_Explain 188
+#define OP_Abortable 189
/* Properties such as "out2" or "jump" that are specified in
** comments following the "case" for each opcode in the vdbe.c
@@ -16274,7 +16765,7 @@ typedef struct VdbeOpList VdbeOpList;
/* 8 */ 0x01, 0x01, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01,\
/* 16 */ 0x03, 0x03, 0x01, 0x12, 0x01, 0x49, 0x49, 0x49,\
/* 24 */ 0x49, 0x01, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49,\
-/* 32 */ 0x41, 0x01, 0x01, 0x01, 0x41, 0x01, 0x41, 0x41,\
+/* 32 */ 0x41, 0x01, 0x41, 0x41, 0x41, 0x01, 0x41, 0x41,\
/* 40 */ 0x41, 0x41, 0x41, 0x26, 0x26, 0x41, 0x23, 0x0b,\
/* 48 */ 0x01, 0x01, 0x03, 0x03, 0x0b, 0x0b, 0x0b, 0x0b,\
/* 56 */ 0x0b, 0x0b, 0x01, 0x03, 0x03, 0x03, 0x01, 0x41,\
@@ -16286,14 +16777,14 @@ typedef struct VdbeOpList VdbeOpList;
/* 104 */ 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26,\
/* 112 */ 0x40, 0x00, 0x12, 0x40, 0x40, 0x10, 0x40, 0x00,\
/* 120 */ 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x10, 0x10,\
-/* 128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,\
+/* 128 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x50,\
/* 136 */ 0x00, 0x40, 0x04, 0x04, 0x00, 0x40, 0x50, 0x40,\
/* 144 */ 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,\
/* 152 */ 0x00, 0x10, 0x00, 0x00, 0x06, 0x10, 0x00, 0x04,\
/* 160 */ 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\
-/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x50, 0x40,\
-/* 176 */ 0x00, 0x10, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00,\
-/* 184 */ 0x00, 0x00, 0x00,}
+/* 168 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x50,\
+/* 176 */ 0x40, 0x00, 0x10, 0x10, 0x02, 0x12, 0x12, 0x00,\
+/* 184 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,}
/* The resolve3P2Values() routine is able to run faster if it knows
** the value of the largest JUMP opcode. The smaller the maximum
@@ -16468,7 +16959,7 @@ SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe*, const char*, ...);
** The VdbeCoverage macros are used to set a coverage testing point
** for VDBE branch instructions. The coverage testing points are line
** numbers in the sqlite3.c source file. VDBE branch coverage testing
-** only works with an amalagmation build. That's ok since a VDBE branch
+** only works with an amalgamation build. That's ok since a VDBE branch
** coverage build designed for testing the test suite only. No application
** should ever ship with VDBE branch coverage measuring turned on.
**
@@ -16486,7 +16977,7 @@ SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe*, const char*, ...);
** // NULL option is not possible
**
** VdbeCoverageEqNe(v) // Previous OP_Jump is only interested
-** // in distingishing equal and not-equal.
+** // in distinguishing equal and not-equal.
**
** Every VDBE branch operation must be tagged with one of the macros above.
** If not, then when "make test" is run with -DSQLITE_VDBE_COVERAGE and
@@ -16496,7 +16987,7 @@ SQLITE_PRIVATE void sqlite3VdbeNoopComment(Vdbe*, const char*, ...);
** During testing, the test application will invoke
** sqlite3_test_control(SQLITE_TESTCTRL_VDBE_COVERAGE,...) to set a callback
** routine that is invoked as each bytecode branch is taken. The callback
-** contains the sqlite3.c source line number ov the VdbeCoverage macro and
+** contains the sqlite3.c source line number of the VdbeCoverage macro and
** flags to indicate whether or not the branch was taken. The test application
** is responsible for keeping track of this and reporting byte-code branches
** that are never taken.
@@ -16544,6 +17035,10 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatusCounters(Vdbe*, int, int, int);
SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, VdbeOp*);
#endif
+#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG)
+SQLITE_PRIVATE int sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr);
+#endif
+
#endif /* SQLITE_VDBE_H */
/************** End of vdbe.h ************************************************/
@@ -16592,7 +17087,7 @@ struct PgHdr {
** private to pcache.c and should not be accessed by other modules.
** pCache is grouped with the public elements for efficiency.
*/
- i16 nRef; /* Number of users of this page */
+ i64 nRef; /* Number of users of this page */
PgHdr *pDirtyNext; /* Next element in list of dirty pages */
PgHdr *pDirtyPrev; /* Previous element in list of dirty pages */
/* NB: pDirtyNext and pDirtyPrev are undefined if the
@@ -16673,12 +17168,12 @@ SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *);
SQLITE_PRIVATE void sqlite3PcacheClear(PCache*);
/* Return the total number of outstanding page references */
-SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache*);
+SQLITE_PRIVATE i64 sqlite3PcacheRefCount(PCache*);
/* Increment the reference count of an existing page */
SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr*);
-SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr*);
+SQLITE_PRIVATE i64 sqlite3PcachePageRefcount(PgHdr*);
/* Return the total number of pages stored in the cache */
SQLITE_PRIVATE int sqlite3PcachePagecount(PCache*);
@@ -16831,7 +17326,7 @@ SQLITE_API int sqlite3_mutex_held(sqlite3_mutex*);
/*
** Default synchronous levels.
**
-** Note that (for historcal reasons) the PAGER_SYNCHRONOUS_* macros differ
+** Note that (for historical reasons) the PAGER_SYNCHRONOUS_* macros differ
** from the SQLITE_DEFAULT_SYNCHRONOUS value by 1.
**
** PAGER_SYNCHRONOUS DEFAULT_SYNCHRONOUS
@@ -16870,7 +17365,7 @@ struct Db {
** An instance of the following structure stores a database schema.
**
** Most Schema objects are associated with a Btree. The exception is
-** the Schema for the TEMP databaes (sqlite3.aDb[1]) which is free-standing.
+** the Schema for the TEMP database (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.
**
@@ -16981,7 +17476,7 @@ struct Lookaside {
LookasideSlot *pInit; /* List of buffers not previously used */
LookasideSlot *pFree; /* List of available buffers */
#ifndef SQLITE_OMIT_TWOSIZE_LOOKASIDE
- LookasideSlot *pSmallInit; /* List of small buffers not prediously used */
+ LookasideSlot *pSmallInit; /* List of small buffers not previously used */
LookasideSlot *pSmallFree; /* List of available small buffers */
void *pMiddle; /* First byte past end of full-size buffers and
** the first byte of LOOKASIDE_SMALL buffers */
@@ -16998,7 +17493,7 @@ struct LookasideSlot {
#define EnableLookaside db->lookaside.bDisable--;\
db->lookaside.sz=db->lookaside.bDisable?0:db->lookaside.szTrue
-/* Size of the smaller allocations in two-size lookside */
+/* Size of the smaller allocations in two-size lookaside */
#ifdef SQLITE_OMIT_TWOSIZE_LOOKASIDE
# define LOOKASIDE_SMALL 0
#else
@@ -17198,6 +17693,7 @@ struct sqlite3 {
i64 nDeferredCons; /* Net deferred constraints this transaction. */
i64 nDeferredImmCons; /* Net deferred immediate constraints */
int *pnBytesFreed; /* If not NULL, increment this in DbFree() */
+ DbClientData *pDbData; /* sqlite3_set_clientdata() content */
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
/* The following variables are all protected by the STATIC_MAIN
** mutex, not by sqlite3.mutex. They are used by code in notify.c.
@@ -17253,7 +17749,7 @@ struct sqlite3 {
#define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */
/* result set is empty */
#define SQLITE_IgnoreChecks 0x00000200 /* Do not enforce check constraints */
-#define SQLITE_ReadUncommit 0x00000400 /* READ UNCOMMITTED in shared-cache */
+#define SQLITE_StmtScanStatus 0x00000400 /* Enable stmt_scanstats() counters */
#define SQLITE_NoCkptOnClose 0x00000800 /* No checkpoint on close()/DETACH */
#define SQLITE_ReverseOrder 0x00001000 /* Reverse unordered SELECTs */
#define SQLITE_RecTriggers 0x00002000 /* Enable recursive triggers */
@@ -17279,6 +17775,8 @@ struct sqlite3 {
/* DELETE, or UPDATE and return */
/* the count using a callback. */
#define SQLITE_CorruptRdOnly HI(0x00002) /* Prohibit writes due to error */
+#define SQLITE_ReadUncommit HI(0x00004) /* READ UNCOMMITTED in shared-cache */
+#define SQLITE_FkNoAction HI(0x00008) /* Treat all FK as NO ACTION */
/* Flags used only if debugging */
#ifdef SQLITE_DEBUG
@@ -17335,6 +17833,8 @@ struct sqlite3 {
/* TH3 expects this value ^^^^^^^^^^ See flatten04.test */
#define SQLITE_IndexedExpr 0x01000000 /* Pull exprs from index when able */
#define SQLITE_Coroutines 0x02000000 /* Co-routines for subqueries */
+#define SQLITE_NullUnusedCols 0x04000000 /* NULL unused columns in subqueries */
+#define SQLITE_OnePass 0x08000000 /* Single-pass DELETE and UPDATE */
#define SQLITE_AllOpts 0xffffffff /* All optimizations */
/*
@@ -17417,6 +17917,7 @@ struct FuncDestructor {
** SQLITE_FUNC_ANYORDER == NC_OrderAgg == SF_OrderByReqd
** SQLITE_FUNC_LENGTH == OPFLAG_LENGTHARG
** SQLITE_FUNC_TYPEOF == OPFLAG_TYPEOFARG
+** SQLITE_FUNC_BYTELEN == OPFLAG_BYTELENARG
** SQLITE_FUNC_CONSTANT == SQLITE_DETERMINISTIC from the API
** SQLITE_FUNC_DIRECT == SQLITE_DIRECTONLY from the API
** SQLITE_FUNC_UNSAFE == SQLITE_INNOCUOUS -- opposite meanings!!!
@@ -17424,7 +17925,7 @@ struct FuncDestructor {
**
** Note that even though SQLITE_FUNC_UNSAFE and SQLITE_INNOCUOUS have the
** same bit value, their meanings are inverted. SQLITE_FUNC_UNSAFE is
-** used internally and if set means tha the function has side effects.
+** used internally and if set means that the function has side effects.
** SQLITE_INNOCUOUS is used by application code and means "not unsafe".
** See multiple instances of tag-20230109-1.
*/
@@ -17435,6 +17936,7 @@ struct FuncDestructor {
#define SQLITE_FUNC_NEEDCOLL 0x0020 /* sqlite3GetFuncCollSeq() might be called*/
#define SQLITE_FUNC_LENGTH 0x0040 /* Built-in length() function */
#define SQLITE_FUNC_TYPEOF 0x0080 /* Built-in typeof() function */
+#define SQLITE_FUNC_BYTELEN 0x00c0 /* Built-in octet_length() function */
#define SQLITE_FUNC_COUNT 0x0100 /* Built-in count(*) aggregate */
/* 0x0200 -- available for reuse */
#define SQLITE_FUNC_UNLIKELY 0x0400 /* Built-in unlikely() function */
@@ -17443,14 +17945,15 @@ struct FuncDestructor {
#define SQLITE_FUNC_SLOCHNG 0x2000 /* "Slow Change". Value constant during a
** single query - might change over time */
#define SQLITE_FUNC_TEST 0x4000 /* Built-in testing functions */
-/* 0x8000 -- available for reuse */
+#define SQLITE_FUNC_RUNONLY 0x8000 /* Cannot be used by valueFromFunction */
#define SQLITE_FUNC_WINDOW 0x00010000 /* Built-in window-only function */
#define SQLITE_FUNC_INTERNAL 0x00040000 /* For use by NestedParse() only */
#define SQLITE_FUNC_DIRECT 0x00080000 /* Not for use in TRIGGERs or VIEWs */
-#define SQLITE_FUNC_SUBTYPE 0x00100000 /* Result likely to have sub-type */
+/* SQLITE_SUBTYPE 0x00100000 // Consumer of subtypes */
#define SQLITE_FUNC_UNSAFE 0x00200000 /* Function has side effects */
#define SQLITE_FUNC_INLINE 0x00400000 /* Functions implemented in-line */
#define SQLITE_FUNC_BUILTIN 0x00800000 /* This is a built-in function */
+/* SQLITE_RESULT_SUBTYPE 0x01000000 // Generator of subtypes */
#define SQLITE_FUNC_ANYORDER 0x08000000 /* count/min/max aggregate */
/* Identifier numbers for each in-line function */
@@ -17542,10 +18045,11 @@ struct FuncDestructor {
#define MFUNCTION(zName, nArg, xPtr, xFunc) \
{nArg, SQLITE_FUNC_BUILTIN|SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \
xPtr, 0, xFunc, 0, 0, 0, #zName, {0} }
-#define JFUNCTION(zName, nArg, iArg, xFunc) \
- {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|\
- SQLITE_FUNC_CONSTANT|SQLITE_UTF8, \
- SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, 0, #zName, {0} }
+#define JFUNCTION(zName, nArg, bUseCache, bWS, bRS, bJsonB, iArg, xFunc) \
+ {nArg, SQLITE_FUNC_BUILTIN|SQLITE_DETERMINISTIC|SQLITE_FUNC_CONSTANT|\
+ SQLITE_UTF8|((bUseCache)*SQLITE_FUNC_RUNONLY)|\
+ ((bRS)*SQLITE_SUBTYPE)|((bWS)*SQLITE_RESULT_SUBTYPE), \
+ SQLITE_INT_TO_PTR(iArg|((bJsonB)*JSON_BLOB)),0,xFunc,0, 0, 0, #zName, {0} }
#define INLINE_FUNC(zName, nArg, iArg, mFlags) \
{nArg, SQLITE_FUNC_BUILTIN|\
SQLITE_UTF8|SQLITE_FUNC_INLINE|SQLITE_FUNC_CONSTANT|(mFlags), \
@@ -17806,6 +18310,7 @@ struct VTable {
sqlite3_vtab *pVtab; /* Pointer to vtab instance */
int nRef; /* Number of pointers to this structure */
u8 bConstraint; /* True if constraints are supported */
+ u8 bAllSchemas; /* True if might use any attached schema */
u8 eVtabRisk; /* Riskiness of allowing hacker access */
int iSavepoint; /* Depth of the SAVEPOINT stack */
VTable *pNext; /* Next in linked list (see above) */
@@ -17942,6 +18447,15 @@ struct Table {
#define HasRowid(X) (((X)->tabFlags & TF_WithoutRowid)==0)
#define VisibleRowid(X) (((X)->tabFlags & TF_NoVisibleRowid)==0)
+/* Macro is true if the SQLITE_ALLOW_ROWID_IN_VIEW (mis-)feature is
+** available. By default, this macro is false
+*/
+#ifndef SQLITE_ALLOW_ROWID_IN_VIEW
+# define ViewCanHaveRowid 0
+#else
+# define ViewCanHaveRowid (sqlite3Config.mNoVisibleRowid==0)
+#endif
+
/*
** Each foreign key constraint is an instance of the following structure.
**
@@ -18013,7 +18527,7 @@ struct FKey {
** foreign key.
**
** The OE_Default value is a place holder that means to use whatever
-** conflict resolution algorthm is required from context.
+** conflict resolution algorithm is required from context.
**
** The following symbolic values are used to record which type
** of conflict resolution action to take.
@@ -18179,6 +18693,7 @@ struct Index {
unsigned isCovering:1; /* True if this is a covering index */
unsigned noSkipScan:1; /* Do not try to use skip-scan if true */
unsigned hasStat1:1; /* aiRowLogEst values come from sqlite_stat1 */
+ unsigned bLowQual:1; /* sqlite_stat1 says this is a low-quality index */
unsigned bNoQuery:1; /* Do not use this index to optimize queries */
unsigned bAscKeyBug:1; /* True if the bba7b69f9849b5bf bug applies */
unsigned bHasVCol:1; /* Index references one or more VIRTUAL columns */
@@ -18186,6 +18701,7 @@ struct Index {
** expression, or a reference to a VIRTUAL column */
#ifdef SQLITE_ENABLE_STAT4
int nSample; /* Number of elements in aSample[] */
+ int mxSample; /* Number of slots allocated to aSample[] */
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */
IndexSample *aSample; /* Samples of the left-most key */
@@ -18288,6 +18804,10 @@ struct AggInfo {
FuncDef *pFunc; /* The aggregate function implementation */
int iDistinct; /* Ephemeral table used to enforce DISTINCT */
int iDistAddr; /* Address of OP_OpenEphemeral */
+ int iOBTab; /* Ephemeral table to implement ORDER BY */
+ u8 bOBPayload; /* iOBTab has payload columns separate from key */
+ u8 bOBUnique; /* Enforce uniqueness on iOBTab keys */
+ u8 bUseSubtype; /* Transfer subtype info through sorter */
} *aFunc;
int nFunc; /* Number of entries in aFunc[] */
u32 selId; /* Select to which this AggInfo belongs */
@@ -18426,7 +18946,7 @@ struct Expr {
** TK_REGISTER: register number
** TK_TRIGGER: 1 -> new, 0 -> old
** EP_Unlikely: 134217728 times likelihood
- ** TK_IN: ephemerial table holding RHS
+ ** TK_IN: ephemeral table holding RHS
** TK_SELECT_COLUMN: Number of columns on the LHS
** TK_SELECT: 1st register of result vector */
ynVar iColumn; /* TK_COLUMN: column index. -1 for rowid.
@@ -18472,7 +18992,7 @@ struct Expr {
#define EP_Reduced 0x004000 /* Expr struct EXPR_REDUCEDSIZE bytes only */
#define EP_Win 0x008000 /* Contains window functions */
#define EP_TokenOnly 0x010000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */
- /* 0x020000 // Available for reuse */
+#define EP_FullSize 0x020000 /* Expr structure must remain full sized */
#define EP_IfNullRow 0x040000 /* The TK_IF_NULL_ROW opcode */
#define EP_Unlikely 0x080000 /* unlikely() or likelihood() function */
#define EP_ConstFunc 0x100000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */
@@ -18502,12 +19022,15 @@ struct Expr {
#define ExprClearProperty(E,P) (E)->flags&=~(P)
#define ExprAlwaysTrue(E) (((E)->flags&(EP_OuterON|EP_IsTrue))==EP_IsTrue)
#define ExprAlwaysFalse(E) (((E)->flags&(EP_OuterON|EP_IsFalse))==EP_IsFalse)
+#define ExprIsFullSize(E) (((E)->flags&(EP_Reduced|EP_TokenOnly))==0)
/* Macros used to ensure that the correct members of unions are accessed
** in Expr.
*/
#define ExprUseUToken(E) (((E)->flags&EP_IntValue)==0)
#define ExprUseUValue(E) (((E)->flags&EP_IntValue)!=0)
+#define ExprUseWOfst(E) (((E)->flags&(EP_InnerON|EP_OuterON))==0)
+#define ExprUseWJoin(E) (((E)->flags&(EP_InnerON|EP_OuterON))!=0)
#define ExprUseXList(E) (((E)->flags&EP_xIsSelect)==0)
#define ExprUseXSelect(E) (((E)->flags&EP_xIsSelect)!=0)
#define ExprUseYTab(E) (((E)->flags&(EP_WinFunc|EP_Subrtn))==0)
@@ -18617,6 +19140,7 @@ struct ExprList {
#define ENAME_NAME 0 /* The AS clause of a result set */
#define ENAME_SPAN 1 /* Complete text of the result set expression */
#define ENAME_TAB 2 /* "DB.TABLE.NAME" for the result set */
+#define ENAME_ROWID 3 /* "DB.TABLE._rowid_" for * expansion of rowid */
/*
** An instance of this structure can hold a simple list of identifiers,
@@ -18696,7 +19220,7 @@ struct SrcItem {
unsigned notCte :1; /* This item may not match a CTE */
unsigned isUsing :1; /* u3.pUsing is valid */
unsigned isOn :1; /* u3.pOn was once valid and non-NULL */
- unsigned isSynthUsing :1; /* u3.pUsing is synthensized from NATURAL */
+ unsigned isSynthUsing :1; /* u3.pUsing is synthesized from NATURAL */
unsigned isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */
} fg;
int iCursor; /* The VDBE cursor number used to access this table */
@@ -18817,6 +19341,7 @@ struct NameContext {
int nRef; /* Number of names resolved by this context */
int nNcErr; /* Number of errors encountered while resolving names */
int ncFlags; /* Zero or more NC_* flags defined below */
+ u32 nNestedSelect; /* Number of nested selects using this NC */
Select *pWinSelect; /* SELECT statement for any window functions */
};
@@ -18837,7 +19362,7 @@ struct NameContext {
#define NC_HasAgg 0x000010 /* One or more aggregate functions seen */
#define NC_IdxExpr 0x000020 /* True if resolving columns of CREATE INDEX */
#define NC_SelfRef 0x00002e /* Combo: PartIdx, isCheck, GenCol, and IdxExpr */
-#define NC_VarSelect 0x000040 /* A correlated subquery has been seen */
+#define NC_Subquery 0x000040 /* A subquery has been seen */
#define NC_UEList 0x000080 /* True if uNC.pEList is used */
#define NC_UAggInfo 0x000100 /* True if uNC.pAggInfo is used */
#define NC_UUpsert 0x000200 /* True if uNC.pUpsert is used */
@@ -18850,6 +19375,7 @@ struct NameContext {
#define NC_InAggFunc 0x020000 /* True if analyzing arguments to an agg func */
#define NC_FromDDL 0x040000 /* SQL text comes from sqlite_schema */
#define NC_NoSelect 0x080000 /* Do not descend into sub-selects */
+#define NC_Where 0x100000 /* Processing WHERE clause of a SELECT */
#define NC_OrderAgg 0x8000000 /* Has an aggregate other than count/min/max */
/*
@@ -18873,6 +19399,7 @@ struct Upsert {
Expr *pUpsertWhere; /* WHERE clause for the ON CONFLICT UPDATE */
Upsert *pNextUpsert; /* Next ON CONFLICT clause in the list */
u8 isDoUpdate; /* True for DO UPDATE. False for DO NOTHING */
+ u8 isDup; /* True if 2nd or later with same pUpsertIdx */
/* Above this point is the parse tree for the ON CONFLICT clauses.
** The next group of fields stores intermediate data. */
void *pToFree; /* Free memory when deleting the Upsert object */
@@ -19209,6 +19736,9 @@ struct Parse {
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */
#endif
+#ifdef SQLITE_DEBUG
+ u8 ifNotExists; /* Might be true if IF NOT EXISTS. Assert()s only */
+#endif
int nRangeReg; /* Size of the temporary register block */
int iRangeReg; /* First register in temporary register block */
int nErr; /* Number of errors seen */
@@ -19222,6 +19752,7 @@ struct Parse {
int *aLabel; /* Space to hold the labels */
ExprList *pConstExpr;/* Constant expressions */
IndexedExpr *pIdxEpr;/* List of expressions used by active indexes */
+ IndexedExpr *pIdxPartExpr; /* Exprs constrained by index WHERE clauses */
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 */
@@ -19229,6 +19760,9 @@ struct Parse {
int regRoot; /* Register holding root page number for new objects */
int nMaxArg; /* Max args passed to user function by sub-program */
int nSelect; /* Number of SELECT stmts. Counter for Select.selId */
+#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
+ u32 nProgressSteps; /* xProgress steps taken during sqlite3_prepare() */
+#endif
#ifndef SQLITE_OMIT_SHARED_CACHE
int nTableLock; /* Number of locks in aTableLock */
TableLock *aTableLock; /* Required table locks for shared-cache mode */
@@ -19242,12 +19776,9 @@ struct Parse {
int addrCrTab; /* Address of OP_CreateBtree on CREATE TABLE */
Returning *pReturning; /* The RETURNING clause */
} u1;
- u32 nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
u32 oldmask; /* Mask of old.* columns referenced */
u32 newmask; /* Mask of new.* columns referenced */
-#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
- u32 nProgressSteps; /* xProgress steps taken during sqlite3_prepare() */
-#endif
+ LogEst nQueryLoop; /* Est number of iterations of a query (10*log2(N)) */
u8 eTriggerOp; /* TK_UPDATE, TK_INSERT or TK_DELETE */
u8 bReturning; /* Coding a RETURNING trigger */
u8 eOrconf; /* Default ON CONFLICT policy for trigger steps */
@@ -19371,6 +19902,7 @@ struct AuthContext {
#define OPFLAG_ISNOOP 0x40 /* OP_Delete does pre-update-hook only */
#define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */
#define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */
+#define OPFLAG_BYTELENARG 0xc0 /* OP_Column only for octet_length() */
#define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */
#define OPFLAG_SEEKEQ 0x02 /* OP_Open** cursor uses EQ seek only */
#define OPFLAG_FORDELETE 0x08 /* OP_Open should use BTREE_FORDELETE */
@@ -19492,6 +20024,7 @@ struct Returning {
int iRetCur; /* Transient table holding RETURNING results */
int nRetCol; /* Number of in pReturnEL after expansion */
int iRetReg; /* Register array for holding a row of RETURNING */
+ char zName[40]; /* Name of trigger: "sqlite_returning_%p" */
};
/*
@@ -19513,6 +20046,28 @@ struct sqlite3_str {
#define isMalloced(X) (((X)->printfFlags & SQLITE_PRINTF_MALLOCED)!=0)
+/*
+** The following object is the header for an "RCStr" or "reference-counted
+** string". An RCStr is passed around and used like any other char*
+** that has been dynamically allocated. The important interface
+** differences:
+**
+** 1. RCStr strings are reference counted. They are deallocated
+** when the reference count reaches zero.
+**
+** 2. Use sqlite3RCStrUnref() to free an RCStr string rather than
+** sqlite3_free()
+**
+** 3. Make a (read-only) copy of a read-only RCStr string using
+** sqlite3RCStrRef().
+**
+** "String" is in the name, but an RCStr object can also be used to hold
+** binary data.
+*/
+struct RCStr {
+ u64 nRCRef; /* Number of references */
+ /* Total structure size should be a multiple of 8 bytes for alignment */
+};
/*
** A pointer to this structure is used to communicate information
@@ -19539,7 +20094,7 @@ typedef struct {
/* Tuning parameters are set using SQLITE_TESTCTRL_TUNE and are controlled
** on debug-builds of the CLI using ".testctrl tune ID VALUE". Tuning
** parameters are for temporary use during development, to help find
-** optimial values for parameters in the query planner. The should not
+** optimal values for parameters in the query planner. The should not
** be used on trunk check-ins. They are a temporary mechanism available
** for transient development builds only.
**
@@ -19565,6 +20120,10 @@ struct Sqlite3Config {
u8 bUseCis; /* Use covering indices for full-scans */
u8 bSmallMalloc; /* Avoid large memory allocations if true */
u8 bExtraSchemaChecks; /* Verify type,name,tbl_name in schema */
+ u8 bUseLongDouble; /* Make use of long double */
+#ifdef SQLITE_DEBUG
+ u8 bJsonSelfcheck; /* Double-check JSON parsing */
+#endif
int mxStrlen; /* Maximum string length */
int neverCorrupt; /* Database is always well-formed */
int szLookaside; /* Default lookaside buffer size */
@@ -19612,6 +20171,11 @@ struct Sqlite3Config {
#ifndef SQLITE_UNTESTABLE
int (*xTestCallback)(int); /* Invoked by sqlite3FaultSim() */
#endif
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ u32 mNoVisibleRowid; /* TF_NoVisibleRowid if the ROWID_IN_VIEW
+ ** feature is disabled. 0 if rowids can
+ ** occur in views. */
+#endif
int bLocaltimeFault; /* True to fail localtime() calls */
int (*xAltLocaltime)(const void*,void*); /* Alternative localtime() routine */
int iOnceResetThreshold; /* When to reset OP_Once counters */
@@ -19651,6 +20215,7 @@ struct Walker {
void (*xSelectCallback2)(Walker*,Select*);/* Second callback for SELECTs */
int walkerDepth; /* Number of subqueries */
u16 eCode; /* A small processing code */
+ u16 mWFlags; /* Use-dependent flags */
union { /* Extra data for callback */
NameContext *pNC; /* Naming context */
int n; /* A counter */
@@ -19669,6 +20234,7 @@ struct Walker {
struct CoveringIndexCheck *pCovIdxCk; /* Check for covering index */
SrcItem *pSrcItem; /* A single FROM clause item */
DbFixer *pFix; /* See sqlite3FixSelect() */
+ Mem *aMem; /* See sqlite3BtreeCursorHint() */
} u;
};
@@ -19689,6 +20255,7 @@ struct DbFixer {
/* Forward declarations */
SQLITE_PRIVATE int sqlite3WalkExpr(Walker*, Expr*);
+SQLITE_PRIVATE int sqlite3WalkExprNN(Walker*, Expr*);
SQLITE_PRIVATE int sqlite3WalkExprList(Walker*, ExprList*);
SQLITE_PRIVATE int sqlite3WalkSelect(Walker*, Select*);
SQLITE_PRIVATE int sqlite3WalkSelectExpr(Walker*, Select*);
@@ -19769,6 +20336,16 @@ struct CteUse {
};
+/* Client data associated with sqlite3_set_clientdata() and
+** sqlite3_get_clientdata().
+*/
+struct DbClientData {
+ DbClientData *pNext; /* Next in a linked list */
+ void *pData; /* The data */
+ void (*xDestructor)(void*); /* Destructor. Might be NULL */
+ char zName[1]; /* Name of this client data. MUST BE LAST */
+};
+
#ifdef SQLITE_DEBUG
/*
** An instance of the TreeView object is used for printing the content of
@@ -19938,6 +20515,8 @@ SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno);
# define sqlite3Isxdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x08)
# define sqlite3Tolower(x) (sqlite3UpperToLower[(unsigned char)(x)])
# define sqlite3Isquote(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x80)
+# define sqlite3JsonId1(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x42)
+# define sqlite3JsonId2(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x46)
#else
# define sqlite3Toupper(x) toupper((unsigned char)(x))
# define sqlite3Isspace(x) isspace((unsigned char)(x))
@@ -19947,6 +20526,8 @@ SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno);
# define sqlite3Isxdigit(x) isxdigit((unsigned char)(x))
# define sqlite3Tolower(x) tolower((unsigned char)(x))
# define sqlite3Isquote(x) ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`')
+# define sqlite3JsonId1(x) (sqlite3IsIdChar(x)&&(x)<'0')
+# define sqlite3JsonId2(x) sqlite3IsIdChar(x)
#endif
SQLITE_PRIVATE int sqlite3IsIdChar(u8);
@@ -20050,10 +20631,13 @@ SQLITE_PRIVATE void sqlite3MutexWarnOnContention(sqlite3_mutex*);
# define EXP754 (((u64)0x7ff)<<52)
# define MAN754 ((((u64)1)<<52)-1)
# define IsNaN(X) (((X)&EXP754)==EXP754 && ((X)&MAN754)!=0)
+# define IsOvfl(X) (((X)&EXP754)==EXP754)
SQLITE_PRIVATE int sqlite3IsNaN(double);
+SQLITE_PRIVATE int sqlite3IsOverflow(double);
#else
-# define IsNaN(X) 0
-# define sqlite3IsNaN(X) 0
+# define IsNaN(X) 0
+# define sqlite3IsNaN(X) 0
+# define sqlite3IsOVerflow(X) 0
#endif
/*
@@ -20066,6 +20650,20 @@ struct PrintfArguments {
sqlite3_value **apArg; /* The argument values */
};
+/*
+** An instance of this object receives the decoding of a floating point
+** value into an approximate decimal representation.
+*/
+struct FpDecode {
+ char sign; /* '+' or '-' */
+ char isSpecial; /* 1: Infinity 2: NaN */
+ int n; /* Significant digits in the decode */
+ int iDP; /* Location of the decimal point */
+ char *z; /* Start of significant digits */
+ char zBuf[24]; /* Storage for significant digits */
+};
+
+SQLITE_PRIVATE void sqlite3FpDecode(FpDecode*,double,int,int);
SQLITE_PRIVATE char *sqlite3MPrintf(sqlite3*,const char*, ...);
SQLITE_PRIVATE char *sqlite3VMPrintf(sqlite3*,const char*, va_list);
#if defined(SQLITE_DEBUG) || defined(SQLITE_HAVE_OS_TRACE)
@@ -20140,6 +20738,10 @@ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse*,int);
SQLITE_PRIVATE int sqlite3GetTempRange(Parse*,int);
SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse*,int,int);
SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse*);
+SQLITE_PRIVATE void sqlite3TouchRegister(Parse*,int);
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_DEBUG)
+SQLITE_PRIVATE int sqlite3FirstAvailableRegister(Parse*,int);
+#endif
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse*,int,int);
#endif
@@ -20151,9 +20753,12 @@ SQLITE_PRIVATE void sqlite3PExprAddSelect(Parse*, Expr*, Select*);
SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse*,Expr*, Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprSimplifiedAndOr(Expr*);
SQLITE_PRIVATE Expr *sqlite3ExprFunction(Parse*,ExprList*, const Token*, int);
+SQLITE_PRIVATE void sqlite3ExprAddFunctionOrderBy(Parse*,Expr*,ExprList*);
+SQLITE_PRIVATE void sqlite3ExprOrderByAggregateError(Parse*,Expr*);
SQLITE_PRIVATE void sqlite3ExprFunctionUsable(Parse*,const Expr*,const FuncDef*);
SQLITE_PRIVATE void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32);
SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3*, Expr*);
+SQLITE_PRIVATE void sqlite3ExprDeleteGeneric(sqlite3*,void*);
SQLITE_PRIVATE void sqlite3ExprDeferredDelete(Parse*, Expr*);
SQLITE_PRIVATE void sqlite3ExprUnmapAndDelete(Parse*, Expr*);
SQLITE_PRIVATE ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*);
@@ -20163,6 +20768,7 @@ SQLITE_PRIVATE void sqlite3ExprListSetSortOrder(ExprList*,int,int);
SQLITE_PRIVATE void sqlite3ExprListSetName(Parse*,ExprList*,const Token*,int);
SQLITE_PRIVATE void sqlite3ExprListSetSpan(Parse*,ExprList*,const char*,const char*);
SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3*, ExprList*);
+SQLITE_PRIVATE void sqlite3ExprListDeleteGeneric(sqlite3*,void*);
SQLITE_PRIVATE u32 sqlite3ExprListFlags(const ExprList*);
SQLITE_PRIVATE int sqlite3IndexHasDuplicateRootPage(Index*);
SQLITE_PRIVATE int sqlite3Init(sqlite3*, char**);
@@ -20253,6 +20859,7 @@ SQLITE_PRIVATE int sqlite3DbMaskAllZero(yDbMask);
SQLITE_PRIVATE void sqlite3DropTable(Parse*, SrcList*, int, int);
SQLITE_PRIVATE void sqlite3CodeDropTable(Parse*, Table*, int, int);
SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3*, Table*);
+SQLITE_PRIVATE void sqlite3DeleteTableGeneric(sqlite3*, void*);
SQLITE_PRIVATE void sqlite3FreeIndex(sqlite3*, Index*);
#ifndef SQLITE_OMIT_AUTOINCREMENT
SQLITE_PRIVATE void sqlite3AutoincrementBegin(Parse *pParse);
@@ -20289,8 +20896,9 @@ SQLITE_PRIVATE int sqlite3Select(Parse*, Select*, SelectDest*);
SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList*,
Expr*,ExprList*,u32,Expr*);
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*);
+SQLITE_PRIVATE void sqlite3SelectDeleteGeneric(sqlite3*,void*);
SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*);
-SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int);
+SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, Trigger*);
SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*);
@@ -20352,7 +20960,7 @@ SQLITE_PRIVATE int sqlite3ExprCompare(const Parse*,const Expr*,const Expr*, int)
SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr*,Expr*,int);
SQLITE_PRIVATE int sqlite3ExprListCompare(const ExprList*,const ExprList*, int);
SQLITE_PRIVATE int sqlite3ExprImpliesExpr(const Parse*,const Expr*,const Expr*, int);
-SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr*,int);
+SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr*,int,int);
SQLITE_PRIVATE void sqlite3AggInfoPersistWalkerInit(Walker*,Parse*);
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
@@ -20379,7 +20987,7 @@ SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8);
SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int);
-SQLITE_PRIVATE int sqlite3ExprIsTableConstraint(Expr*,const SrcItem*);
+SQLITE_PRIVATE int sqlite3ExprIsSingleTableConstraint(Expr*,const SrcList*,int);
#ifdef SQLITE_ENABLE_CURSOR_HINTS
SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*);
#endif
@@ -20387,6 +20995,7 @@ SQLITE_PRIVATE int sqlite3ExprIsInteger(const Expr*, int*);
SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr*);
SQLITE_PRIVATE int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
SQLITE_PRIVATE int sqlite3IsRowid(const char*);
+SQLITE_PRIVATE const char *sqlite3RowidAlias(Table *pTab);
SQLITE_PRIVATE void sqlite3GenerateRowDelete(
Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int);
SQLITE_PRIVATE void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int);
@@ -20501,6 +21110,7 @@ SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*);
SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*);
SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*);
SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
+
SQLITE_PRIVATE int sqlite3RealSameAsInt(double,sqlite3_int64);
SQLITE_PRIVATE i64 sqlite3RealToI64(double);
SQLITE_PRIVATE int sqlite3Int64ToText(i64,char*);
@@ -20513,6 +21123,7 @@ SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar);
#endif
SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte);
SQLITE_PRIVATE u32 sqlite3Utf8Read(const u8**);
+SQLITE_PRIVATE int sqlite3Utf8ReadLimited(const u8*, int, u32*);
SQLITE_PRIVATE LogEst sqlite3LogEst(u64);
SQLITE_PRIVATE LogEst sqlite3LogEstAdd(LogEst,LogEst);
SQLITE_PRIVATE LogEst sqlite3LogEstFromDouble(double);
@@ -20605,6 +21216,7 @@ SQLITE_PRIVATE void sqlite3FileSuffix3(const char*, char*);
SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z,u8);
SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8);
+SQLITE_PRIVATE int sqlite3ValueIsOfClass(const sqlite3_value*, void(*)(void*));
SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8);
SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8,
void(*)(void*));
@@ -20656,7 +21268,8 @@ SQLITE_PRIVATE int sqlite3MatchEName(
const struct ExprList_item*,
const char*,
const char*,
- const char*
+ const char*,
+ int*
);
SQLITE_PRIVATE Bitmask sqlite3ExprColUsed(Expr*);
SQLITE_PRIVATE u8 sqlite3StrIHash(const char*);
@@ -20712,6 +21325,11 @@ SQLITE_PRIVATE void sqlite3OomClear(sqlite3*);
SQLITE_PRIVATE int sqlite3ApiExit(sqlite3 *db, int);
SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *);
+SQLITE_PRIVATE char *sqlite3RCStrRef(char*);
+SQLITE_PRIVATE void sqlite3RCStrUnref(void*);
+SQLITE_PRIVATE char *sqlite3RCStrNew(u64);
+SQLITE_PRIVATE char *sqlite3RCStrResize(char*,u64);
+
SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, sqlite3*, char*, int, int);
SQLITE_PRIVATE int sqlite3StrAccumEnlarge(StrAccum*, i64);
SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*);
@@ -20827,10 +21445,7 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *, VTable *);
SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*);
-#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
- && !defined(SQLITE_OMIT_VIRTUALTABLE)
-SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(sqlite3_index_info*);
-#endif
+SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(Parse*);
SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*);
SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
@@ -20855,6 +21470,7 @@ SQLITE_PRIVATE Cte *sqlite3CteNew(Parse*,Token*,ExprList*,Select*,u8);
SQLITE_PRIVATE void sqlite3CteDelete(sqlite3*,Cte*);
SQLITE_PRIVATE With *sqlite3WithAdd(Parse*,With*,Cte*);
SQLITE_PRIVATE void sqlite3WithDelete(sqlite3*,With*);
+SQLITE_PRIVATE void sqlite3WithDeleteGeneric(sqlite3*,void*);
SQLITE_PRIVATE With *sqlite3WithPush(Parse*, With*, u8);
#else
# define sqlite3CteNew(P,T,E,S) ((void*)0)
@@ -20867,7 +21483,7 @@ SQLITE_PRIVATE With *sqlite3WithPush(Parse*, With*, u8);
SQLITE_PRIVATE Upsert *sqlite3UpsertNew(sqlite3*,ExprList*,Expr*,ExprList*,Expr*,Upsert*);
SQLITE_PRIVATE void sqlite3UpsertDelete(sqlite3*,Upsert*);
SQLITE_PRIVATE Upsert *sqlite3UpsertDup(sqlite3*,Upsert*);
-SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*);
+SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(Parse*,SrcList*,Upsert*,Upsert*);
SQLITE_PRIVATE void sqlite3UpsertDoUpdate(Parse*,Upsert*,Table*,Index*,int);
SQLITE_PRIVATE Upsert *sqlite3UpsertOfIndex(Upsert*,Index*);
SQLITE_PRIVATE int sqlite3UpsertNextIsIPK(Upsert*);
@@ -20966,6 +21582,7 @@ SQLITE_PRIVATE int sqlite3ExprCheckHeight(Parse*, int);
#define sqlite3SelectExprHeight(x) 0
#define sqlite3ExprCheckHeight(x,y)
#endif
+SQLITE_PRIVATE void sqlite3ExprSetErrorOffset(Expr*,int);
SQLITE_PRIVATE u32 sqlite3Get4byte(const u8*);
SQLITE_PRIVATE void sqlite3Put4byte(u8*, u32);
@@ -21077,6 +21694,12 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void);
SQLITE_PRIVATE sqlite3_uint64 sqlite3Hwtime(void);
#endif
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+# define IS_STMT_SCANSTATUS(db) (db->flags & SQLITE_StmtScanStatus)
+#else
+# define IS_STMT_SCANSTATUS(db) 0
+#endif
+
#endif /* SQLITEINT_H */
/************** End of sqliteInt.h *******************************************/
@@ -21245,14 +21868,14 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
"4_BYTE_ALIGNED_MALLOC",
#endif
-#ifdef SQLITE_64BIT_STATS
- "64BIT_STATS",
-#endif
#ifdef SQLITE_ALLOW_COVERING_INDEX_SCAN
# if SQLITE_ALLOW_COVERING_INDEX_SCAN != 1
"ALLOW_COVERING_INDEX_SCAN=" CTIMEOPT_VAL(SQLITE_ALLOW_COVERING_INDEX_SCAN),
# endif
#endif
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ "ALLOW_ROWID_IN_VIEW",
+#endif
#ifdef SQLITE_ALLOW_URI_AUTHORITY
"ALLOW_URI_AUTHORITY",
#endif
@@ -21543,6 +22166,9 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS
"EXPLAIN_ESTIMATED_ROWS",
#endif
+#ifdef SQLITE_EXTRA_AUTOEXT
+ "EXTRA_AUTOEXT=" CTIMEOPT_VAL(SQLITE_EXTRA_AUTOEXT),
+#endif
#ifdef SQLITE_EXTRA_IFNULLROW
"EXTRA_IFNULLROW",
#endif
@@ -21584,6 +22210,9 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_INTEGRITY_CHECK_ERROR_MAX
"INTEGRITY_CHECK_ERROR_MAX=" CTIMEOPT_VAL(SQLITE_INTEGRITY_CHECK_ERROR_MAX),
#endif
+#ifdef SQLITE_LEGACY_JSON_VALID
+ "LEGACY_JSON_VALID",
+#endif
#ifdef SQLITE_LIKE_DOESNT_MATCH_BLOBS
"LIKE_DOESNT_MATCH_BLOBS",
#endif
@@ -21821,6 +22450,9 @@ static const char * const sqlite3azCompileOpt[] = {
#ifdef SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS
"OMIT_SCHEMA_VERSION_PRAGMAS",
#endif
+#ifdef SQLITE_OMIT_SEH
+ "OMIT_SEH",
+#endif
#ifdef SQLITE_OMIT_SHARED_CACHE
"OMIT_SHARED_CACHE",
#endif
@@ -22072,7 +22704,7 @@ SQLITE_PRIVATE const unsigned char *sqlite3aGTb = &sqlite3UpperToLower[256+12-OP
** isalnum() 0x06
** isxdigit() 0x08
** toupper() 0x20
-** SQLite identifier character 0x40
+** SQLite identifier character 0x40 $, _, or non-ascii
** Quote character 0x80
**
** Bit 0x20 is set if the mapped character requires translation to upper
@@ -22218,6 +22850,10 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
SQLITE_ALLOW_COVERING_INDEX_SCAN, /* bUseCis */
0, /* bSmallMalloc */
1, /* bExtraSchemaChecks */
+ sizeof(LONGDOUBLE_TYPE)>8, /* bUseLongDouble */
+#ifdef SQLITE_DEBUG
+ 0, /* bJsonSelfcheck */
+#endif
0x7ffffffe, /* mxStrlen */
0, /* neverCorrupt */
SQLITE_DEFAULT_LOOKASIDE, /* szLookaside, nLookaside */
@@ -22260,13 +22896,16 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
#ifndef SQLITE_UNTESTABLE
0, /* xTestCallback */
#endif
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ 0, /* mNoVisibleRowid. 0 == allow rowid-in-view */
+#endif
0, /* bLocaltimeFault */
0, /* xAltLocaltime */
0x7ffffffe, /* iOnceResetThreshold */
SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */
0, /* iPrngSeed */
#ifdef SQLITE_DEBUG
- {0,0,0,0,0,0} /* aTune */
+ {0,0,0,0,0,0}, /* aTune */
#endif
};
@@ -22447,6 +23086,9 @@ typedef struct VdbeSorter VdbeSorter;
/* Elements of the linked list at Vdbe.pAuxData */
typedef struct AuxData AuxData;
+/* A cache of large TEXT or BLOB values in a VdbeCursor */
+typedef struct VdbeTxtBlbCache VdbeTxtBlbCache;
+
/* Types of VDBE cursors */
#define CURTYPE_BTREE 0
#define CURTYPE_SORTER 1
@@ -22478,6 +23120,7 @@ struct VdbeCursor {
Bool useRandomRowid:1; /* Generate new record numbers semi-randomly */
Bool isOrdered:1; /* True if the table is not BTREE_UNORDERED */
Bool noReuse:1; /* OpenEphemeral may not reuse this cursor */
+ Bool colCache:1; /* pCache pointer is initialized and non-NULL */
u16 seekHit; /* See the OP_SeekHit and OP_IfNoHope opcodes */
union { /* pBtx for isEphermeral. pAltMap otherwise */
Btree *pBtx; /* Separate file holding temporary table */
@@ -22518,6 +23161,7 @@ struct VdbeCursor {
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
u64 maskUsed; /* Mask of columns used by this cursor */
#endif
+ VdbeTxtBlbCache *pCache; /* Cache of large TEXT or BLOB values */
/* 2*nField extra array elements allocated for aType[], beyond the one
** static element declared in the structure. nField total array slots for
@@ -22530,13 +23174,26 @@ struct VdbeCursor {
#define IsNullCursor(P) \
((P)->eCurType==CURTYPE_PSEUDO && (P)->nullRow && (P)->seekResult==0)
-
/*
** A value for VdbeCursor.cacheStatus that means the cache is always invalid.
*/
#define CACHE_STALE 0
/*
+** Large TEXT or BLOB values can be slow to load, so we want to avoid
+** loading them more than once. For that reason, large TEXT and BLOB values
+** can be stored in a cache defined by this object, and attached to the
+** VdbeCursor using the pCache field.
+*/
+struct VdbeTxtBlbCache {
+ char *pCValue; /* A RCStr buffer to hold the value */
+ i64 iOffset; /* File offset of the row being cached */
+ int iCol; /* Column for which the cache is valid */
+ u32 cacheStatus; /* Vdbe.cacheCtr value */
+ u32 colCacheCtr; /* Column cache counter */
+};
+
+/*
** 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
** well as the current memory cell array and various other frame specific
@@ -22856,16 +23513,18 @@ struct Vdbe {
u32 nWrite; /* Number of write operations that have occurred */
#endif
u16 nResColumn; /* Number of columns in one row of the result set */
+ u16 nResAlloc; /* Column slots allocated to aColName[] */
u8 errorAction; /* Recovery action to do in case of an error */
u8 minWriteFileFormat; /* Minimum file format for writable database files */
u8 prepFlags; /* SQLITE_PREPARE_* flags */
u8 eVdbeState; /* On of the VDBE_*_STATE values */
bft expired:2; /* 1: recompile VM immediately 2: when convenient */
- bft explain:2; /* True if EXPLAIN present on SQL command */
+ bft explain:2; /* 0: normal, 1: EXPLAIN, 2: EXPLAIN QUERY PLAN */
bft changeCntOn:1; /* True to update the change-counter */
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 haveEqpOps:1; /* Bytecode supports EXPLAIN QUERY PLAN */
yDbMask btreeMask; /* Bitmask of db->aDb[] entries referenced */
yDbMask lockMask; /* Subset of btreeMask that requires a lock */
u32 aCounter[9]; /* Counters used by sqlite3_stmt_status() */
@@ -22912,7 +23571,7 @@ struct PreUpdate {
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 */
+ Table *pTab; /* Schema object being updated */
Index *pPk; /* PK index if pTab is WITHOUT ROWID */
};
@@ -23002,6 +23661,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemSetZeroBlob(Mem*,int);
SQLITE_PRIVATE int sqlite3VdbeMemIsRowSet(const Mem*);
#endif
SQLITE_PRIVATE int sqlite3VdbeMemSetRowSet(Mem*);
+SQLITE_PRIVATE void sqlite3VdbeMemZeroTerminateIfAble(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemMakeWriteable(Mem*);
SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem*, u8, u8);
SQLITE_PRIVATE int sqlite3IntFloatCompare(i64,double);
@@ -23449,7 +24109,7 @@ SQLITE_API int sqlite3_db_status(
case SQLITE_DBSTATUS_CACHE_MISS:
case SQLITE_DBSTATUS_CACHE_WRITE:{
int i;
- int nRet = 0;
+ u64 nRet = 0;
assert( SQLITE_DBSTATUS_CACHE_MISS==SQLITE_DBSTATUS_CACHE_HIT+1 );
assert( SQLITE_DBSTATUS_CACHE_WRITE==SQLITE_DBSTATUS_CACHE_HIT+2 );
@@ -23462,7 +24122,7 @@ SQLITE_API int sqlite3_db_status(
*pHighwater = 0; /* IMP: R-42420-56072 */
/* IMP: R-54100-20147 */
/* IMP: R-29431-39229 */
- *pCurrent = nRet;
+ *pCurrent = (int)nRet & 0x7fffffff;
break;
}
@@ -23565,6 +24225,7 @@ struct DateTime {
char validTZ; /* True (1) if tz is valid */
char tzSet; /* Timezone was set explicitly */
char isError; /* An overflow has occurred */
+ char useSubsec; /* Display subsecond precision */
};
@@ -23597,8 +24258,8 @@ struct DateTime {
*/
static int getDigits(const char *zDate, const char *zFormat, ...){
/* The aMx[] array translates the 3rd character of each format
- ** spec into a max size: a b c d e f */
- static const u16 aMx[] = { 12, 14, 24, 31, 59, 9999 };
+ ** spec into a max size: a b c d e f */
+ static const u16 aMx[] = { 12, 14, 24, 31, 59, 14712 };
va_list ap;
int cnt = 0;
char nextC;
@@ -23879,6 +24540,11 @@ static int parseDateOrTime(
}else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8)>0 ){
setRawDateNumber(p, r);
return 0;
+ }else if( (sqlite3StrICmp(zDate,"subsec")==0
+ || sqlite3StrICmp(zDate,"subsecond")==0)
+ && sqlite3NotPureFunc(context) ){
+ p->useSubsec = 1;
+ return setDateTimeToCurrent(context, p);
}
return 1;
}
@@ -23934,17 +24600,14 @@ static void computeYMD(DateTime *p){
** Compute the Hour, Minute, and Seconds from the julian day number.
*/
static void computeHMS(DateTime *p){
- int s;
+ int day_ms, day_min; /* milliseconds, minutes into the day */
if( p->validHMS ) return;
computeJD(p);
- s = (int)((p->iJD + 43200000) % 86400000);
- p->s = s/1000.0;
- s = (int)p->s;
- p->s -= s;
- p->h = s/3600;
- s -= p->h*3600;
- p->m = s/60;
- p->s += s - p->m*60;
+ day_ms = (int)((p->iJD + 43200000) % 86400000);
+ p->s = (day_ms % 60000)/1000.0;
+ day_min = day_ms/60000;
+ p->m = day_min % 60;
+ p->h = day_min / 60;
p->rawS = 0;
p->validHMS = 1;
}
@@ -24124,6 +24787,25 @@ static const struct {
};
/*
+** If the DateTime p is raw number, try to figure out if it is
+** a julian day number of a unix timestamp. Set the p value
+** appropriately.
+*/
+static void autoAdjustDate(DateTime *p){
+ if( !p->rawS || p->validJD ){
+ p->rawS = 0;
+ }else if( p->s>=-21086676*(i64)10000 /* -4713-11-24 12:00:00 */
+ && p->s<=(25340230*(i64)10000)+799 /* 9999-12-31 23:59:59 */
+ ){
+ double r = p->s*1000.0 + 210866760000000.0;
+ clearYMD_HMS_TZ(p);
+ p->iJD = (sqlite3_int64)(r + 0.5);
+ p->validJD = 1;
+ p->rawS = 0;
+ }
+}
+
+/*
** Process a modifier to a date-time stamp. The modifiers are
** as follows:
**
@@ -24166,19 +24848,8 @@ static int parseModifier(
*/
if( sqlite3_stricmp(z, "auto")==0 ){
if( idx>1 ) return 1; /* IMP: R-33611-57934 */
- if( !p->rawS || p->validJD ){
- rc = 0;
- p->rawS = 0;
- }else if( p->s>=-21086676*(i64)10000 /* -4713-11-24 12:00:00 */
- && p->s<=(25340230*(i64)10000)+799 /* 9999-12-31 23:59:59 */
- ){
- r = p->s*1000.0 + 210866760000000.0;
- clearYMD_HMS_TZ(p);
- p->iJD = (sqlite3_int64)(r + 0.5);
- p->validJD = 1;
- p->rawS = 0;
- rc = 0;
- }
+ autoAdjustDate(p);
+ rc = 0;
}
break;
}
@@ -24293,8 +24964,22 @@ static int parseModifier(
**
** Move the date backwards to the beginning of the current day,
** or month or year.
+ **
+ ** subsecond
+ ** subsec
+ **
+ ** Show subsecond precision in the output of datetime() and
+ ** unixepoch() and strftime('%s').
*/
- if( sqlite3_strnicmp(z, "start of ", 9)!=0 ) break;
+ if( sqlite3_strnicmp(z, "start of ", 9)!=0 ){
+ if( sqlite3_stricmp(z, "subsec")==0
+ || sqlite3_stricmp(z, "subsecond")==0
+ ){
+ p->useSubsec = 1;
+ rc = 0;
+ }
+ break;
+ }
if( !p->validJD && !p->validYMD && !p->validHMS ) break;
z += 9;
computeYMD(p);
@@ -24330,18 +25015,73 @@ static int parseModifier(
case '9': {
double rRounder;
int i;
- for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){}
+ int Y,M,D,h,m,x;
+ const char *z2 = z;
+ char z0 = z[0];
+ for(n=1; z[n]; n++){
+ if( z[n]==':' ) break;
+ if( sqlite3Isspace(z[n]) ) break;
+ if( z[n]=='-' ){
+ if( n==5 && getDigits(&z[1], "40f", &Y)==1 ) break;
+ if( n==6 && getDigits(&z[1], "50f", &Y)==1 ) break;
+ }
+ }
if( sqlite3AtoF(z, &r, n, SQLITE_UTF8)<=0 ){
- rc = 1;
+ assert( rc==1 );
break;
}
- if( z[n]==':' ){
+ if( z[n]=='-' ){
+ /* A modifier of the form (+|-)YYYY-MM-DD adds or subtracts the
+ ** specified number of years, months, and days. MM is limited to
+ ** the range 0-11 and DD is limited to 0-30.
+ */
+ if( z0!='+' && z0!='-' ) break; /* Must start with +/- */
+ if( n==5 ){
+ if( getDigits(&z[1], "40f-20a-20d", &Y, &M, &D)!=3 ) break;
+ }else{
+ assert( n==6 );
+ if( getDigits(&z[1], "50f-20a-20d", &Y, &M, &D)!=3 ) break;
+ z++;
+ }
+ if( M>=12 ) break; /* M range 0..11 */
+ if( D>=31 ) break; /* D range 0..30 */
+ computeYMD_HMS(p);
+ p->validJD = 0;
+ if( z0=='-' ){
+ p->Y -= Y;
+ p->M -= M;
+ D = -D;
+ }else{
+ p->Y += Y;
+ p->M += M;
+ }
+ x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12;
+ p->Y += x;
+ p->M -= x*12;
+ computeJD(p);
+ p->validHMS = 0;
+ p->validYMD = 0;
+ p->iJD += (i64)D*86400000;
+ if( z[11]==0 ){
+ rc = 0;
+ break;
+ }
+ if( sqlite3Isspace(z[11])
+ && getDigits(&z[12], "20c:20e", &h, &m)==2
+ ){
+ z2 = &z[12];
+ n = 2;
+ }else{
+ break;
+ }
+ }
+ if( z2[n]==':' ){
/* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the
** specified number of hours, minutes, seconds, and fractional seconds
** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be
** omitted.
*/
- const char *z2 = z;
+
DateTime tx;
sqlite3_int64 day;
if( !sqlite3Isdigit(*z2) ) z2++;
@@ -24351,7 +25091,7 @@ static int parseModifier(
tx.iJD -= 43200000;
day = tx.iJD/86400000;
tx.iJD -= day*86400000;
- if( z[0]=='-' ) tx.iJD = -tx.iJD;
+ if( z0=='-' ) tx.iJD = -tx.iJD;
computeJD(p);
clearYMD_HMS_TZ(p);
p->iJD += tx.iJD;
@@ -24367,7 +25107,7 @@ static int parseModifier(
if( n>10 || n<3 ) break;
if( sqlite3UpperToLower[(u8)z[n-1]]=='s' ) n--;
computeJD(p);
- rc = 1;
+ assert( rc==1 );
rRounder = r<0 ? -0.5 : +0.5;
for(i=0; i<ArraySize(aXformType); i++){
if( aXformType[i].nName==n
@@ -24376,7 +25116,6 @@ static int parseModifier(
){
switch( i ){
case 4: { /* Special processing to add months */
- int x;
assert( strcmp(aXformType[i].zName,"month")==0 );
computeYMD_HMS(p);
p->M += (int)r;
@@ -24452,6 +25191,12 @@ static int isDate(
}
computeJD(p);
if( p->isError || !validJulianDay(p->iJD) ) return 1;
+ if( argc==1 && p->validYMD && p->D>28 ){
+ /* Make sure a YYYY-MM-DD is normalized.
+ ** Example: 2023-02-31 -> 2023-03-03 */
+ assert( p->validJD );
+ p->validYMD = 0;
+ }
return 0;
}
@@ -24492,7 +25237,11 @@ static void unixepochFunc(
DateTime x;
if( isDate(context, argc, argv, &x)==0 ){
computeJD(&x);
- sqlite3_result_int64(context, x.iJD/1000 - 21086676*(i64)10000);
+ if( x.useSubsec ){
+ sqlite3_result_double(context, (x.iJD - 21086676*(i64)10000000)/1000.0);
+ }else{
+ sqlite3_result_int64(context, x.iJD/1000 - 21086676*(i64)10000);
+ }
}
}
@@ -24508,8 +25257,8 @@ static void datetimeFunc(
){
DateTime x;
if( isDate(context, argc, argv, &x)==0 ){
- int Y, s;
- char zBuf[24];
+ int Y, s, n;
+ char zBuf[32];
computeYMD_HMS(&x);
Y = x.Y;
if( Y<0 ) Y = -Y;
@@ -24530,15 +25279,28 @@ static void datetimeFunc(
zBuf[15] = '0' + (x.m/10)%10;
zBuf[16] = '0' + (x.m)%10;
zBuf[17] = ':';
- s = (int)x.s;
- zBuf[18] = '0' + (s/10)%10;
- zBuf[19] = '0' + (s)%10;
- zBuf[20] = 0;
+ if( x.useSubsec ){
+ s = (int)(1000.0*x.s + 0.5);
+ zBuf[18] = '0' + (s/10000)%10;
+ zBuf[19] = '0' + (s/1000)%10;
+ zBuf[20] = '.';
+ zBuf[21] = '0' + (s/100)%10;
+ zBuf[22] = '0' + (s/10)%10;
+ zBuf[23] = '0' + (s)%10;
+ zBuf[24] = 0;
+ n = 24;
+ }else{
+ s = (int)x.s;
+ zBuf[18] = '0' + (s/10)%10;
+ zBuf[19] = '0' + (s)%10;
+ zBuf[20] = 0;
+ n = 20;
+ }
if( x.Y<0 ){
zBuf[0] = '-';
- sqlite3_result_text(context, zBuf, 20, SQLITE_TRANSIENT);
+ sqlite3_result_text(context, zBuf, n, SQLITE_TRANSIENT);
}else{
- sqlite3_result_text(context, &zBuf[1], 19, SQLITE_TRANSIENT);
+ sqlite3_result_text(context, &zBuf[1], n-1, SQLITE_TRANSIENT);
}
}
}
@@ -24555,7 +25317,7 @@ static void timeFunc(
){
DateTime x;
if( isDate(context, argc, argv, &x)==0 ){
- int s;
+ int s, n;
char zBuf[16];
computeHMS(&x);
zBuf[0] = '0' + (x.h/10)%10;
@@ -24564,11 +25326,24 @@ static void timeFunc(
zBuf[3] = '0' + (x.m/10)%10;
zBuf[4] = '0' + (x.m)%10;
zBuf[5] = ':';
- s = (int)x.s;
- zBuf[6] = '0' + (s/10)%10;
- zBuf[7] = '0' + (s)%10;
- zBuf[8] = 0;
- sqlite3_result_text(context, zBuf, 8, SQLITE_TRANSIENT);
+ if( x.useSubsec ){
+ s = (int)(1000.0*x.s + 0.5);
+ zBuf[6] = '0' + (s/10000)%10;
+ zBuf[7] = '0' + (s/1000)%10;
+ zBuf[8] = '.';
+ zBuf[9] = '0' + (s/100)%10;
+ zBuf[10] = '0' + (s/10)%10;
+ zBuf[11] = '0' + (s)%10;
+ zBuf[12] = 0;
+ n = 12;
+ }else{
+ s = (int)x.s;
+ zBuf[6] = '0' + (s/10)%10;
+ zBuf[7] = '0' + (s)%10;
+ zBuf[8] = 0;
+ n = 8;
+ }
+ sqlite3_result_text(context, zBuf, n, SQLITE_TRANSIENT);
}
}
@@ -24623,7 +25398,7 @@ static void dateFunc(
** %M minute 00-59
** %s seconds since 1970-01-01
** %S seconds 00-59
-** %w day of week 0-6 sunday==0
+** %w day of week 0-6 Sunday==0
** %W week of year 00-53
** %Y year 0000-9999
** %% %
@@ -24649,13 +25424,16 @@ static void strftimeFunc(
computeJD(&x);
computeYMD_HMS(&x);
for(i=j=0; zFmt[i]; i++){
+ char cf;
if( zFmt[i]!='%' ) continue;
if( j<i ) sqlite3_str_append(&sRes, zFmt+j, (int)(i-j));
i++;
j = i + 1;
- switch( zFmt[i] ){
- case 'd': {
- sqlite3_str_appendf(&sRes, "%02d", x.D);
+ cf = zFmt[i];
+ switch( cf ){
+ case 'd': /* Fall thru */
+ case 'e': {
+ sqlite3_str_appendf(&sRes, cf=='d' ? "%02d" : "%2d", x.D);
break;
}
case 'f': {
@@ -24664,8 +25442,21 @@ static void strftimeFunc(
sqlite3_str_appendf(&sRes, "%06.3f", s);
break;
}
- case 'H': {
- sqlite3_str_appendf(&sRes, "%02d", x.h);
+ case 'F': {
+ sqlite3_str_appendf(&sRes, "%04d-%02d-%02d", x.Y, x.M, x.D);
+ break;
+ }
+ case 'H':
+ case 'k': {
+ sqlite3_str_appendf(&sRes, cf=='H' ? "%02d" : "%2d", x.h);
+ break;
+ }
+ case 'I': /* Fall thru */
+ case 'l': {
+ int h = x.h;
+ if( h>12 ) h -= 12;
+ if( h==0 ) h = 12;
+ sqlite3_str_appendf(&sRes, cf=='I' ? "%02d" : "%2d", h);
break;
}
case 'W': /* Fall thru */
@@ -24677,7 +25468,7 @@ static void strftimeFunc(
y.D = 1;
computeJD(&y);
nDay = (int)((x.iJD-y.iJD+43200000)/86400000);
- if( zFmt[i]=='W' ){
+ if( cf=='W' ){
int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */
wd = (int)(((x.iJD+43200000)/86400000)%7);
sqlite3_str_appendf(&sRes,"%02d",(nDay+7-wd)/7);
@@ -24698,18 +25489,42 @@ static void strftimeFunc(
sqlite3_str_appendf(&sRes,"%02d",x.m);
break;
}
+ case 'p': /* Fall thru */
+ case 'P': {
+ if( x.h>=12 ){
+ sqlite3_str_append(&sRes, cf=='p' ? "PM" : "pm", 2);
+ }else{
+ sqlite3_str_append(&sRes, cf=='p' ? "AM" : "am", 2);
+ }
+ break;
+ }
+ case 'R': {
+ sqlite3_str_appendf(&sRes, "%02d:%02d", x.h, x.m);
+ break;
+ }
case 's': {
- i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000);
- sqlite3_str_appendf(&sRes,"%lld",iS);
+ if( x.useSubsec ){
+ sqlite3_str_appendf(&sRes,"%.3f",
+ (x.iJD - 21086676*(i64)10000000)/1000.0);
+ }else{
+ i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000);
+ sqlite3_str_appendf(&sRes,"%lld",iS);
+ }
break;
}
case 'S': {
sqlite3_str_appendf(&sRes,"%02d",(int)x.s);
break;
}
+ case 'T': {
+ sqlite3_str_appendf(&sRes,"%02d:%02d:%02d", x.h, x.m, (int)x.s);
+ break;
+ }
+ case 'u': /* Fall thru */
case 'w': {
- sqlite3_str_appendchar(&sRes, 1,
- (char)(((x.iJD+129600000)/86400000) % 7) + '0');
+ char c = (char)(((x.iJD+129600000)/86400000) % 7) + '0';
+ if( c=='0' && cf=='u' ) c = '7';
+ sqlite3_str_appendchar(&sRes, 1, c);
break;
}
case 'Y': {
@@ -24759,6 +25574,117 @@ static void cdateFunc(
}
/*
+** timediff(DATE1, DATE2)
+**
+** Return the amount of time that must be added to DATE2 in order to
+** convert it into DATE2. The time difference format is:
+**
+** +YYYY-MM-DD HH:MM:SS.SSS
+**
+** The initial "+" becomes "-" if DATE1 occurs before DATE2. For
+** date/time values A and B, the following invariant should hold:
+**
+** datetime(A) == (datetime(B, timediff(A,B))
+**
+** Both DATE arguments must be either a julian day number, or an
+** ISO-8601 string. The unix timestamps are not supported by this
+** routine.
+*/
+static void timediffFunc(
+ sqlite3_context *context,
+ int NotUsed1,
+ sqlite3_value **argv
+){
+ char sign;
+ int Y, M;
+ DateTime d1, d2;
+ sqlite3_str sRes;
+ UNUSED_PARAMETER(NotUsed1);
+ if( isDate(context, 1, &argv[0], &d1) ) return;
+ if( isDate(context, 1, &argv[1], &d2) ) return;
+ computeYMD_HMS(&d1);
+ computeYMD_HMS(&d2);
+ if( d1.iJD>=d2.iJD ){
+ sign = '+';
+ Y = d1.Y - d2.Y;
+ if( Y ){
+ d2.Y = d1.Y;
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ M = d1.M - d2.M;
+ if( M<0 ){
+ Y--;
+ M += 12;
+ }
+ if( M!=0 ){
+ d2.M = d1.M;
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ while( d1.iJD<d2.iJD ){
+ M--;
+ if( M<0 ){
+ M = 11;
+ Y--;
+ }
+ d2.M--;
+ if( d2.M<1 ){
+ d2.M = 12;
+ d2.Y--;
+ }
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ d1.iJD -= d2.iJD;
+ d1.iJD += (u64)1486995408 * (u64)100000;
+ }else /* d1<d2 */{
+ sign = '-';
+ Y = d2.Y - d1.Y;
+ if( Y ){
+ d2.Y = d1.Y;
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ M = d2.M - d1.M;
+ if( M<0 ){
+ Y--;
+ M += 12;
+ }
+ if( M!=0 ){
+ d2.M = d1.M;
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ while( d1.iJD>d2.iJD ){
+ M--;
+ if( M<0 ){
+ M = 11;
+ Y--;
+ }
+ d2.M++;
+ if( d2.M>12 ){
+ d2.M = 1;
+ d2.Y++;
+ }
+ d2.validJD = 0;
+ computeJD(&d2);
+ }
+ d1.iJD = d2.iJD - d1.iJD;
+ d1.iJD += (u64)1486995408 * (u64)100000;
+ }
+ d1.validYMD = 0;
+ d1.validHMS = 0;
+ d1.validTZ = 0;
+ computeYMD_HMS(&d1);
+ sqlite3StrAccumInit(&sRes, 0, 0, 0, 100);
+ sqlite3_str_appendf(&sRes, "%c%04d-%02d-%02d %02d:%02d:%06.3f",
+ sign, Y, M, d1.D-1, d1.h, d1.m, d1.s);
+ sqlite3ResultStrAccum(context, &sRes);
+}
+
+
+/*
** current_timestamp()
**
** This function returns the same value as datetime('now').
@@ -24832,6 +25758,7 @@ SQLITE_PRIVATE void sqlite3RegisterDateTimeFunctions(void){
PURE_DATE(time, -1, 0, 0, timeFunc ),
PURE_DATE(datetime, -1, 0, 0, datetimeFunc ),
PURE_DATE(strftime, -1, 0, 0, strftimeFunc ),
+ PURE_DATE(timediff, 2, 0, 0, timediffFunc ),
DFUNCTION(current_time, 0, 0, 0, ctimeFunc ),
DFUNCTION(current_timestamp, 0, 0, 0, ctimestampFunc),
DFUNCTION(current_date, 0, 0, 0, cdateFunc ),
@@ -24985,7 +25912,7 @@ SQLITE_PRIVATE int sqlite3OsFileControl(sqlite3_file *id, int op, void *pArg){
/* Faults are not injected into COMMIT_PHASETWO because, assuming SQLite
** is using a regular VFS, it is called after the corresponding
** transaction has been committed. Injecting a fault at this point
- ** confuses the test scripts - the COMMIT comand returns SQLITE_NOMEM
+ ** confuses the test scripts - the COMMIT command returns SQLITE_NOMEM
** but the transaction is committed anyway.
**
** The core must call OsFileControl() though, not OsFileControlHint(),
@@ -25606,7 +26533,7 @@ static void *sqlite3MemMalloc(int nByte){
** or sqlite3MemRealloc().
**
** For this low-level routine, we already know that pPrior!=0 since
-** cases where pPrior==0 will have been intecepted and dealt with
+** cases where pPrior==0 will have been intercepted and dealt with
** by higher-level routines.
*/
static void sqlite3MemFree(void *pPrior){
@@ -25694,7 +26621,7 @@ static int sqlite3MemInit(void *NotUsed){
return SQLITE_OK;
}
len = sizeof(cpuCount);
- /* One usually wants to use hw.acctivecpu for MT decisions, but not here */
+ /* One usually wants to use hw.activecpu for MT decisions, but not here */
sysctlbyname("hw.ncpu", &cpuCount, &len, NULL, 0);
if( cpuCount>1 ){
/* defer MT decisions to system malloc */
@@ -27686,7 +28613,7 @@ static void checkMutexFree(sqlite3_mutex *p){
assert( SQLITE_MUTEX_FAST<2 );
assert( SQLITE_MUTEX_WARNONCONTENTION<2 );
-#if SQLITE_ENABLE_API_ARMOR
+#ifdef SQLITE_ENABLE_API_ARMOR
if( ((CheckMutex*)p)->iType<2 )
#endif
{
@@ -28161,7 +29088,7 @@ SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
/*
** The sqlite3_mutex.id, sqlite3_mutex.nRef, and sqlite3_mutex.owner fields
-** are necessary under two condidtions: (1) Debug builds and (2) using
+** are necessary under two conditions: (1) Debug builds and (2) using
** home-grown mutexes. Encapsulate these conditions into a single #define.
*/
#if defined(SQLITE_DEBUG) || defined(SQLITE_HOMEGROWN_RECURSIVE_MUTEX)
@@ -28358,7 +29285,7 @@ static sqlite3_mutex *pthreadMutexAlloc(int iType){
*/
static void pthreadMutexFree(sqlite3_mutex *p){
assert( p->nRef==0 );
-#if SQLITE_ENABLE_API_ARMOR
+#ifdef SQLITE_ENABLE_API_ARMOR
if( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE )
#endif
{
@@ -28662,7 +29589,7 @@ struct sqlite3_mutex {
CRITICAL_SECTION mutex; /* Mutex controlling the lock */
int id; /* Mutex type */
#ifdef SQLITE_DEBUG
- volatile int nRef; /* Number of enterances */
+ volatile int nRef; /* Number of entrances */
volatile DWORD owner; /* Thread holding this mutex */
volatile LONG trace; /* True to trace changes */
#endif
@@ -28711,7 +29638,7 @@ SQLITE_PRIVATE void sqlite3MemoryBarrier(void){
SQLITE_MEMORY_BARRIER;
#elif defined(__GNUC__)
__sync_synchronize();
-#elif MSVC_VERSION>=1300
+#elif MSVC_VERSION>=1400
_ReadWriteBarrier();
#elif defined(MemoryBarrier)
MemoryBarrier();
@@ -29922,7 +30849,7 @@ SQLITE_PRIVATE int sqlite3ApiExit(sqlite3* db, int rc){
if( db->mallocFailed || rc ){
return apiHandleError(db, rc);
}
- return rc & db->errMask;
+ return 0;
}
/************** End of malloc.c **********************************************/
@@ -30034,43 +30961,6 @@ static const et_info fmtinfo[] = {
** %!S Like %S but prefer the zName over the zAlias
*/
-/* Floating point constants used for rounding */
-static const double arRound[] = {
- 5.0e-01, 5.0e-02, 5.0e-03, 5.0e-04, 5.0e-05,
- 5.0e-06, 5.0e-07, 5.0e-08, 5.0e-09, 5.0e-10,
-};
-
-/*
-** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point
-** conversions will work.
-*/
-#ifndef SQLITE_OMIT_FLOATING_POINT
-/*
-** "*val" is a double such that 0.1 <= *val < 10.0
-** Return the ascii code for the leading digit of *val, then
-** multiply "*val" by 10.0 to renormalize.
-**
-** Example:
-** input: *val = 3.14159
-** output: *val = 1.4159 function return = '3'
-**
-** The counter *cnt is incremented each time. After counter exceeds
-** 16 (the number of significant digits in a 64-bit float) '0' is
-** always returned.
-*/
-static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
- int digit;
- LONGDOUBLE_TYPE d;
- if( (*cnt)<=0 ) return '0';
- (*cnt)--;
- digit = (int)*val;
- d = digit;
- digit += '0';
- *val = (*val - d)*10.0;
- return (char)digit;
-}
-#endif /* SQLITE_OMIT_FLOATING_POINT */
-
/*
** Set the StrAccum object to an error mode.
*/
@@ -30162,18 +31052,15 @@ SQLITE_API void sqlite3_str_vappendf(
u8 bArgList; /* True for SQLITE_PRINTF_SQLFUNC */
char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
sqlite_uint64 longvalue; /* Value for integer types */
- LONGDOUBLE_TYPE realvalue; /* Value for real types */
+ double realvalue; /* Value for real types */
const et_info *infop; /* Pointer to the appropriate info structure */
char *zOut; /* Rendering buffer */
int nOut; /* Size of the rendering buffer */
char *zExtra = 0; /* Malloced memory used by some conversion */
-#ifndef SQLITE_OMIT_FLOATING_POINT
- int exp, e2; /* exponent of real numbers */
- int nsd; /* Number of significant digits returned */
- double rounder; /* Used for rounding floating point values */
+ int exp, e2; /* exponent of real numbers */
etByte flag_dp; /* True if decimal point should be shown */
etByte flag_rtz; /* True if trailing zeros should be removed */
-#endif
+
PrintfArguments *pArgList = 0; /* Arguments for SQLITE_PRINTF_SQLFUNC */
char buf[etBUFSIZE]; /* Conversion buffer */
@@ -30448,73 +31335,67 @@ SQLITE_API void sqlite3_str_vappendf(
break;
case etFLOAT:
case etEXP:
- case etGENERIC:
+ case etGENERIC: {
+ FpDecode s;
+ int iRound;
+ int j;
+
if( bArgList ){
realvalue = getDoubleArg(pArgList);
}else{
realvalue = va_arg(ap,double);
}
-#ifdef SQLITE_OMIT_FLOATING_POINT
- length = 0;
-#else
if( precision<0 ) precision = 6; /* Set default precision */
#ifdef SQLITE_FP_PRECISION_LIMIT
if( precision>SQLITE_FP_PRECISION_LIMIT ){
precision = SQLITE_FP_PRECISION_LIMIT;
}
#endif
- if( realvalue<0.0 ){
- realvalue = -realvalue;
- prefix = '-';
- }else{
- prefix = flag_prefix;
- }
- if( xtype==etGENERIC && precision>0 ) precision--;
- testcase( precision>0xfff );
- idx = precision & 0xfff;
- rounder = arRound[idx%10];
- while( idx>=10 ){ rounder *= 1.0e-10; idx -= 10; }
if( xtype==etFLOAT ){
- double rx = (double)realvalue;
- sqlite3_uint64 u;
- int ex;
- memcpy(&u, &rx, sizeof(u));
- ex = -1023 + (int)((u>>52)&0x7ff);
- if( precision+(ex/3) < 15 ) rounder += realvalue*3e-16;
- realvalue += rounder;
- }
- /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
- exp = 0;
- if( sqlite3IsNaN((double)realvalue) ){
- bufpt = "NaN";
- length = 3;
- break;
+ iRound = -precision;
+ }else if( xtype==etGENERIC ){
+ if( precision==0 ) precision = 1;
+ iRound = precision;
+ }else{
+ iRound = precision+1;
}
- if( realvalue>0.0 ){
- LONGDOUBLE_TYPE scale = 1.0;
- while( realvalue>=1e100*scale && exp<=350 ){ scale *= 1e100;exp+=100;}
- while( realvalue>=1e10*scale && exp<=350 ){ scale *= 1e10; exp+=10; }
- while( realvalue>=10.0*scale && exp<=350 ){ scale *= 10.0; exp++; }
- realvalue /= scale;
- while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; }
- while( realvalue<1.0 ){ realvalue *= 10.0; exp--; }
- if( exp>350 ){
+ sqlite3FpDecode(&s, realvalue, iRound, flag_altform2 ? 26 : 16);
+ if( s.isSpecial ){
+ if( s.isSpecial==2 ){
+ bufpt = flag_zeropad ? "null" : "NaN";
+ length = sqlite3Strlen30(bufpt);
+ break;
+ }else if( flag_zeropad ){
+ s.z[0] = '9';
+ s.iDP = 1000;
+ s.n = 1;
+ }else{
+ memcpy(buf, "-Inf", 5);
bufpt = buf;
- buf[0] = prefix;
- memcpy(buf+(prefix!=0),"Inf",4);
- length = 3+(prefix!=0);
+ if( s.sign=='-' ){
+ /* no-op */
+ }else if( flag_prefix ){
+ buf[0] = flag_prefix;
+ }else{
+ bufpt++;
+ }
+ length = sqlite3Strlen30(bufpt);
break;
}
}
- bufpt = buf;
+ if( s.sign=='-' ){
+ prefix = '-';
+ }else{
+ prefix = flag_prefix;
+ }
+
+ exp = s.iDP-1;
+ if( xtype==etGENERIC && precision>0 ) precision--;
+
/*
** If the field type is etGENERIC, then convert to either etEXP
** or etFLOAT, as appropriate.
*/
- if( xtype!=etFLOAT ){
- realvalue += rounder;
- if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
- }
if( xtype==etGENERIC ){
flag_rtz = !flag_alternateform;
if( exp<-4 || exp>precision ){
@@ -30529,29 +31410,32 @@ SQLITE_API void sqlite3_str_vappendf(
if( xtype==etEXP ){
e2 = 0;
}else{
- e2 = exp;
+ e2 = s.iDP - 1;
}
+ bufpt = buf;
{
i64 szBufNeeded; /* Size of a temporary buffer needed */
szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+15;
+ if( cThousand && e2>0 ) szBufNeeded += (e2+2)/3;
if( szBufNeeded > etBUFSIZE ){
bufpt = zExtra = printfTempBuf(pAccum, szBufNeeded);
if( bufpt==0 ) return;
}
}
zOut = bufpt;
- nsd = 16 + flag_altform2*10;
flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2;
/* The sign in front of the number */
if( prefix ){
*(bufpt++) = prefix;
}
/* Digits prior to the decimal point */
+ j = 0;
if( e2<0 ){
*(bufpt++) = '0';
}else{
for(; e2>=0; e2--){
- *(bufpt++) = et_getdigit(&realvalue,&nsd);
+ *(bufpt++) = j<s.n ? s.z[j++] : '0';
+ if( cThousand && (e2%3)==0 && e2>1 ) *(bufpt++) = ',';
}
}
/* The decimal point */
@@ -30560,13 +31444,12 @@ SQLITE_API void sqlite3_str_vappendf(
}
/* "0" digits after the decimal point but before the first
** significant digit of the number */
- for(e2++; e2<0; precision--, e2++){
- assert( precision>0 );
+ for(e2++; e2<0 && precision>0; precision--, e2++){
*(bufpt++) = '0';
}
/* Significant digits after the decimal point */
while( (precision--)>0 ){
- *(bufpt++) = et_getdigit(&realvalue,&nsd);
+ *(bufpt++) = j<s.n ? s.z[j++] : '0';
}
/* Remove trailing zeros and the "." if no digits follow the "." */
if( flag_rtz && flag_dp ){
@@ -30582,6 +31465,7 @@ SQLITE_API void sqlite3_str_vappendf(
}
/* Add the "eNNN" suffix */
if( xtype==etEXP ){
+ exp = s.iDP - 1;
*(bufpt++) = aDigits[infop->charset];
if( exp<0 ){
*(bufpt++) = '-'; exp = -exp;
@@ -30615,8 +31499,8 @@ SQLITE_API void sqlite3_str_vappendf(
while( nPad-- ) bufpt[i++] = '0';
length = width;
}
-#endif /* !defined(SQLITE_OMIT_FLOATING_POINT) */
break;
+ }
case etSIZE:
if( !bArgList ){
*(va_arg(ap,int*)) = pAccum->nChar;
@@ -31247,12 +32131,22 @@ SQLITE_API char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_li
return zBuf;
}
SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
- char *z;
+ StrAccum acc;
va_list ap;
+ if( n<=0 ) return zBuf;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( zBuf==0 || zFormat==0 ) {
+ (void)SQLITE_MISUSE_BKPT;
+ if( zBuf ) zBuf[0] = 0;
+ return zBuf;
+ }
+#endif
+ sqlite3StrAccumInit(&acc, 0, zBuf, n, 0);
va_start(ap,zFormat);
- z = sqlite3_vsnprintf(n, zBuf, zFormat, ap);
+ sqlite3_str_vappendf(&acc, zFormat, ap);
va_end(ap);
- return z;
+ zBuf[acc.nChar] = 0;
+ return zBuf;
}
/*
@@ -31330,6 +32224,75 @@ SQLITE_API void sqlite3_str_appendf(StrAccum *p, const char *zFormat, ...){
va_end(ap);
}
+
+/*****************************************************************************
+** Reference counted string/blob storage
+*****************************************************************************/
+
+/*
+** Increase the reference count of the string by one.
+**
+** The input parameter is returned.
+*/
+SQLITE_PRIVATE char *sqlite3RCStrRef(char *z){
+ RCStr *p = (RCStr*)z;
+ assert( p!=0 );
+ p--;
+ p->nRCRef++;
+ return z;
+}
+
+/*
+** Decrease the reference count by one. Free the string when the
+** reference count reaches zero.
+*/
+SQLITE_PRIVATE void sqlite3RCStrUnref(void *z){
+ RCStr *p = (RCStr*)z;
+ assert( p!=0 );
+ p--;
+ assert( p->nRCRef>0 );
+ if( p->nRCRef>=2 ){
+ p->nRCRef--;
+ }else{
+ sqlite3_free(p);
+ }
+}
+
+/*
+** Create a new string that is capable of holding N bytes of text, not counting
+** the zero byte at the end. The string is uninitialized.
+**
+** The reference count is initially 1. Call sqlite3RCStrUnref() to free the
+** newly allocated string.
+**
+** This routine returns 0 on an OOM.
+*/
+SQLITE_PRIVATE char *sqlite3RCStrNew(u64 N){
+ RCStr *p = sqlite3_malloc64( N + sizeof(*p) + 1 );
+ if( p==0 ) return 0;
+ p->nRCRef = 1;
+ return (char*)&p[1];
+}
+
+/*
+** Change the size of the string so that it is able to hold N bytes.
+** The string might be reallocated, so return the new allocation.
+*/
+SQLITE_PRIVATE char *sqlite3RCStrResize(char *z, u64 N){
+ RCStr *p = (RCStr*)z;
+ RCStr *pNew;
+ assert( p!=0 );
+ p--;
+ assert( p->nRCRef==1 );
+ pNew = sqlite3_realloc64(p, N+sizeof(RCStr)+1);
+ if( pNew==0 ){
+ sqlite3_free(p);
+ return 0;
+ }else{
+ return (char*)&pNew[1];
+ }
+}
+
/************** End of printf.c **********************************************/
/************** Begin file treeview.c ****************************************/
/*
@@ -31746,6 +32709,7 @@ SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u
sqlite3TreeViewItem(pView, "FILTER", 1);
sqlite3TreeViewExpr(pView, pWin->pFilter, 0);
sqlite3TreeViewPop(&pView);
+ if( pWin->eFrmType==TK_FILTER ) return;
}
sqlite3TreeViewPush(&pView, more);
if( pWin->zName ){
@@ -31755,7 +32719,7 @@ SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u
}
if( pWin->zBase ) nElement++;
if( pWin->pOrderBy ) nElement++;
- if( pWin->eFrmType ) nElement++;
+ if( pWin->eFrmType!=0 && pWin->eFrmType!=TK_FILTER ) nElement++;
if( pWin->eExclude ) nElement++;
if( pWin->zBase ){
sqlite3TreeViewPush(&pView, (--nElement)>0);
@@ -31768,7 +32732,7 @@ SQLITE_PRIVATE void sqlite3TreeViewWindow(TreeView *pView, const Window *pWin, u
if( pWin->pOrderBy ){
sqlite3TreeViewExprList(pView, pWin->pOrderBy, (--nElement)>0, "ORDER-BY");
}
- if( pWin->eFrmType ){
+ if( pWin->eFrmType!=0 && pWin->eFrmType!=TK_FILTER ){
char zBuf[30];
const char *zFrmType = "ROWS";
if( pWin->eFrmType==TK_RANGE ) zFrmType = "RANGE";
@@ -31977,7 +32941,8 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
};
assert( pExpr->op2==TK_IS || pExpr->op2==TK_ISNOT );
assert( pExpr->pRight );
- assert( sqlite3ExprSkipCollate(pExpr->pRight)->op==TK_TRUEFALSE );
+ assert( sqlite3ExprSkipCollateAndLikely(pExpr->pRight)->op
+ == TK_TRUEFALSE );
x = (pExpr->op2==TK_ISNOT)*2 + sqlite3ExprTruthValue(pExpr->pRight);
zUniOp = azOp[x];
break;
@@ -32015,7 +32980,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
assert( ExprUseXList(pExpr) );
pFarg = pExpr->x.pList;
#ifndef SQLITE_OMIT_WINDOWFUNC
- pWin = ExprHasProperty(pExpr, EP_WinFunc) ? pExpr->y.pWin : 0;
+ pWin = IsWindowFunc(pExpr) ? pExpr->y.pWin : 0;
#else
pWin = 0;
#endif
@@ -32041,7 +33006,13 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
sqlite3TreeViewLine(pView, "FUNCTION %Q%s", pExpr->u.zToken, zFlgs);
}
if( pFarg ){
- sqlite3TreeViewExprList(pView, pFarg, pWin!=0, 0);
+ sqlite3TreeViewExprList(pView, pFarg, pWin!=0 || pExpr->pLeft, 0);
+ if( pExpr->pLeft ){
+ Expr *pOB = pExpr->pLeft;
+ assert( pOB->op==TK_ORDER );
+ assert( ExprUseXList(pOB) );
+ sqlite3TreeViewExprList(pView, pOB->x.pList, pWin!=0, "ORDERBY");
+ }
}
#ifndef SQLITE_OMIT_WINDOWFUNC
if( pWin ){
@@ -32050,6 +33021,10 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
#endif
break;
}
+ case TK_ORDER: {
+ sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, "ORDERBY");
+ break;
+ }
#ifndef SQLITE_OMIT_SUBQUERY
case TK_EXISTS: {
assert( ExprUseXSelect(pExpr) );
@@ -32103,7 +33078,7 @@ SQLITE_PRIVATE void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 m
assert( pExpr->x.pList->nExpr==2 );
pY = pExpr->x.pList->a[0].pExpr;
pZ = pExpr->x.pList->a[1].pExpr;
- sqlite3TreeViewLine(pView, "BETWEEN");
+ sqlite3TreeViewLine(pView, "BETWEEN%s", zFlgs);
sqlite3TreeViewExpr(pView, pX, 1);
sqlite3TreeViewExpr(pView, pY, 1);
sqlite3TreeViewExpr(pView, pZ, 0);
@@ -33238,7 +34213,38 @@ SQLITE_PRIVATE u32 sqlite3Utf8Read(
return c;
}
-
+/*
+** Read a single UTF8 character out of buffer z[], but reading no
+** more than n characters from the buffer. z[] is not zero-terminated.
+**
+** Return the number of bytes used to construct the character.
+**
+** Invalid UTF8 might generate a strange result. No effort is made
+** to detect invalid UTF8.
+**
+** At most 4 bytes will be read out of z[]. The return value will always
+** be between 1 and 4.
+*/
+SQLITE_PRIVATE int sqlite3Utf8ReadLimited(
+ const u8 *z,
+ int n,
+ u32 *piOut
+){
+ u32 c;
+ int i = 1;
+ assert( n>0 );
+ c = z[0];
+ if( c>=0xc0 ){
+ c = sqlite3Utf8Trans1[c-0xc0];
+ if( n>4 ) n = 4;
+ while( i<n && (z[i] & 0xc0)==0x80 ){
+ c = (c<<6) + (0x3f & z[i]);
+ i++;
+ }
+ }
+ *piOut = c;
+ return i;
+}
/*
@@ -33636,7 +34642,7 @@ SQLITE_PRIVATE void sqlite3UtfSelfTest(void){
/*
** Calls to sqlite3FaultSim() are used to simulate a failure during testing,
** or to bypass normal error detection during testing in order to let
-** execute proceed futher downstream.
+** execute proceed further downstream.
**
** In deployment, sqlite3FaultSim() *always* return SQLITE_OK (0). The
** sqlite3FaultSim() function only returns non-zero during testing.
@@ -33680,6 +34686,19 @@ SQLITE_PRIVATE int sqlite3IsNaN(double x){
}
#endif /* SQLITE_OMIT_FLOATING_POINT */
+#ifndef SQLITE_OMIT_FLOATING_POINT
+/*
+** Return true if the floating point value is NaN or +Inf or -Inf.
+*/
+SQLITE_PRIVATE int sqlite3IsOverflow(double x){
+ int rc; /* The value return */
+ u64 y;
+ memcpy(&y,&x,sizeof(y));
+ rc = IsOvfl(y);
+ return rc;
+}
+#endif /* SQLITE_OMIT_FLOATING_POINT */
+
/*
** Compute a string length that is limited to what can be stored in
** lower 30 bits of a 32-bit signed integer.
@@ -33753,6 +34772,23 @@ SQLITE_PRIVATE void sqlite3ErrorClear(sqlite3 *db){
*/
SQLITE_PRIVATE void sqlite3SystemError(sqlite3 *db, int rc){
if( rc==SQLITE_IOERR_NOMEM ) return;
+#if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL)
+ if( rc==SQLITE_IOERR_IN_PAGE ){
+ int ii;
+ int iErr;
+ sqlite3BtreeEnterAll(db);
+ for(ii=0; ii<db->nDb; ii++){
+ if( db->aDb[ii].pBt ){
+ iErr = sqlite3PagerWalSystemErrno(sqlite3BtreePager(db->aDb[ii].pBt));
+ if( iErr ){
+ db->iSysErrno = iErr;
+ }
+ }
+ }
+ sqlite3BtreeLeaveAll(db);
+ return;
+ }
+#endif
rc &= 0xff;
if( rc==SQLITE_CANTOPEN || rc==SQLITE_IOERR ){
db->iSysErrno = sqlite3OsGetLastError(db->pVfs);
@@ -33797,12 +34833,16 @@ SQLITE_PRIVATE void sqlite3ProgressCheck(Parse *p){
p->rc = SQLITE_INTERRUPT;
}
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
- if( db->xProgress && (++p->nProgressSteps)>=db->nProgressOps ){
- if( db->xProgress(db->pProgressArg) ){
- p->nErr++;
- p->rc = SQLITE_INTERRUPT;
+ if( db->xProgress ){
+ if( p->rc==SQLITE_INTERRUPT ){
+ p->nProgressSteps = 0;
+ }else if( (++p->nProgressSteps)>=db->nProgressOps ){
+ if( db->xProgress(db->pProgressArg) ){
+ p->nErr++;
+ p->rc = SQLITE_INTERRUPT;
+ }
+ p->nProgressSteps = 0;
}
- p->nProgressSteps = 0;
}
#endif
}
@@ -33998,43 +35038,40 @@ SQLITE_PRIVATE u8 sqlite3StrIHash(const char *z){
return h;
}
-/*
-** Compute 10 to the E-th power. Examples: E==1 results in 10.
-** E==2 results in 100. E==50 results in 1.0e50.
+/* Double-Double multiplication. (x[0],x[1]) *= (y,yy)
**
-** This routine only works for values of E between 1 and 341.
+** Reference:
+** T. J. Dekker, "A Floating-Point Technique for Extending the
+** Available Precision". 1971-07-26.
*/
-static LONGDOUBLE_TYPE sqlite3Pow10(int E){
-#if defined(_MSC_VER)
- static const LONGDOUBLE_TYPE x[] = {
- 1.0e+001L,
- 1.0e+002L,
- 1.0e+004L,
- 1.0e+008L,
- 1.0e+016L,
- 1.0e+032L,
- 1.0e+064L,
- 1.0e+128L,
- 1.0e+256L
- };
- LONGDOUBLE_TYPE r = 1.0;
- int i;
- assert( E>=0 && E<=307 );
- for(i=0; E!=0; i++, E >>=1){
- if( E & 1 ) r *= x[i];
- }
- return r;
-#else
- LONGDOUBLE_TYPE x = 10.0;
- LONGDOUBLE_TYPE r = 1.0;
- while(1){
- if( E & 1 ) r *= x;
- E >>= 1;
- if( E==0 ) break;
- x *= x;
- }
- return r;
-#endif
+static void dekkerMul2(volatile double *x, double y, double yy){
+ /*
+ ** The "volatile" keywords on parameter x[] and on local variables
+ ** below are needed force intermediate results to be truncated to
+ ** binary64 rather than be carried around in an extended-precision
+ ** format. The truncation is necessary for the Dekker algorithm to
+ ** work. Intel x86 floating point might omit the truncation without
+ ** the use of volatile.
+ */
+ volatile double tx, ty, p, q, c, cc;
+ double hx, hy;
+ u64 m;
+ memcpy(&m, (void*)&x[0], 8);
+ m &= 0xfffffffffc000000LL;
+ memcpy(&hx, &m, 8);
+ tx = x[0] - hx;
+ memcpy(&m, &y, 8);
+ m &= 0xfffffffffc000000LL;
+ memcpy(&hy, &m, 8);
+ ty = y - hy;
+ p = hx*hy;
+ q = hx*ty + tx*hy;
+ c = p+q;
+ cc = p - c + q + tx*ty;
+ cc = x[0]*yy + x[1]*y + cc;
+ x[0] = c + cc;
+ x[1] = c - x[0];
+ x[1] += cc;
}
/*
@@ -34075,12 +35112,11 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
const char *zEnd;
/* sign * significand * (10 ^ (esign * exponent)) */
int sign = 1; /* sign of significand */
- i64 s = 0; /* significand */
+ u64 s = 0; /* significand */
int d = 0; /* adjust exponent for shifting decimal point */
int esign = 1; /* sign of exponent */
int e = 0; /* exponent */
int eValid = 1; /* True exponent is either not used or is well-formed */
- double result;
int nDigit = 0; /* Number of digits processed */
int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */
@@ -34120,7 +35156,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
while( z<zEnd && sqlite3Isdigit(*z) ){
s = s*10 + (*z - '0');
z+=incr; nDigit++;
- if( s>=((LARGEST_INT64-9)/10) ){
+ if( s>=((LARGEST_UINT64-9)/10) ){
/* skip non-significant significand digits
** (increase exponent by d to shift decimal left) */
while( z<zEnd && sqlite3Isdigit(*z) ){ z+=incr; d++; }
@@ -34135,7 +35171,7 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
/* copy digits from after decimal to significand
** (decrease exponent by d to shift decimal right) */
while( z<zEnd && sqlite3Isdigit(*z) ){
- if( s<((LARGEST_INT64-9)/10) ){
+ if( s<((LARGEST_UINT64-9)/10) ){
s = s*10 + (*z - '0');
d--;
nDigit++;
@@ -34175,79 +35211,92 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 en
while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
do_atof_calc:
- /* adjust exponent by d, and update sign */
- e = (e*esign) + d;
- if( e<0 ) {
- esign = -1;
- e *= -1;
- } else {
- esign = 1;
+ /* Zero is a special case */
+ if( s==0 ){
+ *pResult = sign<0 ? -0.0 : +0.0;
+ goto atof_return;
}
- if( s==0 ) {
- /* In the IEEE 754 standard, zero is signed. */
- result = sign<0 ? -(double)0 : (double)0;
- } else {
- /* 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 exponent by d, and update sign */
+ e = (e*esign) + d;
- /* adjust the sign of significand */
- s = sign<0 ? -s : s;
+ /* Try to adjust the exponent to make it smaller */
+ while( e>0 && s<(LARGEST_UINT64/10) ){
+ s *= 10;
+ e--;
+ }
+ while( e<0 && (s%10)==0 ){
+ s /= 10;
+ e++;
+ }
- if( e==0 ){ /*OPTIMIZATION-IF-TRUE*/
- result = (double)s;
+ if( e==0 ){
+ *pResult = s;
+ }else if( sqlite3Config.bUseLongDouble ){
+ LONGDOUBLE_TYPE r = (LONGDOUBLE_TYPE)s;
+ if( e>0 ){
+ while( e>=100 ){ e-=100; r *= 1.0e+100L; }
+ while( e>=10 ){ e-=10; r *= 1.0e+10L; }
+ while( e>=1 ){ e-=1; r *= 1.0e+01L; }
}else{
- /* attempt to handle extremely small/large numbers better */
- if( e>307 ){ /*OPTIMIZATION-IF-TRUE*/
- if( e<342 ){ /*OPTIMIZATION-IF-TRUE*/
- LONGDOUBLE_TYPE scale = sqlite3Pow10(e-308);
- 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{
+ while( e<=-100 ){ e+=100; r *= 1.0e-100L; }
+ while( e<=-10 ){ e+=10; r *= 1.0e-10L; }
+ while( e<=-1 ){ e+=1; r *= 1.0e-01L; }
+ }
+ assert( r>=0.0 );
+ if( r>+1.7976931348623157081452742373e+308L ){
#ifdef INFINITY
- result = INFINITY*s;
+ *pResult = +INFINITY;
#else
- result = 1e308*1e308*s; /* Infinity */
+ *pResult = 1.0e308*10.0;
#endif
- }
- }
- }else{
- LONGDOUBLE_TYPE scale = sqlite3Pow10(e);
- if( esign<0 ){
- result = s / scale;
- }else{
- result = s * scale;
- }
+ }else{
+ *pResult = (double)r;
+ }
+ }else{
+ double rr[2];
+ u64 s2;
+ rr[0] = (double)s;
+ s2 = (u64)rr[0];
+#if defined(_MSC_VER) && _MSC_VER<1700
+ if( s2==0x8000000000000000LL ){ s2 = 2*(u64)(0.5*rr[0]); }
+#endif
+ rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s);
+ if( e>0 ){
+ while( e>=100 ){
+ e -= 100;
+ dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
+ }
+ while( e>=10 ){
+ e -= 10;
+ dekkerMul2(rr, 1.0e+10, 0.0);
+ }
+ while( e>=1 ){
+ e -= 1;
+ dekkerMul2(rr, 1.0e+01, 0.0);
+ }
+ }else{
+ while( e<=-100 ){
+ e += 100;
+ dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
+ }
+ while( e<=-10 ){
+ e += 10;
+ dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
+ }
+ while( e<=-1 ){
+ e += 1;
+ dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
}
}
+ *pResult = rr[0]+rr[1];
+ if( sqlite3IsNaN(*pResult) ) *pResult = 1e300*1e300;
}
+ if( sign<0 ) *pResult = -*pResult;
+ assert( !sqlite3IsNaN(*pResult) );
- /* store the result */
- *pResult = result;
-
- /* return true if number and no extra non-whitespace chracters after */
+atof_return:
+ /* return true if number and no extra non-whitespace characters after */
if( z==zEnd && nDigit>0 && eValid && eType>0 ){
return eType;
}else if( eType>=2 && (eType==3 || eValid) && nDigit>0 ){
@@ -34282,13 +35331,15 @@ SQLITE_PRIVATE int sqlite3Int64ToText(i64 v, char *zOut){
}
i = sizeof(zTemp)-2;
zTemp[sizeof(zTemp)-1] = 0;
- do{
- zTemp[i--] = (x%10) + '0';
+ while( 1 /*exit-by-break*/ ){
+ zTemp[i] = (x%10) + '0';
x = x/10;
- }while( x );
- if( v<0 ) zTemp[i--] = '-';
- memcpy(zOut, &zTemp[i+1], sizeof(zTemp)-1-i);
- return sizeof(zTemp)-2-i;
+ if( x==0 ) break;
+ i--;
+ };
+ if( v<0 ) zTemp[--i] = '-';
+ memcpy(zOut, &zTemp[i], sizeof(zTemp)-i);
+ return sizeof(zTemp)-1-i;
}
/*
@@ -34381,7 +35432,7 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
/* This test and assignment is needed only to suppress UB warnings
** from clang and -fsanitize=undefined. This test and assignment make
** the code a little larger and slower, and no harm comes from omitting
- ** them, but we must appaise the undefined-behavior pharisees. */
+ ** them, but we must appease the undefined-behavior pharisees. */
*pNum = neg ? SMALLEST_INT64 : LARGEST_INT64;
}else if( neg ){
*pNum = -(i64)u;
@@ -34453,11 +35504,15 @@ SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
u = u*16 + sqlite3HexToInt(z[k]);
}
memcpy(pOut, &u, 8);
- return (z[k]==0 && k-i<=16) ? 0 : 2;
+ if( k-i>16 ) return 2;
+ if( z[k]!=0 ) return 1;
+ return 0;
}else
#endif /* SQLITE_OMIT_HEX_INTEGER */
{
- return sqlite3Atoi64(z, pOut, sqlite3Strlen30(z), SQLITE_UTF8);
+ int n = (int)(0x3fffffff&strspn(z,"+- \n\t0123456789"));
+ if( z[n] ) n++;
+ return sqlite3Atoi64(z, pOut, n, SQLITE_UTF8);
}
}
@@ -34489,7 +35544,7 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){
u32 u = 0;
zNum += 2;
while( zNum[0]=='0' ) zNum++;
- for(i=0; sqlite3Isxdigit(zNum[i]) && i<8; i++){
+ for(i=0; i<8 && sqlite3Isxdigit(zNum[i]); i++){
u = u*16 + sqlite3HexToInt(zNum[i]);
}
if( (u&0x80000000)==0 && sqlite3Isxdigit(zNum[i])==0 ){
@@ -34537,6 +35592,153 @@ SQLITE_PRIVATE int sqlite3Atoi(const char *z){
}
/*
+** Decode a floating-point value into an approximate decimal
+** representation.
+**
+** Round the decimal representation to n significant digits if
+** n is positive. Or round to -n signficant digits after the
+** decimal point if n is negative. No rounding is performed if
+** n is zero.
+**
+** The significant digits of the decimal representation are
+** stored in p->z[] which is a often (but not always) a pointer
+** into the middle of p->zBuf[]. There are p->n significant digits.
+** The p->z[] array is *not* zero-terminated.
+*/
+SQLITE_PRIVATE void sqlite3FpDecode(FpDecode *p, double r, int iRound, int mxRound){
+ int i;
+ u64 v;
+ int e, exp = 0;
+ p->isSpecial = 0;
+ p->z = p->zBuf;
+
+ /* Convert negative numbers to positive. Deal with Infinity, 0.0, and
+ ** NaN. */
+ if( r<0.0 ){
+ p->sign = '-';
+ r = -r;
+ }else if( r==0.0 ){
+ p->sign = '+';
+ p->n = 1;
+ p->iDP = 1;
+ p->z = "0";
+ return;
+ }else{
+ p->sign = '+';
+ }
+ memcpy(&v,&r,8);
+ e = v>>52;
+ if( (e&0x7ff)==0x7ff ){
+ p->isSpecial = 1 + (v!=0x7ff0000000000000LL);
+ p->n = 0;
+ p->iDP = 0;
+ return;
+ }
+
+ /* Multiply r by powers of ten until it lands somewhere in between
+ ** 1.0e+19 and 1.0e+17.
+ */
+ if( sqlite3Config.bUseLongDouble ){
+ LONGDOUBLE_TYPE rr = r;
+ if( rr>=1.0e+19 ){
+ while( rr>=1.0e+119L ){ exp+=100; rr *= 1.0e-100L; }
+ while( rr>=1.0e+29L ){ exp+=10; rr *= 1.0e-10L; }
+ while( rr>=1.0e+19L ){ exp++; rr *= 1.0e-1L; }
+ }else{
+ while( rr<1.0e-97L ){ exp-=100; rr *= 1.0e+100L; }
+ while( rr<1.0e+07L ){ exp-=10; rr *= 1.0e+10L; }
+ while( rr<1.0e+17L ){ exp--; rr *= 1.0e+1L; }
+ }
+ v = (u64)rr;
+ }else{
+ /* If high-precision floating point is not available using "long double",
+ ** then use Dekker-style double-double computation to increase the
+ ** precision.
+ **
+ ** The error terms on constants like 1.0e+100 computed using the
+ ** decimal extension, for example as follows:
+ **
+ ** SELECT decimal_exp(decimal_sub('1.0e+100',decimal(1.0e+100)));
+ */
+ double rr[2];
+ rr[0] = r;
+ rr[1] = 0.0;
+ if( rr[0]>9.223372036854774784e+18 ){
+ while( rr[0]>9.223372036854774784e+118 ){
+ exp += 100;
+ dekkerMul2(rr, 1.0e-100, -1.99918998026028836196e-117);
+ }
+ while( rr[0]>9.223372036854774784e+28 ){
+ exp += 10;
+ dekkerMul2(rr, 1.0e-10, -3.6432197315497741579e-27);
+ }
+ while( rr[0]>9.223372036854774784e+18 ){
+ exp += 1;
+ dekkerMul2(rr, 1.0e-01, -5.5511151231257827021e-18);
+ }
+ }else{
+ while( rr[0]<9.223372036854774784e-83 ){
+ exp -= 100;
+ dekkerMul2(rr, 1.0e+100, -1.5902891109759918046e+83);
+ }
+ while( rr[0]<9.223372036854774784e+07 ){
+ exp -= 10;
+ dekkerMul2(rr, 1.0e+10, 0.0);
+ }
+ while( rr[0]<9.22337203685477478e+17 ){
+ exp -= 1;
+ dekkerMul2(rr, 1.0e+01, 0.0);
+ }
+ }
+ v = rr[1]<0.0 ? (u64)rr[0]-(u64)(-rr[1]) : (u64)rr[0]+(u64)rr[1];
+ }
+
+
+ /* Extract significant digits. */
+ i = sizeof(p->zBuf)-1;
+ assert( v>0 );
+ while( v ){ p->zBuf[i--] = (v%10) + '0'; v /= 10; }
+ assert( i>=0 && i<sizeof(p->zBuf)-1 );
+ p->n = sizeof(p->zBuf) - 1 - i;
+ assert( p->n>0 );
+ assert( p->n<sizeof(p->zBuf) );
+ p->iDP = p->n + exp;
+ if( iRound<=0 ){
+ iRound = p->iDP - iRound;
+ if( iRound==0 && p->zBuf[i+1]>='5' ){
+ iRound = 1;
+ p->zBuf[i--] = '0';
+ p->n++;
+ p->iDP++;
+ }
+ }
+ if( iRound>0 && (iRound<p->n || p->n>mxRound) ){
+ char *z = &p->zBuf[i+1];
+ if( iRound>mxRound ) iRound = mxRound;
+ p->n = iRound;
+ if( z[iRound]>='5' ){
+ int j = iRound-1;
+ while( 1 /*exit-by-break*/ ){
+ z[j]++;
+ if( z[j]<='9' ) break;
+ z[j] = '0';
+ if( j==0 ){
+ p->z[i--] = '1';
+ p->n++;
+ p->iDP++;
+ break;
+ }else{
+ j--;
+ }
+ }
+ }
+ }
+ p->z = &p->zBuf[i+1];
+ assert( i+p->n < sizeof(p->zBuf) );
+ while( ALWAYS(p->n>0) && p->z[p->n-1]=='0' ){ p->n--; }
+}
+
+/*
** Try to convert z into an unsigned 32-bit integer. Return true on
** success and false if there is an error.
**
@@ -34799,121 +36001,32 @@ SQLITE_PRIVATE u8 sqlite3GetVarint(const unsigned char *p, u64 *v){
** this function assumes the single-byte case has already been handled.
*/
SQLITE_PRIVATE u8 sqlite3GetVarint32(const unsigned char *p, u32 *v){
- u32 a,b;
+ u64 v64;
+ u8 n;
- /* The 1-byte case. Overwhelmingly the most common. Handled inline
- ** by the getVarin32() macro */
- a = *p;
- /* a: p0 (unmasked) */
-#ifndef getVarint32
- if (!(a&0x80))
- {
- /* Values between 0 and 127 */
- *v = a;
- return 1;
- }
-#endif
+ /* Assume that the single-byte case has already been handled by
+ ** the getVarint32() macro */
+ assert( (p[0] & 0x80)!=0 );
- /* The 2-byte case */
- p++;
- b = *p;
- /* b: p1 (unmasked) */
- if (!(b&0x80))
- {
- /* Values between 128 and 16383 */
- a &= 0x7f;
- a = a<<7;
- *v = a | b;
+ if( (p[1] & 0x80)==0 ){
+ /* This is the two-byte case */
+ *v = ((p[0]&0x7f)<<7) | p[1];
return 2;
}
-
- /* The 3-byte case */
- p++;
- a = a<<14;
- a |= *p;
- /* a: p0<<14 | p2 (unmasked) */
- if (!(a&0x80))
- {
- /* Values between 16384 and 2097151 */
- a &= (0x7f<<14)|(0x7f);
- b &= 0x7f;
- b = b<<7;
- *v = a | b;
+ if( (p[2] & 0x80)==0 ){
+ /* This is the three-byte case */
+ *v = ((p[0]&0x7f)<<14) | ((p[1]&0x7f)<<7) | p[2];
return 3;
}
-
- /* A 32-bit varint is used to store size information in btrees.
- ** Objects are rarely larger than 2MiB limit of a 3-byte varint.
- ** A 3-byte varint is sufficient, for example, to record the size
- ** of a 1048569-byte BLOB or string.
- **
- ** We only unroll the first 1-, 2-, and 3- byte cases. The very
- ** rare larger cases can be handled by the slower 64-bit varint
- ** routine.
- */
-#if 1
- {
- u64 v64;
- u8 n;
-
- n = sqlite3GetVarint(p-2, &v64);
- assert( n>3 && n<=9 );
- if( (v64 & SQLITE_MAX_U32)!=v64 ){
- *v = 0xffffffff;
- }else{
- *v = (u32)v64;
- }
- return n;
- }
-
-#else
- /* For following code (kept for historical record only) shows an
- ** unrolling for the 3- and 4-byte varint cases. This code is
- ** slightly faster, but it is also larger and much harder to test.
- */
- p++;
- b = b<<14;
- b |= *p;
- /* b: p1<<14 | p3 (unmasked) */
- if (!(b&0x80))
- {
- /* Values between 2097152 and 268435455 */
- b &= (0x7f<<14)|(0x7f);
- a &= (0x7f<<14)|(0x7f);
- a = a<<7;
- *v = a | b;
- return 4;
- }
-
- p++;
- a = a<<14;
- a |= *p;
- /* a: p0<<28 | p2<<14 | p4 (unmasked) */
- if (!(a&0x80))
- {
- /* Values between 268435456 and 34359738367 */
- a &= SLOT_4_2_0;
- b &= SLOT_4_2_0;
- b = b<<7;
- *v = a | b;
- return 5;
- }
-
- /* We can only reach this point when reading a corrupt database
- ** file. In that case we are not in any hurry. Use the (relatively
- ** slow) general-purpose sqlite3GetVarint() routine to extract the
- ** value. */
- {
- u64 v64;
- u8 n;
-
- p -= 4;
- n = sqlite3GetVarint(p, &v64);
- assert( n>5 && n<=9 );
+ /* four or more bytes */
+ n = sqlite3GetVarint(p, &v64);
+ assert( n>3 && n<=9 );
+ if( (v64 & SQLITE_MAX_U32)!=v64 ){
+ *v = 0xffffffff;
+ }else{
*v = (u32)v64;
- return n;
}
-#endif
+ return n;
}
/*
@@ -35064,7 +36177,7 @@ SQLITE_PRIVATE int sqlite3SafetyCheckSickOrOk(sqlite3 *db){
}
/*
-** Attempt to add, substract, or multiply the 64-bit signed value iB against
+** Attempt to add, subtract, or multiply the 64-bit signed value iB against
** the other 64-bit signed integer at *pA and store the result in *pA.
** Return 0 on success. Or if the operation would have resulted in an
** overflow, leave *pA unchanged and return 1.
@@ -35377,7 +36490,7 @@ SQLITE_PRIVATE int sqlite3VListNameToNum(VList *pIn, const char *zName, int nNam
#define SQLITE_HWTIME_H
/*
-** The following routine only works on pentium-class (or newer) processors.
+** The following routine only works on Pentium-class (or newer) processors.
** It uses the RDTSC opcode to read the cycle count value out of the
** processor and returns that value. This can be used for high-res
** profiling.
@@ -35549,7 +36662,7 @@ static void insertElement(
}
-/* Resize the hash table so that it cantains "new_size" buckets.
+/* Resize the hash table so that it contains "new_size" buckets.
**
** The hash table might fail to resize if sqlite3_malloc() fails or
** if the new size is the same as the prior size.
@@ -35909,19 +37022,22 @@ SQLITE_PRIVATE const char *sqlite3OpcodeName(int i){
/* 171 */ "VCreate" OpHelp(""),
/* 172 */ "VDestroy" OpHelp(""),
/* 173 */ "VOpen" OpHelp(""),
- /* 174 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"),
- /* 175 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
- /* 176 */ "VRename" OpHelp(""),
- /* 177 */ "Pagecount" OpHelp(""),
- /* 178 */ "MaxPgcnt" OpHelp(""),
- /* 179 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"),
- /* 180 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"),
- /* 181 */ "Trace" OpHelp(""),
- /* 182 */ "CursorHint" OpHelp(""),
- /* 183 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"),
- /* 184 */ "Noop" OpHelp(""),
- /* 185 */ "Explain" OpHelp(""),
- /* 186 */ "Abortable" OpHelp(""),
+ /* 174 */ "VCheck" OpHelp(""),
+ /* 175 */ "VInitIn" OpHelp("r[P2]=ValueList(P1,P3)"),
+ /* 176 */ "VColumn" OpHelp("r[P3]=vcolumn(P2)"),
+ /* 177 */ "VRename" OpHelp(""),
+ /* 178 */ "Pagecount" OpHelp(""),
+ /* 179 */ "MaxPgcnt" OpHelp(""),
+ /* 180 */ "ClrSubtype" OpHelp("r[P1].subtype = 0"),
+ /* 181 */ "GetSubtype" OpHelp("r[P2] = r[P1].subtype"),
+ /* 182 */ "SetSubtype" OpHelp("r[P2].subtype = r[P1]"),
+ /* 183 */ "FilterAdd" OpHelp("filter(P1) += key(P3@P4)"),
+ /* 184 */ "Trace" OpHelp(""),
+ /* 185 */ "CursorHint" OpHelp(""),
+ /* 186 */ "ReleaseReg" OpHelp("release r[P1@P2] mask P3"),
+ /* 187 */ "Noop" OpHelp(""),
+ /* 188 */ "Explain" OpHelp(""),
+ /* 189 */ "Abortable" OpHelp(""),
};
return azName[i];
}
@@ -36935,7 +38051,7 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void){
** This source file is organized into divisions where the logic for various
** subfunctions is contained within the appropriate division. PLEASE
** KEEP THE STRUCTURE OF THIS FILE INTACT. New code should be placed
-** in the correct division and should be clearly labeled.
+** in the correct division and should be clearly labelled.
**
** The layout of divisions is as follows:
**
@@ -36985,7 +38101,7 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void){
#endif
/* Use pread() and pwrite() if they are available */
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(__linux__)
# define HAVE_PREAD 1
# define HAVE_PWRITE 1
#endif
@@ -37522,7 +38638,7 @@ static int robustFchown(int fd, uid_t uid, gid_t gid){
/*
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
-** "unix" VFSes. Return SQLITE_OK opon successfully updating the
+** "unix" VFSes. Return SQLITE_OK upon successfully updating the
** system call pointer, or SQLITE_NOTFOUND if there is no configurable
** system call named zName.
*/
@@ -38044,7 +39160,7 @@ static void vxworksReleaseFileId(struct vxworksFileId *pId){
** If you close a file descriptor that points to a file that has locks,
** all locks on that file that are owned by the current process are
** released. To work around this problem, each unixInodeInfo object
-** maintains a count of the number of pending locks on tha inode.
+** maintains a count of the number of pending locks on the inode.
** When an attempt is made to close an unixFile, if there are
** other unixFile open on the same inode that are holding locks, the call
** to close() the file descriptor is deferred until all of the locks clear.
@@ -38058,7 +39174,7 @@ static void vxworksReleaseFileId(struct vxworksFileId *pId){
** not posix compliant. Under LinuxThreads, a lock created by thread
** A cannot be modified or overridden by a different thread B.
** Only thread A can modify the lock. Locking behavior is correct
-** if the appliation uses the newer Native Posix Thread Library (NPTL)
+** if the application uses the newer Native Posix Thread Library (NPTL)
** on linux - with NPTL a lock created by thread A can override locks
** in thread B. But there is no way to know at compile-time which
** threading library is being used. So there is no way to know at
@@ -38260,7 +39376,7 @@ static void storeLastErrno(unixFile *pFile, int error){
}
/*
-** Close all file descriptors accumuated in the unixInodeInfo->pUnused list.
+** Close all file descriptors accumulated in the unixInodeInfo->pUnused list.
*/
static void closePendingFds(unixFile *pFile){
unixInodeInfo *pInode = pFile->pInode;
@@ -38623,7 +39739,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
** 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
+ ** Symbols defined in os.h identify the 'pending byte' and the 'reserved
** byte', each single bytes at well known offsets, and the 'shared byte
** range', a range of 510 bytes at a well known offset.
**
@@ -38631,7 +39747,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
** 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
+ ** and Windows95 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
@@ -38652,7 +39768,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
** obtaining a write-lock on the 'pending byte'. This ensures that no new
** SHARED locks can be obtained, but existing SHARED locks are allowed to
** persist. If the call to this function fails to obtain the EXCLUSIVE
- ** lock in this case, it holds the PENDING lock intead. The client may
+ ** lock in this case, it holds the PENDING lock instead. The client may
** then re-attempt the EXCLUSIVE lock later on, after existing SHARED
** locks have cleared.
*/
@@ -38680,7 +39796,7 @@ static int unixLock(sqlite3_file *id, int eFileLock){
/* Make sure the locking sequence is correct.
** (1) We never move from unlocked to anything higher than shared lock.
- ** (2) SQLite never explicitly requests a pendig lock.
+ ** (2) SQLite never explicitly requests a pending lock.
** (3) A shared lock is always held when a reserve lock is requested.
*/
assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK );
@@ -39898,7 +41014,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){
/* Make sure the locking sequence is correct
** (1) We never move from unlocked to anything higher than shared lock.
- ** (2) SQLite never explicitly requests a pendig lock.
+ ** (2) SQLite never explicitly requests a pending lock.
** (3) A shared lock is always held when a reserve lock is requested.
*/
assert( pFile->eFileLock!=NO_LOCK || eFileLock==SHARED_LOCK );
@@ -40014,7 +41130,7 @@ static int afpLock(sqlite3_file *id, int eFileLock){
if( !(failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST +
pInode->sharedByte, 1, 0)) ){
int failed2 = SQLITE_OK;
- /* now attemmpt to get the exclusive lock range */
+ /* now attempt to get the exclusive lock range */
failed = afpSetLock(context->dbPath, pFile, SHARED_FIRST,
SHARED_SIZE, 1);
if( failed && (failed2 = afpSetLock(context->dbPath, pFile,
@@ -40063,9 +41179,6 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
unixInodeInfo *pInode;
afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
int skipShared = 0;
-#ifdef SQLITE_TEST
- int h = pFile->h;
-#endif
assert( pFile );
OSTRACE(("UNLOCK %d %d was %d(%d,%d) pid=%d (afp)\n", pFile->h, eFileLock,
@@ -40081,9 +41194,6 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
assert( pInode->nShared!=0 );
if( pFile->eFileLock>SHARED_LOCK ){
assert( pInode->eFileLock==pFile->eFileLock );
- SimulateIOErrorBenign(1);
- SimulateIOError( h=(-1) )
- SimulateIOErrorBenign(0);
#ifdef SQLITE_DEBUG
/* When reducing a lock such that other processes can start
@@ -40132,9 +41242,6 @@ static int afpUnlock(sqlite3_file *id, int eFileLock) {
unsigned long long sharedLockByte = SHARED_FIRST+pInode->sharedByte;
pInode->nShared--;
if( pInode->nShared==0 ){
- SimulateIOErrorBenign(1);
- SimulateIOError( h=(-1) )
- SimulateIOErrorBenign(0);
if( !skipShared ){
rc = afpSetLock(context->dbPath, pFile, sharedLockByte, 1, 0);
}
@@ -40235,12 +41342,6 @@ static int nfsUnlock(sqlite3_file *id, int eFileLock){
** Seek to the offset passed as the second argument, then read cnt
** bytes into pBuf. Return the number of bytes actually read.
**
-** NB: If you define USE_PREAD or USE_PREAD64, then it might also
-** be necessary to define _XOPEN_SOURCE to be 500. This varies from
-** one system to another. Since SQLite does not define USE_PREAD
-** in any form by default, we will not attempt to define _XOPEN_SOURCE.
-** See tickets #2741 and #2681.
-**
** To avoid stomping the errno value on a failed read the lastErrno value
** is set before returning.
*/
@@ -40315,7 +41416,7 @@ static int unixRead(
#endif
#if SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this read request as possible by transfering
+ /* Deal with as much of this read request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
@@ -40467,7 +41568,7 @@ static int unixWrite(
#endif
#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this write request as possible by transfering
+ /* Deal with as much of this write request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
@@ -40589,7 +41690,7 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
/* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a
** no-op. But go ahead and call fstat() to validate the file
** descriptor as we need a method to provoke a failure during
- ** coverate testing.
+ ** coverage testing.
*/
#ifdef SQLITE_NO_SYNC
{
@@ -40982,7 +42083,13 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
case SQLITE_FCNTL_LOCK_TIMEOUT: {
int iOld = pFile->iBusyTimeout;
+#if SQLITE_ENABLE_SETLK_TIMEOUT==1
pFile->iBusyTimeout = *(int*)pArg;
+#elif SQLITE_ENABLE_SETLK_TIMEOUT==2
+ pFile->iBusyTimeout = !!(*(int*)pArg);
+#else
+# error "SQLITE_ENABLE_SETLK_TIMEOUT must be set to 1 or 2"
+#endif
*(int*)pArg = iOld;
return SQLITE_OK;
}
@@ -41235,6 +42342,25 @@ static int unixGetpagesize(void){
** Either unixShmNode.pShmMutex must be held or unixShmNode.nRef==0 and
** unixMutexHeld() is true when reading or writing any other field
** in this structure.
+**
+** aLock[SQLITE_SHM_NLOCK]:
+** This array records the various locks held by clients on each of the
+** SQLITE_SHM_NLOCK slots. If the aLock[] entry is set to 0, then no
+** locks are held by the process on this slot. If it is set to -1, then
+** some client holds an EXCLUSIVE lock on the locking slot. If the aLock[]
+** value is set to a positive value, then it is the number of shared
+** locks currently held on the slot.
+**
+** aMutex[SQLITE_SHM_NLOCK]:
+** Normally, when SQLITE_ENABLE_SETLK_TIMEOUT is not defined, mutex
+** pShmMutex is used to protect the aLock[] array and the right to
+** call fcntl() on unixShmNode.hShm to obtain or release locks.
+**
+** If SQLITE_ENABLE_SETLK_TIMEOUT is defined though, we use an array
+** of mutexes - one for each locking slot. To read or write locking
+** slot aLock[iSlot], the caller must hold the corresponding mutex
+** aMutex[iSlot]. Similarly, to call fcntl() to obtain or release a
+** lock corresponding to slot iSlot, mutex aMutex[iSlot] must be held.
*/
struct unixShmNode {
unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */
@@ -41248,10 +42374,11 @@ struct unixShmNode {
char **apRegion; /* Array of mapped shared-memory regions */
int nRef; /* Number of unixShm objects pointing to this */
unixShm *pFirst; /* All unixShm objects pointing to this */
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ sqlite3_mutex *aMutex[SQLITE_SHM_NLOCK];
+#endif
int aLock[SQLITE_SHM_NLOCK]; /* # shared locks on slot, -1==excl lock */
#ifdef SQLITE_DEBUG
- u8 exclMask; /* Mask of exclusive locks held */
- u8 sharedMask; /* Mask of shared locks held */
u8 nextShmId; /* Next available unixShm.id value */
#endif
};
@@ -41334,16 +42461,35 @@ static int unixShmSystemLock(
struct flock f; /* The posix advisory locking structure */
int rc = SQLITE_OK; /* Result code form fcntl() */
- /* Access to the unixShmNode object is serialized by the caller */
pShmNode = pFile->pInode->pShmNode;
- assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) );
- assert( pShmNode->nRef>0 || unixMutexHeld() );
+
+ /* Assert that the parameters are within expected range and that the
+ ** correct mutex or mutexes are held. */
+ assert( pShmNode->nRef>=0 );
+ assert( (ofst==UNIX_SHM_DMS && n==1)
+ || (ofst>=UNIX_SHM_BASE && ofst+n<=(UNIX_SHM_BASE+SQLITE_SHM_NLOCK))
+ );
+ if( ofst==UNIX_SHM_DMS ){
+ assert( pShmNode->nRef>0 || unixMutexHeld() );
+ assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) );
+ }else{
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ int ii;
+ for(ii=ofst-UNIX_SHM_BASE; ii<ofst-UNIX_SHM_BASE+n; ii++){
+ assert( sqlite3_mutex_held(pShmNode->aMutex[ii]) );
+ }
+#else
+ assert( sqlite3_mutex_held(pShmNode->pShmMutex) );
+ assert( pShmNode->nRef>0 );
+#endif
+ }
/* Shared locks never span more than one byte */
assert( n==1 || lockType!=F_RDLCK );
/* Locks are within range */
assert( n>=1 && n<=SQLITE_SHM_NLOCK );
+ assert( ofst>=UNIX_SHM_BASE && ofst<=(UNIX_SHM_DMS+SQLITE_SHM_NLOCK) );
if( pShmNode->hShm>=0 ){
int res;
@@ -41354,7 +42500,7 @@ static int unixShmSystemLock(
f.l_len = n;
res = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
if( res==-1 ){
-#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+#if defined(SQLITE_ENABLE_SETLK_TIMEOUT) && SQLITE_ENABLE_SETLK_TIMEOUT==1
rc = (pFile->iBusyTimeout ? SQLITE_BUSY_TIMEOUT : SQLITE_BUSY);
#else
rc = SQLITE_BUSY;
@@ -41362,39 +42508,28 @@ static int unixShmSystemLock(
}
}
- /* Update the global lock state and do debug tracing */
+ /* Do debug tracing */
#ifdef SQLITE_DEBUG
- { u16 mask;
OSTRACE(("SHM-LOCK "));
- mask = ofst>31 ? 0xffff : (1<<(ofst+n)) - (1<<ofst);
if( rc==SQLITE_OK ){
if( lockType==F_UNLCK ){
- OSTRACE(("unlock %d ok", ofst));
- pShmNode->exclMask &= ~mask;
- pShmNode->sharedMask &= ~mask;
+ OSTRACE(("unlock %d..%d ok\n", ofst, ofst+n-1));
}else if( lockType==F_RDLCK ){
- OSTRACE(("read-lock %d ok", ofst));
- pShmNode->exclMask &= ~mask;
- pShmNode->sharedMask |= mask;
+ OSTRACE(("read-lock %d..%d ok\n", ofst, ofst+n-1));
}else{
assert( lockType==F_WRLCK );
- OSTRACE(("write-lock %d ok", ofst));
- pShmNode->exclMask |= mask;
- pShmNode->sharedMask &= ~mask;
+ OSTRACE(("write-lock %d..%d ok\n", ofst, ofst+n-1));
}
}else{
if( lockType==F_UNLCK ){
- OSTRACE(("unlock %d failed", ofst));
+ OSTRACE(("unlock %d..%d failed\n", ofst, ofst+n-1));
}else if( lockType==F_RDLCK ){
- OSTRACE(("read-lock failed"));
+ OSTRACE(("read-lock %d..%d failed\n", ofst, ofst+n-1));
}else{
assert( lockType==F_WRLCK );
- OSTRACE(("write-lock %d failed", ofst));
+ OSTRACE(("write-lock %d..%d failed\n", ofst, ofst+n-1));
}
}
- OSTRACE((" - afterwards %03x,%03x\n",
- pShmNode->sharedMask, pShmNode->exclMask));
- }
#endif
return rc;
@@ -41431,6 +42566,11 @@ static void unixShmPurge(unixFile *pFd){
int i;
assert( p->pInode==pFd->pInode );
sqlite3_mutex_free(p->pShmMutex);
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ for(i=0; i<SQLITE_SHM_NLOCK; i++){
+ sqlite3_mutex_free(p->aMutex[i]);
+ }
+#endif
for(i=0; i<p->nRegion; i+=nShmPerMap){
if( p->hShm>=0 ){
osMunmap(p->apRegion[i], p->szRegion);
@@ -41490,7 +42630,20 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){
pShmNode->isUnlocked = 1;
rc = SQLITE_READONLY_CANTINIT;
}else{
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ /* Do not use a blocking lock here. If the lock cannot be obtained
+ ** immediately, it means some other connection is truncating the
+ ** *-shm file. And after it has done so, it will not release its
+ ** lock, but only downgrade it to a shared lock. So no point in
+ ** blocking here. The call below to obtain the shared DMS lock may
+ ** use a blocking lock. */
+ int iSaveTimeout = pDbFd->iBusyTimeout;
+ pDbFd->iBusyTimeout = 0;
+#endif
rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1);
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ pDbFd->iBusyTimeout = iSaveTimeout;
+#endif
/* The first connection to attach must truncate the -shm file. We
** truncate to 3 bytes (an arbitrary small number, less than the
** -shm header size) rather than 0 as a system debugging aid, to
@@ -41611,6 +42764,18 @@ static int unixOpenSharedMemory(unixFile *pDbFd){
rc = SQLITE_NOMEM_BKPT;
goto shm_open_err;
}
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ {
+ int ii;
+ for(ii=0; ii<SQLITE_SHM_NLOCK; ii++){
+ pShmNode->aMutex[ii] = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+ if( pShmNode->aMutex[ii]==0 ){
+ rc = SQLITE_NOMEM_BKPT;
+ goto shm_open_err;
+ }
+ }
+ }
+#endif
}
if( pInode->bProcessLock==0 ){
@@ -41832,9 +42997,11 @@ shmpage_out:
*/
#ifdef SQLITE_DEBUG
static int assertLockingArrayOk(unixShmNode *pShmNode){
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ return 1;
+#else
unixShm *pX;
int aLock[SQLITE_SHM_NLOCK];
- assert( sqlite3_mutex_held(pShmNode->pShmMutex) );
memset(aLock, 0, sizeof(aLock));
for(pX=pShmNode->pFirst; pX; pX=pX->pNext){
@@ -41852,13 +43019,14 @@ static int assertLockingArrayOk(unixShmNode *pShmNode){
assert( 0==memcmp(pShmNode->aLock, aLock, sizeof(aLock)) );
return (memcmp(pShmNode->aLock, aLock, sizeof(aLock))==0);
+#endif
}
#endif
/*
** Change the lock state for a shared-memory segment.
**
-** Note that the relationship between SHAREd and EXCLUSIVE locks is a little
+** Note that the relationship between SHARED and EXCLUSIVE locks is a little
** different here than in posix. In xShmLock(), one can go from unlocked
** to shared and back or from unlocked to exclusive and back. But one may
** not go from shared to exclusive or from exclusive to shared.
@@ -41873,7 +43041,7 @@ static int unixShmLock(
unixShm *p; /* The shared memory being locked */
unixShmNode *pShmNode; /* The underlying file iNode */
int rc = SQLITE_OK; /* Result code */
- u16 mask; /* Mask of locks to take or release */
+ u16 mask = (1<<(ofst+n)) - (1<<ofst); /* Mask of locks to take or release */
int *aLock;
p = pDbFd->pShm;
@@ -41908,88 +43076,151 @@ static int unixShmLock(
** It is not permitted to block on the RECOVER lock.
*/
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
- assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
- (ofst!=2) /* not RECOVER */
- && (ofst!=1 || (p->exclMask|p->sharedMask)==0)
- && (ofst!=0 || (p->exclMask|p->sharedMask)<3)
- && (ofst<3 || (p->exclMask|p->sharedMask)<(1<<ofst))
- ));
+ {
+ u16 lockMask = (p->exclMask|p->sharedMask);
+ assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
+ (ofst!=2) /* not RECOVER */
+ && (ofst!=1 || lockMask==0 || lockMask==2)
+ && (ofst!=0 || lockMask<3)
+ && (ofst<3 || lockMask<(1<<ofst))
+ ));
+ }
#endif
- mask = (1<<(ofst+n)) - (1<<ofst);
- assert( n>1 || mask==(1<<ofst) );
- sqlite3_mutex_enter(pShmNode->pShmMutex);
- assert( assertLockingArrayOk(pShmNode) );
- if( flags & SQLITE_SHM_UNLOCK ){
- if( (p->exclMask|p->sharedMask) & mask ){
- int ii;
- int bUnlock = 1;
+ /* Check if there is any work to do. There are three cases:
+ **
+ ** a) An unlock operation where there are locks to unlock,
+ ** b) An shared lock where the requested lock is not already held
+ ** c) An exclusive lock where the requested lock is not already held
+ **
+ ** The SQLite core never requests an exclusive lock that it already holds.
+ ** This is assert()ed below.
+ */
+ assert( flags!=(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK)
+ || 0==(p->exclMask & mask)
+ );
+ if( ((flags & SQLITE_SHM_UNLOCK) && ((p->exclMask|p->sharedMask) & mask))
+ || (flags==(SQLITE_SHM_SHARED|SQLITE_SHM_LOCK) && 0==(p->sharedMask & mask))
+ || (flags==(SQLITE_SHM_EXCLUSIVE|SQLITE_SHM_LOCK))
+ ){
- for(ii=ofst; ii<ofst+n; ii++){
- if( aLock[ii]>((p->sharedMask & (1<<ii)) ? 1 : 0) ){
- bUnlock = 0;
- }
+ /* Take the required mutexes. In SETLK_TIMEOUT mode (blocking locks), if
+ ** this is an attempt on an exclusive lock use sqlite3_mutex_try(). If any
+ ** other thread is holding this mutex, then it is either holding or about
+ ** to hold a lock exclusive to the one being requested, and we may
+ ** therefore return SQLITE_BUSY to the caller.
+ **
+ ** Doing this prevents some deadlock scenarios. For example, thread 1 may
+ ** be a checkpointer blocked waiting on the WRITER lock. And thread 2
+ ** may be a normal SQL client upgrading to a write transaction. In this
+ ** case thread 2 does a non-blocking request for the WRITER lock. But -
+ ** if it were to use sqlite3_mutex_enter() then it would effectively
+ ** become a (doomed) blocking request, as thread 2 would block until thread
+ ** 1 obtained WRITER and released the mutex. Since thread 2 already holds
+ ** a lock on a read-locking slot at this point, this breaks the
+ ** anti-deadlock rules (see above). */
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ int iMutex;
+ for(iMutex=ofst; iMutex<ofst+n; iMutex++){
+ if( flags==(SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE) ){
+ rc = sqlite3_mutex_try(pShmNode->aMutex[iMutex]);
+ if( rc!=SQLITE_OK ) goto leave_shmnode_mutexes;
+ }else{
+ sqlite3_mutex_enter(pShmNode->aMutex[iMutex]);
}
+ }
+#else
+ sqlite3_mutex_enter(pShmNode->pShmMutex);
+#endif
- if( bUnlock ){
- rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
- if( rc==SQLITE_OK ){
- memset(&aLock[ofst], 0, sizeof(int)*n);
+ if( ALWAYS(rc==SQLITE_OK) ){
+ if( flags & SQLITE_SHM_UNLOCK ){
+ /* Case (a) - unlock. */
+ int bUnlock = 1;
+ assert( (p->exclMask & p->sharedMask)==0 );
+ assert( !(flags & SQLITE_SHM_EXCLUSIVE) || (p->exclMask & mask)==mask );
+ assert( !(flags & SQLITE_SHM_SHARED) || (p->sharedMask & mask)==mask );
+
+ /* If this is a SHARED lock being unlocked, it is possible that other
+ ** clients within this process are holding the same SHARED lock. In
+ ** this case, set bUnlock to 0 so that the posix lock is not removed
+ ** from the file-descriptor below. */
+ if( flags & SQLITE_SHM_SHARED ){
+ assert( n==1 );
+ assert( aLock[ofst]>=1 );
+ if( aLock[ofst]>1 ){
+ bUnlock = 0;
+ aLock[ofst]--;
+ p->sharedMask &= ~mask;
+ }
}
- }else if( ALWAYS(p->sharedMask & (1<<ofst)) ){
- assert( n==1 && aLock[ofst]>1 );
- aLock[ofst]--;
- }
- /* Undo the local locks */
- if( rc==SQLITE_OK ){
- p->exclMask &= ~mask;
- p->sharedMask &= ~mask;
- }
- }
- }else if( flags & SQLITE_SHM_SHARED ){
- assert( n==1 );
- assert( (p->exclMask & (1<<ofst))==0 );
- if( (p->sharedMask & mask)==0 ){
- if( aLock[ofst]<0 ){
- rc = SQLITE_BUSY;
- }else if( aLock[ofst]==0 ){
- rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n);
- }
+ if( bUnlock ){
+ rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n);
+ if( rc==SQLITE_OK ){
+ memset(&aLock[ofst], 0, sizeof(int)*n);
+ p->sharedMask &= ~mask;
+ p->exclMask &= ~mask;
+ }
+ }
+ }else if( flags & SQLITE_SHM_SHARED ){
+ /* Case (b) - a shared lock. */
- /* Get the local shared locks */
- if( rc==SQLITE_OK ){
- p->sharedMask |= mask;
- aLock[ofst]++;
- }
- }
- }else{
- /* Make sure no sibling connections hold locks that will block this
- ** lock. If any do, return SQLITE_BUSY right away. */
- int ii;
- for(ii=ofst; ii<ofst+n; ii++){
- assert( (p->sharedMask & mask)==0 );
- if( ALWAYS((p->exclMask & (1<<ii))==0) && aLock[ii] ){
- rc = SQLITE_BUSY;
- break;
- }
- }
+ if( aLock[ofst]<0 ){
+ /* An exclusive lock is held by some other connection. BUSY. */
+ rc = SQLITE_BUSY;
+ }else if( aLock[ofst]==0 ){
+ rc = unixShmSystemLock(pDbFd, F_RDLCK, ofst+UNIX_SHM_BASE, n);
+ }
- /* Get the exclusive locks at the system level. Then if successful
- ** also update the in-memory values. */
- if( rc==SQLITE_OK ){
- rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n);
- if( rc==SQLITE_OK ){
+ /* Get the local shared locks */
+ if( rc==SQLITE_OK ){
+ p->sharedMask |= mask;
+ aLock[ofst]++;
+ }
+ }else{
+ /* Case (c) - an exclusive lock. */
+ int ii;
+
+ assert( flags==(SQLITE_SHM_LOCK|SQLITE_SHM_EXCLUSIVE) );
assert( (p->sharedMask & mask)==0 );
- p->exclMask |= mask;
+ assert( (p->exclMask & mask)==0 );
+
+ /* Make sure no sibling connections hold locks that will block this
+ ** lock. If any do, return SQLITE_BUSY right away. */
for(ii=ofst; ii<ofst+n; ii++){
- aLock[ii] = -1;
+ if( aLock[ii] ){
+ rc = SQLITE_BUSY;
+ break;
+ }
+ }
+
+ /* Get the exclusive locks at the system level. Then if successful
+ ** also update the in-memory values. */
+ if( rc==SQLITE_OK ){
+ rc = unixShmSystemLock(pDbFd, F_WRLCK, ofst+UNIX_SHM_BASE, n);
+ if( rc==SQLITE_OK ){
+ p->exclMask |= mask;
+ for(ii=ofst; ii<ofst+n; ii++){
+ aLock[ii] = -1;
+ }
+ }
}
}
+ assert( assertLockingArrayOk(pShmNode) );
}
+
+ /* Drop the mutexes acquired above. */
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ leave_shmnode_mutexes:
+ for(iMutex--; iMutex>=ofst; iMutex--){
+ sqlite3_mutex_leave(pShmNode->aMutex[iMutex]);
+ }
+#else
+ sqlite3_mutex_leave(pShmNode->pShmMutex);
+#endif
}
- assert( assertLockingArrayOk(pShmNode) );
- sqlite3_mutex_leave(pShmNode->pShmMutex);
+
OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n",
p->id, osGetpid(0), p->sharedMask, p->exclMask));
return rc;
@@ -42239,11 +43470,16 @@ static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
#if SQLITE_MAX_MMAP_SIZE>0
if( pFd->mmapSizeMax>0 ){
+ /* Ensure that there is always at least a 256 byte buffer of addressable
+ ** memory following the returned page. If the database is corrupt,
+ ** SQLite may overread the page slightly (in practice only a few bytes,
+ ** but 256 is safe, round, number). */
+ const int nEofBuffer = 256;
if( pFd->pMapRegion==0 ){
int rc = unixMapfile(pFd, -1);
if( rc!=SQLITE_OK ) return rc;
}
- if( pFd->mmapSize >= iOff+nAmt ){
+ if( pFd->mmapSize >= (iOff+nAmt+nEofBuffer) ){
*pp = &((u8 *)pFd->pMapRegion)[iOff];
pFd->nFetchOut++;
}
@@ -43634,12 +44870,17 @@ static int unixRandomness(sqlite3_vfs *NotUsed, int nBuf, char *zBuf){
** than the argument.
*/
static int unixSleep(sqlite3_vfs *NotUsed, int microseconds){
-#if OS_VXWORKS || _POSIX_C_SOURCE >= 199309L
+#if !defined(HAVE_NANOSLEEP) || HAVE_NANOSLEEP+0
struct timespec sp;
-
sp.tv_sec = microseconds / 1000000;
sp.tv_nsec = (microseconds % 1000000) * 1000;
+
+ /* Almost all modern unix systems support nanosleep(). But if you are
+ ** compiling for one of the rare exceptions, you can use
+ ** -DHAVE_NANOSLEEP=0 (perhaps in conjuction with -DHAVE_USLEEP if
+ ** usleep() is available) in order to bypass the use of nanosleep() */
nanosleep(&sp, NULL);
+
UNUSED_PARAMETER(NotUsed);
return microseconds;
#elif defined(HAVE_USLEEP) && HAVE_USLEEP
@@ -46229,7 +47470,7 @@ static struct win_syscall {
/*
** This is the xSetSystemCall() method of sqlite3_vfs for all of the
-** "win32" VFSes. Return SQLITE_OK opon successfully updating the
+** "win32" VFSes. Return SQLITE_OK upon successfully updating the
** system call pointer, or SQLITE_NOTFOUND if there is no configurable
** system call named zName.
*/
@@ -47809,7 +49050,7 @@ static int winRead(
pFile->h, pBuf, amt, offset, pFile->locktype));
#if SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this read request as possible by transfering
+ /* Deal with as much of this read request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
@@ -47887,7 +49128,7 @@ static int winWrite(
pFile->h, pBuf, amt, offset, pFile->locktype));
#if defined(SQLITE_MMAP_READWRITE) && SQLITE_MAX_MMAP_SIZE>0
- /* Deal with as much of this write request as possible by transfering
+ /* Deal with as much of this write request as possible by transferring
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
@@ -47997,7 +49238,7 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
** all references to memory-mapped content are closed. That is doable,
** but involves adding a few branches in the common write code path which
** could slow down normal operations slightly. Hence, we have decided for
- ** now to simply make trancations a no-op if there are pending reads. We
+ ** now to simply make transactions a no-op if there are pending reads. We
** can maybe revisit this decision in the future.
*/
return SQLITE_OK;
@@ -48056,7 +49297,7 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
#ifdef SQLITE_TEST
/*
** Count the number of fullsyncs and normal syncs. This is used to test
-** that syncs and fullsyncs are occuring at the right times.
+** that syncs and fullsyncs are occurring at the right times.
*/
SQLITE_API int sqlite3_sync_count = 0;
SQLITE_API int sqlite3_fullsync_count = 0;
@@ -48413,7 +49654,7 @@ static int winLock(sqlite3_file *id, int locktype){
*/
if( locktype==EXCLUSIVE_LOCK && res ){
assert( pFile->locktype>=SHARED_LOCK );
- res = winUnlockReadLock(pFile);
+ (void)winUnlockReadLock(pFile);
res = winLockFile(&pFile->h, SQLITE_LOCKFILE_FLAGS, SHARED_FIRST, 0,
SHARED_SIZE, 0);
if( res ){
@@ -49591,6 +50832,11 @@ static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
#if SQLITE_MAX_MMAP_SIZE>0
if( pFd->mmapSizeMax>0 ){
+ /* Ensure that there is always at least a 256 byte buffer of addressable
+ ** memory following the returned page. If the database is corrupt,
+ ** SQLite may overread the page slightly (in practice only a few bytes,
+ ** but 256 is safe, round, number). */
+ const int nEofBuffer = 256;
if( pFd->pMapRegion==0 ){
int rc = winMapfile(pFd, -1);
if( rc!=SQLITE_OK ){
@@ -49599,7 +50845,7 @@ static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
return rc;
}
}
- if( pFd->mmapSize >= iOff+nAmt ){
+ if( pFd->mmapSize >= (iOff+nAmt+nEofBuffer) ){
assert( pFd->pMapRegion!=0 );
*pp = &((u8 *)pFd->pMapRegion)[iOff];
pFd->nFetchOut++;
@@ -49817,6 +51063,7 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
size_t i, j;
+ DWORD pid;
int nPre = sqlite3Strlen30(SQLITE_TEMP_FILE_PREFIX);
int nMax, nBuf, nDir, nLen;
char *zBuf;
@@ -50029,7 +51276,10 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
j = sqlite3Strlen30(zBuf);
sqlite3_randomness(15, &zBuf[j]);
+ pid = osGetCurrentProcessId();
for(i=0; i<15; i++, j++){
+ zBuf[j] += pid & 0xff;
+ pid >>= 8;
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
@@ -50267,7 +51517,7 @@ static int winOpen(
if( isReadWrite ){
int rc2, isRO = 0;
sqlite3BeginBenignMalloc();
- rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@@ -50284,7 +51534,7 @@ static int winOpen(
if( isReadWrite ){
int rc2, isRO = 0;
sqlite3BeginBenignMalloc();
- rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@@ -50304,7 +51554,7 @@ static int winOpen(
if( isReadWrite ){
int rc2, isRO = 0;
sqlite3BeginBenignMalloc();
- rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@@ -50527,6 +51777,13 @@ static int winAccess(
OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n",
zFilename, flags, pResOut));
+ if( zFilename==0 ){
+ *pResOut = 0;
+ OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
+ zFilename, pResOut, *pResOut));
+ return SQLITE_OK;
+ }
+
zConverted = winConvertFromUtf8Filename(zFilename);
if( zConverted==0 ){
OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
@@ -52067,6 +53324,14 @@ SQLITE_API unsigned char *sqlite3_serialize(
pOut = 0;
}else{
sz = sqlite3_column_int64(pStmt, 0)*szPage;
+ if( sz==0 ){
+ sqlite3_reset(pStmt);
+ sqlite3_exec(db, "BEGIN IMMEDIATE; COMMIT;", 0, 0, 0);
+ rc = sqlite3_step(pStmt);
+ if( rc==SQLITE_ROW ){
+ sz = sqlite3_column_int64(pStmt, 0)*szPage;
+ }
+ }
if( piSize ) *piSize = sz;
if( mFlags & SQLITE_SERIALIZE_NOCOPY ){
pOut = 0;
@@ -52387,7 +53652,7 @@ SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec *p, u32 i){
h = BITVEC_HASH(i++);
/* if there wasn't a hash collision, and this doesn't */
/* completely fill the hash, then just add it without */
- /* worring about sub-dividing and re-hashing. */
+ /* worrying about sub-dividing and re-hashing. */
if( !p->u.aHash[h] ){
if (p->nSet<(BITVEC_NINT-1)) {
goto bitvec_set_end;
@@ -52654,7 +53919,7 @@ bitvec_end:
struct PCache {
PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */
PgHdr *pSynced; /* Last synced page in dirty page list */
- int nRefSum; /* Sum of ref counts over all pages */
+ i64 nRefSum; /* Sum of ref counts over all pages */
int szCache; /* Configured cache size */
int szSpill; /* Size before spilling occurs */
int szPage; /* Size of every page in this cache */
@@ -52683,11 +53948,15 @@ struct PCache {
PgHdr *pPg;
unsigned char *a;
int j;
- 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(" ptr %p\n", pPg);
+ if( pLower==0 ){
+ printf("%3d: NULL\n", i);
+ }else{
+ pPg = (PgHdr*)pLower->pExtra;
+ printf("%3d: nRef %2lld flgs %02x data ", i, pPg->nRef, pPg->flags);
+ a = (unsigned char *)pLower->pBuf;
+ for(j=0; j<12; j++) printf("%02x", a[j]);
+ printf(" ptr %p\n", pPg);
+ }
}
static void pcacheDump(PCache *pCache){
int N;
@@ -52700,9 +53969,8 @@ struct PCache {
if( N>sqlite3PcacheMxDump ) N = sqlite3PcacheMxDump;
for(i=1; i<=N; i++){
pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0);
- if( pLower==0 ) continue;
pcachePageTrace(i, pLower);
- if( ((PgHdr*)pLower)->pPage==0 ){
+ if( pLower && ((PgHdr*)pLower)->pPage==0 ){
sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0);
}
}
@@ -52717,7 +53985,7 @@ struct PCache {
** Return 1 if pPg is on the dirty list for pCache. Return 0 if not.
** This routine runs inside of assert() statements only.
*/
-#ifdef SQLITE_DEBUG
+#if defined(SQLITE_ENABLE_EXPENSIVE_ASSERT)
static int pageOnDirtyList(PCache *pCache, PgHdr *pPg){
PgHdr *p;
for(p=pCache->pDirty; p; p=p->pDirtyNext){
@@ -52725,6 +53993,16 @@ static int pageOnDirtyList(PCache *pCache, PgHdr *pPg){
}
return 0;
}
+static int pageNotOnDirtyList(PCache *pCache, PgHdr *pPg){
+ PgHdr *p;
+ for(p=pCache->pDirty; p; p=p->pDirtyNext){
+ if( p==pPg ) return 0;
+ }
+ return 1;
+}
+#else
+# define pageOnDirtyList(A,B) 1
+# define pageNotOnDirtyList(A,B) 1
#endif
/*
@@ -52745,7 +54023,7 @@ SQLITE_PRIVATE int sqlite3PcachePageSanity(PgHdr *pPg){
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( !pageOnDirtyList(pCache, pPg) );/* CLEAN pages not on dirty list */
+ assert( pageNotOnDirtyList(pCache, pPg) );/* CLEAN pages not on dirtylist */
}else{
assert( (pPg->flags & PGHDR_DIRTY)!=0 );/* If not CLEAN must be DIRTY */
assert( pPg->pDirtyNext==0 || pPg->pDirtyNext->pDirtyPrev==pPg );
@@ -52881,7 +54159,7 @@ static int numberOfCachePages(PCache *p){
return p->szCache;
}else{
i64 n;
- /* IMPLEMANTATION-OF: R-59858-46238 If the argument N is negative, then the
+ /* IMPLEMENTATION-OF: R-59858-46238 If the argument N is negative, then the
** number of cache pages is adjusted to be a number of pages that would
** use approximately abs(N*1024) bytes of memory based on the current
** page size. */
@@ -53369,7 +54647,7 @@ static PgHdr *pcacheMergeDirtyList(PgHdr *pA, PgHdr *pB){
}
/*
-** Sort the list of pages in accending order by pgno. Pages are
+** Sort the list of pages in ascending order by pgno. Pages are
** connected by pDirty pointers. The pDirtyPrev pointers are
** corrupted by this sort.
**
@@ -53428,14 +54706,14 @@ SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
** This is not the total number of pages referenced, but the sum of the
** reference count for all pages.
*/
-SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache *pCache){
+SQLITE_PRIVATE i64 sqlite3PcacheRefCount(PCache *pCache){
return pCache->nRefSum;
}
/*
** Return the number of references to the page supplied as an argument.
*/
-SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr *p){
+SQLITE_PRIVATE i64 sqlite3PcachePageRefcount(PgHdr *p){
return p->nRef;
}
@@ -53609,7 +54887,7 @@ SQLITE_PRIVATE void sqlite3PcacheIterateDirty(PCache *pCache, void (*xIter)(PgHd
** If N is positive, then N pages worth of memory are allocated using a single
** sqlite3Malloc() call and that memory is used for the first N pages allocated.
** Or if N is negative, then -1024*N bytes of memory are allocated and used
-** for as many pages as can be accomodated.
+** for as many pages as can be accommodated.
**
** Only one of (2) or (3) can be used. Once the memory available to (2) or
** (3) is exhausted, subsequent allocations fail over to the general-purpose
@@ -53643,7 +54921,7 @@ typedef struct PGroup PGroup;
** in memory directly after the associated page data, if the database is
** corrupt, code at the b-tree layer may overread the page buffer and
** read part of this structure before the corruption is detected. This
-** can cause a valgrind error if the unitialized gap is accessed. Using u16
+** can cause a valgrind error if the uninitialized gap is accessed. Using u16
** ensures there is no such gap, and therefore no bytes of uninitialized
** memory in the structure.
**
@@ -54863,7 +56141,7 @@ SQLITE_PRIVATE void sqlite3PcacheStats(
** The TEST primitive includes a "batch" number. The TEST primitive
** will only see elements that were inserted before the last change
** in the batch number. In other words, if an INSERT occurs between
-** two TESTs where the TESTs have the same batch nubmer, then the
+** two TESTs where the TESTs have the same batch number, then the
** value added by the INSERT will not be visible to the second TEST.
** The initial batch number is zero, so if the very first TEST contains
** a non-zero batch number, it will see all prior INSERTs.
@@ -55395,6 +56673,7 @@ SQLITE_PRIVATE int sqlite3RowSetTest(RowSet *pRowSet, int iBatch, sqlite3_int64
# define sqlite3WalFramesize(z) 0
# define sqlite3WalFindFrame(x,y,z) 0
# define sqlite3WalFile(x) 0
+# undef SQLITE_USE_SEH
#else
#define WAL_SAVEPOINT_NDATA 4
@@ -55501,6 +56780,10 @@ SQLITE_PRIVATE int sqlite3WalWriteLock(Wal *pWal, int bLock);
SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db);
#endif
+#ifdef SQLITE_USE_SEH
+SQLITE_PRIVATE int sqlite3WalSystemErrno(Wal*);
+#endif
+
#endif /* ifndef SQLITE_OMIT_WAL */
#endif /* SQLITE_WAL_H */
@@ -55786,7 +57069,7 @@ int sqlite3PagerTrace=1; /* True to enable tracing */
** outstanding transactions have been abandoned, the pager is able to
** transition back to OPEN state, discarding the contents of the
** page-cache and any other in-memory state at the same time. Everything
-** is reloaded from disk (and, if necessary, hot-journal rollback peformed)
+** is reloaded from disk (and, if necessary, hot-journal rollback performed)
** when a read-transaction is next opened on the pager (transitioning
** the pager into READER state). At that point the system has recovered
** from the error.
@@ -56173,7 +57456,7 @@ struct Pager {
char *zJournal; /* Name of the journal file */
int (*xBusyHandler)(void*); /* Function to call when busy */
void *pBusyHandlerArg; /* Context argument for xBusyHandler */
- int aStat[4]; /* Total cache hits, misses, writes, spills */
+ u32 aStat[4]; /* Total cache hits, misses, writes, spills */
#ifdef SQLITE_TEST
int nRead; /* Database pages read */
#endif
@@ -56303,9 +57586,8 @@ SQLITE_PRIVATE int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno){
#ifndef SQLITE_OMIT_WAL
if( pPager->pWal ){
u32 iRead = 0;
- int rc;
- rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
- return (rc==SQLITE_OK && iRead==0);
+ (void)sqlite3WalFindFrame(pPager->pWal, pgno, &iRead);
+ return iRead==0;
}
#endif
return 1;
@@ -56977,9 +58259,32 @@ static int writeJournalHdr(Pager *pPager){
memset(zHeader, 0, sizeof(aJournalMagic)+4);
}
+
+
/* The random check-hash initializer */
- sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
+ if( pPager->journalMode!=PAGER_JOURNALMODE_MEMORY ){
+ sqlite3_randomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
+ }
+#ifdef SQLITE_DEBUG
+ else{
+ /* The Pager.cksumInit variable is usually randomized above to protect
+ ** against there being existing records in the journal file. This is
+ ** dangerous, as following a crash they may be mistaken for records
+ ** written by the current transaction and rolled back into the database
+ ** file, causing corruption. The following assert statements verify
+ ** that this is not required in "journal_mode=memory" mode, as in that
+ ** case the journal file is always 0 bytes in size at this point.
+ ** It is advantageous to avoid the sqlite3_randomness() call if possible
+ ** as it takes the global PRNG mutex. */
+ i64 sz = 0;
+ sqlite3OsFileSize(pPager->jfd, &sz);
+ assert( sz==0 );
+ assert( pPager->journalOff==journalHdrOffset(pPager) );
+ assert( sqlite3JournalIsInMemory(pPager->jfd) );
+ }
+#endif
put32bits(&zHeader[sizeof(aJournalMagic)+4], pPager->cksumInit);
+
/* The initial database size */
put32bits(&zHeader[sizeof(aJournalMagic)+8], pPager->dbOrigSize);
/* The assumed sector size for this process */
@@ -57159,7 +58464,7 @@ static int readJournalHdr(
** + 4 bytes: super-journal name checksum.
** + 8 bytes: aJournalMagic[].
**
-** The super-journal page checksum is the sum of the bytes in thesuper-journal
+** The super-journal page checksum is the sum of the bytes in the super-journal
** name, where each byte is interpreted as a signed 8-bit integer.
**
** If zSuper is a NULL pointer (occurs for a single database transaction),
@@ -57212,7 +58517,7 @@ static int writeSuperJournal(Pager *pPager, const char *zSuper){
}
pPager->journalOff += (nSuper+20);
- /* If the pager is in peristent-journal mode, then the physical
+ /* If the pager is in persistent-journal mode, then the physical
** journal-file may extend past the end of the super-journal name
** and 8 bytes of magic data just written to the file. This is
** dangerous because the code to rollback a hot-journal file
@@ -57382,7 +58687,7 @@ static void pager_unlock(Pager *pPager){
/*
** This function is called whenever an IOERR or FULL error that requires
-** the pager to transition into the ERROR state may ahve occurred.
+** the pager to transition into the ERROR state may have occurred.
** The first argument is a pointer to the pager structure, the second
** the error-code about to be returned by a pager API function. The
** value returned is a copy of the second argument to this function.
@@ -57623,6 +58928,9 @@ static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){
return (rc==SQLITE_OK?rc2:rc);
}
+/* Forward reference */
+static int pager_playback(Pager *pPager, int isHot);
+
/*
** Execute a rollback if a transaction is active and unlock the
** database file.
@@ -57651,13 +58959,28 @@ static void pagerUnlockAndRollback(Pager *pPager){
assert( pPager->eState==PAGER_READER );
pager_end_transaction(pPager, 0, 0);
}
+ }else if( pPager->eState==PAGER_ERROR
+ && pPager->journalMode==PAGER_JOURNALMODE_MEMORY
+ && isOpen(pPager->jfd)
+ ){
+ /* Special case for a ROLLBACK due to I/O error with an in-memory
+ ** journal: We have to rollback immediately, before the journal is
+ ** closed, because once it is closed, all content is forgotten. */
+ int errCode = pPager->errCode;
+ u8 eLock = pPager->eLock;
+ pPager->eState = PAGER_OPEN;
+ pPager->errCode = SQLITE_OK;
+ pPager->eLock = EXCLUSIVE_LOCK;
+ pager_playback(pPager, 1);
+ pPager->errCode = errCode;
+ pPager->eLock = eLock;
}
pager_unlock(pPager);
}
/*
** Parameter aData must point to a buffer of pPager->pageSize bytes
-** of data. Compute and return a checksum based ont the contents of the
+** of data. Compute and return a checksum based on the contents of the
** page of data and the current value of pPager->cksumInit.
**
** This is not a real checksum. It is really just the sum of the
@@ -58090,6 +59413,8 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
int rc = SQLITE_OK;
assert( pPager->eState!=PAGER_ERROR );
assert( pPager->eState!=PAGER_READER );
+ PAGERTRACE(("Truncate %d npage %u\n", PAGERID(pPager), nPage));
+
if( isOpen(pPager->fd)
&& (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
@@ -58621,7 +59946,7 @@ static int pagerWalFrames(
assert( pPager->pWal );
assert( pList );
#ifdef SQLITE_DEBUG
- /* Verify that the page list is in accending order */
+ /* Verify that the page list is in ascending order */
for(p=pList; p && p->pDirty; p=p->pDirty){
assert( p->pgno < p->pDirty->pgno );
}
@@ -58752,7 +60077,7 @@ static int pagerPagecount(Pager *pPager, Pgno *pnPage){
#ifndef SQLITE_OMIT_WAL
/*
** Check if the *-wal file that corresponds to the database opened by pPager
-** exists if the database is not empy, or verify that the *-wal file does
+** exists if the database is not empty, or verify that the *-wal file does
** not exist (by deleting it) if the database file is empty.
**
** If the database is not empty and the *-wal file exists, open the pager
@@ -60162,11 +61487,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
int rc = SQLITE_OK; /* Return code */
int tempFile = 0; /* True for temp files (incl. in-memory files) */
int memDb = 0; /* True if this is an in-memory file */
-#ifndef SQLITE_OMIT_DESERIALIZE
int memJM = 0; /* Memory journal mode */
-#else
-# define memJM 0
-#endif
int readOnly = 0; /* True if this is a read-only file */
int journalFileSize; /* Bytes to allocate for each journal fd */
char *zPathname = 0; /* Full path to database file */
@@ -60285,12 +61606,13 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
** specific formatting and order of the various filenames, so if the format
** changes here, be sure to change it there as well.
*/
+ assert( SQLITE_PTRSIZE==sizeof(Pager*) );
pPtr = (u8 *)sqlite3MallocZero(
ROUND8(sizeof(*pPager)) + /* Pager structure */
ROUND8(pcacheSize) + /* PCache object */
ROUND8(pVfs->szOsFile) + /* The main db file */
journalFileSize * 2 + /* The two journal files */
- sizeof(pPager) + /* Space to hold a pointer */
+ SQLITE_PTRSIZE + /* Space to hold a pointer */
4 + /* Database prefix */
nPathname + 1 + /* database filename */
nUriByte + /* query parameters */
@@ -60311,7 +61633,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
pPager->sjfd = (sqlite3_file*)pPtr; pPtr += journalFileSize;
pPager->jfd = (sqlite3_file*)pPtr; pPtr += journalFileSize;
assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) );
- memcpy(pPtr, &pPager, sizeof(pPager)); pPtr += sizeof(pPager);
+ memcpy(pPtr, &pPager, SQLITE_PTRSIZE); pPtr += SQLITE_PTRSIZE;
/* Fill in the Pager.zFilename and pPager.zQueryParam fields */
pPtr += 4; /* Skip zero prefix */
@@ -60365,9 +61687,7 @@ SQLITE_PRIVATE int sqlite3PagerOpen(
int fout = 0; /* VFS flags returned by xOpen() */
rc = sqlite3OsOpen(pVfs, pPager->zFilename, pPager->fd, vfsFlags, &fout);
assert( !memDb );
-#ifndef SQLITE_OMIT_DESERIALIZE
pPager->memVfs = memJM = (fout&SQLITE_OPEN_MEMORY)!=0;
-#endif
readOnly = (fout&SQLITE_OPEN_READONLY)!=0;
/* If the file was successfully opened for read/write access,
@@ -60504,15 +61824,18 @@ act_like_temp_file:
/*
** Return the sqlite3_file for the main database given the name
-** of the corresonding WAL or Journal name as passed into
+** of the corresponding WAL or Journal name as passed into
** xOpen.
*/
SQLITE_API sqlite3_file *sqlite3_database_file_object(const char *zName){
Pager *pPager;
+ const char *p;
while( zName[-1]!=0 || zName[-2]!=0 || zName[-3]!=0 || zName[-4]!=0 ){
zName--;
}
- pPager = *(Pager**)(zName - 4 - sizeof(Pager*));
+ p = zName - 4 - sizeof(Pager*);
+ assert( EIGHT_BYTE_ALIGNMENT(p) );
+ pPager = *(Pager**)p;
return pPager->fd;
}
@@ -61007,6 +62330,10 @@ static int getPageNormal(
if( !isOpen(pPager->fd) || pPager->dbSize<pgno || noContent ){
if( pgno>pPager->mxPgno ){
rc = SQLITE_FULL;
+ if( pgno<=pPager->dbSize ){
+ sqlite3PcacheRelease(pPg);
+ pPg = 0;
+ }
goto pager_acquire_err;
}
if( noContent ){
@@ -61142,8 +62469,20 @@ SQLITE_PRIVATE int sqlite3PagerGet(
DbPage **ppPage, /* Write a pointer to the page here */
int flags /* PAGER_GET_XXX flags */
){
- /* printf("PAGE %u\n", pgno); fflush(stdout); */
+#if 0 /* Trace page fetch by setting to 1 */
+ int rc;
+ printf("PAGE %u\n", pgno);
+ fflush(stdout);
+ rc = pPager->xGet(pPager, pgno, ppPage, flags);
+ if( rc ){
+ printf("PAGE %u failed with 0x%02x\n", pgno, rc);
+ fflush(stdout);
+ }
+ return rc;
+#else
+ /* Normal, high-speed version of sqlite3PagerGet() */
return pPager->xGet(pPager, pgno, ppPage, flags);
+#endif
}
/*
@@ -61171,10 +62510,12 @@ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
/*
** Release a page reference.
**
-** The sqlite3PagerUnref() and sqlite3PagerUnrefNotNull() may only be
-** used if we know that the page being released is not the last page.
+** The sqlite3PagerUnref() and sqlite3PagerUnrefNotNull() may only be used
+** if we know that the page being released is not the last reference to page1.
** The btree layer always holds page1 open until the end, so these first
-** to routines can be used to release any page other than BtShared.pPage1.
+** two routines can be used to release any page other than BtShared.pPage1.
+** The assert() at tag-20230419-2 proves that this constraint is always
+** honored.
**
** Use sqlite3PagerUnrefPageOne() to release page1. This latter routine
** checks the total number of outstanding pages and if the number of
@@ -61190,7 +62531,7 @@ SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage *pPg){
sqlite3PcacheRelease(pPg);
}
/* Do not use this routine to release the last reference to page1 */
- assert( sqlite3PcacheRefCount(pPager->pPCache)>0 );
+ assert( sqlite3PcacheRefCount(pPager->pPCache)>0 ); /* tag-20230419-2 */
}
SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){
if( pPg ) sqlite3PagerUnrefNotNull(pPg);
@@ -62017,6 +63358,13 @@ SQLITE_PRIVATE int sqlite3PagerCommitPhaseOne(
rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0);
if( rc==SQLITE_OK ){
rc = pager_write_pagelist(pPager, pList);
+ if( rc==SQLITE_OK && pPager->dbSize>pPager->dbFileSize ){
+ char *pTmp = pPager->pTmpSpace;
+ int szPage = (int)pPager->pageSize;
+ memset(pTmp, 0, szPage);
+ rc = sqlite3OsWrite(pPager->fd, pTmp, szPage,
+ ((i64)pPager->dbSize*pPager->pageSize)-szPage);
+ }
if( rc==SQLITE_OK ){
rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
}
@@ -62251,11 +63599,11 @@ SQLITE_PRIVATE int *sqlite3PagerStats(Pager *pPager){
a[3] = pPager->eState==PAGER_OPEN ? -1 : (int) pPager->dbSize;
a[4] = pPager->eState;
a[5] = pPager->errCode;
- a[6] = pPager->aStat[PAGER_STAT_HIT];
- a[7] = pPager->aStat[PAGER_STAT_MISS];
+ a[6] = (int)pPager->aStat[PAGER_STAT_HIT] & 0x7fffffff;
+ a[7] = (int)pPager->aStat[PAGER_STAT_MISS] & 0x7fffffff;
a[8] = 0; /* Used to be pPager->nOvfl */
a[9] = pPager->nRead;
- a[10] = pPager->aStat[PAGER_STAT_WRITE];
+ a[10] = (int)pPager->aStat[PAGER_STAT_WRITE] & 0x7fffffff;
return a;
}
#endif
@@ -62271,7 +63619,7 @@ SQLITE_PRIVATE int *sqlite3PagerStats(Pager *pPager){
** reset parameter is non-zero, the cache hit or miss count is zeroed before
** returning.
*/
-SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, int *pnVal){
+SQLITE_PRIVATE void sqlite3PagerCacheStat(Pager *pPager, int eStat, int reset, u64 *pnVal){
assert( eStat==SQLITE_DBSTATUS_CACHE_HIT
|| eStat==SQLITE_DBSTATUS_CACHE_MISS
@@ -62507,7 +63855,7 @@ SQLITE_PRIVATE sqlite3_file *sqlite3PagerFile(Pager *pPager){
** This will be either the rollback journal or the WAL file.
*/
SQLITE_PRIVATE sqlite3_file *sqlite3PagerJrnlFile(Pager *pPager){
-#if SQLITE_OMIT_WAL
+#ifdef SQLITE_OMIT_WAL
return pPager->jfd;
#else
return pPager->pWal ? sqlite3WalFile(pPager->pWal) : pPager->jfd;
@@ -62783,7 +64131,7 @@ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
assert( pPager->eState!=PAGER_ERROR );
pPager->journalMode = (u8)eMode;
- /* When transistioning from TRUNCATE or PERSIST to any other journal
+ /* When transitioning from TRUNCATE or PERSIST to any other journal
** mode except WAL, unless the pager is in locking_mode=exclusive mode,
** delete the journal file.
*/
@@ -62828,7 +64176,7 @@ SQLITE_PRIVATE int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){
}
assert( state==pPager->eState );
}
- }else if( eMode==PAGER_JOURNALMODE_OFF ){
+ }else if( eMode==PAGER_JOURNALMODE_OFF || eMode==PAGER_JOURNALMODE_MEMORY ){
sqlite3OsClose(pPager->jfd);
}
}
@@ -62950,13 +64298,15 @@ SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){
*/
static int pagerExclusiveLock(Pager *pPager){
int rc; /* Return code */
+ u8 eOrigLock; /* Original lock */
- assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK );
+ assert( pPager->eLock>=SHARED_LOCK );
+ eOrigLock = pPager->eLock;
rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
if( rc!=SQLITE_OK ){
/* If the attempt to grab the exclusive lock failed, release the
** pending lock that may have been obtained instead. */
- pagerUnlockDb(pPager, SHARED_LOCK);
+ pagerUnlockDb(pPager, eOrigLock);
}
return rc;
@@ -63209,6 +64559,12 @@ SQLITE_PRIVATE int sqlite3PagerWalFramesize(Pager *pPager){
}
#endif
+#if defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL)
+SQLITE_PRIVATE int sqlite3PagerWalSystemErrno(Pager *pPager){
+ return sqlite3WalSystemErrno(pPager->pWal);
+}
+#endif
+
#endif /* SQLITE_OMIT_DISKIO */
/************** End of pager.c ***********************************************/
@@ -63499,7 +64855,7 @@ SQLITE_PRIVATE int sqlite3WalTrace = 0;
**
** Technically, the various VFSes are free to implement these locks however
** they see fit. However, compatibility is encouraged so that VFSes can
-** interoperate. The standard implemention used on both unix and windows
+** interoperate. The standard implementation used on both unix and windows
** is for the index number to indicate a byte offset into the
** WalCkptInfo.aLock[] array in the wal-index header. In other words, all
** locks are on the shm file. The WALINDEX_LOCK_OFFSET constant (which
@@ -63575,7 +64931,7 @@ struct WalIndexHdr {
** the mxFrame for that reader. The value READMARK_NOT_USED (0xffffffff)
** for any aReadMark[] means that entry is unused. aReadMark[0] is
** a special case; its value is never used and it exists as a place-holder
-** to avoid having to offset aReadMark[] indexs by one. Readers holding
+** to avoid having to offset aReadMark[] indexes by one. Readers holding
** WAL_READ_LOCK(0) always ignore the entire WAL and read all content
** directly from the database.
**
@@ -63743,7 +65099,15 @@ struct Wal {
u32 iReCksum; /* On commit, recalculate checksums from here */
const char *zWalName; /* Name of WAL file */
u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
+#ifdef SQLITE_USE_SEH
+ u32 lockMask; /* Mask of locks held */
+ void *pFree; /* Pointer to sqlite3_free() if exception thrown */
+ u32 *pWiValue; /* Value to write into apWiData[iWiPg] */
+ int iWiPg; /* Write pWiValue into apWiData[iWiPg] */
+ int iSysErrno; /* System error code following exception */
+#endif
#ifdef SQLITE_DEBUG
+ int nSehTry; /* Number of nested SEH_TRY{} blocks */
u8 lockError; /* True if a locking error has occurred */
#endif
#ifdef SQLITE_ENABLE_SNAPSHOT
@@ -63826,6 +65190,113 @@ struct WalIterator {
)
/*
+** Structured Exception Handling (SEH) is a Windows-specific technique
+** for catching exceptions raised while accessing memory-mapped files.
+**
+** The -DSQLITE_USE_SEH compile-time option means to use SEH to catch and
+** deal with system-level errors that arise during WAL -shm file processing.
+** Without this compile-time option, any system-level faults that appear
+** while accessing the memory-mapped -shm file will cause a process-wide
+** signal to be deliver, which will more than likely cause the entire
+** process to exit.
+*/
+#ifdef SQLITE_USE_SEH
+#include <Windows.h>
+
+/* Beginning of a block of code in which an exception might occur */
+# define SEH_TRY __try { \
+ assert( walAssertLockmask(pWal) && pWal->nSehTry==0 ); \
+ VVA_ONLY(pWal->nSehTry++);
+
+/* The end of a block of code in which an exception might occur */
+# define SEH_EXCEPT(X) \
+ VVA_ONLY(pWal->nSehTry--); \
+ assert( pWal->nSehTry==0 ); \
+ } __except( sehExceptionFilter(pWal, GetExceptionCode(), GetExceptionInformation() ) ){ X }
+
+/* Simulate a memory-mapping fault in the -shm file for testing purposes */
+# define SEH_INJECT_FAULT sehInjectFault(pWal)
+
+/*
+** The second argument is the return value of GetExceptionCode() for the
+** current exception. Return EXCEPTION_EXECUTE_HANDLER if the exception code
+** indicates that the exception may have been caused by accessing the *-shm
+** file mapping. Or EXCEPTION_CONTINUE_SEARCH otherwise.
+*/
+static int sehExceptionFilter(Wal *pWal, int eCode, EXCEPTION_POINTERS *p){
+ VVA_ONLY(pWal->nSehTry--);
+ if( eCode==EXCEPTION_IN_PAGE_ERROR ){
+ if( p && p->ExceptionRecord && p->ExceptionRecord->NumberParameters>=3 ){
+ /* From MSDN: For this type of exception, the first element of the
+ ** ExceptionInformation[] array is a read-write flag - 0 if the exception
+ ** was thrown while reading, 1 if while writing. The second element is
+ ** the virtual address being accessed. The "third array element specifies
+ ** the underlying NTSTATUS code that resulted in the exception". */
+ pWal->iSysErrno = (int)p->ExceptionRecord->ExceptionInformation[2];
+ }
+ return EXCEPTION_EXECUTE_HANDLER;
+ }
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+/*
+** If one is configured, invoke the xTestCallback callback with 650 as
+** the argument. If it returns true, throw the same exception that is
+** thrown by the system if the *-shm file mapping is accessed after it
+** has been invalidated.
+*/
+static void sehInjectFault(Wal *pWal){
+ int res;
+ assert( pWal->nSehTry>0 );
+
+ res = sqlite3FaultSim(650);
+ if( res!=0 ){
+ ULONG_PTR aArg[3];
+ aArg[0] = 0;
+ aArg[1] = 0;
+ aArg[2] = (ULONG_PTR)res;
+ RaiseException(EXCEPTION_IN_PAGE_ERROR, 0, 3, (const ULONG_PTR*)aArg);
+ }
+}
+
+/*
+** There are two ways to use this macro. To set a pointer to be freed
+** if an exception is thrown:
+**
+** SEH_FREE_ON_ERROR(0, pPtr);
+**
+** and to cancel the same:
+**
+** SEH_FREE_ON_ERROR(pPtr, 0);
+**
+** In the first case, there must not already be a pointer registered to
+** be freed. In the second case, pPtr must be the registered pointer.
+*/
+#define SEH_FREE_ON_ERROR(X,Y) \
+ assert( (X==0 || Y==0) && pWal->pFree==X ); pWal->pFree = Y
+
+/*
+** There are two ways to use this macro. To arrange for pWal->apWiData[iPg]
+** to be set to pValue if an exception is thrown:
+**
+** SEH_SET_ON_ERROR(iPg, pValue);
+**
+** and to cancel the same:
+**
+** SEH_SET_ON_ERROR(0, 0);
+*/
+#define SEH_SET_ON_ERROR(X,Y) pWal->iWiPg = X; pWal->pWiValue = Y
+
+#else
+# define SEH_TRY VVA_ONLY(pWal->nSehTry++);
+# define SEH_EXCEPT(X) VVA_ONLY(pWal->nSehTry--); assert( pWal->nSehTry==0 );
+# define SEH_INJECT_FAULT assert( pWal->nSehTry>0 );
+# define SEH_FREE_ON_ERROR(X,Y)
+# define SEH_SET_ON_ERROR(X,Y)
+#endif /* ifdef SQLITE_USE_SEH */
+
+
+/*
** Obtain a pointer to the iPage'th page of the wal-index. The wal-index
** is broken into pages of WALINDEX_PGSZ bytes. Wal-index pages are
** numbered from zero.
@@ -63897,6 +65368,7 @@ static int walIndexPage(
int iPage, /* The page we seek */
volatile u32 **ppPage /* Write the page pointer here */
){
+ SEH_INJECT_FAULT;
if( pWal->nWiData<=iPage || (*ppPage = pWal->apWiData[iPage])==0 ){
return walIndexPageRealloc(pWal, iPage, ppPage);
}
@@ -63908,6 +65380,7 @@ static int walIndexPage(
*/
static volatile WalCkptInfo *walCkptInfo(Wal *pWal){
assert( pWal->nWiData>0 && pWal->apWiData[0] );
+ SEH_INJECT_FAULT;
return (volatile WalCkptInfo*)&(pWal->apWiData[0][sizeof(WalIndexHdr)/2]);
}
@@ -63916,6 +65389,7 @@ static volatile WalCkptInfo *walCkptInfo(Wal *pWal){
*/
static volatile WalIndexHdr *walIndexHdr(Wal *pWal){
assert( pWal->nWiData>0 && pWal->apWiData[0] );
+ SEH_INJECT_FAULT;
return (volatile WalIndexHdr*)pWal->apWiData[0];
}
@@ -63961,19 +65435,40 @@ static void walChecksumBytes(
assert( nByte>=8 );
assert( (nByte&0x00000007)==0 );
assert( nByte<=65536 );
+ assert( nByte%4==0 );
- if( nativeCksum ){
+ if( !nativeCksum ){
do {
+ s1 += BYTESWAP32(aData[0]) + s2;
+ s2 += BYTESWAP32(aData[1]) + s1;
+ aData += 2;
+ }while( aData<aEnd );
+ }else if( nByte%64==0 ){
+ do {
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
s1 += *aData++ + s2;
s2 += *aData++ + s1;
}while( aData<aEnd );
}else{
do {
- s1 += BYTESWAP32(aData[0]) + s2;
- s2 += BYTESWAP32(aData[1]) + s1;
- aData += 2;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
}while( aData<aEnd );
}
+ assert( aData==aEnd );
aOut[0] = s1;
aOut[1] = s2;
@@ -64084,7 +65579,7 @@ static int walDecodeFrame(
return 0;
}
- /* A frame is only valid if the page number is creater than zero.
+ /* A frame is only valid if the page number is greater than zero.
*/
pgno = sqlite3Get4byte(&aFrame[0]);
if( pgno==0 ){
@@ -64092,7 +65587,7 @@ static int walDecodeFrame(
}
/* A frame is only valid if a checksum of the WAL header,
- ** all prior frams, the first 16 bytes of this frame-header,
+ ** all prior frames, the first 16 bytes of this frame-header,
** and the frame-data matches the checksum in the last 8
** bytes of this frame-header.
*/
@@ -64152,12 +65647,18 @@ static int walLockShared(Wal *pWal, int lockIdx){
WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
walLockName(lockIdx), rc ? "failed" : "ok"));
VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
+#ifdef SQLITE_USE_SEH
+ if( rc==SQLITE_OK ) pWal->lockMask |= (1 << lockIdx);
+#endif
return rc;
}
static void walUnlockShared(Wal *pWal, int lockIdx){
if( pWal->exclusiveMode ) return;
(void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED);
+#ifdef SQLITE_USE_SEH
+ pWal->lockMask &= ~(1 << lockIdx);
+#endif
WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx)));
}
static int walLockExclusive(Wal *pWal, int lockIdx, int n){
@@ -64168,12 +65669,20 @@ static int walLockExclusive(Wal *pWal, int lockIdx, int n){
WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
walLockName(lockIdx), n, rc ? "failed" : "ok"));
VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
+#ifdef SQLITE_USE_SEH
+ if( rc==SQLITE_OK ){
+ pWal->lockMask |= (((1<<n)-1) << (SQLITE_SHM_NLOCK+lockIdx));
+ }
+#endif
return rc;
}
static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
if( pWal->exclusiveMode ) return;
(void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE);
+#ifdef SQLITE_USE_SEH
+ pWal->lockMask &= ~(((1<<n)-1) << (SQLITE_SHM_NLOCK+lockIdx));
+#endif
WALTRACE(("WAL%p: release EXCLUSIVE-%s cnt=%d\n", pWal,
walLockName(lockIdx), n));
}
@@ -64265,6 +65774,7 @@ static int walFramePage(u32 iFrame){
*/
static u32 walFramePgno(Wal *pWal, u32 iFrame){
int iHash = walFramePage(iFrame);
+ SEH_INJECT_FAULT;
if( iHash==0 ){
return pWal->apWiData[0][WALINDEX_HDR_SIZE/sizeof(u32) + iFrame - 1];
}
@@ -64524,6 +66034,7 @@ static int walIndexRecover(Wal *pWal){
/* Malloc a buffer to read frames into. */
szFrame = szPage + WAL_FRAME_HDRSIZE;
aFrame = (u8 *)sqlite3_malloc64(szFrame + WALINDEX_PGSZ);
+ SEH_FREE_ON_ERROR(0, aFrame);
if( !aFrame ){
rc = SQLITE_NOMEM_BKPT;
goto recovery_error;
@@ -64542,6 +66053,7 @@ static int walIndexRecover(Wal *pWal){
rc = walIndexPage(pWal, iPg, (volatile u32**)&aShare);
assert( aShare!=0 || rc!=SQLITE_OK );
if( aShare==0 ) break;
+ SEH_SET_ON_ERROR(iPg, aShare);
pWal->apWiData[iPg] = aPrivate;
for(iFrame=iFirst; iFrame<=iLast; iFrame++){
@@ -64569,6 +66081,7 @@ static int walIndexRecover(Wal *pWal){
}
}
pWal->apWiData[iPg] = aShare;
+ SEH_SET_ON_ERROR(0,0);
nHdr = (iPg==0 ? WALINDEX_HDR_SIZE : 0);
nHdr32 = nHdr / sizeof(u32);
#ifndef SQLITE_SAFER_WALINDEX_RECOVERY
@@ -64599,9 +66112,11 @@ static int walIndexRecover(Wal *pWal){
}
}
#endif
+ SEH_INJECT_FAULT;
if( iFrame<=iLast ) break;
}
+ SEH_FREE_ON_ERROR(aFrame, 0);
sqlite3_free(aFrame);
}
@@ -64629,6 +66144,7 @@ finished:
}else{
pInfo->aReadMark[i] = READMARK_NOT_USED;
}
+ SEH_INJECT_FAULT;
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
}else if( rc!=SQLITE_BUSY ){
goto recovery_error;
@@ -64786,7 +66302,7 @@ SQLITE_PRIVATE int sqlite3WalOpen(
}
/*
-** Change the size to which the WAL file is trucated on each reset.
+** Change the size to which the WAL file is truncated on each reset.
*/
SQLITE_PRIVATE void sqlite3WalLimit(Wal *pWal, i64 iLimit){
if( pWal ) pWal->mxWalSize = iLimit;
@@ -65012,23 +66528,16 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
nByte = sizeof(WalIterator)
+ (nSegment-1)*sizeof(struct WalSegment)
+ iLast*sizeof(ht_slot);
- p = (WalIterator *)sqlite3_malloc64(nByte);
+ p = (WalIterator *)sqlite3_malloc64(nByte
+ + sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
+ );
if( !p ){
return SQLITE_NOMEM_BKPT;
}
memset(p, 0, nByte);
p->nSegment = nSegment;
-
- /* Allocate temporary space used by the merge-sort routine. This block
- ** of memory will be freed before this function returns.
- */
- aTmp = (ht_slot *)sqlite3_malloc64(
- sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
- );
- if( !aTmp ){
- rc = SQLITE_NOMEM_BKPT;
- }
-
+ aTmp = (ht_slot*)&(((u8*)p)[nByte]);
+ SEH_FREE_ON_ERROR(0, p);
for(i=walFramePage(nBackfill+1); rc==SQLITE_OK && i<nSegment; i++){
WalHashLoc sLoc;
@@ -65056,9 +66565,8 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
p->aSegment[i].aPgno = (u32 *)sLoc.aPgno;
}
}
- sqlite3_free(aTmp);
-
if( rc!=SQLITE_OK ){
+ SEH_FREE_ON_ERROR(p, 0);
walIteratorFree(p);
p = 0;
}
@@ -65067,6 +66575,19 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
}
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+
+
+/*
+** Attempt to enable blocking locks that block for nMs ms. Return 1 if
+** blocking locks are successfully enabled, or 0 otherwise.
+*/
+static int walEnableBlockingMs(Wal *pWal, int nMs){
+ int rc = sqlite3OsFileControl(
+ pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&nMs
+ );
+ return (rc==SQLITE_OK);
+}
+
/*
** Attempt to enable blocking locks. Blocking locks are enabled only if (a)
** they are supported by the VFS, and (b) the database handle is configured
@@ -65078,11 +66599,7 @@ static int walEnableBlocking(Wal *pWal){
if( pWal->db ){
int tmout = pWal->db->busyTimeout;
if( tmout ){
- int rc;
- rc = sqlite3OsFileControl(
- pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout
- );
- res = (rc==SQLITE_OK);
+ res = walEnableBlockingMs(pWal, tmout);
}
}
return res;
@@ -65131,20 +66648,10 @@ SQLITE_PRIVATE void sqlite3WalDb(Wal *pWal, sqlite3 *db){
pWal->db = db;
}
-/*
-** Take an exclusive WRITE lock. Blocking if so configured.
-*/
-static int walLockWriter(Wal *pWal){
- int rc;
- walEnableBlocking(pWal);
- rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
- walDisableBlocking(pWal);
- return rc;
-}
#else
# define walEnableBlocking(x) 0
# define walDisableBlocking(x)
-# define walLockWriter(pWal) walLockExclusive((pWal), WAL_WRITE_LOCK, 1)
+# define walEnableBlockingMs(pWal, ms) 0
# define sqlite3WalDb(pWal, db)
#endif /* ifdef SQLITE_ENABLE_SETLK_TIMEOUT */
@@ -65284,13 +66791,13 @@ static int walCheckpoint(
mxSafeFrame = pWal->hdr.mxFrame;
mxPage = pWal->hdr.nPage;
for(i=1; i<WAL_NREADER; i++){
- u32 y = AtomicLoad(pInfo->aReadMark+i);
+ u32 y = AtomicLoad(pInfo->aReadMark+i); SEH_INJECT_FAULT;
if( mxSafeFrame>y ){
assert( y<=pWal->hdr.mxFrame );
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
if( rc==SQLITE_OK ){
u32 iMark = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
- AtomicStore(pInfo->aReadMark+i, iMark);
+ AtomicStore(pInfo->aReadMark+i, iMark); SEH_INJECT_FAULT;
walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
}else if( rc==SQLITE_BUSY ){
mxSafeFrame = y;
@@ -65311,8 +66818,7 @@ static int walCheckpoint(
&& (rc = walBusyLock(pWal,xBusy,pBusyArg,WAL_READ_LOCK(0),1))==SQLITE_OK
){
u32 nBackfill = pInfo->nBackfill;
-
- pInfo->nBackfillAttempted = mxSafeFrame;
+ pInfo->nBackfillAttempted = mxSafeFrame; SEH_INJECT_FAULT;
/* Sync the WAL to disk */
rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags));
@@ -65343,6 +66849,7 @@ static int walCheckpoint(
while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
i64 iOffset;
assert( walFramePgno(pWal, iFrame)==iDbpage );
+ SEH_INJECT_FAULT;
if( AtomicLoad(&db->u1.isInterrupted) ){
rc = db->mallocFailed ? SQLITE_NOMEM_BKPT : SQLITE_INTERRUPT;
break;
@@ -65372,7 +66879,7 @@ static int walCheckpoint(
}
}
if( rc==SQLITE_OK ){
- AtomicStore(&pInfo->nBackfill, mxSafeFrame);
+ AtomicStore(&pInfo->nBackfill, mxSafeFrame); SEH_INJECT_FAULT;
}
}
@@ -65394,6 +66901,7 @@ static int walCheckpoint(
*/
if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
assert( pWal->writeLock );
+ SEH_INJECT_FAULT;
if( pInfo->nBackfill<pWal->hdr.mxFrame ){
rc = SQLITE_BUSY;
}else if( eMode>=SQLITE_CHECKPOINT_RESTART ){
@@ -65425,6 +66933,7 @@ static int walCheckpoint(
}
walcheckpoint_out:
+ SEH_FREE_ON_ERROR(pIter, 0);
walIteratorFree(pIter);
return rc;
}
@@ -65447,6 +66956,93 @@ static void walLimitSize(Wal *pWal, i64 nMax){
}
}
+#ifdef SQLITE_USE_SEH
+/*
+** This is the "standard" exception handler used in a few places to handle
+** an exception thrown by reading from the *-shm mapping after it has become
+** invalid in SQLITE_USE_SEH builds. It is used as follows:
+**
+** SEH_TRY { ... }
+** SEH_EXCEPT( rc = walHandleException(pWal); )
+**
+** This function does three things:
+**
+** 1) Determines the locks that should be held, based on the contents of
+** the Wal.readLock, Wal.writeLock and Wal.ckptLock variables. All other
+** held locks are assumed to be transient locks that would have been
+** released had the exception not been thrown and are dropped.
+**
+** 2) Frees the pointer at Wal.pFree, if any, using sqlite3_free().
+**
+** 3) Set pWal->apWiData[pWal->iWiPg] to pWal->pWiValue if not NULL
+**
+** 4) Returns SQLITE_IOERR.
+*/
+static int walHandleException(Wal *pWal){
+ if( pWal->exclusiveMode==0 ){
+ static const int S = 1;
+ static const int E = (1<<SQLITE_SHM_NLOCK);
+ int ii;
+ u32 mUnlock = pWal->lockMask & ~(
+ (pWal->readLock<0 ? 0 : (S << WAL_READ_LOCK(pWal->readLock)))
+ | (pWal->writeLock ? (E << WAL_WRITE_LOCK) : 0)
+ | (pWal->ckptLock ? (E << WAL_CKPT_LOCK) : 0)
+ );
+ for(ii=0; ii<SQLITE_SHM_NLOCK; ii++){
+ if( (S<<ii) & mUnlock ) walUnlockShared(pWal, ii);
+ if( (E<<ii) & mUnlock ) walUnlockExclusive(pWal, ii, 1);
+ }
+ }
+ sqlite3_free(pWal->pFree);
+ pWal->pFree = 0;
+ if( pWal->pWiValue ){
+ pWal->apWiData[pWal->iWiPg] = pWal->pWiValue;
+ pWal->pWiValue = 0;
+ }
+ return SQLITE_IOERR_IN_PAGE;
+}
+
+/*
+** Assert that the Wal.lockMask mask, which indicates the locks held
+** by the connenction, is consistent with the Wal.readLock, Wal.writeLock
+** and Wal.ckptLock variables. To be used as:
+**
+** assert( walAssertLockmask(pWal) );
+*/
+static int walAssertLockmask(Wal *pWal){
+ if( pWal->exclusiveMode==0 ){
+ static const int S = 1;
+ static const int E = (1<<SQLITE_SHM_NLOCK);
+ u32 mExpect = (
+ (pWal->readLock<0 ? 0 : (S << WAL_READ_LOCK(pWal->readLock)))
+ | (pWal->writeLock ? (E << WAL_WRITE_LOCK) : 0)
+ | (pWal->ckptLock ? (E << WAL_CKPT_LOCK) : 0)
+#ifdef SQLITE_ENABLE_SNAPSHOT
+ | (pWal->pSnapshot ? (pWal->lockMask & (1 << WAL_CKPT_LOCK)) : 0)
+#endif
+ );
+ assert( mExpect==pWal->lockMask );
+ }
+ return 1;
+}
+
+/*
+** Return and zero the "system error" field set when an
+** EXCEPTION_IN_PAGE_ERROR exception is caught.
+*/
+SQLITE_PRIVATE int sqlite3WalSystemErrno(Wal *pWal){
+ int iRet = 0;
+ if( pWal ){
+ iRet = pWal->iSysErrno;
+ pWal->iSysErrno = 0;
+ }
+ return iRet;
+}
+
+#else
+# define walAssertLockmask(x) 1
+#endif /* ifdef SQLITE_USE_SEH */
+
/*
** Close a connection to a log file.
*/
@@ -65461,6 +67057,8 @@ SQLITE_PRIVATE int sqlite3WalClose(
if( pWal ){
int isDelete = 0; /* True to unlink wal and wal-index files */
+ assert( walAssertLockmask(pWal) );
+
/* If an EXCLUSIVE lock can be obtained on the database file (using the
** ordinary, rollback-mode locking methods, this guarantees that the
** connection associated with this log file is the only connection to
@@ -65485,7 +67083,7 @@ SQLITE_PRIVATE int sqlite3WalClose(
);
if( bPersist!=1 ){
/* Try to delete the WAL file if the checkpoint completed and
- ** fsyned (rc==SQLITE_OK) and if we are not in persistent-wal
+ ** fsynced (rc==SQLITE_OK) and if we are not in persistent-wal
** mode (!bPersist) */
isDelete = 1;
}else if( pWal->mxWalSize>=0 ){
@@ -65552,7 +67150,7 @@ static SQLITE_NO_TSAN int walIndexTryHdr(Wal *pWal, int *pChanged){
** give false-positive warnings about these accesses because the tools do not
** account for the double-read and the memory barrier. The use of mutexes
** here would be problematic as the memory being accessed is potentially
- ** shared among multiple processes and not all mutex implementions work
+ ** shared among multiple processes and not all mutex implementations work
** reliably in that environment.
*/
aHdr = walIndexHdr(pWal);
@@ -65654,7 +67252,9 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
}
}else{
int bWriteLock = pWal->writeLock;
- if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){
+ if( bWriteLock
+ || SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1))
+ ){
pWal->writeLock = 1;
if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
badHdr = walIndexTryHdr(pWal, pChanged);
@@ -65662,7 +67262,8 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
/* If the wal-index header is still malformed even while holding
** a WRITE lock, it can only mean that the header is corrupted and
** needs to be reconstructed. So run recovery to do exactly that.
- */
+ ** Disable blocking locks first. */
+ walDisableBlocking(pWal);
rc = walIndexRecover(pWal);
*pChanged = 1;
}
@@ -65873,6 +67474,37 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){
}
/*
+** The final argument passed to walTryBeginRead() is of type (int*). The
+** caller should invoke walTryBeginRead as follows:
+**
+** int cnt = 0;
+** do {
+** rc = walTryBeginRead(..., &cnt);
+** }while( rc==WAL_RETRY );
+**
+** The final value of "cnt" is of no use to the caller. It is used by
+** the implementation of walTryBeginRead() as follows:
+**
+** + Each time walTryBeginRead() is called, it is incremented. Once
+** it reaches WAL_RETRY_PROTOCOL_LIMIT - indicating that walTryBeginRead()
+** has many times been invoked and failed with WAL_RETRY - walTryBeginRead()
+** returns SQLITE_PROTOCOL.
+**
+** + If SQLITE_ENABLE_SETLK_TIMEOUT is defined and walTryBeginRead() failed
+** because a blocking lock timed out (SQLITE_BUSY_TIMEOUT from the OS
+** layer), the WAL_RETRY_BLOCKED_MASK bit is set in "cnt". In this case
+** the next invocation of walTryBeginRead() may omit an expected call to
+** sqlite3OsSleep(). There has already been a delay when the previous call
+** waited on a lock.
+*/
+#define WAL_RETRY_PROTOCOL_LIMIT 100
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+# define WAL_RETRY_BLOCKED_MASK 0x10000000
+#else
+# define WAL_RETRY_BLOCKED_MASK 0
+#endif
+
+/*
** Attempt to start a read transaction. This might fail due to a race or
** other transient condition. When that happens, it returns WAL_RETRY to
** indicate to the caller that it is safe to retry immediately.
@@ -65922,13 +67554,16 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){
** so it takes care to hold an exclusive lock on the corresponding
** WAL_READ_LOCK() while changing values.
*/
-static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
+static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int *pCnt){
volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */
u32 mxReadMark; /* Largest aReadMark[] value */
int mxI; /* Index of largest aReadMark[] value */
int i; /* Loop counter */
int rc = SQLITE_OK; /* Return code */
u32 mxFrame; /* Wal frame to lock to */
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ int nBlockTmout = 0;
+#endif
assert( pWal->readLock<0 ); /* Not currently locked */
@@ -65952,14 +67587,34 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
** so that on the 100th (and last) RETRY we delay for 323 milliseconds.
** The total delay time before giving up is less than 10 seconds.
*/
- if( cnt>5 ){
+ (*pCnt)++;
+ if( *pCnt>5 ){
int nDelay = 1; /* Pause time in microseconds */
- if( cnt>100 ){
+ int cnt = (*pCnt & ~WAL_RETRY_BLOCKED_MASK);
+ if( cnt>WAL_RETRY_PROTOCOL_LIMIT ){
VVA_ONLY( pWal->lockError = 1; )
return SQLITE_PROTOCOL;
}
- if( cnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39;
+ if( *pCnt>=10 ) nDelay = (cnt-9)*(cnt-9)*39;
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ /* In SQLITE_ENABLE_SETLK_TIMEOUT builds, configure the file-descriptor
+ ** to block for locks for approximately nDelay us. This affects three
+ ** locks: (a) the shared lock taken on the DMS slot in os_unix.c (if
+ ** using os_unix.c), (b) the WRITER lock taken in walIndexReadHdr() if the
+ ** first attempted read fails, and (c) the shared lock taken on the
+ ** read-mark.
+ **
+ ** If the previous call failed due to an SQLITE_BUSY_TIMEOUT error,
+ ** then sleep for the minimum of 1us. The previous call already provided
+ ** an extra delay while it was blocking on the lock.
+ */
+ nBlockTmout = (nDelay+998) / 1000;
+ if( !useWal && walEnableBlockingMs(pWal, nBlockTmout) ){
+ if( *pCnt & WAL_RETRY_BLOCKED_MASK ) nDelay = 1;
+ }
+#endif
sqlite3OsSleep(pWal->pVfs, nDelay);
+ *pCnt &= ~WAL_RETRY_BLOCKED_MASK;
}
if( !useWal ){
@@ -65967,6 +67622,13 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
if( pWal->bShmUnreliable==0 ){
rc = walIndexReadHdr(pWal, pChanged);
}
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ walDisableBlocking(pWal);
+ if( rc==SQLITE_BUSY_TIMEOUT ){
+ rc = SQLITE_BUSY;
+ *pCnt |= WAL_RETRY_BLOCKED_MASK;
+ }
+#endif
if( rc==SQLITE_BUSY ){
/* If there is not a recovery running in another thread or process
** then convert BUSY errors to WAL_RETRY. If recovery is known to
@@ -66003,6 +67665,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
assert( pWal->nWiData>0 );
assert( pWal->apWiData[0]!=0 );
pInfo = walCkptInfo(pWal);
+ SEH_INJECT_FAULT;
if( !useWal && AtomicLoad(&pInfo->nBackfill)==pWal->hdr.mxFrame
#ifdef SQLITE_ENABLE_SNAPSHOT
&& (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
@@ -66052,7 +67715,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
}
#endif
for(i=1; i<WAL_NREADER; i++){
- u32 thisMark = AtomicLoad(pInfo->aReadMark+i);
+ u32 thisMark = AtomicLoad(pInfo->aReadMark+i); SEH_INJECT_FAULT;
if( mxReadMark<=thisMark && thisMark<=mxFrame ){
assert( thisMark!=READMARK_NOT_USED );
mxReadMark = thisMark;
@@ -66080,9 +67743,19 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTINIT;
}
+ (void)walEnableBlockingMs(pWal, nBlockTmout);
rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
+ walDisableBlocking(pWal);
if( rc ){
- return rc==SQLITE_BUSY ? WAL_RETRY : rc;
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+ if( rc==SQLITE_BUSY_TIMEOUT ){
+ *pCnt |= WAL_RETRY_BLOCKED_MASK;
+ }
+#else
+ assert( rc!=SQLITE_BUSY_TIMEOUT );
+#endif
+ assert( (rc&0xFF)!=SQLITE_BUSY||rc==SQLITE_BUSY||rc==SQLITE_BUSY_TIMEOUT );
+ return (rc&0xFF)==SQLITE_BUSY ? WAL_RETRY : rc;
}
/* Now that the read-lock has been obtained, check that neither the
** value in the aReadMark[] array or the contents of the wal-index
@@ -66118,7 +67791,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
** we can guarantee that the checkpointer that set nBackfill could not
** see any pages past pWal->hdr.mxFrame, this problem does not come up.
*/
- pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1;
+ pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1; SEH_INJECT_FAULT;
walShmBarrier(pWal);
if( AtomicLoad(pInfo->aReadMark+mxI)!=mxReadMark
|| memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
@@ -66134,6 +67807,54 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
#ifdef SQLITE_ENABLE_SNAPSHOT
/*
+** This function does the work of sqlite3WalSnapshotRecover().
+*/
+static int walSnapshotRecover(
+ Wal *pWal, /* WAL handle */
+ void *pBuf1, /* Temp buffer pWal->szPage bytes in size */
+ void *pBuf2 /* Temp buffer pWal->szPage bytes in size */
+){
+ int szPage = (int)pWal->szPage;
+ int rc;
+ i64 szDb; /* Size of db file in bytes */
+
+ rc = sqlite3OsFileSize(pWal->pDbFd, &szDb);
+ if( rc==SQLITE_OK ){
+ volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
+ u32 i = pInfo->nBackfillAttempted;
+ for(i=pInfo->nBackfillAttempted; i>AtomicLoad(&pInfo->nBackfill); i--){
+ WalHashLoc sLoc; /* Hash table location */
+ u32 pgno; /* Page number in db file */
+ i64 iDbOff; /* Offset of db file entry */
+ i64 iWalOff; /* Offset of wal file entry */
+
+ rc = walHashGet(pWal, walFramePage(i), &sLoc);
+ if( rc!=SQLITE_OK ) break;
+ assert( i - sLoc.iZero - 1 >=0 );
+ pgno = sLoc.aPgno[i-sLoc.iZero-1];
+ 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;
+ }
+ }
+
+ return rc;
+}
+
+/*
** 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),
@@ -66158,50 +67879,21 @@ SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){
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>AtomicLoad(&pInfo->nBackfill); i--){
- WalHashLoc sLoc; /* Hash table location */
- u32 pgno; /* Page number in db file */
- i64 iDbOff; /* Offset of db file entry */
- i64 iWalOff; /* Offset of wal file entry */
-
- rc = walHashGet(pWal, walFramePage(i), &sLoc);
- if( rc!=SQLITE_OK ) break;
- assert( i - sLoc.iZero - 1 >=0 );
- pgno = sLoc.aPgno[i-sLoc.iZero-1];
- 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;
- }
+ void *pBuf1 = sqlite3_malloc(pWal->szPage);
+ void *pBuf2 = sqlite3_malloc(pWal->szPage);
+ if( pBuf1==0 || pBuf2==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ pWal->ckptLock = 1;
+ SEH_TRY {
+ rc = walSnapshotRecover(pWal, pBuf1, pBuf2);
}
-
- sqlite3_free(pBuf1);
- sqlite3_free(pBuf2);
+ SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
+ pWal->ckptLock = 0;
}
+
+ sqlite3_free(pBuf1);
+ sqlite3_free(pBuf2);
walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
}
@@ -66210,28 +67902,20 @@ SQLITE_PRIVATE int sqlite3WalSnapshotRecover(Wal *pWal){
#endif /* SQLITE_ENABLE_SNAPSHOT */
/*
-** Begin a read transaction on the database.
-**
-** This routine used to be called sqlite3OpenSnapshot() and with good reason:
-** it takes a snapshot of the state of the WAL and wal-index for the current
-** instant in time. The current thread will continue to use this snapshot.
-** Other threads might append new content to the WAL and wal-index but
-** that extra content is ignored by the current thread.
-**
-** If the database contents have changes since the previous read
-** transaction, then *pChanged is set to 1 before returning. The
-** Pager layer will use this to know that its cache is stale and
-** needs to be flushed.
+** This function does the work of sqlite3WalBeginReadTransaction() (see
+** below). That function simply calls this one inside an SEH_TRY{...} block.
*/
-SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
+static int walBeginReadTransaction(Wal *pWal, int *pChanged){
int rc; /* Return code */
int cnt = 0; /* Number of TryBeginRead attempts */
#ifdef SQLITE_ENABLE_SNAPSHOT
+ int ckptLock = 0;
int bChanged = 0;
WalIndexHdr *pSnapshot = pWal->pSnapshot;
#endif
assert( pWal->ckptLock==0 );
+ assert( pWal->nSehTry>0 );
#ifdef SQLITE_ENABLE_SNAPSHOT
if( pSnapshot ){
@@ -66254,12 +67938,12 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
if( rc!=SQLITE_OK ){
return rc;
}
- pWal->ckptLock = 1;
+ ckptLock = 1;
}
#endif
do{
- rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
+ rc = walTryBeginRead(pWal, pChanged, 0, &cnt);
}while( rc==WAL_RETRY );
testcase( (rc&0xff)==SQLITE_BUSY );
testcase( (rc&0xff)==SQLITE_IOERR );
@@ -66318,16 +68002,38 @@ SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
}
/* Release the shared CKPT lock obtained above. */
- if( pWal->ckptLock ){
+ if( ckptLock ){
assert( pSnapshot );
walUnlockShared(pWal, WAL_CKPT_LOCK);
- pWal->ckptLock = 0;
}
#endif
return rc;
}
/*
+** Begin a read transaction on the database.
+**
+** This routine used to be called sqlite3OpenSnapshot() and with good reason:
+** it takes a snapshot of the state of the WAL and wal-index for the current
+** instant in time. The current thread will continue to use this snapshot.
+** Other threads might append new content to the WAL and wal-index but
+** that extra content is ignored by the current thread.
+**
+** If the database contents have changes since the previous read
+** transaction, then *pChanged is set to 1 before returning. The
+** Pager layer will use this to know that its cache is stale and
+** needs to be flushed.
+*/
+SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
+ int rc;
+ SEH_TRY {
+ rc = walBeginReadTransaction(pWal, pChanged);
+ }
+ SEH_EXCEPT( rc = walHandleException(pWal); )
+ return rc;
+}
+
+/*
** Finish with a read transaction. All this does is release the
** read-lock.
*/
@@ -66347,7 +68053,7 @@ SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){
** Return SQLITE_OK if successful, or an error code if an error occurs. If an
** error does occur, the final value of *piRead is undefined.
*/
-SQLITE_PRIVATE int sqlite3WalFindFrame(
+static int walFindFrame(
Wal *pWal, /* WAL handle */
Pgno pgno, /* Database page number to read data for */
u32 *piRead /* OUT: Frame number (or zero) */
@@ -66410,6 +68116,7 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
}
nCollide = HASHTABLE_NSLOT;
iKey = walHash(pgno);
+ SEH_INJECT_FAULT;
while( (iH = AtomicLoad(&sLoc.aHash[iKey]))!=0 ){
u32 iFrame = iH + sLoc.iZero;
if( iFrame<=iLast && iFrame>=pWal->minFrame && sLoc.aPgno[iH-1]==pgno ){
@@ -66417,6 +68124,7 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
iRead = iFrame;
}
if( (nCollide--)==0 ){
+ *piRead = 0;
return SQLITE_CORRUPT_BKPT;
}
iKey = walNextHash(iKey);
@@ -66447,6 +68155,30 @@ SQLITE_PRIVATE int sqlite3WalFindFrame(
}
/*
+** Search the wal file for page pgno. If found, set *piRead to the frame that
+** contains the page. Otherwise, if pgno is not in the wal file, set *piRead
+** to zero.
+**
+** Return SQLITE_OK if successful, or an error code if an error occurs. If an
+** error does occur, the final value of *piRead is undefined.
+**
+** The difference between this function and walFindFrame() is that this
+** function wraps walFindFrame() in an SEH_TRY{...} block.
+*/
+SQLITE_PRIVATE int sqlite3WalFindFrame(
+ Wal *pWal, /* WAL handle */
+ Pgno pgno, /* Database page number to read data for */
+ u32 *piRead /* OUT: Frame number (or zero) */
+){
+ int rc;
+ SEH_TRY {
+ rc = walFindFrame(pWal, pgno, piRead);
+ }
+ SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
+ return rc;
+}
+
+/*
** Read the contents of frame iRead from the wal file into buffer pOut
** (which is nOut bytes in size). Return SQLITE_OK if successful, or an
** error code otherwise.
@@ -66527,12 +68259,17 @@ SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
** time the read transaction on this connection was started, then
** the write is disallowed.
*/
- if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
+ SEH_TRY {
+ if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
+ rc = SQLITE_BUSY_SNAPSHOT;
+ }
+ }
+ SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
+
+ if( rc!=SQLITE_OK ){
walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
pWal->writeLock = 0;
- rc = SQLITE_BUSY_SNAPSHOT;
}
-
return rc;
}
@@ -66568,30 +68305,33 @@ SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *p
Pgno iMax = pWal->hdr.mxFrame;
Pgno iFrame;
- /* Restore the clients cache of the wal-index header to the state it
- ** was in before the client began writing to the database.
- */
- memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr));
-
- for(iFrame=pWal->hdr.mxFrame+1;
- ALWAYS(rc==SQLITE_OK) && iFrame<=iMax;
- iFrame++
- ){
- /* This call cannot fail. Unless the page for which the page number
- ** is passed as the second argument is (a) in the cache and
- ** (b) has an outstanding reference, then xUndo is either a no-op
- ** (if (a) is false) or simply expels the page from the cache (if (b)
- ** is false).
- **
- ** If the upper layer is doing a rollback, it is guaranteed that there
- ** are no outstanding references to any page other than page 1. And
- ** page 1 is never written to the log until the transaction is
- ** committed. As a result, the call to xUndo may not fail.
+ SEH_TRY {
+ /* Restore the clients cache of the wal-index header to the state it
+ ** was in before the client began writing to the database.
*/
- assert( walFramePgno(pWal, iFrame)!=1 );
- rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
+ memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr));
+
+ for(iFrame=pWal->hdr.mxFrame+1;
+ ALWAYS(rc==SQLITE_OK) && iFrame<=iMax;
+ iFrame++
+ ){
+ /* This call cannot fail. Unless the page for which the page number
+ ** is passed as the second argument is (a) in the cache and
+ ** (b) has an outstanding reference, then xUndo is either a no-op
+ ** (if (a) is false) or simply expels the page from the cache (if (b)
+ ** is false).
+ **
+ ** If the upper layer is doing a rollback, it is guaranteed that there
+ ** are no outstanding references to any page other than page 1. And
+ ** page 1 is never written to the log until the transaction is
+ ** committed. As a result, the call to xUndo may not fail.
+ */
+ assert( walFramePgno(pWal, iFrame)!=1 );
+ rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
+ }
+ if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
}
- if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
+ SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
}
return rc;
}
@@ -66635,7 +68375,10 @@ SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
pWal->hdr.mxFrame = aWalData[0];
pWal->hdr.aFrameCksum[0] = aWalData[1];
pWal->hdr.aFrameCksum[1] = aWalData[2];
- walCleanupHash(pWal);
+ SEH_TRY {
+ walCleanupHash(pWal);
+ }
+ SEH_EXCEPT( rc = SQLITE_IOERR_IN_PAGE; )
}
return rc;
@@ -66685,7 +68428,7 @@ static int walRestartLog(Wal *pWal){
cnt = 0;
do{
int notUsed;
- rc = walTryBeginRead(pWal, &notUsed, 1, ++cnt);
+ rc = walTryBeginRead(pWal, &notUsed, 1, &cnt);
}while( rc==WAL_RETRY );
assert( (rc&0xff)!=SQLITE_BUSY ); /* BUSY not possible when useWal==1 */
testcase( (rc&0xff)==SQLITE_IOERR );
@@ -66816,7 +68559,7 @@ static int walRewriteChecksums(Wal *pWal, u32 iLast){
** Write a set of frames to the log. The caller must hold the write-lock
** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
*/
-SQLITE_PRIVATE int sqlite3WalFrames(
+static int walFrames(
Wal *pWal, /* Wal handle to write to */
int szPage, /* Database page-size in bytes */
PgHdr *pList, /* List of dirty pages to write */
@@ -66904,7 +68647,9 @@ SQLITE_PRIVATE int sqlite3WalFrames(
if( rc ) return rc;
}
}
- assert( (int)pWal->szPage==szPage );
+ if( (int)pWal->szPage!=szPage ){
+ return SQLITE_CORRUPT_BKPT; /* TH3 test case: cov1/corrupt155.test */
+ }
/* Setup information needed to write frames into the WAL */
w.pWal = pWal;
@@ -66925,7 +68670,7 @@ SQLITE_PRIVATE int sqlite3WalFrames(
** checksums must be recomputed when the transaction is committed. */
if( iFirst && (p->pDirty || isCommit==0) ){
u32 iWrite = 0;
- VVA_ONLY(rc =) sqlite3WalFindFrame(pWal, p->pgno, &iWrite);
+ VVA_ONLY(rc =) walFindFrame(pWal, p->pgno, &iWrite);
assert( rc==SQLITE_OK || iWrite==0 );
if( iWrite>=iFirst ){
i64 iOff = walFrameOffset(iWrite, szPage) + WAL_FRAME_HDRSIZE;
@@ -67045,6 +68790,29 @@ SQLITE_PRIVATE int sqlite3WalFrames(
}
/*
+** Write a set of frames to the log. The caller must hold the write-lock
+** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
+**
+** The difference between this function and walFrames() is that this
+** function wraps walFrames() in an SEH_TRY{...} block.
+*/
+SQLITE_PRIVATE int sqlite3WalFrames(
+ Wal *pWal, /* Wal handle to write to */
+ int szPage, /* Database page-size in bytes */
+ PgHdr *pList, /* List of dirty pages to write */
+ Pgno nTruncate, /* Database size after this commit */
+ int isCommit, /* True if this is a commit */
+ int sync_flags /* Flags to pass to OsSync() (or 0) */
+){
+ int rc;
+ SEH_TRY {
+ rc = walFrames(pWal, szPage, pList, nTruncate, isCommit, sync_flags);
+ }
+ SEH_EXCEPT( rc = walHandleException(pWal); )
+ return rc;
+}
+
+/*
** This routine is called to implement sqlite3_wal_checkpoint() and
** related interfaces.
**
@@ -67081,10 +68849,9 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
if( pWal->readOnly ) return SQLITE_READONLY;
WALTRACE(("WAL%p: checkpoint begins\n", pWal));
- /* Enable blocking locks, if possible. If blocking locks are successfully
- ** enabled, set xBusy2=0 so that the busy-handler is never invoked. */
+ /* Enable blocking locks, if possible. */
sqlite3WalDb(pWal, db);
- (void)walEnableBlocking(pWal);
+ if( xBusy2 ) (void)walEnableBlocking(pWal);
/* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
** "checkpoint" lock on the database file.
@@ -67123,30 +68890,38 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint(
/* Read the wal-index header. */
- if( rc==SQLITE_OK ){
- walDisableBlocking(pWal);
- rc = walIndexReadHdr(pWal, &isChanged);
- (void)walEnableBlocking(pWal);
- if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
- sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
+ SEH_TRY {
+ if( rc==SQLITE_OK ){
+ /* For a passive checkpoint, do not re-enable blocking locks after
+ ** reading the wal-index header. A passive checkpoint should not block
+ ** or invoke the busy handler. The only lock such a checkpoint may
+ ** attempt to obtain is a lock on a read-slot, and it should give up
+ ** immediately and do a partial checkpoint if it cannot obtain it. */
+ walDisableBlocking(pWal);
+ rc = walIndexReadHdr(pWal, &isChanged);
+ if( eMode2!=SQLITE_CHECKPOINT_PASSIVE ) (void)walEnableBlocking(pWal);
+ if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
+ sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
+ }
}
- }
- /* Copy data from the log to the database file. */
- if( rc==SQLITE_OK ){
-
- if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
- rc = SQLITE_CORRUPT_BKPT;
- }else{
- rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags, zBuf);
- }
+ /* Copy data from the log to the database file. */
+ if( rc==SQLITE_OK ){
+ if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
+ rc = SQLITE_CORRUPT_BKPT;
+ }else{
+ rc = walCheckpoint(pWal, db, eMode2, xBusy2, pBusyArg, sync_flags,zBuf);
+ }
- /* If no error occurred, set the output variables. */
- if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
- if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
- if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
+ /* If no error occurred, set the output variables. */
+ if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
+ if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
+ SEH_INJECT_FAULT;
+ if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
+ }
}
}
+ SEH_EXCEPT( rc = walHandleException(pWal); )
if( isChanged ){
/* If a new wal-index header was loaded before the checkpoint was
@@ -67223,7 +68998,9 @@ SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
** locks are taken in this case). Nor should the pager attempt to
** upgrade to exclusive-mode following such an error.
*/
+#ifndef SQLITE_USE_SEH
assert( pWal->readLock>=0 || pWal->lockError );
+#endif
assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
if( op==0 ){
@@ -67324,16 +69101,19 @@ SQLITE_API int sqlite3_snapshot_cmp(sqlite3_snapshot *p1, sqlite3_snapshot *p2){
*/
SQLITE_PRIVATE int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot){
int rc;
- rc = walLockShared(pWal, WAL_CKPT_LOCK);
- if( rc==SQLITE_OK ){
- WalIndexHdr *pNew = (WalIndexHdr*)pSnapshot;
- if( memcmp(pNew->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
- || pNew->mxFrame<walCkptInfo(pWal)->nBackfillAttempted
- ){
- rc = SQLITE_ERROR_SNAPSHOT;
- walUnlockShared(pWal, WAL_CKPT_LOCK);
+ SEH_TRY {
+ rc = walLockShared(pWal, WAL_CKPT_LOCK);
+ if( rc==SQLITE_OK ){
+ WalIndexHdr *pNew = (WalIndexHdr*)pSnapshot;
+ if( memcmp(pNew->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
+ || pNew->mxFrame<walCkptInfo(pWal)->nBackfillAttempted
+ ){
+ rc = SQLITE_ERROR_SNAPSHOT;
+ walUnlockShared(pWal, WAL_CKPT_LOCK);
+ }
}
}
+ SEH_EXCEPT( rc = walHandleException(pWal); )
return rc;
}
@@ -67456,7 +69236,7 @@ SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){
** 22 1 Min embedded payload fraction (must be 32)
** 23 1 Min leaf payload fraction (must be 32)
** 24 4 File change counter
-** 28 4 Reserved for future use
+** 28 4 The size of the database in pages
** 32 4 First freelist page
** 36 4 Number of freelist pages in the file
** 40 60 15 4-byte meta values passed to higher layers
@@ -67564,7 +69344,7 @@ SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){
** byte are used. The integer consists of all bytes that have bit 8 set and
** the first byte with bit 8 clear. The most significant byte of the integer
** appears first. A variable-length integer may not be more than 9 bytes long.
-** As a special case, all 8 bytes of the 9th byte are used as data. This
+** As a special case, all 8 bits of the 9th byte are used as data. This
** allows a 64-bit integer to be encoded in 9 bytes.
**
** 0x00 becomes 0x00000000
@@ -67572,7 +69352,7 @@ SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){
** 0x81 0x00 becomes 0x00000080
** 0x82 0x00 becomes 0x00000100
** 0x80 0x7f becomes 0x0000007f
-** 0x8a 0x91 0xd1 0xac 0x78 becomes 0x12345678
+** 0x81 0x91 0xd1 0xac 0x78 becomes 0x12345678
** 0x81 0x81 0x81 0x81 0x01 becomes 0x10204081
**
** Variable length integers are used for rowids and to hold the number of
@@ -67655,7 +69435,7 @@ typedef struct CellInfo CellInfo;
** page that has been loaded into memory. The information in this object
** is derived from the raw on-disk page content.
**
-** As each database page is loaded into memory, the pager allocats an
+** As each database page is loaded into memory, the pager allocates an
** instance of this object and zeros the first 8 bytes. (This is the
** "extra" information associated with each page of the pager.)
**
@@ -67948,7 +69728,7 @@ struct BtCursor {
#define BTCF_WriteFlag 0x01 /* True if a write cursor */
#define BTCF_ValidNKey 0x02 /* True if info.nKey is valid */
#define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */
-#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */
+#define BTCF_AtLast 0x08 /* Cursor is pointing to the last entry */
#define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */
#define BTCF_Multiple 0x20 /* Maybe another cursor on the same btree */
#define BTCF_Pinned 0x40 /* Cursor is busy and cannot be moved */
@@ -68087,14 +69867,15 @@ struct IntegrityCk {
BtShared *pBt; /* The tree being checked out */
Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
u8 *aPgRef; /* 1 bit per page in the db (see above) */
- Pgno nPage; /* Number of pages in the database */
+ Pgno nCkPage; /* Pages in the database. 0 for partial check */
int mxErr; /* Stop accumulating errors when this reaches zero */
int nErr; /* Number of messages written to zErrMsg so far */
int rc; /* SQLITE_OK, SQLITE_NOMEM, or SQLITE_INTERRUPT */
u32 nStep; /* Number of steps into the integrity_check process */
const char *zPfx; /* Error message prefix */
- Pgno v1; /* Value for first %u substitution in zPfx */
- int v2; /* Value for second %d substitution in zPfx */
+ Pgno v0; /* Value for first %u substitution in zPfx (root page) */
+ Pgno v1; /* Value for second %u substitution in zPfx (current pg) */
+ int v2; /* Value for third %d substitution in zPfx */
StrAccum errMsg; /* Accumulate the error message text here */
u32 *heap; /* Min-heap used for analyzing cell coverage */
sqlite3 *db; /* Database connection running the check */
@@ -68110,7 +69891,7 @@ struct IntegrityCk {
/*
** get2byteAligned(), unlike get2byte(), requires that its argument point to a
-** two-byte aligned address. get2bytea() is only used for accessing the
+** two-byte aligned address. get2byteAligned() is only used for accessing the
** cell addresses in a btree header.
*/
#if SQLITE_BYTEORDER==4321
@@ -68287,7 +70068,7 @@ SQLITE_PRIVATE int sqlite3BtreeHoldsMutex(Btree *p){
**
** There is a corresponding leave-all procedures.
**
-** Enter the mutexes in accending order by BtShared pointer address
+** Enter the mutexes in ascending order by BtShared pointer address
** to avoid the possibility of deadlock when two threads with
** two or more btrees in common both try to lock all their btrees
** at the same instant.
@@ -68557,8 +70338,8 @@ SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){
int corruptPageError(int lineno, MemPage *p){
char *zMsg;
sqlite3BeginBenignMalloc();
- zMsg = sqlite3_mprintf("database corruption page %d of %s",
- (int)p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0)
+ zMsg = sqlite3_mprintf("database corruption page %u of %s",
+ p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0)
);
sqlite3EndBenignMalloc();
if( zMsg ){
@@ -69367,8 +71148,25 @@ SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow)
*/
SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor *pCur, int eHintType, ...){
/* Used only by system that substitute their own storage engine */
+#ifdef SQLITE_DEBUG
+ if( ALWAYS(eHintType==BTREE_HINT_RANGE) ){
+ va_list ap;
+ Expr *pExpr;
+ Walker w;
+ memset(&w, 0, sizeof(w));
+ w.xExprCallback = sqlite3CursorRangeHintExprCheck;
+ va_start(ap, eHintType);
+ pExpr = va_arg(ap, Expr*);
+ w.u.aMem = va_arg(ap, Mem*);
+ va_end(ap);
+ assert( pExpr!=0 );
+ assert( w.u.aMem!=0 );
+ sqlite3WalkExpr(&w, pExpr);
+ }
+#endif /* SQLITE_DEBUG */
}
-#endif
+#endif /* SQLITE_ENABLE_CURSOR_HINTS */
+
/*
** Provide flag hints to the cursor.
@@ -69453,7 +71251,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage);
if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){
- TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent));
+ TRACE(("PTRMAP_UPDATE: %u->(%u,%u)\n", key, eType, parent));
*pRC= rc = sqlite3PagerWrite(pDbPage);
if( rc==SQLITE_OK ){
pPtrmap[offset] = eType;
@@ -69652,27 +71450,31 @@ static void btreeParseCellPtr(
iKey = *pIter;
if( iKey>=0x80 ){
u8 x;
- iKey = ((iKey&0x7f)<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x =*++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ 0x10204000 ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<8) | (*++pIter);
+ iKey = (iKey<<8) ^ 0x8000 ^ (*++pIter);
}
}
}
}
}
+ }else{
+ iKey ^= 0x204000;
}
+ }else{
+ iKey ^= 0x4000;
}
}
pIter++;
@@ -69749,10 +71551,53 @@ static void btreeParseCell(
**
** cellSizePtrNoPayload() => table internal nodes
** cellSizePtrTableLeaf() => table leaf nodes
-** cellSizePtr() => all index nodes & table leaf nodes
+** cellSizePtr() => index internal nodes
+** cellSizeIdxLeaf() => index leaf nodes
*/
static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
- u8 *pIter = pCell + pPage->childPtrSize; /* For looping over bytes of pCell */
+ u8 *pIter = pCell + 4; /* For looping over bytes of pCell */
+ u8 *pEnd; /* End mark for a varint */
+ u32 nSize; /* Size value to return */
+
+#ifdef SQLITE_DEBUG
+ /* The value returned by this function should always be the same as
+ ** the (CellInfo.nSize) value found by doing a full parse of the
+ ** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of
+ ** this function verifies that this invariant is not violated. */
+ CellInfo debuginfo;
+ pPage->xParseCell(pPage, pCell, &debuginfo);
+#endif
+
+ assert( pPage->childPtrSize==4 );
+ nSize = *pIter;
+ if( nSize>=0x80 ){
+ pEnd = &pIter[8];
+ nSize &= 0x7f;
+ do{
+ nSize = (nSize<<7) | (*++pIter & 0x7f);
+ }while( *(pIter)>=0x80 && pIter<pEnd );
+ }
+ pIter++;
+ testcase( nSize==pPage->maxLocal );
+ testcase( nSize==(u32)pPage->maxLocal+1 );
+ if( nSize<=pPage->maxLocal ){
+ nSize += (u32)(pIter - pCell);
+ assert( nSize>4 );
+ }else{
+ int minLocal = pPage->minLocal;
+ nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4);
+ testcase( nSize==pPage->maxLocal );
+ testcase( nSize==(u32)pPage->maxLocal+1 );
+ if( nSize>pPage->maxLocal ){
+ nSize = minLocal;
+ }
+ nSize += 4 + (u16)(pIter - pCell);
+ }
+ assert( nSize==debuginfo.nSize || CORRUPT_DB );
+ return (u16)nSize;
+}
+static u16 cellSizePtrIdxLeaf(MemPage *pPage, u8 *pCell){
+ u8 *pIter = pCell; /* For looping over bytes of pCell */
u8 *pEnd; /* End mark for a varint */
u32 nSize; /* Size value to return */
@@ -69765,6 +71610,7 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
pPage->xParseCell(pPage, pCell, &debuginfo);
#endif
+ assert( pPage->childPtrSize==0 );
nSize = *pIter;
if( nSize>=0x80 ){
pEnd = &pIter[8];
@@ -69889,7 +71735,7 @@ static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){
pPage->xParseCell(pPage, pCell, &info);
if( info.nLocal<info.nPayload ){
Pgno ovfl;
- if( SQLITE_WITHIN(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){
+ if( SQLITE_OVERFLOW(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){
testcase( pSrc!=pPage );
*pRC = SQLITE_CORRUPT_BKPT;
return;
@@ -69990,7 +71836,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
iCellStart = get2byte(&data[hdr+5]);
if( nCell>0 ){
temp = sqlite3PagerTempSpace(pPage->pBt->pPager);
- memcpy(&temp[iCellStart], &data[iCellStart], usableSize - iCellStart);
+ memcpy(temp, data, usableSize);
src = temp;
for(i=0; i<nCell; i++){
u8 *pAddr; /* The i-th cell pointer */
@@ -70001,10 +71847,10 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
/* These conditions have already been verified in btreeInitPage()
** if PRAGMA cell_size_check=ON.
*/
- if( pc<iCellStart || pc>iCellLast ){
+ if( pc>iCellLast ){
return SQLITE_CORRUPT_PAGE(pPage);
}
- assert( pc>=iCellStart && pc<=iCellLast );
+ assert( pc>=0 && pc<=iCellLast );
size = pPage->xCellSize(pPage, &src[pc]);
cbrk -= size;
if( cbrk<iCellStart || pc+size>usableSize ){
@@ -70119,7 +71965,7 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
** allocation is being made in order to insert a new cell, so we will
** also end up needing a new cell pointer.
*/
-static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
+static SQLITE_INLINE int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
const int hdr = pPage->hdrOffset; /* Local cache of pPage->hdrOffset */
u8 * const data = pPage->aData; /* Local cache of pPage->aData */
int top; /* First byte of cell content area */
@@ -70145,13 +71991,14 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
** integer, so a value of 0 is used in its place. */
pTmp = &data[hdr+5];
top = get2byte(pTmp);
- assert( top<=(int)pPage->pBt->usableSize ); /* by btreeComputeFreeSpace() */
if( gap>top ){
if( top==0 && pPage->pBt->usableSize==65536 ){
top = 65536;
}else{
return SQLITE_CORRUPT_PAGE(pPage);
}
+ }else if( top>(int)pPage->pBt->usableSize ){
+ return SQLITE_CORRUPT_PAGE(pPage);
}
/* If there is enough space between gap and top for one more cell pointer,
@@ -70213,7 +72060,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
**
** Even though the freeblock list was checked by btreeComputeFreeSpace(),
** that routine will not detect overlap between cells or freeblocks. Nor
-** does it detect cells or freeblocks that encrouch into the reserved bytes
+** does it detect cells or freeblocks that encroach into the reserved bytes
** at the end of the page. So do additional corruption checks inside this
** routine and return SQLITE_CORRUPT if any problems are found.
*/
@@ -70234,7 +72081,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( iSize>=4 ); /* Minimum cell size is 4 */
- assert( iStart<=pPage->pBt->usableSize-4 );
+ assert( CORRUPT_DB || iStart<=pPage->pBt->usableSize-4 );
/* The list of freeblocks must be in ascending order. Find the
** spot on the list where iStart should be inserted.
@@ -70291,6 +72138,11 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
}
pTmp = &data[hdr+5];
x = get2byte(pTmp);
+ if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
+ /* Overwrite deleted information with zeros when the secure_delete
+ ** option is enabled */
+ memset(&data[iStart], 0, iSize);
+ }
if( iStart<=x ){
/* The new freeblock is at the beginning of the cell content area,
** so just extend the cell content area rather than create another
@@ -70302,14 +72154,9 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
}else{
/* Insert the new freeblock into the freelist */
put2byte(&data[iPtr], iStart);
+ put2byte(&data[iStart], iFreeBlk);
+ put2byte(&data[iStart+2], iSize);
}
- if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
- /* Overwrite deleted information with zeros when the secure_delete
- ** option is enabled */
- memset(&data[iStart], 0, iSize);
- }
- put2byte(&data[iStart], iFreeBlk);
- put2byte(&data[iStart+2], iSize);
pPage->nFree += iOrigSize;
return SQLITE_OK;
}
@@ -70346,14 +72193,14 @@ static int decodeFlags(MemPage *pPage, int flagByte){
}else if( flagByte==(PTF_ZERODATA | PTF_LEAF) ){
pPage->intKey = 0;
pPage->intKeyLeaf = 0;
- pPage->xCellSize = cellSizePtr;
+ pPage->xCellSize = cellSizePtrIdxLeaf;
pPage->xParseCell = btreeParseCellPtrIndex;
pPage->maxLocal = pBt->maxLocal;
pPage->minLocal = pBt->minLocal;
}else{
pPage->intKey = 0;
pPage->intKeyLeaf = 0;
- pPage->xCellSize = cellSizePtr;
+ pPage->xCellSize = cellSizePtrIdxLeaf;
pPage->xParseCell = btreeParseCellPtrIndex;
return SQLITE_CORRUPT_PAGE(pPage);
}
@@ -70672,68 +72519,41 @@ SQLITE_PRIVATE Pgno sqlite3BtreeLastPage(Btree *p){
/*
** Get a page from the pager and initialize it.
-**
-** If pCur!=0 then the page is being fetched as part of a moveToChild()
-** call. Do additional sanity checking on the page in this case.
-** And if the fetch fails, this routine must decrement pCur->iPage.
-**
-** The page is fetched as read-write unless pCur is not NULL and is
-** a read-only cursor.
-**
-** If an error occurs, then *ppPage is undefined. It
-** may remain unchanged, or it may be set to an invalid value.
*/
static int getAndInitPage(
BtShared *pBt, /* The database file */
Pgno pgno, /* Number of the page to get */
MemPage **ppPage, /* Write the page pointer here */
- BtCursor *pCur, /* Cursor to receive the page, or NULL */
int bReadOnly /* True for a read-only page */
){
int rc;
DbPage *pDbPage;
+ MemPage *pPage;
assert( sqlite3_mutex_held(pBt->mutex) );
- assert( pCur==0 || ppPage==&pCur->pPage );
- assert( pCur==0 || bReadOnly==pCur->curPagerFlags );
- assert( pCur==0 || pCur->iPage>0 );
if( pgno>btreePagecount(pBt) ){
- rc = SQLITE_CORRUPT_BKPT;
- goto getAndInitPage_error1;
+ *ppPage = 0;
+ return SQLITE_CORRUPT_BKPT;
}
rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly);
if( rc ){
- goto getAndInitPage_error1;
+ *ppPage = 0;
+ return rc;
}
- *ppPage = (MemPage*)sqlite3PagerGetExtra(pDbPage);
- if( (*ppPage)->isInit==0 ){
+ pPage = (MemPage*)sqlite3PagerGetExtra(pDbPage);
+ if( pPage->isInit==0 ){
btreePageFromDbPage(pDbPage, pgno, pBt);
- rc = btreeInitPage(*ppPage);
+ rc = btreeInitPage(pPage);
if( rc!=SQLITE_OK ){
- goto getAndInitPage_error2;
+ releasePage(pPage);
+ *ppPage = 0;
+ return rc;
}
}
- assert( (*ppPage)->pgno==pgno || CORRUPT_DB );
- assert( (*ppPage)->aData==sqlite3PagerGetData(pDbPage) );
-
- /* If obtaining a child page for a cursor, we must verify that the page is
- ** compatible with the root page. */
- if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){
- rc = SQLITE_CORRUPT_PGNO(pgno);
- goto getAndInitPage_error2;
- }
+ assert( pPage->pgno==pgno || CORRUPT_DB );
+ assert( pPage->aData==sqlite3PagerGetData(pDbPage) );
+ *ppPage = pPage;
return SQLITE_OK;
-
-getAndInitPage_error2:
- releasePage(*ppPage);
-getAndInitPage_error1:
- if( pCur ){
- pCur->iPage--;
- pCur->pPage = pCur->apPage[pCur->iPage];
- }
- testcase( pgno==0 );
- assert( pgno!=0 || rc!=SQLITE_OK );
- return rc;
}
/*
@@ -70816,7 +72636,7 @@ static void pageReinit(DbPage *pData){
** call to btreeInitPage() will likely return SQLITE_CORRUPT.
** But no harm is done by this. And it is very important that
** btreeInitPage() be called on every btree page so we make
- ** the call for every page that comes in for re-initing. */
+ ** the call for every page that comes in for re-initializing. */
btreeInitPage(pPage);
}
}
@@ -70995,6 +72815,9 @@ SQLITE_PRIVATE int sqlite3BtreeOpen(
assert( sizeof(u16)==2 );
assert( sizeof(Pgno)==4 );
+ /* Suppress false-positive compiler warning from PVS-Studio */
+ memset(&zDbHeader[16], 0, 8);
+
pBt = sqlite3MallocZero( sizeof(*pBt) );
if( pBt==0 ){
rc = SQLITE_NOMEM_BKPT;
@@ -71211,7 +73034,7 @@ static SQLITE_NOINLINE int allocateTempSpace(BtShared *pBt){
** can mean that fillInCell() only initializes the first 2 or 3
** bytes of pTmpSpace, but that the first 4 bytes are copied from
** it into a database page. This is not actually a problem, but it
- ** does cause a valgrind error when the 1 or 2 bytes of unitialized
+ ** does cause a valgrind error when the 1 or 2 bytes of uninitialized
** data is passed to system call write(). So to avoid this error,
** zero the first 4 bytes of temp space here.
**
@@ -71446,7 +73269,7 @@ SQLITE_PRIVATE int sqlite3BtreeGetReserveNoMutex(Btree *p){
/*
** Return the number of bytes of space at the end of every page that
-** are intentually left unused. This is the "reserved" space that is
+** are intentionally left unused. This is the "reserved" space that is
** sometimes used by extensions.
**
** The value returned is the larger of the current reserve size and
@@ -71693,7 +73516,6 @@ static int lockBtree(BtShared *pBt){
){
goto page1_init_failed;
}
- pBt->btsFlags |= BTS_PAGESIZE_FIXED;
assert( (pageSize & 7)==0 );
/* EVIDENCE-OF: R-59310-51205 The "reserved space" size in the 1-byte
** integer at offset 20 is the number of bytes of space at the end of
@@ -71713,6 +73535,7 @@ static int lockBtree(BtShared *pBt){
releasePageOne(pPage1);
pBt->usableSize = usableSize;
pBt->pageSize = pageSize;
+ pBt->btsFlags |= BTS_PAGESIZE_FIXED;
freeTempSpace(pBt);
rc = sqlite3PagerSetPagesize(pBt->pPager, &pBt->pageSize,
pageSize-usableSize);
@@ -71732,6 +73555,7 @@ static int lockBtree(BtShared *pBt){
if( usableSize<480 ){
goto page1_init_failed;
}
+ pBt->btsFlags |= BTS_PAGESIZE_FIXED;
pBt->pageSize = pageSize;
pBt->usableSize = usableSize;
#ifndef SQLITE_OMIT_AUTOVACUUM
@@ -71910,7 +73734,11 @@ SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){
** when A already has a read lock, we encourage A to give up and let B
** proceed.
*/
-SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
+static SQLITE_NOINLINE int btreeBeginTrans(
+ Btree *p, /* The btree in which to start the transaction */
+ int wrflag, /* True to start a write transaction */
+ int *pSchemaVersion /* Put schema version number here, if not NULL */
+){
BtShared *pBt = p->pBt;
Pager *pPager = pBt->pPager;
int rc = SQLITE_OK;
@@ -72082,6 +73910,28 @@ trans_begun:
sqlite3BtreeLeave(p);
return rc;
}
+SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
+ BtShared *pBt;
+ if( p->sharable
+ || p->inTrans==TRANS_NONE
+ || (p->inTrans==TRANS_READ && wrflag!=0)
+ ){
+ return btreeBeginTrans(p,wrflag,pSchemaVersion);
+ }
+ pBt = p->pBt;
+ if( pSchemaVersion ){
+ *pSchemaVersion = get4byte(&pBt->pPage1->aData[40]);
+ }
+ if( wrflag ){
+ /* This call makes sure that the pager has the correct number of
+ ** open savepoints. If the second parameter is greater than 0 and
+ ** the sub-journal is not already open, then it will be opened here.
+ */
+ return sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint);
+ }else{
+ return SQLITE_OK;
+ }
+}
#ifndef SQLITE_OMIT_AUTOVACUUM
@@ -72219,7 +74069,7 @@ static int relocatePage(
if( iDbPage<3 ) return SQLITE_CORRUPT_BKPT;
/* Move page iDbPage from its current location to page number iFreePage */
- TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n",
+ TRACE(("AUTOVACUUM: Moving %u to free page %u (ptr page %u type %u)\n",
iDbPage, iFreePage, iPtrPage, eType));
rc = sqlite3PagerMovepage(pPager, pDbPage->pDbPage, iFreePage, isCommit);
if( rc!=SQLITE_OK ){
@@ -73177,7 +75027,6 @@ SQLITE_PRIVATE void sqlite3BtreeCursorUnpin(BtCursor *pCur){
pCur->curFlags &= ~BTCF_Pinned;
}
-#ifdef SQLITE_ENABLE_OFFSET_SQL_FUNC
/*
** Return the offset into the database file for the start of the
** payload to which the cursor is pointing.
@@ -73189,7 +75038,6 @@ SQLITE_PRIVATE i64 sqlite3BtreeOffset(BtCursor *pCur){
return (i64)pCur->pBt->pageSize*((i64)pCur->pPage->pgno - 1) +
(i64)(pCur->info.pPayload - pCur->pPage->aData);
}
-#endif /* SQLITE_ENABLE_OFFSET_SQL_FUNC */
/*
** Return the number of bytes of payload for the entry that pCur is
@@ -73215,7 +75063,7 @@ SQLITE_PRIVATE u32 sqlite3BtreePayloadSize(BtCursor *pCur){
** routine always returns 2147483647 (which is the largest record
** that SQLite can handle) or more. But returning a smaller value might
** prevent large memory allocations when trying to interpret a
-** corrupt datrabase.
+** corrupt database.
**
** The current implementation merely returns the size of the underlying
** database file.
@@ -73515,7 +75363,6 @@ static int accessPayload(
assert( aWrite>=pBufStart ); /* due to (6) */
memcpy(aSave, aWrite, 4);
rc = sqlite3OsRead(fd, aWrite, a+4, (i64)pBt->pageSize*(nextPage-1));
- if( rc && nextPage>pBt->nPage ) rc = SQLITE_CORRUPT_BKPT;
nextPage = get4byte(aWrite);
memcpy(aWrite, aSave, 4);
}else
@@ -73677,6 +75524,7 @@ SQLITE_PRIVATE const void *sqlite3BtreePayloadFetch(BtCursor *pCur, u32 *pAmt){
** vice-versa).
*/
static int moveToChild(BtCursor *pCur, u32 newPgno){
+ int rc;
assert( cursorOwnsBtShared(pCur) );
assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
@@ -73690,8 +75538,18 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
pCur->apPage[pCur->iPage] = pCur->pPage;
pCur->ix = 0;
pCur->iPage++;
- return getAndInitPage(pCur->pBt, newPgno, &pCur->pPage, pCur,
- pCur->curPagerFlags);
+ rc = getAndInitPage(pCur->pBt, newPgno, &pCur->pPage, pCur->curPagerFlags);
+ assert( pCur->pPage!=0 || rc!=SQLITE_OK );
+ if( rc==SQLITE_OK
+ && (pCur->pPage->nCell<1 || pCur->pPage->intKey!=pCur->curIntKey)
+ ){
+ releasePage(pCur->pPage);
+ rc = SQLITE_CORRUPT_PGNO(newPgno);
+ }
+ if( rc ){
+ pCur->pPage = pCur->apPage[--pCur->iPage];
+ }
+ return rc;
}
#ifdef SQLITE_DEBUG
@@ -73798,7 +75656,7 @@ static int moveToRoot(BtCursor *pCur){
sqlite3BtreeClearCursor(pCur);
}
rc = getAndInitPage(pCur->pBt, pCur->pgnoRoot, &pCur->pPage,
- 0, pCur->curPagerFlags);
+ pCur->curPagerFlags);
if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID;
return rc;
@@ -73910,7 +75768,7 @@ SQLITE_PRIVATE int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){
*pRes = 0;
rc = moveToLeftmost(pCur);
}else if( rc==SQLITE_EMPTY ){
- assert( pCur->pgnoRoot==0 || pCur->pPage->nCell==0 );
+ assert( pCur->pgnoRoot==0 || (pCur->pPage!=0 && pCur->pPage->nCell==0) );
*pRes = 1;
rc = SQLITE_OK;
}
@@ -74015,7 +75873,7 @@ SQLITE_PRIVATE int sqlite3BtreeTableMoveto(
/* If the requested key is one more than the previous key, then
** try to get there using sqlite3BtreeNext() rather than a full
** binary search. This is an optimization only. The correct answer
- ** is still obtained without this case, only a little more slowely */
+ ** is still obtained without this case, only a little more slowly. */
if( pCur->info.nKey+1==intKey ){
*pRes = 0;
rc = sqlite3BtreeNext(pCur, 0);
@@ -74411,10 +76269,36 @@ bypass_moveto_root:
}else{
chldPg = get4byte(findCell(pPage, lwr));
}
- pCur->ix = (u16)lwr;
- rc = moveToChild(pCur, chldPg);
- if( rc ) break;
- }
+
+ /* This block is similar to an in-lined version of:
+ **
+ ** pCur->ix = (u16)lwr;
+ ** rc = moveToChild(pCur, chldPg);
+ ** if( rc ) break;
+ */
+ pCur->info.nSize = 0;
+ pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
+ if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
+ return SQLITE_CORRUPT_BKPT;
+ }
+ pCur->aiIdx[pCur->iPage] = (u16)lwr;
+ pCur->apPage[pCur->iPage] = pCur->pPage;
+ pCur->ix = 0;
+ pCur->iPage++;
+ rc = getAndInitPage(pCur->pBt, chldPg, &pCur->pPage, pCur->curPagerFlags);
+ if( rc==SQLITE_OK
+ && (pCur->pPage->nCell<1 || pCur->pPage->intKey!=pCur->curIntKey)
+ ){
+ releasePage(pCur->pPage);
+ rc = SQLITE_CORRUPT_PGNO(chldPg);
+ }
+ if( rc ){
+ pCur->pPage = pCur->apPage[--pCur->iPage];
+ break;
+ }
+ /*
+ ***** End of in-lined moveToChild() call */
+ }
moveto_index_finish:
pCur->info.nSize = 0;
assert( (pCur->curFlags & BTCF_ValidOvfl)==0 );
@@ -74505,7 +76389,8 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
pPage = pCur->pPage;
idx = ++pCur->ix;
- if( NEVER(!pPage->isInit) || sqlite3FaultSim(412) ){
+ if( sqlite3FaultSim(412) ) pPage->isInit = 0;
+ if( !pPage->isInit ){
return SQLITE_CORRUPT_BKPT;
}
@@ -74597,7 +76482,10 @@ static SQLITE_NOINLINE int btreePrevious(BtCursor *pCur){
}
pPage = pCur->pPage;
- assert( pPage->isInit );
+ if( sqlite3FaultSim(412) ) pPage->isInit = 0;
+ if( !pPage->isInit ){
+ return SQLITE_CORRUPT_BKPT;
+ }
if( !pPage->leaf ){
int idx = pCur->ix;
rc = moveToChild(pCur, get4byte(findCell(pPage, idx)));
@@ -74768,7 +76656,7 @@ static int allocateBtreePage(
memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4);
*ppPage = pTrunk;
pTrunk = 0;
- TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
+ TRACE(("ALLOCATE: %u trunk - %u free pages left\n", *pPgno, n-1));
}else if( k>(u32)(pBt->usableSize/4 - 2) ){
/* Value of k is out of range. Database corruption */
rc = SQLITE_CORRUPT_PGNO(iTrunk);
@@ -74834,7 +76722,7 @@ static int allocateBtreePage(
}
}
pTrunk = 0;
- TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
+ TRACE(("ALLOCATE: %u trunk - %u free pages left\n", *pPgno, n-1));
#endif
}else if( k>0 ){
/* Extract a leaf from the trunk */
@@ -74879,8 +76767,8 @@ static int allocateBtreePage(
){
int noContent;
*pPgno = iPage;
- TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
- ": %d more free pages\n",
+ TRACE(("ALLOCATE: %u was leaf %u of %u on trunk %u"
+ ": %u more free pages\n",
*pPgno, closest+1, k, pTrunk->pgno, n-1));
rc = sqlite3PagerWrite(pTrunk->pDbPage);
if( rc ) goto end_allocate_page;
@@ -74936,7 +76824,7 @@ static int allocateBtreePage(
** becomes a new pointer-map page, the second is used by the caller.
*/
MemPage *pPg = 0;
- TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
+ TRACE(("ALLOCATE: %u from end of file (pointer-map page)\n", pBt->nPage));
assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
rc = btreeGetUnusedPage(pBt, pBt->nPage, &pPg, bNoContent);
if( rc==SQLITE_OK ){
@@ -74959,7 +76847,7 @@ static int allocateBtreePage(
releasePage(*ppPage);
*ppPage = 0;
}
- TRACE(("ALLOCATE: %d from end of file\n", *pPgno));
+ TRACE(("ALLOCATE: %u from end of file\n", *pPgno));
}
assert( CORRUPT_DB || *pPgno!=PENDING_BYTE_PAGE(pBt) );
@@ -75087,7 +76975,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
}
rc = btreeSetHasContent(pBt, iPage);
}
- TRACE(("FREE-PAGE: %d leaf on trunk page %d\n",pPage->pgno,pTrunk->pgno));
+ TRACE(("FREE-PAGE: %u leaf on trunk page %u\n",pPage->pgno,pTrunk->pgno));
goto freepage_out;
}
}
@@ -75108,7 +76996,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
put4byte(pPage->aData, iTrunk);
put4byte(&pPage->aData[4], 0);
put4byte(&pPage1->aData[32], iPage);
- TRACE(("FREE-PAGE: %d new trunk page replacing %d\n", pPage->pgno, iTrunk));
+ TRACE(("FREE-PAGE: %u new trunk page replacing %u\n", pPage->pgno, iTrunk));
freepage_out:
if( pPage ){
@@ -75197,7 +77085,7 @@ static SQLITE_NOINLINE int clearCellOverflow(
/* Call xParseCell to compute the size of a cell. If the cell contains
** overflow, then invoke cellClearOverflow to clear out that overflow.
-** STore the result code (SQLITE_OK or some error code) in rc.
+** Store the result code (SQLITE_OK or some error code) in rc.
**
** Implemented as macro to force inlining for performance.
*/
@@ -75270,7 +77158,10 @@ static int fillInCell(
n = nHeader + nPayload;
testcase( n==3 );
testcase( n==4 );
- if( n<4 ) n = 4;
+ if( n<4 ){
+ n = 4;
+ pPayload[nPayload] = 0;
+ }
*pnSize = n;
assert( nSrc<=nPayload );
testcase( nSrc<nPayload );
@@ -75467,6 +77358,14 @@ 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.
+**
+** The insertCellFast() routine below works exactly the same as
+** insertCell() except that it lacks the pTemp and iChild parameters
+** which are assumed zero. Other than that, the two routines are the
+** same.
+**
+** Fixes or enhancements to this routine should be reflected in
+** insertCellFast()!
*/
static int insertCell(
MemPage *pPage, /* Page into which we are copying */
@@ -75489,14 +77388,103 @@ static int insertCell(
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( sz==pPage->xCellSize(pPage, pCell) || CORRUPT_DB );
assert( pPage->nFree>=0 );
+ assert( iChild>0 );
if( pPage->nOverflow || sz+2>pPage->nFree ){
if( pTemp ){
memcpy(pTemp, pCell, sz);
pCell = pTemp;
}
- if( iChild ){
- put4byte(pCell, iChild);
+ put4byte(pCell, iChild);
+ j = pPage->nOverflow++;
+ /* 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;
+
+ /* When multiple overflows occur, they are always sequential and in
+ ** sorted order. This invariants arise because multiple overflows can
+ ** only occur when inserting divider cells into the parent page during
+ ** balancing, and the dividers are adjacent and sorted.
+ */
+ assert( j==0 || pPage->aiOvfl[j-1]<(u16)i ); /* Overflows in sorted order */
+ assert( j==0 || i==pPage->aiOvfl[j-1]+1 ); /* Overflows are sequential */
+ }else{
+ int rc = sqlite3PagerWrite(pPage->pDbPage);
+ if( NEVER(rc!=SQLITE_OK) ){
+ return rc;
}
+ assert( sqlite3PagerIswriteable(pPage->pDbPage) );
+ data = pPage->aData;
+ assert( &data[pPage->cellOffset]==pPage->aCellIdx );
+ rc = allocateSpace(pPage, sz, &idx);
+ if( rc ){ return rc; }
+ /* The allocateSpace() routine guarantees the following properties
+ ** if it returns successfully */
+ assert( idx >= 0 );
+ assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB );
+ assert( idx+sz <= (int)pPage->pBt->usableSize );
+ pPage->nFree -= (u16)(2 + sz);
+ /* In a corrupt database where an entry in the cell index section of
+ ** a btree page has a value of 3 or less, the pCell value might point
+ ** as many as 4 bytes in front of the start of the aData buffer for
+ ** the source page. Make sure this does not cause problems by not
+ ** reading the first 4 bytes */
+ memcpy(&data[idx+4], pCell+4, sz-4);
+ put4byte(&data[idx], iChild);
+ pIns = pPage->aCellIdx + i*2;
+ memmove(pIns+2, pIns, 2*(pPage->nCell - i));
+ put2byte(pIns, idx);
+ pPage->nCell++;
+ /* increment the cell count */
+ if( (++data[pPage->hdrOffset+4])==0 ) data[pPage->hdrOffset+3]++;
+ assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell || CORRUPT_DB );
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ if( pPage->pBt->autoVacuum ){
+ int rc2 = SQLITE_OK;
+ /* The cell may contain a pointer to an overflow page. If so, write
+ ** the entry for the overflow page into the pointer map.
+ */
+ ptrmapPutOvflPtr(pPage, pPage, pCell, &rc2);
+ if( rc2 ) return rc2;
+ }
+#endif
+ }
+ return SQLITE_OK;
+}
+
+/*
+** This variant of insertCell() assumes that the pTemp and iChild
+** parameters are both zero. Use this variant in sqlite3BtreeInsert()
+** for performance improvement, and also so that this variant is only
+** called from that one place, and is thus inlined, and thus runs must
+** faster.
+**
+** Fixes or enhancements to this routine should be reflected into
+** the insertCell() routine.
+*/
+static int insertCellFast(
+ MemPage *pPage, /* Page into which we are copying */
+ int i, /* New cell becomes the i-th cell of the page */
+ u8 *pCell, /* Content of the new cell */
+ int sz /* Bytes of content in pCell */
+){
+ int idx = 0; /* Where to write new cell content in data[] */
+ int j; /* Loop counter */
+ u8 *data; /* The content of the whole page */
+ u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */
+
+ assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
+ assert( MX_CELL(pPage->pBt)<=10921 );
+ assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB );
+ assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) );
+ assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) );
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
+ assert( sz==pPage->xCellSize(pPage, pCell) || CORRUPT_DB );
+ assert( pPage->nFree>=0 );
+ assert( pPage->nOverflow==0 );
+ if( sz+2>pPage->nFree ){
j = pPage->nOverflow++;
/* Comparison against ArraySize-1 since we hold back one extra slot
** as a contingency. In other words, never need more than 3 overflow
@@ -75528,17 +77516,7 @@ static int insertCell(
assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB );
assert( idx+sz <= (int)pPage->pBt->usableSize );
pPage->nFree -= (u16)(2 + sz);
- if( iChild ){
- /* In a corrupt database where an entry in the cell index section of
- ** a btree page has a value of 3 or less, the pCell value might point
- ** as many as 4 bytes in front of the start of the aData buffer for
- ** the source page. Make sure this does not cause problems by not
- ** reading the first 4 bytes */
- memcpy(&data[idx+4], pCell+4, sz-4);
- put4byte(&data[idx], iChild);
- }else{
- memcpy(&data[idx], pCell, sz);
- }
+ memcpy(&data[idx], pCell, sz);
pIns = pPage->aCellIdx + i*2;
memmove(pIns+2, pIns, 2*(pPage->nCell - i));
put2byte(pIns, idx);
@@ -75721,12 +77699,13 @@ static int rebuildPage(
int k; /* Current slot in pCArray->apEnd[] */
u8 *pSrcEnd; /* Current pCArray->apEnd[k] value */
+ assert( nCell>0 );
assert( i<iEnd );
j = get2byte(&aData[hdr+5]);
if( j>(u32)usableSize ){ j = 0; }
memcpy(&pTmp[j], &aData[j], usableSize - j);
- for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
+ for(k=0; ALWAYS(k<NB*2) && pCArray->ixNx[k]<=i; k++){}
pSrcEnd = pCArray->apEnd[k];
pData = pEnd;
@@ -75789,7 +77768,7 @@ static int rebuildPage(
** Finally, argument pBegin points to the byte immediately following the
** end of the space required by this page for the cell-pointer area (for
** all cells - not just those inserted by the current call). If the content
-** area must be extended to before this point in order to accomodate all
+** area must be extended to before this point in order to accommodate all
** cells in apCell[], then the cells do not fit and non-zero is returned.
*/
static int pageInsertArray(
@@ -75809,7 +77788,7 @@ static int pageInsertArray(
u8 *pEnd; /* Maximum extent of cell data */
assert( CORRUPT_DB || pPg->hdrOffset==0 ); /* Never called on page 1 */
if( iEnd<=iFirst ) return 0;
- for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
+ for(k=0; ALWAYS(k<NB*2) && pCArray->ixNx[k]<=i ; k++){}
pEnd = pCArray->apEnd[k];
while( 1 /*Exit by break*/ ){
int sz, rc;
@@ -75867,42 +77846,50 @@ static int pageFreeArray(
u8 * const pEnd = &aData[pPg->pBt->usableSize];
u8 * const pStart = &aData[pPg->hdrOffset + 8 + pPg->childPtrSize];
int nRet = 0;
- int i;
+ int i, j;
int iEnd = iFirst + nCell;
- u8 *pFree = 0; /* \__ Parameters for pending call to */
- int szFree = 0; /* / freeSpace() */
+ int nFree = 0;
+ int aOfst[10];
+ int aAfter[10];
for(i=iFirst; i<iEnd; i++){
u8 *pCell = pCArray->apCell[i];
if( SQLITE_WITHIN(pCell, pStart, pEnd) ){
int sz;
+ int iAfter;
+ int iOfst;
/* No need to use cachedCellSize() here. The sizes of all cells that
** are to be freed have already been computing while deciding which
** cells need freeing */
sz = pCArray->szCell[i]; assert( sz>0 );
- if( pFree!=(pCell + sz) ){
- if( pFree ){
- assert( pFree>aData && (pFree - aData)<65536 );
- freeSpace(pPg, (u16)(pFree - aData), szFree);
- }
- pFree = pCell;
- szFree = sz;
- if( pFree+sz>pEnd ){
- return 0;
+ iOfst = (u16)(pCell - aData);
+ iAfter = iOfst+sz;
+ for(j=0; j<nFree; j++){
+ if( aOfst[j]==iAfter ){
+ aOfst[j] = iOfst;
+ break;
+ }else if( aAfter[j]==iOfst ){
+ aAfter[j] = iAfter;
+ break;
}
- }else{
- /* The current cell is adjacent to and before the pFree cell.
- ** Combine the two regions into one to reduce the number of calls
- ** to freeSpace(). */
- pFree = pCell;
- szFree += sz;
+ }
+ if( j>=nFree ){
+ if( nFree>=(int)(sizeof(aOfst)/sizeof(aOfst[0])) ){
+ for(j=0; j<nFree; j++){
+ freeSpace(pPg, aOfst[j], aAfter[j]-aOfst[j]);
+ }
+ nFree = 0;
+ }
+ aOfst[nFree] = iOfst;
+ aAfter[nFree] = iAfter;
+ if( &aData[iAfter]>pEnd ) return 0;
+ nFree++;
}
nRet++;
}
}
- if( pFree ){
- assert( pFree>aData && (pFree - aData)<65536 );
- freeSpace(pPg, (u16)(pFree - aData), szFree);
+ for(j=0; j<nFree; j++){
+ freeSpace(pPg, aOfst[j], aAfter[j]-aOfst[j]);
}
return nRet;
}
@@ -75955,9 +77942,9 @@ static int editPage(
nCell -= nTail;
}
- pData = &aData[get2byteNotZero(&aData[hdr+5])];
+ pData = &aData[get2byte(&aData[hdr+5])];
if( pData<pBegin ) goto editpage_fail;
- if( pData>pPg->aDataEnd ) goto editpage_fail;
+ if( NEVER(pData>pPg->aDataEnd) ) goto editpage_fail;
/* Add cells to the start of the page */
if( iNew<iOld ){
@@ -76019,6 +78006,7 @@ static int editPage(
return SQLITE_OK;
editpage_fail:
/* Unable to edit this page. Rebuild it from scratch instead. */
+ if( nNew<1 ) return SQLITE_CORRUPT_BKPT;
populateCellCache(pCArray, iNew, nNew);
return rebuildPage(pCArray, iNew, nNew, pPg);
}
@@ -76096,7 +78084,7 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){
** with entries for the new page, and any pointer from the
** cell on the page to an overflow page. If either of these
** operations fails, the return code is set, but the contents
- ** of the parent page are still manipulated by thh code below.
+ ** of the parent page are still manipulated by the code below.
** That is Ok, at this point the parent page is guaranteed to
** be marked as dirty. Returning an error code will cause a
** rollback, undoing any changes made to the parent page.
@@ -76372,7 +78360,7 @@ static int balance_nonroot(
pgno = get4byte(pRight);
while( 1 ){
if( rc==SQLITE_OK ){
- rc = getAndInitPage(pBt, pgno, &apOld[i], 0, 0);
+ rc = getAndInitPage(pBt, pgno, &apOld[i], 0);
}
if( rc ){
memset(apOld, 0, (i+1)*sizeof(MemPage*));
@@ -76686,7 +78674,7 @@ static int balance_nonroot(
}
}
- /* Sanity check: For a non-corrupt database file one of the follwing
+ /* Sanity check: For a non-corrupt database file one of the following
** must be true:
** (1) We found one or more cells (cntNew[0])>0), or
** (2) pPage is a virtual root page. A virtual root page is when
@@ -76694,7 +78682,7 @@ static int balance_nonroot(
** that page.
*/
assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) || CORRUPT_DB);
- TRACE(("BALANCE: old: %d(nc=%d) %d(nc=%d) %d(nc=%d)\n",
+ TRACE(("BALANCE: old: %u(nc=%u) %u(nc=%u) %u(nc=%u)\n",
apOld[0]->pgno, apOld[0]->nCell,
nOld>=2 ? apOld[1]->pgno : 0, nOld>=2 ? apOld[1]->nCell : 0,
nOld>=3 ? apOld[2]->pgno : 0, nOld>=3 ? apOld[2]->nCell : 0
@@ -76778,8 +78766,8 @@ static int balance_nonroot(
}
}
- TRACE(("BALANCE: new: %d(%d nc=%d) %d(%d nc=%d) %d(%d nc=%d) "
- "%d(%d nc=%d) %d(%d nc=%d)\n",
+ TRACE(("BALANCE: new: %u(%u nc=%u) %u(%u nc=%u) %u(%u nc=%u) "
+ "%u(%u nc=%u) %u(%u nc=%u)\n",
apNew[0]->pgno, szNew[0], cntNew[0],
nNew>=2 ? apNew[1]->pgno : 0, nNew>=2 ? szNew[1] : 0,
nNew>=2 ? cntNew[1] - cntNew[0] - !leafData : 0,
@@ -76911,9 +78899,9 @@ static int balance_nonroot(
iOvflSpace += sz;
assert( sz<=pBt->maxLocal+23 );
assert( iOvflSpace <= (int)pBt->pageSize );
- for(k=0; b.ixNx[k]<=j && ALWAYS(k<NB*2); k++){}
+ for(k=0; ALWAYS(k<NB*2) && b.ixNx[k]<=j; k++){}
pSrcEnd = b.apEnd[k];
- if( SQLITE_WITHIN(pSrcEnd, pCell, pCell+sz) ){
+ if( SQLITE_OVERFLOW(pSrcEnd, pCell, pCell+sz) ){
rc = SQLITE_CORRUPT_BKPT;
goto balance_cleanup;
}
@@ -76947,6 +78935,8 @@ static int balance_nonroot(
for(i=1-nNew; i<nNew; i++){
int iPg = i<0 ? -i : i;
assert( iPg>=0 && iPg<nNew );
+ assert( iPg>=1 || i>=0 );
+ assert( iPg<ArraySize(cntOld) );
if( abDone[iPg] ) continue; /* Skip pages already processed */
if( i>=0 /* On the upwards pass, or... */
|| cntOld[iPg-1]>=cntNew[iPg-1] /* Condition (1) is true */
@@ -77024,7 +79014,7 @@ static int balance_nonroot(
}
assert( pParent->isInit );
- TRACE(("BALANCE: finished: old=%d new=%d cells=%d\n",
+ TRACE(("BALANCE: finished: old=%u new=%u cells=%u\n",
nOld, nNew, b.nCell));
/* Free any old pages that were not reused as new pages.
@@ -77109,7 +79099,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
assert( sqlite3PagerIswriteable(pRoot->pDbPage) );
assert( pChild->nCell==pRoot->nCell || CORRUPT_DB );
- TRACE(("BALANCE: copy root %d into %d\n", pRoot->pgno, pChild->pgno));
+ TRACE(("BALANCE: copy root %u into %u\n", pRoot->pgno, pChild->pgno));
/* Copy the overflow cells from pRoot to pChild */
memcpy(pChild->aiOvfl, pRoot->aiOvfl,
@@ -77303,7 +79293,7 @@ static int btreeOverwriteContent(
){
int nData = pX->nData - iOffset;
if( nData<=0 ){
- /* Overwritting with zeros */
+ /* Overwriting with zeros */
int i;
for(i=0; i<iAmt && pDest[i]==0; i++){}
if( i<iAmt ){
@@ -77339,7 +79329,7 @@ static int btreeOverwriteContent(
** cell.
*/
static SQLITE_NOINLINE int btreeOverwriteOverflowCell(
- BtCursor *pCur, /* Cursor pointing to cell to ovewrite */
+ BtCursor *pCur, /* Cursor pointing to cell to overwrite */
const BtreePayload *pX /* Content to write into the cell */
){
int iOffset; /* Next byte of pX->pData to write */
@@ -77592,7 +79582,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
}
}
assert( pCur->eState==CURSOR_VALID
- || (pCur->eState==CURSOR_INVALID && loc) );
+ || (pCur->eState==CURSOR_INVALID && loc) || CORRUPT_DB );
pPage = pCur->pPage;
assert( pPage->intKey || pX->nKey>=0 || (flags & BTREE_PREFORMAT) );
@@ -77607,7 +79597,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
if( rc ) return rc;
}
- TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n",
+ TRACE(("INSERT: table=%u nkey=%lld ndata=%u page=%u %s\n",
pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno,
loc==0 ? "overwrite" : "new entry"));
assert( pPage->isInit || CORRUPT_DB );
@@ -77617,7 +79607,10 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
if( flags & BTREE_PREFORMAT ){
rc = SQLITE_OK;
szNew = p->pBt->nPreformatSize;
- if( szNew<4 ) szNew = 4;
+ if( szNew<4 ){
+ szNew = 4;
+ newCell[3] = 0;
+ }
if( ISAUTOVACUUM(p->pBt) && szNew>pPage->maxLocal ){
CellInfo info;
pPage->xParseCell(pPage, newCell, &info);
@@ -77634,6 +79627,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
assert( szNew==pPage->xCellSize(pPage, newCell) );
assert( szNew <= MX_CELL_SIZE(p->pBt) );
idx = pCur->ix;
+ pCur->info.nSize = 0;
if( loc==0 ){
CellInfo info;
assert( idx>=0 );
@@ -77678,11 +79672,11 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
}else if( loc<0 && pPage->nCell>0 ){
assert( pPage->leaf );
idx = ++pCur->ix;
- pCur->curFlags &= ~BTCF_ValidNKey;
+ pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
}else{
assert( pPage->leaf );
}
- rc = insertCell(pPage, idx, newCell, szNew, 0, 0);
+ rc = insertCellFast(pPage, idx, newCell, szNew);
assert( pPage->nOverflow==0 || rc==SQLITE_OK );
assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
@@ -77706,10 +79700,9 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
** larger than the largest existing key, it is possible to insert the
** row without seeking the cursor. This can be a big performance boost.
*/
- pCur->info.nSize = 0;
if( pPage->nOverflow ){
assert( rc==SQLITE_OK );
- pCur->curFlags &= ~(BTCF_ValidNKey);
+ pCur->curFlags &= ~(BTCF_ValidNKey|BTCF_ValidOvfl);
rc = balance(pCur);
/* Must make sure nOverflow is reset to zero even if the balance()
@@ -77907,6 +79900,9 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ){
return SQLITE_CORRUPT_BKPT;
}
+ if( pCell<&pPage->aCellIdx[pPage->nCell] ){
+ return SQLITE_CORRUPT_BKPT;
+ }
/* If the BTREE_SAVEPOSITION bit is on, then the cursor position must
** be preserved following this delete operation. If the current delete
@@ -78083,7 +80079,7 @@ static int btreeCreateTable(Btree *p, Pgno *piTable, int createTabFlags){
MemPage *pRoot;
Pgno pgnoRoot;
int rc;
- int ptfFlags; /* Page-type flage for the root page of new table */
+ int ptfFlags; /* Page-type flags for the root page of new table */
assert( sqlite3BtreeHoldsMutex(p) );
assert( pBt->inTransaction==TRANS_WRITE );
@@ -78252,7 +80248,7 @@ static int clearDatabasePage(
if( pgno>btreePagecount(pBt) ){
return SQLITE_CORRUPT_BKPT;
}
- rc = getAndInitPage(pBt, pgno, &pPage, 0, 0);
+ rc = getAndInitPage(pBt, pgno, &pPage, 0);
if( rc ) return rc;
if( (pBt->openFlags & BTREE_SINGLE)==0
&& sqlite3PagerPageRefcount(pPage->pDbPage) != (1 + (pgno==1))
@@ -78655,7 +80651,8 @@ static void checkAppendMsg(
sqlite3_str_append(&pCheck->errMsg, "\n", 1);
}
if( pCheck->zPfx ){
- sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2);
+ sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx,
+ pCheck->v0, pCheck->v1, pCheck->v2);
}
sqlite3_str_vappendf(&pCheck->errMsg, zFormat, ap);
va_end(ap);
@@ -78672,7 +80669,8 @@ static void checkAppendMsg(
** corresponds to page iPg is already set.
*/
static int getPageReferenced(IntegrityCk *pCheck, Pgno iPg){
- assert( iPg<=pCheck->nPage && sizeof(pCheck->aPgRef[0])==1 );
+ assert( pCheck->aPgRef!=0 );
+ assert( iPg<=pCheck->nCkPage && sizeof(pCheck->aPgRef[0])==1 );
return (pCheck->aPgRef[iPg/8] & (1 << (iPg & 0x07)));
}
@@ -78680,7 +80678,8 @@ static int getPageReferenced(IntegrityCk *pCheck, Pgno iPg){
** Set the bit in the IntegrityCk.aPgRef[] array that corresponds to page iPg.
*/
static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){
- assert( iPg<=pCheck->nPage && sizeof(pCheck->aPgRef[0])==1 );
+ assert( pCheck->aPgRef!=0 );
+ assert( iPg<=pCheck->nCkPage && sizeof(pCheck->aPgRef[0])==1 );
pCheck->aPgRef[iPg/8] |= (1 << (iPg & 0x07));
}
@@ -78694,12 +80693,12 @@ static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){
** Also check that the page number is in bounds.
*/
static int checkRef(IntegrityCk *pCheck, Pgno iPage){
- if( iPage>pCheck->nPage || iPage==0 ){
- checkAppendMsg(pCheck, "invalid page number %d", iPage);
+ if( iPage>pCheck->nCkPage || iPage==0 ){
+ checkAppendMsg(pCheck, "invalid page number %u", iPage);
return 1;
}
if( getPageReferenced(pCheck, iPage) ){
- checkAppendMsg(pCheck, "2nd reference to page %d", iPage);
+ checkAppendMsg(pCheck, "2nd reference to page %u", iPage);
return 1;
}
setPageReferenced(pCheck, iPage);
@@ -78725,13 +80724,13 @@ static void checkPtrmap(
rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) checkOom(pCheck);
- checkAppendMsg(pCheck, "Failed to read ptrmap key=%d", iChild);
+ checkAppendMsg(pCheck, "Failed to read ptrmap key=%u", iChild);
return;
}
if( ePtrmapType!=eType || iPtrmapParent!=iParent ){
checkAppendMsg(pCheck,
- "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)",
+ "Bad ptr map entry key=%u expected=(%u,%u) got=(%u,%u)",
iChild, eType, iParent, ePtrmapType, iPtrmapParent);
}
}
@@ -78756,7 +80755,7 @@ static void checkList(
if( checkRef(pCheck, iPage) ) break;
N--;
if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){
- checkAppendMsg(pCheck, "failed to get page %d", iPage);
+ checkAppendMsg(pCheck, "failed to get page %u", iPage);
break;
}
pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage);
@@ -78769,7 +80768,7 @@ static void checkList(
#endif
if( n>pCheck->pBt->usableSize/4-2 ){
checkAppendMsg(pCheck,
- "freelist leaf count too big on page %d", iPage);
+ "freelist leaf count too big on page %u", iPage);
N--;
}else{
for(i=0; i<(int)n; i++){
@@ -78801,7 +80800,7 @@ static void checkList(
}
if( N && nErrAtStart==pCheck->nErr ){
checkAppendMsg(pCheck,
- "%s is %d but should be %d",
+ "%s is %u but should be %u",
isFreeList ? "size" : "overflow list length",
expected-N, expected);
}
@@ -78916,11 +80915,12 @@ static int checkTreePage(
usableSize = pBt->usableSize;
if( iPage==0 ) return 0;
if( checkRef(pCheck, iPage) ) return 0;
- pCheck->zPfx = "Page %u: ";
+ pCheck->zPfx = "Tree %u page %u: ";
pCheck->v1 = iPage;
if( (rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0 ){
checkAppendMsg(pCheck,
"unable to get the page. error code=%d", rc);
+ if( rc==SQLITE_IOERR_NOMEM ) pCheck->rc = SQLITE_NOMEM;
goto end_of_check;
}
@@ -78943,7 +80943,7 @@ static int checkTreePage(
hdr = pPage->hdrOffset;
/* Set up for cell analysis */
- pCheck->zPfx = "On tree page %u cell %d: ";
+ pCheck->zPfx = "Tree %u page %u cell %u: ";
contentOffset = get2byteNotZero(&data[hdr+5]);
assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
@@ -78963,7 +80963,7 @@ static int checkTreePage(
pgno = get4byte(&data[hdr+8]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
- pCheck->zPfx = "On page %u at right child: ";
+ pCheck->zPfx = "Tree %u page %u right child: ";
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage);
}
#endif
@@ -78987,7 +80987,7 @@ static int checkTreePage(
pc = get2byteAligned(pCellIdx);
pCellIdx -= 2;
if( pc<contentOffset || pc>usableSize-4 ){
- checkAppendMsg(pCheck, "Offset %d out of range %d..%d",
+ checkAppendMsg(pCheck, "Offset %u out of range %u..%u",
pc, contentOffset, usableSize-4);
doCoverageCheck = 0;
continue;
@@ -79119,7 +81119,7 @@ static int checkTreePage(
*/
if( heap[0]==0 && nFrag!=data[hdr+7] ){
checkAppendMsg(pCheck,
- "Fragmentation of %d bytes reported as %d on page %u",
+ "Fragmentation of %u bytes reported as %u on page %u",
nFrag, data[hdr+7], iPage);
}
}
@@ -79191,15 +81191,15 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
sCheck.db = db;
sCheck.pBt = pBt;
sCheck.pPager = pBt->pPager;
- sCheck.nPage = btreePagecount(sCheck.pBt);
+ sCheck.nCkPage = btreePagecount(sCheck.pBt);
sCheck.mxErr = mxErr;
sqlite3StrAccumInit(&sCheck.errMsg, 0, zErr, sizeof(zErr), SQLITE_MAX_LENGTH);
sCheck.errMsg.printfFlags = SQLITE_PRINTF_INTERNAL;
- if( sCheck.nPage==0 ){
+ if( sCheck.nCkPage==0 ){
goto integrity_ck_cleanup;
}
- sCheck.aPgRef = sqlite3MallocZero((sCheck.nPage / 8)+ 1);
+ sCheck.aPgRef = sqlite3MallocZero((sCheck.nCkPage / 8)+ 1);
if( !sCheck.aPgRef ){
checkOom(&sCheck);
goto integrity_ck_cleanup;
@@ -79211,12 +81211,12 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
}
i = PENDING_BYTE_PAGE(pBt);
- if( i<=sCheck.nPage ) setPageReferenced(&sCheck, i);
+ if( i<=sCheck.nCkPage ) setPageReferenced(&sCheck, i);
/* Check the integrity of the freelist
*/
if( bCkFreelist ){
- sCheck.zPfx = "Main freelist: ";
+ sCheck.zPfx = "Freelist: ";
checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
get4byte(&pBt->pPage1->aData[36]));
sCheck.zPfx = 0;
@@ -79233,7 +81233,7 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
mxInHdr = get4byte(&pBt->pPage1->aData[52]);
if( mx!=mxInHdr ){
checkAppendMsg(&sCheck,
- "max rootpage (%d) disagrees with header (%d)",
+ "max rootpage (%u) disagrees with header (%u)",
mx, mxInHdr
);
}
@@ -79254,6 +81254,7 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0);
}
#endif
+ sCheck.v0 = aRoot[i];
checkTreePage(&sCheck, aRoot[i], &notUsed, LARGEST_INT64);
}
pBt->db->flags = savedDbFlags;
@@ -79261,10 +81262,10 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
/* Make sure every page in the file is referenced
*/
if( !bPartial ){
- for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
+ for(i=1; i<=sCheck.nCkPage && sCheck.mxErr; i++){
#ifdef SQLITE_OMIT_AUTOVACUUM
if( getPageReferenced(&sCheck, i)==0 ){
- checkAppendMsg(&sCheck, "Page %d is never used", i);
+ checkAppendMsg(&sCheck, "Page %u: never used", i);
}
#else
/* If the database supports auto-vacuum, make sure no tables contain
@@ -79272,11 +81273,11 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
*/
if( getPageReferenced(&sCheck, i)==0 &&
(PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
- checkAppendMsg(&sCheck, "Page %d is never used", i);
+ checkAppendMsg(&sCheck, "Page %u: never used", i);
}
if( getPageReferenced(&sCheck, i)!=0 &&
(PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
- checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i);
+ checkAppendMsg(&sCheck, "Page %u: pointer map referenced", i);
}
#endif
}
@@ -79838,13 +81839,7 @@ static int backupOnePage(
assert( !isFatalError(p->rc) );
assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) );
assert( zSrcData );
-
- /* Catch the case where the destination is an in-memory database and the
- ** page sizes of the source and destination differ.
- */
- if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){
- rc = SQLITE_READONLY;
- }
+ assert( nSrcPgsz==nDestPgsz || sqlite3PagerIsMemdb(pDestPager)==0 );
/* This loop runs once for each destination page spanned by the source
** page. For each iteration, variable iOff is set to the byte offset
@@ -79977,7 +81972,10 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
pgszSrc = sqlite3BtreeGetPageSize(p->pSrc);
pgszDest = sqlite3BtreeGetPageSize(p->pDest);
destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest));
- if( SQLITE_OK==rc && destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){
+ if( SQLITE_OK==rc
+ && (destMode==PAGER_JOURNALMODE_WAL || sqlite3PagerIsMemdb(pDestPager))
+ && pgszSrc!=pgszDest
+ ){
rc = SQLITE_READONLY;
}
@@ -80526,6 +82524,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemValidStrRep(Mem *p){
char *z;
int i, j, incr;
if( (p->flags & MEM_Str)==0 ) return 1;
+ if( p->db && p->db->mallocFailed ) return 1;
if( p->flags & MEM_Term ){
/* Insure that the string is properly zero-terminated. Pay particular
** attention to the case where p->n is odd */
@@ -80683,6 +82682,40 @@ SQLITE_PRIVATE int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){
}
/*
+** If pMem is already a string, detect if it is a zero-terminated
+** string, or make it into one if possible, and mark it as such.
+**
+** This is an optimization. Correct operation continues even if
+** this routine is a no-op.
+*/
+SQLITE_PRIVATE void sqlite3VdbeMemZeroTerminateIfAble(Mem *pMem){
+ if( (pMem->flags & (MEM_Str|MEM_Term|MEM_Ephem|MEM_Static))!=MEM_Str ){
+ /* pMem must be a string, and it cannot be an ephemeral or static string */
+ return;
+ }
+ if( pMem->enc!=SQLITE_UTF8 ) return;
+ if( NEVER(pMem->z==0) ) return;
+ if( pMem->flags & MEM_Dyn ){
+ if( pMem->xDel==sqlite3_free
+ && sqlite3_msize(pMem->z) >= (u64)(pMem->n+1)
+ ){
+ pMem->z[pMem->n] = 0;
+ pMem->flags |= MEM_Term;
+ return;
+ }
+ if( pMem->xDel==sqlite3RCStrUnref ){
+ /* Blindly assume that all RCStr objects are zero-terminated */
+ pMem->flags |= MEM_Term;
+ return;
+ }
+ }else if( pMem->szMalloc >= pMem->n+1 ){
+ pMem->z[pMem->n] = 0;
+ pMem->flags |= MEM_Term;
+ return;
+ }
+}
+
+/*
** It is already known that pMem contains an unterminated string.
** Add the zero terminator.
**
@@ -80808,7 +82841,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
vdbeMemRenderNum(nByte, pMem->z, pMem);
assert( pMem->z!=0 );
- assert( pMem->n==sqlite3Strlen30NN(pMem->z) );
+ assert( pMem->n==(int)sqlite3Strlen30NN(pMem->z) );
pMem->enc = SQLITE_UTF8;
pMem->flags |= MEM_Str|MEM_Term;
if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal);
@@ -80944,36 +82977,6 @@ SQLITE_PRIVATE void sqlite3VdbeMemReleaseMalloc(Mem *p){
}
/*
-** Convert a 64-bit IEEE double into a 64-bit signed integer.
-** If the double is out of range of a 64-bit signed integer then
-** return the closest available 64-bit signed integer.
-*/
-static SQLITE_NOINLINE i64 doubleToInt64(double r){
-#ifdef SQLITE_OMIT_FLOATING_POINT
- /* When floating-point is omitted, double and int64 are the same thing */
- return r;
-#else
- /*
- ** Many compilers we encounter do not define constants for the
- ** minimum and maximum 64-bit integers, or they define them
- ** inconsistently. And many do not understand the "LL" notation.
- ** So we define our own static constants here using nothing
- ** larger than a 32-bit integer constant.
- */
- static const i64 maxInt = LARGEST_INT64;
- static const i64 minInt = SMALLEST_INT64;
-
- if( r<=(double)minInt ){
- return minInt;
- }else if( r>=(double)maxInt ){
- return maxInt;
- }else{
- return (i64)r;
- }
-#endif
-}
-
-/*
** Return some kind of integer value which is the best we can do
** at representing the value that *pMem describes as an integer.
** If pMem is an integer, then the value is exact. If pMem is
@@ -80999,7 +83002,7 @@ SQLITE_PRIVATE i64 sqlite3VdbeIntValue(const Mem *pMem){
testcase( flags & MEM_IntReal );
return pMem->u.i;
}else if( flags & MEM_Real ){
- return doubleToInt64(pMem->u.r);
+ return sqlite3RealToI64(pMem->u.r);
}else if( (flags & (MEM_Str|MEM_Blob))!=0 && pMem->z!=0 ){
return memIntValue(pMem);
}else{
@@ -81061,7 +83064,7 @@ SQLITE_PRIVATE void sqlite3VdbeIntegerAffinity(Mem *pMem){
if( pMem->flags & MEM_IntReal ){
MemSetTypeFlag(pMem, MEM_Int);
}else{
- i64 ix = doubleToInt64(pMem->u.r);
+ i64 ix = sqlite3RealToI64(pMem->u.r);
/* Only mark the value as an integer if
**
@@ -81129,8 +83132,8 @@ SQLITE_PRIVATE int sqlite3RealSameAsInt(double r1, sqlite3_int64 i){
** from UBSAN.
*/
SQLITE_PRIVATE i64 sqlite3RealToI64(double r){
- if( r<=(double)SMALLEST_INT64 ) return SMALLEST_INT64;
- if( r>=(double)LARGEST_INT64) return LARGEST_INT64;
+ if( r<-9223372036854774784.0 ) return SMALLEST_INT64;
+ if( r>+9223372036854774784.0 ) return LARGEST_INT64;
return (i64)r;
}
@@ -81201,6 +83204,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
break;
}
default: {
+ int rc;
assert( aff==SQLITE_AFF_TEXT );
assert( MEM_Str==(MEM_Blob>>3) );
pMem->flags |= (pMem->flags&MEM_Blob)>>3;
@@ -81208,7 +83212,9 @@ SQLITE_PRIVATE int sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){
assert( pMem->flags & MEM_Str || pMem->db->mallocFailed );
pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero);
if( encoding!=SQLITE_UTF8 ) pMem->n &= ~1;
- return sqlite3VdbeChangeEncoding(pMem, encoding);
+ rc = sqlite3VdbeChangeEncoding(pMem, encoding);
+ if( rc ) return rc;
+ sqlite3VdbeMemZeroTerminateIfAble(pMem);
}
}
return SQLITE_OK;
@@ -81732,6 +83738,24 @@ SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
return valueToText(pVal, enc);
}
+/* Return true if sqlit3_value object pVal is a string or blob value
+** that uses the destructor specified in the second argument.
+**
+** TODO: Maybe someday promote this interface into a published API so
+** that third-party extensions can get access to it?
+*/
+SQLITE_PRIVATE int sqlite3ValueIsOfClass(const sqlite3_value *pVal, void(*xFree)(void*)){
+ if( ALWAYS(pVal!=0)
+ && ALWAYS((pVal->flags & (MEM_Str|MEM_Blob))!=0)
+ && (pVal->flags & MEM_Dyn)!=0
+ && pVal->xDel==xFree
+ ){
+ return 1;
+ }else{
+ return 0;
+ }
+}
+
/*
** Create a new sqlite3_value object.
*/
@@ -81799,6 +83823,7 @@ static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){
}
pRec->nField = p->iVal+1;
+ sqlite3VdbeMemSetNull(&pRec->aMem[p->iVal]);
return &pRec->aMem[p->iVal];
}
#else
@@ -81852,9 +83877,12 @@ static int valueFromFunction(
if( pList ) nVal = pList->nExpr;
assert( !ExprHasProperty(p, EP_IntValue) );
pFunc = sqlite3FindFunction(db, p->u.zToken, nVal, enc, 0);
+#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
+ if( pFunc==0 ) return SQLITE_OK;
+#endif
assert( pFunc );
if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
- || (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
+ || (pFunc->funcFlags & (SQLITE_FUNC_NEEDCOLL|SQLITE_FUNC_RUNONLY))!=0
){
return SQLITE_OK;
}
@@ -81888,16 +83916,11 @@ static int valueFromFunction(
}else{
sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8);
assert( rc==SQLITE_OK );
- assert( enc==pVal->enc
- || (pVal->flags & MEM_Str)==0
- || db->mallocFailed );
-#if 0 /* Not reachable except after a prior failure */
rc = sqlite3VdbeChangeEncoding(pVal, enc);
- if( rc==SQLITE_OK && sqlite3VdbeMemTooBig(pVal) ){
+ if( NEVER(rc==SQLITE_OK && sqlite3VdbeMemTooBig(pVal)) ){
rc = SQLITE_TOOBIG;
pCtx->pParse->nErr++;
}
-#endif
}
value_from_function_out:
@@ -81961,6 +83984,13 @@ static int valueFromExpr(
rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx);
testcase( rc!=SQLITE_OK );
if( *ppVal ){
+#ifdef SQLITE_ENABLE_STAT4
+ rc = ExpandBlob(*ppVal);
+#else
+ /* zero-blobs only come from functions, not literal values. And
+ ** functions are only processed under STAT4 */
+ assert( (ppVal[0][0].flags & MEM_Zero)==0 );
+#endif
sqlite3VdbeMemCast(*ppVal, aff, enc);
sqlite3ValueApplyAffinity(*ppVal, affinity, enc);
}
@@ -82053,6 +84083,7 @@ static int valueFromExpr(
if( pVal ){
pVal->flags = MEM_Int;
pVal->u.i = pExpr->u.zToken[4]==0;
+ sqlite3ValueApplyAffinity(pVal, affinity, enc);
}
}
@@ -82575,14 +84606,44 @@ static int growOpArray(Vdbe *v, int nOp){
** sqlite3CantopenError(lineno)
*/
static void test_addop_breakpoint(int pc, Op *pOp){
- static int n = 0;
+ static u64 n = 0;
(void)pc;
(void)pOp;
n++;
+ if( n==LARGEST_UINT64 ) abort(); /* so that n is used, preventing a warning */
}
#endif
/*
+** Slow paths for sqlite3VdbeAddOp3() and sqlite3VdbeAddOp4Int() for the
+** unusual case when we need to increase the size of the Vdbe.aOp[] array
+** before adding the new opcode.
+*/
+static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){
+ assert( p->nOpAlloc<=p->nOp );
+ if( growOpArray(p, 1) ) return 1;
+ assert( p->nOpAlloc>p->nOp );
+ return sqlite3VdbeAddOp3(p, op, p1, p2, p3);
+}
+static SQLITE_NOINLINE int addOp4IntSlow(
+ Vdbe *p, /* Add the opcode to this VM */
+ int op, /* The new opcode */
+ int p1, /* The P1 operand */
+ int p2, /* The P2 operand */
+ int p3, /* The P3 operand */
+ int p4 /* The P4 operand as an integer */
+){
+ int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3);
+ if( p->db->mallocFailed==0 ){
+ VdbeOp *pOp = &p->aOp[addr];
+ pOp->p4type = P4_INT32;
+ pOp->p4.i = p4;
+ }
+ return addr;
+}
+
+
+/*
** Add a new instruction to the list of instructions current in the
** VDBE. Return the address of the new instruction.
**
@@ -82592,17 +84653,16 @@ static void test_addop_breakpoint(int pc, Op *pOp){
**
** op The opcode for this instruction
**
-** p1, p2, p3 Operands
-**
-** Use the sqlite3VdbeResolveLabel() function to fix an address and
-** the sqlite3VdbeChangeP4() function to change the value of the P4
-** operand.
+** p1, p2, p3, p4 Operands
*/
-static SQLITE_NOINLINE int growOp3(Vdbe *p, int op, int p1, int p2, int p3){
- assert( p->nOpAlloc<=p->nOp );
- if( growOpArray(p, 1) ) return 1;
- assert( p->nOpAlloc>p->nOp );
- return sqlite3VdbeAddOp3(p, op, p1, p2, p3);
+SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe *p, int op){
+ return sqlite3VdbeAddOp3(p, op, 0, 0, 0);
+}
+SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe *p, int op, int p1){
+ return sqlite3VdbeAddOp3(p, op, p1, 0, 0);
+}
+SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe *p, int op, int p1, int p2){
+ return sqlite3VdbeAddOp3(p, op, p1, p2, 0);
}
SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
int i;
@@ -82625,6 +84685,9 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
pOp->p3 = p3;
pOp->p4.p = 0;
pOp->p4type = P4_NOTUSED;
+
+ /* Replicate this logic in sqlite3VdbeAddOp4Int()
+ ** vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
pOp->zComment = 0;
#endif
@@ -82641,16 +84704,59 @@ SQLITE_PRIVATE int sqlite3VdbeAddOp3(Vdbe *p, int op, int p1, int p2, int p3){
#ifdef SQLITE_VDBE_COVERAGE
pOp->iSrcLine = 0;
#endif
+ /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ ** Replicate in sqlite3VdbeAddOp4Int() */
+
return i;
}
-SQLITE_PRIVATE int sqlite3VdbeAddOp0(Vdbe *p, int op){
- return sqlite3VdbeAddOp3(p, op, 0, 0, 0);
-}
-SQLITE_PRIVATE int sqlite3VdbeAddOp1(Vdbe *p, int op, int p1){
- return sqlite3VdbeAddOp3(p, op, p1, 0, 0);
-}
-SQLITE_PRIVATE int sqlite3VdbeAddOp2(Vdbe *p, int op, int p1, int p2){
- return sqlite3VdbeAddOp3(p, op, p1, p2, 0);
+SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(
+ Vdbe *p, /* Add the opcode to this VM */
+ int op, /* The new opcode */
+ int p1, /* The P1 operand */
+ int p2, /* The P2 operand */
+ int p3, /* The P3 operand */
+ int p4 /* The P4 operand as an integer */
+){
+ int i;
+ VdbeOp *pOp;
+
+ i = p->nOp;
+ if( p->nOpAlloc<=i ){
+ return addOp4IntSlow(p, op, p1, p2, p3, p4);
+ }
+ p->nOp++;
+ pOp = &p->aOp[i];
+ assert( pOp!=0 );
+ pOp->opcode = (u8)op;
+ pOp->p5 = 0;
+ pOp->p1 = p1;
+ pOp->p2 = p2;
+ pOp->p3 = p3;
+ pOp->p4.i = p4;
+ pOp->p4type = P4_INT32;
+
+ /* Replicate this logic in sqlite3VdbeAddOp3()
+ ** vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */
+#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
+ pOp->zComment = 0;
+#endif
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
+ pOp->nExec = 0;
+ pOp->nCycle = 0;
+#endif
+#ifdef SQLITE_DEBUG
+ if( p->db->flags & SQLITE_VdbeAddopTrace ){
+ sqlite3VdbePrintOp(0, i, &p->aOp[i]);
+ test_addop_breakpoint(i, &p->aOp[i]);
+ }
+#endif
+#ifdef SQLITE_VDBE_COVERAGE
+ pOp->iSrcLine = 0;
+#endif
+ /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ ** Replicate in sqlite3VdbeAddOp3() */
+
+ return i;
}
/* Generate code for an unconditional jump to instruction iDest
@@ -82807,10 +84913,10 @@ SQLITE_PRIVATE void sqlite3ExplainBreakpoint(const char *z1, const char *z2){
*/
SQLITE_PRIVATE int sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){
int addr = 0;
-#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+#if !defined(SQLITE_DEBUG)
/* Always include the OP_Explain opcodes if SQLITE_DEBUG is defined.
** But omit them (for performance) during production builds */
- if( pParse->explain==2 )
+ if( pParse->explain==2 || IS_STMT_SCANSTATUS(pParse->db) )
#endif
{
char *zMsg;
@@ -82828,7 +84934,7 @@ SQLITE_PRIVATE int sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt,
if( bPush){
pParse->addrExplain = iThis;
}
- sqlite3VdbeScanStatus(v, iThis, 0, 0, 0, 0);
+ sqlite3VdbeScanStatus(v, iThis, -1, -1, 0, 0);
}
return addr;
}
@@ -82858,26 +84964,6 @@ SQLITE_PRIVATE void sqlite3VdbeAddParseSchemaOp(Vdbe *p, int iDb, char *zWhere,
sqlite3MayAbort(p->pParse);
}
-/*
-** Add an opcode that includes the p4 value as an integer.
-*/
-SQLITE_PRIVATE int sqlite3VdbeAddOp4Int(
- Vdbe *p, /* Add the opcode to this VM */
- int op, /* The new opcode */
- int p1, /* The P1 operand */
- int p2, /* The P2 operand */
- int p3, /* The P3 operand */
- int p4 /* The P4 operand as an integer */
-){
- int addr = sqlite3VdbeAddOp3(p, op, p1, p2, p3);
- if( p->db->mallocFailed==0 ){
- VdbeOp *pOp = &p->aOp[addr];
- pOp->p4type = P4_INT32;
- pOp->p4.i = p4;
- }
- return addr;
-}
-
/* Insert the end of a co-routine
*/
SQLITE_PRIVATE void sqlite3VdbeEndCoroutine(Vdbe *v, int regYield){
@@ -83184,11 +85270,13 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
Op *pOp;
Parse *pParse = p->pParse;
int *aLabel = pParse->aLabel;
+
+ assert( pParse->db->mallocFailed==0 ); /* tag-20230419-1 */
p->readOnly = 1;
p->bIsReader = 0;
pOp = &p->aOp[p->nOp-1];
assert( p->aOp[0].opcode==OP_Init );
- while( 1 /* Loop termates when it reaches the OP_Init opcode */ ){
+ while( 1 /* Loop terminates when it reaches the OP_Init opcode */ ){
/* 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
@@ -83243,6 +85331,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
** have non-negative values for P2. */
assert( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 );
assert( ADDR(pOp->p2)<-pParse->nLabel );
+ assert( aLabel!=0 ); /* True because of tag-20230419-1 */
pOp->p2 = aLabel[ADDR(pOp->p2)];
}
break;
@@ -83309,6 +85398,10 @@ SQLITE_PRIVATE void sqlite3VdbeNoJumpsOutsideSubrtn(
int iDest = pOp->p2; /* Jump destination */
if( iDest==0 ) continue;
if( pOp->opcode==OP_Gosub ) continue;
+ if( pOp->p3==20230325 && pOp->opcode==OP_NotNull ){
+ /* This is a deliberately taken illegal branch. tag-20230325-2 */
+ continue;
+ }
if( iDest<0 ){
int j = ADDR(iDest);
assert( j>=0 );
@@ -83486,18 +85579,20 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(
LogEst nEst, /* Estimated number of output rows */
const char *zName /* Name of table or index being scanned */
){
- sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus);
- ScanStatus *aNew;
- aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte);
- if( aNew ){
- ScanStatus *pNew = &aNew[p->nScan++];
- memset(pNew, 0, sizeof(ScanStatus));
- pNew->addrExplain = addrExplain;
- pNew->addrLoop = addrLoop;
- pNew->addrVisit = addrVisit;
- pNew->nEst = nEst;
- pNew->zName = sqlite3DbStrDup(p->db, zName);
- p->aScan = aNew;
+ if( IS_STMT_SCANSTATUS(p->db) ){
+ sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus);
+ ScanStatus *aNew;
+ aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte);
+ if( aNew ){
+ ScanStatus *pNew = &aNew[p->nScan++];
+ memset(pNew, 0, sizeof(ScanStatus));
+ pNew->addrExplain = addrExplain;
+ pNew->addrLoop = addrLoop;
+ pNew->addrVisit = addrVisit;
+ pNew->nEst = nEst;
+ pNew->zName = sqlite3DbStrDup(p->db, zName);
+ p->aScan = aNew;
+ }
}
}
@@ -83514,20 +85609,22 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatusRange(
int addrStart,
int addrEnd
){
- ScanStatus *pScan = 0;
- int ii;
- for(ii=p->nScan-1; ii>=0; ii--){
- pScan = &p->aScan[ii];
- if( pScan->addrExplain==addrExplain ) break;
- pScan = 0;
- }
- if( pScan ){
- if( addrEnd<0 ) addrEnd = sqlite3VdbeCurrentAddr(p)-1;
- for(ii=0; ii<ArraySize(pScan->aAddrRange); ii+=2){
- if( pScan->aAddrRange[ii]==0 ){
- pScan->aAddrRange[ii] = addrStart;
- pScan->aAddrRange[ii+1] = addrEnd;
- break;
+ if( IS_STMT_SCANSTATUS(p->db) ){
+ ScanStatus *pScan = 0;
+ int ii;
+ for(ii=p->nScan-1; ii>=0; ii--){
+ pScan = &p->aScan[ii];
+ if( pScan->addrExplain==addrExplain ) break;
+ pScan = 0;
+ }
+ if( pScan ){
+ if( addrEnd<0 ) addrEnd = sqlite3VdbeCurrentAddr(p)-1;
+ for(ii=0; ii<ArraySize(pScan->aAddrRange); ii+=2){
+ if( pScan->aAddrRange[ii]==0 ){
+ pScan->aAddrRange[ii] = addrStart;
+ pScan->aAddrRange[ii+1] = addrEnd;
+ break;
+ }
}
}
}
@@ -83544,19 +85641,21 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatusCounters(
int addrLoop,
int addrVisit
){
- ScanStatus *pScan = 0;
- int ii;
- for(ii=p->nScan-1; ii>=0; ii--){
- pScan = &p->aScan[ii];
- if( pScan->addrExplain==addrExplain ) break;
- pScan = 0;
- }
- if( pScan ){
- pScan->addrLoop = addrLoop;
- pScan->addrVisit = addrVisit;
+ if( IS_STMT_SCANSTATUS(p->db) ){
+ ScanStatus *pScan = 0;
+ int ii;
+ for(ii=p->nScan-1; ii>=0; ii--){
+ pScan = &p->aScan[ii];
+ if( pScan->addrExplain==addrExplain ) break;
+ pScan = 0;
+ }
+ if( pScan ){
+ if( addrLoop>0 ) pScan->addrLoop = addrLoop;
+ if( addrVisit>0 ) pScan->addrVisit = addrVisit;
+ }
}
}
-#endif
+#endif /* defined(SQLITE_ENABLE_STMT_SCANSTATUS) */
/*
@@ -83635,7 +85734,7 @@ SQLITE_PRIVATE void sqlite3VdbeJumpHereOrPopInst(Vdbe *p, int addr){
/*
** If the input FuncDef structure is ephemeral, then free it. If
-** the FuncDef is not ephermal, then do nothing.
+** the FuncDef is not ephemeral, then do nothing.
*/
static void freeEphemeralFunction(sqlite3 *db, FuncDef *pDef){
assert( db!=0 );
@@ -83696,6 +85795,10 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
if( db->pnBytesFreed==0 ) sqlite3VtabUnlock((VTable *)p4);
break;
}
+ case P4_TABLEREF: {
+ if( db->pnBytesFreed==0 ) sqlite3DeleteTable(db, (Table*)p4);
+ break;
+ }
}
}
@@ -83799,7 +85902,6 @@ SQLITE_PRIVATE void sqlite3VdbeReleaseRegisters(
}
#endif /* SQLITE_DEBUG */
-
/*
** Change the value of the P4 operand for a specific instruction.
** This routine is useful when a large program is loaded from a
@@ -83824,7 +85926,7 @@ static void SQLITE_NOINLINE vdbeChangeP4Full(
int n
){
if( pOp->p4type ){
- freeP4(p->db, pOp->p4type, pOp->p4.p);
+ assert( pOp->p4type > P4_FREE_IF_LE );
pOp->p4type = 0;
pOp->p4.p = 0;
}
@@ -83980,7 +86082,7 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
/* Return the most recently added opcode
*/
-VdbeOp * sqlite3VdbeGetLastOp(Vdbe *p){
+SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetLastOp(Vdbe *p){
return sqlite3VdbeGetOp(p, p->nOp - 1);
}
@@ -84720,7 +86822,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
sqlite3VdbeMemSetInt64(pMem+1, pOp->p2);
sqlite3VdbeMemSetInt64(pMem+2, pOp->p3);
sqlite3VdbeMemSetStr(pMem+3, zP4, -1, SQLITE_UTF8, sqlite3_free);
- p->nResColumn = 4;
+ assert( p->nResColumn==4 );
}else{
sqlite3VdbeMemSetInt64(pMem+0, i);
sqlite3VdbeMemSetStr(pMem+1, (char*)sqlite3OpcodeName(pOp->opcode),
@@ -84739,7 +86841,7 @@ SQLITE_PRIVATE int sqlite3VdbeList(
sqlite3VdbeMemSetNull(pMem+7);
#endif
sqlite3VdbeMemSetStr(pMem+5, zP4, -1, SQLITE_UTF8, sqlite3_free);
- p->nResColumn = 8;
+ assert( p->nResColumn==8 );
}
p->pResultRow = pMem;
if( db->mallocFailed ){
@@ -84953,26 +87055,9 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
resolveP2Values(p, &nArg);
p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort);
if( pParse->explain ){
- static const char * const azColName[] = {
- "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
- "id", "parent", "notused", "detail"
- };
- int iFirst, mx, i;
if( nMem<10 ) nMem = 10;
p->explain = pParse->explain;
- if( pParse->explain==2 ){
- sqlite3VdbeSetNumCols(p, 4);
- iFirst = 8;
- mx = 12;
- }else{
- sqlite3VdbeSetNumCols(p, 8);
- iFirst = 0;
- mx = 8;
- }
- for(i=iFirst; i<mx; i++){
- sqlite3VdbeSetColName(p, i-iFirst, COLNAME_NAME,
- azColName[i], SQLITE_STATIC);
- }
+ p->nResColumn = 12 - 4*p->explain;
}
p->expired = 0;
@@ -85024,7 +87109,23 @@ SQLITE_PRIVATE void sqlite3VdbeMakeReady(
SQLITE_PRIVATE void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
if( pCx ) sqlite3VdbeFreeCursorNN(p,pCx);
}
+static SQLITE_NOINLINE void freeCursorWithCache(Vdbe *p, VdbeCursor *pCx){
+ VdbeTxtBlbCache *pCache = pCx->pCache;
+ assert( pCx->colCache );
+ pCx->colCache = 0;
+ pCx->pCache = 0;
+ if( pCache->pCValue ){
+ sqlite3RCStrUnref(pCache->pCValue);
+ pCache->pCValue = 0;
+ }
+ sqlite3DbFree(p->db, pCache);
+ sqlite3VdbeFreeCursorNN(p, pCx);
+}
SQLITE_PRIVATE void sqlite3VdbeFreeCursorNN(Vdbe *p, VdbeCursor *pCx){
+ if( pCx->colCache ){
+ freeCursorWithCache(p, pCx);
+ return;
+ }
switch( pCx->eCurType ){
case CURTYPE_SORTER: {
sqlite3VdbeSorterClose(p->db, pCx);
@@ -85125,12 +87226,12 @@ SQLITE_PRIVATE void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){
int n;
sqlite3 *db = p->db;
- if( p->nResColumn ){
- releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
+ if( p->nResAlloc ){
+ releaseMemArray(p->aColName, p->nResAlloc*COLNAME_N);
sqlite3DbFree(db, p->aColName);
}
n = nResColumn*COLNAME_N;
- p->nResColumn = (u16)nResColumn;
+ p->nResColumn = p->nResAlloc = (u16)nResColumn;
p->aColName = (Mem*)sqlite3DbMallocRawNN(db, sizeof(Mem)*n );
if( p->aColName==0 ) return;
initMemArray(p->aColName, n, db, MEM_Null);
@@ -85155,14 +87256,14 @@ SQLITE_PRIVATE int sqlite3VdbeSetColName(
){
int rc;
Mem *pColName;
- assert( idx<p->nResColumn );
+ assert( idx<p->nResAlloc );
assert( var<COLNAME_N );
if( p->db->mallocFailed ){
assert( !zName || xDel!=SQLITE_DYNAMIC );
return SQLITE_NOMEM_BKPT;
}
assert( p->aColName!=0 );
- pColName = &(p->aColName[idx+var*p->nResColumn]);
+ pColName = &(p->aColName[idx+var*p->nResAlloc]);
rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, xDel);
assert( rc!=0 || !zName || (pColName->flags&MEM_Term)!=0 );
return rc;
@@ -85675,6 +87776,7 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
sqlite3VdbeLeave(p);
return SQLITE_BUSY;
}else if( rc!=SQLITE_OK ){
+ sqlite3SystemError(db, rc);
p->rc = rc;
sqlite3RollbackAll(db, SQLITE_OK);
p->nChange = 0;
@@ -85684,6 +87786,8 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
db->flags &= ~(u64)SQLITE_DeferFKs;
sqlite3CommitInternalChanges(db);
}
+ }else if( p->rc==SQLITE_SCHEMA && db->nVdbeActive>1 ){
+ p->nChange = 0;
}else{
sqlite3RollbackAll(db, SQLITE_OK);
p->nChange = 0;
@@ -85984,7 +88088,7 @@ static void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
assert( db!=0 );
assert( p->db==0 || p->db==db );
if( p->aColName ){
- releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
+ releaseMemArray(p->aColName, p->nResAlloc*COLNAME_N);
sqlite3DbNNFreeNN(db, p->aColName);
}
for(pSub=p->pProgram; pSub; pSub=pNext){
@@ -86002,9 +88106,9 @@ static void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
#ifdef SQLITE_ENABLE_NORMALIZE
sqlite3DbFree(db, p->zNormSql);
{
- DblquoteStr *pThis, *pNext;
- for(pThis=p->pDblStr; pThis; pThis=pNext){
- pNext = pThis->pNextStr;
+ DblquoteStr *pThis, *pNxt;
+ for(pThis=p->pDblStr; pThis; pThis=pNxt){
+ pNxt = pThis->pNextStr;
sqlite3DbFree(db, pThis);
}
}
@@ -86351,6 +88455,23 @@ static void serialGet(
pMem->flags = IsNaN(x) ? MEM_Null : MEM_Real;
}
}
+static int serialGet7(
+ const unsigned char *buf, /* Buffer to deserialize from */
+ Mem *pMem /* Memory cell to write value into */
+){
+ u64 x = FOUR_BYTE_UINT(buf);
+ u32 y = FOUR_BYTE_UINT(buf+4);
+ x = (x<<32) + y;
+ assert( sizeof(x)==8 && sizeof(pMem->u.r)==8 );
+ swapMixedEndianFloat(x);
+ memcpy(&pMem->u.r, &x, sizeof(x));
+ if( IsNaN(x) ){
+ pMem->flags = MEM_Null;
+ return 1;
+ }
+ pMem->flags = MEM_Real;
+ return 0;
+}
SQLITE_PRIVATE void sqlite3VdbeSerialGet(
const unsigned char *buf, /* Buffer to deserialize from */
u32 serial_type, /* Serial type to deserialize */
@@ -86584,6 +88705,15 @@ static int vdbeRecordCompareDebug(
if( d1+(u64)serial_type1+2>(u64)nKey1
&& d1+(u64)sqlite3VdbeSerialTypeLen(serial_type1)>(u64)nKey1
){
+ if( serial_type1>=1
+ && serial_type1<=7
+ && d1+(u64)sqlite3VdbeSerialTypeLen(serial_type1)<=(u64)nKey1+8
+ && CORRUPT_DB
+ ){
+ return 1; /* corrupt record not detected by
+ ** sqlite3VdbeRecordCompareWithSkip(). Return true
+ ** to avoid firing the assert() */
+ }
break;
}
@@ -86752,20 +88882,33 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3BlobCompare(const Mem *pB1, const Mem
return n1 - n2;
}
+/* The following two functions are used only within testcase() to prove
+** test coverage. These functions do no exist for production builds.
+** We must use separate SQLITE_NOINLINE functions here, since otherwise
+** optimizer code movement causes gcov to become very confused.
+*/
+#if defined(SQLITE_COVERAGE_TEST) || defined(SQLITE_DEBUG)
+static int SQLITE_NOINLINE doubleLt(double a, double b){ return a<b; }
+static int SQLITE_NOINLINE doubleEq(double a, double b){ return a==b; }
+#endif
+
/*
** Do a comparison between a 64-bit signed integer and a 64-bit floating-point
** number. Return negative, zero, or positive if the first (i64) is less than,
** equal to, or greater than the second (double).
*/
SQLITE_PRIVATE int sqlite3IntFloatCompare(i64 i, double r){
- if( sizeof(LONGDOUBLE_TYPE)>8 ){
+ if( sqlite3IsNaN(r) ){
+ /* SQLite considers NaN to be a NULL. And all integer values are greater
+ ** than NULL */
+ return 1;
+ }
+ if( sqlite3Config.bUseLongDouble ){
LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i;
testcase( x<r );
testcase( x>r );
testcase( x==r );
- if( x<r ) return -1;
- if( x>r ) return +1; /*NO_TEST*/ /* work around bugs in gcov */
- return 0; /*NO_TEST*/ /* work around bugs in gcov */
+ return (x<r) ? -1 : (x>r);
}else{
i64 y;
double s;
@@ -86775,9 +88918,10 @@ SQLITE_PRIVATE int sqlite3IntFloatCompare(i64 i, double r){
if( i<y ) return -1;
if( i>y ) return +1;
s = (double)i;
- if( s<r ) return -1;
- if( s>r ) return +1;
- return 0;
+ testcase( doubleLt(s,r) );
+ testcase( doubleLt(r,s) );
+ testcase( doubleEq(r,s) );
+ return (s<r) ? -1 : (s>r);
}
}
@@ -87007,7 +89151,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
}else if( serial_type==0 ){
rc = -1;
}else if( serial_type==7 ){
- sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
+ serialGet7(&aKey1[d1], &mem1);
rc = -sqlite3IntFloatCompare(pRhs->u.i, mem1.u.r);
}else{
i64 lhs = vdbeRecordDecodeInt(serial_type, &aKey1[d1]);
@@ -87027,19 +89171,23 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
/* Serial types 12 or greater are strings and blobs (greater than
** numbers). Types 10 and 11 are currently "reserved for future
** use", so it doesn't really matter what the results of comparing
- ** them to numberic values are. */
+ ** them to numeric values are. */
rc = serial_type==10 ? -1 : +1;
}else if( serial_type==0 ){
rc = -1;
}else{
- sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
if( serial_type==7 ){
- if( mem1.u.r<pRhs->u.r ){
+ if( serialGet7(&aKey1[d1], &mem1) ){
+ rc = -1; /* mem1 is a NaN */
+ }else if( mem1.u.r<pRhs->u.r ){
rc = -1;
}else if( mem1.u.r>pRhs->u.r ){
rc = +1;
+ }else{
+ assert( rc==0 );
}
}else{
+ sqlite3VdbeSerialGet(&aKey1[d1], serial_type, &mem1);
rc = sqlite3IntFloatCompare(mem1.u.i, pRhs->u.r);
}
}
@@ -87109,7 +89257,14 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompareWithSkip(
/* RHS is null */
else{
serial_type = aKey1[idx1];
- rc = (serial_type!=0 && serial_type!=10);
+ if( serial_type==0
+ || serial_type==10
+ || (serial_type==7 && serialGet7(&aKey1[d1], &mem1)!=0)
+ ){
+ assert( rc==0 );
+ }else{
+ rc = 1;
+ }
}
if( rc!=0 ){
@@ -87631,6 +89786,20 @@ SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context *pCtx){
return 1;
}
+#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG)
+/*
+** This Walker callback is used to help verify that calls to
+** sqlite3BtreeCursorHint() with opcode BTREE_HINT_RANGE have
+** byte-code register values correctly initialized.
+*/
+SQLITE_PRIVATE int sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op==TK_REGISTER ){
+ assert( (pWalker->u.aMem[pExpr->iTable].flags & MEM_Undefined)==0 );
+ }
+ return WRC_Continue;
+}
+#endif /* SQLITE_ENABLE_CURSOR_HINTS && SQLITE_DEBUG */
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored
@@ -87693,6 +89862,16 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
PreUpdate preupdate;
const char *zTbl = pTab->zName;
static const u8 fakeSortOrder = 0;
+#ifdef SQLITE_DEBUG
+ int nRealCol;
+ if( pTab->tabFlags & TF_WithoutRowid ){
+ nRealCol = sqlite3PrimaryKeyIndex(pTab)->nColumn;
+ }else if( pTab->tabFlags & TF_HasVirtual ){
+ nRealCol = pTab->nNVCol;
+ }else{
+ nRealCol = pTab->nCol;
+ }
+#endif
assert( db->pPreUpdate==0 );
memset(&preupdate, 0, sizeof(PreUpdate));
@@ -87709,8 +89888,8 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
assert( pCsr!=0 );
assert( pCsr->eCurType==CURTYPE_BTREE );
- assert( pCsr->nField==pTab->nCol
- || (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1)
+ assert( pCsr->nField==nRealCol
+ || (pCsr->nField==nRealCol+1 && op==SQLITE_DELETE && iReg==-1)
);
preupdate.v = v;
@@ -87898,7 +90077,15 @@ SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
int rc = SQLITE_OK;
Vdbe *p = (Vdbe*)pStmt;
#if SQLITE_THREADSAFE
- sqlite3_mutex *mutex = ((Vdbe*)pStmt)->db->mutex;
+ sqlite3_mutex *mutex;
+#endif
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pStmt==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+#if SQLITE_THREADSAFE
+ mutex = p->db->mutex;
#endif
sqlite3_mutex_enter(mutex);
for(i=0; i<p->nVar; i++){
@@ -88017,7 +90204,7 @@ SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){
SQLITE_NULL, /* 0x1f (not possible) */
SQLITE_FLOAT, /* 0x20 INTREAL */
SQLITE_NULL, /* 0x21 (not possible) */
- SQLITE_TEXT, /* 0x22 INTREAL + TEXT */
+ SQLITE_FLOAT, /* 0x22 INTREAL + TEXT */
SQLITE_NULL, /* 0x23 (not possible) */
SQLITE_FLOAT, /* 0x24 (not possible) */
SQLITE_NULL, /* 0x25 (not possible) */
@@ -88121,7 +90308,7 @@ SQLITE_API void sqlite3_value_free(sqlite3_value *pOld){
** is too big or if an OOM occurs.
**
** The invokeValueDestructor(P,X) routine invokes destructor function X()
-** on value P is not going to be used and need to be destroyed.
+** on value P if P is not going to be used and need to be destroyed.
*/
static void setResultStrOrError(
sqlite3_context *pCtx, /* Function context */
@@ -88151,7 +90338,7 @@ static void setResultStrOrError(
static int invokeValueDestructor(
const void *p, /* Value to destroy */
void (*xDel)(void*), /* The destructor */
- sqlite3_context *pCtx /* Set a SQLITE_TOOBIG error if no NULL */
+ sqlite3_context *pCtx /* Set a SQLITE_TOOBIG error if not NULL */
){
assert( xDel!=SQLITE_DYNAMIC );
if( xDel==0 ){
@@ -88161,7 +90348,14 @@ static int invokeValueDestructor(
}else{
xDel((void*)p);
}
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx!=0 ){
+ sqlite3_result_error_toobig(pCtx);
+ }
+#else
+ assert( pCtx!=0 );
sqlite3_result_error_toobig(pCtx);
+#endif
return SQLITE_TOOBIG;
}
SQLITE_API void sqlite3_result_blob(
@@ -88170,6 +90364,12 @@ SQLITE_API void sqlite3_result_blob(
int n,
void (*xDel)(void *)
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 || n<0 ){
+ invokeValueDestructor(z, xDel, pCtx);
+ return;
+ }
+#endif
assert( n>=0 );
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, 0, xDel);
@@ -88180,8 +90380,14 @@ SQLITE_API void sqlite3_result_blob64(
sqlite3_uint64 n,
void (*xDel)(void *)
){
- assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
assert( xDel!=SQLITE_DYNAMIC );
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ){
+ invokeValueDestructor(z, xDel, 0);
+ return;
+ }
+#endif
+ assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
if( n>0x7fffffff ){
(void)invokeValueDestructor(z, xDel, pCtx);
}else{
@@ -88189,30 +90395,48 @@ SQLITE_API void sqlite3_result_blob64(
}
}
SQLITE_API void sqlite3_result_double(sqlite3_context *pCtx, double rVal){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetDouble(pCtx->pOut, rVal);
}
SQLITE_API void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_ERROR;
sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF8, SQLITE_TRANSIENT);
}
#ifndef SQLITE_OMIT_UTF16
SQLITE_API void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_ERROR;
sqlite3VdbeMemSetStr(pCtx->pOut, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT);
}
#endif
SQLITE_API void sqlite3_result_int(sqlite3_context *pCtx, int iVal){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetInt64(pCtx->pOut, (i64)iVal);
}
SQLITE_API void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetInt64(pCtx->pOut, iVal);
}
SQLITE_API void sqlite3_result_null(sqlite3_context *pCtx){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetNull(pCtx->pOut);
}
@@ -88222,14 +90446,37 @@ SQLITE_API void sqlite3_result_pointer(
const char *zPType,
void (*xDestructor)(void*)
){
- Mem *pOut = pCtx->pOut;
+ Mem *pOut;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ){
+ invokeValueDestructor(pPtr, xDestructor, 0);
+ return;
+ }
+#endif
+ pOut = pCtx->pOut;
assert( sqlite3_mutex_held(pOut->db->mutex) );
sqlite3VdbeMemRelease(pOut);
pOut->flags = MEM_Null;
sqlite3VdbeMemSetPointer(pOut, pPtr, zPType, xDestructor);
}
SQLITE_API void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){
- Mem *pOut = pCtx->pOut;
+ Mem *pOut;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
+#if defined(SQLITE_STRICT_SUBTYPE) && SQLITE_STRICT_SUBTYPE+0!=0
+ if( pCtx->pFunc!=0
+ && (pCtx->pFunc->funcFlags & SQLITE_RESULT_SUBTYPE)==0
+ ){
+ char zErr[200];
+ sqlite3_snprintf(sizeof(zErr), zErr,
+ "misuse of sqlite3_result_subtype() by %s()",
+ pCtx->pFunc->zName);
+ sqlite3_result_error(pCtx, zErr, -1);
+ return;
+ }
+#endif /* SQLITE_STRICT_SUBTYPE */
+ pOut = pCtx->pOut;
assert( sqlite3_mutex_held(pOut->db->mutex) );
pOut->eSubtype = eSubtype & 0xff;
pOut->flags |= MEM_Subtype;
@@ -88240,6 +90487,12 @@ SQLITE_API void sqlite3_result_text(
int n,
void (*xDel)(void *)
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ){
+ invokeValueDestructor(z, xDel, 0);
+ return;
+ }
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
setResultStrOrError(pCtx, z, n, SQLITE_UTF8, xDel);
}
@@ -88250,6 +90503,12 @@ SQLITE_API void sqlite3_result_text64(
void (*xDel)(void *),
unsigned char enc
){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ){
+ invokeValueDestructor(z, xDel, 0);
+ return;
+ }
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
assert( xDel!=SQLITE_DYNAMIC );
if( enc!=SQLITE_UTF8 ){
@@ -88260,6 +90519,7 @@ SQLITE_API void sqlite3_result_text64(
(void)invokeValueDestructor(z, xDel, pCtx);
}else{
setResultStrOrError(pCtx, z, (int)n, enc, xDel);
+ sqlite3VdbeMemZeroTerminateIfAble(pCtx->pOut);
}
}
#ifndef SQLITE_OMIT_UTF16
@@ -88292,7 +90552,16 @@ SQLITE_API void sqlite3_result_text16le(
}
#endif /* SQLITE_OMIT_UTF16 */
SQLITE_API void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
- Mem *pOut = pCtx->pOut;
+ Mem *pOut;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+ if( pValue==0 ){
+ sqlite3_result_null(pCtx);
+ return;
+ }
+#endif
+ pOut = pCtx->pOut;
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemCopy(pOut, pValue);
sqlite3VdbeChangeEncoding(pOut, pCtx->enc);
@@ -88304,7 +90573,12 @@ SQLITE_API void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){
sqlite3_result_zeroblob64(pCtx, n>0 ? n : 0);
}
SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){
- Mem *pOut = pCtx->pOut;
+ Mem *pOut;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return SQLITE_MISUSE_BKPT;
+#endif
+ pOut = pCtx->pOut;
assert( sqlite3_mutex_held(pOut->db->mutex) );
if( n>(u64)pOut->db->aLimit[SQLITE_LIMIT_LENGTH] ){
sqlite3_result_error_toobig(pCtx);
@@ -88318,6 +90592,9 @@ SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context *pCtx, u64 n){
#endif
}
SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
pCtx->isError = errCode ? errCode : -1;
#ifdef SQLITE_DEBUG
if( pCtx->pVdbe ) pCtx->pVdbe->rcApp = errCode;
@@ -88330,6 +90607,9 @@ SQLITE_API void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){
/* Force an SQLITE_TOOBIG error. */
SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
pCtx->isError = SQLITE_TOOBIG;
sqlite3VdbeMemSetStr(pCtx->pOut, "string or blob too big", -1,
@@ -88338,6 +90618,9 @@ SQLITE_API void sqlite3_result_error_toobig(sqlite3_context *pCtx){
/* An SQLITE_NOMEM error. */
SQLITE_API void sqlite3_result_error_nomem(sqlite3_context *pCtx){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
sqlite3VdbeMemSetNull(pCtx->pOut);
pCtx->isError = SQLITE_NOMEM_BKPT;
@@ -88590,6 +90873,9 @@ SQLITE_API int sqlite3_step(sqlite3_stmt *pStmt){
** pointer to it.
*/
SQLITE_API void *sqlite3_user_data(sqlite3_context *p){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ) return 0;
+#endif
assert( p && p->pFunc );
return p->pFunc->pUserData;
}
@@ -88605,7 +90891,11 @@ SQLITE_API void *sqlite3_user_data(sqlite3_context *p){
** application defined function.
*/
SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ) return 0;
+#else
assert( p && p->pOut );
+#endif
return p->pOut->db;
}
@@ -88624,7 +90914,11 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){
** value, as a signal to the xUpdate routine that the column is unchanged.
*/
SQLITE_API int sqlite3_vtab_nochange(sqlite3_context *p){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ) return 0;
+#else
assert( p );
+#endif
return sqlite3_value_nochange(p->pOut);
}
@@ -88632,7 +90926,7 @@ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context *p){
** The destructor function for a ValueList object. This needs to be
** a separate function, unknowable to the application, to ensure that
** calls to sqlite3_vtab_in_first()/sqlite3_vtab_in_next() that are not
-** preceeded by activation of IN processing via sqlite3_vtab_int() do not
+** preceded by activation of IN processing via sqlite3_vtab_int() do not
** try to access a fake ValueList object inserted by a hostile extension.
*/
SQLITE_PRIVATE void sqlite3VdbeValueListFree(void *pToDelete){
@@ -88652,7 +90946,7 @@ static int valueFromValueList(
ValueList *pRhs;
*ppOut = 0;
- if( pVal==0 ) return SQLITE_MISUSE;
+ if( pVal==0 ) return SQLITE_MISUSE_BKPT;
if( (pVal->flags & MEM_Dyn)==0 || pVal->xDel!=sqlite3VdbeValueListFree ){
return SQLITE_ERROR;
}else{
@@ -88783,6 +91077,9 @@ SQLITE_API void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
SQLITE_API void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){
AuxData *pAuxData;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return 0;
+#endif
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
#if SQLITE_ENABLE_STAT4
if( pCtx->pVdbe==0 ) return 0;
@@ -88815,8 +91112,12 @@ SQLITE_API void sqlite3_set_auxdata(
void (*xDelete)(void*)
){
AuxData *pAuxData;
- Vdbe *pVdbe = pCtx->pVdbe;
+ Vdbe *pVdbe;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pCtx==0 ) return;
+#endif
+ pVdbe= pCtx->pVdbe;
assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) );
#ifdef SQLITE_ENABLE_STAT4
if( pVdbe==0 ) goto failed;
@@ -88872,7 +91173,8 @@ SQLITE_API int sqlite3_aggregate_count(sqlite3_context *p){
*/
SQLITE_API int sqlite3_column_count(sqlite3_stmt *pStmt){
Vdbe *pVm = (Vdbe *)pStmt;
- return pVm ? pVm->nResColumn : 0;
+ if( pVm==0 ) return 0;
+ return pVm->nResColumn;
}
/*
@@ -88961,7 +91263,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
** sqlite3_column_real()
** sqlite3_column_bytes()
** sqlite3_column_bytes16()
-** sqiite3_column_blob()
+** sqlite3_column_blob()
*/
static void columnMallocFailure(sqlite3_stmt *pStmt)
{
@@ -89046,6 +91348,32 @@ SQLITE_API int sqlite3_column_type(sqlite3_stmt *pStmt, int i){
}
/*
+** Column names appropriate for EXPLAIN or EXPLAIN QUERY PLAN.
+*/
+static const char * const azExplainColNames8[] = {
+ "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment", /* EXPLAIN */
+ "id", "parent", "notused", "detail" /* EQP */
+};
+static const u16 azExplainColNames16data[] = {
+ /* 0 */ 'a', 'd', 'd', 'r', 0,
+ /* 5 */ 'o', 'p', 'c', 'o', 'd', 'e', 0,
+ /* 12 */ 'p', '1', 0,
+ /* 15 */ 'p', '2', 0,
+ /* 18 */ 'p', '3', 0,
+ /* 21 */ 'p', '4', 0,
+ /* 24 */ 'p', '5', 0,
+ /* 27 */ 'c', 'o', 'm', 'm', 'e', 'n', 't', 0,
+ /* 35 */ 'i', 'd', 0,
+ /* 38 */ 'p', 'a', 'r', 'e', 'n', 't', 0,
+ /* 45 */ 'n', 'o', 't', 'u', 's', 'e', 'd', 0,
+ /* 53 */ 'd', 'e', 't', 'a', 'i', 'l', 0
+};
+static const u8 iExplainColNames16[] = {
+ 0, 5, 12, 15, 18, 21, 24, 27,
+ 35, 38, 45, 53
+};
+
+/*
** Convert the N-th element of pStmt->pColName[] into a string using
** xFunc() then return that string. If N is out of range, return 0.
**
@@ -89077,15 +91405,29 @@ static const void *columnName(
return 0;
}
#endif
+ if( N<0 ) return 0;
ret = 0;
p = (Vdbe *)pStmt;
db = p->db;
assert( db!=0 );
- n = sqlite3_column_count(pStmt);
- if( N<n && N>=0 ){
+ sqlite3_mutex_enter(db->mutex);
+
+ if( p->explain ){
+ if( useType>0 ) goto columnName_end;
+ n = p->explain==1 ? 8 : 4;
+ if( N>=n ) goto columnName_end;
+ if( useUtf16 ){
+ int i = iExplainColNames16[N + 8*p->explain - 8];
+ ret = (void*)&azExplainColNames16data[i];
+ }else{
+ ret = (void*)azExplainColNames8[N + 8*p->explain - 8];
+ }
+ goto columnName_end;
+ }
+ n = p->nResColumn;
+ if( N<n ){
+ u8 prior_mallocFailed = db->mallocFailed;
N += useType*n;
- sqlite3_mutex_enter(db->mutex);
- assert( db->mallocFailed==0 );
#ifndef SQLITE_OMIT_UTF16
if( useUtf16 ){
ret = sqlite3_value_text16((sqlite3_value*)&p->aColName[N]);
@@ -89097,12 +91439,14 @@ static const void *columnName(
/* A malloc may have failed inside of the _text() call. If this
** is the case, clear the mallocFailed flag and return NULL.
*/
- if( db->mallocFailed ){
+ assert( db->mallocFailed==0 || db->mallocFailed==1 );
+ if( db->mallocFailed > prior_mallocFailed ){
sqlite3OomClear(db);
ret = 0;
}
- sqlite3_mutex_leave(db->mutex);
}
+columnName_end:
+ sqlite3_mutex_leave(db->mutex);
return ret;
}
@@ -89195,7 +91539,7 @@ SQLITE_API const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N){
/*
** Unbind the value bound to variable i in virtual machine p. This is the
** the same as binding a NULL value to the column. If the "i" parameter is
-** out of range, then SQLITE_RANGE is returned. Othewise SQLITE_OK.
+** out of range, then SQLITE_RANGE is returned. Otherwise SQLITE_OK.
**
** A successful evaluation of this routine acquires the mutex on p.
** the mutex is released if any kind of error occurs.
@@ -89210,7 +91554,7 @@ static int vdbeUnbind(Vdbe *p, unsigned int i){
}
sqlite3_mutex_enter(p->db->mutex);
if( p->eVdbeState!=VDBE_READY_STATE ){
- sqlite3Error(p->db, SQLITE_MISUSE);
+ sqlite3Error(p->db, SQLITE_MISUSE_BKPT);
sqlite3_mutex_leave(p->db->mutex);
sqlite3_log(SQLITE_MISUSE,
"bind on a busy prepared statement: [%s]", p->zSql);
@@ -89439,6 +91783,9 @@ SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt *pStmt, int i, int n){
SQLITE_API int sqlite3_bind_zeroblob64(sqlite3_stmt *pStmt, int i, sqlite3_uint64 n){
int rc;
Vdbe *p = (Vdbe *)pStmt;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(p->db->mutex);
if( n>(u64)p->db->aLimit[SQLITE_LIMIT_LENGTH] ){
rc = SQLITE_TOOBIG;
@@ -89560,6 +91907,42 @@ SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt){
}
/*
+** Set the explain mode for a statement.
+*/
+SQLITE_API int sqlite3_stmt_explain(sqlite3_stmt *pStmt, int eMode){
+ Vdbe *v = (Vdbe*)pStmt;
+ int rc;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( pStmt==0 ) return SQLITE_MISUSE_BKPT;
+#endif
+ sqlite3_mutex_enter(v->db->mutex);
+ if( ((int)v->explain)==eMode ){
+ rc = SQLITE_OK;
+ }else if( eMode<0 || eMode>2 ){
+ rc = SQLITE_ERROR;
+ }else if( (v->prepFlags & SQLITE_PREPARE_SAVESQL)==0 ){
+ rc = SQLITE_ERROR;
+ }else if( v->eVdbeState!=VDBE_READY_STATE ){
+ rc = SQLITE_BUSY;
+ }else if( v->nMem>=10 && (eMode!=2 || v->haveEqpOps) ){
+ /* No reprepare necessary */
+ v->explain = eMode;
+ rc = SQLITE_OK;
+ }else{
+ v->explain = eMode;
+ rc = sqlite3Reprepare(v);
+ v->haveEqpOps = eMode==2;
+ }
+ if( v->explain ){
+ v->nResColumn = 12 - 4*v->explain;
+ }else{
+ v->nResColumn = v->nResAlloc;
+ }
+ sqlite3_mutex_leave(v->db->mutex);
+ return rc;
+}
+
+/*
** Return true if the prepared statement is in need of being reset.
*/
SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt *pStmt){
@@ -89698,10 +92081,16 @@ static UnpackedRecord *vdbeUnpackRecord(
** 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;
+ PreUpdate *p;
Mem *pMem;
int rc = SQLITE_OK;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( db==0 || ppValue==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+ p = db->pPreUpdate;
/* 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 ){
@@ -89762,7 +92151,12 @@ SQLITE_API int sqlite3_preupdate_old(sqlite3 *db, int iIdx, sqlite3_value **ppVa
** the number of columns in the row being updated, deleted or inserted.
*/
SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){
- PreUpdate *p = db->pPreUpdate;
+ PreUpdate *p;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ p = db!=0 ? db->pPreUpdate : 0;
+#else
+ p = db->pPreUpdate;
+#endif
return (p ? p->keyinfo.nKeyField : 0);
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -89780,7 +92174,12 @@ SQLITE_API int sqlite3_preupdate_count(sqlite3 *db){
** or SET DEFAULT action is considered a trigger.
*/
SQLITE_API int sqlite3_preupdate_depth(sqlite3 *db){
- PreUpdate *p = db->pPreUpdate;
+ PreUpdate *p;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ p = db!=0 ? db->pPreUpdate : 0;
+#else
+ p = db->pPreUpdate;
+#endif
return (p ? p->v->nFrame : 0);
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
@@ -89791,7 +92190,12 @@ SQLITE_API int sqlite3_preupdate_depth(sqlite3 *db){
** only.
*/
SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *db){
- PreUpdate *p = db->pPreUpdate;
+ PreUpdate *p;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ p = db!=0 ? db->pPreUpdate : 0;
+#else
+ p = db->pPreUpdate;
+#endif
return (p ? p->iBlobWrite : -1);
}
#endif
@@ -89802,10 +92206,16 @@ SQLITE_API int sqlite3_preupdate_blobwrite(sqlite3 *db){
** 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;
+ PreUpdate *p;
int rc = SQLITE_OK;
Mem *pMem;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( db==0 || ppValue==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+#endif
+ p = db->pPreUpdate;
if( !p || p->op==SQLITE_DELETE ){
rc = SQLITE_MISUSE_BKPT;
goto preupdate_new_out;
@@ -89884,15 +92294,33 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2(
void *pOut /* OUT: Write the answer here */
){
Vdbe *p = (Vdbe*)pStmt;
- ScanStatus *pScan;
+ VdbeOp *aOp;
+ int nOp;
+ ScanStatus *pScan = 0;
int idx;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( p==0 || pOut==0
+ || iScanStatusOp<SQLITE_SCANSTAT_NLOOP
+ || iScanStatusOp>SQLITE_SCANSTAT_NCYCLE ){
+ return 1;
+ }
+#endif
+ aOp = p->aOp;
+ nOp = p->nOp;
+ if( p->pFrame ){
+ VdbeFrame *pFrame;
+ for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
+ aOp = pFrame->aOp;
+ nOp = pFrame->nOp;
+ }
+
if( iScan<0 ){
int ii;
if( iScanStatusOp==SQLITE_SCANSTAT_NCYCLE ){
i64 res = 0;
- for(ii=0; ii<p->nOp; ii++){
- res += p->aOp[ii].nCycle;
+ for(ii=0; ii<nOp; ii++){
+ res += aOp[ii].nCycle;
}
*(i64*)pOut = res;
return 0;
@@ -89918,7 +92346,7 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2(
switch( iScanStatusOp ){
case SQLITE_SCANSTAT_NLOOP: {
if( pScan->addrLoop>0 ){
- *(sqlite3_int64*)pOut = p->aOp[pScan->addrLoop].nExec;
+ *(sqlite3_int64*)pOut = aOp[pScan->addrLoop].nExec;
}else{
*(sqlite3_int64*)pOut = -1;
}
@@ -89926,7 +92354,7 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2(
}
case SQLITE_SCANSTAT_NVISIT: {
if( pScan->addrVisit>0 ){
- *(sqlite3_int64*)pOut = p->aOp[pScan->addrVisit].nExec;
+ *(sqlite3_int64*)pOut = aOp[pScan->addrVisit].nExec;
}else{
*(sqlite3_int64*)pOut = -1;
}
@@ -89948,7 +92376,7 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2(
}
case SQLITE_SCANSTAT_EXPLAIN: {
if( pScan->addrExplain ){
- *(const char**)pOut = p->aOp[ pScan->addrExplain ].p4.z;
+ *(const char**)pOut = aOp[ pScan->addrExplain ].p4.z;
}else{
*(const char**)pOut = 0;
}
@@ -89956,7 +92384,7 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2(
}
case SQLITE_SCANSTAT_SELECTID: {
if( pScan->addrExplain ){
- *(int*)pOut = p->aOp[ pScan->addrExplain ].p1;
+ *(int*)pOut = aOp[ pScan->addrExplain ].p1;
}else{
*(int*)pOut = -1;
}
@@ -89964,7 +92392,7 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2(
}
case SQLITE_SCANSTAT_PARENTID: {
if( pScan->addrExplain ){
- *(int*)pOut = p->aOp[ pScan->addrExplain ].p2;
+ *(int*)pOut = aOp[ pScan->addrExplain ].p2;
}else{
*(int*)pOut = -1;
}
@@ -89982,18 +92410,18 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2(
if( iIns==0 ) break;
if( iIns>0 ){
while( iIns<=iEnd ){
- res += p->aOp[iIns].nCycle;
+ res += aOp[iIns].nCycle;
iIns++;
}
}else{
int iOp;
- for(iOp=0; iOp<p->nOp; iOp++){
- Op *pOp = &p->aOp[iOp];
+ for(iOp=0; iOp<nOp; iOp++){
+ Op *pOp = &aOp[iOp];
if( pOp->p1!=iEnd ) continue;
if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_NCYCLE)==0 ){
continue;
}
- res += p->aOp[iOp].nCycle;
+ res += aOp[iOp].nCycle;
}
}
}
@@ -90026,7 +92454,7 @@ SQLITE_API int sqlite3_stmt_scanstatus(
SQLITE_API void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){
Vdbe *p = (Vdbe*)pStmt;
int ii;
- for(ii=0; ii<p->nOp; ii++){
+ for(ii=0; p!=0 && ii<p->nOp; ii++){
Op *pOp = &p->aOp[ii];
pOp->nExec = 0;
pOp->nCycle = 0;
@@ -90365,11 +92793,12 @@ SQLITE_API int sqlite3_found_count = 0;
** sqlite3CantopenError(lineno)
*/
static void test_trace_breakpoint(int pc, Op *pOp, Vdbe *v){
- static int n = 0;
+ static u64 n = 0;
(void)pc;
(void)pOp;
(void)v;
n++;
+ if( n==LARGEST_UINT64 ) abort(); /* So that n is used, preventing a warning */
}
#endif
@@ -90789,6 +93218,9 @@ SQLITE_PRIVATE void sqlite3VdbeMemPrettyPrint(Mem *pMem, StrAccum *pStr){
sqlite3_str_appendchar(pStr, 1, (c>=0x20&&c<=0x7f) ? c : '.');
}
sqlite3_str_appendf(pStr, "]%s", encnames[pMem->enc]);
+ if( f & MEM_Term ){
+ sqlite3_str_appendf(pStr, "(0-term)");
+ }
}
}
#endif
@@ -90916,12 +93348,102 @@ static u64 filterHash(const Mem *aMem, const Op *pOp){
}else if( p->flags & MEM_Real ){
h += sqlite3VdbeIntValue(p);
}else if( p->flags & (MEM_Str|MEM_Blob) ){
- /* no-op */
+ /* All strings have the same hash and all blobs have the same hash,
+ ** though, at least, those hashes are different from each other and
+ ** from NULL. */
+ h += 4093 + (p->flags & (MEM_Str|MEM_Blob));
}
}
return h;
}
+
+/*
+** For OP_Column, factor out the case where content is loaded from
+** overflow pages, so that the code to implement this case is separate
+** the common case where all content fits on the page. Factoring out
+** the code reduces register pressure and helps the common case
+** to run faster.
+*/
+static SQLITE_NOINLINE int vdbeColumnFromOverflow(
+ VdbeCursor *pC, /* The BTree cursor from which we are reading */
+ int iCol, /* The column to read */
+ int t, /* The serial-type code for the column value */
+ i64 iOffset, /* Offset to the start of the content value */
+ u32 cacheStatus, /* Current Vdbe.cacheCtr value */
+ u32 colCacheCtr, /* Current value of the column cache counter */
+ Mem *pDest /* Store the value into this register. */
+){
+ int rc;
+ sqlite3 *db = pDest->db;
+ int encoding = pDest->enc;
+ int len = sqlite3VdbeSerialTypeLen(t);
+ assert( pC->eCurType==CURTYPE_BTREE );
+ if( len>db->aLimit[SQLITE_LIMIT_LENGTH] ) return SQLITE_TOOBIG;
+ if( len > 4000 && pC->pKeyInfo==0 ){
+ /* Cache large column values that are on overflow pages using
+ ** an RCStr (reference counted string) so that if they are reloaded,
+ ** that do not have to be copied a second time. The overhead of
+ ** creating and managing the cache is such that this is only
+ ** profitable for larger TEXT and BLOB values.
+ **
+ ** Only do this on table-btrees so that writes to index-btrees do not
+ ** need to clear the cache. This buys performance in the common case
+ ** in exchange for generality.
+ */
+ VdbeTxtBlbCache *pCache;
+ char *pBuf;
+ if( pC->colCache==0 ){
+ pC->pCache = sqlite3DbMallocZero(db, sizeof(VdbeTxtBlbCache) );
+ if( pC->pCache==0 ) return SQLITE_NOMEM;
+ pC->colCache = 1;
+ }
+ pCache = pC->pCache;
+ if( pCache->pCValue==0
+ || pCache->iCol!=iCol
+ || pCache->cacheStatus!=cacheStatus
+ || pCache->colCacheCtr!=colCacheCtr
+ || pCache->iOffset!=sqlite3BtreeOffset(pC->uc.pCursor)
+ ){
+ if( pCache->pCValue ) sqlite3RCStrUnref(pCache->pCValue);
+ pBuf = pCache->pCValue = sqlite3RCStrNew( len+3 );
+ if( pBuf==0 ) return SQLITE_NOMEM;
+ rc = sqlite3BtreePayload(pC->uc.pCursor, iOffset, len, pBuf);
+ if( rc ) return rc;
+ pBuf[len] = 0;
+ pBuf[len+1] = 0;
+ pBuf[len+2] = 0;
+ pCache->iCol = iCol;
+ pCache->cacheStatus = cacheStatus;
+ pCache->colCacheCtr = colCacheCtr;
+ pCache->iOffset = sqlite3BtreeOffset(pC->uc.pCursor);
+ }else{
+ pBuf = pCache->pCValue;
+ }
+ assert( t>=12 );
+ sqlite3RCStrRef(pBuf);
+ if( t&1 ){
+ rc = sqlite3VdbeMemSetStr(pDest, pBuf, len, encoding,
+ sqlite3RCStrUnref);
+ pDest->flags |= MEM_Term;
+ }else{
+ rc = sqlite3VdbeMemSetStr(pDest, pBuf, len, 0,
+ sqlite3RCStrUnref);
+ }
+ }else{
+ rc = sqlite3VdbeMemFromBtree(pC->uc.pCursor, iOffset, len, pDest);
+ if( rc ) return rc;
+ sqlite3VdbeSerialGet((const u8*)pDest->z, t, pDest);
+ if( (t&1)!=0 && encoding==SQLITE_UTF8 ){
+ pDest->z[len] = 0;
+ pDest->flags |= MEM_Term;
+ }
+ }
+ pDest->flags &= ~MEM_Ephem;
+ return rc;
+}
+
+
/*
** Return the symbolic name for the data type of a pMem
*/
@@ -90964,8 +93486,10 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
Mem *pIn2 = 0; /* 2nd input operand */
Mem *pIn3 = 0; /* 3rd input operand */
Mem *pOut = 0; /* Output operand */
+ u32 colCacheCtr = 0; /* Column cache counter */
#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
u64 *pnCycle = 0;
+ int bStmtScanStatus = IS_STMT_SCANSTATUS(db)!=0;
#endif
/*** INSERT STACK UNION HERE ***/
@@ -91030,13 +93554,17 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
assert( pOp>=aOp && pOp<&aOp[p->nOp]);
nVmStep++;
-#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
+
+#if defined(VDBE_PROFILE)
pOp->nExec++;
pnCycle = &pOp->nCycle;
-# ifdef VDBE_PROFILE
- if( sqlite3NProfileCnt==0 )
-# endif
+ if( sqlite3NProfileCnt==0 ) *pnCycle -= sqlite3Hwtime();
+#elif defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+ if( bStmtScanStatus ){
+ pOp->nExec++;
+ pnCycle = &pOp->nCycle;
*pnCycle -= sqlite3Hwtime();
+ }
#endif
/* Only allow tracing if SQLITE_DEBUG is defined.
@@ -91154,8 +93682,8 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
case OP_Goto: { /* jump */
#ifdef SQLITE_DEBUG
- /* In debuggging mode, when the p5 flags is set on an OP_Goto, that
- ** means we should really jump back to the preceeding OP_ReleaseReg
+ /* In debugging mode, when the p5 flags is set on an OP_Goto, that
+ ** means we should really jump back to the preceding OP_ReleaseReg
** instruction. */
if( pOp->p5 ){
assert( pOp->p2 < (int)(pOp - aOp) );
@@ -91363,7 +93891,7 @@ case OP_HaltIfNull: { /* in3 */
** P5 is a value between 0 and 4, inclusive, that modifies the P4 string.
**
** 0: (no change)
-** 1: NOT NULL contraint failed: P4
+** 1: NOT NULL constraint failed: P4
** 2: UNIQUE constraint failed: P4
** 3: CHECK constraint failed: P4
** 4: FOREIGN KEY constraint failed: P4
@@ -92167,7 +94695,7 @@ case OP_AddImm: { /* in1 */
pIn1 = &aMem[pOp->p1];
memAboutToChange(p, pIn1);
sqlite3VdbeMemIntegerify(pIn1);
- pIn1->u.i += pOp->p2;
+ *(u64*)&pIn1->u.i += (u64)pOp->p2;
break;
}
@@ -92434,7 +94962,9 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
}
}
}else if( affinity==SQLITE_AFF_TEXT && ((flags1 | flags3) & MEM_Str)!=0 ){
- if( (flags1 & MEM_Str)==0 && (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
+ if( (flags1 & MEM_Str)!=0 ){
+ pIn1->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal);
+ }else if( (flags1&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
testcase( pIn1->flags & MEM_Int );
testcase( pIn1->flags & MEM_Real );
testcase( pIn1->flags & MEM_IntReal );
@@ -92443,7 +94973,9 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
if( NEVER(pIn1==pIn3) ) flags3 = flags1 | MEM_Str;
}
- if( (flags3 & MEM_Str)==0 && (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
+ if( (flags3 & MEM_Str)!=0 ){
+ pIn3->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal);
+ }else if( (flags3&(MEM_Int|MEM_Real|MEM_IntReal))!=0 ){
testcase( pIn3->flags & MEM_Int );
testcase( pIn3->flags & MEM_Real );
testcase( pIn3->flags & MEM_IntReal );
@@ -92494,10 +95026,10 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */
** opcodes are allowed to occur between this instruction and the previous
** OP_Lt or OP_Gt.
**
-** If result of an OP_Eq comparison on the same two operands as the
-** prior OP_Lt or OP_Gt would have been true, then jump to P2.
-** If the result of an OP_Eq comparison on the two previous
-** operands would have been false or NULL, then fall through.
+** If the result of an OP_Eq comparison on the same two operands as
+** the prior OP_Lt or OP_Gt would have been true, then jump to P2. If
+** the result of an OP_Eq comparison on the two previous operands
+** would have been false or NULL, then fall through.
*/
case OP_ElseEq: { /* same as TK_ESCAPE, jump */
@@ -92624,7 +95156,7 @@ case OP_Compare: {
/* Opcode: Jump P1 P2 P3 * *
**
** Jump to the instruction at address P1, P2, or P3 depending on whether
-** in the most recent OP_Compare instruction the P1 vector was less than
+** in the most recent OP_Compare instruction the P1 vector was less than,
** equal to, or greater than the P2 vector, respectively.
**
** This opcode must immediately follow an OP_Compare opcode.
@@ -92851,6 +95383,12 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */
** (0x01) bit. SQLITE_FLOAT is the 0x02 bit. SQLITE_TEXT is 0x04.
** SQLITE_BLOB is 0x08. SQLITE_NULL is 0x10.
**
+** WARNING: This opcode does not reliably distinguish between NULL and REAL
+** when P1>=0. If the database contains a NaN value, this opcode will think
+** that the datatype is REAL when it should be NULL. When P1<0 and the value
+** is already stored in register P3, then this opcode does reliably
+** distinguish between NULL and REAL. The problem only arises then P1>=0.
+**
** Take the jump to address P2 if and only if the datatype of the
** value determined by P1 and P3 corresponds to one of the bits in the
** P5 bitmask.
@@ -92921,7 +95459,7 @@ case OP_IsType: { /* jump */
/* Opcode: ZeroOrNull P1 P2 P3 * *
** Synopsis: r[P2] = 0 OR NULL
**
-** If all both registers P1 and P3 are NOT NULL, then store a zero in
+** If both registers P1 and P3 are NOT NULL, then store a zero in
** register P2. If either registers P1 or P3 are NULL then put
** a NULL in register P2.
*/
@@ -92964,7 +95502,7 @@ case OP_IfNullRow: { /* jump */
VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
- if( ALWAYS(pC) && pC->nullRow ){
+ if( pC && pC->nullRow ){
sqlite3VdbeMemSetNull(aMem + pOp->p3);
goto jump_to_p2;
}
@@ -93275,11 +95813,16 @@ op_column_restart:
pDest->flags = aFlag[t&1];
}
}else{
+ u8 p5;
pDest->enc = encoding;
+ assert( pDest->db==db );
/* 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))
- || (len = sqlite3VdbeSerialTypeLen(t))==0
+ if( ((p5 = (pOp->p5 & OPFLAG_BYTELENARG))!=0
+ && (p5==OPFLAG_TYPEOFARG
+ || (t>=12 && ((t&1)==0 || p5==OPFLAG_BYTELENARG))
+ )
+ )
+ || sqlite3VdbeSerialTypeLen(t)==0
){
/* Content is irrelevant for
** 1. the typeof() function,
@@ -93296,11 +95839,13 @@ op_column_restart:
*/
sqlite3VdbeSerialGet((u8*)sqlite3CtypeMap, t, pDest);
}else{
- if( len>db->aLimit[SQLITE_LIMIT_LENGTH] ) goto too_big;
- 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;
+ rc = vdbeColumnFromOverflow(pC, p2, t, aOffset[p2],
+ p->cacheCtr, colCacheCtr, pDest);
+ if( rc ){
+ if( rc==SQLITE_NOMEM ) goto no_mem;
+ if( rc==SQLITE_TOOBIG ) goto too_big;
+ goto abort_due_to_error;
+ }
}
}
@@ -93459,7 +96004,7 @@ case OP_Affinity: {
}else{
pIn1->u.r = (double)pIn1->u.i;
pIn1->flags |= MEM_Real;
- pIn1->flags &= ~MEM_Int;
+ pIn1->flags &= ~(MEM_Int|MEM_Str);
}
}
REGISTER_TRACE((int)(pIn1-aMem), pIn1);
@@ -93762,7 +96307,6 @@ case OP_MakeRecord: {
/* NULL value. No change in zPayload */
}else{
u64 v;
- u32 i;
if( serial_type==7 ){
assert( sizeof(v)==sizeof(pRec->u.r) );
memcpy(&v, &pRec->u.r, sizeof(v));
@@ -93770,12 +96314,17 @@ case OP_MakeRecord: {
}else{
v = pRec->u.i;
}
- len = i = sqlite3SmallTypeSizes[serial_type];
- assert( i>0 );
- while( 1 /*exit-by-break*/ ){
- zPayload[--i] = (u8)(v&0xFF);
- if( i==0 ) break;
- v >>= 8;
+ len = sqlite3SmallTypeSizes[serial_type];
+ assert( len>=1 && len<=8 && len!=5 && len!=7 );
+ switch( len ){
+ default: zPayload[7] = (u8)(v&0xff); v >>= 8;
+ zPayload[6] = (u8)(v&0xff); v >>= 8;
+ case 6: zPayload[5] = (u8)(v&0xff); v >>= 8;
+ zPayload[4] = (u8)(v&0xff); v >>= 8;
+ case 4: zPayload[3] = (u8)(v&0xff); v >>= 8;
+ case 3: zPayload[2] = (u8)(v&0xff); v >>= 8;
+ case 2: zPayload[1] = (u8)(v&0xff); v >>= 8;
+ case 1: zPayload[0] = (u8)(v&0xff);
}
zPayload += len;
}
@@ -94584,7 +97133,7 @@ case OP_OpenEphemeral: { /* ncycle */
}
pCx = p->apCsr[pOp->p1];
if( pCx && !pCx->noReuse && ALWAYS(pOp->p2<=pCx->nField) ){
- /* If the ephermeral table is already open and has no duplicates from
+ /* If the ephemeral table is already open and has no duplicates from
** OP_OpenDup, then erase all existing content so that the table is
** empty again, rather than creating a new table. */
assert( pCx->isEphemeral );
@@ -95075,7 +97624,7 @@ seek_not_found:
** row. If This.P5 is false (0) then a jump is made to SeekGE.P2. If
** This.P5 is true (non-zero) then a jump is made to This.P2. The P5==0
** case occurs when there are no inequality constraints to the right of
-** the IN constraing. The jump to SeekGE.P2 ends the loop. The P5!=0 case
+** the IN constraint. The jump to SeekGE.P2 ends the loop. The P5!=0 case
** occurs when there are inequality constraints to the right of the IN
** operator. In that case, the This.P2 will point either directly to or
** to setup code prior to the OP_IdxGT or OP_IdxGE opcode that checks for
@@ -95083,7 +97632,7 @@ seek_not_found:
**
** Possible outcomes from this opcode:<ol>
**
-** <li> If the cursor is initally not pointed to any valid row, then
+** <li> If the cursor is initially not pointed to any valid row, then
** fall through into the subsequent OP_SeekGE opcode.
**
** <li> If the cursor is left pointing to a row that is before the target
@@ -95198,6 +97747,7 @@ case OP_SeekScan: { /* ncycle */
break;
}
nStep--;
+ pC->cacheStatus = CACHE_STALE;
rc = sqlite3BtreeNext(pC->uc.pCursor, 0);
if( rc ){
if( rc==SQLITE_DONE ){
@@ -95314,13 +97864,13 @@ case OP_IfNotOpen: { /* jump */
** operands to OP_NotFound and OP_IdxGT.
**
** This opcode is an optimization attempt only. If this opcode always
-** falls through, the correct answer is still obtained, but extra works
+** falls through, the correct answer is still obtained, but extra work
** is performed.
**
** A value of N in the seekHit flag of cursor P1 means that there exists
** a key P3:N that will match some record in the index. We want to know
** if it is possible for a record P3:P4 to match some record in the
-** index. If it is not possible, we can skips some work. So if seekHit
+** index. If it is not possible, we can skip some work. So if seekHit
** is less than P4, attempt to find out if a match is possible by running
** OP_NotFound.
**
@@ -95832,6 +98382,7 @@ case OP_Insert: {
);
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
+ colCacheCtr++;
/* Invoke the update-hook if required. */
if( rc ) goto abort_due_to_error;
@@ -95885,13 +98436,18 @@ case OP_RowCell: {
** left in an undefined state.
**
** If the OPFLAG_AUXDELETE bit is set on P5, that indicates that this
-** delete one of several associated with deleting a table row and all its
-** associated index entries. Exactly one of those deletes is the "primary"
-** delete. The others are all on OPFLAG_FORDELETE cursors or else are
-** marked with the AUXDELETE flag.
+** delete is one of several associated with deleting a table row and
+** all its associated index entries. Exactly one of those deletes is
+** the "primary" delete. The others are all on OPFLAG_FORDELETE
+** cursors or else are marked with the AUXDELETE flag.
**
-** If the OPFLAG_NCHANGE flag of P2 (NB: P2 not P5) is set, then the row
-** change count is incremented (otherwise not).
+** If the OPFLAG_NCHANGE (0x01) flag of P2 (NB: P2 not P5) is set, then
+** the row change count is incremented (otherwise not).
+**
+** If the OPFLAG_ISNOOP (0x40) flag of P2 (not P5!) is set, then the
+** pre-update-hook for deletes is run, but the btree is otherwise unchanged.
+** This happens when the OP_Delete is to be shortly followed by an OP_Insert
+** with the same key, causing the btree entry to be overwritten.
**
** P1 must not be pseudo-table. It has to be a real table with
** multiple rows.
@@ -95992,6 +98548,7 @@ case OP_Delete: {
rc = sqlite3BtreeDelete(pC->uc.pCursor, pOp->p5);
pC->cacheStatus = CACHE_STALE;
+ colCacheCtr++;
pC->seekResult = 0;
if( rc ) goto abort_due_to_error;
@@ -96059,13 +98616,13 @@ case OP_SorterCompare: {
** Write into register P2 the current sorter data for sorter cursor P1.
** Then clear the column header cache on cursor P3.
**
-** This opcode is normally use to move a record out of the sorter and into
+** This opcode is normally used to move a record out of the sorter and into
** a register that is the source for a pseudo-table cursor created using
** OpenPseudo. That pseudo-table cursor is the one that is identified by
** parameter P3. Clearing the P3 column cache as part of this opcode saves
** us from having to issue a separate NullRow instruction to clear that cache.
*/
-case OP_SorterData: {
+case OP_SorterData: { /* ncycle */
VdbeCursor *pC;
pOut = &aMem[pOp->p2];
@@ -96340,8 +98897,8 @@ case OP_IfSmaller: { /* jump */
** regression tests can determine whether or not the optimizer is
** correctly optimizing out sorts.
*/
-case OP_SorterSort: /* jump */
-case OP_Sort: { /* jump */
+case OP_SorterSort: /* jump ncycle */
+case OP_Sort: { /* jump ncycle */
#ifdef SQLITE_TEST
sqlite3_sort_count++;
sqlite3_search_count--;
@@ -96868,7 +99425,7 @@ case OP_IdxGE: { /* jump, ncycle */
** file is given by P1.
**
** The table being destroyed is in the main database file if P3==0. If
-** P3==1 then the table to be clear is in the auxiliary database file
+** P3==1 then the table to be destroyed is in the auxiliary database file
** that is used to store tables create using CREATE TEMPORARY TABLE.
**
** If AUTOVACUUM is enabled then it is possible that another root page
@@ -96928,8 +99485,8 @@ case OP_Destroy: { /* out2 */
** in the database file is given by P1. But, unlike Destroy, do not
** remove the table or index from the database file.
**
-** The table being clear is in the main database file if P2==0. If
-** P2==1 then the table to be clear is in the auxiliary database file
+** The table being cleared is in the main database file if P2==0. If
+** P2==1 then the table to be cleared is in the auxiliary database file
** that is used to store tables create using CREATE TEMPORARY TABLE.
**
** If the P3 value is non-zero, then the row change count is incremented
@@ -97015,13 +99572,41 @@ case OP_CreateBtree: { /* out2 */
/* Opcode: SqlExec * * * P4 *
**
** Run the SQL statement or statements specified in the P4 string.
+** Disable Auth and Trace callbacks while those statements are running if
+** P1 is true.
*/
case OP_SqlExec: {
+ char *zErr;
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ sqlite3_xauth xAuth;
+#endif
+ u8 mTrace;
+
sqlite3VdbeIncrWriteCounter(p, 0);
db->nSqlExec++;
- rc = sqlite3_exec(db, pOp->p4.z, 0, 0, 0);
+ zErr = 0;
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ xAuth = db->xAuth;
+#endif
+ mTrace = db->mTrace;
+ if( pOp->p1 ){
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ db->xAuth = 0;
+#endif
+ db->mTrace = 0;
+ }
+ rc = sqlite3_exec(db, pOp->p4.z, 0, 0, &zErr);
db->nSqlExec--;
- if( rc ) goto abort_due_to_error;
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ db->xAuth = xAuth;
+#endif
+ db->mTrace = mTrace;
+ if( zErr || rc ){
+ sqlite3VdbeError(p, "%s", zErr);
+ sqlite3_free(zErr);
+ if( rc==SQLITE_NOMEM ) goto no_mem;
+ goto abort_due_to_error;
+ }
break;
}
@@ -97755,7 +100340,7 @@ case OP_AggStep1: {
/* If this function is inside of a trigger, the register array in aMem[]
** might change from one evaluation to the next. The next block of code
** checks to see if the register array has changed, and if so it
- ** reinitializes the relavant parts of the sqlite3_context object */
+ ** reinitializes the relevant parts of the sqlite3_context object */
if( pCtx->pMem != pMem ){
pCtx->pMem = pMem;
for(i=pCtx->argc-1; i>=0; i--) pCtx->argv[i] = &aMem[pOp->p2+i];
@@ -97850,6 +100435,7 @@ case OP_AggFinal: {
}
sqlite3VdbeChangeEncoding(pMem, encoding);
UPDATE_MAX_BLOBSIZE(pMem);
+ REGISTER_TRACE((int)(pMem-aMem), pMem);
break;
}
@@ -98242,6 +100828,52 @@ case OP_VOpen: { /* ncycle */
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#ifndef SQLITE_OMIT_VIRTUALTABLE
+/* Opcode: VCheck P1 P2 P3 P4 *
+**
+** P4 is a pointer to a Table object that is a virtual table in schema P1
+** that supports the xIntegrity() method. This opcode runs the xIntegrity()
+** method for that virtual table, using P3 as the integer argument. If
+** an error is reported back, the table name is prepended to the error
+** message and that message is stored in P2. If no errors are seen,
+** register P2 is set to NULL.
+*/
+case OP_VCheck: { /* out2 */
+ Table *pTab;
+ sqlite3_vtab *pVtab;
+ const sqlite3_module *pModule;
+ char *zErr = 0;
+
+ pOut = &aMem[pOp->p2];
+ sqlite3VdbeMemSetNull(pOut); /* Innocent until proven guilty */
+ assert( pOp->p4type==P4_TABLEREF );
+ pTab = pOp->p4.pTab;
+ assert( pTab!=0 );
+ assert( pTab->nTabRef>0 );
+ assert( IsVirtual(pTab) );
+ if( pTab->u.vtab.p==0 ) break;
+ pVtab = pTab->u.vtab.p->pVtab;
+ assert( pVtab!=0 );
+ pModule = pVtab->pModule;
+ assert( pModule!=0 );
+ assert( pModule->iVersion>=4 );
+ assert( pModule->xIntegrity!=0 );
+ sqlite3VtabLock(pTab->u.vtab.p);
+ assert( pOp->p1>=0 && pOp->p1<db->nDb );
+ rc = pModule->xIntegrity(pVtab, db->aDb[pOp->p1].zDbSName, pTab->zName,
+ pOp->p3, &zErr);
+ sqlite3VtabUnlock(pTab->u.vtab.p);
+ if( rc ){
+ sqlite3_free(zErr);
+ goto abort_due_to_error;
+ }
+ if( zErr ){
+ sqlite3VdbeMemSetStr(pOut, zErr, -1, SQLITE_UTF8, sqlite3_free);
+ }
+ break;
+}
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
/* Opcode: VInitIn P1 P2 P3 * *
** Synopsis: r[P2]=ValueList(P1,P3)
**
@@ -98354,6 +100986,7 @@ case OP_VColumn: { /* ncycle */
const sqlite3_module *pModule;
Mem *pDest;
sqlite3_context sContext;
+ FuncDef nullFunc;
VdbeCursor *pCur = p->apCsr[pOp->p1];
assert( pCur!=0 );
@@ -98371,6 +101004,9 @@ case OP_VColumn: { /* ncycle */
memset(&sContext, 0, sizeof(sContext));
sContext.pOut = pDest;
sContext.enc = encoding;
+ nullFunc.pUserData = 0;
+ nullFunc.funcFlags = SQLITE_RESULT_SUBTYPE;
+ sContext.pFunc = &nullFunc;
assert( pOp->p5==OPFLAG_NOCHNG || pOp->p5==0 );
if( pOp->p5 & OPFLAG_NOCHNG ){
sqlite3VdbeMemSetNull(pDest);
@@ -98632,7 +101268,7 @@ case OP_MaxPgcnt: { /* out2 */
** This opcode works exactly like OP_Function. The only difference is in
** its name. This opcode is used in places where the function must be
** purely non-deterministic. Some built-in date/time functions can be
-** either determinitic of non-deterministic, depending on their arguments.
+** either deterministic of non-deterministic, depending on their arguments.
** When those function are used in a non-deterministic way, they will check
** to see if they were called using OP_PureFunc instead of OP_Function, and
** if they were, they throw an error.
@@ -98650,7 +101286,7 @@ case OP_Function: { /* group */
/* If this function is inside of a trigger, the register array in aMem[]
** might change from one evaluation to the next. The next block of code
** checks to see if the register array has changed, and if so it
- ** reinitializes the relavant parts of the sqlite3_context object */
+ ** reinitializes the relevant parts of the sqlite3_context object */
pOut = &aMem[pOp->p3];
if( pCtx->pOut != pOut ){
pCtx->pVdbe = p;
@@ -98703,6 +101339,42 @@ case OP_ClrSubtype: { /* in1 */
break;
}
+/* Opcode: GetSubtype P1 P2 * * *
+** Synopsis: r[P2] = r[P1].subtype
+**
+** Extract the subtype value from register P1 and write that subtype
+** into register P2. If P1 has no subtype, then P1 gets a NULL.
+*/
+case OP_GetSubtype: { /* in1 out2 */
+ pIn1 = &aMem[pOp->p1];
+ pOut = &aMem[pOp->p2];
+ if( pIn1->flags & MEM_Subtype ){
+ sqlite3VdbeMemSetInt64(pOut, pIn1->eSubtype);
+ }else{
+ sqlite3VdbeMemSetNull(pOut);
+ }
+ break;
+}
+
+/* Opcode: SetSubtype P1 P2 * * *
+** Synopsis: r[P2].subtype = r[P1]
+**
+** Set the subtype value of register P2 to the integer from register P1.
+** If P1 is NULL, clear the subtype from p2.
+*/
+case OP_SetSubtype: { /* in1 out2 */
+ pIn1 = &aMem[pOp->p1];
+ pOut = &aMem[pOp->p2];
+ if( pIn1->flags & MEM_Null ){
+ pOut->flags &= ~MEM_Subtype;
+ }else{
+ assert( pIn1->flags & MEM_Int );
+ pOut->flags |= MEM_Subtype;
+ pOut->eSubtype = (u8)(pIn1->u.i & 0xff);
+ }
+ break;
+}
+
/* Opcode: FilterAdd P1 * P3 P4 *
** Synopsis: filter(P1) += key(P3@P4)
**
@@ -98726,7 +101398,7 @@ case OP_FilterAdd: {
printf("hash: %llu modulo %d -> %u\n", h, pIn1->n, (int)(h%pIn1->n));
}
#endif
- h %= pIn1->n;
+ h %= (pIn1->n*8);
pIn1->z[h/8] |= 1<<(h&7);
break;
}
@@ -98762,7 +101434,7 @@ case OP_Filter: { /* jump */
printf("hash: %llu modulo %d -> %u\n", h, pIn1->n, (int)(h%pIn1->n));
}
#endif
- h %= pIn1->n;
+ h %= (pIn1->n*8);
if( (pIn1->z[h/8] & (1<<(h&7)))==0 ){
VdbeBranchTaken(1, 2);
p->aCounter[SQLITE_STMTSTATUS_FILTER_HIT]++;
@@ -98988,8 +101660,10 @@ default: { /* This is really OP_Noop, OP_Explain */
*pnCycle += sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime();
pnCycle = 0;
#elif defined(SQLITE_ENABLE_STMT_SCANSTATUS)
- *pnCycle += sqlite3Hwtime();
- pnCycle = 0;
+ if( pnCycle ){
+ *pnCycle += sqlite3Hwtime();
+ pnCycle = 0;
+ }
#endif
/* The following code adds nothing to the actual functionality
@@ -99012,7 +101686,7 @@ default: { /* This is really OP_Noop, OP_Explain */
}
if( opProperty==0xff ){
/* Never happens. This code exists to avoid a harmless linkage
- ** warning aboud sqlite3VdbeRegisterDump() being defined but not
+ ** warning about sqlite3VdbeRegisterDump() being defined but not
** used. */
sqlite3VdbeRegisterDump(p);
}
@@ -99185,8 +101859,7 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
/* Set the value of register r[1] in the SQL statement to integer iRow.
** This is done directly as a performance optimization
*/
- v->aMem[1].flags = MEM_Int;
- v->aMem[1].u.i = iRow;
+ sqlite3VdbeMemSetInt64(&v->aMem[1], iRow);
/* If the statement has been run before (and is paused at the OP_ResultRow)
** then back it up to the point where it does the OP_NotExists. This could
@@ -99269,7 +101942,7 @@ SQLITE_API int sqlite3_blob_open(
#endif
*ppBlob = 0;
#ifdef SQLITE_ENABLE_API_ARMOR
- if( !sqlite3SafetyCheckOk(db) || zTable==0 ){
+ if( !sqlite3SafetyCheckOk(db) || zTable==0 || zColumn==0 ){
return SQLITE_MISUSE_BKPT;
}
#endif
@@ -99468,7 +102141,7 @@ blob_open_out:
if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt);
sqlite3DbFree(db, pBlob);
}
- sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
+ sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : (char*)0), zErr);
sqlite3DbFree(db, zErr);
sqlite3ParseObjectReset(&sParse);
rc = sqlite3ApiExit(db, rc);
@@ -99627,7 +102300,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
((Vdbe*)p->pStmt)->rc = SQLITE_OK;
rc = blobSeekToRow(p, iRow, &zErr);
if( rc!=SQLITE_OK ){
- sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
+ sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : (char*)0), zErr);
sqlite3DbFree(db, zErr);
}
assert( rc!=SQLITE_SCHEMA );
@@ -99730,7 +102403,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
** The threshold for the amount of main memory to use before flushing
** records to a PMA is roughly the same as the limit configured for the
** page-cache of the main database. Specifically, the threshold is set to
-** the value returned by "PRAGMA main.page_size" multipled by
+** the value returned by "PRAGMA main.page_size" multiplied by
** that returned by "PRAGMA main.cache_size", in bytes.
**
** If the sorter is running in single-threaded mode, then all PMAs generated
@@ -99753,7 +102426,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
**
** If there are fewer than SORTER_MAX_MERGE_COUNT PMAs in total and the
** sorter is running in single-threaded mode, then these PMAs are merged
-** incrementally as keys are retreived from the sorter by the VDBE. The
+** incrementally as keys are retrieved from the sorter by the VDBE. The
** MergeEngine object, described in further detail below, performs this
** merge.
**
@@ -99831,7 +102504,7 @@ struct SorterFile {
struct SorterList {
SorterRecord *pList; /* Linked list of records */
u8 *aMemory; /* If non-NULL, bulk memory to hold pList */
- int szPMA; /* Size of pList as PMA in bytes */
+ i64 szPMA; /* Size of pList as PMA in bytes */
};
/*
@@ -99916,7 +102589,7 @@ struct MergeEngine {
**
** Essentially, this structure contains all those fields of the VdbeSorter
** structure for which each thread requires a separate instance. For example,
-** each thread requries its own UnpackedRecord object to unpack records in
+** each thread requeries its own UnpackedRecord object to unpack records in
** as part of comparison operations.
**
** Before a background thread is launched, variable bDone is set to 0. Then,
@@ -99940,10 +102613,10 @@ typedef int (*SorterCompare)(SortSubtask*,int*,const void*,int,const void*,int);
struct SortSubtask {
SQLiteThread *pThread; /* Background thread, if any */
int bDone; /* Set if thread is finished but not joined */
+ int nPMA; /* Number of PMAs currently in file */
VdbeSorter *pSorter; /* Sorter that owns this sub-task */
UnpackedRecord *pUnpacked; /* Space to unpack a record */
SorterList list; /* List for thread to write to a PMA */
- int nPMA; /* Number of PMAs currently in file */
SorterCompare xCompare; /* Compare function to use */
SorterFile file; /* Temp file for level-0 PMAs */
SorterFile file2; /* Space for other PMAs */
@@ -99988,7 +102661,7 @@ struct VdbeSorter {
** PMA, in sorted order. The next key to be read is cached in nKey/aKey.
** aKey might point into aMap or into aBuffer. If neither of those locations
** contain a contiguous representation of the key, then aAlloc is allocated
-** and the key is copied into aAlloc and aKey is made to poitn to aAlloc.
+** and the key is copied into aAlloc and aKey is made to point to aAlloc.
**
** pFd==0 at EOF.
*/
@@ -101359,7 +104032,7 @@ static int vdbeSorterFlushPMA(VdbeSorter *pSorter){
** the background thread from a sub-tasks previous turn is still running,
** skip it. If the first (pSorter->nTask-1) sub-tasks are all still busy,
** fall back to using the final sub-task. The first (pSorter->nTask-1)
- ** sub-tasks are prefered as they use background threads - the final
+ ** sub-tasks are preferred as they use background threads - the final
** sub-task uses the main thread. */
for(i=0; i<nWorker; i++){
int iTest = (pSorter->iPrev + i + 1) % nWorker;
@@ -101417,8 +104090,8 @@ SQLITE_PRIVATE int sqlite3VdbeSorterWrite(
int rc = SQLITE_OK; /* Return Code */
SorterRecord *pNew; /* New list element */
int bFlush; /* True to flush contents of memory to PMA */
- int nReq; /* Bytes of memory required */
- int nPMA; /* Bytes of PMA space required */
+ i64 nReq; /* Bytes of memory required */
+ i64 nPMA; /* Bytes of PMA space required */
int t; /* serial type of first record field */
assert( pCsr->eCurType==CURTYPE_SORTER );
@@ -101843,7 +104516,7 @@ static int vdbePmaReaderIncrMergeInit(PmaReader *pReadr, int eMode){
rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode);
- /* Set up the required files for pIncr. A multi-theaded IncrMerge object
+ /* Set up the required files for pIncr. A multi-threaded IncrMerge object
** requires two temp files to itself, whereas a single-threaded object
** only requires a region of pTask->file2. */
if( rc==SQLITE_OK ){
@@ -102483,6 +105156,8 @@ static int bytecodevtabConnect(
"p5 INT,"
"comment TEXT,"
"subprog TEXT,"
+ "nexec INT,"
+ "ncycle INT,"
"stmt HIDDEN"
");",
@@ -102645,7 +105320,7 @@ static int bytecodevtabColumn(
}
}
}
- i += 10;
+ i += 20;
}
}
switch( i ){
@@ -102695,16 +105370,31 @@ static int bytecodevtabColumn(
}
break;
}
- case 10: /* tables_used.type */
+
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ case 9: /* nexec */
+ sqlite3_result_int(ctx, pOp->nExec);
+ break;
+ case 10: /* ncycle */
+ sqlite3_result_int(ctx, pOp->nCycle);
+ break;
+#else
+ case 9: /* nexec */
+ case 10: /* ncycle */
+ sqlite3_result_int(ctx, 0);
+ break;
+#endif
+
+ case 20: /* tables_used.type */
sqlite3_result_text(ctx, pCur->zType, -1, SQLITE_STATIC);
break;
- case 11: /* tables_used.schema */
+ case 21: /* tables_used.schema */
sqlite3_result_text(ctx, pCur->zSchema, -1, SQLITE_STATIC);
break;
- case 12: /* tables_used.name */
+ case 22: /* tables_used.name */
sqlite3_result_text(ctx, pCur->zName, -1, SQLITE_STATIC);
break;
- case 13: /* tables_used.wr */
+ case 23: /* tables_used.wr */
sqlite3_result_int(ctx, pOp->opcode==OP_OpenWrite);
break;
}
@@ -102778,7 +105468,7 @@ static int bytecodevtabBestIndex(
int rc = SQLITE_CONSTRAINT;
struct sqlite3_index_constraint *p;
bytecodevtab *pVTab = (bytecodevtab*)tab;
- int iBaseCol = pVTab->bTablesUsed ? 4 : 8;
+ int iBaseCol = pVTab->bTablesUsed ? 4 : 10;
pIdxInfo->estimatedCost = (double)100;
pIdxInfo->estimatedRows = 100;
pIdxInfo->idxNum = 0;
@@ -102825,7 +105515,8 @@ static sqlite3_module bytecodevtabModule = {
/* xSavepoint */ 0,
/* xRelease */ 0,
/* xRollbackTo */ 0,
- /* xShadowName */ 0
+ /* xShadowName */ 0,
+ /* xIntegrity */ 0
};
@@ -103349,7 +106040,7 @@ static int walkWindowList(Walker *pWalker, Window *pList, int bOneOnly){
** The return value from this routine is WRC_Abort to abandon the tree walk
** and WRC_Continue to continue.
*/
-static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
+SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3WalkExprNN(Walker *pWalker, Expr *pExpr){
int rc;
testcase( ExprHasProperty(pExpr, EP_TokenOnly) );
testcase( ExprHasProperty(pExpr, EP_Reduced) );
@@ -103358,7 +106049,9 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
if( rc ) return rc & WRC_Abort;
if( !ExprHasProperty(pExpr,(EP_TokenOnly|EP_Leaf)) ){
assert( pExpr->x.pList==0 || pExpr->pRight==0 );
- if( pExpr->pLeft && walkExpr(pWalker, pExpr->pLeft) ) return WRC_Abort;
+ if( pExpr->pLeft && sqlite3WalkExprNN(pWalker, pExpr->pLeft) ){
+ return WRC_Abort;
+ }
if( pExpr->pRight ){
assert( !ExprHasProperty(pExpr, EP_WinFunc) );
pExpr = pExpr->pRight;
@@ -103382,7 +106075,7 @@ static SQLITE_NOINLINE int walkExpr(Walker *pWalker, Expr *pExpr){
return WRC_Continue;
}
SQLITE_PRIVATE int sqlite3WalkExpr(Walker *pWalker, Expr *pExpr){
- return pExpr ? walkExpr(pWalker,pExpr) : WRC_Continue;
+ return pExpr ? sqlite3WalkExprNN(pWalker,pExpr) : WRC_Continue;
}
/*
@@ -103508,7 +106201,7 @@ SQLITE_PRIVATE int sqlite3WalkSelect(Walker *pWalker, Select *p){
}
/* Increase the walkerDepth when entering a subquery, and
-** descrease when leaving the subquery.
+** decrease when leaving the subquery.
*/
SQLITE_PRIVATE int sqlite3WalkerDepthIncrease(Walker *pWalker, Select *pSelect){
UNUSED_PARAMETER(pSelect);
@@ -103627,6 +106320,8 @@ static void resolveAlias(
assert( iCol>=0 && iCol<pEList->nExpr );
pOrig = pEList->a[iCol].pExpr;
assert( pOrig!=0 );
+ assert( !ExprHasProperty(pExpr, EP_Reduced|EP_TokenOnly) );
+ if( pExpr->pAggInfo ) return;
db = pParse->db;
pDup = sqlite3ExprDup(db, pOrig, 0);
if( db->mallocFailed ){
@@ -103652,21 +106347,36 @@ static void resolveAlias(
}
/*
-** Subqueries stores the original database, table and column names for their
-** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN".
-** Check to see if the zSpan given to this routine matches the zDb, zTab,
-** and zCol. If any of zDb, zTab, and zCol are NULL then those fields will
-** match anything.
+** Subqueries store the original database, table and column names for their
+** result sets in ExprList.a[].zSpan, in the form "DATABASE.TABLE.COLUMN",
+** and mark the expression-list item by setting ExprList.a[].fg.eEName
+** to ENAME_TAB.
+**
+** Check to see if the zSpan/eEName of the expression-list item passed to this
+** routine matches the zDb, zTab, and zCol. If any of zDb, zTab, and zCol are
+** NULL then those fields will match anything. Return true if there is a match,
+** or false otherwise.
+**
+** SF_NestedFrom subqueries also store an entry for the implicit rowid (or
+** _rowid_, or oid) column by setting ExprList.a[].fg.eEName to ENAME_ROWID,
+** and setting zSpan to "DATABASE.TABLE.<rowid-alias>". This type of pItem
+** argument matches if zCol is a rowid alias. If it is not NULL, (*pbRowid)
+** is set to 1 if there is this kind of match.
*/
SQLITE_PRIVATE int sqlite3MatchEName(
const struct ExprList_item *pItem,
const char *zCol,
const char *zTab,
- const char *zDb
+ const char *zDb,
+ int *pbRowid
){
int n;
const char *zSpan;
- if( pItem->fg.eEName!=ENAME_TAB ) return 0;
+ int eEName = pItem->fg.eEName;
+ if( eEName!=ENAME_TAB && (eEName!=ENAME_ROWID || NEVER(pbRowid==0)) ){
+ return 0;
+ }
+ assert( pbRowid==0 || *pbRowid==0 );
zSpan = pItem->zEName;
for(n=0; ALWAYS(zSpan[n]) && zSpan[n]!='.'; n++){}
if( zDb && (sqlite3StrNICmp(zSpan, zDb, n)!=0 || zDb[n]!=0) ){
@@ -103678,9 +106388,11 @@ SQLITE_PRIVATE int sqlite3MatchEName(
return 0;
}
zSpan += n+1;
- if( zCol && sqlite3StrICmp(zSpan, zCol)!=0 ){
- return 0;
+ if( zCol ){
+ if( eEName==ENAME_TAB && sqlite3StrICmp(zSpan, zCol)!=0 ) return 0;
+ if( eEName==ENAME_ROWID && sqlite3IsRowid(zCol)==0 ) return 0;
}
+ if( eEName==ENAME_ROWID ) *pbRowid = 1;
return 1;
}
@@ -103713,6 +106425,7 @@ SQLITE_PRIVATE Bitmask sqlite3ExprColUsed(Expr *pExpr){
assert( ExprUseYTab(pExpr) );
pExTab = pExpr->y.pTab;
assert( pExTab!=0 );
+ assert( n < pExTab->nCol );
if( (pExTab->tabFlags & TF_HasGenerated)!=0
&& (pExTab->aCol[n].colFlags & COLFLAG_GENERATED)!=0
){
@@ -103813,7 +106526,7 @@ static int lookupName(
){
int i, j; /* Loop counters */
int cnt = 0; /* Number of matching column names */
- int cntTab = 0; /* Number of matching table names */
+ int cntTab = 0; /* Number of potential "rowid" matches */
int nSubquery = 0; /* How many levels of subquery */
sqlite3 *db = pParse->db; /* The database connection */
SrcItem *pItem; /* Use for looping over pSrcList items */
@@ -103890,39 +106603,49 @@ static int lookupName(
assert( pEList!=0 );
assert( pEList->nExpr==pTab->nCol );
for(j=0; j<pEList->nExpr; j++){
- if( !sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb) ){
+ int bRowid = 0; /* True if possible rowid match */
+ if( !sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb, &bRowid) ){
continue;
}
- if( cnt>0 ){
- if( pItem->fg.isUsing==0
- || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
- ){
- /* Two or more tables have the same column name which is
- ** not joined by USING. This is an error. Signal as much
- ** by clearing pFJMatch and letting cnt go above 1. */
- sqlite3ExprListDelete(db, pFJMatch);
- pFJMatch = 0;
- }else
- if( (pItem->fg.jointype & JT_RIGHT)==0 ){
- /* An INNER or LEFT JOIN. Use the left-most table */
- continue;
- }else
- if( (pItem->fg.jointype & JT_LEFT)==0 ){
- /* A RIGHT JOIN. Use the right-most table */
- cnt = 0;
- sqlite3ExprListDelete(db, pFJMatch);
- pFJMatch = 0;
- }else{
- /* For a FULL JOIN, we must construct a coalesce() func */
- extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
+ if( bRowid==0 ){
+ if( cnt>0 ){
+ if( pItem->fg.isUsing==0
+ || sqlite3IdListIndex(pItem->u3.pUsing, zCol)<0
+ ){
+ /* Two or more tables have the same column name which is
+ ** not joined by USING. This is an error. Signal as much
+ ** by clearing pFJMatch and letting cnt go above 1. */
+ sqlite3ExprListDelete(db, pFJMatch);
+ pFJMatch = 0;
+ }else
+ if( (pItem->fg.jointype & JT_RIGHT)==0 ){
+ /* An INNER or LEFT JOIN. Use the left-most table */
+ continue;
+ }else
+ if( (pItem->fg.jointype & JT_LEFT)==0 ){
+ /* A RIGHT JOIN. Use the right-most table */
+ cnt = 0;
+ sqlite3ExprListDelete(db, pFJMatch);
+ pFJMatch = 0;
+ }else{
+ /* For a FULL JOIN, we must construct a coalesce() func */
+ extendFJMatch(pParse, &pFJMatch, pMatch, pExpr->iColumn);
+ }
}
+ cnt++;
+ hit = 1;
+ }else if( cnt>0 ){
+ /* This is a potential rowid match, but there has already been
+ ** a real match found. So this can be ignored. */
+ continue;
}
- cnt++;
- cntTab = 2;
+ cntTab++;
pMatch = pItem;
pExpr->iColumn = j;
pEList->a[j].fg.bUsed = 1;
- hit = 1;
+
+ /* rowid cannot be part of a USING clause - assert() this. */
+ assert( bRowid==0 || pEList->a[j].fg.bUsingTerm==0 );
if( pEList->a[j].fg.bUsingTerm ) break;
}
if( hit || zTab==0 ) continue;
@@ -103986,8 +106709,37 @@ static int lookupName(
}
}
if( 0==cnt && VisibleRowid(pTab) ){
+ /* pTab is a potential ROWID match. Keep track of it and match
+ ** the ROWID later if that seems appropriate. (Search for "cntTab"
+ ** to find related code.) Only allow a ROWID match if there is
+ ** a single ROWID match candidate.
+ */
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ /* In SQLITE_ALLOW_ROWID_IN_VIEW mode, allow a ROWID match
+ ** if there is a single VIEW candidate or if there is a single
+ ** non-VIEW candidate plus multiple VIEW candidates. In other
+ ** words non-VIEW candidate terms take precedence over VIEWs.
+ */
+ if( cntTab==0
+ || (cntTab==1
+ && ALWAYS(pMatch!=0)
+ && ALWAYS(pMatch->pTab!=0)
+ && (pMatch->pTab->tabFlags & TF_Ephemeral)!=0
+ && (pTab->tabFlags & TF_Ephemeral)==0)
+ ){
+ cntTab = 1;
+ pMatch = pItem;
+ }else{
+ cntTab++;
+ }
+#else
+ /* The (much more common) non-SQLITE_ALLOW_ROWID_IN_VIEW case is
+ ** simpler since we require exactly one candidate, which will
+ ** always be a non-VIEW
+ */
cntTab++;
pMatch = pItem;
+#endif
}
}
if( pMatch ){
@@ -104015,7 +106767,8 @@ static int lookupName(
assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT );
if( pParse->bReturning ){
if( (pNC->ncFlags & NC_UBaseReg)!=0
- && (zTab==0 || sqlite3StrICmp(zTab,pParse->pTriggerTab->zName)==0)
+ && ALWAYS(zTab==0
+ || sqlite3StrICmp(zTab,pParse->pTriggerTab->zName)==0)
){
pExpr->iTable = op!=TK_DELETE;
pTab = pParse->pTriggerTab;
@@ -104112,14 +106865,14 @@ static int lookupName(
** Perhaps the name is a reference to the ROWID
*/
if( cnt==0
- && cntTab==1
+ && cntTab>=1
&& pMatch
&& (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0
&& sqlite3IsRowid(zCol)
- && ALWAYS(VisibleRowid(pMatch->pTab))
+ && ALWAYS(VisibleRowid(pMatch->pTab) || pMatch->fg.isNestedFrom)
){
- cnt = 1;
- pExpr->iColumn = -1;
+ cnt = cntTab;
+ if( pMatch->fg.isNestedFrom==0 ) pExpr->iColumn = -1;
pExpr->affExpr = SQLITE_AFF_INTEGER;
}
@@ -104278,6 +107031,7 @@ static int lookupName(
sqlite3RecordErrorOffsetOfExpr(pParse->db, pExpr);
pParse->checkSchema = 1;
pTopNC->nNcErr++;
+ eNewExprOp = TK_NULL;
}
assert( pFJMatch==0 );
@@ -104304,7 +107058,7 @@ static int lookupName(
** If a generated column is referenced, set bits for every column
** of the table.
*/
- if( pExpr->iColumn>=0 && pMatch!=0 ){
+ if( pExpr->iColumn>=0 && cnt==1 && pMatch!=0 ){
pMatch->colUsed |= sqlite3ExprColUsed(pExpr);
}
@@ -104482,6 +107236,19 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
** resolved. This prevents "column" from being counted as having been
** referenced, which might prevent a SELECT from being erroneously
** marked as correlated.
+ **
+ ** 2024-03-28: Beware of aggregates. A bare column of aggregated table
+ ** can still evaluate to NULL even though it is marked as NOT NULL.
+ ** Example:
+ **
+ ** CREATE TABLE t1(a INT NOT NULL);
+ ** SELECT a, a IS NULL, a IS NOT NULL, count(*) FROM t1;
+ **
+ ** The "a IS NULL" and "a IS NOT NULL" expressions cannot be optimized
+ ** here because at the time this case is hit, we do not yet know whether
+ ** or not t1 is being aggregated. We have to assume the worst and omit
+ ** the optimization. The only time it is safe to apply this optimization
+ ** is within the WHERE clause.
*/
case TK_NOTNULL:
case TK_ISNULL: {
@@ -104492,19 +107259,36 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
anRef[i] = p->nRef;
}
sqlite3WalkExpr(pWalker, pExpr->pLeft);
- if( 0==sqlite3ExprCanBeNull(pExpr->pLeft) && !IN_RENAME_OBJECT ){
- testcase( ExprHasProperty(pExpr, EP_OuterON) );
- assert( !ExprHasProperty(pExpr, EP_IntValue) );
- pExpr->u.iValue = (pExpr->op==TK_NOTNULL);
- pExpr->flags |= EP_IntValue;
- pExpr->op = TK_INTEGER;
+ if( IN_RENAME_OBJECT ) return WRC_Prune;
+ if( sqlite3ExprCanBeNull(pExpr->pLeft) ){
+ /* The expression can be NULL. So the optimization does not apply */
+ return WRC_Prune;
+ }
- for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){
- p->nRef = anRef[i];
+ for(i=0, p=pNC; p; p=p->pNext, i++){
+ if( (p->ncFlags & NC_Where)==0 ){
+ return WRC_Prune; /* Not in a WHERE clause. Unsafe to optimize. */
}
- sqlite3ExprDelete(pParse->db, pExpr->pLeft);
- pExpr->pLeft = 0;
}
+ testcase( ExprHasProperty(pExpr, EP_OuterON) );
+ assert( !ExprHasProperty(pExpr, EP_IntValue) );
+#if TREETRACE_ENABLED
+ if( sqlite3TreeTrace & 0x80000 ){
+ sqlite3DebugPrintf(
+ "NOT NULL strength reduction converts the following to %d:\n",
+ pExpr->op==TK_NOTNULL
+ );
+ sqlite3ShowExpr(pExpr);
+ }
+#endif /* TREETRACE_ENABLED */
+ pExpr->u.iValue = (pExpr->op==TK_NOTNULL);
+ pExpr->flags |= EP_IntValue;
+ pExpr->op = TK_INTEGER;
+ for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){
+ p->nRef = anRef[i];
+ }
+ sqlite3ExprDelete(pParse->db, pExpr->pLeft);
+ pExpr->pLeft = 0;
return WRC_Prune;
}
@@ -104572,6 +107356,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
Window *pWin = (IsWindowFunc(pExpr) ? pExpr->y.pWin : 0);
#endif
assert( !ExprHasProperty(pExpr, EP_xIsSelect|EP_IntValue) );
+ assert( pExpr->pLeft==0 || pExpr->pLeft->op==TK_ORDER );
zId = pExpr->u.zToken;
pDef = sqlite3FindFunction(pParse->db, zId, n, enc, 0);
if( pDef==0 ){
@@ -104713,6 +107498,10 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
pNC->nNcErr++;
}
#endif
+ else if( is_agg==0 && pExpr->pLeft ){
+ sqlite3ExprOrderByAggregateError(pParse, pExpr);
+ pNC->nNcErr++;
+ }
if( is_agg ){
/* Window functions may not be arguments of aggregate functions.
** Or arguments of other window functions. But aggregate functions
@@ -104731,6 +107520,11 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
#endif
sqlite3WalkExprList(pWalker, pList);
if( is_agg ){
+ if( pExpr->pLeft ){
+ assert( pExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pExpr->pLeft) );
+ sqlite3WalkExprList(pWalker, pExpr->pLeft->x.pList);
+ }
#ifndef SQLITE_OMIT_WINDOWFUNC
if( pWin ){
Select *pSel = pNC->pWinSelect;
@@ -104759,11 +107553,12 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
while( pNC2
&& sqlite3ReferencesSrcList(pParse, pExpr, pNC2->pSrcList)==0
){
- pExpr->op2++;
+ pExpr->op2 += (1 + pNC2->nNestedSelect);
pNC2 = pNC2->pNext;
}
assert( pDef!=0 || IN_RENAME_OBJECT );
if( pNC2 && pDef ){
+ pExpr->op2 += pNC2->nNestedSelect;
assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg );
assert( SQLITE_FUNC_ANYORDER==NC_OrderAgg );
testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 );
@@ -104800,8 +107595,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
assert( pNC->nRef>=nRef );
if( nRef!=pNC->nRef ){
ExprSetProperty(pExpr, EP_VarSelect);
- pNC->ncFlags |= NC_VarSelect;
}
+ pNC->ncFlags |= NC_Subquery;
}
break;
}
@@ -105241,7 +108036,7 @@ static int resolveOrderGroupBy(
}
for(j=0; j<pSelect->pEList->nExpr; j++){
if( sqlite3ExprCompare(0, pE, pSelect->pEList->a[j].pExpr, -1)==0 ){
- /* Since this expresion is being changed into a reference
+ /* Since this expression is being changed into a reference
** to an identical expression in the result set, remove all Window
** objects belonging to the expression from the Select.pWin list. */
windowRemoveExprFromSelect(pSelect, pE);
@@ -105294,10 +108089,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
while( p ){
assert( (p->selFlags & SF_Expanded)!=0 );
assert( (p->selFlags & SF_Resolved)==0 );
- assert( db->suppressErr==0 ); /* SF_Resolved not set if errors suppressed */
p->selFlags |= SF_Resolved;
-
/* Resolve the expressions in the LIMIT and OFFSET clauses. These
** are not allowed to refer to any names, so pass an empty NameContext.
*/
@@ -105324,6 +108117,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
/* Recursively resolve names in all subqueries in the FROM clause
*/
+ if( pOuterNC ) pOuterNC->nNestedSelect++;
for(i=0; i<p->pSrc->nSrc; i++){
SrcItem *pItem = &p->pSrc->a[i];
if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){
@@ -105348,6 +108142,9 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
}
}
}
+ if( pOuterNC && ALWAYS(pOuterNC->nNestedSelect>0) ){
+ pOuterNC->nNestedSelect--;
+ }
/* Set up the local name-context to pass to sqlite3ResolveExprNames() to
** resolve the result-set expression list.
@@ -105391,7 +108188,9 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
}
if( sqlite3ResolveExprNames(&sNC, p->pHaving) ) return WRC_Abort;
}
+ sNC.ncFlags |= NC_Where;
if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
+ sNC.ncFlags &= ~NC_Where;
/* Resolve names in table-valued-function arguments */
for(i=0; i<p->pSrc->nSrc; i++){
@@ -105564,7 +108363,8 @@ SQLITE_PRIVATE int sqlite3ResolveExprNames(
return SQLITE_ERROR;
}
#endif
- sqlite3WalkExpr(&w, pExpr);
+ assert( pExpr!=0 );
+ sqlite3WalkExprNN(&w, pExpr);
#if SQLITE_MAX_EXPR_DEPTH>0
w.pParse->nHeight -= pExpr->nHeight;
#endif
@@ -105606,7 +108406,7 @@ SQLITE_PRIVATE int sqlite3ResolveExprListNames(
return WRC_Abort;
}
#endif
- sqlite3WalkExpr(&w, pExpr);
+ sqlite3WalkExprNN(&w, pExpr);
#if SQLITE_MAX_EXPR_DEPTH>0
w.pParse->nHeight -= pExpr->nHeight;
#endif
@@ -105628,7 +108428,7 @@ SQLITE_PRIVATE int sqlite3ResolveExprListNames(
/*
** Resolve all names in all expressions of a SELECT and in all
-** decendents of the SELECT, including compounds off of p->pPrior,
+** descendants of the SELECT, including compounds off of p->pPrior,
** subqueries in expressions, and subqueries used as FROM clause
** terms.
**
@@ -105778,6 +108578,7 @@ SQLITE_PRIVATE char sqlite3ExprAffinity(const Expr *pExpr){
if( op==TK_SELECT_COLUMN ){
assert( pExpr->pLeft!=0 && ExprUseXSelect(pExpr->pLeft) );
assert( pExpr->iColumn < pExpr->iTable );
+ assert( pExpr->iColumn >= 0 );
assert( pExpr->iTable==pExpr->pLeft->x.pSelect->pEList->nExpr );
return sqlite3ExprAffinity(
pExpr->pLeft->x.pSelect->pEList->a[pExpr->iColumn].pExpr
@@ -105928,9 +108729,10 @@ SQLITE_PRIVATE Expr *sqlite3ExprSkipCollateAndLikely(Expr *pExpr){
assert( pExpr->x.pList->nExpr>0 );
assert( pExpr->op==TK_FUNCTION );
pExpr = pExpr->x.pList->a[0].pExpr;
- }else{
- assert( pExpr->op==TK_COLLATE );
+ }else if( pExpr->op==TK_COLLATE ){
pExpr = pExpr->pLeft;
+ }else{
+ break;
}
}
return pExpr;
@@ -105989,11 +108791,10 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){
}else{
Expr *pNext = p->pRight;
/* The Expr.x union is never used at the same time as Expr.pRight */
- assert( ExprUseXList(p) );
- assert( p->x.pList==0 || p->pRight==0 );
- if( p->x.pList!=0 && !db->mallocFailed ){
+ assert( !ExprUseXList(p) || p->x.pList==0 || p->pRight==0 );
+ if( ExprUseXList(p) && p->x.pList!=0 && !db->mallocFailed ){
int i;
- for(i=0; ALWAYS(i<p->x.pList->nExpr); i++){
+ for(i=0; i<p->x.pList->nExpr; i++){
if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){
pNext = p->x.pList->a[i].pExpr;
break;
@@ -106015,7 +108816,7 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){
/*
** Return the collation sequence for the expression pExpr. If
** there is no defined collating sequence, return a pointer to the
-** defautl collation sequence.
+** default collation sequence.
**
** See also: sqlite3ExprCollSeq()
**
@@ -106145,7 +108946,7 @@ SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(
return pColl;
}
-/* Expresssion p is a comparison operator. Return a collation sequence
+/* Expression p is a comparison operator. Return a collation sequence
** appropriate for the comparison operator.
**
** This is normally just a wrapper around sqlite3BinaryCompareCollSeq().
@@ -106302,6 +109103,7 @@ SQLITE_PRIVATE Expr *sqlite3ExprForVectorField(
*/
pRet = sqlite3PExpr(pParse, TK_SELECT_COLUMN, 0, 0);
if( pRet ){
+ ExprSetProperty(pRet, EP_FullSize);
pRet->iTable = nField;
pRet->iColumn = iField;
pRet->pLeft = pVector;
@@ -106602,6 +109404,15 @@ SQLITE_PRIVATE void sqlite3ExprSetHeightAndFlags(Parse *pParse, Expr *p){
#endif /* SQLITE_MAX_EXPR_DEPTH>0 */
/*
+** Set the error offset for an Expr node, if possible.
+*/
+SQLITE_PRIVATE void sqlite3ExprSetErrorOffset(Expr *pExpr, int iOfst){
+ if( pExpr==0 ) return;
+ if( NEVER(ExprUseWJoin(pExpr)) ) return;
+ pExpr->w.iOfst = iOfst;
+}
+
+/*
** This routine is the core allocator for Expr nodes.
**
** Construct a new expression node and return a pointer to it. Memory
@@ -106825,9 +109636,9 @@ SQLITE_PRIVATE Select *sqlite3ExprListToValues(Parse *pParse, int nElem, ExprLis
** Join two expressions using an AND operator. If either expression is
** NULL, then just return the other expression.
**
-** If one side or the other of the AND is known to be false, then instead
-** of returning an AND expression, just return a constant expression with
-** a value of false.
+** If one side or the other of the AND is known to be false, and neither side
+** is part of an ON clause, then instead of returning an AND expression,
+** just return a constant expression with a value of false.
*/
SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
sqlite3 *db = pParse->db;
@@ -106835,14 +109646,17 @@ SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
return pRight;
}else if( pRight==0 ){
return pLeft;
- }else if( (ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight))
- && !IN_RENAME_OBJECT
- ){
- sqlite3ExprDeferredDelete(pParse, pLeft);
- sqlite3ExprDeferredDelete(pParse, pRight);
- return sqlite3Expr(db, TK_INTEGER, "0");
}else{
- return sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
+ u32 f = pLeft->flags | pRight->flags;
+ if( (f&(EP_OuterON|EP_InnerON|EP_IsFalse))==EP_IsFalse
+ && !IN_RENAME_OBJECT
+ ){
+ sqlite3ExprDeferredDelete(pParse, pLeft);
+ sqlite3ExprDeferredDelete(pParse, pRight);
+ return sqlite3Expr(db, TK_INTEGER, "0");
+ }else{
+ return sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
+ }
}
}
@@ -106881,6 +109695,67 @@ SQLITE_PRIVATE Expr *sqlite3ExprFunction(
}
/*
+** Report an error when attempting to use an ORDER BY clause within
+** the arguments of a non-aggregate function.
+*/
+SQLITE_PRIVATE void sqlite3ExprOrderByAggregateError(Parse *pParse, Expr *p){
+ sqlite3ErrorMsg(pParse,
+ "ORDER BY may not be used with non-aggregate %#T()", p
+ );
+}
+
+/*
+** Attach an ORDER BY clause to a function call.
+**
+** functionname( arguments ORDER BY sortlist )
+** \_____________________/ \______/
+** pExpr pOrderBy
+**
+** The ORDER BY clause is inserted into a new Expr node of type TK_ORDER
+** and added to the Expr.pLeft field of the parent TK_FUNCTION node.
+*/
+SQLITE_PRIVATE void sqlite3ExprAddFunctionOrderBy(
+ Parse *pParse, /* Parsing context */
+ Expr *pExpr, /* The function call to which ORDER BY is to be added */
+ ExprList *pOrderBy /* The ORDER BY clause to add */
+){
+ Expr *pOB;
+ sqlite3 *db = pParse->db;
+ if( NEVER(pOrderBy==0) ){
+ assert( db->mallocFailed );
+ return;
+ }
+ if( pExpr==0 ){
+ assert( db->mallocFailed );
+ sqlite3ExprListDelete(db, pOrderBy);
+ return;
+ }
+ assert( pExpr->op==TK_FUNCTION );
+ assert( pExpr->pLeft==0 );
+ assert( ExprUseXList(pExpr) );
+ if( pExpr->x.pList==0 || NEVER(pExpr->x.pList->nExpr==0) ){
+ /* Ignore ORDER BY on zero-argument aggregates */
+ sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pOrderBy);
+ return;
+ }
+ if( IsWindowFunc(pExpr) ){
+ sqlite3ExprOrderByAggregateError(pParse, pExpr);
+ sqlite3ExprListDelete(db, pOrderBy);
+ return;
+ }
+
+ pOB = sqlite3ExprAlloc(db, TK_ORDER, 0, 0);
+ if( pOB==0 ){
+ sqlite3ExprListDelete(db, pOrderBy);
+ return;
+ }
+ pOB->x.pList = pOrderBy;
+ assert( ExprUseXList(pOB) );
+ pExpr->pLeft = pOB;
+ ExprSetProperty(pOB, EP_FullSize);
+}
+
+/*
** Check to see if a function is usable according to current access
** rules:
**
@@ -107041,6 +109916,9 @@ static SQLITE_NOINLINE void sqlite3ExprDeleteNN(sqlite3 *db, Expr *p){
SQLITE_PRIVATE void sqlite3ExprDelete(sqlite3 *db, Expr *p){
if( p ) sqlite3ExprDeleteNN(db, p);
}
+SQLITE_PRIVATE void sqlite3ExprDeleteGeneric(sqlite3 *db, void *p){
+ if( ALWAYS(p) ) sqlite3ExprDeleteNN(db, (Expr*)p);
+}
/*
** Clear both elements of an OnOrUsing object
@@ -107058,7 +109936,7 @@ SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3 *db, OnOrUsing *p){
/*
** Arrange to cause pExpr to be deleted when the pParse is deleted.
** This is similar to sqlite3ExprDelete() except that the delete is
-** deferred untilthe pParse is deleted.
+** deferred until the pParse is deleted.
**
** The pExpr might be deleted immediately on an OOM error.
**
@@ -107066,9 +109944,7 @@ SQLITE_PRIVATE void sqlite3ClearOnOrUsing(sqlite3 *db, OnOrUsing *p){
** pExpr to the pParse->pConstExpr list with a register number of 0.
*/
SQLITE_PRIVATE void sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){
- sqlite3ParserAddCleanup(pParse,
- (void(*)(sqlite3*,void*))sqlite3ExprDelete,
- pExpr);
+ sqlite3ParserAddCleanup(pParse, sqlite3ExprDeleteGeneric, pExpr);
}
/* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the
@@ -107133,11 +110009,7 @@ static int dupedExprStructSize(const Expr *p, int flags){
assert( flags==EXPRDUP_REDUCE || flags==0 ); /* Only one flag value allowed */
assert( EXPR_FULLSIZE<=0xfff );
assert( (0xfff & (EP_Reduced|EP_TokenOnly))==0 );
- if( 0==flags || p->op==TK_SELECT_COLUMN
-#ifndef SQLITE_OMIT_WINDOWFUNC
- || ExprHasProperty(p, EP_WinFunc)
-#endif
- ){
+ if( 0==flags || ExprHasProperty(p, EP_FullSize) ){
nSize = EXPR_FULLSIZE;
}else{
assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) );
@@ -107168,56 +110040,93 @@ static int dupedExprNodeSize(const Expr *p, int flags){
/*
** Return the number of bytes required to create a duplicate of the
-** expression passed as the first argument. The second argument is a
-** mask containing EXPRDUP_XXX flags.
+** expression passed as the first argument.
**
** The value returned includes space to create a copy of the Expr struct
** itself and the buffer referred to by Expr.u.zToken, if any.
**
-** If the EXPRDUP_REDUCE flag is set, then the return value includes
-** space to duplicate all Expr nodes in the tree formed by Expr.pLeft
-** and Expr.pRight variables (but not for any structures pointed to or
-** descended from the Expr.x.pList or Expr.x.pSelect variables).
+** The return value includes space to duplicate all Expr nodes in the
+** tree formed by Expr.pLeft and Expr.pRight, but not any other
+** substructure such as Expr.x.pList, Expr.x.pSelect, and Expr.y.pWin.
*/
-static int dupedExprSize(const Expr *p, int flags){
- int nByte = 0;
- if( p ){
- nByte = dupedExprNodeSize(p, flags);
- if( flags&EXPRDUP_REDUCE ){
- nByte += dupedExprSize(p->pLeft, flags) + dupedExprSize(p->pRight, flags);
- }
- }
+static int dupedExprSize(const Expr *p){
+ int nByte;
+ assert( p!=0 );
+ nByte = dupedExprNodeSize(p, EXPRDUP_REDUCE);
+ if( p->pLeft ) nByte += dupedExprSize(p->pLeft);
+ if( p->pRight ) nByte += dupedExprSize(p->pRight);
+ assert( nByte==ROUND8(nByte) );
return nByte;
}
/*
-** This function is similar to sqlite3ExprDup(), except that if pzBuffer
-** is not NULL then *pzBuffer is assumed to point to a buffer large enough
-** to store the copy of expression p, the copies of p->u.zToken
-** (if applicable), and the copies of the p->pLeft and p->pRight expressions,
-** if any. Before returning, *pzBuffer is set to the first byte past the
-** portion of the buffer copied into by this function.
+** An EdupBuf is a memory allocation used to stored multiple Expr objects
+** together with their Expr.zToken content. This is used to help implement
+** compression while doing sqlite3ExprDup(). The top-level Expr does the
+** allocation for itself and many of its decendents, then passes an instance
+** of the structure down into exprDup() so that they decendents can have
+** access to that memory.
*/
-static Expr *exprDup(sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer){
+typedef struct EdupBuf EdupBuf;
+struct EdupBuf {
+ u8 *zAlloc; /* Memory space available for storage */
+#ifdef SQLITE_DEBUG
+ u8 *zEnd; /* First byte past the end of memory */
+#endif
+};
+
+/*
+** This function is similar to sqlite3ExprDup(), except that if pEdupBuf
+** is not NULL then it points to memory that can be used to store a copy
+** of the input Expr p together with its p->u.zToken (if any). pEdupBuf
+** is updated with the new buffer tail prior to returning.
+*/
+static Expr *exprDup(
+ sqlite3 *db, /* Database connection (for memory allocation) */
+ const Expr *p, /* Expr tree to be duplicated */
+ int dupFlags, /* EXPRDUP_REDUCE for compression. 0 if not */
+ EdupBuf *pEdupBuf /* Preallocated storage space, or NULL */
+){
Expr *pNew; /* Value to return */
- u8 *zAlloc; /* Memory space from which to build Expr object */
+ EdupBuf sEdupBuf; /* Memory space from which to build Expr object */
u32 staticFlag; /* EP_Static if space not obtained from malloc */
+ int nToken = -1; /* Space needed for p->u.zToken. -1 means unknown */
assert( db!=0 );
assert( p );
assert( dupFlags==0 || dupFlags==EXPRDUP_REDUCE );
- assert( pzBuffer==0 || dupFlags==EXPRDUP_REDUCE );
+ assert( pEdupBuf==0 || dupFlags==EXPRDUP_REDUCE );
/* Figure out where to write the new Expr structure. */
- if( pzBuffer ){
- zAlloc = *pzBuffer;
+ if( pEdupBuf ){
+ sEdupBuf.zAlloc = pEdupBuf->zAlloc;
+#ifdef SQLITE_DEBUG
+ sEdupBuf.zEnd = pEdupBuf->zEnd;
+#endif
staticFlag = EP_Static;
- assert( zAlloc!=0 );
+ assert( sEdupBuf.zAlloc!=0 );
+ assert( dupFlags==EXPRDUP_REDUCE );
}else{
- zAlloc = sqlite3DbMallocRawNN(db, dupedExprSize(p, dupFlags));
+ int nAlloc;
+ if( dupFlags ){
+ nAlloc = dupedExprSize(p);
+ }else if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
+ nToken = sqlite3Strlen30NN(p->u.zToken)+1;
+ nAlloc = ROUND8(EXPR_FULLSIZE + nToken);
+ }else{
+ nToken = 0;
+ nAlloc = ROUND8(EXPR_FULLSIZE);
+ }
+ assert( nAlloc==ROUND8(nAlloc) );
+ sEdupBuf.zAlloc = sqlite3DbMallocRawNN(db, nAlloc);
+#ifdef SQLITE_DEBUG
+ sEdupBuf.zEnd = sEdupBuf.zAlloc ? sEdupBuf.zAlloc+nAlloc : 0;
+#endif
+
staticFlag = 0;
}
- pNew = (Expr *)zAlloc;
+ pNew = (Expr *)sEdupBuf.zAlloc;
+ assert( EIGHT_BYTE_ALIGNMENT(pNew) );
if( pNew ){
/* Set nNewSize to the size allocated for the structure pointed to
@@ -107226,22 +110135,27 @@ static Expr *exprDup(sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer){
** 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{
- nToken = 0;
+ int nNewSize = nStructSize & 0xfff;
+ if( nToken<0 ){
+ if( !ExprHasProperty(p, EP_IntValue) && p->u.zToken ){
+ nToken = sqlite3Strlen30(p->u.zToken) + 1;
+ }else{
+ nToken = 0;
+ }
}
if( dupFlags ){
+ assert( (int)(sEdupBuf.zEnd - sEdupBuf.zAlloc) >= nNewSize+nToken );
assert( ExprHasProperty(p, EP_Reduced)==0 );
- memcpy(zAlloc, p, nNewSize);
+ memcpy(sEdupBuf.zAlloc, p, nNewSize);
}else{
u32 nSize = (u32)exprStructSize(p);
- memcpy(zAlloc, p, nSize);
+ assert( (int)(sEdupBuf.zEnd - sEdupBuf.zAlloc) >=
+ (int)EXPR_FULLSIZE+nToken );
+ memcpy(sEdupBuf.zAlloc, p, nSize);
if( nSize<EXPR_FULLSIZE ){
- memset(&zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
+ memset(&sEdupBuf.zAlloc[nSize], 0, EXPR_FULLSIZE-nSize);
}
+ nNewSize = EXPR_FULLSIZE;
}
/* Set the EP_Reduced, EP_TokenOnly, and EP_Static flags appropriately. */
@@ -107254,44 +110168,50 @@ static Expr *exprDup(sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer){
}
/* Copy the p->u.zToken string, if any. */
- if( nToken ){
- char *zToken = pNew->u.zToken = (char*)&zAlloc[nNewSize];
+ assert( nToken>=0 );
+ if( nToken>0 ){
+ char *zToken = pNew->u.zToken = (char*)&sEdupBuf.zAlloc[nNewSize];
memcpy(zToken, p->u.zToken, nToken);
+ nNewSize += nToken;
}
+ sEdupBuf.zAlloc += ROUND8(nNewSize);
+
+ if( ((p->flags|pNew->flags)&(EP_TokenOnly|EP_Leaf))==0 ){
- if( 0==((p->flags|pNew->flags) & (EP_TokenOnly|EP_Leaf)) ){
/* Fill in the pNew->x.pSelect or pNew->x.pList member. */
if( ExprUseXSelect(p) ){
pNew->x.pSelect = sqlite3SelectDup(db, p->x.pSelect, dupFlags);
}else{
- pNew->x.pList = sqlite3ExprListDup(db, p->x.pList, dupFlags);
+ pNew->x.pList = sqlite3ExprListDup(db, p->x.pList,
+ p->op!=TK_ORDER ? dupFlags : 0);
}
- }
- /* Fill in pNew->pLeft and pNew->pRight. */
- if( ExprHasProperty(pNew, EP_Reduced|EP_TokenOnly|EP_WinFunc) ){
- 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;
- }
#ifndef SQLITE_OMIT_WINDOWFUNC
if( ExprHasProperty(p, EP_WinFunc) ){
pNew->y.pWin = sqlite3WindowDup(db, pNew, p->y.pWin);
assert( ExprHasProperty(pNew, EP_WinFunc) );
}
#endif /* SQLITE_OMIT_WINDOWFUNC */
- if( pzBuffer ){
- *pzBuffer = zAlloc;
- }
- }else{
- if( !ExprHasProperty(p, EP_TokenOnly|EP_Leaf) ){
- if( pNew->op==TK_SELECT_COLUMN ){
+
+ /* Fill in pNew->pLeft and pNew->pRight. */
+ if( dupFlags ){
+ if( p->op==TK_SELECT_COLUMN ){
pNew->pLeft = p->pLeft;
- assert( p->pRight==0 || p->pRight==p->pLeft
- || ExprHasProperty(p->pLeft, EP_Subquery) );
+ assert( p->pRight==0
+ || p->pRight==p->pLeft
+ || ExprHasProperty(p->pLeft, EP_Subquery) );
+ }else{
+ pNew->pLeft = p->pLeft ?
+ exprDup(db, p->pLeft, EXPRDUP_REDUCE, &sEdupBuf) : 0;
+ }
+ pNew->pRight = p->pRight ?
+ exprDup(db, p->pRight, EXPRDUP_REDUCE, &sEdupBuf) : 0;
+ }else{
+ if( p->op==TK_SELECT_COLUMN ){
+ pNew->pLeft = p->pLeft;
+ assert( p->pRight==0
+ || p->pRight==p->pLeft
+ || ExprHasProperty(p->pLeft, EP_Subquery) );
}else{
pNew->pLeft = sqlite3ExprDup(db, p->pLeft, 0);
}
@@ -107299,6 +110219,8 @@ static Expr *exprDup(sqlite3 *db, const Expr *p, int dupFlags, u8 **pzBuffer){
}
}
}
+ if( pEdupBuf ) memcpy(pEdupBuf, &sEdupBuf, sizeof(sEdupBuf));
+ assert( sEdupBuf.zAlloc <= sEdupBuf.zEnd );
return pNew;
}
@@ -107563,11 +110485,7 @@ SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *p, int flags)
** initially NULL, then create a new expression list.
**
** The pList argument must be either NULL or a pointer to an ExprList
-** obtained from a prior call to sqlite3ExprListAppend(). This routine
-** may not be used with an ExprList obtained from sqlite3ExprListDup().
-** Reason: This routine assumes that the number of slots in pList->a[]
-** is a power of two. That is true for sqlite3ExprListAppend() returns
-** but is not necessarily true from the return value of sqlite3ExprListDup().
+** obtained from a prior call to sqlite3ExprListAppend().
**
** If a memory allocation error occurs, the entire list is freed and
** NULL is returned. If non-NULL is returned, then it is guaranteed
@@ -107832,6 +110750,9 @@ static SQLITE_NOINLINE void exprListDeleteNN(sqlite3 *db, ExprList *pList){
SQLITE_PRIVATE void sqlite3ExprListDelete(sqlite3 *db, ExprList *pList){
if( pList ) exprListDeleteNN(db, pList);
}
+SQLITE_PRIVATE void sqlite3ExprListDeleteGeneric(sqlite3 *db, void *pList){
+ if( ALWAYS(pList) ) exprListDeleteNN(db, (ExprList*)pList);
+}
/*
** Return the bitwise-OR of all Expr.flags fields in the given
@@ -107900,7 +110821,7 @@ SQLITE_PRIVATE int sqlite3ExprIdToTrueFalse(Expr *pExpr){
** and 0 if it is FALSE.
*/
SQLITE_PRIVATE int sqlite3ExprTruthValue(const Expr *pExpr){
- pExpr = sqlite3ExprSkipCollate((Expr*)pExpr);
+ pExpr = sqlite3ExprSkipCollateAndLikely((Expr*)pExpr);
assert( pExpr->op==TK_TRUEFALSE );
assert( !ExprHasProperty(pExpr, EP_IntValue) );
assert( sqlite3StrICmp(pExpr->u.zToken,"true")==0
@@ -108087,12 +111008,17 @@ SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr *p, int iCur){
}
/*
-** Check pExpr to see if it is an invariant constraint on data source pSrc.
+** Check pExpr to see if it is an constraint on the single data source
+** pSrc = &pSrcList->a[iSrc]. In other words, check to see if pExpr
+** constrains pSrc but does not depend on any other tables or data
+** sources anywhere else in the query. Return true (non-zero) if pExpr
+** is a constraint on pSrc only.
+**
** This is an optimization. False negatives will perhaps cause slower
** queries, but false positives will yield incorrect answers. So when in
** doubt, return 0.
**
-** To be an invariant constraint, the following must be true:
+** To be an single-source constraint, the following must be true:
**
** (1) pExpr cannot refer to any table other than pSrc->iCursor.
**
@@ -108103,13 +111029,31 @@ SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr *p, int iCur){
**
** (4) If pSrc is the right operand of a LEFT JOIN, then...
** (4a) pExpr must come from an ON clause..
- (4b) and specifically the ON clause associated with the LEFT JOIN.
+** (4b) and specifically the ON clause associated with the LEFT JOIN.
**
** (5) If pSrc is not the right operand of a LEFT JOIN or the left
** operand of a RIGHT JOIN, then pExpr must be from the WHERE
** clause, not an ON clause.
+**
+** (6) Either:
+**
+** (6a) pExpr does not originate in an ON or USING clause, or
+**
+** (6b) The ON or USING clause from which pExpr is derived is
+** not to the left of a RIGHT JOIN (or FULL JOIN).
+**
+** Without this restriction, accepting pExpr as a single-table
+** constraint might move the the ON/USING filter expression
+** from the left side of a RIGHT JOIN over to the right side,
+** which leads to incorrect answers. See also restriction (9)
+** on push-down.
*/
-SQLITE_PRIVATE int sqlite3ExprIsTableConstraint(Expr *pExpr, const SrcItem *pSrc){
+SQLITE_PRIVATE int sqlite3ExprIsSingleTableConstraint(
+ Expr *pExpr, /* The constraint */
+ const SrcList *pSrcList, /* Complete FROM clause */
+ int iSrc /* Which element of pSrcList to use */
+){
+ const SrcItem *pSrc = &pSrcList->a[iSrc];
if( pSrc->fg.jointype & JT_LTORJ ){
return 0; /* rule (3) */
}
@@ -108119,6 +111063,19 @@ SQLITE_PRIVATE int sqlite3ExprIsTableConstraint(Expr *pExpr, const SrcItem *pSrc
}else{
if( ExprHasProperty(pExpr, EP_OuterON) ) return 0; /* rule (5) */
}
+ if( ExprHasProperty(pExpr, EP_OuterON|EP_InnerON) /* (6a) */
+ && (pSrcList->a[0].fg.jointype & JT_LTORJ)!=0 /* Fast pre-test of (6b) */
+ ){
+ int jj;
+ for(jj=0; jj<iSrc; jj++){
+ if( pExpr->w.iJoin==pSrcList->a[jj].iCursor ){
+ if( (pSrcList->a[jj].fg.jointype & JT_LTORJ)!=0 ){
+ return 0; /* restriction (6) */
+ }
+ break;
+ }
+ }
+ }
return sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor); /* rules (1), (2) */
}
@@ -108294,10 +111251,14 @@ SQLITE_PRIVATE int sqlite3ExprCanBeNull(const Expr *p){
return 0;
case TK_COLUMN:
assert( ExprUseYTab(p) );
- return ExprHasProperty(p, EP_CanBeNull) ||
- p->y.pTab==0 || /* Reference to column of index on expression */
- (p->iColumn>=0
+ return ExprHasProperty(p, EP_CanBeNull)
+ || NEVER(p->y.pTab==0) /* Reference to column of index on expr */
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ || (p->iColumn==XN_ROWID && IsView(p->y.pTab))
+#endif
+ || (p->iColumn>=0
&& p->y.pTab->aCol!=0 /* Possible due to prior error */
+ && ALWAYS(p->iColumn<p->y.pTab->nCol)
&& p->y.pTab->aCol[p->iColumn].notNull==0);
default:
return 1;
@@ -108358,10 +111319,31 @@ SQLITE_PRIVATE int sqlite3IsRowid(const char *z){
}
/*
+** Return a pointer to a buffer containing a usable rowid alias for table
+** pTab. An alias is usable if there is not an explicit user-defined column
+** of the same name.
+*/
+SQLITE_PRIVATE const char *sqlite3RowidAlias(Table *pTab){
+ const char *azOpt[] = {"_ROWID_", "ROWID", "OID"};
+ int ii;
+ assert( VisibleRowid(pTab) );
+ for(ii=0; ii<ArraySize(azOpt); ii++){
+ int iCol;
+ for(iCol=0; iCol<pTab->nCol; iCol++){
+ if( sqlite3_stricmp(azOpt[ii], pTab->aCol[iCol].zCnName)==0 ) break;
+ }
+ if( iCol==pTab->nCol ){
+ return azOpt[ii];
+ }
+ }
+ return 0;
+}
+
+/*
** 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
+** or if the SELECT statement needs to be materialized into a transient
** table, then return NULL.
*/
#ifndef SQLITE_OMIT_SUBQUERY
@@ -108457,7 +111439,7 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
** IN_INDEX_INDEX_ASC - The cursor was opened on an ascending index.
** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index.
** IN_INDEX_EPH - The cursor was opened on a specially created and
-** populated epheremal table.
+** populated ephemeral table.
** IN_INDEX_NOOP - No cursor was allocated. The IN operator must be
** implemented as a sequence of comparisons.
**
@@ -108470,7 +111452,7 @@ static int sqlite3InRhsIsConstant(Expr *pIn){
** an ephemeral table might need to be generated from the RHS and then
** pX->iTable made to point to the ephemeral table instead of an
** existing table. In this case, the creation and initialization of the
-** ephmeral table might be put inside of a subroutine, the EP_Subrtn flag
+** ephemeral table might be put inside of a subroutine, the EP_Subrtn flag
** will be set on pX and the pX->y.sub fields will be set to show where
** the subroutine is coded.
**
@@ -108482,12 +111464,12 @@ 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 will be created unless the selected columns are guaranteed
+** An ephemeral table will be created 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
+** for fast set membership tests) then an ephemeral table must
** 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.
**
@@ -108647,7 +111629,6 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
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] );
@@ -108821,7 +111802,7 @@ SQLITE_PRIVATE void sqlite3VectorErrorMsg(Parse *pParse, Expr *pExpr){
** x IN (SELECT a FROM b) -- IN operator with subquery on the right
**
** The pExpr parameter is the IN operator. The cursor number for the
-** constructed ephermeral table is returned. The first time the ephemeral
+** constructed ephemeral table is returned. The first time the ephemeral
** table is computed, the cursor number is also stored in pExpr->iTable,
** however the cursor number returned might not be the same, as it might
** have been duplicated using OP_OpenDup.
@@ -109550,6 +112531,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(
){
int iAddr;
Vdbe *v = pParse->pVdbe;
+ int nErr = pParse->nErr;
assert( v!=0 );
assert( pParse->iSelfTab!=0 );
if( pParse->iSelfTab>0 ){
@@ -109562,6 +112544,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(
sqlite3VdbeAddOp4(v, OP_Affinity, regOut, 1, 0, &pCol->affinity, 1);
}
if( iAddr ) sqlite3VdbeJumpHere(v, iAddr);
+ if( pParse->nErr>nErr ) pParse->db->errByteOffset = -1;
}
#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
@@ -109578,6 +112561,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(
Column *pCol;
assert( v!=0 );
assert( pTab!=0 );
+ assert( iCol!=XN_EXPR );
if( iCol<0 || iCol==pTab->iPKey ){
sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
VdbeComment((v, "%s.rowid", pTab->zName));
@@ -109633,10 +112617,13 @@ SQLITE_PRIVATE int sqlite3ExprCodeGetColumn(
u8 p5 /* P5 value for OP_Column + FLAGS */
){
assert( pParse->pVdbe!=0 );
+ assert( (p5 & (OPFLAG_NOCHNG|OPFLAG_TYPEOFARG|OPFLAG_LENGTHARG))==p5 );
+ assert( IsVirtual(pTab) || (p5 & OPFLAG_NOCHNG)==0 );
sqlite3ExprCodeGetColumnOfTable(pParse->pVdbe, pTab, iTable, iColumn, iReg);
if( p5 ){
VdbeOp *pOp = sqlite3VdbeGetLastOp(pParse->pVdbe);
if( pOp->opcode==OP_Column ) pOp->p5 = p5;
+ if( pOp->opcode==OP_VColumn ) pOp->p5 = (p5 & OPFLAG_NOCHNG);
}
return iReg;
}
@@ -109665,7 +112652,7 @@ static void exprToRegister(Expr *pExpr, 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 result in contiguous 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
@@ -109705,7 +112692,7 @@ static int exprCodeVector(Parse *pParse, Expr *p, int *piFreeable){
*/
static void setDoNotMergeFlagOnCopy(Vdbe *v){
if( sqlite3VdbeGetLastOp(v)->opcode==OP_Copy ){
- sqlite3VdbeChangeP5(v, 1); /* Tag trailing OP_Copy as not mergable */
+ sqlite3VdbeChangeP5(v, 1); /* Tag trailing OP_Copy as not mergeable */
}
}
@@ -109795,13 +112782,13 @@ static int exprCodeInlineFunction(
}
case INLINEFUNC_implies_nonnull_row: {
- /* REsult of sqlite3ExprImpliesNonNullRow() */
+ /* Result of sqlite3ExprImpliesNonNullRow() */
Expr *pA1;
assert( nFarg==2 );
pA1 = pFarg->a[1].pExpr;
if( pA1->op==TK_COLUMN ){
sqlite3VdbeAddOp2(v, OP_Integer,
- sqlite3ExprImpliesNonNullRow(pFarg->a[0].pExpr,pA1->iTable),
+ sqlite3ExprImpliesNonNullRow(pFarg->a[0].pExpr,pA1->iTable,1),
target);
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
@@ -109890,6 +112877,41 @@ static SQLITE_NOINLINE int sqlite3IndexedExprLookup(
/*
+** Expresion pExpr is guaranteed to be a TK_COLUMN or equivalent. This
+** function checks the Parse.pIdxPartExpr list to see if this column
+** can be replaced with a constant value. If so, it generates code to
+** put the constant value in a register (ideally, but not necessarily,
+** register iTarget) and returns the register number.
+**
+** Or, if the TK_COLUMN cannot be replaced by a constant, zero is
+** returned.
+*/
+static int exprPartidxExprLookup(Parse *pParse, Expr *pExpr, int iTarget){
+ IndexedExpr *p;
+ for(p=pParse->pIdxPartExpr; p; p=p->pIENext){
+ if( pExpr->iColumn==p->iIdxCol && pExpr->iTable==p->iDataCur ){
+ Vdbe *v = pParse->pVdbe;
+ int addr = 0;
+ int ret;
+
+ if( p->bMaybeNullRow ){
+ addr = sqlite3VdbeAddOp1(v, OP_IfNullRow, p->iIdxCur);
+ }
+ ret = sqlite3ExprCodeTarget(pParse, p->pExpr, iTarget);
+ sqlite3VdbeAddOp4(pParse->pVdbe, OP_Affinity, ret, 1, 0,
+ (const char*)&p->aff, 1);
+ if( addr ){
+ sqlite3VdbeJumpHere(v, addr);
+ sqlite3VdbeChangeP3(v, addr, ret);
+ }
+ return ret;
+ }
+ }
+ return 0;
+}
+
+
+/*
** 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.
@@ -109925,12 +112947,25 @@ expr_code_doover:
assert( !ExprHasVVAProperty(pExpr,EP_Immutable) );
op = pExpr->op;
}
+ assert( op!=TK_ORDER );
switch( op ){
case TK_AGG_COLUMN: {
AggInfo *pAggInfo = pExpr->pAggInfo;
struct AggInfo_col *pCol;
assert( pAggInfo!=0 );
- assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
+ assert( pExpr->iAgg>=0 );
+ if( pExpr->iAgg>=pAggInfo->nColumn ){
+ /* Happens when the left table of a RIGHT JOIN is null and
+ ** is using an expression index */
+ sqlite3VdbeAddOp2(v, OP_Null, 0, target);
+#ifdef SQLITE_VDBE_COVERAGE
+ /* Verify that the OP_Null above is exercised by tests
+ ** tag-20230325-2 */
+ sqlite3VdbeAddOp3(v, OP_NotNull, target, 1, 20230325);
+ VdbeCoverageNeverTaken(v);
+#endif
+ break;
+ }
pCol = &pAggInfo->aCol[pExpr->iAgg];
if( !pAggInfo->directMode ){
return AggInfoColumnReg(pAggInfo, pExpr->iAgg);
@@ -109965,7 +113000,7 @@ expr_code_doover:
if( ExprHasProperty(pExpr, EP_FixedCol) ){
/* This COLUMN expression is really a constant due to WHERE clause
** constraints, and that constant is coded by the pExpr->pLeft
- ** expresssion. However, make sure the constant has the correct
+ ** expression. However, make sure the constant has the correct
** datatype by applying the Affinity of the table column to the
** constant.
*/
@@ -110034,6 +113069,11 @@ expr_code_doover:
iTab = pParse->iSelfTab - 1;
}
}
+ else if( pParse->pIdxPartExpr
+ && 0!=(r1 = exprPartidxExprLookup(pParse, pExpr, target))
+ ){
+ return r1;
+ }
assert( ExprUseYTab(pExpr) );
assert( pExpr->y.pTab!=0 );
iReg = sqlite3ExprCodeGetColumn(pParse, pExpr->y.pTab,
@@ -110105,11 +113145,8 @@ expr_code_doover:
#ifndef SQLITE_OMIT_CAST
case TK_CAST: {
/* Expressions of the form: CAST(pLeft AS token) */
- inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
- if( inReg!=target ){
- sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target);
- inReg = target;
- }
+ sqlite3ExprCode(pParse, pExpr->pLeft, target);
+ assert( inReg==target );
assert( !ExprHasProperty(pExpr, EP_IntValue) );
sqlite3VdbeAddOp2(v, OP_Cast, target,
sqlite3AffinityType(pExpr->u.zToken, 0));
@@ -110294,7 +113331,7 @@ expr_code_doover:
sqlite3ErrorMsg(pParse, "unknown function: %#T()", pExpr);
break;
}
- if( pDef->funcFlags & SQLITE_FUNC_INLINE ){
+ if( (pDef->funcFlags & SQLITE_FUNC_INLINE)!=0 && ALWAYS(pFarg!=0) ){
assert( (pDef->funcFlags & SQLITE_FUNC_UNSAFE)==0 );
assert( (pDef->funcFlags & SQLITE_FUNC_DIRECT)==0 );
return exprCodeInlineFunction(pParse, pFarg,
@@ -110320,10 +113357,10 @@ expr_code_doover:
r1 = sqlite3GetTempRange(pParse, nFarg);
}
- /* For length() and typeof() functions with a column argument,
+ /* For length() and typeof() and octet_length() functions,
** set the P5 parameter to the OP_Column opcode to OPFLAG_LENGTHARG
- ** or OPFLAG_TYPEOFARG respectively, to avoid unnecessary data
- ** loading.
+ ** or OPFLAG_TYPEOFARG or OPFLAG_BYTELENARG respectively, to avoid
+ ** unnecessary data loading.
*/
if( (pDef->funcFlags & (SQLITE_FUNC_LENGTH|SQLITE_FUNC_TYPEOF))!=0 ){
u8 exprOp;
@@ -110333,14 +113370,16 @@ expr_code_doover:
if( exprOp==TK_COLUMN || exprOp==TK_AGG_COLUMN ){
assert( SQLITE_FUNC_LENGTH==OPFLAG_LENGTHARG );
assert( SQLITE_FUNC_TYPEOF==OPFLAG_TYPEOFARG );
- testcase( pDef->funcFlags & OPFLAG_LENGTHARG );
- pFarg->a[0].pExpr->op2 =
- pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG);
+ assert( SQLITE_FUNC_BYTELEN==OPFLAG_BYTELENARG );
+ assert( (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG)==OPFLAG_BYTELENARG );
+ testcase( (pDef->funcFlags & OPFLAG_BYTELENARG)==OPFLAG_LENGTHARG );
+ testcase( (pDef->funcFlags & OPFLAG_BYTELENARG)==OPFLAG_TYPEOFARG );
+ testcase( (pDef->funcFlags & OPFLAG_BYTELENARG)==OPFLAG_BYTELENARG);
+ pFarg->a[0].pExpr->op2 = pDef->funcFlags & OPFLAG_BYTELENARG;
}
}
- sqlite3ExprCodeExprList(pParse, pFarg, r1, 0,
- SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
+ sqlite3ExprCodeExprList(pParse, pFarg, r1, 0, SQLITE_ECEL_FACTOR);
}else{
r1 = 0;
}
@@ -110448,13 +113487,9 @@ expr_code_doover:
** Clear subtypes as subtypes may not cross a subquery boundary.
*/
assert( pExpr->pLeft );
- inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
- if( inReg!=target ){
- sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target);
- inReg = target;
- }
- sqlite3VdbeAddOp1(v, OP_ClrSubtype, inReg);
- return inReg;
+ sqlite3ExprCode(pParse, pExpr->pLeft, target);
+ sqlite3VdbeAddOp1(v, OP_ClrSubtype, target);
+ return target;
}else{
pExpr = pExpr->pLeft;
goto expr_code_doover; /* 2018-04-28: Prevent deep recursion. */
@@ -110564,12 +113599,9 @@ expr_code_doover:
** "target" and not someplace else.
*/
pParse->okConstFactor = 0; /* note (1) above */
- inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
+ sqlite3ExprCode(pParse, pExpr->pLeft, target);
+ assert( target==inReg );
pParse->okConstFactor = okConstFactor;
- if( inReg!=target ){ /* note (2) above */
- sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target);
- inReg = target;
- }
sqlite3VdbeJumpHere(v, addrINR);
break;
}
@@ -110702,9 +113734,9 @@ expr_code_doover:
** once. If no functions are involved, then factor the code out and put it at
** the end of the prepared statement in the initialization section.
**
-** If regDest>=0 then the result is always stored in that register and the
+** If regDest>0 then the result is always stored in that register and the
** result is not reusable. If regDest<0 then this routine is free to
-** store the value whereever it wants. The register where the expression
+** store the value wherever it wants. The register where the expression
** is stored is returned. When regDest<0, two identical expressions might
** code to the same register, if they do not contain function calls and hence
** are factored out into the initialization section at the end of the
@@ -110717,6 +113749,7 @@ SQLITE_PRIVATE int sqlite3ExprCodeRunJustOnce(
){
ExprList *p;
assert( ConstFactorOk(pParse) );
+ assert( regDest!=0 );
p = pParse->pConstExpr;
if( regDest<0 && p ){
struct ExprList_item *pItem;
@@ -110807,7 +113840,11 @@ SQLITE_PRIVATE void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
if( inReg!=target ){
u8 op;
- if( ALWAYS(pExpr) && ExprHasProperty(pExpr,EP_Subquery) ){
+ Expr *pX = sqlite3ExprSkipCollateAndLikely(pExpr);
+ testcase( pX!=pExpr );
+ if( ALWAYS(pX)
+ && (ExprHasProperty(pX,EP_Subquery) || pX->op==TK_REGISTER)
+ ){
op = OP_Copy;
}else{
op = OP_SCopy;
@@ -111526,8 +114563,8 @@ SQLITE_PRIVATE int sqlite3ExprListCompare(const ExprList *pA, const ExprList *pB
*/
SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr *pA,Expr *pB, int iTab){
return sqlite3ExprCompare(0,
- sqlite3ExprSkipCollateAndLikely(pA),
- sqlite3ExprSkipCollateAndLikely(pB),
+ sqlite3ExprSkipCollate(pA),
+ sqlite3ExprSkipCollate(pB),
iTab);
}
@@ -111620,7 +114657,7 @@ static int exprImpliesNotNull(
** pE1: x!=123 pE2: x IS NOT NULL Result: true
** pE1: x!=?1 pE2: x IS NOT NULL Result: true
** pE1: x IS NULL pE2: x IS NOT NULL Result: false
-** pE1: x IS ?2 pE2: x IS NOT NULL Reuslt: false
+** pE1: x IS ?2 pE2: x IS NOT NULL Result: false
**
** When comparing TK_COLUMN nodes between pE1 and pE2, if pE2 has
** Expr.iTable<0 then assume a table number given by iTab.
@@ -111657,11 +114694,29 @@ SQLITE_PRIVATE int sqlite3ExprImpliesExpr(
return 0;
}
+/* This is a helper function to impliesNotNullRow(). In this routine,
+** set pWalker->eCode to one only if *both* of the input expressions
+** separately have the implies-not-null-row property.
+*/
+static void bothImplyNotNullRow(Walker *pWalker, Expr *pE1, Expr *pE2){
+ if( pWalker->eCode==0 ){
+ sqlite3WalkExpr(pWalker, pE1);
+ if( pWalker->eCode ){
+ pWalker->eCode = 0;
+ sqlite3WalkExpr(pWalker, pE2);
+ }
+ }
+}
+
/*
** This is the Expr node callback for sqlite3ExprImpliesNonNullRow().
** If the expression node requires that the table at pWalker->iCur
** have one or more non-NULL column, then set pWalker->eCode to 1 and abort.
**
+** pWalker->mWFlags is non-zero if this inquiry is being undertaking on
+** behalf of a RIGHT JOIN (or FULL JOIN). That makes a difference when
+** evaluating terms in the ON clause of an inner join.
+**
** This routine controls an optimization. False positives (setting
** pWalker->eCode to 1 when it should not be) are deadly, but false-negatives
** (never setting pWalker->eCode) is a harmless missed optimization.
@@ -111670,28 +114725,33 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
testcase( pExpr->op==TK_AGG_COLUMN );
testcase( pExpr->op==TK_AGG_FUNCTION );
if( ExprHasProperty(pExpr, EP_OuterON) ) return WRC_Prune;
+ if( ExprHasProperty(pExpr, EP_InnerON) && pWalker->mWFlags ){
+ /* If iCur is used in an inner-join ON clause to the left of a
+ ** RIGHT JOIN, that does *not* mean that the table must be non-null.
+ ** But it is difficult to check for that condition precisely.
+ ** To keep things simple, any use of iCur from any inner-join is
+ ** ignored while attempting to simplify a RIGHT JOIN. */
+ return WRC_Prune;
+ }
switch( pExpr->op ){
case TK_ISNOT:
case TK_ISNULL:
case TK_NOTNULL:
case TK_IS:
- case TK_OR:
case TK_VECTOR:
- case TK_CASE:
- case TK_IN:
case TK_FUNCTION:
case TK_TRUTH:
+ case TK_CASE:
testcase( pExpr->op==TK_ISNOT );
testcase( pExpr->op==TK_ISNULL );
testcase( pExpr->op==TK_NOTNULL );
testcase( pExpr->op==TK_IS );
- testcase( pExpr->op==TK_OR );
testcase( pExpr->op==TK_VECTOR );
- testcase( pExpr->op==TK_CASE );
- testcase( pExpr->op==TK_IN );
testcase( pExpr->op==TK_FUNCTION );
testcase( pExpr->op==TK_TRUTH );
+ testcase( pExpr->op==TK_CASE );
return WRC_Prune;
+
case TK_COLUMN:
if( pWalker->u.iCur==pExpr->iTable ){
pWalker->eCode = 1;
@@ -111699,21 +114759,38 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
}
return WRC_Prune;
+ case TK_OR:
case TK_AND:
- if( pWalker->eCode==0 ){
+ /* Both sides of an AND or OR must separately imply non-null-row.
+ ** Consider these cases:
+ ** 1. NOT (x AND y)
+ ** 2. x OR y
+ ** If only one of x or y is non-null-row, then the overall expression
+ ** can be true if the other arm is false (case 1) or true (case 2).
+ */
+ testcase( pExpr->op==TK_OR );
+ testcase( pExpr->op==TK_AND );
+ bothImplyNotNullRow(pWalker, pExpr->pLeft, pExpr->pRight);
+ return WRC_Prune;
+
+ case TK_IN:
+ /* Beware of "x NOT IN ()" and "x NOT IN (SELECT 1 WHERE false)",
+ ** both of which can be true. But apart from these cases, if
+ ** the left-hand side of the IN is NULL then the IN itself will be
+ ** NULL. */
+ if( ExprUseXList(pExpr) && ALWAYS(pExpr->x.pList->nExpr>0) ){
sqlite3WalkExpr(pWalker, pExpr->pLeft);
- if( pWalker->eCode ){
- pWalker->eCode = 0;
- sqlite3WalkExpr(pWalker, pExpr->pRight);
- }
}
return WRC_Prune;
case TK_BETWEEN:
- if( sqlite3WalkExpr(pWalker, pExpr->pLeft)==WRC_Abort ){
- assert( pWalker->eCode );
- return WRC_Abort;
- }
+ /* In "x NOT BETWEEN y AND z" either x must be non-null-row or else
+ ** both y and z must be non-null row */
+ assert( ExprUseXList(pExpr) );
+ assert( pExpr->x.pList->nExpr==2 );
+ sqlite3WalkExpr(pWalker, pExpr->pLeft);
+ bothImplyNotNullRow(pWalker, pExpr->x.pList->a[0].pExpr,
+ pExpr->x.pList->a[1].pExpr);
return WRC_Prune;
/* Virtual tables are allowed to use constraints like x=NULL. So
@@ -111775,7 +114852,7 @@ static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){
** be non-NULL, then the LEFT JOIN can be safely converted into an
** ordinary join.
*/
-SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){
+SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab, int isRJ){
Walker w;
p = sqlite3ExprSkipCollateAndLikely(p);
if( p==0 ) return 0;
@@ -111783,7 +114860,7 @@ SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){
p = p->pLeft;
}else{
while( p->op==TK_AND ){
- if( sqlite3ExprImpliesNonNullRow(p->pLeft, iTab) ) return 1;
+ if( sqlite3ExprImpliesNonNullRow(p->pLeft, iTab, isRJ) ) return 1;
p = p->pRight;
}
}
@@ -111791,6 +114868,7 @@ SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){
w.xSelectCallback = 0;
w.xSelectCallback2 = 0;
w.eCode = 0;
+ w.mWFlags = isRJ!=0;
w.u.iCur = iTab;
sqlite3WalkExpr(&w, p);
return w.eCode;
@@ -111851,7 +114929,7 @@ SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(
}
-/* Structure used to pass information throught the Walker in order to
+/* Structure used to pass information throughout the Walker in order to
** implement sqlite3ReferencesSrcList().
*/
struct RefSrcList {
@@ -111958,6 +115036,12 @@ SQLITE_PRIVATE int sqlite3ReferencesSrcList(Parse *pParse, Expr *pExpr, SrcList
assert( pExpr->op==TK_AGG_FUNCTION );
assert( ExprUseXList(pExpr) );
sqlite3WalkExprList(&w, pExpr->x.pList);
+ if( pExpr->pLeft ){
+ assert( pExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pExpr->pLeft) );
+ assert( pExpr->pLeft->x.pList!=0 );
+ sqlite3WalkExprList(&w, pExpr->pLeft->x.pList);
+ }
#ifndef SQLITE_OMIT_WINDOWFUNC
if( ExprHasProperty(pExpr, EP_WinFunc) ){
sqlite3WalkExpr(&w, pExpr->y.pWin->pFilter);
@@ -111992,9 +115076,11 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
int iAgg = pExpr->iAgg;
Parse *pParse = pWalker->pParse;
sqlite3 *db = pParse->db;
+ assert( iAgg>=0 );
if( pExpr->op!=TK_AGG_FUNCTION ){
- assert( iAgg>=0 && iAgg<pAggInfo->nColumn );
- if( pAggInfo->aCol[iAgg].pCExpr==pExpr ){
+ if( iAgg<pAggInfo->nColumn
+ && pAggInfo->aCol[iAgg].pCExpr==pExpr
+ ){
pExpr = sqlite3ExprDup(db, pExpr, 0);
if( pExpr ){
pAggInfo->aCol[iAgg].pCExpr = pExpr;
@@ -112003,8 +115089,9 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
}
}else{
assert( pExpr->op==TK_AGG_FUNCTION );
- assert( iAgg>=0 && iAgg<pAggInfo->nFunc );
- if( pAggInfo->aFunc[iAgg].pFExpr==pExpr ){
+ if( ALWAYS(iAgg<pAggInfo->nFunc)
+ && pAggInfo->aFunc[iAgg].pFExpr==pExpr
+ ){
pExpr = sqlite3ExprDup(db, pExpr, 0);
if( pExpr ){
pAggInfo->aFunc[iAgg].pFExpr = pExpr;
@@ -112064,7 +115151,7 @@ static int addAggInfoFunc(sqlite3 *db, AggInfo *pInfo){
** Return the index in aCol[] of the entry that describes that column.
**
** If no prior entry is found, create a new one and return -1. The
-** new column will have an idex of pAggInfo->nColumn-1.
+** new column will have an index of pAggInfo->nColumn-1.
*/
static void findOrCreateAggInfoColumn(
Parse *pParse, /* Parsing context */
@@ -112077,6 +115164,7 @@ static void findOrCreateAggInfoColumn(
assert( pAggInfo->iFirstReg==0 );
pCol = pAggInfo->aCol;
for(k=0; k<pAggInfo->nColumn; k++, pCol++){
+ if( pCol->pCExpr==pExpr ) return;
if( pCol->iTable==pExpr->iTable
&& pCol->iColumn==pExpr->iColumn
&& pExpr->op!=TK_IF_NULL_ROW
@@ -112154,7 +115242,12 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
}
if( pIEpr==0 ) break;
if( NEVER(!ExprUseYTab(pExpr)) ) break;
- if( pExpr->pAggInfo!=0 ) break; /* Already resolved by outer context */
+ for(i=0; i<pSrcList->nSrc; i++){
+ if( pSrcList->a[0].iCursor==pIEpr->iDataCur ) break;
+ }
+ if( i>=pSrcList->nSrc ) break;
+ if( NEVER(pExpr->pAggInfo!=0) ) break; /* Resolved by outer context */
+ if( pParse->nErr ){ return WRC_Abort; }
/* If we reach this point, it means that expression pExpr can be
** translated into a reference to an index column as described by
@@ -112165,6 +115258,9 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
tmp.iTable = pIEpr->iIdxCur;
tmp.iColumn = pIEpr->iIdxCol;
findOrCreateAggInfoColumn(pParse, pAggInfo, &tmp);
+ if( pParse->nErr ){ return WRC_Abort; }
+ assert( pAggInfo->aCol!=0 );
+ assert( tmp.iAgg<pAggInfo->nColumn );
pAggInfo->aCol[tmp.iAgg].pCExpr = pExpr;
pExpr->pAggInfo = pAggInfo;
pExpr->iAgg = tmp.iAgg;
@@ -112188,18 +115284,19 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
} /* endif pExpr->iTable==pItem->iCursor */
} /* end loop over pSrcList */
}
- return WRC_Prune;
+ return WRC_Continue;
}
case TK_AGG_FUNCTION: {
if( (pNC->ncFlags & NC_InAggFunc)==0
&& pWalker->walkerDepth==pExpr->op2
+ && pExpr->pAggInfo==0
){
/* Check to see if pExpr is a duplicate of another aggregate
** function that is already in the pAggInfo structure
*/
struct AggInfo_func *pItem = pAggInfo->aFunc;
for(i=0; i<pAggInfo->nFunc; i++, pItem++){
- if( pItem->pFExpr==pExpr ) break;
+ if( NEVER(pItem->pFExpr==pExpr) ) break;
if( sqlite3ExprCompare(0, pItem->pFExpr, pExpr, -1)==0 ){
break;
}
@@ -112210,14 +115307,44 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
u8 enc = ENC(pParse->db);
i = addAggInfoFunc(pParse->db, pAggInfo);
if( i>=0 ){
+ int nArg;
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
pItem = &pAggInfo->aFunc[i];
pItem->pFExpr = pExpr;
assert( ExprUseUToken(pExpr) );
+ nArg = pExpr->x.pList ? pExpr->x.pList->nExpr : 0;
pItem->pFunc = sqlite3FindFunction(pParse->db,
- pExpr->u.zToken,
- pExpr->x.pList ? pExpr->x.pList->nExpr : 0, enc, 0);
- if( pExpr->flags & EP_Distinct ){
+ pExpr->u.zToken, nArg, enc, 0);
+ assert( pItem->bOBUnique==0 );
+ if( pExpr->pLeft
+ && (pItem->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)==0
+ ){
+ /* The NEEDCOLL test above causes any ORDER BY clause on
+ ** aggregate min() or max() to be ignored. */
+ ExprList *pOBList;
+ assert( nArg>0 );
+ assert( pExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pExpr->pLeft) );
+ pItem->iOBTab = pParse->nTab++;
+ pOBList = pExpr->pLeft->x.pList;
+ assert( pOBList->nExpr>0 );
+ assert( pItem->bOBUnique==0 );
+ if( pOBList->nExpr==1
+ && nArg==1
+ && sqlite3ExprCompare(0,pOBList->a[0].pExpr,
+ pExpr->x.pList->a[0].pExpr,0)==0
+ ){
+ pItem->bOBPayload = 0;
+ pItem->bOBUnique = ExprHasProperty(pExpr, EP_Distinct);
+ }else{
+ pItem->bOBPayload = 1;
+ }
+ pItem->bUseSubtype =
+ (pItem->pFunc->funcFlags & SQLITE_SUBTYPE)!=0;
+ }else{
+ pItem->iOBTab = -1;
+ }
+ if( ExprHasProperty(pExpr, EP_Distinct) && !pItem->bOBUnique ){
pItem->iDistinct = pParse->nTab++;
}else{
pItem->iDistinct = -1;
@@ -112342,6 +115469,37 @@ SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse *pParse){
}
/*
+** Make sure sufficient registers have been allocated so that
+** iReg is a valid register number.
+*/
+SQLITE_PRIVATE void sqlite3TouchRegister(Parse *pParse, int iReg){
+ if( pParse->nMem<iReg ) pParse->nMem = iReg;
+}
+
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_DEBUG)
+/*
+** Return the latest reusable register in the set of all registers.
+** The value returned is no less than iMin. If any register iMin or
+** greater is in permanent use, then return one more than that last
+** permanent register.
+*/
+SQLITE_PRIVATE int sqlite3FirstAvailableRegister(Parse *pParse, int iMin){
+ const ExprList *pList = pParse->pConstExpr;
+ if( pList ){
+ int i;
+ for(i=0; i<pList->nExpr; i++){
+ if( pList->a[i].u.iConstExprReg>=iMin ){
+ iMin = pList->a[i].u.iConstExprReg + 1;
+ }
+ }
+ }
+ pParse->nTempReg = 0;
+ pParse->nRangeReg = 0;
+ return iMin;
+}
+#endif /* SQLITE_ENABLE_STAT4 || SQLITE_DEBUG */
+
+/*
** Validate that no temporary register falls within the range of
** iFirst..iLast, inclusive. This routine is only call from within assert()
** statements.
@@ -112360,6 +115518,14 @@ SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){
return 0;
}
}
+ if( pParse->pConstExpr ){
+ ExprList *pList = pParse->pConstExpr;
+ for(i=0; i<pList->nExpr; i++){
+ int iReg = pList->a[i].u.iConstExprReg;
+ if( iReg==0 ) continue;
+ if( iReg>=iFirst && iReg<=iLast ) return 0;
+ }
+ }
return 1;
}
#endif /* SQLITE_DEBUG */
@@ -112814,14 +115980,19 @@ SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){
/* Verify that constraints are still satisfied */
if( pNew->pCheck!=0
|| (pCol->notNull && (pCol->colFlags & COLFLAG_GENERATED)!=0)
+ || (pTab->tabFlags & TF_Strict)!=0
){
sqlite3NestedParse(pParse,
"SELECT CASE WHEN quick_check GLOB 'CHECK*'"
" THEN raise(ABORT,'CHECK constraint failed')"
+ " WHEN quick_check GLOB 'non-* value in*'"
+ " THEN raise(ABORT,'type mismatch on DEFAULT')"
" ELSE raise(ABORT,'NOT NULL constraint failed')"
" END"
" FROM pragma_quick_check(%Q,%Q)"
- " WHERE quick_check GLOB 'CHECK*' OR quick_check GLOB 'NULL*'",
+ " WHERE quick_check GLOB 'CHECK*'"
+ " OR quick_check GLOB 'NULL*'"
+ " OR quick_check GLOB 'non-* value in*'",
zTab, zDb
);
}
@@ -112910,7 +116081,7 @@ SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
pNew->u.tab.pDfltList = sqlite3ExprListDup(db, pTab->u.tab.pDfltList, 0);
pNew->pSchema = db->aDb[iDb].pSchema;
pNew->u.tab.addColOffset = pTab->u.tab.addColOffset;
- pNew->nTabRef = 1;
+ assert( pNew->nTabRef==1 );
exit_begin_add_column:
sqlite3SrcListDelete(db, pSrc);
@@ -113415,7 +116586,7 @@ static RenameToken *renameColumnTokenNext(RenameCtx *pCtx){
}
/*
-** An error occured while parsing or otherwise processing a database
+** An error occurred while parsing or otherwise processing a database
** object (either pParse->pNewTable, pNewIndex or pNewTrigger) as part of an
** ALTER TABLE RENAME COLUMN program. The error message emitted by the
** sub-routine is currently stored in pParse->zErrMsg. This function
@@ -113648,6 +116819,19 @@ static int renameEditSql(
}
/*
+** Set all pEList->a[].fg.eEName fields in the expression-list to val.
+*/
+static void renameSetENames(ExprList *pEList, int val){
+ if( pEList ){
+ int i;
+ for(i=0; i<pEList->nExpr; i++){
+ assert( val==ENAME_NAME || pEList->a[i].fg.eEName==ENAME_NAME );
+ pEList->a[i].fg.eEName = val;
+ }
+ }
+}
+
+/*
** Resolve all symbols in the trigger at pParse->pNewTrigger, assuming
** it was read from the schema of database zDb. Return SQLITE_OK if
** successful. Otherwise, return an SQLite error code and leave an error
@@ -113694,7 +116878,17 @@ static int renameResolveTrigger(Parse *pParse){
pSrc = 0;
rc = SQLITE_NOMEM;
}else{
+ /* pStep->pExprList contains an expression-list used for an UPDATE
+ ** statement. So the a[].zEName values are the RHS of the
+ ** "<col> = <expr>" clauses of the UPDATE statement. So, before
+ ** running SelectPrep(), change all the eEName values in
+ ** pStep->pExprList to ENAME_SPAN (from their current value of
+ ** ENAME_NAME). This is to prevent any ids in ON() clauses that are
+ ** part of pSrc from being incorrectly resolved against the
+ ** a[].zEName values as if they were column aliases. */
+ renameSetENames(pStep->pExprList, ENAME_SPAN);
sqlite3SelectPrep(pParse, pSel, 0);
+ renameSetENames(pStep->pExprList, ENAME_NAME);
rc = pParse->nErr ? SQLITE_ERROR : SQLITE_OK;
assert( pStep->pExprList==0 || pStep->pExprList==pSel->pEList );
assert( pSrc==pSel->pSrc );
@@ -114913,9 +118107,9 @@ static void openStatTable(
typedef struct StatAccum StatAccum;
typedef struct StatSample StatSample;
struct StatSample {
- tRowcnt *anEq; /* sqlite_stat4.nEq */
tRowcnt *anDLt; /* sqlite_stat4.nDLt */
#ifdef SQLITE_ENABLE_STAT4
+ tRowcnt *anEq; /* sqlite_stat4.nEq */
tRowcnt *anLt; /* sqlite_stat4.nLt */
union {
i64 iRowid; /* Rowid in main table of the key */
@@ -115073,9 +118267,9 @@ static void statInit(
/* Allocate the space required for the StatAccum object */
n = sizeof(*p)
- + sizeof(tRowcnt)*nColUp /* StatAccum.anEq */
- + sizeof(tRowcnt)*nColUp; /* StatAccum.anDLt */
+ + sizeof(tRowcnt)*nColUp; /* StatAccum.anDLt */
#ifdef SQLITE_ENABLE_STAT4
+ n += sizeof(tRowcnt)*nColUp; /* StatAccum.anEq */
if( mxSample ){
n += sizeof(tRowcnt)*nColUp /* StatAccum.anLt */
+ sizeof(StatSample)*(nCol+mxSample) /* StatAccum.aBest[], a[] */
@@ -115096,9 +118290,9 @@ static void statInit(
p->nKeyCol = nKeyCol;
p->nSkipAhead = 0;
p->current.anDLt = (tRowcnt*)&p[1];
- p->current.anEq = &p->current.anDLt[nColUp];
#ifdef SQLITE_ENABLE_STAT4
+ p->current.anEq = &p->current.anDLt[nColUp];
p->mxSample = p->nLimit==0 ? mxSample : 0;
if( mxSample ){
u8 *pSpace; /* Allocated space not yet assigned */
@@ -115365,7 +118559,9 @@ static void statPush(
if( p->nRow==0 ){
/* This is the first call to this function. Do initialization. */
+#ifdef SQLITE_ENABLE_STAT4
for(i=0; i<p->nCol; i++) p->current.anEq[i] = 1;
+#endif
}else{
/* Second and subsequent calls get processed here */
#ifdef SQLITE_ENABLE_STAT4
@@ -115374,15 +118570,17 @@ static void statPush(
/* Update anDLt[], anLt[] and anEq[] to reflect the values that apply
** to the current row of the index. */
+#ifdef SQLITE_ENABLE_STAT4
for(i=0; i<iChng; i++){
p->current.anEq[i]++;
}
+#endif
for(i=iChng; i<p->nCol; i++){
p->current.anDLt[i]++;
#ifdef SQLITE_ENABLE_STAT4
if( p->mxSample ) p->current.anLt[i] += p->current.anEq[i];
-#endif
p->current.anEq[i] = 1;
+#endif
}
}
@@ -115516,7 +118714,9 @@ static void statGet(
u64 iVal = (p->nRow + nDistinct - 1) / nDistinct;
if( iVal==2 && p->nRow*10 <= nDistinct*11 ) iVal = 1;
sqlite3_str_appendf(&sStat, " %llu", iVal);
+#ifdef SQLITE_ENABLE_STAT4
assert( p->current.anEq[i] );
+#endif
}
sqlite3ResultStrAccum(context, &sStat);
}
@@ -115643,11 +118843,15 @@ static void analyzeOneTable(
int regIdxname = iMem++; /* Register containing index name */
int regStat1 = iMem++; /* Value for the stat column of sqlite_stat1 */
int regPrev = iMem; /* MUST BE LAST (see below) */
+#ifdef SQLITE_ENABLE_STAT4
+ int doOnce = 1; /* Flag for a one-time computation */
+#endif
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
Table *pStat1 = 0;
#endif
- pParse->nMem = MAX(pParse->nMem, iMem);
+ sqlite3TouchRegister(pParse, iMem);
+ assert( sqlite3NoTempsInRange(pParse, regNewRowid, iMem) );
v = sqlite3GetVdbe(pParse);
if( v==0 || NEVER(pTab==0) ){
return;
@@ -115753,7 +118957,7 @@ static void analyzeOneTable(
** the regPrev array and a trailing rowid (the rowid slot is required
** when building a record to insert into the sample column of
** the sqlite_stat4 table. */
- pParse->nMem = MAX(pParse->nMem, regPrev+nColTest);
+ sqlite3TouchRegister(pParse, regPrev+nColTest);
/* Open a read-only cursor on the index being analyzed. */
assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) );
@@ -115925,7 +119129,35 @@ static void analyzeOneTable(
int addrIsNull;
u8 seekOp = HasRowid(pTab) ? OP_NotExists : OP_NotFound;
- pParse->nMem = MAX(pParse->nMem, regCol+nCol);
+ if( doOnce ){
+ int mxCol = nCol;
+ Index *pX;
+
+ /* Compute the maximum number of columns in any index */
+ for(pX=pTab->pIndex; pX; pX=pX->pNext){
+ int nColX; /* Number of columns in pX */
+ if( !HasRowid(pTab) && IsPrimaryKeyIndex(pX) ){
+ nColX = pX->nKeyCol;
+ }else{
+ nColX = pX->nColumn;
+ }
+ if( nColX>mxCol ) mxCol = nColX;
+ }
+
+ /* Allocate space to compute results for the largest index */
+ sqlite3TouchRegister(pParse, regCol+mxCol);
+ doOnce = 0;
+#ifdef SQLITE_DEBUG
+ /* Verify that the call to sqlite3ClearTempRegCache() below
+ ** really is needed.
+ ** https://sqlite.org/forum/forumpost/83cb4a95a0 (2023-03-25)
+ */
+ testcase( !sqlite3NoTempsInRange(pParse, regEq, regCol+mxCol) );
+#endif
+ sqlite3ClearTempRegCache(pParse); /* tag-20230325-1 */
+ assert( sqlite3NoTempsInRange(pParse, regEq, regCol+mxCol) );
+ }
+ assert( sqlite3NoTempsInRange(pParse, regEq, regCol+nCol) );
addrNext = sqlite3VdbeCurrentAddr(v);
callStatGet(pParse, regStat, STAT_GET_ROWID, regSampleRowid);
@@ -116006,6 +119238,11 @@ static void analyzeDatabase(Parse *pParse, int iDb){
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
Table *pTab = (Table*)sqliteHashData(k);
analyzeOneTable(pParse, pTab, 0, iStatCur, iMem, iTab);
+#ifdef SQLITE_ENABLE_STAT4
+ iMem = sqlite3FirstAvailableRegister(pParse, iMem);
+#else
+ assert( iMem==sqlite3FirstAvailableRegister(pParse,iMem) );
+#endif
}
loadAnalysis(pParse, iDb);
}
@@ -116168,6 +119405,16 @@ static void decodeIntArray(
while( z[0]!=0 && z[0]!=' ' ) z++;
while( z[0]==' ' ) z++;
}
+
+ /* Set the bLowQual flag if the peak number of rows obtained
+ ** from a full equality match is so large that a full table scan
+ ** seems likely to be faster than using the index.
+ */
+ if( aLog[0] > 66 /* Index has more than 100 rows */
+ && aLog[0] <= aLog[nOut-1] /* And only a single value seen */
+ ){
+ pIndex->bLowQual = 1;
+ }
}
}
@@ -116393,6 +119640,10 @@ static int loadStatTbl(
pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
assert( pIdx==0 || pIdx->nSample==0 );
if( pIdx==0 ) continue;
+ if( pIdx->aSample!=0 ){
+ /* The same index appears in sqlite_stat4 under multiple names */
+ continue;
+ }
assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 );
if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){
nIdxCol = pIdx->nKeyCol;
@@ -116400,6 +119651,7 @@ static int loadStatTbl(
nIdxCol = pIdx->nColumn;
}
pIdx->nSampleCol = nIdxCol;
+ pIdx->mxSample = nSample;
nByte = sizeof(IndexSample) * nSample;
nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample;
nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */
@@ -116439,6 +119691,11 @@ static int loadStatTbl(
if( zIndex==0 ) continue;
pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
if( pIdx==0 ) continue;
+ if( pIdx->nSample>=pIdx->mxSample ){
+ /* Too many slots used because the same index appears in
+ ** sqlite_stat4 using multiple names */
+ continue;
+ }
/* This next condition is true if data has already been loaded from
** the sqlite_stat4 table. */
nCol = pIdx->nSampleCol;
@@ -116451,14 +119708,15 @@ static int loadStatTbl(
decodeIntArray((char*)sqlite3_column_text(pStmt,2),nCol,pSample->anLt,0,0);
decodeIntArray((char*)sqlite3_column_text(pStmt,3),nCol,pSample->anDLt,0,0);
- /* Take a copy of the sample. Add two 0x00 bytes the end of the buffer.
+ /* Take a copy of the sample. Add 8 extra 0x00 bytes the end of the buffer.
** This is in case the sample record is corrupted. In that case, the
** sqlite3VdbeRecordCompare() may read up to two varints past the
** end of the allocated buffer before it realizes it is dealing with
- ** a corrupt record. Adding the two 0x00 bytes prevents this from causing
+ ** a corrupt record. Or it might try to read a large integer from the
+ ** buffer. In any case, eight 0x00 bytes prevents this from causing
** a buffer overread. */
pSample->n = sqlite3_column_bytes(pStmt, 4);
- pSample->p = sqlite3DbMallocZero(db, pSample->n + 2);
+ pSample->p = sqlite3DbMallocZero(db, pSample->n + 8);
if( pSample->p==0 ){
sqlite3_finalize(pStmt);
return SQLITE_NOMEM_BKPT;
@@ -116482,11 +119740,12 @@ static int loadStat4(sqlite3 *db, const char *zDb){
const Table *pStat4;
assert( db->lookaside.bDisable );
- if( (pStat4 = sqlite3FindTable(db, "sqlite_stat4", zDb))!=0
+ if( OptimizationEnabled(db, SQLITE_Stat4)
+ && (pStat4 = sqlite3FindTable(db, "sqlite_stat4", zDb))!=0
&& IsOrdinaryTable(pStat4)
){
rc = loadStatTbl(db,
- "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx",
+ "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx COLLATE nocase",
"SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4",
zDb
);
@@ -117415,7 +120674,7 @@ SQLITE_PRIVATE int sqlite3AuthCheck(
sqlite3 *db = pParse->db;
int rc;
- /* Don't do any authorization checks if the database is initialising
+ /* Don't do any authorization checks if the database is initializing
** or if the parser is being invoked from within sqlite3_declare_vtab.
*/
assert( !IN_RENAME_OBJECT || db->xAuth==0 );
@@ -117716,29 +120975,26 @@ SQLITE_PRIVATE void sqlite3FinishCoding(Parse *pParse){
pParse->nVtabLock = 0;
#endif
+#ifndef SQLITE_OMIT_SHARED_CACHE
/* Once all the cookies have been verified and transactions opened,
** obtain the required table-locks. This is a no-op unless the
** shared-cache feature is enabled.
*/
- codeTableLocks(pParse);
+ if( pParse->nTableLock ) codeTableLocks(pParse);
+#endif
/* Initialize any AUTOINCREMENT data structures required.
*/
- sqlite3AutoincrementBegin(pParse);
+ if( pParse->pAinc ) sqlite3AutoincrementBegin(pParse);
- /* Code constant expressions that where factored out of inner loops.
- **
- ** The pConstExpr list might also contain expressions that we simply
- ** want to keep around until the Parse object is deleted. Such
- ** expressions have iConstExprReg==0. Do not generate code for
- ** those expressions, of course.
+ /* Code constant expressions that were factored out of inner loops.
*/
if( pParse->pConstExpr ){
ExprList *pEL = pParse->pConstExpr;
pParse->okConstFactor = 0;
for(i=0; i<pEL->nExpr; i++){
- int iReg = pEL->a[i].u.iConstExprReg;
- sqlite3ExprCode(pParse, pEL->a[i].pExpr, iReg);
+ assert( pEL->a[i].u.iConstExprReg>0 );
+ sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg);
}
}
@@ -118205,7 +121461,7 @@ SQLITE_PRIVATE void sqlite3ColumnSetExpr(
*/
SQLITE_PRIVATE Expr *sqlite3ColumnExpr(Table *pTab, Column *pCol){
if( pCol->iDflt==0 ) return 0;
- if( NEVER(!IsOrdinaryTable(pTab)) ) return 0;
+ if( !IsOrdinaryTable(pTab) ) return 0;
if( NEVER(pTab->u.tab.pDfltList==0) ) return 0;
if( NEVER(pTab->u.tab.pDfltList->nExpr<pCol->iDflt) ) return 0;
return pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr;
@@ -118237,7 +121493,7 @@ SQLITE_PRIVATE void sqlite3ColumnSetColl(
}
/*
-** Return the collating squence name for a column
+** Return the collating sequence name for a column
*/
SQLITE_PRIVATE const char *sqlite3ColumnColl(Column *pCol){
const char *z;
@@ -118330,7 +121586,7 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
if( IsOrdinaryTable(pTable) ){
sqlite3FkDelete(db, pTable);
}
-#ifndef SQLITE_OMIT_VIRTUAL_TABLE
+#ifndef SQLITE_OMIT_VIRTUALTABLE
else if( IsVirtual(pTable) ){
sqlite3VtabClear(db, pTable);
}
@@ -118358,6 +121614,9 @@ SQLITE_PRIVATE void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
if( db->pnBytesFreed==0 && (--pTable->nTabRef)>0 ) return;
deleteTable(db, pTable);
}
+SQLITE_PRIVATE void sqlite3DeleteTableGeneric(sqlite3 *db, void *pTable){
+ sqlite3DeleteTable(db, (Table*)pTable);
+}
/*
@@ -118893,19 +122152,13 @@ SQLITE_PRIVATE void sqlite3ColumnPropertiesFromName(Table *pTab, Column *pCol){
#endif
/*
-** Name of the special TEMP trigger used to implement RETURNING. The
-** name begins with "sqlite_" so that it is guaranteed not to collide
-** with any application-generated triggers.
-*/
-#define RETURNING_TRIGGER_NAME "sqlite_returning"
-
-/*
** Clean up the data structures associated with the RETURNING clause.
*/
-static void sqlite3DeleteReturning(sqlite3 *db, Returning *pRet){
+static void sqlite3DeleteReturning(sqlite3 *db, void *pArg){
+ Returning *pRet = (Returning*)pArg;
Hash *pHash;
pHash = &(db->aDb[1].pSchema->trigHash);
- sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, 0);
+ sqlite3HashInsert(pHash, pRet->zName, 0);
sqlite3ExprListDelete(db, pRet->pReturnEL);
sqlite3DbFree(db, pRet);
}
@@ -118933,7 +122186,7 @@ SQLITE_PRIVATE void sqlite3AddReturning(Parse *pParse, ExprList *pList){
if( pParse->pNewTrigger ){
sqlite3ErrorMsg(pParse, "cannot use RETURNING in a trigger");
}else{
- assert( pParse->bReturning==0 );
+ assert( pParse->bReturning==0 || pParse->ifNotExists );
}
pParse->bReturning = 1;
pRet = sqlite3DbMallocZero(db, sizeof(*pRet));
@@ -118944,11 +122197,12 @@ SQLITE_PRIVATE void sqlite3AddReturning(Parse *pParse, ExprList *pList){
pParse->u1.pReturning = pRet;
pRet->pParse = pParse;
pRet->pReturnEL = pList;
- sqlite3ParserAddCleanup(pParse,
- (void(*)(sqlite3*,void*))sqlite3DeleteReturning, pRet);
+ sqlite3ParserAddCleanup(pParse, sqlite3DeleteReturning, pRet);
testcase( pParse->earlyCleanup );
if( db->mallocFailed ) return;
- pRet->retTrig.zName = RETURNING_TRIGGER_NAME;
+ sqlite3_snprintf(sizeof(pRet->zName), pRet->zName,
+ "sqlite_returning_%p", pParse);
+ pRet->retTrig.zName = pRet->zName;
pRet->retTrig.op = TK_RETURNING;
pRet->retTrig.tr_tm = TRIGGER_AFTER;
pRet->retTrig.bReturning = 1;
@@ -118959,8 +122213,9 @@ SQLITE_PRIVATE void sqlite3AddReturning(Parse *pParse, ExprList *pList){
pRet->retTStep.pTrig = &pRet->retTrig;
pRet->retTStep.pExprList = pList;
pHash = &(db->aDb[1].pSchema->trigHash);
- assert( sqlite3HashFind(pHash, RETURNING_TRIGGER_NAME)==0 || pParse->nErr );
- if( sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, &pRet->retTrig)
+ assert( sqlite3HashFind(pHash, pRet->zName)==0
+ || pParse->nErr || pParse->ifNotExists );
+ if( sqlite3HashInsert(pHash, pRet->zName, &pRet->retTrig)
==&pRet->retTrig ){
sqlite3OomFault(db);
}
@@ -118994,7 +122249,7 @@ SQLITE_PRIVATE void sqlite3AddColumn(Parse *pParse, Token sName, Token sType){
}
if( !IN_RENAME_OBJECT ) sqlite3DequoteToken(&sName);
- /* Because keywords GENERATE ALWAYS can be converted into indentifiers
+ /* Because keywords GENERATE ALWAYS can be converted into identifiers
** by the parser, we can sometimes end up with a typename that ends
** with "generated always". Check for this case and omit the surplus
** text. */
@@ -119141,7 +122396,8 @@ SQLITE_PRIVATE char sqlite3AffinityType(const char *zIn, Column *pCol){
assert( zIn!=0 );
while( zIn[0] ){
- h = (h<<8) + sqlite3UpperToLower[(*zIn)&0xff];
+ u8 x = *(u8*)zIn;
+ h = (h<<8) + sqlite3UpperToLower[x];
zIn++;
if( h==(('c'<<24)+('h'<<16)+('a'<<8)+'r') ){ /* CHAR */
aff = SQLITE_AFF_TEXT;
@@ -119215,7 +122471,7 @@ SQLITE_PRIVATE void sqlite3AddDefaultValue(
Parse *pParse, /* Parsing context */
Expr *pExpr, /* The parsed expression of the default value */
const char *zStart, /* Start of the default value text */
- const char *zEnd /* First character past end of defaut value text */
+ const char *zEnd /* First character past end of default value text */
){
Table *p;
Column *pCol;
@@ -119563,7 +122819,7 @@ static int identLength(const char *z){
** to the specified offset in the buffer and updates *pIdx to refer
** to the first byte after the last byte written before returning.
**
-** If the string zSignedIdent consists entirely of alpha-numeric
+** If the string zSignedIdent consists entirely of alphanumeric
** characters, does not begin with a digit and is not an SQL keyword,
** then it is copied to the output buffer exactly as it is. Otherwise,
** it is quoted using double-quotes.
@@ -119715,7 +122971,7 @@ static void estimateIndexWidth(Index *pIdx){
for(i=0; i<pIdx->nColumn; i++){
i16 x = pIdx->aiColumn[i];
assert( x<pIdx->pTable->nCol );
- wIndex += x<0 ? 1 : aCol[pIdx->aiColumn[i]].szEst;
+ wIndex += x<0 ? 1 : aCol[x].szEst;
}
pIdx->szIdxRow = sqlite3LogEst(wIndex*4);
}
@@ -120404,6 +123660,17 @@ SQLITE_PRIVATE void sqlite3EndTable(
/* Reparse everything to update our internal data structures */
sqlite3VdbeAddParseSchemaOp(v, iDb,
sqlite3MPrintf(db, "tbl_name='%q' AND type!='trigger'", p->zName),0);
+
+ /* Test for cycles in generated columns and illegal expressions
+ ** in CHECK constraints and in DEFAULT clauses. */
+ if( p->tabFlags & TF_HasGenerated ){
+ sqlite3VdbeAddOp4(v, OP_SqlExec, 1, 0, 0,
+ sqlite3MPrintf(db, "SELECT*FROM\"%w\".\"%w\"",
+ db->aDb[iDb].zDbSName, p->zName), P4_DYNAMIC);
+ }
+ sqlite3VdbeAddOp4(v, OP_SqlExec, 1, 0, 0,
+ sqlite3MPrintf(db, "PRAGMA \"%w\".integrity_check(%Q)",
+ db->aDb[iDb].zDbSName, p->zName), P4_DYNAMIC);
}
/* Add the table to the in-memory representation of the database.
@@ -120480,9 +123747,12 @@ SQLITE_PRIVATE void sqlite3CreateView(
** on a view, even though views do not have rowids. The following flag
** setting fixes this problem. But the fix can be disabled by compiling
** with -DSQLITE_ALLOW_ROWID_IN_VIEW in case there are legacy apps that
- ** depend upon the old buggy behavior. */
-#ifndef SQLITE_ALLOW_ROWID_IN_VIEW
- p->tabFlags |= TF_NoVisibleRowid;
+ ** depend upon the old buggy behavior. The ability can also be toggled
+ ** using sqlite3_config(SQLITE_CONFIG_ROWID_IN_VIEW,...) */
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ p->tabFlags |= sqlite3Config.mNoVisibleRowid; /* Optional. Allow by default */
+#else
+ p->tabFlags |= TF_NoVisibleRowid; /* Never allow rowid in view */
#endif
sqlite3TwoPartName(pParse, pName1, pName2, &pName);
@@ -121453,7 +124723,7 @@ SQLITE_PRIVATE void sqlite3CreateIndex(
#ifndef SQLITE_OMIT_TEMPDB
/* If the index name was unqualified, check if the table
** is a temp table. If so, set the database to 1. Do not do this
- ** if initialising a database schema.
+ ** if initializing a database schema.
*/
if( !db->init.busy ){
pTab = sqlite3SrcListLookup(pParse, pTblName);
@@ -122995,7 +126265,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].zDbSName;
+ zDb = pName2->n ? db->aDb[iDb].zDbSName : 0;
pTab = sqlite3FindTable(db, z, zDb);
if( pTab ){
reindexTable(pParse, pTab, 0);
@@ -123005,6 +126275,7 @@ SQLITE_PRIVATE void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
pIndex = sqlite3FindIndex(db, z, zDb);
sqlite3DbFree(db, z);
if( pIndex ){
+ iDb = sqlite3SchemaToIndex(db, pIndex->pTable->pSchema);
sqlite3BeginWriteOperation(pParse, 0, iDb);
sqlite3RefillIndex(pParse, pIndex, -1);
return;
@@ -123110,7 +126381,7 @@ SQLITE_PRIVATE void sqlite3CteDelete(sqlite3 *db, Cte *pCte){
/*
** This routine is invoked once per CTE by the parser while parsing a
-** WITH clause. The CTE described by teh third argument is added to
+** WITH clause. The CTE described by the third argument is added to
** the WITH clause of the second argument. If the second argument is
** NULL, then a new WITH argument is created.
*/
@@ -123170,6 +126441,9 @@ SQLITE_PRIVATE void sqlite3WithDelete(sqlite3 *db, With *pWith){
sqlite3DbFree(db, pWith);
}
}
+SQLITE_PRIVATE void sqlite3WithDeleteGeneric(sqlite3 *db, void *pWith){
+ sqlite3WithDelete(db, (With*)pWith);
+}
#endif /* !defined(SQLITE_OMIT_CTE) */
/************** End of build.c ***********************************************/
@@ -123361,6 +126635,7 @@ SQLITE_PRIVATE void sqlite3SetTextEncoding(sqlite3 *db, u8 enc){
** strings is BINARY.
*/
db->pDfltColl = sqlite3FindCollSeq(db, enc, sqlite3StrBINARY, 0);
+ sqlite3ExpirePreparedStatements(db, 1);
}
/*
@@ -123751,8 +127026,9 @@ SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
Table *pTab;
assert( pItem && pSrc->nSrc>=1 );
pTab = sqlite3LocateTableItem(pParse, 0, pItem);
- sqlite3DeleteTable(pParse->db, pItem->pTab);
+ if( pItem->pTab ) sqlite3DeleteTable(pParse->db, pItem->pTab);
pItem->pTab = pTab;
+ pItem->fg.notCte = 1;
if( pTab ){
pTab->nTabRef++;
if( pItem->fg.isIndexedBy && sqlite3IndexedByLookup(pParse, pItem) ){
@@ -123832,13 +127108,15 @@ static int tabIsReadOnly(Parse *pParse, Table *pTab){
** If pTab is writable but other errors have occurred -> return 1.
** If pTab is writable and no prior errors -> return 0;
*/
-SQLITE_PRIVATE int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
+SQLITE_PRIVATE int sqlite3IsReadOnly(Parse *pParse, Table *pTab, Trigger *pTrigger){
if( tabIsReadOnly(pParse, pTab) ){
sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
return 1;
}
#ifndef SQLITE_OMIT_VIEW
- if( !viewOk && IsView(pTab) ){
+ if( IsView(pTab)
+ && (pTrigger==0 || (pTrigger->bReturning && pTrigger->pNext==0))
+ ){
sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
return 1;
}
@@ -123903,7 +127181,7 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
sqlite3 *db = pParse->db;
Expr *pLhs = NULL; /* LHS of IN(SELECT...) operator */
Expr *pInClause = NULL; /* WHERE rowid IN ( select ) */
- ExprList *pEList = NULL; /* Expression list contaning only pSelectRowid */
+ ExprList *pEList = NULL; /* Expression list containing only pSelectRowid*/
SrcList *pSelectSrc = NULL; /* SELECT rowid FROM x ... (dup of pSrc) */
Select *pSelect = NULL; /* Complete SELECT tree */
Table *pTab;
@@ -123941,14 +127219,20 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
);
}else{
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
+ assert( pPk!=0 );
+ assert( pPk->nKeyCol>=1 );
if( pPk->nKeyCol==1 ){
- const char *zName = pTab->aCol[pPk->aiColumn[0]].zCnName;
+ const char *zName;
+ assert( pPk->aiColumn[0]>=0 && pPk->aiColumn[0]<pTab->nCol );
+ zName = pTab->aCol[pPk->aiColumn[0]].zCnName;
pLhs = sqlite3Expr(db, TK_ID, zName);
pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ID, zName));
}else{
int i;
for(i=0; i<pPk->nKeyCol; i++){
- Expr *p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zCnName);
+ Expr *p;
+ assert( pPk->aiColumn[i]>=0 && pPk->aiColumn[i]<pTab->nCol );
+ p = sqlite3Expr(db, TK_ID, pTab->aCol[pPk->aiColumn[i]].zCnName);
pEList = sqlite3ExprListAppend(pParse, pEList, p);
}
pLhs = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
@@ -123977,7 +127261,7 @@ SQLITE_PRIVATE Expr *sqlite3LimitWhere(
pOrderBy,0,pLimit
);
- /* now generate the new WHERE rowid IN clause for the DELETE/UDPATE */
+ /* now generate the new WHERE rowid IN clause for the DELETE/UPDATE */
pInClause = sqlite3PExpr(pParse, TK_IN, pLhs, 0);
sqlite3PExprAddSelect(pParse, pInClause, pSelect);
return pInClause;
@@ -124092,7 +127376,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
goto delete_from_cleanup;
}
- if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){
+ if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){
goto delete_from_cleanup;
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -124201,12 +127485,12 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
#endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
{
u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK;
- if( sNC.ncFlags & NC_VarSelect ) bComplex = 1;
+ if( sNC.ncFlags & NC_Subquery ) bComplex = 1;
wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW);
if( HasRowid(pTab) ){
/* For a rowid table, initialize the RowSet to an empty set */
pPk = 0;
- nPk = 1;
+ assert( nPk==1 );
iRowSet = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
}else{
@@ -124234,7 +127518,8 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
if( pWInfo==0 ) goto delete_from_cleanup;
eOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
assert( IsVirtual(pTab)==0 || eOnePass!=ONEPASS_MULTI );
- assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF );
+ assert( IsVirtual(pTab) || bComplex || eOnePass!=ONEPASS_OFF
+ || OptimizationDisabled(db, SQLITE_OnePass) );
if( eOnePass!=ONEPASS_SINGLE ) sqlite3MultiWrite(pParse);
if( sqlite3WhereUsesDeferredSeek(pWInfo) ){
sqlite3VdbeAddOp1(v, OP_FinishSeek, iTabCur);
@@ -124571,9 +127856,11 @@ SQLITE_PRIVATE void sqlite3GenerateRowDelete(
sqlite3FkActions(pParse, pTab, 0, iOld, 0, 0);
/* Invoke AFTER DELETE trigger programs. */
- sqlite3CodeRowTrigger(pParse, pTrigger,
- TK_DELETE, 0, TRIGGER_AFTER, pTab, iOld, onconf, iLabel
- );
+ if( pTrigger ){
+ sqlite3CodeRowTrigger(pParse, pTrigger,
+ TK_DELETE, 0, TRIGGER_AFTER, pTab, iOld, onconf, iLabel
+ );
+ }
/* Jump here if the row had already been deleted before any BEFORE
** trigger programs were invoked. Or if a trigger program throws a
@@ -124887,6 +128174,42 @@ static void lengthFunc(
}
/*
+** Implementation of the octet_length() function
+*/
+static void bytelengthFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ assert( argc==1 );
+ UNUSED_PARAMETER(argc);
+ switch( sqlite3_value_type(argv[0]) ){
+ case SQLITE_BLOB: {
+ sqlite3_result_int(context, sqlite3_value_bytes(argv[0]));
+ break;
+ }
+ case SQLITE_INTEGER:
+ case SQLITE_FLOAT: {
+ i64 m = sqlite3_context_db_handle(context)->enc<=SQLITE_UTF8 ? 1 : 2;
+ sqlite3_result_int64(context, sqlite3_value_bytes(argv[0])*m);
+ break;
+ }
+ case SQLITE_TEXT: {
+ if( sqlite3_value_encoding(argv[0])<=SQLITE_UTF8 ){
+ sqlite3_result_int(context, sqlite3_value_bytes(argv[0]));
+ }else{
+ sqlite3_result_int(context, sqlite3_value_bytes16(argv[0]));
+ }
+ break;
+ }
+ default: {
+ sqlite3_result_null(context);
+ break;
+ }
+ }
+}
+
+/*
** Implementation of the abs() function.
**
** IMP: R-23979-26855 The abs(X) function returns the absolute value of
@@ -125162,7 +128485,7 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
}else if( n==0 ){
r = (double)((sqlite_int64)(r+(r<0?-0.5:+0.5)));
}else{
- zBuf = sqlite3_mprintf("%.*f",n,r);
+ zBuf = sqlite3_mprintf("%!.*f",n,r);
if( zBuf==0 ){
sqlite3_result_error_nomem(context);
return;
@@ -125362,7 +128685,7 @@ struct compareInfo {
/*
** For LIKE and GLOB matching on EBCDIC machines, assume that every
-** character is exactly one byte in size. Also, provde the Utf8Read()
+** character is exactly one byte in size. Also, provide the Utf8Read()
** macro for fast reading of the next character in the common case where
** the next character is ASCII.
*/
@@ -125595,7 +128918,7 @@ SQLITE_API int sqlite3_like_count = 0;
/*
** Implementation of the like() SQL function. This function implements
-** the build-in LIKE operator. The first argument to the function is the
+** the built-in LIKE operator. The first argument to the function is the
** pattern and the second argument is the string. So, the SQL statements:
**
** A LIKE B
@@ -125802,13 +129125,13 @@ SQLITE_PRIVATE void sqlite3QuoteValue(StrAccum *pStr, sqlite3_value *pValue){
double r1, r2;
const char *zVal;
r1 = sqlite3_value_double(pValue);
- sqlite3_str_appendf(pStr, "%!.15g", r1);
+ sqlite3_str_appendf(pStr, "%!0.15g", r1);
zVal = sqlite3_str_value(pStr);
if( zVal ){
sqlite3AtoF(zVal, &r2, pStr->nChar, SQLITE_UTF8);
if( r1!=r2 ){
sqlite3_str_reset(pStr);
- sqlite3_str_appendf(pStr, "%!.20e", r1);
+ sqlite3_str_appendf(pStr, "%!0.20e", r1);
}
}
break;
@@ -125928,6 +129251,7 @@ static void charFunc(
*zOut++ = 0x80 + (u8)(c & 0x3F);
} \
}
+ *zOut = 0;
sqlite3_result_text64(context, (char*)z, zOut-z, sqlite3_free, SQLITE_UTF8);
}
@@ -125956,7 +129280,8 @@ static void hexFunc(
*(z++) = hexdigits[c&0xf];
}
*z = 0;
- sqlite3_result_text(context, zHex, n*2, sqlite3_free);
+ sqlite3_result_text64(context, zHex, (u64)(z-zHex),
+ sqlite3_free, SQLITE_UTF8);
}
}
@@ -125981,7 +129306,7 @@ static int strContainsChar(const u8 *zStr, int nStr, u32 ch){
** decoded and returned as a blob.
**
** If there is only a single argument, then it must consist only of an
-** even number of hexadeximal digits. Otherwise, return NULL.
+** even number of hexadecimal digits. Otherwise, return NULL.
**
** Or, if there is a second argument, then any character that appears in
** the second argument is also allowed to appear between pairs of hexadecimal
@@ -126108,7 +129433,7 @@ static void replaceFunc(
}
if( zPattern[0]==0 ){
assert( sqlite3_value_type(argv[1])!=SQLITE_NULL );
- sqlite3_result_value(context, argv[0]);
+ sqlite3_result_text(context, (const char*)zStr, nStr, SQLITE_TRANSIENT);
return;
}
nPattern = sqlite3_value_bytes(argv[1]);
@@ -126250,12 +129575,87 @@ static void trimFunc(
sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT);
}
+/* The core implementation of the CONCAT(...) and CONCAT_WS(SEP,...)
+** functions.
+**
+** Return a string value that is the concatenation of all non-null
+** entries in argv[]. Use zSep as the separator.
+*/
+static void concatFuncCore(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv,
+ int nSep,
+ const char *zSep
+){
+ i64 j, k, n = 0;
+ int i;
+ char *z;
+ for(i=0; i<argc; i++){
+ n += sqlite3_value_bytes(argv[i]);
+ }
+ n += (argc-1)*nSep;
+ z = sqlite3_malloc64(n+1);
+ if( z==0 ){
+ sqlite3_result_error_nomem(context);
+ return;
+ }
+ j = 0;
+ for(i=0; i<argc; i++){
+ k = sqlite3_value_bytes(argv[i]);
+ if( k>0 ){
+ const char *v = (const char*)sqlite3_value_text(argv[i]);
+ if( v!=0 ){
+ if( j>0 && nSep>0 ){
+ memcpy(&z[j], zSep, nSep);
+ j += nSep;
+ }
+ memcpy(&z[j], v, k);
+ j += k;
+ }
+ }
+ }
+ z[j] = 0;
+ assert( j<=n );
+ sqlite3_result_text64(context, z, j, sqlite3_free, SQLITE_UTF8);
+}
+
+/*
+** The CONCAT(...) function. Generate a string result that is the
+** concatentation of all non-null arguments.
+*/
+static void concatFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ concatFuncCore(context, argc, argv, 0, "");
+}
+
+/*
+** The CONCAT_WS(separator, ...) function.
+**
+** Generate a string that is the concatenation of 2nd through the Nth
+** argument. Use the first argument (which must be non-NULL) as the
+** separator.
+*/
+static void concatwsFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ int nSep = sqlite3_value_bytes(argv[0]);
+ const char *zSep = (const char*)sqlite3_value_text(argv[0]);
+ if( zSep==0 ) return;
+ concatFuncCore(context, argc-1, argv+1, nSep, zSep);
+}
+
#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 SQLITE_ENABLE_UNKNOWN_SQL_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
@@ -126371,14 +129771,69 @@ static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){
*/
typedef struct SumCtx SumCtx;
struct SumCtx {
- double rSum; /* Floating point sum */
- i64 iSum; /* Integer sum */
+ double rSum; /* Running sum as as a double */
+ double rErr; /* Error term for Kahan-Babushka-Neumaier summation */
+ i64 iSum; /* Running sum as a signed integer */
i64 cnt; /* Number of elements summed */
- u8 overflow; /* True if integer overflow seen */
- u8 approx; /* True if non-integer value was input to the sum */
+ u8 approx; /* True if any non-integer value was input to the sum */
+ u8 ovrfl; /* Integer overflow seen */
};
/*
+** Do one step of the Kahan-Babushka-Neumaier summation.
+**
+** https://en.wikipedia.org/wiki/Kahan_summation_algorithm
+**
+** Variables are marked "volatile" to defeat c89 x86 floating point
+** optimizations can mess up this algorithm.
+*/
+static void kahanBabuskaNeumaierStep(
+ volatile SumCtx *pSum,
+ volatile double r
+){
+ volatile double s = pSum->rSum;
+ volatile double t = s + r;
+ if( fabs(s) > fabs(r) ){
+ pSum->rErr += (s - t) + r;
+ }else{
+ pSum->rErr += (r - t) + s;
+ }
+ pSum->rSum = t;
+}
+
+/*
+** Add a (possibly large) integer to the running sum.
+*/
+static void kahanBabuskaNeumaierStepInt64(volatile SumCtx *pSum, i64 iVal){
+ if( iVal<=-4503599627370496LL || iVal>=+4503599627370496LL ){
+ i64 iBig, iSm;
+ iSm = iVal % 16384;
+ iBig = iVal - iSm;
+ kahanBabuskaNeumaierStep(pSum, iBig);
+ kahanBabuskaNeumaierStep(pSum, iSm);
+ }else{
+ kahanBabuskaNeumaierStep(pSum, (double)iVal);
+ }
+}
+
+/*
+** Initialize the Kahan-Babaska-Neumaier sum from a 64-bit integer
+*/
+static void kahanBabuskaNeumaierInit(
+ volatile SumCtx *p,
+ i64 iVal
+){
+ if( iVal<=-4503599627370496LL || iVal>=+4503599627370496LL ){
+ i64 iSm = iVal % 16384;
+ p->rSum = (double)(iVal - iSm);
+ p->rErr = (double)iSm;
+ }else{
+ p->rSum = (double)iVal;
+ p->rErr = 0.0;
+ }
+}
+
+/*
** Routines used to compute the sum, average, and total.
**
** The SUM() function follows the (broken) SQL standard which means
@@ -126397,15 +129852,29 @@ static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
type = sqlite3_value_numeric_type(argv[0]);
if( p && type!=SQLITE_NULL ){
p->cnt++;
- if( type==SQLITE_INTEGER ){
- i64 v = sqlite3_value_int64(argv[0]);
- p->rSum += v;
- if( (p->approx|p->overflow)==0 && sqlite3AddInt64(&p->iSum, v) ){
- p->approx = p->overflow = 1;
+ if( p->approx==0 ){
+ if( type!=SQLITE_INTEGER ){
+ kahanBabuskaNeumaierInit(p, p->iSum);
+ p->approx = 1;
+ kahanBabuskaNeumaierStep(p, sqlite3_value_double(argv[0]));
+ }else{
+ i64 x = p->iSum;
+ if( sqlite3AddInt64(&x, sqlite3_value_int64(argv[0]))==0 ){
+ p->iSum = x;
+ }else{
+ p->ovrfl = 1;
+ kahanBabuskaNeumaierInit(p, p->iSum);
+ p->approx = 1;
+ kahanBabuskaNeumaierStepInt64(p, sqlite3_value_int64(argv[0]));
+ }
}
}else{
- p->rSum += sqlite3_value_double(argv[0]);
- p->approx = 1;
+ if( type==SQLITE_INTEGER ){
+ kahanBabuskaNeumaierStepInt64(p, sqlite3_value_int64(argv[0]));
+ }else{
+ p->ovrfl = 0;
+ kahanBabuskaNeumaierStep(p, sqlite3_value_double(argv[0]));
+ }
}
}
}
@@ -126422,13 +129891,18 @@ static void sumInverse(sqlite3_context *context, int argc, sqlite3_value**argv){
if( ALWAYS(p) && type!=SQLITE_NULL ){
assert( p->cnt>0 );
p->cnt--;
- assert( type==SQLITE_INTEGER || p->approx );
- if( type==SQLITE_INTEGER && p->approx==0 ){
- i64 v = sqlite3_value_int64(argv[0]);
- p->rSum -= v;
- p->iSum -= v;
+ if( !p->approx ){
+ p->iSum -= sqlite3_value_int64(argv[0]);
+ }else if( type==SQLITE_INTEGER ){
+ i64 iVal = sqlite3_value_int64(argv[0]);
+ if( iVal!=SMALLEST_INT64 ){
+ kahanBabuskaNeumaierStepInt64(p, -iVal);
+ }else{
+ kahanBabuskaNeumaierStepInt64(p, LARGEST_INT64);
+ kahanBabuskaNeumaierStepInt64(p, 1);
+ }
}else{
- p->rSum -= sqlite3_value_double(argv[0]);
+ kahanBabuskaNeumaierStep(p, -sqlite3_value_double(argv[0]));
}
}
}
@@ -126439,10 +129913,14 @@ static void sumFinalize(sqlite3_context *context){
SumCtx *p;
p = sqlite3_aggregate_context(context, 0);
if( p && p->cnt>0 ){
- if( p->overflow ){
- sqlite3_result_error(context,"integer overflow",-1);
- }else if( p->approx ){
- sqlite3_result_double(context, p->rSum);
+ if( p->approx ){
+ if( p->ovrfl ){
+ sqlite3_result_error(context,"integer overflow",-1);
+ }else if( !sqlite3IsOverflow(p->rErr) ){
+ sqlite3_result_double(context, p->rSum+p->rErr);
+ }else{
+ sqlite3_result_double(context, p->rSum);
+ }
}else{
sqlite3_result_int64(context, p->iSum);
}
@@ -126452,14 +129930,29 @@ static void avgFinalize(sqlite3_context *context){
SumCtx *p;
p = sqlite3_aggregate_context(context, 0);
if( p && p->cnt>0 ){
- sqlite3_result_double(context, p->rSum/(double)p->cnt);
+ double r;
+ if( p->approx ){
+ r = p->rSum;
+ if( !sqlite3IsOverflow(p->rErr) ) r += p->rErr;
+ }else{
+ r = (double)(p->iSum);
+ }
+ sqlite3_result_double(context, r/(double)p->cnt);
}
}
static void totalFinalize(sqlite3_context *context){
SumCtx *p;
+ double r = 0.0;
p = sqlite3_aggregate_context(context, 0);
- /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
- sqlite3_result_double(context, p ? p->rSum : (double)0);
+ if( p ){
+ if( p->approx ){
+ r = p->rSum;
+ if( !sqlite3IsOverflow(p->rErr) ) r += p->rErr;
+ }else{
+ r = (double)(p->iSum);
+ }
+ }
+ sqlite3_result_double(context, r);
}
/*
@@ -126578,6 +130071,7 @@ static void minMaxFinalize(sqlite3_context *context){
/*
** group_concat(EXPR, ?SEPARATOR?)
+** string_agg(EXPR, SEPARATOR)
**
** The SEPARATOR goes before the EXPR string. This is tragic. The
** groupConcatInverse() implementation would have been easier if the
@@ -126681,7 +130175,7 @@ static void groupConcatInverse(
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
pGCC = (GroupConcatCtx*)sqlite3_aggregate_context(context, sizeof(*pGCC));
/* pGCC is always non-NULL since groupConcatStep() will have always
- ** run frist to initialize it */
+ ** run first to initialize it */
if( ALWAYS(pGCC) ){
int nVS;
/* Must call sqlite3_value_text() to convert the argument into text prior
@@ -126765,8 +130259,10 @@ SQLITE_PRIVATE void sqlite3RegisterPerConnectionBuiltinFunctions(sqlite3 *db){
** sensitive.
*/
SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
+ FuncDef *pDef;
struct compareInfo *pInfo;
int flags;
+ int nArg;
if( caseSensitive ){
pInfo = (struct compareInfo*)&likeInfoAlt;
flags = SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE;
@@ -126774,10 +130270,13 @@ SQLITE_PRIVATE void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive)
pInfo = (struct compareInfo*)&likeInfoNorm;
flags = SQLITE_FUNC_LIKE;
}
- sqlite3CreateFunc(db, "like", 2, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0);
- sqlite3CreateFunc(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0, 0, 0, 0);
- sqlite3FindFunction(db, "like", 2, SQLITE_UTF8, 0)->funcFlags |= flags;
- sqlite3FindFunction(db, "like", 3, SQLITE_UTF8, 0)->funcFlags |= flags;
+ for(nArg=2; nArg<=3; nArg++){
+ sqlite3CreateFunc(db, "like", nArg, SQLITE_UTF8, pInfo, likeFunc,
+ 0, 0, 0, 0, 0);
+ pDef = sqlite3FindFunction(db, "like", nArg, SQLITE_UTF8, 0);
+ pDef->funcFlags |= flags;
+ pDef->funcFlags &= ~SQLITE_FUNC_UNSAFE;
+ }
}
/*
@@ -127049,6 +130548,37 @@ static void signFunc(
sqlite3_result_int(context, x<0.0 ? -1 : x>0.0 ? +1 : 0);
}
+#ifdef SQLITE_DEBUG
+/*
+** Implementation of fpdecode(x,y,z) function.
+**
+** x is a real number that is to be decoded. y is the precision.
+** z is the maximum real precision.
+*/
+static void fpdecodeFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ FpDecode s;
+ double x;
+ int y, z;
+ char zBuf[100];
+ UNUSED_PARAMETER(argc);
+ assert( argc==3 );
+ x = sqlite3_value_double(argv[0]);
+ y = sqlite3_value_int(argv[1]);
+ z = sqlite3_value_int(argv[2]);
+ sqlite3FpDecode(&s, x, y, z);
+ if( s.isSpecial==2 ){
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "NaN");
+ }else{
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%c%.*s/%d", s.sign, s.n, s.z, s.iDP);
+ }
+ sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
+}
+#endif /* SQLITE_DEBUG */
+
/*
** All of the FuncDef structures in the aBuiltinFunc[] array above
** to the global function hash table. This occurs at start-time (as
@@ -127113,12 +130643,16 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
FUNCTION2(typeof, 1, 0, 0, typeofFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(subtype, 1, 0, 0, subtypeFunc, SQLITE_FUNC_TYPEOF),
FUNCTION2(length, 1, 0, 0, lengthFunc, SQLITE_FUNC_LENGTH),
+ FUNCTION2(octet_length, 1, 0, 0, bytelengthFunc,SQLITE_FUNC_BYTELEN),
FUNCTION(instr, 2, 0, 0, instrFunc ),
FUNCTION(printf, -1, 0, 0, printfFunc ),
FUNCTION(format, -1, 0, 0, printfFunc ),
FUNCTION(unicode, 1, 0, 0, unicodeFunc ),
FUNCTION(char, -1, 0, 0, charFunc ),
FUNCTION(abs, 1, 0, 0, absFunc ),
+#ifdef SQLITE_DEBUG
+ FUNCTION(fpdecode, 3, 0, 0, fpdecodeFunc ),
+#endif
#ifndef SQLITE_OMIT_FLOATING_POINT
FUNCTION(round, 1, 0, 0, roundFunc ),
FUNCTION(round, 2, 0, 0, roundFunc ),
@@ -127128,6 +130662,11 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
FUNCTION(hex, 1, 0, 0, hexFunc ),
FUNCTION(unhex, 1, 0, 0, unhexFunc ),
FUNCTION(unhex, 2, 0, 0, unhexFunc ),
+ FUNCTION(concat, -1, 0, 0, concatFunc ),
+ FUNCTION(concat, 0, 0, 0, 0 ),
+ FUNCTION(concat_ws, -1, 0, 0, concatwsFunc ),
+ FUNCTION(concat_ws, 0, 0, 0, 0 ),
+ FUNCTION(concat_ws, 1, 0, 0, 0 ),
INLINE_FUNC(ifnull, 2, INLINEFUNC_coalesce, 0 ),
VFUNCTION(random, 0, 0, 0, randomFunc ),
VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
@@ -127157,6 +130696,8 @@ SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(void){
groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
WAGGREGATE(group_concat, 2, 0, 0, groupConcatStep,
groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
+ WAGGREGATE(string_agg, 2, 0, 0, groupConcatStep,
+ groupConcatFinalize, groupConcatValue, groupConcatInverse, 0),
LIKEFUNC(glob, 2, &globInfo, SQLITE_FUNC_LIKE|SQLITE_FUNC_CASE),
#ifdef SQLITE_CASE_SENSITIVE_LIKE
@@ -128099,6 +131640,7 @@ static int isSetNullAction(Parse *pParse, FKey *pFKey){
if( (p==pFKey->apTrigger[0] && pFKey->aAction[0]==OE_SetNull)
|| (p==pFKey->apTrigger[1] && pFKey->aAction[1]==OE_SetNull)
){
+ assert( (pTop->db->flags & SQLITE_FkNoAction)==0 );
return 1;
}
}
@@ -128293,6 +131835,8 @@ SQLITE_PRIVATE void sqlite3FkCheck(
}
if( regOld!=0 ){
int eAction = pFKey->aAction[aChange!=0];
+ if( (db->flags & SQLITE_FkNoAction) ) eAction = OE_None;
+
fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regOld, 1);
/* If this is a deferred FK constraint, or a CASCADE or SET NULL
** action applies, then any foreign key violations caused by
@@ -128408,7 +131952,11 @@ SQLITE_PRIVATE int sqlite3FkRequired(
/* Check if any parent key columns are being modified. */
for(p=sqlite3FkReferences(pTab); p; p=p->pNextTo){
if( fkParentIsModified(pTab, p, aChange, chngRowid) ){
- if( p->aAction[1]!=OE_None ) return 2;
+ if( (pParse->db->flags & SQLITE_FkNoAction)==0
+ && p->aAction[1]!=OE_None
+ ){
+ return 2;
+ }
bHaveFK = 1;
}
}
@@ -128458,6 +132006,7 @@ static Trigger *fkActionTrigger(
int iAction = (pChanges!=0); /* 1 for UPDATE, 0 for DELETE */
action = pFKey->aAction[iAction];
+ if( (db->flags & SQLITE_FkNoAction) ) action = OE_None;
if( action==OE_Restrict && (db->flags & SQLITE_DeferFKs) ){
return 0;
}
@@ -128558,22 +132107,22 @@ static Trigger *fkActionTrigger(
if( action==OE_Restrict ){
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
- Token tFrom;
- Token tDb;
+ SrcList *pSrc;
Expr *pRaise;
- tFrom.z = zFrom;
- tFrom.n = nFrom;
- tDb.z = db->aDb[iDb].zDbSName;
- tDb.n = sqlite3Strlen30(tDb.z);
-
pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed");
if( pRaise ){
pRaise->affExpr = OE_Abort;
}
+ pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
+ if( pSrc ){
+ assert( pSrc->nSrc==1 );
+ pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom);
+ pSrc->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
+ }
pSelect = sqlite3SelectNew(pParse,
sqlite3ExprListAppend(pParse, 0, pRaise),
- sqlite3SrcListAppend(pParse, 0, &tDb, &tFrom),
+ pSrc,
pWhere,
0, 0, 0, 0, 0
);
@@ -128689,9 +132238,8 @@ SQLITE_PRIVATE void sqlite3FkDelete(sqlite3 *db, Table *pTab){
if( pFKey->pPrevTo ){
pFKey->pPrevTo->pNextTo = pFKey->pNextTo;
}else{
- void *p = (void *)pFKey->pNextTo;
- const char *z = (p ? pFKey->pNextTo->zTo : pFKey->zTo);
- sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, p);
+ const char *z = (pFKey->pNextTo ? pFKey->pNextTo->zTo : pFKey->zTo);
+ sqlite3HashInsert(&pTab->pSchema->fkeyHash, z, pFKey->pNextTo);
}
if( pFKey->pNextTo ){
pFKey->pNextTo->pPrevTo = pFKey->pPrevTo;
@@ -128754,8 +132302,10 @@ SQLITE_PRIVATE void sqlite3OpenTable(
assert( pParse->pVdbe!=0 );
v = pParse->pVdbe;
assert( opcode==OP_OpenWrite || opcode==OP_OpenRead );
- sqlite3TableLock(pParse, iDb, pTab->tnum,
- (opcode==OP_OpenWrite)?1:0, pTab->zName);
+ if( !pParse->db->noSharedCache ){
+ sqlite3TableLock(pParse, iDb, pTab->tnum,
+ (opcode==OP_OpenWrite)?1:0, pTab->zName);
+ }
if( HasRowid(pTab) ){
sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nNVCol);
VdbeComment((v, "%s", pTab->zName));
@@ -128789,46 +132339,48 @@ SQLITE_PRIVATE void sqlite3OpenTable(
** is managed along with the rest of the Index structure. It will be
** released when sqlite3DeleteIndex() is called.
*/
-SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
+static SQLITE_NOINLINE const char *computeIndexAffStr(sqlite3 *db, Index *pIdx){
+ /* The first time a column affinity string for a particular index is
+ ** required, it is allocated and populated here. It is then stored as
+ ** a member of the Index structure for subsequent use.
+ **
+ ** The column affinity string will eventually be deleted by
+ ** sqliteDeleteIndex() when the Index structure itself is cleaned
+ ** up.
+ */
+ int n;
+ Table *pTab = pIdx->pTable;
+ pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+1);
if( !pIdx->zColAff ){
- /* The first time a column affinity string for a particular index is
- ** required, it is allocated and populated here. It is then stored as
- ** a member of the Index structure for subsequent use.
- **
- ** The column affinity string will eventually be deleted by
- ** sqliteDeleteIndex() when the Index structure itself is cleaned
- ** up.
- */
- int n;
- Table *pTab = pIdx->pTable;
- pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+1);
- if( !pIdx->zColAff ){
- sqlite3OomFault(db);
- return 0;
- }
- for(n=0; n<pIdx->nColumn; n++){
- i16 x = pIdx->aiColumn[n];
- char aff;
- if( x>=0 ){
- aff = pTab->aCol[x].affinity;
- }else if( x==XN_ROWID ){
- aff = SQLITE_AFF_INTEGER;
- }else{
- assert( x==XN_EXPR );
- assert( pIdx->bHasExpr );
- assert( pIdx->aColExpr!=0 );
- aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
- }
- if( aff<SQLITE_AFF_BLOB ) aff = SQLITE_AFF_BLOB;
- if( aff>SQLITE_AFF_NUMERIC) aff = SQLITE_AFF_NUMERIC;
- pIdx->zColAff[n] = aff;
+ sqlite3OomFault(db);
+ return 0;
+ }
+ for(n=0; n<pIdx->nColumn; n++){
+ i16 x = pIdx->aiColumn[n];
+ char aff;
+ if( x>=0 ){
+ aff = pTab->aCol[x].affinity;
+ }else if( x==XN_ROWID ){
+ aff = SQLITE_AFF_INTEGER;
+ }else{
+ assert( x==XN_EXPR );
+ assert( pIdx->bHasExpr );
+ assert( pIdx->aColExpr!=0 );
+ aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
}
- pIdx->zColAff[n] = 0;
+ if( aff<SQLITE_AFF_BLOB ) aff = SQLITE_AFF_BLOB;
+ if( aff>SQLITE_AFF_NUMERIC) aff = SQLITE_AFF_NUMERIC;
+ pIdx->zColAff[n] = aff;
}
-
+ pIdx->zColAff[n] = 0;
+ return pIdx->zColAff;
+}
+SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
+ if( !pIdx->zColAff ) return computeIndexAffStr(db, pIdx);
return pIdx->zColAff;
}
+
/*
** Compute an affinity string for a table. Space is obtained
** from sqlite3DbMalloc(). The caller is responsible for freeing
@@ -128882,7 +132434,7 @@ SQLITE_PRIVATE char *sqlite3TableAffinityStr(sqlite3 *db, const Table *pTab){
** For STRICT tables:
** ------------------
**
-** Generate an appropropriate OP_TypeCheck opcode that will verify the
+** Generate an appropriate OP_TypeCheck opcode that will verify the
** datatypes against the column definitions in pTab. If iReg==0, that
** means an OP_MakeRecord opcode has already been generated and should be
** the last opcode generated. The new OP_TypeCheck needs to be inserted
@@ -129513,7 +133065,7 @@ SQLITE_PRIVATE void sqlite3Insert(
/* Cannot insert into a read-only table.
*/
- if( sqlite3IsReadOnly(pParse, pTab, tmask) ){
+ if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){
goto insert_cleanup;
}
@@ -129801,7 +133353,7 @@ SQLITE_PRIVATE void sqlite3Insert(
pNx->iDataCur = iDataCur;
pNx->iIdxCur = iIdxCur;
if( pNx->pUpsertTarget ){
- if( sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx) ){
+ if( sqlite3UpsertAnalyzeTarget(pParse, pTabList, pNx, pUpsert) ){
goto insert_cleanup;
}
}
@@ -129960,7 +133512,7 @@ SQLITE_PRIVATE void sqlite3Insert(
}
/* Copy the new data already generated. */
- assert( pTab->nNVCol>0 );
+ assert( pTab->nNVCol>0 || pParse->nErr>0 );
sqlite3VdbeAddOp3(v, OP_Copy, regRowid+1, regCols+1, pTab->nNVCol-1);
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
@@ -130174,7 +133726,7 @@ insert_cleanup:
/* This is the Walker callback from sqlite3ExprReferencesUpdatedColumn().
* Set bit 0x01 of pWalker->eCode if pWalker->eCode to 0 and if this
** expression node references any of the
-** columns that are being modifed by an UPDATE statement.
+** columns that are being modified by an UPDATE statement.
*/
static int checkConstraintExprNode(Walker *pWalker, Expr *pExpr){
if( pExpr->op==TK_COLUMN ){
@@ -130397,7 +133949,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
int *aiChng, /* column i is unchanged if aiChng[i]<0 */
Upsert *pUpsert /* ON CONFLICT clauses, if any. NULL otherwise */
){
- Vdbe *v; /* VDBE under constrution */
+ Vdbe *v; /* VDBE under construction */
Index *pIdx; /* Pointer to one of the indices */
Index *pPk = 0; /* The PRIMARY KEY index for WITHOUT ROWID tables */
sqlite3 *db; /* Database connection */
@@ -130880,7 +134432,7 @@ SQLITE_PRIVATE void sqlite3GenerateConstraintChecks(
pIdx;
pIdx = indexIteratorNext(&sIdxIter, &ix)
){
- int regIdx; /* Range of registers hold conent for pIdx */
+ int regIdx; /* Range of registers holding content for pIdx */
int regR; /* Range of registers holding conflicting PK */
int iThisCur; /* Cursor for this UNIQUE index */
int addrUniqueOk; /* Jump here if the UNIQUE constraint is satisfied */
@@ -131375,6 +134927,8 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices(
assert( op==OP_OpenRead || op==OP_OpenWrite );
assert( op==OP_OpenWrite || p5==0 );
+ assert( piDataCur!=0 );
+ assert( piIdxCur!=0 );
if( IsVirtual(pTab) ){
/* This routine is a no-op for virtual tables. Leave the output
** variables *piDataCur and *piIdxCur set to illegal cursor numbers
@@ -131387,18 +134941,18 @@ SQLITE_PRIVATE int sqlite3OpenTableAndIndices(
assert( v!=0 );
if( iBase<0 ) iBase = pParse->nTab;
iDataCur = iBase++;
- if( piDataCur ) *piDataCur = iDataCur;
+ *piDataCur = iDataCur;
if( HasRowid(pTab) && (aToOpen==0 || aToOpen[0]) ){
sqlite3OpenTable(pParse, iDataCur, iDb, pTab, op);
- }else{
+ }else if( pParse->db->noSharedCache==0 ){
sqlite3TableLock(pParse, iDb, pTab->tnum, op==OP_OpenWrite, pTab->zName);
}
- if( piIdxCur ) *piIdxCur = iBase;
+ *piIdxCur = iBase;
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;
+ *piDataCur = iIdxCur;
p5 = 0;
}
if( aToOpen==0 || aToOpen[i+1] ){
@@ -131691,12 +135245,15 @@ static int xferOptimization(
}
}
#ifndef SQLITE_OMIT_CHECK
- if( pDest->pCheck && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1) ){
+ if( pDest->pCheck
+ && (db->mDbFlags & DBFLAG_Vacuum)==0
+ && sqlite3ExprListCompare(pSrc->pCheck,pDest->pCheck,-1)
+ ){
return 0; /* Tables have different CHECK constraints. Ticket #2252 */
}
#endif
#ifndef SQLITE_OMIT_FOREIGN_KEY
- /* Disallow the transfer optimization if the destination table constains
+ /* Disallow the transfer optimization if the destination table contains
** any foreign key constraints. This is more restrictive than necessary.
** But the main beneficiary of the transfer optimization is the VACUUM
** command, and the VACUUM command disables foreign key constraints. So
@@ -132406,6 +135963,11 @@ struct sqlite3_api_routines {
int (*value_encoding)(sqlite3_value*);
/* Version 3.41.0 and later */
int (*is_interrupted)(sqlite3*);
+ /* Version 3.43.0 and later */
+ int (*stmt_explain)(sqlite3_stmt*,int);
+ /* Version 3.44.0 and later */
+ void *(*get_clientdata)(sqlite3*,const char*);
+ int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*));
};
/*
@@ -132734,6 +136296,11 @@ typedef int (*sqlite3_loadext_entry)(
#define sqlite3_value_encoding sqlite3_api->value_encoding
/* Version 3.41.0 and later */
#define sqlite3_is_interrupted sqlite3_api->is_interrupted
+/* Version 3.43.0 and later */
+#define sqlite3_stmt_explain sqlite3_api->stmt_explain
+/* Version 3.44.0 and later */
+#define sqlite3_get_clientdata sqlite3_api->get_clientdata
+#define sqlite3_set_clientdata sqlite3_api->set_clientdata
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
@@ -133250,7 +136817,12 @@ static const sqlite3_api_routines sqlite3Apis = {
/* Version 3.40.0 and later */
sqlite3_value_encoding,
/* Version 3.41.0 and later */
- sqlite3_is_interrupted
+ sqlite3_is_interrupted,
+ /* Version 3.43.0 and later */
+ sqlite3_stmt_explain,
+ /* Version 3.44.0 and later */
+ sqlite3_get_clientdata,
+ sqlite3_set_clientdata
};
/* True if x is the directory separator character
@@ -133323,15 +136895,25 @@ static int sqlite3LoadExtension(
/* tag-20210611-1. Some dlopen() implementations will segfault if given
** an oversize filename. Most filesystems have a pathname limit of 4K,
** so limit the extension filename length to about twice that.
- ** https://sqlite.org/forum/forumpost/08a0d6d9bf */
+ ** https://sqlite.org/forum/forumpost/08a0d6d9bf
+ **
+ ** Later (2023-03-25): Save an extra 6 bytes for the filename suffix.
+ ** See https://sqlite.org/forum/forumpost/24083b579d.
+ */
if( nMsg>SQLITE_MAX_PATHLEN ) goto extension_not_found;
+ /* Do not allow sqlite3_load_extension() to link to a copy of the
+ ** running application, by passing in an empty filename. */
+ if( nMsg==0 ) goto extension_not_found;
+
handle = sqlite3OsDlOpen(pVfs, zFile);
#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_BKPT;
- handle = sqlite3OsDlOpen(pVfs, zAltFile);
+ if( nMsg+strlen(azEndings[ii])+1<=SQLITE_MAX_PATHLEN ){
+ handle = sqlite3OsDlOpen(pVfs, zAltFile);
+ }
sqlite3_free(zAltFile);
}
#endif
@@ -133456,6 +137038,9 @@ SQLITE_PRIVATE void sqlite3CloseExtensions(sqlite3 *db){
** default so as not to open security holes in older applications.
*/
SQLITE_API int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
if( onoff ){
db->flags |= SQLITE_LoadExtension|SQLITE_LoadExtFunc;
@@ -133505,6 +137090,9 @@ SQLITE_API int sqlite3_auto_extension(
void (*xInit)(void)
){
int rc = SQLITE_OK;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( xInit==0 ) return SQLITE_MISUSE_BKPT;
+#endif
#ifndef SQLITE_OMIT_AUTOINIT
rc = sqlite3_initialize();
if( rc ){
@@ -133557,6 +137145,9 @@ SQLITE_API int sqlite3_cancel_auto_extension(
int i;
int n = 0;
wsdAutoextInit;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( xInit==0 ) return 0;
+#endif
sqlite3_mutex_enter(mutex);
for(i=(int)wsdAutoext.nExt-1; i>=0; i--){
if( wsdAutoext.aExt[i]==xInit ){
@@ -135156,7 +138747,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
**
** The first form reports the current local setting for the
** page cache spill size. The second form turns cache spill on
- ** or off. When turnning cache spill on, the size is set to the
+ ** or off. When turning cache spill on, the size is set to the
** current cache_size. The third form sets a spill size that
** may be different form the cache size.
** If N is positive then that is the
@@ -135426,7 +139017,11 @@ SQLITE_PRIVATE void sqlite3Pragma(
#endif
if( sqlite3GetBoolean(zRight, 0) ){
- db->flags |= mask;
+ if( (mask & SQLITE_WriteSchema)==0
+ || (db->flags & SQLITE_Defensive)==0
+ ){
+ db->flags |= mask;
+ }
}else{
db->flags &= ~mask;
if( mask==SQLITE_DeferFKs ) db->nDeferredImmCons = 0;
@@ -135826,7 +139421,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
zDb = db->aDb[iDb].zDbSName;
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
- if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow;
+ sqlite3TouchRegister(pParse, pTab->nCol+regRow);
sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead);
sqlite3VdbeLoadString(v, regResult, pTab->zName);
assert( IsOrdinaryTable(pTab) );
@@ -135867,7 +139462,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
** regRow..regRow+n. If any of the child key values are NULL, this
** row cannot cause an FK violation. Jump directly to addrOk in
** this case. */
- if( regRow+pFK->nCol>pParse->nMem ) pParse->nMem = regRow+pFK->nCol;
+ sqlite3TouchRegister(pParse, regRow + pFK->nCol);
for(j=0; j<pFK->nCol; j++){
int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom;
sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j);
@@ -135934,9 +139529,9 @@ SQLITE_PRIVATE void sqlite3Pragma(
** The "quick_check" is reduced version of
** integrity_check designed to detect most database corruption
** without the overhead of cross-checking indexes. Quick_check
- ** is linear time wherease integrity_check is O(NlogN).
+ ** is linear time whereas integrity_check is O(NlogN).
**
- ** The maximum nubmer of errors is 100 by default. A different default
+ ** The maximum number of errors is 100 by default. A different default
** can be specified using a numeric parameter N.
**
** Or, the parameter N can be the name of a table. In that case, only
@@ -135996,6 +139591,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( iDb>=0 && i!=iDb ) continue;
sqlite3CodeVerifySchema(pParse, i);
+ pParse->okConstFactor = 0; /* tag-20230327-1 */
/* Do an integrity check of the B-Tree
**
@@ -136031,7 +139627,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
aRoot[0] = cnt;
/* Make sure sufficient number of registers have been allocated */
- pParse->nMem = MAX( pParse->nMem, 8+mxIdx );
+ sqlite3TouchRegister(pParse, 8+mxIdx);
sqlite3ClearTempRegCache(pParse);
/* Do the b-tree integrity checks */
@@ -136058,8 +139654,8 @@ SQLITE_PRIVATE void sqlite3Pragma(
int r2; /* Previous key for WITHOUT ROWID tables */
int mxCol; /* Maximum non-virtual column number */
- if( !IsOrdinaryTable(pTab) ) continue;
if( pObjTab && pObjTab!=pTab ) continue;
+ if( !IsOrdinaryTable(pTab) ) continue;
if( isQuick || HasRowid(pTab) ){
pPk = 0;
r2 = 0;
@@ -136181,15 +139777,30 @@ SQLITE_PRIVATE void sqlite3Pragma(
labelOk = sqlite3VdbeMakeLabel(pParse);
if( pCol->notNull ){
/* (1) NOT NULL columns may not contain a NULL */
+ int jmp3;
int jmp2 = sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
- sqlite3VdbeChangeP5(v, 0x0f);
VdbeCoverage(v);
+ if( p1<0 ){
+ sqlite3VdbeChangeP5(v, 0x0f); /* INT, REAL, TEXT, or BLOB */
+ jmp3 = jmp2;
+ }else{
+ sqlite3VdbeChangeP5(v, 0x0d); /* INT, TEXT, or BLOB */
+ /* OP_IsType does not detect NaN values in the database file
+ ** which should be treated as a NULL. So if the header type
+ ** is REAL, we have to load the actual data using OP_Column
+ ** to reliably determine if the value is a NULL. */
+ sqlite3VdbeAddOp3(v, OP_Column, p1, p3, 3);
+ sqlite3ColumnDefault(v, pTab, j, 3);
+ jmp3 = sqlite3VdbeAddOp2(v, OP_NotNull, 3, labelOk);
+ VdbeCoverage(v);
+ }
zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
pCol->zCnName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
if( doTypeCheck ){
sqlite3VdbeGoto(v, labelError);
sqlite3VdbeJumpHere(v, jmp2);
+ sqlite3VdbeJumpHere(v, jmp3);
}else{
/* VDBE byte code will fall thru */
}
@@ -136297,7 +139908,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
int jmp7;
sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur+j, 3);
jmp7 = sqlite3VdbeAddOp3(v, OP_Eq, 3, 0, r1+pIdx->nColumn-1);
- VdbeCoverage(v);
+ VdbeCoverageNeverNull(v);
sqlite3VdbeLoadString(v, 3,
"rowid not at end-of-record for row ");
sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
@@ -136370,6 +139981,38 @@ SQLITE_PRIVATE void sqlite3Pragma(
}
}
}
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ /* Second pass to invoke the xIntegrity method on all virtual
+ ** tables.
+ */
+ for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
+ Table *pTab = sqliteHashData(x);
+ sqlite3_vtab *pVTab;
+ int a1;
+ if( pObjTab && pObjTab!=pTab ) continue;
+ if( IsOrdinaryTable(pTab) ) continue;
+ if( !IsVirtual(pTab) ) continue;
+ if( pTab->nCol<=0 ){
+ const char *zMod = pTab->u.vtab.azArg[0];
+ if( sqlite3HashFind(&db->aModule, zMod)==0 ) continue;
+ }
+ sqlite3ViewGetColumnNames(pParse, pTab);
+ if( pTab->u.vtab.p==0 ) continue;
+ pVTab = pTab->u.vtab.p->pVtab;
+ if( NEVER(pVTab==0) ) continue;
+ if( NEVER(pVTab->pModule==0) ) continue;
+ if( pVTab->pModule->iVersion<4 ) continue;
+ if( pVTab->pModule->xIntegrity==0 ) continue;
+ sqlite3VdbeAddOp3(v, OP_VCheck, i, 3, isQuick);
+ pTab->nTabRef++;
+ sqlite3VdbeAppendP4(v, pTab, P4_TABLEREF);
+ a1 = sqlite3VdbeAddOp1(v, OP_IsNull, 3); VdbeCoverage(v);
+ integrityCheckResultRow(v);
+ sqlite3VdbeJumpHere(v, a1);
+ continue;
+ }
+#endif
}
{
static const int iLn = VDBE_OFFSET_LINENO(2);
@@ -136679,7 +140322,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
Schema *pSchema; /* The current schema */
Table *pTab; /* A table in the schema */
Index *pIdx; /* An index of the table */
- LogEst szThreshold; /* Size threshold above which reanalysis is needd */
+ LogEst szThreshold; /* Size threshold above which reanalysis needed */
char *zSubSql; /* SQL statement for the OP_SqlExec opcode */
u32 opMask; /* Mask of operations to perform */
@@ -137006,7 +140649,11 @@ static int pragmaVtabBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
j = seen[0]-1;
pIdxInfo->aConstraintUsage[j].argvIndex = 1;
pIdxInfo->aConstraintUsage[j].omit = 1;
- if( seen[1]==0 ) return SQLITE_OK;
+ if( seen[1]==0 ){
+ pIdxInfo->estimatedCost = (double)1000;
+ pIdxInfo->estimatedRows = 1000;
+ return SQLITE_OK;
+ }
pIdxInfo->estimatedCost = (double)20;
pIdxInfo->estimatedRows = 20;
j = seen[1]-1;
@@ -137171,7 +140818,8 @@ static const sqlite3_module pragmaVtabModule = {
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
/*
@@ -137503,7 +141151,9 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl
#else
encoding = SQLITE_UTF8;
#endif
- if( db->nVdbeActive>0 && encoding!=ENC(db) ){
+ if( db->nVdbeActive>0 && encoding!=ENC(db)
+ && (db->mDbFlags & DBFLAG_Vacuum)==0
+ ){
rc = SQLITE_LOCKED;
goto initone_error_out;
}else{
@@ -137793,8 +141443,6 @@ SQLITE_PRIVATE void sqlite3ParseObjectReset(Parse *pParse){
db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue;
assert( pParse->db->pParse==pParse );
db->pParse = pParse->pOuterParse;
- pParse->db = 0;
- pParse->disableLookaside = 0;
}
/*
@@ -137803,7 +141451,7 @@ SQLITE_PRIVATE void sqlite3ParseObjectReset(Parse *pParse){
** immediately.
**
** Use this mechanism for uncommon cleanups. There is a higher setup
-** cost for this mechansim (an extra malloc), so it should not be used
+** cost for this mechanism (an extra malloc), so it should not be used
** for common cleanups that happen on most calls. But for less
** common cleanups, we save a single NULL-pointer comparison in
** sqlite3ParseObjectReset(), which reduces the total CPU cycle count.
@@ -137895,9 +141543,18 @@ static int sqlite3Prepare(
sParse.pOuterParse = db->pParse;
db->pParse = &sParse;
sParse.db = db;
- sParse.pReprepare = pReprepare;
+ if( pReprepare ){
+ sParse.pReprepare = pReprepare;
+ sParse.explain = sqlite3_stmt_isexplain((sqlite3_stmt*)pReprepare);
+ }else{
+ assert( sParse.pReprepare==0 );
+ }
assert( ppStmt && *ppStmt==0 );
- if( db->mallocFailed ) sqlite3ErrorMsg(&sParse, "out of memory");
+ if( db->mallocFailed ){
+ sqlite3ErrorMsg(&sParse, "out of memory");
+ db->errCode = rc = SQLITE_NOMEM;
+ goto end_prepare;
+ }
assert( sqlite3_mutex_held(db->mutex) );
/* For a long-term use prepared statement avoid the use of
@@ -138056,6 +141713,7 @@ static int sqlite3LockAndPrepare(
assert( (rc&db->errMask)==rc );
db->busyHandler.nBusy = 0;
sqlite3_mutex_leave(db->mutex);
+ assert( rc==SQLITE_OK || (*ppStmt)==0 );
return rc;
}
@@ -138453,6 +142111,9 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3 *db, Select *p){
if( OK_IF_ALWAYS_TRUE(p) ) clearSelect(db, p, 1);
}
+SQLITE_PRIVATE void sqlite3SelectDeleteGeneric(sqlite3 *db, void *p){
+ if( ALWAYS(p) ) clearSelect(db, (Select*)p, 1);
+}
/*
** Return a pointer to the right-most SELECT statement in a compound.
@@ -138501,7 +142162,7 @@ static Select *findRightmost(Select *p){
** NATURAL FULL OUTER JT_NATRUAL|JT_LEFT|JT_RIGHT
**
** To preserve historical compatibly, SQLite also accepts a variety
-** of other non-standard and in many cases non-sensical join types.
+** of other non-standard and in many cases nonsensical join types.
** This routine makes as much sense at it can from the nonsense join
** type and returns a result. Examples of accepted nonsense join types
** include but are not limited to:
@@ -138723,6 +142384,7 @@ static void unsetJoinExpr(Expr *p, int iTable, int nullable){
}
if( p->op==TK_FUNCTION ){
assert( ExprUseXList(p) );
+ assert( p->pLeft==0 );
if( p->x.pList ){
int i;
for(i=0; i<p->x.pList->nExpr; i++){
@@ -138772,7 +142434,7 @@ static int sqlite3ProcessJoin(Parse *pParse, Select *p){
if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue;
joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_OuterON : EP_InnerON;
- /* If this is a NATURAL join, synthesize an approprate USING clause
+ /* If this is a NATURAL join, synthesize an appropriate USING clause
** to specify which columns should be joined.
*/
if( pRight->fg.jointype & JT_NATURAL ){
@@ -138986,9 +142648,9 @@ static void pushOntoSorter(
** (2) All output columns are included in the sort record. In that
** case regData==regOrigData.
** (3) Some output columns are omitted from the sort record due to
- ** the SQLITE_ENABLE_SORTER_REFERENCE optimization, or due to the
+ ** the SQLITE_ENABLE_SORTER_REFERENCES optimization, or due to the
** SQLITE_ECEL_OMITREF optimization, or due to the
- ** SortCtx.pDeferredRowLoad optimiation. In any of these cases
+ ** SortCtx.pDeferredRowLoad optimization. In any of these cases
** regOrigData is 0 to prevent this routine from trying to copy
** values that might not yet exist.
*/
@@ -139044,7 +142706,7 @@ static void pushOntoSorter(
testcase( pKI->nAllField > pKI->nKeyField+2 );
pOp->p4.pKeyInfo = sqlite3KeyInfoFromExprList(pParse,pSort->pOrderBy,nOBSat,
pKI->nAllField-pKI->nKeyField-1);
- pOp = 0; /* Ensure pOp not used after sqltie3VdbeAddOp3() */
+ pOp = 0; /* Ensure pOp not used after sqlite3VdbeAddOp3() */
addrJmp = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp3(v, OP_Jump, addrJmp+1, 0, addrJmp+1); VdbeCoverage(v);
pSort->labelBkOut = sqlite3VdbeMakeLabel(pParse);
@@ -139138,7 +142800,7 @@ static void codeOffset(
** The returned value in this case is a copy of parameter iTab.
**
** WHERE_DISTINCT_ORDERED:
-** In this case rows are being delivered sorted order. The ephermal
+** In this case rows are being delivered sorted order. The ephemeral
** table is not required. Instead, the current set of values
** is compared against previous row. If they match, the new row
** is not distinct and control jumps to VM address addrRepeat. Otherwise,
@@ -139567,6 +143229,16 @@ static void selectInnerLoop(
testcase( eDest==SRT_Fifo );
testcase( eDest==SRT_DistFifo );
sqlite3VdbeAddOp3(v, OP_MakeRecord, regResult, nResultCol, r1+nPrefixReg);
+#if !defined(SQLITE_ENABLE_NULL_TRIM) && defined(SQLITE_DEBUG)
+ /* A destination of SRT_Table and a non-zero iSDParm2 parameter means
+ ** that this is an "UPDATE ... FROM" on a virtual table or view. In this
+ ** case set the p5 parameter of the OP_MakeRecord to OPFLAG_NOCHNG_MAGIC.
+ ** This does not affect operation in any way - it just allows MakeRecord
+ ** to process OPFLAG_NOCHANGE values without an assert() failing. */
+ if( eDest==SRT_Table && pDest->iSDParm2 ){
+ sqlite3VdbeChangeP5(v, OPFLAG_NOCHNG_MAGIC);
+ }
+#endif
#ifndef SQLITE_OMIT_CTE
if( eDest==SRT_DistFifo ){
/* If the destination is DistFifo, then cursor (iParm+1) is open
@@ -140208,11 +143880,7 @@ static const char *columnTypeImpl(
** data for the result-set column of the sub-select.
*/
if( iCol<pS->pEList->nExpr
-#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
- && iCol>=0
-#else
- && ALWAYS(iCol>=0)
-#endif
+ && (!ViewCanHaveRowid || iCol>=0)
){
/* If iCol is less than zero, then the expression requests the
** rowid of the sub-select or view. This expression is legal (see
@@ -140370,13 +144038,6 @@ SQLITE_PRIVATE void sqlite3GenerateColumnNames(
int fullName; /* TABLE.COLUMN if no AS clause and is a direct table ref */
int srcName; /* COLUMN or TABLE.COLUMN if no AS clause and is direct */
-#ifndef SQLITE_OMIT_EXPLAIN
- /* If this is an EXPLAIN, skip this step */
- if( pParse->explain ){
- return;
- }
-#endif
-
if( pParse->colNamesSet ) return;
/* Column names are determined by the left-most term of a compound select */
while( pSelect->pPrior ) pSelect = pSelect->pPrior;
@@ -140563,7 +144224,7 @@ SQLITE_PRIVATE int sqlite3ColumnsFromExprList(
** kind (maybe a parenthesized subquery in the FROM clause of a larger
** query, or a VIEW, or a CTE). This routine computes type information
** for that Table object based on the Select object that implements the
-** subquery. For the purposes of this routine, "type infomation" means:
+** subquery. For the purposes of this routine, "type information" means:
**
** * The datatype name, as it might appear in a CREATE TABLE statement
** * Which collating sequence to use for the column
@@ -140584,10 +144245,11 @@ SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(
NameContext sNC;
assert( pSelect!=0 );
- assert( (pSelect->selFlags & SF_Resolved)!=0 );
+ testcase( (pSelect->selFlags & SF_Resolved)==0 );
+ assert( (pSelect->selFlags & SF_Resolved)!=0 || IN_RENAME_OBJECT );
assert( pTab->nCol==pSelect->pEList->nExpr || pParse->nErr>0 );
assert( aff==SQLITE_AFF_NONE || aff==SQLITE_AFF_BLOB );
- if( db->mallocFailed ) return;
+ if( db->mallocFailed || IN_RENAME_OBJECT ) return;
while( pSelect->pPrior ) pSelect = pSelect->pPrior;
a = pSelect->pEList->a;
memset(&sNC, 0, sizeof(sNC));
@@ -140632,18 +144294,16 @@ SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(
break;
}
}
- }
- }
- if( zType ){
- i64 m = sqlite3Strlen30(zType);
- n = sqlite3Strlen30(pCol->zCnName);
- pCol->zCnName = sqlite3DbReallocOrFree(db, pCol->zCnName, n+m+2);
- if( pCol->zCnName ){
- memcpy(&pCol->zCnName[n+1], zType, m+1);
- pCol->colFlags |= COLFLAG_HASTYPE;
- }else{
- testcase( pCol->colFlags & COLFLAG_HASTYPE );
- pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL);
+ }
+ }
+ if( zType ){
+ i64 m = sqlite3Strlen30(zType);
+ n = sqlite3Strlen30(pCol->zCnName);
+ pCol->zCnName = sqlite3DbReallocOrFree(db, pCol->zCnName, n+m+2);
+ pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL);
+ if( pCol->zCnName ){
+ memcpy(&pCol->zCnName[n+1], zType, m+1);
+ pCol->colFlags |= COLFLAG_HASTYPE;
}
}
pColl = sqlite3ExprCollSeq(pParse, p);
@@ -140894,7 +144554,7 @@ static void generateWithRecursiveQuery(
int iQueue; /* The Queue table */
int iDistinct = 0; /* To ensure unique results if UNION */
int eDest = SRT_Fifo; /* How to write to Queue */
- SelectDest destQueue; /* SelectDest targetting the Queue table */
+ SelectDest destQueue; /* SelectDest targeting the Queue table */
int i; /* Loop counter */
int rc; /* Result code */
ExprList *pOrderBy; /* The ORDER BY clause */
@@ -141470,9 +145130,7 @@ multi_select_end:
pDest->iSdst = dest.iSdst;
pDest->nSdst = dest.nSdst;
if( pDelete ){
- sqlite3ParserAddCleanup(pParse,
- (void(*)(sqlite3*,void*))sqlite3SelectDelete,
- pDelete);
+ sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pDelete);
}
return rc;
}
@@ -141494,7 +145152,7 @@ SQLITE_PRIVATE void sqlite3SelectWrongNumTermsError(Parse *pParse, Select *p){
/*
** Code an output subroutine for a coroutine implementation of a
-** SELECT statment.
+** SELECT statement.
**
** The data to be output is contained in pIn->iSdst. There are
** pIn->nSdst columns to be output. pDest is where the output should
@@ -141716,7 +145374,7 @@ static int generateOutputSubroutine(
**
** We call AltB, AeqB, AgtB, EofA, and EofB "subroutines" but they are not
** actually called using Gosub and they do not Return. EofA and EofB loop
-** until all data is exhausted then jump to the "end" labe. AltB, AeqB,
+** until all data is exhausted then jump to the "end" label. AltB, AeqB,
** and AgtB jump to either L2 or to one of EofA or EofB.
*/
#ifndef SQLITE_OMIT_COMPOUND_SELECT
@@ -141753,7 +145411,7 @@ static int multiSelectOrderBy(
int savedOffset; /* Saved value of p->iOffset */
int labelCmpr; /* Label for the start of the merge algorithm */
int labelEnd; /* Label for the end of the overall SELECT stmt */
- int addr1; /* Jump instructions that get retargetted */
+ int addr1; /* Jump instructions that get retargeted */
int op; /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */
KeyInfo *pKeyDup = 0; /* Comparison information for duplicate removal */
KeyInfo *pKeyMerge; /* Comparison information for merging rows */
@@ -142023,8 +145681,7 @@ static int multiSelectOrderBy(
/* Make arrangements to free the 2nd and subsequent arms of the compound
** after the parse has finished */
if( pSplit->pPrior ){
- sqlite3ParserAddCleanup(pParse,
- (void(*)(sqlite3*,void*))sqlite3SelectDelete, pSplit->pPrior);
+ sqlite3ParserAddCleanup(pParse, sqlite3SelectDeleteGeneric, pSplit->pPrior);
}
pSplit->pPrior = pPrior;
pPrior->pNext = pSplit;
@@ -142122,16 +145779,21 @@ static Expr *substExpr(
#endif
{
Expr *pNew;
- int iColumn = pExpr->iColumn;
- Expr *pCopy = pSubst->pEList->a[iColumn].pExpr;
+ int iColumn;
+ Expr *pCopy;
Expr ifNullRow;
+ iColumn = pExpr->iColumn;
+ assert( iColumn>=0 );
assert( pSubst->pEList!=0 && iColumn<pSubst->pEList->nExpr );
assert( pExpr->pRight==0 );
+ pCopy = pSubst->pEList->a[iColumn].pExpr;
if( sqlite3ExprIsVector(pCopy) ){
sqlite3VectorErrorMsg(pSubst->pParse, pCopy);
}else{
sqlite3 *db = pSubst->pParse->db;
- if( pSubst->isOuterJoin ){
+ if( pSubst->isOuterJoin
+ && (pCopy->op!=TK_COLUMN || pCopy->iTable!=pSubst->iNewTable)
+ ){
memset(&ifNullRow, 0, sizeof(ifNullRow));
ifNullRow.op = TK_IF_NULL_ROW;
ifNullRow.pLeft = pCopy;
@@ -142473,7 +146135,7 @@ static int compoundHasDifferentAffinities(Select *p){
** (9) If the subquery uses LIMIT then the outer query may not be aggregate.
**
** (**) Restriction (10) was removed from the code on 2005-02-05 but we
-** accidently carried the comment forward until 2014-09-15. Original
+** accidentally carried the comment forward until 2014-09-15. Original
** constraint: "If the subquery is aggregate then the outer query
** may not use LIMIT."
**
@@ -142508,8 +146170,7 @@ static int compoundHasDifferentAffinities(Select *p){
** query or there are no RIGHT or FULL JOINs in any arm
** of the subquery. (This is a duplicate of condition (27b).)
** (17h) The corresponding result set expressions in all arms of the
-** compound must have the same affinity. (See restriction (9)
-** on the push-down optimization.)
+** compound must have the same affinity.
**
** The parent and sub-query may contain WHERE clauses. Subject to
** rules (11), (13) and (14), they may also contain ORDER BY,
@@ -142566,7 +146227,8 @@ static int compoundHasDifferentAffinities(Select *p){
** (27b) the subquery is a compound query and the RIGHT JOIN occurs
** in any arm of the compound query. (See also (17g).)
**
-** (28) The subquery is not a MATERIALIZED CTE.
+** (28) The subquery is not a MATERIALIZED CTE. (This is handled
+** in the caller before ever reaching this routine.)
**
**
** In this routine, the "p" parameter is a pointer to the outer query.
@@ -142676,9 +146338,9 @@ static int flattenSubquery(
if( iFrom>0 && (pSubSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){
return 0; /* Restriction (27a) */
}
- if( pSubitem->fg.isCte && pSubitem->u2.pCteUse->eM10d==M10d_Yes ){
- return 0; /* (28) */
- }
+
+ /* Condition (28) is blocked by the caller */
+ assert( !pSubitem->fg.isCte || pSubitem->u2.pCteUse->eM10d!=M10d_Yes );
/* Restriction (17): If the sub-query is a compound SELECT, then it must
** use only the UNION ALL operator. And none of the simple select queries
@@ -142748,7 +146410,7 @@ static int flattenSubquery(
testcase( i==SQLITE_DENY );
pParse->zAuthContext = zSavedAuthContext;
- /* Delete the transient structures associated with thesubquery */
+ /* Delete the transient structures associated with the subquery */
pSub1 = pSubitem->pSelect;
sqlite3DbFree(db, pSubitem->zDatabase);
sqlite3DbFree(db, pSubitem->zName);
@@ -142840,9 +146502,7 @@ static int flattenSubquery(
Table *pTabToDel = pSubitem->pTab;
if( pTabToDel->nTabRef==1 ){
Parse *pToplevel = sqlite3ParseToplevel(pParse);
- sqlite3ParserAddCleanup(pToplevel,
- (void(*)(sqlite3*,void*))sqlite3DeleteTable,
- pTabToDel);
+ sqlite3ParserAddCleanup(pToplevel, sqlite3DeleteTableGeneric, pTabToDel);
testcase( pToplevel->earlyCleanup );
}else{
pTabToDel->nTabRef--;
@@ -142930,7 +146590,7 @@ static int flattenSubquery(
** ORDER BY column expression is identical to the iOrderByCol'th
** expression returned by SELECT statement pSub. Since these values
** do not necessarily correspond to columns in SELECT statement pParent,
- ** zero them before transfering the ORDER BY clause.
+ ** zero them before transferring the ORDER BY clause.
**
** Not doing this may cause an error if a subsequent call to this
** function attempts to flatten a compound sub-query into pParent
@@ -142990,8 +146650,7 @@ static int flattenSubquery(
}
}
- /* Finially, delete what is left of the subquery and return
- ** success.
+ /* Finally, delete what is left of the subquery and return success.
*/
sqlite3AggInfoPersistWalkerInit(&w, pParse);
sqlite3WalkSelect(&w,pSub1);
@@ -143026,7 +146685,7 @@ struct WhereConst {
/*
** Add a new entry to the pConst object. Except, do not add duplicate
-** pColumn entires. Also, do not add if doing so would not be appropriate.
+** pColumn entries. Also, do not add if doing so would not be appropriate.
**
** The caller guarantees the pColumn is a column and pValue is a constant.
** This routine has to do some additional checks before completing the
@@ -143212,7 +146871,7 @@ static int propagateConstantExprRewrite(Walker *pWalker, Expr *pExpr){
** SELECT * FROM t1 WHERE a=123 AND b=123;
**
** The two SELECT statements above should return different answers. b=a
-** is alway true because the comparison uses numeric affinity, but b=123
+** is always true because the comparison uses numeric affinity, but b=123
** is false because it uses text affinity and '0123' is not the same as '123'.
** To work around this, the expression tree is not actually changed from
** "b=a" to "b=123" but rather the "a" in "b=a" is tagged with EP_FixedCol
@@ -143296,7 +146955,7 @@ static int propagateConstants(
** At the time this function is called it is guaranteed that
**
** * the sub-query uses only one distinct window frame, and
-** * that the window frame has a PARTITION BY clase.
+** * that the window frame has a PARTITION BY clause.
*/
static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){
assert( pSubq->pWin->pPartition );
@@ -143377,10 +147036,28 @@ static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){
** or EXCEPT, then all of the result set columns for all arms of
** the compound must use the BINARY collating sequence.
**
-** (9) If the subquery is a compound, then all arms of the compound must
-** have the same affinity. (This is the same as restriction (17h)
-** for query flattening.)
+** (9) All three of the following are true:
+**
+** (9a) The WHERE clause expression originates in the ON or USING clause
+** of a join (either an INNER or an OUTER join), and
+**
+** (9b) The subquery is to the right of the ON/USING clause
+**
+** (9c) There is a RIGHT JOIN (or FULL JOIN) in between the ON/USING
+** clause and the subquery.
+**
+** Without this restriction, the push-down optimization might move
+** the ON/USING filter expression from the left side of a RIGHT JOIN
+** over to the right side, which leads to incorrect answers. See
+** also restriction (6) in sqlite3ExprIsSingleTableConstraint().
+**
+** (10) The inner query is not the right-hand table of a RIGHT JOIN.
+**
+** (11) The subquery is not a VALUES clause
**
+** (12) The WHERE clause is not "rowid ISNULL" or the equivalent. This
+** case only comes up if SQLite is compiled using
+** SQLITE_ALLOW_ROWID_IN_VIEW.
**
** Return 0 if no changes are made and non-zero if one or more WHERE clause
** terms are duplicated into the subquery.
@@ -143389,13 +147066,20 @@ static int pushDownWhereTerms(
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 */
- SrcItem *pSrc /* The subquery term of the outer FROM clause */
+ SrcList *pSrcList, /* The complete from clause of the outer query */
+ int iSrc /* Which FROM clause term to try to push into */
){
Expr *pNew;
+ SrcItem *pSrc; /* The subquery FROM term into which WHERE is pushed */
int nChng = 0;
+ pSrc = &pSrcList->a[iSrc];
if( pWhere==0 ) return 0;
- if( pSubq->selFlags & (SF_Recursive|SF_MultiPart) ) return 0;
- if( pSrc->fg.jointype & (JT_LTORJ|JT_RIGHT) ) return 0;
+ if( pSubq->selFlags & (SF_Recursive|SF_MultiPart) ){
+ return 0; /* restrictions (2) and (11) */
+ }
+ if( pSrc->fg.jointype & (JT_LTORJ|JT_RIGHT) ){
+ return 0; /* restrictions (10) */
+ }
if( pSubq->pPrior ){
Select *pSel;
@@ -143411,9 +147095,6 @@ static int pushDownWhereTerms(
if( pSel->pWin ) return 0; /* restriction (6b) */
#endif
}
- if( compoundHasDifferentAffinities(pSubq) ){
- return 0; /* restriction (9) */
- }
if( notUnionAll ){
/* If any of the compound arms are connected using UNION, INTERSECT,
** or EXCEPT, then we must ensure that none of the columns use a
@@ -143453,11 +147134,28 @@ static int pushDownWhereTerms(
return 0; /* restriction (3) */
}
while( pWhere->op==TK_AND ){
- nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, pSrc);
+ nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, pSrcList, iSrc);
pWhere = pWhere->pLeft;
}
-#if 0 /* Legacy code. Checks now done by sqlite3ExprIsTableConstraint() */
+#if 0 /* These checks now done by sqlite3ExprIsSingleTableConstraint() */
+ if( ExprHasProperty(pWhere, EP_OuterON|EP_InnerON) /* (9a) */
+ && (pSrcList->a[0].fg.jointype & JT_LTORJ)!=0 /* Fast pre-test of (9c) */
+ ){
+ int jj;
+ for(jj=0; jj<iSrc; jj++){
+ if( pWhere->w.iJoin==pSrcList->a[jj].iCursor ){
+ /* If we reach this point, both (9a) and (9b) are satisfied.
+ ** The following loop checks (9c):
+ */
+ for(jj++; jj<iSrc; jj++){
+ if( (pSrcList->a[jj].fg.jointype & JT_RIGHT)!=0 ){
+ return 0; /* restriction (9) */
+ }
+ }
+ }
+ }
+ }
if( isLeftJoin
&& (ExprHasProperty(pWhere,EP_OuterON)==0
|| pWhere->w.iJoin!=iCursor)
@@ -143471,7 +147169,19 @@ static int pushDownWhereTerms(
}
#endif
- if( sqlite3ExprIsTableConstraint(pWhere, pSrc) ){
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ if( ViewCanHaveRowid && (pWhere->op==TK_ISNULL || pWhere->op==TK_NOTNULL) ){
+ Expr *pLeft = pWhere->pLeft;
+ if( ALWAYS(pLeft)
+ && pLeft->op==TK_COLUMN
+ && pLeft->iColumn < 0
+ ){
+ return 0; /* Restriction (12) */
+ }
+ }
+#endif
+
+ if( sqlite3ExprIsSingleTableConstraint(pWhere, pSrcList, iSrc) ){
nChng++;
pSubq->selFlags |= SF_PushDown;
while( pSubq ){
@@ -143506,6 +147216,78 @@ static int pushDownWhereTerms(
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
/*
+** Check to see if a subquery contains result-set columns that are
+** never used. If it does, change the value of those result-set columns
+** to NULL so that they do not cause unnecessary work to compute.
+**
+** Return the number of column that were changed to NULL.
+*/
+static int disableUnusedSubqueryResultColumns(SrcItem *pItem){
+ int nCol;
+ Select *pSub; /* The subquery to be simplified */
+ Select *pX; /* For looping over compound elements of pSub */
+ Table *pTab; /* The table that describes the subquery */
+ int j; /* Column number */
+ int nChng = 0; /* Number of columns converted to NULL */
+ Bitmask colUsed; /* Columns that may not be NULLed out */
+
+ assert( pItem!=0 );
+ if( pItem->fg.isCorrelated || pItem->fg.isCte ){
+ return 0;
+ }
+ assert( pItem->pTab!=0 );
+ pTab = pItem->pTab;
+ assert( pItem->pSelect!=0 );
+ pSub = pItem->pSelect;
+ assert( pSub->pEList->nExpr==pTab->nCol );
+ for(pX=pSub; pX; pX=pX->pPrior){
+ if( (pX->selFlags & (SF_Distinct|SF_Aggregate))!=0 ){
+ testcase( pX->selFlags & SF_Distinct );
+ testcase( pX->selFlags & SF_Aggregate );
+ return 0;
+ }
+ if( pX->pPrior && pX->op!=TK_ALL ){
+ /* This optimization does not work for compound subqueries that
+ ** use UNION, INTERSECT, or EXCEPT. Only UNION ALL is allowed. */
+ return 0;
+ }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( pX->pWin ){
+ /* This optimization does not work for subqueries that use window
+ ** functions. */
+ return 0;
+ }
+#endif
+ }
+ colUsed = pItem->colUsed;
+ if( pSub->pOrderBy ){
+ ExprList *pList = pSub->pOrderBy;
+ for(j=0; j<pList->nExpr; j++){
+ u16 iCol = pList->a[j].u.x.iOrderByCol;
+ if( iCol>0 ){
+ iCol--;
+ colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol);
+ }
+ }
+ }
+ nCol = pTab->nCol;
+ for(j=0; j<nCol; j++){
+ Bitmask m = j<BMS-1 ? MASKBIT(j) : TOPBIT;
+ if( (m & colUsed)!=0 ) continue;
+ for(pX=pSub; pX; pX=pX->pPrior) {
+ Expr *pY = pX->pEList->a[j].pExpr;
+ if( pY->op==TK_NULL ) continue;
+ pY->op = TK_NULL;
+ ExprClearProperty(pY, EP_Skip|EP_Unlikely);
+ pX->selFlags |= SF_PushDown;
+ nChng++;
+ }
+ }
+ return nChng;
+}
+
+
+/*
** The pFunc is the only aggregate function in the query. Check to see
** if the query is a candidate for the min/max optimization.
**
@@ -143783,8 +147565,7 @@ static struct Cte *searchWith(
SQLITE_PRIVATE With *sqlite3WithPush(Parse *pParse, With *pWith, u8 bFree){
if( pWith ){
if( bFree ){
- pWith = (With*)sqlite3ParserAddCleanup(pParse,
- (void(*)(sqlite3*,void*))sqlite3WithDelete,
+ pWith = (With*)sqlite3ParserAddCleanup(pParse, sqlite3WithDeleteGeneric,
pWith);
if( pWith==0 ) return 0;
}
@@ -144027,12 +147808,14 @@ SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){
while( pSel->pPrior ){ pSel = pSel->pPrior; }
sqlite3ColumnsFromExprList(pParse, pSel->pEList,&pTab->nCol,&pTab->aCol);
pTab->iPKey = -1;
+ pTab->eTabType = TABTYP_VIEW;
pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) );
#ifndef SQLITE_ALLOW_ROWID_IN_VIEW
/* The usual case - do not allow ROWID on a subquery */
pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid;
#else
- pTab->tabFlags |= TF_Ephemeral; /* Legacy compatibility mode */
+ /* Legacy compatibility mode */
+ pTab->tabFlags |= TF_Ephemeral | sqlite3Config.mNoVisibleRowid;
#endif
return pParse->nErr ? SQLITE_ERROR : SQLITE_OK;
}
@@ -144269,12 +148052,20 @@ static int selectExpander(Walker *pWalker, Select *p){
** expanded. */
int tableSeen = 0; /* Set to 1 when TABLE matches */
char *zTName = 0; /* text of name of TABLE */
+ int iErrOfst;
if( pE->op==TK_DOT ){
+ assert( (selFlags & SF_NestedFrom)==0 );
assert( pE->pLeft!=0 );
assert( !ExprHasProperty(pE->pLeft, EP_IntValue) );
zTName = pE->pLeft->u.zToken;
+ assert( ExprUseWOfst(pE->pLeft) );
+ iErrOfst = pE->pRight->w.iOfst;
+ }else{
+ assert( ExprUseWOfst(pE) );
+ iErrOfst = pE->w.iOfst;
}
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
+ int nAdd; /* Number of cols including rowid */
Table *pTab = pFrom->pTab; /* Table for this data source */
ExprList *pNestedFrom; /* Result-set of a nested FROM clause */
char *zTabName; /* AS name for this data source */
@@ -144292,6 +148083,7 @@ static int selectExpander(Walker *pWalker, Select *p){
pNestedFrom = pFrom->pSelect->pEList;
assert( pNestedFrom!=0 );
assert( pNestedFrom->nExpr==pTab->nCol );
+ assert( VisibleRowid(pTab)==0 || ViewCanHaveRowid );
}else{
if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){
continue;
@@ -144309,6 +148101,7 @@ static int selectExpander(Walker *pWalker, Select *p){
for(ii=0; ii<pUsing->nId; ii++){
const char *zUName = pUsing->a[ii].zName;
pRight = sqlite3Expr(db, TK_ID, zUName);
+ sqlite3ExprSetErrorOffset(pRight, iErrOfst);
pNew = sqlite3ExprListAppend(pParse, pNew, pRight);
if( pNew ){
struct ExprList_item *pX = &pNew->a[pNew->nExpr-1];
@@ -144321,33 +148114,49 @@ static int selectExpander(Walker *pWalker, Select *p){
}else{
pUsing = 0;
}
- for(j=0; j<pTab->nCol; j++){
- char *zName = pTab->aCol[j].zCnName;
+
+ nAdd = pTab->nCol;
+ if( VisibleRowid(pTab) && (selFlags & SF_NestedFrom)!=0 ) nAdd++;
+ for(j=0; j<nAdd; j++){
+ const char *zName;
struct ExprList_item *pX; /* Newly added ExprList term */
- assert( zName );
- if( zTName
- && pNestedFrom
- && sqlite3MatchEName(&pNestedFrom->a[j], 0, zTName, 0)==0
- ){
- continue;
- }
+ if( j==pTab->nCol ){
+ zName = sqlite3RowidAlias(pTab);
+ if( zName==0 ) continue;
+ }else{
+ zName = pTab->aCol[j].zCnName;
- /* If a column is marked as 'hidden', omit it from the expanded
- ** result-set list unless the SELECT has the SF_IncludeHidden
- ** bit set.
- */
- if( (p->selFlags & SF_IncludeHidden)==0
- && IsHiddenColumn(&pTab->aCol[j])
- ){
- continue;
- }
- if( (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0
- && zTName==0
- && (selFlags & (SF_NestedFrom))==0
- ){
- continue;
+ /* If pTab is actually an SF_NestedFrom sub-select, do not
+ ** expand any ENAME_ROWID columns. */
+ if( pNestedFrom && pNestedFrom->a[j].fg.eEName==ENAME_ROWID ){
+ continue;
+ }
+
+ if( zTName
+ && pNestedFrom
+ && sqlite3MatchEName(&pNestedFrom->a[j], 0, zTName, 0, 0)==0
+ ){
+ continue;
+ }
+
+ /* If a column is marked as 'hidden', omit it from the expanded
+ ** result-set list unless the SELECT has the SF_IncludeHidden
+ ** bit set.
+ */
+ if( (p->selFlags & SF_IncludeHidden)==0
+ && IsHiddenColumn(&pTab->aCol[j])
+ ){
+ continue;
+ }
+ if( (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0
+ && zTName==0
+ && (selFlags & (SF_NestedFrom))==0
+ ){
+ continue;
+ }
}
+ assert( zName );
tableSeen = 1;
if( i>0 && zTName==0 && (selFlags & SF_NestedFrom)==0 ){
@@ -144381,6 +148190,7 @@ static int selectExpander(Walker *pWalker, Select *p){
}else{
pExpr = pRight;
}
+ sqlite3ExprSetErrorOffset(pExpr, iErrOfst);
pNew = sqlite3ExprListAppend(pParse, pNew, pExpr);
if( pNew==0 ){
break; /* OOM */
@@ -144388,7 +148198,8 @@ static int selectExpander(Walker *pWalker, Select *p){
pX = &pNew->a[pNew->nExpr-1];
assert( pX->zEName==0 );
if( (selFlags & SF_NestedFrom)!=0 && !IN_RENAME_OBJECT ){
- if( pNestedFrom ){
+ if( pNestedFrom && (!ViewCanHaveRowid || j<pNestedFrom->nExpr) ){
+ assert( j<pNestedFrom->nExpr );
pX->zEName = sqlite3DbStrDup(db, pNestedFrom->a[j].zEName);
testcase( pX->zEName==0 );
}else{
@@ -144396,11 +148207,11 @@ static int selectExpander(Walker *pWalker, Select *p){
zSchemaName, zTabName, zName);
testcase( pX->zEName==0 );
}
- pX->fg.eEName = ENAME_TAB;
+ pX->fg.eEName = (j==pTab->nCol ? ENAME_ROWID : ENAME_TAB);
if( (pFrom->fg.isUsing
&& sqlite3IdListIndex(pFrom->u3.pUsing, zName)>=0)
|| (pUsing && sqlite3IdListIndex(pUsing, zName)>=0)
- || (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND)!=0
+ || (j<pTab->nCol && (pTab->aCol[j].colFlags & COLFLAG_NOEXPAND))
){
pX->fg.bNoExpand = 1;
}
@@ -144502,10 +148313,11 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){
SrcList *pTabList;
SrcItem *pFrom;
- assert( p->selFlags & SF_Resolved );
if( p->selFlags & SF_HasTypeInfo ) return;
p->selFlags |= SF_HasTypeInfo;
pParse = pWalker->pParse;
+ testcase( (p->selFlags & SF_Resolved)==0 );
+ assert( (p->selFlags & SF_Resolved) || IN_RENAME_OBJECT );
pTabList = p->pSrc;
for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){
Table *pTab = pFrom->pTab;
@@ -144621,8 +148433,14 @@ static void analyzeAggFuncArgs(
pNC->ncFlags |= NC_InAggFunc;
for(i=0; i<pAggInfo->nFunc; i++){
Expr *pExpr = pAggInfo->aFunc[i].pFExpr;
+ assert( pExpr->op==TK_FUNCTION || pExpr->op==TK_AGG_FUNCTION );
assert( ExprUseXList(pExpr) );
sqlite3ExprAnalyzeAggList(pNC, pExpr->x.pList);
+ if( pExpr->pLeft ){
+ assert( pExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pExpr->pLeft) );
+ sqlite3ExprAnalyzeAggList(pNC, pExpr->pLeft->x.pList);
+ }
#ifndef SQLITE_OMIT_WINDOWFUNC
assert( !IsWindowFunc(pExpr) );
if( ExprHasProperty(pExpr, EP_WinFunc) ){
@@ -144651,12 +148469,13 @@ static void optimizeAggregateUseOfIndexedExpr(
assert( pSelect->pGroupBy!=0 );
pAggInfo->nColumn = pAggInfo->nAccumulator;
if( ALWAYS(pAggInfo->nSortingColumn>0) ){
- if( pAggInfo->nColumn==0 ){
- pAggInfo->nSortingColumn = pSelect->pGroupBy->nExpr;
- }else{
- pAggInfo->nSortingColumn =
- pAggInfo->aCol[pAggInfo->nColumn-1].iSorterColumn+1;
+ int mx = pSelect->pGroupBy->nExpr - 1;
+ int j, k;
+ for(j=0; j<pAggInfo->nColumn; j++){
+ k = pAggInfo->aCol[j].iSorterColumn;
+ if( k>mx ) mx = k;
}
+ pAggInfo->nSortingColumn = mx+1;
}
analyzeAggFuncArgs(pAggInfo, pNC);
#if TREETRACE_ENABLED
@@ -144690,11 +148509,13 @@ static int aggregateIdxEprRefToColCallback(Walker *pWalker, Expr *pExpr){
if( pExpr->op==TK_AGG_FUNCTION ) return WRC_Continue;
if( pExpr->op==TK_IF_NULL_ROW ) return WRC_Continue;
pAggInfo = pExpr->pAggInfo;
- assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
+ if( NEVER(pExpr->iAgg>=pAggInfo->nColumn) ) return WRC_Continue;
+ assert( pExpr->iAgg>=0 );
pCol = &pAggInfo->aCol[pExpr->iAgg];
pExpr->op = TK_AGG_COLUMN;
pExpr->iTable = pCol->iTable;
pExpr->iColumn = pCol->iColumn;
+ ExprClearProperty(pExpr, EP_Skip|EP_Collate|EP_Unlikely);
return WRC_Prune;
}
@@ -144725,7 +148546,7 @@ static void aggregateConvertIndexedExprRefToColumn(AggInfo *pAggInfo){
** * The aCol[] and aFunc[] arrays may be modified
** * The AggInfoColumnReg() and AggInfoFuncReg() macros may not be used
**
-** After clling this routine:
+** After calling this routine:
**
** * The aCol[] and aFunc[] arrays are fixed
** * The AggInfoColumnReg() and AggInfoFuncReg() macros may be used
@@ -144774,6 +148595,36 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){
pFunc->pFunc->zName));
}
}
+ if( pFunc->iOBTab>=0 ){
+ ExprList *pOBList;
+ KeyInfo *pKeyInfo;
+ int nExtra = 0;
+ assert( pFunc->pFExpr->pLeft!=0 );
+ assert( pFunc->pFExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pFunc->pFExpr->pLeft) );
+ assert( pFunc->pFunc!=0 );
+ pOBList = pFunc->pFExpr->pLeft->x.pList;
+ if( !pFunc->bOBUnique ){
+ nExtra++; /* One extra column for the OP_Sequence */
+ }
+ if( pFunc->bOBPayload ){
+ /* extra columns for the function arguments */
+ assert( ExprUseXList(pFunc->pFExpr) );
+ nExtra += pFunc->pFExpr->x.pList->nExpr;
+ }
+ if( pFunc->bUseSubtype ){
+ nExtra += pFunc->pFExpr->x.pList->nExpr;
+ }
+ pKeyInfo = sqlite3KeyInfoFromExprList(pParse, pOBList, 0, nExtra);
+ if( !pFunc->bOBUnique && pParse->nErr==0 ){
+ pKeyInfo->nKeyField++;
+ }
+ sqlite3VdbeAddOp4(v, OP_OpenEphemeral,
+ pFunc->iOBTab, pOBList->nExpr+nExtra, 0,
+ (char*)pKeyInfo, P4_KEYINFO);
+ ExplainQueryPlan((pParse, 0, "USE TEMP B-TREE FOR %s(ORDER BY)",
+ pFunc->pFunc->zName));
+ }
}
}
@@ -144789,13 +148640,56 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
ExprList *pList;
assert( ExprUseXList(pF->pFExpr) );
pList = pF->pFExpr->x.pList;
+ if( pF->iOBTab>=0 ){
+ /* For an ORDER BY aggregate, calls to OP_AggStep were deferred. Inputs
+ ** were stored in emphermal table pF->iOBTab. Here, we extract those
+ ** inputs (in ORDER BY order) and make all calls to OP_AggStep
+ ** before doing the OP_AggFinal call. */
+ int iTop; /* Start of loop for extracting columns */
+ int nArg; /* Number of columns to extract */
+ int nKey; /* Key columns to be skipped */
+ int regAgg; /* Extract into this array */
+ int j; /* Loop counter */
+
+ assert( pF->pFunc!=0 );
+ nArg = pList->nExpr;
+ regAgg = sqlite3GetTempRange(pParse, nArg);
+
+ if( pF->bOBPayload==0 ){
+ nKey = 0;
+ }else{
+ assert( pF->pFExpr->pLeft!=0 );
+ assert( ExprUseXList(pF->pFExpr->pLeft) );
+ assert( pF->pFExpr->pLeft->x.pList!=0 );
+ nKey = pF->pFExpr->pLeft->x.pList->nExpr;
+ if( ALWAYS(!pF->bOBUnique) ) nKey++;
+ }
+ iTop = sqlite3VdbeAddOp1(v, OP_Rewind, pF->iOBTab); VdbeCoverage(v);
+ for(j=nArg-1; j>=0; j--){
+ sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, nKey+j, regAgg+j);
+ }
+ if( pF->bUseSubtype ){
+ int regSubtype = sqlite3GetTempReg(pParse);
+ int iBaseCol = nKey + nArg + (pF->bOBPayload==0 && pF->bOBUnique==0);
+ for(j=nArg-1; j>=0; j--){
+ sqlite3VdbeAddOp3(v, OP_Column, pF->iOBTab, iBaseCol+j, regSubtype);
+ sqlite3VdbeAddOp2(v, OP_SetSubtype, regSubtype, regAgg+j);
+ }
+ sqlite3ReleaseTempReg(pParse, regSubtype);
+ }
+ sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i));
+ sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
+ sqlite3VdbeChangeP5(v, (u8)nArg);
+ sqlite3VdbeAddOp2(v, OP_Next, pF->iOBTab, iTop+1); VdbeCoverage(v);
+ sqlite3VdbeJumpHere(v, iTop);
+ sqlite3ReleaseTempRange(pParse, regAgg, nArg);
+ }
sqlite3VdbeAddOp2(v, OP_AggFinal, AggInfoFuncReg(pAggInfo,i),
pList ? pList->nExpr : 0);
sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
}
}
-
/*
** Generate code that will update the accumulator memory cells for an
** aggregate based on the current cursor position.
@@ -144804,6 +148698,13 @@ static void finalizeAggFunctions(Parse *pParse, AggInfo *pAggInfo){
** in pAggInfo, then only populate the pAggInfo->nAccumulator accumulator
** registers if register regAcc contains 0. The caller will take care
** of setting and clearing regAcc.
+**
+** For an ORDER BY aggregate, the actual accumulator memory cell update
+** is deferred until after all input rows have been received, so that they
+** can be run in the requested order. In that case, instead of invoking
+** OP_AggStep to update the accumulator, just add the arguments that would
+** have been passed into OP_AggStep into the sorting ephemeral table
+** (along with the appropriate sort key).
*/
static void updateAccumulator(
Parse *pParse,
@@ -144825,9 +148726,12 @@ static void updateAccumulator(
int nArg;
int addrNext = 0;
int regAgg;
+ int regAggSz = 0;
+ int regDistinct = 0;
ExprList *pList;
assert( ExprUseXList(pF->pFExpr) );
assert( !IsWindowFunc(pF->pFExpr) );
+ assert( pF->pFunc!=0 );
pList = pF->pFExpr->x.pList;
if( ExprHasProperty(pF->pFExpr, EP_WinFunc) ){
Expr *pFilter = pF->pFExpr->y.pWin->pFilter;
@@ -144851,9 +148755,55 @@ static void updateAccumulator(
addrNext = sqlite3VdbeMakeLabel(pParse);
sqlite3ExprIfFalse(pParse, pFilter, addrNext, SQLITE_JUMPIFNULL);
}
- if( pList ){
+ if( pF->iOBTab>=0 ){
+ /* Instead of invoking AggStep, we must push the arguments that would
+ ** have been passed to AggStep onto the sorting table. */
+ int jj; /* Registered used so far in building the record */
+ ExprList *pOBList; /* The ORDER BY clause */
+ assert( pList!=0 );
+ nArg = pList->nExpr;
+ assert( nArg>0 );
+ assert( pF->pFExpr->pLeft!=0 );
+ assert( pF->pFExpr->pLeft->op==TK_ORDER );
+ assert( ExprUseXList(pF->pFExpr->pLeft) );
+ pOBList = pF->pFExpr->pLeft->x.pList;
+ assert( pOBList!=0 );
+ assert( pOBList->nExpr>0 );
+ regAggSz = pOBList->nExpr;
+ if( !pF->bOBUnique ){
+ regAggSz++; /* One register for OP_Sequence */
+ }
+ if( pF->bOBPayload ){
+ regAggSz += nArg;
+ }
+ if( pF->bUseSubtype ){
+ regAggSz += nArg;
+ }
+ regAggSz++; /* One extra register to hold result of MakeRecord */
+ regAgg = sqlite3GetTempRange(pParse, regAggSz);
+ regDistinct = regAgg;
+ sqlite3ExprCodeExprList(pParse, pOBList, regAgg, 0, SQLITE_ECEL_DUP);
+ jj = pOBList->nExpr;
+ if( !pF->bOBUnique ){
+ sqlite3VdbeAddOp2(v, OP_Sequence, pF->iOBTab, regAgg+jj);
+ jj++;
+ }
+ if( pF->bOBPayload ){
+ regDistinct = regAgg+jj;
+ sqlite3ExprCodeExprList(pParse, pList, regDistinct, 0, SQLITE_ECEL_DUP);
+ jj += nArg;
+ }
+ if( pF->bUseSubtype ){
+ int kk;
+ int regBase = pF->bOBPayload ? regDistinct : regAgg;
+ for(kk=0; kk<nArg; kk++, jj++){
+ sqlite3VdbeAddOp2(v, OP_GetSubtype, regBase+kk, regAgg+jj);
+ }
+ }
+ }else if( pList ){
nArg = pList->nExpr;
regAgg = sqlite3GetTempRange(pParse, nArg);
+ regDistinct = regAgg;
sqlite3ExprCodeExprList(pParse, pList, regAgg, 0, SQLITE_ECEL_DUP);
}else{
nArg = 0;
@@ -144864,26 +148814,37 @@ static void updateAccumulator(
addrNext = sqlite3VdbeMakeLabel(pParse);
}
pF->iDistinct = codeDistinct(pParse, eDistinctType,
- pF->iDistinct, addrNext, pList, regAgg);
- }
- if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
- CollSeq *pColl = 0;
- struct ExprList_item *pItem;
- int j;
- assert( pList!=0 ); /* pList!=0 if pF->pFunc has NEEDCOLL */
- for(j=0, pItem=pList->a; !pColl && j<nArg; j++, pItem++){
- pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
- }
- if( !pColl ){
- pColl = pParse->db->pDfltColl;
+ pF->iDistinct, addrNext, pList, regDistinct);
+ }
+ if( pF->iOBTab>=0 ){
+ /* Insert a new record into the ORDER BY table */
+ sqlite3VdbeAddOp3(v, OP_MakeRecord, regAgg, regAggSz-1,
+ regAgg+regAggSz-1);
+ sqlite3VdbeAddOp4Int(v, OP_IdxInsert, pF->iOBTab, regAgg+regAggSz-1,
+ regAgg, regAggSz-1);
+ sqlite3ReleaseTempRange(pParse, regAgg, regAggSz);
+ }else{
+ /* Invoke the AggStep function */
+ if( pF->pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL ){
+ CollSeq *pColl = 0;
+ struct ExprList_item *pItem;
+ int j;
+ assert( pList!=0 ); /* pList!=0 if pF->pFunc has NEEDCOLL */
+ for(j=0, pItem=pList->a; !pColl && j<nArg; j++, pItem++){
+ pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
+ }
+ if( !pColl ){
+ pColl = pParse->db->pDfltColl;
+ }
+ if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
+ sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0,
+ (char *)pColl, P4_COLLSEQ);
}
- if( regHit==0 && pAggInfo->nAccumulator ) regHit = ++pParse->nMem;
- sqlite3VdbeAddOp4(v, OP_CollSeq, regHit, 0, 0, (char *)pColl, P4_COLLSEQ);
+ sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i));
+ sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
+ sqlite3VdbeChangeP5(v, (u8)nArg);
+ sqlite3ReleaseTempRange(pParse, regAgg, nArg);
}
- sqlite3VdbeAddOp3(v, OP_AggStep, 0, regAgg, AggInfoFuncReg(pAggInfo,i));
- sqlite3VdbeAppendP4(v, pF->pFunc, P4_FUNCDEF);
- sqlite3VdbeChangeP5(v, (u8)nArg);
- sqlite3ReleaseTempRange(pParse, regAgg, nArg);
if( addrNext ){
sqlite3VdbeResolveLabel(v, addrNext);
}
@@ -145042,13 +149003,13 @@ static SrcItem *isSelfJoinView(
/*
** Deallocate a single AggInfo object
*/
-static void agginfoFree(sqlite3 *db, AggInfo *p){
+static void agginfoFree(sqlite3 *db, void *pArg){
+ AggInfo *p = (AggInfo*)pArg;
sqlite3DbFree(db, p->aCol);
sqlite3DbFree(db, p->aFunc);
sqlite3DbFreeNN(db, p);
}
-#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
/*
** Attempt to transform a query of the form
**
@@ -145076,6 +149037,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */
if( p->pEList->nExpr!=1 ) return 0; /* Single result column */
if( p->pWhere ) return 0;
+ if( p->pHaving ) return 0;
if( p->pGroupBy ) return 0;
if( p->pOrderBy ) return 0;
pExpr = p->pEList->a[0].pExpr;
@@ -145095,7 +149057,8 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
if( pSub->pWhere ) return 0; /* No WHERE clause */
if( pSub->pLimit ) return 0; /* No LIMIT clause */
if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */
- pSub = pSub->pPrior; /* Repeat over compound */
+ assert( pSub->pHaving==0 ); /* Due to the previous */
+ pSub = pSub->pPrior; /* Repeat over compound */
}while( pSub );
/* If we reach this point then it is OK to perform the transformation */
@@ -145115,7 +149078,7 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
pSub->selFlags |= SF_Aggregate;
pSub->selFlags &= ~SF_Compound;
pSub->nSelectRow = 0;
- sqlite3ExprListDelete(db, pSub->pEList);
+ sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric, pSub->pEList);
pTerm = pPrior ? sqlite3ExprDup(db, pCount, 0) : pCount;
pSub->pEList = sqlite3ExprListAppend(pParse, 0, pTerm);
pTerm = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
@@ -145138,7 +149101,6 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
#endif
return 1;
}
-#endif /* SQLITE_COUNTOFVIEW_OPTIMIZATION */
/*
** If any term of pSrc, or any SF_NestedFrom sub-query, is not the same
@@ -145296,9 +149258,8 @@ SQLITE_PRIVATE int sqlite3Select(
sqlite3TreeViewExprList(0, p->pOrderBy, 0, "ORDERBY");
}
#endif
- sqlite3ParserAddCleanup(pParse,
- (void(*)(sqlite3*,void*))sqlite3ExprListDelete,
- p->pOrderBy);
+ sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric,
+ p->pOrderBy);
testcase( pParse->earlyCleanup );
p->pOrderBy = 0;
}
@@ -145379,22 +149340,58 @@ SQLITE_PRIVATE int sqlite3Select(
** to a real table */
assert( pTab!=0 );
- /* Convert LEFT JOIN into JOIN if there are terms of the right table
- ** of the LEFT JOIN used in the WHERE clause.
+ /* Try to simplify joins:
+ **
+ ** LEFT JOIN -> JOIN
+ ** RIGHT JOIN -> JOIN
+ ** FULL JOIN -> RIGHT JOIN
+ **
+ ** If terms of the i-th table are used in the WHERE clause in such a
+ ** way that the i-th table cannot be the NULL row of a join, then
+ ** perform the appropriate simplification. This is called
+ ** "OUTER JOIN strength reduction" in the SQLite documentation.
*/
- if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==JT_LEFT
- && sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor)
+ if( (pItem->fg.jointype & (JT_LEFT|JT_LTORJ))!=0
+ && sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor,
+ pItem->fg.jointype & JT_LTORJ)
&& OptimizationEnabled(db, SQLITE_SimplifyJoin)
){
- TREETRACE(0x1000,pParse,p,
- ("LEFT-JOIN simplifies to JOIN on term %d\n",i));
- pItem->fg.jointype &= ~(JT_LEFT|JT_OUTER);
- assert( pItem->iCursor>=0 );
- unsetJoinExpr(p->pWhere, pItem->iCursor,
- pTabList->a[0].fg.jointype & JT_LTORJ);
+ if( pItem->fg.jointype & JT_LEFT ){
+ if( pItem->fg.jointype & JT_RIGHT ){
+ TREETRACE(0x1000,pParse,p,
+ ("FULL-JOIN simplifies to RIGHT-JOIN on term %d\n",i));
+ pItem->fg.jointype &= ~JT_LEFT;
+ }else{
+ TREETRACE(0x1000,pParse,p,
+ ("LEFT-JOIN simplifies to JOIN on term %d\n",i));
+ pItem->fg.jointype &= ~(JT_LEFT|JT_OUTER);
+ unsetJoinExpr(p->pWhere, pItem->iCursor, 0);
+ }
+ }
+ if( pItem->fg.jointype & JT_LTORJ ){
+ for(j=i+1; j<pTabList->nSrc; j++){
+ SrcItem *pI2 = &pTabList->a[j];
+ if( pI2->fg.jointype & JT_RIGHT ){
+ if( pI2->fg.jointype & JT_LEFT ){
+ TREETRACE(0x1000,pParse,p,
+ ("FULL-JOIN simplifies to LEFT-JOIN on term %d\n",j));
+ pI2->fg.jointype &= ~JT_RIGHT;
+ }else{
+ TREETRACE(0x1000,pParse,p,
+ ("RIGHT-JOIN simplifies to JOIN on term %d\n",j));
+ pI2->fg.jointype &= ~(JT_RIGHT|JT_OUTER);
+ unsetJoinExpr(p->pWhere, pI2->iCursor, 1);
+ }
+ }
+ }
+ for(j=pTabList->nSrc-1; j>=0; j--){
+ pTabList->a[j].fg.jointype &= ~JT_LTORJ;
+ if( pTabList->a[j].fg.jointype & JT_RIGHT ) break;
+ }
+ }
}
- /* No futher action if this term of the FROM clause is no a subquery */
+ /* No further action if this term of the FROM clause is not a subquery */
if( pSub==0 ) continue;
/* Catch mismatch in the declared columns of a view and the number of
@@ -145405,6 +149402,14 @@ SQLITE_PRIVATE int sqlite3Select(
goto select_end;
}
+ /* Do not attempt the usual optimizations (flattening and ORDER BY
+ ** elimination) on a MATERIALIZED common table expression because
+ ** a MATERIALIZED common table expression is an optimization fence.
+ */
+ if( pItem->fg.isCte && pItem->u2.pCteUse->eM10d==M10d_Yes ){
+ continue;
+ }
+
/* Do not try to flatten an aggregate subquery.
**
** Flattening an aggregate subquery is only possible if the outer query
@@ -145434,6 +149439,8 @@ SQLITE_PRIVATE int sqlite3Select(
** (a) The outer query has a different ORDER BY clause
** (b) The subquery is part of a join
** See forum post 062d576715d277c8
+ **
+ ** Also retain the ORDER BY if the OmitOrderBy optimization is disabled.
*/
if( pSub->pOrderBy!=0
&& (p->pOrderBy!=0 || pTabList->nSrc>1) /* Condition (5) */
@@ -145444,9 +149451,8 @@ SQLITE_PRIVATE int sqlite3Select(
){
TREETRACE(0x800,pParse,p,
("omit superfluous ORDER BY on %r FROM-clause subquery\n",i+1));
- sqlite3ParserAddCleanup(pParse,
- (void(*)(sqlite3*,void*))sqlite3ExprListDelete,
- pSub->pOrderBy);
+ sqlite3ParserAddCleanup(pParse, sqlite3ExprListDeleteGeneric,
+ pSub->pOrderBy);
pSub->pOrderBy = 0;
}
@@ -145527,14 +149533,12 @@ SQLITE_PRIVATE int sqlite3Select(
TREETRACE(0x2000,pParse,p,("Constant propagation not helpful\n"));
}
-#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView)
&& countOfViewOptimization(pParse, p)
){
if( db->mallocFailed ) goto select_end;
pTabList = p->pSrc;
}
-#endif
/* For each term in the FROM clause, do two things:
** (1) Authorized unreferenced tables
@@ -145593,7 +149597,7 @@ SQLITE_PRIVATE int sqlite3Select(
if( OptimizationEnabled(db, SQLITE_PushDown)
&& (pItem->fg.isCte==0
|| (pItem->u2.pCteUse->eM10d!=M10d_Yes && pItem->u2.pCteUse->nUse<2))
- && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem)
+ && pushDownWhereTerms(pParse, pSub, p->pWhere, pTabList, i)
){
#if TREETRACE_ENABLED
if( sqlite3TreeTrace & 0x4000 ){
@@ -145607,6 +149611,22 @@ SQLITE_PRIVATE int sqlite3Select(
TREETRACE(0x4000,pParse,p,("Push-down not possible\n"));
}
+ /* Convert unused result columns of the subquery into simple NULL
+ ** expressions, to avoid unneeded searching and computation.
+ */
+ if( OptimizationEnabled(db, SQLITE_NullUnusedCols)
+ && disableUnusedSubqueryResultColumns(pItem)
+ ){
+#if TREETRACE_ENABLED
+ if( sqlite3TreeTrace & 0x4000 ){
+ TREETRACE(0x4000,pParse,p,
+ ("Change unused result columns to NULL for subquery %d:\n",
+ pSub->selId));
+ sqlite3TreeViewSelect(0, p, 0);
+ }
+#endif
+ }
+
zSavedAuthContext = pParse->zAuthContext;
pParse->zAuthContext = pItem->zName;
@@ -145634,7 +149654,7 @@ SQLITE_PRIVATE int sqlite3Select(
}else if( pItem->fg.isCte && pItem->u2.pCteUse->addrM9e>0 ){
/* This is a CTE for which materialization code has already been
** generated. Invoke the subroutine to compute the materialization,
- ** the make the pItem->iCursor be a copy of the ephemerial table that
+ ** the make the pItem->iCursor be a copy of the ephemeral table that
** holds the result of the materialization. */
CteUse *pCteUse = pItem->u2.pCteUse;
sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e);
@@ -145961,8 +149981,7 @@ SQLITE_PRIVATE int sqlite3Select(
*/
pAggInfo = sqlite3DbMallocZero(db, sizeof(*pAggInfo) );
if( pAggInfo ){
- sqlite3ParserAddCleanup(pParse,
- (void(*)(sqlite3*,void*))agginfoFree, pAggInfo);
+ sqlite3ParserAddCleanup(pParse, agginfoFree, pAggInfo);
testcase( pParse->earlyCleanup );
}
if( db->mallocFailed ){
@@ -146017,7 +150036,7 @@ SQLITE_PRIVATE int sqlite3Select(
*/
if( pGroupBy ){
KeyInfo *pKeyInfo; /* Keying information for the group by clause */
- int addr1; /* A-vs-B comparision jump */
+ int addr1; /* A-vs-B comparison jump */
int addrOutputRow; /* Start of subroutine that outputs a result row */
int regOutputRow; /* Return address register for output subroutine */
int addrSetAbort; /* Set the abort flag and return */
@@ -146108,9 +150127,13 @@ SQLITE_PRIVATE int sqlite3Select(
int nCol;
int nGroupBy;
- explainTempTable(pParse,
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+ int addrExp; /* Address of OP_Explain instruction */
+#endif
+ ExplainQueryPlan2(addrExp, (pParse, 0, "USE TEMP B-TREE FOR %s",
(sDistinct.isTnct && (p->selFlags&SF_Distinct)==0) ?
- "DISTINCT" : "GROUP BY");
+ "DISTINCT" : "GROUP BY"
+ ));
groupBySort = 1;
nGroupBy = pGroupBy->nExpr;
@@ -146135,18 +150158,23 @@ SQLITE_PRIVATE int sqlite3Select(
}
pAggInfo->directMode = 0;
regRecord = sqlite3GetTempReg(pParse);
+ sqlite3VdbeScanStatusCounters(v, addrExp, 0, sqlite3VdbeCurrentAddr(v));
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord);
sqlite3VdbeAddOp2(v, OP_SorterInsert, pAggInfo->sortingIdx, regRecord);
+ sqlite3VdbeScanStatusRange(v, addrExp, sqlite3VdbeCurrentAddr(v)-2, -1);
sqlite3ReleaseTempReg(pParse, regRecord);
sqlite3ReleaseTempRange(pParse, regBase, nCol);
TREETRACE(0x2,pParse,p,("WhereEnd\n"));
sqlite3WhereEnd(pWInfo);
pAggInfo->sortingIdxPTab = sortPTab = pParse->nTab++;
sortOut = sqlite3GetTempReg(pParse);
+ sqlite3VdbeScanStatusCounters(v, addrExp, sqlite3VdbeCurrentAddr(v), 0);
sqlite3VdbeAddOp3(v, OP_OpenPseudo, sortPTab, sortOut, nCol);
sqlite3VdbeAddOp2(v, OP_SorterSort, pAggInfo->sortingIdx, addrEnd);
VdbeComment((v, "GROUP BY sort")); VdbeCoverage(v);
pAggInfo->useSortingIdx = 1;
+ sqlite3VdbeScanStatusRange(v, addrExp, -1, sortPTab);
+ sqlite3VdbeScanStatusRange(v, addrExp, -1, pAggInfo->sortingIdx);
}
/* If there are entries in pAgggInfo->aFunc[] that contain subexpressions
@@ -146874,6 +150902,10 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables");
goto trigger_orphan_error;
}
+ if( (pTab->tabFlags & TF_Shadow)!=0 && sqlite3ReadOnlyShadowTables(db) ){
+ sqlite3ErrorMsg(pParse, "cannot create triggers on shadow tables");
+ goto trigger_orphan_error;
+ }
/* Check that the trigger name is not reserved and that no trigger of the
** specified name exists */
@@ -146893,6 +150925,7 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
}else{
assert( !db->init.busy );
sqlite3CodeVerifySchema(pParse, iDb);
+ VVA_ONLY( pParse->ifNotExists = 1; )
}
goto trigger_cleanup;
}
@@ -147656,10 +151689,17 @@ static void codeReturningTrigger(
SrcList sFrom;
assert( v!=0 );
- assert( pParse->bReturning );
+ if( !pParse->bReturning ){
+ /* This RETURNING trigger must be for a different statement as
+ ** this statement lacks a RETURNING clause. */
+ return;
+ }
assert( db->pParse==pParse );
pReturning = pParse->u1.pReturning;
- assert( pTrigger == &(pReturning->retTrig) );
+ if( pTrigger != &(pReturning->retTrig) ){
+ /* This RETURNING trigger is for a different statement */
+ return;
+ }
memset(&sSelect, 0, sizeof(sSelect));
memset(&sFrom, 0, sizeof(sFrom));
sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0);
@@ -148143,6 +152183,9 @@ SQLITE_PRIVATE u32 sqlite3TriggerColmask(
Trigger *p;
assert( isNew==1 || isNew==0 );
+ if( IsView(pTab) ){
+ return 0xffffffff;
+ }
for(p=pTrigger; p; p=p->pNext){
if( p->op==op
&& (tr_tm&p->tr_tm)
@@ -148393,7 +152436,7 @@ static void updateFromSelect(
assert( pTabList->nSrc>1 );
if( pSrc ){
- pSrc->a[0].fg.notCte = 1;
+ assert( pSrc->a[0].fg.notCte );
pSrc->a[0].iCursor = -1;
pSrc->a[0].pTab->nTabRef--;
pSrc->a[0].pTab = 0;
@@ -148577,7 +152620,7 @@ SQLITE_PRIVATE void sqlite3Update(
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto update_cleanup;
}
- if( sqlite3IsReadOnly(pParse, pTab, tmask) ){
+ if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){
goto update_cleanup;
}
@@ -148896,12 +152939,22 @@ SQLITE_PRIVATE void sqlite3Update(
/* Begin the database scan.
**
** Do not consider a single-pass strategy for a multi-row update if
- ** there are any triggers or foreign keys to process, or rows may
- ** be deleted as a result of REPLACE conflict handling. Any of these
- ** things might disturb a cursor being used to scan through the table
- ** or index, causing a single-pass approach to malfunction. */
+ ** there is anything that might disrupt the cursor being used to do
+ ** the UPDATE:
+ ** (1) This is a nested UPDATE
+ ** (2) There are triggers
+ ** (3) There are FOREIGN KEY constraints
+ ** (4) There are REPLACE conflict handlers
+ ** (5) There are subqueries in the WHERE clause
+ */
flags = WHERE_ONEPASS_DESIRED;
- if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){
+ if( !pParse->nested
+ && !pTrigger
+ && !hasFK
+ && !chngKey
+ && !bReplace
+ && (pWhere==0 || !ExprHasProperty(pWhere, EP_Subquery))
+ ){
flags |= WHERE_ONEPASS_MULTIROW;
}
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0,0,0,flags,iIdxCur);
@@ -148972,6 +153025,8 @@ SQLITE_PRIVATE void sqlite3Update(
if( !isView ){
int addrOnce = 0;
+ int iNotUsed1 = 0;
+ int iNotUsed2 = 0;
/* Open every index that needs updating. */
if( eOnePass!=ONEPASS_OFF ){
@@ -148983,7 +153038,7 @@ SQLITE_PRIVATE void sqlite3Update(
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
}
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur,
- aToOpen, 0, 0);
+ aToOpen, &iNotUsed1, &iNotUsed2);
if( addrOnce ){
sqlite3VdbeJumpHereOrPopInst(v, addrOnce);
}
@@ -149078,6 +153133,9 @@ SQLITE_PRIVATE void sqlite3Update(
}
}
if( chngRowid==0 && pPk==0 ){
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ if( isView ) sqlite3VdbeAddOp2(v, OP_Null, 0, regOldRowid);
+#endif
sqlite3VdbeAddOp2(v, OP_Copy, regOldRowid, regNewRowid);
}
}
@@ -149274,8 +153332,10 @@ SQLITE_PRIVATE void sqlite3Update(
sqlite3VdbeAddOp2(v, OP_AddImm, regRowCount, 1);
}
- sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
- TRIGGER_AFTER, pTab, regOldRowid, onError, labelContinue);
+ if( pTrigger ){
+ sqlite3CodeRowTrigger(pParse, pTrigger, TK_UPDATE, pChanges,
+ TRIGGER_AFTER, pTab, regOldRowid, onError, labelContinue);
+ }
/* Repeat the above with the next record to be updated, until
** all record selected by the WHERE clause have been updated.
@@ -149370,7 +153430,7 @@ static void updateVirtualTable(
int nArg = 2 + pTab->nCol; /* Number of arguments to VUpdate */
int regArg; /* First register in VUpdate arg array */
int regRec; /* Register in which to assemble record */
- int regRowid; /* Register for ephem table rowid */
+ int regRowid; /* Register for ephemeral table rowid */
int iCsr = pSrc->a[0].iCursor; /* Cursor used for virtual table scan */
int aDummy[2]; /* Unused arg for sqlite3WhereOkOnePass() */
int eOnePass; /* True to use onepass strategy */
@@ -149414,7 +153474,9 @@ static void updateVirtualTable(
sqlite3ExprDup(db, pChanges->a[aXRef[i]].pExpr, 0)
);
}else{
- pList = sqlite3ExprListAppend(pParse, pList, exprRowColumn(pParse, i));
+ Expr *pRowExpr = exprRowColumn(pParse, i);
+ if( pRowExpr ) pRowExpr->op2 = OPFLAG_NOCHNG;
+ pList = sqlite3ExprListAppend(pParse, pList, pRowExpr);
}
}
@@ -149491,7 +153553,7 @@ static void updateVirtualTable(
sqlite3WhereEnd(pWInfo);
}
- /* Begin scannning through the ephemeral table. */
+ /* Begin scanning through the ephemeral table. */
addr = sqlite3VdbeAddOp1(v, OP_Rewind, ephemTab); VdbeCoverage(v);
/* Extract arguments from the current row of the ephemeral table and
@@ -149611,7 +153673,8 @@ SQLITE_PRIVATE Upsert *sqlite3UpsertNew(
SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(
Parse *pParse, /* The parsing context */
SrcList *pTabList, /* Table into which we are inserting */
- Upsert *pUpsert /* The ON CONFLICT clauses */
+ Upsert *pUpsert, /* The ON CONFLICT clauses */
+ Upsert *pAll /* Complete list of all ON CONFLICT clauses */
){
Table *pTab; /* That table into which we are inserting */
int rc; /* Result code */
@@ -149699,7 +153762,7 @@ SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(
pExpr = &sCol[0];
}
for(jj=0; jj<nn; jj++){
- if( sqlite3ExprCompare(pParse,pTarget->a[jj].pExpr,pExpr,iCursor)<2 ){
+ if( sqlite3ExprCompare(0,pTarget->a[jj].pExpr,pExpr,iCursor)<2 ){
break; /* Column ii of the index matches column jj of target */
}
}
@@ -149714,6 +153777,14 @@ SQLITE_PRIVATE int sqlite3UpsertAnalyzeTarget(
continue;
}
pUpsert->pUpsertIdx = pIdx;
+ if( sqlite3UpsertOfIndex(pAll,pIdx)!=pUpsert ){
+ /* Really this should be an error. The isDup ON CONFLICT clause will
+ ** never fire. But this problem was not discovered until three years
+ ** after multi-CONFLICT upsert was added, and so we silently ignore
+ ** the problem to prevent breaking applications that might actually
+ ** have redundant ON CONFLICT clauses. */
+ pUpsert->isDup = 1;
+ }
break;
}
if( pUpsert->pUpsertIdx==0 ){
@@ -149740,9 +153811,13 @@ SQLITE_PRIVATE int sqlite3UpsertNextIsIPK(Upsert *pUpsert){
Upsert *pNext;
if( NEVER(pUpsert==0) ) return 0;
pNext = pUpsert->pNextUpsert;
- if( pNext==0 ) return 1;
- if( pNext->pUpsertTarget==0 ) return 1;
- if( pNext->pUpsertIdx==0 ) return 1;
+ while( 1 /*exit-by-return*/ ){
+ if( pNext==0 ) return 1;
+ if( pNext->pUpsertTarget==0 ) return 1;
+ if( pNext->pUpsertIdx==0 ) return 1;
+ if( !pNext->isDup ) return 0;
+ pNext = pNext->pNextUpsert;
+ }
return 0;
}
@@ -150048,7 +154123,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE int sqlite3RunVacuum(
** (possibly synchronous) transaction opened on the main database before
** sqlite3BtreeCopyFile() is called.
**
- ** An optimisation would be to use a non-journaled pager.
+ ** An optimization would be to use a non-journaled pager.
** (Later:) I tried setting "PRAGMA vacuum_db.journal_mode=OFF" but
** that actually made the VACUUM run slower. Very little journalling
** actually occurs when doing a vacuum since the vacuum_db is initially
@@ -150571,7 +154646,6 @@ SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3 *db){
if( p ){
db->pDisconnect = 0;
- sqlite3ExpirePreparedStatements(db, 0);
do {
VTable *pNext = p->pNext;
sqlite3VtabUnlock(p);
@@ -150737,7 +154811,7 @@ SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
** the information we've collected.
**
** The VM register number pParse->regRowid holds the rowid of an
- ** entry in the sqlite_schema table tht was created for this vtab
+ ** entry in the sqlite_schema table that was created for this vtab
** by sqlite3StartTable().
*/
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -150866,7 +154940,9 @@ static int vtabCallConstructor(
sCtx.pPrior = db->pVtabCtx;
sCtx.bDeclared = 0;
db->pVtabCtx = &sCtx;
+ pTab->nTabRef++;
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
+ sqlite3DeleteTable(db, pTab);
db->pVtabCtx = sCtx.pPrior;
if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
assert( sCtx.pTab==pTab );
@@ -151075,7 +155151,7 @@ SQLITE_API int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
sqlite3_mutex_enter(db->mutex);
pCtx = db->pVtabCtx;
if( !pCtx || pCtx->bDeclared ){
- sqlite3Error(db, SQLITE_MISUSE);
+ sqlite3Error(db, SQLITE_MISUSE_BKPT);
sqlite3_mutex_leave(db->mutex);
return SQLITE_MISUSE_BKPT;
}
@@ -151356,7 +155432,10 @@ SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){
break;
}
if( xMethod && pVTab->iSavepoint>iSavepoint ){
+ u64 savedFlags = (db->flags & SQLITE_Defensive);
+ db->flags &= ~(u64)SQLITE_Defensive;
rc = xMethod(pVTab->pVtab, iSavepoint);
+ db->flags |= savedFlags;
}
sqlite3VtabUnlock(pVTab);
}
@@ -151476,7 +155555,7 @@ SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse *pParse, Table *pTab){
**
** An eponymous virtual table instance is one that is named after its
** module, and more importantly, does not require a CREATE VIRTUAL TABLE
-** statement in order to come into existance. Eponymous virtual table
+** statement in order to come into existence. Eponymous virtual table
** instances always exist. They cannot be DROP-ed.
**
** Any virtual table module for which xConnect and xCreate are the same
@@ -151585,6 +155664,10 @@ SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){
p->pVTable->eVtabRisk = SQLITE_VTABRISK_High;
break;
}
+ case SQLITE_VTAB_USES_ALL_SCHEMAS: {
+ p->pVTable->bAllSchemas = 1;
+ break;
+ }
default: {
rc = SQLITE_MISUSE_BKPT;
break;
@@ -151663,7 +155746,7 @@ typedef struct WhereRightJoin WhereRightJoin;
/*
** This object is a header on a block of allocated memory that will be
-** automatically freed when its WInfo oject is destructed.
+** automatically freed when its WInfo object is destructed.
*/
struct WhereMemBlock {
WhereMemBlock *pNext; /* Next block in the chain */
@@ -151724,7 +155807,7 @@ struct WhereLevel {
int iCur; /* The VDBE cursor used by this IN operator */
int addrInTop; /* Top of the IN loop */
int iBase; /* Base register of multi-key index record */
- int nPrefix; /* Number of prior entires in the key */
+ int nPrefix; /* Number of prior entries in the key */
u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */
} *aInLoop; /* Information about each nested IN operator */
} in; /* Used when pWLoop->wsFlags&WHERE_IN_ABLE */
@@ -151974,7 +156057,7 @@ struct WhereClause {
int nTerm; /* Number of terms */
int nSlot; /* Number of entries in a[] */
int nBase; /* Number of terms through the last non-Virtual */
- WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */
+ WhereTerm *a; /* Each a[] describes a term of the WHERE clause */
#if defined(SQLITE_SMALL_STACK)
WhereTerm aStatic[1]; /* Initial static space for a[] */
#else
@@ -152128,7 +156211,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereGetMask(WhereMaskSet*,int);
#ifdef WHERETRACE_ENABLED
SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC);
SQLITE_PRIVATE void sqlite3WhereTermPrint(WhereTerm *pTerm, int iTerm);
-SQLITE_PRIVATE void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC);
+SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC);
#endif
SQLITE_PRIVATE WhereTerm *sqlite3WhereFindTerm(
WhereClause *pWC, /* The WHERE clause to be searched */
@@ -152259,7 +156342,7 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(Parse*, SrcItem*, WhereClause*);
#define WHERE_BLOOMFILTER 0x00400000 /* Consider using a Bloom-filter */
#define WHERE_SELFCULL 0x00800000 /* nOut reduced by extra WHERE terms */
#define WHERE_OMIT_OFFSET 0x01000000 /* Set offset counter to zero */
-#define WHERE_VIEWSCAN 0x02000000 /* A full-scan of a VIEW or subquery */
+ /* 0x02000000 -- available for reuse */
#define WHERE_EXPRIDX 0x04000000 /* Uses an index-on-expressions */
#endif /* !defined(SQLITE_WHEREINT_H) */
@@ -152358,9 +156441,9 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){
/*
** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
-** command, or if either SQLITE_DEBUG or SQLITE_ENABLE_STMT_SCANSTATUS was
-** defined at compile-time. If it is not a no-op, a single OP_Explain opcode
-** is added to the output to describe the table scan strategy in pLevel.
+** command, or if stmt_scanstatus_v2() stats are enabled, or if SQLITE_DEBUG
+** was defined at compile-time. If it is not a no-op, a single OP_Explain
+** opcode is added to the output to describe the table scan strategy in pLevel.
**
** If an OP_Explain opcode is added to the VM, its address is returned.
** Otherwise, if no OP_Explain is coded, zero is returned.
@@ -152372,8 +156455,8 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
){
int ret = 0;
-#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
- if( sqlite3ParseToplevel(pParse)->explain==2 )
+#if !defined(SQLITE_DEBUG)
+ if( sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) )
#endif
{
SrcItem *pItem = &pTabList->a[pLevel->iFrom];
@@ -152539,27 +156622,35 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
WhereLevel *pLvl, /* Level to add scanstatus() entry for */
int addrExplain /* Address of OP_Explain (or 0) */
){
- const char *zObj = 0;
- WhereLoop *pLoop = pLvl->pWLoop;
- int wsFlags = pLoop->wsFlags;
- int viaCoroutine = 0;
-
- if( (wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){
- zObj = pLoop->u.btree.pIndex->zName;
- }else{
- zObj = pSrclist->a[pLvl->iFrom].zName;
- viaCoroutine = pSrclist->a[pLvl->iFrom].fg.viaCoroutine;
- }
- sqlite3VdbeScanStatus(
- v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj
- );
+ if( IS_STMT_SCANSTATUS( sqlite3VdbeDb(v) ) ){
+ const char *zObj = 0;
+ WhereLoop *pLoop = pLvl->pWLoop;
+ int wsFlags = pLoop->wsFlags;
+ int viaCoroutine = 0;
- if( viaCoroutine==0 ){
- if( (wsFlags & (WHERE_MULTI_OR|WHERE_AUTO_INDEX))==0 ){
- sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iTabCur);
+ if( (wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){
+ zObj = pLoop->u.btree.pIndex->zName;
+ }else{
+ zObj = pSrclist->a[pLvl->iFrom].zName;
+ viaCoroutine = pSrclist->a[pLvl->iFrom].fg.viaCoroutine;
}
- if( wsFlags & WHERE_INDEXED ){
- sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
+ sqlite3VdbeScanStatus(
+ v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj
+ );
+
+ if( viaCoroutine==0 ){
+ if( (wsFlags & (WHERE_MULTI_OR|WHERE_AUTO_INDEX))==0 ){
+ sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iTabCur);
+ }
+ if( wsFlags & WHERE_INDEXED ){
+ sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
+ }
+ }else{
+ int addr = pSrclist->a[pLvl->iFrom].addrFillSub;
+ VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-1);
+ assert( sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine );
+ assert( sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr );
+ sqlite3VdbeScanStatusRange(v, addrExplain, addr, pOp->p2-1);
}
}
}
@@ -153057,7 +157148,7 @@ static int codeAllEqualityTerms(
/* Figure out how many memory cells we will need then allocate them.
*/
regBase = pParse->nMem + 1;
- nReg = pLoop->u.btree.nEq + nExtraReg;
+ nReg = nEq + nExtraReg;
pParse->nMem += nReg;
zAff = sqlite3DbStrDup(pParse->db,sqlite3IndexAffinityStr(pParse->db,pIdx));
@@ -153104,9 +157195,6 @@ static int codeAllEqualityTerms(
sqlite3VdbeAddOp2(v, OP_Copy, r1, regBase+j);
}
}
- }
- for(j=nSkip; j<nEq; j++){
- pTerm = pLoop->aLTerm[j];
if( pTerm->eOperator & WO_IN ){
if( pTerm->pExpr->flags & EP_xIsSelect ){
/* No affinity ever needs to be (or should be) applied to a value
@@ -153249,18 +157337,19 @@ static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
** 2) transform the expression node to a TK_REGISTER node that reads
** from the newly populated register.
**
-** Also, if the node is a TK_COLUMN that does access the table idenified
+** Also, if the node is a TK_COLUMN that does access the table identified
** by pCCurHint.iTabCur, and an index is being used (which we will
** know because CCurHint.pIdx!=0) then transform the TK_COLUMN into
** an access of the index rather than the original table.
*/
static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
int rc = WRC_Continue;
+ int reg;
struct CCurHint *pHint = pWalker->u.pCCurHint;
if( pExpr->op==TK_COLUMN ){
if( pExpr->iTable!=pHint->iTabCur ){
- int reg = ++pWalker->pParse->nMem; /* Register for column value */
- sqlite3ExprCode(pWalker->pParse, pExpr, reg);
+ reg = ++pWalker->pParse->nMem; /* Register for column value */
+ reg = sqlite3ExprCodeTarget(pWalker->pParse, pExpr, reg);
pExpr->op = TK_REGISTER;
pExpr->iTable = reg;
}else if( pHint->pIdx!=0 ){
@@ -153268,15 +157357,15 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
pExpr->iColumn = sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn);
assert( pExpr->iColumn>=0 );
}
- }else if( pExpr->op==TK_AGG_FUNCTION ){
- /* An aggregate function in the WHERE clause of a query means this must
- ** be a correlated sub-query, and expression pExpr is an aggregate from
- ** the parent context. Do not walk the function arguments in this case.
- **
- ** todo: It should be possible to replace this node with a TK_REGISTER
- ** expression, as the result of the expression must be stored in a
- ** register at this point. The same holds for TK_AGG_COLUMN nodes. */
+ }else if( pExpr->pAggInfo ){
rc = WRC_Prune;
+ reg = ++pWalker->pParse->nMem; /* Register for column value */
+ reg = sqlite3ExprCodeTarget(pWalker->pParse, pExpr, reg);
+ pExpr->op = TK_REGISTER;
+ pExpr->iTable = reg;
+ }else if( pExpr->op==TK_TRUEFALSE ){
+ /* Do not walk disabled expressions. tag-20230504-1 */
+ return WRC_Prune;
}
return rc;
}
@@ -153378,7 +157467,7 @@ static void codeCursorHint(
}
if( pExpr!=0 ){
sWalker.xExprCallback = codeCursorHintFixExpr;
- sqlite3WalkExpr(&sWalker, pExpr);
+ if( pParse->nErr==0 ) sqlite3WalkExpr(&sWalker, pExpr);
sqlite3VdbeAddOp4(v, OP_CursorHint,
(sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0,
(const char*)pExpr, P4_EXPR);
@@ -153866,7 +157955,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
};
assert( TK_LE==TK_GT+1 ); /* Make sure the ordering.. */
assert( TK_LT==TK_GT+2 ); /* ... of the TK_xx values... */
- assert( TK_GE==TK_GT+3 ); /* ... is correcct. */
+ assert( TK_GE==TK_GT+3 ); /* ... is correct. */
assert( (pStart->wtFlags & TERM_VNULL)==0 );
testcase( pStart->wtFlags & TERM_VIRTUAL );
@@ -154172,7 +158261,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
** guess. */
addrSeekScan = sqlite3VdbeAddOp1(v, OP_SeekScan,
(pIdx->aiRowLogEst[0]+9)/10);
- if( pRangeStart ){
+ if( pRangeStart || pRangeEnd ){
sqlite3VdbeChangeP5(v, 1);
sqlite3VdbeChangeP2(v, addrSeekScan, sqlite3VdbeCurrentAddr(v)+1);
addrSeekScan = 0;
@@ -154213,16 +158302,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
assert( pLevel->p2==0 );
if( pRangeEnd ){
Expr *pRight = pRangeEnd->pExpr->pRight;
- if( addrSeekScan ){
- /* For a seek-scan that has a range on the lowest term of the index,
- ** we have to make the top of the loop be code that sets the end
- ** condition of the range. Otherwise, the OP_SeekScan might jump
- ** over that initialization, leaving the range-end value set to the
- ** range-start value, resulting in a wrong answer.
- ** See ticket 5981a8c041a3c2f3 (2021-11-02).
- */
- pLevel->p2 = sqlite3VdbeCurrentAddr(v);
- }
+ assert( addrSeekScan==0 );
codeExprOrVector(pParse, pRight, regBase+nEq, nTop);
whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd);
if( (pRangeEnd->wtFlags & TERM_VNULL)==0
@@ -154256,7 +158336,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
if( zEndAff ) sqlite3DbNNFreeNN(db, zEndAff);
/* Top of the loop body */
- if( pLevel->p2==0 ) pLevel->p2 = sqlite3VdbeCurrentAddr(v);
+ pLevel->p2 = sqlite3VdbeCurrentAddr(v);
/* Check if the index cursor is past the end of the range. */
if( nConstraint ){
@@ -155055,7 +159135,7 @@ SQLITE_PRIVATE SQLITE_NOINLINE void sqlite3WhereRightJoinLoop(
** the WHERE clause of SQL statements.
**
** This file was originally part of where.c but was split out to improve
-** readability and editabiliity. This file contains utility routines for
+** readability and editability. This file contains utility routines for
** analyzing Expr objects in the WHERE clause.
*/
/* #include "sqliteInt.h" */
@@ -155271,7 +159351,7 @@ static int isLikeOrGlob(
** range search. The third is because the caller assumes that the pattern
** consists of at least one character after all escapes have been
** removed. */
- if( cnt!=0 && 255!=(u8)z[cnt-1] && (cnt>1 || z[0]!=wc[3]) ){
+ if( (cnt>1 || (cnt>0 && z[0]!=wc[3])) && 255!=(u8)z[cnt-1] ){
Expr *pPrefix;
/* A "complete" match if the pattern ends with "*" or "%" */
@@ -155844,7 +159924,7 @@ static void exprAnalyzeOrTerm(
pOrTerm->leftCursor))==0 ){
/* This term must be of the form t1.a==t2.b where t2 is in the
** chngToIN set but t1 is not. This term will be either preceded
- ** or follwed by an inverted copy (t2.b==t1.a). Skip this term
+ ** or followed by an inverted copy (t2.b==t1.a). Skip this term
** and use its inversion. */
testcase( pOrTerm->wtFlags & TERM_COPIED );
testcase( pOrTerm->wtFlags & TERM_VIRTUAL );
@@ -156106,8 +160186,8 @@ static void exprAnalyze(
WhereTerm *pTerm; /* The term to be analyzed */
WhereMaskSet *pMaskSet; /* Set of table index masks */
Expr *pExpr; /* The expression to be analyzed */
- Bitmask prereqLeft; /* Prerequesites of the pExpr->pLeft */
- Bitmask prereqAll; /* Prerequesites of pExpr */
+ Bitmask prereqLeft; /* Prerequisites of the pExpr->pLeft */
+ Bitmask prereqAll; /* Prerequisites of pExpr */
Bitmask extraRight = 0; /* Extra dependencies on LEFT JOIN */
Expr *pStr1 = 0; /* RHS of LIKE/GLOB operator */
int isComplete = 0; /* RHS of LIKE/GLOB ends with wildcard */
@@ -156253,7 +160333,7 @@ static void exprAnalyze(
&& 0==sqlite3ExprCanBeNull(pLeft)
){
assert( !ExprHasProperty(pExpr, EP_IntValue) );
- pExpr->op = TK_TRUEFALSE;
+ pExpr->op = TK_TRUEFALSE; /* See tag-20230504-1 */
pExpr->u.zToken = "false";
ExprSetProperty(pExpr, EP_IsFalse);
pTerm->prereqAll = 0;
@@ -156898,9 +160978,12 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(
pRhs = sqlite3PExpr(pParse, TK_UPLUS,
sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs);
- if( pItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT) ){
+ if( pItem->fg.jointype & (JT_LEFT|JT_RIGHT) ){
+ testcase( pItem->fg.jointype & JT_LEFT ); /* testtag-20230227a */
+ testcase( pItem->fg.jointype & JT_RIGHT ); /* testtag-20230227b */
joinType = EP_OuterON;
}else{
+ testcase( pItem->fg.jointype & JT_LTORJ ); /* testtag-20230227c */
joinType = EP_InnerON;
}
sqlite3SetJoinExpr(pTerm, pItem->iCursor, joinType);
@@ -157590,12 +161673,22 @@ static void translateColumnToCopy(
for(; iStart<iEnd; iStart++, pOp++){
if( pOp->p1!=iTabCur ) continue;
if( pOp->opcode==OP_Column ){
+#ifdef SQLITE_DEBUG
+ if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
+ printf("TRANSLATE OP_Column to OP_Copy at %d\n", iStart);
+ }
+#endif
pOp->opcode = OP_Copy;
pOp->p1 = pOp->p2 + iRegister;
pOp->p2 = pOp->p3;
pOp->p3 = 0;
pOp->p5 = 2; /* Cause the MEM_Subtype flag to be cleared */
}else if( pOp->opcode==OP_Rowid ){
+#ifdef SQLITE_DEBUG
+ if( pParse->db->flags & SQLITE_VdbeAddopTrace ){
+ printf("TRANSLATE OP_Rowid to OP_Sequence at %d\n", iStart);
+ }
+#endif
pOp->opcode = OP_Sequence;
pOp->p1 = iAutoidxCur;
#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
@@ -157743,7 +161836,7 @@ static void explainAutomaticIndex(
int bPartial, /* True if pIdx is a partial index */
int *pAddrExplain /* OUT: Address of OP_Explain */
){
- if( pParse->explain!=2 ){
+ if( IS_STMT_SCANSTATUS(pParse->db) && pParse->explain!=2 ){
Table *pTab = pIdx->pTable;
const char *zSep = "";
char *zText = 0;
@@ -157782,8 +161875,7 @@ static void explainAutomaticIndex(
*/
static SQLITE_NOINLINE void constructAutomaticIndex(
Parse *pParse, /* The parsing context */
- const WhereClause *pWC, /* The WHERE clause */
- const SrcItem *pSrc, /* The FROM clause term to get the next index */
+ WhereClause *pWC, /* The WHERE clause */
const Bitmask notReady, /* Mask of cursors that are not available */
WhereLevel *pLevel /* Write new index here */
){
@@ -157804,10 +161896,12 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
char *zNotUsed; /* Extra space on the end of pIdx */
Bitmask idxCols; /* Bitmap of columns used for indexing */
Bitmask extraCols; /* Bitmap of additional columns */
- u8 sentWarning = 0; /* True if a warnning has been issued */
+ u8 sentWarning = 0; /* True if a warning has been issued */
+ u8 useBloomFilter = 0; /* True to also add a Bloom filter */
Expr *pPartial = 0; /* Partial Index Expression */
int iContinue = 0; /* Jump here to skip excluded rows */
- SrcItem *pTabItem; /* FROM clause term being indexed */
+ SrcList *pTabList; /* The complete FROM clause */
+ SrcItem *pSrc; /* The FROM clause term to get the next index */
int addrCounter = 0; /* Address where integer counter is initialized */
int regBase; /* Array of registers where record is assembled */
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
@@ -157823,6 +161917,8 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
/* Count the number of columns that will be added to the index
** and used to match WHERE clause constraints */
nKeyCol = 0;
+ pTabList = pWC->pWInfo->pTabList;
+ pSrc = &pTabList->a[pLevel->iFrom];
pTable = pSrc->pTab;
pWCEnd = &pWC->a[pWC->nTerm];
pLoop = pLevel->pWLoop;
@@ -157833,7 +161929,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
** WHERE clause (or the ON clause of a LEFT join) that constrain which
** rows of the target table (pSrc) that can be used. */
if( (pTerm->wtFlags & TERM_VIRTUAL)==0
- && sqlite3ExprIsTableConstraint(pExpr, pSrc)
+ && sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, pLevel->iFrom)
){
pPartial = sqlite3ExprAnd(pParse, pPartial,
sqlite3ExprDup(pParse->db, pExpr, 0));
@@ -157874,7 +161970,11 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
** original table changes and the index and table cannot both be used
** if they go out of sync.
*/
- extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1));
+ if( IsView(pTable) ){
+ extraCols = ALLBITS;
+ }else{
+ extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1));
+ }
mxBitCol = MIN(BMS-1,pTable->nCol);
testcase( pTable->nCol==BMS-1 );
testcase( pTable->nCol==BMS-2 );
@@ -157910,6 +162010,16 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
assert( pColl!=0 || pParse->nErr>0 ); /* TH3 collate01.800 */
pIdx->azColl[n] = pColl ? pColl->zName : sqlite3StrBINARY;
n++;
+ if( ALWAYS(pX->pLeft!=0)
+ && sqlite3ExprAffinity(pX->pLeft)!=SQLITE_AFF_TEXT
+ ){
+ /* TUNING: only use a Bloom filter on an automatic index
+ ** if one or more key columns has the ability to hold numeric
+ ** values, since strings all have the same hash in the Bloom
+ ** filter implementation and hence a Bloom filter on a text column
+ ** is not usually helpful. */
+ useBloomFilter = 1;
+ }
}
}
}
@@ -157942,20 +162052,21 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol+1);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
VdbeComment((v, "for %s", pTable->zName));
- if( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ){
+ if( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) && useBloomFilter ){
+ sqlite3WhereExplainBloomFilter(pParse, pWC->pWInfo, pLevel);
pLevel->regFilter = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Blob, 10000, pLevel->regFilter);
}
/* Fill the automatic index with content */
- pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom];
- if( pTabItem->fg.viaCoroutine ){
- int regYield = pTabItem->regReturn;
+ assert( pSrc == &pWC->pWInfo->pTabList->a[pLevel->iFrom] );
+ if( pSrc->fg.viaCoroutine ){
+ int regYield = pSrc->regReturn;
addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0);
- sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
+ sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSrc->addrFillSub);
addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield);
VdbeCoverage(v);
- VdbeComment((v, "next row of %s", pTabItem->pTab->zName));
+ VdbeComment((v, "next row of %s", pSrc->pTab->zName));
}else{
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v);
}
@@ -157976,14 +162087,14 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
- if( pTabItem->fg.viaCoroutine ){
+ if( pSrc->fg.viaCoroutine ){
sqlite3VdbeChangeP2(v, addrCounter, regBase+n);
testcase( pParse->db->mallocFailed );
assert( pLevel->iIdxCur>0 );
translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
- pTabItem->regResult, pLevel->iIdxCur);
+ pSrc->regResult, pLevel->iIdxCur);
sqlite3VdbeGoto(v, addrTop);
- pTabItem->fg.viaCoroutine = 0;
+ pSrc->fg.viaCoroutine = 0;
}else{
sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
@@ -158035,16 +162146,26 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
Vdbe *v = pParse->pVdbe; /* VDBE under construction */
WhereLoop *pLoop = pLevel->pWLoop; /* The loop being coded */
int iCur; /* Cursor for table getting the filter */
+ IndexedExpr *saved_pIdxEpr; /* saved copy of Parse.pIdxEpr */
+ IndexedExpr *saved_pIdxPartExpr; /* saved copy of Parse.pIdxPartExpr */
+
+ saved_pIdxEpr = pParse->pIdxEpr;
+ saved_pIdxPartExpr = pParse->pIdxPartExpr;
+ pParse->pIdxEpr = 0;
+ pParse->pIdxPartExpr = 0;
assert( pLoop!=0 );
assert( v!=0 );
assert( pLoop->wsFlags & WHERE_BLOOMFILTER );
+ assert( (pLoop->wsFlags & WHERE_IDX_ONLY)==0 );
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
do{
+ const SrcList *pTabList;
const SrcItem *pItem;
const Table *pTab;
u64 sz;
+ int iSrc;
sqlite3WhereExplainBloomFilter(pParse, pWInfo, pLevel);
addrCont = sqlite3VdbeMakeLabel(pParse);
iCur = pLevel->iTabCur;
@@ -158058,7 +162179,9 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
** testing complicated. By basing the blob size on the value in the
** sqlite_stat1 table, testing is much easier.
*/
- pItem = &pWInfo->pTabList->a[pLevel->iFrom];
+ pTabList = pWInfo->pTabList;
+ iSrc = pLevel->iFrom;
+ pItem = &pTabList->a[iSrc];
assert( pItem!=0 );
pTab = pItem->pTab;
assert( pTab!=0 );
@@ -158075,7 +162198,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
for(pTerm=pWInfo->sWC.a; pTerm<pWCEnd; pTerm++){
Expr *pExpr = pTerm->pExpr;
if( (pTerm->wtFlags & TERM_VIRTUAL)==0
- && sqlite3ExprIsTableConstraint(pExpr, pItem)
+ && sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, iSrc)
){
sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
}
@@ -158091,9 +162214,8 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
int r1 = sqlite3GetTempRange(pParse, n);
int jj;
for(jj=0; jj<n; jj++){
- int iCol = pIdx->aiColumn[jj];
assert( pIdx->pTable==pItem->pTab );
- sqlite3ExprCodeGetColumnOfTable(v, pIdx->pTable, iCur, iCol,r1+jj);
+ sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj);
}
sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n);
sqlite3ReleaseTempRange(pParse, r1, n);
@@ -158124,6 +162246,8 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
}
}while( iLevel < pWInfo->nLevel );
sqlite3VdbeJumpHere(v, addrOnce);
+ pParse->pIdxEpr = saved_pIdxEpr;
+ pParse->pIdxPartExpr = saved_pIdxPartExpr;
}
@@ -158379,6 +162503,9 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
sqlite3ErrorMsg(pParse, "%s", pVtab->zErrMsg);
}
}
+ if( pTab->u.vtab.p->bAllSchemas ){
+ sqlite3VtabUsesAllSchemas(pParse);
+ }
sqlite3_free(pVtab->zErrMsg);
pVtab->zErrMsg = 0;
return rc;
@@ -158423,6 +162550,7 @@ static int whereKeyStats(
assert( pIdx->nSample>0 );
assert( pRec->nField>0 );
+
/* Do a binary search to find the first sample greater than or equal
** to pRec. If pRec contains a single field, the set of samples to search
** is simply the aSample[] array. If the samples in aSample[] contain more
@@ -158467,7 +162595,12 @@ static int whereKeyStats(
** it is extended to two fields. The duplicates that this creates do not
** cause any problems.
*/
- nField = MIN(pRec->nField, pIdx->nSample);
+ if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){
+ nField = pIdx->nKeyCol;
+ }else{
+ nField = pIdx->nColumn;
+ }
+ nField = MIN(pRec->nField, nField);
iCol = 0;
iSample = pIdx->nSample * nField;
do{
@@ -158630,7 +162763,7 @@ SQLITE_PRIVATE char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCo
** Value pLoop->nOut is currently set to the estimated number of rows
** visited for scanning (a=? AND b=?). This function reduces that estimate
** by some factor to account for the (c BETWEEN ? AND ?) expression based
-** on the stat4 data for the index. this scan will be peformed multiple
+** on the stat4 data for the index. this scan will be performed multiple
** times (once for each (a,b) combination that matches a=?) is dealt with
** by the caller.
**
@@ -158882,7 +163015,8 @@ static int whereRangeScanEst(
** sample, then assume they are 4x more selective. This brings
** the estimated selectivity more in line with what it would be
** if estimated without the use of STAT4 tables. */
- if( iLwrIdx==iUprIdx ) nNew -= 20; assert( 20==sqlite3LogEst(4) );
+ if( iLwrIdx==iUprIdx ){ nNew -= 20; }
+ assert( 20==sqlite3LogEst(4) );
}else{
nNew = 10; assert( 10==sqlite3LogEst(2) );
}
@@ -158903,7 +163037,7 @@ static int whereRangeScanEst(
UNUSED_PARAMETER(pBuilder);
assert( pLower || pUpper );
#endif
- assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 );
+ assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 || pParse->nErr>0 );
nNew = whereRangeAdjust(pLower, nOut);
nNew = whereRangeAdjust(pUpper, nNew);
@@ -159106,17 +163240,34 @@ SQLITE_PRIVATE void sqlite3WhereClausePrint(WhereClause *pWC){
#ifdef WHERETRACE_ENABLED
/*
** Print a WhereLoop object for debugging purposes
-*/
-SQLITE_PRIVATE void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC){
- WhereInfo *pWInfo = pWC->pWInfo;
- int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
- SrcItem *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 & mAll);
- sqlite3DebugPrintf(" %12s",
- pItem->zAlias ? pItem->zAlias : pTab->zName);
+**
+** Format example:
+**
+** .--- Position in WHERE clause rSetup, rRun, nOut ---.
+** | |
+** | .--- selfMask nTerm ------. |
+** | | | |
+** | | .-- prereq Idx wsFlags----. | |
+** | | | Name | | |
+** | | | __|__ nEq ---. ___|__ | __|__
+** | / \ / \ / \ | / \ / \ / \
+** 1.002.001 t2.t2xy 2 f 010241 N 2 cost 0,56,31
+*/
+SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){
+ if( pWC ){
+ WhereInfo *pWInfo = pWC->pWInfo;
+ int nb = 1+(pWInfo->pTabList->nSrc+3)/4;
+ SrcItem *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 & mAll);
+ sqlite3DebugPrintf(" %12s",
+ pItem->zAlias ? pItem->zAlias : pTab->zName);
+ }else{
+ sqlite3DebugPrintf("%c%2d.%03llx.%03llx %c%d",
+ p->cId, p->iTab, p->maskSelf, p->prereq & 0xfff, p->cId, p->iTab);
+ }
if( (p->wsFlags & WHERE_VIRTUALTABLE)==0 ){
const char *zName;
if( p->u.btree.pIndex && (zName = p->u.btree.pIndex->zName)!=0 ){
@@ -159153,6 +163304,15 @@ SQLITE_PRIVATE void sqlite3WhereLoopPrint(WhereLoop *p, WhereClause *pWC){
}
}
}
+SQLITE_PRIVATE void sqlite3ShowWhereLoop(const WhereLoop *p){
+ if( p ) sqlite3WhereLoopPrint(p, 0);
+}
+SQLITE_PRIVATE void sqlite3ShowWhereLoopList(const WhereLoop *p){
+ while( p ){
+ sqlite3ShowWhereLoop(p);
+ p = p->pNextLoop;
+ }
+}
#endif
/*
@@ -159265,46 +163425,60 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
}
/*
-** Return TRUE if all of the following are true:
+** Return TRUE if X is a proper subset of Y but is of equal or less cost.
+** In other words, return true if all constraints of X are also part of Y
+** and Y has additional constraints that might speed the search that X lacks
+** but the cost of running X is not more than the cost of running Y.
**
-** (1) X has the same or lower cost, or returns the same or fewer rows,
-** than Y.
-** (2) X uses fewer WHERE clause terms than Y
-** (3) Every WHERE clause term used by X is also used by Y
-** (4) X skips at least as many columns as Y
-** (5) If X is a covering index, than Y is too
+** In other words, return true if the cost relationwship between X and Y
+** is inverted and needs to be adjusted.
**
-** Conditions (2) and (3) mean that X is a "proper subset" of Y.
-** If X is a proper subset of Y then Y is a better choice and ought
-** to have a lower cost. This routine returns TRUE when that cost
-** relationship is inverted and needs to be adjusted. Constraint (4)
-** was added because if X uses skip-scan less than Y it still might
-** deserve a lower cost even if it is a proper subset of Y. Constraint (5)
-** was added because a covering index probably deserves to have a lower cost
-** than a non-covering index even if it is a proper subset.
+** Case 1:
+**
+** (1a) X and Y use the same index.
+** (1b) X has fewer == terms than Y
+** (1c) Neither X nor Y use skip-scan
+** (1d) X does not have a a greater cost than Y
+**
+** Case 2:
+**
+** (2a) X has the same or lower cost, or returns the same or fewer rows,
+** than Y.
+** (2b) X uses fewer WHERE clause terms than Y
+** (2c) Every WHERE clause term used by X is also used by Y
+** (2d) X skips at least as many columns as Y
+** (2e) If X is a covering index, than Y is too
*/
static int whereLoopCheaperProperSubset(
const WhereLoop *pX, /* First WhereLoop to compare */
const WhereLoop *pY /* Compare against this WhereLoop */
){
int i, j;
+ if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0; /* (1d) and (2a) */
+ assert( (pX->wsFlags & WHERE_VIRTUALTABLE)==0 );
+ assert( (pY->wsFlags & WHERE_VIRTUALTABLE)==0 );
+ if( pX->u.btree.nEq < pY->u.btree.nEq /* (1b) */
+ && pX->u.btree.pIndex==pY->u.btree.pIndex /* (1a) */
+ && pX->nSkip==0 && pY->nSkip==0 /* (1c) */
+ ){
+ return 1; /* Case 1 is true */
+ }
if( pX->nLTerm-pX->nSkip >= pY->nLTerm-pY->nSkip ){
- return 0; /* X is not a subset of Y */
+ return 0; /* (2b) */
}
- if( pX->rRun>pY->rRun && pX->nOut>pY->nOut ) return 0;
- if( pY->nSkip > pX->nSkip ) return 0;
+ if( pY->nSkip > pX->nSkip ) return 0; /* (2d) */
for(i=pX->nLTerm-1; i>=0; i--){
if( pX->aLTerm[i]==0 ) continue;
for(j=pY->nLTerm-1; j>=0; j--){
if( pY->aLTerm[j]==pX->aLTerm[i] ) break;
}
- if( j<0 ) return 0; /* X not a subset of Y since term X[i] not used by Y */
+ if( j<0 ) return 0; /* (2c) */
}
if( (pX->wsFlags&WHERE_IDX_ONLY)!=0
&& (pY->wsFlags&WHERE_IDX_ONLY)==0 ){
- return 0; /* Constraint (5) */
+ return 0; /* (2e) */
}
- return 1; /* All conditions meet */
+ return 1; /* Case 2 is true */
}
/*
@@ -159385,7 +163559,7 @@ static WhereLoop **whereLoopFindLesser(
** rSetup. Call this SETUP-INVARIANT */
assert( p->rSetup>=pTemplate->rSetup );
- /* Any loop using an appliation-defined index (or PRIMARY KEY or
+ /* Any loop using an application-defined index (or PRIMARY KEY or
** UNIQUE constraint) with one or more == constraints is better
** than an automatic index. Unless it is a skip-scan. */
if( (p->wsFlags & WHERE_AUTO_INDEX)!=0
@@ -159412,7 +163586,7 @@ static WhereLoop **whereLoopFindLesser(
/* If pTemplate is always better than p, then cause p to be overwritten
** with pTemplate. pTemplate is better than p if:
- ** (1) pTemplate has no more dependences than p, and
+ ** (1) pTemplate has no more dependencies than p, and
** (2) pTemplate has an equal or lower cost than p.
*/
if( (p->prereq & pTemplate->prereq)==pTemplate->prereq /* (1) */
@@ -159530,7 +163704,7 @@ static int whereLoopInsert(WhereLoopBuilder *pBuilder, WhereLoop *pTemplate){
}else{
/* We will be overwriting WhereLoop p[]. But before we do, first
** go through the rest of the list and delete any other entries besides
- ** p[] that are also supplated by pTemplate */
+ ** p[] that are also supplanted by pTemplate */
WhereLoop **ppTail = &p->pNextLoop;
WhereLoop *pToDel;
while( *ppTail ){
@@ -159730,7 +163904,7 @@ static int whereRangeVectorLen(
}
/*
-** Adjust the cost C by the costMult facter T. This only occurs if
+** Adjust the cost C by the costMult factor T. This only occurs if
** compiled with -DSQLITE_ENABLE_COSTMULT
*/
#ifdef SQLITE_ENABLE_COSTMULT
@@ -159757,7 +163931,7 @@ static int whereLoopAddBtreeIndex(
Index *pProbe, /* An index on pSrc */
LogEst nInMul /* log(Number of iterations due to IN) */
){
- WhereInfo *pWInfo = pBuilder->pWInfo; /* WHERE analyse context */
+ WhereInfo *pWInfo = pBuilder->pWInfo; /* WHERE analyze context */
Parse *pParse = pWInfo->pParse; /* Parsing context */
sqlite3 *db = pParse->db; /* Database connection malloc context */
WhereLoop *pNew; /* Template WhereLoop under construction */
@@ -159794,7 +163968,10 @@ static int whereLoopAddBtreeIndex(
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);
+ if( pProbe->bUnordered || pProbe->bLowQual ){
+ if( pProbe->bUnordered ) opMask &= ~(WO_GT|WO_GE|WO_LT|WO_LE);
+ if( pProbe->bLowQual ) opMask &= ~(WO_EQ|WO_IN|WO_IS);
+ }
assert( pNew->u.btree.nEq<pProbe->nColumn );
assert( pNew->u.btree.nEq<pProbe->nKeyCol
@@ -160067,7 +164244,7 @@ static int whereLoopAddBtreeIndex(
assert( pSrc->pTab->szTabRow>0 );
if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){
/* The pProbe->szIdxRow is low for an IPK table since the interior
- ** pages are small. Thuse szIdxRow gives a good estimate of seek cost.
+ ** pages are small. Thus szIdxRow gives a good estimate of seek cost.
** But the leaf pages are full-size, so pProbe->szIdxRow would badly
** under-estimate the scanning cost. */
rCostIdx = pNew->nOut + 16;
@@ -160375,6 +164552,100 @@ static SQLITE_NOINLINE u32 whereIsCoveringIndex(
}
/*
+** This is an sqlite3ParserAddCleanup() callback that is invoked to
+** free the Parse->pIdxEpr list when the Parse object is destroyed.
+*/
+static void whereIndexedExprCleanup(sqlite3 *db, void *pObject){
+ IndexedExpr **pp = (IndexedExpr**)pObject;
+ while( *pp!=0 ){
+ IndexedExpr *p = *pp;
+ *pp = p->pIENext;
+ sqlite3ExprDelete(db, p->pExpr);
+ sqlite3DbFreeNN(db, p);
+ }
+}
+
+/*
+** This function is called for a partial index - one with a WHERE clause - in
+** two scenarios. In both cases, it determines whether or not the WHERE
+** clause on the index implies that a column of the table may be safely
+** replaced by a constant expression. For example, in the following
+** SELECT:
+**
+** CREATE INDEX i1 ON t1(b, c) WHERE a=<expr>;
+** SELECT a, b, c FROM t1 WHERE a=<expr> AND b=?;
+**
+** The "a" in the select-list may be replaced by <expr>, iff:
+**
+** (a) <expr> is a constant expression, and
+** (b) The (a=<expr>) comparison uses the BINARY collation sequence, and
+** (c) Column "a" has an affinity other than NONE or BLOB.
+**
+** If argument pItem is NULL, then pMask must not be NULL. In this case this
+** function is being called as part of determining whether or not pIdx
+** is a covering index. This function clears any bits in (*pMask)
+** corresponding to columns that may be replaced by constants as described
+** above.
+**
+** Otherwise, if pItem is not NULL, then this function is being called
+** as part of coding a loop that uses index pIdx. In this case, add entries
+** to the Parse.pIdxPartExpr list for each column that can be replaced
+** by a constant.
+*/
+static void wherePartIdxExpr(
+ Parse *pParse, /* Parse context */
+ Index *pIdx, /* Partial index being processed */
+ Expr *pPart, /* WHERE clause being processed */
+ Bitmask *pMask, /* Mask to clear bits in */
+ int iIdxCur, /* Cursor number for index */
+ SrcItem *pItem /* The FROM clause entry for the table */
+){
+ assert( pItem==0 || (pItem->fg.jointype & JT_RIGHT)==0 );
+ assert( (pItem==0 || pMask==0) && (pMask!=0 || pItem!=0) );
+
+ if( pPart->op==TK_AND ){
+ wherePartIdxExpr(pParse, pIdx, pPart->pRight, pMask, iIdxCur, pItem);
+ pPart = pPart->pLeft;
+ }
+
+ if( (pPart->op==TK_EQ || pPart->op==TK_IS) ){
+ Expr *pLeft = pPart->pLeft;
+ Expr *pRight = pPart->pRight;
+ u8 aff;
+
+ if( pLeft->op!=TK_COLUMN ) return;
+ if( !sqlite3ExprIsConstant(pRight) ) return;
+ if( !sqlite3IsBinary(sqlite3ExprCompareCollSeq(pParse, pPart)) ) return;
+ if( pLeft->iColumn<0 ) return;
+ aff = pIdx->pTable->aCol[pLeft->iColumn].affinity;
+ if( aff>=SQLITE_AFF_TEXT ){
+ if( pItem ){
+ sqlite3 *db = pParse->db;
+ IndexedExpr *p = (IndexedExpr*)sqlite3DbMallocRaw(db, sizeof(*p));
+ if( p ){
+ int bNullRow = (pItem->fg.jointype&(JT_LEFT|JT_LTORJ))!=0;
+ p->pExpr = sqlite3ExprDup(db, pRight, 0);
+ p->iDataCur = pItem->iCursor;
+ p->iIdxCur = iIdxCur;
+ p->iIdxCol = pLeft->iColumn;
+ p->bMaybeNullRow = bNullRow;
+ p->pIENext = pParse->pIdxPartExpr;
+ p->aff = aff;
+ pParse->pIdxPartExpr = p;
+ if( p->pIENext==0 ){
+ void *pArg = (void*)&pParse->pIdxPartExpr;
+ sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pArg);
+ }
+ }
+ }else if( pLeft->iColumn<(BMS-1) ){
+ *pMask &= ~((Bitmask)1 << pLeft->iColumn);
+ }
+ }
+ }
+}
+
+
+/*
** Add all WhereLoop objects for a single table of the join where the table
** is identified by pBuilder->pNew->iTab. That table is guaranteed to be
** a b-tree table, not a virtual table.
@@ -160412,7 +164683,7 @@ static SQLITE_NOINLINE u32 whereIsCoveringIndex(
*/
static int whereLoopAddBtree(
WhereLoopBuilder *pBuilder, /* WHERE clause information */
- Bitmask mPrereq /* Extra prerequesites for using this table */
+ Bitmask mPrereq /* Extra prerequisites for using this table */
){
WhereInfo *pWInfo; /* WHERE analysis context */
Index *pProbe; /* An index we are evaluating */
@@ -160577,9 +164848,6 @@ static int whereLoopAddBtree(
#else
pNew->rRun = rSize + 16;
#endif
- if( IsView(pTab) || (pTab->tabFlags & TF_Ephemeral)!=0 ){
- pNew->wsFlags |= WHERE_VIEWSCAN;
- }
ApplyCostMultiplier(pNew->rRun, pTab->costMult);
whereLoopOutputAdjust(pWC, pNew, rSize);
rc = whereLoopInsert(pBuilder, pNew);
@@ -160592,6 +164860,11 @@ static int whereLoopAddBtree(
pNew->wsFlags = WHERE_IDX_ONLY | WHERE_INDEXED;
}else{
m = pSrc->colUsed & pProbe->colNotIdxed;
+ if( pProbe->pPartIdxWhere ){
+ wherePartIdxExpr(
+ pWInfo->pParse, pProbe, pProbe->pPartIdxWhere, &m, 0, 0
+ );
+ }
pNew->wsFlags = WHERE_INDEXED;
if( m==TOPBIT || (pProbe->bHasExpr && !pProbe->bHasVCol && m!=0) ){
u32 isCov = whereIsCoveringIndex(pWInfo, pProbe, pSrc->iCursor);
@@ -160919,7 +165192,7 @@ static int whereLoopAddVirtualOne(
**
** Return a pointer to the collation name:
**
-** 1. If there is an explicit COLLATE operator on the constaint, return it.
+** 1. If there is an explicit COLLATE operator on the constraint, return it.
**
** 2. Else, if the column has an alternative collation, return that.
**
@@ -160974,7 +165247,7 @@ SQLITE_API int sqlite3_vtab_rhs_value(
sqlite3_value *pVal = 0;
int rc = SQLITE_OK;
if( iCons<0 || iCons>=pIdxInfo->nConstraint ){
- rc = SQLITE_MISUSE; /* EV: R-30545-25046 */
+ rc = SQLITE_MISUSE_BKPT; /* EV: R-30545-25046 */
}else{
if( pH->aRhs[iCons]==0 ){
WhereTerm *pTerm = &pH->pWC->a[pIdxInfo->aConstraint[iCons].iTermOffset];
@@ -161004,8 +165277,6 @@ SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info *pIdxInfo){
return pHidden->eDistinct;
}
-#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
- && !defined(SQLITE_OMIT_VIRTUALTABLE)
/*
** Cause the prepared statement that is associated with a call to
** xBestIndex to potentially use all schemas. If the statement being
@@ -161015,9 +165286,7 @@ SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info *pIdxInfo){
**
** This is used by the (built-in) sqlite_dbpage virtual table.
*/
-SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(sqlite3_index_info *pIdxInfo){
- HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
- Parse *pParse = pHidden->pParse;
+SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(Parse *pParse){
int nDb = pParse->db->nDb;
int i;
for(i=0; i<nDb; i++){
@@ -161029,7 +165298,6 @@ SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(sqlite3_index_info *pIdxInfo){
}
}
}
-#endif
/*
** Add all WhereLoop objects for a table of the join identified by
@@ -161885,7 +166153,8 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
** For joins of 3 or more tables, track the 10 best paths */
mxChoice = (nLoop<=1) ? 1 : (nLoop==2 ? 5 : 10);
assert( nLoop<=pWInfo->pTabList->nSrc );
- WHERETRACE(0x002, ("---- begin solver. (nRowEst=%d)\n", nRowEst));
+ WHERETRACE(0x002, ("---- begin solver. (nRowEst=%d, nQueryLoop=%d)\n",
+ nRowEst, pParse->nQueryLoop));
/* If nRowEst is zero and there is an ORDER BY clause, ignore it. In this
** case the purpose of this call is to estimate the number of rows returned
@@ -161988,7 +166257,7 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
);
}
/* TUNING: Add a small extra penalty (3) to sorting as an
- ** extra encouragment to the query planner to select a plan
+ ** extra encouragement to the query planner to select a plan
** where the rows emerge in the correct order without any sorting
** required. */
rCost = sqlite3LogEstAdd(rUnsorted, aSortCost[isOrdered]) + 3;
@@ -162002,13 +166271,6 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
rUnsorted -= 2; /* TUNING: Slight bias in favor of no-sort plans */
}
- /* TUNING: A full-scan of a VIEW or subquery in the outer loop
- ** is not so bad. */
- if( iLoop==0 && (pWLoop->wsFlags & WHERE_VIEWSCAN)!=0 ){
- rCost += -10;
- nOut += -30;
- }
-
/* Check to see if pWLoop should be added to the set of
** mxChoice best-so-far paths.
**
@@ -162195,6 +166457,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){
pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
}
+ if( pWInfo->pSelect->pOrderBy
+ && pWInfo->nOBSat > pWInfo->pSelect->pOrderBy->nExpr ){
+ pWInfo->nOBSat = pWInfo->pSelect->pOrderBy->nExpr;
+ }
}else{
pWInfo->revMask = pFrom->revLoop;
if( pWInfo->nOBSat<=0 ){
@@ -162406,6 +166672,13 @@ static void showAllWhereLoops(WhereInfo *pWInfo, WhereClause *pWC){
** at most a single row.
** 4) The table must not be referenced by any part of the query apart
** from its own USING or ON clause.
+** 5) The table must not have an inner-join ON or USING clause if there is
+** a RIGHT JOIN anywhere in the query. Otherwise the ON/USING clause
+** might move from the right side to the left side of the RIGHT JOIN.
+** Note: Due to (2), this condition can only arise if the table is
+** the right-most table of a subquery that was flattened into the
+** main query and that subquery was the right-hand operand of an
+** inner join that held an ON or USING clause.
**
** For example, given:
**
@@ -162431,6 +166704,7 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
){
int i;
Bitmask tabUsed;
+ int hasRightJoin;
/* Preconditions checked by the caller */
assert( pWInfo->nLevel>=2 );
@@ -162445,6 +166719,7 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
if( pWInfo->pOrderBy ){
tabUsed |= sqlite3WhereExprListUsage(&pWInfo->sMaskSet, pWInfo->pOrderBy);
}
+ hasRightJoin = (pWInfo->pTabList->a[0].fg.jointype & JT_LTORJ)!=0;
for(i=pWInfo->nLevel-1; i>=1; i--){
WhereTerm *pTerm, *pEnd;
SrcItem *pItem;
@@ -162467,6 +166742,12 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
break;
}
}
+ if( hasRightJoin
+ && ExprHasProperty(pTerm->pExpr, EP_InnerON)
+ && pTerm->pExpr->w.iJoin==pItem->iCursor
+ ){
+ break; /* restriction (5) */
+ }
}
if( pTerm<pEnd ) continue;
WHERETRACE(0xffffffff, ("-> drop loop %c not used\n", pLoop->cId));
@@ -162540,20 +166821,6 @@ static SQLITE_NOINLINE void whereCheckIfBloomFilterIsUseful(
}
/*
-** This is an sqlite3ParserAddCleanup() callback that is invoked to
-** free the Parse->pIdxEpr list when the Parse object is destroyed.
-*/
-static void whereIndexedExprCleanup(sqlite3 *db, void *pObject){
- Parse *pParse = (Parse*)pObject;
- while( pParse->pIdxEpr!=0 ){
- IndexedExpr *p = pParse->pIdxEpr;
- pParse->pIdxEpr = p->pIENext;
- sqlite3ExprDelete(db, p->pExpr);
- sqlite3DbFreeNN(db, p);
- }
-}
-
-/*
** The index pIdx is used by a query and contains one or more expressions.
** In other words pIdx is an index on an expression. iIdxCur is the cursor
** number for the index and iDataCur is the cursor number for the corresponding
@@ -162578,20 +166845,28 @@ static SQLITE_NOINLINE void whereAddIndexedExpr(
for(i=0; i<pIdx->nColumn; i++){
Expr *pExpr;
int j = pIdx->aiColumn[i];
- int bMaybeNullRow;
if( j==XN_EXPR ){
pExpr = pIdx->aColExpr->a[i].pExpr;
- testcase( pTabItem->fg.jointype & JT_LEFT );
- testcase( pTabItem->fg.jointype & JT_RIGHT );
- testcase( pTabItem->fg.jointype & JT_LTORJ );
- bMaybeNullRow = (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0;
}else if( j>=0 && (pTab->aCol[j].colFlags & COLFLAG_VIRTUAL)!=0 ){
pExpr = sqlite3ColumnExpr(pTab, &pTab->aCol[j]);
- bMaybeNullRow = 0;
}else{
continue;
}
if( sqlite3ExprIsConstant(pExpr) ) continue;
+ if( pExpr->op==TK_FUNCTION ){
+ /* Functions that might set a subtype should not be replaced by the
+ ** value taken from an expression index since the index omits the
+ ** subtype. https://sqlite.org/forum/forumpost/68d284c86b082c3e */
+ int n;
+ FuncDef *pDef;
+ sqlite3 *db = pParse->db;
+ assert( ExprUseXList(pExpr) );
+ n = pExpr->x.pList ? pExpr->x.pList->nExpr : 0;
+ pDef = sqlite3FindFunction(db, pExpr->u.zToken, n, ENC(db), 0);
+ if( pDef==0 || (pDef->funcFlags & SQLITE_RESULT_SUBTYPE)!=0 ){
+ continue;
+ }
+ }
p = sqlite3DbMallocRaw(pParse->db, sizeof(IndexedExpr));
if( p==0 ) break;
p->pIENext = pParse->pIdxEpr;
@@ -162605,7 +166880,7 @@ static SQLITE_NOINLINE void whereAddIndexedExpr(
p->iDataCur = pTabItem->iCursor;
p->iIdxCur = iIdxCur;
p->iIdxCol = i;
- p->bMaybeNullRow = bMaybeNullRow;
+ p->bMaybeNullRow = (pTabItem->fg.jointype & (JT_LEFT|JT_LTORJ|JT_RIGHT))!=0;
if( sqlite3IndexAffinityStr(pParse->db, pIdx) ){
p->aff = pIdx->zColAff[i];
}
@@ -162614,7 +166889,30 @@ static SQLITE_NOINLINE void whereAddIndexedExpr(
#endif
pParse->pIdxEpr = p;
if( p->pIENext==0 ){
- sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pParse);
+ void *pArg = (void*)&pParse->pIdxEpr;
+ sqlite3ParserAddCleanup(pParse, whereIndexedExprCleanup, pArg);
+ }
+ }
+}
+
+/*
+** Set the reverse-scan order mask to one for all tables in the query
+** with the exception of MATERIALIZED common table expressions that have
+** their own internal ORDER BY clauses.
+**
+** This implements the PRAGMA reverse_unordered_selects=ON setting.
+** (Also SQLITE_DBCONFIG_REVERSE_SCANORDER).
+*/
+static SQLITE_NOINLINE void whereReverseScanOrder(WhereInfo *pWInfo){
+ int ii;
+ for(ii=0; ii<pWInfo->pTabList->nSrc; ii++){
+ SrcItem *pItem = &pWInfo->pTabList->a[ii];
+ if( !pItem->fg.isCte
+ || pItem->u2.pCteUse->eM10d!=M10d_Yes
+ || NEVER(pItem->pSelect==0)
+ || pItem->pSelect->pOrderBy==0
+ ){
+ pWInfo->revMask |= MASKBIT(ii);
}
}
}
@@ -162677,7 +166975,7 @@ static SQLITE_NOINLINE void whereAddIndexedExpr(
**
** OUTER JOINS
**
-** An outer join of tables t1 and t2 is conceptally coded as follows:
+** An outer join of tables t1 and t2 is conceptually coded as follows:
**
** foreach row1 in t1 do
** flag = 0
@@ -162747,7 +167045,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
/* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */
testcase( pOrderBy && pOrderBy->nExpr==BMS-1 );
- if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0;
+ if( pOrderBy && pOrderBy->nExpr>=BMS ){
+ pOrderBy = 0;
+ wctrlFlags &= ~WHERE_WANT_DISTINCT;
+ }
/* The number of tables in the FROM clause is limited by the number of
** bits in a Bitmask
@@ -162772,7 +167073,10 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
** field (type Bitmask) it must be aligned on an 8-byte boundary on
** some architectures. Hence the ROUND8() below.
*/
- nByteWInfo = ROUND8P(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel));
+ nByteWInfo = ROUND8P(sizeof(WhereInfo));
+ if( nTabList>1 ){
+ nByteWInfo = ROUND8P(nByteWInfo + (nTabList-1)*sizeof(WhereLevel));
+ }
pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop));
if( db->mallocFailed ){
sqlite3DbFree(db, pWInfo);
@@ -162832,7 +167136,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
**
** The N-th term of the FROM clause is assigned a bitmask of 1<<N.
**
- ** The rule of the previous sentence ensures thta if X is the bitmask for
+ ** The rule of the previous sentence ensures that if X is the bitmask for
** a table T, then X-1 is the bitmask for all other tables to the left of T.
** Knowing the bitmask for all tables to the left of a left join is
** important. Ticket #3015.
@@ -162866,22 +167170,45 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
}
if( pParse->nErr ) goto whereBeginError;
- /* Special case: WHERE terms that do not refer to any tables in the join
- ** (constant expressions). Evaluate each such term, and jump over all the
- ** generated code if the result is not true.
+ /* The False-WHERE-Term-Bypass optimization:
+ **
+ ** If there are WHERE terms that are false, then no rows will be output,
+ ** so skip over all of the code generated here.
+ **
+ ** Conditions:
**
- ** Do not do this if the expression contains non-deterministic functions
- ** that are not within a sub-select. This is not strictly required, but
- ** preserves SQLite's legacy behaviour in the following two cases:
+ ** (1) The WHERE term must not refer to any tables in the join.
+ ** (2) The term must not come from an ON clause on the
+ ** right-hand side of a LEFT or FULL JOIN.
+ ** (3) The term must not come from an ON clause, or there must be
+ ** no RIGHT or FULL OUTER joins in pTabList.
+ ** (4) If the expression contains non-deterministic functions
+ ** that are not within a sub-select. This is not required
+ ** for correctness but rather to preserves SQLite's legacy
+ ** behaviour in the following two cases:
**
- ** FROM ... WHERE random()>0; -- eval random() once per row
- ** FROM ... WHERE (SELECT random())>0; -- eval random() once overall
+ ** WHERE random()>0; -- eval random() once per row
+ ** WHERE (SELECT random())>0; -- eval random() just once overall
+ **
+ ** Note that the Where term need not be a constant in order for this
+ ** optimization to apply, though it does need to be constant relative to
+ ** the current subquery (condition 1). The term might include variables
+ ** from outer queries so that the value of the term changes from one
+ ** invocation of the current subquery to the next.
*/
for(ii=0; ii<sWLB.pWC->nBase; ii++){
- WhereTerm *pT = &sWLB.pWC->a[ii];
+ WhereTerm *pT = &sWLB.pWC->a[ii]; /* A term of the WHERE clause */
+ Expr *pX; /* The expression of pT */
if( pT->wtFlags & TERM_VIRTUAL ) continue;
- if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){
- sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL);
+ pX = pT->pExpr;
+ assert( pX!=0 );
+ assert( pT->prereqAll!=0 || !ExprHasProperty(pX, EP_OuterON) );
+ if( pT->prereqAll==0 /* Conditions (1) and (2) */
+ && (nTabList==0 || exprIsDeterministic(pX)) /* Condition (4) */
+ && !(ExprHasProperty(pX, EP_InnerON) /* Condition (3) */
+ && (pTabList->a[0].fg.jointype & JT_LTORJ)!=0 )
+ ){
+ sqlite3ExprIfFalse(pParse, pX, pWInfo->iBreak, SQLITE_JUMPIFNULL);
pT->wtFlags |= TERM_CODED;
}
}
@@ -162959,9 +167286,20 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
wherePathSolver(pWInfo, pWInfo->nRowOut+1);
if( db->mallocFailed ) goto whereBeginError;
}
+
+ /* TUNING: Assume that a DISTINCT clause on a subquery reduces
+ ** the output size by a factor of 8 (LogEst -30).
+ */
+ if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT)!=0 ){
+ WHERETRACE(0x0080,("nRowOut reduced from %d to %d due to DISTINCT\n",
+ pWInfo->nRowOut, pWInfo->nRowOut-30));
+ pWInfo->nRowOut -= 30;
+ }
+
}
+ assert( pWInfo->pTabList!=0 );
if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){
- pWInfo->revMask = ALLBITS;
+ whereReverseScanOrder(pWInfo);
}
if( pParse->nErr ){
goto whereBeginError;
@@ -163061,6 +167399,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW)
&& !IsVirtual(pTabList->a[0].pTab)
&& (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK))
+ && OptimizationEnabled(db, SQLITE_OnePass)
)){
pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI;
if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){
@@ -163124,7 +167463,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
assert( n<=pTab->nCol );
}
#ifdef SQLITE_ENABLE_CURSOR_HINTS
- if( pLoop->u.btree.pIndex!=0 ){
+ if( pLoop->u.btree.pIndex!=0 && (pTab->tabFlags & TF_WithoutRowid)==0 ){
sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ|bFordelete);
}else
#endif
@@ -163169,6 +167508,11 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
if( pIx->bHasExpr && OptimizationEnabled(db, SQLITE_IndexedExpr) ){
whereAddIndexedExpr(pParse, pIx, iIndexCur, pTabItem);
}
+ if( pIx->pPartIdxWhere && (pTabItem->fg.jointype & JT_RIGHT)==0 ){
+ wherePartIdxExpr(
+ pParse, pIx, pIx->pPartIdxWhere, 0, iIndexCur, pTabItem
+ );
+ }
}
pLevel->iIdxCur = iIndexCur;
assert( pIx!=0 );
@@ -163261,11 +167605,11 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
sqlite3VdbeJumpHere(v, iOnce);
}
}
+ assert( pTabList == pWInfo->pTabList );
if( (wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))!=0 ){
if( (wsFlags & WHERE_AUTO_INDEX)!=0 ){
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
- constructAutomaticIndex(pParse, &pWInfo->sWC,
- &pTabList->a[pLevel->iFrom], notReady, pLevel);
+ constructAutomaticIndex(pParse, &pWInfo->sWC, notReady, pLevel);
#endif
}else{
sqlite3ConstructBloomFilter(pWInfo, ii, pLevel, notReady);
@@ -163294,6 +167638,11 @@ whereBeginError:
pParse->nQueryLoop = pWInfo->savedNQueryLoop;
whereInfoFree(db, pWInfo);
}
+#ifdef WHERETRACE_ENABLED
+ /* Prevent harmless compiler warnings about debugging routines
+ ** being declared but never used */
+ sqlite3ShowWhereLoopList(0);
+#endif /* WHERETRACE_ENABLED */
return 0;
}
@@ -163582,7 +167931,8 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
k = pLevel->addrBody + 1;
#ifdef SQLITE_DEBUG
if( db->flags & SQLITE_VdbeAddopTrace ){
- printf("TRANSLATE opcodes in range %d..%d\n", k, last-1);
+ printf("TRANSLATE cursor %d->%d in opcode range %d..%d\n",
+ pLevel->iTabCur, pLevel->iIdxCur, k, last-1);
}
/* Proof that the "+1" on the k value above is safe */
pOp = sqlite3VdbeGetOp(v, k - 1);
@@ -163789,7 +168139,7 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
**
** These are the same built-in window functions supported by Postgres.
** Although the behaviour of aggregate window functions (functions that
-** can be used as either aggregates or window funtions) allows them to
+** can be used as either aggregates or window functions) allows them to
** be implemented using an API, built-in window functions are much more
** esoteric. Additionally, some window functions (e.g. nth_value())
** may only be implemented by caching the entire partition in memory.
@@ -164319,7 +168669,7 @@ static Window *windowFind(Parse *pParse, Window *pList, const char *zName){
** is the Window object representing the associated OVER clause. This
** function updates the contents of pWin as follows:
**
-** * If the OVER clause refered to a named window (as in "max(x) OVER win"),
+** * If the OVER clause referred to a named window (as in "max(x) OVER win"),
** search list pList for a matching WINDOW definition, and update pWin
** accordingly. If no such WINDOW clause can be found, leave an error
** in pParse.
@@ -164457,6 +168807,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
}
/* no break */ deliberate_fall_through
+ case TK_IF_NULL_ROW:
case TK_AGG_FUNCTION:
case TK_COLUMN: {
int iCol = -1;
@@ -164709,7 +169060,7 @@ SQLITE_PRIVATE int sqlite3WindowRewrite(Parse *pParse, Select *p){
assert( ExprUseXList(pWin->pOwner) );
assert( pWin->pWFunc!=0 );
pArgs = pWin->pOwner->x.pList;
- if( pWin->pWFunc->funcFlags & SQLITE_FUNC_SUBTYPE ){
+ if( pWin->pWFunc->funcFlags & SQLITE_SUBTYPE ){
selectWindowRewriteEList(pParse, pMWin, pSrc, pArgs, pTab, &pSublist);
pWin->iArgCol = (pSublist ? pSublist->nExpr : 0);
pWin->bExprArgs = 1;
@@ -164939,7 +169290,7 @@ SQLITE_PRIVATE Window *sqlite3WindowAssemble(
}
/*
-** Window *pWin has just been created from a WINDOW clause. Tokne pBase
+** Window *pWin has just been created from a WINDOW clause. Token pBase
** is the base window. Earlier windows from the same WINDOW clause are
** stored in the linked list starting at pWin->pNextWin. This function
** either updates *pWin according to the base specification, or else
@@ -164983,8 +169334,9 @@ SQLITE_PRIVATE void sqlite3WindowAttach(Parse *pParse, Expr *p, Window *pWin){
if( p ){
assert( p->op==TK_FUNCTION );
assert( pWin );
+ assert( ExprIsFullSize(p) );
p->y.pWin = pWin;
- ExprSetProperty(p, EP_WinFunc);
+ ExprSetProperty(p, EP_WinFunc|EP_FullSize);
pWin->pOwner = p;
if( (p->flags & EP_Distinct) && pWin->eFrmType!=TK_FILTER ){
sqlite3ErrorMsg(pParse,
@@ -165245,7 +169597,7 @@ struct WindowCsrAndReg {
**
** (ORDER BY a, b GROUPS BETWEEN 2 PRECEDING AND 2 FOLLOWING)
**
-** The windows functions implmentation caches the input rows in a temp
+** The windows functions implementation caches the input rows in a temp
** table, sorted by "a, b" (it actually populates the cache lazily, and
** aggressively removes rows once they are no longer required, but that's
** a mere detail). It keeps three cursors open on the temp table. One
@@ -166254,7 +170606,7 @@ static int windowExprGtZero(Parse *pParse, Expr *pExpr){
**
** For the most part, the patterns above are adapted to support UNBOUNDED by
** assuming that it is equivalent to "infinity PRECEDING/FOLLOWING" and
-** CURRENT ROW by assuming that it is equivilent to "0 PRECEDING/FOLLOWING".
+** CURRENT ROW by assuming that it is equivalent to "0 PRECEDING/FOLLOWING".
** This is optimized of course - branches that will never be taken and
** conditions that are always true are omitted from the VM code. The only
** exceptional case is:
@@ -166533,7 +170885,7 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
}
/* Allocate registers for the array of values from the sub-query, the
- ** samve values in record form, and the rowid used to insert said record
+ ** same values in record form, and the rowid used to insert said record
** into the ephemeral table. */
regNew = pParse->nMem+1;
pParse->nMem += nInput;
@@ -166774,7 +171126,8 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
/************** End of window.c **********************************************/
/************** Begin file parse.c *******************************************/
/* This file is automatically generated by Lemon from input grammar
-** source file "parse.y". */
+** source file "parse.y".
+*/
/*
** 2001-09-15
**
@@ -166791,7 +171144,7 @@ SQLITE_PRIVATE void sqlite3WindowCodeStep(
** The canonical source code to this file ("parse.y") is a Lemon grammar
** file that specifies the input grammar and actions to take while parsing.
** That input file is processed by Lemon to generate a C-language
-** implementation of a parser for the given grammer. You might be reading
+** implementation of a parser for the given grammar. You might be reading
** this comment as part of the translated C-code. Edits should be made
** to the original parse.y sources.
*/
@@ -167285,18 +171638,18 @@ typedef union {
#define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse;
#define sqlite3ParserCTX_STORE yypParser->pParse=pParse;
#define YYFALLBACK 1
-#define YYNSTATE 576
+#define YYNSTATE 579
#define YYNRULE 405
-#define YYNRULE_WITH_ACTION 342
+#define YYNRULE_WITH_ACTION 340
#define YYNTOKEN 185
-#define YY_MAX_SHIFT 575
-#define YY_MIN_SHIFTREDUCE 835
-#define YY_MAX_SHIFTREDUCE 1239
-#define YY_ERROR_ACTION 1240
-#define YY_ACCEPT_ACTION 1241
-#define YY_NO_ACTION 1242
-#define YY_MIN_REDUCE 1243
-#define YY_MAX_REDUCE 1647
+#define YY_MAX_SHIFT 578
+#define YY_MIN_SHIFTREDUCE 838
+#define YY_MAX_SHIFTREDUCE 1242
+#define YY_ERROR_ACTION 1243
+#define YY_ACCEPT_ACTION 1244
+#define YY_NO_ACTION 1245
+#define YY_MIN_REDUCE 1246
+#define YY_MAX_REDUCE 1650
/************* End control #defines *******************************************/
#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])))
@@ -167363,218 +171716,218 @@ typedef union {
** yy_default[] Default action for each state.
**
*********** Begin parsing tables **********************************************/
-#define YY_ACTTAB_COUNT (2098)
+#define YY_ACTTAB_COUNT (2100)
static const YYACTIONTYPE yy_action[] = {
- /* 0 */ 568, 208, 568, 118, 115, 229, 568, 118, 115, 229,
- /* 10 */ 568, 1314, 377, 1293, 408, 562, 562, 562, 568, 409,
- /* 20 */ 378, 1314, 1276, 41, 41, 41, 41, 208, 1526, 71,
- /* 30 */ 71, 971, 419, 41, 41, 491, 303, 279, 303, 972,
- /* 40 */ 397, 71, 71, 125, 126, 80, 1217, 1217, 1050, 1053,
- /* 50 */ 1040, 1040, 123, 123, 124, 124, 124, 124, 476, 409,
- /* 60 */ 1241, 1, 1, 575, 2, 1245, 550, 118, 115, 229,
- /* 70 */ 317, 480, 146, 480, 524, 118, 115, 229, 529, 1327,
- /* 80 */ 417, 523, 142, 125, 126, 80, 1217, 1217, 1050, 1053,
- /* 90 */ 1040, 1040, 123, 123, 124, 124, 124, 124, 118, 115,
- /* 100 */ 229, 327, 122, 122, 122, 122, 121, 121, 120, 120,
- /* 110 */ 120, 119, 116, 444, 284, 284, 284, 284, 442, 442,
- /* 120 */ 442, 1567, 376, 1569, 1192, 375, 1163, 565, 1163, 565,
- /* 130 */ 409, 1567, 537, 259, 226, 444, 101, 145, 449, 316,
- /* 140 */ 559, 240, 122, 122, 122, 122, 121, 121, 120, 120,
- /* 150 */ 120, 119, 116, 444, 125, 126, 80, 1217, 1217, 1050,
- /* 160 */ 1053, 1040, 1040, 123, 123, 124, 124, 124, 124, 142,
- /* 170 */ 294, 1192, 339, 448, 120, 120, 120, 119, 116, 444,
- /* 180 */ 127, 1192, 1193, 1194, 148, 441, 440, 568, 119, 116,
- /* 190 */ 444, 124, 124, 124, 124, 117, 122, 122, 122, 122,
- /* 200 */ 121, 121, 120, 120, 120, 119, 116, 444, 454, 113,
- /* 210 */ 13, 13, 546, 122, 122, 122, 122, 121, 121, 120,
- /* 220 */ 120, 120, 119, 116, 444, 422, 316, 559, 1192, 1193,
- /* 230 */ 1194, 149, 1224, 409, 1224, 124, 124, 124, 124, 122,
- /* 240 */ 122, 122, 122, 121, 121, 120, 120, 120, 119, 116,
- /* 250 */ 444, 465, 342, 1037, 1037, 1051, 1054, 125, 126, 80,
- /* 260 */ 1217, 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124,
- /* 270 */ 124, 124, 1279, 522, 222, 1192, 568, 409, 224, 514,
- /* 280 */ 175, 82, 83, 122, 122, 122, 122, 121, 121, 120,
- /* 290 */ 120, 120, 119, 116, 444, 1007, 16, 16, 1192, 133,
- /* 300 */ 133, 125, 126, 80, 1217, 1217, 1050, 1053, 1040, 1040,
- /* 310 */ 123, 123, 124, 124, 124, 124, 122, 122, 122, 122,
- /* 320 */ 121, 121, 120, 120, 120, 119, 116, 444, 1041, 546,
- /* 330 */ 1192, 373, 1192, 1193, 1194, 252, 1434, 399, 504, 501,
- /* 340 */ 500, 111, 560, 566, 4, 926, 926, 433, 499, 340,
- /* 350 */ 460, 328, 360, 394, 1237, 1192, 1193, 1194, 563, 568,
- /* 360 */ 122, 122, 122, 122, 121, 121, 120, 120, 120, 119,
- /* 370 */ 116, 444, 284, 284, 369, 1580, 1607, 441, 440, 154,
- /* 380 */ 409, 445, 71, 71, 1286, 565, 1221, 1192, 1193, 1194,
- /* 390 */ 85, 1223, 271, 557, 543, 515, 1561, 568, 98, 1222,
- /* 400 */ 6, 1278, 472, 142, 125, 126, 80, 1217, 1217, 1050,
- /* 410 */ 1053, 1040, 1040, 123, 123, 124, 124, 124, 124, 550,
- /* 420 */ 13, 13, 1027, 507, 1224, 1192, 1224, 549, 109, 109,
- /* 430 */ 222, 568, 1238, 175, 568, 427, 110, 197, 445, 570,
- /* 440 */ 569, 430, 1552, 1017, 325, 551, 1192, 270, 287, 368,
- /* 450 */ 510, 363, 509, 257, 71, 71, 543, 71, 71, 359,
- /* 460 */ 316, 559, 1613, 122, 122, 122, 122, 121, 121, 120,
- /* 470 */ 120, 120, 119, 116, 444, 1017, 1017, 1019, 1020, 27,
- /* 480 */ 284, 284, 1192, 1193, 1194, 1158, 568, 1612, 409, 901,
- /* 490 */ 190, 550, 356, 565, 550, 937, 533, 517, 1158, 516,
- /* 500 */ 413, 1158, 552, 1192, 1193, 1194, 568, 544, 1554, 51,
- /* 510 */ 51, 214, 125, 126, 80, 1217, 1217, 1050, 1053, 1040,
- /* 520 */ 1040, 123, 123, 124, 124, 124, 124, 1192, 474, 135,
- /* 530 */ 135, 409, 284, 284, 1490, 505, 121, 121, 120, 120,
- /* 540 */ 120, 119, 116, 444, 1007, 565, 518, 217, 541, 1561,
- /* 550 */ 316, 559, 142, 6, 532, 125, 126, 80, 1217, 1217,
- /* 560 */ 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124, 124,
- /* 570 */ 1555, 122, 122, 122, 122, 121, 121, 120, 120, 120,
- /* 580 */ 119, 116, 444, 485, 1192, 1193, 1194, 482, 281, 1267,
- /* 590 */ 957, 252, 1192, 373, 504, 501, 500, 1192, 340, 571,
- /* 600 */ 1192, 571, 409, 292, 499, 957, 876, 191, 480, 316,
- /* 610 */ 559, 384, 290, 380, 122, 122, 122, 122, 121, 121,
- /* 620 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1217,
- /* 630 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 640 */ 124, 409, 394, 1136, 1192, 869, 100, 284, 284, 1192,
- /* 650 */ 1193, 1194, 373, 1093, 1192, 1193, 1194, 1192, 1193, 1194,
- /* 660 */ 565, 455, 32, 373, 233, 125, 126, 80, 1217, 1217,
- /* 670 */ 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124, 124,
- /* 680 */ 1433, 959, 568, 228, 958, 122, 122, 122, 122, 121,
- /* 690 */ 121, 120, 120, 120, 119, 116, 444, 1158, 228, 1192,
- /* 700 */ 157, 1192, 1193, 1194, 1553, 13, 13, 301, 957, 1232,
- /* 710 */ 1158, 153, 409, 1158, 373, 1583, 1176, 5, 369, 1580,
- /* 720 */ 429, 1238, 3, 957, 122, 122, 122, 122, 121, 121,
- /* 730 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1217,
- /* 740 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 750 */ 124, 409, 208, 567, 1192, 1028, 1192, 1193, 1194, 1192,
- /* 760 */ 388, 852, 155, 1552, 286, 402, 1098, 1098, 488, 568,
- /* 770 */ 465, 342, 1319, 1319, 1552, 125, 126, 80, 1217, 1217,
- /* 780 */ 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124, 124,
- /* 790 */ 129, 568, 13, 13, 374, 122, 122, 122, 122, 121,
- /* 800 */ 121, 120, 120, 120, 119, 116, 444, 302, 568, 453,
- /* 810 */ 528, 1192, 1193, 1194, 13, 13, 1192, 1193, 1194, 1297,
- /* 820 */ 463, 1267, 409, 1317, 1317, 1552, 1012, 453, 452, 200,
- /* 830 */ 299, 71, 71, 1265, 122, 122, 122, 122, 121, 121,
- /* 840 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1217,
- /* 850 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 860 */ 124, 409, 227, 1073, 1158, 284, 284, 419, 312, 278,
- /* 870 */ 278, 285, 285, 1419, 406, 405, 382, 1158, 565, 568,
- /* 880 */ 1158, 1196, 565, 1600, 565, 125, 126, 80, 1217, 1217,
- /* 890 */ 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124, 124,
- /* 900 */ 453, 1482, 13, 13, 1536, 122, 122, 122, 122, 121,
- /* 910 */ 121, 120, 120, 120, 119, 116, 444, 201, 568, 354,
- /* 920 */ 1586, 575, 2, 1245, 840, 841, 842, 1562, 317, 1212,
- /* 930 */ 146, 6, 409, 255, 254, 253, 206, 1327, 9, 1196,
- /* 940 */ 262, 71, 71, 424, 122, 122, 122, 122, 121, 121,
- /* 950 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1217,
- /* 960 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 970 */ 124, 568, 284, 284, 568, 1213, 409, 574, 313, 1245,
- /* 980 */ 349, 1296, 352, 419, 317, 565, 146, 491, 525, 1643,
- /* 990 */ 395, 371, 491, 1327, 70, 70, 1295, 71, 71, 240,
- /* 1000 */ 1325, 104, 80, 1217, 1217, 1050, 1053, 1040, 1040, 123,
- /* 1010 */ 123, 124, 124, 124, 124, 122, 122, 122, 122, 121,
- /* 1020 */ 121, 120, 120, 120, 119, 116, 444, 1114, 284, 284,
- /* 1030 */ 428, 448, 1525, 1213, 439, 284, 284, 1489, 1352, 311,
- /* 1040 */ 474, 565, 1115, 971, 491, 491, 217, 1263, 565, 1538,
- /* 1050 */ 568, 972, 207, 568, 1027, 240, 383, 1116, 519, 122,
- /* 1060 */ 122, 122, 122, 121, 121, 120, 120, 120, 119, 116,
- /* 1070 */ 444, 1018, 107, 71, 71, 1017, 13, 13, 912, 568,
- /* 1080 */ 1495, 568, 284, 284, 97, 526, 491, 448, 913, 1326,
- /* 1090 */ 1322, 545, 409, 284, 284, 565, 151, 209, 1495, 1497,
- /* 1100 */ 262, 450, 55, 55, 56, 56, 565, 1017, 1017, 1019,
- /* 1110 */ 443, 332, 409, 527, 12, 295, 125, 126, 80, 1217,
- /* 1120 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 1130 */ 124, 347, 409, 864, 1534, 1213, 125, 126, 80, 1217,
- /* 1140 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 1150 */ 124, 1137, 1641, 474, 1641, 371, 125, 114, 80, 1217,
- /* 1160 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 1170 */ 124, 1495, 329, 474, 331, 122, 122, 122, 122, 121,
- /* 1180 */ 121, 120, 120, 120, 119, 116, 444, 203, 1419, 568,
- /* 1190 */ 1294, 864, 464, 1213, 436, 122, 122, 122, 122, 121,
- /* 1200 */ 121, 120, 120, 120, 119, 116, 444, 553, 1137, 1642,
- /* 1210 */ 539, 1642, 15, 15, 892, 122, 122, 122, 122, 121,
- /* 1220 */ 121, 120, 120, 120, 119, 116, 444, 568, 298, 538,
- /* 1230 */ 1135, 1419, 1559, 1560, 1331, 409, 6, 6, 1169, 1268,
- /* 1240 */ 415, 320, 284, 284, 1419, 508, 565, 525, 300, 457,
- /* 1250 */ 43, 43, 568, 893, 12, 565, 330, 478, 425, 407,
- /* 1260 */ 126, 80, 1217, 1217, 1050, 1053, 1040, 1040, 123, 123,
- /* 1270 */ 124, 124, 124, 124, 568, 57, 57, 288, 1192, 1419,
- /* 1280 */ 496, 458, 392, 392, 391, 273, 389, 1135, 1558, 849,
- /* 1290 */ 1169, 407, 6, 568, 321, 1158, 470, 44, 44, 1557,
- /* 1300 */ 1114, 426, 234, 6, 323, 256, 540, 256, 1158, 431,
- /* 1310 */ 568, 1158, 322, 17, 487, 1115, 58, 58, 122, 122,
- /* 1320 */ 122, 122, 121, 121, 120, 120, 120, 119, 116, 444,
- /* 1330 */ 1116, 216, 481, 59, 59, 1192, 1193, 1194, 111, 560,
- /* 1340 */ 324, 4, 236, 456, 526, 568, 237, 456, 568, 437,
- /* 1350 */ 168, 556, 420, 141, 479, 563, 568, 293, 568, 1095,
- /* 1360 */ 568, 293, 568, 1095, 531, 568, 872, 8, 60, 60,
- /* 1370 */ 235, 61, 61, 568, 414, 568, 414, 568, 445, 62,
- /* 1380 */ 62, 45, 45, 46, 46, 47, 47, 199, 49, 49,
- /* 1390 */ 557, 568, 359, 568, 100, 486, 50, 50, 63, 63,
- /* 1400 */ 64, 64, 561, 415, 535, 410, 568, 1027, 568, 534,
- /* 1410 */ 316, 559, 316, 559, 65, 65, 14, 14, 568, 1027,
- /* 1420 */ 568, 512, 932, 872, 1018, 109, 109, 931, 1017, 66,
- /* 1430 */ 66, 131, 131, 110, 451, 445, 570, 569, 416, 177,
- /* 1440 */ 1017, 132, 132, 67, 67, 568, 467, 568, 932, 471,
- /* 1450 */ 1364, 283, 226, 931, 315, 1363, 407, 568, 459, 407,
- /* 1460 */ 1017, 1017, 1019, 239, 407, 86, 213, 1350, 52, 52,
- /* 1470 */ 68, 68, 1017, 1017, 1019, 1020, 27, 1585, 1180, 447,
- /* 1480 */ 69, 69, 288, 97, 108, 1541, 106, 392, 392, 391,
- /* 1490 */ 273, 389, 568, 879, 849, 883, 568, 111, 560, 466,
- /* 1500 */ 4, 568, 152, 30, 38, 568, 1132, 234, 396, 323,
- /* 1510 */ 111, 560, 527, 4, 563, 53, 53, 322, 568, 163,
- /* 1520 */ 163, 568, 337, 468, 164, 164, 333, 563, 76, 76,
- /* 1530 */ 568, 289, 1514, 568, 31, 1513, 568, 445, 338, 483,
- /* 1540 */ 100, 54, 54, 344, 72, 72, 296, 236, 1080, 557,
- /* 1550 */ 445, 879, 1360, 134, 134, 168, 73, 73, 141, 161,
- /* 1560 */ 161, 1574, 557, 535, 568, 319, 568, 348, 536, 1009,
- /* 1570 */ 473, 261, 261, 891, 890, 235, 535, 568, 1027, 568,
- /* 1580 */ 475, 534, 261, 367, 109, 109, 521, 136, 136, 130,
- /* 1590 */ 130, 1027, 110, 366, 445, 570, 569, 109, 109, 1017,
- /* 1600 */ 162, 162, 156, 156, 568, 110, 1080, 445, 570, 569,
- /* 1610 */ 410, 351, 1017, 568, 353, 316, 559, 568, 343, 568,
- /* 1620 */ 100, 497, 357, 258, 100, 898, 899, 140, 140, 355,
- /* 1630 */ 1310, 1017, 1017, 1019, 1020, 27, 139, 139, 362, 451,
- /* 1640 */ 137, 137, 138, 138, 1017, 1017, 1019, 1020, 27, 1180,
- /* 1650 */ 447, 568, 372, 288, 111, 560, 1021, 4, 392, 392,
- /* 1660 */ 391, 273, 389, 568, 1141, 849, 568, 1076, 568, 258,
- /* 1670 */ 492, 563, 568, 211, 75, 75, 555, 962, 234, 261,
- /* 1680 */ 323, 111, 560, 929, 4, 113, 77, 77, 322, 74,
- /* 1690 */ 74, 42, 42, 1373, 445, 48, 48, 1418, 563, 974,
- /* 1700 */ 975, 1092, 1091, 1092, 1091, 862, 557, 150, 930, 1346,
- /* 1710 */ 113, 1358, 554, 1424, 1021, 1275, 1266, 1254, 236, 1253,
- /* 1720 */ 1255, 445, 1593, 1343, 308, 276, 168, 309, 11, 141,
- /* 1730 */ 393, 310, 232, 557, 1405, 1027, 335, 291, 1400, 219,
- /* 1740 */ 336, 109, 109, 936, 297, 1410, 235, 341, 477, 110,
- /* 1750 */ 502, 445, 570, 569, 1393, 1409, 1017, 400, 1293, 365,
- /* 1760 */ 223, 1486, 1027, 1485, 1355, 1356, 1354, 1353, 109, 109,
- /* 1770 */ 204, 1596, 1232, 558, 265, 218, 110, 205, 445, 570,
- /* 1780 */ 569, 410, 387, 1017, 1533, 179, 316, 559, 1017, 1017,
- /* 1790 */ 1019, 1020, 27, 230, 1531, 1229, 79, 560, 85, 4,
- /* 1800 */ 418, 215, 548, 81, 84, 188, 1406, 173, 181, 461,
- /* 1810 */ 451, 35, 462, 563, 183, 1017, 1017, 1019, 1020, 27,
- /* 1820 */ 184, 1491, 185, 186, 495, 242, 98, 398, 1412, 36,
- /* 1830 */ 1411, 484, 91, 469, 401, 1414, 445, 192, 1480, 246,
- /* 1840 */ 1502, 490, 346, 277, 248, 196, 493, 511, 557, 350,
- /* 1850 */ 1256, 249, 250, 403, 1313, 1312, 111, 560, 432, 4,
- /* 1860 */ 1311, 1304, 93, 1611, 883, 1610, 224, 404, 434, 520,
- /* 1870 */ 263, 435, 1579, 563, 1283, 1282, 364, 1027, 306, 1281,
- /* 1880 */ 264, 1609, 1565, 109, 109, 370, 1303, 307, 1564, 438,
- /* 1890 */ 128, 110, 1378, 445, 570, 569, 445, 546, 1017, 10,
- /* 1900 */ 1466, 105, 381, 1377, 34, 572, 99, 1336, 557, 314,
- /* 1910 */ 1186, 530, 272, 274, 379, 210, 1335, 547, 385, 386,
- /* 1920 */ 275, 573, 1251, 1246, 411, 412, 1518, 165, 178, 1519,
- /* 1930 */ 1017, 1017, 1019, 1020, 27, 1517, 1516, 1027, 78, 147,
- /* 1940 */ 166, 220, 221, 109, 109, 836, 304, 167, 446, 212,
- /* 1950 */ 318, 110, 231, 445, 570, 569, 144, 1090, 1017, 1088,
- /* 1960 */ 326, 180, 169, 1212, 182, 334, 238, 915, 241, 1104,
- /* 1970 */ 187, 170, 171, 421, 87, 88, 423, 189, 89, 90,
- /* 1980 */ 172, 1107, 243, 1103, 244, 158, 18, 245, 345, 247,
- /* 1990 */ 1017, 1017, 1019, 1020, 27, 261, 1096, 193, 1226, 489,
- /* 2000 */ 194, 37, 366, 851, 494, 251, 195, 506, 92, 19,
- /* 2010 */ 498, 358, 20, 503, 881, 361, 94, 894, 305, 159,
- /* 2020 */ 513, 39, 95, 1174, 160, 1056, 966, 1143, 96, 174,
- /* 2030 */ 1142, 225, 280, 282, 198, 960, 113, 1164, 1160, 260,
- /* 2040 */ 21, 22, 23, 1162, 1168, 1167, 1148, 24, 33, 25,
- /* 2050 */ 202, 542, 26, 100, 1071, 102, 1057, 103, 7, 1055,
- /* 2060 */ 1059, 1113, 1060, 1112, 266, 267, 28, 40, 390, 1022,
- /* 2070 */ 863, 112, 29, 564, 1182, 1181, 268, 176, 143, 925,
- /* 2080 */ 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242,
- /* 2090 */ 1242, 1242, 1242, 1242, 269, 1602, 1242, 1601,
+ /* 0 */ 572, 210, 572, 119, 116, 231, 572, 119, 116, 231,
+ /* 10 */ 572, 1317, 379, 1296, 410, 566, 566, 566, 572, 411,
+ /* 20 */ 380, 1317, 1279, 42, 42, 42, 42, 210, 1529, 72,
+ /* 30 */ 72, 974, 421, 42, 42, 495, 305, 281, 305, 975,
+ /* 40 */ 399, 72, 72, 126, 127, 81, 1217, 1217, 1054, 1057,
+ /* 50 */ 1044, 1044, 124, 124, 125, 125, 125, 125, 480, 411,
+ /* 60 */ 1244, 1, 1, 578, 2, 1248, 554, 119, 116, 231,
+ /* 70 */ 319, 484, 147, 484, 528, 119, 116, 231, 533, 1330,
+ /* 80 */ 419, 527, 143, 126, 127, 81, 1217, 1217, 1054, 1057,
+ /* 90 */ 1044, 1044, 124, 124, 125, 125, 125, 125, 119, 116,
+ /* 100 */ 231, 329, 123, 123, 123, 123, 122, 122, 121, 121,
+ /* 110 */ 121, 120, 117, 448, 286, 286, 286, 286, 446, 446,
+ /* 120 */ 446, 1568, 378, 1570, 1193, 377, 1164, 569, 1164, 569,
+ /* 130 */ 411, 1568, 541, 261, 228, 448, 102, 146, 453, 318,
+ /* 140 */ 563, 242, 123, 123, 123, 123, 122, 122, 121, 121,
+ /* 150 */ 121, 120, 117, 448, 126, 127, 81, 1217, 1217, 1054,
+ /* 160 */ 1057, 1044, 1044, 124, 124, 125, 125, 125, 125, 143,
+ /* 170 */ 296, 1193, 341, 452, 121, 121, 121, 120, 117, 448,
+ /* 180 */ 128, 1193, 1194, 1193, 149, 445, 444, 572, 120, 117,
+ /* 190 */ 448, 125, 125, 125, 125, 118, 123, 123, 123, 123,
+ /* 200 */ 122, 122, 121, 121, 121, 120, 117, 448, 458, 114,
+ /* 210 */ 13, 13, 550, 123, 123, 123, 123, 122, 122, 121,
+ /* 220 */ 121, 121, 120, 117, 448, 424, 318, 563, 1193, 1194,
+ /* 230 */ 1193, 150, 1225, 411, 1225, 125, 125, 125, 125, 123,
+ /* 240 */ 123, 123, 123, 122, 122, 121, 121, 121, 120, 117,
+ /* 250 */ 448, 469, 344, 1041, 1041, 1055, 1058, 126, 127, 81,
+ /* 260 */ 1217, 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125,
+ /* 270 */ 125, 125, 1282, 526, 224, 1193, 572, 411, 226, 519,
+ /* 280 */ 177, 83, 84, 123, 123, 123, 123, 122, 122, 121,
+ /* 290 */ 121, 121, 120, 117, 448, 1010, 16, 16, 1193, 134,
+ /* 300 */ 134, 126, 127, 81, 1217, 1217, 1054, 1057, 1044, 1044,
+ /* 310 */ 124, 124, 125, 125, 125, 125, 123, 123, 123, 123,
+ /* 320 */ 122, 122, 121, 121, 121, 120, 117, 448, 1045, 550,
+ /* 330 */ 1193, 375, 1193, 1194, 1193, 254, 1438, 401, 508, 505,
+ /* 340 */ 504, 112, 564, 570, 4, 929, 929, 435, 503, 342,
+ /* 350 */ 464, 330, 362, 396, 1238, 1193, 1194, 1193, 567, 572,
+ /* 360 */ 123, 123, 123, 123, 122, 122, 121, 121, 121, 120,
+ /* 370 */ 117, 448, 286, 286, 371, 1581, 1607, 445, 444, 155,
+ /* 380 */ 411, 449, 72, 72, 1289, 569, 1222, 1193, 1194, 1193,
+ /* 390 */ 86, 1224, 273, 561, 547, 520, 520, 572, 99, 1223,
+ /* 400 */ 6, 1281, 476, 143, 126, 127, 81, 1217, 1217, 1054,
+ /* 410 */ 1057, 1044, 1044, 124, 124, 125, 125, 125, 125, 554,
+ /* 420 */ 13, 13, 1031, 511, 1225, 1193, 1225, 553, 110, 110,
+ /* 430 */ 224, 572, 1239, 177, 572, 429, 111, 199, 449, 573,
+ /* 440 */ 449, 432, 1555, 1019, 327, 555, 1193, 272, 289, 370,
+ /* 450 */ 514, 365, 513, 259, 72, 72, 547, 72, 72, 361,
+ /* 460 */ 318, 563, 1613, 123, 123, 123, 123, 122, 122, 121,
+ /* 470 */ 121, 121, 120, 117, 448, 1019, 1019, 1021, 1022, 28,
+ /* 480 */ 286, 286, 1193, 1194, 1193, 1159, 572, 1612, 411, 904,
+ /* 490 */ 192, 554, 358, 569, 554, 940, 537, 521, 1159, 437,
+ /* 500 */ 415, 1159, 556, 1193, 1194, 1193, 572, 548, 548, 52,
+ /* 510 */ 52, 216, 126, 127, 81, 1217, 1217, 1054, 1057, 1044,
+ /* 520 */ 1044, 124, 124, 125, 125, 125, 125, 1193, 478, 136,
+ /* 530 */ 136, 411, 286, 286, 1493, 509, 122, 122, 121, 121,
+ /* 540 */ 121, 120, 117, 448, 1010, 569, 522, 219, 545, 545,
+ /* 550 */ 318, 563, 143, 6, 536, 126, 127, 81, 1217, 1217,
+ /* 560 */ 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, 125,
+ /* 570 */ 1557, 123, 123, 123, 123, 122, 122, 121, 121, 121,
+ /* 580 */ 120, 117, 448, 489, 1193, 1194, 1193, 486, 283, 1270,
+ /* 590 */ 960, 254, 1193, 375, 508, 505, 504, 1193, 342, 574,
+ /* 600 */ 1193, 574, 411, 294, 503, 960, 879, 193, 484, 318,
+ /* 610 */ 563, 386, 292, 382, 123, 123, 123, 123, 122, 122,
+ /* 620 */ 121, 121, 121, 120, 117, 448, 126, 127, 81, 1217,
+ /* 630 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125,
+ /* 640 */ 125, 411, 396, 1139, 1193, 872, 101, 286, 286, 1193,
+ /* 650 */ 1194, 1193, 375, 1096, 1193, 1194, 1193, 1193, 1194, 1193,
+ /* 660 */ 569, 459, 33, 375, 235, 126, 127, 81, 1217, 1217,
+ /* 670 */ 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, 125,
+ /* 680 */ 1437, 962, 572, 230, 961, 123, 123, 123, 123, 122,
+ /* 690 */ 122, 121, 121, 121, 120, 117, 448, 1159, 230, 1193,
+ /* 700 */ 158, 1193, 1194, 1193, 1556, 13, 13, 303, 960, 1233,
+ /* 710 */ 1159, 154, 411, 1159, 375, 1584, 1177, 5, 371, 1581,
+ /* 720 */ 431, 1239, 3, 960, 123, 123, 123, 123, 122, 122,
+ /* 730 */ 121, 121, 121, 120, 117, 448, 126, 127, 81, 1217,
+ /* 740 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125,
+ /* 750 */ 125, 411, 210, 571, 1193, 1032, 1193, 1194, 1193, 1193,
+ /* 760 */ 390, 855, 156, 1555, 376, 404, 1101, 1101, 492, 572,
+ /* 770 */ 469, 344, 1322, 1322, 1555, 126, 127, 81, 1217, 1217,
+ /* 780 */ 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, 125,
+ /* 790 */ 130, 572, 13, 13, 532, 123, 123, 123, 123, 122,
+ /* 800 */ 122, 121, 121, 121, 120, 117, 448, 304, 572, 457,
+ /* 810 */ 229, 1193, 1194, 1193, 13, 13, 1193, 1194, 1193, 1300,
+ /* 820 */ 467, 1270, 411, 1320, 1320, 1555, 1015, 457, 456, 436,
+ /* 830 */ 301, 72, 72, 1268, 123, 123, 123, 123, 122, 122,
+ /* 840 */ 121, 121, 121, 120, 117, 448, 126, 127, 81, 1217,
+ /* 850 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125,
+ /* 860 */ 125, 411, 384, 1076, 1159, 286, 286, 421, 314, 280,
+ /* 870 */ 280, 287, 287, 461, 408, 407, 1539, 1159, 569, 572,
+ /* 880 */ 1159, 1196, 569, 409, 569, 126, 127, 81, 1217, 1217,
+ /* 890 */ 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125, 125,
+ /* 900 */ 457, 1485, 13, 13, 1541, 123, 123, 123, 123, 122,
+ /* 910 */ 122, 121, 121, 121, 120, 117, 448, 202, 572, 462,
+ /* 920 */ 1587, 578, 2, 1248, 843, 844, 845, 1563, 319, 409,
+ /* 930 */ 147, 6, 411, 257, 256, 255, 208, 1330, 9, 1196,
+ /* 940 */ 264, 72, 72, 1436, 123, 123, 123, 123, 122, 122,
+ /* 950 */ 121, 121, 121, 120, 117, 448, 126, 127, 81, 1217,
+ /* 960 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125,
+ /* 970 */ 125, 572, 286, 286, 572, 1213, 411, 577, 315, 1248,
+ /* 980 */ 421, 371, 1581, 356, 319, 569, 147, 495, 529, 1644,
+ /* 990 */ 397, 935, 495, 1330, 71, 71, 934, 72, 72, 242,
+ /* 1000 */ 1328, 105, 81, 1217, 1217, 1054, 1057, 1044, 1044, 124,
+ /* 1010 */ 124, 125, 125, 125, 125, 123, 123, 123, 123, 122,
+ /* 1020 */ 122, 121, 121, 121, 120, 117, 448, 1117, 286, 286,
+ /* 1030 */ 1422, 452, 1528, 1213, 443, 286, 286, 1492, 1355, 313,
+ /* 1040 */ 478, 569, 1118, 454, 351, 495, 354, 1266, 569, 209,
+ /* 1050 */ 572, 418, 179, 572, 1031, 242, 385, 1119, 523, 123,
+ /* 1060 */ 123, 123, 123, 122, 122, 121, 121, 121, 120, 117,
+ /* 1070 */ 448, 1020, 108, 72, 72, 1019, 13, 13, 915, 572,
+ /* 1080 */ 1498, 572, 286, 286, 98, 530, 1537, 452, 916, 1334,
+ /* 1090 */ 1329, 203, 411, 286, 286, 569, 152, 211, 1498, 1500,
+ /* 1100 */ 426, 569, 56, 56, 57, 57, 569, 1019, 1019, 1021,
+ /* 1110 */ 447, 572, 411, 531, 12, 297, 126, 127, 81, 1217,
+ /* 1120 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125,
+ /* 1130 */ 125, 572, 411, 867, 15, 15, 126, 127, 81, 1217,
+ /* 1140 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125,
+ /* 1150 */ 125, 373, 529, 264, 44, 44, 126, 115, 81, 1217,
+ /* 1160 */ 1217, 1054, 1057, 1044, 1044, 124, 124, 125, 125, 125,
+ /* 1170 */ 125, 1498, 478, 1271, 417, 123, 123, 123, 123, 122,
+ /* 1180 */ 122, 121, 121, 121, 120, 117, 448, 205, 1213, 495,
+ /* 1190 */ 430, 867, 468, 322, 495, 123, 123, 123, 123, 122,
+ /* 1200 */ 122, 121, 121, 121, 120, 117, 448, 572, 557, 1140,
+ /* 1210 */ 1642, 1422, 1642, 543, 572, 123, 123, 123, 123, 122,
+ /* 1220 */ 122, 121, 121, 121, 120, 117, 448, 572, 1422, 572,
+ /* 1230 */ 13, 13, 542, 323, 1325, 411, 334, 58, 58, 349,
+ /* 1240 */ 1422, 1170, 326, 286, 286, 549, 1213, 300, 895, 530,
+ /* 1250 */ 45, 45, 59, 59, 1140, 1643, 569, 1643, 565, 417,
+ /* 1260 */ 127, 81, 1217, 1217, 1054, 1057, 1044, 1044, 124, 124,
+ /* 1270 */ 125, 125, 125, 125, 1367, 373, 500, 290, 1193, 512,
+ /* 1280 */ 1366, 427, 394, 394, 393, 275, 391, 896, 1138, 852,
+ /* 1290 */ 478, 258, 1422, 1170, 463, 1159, 12, 331, 428, 333,
+ /* 1300 */ 1117, 460, 236, 258, 325, 460, 544, 1544, 1159, 1098,
+ /* 1310 */ 491, 1159, 324, 1098, 440, 1118, 335, 516, 123, 123,
+ /* 1320 */ 123, 123, 122, 122, 121, 121, 121, 120, 117, 448,
+ /* 1330 */ 1119, 318, 563, 1138, 572, 1193, 1194, 1193, 112, 564,
+ /* 1340 */ 201, 4, 238, 433, 935, 490, 285, 228, 1517, 934,
+ /* 1350 */ 170, 560, 572, 142, 1516, 567, 572, 60, 60, 572,
+ /* 1360 */ 416, 572, 441, 572, 535, 302, 875, 8, 487, 572,
+ /* 1370 */ 237, 572, 416, 572, 485, 61, 61, 572, 449, 62,
+ /* 1380 */ 62, 332, 63, 63, 46, 46, 47, 47, 361, 572,
+ /* 1390 */ 561, 572, 48, 48, 50, 50, 51, 51, 572, 295,
+ /* 1400 */ 64, 64, 482, 295, 539, 412, 471, 1031, 572, 538,
+ /* 1410 */ 318, 563, 65, 65, 66, 66, 409, 475, 572, 1031,
+ /* 1420 */ 572, 14, 14, 875, 1020, 110, 110, 409, 1019, 572,
+ /* 1430 */ 474, 67, 67, 111, 455, 449, 573, 449, 98, 317,
+ /* 1440 */ 1019, 132, 132, 133, 133, 572, 1561, 572, 974, 409,
+ /* 1450 */ 6, 1562, 68, 68, 1560, 6, 975, 572, 6, 1559,
+ /* 1460 */ 1019, 1019, 1021, 6, 346, 218, 101, 531, 53, 53,
+ /* 1470 */ 69, 69, 1019, 1019, 1021, 1022, 28, 1586, 1181, 451,
+ /* 1480 */ 70, 70, 290, 87, 215, 31, 1363, 394, 394, 393,
+ /* 1490 */ 275, 391, 350, 109, 852, 107, 572, 112, 564, 483,
+ /* 1500 */ 4, 1212, 572, 239, 153, 572, 39, 236, 1299, 325,
+ /* 1510 */ 112, 564, 1298, 4, 567, 572, 32, 324, 572, 54,
+ /* 1520 */ 54, 572, 1135, 353, 398, 165, 165, 567, 166, 166,
+ /* 1530 */ 572, 291, 355, 572, 17, 357, 572, 449, 77, 77,
+ /* 1540 */ 1313, 55, 55, 1297, 73, 73, 572, 238, 470, 561,
+ /* 1550 */ 449, 472, 364, 135, 135, 170, 74, 74, 142, 163,
+ /* 1560 */ 163, 374, 561, 539, 572, 321, 572, 886, 540, 137,
+ /* 1570 */ 137, 339, 1353, 422, 298, 237, 539, 572, 1031, 572,
+ /* 1580 */ 340, 538, 101, 369, 110, 110, 162, 131, 131, 164,
+ /* 1590 */ 164, 1031, 111, 368, 449, 573, 449, 110, 110, 1019,
+ /* 1600 */ 157, 157, 141, 141, 572, 111, 572, 449, 573, 449,
+ /* 1610 */ 412, 288, 1019, 572, 882, 318, 563, 572, 219, 572,
+ /* 1620 */ 241, 1012, 477, 263, 263, 894, 893, 140, 140, 138,
+ /* 1630 */ 138, 1019, 1019, 1021, 1022, 28, 139, 139, 525, 455,
+ /* 1640 */ 76, 76, 78, 78, 1019, 1019, 1021, 1022, 28, 1181,
+ /* 1650 */ 451, 572, 1083, 290, 112, 564, 1575, 4, 394, 394,
+ /* 1660 */ 393, 275, 391, 572, 1023, 852, 572, 479, 345, 263,
+ /* 1670 */ 101, 567, 882, 1376, 75, 75, 1421, 501, 236, 260,
+ /* 1680 */ 325, 112, 564, 359, 4, 101, 43, 43, 324, 49,
+ /* 1690 */ 49, 901, 902, 161, 449, 101, 977, 978, 567, 1079,
+ /* 1700 */ 1349, 260, 965, 932, 263, 114, 561, 1095, 517, 1095,
+ /* 1710 */ 1083, 1094, 865, 1094, 151, 933, 1144, 114, 238, 1361,
+ /* 1720 */ 558, 449, 1023, 559, 1426, 1278, 170, 1269, 1257, 142,
+ /* 1730 */ 1601, 1256, 1258, 561, 1594, 1031, 496, 278, 213, 1346,
+ /* 1740 */ 310, 110, 110, 939, 311, 312, 237, 11, 234, 111,
+ /* 1750 */ 221, 449, 573, 449, 293, 395, 1019, 1408, 337, 1403,
+ /* 1760 */ 1396, 338, 1031, 299, 343, 1413, 1412, 481, 110, 110,
+ /* 1770 */ 506, 402, 225, 1296, 206, 367, 111, 1358, 449, 573,
+ /* 1780 */ 449, 412, 1359, 1019, 1489, 1488, 318, 563, 1019, 1019,
+ /* 1790 */ 1021, 1022, 28, 562, 207, 220, 80, 564, 389, 4,
+ /* 1800 */ 1597, 1357, 552, 1356, 1233, 181, 267, 232, 1536, 1534,
+ /* 1810 */ 455, 1230, 420, 567, 82, 1019, 1019, 1021, 1022, 28,
+ /* 1820 */ 86, 217, 85, 1494, 190, 175, 183, 465, 185, 466,
+ /* 1830 */ 36, 1409, 186, 187, 188, 499, 449, 244, 37, 99,
+ /* 1840 */ 400, 1415, 1414, 488, 1417, 194, 473, 403, 561, 1483,
+ /* 1850 */ 248, 92, 1505, 494, 198, 279, 112, 564, 250, 4,
+ /* 1860 */ 348, 497, 405, 352, 1259, 251, 252, 515, 1316, 434,
+ /* 1870 */ 1315, 1314, 94, 567, 1307, 886, 1306, 1031, 226, 406,
+ /* 1880 */ 1611, 1610, 438, 110, 110, 1580, 1286, 524, 439, 308,
+ /* 1890 */ 266, 111, 1285, 449, 573, 449, 449, 309, 1019, 366,
+ /* 1900 */ 1284, 1609, 265, 1566, 1565, 442, 372, 1381, 561, 129,
+ /* 1910 */ 550, 1380, 10, 1470, 383, 106, 316, 551, 100, 35,
+ /* 1920 */ 534, 575, 212, 1339, 381, 387, 1187, 1338, 274, 276,
+ /* 1930 */ 1019, 1019, 1021, 1022, 28, 277, 413, 1031, 576, 1254,
+ /* 1940 */ 388, 1521, 1249, 110, 110, 167, 1522, 168, 148, 1520,
+ /* 1950 */ 1519, 111, 306, 449, 573, 449, 222, 223, 1019, 839,
+ /* 1960 */ 169, 79, 450, 214, 414, 233, 320, 145, 1093, 1091,
+ /* 1970 */ 328, 182, 171, 1212, 918, 184, 240, 336, 243, 1107,
+ /* 1980 */ 189, 172, 173, 423, 425, 88, 180, 191, 89, 90,
+ /* 1990 */ 1019, 1019, 1021, 1022, 28, 91, 174, 1110, 245, 1106,
+ /* 2000 */ 246, 159, 18, 247, 347, 1099, 263, 195, 1227, 493,
+ /* 2010 */ 249, 196, 38, 854, 498, 368, 253, 360, 897, 197,
+ /* 2020 */ 502, 93, 19, 20, 507, 884, 363, 510, 95, 307,
+ /* 2030 */ 160, 96, 518, 97, 1175, 1060, 1146, 40, 21, 227,
+ /* 2040 */ 176, 1145, 282, 284, 969, 200, 963, 114, 262, 1165,
+ /* 2050 */ 22, 23, 24, 1161, 1169, 25, 1163, 1150, 34, 26,
+ /* 2060 */ 1168, 546, 27, 204, 101, 103, 104, 1074, 7, 1061,
+ /* 2070 */ 1059, 1063, 1116, 1064, 1115, 268, 269, 29, 41, 270,
+ /* 2080 */ 1024, 866, 113, 30, 568, 392, 1183, 144, 178, 1182,
+ /* 2090 */ 271, 928, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1602,
};
static const YYCODETYPE yy_lookahead[] = {
/* 0 */ 193, 193, 193, 274, 275, 276, 193, 274, 275, 276,
@@ -167653,7 +172006,7 @@ static const YYCODETYPE yy_lookahead[] = {
/* 730 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46,
/* 740 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
/* 750 */ 57, 19, 193, 193, 59, 23, 116, 117, 118, 59,
- /* 760 */ 201, 21, 241, 304, 22, 206, 127, 128, 129, 193,
+ /* 760 */ 201, 21, 241, 304, 193, 206, 127, 128, 129, 193,
/* 770 */ 128, 129, 235, 236, 304, 43, 44, 45, 46, 47,
/* 780 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
/* 790 */ 22, 193, 216, 217, 193, 102, 103, 104, 105, 106,
@@ -167664,129 +172017,129 @@ static const YYCODETYPE yy_lookahead[] = {
/* 840 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46,
/* 850 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
/* 860 */ 57, 19, 193, 123, 76, 239, 240, 193, 253, 239,
- /* 870 */ 240, 239, 240, 193, 106, 107, 193, 89, 252, 193,
- /* 880 */ 92, 59, 252, 141, 252, 43, 44, 45, 46, 47,
+ /* 870 */ 240, 239, 240, 244, 106, 107, 193, 89, 252, 193,
+ /* 880 */ 92, 59, 252, 254, 252, 43, 44, 45, 46, 47,
/* 890 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
/* 900 */ 284, 161, 216, 217, 193, 102, 103, 104, 105, 106,
- /* 910 */ 107, 108, 109, 110, 111, 112, 113, 231, 193, 16,
- /* 920 */ 187, 188, 189, 190, 7, 8, 9, 309, 195, 25,
+ /* 910 */ 107, 108, 109, 110, 111, 112, 113, 231, 193, 244,
+ /* 920 */ 187, 188, 189, 190, 7, 8, 9, 309, 195, 254,
/* 930 */ 197, 313, 19, 127, 128, 129, 262, 204, 22, 117,
- /* 940 */ 24, 216, 217, 263, 102, 103, 104, 105, 106, 107,
+ /* 940 */ 24, 216, 217, 273, 102, 103, 104, 105, 106, 107,
/* 950 */ 108, 109, 110, 111, 112, 113, 43, 44, 45, 46,
/* 960 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
/* 970 */ 57, 193, 239, 240, 193, 59, 19, 188, 253, 190,
- /* 980 */ 77, 226, 79, 193, 195, 252, 197, 193, 19, 301,
- /* 990 */ 302, 193, 193, 204, 216, 217, 226, 216, 217, 266,
+ /* 980 */ 193, 311, 312, 16, 195, 252, 197, 193, 19, 301,
+ /* 990 */ 302, 135, 193, 204, 216, 217, 140, 216, 217, 266,
/* 1000 */ 204, 159, 45, 46, 47, 48, 49, 50, 51, 52,
/* 1010 */ 53, 54, 55, 56, 57, 102, 103, 104, 105, 106,
/* 1020 */ 107, 108, 109, 110, 111, 112, 113, 12, 239, 240,
- /* 1030 */ 232, 298, 238, 117, 253, 239, 240, 238, 259, 260,
- /* 1040 */ 193, 252, 27, 31, 193, 193, 142, 204, 252, 193,
- /* 1050 */ 193, 39, 262, 193, 100, 266, 278, 42, 204, 102,
+ /* 1030 */ 193, 298, 238, 117, 253, 239, 240, 238, 259, 260,
+ /* 1040 */ 193, 252, 27, 193, 77, 193, 79, 204, 252, 262,
+ /* 1050 */ 193, 299, 300, 193, 100, 266, 278, 42, 204, 102,
/* 1060 */ 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
/* 1070 */ 113, 117, 159, 216, 217, 121, 216, 217, 63, 193,
- /* 1080 */ 193, 193, 239, 240, 115, 116, 193, 298, 73, 238,
+ /* 1080 */ 193, 193, 239, 240, 115, 116, 193, 298, 73, 240,
/* 1090 */ 238, 231, 19, 239, 240, 252, 22, 24, 211, 212,
- /* 1100 */ 24, 193, 216, 217, 216, 217, 252, 153, 154, 155,
- /* 1110 */ 253, 16, 19, 144, 213, 268, 43, 44, 45, 46,
+ /* 1100 */ 263, 252, 216, 217, 216, 217, 252, 153, 154, 155,
+ /* 1110 */ 253, 193, 19, 144, 213, 268, 43, 44, 45, 46,
/* 1120 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 1130 */ 57, 238, 19, 59, 193, 59, 43, 44, 45, 46,
+ /* 1130 */ 57, 193, 19, 59, 216, 217, 43, 44, 45, 46,
/* 1140 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 1150 */ 57, 22, 23, 193, 25, 193, 43, 44, 45, 46,
+ /* 1150 */ 57, 193, 19, 24, 216, 217, 43, 44, 45, 46,
/* 1160 */ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
- /* 1170 */ 57, 284, 77, 193, 79, 102, 103, 104, 105, 106,
- /* 1180 */ 107, 108, 109, 110, 111, 112, 113, 286, 193, 193,
- /* 1190 */ 193, 117, 291, 117, 232, 102, 103, 104, 105, 106,
- /* 1200 */ 107, 108, 109, 110, 111, 112, 113, 204, 22, 23,
- /* 1210 */ 66, 25, 216, 217, 35, 102, 103, 104, 105, 106,
- /* 1220 */ 107, 108, 109, 110, 111, 112, 113, 193, 268, 85,
- /* 1230 */ 101, 193, 309, 309, 240, 19, 313, 313, 94, 208,
- /* 1240 */ 209, 193, 239, 240, 193, 66, 252, 19, 268, 244,
- /* 1250 */ 216, 217, 193, 74, 213, 252, 161, 19, 263, 254,
+ /* 1170 */ 57, 284, 193, 208, 209, 102, 103, 104, 105, 106,
+ /* 1180 */ 107, 108, 109, 110, 111, 112, 113, 286, 59, 193,
+ /* 1190 */ 232, 117, 291, 193, 193, 102, 103, 104, 105, 106,
+ /* 1200 */ 107, 108, 109, 110, 111, 112, 113, 193, 204, 22,
+ /* 1210 */ 23, 193, 25, 66, 193, 102, 103, 104, 105, 106,
+ /* 1220 */ 107, 108, 109, 110, 111, 112, 113, 193, 193, 193,
+ /* 1230 */ 216, 217, 85, 193, 238, 19, 16, 216, 217, 238,
+ /* 1240 */ 193, 94, 193, 239, 240, 231, 117, 268, 35, 116,
+ /* 1250 */ 216, 217, 216, 217, 22, 23, 252, 25, 208, 209,
/* 1260 */ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
- /* 1270 */ 54, 55, 56, 57, 193, 216, 217, 5, 59, 193,
- /* 1280 */ 19, 244, 10, 11, 12, 13, 14, 101, 309, 17,
- /* 1290 */ 146, 254, 313, 193, 193, 76, 115, 216, 217, 309,
- /* 1300 */ 12, 263, 30, 313, 32, 46, 87, 46, 89, 130,
- /* 1310 */ 193, 92, 40, 22, 263, 27, 216, 217, 102, 103,
+ /* 1270 */ 54, 55, 56, 57, 193, 193, 19, 5, 59, 66,
+ /* 1280 */ 193, 263, 10, 11, 12, 13, 14, 74, 101, 17,
+ /* 1290 */ 193, 46, 193, 146, 193, 76, 213, 77, 263, 79,
+ /* 1300 */ 12, 260, 30, 46, 32, 264, 87, 193, 89, 29,
+ /* 1310 */ 263, 92, 40, 33, 232, 27, 193, 108, 102, 103,
/* 1320 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
- /* 1330 */ 42, 150, 291, 216, 217, 116, 117, 118, 19, 20,
- /* 1340 */ 193, 22, 70, 260, 116, 193, 24, 264, 193, 263,
- /* 1350 */ 78, 63, 61, 81, 116, 36, 193, 260, 193, 29,
- /* 1360 */ 193, 264, 193, 33, 145, 193, 59, 48, 216, 217,
- /* 1370 */ 98, 216, 217, 193, 115, 193, 115, 193, 59, 216,
- /* 1380 */ 217, 216, 217, 216, 217, 216, 217, 255, 216, 217,
- /* 1390 */ 71, 193, 131, 193, 25, 65, 216, 217, 216, 217,
- /* 1400 */ 216, 217, 208, 209, 85, 133, 193, 100, 193, 90,
- /* 1410 */ 138, 139, 138, 139, 216, 217, 216, 217, 193, 100,
- /* 1420 */ 193, 108, 135, 116, 117, 106, 107, 140, 121, 216,
- /* 1430 */ 217, 216, 217, 114, 162, 116, 117, 118, 299, 300,
- /* 1440 */ 121, 216, 217, 216, 217, 193, 244, 193, 135, 244,
- /* 1450 */ 193, 256, 257, 140, 244, 193, 254, 193, 193, 254,
- /* 1460 */ 153, 154, 155, 141, 254, 149, 150, 258, 216, 217,
+ /* 1330 */ 42, 138, 139, 101, 193, 116, 117, 118, 19, 20,
+ /* 1340 */ 255, 22, 70, 130, 135, 65, 256, 257, 193, 140,
+ /* 1350 */ 78, 63, 193, 81, 193, 36, 193, 216, 217, 193,
+ /* 1360 */ 115, 193, 263, 193, 145, 268, 59, 48, 193, 193,
+ /* 1370 */ 98, 193, 115, 193, 291, 216, 217, 193, 59, 216,
+ /* 1380 */ 217, 161, 216, 217, 216, 217, 216, 217, 131, 193,
+ /* 1390 */ 71, 193, 216, 217, 216, 217, 216, 217, 193, 260,
+ /* 1400 */ 216, 217, 19, 264, 85, 133, 244, 100, 193, 90,
+ /* 1410 */ 138, 139, 216, 217, 216, 217, 254, 244, 193, 100,
+ /* 1420 */ 193, 216, 217, 116, 117, 106, 107, 254, 121, 193,
+ /* 1430 */ 115, 216, 217, 114, 162, 116, 117, 118, 115, 244,
+ /* 1440 */ 121, 216, 217, 216, 217, 193, 309, 193, 31, 254,
+ /* 1450 */ 313, 309, 216, 217, 309, 313, 39, 193, 313, 309,
+ /* 1460 */ 153, 154, 155, 313, 193, 150, 25, 144, 216, 217,
/* 1470 */ 216, 217, 153, 154, 155, 156, 157, 0, 1, 2,
- /* 1480 */ 216, 217, 5, 115, 158, 193, 160, 10, 11, 12,
- /* 1490 */ 13, 14, 193, 59, 17, 126, 193, 19, 20, 129,
- /* 1500 */ 22, 193, 22, 22, 24, 193, 23, 30, 25, 32,
- /* 1510 */ 19, 20, 144, 22, 36, 216, 217, 40, 193, 216,
- /* 1520 */ 217, 193, 152, 129, 216, 217, 193, 36, 216, 217,
- /* 1530 */ 193, 99, 193, 193, 53, 193, 193, 59, 23, 193,
- /* 1540 */ 25, 216, 217, 193, 216, 217, 152, 70, 59, 71,
- /* 1550 */ 59, 117, 193, 216, 217, 78, 216, 217, 81, 216,
- /* 1560 */ 217, 318, 71, 85, 193, 133, 193, 193, 90, 23,
- /* 1570 */ 23, 25, 25, 120, 121, 98, 85, 193, 100, 193,
- /* 1580 */ 23, 90, 25, 121, 106, 107, 19, 216, 217, 216,
+ /* 1480 */ 216, 217, 5, 149, 150, 22, 193, 10, 11, 12,
+ /* 1490 */ 13, 14, 193, 158, 17, 160, 193, 19, 20, 116,
+ /* 1500 */ 22, 25, 193, 24, 22, 193, 24, 30, 226, 32,
+ /* 1510 */ 19, 20, 226, 22, 36, 193, 53, 40, 193, 216,
+ /* 1520 */ 217, 193, 23, 193, 25, 216, 217, 36, 216, 217,
+ /* 1530 */ 193, 99, 193, 193, 22, 193, 193, 59, 216, 217,
+ /* 1540 */ 193, 216, 217, 193, 216, 217, 193, 70, 129, 71,
+ /* 1550 */ 59, 129, 193, 216, 217, 78, 216, 217, 81, 216,
+ /* 1560 */ 217, 193, 71, 85, 193, 133, 193, 126, 90, 216,
+ /* 1570 */ 217, 152, 258, 61, 152, 98, 85, 193, 100, 193,
+ /* 1580 */ 23, 90, 25, 121, 106, 107, 23, 216, 217, 216,
/* 1590 */ 217, 100, 114, 131, 116, 117, 118, 106, 107, 121,
- /* 1600 */ 216, 217, 216, 217, 193, 114, 117, 116, 117, 118,
- /* 1610 */ 133, 193, 121, 193, 193, 138, 139, 193, 23, 193,
- /* 1620 */ 25, 23, 23, 25, 25, 7, 8, 216, 217, 193,
- /* 1630 */ 193, 153, 154, 155, 156, 157, 216, 217, 193, 162,
+ /* 1600 */ 216, 217, 216, 217, 193, 114, 193, 116, 117, 118,
+ /* 1610 */ 133, 22, 121, 193, 59, 138, 139, 193, 142, 193,
+ /* 1620 */ 141, 23, 23, 25, 25, 120, 121, 216, 217, 216,
+ /* 1630 */ 217, 153, 154, 155, 156, 157, 216, 217, 19, 162,
/* 1640 */ 216, 217, 216, 217, 153, 154, 155, 156, 157, 1,
- /* 1650 */ 2, 193, 193, 5, 19, 20, 59, 22, 10, 11,
- /* 1660 */ 12, 13, 14, 193, 97, 17, 193, 23, 193, 25,
- /* 1670 */ 288, 36, 193, 242, 216, 217, 236, 23, 30, 25,
+ /* 1650 */ 2, 193, 59, 5, 19, 20, 318, 22, 10, 11,
+ /* 1660 */ 12, 13, 14, 193, 59, 17, 193, 23, 23, 25,
+ /* 1670 */ 25, 36, 117, 193, 216, 217, 193, 23, 30, 25,
/* 1680 */ 32, 19, 20, 23, 22, 25, 216, 217, 40, 216,
- /* 1690 */ 217, 216, 217, 193, 59, 216, 217, 193, 36, 83,
- /* 1700 */ 84, 153, 153, 155, 155, 23, 71, 25, 23, 193,
- /* 1710 */ 25, 193, 193, 193, 117, 193, 193, 193, 70, 193,
- /* 1720 */ 193, 59, 193, 255, 255, 287, 78, 255, 243, 81,
- /* 1730 */ 191, 255, 297, 71, 271, 100, 293, 245, 267, 214,
- /* 1740 */ 246, 106, 107, 108, 246, 271, 98, 245, 293, 114,
- /* 1750 */ 220, 116, 117, 118, 267, 271, 121, 271, 225, 219,
- /* 1760 */ 229, 219, 100, 219, 259, 259, 259, 259, 106, 107,
- /* 1770 */ 249, 196, 60, 280, 141, 243, 114, 249, 116, 117,
- /* 1780 */ 118, 133, 245, 121, 200, 297, 138, 139, 153, 154,
- /* 1790 */ 155, 156, 157, 297, 200, 38, 19, 20, 151, 22,
- /* 1800 */ 200, 150, 140, 294, 294, 22, 272, 43, 234, 18,
- /* 1810 */ 162, 270, 200, 36, 237, 153, 154, 155, 156, 157,
- /* 1820 */ 237, 283, 237, 237, 18, 199, 149, 246, 272, 270,
- /* 1830 */ 272, 200, 158, 246, 246, 234, 59, 234, 246, 199,
- /* 1840 */ 290, 62, 289, 200, 199, 22, 221, 115, 71, 200,
- /* 1850 */ 200, 199, 199, 221, 218, 218, 19, 20, 64, 22,
- /* 1860 */ 218, 227, 22, 224, 126, 224, 165, 221, 24, 305,
- /* 1870 */ 200, 113, 312, 36, 218, 220, 218, 100, 282, 218,
- /* 1880 */ 91, 218, 317, 106, 107, 221, 227, 282, 317, 82,
- /* 1890 */ 148, 114, 265, 116, 117, 118, 59, 145, 121, 22,
- /* 1900 */ 277, 158, 200, 265, 25, 202, 147, 250, 71, 279,
- /* 1910 */ 13, 146, 194, 194, 249, 248, 250, 140, 247, 246,
- /* 1920 */ 6, 192, 192, 192, 303, 303, 213, 207, 300, 213,
- /* 1930 */ 153, 154, 155, 156, 157, 213, 213, 100, 213, 222,
- /* 1940 */ 207, 214, 214, 106, 107, 4, 222, 207, 3, 22,
- /* 1950 */ 163, 114, 15, 116, 117, 118, 16, 23, 121, 23,
- /* 1960 */ 139, 151, 130, 25, 142, 16, 24, 20, 144, 1,
- /* 1970 */ 142, 130, 130, 61, 53, 53, 37, 151, 53, 53,
- /* 1980 */ 130, 116, 34, 1, 141, 5, 22, 115, 161, 141,
- /* 1990 */ 153, 154, 155, 156, 157, 25, 68, 68, 75, 41,
- /* 2000 */ 115, 24, 131, 20, 19, 125, 22, 96, 22, 22,
- /* 2010 */ 67, 23, 22, 67, 59, 24, 22, 28, 67, 23,
- /* 2020 */ 22, 22, 149, 23, 23, 23, 116, 23, 25, 37,
- /* 2030 */ 97, 141, 23, 23, 22, 143, 25, 75, 88, 34,
- /* 2040 */ 34, 34, 34, 86, 75, 93, 23, 34, 22, 34,
- /* 2050 */ 25, 24, 34, 25, 23, 142, 23, 142, 44, 23,
- /* 2060 */ 23, 23, 11, 23, 25, 22, 22, 22, 15, 23,
- /* 2070 */ 23, 22, 22, 25, 1, 1, 141, 25, 23, 135,
- /* 2080 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2090 */ 319, 319, 319, 319, 141, 141, 319, 141, 319, 319,
+ /* 1690 */ 217, 7, 8, 23, 59, 25, 83, 84, 36, 23,
+ /* 1700 */ 193, 25, 23, 23, 25, 25, 71, 153, 145, 155,
+ /* 1710 */ 117, 153, 23, 155, 25, 23, 97, 25, 70, 193,
+ /* 1720 */ 193, 59, 117, 236, 193, 193, 78, 193, 193, 81,
+ /* 1730 */ 141, 193, 193, 71, 193, 100, 288, 287, 242, 255,
+ /* 1740 */ 255, 106, 107, 108, 255, 255, 98, 243, 297, 114,
+ /* 1750 */ 214, 116, 117, 118, 245, 191, 121, 271, 293, 267,
+ /* 1760 */ 267, 246, 100, 246, 245, 271, 271, 293, 106, 107,
+ /* 1770 */ 220, 271, 229, 225, 249, 219, 114, 259, 116, 117,
+ /* 1780 */ 118, 133, 259, 121, 219, 219, 138, 139, 153, 154,
+ /* 1790 */ 155, 156, 157, 280, 249, 243, 19, 20, 245, 22,
+ /* 1800 */ 196, 259, 140, 259, 60, 297, 141, 297, 200, 200,
+ /* 1810 */ 162, 38, 200, 36, 294, 153, 154, 155, 156, 157,
+ /* 1820 */ 151, 150, 294, 283, 22, 43, 234, 18, 237, 200,
+ /* 1830 */ 270, 272, 237, 237, 237, 18, 59, 199, 270, 149,
+ /* 1840 */ 246, 272, 272, 200, 234, 234, 246, 246, 71, 246,
+ /* 1850 */ 199, 158, 290, 62, 22, 200, 19, 20, 199, 22,
+ /* 1860 */ 289, 221, 221, 200, 200, 199, 199, 115, 218, 64,
+ /* 1870 */ 218, 218, 22, 36, 227, 126, 227, 100, 165, 221,
+ /* 1880 */ 224, 224, 24, 106, 107, 312, 218, 305, 113, 282,
+ /* 1890 */ 91, 114, 220, 116, 117, 118, 59, 282, 121, 218,
+ /* 1900 */ 218, 218, 200, 317, 317, 82, 221, 265, 71, 148,
+ /* 1910 */ 145, 265, 22, 277, 200, 158, 279, 140, 147, 25,
+ /* 1920 */ 146, 202, 248, 250, 249, 247, 13, 250, 194, 194,
+ /* 1930 */ 153, 154, 155, 156, 157, 6, 303, 100, 192, 192,
+ /* 1940 */ 246, 213, 192, 106, 107, 207, 213, 207, 222, 213,
+ /* 1950 */ 213, 114, 222, 116, 117, 118, 214, 214, 121, 4,
+ /* 1960 */ 207, 213, 3, 22, 303, 15, 163, 16, 23, 23,
+ /* 1970 */ 139, 151, 130, 25, 20, 142, 24, 16, 144, 1,
+ /* 1980 */ 142, 130, 130, 61, 37, 53, 300, 151, 53, 53,
+ /* 1990 */ 153, 154, 155, 156, 157, 53, 130, 116, 34, 1,
+ /* 2000 */ 141, 5, 22, 115, 161, 68, 25, 68, 75, 41,
+ /* 2010 */ 141, 115, 24, 20, 19, 131, 125, 23, 28, 22,
+ /* 2020 */ 67, 22, 22, 22, 67, 59, 24, 96, 22, 67,
+ /* 2030 */ 23, 149, 22, 25, 23, 23, 23, 22, 34, 141,
+ /* 2040 */ 37, 97, 23, 23, 116, 22, 143, 25, 34, 75,
+ /* 2050 */ 34, 34, 34, 88, 75, 34, 86, 23, 22, 34,
+ /* 2060 */ 93, 24, 34, 25, 25, 142, 142, 23, 44, 23,
+ /* 2070 */ 23, 23, 23, 11, 23, 25, 22, 22, 22, 141,
+ /* 2080 */ 23, 23, 22, 22, 25, 15, 1, 23, 25, 1,
+ /* 2090 */ 141, 135, 319, 319, 319, 319, 319, 319, 319, 141,
/* 2100 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
/* 2110 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
/* 2120 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
@@ -167805,176 +172158,177 @@ static const YYCODETYPE yy_lookahead[] = {
/* 2250 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
/* 2260 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
/* 2270 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2280 */ 319, 319, 319,
+ /* 2280 */ 319, 319, 319, 319, 319,
};
-#define YY_SHIFT_COUNT (575)
+#define YY_SHIFT_COUNT (578)
#define YY_SHIFT_MIN (0)
-#define YY_SHIFT_MAX (2074)
+#define YY_SHIFT_MAX (2088)
static const unsigned short int yy_shift_ofst[] = {
/* 0 */ 1648, 1477, 1272, 322, 322, 1, 1319, 1478, 1491, 1837,
/* 10 */ 1837, 1837, 471, 0, 0, 214, 1093, 1837, 1837, 1837,
/* 20 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
- /* 30 */ 271, 271, 1219, 1219, 216, 88, 1, 1, 1, 1,
- /* 40 */ 1, 40, 111, 258, 361, 469, 512, 583, 622, 693,
- /* 50 */ 732, 803, 842, 913, 1073, 1093, 1093, 1093, 1093, 1093,
+ /* 30 */ 1837, 271, 271, 1219, 1219, 216, 88, 1, 1, 1,
+ /* 40 */ 1, 1, 40, 111, 258, 361, 469, 512, 583, 622,
+ /* 50 */ 693, 732, 803, 842, 913, 1073, 1093, 1093, 1093, 1093,
/* 60 */ 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093,
- /* 70 */ 1093, 1093, 1093, 1113, 1093, 1216, 957, 957, 1635, 1662,
- /* 80 */ 1777, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
+ /* 70 */ 1093, 1093, 1093, 1093, 1113, 1093, 1216, 957, 957, 1635,
+ /* 80 */ 1662, 1777, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
/* 90 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
/* 100 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
/* 110 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
/* 120 */ 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837, 1837,
- /* 130 */ 137, 181, 181, 181, 181, 181, 181, 181, 94, 430,
- /* 140 */ 66, 65, 112, 366, 533, 533, 740, 1261, 533, 533,
- /* 150 */ 79, 79, 533, 412, 412, 412, 77, 412, 123, 113,
- /* 160 */ 113, 22, 22, 2098, 2098, 328, 328, 328, 239, 468,
- /* 170 */ 468, 468, 468, 1015, 1015, 409, 366, 1129, 1186, 533,
- /* 180 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 533,
- /* 190 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 969,
- /* 200 */ 621, 621, 533, 642, 788, 788, 1228, 1228, 822, 822,
- /* 210 */ 67, 1274, 2098, 2098, 2098, 2098, 2098, 2098, 2098, 1307,
- /* 220 */ 954, 954, 585, 472, 640, 387, 695, 538, 541, 700,
- /* 230 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 533,
- /* 240 */ 222, 533, 533, 533, 533, 533, 533, 533, 533, 533,
- /* 250 */ 533, 533, 533, 1179, 1179, 1179, 533, 533, 533, 565,
- /* 260 */ 533, 533, 533, 916, 1144, 533, 533, 1288, 533, 533,
- /* 270 */ 533, 533, 533, 533, 533, 533, 639, 1330, 209, 1076,
- /* 280 */ 1076, 1076, 1076, 580, 209, 209, 1313, 768, 917, 649,
- /* 290 */ 1181, 1316, 405, 1316, 1238, 249, 1181, 1181, 249, 1181,
- /* 300 */ 405, 1238, 1369, 464, 1259, 1012, 1012, 1012, 1368, 1368,
- /* 310 */ 1368, 1368, 184, 184, 1326, 904, 1287, 1480, 1712, 1712,
- /* 320 */ 1633, 1633, 1757, 1757, 1633, 1647, 1651, 1783, 1764, 1791,
- /* 330 */ 1791, 1791, 1791, 1633, 1806, 1677, 1651, 1651, 1677, 1783,
- /* 340 */ 1764, 1677, 1764, 1677, 1633, 1806, 1674, 1779, 1633, 1806,
- /* 350 */ 1823, 1633, 1806, 1633, 1806, 1823, 1732, 1732, 1732, 1794,
- /* 360 */ 1840, 1840, 1823, 1732, 1738, 1732, 1794, 1732, 1732, 1701,
- /* 370 */ 1844, 1758, 1758, 1823, 1633, 1789, 1789, 1807, 1807, 1742,
- /* 380 */ 1752, 1877, 1633, 1743, 1742, 1759, 1765, 1677, 1879, 1897,
- /* 390 */ 1897, 1914, 1914, 1914, 2098, 2098, 2098, 2098, 2098, 2098,
- /* 400 */ 2098, 2098, 2098, 2098, 2098, 2098, 2098, 2098, 2098, 207,
- /* 410 */ 1095, 331, 620, 903, 806, 1074, 1483, 1432, 1481, 1322,
- /* 420 */ 1370, 1394, 1515, 1291, 1546, 1547, 1557, 1595, 1598, 1599,
- /* 430 */ 1434, 1453, 1618, 1462, 1567, 1489, 1644, 1654, 1616, 1660,
- /* 440 */ 1548, 1549, 1682, 1685, 1597, 742, 1941, 1945, 1927, 1787,
- /* 450 */ 1937, 1940, 1934, 1936, 1821, 1810, 1832, 1938, 1938, 1942,
- /* 460 */ 1822, 1947, 1824, 1949, 1968, 1828, 1841, 1938, 1842, 1912,
- /* 470 */ 1939, 1938, 1826, 1921, 1922, 1925, 1926, 1850, 1865, 1948,
- /* 480 */ 1843, 1982, 1980, 1964, 1872, 1827, 1928, 1970, 1929, 1923,
- /* 490 */ 1958, 1848, 1885, 1977, 1983, 1985, 1871, 1880, 1984, 1943,
- /* 500 */ 1986, 1987, 1988, 1990, 1946, 1955, 1991, 1911, 1989, 1994,
- /* 510 */ 1951, 1992, 1996, 1873, 1998, 2000, 2001, 2002, 2003, 2004,
- /* 520 */ 1999, 1933, 1890, 2009, 2010, 1910, 2005, 2012, 1892, 2011,
- /* 530 */ 2006, 2007, 2008, 2013, 1950, 1962, 1957, 2014, 1969, 1952,
- /* 540 */ 2015, 2023, 2026, 2027, 2025, 2028, 2018, 1913, 1915, 2031,
- /* 550 */ 2011, 2033, 2036, 2037, 2038, 2039, 2040, 2043, 2051, 2044,
- /* 560 */ 2045, 2046, 2047, 2049, 2050, 2048, 1944, 1935, 1953, 1954,
- /* 570 */ 1956, 2052, 2055, 2053, 2073, 2074,
+ /* 130 */ 1837, 137, 181, 181, 181, 181, 181, 181, 181, 94,
+ /* 140 */ 430, 66, 65, 112, 366, 533, 533, 740, 1257, 533,
+ /* 150 */ 533, 79, 79, 533, 412, 412, 412, 77, 412, 123,
+ /* 160 */ 113, 113, 113, 22, 22, 2100, 2100, 328, 328, 328,
+ /* 170 */ 239, 468, 468, 468, 468, 1015, 1015, 409, 366, 1187,
+ /* 180 */ 1232, 533, 533, 533, 533, 533, 533, 533, 533, 533,
+ /* 190 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 533,
+ /* 200 */ 533, 969, 621, 621, 533, 642, 788, 788, 1133, 1133,
+ /* 210 */ 822, 822, 67, 1193, 2100, 2100, 2100, 2100, 2100, 2100,
+ /* 220 */ 2100, 1307, 954, 954, 585, 472, 640, 387, 695, 538,
+ /* 230 */ 541, 700, 533, 533, 533, 533, 533, 533, 533, 533,
+ /* 240 */ 533, 533, 222, 533, 533, 533, 533, 533, 533, 533,
+ /* 250 */ 533, 533, 533, 533, 533, 1213, 1213, 1213, 533, 533,
+ /* 260 */ 533, 565, 533, 533, 533, 916, 1147, 533, 533, 1288,
+ /* 270 */ 533, 533, 533, 533, 533, 533, 533, 533, 639, 1280,
+ /* 280 */ 209, 1129, 1129, 1129, 1129, 580, 209, 209, 1209, 768,
+ /* 290 */ 917, 649, 1315, 1334, 405, 1334, 1383, 249, 1315, 1315,
+ /* 300 */ 249, 1315, 405, 1383, 1441, 464, 1245, 1417, 1417, 1417,
+ /* 310 */ 1323, 1323, 1323, 1323, 184, 184, 1335, 1476, 856, 1482,
+ /* 320 */ 1744, 1744, 1665, 1665, 1773, 1773, 1665, 1669, 1671, 1802,
+ /* 330 */ 1782, 1809, 1809, 1809, 1809, 1665, 1817, 1690, 1671, 1671,
+ /* 340 */ 1690, 1802, 1782, 1690, 1782, 1690, 1665, 1817, 1693, 1791,
+ /* 350 */ 1665, 1817, 1832, 1665, 1817, 1665, 1817, 1832, 1752, 1752,
+ /* 360 */ 1752, 1805, 1850, 1850, 1832, 1752, 1749, 1752, 1805, 1752,
+ /* 370 */ 1752, 1713, 1858, 1775, 1775, 1832, 1665, 1799, 1799, 1823,
+ /* 380 */ 1823, 1761, 1765, 1890, 1665, 1757, 1761, 1771, 1774, 1690,
+ /* 390 */ 1894, 1913, 1913, 1929, 1929, 1929, 2100, 2100, 2100, 2100,
+ /* 400 */ 2100, 2100, 2100, 2100, 2100, 2100, 2100, 2100, 2100, 2100,
+ /* 410 */ 2100, 207, 1220, 331, 620, 967, 806, 1074, 1499, 1432,
+ /* 420 */ 1463, 1479, 1419, 1422, 1557, 1512, 1598, 1599, 1644, 1645,
+ /* 430 */ 1654, 1660, 1555, 1505, 1684, 1462, 1670, 1563, 1619, 1593,
+ /* 440 */ 1676, 1679, 1613, 1680, 1554, 1558, 1689, 1692, 1605, 1589,
+ /* 450 */ 1955, 1959, 1941, 1803, 1950, 1951, 1945, 1946, 1831, 1820,
+ /* 460 */ 1842, 1948, 1948, 1952, 1833, 1954, 1834, 1961, 1978, 1838,
+ /* 470 */ 1851, 1948, 1852, 1922, 1947, 1948, 1836, 1932, 1935, 1936,
+ /* 480 */ 1942, 1866, 1881, 1964, 1859, 1998, 1996, 1980, 1888, 1843,
+ /* 490 */ 1937, 1981, 1939, 1933, 1968, 1869, 1896, 1988, 1993, 1995,
+ /* 500 */ 1884, 1891, 1997, 1953, 1999, 2000, 1994, 2001, 1957, 1966,
+ /* 510 */ 2002, 1931, 1990, 2006, 1962, 2003, 2007, 2004, 1882, 2010,
+ /* 520 */ 2011, 2012, 2008, 2013, 2015, 1944, 1898, 2019, 2020, 1928,
+ /* 530 */ 2014, 2023, 1903, 2022, 2016, 2017, 2018, 2021, 1965, 1974,
+ /* 540 */ 1970, 2024, 1979, 1967, 2025, 2034, 2036, 2037, 2038, 2039,
+ /* 550 */ 2028, 1923, 1924, 2044, 2022, 2046, 2047, 2048, 2049, 2050,
+ /* 560 */ 2051, 2054, 2062, 2055, 2056, 2057, 2058, 2060, 2061, 2059,
+ /* 570 */ 1956, 1938, 1949, 1958, 2063, 2064, 2070, 2085, 2088,
};
-#define YY_REDUCE_COUNT (408)
+#define YY_REDUCE_COUNT (410)
#define YY_REDUCE_MIN (-271)
-#define YY_REDUCE_MAX (1740)
+#define YY_REDUCE_MAX (1753)
static const short yy_reduce_ofst[] = {
/* 0 */ -125, 733, 789, 241, 293, -123, -193, -191, -183, -187,
/* 10 */ 166, 238, 133, -207, -199, -267, -176, -6, 204, 489,
- /* 20 */ 576, -175, 598, 686, 615, 725, 860, 778, 781, 857,
- /* 30 */ 616, 887, 87, 240, -192, 408, 626, 796, 843, 854,
- /* 40 */ 1003, -271, -271, -271, -271, -271, -271, -271, -271, -271,
+ /* 20 */ 576, 598, -175, 686, 860, 615, 725, 1014, 778, 781,
+ /* 30 */ 857, 616, 887, 87, 240, -192, 408, 626, 796, 843,
+ /* 40 */ 854, 1004, -271, -271, -271, -271, -271, -271, -271, -271,
/* 50 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271,
/* 60 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271,
- /* 70 */ -271, -271, -271, -271, -271, -271, -271, -271, 80, 83,
- /* 80 */ 313, 886, 888, 996, 1034, 1059, 1081, 1100, 1117, 1152,
- /* 90 */ 1155, 1163, 1165, 1167, 1169, 1172, 1180, 1182, 1184, 1198,
- /* 100 */ 1200, 1213, 1215, 1225, 1227, 1252, 1254, 1264, 1299, 1303,
- /* 110 */ 1308, 1312, 1325, 1328, 1337, 1340, 1343, 1371, 1373, 1384,
- /* 120 */ 1386, 1411, 1420, 1424, 1426, 1458, 1470, 1473, 1475, 1479,
- /* 130 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, -271,
- /* 140 */ -271, 138, 459, 396, -158, 470, 302, -212, 521, 201,
- /* 150 */ -195, -92, 559, 630, 632, 630, -271, 632, 901, 63,
- /* 160 */ 407, -271, -271, -271, -271, 161, 161, 161, 251, 335,
- /* 170 */ 847, 960, 980, 537, 588, 618, 628, 688, 688, -166,
- /* 180 */ -161, 674, 790, 794, 799, 851, 852, -122, 680, -120,
- /* 190 */ 995, 1038, 415, 1051, 893, 798, 962, 400, 1086, 779,
- /* 200 */ 923, 924, 263, 1041, 979, 990, 1083, 1097, 1031, 1194,
- /* 210 */ 362, 994, 1139, 1005, 1037, 1202, 1205, 1195, 1210, -194,
- /* 220 */ 56, 185, -135, 232, 522, 560, 601, 617, 669, 683,
- /* 230 */ 711, 856, 908, 941, 1048, 1101, 1147, 1257, 1262, 1265,
- /* 240 */ 392, 1292, 1333, 1339, 1342, 1346, 1350, 1359, 1374, 1418,
- /* 250 */ 1421, 1436, 1437, 593, 755, 770, 997, 1445, 1459, 1209,
- /* 260 */ 1500, 1504, 1516, 1132, 1243, 1518, 1519, 1440, 1520, 560,
- /* 270 */ 1522, 1523, 1524, 1526, 1527, 1529, 1382, 1438, 1431, 1468,
- /* 280 */ 1469, 1472, 1476, 1209, 1431, 1431, 1485, 1525, 1539, 1435,
- /* 290 */ 1463, 1471, 1492, 1487, 1443, 1494, 1474, 1484, 1498, 1486,
- /* 300 */ 1502, 1455, 1530, 1531, 1533, 1540, 1542, 1544, 1505, 1506,
- /* 310 */ 1507, 1508, 1521, 1528, 1493, 1537, 1532, 1575, 1488, 1496,
- /* 320 */ 1584, 1594, 1509, 1510, 1600, 1538, 1534, 1541, 1574, 1577,
- /* 330 */ 1583, 1585, 1586, 1612, 1626, 1581, 1556, 1558, 1587, 1559,
- /* 340 */ 1601, 1588, 1603, 1592, 1631, 1640, 1550, 1553, 1643, 1645,
- /* 350 */ 1625, 1649, 1652, 1650, 1653, 1632, 1636, 1637, 1642, 1634,
- /* 360 */ 1639, 1641, 1646, 1656, 1655, 1658, 1659, 1661, 1663, 1560,
- /* 370 */ 1564, 1596, 1605, 1664, 1670, 1565, 1571, 1627, 1638, 1657,
- /* 380 */ 1665, 1623, 1702, 1630, 1666, 1667, 1671, 1673, 1703, 1718,
- /* 390 */ 1719, 1729, 1730, 1731, 1621, 1622, 1628, 1720, 1713, 1716,
- /* 400 */ 1722, 1723, 1733, 1717, 1724, 1727, 1728, 1725, 1740,
+ /* 70 */ -271, -271, -271, -271, -271, -271, -271, -271, -271, 80,
+ /* 80 */ 83, 313, 886, 888, 918, 938, 1021, 1034, 1036, 1141,
+ /* 90 */ 1159, 1163, 1166, 1168, 1170, 1176, 1178, 1180, 1184, 1196,
+ /* 100 */ 1198, 1205, 1215, 1225, 1227, 1236, 1252, 1254, 1264, 1303,
+ /* 110 */ 1309, 1312, 1322, 1325, 1328, 1337, 1340, 1343, 1353, 1371,
+ /* 120 */ 1373, 1384, 1386, 1411, 1413, 1420, 1424, 1426, 1458, 1470,
+ /* 130 */ 1473, -271, -271, -271, -271, -271, -271, -271, -271, -271,
+ /* 140 */ -271, -271, 138, 459, 396, -158, 470, 302, -212, 521,
+ /* 150 */ 201, -195, -92, 559, 630, 632, 630, -271, 632, 901,
+ /* 160 */ 63, 407, 670, -271, -271, -271, -271, 161, 161, 161,
+ /* 170 */ 251, 335, 847, 979, 1097, 537, 588, 618, 628, 688,
+ /* 180 */ 688, -166, -161, 674, 787, 794, 799, 852, 996, -122,
+ /* 190 */ 837, -120, 1018, 1035, 415, 1047, 1001, 958, 1082, 400,
+ /* 200 */ 1099, 779, 1137, 1142, 263, 1083, 1145, 1150, 1041, 1139,
+ /* 210 */ 965, 1050, 362, 849, 752, 629, 675, 1162, 1173, 1090,
+ /* 220 */ 1195, -194, 56, 185, -135, 232, 522, 560, 571, 601,
+ /* 230 */ 617, 669, 683, 711, 850, 893, 1000, 1040, 1049, 1081,
+ /* 240 */ 1087, 1101, 392, 1114, 1123, 1155, 1161, 1175, 1271, 1293,
+ /* 250 */ 1299, 1330, 1339, 1342, 1347, 593, 1282, 1286, 1350, 1359,
+ /* 260 */ 1368, 1314, 1480, 1483, 1507, 1085, 1338, 1526, 1527, 1487,
+ /* 270 */ 1531, 560, 1532, 1534, 1535, 1538, 1539, 1541, 1448, 1450,
+ /* 280 */ 1496, 1484, 1485, 1489, 1490, 1314, 1496, 1496, 1504, 1536,
+ /* 290 */ 1564, 1451, 1486, 1492, 1509, 1493, 1465, 1515, 1494, 1495,
+ /* 300 */ 1517, 1500, 1519, 1474, 1550, 1543, 1548, 1556, 1565, 1566,
+ /* 310 */ 1518, 1523, 1542, 1544, 1525, 1545, 1513, 1553, 1552, 1604,
+ /* 320 */ 1508, 1510, 1608, 1609, 1520, 1528, 1612, 1540, 1559, 1560,
+ /* 330 */ 1592, 1591, 1595, 1596, 1597, 1629, 1638, 1594, 1569, 1570,
+ /* 340 */ 1600, 1568, 1610, 1601, 1611, 1603, 1643, 1651, 1562, 1571,
+ /* 350 */ 1655, 1659, 1640, 1663, 1666, 1664, 1667, 1641, 1650, 1652,
+ /* 360 */ 1653, 1647, 1656, 1657, 1658, 1668, 1672, 1681, 1649, 1682,
+ /* 370 */ 1683, 1573, 1582, 1607, 1615, 1685, 1702, 1586, 1587, 1642,
+ /* 380 */ 1646, 1673, 1675, 1636, 1714, 1637, 1677, 1674, 1678, 1694,
+ /* 390 */ 1719, 1734, 1735, 1746, 1747, 1750, 1633, 1661, 1686, 1738,
+ /* 400 */ 1728, 1733, 1736, 1737, 1740, 1726, 1730, 1742, 1743, 1748,
+ /* 410 */ 1753,
};
static const YYACTIONTYPE yy_default[] = {
- /* 0 */ 1647, 1647, 1647, 1475, 1240, 1351, 1240, 1240, 1240, 1475,
- /* 10 */ 1475, 1475, 1240, 1381, 1381, 1528, 1273, 1240, 1240, 1240,
- /* 20 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1474, 1240, 1240,
- /* 30 */ 1240, 1240, 1563, 1563, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 40 */ 1240, 1240, 1390, 1240, 1397, 1240, 1240, 1240, 1240, 1240,
- /* 50 */ 1476, 1477, 1240, 1240, 1240, 1527, 1529, 1492, 1404, 1403,
- /* 60 */ 1402, 1401, 1510, 1369, 1395, 1388, 1392, 1470, 1471, 1469,
- /* 70 */ 1473, 1477, 1476, 1240, 1391, 1438, 1454, 1437, 1240, 1240,
- /* 80 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 90 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 100 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 110 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 120 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 130 */ 1446, 1453, 1452, 1451, 1460, 1450, 1447, 1440, 1439, 1441,
- /* 140 */ 1442, 1240, 1240, 1264, 1240, 1240, 1261, 1315, 1240, 1240,
- /* 150 */ 1240, 1240, 1240, 1547, 1546, 1240, 1443, 1240, 1273, 1432,
- /* 160 */ 1431, 1457, 1444, 1456, 1455, 1535, 1599, 1598, 1493, 1240,
- /* 170 */ 1240, 1240, 1240, 1240, 1240, 1563, 1240, 1240, 1240, 1240,
- /* 180 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 190 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1371,
- /* 200 */ 1563, 1563, 1240, 1273, 1563, 1563, 1372, 1372, 1269, 1269,
- /* 210 */ 1375, 1240, 1542, 1342, 1342, 1342, 1342, 1351, 1342, 1240,
- /* 220 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 230 */ 1240, 1240, 1240, 1240, 1532, 1530, 1240, 1240, 1240, 1240,
- /* 240 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 250 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 260 */ 1240, 1240, 1240, 1347, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 270 */ 1240, 1240, 1240, 1240, 1240, 1592, 1240, 1505, 1329, 1347,
- /* 280 */ 1347, 1347, 1347, 1349, 1330, 1328, 1341, 1274, 1247, 1639,
- /* 290 */ 1407, 1396, 1348, 1396, 1636, 1394, 1407, 1407, 1394, 1407,
- /* 300 */ 1348, 1636, 1290, 1615, 1285, 1381, 1381, 1381, 1371, 1371,
- /* 310 */ 1371, 1371, 1375, 1375, 1472, 1348, 1341, 1240, 1639, 1639,
- /* 320 */ 1357, 1357, 1638, 1638, 1357, 1493, 1623, 1416, 1318, 1324,
- /* 330 */ 1324, 1324, 1324, 1357, 1258, 1394, 1623, 1623, 1394, 1416,
- /* 340 */ 1318, 1394, 1318, 1394, 1357, 1258, 1509, 1633, 1357, 1258,
- /* 350 */ 1483, 1357, 1258, 1357, 1258, 1483, 1316, 1316, 1316, 1305,
- /* 360 */ 1240, 1240, 1483, 1316, 1290, 1316, 1305, 1316, 1316, 1581,
- /* 370 */ 1240, 1487, 1487, 1483, 1357, 1573, 1573, 1384, 1384, 1389,
- /* 380 */ 1375, 1478, 1357, 1240, 1389, 1387, 1385, 1394, 1308, 1595,
- /* 390 */ 1595, 1591, 1591, 1591, 1644, 1644, 1542, 1608, 1273, 1273,
- /* 400 */ 1273, 1273, 1608, 1292, 1292, 1274, 1274, 1273, 1608, 1240,
- /* 410 */ 1240, 1240, 1240, 1240, 1240, 1603, 1240, 1537, 1494, 1361,
- /* 420 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 430 */ 1240, 1240, 1240, 1240, 1548, 1240, 1240, 1240, 1240, 1240,
- /* 440 */ 1240, 1240, 1240, 1240, 1240, 1421, 1240, 1243, 1539, 1240,
- /* 450 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1398, 1399, 1362,
- /* 460 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1413, 1240, 1240,
- /* 470 */ 1240, 1408, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 480 */ 1635, 1240, 1240, 1240, 1240, 1240, 1240, 1508, 1507, 1240,
- /* 490 */ 1240, 1359, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 500 */ 1240, 1240, 1240, 1240, 1240, 1288, 1240, 1240, 1240, 1240,
- /* 510 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 520 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1386,
- /* 530 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 540 */ 1240, 1240, 1240, 1240, 1578, 1376, 1240, 1240, 1240, 1240,
- /* 550 */ 1626, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 560 */ 1240, 1240, 1240, 1240, 1240, 1619, 1332, 1423, 1240, 1422,
- /* 570 */ 1426, 1262, 1240, 1252, 1240, 1240,
+ /* 0 */ 1648, 1648, 1648, 1478, 1243, 1354, 1243, 1243, 1243, 1478,
+ /* 10 */ 1478, 1478, 1243, 1384, 1384, 1531, 1276, 1243, 1243, 1243,
+ /* 20 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1477, 1243,
+ /* 30 */ 1243, 1243, 1243, 1564, 1564, 1243, 1243, 1243, 1243, 1243,
+ /* 40 */ 1243, 1243, 1243, 1393, 1243, 1400, 1243, 1243, 1243, 1243,
+ /* 50 */ 1243, 1479, 1480, 1243, 1243, 1243, 1530, 1532, 1495, 1407,
+ /* 60 */ 1406, 1405, 1404, 1513, 1372, 1398, 1391, 1395, 1474, 1475,
+ /* 70 */ 1473, 1626, 1480, 1479, 1243, 1394, 1442, 1458, 1441, 1243,
+ /* 80 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243,
+ /* 90 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243,
+ /* 100 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243,
+ /* 110 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243,
+ /* 120 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243,
+ /* 130 */ 1243, 1450, 1457, 1456, 1455, 1464, 1454, 1451, 1444, 1443,
+ /* 140 */ 1445, 1446, 1243, 1243, 1267, 1243, 1243, 1264, 1318, 1243,
+ /* 150 */ 1243, 1243, 1243, 1243, 1550, 1549, 1243, 1447, 1243, 1276,
+ /* 160 */ 1435, 1434, 1433, 1461, 1448, 1460, 1459, 1538, 1600, 1599,
+ /* 170 */ 1496, 1243, 1243, 1243, 1243, 1243, 1243, 1564, 1243, 1243,
+ /* 180 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243,
+ /* 190 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243,
+ /* 200 */ 1243, 1374, 1564, 1564, 1243, 1276, 1564, 1564, 1375, 1375,
+ /* 210 */ 1272, 1272, 1378, 1243, 1545, 1345, 1345, 1345, 1345, 1354,
+ /* 220 */ 1345, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243,
+ /* 230 */ 1243, 1243, 1243, 1243, 1243, 1243, 1535, 1533, 1243, 1243,
+ /* 240 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243,
+ /* 250 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243,
+ /* 260 */ 1243, 1243, 1243, 1243, 1243, 1350, 1243, 1243, 1243, 1243,
+ /* 270 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1593, 1243, 1508,
+ /* 280 */ 1332, 1350, 1350, 1350, 1350, 1352, 1333, 1331, 1344, 1277,
+ /* 290 */ 1250, 1640, 1410, 1399, 1351, 1399, 1637, 1397, 1410, 1410,
+ /* 300 */ 1397, 1410, 1351, 1637, 1293, 1615, 1288, 1384, 1384, 1384,
+ /* 310 */ 1374, 1374, 1374, 1374, 1378, 1378, 1476, 1351, 1344, 1243,
+ /* 320 */ 1640, 1640, 1360, 1360, 1639, 1639, 1360, 1496, 1623, 1419,
+ /* 330 */ 1321, 1327, 1327, 1327, 1327, 1360, 1261, 1397, 1623, 1623,
+ /* 340 */ 1397, 1419, 1321, 1397, 1321, 1397, 1360, 1261, 1512, 1634,
+ /* 350 */ 1360, 1261, 1486, 1360, 1261, 1360, 1261, 1486, 1319, 1319,
+ /* 360 */ 1319, 1308, 1243, 1243, 1486, 1319, 1293, 1319, 1308, 1319,
+ /* 370 */ 1319, 1582, 1243, 1490, 1490, 1486, 1360, 1574, 1574, 1387,
+ /* 380 */ 1387, 1392, 1378, 1481, 1360, 1243, 1392, 1390, 1388, 1397,
+ /* 390 */ 1311, 1596, 1596, 1592, 1592, 1592, 1645, 1645, 1545, 1608,
+ /* 400 */ 1276, 1276, 1276, 1276, 1608, 1295, 1295, 1277, 1277, 1276,
+ /* 410 */ 1608, 1243, 1243, 1243, 1243, 1243, 1243, 1603, 1243, 1540,
+ /* 420 */ 1497, 1364, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243,
+ /* 430 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1551, 1243,
+ /* 440 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1424,
+ /* 450 */ 1243, 1246, 1542, 1243, 1243, 1243, 1243, 1243, 1243, 1243,
+ /* 460 */ 1243, 1401, 1402, 1365, 1243, 1243, 1243, 1243, 1243, 1243,
+ /* 470 */ 1243, 1416, 1243, 1243, 1243, 1411, 1243, 1243, 1243, 1243,
+ /* 480 */ 1243, 1243, 1243, 1243, 1636, 1243, 1243, 1243, 1243, 1243,
+ /* 490 */ 1243, 1511, 1510, 1243, 1243, 1362, 1243, 1243, 1243, 1243,
+ /* 500 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1291,
+ /* 510 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243,
+ /* 520 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243,
+ /* 530 */ 1243, 1243, 1243, 1389, 1243, 1243, 1243, 1243, 1243, 1243,
+ /* 540 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1579, 1379,
+ /* 550 */ 1243, 1243, 1243, 1243, 1627, 1243, 1243, 1243, 1243, 1243,
+ /* 560 */ 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1243, 1619,
+ /* 570 */ 1335, 1425, 1243, 1428, 1265, 1243, 1255, 1243, 1243,
};
/********** End of lemon-generated parsing tables *****************************/
@@ -168771,59 +173125,59 @@ static const char *const yyRuleName[] = {
/* 175 */ "idlist ::= idlist COMMA nm",
/* 176 */ "idlist ::= nm",
/* 177 */ "expr ::= LP expr RP",
- /* 178 */ "expr ::= ID|INDEXED",
- /* 179 */ "expr ::= JOIN_KW",
- /* 180 */ "expr ::= nm DOT nm",
- /* 181 */ "expr ::= nm DOT nm DOT nm",
- /* 182 */ "term ::= NULL|FLOAT|BLOB",
- /* 183 */ "term ::= STRING",
- /* 184 */ "term ::= INTEGER",
- /* 185 */ "expr ::= VARIABLE",
- /* 186 */ "expr ::= expr COLLATE ID|STRING",
- /* 187 */ "expr ::= CAST LP expr AS typetoken RP",
- /* 188 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
- /* 189 */ "expr ::= ID|INDEXED LP STAR RP",
- /* 190 */ "expr ::= ID|INDEXED LP distinct exprlist RP filter_over",
- /* 191 */ "expr ::= ID|INDEXED LP STAR RP filter_over",
- /* 192 */ "term ::= CTIME_KW",
- /* 193 */ "expr ::= LP nexprlist COMMA expr RP",
- /* 194 */ "expr ::= expr AND expr",
- /* 195 */ "expr ::= expr OR expr",
- /* 196 */ "expr ::= expr LT|GT|GE|LE expr",
- /* 197 */ "expr ::= expr EQ|NE expr",
- /* 198 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
- /* 199 */ "expr ::= expr PLUS|MINUS expr",
- /* 200 */ "expr ::= expr STAR|SLASH|REM expr",
- /* 201 */ "expr ::= expr CONCAT expr",
- /* 202 */ "likeop ::= NOT LIKE_KW|MATCH",
- /* 203 */ "expr ::= expr likeop expr",
- /* 204 */ "expr ::= expr likeop expr ESCAPE expr",
- /* 205 */ "expr ::= expr ISNULL|NOTNULL",
- /* 206 */ "expr ::= expr NOT NULL",
- /* 207 */ "expr ::= expr IS expr",
- /* 208 */ "expr ::= expr IS NOT expr",
- /* 209 */ "expr ::= expr IS NOT DISTINCT FROM expr",
- /* 210 */ "expr ::= expr IS DISTINCT FROM expr",
- /* 211 */ "expr ::= NOT expr",
- /* 212 */ "expr ::= BITNOT expr",
- /* 213 */ "expr ::= PLUS|MINUS expr",
- /* 214 */ "expr ::= expr PTR expr",
- /* 215 */ "between_op ::= BETWEEN",
- /* 216 */ "between_op ::= NOT BETWEEN",
- /* 217 */ "expr ::= expr between_op expr AND expr",
- /* 218 */ "in_op ::= IN",
- /* 219 */ "in_op ::= NOT IN",
- /* 220 */ "expr ::= expr in_op LP exprlist RP",
- /* 221 */ "expr ::= LP select RP",
- /* 222 */ "expr ::= expr in_op LP select RP",
- /* 223 */ "expr ::= expr in_op nm dbnm paren_exprlist",
- /* 224 */ "expr ::= EXISTS LP select RP",
- /* 225 */ "expr ::= CASE case_operand case_exprlist case_else END",
- /* 226 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
- /* 227 */ "case_exprlist ::= WHEN expr THEN expr",
- /* 228 */ "case_else ::= ELSE expr",
- /* 229 */ "case_else ::=",
- /* 230 */ "case_operand ::= expr",
+ /* 178 */ "expr ::= ID|INDEXED|JOIN_KW",
+ /* 179 */ "expr ::= nm DOT nm",
+ /* 180 */ "expr ::= nm DOT nm DOT nm",
+ /* 181 */ "term ::= NULL|FLOAT|BLOB",
+ /* 182 */ "term ::= STRING",
+ /* 183 */ "term ::= INTEGER",
+ /* 184 */ "expr ::= VARIABLE",
+ /* 185 */ "expr ::= expr COLLATE ID|STRING",
+ /* 186 */ "expr ::= CAST LP expr AS typetoken RP",
+ /* 187 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP",
+ /* 188 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP",
+ /* 189 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP",
+ /* 190 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over",
+ /* 191 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over",
+ /* 192 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over",
+ /* 193 */ "term ::= CTIME_KW",
+ /* 194 */ "expr ::= LP nexprlist COMMA expr RP",
+ /* 195 */ "expr ::= expr AND expr",
+ /* 196 */ "expr ::= expr OR expr",
+ /* 197 */ "expr ::= expr LT|GT|GE|LE expr",
+ /* 198 */ "expr ::= expr EQ|NE expr",
+ /* 199 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
+ /* 200 */ "expr ::= expr PLUS|MINUS expr",
+ /* 201 */ "expr ::= expr STAR|SLASH|REM expr",
+ /* 202 */ "expr ::= expr CONCAT expr",
+ /* 203 */ "likeop ::= NOT LIKE_KW|MATCH",
+ /* 204 */ "expr ::= expr likeop expr",
+ /* 205 */ "expr ::= expr likeop expr ESCAPE expr",
+ /* 206 */ "expr ::= expr ISNULL|NOTNULL",
+ /* 207 */ "expr ::= expr NOT NULL",
+ /* 208 */ "expr ::= expr IS expr",
+ /* 209 */ "expr ::= expr IS NOT expr",
+ /* 210 */ "expr ::= expr IS NOT DISTINCT FROM expr",
+ /* 211 */ "expr ::= expr IS DISTINCT FROM expr",
+ /* 212 */ "expr ::= NOT expr",
+ /* 213 */ "expr ::= BITNOT expr",
+ /* 214 */ "expr ::= PLUS|MINUS expr",
+ /* 215 */ "expr ::= expr PTR expr",
+ /* 216 */ "between_op ::= BETWEEN",
+ /* 217 */ "between_op ::= NOT BETWEEN",
+ /* 218 */ "expr ::= expr between_op expr AND expr",
+ /* 219 */ "in_op ::= IN",
+ /* 220 */ "in_op ::= NOT IN",
+ /* 221 */ "expr ::= expr in_op LP exprlist RP",
+ /* 222 */ "expr ::= LP select RP",
+ /* 223 */ "expr ::= expr in_op LP select RP",
+ /* 224 */ "expr ::= expr in_op nm dbnm paren_exprlist",
+ /* 225 */ "expr ::= EXISTS LP select RP",
+ /* 226 */ "expr ::= CASE case_operand case_exprlist case_else END",
+ /* 227 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
+ /* 228 */ "case_exprlist ::= WHEN expr THEN expr",
+ /* 229 */ "case_else ::= ELSE expr",
+ /* 230 */ "case_else ::=",
/* 231 */ "case_operand ::=",
/* 232 */ "exprlist ::=",
/* 233 */ "nexprlist ::= nexprlist COMMA expr",
@@ -168904,100 +173258,100 @@ static const char *const yyRuleName[] = {
/* 308 */ "wqitem ::= nm eidlist_opt wqas LP select RP",
/* 309 */ "wqlist ::= wqitem",
/* 310 */ "wqlist ::= wqlist COMMA wqitem",
- /* 311 */ "windowdefn_list ::= windowdefn",
- /* 312 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn",
- /* 313 */ "windowdefn ::= nm AS LP window RP",
- /* 314 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt",
- /* 315 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt",
- /* 316 */ "window ::= ORDER BY sortlist frame_opt",
- /* 317 */ "window ::= nm ORDER BY sortlist frame_opt",
- /* 318 */ "window ::= frame_opt",
- /* 319 */ "window ::= nm frame_opt",
- /* 320 */ "frame_opt ::=",
- /* 321 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt",
- /* 322 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt",
- /* 323 */ "range_or_rows ::= RANGE|ROWS|GROUPS",
- /* 324 */ "frame_bound_s ::= frame_bound",
- /* 325 */ "frame_bound_s ::= UNBOUNDED PRECEDING",
- /* 326 */ "frame_bound_e ::= frame_bound",
- /* 327 */ "frame_bound_e ::= UNBOUNDED FOLLOWING",
- /* 328 */ "frame_bound ::= expr PRECEDING|FOLLOWING",
- /* 329 */ "frame_bound ::= CURRENT ROW",
- /* 330 */ "frame_exclude_opt ::=",
- /* 331 */ "frame_exclude_opt ::= EXCLUDE frame_exclude",
- /* 332 */ "frame_exclude ::= NO OTHERS",
- /* 333 */ "frame_exclude ::= CURRENT ROW",
- /* 334 */ "frame_exclude ::= GROUP|TIES",
- /* 335 */ "window_clause ::= WINDOW windowdefn_list",
- /* 336 */ "filter_over ::= filter_clause over_clause",
- /* 337 */ "filter_over ::= over_clause",
- /* 338 */ "filter_over ::= filter_clause",
- /* 339 */ "over_clause ::= OVER LP window RP",
- /* 340 */ "over_clause ::= OVER nm",
- /* 341 */ "filter_clause ::= FILTER LP WHERE expr RP",
- /* 342 */ "input ::= cmdlist",
- /* 343 */ "cmdlist ::= cmdlist ecmd",
- /* 344 */ "cmdlist ::= ecmd",
- /* 345 */ "ecmd ::= SEMI",
- /* 346 */ "ecmd ::= cmdx SEMI",
- /* 347 */ "ecmd ::= explain cmdx SEMI",
- /* 348 */ "trans_opt ::=",
- /* 349 */ "trans_opt ::= TRANSACTION",
- /* 350 */ "trans_opt ::= TRANSACTION nm",
- /* 351 */ "savepoint_opt ::= SAVEPOINT",
- /* 352 */ "savepoint_opt ::=",
- /* 353 */ "cmd ::= create_table create_table_args",
- /* 354 */ "table_option_set ::= table_option",
- /* 355 */ "columnlist ::= columnlist COMMA columnname carglist",
- /* 356 */ "columnlist ::= columnname carglist",
- /* 357 */ "nm ::= ID|INDEXED",
- /* 358 */ "nm ::= STRING",
- /* 359 */ "nm ::= JOIN_KW",
- /* 360 */ "typetoken ::= typename",
- /* 361 */ "typename ::= ID|STRING",
- /* 362 */ "signed ::= plus_num",
- /* 363 */ "signed ::= minus_num",
- /* 364 */ "carglist ::= carglist ccons",
- /* 365 */ "carglist ::=",
- /* 366 */ "ccons ::= NULL onconf",
- /* 367 */ "ccons ::= GENERATED ALWAYS AS generated",
- /* 368 */ "ccons ::= AS generated",
- /* 369 */ "conslist_opt ::= COMMA conslist",
- /* 370 */ "conslist ::= conslist tconscomma tcons",
- /* 371 */ "conslist ::= tcons",
- /* 372 */ "tconscomma ::=",
- /* 373 */ "defer_subclause_opt ::= defer_subclause",
- /* 374 */ "resolvetype ::= raisetype",
- /* 375 */ "selectnowith ::= oneselect",
- /* 376 */ "oneselect ::= values",
- /* 377 */ "sclp ::= selcollist COMMA",
- /* 378 */ "as ::= ID|STRING",
- /* 379 */ "indexed_opt ::= indexed_by",
- /* 380 */ "returning ::=",
- /* 381 */ "expr ::= term",
- /* 382 */ "likeop ::= LIKE_KW|MATCH",
- /* 383 */ "exprlist ::= nexprlist",
- /* 384 */ "nmnum ::= plus_num",
- /* 385 */ "nmnum ::= nm",
- /* 386 */ "nmnum ::= ON",
- /* 387 */ "nmnum ::= DELETE",
- /* 388 */ "nmnum ::= DEFAULT",
- /* 389 */ "plus_num ::= INTEGER|FLOAT",
- /* 390 */ "foreach_clause ::=",
- /* 391 */ "foreach_clause ::= FOR EACH ROW",
- /* 392 */ "trnm ::= nm",
- /* 393 */ "tridxby ::=",
- /* 394 */ "database_kw_opt ::= DATABASE",
- /* 395 */ "database_kw_opt ::=",
- /* 396 */ "kwcolumn_opt ::=",
- /* 397 */ "kwcolumn_opt ::= COLUMNKW",
- /* 398 */ "vtabarglist ::= vtabarg",
- /* 399 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
- /* 400 */ "vtabarg ::= vtabarg vtabargtoken",
- /* 401 */ "anylist ::=",
- /* 402 */ "anylist ::= anylist LP anylist RP",
- /* 403 */ "anylist ::= anylist ANY",
- /* 404 */ "with ::=",
+ /* 311 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn",
+ /* 312 */ "windowdefn ::= nm AS LP window RP",
+ /* 313 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt",
+ /* 314 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt",
+ /* 315 */ "window ::= ORDER BY sortlist frame_opt",
+ /* 316 */ "window ::= nm ORDER BY sortlist frame_opt",
+ /* 317 */ "window ::= nm frame_opt",
+ /* 318 */ "frame_opt ::=",
+ /* 319 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt",
+ /* 320 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt",
+ /* 321 */ "range_or_rows ::= RANGE|ROWS|GROUPS",
+ /* 322 */ "frame_bound_s ::= frame_bound",
+ /* 323 */ "frame_bound_s ::= UNBOUNDED PRECEDING",
+ /* 324 */ "frame_bound_e ::= frame_bound",
+ /* 325 */ "frame_bound_e ::= UNBOUNDED FOLLOWING",
+ /* 326 */ "frame_bound ::= expr PRECEDING|FOLLOWING",
+ /* 327 */ "frame_bound ::= CURRENT ROW",
+ /* 328 */ "frame_exclude_opt ::=",
+ /* 329 */ "frame_exclude_opt ::= EXCLUDE frame_exclude",
+ /* 330 */ "frame_exclude ::= NO OTHERS",
+ /* 331 */ "frame_exclude ::= CURRENT ROW",
+ /* 332 */ "frame_exclude ::= GROUP|TIES",
+ /* 333 */ "window_clause ::= WINDOW windowdefn_list",
+ /* 334 */ "filter_over ::= filter_clause over_clause",
+ /* 335 */ "filter_over ::= over_clause",
+ /* 336 */ "filter_over ::= filter_clause",
+ /* 337 */ "over_clause ::= OVER LP window RP",
+ /* 338 */ "over_clause ::= OVER nm",
+ /* 339 */ "filter_clause ::= FILTER LP WHERE expr RP",
+ /* 340 */ "input ::= cmdlist",
+ /* 341 */ "cmdlist ::= cmdlist ecmd",
+ /* 342 */ "cmdlist ::= ecmd",
+ /* 343 */ "ecmd ::= SEMI",
+ /* 344 */ "ecmd ::= cmdx SEMI",
+ /* 345 */ "ecmd ::= explain cmdx SEMI",
+ /* 346 */ "trans_opt ::=",
+ /* 347 */ "trans_opt ::= TRANSACTION",
+ /* 348 */ "trans_opt ::= TRANSACTION nm",
+ /* 349 */ "savepoint_opt ::= SAVEPOINT",
+ /* 350 */ "savepoint_opt ::=",
+ /* 351 */ "cmd ::= create_table create_table_args",
+ /* 352 */ "table_option_set ::= table_option",
+ /* 353 */ "columnlist ::= columnlist COMMA columnname carglist",
+ /* 354 */ "columnlist ::= columnname carglist",
+ /* 355 */ "nm ::= ID|INDEXED|JOIN_KW",
+ /* 356 */ "nm ::= STRING",
+ /* 357 */ "typetoken ::= typename",
+ /* 358 */ "typename ::= ID|STRING",
+ /* 359 */ "signed ::= plus_num",
+ /* 360 */ "signed ::= minus_num",
+ /* 361 */ "carglist ::= carglist ccons",
+ /* 362 */ "carglist ::=",
+ /* 363 */ "ccons ::= NULL onconf",
+ /* 364 */ "ccons ::= GENERATED ALWAYS AS generated",
+ /* 365 */ "ccons ::= AS generated",
+ /* 366 */ "conslist_opt ::= COMMA conslist",
+ /* 367 */ "conslist ::= conslist tconscomma tcons",
+ /* 368 */ "conslist ::= tcons",
+ /* 369 */ "tconscomma ::=",
+ /* 370 */ "defer_subclause_opt ::= defer_subclause",
+ /* 371 */ "resolvetype ::= raisetype",
+ /* 372 */ "selectnowith ::= oneselect",
+ /* 373 */ "oneselect ::= values",
+ /* 374 */ "sclp ::= selcollist COMMA",
+ /* 375 */ "as ::= ID|STRING",
+ /* 376 */ "indexed_opt ::= indexed_by",
+ /* 377 */ "returning ::=",
+ /* 378 */ "expr ::= term",
+ /* 379 */ "likeop ::= LIKE_KW|MATCH",
+ /* 380 */ "case_operand ::= expr",
+ /* 381 */ "exprlist ::= nexprlist",
+ /* 382 */ "nmnum ::= plus_num",
+ /* 383 */ "nmnum ::= nm",
+ /* 384 */ "nmnum ::= ON",
+ /* 385 */ "nmnum ::= DELETE",
+ /* 386 */ "nmnum ::= DEFAULT",
+ /* 387 */ "plus_num ::= INTEGER|FLOAT",
+ /* 388 */ "foreach_clause ::=",
+ /* 389 */ "foreach_clause ::= FOR EACH ROW",
+ /* 390 */ "trnm ::= nm",
+ /* 391 */ "tridxby ::=",
+ /* 392 */ "database_kw_opt ::= DATABASE",
+ /* 393 */ "database_kw_opt ::=",
+ /* 394 */ "kwcolumn_opt ::=",
+ /* 395 */ "kwcolumn_opt ::= COLUMNKW",
+ /* 396 */ "vtabarglist ::= vtabarg",
+ /* 397 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
+ /* 398 */ "vtabarg ::= vtabarg vtabargtoken",
+ /* 399 */ "anylist ::=",
+ /* 400 */ "anylist ::= anylist LP anylist RP",
+ /* 401 */ "anylist ::= anylist ANY",
+ /* 402 */ "with ::=",
+ /* 403 */ "windowdefn_list ::= windowdefn",
+ /* 404 */ "window ::= frame_opt",
};
#endif /* NDEBUG */
@@ -169682,59 +174036,59 @@ static const YYCODETYPE yyRuleInfoLhs[] = {
263, /* (175) idlist ::= idlist COMMA nm */
263, /* (176) idlist ::= nm */
217, /* (177) expr ::= LP expr RP */
- 217, /* (178) expr ::= ID|INDEXED */
- 217, /* (179) expr ::= JOIN_KW */
- 217, /* (180) expr ::= nm DOT nm */
- 217, /* (181) expr ::= nm DOT nm DOT nm */
- 216, /* (182) term ::= NULL|FLOAT|BLOB */
- 216, /* (183) term ::= STRING */
- 216, /* (184) term ::= INTEGER */
- 217, /* (185) expr ::= VARIABLE */
- 217, /* (186) expr ::= expr COLLATE ID|STRING */
- 217, /* (187) expr ::= CAST LP expr AS typetoken RP */
- 217, /* (188) expr ::= ID|INDEXED LP distinct exprlist RP */
- 217, /* (189) expr ::= ID|INDEXED LP STAR RP */
- 217, /* (190) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
- 217, /* (191) expr ::= ID|INDEXED LP STAR RP filter_over */
- 216, /* (192) term ::= CTIME_KW */
- 217, /* (193) expr ::= LP nexprlist COMMA expr RP */
- 217, /* (194) expr ::= expr AND expr */
- 217, /* (195) expr ::= expr OR expr */
- 217, /* (196) expr ::= expr LT|GT|GE|LE expr */
- 217, /* (197) expr ::= expr EQ|NE expr */
- 217, /* (198) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
- 217, /* (199) expr ::= expr PLUS|MINUS expr */
- 217, /* (200) expr ::= expr STAR|SLASH|REM expr */
- 217, /* (201) expr ::= expr CONCAT expr */
- 274, /* (202) likeop ::= NOT LIKE_KW|MATCH */
- 217, /* (203) expr ::= expr likeop expr */
- 217, /* (204) expr ::= expr likeop expr ESCAPE expr */
- 217, /* (205) expr ::= expr ISNULL|NOTNULL */
- 217, /* (206) expr ::= expr NOT NULL */
- 217, /* (207) expr ::= expr IS expr */
- 217, /* (208) expr ::= expr IS NOT expr */
- 217, /* (209) expr ::= expr IS NOT DISTINCT FROM expr */
- 217, /* (210) expr ::= expr IS DISTINCT FROM expr */
- 217, /* (211) expr ::= NOT expr */
- 217, /* (212) expr ::= BITNOT expr */
- 217, /* (213) expr ::= PLUS|MINUS expr */
- 217, /* (214) expr ::= expr PTR expr */
- 275, /* (215) between_op ::= BETWEEN */
- 275, /* (216) between_op ::= NOT BETWEEN */
- 217, /* (217) expr ::= expr between_op expr AND expr */
- 276, /* (218) in_op ::= IN */
- 276, /* (219) in_op ::= NOT IN */
- 217, /* (220) expr ::= expr in_op LP exprlist RP */
- 217, /* (221) expr ::= LP select RP */
- 217, /* (222) expr ::= expr in_op LP select RP */
- 217, /* (223) expr ::= expr in_op nm dbnm paren_exprlist */
- 217, /* (224) expr ::= EXISTS LP select RP */
- 217, /* (225) expr ::= CASE case_operand case_exprlist case_else END */
- 279, /* (226) case_exprlist ::= case_exprlist WHEN expr THEN expr */
- 279, /* (227) case_exprlist ::= WHEN expr THEN expr */
- 280, /* (228) case_else ::= ELSE expr */
- 280, /* (229) case_else ::= */
- 278, /* (230) case_operand ::= expr */
+ 217, /* (178) expr ::= ID|INDEXED|JOIN_KW */
+ 217, /* (179) expr ::= nm DOT nm */
+ 217, /* (180) expr ::= nm DOT nm DOT nm */
+ 216, /* (181) term ::= NULL|FLOAT|BLOB */
+ 216, /* (182) term ::= STRING */
+ 216, /* (183) term ::= INTEGER */
+ 217, /* (184) expr ::= VARIABLE */
+ 217, /* (185) expr ::= expr COLLATE ID|STRING */
+ 217, /* (186) expr ::= CAST LP expr AS typetoken RP */
+ 217, /* (187) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */
+ 217, /* (188) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */
+ 217, /* (189) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */
+ 217, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */
+ 217, /* (191) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */
+ 217, /* (192) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */
+ 216, /* (193) term ::= CTIME_KW */
+ 217, /* (194) expr ::= LP nexprlist COMMA expr RP */
+ 217, /* (195) expr ::= expr AND expr */
+ 217, /* (196) expr ::= expr OR expr */
+ 217, /* (197) expr ::= expr LT|GT|GE|LE expr */
+ 217, /* (198) expr ::= expr EQ|NE expr */
+ 217, /* (199) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
+ 217, /* (200) expr ::= expr PLUS|MINUS expr */
+ 217, /* (201) expr ::= expr STAR|SLASH|REM expr */
+ 217, /* (202) expr ::= expr CONCAT expr */
+ 274, /* (203) likeop ::= NOT LIKE_KW|MATCH */
+ 217, /* (204) expr ::= expr likeop expr */
+ 217, /* (205) expr ::= expr likeop expr ESCAPE expr */
+ 217, /* (206) expr ::= expr ISNULL|NOTNULL */
+ 217, /* (207) expr ::= expr NOT NULL */
+ 217, /* (208) expr ::= expr IS expr */
+ 217, /* (209) expr ::= expr IS NOT expr */
+ 217, /* (210) expr ::= expr IS NOT DISTINCT FROM expr */
+ 217, /* (211) expr ::= expr IS DISTINCT FROM expr */
+ 217, /* (212) expr ::= NOT expr */
+ 217, /* (213) expr ::= BITNOT expr */
+ 217, /* (214) expr ::= PLUS|MINUS expr */
+ 217, /* (215) expr ::= expr PTR expr */
+ 275, /* (216) between_op ::= BETWEEN */
+ 275, /* (217) between_op ::= NOT BETWEEN */
+ 217, /* (218) expr ::= expr between_op expr AND expr */
+ 276, /* (219) in_op ::= IN */
+ 276, /* (220) in_op ::= NOT IN */
+ 217, /* (221) expr ::= expr in_op LP exprlist RP */
+ 217, /* (222) expr ::= LP select RP */
+ 217, /* (223) expr ::= expr in_op LP select RP */
+ 217, /* (224) expr ::= expr in_op nm dbnm paren_exprlist */
+ 217, /* (225) expr ::= EXISTS LP select RP */
+ 217, /* (226) expr ::= CASE case_operand case_exprlist case_else END */
+ 279, /* (227) case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ 279, /* (228) case_exprlist ::= WHEN expr THEN expr */
+ 280, /* (229) case_else ::= ELSE expr */
+ 280, /* (230) case_else ::= */
278, /* (231) case_operand ::= */
261, /* (232) exprlist ::= */
253, /* (233) nexprlist ::= nexprlist COMMA expr */
@@ -169815,100 +174169,100 @@ static const YYCODETYPE yyRuleInfoLhs[] = {
304, /* (308) wqitem ::= nm eidlist_opt wqas LP select RP */
241, /* (309) wqlist ::= wqitem */
241, /* (310) wqlist ::= wqlist COMMA wqitem */
- 306, /* (311) windowdefn_list ::= windowdefn */
- 306, /* (312) windowdefn_list ::= windowdefn_list COMMA windowdefn */
- 307, /* (313) windowdefn ::= nm AS LP window RP */
- 308, /* (314) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
- 308, /* (315) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
- 308, /* (316) window ::= ORDER BY sortlist frame_opt */
- 308, /* (317) window ::= nm ORDER BY sortlist frame_opt */
- 308, /* (318) window ::= frame_opt */
- 308, /* (319) window ::= nm frame_opt */
- 309, /* (320) frame_opt ::= */
- 309, /* (321) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
- 309, /* (322) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
- 313, /* (323) range_or_rows ::= RANGE|ROWS|GROUPS */
- 315, /* (324) frame_bound_s ::= frame_bound */
- 315, /* (325) frame_bound_s ::= UNBOUNDED PRECEDING */
- 316, /* (326) frame_bound_e ::= frame_bound */
- 316, /* (327) frame_bound_e ::= UNBOUNDED FOLLOWING */
- 314, /* (328) frame_bound ::= expr PRECEDING|FOLLOWING */
- 314, /* (329) frame_bound ::= CURRENT ROW */
- 317, /* (330) frame_exclude_opt ::= */
- 317, /* (331) frame_exclude_opt ::= EXCLUDE frame_exclude */
- 318, /* (332) frame_exclude ::= NO OTHERS */
- 318, /* (333) frame_exclude ::= CURRENT ROW */
- 318, /* (334) frame_exclude ::= GROUP|TIES */
- 251, /* (335) window_clause ::= WINDOW windowdefn_list */
- 273, /* (336) filter_over ::= filter_clause over_clause */
- 273, /* (337) filter_over ::= over_clause */
- 273, /* (338) filter_over ::= filter_clause */
- 312, /* (339) over_clause ::= OVER LP window RP */
- 312, /* (340) over_clause ::= OVER nm */
- 311, /* (341) filter_clause ::= FILTER LP WHERE expr RP */
- 185, /* (342) input ::= cmdlist */
- 186, /* (343) cmdlist ::= cmdlist ecmd */
- 186, /* (344) cmdlist ::= ecmd */
- 187, /* (345) ecmd ::= SEMI */
- 187, /* (346) ecmd ::= cmdx SEMI */
- 187, /* (347) ecmd ::= explain cmdx SEMI */
- 192, /* (348) trans_opt ::= */
- 192, /* (349) trans_opt ::= TRANSACTION */
- 192, /* (350) trans_opt ::= TRANSACTION nm */
- 194, /* (351) savepoint_opt ::= SAVEPOINT */
- 194, /* (352) savepoint_opt ::= */
- 190, /* (353) cmd ::= create_table create_table_args */
- 203, /* (354) table_option_set ::= table_option */
- 201, /* (355) columnlist ::= columnlist COMMA columnname carglist */
- 201, /* (356) columnlist ::= columnname carglist */
- 193, /* (357) nm ::= ID|INDEXED */
- 193, /* (358) nm ::= STRING */
- 193, /* (359) nm ::= JOIN_KW */
- 208, /* (360) typetoken ::= typename */
- 209, /* (361) typename ::= ID|STRING */
- 210, /* (362) signed ::= plus_num */
- 210, /* (363) signed ::= minus_num */
- 207, /* (364) carglist ::= carglist ccons */
- 207, /* (365) carglist ::= */
- 215, /* (366) ccons ::= NULL onconf */
- 215, /* (367) ccons ::= GENERATED ALWAYS AS generated */
- 215, /* (368) ccons ::= AS generated */
- 202, /* (369) conslist_opt ::= COMMA conslist */
- 228, /* (370) conslist ::= conslist tconscomma tcons */
- 228, /* (371) conslist ::= tcons */
- 229, /* (372) tconscomma ::= */
- 233, /* (373) defer_subclause_opt ::= defer_subclause */
- 235, /* (374) resolvetype ::= raisetype */
- 239, /* (375) selectnowith ::= oneselect */
- 240, /* (376) oneselect ::= values */
- 254, /* (377) sclp ::= selcollist COMMA */
- 255, /* (378) as ::= ID|STRING */
- 264, /* (379) indexed_opt ::= indexed_by */
- 272, /* (380) returning ::= */
- 217, /* (381) expr ::= term */
- 274, /* (382) likeop ::= LIKE_KW|MATCH */
- 261, /* (383) exprlist ::= nexprlist */
- 284, /* (384) nmnum ::= plus_num */
- 284, /* (385) nmnum ::= nm */
- 284, /* (386) nmnum ::= ON */
- 284, /* (387) nmnum ::= DELETE */
- 284, /* (388) nmnum ::= DEFAULT */
- 211, /* (389) plus_num ::= INTEGER|FLOAT */
- 289, /* (390) foreach_clause ::= */
- 289, /* (391) foreach_clause ::= FOR EACH ROW */
- 292, /* (392) trnm ::= nm */
- 293, /* (393) tridxby ::= */
- 294, /* (394) database_kw_opt ::= DATABASE */
- 294, /* (395) database_kw_opt ::= */
- 297, /* (396) kwcolumn_opt ::= */
- 297, /* (397) kwcolumn_opt ::= COLUMNKW */
- 299, /* (398) vtabarglist ::= vtabarg */
- 299, /* (399) vtabarglist ::= vtabarglist COMMA vtabarg */
- 300, /* (400) vtabarg ::= vtabarg vtabargtoken */
- 303, /* (401) anylist ::= */
- 303, /* (402) anylist ::= anylist LP anylist RP */
- 303, /* (403) anylist ::= anylist ANY */
- 266, /* (404) with ::= */
+ 306, /* (311) windowdefn_list ::= windowdefn_list COMMA windowdefn */
+ 307, /* (312) windowdefn ::= nm AS LP window RP */
+ 308, /* (313) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
+ 308, /* (314) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
+ 308, /* (315) window ::= ORDER BY sortlist frame_opt */
+ 308, /* (316) window ::= nm ORDER BY sortlist frame_opt */
+ 308, /* (317) window ::= nm frame_opt */
+ 309, /* (318) frame_opt ::= */
+ 309, /* (319) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
+ 309, /* (320) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
+ 313, /* (321) range_or_rows ::= RANGE|ROWS|GROUPS */
+ 315, /* (322) frame_bound_s ::= frame_bound */
+ 315, /* (323) frame_bound_s ::= UNBOUNDED PRECEDING */
+ 316, /* (324) frame_bound_e ::= frame_bound */
+ 316, /* (325) frame_bound_e ::= UNBOUNDED FOLLOWING */
+ 314, /* (326) frame_bound ::= expr PRECEDING|FOLLOWING */
+ 314, /* (327) frame_bound ::= CURRENT ROW */
+ 317, /* (328) frame_exclude_opt ::= */
+ 317, /* (329) frame_exclude_opt ::= EXCLUDE frame_exclude */
+ 318, /* (330) frame_exclude ::= NO OTHERS */
+ 318, /* (331) frame_exclude ::= CURRENT ROW */
+ 318, /* (332) frame_exclude ::= GROUP|TIES */
+ 251, /* (333) window_clause ::= WINDOW windowdefn_list */
+ 273, /* (334) filter_over ::= filter_clause over_clause */
+ 273, /* (335) filter_over ::= over_clause */
+ 273, /* (336) filter_over ::= filter_clause */
+ 312, /* (337) over_clause ::= OVER LP window RP */
+ 312, /* (338) over_clause ::= OVER nm */
+ 311, /* (339) filter_clause ::= FILTER LP WHERE expr RP */
+ 185, /* (340) input ::= cmdlist */
+ 186, /* (341) cmdlist ::= cmdlist ecmd */
+ 186, /* (342) cmdlist ::= ecmd */
+ 187, /* (343) ecmd ::= SEMI */
+ 187, /* (344) ecmd ::= cmdx SEMI */
+ 187, /* (345) ecmd ::= explain cmdx SEMI */
+ 192, /* (346) trans_opt ::= */
+ 192, /* (347) trans_opt ::= TRANSACTION */
+ 192, /* (348) trans_opt ::= TRANSACTION nm */
+ 194, /* (349) savepoint_opt ::= SAVEPOINT */
+ 194, /* (350) savepoint_opt ::= */
+ 190, /* (351) cmd ::= create_table create_table_args */
+ 203, /* (352) table_option_set ::= table_option */
+ 201, /* (353) columnlist ::= columnlist COMMA columnname carglist */
+ 201, /* (354) columnlist ::= columnname carglist */
+ 193, /* (355) nm ::= ID|INDEXED|JOIN_KW */
+ 193, /* (356) nm ::= STRING */
+ 208, /* (357) typetoken ::= typename */
+ 209, /* (358) typename ::= ID|STRING */
+ 210, /* (359) signed ::= plus_num */
+ 210, /* (360) signed ::= minus_num */
+ 207, /* (361) carglist ::= carglist ccons */
+ 207, /* (362) carglist ::= */
+ 215, /* (363) ccons ::= NULL onconf */
+ 215, /* (364) ccons ::= GENERATED ALWAYS AS generated */
+ 215, /* (365) ccons ::= AS generated */
+ 202, /* (366) conslist_opt ::= COMMA conslist */
+ 228, /* (367) conslist ::= conslist tconscomma tcons */
+ 228, /* (368) conslist ::= tcons */
+ 229, /* (369) tconscomma ::= */
+ 233, /* (370) defer_subclause_opt ::= defer_subclause */
+ 235, /* (371) resolvetype ::= raisetype */
+ 239, /* (372) selectnowith ::= oneselect */
+ 240, /* (373) oneselect ::= values */
+ 254, /* (374) sclp ::= selcollist COMMA */
+ 255, /* (375) as ::= ID|STRING */
+ 264, /* (376) indexed_opt ::= indexed_by */
+ 272, /* (377) returning ::= */
+ 217, /* (378) expr ::= term */
+ 274, /* (379) likeop ::= LIKE_KW|MATCH */
+ 278, /* (380) case_operand ::= expr */
+ 261, /* (381) exprlist ::= nexprlist */
+ 284, /* (382) nmnum ::= plus_num */
+ 284, /* (383) nmnum ::= nm */
+ 284, /* (384) nmnum ::= ON */
+ 284, /* (385) nmnum ::= DELETE */
+ 284, /* (386) nmnum ::= DEFAULT */
+ 211, /* (387) plus_num ::= INTEGER|FLOAT */
+ 289, /* (388) foreach_clause ::= */
+ 289, /* (389) foreach_clause ::= FOR EACH ROW */
+ 292, /* (390) trnm ::= nm */
+ 293, /* (391) tridxby ::= */
+ 294, /* (392) database_kw_opt ::= DATABASE */
+ 294, /* (393) database_kw_opt ::= */
+ 297, /* (394) kwcolumn_opt ::= */
+ 297, /* (395) kwcolumn_opt ::= COLUMNKW */
+ 299, /* (396) vtabarglist ::= vtabarg */
+ 299, /* (397) vtabarglist ::= vtabarglist COMMA vtabarg */
+ 300, /* (398) vtabarg ::= vtabarg vtabargtoken */
+ 303, /* (399) anylist ::= */
+ 303, /* (400) anylist ::= anylist LP anylist RP */
+ 303, /* (401) anylist ::= anylist ANY */
+ 266, /* (402) with ::= */
+ 306, /* (403) windowdefn_list ::= windowdefn */
+ 308, /* (404) window ::= frame_opt */
};
/* For rule J, yyRuleInfoNRhs[J] contains the negative of the number
@@ -170092,59 +174446,59 @@ static const signed char yyRuleInfoNRhs[] = {
-3, /* (175) idlist ::= idlist COMMA nm */
-1, /* (176) idlist ::= nm */
-3, /* (177) expr ::= LP expr RP */
- -1, /* (178) expr ::= ID|INDEXED */
- -1, /* (179) expr ::= JOIN_KW */
- -3, /* (180) expr ::= nm DOT nm */
- -5, /* (181) expr ::= nm DOT nm DOT nm */
- -1, /* (182) term ::= NULL|FLOAT|BLOB */
- -1, /* (183) term ::= STRING */
- -1, /* (184) term ::= INTEGER */
- -1, /* (185) expr ::= VARIABLE */
- -3, /* (186) expr ::= expr COLLATE ID|STRING */
- -6, /* (187) expr ::= CAST LP expr AS typetoken RP */
- -5, /* (188) expr ::= ID|INDEXED LP distinct exprlist RP */
- -4, /* (189) expr ::= ID|INDEXED LP STAR RP */
- -6, /* (190) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
- -5, /* (191) expr ::= ID|INDEXED LP STAR RP filter_over */
- -1, /* (192) term ::= CTIME_KW */
- -5, /* (193) expr ::= LP nexprlist COMMA expr RP */
- -3, /* (194) expr ::= expr AND expr */
- -3, /* (195) expr ::= expr OR expr */
- -3, /* (196) expr ::= expr LT|GT|GE|LE expr */
- -3, /* (197) expr ::= expr EQ|NE expr */
- -3, /* (198) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
- -3, /* (199) expr ::= expr PLUS|MINUS expr */
- -3, /* (200) expr ::= expr STAR|SLASH|REM expr */
- -3, /* (201) expr ::= expr CONCAT expr */
- -2, /* (202) likeop ::= NOT LIKE_KW|MATCH */
- -3, /* (203) expr ::= expr likeop expr */
- -5, /* (204) expr ::= expr likeop expr ESCAPE expr */
- -2, /* (205) expr ::= expr ISNULL|NOTNULL */
- -3, /* (206) expr ::= expr NOT NULL */
- -3, /* (207) expr ::= expr IS expr */
- -4, /* (208) expr ::= expr IS NOT expr */
- -6, /* (209) expr ::= expr IS NOT DISTINCT FROM expr */
- -5, /* (210) expr ::= expr IS DISTINCT FROM expr */
- -2, /* (211) expr ::= NOT expr */
- -2, /* (212) expr ::= BITNOT expr */
- -2, /* (213) expr ::= PLUS|MINUS expr */
- -3, /* (214) expr ::= expr PTR expr */
- -1, /* (215) between_op ::= BETWEEN */
- -2, /* (216) between_op ::= NOT BETWEEN */
- -5, /* (217) expr ::= expr between_op expr AND expr */
- -1, /* (218) in_op ::= IN */
- -2, /* (219) in_op ::= NOT IN */
- -5, /* (220) expr ::= expr in_op LP exprlist RP */
- -3, /* (221) expr ::= LP select RP */
- -5, /* (222) expr ::= expr in_op LP select RP */
- -5, /* (223) expr ::= expr in_op nm dbnm paren_exprlist */
- -4, /* (224) expr ::= EXISTS LP select RP */
- -5, /* (225) expr ::= CASE case_operand case_exprlist case_else END */
- -5, /* (226) case_exprlist ::= case_exprlist WHEN expr THEN expr */
- -4, /* (227) case_exprlist ::= WHEN expr THEN expr */
- -2, /* (228) case_else ::= ELSE expr */
- 0, /* (229) case_else ::= */
- -1, /* (230) case_operand ::= expr */
+ -1, /* (178) expr ::= ID|INDEXED|JOIN_KW */
+ -3, /* (179) expr ::= nm DOT nm */
+ -5, /* (180) expr ::= nm DOT nm DOT nm */
+ -1, /* (181) term ::= NULL|FLOAT|BLOB */
+ -1, /* (182) term ::= STRING */
+ -1, /* (183) term ::= INTEGER */
+ -1, /* (184) expr ::= VARIABLE */
+ -3, /* (185) expr ::= expr COLLATE ID|STRING */
+ -6, /* (186) expr ::= CAST LP expr AS typetoken RP */
+ -5, /* (187) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */
+ -8, /* (188) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */
+ -4, /* (189) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */
+ -6, /* (190) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */
+ -9, /* (191) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */
+ -5, /* (192) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */
+ -1, /* (193) term ::= CTIME_KW */
+ -5, /* (194) expr ::= LP nexprlist COMMA expr RP */
+ -3, /* (195) expr ::= expr AND expr */
+ -3, /* (196) expr ::= expr OR expr */
+ -3, /* (197) expr ::= expr LT|GT|GE|LE expr */
+ -3, /* (198) expr ::= expr EQ|NE expr */
+ -3, /* (199) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
+ -3, /* (200) expr ::= expr PLUS|MINUS expr */
+ -3, /* (201) expr ::= expr STAR|SLASH|REM expr */
+ -3, /* (202) expr ::= expr CONCAT expr */
+ -2, /* (203) likeop ::= NOT LIKE_KW|MATCH */
+ -3, /* (204) expr ::= expr likeop expr */
+ -5, /* (205) expr ::= expr likeop expr ESCAPE expr */
+ -2, /* (206) expr ::= expr ISNULL|NOTNULL */
+ -3, /* (207) expr ::= expr NOT NULL */
+ -3, /* (208) expr ::= expr IS expr */
+ -4, /* (209) expr ::= expr IS NOT expr */
+ -6, /* (210) expr ::= expr IS NOT DISTINCT FROM expr */
+ -5, /* (211) expr ::= expr IS DISTINCT FROM expr */
+ -2, /* (212) expr ::= NOT expr */
+ -2, /* (213) expr ::= BITNOT expr */
+ -2, /* (214) expr ::= PLUS|MINUS expr */
+ -3, /* (215) expr ::= expr PTR expr */
+ -1, /* (216) between_op ::= BETWEEN */
+ -2, /* (217) between_op ::= NOT BETWEEN */
+ -5, /* (218) expr ::= expr between_op expr AND expr */
+ -1, /* (219) in_op ::= IN */
+ -2, /* (220) in_op ::= NOT IN */
+ -5, /* (221) expr ::= expr in_op LP exprlist RP */
+ -3, /* (222) expr ::= LP select RP */
+ -5, /* (223) expr ::= expr in_op LP select RP */
+ -5, /* (224) expr ::= expr in_op nm dbnm paren_exprlist */
+ -4, /* (225) expr ::= EXISTS LP select RP */
+ -5, /* (226) expr ::= CASE case_operand case_exprlist case_else END */
+ -5, /* (227) case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ -4, /* (228) case_exprlist ::= WHEN expr THEN expr */
+ -2, /* (229) case_else ::= ELSE expr */
+ 0, /* (230) case_else ::= */
0, /* (231) case_operand ::= */
0, /* (232) exprlist ::= */
-3, /* (233) nexprlist ::= nexprlist COMMA expr */
@@ -170225,100 +174579,100 @@ static const signed char yyRuleInfoNRhs[] = {
-6, /* (308) wqitem ::= nm eidlist_opt wqas LP select RP */
-1, /* (309) wqlist ::= wqitem */
-3, /* (310) wqlist ::= wqlist COMMA wqitem */
- -1, /* (311) windowdefn_list ::= windowdefn */
- -3, /* (312) windowdefn_list ::= windowdefn_list COMMA windowdefn */
- -5, /* (313) windowdefn ::= nm AS LP window RP */
- -5, /* (314) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
- -6, /* (315) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
- -4, /* (316) window ::= ORDER BY sortlist frame_opt */
- -5, /* (317) window ::= nm ORDER BY sortlist frame_opt */
- -1, /* (318) window ::= frame_opt */
- -2, /* (319) window ::= nm frame_opt */
- 0, /* (320) frame_opt ::= */
- -3, /* (321) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
- -6, /* (322) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
- -1, /* (323) range_or_rows ::= RANGE|ROWS|GROUPS */
- -1, /* (324) frame_bound_s ::= frame_bound */
- -2, /* (325) frame_bound_s ::= UNBOUNDED PRECEDING */
- -1, /* (326) frame_bound_e ::= frame_bound */
- -2, /* (327) frame_bound_e ::= UNBOUNDED FOLLOWING */
- -2, /* (328) frame_bound ::= expr PRECEDING|FOLLOWING */
- -2, /* (329) frame_bound ::= CURRENT ROW */
- 0, /* (330) frame_exclude_opt ::= */
- -2, /* (331) frame_exclude_opt ::= EXCLUDE frame_exclude */
- -2, /* (332) frame_exclude ::= NO OTHERS */
- -2, /* (333) frame_exclude ::= CURRENT ROW */
- -1, /* (334) frame_exclude ::= GROUP|TIES */
- -2, /* (335) window_clause ::= WINDOW windowdefn_list */
- -2, /* (336) filter_over ::= filter_clause over_clause */
- -1, /* (337) filter_over ::= over_clause */
- -1, /* (338) filter_over ::= filter_clause */
- -4, /* (339) over_clause ::= OVER LP window RP */
- -2, /* (340) over_clause ::= OVER nm */
- -5, /* (341) filter_clause ::= FILTER LP WHERE expr RP */
- -1, /* (342) input ::= cmdlist */
- -2, /* (343) cmdlist ::= cmdlist ecmd */
- -1, /* (344) cmdlist ::= ecmd */
- -1, /* (345) ecmd ::= SEMI */
- -2, /* (346) ecmd ::= cmdx SEMI */
- -3, /* (347) ecmd ::= explain cmdx SEMI */
- 0, /* (348) trans_opt ::= */
- -1, /* (349) trans_opt ::= TRANSACTION */
- -2, /* (350) trans_opt ::= TRANSACTION nm */
- -1, /* (351) savepoint_opt ::= SAVEPOINT */
- 0, /* (352) savepoint_opt ::= */
- -2, /* (353) cmd ::= create_table create_table_args */
- -1, /* (354) table_option_set ::= table_option */
- -4, /* (355) columnlist ::= columnlist COMMA columnname carglist */
- -2, /* (356) columnlist ::= columnname carglist */
- -1, /* (357) nm ::= ID|INDEXED */
- -1, /* (358) nm ::= STRING */
- -1, /* (359) nm ::= JOIN_KW */
- -1, /* (360) typetoken ::= typename */
- -1, /* (361) typename ::= ID|STRING */
- -1, /* (362) signed ::= plus_num */
- -1, /* (363) signed ::= minus_num */
- -2, /* (364) carglist ::= carglist ccons */
- 0, /* (365) carglist ::= */
- -2, /* (366) ccons ::= NULL onconf */
- -4, /* (367) ccons ::= GENERATED ALWAYS AS generated */
- -2, /* (368) ccons ::= AS generated */
- -2, /* (369) conslist_opt ::= COMMA conslist */
- -3, /* (370) conslist ::= conslist tconscomma tcons */
- -1, /* (371) conslist ::= tcons */
- 0, /* (372) tconscomma ::= */
- -1, /* (373) defer_subclause_opt ::= defer_subclause */
- -1, /* (374) resolvetype ::= raisetype */
- -1, /* (375) selectnowith ::= oneselect */
- -1, /* (376) oneselect ::= values */
- -2, /* (377) sclp ::= selcollist COMMA */
- -1, /* (378) as ::= ID|STRING */
- -1, /* (379) indexed_opt ::= indexed_by */
- 0, /* (380) returning ::= */
- -1, /* (381) expr ::= term */
- -1, /* (382) likeop ::= LIKE_KW|MATCH */
- -1, /* (383) exprlist ::= nexprlist */
- -1, /* (384) nmnum ::= plus_num */
- -1, /* (385) nmnum ::= nm */
- -1, /* (386) nmnum ::= ON */
- -1, /* (387) nmnum ::= DELETE */
- -1, /* (388) nmnum ::= DEFAULT */
- -1, /* (389) plus_num ::= INTEGER|FLOAT */
- 0, /* (390) foreach_clause ::= */
- -3, /* (391) foreach_clause ::= FOR EACH ROW */
- -1, /* (392) trnm ::= nm */
- 0, /* (393) tridxby ::= */
- -1, /* (394) database_kw_opt ::= DATABASE */
- 0, /* (395) database_kw_opt ::= */
- 0, /* (396) kwcolumn_opt ::= */
- -1, /* (397) kwcolumn_opt ::= COLUMNKW */
- -1, /* (398) vtabarglist ::= vtabarg */
- -3, /* (399) vtabarglist ::= vtabarglist COMMA vtabarg */
- -2, /* (400) vtabarg ::= vtabarg vtabargtoken */
- 0, /* (401) anylist ::= */
- -4, /* (402) anylist ::= anylist LP anylist RP */
- -2, /* (403) anylist ::= anylist ANY */
- 0, /* (404) with ::= */
+ -3, /* (311) windowdefn_list ::= windowdefn_list COMMA windowdefn */
+ -5, /* (312) windowdefn ::= nm AS LP window RP */
+ -5, /* (313) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
+ -6, /* (314) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
+ -4, /* (315) window ::= ORDER BY sortlist frame_opt */
+ -5, /* (316) window ::= nm ORDER BY sortlist frame_opt */
+ -2, /* (317) window ::= nm frame_opt */
+ 0, /* (318) frame_opt ::= */
+ -3, /* (319) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
+ -6, /* (320) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
+ -1, /* (321) range_or_rows ::= RANGE|ROWS|GROUPS */
+ -1, /* (322) frame_bound_s ::= frame_bound */
+ -2, /* (323) frame_bound_s ::= UNBOUNDED PRECEDING */
+ -1, /* (324) frame_bound_e ::= frame_bound */
+ -2, /* (325) frame_bound_e ::= UNBOUNDED FOLLOWING */
+ -2, /* (326) frame_bound ::= expr PRECEDING|FOLLOWING */
+ -2, /* (327) frame_bound ::= CURRENT ROW */
+ 0, /* (328) frame_exclude_opt ::= */
+ -2, /* (329) frame_exclude_opt ::= EXCLUDE frame_exclude */
+ -2, /* (330) frame_exclude ::= NO OTHERS */
+ -2, /* (331) frame_exclude ::= CURRENT ROW */
+ -1, /* (332) frame_exclude ::= GROUP|TIES */
+ -2, /* (333) window_clause ::= WINDOW windowdefn_list */
+ -2, /* (334) filter_over ::= filter_clause over_clause */
+ -1, /* (335) filter_over ::= over_clause */
+ -1, /* (336) filter_over ::= filter_clause */
+ -4, /* (337) over_clause ::= OVER LP window RP */
+ -2, /* (338) over_clause ::= OVER nm */
+ -5, /* (339) filter_clause ::= FILTER LP WHERE expr RP */
+ -1, /* (340) input ::= cmdlist */
+ -2, /* (341) cmdlist ::= cmdlist ecmd */
+ -1, /* (342) cmdlist ::= ecmd */
+ -1, /* (343) ecmd ::= SEMI */
+ -2, /* (344) ecmd ::= cmdx SEMI */
+ -3, /* (345) ecmd ::= explain cmdx SEMI */
+ 0, /* (346) trans_opt ::= */
+ -1, /* (347) trans_opt ::= TRANSACTION */
+ -2, /* (348) trans_opt ::= TRANSACTION nm */
+ -1, /* (349) savepoint_opt ::= SAVEPOINT */
+ 0, /* (350) savepoint_opt ::= */
+ -2, /* (351) cmd ::= create_table create_table_args */
+ -1, /* (352) table_option_set ::= table_option */
+ -4, /* (353) columnlist ::= columnlist COMMA columnname carglist */
+ -2, /* (354) columnlist ::= columnname carglist */
+ -1, /* (355) nm ::= ID|INDEXED|JOIN_KW */
+ -1, /* (356) nm ::= STRING */
+ -1, /* (357) typetoken ::= typename */
+ -1, /* (358) typename ::= ID|STRING */
+ -1, /* (359) signed ::= plus_num */
+ -1, /* (360) signed ::= minus_num */
+ -2, /* (361) carglist ::= carglist ccons */
+ 0, /* (362) carglist ::= */
+ -2, /* (363) ccons ::= NULL onconf */
+ -4, /* (364) ccons ::= GENERATED ALWAYS AS generated */
+ -2, /* (365) ccons ::= AS generated */
+ -2, /* (366) conslist_opt ::= COMMA conslist */
+ -3, /* (367) conslist ::= conslist tconscomma tcons */
+ -1, /* (368) conslist ::= tcons */
+ 0, /* (369) tconscomma ::= */
+ -1, /* (370) defer_subclause_opt ::= defer_subclause */
+ -1, /* (371) resolvetype ::= raisetype */
+ -1, /* (372) selectnowith ::= oneselect */
+ -1, /* (373) oneselect ::= values */
+ -2, /* (374) sclp ::= selcollist COMMA */
+ -1, /* (375) as ::= ID|STRING */
+ -1, /* (376) indexed_opt ::= indexed_by */
+ 0, /* (377) returning ::= */
+ -1, /* (378) expr ::= term */
+ -1, /* (379) likeop ::= LIKE_KW|MATCH */
+ -1, /* (380) case_operand ::= expr */
+ -1, /* (381) exprlist ::= nexprlist */
+ -1, /* (382) nmnum ::= plus_num */
+ -1, /* (383) nmnum ::= nm */
+ -1, /* (384) nmnum ::= ON */
+ -1, /* (385) nmnum ::= DELETE */
+ -1, /* (386) nmnum ::= DEFAULT */
+ -1, /* (387) plus_num ::= INTEGER|FLOAT */
+ 0, /* (388) foreach_clause ::= */
+ -3, /* (389) foreach_clause ::= FOR EACH ROW */
+ -1, /* (390) trnm ::= nm */
+ 0, /* (391) tridxby ::= */
+ -1, /* (392) database_kw_opt ::= DATABASE */
+ 0, /* (393) database_kw_opt ::= */
+ 0, /* (394) kwcolumn_opt ::= */
+ -1, /* (395) kwcolumn_opt ::= COLUMNKW */
+ -1, /* (396) vtabarglist ::= vtabarg */
+ -3, /* (397) vtabarglist ::= vtabarglist COMMA vtabarg */
+ -2, /* (398) vtabarg ::= vtabarg vtabargtoken */
+ 0, /* (399) anylist ::= */
+ -4, /* (400) anylist ::= anylist LP anylist RP */
+ -2, /* (401) anylist ::= anylist ANY */
+ 0, /* (402) with ::= */
+ -1, /* (403) windowdefn_list ::= windowdefn */
+ -1, /* (404) window ::= frame_opt */
};
static void yy_accept(yyParser*); /* Forward Declaration */
@@ -170361,10 +174715,10 @@ static YYACTIONTYPE yy_reduce(
/********** Begin reduce actions **********************************************/
YYMINORTYPE yylhsminor;
case 0: /* explain ::= EXPLAIN */
-{ pParse->explain = 1; }
+{ if( pParse->pReprepare==0 ) pParse->explain = 1; }
break;
case 1: /* explain ::= EXPLAIN QUERY PLAN */
-{ pParse->explain = 2; }
+{ if( pParse->pReprepare==0 ) pParse->explain = 2; }
break;
case 2: /* cmdx ::= cmd */
{ sqlite3FinishCoding(pParse); }
@@ -170378,7 +174732,7 @@ static YYACTIONTYPE yy_reduce(
case 5: /* transtype ::= DEFERRED */
case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6);
case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7);
- case 323: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==323);
+ case 321: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==321);
{yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-X*/}
break;
case 8: /* cmd ::= COMMIT|END trans_opt */
@@ -170599,8 +174953,8 @@ static YYACTIONTYPE yy_reduce(
break;
case 63: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
case 80: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==80);
- case 216: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==216);
- case 219: /* in_op ::= NOT IN */ yytestcase(yyruleno==219);
+ case 217: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==217);
+ case 220: /* in_op ::= NOT IN */ yytestcase(yyruleno==220);
case 245: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==245);
{yymsp[-1].minor.yy394 = 1;}
break;
@@ -170674,7 +175028,6 @@ static YYACTIONTYPE yy_reduce(
if( p ){
parserDoubleLinkSelect(pParse, p);
}
- yymsp[0].minor.yy47 = p; /*A-overwrites-X*/
}
break;
case 88: /* selectnowith ::= selectnowith multiselect_op oneselect */
@@ -170766,14 +175119,17 @@ static YYACTIONTYPE yy_reduce(
case 101: /* selcollist ::= sclp scanpt STAR */
{
Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0);
+ sqlite3ExprSetErrorOffset(p, (int)(yymsp[0].minor.yy0.z - pParse->zTail));
yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy322, p);
}
break;
case 102: /* selcollist ::= sclp scanpt nm DOT STAR */
{
- Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
- Expr *pLeft = tokenExpr(pParse, TK_ID, yymsp[-2].minor.yy0);
- Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
+ Expr *pRight, *pLeft, *pDot;
+ pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
+ sqlite3ExprSetErrorOffset(pRight, (int)(yymsp[0].minor.yy0.z - pParse->zTail));
+ pLeft = tokenExpr(pParse, TK_ID, yymsp[-2].minor.yy0);
+ pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, pDot);
}
break;
@@ -170824,7 +175180,7 @@ static YYACTIONTYPE yy_reduce(
{
if( yymsp[-5].minor.yy131==0 && yymsp[-1].minor.yy0.n==0 && yymsp[0].minor.yy561.pOn==0 && yymsp[0].minor.yy561.pUsing==0 ){
yymsp[-5].minor.yy131 = yymsp[-3].minor.yy131;
- }else if( yymsp[-3].minor.yy131->nSrc==1 ){
+ }else if( ALWAYS(yymsp[-3].minor.yy131!=0) && yymsp[-3].minor.yy131->nSrc==1 ){
yymsp[-5].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,0,0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy561);
if( yymsp[-5].minor.yy131 ){
SrcItem *pNew = &yymsp[-5].minor.yy131->a[yymsp[-5].minor.yy131->nSrc-1];
@@ -170952,7 +175308,7 @@ static YYACTIONTYPE yy_reduce(
case 146: /* limit_opt ::= */ yytestcase(yyruleno==146);
case 151: /* where_opt ::= */ yytestcase(yyruleno==151);
case 153: /* where_opt_ret ::= */ yytestcase(yyruleno==153);
- case 229: /* case_else ::= */ yytestcase(yyruleno==229);
+ case 230: /* case_else ::= */ yytestcase(yyruleno==230);
case 231: /* case_operand ::= */ yytestcase(yyruleno==231);
case 250: /* vinto ::= */ yytestcase(yyruleno==250);
{yymsp[1].minor.yy528 = 0;}
@@ -170960,7 +175316,7 @@ static YYACTIONTYPE yy_reduce(
case 145: /* having_opt ::= HAVING expr */
case 152: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==152);
case 154: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==154);
- case 228: /* case_else ::= ELSE expr */ yytestcase(yyruleno==228);
+ case 229: /* case_else ::= ELSE expr */ yytestcase(yyruleno==229);
case 249: /* vinto ::= INTO expr */ yytestcase(yyruleno==249);
{yymsp[-1].minor.yy528 = yymsp[0].minor.yy528;}
break;
@@ -171073,11 +175429,10 @@ static YYACTIONTYPE yy_reduce(
case 177: /* expr ::= LP expr RP */
{yymsp[-2].minor.yy528 = yymsp[-1].minor.yy528;}
break;
- case 178: /* expr ::= ID|INDEXED */
- case 179: /* expr ::= JOIN_KW */ yytestcase(yyruleno==179);
+ case 178: /* expr ::= ID|INDEXED|JOIN_KW */
{yymsp[0].minor.yy528=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
break;
- case 180: /* expr ::= nm DOT nm */
+ case 179: /* expr ::= nm DOT nm */
{
Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0);
Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0);
@@ -171085,7 +175440,7 @@ static YYACTIONTYPE yy_reduce(
}
yymsp[-2].minor.yy528 = yylhsminor.yy528;
break;
- case 181: /* expr ::= nm DOT nm DOT nm */
+ case 180: /* expr ::= nm DOT nm DOT nm */
{
Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-4].minor.yy0);
Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0);
@@ -171098,18 +175453,18 @@ static YYACTIONTYPE yy_reduce(
}
yymsp[-4].minor.yy528 = yylhsminor.yy528;
break;
- case 182: /* term ::= NULL|FLOAT|BLOB */
- case 183: /* term ::= STRING */ yytestcase(yyruleno==183);
+ case 181: /* term ::= NULL|FLOAT|BLOB */
+ case 182: /* term ::= STRING */ yytestcase(yyruleno==182);
{yymsp[0].minor.yy528=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/}
break;
- case 184: /* term ::= INTEGER */
+ case 183: /* term ::= INTEGER */
{
yylhsminor.yy528 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
if( yylhsminor.yy528 ) yylhsminor.yy528->w.iOfst = (int)(yymsp[0].minor.yy0.z - pParse->zTail);
}
yymsp[0].minor.yy528 = yylhsminor.yy528;
break;
- case 185: /* expr ::= VARIABLE */
+ case 184: /* expr ::= VARIABLE */
{
if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){
u32 n = yymsp[0].minor.yy0.n;
@@ -171131,50 +175486,65 @@ static YYACTIONTYPE yy_reduce(
}
}
break;
- case 186: /* expr ::= expr COLLATE ID|STRING */
+ case 185: /* expr ::= expr COLLATE ID|STRING */
{
yymsp[-2].minor.yy528 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy528, &yymsp[0].minor.yy0, 1);
}
break;
- case 187: /* expr ::= CAST LP expr AS typetoken RP */
+ case 186: /* expr ::= CAST LP expr AS typetoken RP */
{
yymsp[-5].minor.yy528 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy528, yymsp[-3].minor.yy528, 0);
}
break;
- case 188: /* expr ::= ID|INDEXED LP distinct exprlist RP */
+ case 187: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */
{
yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy394);
}
yymsp[-4].minor.yy528 = yylhsminor.yy528;
break;
- case 189: /* expr ::= ID|INDEXED LP STAR RP */
+ case 188: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP */
+{
+ yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-4].minor.yy322, &yymsp[-7].minor.yy0, yymsp[-5].minor.yy394);
+ sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy528, yymsp[-1].minor.yy322);
+}
+ yymsp[-7].minor.yy528 = yylhsminor.yy528;
+ break;
+ case 189: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP */
{
yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0);
}
yymsp[-3].minor.yy528 = yylhsminor.yy528;
break;
- case 190: /* expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
+ case 190: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */
{
yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy322, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy394);
sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41);
}
yymsp[-5].minor.yy528 = yylhsminor.yy528;
break;
- case 191: /* expr ::= ID|INDEXED LP STAR RP filter_over */
+ case 191: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist ORDER BY sortlist RP filter_over */
+{
+ yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-5].minor.yy322, &yymsp[-8].minor.yy0, yymsp[-6].minor.yy394);
+ sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41);
+ sqlite3ExprAddFunctionOrderBy(pParse, yylhsminor.yy528, yymsp[-2].minor.yy322);
+}
+ yymsp[-8].minor.yy528 = yylhsminor.yy528;
+ break;
+ case 192: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */
{
yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0);
sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41);
}
yymsp[-4].minor.yy528 = yylhsminor.yy528;
break;
- case 192: /* term ::= CTIME_KW */
+ case 193: /* term ::= CTIME_KW */
{
yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0);
}
yymsp[0].minor.yy528 = yylhsminor.yy528;
break;
- case 193: /* expr ::= LP nexprlist COMMA expr RP */
+ case 194: /* expr ::= LP nexprlist COMMA expr RP */
{
ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy322, yymsp[-1].minor.yy528);
yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
@@ -171188,22 +175558,22 @@ static YYACTIONTYPE yy_reduce(
}
}
break;
- case 194: /* expr ::= expr AND expr */
+ case 195: /* expr ::= expr AND expr */
{yymsp[-2].minor.yy528=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);}
break;
- case 195: /* expr ::= expr OR expr */
- case 196: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==196);
- case 197: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==197);
- case 198: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==198);
- case 199: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==199);
- case 200: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==200);
- case 201: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==201);
+ case 196: /* expr ::= expr OR expr */
+ case 197: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==197);
+ case 198: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==198);
+ case 199: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==199);
+ case 200: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==200);
+ case 201: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==201);
+ case 202: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==202);
{yymsp[-2].minor.yy528=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);}
break;
- case 202: /* likeop ::= NOT LIKE_KW|MATCH */
+ case 203: /* 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 203: /* expr ::= expr likeop expr */
+ case 204: /* expr ::= expr likeop expr */
{
ExprList *pList;
int bNot = yymsp[-1].minor.yy0.n & 0x80000000;
@@ -171215,7 +175585,7 @@ static YYACTIONTYPE yy_reduce(
if( yymsp[-2].minor.yy528 ) yymsp[-2].minor.yy528->flags |= EP_InfixFunc;
}
break;
- case 204: /* expr ::= expr likeop expr ESCAPE expr */
+ case 205: /* expr ::= expr likeop expr ESCAPE expr */
{
ExprList *pList;
int bNot = yymsp[-3].minor.yy0.n & 0x80000000;
@@ -171228,47 +175598,47 @@ static YYACTIONTYPE yy_reduce(
if( yymsp[-4].minor.yy528 ) yymsp[-4].minor.yy528->flags |= EP_InfixFunc;
}
break;
- case 205: /* expr ::= expr ISNULL|NOTNULL */
+ case 206: /* expr ::= expr ISNULL|NOTNULL */
{yymsp[-1].minor.yy528 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy528,0);}
break;
- case 206: /* expr ::= expr NOT NULL */
+ case 207: /* expr ::= expr NOT NULL */
{yymsp[-2].minor.yy528 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy528,0);}
break;
- case 207: /* expr ::= expr IS expr */
+ case 208: /* expr ::= expr IS expr */
{
yymsp[-2].minor.yy528 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);
binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-2].minor.yy528, TK_ISNULL);
}
break;
- case 208: /* expr ::= expr IS NOT expr */
+ case 209: /* expr ::= expr IS NOT expr */
{
yymsp[-3].minor.yy528 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy528,yymsp[0].minor.yy528);
binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-3].minor.yy528, TK_NOTNULL);
}
break;
- case 209: /* expr ::= expr IS NOT DISTINCT FROM expr */
+ case 210: /* expr ::= expr IS NOT DISTINCT FROM expr */
{
yymsp[-5].minor.yy528 = sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy528,yymsp[0].minor.yy528);
binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-5].minor.yy528, TK_ISNULL);
}
break;
- case 210: /* expr ::= expr IS DISTINCT FROM expr */
+ case 211: /* expr ::= expr IS DISTINCT FROM expr */
{
yymsp[-4].minor.yy528 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy528,yymsp[0].minor.yy528);
binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-4].minor.yy528, TK_NOTNULL);
}
break;
- case 211: /* expr ::= NOT expr */
- case 212: /* expr ::= BITNOT expr */ yytestcase(yyruleno==212);
+ case 212: /* expr ::= NOT expr */
+ case 213: /* expr ::= BITNOT expr */ yytestcase(yyruleno==213);
{yymsp[-1].minor.yy528 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy528, 0);/*A-overwrites-B*/}
break;
- case 213: /* expr ::= PLUS|MINUS expr */
+ case 214: /* expr ::= PLUS|MINUS expr */
{
yymsp[-1].minor.yy528 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy528, 0);
/*A-overwrites-B*/
}
break;
- case 214: /* expr ::= expr PTR expr */
+ case 215: /* expr ::= expr PTR expr */
{
ExprList *pList = sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy528);
pList = sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy528);
@@ -171276,11 +175646,11 @@ static YYACTIONTYPE yy_reduce(
}
yymsp[-2].minor.yy528 = yylhsminor.yy528;
break;
- case 215: /* between_op ::= BETWEEN */
- case 218: /* in_op ::= IN */ yytestcase(yyruleno==218);
+ case 216: /* between_op ::= BETWEEN */
+ case 219: /* in_op ::= IN */ yytestcase(yyruleno==219);
{yymsp[0].minor.yy394 = 0;}
break;
- case 217: /* expr ::= expr between_op expr AND expr */
+ case 218: /* expr ::= expr between_op expr AND expr */
{
ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528);
pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy528);
@@ -171293,7 +175663,7 @@ static YYACTIONTYPE yy_reduce(
if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
}
break;
- case 220: /* expr ::= expr in_op LP exprlist RP */
+ case 221: /* expr ::= expr in_op LP exprlist RP */
{
if( yymsp[-1].minor.yy322==0 ){
/* Expressions of the form
@@ -171339,20 +175709,20 @@ static YYACTIONTYPE yy_reduce(
}
}
break;
- case 221: /* expr ::= LP select RP */
+ case 222: /* expr ::= LP select RP */
{
yymsp[-2].minor.yy528 = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy528, yymsp[-1].minor.yy47);
}
break;
- case 222: /* expr ::= expr in_op LP select RP */
+ case 223: /* expr ::= expr in_op LP select RP */
{
yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0);
sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, yymsp[-1].minor.yy47);
if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
}
break;
- case 223: /* expr ::= expr in_op nm dbnm paren_exprlist */
+ case 224: /* expr ::= expr in_op nm dbnm paren_exprlist */
{
SrcList *pSrc = sqlite3SrcListAppend(pParse, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);
Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0);
@@ -171362,14 +175732,14 @@ static YYACTIONTYPE yy_reduce(
if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
}
break;
- case 224: /* expr ::= EXISTS LP select RP */
+ case 225: /* expr ::= EXISTS LP select RP */
{
Expr *p;
p = yymsp[-3].minor.yy528 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy47);
}
break;
- case 225: /* expr ::= CASE case_operand case_exprlist case_else END */
+ case 226: /* expr ::= CASE case_operand case_exprlist case_else END */
{
yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy528, 0);
if( yymsp[-4].minor.yy528 ){
@@ -171381,21 +175751,18 @@ static YYACTIONTYPE yy_reduce(
}
}
break;
- case 226: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ case 227: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
{
yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[-2].minor.yy528);
yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[0].minor.yy528);
}
break;
- case 227: /* case_exprlist ::= WHEN expr THEN expr */
+ case 228: /* case_exprlist ::= WHEN expr THEN expr */
{
yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528);
yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322, yymsp[0].minor.yy528);
}
break;
- case 230: /* case_operand ::= expr */
-{yymsp[0].minor.yy528 = yymsp[0].minor.yy528; /*A-overwrites-X*/}
- break;
case 233: /* nexprlist ::= nexprlist COMMA expr */
{yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[0].minor.yy528);}
break;
@@ -171671,11 +176038,7 @@ static YYACTIONTYPE yy_reduce(
yymsp[-2].minor.yy521 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy521, yymsp[0].minor.yy385);
}
break;
- case 311: /* windowdefn_list ::= windowdefn */
-{ yylhsminor.yy41 = yymsp[0].minor.yy41; }
- yymsp[0].minor.yy41 = yylhsminor.yy41;
- break;
- case 312: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */
+ case 311: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */
{
assert( yymsp[0].minor.yy41!=0 );
sqlite3WindowChain(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy41);
@@ -171684,7 +176047,7 @@ static YYACTIONTYPE yy_reduce(
}
yymsp[-2].minor.yy41 = yylhsminor.yy41;
break;
- case 313: /* windowdefn ::= nm AS LP window RP */
+ case 312: /* windowdefn ::= nm AS LP window RP */
{
if( ALWAYS(yymsp[-1].minor.yy41) ){
yymsp[-1].minor.yy41->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n);
@@ -171693,90 +176056,83 @@ static YYACTIONTYPE yy_reduce(
}
yymsp[-4].minor.yy41 = yylhsminor.yy41;
break;
- case 314: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */
+ case 313: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */
{
yymsp[-4].minor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy322, yymsp[-1].minor.yy322, 0);
}
break;
- case 315: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
+ case 314: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
{
yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy322, yymsp[-1].minor.yy322, &yymsp[-5].minor.yy0);
}
yymsp[-5].minor.yy41 = yylhsminor.yy41;
break;
- case 316: /* window ::= ORDER BY sortlist frame_opt */
+ case 315: /* window ::= ORDER BY sortlist frame_opt */
{
yymsp[-3].minor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, yymsp[-1].minor.yy322, 0);
}
break;
- case 317: /* window ::= nm ORDER BY sortlist frame_opt */
+ case 316: /* window ::= nm ORDER BY sortlist frame_opt */
{
yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0);
}
yymsp[-4].minor.yy41 = yylhsminor.yy41;
break;
- case 318: /* window ::= frame_opt */
- case 337: /* filter_over ::= over_clause */ yytestcase(yyruleno==337);
-{
- yylhsminor.yy41 = yymsp[0].minor.yy41;
-}
- yymsp[0].minor.yy41 = yylhsminor.yy41;
- break;
- case 319: /* window ::= nm frame_opt */
+ case 317: /* window ::= nm frame_opt */
{
yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, 0, &yymsp[-1].minor.yy0);
}
yymsp[-1].minor.yy41 = yylhsminor.yy41;
break;
- case 320: /* frame_opt ::= */
+ case 318: /* frame_opt ::= */
{
yymsp[1].minor.yy41 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0);
}
break;
- case 321: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
+ case 319: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
{
yylhsminor.yy41 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy394, yymsp[-1].minor.yy595.eType, yymsp[-1].minor.yy595.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy516);
}
yymsp[-2].minor.yy41 = yylhsminor.yy41;
break;
- case 322: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
+ case 320: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
{
yylhsminor.yy41 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy394, yymsp[-3].minor.yy595.eType, yymsp[-3].minor.yy595.pExpr, yymsp[-1].minor.yy595.eType, yymsp[-1].minor.yy595.pExpr, yymsp[0].minor.yy516);
}
yymsp[-5].minor.yy41 = yylhsminor.yy41;
break;
- case 324: /* frame_bound_s ::= frame_bound */
- case 326: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==326);
+ case 322: /* frame_bound_s ::= frame_bound */
+ case 324: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==324);
{yylhsminor.yy595 = yymsp[0].minor.yy595;}
yymsp[0].minor.yy595 = yylhsminor.yy595;
break;
- case 325: /* frame_bound_s ::= UNBOUNDED PRECEDING */
- case 327: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==327);
- case 329: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==329);
+ case 323: /* frame_bound_s ::= UNBOUNDED PRECEDING */
+ case 325: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==325);
+ case 327: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==327);
{yylhsminor.yy595.eType = yymsp[-1].major; yylhsminor.yy595.pExpr = 0;}
yymsp[-1].minor.yy595 = yylhsminor.yy595;
break;
- case 328: /* frame_bound ::= expr PRECEDING|FOLLOWING */
+ case 326: /* frame_bound ::= expr PRECEDING|FOLLOWING */
{yylhsminor.yy595.eType = yymsp[0].major; yylhsminor.yy595.pExpr = yymsp[-1].minor.yy528;}
yymsp[-1].minor.yy595 = yylhsminor.yy595;
break;
- case 330: /* frame_exclude_opt ::= */
+ case 328: /* frame_exclude_opt ::= */
{yymsp[1].minor.yy516 = 0;}
break;
- case 331: /* frame_exclude_opt ::= EXCLUDE frame_exclude */
+ case 329: /* frame_exclude_opt ::= EXCLUDE frame_exclude */
{yymsp[-1].minor.yy516 = yymsp[0].minor.yy516;}
break;
- case 332: /* frame_exclude ::= NO OTHERS */
- case 333: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==333);
+ case 330: /* frame_exclude ::= NO OTHERS */
+ case 331: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==331);
{yymsp[-1].minor.yy516 = yymsp[-1].major; /*A-overwrites-X*/}
break;
- case 334: /* frame_exclude ::= GROUP|TIES */
+ case 332: /* frame_exclude ::= GROUP|TIES */
{yymsp[0].minor.yy516 = yymsp[0].major; /*A-overwrites-X*/}
break;
- case 335: /* window_clause ::= WINDOW windowdefn_list */
+ case 333: /* window_clause ::= WINDOW windowdefn_list */
{ yymsp[-1].minor.yy41 = yymsp[0].minor.yy41; }
break;
- case 336: /* filter_over ::= filter_clause over_clause */
+ case 334: /* filter_over ::= filter_clause over_clause */
{
if( yymsp[0].minor.yy41 ){
yymsp[0].minor.yy41->pFilter = yymsp[-1].minor.yy528;
@@ -171787,7 +176143,13 @@ static YYACTIONTYPE yy_reduce(
}
yymsp[-1].minor.yy41 = yylhsminor.yy41;
break;
- case 338: /* filter_over ::= filter_clause */
+ case 335: /* filter_over ::= over_clause */
+{
+ yylhsminor.yy41 = yymsp[0].minor.yy41;
+}
+ yymsp[0].minor.yy41 = yylhsminor.yy41;
+ break;
+ case 336: /* filter_over ::= filter_clause */
{
yylhsminor.yy41 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
if( yylhsminor.yy41 ){
@@ -171799,13 +176161,13 @@ static YYACTIONTYPE yy_reduce(
}
yymsp[0].minor.yy41 = yylhsminor.yy41;
break;
- case 339: /* over_clause ::= OVER LP window RP */
+ case 337: /* over_clause ::= OVER LP window RP */
{
yymsp[-3].minor.yy41 = yymsp[-1].minor.yy41;
assert( yymsp[-3].minor.yy41!=0 );
}
break;
- case 340: /* over_clause ::= OVER nm */
+ case 338: /* over_clause ::= OVER nm */
{
yymsp[-1].minor.yy41 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
if( yymsp[-1].minor.yy41 ){
@@ -171813,73 +176175,75 @@ static YYACTIONTYPE yy_reduce(
}
}
break;
- case 341: /* filter_clause ::= FILTER LP WHERE expr RP */
+ case 339: /* filter_clause ::= FILTER LP WHERE expr RP */
{ yymsp[-4].minor.yy528 = yymsp[-1].minor.yy528; }
break;
default:
- /* (342) input ::= cmdlist */ yytestcase(yyruleno==342);
- /* (343) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==343);
- /* (344) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=344);
- /* (345) ecmd ::= SEMI */ yytestcase(yyruleno==345);
- /* (346) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==346);
- /* (347) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=347);
- /* (348) trans_opt ::= */ yytestcase(yyruleno==348);
- /* (349) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==349);
- /* (350) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==350);
- /* (351) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==351);
- /* (352) savepoint_opt ::= */ yytestcase(yyruleno==352);
- /* (353) cmd ::= create_table create_table_args */ yytestcase(yyruleno==353);
- /* (354) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=354);
- /* (355) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==355);
- /* (356) columnlist ::= columnname carglist */ yytestcase(yyruleno==356);
- /* (357) nm ::= ID|INDEXED */ yytestcase(yyruleno==357);
- /* (358) nm ::= STRING */ yytestcase(yyruleno==358);
- /* (359) nm ::= JOIN_KW */ yytestcase(yyruleno==359);
- /* (360) typetoken ::= typename */ yytestcase(yyruleno==360);
- /* (361) typename ::= ID|STRING */ yytestcase(yyruleno==361);
- /* (362) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=362);
- /* (363) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=363);
- /* (364) carglist ::= carglist ccons */ yytestcase(yyruleno==364);
- /* (365) carglist ::= */ yytestcase(yyruleno==365);
- /* (366) ccons ::= NULL onconf */ yytestcase(yyruleno==366);
- /* (367) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==367);
- /* (368) ccons ::= AS generated */ yytestcase(yyruleno==368);
- /* (369) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==369);
- /* (370) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==370);
- /* (371) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=371);
- /* (372) tconscomma ::= */ yytestcase(yyruleno==372);
- /* (373) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=373);
- /* (374) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=374);
- /* (375) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=375);
- /* (376) oneselect ::= values */ yytestcase(yyruleno==376);
- /* (377) sclp ::= selcollist COMMA */ yytestcase(yyruleno==377);
- /* (378) as ::= ID|STRING */ yytestcase(yyruleno==378);
- /* (379) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=379);
- /* (380) returning ::= */ yytestcase(yyruleno==380);
- /* (381) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=381);
- /* (382) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==382);
- /* (383) exprlist ::= nexprlist */ yytestcase(yyruleno==383);
- /* (384) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=384);
- /* (385) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=385);
- /* (386) nmnum ::= ON */ yytestcase(yyruleno==386);
- /* (387) nmnum ::= DELETE */ yytestcase(yyruleno==387);
- /* (388) nmnum ::= DEFAULT */ yytestcase(yyruleno==388);
- /* (389) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==389);
- /* (390) foreach_clause ::= */ yytestcase(yyruleno==390);
- /* (391) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==391);
- /* (392) trnm ::= nm */ yytestcase(yyruleno==392);
- /* (393) tridxby ::= */ yytestcase(yyruleno==393);
- /* (394) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==394);
- /* (395) database_kw_opt ::= */ yytestcase(yyruleno==395);
- /* (396) kwcolumn_opt ::= */ yytestcase(yyruleno==396);
- /* (397) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==397);
- /* (398) vtabarglist ::= vtabarg */ yytestcase(yyruleno==398);
- /* (399) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==399);
- /* (400) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==400);
- /* (401) anylist ::= */ yytestcase(yyruleno==401);
- /* (402) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==402);
- /* (403) anylist ::= anylist ANY */ yytestcase(yyruleno==403);
- /* (404) with ::= */ yytestcase(yyruleno==404);
+ /* (340) input ::= cmdlist */ yytestcase(yyruleno==340);
+ /* (341) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==341);
+ /* (342) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=342);
+ /* (343) ecmd ::= SEMI */ yytestcase(yyruleno==343);
+ /* (344) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==344);
+ /* (345) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=345);
+ /* (346) trans_opt ::= */ yytestcase(yyruleno==346);
+ /* (347) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==347);
+ /* (348) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==348);
+ /* (349) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==349);
+ /* (350) savepoint_opt ::= */ yytestcase(yyruleno==350);
+ /* (351) cmd ::= create_table create_table_args */ yytestcase(yyruleno==351);
+ /* (352) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=352);
+ /* (353) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==353);
+ /* (354) columnlist ::= columnname carglist */ yytestcase(yyruleno==354);
+ /* (355) nm ::= ID|INDEXED|JOIN_KW */ yytestcase(yyruleno==355);
+ /* (356) nm ::= STRING */ yytestcase(yyruleno==356);
+ /* (357) typetoken ::= typename */ yytestcase(yyruleno==357);
+ /* (358) typename ::= ID|STRING */ yytestcase(yyruleno==358);
+ /* (359) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=359);
+ /* (360) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=360);
+ /* (361) carglist ::= carglist ccons */ yytestcase(yyruleno==361);
+ /* (362) carglist ::= */ yytestcase(yyruleno==362);
+ /* (363) ccons ::= NULL onconf */ yytestcase(yyruleno==363);
+ /* (364) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==364);
+ /* (365) ccons ::= AS generated */ yytestcase(yyruleno==365);
+ /* (366) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==366);
+ /* (367) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==367);
+ /* (368) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=368);
+ /* (369) tconscomma ::= */ yytestcase(yyruleno==369);
+ /* (370) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=370);
+ /* (371) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=371);
+ /* (372) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=372);
+ /* (373) oneselect ::= values */ yytestcase(yyruleno==373);
+ /* (374) sclp ::= selcollist COMMA */ yytestcase(yyruleno==374);
+ /* (375) as ::= ID|STRING */ yytestcase(yyruleno==375);
+ /* (376) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=376);
+ /* (377) returning ::= */ yytestcase(yyruleno==377);
+ /* (378) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=378);
+ /* (379) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==379);
+ /* (380) case_operand ::= expr */ yytestcase(yyruleno==380);
+ /* (381) exprlist ::= nexprlist */ yytestcase(yyruleno==381);
+ /* (382) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=382);
+ /* (383) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=383);
+ /* (384) nmnum ::= ON */ yytestcase(yyruleno==384);
+ /* (385) nmnum ::= DELETE */ yytestcase(yyruleno==385);
+ /* (386) nmnum ::= DEFAULT */ yytestcase(yyruleno==386);
+ /* (387) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==387);
+ /* (388) foreach_clause ::= */ yytestcase(yyruleno==388);
+ /* (389) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==389);
+ /* (390) trnm ::= nm */ yytestcase(yyruleno==390);
+ /* (391) tridxby ::= */ yytestcase(yyruleno==391);
+ /* (392) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==392);
+ /* (393) database_kw_opt ::= */ yytestcase(yyruleno==393);
+ /* (394) kwcolumn_opt ::= */ yytestcase(yyruleno==394);
+ /* (395) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==395);
+ /* (396) vtabarglist ::= vtabarg */ yytestcase(yyruleno==396);
+ /* (397) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==397);
+ /* (398) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==398);
+ /* (399) anylist ::= */ yytestcase(yyruleno==399);
+ /* (400) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==400);
+ /* (401) anylist ::= anylist ANY */ yytestcase(yyruleno==401);
+ /* (402) with ::= */ yytestcase(yyruleno==402);
+ /* (403) windowdefn_list ::= windowdefn (OPTIMIZED OUT) */ assert(yyruleno!=403);
+ /* (404) window ::= frame_opt (OPTIMIZED OUT) */ assert(yyruleno!=404);
break;
/********** End reduce actions ************************************************/
};
@@ -172455,7 +176819,7 @@ static const unsigned char aKWHash[127] = {
/* aKWNext[] forms the hash collision chain. If aKWHash[i]==0
** then the i-th keyword has no more hash collisions. Otherwise,
** the next keyword with the same hash is aKWHash[i]-1. */
-static const unsigned char aKWNext[147] = {
+static const unsigned char aKWNext[148] = {0,
0, 0, 0, 0, 4, 0, 43, 0, 0, 106, 114, 0, 0,
0, 2, 0, 0, 143, 0, 0, 0, 13, 0, 0, 0, 0,
141, 0, 0, 119, 52, 0, 0, 137, 12, 0, 0, 62, 0,
@@ -172470,7 +176834,7 @@ static const unsigned char aKWNext[147] = {
102, 0, 0, 87,
};
/* aKWLen[i] is the length (in bytes) of the i-th keyword */
-static const unsigned char aKWLen[147] = {
+static const unsigned char aKWLen[148] = {0,
7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6,
7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 7,
6, 9, 4, 2, 6, 5, 9, 9, 4, 7, 3, 2, 4,
@@ -172486,7 +176850,7 @@ static const unsigned char aKWLen[147] = {
};
/* aKWOffset[i] is the index into zKWText[] of the start of
** the text for the i-th keyword. */
-static const unsigned short int aKWOffset[147] = {
+static const unsigned short int aKWOffset[148] = {0,
0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33,
36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81,
86, 90, 90, 94, 99, 101, 105, 111, 119, 123, 123, 123, 126,
@@ -172501,7 +176865,7 @@ static const unsigned short int aKWOffset[147] = {
648, 650, 655, 659,
};
/* aKWCode[i] is the parser symbol code for the i-th keyword */
-static const unsigned char aKWCode[147] = {
+static const unsigned char aKWCode[148] = {0,
TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE,
TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN,
TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD,
@@ -172668,185 +177032,185 @@ static const unsigned char aKWCode[147] = {
static int keywordCode(const char *z, int n, int *pType){
int i, j;
const char *zKW;
- if( n>=2 ){
- i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n*1) % 127;
- for(i=((int)aKWHash[i])-1; i>=0; i=((int)aKWNext[i])-1){
- if( aKWLen[i]!=n ) continue;
- zKW = &zKWText[aKWOffset[i]];
+ assert( n>=2 );
+ i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n*1) % 127;
+ for(i=(int)aKWHash[i]; i>0; i=aKWNext[i]){
+ if( aKWLen[i]!=n ) continue;
+ zKW = &zKWText[aKWOffset[i]];
#ifdef SQLITE_ASCII
- if( (z[0]&~0x20)!=zKW[0] ) continue;
- if( (z[1]&~0x20)!=zKW[1] ) continue;
- j = 2;
- while( j<n && (z[j]&~0x20)==zKW[j] ){ j++; }
+ if( (z[0]&~0x20)!=zKW[0] ) continue;
+ if( (z[1]&~0x20)!=zKW[1] ) continue;
+ j = 2;
+ while( j<n && (z[j]&~0x20)==zKW[j] ){ j++; }
#endif
#ifdef SQLITE_EBCDIC
- if( toupper(z[0])!=zKW[0] ) continue;
- if( toupper(z[1])!=zKW[1] ) continue;
- j = 2;
- while( j<n && toupper(z[j])==zKW[j] ){ j++; }
-#endif
- if( j<n ) continue;
- testcase( i==0 ); /* REINDEX */
- testcase( i==1 ); /* INDEXED */
- testcase( i==2 ); /* INDEX */
- testcase( i==3 ); /* DESC */
- testcase( i==4 ); /* ESCAPE */
- testcase( i==5 ); /* EACH */
- testcase( i==6 ); /* CHECK */
- testcase( i==7 ); /* KEY */
- testcase( i==8 ); /* BEFORE */
- testcase( i==9 ); /* FOREIGN */
- testcase( i==10 ); /* FOR */
- testcase( i==11 ); /* IGNORE */
- testcase( i==12 ); /* REGEXP */
- testcase( i==13 ); /* EXPLAIN */
- testcase( i==14 ); /* INSTEAD */
- testcase( i==15 ); /* ADD */
- testcase( i==16 ); /* DATABASE */
- testcase( i==17 ); /* AS */
- testcase( i==18 ); /* SELECT */
- testcase( i==19 ); /* TABLE */
- testcase( i==20 ); /* LEFT */
- testcase( i==21 ); /* THEN */
- testcase( i==22 ); /* END */
- testcase( i==23 ); /* DEFERRABLE */
- testcase( i==24 ); /* ELSE */
- testcase( i==25 ); /* EXCLUDE */
- testcase( i==26 ); /* DELETE */
- testcase( i==27 ); /* TEMPORARY */
- testcase( i==28 ); /* TEMP */
- testcase( i==29 ); /* OR */
- testcase( i==30 ); /* ISNULL */
- testcase( i==31 ); /* NULLS */
- testcase( i==32 ); /* SAVEPOINT */
- testcase( i==33 ); /* INTERSECT */
- testcase( i==34 ); /* TIES */
- testcase( i==35 ); /* NOTNULL */
- testcase( i==36 ); /* NOT */
- testcase( i==37 ); /* NO */
- testcase( i==38 ); /* NULL */
- testcase( i==39 ); /* LIKE */
- testcase( i==40 ); /* EXCEPT */
- testcase( i==41 ); /* TRANSACTION */
- testcase( i==42 ); /* ACTION */
- testcase( i==43 ); /* ON */
- testcase( i==44 ); /* NATURAL */
- testcase( i==45 ); /* ALTER */
- testcase( i==46 ); /* RAISE */
- testcase( i==47 ); /* EXCLUSIVE */
- testcase( i==48 ); /* EXISTS */
- testcase( i==49 ); /* CONSTRAINT */
- testcase( i==50 ); /* INTO */
- testcase( i==51 ); /* OFFSET */
- testcase( i==52 ); /* OF */
- testcase( i==53 ); /* SET */
- testcase( i==54 ); /* TRIGGER */
- testcase( i==55 ); /* RANGE */
- testcase( i==56 ); /* GENERATED */
- testcase( i==57 ); /* DETACH */
- testcase( i==58 ); /* HAVING */
- testcase( i==59 ); /* GLOB */
- testcase( i==60 ); /* BEGIN */
- testcase( i==61 ); /* INNER */
- testcase( i==62 ); /* REFERENCES */
- testcase( i==63 ); /* UNIQUE */
- testcase( i==64 ); /* QUERY */
- testcase( i==65 ); /* WITHOUT */
- testcase( i==66 ); /* WITH */
- testcase( i==67 ); /* OUTER */
- testcase( i==68 ); /* RELEASE */
- testcase( i==69 ); /* ATTACH */
- testcase( i==70 ); /* BETWEEN */
- testcase( i==71 ); /* NOTHING */
- testcase( i==72 ); /* GROUPS */
- testcase( i==73 ); /* GROUP */
- testcase( i==74 ); /* CASCADE */
- testcase( i==75 ); /* ASC */
- testcase( i==76 ); /* DEFAULT */
- testcase( i==77 ); /* CASE */
- testcase( i==78 ); /* COLLATE */
- testcase( i==79 ); /* CREATE */
- testcase( i==80 ); /* CURRENT_DATE */
- testcase( i==81 ); /* IMMEDIATE */
- testcase( i==82 ); /* JOIN */
- testcase( i==83 ); /* INSERT */
- testcase( i==84 ); /* MATCH */
- testcase( i==85 ); /* PLAN */
- testcase( i==86 ); /* ANALYZE */
- testcase( i==87 ); /* PRAGMA */
- testcase( i==88 ); /* MATERIALIZED */
- testcase( i==89 ); /* DEFERRED */
- testcase( i==90 ); /* DISTINCT */
- testcase( i==91 ); /* IS */
- testcase( i==92 ); /* UPDATE */
- testcase( i==93 ); /* VALUES */
- testcase( i==94 ); /* VIRTUAL */
- testcase( i==95 ); /* ALWAYS */
- testcase( i==96 ); /* WHEN */
- testcase( i==97 ); /* WHERE */
- testcase( i==98 ); /* RECURSIVE */
- testcase( i==99 ); /* ABORT */
- testcase( i==100 ); /* AFTER */
- testcase( i==101 ); /* RENAME */
- testcase( i==102 ); /* AND */
- testcase( i==103 ); /* DROP */
- testcase( i==104 ); /* PARTITION */
- testcase( i==105 ); /* AUTOINCREMENT */
- testcase( i==106 ); /* TO */
- testcase( i==107 ); /* IN */
- testcase( i==108 ); /* CAST */
- testcase( i==109 ); /* COLUMN */
- testcase( i==110 ); /* COMMIT */
- testcase( i==111 ); /* CONFLICT */
- testcase( i==112 ); /* CROSS */
- testcase( i==113 ); /* CURRENT_TIMESTAMP */
- testcase( i==114 ); /* CURRENT_TIME */
- testcase( i==115 ); /* CURRENT */
- testcase( i==116 ); /* PRECEDING */
- testcase( i==117 ); /* FAIL */
- testcase( i==118 ); /* LAST */
- testcase( i==119 ); /* FILTER */
- testcase( i==120 ); /* REPLACE */
- testcase( i==121 ); /* FIRST */
- testcase( i==122 ); /* FOLLOWING */
- testcase( i==123 ); /* FROM */
- testcase( i==124 ); /* FULL */
- testcase( i==125 ); /* LIMIT */
- testcase( i==126 ); /* IF */
- testcase( i==127 ); /* ORDER */
- testcase( i==128 ); /* RESTRICT */
- testcase( i==129 ); /* OTHERS */
- testcase( i==130 ); /* OVER */
- testcase( i==131 ); /* RETURNING */
- testcase( i==132 ); /* RIGHT */
- testcase( i==133 ); /* ROLLBACK */
- testcase( i==134 ); /* ROWS */
- testcase( i==135 ); /* ROW */
- testcase( i==136 ); /* UNBOUNDED */
- testcase( i==137 ); /* UNION */
- testcase( i==138 ); /* USING */
- testcase( i==139 ); /* VACUUM */
- testcase( i==140 ); /* VIEW */
- testcase( i==141 ); /* WINDOW */
- testcase( i==142 ); /* DO */
- testcase( i==143 ); /* BY */
- testcase( i==144 ); /* INITIALLY */
- testcase( i==145 ); /* ALL */
- testcase( i==146 ); /* PRIMARY */
- *pType = aKWCode[i];
- break;
- }
+ if( toupper(z[0])!=zKW[0] ) continue;
+ if( toupper(z[1])!=zKW[1] ) continue;
+ j = 2;
+ while( j<n && toupper(z[j])==zKW[j] ){ j++; }
+#endif
+ if( j<n ) continue;
+ testcase( i==1 ); /* REINDEX */
+ testcase( i==2 ); /* INDEXED */
+ testcase( i==3 ); /* INDEX */
+ testcase( i==4 ); /* DESC */
+ testcase( i==5 ); /* ESCAPE */
+ testcase( i==6 ); /* EACH */
+ testcase( i==7 ); /* CHECK */
+ testcase( i==8 ); /* KEY */
+ testcase( i==9 ); /* BEFORE */
+ testcase( i==10 ); /* FOREIGN */
+ testcase( i==11 ); /* FOR */
+ testcase( i==12 ); /* IGNORE */
+ testcase( i==13 ); /* REGEXP */
+ testcase( i==14 ); /* EXPLAIN */
+ testcase( i==15 ); /* INSTEAD */
+ testcase( i==16 ); /* ADD */
+ testcase( i==17 ); /* DATABASE */
+ testcase( i==18 ); /* AS */
+ testcase( i==19 ); /* SELECT */
+ testcase( i==20 ); /* TABLE */
+ testcase( i==21 ); /* LEFT */
+ testcase( i==22 ); /* THEN */
+ testcase( i==23 ); /* END */
+ testcase( i==24 ); /* DEFERRABLE */
+ testcase( i==25 ); /* ELSE */
+ testcase( i==26 ); /* EXCLUDE */
+ testcase( i==27 ); /* DELETE */
+ testcase( i==28 ); /* TEMPORARY */
+ testcase( i==29 ); /* TEMP */
+ testcase( i==30 ); /* OR */
+ testcase( i==31 ); /* ISNULL */
+ testcase( i==32 ); /* NULLS */
+ testcase( i==33 ); /* SAVEPOINT */
+ testcase( i==34 ); /* INTERSECT */
+ testcase( i==35 ); /* TIES */
+ testcase( i==36 ); /* NOTNULL */
+ testcase( i==37 ); /* NOT */
+ testcase( i==38 ); /* NO */
+ testcase( i==39 ); /* NULL */
+ testcase( i==40 ); /* LIKE */
+ testcase( i==41 ); /* EXCEPT */
+ testcase( i==42 ); /* TRANSACTION */
+ testcase( i==43 ); /* ACTION */
+ testcase( i==44 ); /* ON */
+ testcase( i==45 ); /* NATURAL */
+ testcase( i==46 ); /* ALTER */
+ testcase( i==47 ); /* RAISE */
+ testcase( i==48 ); /* EXCLUSIVE */
+ testcase( i==49 ); /* EXISTS */
+ testcase( i==50 ); /* CONSTRAINT */
+ testcase( i==51 ); /* INTO */
+ testcase( i==52 ); /* OFFSET */
+ testcase( i==53 ); /* OF */
+ testcase( i==54 ); /* SET */
+ testcase( i==55 ); /* TRIGGER */
+ testcase( i==56 ); /* RANGE */
+ testcase( i==57 ); /* GENERATED */
+ testcase( i==58 ); /* DETACH */
+ testcase( i==59 ); /* HAVING */
+ testcase( i==60 ); /* GLOB */
+ testcase( i==61 ); /* BEGIN */
+ testcase( i==62 ); /* INNER */
+ testcase( i==63 ); /* REFERENCES */
+ testcase( i==64 ); /* UNIQUE */
+ testcase( i==65 ); /* QUERY */
+ testcase( i==66 ); /* WITHOUT */
+ testcase( i==67 ); /* WITH */
+ testcase( i==68 ); /* OUTER */
+ testcase( i==69 ); /* RELEASE */
+ testcase( i==70 ); /* ATTACH */
+ testcase( i==71 ); /* BETWEEN */
+ testcase( i==72 ); /* NOTHING */
+ testcase( i==73 ); /* GROUPS */
+ testcase( i==74 ); /* GROUP */
+ testcase( i==75 ); /* CASCADE */
+ testcase( i==76 ); /* ASC */
+ testcase( i==77 ); /* DEFAULT */
+ testcase( i==78 ); /* CASE */
+ testcase( i==79 ); /* COLLATE */
+ testcase( i==80 ); /* CREATE */
+ testcase( i==81 ); /* CURRENT_DATE */
+ testcase( i==82 ); /* IMMEDIATE */
+ testcase( i==83 ); /* JOIN */
+ testcase( i==84 ); /* INSERT */
+ testcase( i==85 ); /* MATCH */
+ testcase( i==86 ); /* PLAN */
+ testcase( i==87 ); /* ANALYZE */
+ testcase( i==88 ); /* PRAGMA */
+ testcase( i==89 ); /* MATERIALIZED */
+ testcase( i==90 ); /* DEFERRED */
+ testcase( i==91 ); /* DISTINCT */
+ testcase( i==92 ); /* IS */
+ testcase( i==93 ); /* UPDATE */
+ testcase( i==94 ); /* VALUES */
+ testcase( i==95 ); /* VIRTUAL */
+ testcase( i==96 ); /* ALWAYS */
+ testcase( i==97 ); /* WHEN */
+ testcase( i==98 ); /* WHERE */
+ testcase( i==99 ); /* RECURSIVE */
+ testcase( i==100 ); /* ABORT */
+ testcase( i==101 ); /* AFTER */
+ testcase( i==102 ); /* RENAME */
+ testcase( i==103 ); /* AND */
+ testcase( i==104 ); /* DROP */
+ testcase( i==105 ); /* PARTITION */
+ testcase( i==106 ); /* AUTOINCREMENT */
+ testcase( i==107 ); /* TO */
+ testcase( i==108 ); /* IN */
+ testcase( i==109 ); /* CAST */
+ testcase( i==110 ); /* COLUMN */
+ testcase( i==111 ); /* COMMIT */
+ testcase( i==112 ); /* CONFLICT */
+ testcase( i==113 ); /* CROSS */
+ testcase( i==114 ); /* CURRENT_TIMESTAMP */
+ testcase( i==115 ); /* CURRENT_TIME */
+ testcase( i==116 ); /* CURRENT */
+ testcase( i==117 ); /* PRECEDING */
+ testcase( i==118 ); /* FAIL */
+ testcase( i==119 ); /* LAST */
+ testcase( i==120 ); /* FILTER */
+ testcase( i==121 ); /* REPLACE */
+ testcase( i==122 ); /* FIRST */
+ testcase( i==123 ); /* FOLLOWING */
+ testcase( i==124 ); /* FROM */
+ testcase( i==125 ); /* FULL */
+ testcase( i==126 ); /* LIMIT */
+ testcase( i==127 ); /* IF */
+ testcase( i==128 ); /* ORDER */
+ testcase( i==129 ); /* RESTRICT */
+ testcase( i==130 ); /* OTHERS */
+ testcase( i==131 ); /* OVER */
+ testcase( i==132 ); /* RETURNING */
+ testcase( i==133 ); /* RIGHT */
+ testcase( i==134 ); /* ROLLBACK */
+ testcase( i==135 ); /* ROWS */
+ testcase( i==136 ); /* ROW */
+ testcase( i==137 ); /* UNBOUNDED */
+ testcase( i==138 ); /* UNION */
+ testcase( i==139 ); /* USING */
+ testcase( i==140 ); /* VACUUM */
+ testcase( i==141 ); /* VIEW */
+ testcase( i==142 ); /* WINDOW */
+ testcase( i==143 ); /* DO */
+ testcase( i==144 ); /* BY */
+ testcase( i==145 ); /* INITIALLY */
+ testcase( i==146 ); /* ALL */
+ testcase( i==147 ); /* PRIMARY */
+ *pType = aKWCode[i];
+ break;
}
return n;
}
SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char *z, int n){
int id = TK_ID;
- keywordCode((char*)z, n, &id);
+ if( n>=2 ) keywordCode((char*)z, n, &id);
return id;
}
#define SQLITE_N_KEYWORD 147
SQLITE_API int sqlite3_keyword_name(int i,const char **pzName,int *pnName){
if( i<0 || i>=SQLITE_N_KEYWORD ) return SQLITE_ERROR;
+ i++;
*pzName = zKWText + aKWOffset[i];
*pnName = aKWLen[i];
return SQLITE_OK;
@@ -173145,7 +177509,7 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
testcase( z[0]=='0' ); testcase( z[0]=='1' ); testcase( z[0]=='2' );
testcase( z[0]=='3' ); testcase( z[0]=='4' ); testcase( z[0]=='5' );
testcase( z[0]=='6' ); testcase( z[0]=='7' ); testcase( z[0]=='8' );
- testcase( z[0]=='9' );
+ testcase( z[0]=='9' ); testcase( z[0]=='.' );
*tokenType = TK_INTEGER;
#ifndef SQLITE_OMIT_HEX_INTEGER
if( z[0]=='0' && (z[1]=='x' || z[1]=='X') && sqlite3Isxdigit(z[2]) ){
@@ -173217,7 +177581,8 @@ SQLITE_PRIVATE int sqlite3GetToken(const unsigned char *z, int *tokenType){
return i;
}
case CC_KYWD0: {
- for(i=1; aiClass[z[i]]<=CC_KYWD; i++){}
+ if( aiClass[z[1]]>CC_KYWD ){ i = 1; break; }
+ for(i=2; aiClass[z[i]]<=CC_KYWD; i++){}
if( IdChar(z[i]) ){
/* This token started out using characters that can appear in keywords,
** but z[i] is a character not allowed within keywords, so this must
@@ -173996,30 +178361,20 @@ static int sqlite3TestExtInit(sqlite3 *db){
** Forward declarations of external module initializer functions
** for modules that need them.
*/
-#ifdef SQLITE_ENABLE_FTS1
-SQLITE_PRIVATE int sqlite3Fts1Init(sqlite3*);
-#endif
-#ifdef SQLITE_ENABLE_FTS2
-SQLITE_PRIVATE int sqlite3Fts2Init(sqlite3*);
-#endif
#ifdef SQLITE_ENABLE_FTS5
SQLITE_PRIVATE int sqlite3Fts5Init(sqlite3*);
#endif
#ifdef SQLITE_ENABLE_STMTVTAB
SQLITE_PRIVATE int sqlite3StmtVtabInit(sqlite3*);
#endif
-
+#ifdef SQLITE_EXTRA_AUTOEXT
+int SQLITE_EXTRA_AUTOEXT(sqlite3*);
+#endif
/*
** An array of pointers to extension initializer functions for
** built-in extensions.
*/
static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = {
-#ifdef SQLITE_ENABLE_FTS1
- sqlite3Fts1Init,
-#endif
-#ifdef SQLITE_ENABLE_FTS2
- sqlite3Fts2Init,
-#endif
#ifdef SQLITE_ENABLE_FTS3
sqlite3Fts3Init,
#endif
@@ -174048,6 +178403,9 @@ static int (*const sqlite3BuiltinExtensions[])(sqlite3*) = {
#ifdef SQLITE_ENABLE_BYTECODE_VTAB
sqlite3VdbeBytecodeVtabInit,
#endif
+#ifdef SQLITE_EXTRA_AUTOEXT
+ SQLITE_EXTRA_AUTOEXT,
+#endif
};
#ifndef SQLITE_AMALGAMATION
@@ -174122,6 +178480,32 @@ SQLITE_API char *sqlite3_temp_directory = 0;
SQLITE_API char *sqlite3_data_directory = 0;
/*
+** Determine whether or not high-precision (long double) floating point
+** math works correctly on CPU currently running.
+*/
+static SQLITE_NOINLINE int hasHighPrecisionDouble(int rc){
+ if( sizeof(LONGDOUBLE_TYPE)<=8 ){
+ /* If the size of "long double" is not more than 8, then
+ ** high-precision math is not possible. */
+ return 0;
+ }else{
+ /* Just because sizeof(long double)>8 does not mean that the underlying
+ ** hardware actually supports high-precision floating point. For example,
+ ** clearing the 0x100 bit in the floating-point control word on Intel
+ ** processors will make long double work like double, even though long
+ ** double takes up more space. The only way to determine if long double
+ ** actually works is to run an experiment. */
+ LONGDOUBLE_TYPE a, b, c;
+ rc++;
+ a = 1.0+rc*0.1;
+ b = 1.0e+18+rc*25.0;
+ c = a+b;
+ return b!=c;
+ }
+}
+
+
+/*
** Initialize SQLite.
**
** This routine must be called to initialize the memory allocation,
@@ -174316,6 +178700,12 @@ SQLITE_API int sqlite3_initialize(void){
}
#endif
+ /* Experimentally determine if high-precision floating point is
+ ** available. */
+#ifndef SQLITE_OMIT_WSD
+ sqlite3Config.bUseLongDouble = hasHighPrecisionDouble(rc);
+#endif
+
return rc;
}
@@ -174385,9 +178775,21 @@ SQLITE_API int sqlite3_config(int op, ...){
va_list ap;
int rc = SQLITE_OK;
- /* sqlite3_config() shall return SQLITE_MISUSE if it is invoked while
- ** the SQLite library is in use. */
- if( sqlite3GlobalConfig.isInit ) return SQLITE_MISUSE_BKPT;
+ /* sqlite3_config() normally returns SQLITE_MISUSE if it is invoked while
+ ** the SQLite library is in use. Except, a few selected opcodes
+ ** are allowed.
+ */
+ if( sqlite3GlobalConfig.isInit ){
+ static const u64 mAnytimeConfigOption = 0
+ | MASKBIT64( SQLITE_CONFIG_LOG )
+ | MASKBIT64( SQLITE_CONFIG_PCACHE_HDRSZ )
+ ;
+ if( op<0 || op>63 || (MASKBIT64(op) & mAnytimeConfigOption)==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+ testcase( op==SQLITE_CONFIG_LOG );
+ testcase( op==SQLITE_CONFIG_PCACHE_HDRSZ );
+ }
va_start(ap, op);
switch( op ){
@@ -174456,6 +178858,7 @@ SQLITE_API int sqlite3_config(int op, ...){
break;
}
case SQLITE_CONFIG_MEMSTATUS: {
+ assert( !sqlite3GlobalConfig.isInit ); /* Cannot change at runtime */
/* EVIDENCE-OF: R-61275-35157 The SQLITE_CONFIG_MEMSTATUS option takes
** single argument of type int, interpreted as a boolean, which enables
** or disables the collection of memory allocation statistics. */
@@ -174579,8 +178982,10 @@ SQLITE_API int sqlite3_config(int op, ...){
** sqlite3GlobalConfig.xLog = va_arg(ap, void(*)(void*,int,const char*));
*/
typedef void(*LOGFUNC_t)(void*,int,const char*);
- sqlite3GlobalConfig.xLog = va_arg(ap, LOGFUNC_t);
- sqlite3GlobalConfig.pLogArg = va_arg(ap, void*);
+ LOGFUNC_t xLog = va_arg(ap, LOGFUNC_t);
+ void *pLogArg = va_arg(ap, void*);
+ AtomicStore(&sqlite3GlobalConfig.xLog, xLog);
+ AtomicStore(&sqlite3GlobalConfig.pLogArg, pLogArg);
break;
}
@@ -174594,7 +178999,8 @@ SQLITE_API int sqlite3_config(int op, ...){
** argument of type int. If non-zero, then URI handling is globally
** enabled. If the parameter is zero, then URI handling is globally
** disabled. */
- sqlite3GlobalConfig.bOpenUri = va_arg(ap, int);
+ int bOpenUri = va_arg(ap, int);
+ AtomicStore(&sqlite3GlobalConfig.bOpenUri, bOpenUri);
break;
}
@@ -174679,6 +179085,18 @@ SQLITE_API int sqlite3_config(int op, ...){
}
#endif /* SQLITE_OMIT_DESERIALIZE */
+ case SQLITE_CONFIG_ROWID_IN_VIEW: {
+ int *pVal = va_arg(ap,int*);
+#ifdef SQLITE_ALLOW_ROWID_IN_VIEW
+ if( 0==*pVal ) sqlite3GlobalConfig.mNoVisibleRowid = TF_NoVisibleRowid;
+ if( 1==*pVal ) sqlite3GlobalConfig.mNoVisibleRowid = 0;
+ *pVal = (sqlite3GlobalConfig.mNoVisibleRowid==0);
+#else
+ *pVal = 0;
+#endif
+ break;
+ }
+
default: {
rc = SQLITE_ERROR;
break;
@@ -174870,6 +179288,10 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3 *db){
SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
va_list ap;
int rc;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
va_start(ap, op);
switch( op ){
@@ -174909,6 +179331,8 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
{ SQLITE_DBCONFIG_DQS_DML, SQLITE_DqsDML },
{ SQLITE_DBCONFIG_LEGACY_FILE_FORMAT, SQLITE_LegacyFileFmt },
{ SQLITE_DBCONFIG_TRUSTED_SCHEMA, SQLITE_TrustedSchema },
+ { SQLITE_DBCONFIG_STMT_SCANSTATUS, SQLITE_StmtScanStatus },
+ { SQLITE_DBCONFIG_REVERSE_SCANORDER, SQLITE_ReverseOrder },
};
unsigned int i;
rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
@@ -175197,6 +179621,14 @@ static int sqlite3Close(sqlite3 *db, int forceZombie){
}
#endif
+ while( db->pDbData ){
+ DbClientData *p = db->pDbData;
+ db->pDbData = p->pNext;
+ assert( p->pData!=0 );
+ if( p->xDestructor ) p->xDestructor(p->pData);
+ sqlite3_free(p);
+ }
+
/* Convert the connection into a zombie and then close it.
*/
db->eOpenState = SQLITE_STATE_ZOMBIE;
@@ -175614,9 +180046,9 @@ static int sqliteDefaultBusyCallback(
void *ptr, /* Database connection */
int count /* Number of times table has been busy */
){
-#if SQLITE_OS_WIN || HAVE_USLEEP
+#if SQLITE_OS_WIN || !defined(HAVE_NANOSLEEP) || HAVE_NANOSLEEP
/* This case is for systems that have support for sleeping for fractions of
- ** a second. Examples: All windows systems, unix systems with usleep() */
+ ** a second. Examples: All windows systems, unix systems with nanosleep() */
static const u8 delays[] =
{ 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 };
static const u8 totals[] =
@@ -175814,7 +180246,7 @@ SQLITE_PRIVATE int sqlite3CreateFunc(
assert( SQLITE_FUNC_CONSTANT==SQLITE_DETERMINISTIC );
assert( SQLITE_FUNC_DIRECT==SQLITE_DIRECTONLY );
extraFlags = enc & (SQLITE_DETERMINISTIC|SQLITE_DIRECTONLY|
- SQLITE_SUBTYPE|SQLITE_INNOCUOUS);
+ SQLITE_SUBTYPE|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE);
enc &= (SQLITE_FUNC_ENCMASK|SQLITE_ANY);
/* The SQLITE_INNOCUOUS flag is the same bit as SQLITE_FUNC_UNSAFE. But
@@ -176271,6 +180703,12 @@ SQLITE_API void *sqlite3_preupdate_hook(
void *pArg /* First callback argument */
){
void *pRet;
+
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( db==0 ){
+ return 0;
+ }
+#endif
sqlite3_mutex_enter(db->mutex);
pRet = db->pPreUpdateArg;
db->xPreUpdateCallback = xCallback;
@@ -176417,7 +180855,7 @@ SQLITE_API int sqlite3_wal_checkpoint_v2(
if( eMode<SQLITE_CHECKPOINT_PASSIVE || eMode>SQLITE_CHECKPOINT_TRUNCATE ){
/* EVIDENCE-OF: R-03996-12088 The M parameter must be a valid checkpoint
** mode: */
- return SQLITE_MISUSE;
+ return SQLITE_MISUSE_BKPT;
}
sqlite3_mutex_enter(db->mutex);
@@ -176894,9 +181332,9 @@ SQLITE_PRIVATE int sqlite3ParseUri(
assert( *pzErrMsg==0 );
- if( ((flags & SQLITE_OPEN_URI) /* IMP: R-48725-32206 */
- || sqlite3GlobalConfig.bOpenUri) /* IMP: R-51689-46548 */
- && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */
+ if( ((flags & SQLITE_OPEN_URI) /* IMP: R-48725-32206 */
+ || AtomicLoad(&sqlite3GlobalConfig.bOpenUri)) /* IMP: R-51689-46548 */
+ && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */
){
char *zOpt;
int eState; /* Parser state when parsing URI */
@@ -177254,7 +181692,7 @@ static int openDatabase(
** 0 off off
**
** Legacy behavior is 3 (double-quoted string literals are allowed anywhere)
-** and so that is the default. But developers are encouranged to use
+** and so that is the default. But developers are encouraged to use
** -DSQLITE_DQS=0 (best) or -DSQLITE_DQS=1 (second choice) if possible.
*/
#if !defined(SQLITE_DQS)
@@ -177303,6 +181741,9 @@ static int openDatabase(
#if defined(SQLITE_DEFAULT_LEGACY_ALTER_TABLE)
| SQLITE_LegacyAlter
#endif
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+ | SQLITE_StmtScanStatus
+#endif
;
sqlite3HashInit(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -177651,6 +182092,69 @@ SQLITE_API int sqlite3_collation_needed16(
}
#endif /* SQLITE_OMIT_UTF16 */
+/*
+** Find existing client data.
+*/
+SQLITE_API void *sqlite3_get_clientdata(sqlite3 *db, const char *zName){
+ DbClientData *p;
+ sqlite3_mutex_enter(db->mutex);
+ for(p=db->pDbData; p; p=p->pNext){
+ if( strcmp(p->zName, zName)==0 ){
+ void *pResult = p->pData;
+ sqlite3_mutex_leave(db->mutex);
+ return pResult;
+ }
+ }
+ sqlite3_mutex_leave(db->mutex);
+ return 0;
+}
+
+/*
+** Add new client data to a database connection.
+*/
+SQLITE_API int sqlite3_set_clientdata(
+ sqlite3 *db, /* Attach client data to this connection */
+ const char *zName, /* Name of the client data */
+ void *pData, /* The client data itself */
+ void (*xDestructor)(void*) /* Destructor */
+){
+ DbClientData *p, **pp;
+ sqlite3_mutex_enter(db->mutex);
+ pp = &db->pDbData;
+ for(p=db->pDbData; p && strcmp(p->zName,zName); p=p->pNext){
+ pp = &p->pNext;
+ }
+ if( p ){
+ assert( p->pData!=0 );
+ if( p->xDestructor ) p->xDestructor(p->pData);
+ if( pData==0 ){
+ *pp = p->pNext;
+ sqlite3_free(p);
+ sqlite3_mutex_leave(db->mutex);
+ return SQLITE_OK;
+ }
+ }else if( pData==0 ){
+ sqlite3_mutex_leave(db->mutex);
+ return SQLITE_OK;
+ }else{
+ size_t n = strlen(zName);
+ p = sqlite3_malloc64( sizeof(DbClientData)+n+1 );
+ if( p==0 ){
+ if( xDestructor ) xDestructor(pData);
+ sqlite3_mutex_leave(db->mutex);
+ return SQLITE_NOMEM;
+ }
+ memcpy(p->zName, zName, n+1);
+ p->pNext = db->pDbData;
+ db->pDbData = p;
+ }
+ p->pData = pData;
+ p->xDestructor = xDestructor;
+ sqlite3_mutex_leave(db->mutex);
+ return SQLITE_OK;
+}
+
+
#ifndef SQLITE_OMIT_DEPRECATED
/*
** This function is now an anachronism. It used to be used to recover from a
@@ -177786,7 +182290,7 @@ SQLITE_API int sqlite3_table_column_metadata(
/* Find the column for which info is requested */
if( zColumnName==0 ){
- /* Query for existance of table only */
+ /* Query for existence of table only */
}else{
for(iCol=0; iCol<pTab->nCol; iCol++){
pCol = &pTab->aCol[iCol];
@@ -177867,7 +182371,7 @@ SQLITE_API int sqlite3_sleep(int ms){
/* This function works in milliseconds, but the underlying OsSleep()
** API uses microseconds. Hence the 1000's.
*/
- rc = (sqlite3OsSleep(pVfs, 1000*ms)/1000);
+ rc = (sqlite3OsSleep(pVfs, ms<0 ? 0 : 1000*ms)/1000);
return rc;
}
@@ -178000,6 +182504,28 @@ SQLITE_API int sqlite3_test_control(int op, ...){
}
#endif
+ /* sqlite3_test_control(SQLITE_TESTCTRL_FK_NO_ACTION, sqlite3 *db, int b);
+ **
+ ** If b is true, then activate the SQLITE_FkNoAction setting. If b is
+ ** false then clearn that setting. If the SQLITE_FkNoAction setting is
+ ** abled, all foreign key ON DELETE and ON UPDATE actions behave as if
+ ** they were NO ACTION, regardless of how they are defined.
+ **
+ ** NB: One must usually run "PRAGMA writable_schema=RESET" after
+ ** using this test-control, before it will take full effect. failing
+ ** to reset the schema can result in some unexpected behavior.
+ */
+ case SQLITE_TESTCTRL_FK_NO_ACTION: {
+ sqlite3 *db = va_arg(ap, sqlite3*);
+ int b = va_arg(ap, int);
+ if( b ){
+ db->flags |= SQLITE_FkNoAction;
+ }else{
+ db->flags &= ~SQLITE_FkNoAction;
+ }
+ break;
+ }
+
/*
** sqlite3_test_control(BITVEC_TEST, size, program)
**
@@ -178106,10 +182632,12 @@ SQLITE_API int sqlite3_test_control(int op, ...){
sqlite3ShowSrcList(0);
sqlite3ShowWith(0);
sqlite3ShowUpsert(0);
+#ifndef SQLITE_OMIT_TRIGGER
sqlite3ShowTriggerStep(0);
sqlite3ShowTriggerStepList(0);
sqlite3ShowTrigger(0);
sqlite3ShowTriggerList(0);
+#endif
#ifndef SQLITE_OMIT_WINDOWFUNC
sqlite3ShowWindow(0);
sqlite3ShowWinFunc(0);
@@ -178226,7 +182754,7 @@ SQLITE_API int sqlite3_test_control(int op, ...){
** formed and never corrupt. This flag is clear by default, indicating that
** database files might have arbitrary corruption. Setting the flag during
** testing causes certain assert() statements in the code to be activated
- ** that demonstrat invariants on well-formed database files.
+ ** that demonstrate invariants on well-formed database files.
*/
case SQLITE_TESTCTRL_NEVER_CORRUPT: {
sqlite3GlobalConfig.neverCorrupt = va_arg(ap, int);
@@ -178380,7 +182908,7 @@ SQLITE_API int sqlite3_test_control(int op, ...){
**
** op==0 Store the current sqlite3TreeTrace in *ptr
** op==1 Set sqlite3TreeTrace to the value *ptr
- ** op==3 Store the current sqlite3WhereTrace in *ptr
+ ** op==2 Store the current sqlite3WhereTrace in *ptr
** op==3 Set sqlite3WhereTrace to the value *ptr
*/
case SQLITE_TESTCTRL_TRACEFLAGS: {
@@ -178416,6 +182944,23 @@ SQLITE_API int sqlite3_test_control(int op, ...){
break;
}
+#if !defined(SQLITE_OMIT_WSD)
+ /* sqlite3_test_control(SQLITE_TESTCTRL_USELONGDOUBLE, int X);
+ **
+ ** X<0 Make no changes to the bUseLongDouble. Just report value.
+ ** X==0 Disable bUseLongDouble
+ ** X==1 Enable bUseLongDouble
+ ** X>=2 Set bUseLongDouble to its default value for this platform
+ */
+ case SQLITE_TESTCTRL_USELONGDOUBLE: {
+ int b = va_arg(ap, int);
+ if( b>=2 ) b = hasHighPrecisionDouble(b);
+ if( b>=0 ) sqlite3Config.bUseLongDouble = b>0;
+ rc = sqlite3Config.bUseLongDouble!=0;
+ break;
+ }
+#endif
+
#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD)
/* sqlite3_test_control(SQLITE_TESTCTRL_TUNE, id, *piValue)
@@ -178446,6 +182991,28 @@ SQLITE_API int sqlite3_test_control(int op, ...){
break;
}
#endif
+
+ /* sqlite3_test_control(SQLITE_TESTCTRL_JSON_SELFCHECK, &onOff);
+ **
+ ** Activate or deactivate validation of JSONB that is generated from
+ ** text. Off by default, as the validation is slow. Validation is
+ ** only available if compiled using SQLITE_DEBUG.
+ **
+ ** If onOff is initially 1, then turn it on. If onOff is initially
+ ** off, turn it off. If onOff is initially -1, then change onOff
+ ** to be the current setting.
+ */
+ case SQLITE_TESTCTRL_JSON_SELFCHECK: {
+#if defined(SQLITE_DEBUG) && !defined(SQLITE_OMIT_WSD)
+ int *pOnOff = va_arg(ap, int*);
+ if( *pOnOff<0 ){
+ *pOnOff = sqlite3Config.bJsonSelfcheck;
+ }else{
+ sqlite3Config.bJsonSelfcheck = (u8)((*pOnOff)&0xff);
+ }
+#endif
+ break;
+ }
}
va_end(ap);
#endif /* SQLITE_UNTESTABLE */
@@ -178716,7 +183283,7 @@ SQLITE_API int sqlite3_snapshot_get(
}
/*
-** Open a read-transaction on the snapshot idendified by pSnapshot.
+** Open a read-transaction on the snapshot identified by pSnapshot.
*/
SQLITE_API int sqlite3_snapshot_open(
sqlite3 *db,
@@ -178823,7 +183390,7 @@ SQLITE_API int sqlite3_compileoption_used(const char *zOptName){
int nOpt;
const char **azCompileOpt;
-#if SQLITE_ENABLE_API_ARMOR
+#ifdef SQLITE_ENABLE_API_ARMOR
if( zOptName==0 ){
(void)SQLITE_MISUSE_BKPT;
return 0;
@@ -179018,6 +183585,9 @@ SQLITE_API int sqlite3_unlock_notify(
){
int rc = SQLITE_OK;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
sqlite3_mutex_enter(db->mutex);
enterMutex();
@@ -180039,6 +184609,7 @@ struct Fts3Table {
int nPgsz; /* Page size for host database */
char *zSegmentsTbl; /* Name of %_segments table */
sqlite3_blob *pSegments; /* Blob handle open on %_segments table */
+ int iSavepoint;
/*
** The following array of hash tables is used to buffer pending index
@@ -180426,6 +184997,8 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeIsdiacritic(int);
SQLITE_PRIVATE int sqlite3Fts3ExprIterate(Fts3Expr*, int (*x)(Fts3Expr*,int,void*), void*);
+SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk);
+
#endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */
#endif /* _FTSINT_H */
@@ -180782,6 +185355,7 @@ static void fts3DeclareVtab(int *pRc, Fts3Table *p){
zLanguageid = (p->zLanguageid ? p->zLanguageid : "__langid");
sqlite3_vtab_config(p->db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
+ sqlite3_vtab_config(p->db, SQLITE_VTAB_INNOCUOUS);
/* Create a list of user columns for the virtual table */
zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]);
@@ -184031,6 +188605,8 @@ static int fts3RenameMethod(
rc = sqlite3Fts3PendingTermsFlush(p);
}
+ p->bIgnoreSavepoint = 1;
+
if( p->zContentTbl==0 ){
fts3DbExec(&rc, db,
"ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';",
@@ -184058,6 +188634,8 @@ static int fts3RenameMethod(
"ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';",
p->zDb, p->zName, zName
);
+
+ p->bIgnoreSavepoint = 0;
return rc;
}
@@ -184068,12 +188646,28 @@ static int fts3RenameMethod(
*/
static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
int rc = SQLITE_OK;
- UNUSED_PARAMETER(iSavepoint);
- assert( ((Fts3Table *)pVtab)->inTransaction );
- assert( ((Fts3Table *)pVtab)->mxSavepoint <= iSavepoint );
- TESTONLY( ((Fts3Table *)pVtab)->mxSavepoint = iSavepoint );
- if( ((Fts3Table *)pVtab)->bIgnoreSavepoint==0 ){
- rc = fts3SyncMethod(pVtab);
+ Fts3Table *pTab = (Fts3Table*)pVtab;
+ assert( pTab->inTransaction );
+ assert( pTab->mxSavepoint<=iSavepoint );
+ TESTONLY( pTab->mxSavepoint = iSavepoint );
+
+ if( pTab->bIgnoreSavepoint==0 ){
+ if( fts3HashCount(&pTab->aIndex[0].hPending)>0 ){
+ char *zSql = sqlite3_mprintf("INSERT INTO %Q.%Q(%Q) VALUES('flush')",
+ pTab->zDb, pTab->zName, pTab->zName
+ );
+ if( zSql ){
+ pTab->bIgnoreSavepoint = 1;
+ rc = sqlite3_exec(pTab->db, zSql, 0, 0, 0);
+ pTab->bIgnoreSavepoint = 0;
+ sqlite3_free(zSql);
+ }else{
+ rc = SQLITE_NOMEM;
+ }
+ }
+ if( rc==SQLITE_OK ){
+ pTab->iSavepoint = iSavepoint+1;
+ }
}
return rc;
}
@@ -184084,12 +188678,11 @@ static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
** This is a no-op.
*/
static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
- TESTONLY( Fts3Table *p = (Fts3Table*)pVtab );
- UNUSED_PARAMETER(iSavepoint);
- UNUSED_PARAMETER(pVtab);
- assert( p->inTransaction );
- assert( p->mxSavepoint >= iSavepoint );
- TESTONLY( p->mxSavepoint = iSavepoint-1 );
+ Fts3Table *pTab = (Fts3Table*)pVtab;
+ assert( pTab->inTransaction );
+ assert( pTab->mxSavepoint >= iSavepoint );
+ TESTONLY( pTab->mxSavepoint = iSavepoint-1 );
+ pTab->iSavepoint = iSavepoint;
return SQLITE_OK;
}
@@ -184099,11 +188692,13 @@ static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
** Discard the contents of the pending terms table.
*/
static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
- Fts3Table *p = (Fts3Table*)pVtab;
+ Fts3Table *pTab = (Fts3Table*)pVtab;
UNUSED_PARAMETER(iSavepoint);
- assert( p->inTransaction );
- TESTONLY( p->mxSavepoint = iSavepoint );
- sqlite3Fts3PendingTermsClear(p);
+ assert( pTab->inTransaction );
+ TESTONLY( pTab->mxSavepoint = iSavepoint );
+ if( (iSavepoint+1)<=pTab->iSavepoint ){
+ sqlite3Fts3PendingTermsClear(pTab);
+ }
return SQLITE_OK;
}
@@ -184122,8 +188717,40 @@ static int fts3ShadowName(const char *zName){
return 0;
}
+/*
+** Implementation of the xIntegrity() method on the FTS3/FTS4 virtual
+** table.
+*/
+static int fts3IntegrityMethod(
+ sqlite3_vtab *pVtab, /* The virtual table to be checked */
+ const char *zSchema, /* Name of schema in which pVtab lives */
+ const char *zTabname, /* Name of the pVTab table */
+ int isQuick, /* True if this is a quick_check */
+ char **pzErr /* Write error message here */
+){
+ Fts3Table *p = (Fts3Table*)pVtab;
+ int rc;
+ int bOk = 0;
+
+ UNUSED_PARAMETER(isQuick);
+ rc = sqlite3Fts3IntegrityCheck(p, &bOk);
+ assert( rc!=SQLITE_CORRUPT_VTAB || bOk==0 );
+ if( rc!=SQLITE_OK && rc!=SQLITE_CORRUPT_VTAB ){
+ *pzErr = sqlite3_mprintf("unable to validate the inverted index for"
+ " FTS%d table %s.%s: %s",
+ p->bFts4 ? 4 : 3, zSchema, zTabname, sqlite3_errstr(rc));
+ }else if( bOk==0 ){
+ *pzErr = sqlite3_mprintf("malformed inverted index for FTS%d table %s.%s",
+ p->bFts4 ? 4 : 3, zSchema, zTabname);
+ }
+ sqlite3Fts3SegmentsClose(p);
+ return SQLITE_OK;
+}
+
+
+
static const sqlite3_module fts3Module = {
- /* iVersion */ 3,
+ /* iVersion */ 4,
/* xCreate */ fts3CreateMethod,
/* xConnect */ fts3ConnectMethod,
/* xBestIndex */ fts3BestIndexMethod,
@@ -184147,6 +188774,7 @@ static const sqlite3_module fts3Module = {
/* xRelease */ fts3ReleaseMethod,
/* xRollbackTo */ fts3RollbackToMethod,
/* xShadowName */ fts3ShadowName,
+ /* xIntegrity */ fts3IntegrityMethod,
};
/*
@@ -186822,7 +191450,8 @@ SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db){
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
int rc; /* Return code */
@@ -190388,7 +195017,8 @@ SQLITE_PRIVATE int sqlite3Fts3InitTok(sqlite3 *db, Fts3Hash *pHash, void(*xDestr
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
int rc; /* Return code */
@@ -193071,16 +197701,18 @@ static int fts3MsrBufferData(
char *pList,
i64 nList
){
- if( nList>pMsr->nBuffer ){
+ if( (nList+FTS3_NODE_PADDING)>pMsr->nBuffer ){
char *pNew;
- pMsr->nBuffer = nList*2;
- pNew = (char *)sqlite3_realloc64(pMsr->aBuffer, pMsr->nBuffer);
+ int nNew = nList*2 + FTS3_NODE_PADDING;
+ pNew = (char *)sqlite3_realloc64(pMsr->aBuffer, nNew);
if( !pNew ) return SQLITE_NOMEM;
pMsr->aBuffer = pNew;
+ pMsr->nBuffer = nNew;
}
assert( nList>0 );
memcpy(pMsr->aBuffer, pList, nList);
+ memset(&pMsr->aBuffer[nList], 0, FTS3_NODE_PADDING);
return SQLITE_OK;
}
@@ -193727,7 +198359,6 @@ SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){
rc = fts3SegmentMerge(p, p->iPrevLangid, i, FTS3_SEGCURSOR_PENDING);
if( rc==SQLITE_DONE ) rc = SQLITE_OK;
}
- sqlite3Fts3PendingTermsClear(p);
/* Determine the auto-incr-merge setting if unknown. If enabled,
** estimate the number of leaf blocks of content to be written
@@ -193749,6 +198380,10 @@ SQLITE_PRIVATE int sqlite3Fts3PendingTermsFlush(Fts3Table *p){
rc = sqlite3_reset(pStmt);
}
}
+
+ if( rc==SQLITE_OK ){
+ sqlite3Fts3PendingTermsClear(p);
+ }
return rc;
}
@@ -194380,6 +199015,8 @@ static int fts3AppendToNode(
blobGrowBuffer(pPrev, nTerm, &rc);
if( rc!=SQLITE_OK ) return rc;
+ assert( pPrev!=0 );
+ assert( pPrev->a!=0 );
nPrefix = fts3PrefixCompress(pPrev->a, pPrev->n, zTerm, nTerm);
nSuffix = nTerm - nPrefix;
@@ -194436,9 +199073,13 @@ static int fts3IncrmergeAppend(
nSpace += sqlite3Fts3VarintLen(nDoclist) + nDoclist;
/* If the current block is not empty, and if adding this term/doclist
- ** to the current block would make it larger than Fts3Table.nNodeSize
- ** bytes, write this block out to the database. */
- if( pLeaf->block.n>0 && (pLeaf->block.n + nSpace)>p->nNodeSize ){
+ ** to the current block would make it larger than Fts3Table.nNodeSize bytes,
+ ** and if there is still room for another leaf page, write this block out to
+ ** the database. */
+ if( pLeaf->block.n>0
+ && (pLeaf->block.n + nSpace)>p->nNodeSize
+ && pLeaf->iBlock < (pWriter->iStart + pWriter->nLeafEst)
+ ){
rc = fts3WriteSegment(p, pLeaf->iBlock, pLeaf->block.a, pLeaf->block.n);
pWriter->nWork++;
@@ -194749,6 +199390,7 @@ static int fts3IncrmergeLoad(
for(i=nHeight; i>=0 && rc==SQLITE_OK; i--){
NodeReader reader;
+ memset(&reader, 0, sizeof(reader));
pNode = &pWriter->aNodeWriter[i];
if( pNode->block.a){
@@ -194769,7 +199411,7 @@ static int fts3IncrmergeLoad(
rc = sqlite3Fts3ReadBlock(p, reader.iChild, &aBlock, &nBlock,0);
blobGrowBuffer(&pNode->block,
MAX(nBlock, p->nNodeSize)+FTS3_NODE_PADDING, &rc
- );
+ );
if( rc==SQLITE_OK ){
memcpy(pNode->block.a, aBlock, nBlock);
pNode->block.n = nBlock;
@@ -195619,7 +200261,7 @@ static u64 fts3ChecksumIndex(
int rc;
u64 cksum = 0;
- assert( *pRc==SQLITE_OK );
+ if( *pRc ) return 0;
memset(&filter, 0, sizeof(filter));
memset(&csr, 0, sizeof(csr));
@@ -195686,7 +200328,7 @@ static u64 fts3ChecksumIndex(
** If an error occurs (e.g. an OOM or IO error), return an SQLite error
** code. The final value of *pbOk is undefined in this case.
*/
-static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
+SQLITE_PRIVATE int sqlite3Fts3IntegrityCheck(Fts3Table *p, int *pbOk){
int rc = SQLITE_OK; /* Return code */
u64 cksum1 = 0; /* Checksum based on FTS index contents */
u64 cksum2 = 0; /* Checksum based on %_content contents */
@@ -195764,7 +200406,7 @@ static int fts3IntegrityCheck(Fts3Table *p, int *pbOk){
sqlite3_finalize(pStmt);
}
- *pbOk = (cksum1==cksum2);
+ *pbOk = (rc==SQLITE_OK && cksum1==cksum2);
return rc;
}
@@ -195804,7 +200446,7 @@ static int fts3DoIntegrityCheck(
){
int rc;
int bOk = 0;
- rc = fts3IntegrityCheck(p, &bOk);
+ rc = sqlite3Fts3IntegrityCheck(p, &bOk);
if( rc==SQLITE_OK && bOk==0 ) rc = FTS_CORRUPT_VTAB;
return rc;
}
@@ -195834,8 +200476,11 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
rc = fts3DoIncrmerge(p, &zVal[6]);
}else if( nVal>10 && 0==sqlite3_strnicmp(zVal, "automerge=", 10) ){
rc = fts3DoAutoincrmerge(p, &zVal[10]);
+ }else if( nVal==5 && 0==sqlite3_strnicmp(zVal, "flush", 5) ){
+ rc = sqlite3Fts3PendingTermsFlush(p);
+ }
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
- }else{
+ else{
int v;
if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
v = atoi(&zVal[9]);
@@ -195853,8 +200498,8 @@ static int fts3SpecialInsert(Fts3Table *p, sqlite3_value *pVal){
if( v>=4 && v<=FTS3_MERGE_COUNT && (v&1)==0 ) p->nMergeCount = v;
rc = SQLITE_OK;
}
-#endif
}
+#endif
return rc;
}
@@ -198775,59 +203420,242 @@ SQLITE_PRIVATE int sqlite3FtsUnicodeFold(int c, int eRemoveDiacritic){
**
******************************************************************************
**
-** This SQLite JSON functions.
+** SQLite JSON functions.
**
** This file began as an extension in ext/misc/json1.c in 2015. That
** extension proved so useful that it has now been moved into the core.
**
-** For the time being, all JSON is stored as pure text. (We might add
-** a JSONB type in the future which stores a binary encoding of JSON in
-** a BLOB, but there is no support for JSONB in the current implementation.
-** This implementation parses JSON text at 250 MB/s, so it is hard to see
-** how JSONB might improve on that.)
+** The original design stored all JSON as pure text, canonical RFC-8259.
+** Support for JSON-5 extensions was added with version 3.42.0 (2023-05-16).
+** All generated JSON text still conforms strictly to RFC-8259, but text
+** with JSON-5 extensions is accepted as input.
+**
+** Beginning with version 3.45.0 (circa 2024-01-01), these routines also
+** accept BLOB values that have JSON encoded using a binary representation
+** called "JSONB". The name JSONB comes from PostgreSQL, however the on-disk
+** format SQLite JSONB is completely different and incompatible with
+** PostgreSQL JSONB.
+**
+** Decoding and interpreting JSONB is still O(N) where N is the size of
+** the input, the same as text JSON. However, the constant of proportionality
+** for JSONB is much smaller due to faster parsing. The size of each
+** element in JSONB is encoded in its header, so there is no need to search
+** for delimiters using persnickety syntax rules. JSONB seems to be about
+** 3x faster than text JSON as a result. JSONB is also tends to be slightly
+** smaller than text JSON, by 5% or 10%, but there are corner cases where
+** JSONB can be slightly larger. So you are not far mistaken to say that
+** a JSONB blob is the same size as the equivalent RFC-8259 text.
+**
+**
+** THE JSONB ENCODING:
+**
+** Every JSON element is encoded in JSONB as a header and a payload.
+** The header is between 1 and 9 bytes in size. The payload is zero
+** or more bytes.
+**
+** The lower 4 bits of the first byte of the header determines the
+** element type:
+**
+** 0: NULL
+** 1: TRUE
+** 2: FALSE
+** 3: INT -- RFC-8259 integer literal
+** 4: INT5 -- JSON5 integer literal
+** 5: FLOAT -- RFC-8259 floating point literal
+** 6: FLOAT5 -- JSON5 floating point literal
+** 7: TEXT -- Text literal acceptable to both SQL and JSON
+** 8: TEXTJ -- Text containing RFC-8259 escapes
+** 9: TEXT5 -- Text containing JSON5 and/or RFC-8259 escapes
+** 10: TEXTRAW -- Text containing unescaped syntax characters
+** 11: ARRAY
+** 12: OBJECT
+**
+** The other three possible values (13-15) are reserved for future
+** enhancements.
+**
+** The upper 4 bits of the first byte determine the size of the header
+** and sometimes also the size of the payload. If X is the first byte
+** of the element and if X>>4 is between 0 and 11, then the payload
+** will be that many bytes in size and the header is exactly one byte
+** in size. Other four values for X>>4 (12-15) indicate that the header
+** is more than one byte in size and that the payload size is determined
+** by the remainder of the header, interpreted as a unsigned big-endian
+** integer.
+**
+** Value of X>>4 Size integer Total header size
+** ------------- -------------------- -----------------
+** 12 1 byte (0-255) 2
+** 13 2 byte (0-65535) 3
+** 14 4 byte (0-4294967295) 5
+** 15 8 byte (0-1.8e19) 9
+**
+** The payload size need not be expressed in its minimal form. For example,
+** if the payload size is 10, the size can be expressed in any of 5 different
+** ways: (1) (X>>4)==10, (2) (X>>4)==12 following by on 0x0a byte,
+** (3) (X>>4)==13 followed by 0x00 and 0x0a, (4) (X>>4)==14 followed by
+** 0x00 0x00 0x00 0x0a, or (5) (X>>4)==15 followed by 7 bytes of 0x00 and
+** a single byte of 0x0a. The shorter forms are preferred, of course, but
+** sometimes when generating JSONB, the payload size is not known in advance
+** and it is convenient to reserve sufficient header space to cover the
+** largest possible payload size and then come back later and patch up
+** the size when it becomes known, resulting in a non-minimal encoding.
+**
+** The value (X>>4)==15 is not actually used in the current implementation
+** (as SQLite is currently unable handle BLOBs larger than about 2GB)
+** but is included in the design to allow for future enhancements.
+**
+** The payload follows the header. NULL, TRUE, and FALSE have no payload and
+** their payload size must always be zero. The payload for INT, INT5,
+** FLOAT, FLOAT5, TEXT, TEXTJ, TEXT5, and TEXTROW is text. Note that the
+** "..." or '...' delimiters are omitted from the various text encodings.
+** The payload for ARRAY and OBJECT is a list of additional elements that
+** are the content for the array or object. The payload for an OBJECT
+** must be an even number of elements. The first element of each pair is
+** the label and must be of type TEXT, TEXTJ, TEXT5, or TEXTRAW.
+**
+** A valid JSONB blob consists of a single element, as described above.
+** Usually this will be an ARRAY or OBJECT element which has many more
+** elements as its content. But the overall blob is just a single element.
+**
+** Input validation for JSONB blobs simply checks that the element type
+** code is between 0 and 12 and that the total size of the element
+** (header plus payload) is the same as the size of the BLOB. If those
+** checks are true, the BLOB is assumed to be JSONB and processing continues.
+** Errors are only raised if some other miscoding is discovered during
+** processing.
+**
+** Additional information can be found in the doc/jsonb.md file of the
+** canonical SQLite source tree.
*/
#ifndef SQLITE_OMIT_JSON
/* #include "sqliteInt.h" */
+/* JSONB element types
+*/
+#define JSONB_NULL 0 /* "null" */
+#define JSONB_TRUE 1 /* "true" */
+#define JSONB_FALSE 2 /* "false" */
+#define JSONB_INT 3 /* integer acceptable to JSON and SQL */
+#define JSONB_INT5 4 /* integer in 0x000 notation */
+#define JSONB_FLOAT 5 /* float acceptable to JSON and SQL */
+#define JSONB_FLOAT5 6 /* float with JSON5 extensions */
+#define JSONB_TEXT 7 /* Text compatible with both JSON and SQL */
+#define JSONB_TEXTJ 8 /* Text with JSON escapes */
+#define JSONB_TEXT5 9 /* Text with JSON-5 escape */
+#define JSONB_TEXTRAW 10 /* SQL text that needs escaping for JSON */
+#define JSONB_ARRAY 11 /* An array */
+#define JSONB_OBJECT 12 /* An object */
+
+/* Human-readable names for the JSONB values. The index for each
+** string must correspond to the JSONB_* integer above.
+*/
+static const char * const jsonbType[] = {
+ "null", "true", "false", "integer", "integer",
+ "real", "real", "text", "text", "text",
+ "text", "array", "object", "", "", "", ""
+};
+
/*
** Growing our own isspace() routine this way is twice as fast as
** the library isspace() function, resulting in a 7% overall performance
-** increase for the parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
+** increase for the text-JSON parser. (Ubuntu14.10 gcc 4.8.4 x64 with -Os).
*/
static const char jsonIsSpace[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+#define jsonIsspace(x) (jsonIsSpace[(unsigned char)x])
+
+/*
+** The set of all space characters recognized by jsonIsspace().
+** Useful as the second argument to strspn().
+*/
+static const char jsonSpaces[] = "\011\012\015\040";
+
+/*
+** Characters that are special to JSON. Control characters,
+** '"' and '\\' and '\''. Actually, '\'' is not special to
+** canonical JSON, but it is special in JSON-5, so we include
+** it in the set of special characters.
+*/
+static const char jsonIsOk[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 0, 1, 1, 1, 1, 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, 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, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
};
-#define fast_isspace(x) (jsonIsSpace[(unsigned char)x])
-
-#if !defined(SQLITE_DEBUG) && !defined(SQLITE_COVERAGE_TEST)
-# define VVA(X)
-#else
-# define VVA(X) X
-#endif
/* Objects */
+typedef struct JsonCache JsonCache;
typedef struct JsonString JsonString;
-typedef struct JsonNode JsonNode;
typedef struct JsonParse JsonParse;
+/*
+** Magic number used for the JSON parse cache in sqlite3_get_auxdata()
+*/
+#define JSON_CACHE_ID (-429938) /* Cache entry */
+#define JSON_CACHE_SIZE 4 /* Max number of cache entries */
+
+/*
+** jsonUnescapeOneChar() returns this invalid code point if it encounters
+** a syntax error.
+*/
+#define JSON_INVALID_CHAR 0x99999
+
+/* A cache mapping JSON text into JSONB blobs.
+**
+** Each cache entry is a JsonParse object with the following restrictions:
+**
+** * The bReadOnly flag must be set
+**
+** * The aBlob[] array must be owned by the JsonParse object. In other
+** words, nBlobAlloc must be non-zero.
+**
+** * eEdit and delta must be zero.
+**
+** * zJson must be an RCStr. In other words bJsonIsRCStr must be true.
+*/
+struct JsonCache {
+ sqlite3 *db; /* Database connection */
+ int nUsed; /* Number of active entries in the cache */
+ JsonParse *a[JSON_CACHE_SIZE]; /* One line for each cache entry */
+};
+
/* An instance of this object represents a JSON string
** under construction. Really, this is a generic string accumulator
** that can be and is used to create strings other than JSON.
+**
+** If the generated string is longer than will fit into the zSpace[] buffer,
+** then it will be an RCStr string. This aids with caching of large
+** JSON strings.
*/
struct JsonString {
sqlite3_context *pCtx; /* Function context - put error messages here */
@@ -198835,89 +203663,227 @@ struct JsonString {
u64 nAlloc; /* Bytes of storage available in zBuf[] */
u64 nUsed; /* Bytes of zBuf[] currently used */
u8 bStatic; /* True if zBuf is static space */
- u8 bErr; /* True if an error has been encountered */
+ u8 eErr; /* True if an error has been encountered */
char zSpace[100]; /* Initial static space */
};
-/* JSON type values
-*/
-#define JSON_NULL 0
-#define JSON_TRUE 1
-#define JSON_FALSE 2
-#define JSON_INT 3
-#define JSON_REAL 4
-#define JSON_STRING 5
-#define JSON_ARRAY 6
-#define JSON_OBJECT 7
+/* Allowed values for JsonString.eErr */
+#define JSTRING_OOM 0x01 /* Out of memory */
+#define JSTRING_MALFORMED 0x02 /* Malformed JSONB */
+#define JSTRING_ERR 0x04 /* Error already sent to sqlite3_result */
-/* The "subtype" set for JSON values */
+/* The "subtype" set for text JSON values passed through using
+** sqlite3_result_subtype() and sqlite3_value_subtype().
+*/
#define JSON_SUBTYPE 74 /* Ascii for "J" */
/*
-** Names of the various JSON types:
-*/
-static const char * const jsonType[] = {
- "null", "true", "false", "integer", "real", "text", "array", "object"
-};
-
-/* Bit values for the JsonNode.jnFlag field
+** Bit values for the flags passed into various SQL function implementations
+** via the sqlite3_user_data() value.
*/
-#define JNODE_RAW 0x01 /* Content is raw, not JSON encoded */
-#define JNODE_ESCAPE 0x02 /* Content is text with \ escapes */
-#define JNODE_REMOVE 0x04 /* Do not output */
-#define JNODE_REPLACE 0x08 /* Replace with JsonNode.u.iReplace */
-#define JNODE_PATCH 0x10 /* Patch with JsonNode.u.pPatch */
-#define JNODE_APPEND 0x20 /* More ARRAY/OBJECT entries at u.iAppend */
-#define JNODE_LABEL 0x40 /* Is a label of an object */
-
+#define JSON_JSON 0x01 /* Result is always JSON */
+#define JSON_SQL 0x02 /* Result is always SQL */
+#define JSON_ABPATH 0x03 /* Allow abbreviated JSON path specs */
+#define JSON_ISSET 0x04 /* json_set(), not json_insert() */
+#define JSON_BLOB 0x08 /* Use the BLOB output format */
-/* A single node of parsed JSON
-*/
-struct JsonNode {
- u8 eType; /* One of the JSON_ type values */
- u8 jnFlags; /* JNODE flags */
- u8 eU; /* Which union element to use */
- u32 n; /* Bytes of content, or number of sub-nodes */
- union {
- const char *zJContent; /* 1: Content for INT, REAL, and STRING */
- u32 iAppend; /* 2: More terms for ARRAY and OBJECT */
- u32 iKey; /* 3: Key for ARRAY objects in json_tree() */
- u32 iReplace; /* 4: Replacement content for JNODE_REPLACE */
- JsonNode *pPatch; /* 5: Node chain of patch for JNODE_PATCH */
- } u;
-};
-/* A completely parsed JSON string
+/* A parsed JSON value. Lifecycle:
+**
+** 1. JSON comes in and is parsed into a JSONB value in aBlob. The
+** original text is stored in zJson. This step is skipped if the
+** input is JSONB instead of text JSON.
+**
+** 2. The aBlob[] array is searched using the JSON path notation, if needed.
+**
+** 3. Zero or more changes are made to aBlob[] (via json_remove() or
+** json_replace() or json_patch() or similar).
+**
+** 4. New JSON text is generated from the aBlob[] for output. This step
+** is skipped if the function is one of the jsonb_* functions that
+** returns JSONB instead of text JSON.
*/
struct JsonParse {
- u32 nNode; /* Number of slots of aNode[] used */
- u32 nAlloc; /* Number of slots of aNode[] allocated */
- JsonNode *aNode; /* Array of nodes containing the parse */
- const char *zJson; /* Original JSON string */
- u32 *aUp; /* Index of parent of each node */
- u8 oom; /* Set to true if out of memory */
- u8 nErr; /* Number of errors seen */
- u16 iDepth; /* Nesting depth */
+ u8 *aBlob; /* JSONB representation of JSON value */
+ u32 nBlob; /* Bytes of aBlob[] actually used */
+ u32 nBlobAlloc; /* Bytes allocated to aBlob[]. 0 if aBlob is external */
+ char *zJson; /* Json text used for parsing */
+ sqlite3 *db; /* The database connection to which this object belongs */
int nJson; /* Length of the zJson string in bytes */
- u32 iHold; /* Replace cache line with the lowest iHold value */
+ u32 nJPRef; /* Number of references to this object */
+ u32 iErr; /* Error location in zJson[] */
+ u16 iDepth; /* Nesting depth */
+ u8 nErr; /* Number of errors seen */
+ u8 oom; /* Set to true if out of memory */
+ u8 bJsonIsRCStr; /* True if zJson is an RCStr */
+ u8 hasNonstd; /* True if input uses non-standard features like JSON5 */
+ u8 bReadOnly; /* Do not modify. */
+ /* Search and edit information. See jsonLookupStep() */
+ u8 eEdit; /* Edit operation to apply */
+ int delta; /* Size change due to the edit */
+ u32 nIns; /* Number of bytes to insert */
+ u32 iLabel; /* Location of label if search landed on an object value */
+ u8 *aIns; /* Content to be inserted */
};
+/* Allowed values for JsonParse.eEdit */
+#define JEDIT_DEL 1 /* Delete if exists */
+#define JEDIT_REPL 2 /* Overwrite if exists */
+#define JEDIT_INS 3 /* Insert if not exists */
+#define JEDIT_SET 4 /* Insert or overwrite */
+
/*
** Maximum nesting depth of JSON for this implementation.
**
** This limit is needed to avoid a stack overflow in the recursive
-** descent parser. A depth of 2000 is far deeper than any sane JSON
-** should go.
+** descent parser. A depth of 1000 is far deeper than any sane JSON
+** should go. Historical note: This limit was 2000 prior to version 3.42.0
+*/
+#ifndef SQLITE_JSON_MAX_DEPTH
+# define JSON_MAX_DEPTH 1000
+#else
+# define JSON_MAX_DEPTH SQLITE_JSON_MAX_DEPTH
+#endif
+
+/*
+** Allowed values for the flgs argument to jsonParseFuncArg();
+*/
+#define JSON_EDITABLE 0x01 /* Generate a writable JsonParse object */
+#define JSON_KEEPERROR 0x02 /* Return non-NULL even if there is an error */
+
+/**************************************************************************
+** Forward references
+**************************************************************************/
+static void jsonReturnStringAsBlob(JsonString*);
+static int jsonFuncArgMightBeBinary(sqlite3_value *pJson);
+static u32 jsonTranslateBlobToText(const JsonParse*,u32,JsonString*);
+static void jsonReturnParse(sqlite3_context*,JsonParse*);
+static JsonParse *jsonParseFuncArg(sqlite3_context*,sqlite3_value*,u32);
+static void jsonParseFree(JsonParse*);
+static u32 jsonbPayloadSize(const JsonParse*, u32, u32*);
+static u32 jsonUnescapeOneChar(const char*, u32, u32*);
+
+/**************************************************************************
+** Utility routines for dealing with JsonCache objects
+**************************************************************************/
+
+/*
+** Free a JsonCache object.
+*/
+static void jsonCacheDelete(JsonCache *p){
+ int i;
+ for(i=0; i<p->nUsed; i++){
+ jsonParseFree(p->a[i]);
+ }
+ sqlite3DbFree(p->db, p);
+}
+static void jsonCacheDeleteGeneric(void *p){
+ jsonCacheDelete((JsonCache*)p);
+}
+
+/*
+** Insert a new entry into the cache. If the cache is full, expel
+** the least recently used entry. Return SQLITE_OK on success or a
+** result code otherwise.
+**
+** Cache entries are stored in age order, oldest first.
+*/
+static int jsonCacheInsert(
+ sqlite3_context *ctx, /* The SQL statement context holding the cache */
+ JsonParse *pParse /* The parse object to be added to the cache */
+){
+ JsonCache *p;
+
+ assert( pParse->zJson!=0 );
+ assert( pParse->bJsonIsRCStr );
+ assert( pParse->delta==0 );
+ p = sqlite3_get_auxdata(ctx, JSON_CACHE_ID);
+ if( p==0 ){
+ sqlite3 *db = sqlite3_context_db_handle(ctx);
+ p = sqlite3DbMallocZero(db, sizeof(*p));
+ if( p==0 ) return SQLITE_NOMEM;
+ p->db = db;
+ sqlite3_set_auxdata(ctx, JSON_CACHE_ID, p, jsonCacheDeleteGeneric);
+ p = sqlite3_get_auxdata(ctx, JSON_CACHE_ID);
+ if( p==0 ) return SQLITE_NOMEM;
+ }
+ if( p->nUsed >= JSON_CACHE_SIZE ){
+ jsonParseFree(p->a[0]);
+ memmove(p->a, &p->a[1], (JSON_CACHE_SIZE-1)*sizeof(p->a[0]));
+ p->nUsed = JSON_CACHE_SIZE-1;
+ }
+ assert( pParse->nBlobAlloc>0 );
+ pParse->eEdit = 0;
+ pParse->nJPRef++;
+ pParse->bReadOnly = 1;
+ p->a[p->nUsed] = pParse;
+ p->nUsed++;
+ return SQLITE_OK;
+}
+
+/*
+** Search for a cached translation the json text supplied by pArg. Return
+** the JsonParse object if found. Return NULL if not found.
+**
+** When a match if found, the matching entry is moved to become the
+** most-recently used entry if it isn't so already.
+**
+** The JsonParse object returned still belongs to the Cache and might
+** be deleted at any moment. If the caller whants the JsonParse to
+** linger, it needs to increment the nPJRef reference counter.
*/
-#define JSON_MAX_DEPTH 2000
+static JsonParse *jsonCacheSearch(
+ sqlite3_context *ctx, /* The SQL statement context holding the cache */
+ sqlite3_value *pArg /* Function argument containing SQL text */
+){
+ JsonCache *p;
+ int i;
+ const char *zJson;
+ int nJson;
+
+ if( sqlite3_value_type(pArg)!=SQLITE_TEXT ){
+ return 0;
+ }
+ zJson = (const char*)sqlite3_value_text(pArg);
+ if( zJson==0 ) return 0;
+ nJson = sqlite3_value_bytes(pArg);
+
+ p = sqlite3_get_auxdata(ctx, JSON_CACHE_ID);
+ if( p==0 ){
+ return 0;
+ }
+ for(i=0; i<p->nUsed; i++){
+ if( p->a[i]->zJson==zJson ) break;
+ }
+ if( i>=p->nUsed ){
+ for(i=0; i<p->nUsed; i++){
+ if( p->a[i]->nJson!=nJson ) continue;
+ if( memcmp(p->a[i]->zJson, zJson, nJson)==0 ) break;
+ }
+ }
+ if( i<p->nUsed ){
+ if( i<p->nUsed-1 ){
+ /* Make the matching entry the most recently used entry */
+ JsonParse *tmp = p->a[i];
+ memmove(&p->a[i], &p->a[i+1], (p->nUsed-i-1)*sizeof(tmp));
+ p->a[p->nUsed-1] = tmp;
+ i = p->nUsed - 1;
+ }
+ assert( p->a[i]->delta==0 );
+ return p->a[i];
+ }else{
+ return 0;
+ }
+}
/**************************************************************************
** Utility routines for dealing with JsonString objects
**************************************************************************/
-/* Set the JsonString object to an empty string
+/* Turn uninitialized bulk memory into a valid JsonString object
+** holding a zero-length string.
*/
-static void jsonZero(JsonString *p){
+static void jsonStringZero(JsonString *p){
p->zBuf = p->zSpace;
p->nAlloc = sizeof(p->zSpace);
p->nUsed = 0;
@@ -198926,53 +203892,51 @@ static void jsonZero(JsonString *p){
/* Initialize the JsonString object
*/
-static void jsonInit(JsonString *p, sqlite3_context *pCtx){
+static void jsonStringInit(JsonString *p, sqlite3_context *pCtx){
p->pCtx = pCtx;
- p->bErr = 0;
- jsonZero(p);
+ p->eErr = 0;
+ jsonStringZero(p);
}
-
/* Free all allocated memory and reset the JsonString object back to its
** initial state.
*/
-static void jsonReset(JsonString *p){
- if( !p->bStatic ) sqlite3_free(p->zBuf);
- jsonZero(p);
+static void jsonStringReset(JsonString *p){
+ if( !p->bStatic ) sqlite3RCStrUnref(p->zBuf);
+ jsonStringZero(p);
}
-
/* Report an out-of-memory (OOM) condition
*/
-static void jsonOom(JsonString *p){
- p->bErr = 1;
- sqlite3_result_error_nomem(p->pCtx);
- jsonReset(p);
+static void jsonStringOom(JsonString *p){
+ p->eErr |= JSTRING_OOM;
+ if( p->pCtx ) sqlite3_result_error_nomem(p->pCtx);
+ jsonStringReset(p);
}
/* Enlarge pJson->zBuf so that it can hold at least N more bytes.
** Return zero on success. Return non-zero on an OOM error
*/
-static int jsonGrow(JsonString *p, u32 N){
+static int jsonStringGrow(JsonString *p, u32 N){
u64 nTotal = N<p->nAlloc ? p->nAlloc*2 : p->nAlloc+N+10;
char *zNew;
if( p->bStatic ){
- if( p->bErr ) return 1;
- zNew = sqlite3_malloc64(nTotal);
+ if( p->eErr ) return 1;
+ zNew = sqlite3RCStrNew(nTotal);
if( zNew==0 ){
- jsonOom(p);
+ jsonStringOom(p);
return SQLITE_NOMEM;
}
memcpy(zNew, p->zBuf, (size_t)p->nUsed);
p->zBuf = zNew;
p->bStatic = 0;
}else{
- zNew = sqlite3_realloc64(p->zBuf, nTotal);
- if( zNew==0 ){
- jsonOom(p);
+ p->zBuf = sqlite3RCStrResize(p->zBuf, nTotal);
+ if( p->zBuf==0 ){
+ p->eErr |= JSTRING_OOM;
+ jsonStringZero(p);
return SQLITE_NOMEM;
}
- p->zBuf = zNew;
}
p->nAlloc = nTotal;
return SQLITE_OK;
@@ -198980,18 +203944,41 @@ static int jsonGrow(JsonString *p, u32 N){
/* Append N bytes from zIn onto the end of the JsonString string.
*/
-static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
- if( N==0 ) return;
- if( (N+p->nUsed >= p->nAlloc) && jsonGrow(p,N)!=0 ) return;
+static SQLITE_NOINLINE void jsonStringExpandAndAppend(
+ JsonString *p,
+ const char *zIn,
+ u32 N
+){
+ assert( N>0 );
+ if( jsonStringGrow(p,N) ) return;
memcpy(p->zBuf+p->nUsed, zIn, N);
p->nUsed += N;
}
+static void jsonAppendRaw(JsonString *p, const char *zIn, u32 N){
+ if( N==0 ) return;
+ if( N+p->nUsed >= p->nAlloc ){
+ jsonStringExpandAndAppend(p,zIn,N);
+ }else{
+ memcpy(p->zBuf+p->nUsed, zIn, N);
+ p->nUsed += N;
+ }
+}
+static void jsonAppendRawNZ(JsonString *p, const char *zIn, u32 N){
+ assert( N>0 );
+ if( N+p->nUsed >= p->nAlloc ){
+ jsonStringExpandAndAppend(p,zIn,N);
+ }else{
+ memcpy(p->zBuf+p->nUsed, zIn, N);
+ p->nUsed += N;
+ }
+}
+
/* Append formatted text (not to exceed N bytes) to the JsonString.
*/
static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
va_list ap;
- if( (p->nUsed + N >= p->nAlloc) && jsonGrow(p, N) ) return;
+ if( (p->nUsed + N >= p->nAlloc) && jsonStringGrow(p, N) ) return;
va_start(ap, zFormat);
sqlite3_vsnprintf(N, p->zBuf+p->nUsed, zFormat, ap);
va_end(ap);
@@ -199000,10 +203987,38 @@ static void jsonPrintf(int N, JsonString *p, const char *zFormat, ...){
/* Append a single character
*/
-static void jsonAppendChar(JsonString *p, char c){
- if( p->nUsed>=p->nAlloc && jsonGrow(p,1)!=0 ) return;
+static SQLITE_NOINLINE void jsonAppendCharExpand(JsonString *p, char c){
+ if( jsonStringGrow(p,1) ) return;
p->zBuf[p->nUsed++] = c;
}
+static void jsonAppendChar(JsonString *p, char c){
+ if( p->nUsed>=p->nAlloc ){
+ jsonAppendCharExpand(p,c);
+ }else{
+ p->zBuf[p->nUsed++] = c;
+ }
+}
+
+/* Remove a single character from the end of the string
+*/
+static void jsonStringTrimOneChar(JsonString *p){
+ if( p->eErr==0 ){
+ assert( p->nUsed>0 );
+ p->nUsed--;
+ }
+}
+
+
+/* Make sure there is a zero terminator on p->zBuf[]
+**
+** Return true on success. Return false if an OOM prevents this
+** from happening.
+*/
+static int jsonStringTerminate(JsonString *p){
+ jsonAppendChar(p, 0);
+ jsonStringTrimOneChar(p);
+ return p->eErr==0;
+}
/* Append a comma separator to the output buffer, if the previous
** character is not '[' or '{'.
@@ -199012,25 +204027,76 @@ static void jsonAppendSeparator(JsonString *p){
char c;
if( p->nUsed==0 ) return;
c = p->zBuf[p->nUsed-1];
- if( c!='[' && c!='{' ) jsonAppendChar(p, ',');
+ if( c=='[' || c=='{' ) return;
+ jsonAppendChar(p, ',');
}
/* Append the N-byte string in zIn to the end of the JsonString string
-** under construction. Enclose the string in "..." and escape
-** any double-quotes or backslash characters contained within the
+** under construction. Enclose the string in double-quotes ("...") and
+** escape any double-quotes or backslash characters contained within the
** string.
+**
+** This routine is a high-runner. There is a measurable performance
+** increase associated with unwinding the jsonIsOk[] loop.
*/
static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
- u32 i;
- if( zIn==0 || ((N+p->nUsed+2 >= p->nAlloc) && jsonGrow(p,N+2)!=0) ) return;
+ u32 k;
+ u8 c;
+ const u8 *z = (const u8*)zIn;
+ if( z==0 ) return;
+ if( (N+p->nUsed+2 >= p->nAlloc) && jsonStringGrow(p,N+2)!=0 ) return;
p->zBuf[p->nUsed++] = '"';
- for(i=0; i<N; i++){
- unsigned char c = ((unsigned const char*)zIn)[i];
+ while( 1 /*exit-by-break*/ ){
+ k = 0;
+ /* The following while() is the 4-way unwound equivalent of
+ **
+ ** while( k<N && jsonIsOk[z[k]] ){ k++; }
+ */
+ while( 1 /* Exit by break */ ){
+ if( k+3>=N ){
+ while( k<N && jsonIsOk[z[k]] ){ k++; }
+ break;
+ }
+ if( !jsonIsOk[z[k]] ){
+ break;
+ }
+ if( !jsonIsOk[z[k+1]] ){
+ k += 1;
+ break;
+ }
+ if( !jsonIsOk[z[k+2]] ){
+ k += 2;
+ break;
+ }
+ if( !jsonIsOk[z[k+3]] ){
+ k += 3;
+ break;
+ }else{
+ k += 4;
+ }
+ }
+ if( k>=N ){
+ if( k>0 ){
+ memcpy(&p->zBuf[p->nUsed], z, k);
+ p->nUsed += k;
+ }
+ break;
+ }
+ if( k>0 ){
+ memcpy(&p->zBuf[p->nUsed], z, k);
+ p->nUsed += k;
+ z += k;
+ N -= k;
+ }
+ c = z[0];
if( c=='"' || c=='\\' ){
json_simple_escape:
- if( (p->nUsed+N+3-i > p->nAlloc) && jsonGrow(p,N+3-i)!=0 ) return;
+ if( (p->nUsed+N+3 > p->nAlloc) && jsonStringGrow(p,N+3)!=0 ) return;
p->zBuf[p->nUsed++] = '\\';
- }else if( c<=0x1f ){
+ p->zBuf[p->nUsed++] = c;
+ }else if( c=='\'' ){
+ p->zBuf[p->nUsed++] = c;
+ }else{
static const char aSpecial[] = {
0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
@@ -199041,39 +204107,44 @@ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
assert( aSpecial['\n']=='n' );
assert( aSpecial['\r']=='r' );
assert( aSpecial['\t']=='t' );
+ assert( c>=0 && c<sizeof(aSpecial) );
if( aSpecial[c] ){
c = aSpecial[c];
goto json_simple_escape;
}
- if( (p->nUsed+N+7+i > p->nAlloc) && jsonGrow(p,N+7-i)!=0 ) return;
+ if( (p->nUsed+N+7 > p->nAlloc) && jsonStringGrow(p,N+7)!=0 ) return;
p->zBuf[p->nUsed++] = '\\';
p->zBuf[p->nUsed++] = 'u';
p->zBuf[p->nUsed++] = '0';
p->zBuf[p->nUsed++] = '0';
- p->zBuf[p->nUsed++] = '0' + (c>>4);
- c = "0123456789abcdef"[c&0xf];
+ p->zBuf[p->nUsed++] = "0123456789abcdef"[c>>4];
+ p->zBuf[p->nUsed++] = "0123456789abcdef"[c&0xf];
}
- p->zBuf[p->nUsed++] = c;
+ z++;
+ N--;
}
p->zBuf[p->nUsed++] = '"';
assert( p->nUsed<p->nAlloc );
}
/*
-** Append a function parameter value to the JSON string under
-** construction.
+** Append an sqlite3_value (such as a function parameter) to the JSON
+** string under construction in p.
*/
-static void jsonAppendValue(
+static void jsonAppendSqlValue(
JsonString *p, /* Append to this JSON string */
sqlite3_value *pValue /* Value to append */
){
switch( sqlite3_value_type(pValue) ){
case SQLITE_NULL: {
- jsonAppendRaw(p, "null", 4);
+ jsonAppendRawNZ(p, "null", 4);
break;
}
- case SQLITE_INTEGER:
case SQLITE_FLOAT: {
+ jsonPrintf(100, p, "%!0.15g", sqlite3_value_double(pValue));
+ break;
+ }
+ case SQLITE_INTEGER: {
const char *z = (const char*)sqlite3_value_text(pValue);
u32 n = (u32)sqlite3_value_bytes(pValue);
jsonAppendRaw(p, z, n);
@@ -199090,184 +204161,127 @@ static void jsonAppendValue(
break;
}
default: {
- if( p->bErr==0 ){
+ if( jsonFuncArgMightBeBinary(pValue) ){
+ JsonParse px;
+ memset(&px, 0, sizeof(px));
+ px.aBlob = (u8*)sqlite3_value_blob(pValue);
+ px.nBlob = sqlite3_value_bytes(pValue);
+ jsonTranslateBlobToText(&px, 0, p);
+ }else if( p->eErr==0 ){
sqlite3_result_error(p->pCtx, "JSON cannot hold BLOB values", -1);
- p->bErr = 2;
- jsonReset(p);
+ p->eErr = JSTRING_ERR;
+ jsonStringReset(p);
}
break;
}
}
}
-
-/* Make the JSON in p the result of the SQL function.
+/* Make the text in p (which is probably a generated JSON text string)
+** the result of the SQL function.
+**
+** The JsonString is reset.
+**
+** If pParse and ctx are both non-NULL, then the SQL string in p is
+** loaded into the zJson field of the pParse object as a RCStr and the
+** pParse is added to the cache.
*/
-static void jsonResult(JsonString *p){
- if( p->bErr==0 ){
- sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
- p->bStatic ? SQLITE_TRANSIENT : sqlite3_free,
- SQLITE_UTF8);
- jsonZero(p);
+static void jsonReturnString(
+ JsonString *p, /* String to return */
+ JsonParse *pParse, /* JSONB source or NULL */
+ sqlite3_context *ctx /* Where to cache */
+){
+ assert( (pParse!=0)==(ctx!=0) );
+ assert( ctx==0 || ctx==p->pCtx );
+ if( p->eErr==0 ){
+ int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(p->pCtx));
+ if( flags & JSON_BLOB ){
+ jsonReturnStringAsBlob(p);
+ }else if( p->bStatic ){
+ sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed,
+ SQLITE_TRANSIENT, SQLITE_UTF8);
+ }else if( jsonStringTerminate(p) ){
+ if( pParse && pParse->bJsonIsRCStr==0 && pParse->nBlobAlloc>0 ){
+ int rc;
+ pParse->zJson = sqlite3RCStrRef(p->zBuf);
+ pParse->nJson = p->nUsed;
+ pParse->bJsonIsRCStr = 1;
+ rc = jsonCacheInsert(ctx, pParse);
+ if( rc==SQLITE_NOMEM ){
+ sqlite3_result_error_nomem(ctx);
+ jsonStringReset(p);
+ return;
+ }
+ }
+ sqlite3_result_text64(p->pCtx, sqlite3RCStrRef(p->zBuf), p->nUsed,
+ sqlite3RCStrUnref,
+ SQLITE_UTF8);
+ }else{
+ sqlite3_result_error_nomem(p->pCtx);
+ }
+ }else if( p->eErr & JSTRING_OOM ){
+ sqlite3_result_error_nomem(p->pCtx);
+ }else if( p->eErr & JSTRING_MALFORMED ){
+ sqlite3_result_error(p->pCtx, "malformed JSON", -1);
}
- assert( p->bStatic );
+ jsonStringReset(p);
}
/**************************************************************************
-** Utility routines for dealing with JsonNode and JsonParse objects
+** Utility routines for dealing with JsonParse objects
**************************************************************************/
/*
-** Return the number of consecutive JsonNode slots need to represent
-** the parsed JSON at pNode. The minimum answer is 1. For ARRAY and
-** OBJECT types, the number might be larger.
-**
-** Appended elements are not counted. The value returned is the number
-** by which the JsonNode counter should increment in order to go to the
-** next peer value.
-*/
-static u32 jsonNodeSize(JsonNode *pNode){
- return pNode->eType>=JSON_ARRAY ? pNode->n+1 : 1;
-}
-
-/*
** Reclaim all memory allocated by a JsonParse object. But do not
** delete the JsonParse object itself.
*/
static void jsonParseReset(JsonParse *pParse){
- sqlite3_free(pParse->aNode);
- pParse->aNode = 0;
- pParse->nNode = 0;
- pParse->nAlloc = 0;
- sqlite3_free(pParse->aUp);
- pParse->aUp = 0;
+ assert( pParse->nJPRef<=1 );
+ if( pParse->bJsonIsRCStr ){
+ sqlite3RCStrUnref(pParse->zJson);
+ pParse->zJson = 0;
+ pParse->nJson = 0;
+ pParse->bJsonIsRCStr = 0;
+ }
+ if( pParse->nBlobAlloc ){
+ sqlite3DbFree(pParse->db, pParse->aBlob);
+ pParse->aBlob = 0;
+ pParse->nBlob = 0;
+ pParse->nBlobAlloc = 0;
+ }
}
/*
-** Free a JsonParse object that was obtained from sqlite3_malloc().
+** Decrement the reference count on the JsonParse object. When the
+** count reaches zero, free the object.
*/
static void jsonParseFree(JsonParse *pParse){
- jsonParseReset(pParse);
- sqlite3_free(pParse);
-}
-
-/*
-** Convert the JsonNode pNode into a pure JSON string and
-** append to pOut. Subsubstructure is also included. Return
-** the number of JsonNode objects that are encoded.
-*/
-static void jsonRenderNode(
- JsonNode *pNode, /* The node to render */
- JsonString *pOut, /* Write JSON here */
- sqlite3_value **aReplace /* Replacement values */
-){
- assert( pNode!=0 );
- if( pNode->jnFlags & (JNODE_REPLACE|JNODE_PATCH) ){
- if( (pNode->jnFlags & JNODE_REPLACE)!=0 && ALWAYS(aReplace!=0) ){
- assert( pNode->eU==4 );
- jsonAppendValue(pOut, aReplace[pNode->u.iReplace]);
- return;
- }
- assert( pNode->eU==5 );
- pNode = pNode->u.pPatch;
- }
- switch( pNode->eType ){
- default: {
- assert( pNode->eType==JSON_NULL );
- jsonAppendRaw(pOut, "null", 4);
- break;
- }
- case JSON_TRUE: {
- jsonAppendRaw(pOut, "true", 4);
- break;
- }
- case JSON_FALSE: {
- jsonAppendRaw(pOut, "false", 5);
- break;
- }
- case JSON_STRING: {
- if( pNode->jnFlags & JNODE_RAW ){
- assert( pNode->eU==1 );
- jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
- break;
- }
- /* no break */ deliberate_fall_through
- }
- case JSON_REAL:
- case JSON_INT: {
- assert( pNode->eU==1 );
- jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
- break;
- }
- case JSON_ARRAY: {
- u32 j = 1;
- jsonAppendChar(pOut, '[');
- for(;;){
- while( j<=pNode->n ){
- if( (pNode[j].jnFlags & JNODE_REMOVE)==0 ){
- jsonAppendSeparator(pOut);
- jsonRenderNode(&pNode[j], pOut, aReplace);
- }
- j += jsonNodeSize(&pNode[j]);
- }
- if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
- assert( pNode->eU==2 );
- pNode = &pNode[pNode->u.iAppend];
- j = 1;
- }
- jsonAppendChar(pOut, ']');
- break;
- }
- case JSON_OBJECT: {
- u32 j = 1;
- jsonAppendChar(pOut, '{');
- for(;;){
- while( j<=pNode->n ){
- if( (pNode[j+1].jnFlags & JNODE_REMOVE)==0 ){
- jsonAppendSeparator(pOut);
- jsonRenderNode(&pNode[j], pOut, aReplace);
- jsonAppendChar(pOut, ':');
- jsonRenderNode(&pNode[j+1], pOut, aReplace);
- }
- j += 1 + jsonNodeSize(&pNode[j+1]);
- }
- if( (pNode->jnFlags & JNODE_APPEND)==0 ) break;
- assert( pNode->eU==2 );
- pNode = &pNode[pNode->u.iAppend];
- j = 1;
- }
- jsonAppendChar(pOut, '}');
- break;
+ if( pParse ){
+ if( pParse->nJPRef>1 ){
+ pParse->nJPRef--;
+ }else{
+ jsonParseReset(pParse);
+ sqlite3DbFree(pParse->db, pParse);
}
}
}
-/*
-** Return a JsonNode and all its descendents as a JSON string.
-*/
-static void jsonReturnJson(
- JsonNode *pNode, /* Node to return */
- sqlite3_context *pCtx, /* Return value for this function */
- sqlite3_value **aReplace /* Array of replacement values */
-){
- JsonString s;
- jsonInit(&s, pCtx);
- jsonRenderNode(pNode, &s, aReplace);
- jsonResult(&s);
- sqlite3_result_subtype(pCtx, JSON_SUBTYPE);
-}
+/**************************************************************************
+** Utility routines for the JSON text parser
+**************************************************************************/
/*
** Translate a single byte of Hex into an integer.
-** This routine only works if h really is a valid hexadecimal
-** character: 0..9a..fA..F
+** This routine only gives a correct answer if h really is a valid hexadecimal
+** character: 0..9a..fA..F. But unlike sqlite3HexToInt(), it does not
+** assert() if the digit is not hex.
*/
static u8 jsonHexToInt(int h){
- assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') );
+#ifdef SQLITE_ASCII
+ h += 9*(1&(h>>6));
+#endif
#ifdef SQLITE_EBCDIC
h += 9*(1&~(h>>4));
-#else
- h += 9*(1&(h>>6));
#endif
return (u8)(h & 0xf);
}
@@ -199277,10 +204291,6 @@ static u8 jsonHexToInt(int h){
*/
static u32 jsonHexToInt4(const char *z){
u32 v;
- assert( sqlite3Isxdigit(z[0]) );
- assert( sqlite3Isxdigit(z[1]) );
- assert( sqlite3Isxdigit(z[2]) );
- assert( sqlite3Isxdigit(z[3]) );
v = (jsonHexToInt(z[0])<<12)
+ (jsonHexToInt(z[1])<<8)
+ (jsonHexToInt(z[2])<<4)
@@ -199289,420 +204299,1099 @@ static u32 jsonHexToInt4(const char *z){
}
/*
-** Make the JsonNode the return value of the function.
+** Return true if z[] begins with 2 (or more) hexadecimal digits
*/
-static void jsonReturn(
- JsonNode *pNode, /* Node to return */
- sqlite3_context *pCtx, /* Return value for this function */
- sqlite3_value **aReplace /* Array of replacement values */
-){
- switch( pNode->eType ){
- default: {
- assert( pNode->eType==JSON_NULL );
- sqlite3_result_null(pCtx);
- break;
- }
- case JSON_TRUE: {
- sqlite3_result_int(pCtx, 1);
- break;
- }
- case JSON_FALSE: {
- sqlite3_result_int(pCtx, 0);
- break;
- }
- case JSON_INT: {
- sqlite3_int64 i = 0;
- const char *z;
- assert( pNode->eU==1 );
- z = pNode->u.zJContent;
- if( z[0]=='-' ){ z++; }
- while( z[0]>='0' && z[0]<='9' ){
- unsigned v = *(z++) - '0';
- if( i>=LARGEST_INT64/10 ){
- if( i>LARGEST_INT64/10 ) goto int_as_real;
- if( z[0]>='0' && z[0]<='9' ) goto int_as_real;
- if( v==9 ) goto int_as_real;
- if( v==8 ){
- if( pNode->u.zJContent[0]=='-' ){
- sqlite3_result_int64(pCtx, SMALLEST_INT64);
- goto int_done;
- }else{
- goto int_as_real;
+static int jsonIs2Hex(const char *z){
+ return sqlite3Isxdigit(z[0]) && sqlite3Isxdigit(z[1]);
+}
+
+/*
+** Return true if z[] begins with 4 (or more) hexadecimal digits
+*/
+static int jsonIs4Hex(const char *z){
+ return jsonIs2Hex(z) && jsonIs2Hex(&z[2]);
+}
+
+/*
+** Return the number of bytes of JSON5 whitespace at the beginning of
+** the input string z[].
+**
+** JSON5 whitespace consists of any of the following characters:
+**
+** Unicode UTF-8 Name
+** U+0009 09 horizontal tab
+** U+000a 0a line feed
+** U+000b 0b vertical tab
+** U+000c 0c form feed
+** U+000d 0d carriage return
+** U+0020 20 space
+** U+00a0 c2 a0 non-breaking space
+** U+1680 e1 9a 80 ogham space mark
+** U+2000 e2 80 80 en quad
+** U+2001 e2 80 81 em quad
+** U+2002 e2 80 82 en space
+** U+2003 e2 80 83 em space
+** U+2004 e2 80 84 three-per-em space
+** U+2005 e2 80 85 four-per-em space
+** U+2006 e2 80 86 six-per-em space
+** U+2007 e2 80 87 figure space
+** U+2008 e2 80 88 punctuation space
+** U+2009 e2 80 89 thin space
+** U+200a e2 80 8a hair space
+** U+2028 e2 80 a8 line separator
+** U+2029 e2 80 a9 paragraph separator
+** U+202f e2 80 af narrow no-break space (NNBSP)
+** U+205f e2 81 9f medium mathematical space (MMSP)
+** U+3000 e3 80 80 ideographical space
+** U+FEFF ef bb bf byte order mark
+**
+** In addition, comments between '/', '*' and '*', '/' and
+** from '/', '/' to end-of-line are also considered to be whitespace.
+*/
+static int json5Whitespace(const char *zIn){
+ int n = 0;
+ const u8 *z = (u8*)zIn;
+ while( 1 /*exit by "goto whitespace_done"*/ ){
+ switch( z[n] ){
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x20: {
+ n++;
+ break;
+ }
+ case '/': {
+ if( z[n+1]=='*' && z[n+2]!=0 ){
+ int j;
+ for(j=n+3; z[j]!='/' || z[j-1]!='*'; j++){
+ if( z[j]==0 ) goto whitespace_done;
+ }
+ n = j+1;
+ break;
+ }else if( z[n+1]=='/' ){
+ int j;
+ char c;
+ for(j=n+2; (c = z[j])!=0; j++){
+ if( c=='\n' || c=='\r' ) break;
+ if( 0xe2==(u8)c && 0x80==(u8)z[j+1]
+ && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2])
+ ){
+ j += 2;
+ break;
}
}
+ n = j;
+ if( z[n] ) n++;
+ break;
}
- i = i*10 + v;
+ goto whitespace_done;
}
- if( pNode->u.zJContent[0]=='-' ){ i = -i; }
- sqlite3_result_int64(pCtx, i);
- int_done:
- break;
- int_as_real: ; /* no break */ deliberate_fall_through
- }
- case JSON_REAL: {
- double r;
-#ifdef SQLITE_AMALGAMATION
- const char *z;
- assert( pNode->eU==1 );
- z = pNode->u.zJContent;
- sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
-#else
- assert( pNode->eU==1 );
- r = strtod(pNode->u.zJContent, 0);
-#endif
- sqlite3_result_double(pCtx, r);
- break;
- }
- case JSON_STRING: {
-#if 0 /* Never happens because JNODE_RAW is only set by json_set(),
- ** json_insert() and json_replace() and those routines do not
- ** call jsonReturn() */
- if( pNode->jnFlags & JNODE_RAW ){
- assert( pNode->eU==1 );
- sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n,
- SQLITE_TRANSIENT);
- }else
-#endif
- assert( (pNode->jnFlags & JNODE_RAW)==0 );
- if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){
- /* JSON formatted without any backslash-escapes */
- assert( pNode->eU==1 );
- sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2,
- SQLITE_TRANSIENT);
- }else{
- /* Translate JSON formatted string into raw text */
- u32 i;
- u32 n = pNode->n;
- const char *z;
- char *zOut;
- u32 j;
- assert( pNode->eU==1 );
- z = pNode->u.zJContent;
- zOut = sqlite3_malloc( n+1 );
- if( zOut==0 ){
- sqlite3_result_error_nomem(pCtx);
+ case 0xc2: {
+ if( z[n+1]==0xa0 ){
+ n += 2;
break;
}
- for(i=1, j=0; i<n-1; i++){
- char c = z[i];
- if( c!='\\' ){
- zOut[j++] = c;
- }else{
- c = z[++i];
- if( c=='u' ){
- u32 v = jsonHexToInt4(z+i+1);
- i += 4;
- if( v==0 ) break;
- if( v<=0x7f ){
- zOut[j++] = (char)v;
- }else if( v<=0x7ff ){
- zOut[j++] = (char)(0xc0 | (v>>6));
- zOut[j++] = 0x80 | (v&0x3f);
- }else{
- u32 vlo;
- if( (v&0xfc00)==0xd800
- && i<n-6
- && z[i+1]=='\\'
- && z[i+2]=='u'
- && ((vlo = jsonHexToInt4(z+i+3))&0xfc00)==0xdc00
- ){
- /* We have a surrogate pair */
- v = ((v&0x3ff)<<10) + (vlo&0x3ff) + 0x10000;
- i += 6;
- zOut[j++] = 0xf0 | (v>>18);
- zOut[j++] = 0x80 | ((v>>12)&0x3f);
- zOut[j++] = 0x80 | ((v>>6)&0x3f);
- zOut[j++] = 0x80 | (v&0x3f);
- }else{
- zOut[j++] = 0xe0 | (v>>12);
- zOut[j++] = 0x80 | ((v>>6)&0x3f);
- zOut[j++] = 0x80 | (v&0x3f);
- }
- }
- }else{
- if( c=='b' ){
- c = '\b';
- }else if( c=='f' ){
- c = '\f';
- }else if( c=='n' ){
- c = '\n';
- }else if( c=='r' ){
- c = '\r';
- }else if( c=='t' ){
- c = '\t';
- }
- zOut[j++] = c;
- }
+ goto whitespace_done;
+ }
+ case 0xe1: {
+ if( z[n+1]==0x9a && z[n+2]==0x80 ){
+ n += 3;
+ break;
+ }
+ goto whitespace_done;
+ }
+ case 0xe2: {
+ if( z[n+1]==0x80 ){
+ u8 c = z[n+2];
+ if( c<0x80 ) goto whitespace_done;
+ if( c<=0x8a || c==0xa8 || c==0xa9 || c==0xaf ){
+ n += 3;
+ break;
}
+ }else if( z[n+1]==0x81 && z[n+2]==0x9f ){
+ n += 3;
+ break;
}
- zOut[j] = 0;
- sqlite3_result_text(pCtx, zOut, j, sqlite3_free);
+ goto whitespace_done;
+ }
+ case 0xe3: {
+ if( z[n+1]==0x80 && z[n+2]==0x80 ){
+ n += 3;
+ break;
+ }
+ goto whitespace_done;
+ }
+ case 0xef: {
+ if( z[n+1]==0xbb && z[n+2]==0xbf ){
+ n += 3;
+ break;
+ }
+ goto whitespace_done;
+ }
+ default: {
+ goto whitespace_done;
}
- break;
- }
- case JSON_ARRAY:
- case JSON_OBJECT: {
- jsonReturnJson(pNode, pCtx, aReplace);
- break;
}
}
+ whitespace_done:
+ return n;
}
-/* Forward reference */
-static int jsonParseAddNode(JsonParse*,u32,u32,const char*);
-
/*
-** A macro to hint to the compiler that a function should not be
-** inlined.
+** Extra floating-point literals to allow in JSON.
*/
-#if defined(__GNUC__)
-# define JSON_NOINLINE __attribute__((noinline))
-#elif defined(_MSC_VER) && _MSC_VER>=1310
-# define JSON_NOINLINE __declspec(noinline)
-#else
-# define JSON_NOINLINE
-#endif
+static const struct NanInfName {
+ char c1;
+ char c2;
+ char n;
+ char eType;
+ char nRepl;
+ char *zMatch;
+ char *zRepl;
+} aNanInfName[] = {
+ { 'i', 'I', 3, JSONB_FLOAT, 7, "inf", "9.0e999" },
+ { 'i', 'I', 8, JSONB_FLOAT, 7, "infinity", "9.0e999" },
+ { 'n', 'N', 3, JSONB_NULL, 4, "NaN", "null" },
+ { 'q', 'Q', 4, JSONB_NULL, 4, "QNaN", "null" },
+ { 's', 'S', 4, JSONB_NULL, 4, "SNaN", "null" },
+};
-static JSON_NOINLINE int jsonParseAddNodeExpand(
- JsonParse *pParse, /* Append the node to this object */
- u32 eType, /* Node type */
- u32 n, /* Content size or sub-node count */
- const char *zContent /* Content */
+/*
+** Report the wrong number of arguments for json_insert(), json_replace()
+** or json_set().
+*/
+static void jsonWrongNumArgs(
+ sqlite3_context *pCtx,
+ const char *zFuncName
){
- u32 nNew;
- JsonNode *pNew;
- assert( pParse->nNode>=pParse->nAlloc );
- if( pParse->oom ) return -1;
- nNew = pParse->nAlloc*2 + 10;
- pNew = sqlite3_realloc64(pParse->aNode, sizeof(JsonNode)*nNew);
- if( pNew==0 ){
- pParse->oom = 1;
- return -1;
+ char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments",
+ zFuncName);
+ sqlite3_result_error(pCtx, zMsg, -1);
+ sqlite3_free(zMsg);
+}
+
+/****************************************************************************
+** Utility routines for dealing with the binary BLOB representation of JSON
+****************************************************************************/
+
+/*
+** Expand pParse->aBlob so that it holds at least N bytes.
+**
+** Return the number of errors.
+*/
+static int jsonBlobExpand(JsonParse *pParse, u32 N){
+ u8 *aNew;
+ u32 t;
+ assert( N>pParse->nBlobAlloc );
+ if( pParse->nBlobAlloc==0 ){
+ t = 100;
+ }else{
+ t = pParse->nBlobAlloc*2;
}
- pParse->nAlloc = nNew;
- pParse->aNode = pNew;
- assert( pParse->nNode<pParse->nAlloc );
- return jsonParseAddNode(pParse, eType, n, zContent);
+ if( t<N ) t = N+100;
+ aNew = sqlite3DbRealloc(pParse->db, pParse->aBlob, t);
+ if( aNew==0 ){ pParse->oom = 1; return 1; }
+ pParse->aBlob = aNew;
+ pParse->nBlobAlloc = t;
+ return 0;
}
/*
-** Create a new JsonNode instance based on the arguments and append that
-** instance to the JsonParse. Return the index in pParse->aNode[] of the
-** new node, or -1 if a memory allocation fails.
+** If pParse->aBlob is not previously editable (because it is taken
+** from sqlite3_value_blob(), as indicated by the fact that
+** pParse->nBlobAlloc==0 and pParse->nBlob>0) then make it editable
+** by making a copy into space obtained from malloc.
+**
+** Return true on success. Return false on OOM.
+*/
+static int jsonBlobMakeEditable(JsonParse *pParse, u32 nExtra){
+ u8 *aOld;
+ u32 nSize;
+ assert( !pParse->bReadOnly );
+ if( pParse->oom ) return 0;
+ if( pParse->nBlobAlloc>0 ) return 1;
+ aOld = pParse->aBlob;
+ nSize = pParse->nBlob + nExtra;
+ pParse->aBlob = 0;
+ if( jsonBlobExpand(pParse, nSize) ){
+ return 0;
+ }
+ assert( pParse->nBlobAlloc >= pParse->nBlob + nExtra );
+ memcpy(pParse->aBlob, aOld, pParse->nBlob);
+ return 1;
+}
+
+/* Expand pParse->aBlob and append one bytes.
*/
-static int jsonParseAddNode(
- JsonParse *pParse, /* Append the node to this object */
- u32 eType, /* Node type */
- u32 n, /* Content size or sub-node count */
- const char *zContent /* Content */
+static SQLITE_NOINLINE void jsonBlobExpandAndAppendOneByte(
+ JsonParse *pParse,
+ u8 c
){
- JsonNode *p;
- if( pParse->aNode==0 || pParse->nNode>=pParse->nAlloc ){
- return jsonParseAddNodeExpand(pParse, eType, n, zContent);
+ jsonBlobExpand(pParse, pParse->nBlob+1);
+ if( pParse->oom==0 ){
+ assert( pParse->nBlob+1<=pParse->nBlobAlloc );
+ pParse->aBlob[pParse->nBlob++] = c;
}
- p = &pParse->aNode[pParse->nNode];
- p->eType = (u8)eType;
- p->jnFlags = 0;
- VVA( p->eU = zContent ? 1 : 0 );
- p->n = n;
- p->u.zJContent = zContent;
- return pParse->nNode++;
}
-/*
-** Return true if z[] begins with 4 (or more) hexadecimal digits
+/* Append a single character.
*/
-static int jsonIs4Hex(const char *z){
- int i;
- for(i=0; i<4; i++) if( !sqlite3Isxdigit(z[i]) ) return 0;
+static void jsonBlobAppendOneByte(JsonParse *pParse, u8 c){
+ if( pParse->nBlob >= pParse->nBlobAlloc ){
+ jsonBlobExpandAndAppendOneByte(pParse, c);
+ }else{
+ pParse->aBlob[pParse->nBlob++] = c;
+ }
+}
+
+/* Slow version of jsonBlobAppendNode() that first resizes the
+** pParse->aBlob structure.
+*/
+static void jsonBlobAppendNode(JsonParse*,u8,u32,const void*);
+static SQLITE_NOINLINE void jsonBlobExpandAndAppendNode(
+ JsonParse *pParse,
+ u8 eType,
+ u32 szPayload,
+ const void *aPayload
+){
+ if( jsonBlobExpand(pParse, pParse->nBlob+szPayload+9) ) return;
+ jsonBlobAppendNode(pParse, eType, szPayload, aPayload);
+}
+
+
+/* Append an node type byte together with the payload size and
+** possibly also the payload.
+**
+** If aPayload is not NULL, then it is a pointer to the payload which
+** is also appended. If aPayload is NULL, the pParse->aBlob[] array
+** is resized (if necessary) so that it is big enough to hold the
+** payload, but the payload is not appended and pParse->nBlob is left
+** pointing to where the first byte of payload will eventually be.
+*/
+static void jsonBlobAppendNode(
+ JsonParse *pParse, /* The JsonParse object under construction */
+ u8 eType, /* Node type. One of JSONB_* */
+ u32 szPayload, /* Number of bytes of payload */
+ const void *aPayload /* The payload. Might be NULL */
+){
+ u8 *a;
+ if( pParse->nBlob+szPayload+9 > pParse->nBlobAlloc ){
+ jsonBlobExpandAndAppendNode(pParse,eType,szPayload,aPayload);
+ return;
+ }
+ assert( pParse->aBlob!=0 );
+ a = &pParse->aBlob[pParse->nBlob];
+ if( szPayload<=11 ){
+ a[0] = eType | (szPayload<<4);
+ pParse->nBlob += 1;
+ }else if( szPayload<=0xff ){
+ a[0] = eType | 0xc0;
+ a[1] = szPayload & 0xff;
+ pParse->nBlob += 2;
+ }else if( szPayload<=0xffff ){
+ a[0] = eType | 0xd0;
+ a[1] = (szPayload >> 8) & 0xff;
+ a[2] = szPayload & 0xff;
+ pParse->nBlob += 3;
+ }else{
+ a[0] = eType | 0xe0;
+ a[1] = (szPayload >> 24) & 0xff;
+ a[2] = (szPayload >> 16) & 0xff;
+ a[3] = (szPayload >> 8) & 0xff;
+ a[4] = szPayload & 0xff;
+ pParse->nBlob += 5;
+ }
+ if( aPayload ){
+ pParse->nBlob += szPayload;
+ memcpy(&pParse->aBlob[pParse->nBlob-szPayload], aPayload, szPayload);
+ }
+}
+
+/* Change the payload size for the node at index i to be szPayload.
+*/
+static int jsonBlobChangePayloadSize(
+ JsonParse *pParse,
+ u32 i,
+ u32 szPayload
+){
+ u8 *a;
+ u8 szType;
+ u8 nExtra;
+ u8 nNeeded;
+ int delta;
+ if( pParse->oom ) return 0;
+ a = &pParse->aBlob[i];
+ szType = a[0]>>4;
+ if( szType<=11 ){
+ nExtra = 0;
+ }else if( szType==12 ){
+ nExtra = 1;
+ }else if( szType==13 ){
+ nExtra = 2;
+ }else{
+ nExtra = 4;
+ }
+ if( szPayload<=11 ){
+ nNeeded = 0;
+ }else if( szPayload<=0xff ){
+ nNeeded = 1;
+ }else if( szPayload<=0xffff ){
+ nNeeded = 2;
+ }else{
+ nNeeded = 4;
+ }
+ delta = nNeeded - nExtra;
+ if( delta ){
+ u32 newSize = pParse->nBlob + delta;
+ if( delta>0 ){
+ if( newSize>pParse->nBlobAlloc && jsonBlobExpand(pParse, newSize) ){
+ return 0; /* OOM error. Error state recorded in pParse->oom. */
+ }
+ a = &pParse->aBlob[i];
+ memmove(&a[1+delta], &a[1], pParse->nBlob - (i+1));
+ }else{
+ memmove(&a[1], &a[1-delta], pParse->nBlob - (i+1-delta));
+ }
+ pParse->nBlob = newSize;
+ }
+ if( nNeeded==0 ){
+ a[0] = (a[0] & 0x0f) | (szPayload<<4);
+ }else if( nNeeded==1 ){
+ a[0] = (a[0] & 0x0f) | 0xc0;
+ a[1] = szPayload & 0xff;
+ }else if( nNeeded==2 ){
+ a[0] = (a[0] & 0x0f) | 0xd0;
+ a[1] = (szPayload >> 8) & 0xff;
+ a[2] = szPayload & 0xff;
+ }else{
+ a[0] = (a[0] & 0x0f) | 0xe0;
+ a[1] = (szPayload >> 24) & 0xff;
+ a[2] = (szPayload >> 16) & 0xff;
+ a[3] = (szPayload >> 8) & 0xff;
+ a[4] = szPayload & 0xff;
+ }
+ return delta;
+}
+
+/*
+** If z[0] is 'u' and is followed by exactly 4 hexadecimal character,
+** then set *pOp to JSONB_TEXTJ and return true. If not, do not make
+** any changes to *pOp and return false.
+*/
+static int jsonIs4HexB(const char *z, int *pOp){
+ if( z[0]!='u' ) return 0;
+ if( !jsonIs4Hex(&z[1]) ) return 0;
+ *pOp = JSONB_TEXTJ;
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.
+** Check a single element of the JSONB in pParse for validity.
+**
+** The element to be checked starts at offset i and must end at on the
+** last byte before iEnd.
+**
+** Return 0 if everything is correct. Return the 1-based byte offset of the
+** error if a problem is detected. (In other words, if the error is at offset
+** 0, return 1).
+*/
+static u32 jsonbValidityCheck(
+ const JsonParse *pParse, /* Input JSONB. Only aBlob and nBlob are used */
+ u32 i, /* Start of element as pParse->aBlob[i] */
+ u32 iEnd, /* One more than the last byte of the element */
+ u32 iDepth /* Current nesting depth */
+){
+ u32 n, sz, j, k;
+ const u8 *z;
+ u8 x;
+ if( iDepth>JSON_MAX_DEPTH ) return i+1;
+ sz = 0;
+ n = jsonbPayloadSize(pParse, i, &sz);
+ if( NEVER(n==0) ) return i+1; /* Checked by caller */
+ if( NEVER(i+n+sz!=iEnd) ) return i+1; /* Checked by caller */
+ z = pParse->aBlob;
+ x = z[i] & 0x0f;
+ switch( x ){
+ case JSONB_NULL:
+ case JSONB_TRUE:
+ case JSONB_FALSE: {
+ return n+sz==1 ? 0 : i+1;
+ }
+ case JSONB_INT: {
+ if( sz<1 ) return i+1;
+ j = i+n;
+ if( z[j]=='-' ){
+ j++;
+ if( sz<2 ) return i+1;
+ }
+ k = i+n+sz;
+ while( j<k ){
+ if( sqlite3Isdigit(z[j]) ){
+ j++;
+ }else{
+ return j+1;
+ }
+ }
+ return 0;
+ }
+ case JSONB_INT5: {
+ if( sz<3 ) return i+1;
+ j = i+n;
+ if( z[j]=='-' ){
+ if( sz<4 ) return i+1;
+ j++;
+ }
+ if( z[j]!='0' ) return i+1;
+ if( z[j+1]!='x' && z[j+1]!='X' ) return j+2;
+ j += 2;
+ k = i+n+sz;
+ while( j<k ){
+ if( sqlite3Isxdigit(z[j]) ){
+ j++;
+ }else{
+ return j+1;
+ }
+ }
+ return 0;
+ }
+ case JSONB_FLOAT:
+ case JSONB_FLOAT5: {
+ u8 seen = 0; /* 0: initial. 1: '.' seen 2: 'e' seen */
+ if( sz<2 ) return i+1;
+ j = i+n;
+ k = j+sz;
+ if( z[j]=='-' ){
+ j++;
+ if( sz<3 ) return i+1;
+ }
+ if( z[j]=='.' ){
+ if( x==JSONB_FLOAT ) return j+1;
+ if( !sqlite3Isdigit(z[j+1]) ) return j+1;
+ j += 2;
+ seen = 1;
+ }else if( z[j]=='0' && x==JSONB_FLOAT ){
+ if( j+3>k ) return j+1;
+ if( z[j+1]!='.' && z[j+1]!='e' && z[j+1]!='E' ) return j+1;
+ j++;
+ }
+ for(; j<k; j++){
+ if( sqlite3Isdigit(z[j]) ) continue;
+ if( z[j]=='.' ){
+ if( seen>0 ) return j+1;
+ if( x==JSONB_FLOAT && (j==k-1 || !sqlite3Isdigit(z[j+1])) ){
+ return j+1;
+ }
+ seen = 1;
+ continue;
+ }
+ if( z[j]=='e' || z[j]=='E' ){
+ if( seen==2 ) return j+1;
+ if( j==k-1 ) return j+1;
+ if( z[j+1]=='+' || z[j+1]=='-' ){
+ j++;
+ if( j==k-1 ) return j+1;
+ }
+ seen = 2;
+ continue;
+ }
+ return j+1;
+ }
+ if( seen==0 ) return i+1;
+ return 0;
+ }
+ case JSONB_TEXT: {
+ j = i+n;
+ k = j+sz;
+ while( j<k ){
+ if( !jsonIsOk[z[j]] && z[j]!='\'' ) return j+1;
+ j++;
+ }
+ return 0;
+ }
+ case JSONB_TEXTJ:
+ case JSONB_TEXT5: {
+ j = i+n;
+ k = j+sz;
+ while( j<k ){
+ if( !jsonIsOk[z[j]] && z[j]!='\'' ){
+ if( z[j]=='"' ){
+ if( x==JSONB_TEXTJ ) return j+1;
+ }else if( z[j]!='\\' || j+1>=k ){
+ return j+1;
+ }else if( strchr("\"\\/bfnrt",z[j+1])!=0 ){
+ j++;
+ }else if( z[j+1]=='u' ){
+ if( j+5>=k ) return j+1;
+ if( !jsonIs4Hex((const char*)&z[j+2]) ) return j+1;
+ j++;
+ }else if( x!=JSONB_TEXT5 ){
+ return j+1;
+ }else{
+ u32 c = 0;
+ u32 szC = jsonUnescapeOneChar((const char*)&z[j], k-j, &c);
+ if( c==JSON_INVALID_CHAR ) return j+1;
+ j += szC - 1;
+ }
+ }
+ j++;
+ }
+ return 0;
+ }
+ case JSONB_TEXTRAW: {
+ return 0;
+ }
+ case JSONB_ARRAY: {
+ u32 sub;
+ j = i+n;
+ k = j+sz;
+ while( j<k ){
+ sz = 0;
+ n = jsonbPayloadSize(pParse, j, &sz);
+ if( n==0 ) return j+1;
+ if( j+n+sz>k ) return j+1;
+ sub = jsonbValidityCheck(pParse, j, j+n+sz, iDepth+1);
+ if( sub ) return sub;
+ j += n + sz;
+ }
+ assert( j==k );
+ return 0;
+ }
+ case JSONB_OBJECT: {
+ u32 cnt = 0;
+ u32 sub;
+ j = i+n;
+ k = j+sz;
+ while( j<k ){
+ sz = 0;
+ n = jsonbPayloadSize(pParse, j, &sz);
+ if( n==0 ) return j+1;
+ if( j+n+sz>k ) return j+1;
+ if( (cnt & 1)==0 ){
+ x = z[j] & 0x0f;
+ if( x<JSONB_TEXT || x>JSONB_TEXTRAW ) return j+1;
+ }
+ sub = jsonbValidityCheck(pParse, j, j+n+sz, iDepth+1);
+ if( sub ) return sub;
+ cnt++;
+ j += n + sz;
+ }
+ assert( j==k );
+ if( (cnt & 1)!=0 ) return j+1;
+ return 0;
+ }
+ default: {
+ return i+1;
+ }
+ }
+}
+
+/*
+** Translate a single element of JSON text at pParse->zJson[i] into
+** its equivalent binary JSONB representation. Append the translation into
+** pParse->aBlob[] beginning at pParse->nBlob. The size of
+** pParse->aBlob[] is increased as necessary.
**
-** Return negative for a syntax error. Special cases: return -2 if the
-** first non-whitespace character is '}' and return -3 if the first
-** non-whitespace character is ']'.
+** Return the index of the first character past the end of the element parsed,
+** or one of the following special result codes:
+**
+** 0 End of input
+** -1 Syntax error or OOM
+** -2 '}' seen \
+** -3 ']' seen \___ For these returns, pParse->iErr is set to
+** -4 ',' seen / the index in zJson[] of the seen character
+** -5 ':' seen /
*/
-static int jsonParseValue(JsonParse *pParse, u32 i){
+static int jsonTranslateTextToBlob(JsonParse *pParse, u32 i){
char c;
u32 j;
- int iThis;
+ u32 iThis, iStart;
int x;
- JsonNode *pNode;
+ u8 t;
const char *z = pParse->zJson;
- while( fast_isspace(z[i]) ){ i++; }
- if( (c = z[i])=='{' ){
+json_parse_restart:
+ switch( (u8)z[i] ){
+ case '{': {
/* Parse object */
- iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
- if( iThis<0 ) return -1;
+ iThis = pParse->nBlob;
+ jsonBlobAppendNode(pParse, JSONB_OBJECT, pParse->nJson-i, 0);
+ if( ++pParse->iDepth > JSON_MAX_DEPTH ){
+ pParse->iErr = i;
+ return -1;
+ }
+ iStart = pParse->nBlob;
for(j=i+1;;j++){
- while( fast_isspace(z[j]) ){ j++; }
- if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
- x = jsonParseValue(pParse, j);
- if( x<0 ){
- pParse->iDepth--;
- if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1;
- return -1;
+ u32 iBlob = pParse->nBlob;
+ x = jsonTranslateTextToBlob(pParse, j);
+ if( x<=0 ){
+ int op;
+ if( x==(-2) ){
+ j = pParse->iErr;
+ if( pParse->nBlob!=(u32)iStart ) pParse->hasNonstd = 1;
+ break;
+ }
+ j += json5Whitespace(&z[j]);
+ op = JSONB_TEXT;
+ if( sqlite3JsonId1(z[j])
+ || (z[j]=='\\' && jsonIs4HexB(&z[j+1], &op))
+ ){
+ int k = j+1;
+ while( (sqlite3JsonId2(z[k]) && json5Whitespace(&z[k])==0)
+ || (z[k]=='\\' && jsonIs4HexB(&z[k+1], &op))
+ ){
+ k++;
+ }
+ assert( iBlob==pParse->nBlob );
+ jsonBlobAppendNode(pParse, op, k-j, &z[j]);
+ pParse->hasNonstd = 1;
+ x = k;
+ }else{
+ if( x!=-1 ) pParse->iErr = j;
+ return -1;
+ }
}
if( pParse->oom ) return -1;
- pNode = &pParse->aNode[pParse->nNode-1];
- if( pNode->eType!=JSON_STRING ) return -1;
- pNode->jnFlags |= JNODE_LABEL;
+ t = pParse->aBlob[iBlob] & 0x0f;
+ if( t<JSONB_TEXT || t>JSONB_TEXTRAW ){
+ pParse->iErr = j;
+ return -1;
+ }
j = x;
- while( fast_isspace(z[j]) ){ j++; }
- if( z[j]!=':' ) return -1;
- j++;
- x = jsonParseValue(pParse, j);
- pParse->iDepth--;
- if( x<0 ) return -1;
+ if( z[j]==':' ){
+ j++;
+ }else{
+ if( jsonIsspace(z[j]) ){
+ /* strspn() is not helpful here */
+ do{ j++; }while( jsonIsspace(z[j]) );
+ if( z[j]==':' ){
+ j++;
+ goto parse_object_value;
+ }
+ }
+ x = jsonTranslateTextToBlob(pParse, j);
+ if( x!=(-5) ){
+ if( x!=(-1) ) pParse->iErr = j;
+ return -1;
+ }
+ j = pParse->iErr+1;
+ }
+ parse_object_value:
+ x = jsonTranslateTextToBlob(pParse, j);
+ if( x<=0 ){
+ if( x!=(-1) ) pParse->iErr = j;
+ return -1;
+ }
j = x;
- while( fast_isspace(z[j]) ){ j++; }
- c = z[j];
- if( c==',' ) continue;
- if( c!='}' ) return -1;
- break;
+ if( z[j]==',' ){
+ continue;
+ }else if( z[j]=='}' ){
+ break;
+ }else{
+ if( jsonIsspace(z[j]) ){
+ j += 1 + (u32)strspn(&z[j+1], jsonSpaces);
+ if( z[j]==',' ){
+ continue;
+ }else if( z[j]=='}' ){
+ break;
+ }
+ }
+ x = jsonTranslateTextToBlob(pParse, j);
+ if( x==(-4) ){
+ j = pParse->iErr;
+ continue;
+ }
+ if( x==(-2) ){
+ j = pParse->iErr;
+ break;
+ }
+ }
+ pParse->iErr = j;
+ return -1;
}
- pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
+ jsonBlobChangePayloadSize(pParse, iThis, pParse->nBlob - iStart);
+ pParse->iDepth--;
return j+1;
- }else if( c=='[' ){
+ }
+ case '[': {
/* Parse array */
- iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
- if( iThis<0 ) return -1;
- memset(&pParse->aNode[iThis].u, 0, sizeof(pParse->aNode[iThis].u));
+ iThis = pParse->nBlob;
+ assert( i<=(u32)pParse->nJson );
+ jsonBlobAppendNode(pParse, JSONB_ARRAY, pParse->nJson - i, 0);
+ iStart = pParse->nBlob;
+ if( pParse->oom ) return -1;
+ if( ++pParse->iDepth > JSON_MAX_DEPTH ){
+ pParse->iErr = i;
+ return -1;
+ }
for(j=i+1;;j++){
- while( fast_isspace(z[j]) ){ j++; }
- if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
- x = jsonParseValue(pParse, j);
- pParse->iDepth--;
- if( x<0 ){
- if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1;
+ x = jsonTranslateTextToBlob(pParse, j);
+ if( x<=0 ){
+ if( x==(-3) ){
+ j = pParse->iErr;
+ if( pParse->nBlob!=iStart ) pParse->hasNonstd = 1;
+ break;
+ }
+ if( x!=(-1) ) pParse->iErr = j;
return -1;
}
j = x;
- while( fast_isspace(z[j]) ){ j++; }
- c = z[j];
- if( c==',' ) continue;
- if( c!=']' ) return -1;
- break;
+ if( z[j]==',' ){
+ continue;
+ }else if( z[j]==']' ){
+ break;
+ }else{
+ if( jsonIsspace(z[j]) ){
+ j += 1 + (u32)strspn(&z[j+1], jsonSpaces);
+ if( z[j]==',' ){
+ continue;
+ }else if( z[j]==']' ){
+ break;
+ }
+ }
+ x = jsonTranslateTextToBlob(pParse, j);
+ if( x==(-4) ){
+ j = pParse->iErr;
+ continue;
+ }
+ if( x==(-3) ){
+ j = pParse->iErr;
+ break;
+ }
+ }
+ pParse->iErr = j;
+ return -1;
}
- pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
+ jsonBlobChangePayloadSize(pParse, iThis, pParse->nBlob - iStart);
+ pParse->iDepth--;
return j+1;
- }else if( c=='"' ){
+ }
+ case '\'': {
+ u8 opcode;
+ char cDelim;
+ pParse->hasNonstd = 1;
+ opcode = JSONB_TEXT;
+ goto parse_string;
+ case '"':
/* Parse string */
- u8 jnFlags = 0;
+ opcode = JSONB_TEXT;
+ parse_string:
+ cDelim = z[i];
j = i+1;
- for(;;){
- c = z[j];
- if( (c & ~0x1f)==0 ){
- /* Control characters are not allowed in strings */
- return -1;
+ while( 1 /*exit-by-break*/ ){
+ if( jsonIsOk[(u8)z[j]] ){
+ if( !jsonIsOk[(u8)z[j+1]] ){
+ j += 1;
+ }else if( !jsonIsOk[(u8)z[j+2]] ){
+ j += 2;
+ }else{
+ j += 3;
+ continue;
+ }
}
- if( c=='\\' ){
+ c = z[j];
+ if( c==cDelim ){
+ break;
+ }else if( c=='\\' ){
c = z[++j];
if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
|| c=='n' || c=='r' || c=='t'
- || (c=='u' && jsonIs4Hex(z+j+1)) ){
- jnFlags = JNODE_ESCAPE;
+ || (c=='u' && jsonIs4Hex(&z[j+1])) ){
+ if( opcode==JSONB_TEXT ) opcode = JSONB_TEXTJ;
+ }else if( c=='\'' || c=='0' || c=='v' || c=='\n'
+ || (0xe2==(u8)c && 0x80==(u8)z[j+1]
+ && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2]))
+ || (c=='x' && jsonIs2Hex(&z[j+1])) ){
+ opcode = JSONB_TEXT5;
+ pParse->hasNonstd = 1;
+ }else if( c=='\r' ){
+ if( z[j+1]=='\n' ) j++;
+ opcode = JSONB_TEXT5;
+ pParse->hasNonstd = 1;
}else{
+ pParse->iErr = j;
return -1;
}
+ }else if( c<=0x1f ){
+ /* Control characters are not allowed in strings */
+ pParse->iErr = j;
+ return -1;
}else if( c=='"' ){
- break;
+ opcode = JSONB_TEXT5;
}
j++;
}
- jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]);
- if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags;
+ jsonBlobAppendNode(pParse, opcode, j-1-i, &z[i+1]);
return j+1;
- }else if( c=='n'
- && strncmp(z+i,"null",4)==0
- && !sqlite3Isalnum(z[i+4]) ){
- jsonParseAddNode(pParse, JSON_NULL, 0, 0);
- return i+4;
- }else if( c=='t'
- && strncmp(z+i,"true",4)==0
- && !sqlite3Isalnum(z[i+4]) ){
- jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
- return i+4;
- }else if( c=='f'
- && strncmp(z+i,"false",5)==0
- && !sqlite3Isalnum(z[i+5]) ){
- jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
- return i+5;
- }else if( c=='-' || (c>='0' && c<='9') ){
+ }
+ case 't': {
+ if( strncmp(z+i,"true",4)==0 && !sqlite3Isalnum(z[i+4]) ){
+ jsonBlobAppendOneByte(pParse, JSONB_TRUE);
+ return i+4;
+ }
+ pParse->iErr = i;
+ return -1;
+ }
+ case 'f': {
+ if( strncmp(z+i,"false",5)==0 && !sqlite3Isalnum(z[i+5]) ){
+ jsonBlobAppendOneByte(pParse, JSONB_FALSE);
+ return i+5;
+ }
+ pParse->iErr = i;
+ return -1;
+ }
+ case '+': {
+ u8 seenE;
+ pParse->hasNonstd = 1;
+ t = 0x00; /* Bit 0x01: JSON5. Bit 0x02: FLOAT */
+ goto parse_number;
+ case '.':
+ if( sqlite3Isdigit(z[i+1]) ){
+ pParse->hasNonstd = 1;
+ t = 0x03; /* Bit 0x01: JSON5. Bit 0x02: FLOAT */
+ seenE = 0;
+ goto parse_number_2;
+ }
+ pParse->iErr = i;
+ return -1;
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
/* Parse number */
- u8 seenDP = 0;
- u8 seenE = 0;
+ t = 0x00; /* Bit 0x01: JSON5. Bit 0x02: FLOAT */
+ parse_number:
+ seenE = 0;
assert( '-' < '0' );
+ assert( '+' < '0' );
+ assert( '.' < '0' );
+ c = z[i];
+
if( c<='0' ){
- j = c=='-' ? i+1 : i;
- if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1;
+ if( c=='0' ){
+ if( (z[i+1]=='x' || z[i+1]=='X') && sqlite3Isxdigit(z[i+2]) ){
+ assert( t==0x00 );
+ pParse->hasNonstd = 1;
+ t = 0x01;
+ for(j=i+3; sqlite3Isxdigit(z[j]); j++){}
+ goto parse_number_finish;
+ }else if( sqlite3Isdigit(z[i+1]) ){
+ pParse->iErr = i+1;
+ return -1;
+ }
+ }else{
+ if( !sqlite3Isdigit(z[i+1]) ){
+ /* JSON5 allows for "+Infinity" and "-Infinity" using exactly
+ ** that case. SQLite also allows these in any case and it allows
+ ** "+inf" and "-inf". */
+ if( (z[i+1]=='I' || z[i+1]=='i')
+ && sqlite3StrNICmp(&z[i+1], "inf",3)==0
+ ){
+ pParse->hasNonstd = 1;
+ if( z[i]=='-' ){
+ jsonBlobAppendNode(pParse, JSONB_FLOAT, 6, "-9e999");
+ }else{
+ jsonBlobAppendNode(pParse, JSONB_FLOAT, 5, "9e999");
+ }
+ return i + (sqlite3StrNICmp(&z[i+4],"inity",5)==0 ? 9 : 4);
+ }
+ if( z[i+1]=='.' ){
+ pParse->hasNonstd = 1;
+ t |= 0x01;
+ goto parse_number_2;
+ }
+ pParse->iErr = i;
+ return -1;
+ }
+ if( z[i+1]=='0' ){
+ if( sqlite3Isdigit(z[i+2]) ){
+ pParse->iErr = i+1;
+ return -1;
+ }else if( (z[i+2]=='x' || z[i+2]=='X') && sqlite3Isxdigit(z[i+3]) ){
+ pParse->hasNonstd = 1;
+ t |= 0x01;
+ for(j=i+4; sqlite3Isxdigit(z[j]); j++){}
+ goto parse_number_finish;
+ }
+ }
+ }
}
- j = i+1;
- for(;; j++){
+
+ parse_number_2:
+ for(j=i+1;; j++){
c = z[j];
- if( c>='0' && c<='9' ) continue;
+ if( sqlite3Isdigit(c) ) continue;
if( c=='.' ){
- if( z[j-1]=='-' ) return -1;
- if( seenDP ) return -1;
- seenDP = 1;
+ if( (t & 0x02)!=0 ){
+ pParse->iErr = j;
+ return -1;
+ }
+ t |= 0x02;
continue;
}
if( c=='e' || c=='E' ){
- if( z[j-1]<'0' ) return -1;
- if( seenE ) return -1;
- seenDP = seenE = 1;
+ if( z[j-1]<'0' ){
+ if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){
+ pParse->hasNonstd = 1;
+ t |= 0x01;
+ }else{
+ pParse->iErr = j;
+ return -1;
+ }
+ }
+ if( seenE ){
+ pParse->iErr = j;
+ return -1;
+ }
+ t |= 0x02;
+ seenE = 1;
c = z[j+1];
if( c=='+' || c=='-' ){
j++;
c = z[j+1];
}
- if( c<'0' || c>'9' ) return -1;
+ if( c<'0' || c>'9' ){
+ pParse->iErr = j;
+ return -1;
+ }
continue;
}
break;
}
- if( z[j-1]<'0' ) return -1;
- jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT,
- j - i, &z[i]);
+ if( z[j-1]<'0' ){
+ if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){
+ pParse->hasNonstd = 1;
+ t |= 0x01;
+ }else{
+ pParse->iErr = j;
+ return -1;
+ }
+ }
+ parse_number_finish:
+ assert( JSONB_INT+0x01==JSONB_INT5 );
+ assert( JSONB_FLOAT+0x01==JSONB_FLOAT5 );
+ assert( JSONB_INT+0x02==JSONB_FLOAT );
+ if( z[i]=='+' ) i++;
+ jsonBlobAppendNode(pParse, JSONB_INT+t, j-i, &z[i]);
return j;
- }else if( c=='}' ){
+ }
+ case '}': {
+ pParse->iErr = i;
return -2; /* End of {...} */
- }else if( c==']' ){
+ }
+ case ']': {
+ pParse->iErr = i;
return -3; /* End of [...] */
- }else if( c==0 ){
+ }
+ case ',': {
+ pParse->iErr = i;
+ return -4; /* List separator */
+ }
+ case ':': {
+ pParse->iErr = i;
+ return -5; /* Object label/value separator */
+ }
+ case 0: {
return 0; /* End of file */
- }else{
+ }
+ case 0x09:
+ case 0x0a:
+ case 0x0d:
+ case 0x20: {
+ i += 1 + (u32)strspn(&z[i+1], jsonSpaces);
+ goto json_parse_restart;
+ }
+ case 0x0b:
+ case 0x0c:
+ case '/':
+ case 0xc2:
+ case 0xe1:
+ case 0xe2:
+ case 0xe3:
+ case 0xef: {
+ j = json5Whitespace(&z[i]);
+ if( j>0 ){
+ i += j;
+ pParse->hasNonstd = 1;
+ goto json_parse_restart;
+ }
+ pParse->iErr = i;
+ return -1;
+ }
+ case 'n': {
+ if( strncmp(z+i,"null",4)==0 && !sqlite3Isalnum(z[i+4]) ){
+ jsonBlobAppendOneByte(pParse, JSONB_NULL);
+ return i+4;
+ }
+ /* fall-through into the default case that checks for NaN */
+ }
+ default: {
+ u32 k;
+ int nn;
+ c = z[i];
+ for(k=0; k<sizeof(aNanInfName)/sizeof(aNanInfName[0]); k++){
+ if( c!=aNanInfName[k].c1 && c!=aNanInfName[k].c2 ) continue;
+ nn = aNanInfName[k].n;
+ if( sqlite3StrNICmp(&z[i], aNanInfName[k].zMatch, nn)!=0 ){
+ continue;
+ }
+ if( sqlite3Isalnum(z[i+nn]) ) continue;
+ if( aNanInfName[k].eType==JSONB_FLOAT ){
+ jsonBlobAppendNode(pParse, JSONB_FLOAT, 5, "9e999");
+ }else{
+ jsonBlobAppendOneByte(pParse, JSONB_NULL);
+ }
+ pParse->hasNonstd = 1;
+ return i + nn;
+ }
+ pParse->iErr = i;
return -1; /* Syntax error */
}
+ } /* End switch(z[i]) */
}
+
/*
** Parse a complete JSON string. Return 0 on success or non-zero if there
-** are any errors. If an error occurs, free all memory associated with
-** pParse.
+** are any errors. If an error occurs, free all memory held by pParse,
+** but not pParse itself.
**
-** pParse is uninitialized when this routine is called.
+** pParse must be initialized to an empty parse object prior to calling
+** this routine.
*/
-static int jsonParse(
+static int jsonConvertTextToBlob(
JsonParse *pParse, /* Initialize and fill this JsonParse object */
- sqlite3_context *pCtx, /* Report errors here */
- const char *zJson /* Input JSON text to be parsed */
+ sqlite3_context *pCtx /* Report errors here */
){
int i;
- memset(pParse, 0, sizeof(*pParse));
- if( zJson==0 ) return 1;
- pParse->zJson = zJson;
- i = jsonParseValue(pParse, 0);
+ const char *zJson = pParse->zJson;
+ i = jsonTranslateTextToBlob(pParse, 0);
if( pParse->oom ) i = -1;
if( i>0 ){
+#ifdef SQLITE_DEBUG
assert( pParse->iDepth==0 );
- while( fast_isspace(zJson[i]) ) i++;
- if( zJson[i] ) i = -1;
+ if( sqlite3Config.bJsonSelfcheck ){
+ assert( jsonbValidityCheck(pParse, 0, pParse->nBlob, 0)==0 );
+ }
+#endif
+ while( jsonIsspace(zJson[i]) ) i++;
+ if( zJson[i] ){
+ i += json5Whitespace(&zJson[i]);
+ if( zJson[i] ){
+ if( pCtx ) sqlite3_result_error(pCtx, "malformed JSON", -1);
+ jsonParseReset(pParse);
+ return 1;
+ }
+ pParse->hasNonstd = 1;
+ }
}
if( i<=0 ){
if( pCtx!=0 ){
@@ -199718,161 +205407,719 @@ static int jsonParse(
return 0;
}
-/* Mark node i of pParse as being a child of iParent. Call recursively
-** to fill in all the descendants of node i.
+/*
+** The input string pStr is a well-formed JSON text string. Convert
+** this into the JSONB format and make it the return value of the
+** SQL function.
*/
-static void jsonParseFillInParentage(JsonParse *pParse, u32 i, u32 iParent){
- JsonNode *pNode = &pParse->aNode[i];
- u32 j;
- pParse->aUp[i] = iParent;
- switch( pNode->eType ){
- case JSON_ARRAY: {
- for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j)){
- jsonParseFillInParentage(pParse, i+j, i);
+static void jsonReturnStringAsBlob(JsonString *pStr){
+ JsonParse px;
+ memset(&px, 0, sizeof(px));
+ jsonStringTerminate(pStr);
+ if( pStr->eErr ){
+ sqlite3_result_error_nomem(pStr->pCtx);
+ return;
+ }
+ px.zJson = pStr->zBuf;
+ px.nJson = pStr->nUsed;
+ px.db = sqlite3_context_db_handle(pStr->pCtx);
+ (void)jsonTranslateTextToBlob(&px, 0);
+ if( px.oom ){
+ sqlite3DbFree(px.db, px.aBlob);
+ sqlite3_result_error_nomem(pStr->pCtx);
+ }else{
+ assert( px.nBlobAlloc>0 );
+ assert( !px.bReadOnly );
+ sqlite3_result_blob(pStr->pCtx, px.aBlob, px.nBlob, SQLITE_DYNAMIC);
+ }
+}
+
+/* The byte at index i is a node type-code. This routine
+** determines the payload size for that node and writes that
+** payload size in to *pSz. It returns the offset from i to the
+** beginning of the payload. Return 0 on error.
+*/
+static u32 jsonbPayloadSize(const JsonParse *pParse, u32 i, u32 *pSz){
+ u8 x;
+ u32 sz;
+ u32 n;
+ if( NEVER(i>pParse->nBlob) ){
+ *pSz = 0;
+ return 0;
+ }
+ x = pParse->aBlob[i]>>4;
+ if( x<=11 ){
+ sz = x;
+ n = 1;
+ }else if( x==12 ){
+ if( i+1>=pParse->nBlob ){
+ *pSz = 0;
+ return 0;
+ }
+ sz = pParse->aBlob[i+1];
+ n = 2;
+ }else if( x==13 ){
+ if( i+2>=pParse->nBlob ){
+ *pSz = 0;
+ return 0;
+ }
+ sz = (pParse->aBlob[i+1]<<8) + pParse->aBlob[i+2];
+ n = 3;
+ }else if( x==14 ){
+ if( i+4>=pParse->nBlob ){
+ *pSz = 0;
+ return 0;
+ }
+ sz = ((u32)pParse->aBlob[i+1]<<24) + (pParse->aBlob[i+2]<<16) +
+ (pParse->aBlob[i+3]<<8) + pParse->aBlob[i+4];
+ n = 5;
+ }else{
+ if( i+8>=pParse->nBlob
+ || pParse->aBlob[i+1]!=0
+ || pParse->aBlob[i+2]!=0
+ || pParse->aBlob[i+3]!=0
+ || pParse->aBlob[i+4]!=0
+ ){
+ *pSz = 0;
+ return 0;
+ }
+ sz = (pParse->aBlob[i+5]<<24) + (pParse->aBlob[i+6]<<16) +
+ (pParse->aBlob[i+7]<<8) + pParse->aBlob[i+8];
+ n = 9;
+ }
+ if( (i64)i+sz+n > pParse->nBlob
+ && (i64)i+sz+n > pParse->nBlob-pParse->delta
+ ){
+ sz = 0;
+ n = 0;
+ }
+ *pSz = sz;
+ return n;
+}
+
+
+/*
+** Translate the binary JSONB representation of JSON beginning at
+** pParse->aBlob[i] into a JSON text string. Append the JSON
+** text onto the end of pOut. Return the index in pParse->aBlob[]
+** of the first byte past the end of the element that is translated.
+**
+** If an error is detected in the BLOB input, the pOut->eErr flag
+** might get set to JSTRING_MALFORMED. But not all BLOB input errors
+** are detected. So a malformed JSONB input might either result
+** in an error, or in incorrect JSON.
+**
+** The pOut->eErr JSTRING_OOM flag is set on a OOM.
+*/
+static u32 jsonTranslateBlobToText(
+ const JsonParse *pParse, /* the complete parse of the JSON */
+ u32 i, /* Start rendering at this index */
+ JsonString *pOut /* Write JSON here */
+){
+ u32 sz, n, j, iEnd;
+
+ n = jsonbPayloadSize(pParse, i, &sz);
+ if( n==0 ){
+ pOut->eErr |= JSTRING_MALFORMED;
+ return pParse->nBlob+1;
+ }
+ switch( pParse->aBlob[i] & 0x0f ){
+ case JSONB_NULL: {
+ jsonAppendRawNZ(pOut, "null", 4);
+ return i+1;
+ }
+ case JSONB_TRUE: {
+ jsonAppendRawNZ(pOut, "true", 4);
+ return i+1;
+ }
+ case JSONB_FALSE: {
+ jsonAppendRawNZ(pOut, "false", 5);
+ return i+1;
+ }
+ case JSONB_INT:
+ case JSONB_FLOAT: {
+ if( sz==0 ) goto malformed_jsonb;
+ jsonAppendRaw(pOut, (const char*)&pParse->aBlob[i+n], sz);
+ break;
+ }
+ case JSONB_INT5: { /* Integer literal in hexadecimal notation */
+ u32 k = 2;
+ sqlite3_uint64 u = 0;
+ const char *zIn = (const char*)&pParse->aBlob[i+n];
+ int bOverflow = 0;
+ if( sz==0 ) goto malformed_jsonb;
+ if( zIn[0]=='-' ){
+ jsonAppendChar(pOut, '-');
+ k++;
+ }else if( zIn[0]=='+' ){
+ k++;
+ }
+ for(; k<sz; k++){
+ if( !sqlite3Isxdigit(zIn[k]) ){
+ pOut->eErr |= JSTRING_MALFORMED;
+ break;
+ }else if( (u>>60)!=0 ){
+ bOverflow = 1;
+ }else{
+ u = u*16 + sqlite3HexToInt(zIn[k]);
+ }
+ }
+ jsonPrintf(100,pOut,bOverflow?"9.0e999":"%llu", u);
+ break;
+ }
+ case JSONB_FLOAT5: { /* Float literal missing digits beside "." */
+ u32 k = 0;
+ const char *zIn = (const char*)&pParse->aBlob[i+n];
+ if( sz==0 ) goto malformed_jsonb;
+ if( zIn[0]=='-' ){
+ jsonAppendChar(pOut, '-');
+ k++;
+ }
+ if( zIn[k]=='.' ){
+ jsonAppendChar(pOut, '0');
+ }
+ for(; k<sz; k++){
+ jsonAppendChar(pOut, zIn[k]);
+ if( zIn[k]=='.' && (k+1==sz || !sqlite3Isdigit(zIn[k+1])) ){
+ jsonAppendChar(pOut, '0');
+ }
}
break;
}
- case JSON_OBJECT: {
- for(j=1; j<=pNode->n; j += jsonNodeSize(pNode+j+1)+1){
- pParse->aUp[i+j] = i;
- jsonParseFillInParentage(pParse, i+j+1, i);
+ case JSONB_TEXT:
+ case JSONB_TEXTJ: {
+ jsonAppendChar(pOut, '"');
+ jsonAppendRaw(pOut, (const char*)&pParse->aBlob[i+n], sz);
+ jsonAppendChar(pOut, '"');
+ break;
+ }
+ case JSONB_TEXT5: {
+ const char *zIn;
+ u32 k;
+ u32 sz2 = sz;
+ zIn = (const char*)&pParse->aBlob[i+n];
+ jsonAppendChar(pOut, '"');
+ while( sz2>0 ){
+ for(k=0; k<sz2 && zIn[k]!='\\' && zIn[k]!='"'; k++){}
+ if( k>0 ){
+ jsonAppendRawNZ(pOut, zIn, k);
+ if( k>=sz2 ){
+ break;
+ }
+ zIn += k;
+ sz2 -= k;
+ }
+ if( zIn[0]=='"' ){
+ jsonAppendRawNZ(pOut, "\\\"", 2);
+ zIn++;
+ sz2--;
+ continue;
+ }
+ assert( zIn[0]=='\\' );
+ assert( sz2>=1 );
+ if( sz2<2 ){
+ pOut->eErr |= JSTRING_MALFORMED;
+ break;
+ }
+ switch( (u8)zIn[1] ){
+ case '\'':
+ jsonAppendChar(pOut, '\'');
+ break;
+ case 'v':
+ jsonAppendRawNZ(pOut, "\\u0009", 6);
+ break;
+ case 'x':
+ if( sz2<4 ){
+ pOut->eErr |= JSTRING_MALFORMED;
+ sz2 = 2;
+ break;
+ }
+ jsonAppendRawNZ(pOut, "\\u00", 4);
+ jsonAppendRawNZ(pOut, &zIn[2], 2);
+ zIn += 2;
+ sz2 -= 2;
+ break;
+ case '0':
+ jsonAppendRawNZ(pOut, "\\u0000", 6);
+ break;
+ case '\r':
+ if( sz2>2 && zIn[2]=='\n' ){
+ zIn++;
+ sz2--;
+ }
+ break;
+ case '\n':
+ break;
+ case 0xe2:
+ /* '\' followed by either U+2028 or U+2029 is ignored as
+ ** whitespace. Not that in UTF8, U+2028 is 0xe2 0x80 0x29.
+ ** U+2029 is the same except for the last byte */
+ if( sz2<4
+ || 0x80!=(u8)zIn[2]
+ || (0xa8!=(u8)zIn[3] && 0xa9!=(u8)zIn[3])
+ ){
+ pOut->eErr |= JSTRING_MALFORMED;
+ sz2 = 2;
+ break;
+ }
+ zIn += 2;
+ sz2 -= 2;
+ break;
+ default:
+ jsonAppendRawNZ(pOut, zIn, 2);
+ break;
+ }
+ assert( sz2>=2 );
+ zIn += 2;
+ sz2 -= 2;
}
+ jsonAppendChar(pOut, '"');
break;
}
+ case JSONB_TEXTRAW: {
+ jsonAppendString(pOut, (const char*)&pParse->aBlob[i+n], sz);
+ break;
+ }
+ case JSONB_ARRAY: {
+ jsonAppendChar(pOut, '[');
+ j = i+n;
+ iEnd = j+sz;
+ while( j<iEnd && pOut->eErr==0 ){
+ j = jsonTranslateBlobToText(pParse, j, pOut);
+ jsonAppendChar(pOut, ',');
+ }
+ if( j>iEnd ) pOut->eErr |= JSTRING_MALFORMED;
+ if( sz>0 ) jsonStringTrimOneChar(pOut);
+ jsonAppendChar(pOut, ']');
+ break;
+ }
+ case JSONB_OBJECT: {
+ int x = 0;
+ jsonAppendChar(pOut, '{');
+ j = i+n;
+ iEnd = j+sz;
+ while( j<iEnd && pOut->eErr==0 ){
+ j = jsonTranslateBlobToText(pParse, j, pOut);
+ jsonAppendChar(pOut, (x++ & 1) ? ',' : ':');
+ }
+ if( (x & 1)!=0 || j>iEnd ) pOut->eErr |= JSTRING_MALFORMED;
+ if( sz>0 ) jsonStringTrimOneChar(pOut);
+ jsonAppendChar(pOut, '}');
+ break;
+ }
+
default: {
+ malformed_jsonb:
+ pOut->eErr |= JSTRING_MALFORMED;
break;
}
}
+ return i+n+sz;
+}
+
+/* Return true if the input pJson
+**
+** For performance reasons, this routine does not do a detailed check of the
+** input BLOB to ensure that it is well-formed. Hence, false positives are
+** possible. False negatives should never occur, however.
+*/
+static int jsonFuncArgMightBeBinary(sqlite3_value *pJson){
+ u32 sz, n;
+ const u8 *aBlob;
+ int nBlob;
+ JsonParse s;
+ if( sqlite3_value_type(pJson)!=SQLITE_BLOB ) return 0;
+ aBlob = sqlite3_value_blob(pJson);
+ nBlob = sqlite3_value_bytes(pJson);
+ if( nBlob<1 ) return 0;
+ if( NEVER(aBlob==0) || (aBlob[0] & 0x0f)>JSONB_OBJECT ) return 0;
+ memset(&s, 0, sizeof(s));
+ s.aBlob = (u8*)aBlob;
+ s.nBlob = nBlob;
+ n = jsonbPayloadSize(&s, 0, &sz);
+ if( n==0 ) return 0;
+ if( sz+n!=(u32)nBlob ) return 0;
+ if( (aBlob[0] & 0x0f)<=JSONB_FALSE && sz>0 ) return 0;
+ return sz+n==(u32)nBlob;
}
/*
-** Compute the parentage of all nodes in a completed parse.
+** Given that a JSONB_ARRAY object starts at offset i, return
+** the number of entries in that array.
*/
-static int jsonParseFindParents(JsonParse *pParse){
- u32 *aUp;
- assert( pParse->aUp==0 );
- aUp = pParse->aUp = sqlite3_malloc64( sizeof(u32)*pParse->nNode );
- if( aUp==0 ){
- pParse->oom = 1;
- return SQLITE_NOMEM;
+static u32 jsonbArrayCount(JsonParse *pParse, u32 iRoot){
+ u32 n, sz, i, iEnd;
+ u32 k = 0;
+ n = jsonbPayloadSize(pParse, iRoot, &sz);
+ iEnd = iRoot+n+sz;
+ for(i=iRoot+n; n>0 && i<iEnd; i+=sz+n, k++){
+ n = jsonbPayloadSize(pParse, i, &sz);
}
- jsonParseFillInParentage(pParse, 0, 0);
- return SQLITE_OK;
+ return k;
}
/*
-** Magic number used for the JSON parse cache in sqlite3_get_auxdata()
+** Edit the payload size of the element at iRoot by the amount in
+** pParse->delta.
*/
-#define JSON_CACHE_ID (-429938) /* First cache entry */
-#define JSON_CACHE_SZ 4 /* Max number of cache entries */
+static void jsonAfterEditSizeAdjust(JsonParse *pParse, u32 iRoot){
+ u32 sz = 0;
+ u32 nBlob;
+ assert( pParse->delta!=0 );
+ assert( pParse->nBlobAlloc >= pParse->nBlob );
+ nBlob = pParse->nBlob;
+ pParse->nBlob = pParse->nBlobAlloc;
+ (void)jsonbPayloadSize(pParse, iRoot, &sz);
+ pParse->nBlob = nBlob;
+ sz += pParse->delta;
+ pParse->delta += jsonBlobChangePayloadSize(pParse, iRoot, sz);
+}
/*
-** Obtain a complete parse of the JSON found in the first argument
-** of the argv array. Use the sqlite3_get_auxdata() cache for this
-** parse if it is available. If the cache is not available or if it
-** is no longer valid, parse the JSON again and return the new parse,
-** and also register the new parse so that it will be available for
-** future sqlite3_get_auxdata() calls.
+** Modify the JSONB blob at pParse->aBlob by removing nDel bytes of
+** content beginning at iDel, and replacing them with nIns bytes of
+** content given by aIns.
+**
+** nDel may be zero, in which case no bytes are removed. But iDel is
+** still important as new bytes will be insert beginning at iDel.
+**
+** aIns may be zero, in which case space is created to hold nIns bytes
+** beginning at iDel, but that space is uninitialized.
+**
+** Set pParse->oom if an OOM occurs.
*/
-static JsonParse *jsonParseCached(
- sqlite3_context *pCtx,
- sqlite3_value **argv,
- sqlite3_context *pErrCtx
+static void jsonBlobEdit(
+ JsonParse *pParse, /* The JSONB to be modified is in pParse->aBlob */
+ u32 iDel, /* First byte to be removed */
+ u32 nDel, /* Number of bytes to remove */
+ const u8 *aIns, /* Content to insert */
+ u32 nIns /* Bytes of content to insert */
){
- const char *zJson = (const char*)sqlite3_value_text(argv[0]);
- int nJson = sqlite3_value_bytes(argv[0]);
- JsonParse *p;
- JsonParse *pMatch = 0;
- int iKey;
- int iMinKey = 0;
- u32 iMinHold = 0xffffffff;
- u32 iMaxHold = 0;
- if( zJson==0 ) return 0;
- for(iKey=0; iKey<JSON_CACHE_SZ; iKey++){
- p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iKey);
- if( p==0 ){
- iMinKey = iKey;
- break;
+ i64 d = (i64)nIns - (i64)nDel;
+ if( d!=0 ){
+ if( pParse->nBlob + d > pParse->nBlobAlloc ){
+ jsonBlobExpand(pParse, pParse->nBlob+d);
+ if( pParse->oom ) return;
}
- if( pMatch==0
- && p->nJson==nJson
- && memcmp(p->zJson,zJson,nJson)==0
- ){
- p->nErr = 0;
- pMatch = p;
- }else if( p->iHold<iMinHold ){
- iMinHold = p->iHold;
- iMinKey = iKey;
+ memmove(&pParse->aBlob[iDel+nIns],
+ &pParse->aBlob[iDel+nDel],
+ pParse->nBlob - (iDel+nDel));
+ pParse->nBlob += d;
+ pParse->delta += d;
+ }
+ if( nIns && aIns ) memcpy(&pParse->aBlob[iDel], aIns, nIns);
+}
+
+/*
+** Return the number of escaped newlines to be ignored.
+** An escaped newline is a one of the following byte sequences:
+**
+** 0x5c 0x0a
+** 0x5c 0x0d
+** 0x5c 0x0d 0x0a
+** 0x5c 0xe2 0x80 0xa8
+** 0x5c 0xe2 0x80 0xa9
+*/
+static u32 jsonBytesToBypass(const char *z, u32 n){
+ u32 i = 0;
+ while( i+1<n ){
+ if( z[i]!='\\' ) return i;
+ if( z[i+1]=='\n' ){
+ i += 2;
+ continue;
}
- if( p->iHold>iMaxHold ){
- iMaxHold = p->iHold;
+ if( z[i+1]=='\r' ){
+ if( i+2<n && z[i+2]=='\n' ){
+ i += 3;
+ }else{
+ i += 2;
+ }
+ continue;
}
+ if( 0xe2==(u8)z[i+1]
+ && i+3<n
+ && 0x80==(u8)z[i+2]
+ && (0xa8==(u8)z[i+3] || 0xa9==(u8)z[i+3])
+ ){
+ i += 4;
+ continue;
+ }
+ break;
}
- if( pMatch ){
- pMatch->nErr = 0;
- pMatch->iHold = iMaxHold+1;
- return pMatch;
+ return i;
+}
+
+/*
+** Input z[0..n] defines JSON escape sequence including the leading '\\'.
+** Decode that escape sequence into a single character. Write that
+** character into *piOut. Return the number of bytes in the escape sequence.
+**
+** If there is a syntax error of some kind (for example too few characters
+** after the '\\' to complete the encoding) then *piOut is set to
+** JSON_INVALID_CHAR.
+*/
+static u32 jsonUnescapeOneChar(const char *z, u32 n, u32 *piOut){
+ assert( n>0 );
+ assert( z[0]=='\\' );
+ if( n<2 ){
+ *piOut = JSON_INVALID_CHAR;
+ return n;
}
- p = sqlite3_malloc64( sizeof(*p) + nJson + 1 );
- if( p==0 ){
- sqlite3_result_error_nomem(pCtx);
- return 0;
+ switch( (u8)z[1] ){
+ case 'u': {
+ u32 v, vlo;
+ if( n<6 ){
+ *piOut = JSON_INVALID_CHAR;
+ return n;
+ }
+ v = jsonHexToInt4(&z[2]);
+ if( (v & 0xfc00)==0xd800
+ && n>=12
+ && z[6]=='\\'
+ && z[7]=='u'
+ && ((vlo = jsonHexToInt4(&z[8]))&0xfc00)==0xdc00
+ ){
+ *piOut = ((v&0x3ff)<<10) + (vlo&0x3ff) + 0x10000;
+ return 12;
+ }else{
+ *piOut = v;
+ return 6;
+ }
+ }
+ case 'b': { *piOut = '\b'; return 2; }
+ case 'f': { *piOut = '\f'; return 2; }
+ case 'n': { *piOut = '\n'; return 2; }
+ case 'r': { *piOut = '\r'; return 2; }
+ case 't': { *piOut = '\t'; return 2; }
+ case 'v': { *piOut = '\v'; return 2; }
+ case '0': { *piOut = 0; return 2; }
+ case '\'':
+ case '"':
+ case '/':
+ case '\\':{ *piOut = z[1]; return 2; }
+ case 'x': {
+ if( n<4 ){
+ *piOut = JSON_INVALID_CHAR;
+ return n;
+ }
+ *piOut = (jsonHexToInt(z[2])<<4) | jsonHexToInt(z[3]);
+ return 4;
+ }
+ case 0xe2:
+ case '\r':
+ case '\n': {
+ u32 nSkip = jsonBytesToBypass(z, n);
+ if( nSkip==0 ){
+ *piOut = JSON_INVALID_CHAR;
+ return n;
+ }else if( nSkip==n ){
+ *piOut = 0;
+ return n;
+ }else if( z[nSkip]=='\\' ){
+ return nSkip + jsonUnescapeOneChar(&z[nSkip], n-nSkip, piOut);
+ }else{
+ int sz = sqlite3Utf8ReadLimited((u8*)&z[nSkip], n-nSkip, piOut);
+ return nSkip + sz;
+ }
+ }
+ default: {
+ *piOut = JSON_INVALID_CHAR;
+ return 2;
+ }
}
- memset(p, 0, sizeof(*p));
- p->zJson = (char*)&p[1];
- memcpy((char*)p->zJson, zJson, nJson+1);
- if( jsonParse(p, pErrCtx, p->zJson) ){
- sqlite3_free(p);
- return 0;
+}
+
+
+/*
+** Compare two object labels. Return 1 if they are equal and
+** 0 if they differ.
+**
+** In this version, we know that one or the other or both of the
+** two comparands contains an escape sequence.
+*/
+static SQLITE_NOINLINE int jsonLabelCompareEscaped(
+ const char *zLeft, /* The left label */
+ u32 nLeft, /* Size of the left label in bytes */
+ int rawLeft, /* True if zLeft contains no escapes */
+ const char *zRight, /* The right label */
+ u32 nRight, /* Size of the right label in bytes */
+ int rawRight /* True if zRight is escape-free */
+){
+ u32 cLeft, cRight;
+ assert( rawLeft==0 || rawRight==0 );
+ while( 1 /*exit-by-return*/ ){
+ if( nLeft==0 ){
+ cLeft = 0;
+ }else if( rawLeft || zLeft[0]!='\\' ){
+ cLeft = ((u8*)zLeft)[0];
+ if( cLeft>=0xc0 ){
+ int sz = sqlite3Utf8ReadLimited((u8*)zLeft, nLeft, &cLeft);
+ zLeft += sz;
+ nLeft -= sz;
+ }else{
+ zLeft++;
+ nLeft--;
+ }
+ }else{
+ u32 n = jsonUnescapeOneChar(zLeft, nLeft, &cLeft);
+ zLeft += n;
+ assert( n<=nLeft );
+ nLeft -= n;
+ }
+ if( nRight==0 ){
+ cRight = 0;
+ }else if( rawRight || zRight[0]!='\\' ){
+ cRight = ((u8*)zRight)[0];
+ if( cRight>=0xc0 ){
+ int sz = sqlite3Utf8ReadLimited((u8*)zRight, nRight, &cRight);
+ zRight += sz;
+ nRight -= sz;
+ }else{
+ zRight++;
+ nRight--;
+ }
+ }else{
+ u32 n = jsonUnescapeOneChar(zRight, nRight, &cRight);
+ zRight += n;
+ assert( n<=nRight );
+ nRight -= n;
+ }
+ if( cLeft!=cRight ) return 0;
+ if( cLeft==0 ) return 1;
}
- p->nJson = nJson;
- p->iHold = iMaxHold+1;
- sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p,
- (void(*)(void*))jsonParseFree);
- return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey);
}
/*
-** Compare the OBJECT label at pNode against zKey,nKey. Return true on
-** a match.
+** Compare two object labels. Return 1 if they are equal and
+** 0 if they differ. Return -1 if an OOM occurs.
*/
-static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){
- assert( pNode->eU==1 );
- if( pNode->jnFlags & JNODE_RAW ){
- if( pNode->n!=nKey ) return 0;
- return strncmp(pNode->u.zJContent, zKey, nKey)==0;
+static int jsonLabelCompare(
+ const char *zLeft, /* The left label */
+ u32 nLeft, /* Size of the left label in bytes */
+ int rawLeft, /* True if zLeft contains no escapes */
+ const char *zRight, /* The right label */
+ u32 nRight, /* Size of the right label in bytes */
+ int rawRight /* True if zRight is escape-free */
+){
+ if( rawLeft && rawRight ){
+ /* Simpliest case: Neither label contains escapes. A simple
+ ** memcmp() is sufficient. */
+ if( nLeft!=nRight ) return 0;
+ return memcmp(zLeft, zRight, nLeft)==0;
}else{
- if( pNode->n!=nKey+2 ) return 0;
- return strncmp(pNode->u.zJContent+1, zKey, nKey)==0;
+ return jsonLabelCompareEscaped(zLeft, nLeft, rawLeft,
+ zRight, nRight, rawRight);
}
}
-/* forward declaration */
-static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**);
+/*
+** Error returns from jsonLookupStep()
+*/
+#define JSON_LOOKUP_ERROR 0xffffffff
+#define JSON_LOOKUP_NOTFOUND 0xfffffffe
+#define JSON_LOOKUP_PATHERROR 0xfffffffd
+#define JSON_LOOKUP_ISERROR(x) ((x)>=JSON_LOOKUP_PATHERROR)
+
+/* Forward declaration */
+static u32 jsonLookupStep(JsonParse*,u32,const char*,u32);
+
+
+/* This helper routine for jsonLookupStep() populates pIns with
+** binary data that is to be inserted into pParse.
+**
+** In the common case, pIns just points to pParse->aIns and pParse->nIns.
+** But if the zPath of the original edit operation includes path elements
+** that go deeper, additional substructure must be created.
+**
+** For example:
+**
+** json_insert('{}', '$.a.b.c', 123);
+**
+** The search stops at '$.a' But additional substructure must be
+** created for the ".b.c" part of the patch so that the final result
+** is: {"a":{"b":{"c"::123}}}. This routine populates pIns with
+** the binary equivalent of {"b":{"c":123}} so that it can be inserted.
+**
+** The caller is responsible for resetting pIns when it has finished
+** using the substructure.
+*/
+static u32 jsonCreateEditSubstructure(
+ JsonParse *pParse, /* The original JSONB that is being edited */
+ JsonParse *pIns, /* Populate this with the blob data to insert */
+ const char *zTail /* Tail of the path that determins substructure */
+){
+ static const u8 emptyObject[] = { JSONB_ARRAY, JSONB_OBJECT };
+ int rc;
+ memset(pIns, 0, sizeof(*pIns));
+ pIns->db = pParse->db;
+ if( zTail[0]==0 ){
+ /* No substructure. Just insert what is given in pParse. */
+ pIns->aBlob = pParse->aIns;
+ pIns->nBlob = pParse->nIns;
+ rc = 0;
+ }else{
+ /* Construct the binary substructure */
+ pIns->nBlob = 1;
+ pIns->aBlob = (u8*)&emptyObject[zTail[0]=='.'];
+ pIns->eEdit = pParse->eEdit;
+ pIns->nIns = pParse->nIns;
+ pIns->aIns = pParse->aIns;
+ rc = jsonLookupStep(pIns, 0, zTail, 0);
+ pParse->oom |= pIns->oom;
+ }
+ return rc; /* Error code only */
+}
/*
-** Search along zPath to find the node specified. Return a pointer
-** to that node, or NULL if zPath is malformed or if there is no such
-** node.
+** Search along zPath to find the Json element specified. Return an
+** index into pParse->aBlob[] for the start of that element's value.
+**
+** If the value found by this routine is the value half of label/value pair
+** within an object, then set pPath->iLabel to the start of the corresponding
+** label, before returning.
+**
+** Return one of the JSON_LOOKUP error codes if problems are seen.
**
-** If pApnd!=0, then try to append new nodes to complete zPath if it is
-** possible to do so and if no existing node corresponds to zPath. If
-** new nodes are appended *pApnd is set to 1.
+** This routine will also modify the blob. If pParse->eEdit is one of
+** JEDIT_DEL, JEDIT_REPL, JEDIT_INS, or JEDIT_SET, then changes might be
+** made to the selected value. If an edit is performed, then the return
+** value does not necessarily point to the select element. If an edit
+** is performed, the return value is only useful for detecting error
+** conditions.
*/
-static JsonNode *jsonLookupStep(
+static u32 jsonLookupStep(
JsonParse *pParse, /* The JSON to search */
- u32 iRoot, /* Begin the search at this node */
+ u32 iRoot, /* Begin the search at this element of aBlob[] */
const char *zPath, /* The path to search */
- int *pApnd, /* Append nodes to complete path if not NULL */
- const char **pzErr /* Make *pzErr point to any syntax error in zPath */
+ u32 iLabel /* Label if iRoot is a value of in an object */
){
- u32 i, j, nKey;
+ u32 i, j, k, nKey, sz, n, iEnd, rc;
const char *zKey;
- JsonNode *pRoot = &pParse->aNode[iRoot];
- if( zPath[0]==0 ) return pRoot;
- if( pRoot->jnFlags & JNODE_REPLACE ) return 0;
+ u8 x;
+
+ if( zPath[0]==0 ){
+ if( pParse->eEdit && jsonBlobMakeEditable(pParse, pParse->nIns) ){
+ n = jsonbPayloadSize(pParse, iRoot, &sz);
+ sz += n;
+ if( pParse->eEdit==JEDIT_DEL ){
+ if( iLabel>0 ){
+ sz += iRoot - iLabel;
+ iRoot = iLabel;
+ }
+ jsonBlobEdit(pParse, iRoot, sz, 0, 0);
+ }else if( pParse->eEdit==JEDIT_INS ){
+ /* Already exists, so json_insert() is a no-op */
+ }else{
+ /* json_set() or json_replace() */
+ jsonBlobEdit(pParse, iRoot, sz, pParse->aIns, pParse->nIns);
+ }
+ }
+ pParse->iLabel = iLabel;
+ return iRoot;
+ }
if( zPath[0]=='.' ){
- if( pRoot->eType!=JSON_OBJECT ) return 0;
+ int rawKey = 1;
+ x = pParse->aBlob[iRoot];
zPath++;
if( zPath[0]=='"' ){
zKey = zPath + 1;
@@ -199881,303 +206128,850 @@ static JsonNode *jsonLookupStep(
if( zPath[i] ){
i++;
}else{
- *pzErr = zPath;
- return 0;
+ return JSON_LOOKUP_PATHERROR;
}
testcase( nKey==0 );
+ rawKey = memchr(zKey, '\\', nKey)==0;
}else{
zKey = zPath;
for(i=0; zPath[i] && zPath[i]!='.' && zPath[i]!='['; i++){}
nKey = i;
if( nKey==0 ){
- *pzErr = zPath;
- return 0;
- }
- }
- j = 1;
- for(;;){
- while( j<=pRoot->n ){
- if( jsonLabelCompare(pRoot+j, zKey, nKey) ){
- return jsonLookupStep(pParse, iRoot+j+1, &zPath[i], pApnd, pzErr);
- }
- j++;
- j += jsonNodeSize(&pRoot[j]);
+ return JSON_LOOKUP_PATHERROR;
+ }
+ }
+ if( (x & 0x0f)!=JSONB_OBJECT ) return JSON_LOOKUP_NOTFOUND;
+ n = jsonbPayloadSize(pParse, iRoot, &sz);
+ j = iRoot + n; /* j is the index of a label */
+ iEnd = j+sz;
+ while( j<iEnd ){
+ int rawLabel;
+ const char *zLabel;
+ x = pParse->aBlob[j] & 0x0f;
+ if( x<JSONB_TEXT || x>JSONB_TEXTRAW ) return JSON_LOOKUP_ERROR;
+ n = jsonbPayloadSize(pParse, j, &sz);
+ if( n==0 ) return JSON_LOOKUP_ERROR;
+ k = j+n; /* k is the index of the label text */
+ if( k+sz>=iEnd ) return JSON_LOOKUP_ERROR;
+ zLabel = (const char*)&pParse->aBlob[k];
+ rawLabel = x==JSONB_TEXT || x==JSONB_TEXTRAW;
+ if( jsonLabelCompare(zKey, nKey, rawKey, zLabel, sz, rawLabel) ){
+ u32 v = k+sz; /* v is the index of the value */
+ if( ((pParse->aBlob[v])&0x0f)>JSONB_OBJECT ) return JSON_LOOKUP_ERROR;
+ n = jsonbPayloadSize(pParse, v, &sz);
+ if( n==0 || v+n+sz>iEnd ) return JSON_LOOKUP_ERROR;
+ assert( j>0 );
+ rc = jsonLookupStep(pParse, v, &zPath[i], j);
+ if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
+ return rc;
}
- if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
- assert( pRoot->eU==2 );
- iRoot += pRoot->u.iAppend;
- pRoot = &pParse->aNode[iRoot];
- j = 1;
- }
- if( pApnd ){
- u32 iStart, iLabel;
- JsonNode *pNode;
- iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
- iLabel = jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
- zPath += i;
- pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
- if( pParse->oom ) return 0;
- if( pNode ){
- pRoot = &pParse->aNode[iRoot];
- assert( pRoot->eU==0 );
- pRoot->u.iAppend = iStart - iRoot;
- pRoot->jnFlags |= JNODE_APPEND;
- VVA( pRoot->eU = 2 );
- pParse->aNode[iLabel].jnFlags |= JNODE_RAW;
- }
- return pNode;
+ j = k+sz;
+ if( ((pParse->aBlob[j])&0x0f)>JSONB_OBJECT ) return JSON_LOOKUP_ERROR;
+ n = jsonbPayloadSize(pParse, j, &sz);
+ if( n==0 ) return JSON_LOOKUP_ERROR;
+ j += n+sz;
+ }
+ if( j>iEnd ) return JSON_LOOKUP_ERROR;
+ if( pParse->eEdit>=JEDIT_INS ){
+ u32 nIns; /* Total bytes to insert (label+value) */
+ JsonParse v; /* BLOB encoding of the value to be inserted */
+ JsonParse ix; /* Header of the label to be inserted */
+ testcase( pParse->eEdit==JEDIT_INS );
+ testcase( pParse->eEdit==JEDIT_SET );
+ memset(&ix, 0, sizeof(ix));
+ ix.db = pParse->db;
+ jsonBlobAppendNode(&ix, rawKey?JSONB_TEXTRAW:JSONB_TEXT5, nKey, 0);
+ pParse->oom |= ix.oom;
+ rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i]);
+ if( !JSON_LOOKUP_ISERROR(rc)
+ && jsonBlobMakeEditable(pParse, ix.nBlob+nKey+v.nBlob)
+ ){
+ assert( !pParse->oom );
+ nIns = ix.nBlob + nKey + v.nBlob;
+ jsonBlobEdit(pParse, j, 0, 0, nIns);
+ if( !pParse->oom ){
+ assert( pParse->aBlob!=0 ); /* Because pParse->oom!=0 */
+ assert( ix.aBlob!=0 ); /* Because pPasre->oom!=0 */
+ memcpy(&pParse->aBlob[j], ix.aBlob, ix.nBlob);
+ k = j + ix.nBlob;
+ memcpy(&pParse->aBlob[k], zKey, nKey);
+ k += nKey;
+ memcpy(&pParse->aBlob[k], v.aBlob, v.nBlob);
+ if( ALWAYS(pParse->delta) ) jsonAfterEditSizeAdjust(pParse, iRoot);
+ }
+ }
+ jsonParseReset(&v);
+ jsonParseReset(&ix);
+ return rc;
}
}else if( zPath[0]=='[' ){
- i = 0;
- j = 1;
- while( sqlite3Isdigit(zPath[j]) ){
- i = i*10 + zPath[j] - '0';
- j++;
+ x = pParse->aBlob[iRoot] & 0x0f;
+ if( x!=JSONB_ARRAY ) return JSON_LOOKUP_NOTFOUND;
+ n = jsonbPayloadSize(pParse, iRoot, &sz);
+ k = 0;
+ i = 1;
+ while( sqlite3Isdigit(zPath[i]) ){
+ k = k*10 + zPath[i] - '0';
+ i++;
}
- if( j<2 || zPath[j]!=']' ){
+ if( i<2 || zPath[i]!=']' ){
if( zPath[1]=='#' ){
- JsonNode *pBase = pRoot;
- int iBase = iRoot;
- if( pRoot->eType!=JSON_ARRAY ) return 0;
- for(;;){
- while( j<=pBase->n ){
- if( (pBase[j].jnFlags & JNODE_REMOVE)==0 ) i++;
- j += jsonNodeSize(&pBase[j]);
- }
- if( (pBase->jnFlags & JNODE_APPEND)==0 ) break;
- assert( pBase->eU==2 );
- iBase += pBase->u.iAppend;
- pBase = &pParse->aNode[iBase];
- j = 1;
- }
- j = 2;
+ k = jsonbArrayCount(pParse, iRoot);
+ i = 2;
if( zPath[2]=='-' && sqlite3Isdigit(zPath[3]) ){
- unsigned int x = 0;
- j = 3;
+ unsigned int nn = 0;
+ i = 3;
do{
- x = x*10 + zPath[j] - '0';
- j++;
- }while( sqlite3Isdigit(zPath[j]) );
- if( x>i ) return 0;
- i -= x;
+ nn = nn*10 + zPath[i] - '0';
+ i++;
+ }while( sqlite3Isdigit(zPath[i]) );
+ if( nn>k ) return JSON_LOOKUP_NOTFOUND;
+ k -= nn;
}
- if( zPath[j]!=']' ){
- *pzErr = zPath;
- return 0;
+ if( zPath[i]!=']' ){
+ return JSON_LOOKUP_PATHERROR;
}
}else{
- *pzErr = zPath;
- return 0;
+ return JSON_LOOKUP_PATHERROR;
}
}
- if( pRoot->eType!=JSON_ARRAY ) return 0;
- zPath += j + 1;
- j = 1;
- for(;;){
- while( j<=pRoot->n && (i>0 || (pRoot[j].jnFlags & JNODE_REMOVE)!=0) ){
- if( (pRoot[j].jnFlags & JNODE_REMOVE)==0 ) i--;
- j += jsonNodeSize(&pRoot[j]);
- }
- if( (pRoot->jnFlags & JNODE_APPEND)==0 ) break;
- assert( pRoot->eU==2 );
- iRoot += pRoot->u.iAppend;
- pRoot = &pParse->aNode[iRoot];
- j = 1;
- }
- if( j<=pRoot->n ){
- return jsonLookupStep(pParse, iRoot+j, zPath, pApnd, pzErr);
- }
- if( i==0 && pApnd ){
- u32 iStart;
- JsonNode *pNode;
- iStart = jsonParseAddNode(pParse, JSON_ARRAY, 1, 0);
- pNode = jsonLookupAppend(pParse, zPath, pApnd, pzErr);
- if( pParse->oom ) return 0;
- if( pNode ){
- pRoot = &pParse->aNode[iRoot];
- assert( pRoot->eU==0 );
- pRoot->u.iAppend = iStart - iRoot;
- pRoot->jnFlags |= JNODE_APPEND;
- VVA( pRoot->eU = 2 );
+ j = iRoot+n;
+ iEnd = j+sz;
+ while( j<iEnd ){
+ if( k==0 ){
+ rc = jsonLookupStep(pParse, j, &zPath[i+1], 0);
+ if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
+ return rc;
}
- return pNode;
+ k--;
+ n = jsonbPayloadSize(pParse, j, &sz);
+ if( n==0 ) return JSON_LOOKUP_ERROR;
+ j += n+sz;
+ }
+ if( j>iEnd ) return JSON_LOOKUP_ERROR;
+ if( k>0 ) return JSON_LOOKUP_NOTFOUND;
+ if( pParse->eEdit>=JEDIT_INS ){
+ JsonParse v;
+ testcase( pParse->eEdit==JEDIT_INS );
+ testcase( pParse->eEdit==JEDIT_SET );
+ rc = jsonCreateEditSubstructure(pParse, &v, &zPath[i+1]);
+ if( !JSON_LOOKUP_ISERROR(rc)
+ && jsonBlobMakeEditable(pParse, v.nBlob)
+ ){
+ assert( !pParse->oom );
+ jsonBlobEdit(pParse, j, 0, v.aBlob, v.nBlob);
+ }
+ jsonParseReset(&v);
+ if( pParse->delta ) jsonAfterEditSizeAdjust(pParse, iRoot);
+ return rc;
}
}else{
- *pzErr = zPath;
+ return JSON_LOOKUP_PATHERROR;
}
- return 0;
+ return JSON_LOOKUP_NOTFOUND;
}
/*
-** Append content to pParse that will complete zPath. Return a pointer
-** to the inserted node, or return NULL if the append fails.
+** Convert a JSON BLOB into text and make that text the return value
+** of an SQL function.
*/
-static JsonNode *jsonLookupAppend(
- JsonParse *pParse, /* Append content to the JSON parse */
- const char *zPath, /* Description of content to append */
- int *pApnd, /* Set this flag to 1 */
- const char **pzErr /* Make this point to any syntax error */
+static void jsonReturnTextJsonFromBlob(
+ sqlite3_context *ctx,
+ const u8 *aBlob,
+ u32 nBlob
){
- *pApnd = 1;
- if( zPath[0]==0 ){
- jsonParseAddNode(pParse, JSON_NULL, 0, 0);
- return pParse->oom ? 0 : &pParse->aNode[pParse->nNode-1];
- }
- if( zPath[0]=='.' ){
- jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
- }else if( strncmp(zPath,"[0]",3)==0 ){
- jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
- }else{
- return 0;
- }
- if( pParse->oom ) return 0;
- return jsonLookupStep(pParse, pParse->nNode-1, zPath, pApnd, pzErr);
+ JsonParse x;
+ JsonString s;
+
+ if( NEVER(aBlob==0) ) return;
+ memset(&x, 0, sizeof(x));
+ x.aBlob = (u8*)aBlob;
+ x.nBlob = nBlob;
+ jsonStringInit(&s, ctx);
+ jsonTranslateBlobToText(&x, 0, &s);
+ jsonReturnString(&s, 0, 0);
}
+
/*
-** Return the text of a syntax error message on a JSON path. Space is
-** obtained from sqlite3_malloc().
+** Return the value of the BLOB node at index i.
+**
+** If the value is a primitive, return it as an SQL value.
+** If the value is an array or object, return it as either
+** JSON text or the BLOB encoding, depending on the JSON_B flag
+** on the userdata.
*/
-static char *jsonPathSyntaxError(const char *zErr){
- return sqlite3_mprintf("JSON path error near '%q'", zErr);
+static void jsonReturnFromBlob(
+ JsonParse *pParse, /* Complete JSON parse tree */
+ u32 i, /* Index of the node */
+ sqlite3_context *pCtx, /* Return value for this function */
+ int textOnly /* return text JSON. Disregard user-data */
+){
+ u32 n, sz;
+ int rc;
+ sqlite3 *db = sqlite3_context_db_handle(pCtx);
+
+ n = jsonbPayloadSize(pParse, i, &sz);
+ if( n==0 ){
+ sqlite3_result_error(pCtx, "malformed JSON", -1);
+ return;
+ }
+ switch( pParse->aBlob[i] & 0x0f ){
+ case JSONB_NULL: {
+ if( sz ) goto returnfromblob_malformed;
+ sqlite3_result_null(pCtx);
+ break;
+ }
+ case JSONB_TRUE: {
+ if( sz ) goto returnfromblob_malformed;
+ sqlite3_result_int(pCtx, 1);
+ break;
+ }
+ case JSONB_FALSE: {
+ if( sz ) goto returnfromblob_malformed;
+ sqlite3_result_int(pCtx, 0);
+ break;
+ }
+ case JSONB_INT5:
+ case JSONB_INT: {
+ sqlite3_int64 iRes = 0;
+ char *z;
+ int bNeg = 0;
+ char x;
+ if( sz==0 ) goto returnfromblob_malformed;
+ x = (char)pParse->aBlob[i+n];
+ if( x=='-' ){
+ if( sz<2 ) goto returnfromblob_malformed;
+ n++;
+ sz--;
+ bNeg = 1;
+ }
+ z = sqlite3DbStrNDup(db, (const char*)&pParse->aBlob[i+n], (int)sz);
+ if( z==0 ) goto returnfromblob_oom;
+ rc = sqlite3DecOrHexToI64(z, &iRes);
+ sqlite3DbFree(db, z);
+ if( rc==0 ){
+ sqlite3_result_int64(pCtx, bNeg ? -iRes : iRes);
+ }else if( rc==3 && bNeg ){
+ sqlite3_result_int64(pCtx, SMALLEST_INT64);
+ }else if( rc==1 ){
+ goto returnfromblob_malformed;
+ }else{
+ if( bNeg ){ n--; sz++; }
+ goto to_double;
+ }
+ break;
+ }
+ case JSONB_FLOAT5:
+ case JSONB_FLOAT: {
+ double r;
+ char *z;
+ if( sz==0 ) goto returnfromblob_malformed;
+ to_double:
+ z = sqlite3DbStrNDup(db, (const char*)&pParse->aBlob[i+n], (int)sz);
+ if( z==0 ) goto returnfromblob_oom;
+ rc = sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
+ sqlite3DbFree(db, z);
+ if( rc<=0 ) goto returnfromblob_malformed;
+ sqlite3_result_double(pCtx, r);
+ break;
+ }
+ case JSONB_TEXTRAW:
+ case JSONB_TEXT: {
+ sqlite3_result_text(pCtx, (char*)&pParse->aBlob[i+n], sz,
+ SQLITE_TRANSIENT);
+ break;
+ }
+ case JSONB_TEXT5:
+ case JSONB_TEXTJ: {
+ /* Translate JSON formatted string into raw text */
+ u32 iIn, iOut;
+ const char *z;
+ char *zOut;
+ u32 nOut = sz;
+ z = (const char*)&pParse->aBlob[i+n];
+ zOut = sqlite3DbMallocRaw(db, nOut+1);
+ if( zOut==0 ) goto returnfromblob_oom;
+ for(iIn=iOut=0; iIn<sz; iIn++){
+ char c = z[iIn];
+ if( c=='\\' ){
+ u32 v;
+ u32 szEscape = jsonUnescapeOneChar(&z[iIn], sz-iIn, &v);
+ if( v<=0x7f ){
+ zOut[iOut++] = (char)v;
+ }else if( v<=0x7ff ){
+ assert( szEscape>=2 );
+ zOut[iOut++] = (char)(0xc0 | (v>>6));
+ zOut[iOut++] = 0x80 | (v&0x3f);
+ }else if( v<0x10000 ){
+ assert( szEscape>=3 );
+ zOut[iOut++] = 0xe0 | (v>>12);
+ zOut[iOut++] = 0x80 | ((v>>6)&0x3f);
+ zOut[iOut++] = 0x80 | (v&0x3f);
+ }else if( v==JSON_INVALID_CHAR ){
+ /* Silently ignore illegal unicode */
+ }else{
+ assert( szEscape>=4 );
+ zOut[iOut++] = 0xf0 | (v>>18);
+ zOut[iOut++] = 0x80 | ((v>>12)&0x3f);
+ zOut[iOut++] = 0x80 | ((v>>6)&0x3f);
+ zOut[iOut++] = 0x80 | (v&0x3f);
+ }
+ iIn += szEscape - 1;
+ }else{
+ zOut[iOut++] = c;
+ }
+ } /* end for() */
+ assert( iOut<=nOut );
+ zOut[iOut] = 0;
+ sqlite3_result_text(pCtx, zOut, iOut, SQLITE_DYNAMIC);
+ break;
+ }
+ case JSONB_ARRAY:
+ case JSONB_OBJECT: {
+ int flags = textOnly ? 0 : SQLITE_PTR_TO_INT(sqlite3_user_data(pCtx));
+ if( flags & JSON_BLOB ){
+ sqlite3_result_blob(pCtx, &pParse->aBlob[i], sz+n, SQLITE_TRANSIENT);
+ }else{
+ jsonReturnTextJsonFromBlob(pCtx, &pParse->aBlob[i], sz+n);
+ }
+ break;
+ }
+ default: {
+ goto returnfromblob_malformed;
+ }
+ }
+ return;
+
+returnfromblob_oom:
+ sqlite3_result_error_nomem(pCtx);
+ return;
+
+returnfromblob_malformed:
+ sqlite3_result_error(pCtx, "malformed JSON", -1);
+ return;
}
/*
-** Do a node lookup using zPath. Return a pointer to the node on success.
-** Return NULL if not found or if there is an error.
+** pArg is a function argument that might be an SQL value or a JSON
+** value. Figure out what it is and encode it as a JSONB blob.
+** Return the results in pParse.
**
-** On an error, write an error message into pCtx and increment the
-** pParse->nErr counter.
+** pParse is uninitialized upon entry. This routine will handle the
+** initialization of pParse. The result will be contained in
+** pParse->aBlob and pParse->nBlob. pParse->aBlob might be dynamically
+** allocated (if pParse->nBlobAlloc is greater than zero) in which case
+** the caller is responsible for freeing the space allocated to pParse->aBlob
+** when it has finished with it. Or pParse->aBlob might be a static string
+** or a value obtained from sqlite3_value_blob(pArg).
**
-** If pApnd!=NULL then try to append missing nodes and set *pApnd = 1 if
-** nodes are appended.
+** If the argument is a BLOB that is clearly not a JSONB, then this
+** function might set an error message in ctx and return non-zero.
+** It might also set an error message and return non-zero on an OOM error.
*/
-static JsonNode *jsonLookup(
- JsonParse *pParse, /* The JSON to search */
- const char *zPath, /* The path to search */
- int *pApnd, /* Append nodes to complete path if not NULL */
- sqlite3_context *pCtx /* Report errors here, if not NULL */
-){
- const char *zErr = 0;
- JsonNode *pNode = 0;
- char *zMsg;
-
- if( zPath==0 ) return 0;
- if( zPath[0]!='$' ){
- zErr = zPath;
- goto lookup_err;
+static int jsonFunctionArgToBlob(
+ sqlite3_context *ctx,
+ sqlite3_value *pArg,
+ JsonParse *pParse
+){
+ int eType = sqlite3_value_type(pArg);
+ static u8 aNull[] = { 0x00 };
+ memset(pParse, 0, sizeof(pParse[0]));
+ pParse->db = sqlite3_context_db_handle(ctx);
+ switch( eType ){
+ default: {
+ pParse->aBlob = aNull;
+ pParse->nBlob = 1;
+ return 0;
+ }
+ case SQLITE_BLOB: {
+ if( jsonFuncArgMightBeBinary(pArg) ){
+ pParse->aBlob = (u8*)sqlite3_value_blob(pArg);
+ pParse->nBlob = sqlite3_value_bytes(pArg);
+ }else{
+ sqlite3_result_error(ctx, "JSON cannot hold BLOB values", -1);
+ return 1;
+ }
+ break;
+ }
+ case SQLITE_TEXT: {
+ const char *zJson = (const char*)sqlite3_value_text(pArg);
+ int nJson = sqlite3_value_bytes(pArg);
+ if( zJson==0 ) return 1;
+ if( sqlite3_value_subtype(pArg)==JSON_SUBTYPE ){
+ pParse->zJson = (char*)zJson;
+ pParse->nJson = nJson;
+ if( jsonConvertTextToBlob(pParse, ctx) ){
+ sqlite3_result_error(ctx, "malformed JSON", -1);
+ sqlite3DbFree(pParse->db, pParse->aBlob);
+ memset(pParse, 0, sizeof(pParse[0]));
+ return 1;
+ }
+ }else{
+ jsonBlobAppendNode(pParse, JSONB_TEXTRAW, nJson, zJson);
+ }
+ break;
+ }
+ case SQLITE_FLOAT: {
+ double r = sqlite3_value_double(pArg);
+ if( NEVER(sqlite3IsNaN(r)) ){
+ jsonBlobAppendNode(pParse, JSONB_NULL, 0, 0);
+ }else{
+ int n = sqlite3_value_bytes(pArg);
+ const char *z = (const char*)sqlite3_value_text(pArg);
+ if( z==0 ) return 1;
+ if( z[0]=='I' ){
+ jsonBlobAppendNode(pParse, JSONB_FLOAT, 5, "9e999");
+ }else if( z[0]=='-' && z[1]=='I' ){
+ jsonBlobAppendNode(pParse, JSONB_FLOAT, 6, "-9e999");
+ }else{
+ jsonBlobAppendNode(pParse, JSONB_FLOAT, n, z);
+ }
+ }
+ break;
+ }
+ case SQLITE_INTEGER: {
+ int n = sqlite3_value_bytes(pArg);
+ const char *z = (const char*)sqlite3_value_text(pArg);
+ if( z==0 ) return 1;
+ jsonBlobAppendNode(pParse, JSONB_INT, n, z);
+ break;
+ }
}
- zPath++;
- pNode = jsonLookupStep(pParse, 0, zPath, pApnd, &zErr);
- if( zErr==0 ) return pNode;
+ if( pParse->oom ){
+ sqlite3_result_error_nomem(ctx);
+ return 1;
+ }else{
+ return 0;
+ }
+}
-lookup_err:
- pParse->nErr++;
- assert( zErr!=0 && pCtx!=0 );
- zMsg = jsonPathSyntaxError(zErr);
+/*
+** Generate a bad path error.
+**
+** If ctx is not NULL then push the error message into ctx and return NULL.
+** If ctx is NULL, then return the text of the error message.
+*/
+static char *jsonBadPathError(
+ sqlite3_context *ctx, /* The function call containing the error */
+ const char *zPath /* The path with the problem */
+){
+ char *zMsg = sqlite3_mprintf("bad JSON path: %Q", zPath);
+ if( ctx==0 ) return zMsg;
if( zMsg ){
- sqlite3_result_error(pCtx, zMsg, -1);
+ sqlite3_result_error(ctx, zMsg, -1);
sqlite3_free(zMsg);
}else{
- sqlite3_result_error_nomem(pCtx);
+ sqlite3_result_error_nomem(ctx);
}
return 0;
}
+/* argv[0] is a BLOB that seems likely to be a JSONB. Subsequent
+** arguments come in parse where each pair contains a JSON path and
+** content to insert or set at that patch. Do the updates
+** and return the result.
+**
+** The specific operation is determined by eEdit, which can be one
+** of JEDIT_INS, JEDIT_REPL, or JEDIT_SET.
+*/
+static void jsonInsertIntoBlob(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv,
+ int eEdit /* JEDIT_INS, JEDIT_REPL, or JEDIT_SET */
+){
+ int i;
+ u32 rc = 0;
+ const char *zPath = 0;
+ int flgs;
+ JsonParse *p;
+ JsonParse ax;
+
+ assert( (argc&1)==1 );
+ flgs = argc==1 ? 0 : JSON_EDITABLE;
+ p = jsonParseFuncArg(ctx, argv[0], flgs);
+ if( p==0 ) return;
+ for(i=1; i<argc-1; i+=2){
+ if( sqlite3_value_type(argv[i])==SQLITE_NULL ) continue;
+ zPath = (const char*)sqlite3_value_text(argv[i]);
+ if( zPath==0 ){
+ sqlite3_result_error_nomem(ctx);
+ jsonParseFree(p);
+ return;
+ }
+ if( zPath[0]!='$' ) goto jsonInsertIntoBlob_patherror;
+ if( jsonFunctionArgToBlob(ctx, argv[i+1], &ax) ){
+ jsonParseReset(&ax);
+ jsonParseFree(p);
+ return;
+ }
+ if( zPath[1]==0 ){
+ if( eEdit==JEDIT_REPL || eEdit==JEDIT_SET ){
+ jsonBlobEdit(p, 0, p->nBlob, ax.aBlob, ax.nBlob);
+ }
+ rc = 0;
+ }else{
+ p->eEdit = eEdit;
+ p->nIns = ax.nBlob;
+ p->aIns = ax.aBlob;
+ p->delta = 0;
+ rc = jsonLookupStep(p, 0, zPath+1, 0);
+ }
+ jsonParseReset(&ax);
+ if( rc==JSON_LOOKUP_NOTFOUND ) continue;
+ if( JSON_LOOKUP_ISERROR(rc) ) goto jsonInsertIntoBlob_patherror;
+ }
+ jsonReturnParse(ctx, p);
+ jsonParseFree(p);
+ return;
+
+jsonInsertIntoBlob_patherror:
+ jsonParseFree(p);
+ if( rc==JSON_LOOKUP_ERROR ){
+ sqlite3_result_error(ctx, "malformed JSON", -1);
+ }else{
+ jsonBadPathError(ctx, zPath);
+ }
+ return;
+}
/*
-** Report the wrong number of arguments for json_insert(), json_replace()
-** or json_set().
+** If pArg is a blob that seems like a JSONB blob, then initialize
+** p to point to that JSONB and return TRUE. If pArg does not seem like
+** a JSONB blob, then return FALSE;
+**
+** This routine is only called if it is already known that pArg is a
+** blob. The only open question is whether or not the blob appears
+** to be a JSONB blob.
*/
-static void jsonWrongNumArgs(
- sqlite3_context *pCtx,
- const char *zFuncName
-){
- char *zMsg = sqlite3_mprintf("json_%s() needs an odd number of arguments",
- zFuncName);
- sqlite3_result_error(pCtx, zMsg, -1);
- sqlite3_free(zMsg);
+static int jsonArgIsJsonb(sqlite3_value *pArg, JsonParse *p){
+ u32 n, sz = 0;
+ p->aBlob = (u8*)sqlite3_value_blob(pArg);
+ p->nBlob = (u32)sqlite3_value_bytes(pArg);
+ if( p->nBlob==0 ){
+ p->aBlob = 0;
+ return 0;
+ }
+ if( NEVER(p->aBlob==0) ){
+ return 0;
+ }
+ if( (p->aBlob[0] & 0x0f)<=JSONB_OBJECT
+ && (n = jsonbPayloadSize(p, 0, &sz))>0
+ && sz+n==p->nBlob
+ && ((p->aBlob[0] & 0x0f)>JSONB_FALSE || sz==0)
+ ){
+ return 1;
+ }
+ p->aBlob = 0;
+ p->nBlob = 0;
+ return 0;
}
/*
-** Mark all NULL entries in the Object passed in as JNODE_REMOVE.
+** Generate a JsonParse object, containing valid JSONB in aBlob and nBlob,
+** from the SQL function argument pArg. Return a pointer to the new
+** JsonParse object.
+**
+** Ownership of the new JsonParse object is passed to the caller. The
+** caller should invoke jsonParseFree() on the return value when it
+** has finished using it.
+**
+** If any errors are detected, an appropriate error messages is set
+** using sqlite3_result_error() or the equivalent and this routine
+** returns NULL. This routine also returns NULL if the pArg argument
+** is an SQL NULL value, but no error message is set in that case. This
+** is so that SQL functions that are given NULL arguments will return
+** a NULL value.
*/
-static void jsonRemoveAllNulls(JsonNode *pNode){
- int i, n;
- assert( pNode->eType==JSON_OBJECT );
- n = pNode->n;
- for(i=2; i<=n; i += jsonNodeSize(&pNode[i])+1){
- switch( pNode[i].eType ){
- case JSON_NULL:
- pNode[i].jnFlags |= JNODE_REMOVE;
- break;
- case JSON_OBJECT:
- jsonRemoveAllNulls(&pNode[i]);
- break;
+static JsonParse *jsonParseFuncArg(
+ sqlite3_context *ctx,
+ sqlite3_value *pArg,
+ u32 flgs
+){
+ int eType; /* Datatype of pArg */
+ JsonParse *p = 0; /* Value to be returned */
+ JsonParse *pFromCache = 0; /* Value taken from cache */
+ sqlite3 *db; /* The database connection */
+
+ assert( ctx!=0 );
+ eType = sqlite3_value_type(pArg);
+ if( eType==SQLITE_NULL ){
+ return 0;
+ }
+ pFromCache = jsonCacheSearch(ctx, pArg);
+ if( pFromCache ){
+ pFromCache->nJPRef++;
+ if( (flgs & JSON_EDITABLE)==0 ){
+ return pFromCache;
}
}
-}
+ db = sqlite3_context_db_handle(ctx);
+rebuild_from_cache:
+ p = sqlite3DbMallocZero(db, sizeof(*p));
+ if( p==0 ) goto json_pfa_oom;
+ memset(p, 0, sizeof(*p));
+ p->db = db;
+ p->nJPRef = 1;
+ if( pFromCache!=0 ){
+ u32 nBlob = pFromCache->nBlob;
+ p->aBlob = sqlite3DbMallocRaw(db, nBlob);
+ if( p->aBlob==0 ) goto json_pfa_oom;
+ memcpy(p->aBlob, pFromCache->aBlob, nBlob);
+ p->nBlobAlloc = p->nBlob = nBlob;
+ p->hasNonstd = pFromCache->hasNonstd;
+ jsonParseFree(pFromCache);
+ return p;
+ }
+ if( eType==SQLITE_BLOB ){
+ if( jsonArgIsJsonb(pArg,p) ){
+ if( (flgs & JSON_EDITABLE)!=0 && jsonBlobMakeEditable(p, 0)==0 ){
+ goto json_pfa_oom;
+ }
+ return p;
+ }
+ /* If the blob is not valid JSONB, fall through into trying to cast
+ ** the blob into text which is then interpreted as JSON. (tag-20240123-a)
+ **
+ ** This goes against all historical documentation about how the SQLite
+ ** JSON functions were suppose to work. From the beginning, blob was
+ ** reserved for expansion and a blob value should have raised an error.
+ ** But it did not, due to a bug. And many applications came to depend
+ ** upon this buggy behavior, espeically when using the CLI and reading
+ ** JSON text using readfile(), which returns a blob. For this reason
+ ** we will continue to support the bug moving forward.
+ ** See for example https://sqlite.org/forum/forumpost/012136abd5292b8d
+ */
+ }
+ p->zJson = (char*)sqlite3_value_text(pArg);
+ p->nJson = sqlite3_value_bytes(pArg);
+ if( db->mallocFailed ) goto json_pfa_oom;
+ if( p->nJson==0 ) goto json_pfa_malformed;
+ assert( p->zJson!=0 );
+ if( jsonConvertTextToBlob(p, (flgs & JSON_KEEPERROR) ? 0 : ctx) ){
+ if( flgs & JSON_KEEPERROR ){
+ p->nErr = 1;
+ return p;
+ }else{
+ jsonParseFree(p);
+ return 0;
+ }
+ }else{
+ int isRCStr = sqlite3ValueIsOfClass(pArg, sqlite3RCStrUnref);
+ int rc;
+ if( !isRCStr ){
+ char *zNew = sqlite3RCStrNew( p->nJson );
+ if( zNew==0 ) goto json_pfa_oom;
+ memcpy(zNew, p->zJson, p->nJson);
+ p->zJson = zNew;
+ p->zJson[p->nJson] = 0;
+ }else{
+ sqlite3RCStrRef(p->zJson);
+ }
+ p->bJsonIsRCStr = 1;
+ rc = jsonCacheInsert(ctx, p);
+ if( rc==SQLITE_NOMEM ) goto json_pfa_oom;
+ if( flgs & JSON_EDITABLE ){
+ pFromCache = p;
+ p = 0;
+ goto rebuild_from_cache;
+ }
+ }
+ return p;
+json_pfa_malformed:
+ if( flgs & JSON_KEEPERROR ){
+ p->nErr = 1;
+ return p;
+ }else{
+ jsonParseFree(p);
+ sqlite3_result_error(ctx, "malformed JSON", -1);
+ return 0;
+ }
-/****************************************************************************
-** SQL functions used for testing and debugging
-****************************************************************************/
+json_pfa_oom:
+ jsonParseFree(pFromCache);
+ jsonParseFree(p);
+ sqlite3_result_error_nomem(ctx);
+ return 0;
+}
-#ifdef SQLITE_DEBUG
/*
-** The json_parse(JSON) function returns a string which describes
-** a parse of the JSON provided. Or it returns NULL if JSON is not
-** well-formed.
+** Make the return value of a JSON function either the raw JSONB blob
+** or make it JSON text, depending on whether the JSON_BLOB flag is
+** set on the function.
*/
-static void jsonParseFunc(
+static void jsonReturnParse(
sqlite3_context *ctx,
- int argc,
- sqlite3_value **argv
+ JsonParse *p
){
- JsonString s; /* Output string - not real JSON */
- JsonParse x; /* The parse */
- u32 i;
-
- assert( argc==1 );
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- jsonParseFindParents(&x);
- jsonInit(&s, ctx);
- for(i=0; i<x.nNode; i++){
- const char *zType;
- if( x.aNode[i].jnFlags & JNODE_LABEL ){
- assert( x.aNode[i].eType==JSON_STRING );
- zType = "label";
+ int flgs;
+ if( p->oom ){
+ sqlite3_result_error_nomem(ctx);
+ return;
+ }
+ flgs = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
+ if( flgs & JSON_BLOB ){
+ if( p->nBlobAlloc>0 && !p->bReadOnly ){
+ sqlite3_result_blob(ctx, p->aBlob, p->nBlob, SQLITE_DYNAMIC);
+ p->nBlobAlloc = 0;
}else{
- zType = jsonType[x.aNode[i].eType];
+ sqlite3_result_blob(ctx, p->aBlob, p->nBlob, SQLITE_TRANSIENT);
}
- jsonPrintf(100, &s,"node %3u: %7s n=%-4d up=%-4d",
- i, zType, x.aNode[i].n, x.aUp[i]);
- assert( x.aNode[i].eU==0 || x.aNode[i].eU==1 );
- if( x.aNode[i].u.zJContent!=0 ){
- assert( x.aNode[i].eU==1 );
- jsonAppendRaw(&s, " ", 1);
- jsonAppendRaw(&s, x.aNode[i].u.zJContent, x.aNode[i].n);
- }else{
- assert( x.aNode[i].eU==0 );
+ }else{
+ JsonString s;
+ jsonStringInit(&s, ctx);
+ p->delta = 0;
+ jsonTranslateBlobToText(p, 0, &s);
+ jsonReturnString(&s, p, ctx);
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+ }
+}
+
+/****************************************************************************
+** SQL functions used for testing and debugging
+****************************************************************************/
+
+#if SQLITE_DEBUG
+/*
+** Decode JSONB bytes in aBlob[] starting at iStart through but not
+** including iEnd. Indent the
+** content by nIndent spaces.
+*/
+static void jsonDebugPrintBlob(
+ JsonParse *pParse, /* JSON content */
+ u32 iStart, /* Start rendering here */
+ u32 iEnd, /* Do not render this byte or any byte after this one */
+ int nIndent, /* Indent by this many spaces */
+ sqlite3_str *pOut /* Generate output into this sqlite3_str object */
+){
+ while( iStart<iEnd ){
+ u32 i, n, nn, sz = 0;
+ int showContent = 1;
+ u8 x = pParse->aBlob[iStart] & 0x0f;
+ u32 savedNBlob = pParse->nBlob;
+ sqlite3_str_appendf(pOut, "%5d:%*s", iStart, nIndent, "");
+ if( pParse->nBlobAlloc>pParse->nBlob ){
+ pParse->nBlob = pParse->nBlobAlloc;
+ }
+ nn = n = jsonbPayloadSize(pParse, iStart, &sz);
+ if( nn==0 ) nn = 1;
+ if( sz>0 && x<JSONB_ARRAY ){
+ nn += sz;
+ }
+ for(i=0; i<nn; i++){
+ sqlite3_str_appendf(pOut, " %02x", pParse->aBlob[iStart+i]);
+ }
+ if( n==0 ){
+ sqlite3_str_appendf(pOut, " ERROR invalid node size\n");
+ iStart = n==0 ? iStart+1 : iEnd;
+ continue;
+ }
+ pParse->nBlob = savedNBlob;
+ if( iStart+n+sz>iEnd ){
+ iEnd = iStart+n+sz;
+ if( iEnd>pParse->nBlob ){
+ if( pParse->nBlobAlloc>0 && iEnd>pParse->nBlobAlloc ){
+ iEnd = pParse->nBlobAlloc;
+ }else{
+ iEnd = pParse->nBlob;
+ }
+ }
+ }
+ sqlite3_str_appendall(pOut," <-- ");
+ switch( x ){
+ case JSONB_NULL: sqlite3_str_appendall(pOut,"null"); break;
+ case JSONB_TRUE: sqlite3_str_appendall(pOut,"true"); break;
+ case JSONB_FALSE: sqlite3_str_appendall(pOut,"false"); break;
+ case JSONB_INT: sqlite3_str_appendall(pOut,"int"); break;
+ case JSONB_INT5: sqlite3_str_appendall(pOut,"int5"); break;
+ case JSONB_FLOAT: sqlite3_str_appendall(pOut,"float"); break;
+ case JSONB_FLOAT5: sqlite3_str_appendall(pOut,"float5"); break;
+ case JSONB_TEXT: sqlite3_str_appendall(pOut,"text"); break;
+ case JSONB_TEXTJ: sqlite3_str_appendall(pOut,"textj"); break;
+ case JSONB_TEXT5: sqlite3_str_appendall(pOut,"text5"); break;
+ case JSONB_TEXTRAW: sqlite3_str_appendall(pOut,"textraw"); break;
+ case JSONB_ARRAY: {
+ sqlite3_str_appendf(pOut,"array, %u bytes\n", sz);
+ jsonDebugPrintBlob(pParse, iStart+n, iStart+n+sz, nIndent+2, pOut);
+ showContent = 0;
+ break;
+ }
+ case JSONB_OBJECT: {
+ sqlite3_str_appendf(pOut, "object, %u bytes\n", sz);
+ jsonDebugPrintBlob(pParse, iStart+n, iStart+n+sz, nIndent+2, pOut);
+ showContent = 0;
+ break;
+ }
+ default: {
+ sqlite3_str_appendall(pOut, "ERROR: unknown node type\n");
+ showContent = 0;
+ break;
+ }
}
- jsonAppendRaw(&s, "\n", 1);
+ if( showContent ){
+ if( sz==0 && x<=JSONB_FALSE ){
+ sqlite3_str_append(pOut, "\n", 1);
+ }else{
+ u32 j;
+ sqlite3_str_appendall(pOut, ": \"");
+ for(j=iStart+n; j<iStart+n+sz; j++){
+ u8 c = pParse->aBlob[j];
+ if( c<0x20 || c>=0x7f ) c = '.';
+ sqlite3_str_append(pOut, (char*)&c, 1);
+ }
+ sqlite3_str_append(pOut, "\"\n", 2);
+ }
+ }
+ iStart += n + sz;
}
- jsonParseReset(&x);
- jsonResult(&s);
}
+static void jsonShowParse(JsonParse *pParse){
+ sqlite3_str out;
+ char zBuf[1000];
+ if( pParse==0 ){
+ printf("NULL pointer\n");
+ return;
+ }else{
+ printf("nBlobAlloc = %u\n", pParse->nBlobAlloc);
+ printf("nBlob = %u\n", pParse->nBlob);
+ printf("delta = %d\n", pParse->delta);
+ if( pParse->nBlob==0 ) return;
+ printf("content (bytes 0..%u):\n", pParse->nBlob-1);
+ }
+ sqlite3StrAccumInit(&out, 0, zBuf, sizeof(zBuf), 1000000);
+ jsonDebugPrintBlob(pParse, 0, pParse->nBlob, 0, &out);
+ printf("%s", sqlite3_str_value(&out));
+ sqlite3_str_reset(&out);
+}
+#endif /* SQLITE_DEBUG */
+#ifdef SQLITE_DEBUG
/*
-** The json_test1(JSON) function return true (1) if the input is JSON
-** text generated by another json function. It returns (0) if the input
-** is not known to be JSON.
+** SQL function: json_parse(JSON)
+**
+** Parse JSON using jsonParseFuncArg(). Return text that is a
+** human-readable dump of the binary JSONB for the input parameter.
*/
-static void jsonTest1Func(
+static void jsonParseFunc(
sqlite3_context *ctx,
int argc,
sqlite3_value **argv
){
- UNUSED_PARAMETER(argc);
- sqlite3_result_int(ctx, sqlite3_value_subtype(argv[0])==JSON_SUBTYPE);
+ JsonParse *p; /* The parse */
+ sqlite3_str out;
+
+ assert( argc>=1 );
+ sqlite3StrAccumInit(&out, 0, 0, 0, 1000000);
+ p = jsonParseFuncArg(ctx, argv[0], 0);
+ if( p==0 ) return;
+ if( argc==1 ){
+ jsonDebugPrintBlob(p, 0, p->nBlob, 0, &out);
+ sqlite3_result_text64(ctx, out.zText, out.nChar, SQLITE_DYNAMIC, SQLITE_UTF8);
+ }else{
+ jsonShowParse(p);
+ }
+ jsonParseFree(p);
}
#endif /* SQLITE_DEBUG */
@@ -200186,7 +206980,7 @@ static void jsonTest1Func(
****************************************************************************/
/*
-** Implementation of the json_QUOTE(VALUE) function. Return a JSON value
+** 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.
@@ -200199,9 +206993,9 @@ static void jsonQuoteFunc(
JsonString jx;
UNUSED_PARAMETER(argc);
- jsonInit(&jx, ctx);
- jsonAppendValue(&jx, argv[0]);
- jsonResult(&jx);
+ jsonStringInit(&jx, ctx);
+ jsonAppendSqlValue(&jx, argv[0]);
+ jsonReturnString(&jx, 0, 0);
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
@@ -200218,18 +207012,17 @@ static void jsonArrayFunc(
int i;
JsonString jx;
- jsonInit(&jx, ctx);
+ jsonStringInit(&jx, ctx);
jsonAppendChar(&jx, '[');
for(i=0; i<argc; i++){
jsonAppendSeparator(&jx);
- jsonAppendValue(&jx, argv[i]);
+ jsonAppendSqlValue(&jx, argv[i]);
}
jsonAppendChar(&jx, ']');
- jsonResult(&jx);
+ jsonReturnString(&jx, 0, 0);
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
-
/*
** json_array_length(JSON)
** json_array_length(JSON, PATH)
@@ -200243,39 +207036,53 @@ static void jsonArrayLengthFunc(
sqlite3_value **argv
){
JsonParse *p; /* The parse */
- sqlite3_int64 n = 0;
+ sqlite3_int64 cnt = 0;
u32 i;
- JsonNode *pNode;
+ u8 eErr = 0;
- p = jsonParseCached(ctx, argv, ctx);
+ p = jsonParseFuncArg(ctx, argv[0], 0);
if( p==0 ) return;
- assert( p->nNode );
if( argc==2 ){
const char *zPath = (const char*)sqlite3_value_text(argv[1]);
- pNode = jsonLookup(p, zPath, 0, ctx);
+ if( zPath==0 ){
+ jsonParseFree(p);
+ return;
+ }
+ i = jsonLookupStep(p, 0, zPath[0]=='$' ? zPath+1 : "@", 0);
+ if( JSON_LOOKUP_ISERROR(i) ){
+ if( i==JSON_LOOKUP_NOTFOUND ){
+ /* no-op */
+ }else if( i==JSON_LOOKUP_PATHERROR ){
+ jsonBadPathError(ctx, zPath);
+ }else{
+ sqlite3_result_error(ctx, "malformed JSON", -1);
+ }
+ eErr = 1;
+ i = 0;
+ }
}else{
- pNode = p->aNode;
- }
- if( pNode==0 ){
- return;
+ i = 0;
}
- if( pNode->eType==JSON_ARRAY ){
- assert( (pNode->jnFlags & JNODE_APPEND)==0 );
- for(i=1; i<=pNode->n; n++){
- i += jsonNodeSize(&pNode[i]);
- }
+ if( (p->aBlob[i] & 0x0f)==JSONB_ARRAY ){
+ cnt = jsonbArrayCount(p, i);
}
- sqlite3_result_int64(ctx, n);
+ if( !eErr ) sqlite3_result_int64(ctx, cnt);
+ jsonParseFree(p);
}
-/*
-** Bit values for the flags passed into jsonExtractFunc() or
-** jsonSetFunc() via the user-data value.
-*/
-#define JSON_JSON 0x01 /* Result is always JSON */
-#define JSON_SQL 0x02 /* Result is always SQL */
-#define JSON_ABPATH 0x03 /* Allow abbreviated JSON path specs */
-#define JSON_ISSET 0x04 /* json_set(), not json_insert() */
+/* True if the string is all digits */
+static int jsonAllDigits(const char *z, int n){
+ int i;
+ for(i=0; i<n && sqlite3Isdigit(z[i]); i++){}
+ return i==n;
+}
+
+/* True if the string is all alphanumerics and underscores */
+static int jsonAllAlphanum(const char *z, int n){
+ int i;
+ for(i=0; i<n && (sqlite3Isalnum(z[i]) || z[i]=='_'); i++){}
+ return i==n;
+}
/*
** json_extract(JSON, PATH, ...)
@@ -200302,161 +207109,307 @@ static void jsonExtractFunc(
int argc,
sqlite3_value **argv
){
- JsonParse *p; /* The parse */
- JsonNode *pNode;
- const char *zPath;
- int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
- JsonString jx;
+ JsonParse *p = 0; /* The parse */
+ int flags; /* Flags associated with the function */
+ int i; /* Loop counter */
+ JsonString jx; /* String for array result */
if( argc<2 ) return;
- p = jsonParseCached(ctx, argv, ctx);
+ p = jsonParseFuncArg(ctx, argv[0], 0);
if( p==0 ) return;
- if( argc==2 ){
+ flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
+ jsonStringInit(&jx, ctx);
+ if( argc>2 ){
+ jsonAppendChar(&jx, '[');
+ }
+ for(i=1; i<argc; i++){
/* With a single PATH argument */
- zPath = (const char*)sqlite3_value_text(argv[1]);
- if( zPath==0 ) return;
- if( flags & JSON_ABPATH ){
- if( zPath[0]!='$' ){
- /* The -> and ->> operators accept abbreviated PATH arguments. This
- ** is mostly for compatibility with PostgreSQL, but also for
- ** convenience.
- **
- ** NUMBER ==> $[NUMBER] // PG compatible
- ** LABEL ==> $.LABEL // PG compatible
- ** [NUMBER] ==> $[NUMBER] // Not PG. Purely for convenience
- */
- jsonInit(&jx, ctx);
- if( sqlite3Isdigit(zPath[0]) ){
- jsonAppendRaw(&jx, "$[", 2);
- jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
- jsonAppendRaw(&jx, "]", 2);
- }else{
- jsonAppendRaw(&jx, "$.", 1 + (zPath[0]!='['));
- jsonAppendRaw(&jx, zPath, (int)strlen(zPath));
- jsonAppendChar(&jx, 0);
- }
- pNode = jx.bErr ? 0 : jsonLookup(p, jx.zBuf, 0, ctx);
- jsonReset(&jx);
+ const char *zPath = (const char*)sqlite3_value_text(argv[i]);
+ int nPath;
+ u32 j;
+ if( zPath==0 ) goto json_extract_error;
+ nPath = sqlite3Strlen30(zPath);
+ if( zPath[0]=='$' ){
+ j = jsonLookupStep(p, 0, zPath+1, 0);
+ }else if( (flags & JSON_ABPATH) ){
+ /* The -> and ->> operators accept abbreviated PATH arguments. This
+ ** is mostly for compatibility with PostgreSQL, but also for
+ ** convenience.
+ **
+ ** NUMBER ==> $[NUMBER] // PG compatible
+ ** LABEL ==> $.LABEL // PG compatible
+ ** [NUMBER] ==> $[NUMBER] // Not PG. Purely for convenience
+ */
+ jsonStringInit(&jx, ctx);
+ if( jsonAllDigits(zPath, nPath) ){
+ jsonAppendRawNZ(&jx, "[", 1);
+ jsonAppendRaw(&jx, zPath, nPath);
+ jsonAppendRawNZ(&jx, "]", 2);
+ }else if( jsonAllAlphanum(zPath, nPath) ){
+ jsonAppendRawNZ(&jx, ".", 1);
+ jsonAppendRaw(&jx, zPath, nPath);
+ }else if( zPath[0]=='[' && nPath>=3 && zPath[nPath-1]==']' ){
+ jsonAppendRaw(&jx, zPath, nPath);
}else{
- pNode = jsonLookup(p, zPath, 0, ctx);
+ jsonAppendRawNZ(&jx, ".\"", 2);
+ jsonAppendRaw(&jx, zPath, nPath);
+ jsonAppendRawNZ(&jx, "\"", 1);
}
- if( pNode ){
+ jsonStringTerminate(&jx);
+ j = jsonLookupStep(p, 0, jx.zBuf, 0);
+ jsonStringReset(&jx);
+ }else{
+ jsonBadPathError(ctx, zPath);
+ goto json_extract_error;
+ }
+ if( j<p->nBlob ){
+ if( argc==2 ){
if( flags & JSON_JSON ){
- jsonReturnJson(pNode, ctx, 0);
+ jsonStringInit(&jx, ctx);
+ jsonTranslateBlobToText(p, j, &jx);
+ jsonReturnString(&jx, 0, 0);
+ jsonStringReset(&jx);
+ assert( (flags & JSON_BLOB)==0 );
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}else{
- jsonReturn(pNode, ctx, 0);
- sqlite3_result_subtype(ctx, 0);
+ jsonReturnFromBlob(p, j, ctx, 0);
+ if( (flags & (JSON_SQL|JSON_BLOB))==0
+ && (p->aBlob[j]&0x0f)>=JSONB_ARRAY
+ ){
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+ }
}
+ }else{
+ jsonAppendSeparator(&jx);
+ jsonTranslateBlobToText(p, j, &jx);
}
- }else{
- pNode = jsonLookup(p, zPath, 0, ctx);
- if( p->nErr==0 && pNode ) jsonReturn(pNode, ctx, 0);
- }
- }else{
- /* Two or more PATH arguments results in a JSON array with each
- ** element of the array being the value selected by one of the PATHs */
- int i;
- jsonInit(&jx, ctx);
- jsonAppendChar(&jx, '[');
- for(i=1; i<argc; i++){
- zPath = (const char*)sqlite3_value_text(argv[i]);
- pNode = jsonLookup(p, zPath, 0, ctx);
- if( p->nErr ) break;
- jsonAppendSeparator(&jx);
- if( pNode ){
- jsonRenderNode(pNode, &jx, 0);
+ }else if( j==JSON_LOOKUP_NOTFOUND ){
+ if( argc==2 ){
+ goto json_extract_error; /* Return NULL if not found */
}else{
- jsonAppendRaw(&jx, "null", 4);
+ jsonAppendSeparator(&jx);
+ jsonAppendRawNZ(&jx, "null", 4);
}
+ }else if( j==JSON_LOOKUP_ERROR ){
+ sqlite3_result_error(ctx, "malformed JSON", -1);
+ goto json_extract_error;
+ }else{
+ jsonBadPathError(ctx, zPath);
+ goto json_extract_error;
}
- if( i==argc ){
- jsonAppendChar(&jx, ']');
- jsonResult(&jx);
+ }
+ if( argc>2 ){
+ jsonAppendChar(&jx, ']');
+ jsonReturnString(&jx, 0, 0);
+ if( (flags & JSON_BLOB)==0 ){
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
- jsonReset(&jx);
}
+json_extract_error:
+ jsonStringReset(&jx);
+ jsonParseFree(p);
+ return;
}
-/* This is the RFC 7396 MergePatch algorithm.
-*/
-static JsonNode *jsonMergePatch(
- JsonParse *pParse, /* The JSON parser that contains the TARGET */
- u32 iTarget, /* Node of the TARGET in pParse */
- JsonNode *pPatch /* The PATCH */
-){
- u32 i, j;
- u32 iRoot;
- JsonNode *pTarget;
- if( pPatch->eType!=JSON_OBJECT ){
- return pPatch;
- }
- assert( iTarget<pParse->nNode );
- pTarget = &pParse->aNode[iTarget];
- assert( (pPatch->jnFlags & JNODE_APPEND)==0 );
- if( pTarget->eType!=JSON_OBJECT ){
- jsonRemoveAllNulls(pPatch);
- return pPatch;
- }
- iRoot = iTarget;
- for(i=1; i<pPatch->n; i += jsonNodeSize(&pPatch[i+1])+1){
- u32 nKey;
- const char *zKey;
- assert( pPatch[i].eType==JSON_STRING );
- assert( pPatch[i].jnFlags & JNODE_LABEL );
- assert( pPatch[i].eU==1 );
- nKey = pPatch[i].n;
- zKey = pPatch[i].u.zJContent;
- assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
- for(j=1; j<pTarget->n; j += jsonNodeSize(&pTarget[j+1])+1 ){
- assert( pTarget[j].eType==JSON_STRING );
- assert( pTarget[j].jnFlags & JNODE_LABEL );
- assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
- if( pTarget[j].n==nKey && strncmp(pTarget[j].u.zJContent,zKey,nKey)==0 ){
- if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_PATCH) ) break;
- if( pPatch[i+1].eType==JSON_NULL ){
- pTarget[j+1].jnFlags |= JNODE_REMOVE;
- }else{
- JsonNode *pNew = jsonMergePatch(pParse, iTarget+j+1, &pPatch[i+1]);
- if( pNew==0 ) return 0;
- pTarget = &pParse->aNode[iTarget];
- if( pNew!=&pTarget[j+1] ){
- assert( pTarget[j+1].eU==0
- || pTarget[j+1].eU==1
- || pTarget[j+1].eU==2 );
- testcase( pTarget[j+1].eU==1 );
- testcase( pTarget[j+1].eU==2 );
- VVA( pTarget[j+1].eU = 5 );
- pTarget[j+1].u.pPatch = pNew;
- pTarget[j+1].jnFlags |= JNODE_PATCH;
- }
- }
- break;
+/*
+** Return codes for jsonMergePatch()
+*/
+#define JSON_MERGE_OK 0 /* Success */
+#define JSON_MERGE_BADTARGET 1 /* Malformed TARGET blob */
+#define JSON_MERGE_BADPATCH 2 /* Malformed PATCH blob */
+#define JSON_MERGE_OOM 3 /* Out-of-memory condition */
+
+/*
+** RFC-7396 MergePatch for two JSONB blobs.
+**
+** pTarget is the target. pPatch is the patch. The target is updated
+** in place. The patch is read-only.
+**
+** The original RFC-7396 algorithm is this:
+**
+** define MergePatch(Target, Patch):
+** if Patch is an Object:
+** if Target is not an Object:
+** Target = {} # Ignore the contents and set it to an empty Object
+** for each Name/Value pair in Patch:
+** if Value is null:
+** if Name exists in Target:
+** remove the Name/Value pair from Target
+** else:
+** Target[Name] = MergePatch(Target[Name], Value)
+** return Target
+** else:
+** return Patch
+**
+** Here is an equivalent algorithm restructured to show the actual
+** implementation:
+**
+** 01 define MergePatch(Target, Patch):
+** 02 if Patch is not an Object:
+** 03 return Patch
+** 04 else: // if Patch is an Object
+** 05 if Target is not an Object:
+** 06 Target = {}
+** 07 for each Name/Value pair in Patch:
+** 08 if Name exists in Target:
+** 09 if Value is null:
+** 10 remove the Name/Value pair from Target
+** 11 else
+** 12 Target[name] = MergePatch(Target[Name], Value)
+** 13 else if Value is not NULL:
+** 14 if Value is not an Object:
+** 15 Target[name] = Value
+** 16 else:
+** 17 Target[name] = MergePatch('{}',value)
+** 18 return Target
+** |
+** ^---- Line numbers referenced in comments in the implementation
+*/
+static int jsonMergePatch(
+ JsonParse *pTarget, /* The JSON parser that contains the TARGET */
+ u32 iTarget, /* Index of TARGET in pTarget->aBlob[] */
+ const JsonParse *pPatch, /* The PATCH */
+ u32 iPatch /* Index of PATCH in pPatch->aBlob[] */
+){
+ u8 x; /* Type of a single node */
+ u32 n, sz=0; /* Return values from jsonbPayloadSize() */
+ u32 iTCursor; /* Cursor position while scanning the target object */
+ u32 iTStart; /* First label in the target object */
+ u32 iTEndBE; /* Original first byte past end of target, before edit */
+ u32 iTEnd; /* Current first byte past end of target */
+ u8 eTLabel; /* Node type of the target label */
+ u32 iTLabel = 0; /* Index of the label */
+ u32 nTLabel = 0; /* Header size in bytes for the target label */
+ u32 szTLabel = 0; /* Size of the target label payload */
+ u32 iTValue = 0; /* Index of the target value */
+ u32 nTValue = 0; /* Header size of the target value */
+ u32 szTValue = 0; /* Payload size for the target value */
+
+ u32 iPCursor; /* Cursor position while scanning the patch */
+ u32 iPEnd; /* First byte past the end of the patch */
+ u8 ePLabel; /* Node type of the patch label */
+ u32 iPLabel; /* Start of patch label */
+ u32 nPLabel; /* Size of header on the patch label */
+ u32 szPLabel; /* Payload size of the patch label */
+ u32 iPValue; /* Start of patch value */
+ u32 nPValue; /* Header size for the patch value */
+ u32 szPValue; /* Payload size of the patch value */
+
+ assert( iTarget>=0 && iTarget<pTarget->nBlob );
+ assert( iPatch>=0 && iPatch<pPatch->nBlob );
+ x = pPatch->aBlob[iPatch] & 0x0f;
+ if( x!=JSONB_OBJECT ){ /* Algorithm line 02 */
+ u32 szPatch; /* Total size of the patch, header+payload */
+ u32 szTarget; /* Total size of the target, header+payload */
+ n = jsonbPayloadSize(pPatch, iPatch, &sz);
+ szPatch = n+sz;
+ sz = 0;
+ n = jsonbPayloadSize(pTarget, iTarget, &sz);
+ szTarget = n+sz;
+ jsonBlobEdit(pTarget, iTarget, szTarget, pPatch->aBlob+iPatch, szPatch);
+ return pTarget->oom ? JSON_MERGE_OOM : JSON_MERGE_OK; /* Line 03 */
+ }
+ x = pTarget->aBlob[iTarget] & 0x0f;
+ if( x!=JSONB_OBJECT ){ /* Algorithm line 05 */
+ n = jsonbPayloadSize(pTarget, iTarget, &sz);
+ jsonBlobEdit(pTarget, iTarget+n, sz, 0, 0);
+ x = pTarget->aBlob[iTarget];
+ pTarget->aBlob[iTarget] = (x & 0xf0) | JSONB_OBJECT;
+ }
+ n = jsonbPayloadSize(pPatch, iPatch, &sz);
+ if( NEVER(n==0) ) return JSON_MERGE_BADPATCH;
+ iPCursor = iPatch+n;
+ iPEnd = iPCursor+sz;
+ n = jsonbPayloadSize(pTarget, iTarget, &sz);
+ if( NEVER(n==0) ) return JSON_MERGE_BADTARGET;
+ iTStart = iTarget+n;
+ iTEndBE = iTStart+sz;
+
+ while( iPCursor<iPEnd ){ /* Algorithm line 07 */
+ iPLabel = iPCursor;
+ ePLabel = pPatch->aBlob[iPCursor] & 0x0f;
+ if( ePLabel<JSONB_TEXT || ePLabel>JSONB_TEXTRAW ){
+ return JSON_MERGE_BADPATCH;
+ }
+ nPLabel = jsonbPayloadSize(pPatch, iPCursor, &szPLabel);
+ if( nPLabel==0 ) return JSON_MERGE_BADPATCH;
+ iPValue = iPCursor + nPLabel + szPLabel;
+ if( iPValue>=iPEnd ) return JSON_MERGE_BADPATCH;
+ nPValue = jsonbPayloadSize(pPatch, iPValue, &szPValue);
+ if( nPValue==0 ) return JSON_MERGE_BADPATCH;
+ iPCursor = iPValue + nPValue + szPValue;
+ if( iPCursor>iPEnd ) return JSON_MERGE_BADPATCH;
+
+ iTCursor = iTStart;
+ iTEnd = iTEndBE + pTarget->delta;
+ while( iTCursor<iTEnd ){
+ int isEqual; /* true if the patch and target labels match */
+ iTLabel = iTCursor;
+ eTLabel = pTarget->aBlob[iTCursor] & 0x0f;
+ if( eTLabel<JSONB_TEXT || eTLabel>JSONB_TEXTRAW ){
+ return JSON_MERGE_BADTARGET;
+ }
+ nTLabel = jsonbPayloadSize(pTarget, iTCursor, &szTLabel);
+ if( nTLabel==0 ) return JSON_MERGE_BADTARGET;
+ iTValue = iTLabel + nTLabel + szTLabel;
+ if( iTValue>=iTEnd ) return JSON_MERGE_BADTARGET;
+ nTValue = jsonbPayloadSize(pTarget, iTValue, &szTValue);
+ if( nTValue==0 ) return JSON_MERGE_BADTARGET;
+ if( iTValue + nTValue + szTValue > iTEnd ) return JSON_MERGE_BADTARGET;
+ isEqual = jsonLabelCompare(
+ (const char*)&pPatch->aBlob[iPLabel+nPLabel],
+ szPLabel,
+ (ePLabel==JSONB_TEXT || ePLabel==JSONB_TEXTRAW),
+ (const char*)&pTarget->aBlob[iTLabel+nTLabel],
+ szTLabel,
+ (eTLabel==JSONB_TEXT || eTLabel==JSONB_TEXTRAW));
+ if( isEqual ) break;
+ iTCursor = iTValue + nTValue + szTValue;
+ }
+ x = pPatch->aBlob[iPValue] & 0x0f;
+ if( iTCursor<iTEnd ){
+ /* A match was found. Algorithm line 08 */
+ if( x==0 ){
+ /* Patch value is NULL. Algorithm line 09 */
+ jsonBlobEdit(pTarget, iTLabel, nTLabel+szTLabel+nTValue+szTValue, 0,0);
+ /* vvvvvv----- No OOM on a delete-only edit */
+ if( NEVER(pTarget->oom) ) return JSON_MERGE_OOM;
+ }else{
+ /* Algorithm line 12 */
+ int rc, savedDelta = pTarget->delta;
+ pTarget->delta = 0;
+ rc = jsonMergePatch(pTarget, iTValue, pPatch, iPValue);
+ if( rc ) return rc;
+ pTarget->delta += savedDelta;
+ }
+ }else if( x>0 ){ /* Algorithm line 13 */
+ /* No match and patch value is not NULL */
+ u32 szNew = szPLabel+nPLabel;
+ if( (pPatch->aBlob[iPValue] & 0x0f)!=JSONB_OBJECT ){ /* Line 14 */
+ jsonBlobEdit(pTarget, iTEnd, 0, 0, szPValue+nPValue+szNew);
+ if( pTarget->oom ) return JSON_MERGE_OOM;
+ memcpy(&pTarget->aBlob[iTEnd], &pPatch->aBlob[iPLabel], szNew);
+ memcpy(&pTarget->aBlob[iTEnd+szNew],
+ &pPatch->aBlob[iPValue], szPValue+nPValue);
+ }else{
+ int rc, savedDelta;
+ jsonBlobEdit(pTarget, iTEnd, 0, 0, szNew+1);
+ if( pTarget->oom ) return JSON_MERGE_OOM;
+ memcpy(&pTarget->aBlob[iTEnd], &pPatch->aBlob[iPLabel], szNew);
+ pTarget->aBlob[iTEnd+szNew] = 0x00;
+ savedDelta = pTarget->delta;
+ pTarget->delta = 0;
+ rc = jsonMergePatch(pTarget, iTEnd+szNew,pPatch,iPValue);
+ if( rc ) return rc;
+ pTarget->delta += savedDelta;
}
}
- if( j>=pTarget->n && pPatch[i+1].eType!=JSON_NULL ){
- int iStart, iPatch;
- iStart = jsonParseAddNode(pParse, JSON_OBJECT, 2, 0);
- jsonParseAddNode(pParse, JSON_STRING, nKey, zKey);
- iPatch = jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
- if( pParse->oom ) return 0;
- jsonRemoveAllNulls(pPatch);
- pTarget = &pParse->aNode[iTarget];
- assert( pParse->aNode[iRoot].eU==0 || pParse->aNode[iRoot].eU==2 );
- testcase( pParse->aNode[iRoot].eU==2 );
- pParse->aNode[iRoot].jnFlags |= JNODE_APPEND;
- VVA( pParse->aNode[iRoot].eU = 2 );
- pParse->aNode[iRoot].u.iAppend = iStart - iRoot;
- iRoot = iStart;
- assert( pParse->aNode[iPatch].eU==0 );
- VVA( pParse->aNode[iPatch].eU = 5 );
- pParse->aNode[iPatch].jnFlags |= JNODE_PATCH;
- pParse->aNode[iPatch].u.pPatch = &pPatch[i+1];
- }
}
- return pTarget;
+ if( pTarget->delta ) jsonAfterEditSizeAdjust(pTarget, iTarget);
+ return pTarget->oom ? JSON_MERGE_OOM : JSON_MERGE_OK;
}
+
/*
** Implementation of the json_mergepatch(JSON1,JSON2) function. Return a JSON
** object that is the result of running the RFC 7396 MergePatch() algorithm
@@ -200467,25 +207420,27 @@ static void jsonPatchFunc(
int argc,
sqlite3_value **argv
){
- JsonParse x; /* The JSON that is being patched */
- JsonParse y; /* The patch */
- JsonNode *pResult; /* The result of the merge */
+ JsonParse *pTarget; /* The TARGET */
+ JsonParse *pPatch; /* The PATCH */
+ int rc; /* Result code */
UNUSED_PARAMETER(argc);
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- if( jsonParse(&y, ctx, (const char*)sqlite3_value_text(argv[1])) ){
- jsonParseReset(&x);
- return;
- }
- pResult = jsonMergePatch(&x, 0, y.aNode);
- assert( pResult!=0 || x.oom );
- if( pResult ){
- jsonReturnJson(pResult, ctx, 0);
- }else{
- sqlite3_result_error_nomem(ctx);
+ assert( argc==2 );
+ pTarget = jsonParseFuncArg(ctx, argv[0], JSON_EDITABLE);
+ if( pTarget==0 ) return;
+ pPatch = jsonParseFuncArg(ctx, argv[1], 0);
+ if( pPatch ){
+ rc = jsonMergePatch(pTarget, 0, pPatch, 0);
+ if( rc==JSON_MERGE_OK ){
+ jsonReturnParse(ctx, pTarget);
+ }else if( rc==JSON_MERGE_OOM ){
+ sqlite3_result_error_nomem(ctx);
+ }else{
+ sqlite3_result_error(ctx, "malformed JSON", -1);
+ }
+ jsonParseFree(pPatch);
}
- jsonParseReset(&x);
- jsonParseReset(&y);
+ jsonParseFree(pTarget);
}
@@ -200509,23 +207464,23 @@ static void jsonObjectFunc(
"of arguments", -1);
return;
}
- jsonInit(&jx, ctx);
+ jsonStringInit(&jx, ctx);
jsonAppendChar(&jx, '{');
for(i=0; i<argc; i+=2){
if( sqlite3_value_type(argv[i])!=SQLITE_TEXT ){
sqlite3_result_error(ctx, "json_object() labels must be TEXT", -1);
- jsonReset(&jx);
+ jsonStringReset(&jx);
return;
}
jsonAppendSeparator(&jx);
z = (const char*)sqlite3_value_text(argv[i]);
- n = (u32)sqlite3_value_bytes(argv[i]);
+ n = sqlite3_value_bytes(argv[i]);
jsonAppendString(&jx, z, n);
jsonAppendChar(&jx, ':');
- jsonAppendValue(&jx, argv[i+1]);
+ jsonAppendSqlValue(&jx, argv[i+1]);
}
jsonAppendChar(&jx, '}');
- jsonResult(&jx);
+ jsonReturnString(&jx, 0, 0);
sqlite3_result_subtype(ctx, JSON_SUBTYPE);
}
@@ -200541,26 +207496,50 @@ static void jsonRemoveFunc(
int argc,
sqlite3_value **argv
){
- JsonParse x; /* The parse */
- JsonNode *pNode;
- const char *zPath;
- u32 i;
+ JsonParse *p; /* The parse */
+ const char *zPath = 0; /* Path of element to be removed */
+ int i; /* Loop counter */
+ u32 rc; /* Subroutine return code */
if( argc<1 ) return;
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
- for(i=1; i<(u32)argc; i++){
+ p = jsonParseFuncArg(ctx, argv[0], argc>1 ? JSON_EDITABLE : 0);
+ if( p==0 ) return;
+ for(i=1; i<argc; i++){
zPath = (const char*)sqlite3_value_text(argv[i]);
- if( zPath==0 ) goto remove_done;
- pNode = jsonLookup(&x, zPath, 0, ctx);
- if( x.nErr ) goto remove_done;
- if( pNode ) pNode->jnFlags |= JNODE_REMOVE;
- }
- if( (x.aNode[0].jnFlags & JNODE_REMOVE)==0 ){
- jsonReturnJson(x.aNode, ctx, 0);
+ if( zPath==0 ){
+ goto json_remove_done;
+ }
+ if( zPath[0]!='$' ){
+ goto json_remove_patherror;
+ }
+ if( zPath[1]==0 ){
+ /* json_remove(j,'$') returns NULL */
+ goto json_remove_done;
+ }
+ p->eEdit = JEDIT_DEL;
+ p->delta = 0;
+ rc = jsonLookupStep(p, 0, zPath+1, 0);
+ if( JSON_LOOKUP_ISERROR(rc) ){
+ if( rc==JSON_LOOKUP_NOTFOUND ){
+ continue; /* No-op */
+ }else if( rc==JSON_LOOKUP_PATHERROR ){
+ jsonBadPathError(ctx, zPath);
+ }else{
+ sqlite3_result_error(ctx, "malformed JSON", -1);
+ }
+ goto json_remove_done;
+ }
}
-remove_done:
- jsonParseReset(&x);
+ jsonReturnParse(ctx, p);
+ jsonParseFree(p);
+ return;
+
+json_remove_patherror:
+ jsonBadPathError(ctx, zPath);
+
+json_remove_done:
+ jsonParseFree(p);
+ return;
}
/*
@@ -200574,38 +207553,12 @@ static void jsonReplaceFunc(
int argc,
sqlite3_value **argv
){
- JsonParse x; /* The parse */
- JsonNode *pNode;
- const char *zPath;
- u32 i;
-
if( argc<1 ) return;
if( (argc&1)==0 ) {
jsonWrongNumArgs(ctx, "replace");
return;
}
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
- for(i=1; i<(u32)argc; i+=2){
- zPath = (const char*)sqlite3_value_text(argv[i]);
- pNode = jsonLookup(&x, zPath, 0, ctx);
- if( x.nErr ) goto replace_err;
- if( pNode ){
- assert( pNode->eU==0 || pNode->eU==1 || pNode->eU==4 );
- testcase( pNode->eU!=0 && pNode->eU!=1 );
- pNode->jnFlags |= (u8)JNODE_REPLACE;
- VVA( pNode->eU = 4 );
- pNode->u.iReplace = i + 1;
- }
- }
- if( x.aNode[0].jnFlags & JNODE_REPLACE ){
- assert( x.aNode[0].eU==4 );
- sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
- }else{
- jsonReturnJson(x.aNode, ctx, argv);
- }
-replace_err:
- jsonParseReset(&x);
+ jsonInsertIntoBlob(ctx, argc, argv, JEDIT_REPL);
}
@@ -200626,45 +207579,16 @@ static void jsonSetFunc(
int argc,
sqlite3_value **argv
){
- JsonParse x; /* The parse */
- JsonNode *pNode;
- const char *zPath;
- u32 i;
- int bApnd;
- int bIsSet = sqlite3_user_data(ctx)!=0;
+
+ int flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
+ int bIsSet = (flags&JSON_ISSET)!=0;
if( argc<1 ) return;
if( (argc&1)==0 ) {
jsonWrongNumArgs(ctx, bIsSet ? "set" : "insert");
return;
}
- if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return;
- assert( x.nNode );
- for(i=1; i<(u32)argc; i+=2){
- zPath = (const char*)sqlite3_value_text(argv[i]);
- bApnd = 0;
- pNode = jsonLookup(&x, zPath, &bApnd, ctx);
- if( x.oom ){
- sqlite3_result_error_nomem(ctx);
- goto jsonSetDone;
- }else if( x.nErr ){
- goto jsonSetDone;
- }else if( pNode && (bApnd || bIsSet) ){
- testcase( pNode->eU!=0 && pNode->eU!=1 );
- assert( pNode->eU!=3 && pNode->eU!=5 );
- VVA( pNode->eU = 4 );
- pNode->jnFlags |= (u8)JNODE_REPLACE;
- pNode->u.iReplace = i + 1;
- }
- }
- if( x.aNode[0].jnFlags & JNODE_REPLACE ){
- assert( x.aNode[0].eU==4 );
- sqlite3_result_value(ctx, argv[x.aNode[0].u.iReplace]);
- }else{
- jsonReturnJson(x.aNode, ctx, argv);
- }
-jsonSetDone:
- jsonParseReset(&x);
+ jsonInsertIntoBlob(ctx, argc, argv, bIsSet ? JEDIT_SET : JEDIT_INS);
}
/*
@@ -200680,27 +207604,93 @@ static void jsonTypeFunc(
sqlite3_value **argv
){
JsonParse *p; /* The parse */
- const char *zPath;
- JsonNode *pNode;
+ const char *zPath = 0;
+ u32 i;
- p = jsonParseCached(ctx, argv, ctx);
+ p = jsonParseFuncArg(ctx, argv[0], 0);
if( p==0 ) return;
if( argc==2 ){
zPath = (const char*)sqlite3_value_text(argv[1]);
- pNode = jsonLookup(p, zPath, 0, ctx);
+ if( zPath==0 ) goto json_type_done;
+ if( zPath[0]!='$' ){
+ jsonBadPathError(ctx, zPath);
+ goto json_type_done;
+ }
+ i = jsonLookupStep(p, 0, zPath+1, 0);
+ if( JSON_LOOKUP_ISERROR(i) ){
+ if( i==JSON_LOOKUP_NOTFOUND ){
+ /* no-op */
+ }else if( i==JSON_LOOKUP_PATHERROR ){
+ jsonBadPathError(ctx, zPath);
+ }else{
+ sqlite3_result_error(ctx, "malformed JSON", -1);
+ }
+ goto json_type_done;
+ }
}else{
- pNode = p->aNode;
- }
- if( pNode ){
- sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC);
+ i = 0;
}
+ sqlite3_result_text(ctx, jsonbType[p->aBlob[i]&0x0f], -1, SQLITE_STATIC);
+json_type_done:
+ jsonParseFree(p);
}
/*
** json_valid(JSON)
-**
-** Return 1 if JSON is a well-formed JSON string according to RFC-7159.
-** Return 0 otherwise.
+** json_valid(JSON, FLAGS)
+**
+** Check the JSON argument to see if it is well-formed. The FLAGS argument
+** encodes the various constraints on what is meant by "well-formed":
+**
+** 0x01 Canonical RFC-8259 JSON text
+** 0x02 JSON text with optional JSON-5 extensions
+** 0x04 Superficially appears to be JSONB
+** 0x08 Strictly well-formed JSONB
+**
+** If the FLAGS argument is omitted, it defaults to 1. Useful values for
+** FLAGS include:
+**
+** 1 Strict canonical JSON text
+** 2 JSON text perhaps with JSON-5 extensions
+** 4 Superficially appears to be JSONB
+** 5 Canonical JSON text or superficial JSONB
+** 6 JSON-5 text or superficial JSONB
+** 8 Strict JSONB
+** 9 Canonical JSON text or strict JSONB
+** 10 JSON-5 text or strict JSONB
+**
+** Other flag combinations are redundant. For example, every canonical
+** JSON text is also well-formed JSON-5 text, so FLAG values 2 and 3
+** are the same. Similarly, any input that passes a strict JSONB validation
+** will also pass the superficial validation so 12 through 15 are the same
+** as 8 through 11 respectively.
+**
+** This routine runs in linear time to validate text and when doing strict
+** JSONB validation. Superficial JSONB validation is constant time,
+** assuming the BLOB is already in memory. The performance advantage
+** of superficial JSONB validation is why that option is provided.
+** Application developers can choose to do fast superficial validation or
+** slower strict validation, according to their specific needs.
+**
+** Only the lower four bits of the FLAGS argument are currently used.
+** Higher bits are reserved for future expansion. To facilitate
+** compatibility, the current implementation raises an error if any bit
+** in FLAGS is set other than the lower four bits.
+**
+** The original circa 2015 implementation of the JSON routines in
+** SQLite only supported canonical RFC-8259 JSON text and the json_valid()
+** function only accepted one argument. That is why the default value
+** for the FLAGS argument is 1, since FLAGS=1 causes this routine to only
+** recognize canonical RFC-8259 JSON text as valid. The extra FLAGS
+** argument was added when the JSON routines were extended to support
+** JSON5-like extensions and binary JSONB stored in BLOBs.
+**
+** Return Values:
+**
+** * Raise an error if FLAGS is outside the range of 1 to 15.
+** * Return NULL if the input is NULL
+** * Return 1 if the input is well-formed.
+** * Return 0 if the input is not well-formed.
*/
static void jsonValidFunc(
sqlite3_context *ctx,
@@ -200708,11 +207698,127 @@ static void jsonValidFunc(
sqlite3_value **argv
){
JsonParse *p; /* The parse */
- UNUSED_PARAMETER(argc);
- p = jsonParseCached(ctx, argv, 0);
- sqlite3_result_int(ctx, p!=0);
+ u8 flags = 1;
+ u8 res = 0;
+ if( argc==2 ){
+ i64 f = sqlite3_value_int64(argv[1]);
+ if( f<1 || f>15 ){
+ sqlite3_result_error(ctx, "FLAGS parameter to json_valid() must be"
+ " between 1 and 15", -1);
+ return;
+ }
+ flags = f & 0x0f;
+ }
+ switch( sqlite3_value_type(argv[0]) ){
+ case SQLITE_NULL: {
+#ifdef SQLITE_LEGACY_JSON_VALID
+ /* Incorrect legacy behavior was to return FALSE for a NULL input */
+ sqlite3_result_int(ctx, 0);
+#endif
+ return;
+ }
+ case SQLITE_BLOB: {
+ if( jsonFuncArgMightBeBinary(argv[0]) ){
+ if( flags & 0x04 ){
+ /* Superficial checking only - accomplished by the
+ ** jsonFuncArgMightBeBinary() call above. */
+ res = 1;
+ }else if( flags & 0x08 ){
+ /* Strict checking. Check by translating BLOB->TEXT->BLOB. If
+ ** no errors occur, call that a "strict check". */
+ JsonParse px;
+ u32 iErr;
+ memset(&px, 0, sizeof(px));
+ px.aBlob = (u8*)sqlite3_value_blob(argv[0]);
+ px.nBlob = sqlite3_value_bytes(argv[0]);
+ iErr = jsonbValidityCheck(&px, 0, px.nBlob, 1);
+ res = iErr==0;
+ }
+ break;
+ }
+ /* Fall through into interpreting the input as text. See note
+ ** above at tag-20240123-a. */
+ /* no break */ deliberate_fall_through
+ }
+ default: {
+ JsonParse px;
+ if( (flags & 0x3)==0 ) break;
+ memset(&px, 0, sizeof(px));
+
+ p = jsonParseFuncArg(ctx, argv[0], JSON_KEEPERROR);
+ if( p ){
+ if( p->oom ){
+ sqlite3_result_error_nomem(ctx);
+ }else if( p->nErr ){
+ /* no-op */
+ }else if( (flags & 0x02)!=0 || p->hasNonstd==0 ){
+ res = 1;
+ }
+ jsonParseFree(p);
+ }else{
+ sqlite3_result_error_nomem(ctx);
+ }
+ break;
+ }
+ }
+ sqlite3_result_int(ctx, res);
}
+/*
+** json_error_position(JSON)
+**
+** If the argument is NULL, return NULL
+**
+** If the argument is BLOB, do a full validity check and return non-zero
+** if the check fails. The return value is the approximate 1-based offset
+** to the byte of the element that contains the first error.
+**
+** Otherwise interpret the argument is TEXT (even if it is numeric) and
+** return the 1-based character position for where the parser first recognized
+** that the input was not valid JSON, or return 0 if the input text looks
+** ok. JSON-5 extensions are accepted.
+*/
+static void jsonErrorFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ i64 iErrPos = 0; /* Error position to be returned */
+ JsonParse s;
+
+ assert( argc==1 );
+ UNUSED_PARAMETER(argc);
+ memset(&s, 0, sizeof(s));
+ s.db = sqlite3_context_db_handle(ctx);
+ if( jsonFuncArgMightBeBinary(argv[0]) ){
+ s.aBlob = (u8*)sqlite3_value_blob(argv[0]);
+ s.nBlob = sqlite3_value_bytes(argv[0]);
+ iErrPos = (i64)jsonbValidityCheck(&s, 0, s.nBlob, 1);
+ }else{
+ s.zJson = (char*)sqlite3_value_text(argv[0]);
+ if( s.zJson==0 ) return; /* NULL input or OOM */
+ s.nJson = sqlite3_value_bytes(argv[0]);
+ if( jsonConvertTextToBlob(&s,0) ){
+ if( s.oom ){
+ iErrPos = -1;
+ }else{
+ /* Convert byte-offset s.iErr into a character offset */
+ u32 k;
+ assert( s.zJson!=0 ); /* Because s.oom is false */
+ for(k=0; k<s.iErr && ALWAYS(s.zJson[k]); k++){
+ if( (s.zJson[k] & 0xc0)!=0x80 ) iErrPos++;
+ }
+ iErrPos++;
+ }
+ }
+ }
+ jsonParseReset(&s);
+ if( iErrPos<0 ){
+ sqlite3_result_error_nomem(ctx);
+ }else{
+ sqlite3_result_int64(ctx, iErrPos);
+ }
+}
/****************************************************************************
** Aggregate SQL function implementations
@@ -200732,31 +207838,42 @@ static void jsonArrayStep(
pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
if( pStr ){
if( pStr->zBuf==0 ){
- jsonInit(pStr, ctx);
+ jsonStringInit(pStr, ctx);
jsonAppendChar(pStr, '[');
}else if( pStr->nUsed>1 ){
jsonAppendChar(pStr, ',');
}
pStr->pCtx = ctx;
- jsonAppendValue(pStr, argv[0]);
+ jsonAppendSqlValue(pStr, argv[0]);
}
}
static void jsonArrayCompute(sqlite3_context *ctx, int isFinal){
JsonString *pStr;
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
if( pStr ){
+ int flags;
pStr->pCtx = ctx;
jsonAppendChar(pStr, ']');
- if( pStr->bErr ){
- if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
- assert( pStr->bStatic );
+ flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
+ if( pStr->eErr ){
+ jsonReturnString(pStr, 0, 0);
+ return;
+ }else if( flags & JSON_BLOB ){
+ jsonReturnStringAsBlob(pStr);
+ if( isFinal ){
+ if( !pStr->bStatic ) sqlite3RCStrUnref(pStr->zBuf);
+ }else{
+ jsonStringTrimOneChar(pStr);
+ }
+ return;
}else if( isFinal ){
sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed,
- pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
+ pStr->bStatic ? SQLITE_TRANSIENT :
+ sqlite3RCStrUnref);
pStr->bStatic = 1;
}else{
sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
- pStr->nUsed--;
+ jsonStringTrimOneChar(pStr);
}
}else{
sqlite3_result_text(ctx, "[]", 2, SQLITE_STATIC);
@@ -200793,7 +207910,7 @@ static void jsonGroupInverse(
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
#ifdef NEVER
/* pStr is always non-NULL since jsonArrayStep() or jsonObjectStep() will
- ** always have been called to initalize it */
+ ** always have been called to initialize it */
if( NEVER(!pStr) ) return;
#endif
z = pStr->zBuf;
@@ -200837,34 +207954,46 @@ static void jsonObjectStep(
pStr = (JsonString*)sqlite3_aggregate_context(ctx, sizeof(*pStr));
if( pStr ){
if( pStr->zBuf==0 ){
- jsonInit(pStr, ctx);
+ jsonStringInit(pStr, ctx);
jsonAppendChar(pStr, '{');
}else if( pStr->nUsed>1 ){
jsonAppendChar(pStr, ',');
}
pStr->pCtx = ctx;
z = (const char*)sqlite3_value_text(argv[0]);
- n = (u32)sqlite3_value_bytes(argv[0]);
+ n = sqlite3Strlen30(z);
jsonAppendString(pStr, z, n);
jsonAppendChar(pStr, ':');
- jsonAppendValue(pStr, argv[1]);
+ jsonAppendSqlValue(pStr, argv[1]);
}
}
static void jsonObjectCompute(sqlite3_context *ctx, int isFinal){
JsonString *pStr;
pStr = (JsonString*)sqlite3_aggregate_context(ctx, 0);
if( pStr ){
+ int flags;
jsonAppendChar(pStr, '}');
- if( pStr->bErr ){
- if( pStr->bErr==1 ) sqlite3_result_error_nomem(ctx);
- assert( pStr->bStatic );
+ pStr->pCtx = ctx;
+ flags = SQLITE_PTR_TO_INT(sqlite3_user_data(ctx));
+ if( pStr->eErr ){
+ jsonReturnString(pStr, 0, 0);
+ return;
+ }else if( flags & JSON_BLOB ){
+ jsonReturnStringAsBlob(pStr);
+ if( isFinal ){
+ if( !pStr->bStatic ) sqlite3RCStrUnref(pStr->zBuf);
+ }else{
+ jsonStringTrimOneChar(pStr);
+ }
+ return;
}else if( isFinal ){
sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed,
- pStr->bStatic ? SQLITE_TRANSIENT : sqlite3_free);
+ pStr->bStatic ? SQLITE_TRANSIENT :
+ sqlite3RCStrUnref);
pStr->bStatic = 1;
}else{
sqlite3_result_text(ctx, pStr->zBuf, (int)pStr->nUsed, SQLITE_TRANSIENT);
- pStr->nUsed--;
+ jsonStringTrimOneChar(pStr);
}
}else{
sqlite3_result_text(ctx, "{}", 2, SQLITE_STATIC);
@@ -200884,19 +208013,37 @@ static void jsonObjectFinal(sqlite3_context *ctx){
/****************************************************************************
** The json_each virtual table
****************************************************************************/
+typedef struct JsonParent JsonParent;
+struct JsonParent {
+ u32 iHead; /* Start of object or array */
+ u32 iValue; /* Start of the value */
+ u32 iEnd; /* First byte past the end */
+ u32 nPath; /* Length of path */
+ i64 iKey; /* Key for JSONB_ARRAY */
+};
+
typedef struct JsonEachCursor JsonEachCursor;
struct JsonEachCursor {
sqlite3_vtab_cursor base; /* Base class - must be first */
u32 iRowid; /* The rowid */
- u32 iBegin; /* The first node of the scan */
- u32 i; /* Index in sParse.aNode[] of current row */
+ u32 i; /* Index in sParse.aBlob[] of current row */
u32 iEnd; /* EOF when i equals or exceeds this value */
- u8 eType; /* Type of top-level element */
+ u32 nRoot; /* Size of the root path in bytes */
+ u8 eType; /* Type of the container for element i */
u8 bRecursive; /* True for json_tree(). False for json_each() */
- char *zJson; /* Input JSON */
- char *zRoot; /* Path by which to filter zJson */
+ u32 nParent; /* Current nesting depth */
+ u32 nParentAlloc; /* Space allocated for aParent[] */
+ JsonParent *aParent; /* Parent elements of i */
+ sqlite3 *db; /* Database connection */
+ JsonString path; /* Current path */
JsonParse sParse; /* Parse of the input JSON */
};
+typedef struct JsonEachConnection JsonEachConnection;
+struct JsonEachConnection {
+ sqlite3_vtab base; /* Base class - must be first */
+ sqlite3 *db; /* Database connection */
+};
+
/* Constructor for the json_each virtual table */
static int jsonEachConnect(
@@ -200906,7 +208053,7 @@ static int jsonEachConnect(
sqlite3_vtab **ppVtab,
char **pzErr
){
- sqlite3_vtab *pNew;
+ JsonEachConnection *pNew;
int rc;
/* Column numbers */
@@ -200932,28 +208079,32 @@ static int jsonEachConnect(
"CREATE TABLE x(key,value,type,atom,id,parent,fullkey,path,"
"json HIDDEN,root HIDDEN)");
if( rc==SQLITE_OK ){
- pNew = *ppVtab = sqlite3_malloc( sizeof(*pNew) );
+ pNew = (JsonEachConnection*)sqlite3DbMallocZero(db, sizeof(*pNew));
+ *ppVtab = (sqlite3_vtab*)pNew;
if( pNew==0 ) return SQLITE_NOMEM;
- memset(pNew, 0, sizeof(*pNew));
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
+ pNew->db = db;
}
return rc;
}
/* destructor for json_each virtual table */
static int jsonEachDisconnect(sqlite3_vtab *pVtab){
- sqlite3_free(pVtab);
+ JsonEachConnection *p = (JsonEachConnection*)pVtab;
+ sqlite3DbFree(p->db, pVtab);
return SQLITE_OK;
}
/* constructor for a JsonEachCursor object for json_each(). */
static int jsonEachOpenEach(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
+ JsonEachConnection *pVtab = (JsonEachConnection*)p;
JsonEachCursor *pCur;
UNUSED_PARAMETER(p);
- pCur = sqlite3_malloc( sizeof(*pCur) );
+ pCur = sqlite3DbMallocZero(pVtab->db, sizeof(*pCur));
if( pCur==0 ) return SQLITE_NOMEM;
- memset(pCur, 0, sizeof(*pCur));
+ pCur->db = pVtab->db;
+ jsonStringZero(&pCur->path);
*ppCursor = &pCur->base;
return SQLITE_OK;
}
@@ -200971,22 +208122,24 @@ static int jsonEachOpenTree(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){
/* Reset a JsonEachCursor back to its original state. Free any memory
** held. */
static void jsonEachCursorReset(JsonEachCursor *p){
- sqlite3_free(p->zJson);
- sqlite3_free(p->zRoot);
jsonParseReset(&p->sParse);
+ jsonStringReset(&p->path);
+ sqlite3DbFree(p->db, p->aParent);
p->iRowid = 0;
p->i = 0;
+ p->aParent = 0;
+ p->nParent = 0;
+ p->nParentAlloc = 0;
p->iEnd = 0;
p->eType = 0;
- p->zJson = 0;
- p->zRoot = 0;
}
/* Destructor for a jsonEachCursor object */
static int jsonEachClose(sqlite3_vtab_cursor *cur){
JsonEachCursor *p = (JsonEachCursor*)cur;
jsonEachCursorReset(p);
- sqlite3_free(cur);
+
+ sqlite3DbFree(p->db, cur);
return SQLITE_OK;
}
@@ -200997,198 +208150,233 @@ static int jsonEachEof(sqlite3_vtab_cursor *cur){
return p->i >= p->iEnd;
}
-/* Advance the cursor to the next element for json_tree() */
-static int jsonEachNext(sqlite3_vtab_cursor *cur){
- JsonEachCursor *p = (JsonEachCursor*)cur;
- if( p->bRecursive ){
- if( p->sParse.aNode[p->i].jnFlags & JNODE_LABEL ) p->i++;
- p->i++;
- p->iRowid++;
- if( p->i<p->iEnd ){
- u32 iUp = p->sParse.aUp[p->i];
- JsonNode *pUp = &p->sParse.aNode[iUp];
- p->eType = pUp->eType;
- if( pUp->eType==JSON_ARRAY ){
- assert( pUp->eU==0 || pUp->eU==3 );
- testcase( pUp->eU==3 );
- VVA( pUp->eU = 3 );
- if( iUp==p->i-1 ){
- pUp->u.iKey = 0;
- }else{
- pUp->u.iKey++;
+/*
+** If the cursor is currently pointing at the label of a object entry,
+** then return the index of the value. For all other cases, return the
+** current pointer position, which is the value.
+*/
+static int jsonSkipLabel(JsonEachCursor *p){
+ if( p->eType==JSONB_OBJECT ){
+ u32 sz = 0;
+ u32 n = jsonbPayloadSize(&p->sParse, p->i, &sz);
+ return p->i + n + sz;
+ }else{
+ return p->i;
+ }
+}
+
+/*
+** Append the path name for the current element.
+*/
+static void jsonAppendPathName(JsonEachCursor *p){
+ assert( p->nParent>0 );
+ assert( p->eType==JSONB_ARRAY || p->eType==JSONB_OBJECT );
+ if( p->eType==JSONB_ARRAY ){
+ jsonPrintf(30, &p->path, "[%lld]", p->aParent[p->nParent-1].iKey);
+ }else{
+ u32 n, sz = 0, k, i;
+ const char *z;
+ int needQuote = 0;
+ n = jsonbPayloadSize(&p->sParse, p->i, &sz);
+ k = p->i + n;
+ z = (const char*)&p->sParse.aBlob[k];
+ if( sz==0 || !sqlite3Isalpha(z[0]) ){
+ needQuote = 1;
+ }else{
+ for(i=0; i<sz; i++){
+ if( !sqlite3Isalnum(z[i]) ){
+ needQuote = 1;
+ break;
}
}
}
- }else{
- switch( p->eType ){
- case JSON_ARRAY: {
- p->i += jsonNodeSize(&p->sParse.aNode[p->i]);
- p->iRowid++;
- break;
- }
- case JSON_OBJECT: {
- p->i += 1 + jsonNodeSize(&p->sParse.aNode[p->i+1]);
- p->iRowid++;
- break;
- }
- default: {
- p->i = p->iEnd;
- break;
- }
+ if( needQuote ){
+ jsonPrintf(sz+4,&p->path,".\"%.*s\"", sz, z);
+ }else{
+ jsonPrintf(sz+2,&p->path,".%.*s", sz, z);
}
}
- return SQLITE_OK;
}
-/* Append an object label to the JSON Path being constructed
-** in pStr.
-*/
-static void jsonAppendObjectPathElement(
- JsonString *pStr,
- JsonNode *pNode
-){
- int jj, nn;
- const char *z;
- assert( pNode->eType==JSON_STRING );
- assert( pNode->jnFlags & JNODE_LABEL );
- assert( pNode->eU==1 );
- z = pNode->u.zJContent;
- nn = pNode->n;
- assert( nn>=2 );
- assert( z[0]=='"' );
- assert( z[nn-1]=='"' );
- if( nn>2 && sqlite3Isalpha(z[1]) ){
- for(jj=2; jj<nn-1 && sqlite3Isalnum(z[jj]); jj++){}
- if( jj==nn-1 ){
- z++;
- nn -= 2;
+/* Advance the cursor to the next element for json_tree() */
+static int jsonEachNext(sqlite3_vtab_cursor *cur){
+ JsonEachCursor *p = (JsonEachCursor*)cur;
+ int rc = SQLITE_OK;
+ if( p->bRecursive ){
+ u8 x;
+ u8 levelChange = 0;
+ u32 n, sz = 0;
+ u32 i = jsonSkipLabel(p);
+ x = p->sParse.aBlob[i] & 0x0f;
+ n = jsonbPayloadSize(&p->sParse, i, &sz);
+ if( x==JSONB_OBJECT || x==JSONB_ARRAY ){
+ JsonParent *pParent;
+ if( p->nParent>=p->nParentAlloc ){
+ JsonParent *pNew;
+ u64 nNew;
+ nNew = p->nParentAlloc*2 + 3;
+ pNew = sqlite3DbRealloc(p->db, p->aParent, sizeof(JsonParent)*nNew);
+ if( pNew==0 ) return SQLITE_NOMEM;
+ p->nParentAlloc = (u32)nNew;
+ p->aParent = pNew;
+ }
+ levelChange = 1;
+ pParent = &p->aParent[p->nParent];
+ pParent->iHead = p->i;
+ pParent->iValue = i;
+ pParent->iEnd = i + n + sz;
+ pParent->iKey = -1;
+ pParent->nPath = (u32)p->path.nUsed;
+ if( p->eType && p->nParent ){
+ jsonAppendPathName(p);
+ if( p->path.eErr ) rc = SQLITE_NOMEM;
+ }
+ p->nParent++;
+ p->i = i + n;
+ }else{
+ p->i = i + n + sz;
+ }
+ while( p->nParent>0 && p->i >= p->aParent[p->nParent-1].iEnd ){
+ p->nParent--;
+ p->path.nUsed = p->aParent[p->nParent].nPath;
+ levelChange = 1;
+ }
+ if( levelChange ){
+ if( p->nParent>0 ){
+ JsonParent *pParent = &p->aParent[p->nParent-1];
+ u32 iVal = pParent->iValue;
+ p->eType = p->sParse.aBlob[iVal] & 0x0f;
+ }else{
+ p->eType = 0;
+ }
}
+ }else{
+ u32 n, sz = 0;
+ u32 i = jsonSkipLabel(p);
+ n = jsonbPayloadSize(&p->sParse, i, &sz);
+ p->i = i + n + sz;
+ }
+ if( p->eType==JSONB_ARRAY && p->nParent ){
+ p->aParent[p->nParent-1].iKey++;
}
- jsonPrintf(nn+2, pStr, ".%.*s", nn, z);
+ p->iRowid++;
+ return rc;
}
-/* Append the name of the path for element i to pStr
+/* Length of the path for rowid==0 in bRecursive mode.
*/
-static void jsonEachComputePath(
- JsonEachCursor *p, /* The cursor */
- JsonString *pStr, /* Write the path here */
- u32 i /* Path to this element */
-){
- JsonNode *pNode, *pUp;
- u32 iUp;
- if( i==0 ){
- jsonAppendChar(pStr, '$');
- return;
- }
- iUp = p->sParse.aUp[i];
- jsonEachComputePath(p, pStr, iUp);
- pNode = &p->sParse.aNode[i];
- pUp = &p->sParse.aNode[iUp];
- if( pUp->eType==JSON_ARRAY ){
- assert( pUp->eU==3 || (pUp->eU==0 && pUp->u.iKey==0) );
- testcase( pUp->eU==0 );
- jsonPrintf(30, pStr, "[%d]", pUp->u.iKey);
- }else{
- assert( pUp->eType==JSON_OBJECT );
- if( (pNode->jnFlags & JNODE_LABEL)==0 ) pNode--;
- jsonAppendObjectPathElement(pStr, pNode);
+static int jsonEachPathLength(JsonEachCursor *p){
+ u32 n = p->path.nUsed;
+ char *z = p->path.zBuf;
+ if( p->iRowid==0 && p->bRecursive && n>=2 ){
+ while( n>1 ){
+ n--;
+ if( z[n]=='[' || z[n]=='.' ){
+ u32 x, sz = 0;
+ char cSaved = z[n];
+ z[n] = 0;
+ assert( p->sParse.eEdit==0 );
+ x = jsonLookupStep(&p->sParse, 0, z+1, 0);
+ z[n] = cSaved;
+ if( JSON_LOOKUP_ISERROR(x) ) continue;
+ if( x + jsonbPayloadSize(&p->sParse, x, &sz) == p->i ) break;
+ }
+ }
}
+ return n;
}
/* Return the value of a column */
static int jsonEachColumn(
sqlite3_vtab_cursor *cur, /* The cursor */
sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
- int i /* Which column to return */
+ int iColumn /* Which column to return */
){
JsonEachCursor *p = (JsonEachCursor*)cur;
- JsonNode *pThis = &p->sParse.aNode[p->i];
- switch( i ){
+ switch( iColumn ){
case JEACH_KEY: {
- if( p->i==0 ) break;
- if( p->eType==JSON_OBJECT ){
- jsonReturn(pThis, ctx, 0);
- }else if( p->eType==JSON_ARRAY ){
- u32 iKey;
- if( p->bRecursive ){
- if( p->iRowid==0 ) break;
- assert( p->sParse.aNode[p->sParse.aUp[p->i]].eU==3 );
- iKey = p->sParse.aNode[p->sParse.aUp[p->i]].u.iKey;
+ if( p->nParent==0 ){
+ u32 n, j;
+ if( p->nRoot==1 ) break;
+ j = jsonEachPathLength(p);
+ n = p->nRoot - j;
+ if( n==0 ){
+ break;
+ }else if( p->path.zBuf[j]=='[' ){
+ i64 x;
+ sqlite3Atoi64(&p->path.zBuf[j+1], &x, n-1, SQLITE_UTF8);
+ sqlite3_result_int64(ctx, x);
+ }else if( p->path.zBuf[j+1]=='"' ){
+ sqlite3_result_text(ctx, &p->path.zBuf[j+2], n-3, SQLITE_TRANSIENT);
}else{
- iKey = p->iRowid;
+ sqlite3_result_text(ctx, &p->path.zBuf[j+1], n-1, SQLITE_TRANSIENT);
}
- sqlite3_result_int64(ctx, (sqlite3_int64)iKey);
+ break;
+ }
+ if( p->eType==JSONB_OBJECT ){
+ jsonReturnFromBlob(&p->sParse, p->i, ctx, 1);
+ }else{
+ assert( p->eType==JSONB_ARRAY );
+ sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iKey);
}
break;
}
case JEACH_VALUE: {
- if( pThis->jnFlags & JNODE_LABEL ) pThis++;
- jsonReturn(pThis, ctx, 0);
+ u32 i = jsonSkipLabel(p);
+ jsonReturnFromBlob(&p->sParse, i, ctx, 1);
+ if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY ){
+ sqlite3_result_subtype(ctx, JSON_SUBTYPE);
+ }
break;
}
case JEACH_TYPE: {
- if( pThis->jnFlags & JNODE_LABEL ) pThis++;
- sqlite3_result_text(ctx, jsonType[pThis->eType], -1, SQLITE_STATIC);
+ u32 i = jsonSkipLabel(p);
+ u8 eType = p->sParse.aBlob[i] & 0x0f;
+ sqlite3_result_text(ctx, jsonbType[eType], -1, SQLITE_STATIC);
break;
}
case JEACH_ATOM: {
- if( pThis->jnFlags & JNODE_LABEL ) pThis++;
- if( pThis->eType>=JSON_ARRAY ) break;
- jsonReturn(pThis, ctx, 0);
+ u32 i = jsonSkipLabel(p);
+ if( (p->sParse.aBlob[i] & 0x0f)<JSONB_ARRAY ){
+ jsonReturnFromBlob(&p->sParse, i, ctx, 1);
+ }
break;
}
case JEACH_ID: {
- sqlite3_result_int64(ctx,
- (sqlite3_int64)p->i + ((pThis->jnFlags & JNODE_LABEL)!=0));
+ sqlite3_result_int64(ctx, (sqlite3_int64)p->i);
break;
}
case JEACH_PARENT: {
- if( p->i>p->iBegin && p->bRecursive ){
- sqlite3_result_int64(ctx, (sqlite3_int64)p->sParse.aUp[p->i]);
+ if( p->nParent>0 && p->bRecursive ){
+ sqlite3_result_int64(ctx, p->aParent[p->nParent-1].iHead);
}
break;
}
case JEACH_FULLKEY: {
- JsonString x;
- jsonInit(&x, ctx);
- if( p->bRecursive ){
- jsonEachComputePath(p, &x, p->i);
- }else{
- if( p->zRoot ){
- jsonAppendRaw(&x, p->zRoot, (int)strlen(p->zRoot));
- }else{
- jsonAppendChar(&x, '$');
- }
- if( p->eType==JSON_ARRAY ){
- jsonPrintf(30, &x, "[%d]", p->iRowid);
- }else if( p->eType==JSON_OBJECT ){
- jsonAppendObjectPathElement(&x, pThis);
- }
- }
- jsonResult(&x);
+ u64 nBase = p->path.nUsed;
+ if( p->nParent ) jsonAppendPathName(p);
+ sqlite3_result_text64(ctx, p->path.zBuf, p->path.nUsed,
+ SQLITE_TRANSIENT, SQLITE_UTF8);
+ p->path.nUsed = nBase;
break;
}
case JEACH_PATH: {
- if( p->bRecursive ){
- JsonString x;
- jsonInit(&x, ctx);
- jsonEachComputePath(p, &x, p->sParse.aUp[p->i]);
- jsonResult(&x);
- break;
- }
- /* For json_each() path and root are the same so fall through
- ** into the root case */
- /* no break */ deliberate_fall_through
+ u32 n = jsonEachPathLength(p);
+ sqlite3_result_text64(ctx, p->path.zBuf, n,
+ SQLITE_TRANSIENT, SQLITE_UTF8);
+ break;
}
default: {
- const char *zRoot = p->zRoot;
- if( zRoot==0 ) zRoot = "$";
- sqlite3_result_text(ctx, zRoot, -1, SQLITE_STATIC);
+ sqlite3_result_text(ctx, p->path.zBuf, p->nRoot, SQLITE_STATIC);
break;
}
case JEACH_JSON: {
- assert( i==JEACH_JSON );
- sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_STATIC);
+ if( p->sParse.zJson==0 ){
+ sqlite3_result_blob(ctx, p->sParse.aBlob, p->sParse.nBlob,
+ SQLITE_TRANSIENT);
+ }else{
+ sqlite3_result_text(ctx, p->sParse.zJson, -1, SQLITE_TRANSIENT);
+ }
break;
}
}
@@ -201279,78 +208467,97 @@ static int jsonEachFilter(
int argc, sqlite3_value **argv
){
JsonEachCursor *p = (JsonEachCursor*)cur;
- const char *z;
const char *zRoot = 0;
- sqlite3_int64 n;
+ u32 i, n, sz;
UNUSED_PARAMETER(idxStr);
UNUSED_PARAMETER(argc);
jsonEachCursorReset(p);
if( idxNum==0 ) return SQLITE_OK;
- z = (const char*)sqlite3_value_text(argv[0]);
- if( z==0 ) return SQLITE_OK;
- n = sqlite3_value_bytes(argv[0]);
- p->zJson = sqlite3_malloc64( n+1 );
- if( p->zJson==0 ) return SQLITE_NOMEM;
- memcpy(p->zJson, z, (size_t)n+1);
- if( jsonParse(&p->sParse, 0, p->zJson) ){
- int rc = SQLITE_NOMEM;
- if( p->sParse.oom==0 ){
- sqlite3_free(cur->pVtab->zErrMsg);
- cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON");
- if( cur->pVtab->zErrMsg ) rc = SQLITE_ERROR;
+ memset(&p->sParse, 0, sizeof(p->sParse));
+ p->sParse.nJPRef = 1;
+ p->sParse.db = p->db;
+ if( jsonFuncArgMightBeBinary(argv[0]) ){
+ p->sParse.nBlob = sqlite3_value_bytes(argv[0]);
+ p->sParse.aBlob = (u8*)sqlite3_value_blob(argv[0]);
+ }else{
+ p->sParse.zJson = (char*)sqlite3_value_text(argv[0]);
+ p->sParse.nJson = sqlite3_value_bytes(argv[0]);
+ if( p->sParse.zJson==0 ){
+ p->i = p->iEnd = 0;
+ return SQLITE_OK;
}
- jsonEachCursorReset(p);
- return rc;
- }else if( p->bRecursive && jsonParseFindParents(&p->sParse) ){
- jsonEachCursorReset(p);
- return SQLITE_NOMEM;
- }else{
- JsonNode *pNode = 0;
- if( idxNum==3 ){
- const char *zErr = 0;
- zRoot = (const char*)sqlite3_value_text(argv[1]);
- if( zRoot==0 ) return SQLITE_OK;
- n = sqlite3_value_bytes(argv[1]);
- p->zRoot = sqlite3_malloc64( n+1 );
- if( p->zRoot==0 ) return SQLITE_NOMEM;
- memcpy(p->zRoot, zRoot, (size_t)n+1);
- if( zRoot[0]!='$' ){
- zErr = zRoot;
- }else{
- pNode = jsonLookupStep(&p->sParse, 0, p->zRoot+1, 0, &zErr);
+ if( jsonConvertTextToBlob(&p->sParse, 0) ){
+ if( p->sParse.oom ){
+ return SQLITE_NOMEM;
}
- if( zErr ){
+ goto json_each_malformed_input;
+ }
+ }
+ if( idxNum==3 ){
+ zRoot = (const char*)sqlite3_value_text(argv[1]);
+ if( zRoot==0 ) return SQLITE_OK;
+ if( zRoot[0]!='$' ){
+ sqlite3_free(cur->pVtab->zErrMsg);
+ cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot);
+ jsonEachCursorReset(p);
+ return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
+ }
+ p->nRoot = sqlite3Strlen30(zRoot);
+ if( zRoot[1]==0 ){
+ i = p->i = 0;
+ p->eType = 0;
+ }else{
+ i = jsonLookupStep(&p->sParse, 0, zRoot+1, 0);
+ if( JSON_LOOKUP_ISERROR(i) ){
+ if( i==JSON_LOOKUP_NOTFOUND ){
+ p->i = 0;
+ p->eType = 0;
+ p->iEnd = 0;
+ return SQLITE_OK;
+ }
sqlite3_free(cur->pVtab->zErrMsg);
- cur->pVtab->zErrMsg = jsonPathSyntaxError(zErr);
+ cur->pVtab->zErrMsg = jsonBadPathError(0, zRoot);
jsonEachCursorReset(p);
return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
- }else if( pNode==0 ){
- return SQLITE_OK;
}
- }else{
- pNode = p->sParse.aNode;
- }
- p->iBegin = p->i = (int)(pNode - p->sParse.aNode);
- p->eType = pNode->eType;
- if( p->eType>=JSON_ARRAY ){
- assert( pNode->eU==0 );
- VVA( pNode->eU = 3 );
- pNode->u.iKey = 0;
- p->iEnd = p->i + pNode->n + 1;
- if( p->bRecursive ){
- p->eType = p->sParse.aNode[p->sParse.aUp[p->i]].eType;
- if( p->i>0 && (p->sParse.aNode[p->i-1].jnFlags & JNODE_LABEL)!=0 ){
- p->i--;
- }
+ if( p->sParse.iLabel ){
+ p->i = p->sParse.iLabel;
+ p->eType = JSONB_OBJECT;
}else{
- p->i++;
- }
- }else{
- p->iEnd = p->i+1;
- }
+ p->i = i;
+ p->eType = JSONB_ARRAY;
+ }
+ }
+ jsonAppendRaw(&p->path, zRoot, p->nRoot);
+ }else{
+ i = p->i = 0;
+ p->eType = 0;
+ p->nRoot = 1;
+ jsonAppendRaw(&p->path, "$", 1);
+ }
+ p->nParent = 0;
+ n = jsonbPayloadSize(&p->sParse, i, &sz);
+ p->iEnd = i+n+sz;
+ if( (p->sParse.aBlob[i] & 0x0f)>=JSONB_ARRAY && !p->bRecursive ){
+ p->i = i + n;
+ p->eType = p->sParse.aBlob[i] & 0x0f;
+ p->aParent = sqlite3DbMallocZero(p->db, sizeof(JsonParent));
+ if( p->aParent==0 ) return SQLITE_NOMEM;
+ p->nParent = 1;
+ p->nParentAlloc = 1;
+ p->aParent[0].iKey = 0;
+ p->aParent[0].iEnd = p->iEnd;
+ p->aParent[0].iHead = p->i;
+ p->aParent[0].iValue = i;
}
return SQLITE_OK;
+
+json_each_malformed_input:
+ sqlite3_free(cur->pVtab->zErrMsg);
+ cur->pVtab->zErrMsg = sqlite3_mprintf("malformed JSON");
+ jsonEachCursorReset(p);
+ return cur->pVtab->zErrMsg ? SQLITE_ERROR : SQLITE_NOMEM;
}
/* The methods of the json_each virtual table */
@@ -201378,7 +208585,8 @@ static sqlite3_module jsonEachModule = {
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
/* The methods of the json_tree virtual table. */
@@ -201406,7 +208614,8 @@ static sqlite3_module jsonTreeModule = {
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
#endif /* SQLITE_OMIT_VIRTUALTABLE */
#endif /* !defined(SQLITE_OMIT_JSON) */
@@ -201417,33 +208626,57 @@ static sqlite3_module jsonTreeModule = {
SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void){
#ifndef SQLITE_OMIT_JSON
static FuncDef aJsonFunc[] = {
- JFUNCTION(json, 1, 0, jsonRemoveFunc),
- JFUNCTION(json_array, -1, 0, jsonArrayFunc),
- JFUNCTION(json_array_length, 1, 0, jsonArrayLengthFunc),
- JFUNCTION(json_array_length, 2, 0, jsonArrayLengthFunc),
- JFUNCTION(json_extract, -1, 0, jsonExtractFunc),
- JFUNCTION(->, 2, JSON_JSON, jsonExtractFunc),
- JFUNCTION(->>, 2, JSON_SQL, jsonExtractFunc),
- JFUNCTION(json_insert, -1, 0, jsonSetFunc),
- JFUNCTION(json_object, -1, 0, jsonObjectFunc),
- JFUNCTION(json_patch, 2, 0, jsonPatchFunc),
- JFUNCTION(json_quote, 1, 0, jsonQuoteFunc),
- JFUNCTION(json_remove, -1, 0, jsonRemoveFunc),
- JFUNCTION(json_replace, -1, 0, jsonReplaceFunc),
- JFUNCTION(json_set, -1, JSON_ISSET, jsonSetFunc),
- JFUNCTION(json_type, 1, 0, jsonTypeFunc),
- JFUNCTION(json_type, 2, 0, jsonTypeFunc),
- JFUNCTION(json_valid, 1, 0, jsonValidFunc),
+ /* sqlite3_result_subtype() ----, ,--- sqlite3_value_subtype() */
+ /* | | */
+ /* Uses cache ------, | | ,---- Returns JSONB */
+ /* | | | | */
+ /* Number of arguments ---, | | | | ,--- Flags */
+ /* | | | | | | */
+ JFUNCTION(json, 1,1,1, 0,0,0, jsonRemoveFunc),
+ JFUNCTION(jsonb, 1,1,0, 0,1,0, jsonRemoveFunc),
+ JFUNCTION(json_array, -1,0,1, 1,0,0, jsonArrayFunc),
+ JFUNCTION(jsonb_array, -1,0,1, 1,1,0, jsonArrayFunc),
+ JFUNCTION(json_array_length, 1,1,0, 0,0,0, jsonArrayLengthFunc),
+ JFUNCTION(json_array_length, 2,1,0, 0,0,0, jsonArrayLengthFunc),
+ JFUNCTION(json_error_position,1,1,0, 0,0,0, jsonErrorFunc),
+ JFUNCTION(json_extract, -1,1,1, 0,0,0, jsonExtractFunc),
+ JFUNCTION(jsonb_extract, -1,1,0, 0,1,0, jsonExtractFunc),
+ JFUNCTION(->, 2,1,1, 0,0,JSON_JSON, jsonExtractFunc),
+ JFUNCTION(->>, 2,1,0, 0,0,JSON_SQL, jsonExtractFunc),
+ JFUNCTION(json_insert, -1,1,1, 1,0,0, jsonSetFunc),
+ JFUNCTION(jsonb_insert, -1,1,0, 1,1,0, jsonSetFunc),
+ JFUNCTION(json_object, -1,0,1, 1,0,0, jsonObjectFunc),
+ JFUNCTION(jsonb_object, -1,0,1, 1,1,0, jsonObjectFunc),
+ JFUNCTION(json_patch, 2,1,1, 0,0,0, jsonPatchFunc),
+ JFUNCTION(jsonb_patch, 2,1,0, 0,1,0, jsonPatchFunc),
+ JFUNCTION(json_quote, 1,0,1, 1,0,0, jsonQuoteFunc),
+ JFUNCTION(json_remove, -1,1,1, 0,0,0, jsonRemoveFunc),
+ JFUNCTION(jsonb_remove, -1,1,0, 0,1,0, jsonRemoveFunc),
+ JFUNCTION(json_replace, -1,1,1, 1,0,0, jsonReplaceFunc),
+ JFUNCTION(jsonb_replace, -1,1,0, 1,1,0, jsonReplaceFunc),
+ JFUNCTION(json_set, -1,1,1, 1,0,JSON_ISSET, jsonSetFunc),
+ JFUNCTION(jsonb_set, -1,1,0, 1,1,JSON_ISSET, jsonSetFunc),
+ JFUNCTION(json_type, 1,1,0, 0,0,0, jsonTypeFunc),
+ JFUNCTION(json_type, 2,1,0, 0,0,0, jsonTypeFunc),
+ JFUNCTION(json_valid, 1,1,0, 0,0,0, jsonValidFunc),
+ JFUNCTION(json_valid, 2,1,0, 0,0,0, jsonValidFunc),
#if SQLITE_DEBUG
- JFUNCTION(json_parse, 1, 0, jsonParseFunc),
- JFUNCTION(json_test1, 1, 0, jsonTest1Func),
+ JFUNCTION(json_parse, 1,1,0, 0,0,0, jsonParseFunc),
#endif
WAGGREGATE(json_group_array, 1, 0, 0,
jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse,
- SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC),
+ SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|
+ SQLITE_DETERMINISTIC),
+ WAGGREGATE(jsonb_group_array, 1, JSON_BLOB, 0,
+ jsonArrayStep, jsonArrayFinal, jsonArrayValue, jsonGroupInverse,
+ SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC),
WAGGREGATE(json_group_object, 2, 0, 0,
jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse,
- SQLITE_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC)
+ SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|SQLITE_DETERMINISTIC),
+ WAGGREGATE(jsonb_group_object,2, JSON_BLOB, 0,
+ jsonObjectStep, jsonObjectFinal, jsonObjectValue, jsonGroupInverse,
+ SQLITE_SUBTYPE|SQLITE_RESULT_SUBTYPE|SQLITE_UTF8|
+ SQLITE_DETERMINISTIC)
};
sqlite3InsertBuiltinFuncs(aJsonFunc, ArraySize(aJsonFunc));
#endif
@@ -201570,6 +208803,11 @@ typedef unsigned int u32;
#endif
#endif /* !defined(SQLITE_AMALGAMATION) */
+/* Macro to check for 4-byte alignment. Only used inside of assert() */
+#ifdef SQLITE_DEBUG
+# define FOUR_BYTE_ALIGNED(X) ((((char*)(X) - (char*)0) & 3)==0)
+#endif
+
/* #include <string.h> */
/* #include <stdio.h> */
/* #include <assert.h> */
@@ -201635,6 +208873,7 @@ struct Rtree {
int iDepth; /* Current depth of the r-tree structure */
char *zDb; /* Name of database containing r-tree table */
char *zName; /* Name of r-tree table */
+ char *zNodeName; /* Name of the %_node table */
u32 nBusy; /* Current number of users of this structure */
i64 nRowEst; /* Estimated number of rows in this table */
u32 nCursor; /* Number of open cursors */
@@ -201647,7 +208886,6 @@ struct Rtree {
** headed by the node (leaf nodes have RtreeNode.iNode==0).
*/
RtreeNode *pDeleted;
- int iReinsertHeight; /* Height of sub-trees Reinsert() has run on */
/* Blob I/O on xxx_node */
sqlite3_blob *pNodeBlob;
@@ -201944,17 +209182,23 @@ struct RtreeMatchArg {
** -DSQLITE_RUNTIME_BYTEORDER=1 is set, then byte-order is determined
** at run-time.
*/
-#ifndef SQLITE_BYTEORDER
-#if defined(i386) || defined(__i386__) || defined(_M_IX86) || \
- defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
- defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
- defined(__arm__)
-# define SQLITE_BYTEORDER 1234
-#elif defined(sparc) || defined(__ppc__)
-# define SQLITE_BYTEORDER 4321
-#else
-# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */
-#endif
+#ifndef SQLITE_BYTEORDER /* Replicate changes at tag-20230904a */
+# if defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
+# define SQLITE_BYTEORDER 4321
+# elif defined(__BYTE_ORDER__) && __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
+# define SQLITE_BYTEORDER 1234
+# elif defined(__BIG_ENDIAN__) && __BIG_ENDIAN__==1
+# define SQLITE_BYTEORDER 4321
+# elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \
+ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
+ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
+ defined(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64)
+# define SQLITE_BYTEORDER 1234
+# elif defined(sparc) || defined(__ARMEB__) || defined(__AARCH64EB__)
+# define SQLITE_BYTEORDER 4321
+# else
+# define SQLITE_BYTEORDER 0
+# endif
#endif
@@ -201975,7 +209219,7 @@ static int readInt16(u8 *p){
return (p[0]<<8) + p[1];
}
static void readCoord(u8 *p, RtreeCoord *pCoord){
- assert( (((sqlite3_uint64)p)&3)==0 ); /* p is always 4-byte aligned */
+ assert( FOUR_BYTE_ALIGNED(p) );
#if SQLITE_BYTEORDER==1234 && MSVC_VERSION>=1300
pCoord->u = _byteswap_ulong(*(u32*)p);
#elif SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
@@ -202029,7 +209273,7 @@ static void writeInt16(u8 *p, int i){
}
static int writeCoord(u8 *p, RtreeCoord *pCoord){
u32 i;
- assert( (((sqlite3_uint64)p)&3)==0 ); /* p is always 4-byte aligned */
+ assert( FOUR_BYTE_ALIGNED(p) );
assert( sizeof(RtreeCoord)==4 );
assert( sizeof(u32)==4 );
#if SQLITE_BYTEORDER==1234 && GCC_VERSION>=4003000
@@ -202157,11 +209401,9 @@ static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent){
** Clear the Rtree.pNodeBlob object
*/
static void nodeBlobReset(Rtree *pRtree){
- if( pRtree->pNodeBlob && pRtree->inWrTrans==0 && pRtree->nCursor==0 ){
- sqlite3_blob *pBlob = pRtree->pNodeBlob;
- pRtree->pNodeBlob = 0;
- sqlite3_blob_close(pBlob);
- }
+ sqlite3_blob *pBlob = pRtree->pNodeBlob;
+ pRtree->pNodeBlob = 0;
+ sqlite3_blob_close(pBlob);
}
/*
@@ -202180,7 +209422,7 @@ static int nodeAcquire(
** increase its reference count and return it.
*/
if( (pNode = nodeHashLookup(pRtree, iNode))!=0 ){
- if( pParent && pParent!=pNode->pParent ){
+ if( pParent && ALWAYS(pParent!=pNode->pParent) ){
RTREE_IS_CORRUPT(pRtree);
return SQLITE_CORRUPT_VTAB;
}
@@ -202200,14 +209442,11 @@ static int nodeAcquire(
}
}
if( pRtree->pNodeBlob==0 ){
- char *zTab = sqlite3_mprintf("%s_node", pRtree->zName);
- if( zTab==0 ) return SQLITE_NOMEM;
- rc = sqlite3_blob_open(pRtree->db, pRtree->zDb, zTab, "data", iNode, 0,
+ rc = sqlite3_blob_open(pRtree->db, pRtree->zDb, pRtree->zNodeName,
+ "data", iNode, 0,
&pRtree->pNodeBlob);
- sqlite3_free(zTab);
}
if( rc ){
- nodeBlobReset(pRtree);
*ppNode = 0;
/* If unable to open an sqlite3_blob on the desired row, that can only
** be because the shadow tables hold erroneous data. */
@@ -202267,6 +209506,7 @@ static int nodeAcquire(
}
*ppNode = pNode;
}else{
+ nodeBlobReset(pRtree);
if( pNode ){
pRtree->nNodeRef--;
sqlite3_free(pNode);
@@ -202411,6 +209651,7 @@ static void nodeGetCoord(
int iCoord, /* Which coordinate to extract */
RtreeCoord *pCoord /* OUT: Space to write result to */
){
+ assert( iCell<NCELL(pNode) );
readCoord(&pNode->zData[12 + pRtree->nBytesPerCell*iCell + 4*iCoord], pCoord);
}
@@ -202600,7 +209841,9 @@ static int rtreeClose(sqlite3_vtab_cursor *cur){
sqlite3_finalize(pCsr->pReadAux);
sqlite3_free(pCsr);
pRtree->nCursor--;
- nodeBlobReset(pRtree);
+ if( pRtree->nCursor==0 && pRtree->inWrTrans==0 ){
+ nodeBlobReset(pRtree);
+ }
return SQLITE_OK;
}
@@ -202757,7 +210000,7 @@ static void rtreeNonleafConstraint(
assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
|| p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE
|| p->op==RTREE_FALSE );
- assert( (((sqlite3_uint64)pCellData)&3)==0 ); /* 4-byte aligned */
+ assert( FOUR_BYTE_ALIGNED(pCellData) );
switch( p->op ){
case RTREE_TRUE: return; /* Always satisfied */
case RTREE_FALSE: break; /* Never satisfied */
@@ -202810,7 +210053,7 @@ static void rtreeLeafConstraint(
|| p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_TRUE
|| p->op==RTREE_FALSE );
pCellData += 8 + p->iCoord*4;
- assert( (((sqlite3_uint64)pCellData)&3)==0 ); /* 4-byte aligned */
+ assert( FOUR_BYTE_ALIGNED(pCellData) );
RTREE_DECODE_COORD(eInt, pCellData, xN);
switch( p->op ){
case RTREE_TRUE: return; /* Always satisfied */
@@ -203185,7 +210428,11 @@ static int rtreeRowid(sqlite3_vtab_cursor *pVtabCursor, sqlite_int64 *pRowid){
int rc = SQLITE_OK;
RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc);
if( rc==SQLITE_OK && ALWAYS(p) ){
- *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell);
+ if( p->iCell>=NCELL(pNode) ){
+ rc = SQLITE_ABORT;
+ }else{
+ *pRowid = nodeGetRowid(RTREE_OF_CURSOR(pCsr), pNode, p->iCell);
+ }
}
return rc;
}
@@ -203203,6 +210450,7 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
if( rc ) return rc;
if( NEVER(p==0) ) return SQLITE_OK;
+ if( p->iCell>=NCELL(pNode) ) return SQLITE_ABORT;
if( i==0 ){
sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell));
}else if( i<=pRtree->nDim2 ){
@@ -203380,7 +210628,20 @@ static int rtreeFilter(
p->pInfo->nCoord = pRtree->nDim2;
p->pInfo->anQueue = pCsr->anQueue;
p->pInfo->mxLevel = pRtree->iDepth + 1;
- }else if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+ }else if( eType==SQLITE_INTEGER ){
+ sqlite3_int64 iVal = sqlite3_value_int64(argv[ii]);
+#ifdef SQLITE_RTREE_INT_ONLY
+ p->u.rValue = iVal;
+#else
+ p->u.rValue = (double)iVal;
+ if( iVal>=((sqlite3_int64)1)<<48
+ || iVal<=-(((sqlite3_int64)1)<<48)
+ ){
+ if( p->op==RTREE_LT ) p->op = RTREE_LE;
+ if( p->op==RTREE_GT ) p->op = RTREE_GE;
+ }
+#endif
+ }else if( eType==SQLITE_FLOAT ){
#ifdef SQLITE_RTREE_INT_ONLY
p->u.rValue = sqlite3_value_int64(argv[ii]);
#else
@@ -203511,11 +210772,12 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|| p->op==SQLITE_INDEX_CONSTRAINT_MATCH)
){
u8 op;
+ u8 doOmit = 1;
switch( p->op ){
- case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break;
- case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; break;
+ case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; doOmit = 0; break;
+ case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; doOmit = 0; break;
case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break;
- case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break;
+ case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; doOmit = 0; break;
case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break;
case SQLITE_INDEX_CONSTRAINT_MATCH: op = RTREE_MATCH; break;
default: op = 0; break;
@@ -203524,15 +210786,19 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
zIdxStr[iIdx++] = op;
zIdxStr[iIdx++] = (char)(p->iColumn - 1 + '0');
pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2);
- pIdxInfo->aConstraintUsage[ii].omit = 1;
+ pIdxInfo->aConstraintUsage[ii].omit = doOmit;
}
}
}
pIdxInfo->idxNum = 2;
pIdxInfo->needToFreeIdxStr = 1;
- if( iIdx>0 && 0==(pIdxInfo->idxStr = sqlite3_mprintf("%s", zIdxStr)) ){
- return SQLITE_NOMEM;
+ if( iIdx>0 ){
+ pIdxInfo->idxStr = sqlite3_malloc( iIdx+1 );
+ if( pIdxInfo->idxStr==0 ){
+ return SQLITE_NOMEM;
+ }
+ memcpy(pIdxInfo->idxStr, zIdxStr, iIdx+1);
}
nRow = pRtree->nRowEst >> (iIdx/2);
@@ -203611,31 +210877,22 @@ static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
*/
static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
int ii;
- int isInt = (pRtree->eCoordType==RTREE_COORD_INT32);
- for(ii=0; ii<pRtree->nDim2; ii+=2){
- RtreeCoord *a1 = &p1->aCoord[ii];
- RtreeCoord *a2 = &p2->aCoord[ii];
- if( (!isInt && (a2[0].f<a1[0].f || a2[1].f>a1[1].f))
- || ( isInt && (a2[0].i<a1[0].i || a2[1].i>a1[1].i))
- ){
- return 0;
+ if( pRtree->eCoordType==RTREE_COORD_INT32 ){
+ for(ii=0; ii<pRtree->nDim2; ii+=2){
+ RtreeCoord *a1 = &p1->aCoord[ii];
+ RtreeCoord *a2 = &p2->aCoord[ii];
+ if( a2[0].i<a1[0].i || a2[1].i>a1[1].i ) return 0;
+ }
+ }else{
+ for(ii=0; ii<pRtree->nDim2; ii+=2){
+ RtreeCoord *a1 = &p1->aCoord[ii];
+ RtreeCoord *a2 = &p2->aCoord[ii];
+ if( a2[0].f<a1[0].f || a2[1].f>a1[1].f ) return 0;
}
}
return 1;
}
-/*
-** Return the amount cell p would grow by if it were unioned with pCell.
-*/
-static RtreeDValue cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){
- RtreeDValue area;
- RtreeCell cell;
- memcpy(&cell, p, sizeof(RtreeCell));
- area = cellArea(pRtree, &cell);
- cellUnion(pRtree, &cell, pCell);
- return (cellArea(pRtree, &cell)-area);
-}
-
static RtreeDValue cellOverlap(
Rtree *pRtree,
RtreeCell *p,
@@ -203682,38 +210939,52 @@ static int ChooseLeaf(
for(ii=0; rc==SQLITE_OK && ii<(pRtree->iDepth-iHeight); ii++){
int iCell;
sqlite3_int64 iBest = 0;
-
+ int bFound = 0;
RtreeDValue fMinGrowth = RTREE_ZERO;
RtreeDValue fMinArea = RTREE_ZERO;
-
int nCell = NCELL(pNode);
- RtreeCell cell;
RtreeNode *pChild = 0;
- RtreeCell *aCell = 0;
-
- /* Select the child node which will be enlarged the least if pCell
- ** is inserted into it. Resolve ties by choosing the entry with
- ** the smallest area.
+ /* First check to see if there is are any cells in pNode that completely
+ ** contains pCell. If two or more cells in pNode completely contain pCell
+ ** then pick the smallest.
*/
for(iCell=0; iCell<nCell; iCell++){
- int bBest = 0;
- RtreeDValue growth;
- RtreeDValue area;
+ RtreeCell cell;
nodeGetCell(pRtree, pNode, iCell, &cell);
- growth = cellGrowth(pRtree, &cell, pCell);
- area = cellArea(pRtree, &cell);
- if( iCell==0||growth<fMinGrowth||(growth==fMinGrowth && area<fMinArea) ){
- bBest = 1;
+ if( cellContains(pRtree, &cell, pCell) ){
+ RtreeDValue area = cellArea(pRtree, &cell);
+ if( bFound==0 || area<fMinArea ){
+ iBest = cell.iRowid;
+ fMinArea = area;
+ bFound = 1;
+ }
}
- if( bBest ){
- fMinGrowth = growth;
- fMinArea = area;
- iBest = cell.iRowid;
+ }
+ if( !bFound ){
+ /* No cells of pNode will completely contain pCell. So pick the
+ ** cell of pNode that grows by the least amount when pCell is added.
+ ** Break ties by selecting the smaller cell.
+ */
+ for(iCell=0; iCell<nCell; iCell++){
+ RtreeCell cell;
+ RtreeDValue growth;
+ RtreeDValue area;
+ nodeGetCell(pRtree, pNode, iCell, &cell);
+ area = cellArea(pRtree, &cell);
+ cellUnion(pRtree, &cell, pCell);
+ growth = cellArea(pRtree, &cell)-area;
+ if( iCell==0
+ || growth<fMinGrowth
+ || (growth==fMinGrowth && area<fMinArea)
+ ){
+ fMinGrowth = growth;
+ fMinArea = area;
+ iBest = cell.iRowid;
+ }
}
}
- sqlite3_free(aCell);
rc = nodeAcquire(pRtree, iBest, pNode, &pChild);
nodeRelease(pRtree, pNode);
pNode = pChild;
@@ -203786,77 +211057,6 @@ static int parentWrite(Rtree *pRtree, sqlite3_int64 iNode, sqlite3_int64 iPar){
static int rtreeInsertCell(Rtree *, RtreeNode *, RtreeCell *, int);
-/*
-** Arguments aIdx, aDistance and aSpare all point to arrays of size
-** nIdx. The aIdx array contains the set of integers from 0 to
-** (nIdx-1) in no particular order. This function sorts the values
-** in aIdx according to the indexed values in aDistance. For
-** example, assuming the inputs:
-**
-** aIdx = { 0, 1, 2, 3 }
-** aDistance = { 5.0, 2.0, 7.0, 6.0 }
-**
-** this function sets the aIdx array to contain:
-**
-** aIdx = { 0, 1, 2, 3 }
-**
-** The aSpare array is used as temporary working space by the
-** sorting algorithm.
-*/
-static void SortByDistance(
- int *aIdx,
- int nIdx,
- RtreeDValue *aDistance,
- int *aSpare
-){
- if( nIdx>1 ){
- int iLeft = 0;
- int iRight = 0;
-
- int nLeft = nIdx/2;
- int nRight = nIdx-nLeft;
- int *aLeft = aIdx;
- int *aRight = &aIdx[nLeft];
-
- SortByDistance(aLeft, nLeft, aDistance, aSpare);
- SortByDistance(aRight, nRight, aDistance, aSpare);
-
- memcpy(aSpare, aLeft, sizeof(int)*nLeft);
- aLeft = aSpare;
-
- while( iLeft<nLeft || iRight<nRight ){
- if( iLeft==nLeft ){
- aIdx[iLeft+iRight] = aRight[iRight];
- iRight++;
- }else if( iRight==nRight ){
- aIdx[iLeft+iRight] = aLeft[iLeft];
- iLeft++;
- }else{
- RtreeDValue fLeft = aDistance[aLeft[iLeft]];
- RtreeDValue fRight = aDistance[aRight[iRight]];
- if( fLeft<fRight ){
- aIdx[iLeft+iRight] = aLeft[iLeft];
- iLeft++;
- }else{
- aIdx[iLeft+iRight] = aRight[iRight];
- iRight++;
- }
- }
- }
-
-#if 0
- /* Check that the sort worked */
- {
- int jj;
- for(jj=1; jj<nIdx; jj++){
- RtreeDValue left = aDistance[aIdx[jj-1]];
- RtreeDValue right = aDistance[aIdx[jj]];
- assert( left<=right );
- }
- }
-#endif
- }
-}
/*
** Arguments aIdx, aCell and aSpare all point to arrays of size
@@ -204341,107 +211541,6 @@ static int deleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell, int iHeight){
return rc;
}
-static int Reinsert(
- Rtree *pRtree,
- RtreeNode *pNode,
- RtreeCell *pCell,
- int iHeight
-){
- int *aOrder;
- int *aSpare;
- RtreeCell *aCell;
- RtreeDValue *aDistance;
- int nCell;
- RtreeDValue aCenterCoord[RTREE_MAX_DIMENSIONS];
- int iDim;
- int ii;
- int rc = SQLITE_OK;
- int n;
-
- memset(aCenterCoord, 0, sizeof(RtreeDValue)*RTREE_MAX_DIMENSIONS);
-
- nCell = NCELL(pNode)+1;
- n = (nCell+1)&(~1);
-
- /* Allocate the buffers used by this operation. The allocation is
- ** relinquished before this function returns.
- */
- aCell = (RtreeCell *)sqlite3_malloc64(n * (
- sizeof(RtreeCell) + /* aCell array */
- sizeof(int) + /* aOrder array */
- sizeof(int) + /* aSpare array */
- sizeof(RtreeDValue) /* aDistance array */
- ));
- if( !aCell ){
- return SQLITE_NOMEM;
- }
- aOrder = (int *)&aCell[n];
- aSpare = (int *)&aOrder[n];
- aDistance = (RtreeDValue *)&aSpare[n];
-
- for(ii=0; ii<nCell; ii++){
- if( ii==(nCell-1) ){
- memcpy(&aCell[ii], pCell, sizeof(RtreeCell));
- }else{
- nodeGetCell(pRtree, pNode, ii, &aCell[ii]);
- }
- aOrder[ii] = ii;
- for(iDim=0; iDim<pRtree->nDim; iDim++){
- aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2]);
- aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2+1]);
- }
- }
- for(iDim=0; iDim<pRtree->nDim; iDim++){
- aCenterCoord[iDim] = (aCenterCoord[iDim]/(nCell*(RtreeDValue)2));
- }
-
- for(ii=0; ii<nCell; ii++){
- aDistance[ii] = RTREE_ZERO;
- for(iDim=0; iDim<pRtree->nDim; iDim++){
- RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) -
- DCOORD(aCell[ii].aCoord[iDim*2]));
- aDistance[ii] += (coord-aCenterCoord[iDim])*(coord-aCenterCoord[iDim]);
- }
- }
-
- SortByDistance(aOrder, nCell, aDistance, aSpare);
- nodeZero(pRtree, pNode);
-
- for(ii=0; rc==SQLITE_OK && ii<(nCell-(RTREE_MINCELLS(pRtree)+1)); ii++){
- RtreeCell *p = &aCell[aOrder[ii]];
- nodeInsertCell(pRtree, pNode, p);
- if( p->iRowid==pCell->iRowid ){
- if( iHeight==0 ){
- rc = rowidWrite(pRtree, p->iRowid, pNode->iNode);
- }else{
- rc = parentWrite(pRtree, p->iRowid, pNode->iNode);
- }
- }
- }
- if( rc==SQLITE_OK ){
- rc = fixBoundingBox(pRtree, pNode);
- }
- for(; rc==SQLITE_OK && ii<nCell; ii++){
- /* Find a node to store this cell in. pNode->iNode currently contains
- ** the height of the sub-tree headed by the cell.
- */
- RtreeNode *pInsert;
- RtreeCell *p = &aCell[aOrder[ii]];
- rc = ChooseLeaf(pRtree, p, iHeight, &pInsert);
- if( rc==SQLITE_OK ){
- int rc2;
- rc = rtreeInsertCell(pRtree, pInsert, p, iHeight);
- rc2 = nodeRelease(pRtree, pInsert);
- if( rc==SQLITE_OK ){
- rc = rc2;
- }
- }
- }
-
- sqlite3_free(aCell);
- return rc;
-}
-
/*
** Insert cell pCell into node pNode. Node pNode is the head of a
** subtree iHeight high (leaf nodes have iHeight==0).
@@ -204462,12 +211561,7 @@ static int rtreeInsertCell(
}
}
if( nodeInsertCell(pRtree, pNode, pCell) ){
- if( iHeight<=pRtree->iReinsertHeight || pNode->iNode==1){
- rc = SplitNode(pRtree, pNode, pCell, iHeight);
- }else{
- pRtree->iReinsertHeight = iHeight;
- rc = Reinsert(pRtree, pNode, pCell, iHeight);
- }
+ rc = SplitNode(pRtree, pNode, pCell, iHeight);
}else{
rc = AdjustTree(pRtree, pNode, pCell);
if( ALWAYS(rc==SQLITE_OK) ){
@@ -204810,7 +211904,6 @@ static int rtreeUpdate(
}
if( rc==SQLITE_OK ){
int rc2;
- pRtree->iReinsertHeight = -1;
rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0);
rc2 = nodeRelease(pRtree, pLeaf);
if( rc==SQLITE_OK ){
@@ -204839,8 +211932,7 @@ constraint:
*/
static int rtreeBeginTransaction(sqlite3_vtab *pVtab){
Rtree *pRtree = (Rtree *)pVtab;
- assert( pRtree->inWrTrans==0 );
- pRtree->inWrTrans++;
+ pRtree->inWrTrans = 1;
return SQLITE_OK;
}
@@ -204854,6 +211946,9 @@ static int rtreeEndTransaction(sqlite3_vtab *pVtab){
nodeBlobReset(pRtree);
return SQLITE_OK;
}
+static int rtreeRollback(sqlite3_vtab *pVtab){
+ return rtreeEndTransaction(pVtab);
+}
/*
** The xRename method for rtree module virtual tables.
@@ -204951,8 +212046,11 @@ static int rtreeShadowName(const char *zName){
return 0;
}
+/* Forward declaration */
+static int rtreeIntegrity(sqlite3_vtab*, const char*, const char*, int, char**);
+
static sqlite3_module rtreeModule = {
- 3, /* iVersion */
+ 4, /* iVersion */
rtreeCreate, /* xCreate - create a table */
rtreeConnect, /* xConnect - connect to an existing table */
rtreeBestIndex, /* xBestIndex - Determine search strategy */
@@ -204969,13 +212067,14 @@ static sqlite3_module rtreeModule = {
rtreeBeginTransaction, /* xBegin - begin transaction */
rtreeEndTransaction, /* xSync - sync transaction */
rtreeEndTransaction, /* xCommit - commit transaction */
- rtreeEndTransaction, /* xRollback - rollback transaction */
+ rtreeRollback, /* xRollback - rollback transaction */
0, /* xFindFunction - function overloading */
rtreeRename, /* xRename - rename the table */
rtreeSavepoint, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- rtreeShadowName /* xShadowName */
+ rtreeShadowName, /* xShadowName */
+ rtreeIntegrity /* xIntegrity */
};
static int rtreeSqlInit(
@@ -205068,7 +212167,7 @@ static int rtreeSqlInit(
}
sqlite3_free(zSql);
}
- if( pRtree->nAux ){
+ if( pRtree->nAux && rc!=SQLITE_NOMEM ){
pRtree->zReadAuxSql = sqlite3_mprintf(
"SELECT * FROM \"%w\".\"%w_rowid\" WHERE rowid=?1",
zDb, zPrefix);
@@ -205231,22 +212330,27 @@ static int rtreeInit(
}
sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
+ sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
+
/* Allocate the sqlite3_vtab structure */
nDb = (int)strlen(argv[1]);
nName = (int)strlen(argv[2]);
- pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2);
+ pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName*2+8);
if( !pRtree ){
return SQLITE_NOMEM;
}
- memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2);
+ memset(pRtree, 0, sizeof(Rtree)+nDb+nName*2+8);
pRtree->nBusy = 1;
pRtree->base.pModule = &rtreeModule;
pRtree->zDb = (char *)&pRtree[1];
pRtree->zName = &pRtree->zDb[nDb+1];
+ pRtree->zNodeName = &pRtree->zName[nName+1];
pRtree->eCoordType = (u8)eCoordType;
memcpy(pRtree->zDb, argv[1], nDb);
memcpy(pRtree->zName, argv[2], nName);
+ memcpy(pRtree->zNodeName, argv[2], nName);
+ memcpy(&pRtree->zNodeName[nName], "_node", 6);
/* Create/Connect to the underlying relational database schema. If
@@ -205743,7 +212847,6 @@ static int rtreeCheckTable(
){
RtreeCheck check; /* Common context for various routines */
sqlite3_stmt *pStmt = 0; /* Used to find column count of rtree table */
- int bEnd = 0; /* True if transaction should be closed */
int nAux = 0; /* Number of extra columns. */
/* Initialize the context object */
@@ -205752,24 +212855,14 @@ static int rtreeCheckTable(
check.zDb = zDb;
check.zTab = zTab;
- /* If there is not already an open transaction, open one now. This is
- ** to ensure that the queries run as part of this integrity-check operate
- ** on a consistent snapshot. */
- if( sqlite3_get_autocommit(db) ){
- check.rc = sqlite3_exec(db, "BEGIN", 0, 0, 0);
- bEnd = 1;
- }
-
/* Find the number of auxiliary columns */
- if( check.rc==SQLITE_OK ){
- pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab);
- if( pStmt ){
- nAux = sqlite3_column_count(pStmt) - 2;
- sqlite3_finalize(pStmt);
- }else
- if( check.rc!=SQLITE_NOMEM ){
- check.rc = SQLITE_OK;
- }
+ pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab);
+ if( pStmt ){
+ nAux = sqlite3_column_count(pStmt) - 2;
+ sqlite3_finalize(pStmt);
+ }else
+ if( check.rc!=SQLITE_NOMEM ){
+ check.rc = SQLITE_OK;
}
/* Find number of dimensions in the rtree table. */
@@ -205800,16 +212893,36 @@ static int rtreeCheckTable(
sqlite3_finalize(check.aCheckMapping[0]);
sqlite3_finalize(check.aCheckMapping[1]);
- /* If one was opened, close the transaction */
- if( bEnd ){
- int rc = sqlite3_exec(db, "END", 0, 0, 0);
- if( check.rc==SQLITE_OK ) check.rc = rc;
- }
*pzReport = check.zReport;
return check.rc;
}
/*
+** Implementation of the xIntegrity method for Rtree.
+*/
+static int rtreeIntegrity(
+ sqlite3_vtab *pVtab, /* The virtual table to check */
+ const char *zSchema, /* Schema in which the virtual table lives */
+ const char *zName, /* Name of the virtual table */
+ int isQuick, /* True for a quick_check */
+ char **pzErr /* Write results here */
+){
+ Rtree *pRtree = (Rtree*)pVtab;
+ int rc;
+ assert( pzErr!=0 && *pzErr==0 );
+ UNUSED_PARAMETER(zSchema);
+ UNUSED_PARAMETER(zName);
+ UNUSED_PARAMETER(isQuick);
+ rc = rtreeCheckTable(pRtree->db, pRtree->zDb, pRtree->zName, pzErr);
+ if( rc==SQLITE_OK && *pzErr ){
+ *pzErr = sqlite3_mprintf("In RTree %s.%s:\n%z",
+ pRtree->zDb, pRtree->zName, *pzErr);
+ if( (*pzErr)==0 ) rc = SQLITE_NOMEM;
+ }
+ return rc;
+}
+
+/*
** Usage:
**
** rtreecheck(<rtree-table>);
@@ -207130,24 +214243,28 @@ static int geopolyInit(
(void)pAux;
sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1);
+ sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
/* Allocate the sqlite3_vtab structure */
nDb = strlen(argv[1]);
nName = strlen(argv[2]);
- pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName+2);
+ pRtree = (Rtree *)sqlite3_malloc64(sizeof(Rtree)+nDb+nName*2+8);
if( !pRtree ){
return SQLITE_NOMEM;
}
- memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2);
+ memset(pRtree, 0, sizeof(Rtree)+nDb+nName*2+8);
pRtree->nBusy = 1;
pRtree->base.pModule = &rtreeModule;
pRtree->zDb = (char *)&pRtree[1];
pRtree->zName = &pRtree->zDb[nDb+1];
+ pRtree->zNodeName = &pRtree->zName[nName+1];
pRtree->eCoordType = RTREE_COORD_REAL32;
pRtree->nDim = 2;
pRtree->nDim2 = 4;
memcpy(pRtree->zDb, argv[1], nDb);
memcpy(pRtree->zName, argv[2], nName);
+ memcpy(pRtree->zNodeName, argv[2], nName);
+ memcpy(&pRtree->zNodeName[nName], "_node", 6);
/* Create/Connect to the underlying relational database schema. If
@@ -207561,7 +214678,6 @@ static int geopolyUpdate(
}
if( rc==SQLITE_OK ){
int rc2;
- pRtree->iReinsertHeight = -1;
rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0);
rc2 = nodeRelease(pRtree, pLeaf);
if( rc==SQLITE_OK ){
@@ -207658,7 +214774,8 @@ static sqlite3_module geopolyModule = {
rtreeSavepoint, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- rtreeShadowName /* xShadowName */
+ rtreeShadowName, /* xShadowName */
+ rtreeIntegrity /* xIntegrity */
};
static int sqlite3_geopoly_init(sqlite3 *db){
@@ -212499,6 +219616,11 @@ static void rbuCheckpointFrame(sqlite3rbu *p, RbuFrame *pFrame){
p->rc = pDb->pMethods->xWrite(pDb, p->aBuf, p->pgsz, iOff);
}
+/*
+** This value is copied from the definition of ZIPVFS_CTRL_FILE_POINTER
+** in zipvfs.h.
+*/
+#define RBU_ZIPVFS_CTRL_FILE_POINTER 230439
/*
** Take an EXCLUSIVE lock on the database file. Return SQLITE_OK if
@@ -212507,9 +219629,20 @@ static void rbuCheckpointFrame(sqlite3rbu *p, RbuFrame *pFrame){
static int rbuLockDatabase(sqlite3 *db){
int rc = SQLITE_OK;
sqlite3_file *fd = 0;
- sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd);
- if( fd->pMethods ){
+ sqlite3_file_control(db, "main", RBU_ZIPVFS_CTRL_FILE_POINTER, &fd);
+ if( fd ){
+ sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd);
+ rc = fd->pMethods->xLock(fd, SQLITE_LOCK_SHARED);
+ if( rc==SQLITE_OK ){
+ rc = fd->pMethods->xUnlock(fd, SQLITE_LOCK_NONE);
+ }
+ sqlite3_file_control(db, "main", RBU_ZIPVFS_CTRL_FILE_POINTER, &fd);
+ }else{
+ sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd);
+ }
+
+ if( rc==SQLITE_OK && fd->pMethods ){
rc = fd->pMethods->xLock(fd, SQLITE_LOCK_SHARED);
if( rc==SQLITE_OK ){
rc = fd->pMethods->xLock(fd, SQLITE_LOCK_EXCLUSIVE);
@@ -215656,7 +222789,8 @@ SQLITE_PRIVATE int sqlite3DbstatRegister(sqlite3 *db){
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
return sqlite3_create_module(db, "dbstat", &dbstat_module, 0);
}
@@ -215746,6 +222880,7 @@ static int dbpageConnect(
(void)pzErr;
sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
+ sqlite3_vtab_config(db, SQLITE_VTAB_USES_ALL_SCHEMAS);
rc = sqlite3_declare_vtab(db,
"CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
if( rc==SQLITE_OK ){
@@ -215829,7 +222964,6 @@ static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
){
pIdxInfo->orderByConsumed = 1;
}
- sqlite3VtabUsesAllSchemas(pIdxInfo);
return SQLITE_OK;
}
@@ -216093,7 +223227,8 @@ SQLITE_PRIVATE int sqlite3DbpageRegister(sqlite3 *db){
0, /* xSavepoint */
0, /* xRelease */
0, /* xRollbackTo */
- 0 /* xShadowName */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
};
return sqlite3_create_module(db, "sqlite_dbpage", &dbpage_module, 0);
}
@@ -216130,6 +223265,8 @@ typedef struct SessionInput SessionInput;
# endif
#endif
+#define SESSIONS_ROWID "_rowid_"
+
static int sessions_strm_chunk_size = SESSIONS_STRM_CHUNK_SIZE;
typedef struct SessionHook SessionHook;
@@ -216151,6 +223288,7 @@ struct sqlite3_session {
int bEnable; /* True if currently recording */
int bIndirect; /* True if all changes are indirect */
int bAutoAttach; /* True to auto-attach tables */
+ int bImplicitPK; /* True to handle tables with implicit PK */
int rc; /* Non-zero if an error has occurred */
void *pFilterCtx; /* First argument to pass to xTableFilter */
int (*xTableFilter)(void *pCtx, const char *zTab);
@@ -216221,17 +223359,32 @@ struct sqlite3_changeset_iter {
** 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.
+**
+** pDfltStmt:
+** This is only used by the sqlite3changegroup_xxx() APIs, not by
+** regular sqlite3_session objects. It is a SELECT statement that
+** selects the default value for each table column. For example,
+** if the table is
+**
+** CREATE TABLE xx(a DEFAULT 1, b, c DEFAULT 'abc')
+**
+** then this variable is the compiled version of:
+**
+** SELECT 1, NULL, 'abc'
*/
struct SessionTable {
SessionTable *pNext;
char *zName; /* Local name of table */
int nCol; /* Number of columns in table zName */
int bStat1; /* True if this is sqlite_stat1 */
+ int bRowid; /* True if this table uses rowid for PK */
const char **azCol; /* Column names */
+ const char **azDflt; /* Default value expressions */
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 */
+ sqlite3_stmt *pDfltStmt;
};
/*
@@ -216400,6 +223553,7 @@ struct SessionTable {
struct SessionChange {
u8 op; /* One of UPDATE, DELETE, INSERT */
u8 bIndirect; /* True if this change is "indirect" */
+ u16 nRecordField; /* Number of fields in aRecord[] */
int nMaxSize; /* Max size of eventual changeset record */
int nRecord; /* Number of bytes in buffer aRecord[] */
u8 *aRecord; /* Buffer containing old.* record */
@@ -216425,7 +223579,7 @@ static int sessionVarintLen(int iVal){
** Read a varint value from aBuf[] into *piVal. Return the number of
** bytes read.
*/
-static int sessionVarintGet(u8 *aBuf, int *piVal){
+static int sessionVarintGet(const u8 *aBuf, int *piVal){
return getVarint32(aBuf, *piVal);
}
@@ -216619,6 +223773,7 @@ static unsigned int sessionHashAppendType(unsigned int h, int eType){
*/
static int sessionPreupdateHash(
sqlite3_session *pSession, /* Session object that owns pTab */
+ i64 iRowid,
SessionTable *pTab, /* Session table handle */
int bNew, /* True to hash the new.* PK */
int *piHash, /* OUT: Hash value */
@@ -216627,48 +223782,53 @@ static int sessionPreupdateHash(
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;
+ if( pTab->bRowid ){
+ assert( pTab->nCol-1==pSession->hook.xCount(pSession->hook.pCtx) );
+ h = sessionHashAppendI64(h, iRowid);
+ }else{
+ 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;
- 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);
+ if( bNew ){
+ rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal);
}else{
- double rVal = sqlite3_value_double(pVal);
- assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
- memcpy(&iVal, &rVal, 8);
+ rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal);
}
- 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);
+ 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{
- z = (const u8 *)sqlite3_value_blob(pVal);
+ assert( eType==SQLITE_NULL );
+ assert( pTab->bStat1==0 || i!=1 );
+ *pbNullPK = 1;
}
- 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 );
- assert( pTab->bStat1==0 || i!=1 );
- *pbNullPK = 1;
}
}
}
@@ -216682,9 +223842,11 @@ static int sessionPreupdateHash(
** Return the number of bytes of space occupied by the value (including
** the type byte).
*/
-static int sessionSerialLen(u8 *a){
- int e = *a;
+static int sessionSerialLen(const u8 *a){
+ int e;
int n;
+ assert( a!=0 );
+ e = *a;
if( e==0 || e==0xFF ) return 1;
if( e==SQLITE_NULL ) return 1;
if( e==SQLITE_INTEGER || e==SQLITE_FLOAT ) return 9;
@@ -216951,6 +224113,7 @@ static int sessionMergeUpdate(
*/
static int sessionPreupdateEqual(
sqlite3_session *pSession, /* Session object that owns SessionTable */
+ i64 iRowid, /* Rowid value if pTab->bRowid */
SessionTable *pTab, /* Table associated with change */
SessionChange *pChange, /* Change to compare to */
int op /* Current pre-update operation */
@@ -216958,6 +224121,11 @@ static int sessionPreupdateEqual(
int iCol; /* Used to iterate through columns */
u8 *a = pChange->aRecord; /* Cursor used to scan change record */
+ if( pTab->bRowid ){
+ if( a[0]!=SQLITE_INTEGER ) return 0;
+ return sessionGetI64(&a[1])==iRowid;
+ }
+
assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE );
for(iCol=0; iCol<pTab->nCol; iCol++){
if( !pTab->abPK[iCol] ){
@@ -216980,6 +224148,7 @@ static int sessionPreupdateEqual(
rc = pSession->hook.xOld(pSession->hook.pCtx, iCol, &pVal);
}
assert( rc==SQLITE_OK );
+ (void)rc; /* Suppress warning about unused variable */
if( sqlite3_value_type(pVal)!=eType ) return 0;
/* A SessionChange object never has a NULL value in a PK column */
@@ -217082,13 +224251,14 @@ static int sessionGrowHash(
**
** For example, if the table is declared as:
**
-** CREATE TABLE tbl1(w, x, y, z, PRIMARY KEY(w, z));
+** CREATE TABLE tbl1(w, x DEFAULT 'abc', y, z, PRIMARY KEY(w, z));
**
-** Then the four output variables are populated as follows:
+** Then the five output variables are populated as follows:
**
** *pnCol = 4
** *pzTab = "tbl1"
** *pazCol = {"w", "x", "y", "z"}
+** *pazDflt = {NULL, 'abc', NULL, NULL}
** *pabPK = {1, 0, 0, 1}
**
** All returned buffers are part of the same single allocation, which must
@@ -217102,7 +224272,9 @@ static int sessionTableInfo(
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 */
+ const char ***pazDflt, /* OUT: Array of default value expressions */
+ u8 **pabPK, /* OUT: Array of booleans - true for PK col */
+ int *pbRowid /* OUT: True if only PK is a rowid */
){
char *zPragma;
sqlite3_stmt *pStmt;
@@ -217113,10 +224285,18 @@ static int sessionTableInfo(
int i;
u8 *pAlloc = 0;
char **azCol = 0;
+ char **azDflt = 0;
u8 *abPK = 0;
+ int bRowid = 0; /* Set to true to use rowid as PK */
assert( pazCol && pabPK );
+ *pazCol = 0;
+ *pabPK = 0;
+ *pnCol = 0;
+ if( pzTab ) *pzTab = 0;
+ if( pazDflt ) *pazDflt = 0;
+
nThis = sqlite3Strlen30(zThis);
if( nThis==12 && 0==sqlite3_stricmp("sqlite_stat1", zThis) ){
rc = sqlite3_table_column_metadata(db, zDb, zThis, 0, 0, 0, 0, 0, 0);
@@ -217130,50 +224310,47 @@ static int sessionTableInfo(
}else if( rc==SQLITE_ERROR ){
zPragma = sqlite3_mprintf("");
}else{
- *pazCol = 0;
- *pabPK = 0;
- *pnCol = 0;
- if( pzTab ) *pzTab = 0;
return rc;
}
}else{
zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
}
if( !zPragma ){
- *pazCol = 0;
- *pabPK = 0;
- *pnCol = 0;
- if( pzTab ) *pzTab = 0;
return SQLITE_NOMEM;
}
rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
sqlite3_free(zPragma);
if( rc!=SQLITE_OK ){
- *pazCol = 0;
- *pabPK = 0;
- *pnCol = 0;
- if( pzTab ) *pzTab = 0;
return rc;
}
nByte = nThis + 1;
+ bRowid = (pbRowid!=0);
while( SQLITE_ROW==sqlite3_step(pStmt) ){
- nByte += sqlite3_column_bytes(pStmt, 1);
+ nByte += sqlite3_column_bytes(pStmt, 1); /* name */
+ nByte += sqlite3_column_bytes(pStmt, 4); /* dflt_value */
nDbCol++;
+ if( sqlite3_column_int(pStmt, 5) ) bRowid = 0; /* pk */
}
+ if( nDbCol==0 ) bRowid = 0;
+ nDbCol += bRowid;
+ nByte += strlen(SESSIONS_ROWID);
rc = sqlite3_reset(pStmt);
if( rc==SQLITE_OK ){
- nByte += nDbCol * (sizeof(const char *) + sizeof(u8) + 1);
+ nByte += nDbCol * (sizeof(const char *)*2 + sizeof(u8) + 1 + 1);
pAlloc = sessionMalloc64(pSession, nByte);
if( pAlloc==0 ){
rc = SQLITE_NOMEM;
+ }else{
+ memset(pAlloc, 0, nByte);
}
}
if( rc==SQLITE_OK ){
azCol = (char **)pAlloc;
- pAlloc = (u8 *)&azCol[nDbCol];
+ azDflt = (char**)&azCol[nDbCol];
+ pAlloc = (u8 *)&azDflt[nDbCol];
abPK = (u8 *)pAlloc;
pAlloc = &abPK[nDbCol];
if( pzTab ){
@@ -217183,43 +224360,57 @@ static int sessionTableInfo(
}
i = 0;
+ if( bRowid ){
+ size_t nName = strlen(SESSIONS_ROWID);
+ memcpy(pAlloc, SESSIONS_ROWID, nName+1);
+ azCol[i] = (char*)pAlloc;
+ pAlloc += nName+1;
+ abPK[i] = 1;
+ i++;
+ }
while( SQLITE_ROW==sqlite3_step(pStmt) ){
int nName = sqlite3_column_bytes(pStmt, 1);
+ int nDflt = sqlite3_column_bytes(pStmt, 4);
const unsigned char *zName = sqlite3_column_text(pStmt, 1);
+ const unsigned char *zDflt = sqlite3_column_text(pStmt, 4);
+
if( zName==0 ) break;
memcpy(pAlloc, zName, nName+1);
azCol[i] = (char *)pAlloc;
pAlloc += nName+1;
+ if( zDflt ){
+ memcpy(pAlloc, zDflt, nDflt+1);
+ azDflt[i] = (char *)pAlloc;
+ pAlloc += nDflt+1;
+ }else{
+ azDflt[i] = 0;
+ }
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;
+ *pazCol = (const char**)azCol;
+ if( pazDflt ) *pazDflt = (const char**)azDflt;
*pabPK = abPK;
*pnCol = nDbCol;
}else{
- *pazCol = 0;
- *pabPK = 0;
- *pnCol = 0;
- if( pzTab ) *pzTab = 0;
sessionFree(pSession, azCol);
}
+ if( pbRowid ) *pbRowid = bRowid;
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.
+** This function is called to initialize the SessionTable.nCol, azCol[]
+** abPK[] and azDflt[] members of SessionTable object pTab. If these
+** fields are already initilialized, this function is a no-op.
**
** 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
@@ -217227,14 +224418,22 @@ static int sessionTableInfo(
** 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){
+static int sessionInitTable(
+ sqlite3_session *pSession, /* Optional session handle */
+ SessionTable *pTab, /* Table object to initialize */
+ sqlite3 *db, /* Database handle to read schema from */
+ const char *zDb /* Name of db - "main", "temp" etc. */
+){
+ int rc = SQLITE_OK;
+
if( pTab->nCol==0 ){
u8 *abPK;
assert( pTab->azCol==0 || pTab->abPK==0 );
- pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb,
- pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK
+ rc = sessionTableInfo(pSession, db, zDb,
+ pTab->zName, &pTab->nCol, 0, &pTab->azCol, &pTab->azDflt, &abPK,
+ ((pSession==0 || pSession->bImplicitPK) ? &pTab->bRowid : 0)
);
- if( pSession->rc==SQLITE_OK ){
+ if( rc==SQLITE_OK ){
int i;
for(i=0; i<pTab->nCol; i++){
if( abPK[i] ){
@@ -217246,14 +224445,321 @@ static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
pTab->bStat1 = 1;
}
- if( pSession->bEnableSize ){
+ if( pSession && pSession->bEnableSize ){
pSession->nMaxChangesetSize += (
1 + sessionVarintLen(pTab->nCol) + pTab->nCol + strlen(pTab->zName)+1
);
}
}
}
- return (pSession->rc || pTab->abPK==0);
+
+ if( pSession ){
+ pSession->rc = rc;
+ return (rc || pTab->abPK==0);
+ }
+ return rc;
+}
+
+/*
+** Re-initialize table object pTab.
+*/
+static int sessionReinitTable(sqlite3_session *pSession, SessionTable *pTab){
+ int nCol = 0;
+ const char **azCol = 0;
+ const char **azDflt = 0;
+ u8 *abPK = 0;
+ int bRowid = 0;
+
+ assert( pSession->rc==SQLITE_OK );
+
+ pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb,
+ pTab->zName, &nCol, 0, &azCol, &azDflt, &abPK,
+ (pSession->bImplicitPK ? &bRowid : 0)
+ );
+ if( pSession->rc==SQLITE_OK ){
+ if( pTab->nCol>nCol || pTab->bRowid!=bRowid ){
+ pSession->rc = SQLITE_SCHEMA;
+ }else{
+ int ii;
+ int nOldCol = pTab->nCol;
+ for(ii=0; ii<nCol; ii++){
+ if( ii<pTab->nCol ){
+ if( pTab->abPK[ii]!=abPK[ii] ){
+ pSession->rc = SQLITE_SCHEMA;
+ }
+ }else if( abPK[ii] ){
+ pSession->rc = SQLITE_SCHEMA;
+ }
+ }
+
+ if( pSession->rc==SQLITE_OK ){
+ const char **a = pTab->azCol;
+ pTab->azCol = azCol;
+ pTab->nCol = nCol;
+ pTab->azDflt = azDflt;
+ pTab->abPK = abPK;
+ azCol = a;
+ }
+ if( pSession->bEnableSize ){
+ pSession->nMaxChangesetSize += (nCol - nOldCol);
+ pSession->nMaxChangesetSize += sessionVarintLen(nCol);
+ pSession->nMaxChangesetSize -= sessionVarintLen(nOldCol);
+ }
+ }
+ }
+
+ sqlite3_free((char*)azCol);
+ return pSession->rc;
+}
+
+/*
+** Session-change object (*pp) contains an old.* record with fewer than
+** nCol fields. This function updates it with the default values for
+** the missing fields.
+*/
+static void sessionUpdateOneChange(
+ sqlite3_session *pSession, /* For memory accounting */
+ int *pRc, /* IN/OUT: Error code */
+ SessionChange **pp, /* IN/OUT: Change object to update */
+ int nCol, /* Number of columns now in table */
+ sqlite3_stmt *pDflt /* SELECT <default-values...> */
+){
+ SessionChange *pOld = *pp;
+
+ while( pOld->nRecordField<nCol ){
+ SessionChange *pNew = 0;
+ int nByte = 0;
+ int nIncr = 0;
+ int iField = pOld->nRecordField;
+ int eType = sqlite3_column_type(pDflt, iField);
+ switch( eType ){
+ case SQLITE_NULL:
+ nIncr = 1;
+ break;
+ case SQLITE_INTEGER:
+ case SQLITE_FLOAT:
+ nIncr = 9;
+ break;
+ default: {
+ int n = sqlite3_column_bytes(pDflt, iField);
+ nIncr = 1 + sessionVarintLen(n) + n;
+ assert( eType==SQLITE_TEXT || eType==SQLITE_BLOB );
+ break;
+ }
+ }
+
+ nByte = nIncr + (sizeof(SessionChange) + pOld->nRecord);
+ pNew = sessionMalloc64(pSession, nByte);
+ if( pNew==0 ){
+ *pRc = SQLITE_NOMEM;
+ return;
+ }else{
+ memcpy(pNew, pOld, sizeof(SessionChange));
+ pNew->aRecord = (u8*)&pNew[1];
+ memcpy(pNew->aRecord, pOld->aRecord, pOld->nRecord);
+ pNew->aRecord[pNew->nRecord++] = (u8)eType;
+ switch( eType ){
+ case SQLITE_INTEGER: {
+ i64 iVal = sqlite3_column_int64(pDflt, iField);
+ sessionPutI64(&pNew->aRecord[pNew->nRecord], iVal);
+ pNew->nRecord += 8;
+ break;
+ }
+
+ case SQLITE_FLOAT: {
+ double rVal = sqlite3_column_double(pDflt, iField);
+ i64 iVal = 0;
+ memcpy(&iVal, &rVal, sizeof(rVal));
+ sessionPutI64(&pNew->aRecord[pNew->nRecord], iVal);
+ pNew->nRecord += 8;
+ break;
+ }
+
+ case SQLITE_TEXT: {
+ int n = sqlite3_column_bytes(pDflt, iField);
+ const char *z = (const char*)sqlite3_column_text(pDflt, iField);
+ pNew->nRecord += sessionVarintPut(&pNew->aRecord[pNew->nRecord], n);
+ memcpy(&pNew->aRecord[pNew->nRecord], z, n);
+ pNew->nRecord += n;
+ break;
+ }
+
+ case SQLITE_BLOB: {
+ int n = sqlite3_column_bytes(pDflt, iField);
+ const u8 *z = (const u8*)sqlite3_column_blob(pDflt, iField);
+ pNew->nRecord += sessionVarintPut(&pNew->aRecord[pNew->nRecord], n);
+ memcpy(&pNew->aRecord[pNew->nRecord], z, n);
+ pNew->nRecord += n;
+ break;
+ }
+
+ default:
+ assert( eType==SQLITE_NULL );
+ break;
+ }
+
+ sessionFree(pSession, pOld);
+ *pp = pOld = pNew;
+ pNew->nRecordField++;
+ pNew->nMaxSize += nIncr;
+ if( pSession ){
+ pSession->nMaxChangesetSize += nIncr;
+ }
+ }
+ }
+}
+
+/*
+** 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, i64 nByte, int *pRc){
+#define SESSION_MAX_BUFFER_SZ (0x7FFFFF00 - 1)
+ i64 nReq = p->nBuf + nByte;
+ if( *pRc==SQLITE_OK && nReq>p->nAlloc ){
+ u8 *aNew;
+ i64 nNew = p->nAlloc ? p->nAlloc : 128;
+
+ do {
+ nNew = nNew*2;
+ }while( nNew<nReq );
+
+ /* The value of SESSION_MAX_BUFFER_SZ is copied from the implementation
+ ** of sqlite3_realloc64(). Allocations greater than this size in bytes
+ ** always fail. It is used here to ensure that this routine can always
+ ** allocate up to this limit - instead of up to the largest power of
+ ** two smaller than the limit. */
+ if( nNew>SESSION_MAX_BUFFER_SZ ){
+ nNew = SESSION_MAX_BUFFER_SZ;
+ if( nNew<nReq ){
+ *pRc = SQLITE_NOMEM;
+ return 1;
+ }
+ }
+
+ aNew = (u8 *)sqlite3_realloc64(p->aBuf, nNew);
+ if( 0==aNew ){
+ *pRc = SQLITE_NOMEM;
+ }else{
+ p->aBuf = aNew;
+ p->nAlloc = nNew;
+ }
+ }
+ return (*pRc!=SQLITE_OK);
+}
+
+
+/*
+** 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+1, pRc) ){
+ memcpy(&p->aBuf[p->nBuf], zStr, nStr);
+ p->nBuf += nStr;
+ p->aBuf[p->nBuf] = 0x00;
+ }
+}
+
+/*
+** Format a string using printf() style formatting and then append it to the
+** buffer using sessionAppendString().
+*/
+static void sessionAppendPrintf(
+ SessionBuffer *p, /* Buffer to append to */
+ int *pRc,
+ const char *zFmt,
+ ...
+){
+ if( *pRc==SQLITE_OK ){
+ char *zApp = 0;
+ va_list ap;
+ va_start(ap, zFmt);
+ zApp = sqlite3_vmprintf(zFmt, ap);
+ if( zApp==0 ){
+ *pRc = SQLITE_NOMEM;
+ }else{
+ sessionAppendStr(p, zApp, pRc);
+ }
+ va_end(ap);
+ sqlite3_free(zApp);
+ }
+}
+
+/*
+** Prepare a statement against database handle db that SELECTs a single
+** row containing the default values for each column in table pTab. For
+** example, if pTab is declared as:
+**
+** CREATE TABLE pTab(a PRIMARY KEY, b DEFAULT 123, c DEFAULT 'abcd');
+**
+** Then this function prepares and returns the SQL statement:
+**
+** SELECT NULL, 123, 'abcd';
+*/
+static int sessionPrepareDfltStmt(
+ sqlite3 *db, /* Database handle */
+ SessionTable *pTab, /* Table to prepare statement for */
+ sqlite3_stmt **ppStmt /* OUT: Statement handle */
+){
+ SessionBuffer sql = {0,0,0};
+ int rc = SQLITE_OK;
+ const char *zSep = " ";
+ int ii = 0;
+
+ *ppStmt = 0;
+ sessionAppendPrintf(&sql, &rc, "SELECT");
+ for(ii=0; ii<pTab->nCol; ii++){
+ const char *zDflt = pTab->azDflt[ii] ? pTab->azDflt[ii] : "NULL";
+ sessionAppendPrintf(&sql, &rc, "%s%s", zSep, zDflt);
+ zSep = ", ";
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_prepare_v2(db, (const char*)sql.aBuf, -1, ppStmt, 0);
+ }
+ sqlite3_free(sql.aBuf);
+
+ return rc;
+}
+
+/*
+** Table pTab has one or more existing change-records with old.* records
+** with fewer than pTab->nCol columns. This function updates all such
+** change-records with the default values for the missing columns.
+*/
+static int sessionUpdateChanges(sqlite3_session *pSession, SessionTable *pTab){
+ sqlite3_stmt *pStmt = 0;
+ int rc = pSession->rc;
+
+ rc = sessionPrepareDfltStmt(pSession->db, pTab, &pStmt);
+ if( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+ int ii = 0;
+ SessionChange **pp = 0;
+ for(ii=0; ii<pTab->nChange; ii++){
+ for(pp=&pTab->apChange[ii]; *pp; pp=&((*pp)->pNext)){
+ if( (*pp)->nRecordField!=pTab->nCol ){
+ sessionUpdateOneChange(pSession, &rc, pp, pTab->nCol, pStmt);
+ }
+ }
+ }
+ }
+
+ pSession->rc = rc;
+ rc = sqlite3_finalize(pStmt);
+ if( pSession->rc==SQLITE_OK ) pSession->rc = rc;
+ return pSession->rc;
}
/*
@@ -217304,6 +224810,7 @@ static int sessionUpdateMaxSize(
){
i64 nNew = 2;
if( pC->op==SQLITE_INSERT ){
+ if( pTab->bRowid ) nNew += 9;
if( op!=SQLITE_DELETE ){
int ii;
for(ii=0; ii<pTab->nCol; ii++){
@@ -217320,12 +224827,16 @@ static int sessionUpdateMaxSize(
}else{
int ii;
u8 *pCsr = pC->aRecord;
- for(ii=0; ii<pTab->nCol; ii++){
+ if( pTab->bRowid ){
+ nNew += 9 + 1;
+ pCsr += 9;
+ }
+ for(ii=pTab->bRowid; ii<pTab->nCol; ii++){
int bChanged = 1;
int nOld = 0;
int eType;
sqlite3_value *p = 0;
- pSession->hook.xNew(pSession->hook.pCtx, ii, &p);
+ pSession->hook.xNew(pSession->hook.pCtx, ii-pTab->bRowid, &p);
if( p==0 ){
return SQLITE_NOMEM;
}
@@ -217404,22 +224915,29 @@ static int sessionUpdateMaxSize(
*/
static void sessionPreupdateOneChange(
int op, /* One of SQLITE_UPDATE, INSERT, DELETE */
+ i64 iRowid,
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;
+ int nExpect = 0;
SessionStat1Ctx stat1 = {{0,0,0,0,0},0};
if( pSession->rc ) return;
/* Load table details if required */
- if( sessionInitTable(pSession, pTab) ) return;
+ if( sessionInitTable(pSession, pTab, pSession->db, pSession->zDb) ) 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) ){
+ nExpect = pSession->hook.xCount(pSession->hook.pCtx);
+ if( (pTab->nCol-pTab->bRowid)<nExpect ){
+ if( sessionReinitTable(pSession, pTab) ) return;
+ if( sessionUpdateChanges(pSession, pTab) ) return;
+ }
+ if( (pTab->nCol-pTab->bRowid)!=nExpect ){
pSession->rc = SQLITE_SCHEMA;
return;
}
@@ -217452,14 +224970,16 @@ static void sessionPreupdateOneChange(
/* 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);
+ rc = sessionPreupdateHash(
+ pSession, iRowid, 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( sessionPreupdateEqual(pSession, iRowid, pTab, pC, op) ) break;
}
if( pC==0 ){
@@ -217474,7 +224994,7 @@ static void sessionPreupdateOneChange(
/* Figure out how large an allocation is required */
nByte = sizeof(SessionChange);
- for(i=0; i<pTab->nCol; i++){
+ for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
sqlite3_value *p = 0;
if( op!=SQLITE_INSERT ){
TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p);
@@ -217489,9 +225009,12 @@ static void sessionPreupdateOneChange(
rc = sessionSerializeValue(0, p, &nByte);
if( rc!=SQLITE_OK ) goto error_out;
}
+ if( pTab->bRowid ){
+ nByte += 9; /* Size of rowid field - an integer */
+ }
/* Allocate the change object */
- pC = (SessionChange *)sessionMalloc64(pSession, nByte);
+ pC = (SessionChange*)sessionMalloc64(pSession, nByte);
if( !pC ){
rc = SQLITE_NOMEM;
goto error_out;
@@ -217505,7 +225028,12 @@ static void sessionPreupdateOneChange(
** 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++){
+ if( pTab->bRowid ){
+ pC->aRecord[0] = SQLITE_INTEGER;
+ sessionPutI64(&pC->aRecord[1], iRowid);
+ nByte = 9;
+ }
+ for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
sqlite3_value *p = 0;
if( op!=SQLITE_INSERT ){
pSession->hook.xOld(pSession->hook.pCtx, i, &p);
@@ -217519,6 +225047,7 @@ static void sessionPreupdateOneChange(
if( pSession->bIndirect || pSession->hook.xDepth(pSession->hook.pCtx) ){
pC->bIndirect = 1;
}
+ pC->nRecordField = pTab->nCol;
pC->nRecord = nByte;
pC->op = op;
pC->pNext = pTab->apChange[iHash];
@@ -217620,9 +225149,10 @@ static void xPreUpdate(
pSession->rc = sessionFindTable(pSession, zName, &pTab);
if( pTab ){
assert( pSession->rc==SQLITE_OK );
- sessionPreupdateOneChange(op, pSession, pTab);
+ assert( op==SQLITE_UPDATE || iKey1==iKey2 );
+ sessionPreupdateOneChange(op, iKey1, pSession, pTab);
if( op==SQLITE_UPDATE ){
- sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab);
+ sessionPreupdateOneChange(SQLITE_INSERT, iKey2, pSession, pTab);
}
}
}
@@ -217661,6 +225191,7 @@ static void sessionPreupdateHooks(
typedef struct SessionDiffCtx SessionDiffCtx;
struct SessionDiffCtx {
sqlite3_stmt *pStmt;
+ int bRowid;
int nOldOff;
};
@@ -217669,17 +225200,17 @@ struct SessionDiffCtx {
*/
static int sessionDiffOld(void *pCtx, int iVal, sqlite3_value **ppVal){
SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
- *ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff);
+ *ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff+p->bRowid);
return SQLITE_OK;
}
static int sessionDiffNew(void *pCtx, int iVal, sqlite3_value **ppVal){
SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
- *ppVal = sqlite3_column_value(p->pStmt, iVal);
+ *ppVal = sqlite3_column_value(p->pStmt, iVal+p->bRowid);
return SQLITE_OK;
}
static int sessionDiffCount(void *pCtx){
SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
- return p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt);
+ return (p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt)) - p->bRowid;
}
static int sessionDiffDepth(void *pCtx){
(void)pCtx;
@@ -217758,14 +225289,16 @@ static char *sessionExprCompareOther(
static char *sessionSelectFindNew(
const char *zDb1, /* Pick rows in this db only */
const char *zDb2, /* But not in this one */
+ int bRowid,
const char *zTbl, /* Table name */
const char *zExpr
){
+ const char *zSel = (bRowid ? SESSIONS_ROWID ", *" : "*");
char *zRet = sqlite3_mprintf(
- "SELECT * FROM \"%w\".\"%w\" WHERE NOT EXISTS ("
+ "SELECT %s FROM \"%w\".\"%w\" WHERE NOT EXISTS ("
" SELECT 1 FROM \"%w\".\"%w\" WHERE %s"
")",
- zDb1, zTbl, zDb2, zTbl, zExpr
+ zSel, zDb1, zTbl, zDb2, zTbl, zExpr
);
return zRet;
}
@@ -217779,7 +225312,9 @@ static int sessionDiffFindNew(
char *zExpr
){
int rc = SQLITE_OK;
- char *zStmt = sessionSelectFindNew(zDb1, zDb2, pTab->zName,zExpr);
+ char *zStmt = sessionSelectFindNew(
+ zDb1, zDb2, pTab->bRowid, pTab->zName, zExpr
+ );
if( zStmt==0 ){
rc = SQLITE_NOMEM;
@@ -217790,8 +225325,10 @@ static int sessionDiffFindNew(
SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx;
pDiffCtx->pStmt = pStmt;
pDiffCtx->nOldOff = 0;
+ pDiffCtx->bRowid = pTab->bRowid;
while( SQLITE_ROW==sqlite3_step(pStmt) ){
- sessionPreupdateOneChange(op, pSession, pTab);
+ i64 iRowid = (pTab->bRowid ? sqlite3_column_int64(pStmt, 0) : 0);
+ sessionPreupdateOneChange(op, iRowid, pSession, pTab);
}
rc = sqlite3_finalize(pStmt);
}
@@ -217801,6 +225338,27 @@ static int sessionDiffFindNew(
return rc;
}
+/*
+** Return a comma-separated list of the fully-qualified (with both database
+** and table name) column names from table pTab. e.g.
+**
+** "main"."t1"."a", "main"."t1"."b", "main"."t1"."c"
+*/
+static char *sessionAllCols(
+ const char *zDb,
+ SessionTable *pTab
+){
+ int ii;
+ char *zRet = 0;
+ for(ii=0; ii<pTab->nCol; ii++){
+ zRet = sqlite3_mprintf("%z%s\"%w\".\"%w\".\"%w\"",
+ zRet, (zRet ? ", " : ""), zDb, pTab->zName, pTab->azCol[ii]
+ );
+ if( !zRet ) break;
+ }
+ return zRet;
+}
+
static int sessionDiffFindModified(
sqlite3_session *pSession,
SessionTable *pTab,
@@ -217815,11 +225373,13 @@ static int sessionDiffFindModified(
if( zExpr2==0 ){
rc = SQLITE_NOMEM;
}else{
+ char *z1 = sessionAllCols(pSession->zDb, pTab);
+ char *z2 = sessionAllCols(zFrom, pTab);
char *zStmt = sqlite3_mprintf(
- "SELECT * FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)",
- pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2
+ "SELECT %s,%s FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)",
+ z1, z2, pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2
);
- if( zStmt==0 ){
+ if( zStmt==0 || z1==0 || z2==0 ){
rc = SQLITE_NOMEM;
}else{
sqlite3_stmt *pStmt;
@@ -217830,12 +225390,15 @@ static int sessionDiffFindModified(
pDiffCtx->pStmt = pStmt;
pDiffCtx->nOldOff = pTab->nCol;
while( SQLITE_ROW==sqlite3_step(pStmt) ){
- sessionPreupdateOneChange(SQLITE_UPDATE, pSession, pTab);
+ i64 iRowid = (pTab->bRowid ? sqlite3_column_int64(pStmt, 0) : 0);
+ sessionPreupdateOneChange(SQLITE_UPDATE, iRowid, pSession, pTab);
}
rc = sqlite3_finalize(pStmt);
}
- sqlite3_free(zStmt);
}
+ sqlite3_free(zStmt);
+ sqlite3_free(z1);
+ sqlite3_free(z2);
}
return rc;
@@ -217864,7 +225427,7 @@ SQLITE_API int sqlite3session_diff(
/* Locate and if necessary initialize the target table object */
rc = sessionFindTable(pSession, zTbl, &pTo);
if( pTo==0 ) goto diff_out;
- if( sessionInitTable(pSession, pTo) ){
+ if( sessionInitTable(pSession, pTo, pSession->db, pSession->zDb) ){
rc = pSession->rc;
goto diff_out;
}
@@ -217874,9 +225437,12 @@ SQLITE_API int sqlite3session_diff(
int bHasPk = 0;
int bMismatch = 0;
int nCol; /* Columns in zFrom.zTbl */
+ int bRowid = 0;
u8 *abPK;
const char **azCol = 0;
- rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, &abPK);
+ rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, 0, &abPK,
+ pSession->bImplicitPK ? &bRowid : 0
+ );
if( rc==SQLITE_OK ){
if( pTo->nCol!=nCol ){
bMismatch = 1;
@@ -217989,6 +225555,7 @@ static void sessionDeleteTable(sqlite3_session *pSession, SessionTable *pList){
sessionFree(pSession, p);
}
}
+ sqlite3_finalize(pTab->pDfltStmt);
sessionFree(pSession, (char*)pTab->azCol); /* cast works around VC++ bug */
sessionFree(pSession, pTab->apChange);
sessionFree(pSession, pTab);
@@ -218021,9 +225588,7 @@ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession){
** associated hash-tables. */
sessionDeleteTable(pSession, pSession->pTable);
- /* Assert that all allocations have been freed and then free the
- ** session object itself. */
- assert( pSession->nMalloc==0 );
+ /* Free the session object. */
sqlite3_free(pSession);
}
@@ -218095,48 +225660,6 @@ SQLITE_API int sqlite3session_attach(
}
/*
-** 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, i64 nByte, int *pRc){
-#define SESSION_MAX_BUFFER_SZ (0x7FFFFF00 - 1)
- i64 nReq = p->nBuf + nByte;
- if( *pRc==SQLITE_OK && nReq>p->nAlloc ){
- u8 *aNew;
- i64 nNew = p->nAlloc ? p->nAlloc : 128;
-
- do {
- nNew = nNew*2;
- }while( nNew<nReq );
-
- /* The value of SESSION_MAX_BUFFER_SZ is copied from the implementation
- ** of sqlite3_realloc64(). Allocations greater than this size in bytes
- ** always fail. It is used here to ensure that this routine can always
- ** allocate up to this limit - instead of up to the largest power of
- ** two smaller than the limit. */
- if( nNew>SESSION_MAX_BUFFER_SZ ){
- nNew = SESSION_MAX_BUFFER_SZ;
- if( nNew<nReq ){
- *pRc = SQLITE_NOMEM;
- return 1;
- }
- }
-
- aNew = (u8 *)sqlite3_realloc64(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.
**
@@ -218206,26 +225729,6 @@ static void sessionAppendBlob(
/*
** 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.
**
@@ -218256,7 +225759,7 @@ static void sessionAppendIdent(
const char *zStr, /* String to quote, escape and append */
int *pRc /* IN/OUT: Error code */
){
- int nStr = sqlite3Strlen30(zStr)*2 + 2 + 1;
+ int nStr = sqlite3Strlen30(zStr)*2 + 2 + 2;
if( 0==sessionBufferGrow(p, nStr, pRc) ){
char *zOut = (char *)&p->aBuf[p->nBuf];
const char *zIn = zStr;
@@ -218267,6 +225770,7 @@ static void sessionAppendIdent(
}
*zOut++ = '"';
p->nBuf = (int)((u8 *)zOut - p->aBuf);
+ p->aBuf[p->nBuf] = 0x00;
}
}
@@ -218402,7 +225906,7 @@ static int sessionAppendUpdate(
/* 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
+ /* Add a field to the old.* record. This is omitted if this module is
** currently generating a patchset. */
if( bPatchset==0 ){
if( bChanged || abPK[i] ){
@@ -218491,12 +225995,20 @@ static int sessionAppendDelete(
** 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 ...
+** SELECT *, <noop-test> FROM zDb.zTab WHERE (pk1, pk2,...) IS (?1, ?2,...)
+**
+** where <noop-test> is:
+**
+** 1 AND (?A OR ?1 IS <column>) AND ...
+**
+** for each non-pk <column>.
*/
static int sessionSelectStmt(
sqlite3 *db, /* Database handle */
+ int bIgnoreNoop,
const char *zDb, /* Database name */
const char *zTab, /* Table name */
+ int bRowid,
int nCol, /* Number of columns in table */
const char **azCol, /* Names of table columns */
u8 *abPK, /* PRIMARY KEY array */
@@ -218504,16 +226016,57 @@ static int sessionSelectStmt(
){
int rc = SQLITE_OK;
char *zSql = 0;
+ const char *zSep = "";
+ const char *zCols = bRowid ? SESSIONS_ROWID ", *" : "*";
int nSql = -1;
+ int i;
+
+ SessionBuffer nooptest = {0, 0, 0};
+ SessionBuffer pkfield = {0, 0, 0};
+ SessionBuffer pkvar = {0, 0, 0};
+
+ sessionAppendStr(&nooptest, ", 1", &rc);
if( 0==sqlite3_stricmp("sqlite_stat1", zTab) ){
+ sessionAppendStr(&nooptest, " AND (?6 OR ?3 IS stat)", &rc);
+ sessionAppendStr(&pkfield, "tbl, idx", &rc);
+ sessionAppendStr(&pkvar,
+ "?1, (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", &rc
+ );
+ zCols = "tbl, ?2, stat";
+ }else{
+ for(i=0; i<nCol; i++){
+ if( abPK[i] ){
+ sessionAppendStr(&pkfield, zSep, &rc);
+ sessionAppendStr(&pkvar, zSep, &rc);
+ zSep = ", ";
+ sessionAppendIdent(&pkfield, azCol[i], &rc);
+ sessionAppendPrintf(&pkvar, &rc, "?%d", i+1);
+ }else{
+ sessionAppendPrintf(&nooptest, &rc,
+ " AND (?%d OR ?%d IS %w.%w)", i+1+nCol, i+1, zTab, azCol[i]
+ );
+ }
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ zSql = sqlite3_mprintf(
+ "SELECT %s%s FROM %Q.%Q WHERE (%s) IS (%s)",
+ zCols, (bIgnoreNoop ? (char*)nooptest.aBuf : ""),
+ zDb, zTab, (char*)pkfield.aBuf, (char*)pkvar.aBuf
+ );
+ if( zSql==0 ) rc = SQLITE_NOMEM;
+ }
+
+#if 0
+ if( 0==sqlite3_stricmp("sqlite_stat1", zTab) ){
zSql = sqlite3_mprintf(
"SELECT tbl, ?2, stat FROM %Q.sqlite_stat1 WHERE tbl IS ?1 AND "
"idx IS (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", zDb
);
if( zSql==0 ) rc = SQLITE_NOMEM;
}else{
- int i;
const char *zSep = "";
SessionBuffer buf = {0, 0, 0};
@@ -218534,11 +226087,15 @@ static int sessionSelectStmt(
zSql = (char*)buf.aBuf;
nSql = buf.nBuf;
}
+#endif
if( rc==SQLITE_OK ){
rc = sqlite3_prepare_v2(db, zSql, nSql, ppStmt, 0);
}
sqlite3_free(zSql);
+ sqlite3_free(nooptest.aBuf);
+ sqlite3_free(pkfield.aBuf);
+ sqlite3_free(pkvar.aBuf);
return rc;
}
@@ -218678,18 +226235,16 @@ static int sessionGenerateChangeset(
for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
if( pTab->nEntry ){
const char *zName = pTab->zName;
- int nCol = 0; /* Number of columns in table */
- u8 *abPK = 0; /* 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 */
+ int nOldCol = pTab->nCol;
/* Check the table schema is still Ok. */
- rc = sessionTableInfo(0, db, pSession->zDb, zName, &nCol, 0,&azCol,&abPK);
- if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){
- rc = SQLITE_SCHEMA;
+ rc = sessionReinitTable(pSession, pTab);
+ if( rc==SQLITE_OK && pTab->nCol!=nOldCol ){
+ rc = sessionUpdateChanges(pSession, pTab);
}
/* Write a table header */
@@ -218697,8 +226252,9 @@ static int sessionGenerateChangeset(
/* Build and compile a statement to execute: */
if( rc==SQLITE_OK ){
- rc = sessionSelectStmt(
- db, pSession->zDb, zName, nCol, azCol, abPK, &pSel);
+ rc = sessionSelectStmt(db, 0, pSession->zDb,
+ zName, pTab->bRowid, pTab->nCol, pTab->azCol, pTab->abPK, &pSel
+ );
}
nNoop = buf.nBuf;
@@ -218706,22 +226262,22 @@ static int sessionGenerateChangeset(
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);
+ rc = sessionSelectBind(pSel, pTab->nCol, pTab->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++){
+ for(iCol=0; iCol<pTab->nCol; iCol++){
sessionAppendCol(&buf, pSel, iCol, &rc);
}
}else{
- assert( abPK!=0 ); /* Because sessionSelectStmt() returned ok */
- rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, abPK);
+ assert( pTab->abPK!=0 );
+ rc = sessionAppendUpdate(&buf, bPatchset, pSel, p, pTab->abPK);
}
}else if( p->op!=SQLITE_INSERT ){
- rc = sessionAppendDelete(&buf, bPatchset, p, nCol, abPK);
+ rc = sessionAppendDelete(&buf, bPatchset, p, pTab->nCol,pTab->abPK);
}
if( rc==SQLITE_OK ){
rc = sqlite3_reset(pSel);
@@ -218746,7 +226302,6 @@ static int sessionGenerateChangeset(
if( buf.nBuf==nNoop ){
buf.nBuf = nRewind;
}
- sqlite3_free((char*)azCol); /* cast works around VC++ bug */
}
}
@@ -218781,7 +226336,7 @@ SQLITE_API int sqlite3session_changeset(
int rc;
if( pnChangeset==0 || ppChangeset==0 ) return SQLITE_MISUSE;
- rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset,ppChangeset);
+ rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset, ppChangeset);
assert( rc || pnChangeset==0
|| pSession->bEnableSize==0 || *pnChangeset<=pSession->nMaxChangesetSize
);
@@ -218899,6 +226454,19 @@ SQLITE_API int sqlite3session_object_config(sqlite3_session *pSession, int op, v
break;
}
+ case SQLITE_SESSION_OBJCONFIG_ROWID: {
+ int iArg = *(int*)pArg;
+ if( iArg>=0 ){
+ if( pSession->pTable ){
+ rc = SQLITE_MISUSE;
+ }else{
+ pSession->bImplicitPK = (iArg!=0);
+ }
+ }
+ *(int*)pArg = pSession->bImplicitPK;
+ break;
+ }
+
default:
rc = SQLITE_MISUSE;
}
@@ -219157,15 +226725,19 @@ static int sessionReadRecord(
}
}
if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
- sqlite3_int64 v = sessionGetI64(aVal);
- if( eType==SQLITE_INTEGER ){
- sqlite3VdbeMemSetInt64(apOut[i], v);
+ if( (pIn->nData-pIn->iNext)<8 ){
+ rc = SQLITE_CORRUPT_BKPT;
}else{
- double d;
- memcpy(&d, &v, 8);
- sqlite3VdbeMemSetDouble(apOut[i], d);
+ 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;
}
- pIn->iNext += 8;
}
}
}
@@ -219887,6 +227459,8 @@ struct SessionApplyCtx {
SessionBuffer rebase; /* Rebase information (if any) here */
u8 bRebaseStarted; /* If table header is already in rebase */
u8 bRebase; /* True to collect rebase information */
+ u8 bIgnoreNoop; /* True to ignore no-op conflicts */
+ int bRowid;
};
/* Number of prepared UPDATE statements to cache. */
@@ -220137,8 +227711,10 @@ static int sessionSelectRow(
const char *zTab, /* Table name */
SessionApplyCtx *p /* Session changeset-apply context */
){
- return sessionSelectStmt(
- db, "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect);
+ /* TODO */
+ return sessionSelectStmt(db, p->bIgnoreNoop,
+ "main", zTab, p->bRowid, p->nCol, p->azCol, p->abPK, &p->pSelect
+ );
}
/*
@@ -220297,20 +227873,33 @@ static int sessionBindRow(
*/
static int sessionSeekToRow(
sqlite3_changeset_iter *pIter, /* Changeset iterator */
- u8 *abPK, /* Primary key flags array */
- sqlite3_stmt *pSelect /* SELECT statement from sessionSelectRow() */
+ SessionApplyCtx *p
){
+ sqlite3_stmt *pSelect = p->pSelect;
int rc; /* Return code */
int nCol; /* Number of columns in table */
int op; /* Changset operation (SQLITE_UPDATE etc.) */
const char *zDummy; /* Unused */
+ sqlite3_clear_bindings(pSelect);
sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
rc = sessionBindRow(pIter,
op==SQLITE_INSERT ? sqlite3changeset_new : sqlite3changeset_old,
- nCol, abPK, pSelect
+ nCol, p->abPK, pSelect
);
+ if( op!=SQLITE_DELETE && p->bIgnoreNoop ){
+ int ii;
+ for(ii=0; rc==SQLITE_OK && ii<nCol; ii++){
+ if( p->abPK[ii]==0 ){
+ sqlite3_value *pVal = 0;
+ sqlite3changeset_new(pIter, ii, &pVal);
+ sqlite3_bind_int(pSelect, ii+1+nCol, (pVal==0));
+ if( pVal ) rc = sessionBindValue(pSelect, ii+1, pVal);
+ }
+ }
+ }
+
if( rc==SQLITE_OK ){
rc = sqlite3_step(pSelect);
if( rc!=SQLITE_ROW ) rc = sqlite3_reset(pSelect);
@@ -220425,16 +228014,22 @@ static int sessionConflictHandler(
/* Bind the new.* PRIMARY KEY values to the SELECT statement. */
if( pbReplace ){
- rc = sessionSeekToRow(pIter, p->abPK, p->pSelect);
+ rc = sessionSeekToRow(pIter, p);
}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;
+ if( p->bIgnoreNoop
+ && sqlite3_column_int(p->pSelect, sqlite3_column_count(p->pSelect)-1)
+ ){
+ res = SQLITE_CHANGESET_OMIT;
+ }else{
+ 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 ){
@@ -220542,7 +228137,7 @@ static int sessionApplyOneOp(
sqlite3_step(p->pDelete);
rc = sqlite3_reset(p->pDelete);
- if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
+ if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 && p->bIgnoreNoop==0 ){
rc = sessionConflictHandler(
SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
);
@@ -220599,7 +228194,7 @@ static int sessionApplyOneOp(
/* Check if there is a conflicting row. For sqlite_stat1, this needs
** to be done using a SELECT, as there is no PRIMARY KEY in the
** database schema to throw an exception if a duplicate is inserted. */
- rc = sessionSeekToRow(pIter, p->abPK, p->pSelect);
+ rc = sessionSeekToRow(pIter, p);
if( rc==SQLITE_ROW ){
rc = SQLITE_CONSTRAINT;
sqlite3_reset(p->pSelect);
@@ -220776,6 +228371,7 @@ static int sessionChangesetApply(
memset(&sApply, 0, sizeof(sApply));
sApply.bRebase = (ppRebase && pnRebase);
sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
+ sApply.bIgnoreNoop = !!(flags & SQLITE_CHANGESETAPPLY_IGNORENOOP);
sqlite3_mutex_enter(sqlite3_db_mutex(db));
if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
@@ -220813,6 +228409,7 @@ static int sessionChangesetApply(
sApply.bStat1 = 0;
sApply.bDeferConstraints = 1;
sApply.bRebaseStarted = 0;
+ sApply.bRowid = 0;
memset(&sApply.constraints, 0, sizeof(SessionBuffer));
/* If an xFilter() callback was specified, invoke it now. If the
@@ -220832,8 +228429,8 @@ static int sessionChangesetApply(
int i;
sqlite3changeset_pk(pIter, &abPK, 0);
- rc = sessionTableInfo(0,
- db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK
+ rc = sessionTableInfo(0, db, "main", zNew,
+ &sApply.nCol, &zTab, &sApply.azCol, 0, &sApply.abPK, &sApply.bRowid
);
if( rc!=SQLITE_OK ) break;
for(i=0; i<sApply.nCol; i++){
@@ -220965,11 +228562,24 @@ SQLITE_API int sqlite3changeset_apply_v2(
sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */
int bInv = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset, bInv, 1);
+ u64 savedFlag = db->flags & SQLITE_FkNoAction;
+
+ if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){
+ db->flags |= ((u64)SQLITE_FkNoAction);
+ db->aDb[0].pSchema->schema_cookie -= 32;
+ }
+
if( rc==SQLITE_OK ){
rc = sessionChangesetApply(
db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags
);
}
+
+ if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){
+ assert( db->flags & SQLITE_FkNoAction );
+ db->flags &= ~((u64)SQLITE_FkNoAction);
+ db->aDb[0].pSchema->schema_cookie -= 32;
+ }
return rc;
}
@@ -221057,6 +228667,9 @@ struct sqlite3_changegroup {
int rc; /* Error code */
int bPatch; /* True to accumulate patchsets */
SessionTable *pList; /* List of tables in current patch */
+
+ sqlite3 *db; /* Configured by changegroup_schema() */
+ char *zDb; /* Configured by changegroup_schema() */
};
/*
@@ -221077,6 +228690,7 @@ static int sessionChangeMerge(
){
SessionChange *pNew = 0;
int rc = SQLITE_OK;
+ assert( aRec!=0 );
if( !pExist ){
pNew = (SessionChange *)sqlite3_malloc64(sizeof(SessionChange) + nRec);
@@ -221243,6 +228857,114 @@ static int sessionChangeMerge(
}
/*
+** Check if a changeset entry with nCol columns and the PK array passed
+** as the final argument to this function is compatible with SessionTable
+** pTab. If so, return 1. Otherwise, if they are incompatible in some way,
+** return 0.
+*/
+static int sessionChangesetCheckCompat(
+ SessionTable *pTab,
+ int nCol,
+ u8 *abPK
+){
+ if( pTab->azCol && nCol<pTab->nCol ){
+ int ii;
+ for(ii=0; ii<pTab->nCol; ii++){
+ u8 bPK = (ii < nCol) ? abPK[ii] : 0;
+ if( pTab->abPK[ii]!=bPK ) return 0;
+ }
+ return 1;
+ }
+ return (pTab->nCol==nCol && 0==memcmp(abPK, pTab->abPK, nCol));
+}
+
+static int sessionChangesetExtendRecord(
+ sqlite3_changegroup *pGrp,
+ SessionTable *pTab,
+ int nCol,
+ int op,
+ const u8 *aRec,
+ int nRec,
+ SessionBuffer *pOut
+){
+ int rc = SQLITE_OK;
+ int ii = 0;
+
+ assert( pTab->azCol );
+ assert( nCol<pTab->nCol );
+
+ pOut->nBuf = 0;
+ if( op==SQLITE_INSERT || (op==SQLITE_DELETE && pGrp->bPatch==0) ){
+ /* Append the missing default column values to the record. */
+ sessionAppendBlob(pOut, aRec, nRec, &rc);
+ if( rc==SQLITE_OK && pTab->pDfltStmt==0 ){
+ rc = sessionPrepareDfltStmt(pGrp->db, pTab, &pTab->pDfltStmt);
+ }
+ for(ii=nCol; rc==SQLITE_OK && ii<pTab->nCol; ii++){
+ int eType = sqlite3_column_type(pTab->pDfltStmt, ii);
+ sessionAppendByte(pOut, eType, &rc);
+ switch( eType ){
+ case SQLITE_FLOAT:
+ case SQLITE_INTEGER: {
+ i64 iVal;
+ if( eType==SQLITE_INTEGER ){
+ iVal = sqlite3_column_int64(pTab->pDfltStmt, ii);
+ }else{
+ double rVal = sqlite3_column_int64(pTab->pDfltStmt, ii);
+ memcpy(&iVal, &rVal, sizeof(i64));
+ }
+ if( SQLITE_OK==sessionBufferGrow(pOut, 8, &rc) ){
+ sessionPutI64(&pOut->aBuf[pOut->nBuf], iVal);
+ }
+ break;
+ }
+
+ case SQLITE_BLOB:
+ case SQLITE_TEXT: {
+ int n = sqlite3_column_bytes(pTab->pDfltStmt, ii);
+ sessionAppendVarint(pOut, n, &rc);
+ if( eType==SQLITE_TEXT ){
+ const u8 *z = (const u8*)sqlite3_column_text(pTab->pDfltStmt, ii);
+ sessionAppendBlob(pOut, z, n, &rc);
+ }else{
+ const u8 *z = (const u8*)sqlite3_column_blob(pTab->pDfltStmt, ii);
+ sessionAppendBlob(pOut, z, n, &rc);
+ }
+ break;
+ }
+
+ default:
+ assert( eType==SQLITE_NULL );
+ break;
+ }
+ }
+ }else if( op==SQLITE_UPDATE ){
+ /* Append missing "undefined" entries to the old.* record. And, if this
+ ** is an UPDATE, to the new.* record as well. */
+ int iOff = 0;
+ if( pGrp->bPatch==0 ){
+ for(ii=0; ii<nCol; ii++){
+ iOff += sessionSerialLen(&aRec[iOff]);
+ }
+ sessionAppendBlob(pOut, aRec, iOff, &rc);
+ for(ii=0; ii<(pTab->nCol-nCol); ii++){
+ sessionAppendByte(pOut, 0x00, &rc);
+ }
+ }
+
+ sessionAppendBlob(pOut, &aRec[iOff], nRec-iOff, &rc);
+ for(ii=0; ii<(pTab->nCol-nCol); ii++){
+ sessionAppendByte(pOut, 0x00, &rc);
+ }
+ }else{
+ assert( op==SQLITE_DELETE && pGrp->bPatch );
+ sessionAppendBlob(pOut, aRec, nRec, &rc);
+ }
+
+ return rc;
+}
+
+/*
** Add all changes in the changeset traversed by the iterator passed as
** the first argument to the changegroup hash tables.
*/
@@ -221255,6 +228977,7 @@ static int sessionChangesetToHash(
int nRec;
int rc = SQLITE_OK;
SessionTable *pTab = 0;
+ SessionBuffer rec = {0, 0, 0};
while( SQLITE_ROW==sessionChangesetNext(pIter, &aRec, &nRec, 0) ){
const char *zNew;
@@ -221266,6 +228989,9 @@ static int sessionChangesetToHash(
SessionChange *pExist = 0;
SessionChange **pp;
+ /* Ensure that only changesets, or only patchsets, but not a mixture
+ ** of both, are being combined. It is an error to try to combine a
+ ** changeset and a patchset. */
if( pGrp->pList==0 ){
pGrp->bPatch = pIter->bPatchset;
}else if( pIter->bPatchset!=pGrp->bPatch ){
@@ -221298,18 +229024,38 @@ static int sessionChangesetToHash(
pTab->zName = (char*)&pTab->abPK[nCol];
memcpy(pTab->zName, zNew, nNew+1);
+ if( pGrp->db ){
+ pTab->nCol = 0;
+ rc = sessionInitTable(0, pTab, pGrp->db, pGrp->zDb);
+ if( rc ){
+ assert( pTab->azCol==0 );
+ sqlite3_free(pTab);
+ break;
+ }
+ }
+
/* 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) ){
+ }
+
+ if( !sessionChangesetCheckCompat(pTab, nCol, abPK) ){
rc = SQLITE_SCHEMA;
break;
}
}
+ if( nCol<pTab->nCol ){
+ assert( pGrp->db );
+ rc = sessionChangesetExtendRecord(pGrp, pTab, nCol, op, aRec, nRec, &rec);
+ if( rc ) break;
+ aRec = rec.aBuf;
+ nRec = rec.nBuf;
+ }
+
if( sessionGrowHash(0, pIter->bPatchset, pTab) ){
rc = SQLITE_NOMEM;
break;
@@ -221347,6 +229093,7 @@ static int sessionChangesetToHash(
}
}
+ sqlite3_free(rec.aBuf);
if( rc==SQLITE_OK ) rc = pIter->rc;
return rc;
}
@@ -221434,6 +229181,31 @@ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp){
}
/*
+** Provide a database schema to the changegroup object.
+*/
+SQLITE_API int sqlite3changegroup_schema(
+ sqlite3_changegroup *pGrp,
+ sqlite3 *db,
+ const char *zDb
+){
+ int rc = SQLITE_OK;
+
+ if( pGrp->pList || pGrp->db ){
+ /* Cannot add a schema after one or more calls to sqlite3changegroup_add(),
+ ** or after sqlite3changegroup_schema() has already been called. */
+ rc = SQLITE_MISUSE;
+ }else{
+ pGrp->zDb = sqlite3_mprintf("%s", zDb);
+ if( pGrp->zDb==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ pGrp->db = db;
+ }
+ }
+ return rc;
+}
+
+/*
** Add the changeset currently stored in buffer pData, size nData bytes,
** to changeset-group p.
*/
@@ -221496,6 +229268,7 @@ SQLITE_API int sqlite3changegroup_output_strm(
*/
SQLITE_API void sqlite3changegroup_delete(sqlite3_changegroup *pGrp){
if( pGrp ){
+ sqlite3_free(pGrp->zDb);
sessionDeleteTable(0, pGrp->pList);
sqlite3_free(pGrp);
}
@@ -222028,8 +229801,11 @@ struct Fts5PhraseIter {
** created with the "columnsize=0" option.
**
** xColumnText:
-** This function attempts to retrieve the text of column iCol of the
-** current document. If successful, (*pz) is set to point to a buffer
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of columns in the table, SQLITE_RANGE is returned.
+**
+** Otherwise, this function attempts to retrieve the text of column iCol of
+** the current document. If successful, (*pz) is set to point to a buffer
** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
** if an error occurs, an SQLite error code is returned and the final values
@@ -222039,8 +229815,10 @@ struct Fts5PhraseIter {
** Returns the number of phrases in the current query expression.
**
** xPhraseSize:
-** Returns the number of tokens in phrase iPhrase of the query. Phrases
-** are numbered starting from zero.
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of phrases in the current query, as returned by xPhraseCount,
+** 0 is returned. Otherwise, this function returns the number of tokens in
+** phrase iPhrase of the query. Phrases are numbered starting from zero.
**
** xInstCount:
** Set *pnInst to the total number of occurrences of all phrases within
@@ -222056,12 +229834,13 @@ struct Fts5PhraseIter {
** Query for the details of phrase match iIdx within the current row.
** Phrase matches are numbered starting from zero, so the iIdx argument
** should be greater than or equal to zero and smaller than the value
-** output by xInstCount().
+** output by xInstCount(). If iIdx is less than zero or greater than
+** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned.
**
-** Usually, output parameter *piPhrase is set to the phrase number, *piCol
+** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol
** to the column in which it occurs and *piOff the token offset of the
-** first token of the phrase. Returns SQLITE_OK if successful, or an error
-** code (i.e. SQLITE_NOMEM) if an error occurs.
+** first token of the phrase. SQLITE_OK is returned if successful, or an
+** error code (i.e. SQLITE_NOMEM) if an error occurs.
**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option.
@@ -222087,6 +229866,10 @@ struct Fts5PhraseIter {
** Invoking Api.xUserData() returns a copy of the pointer passed as
** the third argument to pUserData.
**
+** If parameter iPhrase is less than zero, or greater than or equal to
+** the number of phrases in the query, as returned by xPhraseCount(),
+** this function returns SQLITE_RANGE.
+**
** If the callback function returns any value other than SQLITE_OK, the
** query is abandoned and the xQueryPhrase function returns immediately.
** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
@@ -222201,6 +229984,39 @@ struct Fts5PhraseIter {
**
** xPhraseNextColumn()
** See xPhraseFirstColumn above.
+**
+** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase iPhrase of the current
+** query. Before returning, output parameter *ppToken is set to point
+** to a buffer containing the requested token, and *pnToken to the
+** size of this buffer in bytes.
+**
+** If iPhrase or iToken are less than zero, or if iPhrase is greater than
+** or equal to the number of phrases in the query as reported by
+** xPhraseCount(), or if iToken is equal to or greater than the number of
+** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken
+ are both zeroed.
+**
+** The output text is not a copy of the query text that specified the
+** token. It is the output of the tokenizer module. For tokendata=1
+** tables, this includes any embedded 0x00 and trailing data.
+**
+** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase hit iIdx within the
+** current row. If iIdx is less than zero or greater than or equal to the
+** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
+** output variable (*ppToken) is set to point to a buffer containing the
+** matching document token, and (*pnToken) to the size of that buffer in
+** bytes. This API is not available if the specified token matches a
+** prefix query term. In that case both output variables are always set
+** to 0.
+**
+** The output text is not a copy of the document text that was tokenized.
+** It is the output of the tokenizer module. For tokendata=1 tables, this
+** includes any embedded 0x00 and trailing data.
+**
+** This API can be quite slow if used with an FTS5 table created with the
+** "detail=none" or "detail=column" option.
*/
struct Fts5ExtensionApi {
int iVersion; /* Currently always set to 3 */
@@ -222238,6 +230054,13 @@ struct Fts5ExtensionApi {
int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
+
+ /* Below this point are iVersion>=3 only */
+ int (*xQueryToken)(Fts5Context*,
+ int iPhrase, int iToken,
+ const char **ppToken, int *pnToken
+ );
+ int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
};
/*
@@ -222432,8 +230255,8 @@ struct Fts5ExtensionApi {
** as separate queries of the FTS index are required for each synonym.
**
** When using methods (2) or (3), it is important that the tokenizer only
-** provide synonyms when tokenizing document text (method (2)) or query
-** text (method (3)), not both. Doing so will not cause any errors, but is
+** provide synonyms when tokenizing document text (method (3)) or query
+** text (method (2)), not both. Doing so will not cause any errors, but is
** inefficient.
*/
typedef struct Fts5Tokenizer Fts5Tokenizer;
@@ -222481,7 +230304,7 @@ struct fts5_api {
int (*xCreateTokenizer)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_tokenizer *pTokenizer,
void (*xDestroy)(void*)
);
@@ -222490,7 +230313,7 @@ struct fts5_api {
int (*xFindTokenizer)(
fts5_api *pApi,
const char *zName,
- void **ppContext,
+ void **ppUserData,
fts5_tokenizer *pTokenizer
);
@@ -222498,7 +230321,7 @@ struct fts5_api {
int (*xCreateFunction)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_extension_function xFunction,
void (*xDestroy)(void*)
);
@@ -222670,6 +230493,10 @@ typedef struct Fts5Config Fts5Config;
** attempt to merge together. A value of 1 sets the object to use the
** compile time default. Zero disables auto-merge altogether.
**
+** bContentlessDelete:
+** True if the contentless_delete option was present in the CREATE
+** VIRTUAL TABLE statement.
+**
** zContent:
**
** zContentRowid:
@@ -222704,9 +230531,11 @@ struct Fts5Config {
int nPrefix; /* Number of prefix indexes */
int *aPrefix; /* Sizes in bytes of nPrefix prefix indexes */
int eContent; /* An FTS5_CONTENT value */
+ int bContentlessDelete; /* "contentless_delete=" option (dflt==0) */
char *zContent; /* content table */
char *zContentRowid; /* "content_rowid=" option value */
int bColumnsize; /* "columnsize=" option value (dflt==1) */
+ int bTokendata; /* "tokendata=" option value (dflt==0) */
int eDetail; /* FTS5_DETAIL_XXX value */
char *zContentExprlist;
Fts5Tokenizer *pTok;
@@ -222715,6 +230544,7 @@ struct Fts5Config {
int ePattern; /* FTS_PATTERN_XXX constant */
/* Values loaded from the %_config table */
+ int iVersion; /* fts5 file format 'version' */
int iCookie; /* Incremented when %_config is modified */
int pgsz; /* Approximate page size used in %_data */
int nAutomerge; /* 'automerge' setting */
@@ -222723,6 +230553,8 @@ struct Fts5Config {
int nHashSize; /* Bytes of memory for in-memory hash */
char *zRank; /* Name of rank function */
char *zRankArgs; /* Arguments to rank function */
+ int bSecureDelete; /* 'secure-delete' */
+ int nDeleteMerge; /* 'deletemerge' */
/* If non-NULL, points to sqlite3_vtab.base.zErrmsg. Often NULL. */
char **pzErrmsg;
@@ -222732,8 +230564,11 @@ struct Fts5Config {
#endif
};
-/* Current expected value of %_config table 'version' field */
-#define FTS5_CURRENT_VERSION 4
+/* Current expected value of %_config table 'version' field. And
+** the expected version if the 'secure-delete' option has ever been
+** set on the table. */
+#define FTS5_CURRENT_VERSION 4
+#define FTS5_CURRENT_VERSION_SECUREDELETE 5
#define FTS5_CONTENT_NORMAL 0
#define FTS5_CONTENT_NONE 1
@@ -222889,16 +230724,19 @@ struct Fts5IndexIter {
/*
** Values used as part of the flags argument passed to IndexQuery().
*/
-#define FTS5INDEX_QUERY_PREFIX 0x0001 /* Prefix query */
-#define FTS5INDEX_QUERY_DESC 0x0002 /* Docs in descending rowid order */
-#define FTS5INDEX_QUERY_TEST_NOIDX 0x0004 /* Do not use prefix index */
-#define FTS5INDEX_QUERY_SCAN 0x0008 /* Scan query (fts5vocab) */
+#define FTS5INDEX_QUERY_PREFIX 0x0001 /* Prefix query */
+#define FTS5INDEX_QUERY_DESC 0x0002 /* Docs in descending rowid order */
+#define FTS5INDEX_QUERY_TEST_NOIDX 0x0004 /* Do not use prefix index */
+#define FTS5INDEX_QUERY_SCAN 0x0008 /* Scan query (fts5vocab) */
/* The following are used internally by the fts5_index.c module. They are
** defined here only to make it easier to avoid clashes with the flags
** above. */
-#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010
-#define FTS5INDEX_QUERY_NOOUTPUT 0x0020
+#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010
+#define FTS5INDEX_QUERY_NOOUTPUT 0x0020
+#define FTS5INDEX_QUERY_SKIPHASH 0x0040
+#define FTS5INDEX_QUERY_NOTOKENDATA 0x0080
+#define FTS5INDEX_QUERY_SCANONETERM 0x0100
/*
** Create/destroy an Fts5Index object.
@@ -222967,6 +230805,10 @@ static void *sqlite3Fts5StructureRef(Fts5Index*);
static void sqlite3Fts5StructureRelease(void*);
static int sqlite3Fts5StructureTest(Fts5Index*, void*);
+/*
+** Used by xInstToken():
+*/
+static int sqlite3Fts5IterToken(Fts5IndexIter*, i64, int, int, const char**, int*);
/*
** Insert or remove data to or from the index. Each time a document is
@@ -223041,6 +230883,16 @@ static int sqlite3Fts5IndexReset(Fts5Index *p);
static int sqlite3Fts5IndexLoadConfig(Fts5Index *p);
+static int sqlite3Fts5IndexGetOrigin(Fts5Index *p, i64 *piOrigin);
+static int sqlite3Fts5IndexContentlessDelete(Fts5Index *p, i64 iOrigin, i64 iRowid);
+
+static void sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter*);
+
+/* Used to populate hash tables for xInstToken in detail=none/column mode. */
+static int sqlite3Fts5IndexIterWriteTokendata(
+ Fts5IndexIter*, const char*, int, i64 iRowid, int iCol, int iOff
+);
+
/*
** End of interface to code in fts5_index.c.
**************************************************************************/
@@ -223053,7 +230905,7 @@ static int sqlite3Fts5GetVarintLen(u32 iVal);
static u8 sqlite3Fts5GetVarint(const unsigned char*, u64*);
static int sqlite3Fts5PutVarint(unsigned char *p, u64 v);
-#define fts5GetVarint32(a,b) sqlite3Fts5GetVarint32(a,(u32*)&b)
+#define fts5GetVarint32(a,b) sqlite3Fts5GetVarint32(a,(u32*)&(b))
#define fts5GetVarint sqlite3Fts5GetVarint
#define fts5FastGetVarint32(a, iOff, nVal) { \
@@ -223125,6 +230977,11 @@ static int sqlite3Fts5HashWrite(
*/
static void sqlite3Fts5HashClear(Fts5Hash*);
+/*
+** Return true if the hash is empty, false otherwise.
+*/
+static int sqlite3Fts5HashIsEmpty(Fts5Hash*);
+
static int sqlite3Fts5HashQuery(
Fts5Hash*, /* Hash table to query */
int nPre,
@@ -223141,11 +230998,13 @@ static void sqlite3Fts5HashScanNext(Fts5Hash*);
static int sqlite3Fts5HashScanEof(Fts5Hash*);
static void sqlite3Fts5HashScanEntry(Fts5Hash *,
const char **pzTerm, /* OUT: term (nul-terminated) */
+ int *pnTerm, /* OUT: Size of term in bytes */
const u8 **ppDoclist, /* OUT: pointer to doclist */
int *pnDoclist /* OUT: size of doclist in bytes */
);
+
/*
** End of interface to code in fts5_hash.c.
**************************************************************************/
@@ -223266,6 +231125,10 @@ static int sqlite3Fts5ExprClonePhrase(Fts5Expr*, int, Fts5Expr**);
static int sqlite3Fts5ExprPhraseCollist(Fts5Expr *, int, const u8 **, int *);
+static int sqlite3Fts5ExprQueryToken(Fts5Expr*, int, int, const char**, int*);
+static int sqlite3Fts5ExprInstToken(Fts5Expr*, i64, int, int, int, int, const char**, int*);
+static void sqlite3Fts5ExprClearTokens(Fts5Expr*);
+
/*******************************************
** The fts5_expr.c API above this point is used by the other hand-written
** C code in this module. The interfaces below this point are called by
@@ -223389,7 +231252,8 @@ static void sqlite3Fts5UnicodeAscii(u8*, u8*);
#define FTS5_STAR 15
/* This file is automatically generated by Lemon from input grammar
-** source file "fts5parse.y". */
+** source file "fts5parse.y".
+*/
/*
** 2000-05-29
**
@@ -224979,15 +232843,19 @@ static int fts5CInstIterInit(
*/
typedef struct HighlightContext HighlightContext;
struct HighlightContext {
- CInstIter iter; /* Coalesced Instance Iterator */
- int iPos; /* Current token offset in zIn[] */
+ /* Constant parameters to fts5HighlightCb() */
int iRangeStart; /* First token to include */
int iRangeEnd; /* If non-zero, last token to include */
const char *zOpen; /* Opening highlight */
const char *zClose; /* Closing highlight */
const char *zIn; /* Input text */
int nIn; /* Size of input text in bytes */
- int iOff; /* Current offset within zIn[] */
+
+ /* Variables modified by fts5HighlightCb() */
+ CInstIter iter; /* Coalesced Instance Iterator */
+ int iPos; /* Current token offset in zIn[] */
+ int iOff; /* Have copied up to this offset in zIn[] */
+ int bOpen; /* True if highlight is open */
char *zOut; /* Output value */
};
@@ -225020,8 +232888,8 @@ static int fts5HighlightCb(
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 iStartOff, /* Start byte offset of token */
+ int iEndOff /* End byte offset of token */
){
HighlightContext *p = (HighlightContext*)pContext;
int rc = SQLITE_OK;
@@ -225032,35 +232900,60 @@ static int fts5HighlightCb(
if( tflags & FTS5_TOKEN_COLOCATED ) return SQLITE_OK;
iPos = p->iPos++;
- if( p->iRangeEnd>0 ){
+ if( p->iRangeEnd>=0 ){
if( iPos<p->iRangeStart || iPos>p->iRangeEnd ) return SQLITE_OK;
if( p->iRangeStart && iPos==p->iRangeStart ) p->iOff = iStartOff;
}
- if( iPos==p->iter.iStart ){
+ /* If the parenthesis is open, and this token is not part of the current
+ ** phrase, and the starting byte offset of this token is past the point
+ ** that has currently been copied into the output buffer, close the
+ ** parenthesis. */
+ if( p->bOpen
+ && (iPos<=p->iter.iStart || p->iter.iStart<0)
+ && iStartOff>p->iOff
+ ){
+ fts5HighlightAppend(&rc, p, p->zClose, -1);
+ p->bOpen = 0;
+ }
+
+ /* If this is the start of a new phrase, and the highlight is not open:
+ **
+ ** * copy text from the input up to the start of the phrase, and
+ ** * open the highlight.
+ */
+ if( iPos==p->iter.iStart && p->bOpen==0 ){
fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iStartOff - p->iOff);
fts5HighlightAppend(&rc, p, p->zOpen, -1);
p->iOff = iStartOff;
+ p->bOpen = 1;
}
if( iPos==p->iter.iEnd ){
- if( p->iRangeEnd && p->iter.iStart<p->iRangeStart ){
+ if( p->bOpen==0 ){
+ assert( p->iRangeEnd>=0 );
fts5HighlightAppend(&rc, p, p->zOpen, -1);
+ p->bOpen = 1;
}
fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
- fts5HighlightAppend(&rc, p, p->zClose, -1);
p->iOff = iEndOff;
+
if( rc==SQLITE_OK ){
rc = fts5CInstIterNext(&p->iter);
}
}
- if( p->iRangeEnd>0 && iPos==p->iRangeEnd ){
- fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
- p->iOff = iEndOff;
- if( iPos>=p->iter.iStart && iPos<p->iter.iEnd ){
+ if( iPos==p->iRangeEnd ){
+ if( p->bOpen ){
+ if( p->iter.iStart>=0 && iPos>=p->iter.iStart ){
+ fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
+ p->iOff = iEndOff;
+ }
fts5HighlightAppend(&rc, p, p->zClose, -1);
+ p->bOpen = 0;
}
+ fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
+ p->iOff = iEndOff;
}
return rc;
@@ -225090,9 +232983,12 @@ static void fts5HighlightFunction(
memset(&ctx, 0, sizeof(HighlightContext));
ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]);
ctx.zClose = (const char*)sqlite3_value_text(apVal[2]);
+ ctx.iRangeEnd = -1;
rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn);
-
- if( ctx.zIn ){
+ if( rc==SQLITE_RANGE ){
+ sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC);
+ rc = SQLITE_OK;
+ }else if( ctx.zIn ){
if( rc==SQLITE_OK ){
rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter);
}
@@ -225100,6 +232996,9 @@ static void fts5HighlightFunction(
if( rc==SQLITE_OK ){
rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
}
+ if( ctx.bOpen ){
+ fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
+ }
fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
if( rc==SQLITE_OK ){
@@ -225275,6 +233174,7 @@ static void fts5SnippetFunction(
iCol = sqlite3_value_int(apVal[0]);
ctx.zOpen = fts5ValueToText(apVal[1]);
ctx.zClose = fts5ValueToText(apVal[2]);
+ ctx.iRangeEnd = -1;
zEllips = fts5ValueToText(apVal[3]);
nToken = sqlite3_value_int(apVal[4]);
@@ -225377,6 +233277,9 @@ static void fts5SnippetFunction(
if( rc==SQLITE_OK ){
rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb);
}
+ if( ctx.bOpen ){
+ fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1);
+ }
if( ctx.iRangeEnd>=(nColSize-1) ){
fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff);
}else{
@@ -225652,6 +233555,7 @@ static void sqlite3Fts5BufferAppendBlob(
){
if( nData ){
if( fts5BufferGrow(pRc, pBuf, nData) ) return;
+ assert( pBuf->p!=0 );
memcpy(&pBuf->p[pBuf->n], pData, nData);
pBuf->n += nData;
}
@@ -225753,6 +233657,7 @@ static int sqlite3Fts5PoslistNext64(
i64 *piOff /* IN/OUT: Current offset */
){
int i = *pi;
+ assert( a!=0 || i==0 );
if( i>=n ){
/* EOF */
*piOff = -1;
@@ -225760,6 +233665,7 @@ static int sqlite3Fts5PoslistNext64(
}else{
i64 iOff = *piOff;
u32 iVal;
+ assert( a!=0 );
fts5FastGetVarint32(a, i, iVal);
if( iVal<=1 ){
if( iVal==0 ){
@@ -226015,6 +233921,8 @@ static void sqlite3Fts5TermsetFree(Fts5Termset *p){
#define FTS5_DEFAULT_CRISISMERGE 16
#define FTS5_DEFAULT_HASHSIZE (1024*1024)
+#define FTS5_DEFAULT_DELETE_AUTOMERGE 10 /* default 10% */
+
/* Maximum allowed page size */
#define FTS5_MAX_PAGE_SIZE (64*1024)
@@ -226345,6 +234253,16 @@ static int fts5ConfigParseSpecial(
return rc;
}
+ if( sqlite3_strnicmp("contentless_delete", zCmd, nCmd)==0 ){
+ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
+ *pzErr = sqlite3_mprintf("malformed contentless_delete=... directive");
+ rc = SQLITE_ERROR;
+ }else{
+ pConfig->bContentlessDelete = (zArg[0]=='1');
+ }
+ return rc;
+ }
+
if( sqlite3_strnicmp("content_rowid", zCmd, nCmd)==0 ){
if( pConfig->zContentRowid ){
*pzErr = sqlite3_mprintf("multiple content_rowid=... directives");
@@ -226379,6 +234297,16 @@ static int fts5ConfigParseSpecial(
return rc;
}
+ if( sqlite3_strnicmp("tokendata", zCmd, nCmd)==0 ){
+ if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){
+ *pzErr = sqlite3_mprintf("malformed tokendata=... directive");
+ rc = SQLITE_ERROR;
+ }else{
+ pConfig->bTokendata = (zArg[0]=='1');
+ }
+ return rc;
+ }
+
*pzErr = sqlite3_mprintf("unrecognized option: \"%.*s\"", nCmd, zCmd);
return SQLITE_ERROR;
}
@@ -226543,6 +234471,7 @@ static int sqlite3Fts5ConfigParse(
rc = SQLITE_ERROR;
}
+ assert( (pRet->abUnindexed && pRet->azCol) || rc!=SQLITE_OK );
for(i=3; rc==SQLITE_OK && i<nArg; i++){
const char *zOrig = azArg[i];
const char *z;
@@ -226588,6 +234517,28 @@ static int sqlite3Fts5ConfigParse(
sqlite3_free(zTwo);
}
+ /* We only allow contentless_delete=1 if the table is indeed contentless. */
+ if( rc==SQLITE_OK
+ && pRet->bContentlessDelete
+ && pRet->eContent!=FTS5_CONTENT_NONE
+ ){
+ *pzErr = sqlite3_mprintf(
+ "contentless_delete=1 requires a contentless table"
+ );
+ rc = SQLITE_ERROR;
+ }
+
+ /* We only allow contentless_delete=1 if columnsize=0 is not present.
+ **
+ ** This restriction may be removed at some point.
+ */
+ if( rc==SQLITE_OK && pRet->bContentlessDelete && pRet->bColumnsize==0 ){
+ *pzErr = sqlite3_mprintf(
+ "contentless_delete=1 is incompatible with columnsize=0"
+ );
+ rc = SQLITE_ERROR;
+ }
+
/* If a tokenizer= option was successfully parsed, the tokenizer has
** already been allocated. Otherwise, allocate an instance of the default
** tokenizer (unicode61) now. */
@@ -226882,6 +234833,18 @@ static int sqlite3Fts5ConfigSetValue(
}
}
+ else if( 0==sqlite3_stricmp(zKey, "deletemerge") ){
+ int nVal = -1;
+ if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
+ nVal = sqlite3_value_int(pVal);
+ }else{
+ *pbBadkey = 1;
+ }
+ if( nVal<0 ) nVal = FTS5_DEFAULT_DELETE_AUTOMERGE;
+ if( nVal>100 ) nVal = 0;
+ pConfig->nDeleteMerge = nVal;
+ }
+
else if( 0==sqlite3_stricmp(zKey, "rank") ){
const char *zIn = (const char*)sqlite3_value_text(pVal);
char *zRank;
@@ -226896,6 +234859,18 @@ static int sqlite3Fts5ConfigSetValue(
rc = SQLITE_OK;
*pbBadkey = 1;
}
+ }
+
+ else if( 0==sqlite3_stricmp(zKey, "secure-delete") ){
+ int bVal = -1;
+ if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
+ bVal = sqlite3_value_int(pVal);
+ }
+ if( bVal<0 ){
+ *pbBadkey = 1;
+ }else{
+ pConfig->bSecureDelete = (bVal ? 1 : 0);
+ }
}else{
*pbBadkey = 1;
}
@@ -226918,6 +234893,7 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
pConfig->nUsermerge = FTS5_DEFAULT_USERMERGE;
pConfig->nCrisisMerge = FTS5_DEFAULT_CRISISMERGE;
pConfig->nHashSize = FTS5_DEFAULT_HASHSIZE;
+ pConfig->nDeleteMerge = FTS5_DEFAULT_DELETE_AUTOMERGE;
zSql = sqlite3Fts5Mprintf(&rc, zSelect, pConfig->zDb, pConfig->zName);
if( zSql ){
@@ -226940,15 +234916,20 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
rc = sqlite3_finalize(p);
}
- if( rc==SQLITE_OK && iVersion!=FTS5_CURRENT_VERSION ){
+ if( rc==SQLITE_OK
+ && iVersion!=FTS5_CURRENT_VERSION
+ && iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE
+ ){
rc = SQLITE_ERROR;
if( pConfig->pzErrmsg ){
assert( 0==*pConfig->pzErrmsg );
- *pConfig->pzErrmsg = sqlite3_mprintf(
- "invalid fts5 file format (found %d, expected %d) - run 'rebuild'",
- iVersion, FTS5_CURRENT_VERSION
+ *pConfig->pzErrmsg = sqlite3_mprintf("invalid fts5 file format "
+ "(found %d, expected %d or %d) - run 'rebuild'",
+ iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE
);
}
+ }else{
+ pConfig->iVersion = iVersion;
}
if( rc==SQLITE_OK ){
@@ -226976,6 +234957,10 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
/* #include "fts5Int.h" */
/* #include "fts5parse.h" */
+#ifndef SQLITE_FTS5_MAX_EXPR_DEPTH
+# define SQLITE_FTS5_MAX_EXPR_DEPTH 256
+#endif
+
/*
** All token types in the generated fts5parse.h file are greater than 0.
*/
@@ -227016,11 +235001,17 @@ struct Fts5Expr {
** FTS5_NOT (nChild, apChild valid)
** FTS5_STRING (pNear valid)
** FTS5_TERM (pNear valid)
+**
+** iHeight:
+** Distance from this node to furthest leaf. This is always 0 for nodes
+** of type FTS5_STRING and FTS5_TERM. For all other nodes it is one
+** greater than the largest child value.
*/
struct Fts5ExprNode {
int eType; /* Node type */
int bEof; /* True at EOF */
int bNomatch; /* True if entry is not a match */
+ int iHeight; /* Distance to tree leaf nodes */
/* Next method for this node. */
int (*xNext)(Fts5Expr*, Fts5ExprNode*, int, i64);
@@ -227049,7 +235040,9 @@ struct Fts5ExprNode {
struct Fts5ExprTerm {
u8 bPrefix; /* True for a prefix term */
u8 bFirst; /* True if token must be first in column */
- char *zTerm; /* nul-terminated term */
+ char *pTerm; /* Term data */
+ int nQueryTerm; /* Effective size of term in bytes */
+ int nFullTerm; /* Size of term in bytes incl. tokendata */
Fts5IndexIter *pIter; /* Iterator for this term */
Fts5ExprTerm *pSynonym; /* Pointer to first in list of synonyms */
};
@@ -227090,6 +235083,31 @@ struct Fts5Parse {
int bPhraseToAnd; /* Convert "a+b" to "a AND b" */
};
+/*
+** Check that the Fts5ExprNode.iHeight variables are set correctly in
+** the expression tree passed as the only argument.
+*/
+#ifndef NDEBUG
+static void assert_expr_depth_ok(int rc, Fts5ExprNode *p){
+ if( rc==SQLITE_OK ){
+ if( p->eType==FTS5_TERM || p->eType==FTS5_STRING || p->eType==0 ){
+ assert( p->iHeight==0 );
+ }else{
+ int ii;
+ int iMaxChild = 0;
+ for(ii=0; ii<p->nChild; ii++){
+ Fts5ExprNode *pChild = p->apChild[ii];
+ iMaxChild = MAX(iMaxChild, pChild->iHeight);
+ assert_expr_depth_ok(SQLITE_OK, pChild);
+ }
+ assert( p->iHeight==iMaxChild+1 );
+ }
+ }
+}
+#else
+# define assert_expr_depth_ok(rc, p)
+#endif
+
static void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...){
va_list ap;
va_start(ap, zFmt);
@@ -227204,6 +235222,8 @@ static int sqlite3Fts5ExprNew(
}while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
+ assert_expr_depth_ok(sParse.rc, sParse.pExpr);
+
/* If the LHS of the MATCH expression was a user column, apply the
** implicit column-filter. */
if( iCol<pConfig->nCol && sParse.pExpr && sParse.rc==SQLITE_OK ){
@@ -227366,7 +235386,7 @@ static int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){
Fts5Parse sParse;
memset(&sParse, 0, sizeof(sParse));
- if( *pp1 ){
+ if( *pp1 && p2 ){
Fts5Expr *p1 = *pp1;
int nPhrase = p1->nPhrase + p2->nPhrase;
@@ -227391,7 +235411,7 @@ static int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){
}
sqlite3_free(p2->apExprPhrase);
sqlite3_free(p2);
- }else{
+ }else if( p2 ){
*pp1 = p2;
}
@@ -227889,7 +235909,7 @@ static int fts5ExprNearInitAll(
p->pIter = 0;
}
rc = sqlite3Fts5IndexQuery(
- pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm),
+ pExpr->pIndex, p->pTerm, p->nQueryTerm,
(pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
(pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0),
pNear->pColset,
@@ -228526,7 +236546,7 @@ static void fts5ExprPhraseFree(Fts5ExprPhrase *pPhrase){
Fts5ExprTerm *pSyn;
Fts5ExprTerm *pNext;
Fts5ExprTerm *pTerm = &pPhrase->aTerm[i];
- sqlite3_free(pTerm->zTerm);
+ sqlite3_free(pTerm->pTerm);
sqlite3Fts5IterClose(pTerm->pIter);
for(pSyn=pTerm->pSynonym; pSyn; pSyn=pNext){
pNext = pSyn->pSynonym;
@@ -228624,6 +236644,7 @@ static Fts5ExprNearset *sqlite3Fts5ParseNearset(
typedef struct TokenCtx TokenCtx;
struct TokenCtx {
Fts5ExprPhrase *pPhrase;
+ Fts5Config *pConfig;
int rc;
};
@@ -228657,8 +236678,12 @@ static int fts5ParseTokenize(
rc = SQLITE_NOMEM;
}else{
memset(pSyn, 0, (size_t)nByte);
- pSyn->zTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer);
- memcpy(pSyn->zTerm, pToken, nToken);
+ pSyn->pTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer);
+ pSyn->nFullTerm = pSyn->nQueryTerm = nToken;
+ if( pCtx->pConfig->bTokendata ){
+ pSyn->nQueryTerm = (int)strlen(pSyn->pTerm);
+ }
+ memcpy(pSyn->pTerm, pToken, nToken);
pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym;
pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn;
}
@@ -228683,7 +236708,11 @@ static int fts5ParseTokenize(
if( rc==SQLITE_OK ){
pTerm = &pPhrase->aTerm[pPhrase->nTerm++];
memset(pTerm, 0, sizeof(Fts5ExprTerm));
- pTerm->zTerm = sqlite3Fts5Strndup(&rc, pToken, nToken);
+ pTerm->pTerm = sqlite3Fts5Strndup(&rc, pToken, nToken);
+ pTerm->nFullTerm = pTerm->nQueryTerm = nToken;
+ if( pCtx->pConfig->bTokendata && rc==SQLITE_OK ){
+ pTerm->nQueryTerm = (int)strlen(pTerm->pTerm);
+ }
}
}
@@ -228750,6 +236779,7 @@ static Fts5ExprPhrase *sqlite3Fts5ParseTerm(
memset(&sCtx, 0, sizeof(TokenCtx));
sCtx.pPhrase = pAppend;
+ sCtx.pConfig = pConfig;
rc = fts5ParseStringFromToken(pToken, &z);
if( rc==SQLITE_OK ){
@@ -228797,12 +236827,15 @@ static int sqlite3Fts5ExprClonePhrase(
Fts5Expr **ppNew
){
int rc = SQLITE_OK; /* Return code */
- Fts5ExprPhrase *pOrig; /* The phrase extracted from pExpr */
+ Fts5ExprPhrase *pOrig = 0; /* The phrase extracted from pExpr */
Fts5Expr *pNew = 0; /* Expression to return via *ppNew */
- TokenCtx sCtx = {0,0}; /* Context object for fts5ParseTokenize */
-
- pOrig = pExpr->apExprPhrase[iPhrase];
- pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
+ TokenCtx sCtx = {0,0,0}; /* Context object for fts5ParseTokenize */
+ if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){
+ rc = SQLITE_RANGE;
+ }else{
+ pOrig = pExpr->apExprPhrase[iPhrase];
+ pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
+ }
if( rc==SQLITE_OK ){
pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc,
sizeof(Fts5ExprPhrase*));
@@ -228815,7 +236848,7 @@ static int sqlite3Fts5ExprClonePhrase(
pNew->pRoot->pNear = (Fts5ExprNearset*)sqlite3Fts5MallocZero(&rc,
sizeof(Fts5ExprNearset) + sizeof(Fts5ExprPhrase*));
}
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK && ALWAYS(pOrig!=0) ){
Fts5Colset *pColsetOrig = pOrig->pNode->pNear->pColset;
if( pColsetOrig ){
sqlite3_int64 nByte;
@@ -228829,26 +236862,27 @@ static int sqlite3Fts5ExprClonePhrase(
}
}
- 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;
- sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
+ if( rc==SQLITE_OK ){
+ if( pOrig->nTerm ){
+ int i; /* Used to iterate through phrase terms */
+ sCtx.pConfig = pExpr->pConfig;
+ 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){
+ rc = fts5ParseTokenize((void*)&sCtx,tflags,p->pTerm,p->nFullTerm,0,0);
+ tflags = FTS5_TOKEN_COLOCATED;
+ }
+ if( rc==SQLITE_OK ){
+ sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
+ sCtx.pPhrase->aTerm[i].bFirst = pOrig->aTerm[i].bFirst;
+ }
}
+ }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));
}
- }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 && ALWAYS(sCtx.pPhrase) ){
@@ -229165,6 +237199,7 @@ static void fts5ExprAssignXNext(Fts5ExprNode *pNode){
}
static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){
+ int ii = p->nChild;
if( p->eType!=FTS5_NOT && pSub->eType==p->eType ){
int nByte = sizeof(Fts5ExprNode*) * pSub->nChild;
memcpy(&p->apChild[p->nChild], pSub->apChild, nByte);
@@ -229173,6 +237208,9 @@ static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){
}else{
p->apChild[p->nChild++] = pSub;
}
+ for( ; ii<p->nChild; ii++){
+ p->iHeight = MAX(p->iHeight, p->apChild[ii]->iHeight + 1);
+ }
}
/*
@@ -229203,6 +237241,7 @@ static Fts5ExprNode *fts5ParsePhraseToAnd(
if( pRet ){
pRet->eType = FTS5_AND;
pRet->nChild = nTerm;
+ pRet->iHeight = 1;
fts5ExprAssignXNext(pRet);
pParse->nPhrase--;
for(ii=0; ii<nTerm; ii++){
@@ -229213,11 +237252,13 @@ static Fts5ExprNode *fts5ParsePhraseToAnd(
if( parseGrowPhraseArray(pParse) ){
fts5ExprPhraseFree(pPhrase);
}else{
+ Fts5ExprTerm *p = &pNear->apPhrase[0]->aTerm[ii];
+ Fts5ExprTerm *pTo = &pPhrase->aTerm[0];
pParse->apPhrase[pParse->nPhrase++] = pPhrase;
pPhrase->nTerm = 1;
- pPhrase->aTerm[0].zTerm = sqlite3Fts5Strndup(
- &pParse->rc, pNear->apPhrase[0]->aTerm[ii].zTerm, -1
- );
+ pTo->pTerm = sqlite3Fts5Strndup(&pParse->rc, p->pTerm, p->nFullTerm);
+ pTo->nQueryTerm = p->nQueryTerm;
+ pTo->nFullTerm = p->nFullTerm;
pRet->apChild[ii] = sqlite3Fts5ParseNode(pParse, FTS5_STRING,
0, 0, sqlite3Fts5ParseNearset(pParse, 0, pPhrase)
);
@@ -229308,6 +237349,14 @@ static Fts5ExprNode *sqlite3Fts5ParseNode(
}else{
fts5ExprAddChildren(pRet, pLeft);
fts5ExprAddChildren(pRet, pRight);
+ if( pRet->iHeight>SQLITE_FTS5_MAX_EXPR_DEPTH ){
+ sqlite3Fts5ParseError(pParse,
+ "fts5 expression tree is too large (maximum depth %d)",
+ SQLITE_FTS5_MAX_EXPR_DEPTH
+ );
+ sqlite3_free(pRet);
+ pRet = 0;
+ }
}
}
}
@@ -229386,7 +237435,7 @@ static Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
return pRet;
}
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
sqlite3_int64 nByte = 0;
Fts5ExprTerm *p;
@@ -229394,16 +237443,17 @@ static char *fts5ExprTermPrint(Fts5ExprTerm *pTerm){
/* Determine the maximum amount of space required. */
for(p=pTerm; p; p=p->pSynonym){
- nByte += (int)strlen(pTerm->zTerm) * 2 + 3 + 2;
+ nByte += pTerm->nQueryTerm * 2 + 3 + 2;
}
zQuoted = sqlite3_malloc64(nByte);
if( zQuoted ){
int i = 0;
for(p=pTerm; p; p=p->pSynonym){
- char *zIn = p->zTerm;
+ char *zIn = p->pTerm;
+ char *zEnd = &zIn[p->nQueryTerm];
zQuoted[i++] = '"';
- while( *zIn ){
+ while( zIn<zEnd ){
if( *zIn=='"' ) zQuoted[i++] = '"';
zQuoted[i++] = *zIn++;
}
@@ -229481,8 +237531,10 @@ static char *fts5ExprPrintTcl(
zRet = fts5PrintfAppend(zRet, " {");
for(iTerm=0; zRet && iTerm<pPhrase->nTerm; iTerm++){
- char *zTerm = pPhrase->aTerm[iTerm].zTerm;
- zRet = fts5PrintfAppend(zRet, "%s%s", iTerm==0?"":" ", zTerm);
+ Fts5ExprTerm *p = &pPhrase->aTerm[iTerm];
+ zRet = fts5PrintfAppend(zRet, "%s%.*s", iTerm==0?"":" ",
+ p->nQueryTerm, p->pTerm
+ );
if( pPhrase->aTerm[iTerm].bPrefix ){
zRet = fts5PrintfAppend(zRet, "*");
}
@@ -229492,6 +237544,8 @@ static char *fts5ExprPrintTcl(
if( zRet==0 ) return 0;
}
+ }else if( pExpr->eType==0 ){
+ zRet = sqlite3_mprintf("{}");
}else{
char const *zOp = 0;
int i;
@@ -229753,14 +237807,14 @@ static void fts5ExprFold(
sqlite3_result_int(pCtx, sqlite3Fts5UnicodeFold(iCode, bRemoveDiacritics));
}
}
-#endif /* ifdef SQLITE_TEST */
+#endif /* if SQLITE_TEST || SQLITE_FTS5_DEBUG */
/*
** This is called during initialization to register the fts5_expr() scalar
** UDF with the SQLite handle passed as the only argument.
*/
static int sqlite3Fts5ExprInit(Fts5Global *pGlobal, sqlite3 *db){
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
struct Fts5ExprFunc {
const char *z;
void (*x)(sqlite3_context*,int,sqlite3_value**);
@@ -229881,6 +237935,17 @@ static int fts5ExprColsetTest(Fts5Colset *pColset, int iCol){
return 0;
}
+/*
+** pToken is a buffer nToken bytes in size that may or may not contain
+** an embedded 0x00 byte. If it does, return the number of bytes in
+** the buffer before the 0x00. If it does not, return nToken.
+*/
+static int fts5QueryTerm(const char *pToken, int nToken){
+ int ii;
+ for(ii=0; ii<nToken && pToken[ii]; ii++){}
+ return ii;
+}
+
static int fts5ExprPopulatePoslistsCb(
void *pCtx, /* Copy of 2nd argument to xTokenize() */
int tflags, /* Mask of FTS5_TOKEN_* flags */
@@ -229892,22 +237957,33 @@ static int fts5ExprPopulatePoslistsCb(
Fts5ExprCtx *p = (Fts5ExprCtx*)pCtx;
Fts5Expr *pExpr = p->pExpr;
int i;
+ int nQuery = nToken;
+ i64 iRowid = pExpr->pRoot->iRowid;
UNUSED_PARAM2(iUnused1, iUnused2);
- if( nToken>FTS5_MAX_TOKEN_SIZE ) nToken = FTS5_MAX_TOKEN_SIZE;
+ if( nQuery>FTS5_MAX_TOKEN_SIZE ) nQuery = FTS5_MAX_TOKEN_SIZE;
+ if( pExpr->pConfig->bTokendata ){
+ nQuery = fts5QueryTerm(pToken, nQuery);
+ }
if( (tflags & FTS5_TOKEN_COLOCATED)==0 ) p->iOff++;
for(i=0; i<pExpr->nPhrase; i++){
- Fts5ExprTerm *pTerm;
+ Fts5ExprTerm *pT;
if( p->aPopulator[i].bOk==0 ) continue;
- for(pTerm=&pExpr->apExprPhrase[i]->aTerm[0]; pTerm; pTerm=pTerm->pSynonym){
- int nTerm = (int)strlen(pTerm->zTerm);
- if( (nTerm==nToken || (nTerm<nToken && pTerm->bPrefix))
- && memcmp(pTerm->zTerm, pToken, nTerm)==0
+ for(pT=&pExpr->apExprPhrase[i]->aTerm[0]; pT; pT=pT->pSynonym){
+ if( (pT->nQueryTerm==nQuery || (pT->nQueryTerm<nQuery && pT->bPrefix))
+ && memcmp(pT->pTerm, pToken, pT->nQueryTerm)==0
){
int rc = sqlite3Fts5PoslistWriterAppend(
&pExpr->apExprPhrase[i]->poslist, &p->aPopulator[i].writer, p->iOff
);
+ if( rc==SQLITE_OK && pExpr->pConfig->bTokendata && !pT->bPrefix ){
+ int iCol = p->iOff>>32;
+ int iTokOff = p->iOff & 0x7FFFFFFF;
+ rc = sqlite3Fts5IndexIterWriteTokendata(
+ pT->pIter, pToken, nToken, iRowid, iCol, iTokOff
+ );
+ }
if( rc ) return rc;
break;
}
@@ -230044,6 +238120,83 @@ static int sqlite3Fts5ExprPhraseCollist(
}
/*
+** Does the work of the fts5_api.xQueryToken() API method.
+*/
+static int sqlite3Fts5ExprQueryToken(
+ Fts5Expr *pExpr,
+ int iPhrase,
+ int iToken,
+ const char **ppOut,
+ int *pnOut
+){
+ Fts5ExprPhrase *pPhrase = 0;
+
+ if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){
+ return SQLITE_RANGE;
+ }
+ pPhrase = pExpr->apExprPhrase[iPhrase];
+ if( iToken<0 || iToken>=pPhrase->nTerm ){
+ return SQLITE_RANGE;
+ }
+
+ *ppOut = pPhrase->aTerm[iToken].pTerm;
+ *pnOut = pPhrase->aTerm[iToken].nFullTerm;
+ return SQLITE_OK;
+}
+
+/*
+** Does the work of the fts5_api.xInstToken() API method.
+*/
+static int sqlite3Fts5ExprInstToken(
+ Fts5Expr *pExpr,
+ i64 iRowid,
+ int iPhrase,
+ int iCol,
+ int iOff,
+ int iToken,
+ const char **ppOut,
+ int *pnOut
+){
+ Fts5ExprPhrase *pPhrase = 0;
+ Fts5ExprTerm *pTerm = 0;
+ int rc = SQLITE_OK;
+
+ if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){
+ return SQLITE_RANGE;
+ }
+ pPhrase = pExpr->apExprPhrase[iPhrase];
+ if( iToken<0 || iToken>=pPhrase->nTerm ){
+ return SQLITE_RANGE;
+ }
+ pTerm = &pPhrase->aTerm[iToken];
+ if( pTerm->bPrefix==0 ){
+ if( pExpr->pConfig->bTokendata ){
+ rc = sqlite3Fts5IterToken(
+ pTerm->pIter, iRowid, iCol, iOff+iToken, ppOut, pnOut
+ );
+ }else{
+ *ppOut = pTerm->pTerm;
+ *pnOut = pTerm->nFullTerm;
+ }
+ }
+ return rc;
+}
+
+/*
+** Clear the token mappings for all Fts5IndexIter objects mannaged by
+** the expression passed as the only argument.
+*/
+static void sqlite3Fts5ExprClearTokens(Fts5Expr *pExpr){
+ int ii;
+ for(ii=0; ii<pExpr->nPhrase; ii++){
+ Fts5ExprTerm *pT;
+ for(pT=&pExpr->apExprPhrase[ii]->aTerm[0]; pT; pT=pT->pSynonym){
+ sqlite3Fts5IndexIterClearTokendata(pT->pIter);
+ }
+ }
+}
+
+/*
** 2014 August 11
**
** The author disclaims copyright to this source code. In place of
@@ -230081,10 +238234,15 @@ struct Fts5Hash {
/*
** Each entry in the hash table is represented by an object of the
-** following type. Each object, its key (a nul-terminated string) and
-** its current data are stored in a single memory allocation. The
-** key immediately follows the object in memory. The position list
-** data immediately follows the key data in memory.
+** following type. Each object, its key, and its current data are stored
+** in a single memory allocation. The key immediately follows the object
+** in memory. The position list data immediately follows the key data
+** in memory.
+**
+** The key is Fts5HashEntry.nKey bytes in size. It consists of a single
+** byte identifying the index (either the main term index or a prefix-index),
+** followed by the term data. For example: "0token". There is no
+** nul-terminator - in this case nKey=6.
**
** The data that follows the key is in a similar, but not identical format
** to the doclist data stored in the database. It is:
@@ -230219,8 +238377,7 @@ static int fts5HashResize(Fts5Hash *pHash){
unsigned int iHash;
Fts5HashEntry *p = apOld[i];
apOld[i] = p->pHashNext;
- iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p),
- (int)strlen(fts5EntryKey(p)));
+ iHash = fts5HashKey(nNew, (u8*)fts5EntryKey(p), p->nKey);
p->pHashNext = apNew[iHash];
apNew[iHash] = p;
}
@@ -230304,7 +238461,7 @@ static int sqlite3Fts5HashWrite(
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
char *zKey = fts5EntryKey(p);
if( zKey[0]==bByte
- && p->nKey==nToken
+ && p->nKey==nToken+1
&& memcmp(&zKey[1], pToken, nToken)==0
){
break;
@@ -230334,9 +238491,9 @@ static int sqlite3Fts5HashWrite(
zKey[0] = bByte;
memcpy(&zKey[1], pToken, nToken);
assert( iHash==fts5HashKey(pHash->nSlot, (u8*)zKey, nToken+1) );
- p->nKey = nToken;
+ p->nKey = nToken+1;
zKey[nToken+1] = '\0';
- p->nData = nToken+1 + 1 + sizeof(Fts5HashEntry);
+ p->nData = nToken+1 + sizeof(Fts5HashEntry);
p->pHashNext = pHash->aSlot[iHash];
pHash->aSlot[iHash] = p;
pHash->nEntry++;
@@ -230453,12 +238610,17 @@ static Fts5HashEntry *fts5HashEntryMerge(
*ppOut = p1;
p1 = 0;
}else{
- int i = 0;
char *zKey1 = fts5EntryKey(p1);
char *zKey2 = fts5EntryKey(p2);
- while( zKey1[i]==zKey2[i] ) i++;
+ int nMin = MIN(p1->nKey, p2->nKey);
+
+ int cmp = memcmp(zKey1, zKey2, nMin);
+ if( cmp==0 ){
+ cmp = p1->nKey - p2->nKey;
+ }
+ assert( cmp!=0 );
- if( ((u8)zKey1[i])>((u8)zKey2[i]) ){
+ if( cmp>0 ){
/* p2 is smaller */
*ppOut = p2;
ppOut = &p2->pScanNext;
@@ -230477,10 +238639,8 @@ static Fts5HashEntry *fts5HashEntryMerge(
}
/*
-** Extract all tokens from hash table iHash and link them into a list
-** in sorted order. The hash table is cleared before returning. It is
-** the responsibility of the caller to free the elements of the returned
-** list.
+** Link all tokens from hash table iHash into a list in sorted order. The
+** tokens are not removed from the hash table.
*/
static int fts5HashEntrySort(
Fts5Hash *pHash,
@@ -230502,7 +238662,7 @@ static int fts5HashEntrySort(
Fts5HashEntry *pIter;
for(pIter=pHash->aSlot[iSlot]; pIter; pIter=pIter->pHashNext){
if( pTerm==0
- || (pIter->nKey+1>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm))
+ || (pIter->nKey>=nTerm && 0==memcmp(fts5EntryKey(pIter), pTerm, nTerm))
){
Fts5HashEntry *pEntry = pIter;
pEntry->pScanNext = 0;
@@ -230520,7 +238680,6 @@ static int fts5HashEntrySort(
pList = fts5HashEntryMerge(pList, ap[i]);
}
- pHash->nEntry = 0;
sqlite3_free(ap);
*ppSorted = pList;
return SQLITE_OK;
@@ -230542,12 +238701,11 @@ static int sqlite3Fts5HashQuery(
for(p=pHash->aSlot[iHash]; p; p=p->pHashNext){
zKey = fts5EntryKey(p);
- assert( p->nKey+1==(int)strlen(zKey) );
- if( nTerm==p->nKey+1 && memcmp(zKey, pTerm, nTerm)==0 ) break;
+ if( nTerm==p->nKey && memcmp(zKey, pTerm, nTerm)==0 ) break;
}
if( p ){
- int nHashPre = sizeof(Fts5HashEntry) + nTerm + 1;
+ int nHashPre = sizeof(Fts5HashEntry) + nTerm;
int nList = p->nData - nHashPre;
u8 *pRet = (u8*)(*ppOut = sqlite3_malloc64(nPre + nList + 10));
if( pRet ){
@@ -230574,6 +238732,28 @@ static int sqlite3Fts5HashScanInit(
return fts5HashEntrySort(p, pTerm, nTerm, &p->pScan);
}
+#ifdef SQLITE_DEBUG
+static int fts5HashCount(Fts5Hash *pHash){
+ int nEntry = 0;
+ int ii;
+ for(ii=0; ii<pHash->nSlot; ii++){
+ Fts5HashEntry *p = 0;
+ for(p=pHash->aSlot[ii]; p; p=p->pHashNext){
+ nEntry++;
+ }
+ }
+ return nEntry;
+}
+#endif
+
+/*
+** Return true if the hash table is empty, false otherwise.
+*/
+static int sqlite3Fts5HashIsEmpty(Fts5Hash *pHash){
+ assert( pHash->nEntry==fts5HashCount(pHash) );
+ return pHash->nEntry==0;
+}
+
static void sqlite3Fts5HashScanNext(Fts5Hash *p){
assert( !sqlite3Fts5HashScanEof(p) );
p->pScan = p->pScan->pScanNext;
@@ -230586,19 +238766,22 @@ static int sqlite3Fts5HashScanEof(Fts5Hash *p){
static void sqlite3Fts5HashScanEntry(
Fts5Hash *pHash,
const char **pzTerm, /* OUT: term (nul-terminated) */
+ int *pnTerm, /* OUT: Size of term in bytes */
const u8 **ppDoclist, /* OUT: pointer to doclist */
int *pnDoclist /* OUT: size of doclist in bytes */
){
Fts5HashEntry *p;
if( (p = pHash->pScan) ){
char *zKey = fts5EntryKey(p);
- int nTerm = (int)strlen(zKey);
+ int nTerm = p->nKey;
fts5HashAddPoslistSize(pHash, p, 0);
*pzTerm = zKey;
- *ppDoclist = (const u8*)&zKey[nTerm+1];
- *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm + 1);
+ *pnTerm = nTerm;
+ *ppDoclist = (const u8*)&zKey[nTerm];
+ *pnDoclist = p->nData - (sizeof(Fts5HashEntry) + nTerm);
}else{
*pzTerm = 0;
+ *pnTerm = 0;
*ppDoclist = 0;
*pnDoclist = 0;
}
@@ -230663,13 +238846,31 @@ static void sqlite3Fts5HashScanEntry(
#define FTS5_MAX_LEVEL 64
/*
+** There are two versions of the format used for the structure record:
+**
+** 1. the legacy format, that may be read by all fts5 versions, and
+**
+** 2. the V2 format, which is used by contentless_delete=1 databases.
+**
+** Both begin with a 4-byte "configuration cookie" value. Then, a legacy
+** format structure record contains a varint - the number of levels in
+** the structure. Whereas a V2 structure record contains the constant
+** 4 bytes [0xff 0x00 0x00 0x01]. This is unambiguous as the value of a
+** varint has to be at least 16256 to begin with "0xFF". And the default
+** maximum number of levels is 64.
+**
+** See below for more on structure record formats.
+*/
+#define FTS5_STRUCTURE_V2 "\xFF\x00\x00\x01"
+
+/*
** Details:
**
** The %_data table managed by this module,
**
** CREATE TABLE %_data(id INTEGER PRIMARY KEY, block BLOB);
**
-** , contains the following 5 types of records. See the comments surrounding
+** , contains the following 6 types of records. See the comments surrounding
** the FTS5_*_ROWID macros below for a description of how %_data rowids are
** assigned to each fo them.
**
@@ -230678,12 +238879,12 @@ static void sqlite3Fts5HashScanEntry(
** The set of segments that make up an index - the index structure - are
** recorded in a single record within the %_data table. The record consists
** of a single 32-bit configuration cookie value followed by a list of
-** SQLite varints. If the FTS table features more than one index (because
-** there are one or more prefix indexes), it is guaranteed that all share
-** the same cookie value.
+** SQLite varints.
+**
+** If the structure record is a V2 record, the configuration cookie is
+** followed by the following 4 bytes: [0xFF 0x00 0x00 0x01].
**
-** Immediately following the configuration cookie, the record begins with
-** three varints:
+** Next, the record continues with three varints:
**
** + number of levels,
** + total number of segments on all levels,
@@ -230698,6 +238899,12 @@ static void sqlite3Fts5HashScanEntry(
** + first leaf page number (often 1, always greater than 0)
** + final leaf page number
**
+** Then, for V2 structures only:
+**
+** + lower origin counter value,
+** + upper origin counter value,
+** + the number of tombstone hash pages.
+**
** 2. The Averages Record:
**
** A single record within the %_data table. The data is a list of varints.
@@ -230813,6 +239020,38 @@ static void sqlite3Fts5HashScanEntry(
** * A list of delta-encoded varints - the first rowid on each subsequent
** child page.
**
+** 6. Tombstone Hash Page
+**
+** These records are only ever present in contentless_delete=1 tables.
+** There are zero or more of these associated with each segment. They
+** are used to store the tombstone rowids for rows contained in the
+** associated segments.
+**
+** The set of nHashPg tombstone hash pages associated with a single
+** segment together form a single hash table containing tombstone rowids.
+** To find the page of the hash on which a key might be stored:
+**
+** iPg = (rowid % nHashPg)
+**
+** Then, within page iPg, which has nSlot slots:
+**
+** iSlot = (rowid / nHashPg) % nSlot
+**
+** Each tombstone hash page begins with an 8 byte header:
+**
+** 1-byte: Key-size (the size in bytes of each slot). Either 4 or 8.
+** 1-byte: rowid-0-tombstone flag. This flag is only valid on the
+** first tombstone hash page for each segment (iPg=0). If set,
+** the hash table contains rowid 0. If clear, it does not.
+** Rowid 0 is handled specially.
+** 2-bytes: unused.
+** 4-bytes: Big-endian integer containing number of entries on page.
+**
+** Following this are nSlot 4 or 8 byte slots (depending on the key-size
+** in the first byte of the page header). The number of slots may be
+** determined based on the size of the page record and the key-size:
+**
+** nSlot = (nByte - 8) / key-size
*/
/*
@@ -230846,6 +239085,7 @@ static void sqlite3Fts5HashScanEntry(
#define FTS5_SEGMENT_ROWID(segid, pgno) fts5_dri(segid, 0, 0, pgno)
#define FTS5_DLIDX_ROWID(segid, height, pgno) fts5_dri(segid, 1, height, pgno)
+#define FTS5_TOMBSTONE_ROWID(segid,ipg) fts5_dri(segid+(1<<16), 0, 0, ipg)
#ifdef SQLITE_DEBUG
static int sqlite3Fts5Corrupt() { return SQLITE_CORRUPT_VTAB; }
@@ -230872,6 +239112,9 @@ typedef struct Fts5SegWriter Fts5SegWriter;
typedef struct Fts5Structure Fts5Structure;
typedef struct Fts5StructureLevel Fts5StructureLevel;
typedef struct Fts5StructureSegment Fts5StructureSegment;
+typedef struct Fts5TokenDataIter Fts5TokenDataIter;
+typedef struct Fts5TokenDataMap Fts5TokenDataMap;
+typedef struct Fts5TombstoneArray Fts5TombstoneArray;
struct Fts5Data {
u8 *p; /* Pointer to buffer containing record */
@@ -230881,6 +239124,12 @@ struct Fts5Data {
/*
** One object per %_data table.
+**
+** nContentlessDelete:
+** The number of contentless delete operations since the most recent
+** call to fts5IndexFlush() or fts5IndexDiscardData(). This is tracked
+** so that extra auto-merge work can be done by fts5IndexFlush() to
+** account for the delete operations.
*/
struct Fts5Index {
Fts5Config *pConfig; /* Virtual table configuration */
@@ -230895,9 +239144,12 @@ struct Fts5Index {
int nPendingData; /* Current bytes of pending data */
i64 iWriteRowid; /* Rowid for current doc being written */
int bDelete; /* Current write is a delete */
+ int nContentlessDelete; /* Number of contentless delete ops */
+ int nPendingRow; /* Number of INSERT in hash table */
/* Error state. */
int rc; /* Current error code */
+ int flushRc;
/* State used by the fts5DataXXX() functions. */
sqlite3_blob *pReader; /* RO incr-blob open on %_data table */
@@ -230906,8 +239158,11 @@ struct Fts5Index {
sqlite3_stmt *pIdxWriter; /* "INSERT ... %_idx VALUES(?,?,?,?)" */
sqlite3_stmt *pIdxDeleter; /* "DELETE FROM %_idx WHERE segid=?" */
sqlite3_stmt *pIdxSelect;
+ sqlite3_stmt *pIdxNextSelect;
int nRead; /* Total number of blocks read */
+ sqlite3_stmt *pDeleteFromIdx;
+
sqlite3_stmt *pDataVersion;
i64 iStructVersion; /* data_version when pStruct read */
Fts5Structure *pStruct; /* Current db structure (or NULL) */
@@ -230927,11 +239182,23 @@ struct Fts5DoclistIter {
** The contents of the "structure" record for each index are represented
** using an Fts5Structure record in memory. Which uses instances of the
** other Fts5StructureXXX types as components.
+**
+** nOriginCntr:
+** This value is set to non-zero for structure records created for
+** contentlessdelete=1 tables only. In that case it represents the
+** origin value to apply to the next top-level segment created.
*/
struct Fts5StructureSegment {
int iSegid; /* Segment id */
int pgnoFirst; /* First leaf page number in segment */
int pgnoLast; /* Last leaf page number in segment */
+
+ /* contentlessdelete=1 tables only: */
+ u64 iOrigin1;
+ u64 iOrigin2;
+ int nPgTombstone; /* Number of tombstone hash table pages */
+ u64 nEntryTombstone; /* Number of tombstone entries that "count" */
+ u64 nEntry; /* Number of rows in this segment */
};
struct Fts5StructureLevel {
int nMerge; /* Number of segments in incr-merge */
@@ -230941,6 +239208,7 @@ struct Fts5StructureLevel {
struct Fts5Structure {
int nRef; /* Object reference count */
u64 nWriteCounter; /* Total leaves written to level 0 */
+ u64 nOriginCntr; /* Origin value for next top-level segment */
int nSegment; /* Total segments in this structure */
int nLevel; /* Number of levels in this index */
Fts5StructureLevel aLevel[1]; /* Array of nLevel level objects */
@@ -231000,9 +239268,6 @@ struct Fts5CResult {
** iLeafOffset:
** Byte offset within the current leaf that is the first byte of the
** position list data (one byte passed the position-list size field).
-** rowid field of the current entry. Usually this is the size field of the
-** position list data. The exception is if the rowid for the current entry
-** is the last thing on the leaf page.
**
** pLeaf:
** Buffer containing current leaf page data. Set to NULL at EOF.
@@ -231032,6 +239297,13 @@ struct Fts5CResult {
**
** iTermIdx:
** Index of current term on iTermLeafPgno.
+**
+** apTombstone/nTombstone:
+** These are used for contentless_delete=1 tables only. When the cursor
+** is first allocated, the apTombstone[] array is allocated so that it
+** is large enough for all tombstones hash pages associated with the
+** segment. The pages themselves are loaded lazily from the database as
+** they are required.
*/
struct Fts5SegIter {
Fts5StructureSegment *pSeg; /* Segment to iterate through */
@@ -231040,6 +239312,7 @@ struct Fts5SegIter {
Fts5Data *pLeaf; /* Current leaf data */
Fts5Data *pNextLeaf; /* Leaf page (iLeafPgno+1) */
i64 iLeafOffset; /* Byte offset within current leaf */
+ Fts5TombstoneArray *pTombArray; /* Array of tombstone pages */
/* Next method */
void (*xNext)(Fts5Index*, Fts5SegIter*, int*);
@@ -231067,6 +239340,15 @@ struct Fts5SegIter {
};
/*
+** Array of tombstone pages. Reference counted.
+*/
+struct Fts5TombstoneArray {
+ int nRef; /* Number of pointers to this object */
+ int nTombstone;
+ Fts5Data *apTombstone[1]; /* Array of tombstone pages */
+};
+
+/*
** Argument is a pointer to an Fts5Data structure that contains a
** leaf page.
*/
@@ -231110,9 +239392,16 @@ struct Fts5SegIter {
** poslist:
** Used by sqlite3Fts5IterPoslist() when the poslist needs to be buffered.
** There is no way to tell if this is populated or not.
+**
+** pColset:
+** If not NULL, points to an object containing a set of column indices.
+** Only matches that occur in one of these columns will be returned.
+** The Fts5Iter does not own the Fts5Colset object, and so it is not
+** freed when the iterator is closed - it is owned by the upper layer.
*/
struct Fts5Iter {
Fts5IndexIter base; /* Base class containing output vars */
+ Fts5TokenDataIter *pTokenDataIter;
Fts5Index *pIndex; /* Index that owns this iterator */
Fts5Buffer poslist; /* Buffer containing current poslist */
@@ -231130,7 +239419,6 @@ struct Fts5Iter {
Fts5SegIter aSeg[1]; /* Array of segment iterators */
};
-
/*
** An instance of the following type is used to iterate through the contents
** of a doclist-index record.
@@ -231170,6 +239458,60 @@ static u16 fts5GetU16(const u8 *aIn){
}
/*
+** The only argument points to a buffer at least 8 bytes in size. This
+** function interprets the first 8 bytes of the buffer as a 64-bit big-endian
+** unsigned integer and returns the result.
+*/
+static u64 fts5GetU64(u8 *a){
+ return ((u64)a[0] << 56)
+ + ((u64)a[1] << 48)
+ + ((u64)a[2] << 40)
+ + ((u64)a[3] << 32)
+ + ((u64)a[4] << 24)
+ + ((u64)a[5] << 16)
+ + ((u64)a[6] << 8)
+ + ((u64)a[7] << 0);
+}
+
+/*
+** The only argument points to a buffer at least 4 bytes in size. This
+** function interprets the first 4 bytes of the buffer as a 32-bit big-endian
+** unsigned integer and returns the result.
+*/
+static u32 fts5GetU32(const u8 *a){
+ return ((u32)a[0] << 24)
+ + ((u32)a[1] << 16)
+ + ((u32)a[2] << 8)
+ + ((u32)a[3] << 0);
+}
+
+/*
+** Write iVal, formated as a 64-bit big-endian unsigned integer, to the
+** buffer indicated by the first argument.
+*/
+static void fts5PutU64(u8 *a, u64 iVal){
+ a[0] = ((iVal >> 56) & 0xFF);
+ a[1] = ((iVal >> 48) & 0xFF);
+ a[2] = ((iVal >> 40) & 0xFF);
+ a[3] = ((iVal >> 32) & 0xFF);
+ a[4] = ((iVal >> 24) & 0xFF);
+ a[5] = ((iVal >> 16) & 0xFF);
+ a[6] = ((iVal >> 8) & 0xFF);
+ a[7] = ((iVal >> 0) & 0xFF);
+}
+
+/*
+** Write iVal, formated as a 32-bit big-endian unsigned integer, to the
+** buffer indicated by the first argument.
+*/
+static void fts5PutU32(u8 *a, u32 iVal){
+ a[0] = ((iVal >> 24) & 0xFF);
+ a[1] = ((iVal >> 16) & 0xFF);
+ a[2] = ((iVal >> 8) & 0xFF);
+ a[3] = ((iVal >> 0) & 0xFF);
+}
+
+/*
** Allocate and return a buffer at least nByte bytes in size.
**
** If an OOM error is encountered, return NULL and set the error code in
@@ -231396,10 +239738,17 @@ static void fts5DataDelete(Fts5Index *p, i64 iFirst, i64 iLast){
/*
** Remove all records associated with segment iSegid.
*/
-static void fts5DataRemoveSegment(Fts5Index *p, int iSegid){
+static void fts5DataRemoveSegment(Fts5Index *p, Fts5StructureSegment *pSeg){
+ int iSegid = pSeg->iSegid;
i64 iFirst = FTS5_SEGMENT_ROWID(iSegid, 0);
i64 iLast = FTS5_SEGMENT_ROWID(iSegid+1, 0)-1;
fts5DataDelete(p, iFirst, iLast);
+
+ if( pSeg->nPgTombstone ){
+ i64 iTomb1 = FTS5_TOMBSTONE_ROWID(iSegid, 0);
+ i64 iTomb2 = FTS5_TOMBSTONE_ROWID(iSegid, pSeg->nPgTombstone-1);
+ fts5DataDelete(p, iTomb1, iTomb2);
+ }
if( p->pIdxDeleter==0 ){
Fts5Config *pConfig = p->pConfig;
fts5IndexPrepareStmt(p, &p->pIdxDeleter, sqlite3_mprintf(
@@ -231510,11 +239859,19 @@ static int fts5StructureDecode(
int nSegment = 0;
sqlite3_int64 nByte; /* Bytes of space to allocate at pRet */
Fts5Structure *pRet = 0; /* Structure object to return */
+ int bStructureV2 = 0; /* True for FTS5_STRUCTURE_V2 */
+ u64 nOriginCntr = 0; /* Largest origin value seen so far */
/* Grab the cookie value */
if( piCookie ) *piCookie = sqlite3Fts5Get32(pData);
i = 4;
+ /* Check if this is a V2 structure record. Set bStructureV2 if it is. */
+ if( 0==memcmp(&pData[i], FTS5_STRUCTURE_V2, 4) ){
+ i += 4;
+ bStructureV2 = 1;
+ }
+
/* Read the total number of levels and segments from the start of the
** structure record. */
i += fts5GetVarint32(&pData[i], nLevel);
@@ -231561,9 +239918,18 @@ static int fts5StructureDecode(
rc = FTS5_CORRUPT;
break;
}
+ assert( pSeg!=0 );
i += fts5GetVarint32(&pData[i], pSeg->iSegid);
i += fts5GetVarint32(&pData[i], pSeg->pgnoFirst);
i += fts5GetVarint32(&pData[i], pSeg->pgnoLast);
+ if( bStructureV2 ){
+ i += fts5GetVarint(&pData[i], &pSeg->iOrigin1);
+ i += fts5GetVarint(&pData[i], &pSeg->iOrigin2);
+ i += fts5GetVarint32(&pData[i], pSeg->nPgTombstone);
+ i += fts5GetVarint(&pData[i], &pSeg->nEntryTombstone);
+ i += fts5GetVarint(&pData[i], &pSeg->nEntry);
+ nOriginCntr = MAX(nOriginCntr, pSeg->iOrigin2);
+ }
if( pSeg->pgnoLast<pSeg->pgnoFirst ){
rc = FTS5_CORRUPT;
break;
@@ -231574,6 +239940,9 @@ static int fts5StructureDecode(
}
}
if( nSegment!=0 && rc==SQLITE_OK ) rc = FTS5_CORRUPT;
+ if( bStructureV2 ){
+ pRet->nOriginCntr = nOriginCntr+1;
+ }
if( rc!=SQLITE_OK ){
fts5StructureRelease(pRet);
@@ -231591,6 +239960,7 @@ static int fts5StructureDecode(
*/
static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){
fts5StructureMakeWritable(pRc, ppStruct);
+ assert( (ppStruct!=0 && (*ppStruct)!=0) || (*pRc)!=SQLITE_OK );
if( *pRc==SQLITE_OK ){
Fts5Structure *pStruct = *ppStruct;
int nLevel = pStruct->nLevel;
@@ -231785,6 +240155,7 @@ static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){
Fts5Buffer buf; /* Buffer to serialize record into */
int iLvl; /* Used to iterate through levels */
int iCookie; /* Cookie value to store */
+ int nHdr = (pStruct->nOriginCntr>0 ? (4+4+9+9+9) : (4+9+9));
assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) );
memset(&buf, 0, sizeof(Fts5Buffer));
@@ -231793,9 +240164,12 @@ static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){
iCookie = p->pConfig->iCookie;
if( iCookie<0 ) iCookie = 0;
- if( 0==sqlite3Fts5BufferSize(&p->rc, &buf, 4+9+9+9) ){
+ if( 0==sqlite3Fts5BufferSize(&p->rc, &buf, nHdr) ){
sqlite3Fts5Put32(buf.p, iCookie);
buf.n = 4;
+ if( pStruct->nOriginCntr>0 ){
+ fts5BufferSafeAppendBlob(&buf, FTS5_STRUCTURE_V2, 4);
+ }
fts5BufferSafeAppendVarint(&buf, pStruct->nLevel);
fts5BufferSafeAppendVarint(&buf, pStruct->nSegment);
fts5BufferSafeAppendVarint(&buf, (i64)pStruct->nWriteCounter);
@@ -231809,9 +240183,17 @@ static void fts5StructureWrite(Fts5Index *p, Fts5Structure *pStruct){
assert( pLvl->nMerge<=pLvl->nSeg );
for(iSeg=0; iSeg<pLvl->nSeg; iSeg++){
- fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].iSegid);
- fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoFirst);
- fts5BufferAppendVarint(&p->rc, &buf, pLvl->aSeg[iSeg].pgnoLast);
+ Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->iSegid);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->pgnoFirst);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->pgnoLast);
+ if( pStruct->nOriginCntr>0 ){
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->iOrigin1);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->iOrigin2);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->nPgTombstone);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->nEntryTombstone);
+ fts5BufferAppendVarint(&p->rc, &buf, pSeg->nEntry);
+ }
}
}
@@ -231954,9 +240336,9 @@ static int fts5DlidxLvlNext(Fts5DlidxLvl *pLvl){
}
if( iOff<pData->nn ){
- i64 iVal;
+ u64 iVal;
pLvl->iLeafPgno += (iOff - pLvl->iOff) + 1;
- iOff += fts5GetVarint(&pData->p[iOff], (u64*)&iVal);
+ iOff += fts5GetVarint(&pData->p[iOff], &iVal);
pLvl->iRowid += iVal;
pLvl->iOff = iOff;
}else{
@@ -232049,42 +240431,25 @@ static int fts5DlidxLvlPrev(Fts5DlidxLvl *pLvl){
pLvl->bEof = 1;
}else{
u8 *a = pLvl->pData->p;
- i64 iVal;
- int iLimit;
- int ii;
- int nZero = 0;
-
- /* Currently iOff points to the first byte of a varint. This block
- ** decrements iOff until it points to the first byte of the previous
- ** varint. Taking care not to read any memory locations that occur
- ** before the buffer in memory. */
- iLimit = (iOff>9 ? iOff-9 : 0);
- for(iOff--; iOff>iLimit; iOff--){
- if( (a[iOff-1] & 0x80)==0 ) break;
- }
-
- fts5GetVarint(&a[iOff], (u64*)&iVal);
- pLvl->iRowid -= iVal;
- pLvl->iLeafPgno--;
-
- /* Skip backwards past any 0x00 varints. */
- for(ii=iOff-1; ii>=pLvl->iFirstOff && a[ii]==0x00; ii--){
- nZero++;
- }
- if( ii>=pLvl->iFirstOff && (a[ii] & 0x80) ){
- /* The byte immediately before the last 0x00 byte has the 0x80 bit
- ** set. So the last 0x00 is only a varint 0 if there are 8 more 0x80
- ** bytes before a[ii]. */
- int bZero = 0; /* True if last 0x00 counts */
- if( (ii-8)>=pLvl->iFirstOff ){
- int j;
- for(j=1; j<=8 && (a[ii-j] & 0x80); j++);
- bZero = (j>8);
+
+ pLvl->iOff = 0;
+ fts5DlidxLvlNext(pLvl);
+ while( 1 ){
+ int nZero = 0;
+ int ii = pLvl->iOff;
+ u64 delta = 0;
+
+ while( a[ii]==0 ){
+ nZero++;
+ ii++;
}
- if( bZero==0 ) nZero--;
+ ii += sqlite3Fts5GetVarint(&a[ii], &delta);
+
+ if( ii>=iOff ) break;
+ pLvl->iLeafPgno += nZero+1;
+ pLvl->iRowid += delta;
+ pLvl->iOff = ii;
}
- pLvl->iLeafPgno -= nZero;
- pLvl->iOff = iOff - nZero;
}
return pLvl->bEof;
@@ -232280,7 +240645,7 @@ static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){
i64 iOff = pIter->iLeafOffset;
ASSERT_SZLEAF_OK(pIter->pLeaf);
- if( iOff>=pIter->pLeaf->szLeaf ){
+ while( iOff>=pIter->pLeaf->szLeaf ){
fts5SegIterNextPage(p, pIter);
if( pIter->pLeaf==0 ){
if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT;
@@ -232352,6 +240717,25 @@ static void fts5SegIterSetNext(Fts5Index *p, Fts5SegIter *pIter){
}
/*
+** Allocate a tombstone hash page array object (pIter->pTombArray) for
+** the iterator passed as the second argument. If an OOM error occurs,
+** leave an error in the Fts5Index object.
+*/
+static void fts5SegIterAllocTombstone(Fts5Index *p, Fts5SegIter *pIter){
+ const int nTomb = pIter->pSeg->nPgTombstone;
+ if( nTomb>0 ){
+ int nByte = nTomb * sizeof(Fts5Data*) + sizeof(Fts5TombstoneArray);
+ Fts5TombstoneArray *pNew;
+ pNew = (Fts5TombstoneArray*)sqlite3Fts5MallocZero(&p->rc, nByte);
+ if( pNew ){
+ pNew->nTombstone = nTomb;
+ pNew->nRef = 1;
+ pIter->pTombArray = pNew;
+ }
+ }
+}
+
+/*
** Initialize the iterator object pIter to iterate through the entries in
** segment pSeg. The iterator is left pointing to the first entry when
** this function returns.
@@ -232379,10 +240763,12 @@ static void fts5SegIterInit(
fts5SegIterSetNext(p, pIter);
pIter->pSeg = pSeg;
pIter->iLeafPgno = pSeg->pgnoFirst-1;
- fts5SegIterNextPage(p, pIter);
+ do {
+ fts5SegIterNextPage(p, pIter);
+ }while( p->rc==SQLITE_OK && pIter->pLeaf && pIter->pLeaf->nn==4 );
}
- if( p->rc==SQLITE_OK ){
+ if( p->rc==SQLITE_OK && pIter->pLeaf ){
pIter->iLeafOffset = 4;
assert( pIter->pLeaf!=0 );
assert_nc( pIter->pLeaf->nn>4 );
@@ -232390,6 +240776,7 @@ static void fts5SegIterInit(
pIter->iPgidxOff = pIter->pLeaf->szLeaf+1;
fts5SegIterLoadTerm(p, pIter, 0);
fts5SegIterLoadNPos(p, pIter);
+ fts5SegIterAllocTombstone(p, pIter);
}
}
@@ -232576,7 +240963,7 @@ static void fts5SegIterNext_None(
iOff = pIter->iLeafOffset;
/* Next entry is on the next page */
- if( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){
+ while( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){
fts5SegIterNextPage(p, pIter);
if( p->rc || pIter->pLeaf==0 ) return;
pIter->iRowid = 0;
@@ -232600,15 +240987,16 @@ static void fts5SegIterNext_None(
}else{
const u8 *pList = 0;
const char *zTerm = 0;
+ int nTerm = 0;
int nList;
sqlite3Fts5HashScanNext(p->pHash);
- sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
+ sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &nTerm, &pList, &nList);
if( pList==0 ) goto next_none_eof;
pIter->pLeaf->p = (u8*)pList;
pIter->pLeaf->nn = nList;
pIter->pLeaf->szLeaf = nList;
pIter->iEndofDoclist = nList;
- sqlite3Fts5BufferSet(&p->rc,&pIter->term, (int)strlen(zTerm), (u8*)zTerm);
+ sqlite3Fts5BufferSet(&p->rc,&pIter->term, nTerm, (u8*)zTerm);
pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
}
@@ -232674,11 +241062,12 @@ static void fts5SegIterNext(
}else if( pIter->pSeg==0 ){
const u8 *pList = 0;
const char *zTerm = 0;
+ int nTerm = 0;
int nList = 0;
assert( (pIter->flags & FTS5_SEGITER_ONETERM) || pbNewTerm );
if( 0==(pIter->flags & FTS5_SEGITER_ONETERM) ){
sqlite3Fts5HashScanNext(p->pHash);
- sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &pList, &nList);
+ sqlite3Fts5HashScanEntry(p->pHash, &zTerm, &nTerm, &pList, &nList);
}
if( pList==0 ){
fts5DataRelease(pIter->pLeaf);
@@ -232688,8 +241077,7 @@ static void fts5SegIterNext(
pIter->pLeaf->nn = nList;
pIter->pLeaf->szLeaf = nList;
pIter->iEndofDoclist = nList+1;
- sqlite3Fts5BufferSet(&p->rc, &pIter->term, (int)strlen(zTerm),
- (u8*)zTerm);
+ sqlite3Fts5BufferSet(&p->rc, &pIter->term, nTerm, (u8*)zTerm);
pIter->iLeafOffset = fts5GetVarint(pList, (u64*)&pIter->iRowid);
*pbNewTerm = 1;
}
@@ -232769,7 +241157,7 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){
Fts5Data *pLast = 0;
int pgnoLast = 0;
- if( pDlidx ){
+ if( pDlidx && p->pConfig->iVersion==FTS5_CURRENT_VERSION ){
int iSegid = pIter->pSeg->iSegid;
pgnoLast = fts5DlidxIterPgno(pDlidx);
pLast = fts5LeafRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast));
@@ -233075,7 +241463,7 @@ static void fts5SegIterSeekInit(
fts5LeafSeek(p, bGe, pIter, pTerm, nTerm);
}
- if( p->rc==SQLITE_OK && bGe==0 ){
+ if( p->rc==SQLITE_OK && (bGe==0 || (flags & FTS5INDEX_QUERY_SCANONETERM)) ){
pIter->flags |= FTS5_SEGITER_ONETERM;
if( pIter->pLeaf ){
if( flags & FTS5INDEX_QUERY_DESC ){
@@ -233091,6 +241479,9 @@ static void fts5SegIterSeekInit(
}
fts5SegIterSetNext(p, pIter);
+ if( 0==(flags & FTS5INDEX_QUERY_SCANONETERM) ){
+ fts5SegIterAllocTombstone(p, pIter);
+ }
/* Either:
**
@@ -233107,6 +241498,79 @@ static void fts5SegIterSeekInit(
);
}
+
+/*
+** SQL used by fts5SegIterNextInit() to find the page to open.
+*/
+static sqlite3_stmt *fts5IdxNextStmt(Fts5Index *p){
+ if( p->pIdxNextSelect==0 ){
+ Fts5Config *pConfig = p->pConfig;
+ fts5IndexPrepareStmt(p, &p->pIdxNextSelect, sqlite3_mprintf(
+ "SELECT pgno FROM '%q'.'%q_idx' WHERE "
+ "segid=? AND term>? ORDER BY term ASC LIMIT 1",
+ pConfig->zDb, pConfig->zName
+ ));
+
+ }
+ return p->pIdxNextSelect;
+}
+
+/*
+** This is similar to fts5SegIterSeekInit(), except that it initializes
+** the segment iterator to point to the first term following the page
+** with pToken/nToken on it.
+*/
+static void fts5SegIterNextInit(
+ Fts5Index *p,
+ const char *pTerm, int nTerm,
+ Fts5StructureSegment *pSeg, /* Description of segment */
+ Fts5SegIter *pIter /* Object to populate */
+){
+ int iPg = -1; /* Page of segment to open */
+ int bDlidx = 0;
+ sqlite3_stmt *pSel = 0; /* SELECT to find iPg */
+
+ pSel = fts5IdxNextStmt(p);
+ if( pSel ){
+ assert( p->rc==SQLITE_OK );
+ sqlite3_bind_int(pSel, 1, pSeg->iSegid);
+ sqlite3_bind_blob(pSel, 2, pTerm, nTerm, SQLITE_STATIC);
+
+ if( sqlite3_step(pSel)==SQLITE_ROW ){
+ i64 val = sqlite3_column_int64(pSel, 0);
+ iPg = (int)(val>>1);
+ bDlidx = (val & 0x0001);
+ }
+ p->rc = sqlite3_reset(pSel);
+ sqlite3_bind_null(pSel, 2);
+ if( p->rc ) return;
+ }
+
+ memset(pIter, 0, sizeof(*pIter));
+ pIter->pSeg = pSeg;
+ pIter->flags |= FTS5_SEGITER_ONETERM;
+ if( iPg>=0 ){
+ pIter->iLeafPgno = iPg - 1;
+ fts5SegIterNextPage(p, pIter);
+ fts5SegIterSetNext(p, pIter);
+ }
+ if( pIter->pLeaf ){
+ const u8 *a = pIter->pLeaf->p;
+ int iTermOff = 0;
+
+ pIter->iPgidxOff = pIter->pLeaf->szLeaf;
+ pIter->iPgidxOff += fts5GetVarint32(&a[pIter->iPgidxOff], iTermOff);
+ pIter->iLeafOffset = iTermOff;
+ fts5SegIterLoadTerm(p, pIter, 0);
+ fts5SegIterLoadNPos(p, pIter);
+ if( bDlidx ) fts5SegIterLoadDlidx(p, pIter);
+
+ assert( p->rc!=SQLITE_OK ||
+ fts5BufferCompareBlob(&pIter->term, (const u8*)pTerm, nTerm)>0
+ );
+ }
+}
+
/*
** Initialize the object pIter to point to term pTerm/nTerm within the
** in-memory hash table. If there is no such term in the hash-table, the
@@ -233133,14 +241597,21 @@ static void fts5SegIterHashInit(
const u8 *pList = 0;
p->rc = sqlite3Fts5HashScanInit(p->pHash, (const char*)pTerm, nTerm);
- sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &pList, &nList);
- n = (z ? (int)strlen((const char*)z) : 0);
+ sqlite3Fts5HashScanEntry(p->pHash, (const char**)&z, &n, &pList, &nList);
if( pList ){
pLeaf = fts5IdxMalloc(p, sizeof(Fts5Data));
if( pLeaf ){
pLeaf->p = (u8*)pList;
}
}
+
+ /* The call to sqlite3Fts5HashScanInit() causes the hash table to
+ ** fill the size field of all existing position lists. This means they
+ ** can no longer be appended to. Since the only scenario in which they
+ ** can be appended to is if the previous operation on this table was
+ ** a DELETE, by clearing the Fts5Index.bDelete flag we can avoid this
+ ** possibility altogether. */
+ p->bDelete = 0;
}else{
p->rc = sqlite3Fts5HashQuery(p->pHash, sizeof(Fts5Data),
(const char*)pTerm, nTerm, (void**)&pLeaf, &nList
@@ -233172,12 +241643,44 @@ static void fts5SegIterHashInit(
}
/*
+** Array ap[] contains n elements. Release each of these elements using
+** fts5DataRelease(). Then free the array itself using sqlite3_free().
+*/
+static void fts5IndexFreeArray(Fts5Data **ap, int n){
+ if( ap ){
+ int ii;
+ for(ii=0; ii<n; ii++){
+ fts5DataRelease(ap[ii]);
+ }
+ sqlite3_free(ap);
+ }
+}
+
+/*
+** Decrement the ref-count of the object passed as the only argument. If it
+** reaches 0, free it and its contents.
+*/
+static void fts5TombstoneArrayDelete(Fts5TombstoneArray *p){
+ if( p ){
+ p->nRef--;
+ if( p->nRef<=0 ){
+ int ii;
+ for(ii=0; ii<p->nTombstone; ii++){
+ fts5DataRelease(p->apTombstone[ii]);
+ }
+ sqlite3_free(p);
+ }
+ }
+}
+
+/*
** Zero the iterator passed as the only argument.
*/
static void fts5SegIterClear(Fts5SegIter *pIter){
fts5BufferFree(&pIter->term);
fts5DataRelease(pIter->pLeaf);
fts5DataRelease(pIter->pNextLeaf);
+ fts5TombstoneArrayDelete(pIter->pTombArray);
fts5DlidxIterFree(pIter->pDlidx);
sqlite3_free(pIter->aRowidOffset);
memset(pIter, 0, sizeof(Fts5SegIter));
@@ -233311,7 +241814,6 @@ static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){
assert_nc( i2!=0 );
pRes->bTermEq = 1;
if( p1->iRowid==p2->iRowid ){
- p1->bDel = p2->bDel;
return i2;
}
res = ((p1->iRowid > p2->iRowid)==pIter->bRev) ? -1 : +1;
@@ -233330,7 +241832,8 @@ static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){
/*
** Move the seg-iter so that it points to the first rowid on page iLeafPgno.
-** It is an error if leaf iLeafPgno does not exist or contains no rowids.
+** It is an error if leaf iLeafPgno does not exist. Unless the db is
+** a 'secure-delete' db, if it contains no rowids then this is also an error.
*/
static void fts5SegIterGotoPage(
Fts5Index *p, /* FTS5 backend object */
@@ -233345,21 +241848,23 @@ static void fts5SegIterGotoPage(
fts5DataRelease(pIter->pNextLeaf);
pIter->pNextLeaf = 0;
pIter->iLeafPgno = iLeafPgno-1;
- fts5SegIterNextPage(p, pIter);
- assert( p->rc!=SQLITE_OK || pIter->iLeafPgno==iLeafPgno );
- if( p->rc==SQLITE_OK && ALWAYS(pIter->pLeaf!=0) ){
+ while( p->rc==SQLITE_OK ){
int iOff;
- u8 *a = pIter->pLeaf->p;
- int n = pIter->pLeaf->szLeaf;
-
+ fts5SegIterNextPage(p, pIter);
+ if( pIter->pLeaf==0 ) break;
iOff = fts5LeafFirstRowidOff(pIter->pLeaf);
- if( iOff<4 || iOff>=n ){
- p->rc = FTS5_CORRUPT;
- }else{
- iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid);
- pIter->iLeafOffset = iOff;
- fts5SegIterLoadNPos(p, pIter);
+ if( iOff>0 ){
+ u8 *a = pIter->pLeaf->p;
+ int n = pIter->pLeaf->szLeaf;
+ if( iOff<4 || iOff>=n ){
+ p->rc = FTS5_CORRUPT;
+ }else{
+ iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid);
+ pIter->iLeafOffset = iOff;
+ fts5SegIterLoadNPos(p, pIter);
+ }
+ break;
}
}
}
@@ -233420,7 +241925,6 @@ static void fts5SegIterNextFrom(
}while( p->rc==SQLITE_OK );
}
-
/*
** Free the iterator object passed as the second argument.
*/
@@ -233513,6 +242017,85 @@ static void fts5MultiIterSetEof(Fts5Iter *pIter){
}
/*
+** The argument to this macro must be an Fts5Data structure containing a
+** tombstone hash page. This macro returns the key-size of the hash-page.
+*/
+#define TOMBSTONE_KEYSIZE(pPg) (pPg->p[0]==4 ? 4 : 8)
+
+#define TOMBSTONE_NSLOT(pPg) \
+ ((pPg->nn > 16) ? ((pPg->nn-8) / TOMBSTONE_KEYSIZE(pPg)) : 1)
+
+/*
+** Query a single tombstone hash table for rowid iRowid. Return true if
+** it is found or false otherwise. The tombstone hash table is one of
+** nHashTable tables.
+*/
+static int fts5IndexTombstoneQuery(
+ Fts5Data *pHash, /* Hash table page to query */
+ int nHashTable, /* Number of pages attached to segment */
+ u64 iRowid /* Rowid to query hash for */
+){
+ const int szKey = TOMBSTONE_KEYSIZE(pHash);
+ const int nSlot = TOMBSTONE_NSLOT(pHash);
+ int iSlot = (iRowid / nHashTable) % nSlot;
+ int nCollide = nSlot;
+
+ if( iRowid==0 ){
+ return pHash->p[1];
+ }else if( szKey==4 ){
+ u32 *aSlot = (u32*)&pHash->p[8];
+ while( aSlot[iSlot] ){
+ if( fts5GetU32((u8*)&aSlot[iSlot])==iRowid ) return 1;
+ if( nCollide--==0 ) break;
+ iSlot = (iSlot+1)%nSlot;
+ }
+ }else{
+ u64 *aSlot = (u64*)&pHash->p[8];
+ while( aSlot[iSlot] ){
+ if( fts5GetU64((u8*)&aSlot[iSlot])==iRowid ) return 1;
+ if( nCollide--==0 ) break;
+ iSlot = (iSlot+1)%nSlot;
+ }
+ }
+
+ return 0;
+}
+
+/*
+** Return true if the iterator passed as the only argument points
+** to an segment entry for which there is a tombstone. Return false
+** if there is no tombstone or if the iterator is already at EOF.
+*/
+static int fts5MultiIterIsDeleted(Fts5Iter *pIter){
+ int iFirst = pIter->aFirst[1].iFirst;
+ Fts5SegIter *pSeg = &pIter->aSeg[iFirst];
+ Fts5TombstoneArray *pArray = pSeg->pTombArray;
+
+ if( pSeg->pLeaf && pArray ){
+ /* Figure out which page the rowid might be present on. */
+ int iPg = ((u64)pSeg->iRowid) % pArray->nTombstone;
+ assert( iPg>=0 );
+
+ /* If tombstone hash page iPg has not yet been loaded from the
+ ** database, load it now. */
+ if( pArray->apTombstone[iPg]==0 ){
+ pArray->apTombstone[iPg] = fts5DataRead(pIter->pIndex,
+ FTS5_TOMBSTONE_ROWID(pSeg->pSeg->iSegid, iPg)
+ );
+ if( pArray->apTombstone[iPg]==0 ) return 0;
+ }
+
+ return fts5IndexTombstoneQuery(
+ pArray->apTombstone[iPg],
+ pArray->nTombstone,
+ pSeg->iRowid
+ );
+ }
+
+ return 0;
+}
+
+/*
** Move the iterator to the next entry.
**
** If an error occurs, an error code is left in Fts5Index.rc. It is not
@@ -233549,7 +242132,9 @@ static void fts5MultiIterNext(
fts5AssertMultiIterSetup(p, pIter);
assert( pSeg==&pIter->aSeg[pIter->aFirst[1].iFirst] && pSeg->pLeaf );
- if( pIter->bSkipEmpty==0 || pSeg->nPos ){
+ if( (pIter->bSkipEmpty==0 || pSeg->nPos)
+ && 0==fts5MultiIterIsDeleted(pIter)
+ ){
pIter->xSetOutputs(pIter, pSeg);
return;
}
@@ -233581,7 +242166,9 @@ static void fts5MultiIterNext2(
}
fts5AssertMultiIterSetup(p, pIter);
- }while( fts5MultiIterIsEmpty(p, pIter) );
+ }while( (fts5MultiIterIsEmpty(p, pIter) || fts5MultiIterIsDeleted(pIter))
+ && (p->rc==SQLITE_OK)
+ );
}
}
@@ -233594,7 +242181,7 @@ static Fts5Iter *fts5MultiIterAlloc(
int nSeg
){
Fts5Iter *pNew;
- int nSlot; /* Power of two >= nSeg */
+ i64 nSlot; /* Power of two >= nSeg */
for(nSlot=2; nSlot<nSeg; nSlot=nSlot*2);
pNew = fts5IdxMalloc(p,
@@ -234039,6 +242626,32 @@ static void fts5IterSetOutputCb(int *pRc, Fts5Iter *pIter){
}
}
+/*
+** All the component segment-iterators of pIter have been set up. This
+** functions finishes setup for iterator pIter itself.
+*/
+static void fts5MultiIterFinishSetup(Fts5Index *p, Fts5Iter *pIter){
+ int iIter;
+ for(iIter=pIter->nSeg-1; iIter>0; iIter--){
+ int iEq;
+ if( (iEq = fts5MultiIterDoCompare(pIter, iIter)) ){
+ Fts5SegIter *pSeg = &pIter->aSeg[iEq];
+ if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0);
+ fts5MultiIterAdvanced(p, pIter, iEq, iIter);
+ }
+ }
+ fts5MultiIterSetEof(pIter);
+ fts5AssertMultiIterSetup(p, pIter);
+
+ if( (pIter->bSkipEmpty && fts5MultiIterIsEmpty(p, pIter))
+ || fts5MultiIterIsDeleted(pIter)
+ ){
+ fts5MultiIterNext(p, pIter, 0, 0);
+ }else if( pIter->base.bEof==0 ){
+ Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
+ pIter->xSetOutputs(pIter, pSeg);
+ }
+}
/*
** Allocate a new Fts5Iter object.
@@ -234074,7 +242687,7 @@ static void fts5MultiIterNew(
if( iLevel<0 ){
assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) );
nSeg = pStruct->nSegment;
- nSeg += (p->pHash ? 1 : 0);
+ nSeg += (p->pHash && 0==(flags & FTS5INDEX_QUERY_SKIPHASH));
}else{
nSeg = MIN(pStruct->aLevel[iLevel].nSeg, nSegment);
}
@@ -234095,7 +242708,7 @@ static void fts5MultiIterNew(
if( p->rc==SQLITE_OK ){
if( iLevel<0 ){
Fts5StructureLevel *pEnd = &pStruct->aLevel[pStruct->nLevel];
- if( p->pHash ){
+ if( p->pHash && 0==(flags & FTS5INDEX_QUERY_SKIPHASH) ){
/* Add a segment iterator for the current contents of the hash table. */
Fts5SegIter *pIter = &pNew->aSeg[iIter++];
fts5SegIterHashInit(p, pTerm, nTerm, flags, pIter);
@@ -234120,29 +242733,12 @@ static void fts5MultiIterNew(
assert( iIter==nSeg );
}
- /* If the above was successful, each component iterators now points
+ /* If the above was successful, each component iterator now points
** to the first entry in its segment. In this case initialize the
** aFirst[] array. Or, if an error has occurred, free the iterator
** object and set the output variable to NULL. */
if( p->rc==SQLITE_OK ){
- for(iIter=pNew->nSeg-1; iIter>0; iIter--){
- int iEq;
- if( (iEq = fts5MultiIterDoCompare(pNew, iIter)) ){
- Fts5SegIter *pSeg = &pNew->aSeg[iEq];
- if( p->rc==SQLITE_OK ) pSeg->xNext(p, pSeg, 0);
- fts5MultiIterAdvanced(p, pNew, iEq, iIter);
- }
- }
- fts5MultiIterSetEof(pNew);
- fts5AssertMultiIterSetup(p, pNew);
-
- if( pNew->bSkipEmpty && fts5MultiIterIsEmpty(p, pNew) ){
- fts5MultiIterNext(p, pNew, 0, 0);
- }else if( pNew->base.bEof==0 ){
- Fts5SegIter *pSeg = &pNew->aSeg[pNew->aFirst[1].iFirst];
- pNew->xSetOutputs(pNew, pSeg);
- }
-
+ fts5MultiIterFinishSetup(p, pNew);
}else{
fts5MultiIterFree(pNew);
*ppOut = 0;
@@ -234167,7 +242763,6 @@ static void fts5MultiIterNew2(
pNew = fts5MultiIterAlloc(p, 2);
if( pNew ){
Fts5SegIter *pIter = &pNew->aSeg[1];
-
pIter->flags = FTS5_SEGITER_ONETERM;
if( pData->szLeaf>0 ){
pIter->pLeaf = pData;
@@ -234314,7 +242909,10 @@ static void fts5IndexDiscardData(Fts5Index *p){
if( p->pHash ){
sqlite3Fts5HashClear(p->pHash);
p->nPendingData = 0;
+ p->nPendingRow = 0;
+ p->flushRc = SQLITE_OK;
}
+ p->nContentlessDelete = 0;
}
/*
@@ -234528,7 +243126,7 @@ static void fts5WriteDlidxAppend(
}
if( pDlidx->bPrevValid ){
- iVal = iRowid - pDlidx->iPrev;
+ iVal = (u64)iRowid - (u64)pDlidx->iPrev;
}else{
i64 iPgno = (i==0 ? pWriter->writer.pgno : pDlidx[-1].pgno);
assert( pDlidx->buf.n==0 );
@@ -234715,7 +243313,7 @@ static void fts5WriteAppendPoslistData(
const u8 *a = aData;
int n = nData;
- assert( p->pConfig->pgsz>0 );
+ assert( p->pConfig->pgsz>0 || p->rc!=SQLITE_OK );
while( p->rc==SQLITE_OK
&& (pPage->buf.n + pPage->pgidx.n + n)>=p->pConfig->pgsz
){
@@ -234850,7 +243448,7 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){
fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr);
fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n);
fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p);
- fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff,&pData->p[iOff]);
+ fts5BufferAppendBlob(&p->rc, &buf,pData->szLeaf-iOff,&pData->p[iOff]);
if( p->rc==SQLITE_OK ){
/* Set the szLeaf field */
fts5PutU16(&buf.p[2], (u16)buf.n);
@@ -234951,6 +243549,12 @@ static void fts5IndexMergeLevel(
/* Read input from all segments in the input level */
nInput = pLvl->nSeg;
+
+ /* Set the range of origins that will go into the output segment. */
+ if( pStruct->nOriginCntr>0 ){
+ pSeg->iOrigin1 = pLvl->aSeg[0].iOrigin1;
+ pSeg->iOrigin2 = pLvl->aSeg[pLvl->nSeg-1].iOrigin2;
+ }
}
bOldest = (pLvlOut->nSeg==1 && pStruct->nLevel==iLvl+2);
@@ -235010,8 +243614,11 @@ static void fts5IndexMergeLevel(
int i;
/* Remove the redundant segments from the %_data table */
+ assert( pSeg->nEntry==0 );
for(i=0; i<nInput; i++){
- fts5DataRemoveSegment(p, pLvl->aSeg[i].iSegid);
+ Fts5StructureSegment *pOld = &pLvl->aSeg[i];
+ pSeg->nEntry += (pOld->nEntry - pOld->nEntryTombstone);
+ fts5DataRemoveSegment(p, pOld);
}
/* Remove the redundant segments from the input level */
@@ -235038,6 +243645,43 @@ static void fts5IndexMergeLevel(
}
/*
+** If this is not a contentless_delete=1 table, or if the 'deletemerge'
+** configuration option is set to 0, then this function always returns -1.
+** Otherwise, it searches the structure object passed as the second argument
+** for a level suitable for merging due to having a large number of
+** tombstones in the tombstone hash. If one is found, its index is returned.
+** Otherwise, if there is no suitable level, -1.
+*/
+static int fts5IndexFindDeleteMerge(Fts5Index *p, Fts5Structure *pStruct){
+ Fts5Config *pConfig = p->pConfig;
+ int iRet = -1;
+ if( pConfig->bContentlessDelete && pConfig->nDeleteMerge>0 ){
+ int ii;
+ int nBest = 0;
+
+ for(ii=0; ii<pStruct->nLevel; ii++){
+ Fts5StructureLevel *pLvl = &pStruct->aLevel[ii];
+ i64 nEntry = 0;
+ i64 nTomb = 0;
+ int iSeg;
+ for(iSeg=0; iSeg<pLvl->nSeg; iSeg++){
+ nEntry += pLvl->aSeg[iSeg].nEntry;
+ nTomb += pLvl->aSeg[iSeg].nEntryTombstone;
+ }
+ assert_nc( nEntry>0 || pLvl->nSeg==0 );
+ if( nEntry>0 ){
+ int nPercent = (nTomb * 100) / nEntry;
+ if( nPercent>=pConfig->nDeleteMerge && nPercent>nBest ){
+ iRet = ii;
+ nBest = nPercent;
+ }
+ }
+ }
+ }
+ return iRet;
+}
+
+/*
** Do up to nPg pages of automerge work on the index.
**
** Return true if any changes were actually made, or false otherwise.
@@ -235056,14 +243700,15 @@ static int fts5IndexMerge(
int iBestLvl = 0; /* Level offering the most input segments */
int nBest = 0; /* Number of input segments on best level */
- /* Set iBestLvl to the level to read input segments from. */
+ /* Set iBestLvl to the level to read input segments from. Or to -1 if
+ ** there is no level suitable to merge segments from. */
assert( pStruct->nLevel>0 );
for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
Fts5StructureLevel *pLvl = &pStruct->aLevel[iLvl];
if( pLvl->nMerge ){
if( pLvl->nMerge>nBest ){
iBestLvl = iLvl;
- nBest = pLvl->nMerge;
+ nBest = nMin;
}
break;
}
@@ -235072,22 +243717,18 @@ static int fts5IndexMerge(
iBestLvl = iLvl;
}
}
-
- /* If nBest is still 0, then the index must be empty. */
-#ifdef SQLITE_DEBUG
- for(iLvl=0; nBest==0 && iLvl<pStruct->nLevel; iLvl++){
- assert( pStruct->aLevel[iLvl].nSeg==0 );
+ if( nBest<nMin ){
+ iBestLvl = fts5IndexFindDeleteMerge(p, pStruct);
}
-#endif
- if( nBest<nMin && pStruct->aLevel[iBestLvl].nMerge==0 ){
- break;
- }
+ if( iBestLvl<0 ) break;
bRet = 1;
fts5IndexMergeLevel(p, &pStruct, iBestLvl, &nRem);
if( p->rc==SQLITE_OK && pStruct->aLevel[iBestLvl].nMerge==0 ){
fts5StructurePromote(p, iBestLvl+1, pStruct);
}
+
+ if( nMin==1 ) nMin = 2;
}
*ppStruct = pStruct;
return bRet;
@@ -235128,16 +243769,16 @@ static void fts5IndexCrisismerge(
){
const int nCrisis = p->pConfig->nCrisisMerge;
Fts5Structure *pStruct = *ppStruct;
- int iLvl = 0;
-
- assert( p->rc!=SQLITE_OK || pStruct->nLevel>0 );
- while( p->rc==SQLITE_OK && pStruct->aLevel[iLvl].nSeg>=nCrisis ){
- fts5IndexMergeLevel(p, &pStruct, iLvl, 0);
- assert( p->rc!=SQLITE_OK || pStruct->nLevel>(iLvl+1) );
- fts5StructurePromote(p, iLvl+1, pStruct);
- iLvl++;
+ if( pStruct && pStruct->nLevel>0 ){
+ int iLvl = 0;
+ while( p->rc==SQLITE_OK && pStruct->aLevel[iLvl].nSeg>=nCrisis ){
+ fts5IndexMergeLevel(p, &pStruct, iLvl, 0);
+ assert( p->rc!=SQLITE_OK || pStruct->nLevel>(iLvl+1) );
+ fts5StructurePromote(p, iLvl+1, pStruct);
+ iLvl++;
+ }
+ *ppStruct = pStruct;
}
- *ppStruct = pStruct;
}
static int fts5IndexReturn(Fts5Index *p){
@@ -235172,6 +243813,469 @@ static int fts5PoslistPrefix(const u8 *aBuf, int nMax){
}
/*
+** Execute the SQL statement:
+**
+** DELETE FROM %_idx WHERE (segid, (pgno/2)) = ($iSegid, $iPgno);
+**
+** This is used when a secure-delete operation removes the last term
+** from a segment leaf page. In that case the %_idx entry is removed
+** too. This is done to ensure that if all instances of a token are
+** removed from an fts5 database in secure-delete mode, no trace of
+** the token itself remains in the database.
+*/
+static void fts5SecureDeleteIdxEntry(
+ Fts5Index *p, /* FTS5 backend object */
+ int iSegid, /* Id of segment to delete entry for */
+ int iPgno /* Page number within segment */
+){
+ if( iPgno!=1 ){
+ assert( p->pConfig->iVersion==FTS5_CURRENT_VERSION_SECUREDELETE );
+ if( p->pDeleteFromIdx==0 ){
+ fts5IndexPrepareStmt(p, &p->pDeleteFromIdx, sqlite3_mprintf(
+ "DELETE FROM '%q'.'%q_idx' WHERE (segid, (pgno/2)) = (?1, ?2)",
+ p->pConfig->zDb, p->pConfig->zName
+ ));
+ }
+ if( p->rc==SQLITE_OK ){
+ sqlite3_bind_int(p->pDeleteFromIdx, 1, iSegid);
+ sqlite3_bind_int(p->pDeleteFromIdx, 2, iPgno);
+ sqlite3_step(p->pDeleteFromIdx);
+ p->rc = sqlite3_reset(p->pDeleteFromIdx);
+ }
+ }
+}
+
+/*
+** This is called when a secure-delete operation removes a position-list
+** that overflows onto segment page iPgno of segment pSeg. This function
+** rewrites node iPgno, and possibly one or more of its right-hand peers,
+** to remove this portion of the position list.
+**
+** Output variable (*pbLastInDoclist) is set to true if the position-list
+** removed is followed by a new term or the end-of-segment, or false if
+** it is followed by another rowid/position list.
+*/
+static void fts5SecureDeleteOverflow(
+ Fts5Index *p,
+ Fts5StructureSegment *pSeg,
+ int iPgno,
+ int *pbLastInDoclist
+){
+ const int bDetailNone = (p->pConfig->eDetail==FTS5_DETAIL_NONE);
+ int pgno;
+ Fts5Data *pLeaf = 0;
+ assert( iPgno!=1 );
+
+ *pbLastInDoclist = 1;
+ for(pgno=iPgno; p->rc==SQLITE_OK && pgno<=pSeg->pgnoLast; pgno++){
+ i64 iRowid = FTS5_SEGMENT_ROWID(pSeg->iSegid, pgno);
+ int iNext = 0;
+ u8 *aPg = 0;
+
+ pLeaf = fts5DataRead(p, iRowid);
+ if( pLeaf==0 ) break;
+ aPg = pLeaf->p;
+
+ iNext = fts5GetU16(&aPg[0]);
+ if( iNext!=0 ){
+ *pbLastInDoclist = 0;
+ }
+ if( iNext==0 && pLeaf->szLeaf!=pLeaf->nn ){
+ fts5GetVarint32(&aPg[pLeaf->szLeaf], iNext);
+ }
+
+ if( iNext==0 ){
+ /* The page contains no terms or rowids. Replace it with an empty
+ ** page and move on to the right-hand peer. */
+ const u8 aEmpty[] = {0x00, 0x00, 0x00, 0x04};
+ assert_nc( bDetailNone==0 || pLeaf->nn==4 );
+ if( bDetailNone==0 ) fts5DataWrite(p, iRowid, aEmpty, sizeof(aEmpty));
+ fts5DataRelease(pLeaf);
+ pLeaf = 0;
+ }else if( bDetailNone ){
+ break;
+ }else if( iNext>=pLeaf->szLeaf || pLeaf->nn<pLeaf->szLeaf || iNext<4 ){
+ p->rc = FTS5_CORRUPT;
+ break;
+ }else{
+ int nShift = iNext - 4;
+ int nPg;
+
+ int nIdx = 0;
+ u8 *aIdx = 0;
+
+ /* Unless the current page footer is 0 bytes in size (in which case
+ ** the new page footer will be as well), allocate and populate a
+ ** buffer containing the new page footer. Set stack variables aIdx
+ ** and nIdx accordingly. */
+ if( pLeaf->nn>pLeaf->szLeaf ){
+ int iFirst = 0;
+ int i1 = pLeaf->szLeaf;
+ int i2 = 0;
+
+ i1 += fts5GetVarint32(&aPg[i1], iFirst);
+ if( iFirst<iNext ){
+ p->rc = FTS5_CORRUPT;
+ break;
+ }
+ aIdx = sqlite3Fts5MallocZero(&p->rc, (pLeaf->nn-pLeaf->szLeaf)+2);
+ if( aIdx==0 ) break;
+ i2 = sqlite3Fts5PutVarint(aIdx, iFirst-nShift);
+ if( i1<pLeaf->nn ){
+ memcpy(&aIdx[i2], &aPg[i1], pLeaf->nn-i1);
+ i2 += (pLeaf->nn-i1);
+ }
+ nIdx = i2;
+ }
+
+ /* Modify the contents of buffer aPg[]. Set nPg to the new size
+ ** in bytes. The new page is always smaller than the old. */
+ nPg = pLeaf->szLeaf - nShift;
+ memmove(&aPg[4], &aPg[4+nShift], nPg-4);
+ fts5PutU16(&aPg[2], nPg);
+ if( fts5GetU16(&aPg[0]) ) fts5PutU16(&aPg[0], 4);
+ if( nIdx>0 ){
+ memcpy(&aPg[nPg], aIdx, nIdx);
+ nPg += nIdx;
+ }
+ sqlite3_free(aIdx);
+
+ /* Write the new page to disk and exit the loop */
+ assert( nPg>4 || fts5GetU16(aPg)==0 );
+ fts5DataWrite(p, iRowid, aPg, nPg);
+ break;
+ }
+ }
+ fts5DataRelease(pLeaf);
+}
+
+/*
+** Completely remove the entry that pSeg currently points to from
+** the database.
+*/
+static void fts5DoSecureDelete(
+ Fts5Index *p,
+ Fts5SegIter *pSeg
+){
+ const int bDetailNone = (p->pConfig->eDetail==FTS5_DETAIL_NONE);
+ int iSegid = pSeg->pSeg->iSegid;
+ u8 *aPg = pSeg->pLeaf->p;
+ int nPg = pSeg->pLeaf->nn;
+ int iPgIdx = pSeg->pLeaf->szLeaf;
+
+ u64 iDelta = 0;
+ int iNextOff = 0;
+ int iOff = 0;
+ int nIdx = 0;
+ u8 *aIdx = 0;
+ int bLastInDoclist = 0;
+ int iIdx = 0;
+ int iStart = 0;
+ int iDelKeyOff = 0; /* Offset of deleted key, if any */
+
+ nIdx = nPg-iPgIdx;
+ aIdx = sqlite3Fts5MallocZero(&p->rc, nIdx+16);
+ if( p->rc ) return;
+ memcpy(aIdx, &aPg[iPgIdx], nIdx);
+
+ /* At this point segment iterator pSeg points to the entry
+ ** this function should remove from the b-tree segment.
+ **
+ ** In detail=full or detail=column mode, pSeg->iLeafOffset is the
+ ** offset of the first byte in the position-list for the entry to
+ ** remove. Immediately before this comes two varints that will also
+ ** need to be removed:
+ **
+ ** + the rowid or delta rowid value for the entry, and
+ ** + the size of the position list in bytes.
+ **
+ ** Or, in detail=none mode, there is a single varint prior to
+ ** pSeg->iLeafOffset - the rowid or delta rowid value.
+ **
+ ** This block sets the following variables:
+ **
+ ** iStart:
+ ** The offset of the first byte of the rowid or delta-rowid
+ ** value for the doclist entry being removed.
+ **
+ ** iDelta:
+ ** The value of the rowid or delta-rowid value for the doclist
+ ** entry being removed.
+ **
+ ** iNextOff:
+ ** The offset of the next entry following the position list
+ ** for the one being removed. If the position list for this
+ ** entry overflows onto the next leaf page, this value will be
+ ** greater than pLeaf->szLeaf.
+ */
+ {
+ int iSOP; /* Start-Of-Position-list */
+ if( pSeg->iLeafPgno==pSeg->iTermLeafPgno ){
+ iStart = pSeg->iTermLeafOffset;
+ }else{
+ iStart = fts5GetU16(&aPg[0]);
+ }
+
+ iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
+ assert_nc( iSOP<=pSeg->iLeafOffset );
+
+ if( bDetailNone ){
+ while( iSOP<pSeg->iLeafOffset ){
+ if( aPg[iSOP]==0x00 ) iSOP++;
+ if( aPg[iSOP]==0x00 ) iSOP++;
+ iStart = iSOP;
+ iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
+ }
+
+ iNextOff = iSOP;
+ if( iNextOff<pSeg->iEndofDoclist && aPg[iNextOff]==0x00 ) iNextOff++;
+ if( iNextOff<pSeg->iEndofDoclist && aPg[iNextOff]==0x00 ) iNextOff++;
+
+ }else{
+ int nPos = 0;
+ iSOP += fts5GetVarint32(&aPg[iSOP], nPos);
+ while( iSOP<pSeg->iLeafOffset ){
+ iStart = iSOP + (nPos/2);
+ iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
+ iSOP += fts5GetVarint32(&aPg[iSOP], nPos);
+ }
+ assert_nc( iSOP==pSeg->iLeafOffset );
+ iNextOff = pSeg->iLeafOffset + pSeg->nPos;
+ }
+ }
+
+ iOff = iStart;
+
+ /* If the position-list for the entry being removed flows over past
+ ** the end of this page, delete the portion of the position-list on the
+ ** next page and beyond.
+ **
+ ** Set variable bLastInDoclist to true if this entry happens
+ ** to be the last rowid in the doclist for its term. */
+ if( iNextOff>=iPgIdx ){
+ int pgno = pSeg->iLeafPgno+1;
+ fts5SecureDeleteOverflow(p, pSeg->pSeg, pgno, &bLastInDoclist);
+ iNextOff = iPgIdx;
+ }
+
+ if( pSeg->bDel==0 ){
+ if( iNextOff!=iPgIdx ){
+ /* Loop through the page-footer. If iNextOff (offset of the
+ ** entry following the one we are removing) is equal to the
+ ** offset of a key on this page, then the entry is the last
+ ** in its doclist. */
+ int iKeyOff = 0;
+ for(iIdx=0; iIdx<nIdx; /* no-op */){
+ u32 iVal = 0;
+ iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
+ iKeyOff += iVal;
+ if( iKeyOff==iNextOff ){
+ bLastInDoclist = 1;
+ }
+ }
+ }
+
+ /* If this is (a) the first rowid on a page and (b) is not followed by
+ ** another position list on the same page, set the "first-rowid" field
+ ** of the header to 0. */
+ if( fts5GetU16(&aPg[0])==iStart && (bLastInDoclist || iNextOff==iPgIdx) ){
+ fts5PutU16(&aPg[0], 0);
+ }
+ }
+
+ if( pSeg->bDel ){
+ iOff += sqlite3Fts5PutVarint(&aPg[iOff], iDelta);
+ aPg[iOff++] = 0x01;
+ }else if( bLastInDoclist==0 ){
+ if( iNextOff!=iPgIdx ){
+ u64 iNextDelta = 0;
+ iNextOff += fts5GetVarint(&aPg[iNextOff], &iNextDelta);
+ iOff += sqlite3Fts5PutVarint(&aPg[iOff], iDelta + iNextDelta);
+ }
+ }else if(
+ pSeg->iLeafPgno==pSeg->iTermLeafPgno
+ && iStart==pSeg->iTermLeafOffset
+ ){
+ /* The entry being removed was the only position list in its
+ ** doclist. Therefore the term needs to be removed as well. */
+ int iKey = 0;
+ int iKeyOff = 0;
+
+ /* Set iKeyOff to the offset of the term that will be removed - the
+ ** last offset in the footer that is not greater than iStart. */
+ for(iIdx=0; iIdx<nIdx; iKey++){
+ u32 iVal = 0;
+ iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
+ if( (iKeyOff+iVal)>(u32)iStart ) break;
+ iKeyOff += iVal;
+ }
+ assert_nc( iKey>=1 );
+
+ /* Set iDelKeyOff to the value of the footer entry to remove from
+ ** the page. */
+ iDelKeyOff = iOff = iKeyOff;
+
+ if( iNextOff!=iPgIdx ){
+ /* This is the only position-list associated with the term, and there
+ ** is another term following it on this page. So the subsequent term
+ ** needs to be moved to replace the term associated with the entry
+ ** being removed. */
+ int nPrefix = 0;
+ int nSuffix = 0;
+ int nPrefix2 = 0;
+ int nSuffix2 = 0;
+
+ iDelKeyOff = iNextOff;
+ iNextOff += fts5GetVarint32(&aPg[iNextOff], nPrefix2);
+ iNextOff += fts5GetVarint32(&aPg[iNextOff], nSuffix2);
+
+ if( iKey!=1 ){
+ iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nPrefix);
+ }
+ iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nSuffix);
+
+ nPrefix = MIN(nPrefix, nPrefix2);
+ nSuffix = (nPrefix2 + nSuffix2) - nPrefix;
+
+ if( (iKeyOff+nSuffix)>iPgIdx || (iNextOff+nSuffix2)>iPgIdx ){
+ p->rc = FTS5_CORRUPT;
+ }else{
+ if( iKey!=1 ){
+ iOff += sqlite3Fts5PutVarint(&aPg[iOff], nPrefix);
+ }
+ iOff += sqlite3Fts5PutVarint(&aPg[iOff], nSuffix);
+ if( nPrefix2>pSeg->term.n ){
+ p->rc = FTS5_CORRUPT;
+ }else if( nPrefix2>nPrefix ){
+ memcpy(&aPg[iOff], &pSeg->term.p[nPrefix], nPrefix2-nPrefix);
+ iOff += (nPrefix2-nPrefix);
+ }
+ memmove(&aPg[iOff], &aPg[iNextOff], nSuffix2);
+ iOff += nSuffix2;
+ iNextOff += nSuffix2;
+ }
+ }
+ }else if( iStart==4 ){
+ int iPgno;
+
+ assert_nc( pSeg->iLeafPgno>pSeg->iTermLeafPgno );
+ /* The entry being removed may be the only position list in
+ ** its doclist. */
+ for(iPgno=pSeg->iLeafPgno-1; iPgno>pSeg->iTermLeafPgno; iPgno-- ){
+ Fts5Data *pPg = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, iPgno));
+ int bEmpty = (pPg && pPg->nn==4);
+ fts5DataRelease(pPg);
+ if( bEmpty==0 ) break;
+ }
+
+ if( iPgno==pSeg->iTermLeafPgno ){
+ i64 iId = FTS5_SEGMENT_ROWID(iSegid, pSeg->iTermLeafPgno);
+ Fts5Data *pTerm = fts5DataRead(p, iId);
+ if( pTerm && pTerm->szLeaf==pSeg->iTermLeafOffset ){
+ u8 *aTermIdx = &pTerm->p[pTerm->szLeaf];
+ int nTermIdx = pTerm->nn - pTerm->szLeaf;
+ int iTermIdx = 0;
+ int iTermOff = 0;
+
+ while( 1 ){
+ u32 iVal = 0;
+ int nByte = fts5GetVarint32(&aTermIdx[iTermIdx], iVal);
+ iTermOff += iVal;
+ if( (iTermIdx+nByte)>=nTermIdx ) break;
+ iTermIdx += nByte;
+ }
+ nTermIdx = iTermIdx;
+
+ memmove(&pTerm->p[iTermOff], &pTerm->p[pTerm->szLeaf], nTermIdx);
+ fts5PutU16(&pTerm->p[2], iTermOff);
+
+ fts5DataWrite(p, iId, pTerm->p, iTermOff+nTermIdx);
+ if( nTermIdx==0 ){
+ fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iTermLeafPgno);
+ }
+ }
+ fts5DataRelease(pTerm);
+ }
+ }
+
+ /* Assuming no error has occurred, this block does final edits to the
+ ** leaf page before writing it back to disk. Input variables are:
+ **
+ ** nPg: Total initial size of leaf page.
+ ** iPgIdx: Initial offset of page footer.
+ **
+ ** iOff: Offset to move data to
+ ** iNextOff: Offset to move data from
+ */
+ if( p->rc==SQLITE_OK ){
+ const int nMove = nPg - iNextOff; /* Number of bytes to move */
+ int nShift = iNextOff - iOff; /* Distance to move them */
+
+ int iPrevKeyOut = 0;
+ int iKeyIn = 0;
+
+ memmove(&aPg[iOff], &aPg[iNextOff], nMove);
+ iPgIdx -= nShift;
+ nPg = iPgIdx;
+ fts5PutU16(&aPg[2], iPgIdx);
+
+ for(iIdx=0; iIdx<nIdx; /* no-op */){
+ u32 iVal = 0;
+ iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
+ iKeyIn += iVal;
+ if( iKeyIn!=iDelKeyOff ){
+ int iKeyOut = (iKeyIn - (iKeyIn>iOff ? nShift : 0));
+ nPg += sqlite3Fts5PutVarint(&aPg[nPg], iKeyOut - iPrevKeyOut);
+ iPrevKeyOut = iKeyOut;
+ }
+ }
+
+ if( iPgIdx==nPg && nIdx>0 && pSeg->iLeafPgno!=1 ){
+ fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iLeafPgno);
+ }
+
+ assert_nc( nPg>4 || fts5GetU16(aPg)==0 );
+ fts5DataWrite(p, FTS5_SEGMENT_ROWID(iSegid,pSeg->iLeafPgno), aPg, nPg);
+ }
+ sqlite3_free(aIdx);
+}
+
+/*
+** This is called as part of flushing a delete to disk in 'secure-delete'
+** mode. It edits the segments within the database described by argument
+** pStruct to remove the entries for term zTerm, rowid iRowid.
+*/
+static void fts5FlushSecureDelete(
+ Fts5Index *p,
+ Fts5Structure *pStruct,
+ const char *zTerm,
+ int nTerm,
+ i64 iRowid
+){
+ const int f = FTS5INDEX_QUERY_SKIPHASH;
+ Fts5Iter *pIter = 0; /* Used to find term instance */
+
+ fts5MultiIterNew(p, pStruct, f, 0, (const u8*)zTerm, nTerm, -1, 0, &pIter);
+ if( fts5MultiIterEof(p, pIter)==0 ){
+ i64 iThis = fts5MultiIterRowid(pIter);
+ if( iThis<iRowid ){
+ fts5MultiIterNextFrom(p, pIter, iRowid);
+ }
+
+ if( p->rc==SQLITE_OK
+ && fts5MultiIterEof(p, pIter)==0
+ && iRowid==fts5MultiIterRowid(pIter)
+ ){
+ Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
+ fts5DoSecureDelete(p, pSeg);
+ }
+ }
+
+ fts5MultiIterFree(pIter);
+}
+
+
+/*
** Flush the contents of in-memory hash table iHash to a new level-0
** segment on disk. Also update the corresponding structure record.
**
@@ -235187,143 +244291,197 @@ static void fts5FlushOneHash(Fts5Index *p){
/* Obtain a reference to the index structure and allocate a new segment-id
** for the new level-0 segment. */
pStruct = fts5StructureRead(p);
- iSegid = fts5AllocateSegid(p, pStruct);
fts5StructureInvalidate(p);
- if( iSegid ){
- const int pgsz = p->pConfig->pgsz;
- int eDetail = p->pConfig->eDetail;
- Fts5StructureSegment *pSeg; /* New segment within pStruct */
- Fts5Buffer *pBuf; /* Buffer in which to assemble leaf page */
- Fts5Buffer *pPgidx; /* Buffer in which to assemble pgidx */
+ if( sqlite3Fts5HashIsEmpty(pHash)==0 ){
+ iSegid = fts5AllocateSegid(p, pStruct);
+ if( iSegid ){
+ const int pgsz = p->pConfig->pgsz;
+ int eDetail = p->pConfig->eDetail;
+ int bSecureDelete = p->pConfig->bSecureDelete;
+ Fts5StructureSegment *pSeg; /* New segment within pStruct */
+ Fts5Buffer *pBuf; /* Buffer in which to assemble leaf page */
+ Fts5Buffer *pPgidx; /* Buffer in which to assemble pgidx */
+
+ Fts5SegWriter writer;
+ fts5WriteInit(p, &writer, iSegid);
+
+ pBuf = &writer.writer.buf;
+ pPgidx = &writer.writer.pgidx;
+
+ /* fts5WriteInit() should have initialized the buffers to (most likely)
+ ** the maximum space required. */
+ assert( p->rc || pBuf->nSpace>=(pgsz + FTS5_DATA_PADDING) );
+ assert( p->rc || pPgidx->nSpace>=(pgsz + FTS5_DATA_PADDING) );
+
+ /* Begin scanning through hash table entries. This loop runs once for each
+ ** term/doclist currently stored within the hash table. */
+ if( p->rc==SQLITE_OK ){
+ p->rc = sqlite3Fts5HashScanInit(pHash, 0, 0);
+ }
+ while( p->rc==SQLITE_OK && 0==sqlite3Fts5HashScanEof(pHash) ){
+ const char *zTerm; /* Buffer containing term */
+ int nTerm; /* Size of zTerm in bytes */
+ const u8 *pDoclist; /* Pointer to doclist for this term */
+ int nDoclist; /* Size of doclist in bytes */
- Fts5SegWriter writer;
- fts5WriteInit(p, &writer, iSegid);
+ /* Get the term and doclist for this entry. */
+ sqlite3Fts5HashScanEntry(pHash, &zTerm, &nTerm, &pDoclist, &nDoclist);
+ if( bSecureDelete==0 ){
+ fts5WriteAppendTerm(p, &writer, nTerm, (const u8*)zTerm);
+ if( p->rc!=SQLITE_OK ) break;
+ assert( writer.bFirstRowidInPage==0 );
+ }
- pBuf = &writer.writer.buf;
- pPgidx = &writer.writer.pgidx;
+ if( !bSecureDelete && pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){
+ /* The entire doclist will fit on the current leaf. */
+ fts5BufferSafeAppendBlob(pBuf, pDoclist, nDoclist);
+ }else{
+ int bTermWritten = !bSecureDelete;
+ i64 iRowid = 0;
+ i64 iPrev = 0;
+ int iOff = 0;
+
+ /* The entire doclist will not fit on this leaf. The following
+ ** loop iterates through the poslists that make up the current
+ ** doclist. */
+ while( p->rc==SQLITE_OK && iOff<nDoclist ){
+ u64 iDelta = 0;
+ iOff += fts5GetVarint(&pDoclist[iOff], &iDelta);
+ iRowid += iDelta;
+
+ /* If in secure delete mode, and if this entry in the poslist is
+ ** in fact a delete, then edit the existing segments directly
+ ** using fts5FlushSecureDelete(). */
+ if( bSecureDelete ){
+ if( eDetail==FTS5_DETAIL_NONE ){
+ if( iOff<nDoclist && pDoclist[iOff]==0x00 ){
+ fts5FlushSecureDelete(p, pStruct, zTerm, nTerm, iRowid);
+ iOff++;
+ if( iOff<nDoclist && pDoclist[iOff]==0x00 ){
+ iOff++;
+ nDoclist = 0;
+ }else{
+ continue;
+ }
+ }
+ }else if( (pDoclist[iOff] & 0x01) ){
+ fts5FlushSecureDelete(p, pStruct, zTerm, nTerm, iRowid);
+ if( p->rc!=SQLITE_OK || pDoclist[iOff]==0x01 ){
+ iOff++;
+ continue;
+ }
+ }
+ }
- /* fts5WriteInit() should have initialized the buffers to (most likely)
- ** the maximum space required. */
- assert( p->rc || pBuf->nSpace>=(pgsz + FTS5_DATA_PADDING) );
- assert( p->rc || pPgidx->nSpace>=(pgsz + FTS5_DATA_PADDING) );
+ if( p->rc==SQLITE_OK && bTermWritten==0 ){
+ fts5WriteAppendTerm(p, &writer, nTerm, (const u8*)zTerm);
+ bTermWritten = 1;
+ assert( p->rc!=SQLITE_OK || writer.bFirstRowidInPage==0 );
+ }
- /* Begin scanning through hash table entries. This loop runs once for each
- ** term/doclist currently stored within the hash table. */
- if( p->rc==SQLITE_OK ){
- p->rc = sqlite3Fts5HashScanInit(pHash, 0, 0);
- }
- while( p->rc==SQLITE_OK && 0==sqlite3Fts5HashScanEof(pHash) ){
- const char *zTerm; /* Buffer containing term */
- const u8 *pDoclist; /* Pointer to doclist for this term */
- int nDoclist; /* Size of doclist in bytes */
-
- /* Write the term for this entry to disk. */
- sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist);
- fts5WriteAppendTerm(p, &writer, (int)strlen(zTerm), (const u8*)zTerm);
- if( p->rc!=SQLITE_OK ) break;
-
- assert( writer.bFirstRowidInPage==0 );
- if( pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){
- /* The entire doclist will fit on the current leaf. */
- fts5BufferSafeAppendBlob(pBuf, pDoclist, nDoclist);
- }else{
- i64 iRowid = 0;
- u64 iDelta = 0;
- int iOff = 0;
-
- /* The entire doclist will not fit on this leaf. The following
- ** loop iterates through the poslists that make up the current
- ** doclist. */
- while( p->rc==SQLITE_OK && iOff<nDoclist ){
- iOff += fts5GetVarint(&pDoclist[iOff], &iDelta);
- iRowid += iDelta;
-
- if( writer.bFirstRowidInPage ){
- fts5PutU16(&pBuf->p[0], (u16)pBuf->n); /* first rowid on page */
- pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
- writer.bFirstRowidInPage = 0;
- fts5WriteDlidxAppend(p, &writer, iRowid);
+ if( writer.bFirstRowidInPage ){
+ fts5PutU16(&pBuf->p[0], (u16)pBuf->n); /* first rowid on page */
+ pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
+ writer.bFirstRowidInPage = 0;
+ fts5WriteDlidxAppend(p, &writer, iRowid);
+ }else{
+ u64 iRowidDelta = (u64)iRowid - (u64)iPrev;
+ pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowidDelta);
+ }
if( p->rc!=SQLITE_OK ) break;
- }else{
- pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta);
- }
- assert( pBuf->n<=pBuf->nSpace );
+ assert( pBuf->n<=pBuf->nSpace );
+ iPrev = iRowid;
- if( eDetail==FTS5_DETAIL_NONE ){
- if( iOff<nDoclist && pDoclist[iOff]==0 ){
- pBuf->p[pBuf->n++] = 0;
- iOff++;
+ if( eDetail==FTS5_DETAIL_NONE ){
if( iOff<nDoclist && pDoclist[iOff]==0 ){
pBuf->p[pBuf->n++] = 0;
iOff++;
+ if( iOff<nDoclist && pDoclist[iOff]==0 ){
+ pBuf->p[pBuf->n++] = 0;
+ iOff++;
+ }
+ }
+ if( (pBuf->n + pPgidx->n)>=pgsz ){
+ fts5WriteFlushLeaf(p, &writer);
}
- }
- if( (pBuf->n + pPgidx->n)>=pgsz ){
- fts5WriteFlushLeaf(p, &writer);
- }
- }else{
- int bDummy;
- int nPos;
- int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDummy);
- nCopy += nPos;
- if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){
- /* The entire poslist will fit on the current leaf. So copy
- ** it in one go. */
- fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy);
}else{
- /* The entire poslist will not fit on this leaf. So it needs
- ** to be broken into sections. The only qualification being
- ** that each varint must be stored contiguously. */
- const u8 *pPoslist = &pDoclist[iOff];
- int iPos = 0;
- while( p->rc==SQLITE_OK ){
- int nSpace = pgsz - pBuf->n - pPgidx->n;
- int n = 0;
- if( (nCopy - iPos)<=nSpace ){
- n = nCopy - iPos;
- }else{
- n = fts5PoslistPrefix(&pPoslist[iPos], nSpace);
- }
- assert( n>0 );
- fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n);
- iPos += n;
- if( (pBuf->n + pPgidx->n)>=pgsz ){
- fts5WriteFlushLeaf(p, &writer);
+ int bDel = 0;
+ int nPos = 0;
+ int nCopy = fts5GetPoslistSize(&pDoclist[iOff], &nPos, &bDel);
+ if( bDel && bSecureDelete ){
+ fts5BufferAppendVarint(&p->rc, pBuf, nPos*2);
+ iOff += nCopy;
+ nCopy = nPos;
+ }else{
+ nCopy += nPos;
+ }
+ if( (pBuf->n + pPgidx->n + nCopy) <= pgsz ){
+ /* The entire poslist will fit on the current leaf. So copy
+ ** it in one go. */
+ fts5BufferSafeAppendBlob(pBuf, &pDoclist[iOff], nCopy);
+ }else{
+ /* The entire poslist will not fit on this leaf. So it needs
+ ** to be broken into sections. The only qualification being
+ ** that each varint must be stored contiguously. */
+ const u8 *pPoslist = &pDoclist[iOff];
+ int iPos = 0;
+ while( p->rc==SQLITE_OK ){
+ int nSpace = pgsz - pBuf->n - pPgidx->n;
+ int n = 0;
+ if( (nCopy - iPos)<=nSpace ){
+ n = nCopy - iPos;
+ }else{
+ n = fts5PoslistPrefix(&pPoslist[iPos], nSpace);
+ }
+ assert( n>0 );
+ fts5BufferSafeAppendBlob(pBuf, &pPoslist[iPos], n);
+ iPos += n;
+ if( (pBuf->n + pPgidx->n)>=pgsz ){
+ fts5WriteFlushLeaf(p, &writer);
+ }
+ if( iPos>=nCopy ) break;
}
- if( iPos>=nCopy ) break;
}
+ iOff += nCopy;
}
- iOff += nCopy;
}
}
- }
- /* TODO2: Doclist terminator written here. */
- /* pBuf->p[pBuf->n++] = '\0'; */
- assert( pBuf->n<=pBuf->nSpace );
- if( p->rc==SQLITE_OK ) sqlite3Fts5HashScanNext(pHash);
- }
- sqlite3Fts5HashClear(pHash);
- fts5WriteFinish(p, &writer, &pgnoLast);
+ /* TODO2: Doclist terminator written here. */
+ /* pBuf->p[pBuf->n++] = '\0'; */
+ assert( pBuf->n<=pBuf->nSpace );
+ if( p->rc==SQLITE_OK ) sqlite3Fts5HashScanNext(pHash);
+ }
+ fts5WriteFinish(p, &writer, &pgnoLast);
- /* Update the Fts5Structure. It is written back to the database by the
- ** fts5StructureRelease() call below. */
- if( pStruct->nLevel==0 ){
- fts5StructureAddLevel(&p->rc, &pStruct);
- }
- fts5StructureExtendLevel(&p->rc, pStruct, 0, 1, 0);
- if( p->rc==SQLITE_OK ){
- pSeg = &pStruct->aLevel[0].aSeg[ pStruct->aLevel[0].nSeg++ ];
- pSeg->iSegid = iSegid;
- pSeg->pgnoFirst = 1;
- pSeg->pgnoLast = pgnoLast;
- pStruct->nSegment++;
+ assert( p->rc!=SQLITE_OK || bSecureDelete || pgnoLast>0 );
+ if( pgnoLast>0 ){
+ /* Update the Fts5Structure. It is written back to the database by the
+ ** fts5StructureRelease() call below. */
+ if( pStruct->nLevel==0 ){
+ fts5StructureAddLevel(&p->rc, &pStruct);
+ }
+ fts5StructureExtendLevel(&p->rc, pStruct, 0, 1, 0);
+ if( p->rc==SQLITE_OK ){
+ pSeg = &pStruct->aLevel[0].aSeg[ pStruct->aLevel[0].nSeg++ ];
+ pSeg->iSegid = iSegid;
+ pSeg->pgnoFirst = 1;
+ pSeg->pgnoLast = pgnoLast;
+ if( pStruct->nOriginCntr>0 ){
+ pSeg->iOrigin1 = pStruct->nOriginCntr;
+ pSeg->iOrigin2 = pStruct->nOriginCntr;
+ pSeg->nEntry = p->nPendingRow;
+ pStruct->nOriginCntr++;
+ }
+ pStruct->nSegment++;
+ }
+ fts5StructurePromote(p, 0, pStruct);
+ }
}
- fts5StructurePromote(p, 0, pStruct);
}
- fts5IndexAutomerge(p, &pStruct, pgnoLast);
+ fts5IndexAutomerge(p, &pStruct, pgnoLast + p->nContentlessDelete);
fts5IndexCrisismerge(p, &pStruct);
fts5StructureWrite(p, pStruct);
fts5StructureRelease(pStruct);
@@ -235334,10 +244492,21 @@ static void fts5FlushOneHash(Fts5Index *p){
*/
static void fts5IndexFlush(Fts5Index *p){
/* Unless it is empty, flush the hash table to disk */
- if( p->nPendingData ){
+ if( p->flushRc ){
+ p->rc = p->flushRc;
+ return;
+ }
+ if( p->nPendingData || p->nContentlessDelete ){
assert( p->pHash );
- p->nPendingData = 0;
fts5FlushOneHash(p);
+ if( p->rc==SQLITE_OK ){
+ sqlite3Fts5HashClear(p->pHash);
+ p->nPendingData = 0;
+ p->nPendingRow = 0;
+ p->nContentlessDelete = 0;
+ }else if( p->nPendingData || p->nContentlessDelete ){
+ p->flushRc = p->rc;
+ }
}
}
@@ -235353,17 +244522,22 @@ static Fts5Structure *fts5IndexOptimizeStruct(
/* 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.
+ ** 1. it consists of fewer than two segments, or
+ ** 2. all segments are on the same level, or
+ ** 3. 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.
+ ** In the first case, if there are no tombstone hash pages, 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;
+ if( nSeg==0 ) 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) ){
+ int nMerge = pStruct->aLevel[i].nMerge;
+ if( nThis>0 && (nThis==nSeg || (nThis==nSeg-1 && nMerge==nThis)) ){
+ if( nSeg==1 && nThis==1 && pStruct->aLevel[i].aSeg[0].nPgTombstone==0 ){
+ return 0;
+ }
fts5StructureRef(pStruct);
return pStruct;
}
@@ -235379,6 +244553,7 @@ static Fts5Structure *fts5IndexOptimizeStruct(
pNew->nLevel = MIN(pStruct->nLevel+1, FTS5_MAX_LEVEL);
pNew->nRef = 1;
pNew->nWriteCounter = pStruct->nWriteCounter;
+ pNew->nOriginCntr = pStruct->nOriginCntr;
pLvl = &pNew->aLevel[pNew->nLevel-1];
pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&p->rc, nByte);
if( pLvl->aSeg ){
@@ -235409,7 +244584,9 @@ static int sqlite3Fts5IndexOptimize(Fts5Index *p){
assert( p->rc==SQLITE_OK );
fts5IndexFlush(p);
+ assert( p->rc!=SQLITE_OK || p->nContentlessDelete==0 );
pStruct = fts5StructureRead(p);
+ assert( p->rc!=SQLITE_OK || pStruct!=0 );
fts5StructureInvalidate(p);
if( pStruct ){
@@ -235438,7 +244615,10 @@ static int sqlite3Fts5IndexOptimize(Fts5Index *p){
** INSERT command.
*/
static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
- Fts5Structure *pStruct = fts5StructureRead(p);
+ Fts5Structure *pStruct = 0;
+
+ fts5IndexFlush(p);
+ pStruct = fts5StructureRead(p);
if( pStruct ){
int nMin = p->pConfig->nUsermerge;
fts5StructureInvalidate(p);
@@ -235446,7 +244626,7 @@ static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
Fts5Structure *pNew = fts5IndexOptimizeStruct(p, pStruct);
fts5StructureRelease(pStruct);
pStruct = pNew;
- nMin = 2;
+ nMin = 1;
nMerge = nMerge*-1;
}
if( pStruct && pStruct->nLevel ){
@@ -235812,7 +244992,7 @@ static void fts5SetupPrefixIter(
u8 *pToken, /* Buffer containing prefix to match */
int nToken, /* Size of buffer pToken in bytes */
Fts5Colset *pColset, /* Restrict matches to these columns */
- Fts5Iter **ppIter /* OUT: New iterator */
+ Fts5Iter **ppIter /* OUT: New iterator */
){
Fts5Structure *pStruct;
Fts5Buffer *aBuf;
@@ -235833,8 +245013,9 @@ static void fts5SetupPrefixIter(
aBuf = (Fts5Buffer*)fts5IdxMalloc(p, sizeof(Fts5Buffer)*nBuf);
pStruct = fts5StructureRead(p);
+ assert( p->rc!=SQLITE_OK || (aBuf && pStruct) );
- if( aBuf && pStruct ){
+ if( p->rc==SQLITE_OK ){
const int flags = FTS5INDEX_QUERY_SCAN
| FTS5INDEX_QUERY_SKIPEMPTY
| FTS5INDEX_QUERY_NOOUTPUT;
@@ -235846,6 +245027,12 @@ static void fts5SetupPrefixIter(
int bNewTerm = 1;
memset(&doclist, 0, sizeof(doclist));
+
+ /* If iIdx is non-zero, then it is the number of a prefix-index for
+ ** prefixes 1 character longer than the prefix being queried for. That
+ ** index contains all the doclists required, except for the one
+ ** corresponding to the prefix itself. That one is extracted from the
+ ** main term index here. */
if( iIdx!=0 ){
int dummy = 0;
const int f2 = FTS5INDEX_QUERY_SKIPEMPTY|FTS5INDEX_QUERY_NOOUTPUT;
@@ -235869,6 +245056,7 @@ static void fts5SetupPrefixIter(
pToken[0] = FTS5_MAIN_PREFIX + iIdx;
fts5MultiIterNew(p, pStruct, flags, pColset, pToken, nToken, -1, 0, &p1);
fts5IterSetOutputCb(&p->rc, p1);
+
for( /* no-op */ ;
fts5MultiIterEof(p, p1)==0;
fts5MultiIterNext2(p, p1, &bNewTerm)
@@ -235884,7 +245072,6 @@ static void fts5SetupPrefixIter(
}
if( p1->base.nData==0 ) continue;
-
if( p1->base.iRowid<=iLastRowid && doclist.n>0 ){
for(i=0; p->rc==SQLITE_OK && doclist.n; i++){
int i1 = i*nMerge;
@@ -235923,7 +245110,7 @@ static void fts5SetupPrefixIter(
}
fts5MultiIterFree(p1);
- pData = fts5IdxMalloc(p, sizeof(Fts5Data)+doclist.n+FTS5_DATA_ZERO_PADDING);
+ pData = fts5IdxMalloc(p, sizeof(*pData)+doclist.n+FTS5_DATA_ZERO_PADDING);
if( pData ){
pData->p = (u8*)&pData[1];
pData->nn = pData->szLeaf = doclist.n;
@@ -235960,6 +245147,9 @@ static int sqlite3Fts5IndexBeginWrite(Fts5Index *p, int bDelete, i64 iRowid){
p->iWriteRowid = iRowid;
p->bDelete = bDelete;
+ if( bDelete==0 ){
+ p->nPendingRow++;
+ }
return fts5IndexReturn(p);
}
@@ -235997,6 +245187,9 @@ static int sqlite3Fts5IndexReinit(Fts5Index *p){
fts5StructureInvalidate(p);
fts5IndexDiscardData(p);
memset(&s, 0, sizeof(Fts5Structure));
+ if( p->pConfig->bContentlessDelete ){
+ s.nOriginCntr = 1;
+ }
fts5DataWrite(p, FTS5_AVERAGES_ROWID, (const u8*)"", 0);
fts5StructureWrite(p, &s);
return fts5IndexReturn(p);
@@ -236060,7 +245253,9 @@ static int sqlite3Fts5IndexClose(Fts5Index *p){
sqlite3_finalize(p->pIdxWriter);
sqlite3_finalize(p->pIdxDeleter);
sqlite3_finalize(p->pIdxSelect);
+ sqlite3_finalize(p->pIdxNextSelect);
sqlite3_finalize(p->pDataVersion);
+ sqlite3_finalize(p->pDeleteFromIdx);
sqlite3Fts5HashFree(p->pHash);
sqlite3_free(p->zDataTbl);
sqlite3_free(p);
@@ -236155,6 +245350,457 @@ static int sqlite3Fts5IndexWrite(
}
/*
+** pToken points to a buffer of size nToken bytes containing a search
+** term, including the index number at the start, used on a tokendata=1
+** table. This function returns true if the term in buffer pBuf matches
+** token pToken/nToken.
+*/
+static int fts5IsTokendataPrefix(
+ Fts5Buffer *pBuf,
+ const u8 *pToken,
+ int nToken
+){
+ return (
+ pBuf->n>=nToken
+ && 0==memcmp(pBuf->p, pToken, nToken)
+ && (pBuf->n==nToken || pBuf->p[nToken]==0x00)
+ );
+}
+
+/*
+** Ensure the segment-iterator passed as the only argument points to EOF.
+*/
+static void fts5SegIterSetEOF(Fts5SegIter *pSeg){
+ fts5DataRelease(pSeg->pLeaf);
+ pSeg->pLeaf = 0;
+}
+
+/*
+** Usually, a tokendata=1 iterator (struct Fts5TokenDataIter) accumulates an
+** array of these for each row it visits. Or, for an iterator used by an
+** "ORDER BY rank" query, it accumulates an array of these for the entire
+** query.
+**
+** Each instance in the array indicates the iterator (and therefore term)
+** associated with position iPos of rowid iRowid. This is used by the
+** xInstToken() API.
+*/
+struct Fts5TokenDataMap {
+ i64 iRowid; /* Row this token is located in */
+ i64 iPos; /* Position of token */
+ int iIter; /* Iterator token was read from */
+};
+
+/*
+** An object used to supplement Fts5Iter for tokendata=1 iterators.
+*/
+struct Fts5TokenDataIter {
+ int nIter;
+ int nIterAlloc;
+
+ int nMap;
+ int nMapAlloc;
+ Fts5TokenDataMap *aMap;
+
+ Fts5PoslistReader *aPoslistReader;
+ int *aPoslistToIter;
+ Fts5Iter *apIter[1];
+};
+
+/*
+** This function appends iterator pAppend to Fts5TokenDataIter pIn and
+** returns the result.
+*/
+static Fts5TokenDataIter *fts5AppendTokendataIter(
+ Fts5Index *p, /* Index object (for error code) */
+ Fts5TokenDataIter *pIn, /* Current Fts5TokenDataIter struct */
+ Fts5Iter *pAppend /* Append this iterator */
+){
+ Fts5TokenDataIter *pRet = pIn;
+
+ if( p->rc==SQLITE_OK ){
+ if( pIn==0 || pIn->nIter==pIn->nIterAlloc ){
+ int nAlloc = pIn ? pIn->nIterAlloc*2 : 16;
+ int nByte = nAlloc * sizeof(Fts5Iter*) + sizeof(Fts5TokenDataIter);
+ Fts5TokenDataIter *pNew = (Fts5TokenDataIter*)sqlite3_realloc(pIn, nByte);
+
+ if( pNew==0 ){
+ p->rc = SQLITE_NOMEM;
+ }else{
+ if( pIn==0 ) memset(pNew, 0, nByte);
+ pRet = pNew;
+ pNew->nIterAlloc = nAlloc;
+ }
+ }
+ }
+ if( p->rc ){
+ sqlite3Fts5IterClose((Fts5IndexIter*)pAppend);
+ }else{
+ pRet->apIter[pRet->nIter++] = pAppend;
+ }
+ assert( pRet==0 || pRet->nIter<=pRet->nIterAlloc );
+
+ return pRet;
+}
+
+/*
+** Delete an Fts5TokenDataIter structure and its contents.
+*/
+static void fts5TokendataIterDelete(Fts5TokenDataIter *pSet){
+ if( pSet ){
+ int ii;
+ for(ii=0; ii<pSet->nIter; ii++){
+ fts5MultiIterFree(pSet->apIter[ii]);
+ }
+ sqlite3_free(pSet->aPoslistReader);
+ sqlite3_free(pSet->aMap);
+ sqlite3_free(pSet);
+ }
+}
+
+/*
+** Append a mapping to the token-map belonging to object pT.
+*/
+static void fts5TokendataIterAppendMap(
+ Fts5Index *p,
+ Fts5TokenDataIter *pT,
+ int iIter,
+ i64 iRowid,
+ i64 iPos
+){
+ if( p->rc==SQLITE_OK ){
+ if( pT->nMap==pT->nMapAlloc ){
+ int nNew = pT->nMapAlloc ? pT->nMapAlloc*2 : 64;
+ int nByte = nNew * sizeof(Fts5TokenDataMap);
+ Fts5TokenDataMap *aNew;
+
+ aNew = (Fts5TokenDataMap*)sqlite3_realloc(pT->aMap, nByte);
+ if( aNew==0 ){
+ p->rc = SQLITE_NOMEM;
+ return;
+ }
+
+ pT->aMap = aNew;
+ pT->nMapAlloc = nNew;
+ }
+
+ pT->aMap[pT->nMap].iRowid = iRowid;
+ pT->aMap[pT->nMap].iPos = iPos;
+ pT->aMap[pT->nMap].iIter = iIter;
+ pT->nMap++;
+ }
+}
+
+/*
+** The iterator passed as the only argument must be a tokendata=1 iterator
+** (pIter->pTokenDataIter!=0). This function sets the iterator output
+** variables (pIter->base.*) according to the contents of the current
+** row.
+*/
+static void fts5IterSetOutputsTokendata(Fts5Iter *pIter){
+ int ii;
+ int nHit = 0;
+ i64 iRowid = SMALLEST_INT64;
+ int iMin = 0;
+
+ Fts5TokenDataIter *pT = pIter->pTokenDataIter;
+
+ pIter->base.nData = 0;
+ pIter->base.pData = 0;
+
+ for(ii=0; ii<pT->nIter; ii++){
+ Fts5Iter *p = pT->apIter[ii];
+ if( p->base.bEof==0 ){
+ if( nHit==0 || p->base.iRowid<iRowid ){
+ iRowid = p->base.iRowid;
+ nHit = 1;
+ pIter->base.pData = p->base.pData;
+ pIter->base.nData = p->base.nData;
+ iMin = ii;
+ }else if( p->base.iRowid==iRowid ){
+ nHit++;
+ }
+ }
+ }
+
+ if( nHit==0 ){
+ pIter->base.bEof = 1;
+ }else{
+ int eDetail = pIter->pIndex->pConfig->eDetail;
+ pIter->base.bEof = 0;
+ pIter->base.iRowid = iRowid;
+
+ if( nHit==1 && eDetail==FTS5_DETAIL_FULL ){
+ fts5TokendataIterAppendMap(pIter->pIndex, pT, iMin, iRowid, -1);
+ }else
+ if( nHit>1 && eDetail!=FTS5_DETAIL_NONE ){
+ int nReader = 0;
+ int nByte = 0;
+ i64 iPrev = 0;
+
+ /* Allocate array of iterators if they are not already allocated. */
+ if( pT->aPoslistReader==0 ){
+ pT->aPoslistReader = (Fts5PoslistReader*)sqlite3Fts5MallocZero(
+ &pIter->pIndex->rc,
+ pT->nIter * (sizeof(Fts5PoslistReader) + sizeof(int))
+ );
+ if( pT->aPoslistReader==0 ) return;
+ pT->aPoslistToIter = (int*)&pT->aPoslistReader[pT->nIter];
+ }
+
+ /* Populate an iterator for each poslist that will be merged */
+ for(ii=0; ii<pT->nIter; ii++){
+ Fts5Iter *p = pT->apIter[ii];
+ if( iRowid==p->base.iRowid ){
+ pT->aPoslistToIter[nReader] = ii;
+ sqlite3Fts5PoslistReaderInit(
+ p->base.pData, p->base.nData, &pT->aPoslistReader[nReader++]
+ );
+ nByte += p->base.nData;
+ }
+ }
+
+ /* Ensure the output buffer is large enough */
+ if( fts5BufferGrow(&pIter->pIndex->rc, &pIter->poslist, nByte+nHit*10) ){
+ return;
+ }
+
+ /* Ensure the token-mapping is large enough */
+ if( eDetail==FTS5_DETAIL_FULL && pT->nMapAlloc<(pT->nMap + nByte) ){
+ int nNew = (pT->nMapAlloc + nByte) * 2;
+ Fts5TokenDataMap *aNew = (Fts5TokenDataMap*)sqlite3_realloc(
+ pT->aMap, nNew*sizeof(Fts5TokenDataMap)
+ );
+ if( aNew==0 ){
+ pIter->pIndex->rc = SQLITE_NOMEM;
+ return;
+ }
+ pT->aMap = aNew;
+ pT->nMapAlloc = nNew;
+ }
+
+ pIter->poslist.n = 0;
+
+ while( 1 ){
+ i64 iMinPos = LARGEST_INT64;
+
+ /* Find smallest position */
+ iMin = 0;
+ for(ii=0; ii<nReader; ii++){
+ Fts5PoslistReader *pReader = &pT->aPoslistReader[ii];
+ if( pReader->bEof==0 ){
+ if( pReader->iPos<iMinPos ){
+ iMinPos = pReader->iPos;
+ iMin = ii;
+ }
+ }
+ }
+
+ /* If all readers were at EOF, break out of the loop. */
+ if( iMinPos==LARGEST_INT64 ) break;
+
+ sqlite3Fts5PoslistSafeAppend(&pIter->poslist, &iPrev, iMinPos);
+ sqlite3Fts5PoslistReaderNext(&pT->aPoslistReader[iMin]);
+
+ if( eDetail==FTS5_DETAIL_FULL ){
+ pT->aMap[pT->nMap].iPos = iMinPos;
+ pT->aMap[pT->nMap].iIter = pT->aPoslistToIter[iMin];
+ pT->aMap[pT->nMap].iRowid = iRowid;
+ pT->nMap++;
+ }
+ }
+
+ pIter->base.pData = pIter->poslist.p;
+ pIter->base.nData = pIter->poslist.n;
+ }
+ }
+}
+
+/*
+** The iterator passed as the only argument must be a tokendata=1 iterator
+** (pIter->pTokenDataIter!=0). This function advances the iterator. If
+** argument bFrom is false, then the iterator is advanced to the next
+** entry. Or, if bFrom is true, it is advanced to the first entry with
+** a rowid of iFrom or greater.
+*/
+static void fts5TokendataIterNext(Fts5Iter *pIter, int bFrom, i64 iFrom){
+ int ii;
+ Fts5TokenDataIter *pT = pIter->pTokenDataIter;
+ Fts5Index *pIndex = pIter->pIndex;
+
+ for(ii=0; ii<pT->nIter; ii++){
+ Fts5Iter *p = pT->apIter[ii];
+ if( p->base.bEof==0
+ && (p->base.iRowid==pIter->base.iRowid || (bFrom && p->base.iRowid<iFrom))
+ ){
+ fts5MultiIterNext(pIndex, p, bFrom, iFrom);
+ while( bFrom && p->base.bEof==0
+ && p->base.iRowid<iFrom
+ && pIndex->rc==SQLITE_OK
+ ){
+ fts5MultiIterNext(pIndex, p, 0, 0);
+ }
+ }
+ }
+
+ if( pIndex->rc==SQLITE_OK ){
+ fts5IterSetOutputsTokendata(pIter);
+ }
+}
+
+/*
+** If the segment-iterator passed as the first argument is at EOF, then
+** set pIter->term to a copy of buffer pTerm.
+*/
+static void fts5TokendataSetTermIfEof(Fts5Iter *pIter, Fts5Buffer *pTerm){
+ if( pIter && pIter->aSeg[0].pLeaf==0 ){
+ fts5BufferSet(&pIter->pIndex->rc, &pIter->aSeg[0].term, pTerm->n, pTerm->p);
+ }
+}
+
+/*
+** This function sets up an iterator to use for a non-prefix query on a
+** tokendata=1 table.
+*/
+static Fts5Iter *fts5SetupTokendataIter(
+ Fts5Index *p, /* FTS index to query */
+ const u8 *pToken, /* Buffer containing query term */
+ int nToken, /* Size of buffer pToken in bytes */
+ Fts5Colset *pColset /* Colset to filter on */
+){
+ Fts5Iter *pRet = 0;
+ Fts5TokenDataIter *pSet = 0;
+ Fts5Structure *pStruct = 0;
+ const int flags = FTS5INDEX_QUERY_SCANONETERM | FTS5INDEX_QUERY_SCAN;
+
+ Fts5Buffer bSeek = {0, 0, 0};
+ Fts5Buffer *pSmall = 0;
+
+ fts5IndexFlush(p);
+ pStruct = fts5StructureRead(p);
+
+ while( p->rc==SQLITE_OK ){
+ Fts5Iter *pPrev = pSet ? pSet->apIter[pSet->nIter-1] : 0;
+ Fts5Iter *pNew = 0;
+ Fts5SegIter *pNewIter = 0;
+ Fts5SegIter *pPrevIter = 0;
+
+ int iLvl, iSeg, ii;
+
+ pNew = fts5MultiIterAlloc(p, pStruct->nSegment);
+ if( pSmall ){
+ fts5BufferSet(&p->rc, &bSeek, pSmall->n, pSmall->p);
+ fts5BufferAppendBlob(&p->rc, &bSeek, 1, (const u8*)"\0");
+ }else{
+ fts5BufferSet(&p->rc, &bSeek, nToken, pToken);
+ }
+ if( p->rc ){
+ sqlite3Fts5IterClose((Fts5IndexIter*)pNew);
+ break;
+ }
+
+ pNewIter = &pNew->aSeg[0];
+ pPrevIter = (pPrev ? &pPrev->aSeg[0] : 0);
+ for(iLvl=0; iLvl<pStruct->nLevel; iLvl++){
+ for(iSeg=pStruct->aLevel[iLvl].nSeg-1; iSeg>=0; iSeg--){
+ Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg];
+ int bDone = 0;
+
+ if( pPrevIter ){
+ if( fts5BufferCompare(pSmall, &pPrevIter->term) ){
+ memcpy(pNewIter, pPrevIter, sizeof(Fts5SegIter));
+ memset(pPrevIter, 0, sizeof(Fts5SegIter));
+ bDone = 1;
+ }else if( pPrevIter->iEndofDoclist>pPrevIter->pLeaf->szLeaf ){
+ fts5SegIterNextInit(p,(const char*)bSeek.p,bSeek.n-1,pSeg,pNewIter);
+ bDone = 1;
+ }
+ }
+
+ if( bDone==0 ){
+ fts5SegIterSeekInit(p, bSeek.p, bSeek.n, flags, pSeg, pNewIter);
+ }
+
+ if( pPrevIter ){
+ if( pPrevIter->pTombArray ){
+ pNewIter->pTombArray = pPrevIter->pTombArray;
+ pNewIter->pTombArray->nRef++;
+ }
+ }else{
+ fts5SegIterAllocTombstone(p, pNewIter);
+ }
+
+ pNewIter++;
+ if( pPrevIter ) pPrevIter++;
+ if( p->rc ) break;
+ }
+ }
+ fts5TokendataSetTermIfEof(pPrev, pSmall);
+
+ pNew->bSkipEmpty = 1;
+ pNew->pColset = pColset;
+ fts5IterSetOutputCb(&p->rc, pNew);
+
+ /* Loop through all segments in the new iterator. Find the smallest
+ ** term that any segment-iterator points to. Iterator pNew will be
+ ** used for this term. Also, set any iterator that points to a term that
+ ** does not match pToken/nToken to point to EOF */
+ pSmall = 0;
+ for(ii=0; ii<pNew->nSeg; ii++){
+ Fts5SegIter *pII = &pNew->aSeg[ii];
+ if( 0==fts5IsTokendataPrefix(&pII->term, pToken, nToken) ){
+ fts5SegIterSetEOF(pII);
+ }
+ if( pII->pLeaf && (!pSmall || fts5BufferCompare(pSmall, &pII->term)>0) ){
+ pSmall = &pII->term;
+ }
+ }
+
+ /* If pSmall is still NULL at this point, then the new iterator does
+ ** not point to any terms that match the query. So delete it and break
+ ** out of the loop - all required iterators have been collected. */
+ if( pSmall==0 ){
+ sqlite3Fts5IterClose((Fts5IndexIter*)pNew);
+ break;
+ }
+
+ /* Append this iterator to the set and continue. */
+ pSet = fts5AppendTokendataIter(p, pSet, pNew);
+ }
+
+ if( p->rc==SQLITE_OK && pSet ){
+ int ii;
+ for(ii=0; ii<pSet->nIter; ii++){
+ Fts5Iter *pIter = pSet->apIter[ii];
+ int iSeg;
+ for(iSeg=0; iSeg<pIter->nSeg; iSeg++){
+ pIter->aSeg[iSeg].flags |= FTS5_SEGITER_ONETERM;
+ }
+ fts5MultiIterFinishSetup(p, pIter);
+ }
+ }
+
+ if( p->rc==SQLITE_OK ){
+ pRet = fts5MultiIterAlloc(p, 0);
+ }
+ if( pRet ){
+ pRet->pTokenDataIter = pSet;
+ if( pSet ){
+ fts5IterSetOutputsTokendata(pRet);
+ }else{
+ pRet->base.bEof = 1;
+ }
+ }else{
+ fts5TokendataIterDelete(pSet);
+ }
+
+ fts5StructureRelease(pStruct);
+ fts5BufferFree(&bSeek);
+ return pRet;
+}
+
+
+/*
** Open a new iterator to iterate though all rowid that match the
** specified token or token prefix.
*/
@@ -236175,8 +245821,13 @@ static int sqlite3Fts5IndexQuery(
if( sqlite3Fts5BufferSize(&p->rc, &buf, nToken+1)==0 ){
int iIdx = 0; /* Index to search */
int iPrefixIdx = 0; /* +1 prefix index */
+ int bTokendata = pConfig->bTokendata;
if( nToken>0 ) memcpy(&buf.p[1], pToken, nToken);
+ if( flags & (FTS5INDEX_QUERY_NOTOKENDATA|FTS5INDEX_QUERY_SCAN) ){
+ bTokendata = 0;
+ }
+
/* Figure out which index to search and set iIdx accordingly. If this
** is a prefix query for which there is no prefix index, set iIdx to
** greater than pConfig->nPrefix to indicate that the query will be
@@ -236202,7 +245853,10 @@ static int sqlite3Fts5IndexQuery(
}
}
- if( iIdx<=pConfig->nPrefix ){
+ if( bTokendata && iIdx==0 ){
+ buf.p[0] = '0';
+ pRet = fts5SetupTokendataIter(p, buf.p, nToken+1, pColset);
+ }else if( iIdx<=pConfig->nPrefix ){
/* Straight index lookup */
Fts5Structure *pStruct = fts5StructureRead(p);
buf.p[0] = (u8)(FTS5_MAIN_PREFIX + iIdx);
@@ -236249,7 +245903,11 @@ static int sqlite3Fts5IndexQuery(
static int sqlite3Fts5IterNext(Fts5IndexIter *pIndexIter){
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
assert( pIter->pIndex->rc==SQLITE_OK );
- fts5MultiIterNext(pIter->pIndex, pIter, 0, 0);
+ if( pIter->pTokenDataIter ){
+ fts5TokendataIterNext(pIter, 0, 0);
+ }else{
+ fts5MultiIterNext(pIter->pIndex, pIter, 0, 0);
+ }
return fts5IndexReturn(pIter->pIndex);
}
@@ -236282,7 +245940,11 @@ static int sqlite3Fts5IterNextScan(Fts5IndexIter *pIndexIter){
*/
static int sqlite3Fts5IterNextFrom(Fts5IndexIter *pIndexIter, i64 iMatch){
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
- fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch);
+ if( pIter->pTokenDataIter ){
+ fts5TokendataIterNext(pIter, 1, iMatch);
+ }else{
+ fts5MultiIterNextFrom(pIter->pIndex, pIter, iMatch);
+ }
return fts5IndexReturn(pIter->pIndex);
}
@@ -236298,12 +245960,106 @@ static const char *sqlite3Fts5IterTerm(Fts5IndexIter *pIndexIter, int *pn){
}
/*
+** This is used by xInstToken() to access the token at offset iOff, column
+** iCol of row iRowid. The token is returned via output variables *ppOut
+** and *pnOut. The iterator passed as the first argument must be a tokendata=1
+** iterator (pIter->pTokenDataIter!=0).
+*/
+static int sqlite3Fts5IterToken(
+ Fts5IndexIter *pIndexIter,
+ i64 iRowid,
+ int iCol,
+ int iOff,
+ const char **ppOut, int *pnOut
+){
+ Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
+ Fts5TokenDataIter *pT = pIter->pTokenDataIter;
+ Fts5TokenDataMap *aMap = pT->aMap;
+ i64 iPos = (((i64)iCol)<<32) + iOff;
+
+ int i1 = 0;
+ int i2 = pT->nMap;
+ int iTest = 0;
+
+ while( i2>i1 ){
+ iTest = (i1 + i2) / 2;
+
+ if( aMap[iTest].iRowid<iRowid ){
+ i1 = iTest+1;
+ }else if( aMap[iTest].iRowid>iRowid ){
+ i2 = iTest;
+ }else{
+ if( aMap[iTest].iPos<iPos ){
+ if( aMap[iTest].iPos<0 ){
+ break;
+ }
+ i1 = iTest+1;
+ }else if( aMap[iTest].iPos>iPos ){
+ i2 = iTest;
+ }else{
+ break;
+ }
+ }
+ }
+
+ if( i2>i1 ){
+ Fts5Iter *pMap = pT->apIter[aMap[iTest].iIter];
+ *ppOut = (const char*)pMap->aSeg[0].term.p+1;
+ *pnOut = pMap->aSeg[0].term.n-1;
+ }
+
+ return SQLITE_OK;
+}
+
+/*
+** Clear any existing entries from the token-map associated with the
+** iterator passed as the only argument.
+*/
+static void sqlite3Fts5IndexIterClearTokendata(Fts5IndexIter *pIndexIter){
+ Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
+ if( pIter && pIter->pTokenDataIter ){
+ pIter->pTokenDataIter->nMap = 0;
+ }
+}
+
+/*
+** Set a token-mapping for the iterator passed as the first argument. This
+** is used in detail=column or detail=none mode when a token is requested
+** using the xInstToken() API. In this case the caller tokenizers the
+** current row and configures the token-mapping via multiple calls to this
+** function.
+*/
+static int sqlite3Fts5IndexIterWriteTokendata(
+ Fts5IndexIter *pIndexIter,
+ const char *pToken, int nToken,
+ i64 iRowid, int iCol, int iOff
+){
+ Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
+ Fts5TokenDataIter *pT = pIter->pTokenDataIter;
+ Fts5Index *p = pIter->pIndex;
+ int ii;
+
+ assert( p->pConfig->eDetail!=FTS5_DETAIL_FULL );
+ assert( pIter->pTokenDataIter );
+
+ for(ii=0; ii<pT->nIter; ii++){
+ Fts5Buffer *pTerm = &pT->apIter[ii]->aSeg[0].term;
+ if( nToken==pTerm->n-1 && memcmp(pToken, pTerm->p+1, nToken)==0 ) break;
+ }
+ if( ii<pT->nIter ){
+ fts5TokendataIterAppendMap(p, pT, ii, iRowid, (((i64)iCol)<<32) + iOff);
+ }
+ return fts5IndexReturn(p);
+}
+
+/*
** Close an iterator opened by an earlier call to sqlite3Fts5IndexQuery().
*/
static void sqlite3Fts5IterClose(Fts5IndexIter *pIndexIter){
if( pIndexIter ){
Fts5Iter *pIter = (Fts5Iter*)pIndexIter;
Fts5Index *pIndex = pIter->pIndex;
+ fts5TokendataIterDelete(pIter->pTokenDataIter);
fts5MultiIterFree(pIter);
sqlite3Fts5IndexCloseReader(pIndex);
}
@@ -236387,6 +246143,347 @@ static int sqlite3Fts5IndexLoadConfig(Fts5Index *p){
return fts5IndexReturn(p);
}
+/*
+** Retrieve the origin value that will be used for the segment currently
+** being accumulated in the in-memory hash table when it is flushed to
+** disk. If successful, SQLITE_OK is returned and (*piOrigin) set to
+** the queried value. Or, if an error occurs, an error code is returned
+** and the final value of (*piOrigin) is undefined.
+*/
+static int sqlite3Fts5IndexGetOrigin(Fts5Index *p, i64 *piOrigin){
+ Fts5Structure *pStruct;
+ pStruct = fts5StructureRead(p);
+ if( pStruct ){
+ *piOrigin = pStruct->nOriginCntr;
+ fts5StructureRelease(pStruct);
+ }
+ return fts5IndexReturn(p);
+}
+
+/*
+** Buffer pPg contains a page of a tombstone hash table - one of nPg pages
+** associated with the same segment. This function adds rowid iRowid to
+** the hash table. The caller is required to guarantee that there is at
+** least one free slot on the page.
+**
+** If parameter bForce is false and the hash table is deemed to be full
+** (more than half of the slots are occupied), then non-zero is returned
+** and iRowid not inserted. Or, if bForce is true or if the hash table page
+** is not full, iRowid is inserted and zero returned.
+*/
+static int fts5IndexTombstoneAddToPage(
+ Fts5Data *pPg,
+ int bForce,
+ int nPg,
+ u64 iRowid
+){
+ const int szKey = TOMBSTONE_KEYSIZE(pPg);
+ const int nSlot = TOMBSTONE_NSLOT(pPg);
+ const int nElem = fts5GetU32(&pPg->p[4]);
+ int iSlot = (iRowid / nPg) % nSlot;
+ int nCollide = nSlot;
+
+ if( szKey==4 && iRowid>0xFFFFFFFF ) return 2;
+ if( iRowid==0 ){
+ pPg->p[1] = 0x01;
+ return 0;
+ }
+
+ if( bForce==0 && nElem>=(nSlot/2) ){
+ return 1;
+ }
+
+ fts5PutU32(&pPg->p[4], nElem+1);
+ if( szKey==4 ){
+ u32 *aSlot = (u32*)&pPg->p[8];
+ while( aSlot[iSlot] ){
+ iSlot = (iSlot + 1) % nSlot;
+ if( nCollide--==0 ) return 0;
+ }
+ fts5PutU32((u8*)&aSlot[iSlot], (u32)iRowid);
+ }else{
+ u64 *aSlot = (u64*)&pPg->p[8];
+ while( aSlot[iSlot] ){
+ iSlot = (iSlot + 1) % nSlot;
+ if( nCollide--==0 ) return 0;
+ }
+ fts5PutU64((u8*)&aSlot[iSlot], iRowid);
+ }
+
+ return 0;
+}
+
+/*
+** This function attempts to build a new hash containing all the keys
+** currently in the tombstone hash table for segment pSeg. The new
+** hash will be stored in the nOut buffers passed in array apOut[].
+** All pages of the new hash use key-size szKey (4 or 8).
+**
+** Return 0 if the hash is successfully rebuilt into the nOut pages.
+** Or non-zero if it is not (because one page became overfull). In this
+** case the caller should retry with a larger nOut parameter.
+**
+** Parameter pData1 is page iPg1 of the hash table being rebuilt.
+*/
+static int fts5IndexTombstoneRehash(
+ Fts5Index *p,
+ Fts5StructureSegment *pSeg, /* Segment to rebuild hash of */
+ Fts5Data *pData1, /* One page of current hash - or NULL */
+ int iPg1, /* Which page of the current hash is pData1 */
+ int szKey, /* 4 or 8, the keysize */
+ int nOut, /* Number of output pages */
+ Fts5Data **apOut /* Array of output hash pages */
+){
+ int ii;
+ int res = 0;
+
+ /* Initialize the headers of all the output pages */
+ for(ii=0; ii<nOut; ii++){
+ apOut[ii]->p[0] = szKey;
+ fts5PutU32(&apOut[ii]->p[4], 0);
+ }
+
+ /* Loop through the current pages of the hash table. */
+ for(ii=0; res==0 && ii<pSeg->nPgTombstone; ii++){
+ Fts5Data *pData = 0; /* Page ii of the current hash table */
+ Fts5Data *pFree = 0; /* Free this at the end of the loop */
+
+ if( iPg1==ii ){
+ pData = pData1;
+ }else{
+ pFree = pData = fts5DataRead(p, FTS5_TOMBSTONE_ROWID(pSeg->iSegid, ii));
+ }
+
+ if( pData ){
+ int szKeyIn = TOMBSTONE_KEYSIZE(pData);
+ int nSlotIn = (pData->nn - 8) / szKeyIn;
+ int iIn;
+ for(iIn=0; iIn<nSlotIn; iIn++){
+ u64 iVal = 0;
+
+ /* Read the value from slot iIn of the input page into iVal. */
+ if( szKeyIn==4 ){
+ u32 *aSlot = (u32*)&pData->p[8];
+ if( aSlot[iIn] ) iVal = fts5GetU32((u8*)&aSlot[iIn]);
+ }else{
+ u64 *aSlot = (u64*)&pData->p[8];
+ if( aSlot[iIn] ) iVal = fts5GetU64((u8*)&aSlot[iIn]);
+ }
+
+ /* If iVal is not 0 at this point, insert it into the new hash table */
+ if( iVal ){
+ Fts5Data *pPg = apOut[(iVal % nOut)];
+ res = fts5IndexTombstoneAddToPage(pPg, 0, nOut, iVal);
+ if( res ) break;
+ }
+ }
+
+ /* If this is page 0 of the old hash, copy the rowid-0-flag from the
+ ** old hash to the new. */
+ if( ii==0 ){
+ apOut[0]->p[1] = pData->p[1];
+ }
+ }
+ fts5DataRelease(pFree);
+ }
+
+ return res;
+}
+
+/*
+** This is called to rebuild the hash table belonging to segment pSeg.
+** If parameter pData1 is not NULL, then one page of the existing hash table
+** has already been loaded - pData1, which is page iPg1. The key-size for
+** the new hash table is szKey (4 or 8).
+**
+** If successful, the new hash table is not written to disk. Instead,
+** output parameter (*pnOut) is set to the number of pages in the new
+** hash table, and (*papOut) to point to an array of buffers containing
+** the new page data.
+**
+** If an error occurs, an error code is left in the Fts5Index object and
+** both output parameters set to 0 before returning.
+*/
+static void fts5IndexTombstoneRebuild(
+ Fts5Index *p,
+ Fts5StructureSegment *pSeg, /* Segment to rebuild hash of */
+ Fts5Data *pData1, /* One page of current hash - or NULL */
+ int iPg1, /* Which page of the current hash is pData1 */
+ int szKey, /* 4 or 8, the keysize */
+ int *pnOut, /* OUT: Number of output pages */
+ Fts5Data ***papOut /* OUT: Output hash pages */
+){
+ const int MINSLOT = 32;
+ int nSlotPerPage = MAX(MINSLOT, (p->pConfig->pgsz - 8) / szKey);
+ int nSlot = 0; /* Number of slots in each output page */
+ int nOut = 0;
+
+ /* Figure out how many output pages (nOut) and how many slots per
+ ** page (nSlot). There are three possibilities:
+ **
+ ** 1. The hash table does not yet exist. In this case the new hash
+ ** table will consist of a single page with MINSLOT slots.
+ **
+ ** 2. The hash table exists but is currently a single page. In this
+ ** case an attempt is made to grow the page to accommodate the new
+ ** entry. The page is allowed to grow up to nSlotPerPage (see above)
+ ** slots.
+ **
+ ** 3. The hash table already consists of more than one page, or of
+ ** a single page already so large that it cannot be grown. In this
+ ** case the new hash consists of (nPg*2+1) pages of nSlotPerPage
+ ** slots each, where nPg is the current number of pages in the
+ ** hash table.
+ */
+ if( pSeg->nPgTombstone==0 ){
+ /* Case 1. */
+ nOut = 1;
+ nSlot = MINSLOT;
+ }else if( pSeg->nPgTombstone==1 ){
+ /* Case 2. */
+ int nElem = (int)fts5GetU32(&pData1->p[4]);
+ assert( pData1 && iPg1==0 );
+ nOut = 1;
+ nSlot = MAX(nElem*4, MINSLOT);
+ if( nSlot>nSlotPerPage ) nOut = 0;
+ }
+ if( nOut==0 ){
+ /* Case 3. */
+ nOut = (pSeg->nPgTombstone * 2 + 1);
+ nSlot = nSlotPerPage;
+ }
+
+ /* Allocate the required array and output pages */
+ while( 1 ){
+ int res = 0;
+ int ii = 0;
+ int szPage = 0;
+ Fts5Data **apOut = 0;
+
+ /* Allocate space for the new hash table */
+ assert( nSlot>=MINSLOT );
+ apOut = (Fts5Data**)sqlite3Fts5MallocZero(&p->rc, sizeof(Fts5Data*) * nOut);
+ szPage = 8 + nSlot*szKey;
+ for(ii=0; ii<nOut; ii++){
+ Fts5Data *pNew = (Fts5Data*)sqlite3Fts5MallocZero(&p->rc,
+ sizeof(Fts5Data)+szPage
+ );
+ if( pNew ){
+ pNew->nn = szPage;
+ pNew->p = (u8*)&pNew[1];
+ apOut[ii] = pNew;
+ }
+ }
+
+ /* Rebuild the hash table. */
+ if( p->rc==SQLITE_OK ){
+ res = fts5IndexTombstoneRehash(p, pSeg, pData1, iPg1, szKey, nOut, apOut);
+ }
+ if( res==0 ){
+ if( p->rc ){
+ fts5IndexFreeArray(apOut, nOut);
+ apOut = 0;
+ nOut = 0;
+ }
+ *pnOut = nOut;
+ *papOut = apOut;
+ break;
+ }
+
+ /* If control flows to here, it was not possible to rebuild the hash
+ ** table. Free all buffers and then try again with more pages. */
+ assert( p->rc==SQLITE_OK );
+ fts5IndexFreeArray(apOut, nOut);
+ nSlot = nSlotPerPage;
+ nOut = nOut*2 + 1;
+ }
+}
+
+
+/*
+** Add a tombstone for rowid iRowid to segment pSeg.
+*/
+static void fts5IndexTombstoneAdd(
+ Fts5Index *p,
+ Fts5StructureSegment *pSeg,
+ u64 iRowid
+){
+ Fts5Data *pPg = 0;
+ int iPg = -1;
+ int szKey = 0;
+ int nHash = 0;
+ Fts5Data **apHash = 0;
+
+ p->nContentlessDelete++;
+
+ if( pSeg->nPgTombstone>0 ){
+ iPg = iRowid % pSeg->nPgTombstone;
+ pPg = fts5DataRead(p, FTS5_TOMBSTONE_ROWID(pSeg->iSegid,iPg));
+ if( pPg==0 ){
+ assert( p->rc!=SQLITE_OK );
+ return;
+ }
+
+ if( 0==fts5IndexTombstoneAddToPage(pPg, 0, pSeg->nPgTombstone, iRowid) ){
+ fts5DataWrite(p, FTS5_TOMBSTONE_ROWID(pSeg->iSegid,iPg), pPg->p, pPg->nn);
+ fts5DataRelease(pPg);
+ return;
+ }
+ }
+
+ /* Have to rebuild the hash table. First figure out the key-size (4 or 8). */
+ szKey = pPg ? TOMBSTONE_KEYSIZE(pPg) : 4;
+ if( iRowid>0xFFFFFFFF ) szKey = 8;
+
+ /* Rebuild the hash table */
+ fts5IndexTombstoneRebuild(p, pSeg, pPg, iPg, szKey, &nHash, &apHash);
+ assert( p->rc==SQLITE_OK || (nHash==0 && apHash==0) );
+
+ /* If all has succeeded, write the new rowid into one of the new hash
+ ** table pages, then write them all out to disk. */
+ if( nHash ){
+ int ii = 0;
+ fts5IndexTombstoneAddToPage(apHash[iRowid % nHash], 1, nHash, iRowid);
+ for(ii=0; ii<nHash; ii++){
+ i64 iTombstoneRowid = FTS5_TOMBSTONE_ROWID(pSeg->iSegid, ii);
+ fts5DataWrite(p, iTombstoneRowid, apHash[ii]->p, apHash[ii]->nn);
+ }
+ pSeg->nPgTombstone = nHash;
+ fts5StructureWrite(p, p->pStruct);
+ }
+
+ fts5DataRelease(pPg);
+ fts5IndexFreeArray(apHash, nHash);
+}
+
+/*
+** Add iRowid to the tombstone list of the segment or segments that contain
+** rows from origin iOrigin. Return SQLITE_OK if successful, or an SQLite
+** error code otherwise.
+*/
+static int sqlite3Fts5IndexContentlessDelete(Fts5Index *p, i64 iOrigin, i64 iRowid){
+ Fts5Structure *pStruct;
+ pStruct = fts5StructureRead(p);
+ if( pStruct ){
+ int bFound = 0; /* True after pSeg->nEntryTombstone incr. */
+ int iLvl;
+ for(iLvl=pStruct->nLevel-1; iLvl>=0; iLvl--){
+ int iSeg;
+ for(iSeg=pStruct->aLevel[iLvl].nSeg-1; iSeg>=0; iSeg--){
+ Fts5StructureSegment *pSeg = &pStruct->aLevel[iLvl].aSeg[iSeg];
+ if( pSeg->iOrigin1<=(u64)iOrigin && pSeg->iOrigin2>=(u64)iOrigin ){
+ if( bFound==0 ){
+ pSeg->nEntryTombstone++;
+ bFound = 1;
+ }
+ fts5IndexTombstoneAdd(p, pSeg, iRowid);
+ }
+ }
+ }
+ fts5StructureRelease(pStruct);
+ }
+ return fts5IndexReturn(p);
+}
/*************************************************************************
**************************************************************************
@@ -236470,7 +246567,9 @@ static int fts5QueryCksum(
int eDetail = p->pConfig->eDetail;
u64 cksum = *pCksum;
Fts5IndexIter *pIter = 0;
- int rc = sqlite3Fts5IndexQuery(p, z, n, flags, 0, &pIter);
+ int rc = sqlite3Fts5IndexQuery(
+ p, z, n, (flags | FTS5INDEX_QUERY_NOTOKENDATA), 0, &pIter
+ );
while( rc==SQLITE_OK && ALWAYS(pIter!=0) && 0==sqlite3Fts5IterEof(pIter) ){
i64 rowid = pIter->iRowid;
@@ -236637,7 +246736,7 @@ static void fts5IndexIntegrityCheckEmpty(
}
static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){
- int iTermOff = 0;
+ i64 iTermOff = 0;
int ii;
Fts5Buffer buf1 = {0,0,0};
@@ -236646,7 +246745,7 @@ static void fts5IntegrityCheckPgidx(Fts5Index *p, Fts5Data *pLeaf){
ii = pLeaf->szLeaf;
while( ii<pLeaf->nn && p->rc==SQLITE_OK ){
int res;
- int iOff;
+ i64 iOff;
int nIncr;
ii += fts5GetVarint32(&pLeaf->p[ii], nIncr);
@@ -236691,6 +246790,7 @@ static void fts5IndexIntegrityCheckSegment(
Fts5StructureSegment *pSeg /* Segment to check internal consistency */
){
Fts5Config *pConfig = p->pConfig;
+ int bSecureDelete = (pConfig->iVersion==FTS5_CURRENT_VERSION_SECUREDELETE);
sqlite3_stmt *pStmt = 0;
int rc2;
int iIdxPrevLeaf = pSeg->pgnoFirst-1;
@@ -236726,7 +246826,19 @@ static void fts5IndexIntegrityCheckSegment(
** is also a rowid pointer within the leaf page header, it points to a
** location before the term. */
if( pLeaf->nn<=pLeaf->szLeaf ){
- p->rc = FTS5_CORRUPT;
+
+ if( nIdxTerm==0
+ && pConfig->iVersion==FTS5_CURRENT_VERSION_SECUREDELETE
+ && pLeaf->nn==pLeaf->szLeaf
+ && pLeaf->nn==4
+ ){
+ /* special case - the very first page in a segment keeps its %_idx
+ ** entry even if all the terms are removed from it by secure-delete
+ ** operations. */
+ }else{
+ p->rc = FTS5_CORRUPT;
+ }
+
}else{
int iOff; /* Offset of first term on leaf */
int iRowidOff; /* Offset of first rowid on leaf */
@@ -236790,9 +246902,12 @@ static void fts5IndexIntegrityCheckSegment(
ASSERT_SZLEAF_OK(pLeaf);
if( iRowidOff>=pLeaf->szLeaf ){
p->rc = FTS5_CORRUPT;
- }else{
+ }else if( bSecureDelete==0 || iRowidOff>0 ){
+ i64 iDlRowid = fts5DlidxIterRowid(pDlidx);
fts5GetVarint(&pLeaf->p[iRowidOff], (u64*)&iRowid);
- if( iRowid!=fts5DlidxIterRowid(pDlidx) ) p->rc = FTS5_CORRUPT;
+ if( iRowid<iDlRowid || (bSecureDelete==0 && iRowid!=iDlRowid) ){
+ p->rc = FTS5_CORRUPT;
+ }
}
fts5DataRelease(pLeaf);
}
@@ -236922,13 +247037,14 @@ static int sqlite3Fts5IndexIntegrityCheck(Fts5Index *p, u64 cksum, int bUseCksum
** function only.
*/
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** Decode a segment-data rowid from the %_data table. This function is
** the opposite of macro FTS5_SEGMENT_ROWID().
*/
static void fts5DecodeRowid(
i64 iRowid, /* Rowid from %_data table */
+ int *pbTombstone, /* OUT: Tombstone hash flag */
int *piSegid, /* OUT: Segment id */
int *pbDlidx, /* OUT: Dlidx flag */
int *piHeight, /* OUT: Height */
@@ -236944,13 +247060,16 @@ static void fts5DecodeRowid(
iRowid >>= FTS5_DATA_DLI_B;
*piSegid = (int)(iRowid & (((i64)1 << FTS5_DATA_ID_B) - 1));
+ iRowid >>= FTS5_DATA_ID_B;
+
+ *pbTombstone = (int)(iRowid & 0x0001);
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){
- int iSegid, iHeight, iPgno, bDlidx; /* Rowid compenents */
- fts5DecodeRowid(iKey, &iSegid, &bDlidx, &iHeight, &iPgno);
+ int iSegid, iHeight, iPgno, bDlidx, bTomb; /* Rowid compenents */
+ fts5DecodeRowid(iKey, &bTomb, &iSegid, &bDlidx, &iHeight, &iPgno);
if( iSegid==0 ){
if( iKey==FTS5_AVERAGES_ROWID ){
@@ -236960,14 +247079,16 @@ static void fts5DebugRowid(int *pRc, Fts5Buffer *pBuf, i64 iKey){
}
}
else{
- sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{%ssegid=%d h=%d pgno=%d}",
- bDlidx ? "dlidx " : "", iSegid, iHeight, iPgno
+ sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "{%s%ssegid=%d h=%d pgno=%d}",
+ bDlidx ? "dlidx " : "",
+ bTomb ? "tombstone " : "",
+ iSegid, iHeight, iPgno
);
}
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
static void fts5DebugStructure(
int *pRc, /* IN/OUT: error code */
Fts5Buffer *pBuf,
@@ -236982,16 +247103,22 @@ static void fts5DebugStructure(
);
for(iSeg=0; iSeg<pLvl->nSeg; iSeg++){
Fts5StructureSegment *pSeg = &pLvl->aSeg[iSeg];
- sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d}",
+ sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " {id=%d leaves=%d..%d",
pSeg->iSegid, pSeg->pgnoFirst, pSeg->pgnoLast
);
+ if( pSeg->iOrigin1>0 ){
+ sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " origin=%lld..%lld",
+ pSeg->iOrigin1, pSeg->iOrigin2
+ );
+ }
+ sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "}");
}
sqlite3Fts5BufferAppendPrintf(pRc, pBuf, "}");
}
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** This is part of the fts5_decode() debugging aid.
**
@@ -237016,9 +247143,9 @@ static void fts5DecodeStructure(
fts5DebugStructure(pRc, pBuf, p);
fts5StructureRelease(p);
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** This is part of the fts5_decode() debugging aid.
**
@@ -237041,9 +247168,9 @@ static void fts5DecodeAverages(
zSpace = " ";
}
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** Buffer (a/n) is assumed to contain a list of serialized varints. Read
** each varint and append its string representation to buffer pBuf. Return
@@ -237060,9 +247187,9 @@ static int fts5DecodePoslist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){
}
return iOff;
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** The start of buffer (a/n) contains the start of a doclist. The doclist
** may or may not finish within the buffer. This function appends a text
@@ -237095,9 +247222,9 @@ static int fts5DecodeDoclist(int *pRc, Fts5Buffer *pBuf, const u8 *a, int n){
return iOff;
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** This function is part of the fts5_decode() debugging function. It is
** only ever used with detail=none tables.
@@ -237138,9 +247265,27 @@ static void fts5DecodeRowidList(
sqlite3Fts5BufferAppendPrintf(pRc, pBuf, " %lld%s", iRowid, zApp);
}
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
+static void fts5BufferAppendTerm(int *pRc, Fts5Buffer *pBuf, Fts5Buffer *pTerm){
+ int ii;
+ fts5BufferGrow(pRc, pBuf, pTerm->n*2 + 1);
+ if( *pRc==SQLITE_OK ){
+ for(ii=0; ii<pTerm->n; ii++){
+ if( pTerm->p[ii]==0x00 ){
+ pBuf->p[pBuf->n++] = '\\';
+ pBuf->p[pBuf->n++] = '0';
+ }else{
+ pBuf->p[pBuf->n++] = pTerm->p[ii];
+ }
+ }
+ pBuf->p[pBuf->n] = 0x00;
+ }
+}
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
+
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** The implementation of user-defined scalar function fts5_decode().
*/
@@ -237151,6 +247296,7 @@ static void fts5DecodeFunction(
){
i64 iRowid; /* Rowid for record being decoded */
int iSegid,iHeight,iPgno,bDlidx;/* Rowid components */
+ int bTomb;
const u8 *aBlob; int n; /* Record to decode */
u8 *a = 0;
Fts5Buffer s; /* Build up text to return here */
@@ -237173,7 +247319,7 @@ static void fts5DecodeFunction(
if( a==0 ) goto decode_out;
if( n>0 ) memcpy(a, aBlob, n);
- fts5DecodeRowid(iRowid, &iSegid, &bDlidx, &iHeight, &iPgno);
+ fts5DecodeRowid(iRowid, &bTomb, &iSegid, &bDlidx, &iHeight, &iPgno);
fts5DebugRowid(&rc, &s, iRowid);
if( bDlidx ){
@@ -237192,6 +247338,28 @@ static void fts5DecodeFunction(
" %d(%lld)", lvl.iLeafPgno, lvl.iRowid
);
}
+ }else if( bTomb ){
+ u32 nElem = fts5GetU32(&a[4]);
+ int szKey = (aBlob[0]==4 || aBlob[0]==8) ? aBlob[0] : 8;
+ int nSlot = (n - 8) / szKey;
+ int ii;
+ sqlite3Fts5BufferAppendPrintf(&rc, &s, " nElem=%d", (int)nElem);
+ if( aBlob[1] ){
+ sqlite3Fts5BufferAppendPrintf(&rc, &s, " 0");
+ }
+ for(ii=0; ii<nSlot; ii++){
+ u64 iVal = 0;
+ if( szKey==4 ){
+ u32 *aSlot = (u32*)&aBlob[8];
+ if( aSlot[ii] ) iVal = fts5GetU32((u8*)&aSlot[ii]);
+ }else{
+ u64 *aSlot = (u64*)&aBlob[8];
+ if( aSlot[ii] ) iVal = fts5GetU64((u8*)&aSlot[ii]);
+ }
+ if( iVal!=0 ){
+ sqlite3Fts5BufferAppendPrintf(&rc, &s, " %lld", (i64)iVal);
+ }
+ }
}else if( iSegid==0 ){
if( iRowid==FTS5_AVERAGES_ROWID ){
fts5DecodeAverages(&rc, &s, a, n);
@@ -237217,16 +247385,15 @@ static void fts5DecodeFunction(
fts5DecodeRowidList(&rc, &s, &a[4], iTermOff-4);
iOff = iTermOff;
- while( iOff<szLeaf ){
+ while( iOff<szLeaf && rc==SQLITE_OK ){
int nAppend;
/* Read the term data for the next term*/
iOff += fts5GetVarint32(&a[iOff], nAppend);
term.n = nKeep;
fts5BufferAppendBlob(&rc, &term, nAppend, &a[iOff]);
- sqlite3Fts5BufferAppendPrintf(
- &rc, &s, " term=%.*s", term.n, (const char*)term.p
- );
+ sqlite3Fts5BufferAppendPrintf(&rc, &s, " term=");
+ fts5BufferAppendTerm(&rc, &s, &term);
iOff += nAppend;
/* Figure out where the doclist for this term ends */
@@ -237237,8 +247404,11 @@ static void fts5DecodeFunction(
}else{
iTermOff = szLeaf;
}
-
- fts5DecodeRowidList(&rc, &s, &a[iOff], iTermOff-iOff);
+ if( iTermOff>szLeaf ){
+ rc = FTS5_CORRUPT;
+ }else{
+ fts5DecodeRowidList(&rc, &s, &a[iOff], iTermOff-iOff);
+ }
iOff = iTermOff;
if( iOff<szLeaf ){
iOff += fts5GetVarint32(&a[iOff], nKeep);
@@ -237331,9 +247501,8 @@ static void fts5DecodeFunction(
fts5BufferAppendBlob(&rc, &term, nByte, &a[iOff]);
iOff += nByte;
- sqlite3Fts5BufferAppendPrintf(
- &rc, &s, " term=%.*s", term.n, (const char*)term.p
- );
+ sqlite3Fts5BufferAppendPrintf(&rc, &s, " term=");
+ fts5BufferAppendTerm(&rc, &s, &term);
iOff += fts5DecodeDoclist(&rc, &s, &a[iOff], iEnd-iOff);
}
@@ -237349,9 +247518,9 @@ static void fts5DecodeFunction(
}
fts5BufferFree(&s);
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
/*
** The implementation of user-defined scalar function fts5_rowid().
*/
@@ -237385,7 +247554,235 @@ static void fts5RowidFunction(
}
}
}
-#endif /* SQLITE_TEST */
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
+
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
+
+typedef struct Fts5StructVtab Fts5StructVtab;
+struct Fts5StructVtab {
+ sqlite3_vtab base;
+};
+
+typedef struct Fts5StructVcsr Fts5StructVcsr;
+struct Fts5StructVcsr {
+ sqlite3_vtab_cursor base;
+ Fts5Structure *pStruct;
+ int iLevel;
+ int iSeg;
+ int iRowid;
+};
+
+/*
+** Create a new fts5_structure() table-valued function.
+*/
+static int fts5structConnectMethod(
+ sqlite3 *db,
+ void *pAux,
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVtab,
+ char **pzErr
+){
+ Fts5StructVtab *pNew = 0;
+ int rc = SQLITE_OK;
+
+ rc = sqlite3_declare_vtab(db,
+ "CREATE TABLE xyz("
+ "level, segment, merge, segid, leaf1, leaf2, loc1, loc2, "
+ "npgtombstone, nentrytombstone, nentry, struct HIDDEN);"
+ );
+ if( rc==SQLITE_OK ){
+ pNew = sqlite3Fts5MallocZero(&rc, sizeof(*pNew));
+ }
+
+ *ppVtab = (sqlite3_vtab*)pNew;
+ return rc;
+}
+
+/*
+** We must have a single struct=? constraint that will be passed through
+** into the xFilter method. If there is no valid stmt=? constraint,
+** then return an SQLITE_CONSTRAINT error.
+*/
+static int fts5structBestIndexMethod(
+ sqlite3_vtab *tab,
+ sqlite3_index_info *pIdxInfo
+){
+ int i;
+ int rc = SQLITE_CONSTRAINT;
+ struct sqlite3_index_constraint *p;
+ pIdxInfo->estimatedCost = (double)100;
+ pIdxInfo->estimatedRows = 100;
+ pIdxInfo->idxNum = 0;
+ for(i=0, p=pIdxInfo->aConstraint; i<pIdxInfo->nConstraint; i++, p++){
+ if( p->usable==0 ) continue;
+ if( p->op==SQLITE_INDEX_CONSTRAINT_EQ && p->iColumn==11 ){
+ rc = SQLITE_OK;
+ pIdxInfo->aConstraintUsage[i].omit = 1;
+ pIdxInfo->aConstraintUsage[i].argvIndex = 1;
+ break;
+ }
+ }
+ return rc;
+}
+
+/*
+** This method is the destructor for bytecodevtab objects.
+*/
+static int fts5structDisconnectMethod(sqlite3_vtab *pVtab){
+ Fts5StructVtab *p = (Fts5StructVtab*)pVtab;
+ sqlite3_free(p);
+ return SQLITE_OK;
+}
+
+/*
+** Constructor for a new bytecodevtab_cursor object.
+*/
+static int fts5structOpenMethod(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCsr){
+ int rc = SQLITE_OK;
+ Fts5StructVcsr *pNew = 0;
+
+ pNew = sqlite3Fts5MallocZero(&rc, sizeof(*pNew));
+ *ppCsr = (sqlite3_vtab_cursor*)pNew;
+
+ return SQLITE_OK;
+}
+
+/*
+** Destructor for a bytecodevtab_cursor.
+*/
+static int fts5structCloseMethod(sqlite3_vtab_cursor *cur){
+ Fts5StructVcsr *pCsr = (Fts5StructVcsr*)cur;
+ fts5StructureRelease(pCsr->pStruct);
+ sqlite3_free(pCsr);
+ return SQLITE_OK;
+}
+
+
+/*
+** Advance a bytecodevtab_cursor to its next row of output.
+*/
+static int fts5structNextMethod(sqlite3_vtab_cursor *cur){
+ Fts5StructVcsr *pCsr = (Fts5StructVcsr*)cur;
+ Fts5Structure *p = pCsr->pStruct;
+
+ assert( pCsr->pStruct );
+ pCsr->iSeg++;
+ pCsr->iRowid++;
+ while( pCsr->iLevel<p->nLevel && pCsr->iSeg>=p->aLevel[pCsr->iLevel].nSeg ){
+ pCsr->iLevel++;
+ pCsr->iSeg = 0;
+ }
+ if( pCsr->iLevel>=p->nLevel ){
+ fts5StructureRelease(pCsr->pStruct);
+ pCsr->pStruct = 0;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Return TRUE if the cursor has been moved off of the last
+** row of output.
+*/
+static int fts5structEofMethod(sqlite3_vtab_cursor *cur){
+ Fts5StructVcsr *pCsr = (Fts5StructVcsr*)cur;
+ return pCsr->pStruct==0;
+}
+
+static int fts5structRowidMethod(
+ sqlite3_vtab_cursor *cur,
+ sqlite_int64 *piRowid
+){
+ Fts5StructVcsr *pCsr = (Fts5StructVcsr*)cur;
+ *piRowid = pCsr->iRowid;
+ return SQLITE_OK;
+}
+
+/*
+** Return values of columns for the row at which the bytecodevtab_cursor
+** is currently pointing.
+*/
+static int fts5structColumnMethod(
+ sqlite3_vtab_cursor *cur, /* The cursor */
+ sqlite3_context *ctx, /* First argument to sqlite3_result_...() */
+ int i /* Which column to return */
+){
+ Fts5StructVcsr *pCsr = (Fts5StructVcsr*)cur;
+ Fts5Structure *p = pCsr->pStruct;
+ Fts5StructureSegment *pSeg = &p->aLevel[pCsr->iLevel].aSeg[pCsr->iSeg];
+
+ switch( i ){
+ case 0: /* level */
+ sqlite3_result_int(ctx, pCsr->iLevel);
+ break;
+ case 1: /* segment */
+ sqlite3_result_int(ctx, pCsr->iSeg);
+ break;
+ case 2: /* merge */
+ sqlite3_result_int(ctx, pCsr->iSeg < p->aLevel[pCsr->iLevel].nMerge);
+ break;
+ case 3: /* segid */
+ sqlite3_result_int(ctx, pSeg->iSegid);
+ break;
+ case 4: /* leaf1 */
+ sqlite3_result_int(ctx, pSeg->pgnoFirst);
+ break;
+ case 5: /* leaf2 */
+ sqlite3_result_int(ctx, pSeg->pgnoLast);
+ break;
+ case 6: /* origin1 */
+ sqlite3_result_int64(ctx, pSeg->iOrigin1);
+ break;
+ case 7: /* origin2 */
+ sqlite3_result_int64(ctx, pSeg->iOrigin2);
+ break;
+ case 8: /* npgtombstone */
+ sqlite3_result_int(ctx, pSeg->nPgTombstone);
+ break;
+ case 9: /* nentrytombstone */
+ sqlite3_result_int64(ctx, pSeg->nEntryTombstone);
+ break;
+ case 10: /* nentry */
+ sqlite3_result_int64(ctx, pSeg->nEntry);
+ break;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Initialize a cursor.
+**
+** idxNum==0 means show all subprograms
+** idxNum==1 means show only the main bytecode and omit subprograms.
+*/
+static int fts5structFilterMethod(
+ sqlite3_vtab_cursor *pVtabCursor,
+ int idxNum, const char *idxStr,
+ int argc, sqlite3_value **argv
+){
+ Fts5StructVcsr *pCsr = (Fts5StructVcsr *)pVtabCursor;
+ int rc = SQLITE_OK;
+
+ const u8 *aBlob = 0;
+ int nBlob = 0;
+
+ assert( argc==1 );
+ fts5StructureRelease(pCsr->pStruct);
+ pCsr->pStruct = 0;
+
+ nBlob = sqlite3_value_bytes(argv[0]);
+ aBlob = (const u8*)sqlite3_value_blob(argv[0]);
+ rc = fts5StructureDecode(aBlob, nBlob, 0, &pCsr->pStruct);
+ if( rc==SQLITE_OK ){
+ pCsr->iLevel = 0;
+ pCsr->iRowid = 0;
+ pCsr->iSeg = -1;
+ rc = fts5structNextMethod(pVtabCursor);
+ }
+
+ return rc;
+}
+
+#endif /* SQLITE_TEST || SQLITE_FTS5_DEBUG */
/*
** This is called as part of registering the FTS5 module with database
@@ -237396,7 +247793,7 @@ static void fts5RowidFunction(
** SQLite error code is returned instead.
*/
static int sqlite3Fts5IndexInit(sqlite3 *db){
-#ifdef SQLITE_TEST
+#if defined(SQLITE_TEST) || defined(SQLITE_FTS5_DEBUG)
int rc = sqlite3_create_function(
db, "fts5_decode", 2, SQLITE_UTF8, 0, fts5DecodeFunction, 0, 0
);
@@ -237413,6 +247810,37 @@ static int sqlite3Fts5IndexInit(sqlite3 *db){
db, "fts5_rowid", -1, SQLITE_UTF8, 0, fts5RowidFunction, 0, 0
);
}
+
+ if( rc==SQLITE_OK ){
+ static const sqlite3_module fts5structure_module = {
+ 0, /* iVersion */
+ 0, /* xCreate */
+ fts5structConnectMethod, /* xConnect */
+ fts5structBestIndexMethod, /* xBestIndex */
+ fts5structDisconnectMethod, /* xDisconnect */
+ 0, /* xDestroy */
+ fts5structOpenMethod, /* xOpen */
+ fts5structCloseMethod, /* xClose */
+ fts5structFilterMethod, /* xFilter */
+ fts5structNextMethod, /* xNext */
+ fts5structEofMethod, /* xEof */
+ fts5structColumnMethod, /* xColumn */
+ fts5structRowidMethod, /* xRowid */
+ 0, /* xUpdate */
+ 0, /* xBegin */
+ 0, /* xSync */
+ 0, /* xCommit */
+ 0, /* xRollback */
+ 0, /* xFindFunction */
+ 0, /* xRename */
+ 0, /* xSavepoint */
+ 0, /* xRelease */
+ 0, /* xRollbackTo */
+ 0, /* xShadowName */
+ 0 /* xIntegrity */
+ };
+ rc = sqlite3_create_module(db, "fts5_structure", &fts5structure_module, 0);
+ }
return rc;
#else
return SQLITE_OK;
@@ -237548,6 +247976,8 @@ struct Fts5FullTable {
Fts5Storage *pStorage; /* Document store */
Fts5Global *pGlobal; /* Global (connection wide) data */
Fts5Cursor *pSortCsr; /* Sort data from this cursor */
+ int iSavepoint; /* Successful xSavepoint()+1 */
+
#ifdef SQLITE_DEBUG
struct Fts5TransactionState ts;
#endif
@@ -237836,6 +248266,13 @@ static int fts5InitVtab(
pConfig->pzErrmsg = 0;
}
+ if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
+ rc = sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, (int)1);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
+ }
+
if( rc!=SQLITE_OK ){
fts5FreeVtab(pTab);
pTab = 0;
@@ -238078,12 +248515,15 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
}
idxStr[iIdxStr] = '\0';
- /* Set idxFlags flags for the ORDER BY clause */
+ /* Set idxFlags flags for the ORDER BY clause
+ **
+ ** Note that tokendata=1 tables cannot currently handle "ORDER BY rowid DESC".
+ */
if( pInfo->nOrderBy==1 ){
int iSort = pInfo->aOrderBy[0].iColumn;
if( iSort==(pConfig->nCol+1) && bSeenMatch ){
idxFlags |= FTS5_BI_ORDER_RANK;
- }else if( iSort==-1 ){
+ }else if( iSort==-1 && (!pInfo->aOrderBy[0].desc || !pConfig->bTokendata) ){
idxFlags |= FTS5_BI_ORDER_ROWID;
}
if( BitFlagTest(idxFlags, FTS5_BI_ORDER_RANK|FTS5_BI_ORDER_ROWID) ){
@@ -238335,6 +248775,16 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
);
assert( !CsrFlagTest(pCsr, FTS5CSR_EOF) );
+ /* If this cursor uses FTS5_PLAN_MATCH and this is a tokendata=1 table,
+ ** clear any token mappings accumulated at the fts5_index.c level. In
+ ** other cases, specifically FTS5_PLAN_SOURCE and FTS5_PLAN_SORTED_MATCH,
+ ** we need to retain the mappings for the entire query. */
+ if( pCsr->ePlan==FTS5_PLAN_MATCH
+ && ((Fts5Table*)pCursor->pVtab)->pConfig->bTokendata
+ ){
+ sqlite3Fts5ExprClearTokens(pCsr->pExpr);
+ }
+
if( pCsr->ePlan<3 ){
int bSkip = 0;
if( (rc = fts5CursorReseek(pCsr, &bSkip)) || bSkip ) return rc;
@@ -238760,6 +249210,9 @@ static int fts5FilterMethod(
pCsr->iFirstRowid = fts5GetRowidLimit(pRowidGe, SMALLEST_INT64);
}
+ rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ if( rc!=SQLITE_OK ) goto filter_out;
+
if( pTab->pSortCsr ){
/* If pSortCsr is non-NULL, then this call is being made as part of
** processing for a "... MATCH <expr> ORDER BY rank" query (ePlan is
@@ -238782,6 +249235,7 @@ static int fts5FilterMethod(
pCsr->pExpr = pTab->pSortCsr->pExpr;
rc = fts5CursorFirst(pTab, pCsr, bDesc);
}else if( pCsr->pExpr ){
+ assert( rc==SQLITE_OK );
rc = fts5CursorParseRank(pConfig, pCsr, pRank);
if( rc==SQLITE_OK ){
if( bOrderByRank ){
@@ -238953,6 +249407,7 @@ static int fts5SpecialInsert(
Fts5Config *pConfig = pTab->p.pConfig;
int rc = SQLITE_OK;
int bError = 0;
+ int bLoadConfig = 0;
if( 0==sqlite3_stricmp("delete-all", zCmd) ){
if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
@@ -238964,6 +249419,7 @@ static int fts5SpecialInsert(
}else{
rc = sqlite3Fts5StorageDeleteAll(pTab->pStorage);
}
+ bLoadConfig = 1;
}else if( 0==sqlite3_stricmp("rebuild", zCmd) ){
if( pConfig->eContent==FTS5_CONTENT_NONE ){
fts5SetVtabError(pTab,
@@ -238973,6 +249429,7 @@ static int fts5SpecialInsert(
}else{
rc = sqlite3Fts5StorageRebuild(pTab->pStorage);
}
+ bLoadConfig = 1;
}else if( 0==sqlite3_stricmp("optimize", zCmd) ){
rc = sqlite3Fts5StorageOptimize(pTab->pStorage);
}else if( 0==sqlite3_stricmp("merge", zCmd) ){
@@ -238985,8 +249442,13 @@ static int fts5SpecialInsert(
}else if( 0==sqlite3_stricmp("prefix-index", zCmd) ){
pConfig->bPrefixIndex = sqlite3_value_int(pVal);
#endif
+ }else if( 0==sqlite3_stricmp("flush", zCmd) ){
+ rc = sqlite3Fts5FlushToDisk(&pTab->p);
}else{
- rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ rc = sqlite3Fts5FlushToDisk(&pTab->p);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ }
if( rc==SQLITE_OK ){
rc = sqlite3Fts5ConfigSetValue(pTab->p.pConfig, zCmd, pVal, &bError);
}
@@ -238998,6 +249460,12 @@ static int fts5SpecialInsert(
}
}
}
+
+ if( rc==SQLITE_OK && bLoadConfig ){
+ pTab->p.pConfig->iCookie--;
+ rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ }
+
return rc;
}
@@ -239054,6 +249522,7 @@ static int fts5UpdateMethod(
Fts5Config *pConfig = pTab->p.pConfig;
int eType0; /* value_type() of apVal[0] */
int rc = SQLITE_OK; /* Return code */
+ int bUpdateOrDelete = 0;
/* A transaction must be open when this is called. */
assert( pTab->ts.eState==1 || pTab->ts.eState==2 );
@@ -239064,6 +249533,11 @@ static int fts5UpdateMethod(
|| sqlite3_value_type(apVal[0])==SQLITE_NULL
);
assert( pTab->p.pConfig->pzErrmsg==0 );
+ if( pConfig->pgsz==0 ){
+ rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ if( rc!=SQLITE_OK ) return rc;
+ }
+
pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
/* Put any active cursors into REQUIRE_SEEK state. */
@@ -239078,7 +249552,14 @@ static int fts5UpdateMethod(
if( pConfig->eContent!=FTS5_CONTENT_NORMAL
&& 0==sqlite3_stricmp("delete", z)
){
- rc = fts5SpecialDelete(pTab, apVal);
+ if( pConfig->bContentlessDelete ){
+ fts5SetVtabError(pTab,
+ "'delete' may not be used with a contentless_delete=1 table"
+ );
+ rc = SQLITE_ERROR;
+ }else{
+ rc = fts5SpecialDelete(pTab, apVal);
+ }
}else{
rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]);
}
@@ -239095,7 +249576,7 @@ static int fts5UpdateMethod(
** Cases 3 and 4 may violate the rowid constraint.
*/
int eConflict = SQLITE_ABORT;
- if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL || pConfig->bContentlessDelete ){
eConflict = sqlite3_vtab_on_conflict(pConfig->db);
}
@@ -239103,8 +249584,12 @@ static int fts5UpdateMethod(
assert( nArg!=1 || eType0==SQLITE_INTEGER );
/* Filter out attempts to run UPDATE or DELETE on contentless tables.
- ** This is not suported. */
- if( eType0==SQLITE_INTEGER && fts5IsContentless(pTab) ){
+ ** This is not suported. Except - they are both supported if the CREATE
+ ** VIRTUAL TABLE statement contained "contentless_delete=1". */
+ if( eType0==SQLITE_INTEGER
+ && pConfig->eContent==FTS5_CONTENT_NONE
+ && pConfig->bContentlessDelete==0
+ ){
pTab->p.base.zErrMsg = sqlite3_mprintf(
"cannot %s contentless fts5 table: %s",
(nArg>1 ? "UPDATE" : "DELETE from"), pConfig->zName
@@ -239116,6 +249601,7 @@ static int fts5UpdateMethod(
else if( nArg==1 ){
i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
+ bUpdateOrDelete = 1;
}
/* INSERT or UPDATE */
@@ -239127,10 +249613,12 @@ static int fts5UpdateMethod(
}
else if( eType0!=SQLITE_INTEGER ){
- /* If this is a REPLACE, first remove the current entry (if any) */
+ /* An INSERT statement. If the conflict-mode is REPLACE, first remove
+ ** the current entry (if any). */
if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){
i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
+ bUpdateOrDelete = 1;
}
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}
@@ -239159,10 +249647,24 @@ static int fts5UpdateMethod(
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}
+ bUpdateOrDelete = 1;
}
}
}
+ if( rc==SQLITE_OK
+ && bUpdateOrDelete
+ && pConfig->bSecureDelete
+ && pConfig->iVersion==FTS5_CURRENT_VERSION
+ ){
+ rc = sqlite3Fts5StorageConfigValue(
+ pTab->pStorage, "version", 0, FTS5_CURRENT_VERSION_SECUREDELETE
+ );
+ if( rc==SQLITE_OK ){
+ pConfig->iVersion = FTS5_CURRENT_VERSION_SECUREDELETE;
+ }
+ }
+
pTab->p.pConfig->pzErrmsg = 0;
return rc;
}
@@ -239175,8 +249677,7 @@ static int fts5SyncMethod(sqlite3_vtab *pVtab){
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
fts5CheckTransactionState(pTab, FTS5_SYNC, 0);
pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
- fts5TripCursors(pTab);
- rc = sqlite3Fts5StorageSync(pTab->pStorage);
+ rc = sqlite3Fts5FlushToDisk(&pTab->p);
pTab->p.pConfig->pzErrmsg = 0;
return rc;
}
@@ -239272,7 +249773,10 @@ static int fts5ApiColumnText(
){
int rc = SQLITE_OK;
Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
- if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab))
+ Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab);
+ if( iCol<0 || iCol>=pTab->pConfig->nCol ){
+ rc = SQLITE_RANGE;
+ }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab))
|| pCsr->ePlan==FTS5_PLAN_SPECIAL
){
*pz = 0;
@@ -239297,8 +249801,9 @@ static int fts5CsrPoslist(
int rc = SQLITE_OK;
int bLive = (pCsr->pSorter==0);
- if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
-
+ if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){
+ rc = SQLITE_RANGE;
+ }else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){
if( pConfig->eDetail!=FTS5_DETAIL_FULL ){
Fts5PoslistPopulator *aPopulator;
int i;
@@ -239322,15 +249827,21 @@ static int fts5CsrPoslist(
CsrFlagClear(pCsr, FTS5CSR_REQUIRE_POSLIST);
}
- if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
- Fts5Sorter *pSorter = pCsr->pSorter;
- int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
- *pn = pSorter->aIdx[iPhrase] - i1;
- *pa = &pSorter->aPoslist[i1];
+ if( rc==SQLITE_OK ){
+ if( pCsr->pSorter && pConfig->eDetail==FTS5_DETAIL_FULL ){
+ Fts5Sorter *pSorter = pCsr->pSorter;
+ int i1 = (iPhrase==0 ? 0 : pSorter->aIdx[iPhrase-1]);
+ *pn = pSorter->aIdx[iPhrase] - i1;
+ *pa = &pSorter->aPoslist[i1];
+ }else{
+ *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
+ }
}else{
- *pn = sqlite3Fts5ExprPoslist(pCsr->pExpr, iPhrase, pa);
+ *pa = 0;
+ *pn = 0;
}
+
return rc;
}
@@ -239437,12 +249948,6 @@ static int fts5ApiInst(
){
if( iIdx<0 || iIdx>=pCsr->nInstCount ){
rc = SQLITE_RANGE;
-#if 0
- }else if( fts5IsOffsetless((Fts5Table*)pCsr->base.pVtab) ){
- *piPhrase = pCsr->aInst[iIdx*3];
- *piCol = pCsr->aInst[iIdx*3 + 2];
- *piOff = -1;
-#endif
}else{
*piPhrase = pCsr->aInst[iIdx*3];
*piCol = pCsr->aInst[iIdx*3 + 1];
@@ -239697,13 +250202,56 @@ static int fts5ApiPhraseFirstColumn(
return rc;
}
+/*
+** xQueryToken() API implemenetation.
+*/
+static int fts5ApiQueryToken(
+ Fts5Context* pCtx,
+ int iPhrase,
+ int iToken,
+ const char **ppOut,
+ int *pnOut
+){
+ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+ return sqlite3Fts5ExprQueryToken(pCsr->pExpr, iPhrase, iToken, ppOut, pnOut);
+}
+
+/*
+** xInstToken() API implemenetation.
+*/
+static int fts5ApiInstToken(
+ Fts5Context *pCtx,
+ int iIdx,
+ int iToken,
+ const char **ppOut, int *pnOut
+){
+ Fts5Cursor *pCsr = (Fts5Cursor*)pCtx;
+ int rc = SQLITE_OK;
+ if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_INST)==0
+ || SQLITE_OK==(rc = fts5CacheInstArray(pCsr))
+ ){
+ if( iIdx<0 || iIdx>=pCsr->nInstCount ){
+ rc = SQLITE_RANGE;
+ }else{
+ int iPhrase = pCsr->aInst[iIdx*3];
+ int iCol = pCsr->aInst[iIdx*3 + 1];
+ int iOff = pCsr->aInst[iIdx*3 + 2];
+ i64 iRowid = fts5CursorRowid(pCsr);
+ rc = sqlite3Fts5ExprInstToken(
+ pCsr->pExpr, iRowid, iPhrase, iCol, iOff, iToken, ppOut, pnOut
+ );
+ }
+ }
+ return rc;
+}
+
static int fts5ApiQueryPhrase(Fts5Context*, int, void*,
int(*)(const Fts5ExtensionApi*, Fts5Context*, void*)
);
static const Fts5ExtensionApi sFts5Api = {
- 2, /* iVersion */
+ 3, /* iVersion */
fts5ApiUserData,
fts5ApiColumnCount,
fts5ApiRowCount,
@@ -239723,6 +250271,8 @@ static const Fts5ExtensionApi sFts5Api = {
fts5ApiPhraseNext,
fts5ApiPhraseFirstColumn,
fts5ApiPhraseNextColumn,
+ fts5ApiQueryToken,
+ fts5ApiInstToken
};
/*
@@ -239943,6 +250493,12 @@ static int fts5ColumnMethod(
sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1));
}
pConfig->pzErrmsg = 0;
+ }else if( pConfig->bContentlessDelete && sqlite3_vtab_nochange(pCtx) ){
+ char *zErr = sqlite3_mprintf("cannot UPDATE a subset of "
+ "columns on fts5 contentless-delete table: %s", pConfig->zName
+ );
+ sqlite3_result_error(pCtx, zErr, -1);
+ sqlite3_free(zErr);
}
return rc;
}
@@ -239981,8 +250537,10 @@ static int fts5RenameMethod(
sqlite3_vtab *pVtab, /* Virtual table handle */
const char *zName /* New name of table */
){
+ int rc;
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
- return sqlite3Fts5StorageRename(pTab->pStorage, zName);
+ rc = sqlite3Fts5StorageRename(pTab->pStorage, zName);
+ return rc;
}
static int sqlite3Fts5FlushToDisk(Fts5Table *pTab){
@@ -239996,9 +250554,15 @@ static int sqlite3Fts5FlushToDisk(Fts5Table *pTab){
** Flush the contents of the pending-terms table to disk.
*/
static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
- UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
- fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_SAVEPOINT, iSavepoint);
- return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
+ Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
+ int rc = SQLITE_OK;
+
+ fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
+ rc = sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
+ if( rc==SQLITE_OK ){
+ pTab->iSavepoint = iSavepoint+1;
+ }
+ return rc;
}
/*
@@ -240007,9 +250571,16 @@ static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
** This is a no-op.
*/
static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
- UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
- fts5CheckTransactionState((Fts5FullTable*)pVtab, FTS5_RELEASE, iSavepoint);
- return sqlite3Fts5FlushToDisk((Fts5Table*)pVtab);
+ Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
+ int rc = SQLITE_OK;
+ fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
+ if( (iSavepoint+1)<pTab->iSavepoint ){
+ rc = sqlite3Fts5FlushToDisk(&pTab->p);
+ if( rc==SQLITE_OK ){
+ pTab->iSavepoint = iSavepoint;
+ }
+ }
+ return rc;
}
/*
@@ -240019,10 +250590,14 @@ static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
*/
static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
- UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
+ int rc = SQLITE_OK;
fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
fts5TripCursors(pTab);
- return sqlite3Fts5StorageRollback(pTab->pStorage);
+ if( (iSavepoint+1)<=pTab->iSavepoint ){
+ pTab->p.pConfig->pgsz = 0;
+ rc = sqlite3Fts5StorageRollback(pTab->pStorage);
+ }
+ return rc;
}
/*
@@ -240224,7 +250799,7 @@ static void fts5SourceIdFunc(
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
- sqlite3_result_text(pCtx, "fts5: 2023-03-10 12:13:52 20399f3eda5ec249d147ba9e48da6e87f969d7966a9a896764ca437ff7e737ff", -1, SQLITE_TRANSIENT);
+ sqlite3_result_text(pCtx, "fts5: 2024-04-15 13:34:05 8653b758870e6ef0c98d46b3ace27849054af85da891eb121e9aaa537f1e8355", -1, SQLITE_TRANSIENT);
}
/*
@@ -240242,9 +250817,40 @@ static int fts5ShadowName(const char *zName){
return 0;
}
+/*
+** Run an integrity check on the FTS5 data structures. Return a string
+** if anything is found amiss. Return a NULL pointer if everything is
+** OK.
+*/
+static int fts5IntegrityMethod(
+ sqlite3_vtab *pVtab, /* the FTS5 virtual table to check */
+ const char *zSchema, /* Name of schema in which this table lives */
+ const char *zTabname, /* Name of the table itself */
+ int isQuick, /* True if this is a quick-check */
+ char **pzErr /* Write error message here */
+){
+ Fts5FullTable *pTab = (Fts5FullTable*)pVtab;
+ int rc;
+
+ assert( pzErr!=0 && *pzErr==0 );
+ UNUSED_PARAM(isQuick);
+ rc = sqlite3Fts5StorageIntegrity(pTab->pStorage, 0);
+ if( (rc&0xff)==SQLITE_CORRUPT ){
+ *pzErr = sqlite3_mprintf("malformed inverted index for FTS5 table %s.%s",
+ zSchema, zTabname);
+ }else if( rc!=SQLITE_OK ){
+ *pzErr = sqlite3_mprintf("unable to validate the inverted index for"
+ " FTS5 table %s.%s: %s",
+ zSchema, zTabname, sqlite3_errstr(rc));
+ }
+ sqlite3Fts5IndexCloseReader(pTab->p.pIndex);
+
+ return SQLITE_OK;
+}
+
static int fts5Init(sqlite3 *db){
static const sqlite3_module fts5Mod = {
- /* iVersion */ 3,
+ /* iVersion */ 4,
/* xCreate */ fts5CreateMethod,
/* xConnect */ fts5ConnectMethod,
/* xBestIndex */ fts5BestIndexMethod,
@@ -240267,7 +250873,8 @@ static int fts5Init(sqlite3 *db){
/* xSavepoint */ fts5SavepointMethod,
/* xRelease */ fts5ReleaseMethod,
/* xRollbackTo */ fts5RollbackToMethod,
- /* xShadowName */ fts5ShadowName
+ /* xShadowName */ fts5ShadowName,
+ /* xIntegrity */ fts5IntegrityMethod
};
int rc;
@@ -240437,10 +251044,10 @@ static int fts5StorageGetStmt(
"INSERT INTO %Q.'%q_content' VALUES(%s)", /* INSERT_CONTENT */
"REPLACE INTO %Q.'%q_content' VALUES(%s)", /* REPLACE_CONTENT */
"DELETE FROM %Q.'%q_content' WHERE id=?", /* DELETE_CONTENT */
- "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)", /* REPLACE_DOCSIZE */
+ "REPLACE INTO %Q.'%q_docsize' VALUES(?,?%s)", /* REPLACE_DOCSIZE */
"DELETE FROM %Q.'%q_docsize' WHERE id=?", /* DELETE_DOCSIZE */
- "SELECT sz FROM %Q.'%q_docsize' WHERE id=?", /* LOOKUP_DOCSIZE */
+ "SELECT sz%s FROM %Q.'%q_docsize' WHERE id=?", /* LOOKUP_DOCSIZE */
"REPLACE INTO %Q.'%q_config' VALUES(?,?)", /* REPLACE_CONFIG */
"SELECT %s FROM %s AS T", /* SCAN */
@@ -240488,6 +251095,19 @@ static int fts5StorageGetStmt(
break;
}
+ case FTS5_STMT_REPLACE_DOCSIZE:
+ zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName,
+ (pC->bContentlessDelete ? ",?" : "")
+ );
+ break;
+
+ case FTS5_STMT_LOOKUP_DOCSIZE:
+ zSql = sqlite3_mprintf(azStmt[eStmt],
+ (pC->bContentlessDelete ? ",origin" : ""),
+ pC->zDb, pC->zName
+ );
+ break;
+
default:
zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName);
break;
@@ -240677,9 +251297,11 @@ static int sqlite3Fts5StorageOpen(
}
if( rc==SQLITE_OK && pConfig->bColumnsize ){
- rc = sqlite3Fts5CreateTable(
- pConfig, "docsize", "id INTEGER PRIMARY KEY, sz BLOB", 0, pzErr
- );
+ const char *zCols = "id INTEGER PRIMARY KEY, sz BLOB";
+ if( pConfig->bContentlessDelete ){
+ zCols = "id INTEGER PRIMARY KEY, sz BLOB, origin INTEGER";
+ }
+ rc = sqlite3Fts5CreateTable(pConfig, "docsize", zCols, 0, pzErr);
}
if( rc==SQLITE_OK ){
rc = sqlite3Fts5CreateTable(
@@ -240756,7 +251378,7 @@ static int fts5StorageDeleteFromIndex(
){
Fts5Config *pConfig = p->pConfig;
sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */
- int rc; /* Return code */
+ int rc = SQLITE_OK; /* Return code */
int rc2; /* sqlite3_reset() return code */
int iCol;
Fts5InsertCtx ctx;
@@ -240772,7 +251394,6 @@ static int fts5StorageDeleteFromIndex(
ctx.pStorage = p;
ctx.iCol = -1;
- rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
if( pConfig->abUnindexed[iCol-1]==0 ){
const char *zText;
@@ -240809,6 +251430,37 @@ static int fts5StorageDeleteFromIndex(
return rc;
}
+/*
+** This function is called to process a DELETE on a contentless_delete=1
+** table. It adds the tombstone required to delete the entry with rowid
+** iDel. If successful, SQLITE_OK is returned. Or, if an error occurs,
+** an SQLite error code.
+*/
+static int fts5StorageContentlessDelete(Fts5Storage *p, i64 iDel){
+ i64 iOrigin = 0;
+ sqlite3_stmt *pLookup = 0;
+ int rc = SQLITE_OK;
+
+ assert( p->pConfig->bContentlessDelete );
+ assert( p->pConfig->eContent==FTS5_CONTENT_NONE );
+
+ /* Look up the origin of the document in the %_docsize table. Store
+ ** this in stack variable iOrigin. */
+ rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup, 0);
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_int64(pLookup, 1, iDel);
+ if( SQLITE_ROW==sqlite3_step(pLookup) ){
+ iOrigin = sqlite3_column_int64(pLookup, 1);
+ }
+ rc = sqlite3_reset(pLookup);
+ }
+
+ if( rc==SQLITE_OK && iOrigin!=0 ){
+ rc = sqlite3Fts5IndexContentlessDelete(p->pIndex, iOrigin, iDel);
+ }
+
+ return rc;
+}
/*
** Insert a record into the %_docsize table. Specifically, do:
@@ -240829,10 +251481,17 @@ static int fts5StorageInsertDocsize(
rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0);
if( rc==SQLITE_OK ){
sqlite3_bind_int64(pReplace, 1, iRowid);
- sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
- sqlite3_step(pReplace);
- rc = sqlite3_reset(pReplace);
- sqlite3_bind_null(pReplace, 2);
+ if( p->pConfig->bContentlessDelete ){
+ i64 iOrigin = 0;
+ rc = sqlite3Fts5IndexGetOrigin(p->pIndex, &iOrigin);
+ sqlite3_bind_int64(pReplace, 3, iOrigin);
+ }
+ if( rc==SQLITE_OK ){
+ sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
+ sqlite3_step(pReplace);
+ rc = sqlite3_reset(pReplace);
+ sqlite3_bind_null(pReplace, 2);
+ }
}
}
return rc;
@@ -240896,7 +251555,15 @@ static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **ap
/* Delete the index records */
if( rc==SQLITE_OK ){
- rc = fts5StorageDeleteFromIndex(p, iDel, apVal);
+ rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
+ }
+
+ if( rc==SQLITE_OK ){
+ if( p->pConfig->bContentlessDelete ){
+ rc = fts5StorageContentlessDelete(p, iDel);
+ }else{
+ rc = fts5StorageDeleteFromIndex(p, iDel, apVal);
+ }
}
/* Delete the %_docsize record */
@@ -240973,7 +251640,7 @@ static int sqlite3Fts5StorageRebuild(Fts5Storage *p){
}
if( rc==SQLITE_OK ){
- rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0);
+ rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, pConfig->pzErrmsg);
}
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pScan) ){
@@ -241484,7 +252151,9 @@ static int sqlite3Fts5StorageSync(Fts5Storage *p){
i64 iLastRowid = sqlite3_last_insert_rowid(p->pConfig->db);
if( p->bTotalsValid ){
rc = fts5StorageSaveTotals(p);
- p->bTotalsValid = 0;
+ if( rc==SQLITE_OK ){
+ p->bTotalsValid = 0;
+ }
}
if( rc==SQLITE_OK ){
rc = sqlite3Fts5IndexSync(p->pIndex);
@@ -241758,6 +252427,12 @@ static const unsigned char sqlite3Utf8Trans1[] = {
#endif /* ifndef SQLITE_AMALGAMATION */
+#define FTS5_SKIP_UTF8(zIn) { \
+ if( ((unsigned char)(*(zIn++)))>=0xc0 ){ \
+ while( (((unsigned char)*zIn) & 0xc0)==0x80 ){ zIn++; } \
+ } \
+}
+
typedef struct Unicode61Tokenizer Unicode61Tokenizer;
struct Unicode61Tokenizer {
unsigned char aTokenChar[128]; /* ASCII range token characters */
@@ -242793,6 +253468,7 @@ static int fts5PorterTokenize(
typedef struct TrigramTokenizer TrigramTokenizer;
struct TrigramTokenizer {
int bFold; /* True to fold to lower-case */
+ int iFoldParam; /* Parameter to pass to Fts5UnicodeFold() */
};
/*
@@ -242819,6 +253495,7 @@ static int fts5TriCreate(
}else{
int i;
pNew->bFold = 1;
+ pNew->iFoldParam = 0;
for(i=0; rc==SQLITE_OK && i<nArg; i+=2){
const char *zArg = azArg[i+1];
if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){
@@ -242827,10 +253504,21 @@ static int fts5TriCreate(
}else{
pNew->bFold = (zArg[0]=='0');
}
+ }else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){
+ if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){
+ rc = SQLITE_ERROR;
+ }else{
+ pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0;
+ }
}else{
rc = SQLITE_ERROR;
}
}
+
+ if( pNew->iFoldParam!=0 && pNew->bFold==0 ){
+ rc = SQLITE_ERROR;
+ }
+
if( rc!=SQLITE_OK ){
fts5TriDelete((Fts5Tokenizer*)pNew);
pNew = 0;
@@ -242853,40 +253541,62 @@ static int fts5TriTokenize(
TrigramTokenizer *p = (TrigramTokenizer*)pTok;
int rc = SQLITE_OK;
char aBuf[32];
+ char *zOut = aBuf;
+ int ii;
const unsigned char *zIn = (const unsigned char*)pText;
const unsigned char *zEof = &zIn[nText];
u32 iCode;
+ int aStart[3]; /* Input offset of each character in aBuf[] */
UNUSED_PARAM(unusedFlags);
- while( 1 ){
- char *zOut = aBuf;
- int iStart = zIn - (const unsigned char*)pText;
- const unsigned char *zNext;
-
- READ_UTF8(zIn, zEof, iCode);
- if( iCode==0 ) break;
- zNext = zIn;
- if( zIn<zEof ){
- if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
- WRITE_UTF8(zOut, iCode);
+
+ /* Populate aBuf[] with the characters for the first trigram. */
+ for(ii=0; ii<3; ii++){
+ do {
+ aStart[ii] = zIn - (const unsigned char*)pText;
READ_UTF8(zIn, zEof, iCode);
- if( iCode==0 ) break;
- }else{
- break;
- }
- if( zIn<zEof ){
- if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
- WRITE_UTF8(zOut, iCode);
+ if( iCode==0 ) return SQLITE_OK;
+ if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
+ }while( iCode==0 );
+ WRITE_UTF8(zOut, iCode);
+ }
+
+ /* At the start of each iteration of this loop:
+ **
+ ** aBuf: Contains 3 characters. The 3 characters of the next trigram.
+ ** zOut: Points to the byte following the last character in aBuf.
+ ** aStart[3]: Contains the byte offset in the input text corresponding
+ ** to the start of each of the three characters in the buffer.
+ */
+ assert( zIn<=zEof );
+ while( 1 ){
+ int iNext; /* Start of character following current tri */
+ const char *z1;
+
+ /* Read characters from the input up until the first non-diacritic */
+ do {
+ iNext = zIn - (const unsigned char*)pText;
READ_UTF8(zIn, zEof, iCode);
if( iCode==0 ) break;
- if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, 0);
- WRITE_UTF8(zOut, iCode);
- }else{
- break;
- }
- rc = xToken(pCtx, 0, aBuf, zOut-aBuf, iStart, iStart + zOut-aBuf);
- if( rc!=SQLITE_OK ) break;
- zIn = zNext;
+ if( p->bFold ) iCode = sqlite3Fts5UnicodeFold(iCode, p->iFoldParam);
+ }while( iCode==0 );
+
+ /* Pass the current trigram back to fts5 */
+ rc = xToken(pCtx, 0, aBuf, zOut-aBuf, aStart[0], iNext);
+ if( iCode==0 || rc!=SQLITE_OK ) break;
+
+ /* Remove the first character from buffer aBuf[]. Append the character
+ ** with codepoint iCode. */
+ z1 = aBuf;
+ FTS5_SKIP_UTF8(z1);
+ memmove(aBuf, z1, zOut - z1);
+ zOut -= (z1 - aBuf);
+ WRITE_UTF8(zOut, iCode);
+
+ /* Update the aStart[] array */
+ aStart[0] = aStart[1];
+ aStart[1] = aStart[2];
+ aStart[2] = iNext;
}
return rc;
@@ -242909,7 +253619,9 @@ static int sqlite3Fts5TokenizerPattern(
){
if( xCreate==fts5TriCreate ){
TrigramTokenizer *p = (TrigramTokenizer*)pTok;
- return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB;
+ if( p->iFoldParam==0 ){
+ return p->bFold ? FTS5_PATTERN_LIKE : FTS5_PATTERN_GLOB;
+ }
}
return FTS5_PATTERN_NONE;
}
@@ -244698,7 +255410,7 @@ static int fts5VocabFilterMethod(
if( pEq ){
zTerm = (const char *)sqlite3_value_text(pEq);
nTerm = sqlite3_value_bytes(pEq);
- f = 0;
+ f = FTS5INDEX_QUERY_NOTOKENDATA;
}else{
if( pGe ){
zTerm = (const char *)sqlite3_value_text(pGe);
@@ -244852,7 +255564,8 @@ static int sqlite3Fts5VocabInit(Fts5Global *pGlobal, sqlite3 *db){
/* xSavepoint */ 0,
/* xRelease */ 0,
/* xRollbackTo */ 0,
- /* xShadowName */ 0
+ /* xShadowName */ 0,
+ /* xIntegrity */ 0
};
void *p = (void*)pGlobal;
@@ -245181,6 +255894,7 @@ static sqlite3_module stmtModule = {
0, /* xRelease */
0, /* xRollbackTo */
0, /* xShadowName */
+ 0 /* xIntegrity */
};
#endif /* SQLITE_OMIT_VIRTUALTABLE */
diff --git a/src/3rdparty/sqlite/sqlite3.h b/src/3rdparty/sqlite/sqlite3.h
index 0a3c56c977..2618b37a7b 100644
--- a/src/3rdparty/sqlite/sqlite3.h
+++ b/src/3rdparty/sqlite/sqlite3.h
@@ -146,9 +146,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.41.1"
-#define SQLITE_VERSION_NUMBER 3041001
-#define SQLITE_SOURCE_ID "2023-03-10 12:13:52 20399f3eda5ec249d147ba9e48da6e87f969d7966a9a896764ca437ff7e737ff"
+#define SQLITE_VERSION "3.45.3"
+#define SQLITE_VERSION_NUMBER 3045003
+#define SQLITE_SOURCE_ID "2024-04-15 13:34:05 8653b758870e6ef0c98d46b3ace27849054af85da891eb121e9aaa537f1e8355"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -420,6 +420,8 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
** <li> The application must not modify the SQL statement text passed into
** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
+** <li> The application must not dereference the arrays or string pointers
+** passed as the 3rd and 4th callback parameters after it returns.
** </ul>
*/
SQLITE_API int sqlite3_exec(
@@ -528,6 +530,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8))
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8))
#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8))
+#define SQLITE_IOERR_IN_PAGE (SQLITE_IOERR | (34<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
@@ -1190,7 +1193,7 @@ struct sqlite3_io_methods {
** by clients within the current process, only within other processes.
**
** <li>[[SQLITE_FCNTL_CKSM_FILE]]
-** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use interally by the
+** The [SQLITE_FCNTL_CKSM_FILE] opcode is for use internally by the
** [checksum VFS shim] only.
**
** <li>[[SQLITE_FCNTL_RESET_CACHE]]
@@ -1655,20 +1658,23 @@ SQLITE_API int sqlite3_os_end(void);
** must ensure that no other SQLite interfaces are invoked by other
** threads while sqlite3_config() is running.</b>
**
-** The sqlite3_config() interface
-** may only be invoked prior to library initialization using
-** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()].
-** ^If sqlite3_config() is called after [sqlite3_initialize()] and before
-** [sqlite3_shutdown()] then it will return SQLITE_MISUSE.
-** Note, however, that ^sqlite3_config() can be called as part of the
-** implementation of an application-defined [sqlite3_os_init()].
-**
** The first argument to sqlite3_config() is an integer
** [configuration option] that determines
** what property of SQLite is to be configured. Subsequent arguments
** vary depending on the [configuration option]
** in the first argument.
**
+** For most configuration options, the sqlite3_config() interface
+** may only be invoked prior to library initialization using
+** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()].
+** The exceptional configuration options that may be invoked at any time
+** are called "anytime configuration options".
+** ^If sqlite3_config() is called after [sqlite3_initialize()] and before
+** [sqlite3_shutdown()] with a first argument that is not an anytime
+** configuration option, then the sqlite3_config() call will return SQLITE_MISUSE.
+** Note, however, that ^sqlite3_config() can be called as part of the
+** implementation of an application-defined [sqlite3_os_init()].
+**
** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK].
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
@@ -1776,6 +1782,23 @@ struct sqlite3_mem_methods {
** These constants are the available integer configuration options that
** can be passed as the first argument to the [sqlite3_config()] interface.
**
+** Most of the configuration options for sqlite3_config()
+** will only work if invoked prior to [sqlite3_initialize()] or after
+** [sqlite3_shutdown()]. The few exceptions to this rule are called
+** "anytime configuration options".
+** ^Calling [sqlite3_config()] with a first argument that is not an
+** anytime configuration option in between calls to [sqlite3_initialize()] and
+** [sqlite3_shutdown()] is a no-op that returns SQLITE_MISUSE.
+**
+** The set of anytime configuration options can change (by insertions
+** and/or deletions) from one release of SQLite to the next.
+** As of SQLite version 3.42.0, the complete set of anytime configuration
+** options is:
+** <ul>
+** <li> SQLITE_CONFIG_LOG
+** <li> SQLITE_CONFIG_PCACHE_HDRSZ
+** </ul>
+**
** New configuration options may be added in future releases of SQLite.
** Existing configuration options might be discontinued. Applications
** should check the return code from [sqlite3_config()] to make sure that
@@ -2106,7 +2129,7 @@ struct sqlite3_mem_methods {
** is stored in each sorted record and the required column values loaded
** from the database as records are returned in sorted order. The default
** value for this option is to never use this optimization. Specifying a
-** negative value for this option restores the default behaviour.
+** negative value for this option restores the default behavior.
** This option is only available if SQLite is compiled with the
** [SQLITE_ENABLE_SORTER_REFERENCES] compile-time option.
**
@@ -2120,30 +2143,46 @@ struct sqlite3_mem_methods {
** configuration setting is never used, then the default maximum is determined
** by the [SQLITE_MEMDB_DEFAULT_MAXSIZE] compile-time option. If that
** compile-time option is not set, then the default maximum is 1073741824.
+**
+** [[SQLITE_CONFIG_ROWID_IN_VIEW]]
+** <dt>SQLITE_CONFIG_ROWID_IN_VIEW
+** <dd>The SQLITE_CONFIG_ROWID_IN_VIEW option enables or disables the ability
+** for VIEWs to have a ROWID. The capability can only be enabled if SQLite is
+** compiled with -DSQLITE_ALLOW_ROWID_IN_VIEW, in which case the capability
+** defaults to on. This configuration option queries the current setting or
+** changes the setting to off or on. The argument is a pointer to an integer.
+** If that integer initially holds a value of 1, then the ability for VIEWs to
+** have ROWIDs is activated. If the integer initially holds zero, then the
+** ability is deactivated. Any other initial value for the integer leaves the
+** setting unchanged. After changes, if any, the integer is written with
+** a 1 or 0, if the ability for VIEWs to have ROWIDs is on or off. If SQLite
+** is compiled without -DSQLITE_ALLOW_ROWID_IN_VIEW (which is the usual and
+** recommended case) then the integer is always filled with zero, regardless
+** if its initial value.
** </dl>
*/
-#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
-#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
-#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
-#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */
-#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */
-#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
-#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
-#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
-#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
-#define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */
-#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */
-/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
-#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
-#define SQLITE_CONFIG_PCACHE 14 /* no-op */
-#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */
-#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
-#define SQLITE_CONFIG_URI 17 /* int */
-#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */
-#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
+#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
+#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
+#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */
+#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */
+#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
+#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
+#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
+#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
+#define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */
+#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */
+/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
+#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
+#define SQLITE_CONFIG_PCACHE 14 /* no-op */
+#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */
+#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
+#define SQLITE_CONFIG_URI 17 /* int */
+#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
-#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
-#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
+#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
+#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
@@ -2151,6 +2190,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_SMALL_MALLOC 27 /* boolean */
#define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */
#define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */
+#define SQLITE_CONFIG_ROWID_IN_VIEW 30 /* int* */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -2281,7 +2321,7 @@ struct sqlite3_mem_methods {
** 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
+** override this behavior. The first parameter passed to this operation
** is an integer - positive to disable checkpoints-on-close, or zero (the
** default) to enable them, and negative to leave the setting unchanged.
** The second parameter is a pointer to an integer
@@ -2378,7 +2418,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DML]]
-** <dt>SQLITE_DBCONFIG_DQS_DML</td>
+** <dt>SQLITE_DBCONFIG_DQS_DML</dt>
** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DML statements
** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
@@ -2387,7 +2427,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DDL]]
-** <dt>SQLITE_DBCONFIG_DQS_DDL</td>
+** <dt>SQLITE_DBCONFIG_DQS_DDL</dt>
** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DDL statements,
** such as CREATE TABLE and CREATE INDEX. The
@@ -2396,7 +2436,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
-** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td>
+** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</dt>
** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
** assume that database schemas are untainted by malicious content.
** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
@@ -2416,7 +2456,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]]
-** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</td>
+** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</dt>
** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
** the legacy file format flag. When activated, this flag causes all newly
** created database file to have a schema format version number (the 4-byte
@@ -2425,7 +2465,7 @@ struct sqlite3_mem_methods {
** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting,
** newly created databases are generally not understandable by SQLite versions
** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there
-** is now scarcely any need to generated database files that are compatible
+** is now scarcely any need to generate database files that are compatible
** all the way back to version 3.0.0, and so this setting is of little
** practical use, but is provided so that SQLite can continue to claim the
** ability to generate new database files that are compatible with version
@@ -2434,8 +2474,40 @@ struct sqlite3_mem_methods {
** the [VACUUM] command will fail with an obscure error when attempting to
** process a table with generated columns and a descending index. This is
** not considered a bug since SQLite versions 3.3.0 and earlier do not support
-** either generated columns or decending indexes.
+** either generated columns or descending indexes.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]]
+** <dt>SQLITE_DBCONFIG_STMT_SCANSTATUS</dt>
+** <dd>The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in
+** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears
+** a flag that enables collection of the sqlite3_stmt_scanstatus_v2()
+** statistics. For statistics to be collected, the flag must be set on
+** the database handle both when the SQL statement is prepared and when it
+** is stepped. The flag is set (collection of statistics is enabled)
+** by default. This option takes two arguments: an integer and a pointer to
+** an integer.. The first argument is 1, 0, or -1 to enable, disable, or
+** leave unchanged the statement scanstatus option. If the second argument
+** is not NULL, then the value of the statement scanstatus setting after
+** processing the first argument is written into the integer that the second
+** argument points to.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_REVERSE_SCANORDER]]
+** <dt>SQLITE_DBCONFIG_REVERSE_SCANORDER</dt>
+** <dd>The SQLITE_DBCONFIG_REVERSE_SCANORDER option changes the default order
+** in which tables and indexes are scanned so that the scans start at the end
+** and work toward the beginning rather than starting at the beginning and
+** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the
+** same as setting [PRAGMA reverse_unordered_selects]. This option takes
+** two arguments which are an integer and a pointer to an integer. The first
+** argument is 1, 0, or -1 to enable, disable, or leave unchanged the
+** reverse scan order flag, respectively. If the second argument is not NULL,
+** then 0 or 1 is written into the integer that the second argument points to
+** depending on if the reverse scan order flag is set after processing the
+** first argument.
** </dd>
+**
** </dl>
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
@@ -2456,7 +2528,9 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */
#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */
-#define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */
+#define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */
+#define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */
+#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@@ -2681,6 +2755,7 @@ SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3*);
**
** ^The [sqlite3_is_interrupted(D)] interface can be used to determine whether
** or not an interrupt is currently in effect for [database connection] D.
+** It returns 1 if an interrupt is currently in effect, or 0 otherwise.
*/
SQLITE_API void sqlite3_interrupt(sqlite3*);
SQLITE_API int sqlite3_is_interrupted(sqlite3*);
@@ -3334,8 +3409,10 @@ SQLITE_API SQLITE_DEPRECATED void *sqlite3_profile(sqlite3*,
** 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().
+** ^Each call to either sqlite3_trace(D,X,P) or sqlite3_trace_v2(D,M,X,P)
+** overrides (cancels) all prior calls to sqlite3_trace(D,X,P) or
+** sqlite3_trace_v2(D,M,X,P) for the [database connection] D. Each
+** database connection may have at most one trace callback.
**
** ^The X callback is invoked whenever any of the events identified by
** mask M occur. ^The integer return value from the callback is currently
@@ -3704,7 +3781,7 @@ SQLITE_API int sqlite3_open_v2(
** as F) must be one of:
** <ul>
** <li> A database filename pointer created by the SQLite core and
-** passed into the xOpen() method of a VFS implemention, or
+** passed into the xOpen() method of a VFS implementation, or
** <li> A filename obtained from [sqlite3_db_filename()], or
** <li> A new filename constructed using [sqlite3_create_filename()].
** </ul>
@@ -3817,7 +3894,7 @@ SQLITE_API sqlite3_file *sqlite3_database_file_object(const char*);
/*
** CAPI3REF: Create and Destroy VFS Filenames
**
-** These interfces are provided for use by [VFS shim] implementations and
+** These interfaces are provided for use by [VFS shim] implementations and
** are not useful outside of that context.
**
** The sqlite3_create_filename(D,J,W,N,P) allocates memory to hold a version of
@@ -3896,14 +3973,17 @@ SQLITE_API void sqlite3_free_filename(sqlite3_filename);
** </ul>
**
** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
-** text that describes the error, as either UTF-8 or UTF-16 respectively.
+** text that describes the error, as either UTF-8 or UTF-16 respectively,
+** or NULL if no error message is available.
+** (See how SQLite handles [invalid UTF] for exceptions to this rule.)
** ^(Memory to hold the error message string is managed internally.
** The application does not need to worry about freeing the result.
** However, the error string might be overwritten or deallocated by
** subsequent calls to other SQLite interface functions.)^
**
-** ^The sqlite3_errstr() interface returns the English-language text
-** that describes the [result code], as UTF-8.
+** ^The sqlite3_errstr(E) interface returns the English-language text
+** that describes the [result code] E, as UTF-8, or NULL if E is not an
+** result code for which a text error message is available.
** ^(Memory to hold the error message string is managed internally
** and must not be freed by the application)^.
**
@@ -4365,6 +4445,41 @@ SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
SQLITE_API int sqlite3_stmt_isexplain(sqlite3_stmt *pStmt);
/*
+** CAPI3REF: Change The EXPLAIN Setting For A Prepared Statement
+** METHOD: sqlite3_stmt
+**
+** The sqlite3_stmt_explain(S,E) interface changes the EXPLAIN
+** setting for [prepared statement] S. If E is zero, then S becomes
+** a normal prepared statement. If E is 1, then S behaves as if
+** its SQL text began with "[EXPLAIN]". If E is 2, then S behaves as if
+** its SQL text began with "[EXPLAIN QUERY PLAN]".
+**
+** Calling sqlite3_stmt_explain(S,E) might cause S to be reprepared.
+** SQLite tries to avoid a reprepare, but a reprepare might be necessary
+** on the first transition into EXPLAIN or EXPLAIN QUERY PLAN mode.
+**
+** Because of the potential need to reprepare, a call to
+** sqlite3_stmt_explain(S,E) will fail with SQLITE_ERROR if S cannot be
+** reprepared because it was created using [sqlite3_prepare()] instead of
+** the newer [sqlite3_prepare_v2()] or [sqlite3_prepare_v3()] interfaces and
+** hence has no saved SQL text with which to reprepare.
+**
+** Changing the explain setting for a prepared statement does not change
+** the original SQL text for the statement. Hence, if the SQL text originally
+** began with EXPLAIN or EXPLAIN QUERY PLAN, but sqlite3_stmt_explain(S,0)
+** is called to convert the statement into an ordinary statement, the EXPLAIN
+** or EXPLAIN QUERY PLAN keywords will still appear in the sqlite3_sql(S)
+** output, even though the statement now acts like a normal SQL statement.
+**
+** This routine returns SQLITE_OK if the explain mode is successfully
+** changed, or an error code if the explain mode could not be changed.
+** The explain mode cannot be changed while a statement is active.
+** Hence, it is good practice to call [sqlite3_reset(S)]
+** immediately prior to calling sqlite3_stmt_explain(S,E).
+*/
+SQLITE_API int sqlite3_stmt_explain(sqlite3_stmt *pStmt, int eMode);
+
+/*
** CAPI3REF: Determine If A Prepared Statement Has Been Reset
** METHOD: sqlite3_stmt
**
@@ -4527,7 +4642,7 @@ typedef struct sqlite3_context sqlite3_context;
** with it may be passed. ^It is called to dispose of the BLOB or string even
** if the call to the bind API fails, except the destructor is not called if
** the third parameter is a NULL pointer or the fourth parameter is negative.
-** ^ (2) The special constant, [SQLITE_STATIC], may be passsed to indicate that
+** ^ (2) The special constant, [SQLITE_STATIC], may be passed to indicate that
** the application remains responsible for disposing of the object. ^In this
** case, the object and the provided pointer to it must remain valid until
** either the prepared statement is finalized or the same SQL parameter is
@@ -5206,20 +5321,33 @@ SQLITE_API int sqlite3_finalize(sqlite3_stmt *pStmt);
** ^The [sqlite3_reset(S)] interface resets the [prepared statement] S
** back to the beginning of its program.
**
-** ^If the most recent call to [sqlite3_step(S)] for the
-** [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE],
-** or if [sqlite3_step(S)] has never before been called on S,
-** then [sqlite3_reset(S)] returns [SQLITE_OK].
+** ^The return code from [sqlite3_reset(S)] indicates whether or not
+** the previous evaluation of prepared statement S completed successfully.
+** ^If [sqlite3_step(S)] has never before been called on S or if
+** [sqlite3_step(S)] has not been called since the previous call
+** to [sqlite3_reset(S)], then [sqlite3_reset(S)] will return
+** [SQLITE_OK].
**
** ^If the most recent call to [sqlite3_step(S)] for the
** [prepared statement] S indicated an error, then
** [sqlite3_reset(S)] returns an appropriate [error code].
+** ^The [sqlite3_reset(S)] interface might also return an [error code]
+** if there were no prior errors but the process of resetting
+** the prepared statement caused a new error. ^For example, if an
+** [INSERT] statement with a [RETURNING] clause is only stepped one time,
+** that one call to [sqlite3_step(S)] might return SQLITE_ROW but
+** the overall statement might still fail and the [sqlite3_reset(S)] call
+** might return SQLITE_BUSY if locking constraints prevent the
+** database change from committing. Therefore, it is important that
+** applications check the return code from [sqlite3_reset(S)] even if
+** no prior call to [sqlite3_step(S)] indicated a problem.
**
** ^The [sqlite3_reset(S)] interface does not change the values
** of any [sqlite3_bind_blob|bindings] on the [prepared statement] S.
*/
SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
+
/*
** CAPI3REF: Create Or Redefine SQL Functions
** KEYWORDS: {function creation routines}
@@ -5430,7 +5558,7 @@ SQLITE_API int sqlite3_create_window_function(
** [application-defined SQL function]
** that has side-effects or that could potentially leak sensitive information.
** This will prevent attacks in which an application is tricked
-** into using a database file that has had its schema surreptiously
+** into using a database file that has had its schema surreptitiously
** modified to invoke the application-defined function in ways that are
** harmful.
** <p>
@@ -5466,13 +5594,27 @@ SQLITE_API int sqlite3_create_window_function(
** </dd>
**
** [[SQLITE_SUBTYPE]] <dt>SQLITE_SUBTYPE</dt><dd>
-** The SQLITE_SUBTYPE flag indicates to SQLite that a function may call
+** The SQLITE_SUBTYPE flag indicates to SQLite that a function might call
** [sqlite3_value_subtype()] to inspect the sub-types of its arguments.
-** Specifying this flag makes no difference for scalar or aggregate user
-** functions. However, if it is not specified for a user-defined window
-** function, then any sub-types belonging to arguments passed to the window
-** function may be discarded before the window function is called (i.e.
-** sqlite3_value_subtype() will always return 0).
+** This flag instructs SQLite to omit some corner-case optimizations that
+** might disrupt the operation of the [sqlite3_value_subtype()] function,
+** causing it to return zero rather than the correct subtype().
+** SQL functions that invokes [sqlite3_value_subtype()] should have this
+** property. If the SQLITE_SUBTYPE property is omitted, then the return
+** value from [sqlite3_value_subtype()] might sometimes be zero even though
+** a non-zero subtype was specified by the function argument expression.
+**
+** [[SQLITE_RESULT_SUBTYPE]] <dt>SQLITE_RESULT_SUBTYPE</dt><dd>
+** The SQLITE_RESULT_SUBTYPE flag indicates to SQLite that a function might call
+** [sqlite3_result_subtype()] to cause a sub-type to be associated with its
+** result.
+** Every function that invokes [sqlite3_result_subtype()] should have this
+** property. If it does not, then the call to [sqlite3_result_subtype()]
+** might become a no-op if the function is used as term in an
+** [expression index]. On the other hand, SQL functions that never invoke
+** [sqlite3_result_subtype()] should avoid setting this property, as the
+** purpose of this property is to disable certain optimizations that are
+** incompatible with subtypes.
** </dd>
** </dl>
*/
@@ -5480,6 +5622,7 @@ SQLITE_API int sqlite3_create_window_function(
#define SQLITE_DIRECTONLY 0x000080000
#define SQLITE_SUBTYPE 0x000100000
#define SQLITE_INNOCUOUS 0x000200000
+#define SQLITE_RESULT_SUBTYPE 0x001000000
/*
** CAPI3REF: Deprecated Functions
@@ -5676,6 +5819,12 @@ SQLITE_API int sqlite3_value_encoding(sqlite3_value*);
** information can be used to pass a limited amount of context from
** one SQL function to another. Use the [sqlite3_result_subtype()]
** routine to set the subtype for the return value of an SQL function.
+**
+** Every [application-defined SQL function] that invoke this interface
+** should include the [SQLITE_SUBTYPE] property in the text
+** encoding argument when the function is [sqlite3_create_function|registered].
+** If the [SQLITE_SUBTYPE] property is omitted, then sqlite3_value_subtype()
+** might return zero instead of the upstream subtype in some corner cases.
*/
SQLITE_API unsigned int sqlite3_value_subtype(sqlite3_value*);
@@ -5774,48 +5923,56 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
** METHOD: sqlite3_context
**
** These functions may be used by (non-aggregate) SQL functions to
-** associate metadata with argument values. If the same value is passed to
-** multiple invocations of the same SQL function during query execution, under
-** some circumstances the associated metadata may be preserved. An example
-** of where this might be useful is in a regular-expression matching
-** function. The compiled version of the regular expression can be stored as
-** metadata associated with the pattern string.
+** associate auxiliary data with argument values. If the same argument
+** value is passed to multiple invocations of the same SQL function during
+** query execution, under some circumstances the associated auxiliary data
+** might be preserved. An example of where this might be useful is in a
+** regular-expression matching function. The compiled version of the regular
+** expression can be stored as auxiliary data associated with the pattern string.
** Then as long as the pattern string remains the same,
** the compiled regular expression can be reused on multiple
** invocations of the same function.
**
-** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the metadata
+** ^The sqlite3_get_auxdata(C,N) interface returns a pointer to the auxiliary data
** associated by the sqlite3_set_auxdata(C,N,P,X) function with the Nth argument
** value to the application-defined function. ^N is zero for the left-most
-** function argument. ^If there is no metadata
+** function argument. ^If there is no auxiliary data
** associated with the function argument, the sqlite3_get_auxdata(C,N) interface
** returns a NULL pointer.
**
-** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as metadata for the N-th
-** argument of the application-defined function. ^Subsequent
+** ^The sqlite3_set_auxdata(C,N,P,X) interface saves P as auxiliary data for the
+** N-th argument of the application-defined function. ^Subsequent
** calls to sqlite3_get_auxdata(C,N) return P from the most recent
-** sqlite3_set_auxdata(C,N,P,X) call if the metadata is still valid or
-** NULL if the metadata has been discarded.
+** sqlite3_set_auxdata(C,N,P,X) call if the auxiliary data is still valid or
+** NULL if the auxiliary data has been discarded.
** ^After each call to sqlite3_set_auxdata(C,N,P,X) where X is not NULL,
** 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>
+** once, when the auxiliary data is discarded.
+** SQLite is free to discard the auxiliary data 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>
+** allocation error occurs.)^
+** <li> ^(during the original sqlite3_set_auxdata() call if the function
+** is evaluated during query planning instead of during query execution,
+** as sometimes happens with [SQLITE_ENABLE_STAT4].)^ </ul>
**
-** Note the last bullet in particular. The destructor X in
+** Note the last two bullets in particular. The destructor X in
** sqlite3_set_auxdata(C,N,P,X) might be called immediately, before the
** sqlite3_set_auxdata() interface even returns. Hence sqlite3_set_auxdata()
** should be called near the end of the function implementation and the
** function implementation should not make any use of P after
-** sqlite3_set_auxdata() has been called.
-**
-** ^(In practice, metadata is preserved between function calls for
+** sqlite3_set_auxdata() has been called. Furthermore, a call to
+** sqlite3_get_auxdata() that occurs immediately after a corresponding call
+** to sqlite3_set_auxdata() might still return NULL if an out-of-memory
+** condition occurred during the sqlite3_set_auxdata() call or if the
+** function is being evaluated during query planning rather than during
+** query execution.
+**
+** ^(In practice, auxiliary data is preserved between function calls for
** function parameters that are compile-time constants, including literal
** values and [parameters] and expressions composed from the same.)^
**
@@ -5825,10 +5982,67 @@ SQLITE_API sqlite3 *sqlite3_context_db_handle(sqlite3_context*);
**
** These routines must be called from the same thread in which
** the SQL function is running.
+**
+** See also: [sqlite3_get_clientdata()] and [sqlite3_set_clientdata()].
*/
SQLITE_API void *sqlite3_get_auxdata(sqlite3_context*, int N);
SQLITE_API void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
+/*
+** CAPI3REF: Database Connection Client Data
+** METHOD: sqlite3
+**
+** These functions are used to associate one or more named pointers
+** with a [database connection].
+** A call to sqlite3_set_clientdata(D,N,P,X) causes the pointer P
+** to be attached to [database connection] D using name N. Subsequent
+** calls to sqlite3_get_clientdata(D,N) will return a copy of pointer P
+** or a NULL pointer if there were no prior calls to
+** sqlite3_set_clientdata() with the same values of D and N.
+** Names are compared using strcmp() and are thus case sensitive.
+**
+** If P and X are both non-NULL, then the destructor X is invoked with
+** argument P on the first of the following occurrences:
+** <ul>
+** <li> An out-of-memory error occurs during the call to
+** sqlite3_set_clientdata() which attempts to register pointer P.
+** <li> A subsequent call to sqlite3_set_clientdata(D,N,P,X) is made
+** with the same D and N parameters.
+** <li> The database connection closes. SQLite does not make any guarantees
+** about the order in which destructors are called, only that all
+** destructors will be called exactly once at some point during the
+** database connection closing process.
+** </ul>
+**
+** SQLite does not do anything with client data other than invoke
+** destructors on the client data at the appropriate time. The intended
+** use for client data is to provide a mechanism for wrapper libraries
+** to store additional information about an SQLite database connection.
+**
+** There is no limit (other than available memory) on the number of different
+** client data pointers (with different names) that can be attached to a
+** single database connection. However, the implementation is optimized
+** for the case of having only one or two different client data names.
+** Applications and wrapper libraries are discouraged from using more than
+** one client data name each.
+**
+** There is no way to enumerate the client data pointers
+** associated with a database connection. The N parameter can be thought
+** of as a secret key such that only code that knows the secret key is able
+** to access the associated data.
+**
+** Security Warning: These interfaces should not be exposed in scripting
+** languages or in other circumstances where it might be possible for an
+** an attacker to invoke them. Any agent that can invoke these interfaces
+** can probably also take control of the process.
+**
+** Database connection client data is only available for SQLite
+** version 3.44.0 ([dateof:3.44.0]) and later.
+**
+** See also: [sqlite3_set_auxdata()] and [sqlite3_get_auxdata()].
+*/
+SQLITE_API void *sqlite3_get_clientdata(sqlite3*,const char*);
+SQLITE_API int sqlite3_set_clientdata(sqlite3*, const char*, void*, void(*)(void*));
/*
** CAPI3REF: Constants Defining Special Destructor Behavior
@@ -6030,6 +6244,20 @@ SQLITE_API int sqlite3_result_zeroblob64(sqlite3_context*, sqlite3_uint64 n);
** higher order bits are discarded.
** The number of subtype bytes preserved by SQLite might increase
** in future releases of SQLite.
+**
+** Every [application-defined SQL function] that invokes this interface
+** should include the [SQLITE_RESULT_SUBTYPE] property in its
+** text encoding argument when the SQL function is
+** [sqlite3_create_function|registered]. If the [SQLITE_RESULT_SUBTYPE]
+** property is omitted from the function that invokes sqlite3_result_subtype(),
+** then in some cases the sqlite3_result_subtype() might fail to set
+** the result subtype.
+**
+** If SQLite is compiled with -DSQLITE_STRICT_SUBTYPE=1, then any
+** SQL function that invokes the sqlite3_result_subtype() interface
+** and that does not have the SQLITE_RESULT_SUBTYPE property will raise
+** an error. Future versions of SQLite might enable -DSQLITE_STRICT_SUBTYPE=1
+** by default.
*/
SQLITE_API void sqlite3_result_subtype(sqlite3_context*,unsigned int);
@@ -6201,6 +6429,13 @@ SQLITE_API void sqlite3_activate_cerod(
** of the default VFS is not implemented correctly, or not implemented at
** all, then the behavior of sqlite3_sleep() may deviate from the description
** in the previous paragraphs.
+**
+** If a negative argument is passed to sqlite3_sleep() the results vary by
+** VFS and operating system. Some system treat a negative argument as an
+** instruction to sleep forever. Others understand it to mean do not sleep
+** at all. ^In SQLite version 3.42.0 and later, a negative
+** argument passed into sqlite3_sleep() is changed to zero before it is relayed
+** down into the xSleep method of the VFS.
*/
SQLITE_API int sqlite3_sleep(int);
@@ -6454,7 +6689,7 @@ SQLITE_API int sqlite3_db_readonly(sqlite3 *db, const char *zDbName);
SQLITE_API int sqlite3_txn_state(sqlite3*,const char *zSchema);
/*
-** CAPI3REF: Allowed return values from [sqlite3_txn_state()]
+** CAPI3REF: Allowed return values from sqlite3_txn_state()
** KEYWORDS: {transaction state}
**
** These constants define the current transaction state of a database file.
@@ -6586,7 +6821,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
** ^Each call to the sqlite3_autovacuum_pages() interface overrides all
** previous invocations for that database connection. ^If the callback
** argument (C) to sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer,
-** then the autovacuum steps callback is cancelled. The return value
+** then the autovacuum steps callback is canceled. The return value
** from sqlite3_autovacuum_pages() is normally SQLITE_OK, but might
** be some other error code if something goes wrong. The current
** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other
@@ -7105,6 +7340,10 @@ struct sqlite3_module {
/* The methods above are in versions 1 and 2 of the sqlite_module object.
** Those below are for version 3 and greater. */
int (*xShadowName)(const char*);
+ /* The methods above are in versions 1 through 3 of the sqlite_module object.
+ ** Those below are for version 4 and greater. */
+ int (*xIntegrity)(sqlite3_vtab *pVTab, const char *zSchema,
+ const char *zTabName, int mFlags, char **pzErr);
};
/*
@@ -7592,7 +7831,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);
** code is returned and the transaction rolled back.
**
** Calling this function with an argument that is not a NULL pointer or an
-** open blob handle results in undefined behaviour. ^Calling this routine
+** open blob handle results in undefined behavior. ^Calling this routine
** with a null pointer (such as would be returned by a failed call to
** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function
** is passed a valid open blob handle, the values returned by the
@@ -7819,18 +8058,20 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
**
** ^(Some systems (for example, Windows 95) do not support the operation
** implemented by sqlite3_mutex_try(). On those systems, sqlite3_mutex_try()
-** will always return SQLITE_BUSY. The SQLite core only ever uses
-** sqlite3_mutex_try() as an optimization so this is acceptable
-** behavior.)^
+** will always return SQLITE_BUSY. In most cases the SQLite core only uses
+** sqlite3_mutex_try() as an optimization, so this is acceptable
+** behavior. The exceptions are unix builds that set the
+** SQLITE_ENABLE_SETLK_TIMEOUT build option. In that case a working
+** sqlite3_mutex_try() is required.)^
**
** ^The sqlite3_mutex_leave() routine exits a mutex that was
** previously entered by the same thread. The behavior
** is undefined if the mutex is not currently entered by the
** calling thread or is not currently allocated.
**
-** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or
-** sqlite3_mutex_leave() is a NULL pointer, then all three routines
-** behave as no-ops.
+** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(),
+** sqlite3_mutex_leave(), or sqlite3_mutex_free() is a NULL pointer,
+** then any of the four routines behaves as a no-op.
**
** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
*/
@@ -8072,6 +8313,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_PRNG_SAVE 5
#define SQLITE_TESTCTRL_PRNG_RESTORE 6
#define SQLITE_TESTCTRL_PRNG_RESET 7 /* NOT USED */
+#define SQLITE_TESTCTRL_FK_NO_ACTION 7
#define SQLITE_TESTCTRL_BITVEC_TEST 8
#define SQLITE_TESTCTRL_FAULT_INSTALL 9
#define SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS 10
@@ -8079,6 +8321,7 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_ASSERT 12
#define SQLITE_TESTCTRL_ALWAYS 13
#define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */
+#define SQLITE_TESTCTRL_JSON_SELFCHECK 14
#define SQLITE_TESTCTRL_OPTIMIZATIONS 15
#define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */
@@ -8100,7 +8343,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_TRACEFLAGS 31
#define SQLITE_TESTCTRL_TUNE 32
#define SQLITE_TESTCTRL_LOGEST 33
-#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */
+#define SQLITE_TESTCTRL_USELONGDOUBLE 34
+#define SQLITE_TESTCTRL_LAST 34 /* Largest TESTCTRL */
/*
** CAPI3REF: SQL Keyword Checking
@@ -9556,7 +9800,7 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
** [[SQLITE_VTAB_DIRECTONLY]]<dt>SQLITE_VTAB_DIRECTONLY</dt>
** <dd>Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_DIRECTONLY) from within the
-** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** prohibits that virtual table from being used from within triggers and
** views.
** </dd>
@@ -9564,18 +9808,28 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt>
** <dd>Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
-** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** identify that virtual table as being safe to use from within triggers
** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
** virtual table can do no serious harm even if it is controlled by a
** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS
** flag unless absolutely necessary.
** </dd>
+**
+** [[SQLITE_VTAB_USES_ALL_SCHEMAS]]<dt>SQLITE_VTAB_USES_ALL_SCHEMAS</dt>
+** <dd>Calls of the form
+** [sqlite3_vtab_config](db,SQLITE_VTAB_USES_ALL_SCHEMA) from within the
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
+** instruct the query planner to begin at least a read transaction on
+** all schemas ("main", "temp", and any ATTACH-ed databases) whenever the
+** virtual table is used.
+** </dd>
** </dl>
*/
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
#define SQLITE_VTAB_INNOCUOUS 2
#define SQLITE_VTAB_DIRECTONLY 3
+#define SQLITE_VTAB_USES_ALL_SCHEMAS 4
/*
** CAPI3REF: Determine The Virtual Table Conflict Policy
@@ -9736,7 +9990,7 @@ SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info*);
** communicated to the xBestIndex method as a
** [SQLITE_INDEX_CONSTRAINT_EQ] constraint.)^ If xBestIndex wants to use
** this constraint, it must set the corresponding
-** aConstraintUsage[].argvIndex to a postive integer. ^(Then, under
+** aConstraintUsage[].argvIndex to a positive integer. ^(Then, under
** the usual mode of handling IN operators, SQLite generates [bytecode]
** that invokes the [xFilter|xFilter() method] once for each value
** on the right-hand side of the IN operator.)^ Thus the virtual table
@@ -10165,7 +10419,7 @@ SQLITE_API int sqlite3_db_cacheflush(sqlite3*);
** When the [sqlite3_blob_write()] API is used to update a blob column,
** the pre-update hook is invoked with SQLITE_DELETE. This is because the
** in this case the new values are not available. In this case, when a
-** callback made with op==SQLITE_DELETE is actuall a write using the
+** callback made with op==SQLITE_DELETE is actually a write using the
** sqlite3_blob_write() API, the [sqlite3_preupdate_blobwrite()] returns
** the index of the column being written. In other cases, where the
** pre-update hook is being invoked for some other reason, including a
@@ -10426,6 +10680,13 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const c
** SQLITE_SERIALIZE_NOCOPY bit is set but no contiguous copy
** of the database exists.
**
+** After the call, if the SQLITE_SERIALIZE_NOCOPY bit had been set,
+** the returned buffer content will remain accessible and unchanged
+** until either the next write operation on the connection or when
+** the connection is closed, and applications must not modify the
+** buffer. If the bit had been clear, the returned buffer will not
+** be accessed by SQLite after the call.
+**
** A call to sqlite3_serialize(D,S,P,F) might return NULL even if the
** SQLITE_SERIALIZE_NOCOPY bit is omitted from argument F if a memory
** allocation error occurs.
@@ -10474,6 +10735,9 @@ SQLITE_API unsigned char *sqlite3_serialize(
** SQLite will try to increase the buffer size using sqlite3_realloc64()
** if writes on the database cause it to grow larger than M bytes.
**
+** Applications must not modify the buffer P or invalidate it before
+** the database connection D is closed.
+**
** The sqlite3_deserialize() interface will fail with SQLITE_BUSY if the
** database is currently in a read transaction or is involved in a backup
** operation.
@@ -10482,6 +10746,13 @@ SQLITE_API unsigned char *sqlite3_serialize(
** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the
** function returns SQLITE_ERROR.
**
+** The deserialized database should not be in [WAL mode]. If the database
+** is in WAL mode, then any attempt to use the database file will result
+** in an [SQLITE_CANTOPEN] error. The application can set the
+** [file format version numbers] (bytes 18 and 19) of the input database P
+** to 0x01 prior to invoking sqlite3_deserialize(D,S,P,N,M,F) to force the
+** database file into rollback mode and work around this limitation.
+**
** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the
** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then
** [sqlite3_free()] is invoked on argument P prior to returning.
@@ -10750,16 +11021,20 @@ SQLITE_API int sqlite3session_create(
SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
/*
-** CAPIREF: Conigure a Session Object
+** CAPI3REF: Configure a Session Object
** METHOD: sqlite3_session
**
** This method is used to configure a session object after it has been
-** created. At present the only valid value for the second parameter is
-** [SQLITE_SESSION_OBJCONFIG_SIZE].
+** created. At present the only valid values for the second parameter are
+** [SQLITE_SESSION_OBJCONFIG_SIZE] and [SQLITE_SESSION_OBJCONFIG_ROWID].
**
-** Arguments for sqlite3session_object_config()
+*/
+SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg);
+
+/*
+** CAPI3REF: Options for sqlite3session_object_config
**
-** The following values may passed as the the 4th parameter to
+** The following values may passed as the the 2nd parameter to
** sqlite3session_object_config().
**
** <dt>SQLITE_SESSION_OBJCONFIG_SIZE <dd>
@@ -10775,12 +11050,21 @@ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
**
** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
** the first table has been attached to the session object.
+**
+** <dt>SQLITE_SESSION_OBJCONFIG_ROWID <dd>
+** This option is used to set, clear or query the flag that enables
+** collection of data for tables with no explicit PRIMARY KEY.
+**
+** Normally, tables with no explicit PRIMARY KEY are simply ignored
+** by the sessions module. However, if this flag is set, it behaves
+** as if such tables have a column "_rowid_ INTEGER PRIMARY KEY" inserted
+** as their leftmost columns.
+**
+** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
+** the first table has been attached to the session object.
*/
-SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg);
-
-/*
-*/
-#define SQLITE_SESSION_OBJCONFIG_SIZE 1
+#define SQLITE_SESSION_OBJCONFIG_SIZE 1
+#define SQLITE_SESSION_OBJCONFIG_ROWID 2
/*
** CAPI3REF: Enable Or Disable A Session Object
@@ -11542,6 +11826,18 @@ SQLITE_API int sqlite3changeset_concat(
/*
+** CAPI3REF: Upgrade the Schema of a Changeset/Patchset
+*/
+SQLITE_API int sqlite3changeset_upgrade(
+ sqlite3 *db,
+ const char *zDb,
+ int nIn, const void *pIn, /* Input changeset */
+ int *pnOut, void **ppOut /* OUT: Inverse of input */
+);
+
+
+
+/*
** CAPI3REF: Changegroup Handle
**
** A changegroup is an object used to combine two or more
@@ -11588,6 +11884,38 @@ typedef struct sqlite3_changegroup sqlite3_changegroup;
SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
/*
+** CAPI3REF: Add a Schema to a Changegroup
+** METHOD: sqlite3_changegroup_schema
+**
+** This method may be used to optionally enforce the rule that the changesets
+** added to the changegroup handle must match the schema of database zDb
+** ("main", "temp", or the name of an attached database). If
+** sqlite3changegroup_add() is called to add a changeset that is not compatible
+** with the configured schema, SQLITE_SCHEMA is returned and the changegroup
+** object is left in an undefined state.
+**
+** A changeset schema is considered compatible with the database schema in
+** the same way as for sqlite3changeset_apply(). Specifically, for each
+** table in the changeset, there exists a database table with:
+**
+** <ul>
+** <li> The name identified by the changeset, and
+** <li> at least as many columns as recorded in the changeset, and
+** <li> the primary key columns in the same position as recorded in
+** the changeset.
+** </ul>
+**
+** The output of the changegroup object always has the same schema as the
+** database nominated using this function. In cases where changesets passed
+** to sqlite3changegroup_add() have fewer columns than the corresponding table
+** in the database schema, these are filled in using the default column
+** values from the database schema. This makes it possible to combined
+** changesets that have different numbers of columns for a single table
+** within a changegroup, provided that they are otherwise compatible.
+*/
+SQLITE_API int sqlite3changegroup_schema(sqlite3_changegroup*, sqlite3*, const char *zDb);
+
+/*
** CAPI3REF: Add A Changeset To A Changegroup
** METHOD: sqlite3_changegroup
**
@@ -11655,13 +11983,18 @@ SQLITE_API int sqlite3changegroup_new(sqlite3_changegroup **pp);
** 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 state
-** of the final contents of the changegroup is undefined.
+** case, this function fails with SQLITE_SCHEMA. Except, if the changegroup
+** object has been configured with a database schema using the
+** sqlite3changegroup_schema() API, then it is possible to combine changesets
+** with different numbers of columns for a single table, provided that
+** they are otherwise compatible.
+**
+** 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.
**
-** If no error occurs, SQLITE_OK is returned.
+** In all cases, if an error occurs the state of the final contents of the
+** changegroup is undefined. If no error occurs, SQLITE_OK is returned.
*/
SQLITE_API int sqlite3changegroup_add(sqlite3_changegroup*, int nData, void *pData);
@@ -11913,9 +12246,30 @@ SQLITE_API int sqlite3changeset_apply_v2(
** Invert the changeset before applying it. This is equivalent to inverting
** a changeset using sqlite3changeset_invert() before applying it. It is
** an error to specify this flag with a patchset.
+**
+** <dt>SQLITE_CHANGESETAPPLY_IGNORENOOP <dd>
+** Do not invoke the conflict handler callback for any changes that
+** would not actually modify the database even if they were applied.
+** Specifically, this means that the conflict handler is not invoked
+** for:
+** <ul>
+** <li>a delete change if the row being deleted cannot be found,
+** <li>an update change if the modified fields are already set to
+** their new values in the conflicting row, or
+** <li>an insert change if all fields of the conflicting row match
+** the row being inserted.
+** </ul>
+**
+** <dt>SQLITE_CHANGESETAPPLY_FKNOACTION <dd>
+** If this flag it set, then all foreign key constraints in the target
+** database behave as if they were declared with "ON UPDATE NO ACTION ON
+** DELETE NO ACTION", even if they are actually CASCADE, RESTRICT, SET NULL
+** or SET DEFAULT.
*/
#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
#define SQLITE_CHANGESETAPPLY_INVERT 0x0002
+#define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004
+#define SQLITE_CHANGESETAPPLY_FKNOACTION 0x0008
/*
** CAPI3REF: Constants Passed To The Conflict Handler
@@ -12481,8 +12835,11 @@ struct Fts5PhraseIter {
** created with the "columnsize=0" option.
**
** xColumnText:
-** This function attempts to retrieve the text of column iCol of the
-** current document. If successful, (*pz) is set to point to a buffer
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of columns in the table, SQLITE_RANGE is returned.
+**
+** Otherwise, this function attempts to retrieve the text of column iCol of
+** the current document. If successful, (*pz) is set to point to a buffer
** containing the text in utf-8 encoding, (*pn) is set to the size in bytes
** (not characters) of the buffer and SQLITE_OK is returned. Otherwise,
** if an error occurs, an SQLite error code is returned and the final values
@@ -12492,8 +12849,10 @@ struct Fts5PhraseIter {
** Returns the number of phrases in the current query expression.
**
** xPhraseSize:
-** Returns the number of tokens in phrase iPhrase of the query. Phrases
-** are numbered starting from zero.
+** If parameter iCol is less than zero, or greater than or equal to the
+** number of phrases in the current query, as returned by xPhraseCount,
+** 0 is returned. Otherwise, this function returns the number of tokens in
+** phrase iPhrase of the query. Phrases are numbered starting from zero.
**
** xInstCount:
** Set *pnInst to the total number of occurrences of all phrases within
@@ -12509,12 +12868,13 @@ struct Fts5PhraseIter {
** Query for the details of phrase match iIdx within the current row.
** Phrase matches are numbered starting from zero, so the iIdx argument
** should be greater than or equal to zero and smaller than the value
-** output by xInstCount().
+** output by xInstCount(). If iIdx is less than zero or greater than
+** or equal to the value returned by xInstCount(), SQLITE_RANGE is returned.
**
-** Usually, output parameter *piPhrase is set to the phrase number, *piCol
+** Otherwise, output parameter *piPhrase is set to the phrase number, *piCol
** to the column in which it occurs and *piOff the token offset of the
-** first token of the phrase. Returns SQLITE_OK if successful, or an error
-** code (i.e. SQLITE_NOMEM) if an error occurs.
+** first token of the phrase. SQLITE_OK is returned if successful, or an
+** error code (i.e. SQLITE_NOMEM) if an error occurs.
**
** This API can be quite slow if used with an FTS5 table created with the
** "detail=none" or "detail=column" option.
@@ -12540,6 +12900,10 @@ struct Fts5PhraseIter {
** Invoking Api.xUserData() returns a copy of the pointer passed as
** the third argument to pUserData.
**
+** If parameter iPhrase is less than zero, or greater than or equal to
+** the number of phrases in the query, as returned by xPhraseCount(),
+** this function returns SQLITE_RANGE.
+**
** If the callback function returns any value other than SQLITE_OK, the
** query is abandoned and the xQueryPhrase function returns immediately.
** If the returned value is SQLITE_DONE, xQueryPhrase returns SQLITE_OK.
@@ -12654,6 +13018,39 @@ struct Fts5PhraseIter {
**
** xPhraseNextColumn()
** See xPhraseFirstColumn above.
+**
+** xQueryToken(pFts5, iPhrase, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase iPhrase of the current
+** query. Before returning, output parameter *ppToken is set to point
+** to a buffer containing the requested token, and *pnToken to the
+** size of this buffer in bytes.
+**
+** If iPhrase or iToken are less than zero, or if iPhrase is greater than
+** or equal to the number of phrases in the query as reported by
+** xPhraseCount(), or if iToken is equal to or greater than the number of
+** tokens in the phrase, SQLITE_RANGE is returned and *ppToken and *pnToken
+ are both zeroed.
+**
+** The output text is not a copy of the query text that specified the
+** token. It is the output of the tokenizer module. For tokendata=1
+** tables, this includes any embedded 0x00 and trailing data.
+**
+** xInstToken(pFts5, iIdx, iToken, ppToken, pnToken)
+** This is used to access token iToken of phrase hit iIdx within the
+** current row. If iIdx is less than zero or greater than or equal to the
+** value returned by xInstCount(), SQLITE_RANGE is returned. Otherwise,
+** output variable (*ppToken) is set to point to a buffer containing the
+** matching document token, and (*pnToken) to the size of that buffer in
+** bytes. This API is not available if the specified token matches a
+** prefix query term. In that case both output variables are always set
+** to 0.
+**
+** The output text is not a copy of the document text that was tokenized.
+** It is the output of the tokenizer module. For tokendata=1 tables, this
+** includes any embedded 0x00 and trailing data.
+**
+** This API can be quite slow if used with an FTS5 table created with the
+** "detail=none" or "detail=column" option.
*/
struct Fts5ExtensionApi {
int iVersion; /* Currently always set to 3 */
@@ -12691,6 +13088,13 @@ struct Fts5ExtensionApi {
int (*xPhraseFirstColumn)(Fts5Context*, int iPhrase, Fts5PhraseIter*, int*);
void (*xPhraseNextColumn)(Fts5Context*, Fts5PhraseIter*, int *piCol);
+
+ /* Below this point are iVersion>=3 only */
+ int (*xQueryToken)(Fts5Context*,
+ int iPhrase, int iToken,
+ const char **ppToken, int *pnToken
+ );
+ int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*);
};
/*
@@ -12885,8 +13289,8 @@ struct Fts5ExtensionApi {
** as separate queries of the FTS index are required for each synonym.
**
** When using methods (2) or (3), it is important that the tokenizer only
-** provide synonyms when tokenizing document text (method (2)) or query
-** text (method (3)), not both. Doing so will not cause any errors, but is
+** provide synonyms when tokenizing document text (method (3)) or query
+** text (method (2)), not both. Doing so will not cause any errors, but is
** inefficient.
*/
typedef struct Fts5Tokenizer Fts5Tokenizer;
@@ -12934,7 +13338,7 @@ struct fts5_api {
int (*xCreateTokenizer)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_tokenizer *pTokenizer,
void (*xDestroy)(void*)
);
@@ -12943,7 +13347,7 @@ struct fts5_api {
int (*xFindTokenizer)(
fts5_api *pApi,
const char *zName,
- void **ppContext,
+ void **ppUserData,
fts5_tokenizer *pTokenizer
);
@@ -12951,7 +13355,7 @@ struct fts5_api {
int (*xCreateFunction)(
fts5_api *pApi,
const char *zName,
- void *pContext,
+ void *pUserData,
fts5_extension_function xFunction,
void (*xDestroy)(void*)
);
diff --git a/src/3rdparty/tinycbor/0001-tst_Encoder-port-away-from-Q_FOREACH.patch b/src/3rdparty/tinycbor/0001-tst_Encoder-port-away-from-Q_FOREACH.patch
new file mode 100644
index 0000000000..43c8b1a452
--- /dev/null
+++ b/src/3rdparty/tinycbor/0001-tst_Encoder-port-away-from-Q_FOREACH.patch
@@ -0,0 +1,79 @@
+From b6e2caf7452bf2b695583196fd7b346c1663d798 Mon Sep 17 00:00:00 2001
+From: Marc Mutz <marc.mutz@qt.io>
+Date: Mon, 7 Aug 2023 16:24:13 +0200
+Subject: [PATCH] tst_Encoder: port away from Q_FOREACH
+
+Qt is defaulting to QT_NO_FOREACH these days, so make sure we
+integrate nicely with downstream and fix the single Q_FOREACH/foreach
+user, in tst_encoder.cpp.
+
+Unfortunately, the container's initialization code doesn't exactly
+lend itself to making the container const (not even IILE
+(Immediately-Invoked Lambda Expression) would help here, due to the
+interdependency with `len`), so the idiomatic solution would be to use
+std::as_const()/qAsConst().
+
+The former is available from C++17, which we don't require, yet, and
+the latter is not available under QT_NO_AS_CONST (the default for Qt
+these days), so grab the nettle and implement a t17::as_const() that
+switches between a manual implementation of std::as_const and the real
+thing, depending on __cpp_lib_as_const. The `t17` here mimicks the qNN
+(q20::remove_cvref_t/q23::forward_like/etc) mechanism used in Qt
+itself for backports, with s/q/t/ because ... _T_inyCbor.
+
+The t17 implementation is local to tst_encoder.cpp, but can easily be
+extracted into a separate header once more users emerge.
+---
+ tests/encoder/encoder.pro | 2 ++
+ tests/encoder/tst_encoder.cpp | 15 ++++++++++++++-
+ 2 files changed, 16 insertions(+), 1 deletion(-)
+
+diff --git a/tests/encoder/encoder.pro b/tests/encoder/encoder.pro
+index 62d9b7e..180f0d7 100644
+--- a/tests/encoder/encoder.pro
++++ b/tests/encoder/encoder.pro
+@@ -3,6 +3,8 @@ SOURCES += tst_encoder.cpp
+ CONFIG += testcase parallel_test c++11
+ QT = core testlib
+
++DEFINES += QT_NO_FOREACH QT_NO_AS_CONST
++
+ INCLUDEPATH += ../../src
+ msvc: POST_TARGETDEPS = ../../lib/tinycbor.lib
+ else: POST_TARGETDEPS += ../../lib/libtinycbor.a
+diff --git a/tests/encoder/tst_encoder.cpp b/tests/encoder/tst_encoder.cpp
+index 31c2915..61ce9c9 100644
+--- a/tests/encoder/tst_encoder.cpp
++++ b/tests/encoder/tst_encoder.cpp
+@@ -29,6 +29,19 @@
+ #include <qfloat16.h>
+ #endif
+
++#include <utility>
++namespace t17 {
++#ifdef __cpp_lib_as_const
++ using std::as_const;
++#else
++ template <typename T>
++ constexpr typename std::add_const<T>::type &as_const(T &t) noexcept { return t; }
++ // prevent rvalue arguments:
++ template <typename T>
++ void as_const(const T &&) = delete;
++#endif // __cpp_lib_as_const
++} // namespace t17
++
+ Q_DECLARE_METATYPE(CborError)
+ namespace QTest {
+ template<> char *toString<CborError>(const CborError &err)
+@@ -153,7 +166,7 @@ CborError encodeVariant(CborEncoder *encoder, const QVariant &v)
+ CborError err = cbor_encoder_create_array(encoder, &sub, len);
+ if (err && !isOomError(err))
+ return err;
+- foreach (const QVariant &v2, list) {
++ for (const QVariant &v2 : t17::as_const(list)) {
+ err = static_cast<CborError>(err | encodeVariant(&sub, v2));
+ if (err && !isOomError(err))
+ return err;
+--
+2.25.1
+
diff --git a/src/3rdparty/tinycbor/qt_attribution.json b/src/3rdparty/tinycbor/qt_attribution.json
index 5fcc82809a..b19c57904b 100644
--- a/src/3rdparty/tinycbor/qt_attribution.json
+++ b/src/3rdparty/tinycbor/qt_attribution.json
@@ -3,6 +3,7 @@
"Name": "TinyCBOR",
"QDocModule": "qtcore",
"QtUsage": "Used for QCborStreamReader and QCborStreamWriter.",
+ "SecurityCritical": true,
"Description": "Concise Binary Object Representation (CBOR) Library",
"Homepage": "https://github.com/intel/tinycbor",
diff --git a/src/3rdparty/tinycbor/src/cborparser.c b/src/3rdparty/tinycbor/src/cborparser.c
index 74d91a30e0..80c44c7e13 100644
--- a/src/3rdparty/tinycbor/src/cborparser.c
+++ b/src/3rdparty/tinycbor/src/cborparser.c
@@ -232,7 +232,7 @@ static CborError preparse_value(CborValue *it)
case SinglePrecisionFloat:
case DoublePrecisionFloat:
it->flags |= CborIteratorFlag_IntegerValueTooLarge;
- /* fall through */
+ Q_FALLTHROUGH();
case TrueValue:
case NullValue:
case UndefinedValue:
diff --git a/src/3rdparty/tinycbor/tests/encoder/data.cpp b/src/3rdparty/tinycbor/tests/encoder/data.cpp
index 6dca49d41c..dc7c6a91a1 100644
--- a/src/3rdparty/tinycbor/tests/encoder/data.cpp
+++ b/src/3rdparty/tinycbor/tests/encoder/data.cpp
@@ -24,7 +24,29 @@
#include <QtTest>
-static float myNaNf()
+struct NegativeInteger { quint64 abs; };
+Q_DECLARE_METATYPE(NegativeInteger)
+
+struct SimpleType { uint8_t type; };
+Q_DECLARE_METATYPE(SimpleType)
+
+struct Float16Standin { uint16_t val; };
+Q_DECLARE_METATYPE(Float16Standin)
+
+struct Tag { CborTag tag; QVariant tagged; };
+Q_DECLARE_METATYPE(Tag)
+
+typedef QVector<QPair<QVariant, QVariant>> Map;
+Q_DECLARE_METATYPE(Map)
+
+struct IndeterminateLengthArray : QVariantList { using QVariantList::QVariantList; };
+struct IndeterminateLengthMap : Map { using Map::Map; };
+Q_DECLARE_METATYPE(IndeterminateLengthArray)
+Q_DECLARE_METATYPE(IndeterminateLengthMap)
+
+namespace {
+
+float myNaNf()
{
uint32_t v = 0x7fc00000;
float f;
@@ -33,7 +55,7 @@ static float myNaNf()
return f;
}
-static float myInff()
+float myInff()
{
uint32_t v = 0x7f800000;
float f;
@@ -42,7 +64,7 @@ static float myInff()
return f;
}
-static float myNInff()
+float myNInff()
{
uint32_t v = 0xff800000;
float f;
@@ -51,7 +73,7 @@ static float myNInff()
return f;
}
-static double myNaN()
+double myNaN()
{
uint64_t v = UINT64_C(0x7ff8000000000000);
double f;
@@ -60,7 +82,7 @@ static double myNaN()
return f;
}
-static double myInf()
+double myInf()
{
uint64_t v = UINT64_C(0x7ff0000000000000);
double f;
@@ -69,7 +91,7 @@ static double myInf()
return f;
}
-static double myNInf()
+double myNInf()
{
uint64_t v = UINT64_C(0xfff0000000000000);
double f;
@@ -83,36 +105,17 @@ template <size_t N> QByteArray raw(const char (&data)[N])
return QByteArray::fromRawData(data, N - 1);
}
-struct NegativeInteger { quint64 abs; };
-Q_DECLARE_METATYPE(NegativeInteger)
-
-struct SimpleType { uint8_t type; };
-Q_DECLARE_METATYPE(SimpleType)
-
-struct Float16Standin { uint16_t val; };
-Q_DECLARE_METATYPE(Float16Standin)
-
-struct Tag { CborTag tag; QVariant tagged; };
-Q_DECLARE_METATYPE(Tag)
-
template <typename... Args>
QVariant make_list(const Args &... args)
{
return QVariantList{args...};
}
-typedef QVector<QPair<QVariant, QVariant>> Map;
-Q_DECLARE_METATYPE(Map)
QVariant make_map(const std::initializer_list<QPair<QVariant, QVariant>> &list)
{
return QVariant::fromValue(Map(list));
}
-struct IndeterminateLengthArray : QVariantList { using QVariantList::QVariantList; };
-struct IndeterminateLengthMap : Map { using Map::Map; };
-Q_DECLARE_METATYPE(IndeterminateLengthArray)
-Q_DECLARE_METATYPE(IndeterminateLengthMap)
-
QVariant make_ilarray(const std::initializer_list<QVariant> &list)
{
return QVariant::fromValue(IndeterminateLengthArray(list));
@@ -239,9 +242,9 @@ void addFixedData()
QTest::newRow("0.f16") << raw("\xf9\0\0") << QVariant::fromValue(qfloat16(0));
QTest::newRow("-1.f16") << raw("\xf9\xbc\0") << QVariant::fromValue(qfloat16(-1));
QTest::newRow("1.5f16") << raw("\xf9\x3e\0") << QVariant::fromValue(qfloat16(1.5));
- QTest::newRow("nan_f16") << raw("\xf9\x7e\0") << QVariant::fromValue<qfloat16>(myNaNf());
- QTest::newRow("-inf_f16") << raw("\xf9\xfc\0") << QVariant::fromValue<qfloat16>(myNInff());
- QTest::newRow("+inf_f16") << raw("\xf9\x7c\0") << QVariant::fromValue<qfloat16>(myInff());
+ QTest::newRow("nan_f16") << raw("\xf9\x7e\0") << QVariant::fromValue<qfloat16>(qfloat16(myNaNf()));
+ QTest::newRow("-inf_f16") << raw("\xf9\xfc\0") << QVariant::fromValue<qfloat16>(qfloat16(myNInff()));
+ QTest::newRow("+inf_f16") << raw("\xf9\x7c\0") << QVariant::fromValue<qfloat16>(qfloat16(myInff()));
#endif
QTest::newRow("0.f") << raw("\xfa\0\0\0\0") << QVariant::fromValue(0.f);
@@ -343,4 +346,4 @@ void addArraysAndMaps()
QTest::newRow("array-1(map)") << raw("\x81\xc1\xa0") << make_list(QVariant::fromValue(Tag{1, make_map({})}));
QTest::newRow("map-1(2):3(4)") << raw("\xa1\xc1\2\xc3\4") << make_map({{QVariant::fromValue(Tag{1, 2}), QVariant::fromValue(Tag{3, 4})}});
}
-
+} // namespace
diff --git a/src/3rdparty/tinycbor/tests/encoder/tst_encoder.cpp b/src/3rdparty/tinycbor/tests/encoder/tst_encoder.cpp
index 31c29152f9..61ce9c995c 100644
--- a/src/3rdparty/tinycbor/tests/encoder/tst_encoder.cpp
+++ b/src/3rdparty/tinycbor/tests/encoder/tst_encoder.cpp
@@ -29,6 +29,19 @@
#include <qfloat16.h>
#endif
+#include <utility>
+namespace t17 {
+#ifdef __cpp_lib_as_const
+ using std::as_const;
+#else
+ template <typename T>
+ constexpr typename std::add_const<T>::type &as_const(T &t) noexcept { return t; }
+ // prevent rvalue arguments:
+ template <typename T>
+ void as_const(const T &&) = delete;
+#endif // __cpp_lib_as_const
+} // namespace t17
+
Q_DECLARE_METATYPE(CborError)
namespace QTest {
template<> char *toString<CborError>(const CborError &err)
@@ -153,7 +166,7 @@ CborError encodeVariant(CborEncoder *encoder, const QVariant &v)
CborError err = cbor_encoder_create_array(encoder, &sub, len);
if (err && !isOomError(err))
return err;
- foreach (const QVariant &v2, list) {
+ for (const QVariant &v2 : t17::as_const(list)) {
err = static_cast<CborError>(err | encodeVariant(&sub, v2));
if (err && !isOomError(err))
return err;
diff --git a/src/3rdparty/tinycbor/tests/parser/data.cpp b/src/3rdparty/tinycbor/tests/parser/data.cpp
index f701a5a5b0..c99160ad31 100644
--- a/src/3rdparty/tinycbor/tests/parser/data.cpp
+++ b/src/3rdparty/tinycbor/tests/parser/data.cpp
@@ -28,6 +28,8 @@
Q_DECLARE_METATYPE(CborError)
+namespace {
+
template <size_t N> QByteArray raw(const char (&data)[N])
{
return QByteArray::fromRawData(data, N - 1);
@@ -605,3 +607,4 @@ void addValidationData(size_t minInvalid = ~size_t(0))
// This test technically tests the dumper, not the parser.
QTest::newRow("string-utf8-chunk-split") << raw("\x81\x7f\x61\xc2\x61\xa0\xff") << 0 << CborErrorInvalidUtf8TextString;
}
+} // namespace
diff --git a/src/3rdparty/wasm/VERA-LICENSE b/src/3rdparty/wasm/VERA-LICENSE
deleted file mode 100644
index 4f9e8544b7..0000000000
--- a/src/3rdparty/wasm/VERA-LICENSE
+++ /dev/null
@@ -1,15 +0,0 @@
-Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license (“Fonts”) and associated documentation files (the “Font Software”), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions:
-
-The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces.
-
-The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words “Bitstream” or the word “Vera”.
-
-This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the “Bitstream Vera” names.
-
-The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself.
-
-THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
-
-Except as contained in this notice, the names of GNOME, the GNOME Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the GNOME Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org.
diff --git a/src/3rdparty/wasm/Vera.ttf b/src/3rdparty/wasm/Vera.ttf
deleted file mode 100644
index 58cd6b5e61..0000000000
--- a/src/3rdparty/wasm/Vera.ttf
+++ /dev/null
Binary files differ
diff --git a/src/3rdparty/wasm/qt_attribution.json b/src/3rdparty/wasm/qt_attribution.json
index 49c32bb747..ed89bc35c1 100644
--- a/src/3rdparty/wasm/qt_attribution.json
+++ b/src/3rdparty/wasm/qt_attribution.json
@@ -1,20 +1,5 @@
[
{
- "Id": "vera_font",
- "Name": "Bitstream Vera Font",
- "QDocModule": "qtgui",
- "QtUsage": "Used for WebAssembly platform.",
- "Files": "Vera.ttf",
- "Description": "Vera is a group typeface (font) with a liberal license.",
-
- "Version": "1.10",
- "DownloadLocation": "http://ftp.gnome.org/pub/GNOME/sources/ttf-bitstream-vera/1.10/ttf-bitstream-vera-1.10.tar.bz2",
- "License": "Bitstream Vera Font License",
- "LicenseId": "urn:dje:license:bitstream",
- "LicenseFile": "VERA-LICENSE",
- "Copyright": "Copyright (C) 2003 Bitstream,Inc"
-},
-{
"Id": "dejayvu",
"Name": "DejaVu Fonts",
"QDocModule": "qtgui",
@@ -27,8 +12,8 @@
"License": "Bitstream Vera Font License",
"LicenseId": "urn:dje:license:bitstream",
"LicenseFile": "DEJAVU-LICENSE",
- "Copyright": "Copyright (c) 2003 by Bitstream, Inc
-Copyright (c) 2006 by Tavmjong Bah
-(c) American Mathematical Society"
+ "Copyright": ["Copyright (c) 2003 by Bitstream, Inc",
+ "Copyright (c) 2006 by Tavmjong Bah",
+ "(c) American Mathematical Society"]
}
]
diff --git a/src/3rdparty/xcb/qt_attribution.json b/src/3rdparty/xcb/qt_attribution.json
index 7c469c2ef1..dce3977905 100644
--- a/src/3rdparty/xcb/qt_attribution.json
+++ b/src/3rdparty/xcb/qt_attribution.json
@@ -10,5 +10,7 @@
"License": "MIT License",
"LicenseId": "MIT",
"LicenseFile": "LICENSE",
- "Copyright": "Copyright (C) 2001-2006 Bart Massey, Jamey Sharp, and Josh Triplett.\nCopyright (C) 2006 Peter Hutterer\nCopyright (C) 2013 Daniel Martin"
+ "Copyright": ["Copyright (C) 2001-2006 Bart Massey, Jamey Sharp, and Josh Triplett.",
+ "Copyright (C) 2006 Peter Hutterer",
+ "Copyright (C) 2013 Daniel Martin"]
}
diff --git a/src/3rdparty/zlib/import_from_zlib_tarball.sh b/src/3rdparty/zlib/import_from_zlib_tarball.sh
index 5251f43d33..0f81f052f3 100755
--- a/src/3rdparty/zlib/import_from_zlib_tarball.sh
+++ b/src/3rdparty/zlib/import_from_zlib_tarball.sh
@@ -1,43 +1,8 @@
#! /bin/sh
-#############################################################################
-##
-## Copyright (C) 2017 André Klitzing
-## Contact: https://www.qt.io/licensing/
-##
-## This file is the build configuration utility 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$
-##
-#############################################################################
+# Copyright (C) 2017 André Klitzing
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+#
# This is a small script to copy the required files from a zlib tarball
# into 3rdparty/zlib/
@@ -46,8 +11,9 @@ if [ $# -ne 2 ]; then
exit 1
fi
-ZLIB_DIR=$1
-TARGET_DIR=$2
+# Name the arguments, omitting trailing slashes as we'll add where needed.
+ZLIB_DIR="${1%/}"
+TARGET_DIR="${2%/}"
if [ ! -d "$ZLIB_DIR" -o ! -r "$ZLIB_DIR" -o ! -d "$TARGET_DIR" -o ! -w "$TARGET_DIR" ]; then
echo "Either the zlib source dir or the target dir do not exist,"
@@ -71,7 +37,7 @@ copy_file() {
fi
mkdir -p "$TARGET_DIR/$(dirname "$SOURCE_FILE")"
- cp "$ZLIB_DIR/$SOURCE_FILE" "$TARGET_DIR/$DEST_FILE"
+ cp -v "$ZLIB_DIR/$SOURCE_FILE" "$TARGET_DIR/$DEST_FILE"
}
FILES="
@@ -110,3 +76,18 @@ FILES="
for i in $FILES; do
copy_file "$i" "src/$i"
done
+
+cat << EOF
+
+Please do not forget to patch qtpatches.diff
+The usual routine after this script is:
+ 1. Create commit to clean staging
+ 2. Apply qtpatches.diff with:
+ patch -p1 < qtpatches.diff
+ 3. Update the version in: ChangeLog and src/zlib.h
+ 4. Validate all changes and create new qtpatches.diff with:
+ git diff --relative > qtpatches.diff
+ 5. Add changed files and amend the commit with these files.
+
+If you want to revert the diff use: patch -p1 -Ri qtpatches.diff
+EOF
diff --git a/src/3rdparty/zlib/qt_attribution.json b/src/3rdparty/zlib/qt_attribution.json
index db176cbe6a..88ed202db1 100644
--- a/src/3rdparty/zlib/qt_attribution.json
+++ b/src/3rdparty/zlib/qt_attribution.json
@@ -3,13 +3,15 @@
"Name": "Data Compression Library (zlib)",
"QDocModule": "qtcore",
"QtUsage": "Optionally used in Qt Core and development tools. Configure with -system-zlib to avoid.",
+ "SecurityCritical": true,
"Description": "zlib is a general purpose data compression library.",
"Homepage": "https://zlib.net/",
- "Version": "1.2.13",
+ "Version": "1.3.1",
+ "DownloadLocation": "https://github.com/madler/zlib/releases/download/v1.3.1/zlib-1.3.1.tar.gz",
"License": "zlib License",
"LicenseId": "Zlib",
"LicenseFile": "LICENSE",
- "Copyright": "(C) 1995-2022 Jean-loup Gailly and Mark Adler"
+ "Copyright": "(C) 1995-2024 Jean-loup Gailly and Mark Adler"
}
diff --git a/src/3rdparty/zlib/qtpatches.diff b/src/3rdparty/zlib/qtpatches.diff
index b94f131f9c..28be579dc9 100644
--- a/src/3rdparty/zlib/qtpatches.diff
+++ b/src/3rdparty/zlib/qtpatches.diff
@@ -1,20 +1,36 @@
-diff -ruN orig/ChangeLog src/ChangeLog
---- orig/ChangeLog
-+++ src/ChangeLog
+diff --git a/src/ChangeLog b/src/ChangeLog
+index b801a1031ec..686283a2aec 100644
+--- a/src/ChangeLog
++++ b/src/ChangeLog
@@ -1,6 +1,10 @@
ChangeLog file for zlib
-+Changes in 1.2.13 (Qt) (14 Nov 2022)
++Changes in 1.3.1 (Qt) (23 Jan 2024)
+- This is a stripped down copy of zlib that contains patches to
+ make it compile as part of Qt. See also "qtpatches.diff".
+
- Changes in 1.2.13 (13 Oct 2022)
- - Fix configure issue that discarded provided CC definition
- - Correct incorrect inputs provided to the CRC functions
-diff -ruN orig/gzguts.h src/gzguts.h
---- orig/gzguts.h
-+++ src/gzguts.h
+ Changes in 1.3.1 (22 Jan 2024)
+ - Reject overflows of zip header fields in minizip
+ - Fix bug in inflateSync() for data held in bit buffer
+diff --git a/src/README b/src/README
+index c5f917540b6..af6b4f32bf5 100644
+--- a/src/README
++++ b/src/README
+@@ -6,6 +6,9 @@ thread safe. The data format used by the zlib library is described by RFCs
+ http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and
+ rfc1952 (gzip format).
+
++This is a stripped down copy of zlib that contains patches to make it compile
++as part of Qt. See also "qtpatches.diff".
++
+ All functions of the compression library are documented in the file zlib.h
+ (volunteer to write man pages welcome, contact zlib@gzip.org). A usage example
+ of the library is given in the file test/example.c which also tests that
+diff --git a/src/gzguts.h b/src/gzguts.h
+index eba72085bb7..5bf6b7d4813 100644
+--- a/src/gzguts.h
++++ b/src/gzguts.h
@@ -3,6 +3,12 @@
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -28,22 +44,10 @@ diff -ruN orig/gzguts.h src/gzguts.h
#ifdef _LARGEFILE64_SOURCE
# ifndef _LARGEFILE_SOURCE
# define _LARGEFILE_SOURCE 1
-diff -ruN orig/README src/README
---- orig/README
-+++ src/README
-@@ -6,6 +6,9 @@
- http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and
- rfc1952 (gzip format).
-
-+This is a stripped down copy of zlib that contains patches to make it compile
-+as part of Qt. See also "qtpatches.diff".
-+
- All functions of the compression library are documented in the file zlib.h
- (volunteer to write man pages welcome, contact zlib@gzip.org). A usage example
- of the library is given in the file test/example.c which also tests that
-diff -ruN orig/zconf.h src/zconf.h
---- orig/zconf.h
-+++ src/zconf.h
+diff --git a/src/zconf.h b/src/zconf.h
+index 62adc8d8431..4e14507a22d 100644
+--- a/src/zconf.h
++++ b/src/zconf.h
@@ -8,6 +8,9 @@
#ifndef ZCONF_H
#define ZCONF_H
@@ -54,17 +58,7 @@ diff -ruN orig/zconf.h src/zconf.h
/*
* If you *really* need a unique prefix for all types and library functions,
* compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
-@@ -38,6 +41,9 @@
- # define crc32 z_crc32
- # define crc32_combine z_crc32_combine
- # define crc32_combine64 z_crc32_combine64
-+# define crc32_combine_gen z_crc32_combine_gen
-+# define crc32_combine_gen64 z_crc32_combine_gen64
-+# define crc32_combine_op z_crc32_combine_op
- # define crc32_z z_crc32_z
- # define deflate z_deflate
- # define deflateBound z_deflateBound
-@@ -136,6 +142,7 @@
+@@ -139,6 +142,7 @@
# endif
# define zlibCompileFlags z_zlibCompileFlags
# define zlibVersion z_zlibVersion
@@ -72,7 +66,7 @@ diff -ruN orig/zconf.h src/zconf.h
/* all zlib typedefs in zlib.h and zconf.h */
# define Byte z_Byte
-@@ -431,7 +438,7 @@
+@@ -433,7 +437,7 @@ typedef uLong FAR uLongf;
typedef unsigned long z_crc_t;
#endif
@@ -81,9 +75,10 @@ diff -ruN orig/zconf.h src/zconf.h
# define Z_HAVE_UNISTD_H
#endif
-diff -ruN orig/zlib.h src/zlib.h
---- orig/zlib.h
-+++ src/zlib.h
+diff --git a/src/zlib.h b/src/zlib.h
+index 8d4b932eaf6..2cff72ee865 100644
+--- a/src/zlib.h
++++ b/src/zlib.h
@@ -33,11 +33,15 @@
#include "zconf.h"
@@ -96,14 +91,15 @@ diff -ruN orig/zlib.h src/zlib.h
extern "C" {
#endif
--#define ZLIB_VERSION "1.2.13"
-+#define ZLIB_VERSION "1.2.13 (Qt)"
- #define ZLIB_VERNUM 0x12c0
+-#define ZLIB_VERSION "1.3.1"
++#define ZLIB_VERSION "1.3.1 (Qt)"
+ #define ZLIB_VERNUM 0x1310
#define ZLIB_VER_MAJOR 1
- #define ZLIB_VER_MINOR 2
-diff -ruN orig/zutil.h src/zutil.h
---- orig/zutil.h
-+++ src/zutil.h
+ #define ZLIB_VER_MINOR 3
+diff --git a/src/zutil.h b/src/zutil.h
+index 48dd7febae6..71dd616ab8d 100644
+--- a/src/zutil.h
++++ b/src/zutil.h
@@ -13,6 +13,12 @@
#ifndef ZUTIL_H
#define ZUTIL_H
@@ -117,19 +113,7 @@ diff -ruN orig/zutil.h src/zutil.h
#ifdef HAVE_HIDDEN
# define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
#else
-@@ -143,6 +149,11 @@
- # if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
- # include <unix.h> /* for fdopen */
- # else
-+// We need to include stdio.h here because zlib.h will include TargetConditionals.h
-+// This will define TARGET_OS_MAC that leads to this check.
-+// Since zutil.h will include gzguts.h and gzguts.h includes stdio.h
-+// AFTER check for fdopen we need to include stdio.h directly
-+# include <stdio.h>
- # ifndef fdopen
- # define fdopen(fd,mode) NULL /* No fdopen() */
- # endif
-@@ -166,7 +177,7 @@
+@@ -157,7 +163,7 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
# define OS_CODE 18
#endif
diff --git a/src/3rdparty/zlib/src/ChangeLog b/src/3rdparty/zlib/src/ChangeLog
index 900c2393a1..26541ea792 100644
--- a/src/3rdparty/zlib/src/ChangeLog
+++ b/src/3rdparty/zlib/src/ChangeLog
@@ -1,10 +1,38 @@
ChangeLog file for zlib
-Changes in 1.2.13 (Qt) (14 Nov 2022)
+Changes in 1.3.1 (Qt) (23 Jan 2024)
- This is a stripped down copy of zlib that contains patches to
make it compile as part of Qt. See also "qtpatches.diff".
+Changes in 1.3.1 (22 Jan 2024)
+- Reject overflows of zip header fields in minizip
+- Fix bug in inflateSync() for data held in bit buffer
+- Add LIT_MEM define to use more memory for a small deflate speedup
+- Fix decision on the emission of Zip64 end records in minizip
+- Add bounds checking to ERR_MSG() macro, used by zError()
+- Neutralize zip file traversal attacks in miniunz
+- Fix a bug in ZLIB_DEBUG compiles in check_match()
+- Various portability and appearance improvements
+
+Changes in 1.3 (18 Aug 2023)
+- Remove K&R function definitions and zlib2ansi
+- Fix bug in deflateBound() for level 0 and memLevel 9
+- Fix bug when gzungetc() is used immediately after gzopen()
+- Fix bug when using gzflush() with a very small buffer
+- Fix crash when gzsetparams() attempted for transparent write
+- Fix test/example.c to work with FORCE_STORED
+- Rewrite of zran in examples (see zran.c version history)
+- Fix minizip to allow it to open an empty zip file
+- Fix reading disk number start on zip64 files in minizip
+- Fix logic error in minizip argument processing
+- Add minizip testing to Makefile
+- Read multiple bytes instead of byte-by-byte in minizip unzip.c
+- Add memory sanitizer to configure (--memory)
+- Various portability improvements
+- Various documentation improvements
+- Various spelling and typo corrections
+
Changes in 1.2.13 (13 Oct 2022)
- Fix configure issue that discarded provided CC definition
- Correct incorrect inputs provided to the CRC functions
@@ -1449,7 +1477,7 @@ Changes in 0.99 (27 Jan 96)
- fix typo in Make_vms.com (f$trnlnm -> f$getsyi)
- in fcalloc, normalize pointer if size > 65520 bytes
- don't use special fcalloc for 32 bit Borland C++
-- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc...
+- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc.
- use Z_BINARY instead of BINARY
- document that gzclose after gzdopen will close the file
- allow "a" as mode in gzopen
diff --git a/src/3rdparty/zlib/src/README b/src/3rdparty/zlib/src/README
index 10c63e17bc..af6b4f32bf 100644
--- a/src/3rdparty/zlib/src/README
+++ b/src/3rdparty/zlib/src/README
@@ -1,6 +1,6 @@
ZLIB DATA COMPRESSION LIBRARY
-zlib 1.2.13 is a general purpose data compression library. All the code is
+zlib 1.3.1 is a general purpose data compression library. All the code is
thread safe. The data format used by the zlib library is described by RFCs
(Request for Comments) 1950 to 1952 in the files
http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and
@@ -32,18 +32,17 @@ PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help.
Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997
issue of Dr. Dobb's Journal; a copy of the article is available at
-http://marknelson.us/1997/01/01/zlib-engine/ .
+https://marknelson.us/posts/1997/01/01/zlib-engine.html .
-The changes made in version 1.2.13 are documented in the file ChangeLog.
+The changes made in version 1.3.1 are documented in the file ChangeLog.
Unsupported third party contributions are provided in directory contrib/ .
-zlib is available in Java using the java.util.zip package, documented at
-http://java.sun.com/developer/technicalArticles/Programming/compression/ .
+zlib is available in Java using the java.util.zip package. Follow the API
+Documentation link at: https://docs.oracle.com/search/?q=java.util.zip .
-A Perl interface to zlib written by Paul Marquess <pmqs@cpan.org> is available
-at CPAN (Comprehensive Perl Archive Network) sites, including
-http://search.cpan.org/~pmqs/IO-Compress-Zlib/ .
+A Perl interface to zlib and bzip2 written by Paul Marquess <pmqs@cpan.org>
+can be found at https://github.com/pmqs/IO-Compress .
A Python interface to zlib written by A.M. Kuchling <amk@amk.ca> is
available in Python 1.5 and later versions, see
@@ -67,7 +66,7 @@ Notes for some targets:
- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works
when compiled with cc.
-- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is
+- On Digital Unix 4.0D (formerly OSF/1) on AlphaServer, the cc option -std1 is
necessary to get gzprintf working correctly. This is done by configure.
- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with
@@ -87,7 +86,7 @@ Acknowledgments:
Copyright notice:
- (C) 1995-2022 Jean-loup Gailly and Mark Adler
+ (C) 1995-2024 Jean-loup Gailly and Mark Adler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
diff --git a/src/3rdparty/zlib/src/adler32.c b/src/3rdparty/zlib/src/adler32.c
index d0be4380a3..04b81d29ba 100644
--- a/src/3rdparty/zlib/src/adler32.c
+++ b/src/3rdparty/zlib/src/adler32.c
@@ -7,8 +7,6 @@
#include "zutil.h"
-local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));
-
#define BASE 65521U /* largest prime smaller than 65536 */
#define NMAX 5552
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
@@ -60,11 +58,7 @@ local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));
#endif
/* ========================================================================= */
-uLong ZEXPORT adler32_z(adler, buf, len)
- uLong adler;
- const Bytef *buf;
- z_size_t len;
-{
+uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, z_size_t len) {
unsigned long sum2;
unsigned n;
@@ -131,20 +125,12 @@ uLong ZEXPORT adler32_z(adler, buf, len)
}
/* ========================================================================= */
-uLong ZEXPORT adler32(adler, buf, len)
- uLong adler;
- const Bytef *buf;
- uInt len;
-{
+uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len) {
return adler32_z(adler, buf, len);
}
/* ========================================================================= */
-local uLong adler32_combine_(adler1, adler2, len2)
- uLong adler1;
- uLong adler2;
- z_off64_t len2;
-{
+local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2) {
unsigned long sum1;
unsigned long sum2;
unsigned rem;
@@ -169,18 +155,10 @@ local uLong adler32_combine_(adler1, adler2, len2)
}
/* ========================================================================= */
-uLong ZEXPORT adler32_combine(adler1, adler2, len2)
- uLong adler1;
- uLong adler2;
- z_off_t len2;
-{
+uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, z_off_t len2) {
return adler32_combine_(adler1, adler2, len2);
}
-uLong ZEXPORT adler32_combine64(adler1, adler2, len2)
- uLong adler1;
- uLong adler2;
- z_off64_t len2;
-{
+uLong ZEXPORT adler32_combine64(uLong adler1, uLong adler2, z_off64_t len2) {
return adler32_combine_(adler1, adler2, len2);
}
diff --git a/src/3rdparty/zlib/src/compress.c b/src/3rdparty/zlib/src/compress.c
index 2ad5326c14..f43bacf7ab 100644
--- a/src/3rdparty/zlib/src/compress.c
+++ b/src/3rdparty/zlib/src/compress.c
@@ -19,13 +19,8 @@
memory, Z_BUF_ERROR if there was not enough room in the output buffer,
Z_STREAM_ERROR if the level parameter is invalid.
*/
-int ZEXPORT compress2(dest, destLen, source, sourceLen, level)
- Bytef *dest;
- uLongf *destLen;
- const Bytef *source;
- uLong sourceLen;
- int level;
-{
+int ZEXPORT compress2(Bytef *dest, uLongf *destLen, const Bytef *source,
+ uLong sourceLen, int level) {
z_stream stream;
int err;
const uInt max = (uInt)-1;
@@ -65,12 +60,8 @@ int ZEXPORT compress2(dest, destLen, source, sourceLen, level)
/* ===========================================================================
*/
-int ZEXPORT compress(dest, destLen, source, sourceLen)
- Bytef *dest;
- uLongf *destLen;
- const Bytef *source;
- uLong sourceLen;
-{
+int ZEXPORT compress(Bytef *dest, uLongf *destLen, const Bytef *source,
+ uLong sourceLen) {
return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
}
@@ -78,9 +69,7 @@ int ZEXPORT compress(dest, destLen, source, sourceLen)
If the default memLevel or windowBits for deflateInit() is changed, then
this function needs to be updated.
*/
-uLong ZEXPORT compressBound(sourceLen)
- uLong sourceLen;
-{
+uLong ZEXPORT compressBound(uLong sourceLen) {
return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
(sourceLen >> 25) + 13;
}
diff --git a/src/3rdparty/zlib/src/crc32.c b/src/3rdparty/zlib/src/crc32.c
index f8357b083f..6c38f5c04c 100644
--- a/src/3rdparty/zlib/src/crc32.c
+++ b/src/3rdparty/zlib/src/crc32.c
@@ -103,19 +103,6 @@
# define ARMCRC32
#endif
-/* Local functions. */
-local z_crc_t multmodp OF((z_crc_t a, z_crc_t b));
-local z_crc_t x2nmodp OF((z_off64_t n, unsigned k));
-
-#if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE))
- local z_word_t byte_swap OF((z_word_t word));
-#endif
-
-#if defined(W) && !defined(ARMCRC32)
- local z_crc_t crc_word OF((z_word_t data));
- local z_word_t crc_word_big OF((z_word_t data));
-#endif
-
#if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE))
/*
Swap the bytes in a z_word_t to convert between little and big endian. Any
@@ -123,9 +110,7 @@ local z_crc_t x2nmodp OF((z_off64_t n, unsigned k));
instruction, if one is available. This assumes that word_t is either 32 bits
or 64 bits.
*/
-local z_word_t byte_swap(word)
- z_word_t word;
-{
+local z_word_t byte_swap(z_word_t word) {
# if W == 8
return
(word & 0xff00000000000000) >> 56 |
@@ -146,24 +131,77 @@ local z_word_t byte_swap(word)
}
#endif
+#ifdef DYNAMIC_CRC_TABLE
+/* =========================================================================
+ * Table of powers of x for combining CRC-32s, filled in by make_crc_table()
+ * below.
+ */
+ local z_crc_t FAR x2n_table[32];
+#else
+/* =========================================================================
+ * Tables for byte-wise and braided CRC-32 calculations, and a table of powers
+ * of x for combining CRC-32s, all made by make_crc_table().
+ */
+# include "crc32.h"
+#endif
+
/* CRC polynomial. */
#define POLY 0xedb88320 /* p(x) reflected, with x^32 implied */
-#ifdef DYNAMIC_CRC_TABLE
+/*
+ Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial,
+ reflected. For speed, this requires that a not be zero.
+ */
+local z_crc_t multmodp(z_crc_t a, z_crc_t b) {
+ z_crc_t m, p;
+
+ m = (z_crc_t)1 << 31;
+ p = 0;
+ for (;;) {
+ if (a & m) {
+ p ^= b;
+ if ((a & (m - 1)) == 0)
+ break;
+ }
+ m >>= 1;
+ b = b & 1 ? (b >> 1) ^ POLY : b >> 1;
+ }
+ return p;
+}
+/*
+ Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been
+ initialized.
+ */
+local z_crc_t x2nmodp(z_off64_t n, unsigned k) {
+ z_crc_t p;
+
+ p = (z_crc_t)1 << 31; /* x^0 == 1 */
+ while (n) {
+ if (n & 1)
+ p = multmodp(x2n_table[k & 31], p);
+ n >>= 1;
+ k++;
+ }
+ return p;
+}
+
+#ifdef DYNAMIC_CRC_TABLE
+/* =========================================================================
+ * Build the tables for byte-wise and braided CRC-32 calculations, and a table
+ * of powers of x for combining CRC-32s.
+ */
local z_crc_t FAR crc_table[256];
-local z_crc_t FAR x2n_table[32];
-local void make_crc_table OF((void));
#ifdef W
local z_word_t FAR crc_big_table[256];
local z_crc_t FAR crc_braid_table[W][256];
local z_word_t FAR crc_braid_big_table[W][256];
- local void braid OF((z_crc_t [][256], z_word_t [][256], int, int));
+ local void braid(z_crc_t [][256], z_word_t [][256], int, int);
#endif
#ifdef MAKECRCH
- local void write_table OF((FILE *, const z_crc_t FAR *, int));
- local void write_table32hi OF((FILE *, const z_word_t FAR *, int));
- local void write_table64 OF((FILE *, const z_word_t FAR *, int));
+ local void write_table(FILE *, const z_crc_t FAR *, int);
+ local void write_table32hi(FILE *, const z_word_t FAR *, int);
+ local void write_table64(FILE *, const z_word_t FAR *, int);
#endif /* MAKECRCH */
/*
@@ -176,7 +214,6 @@ local void make_crc_table OF((void));
/* Definition of once functionality. */
typedef struct once_s once_t;
-local void once OF((once_t *, void (*)(void)));
/* Check for the availability of atomics. */
#if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \
@@ -196,10 +233,7 @@ struct once_s {
invoke once() at the same time. The state must be a once_t initialized with
ONCE_INIT.
*/
-local void once(state, init)
- once_t *state;
- void (*init)(void);
-{
+local void once(once_t *state, void (*init)(void)) {
if (!atomic_load(&state->done)) {
if (atomic_flag_test_and_set(&state->begun))
while (!atomic_load(&state->done))
@@ -222,10 +256,7 @@ struct once_s {
/* Test and set. Alas, not atomic, but tries to minimize the period of
vulnerability. */
-local int test_and_set OF((int volatile *));
-local int test_and_set(flag)
- int volatile *flag;
-{
+local int test_and_set(int volatile *flag) {
int was;
was = *flag;
@@ -234,10 +265,7 @@ local int test_and_set(flag)
}
/* Run the provided init() function once. This is not thread-safe. */
-local void once(state, init)
- once_t *state;
- void (*init)(void);
-{
+local void once(once_t *state, void (*init)(void)) {
if (!state->done) {
if (test_and_set(&state->begun))
while (!state->done)
@@ -279,8 +307,7 @@ local once_t made = ONCE_INIT;
combinations of CRC register values and incoming bytes.
*/
-local void make_crc_table()
-{
+local void make_crc_table(void) {
unsigned i, j, n;
z_crc_t p;
@@ -447,11 +474,7 @@ local void make_crc_table()
Write the 32-bit values in table[0..k-1] to out, five per line in
hexadecimal separated by commas.
*/
-local void write_table(out, table, k)
- FILE *out;
- const z_crc_t FAR *table;
- int k;
-{
+local void write_table(FILE *out, const z_crc_t FAR *table, int k) {
int n;
for (n = 0; n < k; n++)
@@ -464,11 +487,7 @@ local void write_table(out, table, k)
Write the high 32-bits of each value in table[0..k-1] to out, five per line
in hexadecimal separated by commas.
*/
-local void write_table32hi(out, table, k)
-FILE *out;
-const z_word_t FAR *table;
-int k;
-{
+local void write_table32hi(FILE *out, const z_word_t FAR *table, int k) {
int n;
for (n = 0; n < k; n++)
@@ -484,11 +503,7 @@ int k;
bits. If not, then the type cast and format string can be adjusted
accordingly.
*/
-local void write_table64(out, table, k)
- FILE *out;
- const z_word_t FAR *table;
- int k;
-{
+local void write_table64(FILE *out, const z_word_t FAR *table, int k) {
int n;
for (n = 0; n < k; n++)
@@ -498,8 +513,7 @@ local void write_table64(out, table, k)
}
/* Actually do the deed. */
-int main()
-{
+int main(void) {
make_crc_table();
return 0;
}
@@ -511,12 +525,7 @@ int main()
Generate the little and big-endian braid tables for the given n and z_word_t
size w. Each array must have room for w blocks of 256 elements.
*/
-local void braid(ltl, big, n, w)
- z_crc_t ltl[][256];
- z_word_t big[][256];
- int n;
- int w;
-{
+local void braid(z_crc_t ltl[][256], z_word_t big[][256], int n, int w) {
int k;
z_crc_t i, p, q;
for (k = 0; k < w; k++) {
@@ -531,69 +540,13 @@ local void braid(ltl, big, n, w)
}
#endif
-#else /* !DYNAMIC_CRC_TABLE */
-/* ========================================================================
- * Tables for byte-wise and braided CRC-32 calculations, and a table of powers
- * of x for combining CRC-32s, all made by make_crc_table().
- */
-#include "crc32.h"
#endif /* DYNAMIC_CRC_TABLE */
-/* ========================================================================
- * Routines used for CRC calculation. Some are also required for the table
- * generation above.
- */
-
-/*
- Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial,
- reflected. For speed, this requires that a not be zero.
- */
-local z_crc_t multmodp(a, b)
- z_crc_t a;
- z_crc_t b;
-{
- z_crc_t m, p;
-
- m = (z_crc_t)1 << 31;
- p = 0;
- for (;;) {
- if (a & m) {
- p ^= b;
- if ((a & (m - 1)) == 0)
- break;
- }
- m >>= 1;
- b = b & 1 ? (b >> 1) ^ POLY : b >> 1;
- }
- return p;
-}
-
-/*
- Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been
- initialized.
- */
-local z_crc_t x2nmodp(n, k)
- z_off64_t n;
- unsigned k;
-{
- z_crc_t p;
-
- p = (z_crc_t)1 << 31; /* x^0 == 1 */
- while (n) {
- if (n & 1)
- p = multmodp(x2n_table[k & 31], p);
- n >>= 1;
- k++;
- }
- return p;
-}
-
/* =========================================================================
* This function can be used by asm versions of crc32(), and to force the
* generation of the CRC tables in a threaded application.
*/
-const z_crc_t FAR * ZEXPORT get_crc_table()
-{
+const z_crc_t FAR * ZEXPORT get_crc_table(void) {
#ifdef DYNAMIC_CRC_TABLE
once(&made, make_crc_table);
#endif /* DYNAMIC_CRC_TABLE */
@@ -619,11 +572,8 @@ const z_crc_t FAR * ZEXPORT get_crc_table()
#define Z_BATCH_ZEROS 0xa10d3d0c /* computed from Z_BATCH = 3990 */
#define Z_BATCH_MIN 800 /* fewest words in a final batch */
-unsigned long ZEXPORT crc32_z(crc, buf, len)
- unsigned long crc;
- const unsigned char FAR *buf;
- z_size_t len;
-{
+unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf,
+ z_size_t len) {
z_crc_t val;
z_word_t crc1, crc2;
const z_word_t *word;
@@ -723,18 +673,14 @@ unsigned long ZEXPORT crc32_z(crc, buf, len)
least-significant byte of the word as the first byte of data, without any pre
or post conditioning. This is used to combine the CRCs of each braid.
*/
-local z_crc_t crc_word(data)
- z_word_t data;
-{
+local z_crc_t crc_word(z_word_t data) {
int k;
for (k = 0; k < W; k++)
data = (data >> 8) ^ crc_table[data & 0xff];
return (z_crc_t)data;
}
-local z_word_t crc_word_big(data)
- z_word_t data;
-{
+local z_word_t crc_word_big(z_word_t data) {
int k;
for (k = 0; k < W; k++)
data = (data << 8) ^
@@ -745,11 +691,8 @@ local z_word_t crc_word_big(data)
#endif
/* ========================================================================= */
-unsigned long ZEXPORT crc32_z(crc, buf, len)
- unsigned long crc;
- const unsigned char FAR *buf;
- z_size_t len;
-{
+unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf,
+ z_size_t len) {
/* Return initial CRC, if requested. */
if (buf == Z_NULL) return 0;
@@ -781,8 +724,8 @@ unsigned long ZEXPORT crc32_z(crc, buf, len)
words = (z_word_t const *)buf;
/* Do endian check at execution time instead of compile time, since ARM
- processors can change the endianess at execution time. If the
- compiler knows what the endianess will be, it can optimize out the
+ processors can change the endianness at execution time. If the
+ compiler knows what the endianness will be, it can optimize out the
check and the unused branch. */
endian = 1;
if (*(unsigned char *)&endian) {
@@ -1069,20 +1012,13 @@ unsigned long ZEXPORT crc32_z(crc, buf, len)
#endif
/* ========================================================================= */
-unsigned long ZEXPORT crc32(crc, buf, len)
- unsigned long crc;
- const unsigned char FAR *buf;
- uInt len;
-{
+unsigned long ZEXPORT crc32(unsigned long crc, const unsigned char FAR *buf,
+ uInt len) {
return crc32_z(crc, buf, len);
}
/* ========================================================================= */
-uLong ZEXPORT crc32_combine64(crc1, crc2, len2)
- uLong crc1;
- uLong crc2;
- z_off64_t len2;
-{
+uLong ZEXPORT crc32_combine64(uLong crc1, uLong crc2, z_off64_t len2) {
#ifdef DYNAMIC_CRC_TABLE
once(&made, make_crc_table);
#endif /* DYNAMIC_CRC_TABLE */
@@ -1090,18 +1026,12 @@ uLong ZEXPORT crc32_combine64(crc1, crc2, len2)
}
/* ========================================================================= */
-uLong ZEXPORT crc32_combine(crc1, crc2, len2)
- uLong crc1;
- uLong crc2;
- z_off_t len2;
-{
+uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2) {
return crc32_combine64(crc1, crc2, (z_off64_t)len2);
}
/* ========================================================================= */
-uLong ZEXPORT crc32_combine_gen64(len2)
- z_off64_t len2;
-{
+uLong ZEXPORT crc32_combine_gen64(z_off64_t len2) {
#ifdef DYNAMIC_CRC_TABLE
once(&made, make_crc_table);
#endif /* DYNAMIC_CRC_TABLE */
@@ -1109,17 +1039,11 @@ uLong ZEXPORT crc32_combine_gen64(len2)
}
/* ========================================================================= */
-uLong ZEXPORT crc32_combine_gen(len2)
- z_off_t len2;
-{
+uLong ZEXPORT crc32_combine_gen(z_off_t len2) {
return crc32_combine_gen64((z_off64_t)len2);
}
/* ========================================================================= */
-uLong ZEXPORT crc32_combine_op(crc1, crc2, op)
- uLong crc1;
- uLong crc2;
- uLong op;
-{
+uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op) {
return multmodp(op, crc1) ^ (crc2 & 0xffffffff);
}
diff --git a/src/3rdparty/zlib/src/deflate.c b/src/3rdparty/zlib/src/deflate.c
index 4a689db359..012ea8148e 100644
--- a/src/3rdparty/zlib/src/deflate.c
+++ b/src/3rdparty/zlib/src/deflate.c
@@ -1,5 +1,5 @@
/* deflate.c -- compress data using the deflation algorithm
- * Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler
+ * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -52,7 +52,7 @@
#include "deflate.h"
const char deflate_copyright[] =
- " deflate 1.2.13 Copyright 1995-2022 Jean-loup Gailly and Mark Adler ";
+ " deflate 1.3.1 Copyright 1995-2024 Jean-loup Gailly and Mark Adler ";
/*
If you use the zlib library in a product, an acknowledgment is welcome
in the documentation of your product. If for some reason you cannot
@@ -60,9 +60,6 @@ const char deflate_copyright[] =
copyright string in the executable of your product.
*/
-/* ===========================================================================
- * Function prototypes.
- */
typedef enum {
need_more, /* block not completed, need more input or more output */
block_done, /* block flush performed */
@@ -70,29 +67,16 @@ typedef enum {
finish_done /* finish done, accept no more input or output */
} block_state;
-typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+typedef block_state (*compress_func)(deflate_state *s, int flush);
/* Compression function. Returns the block state after the call. */
-local int deflateStateCheck OF((z_streamp strm));
-local void slide_hash OF((deflate_state *s));
-local void fill_window OF((deflate_state *s));
-local block_state deflate_stored OF((deflate_state *s, int flush));
-local block_state deflate_fast OF((deflate_state *s, int flush));
+local block_state deflate_stored(deflate_state *s, int flush);
+local block_state deflate_fast(deflate_state *s, int flush);
#ifndef FASTEST
-local block_state deflate_slow OF((deflate_state *s, int flush));
-#endif
-local block_state deflate_rle OF((deflate_state *s, int flush));
-local block_state deflate_huff OF((deflate_state *s, int flush));
-local void lm_init OF((deflate_state *s));
-local void putShortMSB OF((deflate_state *s, uInt b));
-local void flush_pending OF((z_streamp strm));
-local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
-local uInt longest_match OF((deflate_state *s, IPos cur_match));
-
-#ifdef ZLIB_DEBUG
-local void check_match OF((deflate_state *s, IPos start, IPos match,
- int length));
+local block_state deflate_slow(deflate_state *s, int flush);
#endif
+local block_state deflate_rle(deflate_state *s, int flush);
+local block_state deflate_huff(deflate_state *s, int flush);
/* ===========================================================================
* Local data
@@ -195,9 +179,12 @@ local const config configuration_table[10] = {
* bit values at the expense of memory usage). We slide even when level == 0 to
* keep the hash table consistent if we switch back to level > 0 later.
*/
-local void slide_hash(s)
- deflate_state *s;
-{
+#if defined(__has_feature)
+# if __has_feature(memory_sanitizer)
+ __attribute__((no_sanitize("memory")))
+# endif
+#endif
+local void slide_hash(deflate_state *s) {
unsigned n, m;
Posf *p;
uInt wsize = s->w_size;
@@ -221,30 +208,177 @@ local void slide_hash(s)
#endif
}
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read. All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local unsigned read_buf(z_streamp strm, Bytef *buf, unsigned size) {
+ unsigned len = strm->avail_in;
+
+ if (len > size) len = size;
+ if (len == 0) return 0;
+
+ strm->avail_in -= len;
+
+ zmemcpy(buf, strm->next_in, len);
+ if (strm->state->wrap == 1) {
+ strm->adler = adler32(strm->adler, buf, len);
+ }
+#ifdef GZIP
+ else if (strm->state->wrap == 2) {
+ strm->adler = crc32(strm->adler, buf, len);
+ }
+#endif
+ strm->next_in += len;
+ strm->total_in += len;
+
+ return len;
+}
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ * At least one byte has been read, or avail_in == 0; reads are
+ * performed for at least two bytes (required for the zip translate_eol
+ * option -- not supported here).
+ */
+local void fill_window(deflate_state *s) {
+ unsigned n;
+ unsigned more; /* Amount of free space at the end of the window. */
+ uInt wsize = s->w_size;
+
+ Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");
+
+ do {
+ more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+ /* Deal with !@#$% 64K limit: */
+ if (sizeof(int) <= 2) {
+ if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+ more = wsize;
+
+ } else if (more == (unsigned)(-1)) {
+ /* Very unlikely, but possible on 16 bit machine if
+ * strstart == 0 && lookahead == 1 (input done a byte at time)
+ */
+ more--;
+ }
+ }
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ if (s->strstart >= wsize + MAX_DIST(s)) {
+
+ zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more);
+ s->match_start -= wsize;
+ s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
+ s->block_start -= (long) wsize;
+ if (s->insert > s->strstart)
+ s->insert = s->strstart;
+ slide_hash(s);
+ more += wsize;
+ }
+ if (s->strm->avail_in == 0) break;
+
+ /* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the BIG_MEM or MMAP case (not yet supported),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+ */
+ Assert(more >= 2, "more < 2");
+
+ n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+ s->lookahead += n;
+
+ /* Initialize the hash value now that we have some input: */
+ if (s->lookahead + s->insert >= MIN_MATCH) {
+ uInt str = s->strstart - s->insert;
+ s->ins_h = s->window[str];
+ UPDATE_HASH(s, s->ins_h, s->window[str + 1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ while (s->insert) {
+ UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);
+#ifndef FASTEST
+ s->prev[str & s->w_mask] = s->head[s->ins_h];
+#endif
+ s->head[s->ins_h] = (Pos)str;
+ str++;
+ s->insert--;
+ if (s->lookahead + s->insert < MIN_MATCH)
+ break;
+ }
+ }
+ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+ * but this is not important since only literal bytes will be emitted.
+ */
+
+ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+
+ /* If the WIN_INIT bytes after the end of the current data have never been
+ * written, then zero those bytes in order to avoid memory check reports of
+ * the use of uninitialized (or uninitialised as Julian writes) bytes by
+ * the longest match routines. Update the high water mark for the next
+ * time through here. WIN_INIT is set to MAX_MATCH since the longest match
+ * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
+ */
+ if (s->high_water < s->window_size) {
+ ulg curr = s->strstart + (ulg)(s->lookahead);
+ ulg init;
+
+ if (s->high_water < curr) {
+ /* Previous high water mark below current data -- zero WIN_INIT
+ * bytes or up to end of window, whichever is less.
+ */
+ init = s->window_size - curr;
+ if (init > WIN_INIT)
+ init = WIN_INIT;
+ zmemzero(s->window + curr, (unsigned)init);
+ s->high_water = curr + init;
+ }
+ else if (s->high_water < (ulg)curr + WIN_INIT) {
+ /* High water mark at or above current data, but below current data
+ * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
+ * to end of window, whichever is less.
+ */
+ init = (ulg)curr + WIN_INIT - s->high_water;
+ if (init > s->window_size - s->high_water)
+ init = s->window_size - s->high_water;
+ zmemzero(s->window + s->high_water, (unsigned)init);
+ s->high_water += init;
+ }
+ }
+
+ Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
+ "not enough room for search");
+}
+
/* ========================================================================= */
-int ZEXPORT deflateInit_(strm, level, version, stream_size)
- z_streamp strm;
- int level;
- const char *version;
- int stream_size;
-{
+int ZEXPORT deflateInit_(z_streamp strm, int level, const char *version,
+ int stream_size) {
return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
Z_DEFAULT_STRATEGY, version, stream_size);
/* To do: ignore strm->next_in if we use it as window */
}
/* ========================================================================= */
-int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
- version, stream_size)
- z_streamp strm;
- int level;
- int method;
- int windowBits;
- int memLevel;
- int strategy;
- const char *version;
- int stream_size;
-{
+int ZEXPORT deflateInit2_(z_streamp strm, int level, int method,
+ int windowBits, int memLevel, int strategy,
+ const char *version, int stream_size) {
deflate_state *s;
int wrap = 1;
static const char my_version[] = ZLIB_VERSION;
@@ -359,7 +493,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
* symbols from which it is being constructed.
*/
- s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, 4);
+ s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, LIT_BUFS);
s->pending_buf_size = (ulg)s->lit_bufsize * 4;
if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
@@ -369,8 +503,14 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
deflateEnd (strm);
return Z_MEM_ERROR;
}
+#ifdef LIT_MEM
+ s->d_buf = (ushf *)(s->pending_buf + (s->lit_bufsize << 1));
+ s->l_buf = s->pending_buf + (s->lit_bufsize << 2);
+ s->sym_end = s->lit_bufsize - 1;
+#else
s->sym_buf = s->pending_buf + s->lit_bufsize;
s->sym_end = (s->lit_bufsize - 1) * 3;
+#endif
/* We avoid equality with lit_bufsize*3 because of wraparound at 64K
* on 16 bit machines and because stored blocks are restricted to
* 64K-1 bytes.
@@ -386,9 +526,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
/* =========================================================================
* Check for a valid deflate stream state. Return 0 if ok, 1 if not.
*/
-local int deflateStateCheck(strm)
- z_streamp strm;
-{
+local int deflateStateCheck(z_streamp strm) {
deflate_state *s;
if (strm == Z_NULL ||
strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)
@@ -409,11 +547,8 @@ local int deflateStateCheck(strm)
}
/* ========================================================================= */
-int ZEXPORT deflateSetDictionary(strm, dictionary, dictLength)
- z_streamp strm;
- const Bytef *dictionary;
- uInt dictLength;
-{
+int ZEXPORT deflateSetDictionary(z_streamp strm, const Bytef *dictionary,
+ uInt dictLength) {
deflate_state *s;
uInt str, n;
int wrap;
@@ -478,11 +613,8 @@ int ZEXPORT deflateSetDictionary(strm, dictionary, dictLength)
}
/* ========================================================================= */
-int ZEXPORT deflateGetDictionary(strm, dictionary, dictLength)
- z_streamp strm;
- Bytef *dictionary;
- uInt *dictLength;
-{
+int ZEXPORT deflateGetDictionary(z_streamp strm, Bytef *dictionary,
+ uInt *dictLength) {
deflate_state *s;
uInt len;
@@ -500,9 +632,7 @@ int ZEXPORT deflateGetDictionary(strm, dictionary, dictLength)
}
/* ========================================================================= */
-int ZEXPORT deflateResetKeep(strm)
- z_streamp strm;
-{
+int ZEXPORT deflateResetKeep(z_streamp strm) {
deflate_state *s;
if (deflateStateCheck(strm)) {
@@ -537,10 +667,32 @@ int ZEXPORT deflateResetKeep(strm)
return Z_OK;
}
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init(deflate_state *s) {
+ s->window_size = (ulg)2L*s->w_size;
+
+ CLEAR_HASH(s);
+
+ /* Set the default configuration parameters:
+ */
+ s->max_lazy_match = configuration_table[s->level].max_lazy;
+ s->good_match = configuration_table[s->level].good_length;
+ s->nice_match = configuration_table[s->level].nice_length;
+ s->max_chain_length = configuration_table[s->level].max_chain;
+
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->lookahead = 0;
+ s->insert = 0;
+ s->match_length = s->prev_length = MIN_MATCH-1;
+ s->match_available = 0;
+ s->ins_h = 0;
+}
+
/* ========================================================================= */
-int ZEXPORT deflateReset(strm)
- z_streamp strm;
-{
+int ZEXPORT deflateReset(z_streamp strm) {
int ret;
ret = deflateResetKeep(strm);
@@ -550,10 +702,7 @@ int ZEXPORT deflateReset(strm)
}
/* ========================================================================= */
-int ZEXPORT deflateSetHeader(strm, head)
- z_streamp strm;
- gz_headerp head;
-{
+int ZEXPORT deflateSetHeader(z_streamp strm, gz_headerp head) {
if (deflateStateCheck(strm) || strm->state->wrap != 2)
return Z_STREAM_ERROR;
strm->state->gzhead = head;
@@ -561,11 +710,7 @@ int ZEXPORT deflateSetHeader(strm, head)
}
/* ========================================================================= */
-int ZEXPORT deflatePending(strm, pending, bits)
- unsigned *pending;
- int *bits;
- z_streamp strm;
-{
+int ZEXPORT deflatePending(z_streamp strm, unsigned *pending, int *bits) {
if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
if (pending != Z_NULL)
*pending = strm->state->pending;
@@ -575,19 +720,21 @@ int ZEXPORT deflatePending(strm, pending, bits)
}
/* ========================================================================= */
-int ZEXPORT deflatePrime(strm, bits, value)
- z_streamp strm;
- int bits;
- int value;
-{
+int ZEXPORT deflatePrime(z_streamp strm, int bits, int value) {
deflate_state *s;
int put;
if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
s = strm->state;
+#ifdef LIT_MEM
+ if (bits < 0 || bits > 16 ||
+ (uchf *)s->d_buf < s->pending_out + ((Buf_size + 7) >> 3))
+ return Z_BUF_ERROR;
+#else
if (bits < 0 || bits > 16 ||
s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3))
return Z_BUF_ERROR;
+#endif
do {
put = Buf_size - s->bi_valid;
if (put > bits)
@@ -602,11 +749,7 @@ int ZEXPORT deflatePrime(strm, bits, value)
}
/* ========================================================================= */
-int ZEXPORT deflateParams(strm, level, strategy)
- z_streamp strm;
- int level;
- int strategy;
-{
+int ZEXPORT deflateParams(z_streamp strm, int level, int strategy) {
deflate_state *s;
compress_func func;
@@ -651,13 +794,8 @@ int ZEXPORT deflateParams(strm, level, strategy)
}
/* ========================================================================= */
-int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
- z_streamp strm;
- int good_length;
- int max_lazy;
- int nice_length;
- int max_chain;
-{
+int ZEXPORT deflateTune(z_streamp strm, int good_length, int max_lazy,
+ int nice_length, int max_chain) {
deflate_state *s;
if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
@@ -693,10 +831,7 @@ int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
*
* Shifts are used to approximate divisions, for speed.
*/
-uLong ZEXPORT deflateBound(strm, sourceLen)
- z_streamp strm;
- uLong sourceLen;
-{
+uLong ZEXPORT deflateBound(z_streamp strm, uLong sourceLen) {
deflate_state *s;
uLong fixedlen, storelen, wraplen;
@@ -752,7 +887,8 @@ uLong ZEXPORT deflateBound(strm, sourceLen)
/* if not default parameters, return one of the conservative bounds */
if (s->w_bits != 15 || s->hash_bits != 8 + 7)
- return (s->w_bits <= s->hash_bits ? fixedlen : storelen) + wraplen;
+ return (s->w_bits <= s->hash_bits && s->level ? fixedlen : storelen) +
+ wraplen;
/* default settings: return tight bound for that case -- ~0.03% overhead
plus a small constant */
@@ -765,10 +901,7 @@ uLong ZEXPORT deflateBound(strm, sourceLen)
* IN assertion: the stream state is correct and there is enough room in
* pending_buf.
*/
-local void putShortMSB(s, b)
- deflate_state *s;
- uInt b;
-{
+local void putShortMSB(deflate_state *s, uInt b) {
put_byte(s, (Byte)(b >> 8));
put_byte(s, (Byte)(b & 0xff));
}
@@ -779,9 +912,7 @@ local void putShortMSB(s, b)
* applications may wish to modify it to avoid allocating a large
* strm->next_out buffer and copying into it. (See also read_buf()).
*/
-local void flush_pending(strm)
- z_streamp strm;
-{
+local void flush_pending(z_streamp strm) {
unsigned len;
deflate_state *s = strm->state;
@@ -812,10 +943,7 @@ local void flush_pending(strm)
} while (0)
/* ========================================================================= */
-int ZEXPORT deflate(strm, flush)
- z_streamp strm;
- int flush;
-{
+int ZEXPORT deflate(z_streamp strm, int flush) {
int old_flush; /* value of flush param for previous deflate call */
deflate_state *s;
@@ -1127,9 +1255,7 @@ int ZEXPORT deflate(strm, flush)
}
/* ========================================================================= */
-int ZEXPORT deflateEnd(strm)
- z_streamp strm;
-{
+int ZEXPORT deflateEnd(z_streamp strm) {
int status;
if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
@@ -1153,11 +1279,10 @@ int ZEXPORT deflateEnd(strm)
* To simplify the source, this is not supported for 16-bit MSDOS (which
* doesn't have enough memory anyway to duplicate compression states).
*/
-int ZEXPORT deflateCopy(dest, source)
- z_streamp dest;
- z_streamp source;
-{
+int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) {
#ifdef MAXSEG_64K
+ (void)dest;
+ (void)source;
return Z_STREAM_ERROR;
#else
deflate_state *ds;
@@ -1181,7 +1306,7 @@ int ZEXPORT deflateCopy(dest, source)
ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
- ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, 4);
+ ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, LIT_BUFS);
if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
ds->pending_buf == Z_NULL) {
@@ -1192,10 +1317,15 @@ int ZEXPORT deflateCopy(dest, source)
zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos));
zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos));
- zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+ zmemcpy(ds->pending_buf, ss->pending_buf, ds->lit_bufsize * LIT_BUFS);
ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+#ifdef LIT_MEM
+ ds->d_buf = (ushf *)(ds->pending_buf + (ds->lit_bufsize << 1));
+ ds->l_buf = ds->pending_buf + (ds->lit_bufsize << 2);
+#else
ds->sym_buf = ds->pending_buf + ds->lit_bufsize;
+#endif
ds->l_desc.dyn_tree = ds->dyn_ltree;
ds->d_desc.dyn_tree = ds->dyn_dtree;
@@ -1205,66 +1335,6 @@ int ZEXPORT deflateCopy(dest, source)
#endif /* MAXSEG_64K */
}
-/* ===========================================================================
- * Read a new buffer from the current input stream, update the adler32
- * and total number of bytes read. All deflate() input goes through
- * this function so some applications may wish to modify it to avoid
- * allocating a large strm->next_in buffer and copying from it.
- * (See also flush_pending()).
- */
-local unsigned read_buf(strm, buf, size)
- z_streamp strm;
- Bytef *buf;
- unsigned size;
-{
- unsigned len = strm->avail_in;
-
- if (len > size) len = size;
- if (len == 0) return 0;
-
- strm->avail_in -= len;
-
- zmemcpy(buf, strm->next_in, len);
- if (strm->state->wrap == 1) {
- strm->adler = adler32(strm->adler, buf, len);
- }
-#ifdef GZIP
- else if (strm->state->wrap == 2) {
- strm->adler = crc32(strm->adler, buf, len);
- }
-#endif
- strm->next_in += len;
- strm->total_in += len;
-
- return len;
-}
-
-/* ===========================================================================
- * Initialize the "longest match" routines for a new zlib stream
- */
-local void lm_init(s)
- deflate_state *s;
-{
- s->window_size = (ulg)2L*s->w_size;
-
- CLEAR_HASH(s);
-
- /* Set the default configuration parameters:
- */
- s->max_lazy_match = configuration_table[s->level].max_lazy;
- s->good_match = configuration_table[s->level].good_length;
- s->nice_match = configuration_table[s->level].nice_length;
- s->max_chain_length = configuration_table[s->level].max_chain;
-
- s->strstart = 0;
- s->block_start = 0L;
- s->lookahead = 0;
- s->insert = 0;
- s->match_length = s->prev_length = MIN_MATCH-1;
- s->match_available = 0;
- s->ins_h = 0;
-}
-
#ifndef FASTEST
/* ===========================================================================
* Set match_start to the longest match starting at the given string and
@@ -1275,10 +1345,7 @@ local void lm_init(s)
* string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
* OUT assertion: the match length is not greater than s->lookahead.
*/
-local uInt longest_match(s, cur_match)
- deflate_state *s;
- IPos cur_match; /* current match */
-{
+local uInt longest_match(deflate_state *s, IPos cur_match) {
unsigned chain_length = s->max_chain_length;/* max hash chain length */
register Bytef *scan = s->window + s->strstart; /* current string */
register Bytef *match; /* matched string */
@@ -1426,10 +1493,7 @@ local uInt longest_match(s, cur_match)
/* ---------------------------------------------------------------------------
* Optimized version for FASTEST only
*/
-local uInt longest_match(s, cur_match)
- deflate_state *s;
- IPos cur_match; /* current match */
-{
+local uInt longest_match(deflate_state *s, IPos cur_match) {
register Bytef *scan = s->window + s->strstart; /* current string */
register Bytef *match; /* matched string */
register int len; /* length of current match */
@@ -1490,19 +1554,23 @@ local uInt longest_match(s, cur_match)
/* ===========================================================================
* Check that the match at match_start is indeed a match.
*/
-local void check_match(s, start, match, length)
- deflate_state *s;
- IPos start, match;
- int length;
-{
+local void check_match(deflate_state *s, IPos start, IPos match, int length) {
/* check that the match is indeed a match */
- if (zmemcmp(s->window + match,
- s->window + start, length) != EQUAL) {
- fprintf(stderr, " start %u, match %u, length %d\n",
- start, match, length);
+ Bytef *back = s->window + (int)match, *here = s->window + start;
+ IPos len = length;
+ if (match == (IPos)-1) {
+ /* match starts one byte before the current window -- just compare the
+ subsequent length-1 bytes */
+ back++;
+ here++;
+ len--;
+ }
+ if (zmemcmp(back, here, len) != EQUAL) {
+ fprintf(stderr, " start %u, match %d, length %d\n",
+ start, (int)match, length);
do {
- fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
- } while (--length != 0);
+ fprintf(stderr, "(%02x %02x)", *back++, *here++);
+ } while (--len != 0);
z_error("invalid match");
}
if (z_verbose > 1) {
@@ -1515,137 +1583,6 @@ local void check_match(s, start, match, length)
#endif /* ZLIB_DEBUG */
/* ===========================================================================
- * Fill the window when the lookahead becomes insufficient.
- * Updates strstart and lookahead.
- *
- * IN assertion: lookahead < MIN_LOOKAHEAD
- * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
- * At least one byte has been read, or avail_in == 0; reads are
- * performed for at least two bytes (required for the zip translate_eol
- * option -- not supported here).
- */
-local void fill_window(s)
- deflate_state *s;
-{
- unsigned n;
- unsigned more; /* Amount of free space at the end of the window. */
- uInt wsize = s->w_size;
-
- Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");
-
- do {
- more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
-
- /* Deal with !@#$% 64K limit: */
- if (sizeof(int) <= 2) {
- if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
- more = wsize;
-
- } else if (more == (unsigned)(-1)) {
- /* Very unlikely, but possible on 16 bit machine if
- * strstart == 0 && lookahead == 1 (input done a byte at time)
- */
- more--;
- }
- }
-
- /* If the window is almost full and there is insufficient lookahead,
- * move the upper half to the lower one to make room in the upper half.
- */
- if (s->strstart >= wsize + MAX_DIST(s)) {
-
- zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more);
- s->match_start -= wsize;
- s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
- s->block_start -= (long) wsize;
- if (s->insert > s->strstart)
- s->insert = s->strstart;
- slide_hash(s);
- more += wsize;
- }
- if (s->strm->avail_in == 0) break;
-
- /* If there was no sliding:
- * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
- * more == window_size - lookahead - strstart
- * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
- * => more >= window_size - 2*WSIZE + 2
- * In the BIG_MEM or MMAP case (not yet supported),
- * window_size == input_size + MIN_LOOKAHEAD &&
- * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
- * Otherwise, window_size == 2*WSIZE so more >= 2.
- * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
- */
- Assert(more >= 2, "more < 2");
-
- n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
- s->lookahead += n;
-
- /* Initialize the hash value now that we have some input: */
- if (s->lookahead + s->insert >= MIN_MATCH) {
- uInt str = s->strstart - s->insert;
- s->ins_h = s->window[str];
- UPDATE_HASH(s, s->ins_h, s->window[str + 1]);
-#if MIN_MATCH != 3
- Call UPDATE_HASH() MIN_MATCH-3 more times
-#endif
- while (s->insert) {
- UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);
-#ifndef FASTEST
- s->prev[str & s->w_mask] = s->head[s->ins_h];
-#endif
- s->head[s->ins_h] = (Pos)str;
- str++;
- s->insert--;
- if (s->lookahead + s->insert < MIN_MATCH)
- break;
- }
- }
- /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
- * but this is not important since only literal bytes will be emitted.
- */
-
- } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
-
- /* If the WIN_INIT bytes after the end of the current data have never been
- * written, then zero those bytes in order to avoid memory check reports of
- * the use of uninitialized (or uninitialised as Julian writes) bytes by
- * the longest match routines. Update the high water mark for the next
- * time through here. WIN_INIT is set to MAX_MATCH since the longest match
- * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
- */
- if (s->high_water < s->window_size) {
- ulg curr = s->strstart + (ulg)(s->lookahead);
- ulg init;
-
- if (s->high_water < curr) {
- /* Previous high water mark below current data -- zero WIN_INIT
- * bytes or up to end of window, whichever is less.
- */
- init = s->window_size - curr;
- if (init > WIN_INIT)
- init = WIN_INIT;
- zmemzero(s->window + curr, (unsigned)init);
- s->high_water = curr + init;
- }
- else if (s->high_water < (ulg)curr + WIN_INIT) {
- /* High water mark at or above current data, but below current data
- * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
- * to end of window, whichever is less.
- */
- init = (ulg)curr + WIN_INIT - s->high_water;
- if (init > s->window_size - s->high_water)
- init = s->window_size - s->high_water;
- zmemzero(s->window + s->high_water, (unsigned)init);
- s->high_water += init;
- }
- }
-
- Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
- "not enough room for search");
-}
-
-/* ===========================================================================
* Flush the current block, with given end-of-file flag.
* IN assertion: strstart is set to the end of the current match.
*/
@@ -1687,10 +1624,7 @@ local void fill_window(s)
* copied. It is most efficient with large input and output buffers, which
* maximizes the opportunities to have a single copy from next_in to next_out.
*/
-local block_state deflate_stored(s, flush)
- deflate_state *s;
- int flush;
-{
+local block_state deflate_stored(deflate_state *s, int flush) {
/* Smallest worthy block size when not flushing or finishing. By default
* this is 32K. This can be as small as 507 bytes for memLevel == 1. For
* large input and output buffers, the stored block size will be larger.
@@ -1874,10 +1808,7 @@ local block_state deflate_stored(s, flush)
* new strings in the dictionary only for unmatched strings or for short
* matches. It is used only for the fast compression options.
*/
-local block_state deflate_fast(s, flush)
- deflate_state *s;
- int flush;
-{
+local block_state deflate_fast(deflate_state *s, int flush) {
IPos hash_head; /* head of the hash chain */
int bflush; /* set if current block must be flushed */
@@ -1976,10 +1907,7 @@ local block_state deflate_fast(s, flush)
* evaluation for matches: a match is finally adopted only if there is
* no better match at the next window position.
*/
-local block_state deflate_slow(s, flush)
- deflate_state *s;
- int flush;
-{
+local block_state deflate_slow(deflate_state *s, int flush) {
IPos hash_head; /* head of hash chain */
int bflush; /* set if current block must be flushed */
@@ -2107,10 +2035,7 @@ local block_state deflate_slow(s, flush)
* one. Do not maintain a hash table. (It will be regenerated if this run of
* deflate switches away from Z_RLE.)
*/
-local block_state deflate_rle(s, flush)
- deflate_state *s;
- int flush;
-{
+local block_state deflate_rle(deflate_state *s, int flush) {
int bflush; /* set if current block must be flushed */
uInt prev; /* byte at distance one to match */
Bytef *scan, *strend; /* scan goes up to strend for length of run */
@@ -2181,10 +2106,7 @@ local block_state deflate_rle(s, flush)
* For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table.
* (It will be regenerated if this run of deflate switches away from Huffman.)
*/
-local block_state deflate_huff(s, flush)
- deflate_state *s;
- int flush;
-{
+local block_state deflate_huff(deflate_state *s, int flush) {
int bflush; /* set if current block must be flushed */
for (;;) {
diff --git a/src/3rdparty/zlib/src/deflate.h b/src/3rdparty/zlib/src/deflate.h
index 1a06cd5f25..300c6ada62 100644
--- a/src/3rdparty/zlib/src/deflate.h
+++ b/src/3rdparty/zlib/src/deflate.h
@@ -1,5 +1,5 @@
/* deflate.h -- internal compression state
- * Copyright (C) 1995-2018 Jean-loup Gailly
+ * Copyright (C) 1995-2024 Jean-loup Gailly
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -23,6 +23,10 @@
# define GZIP
#endif
+/* define LIT_MEM to slightly increase the speed of deflate (order 1% to 2%) at
+ the cost of a larger memory footprint */
+/* #define LIT_MEM */
+
/* ===========================================================================
* Internal compression state.
*/
@@ -217,7 +221,14 @@ typedef struct internal_state {
/* Depth of each subtree used as tie breaker for trees of equal frequency
*/
+#ifdef LIT_MEM
+# define LIT_BUFS 5
+ ushf *d_buf; /* buffer for distances */
+ uchf *l_buf; /* buffer for literals/lengths */
+#else
+# define LIT_BUFS 4
uchf *sym_buf; /* buffer for distances and literals/lengths */
+#endif
uInt lit_bufsize;
/* Size of match buffer for literals/lengths. There are 4 reasons for
@@ -239,7 +250,7 @@ typedef struct internal_state {
* - I can't count above 4
*/
- uInt sym_next; /* running index in sym_buf */
+ uInt sym_next; /* running index in symbol buffer */
uInt sym_end; /* symbol table full when sym_next reaches this */
ulg opt_len; /* bit length of current block with optimal trees */
@@ -291,14 +302,14 @@ typedef struct internal_state {
memory checker errors from longest match routines */
/* in trees.c */
-void ZLIB_INTERNAL _tr_init OF((deflate_state *s));
-int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
-void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf,
- ulg stored_len, int last));
-void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s));
-void ZLIB_INTERNAL _tr_align OF((deflate_state *s));
-void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
- ulg stored_len, int last));
+void ZLIB_INTERNAL _tr_init(deflate_state *s);
+int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc);
+void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf,
+ ulg stored_len, int last);
+void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s);
+void ZLIB_INTERNAL _tr_align(deflate_state *s);
+void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf,
+ ulg stored_len, int last);
#define d_code(dist) \
((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
@@ -318,6 +329,25 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
extern const uch ZLIB_INTERNAL _dist_code[];
#endif
+#ifdef LIT_MEM
+# define _tr_tally_lit(s, c, flush) \
+ { uch cc = (c); \
+ s->d_buf[s->sym_next] = 0; \
+ s->l_buf[s->sym_next++] = cc; \
+ s->dyn_ltree[cc].Freq++; \
+ flush = (s->sym_next == s->sym_end); \
+ }
+# define _tr_tally_dist(s, distance, length, flush) \
+ { uch len = (uch)(length); \
+ ush dist = (ush)(distance); \
+ s->d_buf[s->sym_next] = dist; \
+ s->l_buf[s->sym_next++] = len; \
+ dist--; \
+ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+ s->dyn_dtree[d_code(dist)].Freq++; \
+ flush = (s->sym_next == s->sym_end); \
+ }
+#else
# define _tr_tally_lit(s, c, flush) \
{ uch cc = (c); \
s->sym_buf[s->sym_next++] = 0; \
@@ -337,6 +367,7 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
s->dyn_dtree[d_code(dist)].Freq++; \
flush = (s->sym_next == s->sym_end); \
}
+#endif
#else
# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
# define _tr_tally_dist(s, distance, length, flush) \
diff --git a/src/3rdparty/zlib/src/gzclose.c b/src/3rdparty/zlib/src/gzclose.c
index caeb99a317..48d6a86f04 100644
--- a/src/3rdparty/zlib/src/gzclose.c
+++ b/src/3rdparty/zlib/src/gzclose.c
@@ -8,9 +8,7 @@
/* gzclose() is in a separate file so that it is linked in only if it is used.
That way the other gzclose functions can be used instead to avoid linking in
unneeded compression or decompression routines. */
-int ZEXPORT gzclose(file)
- gzFile file;
-{
+int ZEXPORT gzclose(gzFile file) {
#ifndef NO_GZCOMPRESS
gz_statep state;
diff --git a/src/3rdparty/zlib/src/gzguts.h b/src/3rdparty/zlib/src/gzguts.h
index 26d2ac9bd0..5bf6b7d481 100644
--- a/src/3rdparty/zlib/src/gzguts.h
+++ b/src/3rdparty/zlib/src/gzguts.h
@@ -1,5 +1,5 @@
/* gzguts.h -- zlib internal header definitions for gz* operations
- * Copyright (C) 2004-2019 Mark Adler
+ * Copyright (C) 2004-2024 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -13,9 +13,8 @@
# ifndef _LARGEFILE_SOURCE
# define _LARGEFILE_SOURCE 1
# endif
-# ifdef _FILE_OFFSET_BITS
-# undef _FILE_OFFSET_BITS
-# endif
+# undef _FILE_OFFSET_BITS
+# undef _TIME_BITS
#endif
#ifdef HAVE_HIDDEN
@@ -125,8 +124,8 @@
/* gz* functions always use library allocation functions */
#ifndef STDC
- extern voidp malloc OF((uInt size));
- extern void free OF((voidpf ptr));
+ extern voidp malloc(uInt size);
+ extern void free(voidpf ptr);
#endif
/* get errno and strerror definition */
@@ -144,10 +143,10 @@
/* provide prototypes for these when building zlib without LFS */
#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0
- ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
- ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
- ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
- ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
+ ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *);
+ ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int);
+ ZEXTERN z_off64_t ZEXPORT gztell64(gzFile);
+ ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile);
#endif
/* default memLevel */
@@ -209,17 +208,13 @@ typedef struct {
typedef gz_state FAR *gz_statep;
/* shared functions */
-void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *));
+void ZLIB_INTERNAL gz_error(gz_statep, int, const char *);
#if defined UNDER_CE
-char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error));
+char ZLIB_INTERNAL *gz_strwinerror(DWORD error);
#endif
/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t
value -- needed when comparing unsigned to z_off64_t, which is signed
(possible z_off64_t types off_t, off64_t, and long are all signed) */
-#ifdef INT_MAX
-# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX)
-#else
-unsigned ZLIB_INTERNAL gz_intmax OF((void));
-# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())
-#endif
+unsigned ZLIB_INTERNAL gz_intmax(void);
+#define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())
diff --git a/src/3rdparty/zlib/src/gzlib.c b/src/3rdparty/zlib/src/gzlib.c
index 55da46a453..983153cc8e 100644
--- a/src/3rdparty/zlib/src/gzlib.c
+++ b/src/3rdparty/zlib/src/gzlib.c
@@ -1,5 +1,5 @@
/* gzlib.c -- zlib functions common to reading and writing gzip files
- * Copyright (C) 2004-2019 Mark Adler
+ * Copyright (C) 2004-2024 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -15,10 +15,6 @@
#endif
#endif
-/* Local functions */
-local void gz_reset OF((gz_statep));
-local gzFile gz_open OF((const void *, int, const char *));
-
#if defined UNDER_CE
/* Map the Windows error number in ERROR to a locale-dependent error message
@@ -30,9 +26,7 @@ local gzFile gz_open OF((const void *, int, const char *));
The gz_strwinerror function does not change the current setting of
GetLastError. */
-char ZLIB_INTERNAL *gz_strwinerror(error)
- DWORD error;
-{
+char ZLIB_INTERNAL *gz_strwinerror(DWORD error) {
static char buf[1024];
wchar_t *msgbuf;
@@ -72,9 +66,7 @@ char ZLIB_INTERNAL *gz_strwinerror(error)
#endif /* UNDER_CE */
/* Reset gzip file state */
-local void gz_reset(state)
- gz_statep state;
-{
+local void gz_reset(gz_statep state) {
state->x.have = 0; /* no output data available */
if (state->mode == GZ_READ) { /* for reading ... */
state->eof = 0; /* not at end of file */
@@ -90,11 +82,7 @@ local void gz_reset(state)
}
/* Open a gzip file either by name or file descriptor. */
-local gzFile gz_open(path, fd, mode)
- const void *path;
- int fd;
- const char *mode;
-{
+local gzFile gz_open(const void *path, int fd, const char *mode) {
gz_statep state;
z_size_t len;
int oflag;
@@ -269,26 +257,17 @@ local gzFile gz_open(path, fd, mode)
}
/* -- see zlib.h -- */
-gzFile ZEXPORT gzopen(path, mode)
- const char *path;
- const char *mode;
-{
+gzFile ZEXPORT gzopen(const char *path, const char *mode) {
return gz_open(path, -1, mode);
}
/* -- see zlib.h -- */
-gzFile ZEXPORT gzopen64(path, mode)
- const char *path;
- const char *mode;
-{
+gzFile ZEXPORT gzopen64(const char *path, const char *mode) {
return gz_open(path, -1, mode);
}
/* -- see zlib.h -- */
-gzFile ZEXPORT gzdopen(fd, mode)
- int fd;
- const char *mode;
-{
+gzFile ZEXPORT gzdopen(int fd, const char *mode) {
char *path; /* identifier for error messages */
gzFile gz;
@@ -306,19 +285,13 @@ gzFile ZEXPORT gzdopen(fd, mode)
/* -- see zlib.h -- */
#ifdef WIDECHAR
-gzFile ZEXPORT gzopen_w(path, mode)
- const wchar_t *path;
- const char *mode;
-{
+gzFile ZEXPORT gzopen_w(const wchar_t *path, const char *mode) {
return gz_open(path, -2, mode);
}
#endif
/* -- see zlib.h -- */
-int ZEXPORT gzbuffer(file, size)
- gzFile file;
- unsigned size;
-{
+int ZEXPORT gzbuffer(gzFile file, unsigned size) {
gz_statep state;
/* get internal structure and check integrity */
@@ -335,16 +308,14 @@ int ZEXPORT gzbuffer(file, size)
/* check and set requested size */
if ((size << 1) < size)
return -1; /* need to be able to double it */
- if (size < 2)
- size = 2; /* need two bytes to check magic header */
+ if (size < 8)
+ size = 8; /* needed to behave well with flushing */
state->want = size;
return 0;
}
/* -- see zlib.h -- */
-int ZEXPORT gzrewind(file)
- gzFile file;
-{
+int ZEXPORT gzrewind(gzFile file) {
gz_statep state;
/* get internal structure */
@@ -365,11 +336,7 @@ int ZEXPORT gzrewind(file)
}
/* -- see zlib.h -- */
-z_off64_t ZEXPORT gzseek64(file, offset, whence)
- gzFile file;
- z_off64_t offset;
- int whence;
-{
+z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
unsigned n;
z_off64_t ret;
gz_statep state;
@@ -442,11 +409,7 @@ z_off64_t ZEXPORT gzseek64(file, offset, whence)
}
/* -- see zlib.h -- */
-z_off_t ZEXPORT gzseek(file, offset, whence)
- gzFile file;
- z_off_t offset;
- int whence;
-{
+z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) {
z_off64_t ret;
ret = gzseek64(file, (z_off64_t)offset, whence);
@@ -454,9 +417,7 @@ z_off_t ZEXPORT gzseek(file, offset, whence)
}
/* -- see zlib.h -- */
-z_off64_t ZEXPORT gztell64(file)
- gzFile file;
-{
+z_off64_t ZEXPORT gztell64(gzFile file) {
gz_statep state;
/* get internal structure and check integrity */
@@ -471,9 +432,7 @@ z_off64_t ZEXPORT gztell64(file)
}
/* -- see zlib.h -- */
-z_off_t ZEXPORT gztell(file)
- gzFile file;
-{
+z_off_t ZEXPORT gztell(gzFile file) {
z_off64_t ret;
ret = gztell64(file);
@@ -481,9 +440,7 @@ z_off_t ZEXPORT gztell(file)
}
/* -- see zlib.h -- */
-z_off64_t ZEXPORT gzoffset64(file)
- gzFile file;
-{
+z_off64_t ZEXPORT gzoffset64(gzFile file) {
z_off64_t offset;
gz_statep state;
@@ -504,9 +461,7 @@ z_off64_t ZEXPORT gzoffset64(file)
}
/* -- see zlib.h -- */
-z_off_t ZEXPORT gzoffset(file)
- gzFile file;
-{
+z_off_t ZEXPORT gzoffset(gzFile file) {
z_off64_t ret;
ret = gzoffset64(file);
@@ -514,9 +469,7 @@ z_off_t ZEXPORT gzoffset(file)
}
/* -- see zlib.h -- */
-int ZEXPORT gzeof(file)
- gzFile file;
-{
+int ZEXPORT gzeof(gzFile file) {
gz_statep state;
/* get internal structure and check integrity */
@@ -531,10 +484,7 @@ int ZEXPORT gzeof(file)
}
/* -- see zlib.h -- */
-const char * ZEXPORT gzerror(file, errnum)
- gzFile file;
- int *errnum;
-{
+const char * ZEXPORT gzerror(gzFile file, int *errnum) {
gz_statep state;
/* get internal structure and check integrity */
@@ -552,9 +502,7 @@ const char * ZEXPORT gzerror(file, errnum)
}
/* -- see zlib.h -- */
-void ZEXPORT gzclearerr(file)
- gzFile file;
-{
+void ZEXPORT gzclearerr(gzFile file) {
gz_statep state;
/* get internal structure and check integrity */
@@ -578,11 +526,7 @@ void ZEXPORT gzclearerr(file)
memory). Simply save the error message as a static string. If there is an
allocation failure constructing the error message, then convert the error to
out of memory. */
-void ZLIB_INTERNAL gz_error(state, err, msg)
- gz_statep state;
- int err;
- const char *msg;
-{
+void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {
/* free previously allocated message and clear */
if (state->msg != NULL) {
if (state->err != Z_MEM_ERROR)
@@ -619,21 +563,20 @@ void ZLIB_INTERNAL gz_error(state, err, msg)
#endif
}
-#ifndef INT_MAX
/* portably return maximum value for an int (when limits.h presumed not
available) -- we need to do this to cover cases where 2's complement not
used, since C standard permits 1's complement and sign-bit representations,
otherwise we could just use ((unsigned)-1) >> 1 */
-unsigned ZLIB_INTERNAL gz_intmax()
-{
- unsigned p, q;
-
- p = 1;
+unsigned ZLIB_INTERNAL gz_intmax(void) {
+#ifdef INT_MAX
+ return INT_MAX;
+#else
+ unsigned p = 1, q;
do {
q = p;
p <<= 1;
p++;
} while (p > q);
return q >> 1;
-}
#endif
+}
diff --git a/src/3rdparty/zlib/src/gzread.c b/src/3rdparty/zlib/src/gzread.c
index dd77381596..4168cbc887 100644
--- a/src/3rdparty/zlib/src/gzread.c
+++ b/src/3rdparty/zlib/src/gzread.c
@@ -5,25 +5,12 @@
#include "gzguts.h"
-/* Local functions */
-local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *));
-local int gz_avail OF((gz_statep));
-local int gz_look OF((gz_statep));
-local int gz_decomp OF((gz_statep));
-local int gz_fetch OF((gz_statep));
-local int gz_skip OF((gz_statep, z_off64_t));
-local z_size_t gz_read OF((gz_statep, voidp, z_size_t));
-
/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from
state->fd, and update state->eof, state->err, and state->msg as appropriate.
This function needs to loop on read(), since read() is not guaranteed to
read the number of bytes requested, depending on the type of descriptor. */
-local int gz_load(state, buf, len, have)
- gz_statep state;
- unsigned char *buf;
- unsigned len;
- unsigned *have;
-{
+local int gz_load(gz_statep state, unsigned char *buf, unsigned len,
+ unsigned *have) {
int ret;
unsigned get, max = ((unsigned)-1 >> 2) + 1;
@@ -53,9 +40,7 @@ local int gz_load(state, buf, len, have)
If strm->avail_in != 0, then the current data is moved to the beginning of
the input buffer, and then the remainder of the buffer is loaded with the
available data from the input file. */
-local int gz_avail(state)
- gz_statep state;
-{
+local int gz_avail(gz_statep state) {
unsigned got;
z_streamp strm = &(state->strm);
@@ -88,9 +73,7 @@ local int gz_avail(state)
case, all further file reads will be directly to either the output buffer or
a user buffer. If decompressing, the inflate state will be initialized.
gz_look() will return 0 on success or -1 on failure. */
-local int gz_look(state)
- gz_statep state;
-{
+local int gz_look(gz_statep state) {
z_streamp strm = &(state->strm);
/* allocate read buffers and inflate memory */
@@ -170,9 +153,7 @@ local int gz_look(state)
data. If the gzip stream completes, state->how is reset to LOOK to look for
the next gzip stream or raw data, once state->x.have is depleted. Returns 0
on success, -1 on failure. */
-local int gz_decomp(state)
- gz_statep state;
-{
+local int gz_decomp(gz_statep state) {
int ret = Z_OK;
unsigned had;
z_streamp strm = &(state->strm);
@@ -224,9 +205,7 @@ local int gz_decomp(state)
looked for to determine whether to copy or decompress. Returns -1 on error,
otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the
end of the input file has been reached and all data has been processed. */
-local int gz_fetch(state)
- gz_statep state;
-{
+local int gz_fetch(gz_statep state) {
z_streamp strm = &(state->strm);
do {
@@ -254,10 +233,7 @@ local int gz_fetch(state)
}
/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */
-local int gz_skip(state, len)
- gz_statep state;
- z_off64_t len;
-{
+local int gz_skip(gz_statep state, z_off64_t len) {
unsigned n;
/* skip over len bytes or reach end-of-file, whichever comes first */
@@ -289,11 +265,7 @@ local int gz_skip(state, len)
input. Return the number of bytes read. If zero is returned, either the
end of file was reached, or there was an error. state->err must be
consulted in that case to determine which. */
-local z_size_t gz_read(state, buf, len)
- gz_statep state;
- voidp buf;
- z_size_t len;
-{
+local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) {
z_size_t got;
unsigned n;
@@ -370,11 +342,7 @@ local z_size_t gz_read(state, buf, len)
}
/* -- see zlib.h -- */
-int ZEXPORT gzread(file, buf, len)
- gzFile file;
- voidp buf;
- unsigned len;
-{
+int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) {
gz_statep state;
/* get internal structure */
@@ -406,12 +374,7 @@ int ZEXPORT gzread(file, buf, len)
}
/* -- see zlib.h -- */
-z_size_t ZEXPORT gzfread(buf, size, nitems, file)
- voidp buf;
- z_size_t size;
- z_size_t nitems;
- gzFile file;
-{
+z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, gzFile file) {
z_size_t len;
gz_statep state;
@@ -442,9 +405,7 @@ z_size_t ZEXPORT gzfread(buf, size, nitems, file)
#else
# undef gzgetc
#endif
-int ZEXPORT gzgetc(file)
- gzFile file;
-{
+int ZEXPORT gzgetc(gzFile file) {
unsigned char buf[1];
gz_statep state;
@@ -469,17 +430,12 @@ int ZEXPORT gzgetc(file)
return gz_read(state, buf, 1) < 1 ? -1 : buf[0];
}
-int ZEXPORT gzgetc_(file)
-gzFile file;
-{
+int ZEXPORT gzgetc_(gzFile file) {
return gzgetc(file);
}
/* -- see zlib.h -- */
-int ZEXPORT gzungetc(c, file)
- int c;
- gzFile file;
-{
+int ZEXPORT gzungetc(int c, gzFile file) {
gz_statep state;
/* get internal structure */
@@ -487,6 +443,10 @@ int ZEXPORT gzungetc(c, file)
return -1;
state = (gz_statep)file;
+ /* in case this was just opened, set up the input buffer */
+ if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
+ (void)gz_look(state);
+
/* check that we're reading and that there's no (serious) error */
if (state->mode != GZ_READ ||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
@@ -536,11 +496,7 @@ int ZEXPORT gzungetc(c, file)
}
/* -- see zlib.h -- */
-char * ZEXPORT gzgets(file, buf, len)
- gzFile file;
- char *buf;
- int len;
-{
+char * ZEXPORT gzgets(gzFile file, char *buf, int len) {
unsigned left, n;
char *str;
unsigned char *eol;
@@ -600,9 +556,7 @@ char * ZEXPORT gzgets(file, buf, len)
}
/* -- see zlib.h -- */
-int ZEXPORT gzdirect(file)
- gzFile file;
-{
+int ZEXPORT gzdirect(gzFile file) {
gz_statep state;
/* get internal structure */
@@ -620,9 +574,7 @@ int ZEXPORT gzdirect(file)
}
/* -- see zlib.h -- */
-int ZEXPORT gzclose_r(file)
- gzFile file;
-{
+int ZEXPORT gzclose_r(gzFile file) {
int ret, err;
gz_statep state;
diff --git a/src/3rdparty/zlib/src/gzwrite.c b/src/3rdparty/zlib/src/gzwrite.c
index eb8a0e5893..435b4621b5 100644
--- a/src/3rdparty/zlib/src/gzwrite.c
+++ b/src/3rdparty/zlib/src/gzwrite.c
@@ -5,18 +5,10 @@
#include "gzguts.h"
-/* Local functions */
-local int gz_init OF((gz_statep));
-local int gz_comp OF((gz_statep, int));
-local int gz_zero OF((gz_statep, z_off64_t));
-local z_size_t gz_write OF((gz_statep, voidpc, z_size_t));
-
/* Initialize state for writing a gzip file. Mark initialization by setting
state->size to non-zero. Return -1 on a memory allocation failure, or 0 on
success. */
-local int gz_init(state)
- gz_statep state;
-{
+local int gz_init(gz_statep state) {
int ret;
z_streamp strm = &(state->strm);
@@ -70,10 +62,7 @@ local int gz_init(state)
deflate() flush value. If flush is Z_FINISH, then the deflate() state is
reset to start a new gzip stream. If gz->direct is true, then simply write
to the output file without compressing, and ignore flush. */
-local int gz_comp(state, flush)
- gz_statep state;
- int flush;
-{
+local int gz_comp(gz_statep state, int flush) {
int ret, writ;
unsigned have, put, max = ((unsigned)-1 >> 2) + 1;
z_streamp strm = &(state->strm);
@@ -151,10 +140,7 @@ local int gz_comp(state, flush)
/* Compress len zeros to output. Return -1 on a write error or memory
allocation failure by gz_comp(), or 0 on success. */
-local int gz_zero(state, len)
- gz_statep state;
- z_off64_t len;
-{
+local int gz_zero(gz_statep state, z_off64_t len) {
int first;
unsigned n;
z_streamp strm = &(state->strm);
@@ -184,11 +170,7 @@ local int gz_zero(state, len)
/* Write len bytes from buf to file. Return the number of bytes written. If
the returned value is less than len, then there was an error. */
-local z_size_t gz_write(state, buf, len)
- gz_statep state;
- voidpc buf;
- z_size_t len;
-{
+local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
z_size_t put = len;
/* if len is zero, avoid unnecessary operations */
@@ -252,11 +234,7 @@ local z_size_t gz_write(state, buf, len)
}
/* -- see zlib.h -- */
-int ZEXPORT gzwrite(file, buf, len)
- gzFile file;
- voidpc buf;
- unsigned len;
-{
+int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) {
gz_statep state;
/* get internal structure */
@@ -280,12 +258,8 @@ int ZEXPORT gzwrite(file, buf, len)
}
/* -- see zlib.h -- */
-z_size_t ZEXPORT gzfwrite(buf, size, nitems, file)
- voidpc buf;
- z_size_t size;
- z_size_t nitems;
- gzFile file;
-{
+z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems,
+ gzFile file) {
z_size_t len;
gz_statep state;
@@ -310,10 +284,7 @@ z_size_t ZEXPORT gzfwrite(buf, size, nitems, file)
}
/* -- see zlib.h -- */
-int ZEXPORT gzputc(file, c)
- gzFile file;
- int c;
-{
+int ZEXPORT gzputc(gzFile file, int c) {
unsigned have;
unsigned char buf[1];
gz_statep state;
@@ -358,10 +329,7 @@ int ZEXPORT gzputc(file, c)
}
/* -- see zlib.h -- */
-int ZEXPORT gzputs(file, s)
- gzFile file;
- const char *s;
-{
+int ZEXPORT gzputs(gzFile file, const char *s) {
z_size_t len, put;
gz_statep state;
@@ -388,8 +356,7 @@ int ZEXPORT gzputs(file, s)
#include <stdarg.h>
/* -- see zlib.h -- */
-int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va)
-{
+int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {
int len;
unsigned left;
char *next;
@@ -460,8 +427,7 @@ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va)
return len;
}
-int ZEXPORTVA gzprintf(gzFile file, const char *format, ...)
-{
+int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) {
va_list va;
int ret;
@@ -474,13 +440,10 @@ int ZEXPORTVA gzprintf(gzFile file, const char *format, ...)
#else /* !STDC && !Z_HAVE_STDARG_H */
/* -- see zlib.h -- */
-int ZEXPORTVA gzprintf(file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
- a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
- gzFile file;
- const char *format;
- int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
- a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
-{
+int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3,
+ int a4, int a5, int a6, int a7, int a8, int a9, int a10,
+ int a11, int a12, int a13, int a14, int a15, int a16,
+ int a17, int a18, int a19, int a20) {
unsigned len, left;
char *next;
gz_statep state;
@@ -562,10 +525,7 @@ int ZEXPORTVA gzprintf(file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
#endif
/* -- see zlib.h -- */
-int ZEXPORT gzflush(file, flush)
- gzFile file;
- int flush;
-{
+int ZEXPORT gzflush(gzFile file, int flush) {
gz_statep state;
/* get internal structure */
@@ -594,11 +554,7 @@ int ZEXPORT gzflush(file, flush)
}
/* -- see zlib.h -- */
-int ZEXPORT gzsetparams(file, level, strategy)
- gzFile file;
- int level;
- int strategy;
-{
+int ZEXPORT gzsetparams(gzFile file, int level, int strategy) {
gz_statep state;
z_streamp strm;
@@ -609,7 +565,7 @@ int ZEXPORT gzsetparams(file, level, strategy)
strm = &(state->strm);
/* check that we're writing and that there's no error */
- if (state->mode != GZ_WRITE || state->err != Z_OK)
+ if (state->mode != GZ_WRITE || state->err != Z_OK || state->direct)
return Z_STREAM_ERROR;
/* if no change is requested, then do nothing */
@@ -636,9 +592,7 @@ int ZEXPORT gzsetparams(file, level, strategy)
}
/* -- see zlib.h -- */
-int ZEXPORT gzclose_w(file)
- gzFile file;
-{
+int ZEXPORT gzclose_w(gzFile file) {
int ret = Z_OK;
gz_statep state;
diff --git a/src/3rdparty/zlib/src/infback.c b/src/3rdparty/zlib/src/infback.c
index babeaf1806..e7b25b307a 100644
--- a/src/3rdparty/zlib/src/infback.c
+++ b/src/3rdparty/zlib/src/infback.c
@@ -15,9 +15,6 @@
#include "inflate.h"
#include "inffast.h"
-/* function prototypes */
-local void fixedtables OF((struct inflate_state FAR *state));
-
/*
strm provides memory allocation functions in zalloc and zfree, or
Z_NULL to use the library memory allocation functions.
@@ -25,13 +22,9 @@ local void fixedtables OF((struct inflate_state FAR *state));
windowBits is in the range 8..15, and window is a user-supplied
window and output buffer that is 2**windowBits bytes.
*/
-int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)
-z_streamp strm;
-int windowBits;
-unsigned char FAR *window;
-const char *version;
-int stream_size;
-{
+int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits,
+ unsigned char FAR *window, const char *version,
+ int stream_size) {
struct inflate_state FAR *state;
if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
@@ -80,9 +73,7 @@ int stream_size;
used for threaded applications, since the rewriting of the tables and virgin
may not be thread-safe.
*/
-local void fixedtables(state)
-struct inflate_state FAR *state;
-{
+local void fixedtables(struct inflate_state FAR *state) {
#ifdef BUILDFIXED
static int virgin = 1;
static code *lenfix, *distfix;
@@ -248,13 +239,8 @@ struct inflate_state FAR *state;
inflateBack() can also return Z_STREAM_ERROR if the input parameters
are not correct, i.e. strm is Z_NULL or the state was not initialized.
*/
-int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)
-z_streamp strm;
-in_func in;
-void FAR *in_desc;
-out_func out;
-void FAR *out_desc;
-{
+int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc,
+ out_func out, void FAR *out_desc) {
struct inflate_state FAR *state;
z_const unsigned char FAR *next; /* next input */
unsigned char FAR *put; /* next output */
@@ -632,9 +618,7 @@ void FAR *out_desc;
return ret;
}
-int ZEXPORT inflateBackEnd(strm)
-z_streamp strm;
-{
+int ZEXPORT inflateBackEnd(z_streamp strm) {
if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
return Z_STREAM_ERROR;
ZFREE(strm, strm->state);
diff --git a/src/3rdparty/zlib/src/inffast.c b/src/3rdparty/zlib/src/inffast.c
index 1fec7f363f..9354676e78 100644
--- a/src/3rdparty/zlib/src/inffast.c
+++ b/src/3rdparty/zlib/src/inffast.c
@@ -47,10 +47,7 @@
requires strm->avail_out >= 258 for each loop to avoid checking for
output space.
*/
-void ZLIB_INTERNAL inflate_fast(strm, start)
-z_streamp strm;
-unsigned start; /* inflate()'s starting value for strm->avail_out */
-{
+void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) {
struct inflate_state FAR *state;
z_const unsigned char FAR *in; /* local strm->next_in */
z_const unsigned char FAR *last; /* have enough input while in < last */
diff --git a/src/3rdparty/zlib/src/inffast.h b/src/3rdparty/zlib/src/inffast.h
index e5c1aa4ca8..49c6d156c5 100644
--- a/src/3rdparty/zlib/src/inffast.h
+++ b/src/3rdparty/zlib/src/inffast.h
@@ -8,4 +8,4 @@
subject to change. Applications should only use zlib.h.
*/
-void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start));
+void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start);
diff --git a/src/3rdparty/zlib/src/inflate.c b/src/3rdparty/zlib/src/inflate.c
index 8acbef44e9..94ecff015a 100644
--- a/src/3rdparty/zlib/src/inflate.c
+++ b/src/3rdparty/zlib/src/inflate.c
@@ -91,20 +91,7 @@
# endif
#endif
-/* function prototypes */
-local int inflateStateCheck OF((z_streamp strm));
-local void fixedtables OF((struct inflate_state FAR *state));
-local int updatewindow OF((z_streamp strm, const unsigned char FAR *end,
- unsigned copy));
-#ifdef BUILDFIXED
- void makefixed OF((void));
-#endif
-local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf,
- unsigned len));
-
-local int inflateStateCheck(strm)
-z_streamp strm;
-{
+local int inflateStateCheck(z_streamp strm) {
struct inflate_state FAR *state;
if (strm == Z_NULL ||
strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)
@@ -116,9 +103,7 @@ z_streamp strm;
return 0;
}
-int ZEXPORT inflateResetKeep(strm)
-z_streamp strm;
-{
+int ZEXPORT inflateResetKeep(z_streamp strm) {
struct inflate_state FAR *state;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
@@ -142,9 +127,7 @@ z_streamp strm;
return Z_OK;
}
-int ZEXPORT inflateReset(strm)
-z_streamp strm;
-{
+int ZEXPORT inflateReset(z_streamp strm) {
struct inflate_state FAR *state;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
@@ -155,10 +138,7 @@ z_streamp strm;
return inflateResetKeep(strm);
}
-int ZEXPORT inflateReset2(strm, windowBits)
-z_streamp strm;
-int windowBits;
-{
+int ZEXPORT inflateReset2(z_streamp strm, int windowBits) {
int wrap;
struct inflate_state FAR *state;
@@ -195,12 +175,8 @@ int windowBits;
return inflateReset(strm);
}
-int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
-z_streamp strm;
-int windowBits;
-const char *version;
-int stream_size;
-{
+int ZEXPORT inflateInit2_(z_streamp strm, int windowBits,
+ const char *version, int stream_size) {
int ret;
struct inflate_state FAR *state;
@@ -239,22 +215,17 @@ int stream_size;
return ret;
}
-int ZEXPORT inflateInit_(strm, version, stream_size)
-z_streamp strm;
-const char *version;
-int stream_size;
-{
+int ZEXPORT inflateInit_(z_streamp strm, const char *version,
+ int stream_size) {
return inflateInit2_(strm, DEF_WBITS, version, stream_size);
}
-int ZEXPORT inflatePrime(strm, bits, value)
-z_streamp strm;
-int bits;
-int value;
-{
+int ZEXPORT inflatePrime(z_streamp strm, int bits, int value) {
struct inflate_state FAR *state;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
+ if (bits == 0)
+ return Z_OK;
state = (struct inflate_state FAR *)strm->state;
if (bits < 0) {
state->hold = 0;
@@ -278,9 +249,7 @@ int value;
used for threaded applications, since the rewriting of the tables and virgin
may not be thread-safe.
*/
-local void fixedtables(state)
-struct inflate_state FAR *state;
-{
+local void fixedtables(struct inflate_state FAR *state) {
#ifdef BUILDFIXED
static int virgin = 1;
static code *lenfix, *distfix;
@@ -342,7 +311,7 @@ struct inflate_state FAR *state;
a.out > inffixed.h
*/
-void makefixed()
+void makefixed(void)
{
unsigned low, size;
struct inflate_state state;
@@ -396,11 +365,7 @@ void makefixed()
output will fall in the output data, making match copies simpler and faster.
The advantage may be dependent on the size of the processor's data caches.
*/
-local int updatewindow(strm, end, copy)
-z_streamp strm;
-const Bytef *end;
-unsigned copy;
-{
+local int updatewindow(z_streamp strm, const Bytef *end, unsigned copy) {
struct inflate_state FAR *state;
unsigned dist;
@@ -622,10 +587,7 @@ unsigned copy;
will return Z_BUF_ERROR if it has not reached the end of the stream.
*/
-int ZEXPORT inflate(strm, flush)
-z_streamp strm;
-int flush;
-{
+int ZEXPORT inflate(z_streamp strm, int flush) {
struct inflate_state FAR *state;
z_const unsigned char FAR *next; /* next input */
unsigned char FAR *put; /* next output */
@@ -1301,9 +1263,7 @@ int flush;
return ret;
}
-int ZEXPORT inflateEnd(strm)
-z_streamp strm;
-{
+int ZEXPORT inflateEnd(z_streamp strm) {
struct inflate_state FAR *state;
if (inflateStateCheck(strm))
return Z_STREAM_ERROR;
@@ -1315,11 +1275,8 @@ z_streamp strm;
return Z_OK;
}
-int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength)
-z_streamp strm;
-Bytef *dictionary;
-uInt *dictLength;
-{
+int ZEXPORT inflateGetDictionary(z_streamp strm, Bytef *dictionary,
+ uInt *dictLength) {
struct inflate_state FAR *state;
/* check state */
@@ -1338,11 +1295,8 @@ uInt *dictLength;
return Z_OK;
}
-int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
-z_streamp strm;
-const Bytef *dictionary;
-uInt dictLength;
-{
+int ZEXPORT inflateSetDictionary(z_streamp strm, const Bytef *dictionary,
+ uInt dictLength) {
struct inflate_state FAR *state;
unsigned long dictid;
int ret;
@@ -1373,10 +1327,7 @@ uInt dictLength;
return Z_OK;
}
-int ZEXPORT inflateGetHeader(strm, head)
-z_streamp strm;
-gz_headerp head;
-{
+int ZEXPORT inflateGetHeader(z_streamp strm, gz_headerp head) {
struct inflate_state FAR *state;
/* check state */
@@ -1401,11 +1352,8 @@ gz_headerp head;
called again with more data and the *have state. *have is initialized to
zero for the first call.
*/
-local unsigned syncsearch(have, buf, len)
-unsigned FAR *have;
-const unsigned char FAR *buf;
-unsigned len;
-{
+local unsigned syncsearch(unsigned FAR *have, const unsigned char FAR *buf,
+ unsigned len) {
unsigned got;
unsigned next;
@@ -1424,9 +1372,7 @@ unsigned len;
return next;
}
-int ZEXPORT inflateSync(strm)
-z_streamp strm;
-{
+int ZEXPORT inflateSync(z_streamp strm) {
unsigned len; /* number of bytes to look at or looked at */
int flags; /* temporary to save header status */
unsigned long in, out; /* temporary to save total_in and total_out */
@@ -1441,7 +1387,7 @@ z_streamp strm;
/* if first time, start search in bit buffer */
if (state->mode != SYNC) {
state->mode = SYNC;
- state->hold <<= state->bits & 7;
+ state->hold >>= state->bits & 7;
state->bits -= state->bits & 7;
len = 0;
while (state->bits >= 8) {
@@ -1482,9 +1428,7 @@ z_streamp strm;
block. When decompressing, PPP checks that at the end of input packet,
inflate is waiting for these length bytes.
*/
-int ZEXPORT inflateSyncPoint(strm)
-z_streamp strm;
-{
+int ZEXPORT inflateSyncPoint(z_streamp strm) {
struct inflate_state FAR *state;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
@@ -1492,10 +1436,7 @@ z_streamp strm;
return state->mode == STORED && state->bits == 0;
}
-int ZEXPORT inflateCopy(dest, source)
-z_streamp dest;
-z_streamp source;
-{
+int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) {
struct inflate_state FAR *state;
struct inflate_state FAR *copy;
unsigned char FAR *window;
@@ -1539,10 +1480,7 @@ z_streamp source;
return Z_OK;
}
-int ZEXPORT inflateUndermine(strm, subvert)
-z_streamp strm;
-int subvert;
-{
+int ZEXPORT inflateUndermine(z_streamp strm, int subvert) {
struct inflate_state FAR *state;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
@@ -1557,10 +1495,7 @@ int subvert;
#endif
}
-int ZEXPORT inflateValidate(strm, check)
-z_streamp strm;
-int check;
-{
+int ZEXPORT inflateValidate(z_streamp strm, int check) {
struct inflate_state FAR *state;
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
@@ -1572,9 +1507,7 @@ int check;
return Z_OK;
}
-long ZEXPORT inflateMark(strm)
-z_streamp strm;
-{
+long ZEXPORT inflateMark(z_streamp strm) {
struct inflate_state FAR *state;
if (inflateStateCheck(strm))
@@ -1585,9 +1518,7 @@ z_streamp strm;
(state->mode == MATCH ? state->was - state->length : 0));
}
-unsigned long ZEXPORT inflateCodesUsed(strm)
-z_streamp strm;
-{
+unsigned long ZEXPORT inflateCodesUsed(z_streamp strm) {
struct inflate_state FAR *state;
if (inflateStateCheck(strm)) return (unsigned long)-1;
state = (struct inflate_state FAR *)strm->state;
diff --git a/src/3rdparty/zlib/src/inftrees.c b/src/3rdparty/zlib/src/inftrees.c
index 57d2793bec..98cfe16445 100644
--- a/src/3rdparty/zlib/src/inftrees.c
+++ b/src/3rdparty/zlib/src/inftrees.c
@@ -1,5 +1,5 @@
/* inftrees.c -- generate Huffman trees for efficient decoding
- * Copyright (C) 1995-2022 Mark Adler
+ * Copyright (C) 1995-2024 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -9,7 +9,7 @@
#define MAXBITS 15
const char inflate_copyright[] =
- " inflate 1.2.13 Copyright 1995-2022 Mark Adler ";
+ " inflate 1.3.1 Copyright 1995-2024 Mark Adler ";
/*
If you use the zlib library in a product, an acknowledgment is welcome
in the documentation of your product. If for some reason you cannot
@@ -29,14 +29,9 @@ const char inflate_copyright[] =
table index bits. It will differ if the request is greater than the
longest code or if it is less than the shortest code.
*/
-int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work)
-codetype type;
-unsigned short FAR *lens;
-unsigned codes;
-code FAR * FAR *table;
-unsigned FAR *bits;
-unsigned short FAR *work;
-{
+int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
+ unsigned codes, code FAR * FAR *table,
+ unsigned FAR *bits, unsigned short FAR *work) {
unsigned len; /* a code's length in bits */
unsigned sym; /* index of code symbols */
unsigned min, max; /* minimum and maximum code lengths */
@@ -62,7 +57,7 @@ unsigned short FAR *work;
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
static const unsigned short lext[31] = { /* Length codes 257..285 extra */
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
- 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 194, 65};
+ 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 203, 77};
static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
diff --git a/src/3rdparty/zlib/src/inftrees.h b/src/3rdparty/zlib/src/inftrees.h
index f53665311c..396f74b5da 100644
--- a/src/3rdparty/zlib/src/inftrees.h
+++ b/src/3rdparty/zlib/src/inftrees.h
@@ -41,8 +41,8 @@ typedef struct {
examples/enough.c found in the zlib distribution. The arguments to that
program are the number of symbols, the initial root table size, and the
maximum bit length of a code. "enough 286 9 15" for literal/length codes
- returns returns 852, and "enough 30 6 15" for distance codes returns 592.
- The initial root table size (9 or 6) is found in the fifth argument of the
+ returns 852, and "enough 30 6 15" for distance codes returns 592. The
+ initial root table size (9 or 6) is found in the fifth argument of the
inflate_table() calls in inflate.c and infback.c. If the root table size is
changed, then these maximum sizes would be need to be recalculated and
updated. */
@@ -57,6 +57,6 @@ typedef enum {
DISTS
} codetype;
-int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens,
- unsigned codes, code FAR * FAR *table,
- unsigned FAR *bits, unsigned short FAR *work));
+int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
+ unsigned codes, code FAR * FAR *table,
+ unsigned FAR *bits, unsigned short FAR *work);
diff --git a/src/3rdparty/zlib/src/trees.c b/src/3rdparty/zlib/src/trees.c
index 5f305c4722..6a523ef34e 100644
--- a/src/3rdparty/zlib/src/trees.c
+++ b/src/3rdparty/zlib/src/trees.c
@@ -1,5 +1,5 @@
/* trees.c -- output deflated data using Huffman coding
- * Copyright (C) 1995-2021 Jean-loup Gailly
+ * Copyright (C) 1995-2024 Jean-loup Gailly
* detect_data_type() function provided freely by Cosmin Truta, 2006
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -122,39 +122,116 @@ struct static_tree_desc_s {
int max_length; /* max bit length for the codes */
};
-local const static_tree_desc static_l_desc =
+#ifdef NO_INIT_GLOBAL_POINTERS
+# define TCONST
+#else
+# define TCONST const
+#endif
+
+local TCONST static_tree_desc static_l_desc =
{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
-local const static_tree_desc static_d_desc =
+local TCONST static_tree_desc static_d_desc =
{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
-local const static_tree_desc static_bl_desc =
+local TCONST static_tree_desc static_bl_desc =
{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
/* ===========================================================================
- * Local (static) routines in this file.
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+ put_byte(s, (uch)((w) & 0xff)); \
+ put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
*/
+local unsigned bi_reverse(unsigned code, int len) {
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
-local void tr_static_init OF((void));
-local void init_block OF((deflate_state *s));
-local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
-local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
-local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
-local void build_tree OF((deflate_state *s, tree_desc *desc));
-local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
-local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
-local int build_bl_tree OF((deflate_state *s));
-local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
- int blcodes));
-local void compress_block OF((deflate_state *s, const ct_data *ltree,
- const ct_data *dtree));
-local int detect_data_type OF((deflate_state *s));
-local unsigned bi_reverse OF((unsigned code, int len));
-local void bi_windup OF((deflate_state *s));
-local void bi_flush OF((deflate_state *s));
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(deflate_state *s) {
+ if (s->bi_valid == 16) {
+ put_short(s, s->bi_buf);
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ } else if (s->bi_valid >= 8) {
+ put_byte(s, (Byte)s->bi_buf);
+ s->bi_buf >>= 8;
+ s->bi_valid -= 8;
+ }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(deflate_state *s) {
+ if (s->bi_valid > 8) {
+ put_short(s, s->bi_buf);
+ } else if (s->bi_valid > 0) {
+ put_byte(s, (Byte)s->bi_buf);
+ }
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef ZLIB_DEBUG
+ s->bits_sent = (s->bits_sent + 7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes(ct_data *tree, int max_code, ushf *bl_count) {
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ unsigned code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ code = (code + bl_count[bits - 1]) << 1;
+ next_code[bits] = (ush)code;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = (ush)bi_reverse(next_code[len]++, len);
+
+ Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len] - 1));
+ }
+}
#ifdef GEN_TREES_H
-local void gen_trees_header OF((void));
+local void gen_trees_header(void);
#endif
#ifndef ZLIB_DEBUG
@@ -168,26 +245,11 @@ local void gen_trees_header OF((void));
#endif
/* ===========================================================================
- * Output a short LSB first on the stream.
- * IN assertion: there is enough room in pendingBuf.
- */
-#define put_short(s, w) { \
- put_byte(s, (uch)((w) & 0xff)); \
- put_byte(s, (uch)((ush)(w) >> 8)); \
-}
-
-/* ===========================================================================
* Send a value on a given number of bits.
* IN assertion: length <= 16 and value fits in length bits.
*/
#ifdef ZLIB_DEBUG
-local void send_bits OF((deflate_state *s, int value, int length));
-
-local void send_bits(s, value, length)
- deflate_state *s;
- int value; /* value to send */
- int length; /* number of bits */
-{
+local void send_bits(deflate_state *s, int value, int length) {
Tracevv((stderr," l %2d v %4x ", length, value));
Assert(length > 0 && length <= 15, "invalid length");
s->bits_sent += (ulg)length;
@@ -229,8 +291,7 @@ local void send_bits(s, value, length)
/* ===========================================================================
* Initialize the various 'constant' tables.
*/
-local void tr_static_init()
-{
+local void tr_static_init(void) {
#if defined(GEN_TREES_H) || !defined(STDC)
static int static_init_done = 0;
int n; /* iterates over tree elements */
@@ -323,8 +384,7 @@ local void tr_static_init()
((i) == (last)? "\n};\n\n" : \
((i) % (width) == (width) - 1 ? ",\n" : ", "))
-void gen_trees_header()
-{
+void gen_trees_header(void) {
FILE *header = fopen("trees.h", "w");
int i;
@@ -374,11 +434,25 @@ void gen_trees_header()
#endif /* GEN_TREES_H */
/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(deflate_state *s) {
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+ s->dyn_ltree[END_BLOCK].Freq = 1;
+ s->opt_len = s->static_len = 0L;
+ s->sym_next = s->matches = 0;
+}
+
+/* ===========================================================================
* Initialize the tree data structures for a new zlib stream.
*/
-void ZLIB_INTERNAL _tr_init(s)
- deflate_state *s;
-{
+void ZLIB_INTERNAL _tr_init(deflate_state *s) {
tr_static_init();
s->l_desc.dyn_tree = s->dyn_ltree;
@@ -401,24 +475,6 @@ void ZLIB_INTERNAL _tr_init(s)
init_block(s);
}
-/* ===========================================================================
- * Initialize a new block.
- */
-local void init_block(s)
- deflate_state *s;
-{
- int n; /* iterates over tree elements */
-
- /* Initialize the trees. */
- for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
- for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
- for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
-
- s->dyn_ltree[END_BLOCK].Freq = 1;
- s->opt_len = s->static_len = 0L;
- s->sym_next = s->matches = 0;
-}
-
#define SMALLEST 1
/* Index within the heap array of least frequent node in the Huffman tree */
@@ -448,11 +504,7 @@ local void init_block(s)
* when the heap property is re-established (each father smaller than its
* two sons).
*/
-local void pqdownheap(s, tree, k)
- deflate_state *s;
- ct_data *tree; /* the tree to restore */
- int k; /* node to move down */
-{
+local void pqdownheap(deflate_state *s, ct_data *tree, int k) {
int v = s->heap[k];
int j = k << 1; /* left son of k */
while (j <= s->heap_len) {
@@ -483,10 +535,7 @@ local void pqdownheap(s, tree, k)
* The length opt_len is updated; static_len is also updated if stree is
* not null.
*/
-local void gen_bitlen(s, desc)
- deflate_state *s;
- tree_desc *desc; /* the tree descriptor */
-{
+local void gen_bitlen(deflate_state *s, tree_desc *desc) {
ct_data *tree = desc->dyn_tree;
int max_code = desc->max_code;
const ct_data *stree = desc->stat_desc->static_tree;
@@ -561,48 +610,9 @@ local void gen_bitlen(s, desc)
}
}
-/* ===========================================================================
- * Generate the codes for a given tree and bit counts (which need not be
- * optimal).
- * IN assertion: the array bl_count contains the bit length statistics for
- * the given tree and the field len is set for all tree elements.
- * OUT assertion: the field code is set for all tree elements of non
- * zero code length.
- */
-local void gen_codes(tree, max_code, bl_count)
- ct_data *tree; /* the tree to decorate */
- int max_code; /* largest code with non zero frequency */
- ushf *bl_count; /* number of codes at each bit length */
-{
- ush next_code[MAX_BITS+1]; /* next code value for each bit length */
- unsigned code = 0; /* running code value */
- int bits; /* bit index */
- int n; /* code index */
-
- /* The distribution counts are first used to generate the code values
- * without bit reversal.
- */
- for (bits = 1; bits <= MAX_BITS; bits++) {
- code = (code + bl_count[bits - 1]) << 1;
- next_code[bits] = (ush)code;
- }
- /* Check that the bit counts in bl_count are consistent. The last code
- * must be all ones.
- */
- Assert (code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1,
- "inconsistent bit counts");
- Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
-
- for (n = 0; n <= max_code; n++) {
- int len = tree[n].Len;
- if (len == 0) continue;
- /* Now reverse the bits */
- tree[n].Code = (ush)bi_reverse(next_code[len]++, len);
-
- Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
- n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len] - 1));
- }
-}
+#ifdef DUMP_BL_TREE
+# include <stdio.h>
+#endif
/* ===========================================================================
* Construct one Huffman tree and assigns the code bit strings and lengths.
@@ -612,10 +622,7 @@ local void gen_codes(tree, max_code, bl_count)
* and corresponding code. The length opt_len is updated; static_len is
* also updated if stree is not null. The field max_code is set.
*/
-local void build_tree(s, desc)
- deflate_state *s;
- tree_desc *desc; /* the tree descriptor */
-{
+local void build_tree(deflate_state *s, tree_desc *desc) {
ct_data *tree = desc->dyn_tree;
const ct_data *stree = desc->stat_desc->static_tree;
int elems = desc->stat_desc->elems;
@@ -700,11 +707,7 @@ local void build_tree(s, desc)
* Scan a literal or distance tree to determine the frequencies of the codes
* in the bit length tree.
*/
-local void scan_tree(s, tree, max_code)
- deflate_state *s;
- ct_data *tree; /* the tree to be scanned */
- int max_code; /* and its largest code of non zero frequency */
-{
+local void scan_tree(deflate_state *s, ct_data *tree, int max_code) {
int n; /* iterates over all tree elements */
int prevlen = -1; /* last emitted length */
int curlen; /* length of current code */
@@ -745,11 +748,7 @@ local void scan_tree(s, tree, max_code)
* Send a literal or distance tree in compressed form, using the codes in
* bl_tree.
*/
-local void send_tree(s, tree, max_code)
- deflate_state *s;
- ct_data *tree; /* the tree to be scanned */
- int max_code; /* and its largest code of non zero frequency */
-{
+local void send_tree(deflate_state *s, ct_data *tree, int max_code) {
int n; /* iterates over all tree elements */
int prevlen = -1; /* last emitted length */
int curlen; /* length of current code */
@@ -796,9 +795,7 @@ local void send_tree(s, tree, max_code)
* Construct the Huffman tree for the bit lengths and return the index in
* bl_order of the last bit length code to send.
*/
-local int build_bl_tree(s)
- deflate_state *s;
-{
+local int build_bl_tree(deflate_state *s) {
int max_blindex; /* index of last bit length code of non zero freq */
/* Determine the bit length frequencies for literal and distance trees */
@@ -831,10 +828,8 @@ local int build_bl_tree(s)
* lengths of the bit length codes, the literal tree and the distance tree.
* IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
*/
-local void send_all_trees(s, lcodes, dcodes, blcodes)
- deflate_state *s;
- int lcodes, dcodes, blcodes; /* number of codes for each tree */
-{
+local void send_all_trees(deflate_state *s, int lcodes, int dcodes,
+ int blcodes) {
int rank; /* index in bl_order */
Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
@@ -860,12 +855,8 @@ local void send_all_trees(s, lcodes, dcodes, blcodes)
/* ===========================================================================
* Send a stored block
*/
-void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last)
- deflate_state *s;
- charf *buf; /* input block */
- ulg stored_len; /* length of input block */
- int last; /* one if this is the last block for a file */
-{
+void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf,
+ ulg stored_len, int last) {
send_bits(s, (STORED_BLOCK<<1) + last, 3); /* send block type */
bi_windup(s); /* align on byte boundary */
put_short(s, (ush)stored_len);
@@ -884,9 +875,7 @@ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last)
/* ===========================================================================
* Flush the bits in the bit buffer to pending output (leaves at most 7 bits)
*/
-void ZLIB_INTERNAL _tr_flush_bits(s)
- deflate_state *s;
-{
+void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s) {
bi_flush(s);
}
@@ -894,9 +883,7 @@ void ZLIB_INTERNAL _tr_flush_bits(s)
* Send one empty static block to give enough lookahead for inflate.
* This takes 10 bits, of which 7 may remain in the bit buffer.
*/
-void ZLIB_INTERNAL _tr_align(s)
- deflate_state *s;
-{
+void ZLIB_INTERNAL _tr_align(deflate_state *s) {
send_bits(s, STATIC_TREES<<1, 3);
send_code(s, END_BLOCK, static_ltree);
#ifdef ZLIB_DEBUG
@@ -906,15 +893,107 @@ void ZLIB_INTERNAL _tr_align(s)
}
/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(deflate_state *s, const ct_data *ltree,
+ const ct_data *dtree) {
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned sx = 0; /* running index in symbol buffers */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (s->sym_next != 0) do {
+#ifdef LIT_MEM
+ dist = s->d_buf[sx];
+ lc = s->l_buf[sx++];
+#else
+ dist = s->sym_buf[sx++] & 0xff;
+ dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8;
+ lc = s->sym_buf[sx++];
+#endif
+ if (dist == 0) {
+ send_code(s, lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = _length_code[lc];
+ send_code(s, code + LITERALS + 1, ltree); /* send length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(s, lc, extra); /* send the extra length bits */
+ }
+ dist--; /* dist is now the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(s, code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= (unsigned)base_dist[code];
+ send_bits(s, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+
+ /* Check for no overlay of pending_buf on needed symbols */
+#ifdef LIT_MEM
+ Assert(s->pending < 2 * (s->lit_bufsize + sx), "pendingBuf overflow");
+#else
+ Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow");
+#endif
+
+ } while (sx < s->sym_next);
+
+ send_code(s, END_BLOCK, ltree);
+}
+
+/* ===========================================================================
+ * Check if the data type is TEXT or BINARY, using the following algorithm:
+ * - TEXT if the two conditions below are satisfied:
+ * a) There are no non-portable control characters belonging to the
+ * "block list" (0..6, 14..25, 28..31).
+ * b) There is at least one printable character belonging to the
+ * "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
+ * - BINARY otherwise.
+ * - The following partially-portable control characters form a
+ * "gray list" that is ignored in this detection algorithm:
+ * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+local int detect_data_type(deflate_state *s) {
+ /* block_mask is the bit mask of block-listed bytes
+ * set bits 0..6, 14..25, and 28..31
+ * 0xf3ffc07f = binary 11110011111111111100000001111111
+ */
+ unsigned long block_mask = 0xf3ffc07fUL;
+ int n;
+
+ /* Check for non-textual ("block-listed") bytes. */
+ for (n = 0; n <= 31; n++, block_mask >>= 1)
+ if ((block_mask & 1) && (s->dyn_ltree[n].Freq != 0))
+ return Z_BINARY;
+
+ /* Check for textual ("allow-listed") bytes. */
+ if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0
+ || s->dyn_ltree[13].Freq != 0)
+ return Z_TEXT;
+ for (n = 32; n < LITERALS; n++)
+ if (s->dyn_ltree[n].Freq != 0)
+ return Z_TEXT;
+
+ /* There are no "block-listed" or "allow-listed" bytes:
+ * this stream either is empty or has tolerated ("gray-listed") bytes only.
+ */
+ return Z_BINARY;
+}
+
+/* ===========================================================================
* Determine the best encoding for the current block: dynamic trees, static
* trees or store, and write out the encoded block.
*/
-void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
- deflate_state *s;
- charf *buf; /* input block, or NULL if too old */
- ulg stored_len; /* length of input block */
- int last; /* one if this is the last block for a file */
-{
+void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf,
+ ulg stored_len, int last) {
ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
int max_blindex = 0; /* index of last bit length code of non zero freq */
@@ -1011,14 +1090,15 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
* Save the match info and tally the frequency counts. Return true if
* the current block must be flushed.
*/
-int ZLIB_INTERNAL _tr_tally(s, dist, lc)
- deflate_state *s;
- unsigned dist; /* distance of matched string */
- unsigned lc; /* match length - MIN_MATCH or unmatched char (dist==0) */
-{
+int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc) {
+#ifdef LIT_MEM
+ s->d_buf[s->sym_next] = (ush)dist;
+ s->l_buf[s->sym_next++] = (uch)lc;
+#else
s->sym_buf[s->sym_next++] = (uch)dist;
s->sym_buf[s->sym_next++] = (uch)(dist >> 8);
s->sym_buf[s->sym_next++] = (uch)lc;
+#endif
if (dist == 0) {
/* lc is the unmatched char */
s->dyn_ltree[lc].Freq++;
@@ -1035,147 +1115,3 @@ int ZLIB_INTERNAL _tr_tally(s, dist, lc)
}
return (s->sym_next == s->sym_end);
}
-
-/* ===========================================================================
- * Send the block data compressed using the given Huffman trees
- */
-local void compress_block(s, ltree, dtree)
- deflate_state *s;
- const ct_data *ltree; /* literal tree */
- const ct_data *dtree; /* distance tree */
-{
- unsigned dist; /* distance of matched string */
- int lc; /* match length or unmatched char (if dist == 0) */
- unsigned sx = 0; /* running index in sym_buf */
- unsigned code; /* the code to send */
- int extra; /* number of extra bits to send */
-
- if (s->sym_next != 0) do {
- dist = s->sym_buf[sx++] & 0xff;
- dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8;
- lc = s->sym_buf[sx++];
- if (dist == 0) {
- send_code(s, lc, ltree); /* send a literal byte */
- Tracecv(isgraph(lc), (stderr," '%c' ", lc));
- } else {
- /* Here, lc is the match length - MIN_MATCH */
- code = _length_code[lc];
- send_code(s, code + LITERALS + 1, ltree); /* send length code */
- extra = extra_lbits[code];
- if (extra != 0) {
- lc -= base_length[code];
- send_bits(s, lc, extra); /* send the extra length bits */
- }
- dist--; /* dist is now the match distance - 1 */
- code = d_code(dist);
- Assert (code < D_CODES, "bad d_code");
-
- send_code(s, code, dtree); /* send the distance code */
- extra = extra_dbits[code];
- if (extra != 0) {
- dist -= (unsigned)base_dist[code];
- send_bits(s, dist, extra); /* send the extra distance bits */
- }
- } /* literal or match pair ? */
-
- /* Check that the overlay between pending_buf and sym_buf is ok: */
- Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow");
-
- } while (sx < s->sym_next);
-
- send_code(s, END_BLOCK, ltree);
-}
-
-/* ===========================================================================
- * Check if the data type is TEXT or BINARY, using the following algorithm:
- * - TEXT if the two conditions below are satisfied:
- * a) There are no non-portable control characters belonging to the
- * "block list" (0..6, 14..25, 28..31).
- * b) There is at least one printable character belonging to the
- * "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
- * - BINARY otherwise.
- * - The following partially-portable control characters form a
- * "gray list" that is ignored in this detection algorithm:
- * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
- * IN assertion: the fields Freq of dyn_ltree are set.
- */
-local int detect_data_type(s)
- deflate_state *s;
-{
- /* block_mask is the bit mask of block-listed bytes
- * set bits 0..6, 14..25, and 28..31
- * 0xf3ffc07f = binary 11110011111111111100000001111111
- */
- unsigned long block_mask = 0xf3ffc07fUL;
- int n;
-
- /* Check for non-textual ("block-listed") bytes. */
- for (n = 0; n <= 31; n++, block_mask >>= 1)
- if ((block_mask & 1) && (s->dyn_ltree[n].Freq != 0))
- return Z_BINARY;
-
- /* Check for textual ("allow-listed") bytes. */
- if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0
- || s->dyn_ltree[13].Freq != 0)
- return Z_TEXT;
- for (n = 32; n < LITERALS; n++)
- if (s->dyn_ltree[n].Freq != 0)
- return Z_TEXT;
-
- /* There are no "block-listed" or "allow-listed" bytes:
- * this stream either is empty or has tolerated ("gray-listed") bytes only.
- */
- return Z_BINARY;
-}
-
-/* ===========================================================================
- * Reverse the first len bits of a code, using straightforward code (a faster
- * method would use a table)
- * IN assertion: 1 <= len <= 15
- */
-local unsigned bi_reverse(code, len)
- unsigned code; /* the value to invert */
- int len; /* its bit length */
-{
- register unsigned res = 0;
- do {
- res |= code & 1;
- code >>= 1, res <<= 1;
- } while (--len > 0);
- return res >> 1;
-}
-
-/* ===========================================================================
- * Flush the bit buffer, keeping at most 7 bits in it.
- */
-local void bi_flush(s)
- deflate_state *s;
-{
- if (s->bi_valid == 16) {
- put_short(s, s->bi_buf);
- s->bi_buf = 0;
- s->bi_valid = 0;
- } else if (s->bi_valid >= 8) {
- put_byte(s, (Byte)s->bi_buf);
- s->bi_buf >>= 8;
- s->bi_valid -= 8;
- }
-}
-
-/* ===========================================================================
- * Flush the bit buffer and align the output on a byte boundary
- */
-local void bi_windup(s)
- deflate_state *s;
-{
- if (s->bi_valid > 8) {
- put_short(s, s->bi_buf);
- } else if (s->bi_valid > 0) {
- put_byte(s, (Byte)s->bi_buf);
- }
- s->bi_buf = 0;
- s->bi_valid = 0;
-#ifdef ZLIB_DEBUG
- s->bits_sent = (s->bits_sent + 7) & ~7;
-#endif
-}
diff --git a/src/3rdparty/zlib/src/uncompr.c b/src/3rdparty/zlib/src/uncompr.c
index f9532f46c1..5e256663b4 100644
--- a/src/3rdparty/zlib/src/uncompr.c
+++ b/src/3rdparty/zlib/src/uncompr.c
@@ -24,12 +24,8 @@
Z_DATA_ERROR if the input data was corrupted, including if the input data is
an incomplete zlib stream.
*/
-int ZEXPORT uncompress2(dest, destLen, source, sourceLen)
- Bytef *dest;
- uLongf *destLen;
- const Bytef *source;
- uLong *sourceLen;
-{
+int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, const Bytef *source,
+ uLong *sourceLen) {
z_stream stream;
int err;
const uInt max = (uInt)-1;
@@ -83,11 +79,7 @@ int ZEXPORT uncompress2(dest, destLen, source, sourceLen)
err;
}
-int ZEXPORT uncompress(dest, destLen, source, sourceLen)
- Bytef *dest;
- uLongf *destLen;
- const Bytef *source;
- uLong sourceLen;
-{
+int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, const Bytef *source,
+ uLong sourceLen) {
return uncompress2(dest, destLen, source, &sourceLen);
}
diff --git a/src/3rdparty/zlib/src/zconf.h b/src/3rdparty/zlib/src/zconf.h
index a0997ab0e9..4e14507a22 100644
--- a/src/3rdparty/zlib/src/zconf.h
+++ b/src/3rdparty/zlib/src/zconf.h
@@ -1,5 +1,5 @@
/* zconf.h -- configuration of the zlib compression library
- * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler
+ * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -245,7 +245,11 @@
#endif
#ifdef Z_SOLO
- typedef unsigned long z_size_t;
+# ifdef _WIN64
+ typedef unsigned long long z_size_t;
+# else
+ typedef unsigned long z_size_t;
+# endif
#else
# define z_longlong long long
# if defined(NO_SIZE_T)
@@ -300,14 +304,6 @@
# endif
#endif
-#ifndef Z_ARG /* function prototypes for stdarg */
-# if defined(STDC) || defined(Z_HAVE_STDARG_H)
-# define Z_ARG(args) args
-# else
-# define Z_ARG(args) ()
-# endif
-#endif
-
/* The following definitions for FAR are needed only for MSDOS mixed
* model programming (small or medium model with some far allocations).
* This was tested only with MSC; for other MSDOS compilers you may have
@@ -524,7 +520,7 @@ typedef uLong FAR uLongf;
#if !defined(_WIN32) && defined(Z_LARGE64)
# define z_off64_t off64_t
#else
-# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
+# if defined(_WIN32) && !defined(__GNUC__)
# define z_off64_t __int64
# else
# define z_off64_t z_off_t
diff --git a/src/3rdparty/zlib/src/zlib.h b/src/3rdparty/zlib/src/zlib.h
index b06a50c5ca..2cff72ee86 100644
--- a/src/3rdparty/zlib/src/zlib.h
+++ b/src/3rdparty/zlib/src/zlib.h
@@ -1,7 +1,7 @@
/* zlib.h -- interface of the 'zlib' general purpose compression library
- version 1.2.13, October 13th, 2022
+ version 1.3.1, January 22nd, 2024
- Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler
+ Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -41,11 +41,11 @@
extern "C" {
#endif
-#define ZLIB_VERSION "1.2.13 (Qt)"
-#define ZLIB_VERNUM 0x12d0
+#define ZLIB_VERSION "1.3.1 (Qt)"
+#define ZLIB_VERNUM 0x1310
#define ZLIB_VER_MAJOR 1
-#define ZLIB_VER_MINOR 2
-#define ZLIB_VER_REVISION 13
+#define ZLIB_VER_MINOR 3
+#define ZLIB_VER_REVISION 1
#define ZLIB_VER_SUBREVISION 0
/*
@@ -82,8 +82,8 @@ extern "C" {
even in the case of corrupted input.
*/
-typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
-typedef void (*free_func) OF((voidpf opaque, voidpf address));
+typedef voidpf (*alloc_func)(voidpf opaque, uInt items, uInt size);
+typedef void (*free_func)(voidpf opaque, voidpf address);
struct internal_state;
@@ -221,7 +221,7 @@ typedef gz_header FAR *gz_headerp;
/* basic functions */
-ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+ZEXTERN const char * ZEXPORT zlibVersion(void);
/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
If the first character differs, the library code actually used is not
compatible with the zlib.h header file used by the application. This check
@@ -229,12 +229,12 @@ ZEXTERN const char * ZEXPORT zlibVersion OF((void));
*/
/*
-ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+ZEXTERN int ZEXPORT deflateInit(z_streamp strm, int level);
Initializes the internal stream state for compression. The fields
zalloc, zfree and opaque must be initialized before by the caller. If
zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
- allocation functions.
+ allocation functions. total_in, total_out, adler, and msg are initialized.
The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
1 gives best speed, 9 gives best compression, 0 gives no compression at all
@@ -251,7 +251,7 @@ ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
*/
-ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+ZEXTERN int ZEXPORT deflate(z_streamp strm, int flush);
/*
deflate compresses as much data as possible, and stops when the input
buffer becomes empty or the output buffer becomes full. It may introduce
@@ -324,8 +324,8 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
with the same value of the flush parameter and more output space (updated
avail_out), until the flush is complete (deflate returns with non-zero
avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
- avail_out is greater than six to avoid repeated flush markers due to
- avail_out == 0 on return.
+ avail_out is greater than six when the flush marker begins, in order to avoid
+ repeated flush markers upon calling deflate() again when avail_out == 0.
If the parameter flush is set to Z_FINISH, pending input is processed,
pending output is flushed and deflate returns with Z_STREAM_END if there was
@@ -364,7 +364,7 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
*/
-ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+ZEXTERN int ZEXPORT deflateEnd(z_streamp strm);
/*
All dynamically allocated data structures for this stream are freed.
This function discards any unprocessed input and does not flush any pending
@@ -379,7 +379,7 @@ ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
/*
-ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+ZEXTERN int ZEXPORT inflateInit(z_streamp strm);
Initializes the internal stream state for decompression. The fields
next_in, avail_in, zalloc, zfree and opaque must be initialized before by
@@ -387,7 +387,8 @@ ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
read or consumed. The allocation of a sliding window will be deferred to
the first call of inflate (if the decompression does not complete on the
first call). If zalloc and zfree are set to Z_NULL, inflateInit updates
- them to use default allocation functions.
+ them to use default allocation functions. total_in, total_out, adler, and
+ msg are initialized.
inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
@@ -401,7 +402,7 @@ ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
*/
-ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+ZEXTERN int ZEXPORT inflate(z_streamp strm, int flush);
/*
inflate decompresses as much data as possible, and stops when the input
buffer becomes empty or the output buffer becomes full. It may introduce
@@ -521,7 +522,7 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
*/
-ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+ZEXTERN int ZEXPORT inflateEnd(z_streamp strm);
/*
All dynamically allocated data structures for this stream are freed.
This function discards any unprocessed input and does not flush any pending
@@ -539,12 +540,12 @@ ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
*/
/*
-ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
- int level,
- int method,
- int windowBits,
- int memLevel,
- int strategy));
+ZEXTERN int ZEXPORT deflateInit2(z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy);
This is another version of deflateInit with more compression options. The
fields zalloc, zfree and opaque must be initialized before by the caller.
@@ -611,9 +612,9 @@ ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
compression: this will be done by deflate().
*/
-ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
- const Bytef *dictionary,
- uInt dictLength));
+ZEXTERN int ZEXPORT deflateSetDictionary(z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength);
/*
Initializes the compression dictionary from the given byte sequence
without producing any compressed output. When using the zlib format, this
@@ -655,9 +656,9 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
not perform any compression: this will be done by deflate().
*/
-ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm,
- Bytef *dictionary,
- uInt *dictLength));
+ZEXTERN int ZEXPORT deflateGetDictionary(z_streamp strm,
+ Bytef *dictionary,
+ uInt *dictLength);
/*
Returns the sliding dictionary being maintained by deflate. dictLength is
set to the number of bytes in the dictionary, and that many bytes are copied
@@ -677,8 +678,8 @@ ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm,
stream state is inconsistent.
*/
-ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
- z_streamp source));
+ZEXTERN int ZEXPORT deflateCopy(z_streamp dest,
+ z_streamp source);
/*
Sets the destination stream as a complete copy of the source stream.
@@ -695,20 +696,20 @@ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
destination.
*/
-ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+ZEXTERN int ZEXPORT deflateReset(z_streamp strm);
/*
This function is equivalent to deflateEnd followed by deflateInit, but
does not free and reallocate the internal compression state. The stream
will leave the compression level and any other attributes that may have been
- set unchanged.
+ set unchanged. total_in, total_out, adler, and msg are initialized.
deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
stream state was inconsistent (such as zalloc or state being Z_NULL).
*/
-ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
- int level,
- int strategy));
+ZEXTERN int ZEXPORT deflateParams(z_streamp strm,
+ int level,
+ int strategy);
/*
Dynamically update the compression level and compression strategy. The
interpretation of level and strategy is as in deflateInit2(). This can be
@@ -733,7 +734,7 @@ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
Then no more input data should be provided before the deflateParams() call.
If this is done, the old level and strategy will be applied to the data
compressed before deflateParams(), and the new level and strategy will be
- applied to the the data compressed after deflateParams().
+ applied to the data compressed after deflateParams().
deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream
state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if
@@ -744,11 +745,11 @@ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
retried with more output space.
*/
-ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
- int good_length,
- int max_lazy,
- int nice_length,
- int max_chain));
+ZEXTERN int ZEXPORT deflateTune(z_streamp strm,
+ int good_length,
+ int max_lazy,
+ int nice_length,
+ int max_chain);
/*
Fine tune deflate's internal compression parameters. This should only be
used by someone who understands the algorithm used by zlib's deflate for
@@ -761,8 +762,8 @@ ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
*/
-ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
- uLong sourceLen));
+ZEXTERN uLong ZEXPORT deflateBound(z_streamp strm,
+ uLong sourceLen);
/*
deflateBound() returns an upper bound on the compressed size after
deflation of sourceLen bytes. It must be called after deflateInit() or
@@ -776,9 +777,9 @@ ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
than Z_FINISH or Z_NO_FLUSH are used.
*/
-ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm,
- unsigned *pending,
- int *bits));
+ZEXTERN int ZEXPORT deflatePending(z_streamp strm,
+ unsigned *pending,
+ int *bits);
/*
deflatePending() returns the number of bytes and bits of output that have
been generated, but not yet provided in the available output. The bytes not
@@ -791,9 +792,9 @@ ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm,
stream state was inconsistent.
*/
-ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
- int bits,
- int value));
+ZEXTERN int ZEXPORT deflatePrime(z_streamp strm,
+ int bits,
+ int value);
/*
deflatePrime() inserts bits in the deflate output stream. The intent
is that this function is used to start off the deflate output with the bits
@@ -808,8 +809,8 @@ ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
source stream state was inconsistent.
*/
-ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
- gz_headerp head));
+ZEXTERN int ZEXPORT deflateSetHeader(z_streamp strm,
+ gz_headerp head);
/*
deflateSetHeader() provides gzip header information for when a gzip
stream is requested by deflateInit2(). deflateSetHeader() may be called
@@ -825,16 +826,17 @@ ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
gzip file" and give up.
If deflateSetHeader is not used, the default gzip header has text false,
- the time set to zero, and os set to 255, with no extra, name, or comment
- fields. The gzip header is returned to the default state by deflateReset().
+ the time set to zero, and os set to the current operating system, with no
+ extra, name, or comment fields. The gzip header is returned to the default
+ state by deflateReset().
deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
stream state was inconsistent.
*/
/*
-ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
- int windowBits));
+ZEXTERN int ZEXPORT inflateInit2(z_streamp strm,
+ int windowBits);
This is another version of inflateInit with an extra parameter. The
fields next_in, avail_in, zalloc, zfree and opaque must be initialized
@@ -887,9 +889,9 @@ ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
deferred until inflate() is called.
*/
-ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
- const Bytef *dictionary,
- uInt dictLength));
+ZEXTERN int ZEXPORT inflateSetDictionary(z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength);
/*
Initializes the decompression dictionary from the given uncompressed byte
sequence. This function must be called immediately after a call of inflate,
@@ -910,9 +912,9 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
inflate().
*/
-ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm,
- Bytef *dictionary,
- uInt *dictLength));
+ZEXTERN int ZEXPORT inflateGetDictionary(z_streamp strm,
+ Bytef *dictionary,
+ uInt *dictLength);
/*
Returns the sliding dictionary being maintained by inflate. dictLength is
set to the number of bytes in the dictionary, and that many bytes are copied
@@ -925,7 +927,7 @@ ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm,
stream state is inconsistent.
*/
-ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+ZEXTERN int ZEXPORT inflateSync(z_streamp strm);
/*
Skips invalid compressed data until a possible full flush point (see above
for the description of deflate with Z_FULL_FLUSH) can be found, or until all
@@ -938,14 +940,14 @@ ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
inflateSync returns Z_OK if a possible full flush point has been found,
Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point
has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.
- In the success case, the application may save the current current value of
- total_in which indicates where valid compressed data was found. In the
- error case, the application may repeatedly call inflateSync, providing more
- input each time, until success or end of the input data.
+ In the success case, the application may save the current value of total_in
+ which indicates where valid compressed data was found. In the error case,
+ the application may repeatedly call inflateSync, providing more input each
+ time, until success or end of the input data.
*/
-ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
- z_streamp source));
+ZEXTERN int ZEXPORT inflateCopy(z_streamp dest,
+ z_streamp source);
/*
Sets the destination stream as a complete copy of the source stream.
@@ -960,18 +962,19 @@ ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
destination.
*/
-ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+ZEXTERN int ZEXPORT inflateReset(z_streamp strm);
/*
This function is equivalent to inflateEnd followed by inflateInit,
but does not free and reallocate the internal decompression state. The
stream will keep attributes that may have been set by inflateInit2.
+ total_in, total_out, adler, and msg are initialized.
inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
stream state was inconsistent (such as zalloc or state being Z_NULL).
*/
-ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,
- int windowBits));
+ZEXTERN int ZEXPORT inflateReset2(z_streamp strm,
+ int windowBits);
/*
This function is the same as inflateReset, but it also permits changing
the wrap and window size requests. The windowBits parameter is interpreted
@@ -984,9 +987,9 @@ ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,
the windowBits parameter is invalid.
*/
-ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
- int bits,
- int value));
+ZEXTERN int ZEXPORT inflatePrime(z_streamp strm,
+ int bits,
+ int value);
/*
This function inserts bits in the inflate input stream. The intent is
that this function is used to start inflating at a bit position in the
@@ -1005,7 +1008,7 @@ ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
stream state was inconsistent.
*/
-ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));
+ZEXTERN long ZEXPORT inflateMark(z_streamp strm);
/*
This function returns two values, one in the lower 16 bits of the return
value, and the other in the remaining upper bits, obtained by shifting the
@@ -1033,8 +1036,8 @@ ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));
source stream state was inconsistent.
*/
-ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
- gz_headerp head));
+ZEXTERN int ZEXPORT inflateGetHeader(z_streamp strm,
+ gz_headerp head);
/*
inflateGetHeader() requests that gzip header information be stored in the
provided gz_header structure. inflateGetHeader() may be called after
@@ -1074,8 +1077,8 @@ ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
*/
/*
-ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
- unsigned char FAR *window));
+ZEXTERN int ZEXPORT inflateBackInit(z_streamp strm, int windowBits,
+ unsigned char FAR *window);
Initialize the internal stream state for decompression using inflateBack()
calls. The fields zalloc, zfree and opaque in strm must be initialized
@@ -1095,13 +1098,13 @@ ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
the version of the header file.
*/
-typedef unsigned (*in_func) OF((void FAR *,
- z_const unsigned char FAR * FAR *));
-typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+typedef unsigned (*in_func)(void FAR *,
+ z_const unsigned char FAR * FAR *);
+typedef int (*out_func)(void FAR *, unsigned char FAR *, unsigned);
-ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
- in_func in, void FAR *in_desc,
- out_func out, void FAR *out_desc));
+ZEXTERN int ZEXPORT inflateBack(z_streamp strm,
+ in_func in, void FAR *in_desc,
+ out_func out, void FAR *out_desc);
/*
inflateBack() does a raw inflate with a single call using a call-back
interface for input and output. This is potentially more efficient than
@@ -1169,7 +1172,7 @@ ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
cannot return Z_OK.
*/
-ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+ZEXTERN int ZEXPORT inflateBackEnd(z_streamp strm);
/*
All memory allocated by inflateBackInit() is freed.
@@ -1177,7 +1180,7 @@ ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
state was inconsistent.
*/
-ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+ZEXTERN uLong ZEXPORT zlibCompileFlags(void);
/* Return flags indicating compile-time options.
Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
@@ -1230,8 +1233,8 @@ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
you need special options.
*/
-ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
- const Bytef *source, uLong sourceLen));
+ZEXTERN int ZEXPORT compress(Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen);
/*
Compresses the source buffer into the destination buffer. sourceLen is
the byte length of the source buffer. Upon entry, destLen is the total size
@@ -1245,9 +1248,9 @@ ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
buffer.
*/
-ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
- const Bytef *source, uLong sourceLen,
- int level));
+ZEXTERN int ZEXPORT compress2(Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen,
+ int level);
/*
Compresses the source buffer into the destination buffer. The level
parameter has the same meaning as in deflateInit. sourceLen is the byte
@@ -1261,15 +1264,15 @@ ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
Z_STREAM_ERROR if the level parameter is invalid.
*/
-ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+ZEXTERN uLong ZEXPORT compressBound(uLong sourceLen);
/*
compressBound() returns an upper bound on the compressed size after
compress() or compress2() on sourceLen bytes. It would be used before a
compress() or compress2() call to allocate the destination buffer.
*/
-ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
- const Bytef *source, uLong sourceLen));
+ZEXTERN int ZEXPORT uncompress(Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen);
/*
Decompresses the source buffer into the destination buffer. sourceLen is
the byte length of the source buffer. Upon entry, destLen is the total size
@@ -1286,8 +1289,8 @@ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
buffer with the uncompressed data up to that point.
*/
-ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen,
- const Bytef *source, uLong *sourceLen));
+ZEXTERN int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong *sourceLen);
/*
Same as uncompress, except that sourceLen is a pointer, where the
length of the source is *sourceLen. On return, *sourceLen is the number of
@@ -1306,7 +1309,7 @@ ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen,
typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */
/*
-ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+ZEXTERN gzFile ZEXPORT gzopen(const char *path, const char *mode);
Open the gzip (.gz) file at path for reading and decompressing, or
compressing and writing. The mode parameter is as in fopen ("rb" or "wb")
@@ -1343,7 +1346,7 @@ ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
file could not be opened.
*/
-ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+ZEXTERN gzFile ZEXPORT gzdopen(int fd, const char *mode);
/*
Associate a gzFile with the file descriptor fd. File descriptors are
obtained from calls like open, dup, creat, pipe or fileno (if the file has
@@ -1366,7 +1369,7 @@ ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
will not detect if fd is invalid (unless fd is -1).
*/
-ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));
+ZEXTERN int ZEXPORT gzbuffer(gzFile file, unsigned size);
/*
Set the internal buffer size used by this library's functions for file to
size. The default buffer size is 8192 bytes. This function must be called
@@ -1382,7 +1385,7 @@ ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));
too late.
*/
-ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+ZEXTERN int ZEXPORT gzsetparams(gzFile file, int level, int strategy);
/*
Dynamically update the compression level and strategy for file. See the
description of deflateInit2 for the meaning of these parameters. Previously
@@ -1393,7 +1396,7 @@ ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
or Z_MEM_ERROR if there is a memory allocation error.
*/
-ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+ZEXTERN int ZEXPORT gzread(gzFile file, voidp buf, unsigned len);
/*
Read and decompress up to len uncompressed bytes from file into buf. If
the input file is not in gzip format, gzread copies the given number of
@@ -1423,8 +1426,8 @@ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
Z_STREAM_ERROR.
*/
-ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems,
- gzFile file));
+ZEXTERN z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems,
+ gzFile file);
/*
Read and decompress up to nitems items of size size from file into buf,
otherwise operating as gzread() does. This duplicates the interface of
@@ -1449,14 +1452,14 @@ ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems,
file, resetting and retrying on end-of-file, when size is not 1.
*/
-ZEXTERN int ZEXPORT gzwrite OF((gzFile file, voidpc buf, unsigned len));
+ZEXTERN int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len);
/*
Compress and write the len uncompressed bytes at buf to file. gzwrite
returns the number of uncompressed bytes written or 0 in case of error.
*/
-ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size,
- z_size_t nitems, gzFile file));
+ZEXTERN z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size,
+ z_size_t nitems, gzFile file);
/*
Compress and write nitems items of size size from buf to file, duplicating
the interface of stdio's fwrite(), with size_t request and return types. If
@@ -1469,7 +1472,7 @@ ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size,
is returned, and the error state is set to Z_STREAM_ERROR.
*/
-ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...));
+ZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...);
/*
Convert, format, compress, and write the arguments (...) to file under
control of the string format, as in fprintf. gzprintf returns the number of
@@ -1484,7 +1487,7 @@ ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...));
This can be determined using zlibCompileFlags().
*/
-ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+ZEXTERN int ZEXPORT gzputs(gzFile file, const char *s);
/*
Compress and write the given null-terminated string s to file, excluding
the terminating null character.
@@ -1492,7 +1495,7 @@ ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
gzputs returns the number of characters written, or -1 in case of error.
*/
-ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+ZEXTERN char * ZEXPORT gzgets(gzFile file, char *buf, int len);
/*
Read and decompress bytes from file into buf, until len-1 characters are
read, or until a newline character is read and transferred to buf, or an
@@ -1506,13 +1509,13 @@ ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
buf are indeterminate.
*/
-ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+ZEXTERN int ZEXPORT gzputc(gzFile file, int c);
/*
Compress and write c, converted to an unsigned char, into file. gzputc
returns the value that was written, or -1 in case of error.
*/
-ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+ZEXTERN int ZEXPORT gzgetc(gzFile file);
/*
Read and decompress one byte from file. gzgetc returns this byte or -1
in case of end of file or error. This is implemented as a macro for speed.
@@ -1521,7 +1524,7 @@ ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
points to has been clobbered or not.
*/
-ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+ZEXTERN int ZEXPORT gzungetc(int c, gzFile file);
/*
Push c back onto the stream for file to be read as the first character on
the next read. At least one character of push-back is always allowed.
@@ -1533,7 +1536,7 @@ ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
gzseek() or gzrewind().
*/
-ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+ZEXTERN int ZEXPORT gzflush(gzFile file, int flush);
/*
Flush all pending output to file. The parameter flush is as in the
deflate() function. The return value is the zlib error number (see function
@@ -1549,8 +1552,8 @@ ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
*/
/*
-ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
- z_off_t offset, int whence));
+ZEXTERN z_off_t ZEXPORT gzseek(gzFile file,
+ z_off_t offset, int whence);
Set the starting position to offset relative to whence for the next gzread
or gzwrite on file. The offset represents a number of bytes in the
@@ -1568,7 +1571,7 @@ ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
would be before the current position.
*/
-ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
+ZEXTERN int ZEXPORT gzrewind(gzFile file);
/*
Rewind file. This function is supported only for reading.
@@ -1576,7 +1579,7 @@ ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
*/
/*
-ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
+ZEXTERN z_off_t ZEXPORT gztell(gzFile file);
Return the starting position for the next gzread or gzwrite on file.
This position represents a number of bytes in the uncompressed data stream,
@@ -1587,7 +1590,7 @@ ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
*/
/*
-ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));
+ZEXTERN z_off_t ZEXPORT gzoffset(gzFile file);
Return the current compressed (actual) read or write offset of file. This
offset includes the count of bytes that precede the gzip stream, for example
@@ -1596,7 +1599,7 @@ ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));
be used for a progress indicator. On error, gzoffset() returns -1.
*/
-ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+ZEXTERN int ZEXPORT gzeof(gzFile file);
/*
Return true (1) if the end-of-file indicator for file has been set while
reading, false (0) otherwise. Note that the end-of-file indicator is set
@@ -1611,7 +1614,7 @@ ZEXTERN int ZEXPORT gzeof OF((gzFile file));
has grown since the previous end of file was detected.
*/
-ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+ZEXTERN int ZEXPORT gzdirect(gzFile file);
/*
Return true (1) if file is being copied directly while reading, or false
(0) if file is a gzip stream being decompressed.
@@ -1632,7 +1635,7 @@ ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
gzip file reading and decompression, which may not be desired.)
*/
-ZEXTERN int ZEXPORT gzclose OF((gzFile file));
+ZEXTERN int ZEXPORT gzclose(gzFile file);
/*
Flush all pending output for file, if necessary, close file and
deallocate the (de)compression state. Note that once file is closed, you
@@ -1645,8 +1648,8 @@ ZEXTERN int ZEXPORT gzclose OF((gzFile file));
last read ended in the middle of a gzip stream, or Z_OK on success.
*/
-ZEXTERN int ZEXPORT gzclose_r OF((gzFile file));
-ZEXTERN int ZEXPORT gzclose_w OF((gzFile file));
+ZEXTERN int ZEXPORT gzclose_r(gzFile file);
+ZEXTERN int ZEXPORT gzclose_w(gzFile file);
/*
Same as gzclose(), but gzclose_r() is only for use when reading, and
gzclose_w() is only for use when writing or appending. The advantage to
@@ -1657,7 +1660,7 @@ ZEXTERN int ZEXPORT gzclose_w OF((gzFile file));
zlib library.
*/
-ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+ZEXTERN const char * ZEXPORT gzerror(gzFile file, int *errnum);
/*
Return the error message for the last error which occurred on file.
errnum is set to zlib error number. If an error occurred in the file system
@@ -1673,7 +1676,7 @@ ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
functions above that do not distinguish those cases in their return values.
*/
-ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+ZEXTERN void ZEXPORT gzclearerr(gzFile file);
/*
Clear the error and end-of-file flags for file. This is analogous to the
clearerr() function in stdio. This is useful for continuing to read a gzip
@@ -1690,7 +1693,7 @@ ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
library.
*/
-ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+ZEXTERN uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len);
/*
Update a running Adler-32 checksum with the bytes buf[0..len-1] and
return the updated checksum. An Adler-32 value is in the range of a 32-bit
@@ -1710,15 +1713,15 @@ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
if (adler != original_adler) error();
*/
-ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf,
- z_size_t len));
+ZEXTERN uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf,
+ z_size_t len);
/*
Same as adler32(), but with a size_t length.
*/
/*
-ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
- z_off_t len2));
+ZEXTERN uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2,
+ z_off_t len2);
Combine two Adler-32 checksums into one. For two sequences of bytes, seq1
and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
@@ -1728,7 +1731,7 @@ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
negative, the result has no meaning or utility.
*/
-ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
+ZEXTERN uLong ZEXPORT crc32(uLong crc, const Bytef *buf, uInt len);
/*
Update a running CRC-32 with the bytes buf[0..len-1] and return the
updated CRC-32. A CRC-32 value is in the range of a 32-bit unsigned integer.
@@ -1746,30 +1749,30 @@ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
if (crc != original_crc) error();
*/
-ZEXTERN uLong ZEXPORT crc32_z OF((uLong crc, const Bytef *buf,
- z_size_t len));
+ZEXTERN uLong ZEXPORT crc32_z(uLong crc, const Bytef *buf,
+ z_size_t len);
/*
Same as crc32(), but with a size_t length.
*/
/*
-ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+ZEXTERN uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2);
Combine two CRC-32 check values into one. For two sequences of bytes,
seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32
check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
- len2.
+ len2. len2 must be non-negative.
*/
/*
-ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t len2));
+ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t len2);
Return the operator corresponding to length len2, to be used with
- crc32_combine_op().
+ crc32_combine_op(). len2 must be non-negative.
*/
-ZEXTERN uLong ZEXPORT crc32_combine_op OF((uLong crc1, uLong crc2, uLong op));
+ZEXTERN uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op);
/*
Give the same result as crc32_combine(), using op in place of len2. op is
is generated from len2 by crc32_combine_gen(). This will be faster than
@@ -1782,20 +1785,20 @@ ZEXTERN uLong ZEXPORT crc32_combine_op OF((uLong crc1, uLong crc2, uLong op));
/* deflateInit and inflateInit are macros to allow checking the zlib version
* and the compiler's view of z_stream:
*/
-ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
- const char *version, int stream_size));
-ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
- const char *version, int stream_size));
-ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
- int windowBits, int memLevel,
- int strategy, const char *version,
- int stream_size));
-ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
- const char *version, int stream_size));
-ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
- unsigned char FAR *window,
- const char *version,
- int stream_size));
+ZEXTERN int ZEXPORT deflateInit_(z_streamp strm, int level,
+ const char *version, int stream_size);
+ZEXTERN int ZEXPORT inflateInit_(z_streamp strm,
+ const char *version, int stream_size);
+ZEXTERN int ZEXPORT deflateInit2_(z_streamp strm, int level, int method,
+ int windowBits, int memLevel,
+ int strategy, const char *version,
+ int stream_size);
+ZEXTERN int ZEXPORT inflateInit2_(z_streamp strm, int windowBits,
+ const char *version, int stream_size);
+ZEXTERN int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits,
+ unsigned char FAR *window,
+ const char *version,
+ int stream_size);
#ifdef Z_PREFIX_SET
# define z_deflateInit(strm, level) \
deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))
@@ -1840,7 +1843,7 @@ struct gzFile_s {
unsigned char *next;
z_off64_t pos;
};
-ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */
+ZEXTERN int ZEXPORT gzgetc_(gzFile file); /* backward compatibility */
#ifdef Z_PREFIX_SET
# undef z_gzgetc
# define z_gzgetc(g) \
@@ -1857,13 +1860,13 @@ ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */
* without large file support, _LFS64_LARGEFILE must also be true
*/
#ifdef Z_LARGE64
- ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
- ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
- ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
- ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
- ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t));
- ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t));
- ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off64_t));
+ ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *);
+ ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int);
+ ZEXTERN z_off64_t ZEXPORT gztell64(gzFile);
+ ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile);
+ ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off64_t);
+ ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off64_t);
+ ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off64_t);
#endif
#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64)
@@ -1885,50 +1888,50 @@ ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */
# define crc32_combine_gen crc32_combine_gen64
# endif
# ifndef Z_LARGE64
- ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
- ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int));
- ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));
- ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));
- ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
- ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
- ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off_t));
+ ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *);
+ ZEXTERN z_off_t ZEXPORT gzseek64(gzFile, z_off_t, int);
+ ZEXTERN z_off_t ZEXPORT gztell64(gzFile);
+ ZEXTERN z_off_t ZEXPORT gzoffset64(gzFile);
+ ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t);
+ ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t);
+ ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t);
# endif
#else
- ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));
- ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));
- ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));
- ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));
- ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
- ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
- ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t));
+ ZEXTERN gzFile ZEXPORT gzopen(const char *, const char *);
+ ZEXTERN z_off_t ZEXPORT gzseek(gzFile, z_off_t, int);
+ ZEXTERN z_off_t ZEXPORT gztell(gzFile);
+ ZEXTERN z_off_t ZEXPORT gzoffset(gzFile);
+ ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t);
+ ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t);
+ ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t);
#endif
#else /* Z_SOLO */
- ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
- ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
- ZEXTERN uLong ZEXPORT crc32_combine_gen OF((z_off_t));
+ ZEXTERN uLong ZEXPORT adler32_combine(uLong, uLong, z_off_t);
+ ZEXTERN uLong ZEXPORT crc32_combine(uLong, uLong, z_off_t);
+ ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t);
#endif /* !Z_SOLO */
/* undocumented functions */
-ZEXTERN const char * ZEXPORT zError OF((int));
-ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp));
-ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void));
-ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int));
-ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int));
-ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF((z_streamp));
-ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp));
-ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp));
+ZEXTERN const char * ZEXPORT zError(int);
+ZEXTERN int ZEXPORT inflateSyncPoint(z_streamp);
+ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table(void);
+ZEXTERN int ZEXPORT inflateUndermine(z_streamp, int);
+ZEXTERN int ZEXPORT inflateValidate(z_streamp, int);
+ZEXTERN unsigned long ZEXPORT inflateCodesUsed(z_streamp);
+ZEXTERN int ZEXPORT inflateResetKeep(z_streamp);
+ZEXTERN int ZEXPORT deflateResetKeep(z_streamp);
#if defined(_WIN32) && !defined(Z_SOLO)
-ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path,
- const char *mode));
+ZEXTERN gzFile ZEXPORT gzopen_w(const wchar_t *path,
+ const char *mode);
#endif
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
# ifndef Z_SOLO
-ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file,
- const char *format,
- va_list va));
+ZEXTERN int ZEXPORTVA gzvprintf(gzFile file,
+ const char *format,
+ va_list va);
# endif
#endif
diff --git a/src/3rdparty/zlib/src/zutil.c b/src/3rdparty/zlib/src/zutil.c
index 9543ae825e..b1c5d2d3c6 100644
--- a/src/3rdparty/zlib/src/zutil.c
+++ b/src/3rdparty/zlib/src/zutil.c
@@ -24,13 +24,11 @@ z_const char * const z_errmsg[10] = {
};
-const char * ZEXPORT zlibVersion()
-{
+const char * ZEXPORT zlibVersion(void) {
return ZLIB_VERSION;
}
-uLong ZEXPORT zlibCompileFlags()
-{
+uLong ZEXPORT zlibCompileFlags(void) {
uLong flags;
flags = 0;
@@ -121,9 +119,7 @@ uLong ZEXPORT zlibCompileFlags()
# endif
int ZLIB_INTERNAL z_verbose = verbose;
-void ZLIB_INTERNAL z_error(m)
- char *m;
-{
+void ZLIB_INTERNAL z_error(char *m) {
fprintf(stderr, "%s\n", m);
exit(1);
}
@@ -132,9 +128,7 @@ void ZLIB_INTERNAL z_error(m)
/* exported to allow conversion of error code to string for compress() and
* uncompress()
*/
-const char * ZEXPORT zError(err)
- int err;
-{
+const char * ZEXPORT zError(int err) {
return ERR_MSG(err);
}
@@ -148,22 +142,14 @@ const char * ZEXPORT zError(err)
#ifndef HAVE_MEMCPY
-void ZLIB_INTERNAL zmemcpy(dest, source, len)
- Bytef* dest;
- const Bytef* source;
- uInt len;
-{
+void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len) {
if (len == 0) return;
do {
*dest++ = *source++; /* ??? to be unrolled */
} while (--len != 0);
}
-int ZLIB_INTERNAL zmemcmp(s1, s2, len)
- const Bytef* s1;
- const Bytef* s2;
- uInt len;
-{
+int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len) {
uInt j;
for (j = 0; j < len; j++) {
@@ -172,10 +158,7 @@ int ZLIB_INTERNAL zmemcmp(s1, s2, len)
return 0;
}
-void ZLIB_INTERNAL zmemzero(dest, len)
- Bytef* dest;
- uInt len;
-{
+void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len) {
if (len == 0) return;
do {
*dest++ = 0; /* ??? to be unrolled */
@@ -216,8 +199,7 @@ local ptr_table table[MAX_PTR];
* a protected system like OS/2. Use Microsoft C instead.
*/
-voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size)
-{
+voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) {
voidpf buf;
ulg bsize = (ulg)items*size;
@@ -242,8 +224,7 @@ voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size)
return buf;
}
-void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr)
-{
+void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) {
int n;
(void)opaque;
@@ -279,14 +260,12 @@ void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr)
# define _hfree hfree
#endif
-voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size)
-{
+voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) {
(void)opaque;
return _halloc((long)items, size);
}
-void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr)
-{
+void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) {
(void)opaque;
_hfree(ptr);
}
@@ -299,25 +278,18 @@ void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr)
#ifndef MY_ZCALLOC /* Any system without a special alloc function */
#ifndef STDC
-extern voidp malloc OF((uInt size));
-extern voidp calloc OF((uInt items, uInt size));
-extern void free OF((voidpf ptr));
+extern voidp malloc(uInt size);
+extern voidp calloc(uInt items, uInt size);
+extern void free(voidpf ptr);
#endif
-voidpf ZLIB_INTERNAL zcalloc(opaque, items, size)
- voidpf opaque;
- unsigned items;
- unsigned size;
-{
+voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) {
(void)opaque;
return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
(voidpf)calloc(items, size);
}
-void ZLIB_INTERNAL zcfree(opaque, ptr)
- voidpf opaque;
- voidpf ptr;
-{
+void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) {
(void)opaque;
free(ptr);
}
diff --git a/src/3rdparty/zlib/src/zutil.h b/src/3rdparty/zlib/src/zutil.h
index 29c690eea0..71dd616ab8 100644
--- a/src/3rdparty/zlib/src/zutil.h
+++ b/src/3rdparty/zlib/src/zutil.h
@@ -1,5 +1,5 @@
/* zutil.h -- internal interface and configuration of the compression library
- * Copyright (C) 1995-2022 Jean-loup Gailly, Mark Adler
+ * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -62,7 +62,7 @@ typedef unsigned long ulg;
extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
/* (size given to avoid silly warnings with Visual C++) */
-#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+#define ERR_MSG(err) z_errmsg[(err) < -6 || (err) > 2 ? 9 : 2 - (err)]
#define ERR_RETURN(strm,err) \
return (strm->msg = ERR_MSG(err), (err))
@@ -143,22 +143,8 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
# endif
#endif
-#if defined(MACOS) || defined(TARGET_OS_MAC)
+#if defined(MACOS)
# define OS_CODE 7
-# ifndef Z_SOLO
-# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
-# include <unix.h> /* for fdopen */
-# else
-// We need to include stdio.h here because zlib.h will include TargetConditionals.h
-// This will define TARGET_OS_MAC that leads to this check.
-// Since zutil.h will include gzguts.h and gzguts.h includes stdio.h
-// AFTER check for fdopen we need to include stdio.h directly
-# include <stdio.h>
-# ifndef fdopen
-# define fdopen(fd,mode) NULL /* No fdopen() */
-# endif
-# endif
-# endif
#endif
#ifdef __acorn
@@ -181,18 +167,6 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
# define OS_CODE 19
#endif
-#if defined(_BEOS_) || defined(RISCOS)
-# define fdopen(fd,mode) NULL /* No fdopen() */
-#endif
-
-#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX
-# if defined(_WIN32_WCE)
-# define fdopen(fd,mode) NULL /* No fdopen() */
-# else
-# define fdopen(fd,type) _fdopen(fd,type)
-# endif
-#endif
-
#if defined(__BORLANDC__) && !defined(MSDOS)
#pragma warn -8004
#pragma warn -8008
@@ -202,9 +176,9 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
/* provide prototypes for these when building zlib without LFS */
#if !defined(_WIN32) && \
(!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
- ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
- ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
- ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off_t));
+ ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t);
+ ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t);
+ ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t);
#endif
/* common defaults */
@@ -243,16 +217,16 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
# define zmemzero(dest, len) memset(dest, 0, len)
# endif
#else
- void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
- int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
- void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len));
+ void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len);
+ int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len);
+ void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len);
#endif
/* Diagnostic functions */
#ifdef ZLIB_DEBUG
# include <stdio.h>
extern int ZLIB_INTERNAL z_verbose;
- extern void ZLIB_INTERNAL z_error OF((char *m));
+ extern void ZLIB_INTERNAL z_error(char *m);
# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
# define Trace(x) {if (z_verbose>=0) fprintf x ;}
# define Tracev(x) {if (z_verbose>0) fprintf x ;}
@@ -269,9 +243,9 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
#endif
#ifndef Z_SOLO
- voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,
- unsigned size));
- void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr));
+ voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items,
+ unsigned size);
+ void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr);
#endif
#define ZALLOC(strm, items, size) \
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 79d313ce32..afcdd1f463 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -71,6 +71,7 @@ add_subdirectory(tools)
if(QT_FEATURE_gui)
add_subdirectory(gui)
+ add_subdirectory(assets)
if(QT_FEATURE_opengl)
add_subdirectory(opengl)
diff --git a/src/android/jar/CMakeLists.txt b/src/android/jar/CMakeLists.txt
index 170323bf03..c36bbdf75b 100644
--- a/src/android/jar/CMakeLists.txt
+++ b/src/android/jar/CMakeLists.txt
@@ -1,23 +1,45 @@
-# Copyright (C) 2022 The Qt Company Ltd.
+# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
set(java_sources
- src/org/qtproject/qt/android/accessibility/QtAccessibilityDelegate.java
- src/org/qtproject/qt/android/accessibility/QtNativeAccessibility.java
+ src/org/qtproject/qt/android/QtAccessibilityDelegate.java
+ src/org/qtproject/qt/android/QtNativeAccessibility.java
src/org/qtproject/qt/android/CursorHandle.java
src/org/qtproject/qt/android/EditContextView.java
src/org/qtproject/qt/android/EditPopupMenu.java
src/org/qtproject/qt/android/ExtractStyle.java
+ src/org/qtproject/qt/android/QtApplicationBase.java
+ src/org/qtproject/qt/android/QtActivityBase.java
+ src/org/qtproject/qt/android/QtServiceBase.java
src/org/qtproject/qt/android/QtActivityDelegate.java
+ src/org/qtproject/qt/android/QtInputDelegate.java
+ src/org/qtproject/qt/android/QtLoader.java
+ src/org/qtproject/qt/android/QtActivityLoader.java
+ src/org/qtproject/qt/android/QtServiceLoader.java
src/org/qtproject/qt/android/QtEditText.java
src/org/qtproject/qt/android/QtInputConnection.java
src/org/qtproject/qt/android/QtLayout.java
src/org/qtproject/qt/android/QtMessageDialogHelper.java
src/org/qtproject/qt/android/QtNative.java
- src/org/qtproject/qt/android/QtNativeLibrariesDir.java
+ src/org/qtproject/qt/android/QtSurfaceInterface.java
src/org/qtproject/qt/android/QtSurface.java
+ src/org/qtproject/qt/android/QtTextureView.java
src/org/qtproject/qt/android/QtThread.java
- src/org/qtproject/qt/android/QtServiceDelegate.java
+ src/org/qtproject/qt/android/extras/QtAndroidBinder.java
+ src/org/qtproject/qt/android/extras/QtAndroidServiceConnection.java
+ src/org/qtproject/qt/android/extras/QtNative.java
+ src/org/qtproject/qt/android/QtClipboardManager.java
+ src/org/qtproject/qt/android/QtDisplayManager.java
+ src/org/qtproject/qt/android/UsedFromNativeCode.java
+ src/org/qtproject/qt/android/QtRootLayout.java
+ src/org/qtproject/qt/android/QtWindow.java
+ src/org/qtproject/qt/android/QtActivityDelegateBase.java
+ src/org/qtproject/qt/android/QtEmbeddedDelegate.java
+ src/org/qtproject/qt/android/QtEmbeddedDelegateFactory.java
+ src/org/qtproject/qt/android/QtEmbeddedLoader.java
+ src/org/qtproject/qt/android/QtView.java
+ src/org/qtproject/qt/android/QtEmbeddedViewInterface.java
+ src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java
)
qt_internal_add_jar(Qt${QtBase_VERSION_MAJOR}Android
diff --git a/src/android/jar/build.gradle b/src/android/jar/build.gradle
index c947852f79..452d4ad780 100644
--- a/src/android/jar/build.gradle
+++ b/src/android/jar/build.gradle
@@ -7,7 +7,7 @@ buildscript {
}
dependencies {
- classpath 'com.android.tools.build:gradle:7.0.2'
+ classpath 'com.android.tools.build:gradle:8.0.2'
}
}
@@ -23,12 +23,11 @@ repositories {
}
android {
- compileSdkVersion 31
- buildToolsVersion "31.0.3"
+ compileSdk 34
+ namespace "org.qtproject.qt.android"
defaultConfig {
minSdkVersion 23
- targetSdkVersion 31
}
sourceSets {
diff --git a/src/android/jar/src/org/qtproject/qt/android/CursorHandle.java b/src/android/jar/src/org/qtproject/qt/android/CursorHandle.java
index 87257adb3d..7e601c0551 100644
--- a/src/android/jar/src/org/qtproject/qt/android/CursorHandle.java
+++ b/src/android/jar/src/org/qtproject/qt/android/CursorHandle.java
@@ -3,26 +3,26 @@
package org.qtproject.qt.android;
+import android.annotation.SuppressLint;
+import android.app.Activity;
import android.content.Context;
-import android.os.Bundle;
-import android.util.DisplayMetrics;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.LinearLayout;
-import android.widget.ImageView;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
-import android.view.MotionEvent;
-import android.widget.PopupWindow;
-import android.app.Activity;
+import android.util.DisplayMetrics;
+import android.util.Log;
import android.util.TypedValue;
+import android.view.MotionEvent;
+import android.view.View;
import android.view.ViewTreeObserver;
+import android.widget.ImageView;
+import android.widget.PopupWindow;
/* This view represents one of the handle (selection or cursor handle) */
+@SuppressLint("ViewConstructor")
class CursorView extends ImageView
{
- private CursorHandle mHandle;
- // The coordinare which where clicked
+ private final CursorHandle mHandle;
+ // The coordinate which where clicked
private float m_offsetX;
private float m_offsetY;
private boolean m_pressed = false;
@@ -43,7 +43,7 @@ class CursorView extends ImageView
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
m_offsetX = ev.getRawX();
- m_offsetY = ev.getRawY() + getHeight() / 2;
+ m_offsetY = ev.getRawY() + (float) getHeight() / 2;
m_pressed = true;
break;
}
@@ -52,7 +52,7 @@ class CursorView extends ImageView
if (!m_pressed)
return false;
mHandle.updatePosition(Math.round(ev.getRawX() - m_offsetX),
- Math.round(ev.getRawY() - m_offsetY));
+ Math.round(ev.getRawY() - m_offsetY));
break;
}
@@ -63,24 +63,24 @@ class CursorView extends ImageView
}
return true;
}
-
}
// Helper class that manages a cursor or selection handle
-public class CursorHandle implements ViewTreeObserver.OnPreDrawListener
+class CursorHandle implements ViewTreeObserver.OnPreDrawListener
{
- private View m_layout = null;
+ private static final String QtTag = "QtCursorHandle";
+ private final View m_layout;
private CursorView m_cursorView = null;
private PopupWindow m_popup = null;
- private int m_id;
- private int m_attr;
- private Activity m_activity;
+ private final int m_id;
+ private final int m_attr;
+ private final Activity m_activity;
private int m_posX = 0;
private int m_posY = 0;
private int m_lastX;
private int m_lastY;
int tolerance;
- private boolean m_rtl;
+ private final boolean m_rtl;
int m_yShift;
public CursorHandle(Activity activity, View layout, int id, int attr, boolean rtl) {
@@ -95,27 +95,31 @@ public class CursorHandle implements ViewTreeObserver.OnPreDrawListener
m_rtl = rtl;
}
- private boolean initOverlay(){
- if (m_popup == null){
+ private void initOverlay(){
+ if (m_popup != null)
+ return;
- Context context = m_layout.getContext();
- int[] attrs = {m_attr};
- TypedArray a = context.getTheme().obtainStyledAttributes(attrs);
- Drawable drawable = a.getDrawable(0);
+ Context context = m_layout.getContext();
+ int[] attrs = {m_attr};
+ TypedArray a = context.getTheme().obtainStyledAttributes(attrs);
+ Drawable drawable = a.getDrawable(0);
- m_cursorView = new CursorView(context, this);
- m_cursorView.setImageDrawable(drawable);
+ m_cursorView = new CursorView(context, this);
+ m_cursorView.setImageDrawable(drawable);
- m_popup = new PopupWindow(context, null, android.R.attr.textSelectHandleWindowStyle);
- m_popup.setSplitTouchEnabled(true);
- m_popup.setClippingEnabled(false);
- m_popup.setContentView(m_cursorView);
+ m_popup = new PopupWindow(context, null, android.R.attr.textSelectHandleWindowStyle);
+ m_popup.setSplitTouchEnabled(true);
+ m_popup.setClippingEnabled(false);
+ m_popup.setContentView(m_cursorView);
+ if (drawable != null) {
m_popup.setWidth(drawable.getIntrinsicWidth());
m_popup.setHeight(drawable.getIntrinsicHeight());
-
- m_layout.getViewTreeObserver().addOnPreDrawListener(this);
+ } else {
+ Log.w(QtTag, "initOverlay(): cannot get width/height for popup " +
+ "from null drawable for attribute " + m_attr);
}
- return true;
+
+ m_layout.getViewTreeObserver().addOnPreDrawListener(this);
}
// Show the handle at a given position (or move it if it is already shown)
@@ -134,9 +138,9 @@ public class CursorHandle implements ViewTreeObserver.OnPreDrawListener
int x2 = x + layoutLocation[0] - activityLocation[0];
int y2 = y + layoutLocation[1] + m_yShift + (activityLocationInWindow[1] - activityLocation[1]);
- if (m_id == QtNative.IdCursorHandle) {
+ if (m_id == QtInputDelegate.IdCursorHandle) {
x2 -= m_popup.getWidth() / 2 ;
- } else if ((m_id == QtNative.IdLeftHandle && !m_rtl) || (m_id == QtNative.IdRightHandle && m_rtl)) {
+ } else if ((m_id == QtInputDelegate.IdLeftHandle && !m_rtl) || (m_id == QtInputDelegate.IdRightHandle && m_rtl)) {
x2 -= m_popup.getWidth() * 3 / 4;
} else {
x2 -= m_popup.getWidth() / 4;
@@ -176,7 +180,7 @@ public class CursorHandle implements ViewTreeObserver.OnPreDrawListener
public void updatePosition(int x, int y) {
y -= m_yShift;
if (Math.abs(m_lastX - x) > tolerance || Math.abs(m_lastY - y) > tolerance) {
- QtNative.handleLocationChanged(m_id, x + m_posX, y + m_posY);
+ QtInputDelegate.handleLocationChanged(m_id, x + m_posX, y + m_posY);
m_lastX = x;
m_lastY = y;
}
diff --git a/src/android/jar/src/org/qtproject/qt/android/EditContextView.java b/src/android/jar/src/org/qtproject/qt/android/EditContextView.java
index 54b6c14137..fbd32ed98b 100644
--- a/src/android/jar/src/org/qtproject/qt/android/EditContextView.java
+++ b/src/android/jar/src/org/qtproject/qt/android/EditContextView.java
@@ -4,25 +4,27 @@
package org.qtproject.qt.android;
+import android.annotation.SuppressLint;
import android.content.Context;
+import android.graphics.Point;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
-import android.R;
import java.util.HashMap;
-public class EditContextView extends LinearLayout implements View.OnClickListener
+@SuppressLint("ViewConstructor")
+class EditContextView extends LinearLayout implements View.OnClickListener
{
- public static final int CUT_BUTTON = 1 << 0;
+ public static final int CUT_BUTTON = 1;
public static final int COPY_BUTTON = 1 << 1;
public static final int PASTE_BUTTON = 1 << 2;
- public static final int SALL_BUTTON = 1 << 3;
+ public static final int SELECT_ALL_BUTTON = 1 << 3;
- HashMap<Integer, ContextButton> m_buttons = new HashMap<Integer, ContextButton>(4);
+ HashMap<Integer, ContextButton> m_buttons = new HashMap<>(4);
OnClickListener m_onClickListener;
public interface OnClickListener
@@ -40,8 +42,10 @@ public class EditContextView extends LinearLayout implements View.OnClickListene
setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT, 1));
setGravity(Gravity.CENTER);
- setTextColor(getResources().getColor(R.color.widget_edittext_dark));
- EditContextView.this.setBackground(getResources().getDrawable(R.drawable.editbox_background_normal));
+ setTextColor(getResources().getColor(
+ android.R.color.widget_edittext_dark, context.getTheme()));
+ EditContextView.this.setBackground(getResources().getDrawable(
+ android.R.drawable.editbox_background_normal, context.getTheme()));
float scale = getResources().getDisplayMetrics().density;
int hPadding = (int)(16 * scale + 0.5f);
int vPadding = (int)(8 * scale + 0.5f);
@@ -68,10 +72,38 @@ public class EditContextView extends LinearLayout implements View.OnClickListene
public void updateButtons(int buttonsLayout)
{
- m_buttons.get(R.string.cut).setVisibility((buttonsLayout & CUT_BUTTON) != 0 ? View.VISIBLE : View.GONE);
- m_buttons.get(R.string.copy).setVisibility((buttonsLayout & COPY_BUTTON) != 0 ? View.VISIBLE : View.GONE);
- m_buttons.get(R.string.paste).setVisibility((buttonsLayout & PASTE_BUTTON) != 0 ? View.VISIBLE : View.GONE);
- m_buttons.get(R.string.selectAll).setVisibility((buttonsLayout & SALL_BUTTON) != 0 ? View.VISIBLE : View.GONE);
+ ContextButton button = m_buttons.get(android.R.string.cut);
+ if (button != null)
+ button.setVisibility((buttonsLayout & CUT_BUTTON) != 0 ? View.VISIBLE : View.GONE);
+
+ button = m_buttons.get(android.R.string.copy);
+ if (button != null)
+ button.setVisibility((buttonsLayout & COPY_BUTTON) != 0 ? View.VISIBLE : View.GONE);
+
+ button = m_buttons.get(android.R.string.paste);
+ if (button != null)
+ button.setVisibility((buttonsLayout & PASTE_BUTTON) != 0 ? View.VISIBLE : View.GONE);
+
+ button = m_buttons.get(android.R.string.selectAll);
+ if (button != null)
+ button.setVisibility((buttonsLayout & SELECT_ALL_BUTTON) != 0 ? View.VISIBLE : View.GONE);
+ }
+
+ public Point getCalculatedSize()
+ {
+ Point size = new Point(0, 0);
+ for (ContextButton b : m_buttons.values()) {
+ if (b.getVisibility() == View.VISIBLE) {
+ b.measure(0, 0);
+ size.x += b.getMeasuredWidth();
+ size.y = Math.max(size.y, b.getMeasuredHeight());
+ }
+ }
+
+ size.x += getPaddingLeft() + getPaddingRight();
+ size.y += getPaddingTop() + getPaddingBottom();
+
+ return size;
}
public EditContextView(Context context, OnClickListener onClickListener) {
@@ -79,9 +111,9 @@ public class EditContextView extends LinearLayout implements View.OnClickListene
m_onClickListener = onClickListener;
setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
- addButton(R.string.cut);
- addButton(R.string.copy);
- addButton(R.string.paste);
- addButton(R.string.selectAll);
+ addButton(android.R.string.cut);
+ addButton(android.R.string.copy);
+ addButton(android.R.string.paste);
+ addButton(android.R.string.selectAll);
}
}
diff --git a/src/android/jar/src/org/qtproject/qt/android/EditPopupMenu.java b/src/android/jar/src/org/qtproject/qt/android/EditPopupMenu.java
index 00cbb97561..25be522c48 100644
--- a/src/android/jar/src/org/qtproject/qt/android/EditPopupMenu.java
+++ b/src/android/jar/src/org/qtproject/qt/android/EditPopupMenu.java
@@ -4,32 +4,22 @@
package org.qtproject.qt.android;
+import android.app.Activity;
import android.content.Context;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.LayoutInflater;
+import android.graphics.Point;
import android.view.View;
-import android.widget.LinearLayout;
-import android.widget.ImageView;
-import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
-import android.view.MotionEvent;
-import android.widget.PopupWindow;
-import android.app.Activity;
-import android.view.ViewTreeObserver;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup.LayoutParams;
import android.view.ViewGroup;
-import android.R;
+import android.view.ViewTreeObserver;
+import android.widget.PopupWindow;
// Helper class that manages a cursor or selection handle
-public class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.OnLayoutChangeListener,
+class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.OnLayoutChangeListener,
EditContextView.OnClickListener
{
- private View m_layout = null;
- private EditContextView m_view = null;
+ private final View m_layout;
+ private final EditContextView m_view;
private PopupWindow m_popup = null;
- private Activity m_activity;
+ private final Activity m_activity;
private int m_posX;
private int m_posY;
private int m_buttons;
@@ -69,6 +59,8 @@ public class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.O
initOverlay();
m_view.updateButtons(buttons);
+ Point viewSize = m_view.getCalculatedSize();
+
final int[] layoutLocation = new int[2];
m_layout.getLocationOnScreen(layoutLocation);
@@ -81,9 +73,9 @@ public class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.O
int x2 = x + layoutLocation[0] - activityLocation[0];
int y2 = y + layoutLocation[1] + (activityLocationInWindow[1] - activityLocation[1]);
- x2 -= m_view.getWidth() / 2 ;
+ x2 -= viewSize.x / 2 ;
- y2 -= m_view.getHeight();
+ y2 -= viewSize.y;
if (y2 < 0) {
if (cursorHandle != null) {
y2 = cursorHandle.bottom();
@@ -94,8 +86,8 @@ public class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.O
}
}
- if (m_layout.getWidth() < x + m_view.getWidth() / 2)
- x2 = m_layout.getWidth() - m_view.getWidth();
+ if (m_layout.getWidth() < x + viewSize.x / 2)
+ x2 = m_layout.getWidth() - viewSize.x;
if (x2 < 0)
x2 = 0;
@@ -143,16 +135,16 @@ public class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.O
@Override
public void contextButtonClicked(int buttonId) {
switch (buttonId) {
- case R.string.cut:
+ case android.R.string.cut:
QtNativeInputConnection.cut();
break;
- case R.string.copy:
+ case android.R.string.copy:
QtNativeInputConnection.copy();
break;
- case R.string.paste:
+ case android.R.string.paste:
QtNativeInputConnection.paste();
break;
- case R.string.selectAll:
+ case android.R.string.selectAll:
QtNativeInputConnection.selectAll();
break;
}
diff --git a/src/android/jar/src/org/qtproject/qt/android/ExtractStyle.java b/src/android/jar/src/org/qtproject/qt/android/ExtractStyle.java
index 672a2e28d3..6780634317 100644
--- a/src/android/jar/src/org/qtproject/qt/android/ExtractStyle.java
+++ b/src/android/jar/src/org/qtproject/qt/android/ExtractStyle.java
@@ -5,8 +5,10 @@
package org.qtproject.qt.android;
import android.annotation.SuppressLint;
+import android.app.Activity;
import android.content.Context;
import android.content.res.ColorStateList;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
@@ -34,7 +36,6 @@ import android.graphics.drawable.ScaleDrawable;
import android.graphics.drawable.StateListDrawable;
import android.graphics.drawable.VectorDrawable;
import android.os.Build;
-import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
@@ -60,7 +61,7 @@ import java.util.Map;
import java.util.Objects;
-public class ExtractStyle {
+class ExtractStyle {
// This used to be retrieved from android.R.styleable.ViewDrawableStates field via reflection,
// but since the access to that is restricted, we need to have hard-coded here.
@@ -136,26 +137,56 @@ public class ExtractStyle {
Context m_context;
private final HashMap<String, DrawableCache> m_drawableCache = new HashMap<>();
- private static final String EXTRACT_STYLE_KEY = "extract.android.style";
- private static final String EXTRACT_STYLE_MINIMAL_KEY = "extract.android.style.option";
-
private static boolean m_missingNormalStyle = false;
private static boolean m_missingDarkStyle = false;
private static String m_stylePath = null;
private static boolean m_extractMinimal = false;
- public static void setup(Bundle loaderParams) {
- if (loaderParams.containsKey(EXTRACT_STYLE_KEY)) {
- m_stylePath = loaderParams.getString(EXTRACT_STYLE_KEY);
+ private static final String QtTAG = "QtExtractStyle";
+
+ private static boolean isUiModeDark(Configuration config)
+ {
+ return (config.uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
+ }
+
+ public static String setup(Context context, String extractOption, int dpi) {
+
+ String dataDir = context.getApplicationInfo().dataDir;
+ m_stylePath = dataDir + "/qt-reserved-files/android-style/" + dpi + "/";
+
+ if (extractOption.equals("none"))
+ return m_stylePath;
- boolean darkModeFileMissing = !(new File(m_stylePath + "darkUiMode/style.json").exists());
- m_missingDarkStyle = Build.VERSION.SDK_INT > 28 && darkModeFileMissing;
+ if (extractOption.isEmpty())
+ extractOption = "minimal";
- m_missingNormalStyle = !(new File(m_stylePath + "style.json").exists());
+ if (!extractOption.equals("default") && !extractOption.equals("full")
+ && !extractOption.equals("minimal") && !extractOption.equals("none")) {
+ Log.e(QtTAG, "Invalid extract_android_style option \"" + extractOption
+ + "\", defaulting to \"minimal\"");
+ extractOption = "minimal";
+ }
- m_extractMinimal = loaderParams.containsKey(EXTRACT_STYLE_MINIMAL_KEY) &&
- loaderParams.getBoolean(EXTRACT_STYLE_MINIMAL_KEY);
+ // QTBUG-69810: The extraction code will trigger compatibility warnings on Android
+ // SDK version >= 28 when the target SDK version is set to something lower then 28,
+ // so default to "none" and issue a warning if that is the case.
+ if (extractOption.equals("default")) {
+ int targetSdk = context.getApplicationInfo().targetSdkVersion;
+ if (targetSdk < 28 && Build.VERSION.SDK_INT >= 28) {
+ Log.e(QtTAG, "extract_android_style option set to \"none\" when " +
+ "targetSdkVersion is less then 28");
+ extractOption = "none";
+ }
}
+
+ boolean darkModeFileMissing = !(new File(m_stylePath + "darkUiMode/style.json").exists());
+ m_missingDarkStyle = Build.VERSION.SDK_INT > 28 && darkModeFileMissing;
+ m_missingNormalStyle = !(new File(m_stylePath + "style.json").exists());
+ m_extractMinimal = extractOption.equals("minimal");
+
+ ExtractStyle.runIfNeeded(context, isUiModeDark(context.getResources().getConfiguration()));
+
+ return m_stylePath;
}
public static void runIfNeeded(Context context, boolean extractDarkMode) {
@@ -1104,10 +1135,6 @@ public class ExtractStyle {
return json;
}
- public JSONObject extractTextAppearanceInformation(int styleName, String qtClass, AttributeSet attributeSet) {
- return extractTextAppearanceInformation(styleName, qtClass, android.R.attr.textAppearance, attributeSet);
- }
-
public JSONObject extractTextAppearanceInformation(int styleName, String qtClass) {
return extractTextAppearanceInformation(styleName, qtClass, android.R.attr.textAppearance, null);
}
diff --git a/src/android/jar/src/org/qtproject/qt/android/accessibility/QtAccessibilityDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java
index 74d5ce5dde..d23c87e792 100644
--- a/src/android/jar/src/org/qtproject/qt/android/accessibility/QtAccessibilityDelegate.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java
@@ -2,37 +2,31 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-package org.qtproject.qt.android.accessibility;
+package org.qtproject.qt.android;
-import android.accessibilityservice.AccessibilityService;
import android.app.Activity;
+import android.content.Context;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
+import android.system.Os;
+import android.text.TextUtils;
import android.util.Log;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
-import android.text.TextUtils;
-
-import android.view.accessibility.*;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
-import android.view.MotionEvent;
-import android.view.View.OnHoverListener;
+import android.view.accessibility.AccessibilityNodeProvider;
-import android.content.Context;
-import android.system.Os;
-
-import java.util.LinkedList;
-import java.util.List;
-
-import org.qtproject.qt.android.QtActivityDelegate;
-
-public class QtAccessibilityDelegate extends View.AccessibilityDelegate
+class QtAccessibilityDelegate extends View.AccessibilityDelegate
{
private static final String TAG = "Qt A11Y";
- // Qt uses the upper half of the unsiged integers
+ // Qt uses the upper half of the unsigned integers
// all low positive ints should be fine.
public static final int INVALID_ID = 333; // half evil
@@ -41,10 +35,8 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate
private static final String DEFAULT_CLASS_NAME = "$VirtualChild";
private View m_view = null;
- private AccessibilityManager m_manager;
- private QtActivityDelegate m_activityDelegate;
- private Activity m_activity;
- private ViewGroup m_layout;
+ private final AccessibilityManager m_manager;
+ private final QtLayout m_layout;
// The accessible object that currently has the "accessibility focus"
// usually indicated by a yellow rectangle on screen.
@@ -67,14 +59,13 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate
return dispatchHoverEvent(event);
}
}
-
- public QtAccessibilityDelegate(Activity activity, ViewGroup layout, QtActivityDelegate activityDelegate)
+ // TODO do we want to have one QtAccessibilityDelegate for the whole app (QtRootLayout) or
+ // e.g. one per window?
+ public QtAccessibilityDelegate(QtLayout layout)
{
- m_activity = activity;
m_layout = layout;
- m_activityDelegate = activityDelegate;
- m_manager = (AccessibilityManager) m_activity.getSystemService(Context.ACCESSIBILITY_SERVICE);
+ m_manager = (AccessibilityManager) m_layout.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
if (m_manager != null) {
AccessibilityManagerListener accServiceListener = new AccessibilityManagerListener();
if (!m_manager.addAccessibilityStateChangeListener(accServiceListener))
@@ -92,23 +83,26 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate
if (Os.getenv("QT_ANDROID_DISABLE_ACCESSIBILITY") != null)
return;
if (enabled) {
- try {
+ try {
View view = m_view;
if (view == null) {
- view = new View(m_activity);
+ view = new View(m_layout.getContext());
view.setId(View.NO_ID);
}
// ### Keep this for debugging for a while. It allows us to visually see that our View
// ### is on top of the surface(s)
- // ColorDrawable color = new ColorDrawable(0x80ff8080); //0xAARRGGBB
- // view.setBackground(color);
+ //noinspection CommentedOutCode
+ {
+ // ColorDrawable color = new ColorDrawable(0x80ff8080); //0xAARRGGBB
+ // view.setBackground(color);
+ }
view.setAccessibilityDelegate(QtAccessibilityDelegate.this);
// if all is fine, add it to the layout
if (m_view == null) {
//m_layout.addAccessibilityView(view);
- m_layout.addView(view, m_activityDelegate.getSurfaceCount(),
+ m_layout.addView(view, m_layout.getChildCount(),
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
}
m_view = view;
@@ -116,7 +110,7 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate
m_view.setOnHoverListener(new HoverEventListener());
} catch (Exception e) {
// Unknown exception means something went wrong.
- Log.w("Qt A11y", "Unknown exception: " + e.toString());
+ Log.w("Qt A11y", "Unknown exception: " + e);
}
} else {
if (m_view != null) {
@@ -152,8 +146,6 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate
switch (event.getAction()) {
case MotionEvent.ACTION_HOVER_ENTER:
case MotionEvent.ACTION_HOVER_MOVE:
- setHoveredVirtualViewId(virtualViewId);
- break;
case MotionEvent.ACTION_HOVER_EXIT:
setHoveredVirtualViewId(virtualViewId);
break;
@@ -164,95 +156,113 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate
public void notifyScrolledEvent(int viewId)
{
- sendEventForVirtualViewId(viewId, AccessibilityEvent.TYPE_VIEW_SCROLLED);
+ QtNative.runAction(() -> sendEventForVirtualViewId(viewId,
+ AccessibilityEvent.TYPE_VIEW_SCROLLED));
}
public void notifyLocationChange(int viewId)
{
- if (m_focusedVirtualViewId == viewId)
- invalidateVirtualViewId(m_focusedVirtualViewId);
+ QtNative.runAction(() -> {
+ if (m_focusedVirtualViewId == viewId)
+ invalidateVirtualViewId(m_focusedVirtualViewId);
+ });
}
public void notifyObjectHide(int viewId, int parentId)
{
- // If the object had accessibility focus, we need to clear it.
- // Note: This code is mostly copied from
- // AccessibilityNodeProvider::performAction, but we remove the
- // focus only if the focused view id matches the one that was hidden.
- if (m_focusedVirtualViewId == viewId) {
- m_focusedVirtualViewId = INVALID_ID;
- m_view.invalidate();
- sendEventForVirtualViewId(viewId,
- AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
- }
- // When the object is hidden, we need to notify its parent about
- // content change, not the hidden object itself
- invalidateVirtualViewId(parentId);
+ QtNative.runAction(() -> {
+ // If the object had accessibility focus, we need to clear it.
+ // Note: This code is mostly copied from
+ // AccessibilityNodeProvider::performAction, but we remove the
+ // focus only if the focused view id matches the one that was hidden.
+ if (m_focusedVirtualViewId == viewId) {
+ m_focusedVirtualViewId = INVALID_ID;
+ m_view.invalidate();
+ sendEventForVirtualViewId(viewId,
+ AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
+ }
+ // When the object is hidden, we need to notify its parent about
+ // content change, not the hidden object itself
+ invalidateVirtualViewId(parentId);
+ });
+ }
+
+ public void notifyObjectShow(int parentId)
+ {
+ QtNative.runAction(() -> {
+ // When the object is shown, we need to notify its parent about
+ // content change, not the shown object itself
+ invalidateVirtualViewId(parentId);
+ });
}
public void notifyObjectFocus(int viewId)
{
- if (m_view == null)
- return;
- m_focusedVirtualViewId = viewId;
- m_view.invalidate();
- sendEventForVirtualViewId(viewId,
- AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
+ QtNative.runAction(() -> {
+ if (m_view == null)
+ return;
+ m_focusedVirtualViewId = viewId;
+ m_view.invalidate();
+ sendEventForVirtualViewId(viewId,
+ AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
+ });
}
public void notifyValueChanged(int viewId, String value)
{
- // Send a TYPE_ANNOUNCEMENT event with the new value
+ QtNative.runAction(() -> {
+ // Send a TYPE_ANNOUNCEMENT event with the new value
- if ((viewId == INVALID_ID) || !m_manager.isEnabled()) {
- Log.w(TAG, "notifyValueChanged() for invalid view");
- return;
- }
+ if ((viewId == INVALID_ID) || !m_manager.isEnabled()) {
+ Log.w(TAG, "notifyValueChanged() for invalid view");
+ return;
+ }
- final ViewGroup group = (ViewGroup)m_view.getParent();
- if (group == null) {
- Log.w(TAG, "Could not announce value because ViewGroup was null.");
- return;
- }
+ final ViewGroup group = (ViewGroup) m_view.getParent();
+ if (group == null) {
+ Log.w(TAG, "Could not announce value because ViewGroup was null.");
+ return;
+ }
- final AccessibilityEvent event =
- AccessibilityEvent.obtain(AccessibilityEvent.TYPE_ANNOUNCEMENT);
+ final AccessibilityEvent event =
+ AccessibilityEvent.obtain(AccessibilityEvent.TYPE_ANNOUNCEMENT);
- event.setEnabled(true);
- event.setClassName(m_view.getClass().getName() + DEFAULT_CLASS_NAME);
+ event.setEnabled(true);
+ event.setClassName(m_view.getClass().getName() + DEFAULT_CLASS_NAME);
- event.setContentDescription(value);
+ event.setContentDescription(value);
- if (event.getText().isEmpty() && TextUtils.isEmpty(event.getContentDescription())) {
- Log.w(TAG, "No value to announce for " + event.getClassName());
- return;
- }
+ if (event.getText().isEmpty() && TextUtils.isEmpty(event.getContentDescription())) {
+ Log.w(TAG, "No value to announce for " + event.getClassName());
+ return;
+ }
- event.setPackageName(m_view.getContext().getPackageName());
- event.setSource(m_view, viewId);
+ event.setPackageName(m_view.getContext().getPackageName());
+ event.setSource(m_view, viewId);
- if (!group.requestSendAccessibilityEvent(m_view, event))
- Log.w(TAG, "Failed to send value change announcement for " + event.getClassName());
+ if (!group.requestSendAccessibilityEvent(m_view, event))
+ Log.w(TAG, "Failed to send value change announcement for " + event.getClassName());
+ });
}
- public boolean sendEventForVirtualViewId(int virtualViewId, int eventType)
+ public void sendEventForVirtualViewId(int virtualViewId, int eventType)
{
final AccessibilityEvent event = getEventForVirtualViewId(virtualViewId, eventType);
- return sendAccessibilityEvent(event);
+ sendAccessibilityEvent(event);
}
- public boolean sendAccessibilityEvent(AccessibilityEvent event)
+ public void sendAccessibilityEvent(AccessibilityEvent event)
{
if (event == null)
- return false;
+ return;
final ViewGroup group = (ViewGroup) m_view.getParent();
if (group == null) {
Log.w(TAG, "Could not send AccessibilityEvent because group was null. This should really not happen.");
- return false;
+ return;
}
- return group.requestSendAccessibilityEvent(m_view, event);
+ group.requestSendAccessibilityEvent(m_view, event);
}
public void invalidateVirtualViewId(int virtualViewId)
@@ -285,7 +295,7 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate
return null;
}
- if (m_activityDelegate.getSurfaceCount() == 0)
+ if (m_layout.getChildCount() == 0)
return null;
final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
@@ -302,15 +312,17 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate
return event;
}
+ // This can be used for debug by performActionForVirtualViewId()
+ /** @noinspection unused*/
private void dumpNodes(int parentId)
{
Log.i(TAG, "A11Y hierarchy: " + parentId + " parent: " + QtNativeAccessibility.parentId(parentId));
Log.i(TAG, " desc: " + QtNativeAccessibility.descriptionForAccessibleObject(parentId) + " rect: " + QtNativeAccessibility.screenRect(parentId));
Log.i(TAG, " NODE: " + getNodeForVirtualViewId(parentId));
int[] ids = QtNativeAccessibility.childIdListForAccessibleObject(parentId);
- for (int i = 0; i < ids.length; ++i) {
- Log.i(TAG, parentId + " has child: " + ids[i]);
- dumpNodes(ids[i]);
+ for (int id : ids) {
+ Log.i(TAG, parentId + " has child: " + id);
+ dumpNodes(id);
}
}
@@ -347,13 +359,13 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate
result.setPackageName(source.getPackageName());
result.setClassName(source.getClassName());
-// Spit out the entire hierarchy for debugging purposes
-// dumpNodes(-1);
+ // Spit out the entire hierarchy for debugging purposes
+ // dumpNodes(-1);
- if (m_activityDelegate.getSurfaceCount() != 0) {
+ if (m_layout.getChildCount() != 0) {
int[] ids = QtNativeAccessibility.childIdListForAccessibleObject(-1);
- for (int i = 0; i < ids.length; ++i)
- result.addChild(m_view, ids[i]);
+ for (int id : ids)
+ result.addChild(m_view, id);
}
// The offset values have changed, so we need to re-focus the
@@ -382,7 +394,7 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate
node.setClassName(m_view.getClass().getName() + DEFAULT_CLASS_NAME);
node.setPackageName(m_view.getContext().getPackageName());
- if (m_activityDelegate.getSurfaceCount() == 0 || !QtNativeAccessibility.populateNode(virtualViewId, node)) {
+ if (m_layout.getChildCount() == 0 || !QtNativeAccessibility.populateNode(virtualViewId, node)) {
return node;
}
@@ -401,23 +413,22 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate
screenRect.offset(offsetX, offsetY);
node.setBoundsInScreen(screenRect);
- Rect rectInParent = screenRect;
Rect parentScreenRect = QtNativeAccessibility.screenRect(parentId);
- rectInParent.offset(-parentScreenRect.left, -parentScreenRect.top);
- node.setBoundsInParent(rectInParent);
+ screenRect.offset(-parentScreenRect.left, -parentScreenRect.top);
+ node.setBoundsInParent(screenRect);
// Manage internal accessibility focus state.
if (m_focusedVirtualViewId == virtualViewId) {
node.setAccessibilityFocused(true);
- node.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
+ node.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
} else {
node.setAccessibilityFocused(false);
- node.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
+ node.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS);
}
int[] ids = QtNativeAccessibility.childIdListForAccessibleObject(virtualViewId);
- for (int i = 0; i < ids.length; ++i)
- node.addChild(m_view, ids[i]);
+ for (int id : ids)
+ node.addChild(m_view, id);
if (node.isScrollable()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
node.setCollectionInfo(new CollectionInfo(ids.length, 1, false));
@@ -429,12 +440,12 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate
return node;
}
- private AccessibilityNodeProvider m_nodeProvider = new AccessibilityNodeProvider()
+ private final AccessibilityNodeProvider m_nodeProvider = new AccessibilityNodeProvider()
{
@Override
public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId)
{
- if (virtualViewId == View.NO_ID || m_activityDelegate.getSurfaceCount() == 0) {
+ if (virtualViewId == View.NO_ID || m_layout.getChildCount() == 0) {
return getNodeForView();
}
return getNodeForVirtualViewId(virtualViewId);
@@ -476,16 +487,19 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate
return m_view.performAccessibilityAction(action, arguments);
}
}
- handled |= performActionForVirtualViewId(virtualViewId, action, arguments);
+ handled |= performActionForVirtualViewId(virtualViewId, action);
return handled;
}
};
- protected boolean performActionForVirtualViewId(int virtualViewId, int action, Bundle arguments)
+ protected boolean performActionForVirtualViewId(int virtualViewId, int action)
{
-// Log.i(TAG, "ACTION " + action + " on " + virtualViewId);
-// dumpNodes(virtualViewId);
+ //noinspection CommentedOutCode
+ {
+ // Log.i(TAG, "ACTION " + action + " on " + virtualViewId);
+ // dumpNodes(virtualViewId);
+ }
boolean success = false;
switch (action) {
case AccessibilityNodeInfo.ACTION_CLICK:
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtActivityBase.java b/src/android/jar/src/org/qtproject/qt/android/QtActivityBase.java
new file mode 100644
index 0000000000..3cb6ba220e
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityBase.java
@@ -0,0 +1,325 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.provider.Browser;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.Window;
+
+public class QtActivityBase extends Activity
+{
+ private String m_applicationParams = "";
+ private boolean m_isCustomThemeSet = false;
+ private boolean m_retainNonConfigurationInstance = false;
+
+ private QtActivityDelegate m_delegate;
+
+ public static final String EXTRA_SOURCE_INFO = "org.qtproject.qt.android.sourceInfo";
+
+ private void addReferrer(Intent intent)
+ {
+ if (intent.getExtras() != null && intent.getExtras().getString(EXTRA_SOURCE_INFO) != null)
+ return;
+
+ String browserApplicationId = "";
+ if (intent.getExtras() != null)
+ browserApplicationId = intent.getExtras().getString(Browser.EXTRA_APPLICATION_ID);
+
+ String sourceInformation = "";
+ if (browserApplicationId != null && !browserApplicationId.isEmpty()) {
+ sourceInformation = browserApplicationId;
+ } else {
+ Uri referrer = getReferrer();
+ if (referrer != null)
+ sourceInformation = referrer.toString().replaceFirst("android-app://", "");
+ }
+
+ intent.putExtra(EXTRA_SOURCE_INFO, sourceInformation);
+ }
+
+ // Append any parameters to your application.
+ // Either a whitespace or a tab is accepted as a separator between parameters.
+ /** @noinspection unused*/
+ public void appendApplicationParameters(String params)
+ {
+ if (params == null || params.isEmpty())
+ return;
+
+ if (!m_applicationParams.isEmpty())
+ m_applicationParams += " ";
+ m_applicationParams += params;
+ }
+
+ private void handleActivityRestart() {
+ if (QtNative.getStateDetails().isStarted) {
+ boolean updated = m_delegate.updateActivityAfterRestart(this);
+ if (!updated) {
+ // could not update the activity so restart the application
+ Intent intent = Intent.makeRestartActivityTask(getComponentName());
+ startActivity(intent);
+ QtNative.quitApp();
+ Runtime.getRuntime().exit(0);
+ }
+ }
+ }
+
+ @Override
+ public void setTheme(int resId) {
+ super.setTheme(resId);
+ m_isCustomThemeSet = true;
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ requestWindowFeature(Window.FEATURE_ACTION_BAR);
+
+ if (!m_isCustomThemeSet) {
+ setTheme(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ?
+ android.R.style.Theme_DeviceDefault_DayNight :
+ android.R.style.Theme_Holo_Light);
+ }
+
+ m_delegate = new QtActivityDelegate(this);
+
+ handleActivityRestart();
+ addReferrer(getIntent());
+
+ QtActivityLoader loader = new QtActivityLoader(this);
+ loader.appendApplicationParameters(m_applicationParams);
+
+ loader.loadQtLibraries();
+ m_delegate.startNativeApplication(loader.getApplicationParameters(),
+ loader.getMainLibraryPath());
+ }
+
+ @Override
+ protected void onStart()
+ {
+ super.onStart();
+ }
+
+ @Override
+ protected void onRestart()
+ {
+ super.onRestart();
+ }
+
+ @Override
+ protected void onPause()
+ {
+ super.onPause();
+ if (Build.VERSION.SDK_INT < 24 || !isInMultiWindowMode())
+ QtNative.setApplicationState(QtNative.ApplicationState.ApplicationInactive);
+ m_delegate.displayManager().unregisterDisplayListener();
+ }
+
+ @Override
+ protected void onResume()
+ {
+ super.onResume();
+ QtNative.setApplicationState(QtNative.ApplicationState.ApplicationActive);
+ if (QtNative.getStateDetails().isStarted) {
+ m_delegate.displayManager().registerDisplayListener();
+ QtNative.updateWindow();
+ // Suspending the app clears the immersive mode, so we need to set it again.
+ m_delegate.displayManager().updateFullScreen();
+ }
+ }
+
+ @Override
+ protected void onStop()
+ {
+ super.onStop();
+ QtNative.setApplicationState(QtNative.ApplicationState.ApplicationSuspended);
+ }
+
+ @Override
+ protected void onDestroy()
+ {
+ super.onDestroy();
+ if (!m_retainNonConfigurationInstance) {
+ QtNative.terminateQt();
+ QtNative.setActivity(null);
+ QtNative.getQtThread().exit();
+ System.exit(0);
+ }
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig)
+ {
+ super.onConfigurationChanged(newConfig);
+ m_delegate.handleUiModeChange(newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK);
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item)
+ {
+ m_delegate.setContextMenuVisible(false);
+ return QtNative.onContextItemSelected(item.getItemId(), item.isChecked());
+ }
+
+ @Override
+ public void onContextMenuClosed(Menu menu)
+ {
+ if (!m_delegate.isContextMenuVisible())
+ return;
+ m_delegate.setContextMenuVisible(false);
+ QtNative.onContextMenuClosed(menu);
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
+ {
+ menu.clearHeader();
+ QtNative.onCreateContextMenu(menu);
+ m_delegate.setContextMenuVisible(true);
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event)
+ {
+ boolean handleResult = m_delegate.getInputDelegate().handleDispatchKeyEvent(event);
+ if (QtNative.getStateDetails().isStarted && handleResult)
+ return true;
+
+ return super.dispatchKeyEvent(event);
+ }
+
+ @Override
+ public boolean dispatchGenericMotionEvent(MotionEvent event)
+ {
+ boolean handled = m_delegate.getInputDelegate().handleDispatchGenericMotionEvent(event);
+ if (QtNative.getStateDetails().isStarted && handled)
+ return true;
+
+ return super.dispatchGenericMotionEvent(event);
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event)
+ {
+ QtNative.ApplicationStateDetails stateDetails = QtNative.getStateDetails();
+ if (!stateDetails.isStarted || !stateDetails.nativePluginIntegrationReady)
+ return false;
+
+ return m_delegate.getInputDelegate().onKeyDown(keyCode, event);
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event)
+ {
+ QtNative.ApplicationStateDetails stateDetails = QtNative.getStateDetails();
+ if (!stateDetails.isStarted || !stateDetails.nativePluginIntegrationReady)
+ return false;
+
+ return m_delegate.getInputDelegate().onKeyUp(keyCode, event);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu)
+ {
+ menu.clear();
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu)
+ {
+ boolean res = QtNative.onPrepareOptionsMenu(menu);
+ m_delegate.setActionBarVisibility(res && menu.size() > 0);
+ return res;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item)
+ {
+ return QtNative.onOptionsItemSelected(item.getItemId(), item.isChecked());
+ }
+
+ @Override
+ public void onOptionsMenuClosed(Menu menu)
+ {
+ QtNative.onOptionsMenuClosed(menu);
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle savedInstanceState)
+ {
+ super.onRestoreInstanceState(savedInstanceState);
+ QtNative.setStarted(savedInstanceState.getBoolean("Started"));
+ int savedSystemUiVisibility = savedInstanceState.getInt("SystemUiVisibility");
+ m_delegate.displayManager().setSystemUiVisibility(savedSystemUiVisibility);
+ // FIXME restore all surfaces
+ }
+
+ @Override
+ public Object onRetainNonConfigurationInstance()
+ {
+ super.onRetainNonConfigurationInstance();
+ m_retainNonConfigurationInstance = true;
+ return true;
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState)
+ {
+ super.onSaveInstanceState(outState);
+ outState.putInt("SystemUiVisibility", m_delegate.displayManager().systemUiVisibility());
+ outState.putBoolean("Started", QtNative.getStateDetails().isStarted);
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus)
+ {
+ super.onWindowFocusChanged(hasFocus);
+ if (hasFocus)
+ m_delegate.displayManager().updateFullScreen();
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent)
+ {
+ QtNative.onNewIntent(intent);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data)
+ {
+ super.onActivityResult(requestCode, resultCode, data);
+ QtNative.onActivityResult(requestCode, resultCode, data);
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
+ {
+ QtNative.sendRequestPermissionsResult(requestCode, permissions, grantResults);
+ }
+
+ @UsedFromNativeCode
+ public void hideSplashScreen(final int duration)
+ {
+ m_delegate.hideSplashScreen(duration);
+ }
+
+ @UsedFromNativeCode
+ QtActivityDelegateBase getActivityDelegate()
+ {
+ return m_delegate;
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java
index 2a00975aee..1e1a36be3c 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java
@@ -1,817 +1,155 @@
// Copyright (C) 2017 BogDan Vatra <bogdan@kde.org>
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
package org.qtproject.qt.android;
import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.Rect;
-import android.net.LocalServerSocket;
-import android.net.LocalSocket;
import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.ResultReceiver;
-import android.text.method.MetaKeyKeyListener;
-import android.util.Base64;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
+import android.view.Display;
+import android.view.ViewTreeObserver;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.Display;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.Surface;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowInsetsController;
-import android.view.WindowManager;
-import android.view.inputmethod.InputMethodManager;
-import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.PopupMenu;
-import android.hardware.display.DisplayManager;
-import java.io.BufferedReader;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.InputStreamReader;
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
import java.util.HashMap;
-import java.util.Objects;
-import org.qtproject.qt.android.accessibility.QtAccessibilityDelegate;
-
-public class QtActivityDelegate
+class QtActivityDelegate extends QtActivityDelegateBase
{
- private Activity m_activity = null;
- private Method m_super_dispatchKeyEvent = null;
- private Method m_super_onRestoreInstanceState = null;
- private Method m_super_onRetainNonConfigurationInstance = null;
- private Method m_super_onSaveInstanceState = null;
- private Method m_super_onKeyDown = null;
- private Method m_super_onKeyUp = null;
- private Method m_super_onConfigurationChanged = null;
- private Method m_super_onActivityResult = null;
- private Method m_super_dispatchGenericMotionEvent = null;
- private Method m_super_onWindowFocusChanged = null;
-
- private static final String NATIVE_LIBRARIES_KEY = "native.libraries";
- private static final String BUNDLED_LIBRARIES_KEY = "bundled.libraries";
- private static final String MAIN_LIBRARY_KEY = "main.library";
- private static final String ENVIRONMENT_VARIABLES_KEY = "environment.variables";
- private static final String APPLICATION_PARAMETERS_KEY = "application.parameters";
- private static final String STATIC_INIT_CLASSES_KEY = "static.init.classes";
-
- public static final int SYSTEM_UI_VISIBILITY_NORMAL = 0;
- public static final int SYSTEM_UI_VISIBILITY_FULLSCREEN = 1;
- public static final int SYSTEM_UI_VISIBILITY_TRANSLUCENT = 2;
+ private static final String QtTAG = "QtActivityDelegate";
- private static String m_applicationParameters = null;
-
- private int m_currentRotation = -1; // undefined
- private int m_nativeOrientation = Configuration.ORIENTATION_UNDEFINED;
-
- private String m_mainLib;
- private long m_metaState;
- private int m_lastChar = 0;
- private int m_softInputMode = 0;
- private int m_systemUiVisibility = SYSTEM_UI_VISIBILITY_NORMAL;
- private boolean m_started = false;
- private HashMap<Integer, QtSurface> m_surfaces = null;
- private HashMap<Integer, View> m_nativeViews = null;
- private QtLayout m_layout = null;
+ private QtRootLayout m_layout = null;
private ImageView m_splashScreen = null;
private boolean m_splashScreenSticky = false;
- private QtEditText m_editText = null;
- private InputMethodManager m_imm = null;
- private boolean m_quitApp = true;
- private View m_dummyView = null;
- private boolean m_keyboardIsVisible = false;
- public boolean m_backKeyPressedSent = false;
- private long m_showHideTimeStamp = System.nanoTime();
- private int m_portraitKeyboardHeight = 0;
- private int m_landscapeKeyboardHeight = 0;
- private int m_probeKeyboardHeightDelay = 50; // ms
- private CursorHandle m_cursorHandle;
- private CursorHandle m_leftSelectionHandle;
- private CursorHandle m_rightSelectionHandle;
- private EditPopupMenu m_editPopupMenu;
- private boolean m_isPluginRunning = false;
- private QtAccessibilityDelegate m_accessibilityDelegate = null;
+ private View m_dummyView = null;
+ private HashMap<Integer, View> m_nativeViews = new HashMap<Integer, View>();
- public void setSystemUiVisibility(int systemUiVisibility)
+ QtActivityDelegate(Activity activity)
{
- if (m_systemUiVisibility == systemUiVisibility)
- return;
-
- m_systemUiVisibility = systemUiVisibility;
-
- int systemUiVisibilityFlags = 0;
- switch (m_systemUiVisibility) {
- case SYSTEM_UI_VISIBILITY_NORMAL:
- m_activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
- m_activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
- systemUiVisibilityFlags = View.SYSTEM_UI_FLAG_VISIBLE;
- break;
- case SYSTEM_UI_VISIBILITY_FULLSCREEN:
- m_activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
- m_activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
- systemUiVisibilityFlags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_FULLSCREEN
- | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
- | View.INVISIBLE;
- break;
- case SYSTEM_UI_VISIBILITY_TRANSLUCENT:
- m_activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
- | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
- | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
- m_activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
- systemUiVisibilityFlags = View.SYSTEM_UI_FLAG_VISIBLE;
- break;
- };
+ super(activity);
- m_activity.getWindow().getDecorView().setSystemUiVisibility(systemUiVisibilityFlags);
-
- m_layout.requestLayout();
+ setActionBarVisibility(false);
+ setActivityBackgroundDrawable();
}
- public void updateFullScreen()
- {
- if (m_systemUiVisibility == SYSTEM_UI_VISIBILITY_FULLSCREEN) {
- m_systemUiVisibility = SYSTEM_UI_VISIBILITY_NORMAL;
- setSystemUiVisibility(SYSTEM_UI_VISIBILITY_FULLSCREEN);
- }
- }
- public boolean isKeyboardVisible()
+ @UsedFromNativeCode
+ @Override
+ QtLayout getQtLayout()
{
- return m_keyboardIsVisible;
+ return m_layout;
}
- // input method hints - must be kept in sync with QTDIR/src/corelib/global/qnamespace.h
- private final int ImhHiddenText = 0x1;
- private final int ImhSensitiveData = 0x2;
- private final int ImhNoAutoUppercase = 0x4;
- private final int ImhPreferNumbers = 0x8;
- private final int ImhPreferUppercase = 0x10;
- private final int ImhPreferLowercase = 0x20;
- private final int ImhNoPredictiveText = 0x40;
-
- private final int ImhDate = 0x80;
- private final int ImhTime = 0x100;
-
- private final int ImhPreferLatin = 0x200;
-
- private final int ImhMultiLine = 0x400;
-
- private final int ImhDigitsOnly = 0x10000;
- private final int ImhFormattedNumbersOnly = 0x20000;
- private final int ImhUppercaseOnly = 0x40000;
- private final int ImhLowercaseOnly = 0x80000;
- private final int ImhDialableCharactersOnly = 0x100000;
- private final int ImhEmailCharactersOnly = 0x200000;
- private final int ImhUrlCharactersOnly = 0x400000;
- private final int ImhLatinOnly = 0x800000;
-
- // enter key type - must be kept in sync with QTDIR/src/corelib/global/qnamespace.h
- private final int EnterKeyDefault = 0;
- private final int EnterKeyReturn = 1;
- private final int EnterKeyDone = 2;
- private final int EnterKeyGo = 3;
- private final int EnterKeySend = 4;
- private final int EnterKeySearch = 5;
- private final int EnterKeyNext = 6;
- private final int EnterKeyPrevious = 7;
-
- // application state
- public static final int ApplicationSuspended = 0x0;
- public static final int ApplicationHidden = 0x1;
- public static final int ApplicationInactive = 0x2;
- public static final int ApplicationActive = 0x4;
-
-
- public boolean setKeyboardVisibility(boolean visibility, long timeStamp)
+ @UsedFromNativeCode
+ @Override
+ void setSystemUiVisibility(int systemUiVisibility)
{
- if (m_showHideTimeStamp > timeStamp)
- return false;
- m_showHideTimeStamp = timeStamp;
+ QtNative.runAction(() -> {
+ m_displayManager.setSystemUiVisibility(systemUiVisibility);
+ m_layout.requestLayout();
+ QtNative.updateWindow();
+ });
+ }
- if (m_keyboardIsVisible == visibility)
- return false;
- m_keyboardIsVisible = visibility;
- QtNative.keyboardVisibilityUpdated(m_keyboardIsVisible);
+ @Override
+ public boolean updateActivityAfterRestart(Activity activity) {
+ boolean updated = super.updateActivityAfterRestart(activity);
+ // TODO verify whether this is even needed, the last I checked the initMembers
+ // recreates the layout anyway
+ // update the new activity content view to old layout
+ ViewGroup layoutParent = (ViewGroup)m_layout.getParent();
+ if (layoutParent != null)
+ layoutParent.removeView(m_layout);
- if (visibility == false)
- updateFullScreen(); // Hiding the keyboard clears the immersive mode, so we need to set it again.
+ m_activity.setContentView(m_layout);
- return true;
- }
- public void resetSoftwareKeyboard()
- {
- if (m_imm == null)
- return;
- m_editText.postDelayed(new Runnable() {
- @Override
- public void run() {
- m_imm.restartInput(m_editText);
- m_editText.m_optionsChanged = false;
- }
- }, 5);
+ return updated;
}
- public void showSoftwareKeyboard(final int x, final int y, final int width, final int height, final int inputHints, final int enterKeyType)
+ @Override
+ void startNativeApplicationImpl(String appParams, String mainLib)
{
- if (m_imm == null)
- return;
-
- DisplayMetrics metrics = new DisplayMetrics();
- m_activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
-
- // If the screen is in portrait mode than we estimate that keyboard height will not be higher than 2/5 of the screen.
- // else than we estimate that keyboard height will not be higher than 2/3 of the screen
- final int visibleHeight;
- if (metrics.widthPixels < metrics.heightPixels)
- visibleHeight = m_portraitKeyboardHeight != 0 ? m_portraitKeyboardHeight : metrics.heightPixels * 3 / 5;
- else
- visibleHeight = m_landscapeKeyboardHeight != 0 ? m_landscapeKeyboardHeight : metrics.heightPixels / 3;
-
- if (m_softInputMode != 0) {
- m_activity.getWindow().setSoftInputMode(m_softInputMode);
- final boolean softInputIsHidden = (m_softInputMode & WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) != 0;
- if (softInputIsHidden)
- return;
- } else {
- if (height > visibleHeight)
- m_activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
- else
- m_activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
- }
-
- int initialCapsMode = 0;
-
- int imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
-
- switch (enterKeyType) {
- case EnterKeyReturn:
- imeOptions = android.view.inputmethod.EditorInfo.IME_FLAG_NO_ENTER_ACTION;
- break;
- case EnterKeyGo:
- imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_GO;
- break;
- case EnterKeySend:
- imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_SEND;
- break;
- case EnterKeySearch:
- imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_SEARCH;
- break;
- case EnterKeyNext:
- imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_NEXT;
- break;
- case EnterKeyPrevious:
- imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_PREVIOUS;
- break;
- }
-
- int inputType = android.text.InputType.TYPE_CLASS_TEXT;
-
- if ((inputHints & (ImhPreferNumbers | ImhDigitsOnly | ImhFormattedNumbersOnly)) != 0) {
- inputType = android.text.InputType.TYPE_CLASS_NUMBER;
- if ((inputHints & ImhFormattedNumbersOnly) != 0) {
- inputType |= (android.text.InputType.TYPE_NUMBER_FLAG_DECIMAL
- | android.text.InputType.TYPE_NUMBER_FLAG_SIGNED);
- }
-
- if ((inputHints & ImhHiddenText) != 0)
- inputType |= android.text.InputType.TYPE_NUMBER_VARIATION_PASSWORD;
- } else if ((inputHints & ImhDialableCharactersOnly) != 0) {
- inputType = android.text.InputType.TYPE_CLASS_PHONE;
- } else if ((inputHints & (ImhDate | ImhTime)) != 0) {
- inputType = android.text.InputType.TYPE_CLASS_DATETIME;
- if ((inputHints & (ImhDate | ImhTime)) != (ImhDate | ImhTime)) {
- if ((inputHints & ImhDate) != 0)
- inputType |= android.text.InputType.TYPE_DATETIME_VARIATION_DATE;
- else
- inputType |= android.text.InputType.TYPE_DATETIME_VARIATION_TIME;
- } // else { TYPE_DATETIME_VARIATION_NORMAL(0) }
- } else { // CLASS_TEXT
- if ((inputHints & ImhHiddenText) != 0) {
- inputType |= android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
- } else if ((inputHints & ImhSensitiveData) != 0 ||
- ((inputHints & ImhNoPredictiveText) != 0 &&
- System.getenv("QT_ANDROID_ENABLE_WORKAROUND_TO_DISABLE_PREDICTIVE_TEXT") != null)) {
- inputType |= android.text.InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
- } else if ((inputHints & ImhUrlCharactersOnly) != 0) {
- inputType |= android.text.InputType.TYPE_TEXT_VARIATION_URI;
- if (enterKeyType == 0) // not explicitly overridden
- imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_GO;
- } else if ((inputHints & ImhEmailCharactersOnly) != 0) {
- inputType |= android.text.InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
- }
-
- if ((inputHints & ImhMultiLine) != 0) {
- inputType |= android.text.InputType.TYPE_TEXT_FLAG_MULTI_LINE;
- // Clear imeOptions for Multi-Line Type
- // User should be able to insert new line in such case
- imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
- }
- if ((inputHints & (ImhNoPredictiveText | ImhSensitiveData | ImhHiddenText)) != 0)
- inputType |= android.text.InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
-
- if ((inputHints & ImhUppercaseOnly) != 0) {
- initialCapsMode |= android.text.TextUtils.CAP_MODE_CHARACTERS;
- inputType |= android.text.InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS;
- } else if ((inputHints & ImhLowercaseOnly) == 0 && (inputHints & ImhNoAutoUppercase) == 0) {
- initialCapsMode |= android.text.TextUtils.CAP_MODE_SENTENCES;
- inputType |= android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
- }
- }
-
- if (enterKeyType == 0 && (inputHints & ImhMultiLine) != 0)
- imeOptions = android.view.inputmethod.EditorInfo.IME_FLAG_NO_ENTER_ACTION;
-
- m_editText.setInitialCapsMode(initialCapsMode);
- m_editText.setImeOptions(imeOptions);
- m_editText.setInputType(inputType);
-
- m_layout.setLayoutParams(m_editText, new QtLayout.LayoutParams(width, height, x, y), false);
- m_editText.requestFocus();
- m_editText.postDelayed(new Runnable() {
- @Override
- public void run() {
- m_imm.showSoftInput(m_editText, 0, new ResultReceiver(new Handler()) {
+ m_layout.getViewTreeObserver().addOnGlobalLayoutListener(
+ new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- switch (resultCode) {
- case InputMethodManager.RESULT_SHOWN:
- QtNativeInputConnection.updateCursorPosition();
- //FALLTHROUGH
- case InputMethodManager.RESULT_UNCHANGED_SHOWN:
- setKeyboardVisibility(true, System.nanoTime());
- if (m_softInputMode == 0) {
- // probe for real keyboard height
- m_layout.postDelayed(new Runnable() {
- @Override
- public void run() {
- if (!m_keyboardIsVisible)
- return;
- DisplayMetrics metrics = new DisplayMetrics();
- m_activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
- Rect r = new Rect();
- m_activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
- if (metrics.heightPixels != r.bottom) {
- if (metrics.widthPixels > metrics.heightPixels) { // landscape
- if (m_landscapeKeyboardHeight != r.bottom) {
- m_landscapeKeyboardHeight = r.bottom;
- showSoftwareKeyboard(x, y, width, height, inputHints, enterKeyType);
- }
- } else {
- if (m_portraitKeyboardHeight != r.bottom) {
- m_portraitKeyboardHeight = r.bottom;
- showSoftwareKeyboard(x, y, width, height, inputHints, enterKeyType);
- }
- }
- } else {
- // no luck ?
- // maybe the delay was too short, so let's make it longer
- if (m_probeKeyboardHeightDelay < 1000)
- m_probeKeyboardHeightDelay *= 2;
- }
- }
- }, m_probeKeyboardHeightDelay);
- }
- break;
- case InputMethodManager.RESULT_HIDDEN:
- case InputMethodManager.RESULT_UNCHANGED_HIDDEN:
- setKeyboardVisibility(false, System.nanoTime());
- break;
- }
+ public void onGlobalLayout() {
+ QtNative.startApplication(appParams, mainLib);
+ m_layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
});
- if (m_editText.m_optionsChanged) {
- m_imm.restartInput(m_editText);
- m_editText.m_optionsChanged = false;
- }
- }
- }, 15);
}
- public void hideSoftwareKeyboard()
+ @Override
+ protected void setUpLayout()
{
- if (m_imm == null)
- return;
- m_imm.hideSoftInputFromWindow(m_editText.getWindowToken(), 0, new ResultReceiver(new Handler()) {
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- switch (resultCode) {
- case InputMethodManager.RESULT_SHOWN:
- case InputMethodManager.RESULT_UNCHANGED_SHOWN:
- setKeyboardVisibility(true, System.nanoTime());
- break;
- case InputMethodManager.RESULT_HIDDEN:
- case InputMethodManager.RESULT_UNCHANGED_HIDDEN:
- setKeyboardVisibility(false, System.nanoTime());
- break;
- }
- }
- });
- }
-
- int getAppIconSize(Activity a)
- {
- int size = a.getResources().getDimensionPixelSize(android.R.dimen.app_icon_size);
- if (size < 36 || size > 512) { // check size sanity
- DisplayMetrics metrics = new DisplayMetrics();
- a.getWindowManager().getDefaultDisplay().getMetrics(metrics);
- size = metrics.densityDpi / 10 * 3;
- if (size < 36)
- size = 36;
-
- if (size > 512)
- size = 512;
- }
-
- return size;
- }
-
- public void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd)
- {
- if (m_imm == null)
- return;
-
- m_imm.updateSelection(m_editText, selStart, selEnd, candidatesStart, candidatesEnd);
- }
-
- // Values coming from QAndroidInputContext::CursorHandleShowMode
- private static final int CursorHandleNotShown = 0;
- private static final int CursorHandleShowNormal = 1;
- private static final int CursorHandleShowSelection = 2;
- private static final int CursorHandleShowEdit = 0x100;
-
- public int getSelectHandleWidth()
- {
- int width = 0;
- if (m_leftSelectionHandle != null && m_rightSelectionHandle != null) {
- width = Math.max(m_leftSelectionHandle.width(), m_rightSelectionHandle.width());
- } else if (m_cursorHandle != null) {
- width = m_cursorHandle.width();
- }
- return width;
- }
-
- /* called from the C++ code when the position of the cursor or selection handles needs to
- be adjusted.
- mode is one of QAndroidInputContext::CursorHandleShowMode
- */
- public void updateHandles(int mode, int editX, int editY, int editButtons, int x1, int y1, int x2, int y2, boolean rtl)
- {
- switch (mode & 0xff)
- {
- case CursorHandleNotShown:
- if (m_cursorHandle != null) {
- m_cursorHandle.hide();
- m_cursorHandle = null;
- }
- if (m_rightSelectionHandle != null) {
- m_rightSelectionHandle.hide();
- m_leftSelectionHandle.hide();
- m_rightSelectionHandle = null;
- m_leftSelectionHandle = null;
- }
- if (m_editPopupMenu != null)
- m_editPopupMenu.hide();
- break;
-
- case CursorHandleShowNormal:
- if (m_cursorHandle == null) {
- m_cursorHandle = new CursorHandle(m_activity, m_layout, QtNative.IdCursorHandle,
- android.R.attr.textSelectHandle, false);
- }
- m_cursorHandle.setPosition(x1, y1);
- if (m_rightSelectionHandle != null) {
- m_rightSelectionHandle.hide();
- m_leftSelectionHandle.hide();
- m_rightSelectionHandle = null;
- m_leftSelectionHandle = null;
- }
- break;
-
- case CursorHandleShowSelection:
- if (m_rightSelectionHandle == null) {
- m_leftSelectionHandle = new CursorHandle(m_activity, m_layout, QtNative.IdLeftHandle,
- !rtl ? android.R.attr.textSelectHandleLeft :
- android.R.attr.textSelectHandleRight,
- rtl);
- m_rightSelectionHandle = new CursorHandle(m_activity, m_layout, QtNative.IdRightHandle,
- !rtl ? android.R.attr.textSelectHandleRight :
- android.R.attr.textSelectHandleLeft,
- rtl);
- }
- m_leftSelectionHandle.setPosition(x1,y1);
- m_rightSelectionHandle.setPosition(x2,y2);
- if (m_cursorHandle != null) {
- m_cursorHandle.hide();
- m_cursorHandle = null;
- }
- mode |= CursorHandleShowEdit;
- break;
- }
-
- if (!QtNative.hasClipboardText())
- editButtons &= ~EditContextView.PASTE_BUTTON;
-
- if ((mode & CursorHandleShowEdit) == CursorHandleShowEdit && editButtons != 0) {
- m_editPopupMenu.setPosition(editX, editY, editButtons, m_cursorHandle, m_leftSelectionHandle,
- m_rightSelectionHandle);
- } else {
- if (m_editPopupMenu != null)
- m_editPopupMenu.hide();
- }
- }
-
- private final DisplayManager.DisplayListener displayListener = new DisplayManager.DisplayListener()
- {
- @Override
- public void onDisplayAdded(int displayId) {
- QtNative.handleScreenAdded(displayId);
- }
-
- private boolean isSimilarRotation(int r1, int r2)
- {
- return (r1 == r2)
- || (r1 == Surface.ROTATION_0 && r2 == Surface.ROTATION_180)
- || (r1 == Surface.ROTATION_180 && r2 == Surface.ROTATION_0)
- || (r1 == Surface.ROTATION_90 && r2 == Surface.ROTATION_270)
- || (r1 == Surface.ROTATION_270 && r2 == Surface.ROTATION_90);
- }
-
- @Override
- public void onDisplayChanged(int displayId)
- {
- Display display = (Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
- ? m_activity.getWindowManager().getDefaultDisplay()
- : m_activity.getDisplay();
- m_currentRotation = display.getRotation();
- m_layout.setActivityDisplayRotation(m_currentRotation);
- // Process orientation change only if it comes after the size
- // change, or if the screen is rotated by 180 degrees.
- // Otherwise it will be processed in QtLayout.
- if (isSimilarRotation(m_currentRotation, m_layout.displayRotation()))
- QtNative.handleOrientationChanged(m_currentRotation, m_nativeOrientation);
-
- float refreshRate = display.getRefreshRate();
- QtNative.handleRefreshRateChanged(refreshRate);
- QtNative.handleScreenChanged(displayId);
- }
-
- @Override
- public void onDisplayRemoved(int displayId) {
- QtNative.handleScreenRemoved(displayId);
- }
- };
-
- public boolean updateActivity(Activity activity)
- {
- try {
- // set new activity
- loadActivity(activity);
-
- // update the new activity content view to old layout
- ViewGroup layoutParent = (ViewGroup)m_layout.getParent();
- if (layoutParent != null)
- layoutParent.removeView(m_layout);
-
- m_activity.setContentView(m_layout);
-
- // force c++ native activity object to update
- return QtNative.updateNativeActivity();
- } catch (Exception e) {
- Log.w(QtNative.QtTAG, "Failed to update the activity.");
- e.printStackTrace();
- return false;
- }
- }
-
- private void loadActivity(Activity activity)
- throws NoSuchMethodException, PackageManager.NameNotFoundException
- {
- m_activity = activity;
-
- QtNative.setActivity(m_activity, this);
- setActionBarVisibility(false);
-
- Class<?> activityClass = m_activity.getClass();
- m_super_dispatchKeyEvent =
- activityClass.getMethod("super_dispatchKeyEvent", KeyEvent.class);
- m_super_onRestoreInstanceState =
- activityClass.getMethod("super_onRestoreInstanceState", Bundle.class);
- m_super_onRetainNonConfigurationInstance =
- activityClass.getMethod("super_onRetainNonConfigurationInstance");
- m_super_onSaveInstanceState =
- activityClass.getMethod("super_onSaveInstanceState", Bundle.class);
- m_super_onKeyDown =
- activityClass.getMethod("super_onKeyDown", Integer.TYPE, KeyEvent.class);
- m_super_onKeyUp =
- activityClass.getMethod("super_onKeyUp", Integer.TYPE, KeyEvent.class);
- m_super_onConfigurationChanged =
- activityClass.getMethod("super_onConfigurationChanged", Configuration.class);
- m_super_onActivityResult =
- activityClass.getMethod("super_onActivityResult", Integer.TYPE, Integer.TYPE, Intent.class);
- m_super_onWindowFocusChanged =
- activityClass.getMethod("super_onWindowFocusChanged", Boolean.TYPE);
- m_super_dispatchGenericMotionEvent =
- activityClass.getMethod("super_dispatchGenericMotionEvent", MotionEvent.class);
-
- m_softInputMode = m_activity.getPackageManager().getActivityInfo(m_activity.getComponentName(), 0).softInputMode;
-
- DisplayManager displayManager = (DisplayManager)m_activity.getSystemService(Context.DISPLAY_SERVICE);
- displayManager.registerDisplayListener(displayListener, null);
- }
+ int orientation = m_activity.getResources().getConfiguration().orientation;
+ m_layout = new QtRootLayout(m_activity);
- public boolean loadApplication(Activity activity, ClassLoader classLoader, Bundle loaderParams)
- {
- /// check parameters integrity
- if (!loaderParams.containsKey(NATIVE_LIBRARIES_KEY)
- || !loaderParams.containsKey(BUNDLED_LIBRARIES_KEY)
- || !loaderParams.containsKey(ENVIRONMENT_VARIABLES_KEY)) {
- return false;
- }
+ setUpSplashScreen(orientation);
+ m_activity.registerForContextMenu(m_layout);
+ m_activity.setContentView(m_layout,
+ new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ QtDisplayManager.handleOrientationChanges(m_activity);
- try {
- loadActivity(activity);
- QtNative.setClassLoader(classLoader);
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
+ handleUiModeChange(m_activity.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK);
- if (loaderParams.containsKey(STATIC_INIT_CLASSES_KEY)) {
- for (String className: Objects.requireNonNull(loaderParams.getStringArray(STATIC_INIT_CLASSES_KEY))) {
- if (className.length() == 0)
- continue;
+ Display display = (Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
+ ? m_activity.getWindowManager().getDefaultDisplay()
+ : m_activity.getDisplay();
+ QtDisplayManager.handleRefreshRateChanged(QtDisplayManager.getRefreshRate(display));
- try {
- Class<?> initClass = classLoader.loadClass(className);
- Object staticInitDataObject = initClass.newInstance(); // create an instance
- try {
- Method m = initClass.getMethod("setActivity", Activity.class, Object.class);
- m.invoke(staticInitDataObject, m_activity, this);
- } catch (Exception e) {
- Log.d(QtNative.QtTAG, "Class " + className + " does not implement setActivity method");
- }
+ m_layout.getViewTreeObserver().addOnPreDrawListener(() -> {
+ if (!m_inputDelegate.isKeyboardVisible())
+ return true;
- // For modules that don't need/have setActivity
- try {
- Method m = initClass.getMethod("setContext", Context.class);
- m.invoke(staticInitDataObject, (Context)m_activity);
- } catch (Exception e) {
- e.printStackTrace();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
+ Rect r = new Rect();
+ m_activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
+ DisplayMetrics metrics = new DisplayMetrics();
+ m_activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ final int kbHeight = metrics.heightPixels - r.bottom;
+ if (kbHeight < 0) {
+ m_inputDelegate.setKeyboardVisibility(false, System.nanoTime());
+ return true;
}
- }
- QtNative.loadQtLibraries(loaderParams.getStringArrayList(NATIVE_LIBRARIES_KEY));
- ArrayList<String> libraries = loaderParams.getStringArrayList(BUNDLED_LIBRARIES_KEY);
- String nativeLibsDir = QtNativeLibrariesDir.nativeLibrariesDir(m_activity);
- QtNative.loadBundledLibraries(libraries, nativeLibsDir);
- m_mainLib = loaderParams.getString(MAIN_LIBRARY_KEY);
- // older apps provide the main library as the last bundled library; look for this if the main library isn't provided
- if (null == m_mainLib && libraries.size() > 0) {
- m_mainLib = libraries.get(libraries.size() - 1);
- libraries.remove(libraries.size() - 1);
- }
-
- ExtractStyle.setup(loaderParams);
- ExtractStyle.runIfNeeded(m_activity, isUiModeDark(m_activity.getResources().getConfiguration()));
-
- QtNative.setEnvironmentVariables(loaderParams.getString(ENVIRONMENT_VARIABLES_KEY));
- QtNative.setEnvironmentVariable("QT_ANDROID_FONTS_MONOSPACE",
- "Droid Sans Mono;Droid Sans;Droid Sans Fallback");
- QtNative.setEnvironmentVariable("QT_ANDROID_FONTS_SERIF", "Droid Serif");
- QtNative.setEnvironmentVariable("HOME", m_activity.getFilesDir().getAbsolutePath());
- QtNative.setEnvironmentVariable("TMPDIR", m_activity.getCacheDir().getAbsolutePath());
- QtNative.setEnvironmentVariable("QT_ANDROID_FONTS",
- "Roboto;Droid Sans;Droid Sans Fallback");
- QtNative.setEnvironmentVariable("QT_ANDROID_APP_ICON_SIZE",
- String.valueOf(getAppIconSize(activity)));
-
- if (loaderParams.containsKey(APPLICATION_PARAMETERS_KEY))
- m_applicationParameters = loaderParams.getString(APPLICATION_PARAMETERS_KEY);
- else
- m_applicationParameters = "";
-
- m_mainLib = QtNative.loadMainLibrary(m_mainLib, nativeLibsDir);
- return m_mainLib != null;
- }
-
- public boolean startApplication()
- {
- // start application
- try {
-
- Bundle extras = m_activity.getIntent().getExtras();
- if (extras != null) {
- try {
- final boolean isDebuggable = (m_activity.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
- if (!isDebuggable)
- throw new Exception();
-
- if (extras.containsKey("extraenvvars")) {
- try {
- QtNative.setEnvironmentVariables(new String(
- Base64.decode(extras.getString("extraenvvars"), Base64.DEFAULT),
- "UTF-8"));
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- if (extras.containsKey("extraappparams")) {
- try {
- m_applicationParameters += "\t" + new String(Base64.decode(extras.getString("extraappparams"), Base64.DEFAULT), "UTF-8");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- } catch (Exception e) {
- Log.e(QtNative.QtTAG, "Not in debug mode! It is not allowed to use " +
- "extra arguments in non-debug mode.");
- // This is not an error, so keep it silent
- // e.printStackTrace();
- }
- } // extras != null
-
- if (null == m_surfaces)
- onCreate(null);
+ final int[] location = new int[2];
+ m_layout.getLocationOnScreen(location);
+ QtInputDelegate.keyboardGeometryChanged(location[0], r.bottom - location[1],
+ r.width(), kbHeight);
return true;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
-
- public void onTerminate()
- {
- QtNative.terminateQt();
- QtNative.m_qtThread.exit();
+ });
+ registerGlobalFocusChangeListener(m_layout);
+ m_inputDelegate.setEditPopupMenu(new EditPopupMenu(m_activity, m_layout));
}
- public void onCreate(Bundle savedInstanceState)
+ @Override
+ protected void setUpSplashScreen(int orientation)
{
- m_quitApp = true;
- Runnable startApplication = null;
- if (null == savedInstanceState) {
- startApplication = new Runnable() {
- @Override
- public void run() {
- try {
- QtNative.startApplication(m_applicationParameters, m_mainLib);
- m_started = true;
- } catch (Exception e) {
- e.printStackTrace();
- m_activity.finish();
- }
- }
- };
- }
- m_layout = new QtLayout(m_activity, startApplication);
-
- int orientation = m_activity.getResources().getConfiguration().orientation;
-
try {
- ActivityInfo info = m_activity.getPackageManager().getActivityInfo(m_activity.getComponentName(), PackageManager.GET_META_DATA);
+ ActivityInfo info = m_activity.getPackageManager().getActivityInfo(
+ m_activity.getComponentName(),
+ PackageManager.GET_META_DATA);
String splashScreenKey = "android.app.splash_screen_drawable_"
+ (orientation == Configuration.ORIENTATION_LANDSCAPE ? "landscape" : "portrait");
@@ -819,402 +157,86 @@ public class QtActivityDelegate
splashScreenKey = "android.app.splash_screen_drawable";
if (info.metaData.containsKey(splashScreenKey)) {
- m_splashScreenSticky = info.metaData.containsKey("android.app.splash_screen_sticky") && info.metaData.getBoolean("android.app.splash_screen_sticky");
+ m_splashScreenSticky =
+ info.metaData.containsKey("android.app.splash_screen_sticky") &&
+ info.metaData.getBoolean("android.app.splash_screen_sticky");
+
int id = info.metaData.getInt(splashScreenKey);
m_splashScreen = new ImageView(m_activity);
- m_splashScreen.setImageDrawable(m_activity.getResources().getDrawable(id, m_activity.getTheme()));
+ m_splashScreen.setImageDrawable(m_activity.getResources().getDrawable(
+ id, m_activity.getTheme()));
m_splashScreen.setScaleType(ImageView.ScaleType.FIT_XY);
- m_splashScreen.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+ m_splashScreen.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
m_layout.addView(m_splashScreen);
}
} catch (Exception e) {
e.printStackTrace();
}
-
- m_editText = new QtEditText(m_activity, this);
- m_imm = (InputMethodManager)m_activity.getSystemService(Context.INPUT_METHOD_SERVICE);
- m_surfaces = new HashMap<Integer, QtSurface>();
- m_nativeViews = new HashMap<Integer, View>();
- m_activity.registerForContextMenu(m_layout);
- m_activity.setContentView(m_layout,
- new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- int rotation = m_activity.getWindowManager().getDefaultDisplay().getRotation();
- boolean rot90 = (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270);
- boolean currentlyLandscape = (orientation == Configuration.ORIENTATION_LANDSCAPE);
- if ((currentlyLandscape && !rot90) || (!currentlyLandscape && rot90))
- m_nativeOrientation = Configuration.ORIENTATION_LANDSCAPE;
- else
- m_nativeOrientation = Configuration.ORIENTATION_PORTRAIT;
-
- m_layout.setNativeOrientation(m_nativeOrientation);
- QtNative.handleOrientationChanged(rotation, m_nativeOrientation);
- m_currentRotation = rotation;
-
- handleUiModeChange(m_activity.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK);
-
- float refreshRate = (Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
- ? m_activity.getWindowManager().getDefaultDisplay().getRefreshRate()
- : m_activity.getDisplay().getRefreshRate();
- QtNative.handleRefreshRateChanged(refreshRate);
-
- m_layout.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- if (!m_keyboardIsVisible)
- return true;
-
- Rect r = new Rect();
- m_activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
- DisplayMetrics metrics = new DisplayMetrics();
- m_activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
- final int kbHeight = metrics.heightPixels - r.bottom;
- if (kbHeight < 0) {
- setKeyboardVisibility(false, System.nanoTime());
- return true;
- }
- final int[] location = new int[2];
- m_layout.getLocationOnScreen(location);
- QtNative.keyboardGeometryChanged(location[0], r.bottom - location[1],
- r.width(), kbHeight);
- return true;
- }
- });
- m_editPopupMenu = new EditPopupMenu(m_activity, m_layout);
}
- public void hideSplashScreen()
+ @Override
+ protected void hideSplashScreen(final int duration)
{
- hideSplashScreen(0);
- }
+ QtNative.runAction(() -> {
+ if (m_splashScreen == null)
+ return;
- public void hideSplashScreen(final int duration)
- {
- if (m_splashScreen == null)
- return;
+ if (duration <= 0) {
+ m_layout.removeView(m_splashScreen);
+ m_splashScreen = null;
+ return;
+ }
- if (duration <= 0) {
- m_layout.removeView(m_splashScreen);
- m_splashScreen = null;
- return;
- }
+ final Animation fadeOut = new AlphaAnimation(1, 0);
+ fadeOut.setInterpolator(new AccelerateInterpolator());
+ fadeOut.setDuration(duration);
- final Animation fadeOut = new AlphaAnimation(1, 0);
- fadeOut.setInterpolator(new AccelerateInterpolator());
- fadeOut.setDuration(duration);
+ fadeOut.setAnimationListener(new Animation.AnimationListener() {
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ hideSplashScreen(0);
+ }
- fadeOut.setAnimationListener(new Animation.AnimationListener() {
- @Override
- public void onAnimationEnd(Animation animation) { hideSplashScreen(0); }
+ @Override
+ public void onAnimationRepeat(Animation animation) {
+ }
- @Override
- public void onAnimationRepeat(Animation animation) {}
+ @Override
+ public void onAnimationStart(Animation animation) {
+ }
+ });
- @Override
- public void onAnimationStart(Animation animation) {}
+ m_splashScreen.startAnimation(fadeOut);
});
-
- m_splashScreen.startAnimation(fadeOut);
- }
-
- public void notifyAccessibilityLocationChange(int viewId)
- {
- if (m_accessibilityDelegate == null)
- return;
- m_accessibilityDelegate.notifyLocationChange(viewId);
- }
-
- public void notifyObjectHide(int viewId, int parentId)
- {
- if (m_accessibilityDelegate == null)
- return;
- m_accessibilityDelegate.notifyObjectHide(viewId, parentId);
- }
-
- public void notifyObjectFocus(int viewId)
- {
- if (m_accessibilityDelegate == null)
- return;
- m_accessibilityDelegate.notifyObjectFocus(viewId);
- }
-
- public void notifyValueChanged(int viewId, String value)
- {
- if (m_accessibilityDelegate == null)
- return;
- m_accessibilityDelegate.notifyValueChanged(viewId, value);
- }
-
- public void notifyScrolledEvent(int viewId)
- {
- if (m_accessibilityDelegate == null)
- return;
- m_accessibilityDelegate.notifyScrolledEvent(viewId);
- }
-
-
- public void notifyQtAndroidPluginRunning(boolean running)
- {
- m_isPluginRunning = running;
}
+ @UsedFromNativeCode
public void initializeAccessibility()
{
- m_accessibilityDelegate = new QtAccessibilityDelegate(m_activity, m_layout, this);
- }
-
- public void onWindowFocusChanged(boolean hasFocus) {
- try {
- m_super_onWindowFocusChanged.invoke(m_activity, hasFocus);
- } catch (Exception e) {
- e.printStackTrace();
- }
- if (hasFocus)
- updateFullScreen();
- }
-
- boolean isUiModeDark(Configuration config)
- {
- return (config.uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
- }
-
- private void handleUiModeChange(int uiMode)
- {
- // QTBUG-108365
- if (Build.VERSION.SDK_INT >= 30) {
- // Since 29 version we are using Theme_DeviceDefault_DayNight
- Window window = m_activity.getWindow();
- WindowInsetsController controller = window.getInsetsController();
- if (controller != null) {
- // set APPEARANCE_LIGHT_STATUS_BARS if needed
- int appearanceLight = Color.luminance(window.getStatusBarColor()) > 0.5 ?
- WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS : 0;
- controller.setSystemBarsAppearance(appearanceLight,
- WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS);
- }
- }
- switch (uiMode) {
- case Configuration.UI_MODE_NIGHT_NO:
- ExtractStyle.runIfNeeded(m_activity, false);
- QtNative.handleUiDarkModeChanged(0);
- break;
- case Configuration.UI_MODE_NIGHT_YES:
- ExtractStyle.runIfNeeded(m_activity, true);
- QtNative.handleUiDarkModeChanged(1);
- break;
- }
- }
-
- public void onConfigurationChanged(Configuration configuration)
- {
- try {
- m_super_onConfigurationChanged.invoke(m_activity, configuration);
- } catch (Exception e) {
- e.printStackTrace();
- }
- handleUiModeChange(configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK);
- }
-
- public void onDestroy()
- {
- if (m_quitApp) {
- QtNative.terminateQt();
- QtNative.setActivity(null, null);
- QtNative.m_qtThread.exit();
- System.exit(0);
- }
- }
-
- public void onPause()
- {
- if (Build.VERSION.SDK_INT < 24 || !m_activity.isInMultiWindowMode())
- QtNative.setApplicationState(ApplicationInactive);
- }
-
- public void onResume()
- {
- QtNative.setApplicationState(ApplicationActive);
- if (m_started) {
- QtNative.updateWindow();
- updateFullScreen(); // Suspending the app clears the immersive mode, so we need to set it again.
- }
- }
-
- public void onNewIntent(Intent data)
- {
- QtNative.onNewIntent(data);
- }
-
- public void onActivityResult(int requestCode, int resultCode, Intent data)
- {
- try {
- m_super_onActivityResult.invoke(m_activity, requestCode, resultCode, data);
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- QtNative.onActivityResult(requestCode, resultCode, data);
- }
-
-
- public void onStop()
- {
- QtNative.setApplicationState(ApplicationSuspended);
- }
-
- public Object onRetainNonConfigurationInstance()
- {
- try {
- m_super_onRetainNonConfigurationInstance.invoke(m_activity);
- } catch (Exception e) {
- e.printStackTrace();
- }
- m_quitApp = false;
- return true;
- }
-
- public void onSaveInstanceState(Bundle outState) {
- try {
- m_super_onSaveInstanceState.invoke(m_activity, outState);
- } catch (Exception e) {
- e.printStackTrace();
- }
- outState.putInt("SystemUiVisibility", m_systemUiVisibility);
- outState.putBoolean("Started", m_started);
- // It should never
- }
-
- public void onRestoreInstanceState(Bundle savedInstanceState)
- {
- try {
- m_super_onRestoreInstanceState.invoke(m_activity, savedInstanceState);
- } catch (Exception e) {
- e.printStackTrace();
- }
- m_started = savedInstanceState.getBoolean("Started");
- // FIXME restore all surfaces
-
- }
-
- public boolean onKeyDown(int keyCode, KeyEvent event)
- {
- if (!m_started || !m_isPluginRunning)
- return false;
-
- m_metaState = MetaKeyKeyListener.handleKeyDown(m_metaState, keyCode, event);
- int c = event.getUnicodeChar(MetaKeyKeyListener.getMetaState(m_metaState) | event.getMetaState());
- int lc = c;
- m_metaState = MetaKeyKeyListener.adjustMetaAfterKeypress(m_metaState);
-
- if ((c & KeyCharacterMap.COMBINING_ACCENT) != 0) {
- c = c & KeyCharacterMap.COMBINING_ACCENT_MASK;
- int composed = KeyEvent.getDeadChar(m_lastChar, c);
- c = composed;
- }
-
- if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP
- || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
- || keyCode == KeyEvent.KEYCODE_MUTE)
- && System.getenv("QT_ANDROID_VOLUME_KEYS") == null) {
- return false;
- }
-
- m_lastChar = lc;
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- m_backKeyPressedSent = !m_keyboardIsVisible;
- if (!m_backKeyPressedSent)
- return true;
- }
- QtNative.keyDown(keyCode, c, event.getMetaState(), event.getRepeatCount() > 0);
-
- return true;
- }
-
- public boolean onKeyUp(int keyCode, KeyEvent event)
- {
- if (!m_started || !m_isPluginRunning)
- return false;
-
- if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP
- || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
- || keyCode == KeyEvent.KEYCODE_MUTE)
- && System.getenv("QT_ANDROID_VOLUME_KEYS") == null) {
- return false;
- }
-
- if (keyCode == KeyEvent.KEYCODE_BACK && !m_backKeyPressedSent) {
- hideSoftwareKeyboard();
- setKeyboardVisibility(false, System.nanoTime());
- return true;
- }
-
- m_metaState = MetaKeyKeyListener.handleKeyUp(m_metaState, keyCode, event);
- QtNative.keyUp(keyCode, event.getUnicodeChar(), event.getMetaState(), event.getRepeatCount() > 0);
- return true;
- }
-
- public boolean dispatchKeyEvent(KeyEvent event)
- {
- if (m_started
- && event.getAction() == KeyEvent.ACTION_MULTIPLE
- && event.getCharacters() != null
- && event.getCharacters().length() == 1
- && event.getKeyCode() == 0) {
- QtNative.keyDown(0, event.getCharacters().charAt(0), event.getMetaState(), event.getRepeatCount() > 0);
- QtNative.keyUp(0, event.getCharacters().charAt(0), event.getMetaState(), event.getRepeatCount() > 0);
- }
-
- if (QtNative.dispatchKeyEvent(event))
- return true;
-
- try {
- return (Boolean) m_super_dispatchKeyEvent.invoke(m_activity, event);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return false;
- }
-
- private boolean m_optionsMenuIsVisible = false;
- public boolean onCreateOptionsMenu(Menu menu)
- {
- menu.clear();
- return true;
- }
- public boolean onPrepareOptionsMenu(Menu menu)
- {
- m_optionsMenuIsVisible = true;
- boolean res = QtNative.onPrepareOptionsMenu(menu);
- setActionBarVisibility(res && menu.size() > 0);
- return res;
- }
-
- public boolean onOptionsItemSelected(MenuItem item)
- {
- return QtNative.onOptionsItemSelected(item.getItemId(), item.isChecked());
+ QtNative.runAction(() -> {
+ // FIXME make QtAccessibilityDelegate window based
+ if (m_layout != null)
+ m_accessibilityDelegate = new QtAccessibilityDelegate(m_layout);
+ else
+ Log.w(QtTAG, "Null layout, failed to initialize accessibility delegate.");
+ });
}
- public void onOptionsMenuClosed(Menu menu)
+ @UsedFromNativeCode
+ public void resetOptionsMenu()
{
- m_optionsMenuIsVisible = false;
- QtNative.onOptionsMenuClosed(menu);
+ QtNative.runAction(() -> m_activity.invalidateOptionsMenu());
}
- public void resetOptionsMenu()
+ @UsedFromNativeCode
+ public void openOptionsMenu()
{
- m_activity.invalidateOptionsMenu();
+ QtNative.runAction(() -> m_activity.openOptionsMenu());
}
private boolean m_contextMenuVisible = false;
- public void onCreateContextMenu(ContextMenu menu,
- View v,
- ContextMenuInfo menuInfo)
- {
- menu.clearHeader();
- QtNative.onCreateContextMenu(menu);
- m_contextMenuVisible = true;
- }
public void onCreatePopupMenu(Menu menu)
{
@@ -1222,51 +244,35 @@ public class QtActivityDelegate
m_contextMenuVisible = true;
}
- public void onContextMenuClosed(Menu menu)
- {
- if (!m_contextMenuVisible)
- return;
- m_contextMenuVisible = false;
- QtNative.onContextMenuClosed(menu);
- }
-
- public boolean onContextItemSelected(MenuItem item)
- {
- m_contextMenuVisible = false;
- return QtNative.onContextItemSelected(item.getItemId(), item.isChecked());
- }
-
+ @UsedFromNativeCode
+ @Override
public void openContextMenu(final int x, final int y, final int w, final int h)
{
- m_layout.postDelayed(new Runnable() {
- @Override
- public void run() {
- m_layout.setLayoutParams(m_editText, new QtLayout.LayoutParams(w, h, x, y), false);
- PopupMenu popup = new PopupMenu(m_activity, m_editText);
- QtActivityDelegate.this.onCreatePopupMenu(popup.getMenu());
- popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
- @Override
- public boolean onMenuItemClick(MenuItem menuItem) {
- return QtActivityDelegate.this.onContextItemSelected(menuItem);
- }
- });
- popup.setOnDismissListener(new PopupMenu.OnDismissListener() {
- @Override
- public void onDismiss(PopupMenu popupMenu) {
- QtActivityDelegate.this.onContextMenuClosed(popupMenu.getMenu());
- }
- });
- popup.show();
- }
- }, 100);
- }
-
+ m_layout.postDelayed(() -> {
+ final QtEditText focusedEditText = m_inputDelegate.getCurrentQtEditText();
+ if (focusedEditText == null) {
+ Log.w(QtTAG, "No focused view when trying to open context menu");
+ return;
+ }
+ m_layout.setLayoutParams(focusedEditText, new QtLayout.LayoutParams(w, h, x, y), false);
+ PopupMenu popup = new PopupMenu(m_activity, focusedEditText);
+ QtActivityDelegate.this.onCreatePopupMenu(popup.getMenu());
+ popup.setOnMenuItemClickListener(menuItem ->
+ m_activity.onContextItemSelected(menuItem));
+ popup.setOnDismissListener(popupMenu ->
+ m_activity.onContextMenuClosed(popupMenu.getMenu()));
+ popup.show();
+ }, 100);
+ }
+
+ @UsedFromNativeCode
public void closeContextMenu()
{
- m_activity.closeContextMenu();
+ QtNative.runAction(() -> m_activity.closeContextMenu());
}
- private void setActionBarVisibility(boolean visible)
+ @Override
+ void setActionBarVisibility(boolean visible)
{
if (m_activity.getActionBar() == null)
return;
@@ -1276,149 +282,136 @@ public class QtActivityDelegate
m_activity.getActionBar().show();
}
- public void insertNativeView(int id, View view, int x, int y, int w, int h) {
- if (m_dummyView != null) {
- m_layout.removeView(m_dummyView);
- m_dummyView = null;
- }
-
- if (m_nativeViews.containsKey(id))
- m_layout.removeView(m_nativeViews.remove(id));
-
- if (w < 0 || h < 0) {
- view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
- } else {
- view.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
- }
-
- view.setId(id);
- m_layout.addView(view);
- m_nativeViews.put(id, view);
- }
+ @UsedFromNativeCode
+ @Override
+ public void addTopLevelWindow(final QtWindow window)
+ {
+ if (window == null)
+ return;
- public void createSurface(int id, boolean onTop, int x, int y, int w, int h, int imageDepth) {
- if (m_surfaces.size() == 0) {
- TypedValue attr = new TypedValue();
- m_activity.getTheme().resolveAttribute(android.R.attr.windowBackground, attr, true);
- if (attr.type >= TypedValue.TYPE_FIRST_COLOR_INT && attr.type <= TypedValue.TYPE_LAST_COLOR_INT) {
- m_activity.getWindow().setBackgroundDrawable(new ColorDrawable(attr.data));
- } else {
- m_activity.getWindow().setBackgroundDrawable(m_activity.getResources().getDrawable(attr.resourceId, m_activity.getTheme()));
- }
- if (m_dummyView != null) {
- m_layout.removeView(m_dummyView);
- m_dummyView = null;
+ QtNative.runAction(()-> {
+ if (m_topLevelWindows.size() == 0) {
+ if (m_dummyView != null) {
+ m_layout.removeView(m_dummyView);
+ m_dummyView = null;
+ }
}
- }
-
- if (m_surfaces.containsKey(id))
- m_layout.removeView(m_surfaces.remove(id));
-
- QtSurface surface = new QtSurface(m_activity, id, onTop, imageDepth);
- if (w < 0 || h < 0) {
- surface.setLayoutParams( new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
- } else {
- surface.setLayoutParams( new QtLayout.LayoutParams(w, h, x, y));
- }
- // Native views are always inserted in the end of the stack (i.e., on top).
- // All other views are stacked based on the order they are created.
- final int surfaceCount = getSurfaceCount();
- m_layout.addView(surface, surfaceCount);
+ window.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
- m_surfaces.put(id, surface);
- if (!m_splashScreenSticky)
- hideSplashScreen();
+ m_layout.addView(window, m_topLevelWindows.size());
+ m_topLevelWindows.put(window.getId(), window);
+ if (!m_splashScreenSticky)
+ hideSplashScreen();
+ });
}
- public void setSurfaceGeometry(int id, int x, int y, int w, int h) {
- if (m_surfaces.containsKey(id)) {
- QtSurface surface = m_surfaces.get(id);
- surface.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
- } else if (m_nativeViews.containsKey(id)) {
- View view = m_nativeViews.get(id);
- view.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
- } else {
- Log.e(QtNative.QtTAG, "Surface " + id +" not found!");
- return;
- }
+ @UsedFromNativeCode
+ @Override
+ void removeTopLevelWindow(final int id)
+ {
+ QtNative.runAction(()-> {
+ if (m_topLevelWindows.containsKey(id)) {
+ QtWindow window = m_topLevelWindows.remove(id);
+ if (m_topLevelWindows.isEmpty()) {
+ // Keep last frame in stack until it is replaced to get correct
+ // shutdown transition
+ m_dummyView = window;
+ } else {
+ m_layout.removeView(window);
+ }
+ }
+ });
}
- public void destroySurface(int id) {
- View view = null;
-
- if (m_surfaces.containsKey(id)) {
- view = m_surfaces.remove(id);
- } else if (m_nativeViews.containsKey(id)) {
- view = m_nativeViews.remove(id);
- } else {
- Log.e(QtNative.QtTAG, "Surface " + id +" not found!");
- }
-
- if (view == null)
- return;
-
- // Keep last frame in stack until it is replaced to get correct
- // shutdown transition
- if (m_surfaces.size() == 0 && m_nativeViews.size() == 0) {
- m_dummyView = view;
- } else {
- m_layout.removeView(view);
- }
+ @UsedFromNativeCode
+ @Override
+ void bringChildToFront(final int id)
+ {
+ QtNative.runAction(() -> {
+ QtWindow window = m_topLevelWindows.get(id);
+ if (window != null)
+ m_layout.moveChild(window, m_topLevelWindows.size() - 1);
+ });
}
- public int getSurfaceCount()
+ @UsedFromNativeCode
+ @Override
+ void bringChildToBack(int id)
{
- return m_surfaces.size();
+ QtNative.runAction(() -> {
+ QtWindow window = m_topLevelWindows.get(id);
+ if (window != null)
+ m_layout.moveChild(window, 0);
+ });
}
- public void bringChildToFront(int id)
+ @Override
+ QtAccessibilityDelegate createAccessibilityDelegate()
{
- View view = m_surfaces.get(id);
- if (view != null) {
- final int surfaceCount = getSurfaceCount();
- if (surfaceCount > 0)
- m_layout.moveChild(view, surfaceCount - 1);
- return;
- }
+ if (m_layout != null)
+ return new QtAccessibilityDelegate(m_layout);
- view = m_nativeViews.get(id);
- if (view != null)
- m_layout.moveChild(view, -1);
+ Log.w(QtTAG, "Null layout, failed to initialize accessibility delegate.");
+ return null;
}
- public void bringChildToBack(int id)
+ private void setActivityBackgroundDrawable()
{
- View view = m_surfaces.get(id);
- if (view != null) {
- m_layout.moveChild(view, 0);
- return;
+ TypedValue attr = new TypedValue();
+ m_activity.getTheme().resolveAttribute(android.R.attr.windowBackground,
+ attr, true);
+ Drawable backgroundDrawable;
+ if (attr.type >= TypedValue.TYPE_FIRST_COLOR_INT &&
+ attr.type <= TypedValue.TYPE_LAST_COLOR_INT) {
+ backgroundDrawable = new ColorDrawable(attr.data);
+ } else {
+ backgroundDrawable = m_activity.getResources().
+ getDrawable(attr.resourceId, m_activity.getTheme());
}
- view = m_nativeViews.get(id);
- if (view != null) {
- final int index = getSurfaceCount();
- m_layout.moveChild(view, index);
- }
+ m_activity.getWindow().setBackgroundDrawable(backgroundDrawable);
}
- public boolean dispatchGenericMotionEvent (MotionEvent ev)
+ // TODO: QTBUG-122761 To be removed after QtAndroidAutomotive does not depend on it.
+ @UsedFromNativeCode
+ public void insertNativeView(int id, View view, int x, int y, int w, int h)
{
- if (m_started && QtNative.dispatchGenericMotionEvent(ev))
- return true;
+ QtNative.runAction(()-> {
+ if (m_dummyView != null) {
+ m_layout.removeView(m_dummyView);
+ m_dummyView = null;
+ }
- try {
- return (Boolean) m_super_dispatchGenericMotionEvent.invoke(m_activity, ev);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return false;
+ if (m_nativeViews.containsKey(id))
+ m_layout.removeView(m_nativeViews.remove(id));
+
+ if (w < 0 || h < 0) {
+ view.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+ } else {
+ view.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
+ }
+
+ view.setId(id);
+ m_layout.addView(view);
+ m_nativeViews.put(id, view);
+ });
}
- public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
+ // TODO: QTBUG-122761 To be removed after QtAndroidAutomotive does not depend on it.
+ @UsedFromNativeCode
+ public void setNativeViewGeometry(int id, int x, int y, int w, int h)
{
- QtNative.sendRequestPermissionsResult(requestCode, permissions, grantResults);
+ QtNative.runAction(() -> {
+ if (m_nativeViews.containsKey(id)) {
+ View view = m_nativeViews.get(id);
+ view.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
+ } else {
+ Log.e(QtTAG, "View " + id + " not found!");
+ }
+ });
}
}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java
new file mode 100644
index 0000000000..6fd539d8dd
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java
@@ -0,0 +1,267 @@
+// Copyright (C) 2017 BogDan Vatra <bogdan@kde.org>
+// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.app.Activity;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.Rect;
+import android.os.Build;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.Display;
+import android.view.ViewTreeObserver;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.Menu;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowInsetsController;
+import android.widget.ImageView;
+import android.widget.PopupMenu;
+
+import java.util.HashMap;
+
+abstract class QtActivityDelegateBase
+{
+ protected Activity m_activity;
+ protected HashMap<Integer, QtWindow> m_topLevelWindows;
+ protected QtAccessibilityDelegate m_accessibilityDelegate = null;
+ protected QtDisplayManager m_displayManager = null;
+ protected QtInputDelegate m_inputDelegate = null;
+
+ private boolean m_membersInitialized = false;
+ private boolean m_contextMenuVisible = false;
+
+ // Subclass must implement these
+ abstract void startNativeApplicationImpl(String appParams, String mainLib);
+ abstract QtAccessibilityDelegate createAccessibilityDelegate();
+ abstract QtLayout getQtLayout();
+
+ // With these we are okay with default implementation doing nothing
+ void setUpLayout() {}
+ void setUpSplashScreen(int orientation) {}
+ void hideSplashScreen(final int duration) {}
+ void openContextMenu(final int x, final int y, final int w, final int h) {}
+ void setActionBarVisibility(boolean visible) {}
+ void addTopLevelWindow(final QtWindow window) {}
+ void removeTopLevelWindow(final int id) {}
+ void bringChildToFront(final int id) {}
+ void bringChildToBack(int id) {}
+ void setSystemUiVisibility(int systemUiVisibility) {}
+
+ QtActivityDelegateBase(Activity activity)
+ {
+ m_activity = activity;
+ // Set native context
+ QtNative.setActivity(m_activity);
+ }
+
+ QtDisplayManager displayManager() {
+ return m_displayManager;
+ }
+
+ @UsedFromNativeCode
+ QtInputDelegate getInputDelegate() {
+ return m_inputDelegate;
+ }
+
+ void setContextMenuVisible(boolean contextMenuVisible)
+ {
+ m_contextMenuVisible = contextMenuVisible;
+ }
+
+ boolean isContextMenuVisible()
+ {
+ return m_contextMenuVisible;
+ }
+
+ public boolean updateActivityAfterRestart(Activity activity) {
+ try {
+ // set new activity
+ m_activity = activity;
+ QtNative.setActivity(m_activity);
+
+ // force c++ native activity object to update
+ return QtNative.updateNativeActivity();
+ } catch (Exception e) {
+ Log.w(QtNative.QtTAG, "Failed to update the activity.");
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ public void startNativeApplication(String appParams, String mainLib)
+ {
+ if (m_membersInitialized)
+ return;
+ initMembers();
+ startNativeApplicationImpl(appParams, mainLib);
+ }
+
+ void initMembers()
+ {
+ m_membersInitialized = true;
+ m_topLevelWindows = new HashMap<Integer, QtWindow>();
+
+ m_displayManager = new QtDisplayManager(m_activity);
+ m_displayManager.registerDisplayListener();
+
+ QtInputDelegate.KeyboardVisibilityListener keyboardVisibilityListener =
+ () -> m_displayManager.updateFullScreen();
+ m_inputDelegate = new QtInputDelegate(m_activity, keyboardVisibilityListener);
+
+ try {
+ PackageManager pm = m_activity.getPackageManager();
+ ActivityInfo activityInfo = pm.getActivityInfo(m_activity.getComponentName(), 0);
+ m_inputDelegate.setSoftInputMode(activityInfo.softInputMode);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+
+ setUpLayout();
+ }
+
+ protected void registerGlobalFocusChangeListener(final View view) {
+ view.getViewTreeObserver().addOnGlobalFocusChangeListener(this::onGlobalFocusChanged);
+ }
+
+ private void onGlobalFocusChanged(View oldFocus, View newFocus) {
+ if (newFocus instanceof QtEditText) {
+ final QtWindow newWindow = (QtWindow) newFocus.getParent();
+ QtWindow.windowFocusChanged(true, newWindow.getId());
+ m_inputDelegate.setFocusedView((QtEditText) newFocus);
+ } else {
+ int id = -1;
+ if (oldFocus instanceof QtEditText) {
+ final QtWindow oldWindow = (QtWindow) oldFocus.getParent();
+ id = oldWindow.getId();
+ }
+ QtWindow.windowFocusChanged(false, id);
+ m_inputDelegate.setFocusedView(null);
+ }
+ }
+
+ public void hideSplashScreen()
+ {
+ hideSplashScreen(0);
+ }
+
+ @UsedFromNativeCode
+ public void notifyLocationChange(int viewId)
+ {
+ if (m_accessibilityDelegate == null)
+ return;
+ m_accessibilityDelegate.notifyLocationChange(viewId);
+ }
+
+ @UsedFromNativeCode
+ public void notifyObjectHide(int viewId, int parentId)
+ {
+ if (m_accessibilityDelegate == null)
+ return;
+ m_accessibilityDelegate.notifyObjectHide(viewId, parentId);
+ }
+
+ @UsedFromNativeCode
+ public void notifyObjectShow(int parentId)
+ {
+ if (m_accessibilityDelegate == null)
+ return;
+ m_accessibilityDelegate.notifyObjectShow(parentId);
+ }
+
+ @UsedFromNativeCode
+ public void notifyObjectFocus(int viewId)
+ {
+ if (m_accessibilityDelegate == null)
+ return;
+ m_accessibilityDelegate.notifyObjectFocus(viewId);
+ }
+
+ @UsedFromNativeCode
+ public void notifyValueChanged(int viewId, String value)
+ {
+ if (m_accessibilityDelegate == null)
+ return;
+ m_accessibilityDelegate.notifyValueChanged(viewId, value);
+ }
+
+ @UsedFromNativeCode
+ public void notifyScrolledEvent(int viewId)
+ {
+ if (m_accessibilityDelegate == null)
+ return;
+ m_accessibilityDelegate.notifyScrolledEvent(viewId);
+ }
+
+ @UsedFromNativeCode
+ public void initializeAccessibility()
+ {
+ QtNative.runAction(() -> {
+ m_accessibilityDelegate = createAccessibilityDelegate();
+ });
+ }
+
+ void handleUiModeChange(int uiMode)
+ {
+ // QTBUG-108365
+ if (Build.VERSION.SDK_INT >= 30) {
+ // Since 29 version we are using Theme_DeviceDefault_DayNight
+ Window window = m_activity.getWindow();
+ WindowInsetsController controller = window.getInsetsController();
+ if (controller != null) {
+ // set APPEARANCE_LIGHT_STATUS_BARS if needed
+ int appearanceLight = Color.luminance(window.getStatusBarColor()) > 0.5 ?
+ WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS : 0;
+ controller.setSystemBarsAppearance(appearanceLight,
+ WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS);
+ }
+ }
+ switch (uiMode) {
+ case Configuration.UI_MODE_NIGHT_NO:
+ ExtractStyle.runIfNeeded(m_activity, false);
+ QtDisplayManager.handleUiDarkModeChanged(0);
+ break;
+ case Configuration.UI_MODE_NIGHT_YES:
+ ExtractStyle.runIfNeeded(m_activity, true);
+ QtDisplayManager.handleUiDarkModeChanged(1);
+ break;
+ }
+ }
+
+ @UsedFromNativeCode
+ public void resetOptionsMenu()
+ {
+ QtNative.runAction(() -> m_activity.invalidateOptionsMenu());
+ }
+
+ @UsedFromNativeCode
+ public void openOptionsMenu()
+ {
+ QtNative.runAction(() -> m_activity.openOptionsMenu());
+ }
+
+ public void onCreatePopupMenu(Menu menu)
+ {
+ QtNative.fillContextMenu(menu);
+ m_contextMenuVisible = true;
+ }
+
+ @UsedFromNativeCode
+ public void closeContextMenu()
+ {
+ QtNative.runAction(() -> m_activity.closeContextMenu());
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtActivityLoader.java b/src/android/jar/src/org/qtproject/qt/android/QtActivityLoader.java
new file mode 100644
index 0000000000..1b2e8e49a0
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityLoader.java
@@ -0,0 +1,151 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (c) 2016, BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.system.Os;
+import android.util.Base64;
+import android.util.DisplayMetrics;
+import android.util.Log;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
+
+class QtActivityLoader extends QtLoader {
+ private final Activity m_activity;
+
+ public QtActivityLoader(Activity activity)
+ {
+ super(new ContextWrapper(activity));
+ m_activity = activity;
+
+ extractContextMetaData();
+ }
+
+ private void showErrorDialog() {
+ if (m_activity == null) {
+ Log.w(QtTAG, "cannot show the error dialog from a null activity object");
+ return;
+ }
+ Resources resources = m_activity.getResources();
+ String packageName = m_activity.getPackageName();
+ AlertDialog errorDialog = new AlertDialog.Builder(m_activity).create();
+ @SuppressLint("DiscouragedApi") int id = resources.getIdentifier(
+ "fatal_error_msg", "string", packageName);
+ errorDialog.setMessage(resources.getString(id));
+ errorDialog.setButton(Dialog.BUTTON_POSITIVE, resources.getString(android.R.string.ok),
+ (dialog, which) -> finish());
+ errorDialog.show();
+ }
+
+ @Override
+ protected void finish() {
+ if (m_activity == null) {
+ Log.w(QtTAG, "finish() called when activity object is null");
+ return;
+ }
+ showErrorDialog();
+ m_activity.finish();
+ }
+
+ private String getDecodedUtfString(String str)
+ {
+ byte[] decodedExtraEnvVars = Base64.decode(str, Base64.DEFAULT);
+ return new String(decodedExtraEnvVars, StandardCharsets.UTF_8);
+ }
+
+ int getAppIconSize()
+ {
+ int size = m_activity.getResources().getDimensionPixelSize(android.R.dimen.app_icon_size);
+ if (size < 36 || size > 512) { // check size sanity
+ DisplayMetrics metrics = new DisplayMetrics();
+ m_activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ size = metrics.densityDpi / 10 * 3;
+ if (size < 36)
+ size = 36;
+
+ if (size > 512)
+ size = 512;
+ }
+
+ return size;
+ }
+
+ private void setupStyleExtraction()
+ {
+ int displayDensity = m_activity.getResources().getDisplayMetrics().densityDpi;
+ setEnvironmentVariable("QT_ANDROID_THEME_DISPLAY_DPI", String.valueOf(displayDensity));
+
+ String extractOption = getMetaData("android.app.extract_android_style");
+ if (extractOption.equals("full"))
+ setEnvironmentVariable("QT_USE_ANDROID_NATIVE_STYLE", String.valueOf(1));
+
+ String stylePath = ExtractStyle.setup(m_activity, extractOption, displayDensity);
+ setEnvironmentVariable("ANDROID_STYLE_PATH", stylePath);
+ }
+
+ @Override
+ protected void extractContextMetaData()
+ {
+ super.extractContextMetaData();
+
+ setEnvironmentVariable("QT_USE_ANDROID_NATIVE_DIALOGS", String.valueOf(1));
+ setEnvironmentVariable("QT_ANDROID_APP_ICON_SIZE", String.valueOf(getAppIconSize()));
+
+ setupStyleExtraction();
+
+ Intent intent = m_activity.getIntent();
+ if (intent == null) {
+ Log.w(QtTAG, "Null Intent from the current Activity.");
+ return;
+ }
+
+ String intentArgs = intent.getStringExtra("applicationArguments");
+ if (intentArgs != null)
+ appendApplicationParameters(intentArgs);
+
+ Bundle extras = intent.getExtras();
+ if (extras == null) {
+ Log.w(QtTAG, "Null extras from the Activity's intent.");
+ return;
+ }
+
+ int flags = m_activity.getApplicationInfo().flags;
+ boolean isDebuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+
+ if (isDebuggable) {
+ if (extras.containsKey("extraenvvars")) {
+ String extraEnvVars = extras.getString("extraenvvars");
+ setEnvironmentVariables(getDecodedUtfString(extraEnvVars));
+ }
+
+ if (extras.containsKey("extraappparams")) {
+ String extraAppParams = extras.getString("extraappparams");
+ appendApplicationParameters(getDecodedUtfString(extraAppParams));
+ }
+
+ m_debuggerSleepMs = 3000;
+ if (Os.getenv("QT_ANDROID_DEBUGGER_MAIN_THREAD_SLEEP_MS") != null) {
+ try {
+ m_debuggerSleepMs = Integer.parseInt(Os.getenv("QT_ANDROID_DEBUGGER_MAIN_THREAD_SLEEP_MS"));
+ } catch (NumberFormatException ignored) {
+ }
+ }
+ } else {
+ Log.d(QtNative.QtTAG, "Not in debug mode! It is not allowed to use extra arguments " +
+ "in non-debug mode.");
+ }
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtApplicationBase.java b/src/android/jar/src/org/qtproject/qt/android/QtApplicationBase.java
new file mode 100644
index 0000000000..de572266b9
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtApplicationBase.java
@@ -0,0 +1,15 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.app.Application;
+
+public class QtApplicationBase extends Application {
+ @Override
+ public void onTerminate() {
+ QtNative.terminateQt();
+ QtNative.getQtThread().exit();
+ super.onTerminate();
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtClipboardManager.java b/src/android/jar/src/org/qtproject/qt/android/QtClipboardManager.java
new file mode 100644
index 0000000000..ac0d4e1890
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtClipboardManager.java
@@ -0,0 +1,232 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Objects;
+import java.util.concurrent.Semaphore;
+
+class QtClipboardManager
+{
+ public static native void onClipboardDataChanged(long nativePointer);
+
+ private final static String TAG = "QtClipboardManager";
+ private ClipboardManager m_clipboardManager = null;
+ private boolean m_usePrimaryClip = false;
+ private final long m_nativePointer;
+
+ public QtClipboardManager(Context context, long nativePointer)
+ {
+ m_nativePointer = nativePointer;
+ registerClipboardManager(context);
+ }
+
+ private void registerClipboardManager(Context context)
+ {
+ if (context != null) {
+ final Semaphore semaphore = new Semaphore(0);
+ QtNative.runAction(() -> {
+ m_clipboardManager =
+ (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
+ if (m_clipboardManager != null) {
+ m_clipboardManager.addPrimaryClipChangedListener(
+ () -> onClipboardDataChanged(m_nativePointer));
+ }
+ semaphore.release();
+ });
+ try {
+ semaphore.acquire();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ @UsedFromNativeCode
+ public void clearClipData()
+ {
+ if (m_clipboardManager != null) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ m_clipboardManager.clearPrimaryClip();
+ } else {
+ String[] mimeTypes = { "application/octet-stream" };
+ ClipData data = new ClipData("", mimeTypes, new ClipData.Item(new Intent()));
+ m_clipboardManager.setPrimaryClip(data);
+ }
+ }
+ m_usePrimaryClip = false;
+ }
+
+ @UsedFromNativeCode
+ public void setClipboardText(Context context, String text)
+ {
+ if (m_clipboardManager != null) {
+ ClipData clipData = ClipData.newPlainText("text/plain", text);
+ updatePrimaryClip(clipData, context);
+ }
+ }
+
+ public static boolean hasClipboardText(Context context)
+ {
+ ClipboardManager clipboardManager =
+ (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
+
+ if (clipboardManager == null)
+ return false;
+
+ ClipDescription description = clipboardManager.getPrimaryClipDescription();
+ // getPrimaryClipDescription can fail if the app does not have input focus
+ if (description == null)
+ return false;
+
+ for (int i = 0; i < description.getMimeTypeCount(); ++i) {
+ String itemMimeType = description.getMimeType(i);
+ if (itemMimeType.matches("text/(.*)"))
+ return true;
+ }
+ return false;
+ }
+
+ @UsedFromNativeCode
+ public boolean hasClipboardText()
+ {
+ return hasClipboardMimeType("text/(.*)");
+ }
+
+ @UsedFromNativeCode
+ public String getClipboardText()
+ {
+ try {
+ if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
+ ClipData primaryClip = m_clipboardManager.getPrimaryClip();
+ if (primaryClip != null) {
+ for (int i = 0; i < primaryClip.getItemCount(); ++i)
+ if (primaryClip.getItemAt(i).getText() != null)
+ return primaryClip.getItemAt(i).getText().toString();
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to get clipboard data", e);
+ }
+ return "";
+ }
+
+ private void updatePrimaryClip(ClipData clipData, Context context)
+ {
+ try {
+ if (m_usePrimaryClip) {
+ ClipData clip = m_clipboardManager.getPrimaryClip();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ Objects.requireNonNull(clip).addItem(context.getContentResolver(),
+ clipData.getItemAt(0));
+ } else {
+ Objects.requireNonNull(clip).addItem(clipData.getItemAt(0));
+ }
+ m_clipboardManager.setPrimaryClip(clip);
+ } else {
+ m_clipboardManager.setPrimaryClip(clipData);
+ m_usePrimaryClip = true;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to set clipboard data", e);
+ }
+ }
+
+ @UsedFromNativeCode
+ public void setClipboardHtml(Context context, String text, String html)
+ {
+ if (m_clipboardManager != null) {
+ ClipData clipData = ClipData.newHtmlText("text/html", text, html);
+ updatePrimaryClip(clipData, context);
+ }
+ }
+
+ private boolean hasClipboardMimeType(String mimeType)
+ {
+ if (m_clipboardManager == null)
+ return false;
+
+ ClipDescription description = m_clipboardManager.getPrimaryClipDescription();
+ // getPrimaryClipDescription can fail if the app does not have input focus
+ if (description == null)
+ return false;
+
+ for (int i = 0; i < description.getMimeTypeCount(); ++i) {
+ String itemMimeType = description.getMimeType(i);
+ if (itemMimeType.matches(mimeType))
+ return true;
+ }
+ return false;
+ }
+
+ @UsedFromNativeCode
+ public boolean hasClipboardHtml()
+ {
+ return hasClipboardMimeType("text/html");
+ }
+
+ @UsedFromNativeCode
+ public String getClipboardHtml()
+ {
+ try {
+ if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
+ ClipData primaryClip = m_clipboardManager.getPrimaryClip();
+ if (primaryClip != null) {
+ for (int i = 0; i < primaryClip.getItemCount(); ++i)
+ if (primaryClip.getItemAt(i).getHtmlText() != null)
+ return primaryClip.getItemAt(i).getHtmlText();
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to get clipboard data", e);
+ }
+ return "";
+ }
+
+ @UsedFromNativeCode
+ public void setClipboardUri(Context context, String uriString)
+ {
+ if (m_clipboardManager != null) {
+ ClipData clipData = ClipData.newUri(context.getContentResolver(), "text/uri-list",
+ Uri.parse(uriString));
+ updatePrimaryClip(clipData, context);
+ }
+ }
+
+ @UsedFromNativeCode
+ public boolean hasClipboardUri()
+ {
+ return hasClipboardMimeType("text/uri-list");
+ }
+
+ @UsedFromNativeCode
+ private String[] getClipboardUris()
+ {
+ ArrayList<String> uris = new ArrayList<>();
+ try {
+ if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
+ ClipData primaryClip = m_clipboardManager.getPrimaryClip();
+ if (primaryClip != null) {
+ for (int i = 0; i < primaryClip.getItemCount(); ++i)
+ if (primaryClip.getItemAt(i).getUri() != null)
+ uris.add(primaryClip.getItemAt(i).getUri().toString());
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to get clipboard data", e);
+ }
+ String[] strings = new String[uris.size()];
+ strings = uris.toArray(strings);
+ return strings;
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtDisplayManager.java b/src/android/jar/src/org/qtproject/qt/android/QtDisplayManager.java
new file mode 100644
index 0000000000..b6a52fb22f
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtDisplayManager.java
@@ -0,0 +1,287 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
+import android.os.Build;
+import android.util.DisplayMetrics;
+import android.util.Size;
+import android.view.Display;
+import android.view.Surface;
+import android.view.View;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.view.WindowMetrics;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+class QtDisplayManager {
+
+ // screen methods
+ public static native void setDisplayMetrics(int screenWidthPixels, int screenHeightPixels,
+ int availableLeftPixels, int availableTopPixels,
+ int availableWidthPixels, int availableHeightPixels,
+ double XDpi, double YDpi, double scaledDensity,
+ double density, float refreshRate);
+ public static native void handleOrientationChanged(int newRotation, int nativeOrientation);
+ public static native void handleRefreshRateChanged(float refreshRate);
+ public static native void handleUiDarkModeChanged(int newUiMode);
+ public static native void handleScreenAdded(int displayId);
+ public static native void handleScreenChanged(int displayId);
+ public static native void handleScreenRemoved(int displayId);
+ // screen methods
+
+ // Keep in sync with QtAndroid::SystemUiVisibility in androidjnimain.h
+ public static final int SYSTEM_UI_VISIBILITY_NORMAL = 0;
+ public static final int SYSTEM_UI_VISIBILITY_FULLSCREEN = 1;
+ public static final int SYSTEM_UI_VISIBILITY_TRANSLUCENT = 2;
+ private int m_systemUiVisibility = SYSTEM_UI_VISIBILITY_NORMAL;
+
+ private static int m_previousRotation = -1;
+
+ private DisplayManager.DisplayListener m_displayListener = null;
+ private final Activity m_activity;
+
+ QtDisplayManager(Activity activity)
+ {
+ m_activity = activity;
+ initDisplayListener();
+ }
+
+ private void initDisplayListener() {
+ m_displayListener = new DisplayManager.DisplayListener() {
+ @Override
+ public void onDisplayAdded(int displayId) {
+ QtDisplayManager.handleScreenAdded(displayId);
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ Display display = (Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
+ ? m_activity.getWindowManager().getDefaultDisplay()
+ : m_activity.getDisplay();
+ float refreshRate = getRefreshRate(display);
+ QtDisplayManager.handleRefreshRateChanged(refreshRate);
+ QtDisplayManager.handleScreenChanged(displayId);
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ QtDisplayManager.handleScreenRemoved(displayId);
+ }
+ };
+ }
+
+ static void handleOrientationChanges(Activity activity)
+ {
+ int currentRotation = getDisplayRotation(activity);
+ if (m_previousRotation == currentRotation)
+ return;
+ int nativeOrientation = getNativeOrientation(activity, currentRotation);
+ QtDisplayManager.handleOrientationChanged(currentRotation, nativeOrientation);
+ m_previousRotation = currentRotation;
+ }
+
+ public static int getDisplayRotation(Activity activity) {
+ Display display = Build.VERSION.SDK_INT < Build.VERSION_CODES.R ?
+ activity.getWindowManager().getDefaultDisplay() :
+ activity.getDisplay();
+
+ return display != null ? display.getRotation() : 0;
+ }
+
+ private static int getNativeOrientation(Activity activity, int rotation)
+ {
+ int orientation = activity.getResources().getConfiguration().orientation;
+ boolean rot90 = (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270);
+ boolean isLandscape = (orientation == Configuration.ORIENTATION_LANDSCAPE);
+ if ((isLandscape && !rot90) || (!isLandscape && rot90))
+ return Configuration.ORIENTATION_LANDSCAPE;
+
+ return Configuration.ORIENTATION_PORTRAIT;
+ }
+
+ static float getRefreshRate(Display display)
+ {
+ return display != null ? display.getRefreshRate() : 60.0f;
+ }
+
+ public void registerDisplayListener()
+ {
+ DisplayManager displayManager =
+ (DisplayManager) m_activity.getSystemService(Context.DISPLAY_SERVICE);
+ displayManager.registerDisplayListener(m_displayListener, null);
+ }
+
+ public void unregisterDisplayListener()
+ {
+ DisplayManager displayManager =
+ (DisplayManager) m_activity.getSystemService(Context.DISPLAY_SERVICE);
+ displayManager.unregisterDisplayListener(m_displayListener);
+ }
+
+ public void setSystemUiVisibility(int systemUiVisibility)
+ {
+ if (m_systemUiVisibility == systemUiVisibility)
+ return;
+
+ m_systemUiVisibility = systemUiVisibility;
+
+ int systemUiVisibilityFlags = View.SYSTEM_UI_FLAG_VISIBLE;
+ switch (m_systemUiVisibility) {
+ case SYSTEM_UI_VISIBILITY_NORMAL:
+ m_activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+ m_activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ m_activity.getWindow().getAttributes().layoutInDisplayCutoutMode =
+ WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
+ }
+ break;
+ case SYSTEM_UI_VISIBILITY_FULLSCREEN:
+ m_activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ m_activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
+ systemUiVisibilityFlags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+ | View.INVISIBLE;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ m_activity.getWindow().getAttributes().layoutInDisplayCutoutMode =
+ WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
+ }
+ break;
+ case SYSTEM_UI_VISIBILITY_TRANSLUCENT:
+ m_activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
+ | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
+ | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ m_activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ m_activity.getWindow().getAttributes().layoutInDisplayCutoutMode =
+ WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+ }
+ break;
+ }
+ m_activity.getWindow().getDecorView().setSystemUiVisibility(systemUiVisibilityFlags);
+ }
+
+ public int systemUiVisibility()
+ {
+ return m_systemUiVisibility;
+ }
+
+ public void updateFullScreen()
+ {
+ if (m_systemUiVisibility == SYSTEM_UI_VISIBILITY_FULLSCREEN) {
+ m_systemUiVisibility = SYSTEM_UI_VISIBILITY_NORMAL;
+ setSystemUiVisibility(SYSTEM_UI_VISIBILITY_FULLSCREEN);
+ }
+ }
+
+ @UsedFromNativeCode
+ public static Display getDisplay(Context context, int displayId)
+ {
+ DisplayManager displayManager =
+ (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
+ if (displayManager != null) {
+ return displayManager.getDisplay(displayId);
+ }
+ return null;
+ }
+
+ @UsedFromNativeCode
+ public static List<Display> getAvailableDisplays(Context context)
+ {
+ DisplayManager displayManager =
+ (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
+ if (displayManager != null) {
+ Display[] displays = displayManager.getDisplays();
+ return Arrays.asList(displays);
+ }
+ return new ArrayList<>();
+ }
+
+ @UsedFromNativeCode
+ public static Size getDisplaySize(Context displayContext, Display display)
+ {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
+ DisplayMetrics realMetrics = new DisplayMetrics();
+ display.getRealMetrics(realMetrics);
+ return new Size(realMetrics.widthPixels, realMetrics.heightPixels);
+ }
+
+ Context windowsContext = displayContext.createWindowContext(
+ WindowManager.LayoutParams.TYPE_APPLICATION, null);
+ WindowManager windowManager =
+ (WindowManager) windowsContext.getSystemService(Context.WINDOW_SERVICE);
+ WindowMetrics windowsMetrics = windowManager.getCurrentWindowMetrics();
+ Rect bounds = windowsMetrics.getBounds();
+ return new Size(bounds.width(), bounds.height());
+ }
+
+ public static void setApplicationDisplayMetrics(Activity activity, int width, int height)
+ {
+ if (activity == null)
+ return;
+
+ final WindowInsets rootInsets = activity.getWindow().getDecorView().getRootWindowInsets();
+ final WindowManager windowManager = activity.getWindowManager();
+ Display display;
+
+ int insetLeft;
+ int insetTop;
+
+ int maxWidth;
+ int maxHeight;
+
+ if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
+ display = windowManager.getDefaultDisplay();
+
+ final DisplayMetrics maxMetrics = new DisplayMetrics();
+ display.getRealMetrics(maxMetrics);
+ maxWidth = maxMetrics.widthPixels;
+ maxHeight = maxMetrics.heightPixels;
+
+ insetLeft = rootInsets.getStableInsetLeft();
+ insetTop = rootInsets.getStableInsetTop();
+ } else {
+ display = activity.getDisplay();
+
+ final WindowMetrics maxMetrics = windowManager.getMaximumWindowMetrics();
+ maxWidth = maxMetrics.getBounds().width();
+ maxHeight = maxMetrics.getBounds().height();
+
+ insetLeft = rootInsets.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars()).left;
+ insetTop = rootInsets.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars()).top;
+ }
+
+ final DisplayMetrics displayMetrics = activity.getResources().getDisplayMetrics();
+
+ double density = displayMetrics.density;
+ double scaledDensity = displayMetrics.scaledDensity;
+
+ setDisplayMetrics(maxWidth, maxHeight, insetLeft, insetTop,
+ width, height, getXDpi(displayMetrics), getYDpi(displayMetrics),
+ scaledDensity, density, getRefreshRate(display));
+ }
+
+ public static float getXDpi(final DisplayMetrics metrics) {
+ if (metrics.xdpi < android.util.DisplayMetrics.DENSITY_LOW)
+ return android.util.DisplayMetrics.DENSITY_LOW;
+ return metrics.xdpi;
+ }
+
+ public static float getYDpi(final DisplayMetrics metrics) {
+ if (metrics.ydpi < android.util.DisplayMetrics.DENSITY_LOW)
+ return android.util.DisplayMetrics.DENSITY_LOW;
+ return metrics.ydpi;
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtEditText.java b/src/android/jar/src/org/qtproject/qt/android/QtEditText.java
index 66d9ccff8b..4524887242 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtEditText.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtEditText.java
@@ -5,70 +5,217 @@
package org.qtproject.qt.android;
import android.content.Context;
+import android.graphics.Canvas;
import android.text.InputType;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
+import android.view.KeyEvent;
-public class QtEditText extends View
+import org.qtproject.qt.android.QtInputConnection.QtInputConnectionListener;
+
+class QtEditText extends View
{
int m_initialCapsMode = 0;
int m_imeOptions = 0;
int m_inputType = InputType.TYPE_CLASS_TEXT;
boolean m_optionsChanged = false;
- QtActivityDelegate m_activityDelegate;
+ QtInputConnection m_inputConnection = null;
+
+ // input method hints - must be kept in sync with QTDIR/src/corelib/global/qnamespace.h
+ private final int ImhHiddenText = 0x1;
+ private final int ImhSensitiveData = 0x2;
+ private final int ImhNoAutoUppercase = 0x4;
+ private final int ImhPreferNumbers = 0x8;
+ private final int ImhPreferUppercase = 0x10;
+ private final int ImhPreferLowercase = 0x20;
+ private final int ImhNoPredictiveText = 0x40;
+
+ private final int ImhDate = 0x80;
+ private final int ImhTime = 0x100;
+
+ private final int ImhPreferLatin = 0x200;
+
+ private final int ImhMultiLine = 0x400;
+
+ private final int ImhDigitsOnly = 0x10000;
+ private final int ImhFormattedNumbersOnly = 0x20000;
+ private final int ImhUppercaseOnly = 0x40000;
+ private final int ImhLowercaseOnly = 0x80000;
+ private final int ImhDialableCharactersOnly = 0x100000;
+ private final int ImhEmailCharactersOnly = 0x200000;
+ private final int ImhUrlCharactersOnly = 0x400000;
+ private final int ImhLatinOnly = 0x800000;
+
+ private final QtInputConnectionListener m_qtInputConnectionListener;
+
+ public QtEditText(Context context, QtInputConnectionListener listener)
+ {
+ super(context);
+ setFocusable(true);
+ setFocusableInTouchMode(true);
+ m_qtInputConnectionListener = listener;
+ }
- public void setImeOptions(int m_imeOptions)
+ private void setImeOptions(int imeOptions)
{
- if (m_imeOptions == this.m_imeOptions)
+ if (m_imeOptions == imeOptions)
return;
- this.m_imeOptions = m_imeOptions;
+ m_imeOptions = m_imeOptions;
m_optionsChanged = true;
}
- public void setInitialCapsMode(int m_initialCapsMode)
+ private void setInitialCapsMode(int initialCapsMode)
{
- if (m_initialCapsMode == this.m_initialCapsMode)
+ if (m_initialCapsMode == initialCapsMode)
return;
- this.m_initialCapsMode = m_initialCapsMode;
+ m_initialCapsMode = initialCapsMode;
m_optionsChanged = true;
}
- public void setInputType(int m_inputType)
+ private void setInputType(int inputType)
{
- if (m_inputType == this.m_inputType)
+ if (m_inputType == inputType)
return;
- this.m_inputType = m_inputType;
+ m_inputType = m_inputType;
m_optionsChanged = true;
}
- public QtEditText(Context context, QtActivityDelegate activityDelegate)
+ @Override
+ public InputConnection onCreateInputConnection(EditorInfo outAttrs)
{
- super(context);
- setFocusable(true);
- setFocusableInTouchMode(true);
- m_activityDelegate = activityDelegate;
+ outAttrs.inputType = m_inputType;
+ outAttrs.imeOptions = m_imeOptions;
+ outAttrs.initialCapsMode = m_initialCapsMode;
+ m_inputConnection = new QtInputConnection(this,m_qtInputConnectionListener);
+ return m_inputConnection;
}
- public QtActivityDelegate getActivityDelegate()
+
+ @Override
+ public boolean onCheckIsTextEditor ()
{
- return m_activityDelegate;
+ return true;
}
@Override
- public InputConnection onCreateInputConnection(EditorInfo outAttrs)
+ public boolean onKeyDown (int keyCode, KeyEvent event)
{
- outAttrs.inputType = m_inputType;
- outAttrs.imeOptions = m_imeOptions;
- outAttrs.initialCapsMode = m_initialCapsMode;
- outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI;
- return new QtInputConnection(this);
+ if (null != m_inputConnection)
+ m_inputConnection.restartImmInput();
+
+ return super.onKeyDown(keyCode, event);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ // DEBUG CODE
+ // canvas.drawARGB(127, 255, 0, 255);
+ super.onDraw(canvas);
}
-// // DEBUG CODE
-// @Override
-// protected void onDraw(Canvas canvas) {
-// canvas.drawARGB(127, 255, 0, 255);
-// super.onDraw(canvas);
-// }
+
+ public void setEditTextOptions(int enterKeyType, int inputHints)
+ {
+ int initialCapsMode = 0;
+ int imeOptions = imeOptionsFromEnterKeyType(enterKeyType);
+ int inputType = android.text.InputType.TYPE_CLASS_TEXT;
+
+ if ((inputHints & (ImhPreferNumbers | ImhDigitsOnly | ImhFormattedNumbersOnly)) != 0) {
+ inputType = android.text.InputType.TYPE_CLASS_NUMBER;
+ if ((inputHints & ImhFormattedNumbersOnly) != 0) {
+ inputType |= (android.text.InputType.TYPE_NUMBER_FLAG_DECIMAL
+ | android.text.InputType.TYPE_NUMBER_FLAG_SIGNED);
+ }
+
+ if ((inputHints & ImhHiddenText) != 0)
+ inputType |= android.text.InputType.TYPE_NUMBER_VARIATION_PASSWORD;
+ } else if ((inputHints & ImhDialableCharactersOnly) != 0) {
+ inputType = android.text.InputType.TYPE_CLASS_PHONE;
+ } else if ((inputHints & (ImhDate | ImhTime)) != 0) {
+ inputType = android.text.InputType.TYPE_CLASS_DATETIME;
+ if ((inputHints & (ImhDate | ImhTime)) != (ImhDate | ImhTime)) {
+ if ((inputHints & ImhDate) != 0)
+ inputType |= android.text.InputType.TYPE_DATETIME_VARIATION_DATE;
+ else
+ inputType |= android.text.InputType.TYPE_DATETIME_VARIATION_TIME;
+ } // else { TYPE_DATETIME_VARIATION_NORMAL(0) }
+ } else { // CLASS_TEXT
+ if ((inputHints & ImhHiddenText) != 0) {
+ inputType |= android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
+ } else if ((inputHints & ImhSensitiveData) != 0 ||
+ isDisablePredictiveTextWorkaround(inputHints)) {
+ inputType |= android.text.InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
+ } else if ((inputHints & ImhUrlCharactersOnly) != 0) {
+ inputType |= android.text.InputType.TYPE_TEXT_VARIATION_URI;
+ if (enterKeyType == 0) // not explicitly overridden
+ imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_GO;
+ } else if ((inputHints & ImhEmailCharactersOnly) != 0) {
+ inputType |= android.text.InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
+ }
+
+ if ((inputHints & ImhMultiLine) != 0) {
+ inputType |= android.text.InputType.TYPE_TEXT_FLAG_MULTI_LINE;
+ // Clear imeOptions for Multi-Line Type
+ // User should be able to insert new line in such case
+ imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
+ }
+ if ((inputHints & (ImhNoPredictiveText | ImhSensitiveData | ImhHiddenText)) != 0)
+ inputType |= android.text.InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
+
+ if ((inputHints & ImhUppercaseOnly) != 0) {
+ initialCapsMode |= android.text.TextUtils.CAP_MODE_CHARACTERS;
+ inputType |= android.text.InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS;
+ } else if ((inputHints & ImhLowercaseOnly) == 0
+ && (inputHints & ImhNoAutoUppercase) == 0) {
+ initialCapsMode |= android.text.TextUtils.CAP_MODE_SENTENCES;
+ inputType |= android.text.InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
+ }
+ }
+
+ if (enterKeyType == 0 && (inputHints & ImhMultiLine) != 0)
+ imeOptions = android.view.inputmethod.EditorInfo.IME_FLAG_NO_ENTER_ACTION;
+
+ setInitialCapsMode(initialCapsMode);
+ setImeOptions(imeOptions);
+ setInputType(inputType);
+ }
+
+ private int imeOptionsFromEnterKeyType(int enterKeyType)
+ {
+ int imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
+
+ // enter key type - must be kept in sync with QTDIR/src/corelib/global/qnamespace.h
+ switch (enterKeyType) {
+ case 0: // EnterKeyDefault
+ break;
+ case 1: // EnterKeyReturn
+ imeOptions = android.view.inputmethod.EditorInfo.IME_FLAG_NO_ENTER_ACTION;
+ break;
+ case 2: // EnterKeyDone
+ break;
+ case 3: // EnterKeyGo
+ imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_GO;
+ break;
+ case 4: // EnterKeySend
+ imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_SEND;
+ break;
+ case 5: // EnterKeySearch
+ imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_SEARCH;
+ break;
+ case 6: // EnterKeyNext
+ imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_NEXT;
+ break;
+ case 7: // EnterKeyPrevious
+ imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_PREVIOUS;
+ break;
+ }
+ return imeOptions;
+ }
+
+ private boolean isDisablePredictiveTextWorkaround(int inputHints)
+ {
+ return (inputHints & ImhNoPredictiveText) != 0 &&
+ System.getenv("QT_ANDROID_ENABLE_WORKAROUND_TO_DISABLE_PREDICTIVE_TEXT") != null;
+ }
}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegate.java
new file mode 100644
index 0000000000..ff694777d5
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegate.java
@@ -0,0 +1,178 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import static org.qtproject.qt.android.QtNative.ApplicationState.*;
+
+import android.app.Activity;
+import android.app.Application;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+class QtEmbeddedDelegate extends QtActivityDelegateBase
+ implements QtNative.AppStateDetailsListener, QtEmbeddedViewInterface
+{
+ // TODO simplistic implementation with one QtView, expand to support multiple views QTBUG-117649
+ private QtView m_view;
+ private QtNative.ApplicationStateDetails m_stateDetails;
+ private boolean m_windowLoaded = false;
+
+ public QtEmbeddedDelegate(Activity context) {
+ super(context);
+
+ m_stateDetails = QtNative.getStateDetails();
+ QtNative.registerAppStateListener(this);
+
+ m_activity.getApplication().registerActivityLifecycleCallbacks(
+ new Application.ActivityLifecycleCallbacks() {
+ @Override
+ public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}
+
+ @Override
+ public void onActivityStarted(Activity activity) {}
+
+ @Override
+ public void onActivityResumed(Activity activity) {
+ if (m_activity == activity && m_stateDetails.isStarted) {
+ QtNative.setApplicationState(ApplicationActive);
+ QtNative.updateWindow();
+ }
+ }
+
+ @Override
+ public void onActivityPaused(Activity activity) {
+ if (m_activity == activity && m_stateDetails.isStarted) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N ||
+ !activity.isInMultiWindowMode()) {
+ QtNative.setApplicationState(ApplicationInactive);
+ }
+ }
+ }
+
+ @Override
+ public void onActivityStopped(Activity activity) {
+ if (m_activity == activity && m_stateDetails.isStarted) {
+ QtNative.setApplicationState(ApplicationSuspended);
+ }
+ }
+
+ @Override
+ public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
+
+ @Override
+ public void onActivityDestroyed(Activity activity) {
+ if (m_activity == activity && m_stateDetails.isStarted) {
+ m_activity.getApplication().unregisterActivityLifecycleCallbacks(this);
+ QtNative.unregisterAppStateListener(QtEmbeddedDelegate.this);
+ QtEmbeddedDelegateFactory.remove(m_activity);
+ QtNative.terminateQt();
+ QtNative.setActivity(null);
+ QtNative.getQtThread().exit();
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onAppStateDetailsChanged(QtNative.ApplicationStateDetails details) {
+ synchronized (this) {
+ m_stateDetails = details;
+ }
+ }
+
+ @Override
+ public void onNativePluginIntegrationReadyChanged(boolean ready)
+ {
+ synchronized (this) {
+ if (ready) {
+ QtNative.runAction(() -> {
+ DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
+ QtDisplayManager.setApplicationDisplayMetrics(m_activity, metrics.widthPixels,
+ metrics.heightPixels);
+
+ });
+ createRootWindow();
+ }
+ }
+ }
+
+ @Override
+ void startNativeApplicationImpl(String appParams, String mainLib)
+ {
+ QtNative.startApplication(appParams, mainLib);
+ }
+
+ @Override
+ QtAccessibilityDelegate createAccessibilityDelegate()
+ {
+ // FIXME make QtAccessibilityDelegate window based or verify current way works
+ // also for child windows: QTBUG-120685
+ return null;
+ }
+
+ @UsedFromNativeCode
+ @Override
+ QtLayout getQtLayout()
+ {
+ // TODO verify if returning m_view here works, this is used by the androidjniinput
+ // when e.g. showing a keyboard, so depends on getting the keyboard focus working
+ // QTBUG-118873
+ if (m_view == null)
+ return null;
+ return m_view.getQtWindow();
+ }
+
+ // QtEmbeddedViewInterface implementation begin
+ @Override
+ public void startQtApplication(String appParams, String mainLib)
+ {
+ super.startNativeApplication(appParams, mainLib);
+ }
+
+ @Override
+ public void queueLoadWindow()
+ {
+ synchronized (this) {
+ if (m_stateDetails.nativePluginIntegrationReady)
+ createRootWindow();
+ }
+ }
+
+ @Override
+ public void setView(QtView view)
+ {
+ m_view = view;
+ updateInputDelegate();
+ if (m_view != null)
+ registerGlobalFocusChangeListener(m_view);
+ }
+ // QtEmbeddedViewInterface implementation end
+
+ private void updateInputDelegate() {
+ if (m_view == null) {
+ m_inputDelegate.setEditPopupMenu(null);
+ return;
+ }
+ m_inputDelegate.setEditPopupMenu(new EditPopupMenu(m_activity, m_view));
+ }
+
+ private void createRootWindow() {
+ if (m_view != null && !m_windowLoaded) {
+ QtView.createRootWindow(m_view, m_view.getLeft(), m_view.getTop(), m_view.getWidth(),
+ m_view.getHeight());
+ m_windowLoaded = true;
+ }
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegateFactory.java b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegateFactory.java
new file mode 100644
index 0000000000..8cf89e5bc3
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegateFactory.java
@@ -0,0 +1,37 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.app.Activity;
+import android.app.Application;
+import android.os.Bundle;
+
+import java.util.HashMap;
+
+class QtEmbeddedDelegateFactory {
+ private static final HashMap<Activity, QtEmbeddedDelegate> m_delegates = new HashMap<>();
+ private static final Object m_delegateLock = new Object();
+
+ @UsedFromNativeCode
+ public static QtActivityDelegateBase getActivityDelegate(Activity activity) {
+ synchronized (m_delegateLock) {
+ return m_delegates.get(activity);
+ }
+ }
+
+ public static QtEmbeddedDelegate create(Activity activity) {
+ synchronized (m_delegateLock) {
+ if (!m_delegates.containsKey(activity))
+ m_delegates.put(activity, new QtEmbeddedDelegate(activity));
+
+ return m_delegates.get(activity);
+ }
+ }
+
+ public static void remove(Activity activity) {
+ synchronized (m_delegateLock) {
+ m_delegates.remove(activity);
+ }
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedLoader.java b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedLoader.java
new file mode 100644
index 0000000000..0c6c4b49f0
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedLoader.java
@@ -0,0 +1,53 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.app.Activity;
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build;
+import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.SurfaceView;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+
+import dalvik.system.DexClassLoader;
+import android.content.res.Resources;
+
+class QtEmbeddedLoader extends QtLoader {
+ private static final String TAG = "QtEmbeddedLoader";
+
+ public QtEmbeddedLoader(Context context) {
+ super(new ContextWrapper(context));
+ // TODO Service context handling QTBUG-118874
+ int displayDensity = m_context.getResources().getDisplayMetrics().densityDpi;
+ setEnvironmentVariable("QT_ANDROID_THEME_DISPLAY_DPI", String.valueOf(displayDensity));
+ String stylePath = ExtractStyle.setup(m_context, "minimal", displayDensity);
+ setEnvironmentVariable("ANDROID_STYLE_PATH", stylePath);
+ setEnvironmentVariable("QT_ANDROID_NO_EXIT_CALL", String.valueOf(true));
+ }
+
+ @Override
+ protected void finish() {
+ // Called when loading fails - clear the delegate to make sure we don't hold reference
+ // to the embedding Context
+ QtEmbeddedDelegateFactory.remove((Activity)m_context.getBaseContext());
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedViewInterface.java b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedViewInterface.java
new file mode 100644
index 0000000000..a83a65e32c
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedViewInterface.java
@@ -0,0 +1,15 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+/**
+ * QtEmbeddedViewInterface is intended to encapsulate the needs of QtView, so that the Activity and
+ * Service implementations of these functions may be split clearly, and the interface can be stored
+ * and used conveniently in QtView.
+**/
+interface QtEmbeddedViewInterface {
+ void startQtApplication(String appParams, String mainLib);
+ void setView(QtView view);
+ void queueLoadWindow();
+};
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtInputConnection.java b/src/android/jar/src/org/qtproject/qt/android/QtInputConnection.java
index abcc76da17..1bfe05e7ac 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtInputConnection.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtInputConnection.java
@@ -6,6 +6,7 @@ package org.qtproject.qt.android;
import android.content.Context;
import android.os.Build;
+import android.util.Log;
import android.view.WindowMetrics;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.CompletionInfo;
@@ -49,34 +50,11 @@ class QtNativeInputConnection
static native boolean copyURL();
static native boolean paste();
static native boolean updateCursorPosition();
+ static native void reportFullscreenMode(boolean enabled);
+ static native boolean fullscreenMode();
}
-class HideKeyboardRunnable implements Runnable {
- private long m_hideTimeStamp = System.nanoTime();
-
- @Override
- public void run() {
- // Check that the keyboard is really no longer there.
- Activity activity = QtNative.activity();
- Rect r = new Rect();
- activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
-
- int screenHeight = 0;
- if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
- DisplayMetrics metrics = new DisplayMetrics();
- activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
- screenHeight = metrics.heightPixels;
- } else {
- final WindowMetrics maximumWindowMetrics = activity.getWindowManager().getMaximumWindowMetrics();
- screenHeight = maximumWindowMetrics.getBounds().height();
- }
- final int kbHeight = screenHeight - r.bottom;
- if (kbHeight < 100)
- QtNative.activityDelegate().setKeyboardVisibility(false, m_hideTimeStamp);
- }
-}
-
-public class QtInputConnection extends BaseInputConnection
+class QtInputConnection extends BaseInputConnection
{
private static final int ID_SELECT_ALL = android.R.id.selectAll;
private static final int ID_CUT = android.R.id.cut;
@@ -86,21 +64,71 @@ public class QtInputConnection extends BaseInputConnection
private static final int ID_SWITCH_INPUT_METHOD = android.R.id.switchInputMethod;
private static final int ID_ADD_TO_DICTIONARY = android.R.id.addToDictionary;
- private QtEditText m_view = null;
+ private static final String QtTAG = "QtInputConnection";
+
+ private final QtInputConnectionListener m_qtInputConnectionListener;
+
+ class HideKeyboardRunnable implements Runnable {
+ @Override
+ public void run() {
+ // Check that the keyboard is really no longer there.
+ Activity activity = QtNative.activity();
+ if (activity == null) {
+ Log.w(QtTAG, "HideKeyboardRunnable: The activity reference is null");
+ return;
+ }
+
+ Rect r = new Rect();
+ activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
+
+ int screenHeight;
+ if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
+ DisplayMetrics metrics = new DisplayMetrics();
+ activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ screenHeight = metrics.heightPixels;
+ } else {
+ final WindowMetrics maximumWindowMetrics = activity.getWindowManager().getMaximumWindowMetrics();
+ screenHeight = maximumWindowMetrics.getBounds().height();
+ }
+ final int kbHeight = screenHeight - r.bottom;
+ if (kbHeight < 100)
+ m_qtInputConnectionListener.onHideKeyboardRunnableDone(false, System.nanoTime());
+ }
+ }
+
+ public interface QtInputConnectionListener {
+ void onSetClosing(boolean closing);
+ void onHideKeyboardRunnableDone(boolean visibility, long hideTimeStamp);
+ void onSendKeyEventDefaultCase();
+ }
+
+ private final QtEditText m_view;
+ private final InputMethodManager m_imm;
private void setClosing(boolean closing)
{
- if (closing) {
+ if (closing)
m_view.postDelayed(new HideKeyboardRunnable(), 100);
- } else {
- QtNative.activityDelegate().setKeyboardVisibility(true, System.nanoTime());
- }
+ else
+ m_qtInputConnectionListener.onSetClosing(false);
}
- public QtInputConnection(QtEditText targetView)
+ public QtInputConnection(QtEditText targetView, QtInputConnectionListener listener)
{
super(targetView, true);
m_view = targetView;
+ m_imm = (InputMethodManager)m_view.getContext().getSystemService(
+ Context.INPUT_METHOD_SERVICE);
+ m_qtInputConnectionListener = listener;
+ }
+
+ public void restartImmInput()
+ {
+ if (QtNativeInputConnection.fullscreenMode()) {
+ if (m_imm != null)
+ m_imm.restartInput(m_view);
+ }
+
}
@Override
@@ -111,6 +139,18 @@ public class QtInputConnection extends BaseInputConnection
}
@Override
+ public boolean reportFullscreenMode (boolean enabled)
+ {
+ QtNativeInputConnection.reportFullscreenMode(enabled);
+ // Always ignored on calling editor.
+ // Always false on Android 8 and later, true with earlier.
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
+ return false;
+
+ return true;
+ }
+
+ @Override
public boolean endBatchEdit()
{
setClosing(false);
@@ -128,6 +168,7 @@ public class QtInputConnection extends BaseInputConnection
public boolean commitText(CharSequence text, int newCursorPosition)
{
setClosing(false);
+ restartImmInput();
return QtNativeInputConnection.commitText(text.toString(), newCursorPosition);
}
@@ -193,23 +234,25 @@ public class QtInputConnection extends BaseInputConnection
{
switch (id) {
case ID_SELECT_ALL:
+ restartImmInput();
return QtNativeInputConnection.selectAll();
case ID_COPY:
+ restartImmInput();
return QtNativeInputConnection.copy();
case ID_COPY_URL:
+ restartImmInput();
return QtNativeInputConnection.copyURL();
case ID_CUT:
+ restartImmInput();
return QtNativeInputConnection.cut();
case ID_PASTE:
+ restartImmInput();
return QtNativeInputConnection.paste();
-
case ID_SWITCH_INPUT_METHOD:
- InputMethodManager imm = (InputMethodManager)m_view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- if (imm != null)
- imm.showInputMethodPicker();
+ if (m_imm != null)
+ m_imm.showInputMethodPicker();
return true;
-
case ID_ADD_TO_DICTIONARY:
// TODO
// String word = m_editable.subSequence(0, m_editable.length()).toString();
@@ -242,8 +285,7 @@ public class QtInputConnection extends BaseInputConnection
event.getRepeatCount(),
event.getMetaState());
return super.sendKeyEvent(fakeEvent);
-
- case android.view.inputmethod.EditorInfo.IME_ACTION_PREVIOUS:
+ case android.view.inputmethod.EditorInfo.IME_ACTION_PREVIOUS:
fakeEvent = new KeyEvent(event.getDownTime(),
event.getEventTime(),
event.getAction(),
@@ -251,16 +293,14 @@ public class QtInputConnection extends BaseInputConnection
event.getRepeatCount(),
KeyEvent.META_SHIFT_ON);
return super.sendKeyEvent(fakeEvent);
-
case android.view.inputmethod.EditorInfo.IME_FLAG_NO_ENTER_ACTION:
+ restartImmInput();
break;
-
default:
- QtNative.activityDelegate().hideSoftwareKeyboard();
- break;
+ m_qtInputConnectionListener.onSendKeyEventDefaultCase();
+ break;
}
}
-
return super.sendKeyEvent(event);
}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java
new file mode 100644
index 0000000000..cfa273e410
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java
@@ -0,0 +1,654 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.ResultReceiver;
+import android.text.method.MetaKeyKeyListener;
+import android.util.DisplayMetrics;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
+
+import org.qtproject.qt.android.QtInputConnection.QtInputConnectionListener;
+
+/** @noinspection FieldCanBeLocal*/
+class QtInputDelegate implements QtInputConnection.QtInputConnectionListener {
+
+ // keyboard methods
+ public static native void keyDown(int key, int unicode, int modifier, boolean autoRepeat);
+ public static native void keyUp(int key, int unicode, int modifier, boolean autoRepeat);
+ public static native void keyboardVisibilityChanged(boolean visibility);
+ public static native void keyboardGeometryChanged(int x, int y, int width, int height);
+ // keyboard methods
+
+ // dispatch events methods
+ public static native boolean dispatchGenericMotionEvent(MotionEvent event);
+ public static native boolean dispatchKeyEvent(KeyEvent event);
+ // dispatch events methods
+
+ // handle methods
+ public static native void handleLocationChanged(int id, int x, int y);
+ // handle methods
+
+ private QtEditText m_currentEditText = null;
+ private final InputMethodManager m_imm;
+
+ private boolean m_keyboardIsVisible = false;
+ private boolean m_isKeyboardHidingAnimationOngoing = false;
+ private long m_showHideTimeStamp = System.nanoTime();
+ private int m_portraitKeyboardHeight = 0;
+ private int m_landscapeKeyboardHeight = 0;
+ private int m_probeKeyboardHeightDelayMs = 50;
+ private CursorHandle m_cursorHandle;
+ private CursorHandle m_leftSelectionHandle;
+ private CursorHandle m_rightSelectionHandle;
+ private EditPopupMenu m_editPopupMenu;
+
+ private int m_softInputMode = 0;
+
+ // Values coming from QAndroidInputContext::CursorHandleShowMode
+ private static final int CursorHandleNotShown = 0;
+ private static final int CursorHandleShowNormal = 1;
+ private static final int CursorHandleShowSelection = 2;
+ private static final int CursorHandleShowEdit = 0x100;
+
+ // Handle IDs
+ public static final int IdCursorHandle = 1;
+ public static final int IdLeftHandle = 2;
+ public static final int IdRightHandle = 3;
+
+ private static Boolean m_tabletEventSupported = null;
+
+ private static int m_oldX, m_oldY;
+
+
+ private long m_metaState;
+ private int m_lastChar = 0;
+ private boolean m_backKeyPressedSent = false;
+
+ // Note: because of the circular call to updateFullScreen() from the delegate, we need
+ // a listener to be able to do that call from the delegate, because that's where that
+ // logic lives
+ public interface KeyboardVisibilityListener {
+ void onKeyboardVisibilityChange();
+ }
+
+ private final KeyboardVisibilityListener m_keyboardVisibilityListener;
+
+ QtInputDelegate(Activity activity, KeyboardVisibilityListener listener)
+ {
+ this.m_keyboardVisibilityListener = listener;
+ m_imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
+ }
+
+ // QtInputConnectionListener methods
+ @Override
+ public void onSetClosing(boolean closing) {
+ if (!closing)
+ setKeyboardVisibility(true, System.nanoTime());
+ }
+
+ @Override
+ public void onHideKeyboardRunnableDone(boolean visibility, long hideTimeStamp) {
+ setKeyboardVisibility(visibility, hideTimeStamp);
+ }
+
+ @Override
+ public void onSendKeyEventDefaultCase() {
+ hideSoftwareKeyboard();
+ }
+ // QtInputConnectionListener methods
+
+ public boolean isKeyboardVisible()
+ {
+ return m_keyboardIsVisible;
+ }
+
+ // Is the keyboard fully visible i.e. visible and no ongoing animation
+ @UsedFromNativeCode
+ public boolean isSoftwareKeyboardVisible()
+ {
+ return isKeyboardVisible() && !m_isKeyboardHidingAnimationOngoing;
+ }
+
+ void setSoftInputMode(int inputMode)
+ {
+ m_softInputMode = inputMode;
+ }
+
+ QtEditText getCurrentQtEditText()
+ {
+ return m_currentEditText;
+ }
+
+ void setEditPopupMenu(EditPopupMenu editPopupMenu)
+ {
+ m_editPopupMenu = editPopupMenu;
+ }
+
+ private void keyboardVisibilityUpdated(boolean visibility)
+ {
+ m_isKeyboardHidingAnimationOngoing = false;
+ QtInputDelegate.keyboardVisibilityChanged(visibility);
+ }
+
+ public void setKeyboardVisibility(boolean visibility, long timeStamp)
+ {
+ if (m_showHideTimeStamp > timeStamp)
+ return;
+ m_showHideTimeStamp = timeStamp;
+
+ if (m_keyboardIsVisible == visibility)
+ return;
+ m_keyboardIsVisible = visibility;
+ keyboardVisibilityUpdated(m_keyboardIsVisible);
+
+ // Hiding the keyboard clears the immersive mode, so we need to set it again.
+ if (!visibility)
+ m_keyboardVisibilityListener.onKeyboardVisibilityChange();
+
+ }
+
+ @UsedFromNativeCode
+ public void resetSoftwareKeyboard()
+ {
+ if (m_imm == null || m_currentEditText == null)
+ return;
+ m_currentEditText.postDelayed(() -> {
+ m_imm.restartInput(m_currentEditText);
+ m_currentEditText.m_optionsChanged = false;
+ }, 5);
+ }
+
+ void setFocusedView(QtEditText currentEditText)
+ {
+ m_currentEditText = currentEditText;
+ }
+
+ public void showSoftwareKeyboard(Activity activity, QtLayout layout,
+ final int x, final int y, final int width, final int height,
+ final int inputHints, final int enterKeyType)
+ {
+ QtNative.runAction(() -> {
+ if (m_imm == null || m_currentEditText == null)
+ return;
+
+ if (updateSoftInputMode(activity, height))
+ return;
+
+ m_currentEditText.setEditTextOptions(enterKeyType, inputHints);
+
+ m_currentEditText.postDelayed(() -> {
+ m_imm.showSoftInput(m_currentEditText, 0, new ResultReceiver(new Handler()) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ switch (resultCode) {
+ case InputMethodManager.RESULT_SHOWN:
+ QtNativeInputConnection.updateCursorPosition();
+ //FALLTHROUGH
+ case InputMethodManager.RESULT_UNCHANGED_SHOWN:
+ setKeyboardVisibility(true, System.nanoTime());
+ if (m_softInputMode == 0) {
+ probeForKeyboardHeight(layout, activity,
+ x, y, width, height, inputHints, enterKeyType);
+ }
+ break;
+ case InputMethodManager.RESULT_HIDDEN:
+ case InputMethodManager.RESULT_UNCHANGED_HIDDEN:
+ setKeyboardVisibility(false, System.nanoTime());
+ break;
+ }
+ }
+ });
+ if (m_currentEditText.m_optionsChanged) {
+ m_imm.restartInput(m_currentEditText);
+ m_currentEditText.m_optionsChanged = false;
+ }
+ }, 15);
+ });
+ }
+
+ private boolean updateSoftInputMode(Activity activity, int height)
+ {
+ DisplayMetrics metrics = new DisplayMetrics();
+ activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+
+ // If the screen is in portrait mode than we estimate that keyboard height
+ // will not be higher than 2/5 of the screen. Otherwise we estimate that keyboard height
+ // will not be higher than 2/3 of the screen
+ final int visibleHeight;
+ if (metrics.widthPixels < metrics.heightPixels) {
+ visibleHeight = m_portraitKeyboardHeight != 0 ?
+ m_portraitKeyboardHeight : metrics.heightPixels * 3 / 5;
+ } else {
+ visibleHeight = m_landscapeKeyboardHeight != 0 ?
+ m_landscapeKeyboardHeight : metrics.heightPixels / 3;
+ }
+
+ if (m_softInputMode != 0) {
+ activity.getWindow().setSoftInputMode(m_softInputMode);
+ int stateHidden = WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN;
+ return (m_softInputMode & stateHidden) != 0;
+ } else {
+ int stateUnchanged = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED;
+ if (height > visibleHeight) {
+ int adjustResize = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+ activity.getWindow().setSoftInputMode(stateUnchanged | adjustResize);
+ } else {
+ int adjustPan = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
+ activity.getWindow().setSoftInputMode(stateUnchanged | adjustPan);
+ }
+ }
+ return false;
+ }
+
+ private void probeForKeyboardHeight(QtLayout layout, Activity activity, int x, int y,
+ int width, int height, int inputHints, int enterKeyType)
+ {
+ layout.postDelayed(() -> {
+ if (!m_keyboardIsVisible)
+ return;
+ DisplayMetrics metrics = new DisplayMetrics();
+ activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ Rect r = new Rect();
+ activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
+ if (metrics.heightPixels != r.bottom) {
+ if (metrics.widthPixels > metrics.heightPixels) { // landscape
+ if (m_landscapeKeyboardHeight != r.bottom) {
+ m_landscapeKeyboardHeight = r.bottom;
+ showSoftwareKeyboard(activity, layout, x, y, width, height,
+ inputHints, enterKeyType);
+ }
+ } else {
+ if (m_portraitKeyboardHeight != r.bottom) {
+ m_portraitKeyboardHeight = r.bottom;
+ showSoftwareKeyboard(activity, layout, x, y, width, height,
+ inputHints, enterKeyType);
+ }
+ }
+ } else {
+ // no luck ?
+ // maybe the delay was too short, so let's make it longer
+ if (m_probeKeyboardHeightDelayMs < 1000)
+ m_probeKeyboardHeightDelayMs *= 2;
+ }
+ }, m_probeKeyboardHeightDelayMs);
+ }
+
+ public void hideSoftwareKeyboard()
+ {
+ m_isKeyboardHidingAnimationOngoing = true;
+ QtNative.runAction(() -> {
+ if (m_imm == null || m_currentEditText == null)
+ return;
+
+ m_imm.hideSoftInputFromWindow(m_currentEditText.getWindowToken(), 0,
+ new ResultReceiver(new Handler()) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ switch (resultCode) {
+ case InputMethodManager.RESULT_SHOWN:
+ case InputMethodManager.RESULT_UNCHANGED_SHOWN:
+ setKeyboardVisibility(true, System.nanoTime());
+ break;
+ case InputMethodManager.RESULT_HIDDEN:
+ case InputMethodManager.RESULT_UNCHANGED_HIDDEN:
+ setKeyboardVisibility(false, System.nanoTime());
+ break;
+ }
+ }
+ });
+ });
+ }
+
+ @UsedFromNativeCode
+ public void updateSelection(final int selStart, final int selEnd,
+ final int candidatesStart, final int candidatesEnd)
+ {
+ QtNative.runAction(() -> {
+ if (m_imm == null)
+ return;
+
+ m_imm.updateSelection(m_currentEditText, selStart, selEnd, candidatesStart, candidatesEnd);
+ });
+ }
+
+ @UsedFromNativeCode
+ public int getSelectHandleWidth()
+ {
+ int width = 0;
+ if (m_leftSelectionHandle != null && m_rightSelectionHandle != null) {
+ width = Math.max(m_leftSelectionHandle.width(), m_rightSelectionHandle.width());
+ } else if (m_cursorHandle != null) {
+ width = m_cursorHandle.width();
+ }
+ return width;
+ }
+
+ /* called from the C++ code when the position of the cursor or selection handles needs to
+ be adjusted.
+ mode is one of QAndroidInputContext::CursorHandleShowMode
+ */
+ @UsedFromNativeCode
+ public void updateHandles(Activity activity, QtLayout layout, int mode,
+ int editX, int editY, int editButtons,
+ int x1, int y1, int x2, int y2, boolean rtl)
+ {
+ QtNative.runAction(() -> updateHandleImpl(activity, layout, mode, editX, editY, editButtons,
+ x1, y1, x2, y2, rtl));
+ }
+
+ private void updateHandleImpl(Activity activity, QtLayout layout, int mode,
+ int editX, int editY, int editButtons,
+ int x1, int y1, int x2, int y2, boolean rtl)
+ {
+ switch (mode & 0xff)
+ {
+ case CursorHandleNotShown:
+ if (m_cursorHandle != null) {
+ m_cursorHandle.hide();
+ m_cursorHandle = null;
+ }
+ if (m_rightSelectionHandle != null) {
+ m_rightSelectionHandle.hide();
+ m_leftSelectionHandle.hide();
+ m_rightSelectionHandle = null;
+ m_leftSelectionHandle = null;
+ }
+ if (m_editPopupMenu != null)
+ m_editPopupMenu.hide();
+ break;
+
+ case CursorHandleShowNormal:
+ if (m_cursorHandle == null) {
+ m_cursorHandle = new CursorHandle(activity, layout, IdCursorHandle,
+ android.R.attr.textSelectHandle, false);
+ }
+ m_cursorHandle.setPosition(x1, y1);
+ if (m_rightSelectionHandle != null) {
+ m_rightSelectionHandle.hide();
+ m_leftSelectionHandle.hide();
+ m_rightSelectionHandle = null;
+ m_leftSelectionHandle = null;
+ }
+ break;
+
+ case CursorHandleShowSelection:
+ if (m_rightSelectionHandle == null) {
+ m_leftSelectionHandle = new CursorHandle(activity, layout, IdLeftHandle,
+ !rtl ? android.R.attr.textSelectHandleLeft :
+ android.R.attr.textSelectHandleRight,
+ rtl);
+ m_rightSelectionHandle = new CursorHandle(activity, layout, IdRightHandle,
+ !rtl ? android.R.attr.textSelectHandleRight :
+ android.R.attr.textSelectHandleLeft,
+ rtl);
+ }
+ m_leftSelectionHandle.setPosition(x1,y1);
+ m_rightSelectionHandle.setPosition(x2,y2);
+ if (m_cursorHandle != null) {
+ m_cursorHandle.hide();
+ m_cursorHandle = null;
+ }
+ mode |= CursorHandleShowEdit;
+ break;
+ }
+
+ if (!QtClipboardManager.hasClipboardText(activity))
+ editButtons &= ~EditContextView.PASTE_BUTTON;
+
+ if (m_editPopupMenu != null) {
+ if ((mode & CursorHandleShowEdit) == CursorHandleShowEdit && editButtons != 0) {
+ m_editPopupMenu.setPosition(editX, editY, editButtons,
+ m_cursorHandle, m_leftSelectionHandle, m_rightSelectionHandle);
+ } else {
+ m_editPopupMenu.hide();
+ }
+ }
+ }
+
+ public boolean onKeyDown(int keyCode, KeyEvent event)
+ {
+ m_metaState = MetaKeyKeyListener.handleKeyDown(m_metaState, keyCode, event);
+ int metaState = MetaKeyKeyListener.getMetaState(m_metaState) | event.getMetaState();
+ int c = event.getUnicodeChar(metaState);
+ int lc = c;
+ m_metaState = MetaKeyKeyListener.adjustMetaAfterKeypress(m_metaState);
+
+ if ((c & KeyCharacterMap.COMBINING_ACCENT) != 0) {
+ c = c & KeyCharacterMap.COMBINING_ACCENT_MASK;
+ c = KeyEvent.getDeadChar(m_lastChar, c);
+ }
+
+ if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP
+ || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
+ || keyCode == KeyEvent.KEYCODE_MUTE)
+ && System.getenv("QT_ANDROID_VOLUME_KEYS") == null) {
+ return false;
+ }
+
+ m_lastChar = lc;
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ m_backKeyPressedSent = !isKeyboardVisible();
+ if (!m_backKeyPressedSent)
+ return true;
+ }
+
+ QtInputDelegate.keyDown(keyCode, c, event.getMetaState(), event.getRepeatCount() > 0);
+
+ return true;
+ }
+
+ public boolean onKeyUp(int keyCode, KeyEvent event)
+ {
+ if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP
+ || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
+ || keyCode == KeyEvent.KEYCODE_MUTE)
+ && System.getenv("QT_ANDROID_VOLUME_KEYS") == null) {
+ return false;
+ }
+
+ if (keyCode == KeyEvent.KEYCODE_BACK && !m_backKeyPressedSent) {
+ hideSoftwareKeyboard();
+ setKeyboardVisibility(false, System.nanoTime());
+ return true;
+ }
+
+ m_metaState = MetaKeyKeyListener.handleKeyUp(m_metaState, keyCode, event);
+ boolean autoRepeat = event.getRepeatCount() > 0;
+ QtInputDelegate.keyUp(keyCode, event.getUnicodeChar(), event.getMetaState(), autoRepeat);
+
+ return true;
+ }
+
+ public boolean handleDispatchKeyEvent(KeyEvent event)
+ {
+ if (event.getAction() == KeyEvent.ACTION_MULTIPLE
+ && event.getCharacters() != null
+ && event.getCharacters().length() == 1
+ && event.getKeyCode() == 0) {
+ keyDown(0, event.getCharacters().charAt(0), event.getMetaState(),
+ event.getRepeatCount() > 0);
+ keyUp(0, event.getCharacters().charAt(0), event.getMetaState(),
+ event.getRepeatCount() > 0);
+ }
+
+ return dispatchKeyEvent(event);
+ }
+
+ public boolean handleDispatchGenericMotionEvent(MotionEvent event)
+ {
+ return dispatchGenericMotionEvent(event);
+ }
+
+ //////////////////////////////
+ // Mouse and Touch Input //
+ //////////////////////////////
+
+ // tablet methods
+ public static native boolean isTabletEventSupported();
+ public static native void tabletEvent(int winId, int deviceId, long time, int action,
+ int pointerType, int buttonState, float x, float y,
+ float pressure);
+ // tablet methods
+
+ // pointer methods
+ public static native void mouseDown(int winId, int x, int y, int mouseButtonState);
+ public static native void mouseUp(int winId, int x, int y, int mouseButtonState);
+ public static native void mouseMove(int winId, int x, int y);
+ public static native void mouseWheel(int winId, int x, int y, float hDelta, float vDelta);
+ 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 major, float minor, float rotation,
+ float pressure);
+ public static native void touchEnd(int winId, int action);
+ public static native void touchCancel(int winId);
+ public static native void longPress(int winId, int x, int y);
+ // pointer methods
+
+ static private int getAction(int index, MotionEvent event)
+ {
+ int action = event.getActionMasked();
+ if (action == MotionEvent.ACTION_MOVE) {
+ int hsz = event.getHistorySize();
+ if (hsz > 0) {
+ float x = event.getX(index);
+ float y = event.getY(index);
+ for (int h = 0; h < hsz; ++h) {
+ if ( event.getHistoricalX(index, h) != x ||
+ event.getHistoricalY(index, h) != y )
+ return 1;
+ }
+ return 2;
+ }
+ return 1;
+ }
+ if (action == MotionEvent.ACTION_DOWN
+ || action == MotionEvent.ACTION_POINTER_DOWN && index == event.getActionIndex()) {
+ return 0;
+ } else if (action == MotionEvent.ACTION_UP
+ || action == MotionEvent.ACTION_POINTER_UP && index == event.getActionIndex()) {
+ return 3;
+ }
+ return 2;
+ }
+
+ static public void sendTouchEvent(MotionEvent event, int id)
+ {
+ int pointerType = 0;
+
+ if (m_tabletEventSupported == null)
+ m_tabletEventSupported = isTabletEventSupported();
+
+ switch (event.getToolType(0)) {
+ case MotionEvent.TOOL_TYPE_STYLUS:
+ pointerType = 1; // QTabletEvent::Pen
+ break;
+ case MotionEvent.TOOL_TYPE_ERASER:
+ pointerType = 3; // QTabletEvent::Eraser
+ break;
+ }
+
+ if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
+ sendMouseEvent(event, id);
+ } else if (m_tabletEventSupported && pointerType != 0) {
+ tabletEvent(id, event.getDeviceId(), event.getEventTime(), event.getActionMasked(),
+ pointerType, event.getButtonState(),
+ event.getX(), event.getY(), event.getPressure());
+ } else {
+ touchBegin(id);
+ for (int i = 0; i < event.getPointerCount(); ++i) {
+ touchAdd(id,
+ event.getPointerId(i),
+ getAction(i, event),
+ i == 0,
+ (int)event.getX(i),
+ (int)event.getY(i),
+ event.getTouchMajor(i),
+ event.getTouchMinor(i),
+ event.getOrientation(i),
+ event.getPressure(i));
+ }
+
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ touchEnd(id, 0);
+ break;
+
+ case MotionEvent.ACTION_UP:
+ touchEnd(id, 2);
+ break;
+
+ case MotionEvent.ACTION_CANCEL:
+ touchCancel(id);
+ break;
+
+ default:
+ touchEnd(id, 1);
+ }
+ }
+ }
+
+ static public void sendTrackballEvent(MotionEvent event, int id)
+ {
+ sendMouseEvent(event,id);
+ }
+
+ static public boolean sendGenericMotionEvent(MotionEvent event, int id)
+ {
+ int scrollOrHoverMove = MotionEvent.ACTION_SCROLL | MotionEvent.ACTION_HOVER_MOVE;
+ int pointerDeviceModifier = (event.getSource() & InputDevice.SOURCE_CLASS_POINTER);
+ boolean isPointerDevice = pointerDeviceModifier == InputDevice.SOURCE_CLASS_POINTER;
+
+ if ((event.getAction() & scrollOrHoverMove) == 0 || !isPointerDevice )
+ return false;
+
+ return sendMouseEvent(event, id);
+ }
+
+ static public boolean sendMouseEvent(MotionEvent event, int id)
+ {
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_UP:
+ mouseUp(id, (int) event.getX(), (int) event.getY(), event.getButtonState());
+ break;
+
+ case MotionEvent.ACTION_DOWN:
+ mouseDown(id, (int) event.getX(), (int) event.getY(), event.getButtonState());
+ m_oldX = (int) event.getX();
+ m_oldY = (int) event.getY();
+ break;
+ case MotionEvent.ACTION_HOVER_MOVE:
+ case MotionEvent.ACTION_MOVE:
+ if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
+ mouseMove(id, (int) event.getX(), (int) event.getY());
+ } else {
+ int dx = (int) (event.getX() - m_oldX);
+ int dy = (int) (event.getY() - m_oldY);
+ if (Math.abs(dx) > 5 || Math.abs(dy) > 5) {
+ mouseMove(id, (int) event.getX(), (int) event.getY());
+ m_oldX = (int) event.getX();
+ m_oldY = (int) event.getY();
+ }
+ }
+ break;
+ case MotionEvent.ACTION_SCROLL:
+ mouseWheel(id, (int) event.getX(), (int) event.getY(),
+ event.getAxisValue(MotionEvent.AXIS_HSCROLL),
+ event.getAxisValue(MotionEvent.AXIS_VSCROLL));
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtLayout.java b/src/android/jar/src/org/qtproject/qt/android/QtLayout.java
index d7207dc2c5..aedc845014 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtLayout.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtLayout.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
@@ -6,48 +6,19 @@ package org.qtproject.qt.android;
import android.app.Activity;
import android.content.Context;
-import android.graphics.Rect;
import android.os.Build;
-import android.util.Log;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Display;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.view.WindowInsets;
-import android.view.WindowManager;
-import android.graphics.Insets;
-import android.view.WindowMetrics;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-public class QtLayout extends ViewGroup
-{
- private Runnable m_startApplicationRunnable;
+class QtLayout extends ViewGroup {
- private int m_activityDisplayRotation = -1;
- private int m_ownDisplayRotation = -1;
- private int m_nativeOrientation = -1;
-
- public void setActivityDisplayRotation(int rotation)
- {
- m_activityDisplayRotation = rotation;
- }
-
- public void setNativeOrientation(int orientation)
- {
- m_nativeOrientation = orientation;
- }
-
- public int displayRotation()
- {
- return m_ownDisplayRotation;
- }
-
- public QtLayout(Context context, Runnable startRunnable)
+ public QtLayout(Context context)
{
super(context);
- m_startApplicationRunnable = startRunnable;
}
public QtLayout(Context context, AttributeSet attrs)
@@ -61,74 +32,6 @@ public class QtLayout extends ViewGroup
}
@Override
- protected void onSizeChanged (int w, int h, int oldw, int oldh)
- {
- Activity activity = (Activity)getContext();
- if (activity == null)
- return;
-
- final WindowManager windowManager = activity.getWindowManager();
- Display display;
-
- final WindowInsets rootInsets = getRootWindowInsets();
-
- int insetLeft = 0;
- int insetTop = 0;
-
- int maxWidth = 0;
- int maxHeight = 0;
-
- if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
- display = windowManager.getDefaultDisplay();
-
- final DisplayMetrics maxMetrics = new DisplayMetrics();
- display.getRealMetrics(maxMetrics);
- maxWidth = maxMetrics.widthPixels;
- maxHeight = maxMetrics.heightPixels;
-
- insetLeft = rootInsets.getStableInsetLeft();
- insetTop = rootInsets.getStableInsetTop();
- } else {
- display = activity.getDisplay();
-
- final WindowMetrics maxMetrics = windowManager.getMaximumWindowMetrics();
- maxWidth = maxMetrics.getBounds().width();
- maxHeight = maxMetrics.getBounds().height();
-
- insetLeft = rootInsets.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars()).left;
- insetTop = rootInsets.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars()).top;
- }
-
- final DisplayMetrics displayMetrics = activity.getResources().getDisplayMetrics();
- double xdpi = displayMetrics.xdpi;
- double ydpi = displayMetrics.ydpi;
- double density = displayMetrics.density;
- double scaledDensity = displayMetrics.scaledDensity;
- float refreshRate = display.getRefreshRate();
-
- QtNative.setApplicationDisplayMetrics(maxWidth, maxHeight, insetLeft,
- insetTop, w, h,
- xdpi,ydpi,scaledDensity, density,
- refreshRate);
-
- int newRotation = display.getRotation();
- if (m_ownDisplayRotation != m_activityDisplayRotation
- && newRotation == m_activityDisplayRotation) {
- // If the saved rotation value does not match the one from the
- // activity, it means that we got orientation change before size
- // change, and the value was cached. So we need to notify about
- // orientation change now.
- QtNative.handleOrientationChanged(newRotation, m_nativeOrientation);
- }
- m_ownDisplayRotation = newRotation;
-
- if (m_startApplicationRunnable != null) {
- m_startApplicationRunnable.run();
- m_startApplicationRunnable = null;
- }
- }
-
- @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int count = getChildCount();
@@ -146,11 +49,15 @@ public class QtLayout extends ViewGroup
int childRight;
int childBottom;
- QtLayout.LayoutParams lp
- = (QtLayout.LayoutParams) child.getLayoutParams();
-
- childRight = lp.x + child.getMeasuredWidth();
- childBottom = lp.y + child.getMeasuredHeight();
+ if (child.getLayoutParams() instanceof QtLayout.LayoutParams) {
+ QtLayout.LayoutParams lp
+ = (QtLayout.LayoutParams) child.getLayoutParams();
+ childRight = lp.x + child.getMeasuredWidth();
+ childBottom = lp.y + child.getMeasuredHeight();
+ } else {
+ childRight = child.getMeasuredWidth();
+ childBottom = child.getMeasuredHeight();
+ }
maxWidth = Math.max(maxWidth, childRight);
maxHeight = Math.max(maxHeight, childBottom);
@@ -184,7 +91,6 @@ public class QtLayout extends ViewGroup
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
int count = getChildCount();
-
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
@@ -193,10 +99,11 @@ public class QtLayout extends ViewGroup
int childLeft = lp.x;
int childTop = lp.y;
- child.layout(childLeft, childTop,
- childLeft + child.getMeasuredWidth(),
- childTop + child.getMeasuredHeight());
-
+ int childRight = (lp.width == ViewGroup.LayoutParams.MATCH_PARENT) ?
+ r - l : childLeft + child.getMeasuredWidth();
+ int childBottom = (lp.height == ViewGroup.LayoutParams.MATCH_PARENT) ?
+ b - t : childTop + child.getMeasuredHeight();
+ child.layout(childLeft, childTop, childRight, childBottom);
}
}
}
@@ -216,8 +123,7 @@ public class QtLayout extends ViewGroup
/**
* Per-child layout information associated with AbsoluteLayout.
- * See
- * {@link android.R.styleable#AbsoluteLayout_Layout Absolute Layout Attributes}
+ * See {android.R.styleable#AbsoluteLayout_Layout Absolute Layout Attributes}
* for a list of all child view attributes that this class supports.
*/
public static class LayoutParams extends ViewGroup.LayoutParams
@@ -249,6 +155,11 @@ public class QtLayout extends ViewGroup
this.y = y;
}
+ public LayoutParams(int width, int height)
+ {
+ super(width, height);
+ }
+
/**
* {@inheritDoc}
*/
@@ -274,7 +185,7 @@ public class QtLayout extends ViewGroup
/**
* set the layout params on a child view.
- *
+ * <p>
* Note: This function adds the child view if it's not in the
* layout already.
*/
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtLoader.java b/src/android/jar/src/org/qtproject/qt/android/QtLoader.java
new file mode 100644
index 0000000000..a00c4795f7
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtLoader.java
@@ -0,0 +1,558 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (c) 2019, BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ComponentInfo;
+import android.content.res.Resources;
+import android.os.Build;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Objects;
+
+import dalvik.system.DexClassLoader;
+
+abstract class QtLoader {
+
+ protected static final String QtTAG = "QtLoader";
+
+ private final Resources m_resources;
+ private final String m_packageName;
+ private String m_preferredAbi = null;
+ private String m_nativeLibrariesDir = null;
+ private ClassLoader m_classLoader;
+
+ protected final ContextWrapper m_context;
+ protected ComponentInfo m_contextInfo;
+
+ protected String m_mainLibPath;
+ protected String m_mainLibName;
+ protected String m_applicationParameters = "";
+ protected HashMap<String, String> m_environmentVariables = new HashMap<>();
+
+ protected int m_debuggerSleepMs = 0;
+
+ /**
+ * Sets and initialize the basic pieces.
+ * Initializes the class loader since it doesn't rely on anything
+ * other than the context.
+ * Also, we can already initialize the static classes contexts here.
+ **/
+ public QtLoader(ContextWrapper context) {
+ m_context = context;
+ m_resources = m_context.getResources();
+ m_packageName = m_context.getPackageName();
+
+ initClassLoader();
+ initStaticClasses();
+ initContextInfo();
+ }
+
+ /**
+ * Implements the logic for finish the extended context, mostly called
+ * in error cases.
+ **/
+ abstract protected void finish();
+
+ /**
+ * Initializes the context info instance which is used to retrieve
+ * the app metadata from the AndroidManifest.xml or other xml resources.
+ * Some values are dependent on the context being an Activity or Service.
+ **/
+ protected void initContextInfo() {
+ try {
+ Context context = m_context.getBaseContext();
+ if (context instanceof Activity) {
+ m_contextInfo = context.getPackageManager().getActivityInfo(
+ ((Activity)context).getComponentName(), PackageManager.GET_META_DATA);
+ } else if (context instanceof Service) {
+ m_contextInfo = context.getPackageManager().getServiceInfo(
+ new ComponentName(context, context.getClass()),
+ PackageManager.GET_META_DATA);
+ } else {
+ Log.w(QtTAG, "Context is not an instance of Activity or Service, could not get " +
+ "context info for it");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ finish();
+ }
+ }
+
+ /**
+ * Extract the common metadata in the base implementation. And the extended methods
+ * call context specific metadata extraction. This also sets the various environment
+ * variables and application parameters.
+ **/
+ protected void extractContextMetaData() {
+ setEnvironmentVariable("QT_ANDROID_FONTS", "Roboto;Droid Sans;Droid Sans Fallback");
+ String monospaceFonts = "Droid Sans Mono;Droid Sans;Droid Sans Fallback";
+ setEnvironmentVariable("QT_ANDROID_FONTS_MONOSPACE", monospaceFonts);
+ setEnvironmentVariable("QT_ANDROID_FONTS_SERIF", "Droid Serif");
+ setEnvironmentVariable("HOME", m_context.getFilesDir().getAbsolutePath());
+ setEnvironmentVariable("TMPDIR", m_context.getCacheDir().getAbsolutePath());
+ String backgroundRunning = getMetaData("android.app.background_running");
+ setEnvironmentVariable("QT_BLOCK_EVENT_LOOPS_WHEN_SUSPENDED", backgroundRunning);
+ setEnvironmentVariable("QTRACE_LOCATION", getMetaData("android.app.trace_location"));
+ appendApplicationParameters(getMetaData("android.app.arguments"));
+ }
+
+ private ArrayList<String> preferredAbiLibs(String[] libs) {
+ HashMap<String, ArrayList<String>> abiLibs = new HashMap<>();
+ for (String lib : libs) {
+ String[] archLib = lib.split(";", 2);
+ if (m_preferredAbi != null && !archLib[0].equals(m_preferredAbi))
+ continue;
+ if (!abiLibs.containsKey(archLib[0]))
+ abiLibs.put(archLib[0], new ArrayList<>());
+ Objects.requireNonNull(abiLibs.get(archLib[0])).add(archLib[1]);
+ }
+
+ if (m_preferredAbi != null) {
+ if (abiLibs.containsKey(m_preferredAbi)) {
+ return abiLibs.get(m_preferredAbi);
+ }
+ return new ArrayList<>();
+ }
+
+ for (String abi : Build.SUPPORTED_ABIS) {
+ if (abiLibs.containsKey(abi)) {
+ m_preferredAbi = abi;
+ return abiLibs.get(abi);
+ }
+ }
+ return new ArrayList<>();
+ }
+
+ private void initStaticClasses() {
+ Context context = m_context.getBaseContext();
+ boolean isActivity = context instanceof Activity;
+ for (String className : getStaticInitClasses()) {
+ try {
+ Class<?> initClass = m_classLoader.loadClass(className);
+ Object staticInitDataObject = initClass.newInstance(); // create an instance
+
+ if (isActivity) {
+ try {
+ Method m = initClass.getMethod("setActivity", Activity.class, Object.class);
+ m.invoke(staticInitDataObject, (Activity) context, this);
+ } catch (InvocationTargetException | NoSuchMethodException e) {
+ Log.d(QtTAG, "Class " + initClass.getName() + " does not implement " +
+ "setActivity method");
+ }
+ } else {
+ try {
+ Method m = initClass.getMethod("setService", Service.class, Object.class);
+ m.invoke(staticInitDataObject, (Service) context, this);
+ } catch (InvocationTargetException | NoSuchMethodException e) {
+ Log.d(QtTAG, "Class " + initClass.getName() + " does not implement " +
+ "setService method");
+ }
+ }
+
+ try {
+ // For modules that don't need/have setActivity/setService
+ Method m = initClass.getMethod("setContext", Context.class);
+ m.invoke(staticInitDataObject, context);
+ } catch (InvocationTargetException | NoSuchMethodException e) {
+ Log.d(QtTAG, "Class " + initClass.getName() + " does not implement " +
+ "setContext method");
+ }
+ } catch (IllegalAccessException | ClassNotFoundException | InstantiationException e) {
+ Log.d(QtTAG, "Could not instantiate class " + className + ", " + e);
+ }
+ }
+ }
+
+ /**
+ * Initialize the class loader instance and sets it via QtNative.
+ * This would also be used by QJniObject API.
+ **/
+ private void initClassLoader()
+ {
+ // directory where optimized DEX files should be written.
+ String outDexPath = m_context.getDir("outdex", Context.MODE_PRIVATE).getAbsolutePath();
+ String sourceDir = m_context.getApplicationInfo().sourceDir;
+ m_classLoader = new DexClassLoader(sourceDir, outDexPath, null, m_context.getClassLoader());
+ QtNative.setClassLoader(m_classLoader);
+ }
+
+ /**
+ * Returns the context's main library absolute path,
+ * or null if the library hasn't been loaded yet.
+ **/
+ public String getMainLibraryPath() {
+ return m_mainLibPath;
+ }
+
+ /**
+ * Set the name of the main app library to libName, which is the name of the library,
+ * not including the path, target architecture or .so suffix. This matches the target name
+ * of the app target in CMakeLists.txt.
+ * This method can be used when the name is not provided by androiddeployqt, for example when
+ * embedding QML views to a native Android app.
+ **/
+ public void setMainLibraryName(String libName) {
+ m_mainLibName = libName;
+ }
+
+ /**
+ * Returns the context's parameters that are used when calling
+ * the main library's main() function. This is assembled from
+ * a combination of static values and also metadata dependent values.
+ **/
+ public String getApplicationParameters() {
+ return m_applicationParameters;
+ }
+
+ /**
+ * Adds a list of parameters to the internal array list of parameters.
+ * Either a whitespace or a tab is accepted as a separator between parameters.
+ **/
+ public void appendApplicationParameters(String params)
+ {
+ if (params == null || params.isEmpty())
+ return;
+
+ if (!m_applicationParameters.isEmpty())
+ m_applicationParameters += " ";
+ m_applicationParameters += params;
+ }
+
+ /**
+ * Sets a single key/value environment variable pair.
+ **/
+ public void setEnvironmentVariable(String key, String value)
+ {
+ try {
+ android.system.Os.setenv(key, value, true);
+ m_environmentVariables.put(key, value);
+ } catch (Exception e) {
+ Log.e(QtTAG, "Could not set environment variable:" + key + "=" + value);
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Sets a list of keys/values string to as environment variables.
+ * This expects the key/value to be separated by '=', and parameters
+ * to be separated by tabs or space.
+ **/
+ public void setEnvironmentVariables(String environmentVariables)
+ {
+ if (environmentVariables == null || environmentVariables.isEmpty())
+ return;
+
+ environmentVariables = environmentVariables.replaceAll("\t", " ");
+
+ for (String variable : environmentVariables.split(" ")) {
+ String[] keyValue = variable.split("=", 2);
+ if (keyValue.length < 2 || keyValue[0].isEmpty())
+ continue;
+
+ setEnvironmentVariable(keyValue[0], keyValue[1]);
+ }
+ }
+
+ /**
+ * Parses the native libraries dir. If the libraries are part of the APK,
+ * the path is set to the APK extracted libs path.
+ * Otherwise, it looks for the system level dir, that's either set in the Manifest,
+ * the deployment libs.xml.
+ * If none of the above are valid, it falls back to predefined system path.
+ **/
+ private void parseNativeLibrariesDir() {
+ if (isBundleQtLibs()) {
+ String nativeLibraryPrefix = m_context.getApplicationInfo().nativeLibraryDir + "/";
+ File nativeLibraryDir = new File(nativeLibraryPrefix);
+ if (nativeLibraryDir.exists()) {
+ String[] list = nativeLibraryDir.list();
+ if (nativeLibraryDir.isDirectory() && list != null && list.length > 0) {
+ m_nativeLibrariesDir = nativeLibraryPrefix;
+ }
+ }
+ } else {
+ // First check if user has provided system libs prefix in AndroidManifest
+ String systemLibsPrefix = getApplicationMetaData("android.app.system_libs_prefix");
+
+ // If not, check if it's provided by androiddeployqt in libs.xml
+ if (systemLibsPrefix.isEmpty())
+ systemLibsPrefix = getSystemLibsPrefix();
+
+ if (systemLibsPrefix.isEmpty()) {
+ final String SYSTEM_LIB_PATH = "/system/lib/";
+ systemLibsPrefix = SYSTEM_LIB_PATH;
+ Log.e(QtTAG, "Using " + SYSTEM_LIB_PATH + " as default libraries path. "
+ + "It looks like the app is deployed using Unbundled "
+ + "deployment. It may be necessary to specify the path to "
+ + "the directory where Qt libraries are installed using either "
+ + "android.app.system_libs_prefix metadata variable in your "
+ + "AndroidManifest.xml or QT_ANDROID_SYSTEM_LIBS_PATH in your "
+ + "CMakeLists.txt");
+ }
+
+ File systemLibraryDir = new File(systemLibsPrefix);
+ String[] list = systemLibraryDir.list();
+ if (systemLibraryDir.exists()) {
+ if (systemLibraryDir.isDirectory() && list != null && list.length > 0)
+ m_nativeLibrariesDir = systemLibsPrefix;
+ else
+ Log.e(QtTAG, "System library directory " + systemLibsPrefix + " is empty.");
+ } else {
+ Log.e(QtTAG, "System library directory " + systemLibsPrefix + " does not exist.");
+ }
+ }
+
+ if (m_nativeLibrariesDir != null && !m_nativeLibrariesDir.endsWith("/"))
+ m_nativeLibrariesDir += "/";
+ }
+
+ /**
+ * Returns the application level metadata.
+ *
+ * @noinspection SameParameterValue*/
+ private String getApplicationMetaData(String key) {
+ if (m_contextInfo == null)
+ return "";
+
+ ApplicationInfo applicationInfo = m_contextInfo.applicationInfo;
+ if (applicationInfo == null)
+ return "";
+
+ Bundle metadata = applicationInfo.metaData;
+ if (metadata == null || !metadata.containsKey(key))
+ return "";
+
+ return metadata.getString(key);
+ }
+
+ /**
+ * Returns the context level metadata.
+ **/
+ protected String getMetaData(String key) {
+ if (m_contextInfo == null)
+ return "";
+
+ Bundle metadata = m_contextInfo.metaData;
+ if (metadata == null || !metadata.containsKey(key))
+ return "";
+
+ return String.valueOf(metadata.get(key));
+ }
+
+ @SuppressLint("DiscouragedApi")
+ private ArrayList<String> getQtLibrariesList() {
+ int id = m_resources.getIdentifier("qt_libs", "array", m_packageName);
+ return preferredAbiLibs(m_resources.getStringArray(id));
+ }
+
+ @SuppressLint("DiscouragedApi")
+ private boolean useLocalQtLibs() {
+ int id = m_resources.getIdentifier("use_local_qt_libs", "string", m_packageName);
+ return Integer.parseInt(m_resources.getString(id)) == 1;
+ }
+
+ @SuppressLint("DiscouragedApi")
+ private boolean isBundleQtLibs() {
+ int id = m_resources.getIdentifier("bundle_local_qt_libs", "string", m_packageName);
+ return Integer.parseInt(m_resources.getString(id)) == 1;
+ }
+
+ @SuppressLint("DiscouragedApi")
+ private String getSystemLibsPrefix() {
+ int id = m_resources.getIdentifier("system_libs_prefix", "string", m_packageName);
+ return m_resources.getString(id);
+ }
+
+ @SuppressLint("DiscouragedApi")
+ private ArrayList<String> getLocalLibrariesList() {
+ int id = m_resources.getIdentifier("load_local_libs", "array", m_packageName);
+ ArrayList<String> localLibs = new ArrayList<>();
+ for (String arrayItem : preferredAbiLibs(m_resources.getStringArray(id))) {
+ Collections.addAll(localLibs, arrayItem.split(":"));
+ }
+ return localLibs;
+ }
+
+ @SuppressLint("DiscouragedApi")
+ private ArrayList<String> getStaticInitClasses() {
+ int id = m_resources.getIdentifier("static_init_classes", "string", m_packageName);
+ String[] classes = m_resources.getString(id).split(":");
+ ArrayList<String> finalClasses = new ArrayList<>();
+ for (String element : classes) {
+ if (!element.isEmpty()) {
+ finalClasses.add(element);
+ }
+ }
+ return finalClasses;
+ }
+
+ @SuppressLint("DiscouragedApi")
+ private String[] getBundledLibs() {
+ int id = m_resources.getIdentifier("bundled_libs", "array", m_packageName);
+ return m_resources.getStringArray(id);
+ }
+
+ /**
+ * Loads all Qt native bundled libraries and main library.
+ **/
+ public void loadQtLibraries() {
+ if (!useLocalQtLibs()) {
+ Log.w(QtTAG, "Use local Qt libs is false");
+ finish();
+ return;
+ }
+
+ if (m_nativeLibrariesDir == null)
+ parseNativeLibrariesDir();
+
+ if (m_nativeLibrariesDir == null || m_nativeLibrariesDir.isEmpty()) {
+ Log.e(QtTAG, "The native libraries directory is null or empty");
+ finish();
+ return;
+ }
+
+ setEnvironmentVariable("QT_PLUGIN_PATH", m_nativeLibrariesDir);
+ setEnvironmentVariable("QML_PLUGIN_PATH", m_nativeLibrariesDir);
+
+ // Load native Qt APK libraries
+ ArrayList<String> nativeLibraries = getQtLibrariesList();
+ nativeLibraries.addAll(getLocalLibrariesList());
+
+ if (m_debuggerSleepMs > 0) {
+ Log.i(QtTAG, "Sleeping for " + m_debuggerSleepMs +
+ "ms, helping the native debugger to settle. " +
+ "Use the env QT_ANDROID_DEBUGGER_MAIN_THREAD_SLEEP_MS variable to change this value.");
+ QtNative.getQtThread().sleep(m_debuggerSleepMs);
+ }
+
+ if (!loadLibraries(nativeLibraries)) {
+ Log.e(QtTAG, "Loading Qt native libraries failed");
+ finish();
+ return;
+ }
+
+ // add all bundled Qt libs to loader params
+ ArrayList<String> bundledLibraries = new ArrayList<>(preferredAbiLibs(getBundledLibs()));
+ if (!loadLibraries(bundledLibraries)) {
+ Log.e(QtTAG, "Loading Qt bundled libraries failed");
+ finish();
+ return;
+ }
+
+ if (m_mainLibName == null)
+ m_mainLibName = getMetaData("android.app.lib_name");
+ // Load main lib
+ if (!loadMainLibrary(m_mainLibName + "_" + m_preferredAbi)) {
+ Log.e(QtTAG, "Loading main library failed");
+ finish();
+ }
+ }
+
+ // Loading libraries using System.load() uses full lib paths
+ @SuppressLint("UnsafeDynamicallyLoadedCode")
+ private String loadLibraryHelper(String library)
+ {
+ String loadedLib = null;
+ try {
+ File libFile = new File(library);
+ if (libFile.exists()) {
+ System.load(library);
+ loadedLib = library;
+ } else {
+ Log.e(QtTAG, "Can't find '" + library + "'");
+ }
+ } catch (Exception e) {
+ Log.e(QtTAG, "Can't load '" + library + "'", e);
+ }
+
+ return loadedLib;
+ }
+
+ /**
+ * Returns an array with absolute library paths from a list of file names only.
+ **/
+ private ArrayList<String> getLibrariesFullPaths(final ArrayList<String> libraries)
+ {
+ if (libraries == null)
+ return null;
+
+ ArrayList<String> absolutePathLibraries = new ArrayList<>();
+ for (String libName : libraries) {
+ // Add lib and .so to the lib name only if it doesn't already end with .so,
+ // this means some names don't necessarily need to have the lib prefix
+ if (!libName.endsWith(".so")) {
+ libName = libName + ".so";
+ libName = "lib" + libName;
+ }
+
+ File file = new File(m_nativeLibrariesDir + libName);
+ absolutePathLibraries.add(file.getAbsolutePath());
+ }
+
+ return absolutePathLibraries;
+ }
+
+ /**
+ * Loads the main library.
+ * Returns true if loading was successful, and sets the absolute
+ * path to the main library. Otherwise, returns false and the path
+ * to the main library is null.
+ **/
+ private boolean loadMainLibrary(String mainLibName)
+ {
+ ArrayList<String> oneEntryArray = new ArrayList<>(Collections.singletonList(mainLibName));
+ String mainLibPath = getLibrariesFullPaths(oneEntryArray).get(0);
+ final boolean[] success = {true};
+ QtNative.getQtThread().run(() -> {
+ m_mainLibPath = loadLibraryHelper(mainLibPath);
+ if (m_mainLibPath == null)
+ success[0] = false;
+ });
+
+ return success[0];
+ }
+
+ /**
+ * Loads a list of libraries.
+ * Returns true if all libraries were loaded successfully,
+ * and false if any library failed. Stops loading at the first failure.
+ **/
+ @SuppressWarnings("BooleanMethodIsAlwaysInverted")
+ private boolean loadLibraries(final ArrayList<String> libraries)
+ {
+ if (libraries == null)
+ return false;
+
+ ArrayList<String> fullPathLibs = getLibrariesFullPaths(libraries);
+
+ final boolean[] success = {true};
+ QtNative.getQtThread().run(() -> {
+ for (int i = 0; i < fullPathLibs.size(); ++i) {
+ String libName = fullPathLibs.get(i);
+ if (loadLibraryHelper(libName) == null) {
+ success[0] = false;
+ break;
+ }
+ }
+ });
+
+ return success[0];
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtMessageDialogHelper.java b/src/android/jar/src/org/qtproject/qt/android/QtMessageDialogHelper.java
index 26696577b1..e13abbbadd 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtMessageDialogHelper.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtMessageDialogHelper.java
@@ -6,24 +6,23 @@ package org.qtproject.qt.android;
import android.app.Activity;
import android.app.AlertDialog;
+import android.content.ClipData;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.text.ClipboardManager;
+import android.content.ClipboardManager;
import android.text.Html;
import android.text.Spanned;
+import android.util.Log;
import android.util.TypedValue;
import android.view.View;
+import android.view.Window;
import android.widget.Button;
-import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;
-import android.widget.Toast;
import java.util.ArrayList;
@@ -41,7 +40,7 @@ class ButtonStruct implements View.OnClickListener
m_text = Html.fromHtml(text);
}
QtMessageDialogHelper m_dialog;
- private int m_id;
+ private final int m_id;
Spanned m_text;
@Override
@@ -50,7 +49,7 @@ class ButtonStruct implements View.OnClickListener
}
}
-public class QtMessageDialogHelper
+class QtMessageDialogHelper
{
public QtMessageDialogHelper(Activity activity)
@@ -58,7 +57,7 @@ public class QtMessageDialogHelper
m_activity = activity;
}
-
+ @UsedFromNativeCode
public void setStandardIcon(int icon)
{
m_standardIcon = icon;
@@ -70,262 +69,242 @@ public class QtMessageDialogHelper
if (m_standardIcon == 0)
return null;
- try {
- TypedValue typedValue = new TypedValue();
- m_theme.resolveAttribute(android.R.attr.alertDialogIcon, typedValue, true);
- return m_activity.getResources().getDrawable(typedValue.resourceId,
- m_activity.getTheme());
- } catch (Exception e) {
- e.printStackTrace();
- }
-
// Information, Warning, Critical, Question
switch (m_standardIcon)
{
case 1: // Information
- try {
- return m_activity.getResources().getDrawable(android.R.drawable.ic_dialog_info,
- m_activity.getTheme());
- } catch (Exception e) {
- e.printStackTrace();
- }
- break;
+ return m_activity.getResources().getDrawable(android.R.drawable.ic_dialog_info,
+ m_activity.getTheme());
case 2: // Warning
-// try {
-// return Class.forName("android.R$drawable").getDeclaredField("stat_sys_warning").getInt(null);
-// } catch (Exception e) {
-// e.printStackTrace();
-// }
-// break;
+ return m_activity.getResources().getDrawable(android.R.drawable.stat_sys_warning,
+ m_activity.getTheme());
case 3: // Critical
- try {
- return m_activity.getResources().getDrawable(android.R.drawable.ic_dialog_alert,
- m_activity.getTheme());
- } catch (Exception e) {
- e.printStackTrace();
- }
- break;
+ return m_activity.getResources().getDrawable(android.R.drawable.ic_dialog_alert,
+ m_activity.getTheme());
case 4: // Question
- try {
- return m_activity.getResources().getDrawable(android.R.drawable.ic_menu_help,
- m_activity.getTheme());
- } catch (Exception e) {
- e.printStackTrace();
- }
- break;
+ return m_activity.getResources().getDrawable(android.R.drawable.ic_menu_help,
+ m_activity.getTheme());
}
return null;
}
+ @UsedFromNativeCode
public void setTile(String title)
{
m_title = Html.fromHtml(title);
}
+ @UsedFromNativeCode
public void setText(String text)
{
m_text = Html.fromHtml(text);
}
+ @UsedFromNativeCode
public void setInformativeText(String informativeText)
{
m_informativeText = Html.fromHtml(informativeText);
}
+ @UsedFromNativeCode
public void setDetailedText(String text)
{
m_detailedText = Html.fromHtml(text);
}
+ @UsedFromNativeCode
public void addButton(int id, String text)
{
if (m_buttonsList == null)
- m_buttonsList = new ArrayList<ButtonStruct>();
+ m_buttonsList = new ArrayList<>();
m_buttonsList.add(new ButtonStruct(this, id, text));
}
- private Drawable getStyledDrawable(String drawable) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException
+ private Drawable getStyledDrawable(int id)
{
- int[] attrs = {Class.forName("android.R$attr").getDeclaredField(drawable).getInt(null)};
+ int[] attrs = { id };
final TypedArray a = m_theme.obtainStyledAttributes(attrs);
Drawable d = a.getDrawable(0);
a.recycle();
return d;
}
-
+ @UsedFromNativeCode
public void show(long handler)
{
m_handler = handler;
- m_activity.runOnUiThread( new Runnable() {
- @Override
- public void run() {
- if (m_dialog != null && m_dialog.isShowing())
- m_dialog.dismiss();
-
- m_dialog = new AlertDialog.Builder(m_activity).create();
- m_theme = m_dialog.getWindow().getContext().getTheme();
-
- if (m_title != null)
- m_dialog.setTitle(m_title);
- m_dialog.setOnCancelListener( new DialogInterface.OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialogInterface) {
- QtNativeDialogHelper.dialogResult(handler(), -1);
- }
- });
- m_dialog.setCancelable(m_buttonsList == null);
- m_dialog.setCanceledOnTouchOutside(m_buttonsList == null);
- m_dialog.setIcon(getIconDrawable());
- ScrollView scrollView = new ScrollView(m_activity);
- RelativeLayout dialogLayout = new RelativeLayout(m_activity);
- int id = 1;
- View lastView = null;
- View.OnLongClickListener copyText = new View.OnLongClickListener() {
- @Override
- public boolean onLongClick(View view) {
- TextView tv = (TextView)view;
- if (tv != null) {
- ClipboardManager cm = (android.text.ClipboardManager) m_activity.getSystemService(Context.CLIPBOARD_SERVICE);
- cm.setText(tv.getText());
- }
- return true;
- }
- };
- if (m_text != null)
- {
- TextView view = new TextView(m_activity);
- view.setId(id++);
- view.setOnLongClickListener(copyText);
- view.setLongClickable(true);
-
- view.setText(m_text);
- view.setTextAppearance(m_activity, android.R.style.TextAppearance_Medium);
+ m_activity.runOnUiThread(() -> {
+ if (m_dialog != null && m_dialog.isShowing())
+ m_dialog.dismiss();
+
+ m_dialog = new AlertDialog.Builder(m_activity).create();
+ Window window = m_dialog.getWindow();
+ if (window != null)
+ m_theme = window.getContext().getTheme();
+ else
+ Log.w(QtTAG, "show(): cannot set theme from null window!");
+
+ if (m_title != null)
+ m_dialog.setTitle(m_title);
+ m_dialog.setOnCancelListener(dialogInterface -> QtNativeDialogHelper.dialogResult(handler(), -1));
+ m_dialog.setCancelable(m_buttonsList == null);
+ m_dialog.setCanceledOnTouchOutside(m_buttonsList == null);
+ m_dialog.setIcon(getIconDrawable());
+ ScrollView scrollView = new ScrollView(m_activity);
+ RelativeLayout dialogLayout = new RelativeLayout(m_activity);
+ int id = 1;
+ View lastView = null;
+ View.OnLongClickListener copyText = view -> {
+ TextView tv = (TextView)view;
+ if (tv != null) {
+ ClipboardManager cm = (ClipboardManager) m_activity.getSystemService(
+ Context.CLIPBOARD_SERVICE);
+ cm.setPrimaryClip(ClipData.newPlainText(tv.getText(), tv.getText()));
+ }
+ return true;
+ };
+ if (m_text != null)
+ {
+ TextView view = new TextView(m_activity);
+ view.setId(id++);
+ view.setOnLongClickListener(copyText);
+ view.setLongClickable(true);
+
+ view.setText(m_text);
+ view.setTextAppearance(android.R.style.TextAppearance_Medium);
+
+ RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.MATCH_PARENT,
+ RelativeLayout.LayoutParams.WRAP_CONTENT);
+ layout.setMargins(16, 8, 16, 8);
+ layout.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+ dialogLayout.addView(view, layout);
+ lastView = view;
+ }
- RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
- layout.setMargins(16, 8, 16, 8);
+ if (m_informativeText != null)
+ {
+ TextView view= new TextView(m_activity);
+ view.setId(id++);
+ view.setOnLongClickListener(copyText);
+ view.setLongClickable(true);
+
+ view.setText(m_informativeText);
+ view.setTextAppearance(android.R.style.TextAppearance_Medium);
+
+ RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.MATCH_PARENT,
+ RelativeLayout.LayoutParams.WRAP_CONTENT);
+ layout.setMargins(16, 8, 16, 8);
+ if (lastView != null)
+ layout.addRule(RelativeLayout.BELOW, lastView.getId());
+ else
layout.addRule(RelativeLayout.ALIGN_PARENT_TOP);
- dialogLayout.addView(view, layout);
- lastView = view;
- }
+ dialogLayout.addView(view, layout);
+ lastView = view;
+ }
- if (m_informativeText != null)
- {
- TextView view= new TextView(m_activity);
- view.setId(id++);
- view.setOnLongClickListener(copyText);
- view.setLongClickable(true);
-
- view.setText(m_informativeText);
- view.setTextAppearance(m_activity, android.R.style.TextAppearance_Medium);
-
- RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
- layout.setMargins(16, 8, 16, 8);
- if (lastView != null)
- layout.addRule(RelativeLayout.BELOW, lastView.getId());
- else
- layout.addRule(RelativeLayout.ALIGN_PARENT_TOP);
- dialogLayout.addView(view, layout);
- lastView = view;
- }
+ if (m_detailedText != null)
+ {
+ TextView view= new TextView(m_activity);
+ view.setId(id++);
+ view.setOnLongClickListener(copyText);
+ view.setLongClickable(true);
+
+ view.setText(m_detailedText);
+ view.setTextAppearance(android.R.style.TextAppearance_Small);
+
+ RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.MATCH_PARENT,
+ RelativeLayout.LayoutParams.WRAP_CONTENT);
+ layout.setMargins(16, 8, 16, 8);
+ if (lastView != null)
+ layout.addRule(RelativeLayout.BELOW, lastView.getId());
+ else
+ layout.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+ dialogLayout.addView(view, layout);
+ lastView = view;
+ }
- if (m_detailedText != null)
+ if (m_buttonsList != null)
+ {
+ LinearLayout buttonsLayout = new LinearLayout(m_activity);
+ buttonsLayout.setOrientation(LinearLayout.HORIZONTAL);
+ buttonsLayout.setId(id++);
+ boolean firstButton = true;
+ for (ButtonStruct button: m_buttonsList)
{
- TextView view= new TextView(m_activity);
- view.setId(id++);
- view.setOnLongClickListener(copyText);
- view.setLongClickable(true);
-
- view.setText(m_detailedText);
- view.setTextAppearance(m_activity, android.R.style.TextAppearance_Small);
-
- RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
- layout.setMargins(16, 8, 16, 8);
- if (lastView != null)
- layout.addRule(RelativeLayout.BELOW, lastView.getId());
- else
- layout.addRule(RelativeLayout.ALIGN_PARENT_TOP);
- dialogLayout.addView(view, layout);
- lastView = view;
- }
+ Button bv;
+ try {
+ bv = new Button(m_activity, null, android.R.attr.borderlessButtonStyle);
+ } catch (Exception e) {
+ bv = new Button(m_activity);
+ e.printStackTrace();
+ }
- if (m_buttonsList != null)
- {
- LinearLayout buttonsLayout = new LinearLayout(m_activity);
- buttonsLayout.setOrientation(LinearLayout.HORIZONTAL);
- buttonsLayout.setId(id++);
- boolean firstButton = true;
- for (ButtonStruct button: m_buttonsList)
+ bv.setText(button.m_text);
+ bv.setOnClickListener(button);
+ if (!firstButton) // first button
{
- Button bv;
+ View spacer = new View(m_activity);
try {
- bv = new Button(m_activity, null, Class.forName("android.R$attr").getDeclaredField("borderlessButtonStyle").getInt(null));
+ LinearLayout.LayoutParams layout = new LinearLayout.LayoutParams(1,
+ RelativeLayout.LayoutParams.MATCH_PARENT);
+ spacer.setBackground(getStyledDrawable(android.R.attr.dividerVertical));
+ buttonsLayout.addView(spacer, layout);
} catch (Exception e) {
- bv = new Button(m_activity);
e.printStackTrace();
}
-
- bv.setText(button.m_text);
- bv.setOnClickListener(button);
- if (!firstButton) // first button
- {
- LinearLayout.LayoutParams layout = null;
- View spacer = new View(m_activity);
- try {
- layout = new LinearLayout.LayoutParams(1, RelativeLayout.LayoutParams.MATCH_PARENT);
- spacer.setBackgroundDrawable(getStyledDrawable("dividerVertical"));
- buttonsLayout.addView(spacer, layout);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- LinearLayout.LayoutParams layout = null;
- layout = new LinearLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT, 1.0f);
- buttonsLayout.addView(bv, layout);
- firstButton = false;
}
+ LinearLayout.LayoutParams layout = new LinearLayout.LayoutParams(
+ RelativeLayout.LayoutParams.MATCH_PARENT,
+ RelativeLayout.LayoutParams.WRAP_CONTENT, 1.0f);
+ buttonsLayout.addView(bv, layout);
+ firstButton = false;
+ }
- try {
- View horizontalDevider = new View(m_activity);
- horizontalDevider.setId(id++);
- horizontalDevider.setBackgroundDrawable(getStyledDrawable("dividerHorizontal"));
- RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, 1);
- relativeParams.setMargins(0, 10, 0, 0);
- if (lastView != null) {
- relativeParams.addRule(RelativeLayout.BELOW, lastView.getId());
- }
- else
- relativeParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
- dialogLayout.addView(horizontalDevider, relativeParams);
- lastView = horizontalDevider;
- } catch (Exception e) {
- e.printStackTrace();
- }
- RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
+ try {
+ View horizontalDivider = new View(m_activity);
+ horizontalDivider.setId(id);
+ horizontalDivider.setBackground(getStyledDrawable(
+ android.R.attr.dividerHorizontal));
+ RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.MATCH_PARENT, 1);
+ relativeParams.setMargins(0, 10, 0, 0);
if (lastView != null) {
relativeParams.addRule(RelativeLayout.BELOW, lastView.getId());
}
else
relativeParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
- relativeParams.setMargins(2, 0, 2, 0);
- dialogLayout.addView(buttonsLayout, relativeParams);
+ dialogLayout.addView(horizontalDivider, relativeParams);
+ lastView = horizontalDivider;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.MATCH_PARENT,
+ RelativeLayout.LayoutParams.WRAP_CONTENT);
+ if (lastView != null) {
+ relativeParams.addRule(RelativeLayout.BELOW, lastView.getId());
}
- scrollView.addView(dialogLayout);
- m_dialog.setView(scrollView);
- m_dialog.show();
+ else
+ relativeParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+ relativeParams.setMargins(2, 0, 2, 0);
+ dialogLayout.addView(buttonsLayout, relativeParams);
}
+ scrollView.addView(dialogLayout);
+ m_dialog.setView(scrollView);
+ m_dialog.show();
});
}
+ @UsedFromNativeCode
public void hide()
{
- m_activity.runOnUiThread( new Runnable() {
- @Override
- public void run() {
- if (m_dialog != null && m_dialog.isShowing())
- m_dialog.dismiss();
- reset();
- }
+ m_activity.runOnUiThread(() -> {
+ if (m_dialog != null && m_dialog.isShowing())
+ m_dialog.dismiss();
+ reset();
});
}
@@ -346,7 +325,8 @@ public class QtMessageDialogHelper
m_handler = 0;
}
- private Activity m_activity;
+ private static final String QtTAG = "QtMessageDialogHelper";
+ private final Activity m_activity;
private int m_standardIcon = 0;
private Spanned m_title, m_text, m_informativeText, m_detailedText;
private ArrayList<ButtonStruct> m_buttonsList;
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtNative.java b/src/android/jar/src/org/qtproject/qt/android/QtNative.java
index 93bc6d8043..b2a2887ad5 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtNative.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtNative.java
@@ -1,106 +1,56 @@
// Copyright (C) 2016 BogDan Vatra <bogdan@kde.org>
-// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
package org.qtproject.qt.android;
-import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileNotFoundException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Objects;
-import java.util.concurrent.Semaphore;
-
import android.app.Activity;
import android.app.Service;
import android.content.Context;
-import android.content.ContentResolver;
import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ApplicationInfo;
import android.content.UriPermission;
+import android.content.pm.PackageManager;
import android.net.Uri;
-import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
-import android.system.Os;
-import android.content.ClipboardManager;
-import android.content.ClipData;
-import android.content.ClipDescription;
-import android.os.ParcelFileDescriptor;
import android.util.Log;
import android.view.ContextMenu;
-import android.view.KeyEvent;
import android.view.Menu;
-import android.view.MotionEvent;
import android.view.View;
-import android.view.InputDevice;
-import android.view.Display;
-import android.hardware.display.DisplayManager;
-import android.database.Cursor;
-import android.provider.DocumentsContract;
-import java.lang.reflect.Method;
+import java.lang.ref.WeakReference;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
-import java.util.Iterator;
+import java.util.ArrayList;
import java.util.List;
-import javax.net.ssl.TrustManagerFactory;
+import java.util.Objects;
+
import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
-public class QtNative
+class QtNative
{
- private static Activity m_activity = null;
- private static boolean m_activityPaused = false;
- private static Service m_service = null;
- private static QtActivityDelegate m_activityDelegate = null;
- private static QtServiceDelegate m_serviceDelegate = null;
- public static Object m_mainActivityMutex = new Object(); // mutex used to synchronize runnable operations
-
- public static final String QtTAG = "Qt JAVA"; // string used for Log.x
- private static ArrayList<Runnable> m_lostActions = new ArrayList<Runnable>(); // a list containing all actions which could not be performed (e.g. the main activity is destroyed, etc.)
- private static boolean m_started = false;
- private static boolean m_isKeyboardHiding = false;
- private static int m_displayMetricsScreenWidthPixels = 0;
- private static int m_displayMetricsScreenHeightPixels = 0;
- private static int m_displayMetricsAvailableLeftPixels = 0;
- private static int m_displayMetricsAvailableTopPixels = 0;
- private static int m_displayMetricsAvailableWidthPixels = 0;
- private static int m_displayMetricsAvailableHeightPixels = 0;
- private static float m_displayMetricsRefreshRate = 60;
- private static double m_displayMetricsXDpi = .0;
- private static double m_displayMetricsYDpi = .0;
- private static double m_displayMetricsScaledDensity = 1.0;
- private static double m_displayMetricsDensity = 1.0;
- private static int m_oldx, m_oldy;
- private static final int m_moveThreshold = 0;
- private static ClipboardManager m_clipboardManager = null;
- private static Method m_checkSelfPermissionMethod = null;
- private static Boolean m_tabletEventSupported = null;
- private static boolean m_usePrimaryClip = false;
- public static QtThread m_qtThread = new QtThread();
- private static final int KEYBOARD_HEIGHT_THRESHOLD = 100;
-
- private static final String INVALID_OR_NULL_URI_ERROR_MESSAGE = "Received invalid/null Uri";
-
- private static final Runnable runPendingCppRunnablesRunnable = new Runnable() {
- @Override
- public void run() {
- runPendingCppRunnables();
- }
- };
+ private static WeakReference<Activity> m_activity = null;
+ private static WeakReference<Service> m_service = null;
+ public static final Object m_mainActivityMutex = new Object(); // mutex used to synchronize runnable operations
- public static boolean isStarted()
- {
- boolean hasActivity = m_activity != null && m_activityDelegate != null;
- boolean hasService = m_service != null && m_serviceDelegate != null;
- return m_started && (hasActivity || hasService);
- }
+ private static final ApplicationStateDetails m_stateDetails = new ApplicationStateDetails();
+
+ public static final String QtTAG = "Qt JAVA";
+
+ // a list containing all actions which could not be performed (e.g. the main activity is destroyed, etc.)
+ private static final ArrayList<Runnable> m_lostActions = new ArrayList<>();
+ private static final QtThread m_qtThread = new QtThread();
private static ClassLoader m_classLoader = null;
+
+ private static final Runnable runPendingCppRunnablesRunnable = QtNative::runPendingCppRunnables;
+ private static final ArrayList<AppStateDetailsListener> m_appStateListeners = new ArrayList<>();
+ private static final Object m_appStateListenersLock = new Object();
+
+ @UsedFromNativeCode
public static ClassLoader classLoader()
{
return m_classLoader;
@@ -111,35 +61,54 @@ public class QtNative
m_classLoader = classLoader;
}
- public static Activity activity()
+ public static void setActivity(Activity qtMainActivity)
{
synchronized (m_mainActivityMutex) {
- return m_activity;
+ m_activity = new WeakReference<>(qtMainActivity);
}
}
- public static Service service()
+ public static void setService(Service qtMainService)
{
synchronized (m_mainActivityMutex) {
- return m_service;
+ m_service = new WeakReference<>(qtMainService);
}
}
-
- public static QtActivityDelegate activityDelegate()
+ @UsedFromNativeCode
+ public static Activity activity()
{
synchronized (m_mainActivityMutex) {
- return m_activityDelegate;
+ return m_activity != null ? m_activity.get() : null;
}
}
- public static QtServiceDelegate serviceDelegate()
+ public static boolean isActivityValid()
+ {
+ return m_activity != null && m_activity.get() != null;
+ }
+
+ @UsedFromNativeCode
+ public static Service service()
{
synchronized (m_mainActivityMutex) {
- return m_serviceDelegate;
+ return m_service != null ? m_service.get() : null;
}
}
+ public static boolean isServiceValid()
+ {
+ return m_service != null && m_service.get() != null;
+ }
+
+ @UsedFromNativeCode
+ public static Context getContext() {
+ if (isActivityValid())
+ return m_activity.get();
+ return service();
+ }
+
+ @UsedFromNativeCode
public static String[] getStringArray(String joinedString)
{
return joinedString.split(",");
@@ -150,6 +119,7 @@ public class QtNative
return new Exception().getStackTrace()[1].getMethodName() + ": ";
}
+ /** @noinspection SameParameterValue*/
private static Uri getUriWithValidPermission(Context context, String uri, String openMode)
{
Uri parsedUri;
@@ -164,7 +134,7 @@ public class QtNative
String scheme = parsedUri.getScheme();
// We only want to check permissions for content Uris
- if (scheme.compareTo("content") != 0)
+ if (scheme != null && scheme.compareTo("content") != 0)
return parsedUri;
List<UriPermission> permissions = context.getContentResolver().getPersistedUriPermissions();
@@ -177,7 +147,7 @@ public class QtNative
if (!openMode.equals("r"))
isRequestPermission = permissions.get(i).isWritePermission();
- if (iterUri.getPath().equals(uriStr) && isRequestPermission)
+ if (Objects.equals(iterUri.getPath(), uriStr) && isRequestPermission)
return iterUri;
}
@@ -186,16 +156,17 @@ public class QtNative
// and check for SecurityExceptions later
return parsedUri;
} catch (SecurityException e) {
- Log.e(QtTAG, getCurrentMethodNameLog() + e.toString());
+ Log.e(QtTAG, getCurrentMethodNameLog() + e);
return parsedUri;
}
}
+ @UsedFromNativeCode
public static boolean openURL(Context context, String url, String mime)
{
final Uri uri = getUriWithValidPermission(context, url, "r");
if (uri == null) {
- Log.e(QtTAG, getCurrentMethodNameLog() + INVALID_OR_NULL_URI_ERROR_MESSAGE);
+ Log.e(QtTAG, getCurrentMethodNameLog() + "received invalid/null Uri");
return false;
}
@@ -205,165 +176,137 @@ public class QtNative
if (!mime.isEmpty())
intent.setDataAndType(uri, mime);
- activity().startActivity(intent);
+ Activity activity = activity();
+ if (activity == null) {
+ Log.w(QtTAG, "openURL(): The activity reference is null");
+ return false;
+ }
+
+ activity.startActivity(intent);
return true;
} catch (Exception e) {
- Log.e(QtTAG, getCurrentMethodNameLog() + e.toString());
+ Log.e(QtTAG, getCurrentMethodNameLog() + e);
return false;
}
}
- // this method loads full path libs
- public static void loadQtLibraries(final ArrayList<String> libraries)
- {
- m_qtThread.run(new Runnable() {
- @Override
- public void run() {
- if (libraries == null)
- return;
- for (String libName : libraries) {
- try {
- File f = new File(libName);
- if (f.exists())
- System.load(libName);
- else
- Log.i(QtTAG, "Can't find '" + libName + "'");
- } catch (SecurityException e) {
- Log.i(QtTAG, "Can't load '" + libName + "'", e);
- } catch (Exception e) {
- Log.i(QtTAG, "Can't load '" + libName + "'", e);
- }
- }
- }
- });
+ static QtThread getQtThread() {
+ return m_qtThread;
}
- // this method loads bundled libs by name.
- public static void loadBundledLibraries(final ArrayList<String> libraries, final String nativeLibraryDir)
- {
- m_qtThread.run(new Runnable() {
- @Override
- public void run() {
- if (libraries == null)
- return;
+ interface AppStateDetailsListener {
+ default void onAppStateDetailsChanged(ApplicationStateDetails details) {}
+ default void onNativePluginIntegrationReadyChanged(boolean ready) {}
+ }
- for (String libName : libraries) {
- try {
- String libNameTemplate = "lib" + libName + ".so";
- File f = new File(nativeLibraryDir + libNameTemplate);
- if (!f.exists()) {
- Log.i(QtTAG, "Can't find '" + f.getAbsolutePath());
- try {
- ApplicationInfo info = getContext().getApplicationContext().getPackageManager()
- .getApplicationInfo(getContext().getPackageName(), PackageManager.GET_META_DATA);
- String systemLibraryDir = QtNativeLibrariesDir.systemLibrariesDir;
- if (info.metaData.containsKey("android.app.system_libs_prefix"))
- systemLibraryDir = info.metaData.getString("android.app.system_libs_prefix");
- f = new File(systemLibraryDir + libNameTemplate);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- if (f.exists())
- System.load(f.getAbsolutePath());
- else
- Log.i(QtTAG, "Can't find '" + f.getAbsolutePath());
- } catch (Exception e) {
- Log.i(QtTAG, "Can't load '" + libName + "'", e);
- }
- }
- }
- });
+ // Keep in sync with src/corelib/global/qnamespace.h
+ public static class ApplicationState {
+ static final int ApplicationSuspended = 0x0;
+ static final int ApplicationHidden = 0x1;
+ static final int ApplicationInactive = 0x2;
+ static final int ApplicationActive = 0x4;
+ }
+
+ public static class ApplicationStateDetails {
+ int state = ApplicationState.ApplicationSuspended;
+ boolean nativePluginIntegrationReady = false;
+ boolean isStarted = false;
}
- public static String loadMainLibrary(final String mainLibrary, final String nativeLibraryDir)
+ public static ApplicationStateDetails getStateDetails()
{
- final String[] res = new String[1];
- res[0] = null;
- m_qtThread.run(new Runnable() {
- @Override
- public void run() {
- try {
- String mainLibNameTemplate = "lib" + mainLibrary + ".so";
- File f = new File(nativeLibraryDir + mainLibNameTemplate);
- if (!f.exists()) {
- try {
- ApplicationInfo info = getContext().getApplicationContext().getPackageManager()
- .getApplicationInfo(getContext().getPackageName(), PackageManager.GET_META_DATA);
- String systemLibraryDir = QtNativeLibrariesDir.systemLibrariesDir;
- if (info.metaData.containsKey("android.app.system_libs_prefix"))
- systemLibraryDir = info.metaData.getString("android.app.system_libs_prefix");
- f = new File(systemLibraryDir + mainLibNameTemplate);
- } catch (Exception e) {
- e.printStackTrace();
- return;
- }
- }
- if (!f.exists())
- return;
- System.load(f.getAbsolutePath());
- res[0] = f.getAbsolutePath();
- } catch (Exception e) {
- Log.e(QtTAG, "Can't load '" + mainLibrary + "'", e);
- }
- }
- });
- return res[0];
+ return m_stateDetails;
}
- public static void setActivity(Activity qtMainActivity, QtActivityDelegate qtActivityDelegate)
+ public static void setStarted(boolean started)
{
- synchronized (m_mainActivityMutex) {
- m_activity = qtMainActivity;
- m_activityDelegate = qtActivityDelegate;
- }
+ m_stateDetails.isStarted = started;
+ notifyAppStateDetailsChanged(m_stateDetails);
}
- public static void setService(Service qtMainService, QtServiceDelegate qtServiceDelegate)
+ @UsedFromNativeCode
+ public static void notifyNativePluginIntegrationReady(boolean ready)
{
- synchronized (m_mainActivityMutex) {
- m_service = qtMainService;
- m_serviceDelegate = qtServiceDelegate;
- }
+ m_stateDetails.nativePluginIntegrationReady = ready;
+ notifyNativePluginIntegrationReadyChanged(ready);
+ notifyAppStateDetailsChanged(m_stateDetails);
}
public static void setApplicationState(int state)
{
synchronized (m_mainActivityMutex) {
- switch (state) {
- case QtActivityDelegate.ApplicationActive:
- m_activityPaused = false;
- Iterator<Runnable> itr = m_lostActions.iterator();
- while (itr.hasNext())
- runAction(itr.next());
- m_lostActions.clear();
- break;
- default:
- m_activityPaused = true;
- break;
+ m_stateDetails.state = state;
+ if (state == ApplicationState.ApplicationActive) {
+ for (Runnable mLostAction : m_lostActions)
+ runAction(mLostAction);
+ m_lostActions.clear();
}
}
updateApplicationState(state);
+ notifyAppStateDetailsChanged(m_stateDetails);
+ }
+
+ static void registerAppStateListener(AppStateDetailsListener listener) {
+ synchronized (m_appStateListenersLock) {
+ if (!m_appStateListeners.contains(listener))
+ m_appStateListeners.add(listener);
+ }
+ }
+
+ static void unregisterAppStateListener(AppStateDetailsListener listener) {
+ synchronized (m_appStateListenersLock) {
+ m_appStateListeners.remove(listener);
+ }
+ }
+
+ static void notifyNativePluginIntegrationReadyChanged(boolean ready) {
+ synchronized (m_appStateListenersLock) {
+ for (final AppStateDetailsListener listener : m_appStateListeners)
+ listener.onNativePluginIntegrationReadyChanged(ready);
+ }
+ }
+
+ static void notifyAppStateDetailsChanged(ApplicationStateDetails details) {
+ synchronized (m_appStateListenersLock) {
+ for (AppStateDetailsListener listener : m_appStateListeners)
+ listener.onAppStateDetailsChanged(details);
+ }
}
- private static void runAction(Runnable action)
+ // Post a runnable to Main (UI) Thread if the app is active,
+ // otherwise, queue it to be posted when the the app is active again
+ public static void runAction(Runnable action)
+ {
+ runAction(action, true);
+ }
+
+ public static void runAction(Runnable action, boolean queueWhenInactive)
{
synchronized (m_mainActivityMutex) {
final Looper mainLooper = Looper.getMainLooper();
final Handler handler = new Handler(mainLooper);
- final boolean active = (m_activity != null && !m_activityPaused) || m_service != null;
- if (!active || mainLooper == null || !handler.post(action))
- m_lostActions.add(action);
+
+ if (queueWhenInactive) {
+ final boolean isStateVisible =
+ (m_stateDetails.state != ApplicationState.ApplicationSuspended)
+ && (m_stateDetails.state != ApplicationState.ApplicationHidden);
+ final boolean active = (isActivityValid() && isStateVisible) || isServiceValid();
+ if (!active || !handler.post(action))
+ m_lostActions.add(action);
+ } else {
+ handler.post(action);
+ }
}
}
+ @UsedFromNativeCode
private static void runPendingCppRunnablesOnAndroidThread()
{
synchronized (m_mainActivityMutex) {
- if (m_activity != null) {
- if (!m_activityPaused)
- m_activity.runOnUiThread(runPendingCppRunnablesRunnable);
+ if (isActivityValid()) {
+ if (m_stateDetails.state == ApplicationState.ApplicationActive)
+ m_activity.get().runOnUiThread(runPendingCppRunnablesRunnable);
else
runAction(runPendingCppRunnablesRunnable);
} else {
@@ -379,662 +322,54 @@ public class QtNative
}
}
+ @UsedFromNativeCode
private static void setViewVisibility(final View view, final boolean visible)
{
- runAction(new Runnable() {
- @Override
- public void run() {
- view.setVisibility(visible ? View.VISIBLE : View.GONE);
- }
- });
- }
-
- public static Display getDisplay(int displayId)
- {
- Context context = getContext();
- DisplayManager displayManager =
- (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
- if (displayManager != null) {
- return displayManager.getDisplay(displayId);
- }
- return null;
+ runAction(() -> view.setVisibility(visible ? View.VISIBLE : View.GONE));
}
- public static List<Display> getAvailableDisplays()
+ public static void startApplication(String params, String mainLib)
{
- Context context = getContext();
- DisplayManager displayManager =
- (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
- if (displayManager != null) {
- Display[] displays = displayManager.getDisplays();
- return Arrays.asList(displays);
- }
- return new ArrayList<Display>();
- }
-
- public static boolean startApplication(String params, String mainLib) throws Exception
- {
- if (params == null)
- params = "-platform\tandroid";
-
- final boolean[] res = new boolean[1];
- res[0] = false;
synchronized (m_mainActivityMutex) {
- if (params.length() > 0 && !params.startsWith("\t"))
- params = "\t" + params;
- final String qtParams = mainLib + params;
- m_qtThread.run(new Runnable() {
- @Override
- public void run() {
- res[0] = startQtAndroidPlugin(qtParams);
- setDisplayMetrics(
- m_displayMetricsScreenWidthPixels, m_displayMetricsScreenHeightPixels,
- m_displayMetricsAvailableLeftPixels, m_displayMetricsAvailableTopPixels,
- m_displayMetricsAvailableWidthPixels,
- m_displayMetricsAvailableHeightPixels, m_displayMetricsXDpi,
- m_displayMetricsYDpi, m_displayMetricsScaledDensity,
- m_displayMetricsDensity, m_displayMetricsRefreshRate);
- }
- });
- m_qtThread.post(new Runnable() {
- @Override
- public void run() {
- startQtApplication();
- }
+ m_qtThread.run(() -> {
+ final String qtParams = mainLib + " " + params;
+ if (!startQtAndroidPlugin(qtParams))
+ Log.e(QtTAG, "An error occurred while starting the Qt Android plugin");
});
+ m_qtThread.post(QtNative::startQtApplication);
waitForServiceSetup();
- m_started = true;
- }
- return res[0];
- }
-
- public static void setApplicationDisplayMetrics(int screenWidthPixels, int screenHeightPixels,
- int availableLeftPixels, int availableTopPixels,
- int availableWidthPixels,
- int availableHeightPixels, double XDpi,
- double YDpi, double scaledDensity,
- double density, float refreshRate)
- {
- /* Fix buggy dpi report */
- if (XDpi < android.util.DisplayMetrics.DENSITY_LOW)
- XDpi = android.util.DisplayMetrics.DENSITY_LOW;
- if (YDpi < android.util.DisplayMetrics.DENSITY_LOW)
- YDpi = android.util.DisplayMetrics.DENSITY_LOW;
-
- synchronized (m_mainActivityMutex) {
- if (m_started) {
- setDisplayMetrics(screenWidthPixels, screenHeightPixels, availableLeftPixels,
- availableTopPixels, availableWidthPixels, availableHeightPixels,
- XDpi, YDpi, scaledDensity, density, refreshRate);
- } else {
- m_displayMetricsScreenWidthPixels = screenWidthPixels;
- m_displayMetricsScreenHeightPixels = screenHeightPixels;
- m_displayMetricsAvailableLeftPixels = availableLeftPixels;
- m_displayMetricsAvailableTopPixels = availableTopPixels;
- m_displayMetricsAvailableWidthPixels = availableWidthPixels;
- m_displayMetricsAvailableHeightPixels = availableHeightPixels;
- m_displayMetricsXDpi = XDpi;
- m_displayMetricsYDpi = YDpi;
- m_displayMetricsScaledDensity = scaledDensity;
- m_displayMetricsDensity = density;
- m_displayMetricsRefreshRate = refreshRate;
- }
+ m_stateDetails.isStarted = true;
+ notifyAppStateDetailsChanged(m_stateDetails);
}
}
-
-
- // application methods
- public static native boolean startQtAndroidPlugin(String params);
- public static native void startQtApplication();
- public static native void waitForServiceSetup();
- public static native void quitQtCoreApplication();
- public static native void quitQtAndroidPlugin();
- public static native void terminateQt();
- public static native boolean updateNativeActivity();
- // application methods
-
public static void quitApp()
{
- runAction(new Runnable() {
- @Override
- public void run() {
- quitQtAndroidPlugin();
- if (m_activity != null)
- m_activity.finish();
- if (m_service != null)
- m_service.stopSelf();
-
- m_started = false;
- }
+ runAction(() -> {
+ quitQtAndroidPlugin();
+ if (isActivityValid())
+ m_activity.get().finish();
+ if (isServiceValid())
+ m_service.get().stopSelf();
+ m_stateDetails.isStarted = false;
+ notifyAppStateDetailsChanged(m_stateDetails);
});
}
- //@ANDROID-9
- static private int getAction(int index, MotionEvent event)
- {
- int action = event.getActionMasked();
- if (action == MotionEvent.ACTION_MOVE) {
- int hsz = event.getHistorySize();
- if (hsz > 0) {
- float x = event.getX(index);
- float y = event.getY(index);
- for (int h = 0; h < hsz; ++h) {
- if ( event.getHistoricalX(index, h) != x ||
- event.getHistoricalY(index, h) != y )
- return 1;
- }
- return 2;
- }
- return 1;
- }
- if (action == MotionEvent.ACTION_DOWN
- || action == MotionEvent.ACTION_POINTER_DOWN && index == event.getActionIndex()) {
- return 0;
- } else if (action == MotionEvent.ACTION_UP
- || action == MotionEvent.ACTION_POINTER_UP && index == event.getActionIndex()) {
- return 3;
- }
- return 2;
- }
- //@ANDROID-9
-
- static public void sendTouchEvent(MotionEvent event, int id)
- {
- int pointerType = 0;
-
- if (m_tabletEventSupported == null)
- m_tabletEventSupported = isTabletEventSupported();
-
- switch (event.getToolType(0)) {
- case MotionEvent.TOOL_TYPE_STYLUS:
- pointerType = 1; // QTabletEvent::Pen
- break;
- case MotionEvent.TOOL_TYPE_ERASER:
- pointerType = 3; // QTabletEvent::Eraser
- break;
- }
-
- if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
- sendMouseEvent(event, id);
- } else if (m_tabletEventSupported && pointerType != 0) {
- tabletEvent(id, event.getDeviceId(), event.getEventTime(), event.getAction(), pointerType,
- event.getButtonState(), event.getX(), event.getY(), event.getPressure());
- } else {
- touchBegin(id);
- for (int i = 0; i < event.getPointerCount(); ++i) {
- touchAdd(id,
- event.getPointerId(i),
- getAction(i, event),
- i == 0,
- (int)event.getX(i),
- (int)event.getY(i),
- event.getTouchMajor(i),
- event.getTouchMinor(i),
- event.getOrientation(i),
- event.getPressure(i));
- }
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- touchEnd(id, 0);
- break;
-
- case MotionEvent.ACTION_UP:
- touchEnd(id, 2);
- break;
-
- case MotionEvent.ACTION_CANCEL:
- touchCancel(id);
- break;
-
- default:
- touchEnd(id, 1);
- }
- }
- }
-
- static public void sendTrackballEvent(MotionEvent event, int id)
- {
- sendMouseEvent(event,id);
- }
-
- static public boolean sendGenericMotionEvent(MotionEvent event, int id)
- {
- if (((event.getAction() & (MotionEvent.ACTION_SCROLL | MotionEvent.ACTION_HOVER_MOVE)) == 0)
- || (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != InputDevice.SOURCE_CLASS_POINTER) {
- return false;
- }
-
- return sendMouseEvent(event, id);
- }
-
- static public boolean sendMouseEvent(MotionEvent event, int id)
- {
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_UP:
- mouseUp(id, (int) event.getX(), (int) event.getY());
- break;
-
- case MotionEvent.ACTION_DOWN:
- mouseDown(id, (int) event.getX(), (int) event.getY());
- m_oldx = (int) event.getX();
- m_oldy = (int) event.getY();
- break;
- case MotionEvent.ACTION_HOVER_MOVE:
- case MotionEvent.ACTION_MOVE:
- if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
- mouseMove(id, (int) event.getX(), (int) event.getY());
- } else {
- int dx = (int) (event.getX() - m_oldx);
- int dy = (int) (event.getY() - m_oldy);
- if (Math.abs(dx) > 5 || Math.abs(dy) > 5) {
- mouseMove(id, (int) event.getX(), (int) event.getY());
- m_oldx = (int) event.getX();
- m_oldy = (int) event.getY();
- }
- }
- break;
- case MotionEvent.ACTION_SCROLL:
- mouseWheel(id, (int) event.getX(), (int) event.getY(),
- event.getAxisValue(MotionEvent.AXIS_HSCROLL), event.getAxisValue(MotionEvent.AXIS_VSCROLL));
- break;
- default:
- return false;
- }
- return true;
- }
-
- public static Context getContext() {
- if (m_activity != null)
- return m_activity;
- return m_service;
- }
-
+ @UsedFromNativeCode
public static int checkSelfPermission(String permission)
{
- int perm = PackageManager.PERMISSION_DENIED;
synchronized (m_mainActivityMutex) {
Context context = getContext();
PackageManager pm = context.getPackageManager();
- perm = pm.checkPermission(permission, context.getPackageName());
- }
-
- return perm;
- }
-
- private static void updateSelection(final int selStart,
- final int selEnd,
- final int candidatesStart,
- final int candidatesEnd)
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activityDelegate != null)
- m_activityDelegate.updateSelection(selStart, selEnd, candidatesStart, candidatesEnd);
- }
- });
- }
-
- private static int getSelectHandleWidth()
- {
- return m_activityDelegate.getSelectHandleWidth();
- }
-
- private static void updateHandles(final int mode,
- final int editX,
- final int editY,
- final int editButtons,
- final int x1,
- final int y1,
- final int x2,
- final int y2,
- final boolean rtl)
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- m_activityDelegate.updateHandles(mode, editX, editY, editButtons, x1, y1, x2, y2, rtl);
- }
- });
- }
-
- private static void showSoftwareKeyboard(final int x,
- final int y,
- final int width,
- final int height,
- final int inputHints,
- final int enterKeyType)
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activityDelegate != null)
- m_activityDelegate.showSoftwareKeyboard(x, y, width, height, inputHints, enterKeyType);
- }
- });
- }
-
- private static void resetSoftwareKeyboard()
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activityDelegate != null)
- m_activityDelegate.resetSoftwareKeyboard();
- }
- });
- }
-
- private static void hideSoftwareKeyboard()
- {
- m_isKeyboardHiding = true;
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activityDelegate != null)
- m_activityDelegate.hideSoftwareKeyboard();
- }
- });
- }
-
- private static void setSystemUiVisibility(final int systemUiVisibility)
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activityDelegate != null) {
- m_activityDelegate.setSystemUiVisibility(systemUiVisibility);
- }
- updateWindow();
- }
- });
- }
-
- public static boolean isSoftwareKeyboardVisible()
- {
- return m_activityDelegate.isKeyboardVisible() && !m_isKeyboardHiding;
- }
-
- private static void notifyAccessibilityLocationChange(final int viewId)
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activityDelegate != null) {
- m_activityDelegate.notifyAccessibilityLocationChange(viewId);
- }
- }
- });
- }
-
- private static void notifyObjectHide(final int viewId, final int parentId)
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activityDelegate != null) {
- m_activityDelegate.notifyObjectHide(viewId, parentId);
- }
- }
- });
- }
-
- private static void notifyObjectFocus(final int viewId)
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activityDelegate != null) {
- m_activityDelegate.notifyObjectFocus(viewId);
- }
- }
- });
- }
-
- private static void notifyValueChanged(int viewId, String value)
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activityDelegate != null) {
- m_activityDelegate.notifyValueChanged(viewId, value);
- }
- }
- });
- }
-
- private static void notifyScrolledEvent(final int viewId)
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activityDelegate != null) {
- m_activityDelegate.notifyScrolledEvent(viewId);
- }
- }
- });
- }
-
- public static void notifyQtAndroidPluginRunning(final boolean running)
- {
- m_activityDelegate.notifyQtAndroidPluginRunning(running);
- }
-
- private static void registerClipboardManager()
- {
- if (m_service == null || m_activity != null) { // Avoid freezing if only service
- final Semaphore semaphore = new Semaphore(0);
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activity != null)
- m_clipboardManager = (android.content.ClipboardManager) m_activity.getSystemService(Context.CLIPBOARD_SERVICE);
- if (m_clipboardManager != null) {
- m_clipboardManager.addPrimaryClipChangedListener(new ClipboardManager.OnPrimaryClipChangedListener() {
- public void onPrimaryClipChanged() {
- onClipboardDataChanged();
- }
- });
- }
- semaphore.release();
- }
- });
- try {
- semaphore.acquire();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
-
- private static void clearClipData()
- {
- if (m_clipboardManager != null) {
- if (Build.VERSION.SDK_INT >= 28) {
- m_clipboardManager.clearPrimaryClip();
- } else {
- String[] mimeTypes = { ClipDescription.MIMETYPE_UNKNOWN };
- ClipData data = new ClipData("", mimeTypes, new ClipData.Item(new Intent()));
- m_clipboardManager.setPrimaryClip(data);
- }
- }
- m_usePrimaryClip = false;
- }
- private static void setClipboardText(String text)
- {
- if (m_clipboardManager != null) {
- ClipData clipData = ClipData.newPlainText("text/plain", text);
- updatePrimaryClip(clipData);
- }
- }
-
- public static boolean hasClipboardText()
- {
- return hasClipboardMimeType("text/plain");
- }
-
- private static String getClipboardText()
- {
- try {
- if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
- ClipData primaryClip = m_clipboardManager.getPrimaryClip();
- for (int i = 0; i < primaryClip.getItemCount(); ++i)
- if (primaryClip.getItemAt(i).getText() != null)
- return primaryClip.getItemAt(i).getText().toString();
- }
- } catch (Exception e) {
- Log.e(QtTAG, "Failed to get clipboard data", e);
- }
- return "";
- }
-
- private static void updatePrimaryClip(ClipData clipData)
- {
- try {
- if (m_usePrimaryClip) {
- ClipData clip = m_clipboardManager.getPrimaryClip();
- if (Build.VERSION.SDK_INT >= 26) {
- Objects.requireNonNull(clip).addItem(m_activity.getContentResolver(), clipData.getItemAt(0));
- } else {
- Objects.requireNonNull(clip).addItem(clipData.getItemAt(0));
- }
- m_clipboardManager.setPrimaryClip(clip);
- } else {
- m_clipboardManager.setPrimaryClip(clipData);
- m_usePrimaryClip = true;
- }
- } catch (Exception e) {
- Log.e(QtTAG, "Failed to set clipboard data", e);
- }
- }
-
- private static void setClipboardHtml(String text, String html)
- {
- if (m_clipboardManager != null) {
- ClipData clipData = ClipData.newHtmlText("text/html", text, html);
- updatePrimaryClip(clipData);
- }
- }
-
- private static boolean hasClipboardMimeType(String mimeType)
- {
- if (m_clipboardManager == null)
- return false;
-
- ClipDescription description = m_clipboardManager.getPrimaryClipDescription();
- // getPrimaryClipDescription can fail if the app does not have input focus
- if (description == null)
- return false;
-
- for (int i = 0; i < description.getMimeTypeCount(); ++i) {
- String itemMimeType = description.getMimeType(i);
- if (itemMimeType.equals(mimeType))
- return true;
- }
- return false;
- }
-
- public static boolean hasClipboardHtml()
- {
- return hasClipboardMimeType("text/html");
- }
-
- private static String getClipboardHtml()
- {
- try {
- if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
- ClipData primaryClip = m_clipboardManager.getPrimaryClip();
- for (int i = 0; i < primaryClip.getItemCount(); ++i)
- if (primaryClip.getItemAt(i).getHtmlText() != null)
- return primaryClip.getItemAt(i).getHtmlText().toString();
- }
- } catch (Exception e) {
- Log.e(QtTAG, "Failed to get clipboard data", e);
- }
- return "";
- }
-
- private static void setClipboardUri(String uriString)
- {
- if (m_clipboardManager != null) {
- ClipData clipData = ClipData.newUri(m_activity.getContentResolver(), "text/uri-list",
- Uri.parse(uriString));
- updatePrimaryClip(clipData);
+ return pm.checkPermission(permission, context.getPackageName());
}
}
- public static boolean hasClipboardUri()
- {
- return hasClipboardMimeType("text/uri-list");
- }
-
- private static String[] getClipboardUris()
- {
- ArrayList<String> uris = new ArrayList<String>();
- try {
- if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) {
- ClipData primaryClip = m_clipboardManager.getPrimaryClip();
- for (int i = 0; i < primaryClip.getItemCount(); ++i)
- if (primaryClip.getItemAt(i).getUri() != null)
- uris.add(primaryClip.getItemAt(i).getUri().toString());
- }
- } catch (Exception e) {
- Log.e(QtTAG, "Failed to get clipboard data", e);
- }
- String[] strings = new String[uris.size()];
- strings = uris.toArray(strings);
- return strings;
- }
-
- private static void openContextMenu(final int x, final int y, final int w, final int h)
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activityDelegate != null)
- m_activityDelegate.openContextMenu(x, y, w, h);
- }
- });
- }
-
- private static void closeContextMenu()
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activityDelegate != null)
- m_activityDelegate.closeContextMenu();
- }
- });
- }
-
- private static void resetOptionsMenu()
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activityDelegate != null)
- m_activityDelegate.resetOptionsMenu();
- }
- });
- }
-
- private static void openOptionsMenu()
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activity != null)
- m_activity.openOptionsMenu();
- }
- });
- }
-
+ @UsedFromNativeCode
private static byte[][] getSSLCertificates()
{
- ArrayList<byte[]> certificateList = new ArrayList<byte[]>();
+ ArrayList<byte[]> certificateList = new ArrayList<>();
try {
TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
@@ -1045,7 +380,7 @@ public class QtNative
X509TrustManager trustManager = (X509TrustManager) manager;
for (X509Certificate certificate : trustManager.getAcceptedIssuers()) {
- byte buffer[] = certificate.getEncoded();
+ byte[] buffer = certificate.getEncoded();
certificateList.add(buffer);
}
}
@@ -1059,105 +394,13 @@ public class QtNative
return certificateArray;
}
- private static void createSurface(final int id, final boolean onTop, final int x, final int y, final int w, final int h, final int imageDepth)
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activityDelegate != null)
- m_activityDelegate.createSurface(id, onTop, x, y, w, h, imageDepth);
- }
- });
- }
-
- private static void insertNativeView(final int id, final View view, final int x, final int y, final int w, final int h)
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activityDelegate != null)
- m_activityDelegate.insertNativeView(id, view, x, y, w, h);
- }
- });
- }
-
- private static void setSurfaceGeometry(final int id, final int x, final int y, final int w, final int h)
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activityDelegate != null)
- m_activityDelegate.setSurfaceGeometry(id, x, y, w, h);
- }
- });
- }
-
- private static void bringChildToFront(final int id)
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activityDelegate != null)
- m_activityDelegate.bringChildToFront(id);
- }
- });
- }
-
- private static void bringChildToBack(final int id)
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activityDelegate != null)
- m_activityDelegate.bringChildToBack(id);
- }
- });
- }
-
- private static void destroySurface(final int id)
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activityDelegate != null)
- m_activityDelegate.destroySurface(id);
- }
- });
- }
-
- private static void initializeAccessibility()
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- m_activityDelegate.initializeAccessibility();
- }
- });
- }
-
- private static void hideSplashScreen(final int duration)
- {
- runAction(new Runnable() {
- @Override
- public void run() {
- if (m_activityDelegate != null)
- m_activityDelegate.hideSplashScreen(duration);
- }
- });
- }
-
- public static void keyboardVisibilityUpdated(boolean visibility)
- {
- m_isKeyboardHiding = false;
- keyboardVisibilityChanged(visibility);
- }
-
+ @UsedFromNativeCode
private static String[] listAssetContent(android.content.res.AssetManager asset, String path) {
String [] list;
- ArrayList<String> res = new ArrayList<String>();
+ ArrayList<String> res = new ArrayList<>();
try {
list = asset.list(path);
- if (list.length > 0) {
+ if (list != null) {
for (String file : list) {
try {
String[] isDir = asset.list(path.length() > 0 ? path + "/" + file : file);
@@ -1172,95 +415,21 @@ public class QtNative
} catch (Exception e) {
e.printStackTrace();
}
- return res.toArray(new String[res.size()]);
- }
-
- /**
- *Sets a single environment variable
- *
- * returns true if the value was set, false otherwise.
- * in case it cannot set value will log the exception
- **/
- public static void setEnvironmentVariable(String key, String value)
- {
- try {
- android.system.Os.setenv(key, value, true);
- } catch (Exception e) {
- Log.e(QtNative.QtTAG, "Could not set environment variable:" + key + "=" + value);
- e.printStackTrace();
- }
+ return res.toArray(new String[0]);
}
- /**
- *Sets multiple environment variables
- *
- * Uses '\t' as divider between variables and '=' between key/value
- * Ex: key1=val1\tkey2=val2\tkey3=val3
- * Note: it assumed that the key cannot have '=' but the value can
- **/
- public static void setEnvironmentVariables(String environmentVariables)
- {
- for (String variable : environmentVariables.split("\t")) {
- String[] keyvalue = variable.split("=", 2);
- if (keyvalue.length < 2 || keyvalue[0].isEmpty())
- continue;
-
- setEnvironmentVariable(keyvalue[0], keyvalue[1]);
- }
- }
-
- // screen methods
- public static native void setDisplayMetrics(int screenWidthPixels, int screenHeightPixels,
- int availableLeftPixels, int availableTopPixels,
- int availableWidthPixels, int availableHeightPixels,
- double XDpi, double YDpi, double scaledDensity,
- double density, float refreshRate);
- public static native void handleOrientationChanged(int newRotation, int nativeOrientation);
- public static native void handleRefreshRateChanged(float refreshRate);
- public static native void handleScreenAdded(int displayId);
- public static native void handleScreenChanged(int displayId);
- public static native void handleScreenRemoved(int displayId);
- // screen methods
- public static native void handleUiDarkModeChanged(int newUiMode);
-
- // pointer methods
- public static native void mouseDown(int winId, int x, int y);
- 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 mouseWheel(int winId, int x, int y, float hdelta, float vdelta);
- 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 major, float minor, float rotation, float pressure);
- public static native void touchEnd(int winId, int action);
- public static native void touchCancel(int winId);
- public static native void longPress(int winId, int x, int y);
- // pointer methods
-
- // tablet methods
- public static native boolean isTabletEventSupported();
- public static native void tabletEvent(int winId, int deviceId, long time, int action, int pointerType, int buttonState, float x, float y, float pressure);
- // tablet methods
-
- // keyboard methods
- public static native void keyDown(int key, int unicode, int modifier, boolean autoRepeat);
- public static native void keyUp(int key, int unicode, int modifier, boolean autoRepeat);
- public static native void keyboardVisibilityChanged(boolean visibility);
- public static native void keyboardGeometryChanged(int x, int y, int width, int height);
- // keyboard methods
-
- // handle methods
- public static final int IdCursorHandle = 1;
- public static final int IdLeftHandle = 2;
- public static final int IdRightHandle = 3;
- public static native void handleLocationChanged(int id, int x, int y);
- // handle methods
-
- // dispatch events methods
- public static native boolean dispatchGenericMotionEvent(MotionEvent ev);
- public static native boolean dispatchKeyEvent(KeyEvent event);
- // dispatch events methods
+ // application methods
+ public static native boolean startQtAndroidPlugin(String params);
+ public static native void startQtApplication();
+ public static native void waitForServiceSetup();
+ public static native void quitQtCoreApplication();
+ public static native void quitQtAndroidPlugin();
+ public static native void terminateQt();
+ public static native boolean updateNativeActivity();
+ // application methods
// surface methods
- public static native void setSurface(int id, Object surface, int w, int h);
+ public static native void setSurface(int id, Object surface);
// surface methods
// window methods
@@ -1281,10 +450,6 @@ public class QtNative
public static native void onContextMenuClosed(Menu menu);
// menu methods
- // clipboard methods
- public static native void onClipboardDataChanged();
- // clipboard methods
-
// activity methods
public static native void onActivityResult(int requestCode, int resultCode, Intent data);
public static native void onNewIntent(Intent data);
diff --git a/src/android/jar/src/org/qtproject/qt/android/accessibility/QtNativeAccessibility.java b/src/android/jar/src/org/qtproject/qt/android/QtNativeAccessibility.java
index d4cce935ba..dd2cead8cd 100644
--- a/src/android/jar/src/org/qtproject/qt/android/accessibility/QtNativeAccessibility.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtNativeAccessibility.java
@@ -1,7 +1,7 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-package org.qtproject.qt.android.accessibility;
+package org.qtproject.qt.android;
import android.graphics.Rect;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -19,5 +19,4 @@ class QtNativeAccessibility
static native boolean scrollBackward(int objectId);
static native boolean populateNode(int objectId, AccessibilityNodeInfo node);
- static native String valueForAccessibleObject(int objectId);
}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtNativeLibrariesDir.java b/src/android/jar/src/org/qtproject/qt/android/QtNativeLibrariesDir.java
deleted file mode 100644
index b857e7b607..0000000000
--- a/src/android/jar/src/org/qtproject/qt/android/QtNativeLibrariesDir.java
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-package org.qtproject.qt.android;
-
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
-
-public class QtNativeLibrariesDir {
- public static final String systemLibrariesDir = "/system/lib/";
- public static String nativeLibrariesDir(Context context)
- {
- String m_nativeLibraryDir = null;
- try {
- ApplicationInfo ai = context.getPackageManager().getApplicationInfo(context.getPackageName(), 0);
- m_nativeLibraryDir = ai.nativeLibraryDir + "/";
- } catch (NameNotFoundException e) {
- e.printStackTrace();
- }
- return m_nativeLibraryDir;
- }
-}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtRootLayout.java b/src/android/jar/src/org/qtproject/qt/android/QtRootLayout.java
new file mode 100644
index 0000000000..3dae587a71
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtRootLayout.java
@@ -0,0 +1,98 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Build;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.content.res.Configuration;
+import android.view.Surface;
+
+/**
+ A layout which corresponds to one Activity, i.e. is the root layout where the top level window
+ and handles orientation changes.
+*/
+public class QtRootLayout extends QtLayout
+{
+ private int m_activityDisplayRotation = -1;
+ private int m_ownDisplayRotation = -1;
+ private int m_nativeOrientation = -1;
+ private int m_previousRotation = -1;
+
+ public QtRootLayout(Context context)
+ {
+ super(context);
+ }
+
+ public void setActivityDisplayRotation(int rotation)
+ {
+ m_activityDisplayRotation = rotation;
+ }
+
+ public void setNativeOrientation(int orientation)
+ {
+ m_nativeOrientation = orientation;
+ }
+
+ public int displayRotation()
+ {
+ return m_ownDisplayRotation;
+ }
+
+ @Override
+ protected void onSizeChanged (int w, int h, int oldw, int oldh)
+ {
+ Activity activity = (Activity)getContext();
+ if (activity == null)
+ return;
+
+ DisplayMetrics realMetrics = new DisplayMetrics();
+ Display display = (Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
+ ? activity.getWindowManager().getDefaultDisplay()
+ : activity.getDisplay();
+
+ if (display == null)
+ return;
+
+ display.getRealMetrics(realMetrics);
+ if ((realMetrics.widthPixels > realMetrics.heightPixels) != (w > h)) {
+ // This is an intermediate state during display rotation.
+ // The new size is still reported for old orientation, while
+ // realMetrics contain sizes for new orientation. Setting
+ // such parameters will produce inconsistent results, so
+ // we just skip them.
+ // We will have another onSizeChanged() with normal values
+ // a bit later.
+ return;
+ }
+ QtDisplayManager.setApplicationDisplayMetrics(activity, w, h);
+ QtDisplayManager.handleOrientationChanges(activity);
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration configuration)
+ {
+ Context context = getContext();
+ if (context instanceof Activity) {
+ Activity activity = (Activity)context;
+ //if orientation change is betwen invertedPortrait and portrait or
+ //invertedLandscape and landscape, we do not get sizeChanged callback.
+ int rotation = QtDisplayManager.getDisplayRotation(activity);
+ if (isSameSizeForOrientations(rotation, m_previousRotation))
+ QtDisplayManager.handleOrientationChanges(activity);
+ m_previousRotation = rotation;
+ }
+ }
+
+ public boolean isSameSizeForOrientations(int r1, int r2) {
+ return (r1 == r2) ||
+ (r1 == Surface.ROTATION_0 && r2 == Surface.ROTATION_180)
+ || (r1 == Surface.ROTATION_180 && r2 == Surface.ROTATION_0)
+ || (r1 == Surface.ROTATION_90 && r2 == Surface.ROTATION_270)
+ || (r1 == Surface.ROTATION_270 && r2 == Surface.ROTATION_90);
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtServiceBase.java b/src/android/jar/src/org/qtproject/qt/android/QtServiceBase.java
new file mode 100644
index 0000000000..b69dea4416
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtServiceBase.java
@@ -0,0 +1,51 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.util.Log;
+
+public class QtServiceBase extends Service {
+ @Override
+ public void onCreate()
+ {
+ super.onCreate();
+
+ // the application has already started, do not reload everything again
+ if (QtNative.getStateDetails().isStarted) {
+ Log.w(QtNative.QtTAG,
+ "A QtService tried to start in the same process as an initiated " +
+ "QtActivity. That is not supported. This results in the service " +
+ "functioning as an Android Service detached from Qt.");
+ return;
+ }
+
+ QtNative.setService(this);
+
+ QtServiceLoader loader = new QtServiceLoader(this);
+ loader.loadQtLibraries();
+ QtNative.startApplication(loader.getApplicationParameters(), loader.getMainLibraryPath());
+ QtNative.setApplicationState(QtNative.ApplicationState.ApplicationHidden);
+ }
+
+ @Override
+ public void onDestroy()
+ {
+ super.onDestroy();
+ QtNative.quitQtCoreApplication();
+ QtNative.terminateQt();
+ QtNative.setService(null);
+ QtNative.getQtThread().exit();
+ System.exit(0);
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ synchronized (this) {
+ return QtNative.onBind(intent);
+ }
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtServiceDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtServiceDelegate.java
deleted file mode 100644
index 4836985cfc..0000000000
--- a/src/android/jar/src/org/qtproject/qt/android/QtServiceDelegate.java
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright (C) 2016 BogDan Vatra <bogdan@kde.org>
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-package org.qtproject.qt.android;
-
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Configuration;
-import android.graphics.drawable.ColorDrawable;
-import android.net.LocalServerSocket;
-import android.net.LocalSocket;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.ResultReceiver;
-import android.text.method.MetaKeyKeyListener;
-import android.util.Base64;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.Surface;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.inputmethod.InputMethodManager;
-
-import java.io.BufferedReader;
-import java.io.DataOutputStream;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.InputStreamReader;
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Objects;
-
-public class QtServiceDelegate
-{
- private static final String NATIVE_LIBRARIES_KEY = "native.libraries";
- private static final String BUNDLED_LIBRARIES_KEY = "bundled.libraries";
- private static final String MAIN_LIBRARY_KEY = "main.library";
- private static final String ENVIRONMENT_VARIABLES_KEY = "environment.variables";
- private static final String APPLICATION_PARAMETERS_KEY = "application.parameters";
- private static final String STATIC_INIT_CLASSES_KEY = "static.init.classes";
- private static final String APP_DISPLAY_METRIC_SCREEN_DESKTOP_KEY = "display.screen.desktop";
- private static final String APP_DISPLAY_METRIC_SCREEN_XDPI_KEY = "display.screen.dpi.x";
- private static final String APP_DISPLAY_METRIC_SCREEN_YDPI_KEY = "display.screen.dpi.y";
- private static final String APP_DISPLAY_METRIC_SCREEN_DENSITY_KEY = "display.screen.density";
-
- private String m_mainLib = null;
- private Service m_service = null;
- private static String m_applicationParameters = null;
-
- public boolean loadApplication(Service service, ClassLoader classLoader, Bundle loaderParams)
- {
- /// check parameters integrity
- if (!loaderParams.containsKey(NATIVE_LIBRARIES_KEY)
- || !loaderParams.containsKey(BUNDLED_LIBRARIES_KEY)) {
- return false;
- }
-
- m_service = service;
- QtNative.setService(m_service, this);
- QtNative.setClassLoader(classLoader);
-
- QtNative.setApplicationDisplayMetrics(10, 10, 0, 0, 10, 10, 120, 120, 1.0, 1.0, 60.0f);
-
- if (loaderParams.containsKey(STATIC_INIT_CLASSES_KEY)) {
- for (String className :
- Objects.requireNonNull(loaderParams.getStringArray(STATIC_INIT_CLASSES_KEY))) {
- if (className.length() == 0)
- continue;
- try {
- Class<?> initClass = classLoader.loadClass(className);
- Object staticInitDataObject = initClass.newInstance(); // create an instance
- try {
- Method m = initClass.getMethod("setService", Service.class, Object.class);
- m.invoke(staticInitDataObject, m_service, this);
- } catch (Exception e) {
- Log.d(QtNative.QtTAG,
- "Class " + className + " does not implement setService method");
- }
-
- // For modules that don't need/have setService
- try {
- Method m = initClass.getMethod("setContext", Context.class);
- m.invoke(staticInitDataObject, (Context)m_service);
- } catch (Exception e) {
- e.printStackTrace();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- QtNative.loadQtLibraries(loaderParams.getStringArrayList(NATIVE_LIBRARIES_KEY));
- ArrayList<String> libraries = loaderParams.getStringArrayList(BUNDLED_LIBRARIES_KEY);
- String nativeLibsDir = QtNativeLibrariesDir.nativeLibrariesDir(m_service);
- QtNative.loadBundledLibraries(libraries, nativeLibsDir);
- m_mainLib = loaderParams.getString(MAIN_LIBRARY_KEY);
-
- QtNative.setEnvironmentVariables(loaderParams.getString(ENVIRONMENT_VARIABLES_KEY));
- QtNative.setEnvironmentVariable("QT_ANDROID_FONTS_MONOSPACE",
- "Droid Sans Mono;Droid Sans;Droid Sans Fallback");
- QtNative.setEnvironmentVariable("QT_ANDROID_FONTS_SERIF", "Droid Serif");
- QtNative.setEnvironmentVariable("HOME", m_service.getFilesDir().getAbsolutePath());
- QtNative.setEnvironmentVariable("TMPDIR", m_service.getCacheDir().getAbsolutePath());
- QtNative.setEnvironmentVariable("QT_ANDROID_FONTS",
- "Roboto;Droid Sans;Droid Sans Fallback");
-
- if (loaderParams.containsKey(APPLICATION_PARAMETERS_KEY))
- m_applicationParameters = loaderParams.getString(APPLICATION_PARAMETERS_KEY);
- else
- m_applicationParameters = "";
-
- m_mainLib = QtNative.loadMainLibrary(m_mainLib, nativeLibsDir);
- return m_mainLib != null;
- }
-
- public boolean startApplication()
- {
- // start application
- try {
- String nativeLibraryDir = QtNativeLibrariesDir.nativeLibrariesDir(m_service);
- QtNative.startApplication(m_applicationParameters, m_mainLib);
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
-
- public void onDestroy()
- {
- QtNative.quitQtCoreApplication();
- QtNative.terminateQt();
- QtNative.setService(null, null);
- QtNative.m_qtThread.exit();
- System.exit(0);
- }
-
- public IBinder onBind(Intent intent)
- {
- synchronized (this) {
- return QtNative.onBind(intent);
- }
- }
-}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java
new file mode 100644
index 0000000000..29f1d1790f
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java
@@ -0,0 +1,115 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import static org.qtproject.qt.android.QtNative.ApplicationState.ApplicationSuspended;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.display.DisplayManager;
+import android.view.Display;
+import android.view.View;
+import android.util.DisplayMetrics;
+
+/**
+ * QtServiceEmbeddedDelegate is used for embedding QML into Android Service contexts. Implements
+ * {@link QtEmbeddedViewInterface} so it can be used by QtView to communicate with the Qt layer.
+ */
+class QtServiceEmbeddedDelegate implements QtEmbeddedViewInterface, QtNative.AppStateDetailsListener
+{
+ private final Service m_service;
+ private QtView m_view;
+ private boolean m_windowLoaded = false;
+
+ QtServiceEmbeddedDelegate(Service service)
+ {
+ m_service = service;
+ QtNative.registerAppStateListener(this);
+ QtNative.setService(service);
+ }
+
+ @UsedFromNativeCode
+ QtInputDelegate getInputDelegate()
+ {
+ // TODO Implement text input (QTBUG-122552)
+ return null;
+ }
+
+ @Override
+ public void onNativePluginIntegrationReadyChanged(boolean ready)
+ {
+ synchronized (this) {
+ if (ready) {
+ QtNative.runAction(() -> {
+ if (m_view == null)
+ return;
+
+ final DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
+
+ final int maxWidth = m_view.getWidth();
+ final int maxHeight = m_view.getHeight();
+ final int width = maxWidth;
+ final int height = maxHeight;
+ final int insetLeft = m_view.getLeft();
+ final int insetTop = m_view.getTop();
+
+ final DisplayManager dm = m_service.getSystemService(DisplayManager.class);
+ QtDisplayManager.setDisplayMetrics(
+ maxWidth, maxHeight, insetLeft, insetTop, width, height,
+ QtDisplayManager.getXDpi(metrics), QtDisplayManager.getYDpi(metrics),
+ metrics.scaledDensity, metrics.density,
+ QtDisplayManager.getRefreshRate(
+ dm.getDisplay(Display.DEFAULT_DISPLAY)));
+ });
+ createRootWindow();
+ }
+ }
+ }
+
+ // QtEmbeddedViewInterface implementation begin
+ @Override
+ public void startQtApplication(String appParams, String mainLib)
+ {
+ QtNative.startApplication(appParams, mainLib);
+ }
+
+ @Override
+ public void setView(QtView view)
+ {
+ m_view = view;
+ // If the embedded view is destroyed, do cleanup:
+ if (view == null)
+ cleanup();
+ }
+
+ @Override
+ public void queueLoadWindow()
+ {
+ synchronized (this) {
+ if (QtNative.getStateDetails().nativePluginIntegrationReady)
+ createRootWindow();
+ }
+ }
+ // QtEmbeddedViewInterface implementation end
+
+ private void createRootWindow()
+ {
+ if (m_view != null && !m_windowLoaded) {
+ QtView.createRootWindow(m_view, m_view.getLeft(), m_view.getTop(), m_view.getWidth(),
+ m_view.getHeight());
+ m_windowLoaded = true;
+ }
+ }
+
+ private void cleanup()
+ {
+ QtNative.setApplicationState(ApplicationSuspended);
+ QtNative.unregisterAppStateListener(QtServiceEmbeddedDelegate.this);
+
+ QtNative.terminateQt();
+ QtNative.setService(null);
+ QtNative.getQtThread().exit();
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtServiceLoader.java b/src/android/jar/src/org/qtproject/qt/android/QtServiceLoader.java
new file mode 100644
index 0000000000..ce74ec21e7
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtServiceLoader.java
@@ -0,0 +1,28 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (c) 2016, BogDan Vatra <bogdan@kde.org>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.app.Service;
+import android.content.ContextWrapper;
+import android.util.Log;
+
+class QtServiceLoader extends QtLoader {
+ private final Service m_service;
+
+ public QtServiceLoader(Service service) {
+ super(new ContextWrapper(service));
+ m_service = service;
+
+ extractContextMetaData();
+ }
+
+ @Override
+ protected void finish() {
+ if (m_service != null)
+ m_service.stopSelf();
+ else
+ Log.w(QtTAG, "finish() called when service object is null");
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtSurface.java b/src/android/jar/src/org/qtproject/qt/android/QtSurface.java
index 42830783e7..3165de4811 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtSurface.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtSurface.java
@@ -4,42 +4,30 @@
package org.qtproject.qt.android;
-import android.app.Activity;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.PixelFormat;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
+import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-
-public class QtSurface extends SurfaceView implements SurfaceHolder.Callback
+@SuppressLint("ViewConstructor")
+class QtSurface extends SurfaceView implements SurfaceHolder.Callback
{
- private GestureDetector m_gestureDetector;
- private Object m_accessibilityDelegate = null;
+ private QtSurfaceInterface m_surfaceCallback;
- public QtSurface(Context context, int id, boolean onTop, int imageDepth)
+ public QtSurface(Context context, QtSurfaceInterface surfaceCallback, boolean onTop, int imageDepth)
{
super(context);
setFocusable(false);
setFocusableInTouchMode(false);
setZOrderMediaOverlay(onTop);
+ m_surfaceCallback = surfaceCallback;
getHolder().addCallback(this);
if (imageDepth == 16)
getHolder().setFormat(PixelFormat.RGB_565);
else
getHolder().setFormat(PixelFormat.RGBA_8888);
-
- setId(id);
- m_gestureDetector =
- new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
- public void onLongPress(MotionEvent event) {
- QtNative.longPress(getId(), (int) event.getX(), (int) event.getY());
- }
- });
- m_gestureDetector.setIsLongpressEnabled(true);
}
@Override
@@ -52,39 +40,14 @@ public class QtSurface extends SurfaceView implements SurfaceHolder.Callback
{
if (width < 1 || height < 1)
return;
-
- QtNative.setSurface(getId(), holder.getSurface(), width, height);
+ if (m_surfaceCallback != null)
+ m_surfaceCallback.onSurfaceChanged(holder.getSurface());
}
@Override
public void surfaceDestroyed(SurfaceHolder holder)
{
- QtNative.setSurface(getId(), null, 0, 0);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event)
- {
- // QTBUG-65927
- // Fix event positions depending on Surface position.
- // In case when Surface is moved, we should also add this move to event position
- event.setLocation(event.getX() + getX(), event.getY() + getY());
-
- QtNative.sendTouchEvent(event, getId());
- m_gestureDetector.onTouchEvent(event);
- return true;
- }
-
- @Override
- public boolean onTrackballEvent(MotionEvent event)
- {
- QtNative.sendTrackballEvent(event, getId());
- return true;
- }
-
- @Override
- public boolean onGenericMotionEvent(MotionEvent event)
- {
- return QtNative.sendGenericMotionEvent(event, getId());
+ if (m_surfaceCallback != null)
+ m_surfaceCallback.onSurfaceChanged(null);
}
}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtSurfaceInterface.java b/src/android/jar/src/org/qtproject/qt/android/QtSurfaceInterface.java
new file mode 100644
index 0000000000..8df442f730
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtSurfaceInterface.java
@@ -0,0 +1,13 @@
+// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.view.Surface;
+
+
+public interface QtSurfaceInterface
+{
+ void onSurfaceChanged(Surface surface);
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtTextureView.java b/src/android/jar/src/org/qtproject/qt/android/QtTextureView.java
new file mode 100644
index 0000000000..828838a9f0
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtTextureView.java
@@ -0,0 +1,52 @@
+// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.graphics.SurfaceTexture;
+import android.util.Log;
+import android.view.Surface;
+import android.view.TextureView;
+
+public class QtTextureView extends TextureView implements TextureView.SurfaceTextureListener
+{
+ private QtSurfaceInterface m_surfaceCallback;
+ private boolean m_staysOnTop;
+ private Surface m_surface;
+
+ public QtTextureView(Context context, QtSurfaceInterface surfaceCallback, boolean isOpaque)
+ {
+ super(context);
+ setFocusable(false);
+ setFocusableInTouchMode(false);
+ m_surfaceCallback = surfaceCallback;
+ setSurfaceTextureListener(this);
+ setOpaque(isOpaque);
+ setSurfaceTexture(new SurfaceTexture(false));
+ }
+
+ @Override
+ public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
+ m_surface = new Surface(surfaceTexture);
+ m_surfaceCallback.onSurfaceChanged(m_surface);
+ }
+
+ @Override
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) {
+ m_surface = new Surface(surfaceTexture);
+ m_surfaceCallback.onSurfaceChanged(m_surface);
+ }
+
+ @Override
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
+ m_surfaceCallback.onSurfaceChanged(null);
+ return true;
+ }
+
+ @Override
+ public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtThread.java b/src/android/jar/src/org/qtproject/qt/android/QtThread.java
index bc58344c16..0943ad3265 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtThread.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtThread.java
@@ -6,10 +6,10 @@ package org.qtproject.qt.android;
import java.util.ArrayList;
import java.util.concurrent.Semaphore;
-public class QtThread {
- private ArrayList<Runnable> m_pendingRunnables = new ArrayList<Runnable>();
+class QtThread {
+ private final ArrayList<Runnable> m_pendingRunnables = new ArrayList<>();
private boolean m_exit = false;
- private Thread m_qtThread = new Thread(new Runnable() {
+ private final Thread m_qtThread = new Thread(new Runnable() {
@Override
public void run() {
while (!m_exit) {
@@ -18,7 +18,7 @@ public class QtThread {
synchronized (m_qtThread) {
if (m_pendingRunnables.size() == 0)
m_qtThread.wait();
- pendingRunnables = new ArrayList<Runnable>(m_pendingRunnables);
+ pendingRunnables = new ArrayList<>(m_pendingRunnables);
m_pendingRunnables.clear();
}
for (Runnable runnable : pendingRunnables)
@@ -42,15 +42,20 @@ public class QtThread {
}
}
+ public void sleep(int milliseconds) {
+ try {
+ m_qtThread.sleep(milliseconds);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
public void run(final Runnable runnable) {
final Semaphore sem = new Semaphore(0);
synchronized (m_qtThread) {
- m_pendingRunnables.add(new Runnable() {
- @Override
- public void run() {
- runnable.run();
- sem.release();
- }
+ m_pendingRunnables.add(() -> {
+ runnable.run();
+ sem.release();
});
m_qtThread.notify();
}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtView.java b/src/android/jar/src/org/qtproject/qt/android/QtView.java
new file mode 100644
index 0000000000..ddf70b3b5b
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtView.java
@@ -0,0 +1,190 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.security.InvalidParameterException;
+import java.util.ArrayList;
+
+// Base class for embedding QWindow into native Android view hierarchy. Extend to implement
+// the creation of appropriate window to embed.
+abstract class QtView extends ViewGroup {
+ private final static String TAG = "QtView";
+
+ public interface QtWindowListener {
+ // Called when the QWindow has been created and it's Java counterpart embedded into
+ // QtView
+ void onQtWindowLoaded();
+ }
+
+ protected QtWindow m_window;
+ protected long m_windowReference;
+ protected long m_parentWindowReference;
+ protected QtWindowListener m_windowListener;
+ protected QtEmbeddedViewInterface m_viewInterface;
+ // Implement in subclass to handle the creation of the QWindow and its parent container.
+ // TODO could we take care of the parent window creation and parenting outside of the
+ // window creation method to simplify things if user would extend this? Preferably without
+ // too much JNI back and forth. Related to parent window creation, so handle with QTBUG-121511.
+ abstract protected void createWindow(long parentWindowRef);
+
+ static native void createRootWindow(View rootView, int x, int y, int width, int height);
+ static native void deleteWindow(long windowReference);
+ private static native void setWindowVisible(long windowReference, boolean visible);
+ private static native void resizeWindow(long windowReference,
+ int x, int y, int width, int height);
+
+ /**
+ * Create QtView for embedding a QWindow. Instantiating a QtView will load the Qt libraries
+ * if they have not already been loaded, including the app library specified by appName, and
+ * starting the said Qt app.
+ * @param context the hosting Context
+ * @param appLibName the name of the Qt app library to load and start. This corresponds to the
+ target name set in Qt app's CMakeLists.txt
+ **/
+ public QtView(Context context, String appLibName) throws InvalidParameterException {
+ super(context);
+ if (appLibName == null || appLibName.isEmpty()) {
+ throw new InvalidParameterException("QtView: argument 'appLibName' may not be empty "+
+ "or null");
+ }
+
+ QtEmbeddedLoader loader = new QtEmbeddedLoader(context);
+ m_viewInterface = QtEmbeddedDelegateFactory.create((Activity)context);
+ loader.setMainLibraryName(appLibName);
+ addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ if (m_windowReference != 0L) {
+ final int oldWidth = oldRight - oldLeft;
+ final int oldHeight = oldBottom - oldTop;
+ final int newWidth = right - left;
+ final int newHeight = bottom - top;
+ if (oldWidth != newWidth || oldHeight != newHeight || left != oldLeft ||
+ top != oldTop) {
+ resizeWindow(m_windowReference, left, top, newWidth, newHeight);
+ }
+ }
+ }
+ });
+ loader.loadQtLibraries();
+ // Start Native Qt application
+ m_viewInterface.startQtApplication(loader.getApplicationParameters(),
+ loader.getMainLibraryPath());
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ m_viewInterface.setView(this);
+ m_viewInterface.queueLoadWindow();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ destroyWindow();
+ m_viewInterface.setView(null);
+ }
+
+ @Override
+ public void onLayout(boolean changed, int l, int t, int r, int b) {
+ if (m_window != null)
+ m_window.layout(0 /* left */, 0 /* top */, r - l /* right */, b - t /* bottom */);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
+ {
+ measureChildren(widthMeasureSpec, heightMeasureSpec);
+
+ final int count = getChildCount();
+
+ int maxHeight = 0;
+ int maxWidth = 0;
+
+ // Find out how big everyone wants to be
+ measureChildren(widthMeasureSpec, heightMeasureSpec);
+
+ // Find rightmost and bottom-most child
+ for (int i = 0; i < count; i++) {
+ View child = getChildAt(i);
+ if (child.getVisibility() != GONE) {
+ maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
+ maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
+ }
+ }
+
+ // Check against minimum height and width
+ maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
+ maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
+
+ setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec),
+ resolveSize(maxHeight, heightMeasureSpec));
+ }
+
+
+ public void setQtWindowListener(QtWindowListener listener) {
+ m_windowListener = listener;
+ }
+
+ void setWindowReference(long windowReference) {
+ m_windowReference = windowReference;
+ }
+
+ long windowReference() {
+ return m_windowReference;
+ }
+
+ // Set the visibility of the underlying QWindow. If visible is true, showNormal() is called.
+ // If false, the window is hidden.
+ void setWindowVisible(boolean visible) {
+ if (m_windowReference != 0L)
+ setWindowVisible(m_windowReference, true);
+ }
+
+ // Called from Qt when the QWindow has been created.
+ // window - the Java QtWindow of the created QAndroidPlatformWindow, to embed into the QtView
+ // viewReference - the reference to the created QQuickView
+ void addQtWindow(QtWindow window, long viewReference, long parentWindowRef) {
+ setWindowReference(viewReference);
+ m_parentWindowReference = parentWindowRef;
+ final Handler handler = new Handler(Looper.getMainLooper());
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ m_window = window;
+ m_window.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ addView(m_window, 0);
+ // Call show window + parent
+ setWindowVisible(true);
+ if (m_windowListener != null)
+ m_windowListener.onQtWindowLoaded();
+ }
+ });
+ }
+
+ // Destroy the underlying QWindow
+ void destroyWindow() {
+ if (m_parentWindowReference != 0L)
+ deleteWindow(m_parentWindowReference);
+ m_parentWindowReference = 0L;
+ }
+
+ QtWindow getQtWindow() {
+ return m_window;
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtWindow.java b/src/android/jar/src/org/qtproject/qt/android/QtWindow.java
new file mode 100644
index 0000000000..d72e69d32a
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/QtWindow.java
@@ -0,0 +1,215 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.content.Context;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.util.Log;
+import android.view.Surface;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.HashMap;
+
+class QtWindow extends QtLayout implements QtSurfaceInterface {
+ private final static String TAG = "QtWindow";
+
+ private View m_surfaceContainer;
+ private View m_nativeView;
+ private HashMap<Integer, QtWindow> m_childWindows = new HashMap<Integer, QtWindow>();
+ private QtWindow m_parentWindow;
+ private GestureDetector m_gestureDetector;
+ private final QtEditText m_editText;
+
+ private static native void setSurface(int windowId, Surface surface);
+ static native void windowFocusChanged(boolean hasFocus, int id);
+
+ public QtWindow(Context context, QtWindow parentWindow, QtInputDelegate delegate)
+ {
+ super(context);
+ setId(View.generateViewId());
+ m_editText = new QtEditText(context, delegate);
+ setParent(parentWindow);
+ setFocusableInTouchMode(true);
+ addView(m_editText, new QtLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+
+ QtNative.runAction(() -> {
+ m_gestureDetector =
+ new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
+ public void onLongPress(MotionEvent event) {
+ QtInputDelegate.longPress(getId(), (int) event.getX(), (int) event.getY());
+ }
+ });
+ m_gestureDetector.setIsLongpressEnabled(true);
+ });
+ }
+
+ void setVisible(boolean visible) {
+ QtNative.runAction(() -> {
+ if (visible)
+ setVisibility(View.VISIBLE);
+ else
+ setVisibility(View.INVISIBLE);
+ });
+ }
+
+ @Override
+ public void onSurfaceChanged(Surface surface)
+ {
+ setSurface(getId(), surface);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event)
+ {
+ m_editText.requestFocus();
+ event.setLocation(event.getX() + getX(), event.getY() + getY());
+ QtInputDelegate.sendTouchEvent(event, getId());
+ m_gestureDetector.onTouchEvent(event);
+ return true;
+ }
+
+ @Override
+ public boolean onTrackballEvent(MotionEvent event)
+ {
+ QtInputDelegate.sendTrackballEvent(event, getId());
+ return true;
+ }
+
+ @Override
+ public boolean onGenericMotionEvent(MotionEvent event)
+ {
+ return QtInputDelegate.sendGenericMotionEvent(event, getId());
+ }
+
+ public void removeWindow()
+ {
+ if (m_parentWindow != null)
+ m_parentWindow.removeChildWindow(getId());
+ }
+
+ public void createSurface(final boolean onTop,
+ final int x, final int y, final int w, final int h,
+ final int imageDepth, final boolean isOpaque,
+ final int surfaceContainerType) // TODO constant for type
+ {
+ QtNative.runAction(()-> {
+ if (m_surfaceContainer != null)
+ removeView(m_surfaceContainer);
+
+ setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
+ if (surfaceContainerType == 0) {
+ m_surfaceContainer = new QtSurface(getContext(), QtWindow.this,
+ onTop, imageDepth);
+ } else {
+ m_surfaceContainer = new QtTextureView(getContext(), QtWindow.this, isOpaque);
+ }
+ m_surfaceContainer.setLayoutParams(new QtLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ // The surface container of this window will be added as the first of the stack.
+ // All other views are stacked based on the order they are created.
+ addView(m_surfaceContainer, 0);
+ });
+ }
+
+ public void destroySurface()
+ {
+ QtNative.runAction(()-> {
+ if (m_surfaceContainer != null) {
+ removeView(m_surfaceContainer);
+ m_surfaceContainer = null;
+ }
+ }, false);
+ }
+
+ public void setGeometry(final int x, final int y, final int w, final int h)
+ {
+ QtNative.runAction(()-> {
+ if (getContext() instanceof QtActivityBase)
+ setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
+ });
+ }
+
+ public void addChildWindow(QtWindow window)
+ {
+ QtNative.runAction(()-> {
+ m_childWindows.put(window.getId(), window);
+ addView(window, getChildCount());
+ });
+ }
+
+ public void removeChildWindow(int id)
+ {
+ QtNative.runAction(()-> {
+ if (m_childWindows.containsKey(id))
+ removeView(m_childWindows.remove(id));
+ });
+ }
+
+ public void setNativeView(final View view,
+ final int x, final int y, final int w, final int h)
+ {
+ QtNative.runAction(()-> {
+ if (m_nativeView != null)
+ removeView(m_nativeView);
+
+ m_nativeView = view;
+ QtWindow.this.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
+ m_nativeView.setLayoutParams(new QtLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ addView(m_nativeView);
+ });
+ }
+
+ public void bringChildToFront(int id)
+ {
+ QtNative.runAction(()-> {
+ View view = m_childWindows.get(id);
+ if (view != null) {
+ if (getChildCount() > 0)
+ moveChild(view, getChildCount() - 1);
+ }
+ });
+ }
+
+ public void bringChildToBack(int id) {
+ QtNative.runAction(()-> {
+ View view = m_childWindows.get(id);
+ if (view != null) {
+ moveChild(view, 0);
+ }
+ });
+ }
+
+ public void removeNativeView()
+ {
+ QtNative.runAction(()-> {
+ if (m_nativeView != null) {
+ removeView(m_nativeView);
+ m_nativeView = null;
+ }
+ });
+ }
+
+ void setParent(QtWindow parentWindow)
+ {
+ if (m_parentWindow == parentWindow)
+ return;
+
+ if (m_parentWindow != null)
+ m_parentWindow.removeChildWindow(getId());
+
+ m_parentWindow = parentWindow;
+ if (m_parentWindow != null)
+ m_parentWindow.addChildWindow(this);
+ }
+
+ QtWindow parent()
+ {
+ return m_parentWindow;
+ }
+}
diff --git a/src/android/jar/src/org/qtproject/qt/android/UsedFromNativeCode.java b/src/android/jar/src/org/qtproject/qt/android/UsedFromNativeCode.java
new file mode 100644
index 0000000000..e0223c083f
--- /dev/null
+++ b/src/android/jar/src/org/qtproject/qt/android/UsedFromNativeCode.java
@@ -0,0 +1,10 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.CLASS)
+public @interface UsedFromNativeCode { }
diff --git a/src/android/jar/src/org/qtproject/qt/android/extras/QtAndroidBinder.java b/src/android/jar/src/org/qtproject/qt/android/extras/QtAndroidBinder.java
index 1270464576..bd837570fe 100644
--- a/src/android/jar/src/org/qtproject/qt/android/extras/QtAndroidBinder.java
+++ b/src/android/jar/src/org/qtproject/qt/android/extras/QtAndroidBinder.java
@@ -6,8 +6,11 @@ package org.qtproject.qt.android.extras;
import android.os.Binder;
import android.os.Parcel;
-public class QtAndroidBinder extends Binder
+import org.qtproject.qt.android.UsedFromNativeCode;
+
+class QtAndroidBinder extends Binder
{
+ @UsedFromNativeCode
public QtAndroidBinder(long id)
{
m_id = id;
diff --git a/src/android/jar/src/org/qtproject/qt/android/extras/QtAndroidServiceConnection.java b/src/android/jar/src/org/qtproject/qt/android/extras/QtAndroidServiceConnection.java
index 3608051208..b70b64e3ac 100644
--- a/src/android/jar/src/org/qtproject/qt/android/extras/QtAndroidServiceConnection.java
+++ b/src/android/jar/src/org/qtproject/qt/android/extras/QtAndroidServiceConnection.java
@@ -7,8 +7,11 @@ import android.content.ComponentName;
import android.content.ServiceConnection;
import android.os.IBinder;
-public class QtAndroidServiceConnection implements ServiceConnection
+import org.qtproject.qt.android.UsedFromNativeCode;
+
+class QtAndroidServiceConnection implements ServiceConnection
{
+ @UsedFromNativeCode
public QtAndroidServiceConnection(long id)
{
m_id = id;
diff --git a/src/android/jar/src/org/qtproject/qt/android/extras/QtNative.java b/src/android/jar/src/org/qtproject/qt/android/extras/QtNative.java
index 3f847b0bb3..f7ba8dd9b4 100644
--- a/src/android/jar/src/org/qtproject/qt/android/extras/QtNative.java
+++ b/src/android/jar/src/org/qtproject/qt/android/extras/QtNative.java
@@ -3,12 +3,10 @@
package org.qtproject.qt.android.extras;
-import android.content.ComponentName;
-import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.Parcel;
-public class QtNative {
+class QtNative {
// Binder
public static native boolean onTransact(long id, int code, Parcel data, Parcel reply, int flags);
diff --git a/src/android/java/CMakeLists.txt b/src/android/java/CMakeLists.txt
index 32697410eb..2ff2fb5791 100644
--- a/src/android/java/CMakeLists.txt
+++ b/src/android/java/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2022 The Qt Company Ltd.
+# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
# Android Java Resource files
@@ -10,11 +10,8 @@ set(resource_directories
set(java_bindings
"${CMAKE_CURRENT_SOURCE_DIR}/src/org/qtproject/qt/android/bindings/QtActivity.java"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/org/qtproject/qt/android/bindings/QtActivityLoader.java"
"${CMAKE_CURRENT_SOURCE_DIR}/src/org/qtproject/qt/android/bindings/QtService.java"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/org/qtproject/qt/android/bindings/QtServiceLoader.java"
"${CMAKE_CURRENT_SOURCE_DIR}/src/org/qtproject/qt/android/bindings/QtApplication.java"
- "${CMAKE_CURRENT_SOURCE_DIR}/src/org/qtproject/qt/android/bindings/QtLoader.java"
)
set(strings_resouces
@@ -57,3 +54,13 @@ if(NOT QT_WILL_INSTALL)
DIRECTORIES ${resource_directories}
DESTINATION ${destination})
endif()
+
+# To avoid Java build errors after the loader classes have been moved to the internal Jar package,
+# make this step to remove them from the build folder. This mainly useful for existing builds,
+# as clean builds wouldn't have to deal with this case.
+if ("${PROJECT_VERSION}" GREATER_EQUAL "6.7")
+ set(loader_bindings "QtLoader.java" "QtActivityLoader.java" "QtServiceLoader.java")
+ foreach(binding IN LISTS loader_bindings)
+ file(REMOVE "${destination}/src/org/qtproject/qt/android/bindings/${binding}")
+ endforeach()
+endif()
diff --git a/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java b/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java
index 94d3c2dee1..ca4d2128ba 100644
--- a/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java
+++ b/src/android/java/src/org/qtproject/qt/android/bindings/QtActivity.java
@@ -1,1139 +1,18 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// Copyright (c) 2016, BogDan Vatra <bogdan@kde.org>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
package org.qtproject.qt.android.bindings;
-import android.app.Activity;
-import android.app.Dialog;
-import android.app.Fragment;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.content.res.Resources.Theme;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
-import android.util.AttributeSet;
-import android.view.ActionMode;
-import android.view.ActionMode.Callback;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.WindowManager.LayoutParams;
-import android.view.accessibility.AccessibilityEvent;
-import org.qtproject.qt.android.QtNative;
+import org.qtproject.qt.android.QtActivityBase;
-public class QtActivity extends Activity
+public class QtActivity extends QtActivityBase
{
- public static final String EXTRA_SOURCE_INFO = "org.qtproject.qt.android.sourceInfo";
-
- public String APPLICATION_PARAMETERS = null; // use this variable to pass any parameters to your application,
- // the parameters must not contain any white spaces
- // and must be separated with "\t"
- // e.g "-param1\t-param2=value2\t-param3\tvalue3"
-
- public String ENVIRONMENT_VARIABLES = "QT_USE_ANDROID_NATIVE_DIALOGS=1";
- // use this variable to add any environment variables to your application.
- // the env vars must be separated with "\t"
- // e.g. "ENV_VAR1=1\tENV_VAR2=2\t"
- // Currently the following vars are used by the android plugin:
- // * QT_USE_ANDROID_NATIVE_DIALOGS - 1 to use the android native dialogs.
-
- public String[] QT_ANDROID_THEMES = null; // A list with all themes that your application want to use.
- // The name of the theme must be the same with any theme from
- // http://developer.android.com/reference/android/R.style.html
- // The most used themes are:
- // * "Theme" - (fallback) check http://developer.android.com/reference/android/R.style.html#Theme
- // * "Theme_Black" - check http://developer.android.com/reference/android/R.style.html#Theme_Black
- // * "Theme_Light" - (default for API <=10) check http://developer.android.com/reference/android/R.style.html#Theme_Light
- // * "Theme_Holo" - check http://developer.android.com/reference/android/R.style.html#Theme_Holo
- // * "Theme_Holo_Light" - (default for API 11-13) check http://developer.android.com/reference/android/R.style.html#Theme_Holo_Light
- // * "Theme_DeviceDefault" - check http://developer.android.com/reference/android/R.style.html#Theme_DeviceDefault
- // * "Theme_DeviceDefault_Light" - (default for API 14+) check http://developer.android.com/reference/android/R.style.html#Theme_DeviceDefault_Light
-
- public String QT_ANDROID_DEFAULT_THEME = null; // sets the default theme.
-
- private QtActivityLoader m_loader;
- public QtActivity()
- {
- m_loader = new QtActivityLoader(this);
-
- if (Build.VERSION.SDK_INT < 29) {
- QT_ANDROID_THEMES = new String[] {"Theme_Holo_Light"};
- QT_ANDROID_DEFAULT_THEME = "Theme_Holo_Light";
- } else {
- QT_ANDROID_THEMES = new String[] {"Theme_DeviceDefault_DayNight"};
- QT_ANDROID_DEFAULT_THEME = "Theme_DeviceDefault_DayNight";
- }
- }
-
-
- /////////////////////////// forward all notifications ////////////////////////////
- /////////////////////////// Super class calls ////////////////////////////////////
- /////////////// PLEASE DO NOT CHANGE THE FOLLOWING CODE //////////////////////////
- //////////////////////////////////////////////////////////////////////////////////
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event)
- {
- if (QtApplication.m_delegateObject != null && QtApplication.dispatchKeyEvent != null)
- return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.dispatchKeyEvent, event);
- else
- return super.dispatchKeyEvent(event);
- }
- public boolean super_dispatchKeyEvent(KeyEvent event)
- {
- return super.dispatchKeyEvent(event);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event)
- {
- if (QtApplication.m_delegateObject != null && QtApplication.dispatchPopulateAccessibilityEvent != null)
- return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.dispatchPopulateAccessibilityEvent, event);
- else
- return super.dispatchPopulateAccessibilityEvent(event);
- }
- public boolean super_dispatchPopulateAccessibilityEvent(AccessibilityEvent event)
- {
- return super.dispatchPopulateAccessibilityEvent(event);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev)
- {
- if (QtApplication.m_delegateObject != null && QtApplication.dispatchTouchEvent != null)
- return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.dispatchTouchEvent, ev);
- else
- return super.dispatchTouchEvent(ev);
- }
- public boolean super_dispatchTouchEvent(MotionEvent event)
- {
- return super.dispatchTouchEvent(event);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public boolean dispatchTrackballEvent(MotionEvent ev)
- {
- if (QtApplication.m_delegateObject != null && QtApplication.dispatchTrackballEvent != null)
- return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.dispatchTrackballEvent, ev);
- else
- return super.dispatchTrackballEvent(ev);
- }
- public boolean super_dispatchTrackballEvent(MotionEvent event)
- {
- return super.dispatchTrackballEvent(event);
- }
- //---------------------------------------------------------------------------
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data)
- {
-
- if (QtApplication.m_delegateObject != null && QtApplication.onActivityResult != null) {
- QtApplication.invokeDelegateMethod(QtApplication.onActivityResult, requestCode, resultCode, data);
- return;
- }
- super.onActivityResult(requestCode, resultCode, data);
- }
- public void super_onActivityResult(int requestCode, int resultCode, Intent data)
- {
- super.onActivityResult(requestCode, resultCode, data);
- }
- //---------------------------------------------------------------------------
-
- @Override
- protected void onApplyThemeResource(Theme theme, int resid, boolean first)
- {
- if (!QtApplication.invokeDelegate(theme, resid, first).invoked)
- super.onApplyThemeResource(theme, resid, first);
- }
- public void super_onApplyThemeResource(Theme theme, int resid, boolean first)
- {
- super.onApplyThemeResource(theme, resid, first);
- }
- //---------------------------------------------------------------------------
-
-
- @Override
- protected void onChildTitleChanged(Activity childActivity, CharSequence title)
- {
- if (!QtApplication.invokeDelegate(childActivity, title).invoked)
- super.onChildTitleChanged(childActivity, title);
- }
- public void super_onChildTitleChanged(Activity childActivity, CharSequence title)
- {
- super.onChildTitleChanged(childActivity, title);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public void onConfigurationChanged(Configuration newConfig)
- {
- if (!QtApplication.invokeDelegate(newConfig).invoked)
- super.onConfigurationChanged(newConfig);
- }
- public void super_onConfigurationChanged(Configuration newConfig)
- {
- super.onConfigurationChanged(newConfig);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public void onContentChanged()
- {
- if (!QtApplication.invokeDelegate().invoked)
- super.onContentChanged();
- }
- public void super_onContentChanged()
- {
- super.onContentChanged();
- }
- //---------------------------------------------------------------------------
-
- @Override
- public boolean onContextItemSelected(MenuItem item)
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate(item);
- if (res.invoked)
- return (Boolean)res.methodReturns;
- else
- return super.onContextItemSelected(item);
- }
- public boolean super_onContextItemSelected(MenuItem item)
- {
- return super.onContextItemSelected(item);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public void onContextMenuClosed(Menu menu)
- {
- if (!QtApplication.invokeDelegate(menu).invoked)
- super.onContextMenuClosed(menu);
- }
- public void super_onContextMenuClosed(Menu menu)
- {
- super.onContextMenuClosed(menu);
- }
- //---------------------------------------------------------------------------
-
- protected void onCreateHook(Bundle savedInstanceState) {
- m_loader.APPLICATION_PARAMETERS = APPLICATION_PARAMETERS;
- m_loader.ENVIRONMENT_VARIABLES = ENVIRONMENT_VARIABLES;
- m_loader.QT_ANDROID_THEMES = QT_ANDROID_THEMES;
- m_loader.QT_ANDROID_DEFAULT_THEME = QT_ANDROID_DEFAULT_THEME;
- m_loader.onCreate(savedInstanceState);
- }
-
- private void addReferrer(Intent intent)
- {
- if (intent.getExtras() != null && intent.getExtras().getString(EXTRA_SOURCE_INFO) != null)
- return;
-
- String sourceInformation = "";
- Uri referrer = getReferrer();
- if (referrer != null)
- sourceInformation = referrer.toString().replaceFirst("android-app://", "");
-
- intent.putExtra(EXTRA_SOURCE_INFO, sourceInformation);
- }
-
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
- onCreateHook(savedInstanceState);
- addReferrer(getIntent());
- }
- //---------------------------------------------------------------------------
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
- {
- if (!QtApplication.invokeDelegate(menu, v, menuInfo).invoked)
- super.onCreateContextMenu(menu, v, menuInfo);
- }
- public void super_onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
- {
- super.onCreateContextMenu(menu, v, menuInfo);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public CharSequence onCreateDescription()
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate();
- if (res.invoked)
- return (CharSequence)res.methodReturns;
- else
- return super.onCreateDescription();
- }
- public CharSequence super_onCreateDescription()
- {
- return super.onCreateDescription();
- }
- //---------------------------------------------------------------------------
-
- @Override
- protected Dialog onCreateDialog(int id)
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate(id);
- if (res.invoked)
- return (Dialog)res.methodReturns;
- else
- return super.onCreateDialog(id);
- }
- public Dialog super_onCreateDialog(int id)
- {
- return super.onCreateDialog(id);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu)
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate(menu);
- if (res.invoked)
- return (Boolean)res.methodReturns;
- else
- return super.onCreateOptionsMenu(menu);
- }
- public boolean super_onCreateOptionsMenu(Menu menu)
- {
- return super.onCreateOptionsMenu(menu);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public boolean onCreatePanelMenu(int featureId, Menu menu)
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate(featureId, menu);
- if (res.invoked)
- return (Boolean)res.methodReturns;
- else
- return super.onCreatePanelMenu(featureId, menu);
- }
- public boolean super_onCreatePanelMenu(int featureId, Menu menu)
- {
- return super.onCreatePanelMenu(featureId, menu);
- }
- //---------------------------------------------------------------------------
-
-
- @Override
- public View onCreatePanelView(int featureId)
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate(featureId);
- if (res.invoked)
- return (View)res.methodReturns;
- else
- return super.onCreatePanelView(featureId);
- }
- public View super_onCreatePanelView(int featureId)
- {
- return super.onCreatePanelView(featureId);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public boolean onCreateThumbnail(Bitmap outBitmap, Canvas canvas)
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate(outBitmap, canvas);
- if (res.invoked)
- return (Boolean)res.methodReturns;
- else
- return super.onCreateThumbnail(outBitmap, canvas);
- }
- public boolean super_onCreateThumbnail(Bitmap outBitmap, Canvas canvas)
- {
- return super.onCreateThumbnail(outBitmap, canvas);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public View onCreateView(String name, Context context, AttributeSet attrs)
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate(name, context, attrs);
- if (res.invoked)
- return (View)res.methodReturns;
- else
- return super.onCreateView(name, context, attrs);
- }
- public View super_onCreateView(String name, Context context, AttributeSet attrs)
- {
- return super.onCreateView(name, context, attrs);
- }
- //---------------------------------------------------------------------------
-
- @Override
- protected void onDestroy()
- {
- super.onDestroy();
- QtApplication.invokeDelegate();
- }
- //---------------------------------------------------------------------------
-
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event)
- {
- if (QtApplication.m_delegateObject != null && QtApplication.onKeyDown != null)
- return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onKeyDown, keyCode, event);
- else
- return super.onKeyDown(keyCode, event);
- }
- public boolean super_onKeyDown(int keyCode, KeyEvent event)
- {
- return super.onKeyDown(keyCode, event);
- }
- //---------------------------------------------------------------------------
-
-
- @Override
- public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event)
- {
- if (QtApplication.m_delegateObject != null && QtApplication.onKeyMultiple != null)
- return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onKeyMultiple, keyCode, repeatCount, event);
- else
- return super.onKeyMultiple(keyCode, repeatCount, event);
- }
- public boolean super_onKeyMultiple(int keyCode, int repeatCount, KeyEvent event)
- {
- return super.onKeyMultiple(keyCode, repeatCount, event);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event)
- {
- if (QtApplication.m_delegateObject != null && QtApplication.onKeyUp != null)
- return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onKeyUp, keyCode, event);
- else
- return super.onKeyUp(keyCode, event);
- }
- public boolean super_onKeyUp(int keyCode, KeyEvent event)
- {
- return super.onKeyUp(keyCode, event);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public void onLowMemory()
- {
- if (!QtApplication.invokeDelegate().invoked)
- super.onLowMemory();
- }
- //---------------------------------------------------------------------------
-
- @Override
- public boolean onMenuItemSelected(int featureId, MenuItem item)
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate(featureId, item);
- if (res.invoked)
- return (Boolean)res.methodReturns;
- else
- return super.onMenuItemSelected(featureId, item);
- }
- public boolean super_onMenuItemSelected(int featureId, MenuItem item)
- {
- return super.onMenuItemSelected(featureId, item);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public boolean onMenuOpened(int featureId, Menu menu)
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate(featureId, menu);
- if (res.invoked)
- return (Boolean)res.methodReturns;
- else
- return super.onMenuOpened(featureId, menu);
- }
- public boolean super_onMenuOpened(int featureId, Menu menu)
- {
- return super.onMenuOpened(featureId, menu);
- }
- //---------------------------------------------------------------------------
-
- @Override
- protected void onNewIntent(Intent intent)
- {
- addReferrer(intent);
- if (!QtApplication.invokeDelegate(intent).invoked)
- super.onNewIntent(intent);
- }
- public void super_onNewIntent(Intent intent)
- {
- super.onNewIntent(intent);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item)
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate(item);
- if (res.invoked)
- return (Boolean)res.methodReturns;
- else
- return super.onOptionsItemSelected(item);
- }
- public boolean super_onOptionsItemSelected(MenuItem item)
- {
- return super.onOptionsItemSelected(item);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public void onOptionsMenuClosed(Menu menu)
- {
- if (!QtApplication.invokeDelegate(menu).invoked)
- super.onOptionsMenuClosed(menu);
- }
- public void super_onOptionsMenuClosed(Menu menu)
- {
- super.onOptionsMenuClosed(menu);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public void onPanelClosed(int featureId, Menu menu)
- {
- if (!QtApplication.invokeDelegate(featureId, menu).invoked)
- super.onPanelClosed(featureId, menu);
- }
- public void super_onPanelClosed(int featureId, Menu menu)
- {
- super.onPanelClosed(featureId, menu);
- }
- //---------------------------------------------------------------------------
-
- @Override
- protected void onPause()
- {
- super.onPause();
- QtApplication.invokeDelegate();
- }
- //---------------------------------------------------------------------------
-
- @Override
- protected void onPostCreate(Bundle savedInstanceState)
- {
- super.onPostCreate(savedInstanceState);
- QtApplication.invokeDelegate(savedInstanceState);
- }
- //---------------------------------------------------------------------------
-
- @Override
- protected void onPostResume()
- {
- super.onPostResume();
- QtApplication.invokeDelegate();
- }
- //---------------------------------------------------------------------------
-
- @Override
- protected void onPrepareDialog(int id, Dialog dialog)
- {
- if (!QtApplication.invokeDelegate(id, dialog).invoked)
- super.onPrepareDialog(id, dialog);
- }
- public void super_onPrepareDialog(int id, Dialog dialog)
- {
- super.onPrepareDialog(id, dialog);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu)
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate(menu);
- if (res.invoked)
- return (Boolean)res.methodReturns;
- else
- return super.onPrepareOptionsMenu(menu);
- }
- public boolean super_onPrepareOptionsMenu(Menu menu)
- {
- return super.onPrepareOptionsMenu(menu);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public boolean onPreparePanel(int featureId, View view, Menu menu)
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate(featureId, view, menu);
- if (res.invoked)
- return (Boolean)res.methodReturns;
- else
- return super.onPreparePanel(featureId, view, menu);
- }
- public boolean super_onPreparePanel(int featureId, View view, Menu menu)
- {
- return super.onPreparePanel(featureId, view, menu);
- }
- //---------------------------------------------------------------------------
-
- @Override
- protected void onRestart()
- {
- super.onRestart();
- QtApplication.invokeDelegate();
- }
- //---------------------------------------------------------------------------
-
- @Override
- protected void onRestoreInstanceState(Bundle savedInstanceState)
- {
- if (!QtApplication.invokeDelegate(savedInstanceState).invoked)
- super.onRestoreInstanceState(savedInstanceState);
- }
- public void super_onRestoreInstanceState(Bundle savedInstanceState)
- {
- super.onRestoreInstanceState(savedInstanceState);
- }
- //---------------------------------------------------------------------------
-
- @Override
- protected void onResume()
- {
- super.onResume();
- QtApplication.invokeDelegate();
- }
- //---------------------------------------------------------------------------
-
- @Override
- public Object onRetainNonConfigurationInstance()
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate();
- if (res.invoked)
- return res.methodReturns;
- else
- return super.onRetainNonConfigurationInstance();
- }
- public Object super_onRetainNonConfigurationInstance()
- {
- return super.onRetainNonConfigurationInstance();
- }
- //---------------------------------------------------------------------------
-
- @Override
- protected void onSaveInstanceState(Bundle outState)
- {
- if (!QtApplication.invokeDelegate(outState).invoked)
- super.onSaveInstanceState(outState);
- }
- public void super_onSaveInstanceState(Bundle outState)
- {
- super.onSaveInstanceState(outState);
-
- }
- //---------------------------------------------------------------------------
-
- @Override
- public boolean onSearchRequested()
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate();
- if (res.invoked)
- return (Boolean)res.methodReturns;
- else
- return super.onSearchRequested();
- }
- public boolean super_onSearchRequested()
- {
- return super.onSearchRequested();
- }
- //---------------------------------------------------------------------------
-
- @Override
- protected void onStart()
- {
- super.onStart();
- QtApplication.invokeDelegate();
- }
- //---------------------------------------------------------------------------
-
- @Override
- protected void onStop()
- {
- super.onStop();
- QtApplication.invokeDelegate();
- }
- //---------------------------------------------------------------------------
-
- @Override
- protected void onTitleChanged(CharSequence title, int color)
- {
- if (!QtApplication.invokeDelegate(title, color).invoked)
- super.onTitleChanged(title, color);
- }
- public void super_onTitleChanged(CharSequence title, int color)
- {
- super.onTitleChanged(title, color);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public boolean onTouchEvent(MotionEvent event)
- {
- if (QtApplication.m_delegateObject != null && QtApplication.onTouchEvent != null)
- return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onTouchEvent, event);
- else
- return super.onTouchEvent(event);
- }
- public boolean super_onTouchEvent(MotionEvent event)
- {
- return super.onTouchEvent(event);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public boolean onTrackballEvent(MotionEvent event)
- {
- if (QtApplication.m_delegateObject != null && QtApplication.onTrackballEvent != null)
- return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onTrackballEvent, event);
- else
- return super.onTrackballEvent(event);
- }
- public boolean super_onTrackballEvent(MotionEvent event)
- {
- return super.onTrackballEvent(event);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public void onUserInteraction()
- {
- if (!QtApplication.invokeDelegate().invoked)
- super.onUserInteraction();
- }
- public void super_onUserInteraction()
- {
- super.onUserInteraction();
- }
- //---------------------------------------------------------------------------
-
- @Override
- protected void onUserLeaveHint()
- {
- if (!QtApplication.invokeDelegate().invoked)
- super.onUserLeaveHint();
- }
- public void super_onUserLeaveHint()
- {
- super.onUserLeaveHint();
- }
- //---------------------------------------------------------------------------
-
- @Override
- public void onWindowAttributesChanged(LayoutParams params)
- {
- if (!QtApplication.invokeDelegate(params).invoked)
- super.onWindowAttributesChanged(params);
- }
- public void super_onWindowAttributesChanged(LayoutParams params)
- {
- super.onWindowAttributesChanged(params);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public void onWindowFocusChanged(boolean hasFocus)
- {
- if (!QtApplication.invokeDelegate(hasFocus).invoked)
- super.onWindowFocusChanged(hasFocus);
- }
- public void super_onWindowFocusChanged(boolean hasFocus)
- {
- super.onWindowFocusChanged(hasFocus);
- }
- //---------------------------------------------------------------------------
-
- //////////////// Activity API 5 /////////////
-//@ANDROID-5
- @Override
- public void onAttachedToWindow()
- {
- if (!QtApplication.invokeDelegate().invoked)
- super.onAttachedToWindow();
- }
- public void super_onAttachedToWindow()
- {
- super.onAttachedToWindow();
- }
- //---------------------------------------------------------------------------
-
- @Override
- public void onBackPressed()
- {
- if (!QtApplication.invokeDelegate().invoked)
- super.onBackPressed();
- }
- public void super_onBackPressed()
- {
- super.onBackPressed();
- }
- //---------------------------------------------------------------------------
-
- @Override
- public void onDetachedFromWindow()
- {
- if (!QtApplication.invokeDelegate().invoked)
- super.onDetachedFromWindow();
- }
- public void super_onDetachedFromWindow()
- {
- super.onDetachedFromWindow();
- }
- //---------------------------------------------------------------------------
-
- @Override
- public boolean onKeyLongPress(int keyCode, KeyEvent event)
- {
- if (QtApplication.m_delegateObject != null && QtApplication.onKeyLongPress != null)
- return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onKeyLongPress, keyCode, event);
- else
- return super.onKeyLongPress(keyCode, event);
- }
- public boolean super_onKeyLongPress(int keyCode, KeyEvent event)
- {
- return super.onKeyLongPress(keyCode, event);
- }
- //---------------------------------------------------------------------------
-//@ANDROID-5
-
-//////////////// Activity API 8 /////////////
-//@ANDROID-8
-@Override
- protected Dialog onCreateDialog(int id, Bundle args)
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate(id, args);
- if (res.invoked)
- return (Dialog)res.methodReturns;
- else
- return super.onCreateDialog(id, args);
- }
- public Dialog super_onCreateDialog(int id, Bundle args)
- {
- return super.onCreateDialog(id, args);
- }
- //---------------------------------------------------------------------------
-
- @Override
- protected void onPrepareDialog(int id, Dialog dialog, Bundle args)
- {
- if (!QtApplication.invokeDelegate(id, dialog, args).invoked)
- super.onPrepareDialog(id, dialog, args);
- }
- public void super_onPrepareDialog(int id, Dialog dialog, Bundle args)
- {
- super.onPrepareDialog(id, dialog, args);
- }
- //---------------------------------------------------------------------------
-//@ANDROID-8
- //////////////// Activity API 11 /////////////
-
-//@ANDROID-11
- @Override
- public boolean dispatchKeyShortcutEvent(KeyEvent event)
- {
- if (QtApplication.m_delegateObject != null && QtApplication.dispatchKeyShortcutEvent != null)
- return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.dispatchKeyShortcutEvent, event);
- else
- return super.dispatchKeyShortcutEvent(event);
- }
- public boolean super_dispatchKeyShortcutEvent(KeyEvent event)
- {
- return super.dispatchKeyShortcutEvent(event);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public void onActionModeFinished(ActionMode mode)
- {
- if (!QtApplication.invokeDelegate(mode).invoked)
- super.onActionModeFinished(mode);
- }
- public void super_onActionModeFinished(ActionMode mode)
- {
- super.onActionModeFinished(mode);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public void onActionModeStarted(ActionMode mode)
- {
- if (!QtApplication.invokeDelegate(mode).invoked)
- super.onActionModeStarted(mode);
- }
- public void super_onActionModeStarted(ActionMode mode)
- {
- super.onActionModeStarted(mode);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public void onAttachFragment(Fragment fragment)
- {
- if (!QtApplication.invokeDelegate(fragment).invoked)
- super.onAttachFragment(fragment);
- }
- public void super_onAttachFragment(Fragment fragment)
- {
- super.onAttachFragment(fragment);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public View onCreateView(View parent, String name, Context context, AttributeSet attrs)
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate(parent, name, context, attrs);
- if (res.invoked)
- return (View)res.methodReturns;
- else
- return super.onCreateView(parent, name, context, attrs);
- }
- public View super_onCreateView(View parent, String name, Context context,
- AttributeSet attrs) {
- return super.onCreateView(parent, name, context, attrs);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public boolean onKeyShortcut(int keyCode, KeyEvent event)
- {
- if (QtApplication.m_delegateObject != null && QtApplication.onKeyShortcut != null)
- return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onKeyShortcut, keyCode,event);
- else
- return super.onKeyShortcut(keyCode, event);
- }
- public boolean super_onKeyShortcut(int keyCode, KeyEvent event)
- {
- return super.onKeyShortcut(keyCode, event);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public ActionMode onWindowStartingActionMode(Callback callback)
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate(callback);
- if (res.invoked)
- return (ActionMode)res.methodReturns;
- else
- return super.onWindowStartingActionMode(callback);
- }
- public ActionMode super_onWindowStartingActionMode(Callback callback)
- {
- return super.onWindowStartingActionMode(callback);
- }
- //---------------------------------------------------------------------------
-//@ANDROID-11
- //////////////// Activity API 12 /////////////
-
-//@ANDROID-12
- @Override
- public boolean dispatchGenericMotionEvent(MotionEvent ev)
- {
- if (QtApplication.m_delegateObject != null && QtApplication.dispatchGenericMotionEvent != null)
- return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.dispatchGenericMotionEvent, ev);
- else
- return super.dispatchGenericMotionEvent(ev);
- }
- public boolean super_dispatchGenericMotionEvent(MotionEvent event)
- {
- return super.dispatchGenericMotionEvent(event);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public boolean onGenericMotionEvent(MotionEvent event)
- {
- if (QtApplication.m_delegateObject != null && QtApplication.onGenericMotionEvent != null)
- return (Boolean) QtApplication.invokeDelegateMethod(QtApplication.onGenericMotionEvent, event);
- else
- return super.onGenericMotionEvent(event);
- }
- public boolean super_onGenericMotionEvent(MotionEvent event)
- {
- return super.onGenericMotionEvent(event);
- }
- //---------------------------------------------------------------------------
-//@ANDROID-12
-
- public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
- {
- if (QtApplication.m_delegateObject != null && QtApplication.onRequestPermissionsResult != null) {
- QtApplication.invokeDelegateMethod(QtApplication.onRequestPermissionsResult, requestCode , permissions, grantResults);
- return;
- }
- }
-
- public void bringChildToBack(int id)
- {
- QtNative.activityDelegate().bringChildToBack(id);
- }
-
- public void bringChildToFront(int id)
- {
- QtNative.activityDelegate().bringChildToFront(id);
- }
-
- public void closeContextMenu()
- {
- QtNative.activityDelegate().closeContextMenu();
- }
-
- public void createSurface(int id, boolean onTop, int x, int y, int w, int h, int imageDepth)
- {
- QtNative.activityDelegate().createSurface(id, onTop, x, y, w, h, imageDepth);
- }
-
- public void destroySurface(int id)
- {
- QtNative.activityDelegate().destroySurface(id);
- }
-
- public int getSurfaceCount()
- {
- return QtNative.activityDelegate().getSurfaceCount();
- }
-
- public void hideSoftwareKeyboard()
- {
- QtNative.activityDelegate().hideSoftwareKeyboard();
- }
-
- public void hideSplashScreen()
- {
- QtNative.activityDelegate().hideSplashScreen();
- }
-
- public void hideSplashScreen(final int duration)
- {
- QtNative.activityDelegate().hideSplashScreen(duration);
- }
-
- public void initializeAccessibility()
- {
- QtNative.activityDelegate().initializeAccessibility();
- }
-
- public void insertNativeView(int id, View view, int x, int y, int w, int h)
- {
- QtNative.activityDelegate().insertNativeView(id, view, x, y, w, h);
- }
-
- public boolean loadApplication(Activity activity, ClassLoader classLoader, Bundle loaderParams)
- {
- return QtNative.activityDelegate().loadApplication(activity, classLoader, loaderParams);
- }
-
- public void onCreatePopupMenu(Menu menu)
- {
- QtNative.activityDelegate().onCreatePopupMenu(menu);
- }
-
- public void onTerminate()
- {
- QtNative.activityDelegate().onTerminate();
- }
-
- public void openContextMenu(final int x, final int y, final int w, final int h)
- {
- QtNative.activityDelegate().openContextMenu(x, y, w, h);
- }
-
- public void resetOptionsMenu()
- {
- QtNative.activityDelegate().resetOptionsMenu();
- }
-
- public void resetSoftwareKeyboard()
- {
- QtNative.activityDelegate().resetSoftwareKeyboard();
- }
-
- public boolean setKeyboardVisibility(boolean visibility, long timeStamp)
- {
- return QtNative.activityDelegate().setKeyboardVisibility(visibility, timeStamp);
- }
-
- public void setSurfaceGeometry(int id, int x, int y, int w, int h)
- {
- QtNative.activityDelegate().setSurfaceGeometry(id, x, y, w, h);
- }
-
- public void setSystemUiVisibility(int systemUiVisibility)
- {
- QtNative.activityDelegate().setSystemUiVisibility(systemUiVisibility);
- }
-
- public void showSoftwareKeyboard(final int x, final int y, final int width,
- final int height, final int inputHints,
- final int enterKeyType)
- {
- QtNative.activityDelegate().showSoftwareKeyboard(x, y, width, height, inputHints, enterKeyType);
- }
-
- public boolean startApplication()
- {
- return QtNative.activityDelegate().startApplication();
- }
-
- public void updateFullScreen()
- {
- QtNative.activityDelegate().updateFullScreen();
- }
-
- public void updateHandles(int mode, int editX, int editY, int editButtons,
- int x1, int y1, int x2, int y2, boolean rtl)
- {
- QtNative.activityDelegate().updateHandles(mode, editX, editY, editButtons, x1, y1, x2, y2, rtl);
- }
-
- public void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd)
- {
- QtNative.activityDelegate().updateSelection(selStart, selEnd, candidatesStart, candidatesEnd);
- }
-
- public void notifyAccessibilityLocationChange(int viewId)
- {
- QtNative.activityDelegate().notifyAccessibilityLocationChange(viewId);
- }
-
- public void notifyObjectHide(int viewId, int parentId)
- {
- QtNative.activityDelegate().notifyObjectHide(viewId, parentId);
- }
-
- public void notifyObjectFocus(int viewId)
- {
- QtNative.activityDelegate().notifyObjectFocus(viewId);
- }
-
- public void notifyValueChanged(int viewId, String value)
- {
- QtNative.activityDelegate().notifyValueChanged(viewId, value);
- }
-
- public boolean isKeyboardVisible()
- {
- return QtNative.activityDelegate().isKeyboardVisible();
- }
-
- public void notifyQtAndroidPluginRunning(boolean running)
- {
- QtNative.activityDelegate().notifyQtAndroidPluginRunning(running);
}
}
diff --git a/src/android/java/src/org/qtproject/qt/android/bindings/QtActivityLoader.java b/src/android/java/src/org/qtproject/qt/android/bindings/QtActivityLoader.java
deleted file mode 100644
index 7824ddd4a0..0000000000
--- a/src/android/java/src/org/qtproject/qt/android/bindings/QtActivityLoader.java
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// Copyright (c) 2016, BogDan Vatra <bogdan@kde.org>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-package org.qtproject.qt.android.bindings;
-
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.ColorDrawable;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.view.Window;
-
-import org.qtproject.qt.android.QtNative;
-
-import java.lang.reflect.Field;
-
-public class QtActivityLoader extends QtLoader {
- QtActivity m_activity;
-
- QtActivityLoader(QtActivity activity)
- {
- super(activity, QtActivity.class);
- m_activity = activity;
- }
-
- @Override
- protected String loaderClassName() {
- return "org.qtproject.qt.android.QtActivityDelegate";
- }
-
- @Override
- protected Class<?> contextClassName() {
- return android.app.Activity.class;
- }
-
- @Override
- protected void finish() {
- m_activity.finish();
- }
-
- @Override
- protected String getTitle() {
- return (String) m_activity.getTitle();
- }
-
- @Override
- protected void runOnUiThread(Runnable run) {
- m_activity.runOnUiThread(run);
- }
-
- @Override
- Intent getIntent() {
- return m_activity.getIntent();
- }
-
- public void onCreate(Bundle savedInstanceState) {
- try {
- m_contextInfo = m_activity.getPackageManager().getActivityInfo(m_activity.getComponentName(), PackageManager.GET_META_DATA);
- int theme = ((ActivityInfo)m_contextInfo).getThemeResource();
- for (Field f : Class.forName("android.R$style").getDeclaredFields()) {
- if (f.getInt(null) == theme) {
- QT_ANDROID_THEMES = new String[] {f.getName()};
- QT_ANDROID_DEFAULT_THEME = f.getName();
- break;
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- finish();
- return;
- }
-
- try {
- m_activity.setTheme(Class.forName("android.R$style").getDeclaredField(QT_ANDROID_DEFAULT_THEME).getInt(null));
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- m_activity.requestWindowFeature(Window.FEATURE_ACTION_BAR);
- if (QtNative.isStarted()) {
- boolean updated = QtNative.activityDelegate().updateActivity(m_activity);
- if (!updated) {
- // could not update the activity so restart the application
- Intent intent = Intent.makeRestartActivityTask(m_activity.getComponentName());
- m_activity.startActivity(intent);
- QtNative.quitApp();
- Runtime.getRuntime().exit(0);
- }
-
- // there can only be a valid delegate object if the QtNative was started.
- if (QtApplication.m_delegateObject != null && QtApplication.onCreate != null)
- QtApplication.invokeDelegateMethod(QtApplication.onCreate, savedInstanceState);
-
- return;
- }
-
- m_displayDensity = m_activity.getResources().getDisplayMetrics().densityDpi;
-
- ENVIRONMENT_VARIABLES += "\tQT_ANDROID_THEME=" + QT_ANDROID_DEFAULT_THEME
- + "/\tQT_ANDROID_THEME_DISPLAY_DPI=" + m_displayDensity + "\t";
-
- if (m_contextInfo.metaData.containsKey("android.app.background_running")
- && m_contextInfo.metaData.getBoolean("android.app.background_running")) {
- ENVIRONMENT_VARIABLES += "QT_BLOCK_EVENT_LOOPS_WHEN_SUSPENDED=0\t";
- } else {
- ENVIRONMENT_VARIABLES += "QT_BLOCK_EVENT_LOOPS_WHEN_SUSPENDED=1\t";
- }
-
- startApp(true);
-
- }
-}
diff --git a/src/android/java/src/org/qtproject/qt/android/bindings/QtApplication.java b/src/android/java/src/org/qtproject/qt/android/bindings/QtApplication.java
index cb6de3a7c5..d1330565c1 100644
--- a/src/android/java/src/org/qtproject/qt/android/bindings/QtApplication.java
+++ b/src/android/java/src/org/qtproject/qt/android/bindings/QtApplication.java
@@ -1,130 +1,15 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// Copyright (c) 2016, BogDan Vatra <bogdan@kde.org>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
package org.qtproject.qt.android.bindings;
-import android.app.Application;
+import org.qtproject.qt.android.QtApplicationBase;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.HashMap;
-
-public class QtApplication extends Application
+public class QtApplication extends QtApplicationBase
{
- public final static String QtTAG = "Qt";
- public static Object m_delegateObject = null;
- public static HashMap<String, ArrayList<Method>> m_delegateMethods= new HashMap<String, ArrayList<Method>>();
- public static Method dispatchKeyEvent = null;
- public static Method dispatchPopulateAccessibilityEvent = null;
- public static Method dispatchTouchEvent = null;
- public static Method dispatchTrackballEvent = null;
- public static Method onKeyDown = null;
- public static Method onKeyMultiple = null;
- public static Method onKeyUp = null;
- public static Method onTouchEvent = null;
- public static Method onTrackballEvent = null;
- public static Method onActivityResult = null;
- public static Method onCreate = null;
- public static Method onKeyLongPress = null;
- public static Method dispatchKeyShortcutEvent = null;
- public static Method onKeyShortcut = null;
- public static Method dispatchGenericMotionEvent = null;
- public static Method onGenericMotionEvent = null;
- public static Method onRequestPermissionsResult = null;
- private static String activityClassName;
- public static void setQtContextDelegate(Class<?> clazz, Object listener)
- {
- m_delegateObject = listener;
- activityClassName = clazz.getCanonicalName();
-
- ArrayList<Method> delegateMethods = new ArrayList<Method>();
- for (Method m : listener.getClass().getMethods()) {
- if (m.getDeclaringClass().getName().startsWith("org.qtproject.qt.android"))
- delegateMethods.add(m);
- }
-
- ArrayList<Field> applicationFields = new ArrayList<Field>();
- for (Field f : QtApplication.class.getFields()) {
- if (f.getDeclaringClass().getName().equals(QtApplication.class.getName()))
- applicationFields.add(f);
- }
-
- for (Method delegateMethod : delegateMethods) {
- try {
- clazz.getDeclaredMethod(delegateMethod.getName(), delegateMethod.getParameterTypes());
- if (QtApplication.m_delegateMethods.containsKey(delegateMethod.getName())) {
- QtApplication.m_delegateMethods.get(delegateMethod.getName()).add(delegateMethod);
- } else {
- ArrayList<Method> delegateSet = new ArrayList<Method>();
- delegateSet.add(delegateMethod);
- QtApplication.m_delegateMethods.put(delegateMethod.getName(), delegateSet);
- }
- for (Field applicationField:applicationFields) {
- if (applicationField.getName().equals(delegateMethod.getName())) {
- try {
- applicationField.set(null, delegateMethod);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- } catch (Exception e) { }
- }
- }
-
@Override
public void onTerminate() {
- if (m_delegateObject != null && m_delegateMethods.containsKey("onTerminate"))
- invokeDelegateMethod(m_delegateMethods.get("onTerminate").get(0));
super.onTerminate();
}
-
- public static class InvokeResult
- {
- public boolean invoked = false;
- public Object methodReturns = null;
- }
-
- private static int stackDeep=-1;
- public static InvokeResult invokeDelegate(Object... args)
- {
- InvokeResult result = new InvokeResult();
- if (m_delegateObject == null)
- return result;
- StackTraceElement[] elements = Thread.currentThread().getStackTrace();
- if (-1 == stackDeep) {
- for (int it=0;it<elements.length;it++)
- if (elements[it].getClassName().equals(activityClassName)) {
- stackDeep = it;
- break;
- }
- }
- if (-1 == stackDeep)
- return result;
-
- final String methodName=elements[stackDeep].getMethodName();
- if (!m_delegateMethods.containsKey(methodName))
- return result;
-
- for (Method m : m_delegateMethods.get(methodName)) {
- if (m.getParameterTypes().length == args.length) {
- result.methodReturns = invokeDelegateMethod(m, args);
- result.invoked = true;
- return result;
- }
- }
- return result;
- }
-
- public static Object invokeDelegateMethod(Method m, Object... args)
- {
- try {
- return m.invoke(m_delegateObject, args);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
}
diff --git a/src/android/java/src/org/qtproject/qt/android/bindings/QtLoader.java b/src/android/java/src/org/qtproject/qt/android/bindings/QtLoader.java
deleted file mode 100644
index dcb0941556..0000000000
--- a/src/android/java/src/org/qtproject/qt/android/bindings/QtLoader.java
+++ /dev/null
@@ -1,386 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// Copyright (c) 2019, BogDan Vatra <bogdan@kde.org>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-package org.qtproject.qt.android.bindings;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.pm.ComponentInfo;
-import android.content.res.Resources;
-import android.os.Build;
-import android.os.Bundle;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-
-import dalvik.system.DexClassLoader;
-
-public abstract class QtLoader {
-
- public static final String ERROR_CODE_KEY = "error.code";
- public static final String ERROR_MESSAGE_KEY = "error.message";
- public static final String DEX_PATH_KEY = "dex.path";
- public static final String LIB_PATH_KEY = "lib.path";
- public static final String LOADER_CLASS_NAME_KEY = "loader.class.name";
- public static final String NATIVE_LIBRARIES_KEY = "native.libraries";
- public static final String ENVIRONMENT_VARIABLES_KEY = "environment.variables";
- public static final String APPLICATION_PARAMETERS_KEY = "application.parameters";
- public static final String BUNDLED_LIBRARIES_KEY = "bundled.libraries";
- public static final String MAIN_LIBRARY_KEY = "main.library";
- public static final String STATIC_INIT_CLASSES_KEY = "static.init.classes";
- public static final String EXTRACT_STYLE_KEY = "extract.android.style";
- private static final String EXTRACT_STYLE_MINIMAL_KEY = "extract.android.style.option";
-
- // These parameters matter in case of deploying application as system (embedded into firmware)
- public static final String SYSTEM_LIB_PATH = "/system/lib/";
-
- public String APPLICATION_PARAMETERS = null; // use this variable to pass any parameters to your application,
- // the parameters must not contain any white spaces
- // and must be separated with "\t"
- // e.g "-param1\t-param2=value2\t-param3\tvalue3"
-
- public String ENVIRONMENT_VARIABLES = "QT_USE_ANDROID_NATIVE_DIALOGS=1";
- // use this variable to add any environment variables to your application.
- // the env vars must be separated with "\t"
- // e.g. "ENV_VAR1=1\tENV_VAR2=2\t"
- // Currently the following vars are used by the android plugin:
- // * QT_USE_ANDROID_NATIVE_DIALOGS -1 to use the android native dialogs.
-
- public String[] QT_ANDROID_THEMES = null; // A list with all themes that your application want to use.
- // The name of the theme must be the same with any theme from
- // http://developer.android.com/reference/android/R.style.html
- // The most used themes are:
- // * "Theme" - (fallback) check http://developer.android.com/reference/android/R.style.html#Theme
- // * "Theme_Black" - check http://developer.android.com/reference/android/R.style.html#Theme_Black
- // * "Theme_Light" - (default for API <=10) check http://developer.android.com/reference/android/R.style.html#Theme_Light
- // * "Theme_Holo" - check http://developer.android.com/reference/android/R.style.html#Theme_Holo
- // * "Theme_Holo_Light" - (default for API 11-13) check http://developer.android.com/reference/android/R.style.html#Theme_Holo_Light
- // * "Theme_DeviceDefault" - check http://developer.android.com/reference/android/R.style.html#Theme_DeviceDefault
- // * "Theme_DeviceDefault_Light" - (default for API 14+) check http://developer.android.com/reference/android/R.style.html#Theme_DeviceDefault_Light
-
- public String QT_ANDROID_DEFAULT_THEME = null; // sets the default theme.
-
- public ArrayList<String> m_qtLibs = null; // required qt libs
- public int m_displayDensity = -1;
- private ContextWrapper m_context;
- protected ComponentInfo m_contextInfo;
- private Class<?> m_delegateClass;
-
- private static ArrayList<FileOutputStream> m_fileOutputStreams = new ArrayList<FileOutputStream>();
- // List of open file streams associated with files copied during installation.
-
- QtLoader(ContextWrapper context, Class<?> clazz) {
- m_context = context;
- m_delegateClass = clazz;
- }
-
- // Implement in subclass
- protected void finish() {}
-
- protected String getTitle() {
- return "Qt";
- }
-
- protected void runOnUiThread(Runnable run) {
- run.run();
- }
-
- protected abstract String loaderClassName();
- protected abstract Class<?> contextClassName();
-
- Intent getIntent()
- {
- return null;
- }
- // Implement in subclass
-
- private final List<String> supportedAbis = Arrays.asList(Build.SUPPORTED_ABIS);
- private String preferredAbi = null;
-
- private ArrayList<String> prefferedAbiLibs(String []libs)
- {
- HashMap<String, ArrayList<String>> abisLibs = new HashMap<>();
- for (String lib : libs) {
- String[] archLib = lib.split(";", 2);
- if (preferredAbi != null && !archLib[0].equals(preferredAbi))
- continue;
- if (!abisLibs.containsKey(archLib[0]))
- abisLibs.put(archLib[0], new ArrayList<String>());
- abisLibs.get(archLib[0]).add(archLib[1]);
- }
-
- if (preferredAbi != null) {
- if (abisLibs.containsKey(preferredAbi)) {
- return abisLibs.get(preferredAbi);
- }
- return new ArrayList<String>();
- }
-
- for (String abi: supportedAbis) {
- if (abisLibs.containsKey(abi)) {
- preferredAbi = abi;
- return abisLibs.get(abi);
- }
- }
- return new ArrayList<String>();
- }
-
- // this function is used to load and start the loader
- private void loadApplication(Bundle loaderParams)
- {
- final Resources resources = m_context.getResources();
- final String packageName = m_context.getPackageName();
- try {
- final int errorCode = loaderParams.getInt(ERROR_CODE_KEY);
- if (errorCode != 0) {
- // fatal error, show the error and quit
- AlertDialog errorDialog = new AlertDialog.Builder(m_context).create();
- errorDialog.setMessage(loaderParams.getString(ERROR_MESSAGE_KEY));
- errorDialog.setButton(Dialog.BUTTON_POSITIVE,
- resources.getString(android.R.string.ok),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- finish();
- }
- });
- errorDialog.show();
- return;
- }
-
- // add all bundled Qt libs to loader params
- int id = resources.getIdentifier("bundled_libs", "array", packageName);
- final String[] bundledLibs = resources.getStringArray(id);
- ArrayList<String> libs = new ArrayList<>(prefferedAbiLibs(bundledLibs));
-
- String libName = null;
- if (m_contextInfo.metaData.containsKey("android.app.lib_name")) {
- libName = m_contextInfo.metaData.getString("android.app.lib_name") + "_" + preferredAbi;
- loaderParams.putString(MAIN_LIBRARY_KEY, libName); //main library contains main() function
- }
-
- loaderParams.putStringArrayList(BUNDLED_LIBRARIES_KEY, libs);
-
- // load and start QtLoader class
- DexClassLoader classLoader = new DexClassLoader(loaderParams.getString(DEX_PATH_KEY), // .jar/.apk files
- m_context.getDir("outdex", Context.MODE_PRIVATE).getAbsolutePath(), // directory where optimized DEX files should be written.
- loaderParams.containsKey(LIB_PATH_KEY) ? loaderParams.getString(LIB_PATH_KEY) : null, // libs folder (if exists)
- m_context.getClassLoader()); // parent loader
-
- Class<?> loaderClass = classLoader.loadClass(loaderParams.getString(LOADER_CLASS_NAME_KEY)); // load QtLoader class
- Object qtLoader = loaderClass.newInstance(); // create an instance
- Method prepareAppMethod = qtLoader.getClass().getMethod("loadApplication",
- contextClassName(),
- ClassLoader.class,
- Bundle.class);
- if (!(Boolean)prepareAppMethod.invoke(qtLoader, m_context, classLoader, loaderParams))
- throw new Exception("");
-
- QtApplication.setQtContextDelegate(m_delegateClass, qtLoader);
-
- Method startAppMethod=qtLoader.getClass().getMethod("startApplication");
- if (!(Boolean)startAppMethod.invoke(qtLoader))
- throw new Exception("");
-
- } catch (Exception e) {
- e.printStackTrace();
- AlertDialog errorDialog = new AlertDialog.Builder(m_context).create();
- int id = resources.getIdentifier("fatal_error_msg", "string",
- packageName);
- errorDialog.setMessage(resources.getString(id));
- errorDialog.setButton(Dialog.BUTTON_POSITIVE,
- resources.getString(android.R.string.ok),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- finish();
- }
- });
- errorDialog.show();
- }
- }
-
- public void startApp(final boolean firstStart)
- {
- try {
- final Resources resources = m_context.getResources();
- final String packageName = m_context.getPackageName();
- int id = resources.getIdentifier("qt_libs", "array", packageName);
- m_qtLibs = prefferedAbiLibs(resources.getStringArray(id));
-
- id = resources.getIdentifier("use_local_qt_libs", "string", packageName);
- final int useLocalLibs = Integer.parseInt(resources.getString(id));
-
- if (useLocalLibs == 1) {
- ArrayList<String> libraryList = new ArrayList<>();
- String libsDir = null;
- String bundledLibsDir = null;
-
- id = resources.getIdentifier("bundle_local_qt_libs", "string", packageName);
- final int bundleLocalLibs = Integer.parseInt(resources.getString(id));
- if (bundleLocalLibs == 0) {
- String systemLibsPrefix;
- final String systemLibsKey = "android.app.system_libs_prefix";
- // First check if user has provided system libs prefix in AndroidManifest
- if (m_contextInfo.applicationInfo.metaData != null &&
- m_contextInfo.applicationInfo.metaData.containsKey(systemLibsKey)) {
- systemLibsPrefix = m_contextInfo.applicationInfo.metaData.getString(systemLibsKey);
- } else {
- // If not, check if it's provided by androiddeployqt in libs.xml
- id = resources.getIdentifier("system_libs_prefix","string",
- packageName);
- systemLibsPrefix = resources.getString(id);
- }
- if (systemLibsPrefix.isEmpty()) {
- systemLibsPrefix = SYSTEM_LIB_PATH;
- Log.e(QtApplication.QtTAG, "It looks like app deployed using Unbundled "
- + "deployment. It may be necessary to specify path to directory "
- + "where Qt libraries are installed using either "
- + "android.app.system_libs_prefix metadata variable in your "
- + "AndroidManifest.xml or QT_ANDROID_SYSTEM_LIBS_PATH in your "
- + "CMakeLists.txt");
- Log.e(QtApplication.QtTAG, "Using " + SYSTEM_LIB_PATH + " as default path");
- }
-
- File systemLibraryDir = new File(systemLibsPrefix);
- if (systemLibraryDir.exists() && systemLibraryDir.isDirectory()
- && systemLibraryDir.list().length > 0) {
- libsDir = systemLibsPrefix;
- bundledLibsDir = systemLibsPrefix;
- } else {
- Log.e(QtApplication.QtTAG,
- "System library directory " + systemLibsPrefix
- + " does not exist or is empty.");
- }
- } else {
- String nativeLibraryPrefix = m_context.getApplicationInfo().nativeLibraryDir + "/";
- File nativeLibraryDir = new File(nativeLibraryPrefix);
- if (nativeLibraryDir.exists() && nativeLibraryDir.isDirectory() && nativeLibraryDir.list().length > 0) {
- libsDir = nativeLibraryPrefix;
- bundledLibsDir = nativeLibraryPrefix;
- } else {
- Log.e(QtApplication.QtTAG,
- "Native library directory " + nativeLibraryPrefix
- + " does not exist or is empty.");
- }
- }
-
- if (libsDir == null)
- throw new Exception("");
-
-
- if (m_qtLibs != null) {
- String libPrefix = libsDir + "lib";
- for (String lib : m_qtLibs)
- libraryList.add(libPrefix + lib + ".so");
- }
-
- id = resources.getIdentifier("load_local_libs", "array", packageName);
- ArrayList<String> localLibs = prefferedAbiLibs(resources.getStringArray(id));
- for (String libs : localLibs) {
- for (String lib : libs.split(":")) {
- if (!lib.isEmpty())
- libraryList.add(libsDir + lib);
- }
- }
- if (bundledLibsDir != null) {
- ENVIRONMENT_VARIABLES += "\tQT_PLUGIN_PATH=" + bundledLibsDir;
- ENVIRONMENT_VARIABLES += "\tQML_PLUGIN_PATH=" + bundledLibsDir;
- }
-
- Bundle loaderParams = new Bundle();
- loaderParams.putInt(ERROR_CODE_KEY, 0);
- loaderParams.putString(DEX_PATH_KEY, new String());
- loaderParams.putString(LOADER_CLASS_NAME_KEY, loaderClassName());
-
- id = resources.getIdentifier("static_init_classes", "string", packageName);
- loaderParams.putStringArray(STATIC_INIT_CLASSES_KEY, resources.getString(id)
- .split(":"));
-
- loaderParams.putStringArrayList(NATIVE_LIBRARIES_KEY, libraryList);
-
-
- String themePath = m_context.getApplicationInfo().dataDir + "/qt-reserved-files/android-style/";
- String stylePath = themePath + m_displayDensity + "/";
-
- String extractOption = "default";
- if (m_contextInfo.metaData.containsKey("android.app.extract_android_style")) {
- extractOption = m_contextInfo.metaData.getString("android.app.extract_android_style");
- if (!extractOption.equals("default") && !extractOption.equals("full") && !extractOption.equals("minimal") && !extractOption.equals("none")) {
- Log.e(QtApplication.QtTAG, "Invalid extract_android_style option \"" + extractOption + "\", defaulting to \"default\"");
- extractOption = "default";
- }
- }
-
- // QTBUG-69810: The extraction code will trigger compatibility warnings on Android SDK version >= 28
- // when the target SDK version is set to something lower then 28, so default to "none" and issue a warning
- // if that is the case.
- if (extractOption.equals("default")) {
- final int targetSdkVersion = m_context.getApplicationInfo().targetSdkVersion;
- if (targetSdkVersion < 28 && Build.VERSION.SDK_INT >= 28) {
- Log.e(QtApplication.QtTAG, "extract_android_style option set to \"none\" when targetSdkVersion is less then 28");
- extractOption = "none";
- }
- }
-
- if (!extractOption.equals("none")) {
- loaderParams.putString(EXTRACT_STYLE_KEY, stylePath);
- loaderParams.putBoolean(EXTRACT_STYLE_MINIMAL_KEY, extractOption.equals("minimal"));
- }
-
- if (extractOption.equals("full"))
- ENVIRONMENT_VARIABLES += "\tQT_USE_ANDROID_NATIVE_STYLE=1";
-
- ENVIRONMENT_VARIABLES += "\tANDROID_STYLE_PATH=" + stylePath;
-
- if (m_contextInfo.metaData.containsKey("android.app.trace_location")) {
- String loc = m_contextInfo.metaData.getString("android.app.trace_location");
- ENVIRONMENT_VARIABLES += "\tQTRACE_LOCATION="+loc;
- }
-
- loaderParams.putString(ENVIRONMENT_VARIABLES_KEY, ENVIRONMENT_VARIABLES);
-
- String appParams = null;
- if (APPLICATION_PARAMETERS != null)
- appParams = APPLICATION_PARAMETERS;
-
- Intent intent = getIntent();
- if (intent != null) {
- String parameters = intent.getStringExtra("applicationArguments");
- if (parameters != null)
- if (appParams == null)
- appParams = parameters;
- else
- appParams += '\t' + parameters;
- }
-
- if (m_contextInfo.metaData.containsKey("android.app.arguments")) {
- String parameters = m_contextInfo.metaData.getString("android.app.arguments");
- if (appParams == null)
- appParams = parameters;
- else
- appParams += '\t' + parameters;
- }
-
- if (appParams != null)
- loaderParams.putString(APPLICATION_PARAMETERS_KEY, appParams);
-
- loadApplication(loaderParams);
- return;
- }
- } catch (Exception e) {
- Log.e(QtApplication.QtTAG, "Can't create main activity", e);
- }
- }
-}
diff --git a/src/android/java/src/org/qtproject/qt/android/bindings/QtService.java b/src/android/java/src/org/qtproject/qt/android/bindings/QtService.java
index 6a6aa03f2e..6569446901 100644
--- a/src/android/java/src/org/qtproject/qt/android/bindings/QtService.java
+++ b/src/android/java/src/org/qtproject/qt/android/bindings/QtService.java
@@ -1,148 +1,16 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// Copyright (c) 2016, BogDan Vatra <bogdan@kde.org>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
package org.qtproject.qt.android.bindings;
-import android.app.Service;
-import android.util.Log;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.os.IBinder;
+import org.qtproject.qt.android.QtServiceBase;
-import org.qtproject.qt.android.QtNative;
-
-public class QtService extends Service
+public class QtService extends QtServiceBase
{
- QtServiceLoader m_loader = new QtServiceLoader(this);
-
-
- /////////////////////////// forward all notifications ////////////////////////////
- /////////////////////////// Super class calls ////////////////////////////////////
- /////////////// PLEASE DO NOT CHANGE THE FOLLOWING CODE //////////////////////////
- //////////////////////////////////////////////////////////////////////////////////
- protected void onCreateHook() {
- // the application has already started
- // do not reload everything again
- if (QtNative.isStarted()) {
- m_loader = null;
- Log.w(QtNative.QtTAG,
- "A QtService tried to start in the same process as an initiated " +
- "QtActivity. That is not supported. This results in the service " +
- "functioning as an Android Service detached from Qt.");
- } else {
- m_loader.onCreate();
- }
- }
@Override
public void onCreate()
{
super.onCreate();
- onCreateHook();
- }
- //---------------------------------------------------------------------------
-
- @Override
- public void onDestroy()
- {
- super.onDestroy();
- QtApplication.invokeDelegate();
- }
- //---------------------------------------------------------------------------
-
- @Override
- public IBinder onBind(Intent intent)
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate(intent);
- if (res.invoked)
- return (IBinder)res.methodReturns;
- else
- return null;
- }
- //---------------------------------------------------------------------------
-
- @Override
- public void onConfigurationChanged(Configuration newConfig)
- {
- if (!QtApplication.invokeDelegate(newConfig).invoked)
- super.onConfigurationChanged(newConfig);
- }
- public void super_onConfigurationChanged(Configuration newConfig)
- {
- super.onConfigurationChanged(newConfig);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public void onLowMemory()
- {
- if (!QtApplication.invokeDelegate().invoked)
- super.onLowMemory();
- }
- //---------------------------------------------------------------------------
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId)
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate(intent, flags, startId);
- if (res.invoked)
- return (Integer) res.methodReturns;
- else
- return super.onStartCommand(intent, flags, startId);
- }
- public int super_onStartCommand(Intent intent, int flags, int startId)
- {
- return super.onStartCommand(intent, flags, startId);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public void onTaskRemoved(Intent rootIntent)
- {
- if (!QtApplication.invokeDelegate(rootIntent).invoked)
- super.onTaskRemoved(rootIntent);
- }
- public void super_onTaskRemoved(Intent rootIntent)
- {
- super.onTaskRemoved(rootIntent);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public void onTrimMemory(int level)
- {
- if (!QtApplication.invokeDelegate(level).invoked)
- super.onTrimMemory(level);
- }
- public void super_onTrimMemory(int level)
- {
- super.onTrimMemory(level);
- }
- //---------------------------------------------------------------------------
-
- @Override
- public boolean onUnbind(Intent intent)
- {
- QtApplication.InvokeResult res = QtApplication.invokeDelegate(intent);
- if (res.invoked)
- return (Boolean) res.methodReturns;
- else
- return super.onUnbind(intent);
- }
- public boolean super_onUnbind(Intent intent)
- {
- return super.onUnbind(intent);
- }
- //---------------------------------------------------------------------------
-
- public boolean loadApplication(Service service, ClassLoader classLoader, Bundle loaderParams)
- {
- return QtNative.serviceDelegate().loadApplication(service, classLoader, loaderParams);
- }
-
- public boolean startApplication()
- {
- return QtNative.serviceDelegate().startApplication();
}
}
diff --git a/src/android/java/src/org/qtproject/qt/android/bindings/QtServiceLoader.java b/src/android/java/src/org/qtproject/qt/android/bindings/QtServiceLoader.java
deleted file mode 100644
index 5511266305..0000000000
--- a/src/android/java/src/org/qtproject/qt/android/bindings/QtServiceLoader.java
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// Copyright (c) 2016, BogDan Vatra <bogdan@kde.org>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-package org.qtproject.qt.android.bindings;
-
-import android.os.Bundle;
-import android.content.ComponentName;
-import android.content.pm.PackageManager;
-
-public class QtServiceLoader extends QtLoader {
- QtService m_service;
- QtServiceLoader(QtService service) {
- super(service, QtService.class);
- m_service = service;
- }
-
- public void onCreate() {
- try {
- m_contextInfo = m_service.getPackageManager().getServiceInfo(new ComponentName(m_service, m_service.getClass()), PackageManager.GET_META_DATA);
- } catch (Exception e) {
- e.printStackTrace();
- m_service.stopSelf();
- return;
- }
-
- if (QtApplication.m_delegateObject != null && QtApplication.onCreate != null) {
- Bundle bundle = null;
- QtApplication.invokeDelegateMethod(QtApplication.onCreate, bundle);
- }
- startApp(true);
- }
-
- @Override
- protected void finish() {
- m_service.stopSelf();
- }
-
- @Override
- protected String loaderClassName() {
- return "org.qtproject.qt.android.QtServiceDelegate";
- }
-
- @Override
- protected Class<?> contextClassName() {
- return android.app.Service.class;
- }
-}
diff --git a/src/android/templates/AndroidManifest.xml b/src/android/templates/AndroidManifest.xml
index 8f91863719..21ceaacc2e 100644
--- a/src/android/templates/AndroidManifest.xml
+++ b/src/android/templates/AndroidManifest.xml
@@ -16,13 +16,11 @@
android:hardwareAccelerated="true"
android:label="-- %%INSERT_APP_NAME%% --"
android:requestLegacyExternalStorage="true"
- android:allowNativeHeapPointerTagging="false"
android:allowBackup="true"
android:fullBackupOnly="false">
<activity
android:name="org.qtproject.qt.android.bindings.QtActivity"
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
- android:label="-- %%INSERT_APP_NAME%% --"
android:launchMode="singleTop"
android:screenOrientation="unspecified"
android:exported="true">
@@ -38,10 +36,6 @@
<meta-data
android:name="android.app.arguments"
android:value="-- %%INSERT_APP_ARGUMENTS%% --" />
-
- <meta-data
- android:name="android.app.extract_android_style"
- android:value="minimal" />
</activity>
<provider
diff --git a/src/android/templates/build.gradle b/src/android/templates/build.gradle
index 33867903c2..f94ffbde54 100644
--- a/src/android/templates/build.gradle
+++ b/src/android/templates/build.gradle
@@ -18,7 +18,7 @@ apply plugin: 'com.android.application'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
- implementation 'androidx.core:core:1.8.0'
+ implementation 'androidx.core:core:1.10.1'
}
android {
@@ -35,7 +35,7 @@ android {
* Changing them manually might break the compilation!
*******************************************************/
- compileSdkVersion androidCompileSdkVersion.toInteger()
+ compileSdkVersion androidCompileSdkVersion
buildToolsVersion androidBuildToolsVersion
ndkVersion androidNdkVersion
diff --git a/src/android/templates/doc/src/android-manifest-file-configuration.qdoc b/src/android/templates/doc/src/android-manifest-file-configuration.qdoc
index 12432d1ba2..db0d3c7277 100644
--- a/src/android/templates/doc/src/android-manifest-file-configuration.qdoc
+++ b/src/android/templates/doc/src/android-manifest-file-configuration.qdoc
@@ -68,7 +68,7 @@ Qt sets the following manifest configuration by default:
default values are \c anyDensity, \c largeScreens,
\c normalScreens, and \c smallScreens.
\row
- \li {1, 7} \l {Android: App Manifest <application>}{<application>}
+ \li {1, 6} \l {Android: App Manifest <application>}{<application>}
\li android:name
\li The application class name. Default value is
\c {org.qtproject.qt.android.bindings.QtApplication}.
@@ -82,13 +82,6 @@ Qt sets the following manifest configuration by default:
\li android:requestLegacyExternalStorage
\li Whether to use Android scoped storage. The default value is \c true.
\row
- \li android:allowNativeHeapPointerTagging
- \li Whether or not the app has the Heap pointer tagging feature enabled.
- This has to be set to \c false when targeting Arm64 hardware with Android 11+
- because it can break QML's NaN-tagging scheme.
- For more information, see \l {Android: Tagged Pointers}{Tagged Pointers}.
- The default value is \c false.
-\row
\li android:allowBackup
\li Whether to allow the application to participate in the backup and restore
infrastructure. If this is set to \c false, no backup or restore of the
@@ -98,13 +91,10 @@ Qt sets the following manifest configuration by default:
\li Whether or not to use Auto Backup on devices where it is available.
The default value is \c false.
\row
- \li {1, 7} \l {Android: App Manifest <activity>}{<activity>}
+ \li {1, 6} \l {Android: App Manifest <activity>}{<activity>}
\li android:name
\li The activity class name. The default value is \c {org.qtproject.qt.android.bindings.QtActivity}.
\row
- \li android:label
- \li The activity name label. Default value is the Qt project's target name.
-\row
\li android:configChanges
\li Lists configuration changes that the activity handles. Default value is
\c orientation, \c uiMode, \c screenLayout, \c screenSize,
@@ -148,8 +138,7 @@ The following is a list of such meta-data defined by Qt:
\li Meta-data Name
\li Description
\row
- \target android.app.lib_name
- \li android.app.lib_name
+ \li android.app.lib_name \target android.app.lib_name
\li The filename of the native C++ library that is used by the activity.
\note This attribute is mandatory and shouldn't be removed.
Default value is the Qt project's target name.
@@ -159,8 +148,7 @@ The following is a list of such meta-data defined by Qt:
For more information, see \l {Style Extraction}.
The default value is \c minimal.
\row
- \target android.app.background_running
- \li android.app.background_running
+ \li android.app.background_running \target android.app.background_running
\li Sets whether the app keeps running tasks in the background.
Setting this to \c true is the equivalent of setting the environment
variable \c QT_BLOCK_EVENT_LOOPS_WHEN_SUSPENDED to \c 0.
@@ -170,8 +158,7 @@ The following is a list of such meta-data defined by Qt:
application tries to draw after \l {QGuiApplication::applicationStateChanged()}
signal is sent with a \l {Qt::ApplicationSuspended} state.
\row
- \target android.app.arguments
- \li android.app.arguments
+ \li android.app.arguments \target android.app.arguments
\li Sets a list of arguments to pass to the app \c {"arg1 arg2"}.
Populated from \c ANDROID_APPLICATION_ARGUMENTS (qmake) and
\c QT_ANDROID_APPLICATION_ARGUMENTS (CMake).
@@ -218,8 +205,7 @@ the \c <application> section:
\li Meta-data Name
\li Description
\row
- \target android.app.system_libs_prefix
- \li android.app.system_libs_prefix
+ \li android.app.system_libs_prefix \target android.app.system_libs_prefix
\li Specifies a custom system library path to use for library loading lookup.
This is necessary when using Qt libraries installed outside an app's
default native (JNI) library directory.
diff --git a/src/assets/CMakeLists.txt b/src/assets/CMakeLists.txt
new file mode 100644
index 0000000000..9357953132
--- /dev/null
+++ b/src/assets/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(icons)
diff --git a/src/assets/icons/128x128/document-new.png b/src/assets/icons/128x128/document-new.png
new file mode 100644
index 0000000000..8d86a4827a
--- /dev/null
+++ b/src/assets/icons/128x128/document-new.png
Binary files differ
diff --git a/src/assets/icons/128x128/document-open.png b/src/assets/icons/128x128/document-open.png
new file mode 100644
index 0000000000..2183dbbea6
--- /dev/null
+++ b/src/assets/icons/128x128/document-open.png
Binary files differ
diff --git a/src/assets/icons/128x128/document-print.png b/src/assets/icons/128x128/document-print.png
new file mode 100644
index 0000000000..9e7378aab2
--- /dev/null
+++ b/src/assets/icons/128x128/document-print.png
Binary files differ
diff --git a/src/assets/icons/128x128/document-save.png b/src/assets/icons/128x128/document-save.png
new file mode 100644
index 0000000000..e8b2840643
--- /dev/null
+++ b/src/assets/icons/128x128/document-save.png
Binary files differ
diff --git a/src/assets/icons/128x128/edit-copy.png b/src/assets/icons/128x128/edit-copy.png
new file mode 100644
index 0000000000..7585f4baa0
--- /dev/null
+++ b/src/assets/icons/128x128/edit-copy.png
Binary files differ
diff --git a/src/assets/icons/128x128/edit-cut.png b/src/assets/icons/128x128/edit-cut.png
new file mode 100644
index 0000000000..51ede2fe37
--- /dev/null
+++ b/src/assets/icons/128x128/edit-cut.png
Binary files differ
diff --git a/src/assets/icons/128x128/edit-delete.png b/src/assets/icons/128x128/edit-delete.png
new file mode 100644
index 0000000000..bdf785c828
--- /dev/null
+++ b/src/assets/icons/128x128/edit-delete.png
Binary files differ
diff --git a/src/assets/icons/128x128/edit-paste.png b/src/assets/icons/128x128/edit-paste.png
new file mode 100644
index 0000000000..690ffa172d
--- /dev/null
+++ b/src/assets/icons/128x128/edit-paste.png
Binary files differ
diff --git a/src/assets/icons/128x128/edit-redo.png b/src/assets/icons/128x128/edit-redo.png
new file mode 100644
index 0000000000..f1c97f71c2
--- /dev/null
+++ b/src/assets/icons/128x128/edit-redo.png
Binary files differ
diff --git a/src/assets/icons/128x128/edit-undo.png b/src/assets/icons/128x128/edit-undo.png
new file mode 100644
index 0000000000..e728cbf6e0
--- /dev/null
+++ b/src/assets/icons/128x128/edit-undo.png
Binary files differ
diff --git a/src/assets/icons/128x128/format-justify-center.png b/src/assets/icons/128x128/format-justify-center.png
new file mode 100644
index 0000000000..44ceb2af4d
--- /dev/null
+++ b/src/assets/icons/128x128/format-justify-center.png
Binary files differ
diff --git a/src/assets/icons/128x128/format-justify-fill.png b/src/assets/icons/128x128/format-justify-fill.png
new file mode 100644
index 0000000000..b99a850704
--- /dev/null
+++ b/src/assets/icons/128x128/format-justify-fill.png
Binary files differ
diff --git a/src/assets/icons/128x128/format-justify-left.png b/src/assets/icons/128x128/format-justify-left.png
new file mode 100644
index 0000000000..2b63887b49
--- /dev/null
+++ b/src/assets/icons/128x128/format-justify-left.png
Binary files differ
diff --git a/src/assets/icons/128x128/format-justify-right.png b/src/assets/icons/128x128/format-justify-right.png
new file mode 100644
index 0000000000..6c61889d59
--- /dev/null
+++ b/src/assets/icons/128x128/format-justify-right.png
Binary files differ
diff --git a/src/assets/icons/128x128/format-text-bold.png b/src/assets/icons/128x128/format-text-bold.png
new file mode 100644
index 0000000000..96a5ca88a2
--- /dev/null
+++ b/src/assets/icons/128x128/format-text-bold.png
Binary files differ
diff --git a/src/assets/icons/128x128/format-text-italic.png b/src/assets/icons/128x128/format-text-italic.png
new file mode 100644
index 0000000000..2bb71b4a4d
--- /dev/null
+++ b/src/assets/icons/128x128/format-text-italic.png
Binary files differ
diff --git a/src/assets/icons/128x128/format-text-underline.png b/src/assets/icons/128x128/format-text-underline.png
new file mode 100644
index 0000000000..ecf6830c92
--- /dev/null
+++ b/src/assets/icons/128x128/format-text-underline.png
Binary files differ
diff --git a/src/assets/icons/128x128@2/document-new@2x.png b/src/assets/icons/128x128@2/document-new@2x.png
new file mode 100644
index 0000000000..32776b51a9
--- /dev/null
+++ b/src/assets/icons/128x128@2/document-new@2x.png
Binary files differ
diff --git a/src/assets/icons/128x128@2/document-open@2x.png b/src/assets/icons/128x128@2/document-open@2x.png
new file mode 100644
index 0000000000..06e188b93b
--- /dev/null
+++ b/src/assets/icons/128x128@2/document-open@2x.png
Binary files differ
diff --git a/src/assets/icons/128x128@2/document-print@2x.png b/src/assets/icons/128x128@2/document-print@2x.png
new file mode 100644
index 0000000000..644e3c149a
--- /dev/null
+++ b/src/assets/icons/128x128@2/document-print@2x.png
Binary files differ
diff --git a/src/assets/icons/128x128@2/document-save@2x.png b/src/assets/icons/128x128@2/document-save@2x.png
new file mode 100644
index 0000000000..16fa70493a
--- /dev/null
+++ b/src/assets/icons/128x128@2/document-save@2x.png
Binary files differ
diff --git a/src/assets/icons/128x128@2/edit-copy@2x.png b/src/assets/icons/128x128@2/edit-copy@2x.png
new file mode 100644
index 0000000000..b18bead117
--- /dev/null
+++ b/src/assets/icons/128x128@2/edit-copy@2x.png
Binary files differ
diff --git a/src/assets/icons/128x128@2/edit-cut@2x.png b/src/assets/icons/128x128@2/edit-cut@2x.png
new file mode 100644
index 0000000000..d9454cebf1
--- /dev/null
+++ b/src/assets/icons/128x128@2/edit-cut@2x.png
Binary files differ
diff --git a/src/assets/icons/128x128@2/edit-delete@2x.png b/src/assets/icons/128x128@2/edit-delete@2x.png
new file mode 100644
index 0000000000..4081cdb2ca
--- /dev/null
+++ b/src/assets/icons/128x128@2/edit-delete@2x.png
Binary files differ
diff --git a/src/assets/icons/128x128@2/edit-paste@2x.png b/src/assets/icons/128x128@2/edit-paste@2x.png
new file mode 100644
index 0000000000..3358426818
--- /dev/null
+++ b/src/assets/icons/128x128@2/edit-paste@2x.png
Binary files differ
diff --git a/src/assets/icons/128x128@2/edit-redo@2x.png b/src/assets/icons/128x128@2/edit-redo@2x.png
new file mode 100644
index 0000000000..e28b28542c
--- /dev/null
+++ b/src/assets/icons/128x128@2/edit-redo@2x.png
Binary files differ
diff --git a/src/assets/icons/128x128@2/edit-undo@2x.png b/src/assets/icons/128x128@2/edit-undo@2x.png
new file mode 100644
index 0000000000..fe10f57a39
--- /dev/null
+++ b/src/assets/icons/128x128@2/edit-undo@2x.png
Binary files differ
diff --git a/src/assets/icons/128x128@2/format-justify-center@2x.png b/src/assets/icons/128x128@2/format-justify-center@2x.png
new file mode 100644
index 0000000000..d4ad74b0d0
--- /dev/null
+++ b/src/assets/icons/128x128@2/format-justify-center@2x.png
Binary files differ
diff --git a/src/assets/icons/128x128@2/format-justify-fill@2x.png b/src/assets/icons/128x128@2/format-justify-fill@2x.png
new file mode 100644
index 0000000000..bf0dd84bbb
--- /dev/null
+++ b/src/assets/icons/128x128@2/format-justify-fill@2x.png
Binary files differ
diff --git a/src/assets/icons/128x128@2/format-justify-left@2x.png b/src/assets/icons/128x128@2/format-justify-left@2x.png
new file mode 100644
index 0000000000..dde68c8514
--- /dev/null
+++ b/src/assets/icons/128x128@2/format-justify-left@2x.png
Binary files differ
diff --git a/src/assets/icons/128x128@2/format-justify-right@2x.png b/src/assets/icons/128x128@2/format-justify-right@2x.png
new file mode 100644
index 0000000000..8a5e7518bd
--- /dev/null
+++ b/src/assets/icons/128x128@2/format-justify-right@2x.png
Binary files differ
diff --git a/src/assets/icons/128x128@2/format-text-bold@2x.png b/src/assets/icons/128x128@2/format-text-bold@2x.png
new file mode 100644
index 0000000000..665d3ce37b
--- /dev/null
+++ b/src/assets/icons/128x128@2/format-text-bold@2x.png
Binary files differ
diff --git a/src/assets/icons/128x128@2/format-text-italic@2x.png b/src/assets/icons/128x128@2/format-text-italic@2x.png
new file mode 100644
index 0000000000..4b6846a6b9
--- /dev/null
+++ b/src/assets/icons/128x128@2/format-text-italic@2x.png
Binary files differ
diff --git a/src/assets/icons/128x128@2/format-text-underline@2x.png b/src/assets/icons/128x128@2/format-text-underline@2x.png
new file mode 100644
index 0000000000..601f73216a
--- /dev/null
+++ b/src/assets/icons/128x128@2/format-text-underline@2x.png
Binary files differ
diff --git a/src/assets/icons/16x16/document-new.png b/src/assets/icons/16x16/document-new.png
new file mode 100644
index 0000000000..893e7e1aec
--- /dev/null
+++ b/src/assets/icons/16x16/document-new.png
Binary files differ
diff --git a/src/assets/icons/16x16/document-open.png b/src/assets/icons/16x16/document-open.png
new file mode 100644
index 0000000000..b07906f40b
--- /dev/null
+++ b/src/assets/icons/16x16/document-open.png
Binary files differ
diff --git a/src/assets/icons/16x16/document-print.png b/src/assets/icons/16x16/document-print.png
new file mode 100644
index 0000000000..9341060076
--- /dev/null
+++ b/src/assets/icons/16x16/document-print.png
Binary files differ
diff --git a/src/assets/icons/16x16/document-save.png b/src/assets/icons/16x16/document-save.png
new file mode 100644
index 0000000000..6238718191
--- /dev/null
+++ b/src/assets/icons/16x16/document-save.png
Binary files differ
diff --git a/src/assets/icons/16x16/edit-copy.png b/src/assets/icons/16x16/edit-copy.png
new file mode 100644
index 0000000000..585f5bfc8d
--- /dev/null
+++ b/src/assets/icons/16x16/edit-copy.png
Binary files differ
diff --git a/src/assets/icons/16x16/edit-cut.png b/src/assets/icons/16x16/edit-cut.png
new file mode 100644
index 0000000000..661ef1ad03
--- /dev/null
+++ b/src/assets/icons/16x16/edit-cut.png
Binary files differ
diff --git a/src/assets/icons/16x16/edit-delete.png b/src/assets/icons/16x16/edit-delete.png
new file mode 100644
index 0000000000..7b5998df8a
--- /dev/null
+++ b/src/assets/icons/16x16/edit-delete.png
Binary files differ
diff --git a/src/assets/icons/16x16/edit-paste.png b/src/assets/icons/16x16/edit-paste.png
new file mode 100644
index 0000000000..6318a22caf
--- /dev/null
+++ b/src/assets/icons/16x16/edit-paste.png
Binary files differ
diff --git a/src/assets/icons/16x16/edit-redo.png b/src/assets/icons/16x16/edit-redo.png
new file mode 100644
index 0000000000..7eb10fe899
--- /dev/null
+++ b/src/assets/icons/16x16/edit-redo.png
Binary files differ
diff --git a/src/assets/icons/16x16/edit-undo.png b/src/assets/icons/16x16/edit-undo.png
new file mode 100644
index 0000000000..108712547c
--- /dev/null
+++ b/src/assets/icons/16x16/edit-undo.png
Binary files differ
diff --git a/src/assets/icons/16x16/format-justify-center.png b/src/assets/icons/16x16/format-justify-center.png
new file mode 100644
index 0000000000..6b0951fa5d
--- /dev/null
+++ b/src/assets/icons/16x16/format-justify-center.png
Binary files differ
diff --git a/src/assets/icons/16x16/format-justify-fill.png b/src/assets/icons/16x16/format-justify-fill.png
new file mode 100644
index 0000000000..6e1c10d7c4
--- /dev/null
+++ b/src/assets/icons/16x16/format-justify-fill.png
Binary files differ
diff --git a/src/assets/icons/16x16/format-justify-left.png b/src/assets/icons/16x16/format-justify-left.png
new file mode 100644
index 0000000000..9dfdc89b68
--- /dev/null
+++ b/src/assets/icons/16x16/format-justify-left.png
Binary files differ
diff --git a/src/assets/icons/16x16/format-justify-right.png b/src/assets/icons/16x16/format-justify-right.png
new file mode 100644
index 0000000000..36a52081f1
--- /dev/null
+++ b/src/assets/icons/16x16/format-justify-right.png
Binary files differ
diff --git a/src/assets/icons/16x16/format-text-bold.png b/src/assets/icons/16x16/format-text-bold.png
new file mode 100644
index 0000000000..a079317a94
--- /dev/null
+++ b/src/assets/icons/16x16/format-text-bold.png
Binary files differ
diff --git a/src/assets/icons/16x16/format-text-italic.png b/src/assets/icons/16x16/format-text-italic.png
new file mode 100644
index 0000000000..04202b2842
--- /dev/null
+++ b/src/assets/icons/16x16/format-text-italic.png
Binary files differ
diff --git a/src/assets/icons/16x16/format-text-underline.png b/src/assets/icons/16x16/format-text-underline.png
new file mode 100644
index 0000000000..a80368212d
--- /dev/null
+++ b/src/assets/icons/16x16/format-text-underline.png
Binary files differ
diff --git a/src/assets/icons/16x16@2/document-new@2x.png b/src/assets/icons/16x16@2/document-new@2x.png
new file mode 100644
index 0000000000..482ae52024
--- /dev/null
+++ b/src/assets/icons/16x16@2/document-new@2x.png
Binary files differ
diff --git a/src/assets/icons/16x16@2/document-open@2x.png b/src/assets/icons/16x16@2/document-open@2x.png
new file mode 100644
index 0000000000..9858b146f4
--- /dev/null
+++ b/src/assets/icons/16x16@2/document-open@2x.png
Binary files differ
diff --git a/src/assets/icons/16x16@2/document-print@2x.png b/src/assets/icons/16x16@2/document-print@2x.png
new file mode 100644
index 0000000000..1672ec5897
--- /dev/null
+++ b/src/assets/icons/16x16@2/document-print@2x.png
Binary files differ
diff --git a/src/assets/icons/16x16@2/document-save@2x.png b/src/assets/icons/16x16@2/document-save@2x.png
new file mode 100644
index 0000000000..f04de74673
--- /dev/null
+++ b/src/assets/icons/16x16@2/document-save@2x.png
Binary files differ
diff --git a/src/assets/icons/16x16@2/edit-copy@2x.png b/src/assets/icons/16x16@2/edit-copy@2x.png
new file mode 100644
index 0000000000..bbb34cc4c2
--- /dev/null
+++ b/src/assets/icons/16x16@2/edit-copy@2x.png
Binary files differ
diff --git a/src/assets/icons/16x16@2/edit-cut@2x.png b/src/assets/icons/16x16@2/edit-cut@2x.png
new file mode 100644
index 0000000000..d89ef6c016
--- /dev/null
+++ b/src/assets/icons/16x16@2/edit-cut@2x.png
Binary files differ
diff --git a/src/assets/icons/16x16@2/edit-delete@2x.png b/src/assets/icons/16x16@2/edit-delete@2x.png
new file mode 100644
index 0000000000..4c97ee2495
--- /dev/null
+++ b/src/assets/icons/16x16@2/edit-delete@2x.png
Binary files differ
diff --git a/src/assets/icons/16x16@2/edit-paste@2x.png b/src/assets/icons/16x16@2/edit-paste@2x.png
new file mode 100644
index 0000000000..299fa77686
--- /dev/null
+++ b/src/assets/icons/16x16@2/edit-paste@2x.png
Binary files differ
diff --git a/src/assets/icons/16x16@2/edit-redo@2x.png b/src/assets/icons/16x16@2/edit-redo@2x.png
new file mode 100644
index 0000000000..4f8849c711
--- /dev/null
+++ b/src/assets/icons/16x16@2/edit-redo@2x.png
Binary files differ
diff --git a/src/assets/icons/16x16@2/edit-undo@2x.png b/src/assets/icons/16x16@2/edit-undo@2x.png
new file mode 100644
index 0000000000..b3d366c53f
--- /dev/null
+++ b/src/assets/icons/16x16@2/edit-undo@2x.png
Binary files differ
diff --git a/src/assets/icons/16x16@2/format-justify-center@2x.png b/src/assets/icons/16x16@2/format-justify-center@2x.png
new file mode 100644
index 0000000000..80c3afd9a6
--- /dev/null
+++ b/src/assets/icons/16x16@2/format-justify-center@2x.png
Binary files differ
diff --git a/src/assets/icons/16x16@2/format-justify-fill@2x.png b/src/assets/icons/16x16@2/format-justify-fill@2x.png
new file mode 100644
index 0000000000..33589ea25d
--- /dev/null
+++ b/src/assets/icons/16x16@2/format-justify-fill@2x.png
Binary files differ
diff --git a/src/assets/icons/16x16@2/format-justify-left@2x.png b/src/assets/icons/16x16@2/format-justify-left@2x.png
new file mode 100644
index 0000000000..ba02821135
--- /dev/null
+++ b/src/assets/icons/16x16@2/format-justify-left@2x.png
Binary files differ
diff --git a/src/assets/icons/16x16@2/format-justify-right@2x.png b/src/assets/icons/16x16@2/format-justify-right@2x.png
new file mode 100644
index 0000000000..8e15d0cb44
--- /dev/null
+++ b/src/assets/icons/16x16@2/format-justify-right@2x.png
Binary files differ
diff --git a/src/assets/icons/16x16@2/format-text-bold@2x.png b/src/assets/icons/16x16@2/format-text-bold@2x.png
new file mode 100644
index 0000000000..754efdd975
--- /dev/null
+++ b/src/assets/icons/16x16@2/format-text-bold@2x.png
Binary files differ
diff --git a/src/assets/icons/16x16@2/format-text-italic@2x.png b/src/assets/icons/16x16@2/format-text-italic@2x.png
new file mode 100644
index 0000000000..6db31a4f69
--- /dev/null
+++ b/src/assets/icons/16x16@2/format-text-italic@2x.png
Binary files differ
diff --git a/src/assets/icons/16x16@2/format-text-underline@2x.png b/src/assets/icons/16x16@2/format-text-underline@2x.png
new file mode 100644
index 0000000000..977cde9d97
--- /dev/null
+++ b/src/assets/icons/16x16@2/format-text-underline@2x.png
Binary files differ
diff --git a/src/assets/icons/256x256/document-new.png b/src/assets/icons/256x256/document-new.png
new file mode 100644
index 0000000000..32776b51a9
--- /dev/null
+++ b/src/assets/icons/256x256/document-new.png
Binary files differ
diff --git a/src/assets/icons/256x256/document-open.png b/src/assets/icons/256x256/document-open.png
new file mode 100644
index 0000000000..06e188b93b
--- /dev/null
+++ b/src/assets/icons/256x256/document-open.png
Binary files differ
diff --git a/src/assets/icons/256x256/document-print.png b/src/assets/icons/256x256/document-print.png
new file mode 100644
index 0000000000..644e3c149a
--- /dev/null
+++ b/src/assets/icons/256x256/document-print.png
Binary files differ
diff --git a/src/assets/icons/256x256/document-save.png b/src/assets/icons/256x256/document-save.png
new file mode 100644
index 0000000000..16fa70493a
--- /dev/null
+++ b/src/assets/icons/256x256/document-save.png
Binary files differ
diff --git a/src/assets/icons/256x256/edit-copy.png b/src/assets/icons/256x256/edit-copy.png
new file mode 100644
index 0000000000..b18bead117
--- /dev/null
+++ b/src/assets/icons/256x256/edit-copy.png
Binary files differ
diff --git a/src/assets/icons/256x256/edit-cut.png b/src/assets/icons/256x256/edit-cut.png
new file mode 100644
index 0000000000..d9454cebf1
--- /dev/null
+++ b/src/assets/icons/256x256/edit-cut.png
Binary files differ
diff --git a/src/assets/icons/256x256/edit-delete.png b/src/assets/icons/256x256/edit-delete.png
new file mode 100644
index 0000000000..4081cdb2ca
--- /dev/null
+++ b/src/assets/icons/256x256/edit-delete.png
Binary files differ
diff --git a/src/assets/icons/256x256/edit-paste.png b/src/assets/icons/256x256/edit-paste.png
new file mode 100644
index 0000000000..3358426818
--- /dev/null
+++ b/src/assets/icons/256x256/edit-paste.png
Binary files differ
diff --git a/src/assets/icons/256x256/edit-redo.png b/src/assets/icons/256x256/edit-redo.png
new file mode 100644
index 0000000000..e28b28542c
--- /dev/null
+++ b/src/assets/icons/256x256/edit-redo.png
Binary files differ
diff --git a/src/assets/icons/256x256/edit-undo.png b/src/assets/icons/256x256/edit-undo.png
new file mode 100644
index 0000000000..fe10f57a39
--- /dev/null
+++ b/src/assets/icons/256x256/edit-undo.png
Binary files differ
diff --git a/src/assets/icons/256x256/format-justify-center.png b/src/assets/icons/256x256/format-justify-center.png
new file mode 100644
index 0000000000..d4ad74b0d0
--- /dev/null
+++ b/src/assets/icons/256x256/format-justify-center.png
Binary files differ
diff --git a/src/assets/icons/256x256/format-justify-fill.png b/src/assets/icons/256x256/format-justify-fill.png
new file mode 100644
index 0000000000..bf0dd84bbb
--- /dev/null
+++ b/src/assets/icons/256x256/format-justify-fill.png
Binary files differ
diff --git a/src/assets/icons/256x256/format-justify-left.png b/src/assets/icons/256x256/format-justify-left.png
new file mode 100644
index 0000000000..dde68c8514
--- /dev/null
+++ b/src/assets/icons/256x256/format-justify-left.png
Binary files differ
diff --git a/src/assets/icons/256x256/format-justify-right.png b/src/assets/icons/256x256/format-justify-right.png
new file mode 100644
index 0000000000..8a5e7518bd
--- /dev/null
+++ b/src/assets/icons/256x256/format-justify-right.png
Binary files differ
diff --git a/src/assets/icons/256x256/format-text-bold.png b/src/assets/icons/256x256/format-text-bold.png
new file mode 100644
index 0000000000..665d3ce37b
--- /dev/null
+++ b/src/assets/icons/256x256/format-text-bold.png
Binary files differ
diff --git a/src/assets/icons/256x256/format-text-italic.png b/src/assets/icons/256x256/format-text-italic.png
new file mode 100644
index 0000000000..4b6846a6b9
--- /dev/null
+++ b/src/assets/icons/256x256/format-text-italic.png
Binary files differ
diff --git a/src/assets/icons/256x256/format-text-underline.png b/src/assets/icons/256x256/format-text-underline.png
new file mode 100644
index 0000000000..601f73216a
--- /dev/null
+++ b/src/assets/icons/256x256/format-text-underline.png
Binary files differ
diff --git a/src/assets/icons/256x256@2/document-new@2x.png b/src/assets/icons/256x256@2/document-new@2x.png
new file mode 100644
index 0000000000..bfec6d0e6d
--- /dev/null
+++ b/src/assets/icons/256x256@2/document-new@2x.png
Binary files differ
diff --git a/src/assets/icons/256x256@2/document-open@2x.png b/src/assets/icons/256x256@2/document-open@2x.png
new file mode 100644
index 0000000000..630a05f622
--- /dev/null
+++ b/src/assets/icons/256x256@2/document-open@2x.png
Binary files differ
diff --git a/src/assets/icons/256x256@2/document-print@2x.png b/src/assets/icons/256x256@2/document-print@2x.png
new file mode 100644
index 0000000000..c8611c31c4
--- /dev/null
+++ b/src/assets/icons/256x256@2/document-print@2x.png
Binary files differ
diff --git a/src/assets/icons/256x256@2/document-save@2x.png b/src/assets/icons/256x256@2/document-save@2x.png
new file mode 100644
index 0000000000..6f46095981
--- /dev/null
+++ b/src/assets/icons/256x256@2/document-save@2x.png
Binary files differ
diff --git a/src/assets/icons/256x256@2/edit-copy@2x.png b/src/assets/icons/256x256@2/edit-copy@2x.png
new file mode 100644
index 0000000000..2f350041a0
--- /dev/null
+++ b/src/assets/icons/256x256@2/edit-copy@2x.png
Binary files differ
diff --git a/src/assets/icons/256x256@2/edit-cut@2x.png b/src/assets/icons/256x256@2/edit-cut@2x.png
new file mode 100644
index 0000000000..e11cf6d234
--- /dev/null
+++ b/src/assets/icons/256x256@2/edit-cut@2x.png
Binary files differ
diff --git a/src/assets/icons/256x256@2/edit-delete@2x.png b/src/assets/icons/256x256@2/edit-delete@2x.png
new file mode 100644
index 0000000000..efe6b90bf5
--- /dev/null
+++ b/src/assets/icons/256x256@2/edit-delete@2x.png
Binary files differ
diff --git a/src/assets/icons/256x256@2/edit-paste@2x.png b/src/assets/icons/256x256@2/edit-paste@2x.png
new file mode 100644
index 0000000000..32f54b3959
--- /dev/null
+++ b/src/assets/icons/256x256@2/edit-paste@2x.png
Binary files differ
diff --git a/src/assets/icons/256x256@2/edit-redo@2x.png b/src/assets/icons/256x256@2/edit-redo@2x.png
new file mode 100644
index 0000000000..1f6e366535
--- /dev/null
+++ b/src/assets/icons/256x256@2/edit-redo@2x.png
Binary files differ
diff --git a/src/assets/icons/256x256@2/edit-undo@2x.png b/src/assets/icons/256x256@2/edit-undo@2x.png
new file mode 100644
index 0000000000..980ed37062
--- /dev/null
+++ b/src/assets/icons/256x256@2/edit-undo@2x.png
Binary files differ
diff --git a/src/assets/icons/256x256@2/format-justify-center@2x.png b/src/assets/icons/256x256@2/format-justify-center@2x.png
new file mode 100644
index 0000000000..af7044ddee
--- /dev/null
+++ b/src/assets/icons/256x256@2/format-justify-center@2x.png
Binary files differ
diff --git a/src/assets/icons/256x256@2/format-justify-fill@2x.png b/src/assets/icons/256x256@2/format-justify-fill@2x.png
new file mode 100644
index 0000000000..da14563bd6
--- /dev/null
+++ b/src/assets/icons/256x256@2/format-justify-fill@2x.png
Binary files differ
diff --git a/src/assets/icons/256x256@2/format-justify-left@2x.png b/src/assets/icons/256x256@2/format-justify-left@2x.png
new file mode 100644
index 0000000000..c1025bf010
--- /dev/null
+++ b/src/assets/icons/256x256@2/format-justify-left@2x.png
Binary files differ
diff --git a/src/assets/icons/256x256@2/format-justify-right@2x.png b/src/assets/icons/256x256@2/format-justify-right@2x.png
new file mode 100644
index 0000000000..3a07e06e0f
--- /dev/null
+++ b/src/assets/icons/256x256@2/format-justify-right@2x.png
Binary files differ
diff --git a/src/assets/icons/256x256@2/format-text-bold@2x.png b/src/assets/icons/256x256@2/format-text-bold@2x.png
new file mode 100644
index 0000000000..b0f4cb0995
--- /dev/null
+++ b/src/assets/icons/256x256@2/format-text-bold@2x.png
Binary files differ
diff --git a/src/assets/icons/256x256@2/format-text-italic@2x.png b/src/assets/icons/256x256@2/format-text-italic@2x.png
new file mode 100644
index 0000000000..85f0cfc1d6
--- /dev/null
+++ b/src/assets/icons/256x256@2/format-text-italic@2x.png
Binary files differ
diff --git a/src/assets/icons/256x256@2/format-text-underline@2x.png b/src/assets/icons/256x256@2/format-text-underline@2x.png
new file mode 100644
index 0000000000..51ee0aa778
--- /dev/null
+++ b/src/assets/icons/256x256@2/format-text-underline@2x.png
Binary files differ
diff --git a/src/assets/icons/32x32/document-new.png b/src/assets/icons/32x32/document-new.png
new file mode 100644
index 0000000000..482ae52024
--- /dev/null
+++ b/src/assets/icons/32x32/document-new.png
Binary files differ
diff --git a/src/assets/icons/32x32/document-open.png b/src/assets/icons/32x32/document-open.png
new file mode 100644
index 0000000000..9858b146f4
--- /dev/null
+++ b/src/assets/icons/32x32/document-open.png
Binary files differ
diff --git a/src/assets/icons/32x32/document-print.png b/src/assets/icons/32x32/document-print.png
new file mode 100644
index 0000000000..1672ec5897
--- /dev/null
+++ b/src/assets/icons/32x32/document-print.png
Binary files differ
diff --git a/src/assets/icons/32x32/document-save.png b/src/assets/icons/32x32/document-save.png
new file mode 100644
index 0000000000..f04de74673
--- /dev/null
+++ b/src/assets/icons/32x32/document-save.png
Binary files differ
diff --git a/src/assets/icons/32x32/edit-copy.png b/src/assets/icons/32x32/edit-copy.png
new file mode 100644
index 0000000000..bbb34cc4c2
--- /dev/null
+++ b/src/assets/icons/32x32/edit-copy.png
Binary files differ
diff --git a/src/assets/icons/32x32/edit-cut.png b/src/assets/icons/32x32/edit-cut.png
new file mode 100644
index 0000000000..d89ef6c016
--- /dev/null
+++ b/src/assets/icons/32x32/edit-cut.png
Binary files differ
diff --git a/src/assets/icons/32x32/edit-delete.png b/src/assets/icons/32x32/edit-delete.png
new file mode 100644
index 0000000000..4c97ee2495
--- /dev/null
+++ b/src/assets/icons/32x32/edit-delete.png
Binary files differ
diff --git a/src/assets/icons/32x32/edit-paste.png b/src/assets/icons/32x32/edit-paste.png
new file mode 100644
index 0000000000..299fa77686
--- /dev/null
+++ b/src/assets/icons/32x32/edit-paste.png
Binary files differ
diff --git a/src/assets/icons/32x32/edit-redo.png b/src/assets/icons/32x32/edit-redo.png
new file mode 100644
index 0000000000..4f8849c711
--- /dev/null
+++ b/src/assets/icons/32x32/edit-redo.png
Binary files differ
diff --git a/src/assets/icons/32x32/edit-undo.png b/src/assets/icons/32x32/edit-undo.png
new file mode 100644
index 0000000000..b3d366c53f
--- /dev/null
+++ b/src/assets/icons/32x32/edit-undo.png
Binary files differ
diff --git a/src/assets/icons/32x32/format-justify-center.png b/src/assets/icons/32x32/format-justify-center.png
new file mode 100644
index 0000000000..80c3afd9a6
--- /dev/null
+++ b/src/assets/icons/32x32/format-justify-center.png
Binary files differ
diff --git a/src/assets/icons/32x32/format-justify-fill.png b/src/assets/icons/32x32/format-justify-fill.png
new file mode 100644
index 0000000000..33589ea25d
--- /dev/null
+++ b/src/assets/icons/32x32/format-justify-fill.png
Binary files differ
diff --git a/src/assets/icons/32x32/format-justify-left.png b/src/assets/icons/32x32/format-justify-left.png
new file mode 100644
index 0000000000..ba02821135
--- /dev/null
+++ b/src/assets/icons/32x32/format-justify-left.png
Binary files differ
diff --git a/src/assets/icons/32x32/format-justify-right.png b/src/assets/icons/32x32/format-justify-right.png
new file mode 100644
index 0000000000..8e15d0cb44
--- /dev/null
+++ b/src/assets/icons/32x32/format-justify-right.png
Binary files differ
diff --git a/src/assets/icons/32x32/format-text-bold.png b/src/assets/icons/32x32/format-text-bold.png
new file mode 100644
index 0000000000..754efdd975
--- /dev/null
+++ b/src/assets/icons/32x32/format-text-bold.png
Binary files differ
diff --git a/src/assets/icons/32x32/format-text-italic.png b/src/assets/icons/32x32/format-text-italic.png
new file mode 100644
index 0000000000..6db31a4f69
--- /dev/null
+++ b/src/assets/icons/32x32/format-text-italic.png
Binary files differ
diff --git a/src/assets/icons/32x32/format-text-underline.png b/src/assets/icons/32x32/format-text-underline.png
new file mode 100644
index 0000000000..977cde9d97
--- /dev/null
+++ b/src/assets/icons/32x32/format-text-underline.png
Binary files differ
diff --git a/src/assets/icons/32x32@2/document-new@2x.png b/src/assets/icons/32x32@2/document-new@2x.png
new file mode 100644
index 0000000000..c924576061
--- /dev/null
+++ b/src/assets/icons/32x32@2/document-new@2x.png
Binary files differ
diff --git a/src/assets/icons/32x32@2/document-open@2x.png b/src/assets/icons/32x32@2/document-open@2x.png
new file mode 100644
index 0000000000..68e75b549a
--- /dev/null
+++ b/src/assets/icons/32x32@2/document-open@2x.png
Binary files differ
diff --git a/src/assets/icons/32x32@2/document-print@2x.png b/src/assets/icons/32x32@2/document-print@2x.png
new file mode 100644
index 0000000000..b784336739
--- /dev/null
+++ b/src/assets/icons/32x32@2/document-print@2x.png
Binary files differ
diff --git a/src/assets/icons/32x32@2/document-save@2x.png b/src/assets/icons/32x32@2/document-save@2x.png
new file mode 100644
index 0000000000..f4cca4b323
--- /dev/null
+++ b/src/assets/icons/32x32@2/document-save@2x.png
Binary files differ
diff --git a/src/assets/icons/32x32@2/edit-copy@2x.png b/src/assets/icons/32x32@2/edit-copy@2x.png
new file mode 100644
index 0000000000..9690d6bb04
--- /dev/null
+++ b/src/assets/icons/32x32@2/edit-copy@2x.png
Binary files differ
diff --git a/src/assets/icons/32x32@2/edit-cut@2x.png b/src/assets/icons/32x32@2/edit-cut@2x.png
new file mode 100644
index 0000000000..408b0ae19b
--- /dev/null
+++ b/src/assets/icons/32x32@2/edit-cut@2x.png
Binary files differ
diff --git a/src/assets/icons/32x32@2/edit-delete@2x.png b/src/assets/icons/32x32@2/edit-delete@2x.png
new file mode 100644
index 0000000000..58abfc1fa5
--- /dev/null
+++ b/src/assets/icons/32x32@2/edit-delete@2x.png
Binary files differ
diff --git a/src/assets/icons/32x32@2/edit-paste@2x.png b/src/assets/icons/32x32@2/edit-paste@2x.png
new file mode 100644
index 0000000000..b8c288f6c7
--- /dev/null
+++ b/src/assets/icons/32x32@2/edit-paste@2x.png
Binary files differ
diff --git a/src/assets/icons/32x32@2/edit-redo@2x.png b/src/assets/icons/32x32@2/edit-redo@2x.png
new file mode 100644
index 0000000000..89fcd33c30
--- /dev/null
+++ b/src/assets/icons/32x32@2/edit-redo@2x.png
Binary files differ
diff --git a/src/assets/icons/32x32@2/edit-undo@2x.png b/src/assets/icons/32x32@2/edit-undo@2x.png
new file mode 100644
index 0000000000..6f7ad2cb40
--- /dev/null
+++ b/src/assets/icons/32x32@2/edit-undo@2x.png
Binary files differ
diff --git a/src/assets/icons/32x32@2/format-justify-center@2x.png b/src/assets/icons/32x32@2/format-justify-center@2x.png
new file mode 100644
index 0000000000..9b2cc1ed16
--- /dev/null
+++ b/src/assets/icons/32x32@2/format-justify-center@2x.png
Binary files differ
diff --git a/src/assets/icons/32x32@2/format-justify-fill@2x.png b/src/assets/icons/32x32@2/format-justify-fill@2x.png
new file mode 100644
index 0000000000..1212e9f761
--- /dev/null
+++ b/src/assets/icons/32x32@2/format-justify-fill@2x.png
Binary files differ
diff --git a/src/assets/icons/32x32@2/format-justify-left@2x.png b/src/assets/icons/32x32@2/format-justify-left@2x.png
new file mode 100644
index 0000000000..8c0eca3037
--- /dev/null
+++ b/src/assets/icons/32x32@2/format-justify-left@2x.png
Binary files differ
diff --git a/src/assets/icons/32x32@2/format-justify-right@2x.png b/src/assets/icons/32x32@2/format-justify-right@2x.png
new file mode 100644
index 0000000000..fb0ed70252
--- /dev/null
+++ b/src/assets/icons/32x32@2/format-justify-right@2x.png
Binary files differ
diff --git a/src/assets/icons/32x32@2/format-text-bold@2x.png b/src/assets/icons/32x32@2/format-text-bold@2x.png
new file mode 100644
index 0000000000..0e67ead0b8
--- /dev/null
+++ b/src/assets/icons/32x32@2/format-text-bold@2x.png
Binary files differ
diff --git a/src/assets/icons/32x32@2/format-text-italic@2x.png b/src/assets/icons/32x32@2/format-text-italic@2x.png
new file mode 100644
index 0000000000..f746f8956f
--- /dev/null
+++ b/src/assets/icons/32x32@2/format-text-italic@2x.png
Binary files differ
diff --git a/src/assets/icons/32x32@2/format-text-underline@2x.png b/src/assets/icons/32x32@2/format-text-underline@2x.png
new file mode 100644
index 0000000000..47d6fced02
--- /dev/null
+++ b/src/assets/icons/32x32@2/format-text-underline@2x.png
Binary files differ
diff --git a/src/assets/icons/CMakeLists.txt b/src/assets/icons/CMakeLists.txt
new file mode 100644
index 0000000000..f5adb229d8
--- /dev/null
+++ b/src/assets/icons/CMakeLists.txt
@@ -0,0 +1,174 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_module(ExampleIconsPrivate
+ CONFIG_MODULE_NAME example_icons
+ STATIC
+ INTERNAL_MODULE
+ NO_GENERATE_CPP_EXPORTS
+)
+
+set(icons_resource_files
+ index.theme
+ 16x16/document-new.png
+ 16x16/document-open.png
+ 16x16/document-print.png
+ 16x16/document-save.png
+ 16x16/edit-copy.png
+ 16x16/edit-cut.png
+ 16x16/edit-delete.png
+ 16x16/edit-paste.png
+ 16x16/edit-redo.png
+ 16x16/edit-undo.png
+ 16x16/format-justify-center.png
+ 16x16/format-justify-fill.png
+ 16x16/format-justify-left.png
+ 16x16/format-justify-right.png
+ 16x16/format-text-bold.png
+ 16x16/format-text-italic.png
+ 16x16/format-text-underline.png
+ 16x16@2/document-new@2x.png
+ 16x16@2/document-open@2x.png
+ 16x16@2/document-print@2x.png
+ 16x16@2/document-save@2x.png
+ 16x16@2/edit-copy@2x.png
+ 16x16@2/edit-cut@2x.png
+ 16x16@2/edit-delete@2x.png
+ 16x16@2/edit-paste@2x.png
+ 16x16@2/edit-redo@2x.png
+ 16x16@2/edit-undo@2x.png
+ 16x16@2/format-justify-center@2x.png
+ 16x16@2/format-justify-fill@2x.png
+ 16x16@2/format-justify-left@2x.png
+ 16x16@2/format-justify-right@2x.png
+ 16x16@2/format-text-bold@2x.png
+ 16x16@2/format-text-italic@2x.png
+ 16x16@2/format-text-underline@2x.png
+ 32x32/document-new.png
+ 32x32/document-open.png
+ 32x32/document-print.png
+ 32x32/document-save.png
+ 32x32/edit-copy.png
+ 32x32/edit-cut.png
+ 32x32/edit-delete.png
+ 32x32/edit-paste.png
+ 32x32/edit-redo.png
+ 32x32/edit-undo.png
+ 32x32/format-justify-center.png
+ 32x32/format-justify-fill.png
+ 32x32/format-justify-left.png
+ 32x32/format-justify-right.png
+ 32x32/format-text-bold.png
+ 32x32/format-text-italic.png
+ 32x32/format-text-underline.png
+ 32x32@2/document-new@2x.png
+ 32x32@2/document-open@2x.png
+ 32x32@2/document-print@2x.png
+ 32x32@2/document-save@2x.png
+ 32x32@2/edit-copy@2x.png
+ 32x32@2/edit-cut@2x.png
+ 32x32@2/edit-delete@2x.png
+ 32x32@2/edit-paste@2x.png
+ 32x32@2/edit-redo@2x.png
+ 32x32@2/edit-undo@2x.png
+ 32x32@2/format-justify-center@2x.png
+ 32x32@2/format-justify-fill@2x.png
+ 32x32@2/format-justify-left@2x.png
+ 32x32@2/format-justify-right@2x.png
+ 32x32@2/format-text-bold@2x.png
+ 32x32@2/format-text-italic@2x.png
+ 32x32@2/format-text-underline@2x.png
+ 128x128/document-new.png
+ 128x128/document-open.png
+ 128x128/document-print.png
+ 128x128/document-save.png
+ 128x128/edit-copy.png
+ 128x128/edit-cut.png
+ 128x128/edit-delete.png
+ 128x128/edit-paste.png
+ 128x128/edit-redo.png
+ 128x128/edit-undo.png
+ 128x128/format-justify-center.png
+ 128x128/format-justify-fill.png
+ 128x128/format-justify-left.png
+ 128x128/format-justify-right.png
+ 128x128/format-text-bold.png
+ 128x128/format-text-italic.png
+ 128x128/format-text-underline.png
+ 128x128@2/document-new@2x.png
+ 128x128@2/document-open@2x.png
+ 128x128@2/document-print@2x.png
+ 128x128@2/document-save@2x.png
+ 128x128@2/edit-copy@2x.png
+ 128x128@2/edit-cut@2x.png
+ 128x128@2/edit-delete@2x.png
+ 128x128@2/edit-paste@2x.png
+ 128x128@2/edit-redo@2x.png
+ 128x128@2/edit-undo@2x.png
+ 128x128@2/format-justify-center@2x.png
+ 128x128@2/format-justify-fill@2x.png
+ 128x128@2/format-justify-left@2x.png
+ 128x128@2/format-justify-right@2x.png
+ 128x128@2/format-text-bold@2x.png
+ 128x128@2/format-text-italic@2x.png
+ 128x128@2/format-text-underline@2x.png
+ 256x256/document-new.png
+ 256x256/document-open.png
+ 256x256/document-print.png
+ 256x256/document-save.png
+ 256x256/edit-copy.png
+ 256x256/edit-cut.png
+ 256x256/edit-delete.png
+ 256x256/edit-paste.png
+ 256x256/edit-redo.png
+ 256x256/edit-undo.png
+ 256x256/format-justify-center.png
+ 256x256/format-justify-fill.png
+ 256x256/format-justify-left.png
+ 256x256/format-justify-right.png
+ 256x256/format-text-bold.png
+ 256x256/format-text-italic.png
+ 256x256/format-text-underline.png
+ 256x256@2/document-new@2x.png
+ 256x256@2/document-open@2x.png
+ 256x256@2/document-print@2x.png
+ 256x256@2/document-save@2x.png
+ 256x256@2/edit-copy@2x.png
+ 256x256@2/edit-cut@2x.png
+ 256x256@2/edit-delete@2x.png
+ 256x256@2/edit-paste@2x.png
+ 256x256@2/edit-redo@2x.png
+ 256x256@2/edit-undo@2x.png
+ 256x256@2/format-justify-center@2x.png
+ 256x256@2/format-justify-fill@2x.png
+ 256x256@2/format-justify-left@2x.png
+ 256x256@2/format-justify-right@2x.png
+ 256x256@2/format-text-bold@2x.png
+ 256x256@2/format-text-italic@2x.png
+ 256x256@2/format-text-underline@2x.png
+ scalable/document-new.svg
+ scalable/document-open.svg
+ scalable/document-print.svg
+ scalable/document-save.svg
+ scalable/edit-copy.svg
+ scalable/edit-cut.svg
+ scalable/edit-delete.svg
+ scalable/edit-paste.svg
+ scalable/edit-redo.svg
+ scalable/edit-undo.svg
+ scalable/format-justify-center.svg
+ scalable/format-justify-fill.svg
+ scalable/format-justify-left.svg
+ scalable/format-justify-right.svg
+ scalable/format-text-bold.svg
+ scalable/format-text-italic.svg
+ scalable/format-text-underline.svg
+)
+
+qt_internal_add_resource(ExampleIconsPrivate "example_icons"
+ PREFIX
+ "/qt-project.org/icons/example_icons"
+ FILES
+ ${icons_resource_files}
+)
+
diff --git a/src/assets/icons/README b/src/assets/icons/README
new file mode 100644
index 0000000000..26d94e9ff1
--- /dev/null
+++ b/src/assets/icons/README
@@ -0,0 +1,29 @@
+Copyright (C) 2023 The Qt Company Ltd.
+SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+Setting up a project for using Example icon library
+
+1. Add ExampleIconsPrivate component to your project CMakeList.txt file
+ ...
+ find_package(Qt6
+ REQUIRED COMPONENTS Core Gui Widgets ExampleIconsPrivate
+ )
+
+ target_link_libraries(imageviewer PRIVATE
+ Qt6::Core
+ Qt6::Gui
+ Qt6::Widgets
+ Qt6::ExampleIconsPrivate
+ )
+ ...
+
+2. Load the theme
+ ...
+ QIcon::setThemeSearchPaths(QIcon::themeSearchPaths() << u":/qt-project.org/icons"_s);
+ QIcon::setFallbackThemeName(u"example_icons"_s);
+ ...
+
+3. Use the icons
+ ...
+ const QIcon openIcon = QIcon::fromTheme("document-open");
+ ...
diff --git a/src/assets/icons/index.theme b/src/assets/icons/index.theme
new file mode 100644
index 0000000000..e389719e01
--- /dev/null
+++ b/src/assets/icons/index.theme
@@ -0,0 +1,46 @@
+[Icon Theme]
+Name=example_icons
+
+Directories=16x16,16x16@2,32x32,32x32@2,128x128,128x128@2,256x256,256x256@2,scalable
+
+[16x16]
+Size=16
+Type=Fixed
+
+[16x16@2]
+Size=16
+Scale=2
+Type=Fixed
+
+[32x32]
+Size=32
+Type=Fixed
+
+[32x32@2]
+Size=32
+Scale=2
+Type=Fixed
+
+[128x128]
+Size=128
+Type=Fixed
+
+[128x128@2]
+Size=128
+Scale=2
+Type=Fixed
+
+[256x256]
+Size=256
+Type=Fixed
+
+[256x256@2]
+Size=256
+Scale=2
+Type=Fixed
+
+[scalable]
+Size=512
+Type=Scalable
+MinSize=16
+MaxSize=512
diff --git a/src/assets/icons/scalable/document-new.svg b/src/assets/icons/scalable/document-new.svg
new file mode 100644
index 0000000000..b926a7b0e1
--- /dev/null
+++ b/src/assets/icons/scalable/document-new.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_New" d="m15,13c0,.28-.22.5-.5.5h-2v2c0,.28-.22.5-.5.5s-.5-.22-.5-.5v-2h-2c-.28,0-.5-.22-.5-.5s.22-.5.5-.5h2v-2c0-.28.22-.5.5-.5s.5.22.5.5v2h2c.28,0,.5.22.5.5Zm-12,2h5v1H3c-1.1,0-2-.9-2-2V2C1,.9,1.9,0,3,0h7c1.14,1.14,2.93,2.93,4,4v5h-1v-4h-2c-1.1,0-2-.9-2-2V1H3c-.55,0-1,.45-1,1v12c0,.55.45,1,1,1ZM10,1.41v1.59c0,.55.45,1,1,1h1.59l-.82-.82-1.76-1.76Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/document-open.svg b/src/assets/icons/scalable/document-open.svg
new file mode 100644
index 0000000000..778c1b7c6e
--- /dev/null
+++ b/src/assets/icons/scalable/document-open.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Open" d="m14.5,5h-1.5v-1c0-1.1-.9-2-2-2h-5L4,0h-2C.9,0,0,.9,0,2v12c0,1.1.9,2,2,2h9s0,0,0,0c.12,0,.25-.01.36-.03.98-.16,1.94-.94,2.24-1.87l2.29-7.19c.33-1.05-.29-1.91-1.39-1.91ZM1,14V2c0-.55.45-1,1-1h1.59l1.71,1.71c.19.19.44.29.71.29h5c.55,0,1,.45,1,1v1h-5.5c-1.1,0-2.27.86-2.61,1.91l-2.29,7.19c-.09.28-.11.54-.07.78-.32-.17-.54-.49-.54-.87Zm13.94-7.4l-2.29,7.19c-.2.63-.99,1.21-1.65,1.21H3c-.2,0-.36-.05-.43-.15-.07-.1-.07-.26-.01-.45l2.29-7.19c.2-.63.99-1.21,1.65-1.21h8c.2,0,.36.05.43.15.07.1.07.26.01.45Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/document-print.svg b/src/assets/icons/scalable/document-print.svg
new file mode 100644
index 0000000000..fb8436af81
--- /dev/null
+++ b/src/assets/icons/scalable/document-print.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Print" d="m14,4h-2v-2c0-1.1-.9-2-2-2h-4c-1.1,0-2,.9-2,2v2h-2c-1.1,0-2,.9-2,2v4c0,1.1.9,2,2,2h2v2c0,1.1.9,2,2,2h4c1.1,0,2-.9,2-2v-2h2c1.1,0,2-.9,2-2v-4c0-1.1-.9-2-2-2ZM5,2c0-.55.45-1,1-1h4c.55,0,1,.45,1,1v2h-6v-2Zm5,13h-4c-.55,0-1-.45-1-1v-5h6v5c0,.55-.45,1-1,1Zm5-5c0,.55-.45,1-1,1h-2v-2h.5c.28,0,.5-.22.5-.5s-.22-.5-.5-.5h-.5s-8,0-8,0h0s-.5,0-.5,0c-.28,0-.5.22-.5.5s.22.5.5.5h.5v2h-2c-.55,0-1-.45-1-1v-4c0-.55.45-1,1-1h12c.55,0,1,.45,1,1v4Zm-5,1.5c0,.28-.22.5-.5.5h-3c-.28,0-.5-.22-.5-.5s.22-.5.5-.5h3c.28,0,.5.22.5.5Zm0,2c0,.28-.22.5-.5.5h-3c-.28,0-.5-.22-.5-.5s.22-.5.5-.5h3c.28,0,.5.22.5.5Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/document-save.svg b/src/assets/icons/scalable/document-save.svg
new file mode 100644
index 0000000000..03675f4dab
--- /dev/null
+++ b/src/assets/icons/scalable/document-save.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Save" d="m16,11h0V2.29c0-1.26-1.02-2.29-2.29-2.29H2.29C1.02,0,0,1.02,0,2.29v8.71h0v1h0v1.71c0,1.26,1.02,2.29,2.29,2.29h11.43c1.26,0,2.29-1.02,2.29-2.29v-1.71h0v-1ZM5.71,1h5.29v4.5c0,.28-.22.5-.5.5h-5c-.28,0-.5-.22-.5-.5V1h.71ZM1,2.29c0-.71.58-1.29,1.29-1.29h1.71v4.5c0,.83.67,1.5,1.5,1.5h5c.83,0,1.5-.67,1.5-1.5V1h1.71c.71,0,1.29.58,1.29,1.29v8.71H1V2.29Zm14,11.43c0,.71-.58,1.29-1.29,1.29H2.29c-.71,0-1.29-.58-1.29-1.29v-1.71h14v1.71Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/edit-copy.svg b/src/assets/icons/scalable/edit-copy.svg
new file mode 100644
index 0000000000..db53ff1162
--- /dev/null
+++ b/src/assets/icons/scalable/edit-copy.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Copy" d="m12,0h-5c-1.1,0-2,.9-2,2h1c0-.55.45-1,1-1h4v2c0,1.1.9,2,2,2h2v6c0,.55-.45,1-1,1h-2v1h2c1.1,0,2-.9,2-2v-7c-1.07-1.07-2.86-2.86-4-4Zm1,4c-.55,0-1-.45-1-1v-1.59l1.29,1.29,1.29,1.29h-1.59Zm-6-1H2c-1.1,0-2,.9-2,2v9c0,1.1.9,2,2,2h7c1.1,0,2-.9,2-2v-7c-1.07-1.07-2.86-2.86-4-4Zm3,6v5c0,.55-.45,1-1,1H2c-.55,0-1-.45-1-1V5c0-.55.45-1,1-1h4v2c0,1.1.9,2,2,2h2v1Zm-2-2c-.55,0-1-.45-1-1v-1.59l1.29,1.29,1.29,1.29h-1.59Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/edit-cut.svg b/src/assets/icons/scalable/edit-cut.svg
new file mode 100644
index 0000000000..7f75d0b829
--- /dev/null
+++ b/src/assets/icons/scalable/edit-cut.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Cut" d="m15.22,12.05l-7.39-3.55,7.39-3.55c.25-.12.35-.42.23-.67-.12-.25-.42-.35-.67-.23l-8.12,3.9-2.48-1.19c1.07-.46,1.81-1.52,1.81-2.75,0-1.66-1.34-3-3-3S0,2.34,0,4c0,1.28.81,2.36,1.93,2.8.1.05.22.1.35.15l3.23,1.55-3.23,1.55c-.1.05-.18.09-.26.13-1.18.41-2.02,1.51-2.02,2.82,0,1.66,1.34,3,3,3s3-1.34,3-3c0-1.24-.75-2.29-1.81-2.75l2.48-1.19,8.12,3.9c.07.03.14.05.22.05.19,0,.37-.1.45-.28.12-.25.01-.55-.23-.67ZM3,2c1.1,0,2,.9,2,2s-.9,2-2,2-2-.9-2-2,.9-2,2-2Zm2,11c0,1.1-.9,2-2,2s-2-.9-2-2,.9-2,2-2,2,.9,2,2Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/edit-delete.svg b/src/assets/icons/scalable/edit-delete.svg
new file mode 100644
index 0000000000..15d1a9c7fd
--- /dev/null
+++ b/src/assets/icons/scalable/edit-delete.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Delete" d="m8,0C3.58,0,0,3.58,0,8s3.58,8,8,8,8-3.58,8-8S12.42,0,8,0Zm0,15c-3.86,0-7-3.14-7-7S4.14,1,8,1s7,3.14,7,7-3.14,7-7,7Zm2.83-9.12l-2.12,2.12,2.12,2.12c.2.2.2.51,0,.71-.1.1-.23.15-.35.15s-.26-.05-.35-.15l-2.12-2.12-2.12,2.12c-.1.1-.23.15-.35.15s-.26-.05-.35-.15c-.2-.2-.2-.51,0-.71l2.12-2.12-2.12-2.12c-.2-.2-.2-.51,0-.71s.51-.2.71,0l2.12,2.12,2.12-2.12c.2-.2.51-.2.71,0s.2.51,0,.71Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/edit-paste.svg b/src/assets/icons/scalable/edit-paste.svg
new file mode 100644
index 0000000000..57e94d917d
--- /dev/null
+++ b/src/assets/icons/scalable/edit-paste.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Paste" d="m14.09,6.09c-.71-.74-1.44-1.5-2.09-2.09h-3.78c-1.23,0-2.22.9-2.22,2v8c0,1.1.99,2,2.22,2h5.56c1.23,0,2.22-.9,2.22-2v-6c-.52-.52-1.21-1.21-1.91-1.91Zm-2.09-.68l1.38,1.38c.41.43.8.83,1.18,1.21h-1.56c-.55,0-1-.45-1-1v-1.59Zm3,5.59v3c0,.55-.55,1-1.22,1h-5.56c-.67,0-1.22-.45-1.22-1V6c0-.55.55-1,1.22-1h2.78v2c0,1.1.9,2,2,2h2v2Zm-6.5,0h5c.28,0,.5.22.5.5s-.22.5-.5.5h-5c-.28,0-.5-.22-.5-.5s.22-.5.5-.5ZM5.5,3h1c.83,0,1.5-.67,1.5-1.5v-.5h2c.55,0,1,.45,1,1v1h1v-1C12,.9,11.1,0,10,0h-2s-4,0-4,0h0s-2,0-2,0C.9,0,0,.9,0,2v10c0,1.1.9,2,2,2h3v-1h-3c-.55,0-1-.45-1-1V2c0-.55.45-1,1-1h2v.5c0,.83.67,1.5,1.5,1.5Zm1.5-1.5c0,.28-.22.5-.5.5h-1c-.28,0-.5-.22-.5-.5v-.5h2v.5Zm7,12c0,.28-.22.5-.5.5h-5c-.28,0-.5-.22-.5-.5s.22-.5.5-.5h5c.28,0,.5.22.5.5Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/edit-redo.svg b/src/assets/icons/scalable/edit-redo.svg
new file mode 100644
index 0000000000..92d60e1dd8
--- /dev/null
+++ b/src/assets/icons/scalable/edit-redo.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Redo" d="m15.85,4.68l-3.54-3.54c-.2-.2-.51-.2-.71,0s-.2.51,0,.71l2.68,2.68H2.5c-1.38,0-2.5,1.12-2.5,2.5v4c0,1.38,1.12,2.5,2.5,2.5h7c.28,0,.5-.22.5-.5s-.22-.5-.5-.5H2.5c-.83,0-1.5-.67-1.5-1.5v-4c0-.83.67-1.5,1.5-1.5h11.79l-2.68,2.68c-.2.2-.2.51,0,.71.1.1.23.15.35.15s.26-.05.35-.15l3.54-3.54c.2-.2.2-.51,0-.71Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/edit-undo.svg b/src/assets/icons/scalable/edit-undo.svg
new file mode 100644
index 0000000000..91731bb86f
--- /dev/null
+++ b/src/assets/icons/scalable/edit-undo.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconDesktopApp_Undo" d="m13.5,4.54H1.71l2.68-2.68c.2-.2.2-.51,0-.71s-.51-.2-.71,0L.15,4.68c-.2.2-.2.51,0,.71l3.54,3.54c.1.1.23.15.35.15s.26-.05.35-.15c.2-.2.2-.51,0-.71l-2.68-2.68h11.79c.83,0,1.5.67,1.5,1.5v4c0,.83-.67,1.5-1.5,1.5h-7c-.28,0-.5.22-.5.5s.22.5.5.5h7c1.38,0,2.5-1.12,2.5-2.5v-4c0-1.38-1.12-2.5-2.5-2.5Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/format-justify-center.svg b/src/assets/icons/scalable/format-justify-center.svg
new file mode 100644
index 0000000000..9822c95f2f
--- /dev/null
+++ b/src/assets/icons/scalable/format-justify-center.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconTextEditor_alignCenter" d="m15.5,8H.5c-.28,0-.5-.22-.5-.5h0c0-.28.22-.5.5-.5h15c.28,0,.5.22.5.5h0c0,.28-.22.5-.5.5Zm-2,3.5h0c0-.28-.22-.5-.5-.5H3c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h10c.28,0,.5-.22.5-.5Zm2.5,4h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h15c.28,0,.5-.22.5-.5Zm-2.5-12h0c0-.28-.22-.5-.5-.5H3c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h10c.28,0,.5-.22.5-.5Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/format-justify-fill.svg b/src/assets/icons/scalable/format-justify-fill.svg
new file mode 100644
index 0000000000..2fa7ddfa40
--- /dev/null
+++ b/src/assets/icons/scalable/format-justify-fill.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconTextEditor_alignJustify" d="m15.5,8H.5c-.28,0-.5-.22-.5-.5h0c0-.28.22-.5.5-.5h15c.28,0,.5.22.5.5h0c0,.28-.22.5-.5.5Zm.5,3.5h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h15c.28,0,.5-.22.5-.5Zm0,4h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h15c.28,0,.5-.22.5-.5Zm0-12h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h15c.28,0,.5-.22.5-.5Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/format-justify-left.svg b/src/assets/icons/scalable/format-justify-left.svg
new file mode 100644
index 0000000000..99d666428d
--- /dev/null
+++ b/src/assets/icons/scalable/format-justify-left.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconTextEditor_alignLeft" d="m15.5,8H.5c-.28,0-.5-.22-.5-.5h0c0-.28.22-.5.5-.5h15c.28,0,.5.22.5.5h0c0,.28-.22.5-.5.5Zm-4.5,3.5h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h10c.28,0,.5-.22.5-.5Zm5,4h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h15c.28,0,.5-.22.5-.5ZM11,3.5h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h10c.28,0,.5-.22.5-.5Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/format-justify-right.svg b/src/assets/icons/scalable/format-justify-right.svg
new file mode 100644
index 0000000000..7041f5e3f8
--- /dev/null
+++ b/src/assets/icons/scalable/format-justify-right.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconTextEditor_alignRight" d="m15.5,8H.5c-.28,0-.5-.22-.5-.5h0c0-.28.22-.5.5-.5h15c.28,0,.5.22.5.5h0c0,.28-.22.5-.5.5Zm.5,3.5h0c0-.28-.22-.5-.5-.5H5.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h10c.28,0,.5-.22.5-.5Zm0,4h0c0-.28-.22-.5-.5-.5H.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h15c.28,0,.5-.22.5-.5Zm0-12h0c0-.28-.22-.5-.5-.5H5.5c-.28,0-.5.22-.5.5h0c0,.28.22.5.5.5h10c.28,0,.5-.22.5-.5Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/format-text-bold.svg b/src/assets/icons/scalable/format-text-bold.svg
new file mode 100644
index 0000000000..c0f43e0a69
--- /dev/null
+++ b/src/assets/icons/scalable/format-text-bold.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconTextEditor_Bold" d="m12.06,7.75c.65-.36,1.13-.81,1.44-1.35.3-.55.46-1.29.46-2.24,0-1.45-.4-2.5-1.21-3.16-.81-.66-2.03-.99-3.67-.99H3v16h6.26c3.39,0,5.09-1.51,5.09-4.53,0-1.88-.76-3.12-2.29-3.71ZM5.59,2.24h3.34c1.59,0,2.38.74,2.38,2.22,0,1.57-.76,2.36-2.29,2.36h-3.43V2.24Zm5.45,10.98c-.43.36-1.07.54-1.93.54h-3.53v-4.74h3.48c.75,0,1.37.17,1.87.53.5.35.75.96.75,1.83s-.21,1.49-.64,1.85Z"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/format-text-italic.svg b/src/assets/icons/scalable/format-text-italic.svg
new file mode 100644
index 0000000000..43df7ca54d
--- /dev/null
+++ b/src/assets/icons/scalable/format-text-italic.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><polygon id="iconTextEditor_Italic" points="6.63 0 6.18 2.01 8.18 2.01 5.45 13.99 3.45 13.99 3 16 9.56 16 10.01 13.99 8.01 13.99 10.74 2.01 12.74 2.01 13.19 0 6.63 0"/></svg> \ No newline at end of file
diff --git a/src/assets/icons/scalable/format-text-underline.svg b/src/assets/icons/scalable/format-text-underline.svg
new file mode 100644
index 0000000000..62778fc579
--- /dev/null
+++ b/src/assets/icons/scalable/format-text-underline.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg id="Outlined_icons" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path id="iconTextEditor_Underline" d="m3.38,11.88c-.92-.75-1.38-1.94-1.38-3.57V0h2.44v8.35c0,1.79,1.02,2.69,3.06,2.69s3.06-.9,3.06-2.69V0h2.44v8.31c0,1.63-.46,2.82-1.39,3.57-.92.75-2.3,1.12-4.13,1.12s-3.2-.37-4.11-1.12Zm10.12,3.12H1.5c-.28,0-.5.22-.5.5s.22.5.5.5h12c.28,0,.5-.22.5-.5s-.22-.5-.5-.5Z"/></svg> \ No newline at end of file
diff --git a/src/concurrent/CMakeLists.txt b/src/concurrent/CMakeLists.txt
index 73aa12dea0..504f854534 100644
--- a/src/concurrent/CMakeLists.txt
+++ b/src/concurrent/CMakeLists.txt
@@ -25,8 +25,10 @@ qt_internal_add_module(Concurrent
qtconcurrenttask.h
qtconcurrentthreadengine.cpp qtconcurrentthreadengine.h
DEFINES
+ QT_NO_CONTEXTLESS_CONNECT
QT_NO_FOREACH
QT_NO_USING_NAMESPACE
+ QT_USE_NODISCARD_FILE_OPEN
LIBRARIES
Qt::CorePrivate
PUBLIC_LIBRARIES
diff --git a/src/concurrent/doc/qtconcurrent.qdocconf b/src/concurrent/doc/qtconcurrent.qdocconf
index 419ca1f801..c4efe64d0a 100644
--- a/src/concurrent/doc/qtconcurrent.qdocconf
+++ b/src/concurrent/doc/qtconcurrent.qdocconf
@@ -26,7 +26,7 @@ qhp.QtConcurrent.subprojects.examples.selectors = fake:example
tagfile = ../../../doc/qtconcurrent/qtconcurrent.tags
-depends += qtcore qtdoc qmake qtcmake
+depends += qtcore qtnetwork qtdoc qmake qtcmake
headerdirs += ..
@@ -43,5 +43,5 @@ imagedirs += images
navigation.landingpage = "Qt Concurrent"
navigation.cppclassespage = "Qt Concurrent C++ Classes"
-# Fail the documentation build if there are more warnings than the limit
+# Enforce zero documentation warnings
warninglimit = 0
diff --git a/src/concurrent/doc/snippets/CMakeLists.txt b/src/concurrent/doc/snippets/CMakeLists.txt
index d1cc570d62..03ebb75a2e 100644
--- a/src/concurrent/doc/snippets/CMakeLists.txt
+++ b/src/concurrent/doc/snippets/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#! [cmake_use]
find_package(Qt6 REQUIRED COMPONENTS Concurrent)
diff --git a/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrenttask.cpp b/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrenttask.cpp
index ac3ca7fdfb..cb1889afb6 100644
--- a/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrenttask.cpp
+++ b/src/concurrent/doc/snippets/code/src_concurrent_qtconcurrenttask.cpp
@@ -30,7 +30,7 @@ std::is_invocable_v<std::decay_t<Task>, std::decay_t<Args>...>
//! [5]
QVariant value(42);
-auto result = QtConcurrent::task(&qvariant_cast<int>)
+auto result = QtConcurrent::task([](const QVariant &var){return qvariant_cast<int>(var);})
.withArguments(value)
.spawn()
.result(); // result == 42
diff --git a/src/concurrent/doc/src/qt6-changes.qdoc b/src/concurrent/doc/src/qt6-changes.qdoc
index cb0c606435..fa23ee21a7 100644
--- a/src/concurrent/doc/src/qt6-changes.qdoc
+++ b/src/concurrent/doc/src/qt6-changes.qdoc
@@ -5,7 +5,7 @@
\page concurrent-changes-qt6.html
\title Changes to Qt Concurrent
\ingroup changes-qt-5-to-6
- \brief Migrate Qt Concurrent to Qt 6.
+ \brief Improved to work with a variable number of arguments.
Qt 6 is a result of the conscious effort to make the framework more
efficient and easy to use.
diff --git a/src/concurrent/qtaskbuilder.qdoc b/src/concurrent/qtaskbuilder.qdoc
index 19c117b156..811a48f62b 100644
--- a/src/concurrent/qtaskbuilder.qdoc
+++ b/src/concurrent/qtaskbuilder.qdoc
@@ -51,7 +51,7 @@
*/
/*!
- \typedef InvokeResultType
+ \typedef QtConcurrent::InvokeResultType
\relates QtConcurrent::QTaskBuilder
The simplified definition of this type looks like this:
diff --git a/src/concurrent/qtconcurrentiteratekernel.cpp b/src/concurrent/qtconcurrentiteratekernel.cpp
index 088c8384ce..00228f181c 100644
--- a/src/concurrent/qtconcurrentiteratekernel.cpp
+++ b/src/concurrent/qtconcurrentiteratekernel.cpp
@@ -67,7 +67,7 @@ namespace QtConcurrent {
*/
BlockSizeManager::BlockSizeManager(QThreadPool *pool, int iterationCount)
- : maxBlockSize(iterationCount / (pool->maxThreadCount() * 2)),
+ : maxBlockSize(iterationCount / (std::max(pool->maxThreadCount(), 1) * 2)),
beforeUser(0), afterUser(0),
m_blockSize(1)
{ }
diff --git a/src/concurrent/qtconcurrentiteratekernel.h b/src/concurrent/qtconcurrentiteratekernel.h
index a23fe37a3c..232f4c8bfe 100644
--- a/src/concurrent/qtconcurrentiteratekernel.h
+++ b/src/concurrent/qtconcurrentiteratekernel.h
@@ -85,7 +85,7 @@ public:
return vector.data();
}
- int currentResultCount;
+ int currentResultCount = 0;
ThreadEngine<T> *threadEngine;
QList<T> vector;
@@ -156,7 +156,7 @@ public:
begin(_begin),
end(_end),
current(_begin),
- iterationCount(selectIteration(IteratorCategory()) ? std::distance(_begin, _end) : 0),
+ iterationCount(selectIteration(IteratorCategory()) ? static_cast<int>(std::distance(_begin, _end)) : 0),
forIteration(selectIteration(IteratorCategory())),
progressReportingEnabled(true)
{
@@ -168,7 +168,7 @@ public:
begin(_begin),
end(_end),
current(_begin),
- iterationCount(selectIteration(IteratorCategory()) ? std::distance(_begin, _end) : 0),
+ iterationCount(selectIteration(IteratorCategory()) ? static_cast<int>(std::distance(_begin, _end)) : 0),
forIteration(selectIteration(IteratorCategory())),
progressReportingEnabled(true),
defaultValue(U())
@@ -181,7 +181,7 @@ public:
begin(_begin),
end(_end),
current(_begin),
- iterationCount(selectIteration(IteratorCategory()) ? std::distance(_begin, _end) : 0),
+ iterationCount(selectIteration(IteratorCategory()) ? static_cast<int>(std::distance(_begin, _end)) : 0),
forIteration(selectIteration(IteratorCategory())),
progressReportingEnabled(true),
defaultValue(std::forward<U>(_defaultValue))
diff --git a/src/concurrent/qtconcurrentreducekernel.h b/src/concurrent/qtconcurrentreducekernel.h
index cb7d7910aa..c337a9192f 100644
--- a/src/concurrent/qtconcurrentreducekernel.h
+++ b/src/concurrent/qtconcurrentreducekernel.h
@@ -117,7 +117,7 @@ class ReduceKernel
public:
ReduceKernel(QThreadPool *pool, ReduceOptions _reduceOptions)
: reduceOptions(_reduceOptions), progress(0), resultsMapSize(0),
- threadCount(pool->maxThreadCount())
+ threadCount(std::max(pool->maxThreadCount(), 1))
{ }
void runReduce(ReduceFunctor &reduce,
diff --git a/src/concurrent/qtconcurrentrun.cpp b/src/concurrent/qtconcurrentrun.cpp
index fc19b947e5..017f2df480 100644
--- a/src/concurrent/qtconcurrentrun.cpp
+++ b/src/concurrent/qtconcurrentrun.cpp
@@ -80,6 +80,10 @@
\snippet code/src_concurrent_qtconcurrentrun.cpp 2
+ If you don't need the result (for example, because the function returns
+ \c{void}), using the QThreadPool::start() overload taking a function object
+ is more efficient.
+
As documented above, passing arguments is done like this:
\snippet code/src_concurrent_qtconcurrentrun.cpp 3
@@ -220,7 +224,7 @@
*/
/*!
- \fn QFuture<T> QtConcurrent::run(Function function, ...);
+ \fn template <typename T> QFuture<T> QtConcurrent::run(Function function, ...);
Equivalent to
\code
@@ -251,17 +255,16 @@
running task, fetching multiple results from the called \a function or
monitoring progress reported by the \a function.
- \sa {Concurrent Run (basic mode)}, {Concurrent Run With Promise}
+ \sa {Concurrent Run (basic mode)}, {Concurrent Run With Promise}, QThreadPool::start()
//! [run-description]
*/
/*!
\since 5.4
- \fn QFuture<T> QtConcurrent::run(QThreadPool *pool, Function function, ...);
+ \fn template <typename T> QFuture<T> QtConcurrent::run(QThreadPool *pool, Function function, ...);
- Runs \a function in a separate thread. The thread is taken from the
- QThreadPool \a pool. Note that \a function may not run immediately; \a function
- will only be run once a thread becomes available.
+ Schedules \a function on \a pool. Note that \a function may not run
+ immediately; \a function will only be run once a thread becomes available.
\include qtconcurrentrun.cpp run-description
*/
diff --git a/src/concurrent/qtconcurrentrun.h b/src/concurrent/qtconcurrentrun.h
index cf153ab34e..cbc750de84 100644
--- a/src/concurrent/qtconcurrentrun.h
+++ b/src/concurrent/qtconcurrentrun.h
@@ -35,8 +35,11 @@ namespace QtConcurrent {
namespace QtConcurrent {
+#define QTCONCURRENT_RUN_NODISCARD \
+ Q_NODISCARD_X("Use QThreadPool::start(Callable&&) if you don't need the returned QFuture")
+
template <class Function, class ...Args>
-[[nodiscard]]
+QTCONCURRENT_RUN_NODISCARD
auto run(QThreadPool *pool, Function &&f, Args &&...args)
{
DecayedTuple<Function, Args...> tuple { std::forward<Function>(f),
@@ -46,7 +49,7 @@ auto run(QThreadPool *pool, Function &&f, Args &&...args)
}
template <class Function, class ...Args>
-[[nodiscard]]
+QTCONCURRENT_RUN_NODISCARD
auto run(QThreadPool *pool, std::reference_wrapper<const Function> &&functionWrapper,
Args &&...args)
{
@@ -55,7 +58,7 @@ auto run(QThreadPool *pool, std::reference_wrapper<const Function> &&functionWra
}
template <class Function, class ...Args>
-[[nodiscard]]
+QTCONCURRENT_RUN_NODISCARD
auto run(Function &&f, Args &&...args)
{
return run(QThreadPool::globalInstance(), std::forward<Function>(f),
@@ -64,7 +67,7 @@ auto run(Function &&f, Args &&...args)
// overload with a Promise Type hint, takes thread pool
template <class PromiseType, class Function, class ...Args>
-[[nodiscard]]
+QTCONCURRENT_RUN_NODISCARD
auto run(QThreadPool *pool, Function &&f, Args &&...args)
{
return (new StoredFunctionCallWithPromise<Function, PromiseType, Args...>(
@@ -73,13 +76,15 @@ auto run(QThreadPool *pool, Function &&f, Args &&...args)
// overload with a Promise Type hint, uses global thread pool
template <class PromiseType, class Function, class ...Args>
-[[nodiscard]]
+QTCONCURRENT_RUN_NODISCARD
auto run(Function &&f, Args &&...args)
{
return run<PromiseType>(QThreadPool::globalInstance(), std::forward<Function>(f),
std::forward<Args>(args)...);
}
+#undef QTCONCURRENT_RUN_NODISCARD
+
} //namespace QtConcurrent
#endif // Q_QDOC
diff --git a/src/concurrent/qtconcurrentthreadengine.cpp b/src/concurrent/qtconcurrentthreadengine.cpp
index 03e018b0a2..ce02d0c2c9 100644
--- a/src/concurrent/qtconcurrentthreadengine.cpp
+++ b/src/concurrent/qtconcurrentthreadengine.cpp
@@ -3,8 +3,6 @@
#include "qtconcurrentthreadengine.h"
-#include <QtCore/private/qsimd_p.h>
-
#if !defined(QT_NO_CONCURRENT) || defined(Q_QDOC)
QT_BEGIN_NAMESPACE
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index abc4058bf3..e1fb0d7e39 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -1,22 +1,9 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
-qt_find_package(Threads PROVIDED_TARGETS Threads::Threads)
qt_find_package(WrapPCRE2 PROVIDED_TARGETS WrapPCRE2::WrapPCRE2)
qt_find_package(WrapZLIB PROVIDED_TARGETS WrapZLIB::WrapZLIB)
-
-# compute the reverse relative path from QtCoreConfigExtras to the install prefix
-# this is used in QtCoreConfigExtras to make its install paths relocatable
-if(QT_WILL_INSTALL)
- get_filename_component(_clean_prefix
- "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}/${QT_CONFIG_INSTALL_DIR}" ABSOLUTE)
-else()
- get_filename_component(_clean_prefix "${QT_CONFIG_BUILD_DIR}" ABSOLUTE)
-endif()
-file(RELATIVE_PATH QT_INVERSE_CONFIG_INSTALL_DIR
- "${_clean_prefix}" "${QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX}")
-
if(ANDROID)
set(corelib_extra_cmake_files
"${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}AndroidMacros.cmake")
@@ -26,17 +13,10 @@ if(WASM)
"${CMAKE_CURRENT_SOURCE_DIR}/${QT_CMAKE_EXPORT_NAMESPACE}WasmMacros.cmake")
endif()
-qt_path_join(config_build_dir ${QT_CONFIG_BUILD_DIR} "${INSTALL_CMAKE_NAMESPACE}Core")
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/QtInstallPaths.cmake.in"
- "${config_build_dir}/QtInstallPaths.cmake" @ONLY)
-
#####################################################################
## Core Module:
#####################################################################
-set(core_version_tagging_files
- global/qversiontagging.cpp
- global/qversiontagging.h)
qt_internal_add_module(Core
QMAKE_MODULE_CONFIG moc resources
NO_GENERATE_METATYPES # metatypes are extracted manually below
@@ -52,7 +32,8 @@ qt_internal_add_module(Core
global/archdetect.cpp
global/qassert.cpp global/qassert.h
global/qcompare_impl.h
- global/qcompare.h
+ global/qcompare.cpp global/qcompare.h
+ global/qcomparehelpers.h
global/qcompilerdetection.h
global/qconstructormacros.h
global/qcontainerinfo.h
@@ -90,24 +71,28 @@ qt_internal_add_module(Core
global/qtpreprocessorsupport.h
global/qtrace_p.h
global/qtresource.h
+ global/qtsymbolmacros.h
global/qttranslation.h
global/qttypetraits.h
global/qtversionchecks.h
global/qtversion.h
global/qtypeinfo.h
global/qtypes.cpp global/qtypes.h
- ${core_version_tagging_files}
global/qvolatile_p.h
global/q20algorithm.h
+ global/q20chrono.h
global/q20functional.h
global/q20iterator.h
+ global/q20map.h
global/q20memory.h
global/q20type_traits.h
+ global/q20vector.h
global/q23functional.h
global/q23utility.cpp # remove once we have a user that tests this
global/q23utility.h
global/qxpfunctional.h
global/qxptype_traits.h
+ global/qversiontagging.h
ipc/qsharedmemory.cpp ipc/qsharedmemory.h ipc/qsharedmemory_p.h
ipc/qsystemsemaphore.cpp ipc/qsystemsemaphore.h ipc/qsystemsemaphore_p.h
ipc/qtipccommon.cpp ipc/qtipccommon.h ipc/qtipccommon_p.h
@@ -116,6 +101,7 @@ qt_internal_add_module(Core
io/qdataurl.cpp io/qdataurl_p.h
io/qdebug.cpp io/qdebug.h io/qdebug_p.h
io/qdir.cpp io/qdir.h io/qdir_p.h
+ io/qdirlisting.cpp io/qdirlisting.h io/qdirentryinfo_p.h
io/qdiriterator.cpp io/qdiriterator.h
io/qfile.cpp io/qfile.h io/qfile_p.h
io/qfiledevice.cpp io/qfiledevice.h io/qfiledevice_p.h
@@ -145,17 +131,19 @@ qt_internal_add_module(Core
io/qurlidna.cpp
io/qurlquery.cpp io/qurlquery.h
io/qurlrecode.cpp
+ io/qzipreader_p.h io/qzipwriter_p.h io/qzip.cpp
kernel/qabstracteventdispatcher.cpp kernel/qabstracteventdispatcher.h kernel/qabstracteventdispatcher_p.h
kernel/qabstractnativeeventfilter.cpp kernel/qabstractnativeeventfilter.h
kernel/qapplicationstatic.h
kernel/qassociativeiterable.cpp kernel/qassociativeiterable.h
kernel/qbasictimer.cpp kernel/qbasictimer.h
kernel/qbindingstorage.h
+ kernel/qchronotimer.cpp kernel/qchronotimer.h
kernel/qcoreapplication.cpp kernel/qcoreapplication.h kernel/qcoreapplication_p.h
kernel/qcoreapplication_platform.h
kernel/qcorecmdlineargs_p.h
- kernel/qcoreevent.cpp kernel/qcoreevent.h
- kernel/qdeadlinetimer.cpp kernel/qdeadlinetimer.h kernel/qdeadlinetimer_p.h
+ kernel/qcoreevent.cpp kernel/qcoreevent.h kernel/qcoreevent_p.h
+ kernel/qdeadlinetimer.cpp kernel/qdeadlinetimer.h
kernel/qelapsedtimer.cpp kernel/qelapsedtimer.h
kernel/qeventloop.cpp kernel/qeventloop.h kernel/qeventloop_p.h
kernel/qfunctions_p.h
@@ -173,7 +161,7 @@ qt_internal_add_module(Core
kernel/qobjectcleanuphandler.cpp kernel/qobjectcleanuphandler.h
kernel/qobjectdefs.h
kernel/qobjectdefs_impl.h
- kernel/qpointer.cpp kernel/qpointer.h
+ kernel/qpointer.h
kernel/qproperty.cpp kernel/qproperty.h kernel/qproperty_p.h
kernel/qpropertyprivate.h
kernel/qsequentialiterable.cpp kernel/qsequentialiterable.h
@@ -181,6 +169,7 @@ qt_internal_add_module(Core
kernel/qsocketnotifier.cpp kernel/qsocketnotifier.h
kernel/qsystemerror.cpp kernel/qsystemerror_p.h
kernel/qtestsupport_core.cpp kernel/qtestsupport_core.h
+ kernel/qsingleshottimer_p.h
kernel/qtimer.cpp kernel/qtimer.h kernel/qtimer_p.h
kernel/qtranslator.cpp kernel/qtranslator.h kernel/qtranslator_p.h
kernel/qvariant.cpp kernel/qvariant.h kernel/qvariant_p.h
@@ -206,12 +195,9 @@ qt_internal_add_module(Core
serialization/qjsonvalue.cpp serialization/qjsonvalue.h
serialization/qjsonwriter.cpp serialization/qjsonwriter_p.h
serialization/qtextstream.cpp serialization/qtextstream.h serialization/qtextstream_p.h
- serialization/qxmlstream.cpp serialization/qxmlstream.h serialization/qxmlstream_p.h
- serialization/qxmlstreamgrammar.cpp serialization/qxmlstreamgrammar_p.h
- serialization/qxmlstreamparser_p.h
serialization/qxmlutils.cpp serialization/qxmlutils_p.h
- text/qanystringview.h
- text/qbytearray.cpp text/qbytearray.h text/qbytearray_p.h
+ text/qanystringview.cpp text/qanystringview.h
+ text/qbytearray.cpp text/qbytearray.h
text/qbytearrayalgorithms.h
text/qbytearraylist.cpp text/qbytearraylist.h
text/qbytearraymatcher.cpp text/qbytearraymatcher.h
@@ -225,6 +211,7 @@ qt_internal_add_module(Core
text/qlocale.cpp text/qlocale.h text/qlocale_p.h
text/qlocale_data_p.h
text/qlocale_tools.cpp text/qlocale_tools_p.h
+ text/qstaticlatin1stringmatcher.h
text/qstring.cpp text/qstring.h
text/qstringalgorithms.h text/qstringalgorithms_p.h
text/qstringbuilder.cpp text/qstringbuilder.h
@@ -255,6 +242,7 @@ qt_internal_add_module(Core
thread/qthreadstorage.h
thread/qtsan_impl.h
thread/qwaitcondition.h thread/qwaitcondition_p.h
+ thread/qyieldcpu.h
time/qcalendar.cpp time/qcalendar.h
time/qcalendarbackend_p.h
time/qcalendarmath_p.h
@@ -270,7 +258,7 @@ qt_internal_add_module(Core
tools/qarraydata.cpp tools/qarraydata.h
tools/qarraydataops.h
tools/qarraydatapointer.h
- tools/qatomicscopedvaluerollback_p.h
+ tools/qatomicscopedvaluerollback.h
tools/qbitarray.cpp tools/qbitarray.h
tools/qcache.h
tools/qcontainerfwd.h
@@ -280,6 +268,7 @@ qt_internal_add_module(Core
tools/qduplicatetracker_p.h
tools/qflatmap_p.h
tools/qfreelist.cpp tools/qfreelist_p.h
+ tools/qfunctionaltools_impl.cpp tools/qfunctionaltools_impl.h
tools/qhashfunctions.h
tools/qiterator.h
tools/qline.cpp tools/qline.h
@@ -288,6 +277,7 @@ qt_internal_add_module(Core
tools/qmap.h
tools/qmargins.cpp tools/qmargins.h
tools/qmessageauthenticationcode.h
+ tools/qminimalflatset_p.h
tools/qoffsetstringarray_p.h
tools/qpair.h
tools/qpoint.cpp tools/qpoint.h
@@ -304,9 +294,13 @@ qt_internal_add_module(Core
tools/qsharedpointer.cpp tools/qsharedpointer.h
tools/qsharedpointer_impl.h
tools/qsize.cpp tools/qsize.h
+ tools/qspan.h
+ tools/qspan_p.h
tools/qstack.h
tools/qtaggedpointer.h
tools/qtools_p.h
+ tools/qtyperevision.cpp tools/qtyperevision.h
+ tools/quniquehandle_p.h
tools/qvarlengtharray.h
tools/qvector.h
tools/qversionnumber.cpp tools/qversionnumber.h
@@ -315,10 +309,22 @@ qt_internal_add_module(Core
# despite the fact that appropriate checks are in place to avoid that!
tools/qshareddata.cpp tools/qshareddata.h
text/qlocale.cpp text/qlocale.h
+ global/qglobal.cpp # undef qFatal
+ global/qlogging.cpp # undef qFatal/qInfo/qDebug
+ global/qrandom.cpp # undef Q_ASSERT/_X
+ text/qstringconverter.cpp # enum Data
+ tools/qcryptographichash.cpp # KeccakNISTInterface/Final
+ io/qdebug.cpp # undef qDebug
+ NO_PCH_SOURCES
+ compat/removed_api.cpp
+ global/qsimd.cpp
DEFINES
+ QT_NO_CONTEXTLESS_CONNECT
QT_NO_FOREACH
+ QT_NO_QPAIR
QT_NO_USING_NAMESPACE
QT_TYPESAFE_FLAGS
+ QT_USE_NODISCARD_FILE_OPEN
INCLUDE_DIRECTORIES
"${CMAKE_CURRENT_BINARY_DIR}/global"
"${CMAKE_CURRENT_BINARY_DIR}/kernel" # for moc_qobject.cpp to be found by qobject.cpp
@@ -332,27 +338,25 @@ qt_internal_add_module(Core
PUBLIC_LIBRARIES
Qt::Platform
EXTRA_CMAKE_FILES
- "${CMAKE_CURRENT_SOURCE_DIR}/Qt6CTestMacros.cmake"
- "${CMAKE_CURRENT_SOURCE_DIR}/Qt6CoreConfigureFileTemplate.in"
- "${CMAKE_CURRENT_SOURCE_DIR}/Qt6CoreDeploySupport.cmake"
- "${config_build_dir}/QtInstallPaths.cmake"
- ${corelib_extra_cmake_files}
+ "${CMAKE_CURRENT_SOURCE_DIR}/Qt6CTestMacros.cmake"
+ "${CMAKE_CURRENT_SOURCE_DIR}/Qt6CoreConfigureFileTemplate.in"
+ "${CMAKE_CURRENT_SOURCE_DIR}/Qt6CoreResourceInit.in.cpp"
+ "${CMAKE_CURRENT_SOURCE_DIR}/Qt6CoreDeploySupport.cmake"
+ ${corelib_extra_cmake_files}
+ POLICIES
+ QTP0002
+ QTP0003
)
_qt_internal_setup_deploy_support()
-set(corelib_no_pch_sources
- compat/removed_api.cpp
- global/qsimd.cpp
-)
-
-foreach(src ${corelib_no_pch_sources})
- qt_update_ignore_pch_source(Core ${src})
-endforeach()
-
add_dependencies(Core qmodule_pri)
if (NOT QT_NAMESPACE STREQUAL "")
- target_compile_definitions(Core PUBLIC "QT_NAMESPACE=${QT_NAMESPACE}")
+ set(core_namespace_defs "QT_NAMESPACE=${QT_NAMESPACE}")
+ if(QT_INLINE_NAMESPACE)
+ list(APPEND core_namespace_defs QT_INLINE_NAMESPACE)
+ endif()
+ target_compile_definitions(Core PUBLIC ${core_namespace_defs})
set_target_properties(Core PROPERTIES _qt_namespace "${QT_NAMESPACE}")
set_property(TARGET Core APPEND PROPERTY EXPORT_PROPERTIES _qt_namespace)
endif()
@@ -407,7 +411,7 @@ set_source_files_properties(
# Find ELF interpreter and define a macro for that:
if ((LINUX OR HURD) AND NOT CMAKE_CROSSCOMPILING AND BUILD_SHARED_LIBS)
if (NOT DEFINED ELF_INTERPRETER)
- execute_process(COMMAND ${CMAKE_COMMAND} -E env LC_ALL=C readelf -l /bin/ls
+ execute_process(COMMAND ${CMAKE_COMMAND} -E env LC_ALL=C readelf -l /bin/sh
RESULT_VARIABLE readelf_ok
OUTPUT_VARIABLE readelf_output
)
@@ -447,8 +451,25 @@ if(ANDROID)
)
endif()
-## Scopes:
-#####################################################################
+# Add version tagging source files if the linker has version script support
+# or the platform supports it.
+set(core_version_tagging_files
+ global/qversiontagging.cpp)
+qt_internal_extend_target(Core
+ CONDITION TEST_ld_version_script OR APPLE OR WIN32
+ SOURCES ${core_version_tagging_files}
+)
+
+
+if(GCC)
+ # Disable LTO, as the symbols disappear somehow under GCC
+ # (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48200)
+ # The issue should be fixed in GCC >= 10
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10)
+ set_source_files_properties(${core_version_tagging_files}
+ PROPERTIES COMPILE_OPTIONS "-fno-lto")
+ endif()
+endif()
qt_internal_extend_target(Core
CONDITION ( TEST_architecture_arch STREQUAL i386 ) OR
@@ -469,12 +490,11 @@ qt_internal_extend_target(Core CONDITION MSVC AND (TEST_architecture_arch STREQU
"/BASE:0x67000000"
)
-# QtCore can't be compiled with -Wl,-no-undefined because it uses the
-# "environ" variable and FreeBSD does not include a weak symbol for it
-# in libc.
-qt_internal_extend_target(Core CONDITION FREEBSD
- LINK_OPTIONS
- "LINKER:--warn-unresolved-symbols"
+qt_internal_extend_target(Core CONDITION QT_FEATURE_xmlstream
+ SOURCES
+ serialization/qxmlstream.cpp serialization/qxmlstream.h serialization/qxmlstream_p.h
+ serialization/qxmlstreamgrammar.cpp serialization/qxmlstreamgrammar_p.h
+ serialization/qxmlstreamparser_p.h
)
qt_internal_extend_target(Core CONDITION QT_FEATURE_animation
@@ -494,6 +514,7 @@ qt_internal_extend_target(Core CONDITION QT_FEATURE_animation
# from the wrong DLL at runtime and crash!
qt_internal_extend_target(Core CONDITION QT_FEATURE_thread AND WIN32
SOURCES
+ thread/qfutex_win_p.h
thread/qwaitcondition_win.cpp
LIBRARIES
synchronization
@@ -512,7 +533,6 @@ qt_internal_extend_target(Core CONDITION WIN32
io/qwindowspipewriter.cpp io/qwindowspipewriter_p.h
io/qntdll_p.h
kernel/qcoreapplication_win.cpp
- kernel/qelapsedtimer_win.cpp
kernel/qeventdispatcher_win.cpp kernel/qeventdispatcher_win_p.h
kernel/qfunctions_win.cpp kernel/qfunctions_win_p.h kernel/qfunctions_winrt_p.h
ipc/qsharedmemory_win.cpp
@@ -521,7 +541,7 @@ qt_internal_extend_target(Core CONDITION WIN32
kernel/qwinregistry.cpp kernel/qwinregistry_p.h
plugin/qsystemlibrary.cpp plugin/qsystemlibrary_p.h
thread/qthread_win.cpp
- # DEFINES # special case: remove
+ platform/windows/qcomobject_p.h
LIBRARIES
advapi32
authz
@@ -539,6 +559,19 @@ qt_internal_extend_target(Core CONDITION WIN32
userenv
)
+qt_internal_extend_target(Core CONDITION WIN32
+ NO_UNITY_BUILD_SOURCES
+ global/qsimd.cpp # Q_DECL_INIT_PRIORITY
+ serialization/qcborvalue.cpp # various windows.h clashes
+ serialization/qjsoncbor.cpp
+ serialization/qjsonvalue.cpp
+ serialization/qxmlstream.cpp
+ text/qbytearray.cpp
+ text/qlatin1stringmatcher.cpp
+ text/qunicodetools.cpp
+ tools/qhash.cpp # Q_DECL_INIT_PRIORITY
+)
+
if(NOT WIN32)
### Qt7: remove
# Make qwineventnotifier.h available on non-Windows platforms too for code bases that include
@@ -561,7 +594,6 @@ qt_internal_extend_target(Core CONDITION APPLE
kernel/qcore_foundation.mm
kernel/qcore_mac.mm kernel/qcore_mac_p.h
kernel/qcoreapplication_mac.cpp
- kernel/qelapsedtimer_mac.cpp
kernel/qeventdispatcher_cf.mm kernel/qeventdispatcher_cf_p.h
LIBRARIES
${FWCoreFoundation}
@@ -621,13 +653,6 @@ qt_internal_extend_target(Core CONDITION QT_FEATURE_journald
PkgConfig::Libsystemd
)
-# Disable LTO, as the symbols disappear somehow under GCC
-# (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48200)
-if(GCC)
- set_source_files_properties(${core_version_tagging_files}
- PROPERTIES COMPILE_OPTIONS "-fno-lto")
-endif()
-
qt_internal_extend_target(Core CONDITION UNIX
SOURCES
io/qfilesystemengine_unix.cpp
@@ -635,11 +660,21 @@ qt_internal_extend_target(Core CONDITION UNIX
io/qfsfileengine_unix.cpp
io/qlockfile_unix.cpp
kernel/qcore_unix.cpp kernel/qcore_unix_p.h
- kernel/qeventdispatcher_unix.cpp kernel/qeventdispatcher_unix_p.h
kernel/qpoll_p.h
kernel/qtimerinfo_unix.cpp kernel/qtimerinfo_unix_p.h
thread/qthread_unix.cpp
)
+if(APPLE)
+ set_source_files_properties(io/qfilesystemengine_unix.cpp PROPERTIES LANGUAGE OBJCXX)
+ qt_internal_extend_target(Core CONDITION
+ PUBLIC_LIBRARIES ${FWUniformTypeIdentifiers}
+ )
+endif()
+
+qt_internal_extend_target(Core CONDITION UNIX AND NOT WASM
+ SOURCES
+ kernel/qeventdispatcher_unix.cpp kernel/qeventdispatcher_unix_p.h
+)
qt_internal_extend_target(Core CONDITION QT_FEATURE_thread
SOURCES
@@ -659,6 +694,7 @@ qt_internal_extend_target(Core CONDITION QT_FEATURE_thread AND UNIX
qt_internal_extend_target(Core CONDITION APPLE AND QT_FEATURE_thread
SOURCES
+ thread/qfutex_mac_p.h
thread/qmutex_mac.cpp
)
@@ -667,6 +703,16 @@ qt_internal_extend_target(Core CONDITION QT_FEATURE_thread AND UNIX AND NOT APPL
thread/qmutex_unix.cpp
)
+qt_internal_extend_target(Core CONDITION QT_FEATURE_thread AND FREEBSD
+ SOURCES
+ thread/qfutex_freebsd_p.h
+)
+
+qt_internal_extend_target(Core CONDITION QT_FEATURE_thread AND LINUX
+ SOURCES
+ thread/qfutex_linux_p.h
+)
+
qt_internal_extend_target(Core CONDITION QT_FEATURE_future
SOURCES
thread/qexception.cpp thread/qexception.h
@@ -750,12 +796,12 @@ qt_internal_extend_target(Core CONDITION UNIX AND NOT HAIKU AND NOT INTEGRITY AN
m
)
-qt_internal_extend_target(Core CONDITION APPLE AND NOT NACL
+qt_internal_extend_target(Core CONDITION APPLE
SOURCES
text/qlocale_mac.mm
)
-qt_internal_extend_target(Core CONDITION UNIX AND (NACL OR NOT APPLE)
+qt_internal_extend_target(Core CONDITION UNIX AND NOT APPLE AND NOT WASM
SOURCES
text/qlocale_unix.cpp
)
@@ -765,8 +811,13 @@ qt_internal_extend_target(Core CONDITION WIN32
text/qlocale_win.cpp
)
+qt_internal_extend_target(Core CONDITION WASM
+ SOURCES
+ text/qlocale_wasm.cpp
+)
+
# On MS-Win, clang has two flavors, one of which immitates MSVC (so claims to be it)
-qt_internal_extend_target(Core CONDITION WIN32 AND MSVC AND NOT CLANG
+qt_internal_extend_target(Core CONDITION MSVC
LIBRARIES
runtimeobject
)
@@ -801,7 +852,7 @@ qt_internal_extend_target(Core CONDITION QT_FEATURE_regularexpression
WrapPCRE2::WrapPCRE2
)
-qt_internal_extend_target(Core CONDITION QT_FEATURE_openssl_linked AND QT_FEATURE_opensslv30
+qt_internal_extend_target(Core CONDITION QT_FEATURE_openssl_hash
LIBRARIES
WrapOpenSSL::WrapOpenSSL
)
@@ -829,34 +880,46 @@ qt_internal_extend_target(Core CONDITION QT_FEATURE_timezone
time/qtimezoneprivate_data_p.h
)
-qt_internal_extend_target(Core CONDITION APPLE AND QT_FEATURE_timezone AND NOT NACL
+qt_internal_extend_target(Core CONDITION APPLE AND QT_FEATURE_timezone
SOURCES
time/qtimezoneprivate_mac.mm
)
-qt_internal_extend_target(Core CONDITION QT_FEATURE_timezone AND ANDROID AND (NACL OR NOT APPLE)
+qt_internal_extend_target(Core CONDITION QT_FEATURE_timezone AND ANDROID AND NOT APPLE
SOURCES
time/qtimezoneprivate_android.cpp
)
-qt_internal_extend_target(Core CONDITION QT_FEATURE_timezone AND UNIX AND NOT ANDROID AND (NACL OR NOT APPLE)
+qt_internal_extend_target(Core CONDITION QT_FEATURE_timezone AND UNIX AND NOT ANDROID AND NOT APPLE
SOURCES
time/qtimezoneprivate_tz.cpp
)
-qt_internal_extend_target(Core CONDITION QT_FEATURE_icu AND QT_FEATURE_timezone AND UNIX AND NOT ANDROID AND (NACL OR NOT APPLE)
+qt_internal_extend_target(Core
+ CONDITION
+ QT_FEATURE_icu AND QT_FEATURE_timezone AND NOT ANDROID AND NOT APPLE
SOURCES
time/qtimezoneprivate_icu.cpp
)
-qt_internal_extend_target(Core CONDITION QT_FEATURE_icu AND QT_FEATURE_timezone AND WIN32 AND NOT ANDROID AND (NACL OR NOT APPLE)
+# Even MS says we should prefer ICU over its APIs for TZ data:
+qt_internal_extend_target(Core
+ CONDITION
+ QT_FEATURE_timezone AND WIN32 AND NOT QT_FEATURE_icu
SOURCES
- time/qtimezoneprivate_icu.cpp
+ time/qtimezoneprivate_win.cpp
)
-qt_internal_extend_target(Core CONDITION QT_FEATURE_timezone AND WIN32 AND NOT QT_FEATURE_icu AND NOT ANDROID AND (NACL OR NOT APPLE)
+qt_internal_extend_target(Core
+ CONDITION QT_FEATURE_timezone_locale
SOURCES
- time/qtimezoneprivate_win.cpp
+ time/qtimezonelocale.cpp time/qtimezonelocale_p.h
+)
+
+qt_internal_extend_target(Core
+ CONDITION QT_FEATURE_timezone_locale AND NOT QT_FEATURE_icu
+ SOURCES
+ time/qtimezonelocale_data_p.h
)
qt_internal_extend_target(Core CONDITION QT_FEATURE_datetimeparser
@@ -920,7 +983,7 @@ qt_internal_extend_target(Core CONDITION QT_FEATURE_settings AND WIN32
io/qsettings_win.cpp
)
-qt_internal_extend_target(Core CONDITION APPLE AND QT_FEATURE_settings AND NOT NACL
+qt_internal_extend_target(Core CONDITION APPLE AND QT_FEATURE_settings
SOURCES
io/qsettings_mac.cpp
)
@@ -938,7 +1001,7 @@ qt_internal_extend_target(Core CONDITION QT_FEATURE_filesystemiterator AND WIN32
qt_internal_extend_target(Core CONDITION QT_FEATURE_process AND UNIX
SOURCES
../3rdparty/forkfd/forkfd.h
- io/forkfd_qt.cpp
+ io/forkfd_qt.c
INCLUDE_DIRECTORIES
../3rdparty/forkfd
)
@@ -953,24 +1016,26 @@ qt_internal_extend_target(Core CONDITION APPLE AND NOT MACOS
${FWMobileCoreServices}
)
-qt_internal_extend_target(Core CONDITION UNIX AND NOT APPLE
- SOURCES
- kernel/qelapsedtimer_unix.cpp
-)
-
qt_internal_extend_target(Core CONDITION ANDROID
SOURCES
io/qstandardpaths_android.cpp
- io/qstorageinfo_unix.cpp
- kernel/qjnitypes.h
+ io/qstorageinfo_linux.cpp io/qstorageinfo_linux_p.h
+ kernel/qjniarray.h
+ kernel/qjnitypes.h kernel/qjnitypes_impl.h
kernel/qjnienvironment.cpp kernel/qjnienvironment.h
kernel/qjniobject.cpp kernel/qjniobject.h
kernel/qjnihelpers.cpp kernel/qjnihelpers_p.h
platform/android/qandroidextras_p.h platform/android/qandroidextras.cpp
platform/android/qandroidnativeinterface.cpp
+ NO_UNITY_BUILD_SOURCES
+ platform/android/qandroidextras.cpp
+ # qtNativeClassName conflicts with similar symbols in android headers
+ # TODO: Resolve conflicts between various variables set as,
+ # `org/qtproject/qt/android/QtNative` QtAndroidPrivate might be a good
+ # place to put them.
)
-qt_internal_extend_target(Core CONDITION WIN32
+qt_internal_extend_target(Core CONDITION QT_FEATURE_cpp_winrt
SOURCES
platform/windows/qfactorycacheregistration_p.h
platform/windows/qfactorycacheregistration.cpp
@@ -985,12 +1050,19 @@ qt_internal_extend_target(Core CONDITION HAIKU AND NOT ANDROID
be
)
-qt_internal_extend_target(Core CONDITION UNIX AND NOT APPLE AND NOT HAIKU AND NOT ANDROID
+qt_internal_extend_target(Core
+ CONDITION UNIX AND NOT LINUX AND NOT APPLE AND NOT HAIKU AND NOT ANDROID AND NOT VXWORKS
SOURCES
io/qstandardpaths_unix.cpp
io/qstorageinfo_unix.cpp
)
+qt_internal_extend_target(Core CONDITION LINUX AND NOT ANDROID AND NOT VXWORKS
+ SOURCES
+ io/qstandardpaths_unix.cpp
+ io/qstorageinfo_linux.cpp
+)
+
qt_internal_extend_target(Core CONDITION QT_FEATURE_itemmodel
SOURCES
itemmodels/qabstractitemmodel.cpp itemmodels/qabstractitemmodel.h itemmodels/qabstractitemmodel_p.h
@@ -1052,7 +1124,7 @@ qt_internal_extend_target(Core CONDITION QT_FEATURE_dlopen
${CMAKE_DL_LIBS}
)
-qt_internal_extend_target(Core CONDITION APPLE AND (IOS OR TVOS)
+qt_internal_extend_target(Core CONDITION APPLE AND UIKIT
LIBRARIES
${FWUIKit}
)
@@ -1102,17 +1174,22 @@ qt_internal_extend_target(Core CONDITION QT_FEATURE_sysv_sem
qt_internal_extend_target(Core CONDITION VXWORKS
SOURCES
- kernel/qfunctions_vxworks.cpp kernel/qfunctions_vxworks.h
+ io/qstandardpaths_unix.cpp
+ io/qstorageinfo_stub.cpp
)
qt_internal_extend_target(Core CONDITION QT_FEATURE_cborstreamreader
SOURCES
serialization/qcborstreamreader.cpp serialization/qcborstreamreader.h
+ NO_UNITY_BUILD_SOURCES
+ serialization/qcborstreamreader.cpp # some problem with cbor_value_get_type etc
)
qt_internal_extend_target(Core CONDITION QT_FEATURE_cborstreamwriter
SOURCES
serialization/qcborstreamwriter.cpp serialization/qcborstreamwriter.h
+ NO_UNITY_BUILD_SOURCES
+ serialization/qcborstreamwriter.cpp # CBOR macro clashes
)
qt_internal_extend_target(Core CONDITION QT_FEATURE_mimetype
@@ -1281,50 +1358,31 @@ qt_internal_extend_target(Core CONDITION WASM
kernel/qeventdispatcher_wasm.cpp kernel/qeventdispatcher_wasm_p.h
)
-qt_internal_extend_target(Core CONDITION QT_FEATURE_ctf AND QT_FEATURE_library
+qt_internal_extend_target(Core CONDITION QT_FEATURE_ctf
SOURCES
tracing/qctf_p.h tracing/qctf.cpp
PLUGIN_TYPES
tracing
)
+# These files are included by qmutex.cpp
set_source_files_properties(
thread/qmutex_mac.cpp
thread/qmutex_unix.cpp
- PROPERTIES HEADER_FILE_ONLY ON) # special case: These files are included by qmutex.cpp!
-
-set_source_files_properties(serialization/qcborstreamwriter.cpp # CBOR macro clashes
- io/forkfd_qt.cpp # EINTR_LOOP macro clashes
- global/qglobal.cpp # undef qFatal
- global/qlogging.cpp # undef qFatal
- text/qstringconverter.cpp # enum Data
- tools/qcryptographichash.cpp # KeccakNISTInterface/Final
- ${corelib_no_pch_sources} # NO_PCH_SOURCES
- PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
+ PROPERTIES HEADER_FILE_ONLY ON)
# Remove QT_NO_CAST_TO_ASCII to ensure that the symbols are included in the library.
if(WIN32)
get_target_property(defines Core COMPILE_DEFINITIONS)
list(REMOVE_ITEM defines QT_NO_CAST_TO_ASCII)
set_target_properties(Core PROPERTIES COMPILE_DEFINITIONS "${defines}")
-
- set_source_files_properties(global/qsimd.cpp # Q_DECL_INIT_PRIORITY
- serialization/qcborvalue.cpp # various windows.h clashes
- serialization/qjsoncbor.cpp
- serialization/qjsonvalue.cpp
- serialization/qxmlstream.cpp
- text/qbytearray.cpp
- text/qlatin1stringmatcher.cpp
- text/qunicodetools.cpp
- tools/qhash.cpp # Q_DECL_INIT_PRIORITY
- PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
endif()
qt_internal_apply_gc_binaries_conditional(Core PUBLIC)
# Add entry-point on platforms that need it. A project can opt-out of using the
# entrypoint by setting the qt_no_entrypoint property to TRUE on a target.
-if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "iOS")
+if(WIN32 OR UIKIT)
# find_package(Qt6Core) should call find_package(Qt6EntryPointPrivate) so that we can
# link against EntryPointPrivate. Normally this is handled automatically for deps, but
# for some reason it doesn't work for the EntryPointPrivate, so we need to add it manually.
@@ -1394,3 +1452,35 @@ if(APPLE AND QT_FEATURE_framework AND QT_FEATURE_separate_debug_info)
DESTINATION "${dsym_script_install_dir}"
)
endif()
+
+if(IOS)
+ qt_internal_set_apple_privacy_manifest(Core
+ "${CMAKE_CURRENT_SOURCE_DIR}/platform/ios/PrivacyInfo.xcprivacy")
+endif()
+
+set(linker_script_contents "")
+if (QT_NAMESPACE STREQUAL "")
+ set(tag_symbol "qt_version_tag")
+else()
+ set(tag_symbol "qt_version_tag_${QT_NAMESPACE}")
+endif()
+foreach(minor_version RANGE ${PROJECT_VERSION_MINOR})
+ set(previous "${current}")
+ set(current "Qt_${PROJECT_VERSION_MAJOR}.${minor_version}")
+ if (minor_version EQUAL ${PROJECT_VERSION_MINOR})
+ string(APPEND linker_script_contents "${current} { ${tag_symbol}; } ${previous};\n")
+ else()
+ string(APPEND linker_script_contents "${current} {} ${previous};\n")
+ endif()
+endforeach()
+qt_internal_extend_target(Core
+ EXTRA_LINKER_SCRIPT_CONTENT "${linker_script_contents}"
+
+ # Workaround for QTBUG-117514:
+ # Function called by inline methods taking a pointer to a private class as a parameter
+ EXTRA_LINKER_SCRIPT_EXPORTS
+ # QFutureInterfaceBase::setContinuation(std::function<void (QFutureInterfaceBase const&)>, QFutureInterfaceBasePrivate*)
+ "_ZN*20QFutureInterfaceBase15setContinuationE*27QFutureInterfaceBasePrivate*"
+ # QReadWriteLock::destroyRecursive(QReadWriteLockPrivate*)
+ "_ZN*14QReadWriteLock16destroyRecursiveEP*21QReadWriteLockPrivate*"
+)
diff --git a/src/corelib/Qt6AndroidMacros.cmake b/src/corelib/Qt6AndroidMacros.cmake
index 2187e54cf0..6218df1947 100644
--- a/src/corelib/Qt6AndroidMacros.cmake
+++ b/src/corelib/Qt6AndroidMacros.cmake
@@ -107,7 +107,7 @@ function(qt6_android_generate_deployment_settings target)
set(config_suffix "$<$<NOT:$<CONFIG:${first_config_type}>>:-$<CONFIG>>")
endif()
set(deploy_file
- "${target_binary_dir}/android-${target_output_name}-deployment-settings${config_suffix}.json")
+ "${target_binary_dir}/android-${target}-deployment-settings${config_suffix}.json")
set(file_contents "{\n")
# content begin
@@ -197,7 +197,7 @@ function(qt6_android_generate_deployment_settings target)
" \"architectures\": { ${architecture_records} },\n")
# deployment dependencies
- _qt_internal_add_android_deployment_multi_value_property(file_contents "dependencies"
+ _qt_internal_add_android_deployment_multi_value_property(file_contents "deployment-dependencies"
${target} "QT_ANDROID_DEPLOYMENT_DEPENDENCIES" )
# Extra plugins
@@ -236,6 +236,10 @@ function(qt6_android_generate_deployment_settings target)
_qt_internal_add_android_deployment_property(file_contents "android-no-deploy-qt-libs"
${target} "QT_ANDROID_NO_DEPLOY_QT_LIBS")
+ __qt_internal_collect_plugin_targets_from_dependencies("${target}" plugin_targets)
+ __qt_internal_collect_plugin_library_files("${target}" "${plugin_targets}" plugin_targets)
+ string(APPEND file_contents " \"android-deploy-plugins\":\"${plugin_targets}\",\n")
+
# App binary
string(APPEND file_contents
" \"application-binary\": \"${target_output_name}\",\n")
@@ -303,7 +307,7 @@ function(qt6_android_generate_deployment_settings target)
# content end
string(APPEND file_contents "}\n")
- file(GENERATE OUTPUT ${deploy_file} CONTENT ${file_contents})
+ file(GENERATE OUTPUT ${deploy_file} CONTENT "${file_contents}")
set_target_properties(${target}
PROPERTIES
@@ -367,7 +371,11 @@ function(qt6_android_add_apk_target target)
endif()
# Use genex to get path to the deployment settings, the above check only to confirm that
# qt6_android_add_apk_target is called on an android executable target.
- set(deployment_file "$<TARGET_PROPERTY:${target},QT_ANDROID_DEPLOYMENT_SETTINGS_FILE>")
+ string(JOIN "" deployment_file
+ "$<GENEX_EVAL:"
+ "$<TARGET_PROPERTY:${target},QT_ANDROID_DEPLOYMENT_SETTINGS_FILE>"
+ ">"
+ )
# Make global apk and aab targets depend on the current apk target.
if(TARGET aab)
@@ -381,7 +389,34 @@ function(qt6_android_add_apk_target target)
set(deployment_tool "${QT_HOST_PATH}/${QT6_HOST_INFO_BINDIR}/androiddeployqt")
# No need to use genex for the BINARY_DIR since it's read-only.
get_target_property(target_binary_dir ${target} BINARY_DIR)
- set(apk_final_dir "${target_binary_dir}/android-build")
+
+ if($CACHE{QT_USE_TARGET_ANDROID_BUILD_DIR})
+ set(apk_final_dir "${target_binary_dir}/android-build-${target}")
+ else()
+ if(QT_USE_TARGET_ANDROID_BUILD_DIR)
+ message(WARNING "QT_USE_TARGET_ANDROID_BUILD_DIR needs to be set in CACHE")
+ endif()
+
+ get_property(known_android_build GLOBAL PROPERTY _qt_internal_known_android_build_dir)
+ get_property(already_warned GLOBAL PROPERTY _qt_internal_already_warned_android_build_dir)
+ set(apk_final_dir "${target_binary_dir}/android-build")
+ if(NOT QT_SKIP_ANDROID_BUILD_DIR_CHECK AND "${apk_final_dir}" IN_LIST known_android_build
+ AND NOT "${apk_final_dir}" IN_LIST already_warned)
+ message(WARNING "${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt contains multiple"
+ " Qt Android executable targets. This can lead to mixing of deployment artifacts"
+ " of targets defined there. Setting QT_USE_TARGET_ANDROID_BUILD_DIR=TRUE"
+ " allows building multiple executable targets within a single CMakeLists.txt."
+ " Note: This option is not supported by Qt Creator versions older than 13."
+ " Set QT_SKIP_ANDROID_BUILD_DIR_CHECK=TRUE to suppress this warning."
+ )
+ set_property(GLOBAL APPEND PROPERTY _qt_internal_already_warned_android_build_dir
+ "${apk_final_dir}")
+ else()
+ set_property(GLOBAL APPEND PROPERTY
+ _qt_internal_known_android_build_dir "${apk_final_dir}")
+ endif()
+ endif()
+
set(apk_file_name "${target}.apk")
set(dep_file_name "${target}.d")
set(apk_final_file_path "${apk_final_dir}/${apk_file_name}")
@@ -391,6 +426,10 @@ function(qt6_android_add_apk_target target)
set(extra_deps "")
+ if(QT_ENABLE_VERBOSE_DEPLOYMENT)
+ set(uses_terminal USES_TERMINAL)
+ endif()
+
# Plugins still might be added after creating the deployment targets.
if(NOT TARGET qt_internal_plugins)
add_custom_target(qt_internal_plugins)
@@ -410,6 +449,7 @@ function(qt6_android_add_apk_target target)
DEPENDS ${target} ${extra_deps}
COMMAND ${copy_command}
COMMENT "Copying ${target} binary to apk folder"
+ ${uses_terminal}
)
set(sign_apk "")
@@ -429,6 +469,26 @@ function(qt6_android_add_apk_target target)
list(APPEND extra_args "--verbose")
endif()
+ if(QT_ANDROID_DEPLOY_RELEASE)
+ message(WARNING "QT_ANDROID_DEPLOY_RELEASE is not a valid Qt variable."
+ " Please set QT_ANDROID_DEPLOYMENT_TYPE to RELEASE instead.")
+ endif()
+ # Setting QT_ANDROID_DEPLOYMENT_TYPE to a value other than Release disables
+ # release package signing regardless of the build type.
+ if(QT_ANDROID_DEPLOYMENT_TYPE)
+ string(TOUPPER "${QT_ANDROID_DEPLOYMENT_TYPE}" deployment_type_upper)
+ if("${deployment_type_upper}" STREQUAL "RELEASE")
+ list(APPEND extra_args "--release")
+ endif()
+ elseif(NOT QT_BUILD_TESTS)
+ # Workaround for tests: do not set automatically --release flag if QT_BUILD_TESTS is set.
+ # Release package need to be signed. Signing is currently not supported by CI.
+ # What is more, also androidtestrunner is not working on release APKs,
+ # For example running "adb shell run-as" on release APK will finish with the error:
+ # run-as: Package '[PACKAGE-NAME]' is not debuggable
+ list(APPEND extra_args $<$<OR:$<CONFIG:Release>,$<CONFIG:RelWithDebInfo>,$<CONFIG:MinSizeRel>>:--release>)
+ endif()
+
_qt_internal_check_depfile_support(has_depfile_support)
if(has_depfile_support)
@@ -461,6 +521,7 @@ function(qt6_android_add_apk_target target)
DEPENDS "${target}" "${deployment_file}" ${extra_deps}
DEPFILE "${dep_file_path}"
VERBATIM
+ ${uses_terminal}
)
cmake_policy(POP)
@@ -477,6 +538,7 @@ function(qt6_android_add_apk_target target)
${sign_apk}
COMMENT "Creating APK for ${target}"
VERBATIM
+ ${uses_terminal}
)
endif()
@@ -493,6 +555,7 @@ function(qt6_android_add_apk_target target)
${sign_aab}
${extra_args}
COMMENT "Creating AAB for ${target}"
+ ${uses_terminal}
)
if(QT_IS_ANDROID_MULTI_ABI_EXTERNAL_PROJECT)
@@ -532,6 +595,7 @@ function(qt6_android_add_apk_target target)
COMMENT "Resolving ${CMAKE_ANDROID_ARCH_ABI} dependencies for the ${target} APK"
DEPFILE "${dep_file}"
VERBATIM
+ ${uses_terminal}
)
add_custom_target(qt_internal_${target}_copy_apk_dependencies
DEPENDS "${timestamp_file}")
@@ -545,6 +609,7 @@ function(qt6_android_add_apk_target target)
--copy-dependencies-only
${extra_args}
COMMENT "Resolving ${CMAKE_ANDROID_ARCH_ABI} dependencies for the ${target} APK"
+ ${uses_terminal}
)
endif()
endif()
@@ -626,7 +691,8 @@ function(_qt_internal_collect_apk_dependencies)
get_property(apk_targets GLOBAL PROPERTY _qt_apk_targets)
- _qt_internal_collect_buildsystem_shared_libraries(libs "${CMAKE_SOURCE_DIR}")
+ _qt_internal_collect_buildsystem_targets(libs
+ "${CMAKE_SOURCE_DIR}" INCLUDE SHARED_LIBRARY MODULE_LIBRARY)
list(REMOVE_DUPLICATES libs)
if(NOT TARGET qt_internal_plugins)
@@ -655,28 +721,6 @@ function(_qt_internal_collect_apk_dependencies)
)
endfunction()
-# This function recursively walks the current directory and its subdirectories to collect shared
-# library targets built in those directories.
-function(_qt_internal_collect_buildsystem_shared_libraries out_var subdir)
- set(result "")
- get_directory_property(buildsystem_targets DIRECTORY ${subdir} BUILDSYSTEM_TARGETS)
- foreach(buildsystem_target IN LISTS buildsystem_targets)
- if(buildsystem_target AND TARGET ${buildsystem_target})
- get_target_property(target_type ${buildsystem_target} TYPE)
- if(target_type STREQUAL "SHARED_LIBRARY" OR target_type STREQUAL "MODULE_LIBRARY")
- list(APPEND result ${buildsystem_target})
- endif()
- endif()
- endforeach()
-
- get_directory_property(subdirs DIRECTORY "${subdir}" SUBDIRECTORIES)
- foreach(dir IN LISTS subdirs)
- _qt_internal_collect_buildsystem_shared_libraries(result_inner "${dir}")
- endforeach()
- list(APPEND result ${result_inner})
- set(${out_var} "${result}" PARENT_SCOPE)
-endfunction()
-
# This function collects all imported shared libraries that might be dependencies for
# the main apk targets. The actual collection is deferred until the target's directory scope
# is processed.
@@ -837,6 +881,9 @@ function(_qt_internal_add_android_deployment_list_property out_var json_key)
set(add_quote_genex
"$<$<BOOL:${property_genex}>:\">"
)
+
+ # Add comma only if next property genex contains non-empty value.
+ set(add_comma_genex "$<$<BOOL:${property_genex}>:${add_comma_genex}>")
string(JOIN "" list_join_genex
"${list_join_genex}"
"${add_comma_genex}${add_quote_genex}"
@@ -881,15 +928,55 @@ endfunction()
# It doesn't overwrite public properties, but instead writes formatted values to internal
# properties.
function(_qt_internal_android_format_deployment_paths target)
- if(QT_BUILD_STANDALONE_TESTS OR QT_BUILDING_QT)
+ if(QT_BUILD_STANDALONE_TESTS OR QT_BUILDING_QT OR QT_INTERNAL_IS_STANDALONE_TEST)
+ set(android_deployment_paths_policy NEW)
+ else()
+ set(policy_path_properties
+ QT_QML_IMPORT_PATH
+ QT_QML_ROOT_PATH
+ QT_ANDROID_PACKAGE_SOURCE_DIR
+ QT_ANDROID_EXTRA_PLUGINS
+ QT_ANDROID_EXTRA_LIBS
+ )
+
+ # Check if any of paths contains the value and stop the evaluation if all properties are
+ # empty or -NOTFOUND
+ set(has_android_paths FALSE)
+ foreach(prop_name IN LISTS policy_path_properties)
+ get_target_property(prop_value ${target} ${prop_name})
+ if(prop_value)
+ set(has_android_paths TRUE)
+ break()
+ endif()
+ endforeach()
+ if(has_android_paths)
+ __qt_internal_setup_policy(QTP0002 "6.6.0"
+ "Target properties that specify android-specific paths may contain generator\
+ expressions but they must evaluate to valid JSON strings.\
+ Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0002.html for policy details."
+ )
+ qt6_policy(GET QTP0002 android_deployment_paths_policy)
+ endif()
+ endif()
+ if(android_deployment_paths_policy STREQUAL "NEW")
# When building standalone tests or Qt itself we obligate developers to not use
# windows paths when setting QT_* properties below, so their values are used as is when
# generating deployment settings.
+ string(JOIN "" qml_root_path_genex
+ "$<GENEX_EVAL:$<TARGET_PROPERTY:${target},QT_QML_ROOT_PATH>>"
+ "$<"
+ "$<AND:"
+ "$<BOOL:$<GENEX_EVAL:$<TARGET_PROPERTY:${target},QT_QML_ROOT_PATH>>>,"
+ "$<BOOL:$<GENEX_EVAL:$<TARGET_PROPERTY:${target},_qt_internal_qml_root_path>>>"
+ ">:;"
+ ">"
+ "$<GENEX_EVAL:$<TARGET_PROPERTY:${target},_qt_internal_qml_root_path>>"
+ )
set_target_properties(${target} PROPERTIES
_qt_native_qml_import_paths
"$<GENEX_EVAL:$<TARGET_PROPERTY:${target},QT_QML_IMPORT_PATH>>"
_qt_android_native_qml_root_paths
- "$<GENEX_EVAL:$<TARGET_PROPERTY:${target},QT_QML_ROOT_PATH>>"
+ "${qml_root_path_genex}"
_qt_android_native_package_source_dir
"$<GENEX_EVAL:$<TARGET_PROPERTY:${target},QT_ANDROID_PACKAGE_SOURCE_DIR>>"
_qt_android_native_extra_plugins
@@ -907,6 +994,9 @@ function(_qt_internal_android_format_deployment_paths target)
QT_QML_ROOT_PATH _qt_android_native_qml_root_paths)
_qt_internal_android_format_deployment_path_property(${target}
+ _qt_internal_qml_root_path _qt_android_native_qml_root_paths APPEND)
+
+ _qt_internal_android_format_deployment_path_property(${target}
QT_ANDROID_PACKAGE_SOURCE_DIR _qt_android_native_package_source_dir)
_qt_internal_android_format_deployment_path_property(${target}
@@ -920,7 +1010,20 @@ endfunction()
# The function converts the value of target property to JSON compatible path and writes the
# result to out_property. Property might be either single value, semicolon separated list or system
# path spec.
+# The APPEND argument controls the property is set. The argument should be added after all
+# the required arguments.
function(_qt_internal_android_format_deployment_path_property target property out_property)
+ set(should_append "")
+ if(ARGC EQUAL 4)
+ if("${ARGV3}" STREQUAL "APPEND")
+ set(should_append APPEND)
+ else()
+ message(FATAL_ERROR "Unexpected argument ${ARGV3}")
+ endif()
+ elseif(ARGC GREATER 4)
+ message(FATAL_ERROR "Unexpected arguments ${ARGN}")
+ endif()
+
get_target_property(_paths ${target} ${property})
if(_paths)
set(native_paths "")
@@ -928,7 +1031,7 @@ function(_qt_internal_android_format_deployment_path_property target property ou
file(TO_CMAKE_PATH "${_path}" _path)
list(APPEND native_paths "${_path}")
endforeach()
- set_target_properties(${target} PROPERTIES
+ set_property(TARGET ${target} ${should_append} PROPERTY
${out_property} "${native_paths}")
endif()
endfunction()
@@ -981,10 +1084,11 @@ function(_qt_internal_get_android_abi_cmake_dir_path out_path abi)
else()
_qt_internal_get_android_abi_prefix_path(prefix_path ${abi})
if((PROJECT_NAME STREQUAL "QtBase" OR QT_SUPERBUILD) AND QT_BUILDING_QT AND
- NOT QT_BUILD_STANDALONE_TESTS)
+ NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_INTERNAL_IS_STANDALONE_TEST)
set(cmake_dir "${QT_CONFIG_BUILD_DIR}")
else()
- set(cmake_dir "${prefix_path}/${QT6_INSTALL_LIBS}/cmake")
+ string(TOUPPER "${QT_CMAKE_EXPORT_NAMESPACE}" export_namespace_upper)
+ set(cmake_dir "${prefix_path}/${${export_namespace_upper}_INSTALL_LIBS}/cmake")
endif()
endif()
@@ -1000,7 +1104,7 @@ function(_qt_internal_get_android_abi_toolchain_path out_path abi)
endfunction()
function(_qt_internal_get_android_abi_subdir_path out_path subdir abi)
- set(install_paths_path "${QT_CMAKE_EXPORT_NAMESPACE}Core/QtInstallPaths.cmake")
+ set(install_paths_path "${QT_CMAKE_EXPORT_NAMESPACE}/QtInstallPaths.cmake")
_qt_internal_get_android_abi_cmake_dir_path(cmake_dir ${abi})
include("${cmake_dir}/${install_paths_path}")
set(${out_path} "${${subdir}}" PARENT_SCOPE)
@@ -1080,6 +1184,91 @@ function(_qt_internal_collect_default_android_abis)
)
endfunction()
+# Returns a path to the timestamp file for the specific step of the multi-ABI Android project
+function(_qt_internal_get_android_abi_step_stampfile out project abi step)
+ get_target_property(build_dir ${project} _qt_android_build_directory)
+ get_property(is_multi GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ if(is_multi)
+ set(${out} "${build_dir}/$<CONFIG>/${project}_${step}_stamp" PARENT_SCOPE)
+ else()
+ set(${out} "${build_dir}/${project}_${step}_stamp" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Creates the multi-ABI Android projects and assigns the JOB_POOL to them if it's possible
+function(_qt_internal_add_android_abi_project project abi)
+ add_custom_target(${project})
+
+ set(build_dir "${CMAKE_BINARY_DIR}/android_abi_builds/${abi}")
+ set_target_properties(${project} PROPERTIES
+ _qt_android_build_directory "${build_dir}"
+ )
+
+ file(MAKE_DIRECTORY "${build_dir}")
+ if(CMAKE_GENERATOR MATCHES "^Ninja")
+ set_property(GLOBAL APPEND PROPERTY JOB_POOLS _qt_android_${project}_pool=1)
+ endif()
+endfunction()
+
+# Adds the custom build step to the multi-ABI Android project
+function(_qt_internal_add_android_abi_step project abi step)
+ cmake_parse_arguments(arg "" "" "COMMAND;DEPENDS" ${ARGV})
+
+ if(NOT arg_COMMAND)
+ message(FATAL_ERROR "COMMAND is not set for ${project} step ${step} Android ABI ${abi}.")
+ endif()
+
+ set(dep_stamps "")
+ foreach(dep ${arg_DEPENDS})
+ _qt_internal_get_android_abi_step_stampfile(stamp ${project} ${abi} ${dep})
+ list(APPEND dep_stamps "${stamp}")
+ endforeach()
+
+ get_target_property(build_dir ${project} _qt_android_build_directory)
+
+ if(CMAKE_GENERATOR MATCHES "^Ninja")
+ set(add_to_pool JOB_POOL _qt_android_${project}_pool)
+ else()
+ set(add_to_pool "")
+ endif()
+
+ _qt_internal_get_android_abi_step_stampfile(stamp ${project} ${abi} ${step})
+ add_custom_command(OUTPUT "${stamp}"
+ COMMAND ${arg_COMMAND}
+ COMMAND "${CMAKE_COMMAND}" -E touch "${stamp}"
+ ${add_to_pool}
+ DEPENDS
+ ${dep_stamps}
+ WORKING_DIRECTORY
+ "${build_dir}"
+ VERBATIM
+ )
+ add_custom_target("${project}_${step}" DEPENDS "${stamp}")
+
+ get_target_property(known_steps ${project} _qt_android_abi_steps)
+ if(NOT CMAKE_GENERATOR MATCHES "^Ninja")
+ if(NOT QT_NO_WARN_ANDROID_MULTI_ABI_GENERATOR)
+ get_property(is_warned GLOBAL PROPERTY _qt_internal_warn_android_multi_abi_generator)
+ if(NOT is_warned)
+ set_property(GLOBAL PROPERTY _qt_internal_warn_android_multi_abi_generator TRUE)
+ message(WARNING "Building Multi-ABI Qt projects with the '${CMAKE_GENERATOR}'"
+ " generator has limitations. All targets from non-main ABI will be built"
+ " unconditionally. Please use the 'Ninja' or 'Ninja Multi-config' generators"
+ " with ninja build instead. Set QT_NO_WARN_ANDROID_MULTI_ABI_GENERATOR to"
+ " 'TRUE' to suppress this warning."
+ )
+ endif()
+ endif()
+ if(known_steps)
+ list(GET known_steps 0 first)
+ add_dependencies(${first} ${project}_${step})
+ endif()
+ endif()
+
+ list(PREPEND known_steps ${project}_${step})
+ set_target_properties(${project} PROPERTIES _qt_android_abi_steps "${known_steps}")
+endfunction()
+
# The function configures external projects for ABIs that target packages need to build with.
# Each target adds build step to the external project that is linked to the
# qt_internal_android_${abi}-${target}_build target in the primary ABI build tree.
@@ -1189,7 +1378,6 @@ function(_qt_internal_configure_android_multiabi_target target)
set(previous_copy_apk_dependencies_target ${target})
# Create external projects for each android ABI except the main one.
list(REMOVE_ITEM android_abis "${CMAKE_ANDROID_ARCH_ABI}")
- include(ExternalProject)
foreach(abi IN ITEMS ${android_abis})
if(NOT "${abi}" IN_LIST QT_DEFAULT_ANDROID_ABIS)
list(APPEND missing_qt_abi_toolchains ${abi})
@@ -1197,16 +1385,17 @@ function(_qt_internal_configure_android_multiabi_target target)
continue()
endif()
- set(android_abi_build_dir "${CMAKE_BINARY_DIR}/android_abi_builds/${abi}")
get_property(abi_external_projects GLOBAL
PROPERTY _qt_internal_abi_external_projects)
if(NOT abi_external_projects
OR NOT "qt_internal_android_${abi}" IN_LIST abi_external_projects)
+ _qt_internal_add_android_abi_project(qt_internal_android_${abi} ${abi})
+
+ get_target_property(android_abi_build_dir qt_internal_android_${abi}
+ _qt_android_build_directory)
_qt_internal_get_android_abi_toolchain_path(qt_abi_toolchain_path ${abi})
- ExternalProject_Add("qt_internal_android_${abi}"
- SOURCE_DIR "${CMAKE_SOURCE_DIR}"
- BINARY_DIR "${android_abi_build_dir}"
- CONFIGURE_COMMAND
+ _qt_internal_add_android_abi_step(qt_internal_android_${abi} ${abi} configure
+ COMMAND
"${CMAKE_COMMAND}"
"-G${CMAKE_GENERATOR}"
"-DCMAKE_TOOLCHAIN_FILE=${qt_abi_toolchain_path}"
@@ -1218,44 +1407,36 @@ function(_qt_internal_configure_android_multiabi_target target)
"${user_cmake_args}"
"-B" "${android_abi_build_dir}"
"-S" "${CMAKE_SOURCE_DIR}"
- EXCLUDE_FROM_ALL TRUE
- BUILD_COMMAND "" # avoid top-level build of external project
)
set_property(GLOBAL APPEND PROPERTY
_qt_internal_abi_external_projects "qt_internal_android_${abi}")
endif()
- ExternalProject_Add_Step("qt_internal_android_${abi}"
- "${target}_build"
- DEPENDEES configure
- # TODO: Remove this when the step will depend on DEPFILE generated by
- # androiddeployqt for the ${target}.
- ALWAYS TRUE
- EXCLUDE_FROM_MAIN TRUE
- COMMAND "${CMAKE_COMMAND}"
- "--build" "${android_abi_build_dir}"
- "--config" "$<CONFIG>"
- "--target" "${target}"
+
+ get_target_property(android_abi_build_dir qt_internal_android_${abi}
+ _qt_android_build_directory)
+ _qt_internal_add_android_abi_step(qt_internal_android_${abi} ${abi} ${target}_build
+ DEPENDS
+ configure
+ COMMAND
+ "${CMAKE_COMMAND}"
+ --build "${android_abi_build_dir}"
+ --config $<CONFIG>
+ --target ${target}
)
- ExternalProject_Add_StepTargets("qt_internal_android_${abi}"
- "${target}_build")
- add_dependencies(${target} "qt_internal_android_${abi}-${target}_build")
-
- ExternalProject_Add_Step("qt_internal_android_${abi}"
- "${target}_copy_apk_dependencies"
- DEPENDEES "${target}_build"
- # TODO: Remove this when the step will depend on DEPFILE generated by
- # androiddeployqt for the ${target}.
- ALWAYS TRUE
- EXCLUDE_FROM_MAIN TRUE
- COMMAND "${CMAKE_COMMAND}"
- "--build" "${android_abi_build_dir}"
- "--config" "$<CONFIG>"
- "--target" "qt_internal_${target}_copy_apk_dependencies"
+ add_dependencies(${target} "qt_internal_android_${abi}_${target}_build")
+
+ _qt_internal_add_android_abi_step(qt_internal_android_${abi} ${abi}
+ ${target}_copy_apk_dependencies
+ DEPENDS
+ ${target}_build
+ COMMAND
+ "${CMAKE_COMMAND}"
+ --build "${android_abi_build_dir}"
+ --config $<CONFIG>
+ --target qt_internal_${target}_copy_apk_dependencies
)
- ExternalProject_Add_StepTargets("qt_internal_android_${abi}"
- "${target}_copy_apk_dependencies")
set(external_project_copy_target
- "qt_internal_android_${abi}-${target}_copy_apk_dependencies")
+ "qt_internal_android_${abi}_${target}_copy_apk_dependencies")
# Need to build dependency chain between the
# qt_internal_android_${abi}-${target}_copy_apk_dependencies targets for all ABI's, to
@@ -1327,3 +1508,6 @@ function(_qt_internal_expose_android_package_source_dir_to_ide target)
endforeach()
endif()
endfunction()
+
+set(QT_INTERNAL_ANDROID_TARGET_BUILD_DIR_SUPPORT ON CACHE INTERNAL
+ "Indicates that Qt supports per-target Android build directories")
diff --git a/src/corelib/Qt6CTestMacros.cmake b/src/corelib/Qt6CTestMacros.cmake
index a27581dd8e..8722553cd0 100644
--- a/src/corelib/Qt6CTestMacros.cmake
+++ b/src/corelib/Qt6CTestMacros.cmake
@@ -142,17 +142,18 @@ function(_qt_internal_get_cmake_test_configure_options out_var)
)
endforeach()
- set(prefixes "")
- foreach(prefix_path IN LISTS CMAKE_PREFIX_PATH)
- file(TO_CMAKE_PATH "${prefix_path}" prefix_path)
- list(APPEND prefixes "${prefix_path}")
- endforeach()
+ _qt_internal_get_build_vars_for_external_projects(
+ PREFIXES_VAR prefixes
+ ADDITIONAL_PACKAGES_PREFIXES_VAR additional_prefixes
+ )
+
if(arg_OUT_PREFIX_PATH)
set(${arg_OUT_PREFIX_PATH} "${prefixes}" PARENT_SCOPE)
endif()
string(REPLACE ";" "\;" prefixes "${prefixes}")
list(APPEND option_list "-DCMAKE_PREFIX_PATH=${prefixes}")
+ list(APPEND option_list "-DQT_ADDITIONAL_PACKAGES_PREFIX_PATH=${additional_prefixes}")
set(${out_var} "${option_list}" PARENT_SCOPE)
endfunction()
@@ -383,7 +384,7 @@ macro(_qt_internal_test_expect_pass _dir)
endif()
if(build_environment STREQUAL "ci"
AND osx_arch_count GREATER_EQUAL 2
- AND NOT QT_UIKIT_SDK
+ AND NOT QT_APPLE_SDK
AND NOT QT_NO_IOS_BUILD_ADJUSTMENT_IN_CI)
list(APPEND additional_configure_args
-DCMAKE_OSX_ARCHITECTURES=x86_64 -DCMAKE_OSX_SYSROOT=iphonesimulator)
diff --git a/src/corelib/Qt6CoreConfigExtras.cmake.in b/src/corelib/Qt6CoreConfigExtras.cmake.in
index 4a9f72a049..7fd929e59b 100644
--- a/src/corelib/Qt6CoreConfigExtras.cmake.in
+++ b/src/corelib/Qt6CoreConfigExtras.cmake.in
@@ -2,16 +2,6 @@ if(NOT DEFINED QT_DEFAULT_MAJOR_VERSION)
set(QT_DEFAULT_MAJOR_VERSION 6)
endif()
-# include(\"${CMAKE_CURRENT_LIST_DIR}/Qt5CoreConfigExtrasMkspecDir.cmake\")
-#
-# foreach(_dir ${_qt5_corelib_extra_includes})
-# _qt5_Core_check_file_exists(${_dir})
-# endforeach()
-
-# list(APPEND Qt5Core_INCLUDE_DIRS ${_qt5_corelib_extra_includes})
-# set_property(TARGET @QT_CMAKE_EXPORT_NAMESPACE@::Core APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${_qt5_corelib_extra_includes})
-# set(_qt5_corelib_extra_includes)
-
if (NOT QT_NO_CREATE_TARGETS)
set(__qt_core_target @QT_CMAKE_EXPORT_NAMESPACE@::Core)
get_property(__qt_core_aliased_target TARGET ${__qt_core_target} PROPERTY ALIASED_TARGET)
@@ -19,19 +9,17 @@ if (NOT QT_NO_CREATE_TARGETS)
set(__qt_core_target "${__qt_core_aliased_target}")
endif()
unset(__qt_core_aliased_target)
- if (NOT "@QT_NAMESPACE@" STREQUAL "")
- set_property(TARGET ${__qt_core_target} APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS QT_NAMESPACE=@QT_NAMESPACE@)
- endif()
+ @qtcore_namespace_definition@
set_property(TARGET ${__qt_core_target} APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS $<$<NOT:$<CONFIG:Debug>>:QT_NO_DEBUG>)
set_property(TARGET ${__qt_core_target} PROPERTY INTERFACE_COMPILE_FEATURES cxx_decltype)
endif()
-list(APPEND CMAKE_AUTOMOC_MACRO_NAMES Q_OBJECT Q_GADGET Q_GADGET_EXPORT Q_NAMESPACE Q_NAMESPACE_EXPORT)
+# note: all the other AUTOMOC_MACRO_NAMES are already set by upstream CMake
+list(APPEND CMAKE_AUTOMOC_MACRO_NAMES Q_GADGET_EXPORT Q_ENUM_NS)
list(REMOVE_DUPLICATES CMAKE_AUTOMOC_MACRO_NAMES)
-include("${CMAKE_CURRENT_LIST_DIR}/QtInstallPaths.cmake")
-
set(QT@PROJECT_VERSION_MAJOR@_IS_SHARED_LIBS_BUILD "@BUILD_SHARED_LIBS@")
+set(QT@PROJECT_VERSION_MAJOR@_DEBUG_POSTFIX "@CMAKE_DEBUG_POSTFIX@")
set(_Qt6CTestMacros "${CMAKE_CURRENT_LIST_DIR}/Qt6CTestMacros.cmake")
diff --git a/src/corelib/Qt6CoreDeploySupport.cmake b/src/corelib/Qt6CoreDeploySupport.cmake
index aeda7405be..2fc8f8bf1c 100644
--- a/src/corelib/Qt6CoreDeploySupport.cmake
+++ b/src/corelib/Qt6CoreDeploySupport.cmake
@@ -153,6 +153,34 @@ function(_qt_internal_get_rpath_origin out_var)
set(${out_var} ${rpath_origin} PARENT_SCOPE)
endfunction()
+# Add a function to the list of deployment hooks.
+# The hooks are run at the end of _qt_internal_generic_deployqt.
+#
+# Every hook is passed the parameters of _qt_internal_generic_deployqt plus the following:
+# RESOLVED_DEPENDENCIES: list of resolved dependencies that were installed.
+function(_qt_internal_add_deployment_hook function_name)
+ set_property(GLOBAL APPEND PROPERTY QT_INTERNAL_DEPLOYMENT_HOOKS "${function_name}")
+endfunction()
+
+# Run all registered deployment hooks.
+function(_qt_internal_run_deployment_hooks)
+ get_property(hooks GLOBAL PROPERTY QT_INTERNAL_DEPLOYMENT_HOOKS)
+ foreach(hook IN LISTS hooks)
+ if(NOT COMMAND "${hook}")
+ message(AUTHOR_WARNING "'${hook}' is not a command but was added as deployment hook.")
+ continue()
+ endif()
+ if(CMAKE_VERSION GREATER_EQUAL "3.19")
+ cmake_language(CALL "${hook}" ${ARGV})
+ else()
+ set(temp_file ".qt-run-deploy-hook.cmake")
+ file(WRITE "${temp_file}" "${hook}(${ARGV})")
+ include(${temp_file})
+ file(REMOVE "${temp_file}")
+ endif()
+ endforeach()
+endfunction()
+
function(_qt_internal_generic_deployqt)
set(no_value_options
NO_TRANSLATIONS
@@ -273,6 +301,8 @@ function(_qt_internal_generic_deployqt)
if(NOT arg_NO_TRANSLATIONS)
qt6_deploy_translations()
endif()
+
+ _qt_internal_run_deployment_hooks(${ARGV} RESOLVED_DEPENDENCIES ${resolved})
endfunction()
function(qt6_deploy_runtime_dependencies)
@@ -293,6 +323,7 @@ function(qt6_deploy_runtime_dependencies)
EXECUTABLE
BIN_DIR
LIB_DIR
+ LIBEXEC_DIR
PLUGINS_DIR
QML_DIR
)
@@ -316,6 +347,7 @@ function(qt6_deploy_runtime_dependencies)
ADDITIONAL_LIBRARIES
ADDITIONAL_MODULES
${file_GRD_options}
+ DEPLOY_TOOL_OPTIONS
)
cmake_parse_arguments(PARSE_ARGV 0 arg
"${no_value_options}" "${single_value_options}" "${multi_value_options}"
@@ -333,6 +365,9 @@ function(qt6_deploy_runtime_dependencies)
if(NOT arg_BIN_DIR)
set(arg_BIN_DIR "${QT_DEPLOY_BIN_DIR}")
endif()
+ if(NOT arg_LIBEXEC_DIR)
+ set(arg_LIBEXEC_DIR "${QT_DEPLOY_LIBEXEC_DIR}")
+ endif()
if(NOT arg_LIB_DIR)
set(arg_LIB_DIR "${QT_DEPLOY_LIB_DIR}")
endif()
@@ -393,6 +428,8 @@ function(qt6_deploy_runtime_dependencies)
--dir .
--libdir "${arg_BIN_DIR}" # NOTE: Deliberately not arg_LIB_DIR
--plugindir "${arg_PLUGINS_DIR}"
+ --qml-deploy-dir "${arg_QML_DIR}"
+ --translationdir "${QT_DEPLOY_TRANSLATIONS_DIR}"
)
if(NOT arg_NO_OVERWRITE)
list(APPEND tool_options --force)
@@ -403,6 +440,19 @@ function(qt6_deploy_runtime_dependencies)
if(arg_NO_COMPILER_RUNTIME)
list(APPEND tool_options --no-compiler-runtime)
endif()
+
+ # Specify path to target Qt's qtpaths .exe or .bat file, so windeployqt deploys the correct
+ # libraries when cross-compiling from x86_64 to arm64 windows.
+ if(__QT_DEPLOY_TARGET_QT_PATHS_PATH AND EXISTS "${__QT_DEPLOY_TARGET_QT_PATHS_PATH}")
+ list(APPEND tool_options --qtpaths "${__QT_DEPLOY_TARGET_QT_PATHS_PATH}")
+ else()
+ message(WARNING
+ "No qtpaths executable found for target Qt "
+ "at: ${__QT_DEPLOY_TARGET_QT_PATHS_PATH}. "
+ "Libraries may not be deployed correctly.")
+ endif()
+
+ list(APPEND tool_options ${arg_DEPLOY_TOOL_OPTIONS})
elseif(__QT_DEPLOY_SYSTEM_NAME STREQUAL Darwin)
set(extra_binaries_option "-executable=")
if(NOT arg_NO_APP_STORE_COMPLIANCE)
@@ -411,6 +461,7 @@ function(qt6_deploy_runtime_dependencies)
if(NOT arg_NO_OVERWRITE)
list(APPEND tool_options -always-overwrite)
endif()
+ list(APPEND tool_options ${arg_DEPLOY_TOOL_OPTIONS})
endif()
# This is an internal variable. It is normally unset and is only intended
@@ -420,6 +471,13 @@ function(qt6_deploy_runtime_dependencies)
if(__QT_DEPLOY_TOOL STREQUAL "GRD")
message(STATUS "Running generic Qt deploy tool on ${arg_EXECUTABLE}")
+ if(NOT "${arg_DEPLOY_TOOL_OPTIONS}" STREQUAL "")
+ message(WARNING
+ "DEPLOY_TOOL_OPTIONS was specified but has no effect when using the generic "
+ "deployment tool."
+ )
+ endif()
+
# Construct the EXECUTABLES, LIBRARIES and MODULES arguments.
list(APPEND tool_options EXECUTABLES ${arg_EXECUTABLE})
if(NOT "${arg_ADDITIONAL_EXECUTABLES}" STREQUAL "")
@@ -488,10 +546,19 @@ if(NOT __QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
endif()
function(_qt_internal_show_skip_runtime_deploy_message qt_build_type_string)
+ set(no_value_options "")
+ set(single_value_options
+ EXTRA_MESSAGE
+ )
+ set(multi_value_options "")
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${no_value_options}" "${single_value_options}" "${multi_value_options}"
+ )
message(STATUS
"Skipping runtime deployment steps. "
"Support for installing runtime dependencies is not implemented for "
- "this target platform (${__QT_DEPLOY_SYSTEM_NAME}, ${qt_build_type_string})."
+ "this target platform (${__QT_DEPLOY_SYSTEM_NAME}, ${qt_build_type_string}). "
+ "${arg_EXTRA_MESSAGE}"
)
endfunction()
@@ -518,34 +585,7 @@ function(qt6_deploy_translations)
if(arg_CATALOGS)
set(catalogs ${arg_CATALOGS})
else()
- set(catalogs qt qtbase)
-
- # Find the translations that belong to the Qt modules that are used by the project.
- # "Used by the project" means just all modules that are pulled in via find_package for now.
- set(modules ${__QT_DEPLOY_ALL_MODULES_FOUND_VIA_FIND_PACKAGE})
-
- set(module_catalog_mapping
- "Bluetooth|Nfc" qtconnectivity
- "Help" qt_help
- "Multimedia(Widgets|QuickPrivate)?" qtmultimedia
- "Qml|Quick" qtdeclarative
- "SerialPort" qtserialport
- "WebEngine" qtwebengine
- "WebSockets" qtwebsockets
- )
- list(LENGTH module_catalog_mapping max_i)
- math(EXPR max_i "${max_i} - 1")
- foreach(module IN LISTS modules)
- foreach(i RANGE 0 ${max_i} 2)
- list(GET module_catalog_mapping ${i} module_rex)
- if(NOT module MATCHES "^${module_rex}")
- continue()
- endif()
- math(EXPR k "${i} + 1")
- list(GET module_catalog_mapping ${k} catalog)
- list(APPEND catalogs ${catalog})
- endforeach()
- endforeach()
+ set(catalogs ${__QT_DEPLOY_I18N_CATALOGS})
endif()
get_filename_component(qt_translations_dir "${__QT_DEPLOY_QT_INSTALL_TRANSLATIONS}" ABSOLUTE
diff --git a/src/corelib/Qt6CoreMacros.cmake b/src/corelib/Qt6CoreMacros.cmake
index 721358b900..9e71b4265a 100644
--- a/src/corelib/Qt6CoreMacros.cmake
+++ b/src/corelib/Qt6CoreMacros.cmake
@@ -101,11 +101,22 @@ function(_qt_internal_create_moc_command infile outfile moc_flags moc_options
set(targetincludes "$<$<BOOL:${targetincludes}>:-I$<JOIN:${targetincludes},;-I>>")
set(targetdefines "$<$<BOOL:${targetdefines}>:-D$<JOIN:${targetdefines},;-D>>")
- string(REPLACE ">" "$<ANGLE-R>" _moc_escaped_parameters "${_moc_parameters}")
- string(REPLACE "," "$<COMMA>" _moc_escaped_parameters "${_moc_escaped_parameters}")
+ set(_moc_parameters_list_without_genex)
+ set(_moc_parameters_list_with_genex)
+ foreach(_moc_parameter ${_moc_parameters})
+ if(_moc_parameter MATCHES "\\\$<")
+ list(APPEND _moc_parameters_list_with_genex ${_moc_parameter})
+ else()
+ list(APPEND _moc_parameters_list_without_genex ${_moc_parameter})
+ endif()
+ endforeach()
+ string(REPLACE ">" "$<ANGLE-R>" _moc_escaped_parameters "${_moc_parameters_list_without_genex}")
+ string(REPLACE "," "$<COMMA>" _moc_escaped_parameters "${_moc_escaped_parameters}")
+ string(REPLACE ";" "$<SEMICOLON>" _moc_escaped_parameters "${_moc_escaped_parameters}")
set(concatenated "$<$<BOOL:${targetincludes}>:${targetincludes};>$<$<BOOL:${targetdefines}>:${targetdefines};>$<$<BOOL:${_moc_escaped_parameters}>:${_moc_escaped_parameters};>")
+ list(APPEND concatenated ${_moc_parameters_list_with_genex})
set(concatenated "$<FILTER:$<REMOVE_DUPLICATES:${concatenated}>,EXCLUDE,^-[DI]$>")
set(concatenated "$<JOIN:${concatenated},\n>")
@@ -129,8 +140,12 @@ function(_qt_internal_create_moc_command infile outfile moc_flags moc_options
${_moc_working_dir}
VERBATIM)
set_source_files_properties(${infile} PROPERTIES SKIP_AUTOMOC ON)
- set_source_files_properties(${outfile} PROPERTIES SKIP_AUTOMOC ON)
- set_source_files_properties(${outfile} PROPERTIES SKIP_AUTOUIC ON)
+ set_source_files_properties(${outfile} PROPERTIES SKIP_AUTOMOC ON
+ SKIP_AUTOUIC ON
+ )
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.27")
+ set_source_files_properties(${outfile} PROPERTIES SKIP_LINTING ON)
+ endif()
endfunction()
function(qt6_generate_moc infile outfile )
@@ -185,7 +200,49 @@ function(qt6_wrap_cpp outfiles )
foreach(it ${moc_files})
get_filename_component(it ${it} ABSOLUTE)
- _qt_internal_make_output_file(${it} moc_ cpp outfile)
+ get_filename_component(it_ext ${it} EXT)
+ # remove the dot
+ string(SUBSTRING ${it_ext} 1 -1 it_ext)
+ set(HEADER_REGEX "(h|hh|h\\+\\+|hm|hpp|hxx|in|txx|inl)$")
+
+ if(it_ext MATCHES "${HEADER_REGEX}")
+ _qt_internal_make_output_file("${it}" moc_ cpp outfile)
+ set(is_header_file TRUE)
+ else()
+ set(found_source_extension FALSE)
+ foreach(LANG C CXX OBJC OBJCXX CUDA)
+ list(FIND CMAKE_${LANG}_SOURCE_FILE_EXTENSIONS "${it_ext}"
+ index)
+ if(${index} GREATER -1)
+ set(found_extension TRUE)
+ break()
+ endif()
+ endforeach()
+ if(found_extension)
+ if(TARGET ${moc_target})
+ _qt_internal_make_output_file(${it} "" moc outfile)
+ target_sources(${moc_target} PRIVATE "${outfile}")
+ target_include_directories("${moc_target}" PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}")
+ else()
+ if("${moc_target}" STREQUAL "")
+ string(JOIN "" err_msg
+ "qt6_wrap_cpp: TARGET parameter is empty. "
+ "Since the file ${it} is a source file, "
+ "the TARGET option must be specified.")
+ else()
+ string(JOIN "" err_msg
+ "qt6_wrap_cpp: TARGET \"${moc_target}\" "
+ "not found.")
+ endif()
+ message(FATAL_ERROR "${err_msg}")
+ endif()
+ else()
+ string(JOIN "" err_msg "qt6_wrap_cpp: Unknown file extension: "
+ "\"\.${it_ext}\".")
+ message(FATAL_ERROR "${err_msg}")
+ endif()
+ endif()
set(out_json_file_var "")
if(_WRAP_CPP___QT_INTERNAL_OUTPUT_MOC_JSON_FILES)
@@ -200,7 +257,10 @@ function(qt6_wrap_cpp outfiles )
list(APPEND metatypes_json_list "${${out_json_file_var}}")
endif()
endforeach()
- set(${outfiles} ${${outfiles}} PARENT_SCOPE)
+
+ if(is_header_file)
+ set(${outfiles} "${${outfiles}}" PARENT_SCOPE)
+ endif()
if(metatypes_json_list)
set(${_WRAP_CPP___QT_INTERNAL_OUTPUT_MOC_JSON_FILES}
@@ -442,6 +502,9 @@ function(qt6_add_big_resources outfiles )
_qt6_parse_qrc_file(${infile} _out_depends _rc_depends)
set_source_files_properties(${infile} PROPERTIES SKIP_AUTOGEN ON)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.27")
+ set_source_files_properties(${tmpoutfile} PROPERTIES SKIP_LINTING ON)
+ endif()
add_custom_command(OUTPUT ${tmpoutfile}
COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::rcc ${rcc_options} --name ${outfilename} --pass 1 --output ${tmpoutfile} ${infile}
DEPENDS ${infile} ${_rc_depends} "${out_depends}" ${QT_CMAKE_EXPORT_NAMESPACE}::rcc
@@ -554,6 +617,8 @@ set(_Qt6_COMPONENT_PATH "${CMAKE_CURRENT_LIST_DIR}/..")
function(qt6_add_executable target)
cmake_parse_arguments(PARSE_ARGV 1 arg "MANUAL_FINALIZATION" "" "")
+ _qt_internal_warn_about_example_add_subdirectory()
+
_qt_internal_create_executable("${target}" ${arg_UNPARSED_ARGUMENTS})
target_link_libraries("${target}" PRIVATE Qt6::Core)
set_property(TARGET ${target} PROPERTY _qt_expects_finalization TRUE)
@@ -576,6 +641,21 @@ function(qt6_add_executable target)
endif()
endfunction()
+# Just like for qt_add_resources, we should disable zstd compression when cross-compiling to a
+# target that doesn't support zstd decompression, even if the host tool supports it.
+# Allow an opt out via a QT_NO_AUTORCC_ZSTD variable.
+function(_qt_internal_disable_autorcc_zstd_when_not_supported target)
+ if(TARGET "${target}"
+ AND DEFINED QT_FEATURE_zstd
+ AND NOT QT_FEATURE_zstd
+ AND NOT QT_NO_AUTORCC_ZSTD)
+ get_target_property(target_type ${target} TYPE)
+ if(NOT target_type STREQUAL "INTERFACE_LIBRARY")
+ set_property(TARGET "${target}" APPEND PROPERTY AUTORCC_OPTIONS "--no-zstd")
+ endif()
+ endif()
+endfunction()
+
function(_qt_internal_create_executable target)
if(ANDROID)
list(REMOVE_ITEM ARGN "WIN32" "MACOSX_BUNDLE")
@@ -596,6 +676,7 @@ function(_qt_internal_create_executable target)
add_executable("${target}" ${ARGN})
endif()
+ _qt_internal_disable_autorcc_zstd_when_not_supported("${target}")
_qt_internal_set_up_static_runtime_library("${target}")
endfunction()
@@ -649,11 +730,16 @@ function(_qt_internal_finalize_executable target)
if(EMSCRIPTEN)
_qt_internal_wasm_add_target_helpers("${target}")
_qt_internal_add_wasm_extra_exported_methods("${target}")
+ _qt_internal_set_wasm_export_name("${target}")
endif()
- if(IOS)
- _qt_internal_finalize_ios_app("${target}")
- elseif(APPLE)
- _qt_internal_finalize_macos_app("${target}")
+
+ if(APPLE)
+ if(NOT CMAKE_SYSTEM_NAME OR CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ # macOS
+ _qt_internal_finalize_macos_app("${target}")
+ else()
+ _qt_internal_finalize_uikit_app("${target}")
+ endif()
endif()
# For finalizer mode of plugin importing to work safely, we need to know the list of Qt
@@ -731,6 +817,7 @@ function(qt6_finalize_target target)
endif()
_qt_internal_expose_deferred_files_to_ide(${target})
+ _qt_internal_finalize_source_groups(${target})
get_target_property(target_type ${target} TYPE)
get_target_property(is_android_executable "${target}" _qt_is_android_executable)
@@ -738,9 +825,83 @@ function(qt6_finalize_target target)
_qt_internal_finalize_executable(${ARGV})
endif()
+ if(APPLE)
+ # Tell CMake to generate run-scheme for the executable when generating
+ # Xcode projects. This avoids Xcode auto-generating default schemes for
+ # all targets, which includes internal and build-only targets.
+ get_target_property(generate_scheme "${target}" XCODE_GENERATE_SCHEME)
+ if(generate_scheme MATCHES "-NOTFOUND" AND (
+ target_type STREQUAL "EXECUTABLE" OR
+ target_type STREQUAL "SHARED_LIBRARY" OR
+ target_type STREQUAL "STATIC_LIBRARY" OR
+ target_type STREQUAL "MODULE_LIBRARY"))
+ set_property(TARGET "${target}" PROPERTY XCODE_GENERATE_SCHEME TRUE)
+ endif()
+ endif()
+
+ if(target_type STREQUAL "SHARED_LIBRARY" OR
+ target_type STREQUAL "STATIC_LIBRARY" OR
+ target_type STREQUAL "MODULE_LIBRARY" OR
+ target_type STREQUAL "OBJECT_LIBRARY")
+ get_target_property(is_immediately_finalized "${target}" _qt_is_immediately_finalized)
+ get_target_property(uses_automoc ${target} AUTOMOC)
+ if(uses_automoc AND NOT is_immediately_finalized)
+ qt6_extract_metatypes(${target})
+ endif()
+ endif()
+
set_target_properties(${target} PROPERTIES _qt_is_finalized TRUE)
endfunction()
+function(_qt_internal_finalize_source_groups target)
+ if(NOT ("${CMAKE_GENERATOR}" STREQUAL "Xcode"
+ OR "${CMAKE_GENERATOR}" MATCHES "^Visual Studio"))
+ return()
+ endif()
+
+ get_target_property(sources ${target} SOURCES)
+ if(NOT sources)
+ return()
+ endif()
+
+ get_target_property(source_dir ${target} SOURCE_DIR)
+ get_target_property(binary_dir ${target} BINARY_DIR)
+
+ get_property(generated_source_group GLOBAL PROPERTY AUTOGEN_SOURCE_GROUP)
+ if(NOT generated_source_group)
+ set(generated_source_group "Source Files/Generated")
+ endif()
+
+ foreach(source IN LISTS sources)
+ string(GENEX_STRIP "${source}" source)
+
+ if(IS_ABSOLUTE ${source})
+ set(source_file_path "${source}")
+ else()
+ # Resolve absolute path. Can't use LOCATION, as that
+ # will error out if the file doesn't exist :(
+ get_filename_component(source_file_path "${source}"
+ ABSOLUTE BASE_DIR "${source_dir}")
+ if(NOT EXISTS ${source_file_path})
+ # Likely generated file, will end up in build dir
+ get_filename_component(source_file_path "${source}"
+ ABSOLUTE BASE_DIR "${binary_dir}")
+ endif()
+ endif()
+
+ # Include qml files in "Source Files". Can not be done via regex,
+ # due to https://gitlab.kitware.com/cmake/cmake/-/issues/25597
+ if(${source_file_path} MATCHES "\\.qml$")
+ source_group("Source Files" FILES ${source_file_path})
+ endif()
+
+ get_source_file_property(is_generated "${source_file_path}" GENERATED)
+ if(${is_generated})
+ source_group(${generated_source_group} FILES ${source_file_path})
+ endif()
+ endforeach()
+endfunction()
+
function(_qt_internal_darwin_permission_finalizer target)
get_target_property(plist_file "${target}" MACOSX_BUNDLE_INFO_PLIST)
if(NOT plist_file)
@@ -922,6 +1083,150 @@ function(_qt_internal_get_target_autogen_build_dir target out_var)
endif()
endfunction()
+function(_qt_internal_should_install_metatypes target)
+ set(args_option
+ INTERNAL_INSTALL
+ )
+ set(args_single
+ OUT_VAR
+ )
+ set(args_multi
+ )
+
+ cmake_parse_arguments(arg
+ "${args_option}"
+ "${args_single}"
+ "${args_multi}" ${ARGN})
+
+ # Check whether the generated json file needs to be installed.
+ # Executable metatypes.json files should not be installed. Qt non-prefix builds should also
+ # not install the files.
+ set(should_install FALSE)
+
+ get_target_property(target_type ${target} TYPE)
+ if(NOT target_type STREQUAL "EXECUTABLE" AND arg_INTERNAL_INSTALL)
+ set(should_install TRUE)
+ endif()
+ set(${arg_OUT_VAR} "${should_install}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_get_metatypes_install_dir internal_install_dir arch_data_dir out_var)
+ # Automatically fill default install args when not specified.
+ if(NOT internal_install_dir)
+ # INSTALL_ARCHDATADIR is not set when QtBuildInternals is not loaded
+ # (when not doing a Qt build). Default to a hardcoded location for user
+ # projects (will likely be wrong).
+ if(arch_data_dir)
+ set(install_dir "${arch_data_dir}/metatypes")
+ else()
+ set(install_dir "lib/metatypes")
+ endif()
+ else()
+ set(install_dir "${internal_install_dir}")
+ endif()
+ set(${out_var} "${install_dir}" PARENT_SCOPE)
+endfunction()
+
+# Propagates the build time metatypes file via INTERFACE_SOURCES (using $<BUILD_INTERFACE>)
+# and saves the path and file name in properties, so that they can be queryied in the qml api
+# implementation for the purpose of duplicating a qml module backing library's metatypes in its
+# associated plugin. This is required for qmltyperegistrar to get the full set of foreign types
+# when projects link to the plugin and not the backing library.
+function(_qt_internal_assign_build_metatypes_files_and_properties target)
+ get_target_property(existing_meta_types_file ${target} INTERFACE_QT_META_TYPES_BUILD_FILE)
+ if (existing_meta_types_file)
+ return()
+ endif()
+
+ set(args_option
+ )
+ set(args_single
+ METATYPES_FILE_NAME
+ METATYPES_FILE_PATH
+ )
+ set(args_multi
+ )
+
+ cmake_parse_arguments(arg
+ "${args_option}"
+ "${args_single}"
+ "${args_multi}" ${ARGN})
+
+ if(NOT arg_METATYPES_FILE_NAME)
+ message(FATAL_ERROR "METATYPES_FILE_NAME must be specified")
+ endif()
+
+ if(NOT arg_METATYPES_FILE_PATH)
+ message(FATAL_ERROR "METATYPES_FILE_PATH must be specified")
+ endif()
+
+ set(metatypes_file_name "${arg_METATYPES_FILE_NAME}")
+ set(metatypes_file_path "${arg_METATYPES_FILE_PATH}")
+
+ # Set up consumption of files via INTERFACE_SOURCES.
+ set(consumes_metatypes "$<BOOL:$<TARGET_PROPERTY:QT_CONSUMES_METATYPES>>")
+ set(metatypes_file_genex_build
+ "$<BUILD_INTERFACE:$<${consumes_metatypes}:${metatypes_file_path}>>"
+ )
+ target_sources(${target} INTERFACE ${metatypes_file_genex_build})
+
+ set_target_properties(${target} PROPERTIES
+ INTERFACE_QT_MODULE_HAS_META_TYPES YES
+ # The property name is a bit misleading, it's not wrapped in a genex.
+ INTERFACE_QT_META_TYPES_BUILD_FILE "${metatypes_file_path}"
+ INTERFACE_QT_META_TYPES_FILE_NAME "${metatypes_file_name}"
+ )
+endfunction()
+
+# Same as above, but with $<INSTALL_INTERFACE>.
+function(_qt_internal_assign_install_metatypes_files_and_properties target)
+ get_target_property(existing_meta_types_file ${target} INTERFACE_QT_META_TYPES_INSTALL_FILE)
+ if (existing_meta_types_file)
+ return()
+ endif()
+
+ set(args_option
+ )
+ set(args_single
+ INSTALL_DIR
+ )
+ set(args_multi
+ )
+
+ cmake_parse_arguments(arg
+ "${args_option}"
+ "${args_single}"
+ "${args_multi}" ${ARGN})
+
+
+ get_target_property(metatypes_file_name "${target}" INTERFACE_QT_META_TYPES_FILE_NAME)
+
+ if(NOT metatypes_file_name)
+ message(FATAL_ERROR "INTERFACE_QT_META_TYPES_FILE_NAME of target ${target} is empty")
+ endif()
+
+ if(NOT arg_INSTALL_DIR)
+ message(FATAL_ERROR "INSTALL_DIR must be specified")
+ endif()
+
+ # Set up consumption of files via INTERFACE_SOURCES.
+ set(consumes_metatypes "$<BOOL:$<TARGET_PROPERTY:QT_CONSUMES_METATYPES>>")
+
+ set(install_dir "${arg_INSTALL_DIR}")
+
+ set(metatypes_file_install_path "${install_dir}/${metatypes_file_name}")
+ set(metatypes_file_install_path_genex "$<INSTALL_PREFIX>/${metatypes_file_install_path}")
+ set(metatypes_file_genex_install
+ "$<INSTALL_INTERFACE:$<${consumes_metatypes}:${metatypes_file_install_path_genex}>>"
+ )
+ target_sources(${target} INTERFACE ${metatypes_file_genex_install})
+
+ set_target_properties(${target} PROPERTIES
+ INTERFACE_QT_META_TYPES_INSTALL_FILE "${metatypes_file_install_path}"
+ )
+endfunction()
+
+
function(qt6_extract_metatypes target)
get_target_property(existing_meta_types_file ${target} INTERFACE_QT_META_TYPES_BUILD_FILE)
@@ -1002,8 +1307,15 @@ function(qt6_extract_metatypes target)
set (use_dep_files FALSE)
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.17") # Requires automoc changes present only in 3.17
- if(CMAKE_GENERATOR STREQUAL "Ninja" OR CMAKE_GENERATOR STREQUAL "Ninja Multi-Config")
- set(use_dep_files TRUE)
+ if(CMAKE_GENERATOR STREQUAL "Ninja" OR
+ CMAKE_GENERATOR STREQUAL "Ninja Multi-Config" OR
+ (CMAKE_GENERATOR MATCHES "Makefiles" AND
+ CMAKE_VERSION VERSION_GREATER_EQUAL "3.28"))
+ if(DEFINED QT_USE_CMAKE_DEPFILES)
+ set(use_dep_files ${QT_USE_CMAKE_DEPFILES})
+ else()
+ set(use_dep_files TRUE)
+ endif()
endif()
endif()
@@ -1054,9 +1366,18 @@ function(qt6_extract_metatypes target)
add_dependencies(${target}_automoc_json_extraction ${target}_autogen)
_qt_internal_assign_to_internal_targets_folder(${target}_automoc_json_extraction)
else()
- set(cmake_autogen_timestamp_file
- "${target_autogen_build_dir}/timestamp"
- )
+ set(timestamp_file "${target_autogen_build_dir}/timestamp")
+ set(timestamp_file_with_config "${timestamp_file}_$<CONFIG>")
+ if (is_multi_config AND CMAKE_VERSION VERSION_GREATER_EQUAL "3.29"
+ AND NOT QT_INTERNAL_USE_OLD_AUTOGEN_GRAPH_MULTI_CONFIG_METATYPES)
+ string(JOIN "" timestamp_genex
+ "$<IF:$<BOOL:$<TARGET_PROPERTY:${target},"
+ "AUTOGEN_BETTER_GRAPH_MULTI_CONFIG>>,"
+ "${timestamp_file_with_config},${timestamp_file}>")
+ set(cmake_autogen_timestamp_file "${timestamp_genex}")
+ else()
+ set(cmake_autogen_timestamp_file ${timestamp_file})
+ endif()
add_custom_command(OUTPUT ${type_list_file}
DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::cmake_automoc_parser
@@ -1124,6 +1445,7 @@ function(qt6_extract_metatypes target)
add_custom_command(
OUTPUT
${metatypes_file_gen}
+ BYPRODUCTS
${metatypes_file}
DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::moc ${automoc_dependencies} ${manual_dependencies}
COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::moc
@@ -1136,6 +1458,17 @@ function(qt6_extract_metatypes target)
VERBATIM
)
+ if(CMAKE_GENERATOR MATCHES " Makefiles")
+ # Work around https://gitlab.kitware.com/cmake/cmake/-/issues/19005 to trigger the command
+ # that generates ${metatypes_file}.
+ add_custom_command(
+ OUTPUT ${metatypes_file}
+ DEPENDS ${metatypes_file_gen}
+ COMMAND ${CMAKE_COMMAND} -E true
+ VERBATIM
+ )
+ endif()
+
# We can't rely on policy CMP0118 since user project controls it
set(scope_args)
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
@@ -1155,52 +1488,42 @@ function(qt6_extract_metatypes target)
PROPERTIES HEADER_FILE_ONLY TRUE
)
- set_target_properties(${target} PROPERTIES
- INTERFACE_QT_MODULE_HAS_META_TYPES YES
- INTERFACE_QT_META_TYPES_BUILD_FILE "${metatypes_file}"
- )
-
- # Set up consumption of files via INTERFACE_SOURCES.
- set(consumes_metatypes "$<BOOL:$<TARGET_PROPERTY:QT_CONSUMES_METATYPES>>")
- set(metatypes_file_genex_build
- "$<BUILD_INTERFACE:$<${consumes_metatypes}:${metatypes_file}>>"
- )
- target_sources(${target} INTERFACE ${metatypes_file_genex_build})
-
if(arg_OUTPUT_FILES)
set(${arg_OUTPUT_FILES} "${metatypes_file}" PARENT_SCOPE)
endif()
- # Check whether the generated json file needs to be installed.
- # Executable metatypes.json files should not be installed. Qt non-prefix builds should also
- # not install the files.
- set(should_install FALSE)
-
- if(NOT target_type STREQUAL "EXECUTABLE" AND arg___QT_INTERNAL_INSTALL)
- set(should_install TRUE)
- endif()
+ # Propagate the build time metatypes file.
+ _qt_internal_assign_build_metatypes_files_and_properties(
+ "${target}"
+ METATYPES_FILE_NAME "${metatypes_file_name}"
+ METATYPES_FILE_PATH "${metatypes_file}"
+ )
- # Automatically fill default install args when not specified.
- if(NOT arg___QT_INTERNAL_INSTALL_DIR)
- # INSTALL_ARCHDATADIR is not set when QtBuildInternals is not loaded
- # (when not doing a Qt build). Default to a hardcoded location for user
- # projects (will likely be wrong).
- if(INSTALL_ARCHDATADIR)
- set(install_dir "${INSTALL_ARCHDATADIR}/metatypes")
- else()
- set(install_dir "lib/metatypes")
- endif()
+ if(arg___QT_INTERNAL_INSTALL)
+ set(internal_install_option "INTERNAL_INSTALL")
else()
- set(install_dir "${arg___QT_INTERNAL_INSTALL_DIR}")
+ set(internal_install_option "")
endif()
+ # TODO: Clean up Qt-specific installation not to happen in the public api.
+ # Check whether the metatype files should be installed.
+ _qt_internal_should_install_metatypes("${target}"
+ ${internal_install_option}
+ OUT_VAR should_install
+ )
+
if(should_install)
- set(metatypes_file_install_path "${install_dir}/${metatypes_file_name}")
- set(metatypes_file_install_path_genex "$<INSTALL_PREFIX>/${metatypes_file_install_path}")
- set(metatypes_file_genex_install
- "$<INSTALL_INTERFACE:$<${consumes_metatypes}:${metatypes_file_install_path_genex}>>"
+ _qt_internal_get_metatypes_install_dir(
+ "${arg___QT_INTERNAL_INSTALL_DIR}"
+ "${INSTALL_ARCHDATADIR}"
+ install_dir
+ )
+
+ # Propagate the install time metatypes file.
+ _qt_internal_assign_install_metatypes_files_and_properties(
+ "${target}"
+ INSTALL_DIR "${install_dir}"
)
- target_sources(${target} INTERFACE ${metatypes_file_genex_install})
install(FILES "${metatypes_file}" DESTINATION "${install_dir}")
endif()
endfunction()
@@ -1692,11 +2015,29 @@ function(__qt_propagate_generated_resource target resource_name generated_source
math(EXPR resource_count "${resource_count} + 1")
set_target_properties(${target} PROPERTIES _qt_generated_resource_target_count ${resource_count})
+ __qt_internal_generate_init_resource_source_file(
+ resource_init_file ${target} ${resource_name})
+
set(resource_target "${target}_resources_${resource_count}")
- add_library("${resource_target}" OBJECT "${generated_source_code}")
+ add_library("${resource_target}" OBJECT "${resource_init_file}")
+ set_target_properties(${resource_target} PROPERTIES
+ AUTOMOC FALSE
+ AUTOUIC FALSE
+ AUTORCC FALSE
+ )
+ # Needed so that qtsymbolmacros.h and its dependent headers are already created / syncqt'ed.
+ if(TARGET Core_sync_headers)
+ set(headers_available_target "Core_sync_headers")
+ else()
+ set(headers_available_target "${QT_CMAKE_EXPORT_NAMESPACE}::Core")
+ endif()
+ add_dependencies(${resource_target} ${headers_available_target})
target_compile_definitions("${resource_target}" PRIVATE
"$<TARGET_PROPERTY:${QT_CMAKE_EXPORT_NAMESPACE}::Core,INTERFACE_COMPILE_DEFINITIONS>"
)
+ target_include_directories("${resource_target}" PRIVATE
+ "$<TARGET_PROPERTY:${QT_CMAKE_EXPORT_NAMESPACE}::Core,INTERFACE_INCLUDE_DIRECTORIES>"
+ )
_qt_internal_set_up_static_runtime_library("${resource_target}")
# Special handling is required for the Core library resources. The linking of the Core
@@ -1715,7 +2056,7 @@ function(__qt_propagate_generated_resource target resource_name generated_source
# .rcc/qrc_qprintdialog.cpp
file(RELATIVE_PATH generated_cpp_file_relative_path
"${CMAKE_CURRENT_BINARY_DIR}"
- "${generated_source_code}")
+ "${resource_init_file}")
set_property(TARGET ${resource_target} APPEND PROPERTY
_qt_resource_generated_cpp_relative_path "${generated_cpp_file_relative_path}")
@@ -1729,8 +2070,39 @@ function(__qt_propagate_generated_resource target resource_name generated_source
set(${output_generated_target} "${resource_target}" PARENT_SCOPE)
else()
set(${output_generated_target} "" PARENT_SCOPE)
- target_sources(${target} PRIVATE ${generated_source_code})
endif()
+
+ target_sources(${target} PRIVATE ${generated_source_code})
+endfunction()
+
+function(__qt_internal_sanitize_resource_name out_var name)
+ # The sanitized output should match RCCResourceLibrary::writeInitializer()'s
+ # isAsciiLetterOrNumber-based substituion.
+ # MAKE_C_IDENTIFIER matches that, it replaces non-alphanumeric chars with underscores.
+ string(MAKE_C_IDENTIFIER "${name}" sanitized_resource_name)
+ set(${out_var} "${sanitized_resource_name}" PARENT_SCOPE)
+endfunction()
+
+function(__qt_internal_generate_init_resource_source_file out_var target resource_name)
+ set(template_file "${__qt_core_macros_module_base_dir}/Qt6CoreResourceInit.in.cpp")
+
+ # Gets replaced in the template
+ __qt_internal_sanitize_resource_name(RESOURCE_NAME "${resource_name}")
+ set(resource_init_path "${CMAKE_CURRENT_BINARY_DIR}/.qt/rcc/qrc_${resource_name}_init.cpp")
+
+ configure_file("${template_file}" "${resource_init_path}" @ONLY)
+
+ set(scope_args "")
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set(scope_args TARGET_DIRECTORY ${target})
+ endif()
+ set_source_files_properties(${resource_init_path} ${scope_args} PROPERTIES
+ SKIP_AUTOGEN TRUE
+ SKIP_UNITY_BUILD_INCLUSION TRUE
+ SKIP_PRECOMPILE_HEADERS TRUE
+ )
+
+ set(${out_var} "${resource_init_path}" PARENT_SCOPE)
endfunction()
# Make file visible in IDEs.
@@ -1910,8 +2282,9 @@ function(_qt_internal_process_resource target resourceName)
endif()
return()
endif()
- set(generatedResourceFile "${CMAKE_CURRENT_BINARY_DIR}/.rcc/${resourceName}.qrc")
+ set(generatedResourceFile "${CMAKE_CURRENT_BINARY_DIR}/.qt/rcc/${resourceName}.qrc")
_qt_internal_expose_source_file_to_ide(${target} ${generatedResourceFile})
+ set_source_files_properties(${generatedResourceFile} PROPERTIES GENERATED TRUE)
# Generate .qrc file:
@@ -2006,9 +2379,9 @@ function(_qt_internal_process_resource target resourceName)
endif()
endif()
elseif(rcc_BIG_RESOURCES)
- set(generatedOutfile "${CMAKE_CURRENT_BINARY_DIR}/.rcc/qrc_${resourceName}_tmp.cpp")
+ set(generatedOutfile "${CMAKE_CURRENT_BINARY_DIR}/.qt/rcc/qrc_${resourceName}_tmp.cpp")
else()
- set(generatedOutfile "${CMAKE_CURRENT_BINARY_DIR}/.rcc/qrc_${resourceName}.cpp")
+ set(generatedOutfile "${CMAKE_CURRENT_BINARY_DIR}/.qt/rcc/qrc_${resourceName}.cpp")
endif()
set(pass_msg)
@@ -2047,6 +2420,9 @@ function(_qt_internal_process_resource target resourceName)
SKIP_UNITY_BUILD_INCLUSION TRUE
SKIP_PRECOMPILE_HEADERS TRUE
)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.27")
+ set_source_files_properties(${generatedOutfile} ${scope_args} PROPERTIES SKIP_LINTING ON)
+ endif()
get_target_property(target_source_dir ${target} SOURCE_DIR)
if(NOT target_source_dir STREQUAL CMAKE_CURRENT_SOURCE_DIR)
@@ -2060,7 +2436,7 @@ function(_qt_internal_process_resource target resourceName)
if(rcc_BIG_RESOURCES)
set(pass1OutputFile ${generatedOutfile})
set(generatedOutfile
- "${CMAKE_CURRENT_BINARY_DIR}/.rcc/qrc_${resourceName}${CMAKE_CXX_OUTPUT_EXTENSION}")
+ "${CMAKE_CURRENT_BINARY_DIR}/.qt/rcc/qrc_${resourceName}${CMAKE_CXX_OUTPUT_EXTENSION}")
_qt_internal_add_rcc_pass2(
RESOURCE_NAME ${resourceName}
RCC_OPTIONS ${rccArgsAllPasses}
@@ -2323,14 +2699,36 @@ function(_qt_internal_add_library target)
# This in contrast to CMake which defaults to STATIC.
if(NOT arg_STATIC AND NOT arg_SHARED AND NOT arg_MODULE AND NOT arg_INTERFACE
AND NOT arg_OBJECT)
- if(QT6_IS_SHARED_LIBS_BUILD)
- set(type_to_create SHARED)
+ if(DEFINED BUILD_SHARED_LIBS AND NOT QT_BUILDING_QT AND NOT QT_BUILD_STANDALONE_TESTS)
+ __qt_internal_setup_policy(QTP0003 "6.7.0"
+ "BUILD_SHARED_LIBS is set to ${BUILD_SHARED_LIBS} but it has no effect on\
+ default library type created by Qt CMake API commands. The default library type\
+ is set to the Qt build type.\
+ This behavior can be changed by setting QTP0003 to NEW.\
+ Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0003.html for policy details."
+ )
+ qt6_policy(GET QTP0003 build_shared_libs_policy)
else()
- set(type_to_create STATIC)
+ set(build_shared_libs_policy "")
+ endif()
+
+ if(build_shared_libs_policy STREQUAL "NEW" OR QT_BUILDING_QT OR QT_BUILD_STANDALONE_TESTS)
+ if(BUILD_SHARED_LIBS OR (NOT DEFINED BUILD_SHARED_LIBS AND QT6_IS_SHARED_LIBS_BUILD))
+ set(type_to_create SHARED)
+ else()
+ set(type_to_create STATIC)
+ endif()
+ else()
+ if(QT6_IS_SHARED_LIBS_BUILD)
+ set(type_to_create SHARED)
+ else()
+ set(type_to_create STATIC)
+ endif()
endif()
endif()
add_library(${target} ${type_to_create} ${arg_UNPARSED_ARGUMENTS})
+ _qt_internal_disable_autorcc_zstd_when_not_supported("${target}")
_qt_internal_set_up_static_runtime_library(${target})
if(NOT type_to_create STREQUAL "INTERFACE" AND NOT type_to_create STREQUAL "OBJECT")
@@ -2531,6 +2929,22 @@ function(_qt_internal_setup_deploy_support)
set(target ${aliased_target})
endif()
+ # Generate deployment information for each target if the CMake version is recent enough.
+ # The call is deferred to have all targets of the projects available.
+ if(CMAKE_VERSION GREATER_EQUAL "3.19.0")
+ if(is_multi_config)
+ set(targets_file "${deploy_impl_dir}/QtDeployTargets-$<CONFIG>.cmake")
+ else()
+ set(targets_file "${deploy_impl_dir}/QtDeployTargets.cmake")
+ endif()
+ cmake_language(EVAL CODE
+ "cmake_language(DEFER
+ DIRECTORY [[${CMAKE_SOURCE_DIR}]]
+ CALL _qt_internal_write_target_deploy_info [[${targets_file}]])"
+ )
+ _qt_internal_add_deploy_support("${targets_file}")
+ endif()
+
# Make sure to look under the Qt bin dir with find_program, rather than randomly picking up
# a deployqt tool in the system.
# QT6_INSTALL_PREFIX is not set during Qt build, so add the hints conditionally.
@@ -2569,6 +2983,18 @@ function(_qt_internal_setup_deploy_support)
set(__QT_DEPLOY_TOOL "")
endif()
+ # Determine whether this is a multi-config build with a Debug configuration.
+ set(is_multi_config_build_with_debug_config FALSE)
+ get_target_property(target_is_imported ${target} IMPORTED)
+ if(target_is_imported)
+ get_target_property(target_imported_configs ${target} IMPORTED_CONFIGURATIONS)
+ list(LENGTH target_imported_configs target_imported_configs_length)
+ if(target_imported_configs_length GREATER "1"
+ AND "DEBUG" IN_LIST target_imported_configs)
+ set(is_multi_config_build_with_debug_config TRUE)
+ endif()
+ endif()
+
_qt_internal_add_deploy_support("${CMAKE_CURRENT_LIST_DIR}/Qt6CoreDeploySupport.cmake")
set(deploy_ignored_lib_dirs "")
@@ -2616,6 +3042,43 @@ function(_qt_internal_setup_deploy_support)
endif()
endif()
+ # Generate path to the target (not host) qtpaths file. Needed for windeployqt when
+ # cross-compiling from an x86_64 host to an arm64 target, so it knows which architecture
+ # libraries should be deployed.
+ if(CMAKE_HOST_WIN32)
+ if(CMAKE_CROSSCOMPILING)
+ set(qt_paths_ext ".bat")
+ else()
+ set(qt_paths_ext ".exe")
+ endif()
+ else()
+ set(qt_paths_ext "")
+ endif()
+
+
+
+ set(target_qtpaths_path "")
+ set(qtpaths_prefix "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_BINS}")
+ get_property(qt_major_version TARGET "${target}" PROPERTY INTERFACE_QT_MAJOR_VERSION)
+ if(qt_major_version)
+ set(target_qtpaths_with_major_version_path
+ "${qtpaths_prefix}/qtpaths${qt_major_version}${qt_paths_ext}")
+ if(EXISTS "${target_qtpaths_with_major_version_path}")
+ set(target_qtpaths_path "${target_qtpaths_with_major_version_path}")
+ endif()
+ endif()
+
+ if(NOT target_qtpaths_path)
+ set(target_qtpaths_path_without_version "${qtpaths_prefix}/qtpaths${qt_paths_ext}")
+ if(EXISTS "${target_qtpaths_path_without_version}")
+ set(target_qtpaths_path "${target_qtpaths_path_without_version}")
+ endif()
+ endif()
+
+ if(NOT target_qtpaths_path)
+ message(DEBUG "No qtpaths executable found for deployment purposes.")
+ endif()
+
file(GENERATE OUTPUT "${QT_DEPLOY_SUPPORT}" CONTENT
"cmake_minimum_required(VERSION 3.16...3.21)
@@ -2624,6 +3087,9 @@ function(_qt_internal_setup_deploy_support)
if(NOT QT_DEPLOY_BIN_DIR)
set(QT_DEPLOY_BIN_DIR \"${CMAKE_INSTALL_BINDIR}\")
endif()
+if(NOT QT_DEPLOY_LIBEXEC_DIR)
+ set(QT_DEPLOY_LIBEXEC_DIR \"${CMAKE_INSTALL_LIBEXECDIR}\")
+endif()
if(NOT QT_DEPLOY_LIB_DIR)
set(QT_DEPLOY_LIB_DIR \"${CMAKE_INSTALL_LIBDIR}\")
endif()
@@ -2660,16 +3126,21 @@ set(__QT_DEFAULT_MAJOR_VERSION \"${QT_DEFAULT_MAJOR_VERSION}\")
set(__QT_DEPLOY_QT_ADDITIONAL_PACKAGES_PREFIX_PATH \"${QT_ADDITIONAL_PACKAGES_PREFIX_PATH}\")
set(__QT_DEPLOY_QT_INSTALL_PREFIX \"${QT6_INSTALL_PREFIX}\")
set(__QT_DEPLOY_QT_INSTALL_BINS \"${QT6_INSTALL_BINS}\")
+set(__QT_DEPLOY_QT_INSTALL_DATA \"${QT6_INSTALL_DATA}\")
+set(__QT_DEPLOY_QT_INSTALL_LIBEXECS \"${QT6_INSTALL_LIBEXECS}\")
set(__QT_DEPLOY_QT_INSTALL_PLUGINS \"${QT6_INSTALL_PLUGINS}\")
set(__QT_DEPLOY_QT_INSTALL_TRANSLATIONS \"${QT6_INSTALL_TRANSLATIONS}\")
+set(__QT_DEPLOY_TARGET_QT_PATHS_PATH \"${target_qtpaths_path}\")
set(__QT_DEPLOY_PLUGINS \"\")
set(__QT_DEPLOY_MUST_ADJUST_PLUGINS_RPATH \"${must_adjust_plugins_rpath}\")
set(__QT_DEPLOY_USE_PATCHELF \"${QT_DEPLOY_USE_PATCHELF}\")
set(__QT_DEPLOY_PATCHELF_EXECUTABLE \"${QT_DEPLOY_PATCHELF_EXECUTABLE}\")
+set(__QT_DEPLOY_QT_IS_MULTI_CONFIG_BUILD_WITH_DEBUG \"${is_multi_config_build_with_debug_config}\")
+set(__QT_DEPLOY_QT_DEBUG_POSTFIX \"${QT6_DEBUG_POSTFIX}\")
# Define the CMake commands to be made available during deployment.
set(__qt_deploy_support_files
- \"$<JOIN:$<TARGET_PROPERTY:${target},_qt_deploy_support_files>,\"
+ \"$<JOIN:$<TARGET_GENEX_EVAL:${target},$<TARGET_PROPERTY:${target},_qt_deploy_support_files>>,\"
\">\"
)
foreach(__qt_deploy_support_file IN LISTS __qt_deploy_support_files)
@@ -2681,6 +3152,138 @@ unset(__qt_deploy_support_files)
")
endfunction()
+# Write deployment information for the targets of the project.
+function(_qt_internal_write_target_deploy_info out_file)
+ set(targets "")
+ _qt_internal_collect_buildsystem_targets(targets
+ "${CMAKE_SOURCE_DIR}" INCLUDE EXECUTABLE SHARED_LIBRARY MODULE_LIBRARY)
+ set(content "")
+ foreach(target IN LISTS targets)
+ set(var_prefix "__QT_DEPLOY_TARGET_${target}")
+ string(APPEND content "set(${var_prefix}_FILE $<TARGET_FILE:${target}>)\n")
+ if(WIN32 AND CMAKE_VERSION GREATER_EQUAL "3.21")
+ string(APPEND content
+ "set(${var_prefix}_RUNTIME_DLLS $<TARGET_RUNTIME_DLLS:${target}>)\n")
+ endif()
+ endforeach()
+ file(GENERATE OUTPUT "${out_file}" CONTENT "${content}")
+endfunction()
+
+function(_qt_internal_is_examples_deployment_supported_in_current_config out_var out_var_reason)
+ # Deployment API doesn't work when examples / tests are built in-tree of a prefix qt build.
+ if(QT_BUILDING_QT AND QT_WILL_INSTALL AND NOT QT_INTERNAL_BUILD_STANDALONE_PARTS)
+ set(deployment_supported FALSE)
+ set(not_supported_reason "PREFIX_BUILD")
+ else()
+ set(deployment_supported TRUE)
+ set(not_supported_reason "")
+ endif()
+
+ set(${out_var} "${deployment_supported}" PARENT_SCOPE)
+ set(${out_var_reason} "${not_supported_reason}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_should_skip_deployment_api out_var out_var_reason)
+ set(skip_deployment FALSE)
+ _qt_internal_is_examples_deployment_supported_in_current_config(
+ deployment_supported
+ not_supported_reason
+ )
+
+ # Allow opting out of deployment, so that we can add deployment api to all our examples,
+ # but only run it in the CI for a select few, to avoid the overhead of deploying all examples.
+ if(QT_INTERNAL_SKIP_DEPLOYMENT OR (NOT deployment_supported))
+ set(skip_deployment TRUE)
+ endif()
+
+ set(reason "")
+ if(NOT deployment_supported)
+ set(reason "${not_supported_reason}")
+ elseif(QT_INTERNAL_SKIP_DEPLOYMENT)
+ set(reason "SKIP_REQUESTED")
+ endif()
+
+ set(${out_var} "${skip_deployment}" PARENT_SCOPE)
+ set(${out_var_reason} "${reason}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_should_skip_post_build_deployment_api out_var out_var_reason)
+ set(skip_deployment FALSE)
+ set(deployment_supported TRUE)
+
+ # Allow opting out of deployment, so that we can add deployment api to all our examples,
+ # but only run it in the CI for a select few, to avoid the overhead of deploying all examples.
+ if(QT_INTERNAL_SKIP_DEPLOYMENT OR (NOT deployment_supported))
+ set(skip_deployment TRUE)
+ endif()
+
+ set(reason "")
+ if(NOT deployment_supported)
+ set(reason "REASON_UNSPECIFIED")
+ elseif(QT_INTERNAL_SKIP_DEPLOYMENT)
+ set(reason "SKIP_REQUESTED")
+ endif()
+
+ set(${out_var} "${skip_deployment}" PARENT_SCOPE)
+ set(${out_var_reason} "${reason}" PARENT_SCOPE)
+endfunction()
+
+# Generate a deploy script that does nothing aside from showing a warning message.
+# The warning can be hidden by setting the QT_INTERNAL_HIDE_NO_OP_DEPLOYMENT_WARNING variable.
+function(_qt_internal_generate_no_op_deploy_script)
+ set(no_value_options
+ )
+ set(single_value_options
+ FUNCTION_NAME
+ NAME
+ OUTPUT_SCRIPT
+ SKIP_REASON
+ TARGET
+ )
+ set(multi_value_options
+ )
+
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "${no_value_options}" "${single_value_options}" "${multi_value_options}"
+ )
+
+ if(NOT arg_OUTPUT_SCRIPT)
+ message(FATAL_ERROR "No OUTPUT_SCRIPT option specified")
+ endif()
+ if(NOT arg_FUNCTION_NAME)
+ message(FATAL_ERROR "No FUNCTION_NAME option specified")
+ endif()
+
+ set(generate_args "")
+ if(arg_NAME)
+ list(APPEND generate_args NAME "${arg_NAME}")
+ endif()
+ if(arg_TARGET)
+ list(APPEND generate_args TARGET "${arg_TARGET}")
+ endif()
+
+ set(function_name "${arg_FUNCTION_NAME}")
+
+ # The empty space is required, otherwise
+ set(content "
+message(DEBUG \"Running no-op deployment script because QT_INTERNAL_SKIP_DEPLOYMENT was ON.\")
+")
+ if(NOT QT_INTERNAL_HIDE_NO_OP_DEPLOYMENT_WARNING AND arg_SKIP_REASON STREQUAL "PREFIX_BUILD")
+ set(content "
+message(STATUS \"${function_name}(TARGET ${arg_TARGET}) is a no-op for prefix \"
+\"non-standalone builds due to various issues. Consider using a -no-prefix build \"
+\"or qt-internal-configure-tests or qt-internal-configure-examples if you want deployment to run.\")
+")
+ endif()
+
+ qt6_generate_deploy_script(
+ ${generate_args}
+ OUTPUT_SCRIPT deploy_script
+ CONTENT "${content}")
+
+ set("${arg_OUTPUT_SCRIPT}" "${deploy_script}" PARENT_SCOPE)
+endfunction()
+
# We basically mirror CMake's policy setup
# A policy can be set to OLD, set to NEW or unset
# unset is the default state
@@ -2749,8 +3352,13 @@ macro(qt6_standard_project_setup)
set(__qt_sps_args_single
REQUIRES
SUPPORTS_UP_TO
+ I18N_SOURCE_LANGUAGE
+ I18N_NATIVE_LANGUAGE # intermediate, remove after dependencies trickled through
+ )
+ set(__qt_sps_args_multi
+ I18N_TRANSLATED_LANGUAGES
+ I18N_LANGUAGES # intermediate, remove after dependencies trickled through
)
- set(__qt_sps_args_multi)
cmake_parse_arguments(__qt_sps_arg
"${__qt_sps_args_option}"
"${__qt_sps_args_single}"
@@ -2758,6 +3366,14 @@ macro(qt6_standard_project_setup)
${ARGN}
)
+ # intermediate, remove after dependencies trickled through
+ if(DEFINED arg_I18N_NATIVE_LANGUAGE)
+ set(arg_I18N_SOURCE_LANGUAGE ${arg_I18N_NATIVE_LANGUAGE})
+ endif()
+ if(DEFINED arg_I18N_LANGUAGES)
+ set(arg_I18N_TRANSLATED_LANGUAGES ${arg_I18N_LANGUAGES})
+ endif()
+
if(__qt_sps_arg_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unexpected arguments: ${arg_UNPARSED_ARGUMENTS}")
endif()
@@ -2834,8 +3450,8 @@ macro(qt6_standard_project_setup)
endif()
endforeach()
- # Enable folder support for IDEs. A future CMake version might enable this by default.
- # See CMake issue #21695.
+ # Enable folder support for IDEs. CMake >= 3.26 enables USE_FOLDERS by default but this is
+ # guarded by CMake policy CMP0143.
get_property(__qt_use_folders GLOBAL PROPERTY USE_FOLDERS)
if(__qt_use_folders OR "${__qt_use_folders}" STREQUAL "")
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
@@ -2844,11 +3460,50 @@ macro(qt6_standard_project_setup)
set(__qt_qt_targets_folder QtInternalTargets)
set_property(GLOBAL PROPERTY QT_TARGETS_FOLDER ${__qt_qt_targets_folder})
endif()
- get_property(__qt_autogen_targets_folder GLOBAL PROPERTY AUTOGEN_TARGETS_FOLDERS)
+ get_property(__qt_autogen_targets_folder GLOBAL PROPERTY AUTOGEN_TARGETS_FOLDER)
if("${__qt_autogen_targets_folder}" STREQUAL "")
set_property(GLOBAL PROPERTY AUTOGEN_TARGETS_FOLDER ${__qt_qt_targets_folder})
endif()
endif()
+
+ # Hide generated files in dedicated folder. Unfortunately we can't use a
+ # top level "Generated Files" folder for this, as CMake will then put the
+ # folder first in the list of folders, whereas we want to keep Sources and
+ # Headers front and center. See also _qt_internal_finalize_source_groups
+ set_property(GLOBAL PROPERTY AUTOGEN_SOURCE_GROUP "Source Files/Generated")
+
+ # Treat metatypes JSON files as generated. We propagate these INTERFACE_SOURCES,
+ # due to CMake's lack of a generic mechanism for property inheritance (see
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/20416), but we don't want
+ # them to clutter up the user's project.
+ source_group("Source Files/Generated" REGULAR_EXPRESSION "(_metatypes\\.json)$")
+
+ # I18N support.
+ if(DEFINED __qt_sps_arg_I18N_TRANSLATED_LANGUAGES
+ AND NOT DEFINED QT_I18N_TRANSLATED_LANGUAGES)
+ set(QT_I18N_TRANSLATED_LANGUAGES ${__qt_sps_arg_I18N_TRANSLATED_LANGUAGES})
+ endif()
+ if(NOT DEFINED __qt_sps_arg_I18N_SOURCE_LANGUAGE)
+ set(__qt_sps_arg_I18N_SOURCE_LANGUAGE en)
+ endif()
+ if(NOT DEFINED QT_I18N_SOURCE_LANGUAGE)
+ set(QT_I18N_SOURCE_LANGUAGE ${__qt_sps_arg_I18N_SOURCE_LANGUAGE})
+ endif()
+
+ if(CMAKE_GENERATOR STREQUAL "Xcode")
+ # Ensure we always use device SDK for Xcode for single-arch Qt builds
+ set(qt_osx_arch_count 0)
+ if(QT_OSX_ARCHITECTURES)
+ list(LENGTH QT_OSX_ARCHITECTURES qt_osx_arch_count)
+ endif()
+ if(NOT qt_osx_arch_count GREATER 1 AND ${CMAKE_OSX_SYSROOT} MATCHES "^[a-z]+simulator$")
+ # Xcode expects the base SDK to be the device SDK
+ set(simulator_sysroot "${CMAKE_OSX_SYSROOT}")
+ string(REGEX REPLACE "simulator" "os" CMAKE_OSX_SYSROOT "${CMAKE_OSX_SYSROOT}")
+ set(CMAKE_OSX_SYSROOT "${CMAKE_OSX_SYSROOT}" CACHE STRING "" FORCE)
+ set(CMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS "${simulator_sysroot}")
+ endif()
+ endif()
endif()
endmacro()
@@ -2861,6 +3516,40 @@ if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
endmacro()
endif()
+# Store in ${out_var} the i18n catalogs that belong to the passed Qt modules.
+# The catalog "qtbase" is always added to the result.
+#
+# Example:
+# _qt_internal_get_i18n_catalogs_for_modules(catalogs Quick Help)
+# catalogs -> qtbase;qtdeclarative;qt_help
+function(_qt_internal_get_i18n_catalogs_for_modules out_var)
+ set(result "qtbase")
+ set(modules "${ARGN}")
+ set(module_catalog_mapping
+ "Bluetooth|Nfc" qtconnectivity
+ "Help" qt_help
+ "Multimedia(Widgets|QuickPrivate)?" qtmultimedia
+ "Qml|Quick" qtdeclarative
+ "SerialPort" qtserialport
+ "WebEngine" qtwebengine
+ "WebSockets" qtwebsockets
+ )
+ list(LENGTH module_catalog_mapping max_i)
+ math(EXPR max_i "${max_i} - 1")
+ foreach(module IN LISTS modules)
+ foreach(i RANGE 0 ${max_i} 2)
+ list(GET module_catalog_mapping ${i} module_rex)
+ if(NOT module MATCHES "^(${module_rex})")
+ continue()
+ endif()
+ math(EXPR k "${i} + 1")
+ list(GET module_catalog_mapping ${k} catalog)
+ list(APPEND result ${catalog})
+ endforeach()
+ endforeach()
+ set("${out_var}" "${result}" PARENT_SCOPE)
+endfunction()
+
function(qt6_generate_deploy_script)
set(no_value_options "")
set(single_value_options
@@ -2950,9 +3639,10 @@ function(qt6_generate_deploy_script)
string(APPEND deploy_script "${config_infix}.cmake")
set(${arg_OUTPUT_SCRIPT} "${deploy_script}" PARENT_SCOPE)
+ _qt_internal_get_i18n_catalogs_for_modules(catalogs ${QT_ALL_MODULES_FOUND_VIA_FIND_PACKAGE})
set(boiler_plate "include(${QT_DEPLOY_SUPPORT})
include(\"\${CMAKE_CURRENT_LIST_DIR}/${arg_TARGET}-plugins${config_infix}.cmake\" OPTIONAL)
-set(__QT_DEPLOY_ALL_MODULES_FOUND_VIA_FIND_PACKAGE \"${QT_ALL_MODULES_FOUND_VIA_FIND_PACKAGE}\")
+set(__QT_DEPLOY_I18N_CATALOGS \"${catalogs}\")
")
list(TRANSFORM arg_CONTENT REPLACE "\\$" "\$")
file(GENERATE OUTPUT ${deploy_script} CONTENT "${boiler_plate}${arg_CONTENT}")
@@ -2990,6 +3680,7 @@ function(qt6_generate_deploy_app_script)
)
set(qt_deploy_runtime_dependencies_options
# These options are forwarded as is to qt_deploy_runtime_dependencies.
+ DEPLOY_TOOL_OPTIONS
PRE_INCLUDE_REGEXES
PRE_EXCLUDE_REGEXES
POST_INCLUDE_REGEXES
@@ -3029,12 +3720,25 @@ function(qt6_generate_deploy_app_script)
message(FATAL_ERROR "OUTPUT_SCRIPT must be specified")
endif()
+ get_target_property(is_bundle ${arg_TARGET} MACOSX_BUNDLE)
+
+ set(unsupported_platform_extra_message "")
if(QT6_IS_SHARED_LIBS_BUILD)
set(qt_build_type_string "shared Qt libs")
else()
set(qt_build_type_string "static Qt libs")
endif()
+ if(CMAKE_CROSSCOMPILING)
+ string(APPEND qt_build_type_string ", cross-compiled")
+ endif()
+
+ if(NOT is_bundle)
+ string(APPEND qt_build_type_string ", non-bundle app")
+ set(unsupported_platform_extra_message
+ "Executable targets have to be app bundles to use this command on Apple platforms.")
+ endif()
+
set(generate_args
TARGET ${arg_TARGET}
OUTPUT_SCRIPT deploy_script
@@ -3055,15 +3759,16 @@ function(qt6_generate_deploy_app_script)
endif()
endforeach()
- if(APPLE AND NOT IOS AND QT6_IS_SHARED_LIBS_BUILD)
- # TODO: Handle non-bundle applications if possible.
- get_target_property(is_bundle ${arg_TARGET} MACOSX_BUNDLE)
- if(NOT is_bundle)
- message(FATAL_ERROR
- "Executable targets have to be app bundles to use this command "
- "on Apple platforms."
- )
- endif()
+ _qt_internal_should_skip_deployment_api(skip_deployment skip_reason)
+ if(skip_deployment)
+ _qt_internal_generate_no_op_deploy_script(
+ FUNCTION_NAME "qt6_generate_deploy_app_script"
+ SKIP_REASON "${skip_reason}"
+ ${generate_args}
+ )
+ elseif(APPLE AND NOT IOS AND QT6_IS_SHARED_LIBS_BUILD AND is_bundle)
+ # TODO: Consider handling non-bundle applications in the future using the generic cmake
+ # runtime dependency feature.
qt6_generate_deploy_script(${generate_args}
CONTENT "
qt6_deploy_runtime_dependencies(
@@ -3080,7 +3785,8 @@ qt6_deploy_runtime_dependencies(
${common_deploy_args})
")
- elseif(UNIX AND NOT APPLE AND NOT ANDROID AND QT6_IS_SHARED_LIBS_BUILD)
+ elseif(UNIX AND NOT APPLE AND NOT ANDROID AND QT6_IS_SHARED_LIBS_BUILD
+ AND NOT CMAKE_CROSSCOMPILING)
qt6_generate_deploy_script(${generate_args}
CONTENT "
qt6_deploy_runtime_dependencies(
@@ -3091,19 +3797,22 @@ ${common_deploy_args})
elseif(NOT arg_NO_UNSUPPORTED_PLATFORM_ERROR AND NOT QT_INTERNAL_NO_UNSUPPORTED_PLATFORM_ERROR)
# Currently we don't deploy runtime dependencies if cross-compiling or using a static Qt.
- # We also don't do it if targeting Linux, but we could provide an option to do
- # so if we had a deploy tool or purely CMake-based deploy implementation.
# Error out by default unless the project opted out of the error.
# This provides us a migration path in the future without breaking compatibility promises.
message(FATAL_ERROR
"Support for installing runtime dependencies is not implemented for "
- "this target platform (${CMAKE_SYSTEM_NAME}, ${qt_build_type_string})."
+ "this target platform (${CMAKE_SYSTEM_NAME}, ${qt_build_type_string}). "
+ ${unsupported_platform_extra_message}
)
else()
- qt6_generate_deploy_script(${generate_args}
- CONTENT "
-_qt_internal_show_skip_runtime_deploy_message(\"${qt_build_type_string}\")
-")
+ set(skip_message
+ "_qt_internal_show_skip_runtime_deploy_message(\"${qt_build_type_string}\"")
+ if(unsupported_platform_extra_message)
+ string(APPEND skip_message
+ "\n EXTRA_MESSAGE \"${unsupported_platform_extra_message}\"")
+ endif()
+ string(APPEND skip_message "\n)")
+ qt6_generate_deploy_script(${generate_args} CONTENT "${skip_message}")
endif()
set(${arg_OUTPUT_SCRIPT} "${deploy_script}" PARENT_SCOPE)
diff --git a/src/corelib/Qt6CoreResourceInit.in.cpp b/src/corelib/Qt6CoreResourceInit.in.cpp
new file mode 100644
index 0000000000..3f1757362d
--- /dev/null
+++ b/src/corelib/Qt6CoreResourceInit.in.cpp
@@ -0,0 +1,14 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+// This file was generated by the qt_add_resources command.
+
+#include <QtCore/qtsymbolmacros.h>
+
+QT_DECLARE_EXTERN_RESOURCE(@RESOURCE_NAME@)
+
+namespace {
+ struct resourceReferenceKeeper {
+ resourceReferenceKeeper() { QT_KEEP_RESOURCE(@RESOURCE_NAME@) }
+ } resourceReferenceKeeperInstance;
+}
diff --git a/src/corelib/Qt6WasmMacros.cmake b/src/corelib/Qt6WasmMacros.cmake
index 5cb8b73a8e..1de6e5448c 100644
--- a/src/corelib/Qt6WasmMacros.cmake
+++ b/src/corelib/Qt6WasmMacros.cmake
@@ -22,6 +22,16 @@ function(_qt_internal_wasm_add_target_helpers target)
endif()
set(APPNAME ${_target_output_name})
+ _qt_internal_wasm_export_name_for_target(_export_name ${target})
+ set(APPEXPORTNAME ${_export_name})
+
+ # Shared library builds preload plugins and qml imports by default.
+ # The json files are generated by scripts in qtbase/util/wasm/preload
+ if (QT_FEATURE_shared)
+ set(PRELOAD "preload: ['qt_plugins.json', 'qt_qml_imports.json'],")
+ else()
+ set(PRELOAD "")
+ endif()
get_target_property(target_output_directory ${target} RUNTIME_OUTPUT_DIRECTORY)
@@ -53,7 +63,7 @@ function(_qt_internal_wasm_add_target_helpers target)
endif()
configure_file("${WASM_BUILD_DIR}/plugins/platforms/wasm_shell.html"
- "${_target_directory}/${_target_output_name}.html")
+ "${_target_directory}/${_target_output_name}.html" @ONLY)
configure_file("${WASM_BUILD_DIR}/plugins/platforms/qtloader.js"
${_target_directory}/qtloader.js COPYONLY)
configure_file("${WASM_BUILD_DIR}/plugins/platforms/qtlogo.svg"
@@ -81,13 +91,22 @@ function(_qt_internal_wasm_add_target_helpers target)
endif()
target_link_options("${target}" PRIVATE "SHELL:-s INITIAL_MEMORY=${QT_WASM_INITIAL_MEMORY}")
+ # Set maximum memory size, either from user setting or to 4GB (the 32-bit maximum)
+ get_target_property(_tmp_maximumMemory "${target}" QT_WASM_MAXIMUM_MEMORY)
+ if(_tmp_maximumMemory)
+ set(QT_WASM_MAXIMUM_MEMORY "${_tmp_maximumMemory}")
+ elseif(NOT DEFINED QT_WASM_MAXIMUM_MEMORY)
+ set(QT_WASM_MAXIMUM_MEMORY "4GB")
+ endif()
+ target_link_options("${target}" PRIVATE "SHELL:-s MAXIMUM_MEMORY=${QT_WASM_MAXIMUM_MEMORY}")
+
endif()
endfunction()
function(_qt_internal_add_wasm_extra_exported_methods target)
get_target_property(wasm_extra_exported_methods "${target}" QT_WASM_EXTRA_EXPORTED_METHODS)
- set(wasm_default_exported_methods "UTF16ToString,stringToUTF16,JSEvents,specialHTMLTargets")
+ set(wasm_default_exported_methods "UTF16ToString,stringToUTF16,JSEvents,specialHTMLTargets,FS,callMain")
if(NOT wasm_extra_exported_methods)
set(wasm_extra_exported_methods ${QT_WASM_EXTRA_EXPORTED_METHODS})
@@ -104,3 +123,18 @@ function(_qt_internal_add_wasm_extra_exported_methods target)
)
endif()
endfunction()
+
+function(_qt_internal_set_wasm_export_name target)
+ _qt_internal_wasm_export_name_for_target(export_name ${target})
+ target_link_options("${target}" PRIVATE "SHELL:-s EXPORT_NAME=${export_name}")
+endfunction()
+
+function(_qt_internal_wasm_export_name_for_target out target)
+ get_target_property(export_name "${target}" QT_WASM_EXPORT_NAME)
+ if(export_name)
+ set(${out} "${export_name}" PARENT_SCOPE)
+ else()
+ string(REGEX REPLACE "[^a-zA-Z0-9_]" "_" target "${target}")
+ set(${out} "${target}_entry" PARENT_SCOPE)
+ endif()
+endfunction()
diff --git a/src/corelib/QtInstallPaths.cmake.in b/src/corelib/QtInstallPaths.cmake.in
deleted file mode 100644
index 977fffd0e4..0000000000
--- a/src/corelib/QtInstallPaths.cmake.in
+++ /dev/null
@@ -1,16 +0,0 @@
-# install layout information, following what qmake -query provides
-get_filename_component(QT@PROJECT_VERSION_MAJOR@_INSTALL_PREFIX
- ${CMAKE_CURRENT_LIST_DIR}/../@QT_INVERSE_CONFIG_INSTALL_DIR@ ABSOLUTE)
-set(QT@PROJECT_VERSION_MAJOR@_INSTALL_ARCHDATA "@INSTALL_ARCHDATADIR@")
-set(QT@PROJECT_VERSION_MAJOR@_INSTALL_BINS "@INSTALL_BINDIR@")
-set(QT@PROJECT_VERSION_MAJOR@_INSTALL_CONFIGURATION "@INSTALL_SYSCONFDIR@")
-set(QT@PROJECT_VERSION_MAJOR@_INSTALL_DATA "@INSTALL_DATADIR@")
-set(QT@PROJECT_VERSION_MAJOR@_INSTALL_DOCS "@INSTALL_DOCDIR@")
-set(QT@PROJECT_VERSION_MAJOR@_INSTALL_EXAMPLES "@INSTALL_EXAMPLESDIR@")
-set(QT@PROJECT_VERSION_MAJOR@_INSTALL_HEADERS "@INSTALL_INCLUDEDIR@")
-set(QT@PROJECT_VERSION_MAJOR@_INSTALL_LIBS "@INSTALL_LIBDIR@")
-set(QT@PROJECT_VERSION_MAJOR@_INSTALL_LIBEXECS "@INSTALL_LIBEXECDIR@")
-set(QT@PROJECT_VERSION_MAJOR@_INSTALL_PLUGINS "@INSTALL_PLUGINSDIR@")
-set(QT@PROJECT_VERSION_MAJOR@_INSTALL_QML "@INSTALL_QMLDIR@")
-set(QT@PROJECT_VERSION_MAJOR@_INSTALL_TESTS "@INSTALL_TESTSDIR@")
-set(QT@PROJECT_VERSION_MAJOR@_INSTALL_TRANSLATIONS "@INSTALL_TRANSLATIONSDIR@")
diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp
index 4965ed4fd5..9687af0987 100644
--- a/src/corelib/animation/qabstractanimation.cpp
+++ b/src/corelib/animation/qabstractanimation.cpp
@@ -856,12 +856,15 @@ qint64 QAnimationDriver::elapsed() const
QDefaultAnimationDriver::QDefaultAnimationDriver(QUnifiedTimer *timer)
: QAnimationDriver(nullptr), m_unified_timer(timer)
{
- connect(this, SIGNAL(started()), this, SLOT(startTimer()));
- connect(this, SIGNAL(stopped()), this, SLOT(stopTimer()));
+ connect(this, &QAnimationDriver::started, this, &QDefaultAnimationDriver::startTimer);
+ connect(this, &QAnimationDriver::stopped, this, &QDefaultAnimationDriver::stopTimer);
}
QDefaultAnimationDriver::~QDefaultAnimationDriver()
- = default;
+{
+ disconnect(this, &QAnimationDriver::started, this, &QDefaultAnimationDriver::startTimer);
+ disconnect(this, &QAnimationDriver::stopped, this, &QDefaultAnimationDriver::stopTimer);
+}
void QDefaultAnimationDriver::timerEvent(QTimerEvent *e)
{
@@ -901,13 +904,13 @@ QAbstractAnimationPrivate::~QAbstractAnimationPrivate() { }
void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
{
Q_Q(QAbstractAnimation);
- if (state == newState)
+ const QAbstractAnimation::State oldState = state.valueBypassingBindings();
+ if (oldState == newState)
return;
if (loopCount == 0)
return;
- QAbstractAnimation::State oldState = state;
int oldCurrentTime = currentTime;
int oldCurrentLoop = currentLoop;
QAbstractAnimation::Direction oldDirection = direction;
@@ -941,13 +944,15 @@ void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState)
}
q->updateState(newState, oldState);
- if (!guard || newState != state) //this is to be safe if updateState changes the state
+ //this is to be safe if updateState changes the state
+ if (!guard || newState != state.valueBypassingBindings())
return;
// Notify state change
state.notify();
emit q->stateChanged(newState, oldState);
- if (!guard || newState != state) //this is to be safe if updateState changes the state
+ //this is to be safe if updateState changes the state
+ if (!guard || newState != state.valueBypassingBindings())
return;
switch (state) {
@@ -1301,46 +1306,59 @@ void QAbstractAnimation::setCurrentTime(int msecs)
msecs = qMax(msecs, 0);
// Calculate new time and loop.
- int dura = duration();
- int totalDura = dura <= 0 ? dura : ((d->loopCount < 0) ? -1 : dura * d->loopCount);
+ const int dura = duration();
+ const int totalLoopCount = d->loopCount;
+ const int totalDura = dura <= 0 ? dura : ((totalLoopCount < 0) ? -1 : dura * totalLoopCount);
if (totalDura != -1)
msecs = qMin(totalDura, msecs);
- const int oldCurrentTime = d->totalCurrentTime;
- d->totalCurrentTime = msecs;
+ d->totalCurrentTime.removeBindingUnlessInWrapper();
+
+ const int oldCurrentTime = d->totalCurrentTime.valueBypassingBindings();
+ d->totalCurrentTime.setValueBypassingBindings(msecs);
+
+ QAbstractAnimation::Direction currentDirection = d->direction;
// Update new values.
- int oldLoop = d->currentLoop;
- d->currentLoop = ((dura <= 0) ? 0 : (msecs / dura));
- if (d->currentLoop == d->loopCount) {
+ const int oldLoop = d->currentLoop.valueBypassingBindings();
+ int newCurrentLoop = (dura <= 0) ? 0 : (msecs / dura);
+ if (newCurrentLoop == totalLoopCount) {
//we're at the end
d->currentTime = qMax(0, dura);
- d->currentLoop = qMax(0, d->loopCount - 1);
+ newCurrentLoop = qMax(0, totalLoopCount - 1);
} else {
- if (d->direction == Forward) {
+ if (currentDirection == Forward) {
d->currentTime = (dura <= 0) ? msecs : (msecs % dura);
} else {
d->currentTime = (dura <= 0) ? msecs : ((msecs - 1) % dura) + 1;
if (d->currentTime == dura)
- d->currentLoop = d->currentLoop - 1;
+ newCurrentLoop = newCurrentLoop - 1;
}
}
+ d->currentLoop.setValueBypassingBindings(newCurrentLoop);
+ // this is a virtual function, so it can update the properties as well
updateCurrentTime(d->currentTime);
- if (d->currentLoop != oldLoop)
+
+ // read the property values again
+ newCurrentLoop = d->currentLoop.valueBypassingBindings();
+ currentDirection = d->direction;
+ const int newTotalCurrentTime = d->totalCurrentTime.valueBypassingBindings();
+
+ if (newCurrentLoop != oldLoop)
d->currentLoop.notify();
/* Notify before calling stop: As seen in tst_QSequentialAnimationGroup::clear
* we might delete the animation when stop is called. Thus after stop no member
* of the object must be used anymore.
*/
- if (oldCurrentTime != d->totalCurrentTime)
+ if (oldCurrentTime != newTotalCurrentTime)
d->totalCurrentTime.notify();
// All animations are responsible for stopping the animation when their
// own end state is reached; in this case the animation is time driven,
// and has reached the end.
- if ((d->direction == Forward && d->totalCurrentTime == totalDura)
- || (d->direction == Backward && d->totalCurrentTime == 0)) {
+ if ((currentDirection == Forward && newTotalCurrentTime == totalDura)
+ || (currentDirection == Backward && newTotalCurrentTime == 0)) {
stop();
}
}
@@ -1364,7 +1382,7 @@ void QAbstractAnimation::setCurrentTime(int msecs)
void QAbstractAnimation::start(DeletionPolicy policy)
{
Q_D(QAbstractAnimation);
- if (d->state == Running)
+ if (d->state.valueBypassingBindings() == Running)
return;
d->deleteWhenStopped = policy;
d->setState(Running);
@@ -1384,7 +1402,7 @@ void QAbstractAnimation::stop()
{
Q_D(QAbstractAnimation);
- if (d->state == Stopped)
+ if (d->state.valueBypassingBindings() == Stopped)
return;
d->setState(Stopped);
@@ -1400,7 +1418,7 @@ void QAbstractAnimation::stop()
void QAbstractAnimation::pause()
{
Q_D(QAbstractAnimation);
- if (d->state == Stopped) {
+ if (d->state.valueBypassingBindings() == Stopped) {
qWarning("QAbstractAnimation::pause: Cannot pause a stopped animation");
return;
}
@@ -1418,7 +1436,7 @@ void QAbstractAnimation::pause()
void QAbstractAnimation::resume()
{
Q_D(QAbstractAnimation);
- if (d->state != Paused) {
+ if (d->state.valueBypassingBindings() != Paused) {
qWarning("QAbstractAnimation::resume: "
"Cannot resume an animation that is not paused");
return;
diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h
index 5be59543c8..cb9042777a 100644
--- a/src/corelib/animation/qabstractanimation_p.h
+++ b/src/corelib/animation/qabstractanimation_p.h
@@ -29,7 +29,7 @@ QT_BEGIN_NAMESPACE
class QAnimationGroup;
class QAbstractAnimation;
-class QAbstractAnimationPrivate : public QObjectPrivate
+class Q_CORE_EXPORT QAbstractAnimationPrivate : public QObjectPrivate
{
public:
QAbstractAnimationPrivate();
@@ -48,7 +48,7 @@ public:
{
q_func()->setDirection(direction);
}
- void emitDirectionChanged() { emit q_func()->directionChanged(direction); }
+ void emitDirectionChanged() { Q_EMIT q_func()->directionChanged(direction); }
Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QAbstractAnimationPrivate, QAbstractAnimation::Direction,
direction, &QAbstractAnimationPrivate::setDirection,
&QAbstractAnimationPrivate::emitDirectionChanged,
@@ -61,7 +61,7 @@ public:
Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QAbstractAnimationPrivate, int, loopCount, 1)
- void emitCurrentLoopChanged() { emit q_func()->currentLoopChanged(currentLoop); }
+ void emitCurrentLoopChanged() { Q_EMIT q_func()->currentLoopChanged(currentLoop); }
Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QAbstractAnimationPrivate, int, currentLoop, nullptr,
&QAbstractAnimationPrivate::emitCurrentLoopChanged, 0)
diff --git a/src/corelib/animation/qpauseanimation.cpp b/src/corelib/animation/qpauseanimation.cpp
index eb1e6c3c81..344b21946e 100644
--- a/src/corelib/animation/qpauseanimation.cpp
+++ b/src/corelib/animation/qpauseanimation.cpp
@@ -94,11 +94,10 @@ void QPauseAnimation::setDuration(int msecs)
}
Q_D(QPauseAnimation);
- if (msecs != d->duration) {
- d->duration = msecs;
+ d->duration.removeBindingUnlessInWrapper();
+ if (msecs != d->duration.valueBypassingBindings()) {
+ d->duration.setValueBypassingBindings(msecs);
d->duration.notify();
- } else {
- d->duration.removeBindingUnlessInWrapper();
}
}
diff --git a/src/corelib/animation/qpropertyanimation.cpp b/src/corelib/animation/qpropertyanimation.cpp
index 985371d30f..d461668dbb 100644
--- a/src/corelib/animation/qpropertyanimation.cpp
+++ b/src/corelib/animation/qpropertyanimation.cpp
@@ -60,7 +60,8 @@ QT_BEGIN_NAMESPACE
void QPropertyAnimationPrivate::updateMetaProperty()
{
- if (!targetObject || propertyName.value().isEmpty()) {
+ const QObject *target = targetObject.valueBypassingBindings();
+ if (!target || propertyName.value().isEmpty()) {
propertyType = QMetaType::UnknownType;
propertyIndex = -1;
return;
@@ -68,19 +69,19 @@ void QPropertyAnimationPrivate::updateMetaProperty()
//propertyType will be set to a valid type only if there is a Q_PROPERTY
//otherwise it will be set to QVariant::Invalid at the end of this function
- propertyType = targetObject->property(propertyName.value()).userType();
- propertyIndex = targetObject->metaObject()->indexOfProperty(propertyName.value());
+ propertyType = target->property(propertyName.value()).userType();
+ propertyIndex = target->metaObject()->indexOfProperty(propertyName.value());
if (propertyType != QMetaType::UnknownType)
convertValues(propertyType);
if (propertyIndex == -1) {
//there is no Q_PROPERTY on the object
propertyType = QMetaType::UnknownType;
- if (!targetObject->dynamicPropertyNames().contains(propertyName))
+ if (!target->dynamicPropertyNames().contains(propertyName))
qWarning("QPropertyAnimation: you're trying to animate a non-existing property %s of "
"your QObject",
propertyName.value().constData());
- } else if (!targetObject->metaObject()->property(propertyIndex).isWritable()) {
+ } else if (!target->metaObject()->property(propertyIndex).isWritable()) {
qWarning("QPropertyAnimation: you're trying to animate the non-writable property %s of "
"your QObject",
propertyName.value().constData());
@@ -163,15 +164,16 @@ void QPropertyAnimation::setTargetObject(QObject *target)
}
d->targetObject.removeBindingUnlessInWrapper();
- if (d->targetObject == target)
+ const QObject *oldTarget = d->targetObject.valueBypassingBindings();
+ if (oldTarget == target)
return;
- if (d->targetObject != nullptr)
- QObject::disconnect(d->targetObject, &QObject::destroyed, this, nullptr);
+ if (oldTarget != nullptr)
+ QObject::disconnect(oldTarget, &QObject::destroyed, this, nullptr);
d->targetObject.setValueBypassingBindings(target);
- if (d->targetObject != nullptr) {
- QObject::connect(d->targetObject, &QObject::destroyed, this,
+ if (target != nullptr) {
+ QObject::connect(target, &QObject::destroyed, this,
[d] { d->targetObjectDestroyed(); });
}
d->updateMetaProperty();
@@ -201,7 +203,7 @@ void QPropertyAnimation::setPropertyName(const QByteArray &propertyName)
d->propertyName.removeBindingUnlessInWrapper();
- if (d->propertyName == propertyName)
+ if (d->propertyName.valueBypassingBindings() == propertyName)
return;
d->propertyName.setValueBypassingBindings(propertyName);
@@ -259,7 +261,7 @@ void QPropertyAnimation::updateState(QAbstractAnimation::State newState,
{
Q_CONSTINIT static QBasicMutex mutex;
auto locker = qt_unique_lock(mutex);
- typedef QPair<QObject *, QByteArray> QPropertyAnimationPair;
+ using QPropertyAnimationPair = std::pair<QObject *, QByteArray>;
typedef QHash<QPropertyAnimationPair, QPropertyAnimation*> QPropertyAnimationHash;
Q_CONSTINIT static QPropertyAnimationHash hash;
diff --git a/src/corelib/animation/qvariantanimation.cpp b/src/corelib/animation/qvariantanimation.cpp
index cf84200f2a..b4d47aae8f 100644
--- a/src/corelib/animation/qvariantanimation.cpp
+++ b/src/corelib/animation/qvariantanimation.cpp
@@ -203,7 +203,7 @@ void QVariantAnimationPrivate::recalculateCurrentInterval(bool force/*=false*/)
//let's update currentInterval
QVariantAnimation::KeyValues::const_iterator it = std::lower_bound(keyValues.constBegin(),
keyValues.constEnd(),
- qMakePair(progress, QVariant()),
+ std::pair{progress, QVariant{}},
animationValueLessThan);
if (it == keyValues.constBegin()) {
//the item pointed to by it is the start element in the range
@@ -211,7 +211,7 @@ void QVariantAnimationPrivate::recalculateCurrentInterval(bool force/*=false*/)
currentInterval.start = *it;
currentInterval.end = *(it+1);
} else {
- currentInterval.start = qMakePair(qreal(0), defaultStartEndValue);
+ currentInterval.start = {qreal(0), defaultStartEndValue};
currentInterval.end = *it;
}
} else if (it == keyValues.constEnd()) {
@@ -223,7 +223,7 @@ void QVariantAnimationPrivate::recalculateCurrentInterval(bool force/*=false*/)
} else {
//we use the default end value here
currentInterval.start = *it;
- currentInterval.end = qMakePair(qreal(1), defaultStartEndValue);
+ currentInterval.end = {qreal(1), defaultStartEndValue};
}
} else {
currentInterval.start = *(it-1);
@@ -264,9 +264,10 @@ void QVariantAnimationPrivate::setCurrentValueForProgress(const qreal progress)
QVariant QVariantAnimationPrivate::valueAt(qreal step) const
{
- QVariantAnimation::KeyValues::const_iterator result =
- std::lower_bound(keyValues.constBegin(), keyValues.constEnd(), qMakePair(step, QVariant()), animationValueLessThan);
- if (result != keyValues.constEnd() && !animationValueLessThan(qMakePair(step, QVariant()), *result))
+ const auto sought = std::pair{step, QVariant()};
+ const auto result = std::lower_bound(keyValues.cbegin(), keyValues.cend(), sought,
+ animationValueLessThan);
+ if (result != keyValues.cend() && !animationValueLessThan(sought, *result))
return result->second;
return QVariant();
@@ -353,8 +354,9 @@ QEasingCurve QVariantAnimation::easingCurve() const
void QVariantAnimation::setEasingCurve(const QEasingCurve &easing)
{
Q_D(QVariantAnimation);
- const bool valueChanged = easing != d->easing;
- d->easing = easing;
+ d->easing.removeBindingUnlessInWrapper();
+ const bool valueChanged = easing != d->easing.valueBypassingBindings();
+ d->easing.setValueBypassingBindings(easing);
d->recalculateCurrentInterval();
if (valueChanged)
d->easing.notify();
@@ -482,13 +484,12 @@ void QVariantAnimation::setDuration(int msecs)
qWarning("QVariantAnimation::setDuration: cannot set a negative duration");
return;
}
- if (d->duration == msecs) {
- d->duration.removeBindingUnlessInWrapper();
- return;
+ d->duration.removeBindingUnlessInWrapper();
+ if (d->duration.valueBypassingBindings() != msecs) {
+ d->duration.setValueBypassingBindings(msecs);
+ d->recalculateCurrentInterval();
+ d->duration.notify();
}
- d->duration = msecs;
- d->recalculateCurrentInterval();
- d->duration.notify();
}
QBindable<int> QVariantAnimation::bindableDuration()
@@ -552,7 +553,7 @@ QVariant QVariantAnimation::keyValueAt(qreal step) const
/*!
\typedef QVariantAnimation::KeyValue
- This is a typedef for QPair<qreal, QVariant>.
+ This is a typedef for std::pair<qreal, QVariant>.
*/
/*!
\typedef QVariantAnimation::KeyValues
diff --git a/src/corelib/animation/qvariantanimation.h b/src/corelib/animation/qvariantanimation.h
index 640c057ef8..4bdb971357 100644
--- a/src/corelib/animation/qvariantanimation.h
+++ b/src/corelib/animation/qvariantanimation.h
@@ -26,7 +26,7 @@ class Q_CORE_EXPORT QVariantAnimation : public QAbstractAnimation
BINDABLE bindableEasingCurve)
public:
- typedef QPair<qreal, QVariant> KeyValue;
+ using KeyValue = std::pair<qreal, QVariant>;
typedef QList<KeyValue> KeyValues;
QVariantAnimation(QObject *parent = nullptr);
diff --git a/src/corelib/compat/removed_api.cpp b/src/corelib/compat/removed_api.cpp
index fdbe5de41c..23679bf4cc 100644
--- a/src/corelib/compat/removed_api.cpp
+++ b/src/corelib/compat/removed_api.cpp
@@ -139,6 +139,16 @@ QLocale::Language QLocale::codeToLanguage(QStringView languageCode) noexcept
#include "qoperatingsystemversion.h"
+QOperatingSystemVersion QOperatingSystemVersion::current()
+{
+ return QOperatingSystemVersionBase::current();
+}
+
+QString QOperatingSystemVersion::name() const
+{
+ return QOperatingSystemVersionBase::name();
+}
+
int QOperatingSystemVersion::compare(const QOperatingSystemVersion &v1,
const QOperatingSystemVersion &v2)
{
@@ -200,7 +210,7 @@ void QObject::setObjectName(const QString &name)
void QSettings::beginGroup(const QString &prefix)
{
- return beginGroup(qToAnyStringViewIgnoringNull(prefix));
+ beginGroup(qToAnyStringViewIgnoringNull(prefix));
}
int QSettings::beginReadArray(const QString &prefix)
@@ -509,6 +519,15 @@ QByteArray QMessageAuthenticationCode::hash(const QByteArray &msg, const QByteAr
qToByteArrayViewIgnoringNull(key), method);
}
+#include "qobject.h" // inlined API
+
+#include "qrunnable.h"
+
+QRunnable *QRunnable::create(std::function<void()> functionToRun)
+{
+ return QRunnable::create<std::function<void()>>(std::move(functionToRun));
+}
+
#include "qstring.h"
qsizetype QString::toUcs4_helper(const ushort *uc, qsizetype length, uint *out)
@@ -517,8 +536,571 @@ qsizetype QString::toUcs4_helper(const ushort *uc, qsizetype length, uint *out)
reinterpret_cast<char32_t *>(out));
}
+#if QT_CONFIG(thread)
+#include "qreadwritelock.h"
+
+bool QReadWriteLock::tryLockForRead()
+{
+ return tryLockForRead(0);
+}
+
+bool QReadWriteLock::tryLockForWrite()
+{
+ return tryLockForWrite(0);
+}
+
+#include "qthreadpool.h"
+#include "private/qthreadpool_p.h"
+
+void QThreadPool::start(std::function<void()> functionToRun, int priority)
+{
+ if (!functionToRun)
+ return;
+ start(QRunnable::create(std::move(functionToRun)), priority);
+}
+
+bool QThreadPool::tryStart(std::function<void()> functionToRun)
+{
+ if (!functionToRun)
+ return false;
+
+ Q_D(QThreadPool);
+ QMutexLocker locker(&d->mutex);
+ if (!d->allThreads.isEmpty() && d->areAllThreadsActive())
+ return false;
+
+ QRunnable *runnable = QRunnable::create(std::move(functionToRun));
+ if (d->tryStart(runnable))
+ return true;
+ delete runnable;
+ return false;
+}
+
+void QThreadPool::startOnReservedThread(std::function<void()> functionToRun)
+{
+ if (!functionToRun)
+ return releaseThread();
+
+ startOnReservedThread(QRunnable::create(std::move(functionToRun)));
+}
+
+#endif // QT_CONFIG(thread)
+
+#include "qxmlstream.h"
+
+QStringView QXmlStreamAttributes::value(const QString &namespaceUri, const QString &name) const
+{
+ return value(qToAnyStringViewIgnoringNull(namespaceUri), qToAnyStringViewIgnoringNull(name));
+}
+
+QStringView QXmlStreamAttributes::value(const QString &namespaceUri, QLatin1StringView name) const
+{
+ return value(qToAnyStringViewIgnoringNull(namespaceUri), QAnyStringView(name));
+}
+
+QStringView QXmlStreamAttributes::value(QLatin1StringView namespaceUri, QLatin1StringView name) const
+{
+ return value(QAnyStringView(namespaceUri), QAnyStringView(name));
+}
+
+QStringView QXmlStreamAttributes::value(const QString &qualifiedName) const
+{
+ return value(qToAnyStringViewIgnoringNull(qualifiedName));
+}
+
+QStringView QXmlStreamAttributes::value(QLatin1StringView qualifiedName) const
+{
+ return value(QAnyStringView(qualifiedName));
+}
+
+// inlined API
+#if QT_CONFIG(thread)
+#include "qmutex.h"
+#include "qreadwritelock.h"
+#include "qsemaphore.h"
+#endif
+
// #include "qotherheader.h"
// // implement removed functions from qotherheader.h
// order sections alphabetically to reduce chances of merge conflicts
#endif // QT_CORE_REMOVED_SINCE(6, 6)
+
+#if QT_CORE_REMOVED_SINCE(6, 7)
+
+#include "qbitarray.h"
+
+QBitArray QBitArray::operator~() const
+{
+ return QBitArray(*this).inverted_inplace();
+}
+
+#include "qbytearray.h" // also includes inlined API
+
+QByteArray QByteArray::left(qsizetype len) const
+{
+ if (len >= size())
+ return *this;
+ if (len < 0)
+ len = 0;
+ return QByteArray(data(), len);
+}
+
+QByteArray QByteArray::right(qsizetype len) const
+{
+ if (len >= size())
+ return *this;
+ if (len < 0)
+ len = 0;
+ return QByteArray(end() - len, len);
+}
+
+QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
+{
+ qsizetype p = pos;
+ qsizetype l = len;
+ using namespace QtPrivate;
+ switch (QContainerImplHelper::mid(size(), &p, &l)) {
+ case QContainerImplHelper::Null:
+ return QByteArray();
+ case QContainerImplHelper::Empty:
+ {
+ return QByteArray(DataPointer::fromRawData(&_empty, 0));
+ }
+ case QContainerImplHelper::Full:
+ return *this;
+ case QContainerImplHelper::Subset:
+ return QByteArray(d.data() + p, l);
+ }
+ Q_UNREACHABLE_RETURN(QByteArray());
+}
+
+#ifdef Q_CC_MSVC
+// previously inline methods, only needed for MSVC compat
+QByteArray QByteArray::first(qsizetype n) const
+{ return sliced(0, n); }
+QByteArray QByteArray::last(qsizetype n) const
+{ return sliced(size() - n, n); }
+QByteArray QByteArray::sliced(qsizetype pos) const
+{ return sliced(pos, size() - pos); }
+QByteArray QByteArray::sliced(qsizetype pos, qsizetype n) const
+{ verify(pos, n); return QByteArray(d.data() + pos, n); }
+QByteArray QByteArray::chopped(qsizetype n) const
+{ return sliced(0, size() - n); }
+#endif
+
+#include "qcborstreamreader.h"
+
+QCborError QCborStreamReader::lastError()
+{
+ return std::as_const(*this).lastError();
+}
+
+#include "qdatetime.h"
+
+QDateTime::QDateTime(QDate date, QTime time, const QTimeZone &timeZone)
+ : QDateTime(date, time, timeZone, TransitionResolution::LegacyBehavior) {}
+QDateTime::QDateTime(QDate date, QTime time)
+ : QDateTime(date, time, TransitionResolution::LegacyBehavior) {}
+void QDateTime::setDate(QDate date) { setDate(date, TransitionResolution::LegacyBehavior); }
+void QDateTime::setTime(QTime time) { setTime(time, TransitionResolution::LegacyBehavior); }
+void QDateTime::setTimeZone(const QTimeZone &toZone)
+{
+ setTimeZone(toZone, TransitionResolution::LegacyBehavior);
+}
+
+bool QDateTime::precedes(const QDateTime &other) const
+{
+ return compareThreeWay(*this, other) < 0;
+}
+
+#include "qdatastream.h"
+
+QDataStream &QDataStream::writeBytes(const char *s, uint len)
+{
+ return writeBytes(s, qint64(len));
+}
+
+int QDataStream::skipRawData(int len)
+{
+ return int(skipRawData(qint64(len)));
+}
+
+int QDataStream::readBlock(char *data, int len)
+{
+ return int(readBlock(data, qint64(len)));
+}
+
+int QDataStream::readRawData(char *s, int len)
+{
+ return int(readRawData(s, qint64(len)));
+}
+
+int QDataStream::writeRawData(const char *s, int len)
+{
+ return writeRawData(s, qint64(len));
+}
+
+#if defined(Q_OS_ANDROID)
+
+#include "qjniobject.h"
+
+jclass QJniObject::loadClass(const QByteArray &className, JNIEnv *env, bool /*binEncoded*/)
+{
+ return QJniObject::loadClass(className, env);
+}
+
+QByteArray QJniObject::toBinaryEncClassName(const QByteArray &className)
+{
+ return QByteArray(className).replace('/', '.');
+}
+
+void QJniObject::callVoidMethodV(JNIEnv *env, jmethodID id, va_list args) const
+{
+ env->CallVoidMethodV(javaObject(), id, args);
+}
+
+#endif // Q_OS_ANDROID
+
+#include "qlocale.h"
+
+QStringList QLocale::uiLanguages() const
+{
+ return uiLanguages(TagSeparator::Dash);
+}
+
+QString QLocale::name() const
+{
+ return name(TagSeparator::Underscore);
+}
+
+QString QLocale::bcp47Name() const
+{
+ return bcp47Name(TagSeparator::Dash);
+}
+
+QDate QLocale::toDate(const QString &string, FormatType format) const
+{
+ return toDate(string, dateFormat(format), DefaultTwoDigitBaseYear);
+}
+
+QDate QLocale::toDate(const QString &string, FormatType format, QCalendar cal) const
+{
+ return toDate(string, dateFormat(format), cal, DefaultTwoDigitBaseYear);
+}
+
+QDateTime QLocale::toDateTime(const QString &string, FormatType format) const
+{
+ return toDateTime(string, dateTimeFormat(format), DefaultTwoDigitBaseYear);
+}
+
+QDateTime QLocale::toDateTime(const QString &string, FormatType format, QCalendar cal) const
+{
+ return toDateTime(string, dateTimeFormat(format), cal, DefaultTwoDigitBaseYear);
+}
+
+QDate QLocale::toDate(const QString &string, const QString &format) const
+{
+ return toDate(string, format, QCalendar(), DefaultTwoDigitBaseYear);
+}
+
+QDate QLocale::toDate(const QString &string, const QString &format, QCalendar cal) const
+{
+ return toDate(string, format, cal, DefaultTwoDigitBaseYear);
+}
+
+QDateTime QLocale::toDateTime(const QString &string, const QString &format) const
+{
+ return toDateTime(string, format, QCalendar(), DefaultTwoDigitBaseYear);
+}
+
+QDateTime QLocale::toDateTime(const QString &string, const QString &format, QCalendar cal) const
+{
+ return toDateTime(string, format, cal, DefaultTwoDigitBaseYear);
+}
+
+#include "qobject.h"
+
+void qt_qFindChildren_helper(const QObject *parent, const QMetaObject &mo,
+ QList<void*> *list, Qt::FindChildOptions options)
+{
+ qt_qFindChildren_helper(parent, QAnyStringView(), mo, list, options);
+}
+
+void qt_qFindChildren_helper(const QObject *parent, const QString &name, const QMetaObject &mo,
+ QList<void*> *list, Qt::FindChildOptions options)
+{
+ qt_qFindChildren_helper(parent, QAnyStringView{name}, mo, list, options);
+}
+
+QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo,
+ Qt::FindChildOptions options)
+{
+ return qt_qFindChild_helper(parent, QAnyStringView{name}, mo, options);
+}
+
+void QObject::moveToThread(QThread *targetThread)
+{
+ moveToThread(targetThread, QT6_CALL_NEW_OVERLOAD);
+}
+
+#include "qobjectdefs.h"
+
+bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type, void *ret)
+{
+ return invokeMethodImpl(object, slot, type, 1, &ret, nullptr, nullptr);
+}
+
+#include "qstring.h"
+
+QString QString::left(qsizetype n) const
+{
+ if (size_t(n) >= size_t(size()))
+ return *this;
+ return QString((const QChar*) d.data(), n);
+}
+
+QString QString::right(qsizetype n) const
+{
+ if (size_t(n) >= size_t(size()))
+ return *this;
+ return QString(constData() + size() - n, n);
+}
+
+QString QString::mid(qsizetype position, qsizetype n) const
+{
+ qsizetype p = position;
+ qsizetype l = n;
+ using namespace QtPrivate;
+ switch (QContainerImplHelper::mid(size(), &p, &l)) {
+ case QContainerImplHelper::Null:
+ return QString();
+ case QContainerImplHelper::Empty:
+ return QString(DataPointer::fromRawData(&_empty, 0));
+ case QContainerImplHelper::Full:
+ return *this;
+ case QContainerImplHelper::Subset:
+ return QString(constData() + p, l);
+ }
+ Q_UNREACHABLE_RETURN(QString());
+}
+
+#ifdef Q_CC_MSVC
+// previously inline methods, only needed for MSVC compat
+QString QString::first(qsizetype n) const
+{ return sliced(0, n); }
+QString QString::last(qsizetype n) const
+{ return sliced(size() - n, n); }
+QString QString::sliced(qsizetype pos) const
+{ return sliced(pos, size() - pos); }
+QString QString::sliced(qsizetype pos, qsizetype n) const
+{ verify(pos, n); return QString(begin() + pos, n); }
+QString QString::chopped(qsizetype n) const
+{ return sliced(0, size() - n); }
+#endif
+
+#include "qtimezone.h"
+
+bool QTimeZone::operator==(const QTimeZone &other) const
+{
+ return comparesEqual(*this, other);
+}
+
+bool QTimeZone::operator!=(const QTimeZone &other) const
+{
+ return !comparesEqual(*this, other);
+}
+
+#include "qurl.h"
+
+QUrl QUrl::fromEncoded(const QByteArray &input, ParsingMode mode)
+{
+ return QUrl::fromEncoded(QByteArrayView(input), mode);
+}
+
+#include "qtimer.h" // inlined API
+
+
+// #include "qotherheader.h"
+// // implement removed functions from qotherheader.h
+// order sections alphabetically to reduce chances of merge conflicts
+
+#endif // QT_CORE_REMOVED_SINCE(6, 7)
+
+#if QT_CORE_REMOVED_SINCE(6, 8)
+#include "qbitarray.h" // inlined API
+
+#include "qbytearray.h" // inlined API
+
+#include "qcborarray.h" // inlined API
+
+#include "qcbormap.h" // inlined API
+
+#include "qcborvalue.h" // inlined API
+
+#include "qdatastream.h" // inlined API
+
+QDataStream &QDataStream::operator<<(bool i)
+{
+ return (*this << qint8(i));
+}
+
+#include "qdir.h" // inlined API
+
+bool QDir::operator==(const QDir &dir) const
+{
+ return comparesEqual(*this, dir);
+}
+
+#include "qfileinfo.h" // inlined API
+
+bool QFileInfo::operator==(const QFileInfo &fileinfo) const
+{
+ return comparesEqual(*this, fileinfo);
+}
+
+#include "qitemselectionmodel.h" // inlined API
+
+#include "qjsonarray.h"
+
+bool QJsonArray::operator==(const QJsonArray &other) const
+{
+ return comparesEqual(*this, other);
+}
+
+bool QJsonArray::operator!=(const QJsonArray &other) const
+{
+ return !comparesEqual(*this, other);
+}
+
+#include "qjsondocument.h"
+
+bool QJsonDocument::operator==(const QJsonDocument &other) const
+{
+ return comparesEqual(*this, other);
+}
+
+#include "qjsonobject.h"
+
+bool QJsonObject::operator==(const QJsonObject &other) const
+{
+ return comparesEqual(*this, other);
+}
+
+
+bool QJsonObject::operator!=(const QJsonObject &other) const
+{
+ return !comparesEqual(*this, other);
+}
+
+#include "qjsonvalue.h"
+
+bool QJsonValue::operator==(const QJsonValue &other) const
+{
+ return comparesEqual(*this, other);
+}
+
+bool QJsonValue::operator!=(const QJsonValue &other) const
+{
+ return !comparesEqual(*this, other);
+}
+
+#include "qmimetype.h"
+
+bool QMimeType::operator==(const QMimeType &other) const
+{
+ return comparesEqual(*this, other);
+}
+
+#include "qobject.h"
+#include "qnumeric.h"
+
+int QObject::startTimer(std::chrono::milliseconds time, Qt::TimerType timerType)
+{
+ using namespace std::chrono;
+ using ratio = std::ratio_divide<std::milli, std::nano>;
+ nanoseconds::rep r;
+ if (qMulOverflow<ratio::num>(time.count(), &r)) {
+ qWarning("QObject::startTimer(std::chrono::milliseconds): "
+ "'time' arg overflowed when converted to nanoseconds.");
+ r = nanoseconds::max().count();
+ }
+ return startTimer(nanoseconds{r}, timerType);
+}
+
+#if QT_CONFIG(processenvironment)
+#include "qprocess.h" // inlined API
+
+bool QProcessEnvironment::operator==(const QProcessEnvironment &other) const
+{
+ return comparesEqual(*this, other);
+}
+#endif // QT_CONFIG(processenvironment)
+
+#if QT_CONFIG(regularexpression)
+#include "qregularexpression.h"
+
+bool QRegularExpressionMatch::hasCaptured(QStringView name) const
+{
+ return hasCaptured(QAnyStringView(name));
+}
+
+QString QRegularExpressionMatch::captured(QStringView name) const
+{
+ return captured(QAnyStringView(name));
+}
+
+QStringView QRegularExpressionMatch::capturedView(QStringView name) const
+{
+ return capturedView(QAnyStringView(name));
+}
+
+qsizetype QRegularExpressionMatch::capturedStart(QStringView name) const
+{
+ return capturedStart(QAnyStringView(name));
+}
+
+qsizetype QRegularExpressionMatch::capturedLength(QStringView name) const
+{
+ return capturedLength(QAnyStringView(name));
+}
+
+qsizetype QRegularExpressionMatch::capturedEnd(QStringView name) const
+{
+ return capturedEnd(QAnyStringView(name));
+}
+#endif // QT_CONFIG(regularexpression)
+
+#include "qstring.h" // inlined API
+
+#include "qurl.h"
+
+bool QUrl::operator<(const QUrl &url) const
+{
+ return is_lt(compareThreeWay(*this, url));
+}
+
+bool QUrl::operator==(const QUrl &url) const
+{
+ return comparesEqual(*this, url);
+}
+
+bool QUrl::operator!=(const QUrl &url) const
+{
+ return !comparesEqual(*this, url);
+}
+
+#include "qurlquery.h"
+
+bool QUrlQuery::operator==(const QUrlQuery &other) const
+{
+ return comparesEqual(*this, other);
+}
+
+#include "qxmlstream.h" // inlined API
+
+// #include "qotherheader.h"
+// // implement removed functions from qotherheader.h
+// order sections alphabetically to reduce chances of merge conflicts
+
+#endif // QT_CORE_REMOVED_SINCE(6, 8)
diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake
index d84a52132e..80e6d93193 100644
--- a/src/corelib/configure.cmake
+++ b/src/corelib/configure.cmake
@@ -98,6 +98,18 @@ clock_gettime(CLOCK_MONOTONIC, &ts);
}
")
+# close_range
+qt_config_compile_test(close_range
+ LABEL "close_range()"
+ CODE
+"#include <unistd.h>
+
+int main()
+{
+ return close_range(3, 1024, 0) != 0;
+}
+")
+
# cloexec
qt_config_compile_test(cloexec
LABEL "O_CLOEXEC"
@@ -125,44 +137,6 @@ int pipes[2];
}
")
-# special case begin
-# cxx11_future
-if (UNIX AND NOT ANDROID AND NOT QNX AND NOT INTEGRITY)
- set(cxx11_future_TEST_LIBRARIES pthread)
-endif()
-qt_config_compile_test(cxx11_future
- LABEL "C++11 <future>"
- LIBRARIES
- "${cxx11_future_TEST_LIBRARIES}"
- CODE
-"#include <future>
-
-int main(void)
-{
- /* BEGIN TEST: */
-std::future<int> f = std::async([]() { return 42; });
-(void)f.get();
- /* END TEST: */
- return 0;
-}
-")
-# special case end
-
-# cxx11_random
-qt_config_compile_test(cxx11_random
- LABEL "C++11 <random>"
- CODE
-"#include <random>
-
-int main(void)
-{
- /* BEGIN TEST: */
-std::mt19937 mt(0);
- /* END TEST: */
- return 0;
-}
-")
-
# cxx17_filesystem
qt_config_compile_test(cxx17_filesystem
LABEL "C++17 <filesystem>"
@@ -198,24 +172,6 @@ int main(void)
}"
)
-# eventfd
-qt_config_compile_test(eventfd
- LABEL "eventfd"
- CODE
-"#include <sys/eventfd.h>
-
-int main(void)
-{
- /* BEGIN TEST: */
-eventfd_t value;
-int fd = eventfd(0, EFD_CLOEXEC);
-eventfd_read(fd, &value);
-eventfd_write(fd, value);
- /* END TEST: */
- return 0;
-}
-")
-
# futimens
qt_config_compile_test(futimens
LABEL "futimens()"
@@ -265,21 +221,6 @@ char buf[32];
}
")
-# glibc
-qt_config_compile_test(glibc
- LABEL "GNU libc"
- CODE
-"#include <stdlib.h>
-
-int main(void)
-{
- /* BEGIN TEST: */
-return __GLIBC__;
- /* END TEST: */
- return 0;
-}
-")
-
# inotify
qt_config_compile_test(inotify
LABEL "inotify"
@@ -455,44 +396,6 @@ renameat2(AT_FDCWD, argv[1], AT_FDCWD, argv[2], RENAME_NOREPLACE | RENAME_WHITEO
}
")
-# statx
-qt_config_compile_test(statx
- LABEL "statx() in libc"
- CODE
-"#define _ATFILE_SOURCE 1
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-int main(void)
-{
- /* BEGIN TEST: */
-struct statx statxbuf;
-unsigned int mask = STATX_BASIC_STATS;
-return statx(AT_FDCWD, \"\", AT_STATX_SYNC_AS_STAT, mask, &statxbuf);
- /* END TEST: */
- return 0;
-}
-")
-
-# syslog
-qt_config_compile_test(syslog
- LABEL "syslog"
- CODE
-"#include <syslog.h>
-
-int main(void)
-{
- /* BEGIN TEST: */
-openlog(\"qt\", 0, LOG_USER);
-syslog(LOG_INFO, \"configure\");
-closelog();
- /* END TEST: */
- return 0;
-}
-")
-
# cpp_winrt
qt_config_compile_test(cpp_winrt
LABEL "cpp/winrt"
@@ -508,40 +411,25 @@ int main(void)
}
")
-# xlocalescanprint
-qt_config_compile_test(xlocalescanprint
- LABEL "xlocale.h (or equivalents)"
+# <stacktrace>
+qt_config_compile_test(cxx23_stacktrace
+ LABEL "C++23 <stacktrace> support"
CODE
-"#define QT_BEGIN_NAMESPACE
-#define QT_END_NAMESPACE
-
-#ifdef _MSVC_VER
-#define Q_CC_MSVC _MSVC_VER
+"#include <stacktrace>
+#if !defined(__cpp_lib_stacktrace)
+#error
#endif
-#define QT_NO_DOUBLECONVERSION
-
-#include QDSP_P_H
-
int main(void)
{
/* BEGIN TEST: */
-#ifdef _MSVC_VER
-_locale_t invalidLocale = NULL;
-#else
-locale_t invalidLocale = NULL;
-#endif
-double a = 3.4;
-qDoubleSnprintf(argv[0], 1, invalidLocale, \"invalid format\", a);
-qDoubleSscanf(argv[0], invalidLocale, \"invalid format\", &a, &argc);
+const auto backtrace = std::stacktrace::current();
/* END TEST: */
- return 0;
}
-"# FIXME: qmake: DEFINES += QDSP_P_H=$$shell_quote(\"@PWD@/text/qdoublescanprint_p.h\")
+"
+ CXX_STANDARD 23
)
-
-
#### Features
qt_feature("clock-gettime" PRIVATE
@@ -553,6 +441,11 @@ qt_feature("clock-monotonic" PUBLIC
CONDITION QT_FEATURE_clock_gettime AND TEST_clock_monotonic
)
qt_feature_definition("clock-monotonic" "QT_NO_CLOCK_MONOTONIC" NEGATE VALUE "1")
+qt_feature("close_range" PRIVATE
+ LABEL "close_range()"
+ CONDITION QT_FEATURE_process AND TEST_close_range
+ AUTODETECT UNIX
+)
qt_feature("doubleconversion" PRIVATE
LABEL "DoubleConversion"
)
@@ -565,7 +458,7 @@ qt_feature("system-doubleconversion" PRIVATE
)
qt_feature("cxx11_future" PUBLIC
LABEL "C++11 <future>"
- CONDITION TEST_cxx11_future
+ CONDITION NOT VXWORKS
)
qt_feature("cxx17_filesystem" PUBLIC
LABEL "C++17 <filesystem>"
@@ -575,11 +468,6 @@ qt_feature("dladdr" PRIVATE
LABEL "dladdr"
CONDITION QT_FEATURE_dlopen AND TEST_dladdr
)
-qt_feature("eventfd" PUBLIC
- LABEL "eventfd"
- CONDITION NOT WASM AND TEST_eventfd
-)
-qt_feature_definition("eventfd" "QT_NO_EVENTFD" NEGATE VALUE "1")
qt_feature("futimens" PRIVATE
LABEL "futimens()"
CONDITION NOT WIN32 AND TEST_futimens
@@ -598,11 +486,6 @@ qt_feature("glib" PUBLIC PRIVATE
CONDITION GLIB2_FOUND
)
qt_feature_definition("glib" "QT_NO_GLIB" NEGATE VALUE "1")
-qt_feature("glibc" PRIVATE
- LABEL "GNU libc"
- AUTODETECT ( LINUX OR HURD )
- CONDITION TEST_glibc
-)
qt_feature("icu" PRIVATE
LABEL "ICU"
AUTODETECT NOT WIN32
@@ -617,7 +500,7 @@ qt_feature("ipc_posix"
LABEL "Defaulting legacy IPC to POSIX"
CONDITION TEST_posix_shm AND TEST_posix_sem AND (
FEATURE_ipc_posix OR (APPLE AND QT_FEATURE_appstore_compliant)
- OR NOT (TEST_sysv_shm AND TEST_sysv_sem)
+ OR NOT TEST_sysv_shm OR NOT TEST_sysv_sem
)
)
qt_feature_definition("ipc_posix" "QT_POSIX_IPC")
@@ -688,7 +571,7 @@ qt_feature("poll_select" PRIVATE
qt_feature_definition("poll_select" "QT_NO_NATIVE_POLL")
qt_feature("posix_sem" PRIVATE
LABEL "POSIX semaphores"
- CONDITION TEST_posix_sem
+ CONDITION TEST_posix_sem AND QT_FEATURE_systemsemaphore
)
qt_feature("posix_shm" PRIVATE
LABEL "POSIX shared memory"
@@ -707,18 +590,13 @@ qt_feature("slog2" PRIVATE
LABEL "slog2"
CONDITION Slog2_FOUND
)
-qt_feature("statx" PRIVATE
- LABEL "statx() in libc"
- CONDITION ( LINUX OR HURD ) AND TEST_statx
-)
qt_feature("syslog" PRIVATE
LABEL "syslog"
AUTODETECT OFF
- CONDITION TEST_syslog
)
qt_feature("sysv_sem" PRIVATE
LABEL "System V / XSI semaphores"
- CONDITION TEST_sysv_sem
+ CONDITION TEST_sysv_sem AND QT_FEATURE_systemsemaphore
)
qt_feature("sysv_shm" PRIVATE
LABEL "System V / XSI shared memory"
@@ -741,6 +619,10 @@ qt_feature("backtrace" PRIVATE
LABEL "backtrace"
CONDITION UNIX AND QT_FEATURE_regularexpression AND WrapBacktrace_FOUND
)
+qt_feature("cxx23_stacktrace" PRIVATE
+ LABEL "C++23 <stacktrace>"
+ CONDITION TEST_cxx23_stacktrace AND QT_FEATURE_cxx2b
+)
qt_feature("sharedmemory" PUBLIC
SECTION "Kernel"
LABEL "QSharedMemory"
@@ -772,21 +654,18 @@ qt_feature("cpp-winrt" PRIVATE PUBLIC
AUTODETECT WIN32
CONDITION WIN32 AND TEST_cpp_winrt
)
-qt_feature_definition("xmlstream" "QT_NO_XMLSTREAM" NEGATE VALUE "1")
qt_feature("xmlstreamreader" PUBLIC
SECTION "Kernel"
LABEL "QXmlStreamReader"
PURPOSE "Provides a well-formed XML parser with a simple streaming API."
CONDITION QT_FEATURE_xmlstream
)
-qt_feature_definition("xmlstreamreader" "QT_NO_XMLSTREAMREADER" NEGATE VALUE "1")
qt_feature("xmlstreamwriter" PUBLIC
SECTION "Kernel"
LABEL "QXmlStreamWriter"
PURPOSE "Provides a XML writer with a simple streaming API."
CONDITION QT_FEATURE_xmlstream
)
-qt_feature_definition("xmlstreamwriter" "QT_NO_XMLSTREAMWRITER" NEGATE VALUE "1")
qt_feature("textdate" PUBLIC
SECTION "Data structures"
LABEL "Text Date"
@@ -829,7 +708,7 @@ qt_feature("library" PUBLIC
SECTION "File I/O"
LABEL "QLibrary"
PURPOSE "Provides a wrapper for dynamically loaded libraries."
- CONDITION WIN32 OR HPUX OR ( NOT NACL AND QT_FEATURE_dlopen )
+ CONDITION WIN32 OR HPUX OR QT_FEATURE_dlopen
)
qt_feature_definition("library" "QT_NO_LIBRARY" NEGATE VALUE "1")
qt_feature("settings" PUBLIC
@@ -947,7 +826,13 @@ qt_feature("timezone" PUBLIC
SECTION "Utilities"
LABEL "QTimeZone"
PURPOSE "Provides support for time-zone handling."
- CONDITION NOT WASM
+ CONDITION NOT WASM AND NOT VXWORKS
+)
+qt_feature("timezone_locale" PRIVATE
+ SECTION "Utilities"
+ LABEL "QTimeZone"
+ PURPOSE "Provides support for localized time-zone display names."
+ DISABLE ON # Implementation is currently incomplete, so leave turned off
)
qt_feature("datetimeparser" PRIVATE
SECTION "Utilities"
@@ -1004,11 +889,17 @@ qt_feature("permissions" PUBLIC
SECTION "Utilities"
LABEL "Application permissions"
PURPOSE "Provides support for requesting user permission to access restricted data or APIs"
- CONDITION APPLE OR ANDROID OR WASM
+)
+qt_feature("openssl-hash" PRIVATE
+ LABEL "OpenSSL based cryptographic hash"
+ AUTODETECT OFF
+ CONDITION QT_FEATURE_openssl_linked AND QT_FEATURE_opensslv30
+ PURPOSE "Uses OpenSSL based implementation of cryptographic hash algorithms."
)
qt_configure_add_summary_section(NAME "Qt Core")
qt_configure_add_summary_entry(ARGS "backtrace")
+qt_configure_add_summary_entry(ARGS "cxx23_stacktrace")
qt_configure_add_summary_entry(ARGS "doubleconversion")
qt_configure_add_summary_entry(ARGS "system-doubleconversion")
qt_configure_add_summary_entry(ARGS "forkfd_pidfd" CONDITION LINUX)
@@ -1023,6 +914,7 @@ qt_configure_add_summary_entry(
ARGS "etw lttng ctf"
MESSAGE "Tracing backend"
)
+qt_configure_add_summary_entry(ARGS "openssl-hash")
qt_configure_add_summary_section(NAME "Logging backends")
qt_configure_add_summary_entry(ARGS "journald")
qt_configure_add_summary_entry(ARGS "syslog")
@@ -1042,16 +934,6 @@ qt_configure_add_report_entry(
)
qt_configure_add_report_entry(
TYPE ERROR
- MESSAGE "C++11 <random> is required and is missing or failed to compile."
- CONDITION NOT TEST_cxx11_random
-)
-qt_configure_add_report_entry(
- TYPE ERROR
- MESSAGE "Your C library does not provide sscanf_l or snprintf_l. You need to use libdouble-conversion for double/string conversion."
- CONDITION INPUT_doubleconversion STREQUAL 'no' AND NOT TEST_xlocalescanprint
-)
-qt_configure_add_report_entry(
- TYPE ERROR
MESSAGE "detected a std::atomic implementation that fails for function pointers. Please apply the patch corresponding to your Standard Library vendor, found in qtbase/config.tests/atomicfptr"
CONDITION NOT TEST_atomicfptr
)
diff --git a/src/corelib/debug_script.py b/src/corelib/debug_script.py
index f6207c6104..b4a58530da 100644
--- a/src/corelib/debug_script.py
+++ b/src/corelib/debug_script.py
@@ -34,10 +34,6 @@ def import_bridge(path, debugger, session_dict, reload_module=False):
return bridge
-def report_success(bridge):
- print("Using Qt summary providers from Creator {} in '{}'".format(
- bridge.CREATOR_VERSION, bridge.CREATOR_PATH))
-
def __lldb_init_module(debugger, session_dict):
# Check if the module has already been imported globally. This ensures
# that the Qt Creator application search is only performed once per
@@ -48,28 +44,36 @@ def __lldb_init_module(debugger, session_dict):
bridge = import_bridge(module.__file__, debugger, session_dict,
reload_module = True)
if bridge:
- report_success(bridge)
return
versions = {}
- for install in os.popen(
- 'mdfind kMDItemCFBundleIdentifier=org.qt-project.qtcreator'
- '| while read p;'
- 'do echo $p=$(mdls "$p" -name kMDItemVersion -raw);'
- 'done'):
- install = install.strip()
- (p, v) = install.split('=')
- versions[v] = p
+ for path in os.popen('mdfind kMDItemCFBundleIdentifier=org.qt-project.qtcreator'):
+ path = path.strip()
+ file = open(os.path.join(path, 'Contents', 'Info.plist'), "rb")
+
+ import plistlib
+ plist = plistlib.load(file)
+
+ version = None
+ for key in ["CFBundleVersion", "CFBundleShortVersionString"]:
+ if key in plist:
+ version = plist[key]
+ break
+
+ if not version:
+ print(f"Could not resolve version for '{path}'. Ignoring.")
+ continue
+
+ versions[version] = path
+
+ if not len(versions):
+ print("Could not find Qt Creator installation. No Qt summary providers installed.")
+ return
for version in sorted(versions, key=LooseVersion, reverse=True):
path = versions[version]
-
+ print(f"Loading Qt summary providers from Creator {version} in '{path}'")
bridge_path = '{}/Contents/Resources/debugger/lldbbridge.py'.format(path)
bridge = import_bridge(bridge_path, debugger, session_dict)
if bridge:
- bridge.CREATOR_VERSION = version
- bridge.CREATOR_PATH = path
- report_success(bridge)
return
-
- print("Could not find Qt Creator installation, no Qt summary providers installed")
diff --git a/src/corelib/doc/include/QtCoreDoc b/src/corelib/doc/include/QtCoreDoc
index f3c875e49a..5f5490cbc9 100644
--- a/src/corelib/doc/include/QtCoreDoc
+++ b/src/corelib/doc/include/QtCoreDoc
@@ -1,3 +1,4 @@
#include <QtCore/QtCore>
#include "../../platform/android/qandroidextras_p.h"
#include "../../kernel/qpermissions.h"
+#include "../../tools/qatomicscopedvaluerollback_p.h"
diff --git a/src/corelib/doc/qtcore.qdocconf b/src/corelib/doc/qtcore.qdocconf
index a3966397f8..4ed46ae6dd 100644
--- a/src/corelib/doc/qtcore.qdocconf
+++ b/src/corelib/doc/qtcore.qdocconf
@@ -60,5 +60,11 @@ excludefiles += ../kernel/qtestsupport_core.cpp
navigation.landingpage = "Qt Core"
navigation.cppclassespage = "Qt Core C++ Classes"
-# Fail the documentation build if there are more warnings than the limit
-warninglimit = 0
+# Highlighted examples in Data Processing & IO category
+manifestmeta.highlighted.names = \
+ "QtCore/Mandelbrot" \
+ "QtCore/Serialization Converter" \
+ "QtCore/QXmlStream Bookmarks Example"
+
+# Temporarily allow warning: No such parameter 'other' in QFlags::operator=()
+warninglimit = 1
diff --git a/src/corelib/doc/snippets/cmake-macros/deployment.cmake b/src/corelib/doc/snippets/cmake-macros/deployment.cmake
index 754e3ee759..ef7aa726c0 100644
--- a/src/corelib/doc/snippets/cmake-macros/deployment.cmake
+++ b/src/corelib/doc/snippets/cmake-macros/deployment.cmake
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#! [qt_generate_deploy_script_example]
cmake_minimum_required(VERSION 3.16...3.22)
diff --git a/src/corelib/doc/snippets/cmake-macros/examples.cmake b/src/corelib/doc/snippets/cmake-macros/examples.cmake
index 2ed094cb72..09b7470962 100644
--- a/src/corelib/doc/snippets/cmake-macros/examples.cmake
+++ b/src/corelib/doc/snippets/cmake-macros/examples.cmake
@@ -1,20 +1,46 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-#! [qt_wrap_cpp]
+#! [qt_wrap_cpp_1]
set(SOURCES myapp.cpp main.cpp)
qt_wrap_cpp(SOURCES myapp.h)
-add_executable(myapp ${SOURCES})
-#! [qt_wrap_cpp]
+qt_add_executable(myapp ${SOURCES})
+#! [qt_wrap_cpp_1]
+
+#! [qt_wrap_cpp_2]
+set(SOURCES myapp.cpp main.cpp)
+qt_wrap_cpp(SOURCES myapp.h
+ TARGET myapp
+ OPTIONS
+ "$<$<CONFIG:Debug>:-DMY_OPTION_FOR_DEBUG>"
+ "-DDEFINE_CMDLINE_SIGNAL=void cmdlineSignal(const QMap<int, int> &i)"
+ "$<$<CONFIG:Debug>:-DDEFINE_CMDLINE_SIGNAL_IN_GENEX=void cmdlineSignal(const QMap<int$<COMMA> int$<ANGLE-R> &i)>")
+qt_add_executable(myapp ${SOURCES})
+#! [qt_wrap_cpp_2]
+
+#! [qt_wrap_cpp_3]
+set(SOURCES myapp.cpp main.cpp)
+qt_wrap_cpp(SOURCES myapp.h
+ TARGET myapp)
+qt_add_executable(myapp ${SOURCES})
+target_compile_definitions(myapp PRIVATE "$<$<CONFIG:Debug>:MY_OPTION_FOR_DEBUG>"
+ "DEFINE_CMDLINE_SIGNAL=void cmdlineSignal(const QMap<int, int> &i)"
+ "$<$<BOOL:TRUE>:DEFINE_CMDLINE_SIGNAL_IN_GENEX=void cmdlineSignal(const QMap<int$<COMMA> int$<ANGLE-R> &i)>")
+#! [qt_wrap_cpp_3]
+
+#! [qt_wrap_cpp_4]
+qt_add_executable(myapp myapp.cpp main.cpp)
+qt_wrap_cpp("" myapp.cpp TARGET myapp)
+#! [qt_wrap_cpp_4]
#! [qt_add_resources]
set(SOURCES main.cpp)
qt_add_resources(SOURCES example.qrc)
-add_executable(myapp ${SOURCES})
+qt_add_executable(myapp ${SOURCES})
#! [qt_add_resources]
#! [qt_add_resources_target]
-add_executable(myapp main.cpp)
+qt_add_executable(myapp main.cpp)
qt_add_resources(myapp "images"
PREFIX "/images"
FILES image1.png image2.png)
@@ -28,7 +54,7 @@ qt_add_big_resources(SOURCES big_resource.qrc)
list(APPEND SOURCES big_resource.qrc)
set_property(SOURCE big_resource.qrc PROPERTY SKIP_AUTORCC ON)
-add_executable(myapp ${SOURCES})
+qt_add_executable(myapp ${SOURCES})
#! [qt_add_big_resources]
#! [qt_add_binary_resources]
@@ -41,7 +67,7 @@ qt_generate_moc(main.cpp main.moc TARGET myapp)
#! [qt_generate_moc]
#! [qt_import_plugins]
-add_executable(myapp main.cpp)
+qt_add_executable(myapp main.cpp)
target_link_libraries(myapp Qt::Gui Qt::Sql)
qt_import_plugins(myapp
INCLUDE Qt::QCocoaIntegrationPlugin
diff --git a/src/corelib/doc/snippets/cmake-macros/examples.cpp b/src/corelib/doc/snippets/cmake-macros/examples.cpp
new file mode 100644
index 0000000000..b17fcd8e77
--- /dev/null
+++ b/src/corelib/doc/snippets/cmake-macros/examples.cpp
@@ -0,0 +1,16 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [qt_wrap_cpp_4]
+// myapp.cpp
+#include "myapp.h"
+#include <QObject>
+
+class MyApp : public QObject {
+ Q_OBJECT
+public:
+ MyApp() = default;
+};
+
+#include "myapp.moc"
+//! [qt_wrap_cpp_4]
diff --git a/src/corelib/doc/snippets/code/doc_src_containers.cpp b/src/corelib/doc/snippets/code/doc_src_containers.cpp
index 680a099f68..b568462492 100644
--- a/src/corelib/doc/snippets/code/doc_src_containers.cpp
+++ b/src/corelib/doc/snippets/code/doc_src_containers.cpp
@@ -1,6 +1,8 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
+
//! [0]
class Employee
{
@@ -226,13 +228,6 @@ foreach (const QString &str, map.uniqueKeys()) {
//! [20]
-//! [21]
-forever {
- ...
-}
-//! [21]
-
-
//! [22]
CONFIG += no_keywords
//! [22]
diff --git a/src/corelib/doc/snippets/code/doc_src_properties.cpp b/src/corelib/doc/snippets/code/doc_src_properties.cpp
index bb369e6456..190a843710 100644
--- a/src/corelib/doc/snippets/code/doc_src_properties.cpp
+++ b/src/corelib/doc/snippets/code/doc_src_properties.cpp
@@ -68,6 +68,9 @@ public:
void setPriority(Priority priority)
{
+ if (m_priority == priority)
+ return;
+
m_priority = priority;
emit priorityChanged(priority);
}
@@ -93,7 +96,7 @@ object->setProperty("priority", "VeryHigh");
//! [7]
-Q_CLASSINFO("Version", "3.0.0")
+Q_CLASSINFO("DefaultProperty", "content")
//! [7]
//! [8]
diff --git a/src/corelib/doc/snippets/code/doc_src_qalgorithms.cpp b/src/corelib/doc/snippets/code/doc_src_qalgorithms.cpp
index 201517aa2a..f2b94a7416 100644
--- a/src/corelib/doc/snippets/code/doc_src_qalgorithms.cpp
+++ b/src/corelib/doc/snippets/code/doc_src_qalgorithms.cpp
@@ -1,15 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-//! [0]
-double pi = 3.14;
-double e = 2.71;
-
-qSwap(pi, e);
-// pi == 2.71, e == 3.14
-//! [0]
-
-
//! [1]
QList<Employee *> list;
list.append(new Employee("Blackpool", "Stephen"));
diff --git a/src/corelib/doc/snippets/code/doc_src_qiterator.cpp b/src/corelib/doc/snippets/code/doc_src_qiterator.cpp
index f033a7e1bb..0d921b87e6 100644
--- a/src/corelib/doc/snippets/code/doc_src_qiterator.cpp
+++ b/src/corelib/doc/snippets/code/doc_src_qiterator.cpp
@@ -25,15 +25,6 @@ while (i.hasNext())
float f = i.next();
//! [6]
-
-//! [7]
-QSetIterator<QString> i(set);
-i.toBack();
-while (i.hasPrevious())
- QString s = i.previous();
-//! [7]
-
-
//! [8]
QList<float> list;
...
diff --git a/src/corelib/doc/snippets/code/doc_src_qnamespace.qdoc b/src/corelib/doc/snippets/code/doc_src_qnamespace.qdoc
index 41fc57df40..6ce29308f1 100644
--- a/src/corelib/doc/snippets/code/doc_src_qnamespace.qdoc
+++ b/src/corelib/doc/snippets/code/doc_src_qnamespace.qdoc
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
//! [0]
QObject::connect: Cannot queue arguments of type 'MyType'
diff --git a/src/corelib/doc/snippets/code/doc_src_qplugin.cpp b/src/corelib/doc/snippets/code/doc_src_qplugin.cpp
index 2d6e4a430f..3bca27b966 100644
--- a/src/corelib/doc/snippets/code/doc_src_qplugin.cpp
+++ b/src/corelib/doc/snippets/code/doc_src_qplugin.cpp
@@ -22,9 +22,3 @@ class MyInstance : public QObject
//! [2]
Q_IMPORT_PLUGIN(qjpeg)
//! [2]
-
-
-//! [3]
-TEMPLATE = app
-QTPLUGIN += qjpeg qgif # image formats
-//! [3]
diff --git a/src/corelib/doc/snippets/code/doc_src_qset.cpp b/src/corelib/doc/snippets/code/doc_src_qset.cpp
index 64e0b6e450..98a6f336f5 100644
--- a/src/corelib/doc/snippets/code/doc_src_qset.cpp
+++ b/src/corelib/doc/snippets/code/doc_src_qset.cpp
@@ -34,18 +34,15 @@ while (i.hasNext()) {
//! [5]
-QSet<QWidget *>::const_iterator i = set.constBegin();
-while (i != set.constEnd()) {
+for (auto i = set.cbegin(), end = set.cend(); i != end; ++i)
qDebug() << *i;
- ++i;
-}
//! [5]
//! [6]
QSet<QString> set;
...
-foreach (const QString &value, set)
+for (const auto &value : set)
qDebug() << value;
//! [6]
@@ -59,20 +56,18 @@ for (int i = 0; i < 20000; ++i)
//! [8]
-QSet<QString> set;
-set << "January" << "February" << ... << "December";
+QSet<QString> set = {"January", "February", ... "December"}
-QSet<QString>::iterator i;
-for (i = set.begin(); i != set.end(); ++i)
+// i is a QSet<QString>::iterator
+for (auto i = set.begin(), end = set.end(); i != end; ++i)
qDebug() << *i;
//! [8]
//! [9]
-QSet<QString> set;
-set << "January" << "February" << ... << "December";
+QSet<QString> set = {"January", "February", ... "December"};
-QSet<QString>::iterator i = set.begin();
+auto i = set.begin();
while (i != set.end()) {
if ((*i).startsWith('J')) {
i = set.erase(i);
@@ -94,11 +89,10 @@ if (it != set.end())
//! [11]
-QSet<QString> set;
-set << "January" << "February" << ... << "December";
+QSet<QString> set = {"January", "February", ... "December"};
-QSet<QString>::const_iterator i;
-for (i = set.begin(); i != set.end(); ++i)
+// i is QSet<QString>::const_iterator
+for (auto i = set.cbegin(), end = set.cend(); i != end; ++i)
qDebug() << *i;
//! [11]
@@ -111,23 +105,3 @@ QSet<QString>::const_iterator it = std::find_if(set.cbegin(), set.cend(), predic
if (it != set.constEnd())
cout << "Found Jeanette" << endl;
//! [12]
-
-
-//! [13]
-QSet<QString> set;
-set << "red" << "green" << "blue" << ... << "black";
-
-QList<QString> list = set.toList();
-std::sort(list.begin(), list.end());
-//! [13]
-
-
-//! [14]
-QStringList list;
-list << "Julia" << "Mike" << "Mike" << "Julia" << "Julia";
-
-QSet<QString> set = QSet<QString>::fromList(list);
-set.contains("Julia"); // returns true
-set.contains("Mike"); // returns true
-set.size(); // returns 2
-//! [14]
diff --git a/src/corelib/doc/snippets/code/doc_src_resources.cpp b/src/corelib/doc/snippets/code/doc_src_resources.cpp
index 5df085d145..04ecf810ec 100644
--- a/src/corelib/doc/snippets/code/doc_src_resources.cpp
+++ b/src/corelib/doc/snippets/code/doc_src_resources.cpp
@@ -15,16 +15,3 @@ MyClass::MyClass() : BaseClass()
...
}
//! [5]
-
-
-//! [6]
-int main(int argc, char *argv[])
-{
- QApplication app(argc, argv);
- Q_INIT_RESOURCE(graphlib);
-
- QFile file(":/graph.png");
- ...
- return app.exec();
-}
-//! [6]
diff --git a/src/corelib/doc/snippets/code/doc_src_resources.qdoc b/src/corelib/doc/snippets/code/doc_src_resources.qdoc
index f5a12ee86a..70c2a7b7ab 100644
--- a/src/corelib/doc/snippets/code/doc_src_resources.qdoc
+++ b/src/corelib/doc/snippets/code/doc_src_resources.qdoc
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
//! [0]
<file alias="cut-img.png">images/cut.png</file>
diff --git a/src/corelib/doc/snippets/code/qlogging/qlogging.cpp b/src/corelib/doc/snippets/code/qlogging/qlogging.cpp
index d1c3c7b00d..e61eb70df3 100644
--- a/src/corelib/doc/snippets/code/qlogging/qlogging.cpp
+++ b/src/corelib/doc/snippets/code/qlogging/qlogging.cpp
@@ -1,14 +1,16 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
+
#include <QtGui>
#include <QtDebug>
-#include <QDeclarativeComponent>
+#include <QQmlComponent>
//! [1]
- void statusChanged(QDeclarativeComponent::Status status) {
- if (status == QDeclarativeComponent::Error) {
- foreach (const QDeclarativeError &error, component->errors()) {
+ void statusChanged(QQmlComponent::Status status) {
+ if (status == QQmlComponent::Error) {
+ for (const QQmlError &error: std::as_const(component->errors())) {
const QByteArray file = error.url().toEncoded();
QMessageLogger(file.constData(), error.line(), 0).debug() << error.description();
}
diff --git a/src/corelib/doc/snippets/code/src_corelib_animation_qpropertyanimation.cpp b/src/corelib/doc/snippets/code/src_corelib_animation_qpropertyanimation.cpp
index f8b74cd542..4b77ab607d 100644
--- a/src/corelib/doc/snippets/code/src_corelib_animation_qpropertyanimation.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_animation_qpropertyanimation.cpp
@@ -6,7 +6,7 @@
#include <QApplication>
#include <QPushButton>
#include <QPropertyAnimation>
-//! [1]
+
class MyButtonWidget : public QWidget
{
public:
@@ -31,7 +31,6 @@ int main(int argc, char *argv[])
buttonAnimWidget.show();
return a.exec();
}
-//! [1]
//! [0]
diff --git a/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp b/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp
index 096e36dc72..25d3abf67e 100644
--- a/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_global_qglobal.cpp
@@ -32,17 +32,6 @@ Q_FLAG(Options)
typedef QFlags<Enum> Flags;
//! [2]
-
-//! [3]
-int myValue = 10;
-int minValue = 2;
-int maxValue = 6;
-
-int boundedValue = qBound(minValue, myValue, maxValue);
-// boundedValue == 6
-//! [3]
-
-
//! [4]
if (!driver()->isOpen() || driver()->isOpenError()) {
qWarning("QSqlQuery::exec: database not open");
@@ -61,11 +50,6 @@ quint64 value = Q_UINT64_C(932838457459459);
//! [6]
-//! [7]
-void myMsgHandler(QtMsgType, const char *);
-//! [7]
-
-
//! [8]
qint64 value = Q_INT64_C(932838457459459);
//! [8]
@@ -226,37 +210,26 @@ const TInputType &myMin(const TInputType &value1, const TInputType &value2)
//! [23]
-#include <qapplication.h>
+#include <QApplication>
#include <stdio.h>
#include <stdlib.h>
-void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
+QtMessageHandler originalHandler = nullptr;
+
+void logToFile(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
- QByteArray localMsg = msg.toLocal8Bit();
- const char *file = context.file ? context.file : "";
- const char *function = context.function ? context.function : "";
- switch (type) {
- case QtDebugMsg:
- fprintf(stderr, "Debug: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
- break;
- case QtInfoMsg:
- fprintf(stderr, "Info: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
- break;
- case QtWarningMsg:
- fprintf(stderr, "Warning: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
- break;
- case QtCriticalMsg:
- fprintf(stderr, "Critical: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
- break;
- case QtFatalMsg:
- fprintf(stderr, "Fatal: %s (%s:%u, %s)\n", localMsg.constData(), file, context.line, function);
- break;
- }
+ QString message = qFormatLogMessage(type, context, msg);
+ static FILE *f = fopen("log.txt", "a");
+ fprintf(f, "%s\n", qPrintable(message));
+ fflush(f);
+
+ if (originalHandler)
+ *originalHandler(type, context, msg);
}
int main(int argc, char **argv)
{
- qInstallMessageHandler(myMessageOutput);
+ originalHandler = qInstallMessageHandler(logToFile);
QApplication app(argc, argv);
...
return app.exec();
@@ -579,11 +552,6 @@ qFuzzyCompare(0.0, 1.0e-200); // This will return false
qFuzzyCompare(1 + 0.0, 1 + 1.0e-200); // This will return true
//! [46]
-//! [47]
-CApaApplication *myApplicationFactory();
-//! [47]
-
-
//! [49]
void myMessageHandler(QtMsgType, const QMessageLogContext &, const QString &);
//! [49]
@@ -667,19 +635,6 @@ bool readConfiguration(const QFile &file)
}
//! [qunreachable-switch]
-//! [qunreachable-return]
- switch (shape) {
- case Rectangle:
- return rectangle();
- case Triangle:
- return triangle();
- case Circle:
- return circle();
- case NumShapes:
- Q_UNREACHABLE_RETURN(nullptr);
- }
-//! [qunreachable-return]
-
//! [qt-version-check]
#include <QtGlobal>
diff --git a/src/corelib/doc/snippets/code/src_corelib_io_qabstractfileengine.cpp b/src/corelib/doc/snippets/code/src_corelib_io_qabstractfileengine.cpp
index 8c80ec1eba..4300fc2da9 100644
--- a/src/corelib/doc/snippets/code/src_corelib_io_qabstractfileengine.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_io_qabstractfileengine.cpp
@@ -1,17 +1,21 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+using namespace Qt::StringLiterals;
+
//! [0]
class ZipEngineHandler : public QAbstractFileEngineHandler
{
public:
- QAbstractFileEngine *create(const QString &fileName) const override;
+ std::unique_ptr<QAbstractFileEngine> create(const QString &fileName) const override;
};
-QAbstractFileEngine *ZipEngineHandler::create(const QString &fileName) const
+std::unique_ptr<QAbstractFileEngine> ZipEngineHandler::create(const QString &fileName) const
{
// ZipEngineHandler returns a ZipEngine for all .zip files
- return fileName.toLower().endsWith(".zip") ? new ZipEngine(fileName) : 0;
+ if (fileName.toLower().endsWith(".zip"_L1))
+ return std::make_unique<ZipEngine>(fileName);
+ return {};
}
int main(int argc, char **argv)
@@ -27,21 +31,24 @@ int main(int argc, char **argv)
}
//! [0]
-
//! [1]
-QAbstractSocketEngine *ZipEngineHandler::create(const QString &fileName) const
+std::unique_ptr<QAbstractFileEngine> ZipEngineHandler::create(const QString &fileName) const
{
// ZipEngineHandler returns a ZipEngine for all .zip files
- return fileName.toLower().endsWith(".zip") ? new ZipEngine(fileName) : 0;
+ if (fileName.toLower().endsWith(".zip"_L1))
+ return std::make_unique<ZipEngine>(fileName);
+ else
+ return {};
}
//! [1]
//! [2]
-QAbstractFileEngineIterator *
-CustomFileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames)
+QAbstractFileEngine::IteratorUniquePtr
+CustomFileEngine::beginEntryList(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames)
{
- return new CustomFileEngineIterator(filters, filterNames);
+ return std::make_unique<CustomFileEngineIterator>(path, filters, filterNames);
}
//! [2]
@@ -50,25 +57,23 @@ CustomFileEngine::beginEntryList(QDir::Filters filters, const QStringList &filte
class CustomIterator : public QAbstractFileEngineIterator
{
public:
- CustomIterator(const QStringList &nameFilters, QDir::Filters filters)
- : QAbstractFileEngineIterator(nameFilters, filters), index(0)
+ CustomIterator(const QString &path, const QStringList &nameFilters, QDir::Filters filters)
+ : QAbstractFileEngineIterator(path, nameFilters, filters), index(0)
{
// In a real iterator, these entries are fetched from the
// file system based on the value of path().
entries << "entry1" << "entry2" << "entry3";
}
- bool hasNext() const override
- {
- return index < entries.size() - 1;
- }
-
- QString next() override
+ bool advance() override
{
- if (!hasNext())
- return QString();
- ++index;
- return currentFilePath();
+ if (entries.isEmpty())
+ return false;
+ if (index < entries.size() - 1) {
+ ++index;
+ return true;
+ }
+ return false;
}
QString currentFileName() override
diff --git a/src/corelib/doc/snippets/code/src_corelib_io_qdirlisting.cpp b/src/corelib/doc/snippets/code/src_corelib_io_qdirlisting.cpp
new file mode 100644
index 0000000000..231bf48d26
--- /dev/null
+++ b/src/corelib/doc/snippets/code/src_corelib_io_qdirlisting.cpp
@@ -0,0 +1,70 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QDirListing>
+
+using namespace Qt::StringLiterals;
+
+[[maybe_unused]] static void func() {
+{
+//! [0]
+using ItFlag = QDirListing::IteratorFlag;
+for (const auto &dirEntry : QDirListing(u"/etc"_s, ItFlag::Recursive)) {
+ qDebug() << dirEntry.filePath();
+ // /etc/.
+ // /etc/..
+ // /etc/X11
+ // /etc/X11/fs
+ // ...
+}
+//! [0]
+}
+
+{
+//! [1]
+using ItFlag = QDirListing::IteratorFlag;
+QDirListing dirList(u"/sys"_s, QStringList{u"scaling_cur_freq"_s},
+ QDir::NoFilter, ItFlag::Recursive);
+for (const auto &dirEntry : dirList) {
+ QFile f(dirEntry.filePath());
+ f.open(QIODevice::ReadOnly);
+ qDebug() << f.fileName() << f.readAll().trimmed().toDouble() / 1000 << "MHz";
+}
+//! [1]
+}
+
+{
+//! [2]
+QDirListing audioFileIt(u"/home/johndoe/"_s, {"*.mp3", "*.wav"}, QDir::Files);
+//! [2]
+}
+
+{
+//! [3]
+using ItFlag = QDirListing::IteratorFlag;
+for (const auto &dirEntry : QDirListing(u"/etc"_s, ItFlag::Recursive)) {
+ // Faster
+ if (dirEntry.fileName().endsWith(u".conf")) { /* ... */ }
+
+ // This works, but might be potentially slower, since it has to construct a
+ // QFileInfo, whereas (depending on the implemnetation) the fileName could
+ // be known already
+ if (dirEntry.fileInfo().fileName().endsWith(u".conf")) { /* ... */ }
+}
+//! [3]
+}
+
+{
+//! [4]
+using ItFlag = QDirListing::IteratorFlag;
+for (const auto &dirEntry : QDirListing(u"/etc"_s, ItFlag::Recursive)) {
+ // Both approaches are the same, because DirEntry will have to construct
+ // a QFileInfo to get this info (for example, by calling system stat())
+
+ if (dirEntry.size() >= 4'000 /* 4KB */) { /* ...*/ }
+ if (dirEntry.fileInfo().size() >= 4'000 /* 4KB */) { /* ... */ }
+}
+//! [4]
+}
+
+}
diff --git a/src/corelib/doc/snippets/code/src_corelib_io_qfile.cpp b/src/corelib/doc/snippets/code/src_corelib_io_qfile.cpp
index 475bc874ec..3a8f7d2747 100644
--- a/src/corelib/doc/snippets/code/src_corelib_io_qfile.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_io_qfile.cpp
@@ -10,16 +10,6 @@ file.open(QIODevice::ReadOnly); // opens "/home/readme.txt" under Unix
//! [0]
-//! [1]
-QByteArray myEncoderFunc(const QString &fileName);
-//! [1]
-
-
-//! [2]
-QString myDecoderFunc(const QByteArray &localFileName);
-//! [2]
-
-
//! [3]
#include <stdio.h>
diff --git a/src/corelib/doc/snippets/code/src_corelib_io_qfileinfo.cpp b/src/corelib/doc/snippets/code/src_corelib_io_qfileinfo.cpp
index 9e548afafc..a8dd621111 100644
--- a/src/corelib/doc/snippets/code/src_corelib_io_qfileinfo.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_io_qfileinfo.cpp
@@ -1,11 +1,21 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+#include <QDir>
+#include <QFileInfo>
+using namespace Qt::StringLiterals;
+
+[[maybe_unused]] static void func()
+{
+{
//![newstuff]
- QFileInfo fi("c:/temp/foo"); => fi.absoluteFilePath() => "C:/temp/foo"
+ QFileInfo fi("c:/temp/foo");
+ qDebug() << fi.absoluteFilePath(); // "C:/temp/foo"
//![newstuff]
+}
+{
//! [0]
#ifdef Q_OS_UNIX
@@ -22,7 +32,7 @@ info2.size(); // returns 56201
#endif
//! [0]
-
+}
//! [1]
#ifdef Q_OS_WIN
@@ -41,7 +51,7 @@ info2.size(); // returns 63942
#endif
//! [1]
-
+{
//! [2]
QFileInfo info("/usr/bin/env");
@@ -53,50 +63,60 @@ info.setFile("/etc/hosts");
path = info.absolutePath(); // path = /etc
base = info.baseName(); // base = hosts
//! [2]
+}
+{
//! [3]
QFileInfo fi("/tmp/archive.tar.gz");
QString name = fi.fileName(); // name = "archive.tar.gz"
//! [3]
+}
-
+{
//! [4]
QFileInfo fi("/Applications/Safari.app");
QString bundle = fi.bundleName(); // name = "Safari"
//! [4]
+}
-
+{
//! [5]
QFileInfo fi("/tmp/archive.tar.gz");
QString base = fi.baseName(); // base = "archive"
//! [5]
+}
-
+{
//! [6]
QFileInfo fi("/tmp/archive.tar.gz");
QString base = fi.completeBaseName(); // base = "archive.tar"
//! [6]
+}
-
+{
//! [7]
QFileInfo fi("/tmp/archive.tar.gz");
QString ext = fi.completeSuffix(); // ext = "tar.gz"
//! [7]
+}
-
+{
//! [8]
QFileInfo fi("/tmp/archive.tar.gz");
QString ext = fi.suffix(); // ext = "gz"
//! [8]
+}
-
+{
+QString fileName = "foo";
//! [9]
QFileInfo info(fileName);
if (info.isSymLink())
fileName = info.symLinkTarget();
//! [9]
+}
-
+{
//! [10]
QFileInfo fi("/tmp/archive.tar.gz");
if (fi.permission(QFile::WriteUser | QFile::ReadGroup))
@@ -104,3 +124,24 @@ if (fi.permission(QFile::WriteUser | QFile::ReadGroup))
if (fi.permission(QFile::WriteGroup | QFile::WriteOther))
qWarning("The group or others can change the file");
//! [10]
+}
+
+{
+//! [11]
+// Given a current working directory of "/home/user/Documents/memos/"
+QFileInfo info1(u"relativeFile"_s);
+qDebug() << info1.absolutePath(); // "/home/user/Documents/memos/"
+qDebug() << info1.baseName(); // "relativeFile"
+qDebug() << info1.absoluteDir(); // QDir(u"/home/user/Documents/memos"_s)
+qDebug() << info1.absoluteDir().path(); // "/home/user/Documents/memos"
+
+// A QFileInfo on a dir
+QFileInfo info2(u"/home/user/Documents/memos"_s);
+qDebug() << info2.absolutePath(); // "/home/user/Documents"
+qDebug() << info2.baseName(); // "memos"
+qDebug() << info2.absoluteDir(); // QDir(u"/home/user/Documents"_s)
+qDebug() << info2.absoluteDir().path(); // "/home/user/Documents"
+//! [11]
+}
+
+}
diff --git a/src/corelib/doc/snippets/code/src_corelib_io_qsettings.cpp b/src/corelib/doc/snippets/code/src_corelib_io_qsettings.cpp
index 92e40c3667..5774add2a7 100644
--- a/src/corelib/doc/snippets/code/src_corelib_io_qsettings.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_io_qsettings.cpp
@@ -138,10 +138,10 @@ QList<Login> logins;
QSettings settings;
settings.beginWriteArray("logins");
-for (int i = 0; i < logins.size(); ++i) {
+for (qsizetype i = 0; i < logins.size(); ++i) {
settings.setArrayIndex(i);
- settings.setValue("userName", list.at(i).userName);
- settings.setValue("password", list.at(i).password);
+ settings.setValue("userName", logins.at(i).userName);
+ settings.setValue("password", logins.at(i).password);
}
settings.endArray();
//! [16]
diff --git a/src/corelib/doc/snippets/code/src_corelib_io_qstorageinfo.cpp b/src/corelib/doc/snippets/code/src_corelib_io_qstorageinfo.cpp
index d11368a83d..93029274b1 100644
--- a/src/corelib/doc/snippets/code/src_corelib_io_qstorageinfo.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_io_qstorageinfo.cpp
@@ -1,6 +1,8 @@
// Copyright (C) 2014 Ivan Komissarov
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
+
//! [0]
QStorageInfo storage(qApp->applicationDirPath());
if (storage.isValid() && storage.isReady()) {
diff --git a/src/corelib/doc/snippets/code/src_corelib_io_qtextstream.cpp b/src/corelib/doc/snippets/code/src_corelib_io_qtextstream.cpp
index bcc08c0f16..75a04e654f 100644
--- a/src/corelib/doc/snippets/code/src_corelib_io_qtextstream.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_io_qtextstream.cpp
@@ -84,9 +84,3 @@ out << "Qt rocks!" << Qt::endl;
//! [9]
stream << '\n' << Qt::flush;
//! [9]
-
-
-//! [10]
-QTextStream out(&file);
-out.setEncoding(QStringConverter::Utf8);
-//! [10]
diff --git a/src/corelib/doc/snippets/code/src_corelib_io_qurl.cpp b/src/corelib/doc/snippets/code/src_corelib_io_qurl.cpp
index f002ea6fd5..945f3ae3e7 100644
--- a/src/corelib/doc/snippets/code/src_corelib_io_qurl.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_io_qurl.cpp
@@ -39,7 +39,7 @@ sock.connectToHost(url.host(), url.port(80));
//! [4]
-http://www.example.com/cgi-bin/drawgraph.cgi?type(pie)color(green)
+http://www.example.com/cgi-bin/drawgraph.cgi?type,pie;color,green
//! [4]
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp
index 3f7dc07d9f..4fd7f97ae8 100644
--- a/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qabstractitemmodel.cpp
@@ -50,16 +50,6 @@ beginMoveRows(parent, 2, 2, parent, 0);
beginMoveRows(parent, 2, 2, parent, 4);
//! [9]
-//! [10]
-myData.clear();
-reset();
-//! [10]
-
-//! [11]
-beginResetModel();
-myData.clear();
-endResetModel();
-//! [11]
//! [12]
class CustomDataProxy : public QSortFilterProxyModel
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qcoreapplication.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qcoreapplication.cpp
index 2a3a27e94b..8087ff8f8b 100644
--- a/src/corelib/doc/snippets/code/src_corelib_kernel_qcoreapplication.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qcoreapplication.cpp
@@ -1,6 +1,8 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
+
//! [0]
QMouseEvent event(QEvent::MouseButtonPress, pos, 0, 0, 0);
QApplication::sendEvent(mainWindow, &event);
@@ -13,12 +15,6 @@ connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::Qu
//! [1]
-//! [2]
-foreach (const QString &path, app.libraryPaths())
- do_something(path);
-//! [2]
-
-
//! [3]
// Called once QCoreApplication exists
static void preRoutineMyDebugTool()
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qdeadlinetimer.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qdeadlinetimer.cpp
index a3b366a588..f7440f2bb0 100644
--- a/src/corelib/doc/snippets/code/src_corelib_kernel_qdeadlinetimer.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qdeadlinetimer.cpp
@@ -63,25 +63,25 @@
//! [7]
//! [8]
- return d1.deadlineNSecs() == d2.deadlineNSecs();
+ return lhs.deadlineNSecs() == rhs.deadlineNSecs();
//! [8]
//! [9]
- return d1.deadlineNSecs() != d2.deadlineNSecs();
+ return lhs.deadlineNSecs() != rhs.deadlineNSecs();
//! [9]
//! [10]
- return d1.deadlineNSecs() < d2.deadlineNSecs();
+ return lhs.deadlineNSecs() < rhs.deadlineNSecs();
//! [10]
//! [11]
- return d1.deadlineNSecs() <= d2.deadlineNSecs();
+ return lhs.deadlineNSecs() <= rhs.deadlineNSecs();
//! [11]
//! [12]
- return d1.deadlineNSecs() > d2.deadlineNSecs();
+ return lhs.deadlineNSecs() > rhs.deadlineNSecs();
//! [12]
//! [13]
- return d1.deadlineNSecs() >= d2.deadlineNSecs();
+ return lhs.deadlineNSecs() >= rhs.deadlineNSecs();
//! [13]
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qmetatype.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qmetatype.cpp
index a213ccbca6..757700786e 100644
--- a/src/corelib/doc/snippets/code/src_corelib_kernel_qmetatype.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qmetatype.cpp
@@ -101,16 +101,6 @@ void someFunc()
//! [11]
-//! [12]
-QPointer<QFile> fp(new QFile);
-QVariant var = QVariant::fromValue(fp);
-// ...
-if (var.canConvert<QObject*>()) {
- QObject *sp = var.value<QObject*>();
- qDebug() << sp->metaObject()->className(); // Prints 'QFile'.
-}
-//! [12]
-
//! [13]
#include <memory>
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qmimedata.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qmimedata.cpp
index 36cbdefa1c..c6a48c8827 100644
--- a/src/corelib/doc/snippets/code/src_corelib_kernel_qmimedata.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qmimedata.cpp
@@ -1,6 +1,8 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
+
//! [0]
void MyWidget::dragEnterEvent(QDragEnterEvent *event)
{
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 2c5483abce..e3bbac7a3c 100644
--- a/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qobject.cpp
@@ -129,13 +129,6 @@ void MyObject::timerEvent(QTimerEvent *event)
//! [8]
-//! [9]
-QList<QObject *> list = window()->queryList("QAbstractButton"));
-foreach (QObject *obj, list)
- static_cast<QAbstractButton *>(obj)->setEnabled(false);
-//! [9]
-
-
//! [10]
QPushButton *button = parentWidget->findChild<QPushButton *>("button1");
//! [10]
@@ -204,22 +197,6 @@ MyWindow::MyWindow()
}
-//! [18]
-int n = messages.count();
-showMessage(tr("%n message(s) saved", "", n));
-//! [18]
-
-
-//! [19]
-n == 1 ? tr("%n message saved") : tr("%n messages saved")
-//! [19]
-
-
-//! [20]
-label->setText(tr("F\374r \310lise"));
-//! [20]
-
-
//! [21]
if (receivers(SIGNAL(valueChanged(QByteArray))) > 0) {
QByteArray data;
@@ -383,21 +360,13 @@ public:
//! [39]
-//! [40]
-//: This name refers to a host name.
-hostNameLabel->setText(tr("Name:"));
-
-/*: This text refers to a C++ code example. */
-QString example = tr("Example");
-//! [40]
-
//! [41]
QPushButton *button = parentWidget->findChild<QPushButton *>("button1", Qt::FindDirectChildrenOnly);
//! [41]
//! [42]
-QListWidget *list = parentWidget->findChild<QListWidget *>(QString(), Qt::FindDirectChildrenOnly);
+QListWidget *list = parentWidget->findChild<QListWidget *>(Qt::FindDirectChildrenOnly);
//! [42]
@@ -487,18 +456,6 @@ public:
};
//! [52]
-//! [meta data]
-//: This is a comment for the translator.
-//= qtn_foo_bar
-//~ loc-layout_id foo_dialog
-//~ loc-blank False
-//~ magic-stuff This might mean something magic.
-QString text = MyMagicClass::tr("Sim sala bim.");
-//! [meta data]
-
-//! [explicit tr context]
-QString text = QScrollBar::tr("Page up");
-//! [explicit tr context]
//! [53]
{
@@ -512,3 +469,16 @@ const bool wasBlocked = someQObject->blockSignals(true);
// no signals here
someQObject->blockSignals(wasBlocked);
//! [54]
+
+{
+//! [invalid-timer-id]
+ QObject *obj;
+ ...
+ int id = obj->startTimer(100ms);
+ if (id > Qt::TimerId::Invalid)
+ // The timer has been started successfully
+
+ if (id > 0) // Equivalent, albeit less readable
+ // The timer has been started successfully
+//! [invalid-timer-id]
+}
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qvariant.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qvariant.cpp
index e0c846a587..7f3f1ce7a0 100644
--- a/src/corelib/doc/snippets/code/src_corelib_kernel_qvariant.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qvariant.cpp
@@ -1,6 +1,8 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
+
//! [0]
QDataStream out(...);
QVariant v(123); // The variant now contains an int
@@ -89,11 +91,6 @@ return QVariant::fromValue(s);
//! [7]
-//! [8]
-QObject *object = getObjectFromSomewhere();
-QVariant data = QVariant::fromValue(object);
-//! [8]
-
//! [9]
QList<int> intList = {7, 11, 42};
diff --git a/src/corelib/doc/snippets/code/src_corelib_serialization_qcborstream.cpp b/src/corelib/doc/snippets/code/src_corelib_serialization_qcborstream.cpp
index 90f89d8bd1..acb5a6272e 100644
--- a/src/corelib/doc/snippets/code/src_corelib_serialization_qcborstream.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_serialization_qcborstream.cpp
@@ -183,7 +183,7 @@ using namespace Qt::StringLiterals;
//! [21]
//! [22]
- void appendMap(QCborStreamWriter &writer, const QList<QPair<int, QString>> &values)
+ void appendMap(QCborStreamWriter &writer, const QList<std::pair<int, QString>> &values)
{
writer.startMap();
for (const auto pair : values) {
@@ -198,7 +198,7 @@ using namespace Qt::StringLiterals;
void appendMap(QCborStreamWriter &writer, const QMap<int, QString> &map)
{
writer.startMap(map.size());
- for (auto it = map.begin(); it != map.end(); ++it) {
+ for (auto it = map.cbegin(), end = map.cend(); it != end; ++it) {
writer.append(it.key());
writer.append(it.value());
}
@@ -271,12 +271,12 @@ using namespace Qt::StringLiterals;
{
QString result;
auto r = reader.readString();
- while (r.code == QCborStreamReader::Ok) {
+ while (r.status == QCborStreamReader::Ok) {
result += r.data;
r = reader.readString();
}
- if (r.code == QCborStreamReader::Error) {
+ if (r.status == QCborStreamReader::Error) {
// handle error condition
result.clear();
}
@@ -289,12 +289,12 @@ using namespace Qt::StringLiterals;
{
QBytearray result;
auto r = reader.readBytearray();
- while (r.code == QCborStreamReader::Ok) {
+ while (r.status == QCborStreamReader::Ok) {
result += r.data;
r = reader.readByteArray();
}
- if (r.code == QCborStreamReader::Error) {
+ if (r.status == QCborStreamReader::Error) {
// handle error condition
result.clear();
}
diff --git a/src/corelib/doc/snippets/code/src_corelib_serialization_qdatastream.cpp b/src/corelib/doc/snippets/code/src_corelib_serialization_qdatastream.cpp
index 296a341b11..dfdebe6a76 100644
--- a/src/corelib/doc/snippets/code/src_corelib_serialization_qdatastream.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_serialization_qdatastream.cpp
@@ -2,11 +2,11 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
- QDataStream &operator<<(QDataStream &, const QXxx &);
- QDataStream &operator>>(QDataStream &, QXxx &);
+QDataStream &operator<<(QDataStream &, const QXxx &);
+QDataStream &operator>>(QDataStream &, QXxx &);
//! [0]
//! [1]
- QDataStream & operator<< (QDataStream& stream, const QImage& image);
- QDataStream & operator>> (QDataStream& stream, QImage& image);
+QDataStream &operator<<(QDataStream &stream, const QImage &image);
+QDataStream &operator>>(QDataStream &stream, QImage &image);
//! [1]
diff --git a/src/corelib/doc/snippets/code/src_corelib_text_qbytearray.cpp b/src/corelib/doc/snippets/code/src_corelib_text_qbytearray.cpp
index 308fe0a5ac..a4fecc41f9 100644
--- a/src/corelib/doc/snippets/code/src_corelib_text_qbytearray.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_text_qbytearray.cpp
@@ -24,7 +24,7 @@ ba[4] = 0xca;
//! [2]
for (qsizetype i = 0; i < ba.size(); ++i) {
if (ba.at(i) >= 'a' && ba.at(i) <= 'f')
- cout << "Found character in range [a-f]" << Qt::endl;
+ cout << "Found character in range [a-f]" << endl;
}
//! [2]
@@ -41,7 +41,7 @@ x.replace(5, 3, "&"); // x == "rock & roll"
QByteArray ba("We must be <b>bold</b>, very <b>bold</b>");
qsizetype j = 0;
while ((j = ba.indexOf("<b>", j)) != -1) {
- cout << "Found <b> tag at index position " << j << Qt::endl;
+ cout << "Found <b> tag at index position " << j << endl;
++j;
}
//! [4]
@@ -79,7 +79,7 @@ QByteArray("abc").isEmpty(); // returns false
QByteArray ba("Hello world");
char *data = ba.data();
while (*data) {
- cout << "[" << *data << "]" << Qt::endl;
+ cout << "[" << *data << "]" << endl;
++data;
}
//! [8]
@@ -472,4 +472,10 @@ QByteArray byteArray = "test";
emscripten::val uint8array = QByteArray::toEcmaUint8Array(byteArray);
//! [56]
+//! [57]
+QByteArray x = "Five pineapples"_ba;
+x.slice(5); // x == "pineapples"
+x.slice(4, 3); // x == "app"
+//! [57]
+
}
diff --git a/src/corelib/doc/snippets/code/src_corelib_text_qstaticlatin1stringmatcher.cpp b/src/corelib/doc/snippets/code/src_corelib_text_qstaticlatin1stringmatcher.cpp
new file mode 100644
index 0000000000..ae6e19e471
--- /dev/null
+++ b/src/corelib/doc/snippets/code/src_corelib_text_qstaticlatin1stringmatcher.cpp
@@ -0,0 +1,8 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+//! [0]
+static constexpr auto matcher = qMakeStaticCaseSensitiveLatin1StringViewMatcher("needle");
+//! [0]
+//! [1]
+static constexpr auto matcher = qMakeStaticCaseInsensitiveLatin1StringViewMatcher("needle");
+//! [1]
diff --git a/src/corelib/doc/snippets/code/src_corelib_text_qstringconverter.cpp b/src/corelib/doc/snippets/code/src_corelib_text_qstringconverter.cpp
index e7bd39c95c..b5bfc9cd55 100644
--- a/src/corelib/doc/snippets/code/src_corelib_text_qstringconverter.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_text_qstringconverter.cpp
@@ -34,3 +34,27 @@ while (new_data_available()) {
encoded += fromUtf16(chunk);
}
//! [3]
+
+{
+//! [4]
+QByteArray encodedString = "...";
+auto toUtf16 = QStringDecoder(QStringDecoder::Utf8);
+auto data = toUtf16(encodedString); // data's type is QStringDecoder::EncodedData<const QByteArray &>
+QString string = toUtf16(encodedString); // Implicit conversion to QString
+
+// Here you have to cast "data" to QString
+auto func = [&]() { return !toUtf16.hasError() ? QString(data) : u"foo"_s; }
+//! [4]
+}
+
+{
+//! [5]
+QString string = "...";
+auto fromUtf16 = QStringEncoder(QStringEncoder::Utf8);
+auto data = fromUtf16(string); // data's type is QStringEncoder::DecodedData<const QString &>
+QByteArray encodedString = fromUtf16(string); // Implicit conversion to QByteArray
+
+// Here you have to cast "data" to QByteArray
+auto func = [&]() { return !fromUtf16.hasError() ? QByteArray(data) : "foo"_ba; }
+//! [5]
+}
diff --git a/src/corelib/doc/snippets/code/src_corelib_thread_qfuture.cpp b/src/corelib/doc/snippets/code/src_corelib_thread_qfuture.cpp
index 091d98539b..500d7cc7a5 100644
--- a/src/corelib/doc/snippets/code/src_corelib_thread_qfuture.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_thread_qfuture.cpp
@@ -6,7 +6,7 @@ QFuture<QString> future = ...;
QFuture<QString>::const_iterator i;
for (i = future.constBegin(); i != future.constEnd(); ++i)
- cout << *i << Qt::endl;
+ cout << qPrintable(*i) << endl;
//! [0]
@@ -239,9 +239,9 @@ auto future = QtConcurrent::run([] {
//! [20]
QObject *context = ...;
-auto future = cachedResultsReady ? QtFuture::makeReadyFuture(results)
- : QtConcurrent::run([] { /* compute results */});
-auto continuation = future.then(context, [] (Results results) {
+auto future = cachedResultsReady ? QtFuture::makeReadyValueFuture(result)
+ : QtConcurrent::run([] { /* compute result */});
+auto continuation = future.then(context, [] (Result result) {
// Runs in the context's thread
}).then([] {
// May or may not run in the context's thread
@@ -385,3 +385,58 @@ QFuture<QFuture<QFuture<int>>>> outerFuture;
QFuture<int> unwrappedFuture = outerFuture.unwrap();
//! [30]
+
+//! [31]
+QPromise<int> p;
+
+QFuture<int> f1 = p.future();
+f1.then([](int) { qDebug("first"); });
+
+QFuture<int> f2 = p.future();
+f2.then([](int) { qDebug("second"); });
+
+p.start();
+p.addResult(42);
+p.finish();
+//! [31]
+
+//! [32]
+const std::vector<int> values{1, 2, 3};
+auto f = QtFuture::makeReadyRangeFuture(values);
+//! [32]
+
+//! [33]
+auto f = QtFuture::makeReadyRangeFuture({1, 2, 3});
+//! [33]
+
+//! [34]
+const int count = f.resultCount(); // count == 3
+const auto results = f.results(); // results == { 1, 2, 3 }
+//! [34]
+
+//! [35]
+auto f = QtFuture::makeReadyValueFuture(std::make_unique<int>(42));
+...
+const int result = *f.takeResult(); // result == 42
+//! [35]
+
+//! [36]
+auto f = QtFuture::makeReadyVoidFuture();
+...
+const bool started = f.isStarted(); // started == true
+const bool running = f.isRunning(); // running == false
+const bool finished = f.isFinished(); // finished == true
+//! [36]
+
+//! [37]
+QObject *context = ...;
+auto future = ...;
+auto continuation = future.then(context, [context](Result result) {
+ // ...
+ }).onCanceled([context = QPointer(context)] {
+ if (!context)
+ return; // context was destroyed already
+ // handle cancellation
+ });
+
+//! [37]
diff --git a/src/corelib/doc/snippets/code/src_corelib_thread_qmutexpool.cpp b/src/corelib/doc/snippets/code/src_corelib_thread_qmutexpool.cpp
deleted file mode 100644
index 1368559b24..0000000000
--- a/src/corelib/doc/snippets/code/src_corelib_thread_qmutexpool.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-//! [0]
-class Number {
-public:
- Number(double n) : num (n) { }
-
- void setNumber(double n) { num = n; }
- double number() const { return num; }
-
-private:
- double num;
-};
-//! [0]
-
-
-//! [1]
-void calcSquare(Number *num)
-{
- QMutexLocker locker(mutexpool.get(num));
- num.setNumber(num.number() * num.number());
-}
-//! [1]
diff --git a/src/corelib/doc/snippets/code/src_corelib_thread_qsemaphore.cpp b/src/corelib/doc/snippets/code/src_corelib_thread_qsemaphore.cpp
index a46e10c7b0..d7c9b900af 100644
--- a/src/corelib/doc/snippets/code/src_corelib_thread_qsemaphore.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_thread_qsemaphore.cpp
@@ -35,6 +35,12 @@ sem.tryAcquire(250, 1000); // sem.available() == 5, waits 1000 milliseconds a
sem.tryAcquire(3, 30000); // sem.available() == 2, returns true without waiting
//! [3]
+//! [tryAcquire-QDeadlineTimer]
+QSemaphore sem(5); // sem.available() == 5
+sem.tryAcquire(250, QDeadlineTimer(1000)); // sem.available() == 5, waits 1000 milliseconds and returns false
+sem.tryAcquire(3, QDeadlineTimer(30s)); // sem.available() == 2, returns true without waiting
+//! [tryAcquire-QDeadlineTimer]
+
//! [4]
// ... do something that may throw or return early
sem.release();
diff --git a/src/corelib/doc/snippets/code/src_corelib_time_qdatetime.cpp b/src/corelib/doc/snippets/code/src_corelib_time_qdatetime.cpp
index e86f01a341..588e81bab1 100644
--- a/src/corelib/doc/snippets/code/src_corelib_time_qdatetime.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_time_qdatetime.cpp
@@ -71,14 +71,6 @@ QTime::isValid(22, 5, 62); // returns false
//! [9]
-//! [10]
-QTime t;
-t.start();
-some_lengthy_task();
-qDebug("Time elapsed: %d ms", t.elapsed());
-//! [10]
-
-
//! [11]
QDateTime now = QDateTime::currentDateTime();
QDateTime xmas(QDate(now.date().year(), 12, 25).startOfDay());
diff --git a/src/corelib/doc/snippets/code/src_corelib_tools_qcommandlineparser.cpp b/src/corelib/doc/snippets/code/src_corelib_tools_qcommandlineparser.cpp
index 6fc3cf5c3c..cc22ba88ce 100644
--- a/src/corelib/doc/snippets/code/src_corelib_tools_qcommandlineparser.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_tools_qcommandlineparser.cpp
@@ -90,12 +90,4 @@ Arguments:
//! [3]
}
-{
-//! [4]
-QCommandLineParser parser;
-parser.setApplicationDescription(QCoreApplication::translate("main", "The best application in the world"));
-parser.addHelpOption();
-//! [4]
-}
-
}
diff --git a/src/corelib/doc/snippets/code/src_corelib_tools_qhash.cpp b/src/corelib/doc/snippets/code/src_corelib_tools_qhash.cpp
index b7e56c5ec3..c779b9e3e7 100644
--- a/src/corelib/doc/snippets/code/src_corelib_tools_qhash.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_tools_qhash.cpp
@@ -42,7 +42,7 @@ QHash<int, QWidget *> hash;
...
for (int i = 0; i < 1000; ++i) {
if (hash[i] == okButton)
- cout << "Found button at index " << i << Qt::endl;
+ cout << "Found button at index " << i << endl;
}
//! [6]
@@ -51,17 +51,14 @@ for (int i = 0; i < 1000; ++i) {
QHashIterator<QString, int> i(hash);
while (i.hasNext()) {
i.next();
- cout << i.key() << ": " << i.value() << Qt::endl;
+ cout << qPrintable(i.key()) << ": " << i.value() << endl;
}
//! [7]
//! [8]
-QHash<QString, int>::const_iterator i = hash.constBegin();
-while (i != hash.constEnd()) {
- cout << i.key() << ": " << i.value() << Qt::endl;
- ++i;
-}
+for (auto i = hash.cbegin(), end = hash.cend(); i != end; ++i)
+ cout << qPrintable(i.key()) << ": " << i.value() << endl;
//! [8]
@@ -75,8 +72,8 @@ hash.insert("plenty", 2000);
//! [12]
QHash<QString, int> hash;
...
-foreach (int value, hash)
- cout << value << Qt::endl;
+for (int value : std::as_const(hash))
+ cout << value << endl;
//! [12]
@@ -138,7 +135,7 @@ QHash<QString, int> hash;
...
QHash<QString, int>::const_iterator i = hash.find("HDR");
while (i != hash.end() && i.key() == "HDR") {
- cout << i.value() << Qt::endl;
+ cout << i.value() << endl;
++i;
}
//! [16]
@@ -151,50 +148,20 @@ hash.insert("February", 2);
...
hash.insert("December", 12);
-QHash<QString, int>::iterator i;
-for (i = hash.begin(); i != hash.end(); ++i)
- cout << i.key() << ": " << i.value() << Qt::endl;
+for (auto i = hash.cbegin(), end = hash.cend(); i != end; ++i)
+ cout << qPrintable(key()) << ": " << i.value() << endl;
//! [17]
//! [18]
-QHash<QString, int>::iterator i;
-for (i = hash.begin(); i != hash.end(); ++i)
+for (auto i = hash.begin(), end = hash.end(); i != end; ++i)
i.value() += 2;
//! [18]
-
-//! [19]
-QHash<QString, int>::iterator i = hash.begin();
-while (i != hash.end()) {
- if (i.key().startsWith('_'))
- i = hash.erase(i);
- else
- ++i;
-}
-//! [19]
-
-
-//! [20]
-QHash<QString, int>::iterator i = hash.begin();
-while (i != hash.end()) {
- QHash<QString, int>::iterator prev = i;
- ++i;
- if (prev.key().startsWith('_'))
- hash.erase(prev);
-}
-//! [20]
-
-
//! [21]
-// WRONG
-while (i != hash.end()) {
- if (i.key().startsWith('_'))
- hash.erase(i);
- ++i;
-}
+erase_if(hash, [](const QHash<QString, int>::iterator it) { return it.value() > 10; });
//! [21]
-
+}
//! [22]
if (i.key() == "Hello")
@@ -209,9 +176,8 @@ hash.insert("February", 2);
...
hash.insert("December", 12);
-QHash<QString, int>::const_iterator i;
-for (i = hash.constBegin(); i != hash.constEnd(); ++i)
- cout << i.key() << ": " << i.value() << Qt::endl;
+for (auto i = hash.cbegin(), end = hash.cend(); i != end; ++i)
+ cout << qPrintable(i.key()) << ": " << i.value() << endl;
//! [23]
@@ -232,24 +198,24 @@ hash3 = hash1 + hash2;
//! [25]
QList<int> values = hash.values("plenty");
-for (int i = 0; i < values.size(); ++i)
- cout << values.at(i) << Qt::endl;
+for (auto i : std::as_const(values))
+ cout << i << endl;
//! [25]
//! [26]
-QMultiHash<QString, int>::iterator i = hash.find("plenty");
-while (i != hash.end() && i.key() == "plenty") {
- cout << i.value() << Qt::endl;
+auto i = hash.constFind("plenty");
+while (i != hash.cend() && i.key() == "plenty") {
+ cout << i.value() << endl;
++i;
}
//! [26]
//! [27]
-for (QHash<int, QString>::const_iterator it = hash.cbegin(), end = hash.cend(); it != end; ++it) {
- cout << "The key: " << it.key() << Qt::endl
- cout << "The value: " << it.value() << Qt::endl;
- cout << "Also the value: " << (*it) << Qt::endl;
+for (auto it = hash.cbegin(), end = hash.cend(); it != end; ++it) {
+ cout << "The key: " << it.key() << endl;
+ cout << "The value: " << qPrintable(it.value()) << endl;
+ cout << "Also the value: " << qPrintable(*it) << endl;
}
//! [27]
@@ -322,7 +288,7 @@ hash.insert("February", 2);
hash.insert("December", 12);
for (auto [key, value] : hash.asKeyValueRange()) {
- cout << key << ": " << value << Qt::endl;
+ cout << qPrintable(key) << ": " << value << endl;
--value; // convert to JS month indexing
}
//! [34]
@@ -335,7 +301,7 @@ hash.insert("February", 2);
hash.insert("December", 12);
for (auto [key, value] : hash.asKeyValueRange()) {
- cout << key << ": " << value << Qt::endl;
+ cout << qPrintable(key) << ": " << value << endl;
--value; // convert to JS month indexing
}
//! [35]
diff --git a/src/corelib/doc/snippets/code/src_corelib_tools_qlist.cpp b/src/corelib/doc/snippets/code/src_corelib_tools_qlist.cpp
index 8957d43476..499e8fe480 100644
--- a/src/corelib/doc/snippets/code/src_corelib_tools_qlist.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_tools_qlist.cpp
@@ -26,7 +26,7 @@ if (list[0] == "Liz")
//! [4]
for (qsizetype i = 0; i < list.size(); ++i) {
if (list.at(i) == "Alfonso")
- cout << "Found Alfonso at position " << i << Qt::endl;
+ cout << "Found Alfonso at position " << i << endl;
}
//! [4]
@@ -34,7 +34,7 @@ for (qsizetype i = 0; i < list.size(); ++i) {
//! [5]
qsizetype i = list.indexOf("Harumi");
if (i != -1)
- cout << "First occurrence of Harumi is at position " << i << Qt::endl;
+ cout << "First occurrence of Harumi is at position " << i << endl;
//! [5]
@@ -101,16 +101,14 @@ list.prepend("three");
//! [9]
-QList<QString> list;
-list << "alpha" << "beta" << "delta";
+QList<QString> list = {"alpha", "beta", "delta"};
list.insert(2, "gamma");
// list: ["alpha", "beta", "gamma", "delta"]
//! [9]
//! [10]
-QList<double> list;
-list << 2.718 << 1.442 << 0.4342;
+QList<double> list = {2.718, 1.442, 0.4342};
list.insert(1, 3, 9.9);
// list: [2.718, 9.9, 9.9, 9.9, 1.442, 0.4342]
//! [10]
@@ -127,8 +125,7 @@ list.fill("oh", 5);
//! [12]
-QList<QString> list;
-list << "A" << "B" << "C" << "B" << "A";
+QList<QString> list{"A", "B", "C", "B", "A"};
list.indexOf("B"); // returns 1
list.indexOf("B", 1); // returns 1
list.indexOf("B", 2); // returns 3
@@ -137,8 +134,7 @@ list.indexOf("X"); // returns -1
//! [13]
-QList<QString> list;
-list << "A" << "B" << "C" << "B" << "A";
+QList<QString> list = {"A", "B", "C", "B", "A"};
list.lastIndexOf("B"); // returns 3
list.lastIndexOf("B", 3); // returns 3
list.lastIndexOf("B", 2); // returns 1
diff --git a/src/corelib/doc/snippets/code/src_corelib_tools_qmap.cpp b/src/corelib/doc/snippets/code/src_corelib_tools_qmap.cpp
index 552b7be80a..5f87211968 100644
--- a/src/corelib/doc/snippets/code/src_corelib_tools_qmap.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_tools_qmap.cpp
@@ -42,7 +42,7 @@ QMap<int, QWidget *> map;
...
for (int i = 0; i < 1000; ++i) {
if (map[i] == okButton)
- cout << "Found button at index " << i << Qt::endl;
+ cout << "Found button at index " << i << endl;
}
//! [6]
@@ -51,17 +51,14 @@ for (int i = 0; i < 1000; ++i) {
QMapIterator<QString, int> i(map);
while (i.hasNext()) {
i.next();
- cout << i.key() << ": " << i.value() << Qt::endl;
+ cout << qPrintable(i.key()) << ": " << i.value() << endl;
}
//! [7]
//! [8]
-QMap<QString, int>::const_iterator i = map.constBegin();
-while (i != map.constEnd()) {
- cout << i.key() << ": " << i.value() << Qt::endl;
- ++i;
-}
+for (auto i = map.cbegin(), end = map.cend(); i != end; ++i)
+ cout << qPrintable(i.key()) << ": " << i.value() << endl;
//! [8]
@@ -75,8 +72,8 @@ map.insert("plenty", 2000);
//! [12]
QMap<QString, int> map;
...
-foreach (int value, map)
- cout << value << Qt::endl;
+for (int value : std::as_const(map))
+ cout << value << endl;
//! [12]
@@ -107,43 +104,6 @@ inline bool operator<(const Employee &e1, const Employee &e2)
//! [13]
-//! [14]
-QMap<QString, int> map;
-...
-QMap<QString, int>::const_iterator i = map.find("HDR");
-while (i != map.end() && i.key() == "HDR") {
- cout << i.value() << Qt::endl;
- ++i;
-}
-//! [14]
-
-
-//! [15]
-QMap<int, QString> map;
-map.insert(1, "one");
-map.insert(5, "five");
-map.insert(10, "ten");
-
-map.lowerBound(0); // returns iterator to (1, "one")
-map.lowerBound(1); // returns iterator to (1, "one")
-map.lowerBound(2); // returns iterator to (5, "five")
-map.lowerBound(10); // returns iterator to (10, "ten")
-map.lowerBound(999); // returns end()
-//! [15]
-
-
-//! [16]
-QMap<QString, int> map;
-...
-QMap<QString, int>::const_iterator i = map.lowerBound("HDR");
-QMap<QString, int>::const_iterator upperBound = map.upperBound("HDR");
-while (i != upperBound) {
- cout << i.value() << Qt::endl;
- ++i;
-}
-//! [16]
-
-
//! [17]
QMap<int, QString> map;
map.insert(1, "one");
@@ -165,50 +125,33 @@ map.insert("February", 2);
...
map.insert("December", 12);
-QMap<QString, int>::iterator i;
-for (i = map.begin(); i != map.end(); ++i)
- cout << i.key() << ": " << i.value() << Qt::endl;
+for (auto i = map.cbegin(), end = map.cend(); i != end; ++i)
+ cout << qPrintable(i.key()) << ": " << i.value() << endl;
//! [18]
//! [19]
-QMap<QString, int>::iterator i;
-for (i = map.begin(); i != map.end(); ++i)
+for (auto i = map.begin(), end = map.end(); i != end; ++i)
i.value() += 2;
//! [19]
+void erase()
+{
+QMap<QString, int> map;
//! [20]
-QMap<QString, int>::iterator i = map.begin();
-while (i != map.end()) {
- if (i.key().startsWith('_'))
+QMap<QString, int>::const_iterator i = map.cbegin();
+while (i != map.cend()) {
+ if (i.value() > 10)
i = map.erase(i);
else
++i;
}
//! [20]
-
-
//! [21]
-QMap<QString, int>::iterator i = map.begin();
-while (i != map.end()) {
- QMap<QString, int>::iterator prev = i;
- ++i;
- if (prev.key().startsWith('_'))
- map.erase(prev);
-}
+erase_if(map, [](const QMap<QString, int>::iterator it) { return it.value() > 10; });
//! [21]
-
-
-//! [22]
-// WRONG
-while (i != map.end()) {
- if (i.key().startsWith('_'))
- map.erase(i);
- ++i;
}
-//! [22]
-
//! [23]
if (i.key() == "Hello")
@@ -223,47 +166,16 @@ map.insert("February", 2);
...
map.insert("December", 12);
-QMap<QString, int>::const_iterator i;
-for (i = map.constBegin(); i != map.constEnd(); ++i)
- cout << i.key() << ": " << i.value() << Qt::endl;
+for (auto i = map.cbegin(), end = map.cend(); i != end; ++i)
+ cout << qPrintable(i.key()) << ": " << i.value() << endl;
//! [24]
-//! [25]
-QMultiMap<QString, int> map1, map2, map3;
-
-map1.insert("plenty", 100);
-map1.insert("plenty", 2000);
-// map1.size() == 2
-
-map2.insert("plenty", 5000);
-// map2.size() == 1
-
-map3 = map1 + map2;
-// map3.size() == 3
-//! [25]
-
-
-//! [26]
-QList<int> values = map.values("plenty");
-for (int i = 0; i < values.size(); ++i)
- cout << values.at(i) << Qt::endl;
-//! [26]
-
-
-//! [27]
-QMultiMap<QString, int>::iterator i = map.find("plenty");
-while (i != map.end() && i.key() == "plenty") {
- cout << i.value() << Qt::endl;
- ++i;
-}
-//! [27]
-
//! [keyiterator1]
for (QMap<int, QString>::const_iterator it = map.cbegin(), end = map.cend(); it != end; ++it) {
- cout << "The key: " << it.key() << Qt::endl
- cout << "The value: " << it.value() << Qt::endl;
- cout << "Also the value: " << (*it) << Qt::endl;
+ cout << "The key: " << it.key() << endl;
+ cout << "The value: " << qPrintable(it.value()) << endl;
+ cout << "Also the value: " << qPrintable(*it) << endl;
}
//! [keyiterator1]
@@ -286,7 +198,7 @@ map.insert("February", 2);
map.insert("December", 12);
for (auto [key, value] : map.asKeyValueRange()) {
- cout << key << ": " << value << Qt::endl;
+ cout << qPrintable(key) << ": " << value << endl;
--value; // convert to JS month indexing
}
//! [28]
diff --git a/src/corelib/doc/snippets/code/src_corelib_tools_qmultimap.cpp b/src/corelib/doc/snippets/code/src_corelib_tools_qmultimap.cpp
index 60793ab111..42ec46585b 100644
--- a/src/corelib/doc/snippets/code/src_corelib_tools_qmultimap.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_tools_qmultimap.cpp
@@ -19,8 +19,8 @@ multimap.insert("c", -5);
int num2 = multimap.value("a"); // 1
int num3 = multimap.value("thirteen"); // not found; 0
int num3 = 0;
-auto it = multimap.value("b");
-if (it != multimap.end()) {
+auto it = multimap.constFind("b");
+if (it != multimap.cend()) {
num3 = it.value();
}
//! [3]
@@ -47,17 +47,14 @@ int timeout = multimap.value("TIMEOUT", 30);
QMultiMapIterator<QString, int> i(multimap);
while (i.hasNext()) {
i.next();
- cout << i.key() << ": " << i.value() << Qt::endl;
+ cout << qPrintable(i.key()) << ": " << i.value() << endl;
}
//! [7]
//! [8]
-auto i = multimap.constBegin();
-while (i != multimap.constEnd()) {
- cout << i.key() << ": " << i.value() << Qt::endl;
- ++i;
-}
+for (auto i = multimap.cbegin(), end = multimap.cend(); i != end; ++i)
+ cout << qPrintable(i.key()) << ": " << i.value() << endl;
//! [8]
@@ -70,22 +67,22 @@ multimap.insert("plenty", 2000);
//! [10]
QList<int> values = multimap.values("plenty");
-for (int i = 0; i < values.size(); ++i)
- cout << values.at(i) << Qt::endl;
+for (auto i : std::as_const(values))
+ cout << i << endl;
//! [10]
//! [11]
-QMultiMap<QString, int>::iterator i = multimap.find("plenty");
+auto i = multimap.find("plenty");
while (i != map.end() && i.key() == "plenty") {
- cout << i.value() << Qt::endl;
+ cout << i.value() << endl;
++i;
}
// better:
auto [i, end] = multimap.equal_range("plenty");
while (i != end) {
- cout << i.value() << Qt::endl;
+ cout << i.value() << endl;
++i;
}
//! [11]
@@ -94,8 +91,8 @@ while (i != end) {
//! [12]
QMap<QString, int> multimap;
...
-foreach (int value, multimap)
- cout << value << Qt::endl;
+for (int value : std::as_const(multimap))
+ cout << value << endl;
//! [12]
@@ -149,7 +146,7 @@ QMap<QString, int> multimap;
QMap<QString, int>::const_iterator i = multimap.lowerBound("HDR");
QMap<QString, int>::const_iterator upperBound = multimap.upperBound("HDR");
while (i != upperBound) {
- cout << i.value() << Qt::endl;
+ cout << i.value() << endl;
++i;
}
//! [16]
@@ -171,57 +168,27 @@ multimap.upperBound(10); // returns end()
multimap.upperBound(999); // returns end()
//! [17]
-
-//! [18]
-QMultiMap<QString, int> multimap;
-multimap.insert("January", 1);
-multimap.insert("February", 2);
-...
-multimap.insert("December", 12);
-
-QMap<QString, int>::iterator i;
-for (i = multimap.begin(); i != multimap.end(); ++i)
- cout << i.key() << ": " << i.value() << Qt::endl;
-//! [18]
-
-
//! [19]
-QMultiMap<QString, int>::iterator i;
-for (i = multimap.begin(); i != multimap.end(); ++i)
+for (auto it = multimap.begin(), end = multimap.end(); i != end; ++i)
i.value() += 2;
//! [19]
-
+void erase()
+{
+QMultiMap<QString, int> multimap;
//! [20]
-QMultiMap<QString, int>::iterator i = multimap.begin();
-while (i != multimap.end()) {
- if (i.key().startsWith('_'))
+QMultiMap<QString, int>::const_iterator i = multimap.cbegin();
+while (i != multimap.cend()) {
+ if (i.value() > 10)
i = multimap.erase(i);
else
++i;
}
//! [20]
-
-
//! [21]
-QMultiMap<QString, int>::iterator i = multimap.begin();
-while (i != multimap.end()) {
- QMap<QString, int>::iterator prev = i;
- ++i;
- if (prev.key().startsWith('_'))
- multimap.erase(prev);
-}
+erase_if(multimap, [](const QMultiMap<QString, int>::iterator it) { return it.value() > 10; });
//! [21]
-
-
-//! [22]
-// WRONG
-while (i != multimap.end()) {
- if (i.key().startsWith('_'))
- multimap.erase(i);
- ++i;
}
-//! [22]
//! [23]
@@ -237,9 +204,8 @@ multimap.insert("February", 2);
...
multimap.insert("December", 12);
-QMultiMap<QString, int>::const_iterator i;
-for (i = multimap.constBegin(); i != multimap.constEnd(); ++i)
- cout << i.key() << ": " << i.value() << Qt::endl;
+for (auto i = multimap.cbegin(), end = multimap.cend(); i != end; ++i)
+ cout << qPrintable(i.key()) << ": " << i.value() << endl;
//! [24]
@@ -258,10 +224,10 @@ map3 = map1 + map2;
//! [25]
//! [keyiterator1]
-for (QMultiMap<int, QString>::const_iterator it = multimap.cbegin(), end = multimap.cend(); it != end; ++it) {
- cout << "The key: " << it.key() << Qt::endl
- cout << "The value: " << it.value() << Qt::endl;
- cout << "Also the value: " << (*it) << Qt::endl;
+for (auto it = multimap.cbegin(), end = multimap.cend(); it != end; ++it) {
+ cout << "The key: " << it.key() << endl
+ cout << "The value: " << qPrintable(it.value()) << endl;
+ cout << "Also the value: " << qPrintable(*it) << endl;
}
//! [keyiterator1]
@@ -284,7 +250,7 @@ map.insert("February", 2);
map.insert("December", 12);
for (auto [key, value] : map.asKeyValueRange()) {
- cout << key << ": " << value << Qt::endl;
+ cout << qPrintable(key) << ": " << value << endl;
--value; // convert to JS month indexing
}
//! [26]
diff --git a/src/corelib/doc/snippets/code/src_corelib_tools_qqueue.cpp b/src/corelib/doc/snippets/code/src_corelib_tools_qqueue.cpp
index 81b8eb4dbd..c59ec1060a 100644
--- a/src/corelib/doc/snippets/code/src_corelib_tools_qqueue.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_tools_qqueue.cpp
@@ -7,5 +7,5 @@ queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
while (!queue.isEmpty())
- cout << queue.dequeue() << Qt::endl;
+ cout << queue.dequeue() << endl;
//! [0]
diff --git a/src/corelib/doc/snippets/code/src_gui_dialogs_qmessagebox.cpp b/src/corelib/doc/snippets/code/src_gui_dialogs_qmessagebox.cpp
deleted file mode 100644
index 0b307c33c4..0000000000
--- a/src/corelib/doc/snippets/code/src_gui_dialogs_qmessagebox.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-//! [0]
-int ret = QMessageBox::warning(this, tr("My Application"),
- tr("The document has been modified.\n"
- "Do you want to save your changes?"),
- QMessageBox::Save | QMessageBox::Discard
- | QMessageBox::Cancel,
- QMessageBox::Save);
-//! [0]
-
-
-//! [1]
-QMessageBox msgBox;
-msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
-switch (msgBox.exec()) {
-case QMessageBox::Yes:
- // yes was clicked
- break;
-case QMessageBox::No:
- // no was clicked
- break;
-default:
- // should never be reached
- break;
-}
-//! [1]
-
-
-//! [2]
-QMessageBox msgBox;
-QPushButton *connectButton = msgBox.addButton(tr("Connect"), QMessageBox::ActionRole);
-QPushButton *abortButton = msgBox.addButton(QMessageBox::Abort);
-
-msgBox.exec();
-
-if (msgBox.clickedButton() == connectButton) {
- // connect
-} else if (msgBox.clickedButton() == abortButton) {
- // abort
-}
-//! [2]
-
-
-//! [3]
-QMessageBox messageBox(this);
-QAbstractButton *disconnectButton =
- messageBox.addButton(tr("Disconnect"), QMessageBox::ActionRole);
-...
-messageBox.exec();
-if (messageBox.clickedButton() == disconnectButton) {
- ...
-}
-//! [3]
-
-
-//! [4]
-#include <QApplication>
-#include <QMessageBox>
-
-int main(int argc, char *argv[])
-{
- QT_REQUIRE_VERSION(argc, argv, "6.1.2")
-
- QApplication app(argc, argv);
- ...
- return app.exec();
-}
-//! [4]
-
-//! [5]
-QMessageBox msgBox;
-msgBox.setText("The document has been modified.");
-msgBox.exec();
-//! [5]
-
-//! [6]
-QMessageBox msgBox;
-msgBox.setText("Do you want to save your changes?");
-msgBox.setInformativeText("The document has been modified. It was last saved 5 days ago.");
-msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
-msgBox.setDefaultButton(QMessageBox::Save);
-int ret = msgBox.exec();
-//! [6]
-
-//! [7]
-switch (ret) {
- case QMessageBox::Save:
- // Save was clicked
- break;
- case QMessageBox::Discard:
- // Don't Save was clicked
- break;
- case QMessageBox::Cancel:
- // Cancel was clicked
- break;
- default:
- // should never be reached
- break;
-}
-//! [7]
-
-//! [9]
-QMessageBox msgBox(this);
-msgBox.setText(tr("The document has been modified.\n"
- "Do you want to save your changes?"));
-msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard
- | QMessageBox::Cancel);
-msgBox.setDefaultButton(QMessageBox::Save);
-//! [9]
diff --git a/src/corelib/doc/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp b/src/corelib/doc/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp
index 52934b6159..4ef1891cdb 100644
--- a/src/corelib/doc/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp
+++ b/src/corelib/doc/snippets/code/src_gui_itemviews_qidentityproxymodel.cpp
@@ -17,10 +17,16 @@ class DateFormatProxyModel : public QIdentityProxyModel
return QIdentityProxyModel::data(index, role);
const QDateTime dateTime = sourceModel()->data(SourceClass::DateRole).toDateTime();
-
return dateTime.toString(m_formatString);
}
+ QMap<int, QVariant> itemData(const QModelIndex &proxyIndex) const override
+ {
+ QMap<int, QVariant> map = QIdentityProxyModel::itemData(proxyIndex);
+ map[Qt::DisplayRole] = data(proxyIndex);
+ return map;
+ }
+
private:
QString m_formatString;
};
diff --git a/src/corelib/doc/snippets/customtype/customtypeexample.cpp b/src/corelib/doc/snippets/customtype/customtypeexample.cpp
new file mode 100644
index 0000000000..afa2c4b268
--- /dev/null
+++ b/src/corelib/doc/snippets/customtype/customtypeexample.cpp
@@ -0,0 +1,90 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+#include <QCoreApplication>
+#include <QDebug>
+#include <QVariant>
+
+//message.h
+
+//! [custom type definition]
+class Message
+{
+public:
+ Message() = default;
+ ~Message() = default;
+ Message(const Message &) = default;
+ Message &operator=(const Message &) = default;
+
+ Message(const QString &body, const QStringList &headers);
+
+ QStringView body() const;
+ QStringList headers() const;
+
+private:
+ QString m_body;
+ QStringList m_headers;
+};
+//! [custom type definition]
+
+//! [custom type meta-type declaration]
+Q_DECLARE_METATYPE(Message);
+//! [custom type meta-type declaration]
+
+//! [custom type streaming operator declaration]
+QDebug operator<<(QDebug dbg, const Message &message);
+//! [custom type streaming operator declaration]
+
+// message.cpp
+
+//! [custom type streaming operator]
+QDebug operator<<(QDebug dbg, const Message &message)
+{
+ const QList<QStringView> pieces = message.body().split(u"\r\n", Qt::SkipEmptyParts);
+ if (pieces.isEmpty())
+ dbg.nospace() << "Message()";
+ else if (pieces.size() == 1)
+ dbg.nospace() << "Message(" << pieces.first() << ")";
+ else
+ dbg.nospace() << "Message(" << pieces.first() << " ...)";
+ return dbg;
+}
+//! [custom type streaming operator]
+
+//! [getter functions]
+QStringView Message::body() const
+{
+ return m_body;
+}
+
+QStringList Message::headers() const
+{
+ return m_headers;
+}
+//! [getter functions]
+
+//main.cpp
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication app(argc, argv);
+ QStringList headers;
+ headers << "Subject: Hello World"
+ << "From: address@example.com";
+ QString body = "This is a test.\r\n";
+ //! [printing a custom type]
+ Message message(body, headers);
+ qDebug() << "Original:" << message;
+ //! [printing a custom type]
+ //! [storing a custom value]
+ QVariant stored;
+ stored.setValue(message);
+ //! [storing a custom value]
+ qDebug() << "Stored:" << stored;
+ //! [retrieving a custom value]
+ Message retrieved = qvariant_cast<Message>(stored);
+ qDebug() << "Retrieved:" << retrieved;
+ retrieved = qvariant_cast<Message>(stored);
+ qDebug() << "Retrieved:" << retrieved;
+ //! [retrieving a custom value]
+ return 0;
+}
diff --git a/src/corelib/doc/snippets/jni/src_qjniobject.cpp b/src/corelib/doc/snippets/jni/src_qjniobject.cpp
index ca402fa3d7..6e66b51383 100644
--- a/src/corelib/doc/snippets/jni/src_qjniobject.cpp
+++ b/src/corelib/doc/snippets/jni/src_qjniobject.cpp
@@ -1,23 +1,6 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-//! [Working with lists]
-QStringList getTrackTitles(const QJniObject &album) {
- QStringList stringList;
- QJniObject list = album.callObjectMethod("getTitles",
- "()Ljava/util/List;");
-
- if (list.isValid()) {
- const int size = list.callMethod<jint>("size");
- for (int i = 0; i < size; ++i) {
- QJniObject title = list.callObjectMethod("get", "(I)Ljava/lang/Object;", i);
- stringList.append(title.toString());
- }
- }
- return stringList;
-}
-//! [Working with lists]
-
//! [QJniObject scope]
void functionScope()
{
diff --git a/src/corelib/doc/snippets/qsignalmapper/buttonwidget.cpp b/src/corelib/doc/snippets/qsignalmapper/buttonwidget.cpp
index 235d8b27db..e2e97fa11c 100644
--- a/src/corelib/doc/snippets/qsignalmapper/buttonwidget.cpp
+++ b/src/corelib/doc/snippets/qsignalmapper/buttonwidget.cpp
@@ -14,7 +14,7 @@ ButtonWidget::ButtonWidget(const QStringList &texts, QWidget *parent)
QGridLayout *gridLayout = new QGridLayout(this);
for (int i = 0; i < texts.size(); ++i) {
QPushButton *button = new QPushButton(texts[i]);
- connect(button, &QPushButton::clicked, signalMapper, &QSignalMapper::map);
+ connect(button, &QPushButton::clicked, signalMapper, qOverload<>(&QSignalMapper::map));
//! [0] //! [1]
signalMapper->setMapping(button, texts[i]);
gridLayout->addWidget(button, i / 3, i % 3);
diff --git a/src/corelib/doc/snippets/qstring/main.cpp b/src/corelib/doc/snippets/qstring/main.cpp
index c6f35339c6..8b39ae2f13 100644
--- a/src/corelib/doc/snippets/qstring/main.cpp
+++ b/src/corelib/doc/snippets/qstring/main.cpp
@@ -41,6 +41,7 @@ public:
void firstFunction();
void leftJustifiedFunction();
void slicedFunction();
+ void sliceFunction();
void numberFunction();
void prependFunction();
@@ -909,6 +910,15 @@ void Widget::arrayOperator()
//! [85]
}
+void Widget::sliceFunction()
+{
+ //! [86]
+ QString x = u"Nine pineapples"_s;
+ x.slice(5); // x == "pineapples"
+ x.slice(4, 3); // x == "app"
+ //! [86]
+}
+
int main(int argc, char *argv[])
{
diff --git a/src/corelib/doc/snippets/qstring/stringbuilder.cpp b/src/corelib/doc/snippets/qstring/stringbuilder.cpp
index 61b7a9a133..c3a709bd4c 100644
--- a/src/corelib/doc/snippets/qstring/stringbuilder.cpp
+++ b/src/corelib/doc/snippets/qstring/stringbuilder.cpp
@@ -15,10 +15,6 @@ using namespace Qt::StringLiterals;
...
//! [0]
-//! [3]
- DEFINES *= QT_USE_QSTRINGBUILDER
-//! [3]
-
//! [5]
#include <QStringBuilder>
@@ -31,10 +27,10 @@ using namespace Qt::StringLiterals;
//! [6]
QString str("QStringBuilder");
- // "s" type is deduced as QStringBuilder
+ // "s" type is deduced as QStringBuilder<...>
auto s = "Like hot glue, " % str % " concatenates strings";
- // Similarly the return type of this lambda is deduced as QStringBuilder
+ // Similarly the return type of this lambda is deduced as QStringBuilder<...>
auto concatenateStr = []() {
return "Like hot glue, " % str % " concatenates strings";
};
@@ -43,7 +39,7 @@ using namespace Qt::StringLiterals;
//! [7]
QString s = "Like hot glue, " % str % " concatenates strings";
- // With a lambda, specify a trailing return type
+ // With a lambda, specify a trailing return type:
auto concatenateStr = []() -> QString {
return "Like hot glue, " % str % " concatenates strings";
};
diff --git a/src/corelib/doc/snippets/qstringlist/main.cpp b/src/corelib/doc/snippets/qstringlist/main.cpp
index d2175aafb5..1b7453cf6a 100644
--- a/src/corelib/doc/snippets/qstringlist/main.cpp
+++ b/src/corelib/doc/snippets/qstringlist/main.cpp
@@ -66,7 +66,7 @@ Widget::Widget(QWidget *parent)
result.clear();
//! [12]
- foreach (const QString &str, list) {
+ for (const auto &str : std::as_const(list)) {
if (str.contains("Bill"))
result += str;
}
@@ -93,6 +93,13 @@ Widget::Widget(QWidget *parent)
// list == ["Bill Clinton", "Bill Murray"]
//! [17]
+ {
+//! [18]
+ QStringList veryLongList;
+ QStringMatcher matcher(u"Straße", Qt::CaseInsensitive);
+ QStringList filtered = veryLongList.filter(matcher);
+//! [18]
+ }
}
int main(int argc, char *argv[])
diff --git a/src/corelib/doc/snippets/resource-system/CMakeLists.txt b/src/corelib/doc/snippets/resource-system/CMakeLists.txt
index 267e9a59ad..f0ec0f6816 100644
--- a/src/corelib/doc/snippets/resource-system/CMakeLists.txt
+++ b/src/corelib/doc/snippets/resource-system/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
project(my_app)
cmake_minimum_required(VERSION 3.16)
diff --git a/src/corelib/doc/snippets/resource-system/application.pro b/src/corelib/doc/snippets/resource-system/application.pro
index 4b1f1d7635..42c66eba4c 100644
--- a/src/corelib/doc/snippets/resource-system/application.pro
+++ b/src/corelib/doc/snippets/resource-system/application.pro
@@ -2,9 +2,9 @@ TEMPLATE = app
QT += qml widgets
-#! [0]
+#! [0] #! [qrc]
RESOURCES = application.qrc
-#! [0]
+#! [0] #! [qrc]
#! [1]
resources.files = \
diff --git a/src/corelib/doc/snippets/resource-system/mainwindow.cpp b/src/corelib/doc/snippets/resource-system/mainwindow.cpp
index 92456c35c4..de98aa56ec 100644
--- a/src/corelib/doc/snippets/resource-system/mainwindow.cpp
+++ b/src/corelib/doc/snippets/resource-system/mainwindow.cpp
@@ -1,15 +1,10 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-//! [0]
#include <QtWidgets>
#include "mainwindow.h"
-//! [0]
-
-//! [1]
MainWindow::MainWindow()
-//! [1] //! [2]
{
textEdit = new QPlainTextEdit;
setCentralWidget(textEdit);
@@ -27,11 +22,8 @@ MainWindow::MainWindow()
setCurrentFile(QString());
setUnifiedTitleAndToolBarOnMac(true);
}
-//! [2]
-//! [3]
void MainWindow::closeEvent(QCloseEvent *event)
-//! [3] //! [4]
{
if (maybeSave()) {
writeSettings();
@@ -40,22 +32,16 @@ void MainWindow::closeEvent(QCloseEvent *event)
event->ignore();
}
}
-//! [4]
-//! [5]
void MainWindow::newFile()
-//! [5] //! [6]
{
if (maybeSave()) {
textEdit->clear();
setCurrentFile(QString());
}
}
-//! [6]
-//! [7]
void MainWindow::open()
-//! [7] //! [8]
{
if (maybeSave()) {
QString fileName = QFileDialog::getOpenFileName(this);
@@ -63,11 +49,8 @@ void MainWindow::open()
loadFile(fileName);
}
}
-//! [8]
-//! [9]
bool MainWindow::save()
-//! [9] //! [10]
{
if (curFile.isEmpty()) {
return saveAs();
@@ -75,11 +58,8 @@ bool MainWindow::save()
return saveFile(curFile);
}
}
-//! [10]
-//! [11]
bool MainWindow::saveAs()
-//! [11] //! [12]
{
QString fileName = QFileDialog::getSaveFileName(this);
if (fileName.isEmpty())
@@ -87,42 +67,31 @@ bool MainWindow::saveAs()
return saveFile(fileName);
}
-//! [12]
-//! [13]
void MainWindow::about()
-//! [13] //! [14]
{
QMessageBox::about(this, tr("About Application"),
tr("The <b>Application</b> example demonstrates how to "
"write modern GUI applications using Qt, with a menu bar, "
"toolbars, and a status bar."));
}
-//! [14]
-//! [15]
void MainWindow::documentWasModified()
-//! [15] //! [16]
{
setWindowModified(textEdit->document()->isModified());
}
-//! [16]
-//! [17]
void MainWindow::createActions()
-//! [17] //! [18]
{
newAct = new QAction(QIcon(":/images/new.png"), tr("&New"), this);
newAct->setShortcuts(QKeySequence::New);
newAct->setStatusTip(tr("Create a new file"));
connect(newAct, &QAction::triggered, this, &MainWindow::newFile);
-//! [19]
openAct = new QAction(QIcon(":/images/open.png"), tr("&Open..."), this);
openAct->setShortcuts(QKeySequence::Open);
openAct->setStatusTip(tr("Open an existing file"));
connect(openAct, &QAction::triggered, this, &MainWindow::open);
-//! [18] //! [19]
saveAct = new QAction(QIcon(":/images/save.png"), tr("&Save"), this);
saveAct->setShortcuts(QKeySequence::Save);
@@ -134,10 +103,8 @@ void MainWindow::createActions()
saveAsAct->setStatusTip(tr("Save the document under a new name"));
connect(saveAsAct, &QAction::triggered, this, &MainWindow::saveAs);
-//! [20]
exitAct = new QAction(tr("E&xit"), this);
exitAct->setShortcuts(QKeySequence::Quit);
-//! [20]
exitAct->setStatusTip(tr("Exit the application"));
connect(exitAct, &QAction::triggered, this, &MainWindow::close);
@@ -165,34 +132,24 @@ void MainWindow::createActions()
aboutAct->setStatusTip(tr("Show the application's About box"));
connect(aboutAct, &QAction::triggered, this, &MainWindow::about);
-//! [22]
aboutQtAct = new QAction(tr("About &Qt"), this);
aboutQtAct->setStatusTip(tr("Show the Qt library's About box"));
connect(aboutQtAct, &QAction::triggered, qApp, &QApplication::aboutQt);
-//! [22]
-//! [23]
cutAct->setEnabled(false);
-//! [23] //! [24]
copyAct->setEnabled(false);
connect(textEdit, &QTextEdit::copyAvailable,
cutAct, &QAction::setEnabled);
connect(textEdit, &QTextEdit::copyAvailable,
copyAct, &QAction::setEnabled);
}
-//! [24]
-//! [25] //! [26]
void MainWindow::createMenus()
-//! [25] //! [27]
{
fileMenu = menuBar()->addMenu(tr("&File"));
fileMenu->addAction(newAct);
-//! [28]
fileMenu->addAction(openAct);
-//! [28]
fileMenu->addAction(saveAct);
-//! [26]
fileMenu->addAction(saveAsAct);
fileMenu->addSeparator();
fileMenu->addAction(exitAct);
@@ -208,16 +165,12 @@ void MainWindow::createMenus()
helpMenu->addAction(aboutAct);
helpMenu->addAction(aboutQtAct);
}
-//! [27]
-//! [29] //! [30]
void MainWindow::createToolBars()
{
fileToolBar = addToolBar(tr("File"));
fileToolBar->addAction(newAct);
-//! [29] //! [31]
fileToolBar->addAction(openAct);
-//! [31]
fileToolBar->addAction(saveAct);
editToolBar = addToolBar(tr("Edit"));
@@ -225,19 +178,13 @@ void MainWindow::createToolBars()
editToolBar->addAction(copyAct);
editToolBar->addAction(pasteAct);
}
-//! [30]
-//! [32]
void MainWindow::createStatusBar()
-//! [32] //! [33]
{
statusBar()->showMessage(tr("Ready"));
}
-//! [33]
-//! [34] //! [35]
void MainWindow::readSettings()
-//! [34] //! [36]
{
QSettings settings("QtProject", "Application Example");
QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
@@ -245,21 +192,15 @@ void MainWindow::readSettings()
resize(size);
move(pos);
}
-//! [35] //! [36]
-//! [37] //! [38]
void MainWindow::writeSettings()
-//! [37] //! [39]
{
QSettings settings("QtProject", "Application Example");
settings.setValue("pos", pos());
settings.setValue("size", size());
}
-//! [38] //! [39]
-//! [40]
bool MainWindow::maybeSave()
-//! [40] //! [41]
{
if (textEdit->document()->isModified()) {
QMessageBox::StandardButton ret;
@@ -274,11 +215,8 @@ bool MainWindow::maybeSave()
}
return true;
}
-//! [41]
-//! [42]
void MainWindow::loadFile(const QString &fileName)
-//! [42] //! [43]
{
QFile file(fileName);
if (!file.open(QFile::ReadOnly | QFile::Text)) {
@@ -301,11 +239,8 @@ void MainWindow::loadFile(const QString &fileName)
setCurrentFile(fileName);
statusBar()->showMessage(tr("File loaded"), 2000);
}
-//! [43]
-//! [44]
bool MainWindow::saveFile(const QString &fileName)
-//! [44] //! [45]
{
QFile file(fileName);
if (!file.open(QFile::WriteOnly | QFile::Text)) {
@@ -329,11 +264,8 @@ bool MainWindow::saveFile(const QString &fileName)
statusBar()->showMessage(tr("File saved"), 2000);
return true;
}
-//! [45]
-//! [46]
void MainWindow::setCurrentFile(const QString &fileName)
-//! [46] //! [47]
{
curFile = fileName;
textEdit->document()->setModified(false);
@@ -344,12 +276,8 @@ void MainWindow::setCurrentFile(const QString &fileName)
shownName = "untitled.txt";
setWindowFilePath(shownName);
}
-//! [47]
-//! [48]
QString MainWindow::strippedName(const QString &fullFileName)
-//! [48] //! [49]
{
return QFileInfo(fullFileName).fileName();
}
-//! [49]
diff --git a/src/corelib/doc/snippets/threads/threads.cpp b/src/corelib/doc/snippets/threads/threads.cpp
index 57c68cd358..502bc4bfe0 100644
--- a/src/corelib/doc/snippets/threads/threads.cpp
+++ b/src/corelib/doc/snippets/threads/threads.cpp
@@ -7,9 +7,7 @@
#define Counter ReentrantCounter
-//! [3]
class Counter
-//! [3] //! [4]
{
public:
Counter() { n = 0; }
@@ -21,14 +19,11 @@ public:
private:
int n;
};
-//! [4]
#undef Counter
#define Counter ThreadSafeCounter
-//! [5]
class Counter
-//! [5] //! [6]
{
public:
Counter() { n = 0; }
@@ -41,7 +36,6 @@ private:
mutable QMutex mutex;
int n;
};
-//! [6]
typedef int SomeClass;
diff --git a/src/corelib/doc/snippets/timers/analogclock.cpp b/src/corelib/doc/snippets/timers/analogclock.cpp
index 4052c185c4..5241e57879 100644
--- a/src/corelib/doc/snippets/timers/analogclock.cpp
+++ b/src/corelib/doc/snippets/timers/analogclock.cpp
@@ -5,7 +5,8 @@
#include "analogclock.h"
-//! [0] //! [1]
+// QTimer
+//! [0]
AnalogClock::AnalogClock(QWidget *parent)
//! [0] //! [2]
: QWidget(parent)
@@ -23,11 +24,24 @@ AnalogClock::AnalogClock(QWidget *parent)
resize(200, 200);
//! [7]
}
-//! [1] //! [7]
+//! [7]
+
+//! [analogclock-qchronotimer]
+AnalogClock::AnalogClock(QWidget *parent)
+
+ : QWidget(parent)
+{
+ auto *timer = new QChronoTimer(1s, this);
+ connect(timer, &QTimer::timeout, this, QOverload<>::of(&AnalogClock::update));
+ timer->start();
+ ...
+ ...
+ setWindowTitle(tr("Analog Clock"));
+ resize(200, 200);
+}
+//! [analogclock-qchronotimer]
-//! [8] //! [9]
void AnalogClock::paintEvent(QPaintEvent *)
-//! [8] //! [10]
{
static const QPoint hourHand[3] = {
QPoint(7, 8),
@@ -45,64 +59,40 @@ void AnalogClock::paintEvent(QPaintEvent *)
int side = qMin(width(), height());
QTime time = QTime::currentTime();
-//! [10]
-//! [11]
QPainter painter(this);
-//! [11] //! [12]
painter.setRenderHint(QPainter::Antialiasing);
-//! [12] //! [13]
painter.translate(width() / 2, height() / 2);
-//! [13] //! [14]
painter.scale(side / 200.0, side / 200.0);
-//! [9] //! [14]
-//! [15]
painter.setPen(Qt::NoPen);
-//! [15] //! [16]
painter.setBrush(hourColor);
-//! [16]
-//! [17] //! [18]
painter.save();
-//! [17] //! [19]
painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0)));
painter.drawConvexPolygon(hourHand, 3);
painter.restore();
-//! [18] //! [19]
-//! [20]
painter.setPen(hourColor);
-//! [20] //! [21]
for (int i = 0; i < 12; ++i) {
painter.drawLine(88, 0, 96, 0);
painter.rotate(30.0);
}
-//! [21]
-//! [22]
painter.setPen(Qt::NoPen);
-//! [22] //! [23]
painter.setBrush(minuteColor);
-//! [24]
painter.save();
painter.rotate(6.0 * (time.minute() + time.second() / 60.0));
painter.drawConvexPolygon(minuteHand, 3);
painter.restore();
-//! [23] //! [24]
-//! [25]
painter.setPen(minuteColor);
-//! [25] //! [26]
-//! [27]
for (int j = 0; j < 60; ++j) {
if ((j % 5) != 0)
painter.drawLine(92, 0, 96, 0);
painter.rotate(6.0);
}
-//! [27]
}
-//! [26]
diff --git a/src/corelib/doc/snippets/timers/timers.cpp b/src/corelib/doc/snippets/timers/timers.cpp
index c89db6890c..1a97ba535e 100644
--- a/src/corelib/doc/snippets/timers/timers.cpp
+++ b/src/corelib/doc/snippets/timers/timers.cpp
@@ -1,8 +1,12 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+#include <QChronoTimer>
+#include <QObject>
#include <QTimer>
+using namespace std::chrono;
+
class Foo : public QObject
{
public:
@@ -35,7 +39,45 @@ Foo::Foo()
}
}
-int main()
+// QChronoTimer
+class MyWidget : QObject
{
+ MyWidget()
+ {
+//! [qchronotimer-singleshot]
+ MyWidget widget;
+ QChronoTimer::singleShot(200ms, &widget, &MyWidget::updateCaption);
+//! [qchronotimer-singleshot]
+//! [zero-timer]
+ // The default interval is 0ns
+ QChronoTimer *timer = new QChronoTimer(this);
+ connect(timer, &QChronoTimer::timeout, this, &MyWidget::processOneThing);
+ timer->start();
+//! [zero-timer]
+
+ {
+//! [timer-interval-in-ctor]
+ QChronoTimer *timer = new QChronoTimer(1s, this);
+ connect(timer, &QChronoTimer::timeout, this, &MyWidget::processOneThing);
+ timer->start();
+//! [timer-interval-in-ctor]
+ }
+
+ {
+//! [timer-setinterval]
+ QChronoTimer *timer = new QChronoTimer(this);
+ connect(timer, &QChronoTimer::timeout, this, &MyWidget::processOneThing);
+ timer->setInterval(1s);
+ timer->start();
+//! [timer-setinterval]
+ }
+ }
+
+public Q_SLOTS:
+ void processOneThing();
+};
+
+int main()
+{
}
diff --git a/src/corelib/doc/src/animation.qdoc b/src/corelib/doc/src/animation.qdoc
index 28f88c907a..3d6c1eefa2 100644
--- a/src/corelib/doc/src/animation.qdoc
+++ b/src/corelib/doc/src/animation.qdoc
@@ -222,7 +222,7 @@
A QPropertyAnimation should always have a parent that controls
its lifespan. A typical application may include several animations that
are grouped, where the animation group takes ownership of those animations.
- An independent QProperyAnimation must be explicitly assigned a parent to
+ An independent QPropertyAnimation must be explicitly assigned a parent to
control its lifespan. In the following example, you can see that an
independent QPropertyAnimation has the QApplication instance as its
parent:
diff --git a/src/corelib/doc/src/cbor.qdoc b/src/corelib/doc/src/cbor.qdoc
index 22252bbd88..30d7ddaf60 100644
--- a/src/corelib/doc/src/cbor.qdoc
+++ b/src/corelib/doc/src/cbor.qdoc
@@ -6,6 +6,7 @@
\title CBOR Support in Qt
\ingroup qt-basic-concepts
\brief An overview of CBOR support in Qt.
+ \ingroup explanations-dataprocessingandio
\ingroup frameworks-technologies
@@ -35,7 +36,7 @@
In addition, CBOR can add a "tag" to extend the meaning of the type. The
container types can contain basic types, string-like types and containers.
- \sa {Cbordump Example}, {Convert Example}, {JSON Save Game Example}
+ \sa {Parsing and displaying CBOR data}, {Serialization Converter}, {Saving and Loading a Game}
\section1 The CBOR Classes
diff --git a/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc b/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc
index fd303755fc..b710ba7275 100644
--- a/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc
+++ b/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc
@@ -35,7 +35,7 @@ find_package(Qt6 REQUIRED COMPONENTS Core)
\preliminarycmakevariable
\cmakevariableandroidonly
-This is normally set by the Android NDK toolchain file. It is written out as
+Usually, this variable is set by the Android NDK toolchain file. It is written out as
part of the deployment settings for a target.
\sa{qt6_android_generate_deployment_settings}{qt_android_generate_deployment_settings()}
@@ -54,8 +54,8 @@ part of the deployment settings for a target.
\preliminarycmakevariable
\cmakevariableandroidonly
-This specifies the location of the Android SDK when building for the Android platform.
-It is written out as part of the deployment settings for a target.
+Specifies the location of the Android SDK when building for the Android platform.
+This variable is written out as part of the deployment settings for a target.
\sa{qt6_android_generate_deployment_settings}{qt_android_generate_deployment_settings()}.
*/
@@ -63,6 +63,7 @@ It is written out as part of the deployment settings for a target.
/*!
\page cmake-variable-qt-android-application-arguments.html
\ingroup cmake-variables-qtcore
+\ingroup cmake-android-manifest-properties
\title QT_ANDROID_APPLICATION_ARGUMENTS
\target cmake-variable-QT_ANDROID_APPLICATION_ARGUMENTS
@@ -73,26 +74,51 @@ It is written out as part of the deployment settings for a target.
\preliminarycmakevariable
\cmakevariableandroidonly
-This contains a list of arguments to be passed to Android applications. It is written
-out as part of the deployment settings for a target.
+Contains a list of arguments to be passed to Android applications. This variable
+is written out as part of the deployment settings for a target.
\sa{qt6_android_generate_deployment_settings}{qt_android_generate_deployment_settings()}
*/
/*!
+\page cmake-variable-qt-android-deployment-type.html
+\ingroup cmake-variables-qtcore
+\ingroup cmake-android-build-properties
+
+\title QT_ANDROID_DEPLOYMENT_TYPE
+\target cmake-variable-QT_ANDROID_DEPLOYMENT_TYPE
+
+\summary {Forces or disables release package signing regardless of the build type.}
+
+\cmakevariablesince 6.7
+\preliminarycmakevariable
+\cmakevariableandroidonly
+
+When set to \c Release, the \c --release flag is passed to the \c
+androiddeployqt tool, regardless of the application build type. When set to
+another value, the \c --release flag is never passed to the tool, which
+effectively disables release package signing even in Release or RelWithDebInfo
+builds. When not set, the default behavior is to use release package signing in
+build types other than Debug.
+
+\sa {androiddeployqt}
+*/
+
+/*!
\page cmake_variable-qt-android-multi-abi-forward-vars
\ingroup cmake-variables-qtcore
+\ingroup cmake-android-build-properties
\title QT_ANDROID_MULTI_ABI_FORWARD_VARS
\target cmake-variable-QT_ANDROID_MULTI_ABI_FORWARD_VARS
-\summary {Allows to share CMake variables in multi-ABI builds}
+\summary {Allows to share CMake variables in multi-ABI builds.}
\cmakevariablesince 6.4.2
\preliminarycmakevariable
\cmakevariableandroidonly
-The \c{QT_ANDROID_MULTI_ABI_FORWARD_VARS} variable allows specifying the list of
+Allows specifying the list of
CMake variables that need to be forwarded from the main ABI project to
ABI-specific subprojects. Due to the specifics of the Multi-ABI project build
process, there is no generic way to forward the CMake cache variables
@@ -149,8 +175,8 @@ endif()
...
\endcode
-Setting the variable in this way allows you to have a predefined set of
-variables that will always be forwarded to abi-specific projects.
+Set the variable in this way to have a predefined set of
+variables that will always be forwarded to ABI-specific projects.
\note The forwarding is done in the target finalizer, which is implicitly
called when \l{qt6_add_executable}{qt_add_executable()} is used. The
@@ -163,6 +189,7 @@ finalization occurs automatically when using CMake 3.19 or later.
/*!
\page cmake-variable-qt-android-build-all-abis.html
\ingroup cmake-variables-qtcore
+\ingroup cmake-android-build-properties
\title QT_ANDROID_BUILD_ALL_ABIS
\target cmake-variable-QT_ANDROID_BUILD_ALL_ABIS
@@ -173,7 +200,7 @@ finalization occurs automatically when using CMake 3.19 or later.
\preliminarycmakevariable
\cmakevariableandroidonly
-The option automatically detects available ABIs of Qt for Android and uses them to
+Automatically detects available ABIs of Qt for Android and uses them to
build a package. The automatic detection expects the default directory structure
supplied by the Qt installer, with the corresponding naming of the directories.
\include cmake-android-supported-abis.qdocinc
@@ -188,7 +215,7 @@ The typical directory structure looks as below:
\endcode
The auto-detected paths can be customized using one of \c{QT_PATH_ANDROID_ABI_<ABI>} variables.
-The variable is set to FALSE by default.
+The variable is set to \c FALSE by default.
\sa{QT_PATH_ANDROID_ABI_<ABI>}
*/
@@ -196,6 +223,7 @@ The variable is set to FALSE by default.
/*!
\page cmake-variable-qt-android-abis.html
\ingroup cmake-variables-qtcore
+\ingroup cmake-android-build-properties
\title QT_ANDROID_ABIS
\target cmake-variable-QT_ANDROID_ABIS
@@ -206,10 +234,10 @@ The variable is set to FALSE by default.
\preliminarycmakevariable
\cmakevariableandroidonly
-This variable specifies a list of ABIs to be used to build the project packages.
+Specifies a list of ABIs to be used to build the project packages.
\include cmake-android-supported-abis.qdocinc
Each ABI should have the corresponding Qt for Android either installed or
-user-built. It's possible to specify the path to the Qt for Android ABI using
+user-built. To specify the path to the Qt for Android ABI, use
the corresponding \c{QT_PATH_ANDROID_ABI_<ABI>} variable.
\note \c{QT_ANDROID_BUILD_ALL_ABIS} has the higher priority and ignores the
@@ -240,16 +268,17 @@ Each variable can be used to specify the path to Qt for Android for the correspo
/*!
\page cmake-variable-qt-android-sign-aab.html
\ingroup cmake-variables-qtcore
+\ingroup cmake-android-build-properties
\title QT_ANDROID_SIGN_AAB
\target cmake-variable-QT_ANDROID_SIGN_AAB
-\summary {Sign the .aab package with the specified keystore, alias and store password.}
+\summary {Signs the .aab package with the specified keystore, alias, and store password.}
\cmakevariablesince 6.4
\preliminarycmakevariable
\cmakevariableandroidonly
-Sign the resulting package. The path of the keystore file, the alias of the key and passwords
+Signs the resulting package. The path of the keystore file, the alias of the key, and passwords
have to be specified by additional environment variables:
\badcode
QT_ANDROID_KEYSTORE_PATH
@@ -257,7 +286,7 @@ have to be specified by additional environment variables:
QT_ANDROID_KEYSTORE_STORE_PASS
QT_ANDROID_KEYSTORE_KEY_PASS
\endcode
-Mentioned variables are used internally by \l{androiddeployqt}.
+The mentioned variables are used internally by \l{androiddeployqt}.
\sa{androiddeployqt}
*/
@@ -265,16 +294,17 @@ Mentioned variables are used internally by \l{androiddeployqt}.
/*!
\page cmake-variable-qt-android-sign-apk.html
\ingroup cmake-variables-qtcore
+\ingroup cmake-android-build-properties
\title QT_ANDROID_SIGN_APK
\target cmake-variable-QT_ANDROID_SIGN_APK
-\summary {Sign the package with the specified keystore, alias and store password.}
+\summary {Signs the package with the specified keystore, alias, and store password.}
\cmakevariablesince 6.4
\preliminarycmakevariable
\cmakevariableandroidonly
-Sign the resulting package. The path of the keystore file, the alias of the key and passwords
+Signs the resulting package. The path of the keystore file, the alias of the key, and passwords
have to be specified by additional environment variables:
\badcode
QT_ANDROID_KEYSTORE_PATH
@@ -282,12 +312,33 @@ have to be specified by additional environment variables:
QT_ANDROID_KEYSTORE_STORE_PASS
QT_ANDROID_KEYSTORE_KEY_PASS
\endcode
-Mentioned variables are used internally by \l{androiddeployqt}.
+The mentioned variables are used internally by \l{androiddeployqt}.
\sa{androiddeployqt}
*/
/*!
+\page cmake-variable-qt-use-target-android-build-dir.html
+\ingroup cmake-variables-qtcore
+
+\title QT_USE_TARGET_ANDROID_BUILD_DIR
+\target cmake-variable-QT_USE_TARGET_ANDROID_BUILD_DIR
+
+\summary {Enables the use of per-target Android build directories.}
+
+\cmakevariablesince 6.7
+\preliminarycmakevariable
+\cmakevariableandroidonly
+
+The variable appends the target-specific suffix to the android-build directory.
+The variable only takes an effect when it's set in \c CACHE. The variable is
+only supported by Qt Creator starting from version 13.
+If a single \c CMakeLists.txt contains more than one Android executable and
+this option is not set, you will see a warning. To disable the warning, set
+\c QT_SKIP_ANDROID_BUILD_DIR_CHECK to \c TRUE.
+*/
+
+/*!
\page cmake-variable-qt-no-collect-build-tree-apk-deps.html
\ingroup cmake-variables-qtcore
@@ -304,7 +355,7 @@ During project finalization, the build system collects the locations of
all built shared library targets in the project.
These locations are passed to \l androiddeployqt for deployment consideration when
resolving dependencies between libraries.
-Set \c QT_NO_COLLECT_BUILD_TREE_APK_DEPS to \c TRUE to disable this behavior.
+To disable this behavior, set this variable to \c TRUE.
\sa {qt6_finalize_project}{qt_finalize_project()}
\sa {cmake-variable-QT_NO_COLLECT_IMPORTED_TARGET_APK_DEPS}{QT_NO_COLLECT_IMPORTED_TARGET_APK_DEPS}
@@ -330,7 +381,7 @@ of the currently processed executable target. That includes the target's source
scope and its parents.
The collected locations are passed to \l androiddeployqt for deployment consideration when
resolving dependencies between libraries.
-Set \c QT_NO_COLLECT_IMPORTED_TARGET_APK_DEPS to \c TRUE to disable this behavior.
+To disable this behavior, set this variable to \c TRUE.
\sa {qt6_finalize_project}{qt_finalize_project()}
\sa {cmake-variable-QT_NO_COLLECT_BUILD_TREE_APK_DEPS}{QT_NO_COLLECT_BUILD_TREE_APK_DEPS}
@@ -347,9 +398,12 @@ Set \c QT_NO_COLLECT_IMPORTED_TARGET_APK_DEPS to \c TRUE to disable this behavio
\cmakevariablesince 6.0
-When cross-compiling, this must be set to the install location of Qt for the host
+When cross-compiling, this variable must be set to the install location of Qt for the host
platform. It is used to locate tools to be run on the host (\l{moc}, \l{rcc},
-\l{androiddeployqt}, and so on).
+\l{androiddeployqt}, and so on). It's possible to reuse pre-installed tools
+when compiling Qt for host systems too, by using \c QT_HOST_PATH that points to
+a pre-installed host Qt and setting the \c QT_FORCE_FIND_TOOLS to \c ON. The Qt
+versions should match in this case.
*/
/*!
@@ -366,7 +420,7 @@ platform. It is used to locate tools to be run on the host (\l{moc}, \l{rcc},
When finalizing an executable target on iOS,
\l{qt6_finalize_target}{qt_finalize_target()} will populate the target's
\c XCODE_ATTRIBUTE_DEVELOPMENT_TEAM property if it hasn't been set.
-Set \c QT_NO_SET_XCODE_DEVELOPMENT_TEAM_ID to true if you want to prevent this.
+To prevent this, set \c QT_NO_SET_XCODE_DEVELOPMENT_TEAM_ID to \c TRUE.
*/
/*!
@@ -384,7 +438,7 @@ When finalizing an executable target on iOS,
\l{qt6_finalize_target}{qt_finalize_target()} will populate the target's
\c XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER and
\c MACOSX_BUNDLE_GUI_IDENTIFIER properties if they haven't been set.
-Set \c QT_NO_SET_XCODE_BUNDLE_IDENTIFIER to true if you want to prevent this.
+To prevent this, set \c QT_NO_SET_XCODE_BUNDLE_IDENTIFIER to \c TRUE.
*/
/*!
@@ -394,7 +448,7 @@ Set \c QT_NO_SET_XCODE_BUNDLE_IDENTIFIER to true if you want to prevent this.
\title QT_ENABLE_VERBOSE_DEPLOYMENT
\target cmake-variable-QT_ENABLE_VERBOSE_DEPLOYMENT
-\summary {Enables verbose mode of deployment tools}
+\summary {Enables verbose mode of deployment tools.}
\cmakevariablesince 6.3
\preliminarycmakevariable
@@ -423,13 +477,13 @@ must be set before the first \c{find_package(Qt6)} call to have that effect.
This configure-phase variable is set by the Core package. It is intended to be
used as the first line of any deployment script to ensure access to the
deployment APIs provided by Qt. Such deployment scripts do not run during
-CMake's configure phase, they are executed during installation or as
+CMake's configure phase. They are executed during installation or as
part of a post-build rule.
The following example shows one way the variable would be used when installing
an application, along with its runtime dependencies:
-\include cmake-deploy-runtime-dependencies.qdocinc
+\include cmake-deploy-modified-variable-values.qdocinc
\sa {qt6_deploy_runtime_dependencies}{qt_deploy_runtime_dependencies()},
{qt6_deploy_qml_imports}{qt_deploy_qml_imports()}
@@ -448,24 +502,79 @@ an application, along with its runtime dependencies:
The \l{qt6_standard_project_setup}{qt_standard_project_setup()} command is
typically called in the top level \c{CMakeLists.txt} file of a project. In some
-scenarios, such projects may be absorbed as a child project of a larger project
+scenarios, such a project may be absorbed as a child project of a larger project
hierarchy. A parent project may want to prevent any child project from applying
changes to the setup. The parent project can achieve this by setting
-\c{QT_NO_STANDARD_PROJECT_SETUP} to true before bringing in the child project
-via \l{add_subdirectory()}, \l{FetchContent_MakeAvailable()} or other similar
+\c{QT_NO_STANDARD_PROJECT_SETUP} to \c TRUE before bringing in the child project
+via \l{add_subdirectory()}, \l{FetchContent_MakeAvailable()}, or other similar
methods provided by CMake.
\sa {qt6_standard_project_setup}{qt_standard_project_setup()}
*/
/*!
+\page cmake-variable-qt-i18n-languages.html
+\ingroup cmake-variables-qtcore
+
+\title QT_I18N_TRANSLATED_LANGUAGES
+\target cmake-variable-QT_I18N_TRANSLATED_LANGUAGES
+
+\summary {List of languages to be used for project internationalization.}
+
+\cmakevariablesince 6.7
+
+Specifies a list of languages that are used for project
+internationalization. The single languages must be compatible with the
+string-based \l QLocale constructor.
+
+The languages in \c QT_I18N_TRANSLATED_LANGUAGES are used to:
+\list
+ \li Set up executable targets for consuming \c{.qm} files.
+ \li Automatically construct \c{.ts} file names in
+ \l{qt6_add_translations}{qt_add_translations()}.
+\endlist
+
+This variable can be conveniently set with the
+\l {qt6_standard_project_setup}{qt_standard_project_setup()} command.
+
+By default, translatable strings are considered to be written in \c{en}.
+
+\sa {qt6_standard_project_setup}{qt_standard_project_setup()}
+\sa {qt6_add_translations}{qt_add_translations()}
+*/
+
+/*!
+\page cmake-variable-qt-i18n-native-language.html
+\ingroup cmake-variables-qtcore
+
+\title QT_I18N_SOURCE_LANGUAGE
+\target cmake-variable-QT_I18N_SOURCE_LANGUAGE
+
+\summary {Specifies the language of translatable strings.}
+
+\cmakevariablesince 6.7
+
+Specifies the language of translatable strings in the source code.
+The language must be compatible with the string-based \l QLocale constructor.
+
+Together with \c{QT_I18N_TRANSLATED_LANGUAGES}, this variable is used to determine the
+names of \c{.ts} files for \l{qt6_add_translations}{qt_add_translations()}.
+
+This variable can be conveniently set with the
+\l {qt6_standard_project_setup}{qt_standard_project_setup()} command.
+
+\sa {qt6_standard_project_setup}{qt_standard_project_setup()}
+\sa {qt6_add_translations}{qt_add_translations()}
+*/
+
+/*!
\page cmake-variable-qt-ios-launch-screen.html
\ingroup cmake-variables-qtcore
\title QT_IOS_LAUNCH_SCREEN
\target cmake-variable-QT_IOS_LAUNCH_SCREEN
-\summary {Path to iOS launch screen storyboard used by all targets}
+\summary {Path to iOS launch screen storyboard used by all targets.}
\cmakevariablesince 6.4
\preliminarycmakevariable
diff --git a/src/corelib/doc/src/cmake/cmake-deploy-variables.qdoc b/src/corelib/doc/src/cmake/cmake-deploy-variables.qdoc
index 61826981a1..ac5094e7cb 100644
--- a/src/corelib/doc/src/cmake/cmake-deploy-variables.qdoc
+++ b/src/corelib/doc/src/cmake/cmake-deploy-variables.qdoc
@@ -47,8 +47,9 @@ scripts should assume that the working directory is already set to the base
install location and just use the prefix-relative \c{QT_DEPLOY_..._DIR}
variables.
-\sa QT_DEPLOY_SUPPORT, QT_DEPLOY_BIN_DIR, QT_DEPLOY_LIB_DIR,
- QT_DEPLOY_PLUGINS_DIR, QT_DEPLOY_QML_DIR, QT_DEPLOY_TRANSLATIONS_DIR
+\sa QT_DEPLOY_SUPPORT, QT_DEPLOY_BIN_DIR, QT_DEPLOY_LIBEXEC_DIR,
+ QT_DEPLOY_LIB_DIR, QT_DEPLOY_PLUGINS_DIR, QT_DEPLOY_QML_DIR,
+ QT_DEPLOY_TRANSLATIONS_DIR
*/
/*!
@@ -87,7 +88,46 @@ should not be used for that scenario.
\include cmake-deploy-runtime-dependencies.qdocinc
-\sa QT_DEPLOY_SUPPORT, QT_DEPLOY_PREFIX, QT_DEPLOY_LIB_DIR,
+\sa QT_DEPLOY_SUPPORT, QT_DEPLOY_PREFIX, QT_DEPLOY_LIBEXEC_DIR,
+ QT_DEPLOY_LIB_DIR, QT_DEPLOY_PLUGINS_DIR, QT_DEPLOY_QML_DIR,
+ QT_DEPLOY_TRANSLATIONS_DIR
+*/
+
+/*!
+\page cmake-variable-qt-deploy-libexec-dir.html
+\ingroup cmake-variables-qtcore
+
+\title QT_DEPLOY_LIBEXEC_DIR
+\target cmake-variable-QT_DEPLOY_LIBEXEC_DIR
+
+\summary {Prefix-relative subdirectory for deploying program executables on some target platforms.}
+
+\include cmake-deploy-var-usage.qdocinc
+
+\cmakevariablesince 6.7
+
+On Unix derivatives, projects should use \c QT_DEPLOY_LIBEXEC_DIR in their
+deploy scripts to avoid hard-coding a particular directory in which to deploy
+helper executables that are local to the project.
+
+For example, projects using QtWebEngine would deploy the \c QtWebEngineProcess
+executable to this directory.
+
+\c QT_DEPLOY_LIBEXEC_DIR defaults to the value of \c${CMAKE_INSTALL_LIBEXECDIR}
+(usually \c{libexec}), which is provided by CMake's \l{GNUInstallDirs} module.
+To change the value of \c QT_DEPLOY_LIBEXEC_DIR, ensure that the project sets
+\c{CMAKE_INSTALL_LIBEXECDIR} before the \c Core package is found.
+
+The \c QT_DEPLOY_LIBEXEC_DIR path is relative to \l{QT_DEPLOY_PREFIX}.
+
+This variable is not meaningful when deploying into a macOS app bundle and
+should not be used for that scenario.
+
+\section1 Example
+
+\include cmake-deploy-modified-variable-values.qdocinc
+
+\sa QT_DEPLOY_SUPPORT, QT_DEPLOY_PREFIX, QT_DEPLOY_BIN_DIR, QT_DEPLOY_LIB_DIR,
QT_DEPLOY_PLUGINS_DIR, QT_DEPLOY_QML_DIR, QT_DEPLOY_TRANSLATIONS_DIR
*/
@@ -163,8 +203,9 @@ bundle contents.
\include cmake-deploy-modified-variable-values.qdocinc
-\sa QT_DEPLOY_SUPPORT, QT_DEPLOY_PREFIX, QT_DEPLOY_BIN_DIR, QT_DEPLOY_LIB_DIR,
- QT_DEPLOY_QML_DIR, QT_DEPLOY_TRANSLATIONS_DIR
+\sa QT_DEPLOY_SUPPORT, QT_DEPLOY_PREFIX, QT_DEPLOY_BIN_DIR,
+ QT_DEPLOY_LIBEXEC_DIR, QT_DEPLOY_LIB_DIR, QT_DEPLOY_QML_DIR,
+ QT_DEPLOY_TRANSLATIONS_DIR
*/
/*!
@@ -200,8 +241,9 @@ to be deployed to different locations within the app bundle.
\include cmake-deploy-modified-variable-values.qdocinc
-\sa QT_DEPLOY_SUPPORT, QT_DEPLOY_PREFIX, QT_DEPLOY_BIN_DIR, QT_DEPLOY_LIB_DIR,
- QT_DEPLOY_PLUGINS_DIR, QT_DEPLOY_TRANSLATIONS_DIR
+\sa QT_DEPLOY_SUPPORT, QT_DEPLOY_PREFIX, QT_DEPLOY_BIN_DIR,
+ QT_DEPLOY_LIBEXEC_DIR, QT_DEPLOY_LIB_DIR, QT_DEPLOY_PLUGINS_DIR,
+ QT_DEPLOY_TRANSLATIONS_DIR
*/
/*!
@@ -233,7 +275,7 @@ This variable is not meaningful when deploying on macOS or Windows.
\include cmake-deploy-modified-variable-values.qdocinc
\sa QT_DEPLOY_SUPPORT, QT_DEPLOY_PREFIX, QT_DEPLOY_BIN_DIR, QT_DEPLOY_LIB_DIR,
- QT_DEPLOY_PLUGINS_DIR, QT_DEPLOY_QML_DIR
+ QT_DEPLOY_LIBEXEC_DIR, QT_DEPLOY_PLUGINS_DIR, QT_DEPLOY_QML_DIR
*/
/*!
diff --git a/src/corelib/doc/src/cmake/cmake-properties.qdoc b/src/corelib/doc/src/cmake/cmake-properties.qdoc
index a7ad6c75da..8fe2b0e88f 100644
--- a/src/corelib/doc/src/cmake/cmake-properties.qdoc
+++ b/src/corelib/doc/src/cmake/cmake-properties.qdoc
@@ -16,6 +16,7 @@ target properties:
\page cmake-target-property-qt-android-deployment-dependencies.html
\ingroup cmake-properties-qtcore
\ingroup cmake-target-properties-qtcore
+\ingroup cmake-android-build-properties
\title QT_ANDROID_DEPLOYMENT_DEPENDENCIES
\target cmake-target-property-QT_ANDROID_DEPLOYMENT_DEPENDENCIES
@@ -47,6 +48,7 @@ is listed before its dependencies, it will fail to load on some devices.
\page cmake-target-property-qt-android-extra-libs.html
\ingroup cmake-properties-qtcore
\ingroup cmake-target-properties-qtcore
+\ingroup cmake-android-build-properties
\title QT_ANDROID_EXTRA_LIBS
\target cmake-target-property-QT_ANDROID_EXTRA_LIBS
@@ -85,6 +87,33 @@ library to the MyApp dependencies:
add_dependencies(MyApp MyService)
\endcode
+When adding per-architecture libraries to a multi-abi project,
+list all their paths explicitly, rather than rely on variables like
+\c CMAKE_ANDROID_ARCH_ABI to dynamically compute the paths.
+
+Prefer:
+
+\badcode
+set(libs
+ ${CMAKE_CURRENT_BINARY_DIR}/libA_x86so
+ ${CMAKE_CURRENT_BINARY_DIR}/libA_x86_64.so
+ ${CMAKE_CURRENT_BINARY_DIR}/libA_arm64-v8a.so
+ ${CMAKE_CURRENT_BINARY_DIR}/libA_armeabi-v7a.so
+)
+set_target_properties(MyApp PROPERTIES QT_ANDROID_EXTRA_LIBS ${libs})
+
+# When targeting precompiled libs
+target_link_libraries(${CMAKE_PROJECT_NAME} PUBLIC libA_${ANDROID_ABI})
+\endcode
+
+over:
+
+\badcode
+set_target_properties(MyApp PROPERTIES
+ QT_ANDROID_EXTRA_LIBS
+ ${CMAKE_CURRENT_BINARY_DIR}/libA_${CMAKE_ANDROID_ARCH_ABI}.so)
+\endcode
+
\sa{qt6_android_generate_deployment_settings}{qt_android_generate_deployment_settings()}
*/
@@ -92,6 +121,7 @@ add_dependencies(MyApp MyService)
\page cmake-target-property-qt-android-extra-plugins.html
\ingroup cmake-properties-qtcore
\ingroup cmake-target-properties-qtcore
+\ingroup cmake-android-build-properties
\title QT_ANDROID_EXTRA_PLUGINS
\target cmake-target-property-QT_ANDROID_EXTRA_PLUGINS
@@ -123,6 +153,7 @@ mangling is applied to the plugin library.
\page cmake-target-property-qt-android-min-sdk-version.html
\ingroup cmake-properties-qtcore
\ingroup cmake-target-properties-qtcore
+\ingroup cmake-android-build-properties
\title QT_ANDROID_MIN_SDK_VERSION
\target cmake-target-property-QT_ANDROID_MIN_SDK_VERSION
@@ -142,6 +173,7 @@ Specifies the minimum Android API level for the target.
\page cmake-target-property-qt-android-package-source-dir.html
\ingroup cmake-properties-qtcore
\ingroup cmake-target-properties-qtcore
+\ingroup cmake-android-build-properties
\title QT_ANDROID_PACKAGE_SOURCE_DIR
\target cmake-target-property-QT_ANDROID_PACKAGE_SOURCE_DIR
@@ -175,6 +207,7 @@ then place this directly into the directory specified by this variable.
\page cmake-target-property-qt-android-target-sdk-version.html
\ingroup cmake-properties-qtcore
\ingroup cmake-target-properties-qtcore
+\ingroup cmake-android-build-properties
\title QT_ANDROID_TARGET_SDK_VERSION
\target cmake-target-property-QT_ANDROID_TARGET_SDK_VERSION
@@ -194,6 +227,7 @@ Specifies the target Android API level for the target.
\page cmake-target-property-qt-android-sdk-build-tools-revision.html
\ingroup cmake-properties-qtcore
\ingroup cmake-target-properties-qtcore
+\ingroup cmake-android-build-properties
\title QT_ANDROID_SDK_BUILD_TOOLS_REVISION
\target cmake-target-property-QT_ANDROID_SDK_BUILD_TOOLS_REVISION
@@ -217,6 +251,7 @@ CMake will attempt to use the latest installed version.
\title QT_ANDROID_VERSION_CODE
\target cmake-target-property-QT_ANDROID_VERSION_CODE
+\ingroup cmake-android-manifest-properties
\summary {Internal Android app version.}
@@ -239,6 +274,7 @@ For more information, see \l{Android: App Versioning}{Android App Versioning}.
\title QT_ANDROID_VERSION_NAME
\target cmake-target-property-QT_ANDROID_VERSION_NAME
+\ingroup cmake-android-manifest-properties
\summary {Human-readable Android app version.}
@@ -258,6 +294,7 @@ For more information, see \l{Android: App Versioning}{Android App Versioning}.
\page cmake-target-property-qt-android-abis.html
\ingroup cmake-properties-qtcore
\ingroup cmake-target-properties-qtcore
+\ingroup cmake-android-build-properties
\title QT_ANDROID_ABIS
\target cmake-target-property-QT_ANDROID_ABIS
@@ -324,6 +361,7 @@ For application-specific QML imports, use
\page cmake-target-property-qt-android-deployment-settings-file.html
\ingroup cmake-properties-qtcore
\ingroup cmake-target-properties-qtcore
+\ingroup cmake-android-build-properties
\title QT_ANDROID_DEPLOYMENT_SETTINGS_FILE
\target cmake-target-property-QT_ANDROID_DEPLOYMENT_SETTINGS_FILE
@@ -344,6 +382,7 @@ and overwritten by that command.
\page cmake-target-property-qt-android-system-libs-prefix.html
\ingroup cmake-properties-qtcore
\ingroup cmake-target-properties-qtcore
+\ingroup cmake-android-build-properties
\title QT_ANDROID_SYSTEM_LIBS_PREFIX
\target cmake-target-property-QT_ANDROID_SYSTEM_LIBS_PREFIX
@@ -361,6 +400,7 @@ when those libraries are installed outside app's native (JNI) library directory.
\page cmake-target-property-qt-android-no-deploy-qt-libs.html
\ingroup cmake-properties-qtcore
\ingroup cmake-target-properties-qtcore
+\ingroup cmake-android-build-properties
\title QT_ANDROID_NO_DEPLOY_QT_LIBS
\target cmake-target-property-QT_ANDROID_NO_DEPLOY_QT_LIBS
@@ -453,7 +493,7 @@ the property value overrides the runtime path where the resource file is found.
\summary {Specifies that the given files should be empty in the resource file system}
-\cmakepropertysince 6.5
+\cmakepropertysince 6.6
\preliminarycmakeproperty
When using the target-based variant of \l{qt6_add_resources}{qt_add_resources}
@@ -555,6 +595,29 @@ For more information, see \l{https://github.com/emscripten-core/emscripten/blob/
*/
/*!
+\page cmake-target-property-qt-wasm-maximum-memory.html
+\ingroup cmake-properties-qtcore
+\ingroup cmake-target-properties-qtcore
+
+\title QT_WASM_MAXIMUM_MEMORY
+\target cmake-target-property-QT_WASM_MAXIMUM_MEMORY
+
+\summary {Internal WebAssembly maximum memory.}
+
+\cmakepropertysince 6.7
+\preliminarycmakeproperty
+\cmakepropertywebassemblyonly
+
+Specifies the maximum amount of memory the application can use. Translates into
+the Emscripten compiler setting of \c MAXIMUM_MEMORY. The default value
+is 4GB, which is the maximum for 32-bit WebAssembly.
+
+For more information, see the \l{https://github.com/emscripten-core/emscripten/blob/3319a313d3b589624d342b650884caaf8cd9ef30/src/settings.js#L187}{Emscripten compiler settings}.
+*/
+
+
+
+/*!
\page cmake-target-property-qt-ios-launch-screen.html
\ingroup cmake-properties-qtcore
\ingroup cmake-target-properties-qtcore
diff --git a/src/corelib/doc/src/cmake/cmake-standard-properties.qdoc b/src/corelib/doc/src/cmake/cmake-standard-properties.qdoc
new file mode 100644
index 0000000000..a8ece6ba8f
--- /dev/null
+++ b/src/corelib/doc/src/cmake/cmake-standard-properties.qdoc
@@ -0,0 +1,24 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page cmake-standard-property-autogen-better-graph-multi-config.html
+\ingroup cmake-standard-properties
+
+\title AUTOGEN_BETTER_GRAPH_MULTI_CONFIG
+
+\brief Improves the dependency graph for multi-configuration generators when you
+set it on a target.
+
+When this boolean property is enabled, \c{CMake} will generate more per-config targets.
+Thus, the dependency graph will be more accurate for multi-configuration
+generators and some recompilations will be avoided.
+
+Since Qt 6.8, this property is enabled by default. For older versions,
+you need to enable it manually to use it.
+However, \l{qt_extract_metatypes} and \l{qt_add_qml_module} were updated to
+support \c{AUTOGEN_BETTER_GRAPH_MULTI_CONFIG} in Qt 6.8, so you will get build
+errors, unless you patch the older Qt version to support it.
+
+See \l{https://cmake.org/cmake/help/latest/prop_tgt/AUTOGEN_BETTER_GRAPH_MULTI_CONFIG.html}{AUTOGEN_BETTER_GRAPH_MULTI_CONFIG} for more information.
+*/
diff --git a/src/corelib/doc/src/cmake/policy/qtp0002.qdoc b/src/corelib/doc/src/cmake/policy/qtp0002.qdoc
new file mode 100644
index 0000000000..a40344a167
--- /dev/null
+++ b/src/corelib/doc/src/cmake/policy/qtp0002.qdoc
@@ -0,0 +1,63 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qt-cmake-policy-qtp0002.html
+\ingroup qt-cmake-policies
+
+\title QTP0002
+\keyword qt_cmake_policy_qtp0002
+
+\summary {Target properties that specify Android-specific paths may contain generator expressions.}
+
+This policy was introduced in Qt 6.6. It changes the processing of target
+properties that specify Android-specific paths:
+\list
+ \li \l QT_QML_IMPORT_PATH
+ \li \l QT_QML_ROOT_PATH
+ \li \l QT_ANDROID_PACKAGE_SOURCE_DIR
+ \li \l QT_ANDROID_EXTRA_PLUGINS
+ \li \l QT_ANDROID_EXTRA_LIBS
+\endlist
+
+The \c OLD behavior of this policy doesn't allow generator expressions in the
+target properties that specify Android-specific paths but implicitly converts
+the specified paths to valid JSON strings.
+
+The \c NEW behavior of this policy allows using generator expressions in the
+target properties that specify Android-specific paths, but they must evaluate to
+valid JSON strings.
+
+The following value of the \l QT_ANDROID_EXTRA_PLUGINS property is converted to
+a valid JSON string if you set the policy to OLD, but leads to an error if the
+policy is set to NEW:
+\badcode
+set_target_properties(
+ QT_ANDROID_EXTRA_PLUGINS "\\path\\to\\MyPlugin.so"
+)
+\endcode
+If the policy is set to NEW for the above example, the resulting JSON string in
+the deployment settings file will contain escaped symbols instead of path
+separators.
+
+Generator expressions are only supported if the policy is set to NEW, so the
+OLD behavior generates a malformed deployment settings file with the following
+code:
+\badcode
+set_target_properties(
+ QT_ANDROID_EXTRA_PLUGINS "$<TARGET_FILE_DIR:MyPlugin>"
+)
+\endcode
+
+This property value works as expected with both OLD and NEW policy values:
+\badcode
+set_target_properties(
+ QT_ANDROID_EXTRA_PLUGINS "/path/to/MyPlugin.so"
+)
+\endcode
+
+\qtpolicydeprecatedbehavior
+
+\sa qt_policy, {Qt CMake policies}
+
+*/
diff --git a/src/corelib/doc/src/cmake/policy/qtp0003.qdoc b/src/corelib/doc/src/cmake/policy/qtp0003.qdoc
new file mode 100644
index 0000000000..bf11b6f8b5
--- /dev/null
+++ b/src/corelib/doc/src/cmake/policy/qtp0003.qdoc
@@ -0,0 +1,46 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+\page qt-cmake-policy-qtp0003.html
+\ingroup qt-cmake-policies
+\since 6.7
+\title QTP0003
+\keyword qt_cmake_policy_qtp0003
+
+\summary {Consider the BUILD_SHARED_LIBS value when creating Qt libraries.}
+
+This policy was introduced in Qt 6.7. The policy affects the default type of the
+libraries created using \l {CMake Commands in Qt6 Core}{Qt CMake API}, like
+\l {qt_add_library}, \l{qt_add_plugin}, \l{qt_add_qml_module}.
+
+If the policy is set to \c OLD, the default library type that is selected is
+aligned with the Qt build type, either \c shared or \c static.
+
+If the policy is set to \c NEW, the library type is selected according to the
+\l {CMake BUILD_SHARED_LIBS Documentation}{BUILD_SHARED_LIBS} value if it's set.
+If \c BUILD_SHARED_LIBS is not set, the default library type falls back to the
+Qt build type.
+
+For example, the following code will use the Qt build type as the default
+library type for the \c MyLib target, despite the fact \c BUILD_SHARED_LIBS is
+set to \c ON:
+\badcode
+set(BUILD_SHARED_LIBS ON)
+...
+qt6_add_library(MyLib sourcefile.h sourcefile.cpp)
+\endcode
+
+If you set the QTP0003 to \c NEW before the \l {qt6_add_library}{qt_add_library}
+call, \c BUILD_SHARED_LIBS will affect the library default type and \c MyLib
+will be the shared library.
+\badcode
+set(BUILD_SHARED_LIBS ON)
+...
+qt_policy(SET QTP0003 NEW)
+qt6_add_library(MyLib sourcefile.h sourcefile.cpp)
+\endcode
+
+\sa qt_policy, {Qt CMake policies}, qt_add_library
+
+*/
diff --git a/src/corelib/doc/src/cmake/qt_add_executable.qdoc b/src/corelib/doc/src/cmake/qt_add_executable.qdoc
index 97f415f6c4..cc8c924c79 100644
--- a/src/corelib/doc/src/cmake/qt_add_executable.qdoc
+++ b/src/corelib/doc/src/cmake/qt_add_executable.qdoc
@@ -110,5 +110,5 @@ for finalizing the target by adding the \c{MANUAL_FINALIZATION} keyword.
\snippet cmake-macros/examples.cmake qt_add_executable_deferred
-\include cmake-android-qt-finalize-project-warning.qdocinc
+\include cmake-android-qt-finalize-project-warning.qdocinc warning
*/
diff --git a/src/corelib/doc/src/cmake/qt_add_library.qdoc b/src/corelib/doc/src/cmake/qt_add_library.qdoc
index 66336da4b9..851a2d6210 100644
--- a/src/corelib/doc/src/cmake/qt_add_library.qdoc
+++ b/src/corelib/doc/src/cmake/qt_add_library.qdoc
@@ -45,8 +45,10 @@ library type created depends on how Qt was built. If Qt was built statically,
a static library will be created. Otherwise, a shared library will
be created. Note that this is different to how CMake's \c{add_library()}
command works, where the \c BUILD_SHARED_LIBS variable controls the type of
-library created. The \c{qt_add_library()} command does not consider
-\c BUILD_SHARED_LIBS when deciding the library type.
+library created.
+Since 6.7, the \c{qt_add_library()} command considers \c BUILD_SHARED_LIBS
+when deciding the library type only if the variable is set explicitly and
+\l {QTP0003} is set to \c NEW.
Any \c{sources} provided will be passed through to the internal call to
\c{add_library()}.
@@ -73,6 +75,6 @@ time. In general, \c MANUAL_FINALIZATION should not be needed unless the
project has to support CMake 3.18 or earlier.
\sa {qt6_finalize_target}{qt_finalize_target()},
- {qt6_add_executable}{qt_add_executable()}
+ {qt6_add_executable}{qt_add_executable()}, QTP0003
*/
diff --git a/src/corelib/doc/src/cmake/qt_add_resources.qdoc b/src/corelib/doc/src/cmake/qt_add_resources.qdoc
index 4893361722..2e713b1b8e 100644
--- a/src/corelib/doc/src/cmake/qt_add_resources.qdoc
+++ b/src/corelib/doc/src/cmake/qt_add_resources.qdoc
@@ -48,8 +48,6 @@ When passing a target as first argument, the function creates a resource with
the name \c{RESOURCE_NAME}, containing the specified \c{FILES}. The resource is
automatically linked into \c{TARGET}.
-For embedding bigger resources, see \l qt_add_big_resources.
-
See \l{The Qt Resource System} for a general description of Qt resources.
\section1 Arguments of the target-based variant
@@ -107,4 +105,6 @@ resources linked into the final target.
This especially affects static builds. There, the same resource name in
different static libraries conflict in the consuming target.
+
+\sa {qt6_add_big_resources}{qt_add_big_resources()}
*/
diff --git a/src/corelib/doc/src/cmake/qt_deploy_runtime_dependencies.qdoc b/src/corelib/doc/src/cmake/qt_deploy_runtime_dependencies.qdoc
index ec03eba706..f64960492a 100644
--- a/src/corelib/doc/src/cmake/qt_deploy_runtime_dependencies.qdoc
+++ b/src/corelib/doc/src/cmake/qt_deploy_runtime_dependencies.qdoc
@@ -31,6 +31,7 @@ qt_deploy_runtime_dependencies(
[ADDITIONAL_MODULES files...]
[GENERATE_QT_CONF]
[BIN_DIR bin_dir]
+ [LIBEXEC_DIR libexec_dir]
[LIB_DIR lib_dir]
[PLUGINS_DIR plugins_dir]
[QML_DIR qml_dir]
@@ -39,6 +40,7 @@ qt_deploy_runtime_dependencies(
[NO_APP_STORE_COMPLIANCE]
[NO_TRANSLATIONS]
[NO_COMPILER_RUNTIME]
+ [DEPLOY_TOOL_OPTIONS]
[PRE_INCLUDE_REGEXES regexes...]
[PRE_EXCLUDE_REGEXES regexes...]
[POST_INCLUDE_REGEXES regexes...]
@@ -54,8 +56,12 @@ When installing an application, it may be desirable to also install the
libraries and plugins it depends on. When the application is a macOS app bundle
or a Windows executable, \c{qt_deploy_runtime_dependencies()} can be called
from an install-time script to deploy those dependencies. It will install
-non-system libraries (both Qt and those provided by the project), plus an
-appropriate set of Qt plugins.
+non-system Qt libraries plus an appropriate set of Qt plugins.
+
+On Linux, the command will deploy additional libraries, beyond just those
+related to Qt, that are included with the project. However, when executed on
+macOS or Windows, the command will use either \c macdeployqt or \c windeployqt,
+which will only deploy libraries that are specific to Qt.
This command only considers runtime dependencies for which linking
relationships exist in the underlying binaries. It does not deploy QML modules,
@@ -98,13 +104,41 @@ directory structure. If the \c{GENERATE_QT_CONF} option is given, an appropriate
\c{qt.conf} file will be written to the same directory as the \c{executable}.
The paths in that \c{qt.conf} file will be based on the \c{CMAKE_INSTALL_xxxDIR}
variables, whose defaults are provided by CMake's \l{GNUInstallDirs} module.
-You can override some of those defaults with the \c{BIN_DIR}, \c{LIB_DIR},
-\c{PLUGINS_DIR}, and \c{QML_DIR} options, all of which are expected to be
-relative to the base install location. A \c{qt.conf} file is always written if
-\c{executable} is a macOS app bundle, regardless of whether or not
-\c{GENERATE_QT_CONF} is provided. The \c{..._DIR} options are also ignored in
-that case, since the directory layout of an app bundle is dictated by Apple's
-requirements.
+
+You can override some of those defaults with the parameters in the following
+table, all of which are expected to be relative to the base install location.
+
+\table
+\header
+ \li parameter
+ \li affected variable
+ \li notes
+\row
+ \li \c BIN_DIR
+ \li \l QT_DEPLOY_BIN_DIR
+ \li
+\row
+ \li \c LIBEXEC_DIR
+ \li \l QT_DEPLOY_LIBEXEC_DIR
+ \li since Qt 6.7
+\row
+ \li \c LIB_DIR
+ \li \l QT_DEPLOY_LIB_DIR
+ \li
+\row
+ \li \c PLUGINS_DIR
+ \li \l QT_DEPLOY_PLUGINS_DIR
+ \li
+\row
+ \li \c QML_DIR
+ \li \l QT_DEPLOY_QML_DIR
+ \li
+\endtable
+
+A \c{qt.conf} file is always written if \c{executable} is a macOS app bundle,
+regardless of whether or not \c{GENERATE_QT_CONF} is provided. The \c{..._DIR}
+options are also ignored in that case, since the directory layout of an app
+bundle is dictated by Apple's requirements.
More verbose output about the deployment steps can be enabled by providing the
\c{VERBOSE} option. Alternatively, the \l{QT_ENABLE_VERBOSE_DEPLOYMENT}
@@ -128,6 +162,10 @@ in a customized way.
For Windows desktop applications, the required runtime files for the compiler
are also installed by default. To prevent this, specify \c{NO_COMPILER_RUNTIME}.
+Since Qt 6.7, you can use \c{DEPLOY_TOOL_OPTIONS} to pass additional options to
+the underlying deployment tool. This only has an effect if the underlying
+deployment tool is either macdeployqt or windeployqt.
+
On Linux, deploying runtime dependencies is based on CMake's
\c{file(GET_RUNTIME_DEPENDENCIES)} command. The options \c{PRE_INCLUDE_REGEXES},
\c{PRE_EXCLUDE_REGEXES}, \c{POST_INCLUDE_REGEXES}, \c{POST_EXCLUDE_REGEXES},
@@ -148,5 +186,13 @@ The default value of \c{POST_EXCLUDE_REGEXES} is constructed from the value of
\section1 Example
+The following example shows how to deploy an application \c{MyApp}.
+
\include cmake-deploy-runtime-dependencies.qdocinc
+
+The following example shows how to use the \c{DEPLOY_TOOL_OPTIONS} parameter to
+pass different options to macdeployqt and windeployqt.
+
+\include cmake-deploy-runtime-dependencies-deploy-tool-options.qdocinc
+
*/
diff --git a/src/corelib/doc/src/cmake/qt_deploy_translations.qdoc b/src/corelib/doc/src/cmake/qt_deploy_translations.qdoc
index b2c82dcdac..43ff23a35a 100644
--- a/src/corelib/doc/src/cmake/qt_deploy_translations.qdoc
+++ b/src/corelib/doc/src/cmake/qt_deploy_translations.qdoc
@@ -58,7 +58,7 @@ that is used in the project via \c{find_package}.
The \c LCONVERT argument specifies the \c lconvert executable that is used to
combine the catalogs. By default, the Qt installation's \c lconvert is used.
-For debugging purposed, the \c VERBOSE argument can be set to turn on diagnostic
+For debugging purposes, the \c VERBOSE argument can be set to turn on diagnostic
messages.
\sa QT_DEPLOY_TRANSLATIONS_DIR
diff --git a/src/corelib/doc/src/cmake/qt_extract_metatypes.qdoc b/src/corelib/doc/src/cmake/qt_extract_metatypes.qdoc
index 7d9cd936ff..7ec8d90f9b 100644
--- a/src/corelib/doc/src/cmake/qt_extract_metatypes.qdoc
+++ b/src/corelib/doc/src/cmake/qt_extract_metatypes.qdoc
@@ -52,4 +52,18 @@ example, to pass it to another command or to install it), use the
\c OUTPUT_FILES option to provide the name of a variable in which to store its
absolute path.
+\section1 Automatic metatype extraction
+
+Since Qt 6.8, if you have not disabled \c{AUTOMOC} and either are using CMake
+3.19 or later or are calling \l{qt6_finalize_target}{qt_finalize_target()}
+manually, then \c{qt_extract_metatypes()} is automatically called as part of the
+finalization step for \l{qt_add_library}. This has no effect if you have
+manually called \c{qt_extract_metatypes()} before the finalization, possibly
+with custom arguments. However, it does make sure that the metatypes are also
+produced if you haven't. This is important if any of the types in the library
+are used as part of any QML types any time in the future and has no downsides.
+
+Furthermore, \l{qt_add_qml_module} automatically invokes
+\c{qt_extract_metatypes()} for its target.
+
*/
diff --git a/src/corelib/doc/src/cmake/qt_finalize_project.qdoc b/src/corelib/doc/src/cmake/qt_finalize_project.qdoc
index 9beb427050..5506712691 100644
--- a/src/corelib/doc/src/cmake/qt_finalize_project.qdoc
+++ b/src/corelib/doc/src/cmake/qt_finalize_project.qdoc
@@ -38,7 +38,7 @@ With CMake version 3.19 or later, you don't need to call this command since
it consists of sub-commands that are ordinarily invoked at the end of
\c CMAKE_SOURCE_DIR directory scope processing.
-\include cmake-android-qt-finalize-project-warning.qdocinc
+\include cmake-android-qt-finalize-project-warning.qdocinc warning
\section2 Examples
diff --git a/src/corelib/doc/src/cmake/qt_finalize_target.qdoc b/src/corelib/doc/src/cmake/qt_finalize_target.qdoc
index 17b18daffe..b74dee64d2 100644
--- a/src/corelib/doc/src/cmake/qt_finalize_target.qdoc
+++ b/src/corelib/doc/src/cmake/qt_finalize_target.qdoc
@@ -32,10 +32,10 @@ was created, so this command should also be called from that same directory
scope.
This command is ordinarily invoked as part of a call to
-\l{qt6_add_executable}{qt_add_executable()} or
-\l{qt6_add_library}{qt_add_library()}. The timing of when that call takes
-place and when it might need to be called explicitly by a project is discussed
-in the documentation of those commands.
+\l{qt6_add_executable}{qt_add_executable()},
+\l{qt6_add_library}{qt_add_library()}, or \l{qt6_add_plugin}{qt_add_plugin()}.
+The timing of when that call takes place and when a project might need to call
+it explicitly, is discussed in the documentation of those commands.
\sa {qt6_set_finalizer_mode}{qt_set_finalizer_mode()}
diff --git a/src/corelib/doc/src/cmake/qt_generate_deploy_app_script.qdoc b/src/corelib/doc/src/cmake/qt_generate_deploy_app_script.qdoc
index 7566455d9d..31d9e4384b 100644
--- a/src/corelib/doc/src/cmake/qt_generate_deploy_app_script.qdoc
+++ b/src/corelib/doc/src/cmake/qt_generate_deploy_app_script.qdoc
@@ -13,7 +13,7 @@
\include cmake-find-package-core.qdocinc
\cmakecommandsince 6.3
-\note This command is currently only supported on Windows and macOS.
+\note This command is currently only supported on Windows, macOS, and Linux.
\section1 Synopsis
@@ -24,6 +24,7 @@ qt_generate_deploy_app_script(
[NO_TRANSLATIONS]
[NO_COMPILER_RUNTIME]
[NO_UNSUPPORTED_PLATFORM_ERROR]
+ [DEPLOY_TOOL_OPTIONS ...]
[PRE_INCLUDE_REGEXES regexes...]
[PRE_EXCLUDE_REGEXES regexes...]
[POST_INCLUDE_REGEXES regexes...]
@@ -74,6 +75,10 @@ customized way.
For Windows desktop applications, the required runtime files for the compiler
are also installed by default. To prevent this, specify \c{NO_COMPILER_RUNTIME}.
+Since Qt 6.7, you can use \c{DEPLOY_TOOL_OPTIONS} to pass additional options to
+the underlying deployment tool. This only has an effect if the underlying
+deployment tool is either macdeployqt or windeployqt.
+
For deploying a QML application, use
\l{qt6_generate_deploy_qml_app_script}{qt_generate_deploy_qml_app_script()}
instead.
@@ -93,25 +98,13 @@ unmodified to \l{qt6_deploy_runtime_dependencies}{qt_deploy_runtime_dependencies
\section1 Example
-\badcode
-cmake_minimum_required(VERSION 3.16...3.22)
-project(MyThings)
+The following example shows how to deploy an application \c{MyApp}.
-find_package(Qt6 REQUIRED COMPONENTS Core)
-qt_standard_project_setup()
+\include cmake-generate-deploy-app-script.qdocinc
-qt_add_executable(MyApp main.cpp)
+The following example shows how to use the \c{DEPLOY_TOOL_OPTIONS} parameter to
+pass different options to macdeployqt and windeployqt.
-install(TARGETS MyApp
- BUNDLE DESTINATION .
- RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
-)
+\include cmake-generate-deploy-app-script-deploy-tool-options.qdocinc
-qt_generate_deploy_app_script(
- TARGET MyApp
- OUTPUT_SCRIPT deploy_script
- NO_UNSUPPORTED_PLATFORM_ERROR
-)
-install(SCRIPT ${deploy_script})
-\endcode
*/
diff --git a/src/corelib/doc/src/cmake/qt_import_plugins.qdoc b/src/corelib/doc/src/cmake/qt_import_plugins.qdoc
index 4b612206ee..1f81a21cd2 100644
--- a/src/corelib/doc/src/cmake/qt_import_plugins.qdoc
+++ b/src/corelib/doc/src/cmake/qt_import_plugins.qdoc
@@ -8,7 +8,7 @@
\title qt_import_plugins
\keyword qt6_import_plugins
-\summary {Specifies a custom set of plugins to import for a static Qt build.}
+\summary {Specifies a custom set of plugins to import or exclude.}
\include cmake-find-package-core.qdocinc
@@ -48,17 +48,35 @@ can be used more than once.
Qt provides plugin types such as \c imageformats, \c platforms,
and \c sqldrivers.
+\section2 Dynamic plugins
+
+If plugins are dynamic libraries, the function controls the plugin deployment.
+Using this function, you may exclude specific plugin types from
+being packaged into an Android APK, for example:
+
+\badcode
+qt_add_executable(MyApp ...)
+...
+qt_import_plugins(MyApp EXCLUDE_BY_TYPE imageformats)
+\endcode
+
+In the snippet above, all plugins that have the \c imageformats type will
+be excluded when deploying \c MyApp. The resulting Android APK will not
+contain any of the \c imageformats plugins.
+
+If the command isn't used, the target automatically deploys all plugins that
+belong to the Qt modules that the target is linked against.
+
+\section2 Static plugins
+
If the command isn't used the target automatically links against
-a sane set of default plugins, for each Qt module that the target is linked
-against. For more information, see
+a sane set of default static plugins, for each Qt module that the target is
+linked against. For more information, see
\l{CMake target_link_libraries Documentation}{target_link_libraries}.
Each plugin comes with a C++ stub file that automatically
-initializes the plugin. Consequently, any target that links against a plugin
-has this C++ file added to its \c SOURCES.
-
-\note This command imports plugins from static Qt builds only.
-On shared builds, it does nothing.
+initializes the static plugin. Consequently, any target that links against
+a plugin has this C++ file added to its \c SOURCES.
\section1 Examples
diff --git a/src/corelib/doc/src/cmake/qt_policy.qdoc b/src/corelib/doc/src/cmake/qt_policy.qdoc
index 7c44b4d824..6deb7a729c 100644
--- a/src/corelib/doc/src/cmake/qt_policy.qdoc
+++ b/src/corelib/doc/src/cmake/qt_policy.qdoc
@@ -58,8 +58,7 @@ You can set \c behavior to one of the following options:
\li \c{OLD} to explicitly opt-out of it
\endlist
-\note The \c{OLD} behavior of a policy is deprecated, and may
-be removed in the future.
+\qtpolicydeprecatedbehavior
\sa qt_standard_project_setup
diff --git a/src/corelib/doc/src/cmake/qt_standard_project_setup.qdoc b/src/corelib/doc/src/cmake/qt_standard_project_setup.qdoc
index c76eba42f2..59b33f599c 100644
--- a/src/corelib/doc/src/cmake/qt_standard_project_setup.qdoc
+++ b/src/corelib/doc/src/cmake/qt_standard_project_setup.qdoc
@@ -20,6 +20,8 @@
qt_standard_project_setup(
[REQUIRES <version>]
[SUPPORTS_UP_TO <version>]
+ [I18N_TRANSLATED_LANGUAGES <language...>]
+ [I18N_SOURCE_LANGUAGE <language>]
)
\endcode
@@ -81,7 +83,19 @@ setting the \l{QT_NO_STANDARD_PROJECT_SETUP} variable to true.
\sa {qt6_generate_deploy_app_script}{qt_generate_deploy_app_script()}
\sa qt_policy
+\section1 Internationalization
+
+Since Qt 6.7, it is possible to specify the languages that are used for project
+internationalization with the \c I18N_TRANSLATED_LANGUAGES argument. See \l
+QT_I18N_TRANSLATED_LANGUAGES for details.
+
+Use I18N_SOURCE_LANGUAGE to specify the language that translatable strings are
+written in. By default, \c en is used. See \l QT_I18N_SOURCE_LANGUAGE for
+details.
+
\section1 Example
-\include cmake-deploy-runtime-dependencies.qdocinc
+\include cmake-generate-deploy-app-script.qdocinc
+
+\sa {Automatic Determination of .ts File Paths}{qt_add_translations()}
*/
diff --git a/src/corelib/doc/src/cmake/qt_wrap_cpp.qdoc b/src/corelib/doc/src/cmake/qt_wrap_cpp.qdoc
index 03b7a866a7..3b298a9d7e 100644
--- a/src/corelib/doc/src/cmake/qt_wrap_cpp.qdoc
+++ b/src/corelib/doc/src/cmake/qt_wrap_cpp.qdoc
@@ -40,9 +40,23 @@ You can set an explicit \c{TARGET}. This will make sure that the target
properties \c{INCLUDE_DIRECTORIES} and \c{COMPILE_DEFINITIONS} are also used
when scanning the source files with \c{moc}.
+Since Qt 6.8, when a source file is passed to \c{qt_wrap_cpp} instead of a
+header file to generate a \c{.moc} file for a target, the \c{TARGET} parameter
+is needed to set the correct include path for the generated \c{.moc} file in
+the source file. As generated \c{.moc} files are added to the target's
+sources by \c{qt_wrap_cpp}, they are not added to \c{<VAR>}.
+
You can set additional \c{OPTIONS} that should be added to the \c{moc} calls.
You can find possible options in the \l{moc}{moc documentation}.
+The \c{OPTIONS} can evaluate generator expressions when \c{TARGET} is set.
+\note If the \c{OPTIONS} include both generator expressions and special
+characters, use variables to implement them. For example, use \c{$<ANGLE-R>},
+\c{$<COMMA>} and \c{$<SEMICOLON>} instead of \c{>}, \c{,} and \c{:}. Otherwise,
+the generator expression will not be evaluated correctly. \c {OPTIONS} are
+wrapped in generator expressions, so you must escape special characters in
+them.
+
\c{DEPENDS} allows you to add additional dependencies for recreation of the
generated files. This is useful when the sources have implicit dependencies,
like code for a Qt plugin that includes a \c{.json} file using the
@@ -50,5 +64,27 @@ Q_PLUGIN_METADATA() macro.
\section1 Examples
-\snippet cmake-macros/examples.cmake qt_wrap_cpp
+\snippet cmake-macros/examples.cmake qt_wrap_cpp_1
+
+In the following example, the generator expressions passed to \c{OPTIONS}
+will be evaluated since \c{TARGET} is set. The argument is specified this way to
+avoid syntax errors in the generator expressions.
+
+\snippet cmake-macros/examples.cmake qt_wrap_cpp_2
+
+The following example uses \l{https://cmake.org/cmake/help/latest/command/target_compile_definitions.html}{target_compile_definitions}
+to set \l{https://cmake.org/cmake/help/latest/prop_tgt/COMPILE_DEFINITIONS.html}{COMPILE_DEFINITIONS} which will be added to
+\c{OPTIONS}.
+
+\snippet cmake-macros/examples.cmake qt_wrap_cpp_4
+
+\snippet cmake-macros/examples.cpp qt_wrap_cpp_4
+
+In the above file, \c{myapp.moc} is included in \c{myapp.cpp}.
+To generate the \c{myapp.moc} file, the \c{qt_wrap_cpp} macro is used with the
+\c{TARGET} parameter. The first parameter is empty because the \c{.moc} file
+and its path will be added to the target's sources and include directories by
+the \c{qt_wrap_cpp} macro.
+
+\snippet cmake-macros/examples.cmake qt_wrap_cpp_4
*/
diff --git a/src/corelib/doc/src/containers.qdoc b/src/corelib/doc/src/containers.qdoc
index df82830792..847be1bff6 100644
--- a/src/corelib/doc/src/containers.qdoc
+++ b/src/corelib/doc/src/containers.qdoc
@@ -351,7 +351,8 @@
the problem exists for all the implicitly shared Qt containers.
\section3 Java-Style Iterators
- \l{java-style-iterators}{Java-Style iterators} were introduced in Qt 4. Their API is modelled
+ \l{java-style-iterators}{Java-Style iterators}
+ are modelled
on Java's iterator classes.
New code should prefer \l{STL-Style Iterators}.
@@ -387,16 +388,16 @@
\l{QHash}.
\row \li \l{QMap}<Key, T>
- \li Similar to std::map<T>.
+ \li Similar to std::map<Key, T>.
\row \li \l{QMultiMap}<Key, T>
- \li Similar to std::multimap<T>.
+ \li Similar to std::multimap<Key, T>.
\row \li \l{QHash}<Key, T>
- \li Most similar to std::unordered_map<T>.
+ \li Most similar to std::unordered_map<Key, T>.
\row \li \l{QMultiHash}<Key, T>
- \li Most similar to std::unordered_multimap<T>.
+ \li Most similar to std::unordered_multimap<Key, T>.
\endtable
diff --git a/src/corelib/doc/src/custom-types.qdoc b/src/corelib/doc/src/custom-types.qdoc
index 352a43549d..7922fd9477 100644
--- a/src/corelib/doc/src/custom-types.qdoc
+++ b/src/corelib/doc/src/custom-types.qdoc
@@ -6,7 +6,7 @@
\title Creating Custom Qt Types
\brief How to create and register new types with Qt.
- \ingroup best-practices
+ \ingroup how-to
\tableofcontents
@@ -37,7 +37,7 @@
The following \c Message class definition includes these members:
- \snippet tools/customtype/message.h custom type definition
+ \snippet customtype/customtypeexample.cpp custom type definition
The class also provides a constructor for normal use and two public member functions
that are used to obtain the private data.
@@ -53,11 +53,14 @@
to this class, we invoke the Q_DECLARE_METATYPE() macro on the class in the header
file where it is defined:
- \snippet tools/customtype/message.h custom type meta-type declaration
+ \snippet customtype/customtypeexample.cpp custom type meta-type declaration
This now makes it possible for \c Message values to be stored in QVariant objects
- and retrieved later. See the \l{Custom Type Example} for code that demonstrates
- this.
+ and retrieved later:
+
+ \snippet customtype/customtypeexample.cpp storing a custom value
+ \dots
+ \snippet customtype/customtypeexample.cpp retrieving a custom value
The Q_DECLARE_METATYPE() macro also makes it possible for these values to be used as
arguments to signals, but \e{only in direct signal-slot connections}.
@@ -77,7 +80,7 @@
available for queued signal-slot communication as long as you call it before you
make the first connection that uses the type.
- The \l{Queued Custom Type Example} declares a \c Block class which is registered
+ The \l{Queued Custom Type} example declares a \c Block class which is registered
in the \c{main.cpp} file:
\snippet threads/queuedcustomtype/main.cpp main start
@@ -107,18 +110,17 @@
It is often quite useful to make a custom type printable for debugging purposes,
as in the following code:
- \snippet tools/customtype/main.cpp printing a custom type
+ \snippet customtype/customtypeexample.cpp printing a custom type
This is achieved by creating a streaming operator for the type, which is often
defined in the header file for that type:
- \snippet tools/customtype/message.h custom type streaming operator
+ \snippet customtype/customtypeexample.cpp custom type streaming operator declaration
- The implementation for the \c Message type in the \l{Custom Type Example}
- goes to some effort to make the printable representation as readable as
- possible:
+ The implementation for the \c Message type here goes to some effort to make the
+ printable representation as readable as possible:
- \snippet tools/customtype/message.cpp custom type streaming operator
+ \snippet customtype/customtypeexample.cpp custom type streaming operator
The output sent to the debug stream can, of course, be made as simple or as
complicated as you like. Note that the value returned by this function is
@@ -131,9 +133,8 @@
The Q_DECLARE_METATYPE() macro and qRegisterMetaType() function documentation
contain more detailed information about their uses and limitations.
- The \l{Custom Type Example}{Custom Type} and \l{Queued Custom Type Example}
- {Queued Custom Type} examples show how to implement a custom type with the
- features outlined in this document.
+ The \l{Queued Custom Type} example shows how to implement a custom type with
+ the features outlined in this document.
The \l{Debugging Techniques} document provides an overview of the debugging
mechanisms discussed above.
diff --git a/src/corelib/doc/src/datastreamformat.qdoc b/src/corelib/doc/src/datastreamformat.qdoc
index b1b2e6ba34..65b7eb5a20 100644
--- a/src/corelib/doc/src/datastreamformat.qdoc
+++ b/src/corelib/doc/src/datastreamformat.qdoc
@@ -31,7 +31,11 @@
\li QBitArray
\li QBrush
\li QByteArray
+ \li QCborArray
+ \li QCborMap
+ \li QCborValue
\li QColor
+ \li QColorSpace
\li QCursor
\li QDate
\li QDateTime
@@ -39,32 +43,71 @@
\li QFont
\li QGenericMatrix
\li QHash<Key, T>
+ \li QHostAddress
\li QIcon
\li QImage
+ \li QJsonArray
+ \li QJsonDocument
+ \li QJsonObject
+ \li QJsonValue
\li QKeySequence
+ \li QLine
+ \li QLineF
\li QList<T>
+ \li QListWidgetItem
+ \li QLocale
\li QMap<Key, T>
\li QMargins
+ \li QMarginsF
\li QMatrix4x4
- \li QPair<T1, T2>
+ \li QModelIndex
+ \li QModelIndexList
+ \li QMultiHash<Key
+ \li QMultiMap<Key
+ \li QNetworkCacheMetaData
+ \li QNetworkCacheMetaData::AttributesMap
+ \li QPageRanges
+ \li QPainterPath
+ \li std::pair<T1, T2>
\li QPalette
\li QPen
\li QPicture
\li QPixmap
\li QPoint
+ \li QPointF
+ \li QPolygon
+ \li QPolygonF
\li QQuaternion
\li QRect
+ \li QRectF
\li QRegularExpression
\li QRegion
+ \li QSet
\li QSize
+ \li QSizeF
+ \li QSizePolicy
+ \li QStandardItem
\li QString
+ \li QTableWidgetItem
+ \li QTextBlockFormat
+ \li QTextCharFormat
+ \li QTextFormat
+ \li QTextFrameFormat
+ \li QTextLength
+ \li QTextListFormat
+ \li QTextTableCellFormat
+ \li QTimeZone
\li QTime
\li QTransform
+ \li QTreeWidgetItem
+ \li QTypeRevision
\li QUrl
+ \li QUuid
\li QVariant
\li QVector2D
\li QVector3D
\li QVector4D
+ \li QVersionNumber
\endlist
\sa {JSON Support in Qt}, {CBOR Support in Qt}
diff --git a/src/corelib/doc/src/external-resources.qdoc b/src/corelib/doc/src/external-resources.qdoc
index 71e6cf17c6..b787651aba 100644
--- a/src/corelib/doc/src/external-resources.qdoc
+++ b/src/corelib/doc/src/external-resources.qdoc
@@ -166,3 +166,8 @@
\externalpage https://cmake.org/cmake/help/latest/command/cmake_policy.html
\title cmake_policy
*/
+
+/*!
+ \externalpage https://cmake.org/cmake/help/latest/guide/importing-exporting/index.html#creating-packages
+ \title Creating CMake packages
+*/
diff --git a/src/corelib/doc/src/foreach-keyword.qdoc b/src/corelib/doc/src/foreach-keyword.qdoc
index 780be6e09c..b3a4482528 100644
--- a/src/corelib/doc/src/foreach-keyword.qdoc
+++ b/src/corelib/doc/src/foreach-keyword.qdoc
@@ -31,7 +31,7 @@
\snippet code/doc_src_containers.cpp 16
- Unless the data type contains a comma (e.g., \c{QPair<int,
+ Unless the data type contains a comma (e.g., \c{std::pair<int,
int>}), the variable used for iteration can be defined within the
\c foreach statement:
@@ -73,4 +73,15 @@
\c foreach would not. But using \c foreach always copies the container,
which is usually not cheap for STL containers. If in doubt, prefer
\c foreach for Qt containers, and range based \c for for STL ones.
+
+ You can remove the availability of the Qt's \c foreach loop by
+ defining the \c{QT_NO_FOREACH} macro.
+*/
+
+/*!
+ \macro QT_NO_FOREACH
+ \since 6.0
+
+ Defining this macro removes the availability of Qt's \c foreach
+ loop.
*/
diff --git a/src/corelib/doc/src/includes/cmake-android-qt-finalize-project-warning.qdocinc b/src/corelib/doc/src/includes/cmake-android-qt-finalize-project-warning.qdocinc
index 3f2a4ab6ec..47133f6d10 100644
--- a/src/corelib/doc/src/includes/cmake-android-qt-finalize-project-warning.qdocinc
+++ b/src/corelib/doc/src/includes/cmake-android-qt-finalize-project-warning.qdocinc
@@ -1,6 +1,8 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+//! [warning]
\warning If your \e Android project is built using a CMake version lower than
3.19, make sure that you call \l{qt_finalize_project}{qt6_finalize_project()} at
the end of a top-level CMakeLists.txt.
+//! [warning]
diff --git a/src/corelib/doc/src/includes/cmake-deploy-modified-variable-values.qdocinc b/src/corelib/doc/src/includes/cmake-deploy-modified-variable-values.qdocinc
index 6c1f20adb2..632ddf756f 100644
--- a/src/corelib/doc/src/includes/cmake-deploy-modified-variable-values.qdocinc
+++ b/src/corelib/doc/src/includes/cmake-deploy-modified-variable-values.qdocinc
@@ -2,8 +2,11 @@
cmake_minimum_required(VERSION 3.16...3.22)
project(MyThings)
+# The following CMAKE_INSTALL_*DIR variables are used to initialize their
+# QT_DEPLOY_*_DIR counterparts.
set(CMAKE_INSTALL_BINDIR "mybindir")
set(CMAKE_INSTALL_LIBDIR "mylibdir")
+set(CMAKE_INSTALL_LIBEXECDIR "mylibexecdir")
find_package(Qt6 REQUIRED COMPONENTS Core)
qt_standard_project_setup()
@@ -15,10 +18,13 @@ file(GENERATE OUTPUT ${deploy_script} CONTENT "
set(QT_DEPLOY_PLUGINS_DIR \"mypluginsdir\")
set(QT_DEPLOY_QML_DIR \"myqmldir\")
+set(QT_DEPLOY_TRANSLATIONS_DIR \"i18n\")
include(\"${QT_DEPLOY_SUPPORT}\")
qt_deploy_runtime_dependencies(
EXECUTABLE \"\${QT_DEPLOY_BIN_DIR}/$<TARGET_FILE_NAME:MyApp>\"
)")
+
+install(SCRIPT ${deploy_script})
\endcode
diff --git a/src/corelib/doc/src/includes/cmake-deploy-runtime-dependencies-deploy-tool-options.qdocinc b/src/corelib/doc/src/includes/cmake-deploy-runtime-dependencies-deploy-tool-options.qdocinc
new file mode 100644
index 0000000000..0f46379c45
--- /dev/null
+++ b/src/corelib/doc/src/includes/cmake-deploy-runtime-dependencies-deploy-tool-options.qdocinc
@@ -0,0 +1,20 @@
+\badcode
+set(deploy_tool_options_arg "")
+if(APPLE)
+ set(deploy_tool_options_arg --hardened-runtime)
+elseif(WIN32)
+ set(deploy_tool_options_arg --no-compiler-runtime)
+endif()
+
+# Generate a deployment script to be executed at install time
+qt_generate_deploy_script(
+ TARGET MyApp
+ OUTPUT_SCRIPT deploy_script
+ CONTENT "
+qt_deploy_runtime_dependencies(
+ EXECUTABLE \"${executable_path}\"
+ DEPLOY_TOOL_OPTIONS "${deploy_tool_options_arg}"
+ GENERATE_QT_CONF
+ VERBOSE
+)")
+\endcode
diff --git a/src/corelib/doc/src/includes/cmake-deploy-var-usage.qdocinc b/src/corelib/doc/src/includes/cmake-deploy-var-usage.qdocinc
index c5a1a40356..27e04b5b08 100644
--- a/src/corelib/doc/src/includes/cmake-deploy-var-usage.qdocinc
+++ b/src/corelib/doc/src/includes/cmake-deploy-var-usage.qdocinc
@@ -1,2 +1,6 @@
This variable is defined by the script named by \l QT_DEPLOY_SUPPORT. It should
only be used as part of deployment during installation or a post-build rule.
+
+\note This is a low-level deployment API variable, and should only be used in
+advanced use-cases that are not covered by the higher-level API commands, like
+\l{qt_generate_deploy_app_script}.
diff --git a/src/corelib/doc/src/includes/cmake-generate-deploy-app-script-deploy-tool-options.qdocinc b/src/corelib/doc/src/includes/cmake-generate-deploy-app-script-deploy-tool-options.qdocinc
new file mode 100644
index 0000000000..64c6b3e49f
--- /dev/null
+++ b/src/corelib/doc/src/includes/cmake-generate-deploy-app-script-deploy-tool-options.qdocinc
@@ -0,0 +1,16 @@
+\badcode
+set(deploy_tool_options_arg "")
+if(APPLE)
+ set(deploy_tool_options_arg --hardened-runtime)
+elseif(WIN32)
+ set(deploy_tool_options_arg --no-compiler-runtime)
+endif()
+
+qt_generate_deploy_app_script(
+ TARGET MyApp
+ OUTPUT_SCRIPT deploy_script
+ NO_UNSUPPORTED_PLATFORM_ERROR
+ DEPLOY_TOOL_OPTIONS ${deploy_tool_options_arg}
+)
+install(SCRIPT ${deploy_script})
+\endcode
diff --git a/src/corelib/doc/src/includes/cmake-generate-deploy-app-script.qdocinc b/src/corelib/doc/src/includes/cmake-generate-deploy-app-script.qdocinc
new file mode 100644
index 0000000000..d5c1d2cf4a
--- /dev/null
+++ b/src/corelib/doc/src/includes/cmake-generate-deploy-app-script.qdocinc
@@ -0,0 +1,21 @@
+\badcode
+cmake_minimum_required(VERSION 3.16...3.22)
+project(MyThings)
+
+find_package(Qt6 REQUIRED COMPONENTS Core)
+qt_standard_project_setup()
+
+qt_add_executable(MyApp main.cpp)
+
+install(TARGETS MyApp
+ BUNDLE DESTINATION .
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+)
+
+qt_generate_deploy_app_script(
+ TARGET MyApp
+ OUTPUT_SCRIPT deploy_script
+ NO_UNSUPPORTED_PLATFORM_ERROR
+)
+install(SCRIPT ${deploy_script})
+\endcode
diff --git a/src/corelib/doc/src/includes/models.qdocinc b/src/corelib/doc/src/includes/models.qdocinc
new file mode 100644
index 0000000000..cf840b1cae
--- /dev/null
+++ b/src/corelib/doc/src/includes/models.qdocinc
@@ -0,0 +1,14 @@
+//! [thread-safety-section1]
+\section1 Thread safety
+
+Being a \l {Accessing QObject Subclasses from Other Threads}{subclass of
+QObject}, \1 is not \l {Reentrancy and Thread-Safety}{thread-safe}. Any \1
+model-related API should only be called from the thread the model object lives
+in. If the \1 is connected with a view, that means the GUI thread, as that is
+where the view lives, and it will call into the model from the GUI thread.
+Using a background thread to populate or modify the contents of a model is
+possible, but requires care, as the background thread cannot call any
+model-related API directly. Instead, you should queue the updates and apply
+them in the main thread. This can be done with \l {Signals and Slots Across
+Threads}{queued connections}.
+//! [thread-safety-section1]
diff --git a/src/corelib/doc/src/includes/qstring.qdocinc b/src/corelib/doc/src/includes/qstring.qdocinc
index dade4f0af0..66ed12dff3 100644
--- a/src/corelib/doc/src/includes/qstring.qdocinc
+++ b/src/corelib/doc/src/includes/qstring.qdocinc
@@ -26,9 +26,9 @@ in this string, searching backward from index position \a from.
//! [qstring-local-8-bit-equivalent]
On Unix systems this is equivalent to \1().
Note that on Apple systems this function does not take
-\c\l{https://developer.apple.com/documentation/foundation/nsstring/1410091-defaultcstringencoding?language=objc}
+\l{https://developer.apple.com/documentation/foundation/nsstring/1410091-defaultcstringencoding?language=objc}
{NSString.defaultCStringEncoding} or
-\c\l{https://developer.apple.com/documentation/corefoundation/1541720-cfstringgetsystemencoding?language=objc}
+\l{https://developer.apple.com/documentation/corefoundation/1541720-cfstringgetsystemencoding?language=objc}
{CFStringGetSystemEncoding()} into account, as these functions
typically return the legacy "Western (Mac OS Roman)" encoding,
which should not be used on modern Apple operating systems.
diff --git a/src/corelib/doc/src/ipc.qdoc b/src/corelib/doc/src/ipc.qdoc
index 1de20f89a2..7ec6f5fa3b 100644
--- a/src/corelib/doc/src/ipc.qdoc
+++ b/src/corelib/doc/src/ipc.qdoc
@@ -7,6 +7,7 @@
\ingroup groups
\ingroup frameworks-technologies
\keyword ipc
+ \ingroup explanations-networkingandconnectivity
\brief An overview of Qt's inter-process communication functionality
@@ -85,7 +86,7 @@
\keyword ipc
\keyword shared memory
- \brief Overview of the techniques for sharing memory between processes
+ \brief Overview of the techniques for sharing memory between processes.
Qt provides two techniques to share memory with other processes in the same
system: \l{QSharedMemory} and memory-mapped files using \l{QFile}. Memory
@@ -273,7 +274,10 @@
file names, in particular those that separate path components (slash and
backslash), with the exception of sandboxed applications on Apple operating
systems. The following are good examples of cross-platform keys: "myapp",
- "org.example.myapp", "org.example.myapp-12345".
+ "org.example.myapp", "org.example.myapp-12345". Note that it is up to the
+ caller to prevent oversized keys, and to ensure that the key contains legal
+ characters on the respective platform. Qt will silently truncate keys that
+ are too long.
\b{Apple sandbox limitations:} if the application is running inside of a
sandbox in an Apple operating system, the key must be in a very specific
@@ -386,7 +390,7 @@
Qt's own build. For Windows systems, it was always the Windows backend. For
Unix systems, it defaulted to the System V backend if the configuration
script determined it was available. If it was not available, it fell back
- to the POSIX one (since Qt 4.8). The POSIX backend could be explicitly
+ to the POSIX one. The POSIX backend could be explicitly
selected using the \c{-feature-ipc_posix} option to the Qt configure
script; if it was enabled, the \c{QT_POSIX_IPC} macro would be defined.
@@ -410,7 +414,7 @@
It can be updated to be:
\code
QSharedMemory shm(QSharedMemory::legacyNativeKey("org.example.myapplication"));
- QSystemSempahore sem(QSystemSemaphore::legacyNativeKey("org.example.myapplication"));
+ QSystemSemaphore sem(QSystemSemaphore::legacyNativeKey("org.example.myapplication"));
\endcode
If the two applications exchanged native keys, there is no need to update
diff --git a/src/corelib/doc/src/json.qdoc b/src/corelib/doc/src/json.qdoc
index 3097075eb9..98ae202cfa 100644
--- a/src/corelib/doc/src/json.qdoc
+++ b/src/corelib/doc/src/json.qdoc
@@ -6,7 +6,7 @@
\title JSON Support in Qt
\ingroup qt-basic-concepts
\brief An overview of JSON support in Qt.
-
+ \ingroup explanations-dataprocessingandio
\ingroup frameworks-technologies
\keyword JSON
@@ -73,8 +73,7 @@
A valid JSON document is either an array or an object, so a document always starts
with a square or curly bracket.
- \sa {JSON Save Game Example}
-
+ \sa {Saving and Loading a Game}
\section1 The JSON Classes
@@ -82,5 +81,4 @@
\l{Implicit Sharing}{implicitly shared classes}.
JSON support in Qt consists of these classes:
-
*/
diff --git a/src/corelib/doc/src/objectmodel/bindableproperties.qdoc b/src/corelib/doc/src/objectmodel/bindableproperties.qdoc
index d6f96f6579..9b3ea6ae66 100644
--- a/src/corelib/doc/src/objectmodel/bindableproperties.qdoc
+++ b/src/corelib/doc/src/objectmodel/bindableproperties.qdoc
@@ -32,7 +32,7 @@
different objects.
The \l {Introductory Example} below demonstrates the usage of bindable
- properties in C++ code. You can also check \l {Bindable Properties Example}
+ properties in C++ code. You can also check \l {Bindable Properties} example
to see how the bindable properties can help to improve your code.
\section1 Introductory Example
@@ -256,8 +256,8 @@
Q_PROPERTYs without \c BINDABLE can also be bound and be used in binding expressions,
as long as they define a \c NOTIFY signal. You must wrap the property in a \l QBindable
using the \c {QBindable(QObject* obj, const char* property)} constructor. Then, the
- property can be bound using \c \l QBindable::setBinding() or used in a binding
- expression via \c \l QBindable::value(). You must use \c QBindable::value() in binding
+ property can be bound using \l QBindable::setBinding() or used in a binding
+ expression via \l QBindable::value(). You must use \c QBindable::value() in binding
expressions instead of the normal property \c READ function (or \c MEMBER) to enable
dependency tracking if the property is not \c BINDABLE.
diff --git a/src/corelib/doc/src/objectmodel/metaobjects.qdoc b/src/corelib/doc/src/objectmodel/metaobjects.qdoc
index 62226ca466..3d7685447f 100644
--- a/src/corelib/doc/src/objectmodel/metaobjects.qdoc
+++ b/src/corelib/doc/src/objectmodel/metaobjects.qdoc
@@ -5,7 +5,7 @@
\page metaobjects.html
\title The Meta-Object System
\brief An overview of Qt's meta-object system and introspection capabilities.
-
+ \ingroup explanations-basics
\ingroup qt-basic-concepts
\keyword meta-object
\keyword Meta-Object System
diff --git a/src/corelib/doc/src/objectmodel/properties.qdoc b/src/corelib/doc/src/objectmodel/properties.qdoc
index eef2df7028..99a3e60d88 100644
--- a/src/corelib/doc/src/objectmodel/properties.qdoc
+++ b/src/corelib/doc/src/objectmodel/properties.qdoc
@@ -5,7 +5,7 @@
\page properties.html
\title The Property System
\brief An overview of Qt's property system.
-
+ \ingroup explanations-basics
\ingroup qt-basic-concepts
\keyword Qt's Property System
@@ -93,7 +93,7 @@
\li The \c DESIGNABLE attribute indicates whether the property
should be visible in the property editor of GUI design tool (e.g.,
- \l {Qt Designer Manual}{Qt Designer}). Most properties are \c DESIGNABLE
+ \l {Qt Widgets Designer Manual}{\QD}). Most properties are \c DESIGNABLE
(default true). Valid values are true and false.
\li The \c SCRIPTABLE attribute indicates whether this property
@@ -208,7 +208,10 @@
The \c READ function is const and returns the property type. The
\c WRITE function returns void and has exactly one parameter of
the property type. The meta-object compiler enforces these
- requirements.
+ requirements. The equality check in the \c WRITE function, while not
+ mandatory, is good practice as there is no point in notifying and
+ potentially forcing re-evaluation in other places if nothing has
+ changed.
Given a pointer to an instance of MyClass or a pointer to a
QObject that is an instance of MyClass, we have two ways to set
@@ -274,7 +277,9 @@
Connected to the property system is an additional macro,
Q_CLASSINFO(), that can be used to attach additional
- \e{name}--\e{value} pairs to a class's meta-object, for example:
+ \e{name}--\e{value} pairs to a class's meta-object. This is
+ used for instance to mark a property as the \e default one
+ in the context of \l{QML Object Types}:
\snippet code/doc_src_properties.cpp 7
@@ -296,5 +301,5 @@
and the general tips on implementing and using
\l {Qt Bindable Properties}{bindable properties}.
- \sa {Qt Bindable Properties}
+ \sa {Qt Bindable Properties}, {Defining QML Types from C++}
*/
diff --git a/src/corelib/doc/src/objectmodel/signalsandslots.qdoc b/src/corelib/doc/src/objectmodel/signalsandslots.qdoc
index 1b427f5775..f0eeb20048 100644
--- a/src/corelib/doc/src/objectmodel/signalsandslots.qdoc
+++ b/src/corelib/doc/src/objectmodel/signalsandslots.qdoc
@@ -8,7 +8,7 @@
\ingroup qt-basic-concepts
\brief An overview of Qt's signals and slots inter-object
communication mechanism.
-
+ \ingroup explanations-basics
Signals and slots are used for communication between objects. The
signals and slots mechanism is a central feature of Qt and
probably the part that differs most from the features provided by
@@ -109,8 +109,7 @@
when the signal is emitted.
Signals are automatically generated by the \l moc and must not be
- implemented in the \c .cpp file. They can never have return types
- (i.e. use \c void).
+ implemented in the \c .cpp file.
A note about arguments: Our experience shows that signals and slots
are more reusable if they do not use special types. If
@@ -297,8 +296,7 @@
callbacks, you'd have to find five different names and keep track
of the types yourself.
- \sa QLCDNumber, QObject::connect(), {Digital Clock Example},
- {Tetrix Example}
+ \sa QLCDNumber, QObject::connect()
\section1 Signals And Slots With Default Arguments
diff --git a/src/corelib/doc/src/qt6-changes.qdoc b/src/corelib/doc/src/qt6-changes.qdoc
index 5073a72d6a..011568ef75 100644
--- a/src/corelib/doc/src/qt6-changes.qdoc
+++ b/src/corelib/doc/src/qt6-changes.qdoc
@@ -5,7 +5,7 @@
\page qtcore-changes-qt6.html
\title Changes to Qt Core
\ingroup changes-qt-5-to-6
- \brief Migrate Qt Core to Qt 6.
+ \brief Changes to containers, strings, serialization and I/O classes.
Qt 6 is a result of the conscious effort to make the framework more
efficient and easy to use.
diff --git a/src/corelib/doc/src/qtcore-index.qdoc b/src/corelib/doc/src/qtcore-index.qdoc
index 48f7765568..38452e1b2b 100644
--- a/src/corelib/doc/src/qtcore-index.qdoc
+++ b/src/corelib/doc/src/qtcore-index.qdoc
@@ -79,6 +79,7 @@
\li \l{Inter-Process Communication}
\li \l{How to Create Qt Plugins}
\li \l{The Event System}
+ \li \l{Application Permissions}
\endlist
\section1 Reference
diff --git a/src/corelib/doc/src/qtserialization.qdoc b/src/corelib/doc/src/qtserialization.qdoc
index 528a4aa827..14ee5e7a9c 100644
--- a/src/corelib/doc/src/qtserialization.qdoc
+++ b/src/corelib/doc/src/qtserialization.qdoc
@@ -109,13 +109,20 @@
\section1 Advantages of Qt XML C++ Classes
+ Qt provides both DOM classes and stream-based classes to read and write
+ XML content.
+
Qt provides the QDomDocument class that represents the XML document and
two classes for reading and writing the XML through a simple streaming API:
QXmlStreamReader and QXmlStreamWriter.
+ \section2 The DOM XML Classes
+
QDomDocument class represents the entire XML document. It is the root of the
document tree and provides primary access to the document's data.
+ \section2 The Stream-Based XML Classes
+
A stream reader reports an XML document as a stream of tokens. This differs
from SAX as SAX applications provide handlers to receive XML events from the
parser, whereas the QXmlStreamReader drives the loop, pulling tokens from the
@@ -132,7 +139,7 @@
The QXmlStreamWriter is a streaming API that takes care of prefixing namespaces,
when the namespaceUri is specified when writing elements or attributes.
- \section1 Classes that provide serialization
+ \section1 Classes that Provide Serialization
\annotatedlist qtserialization
*/
diff --git a/src/corelib/doc/src/resource-system.qdoc b/src/corelib/doc/src/resource-system.qdoc
index a0d253799a..7c7613c9b8 100644
--- a/src/corelib/doc/src/resource-system.qdoc
+++ b/src/corelib/doc/src/resource-system.qdoc
@@ -17,7 +17,7 @@
Most commonly, the resource files are embedded into your application
executable, or in libraries and plugins that are loaded by the application
executable. Alternatively, the resource files can also be stored in an
- \l{External Resource Files}{exernal resource file}.
+ \l{External Resource Files}{external resource file}.
The resource system is based on tight cooperation between Qt's \l rcc
resource compiler, the build system, and the Qt runtime API.
@@ -59,8 +59,8 @@
the \c .qrc file.
The path is also used by default to identify the file's content at runtime.
- That is, the file \c copy.png will be available in the resource system as
- \c{:/images/copy.png} or \c{qrc:/images/copy.png}.
+ That is, the file \c titlebarLeft.png will be available in the resource system as
+ \c{:/res/titlebarLeft.png} or \c{qrc:/res/titlebarLeft.png}.
To override this default run-time name, see \l{Prefixes} and \l{Aliases}.
\e{Qt Creator}, \e{Qt Design Studio}, \QD, and \e{Qt Visual Studio Tools}
@@ -102,22 +102,16 @@
variable. If you add a \c .qrc file path to the variable, the listed
resource files will be embedded into the generated library or executable:
- \snippet resource-system/application.pro 0
-
- For simple applications, it is also possible to let qmake generate the
- \c .qrc file for you, avoiding the need for an additional file to be
- maintained:
-
- \snippet resource-system/application.pro 1
+ \snippet resource-system/application.pro qrc
This creates a resource of several \c{.png} files, that are addressable
- like this: \c{":/images/copy.png"}.
+ like this: \c{":/res/titlebarLeft.png"}.
If the directory layout of the files you want to embed into the resource
doesn't match the expectations of the application, you can specify
\c{resources.base}. \c base is a path prefix that denotes the root point of
the file's alias. In the example above, if \c{resources.base} is set to
- \c{"images"}, then \c{copy.png} is addressable as \c{":/copy.png"}.
+ \c{"res"}, then \c{titlebarLeft.png} is addressable as \c{":/titlebarLeft.png"}.
\section1 Runtime API
@@ -136,9 +130,6 @@
\snippet resource-system/main.cpp url
- See the \l{mainwindows/application}{Application} example for an actual
- application that uses Qt's resource system to store its icons.
-
\section1 Advanced Topics
\section2 Prefixes
@@ -216,14 +207,7 @@
resource file's content and metadata is then done after the compilation and
linking phase, through another rcc call.
- For qmake, this is enabled by adding \c resources_big to the \c CONFIG
- variable:
-
- \snippet resource-system/application.pro 2
-
- For CMake, you need to use the \l{qt_add_big_resources} function:
-
- \snippet resource-system/CMakeLists.txt qt_add_big_resources
+ For CMake, you need to use the \l{qt_add_big_resources} function.
\section2 External Resource Files
@@ -251,13 +235,13 @@
resource compiler \l rcc:
\code
- rcc -g python application.qrc > application_rc.py
+ rcc -g python mainwindow.qrc > mainwindow_rc.py
\endcode
The module can then be imported in the application:
\code
- import application_rc.py
+ import mainwindow_rc.py
\endcode
\section2 Compression
diff --git a/src/corelib/doc/src/timers.qdoc b/src/corelib/doc/src/timers.qdoc
index 1d5a48af3d..dc205a47b9 100644
--- a/src/corelib/doc/src/timers.qdoc
+++ b/src/corelib/doc/src/timers.qdoc
@@ -6,17 +6,17 @@
\title Timers
\brief How to use Qt timers in your application.
- \ingroup best-practices
+ \ingroup how-to
QObject, the base class of all Qt objects, provides the basic
timer support in Qt. With QObject::startTimer(), you start a
timer with an interval in milliseconds as argument. The function
- returns a unique integer timer ID. The timer will now fire at
+ returns a unique integral timer ID. The timer will then fire at
regular intervals until you explicitly call QObject::killTimer()
- with the timer ID.
+ with that timer ID.
For this mechanism to work, the application must run in an event
- loop. You start an event loop with QApplication::exec(). When a
+ loop. You cat start an event loop with QApplication::exec(). When a
timer fires, the application sends a QTimerEvent, and the flow of
control leaves the event loop until the timer event is processed.
This implies that a timer cannot fire while your application is
@@ -31,69 +31,65 @@
stop all timers in the object's thread; it is not possible to
start timers for objects in another thread.
- The upper limit for the interval value is determined by the number
- of milliseconds that can be specified in a signed integer
- (in practice, this is a period of just over 24 days). The accuracy
- depends on the underlying operating system. Windows 2000 has 15
- millisecond accuracy; other systems that we have tested can handle
- 1 millisecond intervals.
-
- The main API for the timer functionality is QTimer. That class
- provides regular timers that emit a signal when the timer fires, and
- inherits QObject so that it fits well into the ownership structure
- of most Qt programs. The normal way of using it is like this:
-
- \snippet timers/timers.cpp 0
- \snippet timers/timers.cpp 1
- \snippet timers/timers.cpp 2
-
- The QTimer object is made into a child of \c this object so that,
- when \c this object is deleted, the timer is deleted too.
- Next, its \l{QTimer::}{timeout()} signal is connected to the slot
- that will do the work, it is started with a value of 1000
- milliseconds, indicating that it will time out every second.
-
- QTimer also provides a static function for single-shot timers.
+ The main API for the timer functionality was \l QTimer. QTimer stores
+ the interval in a signed integer, which limits the maximum interval it
+ supports to the number of milliseconds that can fit in a signed integer
+ (in practice, this is a period of around 24 days).
+
+ Qt 6.8 introduced the \l QChronoTimer class to replace QTimer. QChronoTimer
+ stores the interval as \c std::chrono::nanoseconds, which means that
+ the maximum interval it supports is around 292 years. This mitigates
+ the chances of integer overflow that QTimer had if the interval was more
+ than \c{std::numeric_limits<int>::max()}.
+
+ The accuracy of the timers depends on the underlying operating system.
+ Windows 2000 has 15ms accuracy; other systems that we have tested can
+ handle 1ms intervals.
+
+ QChronoTimer provides regular timers that emit a signal when the timer
+ fires, and inherits from QObject so that it fits well into the ownership
+ structure of most Qt programs. The normal way of using it is like this:
+
+ \snippet timers/timers.cpp timer-interval-in-ctor
+ \snippet timers/timers.cpp timer-setinterval
+
+ The QChronoTimer object is made into a child of the \c this object so
+ that, when \c this is destroyed, the timer is destroyed too. Next, the
+ \l{QChronoTimer::}{timeout()} signal is connected to the slot that will
+ do the work, the timer interval can be either passed to the constructor,
+ or set later on with setInterval().
+
+ QChronoTimer also provides static functions for single-shot timers.
For example:
- \snippet timers/timers.cpp 3
+ \snippet timers/timers.cpp qchronotimer-singleshot
- 200 milliseconds (0.2 seconds) after this line of code is
- executed, the \c updateCaption() slot will be called.
+ 200ms after this line of code is executed, the \c updateCaption() slot
+ will be called.
- For QTimer to work, you must have an event loop in your
- application; that is, you must call QCoreApplication::exec()
- somewhere. Timer events will be delivered only while the event
- loop is running.
+ For QChronoTimer to work, you must have an event loop in your application;
+ that is, you must call QCoreApplication::exec() somewhere. Timer events
+ will be delivered only while the event loop is running.
- In multithreaded applications, you can use QTimer in any thread
- that has an event loop. To start an event loop from a non-GUI
- thread, use QThread::exec(). Qt uses the timer's
- \l{QObject::thread()}{thread affinity} to determine which thread
- will emit the \l{QTimer::}{timeout()} signal. Because of this, you
- must start and stop the timer in its thread; it is not possible to
- start a timer from another thread.
-
- The \l{widgets/analogclock}{Analog Clock} example shows how to use
- QTimer to redraw a widget at regular intervals. From \c{AnalogClock}'s
- implementation:
-
- \snippet timers/analogclock.cpp 0
- \snippet timers/analogclock.cpp 2
- \snippet timers/analogclock.cpp 3
- \snippet timers/analogclock.cpp 4
- \snippet timers/analogclock.cpp 5
- \snippet timers/analogclock.cpp 6
- \dots
- \snippet timers/analogclock.cpp 7
-
- Every second, QTimer will call the QWidget::update() slot to
+ In multithreaded applications, you can use QChronoTimer in any thread
+ that has an event loop. To start an event loop from a non-GUI thread, use
+ QThread::exec(). Qt uses the timer's \l{QObject::thread()}{thread affinity}
+ to determine which thread will emit the \l{QChronoTimer::}{timeout()}
+ signal. Because of this, you must start and stop the timer in its thread;
+ it is not possible to start a timer from another thread.
+
+ The \l{widgets/analogclock}{Analog Clock} example shows how to
+ use QChronoTimer to redraw a widget at regular intervals. From
+ \c{AnalogClock}'s implementation:
+
+ \snippet timers/analogclock.cpp analogclock-qchronotimer
+
+ Every second, QChronoTimer will call the QWidget::update() slot to
refresh the clock's display.
If you already have a QObject subclass and want an easy
optimization, you can use QBasicTimer instead of QTimer. With
QBasicTimer, you must reimplement
\l{QObject::timerEvent()}{timerEvent()} in your QObject subclass
- and handle the timeout there. The \l{widgets/tetrix}{Tetrix}
- example shows how to use QBasicTimer.
+ and handle the timeout there.
*/
diff --git a/src/corelib/global/minimum-linux_p.h b/src/corelib/global/minimum-linux_p.h
index 509ad792f7..d52df474fb 100644
--- a/src/corelib/global/minimum-linux_p.h
+++ b/src/corelib/global/minimum-linux_p.h
@@ -22,6 +22,7 @@
//
#include "private/qglobal_p.h"
+#include <sys/stat.h>
QT_BEGIN_NAMESPACE
@@ -35,18 +36,17 @@ QT_BEGIN_NAMESPACE
* - FUTEX_PRIVATE_FLAG 2.6.22
* - O_CLOEXEC 2.6.23
* - eventfd 2.6.23
+ * - FUTEX_WAIT_BITSET 2.6.25
* - pipe2 & dup3 2.6.27
* - accept4 2.6.28
* - renameat2 3.16 QT_CONFIG(renameat2)
* - getrandom 3.17 QT_CONFIG(getentropy)
- * - statx 4.11 QT_CONFIG(statx)
+ * - statx 4.11 STATX_BASIC_STATS
*/
-#if QT_CONFIG(statx) && !QT_CONFIG(glibc)
+#if defined(__GLIBC__) && defined(STATX_BASIC_STATS)
// if using glibc, the statx() function in sysdeps/unix/sysv/linux/statx.c
// falls back to stat() for us.
-// (Using QT_CONFIG(glibc) instead of __GLIBC__ because the macros aren't
-// defined in assembler mode)
# define QT_ELF_NOTE_OS_MAJOR 4
# define QT_ELF_NOTE_OS_MINOR 11
# define QT_ELF_NOTE_OS_PATCH 0
@@ -59,6 +59,7 @@ QT_BEGIN_NAMESPACE
# define QT_ELF_NOTE_OS_MINOR 16
# define QT_ELF_NOTE_OS_PATCH 0
#else
+
# define QT_ELF_NOTE_OS_MAJOR 2
# define QT_ELF_NOTE_OS_MINOR 6
# define QT_ELF_NOTE_OS_PATCH 28
diff --git a/src/corelib/global/q20algorithm.h b/src/corelib/global/q20algorithm.h
index f670a5dbee..24d801b2cd 100644
--- a/src/corelib/global/q20algorithm.h
+++ b/src/corelib/global/q20algorithm.h
@@ -147,7 +147,7 @@ using std::ranges::none_of;
[[maybe_unused]] inline constexpr struct { // Niebloid
template <typename InputIterator, typename Sentinel,
typename Predicate, typename Projection = q20::identity>
- constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
+ [[maybe_unused]] constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
{
while (first != last) {
if (std::invoke(pred, std::invoke(proj, *first)))
@@ -160,7 +160,7 @@ using std::ranges::none_of;
[[maybe_unused]] inline constexpr struct { // Niebloid
template <typename InputIterator, typename Sentinel,
typename Predicate, typename Projection = q20::identity>
- constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
+ [[maybe_unused]] constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
{
while (first != last) {
if (!std::invoke(pred, std::invoke(proj, *first)))
@@ -173,7 +173,7 @@ using std::ranges::none_of;
[[maybe_unused]] inline constexpr struct { // Niebloid
template <typename InputIterator, typename Sentinel,
typename Predicate, typename Projection = q20::identity>
- constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
+ [[maybe_unused]] constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
{
while (first != last) {
if (std::invoke(pred, std::invoke(proj, *first)))
diff --git a/src/corelib/global/q20chrono.h b/src/corelib/global/q20chrono.h
new file mode 100644
index 0000000000..19c2eabe3d
--- /dev/null
+++ b/src/corelib/global/q20chrono.h
@@ -0,0 +1,62 @@
+// Copyright (C) 2023 Ahmad Samir <a.samirh78@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef Q20CHRONO_H
+#define Q20CHRONO_H
+
+#include <QtCore/qtconfigmacros.h>
+
+#include <chrono>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. Types and functions defined in this
+// file can reliably be replaced by their std counterparts, once available.
+// You may use these definitions in your own code, but be aware that we
+// will remove them once Qt depends on the C++ version that supports
+// them in namespace std. There will be NO deprecation warning, the
+// definitions will JUST go away.
+//
+// If you can't agree to these terms, don't use these definitions!
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+namespace q20 {
+namespace chrono {
+
+#if defined(__GLIBCXX__)
+// https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/include/bits/chrono.h
+using IntRep = int64_t;
+#else
+// https://github.com/llvm/llvm-project/blob/main/libcxx/include/__chrono/duration.h
+// https://github.com/microsoft/STL/blob/main/stl/inc/__msvc_chrono.hpp
+using IntRep = int;
+#endif
+
+#if __cpp_lib_chrono >= 201907L
+using std::chrono::days;
+using std::chrono::weeks;
+using std::chrono::years;
+using std::chrono::months;
+
+static_assert(std::is_same_v<days::rep, IntRep>);
+static_assert(std::is_same_v<weeks::rep, IntRep>);
+static_assert(std::is_same_v<years::rep, IntRep>);
+static_assert(std::is_same_v<months::rep, IntRep>);
+#else
+using days = std::chrono::duration<IntRep, std::ratio<86400>>;
+using weeks = std::chrono::duration<IntRep, std::ratio_multiply<std::ratio<7>, days::period>>;
+using years = std::chrono::duration<IntRep, std::ratio_multiply<std::ratio<146097, 400>, days::period>>;
+using months = std::chrono::duration<IntRep, std::ratio_divide<years::period, std::ratio<12>>>;
+#endif // __cpp_lib_chrono >= 201907L
+} // namespace chrono
+} // namespace q20
+
+QT_END_NAMESPACE
+
+#endif /* Q20CHRONO_H */
diff --git a/src/corelib/global/q20iterator.h b/src/corelib/global/q20iterator.h
index 23b6406b64..9ed4d69965 100644
--- a/src/corelib/global/q20iterator.h
+++ b/src/corelib/global/q20iterator.h
@@ -39,6 +39,16 @@ namespace q20 {
#endif
} // namespace q20
+// like q20::iter_reference_t
+namespace q20 {
+#ifdef __cpp_lib_ranges
+ using std::iter_reference_t;
+#else
+ template <typename Dereferencable> // unconstrained (constraint requires concepts)
+ using iter_reference_t = decltype(*std::declval<Dereferencable&>());
+#endif // __cpp_lib_ranges
+} // namespace q20
+
QT_END_NAMESPACE
#endif /* Q20ITERATOR_H */
diff --git a/src/corelib/global/q20map.h b/src/corelib/global/q20map.h
new file mode 100644
index 0000000000..c719067480
--- /dev/null
+++ b/src/corelib/global/q20map.h
@@ -0,0 +1,72 @@
+// Copyright (C) 2023 Ahmad Samir <a.samirh78@gmail.com>
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef Q20MAP_H
+#define Q20MAP_H
+
+#include <QtCore/qtconfigmacros.h>
+
+#include <map>
+#if __has_include(<memory_resource>)
+# include <memory_resource>
+#endif
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. Types and functions defined in this
+// file can reliably be replaced by their std counterparts, once available.
+// You may use these definitions in your own code, but be aware that we
+// will remove them once Qt depends on the C++ version that supports
+// them in namespace std. There will be NO deprecation warning, the
+// definitions will JUST go away.
+//
+// If you can't agree to these terms, don't use these definitions!
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+namespace q20 {
+// like std::erase/std::erase_if for std::map
+#if defined(__cpp_lib_erase_if) && __cpp_lib_erase_if >= 202002L // the one returning size_type
+using std::erase_if;
+#else
+
+// Make it more specialized than the compiler's, so that our implementation is preferred over
+// the compiler's (which may be present, but return void instead of the number of erased elements).
+
+#define MAKE_OVERLOAD(map, allocator) \
+ template <typename Key, typename T, typename Compare, typename Pred> \
+ constexpr typename std::map<Key, T, Compare, std::allocator<std::pair<const Key, T>>>::size_type \
+ erase_if(std::map<Key, T, Compare, std::allocator<std::pair<const Key, T>>> &c, Pred p) \
+ { \
+ const auto origSize = c.size(); \
+ for (auto it = c.begin(), end = c.end(); it != end; /* erasing */) { \
+ if (p(*it)) \
+ it = c.erase(it); \
+ else \
+ ++it; \
+ } \
+ return origSize - c.size(); \
+ } \
+ /* end */
+
+MAKE_OVERLOAD(map, allocator)
+MAKE_OVERLOAD(multimap, allocator)
+#ifdef __cpp_lib_polymorphic_allocator
+MAKE_OVERLOAD(map, pmr::polymorphic_allocator)
+MAKE_OVERLOAD(multimap, pmr::polymorphic_allocator)
+#endif // __cpp_lib_polymorphic_allocator
+
+#undef MAKE_OVERLOAD
+
+#endif // __cpp_lib_erase_if
+} // namespace q20
+
+QT_END_NAMESPACE
+
+#endif /* Q20MAP_H */
diff --git a/src/corelib/global/q20memory.h b/src/corelib/global/q20memory.h
index bb337a9f7f..008f4ddeb2 100644
--- a/src/corelib/global/q20memory.h
+++ b/src/corelib/global/q20memory.h
@@ -1,4 +1,5 @@
// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef Q20MEMORY_H
@@ -7,9 +8,9 @@
#include <QtCore/qtconfigmacros.h>
#include <memory>
-#include <utility>
#include <type_traits>
+#include <utility>
//
// W A R N I N G
@@ -45,6 +46,48 @@ T *construct_at(T *ptr, Args && ... args)
#endif // __cpp_lib_constexpr_dynamic_alloc
} // namespace q20
+
+namespace q20 {
+// like std::to_address
+#ifdef __cpp_lib_to_address
+using std::to_address;
+#else
+// http://eel.is/c++draft/pointer.conversion
+template <typename T>
+constexpr T *to_address(T *p) noexcept {
+ // http://eel.is/c++draft/pointer.conversion#1:
+ // Mandates: T is not a function type.
+ static_assert(!std::is_function_v<T>, "to_address must not be used on function types");
+ return p;
+}
+
+template <typename Ptr, typename std::enable_if_t<!std::is_pointer_v<Ptr>, bool> = true>
+constexpr auto to_address(const Ptr &ptr) noexcept; // fwd declared
+
+namespace detail {
+ // http://eel.is/c++draft/pointer.conversion#3
+ template <typename Ptr, typename = void>
+ struct to_address_helper {
+ static auto get(const Ptr &ptr) noexcept
+ { return q20::to_address(ptr.operator->()); }
+ };
+ template <typename Ptr>
+ struct to_address_helper<Ptr, std::void_t<
+ decltype(std::pointer_traits<Ptr>::to_address(std::declval<const Ptr&>()))
+ >>
+ {
+ static auto get(const Ptr &ptr) noexcept
+ { return std::pointer_traits<Ptr>::to_address(ptr); }
+ };
+} // namespace detail
+
+template <typename Ptr, typename std::enable_if_t<!std::is_pointer_v<Ptr>, bool>>
+constexpr auto to_address(const Ptr &ptr) noexcept
+{ return detail::to_address_helper<Ptr>::get(ptr); }
+
+#endif // __cpp_lib_to_address
+} // namespace q20
+
QT_END_NAMESPACE
#endif /* Q20MEMORY_H */
diff --git a/src/corelib/global/q20type_traits.h b/src/corelib/global/q20type_traits.h
index 2e812ed39c..63a453daca 100644
--- a/src/corelib/global/q20type_traits.h
+++ b/src/corelib/global/q20type_traits.h
@@ -3,6 +3,8 @@
#ifndef Q20TYPE_TRAITS_H
#define Q20TYPE_TRAITS_H
+#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qsystemdetection.h>
#include <QtCore/qtconfigmacros.h>
//
@@ -26,6 +28,29 @@
QT_BEGIN_NAMESPACE
namespace q20 {
+// like std::is_constant_evaluated
+#ifdef __cpp_lib_is_constant_evaluated
+using std::is_constant_evaluated;
+#define QT_SUPPORTS_IS_CONSTANT_EVALUATED
+#else
+constexpr bool is_constant_evaluated() noexcept
+{
+#ifdef Q_OS_INTEGRITY
+ // Integrity complains "calling __has_builtin() from a constant expression".
+ // Avoid the __has_builtin check until we know what's going on.
+ return false;
+#elif __has_builtin(__builtin_is_constant_evaluated) || \
+ (defined(Q_CC_MSVC_ONLY) /* >= 1925, but we require 1927 in qglobal.h */)
+# define QT_SUPPORTS_IS_CONSTANT_EVALUATED
+ return __builtin_is_constant_evaluated();
+#else
+ return false;
+#endif
+}
+#endif // __cpp_lib_is_constant_evaluated
+}
+
+namespace q20 {
// like std::remove_cvref(_t)
#ifdef __cpp_lib_remove_cvref
using std::remove_cvref;
@@ -38,6 +63,19 @@ using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
#endif // __cpp_lib_remove_cvref
}
+namespace q20 {
+// like std::type_identity(_t)
+#ifdef __cpp_lib_type_identity
+using std::type_identity;
+using std::type_identity_t;
+#else
+template <typename T>
+struct type_identity { using type = T; };
+template <typename T>
+using type_identity_t = typename type_identity<T>::type;
+#endif // __cpp_lib_type_identity
+}
+
QT_END_NAMESPACE
#endif /* Q20TYPE_TRAITS_H */
diff --git a/src/corelib/global/q20vector.h b/src/corelib/global/q20vector.h
new file mode 100644
index 0000000000..9d312355ea
--- /dev/null
+++ b/src/corelib/global/q20vector.h
@@ -0,0 +1,90 @@
+// Copyright (C) 2023 Ahmad Samir <a.samirh78@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef Q20VECTOR_H
+#define Q20VECTOR_H
+
+#include <QtCore/qtconfigmacros.h>
+
+#include <algorithm>
+#include <vector>
+#if __has_include(<memory_resource>)
+# include <memory_resource>
+#endif
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. Types and functions defined in this
+// file can reliably be replaced by their std counterparts, once available.
+// You may use these definitions in your own code, but be aware that we
+// will remove them once Qt depends on the C++ version that supports
+// them in namespace std. There will be NO deprecation warning, the
+// definitions will JUST go away.
+//
+// If you can't agree to these terms, don't use these definitions!
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+namespace q20 {
+// like std::erase/std::erase_if for std::vector
+#if defined(__cpp_lib_erase_if) && __cpp_lib_erase_if >= 202002L // the one returning size_type
+using std::erase;
+using std::erase_if;
+#else
+
+// Make it more specialized than the compiler's, so that our implementation is preferred over
+// the compiler's (which may be present, but return void instead of the number of erased elements).
+
+template <typename T, typename U>
+constexpr typename std::vector<T, std::allocator<T>>::size_type
+erase(std::vector<T, std::allocator<T>> &c, const U &value)
+{
+ const auto origSize = c.size();
+ auto it = std::remove(c.begin(), c.end(), value);
+ c.erase(it, c.end());
+ return origSize - c.size();
+}
+
+template <typename T, typename Pred>
+constexpr typename std::vector<T, std::allocator<T>>::size_type
+erase_if(std::vector<T, std::allocator<T>> &c, Pred pred)
+{
+ const auto origSize = c.size();
+ auto it = std::remove_if(c.begin(), c.end(), pred);
+ c.erase(it, c.end());
+ return origSize - c.size();
+}
+
+#ifdef __cpp_lib_polymorphic_allocator
+template <typename T, typename U>
+constexpr typename std::vector<T, std::pmr::polymorphic_allocator<T>>::size_type
+erase(std::vector<T, std::pmr::polymorphic_allocator<T>> &c, const U &value)
+{
+ const auto origSize = c.size();
+ auto it = std::remove(c.begin(), c.end(), value);
+ c.erase(it, c.end());
+ return origSize - c.size();
+}
+
+template <typename T, typename Pred>
+constexpr typename std::vector<T, std::pmr::polymorphic_allocator<T>>::size_type
+erase_if(std::vector<T, std::pmr::polymorphic_allocator<T>> &c, Pred pred)
+{
+ const auto origSize = c.size();
+ auto it = std::remove_if(c.begin(), c.end(), pred);
+ c.erase(it, c.end());
+ return origSize - c.size();
+}
+#endif // __cpp_lib_polymorphic_allocator
+
+#endif // __cpp_lib_erase_if
+} // namespace q20
+
+QT_END_NAMESPACE
+
+#endif /* Q20VECTOR_H */
diff --git a/src/corelib/global/qassert.cpp b/src/corelib/global/qassert.cpp
index 4165429d4b..6a29cbfa21 100644
--- a/src/corelib/global/qassert.cpp
+++ b/src/corelib/global/qassert.cpp
@@ -5,14 +5,51 @@
#include <QtCore/qlogging.h>
+#include <cstdlib>
#include <cstdio>
#include <exception>
#ifndef QT_NO_EXCEPTIONS
#include <new>
#endif
+#if defined(Q_CC_MSVC)
+# include <crtdbg.h>
+#endif
+#ifdef Q_OS_WIN
+# include <qt_windows.h>
+#endif
+
QT_BEGIN_NAMESPACE
+void qAbort()
+{
+#ifdef Q_OS_WIN
+ // std::abort() in the MSVC runtime will call _exit(3) if the abort
+ // behavior is _WRITE_ABORT_MSG - see also _set_abort_behavior(). This is
+ // the default for a debug-mode build of the runtime. Worse, MinGW's
+ // std::abort() implementation (in msvcrt.dll) is basically a call to
+ // _exit(3) too. Unfortunately, _exit() and _Exit() *do* run the static
+ // destructors of objects in DLLs, a violation of the C++ standard (see
+ // [support.start.term]). So we bypass std::abort() and directly
+ // terminate the application.
+
+# if defined(Q_CC_MSVC)
+ if (IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE))
+ __fastfail(FAST_FAIL_FATAL_APP_EXIT);
+# else
+ RaiseFailFastException(nullptr, nullptr, 0);
+# endif
+
+ // Fallback
+ TerminateProcess(GetCurrentProcess(), STATUS_FATAL_APP_EXIT);
+
+ // Tell the compiler the application has stopped.
+ Q_UNREACHABLE_IMPL();
+#else // !Q_OS_WIN
+ std::abort();
+#endif
+}
+
/*!
\macro void Q_ASSERT(bool test)
\relates <QtAssert>
@@ -139,31 +176,52 @@ void qBadAlloc()
/*!
\macro void Q_ASSUME(bool expr)
+ \deprecated
\relates <QtAssert>
\since 5.0
- Causes the compiler to assume that \a expr is \c true. This macro is useful
- for improving code generation, by providing the compiler with hints about
- conditions that it would not otherwise know about. However, there is no
- guarantee that the compiler will actually use those hints.
+ Causes the compiler to assume that \a expr is \c true.
- This macro could be considered a "lighter" version of \l{Q_ASSERT()}. While
- Q_ASSERT will abort the program's execution if the condition is \c false,
- Q_ASSUME will tell the compiler not to generate code for those conditions.
- Therefore, it is important that the assumptions always hold, otherwise
- undefined behavior may occur.
+ This macro is known to produce worse code than when no assumption was
+ inserted in the code, with some compiler versions. The arguments passed to
+ it are always evaluated, even in release mode, with some compilers and not
+ others, so application code needs to be aware of those possible differences
+ in behavior.
- If \a expr is a constantly \c false condition, Q_ASSUME will tell the compiler
- that the current code execution cannot be reached. That is, Q_ASSUME(false)
- is equivalent to Q_UNREACHABLE().
+ Do not use it in new code. It is retained as-is for compatibility with old
+ code and will likely be removed in the next major version Qt.
- In debug builds the condition is enforced by an assert to facilitate debugging.
+ \sa Q_ASSERT(), Q_UNREACHABLE(), Q_LIKELY()
+*/
- \note Q_LIKELY() tells the compiler that the expression is likely, but not
- the only possibility. Q_ASSUME tells the compiler that it is the only
- possibility.
+/*!
+ \macro QT_TERMINATE_ON_EXCEPTION(expr)
+ \relates <QtGlobal>
+ \internal
- \sa Q_ASSERT(), Q_UNREACHABLE(), Q_LIKELY()
+ In general, use of the Q_DECL_NOEXCEPT macro is preferred over
+ Q_DECL_NOTHROW, because it exhibits well-defined behavior and
+ supports the more powerful Q_DECL_NOEXCEPT_EXPR variant. However,
+ use of Q_DECL_NOTHROW has the advantage that Windows builds
+ benefit on a wide range or compiler versions that do not yet
+ support the C++11 noexcept feature.
+
+ It may therefore be beneficial to use Q_DECL_NOTHROW and emulate
+ the C++11 behavior manually with an embedded try/catch.
+
+ Qt provides the QT_TERMINATE_ON_EXCEPTION(expr) macro for this
+ purpose. It either expands to \c expr (if Qt is compiled without
+ exception support or the compiler supports C++11 noexcept
+ semantics) or to
+ \snippet code/src_corelib_global_qglobal.cpp qterminate
+ otherwise.
+
+ Since this macro expands to just \c expr if the compiler supports
+ C++11 noexcept, expecting the compiler to take over responsibility
+ of calling std::terminate() in that case, it should not be used
+ outside Q_DECL_NOTHROW functions.
+
+ \sa Q_DECL_NOEXCEPT, Q_DECL_NOTHROW, qTerminate()
*/
/*!
@@ -199,7 +257,7 @@ void qBadAlloc()
compilers that need them, without causing warnings for compilers that
complain about its presence.
- \sa Q_ASSERT(), Q_ASSUME(), qFatal(), Q_UNREACHABLE_RETURN()
+ \sa Q_ASSERT(), qFatal(), Q_UNREACHABLE_RETURN()
*/
/*!
diff --git a/src/corelib/global/qassert.h b/src/corelib/global/qassert.h
index a3cd60b06a..388932a8f7 100644
--- a/src/corelib/global/qassert.h
+++ b/src/corelib/global/qassert.h
@@ -18,7 +18,7 @@ QT_BEGIN_NAMESPACE
#if defined(__cplusplus)
-#ifndef Q_CC_MSVC
+#if !defined(Q_CC_MSVC_ONLY)
Q_NORETURN
#endif
Q_DECL_COLD_FUNCTION
@@ -32,7 +32,7 @@ Q_CORE_EXPORT void qt_assert(const char *assertion, const char *file, int line)
# endif
#endif
-#ifndef Q_CC_MSVC
+#if !defined(Q_CC_MSVC_ONLY)
Q_NORETURN
#endif
Q_DECL_COLD_FUNCTION
@@ -79,11 +79,14 @@ inline T *q_check_ptr(T *p) { Q_CHECK_PTR(p); return p; }
# endif
#endif
+Q_DECL_DEPRECATED_X("Q_ASSUME() is deprecated because it can produce worse code than when it's absent; "
+ "use C++23 [[assume]] instead")
+inline bool qt_assume_is_deprecated(bool cond) noexcept { return cond; }
#define Q_ASSUME(Expr) \
[] (bool valueOfExpression) {\
Q_ASSERT_X(valueOfExpression, "Q_ASSUME()", "Assumption in Q_ASSUME(\"" #Expr "\") was not correct");\
Q_ASSUME_IMPL(valueOfExpression);\
- }(Expr)
+ }(qt_assume_is_deprecated(Expr))
// Don't use these in C++ mode, use static_assert directly.
// These are here only to keep old code compiling.
diff --git a/src/corelib/global/qcompare.cpp b/src/corelib/global/qcompare.cpp
new file mode 100644
index 0000000000..ac220b8434
--- /dev/null
+++ b/src/corelib/global/qcompare.cpp
@@ -0,0 +1,1357 @@
+// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qcompare.h"
+
+#ifdef __cpp_lib_bit_cast
+#include <bit>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifdef __cpp_lib_three_way_comparison
+#ifdef __cpp_lib_bit_cast
+#define CHECK(type, flag) \
+ static_assert(std::bit_cast<Qt:: type ## _ordering>(std:: type ## _ordering:: flag) \
+ == Qt:: type ## _ordering :: flag); \
+ static_assert(std::bit_cast<std:: type ## _ordering>(Qt:: type ## _ordering:: flag) \
+ == std:: type ## _ordering :: flag) \
+ /* end */
+CHECK(partial, unordered);
+CHECK(partial, less);
+CHECK(partial, greater);
+CHECK(partial, equivalent);
+CHECK(weak, less);
+CHECK(weak, greater);
+CHECK(weak, equivalent);
+CHECK(strong, less);
+CHECK(strong, greater);
+CHECK(strong, equal);
+CHECK(strong, equivalent);
+#undef CHECK
+#endif // __cpp_lib_bit_cast
+#endif //__cpp_lib_three_way_comparison
+
+
+/*!
+ \page comparison-types.html overview
+ \title Comparison types overview
+ \keyword three-way comparison
+ \inmodule QtCore
+ \sa Qt::strong_ordering, Qt::weak_ordering, Qt::partial_ordering
+
+ \note Qt's comparison types provide functionality equivalent to their C++20
+ standard counterparts. The only reason why they exist is to make the
+ functionality available in C++17 builds, too. In a C++20 build, they
+ implicitly convert to and from the \c std types, making them fully
+ interchangeable. We therefore recommended that you prefer to use the C++
+ standard types in your code, if you can use C++20 in your projects already.
+ The Qt comparison types will be removed in Qt 7.
+
+ Qt provides several comparison types for a \l
+ {https://en.cppreference.com/w/cpp/language/operator_comparison#Three-way_comparison}
+ {three-way comparison}, which are comparable against a \e {zero literal}.
+ To use these comparison types, you need to include the \c <QtCompare>
+ header. These comparison types are categorized based on their \e order,
+ which is a mathematical concept used to describe the arrangement or ranking
+ of elements. The following categories are provided:
+
+ \table 100 %
+ \header
+ \li C++ type
+ \li Qt type
+ \li strict
+ \li total
+ \li Example
+ \row
+ \li \l {https://en.cppreference.com/w/cpp/utility/compare/strong_ordering}
+ {std::strong_ordering}
+ \li Qt::strong_ordering
+ \li yes
+ \li yes
+ \li integral types, case-sensitive strings, QDate, QTime
+ \row
+ \li \l {https://en.cppreference.com/w/cpp/utility/compare/weak_ordering}
+ {std::weak_ordering}
+ \li Qt::weak_ordering
+ \li no
+ \li yes
+ \li case-insensitive strings, unordered associative containers, QDateTime
+ \row
+ \li \l {https://en.cppreference.com/w/cpp/utility/compare/partial_ordering}
+ {std::partial_ordering}
+ \li Qt::partial_ordering
+ \li no
+ \li no
+ \li floating-point types, QOperatingSystemVersion, QVariant
+ \endtable
+
+ The strongest comparison type, Qt::strong_ordering, represents a strict total
+ order. It requires that any two elements be comparable in a way where
+ equality implies substitutability. In other words, equivalent values
+ cannot be distinguished from each other. A practical example would be the
+ case-sensitive comparison of two strings. For instance, when comparing the
+ values \c "Qt" and \c "Qt" the result would be \l Qt::strong_ordering::equal.
+ Both values are indistinguishable and all deterministic operations performed
+ on these values would yield identical results.
+
+ Qt::weak_ordering represents a total order. While any two values still need to
+ be comparable, equivalent values may be distinguishable. The canonical
+ example here would be the case-insensitive comparison of two strings. For
+ instance, when comparing the values \c "Qt" and \c "qt" both hold the same
+ letters but with different representations. This comparison would
+ result in \l Qt::weak_ordering::equivalent, but not actually \c Equal.
+ Another example would be QDateTime, which can represent a given instant in
+ time in terms of local time or any other time-zone, including UTC. The
+ different representations are equivalent, even though their \c time() and
+ sometimes \c date() may differ.
+
+ Qt::partial_ordering represents, as the name implies, a partial ordering. It
+ allows for the possibility that two values may not be comparable, resulting
+ in an \l {Qt::partial_ordering::}{unordered} state. Additionally, equivalent
+ values may still be distinguishable. A practical example would be the
+ comparison of two floating-point values, comparing with NaN (Not-a-Number)
+ would yield an unordered result. Another example is the comparison of two
+ QOperatingSystemVersion objects. Comparing versions of two different
+ operating systems, such as Android and Windows, would produce an unordered
+ result.
+
+ Utilizing these comparison types enhances the expressiveness of defining
+ relations. Furthermore, they serve as a fundamental component for
+ implementing three-way comparison with C++17.
+*/
+
+/*!
+ \headerfile <QtCompare>
+ \inmodule QtCore
+ \title Classes and helpers for defining comparison operators
+ \keyword qtcompare
+
+ \brief The <QtCompare> header file defines \c {Qt::*_ordering} types and helper
+ macros for defining comparison operators.
+
+ This header introduces the \l Qt::partial_ordering, \l Qt::weak_ordering, and
+ \l Qt::strong_ordering types, which are Qt's C++17 backports of
+ \c {std::*_ordering} types.
+
+ This header also contains functions for implementing three-way comparison
+ in C++17.
+
+ The \c {Qt::compareThreeWay()} function overloads provide three-way
+ comparison for built-in C++ types.
+
+ The \l qCompareThreeWay() template serves as a generic three-way comparison
+ implementation. It relies on \c {Qt::compareThreeWay()} and free
+ \c {compareThreeWay()} functions in its implementation.
+*/
+
+/*!
+ \class Qt::strong_ordering
+ \inmodule QtCore
+ \brief Qt::strong_ordering represents a comparison where equivalent values are
+ indistinguishable.
+ \sa Qt::weak_ordering, Qt::partial_ordering, {Comparison types overview}
+ \since 6.7
+
+ A value of type Qt::strong_ordering is typically returned from a three-way
+ comparison function. Such a function compares two objects and establishes
+ how they are ordered. It uses this return type to indicate that the ordering
+ is strict; that is, the function establishes a well-defined total order.
+
+ Qt::strong_ordering has four values, represented by the following symbolic
+ constants:
+
+ \list
+ \li \l less represents that the left operand is less than the right;
+ \li \l equal represents that the left operand is equivalent to the right;
+ \li \l equivalent is an alias for \c equal;
+ \li \l greater represents that the left operand is greater than the right.
+ \endlist
+
+ Qt::strong_ordering is idiomatically used by comparing an instance against a
+ literal zero, for instance like this:
+
+ \code
+
+ // given a, b, c, d as objects of some type that allows for a 3-way compare,
+ // and a compare function declared as follows:
+
+ Qt::strong_ordering compare(T lhs, T rhs); // defined out-of-line
+ ~~~
+
+ Qt::strong_ordering result = compare(a, b);
+ if (result < 0) {
+ // a is less than b
+ }
+
+ if (compare(c, d) >= 0) {
+ // c is greater than or equal to d
+ }
+
+ \endcode
+*/
+
+/*!
+ \fn Qt::strong_ordering::operator Qt::partial_ordering() const
+
+ Converts this Qt::strong_ordering value to a Qt::partial_ordering object using the
+ following rules:
+
+ \list
+ \li \l less converts to \l {Qt::partial_ordering::less}.
+ \li \l equivalent converts to \l {Qt::partial_ordering::equivalent}.
+ \li \l equal converts to \l {Qt::partial_ordering::equivalent}.
+ \li \l greater converts to \l {Qt::partial_ordering::greater}.
+ \endlist
+*/
+
+/*!
+ \fn Qt::strong_ordering::operator Qt::weak_ordering() const
+
+ Converts this Qt::strong_ordering value to a Qt::weak_ordering object using the
+ following rules:
+
+ \list
+ \li \l less converts to \l {Qt::weak_ordering::less}.
+ \li \l equivalent converts to \l {Qt::weak_ordering::equivalent}.
+ \li \l equal converts to \l {Qt::weak_ordering::equivalent}.
+ \li \l greater converts to \l {Qt::weak_ordering::greater}.
+ \endlist
+*/
+
+/*!
+ \fn Qt::strong_ordering::strong_ordering(std::strong_ordering stdorder)
+
+ Constructs a Qt::strong_ordering object from \a stdorder using the following rules:
+
+ \list
+ \li std::strong_ordering::less converts to \l less.
+ \li std::strong_ordering::equivalent converts to \l equivalent.
+ \li std::strong_ordering::equal converts to \l equal.
+ \li std::strong_ordering::greater converts to \l greater.
+ \endlist
+*/
+
+/*!
+ \fn Qt::strong_ordering::operator std::strong_ordering() const
+
+ Converts this Qt::strong_ordering value to a std::strong_ordering object using
+ the following rules:
+
+ \list
+ \li \l less converts to std::strong_ordering::less.
+ \li \l equivalent converts to std::strong_ordering::equivalent.
+ \li \l equal converts to std::strong_ordering::equal.
+ \li \l greater converts to std::strong_ordering::greater.
+ \endlist
+*/
+
+/*!
+ \fn bool Qt::strong_ordering::operator==(Qt::strong_ordering lhs, Qt::strong_ordering rhs)
+
+ Returns true if \a lhs and \a rhs represent the same result;
+ otherwise, returns false.
+*/
+
+/*!
+ \fn bool Qt::strong_ordering::operator!=(Qt::strong_ordering lhs, Qt::strong_ordering rhs)
+
+ Returns true if \a lhs and \a rhs represent different results;
+ otherwise, returns true.
+*/
+
+/*!
+ \internal
+ \relates Qt::strong_ordering
+ \fn bool operator==(Qt::strong_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator!=(Qt::strong_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator< (Qt::strong_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator<=(Qt::strong_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator> (Qt::strong_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator>=(Qt::strong_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+
+ \fn bool operator==(QtPrivate::CompareAgainstLiteralZero, Qt::strong_ordering rhs)
+ \fn bool operator!=(QtPrivate::CompareAgainstLiteralZero, Qt::strong_ordering rhs)
+ \fn bool operator< (QtPrivate::CompareAgainstLiteralZero, Qt::strong_ordering rhs)
+ \fn bool operator<=(QtPrivate::CompareAgainstLiteralZero, Qt::strong_ordering rhs)
+ \fn bool operator> (QtPrivate::CompareAgainstLiteralZero, Qt::strong_ordering rhs)
+ \fn bool operator>=(QtPrivate::CompareAgainstLiteralZero, Qt::strong_ordering rhs)
+*/
+
+/*!
+ \fn Qt::strong_ordering::is_eq (Qt::strong_ordering o)
+ \fn Qt::strong_ordering::is_neq (Qt::strong_ordering o)
+ \fn Qt::strong_ordering::is_lt (Qt::strong_ordering o)
+ \fn Qt::strong_ordering::is_lteq(Qt::strong_ordering o)
+ \fn Qt::strong_ordering::is_gt (Qt::strong_ordering o)
+ \fn Qt::strong_ordering::is_gteq(Qt::strong_ordering o)
+
+//! [is_eq_table]
+ Converts \a o into the result of one of the six relational operators:
+ \table
+ \header \li Function \li Operation
+ \row \li \c{is_eq} \li \a o \c{== 0}
+ \row \li \c{is_neq} \li \a o \c{!= 0}
+ \row \li \c{is_lt} \li \a o \c{< 0}
+ \row \li \c{is_lteq} \li \a o \c{<= 0}
+ \row \li \c{is_gt} \li \a o \c{> 0}
+ \row \li \c{is_gteq} \li \a o \c{>= 0}
+ \endtable
+//! [is_eq_table]
+
+ These functions are provided for compatibility with \c{std::strong_ordering}.
+*/
+
+/*!
+ \variable Qt::strong_ordering::less
+
+ Represents the result of a comparison where the left operand is less
+ than the right operand.
+*/
+
+/*!
+ \variable Qt::strong_ordering::equivalent
+
+ Represents the result of a comparison where the left operand is equal
+ to the right operand. Same as \l {Qt::strong_ordering::equal}.
+*/
+
+/*!
+ \variable Qt::strong_ordering::equal
+
+ Represents the result of a comparison where the left operand is equal
+ to the right operand. Same as \l {Qt::strong_ordering::equivalent}.
+*/
+
+/*!
+ \variable Qt::strong_ordering::greater
+
+ Represents the result of a comparison where the left operand is greater
+ than the right operand.
+*/
+
+/*!
+ \class Qt::weak_ordering
+ \inmodule QtCore
+ \brief Qt::weak_ordering represents a comparison where equivalent values are
+ still distinguishable.
+ \sa Qt::strong_ordering, Qt::partial_ordering, {Comparison types overview}
+ \since 6.7
+
+ A value of type Qt::weak_ordering is typically returned from a three-way
+ comparison function. Such a function compares two objects and establishes
+ how they are ordered. It uses this return type to indicate that the ordering
+ is weak; that is, equivalent values may be distinguishable.
+
+ Qt::weak_ordering has three values, represented by the following symbolic
+ constants:
+
+ \list
+ \li \l less represents that the left operand is less than the right;
+ \li \l equivalent represents that the left operand is equivalent to the
+ right;
+ \li \l greater represents that the left operand is greater than the right,
+ \endlist
+
+ Qt::weak_ordering is idiomatically used by comparing an instance against a
+ literal zero, for instance like this:
+
+ \code
+
+ // given a, b, c, d as objects of some type that allows for a 3-way compare,
+ // and a compare function declared as follows:
+
+ Qt::weak_ordering compare(T lhs, T rhs); // defined out-of-line
+ ~~~
+
+ Qt::weak_ordering result = compare(a, b);
+ if (result < 0) {
+ // a is less than b
+ }
+
+ if (compare(c, d) >= 0) {
+ // c is greater than or equivalent to d
+ }
+
+ \endcode
+*/
+
+/*!
+ \fn Qt::weak_ordering::operator Qt::partial_ordering() const
+
+ Converts this Qt::weak_ordering value to a Qt::partial_ordering object using the
+ following rules:
+
+ \list
+ \li \l less converts to \l {Qt::partial_ordering::less}.
+ \li \l equivalent converts to \l {Qt::partial_ordering::equivalent}.
+ \li \l greater converts to \l {Qt::partial_ordering::greater}.
+ \endlist
+*/
+
+/*!
+ \fn Qt::weak_ordering::weak_ordering(std::weak_ordering stdorder)
+
+ Constructs a Qt::weak_ordering object from \a stdorder using the following rules:
+
+ \list
+ \li std::weak_ordering::less converts to \l less.
+ \li std::weak_ordering::equivalent converts to \l equivalent.
+ \li std::weak_ordering::greater converts to \l greater.
+ \endlist
+*/
+
+/*!
+ \fn Qt::weak_ordering::operator std::weak_ordering() const
+
+ Converts this Qt::weak_ordering value to a std::weak_ordering object using
+ the following rules:
+
+ \list
+ \li \l less converts to std::weak_ordering::less.
+ \li \l equivalent converts to std::weak_ordering::equivalent.
+ \li \l greater converts to std::weak_ordering::greater.
+ \endlist
+*/
+
+/*!
+ \fn bool Qt::weak_ordering::operator==(Qt::weak_ordering lhs, Qt::weak_ordering rhs)
+
+ Return true if \a lhs and \a rhs represent the same result;
+ otherwise, returns false.
+*/
+
+/*!
+ \fn bool Qt::weak_ordering::operator!=(Qt::weak_ordering lhs, Qt::weak_ordering rhs)
+
+ Return true if \a lhs and \a rhs represent different results;
+ otherwise, returns true.
+*/
+
+/*!
+ \internal
+ \relates Qt::weak_ordering
+ \fn bool operator==(Qt::weak_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator!=(Qt::weak_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator< (Qt::weak_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator<=(Qt::weak_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator> (Qt::weak_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator>=(Qt::weak_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+
+ \fn bool operator==(QtPrivate::CompareAgainstLiteralZero, Qt::weak_ordering rhs)
+ \fn bool operator!=(QtPrivate::CompareAgainstLiteralZero, Qt::weak_ordering rhs)
+ \fn bool operator< (QtPrivate::CompareAgainstLiteralZero, Qt::weak_ordering rhs)
+ \fn bool operator<=(QtPrivate::CompareAgainstLiteralZero, Qt::weak_ordering rhs)
+ \fn bool operator> (QtPrivate::CompareAgainstLiteralZero, Qt::weak_ordering rhs)
+ \fn bool operator>=(QtPrivate::CompareAgainstLiteralZero, Qt::weak_ordering rhs)
+*/
+
+/*!
+ \fn Qt::weak_ordering::is_eq (Qt::weak_ordering o)
+ \fn Qt::weak_ordering::is_neq (Qt::weak_ordering o)
+ \fn Qt::weak_ordering::is_lt (Qt::weak_ordering o)
+ \fn Qt::weak_ordering::is_lteq(Qt::weak_ordering o)
+ \fn Qt::weak_ordering::is_gt (Qt::weak_ordering o)
+ \fn Qt::weak_ordering::is_gteq(Qt::weak_ordering o)
+
+ \include qcompare.cpp is_eq_table
+
+ These functions are provided for compatibility with \c{std::weak_ordering}.
+*/
+
+/*!
+ \variable Qt::weak_ordering::less
+
+ Represents the result of a comparison where the left operand is less than
+ the right operand.
+*/
+
+/*!
+ \variable Qt::weak_ordering::equivalent
+
+ Represents the result of a comparison where the left operand is equivalent
+ to the right operand.
+*/
+
+/*!
+ \variable Qt::weak_ordering::greater
+
+ Represents the result of a comparison where the left operand is greater
+ than the right operand.
+*/
+
+/*!
+ \class Qt::partial_ordering
+ \inmodule QtCore
+ \brief Qt::partial_ordering represents the result of a comparison that allows
+ for unordered results.
+ \sa Qt::strong_ordering, Qt::weak_ordering, {Comparison types overview}
+ \since 6.7
+
+ A value of type Qt::partial_ordering is typically returned from a
+ three-way comparison function. Such a function compares two objects,
+ establishing whether they are ordered and, if so, their ordering. It uses
+ this return type to indicate that the ordering is partial; that is, not all
+ pairs of values are ordered.
+
+ Qt::partial_ordering has four values, represented by the following symbolic
+ constants:
+
+ \list
+ \li \l less represents that the left operand is less than the right;
+ \li \l equivalent represents that the two operands are equivalent;
+ \li \l greater represents that the left operand is greater than the right;
+ \li \l unordered represents that the two operands are \e {not ordered}.
+ \endlist
+
+ Qt::partial_ordering is idiomatically used by comparing an instance
+ against a literal zero, for instance like this:
+
+ \code
+
+ // given a, b, c, d as objects of some type that allows for a 3-way compare,
+ // and a compare function declared as follows:
+
+ Qt::partial_ordering compare(T lhs, T rhs); // defined out-of-line
+ ~~~
+
+ Qt::partial_ordering result = compare(a, b);
+ if (result < 0) {
+ // a is less than b
+ }
+
+ if (compare(c, d) >= 0) {
+ // c is greater than or equal to d
+ }
+
+ \endcode
+
+ Comparing Qt::partial_ordering::unordered against literal 0 always returns
+ a \c false result.
+*/
+
+/*!
+ \fn Qt::partial_ordering::partial_ordering(std::partial_ordering stdorder)
+
+ Constructs a Qt::partial_ordering object from \a stdorder using the following
+ rules:
+
+ \list
+ \li std::partial_ordering::less converts to \l less.
+ \li std::partial_ordering::equivalent converts to \l equivalent.
+ \li std::partial_ordering::greater converts to \l greater.
+ \li std::partial_ordering::unordered converts to \l unordered
+ \endlist
+*/
+
+/*!
+ \fn Qt::partial_ordering::operator std::partial_ordering() const
+
+ Converts this Qt::partial_ordering value to a std::partial_ordering object using
+ the following rules:
+
+ \list
+ \li \l less converts to std::partial_ordering::less.
+ \li \l equivalent converts to std::partial_ordering::equivalent.
+ \li \l greater converts to std::partial_ordering::greater.
+ \li \l unordered converts to std::partial_ordering::unordered.
+ \endlist
+*/
+
+/*!
+ \fn bool Qt::partial_ordering::operator==(Qt::partial_ordering lhs, Qt::partial_ordering rhs)
+
+ Return true if \a lhs and \a rhs represent the same result;
+ otherwise, returns false.
+*/
+
+/*!
+ \fn bool Qt::partial_ordering::operator!=(Qt::partial_ordering lhs, Qt::partial_ordering rhs)
+
+ Return true if \a lhs and \a rhs represent different results;
+ otherwise, returns true.
+*/
+
+/*!
+ \internal
+ \relates Qt::partial_ordering
+ \fn bool operator==(Qt::partial_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator!=(Qt::partial_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator< (Qt::partial_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator<=(Qt::partial_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator> (Qt::partial_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator>=(Qt::partial_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+
+ \fn bool operator==(QtPrivate::CompareAgainstLiteralZero, Qt::partial_ordering rhs)
+ \fn bool operator!=(QtPrivate::CompareAgainstLiteralZero, Qt::partial_ordering rhs)
+ \fn bool operator< (QtPrivate::CompareAgainstLiteralZero, Qt::partial_ordering rhs)
+ \fn bool operator<=(QtPrivate::CompareAgainstLiteralZero, Qt::partial_ordering rhs)
+ \fn bool operator> (QtPrivate::CompareAgainstLiteralZero, Qt::partial_ordering rhs)
+ \fn bool operator>=(QtPrivate::CompareAgainstLiteralZero, Qt::partial_ordering rhs)
+*/
+
+/*!
+ \fn Qt::partial_ordering::is_eq (Qt::partial_ordering o)
+ \fn Qt::partial_ordering::is_neq (Qt::partial_ordering o)
+ \fn Qt::partial_ordering::is_lt (Qt::partial_ordering o)
+ \fn Qt::partial_ordering::is_lteq(Qt::partial_ordering o)
+ \fn Qt::partial_ordering::is_gt (Qt::partial_ordering o)
+ \fn Qt::partial_ordering::is_gteq(Qt::partial_ordering o)
+
+ \include qcompare.cpp is_eq_table
+
+ These functions are provided for compatibility with \c{std::partial_ordering}.
+*/
+
+/*!
+ \variable Qt::partial_ordering::less
+
+ Represents the result of a comparison where the left operand is less than
+ the right operand.
+*/
+
+/*!
+ \variable Qt::partial_ordering::equivalent
+
+ Represents the result of a comparison where the two operands are equivalent.
+*/
+
+/*!
+ \variable Qt::partial_ordering::greater
+
+ Represents the result of a comparison where the left operand is greater
+ than the right operand.
+*/
+
+/*!
+ \variable Qt::partial_ordering::unordered
+
+ Represents the result of a comparison where there is no ordering
+ relationship between the two operands.
+*/
+
+/*!
+ \class QPartialOrdering
+ \inmodule QtCore
+ \brief QPartialOrdering represents the result of a comparison that allows
+ for unordered results.
+ \sa Qt::strong_ordering, Qt::weak_ordering, {Comparison types overview}
+ \since 6.0
+
+ A value of type QPartialOrdering is typically returned from a
+ three-way comparison function. Such a function compares two objects,
+ establishing whether they are ordered and, if so, their ordering. It uses
+ this return type to indicate that the ordering is partial; that is, not all
+ pairs of values are ordered.
+
+ QPartialOrdering has four values, represented by the following symbolic
+ constants:
+
+ \list
+ \li \l less represents that the left operand is less than the right;
+ \li \l equivalent represents that the two operands are equivalent;
+ \li \l greater represents that the left operand is greater than the right;
+ \li \l unordered represents that the two operands are \e {not ordered}.
+ \endlist
+
+ QPartialOrdering is idiomatically used by comparing an instance
+ against a literal zero, for instance like this:
+
+ \code
+
+ // given a, b, c, d as objects of some type that allows for a 3-way compare,
+ // and a compare function declared as follows:
+
+ QPartialOrdering compare(T lhs, T rhs); // defined out-of-line
+ ~~~
+
+ QPartialOrdering result = compare(a, b);
+ if (result < 0) {
+ // a is less than b
+ }
+
+ if (compare(c, d) >= 0) {
+ // c is greater than or equal to d
+ }
+
+ \endcode
+
+ Comparing QPartialOrdering::unordered against literal 0 always returns
+ a \c false result.
+*/
+
+/*!
+ \fn QPartialOrdering::QPartialOrdering(std::partial_ordering stdorder)
+
+ Constructs a QPartialOrdering object from \a stdorder using the following
+ rules:
+
+ \list
+ \li std::partial_ordering::less converts to \l less.
+ \li std::partial_ordering::equivalent converts to \l equivalent.
+ \li std::partial_ordering::greater converts to \l greater.
+ \li std::partial_ordering::unordered converts to \l unordered
+ \endlist
+*/
+
+/*!
+ \fn QPartialOrdering::operator std::partial_ordering() const
+
+ Converts this QPartialOrdering value to a std::partial_ordering object using
+ the following rules:
+
+ \list
+ \li \l less converts to std::partial_ordering::less.
+ \li \l equivalent converts to std::partial_ordering::equivalent.
+ \li \l greater converts to std::partial_ordering::greater.
+ \li \l unordered converts to std::partial_ordering::unordered.
+ \endlist
+*/
+
+/*!
+ \fn bool QPartialOrdering::operator==(QPartialOrdering lhs, QPartialOrdering rhs)
+
+ Return true if \a lhs and \a rhs represent the same result;
+ otherwise, returns false.
+*/
+
+/*!
+ \fn bool QPartialOrdering::operator!=(QPartialOrdering lhs, QPartialOrdering rhs)
+
+ Return true if \a lhs and \a rhs represent different results;
+ otherwise, returns true.
+*/
+
+/*!
+ \internal
+ \relates QPartialOrdering
+ \fn bool operator==(QPartialOrdering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator!=(QPartialOrdering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator< (QPartialOrdering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator<=(QPartialOrdering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator> (QPartialOrdering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator>=(QPartialOrdering lhs, QtPrivate::CompareAgainstLiteralZero)
+
+ \fn bool operator==(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering rhs)
+ \fn bool operator!=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering rhs)
+ \fn bool operator< (QtPrivate::CompareAgainstLiteralZero, QPartialOrdering rhs)
+ \fn bool operator<=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering rhs)
+ \fn bool operator> (QtPrivate::CompareAgainstLiteralZero, QPartialOrdering rhs)
+ \fn bool operator>=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering rhs)
+*/
+
+/*!
+ \fn QPartialOrdering::is_eq (QPartialOrdering o)
+ \fn QPartialOrdering::is_neq (QPartialOrdering o)
+ \fn QPartialOrdering::is_lt (QPartialOrdering o)
+ \fn QPartialOrdering::is_lteq(QPartialOrdering o)
+ \fn QPartialOrdering::is_gt (QPartialOrdering o)
+ \fn QPartialOrdering::is_gteq(QPartialOrdering o)
+
+ \since 6.7
+ \include qcompare.cpp is_eq_table
+
+ These functions are provided for compatibility with \c{std::partial_ordering}.
+*/
+
+/*!
+ \variable QPartialOrdering::less
+
+ Represents the result of a comparison where the left operand is less than
+ the right operand.
+*/
+
+/*!
+ \variable QPartialOrdering::equivalent
+
+ Represents the result of a comparison where the two operands are equivalent.
+*/
+
+/*!
+ \variable QPartialOrdering::greater
+
+ Represents the result of a comparison where the left operand is greater
+ than the right operand.
+*/
+
+/*!
+ \variable QPartialOrdering::unordered
+
+ Represents the result of a comparison where there is no ordering
+ relationship between the two operands.
+*/
+
+/*!
+ \variable QPartialOrdering::Less
+
+ Represents the result of a comparison where the left operand is less than
+ the right operand.
+*/
+
+/*!
+ \variable QPartialOrdering::Equivalent
+
+ Represents the result of a comparison where the two operands are equivalent.
+*/
+
+/*!
+ \variable QPartialOrdering::Greater
+
+ Represents the result of a comparison where the left operand is greater
+ than the right operand.
+*/
+
+/*!
+ \variable QPartialOrdering::Unordered
+
+ Represents the result of a comparison where there is no ordering
+ relationship between the two operands.
+*/
+
+/*!
+ \internal
+ \macro Q_DECLARE_EQUALITY_COMPARABLE(Type)
+ \macro Q_DECLARE_EQUALITY_COMPARABLE(LeftType, RightType)
+ \macro Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(Type)
+ \macro Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(LeftType, RightType)
+ \since 6.7
+ \relates <QtCompare>
+
+ These macros are used to generate \c {operator==()} and \c {operator!=()}.
+
+ In C++17 mode, the mixed-type overloads also generate the reversed
+ operators.
+
+ In C++20 mode, only \c {operator==()} is defined. \c {operator!=()},
+ as well as the reversed operators for mixed-type comparison, are synthesized
+ by the compiler.
+
+ The operators are implemented in terms of a helper function
+ \c {comparesEqual()}.
+ It's the user's responsibility to declare and define this function.
+
+ Consider the following example of a comparison operators declaration:
+
+ \code
+ class MyClass {
+ ...
+ private:
+ friend bool comparesEqual(const MyClass &, const MyClass &) noexcept;
+ Q_DECLARE_EQUALITY_COMPARABLE(MyClass)
+ };
+ \endcode
+
+ When compiled with C++17, the macro will expand into the following code:
+
+ \code
+ friend bool operator==(const MyClass &lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses comparesEqual()
+ }
+ friend bool operator!=(const MyClass &lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses comparesEqual()
+ }
+ \endcode
+
+ When compiled with C++20, the macro will expand only into \c {operator==()}:
+
+ \code
+ friend bool operator==(const MyClass &lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses comparesEqual()
+ }
+ \endcode
+
+ The \c {*_LITERAL_TYPE} versions of the macros are used to generate
+ \c constexpr operators. This means that the helper \c {comparesEqual()}
+ function must also be \c constexpr.
+
+ Consider the following example of a mixed-type \c constexpr comparison
+ operators declaration:
+
+ \code
+ class MyClass {
+ ...
+ private:
+ friend constexpr bool comparesEqual(const MyClass &, int) noexcept;
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(MyClass, int)
+ };
+ \endcode
+
+ When compiled with C++17, the macro will expand into the following code:
+
+ \code
+ friend constexpr bool operator==(const MyClass &lhs, int rhs) noexcept
+ {
+ // inline implementation which uses comparesEqual()
+ }
+ friend constexpr bool operator!=(const MyClass &lhs, int rhs) noexcept
+ {
+ // inline implementation which uses comparesEqual()
+ }
+ friend constexpr bool operator==(int lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses comparesEqual()
+ }
+ friend constexpr bool operator!=(int lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses comparesEqual()
+ }
+ \endcode
+
+ When compiled with C++20, the macro expands only into \c {operator==()}:
+
+ \code
+ friend constexpr bool operator==(const MyClass &lhs, int rhs) noexcept
+ {
+ // inline implementation which uses comparesEqual()
+ }
+ \endcode
+*/
+
+/*!
+ \internal
+ \macro Q_DECLARE_PARTIALLY_ORDERED(Type)
+ \macro Q_DECLARE_PARTIALLY_ORDERED(LeftType, RightType)
+ \macro Q_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE(Type)
+ \macro Q_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE(LeftType, RightType)
+ \since 6.7
+ \relates <QtCompare>
+
+ These macros are used to generate all six relational operators.
+ The operators represent
+ \l {https://en.cppreference.com/w/cpp/utility/compare/partial_ordering}
+ {partial ordering}.
+
+ These macros use respective overloads of the
+ \l {Q_DECLARE_EQUALITY_COMPARABLE} macro to generate \c {operator==()} and
+ \c {operator!=()}, and also generate the four relational operators:
+ \c {operator<()}, \c {operator>()}, \c {operator<=()}, and \c {operator>()}.
+
+ In C++17 mode, the mixed-type overloads also generate the reversed
+ operators.
+
+ In C++20 mode, only \c {operator==()} and \c {operator<=>()} are defined.
+ Other operators, as well as the reversed operators for mixed-type
+ comparison, are synthesized by the compiler.
+
+ The (in)equality operators are implemented in terms of a helper function
+ \c {comparesEqual()}. The other relational operators are implemented in
+ terms of a helper function \c {compareThreeWay()}.
+ The \c {compareThreeWay()} function \e must return an object of type
+ \l Qt::partial_ordering. It's the user's responsibility to declare and define
+ both helper functions.
+
+ Consider the following example of a comparison operators declaration:
+
+ \code
+ class MyClass {
+ ...
+ private:
+ friend bool comparesEqual(const MyClass &, const MyClass &) noexcept;
+ friend Qt::partial_ordering compareThreeWay(const MyClass &, const MyClass &) noexcept;
+ Q_DECLARE_PARTIALLY_ORDERED(MyClass)
+ };
+ \endcode
+
+ When compiled with C++17, the macro will expand into the following code:
+
+ \code
+ // operator==() and operator!=() are generated from
+ // Q_DECLARE_EQUALITY_COMPARABLE
+ friend bool operator<(const MyClass &lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ friend bool operator>(const MyClass &lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ friend bool operator<=(const MyClass &lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ friend bool operator>=(const MyClass &lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ \endcode
+
+ When compiled with C++20, the macro will expand into \c {operator==()} and
+ \c {operator<=>()}:
+
+ \code
+ friend bool operator==(const MyClass &lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses comparesEqual()
+ }
+ friend std::partial_ordering
+ operator<=>(const MyClass &lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ \endcode
+
+ The \c {*_LITERAL_TYPE} versions of the macros are used to generate
+ \c constexpr operators. This means that the helper \c {comparesEqual()} and
+ \c {compareThreeWay()} functions must also be \c constexpr.
+
+ Consider the following example of a mixed-type \c constexpr comparison
+ operators declaration:
+
+ \code
+ class MyClass {
+ ...
+ private:
+ friend constexpr bool comparesEqual(const MyClass &, int) noexcept;
+ friend constexpr Qt::partial_ordering compareThreeWay(const MyClass &, int) noexcept;
+ Q_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE(MyClass, int)
+ };
+ \endcode
+
+ When compiled with C++17, the macro will expand into the following code:
+
+ \code
+ // operator==(), operator!=(), and their reversed versions are generated
+ // from Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE
+ friend constexpr bool operator<(const MyClass &lhs, int rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ friend constexpr bool operator>(const MyClass &lhs, int rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ friend constexpr bool operator<=(const MyClass &lhs, int rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ friend constexpr bool operator>=(const MyClass &lhs, int rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ friend constexpr bool operator<(int lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ friend constexpr bool operator>(int lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ friend constexpr bool operator<=(int lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ friend constexpr bool operator>=(int lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ \endcode
+
+ When compiled with C++20, the macro will expand into \c {operator==()} and
+ \c {operator<=>()}:
+
+ \code
+ friend constexpr bool operator==(const MyClass &lhs, int rhs) noexcept
+ {
+ // inline implementation which uses comparesEqual()
+ }
+ friend constexpr std::partial_ordering
+ operator<=>(const MyClass &lhs, int rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ \endcode
+
+ \sa Q_DECLARE_EQUALITY_COMPARABLE, Q_DECLARE_WEAKLY_ORDERED,
+ Q_DECLARE_STRONGLY_ORDERED
+*/
+
+/*!
+ \internal
+ \macro Q_DECLARE_WEAKLY_ORDERED(Type)
+ \macro Q_DECLARE_WEAKLY_ORDERED(LeftType, RightType)
+ \macro Q_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE(Type)
+ \macro Q_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE(LeftType, RightType)
+ \since 6.7
+ \relates <QtCompare>
+
+ These macros behave similarly to the
+ \l {Q_DECLARE_PARTIALLY_ORDERED} overloads, but represent
+ \l {https://en.cppreference.com/w/cpp/utility/compare/weak_ordering}
+ {weak ordering}.
+
+ The (in)equality operators are implemented in terms of a helper function
+ \c {comparesEqual()}. The other relational operators are implemented in
+ terms of a helper function \c {compareThreeWay()}.
+ The \c {compareThreeWay()} function \e must return an object of type
+ \l Qt::weak_ordering. It's the user's responsibility to declare and define both
+ helper functions.
+
+ The \c {*_LITERAL_TYPE} overloads are used to generate \c constexpr
+ operators. This means that the helper \c {comparesEqual()} and
+ \c {compareThreeWay()} functions must also be \c constexpr.
+
+ See \l {Q_DECLARE_PARTIALLY_ORDERED} for usage examples.
+
+ \sa Q_DECLARE_PARTIALLY_ORDERED, Q_DECLARE_STRONGLY_ORDERED,
+ Q_DECLARE_EQUALITY_COMPARABLE
+*/
+
+/*!
+ \internal
+ \macro Q_DECLARE_STRONGLY_ORDERED(Type)
+ \macro Q_DECLARE_STRONGLY_ORDERED(LeftType, RightType)
+ \macro Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(Type)
+ \macro Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(LeftType, RightType)
+ \since 6.7
+ \relates <QtCompare>
+
+ These macros behave similarly to the
+ \l {Q_DECLARE_PARTIALLY_ORDERED} overloads, but represent
+ \l {https://en.cppreference.com/w/cpp/utility/compare/strong_ordering}
+ {strong ordering}.
+
+ The (in)equality operators are implemented in terms of a helper function
+ \c {comparesEqual()}. The other relational operators are implemented in
+ terms of a helper function \c {compareThreeWay()}.
+ The \c {compareThreeWay()} function \e must return an object of type
+ \l Qt::strong_ordering. It's the user's responsibility to declare and define
+ both helper functions.
+
+ The \c {*_LITERAL_TYPE} overloads are used to generate \c constexpr
+ operators. This means that the helper \c {comparesEqual()} and
+ \c {compareThreeWay()} functions must also be \c constexpr.
+
+ See \l {Q_DECLARE_PARTIALLY_ORDERED} for usage examples.
+
+ \sa Q_DECLARE_PARTIALLY_ORDERED, Q_DECLARE_WEAKLY_ORDERED,
+ Q_DECLARE_EQUALITY_COMPARABLE
+*/
+
+/*!
+ \internal
+ \macro Q_DECLARE_EQUALITY_COMPARABLE(LeftType, RightType, Attributes)
+ \macro Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(LeftType, RightType, Attributes)
+ \macro Q_DECLARE_PARTIALLY_ORDERED(LeftType, RightType, Attributes)
+ \macro Q_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE(LeftType, RightType, Attributes)
+ \macro Q_DECLARE_WEAKLY_ORDERED(LeftType, RightType, Attributes)
+ \macro Q_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE(LeftType, RightType, Attributes)
+ \macro Q_DECLARE_STRONGLY_ORDERED(LeftType, RightType, Attributes)
+ \macro Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(LeftType, RightType, Attributes)
+ \since 6.8
+ \relates <QtCompare>
+
+ These macros behave like their two-argument versions, but allow
+ specification of C++ attributes to add before every generated relational
+ operator.
+
+ As an example, the \c Attributes parameter can be used in Qt to pass
+ the \c QT_ASCII_CAST_WARN marco (whose expansion can mark the function as
+ deprecated) when implementing comparison of encoding-aware string types
+ with C-style strings or byte arrays.
+*/
+
+/*!
+ \fn template <typename LeftInt, typename RightInt, Qt::if_integral<LeftInt> = true, Qt::if_integral<RightInt> = true> auto Qt::compareThreeWay(LeftInt lhs, RightInt rhs)
+ \since 6.7
+ \relates <QtCompare>
+ \overload
+
+ Implements three-way comparison of integral types.
+
+ \note This function participates in overload resolution only if both
+ \c LeftInt and \c RightInt are built-in integral types.
+
+ Returns \c {lhs <=> rhs}, provided \c LeftInt and \c RightInt are built-in
+ integral types. Unlike \c {operator<=>()}, this function template is also
+ available in C++17. See
+ \l {https://en.cppreference.com/w/cpp/language/operator_comparison#Three-way_comparison}
+ {cppreference} for more details.
+
+ This function can also be used in custom \c {compareThreeWay()} functions,
+ when ordering members of a custom class represented by built-in types:
+
+ \code
+ class MyClass {
+ public:
+ ...
+ private:
+ int value;
+ ...
+ friend Qt::strong_ordering
+ compareThreeWay(const MyClass &lhs, const MyClass &rhs) noexcept
+ { return Qt::compareThreeWay(lhs.value, rhs.value); }
+ Q_DECLARE_STRONGLY_ORDERED(MyClass)
+ };
+ \endcode
+
+ Returns an instance of \l Qt::strong_ordering that represents the relation
+ between \a lhs and \a rhs.
+*/
+
+/*!
+ \fn template <typename LeftFloat, typename RightFloat, Qt::if_floating_point<LeftFloat> = true, Qt::if_floating_point<RightFloat> = true> auto Qt::compareThreeWay(LeftFloat lhs, RightFloat rhs)
+ \since 6.7
+ \relates <QtCompare>
+ \overload
+
+ Implements three-way comparison of floating point types.
+
+ \note This function participates in overload resolution only if both
+ \c LeftFloat and \c RightFloat are built-in floating-point types.
+
+ Returns \c {lhs <=> rhs}, provided \c LeftFloat and \c RightFloat are
+ built-in floating-point types. Unlike \c {operator<=>()}, this function
+ template is also available in C++17. See
+ \l {https://en.cppreference.com/w/cpp/language/operator_comparison#Three-way_comparison}
+ {cppreference} for more details.
+
+ This function can also be used in custom \c {compareThreeWay()} functions,
+ when ordering members of a custom class represented by built-in types:
+
+ \code
+ class MyClass {
+ public:
+ ...
+ private:
+ double value;
+ ...
+ friend Qt::partial_ordering
+ compareThreeWay(const MyClass &lhs, const MyClass &rhs) noexcept
+ { return Qt::compareThreeWay(lhs.value, rhs.value); }
+ Q_DECLARE_PARTIALLY_ORDERED(MyClass)
+ };
+ \endcode
+
+ Returns an instance of \l Qt::partial_ordering that represents the relation
+ between \a lhs and \a rhs. If \a lhs or \a rhs is not a number (NaN),
+ \l Qt::partial_ordering::unordered is returned.
+*/
+
+/*!
+ \fn template <typename IntType, typename FloatType, Qt::if_integral<IntType> = true, Qt::if_floating_point<FloatType> = true> auto Qt::compareThreeWay(IntType lhs, FloatType rhs)
+ \since 6.7
+ \relates <QtCompare>
+ \overload
+
+ Implements three-way comparison of integral and floating point types.
+
+ \note This function participates in overload resolution only if \c IntType
+ is a built-in integral type and \c FloatType is a built-in floating-point
+ type.
+
+ This function converts \a lhs to \c FloatType and calls the overload for
+ floating-point types.
+
+ Returns an instance of \l Qt::partial_ordering that represents the relation
+ between \a lhs and \a rhs. If \a rhs is not a number (NaN),
+ \l Qt::partial_ordering::unordered is returned.
+*/
+
+/*!
+ \fn template <typename FloatType, typename IntType, Qt::if_floating_point<FloatType> = true, Qt::if_integral<IntType> = true> auto Qt::compareThreeWay(FloatType lhs, IntType rhs)
+ \since 6.7
+ \relates <QtCompare>
+ \overload
+
+ Implements three-way comparison of floating point and integral types.
+
+ \note This function participates in overload resolution only if \c FloatType
+ is a built-in floating-point type and \c IntType is a built-in integral
+ type.
+
+ This function converts \a rhs to \c FloatType and calls the overload for
+ floating-point types.
+
+ Returns an instance of \l Qt::partial_ordering that represents the relation
+ between \a lhs and \a rhs. If \a lhs is not a number (NaN),
+ \l Qt::partial_ordering::unordered is returned.
+*/
+
+/*!
+ \fn template <typename LeftType, typename RightType, Qt::if_compatible_pointers<LeftType, RightType> = true> Qt::compareThreeWay(const LeftType *lhs, const RightType *rhs)
+ \since 6.7
+ \relates <QtCompare>
+ \overload
+
+ Implements three-way comparison of pointers.
+
+ \note This function participates in overload resolution if \c LeftType and
+ \c RightType are the same type, or base and derived types. It is also used
+ to compare any pointer to \c {std::nullptr_t}.
+
+ Returns an instance of \l Qt::strong_ordering that represents the relation
+ between \a lhs and \a rhs.
+*/
+
+/*!
+ \fn template <class Enum, Qt::if_enum<Enum> = true> Qt::compareThreeWay(Enum lhs, Enum rhs)
+ \since 6.7
+ \relates <QtCompare>
+ \overload
+
+ Implements three-way comparison of enum types.
+
+ \note This function participates in overload resolution only if \c Enum
+ is an enum type.
+
+ This function converts \c Enum to its underlying type and calls the
+ overload for integral types.
+
+ Returns an instance of \l Qt::strong_ordering that represents the relation
+ between \a lhs and \a rhs.
+*/
+
+/*!
+ \fn template <typename LeftType, typename RightType> qCompareThreeWay(const LeftType &lhs, const RightType &rhs)
+ \since 6.7
+ \relates <QtCompare>
+
+ Performs the three-way comparison on \a lhs and \a rhs and returns one of
+ the Qt ordering types as a result. This function is available for both
+ C++17 and C++20.
+
+ The actual returned type depends on \c LeftType and \c RightType.
+
+ \note This function template is only available when \c {compareThreeWay()}
+ is implemented for the \c {(LeftType, RightType)} pair or the reversed
+ \c {(RightType, LeftType)} pair.
+
+ This method is equivalent to
+
+ \code
+ using Qt::compareThreeWay;
+ return compareThreeWay(lhs, rhs);
+ \endcode
+
+ where \c {Qt::compareThreeWay} is the Qt implementation of three-way
+ comparison for built-in types.
+
+ The free \c {compareThreeWay} functions should provide three-way comparison
+ for custom types. The functions should return one of the Qt ordering types.
+
+ Qt provides \c {compareThreeWay} implementation for some of its types.
+
+ \note \b {Do not} re-implement \c {compareThreeWay()} for Qt types, as more
+ Qt types will get support for it in future Qt releases.
+
+ Use this function primarly in generic code, when you know nothing about
+ \c LeftType and \c RightType.
+
+ If you know the types, use
+
+ \list
+ \li \c {Qt::compareThreeWay} for built-in types
+ \li \c {compareThreeWay} for custom types
+ \endlist
+
+ Use \c {operator<=>()} directly in code that will only be compiled with
+ C++20 or later.
+
+ \sa Qt::partial_ordering, Qt::weak_ordering, Qt::strong_ordering
+*/
+
+QT_END_NAMESPACE
diff --git a/src/corelib/global/qcompare.h b/src/corelib/global/qcompare.h
index aa0e5eefa8..9dd244c8f9 100644
--- a/src/corelib/global/qcompare.h
+++ b/src/corelib/global/qcompare.h
@@ -1,4 +1,5 @@
// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOMPARE_H
@@ -11,6 +12,13 @@
#include <QtCore/qglobal.h>
#include <QtCore/qcompare_impl.h>
+#ifdef __cpp_lib_bit_cast
+#include <bit>
+#endif
+#ifdef __cpp_lib_three_way_comparison
+#include <compare>
+#endif
+
QT_BEGIN_NAMESPACE
namespace QtPrivate {
@@ -27,11 +35,645 @@ enum class Ordering : CompareUnderlyingType
enum class Uncomparable : CompareUnderlyingType
{
- Unordered = -127
+ Unordered =
+ #if defined(_LIBCPP_VERSION) // libc++
+ -127
+ #elif defined(__GLIBCXX__) // libstdc++
+ 2
+ #else // assume MSSTL
+ -128
+ #endif
};
} // namespace QtPrivate
+namespace QtOrderingPrivate {
+
+template <typename O>
+constexpr O reversed(O o) noexcept
+{
+ // https://eel.is/c++draft/cmp.partialord#5
+ return is_lt(o) ? O::greater :
+ is_gt(o) ? O::less :
+ /*else*/ o ;
+}
+
+} // namespace QtOrderingPrivate
+
+namespace Qt {
+
+class partial_ordering
+{
+public:
+ static const partial_ordering less;
+ static const partial_ordering equivalent;
+ static const partial_ordering greater;
+ static const partial_ordering unordered;
+
+ friend constexpr bool operator==(partial_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order == 0; }
+
+ friend constexpr bool operator!=(partial_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order != 0; }
+
+ friend constexpr bool operator< (partial_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order < 0; }
+
+ friend constexpr bool operator<=(partial_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order <= 0; }
+
+ friend constexpr bool operator> (partial_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order > 0; }
+
+ friend constexpr bool operator>=(partial_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order >= 0; }
+
+
+ friend constexpr bool operator==(QtPrivate::CompareAgainstLiteralZero,
+ partial_ordering rhs) noexcept
+ { return rhs.isOrdered() && 0 == rhs.m_order; }
+
+ friend constexpr bool operator!=(QtPrivate::CompareAgainstLiteralZero,
+ partial_ordering rhs) noexcept
+ { return rhs.isOrdered() && 0 != rhs.m_order; }
+
+ friend constexpr bool operator< (QtPrivate::CompareAgainstLiteralZero,
+ partial_ordering rhs) noexcept
+ { return rhs.isOrdered() && 0 < rhs.m_order; }
+
+ friend constexpr bool operator<=(QtPrivate::CompareAgainstLiteralZero,
+ partial_ordering rhs) noexcept
+ { return rhs.isOrdered() && 0 <= rhs.m_order; }
+
+ friend constexpr bool operator> (QtPrivate::CompareAgainstLiteralZero,
+ partial_ordering rhs) noexcept
+ { return rhs.isOrdered() && 0 > rhs.m_order; }
+
+ friend constexpr bool operator>=(QtPrivate::CompareAgainstLiteralZero,
+ partial_ordering rhs) noexcept
+ { return rhs.isOrdered() && 0 >= rhs.m_order; }
+
+
+#ifdef __cpp_lib_three_way_comparison
+ friend constexpr std::partial_ordering
+ operator<=>(partial_ordering lhs, QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs; } // https://eel.is/c++draft/cmp.partialord#4
+
+ friend constexpr std::partial_ordering
+ operator<=>(QtPrivate::CompareAgainstLiteralZero, partial_ordering rhs) noexcept
+ { return QtOrderingPrivate::reversed(rhs); }
+#endif // __cpp_lib_three_way_comparison
+
+
+ friend constexpr bool operator==(partial_ordering lhs, partial_ordering rhs) noexcept
+ { return lhs.m_order == rhs.m_order; }
+
+ friend constexpr bool operator!=(partial_ordering lhs, partial_ordering rhs) noexcept
+ { return lhs.m_order != rhs.m_order; }
+
+#ifdef __cpp_lib_three_way_comparison
+ constexpr Q_IMPLICIT partial_ordering(std::partial_ordering stdorder) noexcept
+ {
+ if (stdorder == std::partial_ordering::less)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Less);
+ else if (stdorder == std::partial_ordering::equivalent)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Equivalent);
+ else if (stdorder == std::partial_ordering::greater)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater);
+ else if (stdorder == std::partial_ordering::unordered)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Uncomparable::Unordered);
+ }
+
+ constexpr Q_IMPLICIT operator std::partial_ordering() const noexcept
+ {
+ static_assert(sizeof(*this) == sizeof(std::partial_ordering));
+#ifdef __cpp_lib_bit_cast
+ return std::bit_cast<std::partial_ordering>(*this);
+#else
+ using O = QtPrivate::Ordering;
+ using U = QtPrivate::Uncomparable;
+ using R = std::partial_ordering;
+ switch (m_order) {
+ case qToUnderlying(O::Less): return R::less;
+ case qToUnderlying(O::Greater): return R::greater;
+ case qToUnderlying(O::Equivalent): return R::equivalent;
+ case qToUnderlying(U::Unordered): return R::unordered;
+ }
+ Q_UNREACHABLE_RETURN(R::unordered);
+#endif // __cpp_lib_bit_cast
+ }
+
+ friend constexpr bool operator==(partial_ordering lhs, std::partial_ordering rhs) noexcept
+ { return static_cast<std::partial_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(partial_ordering lhs, std::partial_ordering rhs) noexcept
+ { return static_cast<std::partial_ordering>(lhs) != rhs; }
+
+ friend constexpr bool operator==(std::partial_ordering lhs, partial_ordering rhs) noexcept
+ { return lhs == static_cast<std::partial_ordering>(rhs); }
+
+ friend constexpr bool operator!=(std::partial_ordering lhs, partial_ordering rhs) noexcept
+ { return lhs != static_cast<std::partial_ordering>(rhs); }
+#endif // __cpp_lib_three_way_comparison
+
+private:
+ friend class weak_ordering;
+ friend class strong_ordering;
+
+ constexpr explicit partial_ordering(QtPrivate::Ordering order) noexcept
+ : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
+ {}
+ constexpr explicit partial_ordering(QtPrivate::Uncomparable order) noexcept
+ : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
+ {}
+
+ QT_WARNING_PUSH
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903
+ QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant")
+ friend constexpr bool is_eq (partial_ordering o) noexcept { return o == 0; }
+ friend constexpr bool is_neq (partial_ordering o) noexcept { return o != 0; }
+ friend constexpr bool is_lt (partial_ordering o) noexcept { return o < 0; }
+ friend constexpr bool is_lteq(partial_ordering o) noexcept { return o <= 0; }
+ friend constexpr bool is_gt (partial_ordering o) noexcept { return o > 0; }
+ friend constexpr bool is_gteq(partial_ordering o) noexcept { return o >= 0; }
+ QT_WARNING_POP
+
+ // instead of the exposition only is_ordered member in [cmp.partialord],
+ // use a private function
+ constexpr bool isOrdered() const noexcept
+ { return m_order != static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Uncomparable::Unordered); }
+
+ QtPrivate::CompareUnderlyingType m_order;
+};
+
+inline constexpr partial_ordering partial_ordering::less(QtPrivate::Ordering::Less);
+inline constexpr partial_ordering partial_ordering::equivalent(QtPrivate::Ordering::Equivalent);
+inline constexpr partial_ordering partial_ordering::greater(QtPrivate::Ordering::Greater);
+inline constexpr partial_ordering partial_ordering::unordered(QtPrivate::Uncomparable::Unordered);
+
+class weak_ordering
+{
+public:
+ static const weak_ordering less;
+ static const weak_ordering equivalent;
+ static const weak_ordering greater;
+
+ constexpr Q_IMPLICIT operator partial_ordering() const noexcept
+ { return partial_ordering(static_cast<QtPrivate::Ordering>(m_order)); }
+
+ friend constexpr bool operator==(weak_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order == 0; }
+
+ friend constexpr bool operator!=(weak_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order != 0; }
+
+ friend constexpr bool operator< (weak_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order < 0; }
+
+ friend constexpr bool operator<=(weak_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order <= 0; }
+
+ friend constexpr bool operator> (weak_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order > 0; }
+
+ friend constexpr bool operator>=(weak_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order >= 0; }
+
+
+ friend constexpr bool operator==(QtPrivate::CompareAgainstLiteralZero,
+ weak_ordering rhs) noexcept
+ { return 0 == rhs.m_order; }
+
+ friend constexpr bool operator!=(QtPrivate::CompareAgainstLiteralZero,
+ weak_ordering rhs) noexcept
+ { return 0 != rhs.m_order; }
+
+ friend constexpr bool operator< (QtPrivate::CompareAgainstLiteralZero,
+ weak_ordering rhs) noexcept
+ { return 0 < rhs.m_order; }
+
+ friend constexpr bool operator<=(QtPrivate::CompareAgainstLiteralZero,
+ weak_ordering rhs) noexcept
+ { return 0 <= rhs.m_order; }
+
+ friend constexpr bool operator> (QtPrivate::CompareAgainstLiteralZero,
+ weak_ordering rhs) noexcept
+ { return 0 > rhs.m_order; }
+
+ friend constexpr bool operator>=(QtPrivate::CompareAgainstLiteralZero,
+ weak_ordering rhs) noexcept
+ { return 0 >= rhs.m_order; }
+
+
+#ifdef __cpp_lib_three_way_comparison
+ friend constexpr std::weak_ordering
+ operator<=>(weak_ordering lhs, QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs; } // https://eel.is/c++draft/cmp.weakord#5
+
+ friend constexpr std::weak_ordering
+ operator<=>(QtPrivate::CompareAgainstLiteralZero, weak_ordering rhs) noexcept
+ { return QtOrderingPrivate::reversed(rhs); }
+#endif // __cpp_lib_three_way_comparison
+
+
+ friend constexpr bool operator==(weak_ordering lhs, weak_ordering rhs) noexcept
+ { return lhs.m_order == rhs.m_order; }
+
+ friend constexpr bool operator!=(weak_ordering lhs, weak_ordering rhs) noexcept
+ { return lhs.m_order != rhs.m_order; }
+
+ friend constexpr bool operator==(weak_ordering lhs, partial_ordering rhs) noexcept
+ { return static_cast<partial_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(weak_ordering lhs, partial_ordering rhs) noexcept
+ { return static_cast<partial_ordering>(lhs) != rhs; }
+
+ friend constexpr bool operator==(partial_ordering lhs, weak_ordering rhs) noexcept
+ { return lhs == static_cast<partial_ordering>(rhs); }
+
+ friend constexpr bool operator!=(partial_ordering lhs, weak_ordering rhs) noexcept
+ { return lhs != static_cast<partial_ordering>(rhs); }
+
+#ifdef __cpp_lib_three_way_comparison
+ constexpr Q_IMPLICIT weak_ordering(std::weak_ordering stdorder) noexcept
+ {
+ if (stdorder == std::weak_ordering::less)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Less);
+ else if (stdorder == std::weak_ordering::equivalent)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Equivalent);
+ else if (stdorder == std::weak_ordering::greater)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater);
+ }
+
+ constexpr Q_IMPLICIT operator std::weak_ordering() const noexcept
+ {
+ static_assert(sizeof(*this) == sizeof(std::weak_ordering));
+#ifdef __cpp_lib_bit_cast
+ return std::bit_cast<std::weak_ordering>(*this);
+#else
+ using O = QtPrivate::Ordering;
+ using R = std::weak_ordering;
+ switch (m_order) {
+ case qToUnderlying(O::Less): return R::less;
+ case qToUnderlying(O::Greater): return R::greater;
+ case qToUnderlying(O::Equivalent): return R::equivalent;
+ }
+ Q_UNREACHABLE_RETURN(R::equivalent);
+#endif // __cpp_lib_bit_cast
+ }
+
+ friend constexpr bool operator==(weak_ordering lhs, std::weak_ordering rhs) noexcept
+ { return static_cast<std::weak_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(weak_ordering lhs, std::weak_ordering rhs) noexcept
+ { return static_cast<std::weak_ordering>(lhs) != rhs; }
+
+ friend constexpr bool operator==(weak_ordering lhs, std::partial_ordering rhs) noexcept
+ { return static_cast<std::weak_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(weak_ordering lhs, std::partial_ordering rhs) noexcept
+ { return static_cast<std::weak_ordering>(lhs) != rhs; }
+
+ friend constexpr bool operator==(weak_ordering lhs, std::strong_ordering rhs) noexcept
+ { return static_cast<std::weak_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(weak_ordering lhs, std::strong_ordering rhs) noexcept
+ { return static_cast<std::weak_ordering>(lhs) != rhs; }
+
+ friend constexpr bool operator==(std::weak_ordering lhs, weak_ordering rhs) noexcept
+ { return lhs == static_cast<std::weak_ordering>(rhs); }
+
+ friend constexpr bool operator!=(std::weak_ordering lhs, weak_ordering rhs) noexcept
+ { return lhs != static_cast<std::weak_ordering>(rhs); }
+
+ friend constexpr bool operator==(std::partial_ordering lhs, weak_ordering rhs) noexcept
+ { return lhs == static_cast<std::weak_ordering>(rhs); }
+
+ friend constexpr bool operator!=(std::partial_ordering lhs, weak_ordering rhs) noexcept
+ { return lhs != static_cast<std::weak_ordering>(rhs); }
+
+ friend constexpr bool operator==(std::strong_ordering lhs, weak_ordering rhs) noexcept
+ { return lhs == static_cast<std::weak_ordering>(rhs); }
+
+ friend constexpr bool operator!=(std::strong_ordering lhs, weak_ordering rhs) noexcept
+ { return lhs != static_cast<std::weak_ordering>(rhs); }
+#endif // __cpp_lib_three_way_comparison
+
+private:
+ friend class strong_ordering;
+
+ constexpr explicit weak_ordering(QtPrivate::Ordering order) noexcept
+ : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
+ {}
+
+ QT_WARNING_PUSH
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903
+ QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant")
+ friend constexpr bool is_eq (weak_ordering o) noexcept { return o == 0; }
+ friend constexpr bool is_neq (weak_ordering o) noexcept { return o != 0; }
+ friend constexpr bool is_lt (weak_ordering o) noexcept { return o < 0; }
+ friend constexpr bool is_lteq(weak_ordering o) noexcept { return o <= 0; }
+ friend constexpr bool is_gt (weak_ordering o) noexcept { return o > 0; }
+ friend constexpr bool is_gteq(weak_ordering o) noexcept { return o >= 0; }
+ QT_WARNING_POP
+
+ QtPrivate::CompareUnderlyingType m_order;
+};
+
+inline constexpr weak_ordering weak_ordering::less(QtPrivate::Ordering::Less);
+inline constexpr weak_ordering weak_ordering::equivalent(QtPrivate::Ordering::Equivalent);
+inline constexpr weak_ordering weak_ordering::greater(QtPrivate::Ordering::Greater);
+
+class strong_ordering
+{
+public:
+ static const strong_ordering less;
+ static const strong_ordering equivalent;
+ static const strong_ordering equal;
+ static const strong_ordering greater;
+
+ constexpr Q_IMPLICIT operator partial_ordering() const noexcept
+ { return partial_ordering(static_cast<QtPrivate::Ordering>(m_order)); }
+
+ constexpr Q_IMPLICIT operator weak_ordering() const noexcept
+ { return weak_ordering(static_cast<QtPrivate::Ordering>(m_order)); }
+
+ friend constexpr bool operator==(strong_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order == 0; }
+
+ friend constexpr bool operator!=(strong_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order != 0; }
+
+ friend constexpr bool operator< (strong_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order < 0; }
+
+ friend constexpr bool operator<=(strong_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order <= 0; }
+
+ friend constexpr bool operator> (strong_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order > 0; }
+
+ friend constexpr bool operator>=(strong_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order >= 0; }
+
+
+ friend constexpr bool operator==(QtPrivate::CompareAgainstLiteralZero,
+ strong_ordering rhs) noexcept
+ { return 0 == rhs.m_order; }
+
+ friend constexpr bool operator!=(QtPrivate::CompareAgainstLiteralZero,
+ strong_ordering rhs) noexcept
+ { return 0 != rhs.m_order; }
+
+ friend constexpr bool operator< (QtPrivate::CompareAgainstLiteralZero,
+ strong_ordering rhs) noexcept
+ { return 0 < rhs.m_order; }
+
+ friend constexpr bool operator<=(QtPrivate::CompareAgainstLiteralZero,
+ strong_ordering rhs) noexcept
+ { return 0 <= rhs.m_order; }
+
+ friend constexpr bool operator> (QtPrivate::CompareAgainstLiteralZero,
+ strong_ordering rhs) noexcept
+ { return 0 > rhs.m_order; }
+
+ friend constexpr bool operator>=(QtPrivate::CompareAgainstLiteralZero,
+ strong_ordering rhs) noexcept
+ { return 0 >= rhs.m_order; }
+
+
+#ifdef __cpp_lib_three_way_comparison
+ friend constexpr std::strong_ordering
+ operator<=>(strong_ordering lhs, QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs; } // https://eel.is/c++draft/cmp.strongord#6
+
+ friend constexpr std::strong_ordering
+ operator<=>(QtPrivate::CompareAgainstLiteralZero, strong_ordering rhs) noexcept
+ { return QtOrderingPrivate::reversed(rhs); }
+#endif // __cpp_lib_three_way_comparison
+
+
+ friend constexpr bool operator==(strong_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs.m_order == rhs.m_order; }
+
+ friend constexpr bool operator!=(strong_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs.m_order != rhs.m_order; }
+
+ friend constexpr bool operator==(strong_ordering lhs, partial_ordering rhs) noexcept
+ { return static_cast<partial_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(strong_ordering lhs, partial_ordering rhs) noexcept
+ { return static_cast<partial_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator==(partial_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs == static_cast<partial_ordering>(rhs); }
+
+ friend constexpr bool operator!=(partial_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs != static_cast<partial_ordering>(rhs); }
+
+ friend constexpr bool operator==(strong_ordering lhs, weak_ordering rhs) noexcept
+ { return static_cast<weak_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(strong_ordering lhs, weak_ordering rhs) noexcept
+ { return static_cast<weak_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator==(weak_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs == static_cast<weak_ordering>(rhs); }
+
+ friend constexpr bool operator!=(weak_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs != static_cast<weak_ordering>(rhs); }
+
+#ifdef __cpp_lib_three_way_comparison
+ constexpr Q_IMPLICIT strong_ordering(std::strong_ordering stdorder) noexcept
+ {
+ if (stdorder == std::strong_ordering::less)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Less);
+ else if (stdorder == std::strong_ordering::equivalent)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Equivalent);
+ else if (stdorder == std::strong_ordering::equal)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Equal);
+ else if (stdorder == std::strong_ordering::greater)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater);
+ }
+
+ constexpr Q_IMPLICIT operator std::strong_ordering() const noexcept
+ {
+ static_assert(sizeof(*this) == sizeof(std::strong_ordering));
+#ifdef __cpp_lib_bit_cast
+ return std::bit_cast<std::strong_ordering>(*this);
+#else
+ using O = QtPrivate::Ordering;
+ using R = std::strong_ordering;
+ switch (m_order) {
+ case qToUnderlying(O::Less): return R::less;
+ case qToUnderlying(O::Greater): return R::greater;
+ case qToUnderlying(O::Equal): return R::equal;
+ }
+ Q_UNREACHABLE_RETURN(R::equal);
+#endif // __cpp_lib_bit_cast
+ }
+
+ friend constexpr bool operator==(strong_ordering lhs, std::strong_ordering rhs) noexcept
+ { return static_cast<std::strong_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(strong_ordering lhs, std::strong_ordering rhs) noexcept
+ { return static_cast<std::strong_ordering>(lhs) != rhs; }
+
+ friend constexpr bool operator==(strong_ordering lhs, std::partial_ordering rhs) noexcept
+ { return static_cast<std::strong_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(strong_ordering lhs, std::partial_ordering rhs) noexcept
+ { return static_cast<std::strong_ordering>(lhs) != rhs; }
+
+ friend constexpr bool operator==(strong_ordering lhs, std::weak_ordering rhs) noexcept
+ { return static_cast<std::strong_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(strong_ordering lhs, std::weak_ordering rhs) noexcept
+ { return static_cast<std::strong_ordering>(lhs) != rhs; }
+
+ friend constexpr bool operator==(std::strong_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs == static_cast<std::strong_ordering>(rhs); }
+
+ friend constexpr bool operator!=(std::strong_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs != static_cast<std::strong_ordering>(rhs); }
+
+ friend constexpr bool operator==(std::partial_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs == static_cast<std::strong_ordering>(rhs); }
+
+ friend constexpr bool operator!=(std::partial_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs != static_cast<std::strong_ordering>(rhs); }
+
+ friend constexpr bool operator==(std::weak_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs == static_cast<std::strong_ordering>(rhs); }
+
+ friend constexpr bool operator!=(std::weak_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs != static_cast<std::strong_ordering>(rhs); }
+#endif // __cpp_lib_three_way_comparison
+
+ private:
+ constexpr explicit strong_ordering(QtPrivate::Ordering order) noexcept
+ : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
+ {}
+
+ QT_WARNING_PUSH
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903
+ QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant")
+ friend constexpr bool is_eq (strong_ordering o) noexcept { return o == 0; }
+ friend constexpr bool is_neq (strong_ordering o) noexcept { return o != 0; }
+ friend constexpr bool is_lt (strong_ordering o) noexcept { return o < 0; }
+ friend constexpr bool is_lteq(strong_ordering o) noexcept { return o <= 0; }
+ friend constexpr bool is_gt (strong_ordering o) noexcept { return o > 0; }
+ friend constexpr bool is_gteq(strong_ordering o) noexcept { return o >= 0; }
+ QT_WARNING_POP
+
+ QtPrivate::CompareUnderlyingType m_order;
+};
+
+inline constexpr strong_ordering strong_ordering::less(QtPrivate::Ordering::Less);
+inline constexpr strong_ordering strong_ordering::equivalent(QtPrivate::Ordering::Equivalent);
+inline constexpr strong_ordering strong_ordering::equal(QtPrivate::Ordering::Equal);
+inline constexpr strong_ordering strong_ordering::greater(QtPrivate::Ordering::Greater);
+
+} // namespace Qt
+
+QT_BEGIN_INCLUDE_NAMESPACE
+
+// This is intentionally included after Qt::*_ordering types and before
+// qCompareThreeWay. Do not change!
+#include <QtCore/qcomparehelpers.h>
+
+QT_END_INCLUDE_NAMESPACE
+
+namespace QtPrivate {
+
+namespace CompareThreeWayTester {
+
+ using Qt::compareThreeWay;
+
+ // Check if compareThreeWay is implemented for the (LT, RT) argument
+ // pair.
+ template <typename LT, typename RT, typename = void>
+ constexpr bool hasCompareThreeWay = false;
+
+ template <typename LT, typename RT>
+ constexpr bool hasCompareThreeWay<
+ LT, RT, std::void_t<decltype(compareThreeWay(std::declval<LT>(), std::declval<RT>()))>
+ > = true;
+
+ // Check if the operation is noexcept. We have two different overloads,
+ // depending on the available compareThreeWay() implementation.
+ // Both are declared, but not implemented. To be used only in unevaluated
+ // context.
+
+ template <typename LT, typename RT,
+ std::enable_if_t<hasCompareThreeWay<LT, RT>, bool> = true>
+ constexpr bool compareThreeWayNoexcept() noexcept
+ { return noexcept(compareThreeWay(std::declval<LT>(), std::declval<RT>())); }
+
+ template <typename LT, typename RT,
+ std::enable_if_t<!hasCompareThreeWay<LT, RT> && hasCompareThreeWay<RT, LT>,
+ bool> = true>
+ constexpr bool compareThreeWayNoexcept() noexcept
+ { return noexcept(compareThreeWay(std::declval<RT>(), std::declval<LT>())); }
+
+} // namespace CompareThreeWayTester
+
+} // namespace QtPrivate
+
+#if defined(Q_QDOC)
+
+template <typename LeftType, typename RightType>
+auto qCompareThreeWay(const LeftType &lhs, const RightType &rhs);
+
+#else
+
+template <typename LT, typename RT,
+ std::enable_if_t<QtPrivate::CompareThreeWayTester::hasCompareThreeWay<LT, RT>
+ || QtPrivate::CompareThreeWayTester::hasCompareThreeWay<RT, LT>,
+ bool> = true>
+auto qCompareThreeWay(const LT &lhs, const RT &rhs)
+ noexcept(QtPrivate::CompareThreeWayTester::compareThreeWayNoexcept<LT, RT>())
+{
+ using Qt::compareThreeWay;
+ if constexpr (QtPrivate::CompareThreeWayTester::hasCompareThreeWay<LT, RT>) {
+ return compareThreeWay(lhs, rhs);
+ } else {
+ const auto retval = compareThreeWay(rhs, lhs);
+ return QtOrderingPrivate::reversed(retval);
+ }
+}
+
+#endif // defined(Q_QDOC)
+
+//
+// Legacy QPartialOrdering
+//
+
+namespace QtPrivate {
+enum class LegacyUncomparable : CompareUnderlyingType
+{
+ Unordered = -127
+};
+}
+
// [cmp.partialord]
class QPartialOrdering
{
@@ -41,49 +683,195 @@ public:
static const QPartialOrdering Greater;
static const QPartialOrdering Unordered;
- friend constexpr bool operator==(QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- { return p.isOrdered() && p.m_order == 0; }
- friend constexpr bool operator!=(QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- { return p.isOrdered() && p.m_order != 0; }
- friend constexpr bool operator< (QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- { return p.isOrdered() && p.m_order < 0; }
- friend constexpr bool operator<=(QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- { return p.isOrdered() && p.m_order <= 0; }
- friend constexpr bool operator> (QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- { return p.isOrdered() && p.m_order > 0; }
- friend constexpr bool operator>=(QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- { return p.isOrdered() && p.m_order >= 0; }
-
- friend constexpr bool operator==(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- { return p.isOrdered() && 0 == p.m_order; }
- friend constexpr bool operator!=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- { return p.isOrdered() && 0 != p.m_order; }
- friend constexpr bool operator< (QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- { return p.isOrdered() && 0 < p.m_order; }
- friend constexpr bool operator<=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- { return p.isOrdered() && 0 <= p.m_order; }
- friend constexpr bool operator> (QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- { return p.isOrdered() && 0 > p.m_order; }
- friend constexpr bool operator>=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- { return p.isOrdered() && 0 >= p.m_order; }
-
- friend constexpr bool operator==(QPartialOrdering p1, QPartialOrdering p2) noexcept
- { return p1.m_order == p2.m_order; }
- friend constexpr bool operator!=(QPartialOrdering p1, QPartialOrdering p2) noexcept
- { return p1.m_order != p2.m_order; }
+ static const QPartialOrdering less;
+ static const QPartialOrdering equivalent;
+ static const QPartialOrdering greater;
+ static const QPartialOrdering unordered;
+
+ friend constexpr bool operator==(QPartialOrdering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order == 0; }
+
+ friend constexpr bool operator!=(QPartialOrdering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order != 0; }
+
+ friend constexpr bool operator< (QPartialOrdering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order < 0; }
+
+ friend constexpr bool operator<=(QPartialOrdering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order <= 0; }
+
+ friend constexpr bool operator> (QPartialOrdering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order > 0; }
+
+ friend constexpr bool operator>=(QPartialOrdering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order >= 0; }
+
+
+ friend constexpr bool operator==(QtPrivate::CompareAgainstLiteralZero,
+ QPartialOrdering rhs) noexcept
+ { return rhs.isOrdered() && 0 == rhs.m_order; }
+
+ friend constexpr bool operator!=(QtPrivate::CompareAgainstLiteralZero,
+ QPartialOrdering rhs) noexcept
+ { return rhs.isOrdered() && 0 != rhs.m_order; }
+
+ friend constexpr bool operator< (QtPrivate::CompareAgainstLiteralZero,
+ QPartialOrdering rhs) noexcept
+ { return rhs.isOrdered() && 0 < rhs.m_order; }
+
+ friend constexpr bool operator<=(QtPrivate::CompareAgainstLiteralZero,
+ QPartialOrdering rhs) noexcept
+ { return rhs.isOrdered() && 0 <= rhs.m_order; }
+
+ friend constexpr bool operator> (QtPrivate::CompareAgainstLiteralZero,
+ QPartialOrdering rhs) noexcept
+ { return rhs.isOrdered() && 0 > rhs.m_order; }
+
+ friend constexpr bool operator>=(QtPrivate::CompareAgainstLiteralZero,
+ QPartialOrdering rhs) noexcept
+ { return rhs.isOrdered() && 0 >= rhs.m_order; }
+
+
+#ifdef __cpp_lib_three_way_comparison
+ friend constexpr std::partial_ordering
+ operator<=>(QPartialOrdering lhs, QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs; } // https://eel.is/c++draft/cmp.partialord#4
+
+ friend constexpr std::partial_ordering
+ operator<=>(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering rhs) noexcept
+ { return QtOrderingPrivate::reversed(rhs); }
+#endif // __cpp_lib_three_way_comparison
+
+
+ friend constexpr bool operator==(QPartialOrdering lhs, QPartialOrdering rhs) noexcept
+ { return lhs.m_order == rhs.m_order; }
+
+ friend constexpr bool operator!=(QPartialOrdering lhs, QPartialOrdering rhs) noexcept
+ { return lhs.m_order != rhs.m_order; }
+
+ constexpr Q_IMPLICIT QPartialOrdering(Qt::partial_ordering order) noexcept
+ : m_order{} // == equivalent
+ {
+ if (order == Qt::partial_ordering::less)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Less);
+ else if (order == Qt::partial_ordering::greater)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater);
+ else if (order == Qt::partial_ordering::unordered)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::LegacyUncomparable::Unordered);
+ }
+
+ constexpr Q_IMPLICIT QPartialOrdering(Qt::weak_ordering stdorder) noexcept
+ : QPartialOrdering(Qt::partial_ordering{stdorder}) {}
+
+ constexpr Q_IMPLICIT QPartialOrdering(Qt::strong_ordering stdorder) noexcept
+ : QPartialOrdering(Qt::partial_ordering{stdorder}) {}
+
+ constexpr Q_IMPLICIT operator Qt::partial_ordering() const noexcept
+ {
+ using O = QtPrivate::Ordering;
+ using U = QtPrivate::LegacyUncomparable;
+ using R = Qt::partial_ordering;
+ switch (m_order) {
+ case qToUnderlying(O::Less): return R::less;
+ case qToUnderlying(O::Greater): return R::greater;
+ case qToUnderlying(O::Equivalent): return R::equivalent;
+ case qToUnderlying(U::Unordered): return R::unordered;
+ }
+ // GCC 8.x does not treat __builtin_unreachable() as constexpr
+#if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
+ // NOLINTNEXTLINE(qt-use-unreachable-return): Triggers on Clang, breaking GCC 8
+ Q_UNREACHABLE();
+#endif
+ return R::unordered;
+ }
+
+ friend constexpr bool operator==(QPartialOrdering lhs, Qt::partial_ordering rhs) noexcept
+ { Qt::partial_ordering qt = lhs; return qt == rhs; }
+
+ friend constexpr bool operator!=(QPartialOrdering lhs, Qt::partial_ordering rhs) noexcept
+ { Qt::partial_ordering qt = lhs; return qt != rhs; }
+
+ friend constexpr bool operator==(Qt::partial_ordering lhs, QPartialOrdering rhs) noexcept
+ { Qt::partial_ordering qt = rhs; return lhs == qt; }
+
+ friend constexpr bool operator!=(Qt::partial_ordering lhs, QPartialOrdering rhs) noexcept
+ { Qt::partial_ordering qt = rhs; return lhs != qt; }
+
+#ifdef __cpp_lib_three_way_comparison
+ constexpr Q_IMPLICIT QPartialOrdering(std::partial_ordering stdorder) noexcept
+ {
+ if (stdorder == std::partial_ordering::less)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Less);
+ else if (stdorder == std::partial_ordering::equivalent)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Equivalent);
+ else if (stdorder == std::partial_ordering::greater)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater);
+ else if (stdorder == std::partial_ordering::unordered)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::LegacyUncomparable::Unordered);
+ }
+
+ constexpr Q_IMPLICIT QPartialOrdering(std::weak_ordering stdorder) noexcept
+ : QPartialOrdering(std::partial_ordering(stdorder)) {}
+
+ constexpr Q_IMPLICIT QPartialOrdering(std::strong_ordering stdorder) noexcept
+ : QPartialOrdering(std::partial_ordering(stdorder)) {}
+
+ constexpr Q_IMPLICIT operator std::partial_ordering() const noexcept
+ {
+ using O = QtPrivate::Ordering;
+ using U = QtPrivate::LegacyUncomparable;
+ using R = std::partial_ordering;
+ switch (m_order) {
+ case qToUnderlying(O::Less): return R::less;
+ case qToUnderlying(O::Greater): return R::greater;
+ case qToUnderlying(O::Equivalent): return R::equivalent;
+ case qToUnderlying(U::Unordered): return R::unordered;
+ }
+ Q_UNREACHABLE_RETURN(R::unordered);
+ }
+
+ friend constexpr bool operator==(QPartialOrdering lhs, std::partial_ordering rhs) noexcept
+ { return static_cast<std::partial_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(QPartialOrdering lhs, std::partial_ordering rhs) noexcept
+ { return static_cast<std::partial_ordering>(lhs) != rhs; }
+
+ friend constexpr bool operator==(std::partial_ordering lhs, QPartialOrdering rhs) noexcept
+ { return lhs == static_cast<std::partial_ordering>(rhs); }
+
+ friend constexpr bool operator!=(std::partial_ordering lhs, QPartialOrdering rhs) noexcept
+ { return lhs != static_cast<std::partial_ordering>(rhs); }
+#endif // __cpp_lib_three_way_comparison
private:
constexpr explicit QPartialOrdering(QtPrivate::Ordering order) noexcept
: m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
{}
- constexpr explicit QPartialOrdering(QtPrivate::Uncomparable order) noexcept
+ constexpr explicit QPartialOrdering(QtPrivate::LegacyUncomparable order) noexcept
: m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
{}
+ QT_WARNING_PUSH
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903
+ QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant")
+ friend constexpr bool is_eq (QPartialOrdering o) noexcept { return o == 0; }
+ friend constexpr bool is_neq (QPartialOrdering o) noexcept { return o != 0; }
+ friend constexpr bool is_lt (QPartialOrdering o) noexcept { return o < 0; }
+ friend constexpr bool is_lteq(QPartialOrdering o) noexcept { return o <= 0; }
+ friend constexpr bool is_gt (QPartialOrdering o) noexcept { return o > 0; }
+ friend constexpr bool is_gteq(QPartialOrdering o) noexcept { return o >= 0; }
+ QT_WARNING_POP
+
// instead of the exposition only is_ordered member in [cmp.partialord],
// use a private function
- constexpr bool isOrdered() noexcept
- { return m_order != static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Uncomparable::Unordered); }
+ constexpr bool isOrdered() const noexcept
+ { return m_order != static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::LegacyUncomparable::Unordered); }
QtPrivate::CompareUnderlyingType m_order;
};
@@ -91,7 +879,12 @@ private:
inline constexpr QPartialOrdering QPartialOrdering::Less(QtPrivate::Ordering::Less);
inline constexpr QPartialOrdering QPartialOrdering::Equivalent(QtPrivate::Ordering::Equivalent);
inline constexpr QPartialOrdering QPartialOrdering::Greater(QtPrivate::Ordering::Greater);
-inline constexpr QPartialOrdering QPartialOrdering::Unordered(QtPrivate::Uncomparable::Unordered);
+inline constexpr QPartialOrdering QPartialOrdering::Unordered(QtPrivate::LegacyUncomparable::Unordered);
+
+inline constexpr QPartialOrdering QPartialOrdering::less(QtPrivate::Ordering::Less);
+inline constexpr QPartialOrdering QPartialOrdering::equivalent(QtPrivate::Ordering::Equivalent);
+inline constexpr QPartialOrdering QPartialOrdering::greater(QtPrivate::Ordering::Greater);
+inline constexpr QPartialOrdering QPartialOrdering::unordered(QtPrivate::LegacyUncomparable::Unordered);
QT_END_NAMESPACE
diff --git a/src/corelib/global/qcompare.qdoc b/src/corelib/global/qcompare.qdoc
deleted file mode 100644
index 33b8f31000..0000000000
--- a/src/corelib/global/qcompare.qdoc
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
-
-/*!
- \class QPartialOrdering
- \inmodule QtCore
- \brief QPartialOrdering represents the result of a comparison that allows for unordered results.
- \since 6.0
-
- A value of type QPartialOrdering is typically returned from a
- three-way comparison function. Such a function compares two
- objects, and it may either establish that the two objects are
- ordered relative to each other, or that they are not ordered. The
- QPartialOrdering value returned from the comparison function
- represents one of those possibilities.
-
- The possible values of type QPartialOrdering are, in fact, fully
- represented by the following four static values:
-
- \list
-
- \li \c QPartialOrdering::Less represents that the first object is
- less than the second;
-
- \li \c QPartialOrdering::Equivalent represents that the first
- object is equivalent to the second;
-
- \li \c QPartialOrdering::Greater represents that the first object
- is greater than the second;
-
- \li \c QPartialOrdering::Unordered represents that the first object
- is \e{not ordered} with respect to the second.
-
- \endlist
-
- QPartialOrdering is idiomatically used by comparing an instance
- against a literal zero, for instance like this:
-
- \code
-
- // given a, b, c, d as objects of some type that allows for a 3-way compare
-
- QPartialOrdering result = a.compare(b);
- if (result < 0) {
- // a is less than b
- }
-
- if (c.compare(d) >= 0) {
- // c is greater than or equal to d
- }
-
- \endcode
-
- A QPartialOrdering value which represents an unordered result will
- always return false when compared against literal 0.
-*/
-
-/*!
- \fn bool QPartialOrdering::operator==(QPartialOrdering p1, QPartialOrdering p2) noexcept
-
- Return true if \a p1 and \a p2 represent the same result;
- otherwise, returns false.
-*/
-
-/*!
- \fn bool QPartialOrdering::operator!=(QPartialOrdering p1, QPartialOrdering p2) noexcept
-
- Return true if \a p1 and \a p2 represent different results;
- otherwise, returns true.
-*/
-
-/*!
- \fn bool operator==(QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- \fn bool operator!=(QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- \fn bool operator< (QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- \fn bool operator<=(QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- \fn bool operator> (QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- \fn bool operator>=(QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
-
- \fn bool operator==(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- \fn bool operator!=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- \fn bool operator< (QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- \fn bool operator<=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- \fn bool operator> (QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- \fn bool operator>=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- \relates QPartialOrdering
- \internal
-*/
-
-/*!
- \variable QPartialOrdering::Less
- Represents the result of a comparison where the value on the left
- hand side is less than the value on right hand side.
-*/
-
-/*!
- \variable QPartialOrdering::Equivalent
- Represents the result of a comparison where the value on the left
- hand side is equivalent to the value on right hand side.
-*/
-
-/*!
- \variable QPartialOrdering::Greater
- Represents the result of a comparison where the value on the left
- hand side is greater than the value on right hand side.
-*/
-
-/*!
- \variable QPartialOrdering::Unordered
- Represents the result of a comparison where the value on the left
- hand side is not ordered with respect to the value on right hand
- side.
-*/
diff --git a/src/corelib/global/qcompare_impl.h b/src/corelib/global/qcompare_impl.h
index a2670a2b49..c52417fcec 100644
--- a/src/corelib/global/qcompare_impl.h
+++ b/src/corelib/global/qcompare_impl.h
@@ -1,15 +1,16 @@
// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef QCOMPARE_IMPL_H
+#define QCOMPARE_IMPL_H
+
#if 0
#pragma qt_sync_skip_header_check
#pragma qt_sync_stop_processing
#endif
-#ifndef QCOMPARE_IMPL_H
-#define QCOMPARE_IMPL_H
-
-#include <QtCore/qglobal.h>
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qcompilerdetection.h>
QT_BEGIN_NAMESPACE
@@ -22,7 +23,7 @@ public:
using SafeZero = void (CompareAgainstLiteralZero::*)();
Q_IMPLICIT constexpr CompareAgainstLiteralZero(SafeZero) noexcept {}
- template <typename T, std::enable_if_t<!std::is_same_v<T, int>, bool> = false>
+ template <typename T, std::enable_if_t<std::is_null_pointer_v<T>, bool> = true>
CompareAgainstLiteralZero(T) = delete;
};
diff --git a/src/corelib/global/qcomparehelpers.h b/src/corelib/global/qcomparehelpers.h
new file mode 100644
index 0000000000..97c972bfa7
--- /dev/null
+++ b/src/corelib/global/qcomparehelpers.h
@@ -0,0 +1,567 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QCOMPARE_H
+#error "Do not include qcomparehelpers.h directly. Use qcompare.h instead."
+#endif
+
+#ifndef QCOMPAREHELPERS_H
+#define QCOMPAREHELPERS_H
+
+#if 0
+#pragma qt_no_master_include
+#pragma qt_sync_skip_header_check
+#pragma qt_sync_stop_processing
+#endif
+
+#include <QtCore/qoverload.h>
+#include <QtCore/qttypetraits.h>
+#include <QtCore/qtypes.h>
+
+#ifdef __cpp_lib_three_way_comparison
+#include <compare>
+#endif
+#include <QtCore/q20type_traits.h>
+
+#include <functional> // std::less
+
+QT_BEGIN_NAMESPACE
+
+class QPartialOrdering;
+
+namespace QtOrderingPrivate {
+#ifdef __cpp_lib_three_way_comparison
+
+template <typename QtOrdering> struct StdOrdering;
+template <typename StdOrdering> struct QtOrdering;
+
+#define QT_STD_MAP(x) \
+ template <> struct StdOrdering< Qt::x##_ordering> : q20::type_identity<std::x##_ordering> {};\
+ template <> struct StdOrdering<std::x##_ordering> : q20::type_identity<std::x##_ordering> {};\
+ template <> struct QtOrdering<std::x##_ordering> : q20::type_identity< Qt::x##_ordering> {};\
+ template <> struct QtOrdering< Qt::x##_ordering> : q20::type_identity< Qt::x##_ordering> {};\
+ /* end */
+QT_STD_MAP(partial)
+QT_STD_MAP(weak)
+QT_STD_MAP(strong)
+#undef QT_STD_MAP
+
+template <> struct StdOrdering<QPartialOrdering> : q20::type_identity<std::partial_ordering> {};
+template <> struct QtOrdering<QPartialOrdering> : q20::type_identity< Qt::partial_ordering> {};
+
+template <typename In> constexpr auto to_std(In in) noexcept
+ -> typename QtOrderingPrivate::StdOrdering<In>::type
+{ return in; }
+
+template <typename In> constexpr auto to_Qt(In in) noexcept
+ -> typename QtOrderingPrivate::QtOrdering<In>::type
+{ return in; }
+
+#endif // __cpp_lib_three_way_comparison
+} // namespace QtOrderingPrivate
+
+/*
+ For all the macros these parameter names are used:
+ * LeftType - the type of the left operand of the comparison
+ * RightType - the type of the right operand of the comparison
+ * Constexpr - must be either constexpr or empty. Defines whether the
+ operator is constexpr or not
+ * Attributes - an optional list of attributes. For example, pass
+ \c QT_ASCII_CAST_WARN when defining comparisons between
+ C-style string and an encoding-aware string type.
+
+ The macros require two helper functions. For operators to be constexpr,
+ these must be constexpr, too. Additionally, other attributes (like
+ Q_<Module>_EXPORT, Q_DECL_CONST_FUNCTION, etc) can be applied to them.
+ Aside from that, their declaration should match:
+ bool comparesEqual(LeftType, RightType) noexcept;
+ ReturnType compareThreeWay(LeftType, RightType) noexcept;
+
+ The ReturnType can be one of Qt::{partial,weak,strong}_ordering. The actual
+ type depends on the macro being used.
+ It makes sense to define the helper functions as hidden friends of the
+ class, so that they could be found via ADL, and don't participate in
+ unintended implicit conversions.
+*/
+
+// Seems that qdoc uses C++20 even when Qt is compiled in C++17 mode.
+// Or at least it defines __cpp_lib_three_way_comparison.
+// Let qdoc see only the C++17 operators for now, because that's what our docs
+// currently describe.
+#if defined(__cpp_lib_three_way_comparison) && !defined(Q_QDOC)
+// C++20 - provide operator==() for equality, and operator<=>() for ordering
+
+#define QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr, Attributes) \
+ Attributes \
+ friend Constexpr bool operator==(LeftType const &lhs, RightType const &rhs) \
+ noexcept(noexcept(comparesEqual(lhs, rhs))) \
+ { return comparesEqual(lhs, rhs); }
+
+#define QT_DECLARE_3WAY_HELPER_STRONG(LeftType, RightType, Constexpr, Attributes) \
+ Attributes \
+ friend Constexpr std::strong_ordering \
+ operator<=>(LeftType const &lhs, RightType const &rhs) \
+ noexcept(noexcept(compareThreeWay(lhs, rhs))) \
+ { \
+ return compareThreeWay(lhs, rhs); \
+ }
+
+#define QT_DECLARE_3WAY_HELPER_WEAK(LeftType, RightType, Constexpr, Attributes) \
+ Attributes \
+ friend Constexpr std::weak_ordering \
+ operator<=>(LeftType const &lhs, RightType const &rhs) \
+ noexcept(noexcept(compareThreeWay(lhs, rhs))) \
+ { \
+ return compareThreeWay(lhs, rhs); \
+ }
+
+#define QT_DECLARE_3WAY_HELPER_PARTIAL(LeftType, RightType, Constexpr, Attributes) \
+ Attributes \
+ friend Constexpr std::partial_ordering \
+ operator<=>(LeftType const &lhs, RightType const &rhs) \
+ noexcept(noexcept(compareThreeWay(lhs, rhs))) \
+ { \
+ return compareThreeWay(lhs, rhs); \
+ }
+
+#define QT_DECLARE_ORDERING_OPERATORS_HELPER(OrderingType, LeftType, RightType, Constexpr, \
+ Attributes) \
+ QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr, Attributes) \
+ QT_DECLARE_3WAY_HELPER_ ## OrderingType (LeftType, RightType, Constexpr, Attributes)
+
+#ifdef Q_COMPILER_LACKS_THREE_WAY_COMPARE_SYMMETRY
+
+// define reversed versions of the operators manually, because buggy MSVC versions do not do it
+#define QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, Attributes) \
+ Attributes \
+ friend Constexpr bool operator==(RightType const &lhs, LeftType const &rhs) \
+ noexcept(noexcept(comparesEqual(rhs, lhs))) \
+ { return comparesEqual(rhs, lhs); }
+
+#define QT_DECLARE_REVERSED_3WAY_HELPER_STRONG(LeftType, RightType, Constexpr, Attributes) \
+ Attributes \
+ friend Constexpr std::strong_ordering \
+ operator<=>(RightType const &lhs, LeftType const &rhs) \
+ noexcept(noexcept(compareThreeWay(rhs, lhs))) \
+ { \
+ const auto r = compareThreeWay(rhs, lhs); \
+ if (is_gt(r)) return std::strong_ordering::less; \
+ if (is_lt(r)) return std::strong_ordering::greater; \
+ return r; \
+ }
+
+#define QT_DECLARE_REVERSED_3WAY_HELPER_WEAK(LeftType, RightType, Constexpr, Attributes) \
+ Attributes \
+ friend Constexpr std::weak_ordering \
+ operator<=>(RightType const &lhs, LeftType const &rhs) \
+ noexcept(noexcept(compareThreeWay(rhs, lhs))) \
+ { \
+ const auto r = compareThreeWay(rhs, lhs); \
+ if (is_gt(r)) return std::weak_ordering::less; \
+ if (is_lt(r)) return std::weak_ordering::greater; \
+ return r; \
+ }
+
+#define QT_DECLARE_REVERSED_3WAY_HELPER_PARTIAL(LeftType, RightType, Constexpr, Attributes) \
+ Attributes \
+ friend Constexpr std::partial_ordering \
+ operator<=>(RightType const &lhs, LeftType const &rhs) \
+ noexcept(noexcept(compareThreeWay(rhs, lhs))) \
+ { \
+ const auto r = compareThreeWay(rhs, lhs); \
+ if (is_gt(r)) return std::partial_ordering::less; \
+ if (is_lt(r)) return std::partial_ordering::greater; \
+ return r; \
+ }
+
+#define QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(OrderingString, LeftType, RightType, \
+ Constexpr, Attributes) \
+ QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, Attributes) \
+ QT_DECLARE_REVERSED_3WAY_HELPER_ ## OrderingString (LeftType, RightType, Constexpr, Attributes)
+
+#else
+
+// dummy macros for C++17 compatibility, reversed operators are generated by the compiler
+#define QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, Attributes)
+#define QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(OrderingString, LeftType, RightType, \
+ Constexpr, Attributes)
+
+#endif // Q_COMPILER_LACKS_THREE_WAY_COMPARE_SYMMETRY
+
+#else
+// C++17 - provide operator==() and operator!=() for equality,
+// and all 4 comparison operators for ordering
+
+#define QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr, Attributes) \
+ Attributes \
+ friend Constexpr bool operator==(LeftType const &lhs, RightType const &rhs) \
+ noexcept(noexcept(comparesEqual(lhs, rhs))) \
+ { return comparesEqual(lhs, rhs); } \
+ Attributes \
+ friend Constexpr bool operator!=(LeftType const &lhs, RightType const &rhs) \
+ noexcept(noexcept(comparesEqual(lhs, rhs))) \
+ { return !comparesEqual(lhs, rhs); }
+
+// Helpers for reversed comparison, using the existing comparesEqual() function.
+#define QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, Attributes) \
+ Attributes \
+ friend Constexpr bool operator==(RightType const &lhs, LeftType const &rhs) \
+ noexcept(noexcept(comparesEqual(rhs, lhs))) \
+ { return comparesEqual(rhs, lhs); } \
+ Attributes \
+ friend Constexpr bool operator!=(RightType const &lhs, LeftType const &rhs) \
+ noexcept(noexcept(comparesEqual(rhs, lhs))) \
+ { return !comparesEqual(rhs, lhs); }
+
+#define QT_DECLARE_ORDERING_HELPER_TEMPLATE(OrderingType, LeftType, RightType, Constexpr, \
+ Attributes) \
+ Attributes \
+ friend Constexpr bool operator<(LeftType const &lhs, RightType const &rhs) \
+ noexcept(noexcept(compareThreeWay(lhs, rhs))) \
+ { return is_lt(compareThreeWay(lhs, rhs)); } \
+ Attributes \
+ friend Constexpr bool operator>(LeftType const &lhs, RightType const &rhs) \
+ noexcept(noexcept(compareThreeWay(lhs, rhs))) \
+ { return is_gt(compareThreeWay(lhs, rhs)); } \
+ Attributes \
+ friend Constexpr bool operator<=(LeftType const &lhs, RightType const &rhs) \
+ noexcept(noexcept(compareThreeWay(lhs, rhs))) \
+ { return is_lteq(compareThreeWay(lhs, rhs)); } \
+ Attributes \
+ friend Constexpr bool operator>=(LeftType const &lhs, RightType const &rhs) \
+ noexcept(noexcept(compareThreeWay(lhs, rhs))) \
+ { return is_gteq(compareThreeWay(lhs, rhs)); }
+
+#define QT_DECLARE_ORDERING_HELPER_PARTIAL(LeftType, RightType, Constexpr, Attributes) \
+ QT_DECLARE_ORDERING_HELPER_TEMPLATE(Qt::partial_ordering, LeftType, RightType, Constexpr, \
+ Attributes)
+
+#define QT_DECLARE_ORDERING_HELPER_WEAK(LeftType, RightType, Constexpr, Attributes) \
+ QT_DECLARE_ORDERING_HELPER_TEMPLATE(Qt::weak_ordering, LeftType, RightType, Constexpr, \
+ Attributes)
+
+#define QT_DECLARE_ORDERING_HELPER_STRONG(LeftType, RightType, Constexpr, Attributes) \
+ QT_DECLARE_ORDERING_HELPER_TEMPLATE(Qt::strong_ordering, LeftType, RightType, Constexpr, \
+ Attributes)
+
+#define QT_DECLARE_ORDERING_OPERATORS_HELPER(OrderingString, LeftType, RightType, Constexpr, \
+ Attributes) \
+ QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr, Attributes) \
+ QT_DECLARE_ORDERING_HELPER_ ## OrderingString (LeftType, RightType, Constexpr, Attributes)
+
+// Helpers for reversed ordering, using the existing compareThreeWay() function.
+#define QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(OrderingType, LeftType, RightType, Constexpr, \
+ Attributes) \
+ Attributes \
+ friend Constexpr bool operator<(RightType const &lhs, LeftType const &rhs) \
+ noexcept(noexcept(compareThreeWay(rhs, lhs))) \
+ { return is_gt(compareThreeWay(rhs, lhs)); } \
+ Attributes \
+ friend Constexpr bool operator>(RightType const &lhs, LeftType const &rhs) \
+ noexcept(noexcept(compareThreeWay(rhs, lhs))) \
+ { return is_lt(compareThreeWay(rhs, lhs)); } \
+ Attributes \
+ friend Constexpr bool operator<=(RightType const &lhs, LeftType const &rhs) \
+ noexcept(noexcept(compareThreeWay(rhs, lhs))) \
+ { return is_gteq(compareThreeWay(rhs, lhs)); } \
+ Attributes \
+ friend Constexpr bool operator>=(RightType const &lhs, LeftType const &rhs) \
+ noexcept(noexcept(compareThreeWay(rhs, lhs))) \
+ { return is_lteq(compareThreeWay(rhs, lhs)); }
+
+#define QT_DECLARE_REVERSED_ORDERING_HELPER_PARTIAL(LeftType, RightType, Constexpr, Attributes) \
+ QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(Qt::partial_ordering, LeftType, RightType, \
+ Constexpr, Attributes)
+
+#define QT_DECLARE_REVERSED_ORDERING_HELPER_WEAK(LeftType, RightType, Constexpr, Attributes) \
+ QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(Qt::weak_ordering, LeftType, RightType, \
+ Constexpr, Attributes)
+
+#define QT_DECLARE_REVERSED_ORDERING_HELPER_STRONG(LeftType, RightType, Constexpr, Attributes) \
+ QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(Qt::strong_ordering, LeftType, RightType, \
+ Constexpr, Attributes)
+
+#define QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(OrderingString, LeftType, RightType, \
+ Constexpr, Attributes) \
+ QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, Attributes) \
+ QT_DECLARE_REVERSED_ORDERING_HELPER_ ## OrderingString (LeftType, RightType, Constexpr, \
+ Attributes)
+
+#endif // __cpp_lib_three_way_comparison
+
+/* Public API starts here */
+
+// Equality operators
+#define QT_DECLARE_EQUALITY_COMPARABLE_1(Type) \
+ QT_DECLARE_EQUALITY_OPERATORS_HELPER(Type, Type, /* non-constexpr */, /* no attributes */)
+
+#define QT_DECLARE_EQUALITY_COMPARABLE_2(LeftType, RightType) \
+ QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, /* non-constexpr */, \
+ /* no attributes */) \
+ QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, /* non-constexpr */, \
+ /* no attributes */)
+
+#define QT_DECLARE_EQUALITY_COMPARABLE_3(LeftType, RightType, Attributes) \
+ QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, /* non-constexpr */, Attributes) \
+ QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, /* non-constexpr */, \
+ Attributes)
+
+#define Q_DECLARE_EQUALITY_COMPARABLE(...) \
+ QT_OVERLOADED_MACRO(QT_DECLARE_EQUALITY_COMPARABLE, __VA_ARGS__)
+
+#define QT_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE_1(Type) \
+ QT_DECLARE_EQUALITY_OPERATORS_HELPER(Type, Type, constexpr, /* no attributes */)
+
+#define QT_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE_2(LeftType, RightType) \
+ QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, constexpr, /* no attributes */) \
+ QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, constexpr, \
+ /* no attributes */)
+
+#define QT_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE_3(LeftType, RightType, Attributes) \
+ QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, constexpr, Attributes) \
+ QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, constexpr, Attributes)
+
+#define Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(...) \
+ QT_OVERLOADED_MACRO(QT_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE, __VA_ARGS__)
+
+// Partial ordering operators
+#define QT_DECLARE_PARTIALLY_ORDERED_1(Type) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, Type, Type, /* non-constexpr */, \
+ /* no attributes */)
+
+#define QT_DECLARE_PARTIALLY_ORDERED_2(LeftType, RightType) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, LeftType, RightType, /* non-constexpr */, \
+ /* no attributes */) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(PARTIAL, LeftType, RightType, \
+ /* non-constexpr */, /* no attributes */)
+
+#define QT_DECLARE_PARTIALLY_ORDERED_3(LeftType, RightType, Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, LeftType, RightType, /* non-constexpr */, \
+ Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(PARTIAL, LeftType, RightType, \
+ /* non-constexpr */, Attributes)
+
+#define Q_DECLARE_PARTIALLY_ORDERED(...) \
+ QT_OVERLOADED_MACRO(QT_DECLARE_PARTIALLY_ORDERED, __VA_ARGS__)
+
+#define QT_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE_1(Type) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, Type, Type, constexpr, /* no attributes */)
+
+#define QT_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE_2(LeftType, RightType) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, LeftType, RightType, constexpr, \
+ /* no attributes */) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(PARTIAL, LeftType, RightType, constexpr, \
+ /* no attributes */)
+
+#define QT_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE_3(LeftType, RightType, Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, LeftType, RightType, constexpr, Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(PARTIAL, LeftType, RightType, constexpr, \
+ Attributes)
+
+#define Q_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE(...) \
+ QT_OVERLOADED_MACRO(QT_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE, __VA_ARGS__)
+
+// Weak ordering operators
+#define QT_DECLARE_WEAKLY_ORDERED_1(Type) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, Type, Type, /* non-constexpr */, /* no attributes */)
+
+#define QT_DECLARE_WEAKLY_ORDERED_2(LeftType, RightType) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, LeftType, RightType, /* non-constexpr */, \
+ /* no attributes */) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(WEAK, LeftType, RightType, /* non-constexpr */, \
+ /* no attributes */)
+
+#define QT_DECLARE_WEAKLY_ORDERED_3(LeftType, RightType, Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, LeftType, RightType, /* non-constexpr */, \
+ Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(WEAK, LeftType, RightType, /* non-constexpr */, \
+ Attributes)
+
+#define Q_DECLARE_WEAKLY_ORDERED(...) \
+ QT_OVERLOADED_MACRO(QT_DECLARE_WEAKLY_ORDERED, __VA_ARGS__)
+
+#define QT_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE_1(Type) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, Type, Type, constexpr, /* no attributes */)
+
+#define QT_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE_2(LeftType, RightType) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, LeftType, RightType, constexpr, \
+ /* no attributes */) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(WEAK, LeftType, RightType, constexpr, \
+ /* no attributes */)
+
+#define QT_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE_3(LeftType, RightType, Attributes) \
+QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, LeftType, RightType, constexpr, Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(WEAK, LeftType, RightType, constexpr, \
+ Attributes)
+
+#define Q_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE(...) \
+ QT_OVERLOADED_MACRO(QT_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE, __VA_ARGS__)
+
+// Strong ordering operators
+#define QT_DECLARE_STRONGLY_ORDERED_1(Type) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, Type, Type, /* non-constexpr */, \
+ /* no attributes */)
+
+#define QT_DECLARE_STRONGLY_ORDERED_2(LeftType, RightType) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, LeftType, RightType, /* non-constexpr */, \
+ /* no attributes */) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(STRONG, LeftType, RightType, \
+ /* non-constexpr */, /* no attributes */)
+
+#define QT_DECLARE_STRONGLY_ORDERED_3(LeftType, RightType, Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, LeftType, RightType, /* non-constexpr */, \
+ Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(STRONG, LeftType, RightType, \
+ /* non-constexpr */, Attributes)
+
+#define Q_DECLARE_STRONGLY_ORDERED(...) \
+ QT_OVERLOADED_MACRO(QT_DECLARE_STRONGLY_ORDERED, __VA_ARGS__)
+
+#define QT_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE_1(Type) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, Type, Type, constexpr, /* no attributes */)
+
+#define QT_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE_2(LeftType, RightType) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, LeftType, RightType, constexpr, \
+ /* no attributes */) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(STRONG, LeftType, RightType, constexpr, \
+ /* no attributes */)
+
+#define QT_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE_3(LeftType, RightType, Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, LeftType, RightType, constexpr, Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(STRONG, LeftType, RightType, constexpr, \
+ Attributes)
+
+#define Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(...) \
+ QT_OVERLOADED_MACRO(QT_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE, __VA_ARGS__)
+
+namespace QtPrivate {
+
+template <typename T>
+constexpr bool IsIntegralType_v = std::numeric_limits<std::remove_const_t<T>>::is_specialized
+ && std::numeric_limits<std::remove_const_t<T>>::is_integer;
+
+template <typename T>
+constexpr bool IsFloatType_v = std::is_floating_point_v<T>;
+
+#if QFLOAT16_IS_NATIVE
+template <>
+constexpr bool IsFloatType_v<QtPrivate::NativeFloat16Type> = true;
+#endif
+
+} // namespace QtPrivate
+
+namespace Qt {
+
+template <typename T>
+using if_integral = std::enable_if_t<QtPrivate::IsIntegralType_v<T>, bool>;
+
+template <typename T>
+using if_floating_point = std::enable_if_t<QtPrivate::IsFloatType_v<T>, bool>;
+
+template <typename T, typename U>
+using if_compatible_pointers =
+ std::enable_if_t<std::disjunction_v<std::is_same<T, U>,
+ std::is_base_of<T, U>,
+ std::is_base_of<U, T>>,
+ bool>;
+
+template <typename Enum>
+using if_enum = std::enable_if_t<std::is_enum_v<Enum>, bool>;
+
+template <typename LeftInt, typename RightInt,
+ if_integral<LeftInt> = true,
+ if_integral<RightInt> = true>
+constexpr Qt::strong_ordering compareThreeWay(LeftInt lhs, RightInt rhs) noexcept
+{
+ static_assert(std::is_signed_v<LeftInt> == std::is_signed_v<RightInt>,
+ "Qt::compareThreeWay() does not allow mixed-sign comparison.");
+
+#ifdef __cpp_lib_three_way_comparison
+ return lhs <=> rhs;
+#else
+ if (lhs == rhs)
+ return Qt::strong_ordering::equivalent;
+ else if (lhs < rhs)
+ return Qt::strong_ordering::less;
+ else
+ return Qt::strong_ordering::greater;
+#endif // __cpp_lib_three_way_comparison
+}
+
+template <typename LeftFloat, typename RightFloat,
+ if_floating_point<LeftFloat> = true,
+ if_floating_point<RightFloat> = true>
+constexpr Qt::partial_ordering compareThreeWay(LeftFloat lhs, RightFloat rhs) noexcept
+{
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_FLOAT_COMPARE
+#ifdef __cpp_lib_three_way_comparison
+ return lhs <=> rhs;
+#else
+ if (lhs < rhs)
+ return Qt::partial_ordering::less;
+ else if (lhs > rhs)
+ return Qt::partial_ordering::greater;
+ else if (lhs == rhs)
+ return Qt::partial_ordering::equivalent;
+ else
+ return Qt::partial_ordering::unordered;
+#endif // __cpp_lib_three_way_comparison
+QT_WARNING_POP
+}
+
+template <typename IntType, typename FloatType,
+ if_integral<IntType> = true,
+ if_floating_point<FloatType> = true>
+constexpr Qt::partial_ordering compareThreeWay(IntType lhs, FloatType rhs) noexcept
+{
+ return compareThreeWay(FloatType(lhs), rhs);
+}
+
+template <typename FloatType, typename IntType,
+ if_floating_point<FloatType> = true,
+ if_integral<IntType> = true>
+constexpr Qt::partial_ordering compareThreeWay(FloatType lhs, IntType rhs) noexcept
+{
+ return compareThreeWay(lhs, FloatType(rhs));
+}
+
+template <typename LeftType, typename RightType,
+ if_compatible_pointers<LeftType, RightType> = true>
+constexpr Qt::strong_ordering compareThreeWay(const LeftType *lhs, const RightType *rhs) noexcept
+{
+#ifdef __cpp_lib_three_way_comparison
+ return std::compare_three_way{}(lhs, rhs);
+#else
+ if (lhs == rhs)
+ return Qt::strong_ordering::equivalent;
+ else if (std::less<>{}(lhs, rhs))
+ return Qt::strong_ordering::less;
+ else
+ return Qt::strong_ordering::greater;
+#endif // __cpp_lib_three_way_comparison
+}
+
+template <typename T>
+constexpr Qt::strong_ordering compareThreeWay(const T *lhs, std::nullptr_t rhs) noexcept
+{
+ return compareThreeWay(lhs, static_cast<const T *>(rhs));
+}
+
+template <typename T>
+constexpr Qt::strong_ordering compareThreeWay(std::nullptr_t lhs, const T *rhs) noexcept
+{
+ return compareThreeWay(static_cast<const T *>(lhs), rhs);
+}
+
+template <class Enum, if_enum<Enum> = true>
+constexpr Qt::strong_ordering compareThreeWay(Enum lhs, Enum rhs) noexcept
+{
+ return compareThreeWay(qToUnderlying(lhs), qToUnderlying(rhs));
+}
+
+} // namespace Qt
+
+QT_END_NAMESPACE
+
+#endif // QCOMPAREHELPERS_H
diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h
index 5baa69270e..b2340bff8e 100644
--- a/src/corelib/global/qcompilerdetection.h
+++ b/src/corelib/global/qcompilerdetection.h
@@ -2,10 +2,6 @@
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QGLOBAL_H
-# include <QtCore/qglobal.h>
-#endif
-
#if 0
#pragma qt_class(QtCompilerDetection)
#pragma qt_sync_skip_header_check
@@ -16,6 +12,8 @@
#define QCOMPILERDETECTION_H
#include <QtCore/qprocessordetection.h>
+#include <QtCore/qsystemdetection.h>
+#include <QtCore/qtconfiginclude.h>
/*
The compiler, must be one of: (Q_CC_x)
@@ -77,8 +75,10 @@
# define Q_UNREACHABLE_IMPL() __assume(0)
# define Q_DECL_EXPORT __declspec(dllexport)
# define Q_DECL_IMPORT __declspec(dllimport)
-# define QT_MAKE_UNCHECKED_ARRAY_ITERATOR(x) stdext::make_unchecked_array_iterator(x) // Since _MSC_VER >= 1800
-# define QT_MAKE_CHECKED_ARRAY_ITERATOR(x, N) stdext::make_checked_array_iterator(x, size_t(N)) // Since _MSC_VER >= 1500
+# if _MSC_VER < 1938 // stdext is deprecated since VS 2022 17.8
+# define QT_MAKE_CHECKED_ARRAY_ITERATOR(x, N) stdext::make_checked_array_iterator(x, size_t(N)) // Since _MSC_VER >= 1500
+# endif
+# define Q_COMPILER_COMPLAINS_ABOUT_RETURN_AFTER_UNREACHABLE
#elif defined(__BORLANDC__) || defined(__TURBOC__)
# define Q_CC_BOR
@@ -122,7 +122,11 @@
// define to verify the Clang version we hard-code the versions
// based on the best available info we have about the actual
// version: http://en.wikipedia.org/wiki/Xcode#Toolchain_Versions
-# if __apple_build_version__ >= 13160021 // Xcode 13.3
+# if __apple_build_version__ >= 14030022 // Xcode 14.3
+# define Q_CC_CLANG 1500
+# elif __apple_build_version__ >= 14000029 // Xcode 14.0
+# define Q_CC_CLANG 1400
+# elif __apple_build_version__ >= 13160021 // Xcode 13.3
# define Q_CC_CLANG 1300
# elif __apple_build_version__ >= 13000029 // Xcode 13.0
# define Q_CC_CLANG 1200
@@ -846,6 +850,15 @@
# if _MSC_VER >= 1910
# define Q_COMPILER_CONSTEXPR
# endif
+// MSVC versions before 19.36 have a bug in C++20 comparison implementation.
+// This leads to ambiguities when resolving comparison operator overloads in
+// certain scenarios (the buggy MSVC versions were checked using our CI and
+// compiler explorer).
+# if _MSC_VER < 1936
+# define Q_COMPILER_LACKS_THREE_WAY_COMPARE_SYMMETRY
+# endif
+// QTBUG-124376: MSVC is slow at compiling qstrnlen()
+# define Q_COMPILER_SLOW_QSTRNLEN_COMPILATION
# endif /* __cplusplus */
#endif // defined(Q_CC_MSVC) && !defined(Q_CC_CLANG)
@@ -891,16 +904,22 @@
# endif // !_HAS_CONSTEXPR
# endif // !__GLIBCXX__ && !_LIBCPP_VERSION
# endif // Q_OS_QNX
-# if defined(Q_CC_CLANG) && defined(Q_OS_DARWIN) && defined(__GNUC_LIBSTD__) \
- && ((__GNUC_LIBSTD__-0) * 100 + __GNUC_LIBSTD_MINOR__-0 <= 402)
+# if defined(Q_CC_CLANG) && defined(Q_OS_DARWIN)
+# if defined(__GNUC_LIBSTD__) && ((__GNUC_LIBSTD__-0) * 100 + __GNUC_LIBSTD_MINOR__-0 <= 402)
// Apple has not updated libstdc++ since 2007, which means it does not have
// <initializer_list> or std::move. Let's disable these features
-# undef Q_COMPILER_INITIALIZER_LISTS
-# undef Q_COMPILER_RVALUE_REFS
-# undef Q_COMPILER_REF_QUALIFIERS
+# undef Q_COMPILER_INITIALIZER_LISTS
+# undef Q_COMPILER_RVALUE_REFS
+# undef Q_COMPILER_REF_QUALIFIERS
// Also disable <atomic>, since it's clearly not there
-# undef Q_COMPILER_ATOMICS
-# endif
+# undef Q_COMPILER_ATOMICS
+# endif
+# if defined(__cpp_lib_memory_resource) \
+ && ((defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 140000) \
+ || (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 170000))
+# undef __cpp_lib_memory_resource // Only supported on macOS 14 and iOS 17
+# endif
+# endif // defined(Q_CC_CLANG) && defined(Q_OS_DARWIN)
#endif
// Don't break code that is already using Q_COMPILER_DEFAULT_DELETE_MEMBERS
@@ -946,6 +965,20 @@
# define Q_REQUIRED_RESULT [[nodiscard]]
#endif
+#if __has_cpp_attribute(nodiscard) >= 201907L /* used for both P1771 and P1301... */
+// [[nodiscard]] constructor (P1771)
+# ifndef Q_NODISCARD_CTOR
+# define Q_NODISCARD_CTOR [[nodiscard]]
+# endif
+// [[nodiscard("reason")]] (P1301)
+# ifndef Q_NODISCARD_X
+# define Q_NODISCARD_X(message) [[nodiscard(message)]]
+# endif
+# ifndef Q_NODISCARD_CTOR_X
+# define Q_NODISCARD_CTOR_X(message) [[nodiscard(message)]]
+# endif
+#endif
+
#if __has_cpp_attribute(maybe_unused)
# undef Q_DECL_UNUSED
# define Q_DECL_UNUSED [[maybe_unused]]
@@ -995,6 +1028,15 @@
#ifndef Q_REQUIRED_RESULT
# define Q_REQUIRED_RESULT
#endif
+#ifndef Q_NODISCARD_X
+# define Q_NODISCARD_X(message) Q_REQUIRED_RESULT
+#endif
+#ifndef Q_NODISCARD_CTOR
+# define Q_NODISCARD_CTOR
+#endif
+#ifndef Q_NODISCARD_CTOR_X
+# define Q_NODISCARD_CTOR_X(message) Q_NODISCARD_CTOR
+#endif
#ifndef Q_DECL_DEPRECATED
# define Q_DECL_DEPRECATED
#endif
@@ -1181,11 +1223,11 @@
#endif
#endif
#ifndef Q_FALLTHROUGH
-# if defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 700
+# ifdef Q_CC_GNU
# define Q_FALLTHROUGH() __attribute__((fallthrough))
# else
# define Q_FALLTHROUGH() (void)0
-#endif
+# endif
#endif
@@ -1358,8 +1400,17 @@ QT_WARNING_DISABLE_MSVC(4530) /* C++ exception handler used, but unwind semantic
# endif
#endif
-#if __cplusplus >= 202002L // P0846 doesn't have a feature macro :/
+// libstdc++ shipped with gcc < 11 does not have a fix for defect LWG 3346
+#if __cplusplus >= 202002L && (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE >= 11)
+# define QT_COMPILER_HAS_LWG3346
+#endif
+
+#if defined(__cplusplus) && __cplusplus >= 202002L // P0846 doesn't have a feature macro :/
+# if !defined(Q_CC_MSVC_ONLY) || Q_CC_MSVC < 1939 // claims C++20 support but lacks P0846
+ // 1939 is known to work
+ // 1936 is known to fail
# define QT_COMPILER_HAS_P0846
+# endif
#endif
#ifdef QT_COMPILER_HAS_P0846
diff --git a/src/corelib/global/qcompilerdetection.qdoc b/src/corelib/global/qcompilerdetection.qdoc
index cb9108e76c..191f26cc1f 100644
--- a/src/corelib/global/qcompilerdetection.qdoc
+++ b/src/corelib/global/qcompilerdetection.qdoc
@@ -197,7 +197,7 @@
\snippet code/src_corelib_global_qglobal.cpp qlikely
- \sa Q_UNLIKELY(), Q_ASSUME()
+ \sa Q_UNLIKELY()
*/
/*!
@@ -392,3 +392,36 @@
If this macro is used outside a function, the behavior is undefined.
*/
+
+/*!
+ \macro Q_NODISCARD_CTOR
+ \relates <QtCompilerDetection>
+ \since 6.6
+
+ \brief Expands to \c{[[nodiscard]]} on compilers that accept it on constructors.
+
+ Otherwise it expands to nothing.
+
+ Constructors marked as Q_NODISCARD_CTOR cause a compiler warning if a call
+ site doesn't use the resulting object.
+
+ This macro is exists solely to prevent warnings on compilers that don't
+ implement the feature. If your supported platforms all allow \c{[[nodiscard]]}
+ on constructors, we strongly recommend you use the C++ attribute directly instead
+ of this macro.
+
+ \sa Q_NODISCARD_CTOR_X
+*/
+
+/*!
+ \macro Q_NODISCARD_X(message)
+ \macro Q_NODISCARD_CTOR_X(message)
+ \relates <QtCompilerDetection>
+ \since 6.7
+
+ \brief Expand to \c{[[nodiscard(message)]]} on compilers that support the feature.
+
+ Otherwise they expand to \c {[[nodiscard]]} and Q_NODISCARD_CTOR, respectively.
+
+ \sa Q_NODISCARD_CTOR
+*/
diff --git a/src/corelib/global/qconfig-bootstrapped.h b/src/corelib/global/qconfig-bootstrapped.h
index ace4c51d33..4d80f23786 100644
--- a/src/corelib/global/qconfig-bootstrapped.h
+++ b/src/corelib/global/qconfig-bootstrapped.h
@@ -43,7 +43,6 @@
#define QT_FEATURE_cborstreamreader -1
#define QT_FEATURE_cborstreamwriter 1
#define QT_CRYPTOGRAPHICHASH_ONLY_SHA1
-#define QT_FEATURE_cxx11_random (__has_include(<random>) ? 1 : -1)
#define QT_FEATURE_cxx17_filesystem -1
#define QT_NO_DATASTREAM
#define QT_FEATURE_datestring 1
@@ -83,14 +82,9 @@
#endif
#define QT_FEATURE_shortcut -1
#define QT_FEATURE_slog2 -1
-#ifdef __GLIBC_PREREQ
-# define QT_FEATURE_statx (__GLIBC_PREREQ(2, 28) ? 1 : -1)
-#else
-# define QT_FEATURE_statx -1
-#endif
#define QT_FEATURE_syslog -1
#define QT_NO_SYSTEMLOCALE
-#define QT_FEATURE_temporaryfile 1
+#define QT_FEATURE_temporaryfile -1
#define QT_FEATURE_textdate 1
#undef QT_FEATURE_thread
#define QT_FEATURE_thread -1
@@ -98,6 +92,7 @@
#define QT_FEATURE_topleveldomain -1
#define QT_NO_TRANSLATION
#define QT_FEATURE_translation -1
+#define QT_NO_VARIANT -1
#define QT_NO_COMPRESS
diff --git a/src/corelib/global/qcontainerinfo.h b/src/corelib/global/qcontainerinfo.h
index e27877073f..14468510a5 100644
--- a/src/corelib/global/qcontainerinfo.h
+++ b/src/corelib/global/qcontainerinfo.h
@@ -51,6 +51,11 @@ template<typename C>
inline constexpr bool has_size_v<C, std::void_t<decltype(C().size())>> = true;
template<typename C, typename = void>
+inline constexpr bool has_reserve_v = false;
+template<typename C>
+inline constexpr bool has_reserve_v<C, std::void_t<decltype(C().reserve(0))>> = true;
+
+template<typename C, typename = void>
inline constexpr bool has_clear_v = false;
template<typename C>
inline constexpr bool has_clear_v<C, std::void_t<decltype(C().clear())>> = true;
diff --git a/src/corelib/global/qdarwinhelpers.h b/src/corelib/global/qdarwinhelpers.h
index 2ffc740d58..ad72211663 100644
--- a/src/corelib/global/qdarwinhelpers.h
+++ b/src/corelib/global/qdarwinhelpers.h
@@ -27,10 +27,10 @@
# define Q_FORWARD_DECLARE_MUTABLE_CF_TYPE(type) typedef struct __ ## type * type ## Ref
#endif
#ifndef Q_FORWARD_DECLARE_CG_TYPE
-#define Q_FORWARD_DECLARE_CG_TYPE(type) typedef const struct type *type ## Ref;
+# define Q_FORWARD_DECLARE_CG_TYPE(type) typedef const struct type *type##Ref
#endif
#ifndef Q_FORWARD_DECLARE_MUTABLE_CG_TYPE
-#define Q_FORWARD_DECLARE_MUTABLE_CG_TYPE(type) typedef struct type *type ## Ref;
+# define Q_FORWARD_DECLARE_MUTABLE_CG_TYPE(type) typedef struct type *type##Ref
#endif
diff --git a/src/corelib/global/qendian.cpp b/src/corelib/global/qendian.cpp
index 2fa7404507..5e46109dd1 100644
--- a/src/corelib/global/qendian.cpp
+++ b/src/corelib/global/qendian.cpp
@@ -445,8 +445,8 @@ QT_BEGIN_NAMESPACE
The template parameter \c T must be a C++ integer type:
\list
\li 8-bit: char, signed char, unsigned char, qint8, quint8
- \li 16-bit: short, unsigned short, qint16, quint16, char16_t (C++11)
- \li 32-bit: int, unsigned int, qint32, quint32, char32_t (C++11)
+ \li 16-bit: short, unsigned short, qint16, quint16, char16_t
+ \li 32-bit: int, unsigned int, qint32, quint32, char32_t
\li 64-bit: long long, unsigned long long, qint64, quint64
\li platform-specific size: long, unsigned long
\li pointer size: qintptr, quintptr, qptrdiff
diff --git a/src/corelib/global/qendian.h b/src/corelib/global/qendian.h
index 9cd0044cbc..8c3b5e4374 100644
--- a/src/corelib/global/qendian.h
+++ b/src/corelib/global/qendian.h
@@ -105,6 +105,23 @@ inline constexpr T qbswap(T source)
return T(qbswap_helper(typename QIntegerForSizeof<T>::Unsigned(source)));
}
+#ifdef QT_SUPPORTS_INT128
+// extra definitions for q(u)int128, in case std::is_integral_v<~~> == false
+inline constexpr quint128 qbswap(quint128 source)
+{
+ quint128 result = {};
+ result = qbswap_helper(quint64(source));
+ result <<= 64;
+ result |= qbswap_helper(quint64(source >> 64));
+ return result;
+}
+
+inline constexpr qint128 qbswap(qint128 source)
+{
+ return qint128(qbswap(quint128(source)));
+}
+#endif
+
// floating specializations
template<typename Float>
Float qbswapFloatHelper(Float source)
diff --git a/src/corelib/global/qexceptionhandling.h b/src/corelib/global/qexceptionhandling.h
index aca8de9003..76c6185c3e 100644
--- a/src/corelib/global/qexceptionhandling.h
+++ b/src/corelib/global/qexceptionhandling.h
@@ -6,6 +6,7 @@
#include <QtCore/qtconfigmacros.h>
#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qtcoreexports.h>
#if 0
#pragma qt_class(QtExceptionHandling)
diff --git a/src/corelib/global/qflags.h b/src/corelib/global/qflags.h
index 26a8e5c9cf..cc028e0095 100644
--- a/src/corelib/global/qflags.h
+++ b/src/corelib/global/qflags.h
@@ -1,12 +1,12 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <QtCore/qglobal.h>
-#include <QtCore/qcompare_impl.h>
-
#ifndef QFLAGS_H
#define QFLAGS_H
+#include <QtCore/qcompare_impl.h>
+#include <QtCore/qtypeinfo.h>
+
#include <initializer_list>
QT_BEGIN_NAMESPACE
diff --git a/src/corelib/global/qflags.qdoc b/src/corelib/global/qflags.qdoc
index 4542d99268..dd3b1e4c9b 100644
--- a/src/corelib/global/qflags.qdoc
+++ b/src/corelib/global/qflags.qdoc
@@ -98,7 +98,7 @@
\section1 Flags and the Meta-Object System
The Q_DECLARE_FLAGS() macro does not expose the flags to the meta-object
- system, so they cannot be used by Qt Script or edited in Qt Designer.
+ system, so they cannot be used by Qt Script or edited in \QD.
To make the flags available for these purposes, the Q_FLAG() macro must
be used:
@@ -174,7 +174,7 @@
/*!
\fn template <typename Enum> QFlags &QFlags<Enum>::operator=(const QFlags &other)
- Assigns \e other to this object and returns a reference to this
+ Assigns \a other to this object and returns a reference to this
object.
*/
diff --git a/src/corelib/global/qfloat16.cpp b/src/corelib/global/qfloat16.cpp
index b8e7cbe928..f6f782e364 100644
--- a/src/corelib/global/qfloat16.cpp
+++ b/src/corelib/global/qfloat16.cpp
@@ -23,6 +23,15 @@ QT_IMPL_METATYPE_EXTERN(qfloat16)
\inheaderfile QFloat16
\brief Provides 16-bit floating point support.
+ \compares partial
+ \compareswith partial float double {long double} qint8 quint8 qint16 quint16 \
+ qint32 quint32 long {unsigned long} qint64 quint64
+ \endcompareswith
+ \compareswith partial qint128 quint128
+ Comparison with 128-bit integral types is only supported if Qt provides
+ these types.
+ \endcompareswith
+
The \c qfloat16 class provides support for half-precision (16-bit) floating
point data. It is fully compliant with IEEE 754 as a storage type. This
implies that any arithmetic operation on a \c qfloat16 instance results in
@@ -363,6 +372,19 @@ Q_CORE_EXPORT void qFloatFromFloat16(float *out, const qfloat16 *in, qsizetype l
out[i] = float(in[i]);
}
+/*!
+ \fn size_t qfloat16::qHash(qfloat16 key, size_t seed)
+ \since 6.5.3
+
+ Returns the hash value for the \a key, using \a seed to seed the
+ calculation.
+
+ \note In Qt versions before 6.5, this operation was provided by the
+ qHash(float) overload. In Qt versions 6.5.0 to 6.5.2, this functionality
+ was broken in various ways. In Qt versions 6.5.3 and 6.6 onwards, this
+ overload restores the Qt 6.4 behavior.
+*/
+
#ifndef QT_NO_DATASTREAM
/*!
\fn qfloat16::operator<<(QDataStream &ds, qfloat16 f)
diff --git a/src/corelib/global/qfloat16.h b/src/corelib/global/qfloat16.h
index 76ea990c33..30dd9a60af 100644
--- a/src/corelib/global/qfloat16.h
+++ b/src/corelib/global/qfloat16.h
@@ -5,16 +5,17 @@
#ifndef QFLOAT16_H
#define QFLOAT16_H
+#include <QtCore/qcompare.h>
#include <QtCore/qglobal.h>
+#include <QtCore/qhashfunctions.h>
#include <QtCore/qmath.h>
#include <QtCore/qnamespace.h>
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qtypes.h>
+
#include <limits>
#include <string.h>
-
-#if defined(__STDCPP_FLOAT16_T__) && __has_include(<stdfloat>)
-// P1467 implementation - https://wg21.link/p1467
-# include <stdfloat>
-#endif
+#include <type_traits>
#if defined(QT_COMPILER_SUPPORTS_F16C) && defined(__AVX2__) && !defined(__F16C__)
// All processors that support AVX2 do support F16C too, so we could enable the
@@ -52,25 +53,22 @@ class qfloat16
constexpr inline explicit Wrap(int value) : b16(quint16(value)) {}
};
-public:
-#if defined(__STDCPP_FLOAT16_T__)
-# define QFLOAT16_IS_NATIVE 1
- using NativeType = std::float16_t;
-#elif defined(Q_CC_CLANG) && defined(__FLT16_MAX__) && 0
- // disabled due to https://github.com/llvm/llvm-project/issues/56963
-# define QFLOAT16_IS_NATIVE 1
- using NativeType = decltype(__FLT16_MAX__);
-#elif defined(Q_CC_GNU_ONLY) && defined(__FLT16_MAX__)
-# define QFLOAT16_IS_NATIVE 1
-# ifdef __ARM_FP16_FORMAT_IEEE
- using NativeType = __fp16;
-# else
- using NativeType = _Float16;
-# endif
+#ifdef QT_SUPPORTS_INT128
+ template <typename T>
+ using IsIntegral = std::disjunction<std::is_integral<T>,
+ std::is_same<std::remove_const_t<T>, qint128>,
+ std::is_same<std::remove_const_t<T>, quint128>>;
#else
-# define QFLOAT16_IS_NATIVE 0
- using NativeType = void;
+ template <typename T>
+ using IsIntegral = std::is_integral<T>;
#endif
+ template <typename T>
+ using if_type_is_integral = std::enable_if_t<IsIntegral<std::remove_reference_t<T>>::value,
+ bool>;
+
+public:
+ using NativeType = QtPrivate::NativeFloat16Type;
+
static constexpr bool IsNative = QFLOAT16_IS_NATIVE;
using NearestFloat = std::conditional_t<IsNative, NativeType, float>;
@@ -96,6 +94,22 @@ public:
qfloat16 copySign(qfloat16 sign) const noexcept
{ return qfloat16(Wrap((sign.b16 & 0x8000) | (b16 & 0x7fff))); }
// Support for std::numeric_limits<qfloat16>
+
+#ifdef __STDCPP_FLOAT16_T__
+private:
+ using Bounds = std::numeric_limits<NativeType>;
+public:
+ static constexpr qfloat16 _limit_epsilon() noexcept { return Bounds::epsilon(); }
+ static constexpr qfloat16 _limit_min() noexcept { return Bounds::min(); }
+ static constexpr qfloat16 _limit_denorm_min() noexcept { return Bounds::denorm_min(); }
+ static constexpr qfloat16 _limit_max() noexcept { return Bounds::max(); }
+ static constexpr qfloat16 _limit_lowest() noexcept { return Bounds::lowest(); }
+ static constexpr qfloat16 _limit_infinity() noexcept { return Bounds::infinity(); }
+ static constexpr qfloat16 _limit_quiet_NaN() noexcept { return Bounds::quiet_NaN(); }
+#if QT_CONFIG(signaling_nan)
+ static constexpr qfloat16 _limit_signaling_NaN() noexcept { return Bounds::signaling_NaN(); }
+#endif
+#else
static constexpr qfloat16 _limit_epsilon() noexcept { return qfloat16(Wrap(0x1400)); }
static constexpr qfloat16 _limit_min() noexcept { return qfloat16(Wrap(0x400)); }
static constexpr qfloat16 _limit_denorm_min() noexcept { return qfloat16(Wrap(1)); }
@@ -106,6 +120,7 @@ public:
#if QT_CONFIG(signaling_nan)
static constexpr qfloat16 _limit_signaling_NaN() noexcept { return qfloat16(Wrap(0x7d00)); }
#endif
+#endif
inline constexpr bool isNormal() const noexcept
{ return (b16 & 0x7c00) && (b16 & 0x7c00) != 0x7c00; }
private:
@@ -121,7 +136,13 @@ private:
NativeType nf;
#endif
};
- constexpr inline explicit qfloat16(Wrap nibble) noexcept : b16(nibble.b16) {}
+ constexpr inline explicit qfloat16(Wrap nibble) noexcept :
+#if QFLOAT16_IS_NATIVE && defined(__cpp_lib_bit_cast)
+ nf(std::bit_cast<NativeType>(nibble.b16))
+#else
+ b16(nibble.b16)
+#endif
+ {}
Q_CORE_EXPORT static const quint32 mantissatable[];
Q_CORE_EXPORT static const quint32 exponenttable[];
@@ -144,6 +165,12 @@ private:
friend inline qfloat16 operator*(qfloat16 a, qfloat16 b) noexcept { return qfloat16(static_cast<NearestFloat>(a) * static_cast<NearestFloat>(b)); }
friend inline qfloat16 operator/(qfloat16 a, qfloat16 b) noexcept { return qfloat16(static_cast<NearestFloat>(a) / static_cast<NearestFloat>(b)); }
+ friend size_t qHash(qfloat16 key, size_t seed = 0) noexcept
+ { return qHash(float(key), seed); } // 6.4 algorithm, so keep using it; ### Qt 7: fix QTBUG-116077
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Wfloat-conversion")
+
#define QF16_MAKE_ARITH_OP_FP(FP, OP) \
friend inline FP operator OP(qfloat16 lhs, FP rhs) noexcept { return static_cast<FP>(lhs) OP rhs; } \
friend inline FP operator OP(FP lhs, qfloat16 rhs) noexcept { return lhs OP static_cast<FP>(rhs); }
@@ -179,44 +206,63 @@ private:
QF16_MAKE_ARITH_OP_INT(/)
#undef QF16_MAKE_ARITH_OP_INT
-QT_WARNING_PUSH
QT_WARNING_DISABLE_FLOAT_COMPARE
- friend inline bool operator>(qfloat16 a, qfloat16 b) noexcept { return static_cast<NearestFloat>(a) > static_cast<NearestFloat>(b); }
- friend inline bool operator<(qfloat16 a, qfloat16 b) noexcept { return static_cast<NearestFloat>(a) < static_cast<NearestFloat>(b); }
- friend inline bool operator>=(qfloat16 a, qfloat16 b) noexcept { return static_cast<NearestFloat>(a) >= static_cast<NearestFloat>(b); }
- friend inline bool operator<=(qfloat16 a, qfloat16 b) noexcept { return static_cast<NearestFloat>(a) <= static_cast<NearestFloat>(b); }
- friend inline bool operator==(qfloat16 a, qfloat16 b) noexcept { return static_cast<NearestFloat>(a) == static_cast<NearestFloat>(b); }
- friend inline bool operator!=(qfloat16 a, qfloat16 b) noexcept { return static_cast<NearestFloat>(a) != static_cast<NearestFloat>(b); }
-
-#define QF16_MAKE_BOOL_OP_FP(FP, OP) \
- friend inline bool operator OP(qfloat16 lhs, FP rhs) noexcept { return static_cast<FP>(lhs) OP rhs; } \
- friend inline bool operator OP(FP lhs, qfloat16 rhs) noexcept { 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) \
- friend inline bool operator OP(qfloat16 a, int b) noexcept { return static_cast<NearestFloat>(a) OP static_cast<NearestFloat>(b); } \
- friend inline bool operator OP(int a, qfloat16 b) noexcept { return static_cast<NearestFloat>(a) OP static_cast<NearestFloat>(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
+#if QFLOAT16_IS_NATIVE
+# define QF16_CONSTEXPR constexpr
+# define QF16_PARTIALLY_ORDERED Q_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE
+#else
+# define QF16_CONSTEXPR
+# define QF16_PARTIALLY_ORDERED Q_DECLARE_PARTIALLY_ORDERED
+#endif
+
+ friend QF16_CONSTEXPR bool comparesEqual(const qfloat16 &lhs, const qfloat16 &rhs) noexcept
+ { return static_cast<NearestFloat>(lhs) == static_cast<NearestFloat>(rhs); }
+ friend QF16_CONSTEXPR
+ Qt::partial_ordering compareThreeWay(const qfloat16 &lhs, const qfloat16 &rhs) noexcept
+ { return Qt::compareThreeWay(static_cast<NearestFloat>(lhs), static_cast<NearestFloat>(rhs)); }
+ QF16_PARTIALLY_ORDERED(qfloat16)
+
+#define QF16_MAKE_ORDER_OP_FP(FP) \
+ friend QF16_CONSTEXPR bool comparesEqual(const qfloat16 &lhs, FP rhs) noexcept \
+ { return static_cast<FP>(lhs) == rhs; } \
+ friend QF16_CONSTEXPR \
+ Qt::partial_ordering compareThreeWay(const qfloat16 &lhs, FP rhs) noexcept \
+ { return Qt::compareThreeWay(static_cast<FP>(lhs), rhs); } \
+ QF16_PARTIALLY_ORDERED(qfloat16, FP)
+
+ QF16_MAKE_ORDER_OP_FP(long double)
+ QF16_MAKE_ORDER_OP_FP(double)
+ QF16_MAKE_ORDER_OP_FP(float)
+#if QFLOAT16_IS_NATIVE
+ QF16_MAKE_ORDER_OP_FP(qfloat16::NativeType)
+#endif
+#undef QF16_MAKE_ORDER_OP_FP
+
+ template <typename T, if_type_is_integral<T> = true>
+ friend QF16_CONSTEXPR bool comparesEqual(const qfloat16 &lhs, T rhs) noexcept
+ { return static_cast<NearestFloat>(lhs) == static_cast<NearestFloat>(rhs); }
+ template <typename T, if_type_is_integral<T> = true>
+ friend QF16_CONSTEXPR Qt::partial_ordering compareThreeWay(const qfloat16 &lhs, T rhs) noexcept
+ { return Qt::compareThreeWay(static_cast<NearestFloat>(lhs), static_cast<NearestFloat>(rhs)); }
+
+ QF16_PARTIALLY_ORDERED(qfloat16, qint8)
+ QF16_PARTIALLY_ORDERED(qfloat16, quint8)
+ QF16_PARTIALLY_ORDERED(qfloat16, qint16)
+ QF16_PARTIALLY_ORDERED(qfloat16, quint16)
+ QF16_PARTIALLY_ORDERED(qfloat16, qint32)
+ QF16_PARTIALLY_ORDERED(qfloat16, quint32)
+ QF16_PARTIALLY_ORDERED(qfloat16, long)
+ QF16_PARTIALLY_ORDERED(qfloat16, unsigned long)
+ QF16_PARTIALLY_ORDERED(qfloat16, qint64)
+ QF16_PARTIALLY_ORDERED(qfloat16, quint64)
+#ifdef QT_SUPPORTS_INT128
+ QF16_PARTIALLY_ORDERED(qfloat16, qint128)
+ QF16_PARTIALLY_ORDERED(qfloat16, quint128)
+#endif
+
+#undef QF16_PARTIALLY_ORDERED
+#undef QF16_CONSTEXPR
QT_WARNING_POP
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index cddf446392..222c008f8a 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -12,15 +12,6 @@
#include "qnativeinterface.h"
#include "qnativeinterface_p.h"
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-
-#include <errno.h>
-#if defined(Q_CC_MSVC)
-# include <crtdbg.h>
-#endif
-
#ifdef Q_OS_WIN
# include <qt_windows.h>
#endif
@@ -42,12 +33,6 @@ extern "C" {
}
#endif
-#ifdef qFatal
-// the qFatal in this file are just redirections from elsewhere, so
-// don't capture any context again
-# undef qFatal
-#endif
-
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
@@ -107,8 +92,8 @@ using namespace Qt::StringLiterals;
/*
Dijkstra's bisection algorithm to find the square root of an integer.
- Deliberately not exported as part of the Qt API, but used in both
- qsimplerichtext.cpp and qgfxraster_qws.cpp
+ Deliberately not exported as part of the Qt API, but used in
+ qtextdocument.cpp.
*/
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION unsigned int qt_int_sqrt(unsigned int n)
{
@@ -133,35 +118,6 @@ Q_CORE_EXPORT Q_DECL_CONST_FUNCTION unsigned int qt_int_sqrt(unsigned int n)
return p;
}
-void qAbort()
-{
-#ifdef Q_OS_WIN
- // std::abort() in the MSVC runtime will call _exit(3) if the abort
- // behavior is _WRITE_ABORT_MSG - see also _set_abort_behavior(). This is
- // the default for a debug-mode build of the runtime. Worse, MinGW's
- // std::abort() implementation (in msvcrt.dll) is basically a call to
- // _exit(3) too. Unfortunately, _exit() and _Exit() *do* run the static
- // destructors of objects in DLLs, a violation of the C++ standard (see
- // [support.start.term]). So we bypass std::abort() and directly
- // terminate the application.
-
-# if defined(Q_CC_MSVC)
- if (IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE))
- __fastfail(FAST_FAIL_FATAL_APP_EXIT);
-# else
- RaiseFailFastException(nullptr, nullptr, 0);
-# endif
-
- // Fallback
- TerminateProcess(GetCurrentProcess(), STATUS_FATAL_APP_EXIT);
-
- // Tell the compiler the application has stopped.
- Q_UNREACHABLE_IMPL();
-#else // !Q_OS_WIN
- std::abort();
-#endif
-}
-
// Also specified to behave as if they call tzset():
// localtime() -- but not localtime_r(), which we use when threaded
// strftime() -- not used (except in tests)
@@ -355,33 +311,49 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters)
*/
/*!
- \macro QT_TERMINATE_ON_EXCEPTION(expr)
+ \macro QT_ENABLE_STRICT_MODE_UP_TO
\relates <QtGlobal>
- \internal
+ \since 6.8
+
+ Defining this macro will disable a number of Qt APIs that are
+ deemed suboptimal or dangerous.
+
+ This macro's value must be set to a Qt version, using
+ \l{QT_VERSION_CHECK}'s encoding. For instance, in order to set it
+ to Qt 6.6, define \c{QT_ENABLE_STRICT_MODE_UP_TO=0x060600}.
+ This will disable only the APIs introduced in versions up to (and
+ including) the specified Qt version.
+
+ If the \l QT_DISABLE_DEPRECATED_UP_TO macro is \e not defined,
+ then QT_ENABLE_STRICT_MODE_UP_TO will define it as well,
+ to the same value.
+
+ This macro should always be set to the minimum Qt version that
+ your project wants to support.
+
+ The APIs disabled by this macro are listed in the table below,
+ together with the minimum value to use in order to disable them.
+
+ \table
+ \header \li Version \li Disabled APIs
+ \row \li 6.0.0 \li \l{foreach-keyword}{foreach} (see \l{QT_NO_FOREACH})
+ \row \li 6.0.0 \li QString constructors from \c{const char *} (see \l{QT_NO_CAST_FROM_ASCII})
+ \row \li 6.0.0 \li QString conversions towards \c{const char *} / QByteArray (see \l{QT_NO_CAST_TO_ASCII})
+ \row \li 6.0.0 \li QByteArray implicit conversions towards \c{const char *} (see \l{QT_NO_CAST_FROM_BYTEARRAY})
+ \row \li 6.0.0 \li QUrl implicit conversions from QString (see \l{QT_NO_URL_CAST_FROM_STRING})
+ \row \li 6.0.0 \li Allowing narrowing conversions in signal-slot connections (see \l{QT_NO_NARROWING_CONVERSIONS_IN_CONNECT})
+ \row \li 6.0.0 \li Java-style iterators for Qt containers
+ \row \li 6.6.0 \li The qExchange() function (see \l{QT_NO_QEXCHANGE})
+ \row \li 6.7.0 \li Overloads of QObject::connect that do not take a context object (see \l{QT_NO_CONTEXTLESS_CONNECT})
+ \row \li 6.8.0 \li The qAsConst() function (see \l{QT_NO_QASCONST})
+ \row \li 6.8.0 \li File-related I/O classes have their \c{open()} functions marked \c{[[nodiscard]]} (see \l{QT_USE_NODISCARD_FILE_OPEN})
+ \endtable
+
+ Moreover, individual APIs may also get disabled as part of the
+ setting of QT_DISABLE_DEPRECATED_UP_TO. Please refer to each class'
+ documentation for more details.
- In general, use of the Q_DECL_NOEXCEPT macro is preferred over
- Q_DECL_NOTHROW, because it exhibits well-defined behavior and
- supports the more powerful Q_DECL_NOEXCEPT_EXPR variant. However,
- use of Q_DECL_NOTHROW has the advantage that Windows builds
- benefit on a wide range or compiler versions that do not yet
- support the C++11 noexcept feature.
-
- It may therefore be beneficial to use Q_DECL_NOTHROW and emulate
- the C++11 behavior manually with an embedded try/catch.
-
- Qt provides the QT_TERMINATE_ON_EXCEPTION(expr) macro for this
- purpose. It either expands to \c expr (if Qt is compiled without
- exception support or the compiler supports C++11 noexcept
- semantics) or to
- \snippet code/src_corelib_global_qglobal.cpp qterminate
- otherwise.
-
- Since this macro expands to just \c expr if the compiler supports
- C++11 noexcept, expecting the compiler to take over responsibility
- of calling std::terminate() in that case, it should not be used
- outside Q_DECL_NOTHROW functions.
-
- \sa Q_DECL_NOEXCEPT, Q_DECL_NOTHROW, qTerminate()
+ \sa QT_DISABLE_DEPRECATED_UP_TO, QT_NO_KEYWORDS, QT_VERSION_CHECK
*/
namespace QtPrivate {
diff --git a/src/corelib/global/qglobal_p.h b/src/corelib/global/qglobal_p.h
index 8b1a6ba149..31f67510e3 100644
--- a/src/corelib/global/qglobal_p.h
+++ b/src/corelib/global/qglobal_p.h
@@ -54,10 +54,7 @@
#if defined(__cplusplus)
QT_BEGIN_NAMESPACE
-#if !defined(Q_CC_MSVC) || defined(Q_CC_CLANG)
-Q_NORETURN
-#endif
-Q_CORE_EXPORT void qAbort();
+Q_NORETURN Q_CORE_EXPORT void qAbort();
QT_END_NAMESPACE
diff --git a/src/corelib/global/qglobalstatic.h b/src/corelib/global/qglobalstatic.h
index d865e08fdd..93127adab3 100644
--- a/src/corelib/global/qglobalstatic.h
+++ b/src/corelib/global/qglobalstatic.h
@@ -1,12 +1,12 @@
// Copyright (C) 2021 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <QtCore/qglobal.h>
-
#ifndef QGLOBALSTATIC_H
#define QGLOBALSTATIC_H
+#include <QtCore/qassert.h>
#include <QtCore/qatomic.h>
+#include <QtCore/qtclasshelpermacros.h>
#include <atomic> // for bootstrapped (no thread) builds
#include <type_traits>
@@ -40,9 +40,18 @@ template <typename QGS> union Holder
~Holder()
{
+ // TSAN does not support atomic_thread_fence and GCC complains:
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97868
+ // https://github.com/google/sanitizers/issues/1352
+QT_WARNING_PUSH
+#if defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 1100
+QT_WARNING_DISABLE_GCC("-Wtsan")
+#endif
+ // import changes to *pointer() by other threads before running ~PlainType():
+ std::atomic_thread_fence(std::memory_order_acquire);
+QT_WARNING_POP
pointer()->~PlainType();
- std::atomic_thread_fence(std::memory_order_acquire); // avoid mixing stores to guard and *pointer()
- guard.storeRelaxed(QtGlobalStatic::Destroyed);
+ guard.storeRelease(QtGlobalStatic::Destroyed);
}
PlainType *pointer() noexcept
@@ -74,13 +83,13 @@ template <typename Holder> struct QGlobalStatic
}
Type *operator->()
{
- Q_ASSERT_X(!isDestroyed(), "Q_GLOBAL_STATIC",
+ Q_ASSERT_X(!isDestroyed(), Q_FUNC_INFO,
"The global static was used after being destroyed");
return instance();
}
Type &operator*()
{
- Q_ASSERT_X(!isDestroyed(), "Q_GLOBAL_STATIC",
+ Q_ASSERT_X(!isDestroyed(), Q_FUNC_INFO,
"The global static was used after being destroyed");
return *instance();
}
diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp
index 68db820f01..1b03733d2a 100644
--- a/src/corelib/global/qlibraryinfo.cpp
+++ b/src/corelib/global/qlibraryinfo.cpp
@@ -87,10 +87,19 @@ void QLibrarySettings::load()
}
}
+namespace {
+const QString *qtconfManualPath = nullptr;
+}
+
+void QLibraryInfoPrivate::setQtconfManualPath(const QString *path)
+{
+ qtconfManualPath = path;
+}
+
static QSettings *findConfiguration()
{
- if (QLibraryInfoPrivate::qtconfManualPath)
- return new QSettings(*QLibraryInfoPrivate::qtconfManualPath, QSettings::IniFormat);
+ if (qtconfManualPath)
+ return new QSettings(*qtconfManualPath, QSettings::IniFormat);
QString qtconfig = QStringLiteral(":/qt/etc/qt.conf");
if (QFile::exists(qtconfig))
@@ -122,8 +131,6 @@ static QSettings *findConfiguration()
return nullptr; //no luck
}
-const QString *QLibraryInfoPrivate::qtconfManualPath = nullptr;
-
QSettings *QLibraryInfoPrivate::configuration()
{
QLibrarySettings *ls = qt_library_settings();
@@ -365,6 +372,11 @@ static QString getRelocatablePrefix(QLibraryInfoPrivate::UsageMode usageMode)
const QString prefixDir = QString(libDirCFString) + "/" QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH;
prefixPath = QDir::cleanPath(prefixDir);
+#elif defined(Q_OS_WASM)
+ // Emscripten expects to find shared libraries at the root of the in-memory
+ // file system when resolving dependencies for for dlopen() calls. So that's
+ // where libqt6core.so would be.
+ prefixPath = QStringLiteral("/");
#elif QT_CONFIG(dlopen)
Q_UNUSED(usageMode);
Dl_info info;
@@ -475,9 +487,8 @@ QLibraryInfoPrivate::LocationInfo QLibraryInfoPrivate::locationInfo(QLibraryInfo
"Examples", "examples",
"Tests", "tests"
);
- static constexpr QByteArrayView dot = qtConfEntries.viewAt(1);
- static_assert(dot.size() == 1);
- static_assert(dot[0] == '.');
+ [[maybe_unused]]
+ constexpr QByteArrayView dot{"."};
LocationInfo result;
@@ -543,6 +554,10 @@ QString QLibraryInfoPrivate::path(QLibraryInfo::LibraryPath p, UsageMode usageMo
}
qsizetype startIndex = 0;
+ /* We support placeholders of the form $(<ENV_VAR>) in qt.conf.
+ The loop below tries to find all such placeholders, and replaces
+ them with the actual value of the ENV_VAR environment variable
+ */
while (true) {
startIndex = ret.indexOf(u'$', startIndex);
if (startIndex < 0)
@@ -745,13 +760,14 @@ extern "C" void qt_core_boilerplate() __attribute__((force_align_arg_pointer));
void qt_core_boilerplate()
{
printf("This is the QtCore library version %s\n"
- "Copyright (C) 2016 The Qt Company Ltd.\n"
- "Contact: http://www.qt.io/licensing/\n"
+ "%s\n"
+ "Contact: https://www.qt.io/licensing/\n"
"\n"
"Installation prefix: %s\n"
"Library path: %s\n"
"Plugin path: %s\n",
QT_PREPEND_NAMESPACE(qt_build_string)(),
+ QT_COPYRIGHT,
QT_CONFIGURE_PREFIX_PATH,
qt_configure_strs[QT_PREPEND_NAMESPACE(QLibraryInfo)::LibrariesPath - 1],
qt_configure_strs[QT_PREPEND_NAMESPACE(QLibraryInfo)::PluginsPath - 1]);
diff --git a/src/corelib/global/qlibraryinfo_p.h b/src/corelib/global/qlibraryinfo_p.h
index d3c458290b..4b471b932e 100644
--- a/src/corelib/global/qlibraryinfo_p.h
+++ b/src/corelib/global/qlibraryinfo_p.h
@@ -32,7 +32,7 @@ public:
#if QT_CONFIG(settings)
static QSettings *configuration();
static void reload();
- static const QString *qtconfManualPath;
+ static void setQtconfManualPath(const QString *qtconfManualPath);
#endif
struct LocationInfo
diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp
index 82e79e5e01..dec16e4a77 100644
--- a/src/corelib/global/qlogging.cpp
+++ b/src/corelib/global/qlogging.cpp
@@ -23,7 +23,6 @@
#include "qthread.h"
#include "private/qloggingregistry_p.h"
#include "private/qcoreapplication_p.h"
-#include "private/qsimd_p.h"
#include <qtcore_tracepoints_p.h>
#endif
#ifdef Q_OS_WIN
@@ -70,17 +69,19 @@
extern char *__progname;
#endif
-#ifndef QT_BOOTSTRAPPED
-#if __has_include(<cxxabi.h>) && QT_CONFIG(backtrace) && QT_CONFIG(regularexpression)
+#ifdef QLOGGING_HAVE_BACKTRACE
# include <qregularexpression.h>
+#endif
+
+#ifdef QLOGGING_USE_EXECINFO_BACKTRACE
# if QT_CONFIG(dladdr)
# include <dlfcn.h>
# endif
# include BACKTRACE_HEADER
# include <cxxabi.h>
-# define QLOGGING_HAVE_BACKTRACE
-#endif
+#endif // QLOGGING_USE_EXECINFO_BACKTRACE
+#ifndef QT_BOOTSTRAPPED
#if defined(Q_OS_LINUX) && (defined(__GLIBC__) || __has_include(<sys/syscall.h>))
# include <sys/syscall.h>
@@ -163,12 +164,15 @@ Q_TRACE_POINT(qtcore, qt_message_print, int type, const char *category, const ch
\snippet code/src_corelib_global_qglobal.cpp 4
*/
-#if !defined(Q_CC_MSVC) || defined(Q_CC_CLANG)
+template <typename String>
+#if !defined(Q_CC_MSVC_ONLY)
Q_NORETURN
#endif
-static void qt_message_fatal(QtMsgType, const QMessageLogContext &context, const QString &message);
+static void qt_message_fatal(QtMsgType, const QMessageLogContext &context, String &&message);
static void qt_message_print(QtMsgType, const QMessageLogContext &context, const QString &message);
-static void qt_message_print(const QString &message);
+static void preformattedMessageHandler(QtMsgType type, const QMessageLogContext &context,
+ const QString &formattedMessage);
+static QString formatLogMessage(QtMsgType type, const QMessageLogContext &context, const QString &str);
static int checked_var_value(const char *varname)
{
@@ -184,6 +188,17 @@ static int checked_var_value(const char *varname)
return ok ? value : 1;
}
+static bool is_fatal_count_down(QAtomicInt &n)
+{
+ // it's fatal if the current value is exactly 1,
+ // otherwise decrement if it's non-zero
+
+ int v = n.loadRelaxed();
+ while (v != 0 && !n.testAndSetRelaxed(v, v - 1, v))
+ qYieldCpu();
+ return v == 1; // we exited the loop, so either v == 0 or CAS succeeded to set n from v to v-1
+}
+
static bool isFatal(QtMsgType msgType)
{
if (msgType == QtFatalMsg)
@@ -191,28 +206,17 @@ static bool isFatal(QtMsgType msgType)
if (msgType == QtCriticalMsg) {
static QAtomicInt fatalCriticals = checked_var_value("QT_FATAL_CRITICALS");
-
- // it's fatal if the current value is exactly 1,
- // otherwise decrement if it's non-zero
- return fatalCriticals.loadRelaxed() && fatalCriticals.fetchAndAddRelaxed(-1) == 1;
+ return is_fatal_count_down(fatalCriticals);
}
if (msgType == QtWarningMsg || msgType == QtCriticalMsg) {
static QAtomicInt fatalWarnings = checked_var_value("QT_FATAL_WARNINGS");
-
- // it's fatal if the current value is exactly 1,
- // otherwise decrement if it's non-zero
- return fatalWarnings.loadRelaxed() && fatalWarnings.fetchAndAddRelaxed(-1) == 1;
+ return is_fatal_count_down(fatalWarnings);
}
return false;
}
-static bool isDefaultCategory(const char *category)
-{
- return !category || strcmp(category, "default") == 0;
-}
-
/*!
Returns true if writing to \c stderr is supported.
@@ -224,6 +228,8 @@ static bool systemHasStderr()
return true;
}
+#ifndef Q_OS_WASM
+
/*!
Returns true if writing to \c stderr will end up in a console/terminal visible to the user.
@@ -308,6 +314,8 @@ bool shouldLogToStderr()
using namespace QtPrivate;
+#endif // ifndef Q_OS_WASM
+
/*!
\class QMessageLogContext
\inmodule QtCore
@@ -342,7 +350,7 @@ using namespace QtPrivate;
\sa QMessageLogContext, qDebug(), qInfo(), qWarning(), qCritical(), qFatal()
*/
-#if defined(Q_CC_MSVC) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
+#if defined(Q_CC_MSVC_ONLY) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
static inline void convert_to_wchar_t_elided(wchar_t *d, size_t space, const char *s) noexcept
{
size_t len = qstrlen(s);
@@ -363,14 +371,15 @@ static inline void convert_to_wchar_t_elided(wchar_t *d, size_t space, const cha
\internal
*/
Q_NEVER_INLINE
-static QString qt_message(QtMsgType msgType, const QMessageLogContext &context, const char *msg, va_list ap)
+static void qt_message(QtMsgType msgType, const QMessageLogContext &context, const char *msg, va_list ap)
{
QString buf = QString::vasprintf(msg, ap);
qt_message_print(msgType, context, buf);
- return buf;
+
+ if (isFatal(msgType))
+ qt_message_fatal(msgType, context, buf);
}
-#undef qDebug
/*!
Logs a debug message specified with format \a msg. Additional
parameters, specified by \a msg, may be used.
@@ -379,17 +388,13 @@ static QString qt_message(QtMsgType msgType, const QMessageLogContext &context,
*/
void QMessageLogger::debug(const char *msg, ...) const
{
+ QInternalMessageLogContext ctxt(context);
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtDebugMsg, context, msg, ap);
+ qt_message(QtDebugMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtDebugMsg))
- qt_message_fatal(QtDebugMsg, context, message);
}
-
-#undef qInfo
/*!
Logs an informational message specified with format \a msg. Additional
parameters, specified by \a msg, may be used.
@@ -399,13 +404,11 @@ void QMessageLogger::debug(const char *msg, ...) const
*/
void QMessageLogger::info(const char *msg, ...) const
{
+ QInternalMessageLogContext ctxt(context);
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtInfoMsg, context, msg, ap);
+ qt_message(QtInfoMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtInfoMsg))
- qt_message_fatal(QtInfoMsg, context, message);
}
/*!
@@ -434,17 +437,12 @@ void QMessageLogger::debug(const QLoggingCategory &cat, const char *msg, ...) co
if (!cat.isDebugEnabled())
return;
- QMessageLogContext ctxt;
- ctxt.copyContextFrom(context);
- ctxt.category = cat.categoryName();
+ QInternalMessageLogContext ctxt(context, cat());
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtDebugMsg, ctxt, msg, ap);
+ qt_message(QtDebugMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtDebugMsg))
- qt_message_fatal(QtDebugMsg, ctxt, message);
}
/*!
@@ -461,17 +459,12 @@ void QMessageLogger::debug(QMessageLogger::CategoryFunction catFunc,
if (!cat.isDebugEnabled())
return;
- QMessageLogContext ctxt;
- ctxt.copyContextFrom(context);
- ctxt.category = cat.categoryName();
+ QInternalMessageLogContext ctxt(context, cat());
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtDebugMsg, ctxt, msg, ap);
+ qt_message(QtDebugMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtDebugMsg))
- qt_message_fatal(QtDebugMsg, ctxt, message);
}
#ifndef QT_NO_DEBUG_STREAM
@@ -545,17 +538,12 @@ void QMessageLogger::info(const QLoggingCategory &cat, const char *msg, ...) con
if (!cat.isInfoEnabled())
return;
- QMessageLogContext ctxt;
- ctxt.copyContextFrom(context);
- ctxt.category = cat.categoryName();
+ QInternalMessageLogContext ctxt(context, cat());
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtInfoMsg, ctxt, msg, ap);
+ qt_message(QtInfoMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtInfoMsg))
- qt_message_fatal(QtInfoMsg, ctxt, message);
}
/*!
@@ -572,17 +560,12 @@ void QMessageLogger::info(QMessageLogger::CategoryFunction catFunc,
if (!cat.isInfoEnabled())
return;
- QMessageLogContext ctxt;
- ctxt.copyContextFrom(context);
- ctxt.category = cat.categoryName();
+ QInternalMessageLogContext ctxt(context, cat());
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtInfoMsg, ctxt, msg, ap);
+ qt_message(QtInfoMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtInfoMsg))
- qt_message_fatal(QtInfoMsg, ctxt, message);
}
#ifndef QT_NO_DEBUG_STREAM
@@ -633,7 +616,6 @@ QDebug QMessageLogger::info(QMessageLogger::CategoryFunction catFunc) const
#endif
-#undef qWarning
/*!
Logs a warning message specified with format \a msg. Additional
parameters, specified by \a msg, may be used.
@@ -642,13 +624,11 @@ QDebug QMessageLogger::info(QMessageLogger::CategoryFunction catFunc) const
*/
void QMessageLogger::warning(const char *msg, ...) const
{
+ QInternalMessageLogContext ctxt(context);
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtWarningMsg, context, msg, ap);
+ qt_message(QtWarningMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtWarningMsg))
- qt_message_fatal(QtWarningMsg, context, message);
}
/*!
@@ -663,17 +643,12 @@ void QMessageLogger::warning(const QLoggingCategory &cat, const char *msg, ...)
if (!cat.isWarningEnabled())
return;
- QMessageLogContext ctxt;
- ctxt.copyContextFrom(context);
- ctxt.category = cat.categoryName();
+ QInternalMessageLogContext ctxt(context, cat());
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtWarningMsg, ctxt, msg, ap);
+ qt_message(QtWarningMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtWarningMsg))
- qt_message_fatal(QtWarningMsg, ctxt, message);
}
/*!
@@ -690,17 +665,12 @@ void QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc,
if (!cat.isWarningEnabled())
return;
- QMessageLogContext ctxt;
- ctxt.copyContextFrom(context);
- ctxt.category = cat.categoryName();
+ QInternalMessageLogContext ctxt(context, cat());
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtWarningMsg, ctxt, msg, ap);
+ qt_message(QtWarningMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtWarningMsg))
- qt_message_fatal(QtWarningMsg, ctxt, message);
}
#ifndef QT_NO_DEBUG_STREAM
@@ -748,8 +718,6 @@ QDebug QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc) const
#endif
-#undef qCritical
-
/*!
Logs a critical message specified with format \a msg. Additional
parameters, specified by \a msg, may be used.
@@ -758,13 +726,11 @@ QDebug QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc) const
*/
void QMessageLogger::critical(const char *msg, ...) const
{
+ QInternalMessageLogContext ctxt(context);
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtCriticalMsg, context, msg, ap);
+ qt_message(QtCriticalMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtCriticalMsg))
- qt_message_fatal(QtCriticalMsg, context, message);
}
/*!
@@ -779,17 +745,12 @@ void QMessageLogger::critical(const QLoggingCategory &cat, const char *msg, ...)
if (!cat.isCriticalEnabled())
return;
- QMessageLogContext ctxt;
- ctxt.copyContextFrom(context);
- ctxt.category = cat.categoryName();
+ QInternalMessageLogContext ctxt(context, cat());
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtCriticalMsg, ctxt, msg, ap);
+ qt_message(QtCriticalMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtCriticalMsg))
- qt_message_fatal(QtCriticalMsg, ctxt, message);
}
/*!
@@ -806,17 +767,12 @@ void QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc,
if (!cat.isCriticalEnabled())
return;
- QMessageLogContext ctxt;
- ctxt.copyContextFrom(context);
- ctxt.category = cat.categoryName();
+ QInternalMessageLogContext ctxt(context, cat());
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtCriticalMsg, ctxt, msg, ap);
+ qt_message(QtCriticalMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtCriticalMsg))
- qt_message_fatal(QtCriticalMsg, ctxt, message);
}
#ifndef QT_NO_DEBUG_STREAM
@@ -865,8 +821,6 @@ QDebug QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc) const
#endif
-#undef qFatal
-
/*!
Logs a fatal message specified with format \a msg for the context \a cat.
Additional parameters, specified by \a msg, may be used.
@@ -876,18 +830,16 @@ QDebug QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc) const
*/
void QMessageLogger::fatal(const QLoggingCategory &cat, const char *msg, ...) const noexcept
{
- QMessageLogContext ctxt;
- ctxt.copyContextFrom(context);
- ctxt.category = cat.categoryName();
-
- QString message;
+ QInternalMessageLogContext ctxt(context, cat());
va_list ap;
va_start(ap, msg); // use variable arg list
- QT_TERMINATE_ON_EXCEPTION(message = qt_message(QtFatalMsg, ctxt, msg, ap));
+ QT_TERMINATE_ON_EXCEPTION(qt_message(QtFatalMsg, ctxt, msg, ap));
va_end(ap);
- qt_message_fatal(QtCriticalMsg, ctxt, message);
+#ifndef Q_CC_MSVC_ONLY
+ Q_UNREACHABLE();
+#endif
}
/*!
@@ -902,18 +854,16 @@ void QMessageLogger::fatal(QMessageLogger::CategoryFunction catFunc,
{
const QLoggingCategory &cat = (*catFunc)();
- QMessageLogContext ctxt;
- ctxt.copyContextFrom(context);
- ctxt.category = cat.categoryName();
-
- QString message;
+ QInternalMessageLogContext ctxt(context, cat());
va_list ap;
va_start(ap, msg); // use variable arg list
- QT_TERMINATE_ON_EXCEPTION(message = qt_message(QtFatalMsg, ctxt, msg, ap));
+ QT_TERMINATE_ON_EXCEPTION(qt_message(QtFatalMsg, ctxt, msg, ap));
va_end(ap);
- qt_message_fatal(QtFatalMsg, ctxt, message);
+#ifndef Q_CC_MSVC_ONLY
+ Q_UNREACHABLE();
+#endif
}
/*!
@@ -924,14 +874,15 @@ void QMessageLogger::fatal(QMessageLogger::CategoryFunction catFunc,
*/
void QMessageLogger::fatal(const char *msg, ...) const noexcept
{
- QString message;
-
+ QInternalMessageLogContext ctxt(context);
va_list ap;
va_start(ap, msg); // use variable arg list
- QT_TERMINATE_ON_EXCEPTION(message = qt_message(QtFatalMsg, context, msg, ap));
+ QT_TERMINATE_ON_EXCEPTION(qt_message(QtFatalMsg, ctxt, msg, ap));
va_end(ap);
- qt_message_fatal(QtFatalMsg, context, message);
+#ifndef Q_CC_MSVC_ONLY
+ Q_UNREACHABLE();
+#endif
}
#ifndef QT_NO_DEBUG_STREAM
@@ -979,6 +930,12 @@ QDebug QMessageLogger::fatal(QMessageLogger::CategoryFunction catFunc) const
}
#endif // QT_NO_DEBUG_STREAM
+#if !defined(QT_BOOTSTRAPPED)
+static bool isDefaultCategory(const char *category)
+{
+ return !category || strcmp(category, "default") == 0;
+}
+
/*!
\internal
*/
@@ -998,8 +955,13 @@ Q_AUTOTEST_EXPORT QByteArray qCleanupFuncinfo(QByteArray info)
pos = info.size() - 1;
if (info.endsWith(']') && !(info.startsWith('+') || info.startsWith('-'))) {
while (--pos) {
- if (info.at(pos) == '[')
- info.truncate(pos);
+ if (info.at(pos) == '[') {
+ info.truncate(pos);
+ break;
+ }
+ }
+ if (info.endsWith(' ')) {
+ info.chop(1);
}
}
@@ -1013,10 +975,11 @@ Q_AUTOTEST_EXPORT QByteArray qCleanupFuncinfo(QByteArray info)
// canonize operator names
info.replace("operator ", "operator");
+ pos = -1;
// remove argument list
forever {
int parencount = 0;
- pos = info.lastIndexOf(')');
+ pos = info.lastIndexOf(')', pos);
if (pos == -1) {
// Don't know how to parse this function name
return info;
@@ -1024,8 +987,8 @@ Q_AUTOTEST_EXPORT QByteArray qCleanupFuncinfo(QByteArray info)
if (info.indexOf('>', pos) != -1
|| info.indexOf(':', pos) != -1) {
// that wasn't the function argument list.
- pos = info.size();
- break;
+ --pos;
+ continue;
}
// find the beginning of the argument list
@@ -1186,6 +1149,7 @@ struct QMessagePattern
int backtraceDepth;
};
QList<BacktraceParams> backtraceArgs; // backtrace arguments in sequence of %{backtrace
+ int maxBacktraceDepth = 0;
#endif
bool fromEnvironment;
@@ -1219,6 +1183,7 @@ void QMessagePattern::setPattern(const QString &pattern)
timeArgs.clear();
#ifdef QLOGGING_HAVE_BACKTRACE
backtraceArgs.clear();
+ maxBacktraceDepth = 0;
#endif
// scanner
@@ -1313,6 +1278,7 @@ void QMessagePattern::setPattern(const QString &pattern)
backtraceParams.backtraceDepth = backtraceDepth;
backtraceParams.backtraceSeparator = backtraceSeparator;
backtraceArgs.append(backtraceParams);
+ maxBacktraceDepth = qMax(maxBacktraceDepth, backtraceDepth);
#else
error += "QT_MESSAGE_PATTERN: %{backtrace} is not supported by this Qt build\n"_L1;
tokens[i] = "";
@@ -1340,8 +1306,7 @@ void QMessagePattern::setPattern(const QString &pattern)
inIf = false;
} else {
tokens[i] = emptyTokenC;
- error += QStringLiteral("QT_MESSAGE_PATTERN: Unknown placeholder %1\n")
- .arg(lexeme);
+ error += "QT_MESSAGE_PATTERN: Unknown placeholder "_L1 + lexeme + '\n'_L1;
}
} else {
using UP = std::unique_ptr<char[]>;
@@ -1353,35 +1318,94 @@ void QMessagePattern::setPattern(const QString &pattern)
else if (inIf)
error += "QT_MESSAGE_PATTERN: missing %{endif}\n"_L1;
- if (!error.isEmpty())
- qt_message_print(error);
+ if (!error.isEmpty()) {
+ // remove the last '\n' because the sinks deal with that on their own
+ error.chop(1);
+
+ QMessageLogContext ctx(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE,
+ "QMessagePattern::setPattern", nullptr);
+ preformattedMessageHandler(QtWarningMsg, ctx, error);
+ }
literals.reset(new std::unique_ptr<const char[]>[literalsVar.size() + 1]);
std::move(literalsVar.begin(), literalsVar.end(), &literals[0]);
}
-#if defined(QLOGGING_HAVE_BACKTRACE) && !defined(QT_BOOTSTRAPPED)
+#if defined(QLOGGING_HAVE_BACKTRACE)
// make sure the function has "Message" in the name so the function is removed
/*
A typical backtrace in debug mode looks like:
- #0 backtraceFramesForLogMessage (frameCount=5) at qlogging.cpp:1296
- #1 formatBacktraceForLogMessage (backtraceParams=..., function=0x4040b8 "virtual void MyClass::myFunction(int)") at qlogging.cpp:1344
- #2 qFormatLogMessage (type=QtDebugMsg, context=..., str=...) at qlogging.cpp:1452
- #3 stderr_message_handler (type=QtDebugMsg, context=..., message=...) at qlogging.cpp:1744
- #4 qDefaultMessageHandler (type=QtDebugMsg, context=..., message=...) at qlogging.cpp:1795
- #5 qt_message_print (msgType=QtDebugMsg, context=..., message=...) at qlogging.cpp:1840
- #6 qt_message_output (msgType=QtDebugMsg, context=..., message=...) at qlogging.cpp:1891
- #7 QDebug::~QDebug (this=<optimized out>, __in_chrg=<optimized out>) at qdebug.h:111
+ #0 QInternalMessageLogContext::populateBacktrace (this=0x7fffffffd660, frameCount=5) at qlogging.cpp:1342
+ #1 QInternalMessageLogContext::QInternalMessageLogContext (logContext=..., this=<optimized out>) at qlogging_p.h:42
+ #2 QDebug::~QDebug (this=0x7fffffffdac8, __in_chrg=<optimized out>) at qdebug.cpp:160
+
+ In release mode, the QInternalMessageLogContext constructor will be usually
+ inlined. Empirical testing with GCC 13 and Clang 17 suggest they do obey the
+ Q_ALWAYS_INLINE in that constructor even in debug mode and do inline it.
+ Unfortunately, we can't know for sure if it has been.
*/
-static constexpr int TypicalBacktraceFrameCount = 8;
+static constexpr int TypicalBacktraceFrameCount = 3;
+static constexpr const char *QtCoreLibraryName = "Qt" QT_STRINGIFY(QT_VERSION_MAJOR) "Core";
-# if defined(Q_CC_GNU) && !defined(Q_CC_CLANG)
-// force skipping the frame pointer, to save the backtrace() function some work
-# pragma GCC push_options
-# pragma GCC optimize ("omit-frame-pointer")
-# endif
+#if defined(QLOGGING_USE_STD_BACKTRACE)
+Q_NEVER_INLINE void QInternalMessageLogContext::populateBacktrace(int frameCount)
+{
+ assert(frameCount >= 0);
+ backtrace = std::stacktrace::current(0, TypicalBacktraceFrameCount + frameCount);
+}
-static QStringList backtraceFramesForLogMessage(int frameCount)
+static QStringList
+backtraceFramesForLogMessage(int frameCount,
+ const QInternalMessageLogContext::BacktraceStorage &buffer)
+{
+ QStringList result;
+ result.reserve(buffer.size());
+
+ const auto shouldSkipFrame = [](QByteArrayView description)
+ {
+#if defined(_MSVC_STL_VERSION)
+ const auto libraryNameEnd = description.indexOf('!');
+ if (libraryNameEnd != -1) {
+ const auto libraryName = description.first(libraryNameEnd);
+ if (!libraryName.contains(QtCoreLibraryName))
+ return false;
+ }
+#endif
+ if (description.contains("populateBacktrace"))
+ return true;
+ if (description.contains("QInternalMessageLogContext"))
+ return true;
+ if (description.contains("~QDebug"))
+ return true;
+ return false;
+ };
+
+ for (const auto &entry : buffer) {
+ const std::string description = entry.description();
+ if (result.isEmpty() && shouldSkipFrame(description))
+ continue;
+ result.append(QString::fromStdString(description));
+ }
+
+ return result;
+}
+
+#elif defined(QLOGGING_USE_EXECINFO_BACKTRACE)
+
+Q_NEVER_INLINE void QInternalMessageLogContext::populateBacktrace(int frameCount)
+{
+ assert(frameCount >= 0);
+ BacktraceStorage &result = backtrace.emplace(TypicalBacktraceFrameCount + frameCount);
+ int n = ::backtrace(result.data(), result.size());
+ if (n <= 0)
+ result.clear();
+ else
+ result.resize(n);
+}
+
+static QStringList
+backtraceFramesForLogMessage(int frameCount,
+ const QInternalMessageLogContext::BacktraceStorage &buffer)
{
struct DecodedFrame {
QString library;
@@ -1392,20 +1416,18 @@ static QStringList backtraceFramesForLogMessage(int frameCount)
if (frameCount == 0)
return result;
- QVarLengthArray<void *, 32> buffer(TypicalBacktraceFrameCount + frameCount);
- int n = backtrace(buffer.data(), buffer.size());
- if (n <= 0)
- return result;
- buffer.resize(n);
-
auto shouldSkipFrame = [&result](const auto &library, const auto &function) {
- if (!result.isEmpty() || !library.contains("Qt6Core"_L1))
+ if (!result.isEmpty() || !library.contains(QLatin1StringView(QtCoreLibraryName)))
return false;
if (function.isEmpty())
return true;
if (function.contains("6QDebug"_L1))
return true;
- if (function.contains("Message"_L1) || function.contains("_message"_L1))
+ if (function.contains("14QMessageLogger"_L1))
+ return true;
+ if (function.contains("17qt_message_output"_L1))
+ return true;
+ if (function.contains("26QInternalMessageLogContext"_L1))
return true;
return false;
};
@@ -1484,7 +1506,7 @@ static QStringList backtraceFramesForLogMessage(int frameCount)
};
# endif
- for (void *&addr : buffer) {
+ for (void *const &addr : buffer) {
DecodedFrame frame = decodeFrame(addr);
if (!frame.library.isEmpty()) {
if (frame.function.isEmpty())
@@ -1502,27 +1524,34 @@ static QStringList backtraceFramesForLogMessage(int frameCount)
}
return result;
}
+#else
+#error "Internal error: backtrace enabled, but no way to gather backtraces available"
+#endif // QLOGGING_USE_..._BACKTRACE
static QString formatBacktraceForLogMessage(const QMessagePattern::BacktraceParams backtraceParams,
- const char *function)
+ const QMessageLogContext &ctx)
{
+ // do we have a backtrace stored?
+ if (ctx.version <= QMessageLogContext::CurrentVersion)
+ return QString();
+
+ auto &fullctx = static_cast<const QInternalMessageLogContext &>(ctx);
+ if (!fullctx.backtrace.has_value())
+ return QString();
+
QString backtraceSeparator = backtraceParams.backtraceSeparator;
int backtraceDepth = backtraceParams.backtraceDepth;
- QStringList frames = backtraceFramesForLogMessage(backtraceDepth);
+ QStringList frames = backtraceFramesForLogMessage(backtraceDepth, *fullctx.backtrace);
if (frames.isEmpty())
return QString();
// if the first frame is unknown, replace it with the context function
- if (function && frames.at(0).startsWith(u'?'))
- frames[0] = QString::fromUtf8(qCleanupFuncinfo(function));
+ if (ctx.function && frames.at(0).startsWith(u'?'))
+ frames[0] = QString::fromUtf8(qCleanupFuncinfo(ctx.function));
return frames.join(backtraceSeparator);
}
-
-# if defined(Q_CC_GNU) && !defined(Q_CC_CLANG)
-# pragma GCC pop_options
-# endif
#endif // QLOGGING_HAVE_BACKTRACE && !QT_BOOTSTRAPPED
Q_GLOBAL_STATIC(QMessagePattern, qMessagePattern)
@@ -1543,6 +1572,14 @@ Q_GLOBAL_STATIC(QMessagePattern, qMessagePattern)
*/
QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, const QString &str)
{
+ return formatLogMessage(type, context, str);
+}
+
+// Separate function so the default message handler can bypass the public,
+// exported function above. Static functions can't get added to the dynamic
+// symbol tables, so they never show up in backtrace_symbols() or equivalent.
+static QString formatLogMessage(QtMsgType type, const QMessageLogContext &context, const QString &str)
+{
QString message;
const auto locker = qt_scoped_lock(QMessagePattern::mutex);
@@ -1556,12 +1593,10 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con
bool skip = false;
-#ifndef QT_BOOTSTRAPPED
int timeArgsIdx = 0;
#ifdef QLOGGING_HAVE_BACKTRACE
int backtraceArgsIdx = 0;
#endif
-#endif
// we do not convert file, function, line literals to local encoding due to overhead
for (int i = 0; pattern->tokens[i]; ++i) {
@@ -1571,14 +1606,12 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con
} else if (skip) {
// we skip adding messages, but we have to iterate over
// timeArgsIdx and backtraceArgsIdx anyway
-#ifndef QT_BOOTSTRAPPED
if (token == timeTokenC)
timeArgsIdx++;
#ifdef QLOGGING_HAVE_BACKTRACE
else if (token == backtraceTokenC)
backtraceArgsIdx++;
#endif
-#endif
} else if (token == messageTokenC) {
message.append(str);
} else if (token == categoryTokenC) {
@@ -1606,7 +1639,6 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con
message.append(QString::fromLatin1(qCleanupFuncinfo(context.function)));
else
message.append("unknown"_L1);
-#ifndef QT_BOOTSTRAPPED
} else if (token == pidTokenC) {
message.append(QString::number(QCoreApplication::applicationPid()));
} else if (token == appnameTokenC) {
@@ -1621,18 +1653,18 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con
} else if (token == backtraceTokenC) {
QMessagePattern::BacktraceParams backtraceParams = pattern->backtraceArgs.at(backtraceArgsIdx);
backtraceArgsIdx++;
- message.append(formatBacktraceForLogMessage(backtraceParams, context.function));
+ message.append(formatBacktraceForLogMessage(backtraceParams, context));
#endif
} else if (token == timeTokenC) {
QString timeFormat = pattern->timeArgs.at(timeArgsIdx);
timeArgsIdx++;
if (timeFormat == "process"_L1) {
- quint64 ms = pattern->timer.elapsed();
- message.append(QString::asprintf("%6d.%03d", uint(ms / 1000), uint(ms % 1000)));
+ quint64 ms = pattern->timer.elapsed();
+ message.append(QString::asprintf("%6d.%03d", uint(ms / 1000), uint(ms % 1000)));
} else if (timeFormat == "boot"_L1) {
// just print the milliseconds since the elapsed timer reference
// like the Linux kernel does
- uint ms = QDeadlineTimer::current().deadline();
+ qint64 ms = QDeadlineTimer::current().deadline();
message.append(QString::asprintf("%6d.%03d", uint(ms / 1000), uint(ms % 1000)));
#if QT_CONFIG(datestring)
} else if (timeFormat.isEmpty()) {
@@ -1641,7 +1673,6 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con
message.append(QDateTime::currentDateTime().toString(timeFormat));
#endif // QT_CONFIG(datestring)
}
-#endif // !QT_BOOTSTRAPPED
} else if (token == ifCategoryTokenC) {
if (isDefaultCategory(context.category))
skip = true;
@@ -1660,6 +1691,20 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con
}
return message;
}
+#else // QT_BOOTSTRAPPED
+static QString formatLogMessage(QtMsgType type, const QMessageLogContext &context, const QString &str)
+{
+ Q_UNUSED(type);
+ Q_UNUSED(context);
+ return str;
+}
+#endif
+#ifndef QLOGGING_HAVE_BACKTRACE
+void QInternalMessageLogContext::populateBacktrace(int)
+{
+ Q_UNREACHABLE();
+}
+#endif
static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &buf);
@@ -1677,12 +1722,13 @@ Q_CONSTINIT static QBasicAtomicPointer<void (QtMsgType, const QMessageLogContext
#define QT_LOG_CODE 9000
#endif
-static bool slog2_default_handler(QtMsgType type, const QMessageLogContext &context, const QString &message)
+static bool slog2_default_handler(QtMsgType type, const QMessageLogContext &,
+ const QString &message)
{
if (shouldLogToStderr())
return false; // Leave logging up to stderr handler
- QString formattedMessage = qFormatLogMessage(type, context, message);
+ QString formattedMessage = message;
formattedMessage.append(u'\n');
if (slog2_set_default_buffer((slog2_buffer_t)-1) == 0) {
slog2_buffer_set_config_t buffer_config;
@@ -1733,13 +1779,11 @@ static bool slog2_default_handler(QtMsgType type, const QMessageLogContext &cont
#if QT_CONFIG(journald)
static bool systemd_default_message_handler(QtMsgType type,
const QMessageLogContext &context,
- const QString &message)
+ const QString &formattedMessage)
{
if (shouldLogToStderr())
return false; // Leave logging up to stderr handler
- QString formattedMessage = qFormatLogMessage(type, context, message);
-
int priority = LOG_INFO; // Informational
switch (type) {
case QtDebugMsg:
@@ -1772,13 +1816,12 @@ static bool systemd_default_message_handler(QtMsgType type,
#endif
#if QT_CONFIG(syslog)
-static bool syslog_default_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &message)
+static bool syslog_default_message_handler(QtMsgType type, const QMessageLogContext &context,
+ const QString &formattedMessage)
{
if (shouldLogToStderr())
return false; // Leave logging up to stderr handler
- QString formattedMessage = qFormatLogMessage(type, context, message);
-
int priority = LOG_INFO; // Informational
switch (type) {
case QtDebugMsg:
@@ -1807,13 +1850,11 @@ static bool syslog_default_message_handler(QtMsgType type, const QMessageLogCont
#ifdef Q_OS_ANDROID
static bool android_default_message_handler(QtMsgType type,
const QMessageLogContext &context,
- const QString &message)
+ const QString &formattedMessage)
{
if (shouldLogToStderr())
return false; // Leave logging up to stderr handler
- QString formattedMessage = qFormatLogMessage(type, context, message);
-
android_LogPriority priority = ANDROID_LOG_DEBUG;
switch (type) {
case QtDebugMsg:
@@ -1865,13 +1906,13 @@ static void win_outputDebugString_helper(const QString &message)
}
}
-static bool win_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &message)
+static bool win_message_handler(QtMsgType, const QMessageLogContext &,
+ const QString &formattedMessage)
{
if (shouldLogToStderr())
return false; // Leave logging up to stderr handler
- const QString formattedMessage = qFormatLogMessage(type, context, message).append(u'\n');
- win_outputDebugString_helper(formattedMessage);
+ win_outputDebugString_helper(formattedMessage + u'\n');
return true; // Prevent further output to stderr
}
@@ -1879,15 +1920,15 @@ static bool win_message_handler(QtMsgType type, const QMessageLogContext &contex
#ifdef Q_OS_WASM
static bool wasm_default_message_handler(QtMsgType type,
- const QMessageLogContext &context,
- const QString &message)
+ const QMessageLogContext &,
+ const QString &formattedMessage)
{
- if (shouldLogToStderr())
- return false; // Leave logging up to stderr handler
+ static bool forceStderrLogging = qEnvironmentVariableIntValue("QT_FORCE_STDERR_LOGGING");
+ if (forceStderrLogging)
+ return false;
- QString formattedMessage = qFormatLogMessage(type, context, message);
- int emOutputFlags = (EM_LOG_CONSOLE | EM_LOG_DEMANGLE);
- QByteArray localMsg = message.toLocal8Bit();
+ int emOutputFlags = EM_LOG_CONSOLE;
+ QByteArray localMsg = formattedMessage.toLocal8Bit();
switch (type) {
case QtDebugMsg:
break;
@@ -1912,56 +1953,87 @@ static bool wasm_default_message_handler(QtMsgType type,
// --------------------------------------------------------------------------
-static void stderr_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &message)
+static void stderr_message_handler(QtMsgType type, const QMessageLogContext &context,
+ const QString &formattedMessage)
{
- QString formattedMessage = qFormatLogMessage(type, context, message);
+ Q_UNUSED(type);
+ Q_UNUSED(context);
// print nothing if message pattern didn't apply / was empty.
// (still print empty lines, e.g. because message itself was empty)
if (formattedMessage.isNull())
return;
-
fprintf(stderr, "%s\n", formattedMessage.toLocal8Bit().constData());
fflush(stderr);
}
+namespace {
+struct SystemMessageSink
+{
+ using Fn = bool(QtMsgType, const QMessageLogContext &, const QString &);
+ Fn *sink;
+ bool messageIsUnformatted = false;
+};
+}
+
+static constexpr SystemMessageSink systemMessageSink = {
+#if defined(QT_BOOTSTRAPPED)
+ nullptr
+#elif defined(Q_OS_WIN)
+ win_message_handler
+#elif QT_CONFIG(slog2)
+ slog2_default_handler
+#elif QT_CONFIG(journald)
+ systemd_default_message_handler
+#elif QT_CONFIG(syslog)
+ syslog_default_message_handler
+#elif defined(Q_OS_ANDROID)
+ android_default_message_handler
+#elif defined(QT_USE_APPLE_UNIFIED_LOGGING)
+ AppleUnifiedLogger::messageHandler, true
+#elif defined Q_OS_WASM
+ wasm_default_message_handler
+#else
+ nullptr
+#endif
+};
+
+static void preformattedMessageHandler(QtMsgType type, const QMessageLogContext &context,
+ const QString &formattedMessage)
+{
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Waddress") // "the address of ~~ will never be NULL
+ if (systemMessageSink.sink && systemMessageSink.sink(type, context, formattedMessage))
+ return;
+QT_WARNING_POP
+
+ stderr_message_handler(type, context, formattedMessage);
+}
+
/*!
\internal
*/
static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &context,
const QString &message)
{
- bool handledStderr = false;
-
// A message sink logs the message to a structured or unstructured destination,
// optionally formatting the message if the latter, and returns true if the sink
// handled stderr output as well, which will shortcut our default stderr output.
- // In the future, if we allow multiple/dynamic sinks, this will be iterating
- // a list of sinks.
-#if !defined(QT_BOOTSTRAPPED)
-# if defined(Q_OS_WIN)
- handledStderr |= win_message_handler(type, context, message);
-# elif QT_CONFIG(slog2)
- handledStderr |= slog2_default_handler(type, context, message);
-# elif QT_CONFIG(journald)
- handledStderr |= systemd_default_message_handler(type, context, message);
-# elif QT_CONFIG(syslog)
- handledStderr |= syslog_default_message_handler(type, context, message);
-# elif defined(Q_OS_ANDROID)
- handledStderr |= android_default_message_handler(type, context, message);
-# elif defined(QT_USE_APPLE_UNIFIED_LOGGING)
- handledStderr |= AppleUnifiedLogger::messageHandler(type, context, message);
-# elif defined Q_OS_WASM
- handledStderr |= wasm_default_message_handler(type, context, message);
-# endif
-#endif
+ if (systemMessageSink.messageIsUnformatted) {
+ if (systemMessageSink.sink(type, context, message))
+ return;
+ }
- if (!handledStderr)
- stderr_message_handler(type, context, message);
+ preformattedMessageHandler(type, context, formatLogMessage(type, context, message));
}
-#if defined(Q_COMPILER_THREAD_LOCAL)
+#if defined(QT_BOOTSTRAPPED)
+// there's no message handler in bootstrapped mode; force everything to stderr
+static bool grabMessageHandler() { return false; }
+static void ungrabMessageHandler() { }
+
+#elif defined(Q_COMPILER_THREAD_LOCAL)
Q_CONSTINIT static thread_local bool msgHandlerGrabbed = false;
@@ -2005,25 +2077,14 @@ static void qt_message_print(QtMsgType msgType, const QMessageLogContext &contex
auto msgHandler = messageHandler.loadAcquire();
(msgHandler ? msgHandler : qDefaultMessageHandler)(msgType, context, message);
} else {
- fprintf(stderr, "%s\n", message.toLocal8Bit().constData());
- }
-}
-
-static void qt_message_print(const QString &message)
-{
-#if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED)
- if (!shouldLogToStderr()) {
- win_outputDebugString_helper(message);
- return;
+ stderr_message_handler(msgType, context, message);
}
-#endif
- fprintf(stderr, "%s", message.toLocal8Bit().constData());
- fflush(stderr);
}
-static void qt_message_fatal(QtMsgType, const QMessageLogContext &context, const QString &message)
+template <typename String>
+static void qt_message_fatal(QtMsgType, const QMessageLogContext &context, String &&message)
{
-#if defined(Q_CC_MSVC) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
+#if defined(Q_CC_MSVC_ONLY) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
wchar_t contextFileL[256];
// we probably should let the compiler do this for us, by declaring QMessageLogContext::file to
// be const wchar_t * in the first place, but the #ifdefery above is very complex and we
@@ -2042,21 +2103,24 @@ static void qt_message_fatal(QtMsgType, const QMessageLogContext &context, const
_CrtDbgBreak();
#else
Q_UNUSED(context);
- Q_UNUSED(message);
#endif
+ if constexpr (std::is_class_v<String> && !std::is_const_v<String>)
+ message.clear();
+ else
+ Q_UNUSED(message);
qAbort();
}
-
/*!
\internal
*/
void qt_message_output(QtMsgType msgType, const QMessageLogContext &context, const QString &message)
{
- qt_message_print(msgType, context, message);
+ QInternalMessageLogContext ctx(context);
+ qt_message_print(msgType, ctx, message);
if (isFatal(msgType))
- qt_message_fatal(msgType, context, message);
+ qt_message_fatal(msgType, ctx, message);
}
void qErrnoWarning(const char *msg, ...)
@@ -2071,8 +2135,8 @@ void qErrnoWarning(const char *msg, ...)
va_end(ap);
buf += " ("_L1 + error_string + u')';
- QMessageLogContext context;
- qt_message_output(QtCriticalMsg, context, buf);
+ QInternalMessageLogContext context{QMessageLogContext()};
+ qt_message_output(QtWarningMsg, context, buf);
}
void qErrnoWarning(int code, const char *msg, ...)
@@ -2085,8 +2149,8 @@ void qErrnoWarning(int code, const char *msg, ...)
va_end(ap);
buf += " ("_L1 + qt_error_string(code) + u')';
- QMessageLogContext context;
- qt_message_output(QtCriticalMsg, context, buf);
+ QInternalMessageLogContext context{QMessageLogContext()};
+ qt_message_output(QtWarningMsg, context, buf);
}
/*!
@@ -2107,34 +2171,61 @@ void qErrnoWarning(int code, const char *msg, ...)
\relates <QtLogging>
\since 5.0
- Installs a Qt message \a handler which has been defined
- previously. Returns a pointer to the previous message handler.
-
- The message handler is a function that prints out debug messages,
- warnings, critical and fatal error messages. The Qt library (debug
- mode) contains hundreds of warning messages that are printed
- when internal errors (usually invalid function arguments)
- occur. Qt built in release mode also contains such warnings unless
- QT_NO_WARNING_OUTPUT and/or QT_NO_DEBUG_OUTPUT have been set during
- compilation. If you implement your own message handler, you get total
- control of these messages.
-
- The default message handler prints the message to the standard output
- under X11 or to the debugger under Windows. If it is a fatal message, the
- application aborts immediately after handling that message. Custom
- message handlers should not attempt to exit an application on their own.
-
- Only one message handler can be defined, since this is usually
- done on an application-wide basis to control debug output.
-
- To restore the message handler, call \c qInstallMessageHandler(0).
-
- Example:
+ Installs a Qt message \a handler.
+ Returns a pointer to the previously installed message handler.
+
+ A message handler is a function that prints out debug, info,
+ warning, critical, and fatal messages from Qt's logging infrastructure.
+ By default, Qt uses a standard message handler that formats and
+ prints messages to different sinks specific to the operating system
+ and Qt configuration. Installing your own message handler allows you
+ to assume full control, and for instance log messages to the
+ file system.
+
+ Note that Qt supports \l{QLoggingCategory}{logging categories} for
+ grouping related messages in semantic categories. You can use these
+ to enable or disable logging per category and \l{QtMsgType}{message type}.
+ As the filtering for logging categories is done even before a message
+ is created, messages for disabled types and categories will not reach
+ the message handler.
+
+ A message handler needs to be
+ \l{Reentrancy and Thread-Safety}{reentrant}. That is, it might be called
+ from different threads, in parallel. Therefore, writes to common sinks
+ (like a database, or a file) often need to be synchronized.
+
+ Qt allows to enrich logging messages with further meta-information
+ by calling \l qSetMessagePattern(), or setting the \c QT_MESSAGE_PATTERN
+ environment variable. To keep this formatting, a custom message handler
+ can use \l qFormatLogMessage().
+
+ Try to keep the code in the message handler itself minimal, as expensive
+ operations might block the application. Also, to avoid recursion, any
+ logging messages generated in the message handler itself will be ignored.
+
+ The message handler should always return. For
+ \l{QtFatalMsg}{fatal messages}, the application aborts immediately after
+ handling that message.
+
+ Only one message handler can be installed at a time, for the whole application.
+ If there was a previous custom message handler installed,
+ the function will return a pointer to it. This handler can then
+ be later reinstalled by another call to the method. Also, calling
+ \c qInstallMessageHandler(nullptr) will restore the default
+ message handler.
+
+ Here is an example of a message handler that logs to a local file
+ before calling the default handler:
\snippet code/src_corelib_global_qglobal.cpp 23
+ Note that the C++ standard guarantees that \c{static FILE *f} is
+ initialized in a thread-safe way. We can also expect \c{fprintf()}
+ and \c{fflush()} to be thread-safe, so no further synchronization
+ is necessary.
+
\sa QtMessageHandler, QtMsgType, qDebug(), qInfo(), qWarning(), qCritical(), qFatal(),
- {Debugging Techniques}
+ {Debugging Techniques}, qFormatLogMessage()
*/
/*!
@@ -2173,8 +2264,18 @@ void qErrnoWarning(int code, const char *msg, ...)
specified by the optional \c depth parameter (defaults to 5), and separated by the optional
\c separator parameter (defaults to "|").
- This expansion is available only on some platforms (currently only platfoms using glibc).
- Names are only known for exported functions. If you want to see the name of every function
+ This expansion is available only on some platforms:
+
+ \list
+ \li platforms using glibc;
+ \li platforms shipping C++23's \c{<stacktrace>} header (requires compiling Qt in C++23 mode).
+ \endlist
+
+ Depending on the platform, there are some restrictions on the function
+ names printed by this expansion.
+
+ On some platforms,
+ names are only known for exported functions. If you want to see the name of every function
in your application, make sure your application is compiled and linked with \c{-rdynamic},
or an equivalent of it.
@@ -2220,6 +2321,7 @@ QtMessageHandler qInstallMessageHandler(QtMessageHandler h)
return qDefaultMessageHandler;
}
+#ifndef QT_BOOTSTRAPPED
void qSetMessagePattern(const QString &pattern)
{
const auto locker = qt_scoped_lock(QMessagePattern::mutex);
@@ -2227,7 +2329,38 @@ void qSetMessagePattern(const QString &pattern)
if (!qMessagePattern()->fromEnvironment)
qMessagePattern()->setPattern(pattern);
}
+#endif
+
+static void copyInternalContext(QInternalMessageLogContext *self,
+ const QMessageLogContext &logContext) noexcept
+{
+ if (logContext.version == self->version) {
+ auto other = static_cast<const QInternalMessageLogContext *>(&logContext);
+ self->backtrace = other->backtrace;
+ }
+}
+
+/*!
+ \internal
+ Copies context information from \a logContext into this QMessageLogContext.
+ Returns the number of backtrace frames that are desired.
+*/
+int QInternalMessageLogContext::initFrom(const QMessageLogContext &logContext)
+{
+ version = CurrentVersion + 1;
+ copyContextFrom(logContext);
+
+#ifdef QLOGGING_HAVE_BACKTRACE
+ if (backtrace.has_value())
+ return 0; // we have a stored backtrace, no need to get it again
+ // initializes the message pattern, if needed
+ if (auto pattern = qMessagePattern())
+ return pattern->maxBacktraceDepth;
+#endif
+
+ return 0;
+}
/*!
Copies context information from \a logContext into this QMessageLogContext.
@@ -2243,6 +2376,8 @@ QMessageLogContext &QMessageLogContext::copyContextFrom(const QMessageLogContext
this->file = logContext.file;
this->line = logContext.line;
this->function = logContext.function;
+ if (Q_UNLIKELY(version == CurrentVersion + 1))
+ copyInternalContext(static_cast<QInternalMessageLogContext *>(this), logContext);
return *this;
}
@@ -2373,13 +2508,7 @@ QMessageLogContext &QMessageLogContext::copyContextFrom(const QMessageLogContext
Calls the message handler with the warning message \a message. If no
message handler has been installed, the message is printed to
stderr. Under Windows, the message is sent to the debugger.
- On QNX the message is sent to slogger2. This
- function does nothing if \c QT_NO_WARNING_OUTPUT was defined
- during compilation; it exits if at the nth warning corresponding to the
- counter in environment variable \c QT_FATAL_WARNINGS. That is, if the
- environment variable contains the value 1, it will exit on the 1st message;
- if it contains the value 10, it will exit on the 10th message. Any
- non-numeric value is equivalent to 1.
+ On QNX the message is sent to slogger2.
This function takes a format string and a list of arguments,
similar to the C printf() function. The format should be a Latin-1
@@ -2396,8 +2525,20 @@ QMessageLogContext &QMessageLogContext::copyContextFrom(const QMessageLogContext
This syntax inserts a space between each item, and
appends a newline at the end.
- To suppress the output at runtime, install your own message handler
- with qInstallMessageHandler().
+ This function does nothing if \c QT_NO_WARNING_OUTPUT was defined
+ during compilation.
+ To suppress the output at runtime, you can set
+ \l{QLoggingCategory}{logging rules} or register a custom
+ \l{QLoggingCategory::installFilter()}{filter}.
+
+ For debugging purposes, it is sometimes convenient to let the
+ program abort for warning messages. This allows you then
+ to inspect the core dump, or attach a debugger - see also \l{qFatal()}.
+ To enable this, set the environment variable \c{QT_FATAL_WARNINGS}
+ to a number \c n. The program terminates then for the n-th warning.
+ That is, if the environment variable is set to 1, it will terminate
+ on the first call; if it contains the value 10, it will exit on the 10th
+ call. Any non-numeric value in the environment variable is equivalent to 1.
\sa qDebug(), qInfo(), qCritical(), qFatal(), qInstallMessageHandler(),
{Debugging Techniques}
@@ -2413,8 +2554,6 @@ QMessageLogContext &QMessageLogContext::copyContextFrom(const QMessageLogContext
stderr. Under Windows, the message is sent to the debugger.
On QNX the message is sent to slogger2.
- It exits if the environment variable QT_FATAL_CRITICALS is not empty.
-
This function takes a format string and a list of arguments,
similar to the C printf() function. The format should be a Latin-1
string.
@@ -2430,8 +2569,19 @@ QMessageLogContext &QMessageLogContext::copyContextFrom(const QMessageLogContext
A space is inserted between the items, and a newline is
appended at the end.
- To suppress the output at runtime, install your own message handler
- with qInstallMessageHandler().
+ To suppress the output at runtime, you can define
+ \l{QLoggingCategory}{logging rules} or register a custom
+ \l{QLoggingCategory::installFilter()}{filter}.
+
+ For debugging purposes, it is sometimes convenient to let the
+ program abort for critical messages. This allows you then
+ to inspect the core dump, or attach a debugger - see also \l{qFatal()}.
+ To enable this, set the environment variable \c{QT_FATAL_CRITICALS}
+ to a number \c n. The program terminates then for the n-th critical
+ message.
+ That is, if the environment variable is set to 1, it will terminate
+ on the first call; if it contains the value 10, it will exit on the 10th
+ call. Any non-numeric value in the environment variable is equivalent to 1.
\sa qDebug(), qInfo(), qWarning(), qFatal(), qInstallMessageHandler(),
{Debugging Techniques}
@@ -2483,7 +2633,7 @@ QMessageLogContext &QMessageLogContext::copyContextFrom(const QMessageLogContext
A message generated by the qCritical() function.
\value QtFatalMsg
A message generated by the qFatal() function.
- \value QtSystemMsg
+ \omitvalue QtSystemMsg
\c QtInfoMsg was added in Qt 5.5.
diff --git a/src/corelib/global/qlogging.h b/src/corelib/global/qlogging.h
index ea1c68b168..aa0ab93a2d 100644
--- a/src/corelib/global/qlogging.h
+++ b/src/corelib/global/qlogging.h
@@ -1,11 +1,14 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <QtCore/qglobal.h>
-
#ifndef QLOGGING_H
#define QLOGGING_H
+#include <QtCore/qtclasshelpermacros.h>
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qtcoreexports.h>
+#include <QtCore/qcontainerfwd.h>
+
#if 0
// header is automatically included in qglobal.h
#pragma qt_no_master_include
@@ -22,24 +25,29 @@ QT_BEGIN_NAMESPACE
class QDebug;
class QNoDebug;
+
enum QtMsgType {
QtDebugMsg,
QtWarningMsg,
QtCriticalMsg,
QtFatalMsg,
QtInfoMsg,
- QtSystemMsg = QtCriticalMsg
+#if QT_DEPRECATED_SINCE(6, 7)
+ QtSystemMsg Q_DECL_ENUMERATOR_DEPRECATED_X("Use QtCriticalMsg instead.") = QtCriticalMsg
+#endif
};
+class QInternalMessageLogContext;
class QMessageLogContext
{
Q_DISABLE_COPY(QMessageLogContext)
public:
+ static constexpr int CurrentVersion = 2;
constexpr QMessageLogContext() noexcept = default;
constexpr QMessageLogContext(const char *fileName, int lineNumber, const char *functionName, const char *categoryName) noexcept
: line(lineNumber), file(fileName), function(functionName), category(categoryName) {}
- int version = 2;
+ int version = CurrentVersion;
int line = 0;
const char *file = nullptr;
const char *function = nullptr;
@@ -48,13 +56,13 @@ public:
private:
QMessageLogContext &copyContextFrom(const QMessageLogContext &logContext) noexcept;
+ friend class QInternalMessageLogContext;
friend class QMessageLogger;
- friend class QDebug;
};
class QLoggingCategory;
-#ifdef Q_CC_MSVC
+#if defined(Q_CC_MSVC_ONLY)
# define QT_MESSAGE_LOGGER_NORETURN
#else
# define QT_MESSAGE_LOGGER_NORETURN Q_NORETURN
diff --git a/src/corelib/global/qlogging_p.h b/src/corelib/global/qlogging_p.h
index 9492f10f1f..bc331c80c0 100644
--- a/src/corelib/global/qlogging_p.h
+++ b/src/corelib/global/qlogging_p.h
@@ -16,6 +16,22 @@
//
#include <QtCore/private/qglobal_p.h>
+#include "qlogging.h"
+#include "qloggingcategory.h"
+
+#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(regularexpression)
+# if __has_include(<cxxabi.h>) && QT_CONFIG(backtrace)
+# include <optional>
+# include "qvarlengtharray.h"
+# define QLOGGING_USE_EXECINFO_BACKTRACE
+# define QLOGGING_HAVE_BACKTRACE
+# elif QT_CONFIG(cxx23_stacktrace)
+# include <optional>
+# include <stacktrace>
+# define QLOGGING_USE_STD_BACKTRACE
+# define QLOGGING_HAVE_BACKTRACE
+# endif
+#endif // QT_BOOTSTRAPPED
QT_BEGIN_NAMESPACE
@@ -25,6 +41,38 @@ Q_CORE_EXPORT bool shouldLogToStderr();
}
+class QInternalMessageLogContext : public QMessageLogContext
+{
+public:
+ static constexpr int DefaultBacktraceDepth = 32;
+
+#if defined(QLOGGING_USE_EXECINFO_BACKTRACE)
+ using BacktraceStorage = QVarLengthArray<void *, DefaultBacktraceDepth>;
+#elif defined(QLOGGING_USE_STD_BACKTRACE)
+ using BacktraceStorage = std::stacktrace;
+#else
+ using BacktraceStorage = bool; // dummy
+#endif
+
+ std::optional<BacktraceStorage> backtrace;
+
+ Q_ALWAYS_INLINE QInternalMessageLogContext(const QMessageLogContext &logContext)
+ {
+ int backtraceFrames = initFrom(logContext);
+ if (backtraceFrames)
+ populateBacktrace(backtraceFrames);
+ }
+ QInternalMessageLogContext(const QMessageLogContext &logContext,
+ const QLoggingCategory &categoryOverride)
+ : QInternalMessageLogContext(logContext)
+ {
+ category = categoryOverride.categoryName();
+ }
+
+ int initFrom(const QMessageLogContext &logContext);
+ void populateBacktrace(int frameCount);
+};
+
QT_END_NAMESPACE
#endif // QLOGGING_P_H
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index 8a2769a3ed..2398c0a1a4 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -10,6 +10,7 @@
#endif
#include <QtCore/qglobal.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qtmetamacros.h>
#if defined(__OBJC__) && !defined(__cplusplus)
@@ -212,7 +213,7 @@ namespace Qt {
ToolTip = Popup | Sheet,
SplashScreen = ToolTip | Dialog,
Desktop = 0x00000010 | Window,
- SubWindow = 0x00000012,
+ SubWindow = 0x00000012, // Note QTBUG-115729 before using
ForeignWindow = 0x00000020 | Window,
CoverWindow = 0x00000040 | Window,
@@ -422,7 +423,7 @@ namespace Qt {
enum ApplicationAttribute
{
// AA_ImmediateWidgetCreation = 0,
- // AA_MSWindowsUseDirect3DByDefault = 1,
+ AA_QtQuickUseDefaultSizePolicy = 1 QT_TECH_PREVIEW_API,
AA_DontShowIconsInMenus = 2,
AA_NativeWindows = 3,
AA_DontCreateNativeWidgetSiblings = 4,
@@ -431,7 +432,7 @@ namespace Qt {
AA_MacDontSwapCtrlAndMeta = 7,
AA_Use96Dpi = 8,
AA_DisableNativeVirtualKeyboard = 9,
- // AA_X11InitThreads = 10,
+ AA_DontUseNativeMenuWindows = 10,
AA_SynthesizeTouchForUnhandledMouseEvents = 11,
AA_SynthesizeMouseForUnhandledTouchEvents = 12,
#if QT_DEPRECATED_SINCE(6, 0)
@@ -461,7 +462,7 @@ namespace Qt {
AA_DisableShaderDiskCache = 27,
AA_DontShowShortcutsInContextMenus = 28,
AA_CompressTabletEvents = 29,
- // AA_DisableWindowContextHelpButton = 30,
+ AA_DontUsePopupWindows = 30,
AA_DisableSessionManager = 31,
// Add new attributes before this line
@@ -602,7 +603,11 @@ namespace Qt {
Key_twosuperior = 0x0b2,
Key_threesuperior = 0x0b3,
Key_acute = 0x0b4,
- Key_mu = 0x0b5,
+ Key_micro = 0x0b5,
+#if QT_DEPRECATED_SINCE(6, 11)
+ Key_mu Q_DECL_ENUMERATOR_DEPRECATED_X("This key was misnamed, use Key_micro instead")
+ = Key_micro,
+#endif
Key_paragraph = 0x0b6,
Key_periodcentered = 0x0b7,
Key_cedilla = 0x0b8,
@@ -1671,6 +1676,10 @@ namespace Qt {
VeryCoarseTimer
};
+ enum class TimerId {
+ Invalid = 0,
+ };
+
enum ScrollPhase {
NoScrollPhase = 0,
ScrollBegin,
@@ -1900,18 +1909,14 @@ public:
return combination;
}
#endif
-
- friend constexpr bool operator==(QKeyCombination lhs, QKeyCombination rhs) noexcept
+ bool operator<(QKeyCombination) const = delete;
+private:
+ friend constexpr bool comparesEqual(const QKeyCombination &lhs,
+ const QKeyCombination &rhs) noexcept
{
return lhs.combination == rhs.combination;
}
-
- friend constexpr bool operator!=(QKeyCombination lhs, QKeyCombination rhs) noexcept
- {
- return lhs.combination != rhs.combination;
- }
-
- bool operator<(QKeyCombination) const = delete;
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QKeyCombination)
};
Q_DECLARE_TYPEINFO(QKeyCombination, Q_RELOCATABLE_TYPE);
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
index 86ec1aee51..ddfade675a 100644
--- a/src/corelib/global/qnamespace.qdoc
+++ b/src/corelib/global/qnamespace.qdoc
@@ -84,6 +84,19 @@
QCoreApplication::testAttribute().
+ \value [since 6.7] AA_QtQuickUseDefaultSizePolicy Qt Quick Layouts use the built-in size
+ policy of \l Item. For example, when this is set, \l Button fills the available
+ width, but has a fixed height. When this is not set, it will use the default
+ sizing behavior of the layout it's in, which is to use its implicit size as the
+ preferred size. This is explained in detail in \l {Specifying preferred size} and
+ \l {Size constraints}. When this is set, the default size policy of the item
+ with the layout can be overridden by explicitly setting
+ \l{Layout::fillWidth}{Layout.fillWidth} or
+ \l{Layout::fillHeight}{Layout.fillHeight}.
+ \b Note: This API is considered tech preview and may change or be removed in future
+ versions of Qt.
+
+
\value AA_DontShowIconsInMenus Actions with the Icon property won't be
shown in any menus unless specifically set by the
QAction::iconVisibleInMenu property.
@@ -120,15 +133,15 @@
set to true won't be used as a native menubar (e.g, the menubar at
the top of the main screen on \macos).
- \value AA_MacDontSwapCtrlAndMeta Keyboard shortcuts on \macos are typically
+ \value AA_MacDontSwapCtrlAndMeta Keyboard shortcuts on Apple platforms are typically
based on the Command (or Cmd) keyboard modifier, represented by
the ⌘ symbol. For example, the 'Copy' action is Command+C (⌘+C).
To ease cross platform development Qt will by default remap Command
to the Qt::ControlModifier, to align with other platforms. This
allows creating keyboard shortcuts such as "Ctrl+J", which on
\macos will then map to Command+J, as expected by \macos users. The
- actual Control (or Ctrl) modifier on \macos, represented by ⌃, is
- mapped to Qt::MetaModifier.
+ actual Control (or Ctrl) modifier on Apple platforms, represented by ⌃,
+ is mapped to Qt::MetaModifier.
When this attribute is true Qt will not do the remapping, and pressing
the Command modifier will result in Qt::MetaModifier, while pressing
@@ -191,9 +204,9 @@
\value AA_UseStyleSheetPropagationInWidgetStyles By default, Qt Style Sheets
disable regular QWidget palette and font propagation. When this flag
- is enabled, font and palette changes propagate as though the user had
- manually called the corresponding QWidget methods. See
- \l{The Style Sheet Syntax#Inheritance}{The Style Sheet Syntax - Inheritance}
+ is enabled, font and palette changes done from a style sheet will propagate
+ a single time, when the style sheet is set.
+ See \l{The Style Sheet Syntax#Inheritance}{The Style Sheet Syntax - Inheritance}
for more details.
This value was added in Qt 5.7.
@@ -260,6 +273,17 @@
Currently supported on the Windows platform only.
This value was added in 5.15
+ \value AA_DontUseNativeMenuWindows Menu popup windows (e.g. context menus,
+ combo box menus, and non-native menubar menus) created while this
+ attribute is set to true will not be represented as native top
+ level windows, unless required by the implementation.
+ This value was added in Qt 6.8.
+
+ \value AA_DontUsePopupWindows When this attribute is set, popups will always appear
+ as items in the scene, rather than having their own dedicated windows.
+ Setting this attribute will only affect Qt Quick applications.
+ This value was added in Qt 6.8.
+
\omitvalue AA_AttributeCount
\omitvalue AA_EnableHighDpiScaling
\omitvalue AA_UseHighDpiPixmaps
@@ -617,7 +641,7 @@
connection types, using a bitwise OR. When Qt::UniqueConnection is
set, QObject::connect() will fail if the connection already exists
(i.e. if the same signal is already connected to the same slot
- for the same pair of objects). This flag was introduced in Qt 4.6.
+ for the same pair of objects).
\value SingleShotConnection
This is a flag that can be combined with any one of the above
@@ -980,8 +1004,7 @@
\value WA_Hover Forces Qt to generate paint events when the mouse
enters or leaves the widget. This feature is typically used when
- implementing custom styles; see the \l{widgets/styles}{Styles}
- example for details.
+ implementing custom styles.
\value WA_InputMethodEnabled Enables input methods for Asian languages.
Must be set when creating custom text editing widgets.
@@ -1442,6 +1465,7 @@
\value Key_Help
\value Key_Direction_L
\value Key_Direction_R
+
\value Key_Space
\value Key_Any
\value Key_Exclam
@@ -1533,7 +1557,8 @@
\value Key_twosuperior
\value Key_threesuperior
\value Key_acute
- \value Key_mu
+ \value [since 6.7] Key_micro
+ \value Key_mu Deprecated alias for Key_micro
\value Key_paragraph
\value Key_periodcentered
\value Key_cedilla
@@ -1578,6 +1603,7 @@
\value Key_ssharp
\value Key_division
\value Key_ydiaeresis
+
\value Key_Multi_key
\value Key_Codeinput
\value Key_SingleCandidate
@@ -2770,8 +2796,7 @@
\value CheckStateRole This role is used to obtain the checked state of
an item. (Qt::CheckState)
\value InitialSortOrderRole This role is used to obtain the initial sort order
- of a header view section. (Qt::SortOrder). This
- role was introduced in Qt 4.8.
+ of a header view section. (Qt::SortOrder).
Accessibility roles (with associated types):
@@ -2874,7 +2899,10 @@
\value ElideLeft The ellipsis should appear at the beginning of the text.
\value ElideRight The ellipsis should appear at the end of the text.
\value ElideMiddle The ellipsis should appear in the middle of the text.
- \value ElideNone Ellipsis should NOT appear in the text.
+ \value ElideNone Ellipsis should NOT appear in the text. When passed to functions such as
+ QFontMetrics::elidedText(), this will cause the full string to return unless
+ the text contains multi-length variants. Elision in this case must be done
+ by clipping to the component width.
Qt::ElideMiddle is normally the most appropriate choice for URLs (e.g.,
"\l{http://bugreports.qt.io/browse/QTWEBSITE-13}{http://bugreports.qt.../QTWEBSITE-13/}"),
@@ -3213,6 +3241,26 @@
*/
/*!
+ \enum Qt::TimerId
+ \since 6.8
+ \relates QObject
+ \relates QTimer
+ \relates QChronoTimer
+
+ This is used to represent timer IDs (for example, QTimer and QChronoTimer).
+ The underlying type is \c int. You can use \l qToUnderlying() to convert
+ Qt::TimerId to \c int.
+
+ \value Invalid Represents a no-op timer ID; it's usage depends on the
+ context, for example, this is the value returned by QObject::startTimer()
+ to indicate it failed to start a timer; whereas QChronoTimer::id() returns
+ this value when the timer is inactive, that is, \c timer.isActive()
+ returns \c false.
+
+ \sa QTimer::id(), QChronoTimer::id(), QObject::startTimer()
+*/
+
+/*!
\enum Qt::ScrollPhase
\since 5.2
@@ -3359,6 +3407,8 @@
\since 6.0
\brief The QKeyCombination class stores a combination of a key with optional modifiers.
+ \compares equality
+
The QKeyCombination class can be used to represent a combination of a key
with zero or more keyboard modifiers.
@@ -3441,14 +3491,14 @@
#endif
/*!
- \fn bool QKeyCombination::operator==(QKeyCombination lhs, QKeyCombination rhs) noexcept
+ \fn bool QKeyCombination::operator==(const QKeyCombination &lhs, const QKeyCombination &rhs)
Returns \c true if \a lhs and \a rhs have the same combination
of key and modifiers, and \c false otherwise.
*/
/*!
- \fn bool QKeyCombination::operator!=(QKeyCombination lhs, QKeyCombination rhs) noexcept
+ \fn bool QKeyCombination::operator!=(const QKeyCombination &lhs, const QKeyCombination &rhs)
Returns \c true if \a lhs and \a rhs have different combinations
of key and modifiers, otherwise \c false.
diff --git a/src/corelib/global/qnumeric.h b/src/corelib/global/qnumeric.h
index 7779c03515..2238c13da0 100644
--- a/src/corelib/global/qnumeric.h
+++ b/src/corelib/global/qnumeric.h
@@ -8,7 +8,9 @@
#pragma qt_class(QtNumeric)
#endif
-#include <QtCore/qglobal.h>
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qtcoreexports.h>
+#include <QtCore/qtypes.h>
#include <cmath>
#include <limits>
diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h
index 40c459991c..d40e6b964b 100644
--- a/src/corelib/global/qnumeric_p.h
+++ b/src/corelib/global/qnumeric_p.h
@@ -23,6 +23,10 @@
#include <limits>
#include <type_traits>
+#ifndef __has_extension
+# define __has_extension(X) 0
+#endif
+
#if !defined(Q_CC_MSVC) && defined(Q_OS_QNX)
# include <math.h>
# ifdef isnan
@@ -51,6 +55,8 @@ QT_END_NAMESPACE
QT_BEGIN_NAMESPACE
+class qfloat16;
+
namespace qnumeric_std_wrapper {
#if defined(QT_MATH_H_DEFINES_MACROS)
# undef QT_MATH_H_DEFINES_MACROS
@@ -145,15 +151,16 @@ namespace {
it's out of range. If the conversion is successful, the converted value is
stored in \a value; if it was not successful, \a value will contain the
minimum or maximum of T, depending on the sign of \a d. If \c T is
- unsigned, then \a value contains the absolute value of \a v.
+ unsigned, then \a value contains the absolute value of \a v. If \c T is \c
+ float, an underflow is also signalled by returning false and setting \a
+ value to zero.
This function works for v containing infinities, but not NaN. It's the
caller's responsibility to exclude that possibility before calling it.
*/
-template<typename T>
-static inline bool convertDoubleTo(double v, T *value, bool allow_precision_upgrade = true)
+template <typename T> static inline std::enable_if_t<std::is_integral_v<T>, bool>
+convertDoubleTo(double v, T *value, bool allow_precision_upgrade = true)
{
- static_assert(std::numeric_limits<T>::is_integer);
static_assert(std::is_integral_v<T>);
constexpr bool TypeIsLarger = std::numeric_limits<T>::digits > std::numeric_limits<double>::digits;
@@ -278,6 +285,116 @@ QT_WARNING_DISABLE_FLOAT_COMPARE
QT_WARNING_POP
}
+template <typename T> static
+std::enable_if_t<std::is_floating_point_v<T> || std::is_same_v<T, qfloat16>, bool>
+convertDoubleTo(double v, T *value, bool allow_precision_upgrade = true)
+{
+ Q_UNUSED(allow_precision_upgrade);
+ constexpr T Huge = std::numeric_limits<T>::infinity();
+
+ if constexpr (std::numeric_limits<double>::max_exponent <=
+ std::numeric_limits<T>::max_exponent) {
+ // no UB can happen
+ *value = T(v);
+ return true;
+ }
+
+#if defined(__SSE2__) && (defined(Q_CC_GNU) || __has_extension(gnu_asm))
+ // The x86 CVTSD2SH instruction from SSE2 does what we want:
+ // - converts out-of-range doubles to ±infinity and sets #O
+ // - converts underflows to zero and sets #U
+ // We need to clear any previously-stored exceptions from it before the
+ // operation (3-cycle cost) and obtain the new state afterwards (1 cycle).
+
+ unsigned csr = _MM_MASK_MASK; // clear stored exception indicators
+ auto sse_check_result = [&](auto result) {
+ if ((csr & (_MM_EXCEPT_UNDERFLOW | _MM_EXCEPT_OVERFLOW)) == 0)
+ return true;
+ if (csr & _MM_EXCEPT_OVERFLOW)
+ return false;
+
+ // According to IEEE 754[1], #U is also set when the result is tiny and
+ // inexact, but still non-zero, so detect that (this won't generate
+ // good code for types without hardware support).
+ // [1] https://en.wikipedia.org/wiki/Floating-point_arithmetic#Exception_handling
+ return result != 0;
+ };
+
+ // Written directly in assembly because both Clang and GCC have been
+ // observed to reorder the STMXCSR instruction above the conversion
+ // operation. MSVC generates horrid code when using the intrinsics anyway,
+ // so it's not a loss.
+ // See https://github.com/llvm/llvm-project/issues/83661.
+ if constexpr (std::is_same_v<T, float>) {
+# ifdef __AVX__
+ asm ("vldmxcsr %[csr]\n\t"
+ "vcvtsd2ss %[in], %[in], %[out]\n\t"
+ "vstmxcsr %[csr]"
+ : [csr] "+m" (csr), [out] "=v" (*value) : [in] "v" (v));
+# else
+ asm ("ldmxcsr %[csr]\n\t"
+ "cvtsd2ss %[in], %[out]\n\t"
+ "stmxcsr %[csr]"
+ : [csr] "+m" (csr), [out] "=v" (*value) : [in] "v" (v));
+# endif
+ return sse_check_result(*value);
+ }
+
+# if defined(__F16C__) || defined(__AVX512FP16__)
+ if constexpr (sizeof(T) == 2 && std::numeric_limits<T>::max_exponent == 16) {
+ // qfloat16 or std::float16_t, but not std::bfloat16_t or std::bfloat8_t
+ auto doConvert = [&](auto *out) {
+ asm ("vldmxcsr %[csr]\n\t"
+# ifdef __AVX512FP16__
+ // AVX512FP16 & AVX10 have an instruction for this
+ "vcvtsd2sh %[in], %[in], %[out]\n\t"
+# else
+ "vcvtsd2ss %[in], %[in], %[out]\n\t" // sets DEST[MAXVL-1:128] := 0
+ "vcvtps2ph %[rc], %[out], %[out]\n\t"
+# endif
+ "vstmxcsr %[csr]"
+ : [csr] "+m" (csr), [out] "=v" (*out)
+ : [in] "v" (v), [rc] "i" (_MM_FROUND_CUR_DIRECTION)
+ );
+ return sse_check_result(out);
+ };
+
+ if constexpr (std::is_same_v<T, qfloat16> && !std::is_void_v<typename T::NativeType>) {
+ typename T::NativeType tmp;
+ bool b = doConvert(&tmp);
+ *value = tmp;
+ return b;
+ } else {
+# ifndef Q_CC_CLANG
+ // Clang can only implement this if it has a native FP16 type
+ return doConvert(value);
+# endif
+ }
+ }
+# endif
+#endif // __SSE2__ && inline assembly
+
+ if (!qt_is_finite(v) && std::numeric_limits<T>::has_infinity) {
+ // infinity (or NaN)
+ *value = T(v);
+ return true;
+ }
+
+ // Check for in-range value to ensure the conversion is not UB (see the
+ // comment above for Standard language).
+ if (std::fabs(v) > (std::numeric_limits<T>::max)()) {
+ *value = v < 0 ? -Huge : Huge;
+ return false;
+ }
+
+ *value = T(v);
+ if (v != 0 && *value == 0) {
+ // Underflow through loss of precision
+ return false;
+ }
+ return true;
+}
+
template <typename T> inline bool add_overflow(T v1, T v2, T *r) { return qAddOverflow(v1, v2, r); }
template <typename T> inline bool sub_overflow(T v1, T v2, T *r) { return qSubOverflow(v1, v2, r); }
template <typename T> inline bool mul_overflow(T v1, T v2, T *r) { return qMulOverflow(v1, v2, r); }
diff --git a/src/corelib/global/qoperatingsystemversion.cpp b/src/corelib/global/qoperatingsystemversion.cpp
index c57483273f..cf6063fca0 100644
--- a/src/corelib/global/qoperatingsystemversion.cpp
+++ b/src/corelib/global/qoperatingsystemversion.cpp
@@ -34,7 +34,7 @@ QT_BEGIN_NAMESPACE
operating system version (as opposed to the kernel version number or
marketing version).
- Presently, Android, Apple Platforms (iOS, macOS, tvOS, and watchOS),
+ Presently, Android, Apple Platforms (iOS, macOS, tvOS, watchOS, and visionOS),
and Windows are supported.
The \a majorVersion(), \a minorVersion(), and \a microVersion() functions
@@ -98,6 +98,7 @@ QT_BEGIN_NAMESPACE
\value MacOS The Apple macOS operating system.
\value TvOS The Apple tvOS operating system.
\value WatchOS The Apple watchOS operating system.
+ \value VisionOS The Apple visionOS operating system.
\value Windows The Microsoft Windows operating system.
\value Unknown An unknown or unsupported operating system.
@@ -111,15 +112,11 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \fn QOperatingSystemVersion::current()
Returns a QOperatingSystemVersion indicating the current OS and its version number.
\sa currentType()
*/
-QOperatingSystemVersion QOperatingSystemVersion::current()
-{
- return QOperatingSystemVersionBase::current();
-}
-
QOperatingSystemVersionBase QOperatingSystemVersionBase::current()
{
static const QOperatingSystemVersionBase v = current_impl();
@@ -203,13 +200,13 @@ QOperatingSystemVersionBase QOperatingSystemVersionBase::current_impl()
}
#endif
-static inline int compareVersionComponents(int lhs, int rhs)
+static inline int compareVersionComponents(int lhs, int rhs) noexcept
{
return lhs >= 0 && rhs >= 0 ? lhs - rhs : 0;
}
int QOperatingSystemVersionBase::compare(QOperatingSystemVersionBase v1,
- QOperatingSystemVersionBase v2)
+ QOperatingSystemVersionBase v2) noexcept
{
if (v1.m_major == v2.m_major) {
if (v1.m_minor == v2.m_minor) {
@@ -306,11 +303,6 @@ int QOperatingSystemVersionBase::compare(QOperatingSystemVersionBase v1,
\sa type()
*/
-QString QOperatingSystemVersion::name() const
-{
- return QOperatingSystemVersionBase::name();
-}
-
QString QOperatingSystemVersionBase::name(QOperatingSystemVersionBase osversion)
{
switch (osversion.type()) {
@@ -334,6 +326,8 @@ QString QOperatingSystemVersionBase::name(QOperatingSystemVersionBase osversion)
return QStringLiteral("tvOS");
case QOperatingSystemVersionBase::WatchOS:
return QStringLiteral("watchOS");
+ case QOperatingSystemVersionBase::VisionOS:
+ return QStringLiteral("visionOS");
case QOperatingSystemVersionBase::Android:
return QStringLiteral("Android");
case QOperatingSystemVersionBase::Unknown:
@@ -480,6 +474,12 @@ const QOperatingSystemVersionBase QOperatingSystemVersion::Windows11_21H2;
const QOperatingSystemVersionBase QOperatingSystemVersion::Windows11_22H2;
/*!
+ \variable QOperatingSystemVersion::Windows11_23H2
+ \brief a version corresponding to Windows 11 Version 23H2 (version 10.0.22631).
+ \since 6.6
+ */
+
+/*!
\variable QOperatingSystemVersion::OSXMavericks
\brief a version corresponding to OS X Mavericks (version 10.9).
\since 5.9
@@ -559,6 +559,12 @@ const QOperatingSystemVersion QOperatingSystemVersion::MacOSMonterey =
const QOperatingSystemVersionBase QOperatingSystemVersion::MacOSVentura;
/*!
+ \variable QOperatingSystemVersion::MacOSSonoma
+ \brief a version corresponding to macOS Sonoma (version 14).
+ \since 6.5
+*/
+
+/*!
\variable QOperatingSystemVersion::AndroidJellyBean
\brief a version corresponding to Android Jelly Bean (version 4.1, API level 16).
\since 5.9
@@ -695,6 +701,12 @@ const QOperatingSystemVersionBase QOperatingSystemVersion::Android12L;
*/
const QOperatingSystemVersionBase QOperatingSystemVersion::Android13;
+/*!
+ \variable QOperatingSystemVersion::Android14
+ \brief a version corresponding to Android 14 (version 14.0, API level 34).
+ \since 6.7
+ */
+
#endif // !QT_BOOTSTRAPPED
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/corelib/global/qoperatingsystemversion.h b/src/corelib/global/qoperatingsystemversion.h
index 80a4cbbacb..a9f30dc275 100644
--- a/src/corelib/global/qoperatingsystemversion.h
+++ b/src/corelib/global/qoperatingsystemversion.h
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/qglobal.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qversionnumber.h>
#ifndef QOPERATINGSYSTEMVERSION_H
@@ -9,6 +10,12 @@
QT_BEGIN_NAMESPACE
+#if 0
+# pragma qt_class(QOperatingSystemVersionBase)
+# pragma qt_class(QOperatingSystemVersion)
+# pragma qt_sync_stop_processing // we have some ifdef'ery fooling syncqt
+#endif
+
class QString;
class QOperatingSystemVersionBase
@@ -23,7 +30,8 @@ public:
IOS,
TvOS,
WatchOS,
- Android
+ Android,
+ VisionOS
};
constexpr QOperatingSystemVersionBase(OSType osType,
@@ -50,6 +58,8 @@ public:
return TvOS;
#elif defined(Q_OS_WATCHOS)
return WatchOS;
+#elif defined(Q_OS_VISIONOS)
+ return VisionOS;
#elif defined(Q_OS_ANDROID)
return Android;
#else
@@ -73,36 +83,74 @@ public:
constexpr OSType type() const { return m_os; }
inline QString name() const { return name(*this); }
- friend bool operator>(QOperatingSystemVersionBase lhs, QOperatingSystemVersionBase rhs)
- { return lhs.type() == rhs.type() && QOperatingSystemVersionBase::compare(lhs, rhs) > 0; }
+protected:
+ static Q_CORE_EXPORT int compare(QOperatingSystemVersionBase v1,
+ QOperatingSystemVersionBase v2) noexcept;
- friend bool operator>=(QOperatingSystemVersionBase lhs, QOperatingSystemVersionBase rhs)
- { return lhs.type() == rhs.type() && QOperatingSystemVersionBase::compare(lhs, rhs) >= 0; }
+ friend Qt::partial_ordering compareThreeWay(const QOperatingSystemVersionBase &lhs,
+ const QOperatingSystemVersionBase &rhs) noexcept
+ {
+ if (lhs.type() != rhs.type())
+ return Qt::partial_ordering::unordered;
+ const int res = QOperatingSystemVersionBase::compare(lhs, rhs);
+ return Qt::compareThreeWay(res, 0);
+ }
+#ifdef __cpp_lib_three_way_comparison
+ friend std::partial_ordering
+ operator<=>(QOperatingSystemVersionBase lhs, QOperatingSystemVersionBase rhs) noexcept
+ { return compareThreeWay(lhs, rhs); }
+#else
+ friend bool
+ operator>(QOperatingSystemVersionBase lhs, QOperatingSystemVersionBase rhs) noexcept
+ { return is_gt(compareThreeWay(lhs, rhs)); }
- friend bool operator<(QOperatingSystemVersionBase lhs, QOperatingSystemVersionBase rhs)
- { return lhs.type() == rhs.type() && QOperatingSystemVersionBase::compare(lhs, rhs) < 0; }
+ friend bool
+ operator>=(QOperatingSystemVersionBase lhs, QOperatingSystemVersionBase rhs) noexcept
+ { return is_gteq(compareThreeWay(lhs, rhs)); }
- friend bool operator<=(QOperatingSystemVersionBase lhs, QOperatingSystemVersionBase rhs)
- { return lhs.type() == rhs.type() && QOperatingSystemVersionBase::compare(lhs, rhs) <= 0; }
+ friend bool
+ operator<(QOperatingSystemVersionBase lhs, QOperatingSystemVersionBase rhs) noexcept
+ { return is_lt(compareThreeWay(lhs, rhs)); }
-protected:
- static Q_CORE_EXPORT int compare(QOperatingSystemVersionBase v1,
- QOperatingSystemVersionBase v2);
+ friend bool
+ operator<=(QOperatingSystemVersionBase lhs, QOperatingSystemVersionBase rhs) noexcept
+ { return is_lteq(compareThreeWay(lhs, rhs)); }
+#endif
QOperatingSystemVersionBase() = default;
private:
static QOperatingSystemVersionBase current_impl();
-
OSType m_os;
int m_major;
int m_minor;
int m_micro;
};
-// ### Qt 7: Un-export the class, export relevant functions. Remove the enum.
-class Q_CORE_EXPORT QOperatingSystemVersion : public QOperatingSystemVersionBase
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED) && !defined(Q_QDOC)
+class QOperatingSystemVersionUnexported : public QOperatingSystemVersionBase
+{
+public:
+ using QOperatingSystemVersionBase::QOperatingSystemVersionBase;
+ constexpr QOperatingSystemVersionUnexported(QOperatingSystemVersionBase other) noexcept
+ : QOperatingSystemVersionBase(other) {}
+#else
+class QOperatingSystemVersion : public QOperatingSystemVersionBase
+{
+ using QOperatingSystemVersionUnexported = QOperatingSystemVersionBase;
+#endif
+
+ // ### Qt7: Regroup with the rest below
+ static constexpr QOperatingSystemVersionBase MacOSSonoma { QOperatingSystemVersionBase::MacOS, 14, 0 };
+ static constexpr QOperatingSystemVersionBase Android14 { QOperatingSystemVersionBase::Android, 14, 0 };
+ static constexpr QOperatingSystemVersionBase Windows11_23H2 { QOperatingSystemVersionBase::Windows, 10, 0, 22631 };
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED) && !defined(Q_QDOC)
+};
+
+class Q_CORE_EXPORT QOperatingSystemVersion : public QOperatingSystemVersionUnexported
{
+#endif
public:
// ### Qt7: Remove. Keep synchronized with QOperatingSystemVersionBase::OSType until then!
#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
@@ -113,15 +161,14 @@ public:
IOS,
TvOS,
WatchOS,
- Android
+ Android,
+ VisionOS
};
#endif
- // ### Qt7: remove the branch with static const variables. Then group and sort the inline ones.
- // Since the exported variables emit symbols they cannot be cherry-picked back to patch-releases
- // without breaking our BC promises. They must be fully inline but we cannot make that change
- // until Qt7
- // @note: New entries should be added after the if-def-ery until Qt 7!!
+ // ### Qt7: remove the branch with static const variables. Then group and
+ // sort the inline ones. Until then, new entries should be added to
+ // QOperatingSystemVersionUnexported.
#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
static const QOperatingSystemVersion Windows7;
static const QOperatingSystemVersion Windows8;
@@ -182,7 +229,7 @@ public:
static constexpr QOperatingSystemVersionBase AndroidPie { QOperatingSystemVersionBase::Android, 9, 0 };
static constexpr QOperatingSystemVersionBase Android10 { QOperatingSystemVersionBase::Android, 10, 0 };
static constexpr QOperatingSystemVersionBase Android11 { QOperatingSystemVersionBase::Android, 11, 0 };
-#endif // New (static constexpr) entries go here, only cherry-pick as far back as 6.3 (QTBUG-97808):
+#endif
static constexpr QOperatingSystemVersionBase Windows10_1809 { QOperatingSystemVersionBase::Windows, 10, 0, 17763 }; // RS5
static constexpr QOperatingSystemVersionBase Windows10_1903 { QOperatingSystemVersionBase::Windows, 10, 0, 18362 }; // 19H1
@@ -203,21 +250,24 @@ public:
static constexpr QOperatingSystemVersionBase MacOSVentura { QOperatingSystemVersionBase::MacOS, 13, 0 };
constexpr QOperatingSystemVersion(const QOperatingSystemVersionBase &osversion)
- : QOperatingSystemVersionBase(osversion) {}
+ : QOperatingSystemVersionUnexported(osversion) {}
constexpr QOperatingSystemVersion(OSType osType, int vmajor, int vminor = -1, int vmicro = -1)
- : QOperatingSystemVersionBase(QOperatingSystemVersionBase::OSType(osType), vmajor, vminor,
+ : QOperatingSystemVersionUnexported(QOperatingSystemVersionBase::OSType(osType), vmajor, vminor,
vmicro)
{
}
+#if QT_CORE_REMOVED_SINCE(6, 3) || defined(Q_QDOC)
static QOperatingSystemVersion current();
+#endif
static constexpr OSType currentType()
{
return OSType(QOperatingSystemVersionBase::currentType());
}
+#if QT_CORE_REMOVED_SINCE(6, 3) || defined(Q_QDOC)
QVersionNumber version() const { return QOperatingSystemVersionBase::version(); }
constexpr int majorVersion() const { return QOperatingSystemVersionBase::majorVersion(); }
@@ -226,10 +276,13 @@ public:
constexpr int segmentCount() const
{ return QOperatingSystemVersionBase::segmentCount(); }
+#endif // QT_CORE_REMOVED_SINCE(6, 3)
constexpr OSType type() const { return OSType(QOperatingSystemVersionBase::type()); }
- bool isAnyOfType(std::initializer_list<OSType> types) const;
+ QT7_ONLY(Q_CORE_EXPORT) bool isAnyOfType(std::initializer_list<OSType> types) const;
+#if QT_CORE_REMOVED_SINCE(6, 3) || defined(Q_QDOC)
QString name() const;
+#endif
private:
QOperatingSystemVersion() = default;
diff --git a/src/corelib/global/qrandom.cpp b/src/corelib/global/qrandom.cpp
index c1c2792736..fd742898f8 100644
--- a/src/corelib/global/qrandom.cpp
+++ b/src/corelib/global/qrandom.cpp
@@ -377,8 +377,9 @@ struct QRandomGenerator::SystemAndGlobalGenerators
struct PRNGLocker
{
+ Q_DISABLE_COPY_MOVE(PRNGLocker)
const bool locked;
- PRNGLocker(const QRandomGenerator *that)
+ Q_NODISCARD_CTOR explicit PRNGLocker(const QRandomGenerator *that)
: locked(that == globalNoInit())
{
if (locked)
@@ -765,7 +766,7 @@ inline QRandomGenerator::SystemGenerator &QRandomGenerator::SystemGenerator::sel
*/
/*!
- \fn template <typename UInt> void QRandomGenerator::fillRange(UInt *buffer, qsizetype count)
+ \fn template <typename UInt, QRandomGenerator::IfValidUInt<UInt> = true> void QRandomGenerator::fillRange(UInt *buffer, qsizetype count)
Generates \a count 32- or 64-bit quantities (depending on the type \c UInt)
and stores them in the buffer pointed by \a buffer. This is the most
@@ -781,7 +782,7 @@ inline QRandomGenerator::SystemGenerator &QRandomGenerator::SystemGenerator::sel
*/
/*!
- \fn template <typename UInt, size_t N> void QRandomGenerator::fillRange(UInt (&buffer)[N])
+ \fn template <typename UInt, size_t N, QRandomGenerator::IfValidUInt<UInt> = true> void QRandomGenerator::fillRange(UInt (&buffer)[N])
Generates \c N 32- or 64-bit quantities (depending on the type \c UInt) and
stores them in the \a buffer array. This is the most efficient way to
diff --git a/src/corelib/global/qsimd.cpp b/src/corelib/global/qsimd.cpp
index 7985283d15..8bc5381591 100644
--- a/src/corelib/global/qsimd.cpp
+++ b/src/corelib/global/qsimd.cpp
@@ -103,12 +103,7 @@ static const int features_indices[] = { 0 };
#endif
// end generated
-#if defined (Q_OS_NACL)
-static inline uint detectProcessorFeatures()
-{
- return 0;
-}
-#elif defined(Q_PROCESSOR_ARM)
+#if defined(Q_PROCESSOR_ARM)
static inline quint64 detectProcessorFeatures()
{
quint64 features = 0;
@@ -566,11 +561,6 @@ QT_FUNCTION_TARGET_BASELINE
uint64_t QT_MANGLE_NAMESPACE(qDetectCpuFeatures)()
{
auto minFeatureTest = minFeature;
-#if defined(Q_OS_LINUX) && defined(Q_PROCESSOR_ARM_64)
- // Yocto hard-codes CRC32+AES on. Since they are unlikely to be used
- // automatically by compilers, we can just add runtime check.
- minFeatureTest &= ~(CpuFeatureAES|CpuFeatureCRC32);
-#endif
#if defined(Q_PROCESSOR_X86_64) && defined(cpu_feature_shstk)
// Controlflow Enforcement Technology (CET) is an OS-assisted
// hardware-feature, meaning the CPUID bit may be disabled if the OS
@@ -766,7 +756,7 @@ QT_FUNCTION_TARGET(RDRND) qsizetype qRandomCpu(void *buffer, qsizetype count) no
ptr = qt_random_rdrnd(ptr, end);
return ptr - reinterpret_cast<unsigned *>(buffer);
}
-#elif defined(Q_PROCESSOR_X86) && !defined(Q_OS_NACL) && !defined(Q_PROCESSOR_ARM)
+#elif defined(Q_PROCESSOR_X86) && !defined(Q_PROCESSOR_ARM)
static bool checkRdrndWorks() noexcept { return false; }
#endif // Q_PROCESSOR_X86 && RDRND
diff --git a/src/corelib/global/qsimd_p.h b/src/corelib/global/qsimd_p.h
index 5d53ec7dd4..012eb6cf4f 100644
--- a/src/corelib/global/qsimd_p.h
+++ b/src/corelib/global/qsimd_p.h
@@ -218,29 +218,31 @@ asm(
// x86-64 sub-architecture version 3
//
// The Intel Core 4th generation was codenamed "Haswell" and introduced AVX2,
-// BMI1, BMI2, FMA, LZCNT, MOVBE, which makes it a good divider for a
-// sub-target for us. The first AMD processor with AVX2 support (Zen) has the
-// same features, but had already introduced BMI1 in the previous generation.
-// This feature set was chosen as the version 3 of the x86-64 ISA (x86-64-v3)
-// and is supported by GCC and Clang.
-//
-// macOS's fat binaries support the "x86_64h" sub-architecture and the GNU libc
-// ELF loader also supports a "haswell/" subdir (e.g., /usr/lib/haswell).
-# define ARCH_HASWELL_MACROS (__AVX2__ + __FMA__)
-# if ARCH_HASWELL_MACROS != 0
-# if ARCH_HASWELL_MACROS != 2
+// BMI1, BMI2, FMA, LZCNT, MOVBE. This feature set was chosen as the version 3
+// of the x86-64 ISA (x86-64-v3) and is supported by GCC and Clang. On systems
+// with the GNU libc, libraries with this feature can be installed on a
+// "glibc-hwcaps/x86-64-v3" subdir. macOS's fat binaries support the "x86_64h"
+// sub-architecture too.
+
+# if defined(__AVX2__)
+// List of features present with -march=x86-64-v3 and not architecturally
+// implied by __AVX2__
+# define ARCH_HASWELL_MACROS \
+ (__AVX2__ + __BMI__ + __BMI2__ + __F16C__ + __FMA__ + __LZCNT__ + __POPCNT__)
+# if ARCH_HASWELL_MACROS != 7
# error "Please enable all x86-64-v3 extensions; you probably want to use -march=haswell or -march=x86-64-v3 instead of -mavx2"
# endif
static_assert(ARCH_HASWELL_MACROS, "Undeclared identifiers indicate which features are missing.");
# define __haswell__ 1
+# undef ARCH_HASWELL_MACROS
# endif
-# undef ARCH_HASWELL_MACROS
// x86-64 sub-architecture version 4
//
// Similar to the above, x86-64-v4 matches the AVX512 variant of the Intel Core
// 6th generation (codename "Skylake"). AMD Zen4 is the their first processor
-// with AVX512 support and it includes all of these too.
+// with AVX512 support and it includes all of these too. The GNU libc subdir for
+// this is "glibc-hwcaps/x86-64-v4".
//
# define ARCH_SKX_MACROS (__AVX512F__ + __AVX512BW__ + __AVX512CD__ + __AVX512DQ__ + __AVX512VL__)
# if ARCH_SKX_MACROS != 0
@@ -323,12 +325,19 @@ static const uint64_t qCompilerCpuFeatures = 0
#if defined __ARM_NEON__
| CpuFeatureNEON
#endif
+#if !(defined(Q_OS_LINUX) && defined(Q_PROCESSOR_ARM_64))
+ // Yocto Project recipes enable Crypto extension for all ARMv8 configs,
+ // even for targets without the Crypto extension. That's wrong, but as
+ // the compiler never generates the code for them on their own, most
+ // code never notices the problem. But we would. By not setting the
+ // bits here, we force a runtime detection.
#if defined __ARM_FEATURE_CRC32
| CpuFeatureCRC32
#endif
#if defined __ARM_FEATURE_CRYPTO
| CpuFeatureAES
#endif
+#endif // Q_OS_LINUX && Q_PROCESSOR_ARM64
#if defined __mips_dsp
| CpuFeatureDSP
#endif
@@ -378,50 +387,6 @@ static inline uint64_t qCpuFeatures()
#define qCpuHasFeature(feature) (((qCompilerCpuFeatures & CpuFeature ## feature) == CpuFeature ## feature) \
|| ((qCpuFeatures() & CpuFeature ## feature) == CpuFeature ## feature))
-/*
- Small wrapper around x86's PAUSE and ARM's YIELD instructions.
-
- This is completely different from QThread::yieldCurrentThread(), which is
- an OS-level operation that takes the whole thread off the CPU.
-
- This is just preventing one SMT thread from filling a core's pipeline with
- speculated further loop iterations (which need to be expensively flushed on
- final success) when it could just give those pipeline slots to a second SMT
- thread that can do something useful with the core, such as unblocking this
- SMT thread :)
-
- So, instead of
-
- while (!condition)
- ;
-
- it's better to use
-
- while (!condition)
- qYieldCpu();
-*/
-static inline void qYieldCpu()
-{
-#if defined(Q_PROCESSOR_X86)
- _mm_pause();
-#elif defined(Q_PROCESSOR_ARM) && Q_PROCESSOR_ARM >= 7 /* yield was added in ARMv7 */
-# if __has_builtin(__builtin_arm_yield) /* e.g. Clang */
- __builtin_arm_yield();
-# elif defined(Q_OS_INTEGRITY) || \
- (defined(Q_CC_GNU) && !defined(Q_CC_CLANG))
- /*
- - Integrity is missing the arm_acle.h header
- - GCC doesn't have __yield() in arm_acle.h
- https://stackoverflow.com/a/70076751/134841
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105416
- */
- asm volatile("yield"); /* this works everywhere */
-# else
- __yield(); /* this is what should work everywhere */
-# endif
-#endif
-}
-
#ifdef __cplusplus
} // extern "C"
diff --git a/src/corelib/global/qsimd_x86.cpp b/src/corelib/global/qsimd_x86.cpp
index f1a08e05e8..9a3bd80b39 100644
--- a/src/corelib/global/qsimd_x86.cpp
+++ b/src/corelib/global/qsimd_x86.cpp
@@ -1,8 +1,8 @@
// Copyright (C) 2022 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
// This is a generated file. DO NOT EDIT.
// Please see util/x86simdgen/README.md
+
#include "qsimd_x86_p.h"
static const char features_string[] =
@@ -30,24 +30,28 @@ static const char features_string[] =
" avx512bw\0"
" avx512vl\0"
" avx512vbmi\0"
+ " waitpkg\0"
" avx512vbmi2\0"
" shstk\0"
" gfni\0"
" vaes\0"
- " avx512vnni\0"
" avx512bitalg\0"
" avx512vpopcntdq\0"
" hybrid\0"
" ibt\0"
" avx512fp16\0"
+ " raoint\0"
+ " cmpccxadd\0"
+ " avxifma\0"
+ " lam\0"
"\0";
static const uint16_t features_indices[] = {
0, 6, 12, 19, 24, 32, 40, 47,
55, 60, 65, 71, 78, 83, 89, 95,
104, 114, 122, 134, 144, 149, 159, 169,
- 181, 194, 201, 207, 213, 225, 239, 256,
- 264, 269,
+ 181, 190, 203, 210, 216, 222, 236, 253,
+ 261, 266, 278, 286, 297, 306,
};
enum X86CpuidLeaves {
@@ -57,6 +61,7 @@ enum X86CpuidLeaves {
Leaf07_00ECX,
Leaf07_00EDX,
Leaf07_01EAX,
+ Leaf07_01EDX,
Leaf13_01EAX,
Leaf80000001hECX,
Leaf80000008hEBX,
@@ -88,16 +93,20 @@ static const uint16_t x86_locators[] = {
Leaf07_00EBX*32 + 30, // avx512bw
Leaf07_00EBX*32 + 31, // avx512vl
Leaf07_00ECX*32 + 1, // avx512vbmi
+ Leaf07_00ECX*32 + 5, // waitpkg
Leaf07_00ECX*32 + 6, // avx512vbmi2
Leaf07_00ECX*32 + 7, // shstk
Leaf07_00ECX*32 + 8, // gfni
Leaf07_00ECX*32 + 9, // vaes
- Leaf07_00ECX*32 + 11, // avx512vnni
Leaf07_00ECX*32 + 12, // avx512bitalg
Leaf07_00ECX*32 + 14, // avx512vpopcntdq
Leaf07_00EDX*32 + 15, // hybrid
Leaf07_00EDX*32 + 20, // ibt
Leaf07_00EDX*32 + 23, // avx512fp16
+ Leaf07_01EAX*32 + 3, // raoint
+ Leaf07_01EAX*32 + 6, // cmpccxadd
+ Leaf07_01EAX*32 + 23, // avxifma
+ Leaf07_01EAX*32 + 26, // lam
};
struct X86Architecture
@@ -107,25 +116,31 @@ struct X86Architecture
};
static const struct X86Architecture x86_architectures[] = {
- { cpu_sapphirerapids, "Sapphire Rapids" },
- { cpu_tigerlake, "Tiger Lake" },
- { cpu_icelake_server, "Ice Lake (Server)" },
- { cpu_icelake_client, "Ice Lake (Client)" },
- { cpu_alderlake, "Alder Lake" },
- { cpu_cannonlake, "Cannon Lake" },
- { cpu_cooperlake, "Cooper Lake" },
- { cpu_cascadelake, "Cascade Lake" },
- { cpu_skylake_avx512, "Skylake (Avx512)" },
- { cpu_skylake, "Skylake" },
- { cpu_tremont, "Tremont" },
- { cpu_broadwell, "Broadwell" },
- { cpu_haswell, "Haswell" },
- { cpu_goldmont, "Goldmont" },
- { cpu_ivybridge, "Ivy Bridge" },
- { cpu_silvermont, "Silvermont" },
- { cpu_sandybridge, "Sandy Bridge" },
- { cpu_westmere, "Westmere" },
{ cpu_core2, "Core2" },
+ { cpu_westmere, "Westmere" },
+ { cpu_sandybridge, "Sandy Bridge" },
+ { cpu_silvermont, "Silvermont" },
+ { cpu_ivybridge, "Ivy Bridge" },
+ { cpu_goldmont, "Goldmont" },
+ { cpu_haswell, "Haswell" },
+ { cpu_broadwell, "Broadwell" },
+ { cpu_tremont, "Tremont" },
+ { cpu_skylake, "Skylake" },
+ { cpu_skylake_avx512, "Skylake (Avx512)" },
+ { cpu_cascadelake, "Cascade Lake" },
+ { cpu_cooperlake, "Cooper Lake" },
+ { cpu_cannonlake, "Cannon Lake" },
+ { cpu_gracemont, "Gracemont" },
+ { cpu_icelake_client, "Ice Lake (Client)" },
+ { cpu_icelake_server, "Ice Lake (Server)" },
+ { cpu_crestmont, "Crestmont" },
+ { cpu_tigerlake, "Tiger Lake" },
+ { cpu_clearwaterforest, "Clearwater Forest" },
+ { cpu_grandridge, "Grand Ridge" },
+ { cpu_raptorcove, "Raptor Cove" },
+ { cpu_redwoodcove, "Redwood Cove" },
+ { cpu_emeraldrapids, "Emerald Rapids" },
+ { cpu_graniterapids, "Granite Rapids" },
};
enum XSaveBits {
@@ -168,10 +183,10 @@ static const uint64_t XSaveReq_AvxState = 0
| cpu_feature_avx512vbmi
| cpu_feature_avx512vbmi2
| cpu_feature_vaes
- | cpu_feature_avx512vnni
| cpu_feature_avx512bitalg
| cpu_feature_avx512vpopcntdq
- | cpu_feature_avx512fp16;
+ | cpu_feature_avx512fp16
+ | cpu_feature_avxifma;
// List of features requiring XSave_Avx512State
static const uint64_t XSaveReq_Avx512State = 0
@@ -183,7 +198,6 @@ static const uint64_t XSaveReq_Avx512State = 0
| cpu_feature_avx512vl
| cpu_feature_avx512vbmi
| cpu_feature_avx512vbmi2
- | cpu_feature_avx512vnni
| cpu_feature_avx512bitalg
| cpu_feature_avx512vpopcntdq
| cpu_feature_avx512fp16;
diff --git a/src/corelib/global/qsimd_x86_p.h b/src/corelib/global/qsimd_x86_p.h
index 3e7427b0b1..1ec89d0c6c 100644
--- a/src/corelib/global/qsimd_x86_p.h
+++ b/src/corelib/global/qsimd_x86_p.h
@@ -1,5 +1,7 @@
// Copyright (C) 2022 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// This is a generated file. DO NOT EDIT.
+// Please see util/x86simdgen/README.md
//
// W A R N I N G
@@ -50,11 +52,11 @@
// in CPUID Leaf 7, Sub-leaf 0, ECX:
#define cpu_feature_avx512vbmi (UINT64_C(1) << 23)
-#define cpu_feature_avx512vbmi2 (UINT64_C(1) << 24)
-#define cpu_feature_shstk (UINT64_C(1) << 25)
-#define cpu_feature_gfni (UINT64_C(1) << 26)
-#define cpu_feature_vaes (UINT64_C(1) << 27)
-#define cpu_feature_avx512vnni (UINT64_C(1) << 28)
+#define cpu_feature_waitpkg (UINT64_C(1) << 24)
+#define cpu_feature_avx512vbmi2 (UINT64_C(1) << 25)
+#define cpu_feature_shstk (UINT64_C(1) << 26)
+#define cpu_feature_gfni (UINT64_C(1) << 27)
+#define cpu_feature_vaes (UINT64_C(1) << 28)
#define cpu_feature_avx512bitalg (UINT64_C(1) << 29)
#define cpu_feature_avx512vpopcntdq (UINT64_C(1) << 30)
@@ -63,6 +65,12 @@
#define cpu_feature_ibt (UINT64_C(1) << 32)
#define cpu_feature_avx512fp16 (UINT64_C(1) << 33)
+// in CPUID Leaf 7, Sub-leaf 1, EAX:
+#define cpu_feature_raoint (UINT64_C(1) << 34)
+#define cpu_feature_cmpccxadd (UINT64_C(1) << 35)
+#define cpu_feature_avxifma (UINT64_C(1) << 36)
+#define cpu_feature_lam (UINT64_C(1) << 37)
+
// CPU architectures
#define cpu_x86_64 (0 \
| cpu_feature_sse2)
@@ -89,42 +97,65 @@
| cpu_feature_rdseed)
#define cpu_bdx (cpu_bdw)
#define cpu_skl (cpu_bdw)
-#define cpu_adl (cpu_skl \
- | cpu_feature_gfni \
- | cpu_feature_vaes \
- | cpu_feature_shstk \
- | cpu_feature_ibt)
#define cpu_skx (cpu_skl \
| cpu_feature_avx512f \
| cpu_feature_avx512dq \
| cpu_feature_avx512cd \
| cpu_feature_avx512bw \
| cpu_feature_avx512vl)
-#define cpu_clx (cpu_skx \
- | cpu_feature_avx512vnni)
+#define cpu_clx (cpu_skx)
#define cpu_cpx (cpu_clx)
-#define cpu_cnl (cpu_skx \
+#define cpu_plc (cpu_skx \
| cpu_feature_avx512ifma \
| cpu_feature_avx512vbmi)
-#define cpu_icl (cpu_cnl \
+#define cpu_snc (cpu_plc \
| cpu_feature_avx512vbmi2 \
| cpu_feature_gfni \
| cpu_feature_vaes \
- | cpu_feature_avx512vnni \
| cpu_feature_avx512bitalg \
| cpu_feature_avx512vpopcntdq)
-#define cpu_icx (cpu_icl)
-#define cpu_tgl (cpu_icl \
+#define cpu_wlc (cpu_snc \
| cpu_feature_shstk \
| cpu_feature_ibt)
-#define cpu_spr (cpu_tgl)
+#define cpu_glc (cpu_wlc \
+ | cpu_feature_waitpkg)
+#define cpu_rpc (cpu_glc)
+#define cpu_rwc (cpu_rpc)
#define cpu_slm (cpu_wsm \
| cpu_feature_rdrnd \
| cpu_feature_movbe)
#define cpu_glm (cpu_slm \
| cpu_feature_rdseed)
#define cpu_tnt (cpu_glm \
- | cpu_feature_gfni)
+ | cpu_feature_gfni \
+ | cpu_feature_waitpkg)
+#define cpu_grt (cpu_skl \
+ | cpu_feature_gfni \
+ | cpu_feature_vaes \
+ | cpu_feature_shstk \
+ | cpu_feature_ibt \
+ | cpu_feature_waitpkg)
+#define cpu_cmt (cpu_grt \
+ | cpu_feature_cmpccxadd \
+ | cpu_feature_avxifma)
+#define cpu_cnl (cpu_plc)
+#define cpu_icl (cpu_snc)
+#define cpu_tgl (cpu_wlc)
+#define cpu_adl (cpu_grt)
+#define cpu_rpl (cpu_grt)
+#define cpu_mtl (cpu_cmt)
+#define cpu_arl (cpu_cmt)
+#define cpu_lnl (cpu_cmt)
+#define cpu_icx (cpu_snc)
+#define cpu_spr (cpu_glc)
+#define cpu_emr (cpu_spr)
+#define cpu_gnr (cpu_glc)
+#define cpu_srf (cpu_cmt \
+ | cpu_feature_cmpccxadd \
+ | cpu_feature_avxifma)
+#define cpu_grr (cpu_srf \
+ | cpu_feature_raoint)
+#define cpu_cwf (cpu_srf)
#define cpu_nehalem (cpu_nhm)
#define cpu_westmere (cpu_wsm)
#define cpu_sandybridge (cpu_snb)
@@ -135,15 +166,32 @@
#define cpu_skylake_avx512 (cpu_skx)
#define cpu_cascadelake (cpu_clx)
#define cpu_cooperlake (cpu_cpx)
+#define cpu_palmcove (cpu_plc)
#define cpu_cannonlake (cpu_cnl)
+#define cpu_sunnycove (cpu_snc)
#define cpu_icelake_client (cpu_icl)
#define cpu_icelake_server (cpu_icx)
+#define cpu_willowcove (cpu_wlc)
+#define cpu_tigerlake (cpu_tgl)
+#define cpu_goldencove (cpu_glc)
#define cpu_alderlake (cpu_adl)
+#define cpu_raptorcove (cpu_rpc)
+#define cpu_raptorlake (cpu_rpl)
+#define cpu_redwoodcove (cpu_rwc)
+#define cpu_meteorlake (cpu_mtl)
+#define cpu_arrowlake (cpu_arl)
+#define cpu_lunarlake (cpu_lnl)
#define cpu_sapphirerapids (cpu_spr)
-#define cpu_tigerlake (cpu_tgl)
+#define cpu_emeraldrapids (cpu_emr)
+#define cpu_graniterapids (cpu_gnr)
#define cpu_silvermont (cpu_slm)
#define cpu_goldmont (cpu_glm)
#define cpu_tremont (cpu_tnt)
+#define cpu_gracemont (cpu_grt)
+#define cpu_crestmont (cpu_cmt)
+#define cpu_grandridge (cpu_grr)
+#define cpu_sierraforest (cpu_srf)
+#define cpu_clearwaterforest (cpu_cwf)
// __attribute__ target strings for GCC and Clang
#define QT_FUNCTION_TARGET_STRING_SSE2 "sse2"
@@ -170,16 +218,20 @@
#define QT_FUNCTION_TARGET_STRING_AVX512BW "avx512bw,avx512f"
#define QT_FUNCTION_TARGET_STRING_AVX512VL "avx512vl,avx512f"
#define QT_FUNCTION_TARGET_STRING_AVX512VBMI "avx512vbmi,avx512f"
+#define QT_FUNCTION_TARGET_STRING_WAITPKG "waitpkg"
#define QT_FUNCTION_TARGET_STRING_AVX512VBMI2 "avx512vbmi2,avx512f"
#define QT_FUNCTION_TARGET_STRING_SHSTK "shstk"
#define QT_FUNCTION_TARGET_STRING_GFNI "gfni"
#define QT_FUNCTION_TARGET_STRING_VAES "vaes,avx2,avx,aes"
-#define QT_FUNCTION_TARGET_STRING_AVX512VNNI "avx512vnni,avx512f"
#define QT_FUNCTION_TARGET_STRING_AVX512BITALG "avx512bitalg,avx512f"
#define QT_FUNCTION_TARGET_STRING_AVX512VPOPCNTDQ "avx512vpopcntdq,avx512f"
#define QT_FUNCTION_TARGET_STRING_HYBRID "hybrid"
#define QT_FUNCTION_TARGET_STRING_IBT "ibt"
#define QT_FUNCTION_TARGET_STRING_AVX512FP16 "avx512fp16,avx512f,f16c"
+#define QT_FUNCTION_TARGET_STRING_RAOINT "raoint"
+#define QT_FUNCTION_TARGET_STRING_CMPCCXADD "cmpccxadd"
+#define QT_FUNCTION_TARGET_STRING_AVXIFMA "avxifma,avx"
+#define QT_FUNCTION_TARGET_STRING_LAM "lam"
#define QT_FUNCTION_TARGET_STRING_ARCH_X86_64 "sse2"
#define QT_FUNCTION_TARGET_STRING_ARCH_CORE2 QT_FUNCTION_TARGET_STRING_ARCH_X86_64 ",sse3,ssse3,cx16"
#define QT_FUNCTION_TARGET_STRING_ARCH_NHM QT_FUNCTION_TARGET_STRING_ARCH_CORE2 ",sse4.1,sse4.2,popcnt"
@@ -190,18 +242,35 @@
#define QT_FUNCTION_TARGET_STRING_ARCH_BDW QT_FUNCTION_TARGET_STRING_ARCH_HSW ",adx,rdseed"
#define QT_FUNCTION_TARGET_STRING_ARCH_BDX QT_FUNCTION_TARGET_STRING_ARCH_BDW
#define QT_FUNCTION_TARGET_STRING_ARCH_SKL QT_FUNCTION_TARGET_STRING_ARCH_BDW ",xsavec,xsaves"
-#define QT_FUNCTION_TARGET_STRING_ARCH_ADL QT_FUNCTION_TARGET_STRING_ARCH_SKL ",avxvnni,gfni,vaes,vpclmulqdq,serialize,shstk,cldemote,movdiri,movdir64b,ibt,waitpkg,keylocker"
#define QT_FUNCTION_TARGET_STRING_ARCH_SKX QT_FUNCTION_TARGET_STRING_ARCH_SKL ",avx512f,avx512dq,avx512cd,avx512bw,avx512vl"
#define QT_FUNCTION_TARGET_STRING_ARCH_CLX QT_FUNCTION_TARGET_STRING_ARCH_SKX ",avx512vnni"
#define QT_FUNCTION_TARGET_STRING_ARCH_CPX QT_FUNCTION_TARGET_STRING_ARCH_CLX ",avx512bf16"
-#define QT_FUNCTION_TARGET_STRING_ARCH_CNL QT_FUNCTION_TARGET_STRING_ARCH_SKX ",avx512ifma,avx512vbmi"
-#define QT_FUNCTION_TARGET_STRING_ARCH_ICL QT_FUNCTION_TARGET_STRING_ARCH_CNL ",avx512vbmi2,gfni,vaes,vpclmulqdq,avx512vnni,avx512bitalg,avx512vpopcntdq"
-#define QT_FUNCTION_TARGET_STRING_ARCH_ICX QT_FUNCTION_TARGET_STRING_ARCH_ICL ",pconfig"
-#define QT_FUNCTION_TARGET_STRING_ARCH_TGL QT_FUNCTION_TARGET_STRING_ARCH_ICL ",avx512vp2intersect,shstk,,movdiri,movdir64b,ibt,keylocker"
-#define QT_FUNCTION_TARGET_STRING_ARCH_SPR QT_FUNCTION_TARGET_STRING_ARCH_TGL ",avx512bf16,amxtile,amxbf16,amxint8,avxvnni,cldemote,pconfig,waitpkg,serialize,tsxldtrk,uintr"
+#define QT_FUNCTION_TARGET_STRING_ARCH_PLC QT_FUNCTION_TARGET_STRING_ARCH_SKX ",avx512ifma,avx512vbmi"
+#define QT_FUNCTION_TARGET_STRING_ARCH_SNC QT_FUNCTION_TARGET_STRING_ARCH_PLC ",avx512vbmi2,gfni,vaes,vpclmulqdq,avx512vnni,avx512bitalg,avx512vpopcntdq"
+#define QT_FUNCTION_TARGET_STRING_ARCH_WLC QT_FUNCTION_TARGET_STRING_ARCH_SNC ",shstk,movdiri,movdir64b,ibt,keylocker"
+#define QT_FUNCTION_TARGET_STRING_ARCH_GLC QT_FUNCTION_TARGET_STRING_ARCH_WLC ",avx512bf16,avxvnni,cldemote,waitpkg,serialize,uintr"
+#define QT_FUNCTION_TARGET_STRING_ARCH_RPC QT_FUNCTION_TARGET_STRING_ARCH_GLC
+#define QT_FUNCTION_TARGET_STRING_ARCH_RWC QT_FUNCTION_TARGET_STRING_ARCH_RPC ",prefetchiti"
#define QT_FUNCTION_TARGET_STRING_ARCH_SLM QT_FUNCTION_TARGET_STRING_ARCH_WSM ",rdrnd,movbe"
#define QT_FUNCTION_TARGET_STRING_ARCH_GLM QT_FUNCTION_TARGET_STRING_ARCH_SLM ",fsgsbase,rdseed,lzcnt,xsavec,xsaves"
#define QT_FUNCTION_TARGET_STRING_ARCH_TNT QT_FUNCTION_TARGET_STRING_ARCH_GLM ",clwb,gfni,cldemote,waitpkg,movdiri,movdir64b"
+#define QT_FUNCTION_TARGET_STRING_ARCH_GRT QT_FUNCTION_TARGET_STRING_ARCH_SKL ",avxvnni,gfni,vaes,vpclmulqdq,serialize,shstk,cldemote,movdiri,movdir64b,ibt,waitpkg,keylocker"
+#define QT_FUNCTION_TARGET_STRING_ARCH_CMT QT_FUNCTION_TARGET_STRING_ARCH_GRT ",cmpccxadd,avxifma,avxneconvert,avxvnniint8"
+#define QT_FUNCTION_TARGET_STRING_ARCH_CNL QT_FUNCTION_TARGET_STRING_ARCH_PLC
+#define QT_FUNCTION_TARGET_STRING_ARCH_ICL QT_FUNCTION_TARGET_STRING_ARCH_SNC
+#define QT_FUNCTION_TARGET_STRING_ARCH_TGL QT_FUNCTION_TARGET_STRING_ARCH_WLC
+#define QT_FUNCTION_TARGET_STRING_ARCH_ADL QT_FUNCTION_TARGET_STRING_ARCH_GRT
+#define QT_FUNCTION_TARGET_STRING_ARCH_RPL QT_FUNCTION_TARGET_STRING_ARCH_GRT
+#define QT_FUNCTION_TARGET_STRING_ARCH_MTL QT_FUNCTION_TARGET_STRING_ARCH_CMT
+#define QT_FUNCTION_TARGET_STRING_ARCH_ARL QT_FUNCTION_TARGET_STRING_ARCH_CMT
+#define QT_FUNCTION_TARGET_STRING_ARCH_LNL QT_FUNCTION_TARGET_STRING_ARCH_CMT
+#define QT_FUNCTION_TARGET_STRING_ARCH_ICX QT_FUNCTION_TARGET_STRING_ARCH_SNC ",pconfig"
+#define QT_FUNCTION_TARGET_STRING_ARCH_SPR QT_FUNCTION_TARGET_STRING_ARCH_GLC ",pconfig,amx-tile,amx-bf16,amx-int8"
+#define QT_FUNCTION_TARGET_STRING_ARCH_EMR QT_FUNCTION_TARGET_STRING_ARCH_SPR
+#define QT_FUNCTION_TARGET_STRING_ARCH_GNR QT_FUNCTION_TARGET_STRING_ARCH_GLC ",pconfig,amx-tile,amx-bf16,amx-int8,amx-fp16,amx-complex"
+#define QT_FUNCTION_TARGET_STRING_ARCH_SRF QT_FUNCTION_TARGET_STRING_ARCH_CMT ",cmpccxadd,avxifma,avxneconvert,avxvnniint8"
+#define QT_FUNCTION_TARGET_STRING_ARCH_GRR QT_FUNCTION_TARGET_STRING_ARCH_SRF ",raoint"
+#define QT_FUNCTION_TARGET_STRING_ARCH_CWF QT_FUNCTION_TARGET_STRING_ARCH_SRF
#define QT_FUNCTION_TARGET_STRING_ARCH_NEHALEM QT_FUNCTION_TARGET_STRING_ARCH_NHM
#define QT_FUNCTION_TARGET_STRING_ARCH_WESTMERE QT_FUNCTION_TARGET_STRING_ARCH_WSM
#define QT_FUNCTION_TARGET_STRING_ARCH_SANDYBRIDGE QT_FUNCTION_TARGET_STRING_ARCH_SNB
@@ -212,15 +281,32 @@
#define QT_FUNCTION_TARGET_STRING_ARCH_SKYLAKE_AVX512 QT_FUNCTION_TARGET_STRING_ARCH_SKX
#define QT_FUNCTION_TARGET_STRING_ARCH_CASCADELAKE QT_FUNCTION_TARGET_STRING_ARCH_CLX
#define QT_FUNCTION_TARGET_STRING_ARCH_COOPERLAKE QT_FUNCTION_TARGET_STRING_ARCH_CPX
+#define QT_FUNCTION_TARGET_STRING_ARCH_PALMCOVE QT_FUNCTION_TARGET_STRING_ARCH_PLC
#define QT_FUNCTION_TARGET_STRING_ARCH_CANNONLAKE QT_FUNCTION_TARGET_STRING_ARCH_CNL
+#define QT_FUNCTION_TARGET_STRING_ARCH_SUNNYCOVE QT_FUNCTION_TARGET_STRING_ARCH_SNC
#define QT_FUNCTION_TARGET_STRING_ARCH_ICELAKE_CLIENT QT_FUNCTION_TARGET_STRING_ARCH_ICL
#define QT_FUNCTION_TARGET_STRING_ARCH_ICELAKE_SERVER QT_FUNCTION_TARGET_STRING_ARCH_ICX
+#define QT_FUNCTION_TARGET_STRING_ARCH_WILLOWCOVE QT_FUNCTION_TARGET_STRING_ARCH_WLC
+#define QT_FUNCTION_TARGET_STRING_ARCH_TIGERLAKE QT_FUNCTION_TARGET_STRING_ARCH_TGL
+#define QT_FUNCTION_TARGET_STRING_ARCH_GOLDENCOVE QT_FUNCTION_TARGET_STRING_ARCH_GLC
#define QT_FUNCTION_TARGET_STRING_ARCH_ALDERLAKE QT_FUNCTION_TARGET_STRING_ARCH_ADL
+#define QT_FUNCTION_TARGET_STRING_ARCH_RAPTORCOVE QT_FUNCTION_TARGET_STRING_ARCH_RPC
+#define QT_FUNCTION_TARGET_STRING_ARCH_RAPTORLAKE QT_FUNCTION_TARGET_STRING_ARCH_RPL
+#define QT_FUNCTION_TARGET_STRING_ARCH_REDWOODCOVE QT_FUNCTION_TARGET_STRING_ARCH_RWC
+#define QT_FUNCTION_TARGET_STRING_ARCH_METEORLAKE QT_FUNCTION_TARGET_STRING_ARCH_MTL
+#define QT_FUNCTION_TARGET_STRING_ARCH_ARROWLAKE QT_FUNCTION_TARGET_STRING_ARCH_ARL
+#define QT_FUNCTION_TARGET_STRING_ARCH_LUNARLAKE QT_FUNCTION_TARGET_STRING_ARCH_LNL
#define QT_FUNCTION_TARGET_STRING_ARCH_SAPPHIRERAPIDS QT_FUNCTION_TARGET_STRING_ARCH_SPR
-#define QT_FUNCTION_TARGET_STRING_ARCH_TIGERLAKE QT_FUNCTION_TARGET_STRING_ARCH_TGL
+#define QT_FUNCTION_TARGET_STRING_ARCH_EMERALDRAPIDS QT_FUNCTION_TARGET_STRING_ARCH_EMR
+#define QT_FUNCTION_TARGET_STRING_ARCH_GRANITERAPIDS QT_FUNCTION_TARGET_STRING_ARCH_GNR
#define QT_FUNCTION_TARGET_STRING_ARCH_SILVERMONT QT_FUNCTION_TARGET_STRING_ARCH_SLM
#define QT_FUNCTION_TARGET_STRING_ARCH_GOLDMONT QT_FUNCTION_TARGET_STRING_ARCH_GLM
#define QT_FUNCTION_TARGET_STRING_ARCH_TREMONT QT_FUNCTION_TARGET_STRING_ARCH_TNT
+#define QT_FUNCTION_TARGET_STRING_ARCH_GRACEMONT QT_FUNCTION_TARGET_STRING_ARCH_GRT
+#define QT_FUNCTION_TARGET_STRING_ARCH_CRESTMONT QT_FUNCTION_TARGET_STRING_ARCH_CMT
+#define QT_FUNCTION_TARGET_STRING_ARCH_GRANDRIDGE QT_FUNCTION_TARGET_STRING_ARCH_GRR
+#define QT_FUNCTION_TARGET_STRING_ARCH_SIERRAFOREST QT_FUNCTION_TARGET_STRING_ARCH_SRF
+#define QT_FUNCTION_TARGET_STRING_ARCH_CLEARWATERFOREST QT_FUNCTION_TARGET_STRING_ARCH_CWF
static const uint64_t _compilerCpuFeatures = 0
#ifdef __SSE2__
@@ -295,6 +381,9 @@ static const uint64_t _compilerCpuFeatures = 0
#ifdef __AVX512VBMI__
| cpu_feature_avx512vbmi
#endif
+#ifdef __WAITPKG__
+ | cpu_feature_waitpkg
+#endif
#ifdef __AVX512VBMI2__
| cpu_feature_avx512vbmi2
#endif
@@ -307,9 +396,6 @@ static const uint64_t _compilerCpuFeatures = 0
#ifdef __VAES__
| cpu_feature_vaes
#endif
-#ifdef __AVX512VNNI__
- | cpu_feature_avx512vnni
-#endif
#ifdef __AVX512BITALG__
| cpu_feature_avx512bitalg
#endif
@@ -325,6 +411,18 @@ static const uint64_t _compilerCpuFeatures = 0
#ifdef __AVX512FP16__
| cpu_feature_avx512fp16
#endif
+#ifdef __RAOINT__
+ | cpu_feature_raoint
+#endif
+#ifdef __CMPCCXADD__
+ | cpu_feature_cmpccxadd
+#endif
+#ifdef __AVXIFMA__
+ | cpu_feature_avxifma
+#endif
+#ifdef __LAM__
+ | cpu_feature_lam
+#endif
;
#if (defined __cplusplus) && __cplusplus >= 201103L
@@ -353,16 +451,20 @@ enum X86CpuFeatures : uint64_t {
CpuFeatureAVX512BW = cpu_feature_avx512bw, ///< AVX512 Byte & Word
CpuFeatureAVX512VL = cpu_feature_avx512vl, ///< AVX512 Vector Length
CpuFeatureAVX512VBMI = cpu_feature_avx512vbmi, ///< AVX512 Vector Byte Manipulation Instructions
+ CpuFeatureWAITPKG = cpu_feature_waitpkg, ///< User-Level Monitor / Wait
CpuFeatureAVX512VBMI2 = cpu_feature_avx512vbmi2, ///< AVX512 Vector Byte Manipulation Instructions 2
CpuFeatureSHSTK = cpu_feature_shstk, ///< Control Flow Enforcement Technology Shadow Stack
CpuFeatureGFNI = cpu_feature_gfni, ///< Galois Field new instructions
CpuFeatureVAES = cpu_feature_vaes, ///< 256- and 512-bit AES
- CpuFeatureAVX512VNNI = cpu_feature_avx512vnni, ///< AVX512 Vector Neural Network Instructions
CpuFeatureAVX512BITALG = cpu_feature_avx512bitalg, ///< AVX512 Bit Algorithms
CpuFeatureAVX512VPOPCNTDQ = cpu_feature_avx512vpopcntdq, ///< AVX512 Population Count
CpuFeatureHYBRID = cpu_feature_hybrid, ///< Hybrid processor
CpuFeatureIBT = cpu_feature_ibt, ///< Control Flow Enforcement Technology Indirect Branch Tracking
CpuFeatureAVX512FP16 = cpu_feature_avx512fp16, ///< AVX512 16-bit Floating Point
+ CpuFeatureRAOINT = cpu_feature_raoint, ///< Remote Atomic Operations, Integer
+ CpuFeatureCMPCCXADD = cpu_feature_cmpccxadd, ///< CMPccXADD instructions
+ CpuFeatureAVXIFMA = cpu_feature_avxifma, ///< AVX-IFMA instructions
+ CpuFeatureLAM = cpu_feature_lam, ///< Linear Address Masking
}; // enum X86CpuFeatures
enum X86CpuArchitectures : uint64_t {
@@ -372,22 +474,39 @@ enum X86CpuArchitectures : uint64_t {
CpuArchWSM = cpu_wsm,
CpuArchSNB = cpu_snb,
CpuArchIVB = cpu_ivb,
- CpuArchHSW = cpu_hsw,
+ CpuArchHSW = cpu_hsw, ///< hle,rtm
CpuArchBDW = cpu_bdw,
CpuArchBDX = cpu_bdx,
CpuArchSKL = cpu_skl,
- CpuArchADL = cpu_adl,
- CpuArchSKX = cpu_skx,
+ CpuArchSKX = cpu_skx, ///< clwb
CpuArchCLX = cpu_clx,
CpuArchCPX = cpu_cpx,
+ CpuArchPLC = cpu_plc, ///< sha
+ CpuArchSNC = cpu_snc, ///< fsrm,rdpid
+ CpuArchWLC = cpu_wlc, ///< avx512vp2intersect
+ CpuArchGLC = cpu_glc, ///< tsxldtrk
+ CpuArchRPC = cpu_rpc,
+ CpuArchRWC = cpu_rwc,
+ CpuArchSLM = cpu_slm,
+ CpuArchGLM = cpu_glm,
+ CpuArchTNT = cpu_tnt,
+ CpuArchGRT = cpu_grt, ///< rdpid
+ CpuArchCMT = cpu_cmt,
CpuArchCNL = cpu_cnl,
CpuArchICL = cpu_icl,
- CpuArchICX = cpu_icx,
CpuArchTGL = cpu_tgl,
+ CpuArchADL = cpu_adl,
+ CpuArchRPL = cpu_rpl,
+ CpuArchMTL = cpu_mtl,
+ CpuArchARL = cpu_arl,
+ CpuArchLNL = cpu_lnl,
+ CpuArchICX = cpu_icx,
CpuArchSPR = cpu_spr,
- CpuArchSLM = cpu_slm,
- CpuArchGLM = cpu_glm,
- CpuArchTNT = cpu_tnt,
+ CpuArchEMR = cpu_emr,
+ CpuArchGNR = cpu_gnr,
+ CpuArchSRF = cpu_srf,
+ CpuArchGRR = cpu_grr,
+ CpuArchCWF = cpu_cwf,
CpuArchNehalem = cpu_nehalem, ///< Intel Core i3/i5/i7
CpuArchWestmere = cpu_westmere, ///< Intel Core i3/i5/i7
CpuArchSandyBridge = cpu_sandybridge, ///< Second Generation Intel Core i3/i5/i7
@@ -398,15 +517,32 @@ enum X86CpuArchitectures : uint64_t {
CpuArchSkylakeAvx512 = cpu_skylake_avx512, ///< Intel Xeon Scalable
CpuArchCascadeLake = cpu_cascadelake, ///< Second Generation Intel Xeon Scalable
CpuArchCooperLake = cpu_cooperlake, ///< Third Generation Intel Xeon Scalable
+ CpuArchPalmCove = cpu_palmcove,
CpuArchCannonLake = cpu_cannonlake, ///< Intel Core i3-8121U
+ CpuArchSunnyCove = cpu_sunnycove,
CpuArchIceLakeClient = cpu_icelake_client, ///< Tenth Generation Intel Core i3/i5/i7
CpuArchIceLakeServer = cpu_icelake_server, ///< Third Generation Intel Xeon Scalable
- CpuArchAlderLake = cpu_alderlake,
- CpuArchSapphireRapids = cpu_sapphirerapids,
+ CpuArchWillowCove = cpu_willowcove,
CpuArchTigerLake = cpu_tigerlake, ///< Eleventh Generation Intel Core i3/i5/i7
+ CpuArchGoldenCove = cpu_goldencove,
+ CpuArchAlderLake = cpu_alderlake, ///< Twelfth Generation Intel Core
+ CpuArchRaptorCove = cpu_raptorcove,
+ CpuArchRaptorLake = cpu_raptorlake, ///< Thirteenth Generation Intel Core
+ CpuArchRedwoodCove = cpu_redwoodcove,
+ CpuArchMeteorLake = cpu_meteorlake,
+ CpuArchArrowLake = cpu_arrowlake,
+ CpuArchLunarLake = cpu_lunarlake,
+ CpuArchSapphireRapids = cpu_sapphirerapids, ///< Fourth Generation Intel Xeon Scalable
+ CpuArchEmeraldRapids = cpu_emeraldrapids, ///< Fifth Generation Intel Xeon Scalable
+ CpuArchGraniteRapids = cpu_graniterapids,
CpuArchSilvermont = cpu_silvermont,
CpuArchGoldmont = cpu_goldmont,
CpuArchTremont = cpu_tremont,
+ CpuArchGracemont = cpu_gracemont,
+ CpuArchCrestmont = cpu_crestmont,
+ CpuArchGrandRidge = cpu_grandridge,
+ CpuArchSierraForest = cpu_sierraforest,
+ CpuArchClearwaterForest = cpu_clearwaterforest,
}; // enum X86cpuArchitectures
#endif /* C++11 */
diff --git a/src/corelib/global/qswap.h b/src/corelib/global/qswap.h
index 9ff6c7d9c5..3d533c8a95 100644
--- a/src/corelib/global/qswap.h
+++ b/src/corelib/global/qswap.h
@@ -1,11 +1,13 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QSWAP_H
-#define QSWAP_H
+#ifndef QTCORE_QSWAP_H
+#define QTCORE_QSWAP_H
#include <QtCore/qtconfigmacros.h>
-#include <QtCore/qcompilerdetection.h>
+
+#include <type_traits>
+#include <utility>
#if 0
#pragma qt_class(QtSwap)
@@ -14,25 +16,9 @@
QT_BEGIN_NAMESPACE
-QT_WARNING_PUSH
-// warning: noexcept-expression evaluates to 'false' because of a call to 'void swap(..., ...)'
-QT_WARNING_DISABLE_GCC("-Wnoexcept")
-
-namespace QtPrivate
-{
-namespace SwapExceptionTester { // insulate users from the "using std::swap" below
- using std::swap; // import std::swap
- template <typename T>
- void checkSwap(T &t)
- noexcept(noexcept(swap(t, t)));
- // declared, but not implemented (only to be used in unevaluated contexts (noexcept operator))
-}
-} // namespace QtPrivate
-
-// Documented in ../tools/qalgorithm.qdoc
template <typename T>
constexpr void qSwap(T &value1, T &value2)
- noexcept(noexcept(QtPrivate::SwapExceptionTester::checkSwap(value1)))
+ noexcept(std::is_nothrow_swappable_v<T>)
{
using std::swap;
swap(value1, value2);
@@ -47,8 +33,6 @@ constexpr inline void qt_ptr_swap(T* &lhs, T* &rhs) noexcept
rhs = tmp;
}
-QT_WARNING_POP
-
QT_END_NAMESPACE
-#endif // QSWAP_H
+#endif // QTCORE_QSWAP_H
diff --git a/src/corelib/global/qswap.qdoc b/src/corelib/global/qswap.qdoc
index 2d9d56b694..bffad903f9 100644
--- a/src/corelib/global/qswap.qdoc
+++ b/src/corelib/global/qswap.qdoc
@@ -1,14 +1,38 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
-/*! \fn template <typename T> void qSwap(T &var1, T &var2)
+/*!
+ \fn template <typename T> void qSwap(T &lhs, T &rhs)
\relates <QtSwap>
- \deprecated
- Use \c std::swap instead.
+ Exchanges the values of variables \a lhs and \a rhs,
+ taking type-specific \c{swap()} overloads into account.
- Exchanges the values of variables \a var1 and \a var2.
+ This function is Qt's version of
+ \l{https://www.boost.org/doc/libs/release/libs/core/doc/html/core/swap.html}{\c{boost::swap()}},
+ and is equivalent to
+ \code
+ using std::swap; // bring std::swap into scope (for built-in types)
+ swap(lhs, rhs); // unqualified call (picks up type-specific overloads
+ // via Argument-Dependent Lookup, or falls back to std::swap)
+ \endcode
- Example:
- \snippet code/doc_src_qalgorithms.cpp 0
+ Use this function primarily in generic code, where you would traditionally
+ have written the above two lines, because you don't know anything about \c{T}.
+
+ If you already know what \c{T} is, then use one of the following options, in
+ order of preference:
+
+ \list
+ \li \c{lhs.swap(rhs);} if such a member-swap exists
+ \li \c{std::swap(lhs, rhs);} if no type-specific \c{swap()} exists
+ \endlist
+
+ See
+ \l{https://www.boost.org/doc/libs/release/libs/core/doc/html/core/swap.html}{\c{boost::swap()} on boost.org}
+ for more details.
+
+ See also
+ \l{https://en.cppreference.com/w/cpp/algorithm/swap}{\c{std::swap} on cppreference.com},
+ \l{https://en.cppreference.com/w/cpp/named_req/Swappable}{\c{Swappable} on cppreference.com}.
*/
diff --git a/src/corelib/global/qsysinfo.cpp b/src/corelib/global/qsysinfo.cpp
index 20919d0865..79cb76b236 100644
--- a/src/corelib/global/qsysinfo.cpp
+++ b/src/corelib/global/qsysinfo.cpp
@@ -224,7 +224,7 @@ struct QUnixOSVersion
QString prettyName; // $PRETTY_NAME $DISTRIB_DESCRIPTION
};
-static QString unquote(const char *begin, const char *end)
+static QString unquote(QByteArrayView str)
{
// man os-release says:
// Variable assignment values must be enclosed in double
@@ -235,10 +235,11 @@ static QString unquote(const char *begin, const char *end)
// All strings should be in UTF-8 format, and non-printable
// characters should not be used. It is not supported to
// concatenate multiple individually quoted strings.
- if (*begin == '"')
- return QString::fromUtf8(begin + 1, end - begin - 2);
- return QString::fromUtf8(begin, end - begin);
+ if (str.size() >= 2 && str.front() == '"' && str.back() == '"')
+ str = str.sliced(1).chopped(1);
+ return QString::fromUtf8(str);
}
+
static QByteArray getEtcFileContent(const char *filename)
{
// we're avoiding QFile here
@@ -279,19 +280,19 @@ static bool readEtcFile(QUnixOSVersion &v, const char *filename,
if (line.startsWith(idKey)) {
ptr += idKey.size();
- v.productType = unquote(ptr, eol);
+ v.productType = unquote({ptr, eol});
continue;
}
if (line.startsWith(prettyNameKey)) {
ptr += prettyNameKey.size();
- v.prettyName = unquote(ptr, eol);
+ v.prettyName = unquote({ptr, eol});
continue;
}
if (line.startsWith(versionKey)) {
ptr += versionKey.size();
- v.productVersion = unquote(ptr, eol);
+ v.productVersion = unquote({ptr, eol});
continue;
}
}
@@ -783,6 +784,8 @@ QString QSysInfo::productType()
return QStringLiteral("tvos");
#elif defined(Q_OS_WATCHOS)
return QStringLiteral("watchos");
+#elif defined(Q_OS_VISIONOS)
+ return QStringLiteral("visionos");
#elif defined(Q_OS_MACOS)
return QStringLiteral("macos");
#elif defined(Q_OS_DARWIN)
@@ -991,8 +994,7 @@ QByteArray QSysInfo::machineUniqueId()
{
#if defined(Q_OS_DARWIN) && __has_include(<IOKit/IOKitLib.h>)
char uuid[UuidStringLen + 1];
- static const mach_port_t defaultPort = 0; // Effectively kIOMasterPortDefault/kIOMainPortDefault
- io_service_t service = IOServiceGetMatchingService(defaultPort, IOServiceMatching("IOPlatformExpertDevice"));
+ io_service_t service = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
QCFString stringRef = (CFStringRef)IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0);
CFStringGetCString(stringRef, uuid, sizeof(uuid), kCFStringEncodingMacRoman);
return QByteArray(uuid);
diff --git a/src/corelib/global/qsysinfo.h b/src/corelib/global/qsysinfo.h
index b1d7f000be..01f6313299 100644
--- a/src/corelib/global/qsysinfo.h
+++ b/src/corelib/global/qsysinfo.h
@@ -2,11 +2,13 @@
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <QtCore/qglobal.h>
-
#ifndef QSYSINFO_H
#define QSYSINFO_H
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qprocessordetection.h>
+#include <QtCore/qtcoreexports.h>
+
QT_BEGIN_NAMESPACE
/*
@@ -14,6 +16,8 @@ QT_BEGIN_NAMESPACE
*/
class QString;
+class QByteArray;
+
class Q_CORE_EXPORT QSysInfo
{
public:
diff --git a/src/corelib/global/qsystemdetection.h b/src/corelib/global/qsystemdetection.h
index 3a992f2aba..b29f2e9496 100644
--- a/src/corelib/global/qsystemdetection.h
+++ b/src/corelib/global/qsystemdetection.h
@@ -2,10 +2,6 @@
// Copyright (C) 2019 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QGLOBAL_H
-# include <QtCore/qglobal.h>
-#endif
-
#if 0
#pragma qt_class(QtSystemDetection)
#pragma qt_sync_skip_header_check
@@ -23,6 +19,7 @@
IOS - iOS
WATCHOS - watchOS
TVOS - tvOS
+ VISIONOS - visionOS
WIN32 - Win32 (Windows 2000/XP/Vista/7 and Windows Server 2003/2008)
CYGWIN - Cygwin
SOLARIS - Sun Solaris
@@ -42,6 +39,7 @@
ANDROID - Android platform
HAIKU - Haiku
WEBOS - LG WebOS
+ WASM - WebAssembly
The following operating systems have variants:
LINUX - both Q_OS_LINUX and Q_OS_ANDROID are defined when building for Android
@@ -54,20 +52,18 @@
#if defined(__APPLE__) && (defined(__GNUC__) || defined(__xlC__) || defined(__xlc__))
# include <TargetConditionals.h>
+# define Q_OS_APPLE
# if defined(TARGET_OS_MAC) && TARGET_OS_MAC
# define Q_OS_DARWIN
# define Q_OS_BSD4
-# ifdef __LP64__
-# define Q_OS_DARWIN64
-# else
-# define Q_OS_DARWIN32
-# endif
# if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
# define QT_PLATFORM_UIKIT
# if defined(TARGET_OS_WATCH) && TARGET_OS_WATCH
# define Q_OS_WATCHOS
# elif defined(TARGET_OS_TV) && TARGET_OS_TV
# define Q_OS_TVOS
+# elif defined(TARGET_OS_VISION) && TARGET_OS_VISION
+# define Q_OS_VISIONOS
# else
# // TARGET_OS_IOS is only available in newer SDKs,
# // so assume any other iOS-based platform is iOS for now
@@ -98,8 +94,6 @@
# define Q_OS_SOLARIS
#elif defined(hpux) || defined(__hpux)
# define Q_OS_HPUX
-#elif defined(__native_client__)
-# define Q_OS_NACL
#elif defined(__EMSCRIPTEN__)
# define Q_OS_WASM
#elif defined(__linux__) || defined(__linux)
@@ -131,7 +125,7 @@
# define Q_OS_INTEGRITY
#elif defined(__rtems__)
# define Q_OS_RTEMS
-#elif defined(VXWORKS) /* there is no "real" VxWorks define - this has to be set in the mkspec! */
+#elif defined(__vxworks)
# define Q_OS_VXWORKS
#elif defined(__HAIKU__)
# define Q_OS_HAIKU
@@ -157,92 +151,32 @@
// Compatibility synonyms
#ifdef Q_OS_DARWIN
-#define Q_OS_MAC
-#endif
-#ifdef Q_OS_DARWIN32
-#define Q_OS_MAC32
-#endif
-#ifdef Q_OS_DARWIN64
-#define Q_OS_MAC64
-#endif
-#ifdef Q_OS_MACOS
-#define Q_OS_MACX
-#define Q_OS_OSX
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wunknown-pragmas"
+# define Q_OS_MAC // FIXME: Deprecate
+# ifdef __LP64__
+# define Q_OS_DARWIN64
+# pragma clang deprecated(Q_OS_DARWIN64, "use Q_OS_DARWIN and QT_POINTER_SIZE/Q_PROCESSOR_* instead")
+# define Q_OS_MAC64
+# pragma clang deprecated(Q_OS_MAC64, "use Q_OS_DARWIN and QT_POINTER_SIZE/Q_PROCESSOR_* instead")
+# else
+# define Q_OS_DARWIN32
+# pragma clang deprecated(Q_OS_DARWIN32, "use Q_OS_DARWIN and QT_POINTER_SIZE/Q_PROCESSOR_* instead")
+# define Q_OS_MAC32
+# pragma clang deprecated(Q_OS_MAC32, "use Q_OS_DARWIN and QT_POINTER_SIZE/Q_PROCESSOR_* instead")
+# endif
+# ifdef Q_OS_MACOS
+# define Q_OS_MACX
+# pragma clang deprecated(Q_OS_MACX, "use Q_OS_MACOS instead")
+# define Q_OS_OSX
+# pragma clang deprecated(Q_OS_OSX, "use Q_OS_MACOS instead")
+# endif
+# pragma clang diagnostic pop
#endif
#ifdef Q_OS_DARWIN
# include <Availability.h>
# include <AvailabilityMacros.h>
-#
-# ifdef Q_OS_MACOS
-# if !defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_6
-# undef __MAC_OS_X_VERSION_MIN_REQUIRED
-# define __MAC_OS_X_VERSION_MIN_REQUIRED __MAC_10_6
-# endif
-# if !defined(MAC_OS_X_VERSION_MIN_REQUIRED) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6
-# undef MAC_OS_X_VERSION_MIN_REQUIRED
-# define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_6
-# endif
-# endif
-#
-# // Numerical checks are preferred to named checks, but to be safe
-# // we define the missing version names in case Qt uses them.
-#
-# if !defined(__MAC_10_11)
-# define __MAC_10_11 101100
-# endif
-# if !defined(__MAC_10_12)
-# define __MAC_10_12 101200
-# endif
-# if !defined(__MAC_10_13)
-# define __MAC_10_13 101300
-# endif
-# if !defined(__MAC_10_14)
-# define __MAC_10_14 101400
-# endif
-# if !defined(__MAC_10_15)
-# define __MAC_10_15 101500
-# endif
-# if !defined(__MAC_10_16)
-# define __MAC_10_16 101600
-# endif
-# if !defined(MAC_OS_X_VERSION_10_11)
-# define MAC_OS_X_VERSION_10_11 __MAC_10_11
-# endif
-# if !defined(MAC_OS_X_VERSION_10_12)
-# define MAC_OS_X_VERSION_10_12 __MAC_10_12
-# endif
-# if !defined(MAC_OS_X_VERSION_10_13)
-# define MAC_OS_X_VERSION_10_13 __MAC_10_13
-# endif
-# if !defined(MAC_OS_X_VERSION_10_14)
-# define MAC_OS_X_VERSION_10_14 __MAC_10_14
-# endif
-# if !defined(MAC_OS_X_VERSION_10_15)
-# define MAC_OS_X_VERSION_10_15 __MAC_10_15
-# endif
-# if !defined(MAC_OS_X_VERSION_10_16)
-# define MAC_OS_X_VERSION_10_16 __MAC_10_16
-# endif
-#
-# if !defined(__IPHONE_10_0)
-# define __IPHONE_10_0 100000
-# endif
-# if !defined(__IPHONE_10_1)
-# define __IPHONE_10_1 100100
-# endif
-# if !defined(__IPHONE_10_2)
-# define __IPHONE_10_2 100200
-# endif
-# if !defined(__IPHONE_10_3)
-# define __IPHONE_10_3 100300
-# endif
-# if !defined(__IPHONE_11_0)
-# define __IPHONE_11_0 110000
-# endif
-# if !defined(__IPHONE_12_0)
-# define __IPHONE_12_0 120000
-# endif
# define QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(macos, ios, tvos, watchos) \
((defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && macos != __MAC_NA && __MAC_OS_X_VERSION_MAX_ALLOWED >= macos) || \
@@ -278,13 +212,7 @@
# define QT_WATCHOS_DEPLOYMENT_TARGET_BELOW(watchos) \
QT_DARWIN_DEPLOYMENT_TARGET_BELOW(__MAC_NA, __IPHONE_NA, __TVOS_NA, watchos)
-// Compatibility synonyms, do not use
-# define QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(osx, ios) QT_MACOS_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(osx, ios)
-# define QT_MAC_DEPLOYMENT_TARGET_BELOW(osx, ios) QT_MACOS_IOS_DEPLOYMENT_TARGET_BELOW(osx, ios)
-# define QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(osx) QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(osx)
-# define QT_OSX_DEPLOYMENT_TARGET_BELOW(osx) QT_MACOS_DEPLOYMENT_TARGET_BELOW(osx)
-
-#else
+#else // !Q_OS_DARWIN
#define QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(macos, ios, tvos, watchos) (0)
#define QT_MACOS_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(macos, ios) (0)
@@ -293,9 +221,6 @@
#define QT_TVOS_PLATFORM_SDK_EQUAL_OR_ABOVE(tvos) (0)
#define QT_WATCHOS_PLATFORM_SDK_EQUAL_OR_ABOVE(watchos) (0)
-#define QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(osx, ios) (0)
-#define QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(osx) (0)
-
#endif // Q_OS_DARWIN
#ifdef __LSB_VERSION__
diff --git a/src/corelib/global/qsystemdetection.qdoc b/src/corelib/global/qsystemdetection.qdoc
index 210f865ffe..a48a79bbb2 100644
--- a/src/corelib/global/qsystemdetection.qdoc
+++ b/src/corelib/global/qsystemdetection.qdoc
@@ -23,6 +23,16 @@
\relates <QtSystemDetection>
Defined on Darwin-based operating systems such as \macos, iOS, watchOS, and tvOS.
+
+ \note Unless you are dealing with code specific to the Darwin kernel,
+ prefer Q_OS_APPLE to refer to the family of Apple operating systems.
+*/
+
+/*!
+ \macro Q_OS_APPLE
+ \relates <QtSystemDetection>
+
+ Defined on Apple operating systems such as \macos, iOS, watchOS, and tvOS.
*/
/*!
@@ -68,6 +78,13 @@
*/
/*!
+ \macro Q_OS_VISIONOS
+ \relates <QtSystemDetection>
+
+ Defined on visionOS.
+*/
+
+/*!
\macro Q_OS_WIN
\relates <QtSystemDetection>
diff --git a/src/corelib/global/qt_pch.h b/src/corelib/global/qt_pch.h
index 207a30a5ee..3f224cda85 100644
--- a/src/corelib/global/qt_pch.h
+++ b/src/corelib/global/qt_pch.h
@@ -14,36 +14,31 @@
// for rand_s, _CRT_RAND_S must be #defined before #including stdlib.h.
// put it at the beginning so some indirect inclusion doesn't break it
#ifndef _CRT_RAND_S
-#define _CRT_RAND_S
+# define _CRT_RAND_S
#endif
#include <stdlib.h>
#include <qglobal.h>
#ifdef Q_OS_WIN
-# ifdef Q_CC_MINGW
+# ifdef Q_CC_MINGW
// <unistd.h> must be included before any other header pulls in <time.h>.
-# include <unistd.h> // Define _POSIX_THREAD_SAFE_FUNCTIONS to obtain localtime_r()
-# endif
-# define _POSIX_
-# include <limits.h>
-# undef _POSIX_
-# if defined(Q_CC_CLANG) && defined(Q_CC_MSVC)
-// See https://bugs.llvm.org/show_bug.cgi?id=41226
-# include <wchar.h>
-__declspec(selectany) auto *__wmemchr_symbol_loader_value = wmemchr(L"", L'0', 0);
-# endif
-# endif
-# include <qcoreapplication.h>
-# include <qcoreevent.h>
-# include <qiodevice.h>
-# include <qlist.h>
-# include <qvariant.h> /* All moc generated code has this include */
-# include <qobject.h>
-# if QT_CONFIG(regularexpression)
-# include <qregularexpression.h>
-# endif
-# include <qscopedpointer.h>
-# include <qshareddata.h>
-# include <qstring.h>
-# include <qstringlist.h>
-# include <qtimer.h>
+# include <unistd.h> // Define _POSIX_THREAD_SAFE_FUNCTIONS to obtain localtime_r()
+# endif // Q_CC_MINGW
+# define _POSIX_
+# include <limits.h>
+# undef _POSIX_
+#endif // Q_OS_WIN
+#include <qcoreapplication.h>
+#include <qcoreevent.h>
+#include <qiodevice.h>
+#include <qlist.h>
+#include <qvariant.h> /* All moc generated code has this include */
+#include <qobject.h>
+#if QT_CONFIG(regularexpression)
+# include <qregularexpression.h>
+#endif
+#include <qscopedpointer.h>
+#include <qshareddata.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qtimer.h>
#endif
diff --git a/src/corelib/global/qtconfigmacros.h b/src/corelib/global/qtconfigmacros.h
index 2bb1016cac..03d52d885a 100644
--- a/src/corelib/global/qtconfigmacros.h
+++ b/src/corelib/global/qtconfigmacros.h
@@ -9,6 +9,9 @@
#endif
#include <QtCore/qtconfiginclude.h>
+#include <QtCore/qtversionchecks.h>
+
+#include <assert.h>
/*
The Qt modules' export macros.
@@ -41,6 +44,9 @@
No, this is not an evil backdoor. QT_BUILD_INTERNAL just exports more symbols
for Qt's internal unit tests. If you want slower loading times and more
symbols that can vanish from version to version, feel free to define QT_BUILD_INTERNAL.
+
+ \note After adding Q_AUTOTEST_EXPORT to a method, you'll need to wrap any unittests
+ that will use that method in "#ifdef QT_BUILD_INTERNAL".
*/
#if defined(QT_BUILD_INTERNAL) && defined(QT_BUILDING_QT) && defined(QT_SHARED)
# define Q_AUTOTEST_EXPORT Q_DECL_EXPORT
@@ -58,7 +64,7 @@
1: The feature is available
*/
#define QT_CONFIG(feature) (1/QT_FEATURE_##feature == 1)
-#define QT_REQUIRE_CONFIG(feature) Q_STATIC_ASSERT_X(QT_FEATURE_##feature == 1, "Required feature " #feature " for file " __FILE__ " not available.")
+#define QT_REQUIRE_CONFIG(feature) static_assert(QT_FEATURE_##feature == 1, "Required feature " #feature " for file " __FILE__ " not available.")
/* moc compats (signals/slots) */
#ifndef QT_MOC_COMPAT
@@ -100,6 +106,22 @@
# define QT_FORWARD_DECLARE_CLASS(name) class name;
# define QT_FORWARD_DECLARE_STRUCT(name) struct name;
+#elif defined(QT_INLINE_NAMESPACE) /* user inline namespace FIXME in Qt 7: Default */
+
+# define QT_PREPEND_NAMESPACE(name) ::QT_NAMESPACE::name
+# define QT_USE_NAMESPACE
+# define QT_BEGIN_NAMESPACE inline namespace QT_NAMESPACE {
+# define QT_END_NAMESPACE }
+# define QT_BEGIN_INCLUDE_NAMESPACE }
+# define QT_END_INCLUDE_NAMESPACE inline namespace QT_NAMESPACE {
+# define QT_FORWARD_DECLARE_CLASS(name) \
+QT_BEGIN_NAMESPACE class name; QT_END_NAMESPACE
+
+# define QT_FORWARD_DECLARE_STRUCT(name) \
+QT_BEGIN_NAMESPACE struct name; QT_END_NAMESPACE
+
+inline namespace QT_NAMESPACE {}
+
#else /* user namespace */
# define QT_PREPEND_NAMESPACE(name) ::QT_NAMESPACE::name
@@ -150,4 +172,38 @@ namespace QT_NAMESPACE {}
# define QT_END_MOC_NAMESPACE
#endif
+/*
+ Strict mode
+*/
+#ifdef QT_ENABLE_STRICT_MODE_UP_TO
+#ifndef QT_DISABLE_DEPRECATED_UP_TO
+# define QT_DISABLE_DEPRECATED_UP_TO QT_ENABLE_STRICT_MODE_UP_TO
+#endif
+
+#if QT_ENABLE_STRICT_MODE_UP_TO >= QT_VERSION_CHECK(6, 0, 0)
+# define QT_NO_FOREACH
+# define QT_NO_CAST_FROM_ASCII
+# define QT_NO_CAST_TO_ASCII
+# define QT_NO_CAST_FROM_BYTEARRAY
+# define QT_NO_URL_CAST_FROM_STRING
+# define QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
+# define QT_NO_JAVA_STYLE_ITERATORS
+#endif // 6.0.0
+
+#if QT_ENABLE_STRICT_MODE_UP_TO >= QT_VERSION_CHECK(6, 6, 0)
+# define QT_NO_QEXCHANGE
+#endif // 6.6.0
+
+#if QT_ENABLE_STRICT_MODE_UP_TO >= QT_VERSION_CHECK(6, 7, 0)
+# define QT_NO_CONTEXTLESS_CONNECT
+#endif // 6.7.0
+
+#if QT_ENABLE_STRICT_MODE_UP_TO >= QT_VERSION_CHECK(6, 8, 0)
+# define QT_NO_QASCONST
+# if !defined(QT_USE_NODISCARD_FILE_OPEN) && !defined(QT_NO_USE_NODISCARD_FILE_OPEN)
+# define QT_USE_NODISCARD_FILE_OPEN
+# endif
+#endif // 6.8.0
+#endif // QT_ENABLE_STRICT_MODE_UP_TO
+
#endif /* QTCONFIGMACROS_H */
diff --git a/src/corelib/global/qtdeprecationmarkers.h b/src/corelib/global/qtdeprecationmarkers.h
index d283954167..6df5ebce6d 100644
--- a/src/corelib/global/qtdeprecationmarkers.h
+++ b/src/corelib/global/qtdeprecationmarkers.h
@@ -40,6 +40,8 @@ QT_BEGIN_NAMESPACE
# define QT_DEPRECATED_CONSTRUCTOR
# undef Q_DECL_ENUMERATOR_DEPRECATED
# define Q_DECL_ENUMERATOR_DEPRECATED
+# undef Q_DECL_ENUMERATOR_DEPRECATED_X
+# define Q_DECL_ENUMERATOR_DEPRECATED_X(ignored)
#endif
// If the deprecated macro is defined, use its value
@@ -209,6 +211,14 @@ QT_BEGIN_NAMESPACE
# define QT_DEPRECATED_VERSION_6_10
#endif
+#if QT_WARN_DEPRECATED_UP_TO >= QT_VERSION_CHECK(6, 11, 0)
+# define QT_DEPRECATED_VERSION_X_6_11(text) QT_DEPRECATED_X(text)
+# define QT_DEPRECATED_VERSION_6_11 QT_DEPRECATED
+#else
+# define QT_DEPRECATED_VERSION_X_6_11(text)
+# define QT_DEPRECATED_VERSION_6_11
+#endif
+
#define QT_DEPRECATED_VERSION_X_5(minor, text) QT_DEPRECATED_VERSION_X_5_##minor(text)
#define QT_DEPRECATED_VERSION_X(major, minor, text) QT_DEPRECATED_VERSION_X_##major##_##minor(text)
@@ -311,6 +321,12 @@ QT_BEGIN_NAMESPACE
# define QT_IF_DEPRECATED_SINCE_6_10(whenTrue, whenFalse) whenTrue
#endif
+#if QT_DEPRECATED_SINCE(6, 11)
+# define QT_IF_DEPRECATED_SINCE_6_11(whenTrue, whenFalse) whenFalse
+#else
+# define QT_IF_DEPRECATED_SINCE_6_11(whenTrue, whenFalse) whenTrue
+#endif
+
#ifdef __cplusplus
// A tag to help mark stuff deprecated (cf. QStringViewLiteral)
namespace QtPrivate {
diff --git a/src/corelib/global/qtenvironmentvariables.cpp b/src/corelib/global/qtenvironmentvariables.cpp
index 47fc8f7eec..cf5955902a 100644
--- a/src/corelib/global/qtenvironmentvariables.cpp
+++ b/src/corelib/global/qtenvironmentvariables.cpp
@@ -353,6 +353,10 @@ void qTzSet()
time_t qMkTime(struct tm *when)
{
const auto locker = qt_scoped_lock(environmentMutex);
+#if defined(Q_OS_WIN)
+ // QTBUG-83881 MS's mktime() seems to need _tzset() called first.
+ _tzset();
+#endif
return mktime(when);
}
@@ -404,7 +408,7 @@ QString qTzName(int dstIndex)
{
char name[512];
bool ok;
-#if defined(Q_CC_MSVC)
+#if defined(_UCRT) // i.e., MSVC and MinGW-UCRT
size_t s = 0;
{
const auto locker = qt_scoped_lock(environmentMutex);
diff --git a/src/corelib/global/qtnoop.h b/src/corelib/global/qtnoop.h
index ea0cedd9bc..c84e6c8a99 100644
--- a/src/corelib/global/qtnoop.h
+++ b/src/corelib/global/qtnoop.h
@@ -8,6 +8,13 @@
#pragma qt_sync_stop_processing
#endif
-inline void qt_noop(void) {}
+#ifdef __cplusplus
+constexpr
+#endif
+inline void qt_noop(void)
+#ifdef __cplusplus
+ noexcept
+#endif
+{}
#endif // QTNOOP_H
diff --git a/src/corelib/global/qtsymbolmacros.h b/src/corelib/global/qtsymbolmacros.h
new file mode 100644
index 0000000000..18cdc85f72
--- /dev/null
+++ b/src/corelib/global/qtsymbolmacros.h
@@ -0,0 +1,65 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTSYMBOLMACROS_H
+#define QTSYMBOLMACROS_H
+
+#if 0
+# pragma qt_sync_stop_processing
+#endif
+
+// For GHS symbol keeping.
+#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qtpreprocessorsupport.h>
+
+// For handling namespaced resources.
+#ifdef QT_NAMESPACE
+# define QT_RCC_MANGLE_NAMESPACE0(x) x
+# define QT_RCC_MANGLE_NAMESPACE1(a, b) a##_##b
+# define QT_RCC_MANGLE_NAMESPACE2(a, b) QT_RCC_MANGLE_NAMESPACE1(a,b)
+# define QT_RCC_MANGLE_NAMESPACE(name) QT_RCC_MANGLE_NAMESPACE2( \
+ QT_RCC_MANGLE_NAMESPACE0(name), QT_RCC_MANGLE_NAMESPACE0(QT_NAMESPACE))
+#else
+# define QT_RCC_MANGLE_NAMESPACE(name) name
+#endif
+
+// GHS needs special handling to keep a symbol around.
+#if defined(Q_CC_GHS)
+# define Q_GHS_KEEP_REFERENCE(S) QT_DO_PRAGMA(ghs reference S ##__Fv)
+#else
+# define Q_GHS_KEEP_REFERENCE(S)
+#endif
+
+// Macros to ensure a symbol is not dropped by the linker even if it's not used.
+#define QT_DECLARE_EXTERN_SYMBOL(NAME, RETURN_TYPE) \
+ extern RETURN_TYPE NAME(); \
+ Q_GHS_KEEP_REFERENCE(NAME)
+
+#define QT_DECLARE_EXTERN_SYMBOL_INT(NAME) \
+ QT_DECLARE_EXTERN_SYMBOL(NAME, int)
+
+#define QT_DECLARE_EXTERN_SYMBOL_VOID(NAME) \
+ QT_DECLARE_EXTERN_SYMBOL(NAME, void)
+
+#define QT_KEEP_SYMBOL_VAR_NAME(NAME) NAME ## _keep
+
+#define QT_KEEP_SYMBOL_HELPER(NAME, VAR_NAME) \
+ volatile auto VAR_NAME = &NAME; \
+ Q_UNUSED(VAR_NAME)
+
+#define QT_KEEP_SYMBOL(NAME) \
+ QT_KEEP_SYMBOL_HELPER(NAME, QT_KEEP_SYMBOL_VAR_NAME(NAME))
+
+
+// Similar to the ones above, but for rcc resource symbols specifically.
+#define QT_GET_RESOURCE_INIT_SYMBOL(NAME) \
+ QT_RCC_MANGLE_NAMESPACE(qInitResources_ ## NAME)
+
+#define QT_DECLARE_EXTERN_RESOURCE(NAME) \
+ QT_DECLARE_EXTERN_SYMBOL_INT(QT_GET_RESOURCE_INIT_SYMBOL(NAME))
+
+#define QT_KEEP_RESOURCE(NAME) \
+ QT_KEEP_SYMBOL(QT_GET_RESOURCE_INIT_SYMBOL(NAME))
+
+#endif // QTSYMBOLMACROS_H
+
diff --git a/src/corelib/global/qttypetraits.h b/src/corelib/global/qttypetraits.h
index a7bb4e5353..1efb24bf70 100644
--- a/src/corelib/global/qttypetraits.h
+++ b/src/corelib/global/qttypetraits.h
@@ -5,6 +5,7 @@
#define QTTYPETRAITS_H
#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qtdeprecationmarkers.h>
#include <type_traits>
#include <utility>
@@ -23,16 +24,19 @@ constexpr std::underlying_type_t<Enum> qToUnderlying(Enum e) noexcept
return static_cast<std::underlying_type_t<Enum>>(e);
}
-#ifndef QT_NO_AS_CONST
+#ifndef QT_NO_QASCONST
+#if QT_DEPRECATED_SINCE(6, 6)
// this adds const to non-const objects (like std::as_const)
template <typename T>
+QT_DEPRECATED_VERSION_X_6_6("Use std::as_const() instead.")
constexpr typename std::add_const<T>::type &qAsConst(T &t) noexcept { return t; }
// prevent rvalue arguments:
template <typename T>
void qAsConst(const T &&) = delete;
-#endif // QT_NO_AS_CONST
+#endif // QT_DEPRECATED_SINCE(6, 6)
+#endif // QT_NO_QASCONST
#ifndef QT_NO_QEXCHANGE
diff --git a/src/corelib/global/qttypetraits.qdoc b/src/corelib/global/qttypetraits.qdoc
index 082b6255a1..ed814d6f43 100644
--- a/src/corelib/global/qttypetraits.qdoc
+++ b/src/corelib/global/qttypetraits.qdoc
@@ -2,6 +2,14 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
+ \headerfile <QtTypeTraits>
+ \inmodule QtCore
+ \since 6.5
+ \title Qt Type Traits
+ \brief Functionality for type traits and transformations.
+*/
+
+/*!
\fn template <typename Enum> std::underlying_type_t<Enum> qToUnderlying(Enum e)
\relates <QtTypeTraits>
\since 6.2
@@ -15,6 +23,8 @@
\relates <QtTypeTraits>
\since 5.7
+ \deprecated [6.6] Use std::as_const() instead.
+
Returns \a t cast to \c{const T}.
This function is a Qt implementation of C++17's std::as_const(),
@@ -44,6 +54,20 @@
To prevent this construct from compiling (and failing at runtime), qAsConst() has
a second, deleted, overload which binds to rvalues.
+
+ \note You can make the qAsConst() function unavailable by defining
+ the \l{QT_NO_QASCONST} macro.
+*/
+
+/*!
+ \macro QT_NO_QASCONST
+ \since 6.8
+ \relates <QtTypeTraits>
+
+ Defining this macro removes the availability of the qAsConst()
+ function.
+
+ \sa qAsConst
*/
/*!
@@ -52,6 +76,8 @@
\since 5.7
\overload
+ \deprecated [6.6]
+
This overload is deleted to prevent a dangling reference in code like
\snippet code/src_corelib_global_qglobal.cpp as-const-4
*/
@@ -67,6 +93,7 @@
only in that it is \c constexpr already before C++20 and noexcept already before C++23.
We strongly advise to use std::exchange() when you don't need the C++20 or C++23 variants.
+ You can make qExchange() unavailable by defining the \l{QT_NO_QEXCHANGE} macro.
Here is how to use qExchange() to implement move constructors:
\code
@@ -106,3 +133,14 @@
long as the loop runs, saving the declaration of a temporary variable. Be aware, though,
that qExchange() returns a non-const object, so Qt containers may detach.
*/
+
+/*!
+ \macro QT_NO_QEXCHANGE
+ \since 6.6
+ \relates <QtTypeTraits>
+
+ Defining this macro removes the availability of the qExchange()
+ function.
+
+ \sa qExchange
+*/
diff --git a/src/corelib/global/qtversionchecks.h b/src/corelib/global/qtversionchecks.h
index 72b62ce105..86fc094f4e 100644
--- a/src/corelib/global/qtversionchecks.h
+++ b/src/corelib/global/qtversionchecks.h
@@ -28,7 +28,7 @@
void QT7_ONLY(Q_CORE_EXPORT) void operate();
}
*/
-#if QT_VERSION_MAJOR == 7
+#if QT_VERSION_MAJOR == 7 || defined(QT_BOOTSTRAPPED)
# define QT7_ONLY(...) __VA_ARGS__
# define QT6_ONLY(...)
#elif QT_VERSION_MAJOR == 6
@@ -72,4 +72,43 @@
# define QT6_CALL_NEW_OVERLOAD_TAIL QT6_ONLY(, QT6_CALL_NEW_OVERLOAD)
#endif
+/*
+ Macro to tag Tech Preview APIs.
+ It expands to nothing, because we want to use it in places where
+ nothing is generally allowed (not even an attribute); for instance:
+ to tag other macros, Q_PROPERTY declarations, and so on.
+
+ Still: use it as if it were an C++ attribute.
+
+ To mark a class as TP:
+ class QT_TECH_PREVIEW_API Q_CORE_EXPORT QClass { ... };
+
+ To mark a function:
+ QT_TECH_PREVIEW_API void qFunction();
+
+ To mark an enumeration or enumerator:
+ enum class QT_TECH_PREVIEW_API QEnum {
+ Enum1,
+ Enum2 QT_TECH_PREVIEW_API,
+ };
+
+ To mark parts of a class:
+ class QClass : public QObject
+ {
+ // Q_OBJECT omitted d/t QTBUG-123229
+
+ QT_TECH_PREVIEW_API
+ Q_PROPERTY(int countNG ...) // this is TP
+
+ Q_PROPERTY(int count ...) // this is stable API
+
+ public:
+ QT_TECH_PREVIEW_API
+ void f(); // TP
+
+ void g(); // stable
+ };
+*/
+#define QT_TECH_PREVIEW_API
+
#endif /* QTVERSIONCHECKS_H */
diff --git a/src/corelib/global/qtypeinfo.h b/src/corelib/global/qtypeinfo.h
index b07c9f4afe..255a2b33c6 100644
--- a/src/corelib/global/qtypeinfo.h
+++ b/src/corelib/global/qtypeinfo.h
@@ -2,14 +2,16 @@
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <QtCore/qglobal.h>
+#ifndef QTYPEINFO_H
+#define QTYPEINFO_H
+
+#include <QtCore/qcompilerdetection.h>
#include <QtCore/qcontainerfwd.h>
+
#include <variant>
#include <optional>
#include <tuple>
-
-#ifndef QTYPEINFO_H
-#define QTYPEINFO_H
+#include <type_traits>
QT_BEGIN_NAMESPACE
@@ -21,6 +23,13 @@ class QDebug;
namespace QtPrivate {
+// A trivially copyable class must also have a trivial, non-deleted
+// destructor [class.prop/1.3], CWG1734. Some implementations don't
+// check for a trivial destructor, because of backwards compatibility
+// with C++98's definition of trivial copyability.
+// Since trivial copiability has implications for the ABI, implementations
+// can't "just fix" their traits. So, although formally redundant, we
+// explicitly check for trivial destruction here.
template <typename T>
inline constexpr bool qIsRelocatable = std::is_trivially_copyable_v<T> && std::is_trivially_destructible_v<T>;
@@ -96,6 +105,11 @@ public:
[[deprecated("Use std::is_pointer instead")]] static constexpr bool isPointer = false;
[[deprecated("Use std::is_integral instead")]] static constexpr bool isIntegral = false;
static constexpr bool isValueInitializationBitwiseZero = false;
+ static_assert(!isRelocatable ||
+ std::is_copy_constructible_v<T> ||
+ std::is_move_constructible_v<T>,
+ "All Ts... are Q_RELOCATABLE_TYPE, but T is neither copy- nor move-constructible, "
+ "so cannot be Q_RELOCATABLE_TYPE. Please mark T as Q_COMPLEX_TYPE manually.");
};
// QTypeInfo for std::pair:
@@ -157,6 +171,10 @@ public: \
isIntegral [[deprecated("Use std::is_integral instead")]] = std::is_integral< TYPE >::value, \
isValueInitializationBitwiseZero = QtPrivate::qIsValueInitializationBitwiseZero<TYPE>, \
}; \
+ static_assert(!isRelocatable || \
+ std::is_copy_constructible_v<TYPE > || \
+ std::is_move_constructible_v<TYPE >, \
+ #TYPE " is neither copy- nor move-constructible, so cannot be Q_RELOCATABLE_TYPE"); \
}
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS) \
@@ -236,7 +254,7 @@ using expand_operator_equal_recursive = std::conjunction<expand_operator_equal<T
template<typename T>
struct expand_operator_equal_tuple : has_operator_equal<T> {};
template<typename T>
-struct expand_operator_equal_tuple<std::optional<T>> : has_operator_equal<T> {};
+struct expand_operator_equal_tuple<std::optional<T>> : expand_operator_equal_recursive<T> {};
template<typename T1, typename T2>
struct expand_operator_equal_tuple<std::pair<T1, T2>> : expand_operator_equal_recursive<T1, T2> {};
template<typename ...T>
@@ -276,7 +294,7 @@ using expand_operator_less_than_recursive = std::conjunction<expand_operator_les
template<typename T>
struct expand_operator_less_than_tuple : has_operator_less_than<T> {};
template<typename T>
-struct expand_operator_less_than_tuple<std::optional<T>> : has_operator_less_than<T> {};
+struct expand_operator_less_than_tuple<std::optional<T>> : expand_operator_less_than_recursive<T> {};
template<typename T1, typename T2>
struct expand_operator_less_than_tuple<std::pair<T1, T2>> : expand_operator_less_than_recursive<T1, T2> {};
template<typename ...T>
diff --git a/src/corelib/global/qtypeinfo.qdoc b/src/corelib/global/qtypeinfo.qdoc
index 78d9d423cd..75a92da197 100644
--- a/src/corelib/global/qtypeinfo.qdoc
+++ b/src/corelib/global/qtypeinfo.qdoc
@@ -13,13 +13,13 @@
\a Flags can be one of the following:
\list
- \li \c Q_PRIMITIVE_TYPE specifies that \a Type can be created by
- zero-initializing its storage, requires no operation to be properly
- destroyed, and for which memcpy()ing creates a valid independent
- copy of the object.
+ \li \c Q_PRIMITIVE_TYPE specifies that \a Type requires no
+ operation to be performed in order to be properly destroyed,
+ and that it is possible to use memcpy() in order to create a
+ valid independent copy of an object.
\li \c Q_RELOCATABLE_TYPE specifies that \a Type has a constructor
- and/or a destructor but can be moved in memory using \c
- memcpy().
+ and/or a destructor, but it can still be \e{relocated} in memory
+ by using \c memcpy().
\li \c Q_MOVABLE_TYPE is the same as \c Q_RELOCATABLE_TYPE. Prefer to use
\c Q_RELOCATABLE_TYPE in new code. Note: despite the name, this
has nothing to do with move constructors or C++ move semantics.
@@ -41,15 +41,8 @@
\snippet code/src_corelib_global_qglobal.cpp 39
- Qt will try to detect the class of a type using
- \l {https://en.cppreference.com/w/cpp/types/is_trivial} {std::is_trivial_v<T>}
- to identify primitive
- types and it will require both
- \l {https://en.cppreference.com/w/cpp/types/is_trivially_copyable} {std::is_trivially_copyable_v<T>}
- and
- \l {https://en.cppreference.com/w/cpp/types/is_destructible} {std::is_trivially_destructible_v<T>}
- to identify relocatable types.
- Use this macro to tune the behavior.
+ Qt will try to detect the class of a type using standard C++ type traits;
+ use this macro to tune the behavior.
For instance many types would be candidates for Q_RELOCATABLE_TYPE despite
not being trivially-copyable.
*/
diff --git a/src/corelib/global/qtypes.cpp b/src/corelib/global/qtypes.cpp
index 5c3b963a92..9de3960e2f 100644
--- a/src/corelib/global/qtypes.cpp
+++ b/src/corelib/global/qtypes.cpp
@@ -145,6 +145,43 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \typedef qint128
+ \relates <QtTypes>
+ \since 6.6
+
+ Typedef for \c{__int128} on platforms that support it (Qt defines the macro
+ \l QT_SUPPORTS_INT128 if this is the case).
+
+ Literals of this type can be created using the Q_INT128_C() macro.
+
+ \sa Q_INT128_C(), Q_INT128_MIN, Q_INT128_MAX, quint128, QT_SUPPORTS_INT128
+*/
+
+/*!
+ \typedef quint128
+ \relates <QtTypes>
+ \since 6.6
+
+ Typedef for \c{unsigned __int128} on platforms that support it (Qt defines
+ the macro \l QT_SUPPORTS_INT128 if this is the case).
+
+ Literals of this type can be created using the Q_UINT128_C() macro.
+
+ \sa Q_UINT128_C(), Q_UINT128_MAX, qint128, QT_SUPPORTS_INT128
+*/
+
+/*!
+ \macro QT_SUPPORTS_INT128
+ \relates <QtTypes>
+ \since 6.6
+
+ Qt defines this macro as well as the \l qint128 and \l quint128 types if
+ the platform has support for 128-bit integer types.
+
+ \sa qint128, quint128, Q_INT128_C(), Q_UINT128_C(), Q_INT128_MIN, Q_INT128_MAX, Q_UINT128_MAX
+*/
+
+/*!
\typedef qintptr
\relates <QtTypes>
@@ -327,7 +364,7 @@ QT_BEGIN_NAMESPACE
\snippet code/src_corelib_global_qglobal.cpp 8
- \sa qint64, Q_UINT64_C()
+ \sa qint64, Q_UINT64_C(), Q_INT128_C()
*/
/*! \macro quint64 Q_UINT64_C(literal)
@@ -340,7 +377,79 @@ QT_BEGIN_NAMESPACE
\snippet code/src_corelib_global_qglobal.cpp 9
- \sa quint64, Q_INT64_C()
+ \sa quint64, Q_INT64_C(), Q_UINT128_C()
+*/
+
+/*!
+ \macro qint128 Q_INT128_C(literal)
+ \relates <QtTypes>
+ \since 6.6
+
+ Wraps the signed 128-bit integer \a literal in a
+ platform-independent way.
+
+ \note Unlike Q_INT64_C(), this macro is only available in C++, not in C.
+ This is because compilers do not provide these literals as built-ins and C
+ does not have support for user-defined literals.
+
+ \sa qint128, Q_UINT128_C(), Q_INT128_MIN, Q_INT128_MAX, Q_INT64_C(), QT_SUPPORTS_INT128
+*/
+
+/*!
+ \macro quint128 Q_UINT128_C(literal)
+ \relates <QtTypes>
+ \since 6.6
+
+ Wraps the unsigned 128-bit integer \a literal in a
+ platform-independent way.
+
+ \note Unlike Q_UINT64_C(), this macro is only available in C++, not in C.
+ This is because compilers do not provide these literals as built-ins and C
+ does not have support for user-defined literals.
+
+ \sa quint128, Q_INT128_C(), Q_UINT128_MAX, Q_UINT64_C(), QT_SUPPORTS_INT128
+*/
+
+/*!
+ \macro Q_UINT128_MAX
+ \relates <QtTypes>
+ \since 6.6
+
+ This macro expands to a compile-time constant representing the
+ maximum value representable in a \l quint128.
+
+ This macro is available in both C++ and C modes.
+
+ The minimum of \l quint128 is 0 (zero), so a \c{Q_UINT128_MIN} is neither
+ needed nor provided.
+
+ \sa Q_INT128_MAX, quint128, Q_UINT128_C, QT_SUPPORTS_INT128
+*/
+
+/*!
+ \macro Q_INT128_MIN
+ \relates <QtTypes>
+ \since 6.6
+
+ This macro expands to a compile-time constant representing the
+ minimum value representable in a \l qint128.
+
+ This macro is available in both C++ and C modes.
+
+ \sa Q_INT128_MAX, qint128, Q_INT128_C, QT_SUPPORTS_INT128
+*/
+
+/*!
+ \macro Q_INT128_MAX
+ \relates <QtTypes>
+ \since 6.6
+
+ This macro expands to a compile-time constant representing the
+ maximum value representable in a \l qint128.
+
+ This macro is available in both C++ and C modes.
+
+ \sa Q_INT128_MIN, Q_UINT128_MAX, qint128, Q_INT128_C, QT_SUPPORTS_INT128
*/
// Statically check assumptions about the environment we're running
@@ -399,5 +508,21 @@ static_assert(sizeof(qint8) == 1, "Internal error, qint8 is misdefined");
static_assert(sizeof(qint16)== 2, "Internal error, qint16 is misdefined");
static_assert(sizeof(qint32) == 4, "Internal error, qint32 is misdefined");
static_assert(sizeof(qint64) == 8, "Internal error, qint64 is misdefined");
+#ifdef QT_SUPPORTS_INT128
+static_assert(sizeof(qint128) == 16, "Internal error, qint128 is misdefined");
+#endif
+
+#ifdef QT_SUPPORTS_INT128
+// Standard Library supports for 128-bit integers:
+// Implementation | Version | Note
+// ---------------------|---------|------
+// GNU libstdc++ | 11.1.0 |
+// LLVM libc++ | 3.5 | May change if compiler has __is_integral()
+// MS STL | none |
+
+# if defined(_LIBCPP_VERSION) || (defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE >= 11)
+static_assert(std::numeric_limits<quint128>::max() == Q_UINT128_MAX);
+# endif
+#endif
QT_END_NAMESPACE
diff --git a/src/corelib/global/qtypes.h b/src/corelib/global/qtypes.h
index fa41f03c44..db9ba38e4c 100644
--- a/src/corelib/global/qtypes.h
+++ b/src/corelib/global/qtypes.h
@@ -7,10 +7,17 @@
#include <QtCore/qprocessordetection.h>
#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qassert.h>
#ifdef __cplusplus
# include <cstddef>
# include <cstdint>
+# if defined(__STDCPP_FLOAT16_T__) && __has_include(<stdfloat>)
+// P1467 implementation - https://wg21.link/p1467
+# include <stdfloat>
+# endif // defined(__STDCPP_FLOAT16_T__) && __has_include(<stdfloat>)
+#else
+# include <assert.h>
#endif
#if 0
@@ -56,9 +63,104 @@ typedef unsigned long long quint64; /* 64 bit unsigned */
typedef qint64 qlonglong;
typedef quint64 qulonglong;
+#if defined(__SIZEOF_INT128__) && !defined(QT_NO_INT128)
+# define QT_SUPPORTS_INT128 __SIZEOF_INT128__
+#else
+# undef QT_SUPPORTS_INT128
+#endif
+
+#if defined(QT_SUPPORTS_INT128)
+__extension__ typedef __int128_t qint128;
+__extension__ typedef __uint128_t quint128;
+
+// limits:
+# ifdef __cplusplus /* need to avoid c-style-casts in C++ mode */
+# define QT_C_STYLE_CAST(type, x) static_cast<type>(x)
+# else /* but C doesn't have constructor-style casts */
+# define QT_C_STYLE_CAST(type, x) ((type)(x))
+# endif
+# ifndef Q_UINT128_MAX /* allow qcompilerdetection.h/user override */
+# define Q_UINT128_MAX QT_C_STYLE_CAST(quint128, -1)
+# endif
+# define Q_INT128_MAX QT_C_STYLE_CAST(qint128, Q_UINT128_MAX / 2)
+# define Q_INT128_MIN (-Q_INT128_MAX - 1)
+
+# ifdef __cplusplus
+ namespace QtPrivate::NumberLiterals {
+ namespace detail {
+ template <quint128 accu, int base>
+ constexpr quint128 construct() { return accu; }
+
+ template <quint128 accu, int base, char C, char...Cs>
+ constexpr quint128 construct()
+ {
+ if constexpr (C != '\'') { // ignore digit separators
+ const int digitValue = '0' <= C && C <= '9' ? C - '0' :
+ 'a' <= C && C <= 'z' ? C - 'a' + 10 :
+ 'A' <= C && C <= 'Z' ? C - 'A' + 10 :
+ /* else */ -1 ;
+ static_assert(digitValue >= 0 && digitValue < base,
+ "Invalid character");
+ // accu * base + digitValue <= MAX, but without overflow:
+ static_assert(accu <= (Q_UINT128_MAX - digitValue) / base,
+ "Overflow occurred");
+ return construct<accu * base + digitValue, base, Cs...>();
+ } else {
+ return construct<accu, base, Cs...>();
+ }
+ }
+
+ template <char C, char...Cs>
+ constexpr quint128 parse0xb()
+ {
+ constexpr quint128 accu = 0;
+ if constexpr (C == 'x' || C == 'X')
+ return construct<accu, 16, Cs...>(); // base 16, skip 'x'
+ else if constexpr (C == 'b' || C == 'B')
+ return construct<accu, 2, Cs...>(); // base 2, skip 'b'
+ else
+ return construct<accu, 8, C, Cs...>(); // base 8, include C
+ }
+
+ template <char...Cs>
+ constexpr quint128 parse0()
+ {
+ if constexpr (sizeof...(Cs) == 0) // this was just a literal 0
+ return 0;
+ else
+ return parse0xb<Cs...>();
+ }
+
+ template <char C, char...Cs>
+ constexpr quint128 parse()
+ {
+ if constexpr (C == '0')
+ return parse0<Cs...>(); // base 2, 8, or 16 (or just a literal 0), skip '0'
+ else
+ return construct<0, 10, C, Cs...>(); // initial accu 0, base 10, include C
+ }
+ } // namespace detail
+ template <char...Cs>
+ constexpr quint128 operator""_quint128() noexcept
+ { return QtPrivate::NumberLiterals::detail::parse<Cs...>(); }
+ template <char...Cs>
+ constexpr qint128 operator""_qint128() noexcept
+ { return qint128(QtPrivate::NumberLiterals::detail::parse<Cs...>()); }
+
+ #ifndef Q_UINT128_C // allow qcompilerdetection.h/user override
+ # define Q_UINT128_C(c) ([]{ using namespace QtPrivate::NumberLiterals; return c ## _quint128; }())
+ #endif
+ #ifndef Q_INT128_C // allow qcompilerdetection.h/user override
+ # define Q_INT128_C(c) ([]{ using namespace QtPrivate::NumberLiterals; return c ## _qint128; }())
+ #endif
+
+ } // namespace QtPrivate::NumberLiterals
+# endif // __cplusplus
+#endif // QT_SUPPORTS_INT128
+
#ifndef __cplusplus
// In C++ mode, we define below using QIntegerForSize template
-Q_STATIC_ASSERT_X(sizeof(ptrdiff_t) == sizeof(size_t), "Weird ptrdiff_t and size_t definitions");
+static_assert(sizeof(ptrdiff_t) == sizeof(size_t), "Weird ptrdiff_t and size_t definitions");
typedef ptrdiff_t qptrdiff;
typedef ptrdiff_t qsizetype;
typedef ptrdiff_t qintptr;
@@ -100,8 +202,8 @@ template <> struct QIntegerForSize<1> { typedef quint8 Unsigned; typedef qin
template <> struct QIntegerForSize<2> { typedef quint16 Unsigned; typedef qint16 Signed; };
template <> struct QIntegerForSize<4> { typedef quint32 Unsigned; typedef qint32 Signed; };
template <> struct QIntegerForSize<8> { typedef quint64 Unsigned; typedef qint64 Signed; };
-#if defined(Q_CC_GNU) && defined(__SIZEOF_INT128__)
-template <> struct QIntegerForSize<16> { __extension__ typedef unsigned __int128 Unsigned; __extension__ typedef __int128 Signed; };
+#if defined(QT_SUPPORTS_INT128)
+template <> struct QIntegerForSize<16> { typedef quint128 Unsigned; typedef qint128 Signed; };
#endif
template <class T> struct QIntegerForSizeof: QIntegerForSize<sizeof(T)> { };
typedef QIntegerForSize<Q_PROCESSOR_WORDSIZE>::Signed qregisterint;
@@ -152,6 +254,28 @@ using qsizetype = QIntegerForSizeof<std::size_t>::Signed;
#error Unsupported platform (unknown value for SIZE_MAX)
#endif
+// Define a native float16 type
+namespace QtPrivate {
+#if defined(__STDCPP_FLOAT16_T__)
+# define QFLOAT16_IS_NATIVE 1
+using NativeFloat16Type = std::float16_t;
+#elif defined(Q_CC_CLANG) && defined(__FLT16_MAX__) && 0
+// disabled due to https://github.com/llvm/llvm-project/issues/56963
+# define QFLOAT16_IS_NATIVE 1
+using NativeFloat16Type = decltype(__FLT16_MAX__);
+#elif defined(Q_CC_GNU_ONLY) && defined(__FLT16_MAX__)
+# define QFLOAT16_IS_NATIVE 1
+# ifdef __ARM_FP16_FORMAT_IEEE
+using NativeFloat16Type = __fp16;
+# else
+using NativeFloat16Type = _Float16;
+# endif
+#else
+# define QFLOAT16_IS_NATIVE 0
+using NativeFloat16Type = void;
+#endif
+} // QtPrivate
+
#endif // __cplusplus
QT_END_NAMESPACE
diff --git a/src/corelib/global/qversiontagging.h b/src/corelib/global/qversiontagging.h
index 05d0998c45..965d53e88f 100644
--- a/src/corelib/global/qversiontagging.h
+++ b/src/corelib/global/qversiontagging.h
@@ -1,12 +1,18 @@
// Copyright (C) 2022 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-// qglobal.h includes this header, so keep it outside of our include guards
-#include <QtCore/qglobal.h>
-
#if !defined(QVERSIONTAGGING_H)
#define QVERSIONTAGGING_H
+#if 0
+#pragma qt_no_master_include
+#endif
+
+#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qtversionchecks.h>
+#include <QtCore/qtypes.h>
+
QT_BEGIN_NAMESPACE
/*
diff --git a/src/corelib/global/qxpfunctional.h b/src/corelib/global/qxpfunctional.h
index abe00087ad..cbeef8b293 100644
--- a/src/corelib/global/qxpfunctional.h
+++ b/src/corelib/global/qxpfunctional.h
@@ -108,6 +108,23 @@ public:
class F,
std::enable_if_t<std::conjunction_v<
std::negation<std::is_same<q20::remove_cvref_t<F>, function_ref_base>>,
+#ifdef Q_OS_VXWORKS
+ // The VxWorks compiler is trying to match this ctor against
+ // qxp::function_ref in lieu of using the copy-constructor, so ban
+ // matching against the equivalent qxp::function_ref here.
+ // This doesn't change anything on other platforms, so to save
+ // on compile-speed, enable it only for VxWorks:
+ std::negation<
+ std::is_same<
+ q20::remove_cvref_t<F>,
+ std::conditional_t<
+ std::is_const_v<Const>,
+ qxp::function_ref<R(ArgTypes...) const noexcept(noex)>,
+ qxp::function_ref<R(ArgTypes...) noexcept(noex)>
+ >
+ >
+ >,
+#endif // Q_OS_VXWORKS
std::negation<std::is_member_pointer<std::remove_reference_t<F>>>,
is_invocable_using<copy_const_t<Const, std::remove_reference_t<F>>&>
>, bool> = true
@@ -124,9 +141,11 @@ public:
protected:
template <
class T,
- std::enable_if_t<std::conjunction_v<
- std::negation<std::is_same<q20::remove_cvref_t<T>, function_ref_base>>,
- std::negation<std::is_pointer<T>>
+ std::enable_if_t<std::negation_v<
+ std::disjunction<
+ std::is_same<T, function_ref_base>,
+ std::is_pointer<T>
+ >
>, bool> = true
>
function_ref_base& operator=(T) = delete;
@@ -165,7 +184,7 @@ QT_SPECIALIZE_FUNCTION_REF(const, true );
template <
class F,
- std::enable_if_t<std::is_function_v<F>, bool> = true
+ detail::if_function<F> = true
>
function_ref(F*) -> function_ref<F>;
diff --git a/src/corelib/global/qxptype_traits.h b/src/corelib/global/qxptype_traits.h
index 7da0478583..d1641e1d0d 100644
--- a/src/corelib/global/qxptype_traits.h
+++ b/src/corelib/global/qxptype_traits.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
+// Copyright (C) 2023 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>, Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
@@ -6,6 +6,7 @@
#define QXPTYPE_TRAITS_H
#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qcompilerdetection.h>
#include <type_traits>
@@ -55,6 +56,63 @@ using is_detected = typename _detail::detector<qxp::nonesuch, void, Op, Args...>
template <template <typename...> class Op, typename...Args>
constexpr inline bool is_detected_v = is_detected<Op, Args...>::value;
+
+// qxp::is_virtual_base_of_v<B, D> is true if and only if B is a virtual base class of D.
+// Just like is_base_of:
+// * only works on complete types;
+// * B and D must be class types;
+// * ignores cv-qualifications;
+// * B may be inaccessibile.
+
+namespace _detail {
+ // Check that From* can be converted to To*, ignoring accessibility.
+ // This can be done using a C cast (see [expr.cast]/4).
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Wold-style-cast")
+QT_WARNING_DISABLE_CLANG("-Wold-style-cast")
+ template <typename From, typename To>
+ using is_virtual_base_conversion_test = decltype(
+ (To *)std::declval<From *>()
+ );
+QT_WARNING_POP
+
+ template <typename Base, typename Derived, typename = void>
+ struct is_virtual_base_of : std::false_type {};
+
+ template <typename Base, typename Derived>
+ struct is_virtual_base_of<
+ Base, Derived,
+ std::enable_if_t<
+ std::conjunction_v<
+ // Base is a base class of Derived.
+ std::is_base_of<Base, Derived>,
+
+ // Check that Derived* can be converted to Base*, ignoring
+ // accessibility. If this is possible, then Base is
+ // an unambiguous base of Derived (=> virtual bases are always
+ // unambiguous).
+ qxp::is_detected<is_virtual_base_conversion_test, Derived, Base>,
+
+ // Check that Base* can _not_ be converted to Derived*,
+ // again ignoring accessibility. This seals the deal:
+ // if this conversion cannot happen, it means that Base is an
+ // ambiguous base and/or it is a virtual base.
+ // But we have already established that Base is an unambiguous
+ // base, hence: Base is a virtual base.
+ std::negation<
+ qxp::is_detected<is_virtual_base_conversion_test, Base, Derived>
+ >
+ >
+ >
+ > : std::true_type {};
+}
+
+template <typename Base, typename Derived>
+using is_virtual_base_of = _detail::is_virtual_base_of<std::remove_cv_t<Base>, std::remove_cv_t<Derived>>;
+
+template <typename Base, typename Derived>
+constexpr inline bool is_virtual_base_of_v = is_virtual_base_of<Base, Derived>::value;
+
} // namespace qxp
QT_END_NAMESPACE
diff --git a/src/corelib/io/forkfd_qt.cpp b/src/corelib/io/forkfd_qt.c
index 3c6d05d6a8..7107b2c6a0 100644
--- a/src/corelib/io/forkfd_qt.cpp
+++ b/src/corelib/io/forkfd_qt.c
@@ -1,6 +1,9 @@
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
#include <QtCore/qglobal.h>
#define FORKFD_NO_SPAWNFD
diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp
index 25dfe79d64..ea5ce13b5e 100644
--- a/src/corelib/io/qabstractfileengine.cpp
+++ b/src/corelib/io/qabstractfileengine.cpp
@@ -10,7 +10,7 @@
#include "qreadwritelock.h"
#include "qvariant.h"
// built-in handlers
-#include "qdiriterator.h"
+#include "qdirlisting.h"
#include "qstringbuilder.h"
#include <QtCore/private/qfilesystementry_p.h>
@@ -19,6 +19,19 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+static QString appendSlashIfNeeded(const QString &path)
+{
+ if (!path.isEmpty() && !path.endsWith(u'/')
+#ifdef Q_OS_ANDROID
+ && !path.startsWith("content:/"_L1)
+#endif
+ )
+ return QString{path + u'/'};
+ return path;
+}
+
/*!
\class QAbstractFileEngineHandler
\inmodule QtCore
@@ -75,7 +88,10 @@ Q_GLOBAL_STATIC(QReadWriteLock, fileEngineHandlerMutex, QReadWriteLock::Recursiv
Q_CONSTINIT static bool qt_abstractfileenginehandlerlist_shutDown = false;
class QAbstractFileEngineHandlerList : public QList<QAbstractFileEngineHandler *>
{
+ Q_DISABLE_COPY_MOVE(QAbstractFileEngineHandlerList)
public:
+ QAbstractFileEngineHandlerList() = default;
+
~QAbstractFileEngineHandlerList()
{
QWriteLocker locker(fileEngineHandlerMutex());
@@ -121,14 +137,14 @@ QAbstractFileEngineHandler::~QAbstractFileEngineHandler()
Handles calls to custom file engine handlers.
*/
-QAbstractFileEngine *qt_custom_file_engine_handler_create(const QString &path)
+std::unique_ptr<QAbstractFileEngine> qt_custom_file_engine_handler_create(const QString &path)
{
if (qt_file_engine_handlers_in_use.loadRelaxed()) {
QReadLocker locker(fileEngineHandlerMutex());
// check for registered handlers that can load the file
for (QAbstractFileEngineHandler *handler : std::as_const(*fileEngineHandlers())) {
- if (QAbstractFileEngine *engine = handler->create(path))
+ if (auto engine = handler->create(path))
return engine;
}
}
@@ -137,10 +153,11 @@ QAbstractFileEngine *qt_custom_file_engine_handler_create(const QString &path)
}
/*!
- \fn QAbstractFileEngine *QAbstractFileEngineHandler::create(const QString &fileName) const
+ \fn std::unique_ptr<QAbstractFileEngine> QAbstractFileEngineHandler::create(const QString &fileName) const
- Creates a file engine for file \a fileName. Returns 0 if this
- file handler cannot handle \a fileName.
+ If this file handler can handle \a fileName, this method creates a file
+ engine and returns it wrapped in a std::unique_ptr; otherwise returns
+ nullptr.
Example:
@@ -162,16 +179,15 @@ QAbstractFileEngine *qt_custom_file_engine_handler_create(const QString &path)
\sa QAbstractFileEngineHandler
*/
-QAbstractFileEngine *QAbstractFileEngine::create(const QString &fileName)
+std::unique_ptr<QAbstractFileEngine> QAbstractFileEngine::create(const QString &fileName)
{
QFileSystemEntry entry(fileName);
QFileSystemMetaData metaData;
- QAbstractFileEngine *engine = QFileSystemEngine::resolveEntryAndCreateLegacyEngine(entry, metaData);
+ auto engine = QFileSystemEngine::createLegacyEngine(entry, metaData);
#ifndef QT_NO_FSFILEENGINE
- if (!engine)
- // fall back to regular file engine
- return new QFSFileEngine(entry.filePath());
+ if (!engine) // fall back to regular file engine
+ engine = std::make_unique<QFSFileEngine>(entry.filePath());
#endif
return engine;
@@ -289,20 +305,6 @@ QAbstractFileEngine *QAbstractFileEngine::create(const QString &fileName)
*/
/*!
- \enum QAbstractFileEngine::FileTime
-
- These are used by the fileTime() function.
-
- \value BirthTime When the file was born (created).
- \value MetadataChangeTime When the file's metadata was last changed.
- \value ModificationTime When the file was most recently modified.
- \value AccessTime When the file was most recently accessed (e.g.
- read or written to).
-
- \sa setFileName()
-*/
-
-/*!
\enum QAbstractFileEngine::FileOwner
\value OwnerUser The user who owns the file.
@@ -590,12 +592,15 @@ bool QAbstractFileEngine::isRelativePath() const
QStringList QAbstractFileEngine::entryList(QDir::Filters filters, const QStringList &filterNames) const
{
QStringList ret;
- QDirIterator it(fileName(), filterNames, filters);
- while (it.hasNext()) {
- it.next();
- ret << it.fileName();
- }
+#ifdef QT_BOOTSTRAPPED
+ Q_UNUSED(filters);
+ Q_UNUSED(filterNames);
+ Q_UNREACHABLE_RETURN(ret);
+#else
+ for (const auto &dirEntry : QDirListing(fileName(), filterNames, filters))
+ ret.emplace_back(dirEntry.fileName());
return ret;
+#endif
}
/*!
@@ -695,7 +700,7 @@ QString QAbstractFileEngine::owner(FileOwner owner) const
\sa fileTime()
*/
-bool QAbstractFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
+bool QAbstractFileEngine::setFileTime(const QDateTime &newDate, QFile::FileTime time)
{
Q_UNUSED(newDate);
Q_UNUSED(time);
@@ -712,7 +717,7 @@ bool QAbstractFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
\sa setFileName(), QDateTime, QDateTime::isValid(), FileTime
*/
-QDateTime QAbstractFileEngine::fileTime(FileTime time) const
+QDateTime QAbstractFileEngine::fileTime(QFile::FileTime time) const
{
Q_UNUSED(time);
return QDateTime();
@@ -774,10 +779,7 @@ bool QAbstractFileEngine::atEnd() const
uchar *QAbstractFileEngine::map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags)
{
- MapExtensionOption option;
- option.offset = offset;
- option.size = size;
- option.flags = flags;
+ const MapExtensionOption option(offset, size, flags);
MapExtensionReturn r;
if (!extension(MapExtension, &option, &r))
return nullptr;
@@ -798,8 +800,7 @@ uchar *QAbstractFileEngine::map(qint64 offset, qint64 size, QFile::MemoryMapFlag
*/
bool QAbstractFileEngine::unmap(uchar *address)
{
- UnMapExtensionOption options;
- options.address = address;
+ const UnMapExtensionOption options(address);
return extension(UnMapExtension, &options);
}
@@ -826,11 +827,12 @@ bool QAbstractFileEngine::cloneTo(QAbstractFileEngine *target)
\internal
If all you want is to iterate over entries in a directory, see
- QDirIterator instead. This class is only for custom file engine authors.
+ QDirListing instead. This class is useful only for custom file engine
+ authors.
QAbstractFileEngineIterator is a unidirectional single-use virtual
- iterator that plugs into QDirIterator, providing transparent proxy
- iteration for custom file engines.
+ iterator that plugs into QDirListing, providing transparent proxy
+ iteration for custom file engines (for example, QResourceFileEngine).
You can subclass QAbstractFileEngineIterator to provide an iterator when
writing your own file engine. To plug the iterator into your file system,
@@ -851,10 +853,11 @@ bool QAbstractFileEngine::cloneTo(QAbstractFileEngine *target)
You can call dirName() to get the directory name, nameFilters() to get a
stringlist of name filters, and filters() to get the entry filters.
- The pure virtual function hasNext() returns \c true if the current directory
- has at least one more entry (i.e., the directory name is valid and
- accessible, and we have not reached the end of the entry list), and false
- otherwise. Reimplement next() to seek to the next entry.
+ The pure virtual function advance(), as its name implies, advances the
+ iterator to the next entry in the current directory; if the operation
+ was successful this method returns \c true, otherwise it returns \c
+ false. You have to reimplement this function in your sub-class to work
+ with your file engine implementation.
The pure virtual function currentFileName() returns the name of the
current entry without advancing the iterator. The currentFilePath()
@@ -869,15 +872,7 @@ bool QAbstractFileEngine::cloneTo(QAbstractFileEngine *target)
Note: QAbstractFileEngineIterator does not deal with QDir::IteratorFlags;
it simply returns entries for a single directory.
- \sa QDirIterator
-*/
-
-/*!
- \enum QAbstractFileEngineIterator::EntryInfoType
- \internal
-
- This enum describes the different types of information that can be
- requested through the QAbstractFileEngineIterator::entryInfo() function.
+ \sa QDirListing
*/
/*!
@@ -887,56 +882,45 @@ bool QAbstractFileEngine::cloneTo(QAbstractFileEngine *target)
Synonym for QAbstractFileEngineIterator.
*/
-class QAbstractFileEngineIteratorPrivate
-{
-public:
- QString path;
- QDir::Filters filters;
- QStringList nameFilters;
- QFileInfo fileInfo;
-};
+/*!
+ \typedef QAbstractFileEngine::IteratorUniquePtr
+ \since 6.8
+
+ Synonym for std::unique_ptr<Iterator> (that is a
+ std::unique_ptr<QAbstractFileEngineIterator>).
+*/
/*!
Constructs a QAbstractFileEngineIterator, using the entry filters \a
filters, and wildcard name filters \a nameFilters.
*/
-QAbstractFileEngineIterator::QAbstractFileEngineIterator(QDir::Filters filters,
+QAbstractFileEngineIterator::QAbstractFileEngineIterator(const QString &path, QDir::Filters filters,
const QStringList &nameFilters)
- : d(new QAbstractFileEngineIteratorPrivate)
+ : m_filters(filters),
+ m_nameFilters(nameFilters),
+ m_path(appendSlashIfNeeded(path))
{
- d->nameFilters = nameFilters;
- d->filters = filters;
}
/*!
Destroys the QAbstractFileEngineIterator.
- \sa QDirIterator
+ \sa QDirListing
*/
QAbstractFileEngineIterator::~QAbstractFileEngineIterator()
{
}
/*!
- Returns the path for this iterator. QDirIterator is responsible for
- assigning this path; it cannot change during the iterator's lifetime.
+
+ Returns the path for this iterator. The path is set by beginEntryList().
+ The path should't be changed once iteration begins.
\sa nameFilters(), filters()
*/
QString QAbstractFileEngineIterator::path() const
{
- return d->path;
-}
-
-/*!
- \internal
-
- Sets the iterator path to \a path. This function is called from within
- QDirIterator.
-*/
-void QAbstractFileEngineIterator::setPath(const QString &path)
-{
- d->path = path;
+ return m_path;
}
/*!
@@ -946,7 +930,7 @@ void QAbstractFileEngineIterator::setPath(const QString &path)
*/
QStringList QAbstractFileEngineIterator::nameFilters() const
{
- return d->nameFilters;
+ return m_nameFilters;
}
/*!
@@ -956,7 +940,7 @@ QStringList QAbstractFileEngineIterator::nameFilters() const
*/
QDir::Filters QAbstractFileEngineIterator::filters() const
{
- return d->filters;
+ return m_filters;
}
/*!
@@ -977,15 +961,10 @@ QDir::Filters QAbstractFileEngineIterator::filters() const
QString QAbstractFileEngineIterator::currentFilePath() const
{
QString name = currentFileName();
- if (!name.isNull()) {
- QString tmp = path();
- if (!tmp.isEmpty()) {
- if (!tmp.endsWith(u'/'))
- tmp.append(u'/');
- name.prepend(tmp);
- }
- }
- return name;
+ if (name.isNull())
+ return name;
+
+ return path() + name;
}
/*!
@@ -1000,75 +979,42 @@ QString QAbstractFileEngineIterator::currentFilePath() const
QFileInfo QAbstractFileEngineIterator::currentFileInfo() const
{
QString path = currentFilePath();
- if (d->fileInfo.filePath() != path)
- d->fileInfo.setFile(path);
+ if (m_fileInfo.filePath() != path)
+ m_fileInfo.setFile(path);
// return a shallow copy
- return d->fileInfo;
-}
-
-/*!
- \internal
-
- Returns the entry info \a type for this iterator's current directory entry
- as a QVariant. If \a type is undefined for this entry, a null QVariant is
- returned.
-
- \sa QAbstractFileEngine::beginEntryList(), QDir::beginEntryList()
-*/
-QVariant QAbstractFileEngineIterator::entryInfo(EntryInfoType type) const
-{
- Q_UNUSED(type);
- return QVariant();
+ return m_fileInfo;
}
/*!
- \fn virtual QString QAbstractFileEngineIterator::next() = 0
+ \fn virtual bool QAbstractFileEngineIterator::advance() = 0
This pure virtual function advances the iterator to the next directory
- entry, and returns the file path to the current entry.
+ entry; if the operation was successful this method returns \c true,
+ otherwise it returs \c false.
This function can optionally make use of nameFilters() and filters() to
optimize its performance.
Reimplement this function in a subclass to advance the iterator.
-
- \sa QDirIterator::next()
-*/
-
-/*!
- \fn virtual bool QAbstractFileEngineIterator::hasNext() const = 0
-
- This pure virtual function returns \c true if there is at least one more
- entry in the current directory (i.e., the iterator path is valid and
- accessible, and the iterator has not reached the end of the entry list).
-
- \sa QDirIterator::hasNext()
*/
/*!
- Returns an instance of a QAbstractFileEngineIterator using \a filters for
- entry filtering and \a filterNames for name filtering. This function is
- called by QDirIterator to initiate directory iteration.
+ Returns a QAbstractFileEngine::IteratorUniquePtr, that can be used
+ to iterate over the entries in \a path, using \a filters for entry
+ filtering and \a filterNames for name filtering. This function is called
+ by QDirListing to initiate directory iteration.
- QDirIterator takes ownership of the returned instance, and deletes it when
- it's done.
-
- \sa QDirIterator
+ \sa QDirListing
*/
-QAbstractFileEngine::Iterator *QAbstractFileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames)
+QAbstractFileEngine::IteratorUniquePtr
+QAbstractFileEngine::beginEntryList(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames)
{
+ Q_UNUSED(path);
Q_UNUSED(filters);
Q_UNUSED(filterNames);
- return nullptr;
-}
-
-/*!
- \internal
-*/
-QAbstractFileEngine::Iterator *QAbstractFileEngine::endEntryList()
-{
- return nullptr;
+ return {};
}
/*!
diff --git a/src/corelib/io/qabstractfileengine_p.h b/src/corelib/io/qabstractfileengine_p.h
index 28f07bf8f9..b2e0b248da 100644
--- a/src/corelib/io/qabstractfileengine_p.h
+++ b/src/corelib/io/qabstractfileengine_p.h
@@ -19,6 +19,7 @@
#include "QtCore/qfile.h"
#include "QtCore/qdir.h"
+#include <memory>
#include <optional>
#ifdef open
@@ -80,12 +81,7 @@ public:
OwnerUser,
OwnerGroup
};
- enum FileTime {
- AccessTime,
- BirthTime,
- MetadataChangeTime,
- ModificationTime
- };
+
virtual ~QAbstractFileEngine();
@@ -116,8 +112,8 @@ public:
virtual QString fileName(FileName file=DefaultName) const;
virtual uint ownerId(FileOwner) const;
virtual QString owner(FileOwner) const;
- virtual bool setFileTime(const QDateTime &newDate, FileTime time);
- virtual QDateTime fileTime(FileTime time) const;
+ virtual bool setFileTime(const QDateTime &newDate, QFile::FileTime time);
+ virtual QDateTime fileTime(QFile::FileTime time) const;
virtual void setFileName(const QString &file);
virtual int handle() const;
virtual bool cloneTo(QAbstractFileEngine *target);
@@ -126,8 +122,11 @@ public:
bool unmap(uchar *ptr);
typedef QAbstractFileEngineIterator Iterator;
- virtual Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames);
- virtual Iterator *endEntryList();
+ using IteratorUniquePtr = std::unique_ptr<Iterator>;
+
+ virtual IteratorUniquePtr
+ beginEntryList(const QString &path, QDir::Filters filters, const QStringList &filterNames);
+ virtual IteratorUniquePtr endEntryList() { return {}; }
virtual qint64 read(char *data, qint64 maxlen);
virtual qint64 readLine(char *data, qint64 maxlen);
@@ -148,26 +147,33 @@ public:
{};
class MapExtensionOption : public ExtensionOption {
+ Q_DISABLE_COPY_MOVE(MapExtensionOption)
public:
qint64 offset;
qint64 size;
QFile::MemoryMapFlags flags;
+ constexpr MapExtensionOption(qint64 off, qint64 sz, QFile::MemoryMapFlags f)
+ : offset(off), size(sz), flags(f) {}
};
class MapExtensionReturn : public ExtensionReturn {
+ Q_DISABLE_COPY_MOVE(MapExtensionReturn)
public:
- uchar *address;
+ MapExtensionReturn() = default;
+ uchar *address = nullptr;
};
class UnMapExtensionOption : public ExtensionOption {
+ Q_DISABLE_COPY_MOVE(UnMapExtensionOption)
public:
- uchar *address;
+ uchar *address = nullptr;
+ constexpr UnMapExtensionOption(uchar *p) : address(p) {}
};
virtual bool extension(Extension extension, const ExtensionOption *option = nullptr, ExtensionReturn *output = nullptr);
virtual bool supportsExtension(Extension extension) const;
// Factory
- static QAbstractFileEngine *create(const QString &fileName);
+ static std::unique_ptr<QAbstractFileEngine> create(const QString &fileName);
protected:
void setError(QFile::FileError error, const QString &str);
@@ -185,21 +191,21 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractFileEngine::FileFlags)
class Q_CORE_EXPORT QAbstractFileEngineHandler
{
+ Q_DISABLE_COPY_MOVE(QAbstractFileEngineHandler)
public:
QAbstractFileEngineHandler();
virtual ~QAbstractFileEngineHandler();
- virtual QAbstractFileEngine *create(const QString &fileName) const = 0;
+ virtual std::unique_ptr<QAbstractFileEngine> create(const QString &fileName) const = 0;
};
-class QAbstractFileEngineIteratorPrivate;
class Q_CORE_EXPORT QAbstractFileEngineIterator
{
public:
- QAbstractFileEngineIterator(QDir::Filters filters, const QStringList &nameFilters);
+ QAbstractFileEngineIterator(const QString &path, QDir::Filters filters,
+ const QStringList &nameFilters);
virtual ~QAbstractFileEngineIterator();
- virtual QString next() = 0;
- virtual bool hasNext() const = 0;
+ virtual bool advance() = 0;
QString path() const;
QStringList nameFilters() const;
@@ -210,16 +216,17 @@ public:
virtual QString currentFilePath() const;
protected:
- enum EntryInfoType {
- };
- virtual QVariant entryInfo(EntryInfoType type) const;
+ mutable QFileInfo m_fileInfo;
private:
Q_DISABLE_COPY_MOVE(QAbstractFileEngineIterator)
friend class QDirIterator;
friend class QDirIteratorPrivate;
- void setPath(const QString &path);
- QScopedPointer<QAbstractFileEngineIteratorPrivate> d;
+ friend class QDirListingPrivate;
+
+ QDir::Filters m_filters;
+ QStringList m_nameFilters;
+ QString m_path;
};
class QAbstractFileEnginePrivate
@@ -238,7 +245,7 @@ public:
Q_DECLARE_PUBLIC(QAbstractFileEngine)
};
-QAbstractFileEngine *qt_custom_file_engine_handler_create(const QString &path);
+std::unique_ptr<QAbstractFileEngine> qt_custom_file_engine_handler_create(const QString &path);
QT_END_NAMESPACE
diff --git a/src/corelib/io/qbuffer.cpp b/src/corelib/io/qbuffer.cpp
index ba1ce7463b..763620692c 100644
--- a/src/corelib/io/qbuffer.cpp
+++ b/src/corelib/io/qbuffer.cpp
@@ -401,7 +401,7 @@ qint64 QBuffer::writeData(const char *data, qint64 len)
if (required > quint64(d->buf->size())) { // capacity exceeded
// The following must hold, since qsizetype covers half the virtual address space:
- Q_ASSUME(required <= quint64((std::numeric_limits<qsizetype>::max)()));
+ Q_ASSERT(required <= quint64((std::numeric_limits<qsizetype>::max)()));
d->buf->resize(qsizetype(required));
if (quint64(d->buf->size()) != required) { // could not resize
qWarning("QBuffer::writeData: Memory allocation error");
diff --git a/src/corelib/io/qdataurl.cpp b/src/corelib/io/qdataurl.cpp
index 92c6f54122..65b934b3f6 100644
--- a/src/corelib/io/qdataurl.cpp
+++ b/src/corelib/io/qdataurl.cpp
@@ -26,32 +26,36 @@ Q_CORE_EXPORT bool qDecodeDataUrl(const QUrl &uri, QString &mimeType, QByteArray
// reality often differs from the specification. People have
// data: URIs with ? and #
//QByteArray data = QByteArray::fromPercentEncoding(uri.path(QUrl::FullyEncoded).toLatin1());
- QByteArray data = QByteArray::fromPercentEncoding(uri.url(QUrl::FullyEncoded | QUrl::RemoveScheme).toLatin1());
+ const QByteArray dataArray =
+ QByteArray::fromPercentEncoding(uri.url(QUrl::FullyEncoded | QUrl::RemoveScheme).toLatin1());
+ QByteArrayView data = dataArray;
// parse it:
const qsizetype pos = data.indexOf(',');
if (pos != -1) {
- payload = data.mid(pos + 1);
+ payload = data.mid(pos + 1).toByteArray();
data.truncate(pos);
data = data.trimmed();
// find out if the payload is encoded in Base64
- if (QLatin1StringView{data}.endsWith(";base64"_L1, Qt::CaseInsensitive)) {
+ constexpr auto base64 = ";base64"_L1;
+ if (QLatin1StringView{data}.endsWith(base64, Qt::CaseInsensitive)) {
payload = QByteArray::fromBase64(payload);
- data.chop(7);
+ data.chop(base64.size());
}
- if (QLatin1StringView{data}.startsWith("charset"_L1, Qt::CaseInsensitive)) {
- qsizetype i = 7; // strlen("charset")
+ QLatin1StringView textPlain;
+ constexpr auto charset = "charset"_L1;
+ if (QLatin1StringView{data}.startsWith(charset, Qt::CaseInsensitive)) {
+ qsizetype i = charset.size();
while (data.at(i) == ' ')
++i;
if (data.at(i) == '=')
- data.prepend("text/plain;");
+ textPlain = "text/plain;"_L1;
}
if (!data.isEmpty())
- mimeType = QString::fromLatin1(data.trimmed());
-
+ mimeType = textPlain + QLatin1StringView(data.trimmed());
}
return true;
diff --git a/src/corelib/io/qdataurl_p.h b/src/corelib/io/qdataurl_p.h
index 91b8333108..2763056cc4 100644
--- a/src/corelib/io/qdataurl_p.h
+++ b/src/corelib/io/qdataurl_p.h
@@ -19,7 +19,6 @@
#include "QtCore/qurl.h"
#include "QtCore/qbytearray.h"
#include "QtCore/qstring.h"
-#include "QtCore/qpair.h"
QT_BEGIN_NAMESPACE
diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp
index 0a72696a37..64b693fea5 100644
--- a/src/corelib/io/qdebug.cpp
+++ b/src/corelib/io/qdebug.cpp
@@ -2,19 +2,16 @@
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifdef QT_NO_DEBUG
-#undef QT_NO_DEBUG
-#endif
-#ifdef qDebug
-#undef qDebug
-#endif
-
#include "qdebug.h"
#include "private/qdebug_p.h"
#include "qmetaobject.h"
+#include <private/qlogging_p.h>
#include <private/qtextstream_p.h>
#include <private/qtools_p.h>
+#include <array>
+#include <q20chrono.h>
+
QT_BEGIN_NAMESPACE
using namespace QtMiscUtils;
@@ -154,15 +151,15 @@ QByteArray QtDebugUtils::toPrintable(const char *data, qint64 len, qsizetype max
Flushes any pending data to be written and destroys the debug stream.
*/
-// Has been defined in the header / inlined before Qt 5.4
QDebug::~QDebug()
{
if (stream && !--stream->ref) {
if (stream->space && stream->buffer.endsWith(u' '))
stream->buffer.chop(1);
if (stream->message_output) {
+ QInternalMessageLogContext ctxt(stream->context);
qt_message_output(stream->type,
- stream->context,
+ ctxt,
stream->buffer);
}
delete stream;
@@ -345,6 +342,176 @@ void QDebug::putByteArray(const char *begin, size_t length, Latin1Content conten
}
}
+static QByteArray timeUnit(qint64 num, qint64 den)
+{
+ using namespace std::chrono;
+ using namespace q20::chrono;
+
+ if (num == 1 && den > 1) {
+ // sub-multiple of seconds
+ char prefix = '\0';
+ auto tryprefix = [&](auto d, char c) {
+ static_assert(decltype(d)::num == 1, "not an SI prefix");
+ if (den == decltype(d)::den)
+ prefix = c;
+ };
+
+ // "u" should be "µ", but debugging output is not always UTF-8-safe
+ tryprefix(std::milli{}, 'm');
+ tryprefix(std::micro{}, 'u');
+ tryprefix(std::nano{}, 'n');
+ tryprefix(std::pico{}, 'p');
+ tryprefix(std::femto{}, 'f');
+ tryprefix(std::atto{}, 'a');
+ // uncommon ones later
+ tryprefix(std::centi{}, 'c');
+ tryprefix(std::deci{}, 'd');
+ if (prefix) {
+ char unit[3] = { prefix, 's' };
+ return QByteArray(unit, sizeof(unit) - 1);
+ }
+ }
+
+ const char *unit = nullptr;
+ if (num > 1 && den == 1) {
+ // multiple of seconds - but we don't use SI prefixes
+ auto tryunit = [&](auto d, const char *name) {
+ static_assert(decltype(d)::period::den == 1, "not a multiple of a second");
+ if (unit || num % decltype(d)::period::num)
+ return;
+ unit = name;
+ num /= decltype(d)::period::num;
+ };
+ tryunit(years{}, "yr");
+ tryunit(weeks{}, "wk");
+ tryunit(days{}, "d");
+ tryunit(hours{}, "h");
+ tryunit(minutes{}, "min");
+ }
+ if (!unit)
+ unit = "s";
+
+ if (num == 1 && den == 1)
+ return unit;
+ if (Q_UNLIKELY(num < 1 || den < 1))
+ return QString::asprintf("<invalid time unit %lld/%lld>", num, den).toLatin1();
+
+ // uncommon units: will return something like "[2/3]s"
+ // strlen("[/]min") = 6
+ char buf[2 * (std::numeric_limits<qint64>::digits10 + 2) + 10];
+ size_t len = 0;
+ auto appendChar = [&](char c) {
+ Q_ASSERT(len < sizeof(buf));
+ buf[len++] = c;
+ };
+ auto appendNumber = [&](qint64 value) {
+ if (value >= 10'000 && (value % 1000) == 0)
+ len += qsnprintf(buf + len, sizeof(buf) - len, "%.6g", double(value)); // "1e+06"
+ else
+ len += qsnprintf(buf + len, sizeof(buf) - len, "%lld", value);
+ };
+ appendChar('[');
+ appendNumber(num);
+ if (den != 1) {
+ appendChar('/');
+ appendNumber(den);
+ }
+ appendChar(']');
+ memcpy(buf + len, unit, strlen(unit));
+ return QByteArray(buf, len + strlen(unit));
+}
+
+/*!
+ \since 6.6
+ \internal
+ Helper to the std::chrono::duration debug streaming output.
+ */
+void QDebug::putTimeUnit(qint64 num, qint64 den)
+{
+ stream->ts << timeUnit(num, den); // ### optimize
+}
+
+namespace {
+
+#ifdef QT_SUPPORTS_INT128
+
+constexpr char Q_INT128_MIN_STR[] = "-170141183460469231731687303715884105728";
+
+constexpr int Int128BufferSize = sizeof(Q_INT128_MIN_STR);
+using Int128Buffer = std::array<char, Int128BufferSize>;
+ // numeric_limits<qint128>::digits10 may not exist
+
+static char *i128ToStringHelper(Int128Buffer &buffer, quint128 n)
+{
+ auto dst = buffer.data() + buffer.size();
+ *--dst = '\0'; // NUL-terminate
+ if (n == 0) {
+ *--dst = '0'; // and done
+ } else {
+ while (n != 0) {
+ *--dst = "0123456789"[n % 10];
+ n /= 10;
+ }
+ }
+ return dst;
+}
+#endif // QT_SUPPORTS_INT128
+
+[[maybe_unused]]
+static const char *int128Warning()
+{
+ const char *msg = "Qt was not compiled with int128 support.";
+ qWarning("%s", msg);
+ return msg;
+}
+
+} // unnamed namespace
+
+/*!
+ \since 6.7
+ \internal
+ Helper to the qint128 debug streaming output.
+ */
+void QDebug::putInt128([[maybe_unused]] const void *p)
+{
+#ifdef QT_SUPPORTS_INT128
+ Q_ASSERT(p);
+ qint128 i;
+ memcpy(&i, p, sizeof(i)); // alignment paranoia
+ if (i == Q_INT128_MIN) {
+ // -i is not representable, hardcode the result:
+ stream->ts << Q_INT128_MIN_STR;
+ } else {
+ Int128Buffer buffer;
+ auto dst = i128ToStringHelper(buffer, i < 0 ? -i : i);
+ if (i < 0)
+ *--dst = '-';
+ stream->ts << dst;
+ }
+ return;
+#endif // QT_SUPPORTS_INT128
+ stream->ts << int128Warning();
+}
+
+/*!
+ \since 6.7
+ \internal
+ Helper to the quint128 debug streaming output.
+ */
+void QDebug::putUInt128([[maybe_unused]] const void *p)
+{
+#ifdef QT_SUPPORTS_INT128
+ Q_ASSERT(p);
+ quint128 i;
+ memcpy(&i, p, sizeof(i)); // alignment paranoia
+ Int128Buffer buffer;
+ stream->ts << i128ToStringHelper(buffer, i);
+ return;
+#endif // QT_SUPPORTS_INT128
+ stream->ts << int128Warning();
+}
+
+
/*!
\fn QDebug::swap(QDebug &other)
\since 5.0
@@ -421,6 +588,29 @@ QDebug &QDebug::resetFormat()
/*!
+ \fn bool QDebug::quoteStrings() const
+ \since 6.7
+
+ Returns \c true if this QDebug instance will quote strings streamed into
+ it (which is the default).
+
+ \sa QDebugStateSaver, quote(), noquote(), setQuoteStrings()
+*/
+
+/*!
+ \fn void QDebug::setQuoteStrings(bool b)
+ \since 6.7
+
+ Enables quoting of strings streamed into this QDebug instance if \a b is
+ \c true; otherwise quoting is disabled.
+
+ The default is to quote strings.
+
+ \sa QDebugStateSaver, quote(), noquote(), quoteStrings()
+*/
+
+
+/*!
\fn QDebug &QDebug::quote()
\since 5.4
@@ -777,6 +967,35 @@ QDebug &QDebug::resetFormat()
*/
/*!
+ \since 6.6
+ \fn template <typename Rep, typename Period> QDebug &QDebug::operator<<(std::chrono::duration<Rep, Period> duration)
+
+ Prints the time duration \a duration to the stream and returns a reference
+ to the stream. The printed string is the numeric representation of the
+ period followed by the time unit, similar to what the C++ Standard Library
+ would produce with \c{std::ostream}.
+
+ The unit is not localized.
+*/
+
+/*!
+ \fn template <typename T, QDebug::if_qint128<T>> QDebug::operator<<(T i)
+ \fn template <typename T, QDebug::if_quint128<T>> QDebug::operator<<(T i)
+ \since 6.7
+
+ Prints the textual representation of the 128-bit integer \a i.
+
+ \note This operator is only available if Qt supports 128-bit integer types.
+ If 128-bit integer types are available in your build, but the Qt libraries
+ were compiled without, the operator will print a warning instead.
+
+ \note Because the operator is a function template, no implicit conversions
+ are performed on its argument. It must be exactly qint128/quint128.
+
+ \sa QT_SUPPORTS_INT128
+*/
+
+/*!
\fn template <class T> QString QDebug::toString(T &&object)
\since 6.0
@@ -877,7 +1096,7 @@ QDebug &QDebug::resetFormat()
*/
/*!
- \fn template <class T1, class T2> QDebug operator<<(QDebug debug, const QPair<T1, T2> &pair)
+ \fn template <class T1, class T2> QDebug operator<<(QDebug debug, const std::pair<T1, T2> &pair)
\relates QDebug
Writes the contents of \a pair to \a debug. Both \c T1 and
@@ -885,11 +1104,12 @@ QDebug &QDebug::resetFormat()
*/
/*!
- \fn template <class T1, class T2> QDebug operator<<(QDebug debug, const std::pair<T1, T2> &pair)
+ \since 6.7
+ \fn template <class T> QDebug operator<<(QDebug debug, const std::optional<T> &opt)
\relates QDebug
- Writes the contents of \a pair to \a debug. Both \c T1 and
- \c T2 need to support streaming into QDebug.
+ Writes the contents of \a opt (or \c nullopt if not set) to \a debug.
+ \c T needs to support streaming into QDebug.
*/
/*!
@@ -925,6 +1145,13 @@ QDebug &QDebug::resetFormat()
*/
/*!
+ \since 6.7
+ \fn QDebug &QDebug::operator<<(std::nullopt_t)
+
+ Writes nullopt to the stream.
+*/
+
+/*!
\class QDebugStateSaver
\inmodule QtCore
\brief Convenience class for custom QDebug operators.
@@ -942,7 +1169,7 @@ QDebug &QDebug::resetFormat()
QDebugStateSaver is typically used in the implementation of an operator<<() for debugging:
- \snippet tools/customtype/message.cpp custom type streaming operator
+ \snippet customtype/customtypeexample.cpp custom type streaming operator
\since 5.1
*/
diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h
index e39f9afd31..4797bcd169 100644
--- a/src/corelib/io/qdebug.h
+++ b/src/corelib/io/qdebug.h
@@ -11,13 +11,16 @@
#include <QtCore/qcontainerfwd.h>
#include <QtCore/qtextstream.h>
+#include <QtCore/qtypes.h>
#include <QtCore/qstring.h>
#include <QtCore/qcontiguouscache.h>
#include <QtCore/qsharedpointer.h>
// all these have already been included by various headers above, but don't rely on indirect includes:
+#include <chrono>
#include <list>
#include <map>
+#include <optional>
#include <string>
#include <string_view>
#include <utility>
@@ -67,6 +70,9 @@ class QT6_ONLY(Q_CORE_EXPORT) QDebug : public QIODeviceBase
QT7_ONLY(Q_CORE_EXPORT) void putUcs4(uint ucs4);
QT7_ONLY(Q_CORE_EXPORT) void putString(const QChar *begin, size_t length);
QT7_ONLY(Q_CORE_EXPORT) void putByteArray(const char *begin, size_t length, Latin1Content content);
+ QT7_ONLY(Q_CORE_EXPORT) void putTimeUnit(qint64 num, qint64 den);
+ QT7_ONLY(Q_CORE_EXPORT) void putInt128(const void *i);
+ QT7_ONLY(Q_CORE_EXPORT) void putUInt128(const void *i);
public:
explicit QDebug(QIODevice *device) : stream(new Stream(device)) {}
explicit QDebug(QString *string) : stream(new Stream(string)) {}
@@ -91,6 +97,9 @@ public:
bool autoInsertSpaces() const { return stream->space; }
void setAutoInsertSpaces(bool b) { stream->space = b; }
+ [[nodiscard]] bool quoteStrings() const noexcept { return !stream->noQuotes; }
+ void setQuoteStrings(bool b) { stream->noQuotes = !b; }
+
inline QDebug &quote() { stream->noQuotes = false; return *this; }
inline QDebug &noquote() { stream->noQuotes = true; return *this; }
inline QDebug &maybeQuote(char c = '"') { if (!stream->noQuotes) stream->ts << c; return *this; }
@@ -121,6 +130,7 @@ public:
inline QDebug &operator<<(QByteArrayView t) { putByteArray(t.constData(), t.size(), ContainsBinary); return maybeSpace(); }
inline QDebug &operator<<(const void * t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(std::nullptr_t) { stream->ts << "(nullptr)"; return maybeSpace(); }
+ inline QDebug &operator<<(std::nullopt_t) { stream->ts << "nullopt"; return maybeSpace(); }
inline QDebug &operator<<(QTextStreamFunction f) {
stream->ts << f;
return *this;
@@ -189,6 +199,29 @@ public:
{ return *this << QString::fromUcs4(s.data(), s.size()); }
#endif // !Q_QDOC
+ template <typename Rep, typename Period>
+ QDebug &operator<<(std::chrono::duration<Rep, Period> duration)
+ {
+ stream->ts << duration.count();
+ putTimeUnit(Period::num, Period::den);
+ return maybeSpace();
+ }
+
+#ifdef QT_SUPPORTS_INT128
+private:
+ // Constrained templates so they only match q(u)int128 without conversions.
+ // Also keeps these operators out of the ABI.
+ template <typename T>
+ using if_qint128 = std::enable_if_t<std::is_same_v<T, qint128>, bool>;
+ template <typename T>
+ using if_quint128 = std::enable_if_t<std::is_same_v<T, quint128>, bool>;
+public:
+ template <typename T, if_qint128<T> = true>
+ QDebug &operator<<(T i128) { putInt128(&i128); return maybeSpace(); }
+ template <typename T, if_quint128<T> = true>
+ QDebug &operator<<(T u128) { putUInt128(&u128); return maybeSpace(); }
+#endif // QT_SUPPORTS_INT128
+
template <typename T>
static QString toString(T &&object)
{
@@ -202,10 +235,12 @@ public:
Q_DECLARE_SHARED(QDebug)
class QDebugStateSaverPrivate;
-class Q_CORE_EXPORT QDebugStateSaver
+class QDebugStateSaver
{
public:
+ Q_NODISCARD_CTOR Q_CORE_EXPORT
QDebugStateSaver(QDebug &dbg);
+ Q_CORE_EXPORT
~QDebugStateSaver();
private:
Q_DISABLE_COPY(QDebugStateSaver)
@@ -283,67 +318,78 @@ using QDebugIfHasDebugStreamContainer =
template<typename T>
inline QDebugIfHasDebugStreamContainer<QList<T>, T> operator<<(QDebug debug, const QList<T> &vec)
{
- return QtPrivate::printSequentialContainer(debug, "QList", vec);
+ return QtPrivate::printSequentialContainer(std::move(debug), "QList", vec);
}
template<typename T, qsizetype P>
inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const QVarLengthArray<T, P> &vec)
{
- return QtPrivate::printSequentialContainer(debug, "QVarLengthArray", vec);
+ return QtPrivate::printSequentialContainer(std::move(debug), "QVarLengthArray", vec);
}
template <typename T, typename Alloc>
inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const std::vector<T, Alloc> &vec)
{
- return QtPrivate::printSequentialContainer(debug, "std::vector", vec);
+ return QtPrivate::printSequentialContainer(std::move(debug), "std::vector", vec);
}
template <typename T, typename Alloc>
inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const std::list<T, Alloc> &vec)
{
- return QtPrivate::printSequentialContainer(debug, "std::list", vec);
+ return QtPrivate::printSequentialContainer(std::move(debug), "std::list", vec);
}
template <typename T>
inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, std::initializer_list<T> list)
{
- return QtPrivate::printSequentialContainer(debug, "std::initializer_list", list);
+ return QtPrivate::printSequentialContainer(std::move(debug), "std::initializer_list", list);
}
template <typename Key, typename T, typename Compare, typename Alloc>
inline QDebugIfHasDebugStream<Key, T> operator<<(QDebug debug, const std::map<Key, T, Compare, Alloc> &map)
{
- return QtPrivate::printSequentialContainer(debug, "std::map", map); // yes, sequential: *it is std::pair
+ return QtPrivate::printSequentialContainer(std::move(debug), "std::map", map); // yes, sequential: *it is std::pair
}
template <typename Key, typename T, typename Compare, typename Alloc>
inline QDebugIfHasDebugStream<Key, T> operator<<(QDebug debug, const std::multimap<Key, T, Compare, Alloc> &map)
{
- return QtPrivate::printSequentialContainer(debug, "std::multimap", map); // yes, sequential: *it is std::pair
+ return QtPrivate::printSequentialContainer(std::move(debug), "std::multimap", map); // yes, sequential: *it is std::pair
}
template <class Key, class T>
inline QDebugIfHasDebugStreamContainer<QMap<Key, T>, Key, T> operator<<(QDebug debug, const QMap<Key, T> &map)
{
- return QtPrivate::printAssociativeContainer(debug, "QMap", map);
+ return QtPrivate::printAssociativeContainer(std::move(debug), "QMap", map);
}
template <class Key, class T>
inline QDebugIfHasDebugStreamContainer<QMultiMap<Key, T>, Key, T> operator<<(QDebug debug, const QMultiMap<Key, T> &map)
{
- return QtPrivate::printAssociativeContainer(debug, "QMultiMap", map);
+ return QtPrivate::printAssociativeContainer(std::move(debug), "QMultiMap", map);
}
template <class Key, class T>
inline QDebugIfHasDebugStreamContainer<QHash<Key, T>, Key, T> operator<<(QDebug debug, const QHash<Key, T> &hash)
{
- return QtPrivate::printAssociativeContainer(debug, "QHash", hash);
+ return QtPrivate::printAssociativeContainer(std::move(debug), "QHash", hash);
}
template <class Key, class T>
inline QDebugIfHasDebugStreamContainer<QMultiHash<Key, T>, Key, T> operator<<(QDebug debug, const QMultiHash<Key, T> &hash)
{
- return QtPrivate::printAssociativeContainer(debug, "QMultiHash", hash);
+ return QtPrivate::printAssociativeContainer(std::move(debug), "QMultiHash", hash);
+}
+
+template <class T>
+inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const std::optional<T> &opt)
+{
+ const QDebugStateSaver saver(debug);
+ if (!opt)
+ debug.nospace() << std::nullopt;
+ else
+ debug.nospace() << "std::optional(" << *opt << ')';
+ return debug;
}
template <class T1, class T2>
@@ -357,7 +403,7 @@ inline QDebugIfHasDebugStream<T1, T2> operator<<(QDebug debug, const std::pair<T
template <typename T>
inline QDebugIfHasDebugStreamContainer<QSet<T>, T> operator<<(QDebug debug, const QSet<T> &set)
{
- return QtPrivate::printSequentialContainer(debug, "QSet", set);
+ return QtPrivate::printSequentialContainer(std::move(debug), "QSet", set);
}
template <class T>
@@ -409,9 +455,6 @@ template <typename T>
QDebug operator<<(QDebug debug, const QSet<T> &set);
template <class T1, class T2>
-QDebug operator<<(QDebug debug, const QPair<T1, T2> &pair);
-
-template <class T1, class T2>
QDebug operator<<(QDebug debug, const std::pair<T1, T2> &pair);
template <typename T>
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp
index 3ad804b9e8..9291201d88 100644
--- a/src/corelib/io/qdir.cpp
+++ b/src/corelib/io/qdir.cpp
@@ -9,7 +9,7 @@
#ifndef QT_NO_DEBUG_STREAM
#include "qdebug.h"
#endif
-#include "qdiriterator.h"
+#include "qdirlisting.h"
#include "qdatetime.h"
#include "qstring.h"
#if QT_CONFIG(regularexpression)
@@ -346,9 +346,8 @@ inline void QDirPrivate::initFileLists(const QDir &dir) const
QMutexLocker locker(&fileCache.mutex);
if (!fileCache.fileListsInitialized) {
QFileInfoList l;
- QDirIterator it(dir);
- while (it.hasNext())
- l.append(it.nextFileInfo());
+ for (const auto &dirEntry : QDirListing(dir))
+ l.emplace_back(dirEntry.fileInfo());
sortFileList(sort, l, &fileCache.files, &fileCache.fileInfos);
fileCache.fileListsInitialized = true;
@@ -363,8 +362,7 @@ inline void QDirPrivate::clearCache(MetaDataClearing mode)
fileCache.fileListsInitialized = false;
fileCache.files.clear();
fileCache.fileInfos.clear();
- fileEngine.reset(
- QFileSystemEngine::resolveEntryAndCreateLegacyEngine(dirEntry, fileCache.metaData));
+ fileEngine = QFileSystemEngine::createLegacyEngine(dirEntry, fileCache.metaData);
}
/*!
@@ -376,6 +374,7 @@ inline void QDirPrivate::clearCache(MetaDataClearing mode)
\ingroup shared
\reentrant
+ \compares equality
A QDir is used to manipulate path names, access information
regarding paths and files, and manipulate the underlying file
@@ -1294,6 +1293,7 @@ QDir::SortFlags QDir::sorting() const
after the directories, again in reverse order.
*/
+#ifndef QT_BOOTSTRAPPED
/*!
Sets the sort order used by entryList() and entryInfoList().
@@ -1426,18 +1426,16 @@ QStringList QDir::entryList(const QStringList &nameFilters, Filters filters,
}
}
- QDirIterator it(d->dirEntry.filePath(), nameFilters, filters);
+ QDirListing dirList(d->dirEntry.filePath(), nameFilters, filters);
QStringList ret;
if (needsSorting) {
QFileInfoList l;
- while (it.hasNext())
- l.append(it.nextFileInfo());
+ for (const auto &dirEntry : dirList)
+ l.emplace_back(dirEntry.fileInfo());
d->sortFileList(sort, l, &ret, nullptr);
} else {
- while (it.hasNext()) {
- it.next();
- ret.append(it.fileName());
- }
+ for (const auto &dirEntry : dirList)
+ ret.emplace_back(dirEntry.fileName());
}
return ret;
}
@@ -1474,13 +1472,13 @@ QFileInfoList QDir::entryInfoList(const QStringList &nameFilters, Filters filter
}
QFileInfoList l;
- QDirIterator it(d->dirEntry.filePath(), nameFilters, filters);
- while (it.hasNext())
- l.append(it.nextFileInfo());
+ for (const auto &dirEntry : QDirListing(d->dirEntry.filePath(), nameFilters, filters))
+ l.emplace_back(dirEntry.fileInfo());
QFileInfoList ret;
d->sortFileList(sort, l, nullptr, &ret);
return ret;
}
+#endif // !QT_BOOTSTRAPPED
/*!
Creates a sub-directory called \a dirName.
@@ -1617,6 +1615,7 @@ bool QDir::rmpath(const QString &dirPath) const
return d->fileEngine->rmdir(fn, true);
}
+#ifndef QT_BOOTSTRAPPED
/*!
\since 5.0
Removes the directory, including all its contents.
@@ -1645,12 +1644,11 @@ bool QDir::removeRecursively()
bool success = true;
const QString dirPath = path();
// not empty -- we must empty it first
- QDirIterator di(dirPath, QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot);
- while (di.hasNext()) {
- const QFileInfo fi = di.nextFileInfo();
- const QString &filePath = di.filePath();
+ constexpr auto dirFilters = QDir::AllEntries | QDir::Hidden | QDir::System | QDir::NoDotAndDotDot;
+ for (const auto &dirEntry : QDirListing(dirPath, dirFilters)) {
+ const QString &filePath = dirEntry.filePath();
bool ok;
- if (fi.isDir() && !fi.isSymLink()) {
+ if (dirEntry.isDir() && !dirEntry.isSymLink()) {
ok = QDir(filePath).removeRecursively(); // recursive
} else {
ok = QFile::remove(filePath);
@@ -1670,6 +1668,7 @@ bool QDir::removeRecursively()
return success;
}
+#endif // !QT_BOOTSTRAPPED
/*!
Returns \c true if the directory is readable \e and we can open files
@@ -1806,7 +1805,9 @@ bool QDir::makeAbsolute()
}
/*!
- Returns \c true if directory \a dir and this directory have the same
+ \fn bool QDir::operator==(const QDir &lhs, const QDir &rhs)
+
+ Returns \c true if directory \a lhs and directory \a rhs have the same
path and their sort and filter settings are the same; otherwise
returns \c false.
@@ -1814,10 +1815,10 @@ bool QDir::makeAbsolute()
\snippet code/src_corelib_io_qdir.cpp 10
*/
-bool QDir::operator==(const QDir &dir) const
+bool comparesEqual(const QDir &lhs, const QDir &rhs)
{
- Q_D(const QDir);
- const QDirPrivate *other = dir.d_ptr.constData();
+ const QDirPrivate *d = lhs.d_ptr.constData();
+ const QDirPrivate *other = rhs.d_ptr.constData();
if (d == other)
return true;
@@ -1841,13 +1842,13 @@ bool QDir::operator==(const QDir &dir) const
if (d->dirEntry.filePath() == other->dirEntry.filePath())
return true;
- if (exists()) {
- if (!dir.exists())
+ if (lhs.exists()) {
+ if (!rhs.exists())
return false; //can't be equal if only one exists
// Both exist, fallback to expensive canonical path computation
- return canonicalPath().compare(dir.canonicalPath(), sensitive) == 0;
+ return lhs.canonicalPath().compare(rhs.canonicalPath(), sensitive) == 0;
} else {
- if (dir.exists())
+ if (rhs.exists())
return false; //can't be equal if only one exists
// Neither exists, compare absolute paths rather than canonical (which would be empty strings)
QString thisFilePath = d->resolveAbsoluteEntry();
@@ -1877,11 +1878,10 @@ QDir &QDir::operator=(const QDir &dir)
*/
/*!
- \fn bool QDir::operator!=(const QDir &dir) const
+ \fn bool QDir::operator!=(const QDir &lhs, const QDir &rhs)
- Returns \c true if directory \a dir and this directory have different
- paths or different sort or filter settings; otherwise returns
- false.
+ Returns \c true if directory \a lhs and directory \a rhs have different
+ paths or different sort or filter settings; otherwise returns \c false.
Example:
@@ -1951,6 +1951,7 @@ bool QDir::exists(const QString &name) const
return QFileInfo::exists(filePath(name));
}
+#ifndef QT_BOOTSTRAPPED
/*!
Returns whether the directory is empty.
@@ -1967,9 +1968,10 @@ bool QDir::exists(const QString &name) const
bool QDir::isEmpty(Filters filters) const
{
Q_D(const QDir);
- QDirIterator it(d->dirEntry.filePath(), d->nameFilters, filters);
- return !it.hasNext();
+ QDirListing dirList(d->dirEntry.filePath(), d->nameFilters, filters);
+ return dirList.cbegin() == dirList.cend();
}
+#endif // !QT_BOOTSTRAPPED
/*!
Returns a list of the root directories on this system.
@@ -2356,7 +2358,7 @@ QString qt_normalizePathSegments(const QString &name, QDirPrivate::PathNormaliza
// If path was not modified return the original value
if (used == 0)
return name;
- return QString::fromUtf16(out + used, len - used);
+ return QStringView(out + used, len - used).toString();
}
static QString qt_cleanPath(const QString &path, bool *ok)
diff --git a/src/corelib/io/qdir.h b/src/corelib/io/qdir.h
index 7d5e940e84..53c0900f95 100644
--- a/src/corelib/io/qdir.h
+++ b/src/corelib/io/qdir.h
@@ -4,6 +4,7 @@
#ifndef QDIR_H
#define QDIR_H
+#include <QtCore/qcompare.h>
#include <QtCore/qstring.h>
#include <QtCore/qfile.h>
#include <QtCore/qfileinfo.h>
@@ -185,8 +186,10 @@ public:
inline bool isAbsolute() const { return !isRelative(); }
bool makeAbsolute();
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QDir &dir) const;
inline bool operator!=(const QDir &dir) const { return !operator==(dir); }
+#endif
bool remove(const QString &fileName);
bool rename(const QString &oldName, const QString &newName);
@@ -237,7 +240,10 @@ protected:
QSharedDataPointer<QDirPrivate> d_ptr;
private:
+ friend Q_CORE_EXPORT bool comparesEqual(const QDir &lhs, const QDir &rhs);
+ Q_DECLARE_EQUALITY_COMPARABLE(QDir)
friend class QDirIterator;
+ friend class QDirListing;
// Q_DECLARE_PRIVATE equivalent for shared data pointers
QDirPrivate *d_func();
const QDirPrivate *d_func() const { return d_ptr.constData(); }
diff --git a/src/corelib/io/qdirentryinfo_p.h b/src/corelib/io/qdirentryinfo_p.h
new file mode 100644
index 0000000000..7ed5391ff0
--- /dev/null
+++ b/src/corelib/io/qdirentryinfo_p.h
@@ -0,0 +1,156 @@
+// Copyright (C) 2024 Ahmad Samir <a.samirh78@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QDIRENTRYINFO_P_H
+#define QDIRENTRYINFO_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/private/qfileinfo_p.h>
+#include <QtCore/private/qfilesystementry_p.h>
+#include <QtCore/private/qfilesystemmetadata_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDirEntryInfo
+{
+ const QFileSystemMetaData &ensureFilled(QFileSystemMetaData::MetaDataFlags what)
+ {
+ if (!metaData.hasFlags(what))
+ QFileSystemEngine::fillMetaData(entry, metaData, what);
+ return metaData;
+ }
+
+public:
+ const QFileInfo &fileInfo()
+ {
+ if (!fileInfoOpt) {
+ fileInfoOpt.emplace(new QFileInfoPrivate(entry, metaData));
+ metaData.clear();
+ }
+ return *fileInfoOpt;
+ }
+
+ QString fileName()
+ { return fileInfoOpt ? fileInfoOpt->fileName() : entry.fileName(); }
+ QString baseName()
+ { return fileInfoOpt ? fileInfoOpt->baseName() : entry.baseName(); }
+ QString completeBaseName() const
+ { return fileInfoOpt ? fileInfoOpt->completeBaseName() : entry.completeBaseName(); }
+ QString suffix() const
+ { return fileInfoOpt ? fileInfoOpt->suffix() : entry.suffix(); }
+ QString completeSuffix() const
+ { return fileInfoOpt ? fileInfoOpt->completeSuffix() : entry.completeSuffix(); }
+ QString filePath()
+ { return fileInfoOpt ? fileInfoOpt->filePath() : entry.filePath(); }
+
+ QString bundleName() { return fileInfo().bundleName(); }
+
+ QString canonicalFilePath()
+ {
+ // QFileInfo caches these strings
+ return fileInfo().canonicalFilePath();
+ }
+
+ QString absoluteFilePath() {
+ // QFileInfo caches these strings
+ return fileInfo().absoluteFilePath();
+ }
+
+ QString absolutePath() {
+ // QFileInfo caches these strings
+ return fileInfo().absolutePath();
+ }
+
+
+ bool isDir() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isDir();
+
+ return ensureFilled(QFileSystemMetaData::DirectoryType).isDirectory();
+ }
+
+ bool isFile() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isFile();
+
+ return ensureFilled(QFileSystemMetaData::FileType).isFile();
+ }
+
+ bool isSymLink() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isSymLink();
+
+ return ensureFilled(QFileSystemMetaData::LegacyLinkType).isLegacyLink();
+ }
+
+ bool isSymbolicLink() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isSymbolicLink();
+
+ return ensureFilled(QFileSystemMetaData::LinkType).isLink();
+ }
+
+ bool exists() {
+ if (fileInfoOpt)
+ return fileInfoOpt->exists();
+
+ return ensureFilled(QFileSystemMetaData::ExistsAttribute).exists();
+ }
+
+ bool isHidden() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isHidden();
+
+ return ensureFilled(QFileSystemMetaData::HiddenAttribute).isHidden();
+ }
+
+ bool isReadable() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isReadable();
+
+ return ensureFilled(QFileSystemMetaData::UserReadPermission).isReadable();
+ }
+
+ bool isWritable() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isWritable();
+
+ return ensureFilled(QFileSystemMetaData::UserWritePermission).isWritable();
+ }
+
+ bool isExecutable() {
+ if (fileInfoOpt)
+ return fileInfoOpt->isExecutable();
+
+ return ensureFilled(QFileSystemMetaData::UserExecutePermission).isExecutable();
+ }
+
+ qint64 size() { return fileInfo().size(); }
+
+ QDateTime fileTime(QFile::FileTime type, const QTimeZone &tz)
+ {
+ return fileInfo().fileTime(type, tz);
+ }
+
+private:
+ friend class QDirListingPrivate;
+ friend class QDirListing;
+
+ QFileSystemEntry entry;
+ QFileSystemMetaData metaData;
+ std::optional<QFileInfo> fileInfoOpt;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDIRENTRYINFO_P_H
diff --git a/src/corelib/io/qdiriterator.cpp b/src/corelib/io/qdiriterator.cpp
index 101c8fd2e7..3604e673e2 100644
--- a/src/corelib/io/qdiriterator.cpp
+++ b/src/corelib/io/qdiriterator.cpp
@@ -34,6 +34,9 @@
you cannot iterate directories in reverse order) and does not allow random
access.
+ \note This class is deprecated and may be removed in a Qt release. Use
+ QDirListing instead.
+
\sa QDir, QDir::entryList()
*/
@@ -56,6 +59,8 @@
#include "qdiriterator.h"
#include "qdir_p.h"
#include "qabstractfileengine_p.h"
+#include "qdirlisting.h"
+#include "qdirentryinfo_p.h"
#include <QtCore/qset.h>
#include <QtCore/qstack.h>
@@ -72,297 +77,74 @@
#include <QtCore/private/qduplicatetracker_p.h>
#include <memory>
+#include <stack>
+#include <vector>
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-template <class Iterator>
-class QDirIteratorPrivateIteratorStack : public QStack<Iterator *>
-{
-public:
- ~QDirIteratorPrivateIteratorStack()
- {
- qDeleteAll(*this);
- }
-};
-
class QDirIteratorPrivate
{
-public:
- QDirIteratorPrivate(const QFileSystemEntry &entry, const QStringList &nameFilters,
- QDir::Filters _filters, QDirIterator::IteratorFlags flags, bool resolveEngine = true);
-
- void advance();
-
- bool entryMatches(const QString & fileName, const QFileInfo &fileInfo);
- void pushDirectory(const QFileInfo &fileInfo);
- void checkAndPushDirectory(const QFileInfo &);
- bool matchesFilters(const QString &fileName, const QFileInfo &fi) const;
-
- std::unique_ptr<QAbstractFileEngine> engine;
-
- QFileSystemEntry dirEntry;
- const QStringList nameFilters;
- const QDir::Filters filters;
- const QDirIterator::IteratorFlags iteratorFlags;
-
-#if QT_CONFIG(regularexpression)
- QList<QRegularExpression> nameRegExps;
-#endif
-
- QDirIteratorPrivateIteratorStack<QAbstractFileEngineIterator> fileEngineIterators;
-#ifndef QT_NO_FILESYSTEMITERATOR
- QDirIteratorPrivateIteratorStack<QFileSystemIterator> nativeIterators;
-#endif
-
- QFileInfo currentFileInfo;
- QFileInfo nextFileInfo;
+ static QDirListing::IteratorFlags toDirListingFlags(QDirIterator::IteratorFlags flags)
+ {
+ using F = QDirListing::IteratorFlag;
+ QDirListing::IteratorFlags listerFlags;
- // Loop protection
- QDuplicateTracker<QString> visitedLinks;
-};
+ if (flags & QDirIterator::NoIteratorFlags)
+ listerFlags.setFlag(F::NoFlag);
+ if (flags & QDirIterator::FollowSymlinks)
+ listerFlags.setFlag(F::FollowSymlinks);
+ if (flags & QDirIterator::Subdirectories)
+ listerFlags.setFlag(F::Recursive);
-/*!
- \internal
-*/
-QDirIteratorPrivate::QDirIteratorPrivate(const QFileSystemEntry &entry, const QStringList &nameFilters,
- QDir::Filters _filters, QDirIterator::IteratorFlags flags, bool resolveEngine)
- : dirEntry(entry)
- , nameFilters(nameFilters.contains("*"_L1) ? QStringList() : nameFilters)
- , filters(QDir::NoFilter == _filters ? QDir::AllEntries : _filters)
- , iteratorFlags(flags)
-{
-#if QT_CONFIG(regularexpression)
- nameRegExps.reserve(nameFilters.size());
- for (const auto &filter : nameFilters) {
- auto re = QRegularExpression::fromWildcard(filter, (filters & QDir::CaseSensitive ?
- Qt::CaseSensitive : Qt::CaseInsensitive));
- nameRegExps.append(re);
+ return listerFlags;
}
-#endif
- QFileSystemMetaData metaData;
- if (resolveEngine)
- engine.reset(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(dirEntry, metaData));
- QFileInfo fileInfo(new QFileInfoPrivate(dirEntry, metaData));
-
- // Populate fields for hasNext() and next()
- pushDirectory(fileInfo);
- advance();
-}
-
-/*!
- \internal
-*/
-void QDirIteratorPrivate::pushDirectory(const QFileInfo &fileInfo)
-{
- QString path = fileInfo.filePath();
-
-#ifdef Q_OS_WIN
- if (fileInfo.isSymLink())
- path = fileInfo.canonicalFilePath();
-#endif
- if ((iteratorFlags & QDirIterator::FollowSymlinks)) {
- // Stop link loops
- if (visitedLinks.hasSeen(fileInfo.canonicalFilePath()))
- return;
+public:
+ QDirIteratorPrivate(const QDir &dir, QDirIterator::IteratorFlags flags)
+ : lister(dir, toDirListingFlags(flags))
+ {
+ init();
}
-
- if (engine) {
- engine->setFileName(path);
- QAbstractFileEngineIterator *it = engine->beginEntryList(filters, nameFilters);
- if (it) {
- it->setPath(path);
- fileEngineIterators << it;
- } else {
- // No iterator; no entry list.
- }
- } else {
-#ifndef QT_NO_FILESYSTEMITERATOR
- QFileSystemIterator *it = new QFileSystemIterator(fileInfo.d_ptr->fileEntry,
- filters, nameFilters, iteratorFlags);
- nativeIterators << it;
-#else
- qWarning("Qt was built with -no-feature-filesystemiterator: no files/plugins will be found!");
-#endif
+ QDirIteratorPrivate(const QString &path, QDirIterator::IteratorFlags flags)
+ : lister(path, toDirListingFlags(flags))
+ {
+ init();
}
-}
-
-inline bool QDirIteratorPrivate::entryMatches(const QString & fileName, const QFileInfo &fileInfo)
-{
- checkAndPushDirectory(fileInfo);
-
- if (matchesFilters(fileName, fileInfo)) {
- currentFileInfo = nextFileInfo;
- nextFileInfo = fileInfo;
-
- //We found a matching entry.
- return true;
+ QDirIteratorPrivate(const QString &path, QDir::Filters filters,
+ QDirIterator::IteratorFlags flags)
+ : lister(path, filters, toDirListingFlags(flags))
+ {
+ init();
}
-
- return false;
-}
-
-/*!
- \internal
-*/
-void QDirIteratorPrivate::advance()
-{
- if (engine) {
- while (!fileEngineIterators.isEmpty()) {
- // Find the next valid iterator that matches the filters.
- QAbstractFileEngineIterator *it;
- while (it = fileEngineIterators.top(), it->hasNext()) {
- it->next();
- if (entryMatches(it->currentFileName(), it->currentFileInfo()))
- return;
- }
-
- fileEngineIterators.pop();
- delete it;
- }
- } else {
-#ifndef QT_NO_FILESYSTEMITERATOR
- QFileSystemEntry nextEntry;
- QFileSystemMetaData nextMetaData;
-
- while (!nativeIterators.isEmpty()) {
- // Find the next valid iterator that matches the filters.
- QFileSystemIterator *it;
- while (it = nativeIterators.top(), it->advance(nextEntry, nextMetaData)) {
- QFileInfo info(new QFileInfoPrivate(nextEntry, nextMetaData));
-
- if (entryMatches(nextEntry.fileName(), info))
- return;
- nextMetaData = QFileSystemMetaData();
- }
-
- nativeIterators.pop();
- delete it;
- }
-#endif
+ QDirIteratorPrivate(const QString &path, const QStringList &nameFilters, QDir::Filters filters,
+ QDirIterator::IteratorFlags flags)
+ : lister(path, nameFilters, filters, toDirListingFlags(flags))
+ {
+ init();
}
- currentFileInfo = nextFileInfo;
- nextFileInfo = QFileInfo();
-}
-
-/*!
- \internal
- */
-void QDirIteratorPrivate::checkAndPushDirectory(const QFileInfo &fileInfo)
-{
- // If we're doing flat iteration, we're done.
- if (!(iteratorFlags & QDirIterator::Subdirectories))
- return;
-
- // Never follow non-directory entries
- if (!fileInfo.isDir())
- return;
-
- // Follow symlinks only when asked
- if (!(iteratorFlags & QDirIterator::FollowSymlinks) && fileInfo.isSymLink())
- return;
-
- // Never follow . and ..
- QString fileName = fileInfo.fileName();
- if ("."_L1 == fileName || ".."_L1 == fileName)
- return;
-
- // No hidden directories unless requested
- if (!(filters & QDir::AllDirs) && !(filters & QDir::Hidden) && fileInfo.isHidden())
- return;
-
- pushDirectory(fileInfo);
-}
-
-/*!
- \internal
-
- This convenience function implements the iterator's filtering logics and
- applies then to the current directory entry.
-
- It returns \c true if the current entry matches the filters (i.e., the
- current entry will be returned as part of the directory iteration);
- otherwise, false is returned.
-*/
-
-bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInfo &fi) const
-{
- if (fileName.isEmpty())
- return false;
-
- // filter . and ..?
- const qsizetype fileNameSize = fileName.size();
- const bool dotOrDotDot = fileName[0] == u'.'
- && ((fileNameSize == 1)
- ||(fileNameSize == 2 && fileName[1] == u'.'));
- if ((filters & QDir::NoDot) && dotOrDotDot && fileNameSize == 1)
- return false;
- if ((filters & QDir::NoDotDot) && dotOrDotDot && fileNameSize == 2)
- return false;
-
- // name filter
-#if QT_CONFIG(regularexpression)
- // Pass all entries through name filters, except dirs if the AllDirs
- if (!nameFilters.isEmpty() && !((filters & QDir::AllDirs) && fi.isDir())) {
- bool matched = false;
- for (const auto &re : nameRegExps) {
- if (re.match(fileName).hasMatch()) {
- matched = true;
- break;
- }
- }
- if (!matched)
- return false;
- }
-#endif
- // skip symlinks
- const bool skipSymlinks = filters.testAnyFlag(QDir::NoSymLinks);
- const bool includeSystem = filters.testAnyFlag(QDir::System);
- if (skipSymlinks && fi.isSymLink()) {
- // The only reason to save this file is if it is a broken link and we are requesting system files.
- if (!includeSystem || fi.exists())
- return false;
+ void init()
+ {
+ it = lister.begin();
+ if (it != lister.end())
+ nextFileInfo = it->fileInfo();
}
- // filter hidden
- const bool includeHidden = filters.testAnyFlag(QDir::Hidden);
- if (!includeHidden && !dotOrDotDot && fi.isHidden())
- return false;
-
- // filter system files
- if (!includeSystem && (!(fi.isFile() || fi.isDir() || fi.isSymLink())
- || (!fi.exists() && fi.isSymLink())))
- return false;
-
- // skip directories
- const bool skipDirs = !(filters & (QDir::Dirs | QDir::AllDirs));
- if (skipDirs && fi.isDir())
- return false;
-
- // skip files
- const bool skipFiles = !(filters & QDir::Files);
- if (skipFiles && fi.isFile())
- // Basically we need a reason not to exclude this file otherwise we just eliminate it.
- return false;
-
- // filter permissions
- const bool filterPermissions = ((filters & QDir::PermissionMask)
- && (filters & QDir::PermissionMask) != QDir::PermissionMask);
- const bool doWritable = !filterPermissions || (filters & QDir::Writable);
- const bool doExecutable = !filterPermissions || (filters & QDir::Executable);
- const bool doReadable = !filterPermissions || (filters & QDir::Readable);
- if (filterPermissions
- && ((doReadable && !fi.isReadable())
- || (doWritable && !fi.isWritable())
- || (doExecutable && !fi.isExecutable()))) {
- return false;
+ void advance()
+ {
+ currentFileInfo = nextFileInfo;
+ if (++it != lister.end()) {
+ nextFileInfo = it->fileInfo();
+ }
}
- return true;
-}
+ QDirListing lister;
+ QDirListing::const_iterator it = {};
+ QFileInfo currentFileInfo;
+ QFileInfo nextFileInfo;
+};
/*!
Constructs a QDirIterator that can iterate over \a dir's entrylist, using
@@ -380,9 +162,8 @@ bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInf
\sa hasNext(), next(), IteratorFlags
*/
QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags)
+ : d(new QDirIteratorPrivate(dir, flags))
{
- const QDirPrivate *other = dir.d_ptr.constData();
- d.reset(new QDirIteratorPrivate(other->dirEntry, other->nameFilters, other->filters, flags, bool(other->fileEngine)));
}
/*!
@@ -399,7 +180,7 @@ QDirIterator::QDirIterator(const QDir &dir, IteratorFlags flags)
\sa hasNext(), next(), IteratorFlags
*/
QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorFlags flags)
- : d(new QDirIteratorPrivate(QFileSystemEntry(path), QStringList(), filters, flags))
+ : d(new QDirIteratorPrivate(path, filters, flags))
{
}
@@ -416,7 +197,7 @@ QDirIterator::QDirIterator(const QString &path, QDir::Filters filters, IteratorF
\sa hasNext(), next(), IteratorFlags
*/
QDirIterator::QDirIterator(const QString &path, IteratorFlags flags)
- : d(new QDirIteratorPrivate(QFileSystemEntry(path), QStringList(), QDir::NoFilter, flags))
+ : d(new QDirIteratorPrivate(path, flags))
{
}
@@ -440,7 +221,7 @@ QDirIterator::QDirIterator(const QString &path, IteratorFlags flags)
*/
QDirIterator::QDirIterator(const QString &path, const QStringList &nameFilters,
QDir::Filters filters, IteratorFlags flags)
- : d(new QDirIteratorPrivate(QFileSystemEntry(path), nameFilters, filters, flags))
+ : d(new QDirIteratorPrivate(path, nameFilters, filters, flags))
{
}
@@ -466,7 +247,7 @@ QDirIterator::~QDirIterator()
QString QDirIterator::next()
{
d->advance();
- return filePath();
+ return d->currentFileInfo.filePath();
}
/*!
@@ -486,7 +267,7 @@ QString QDirIterator::next()
QFileInfo QDirIterator::nextFileInfo()
{
d->advance();
- return fileInfo();
+ return d->currentFileInfo;
}
/*!
@@ -497,14 +278,7 @@ QFileInfo QDirIterator::nextFileInfo()
*/
bool QDirIterator::hasNext() const
{
- if (d->engine)
- return !d->fileEngineIterators.isEmpty();
- else
-#ifndef QT_NO_FILESYSTEMITERATOR
- return !d->nativeIterators.isEmpty();
-#else
- return false;
-#endif
+ return d->it != d->lister.end();
}
/*!
@@ -547,7 +321,7 @@ QFileInfo QDirIterator::fileInfo() const
*/
QString QDirIterator::path() const
{
- return d->dirEntry.filePath();
+ return d->lister.iteratorPath();
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qdirlisting.cpp b/src/corelib/io/qdirlisting.cpp
new file mode 100644
index 0000000000..008003e856
--- /dev/null
+++ b/src/corelib/io/qdirlisting.cpp
@@ -0,0 +1,673 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2024 Ahmad Samir <a.samirh78@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+/*!
+ \since 6.8
+ \class QDirListing
+ \inmodule QtCore
+ \brief The QDirListing class provides an STL-style iterator for directory entries.
+
+ You can use QDirListing to navigate entries of a directory one at a time.
+ It is similar to QDir::entryList() and QDir::entryInfoList(), but because
+ it lists entries one at a time instead of all at once, it scales better
+ and is more suitable for large directories. It also supports listing
+ directory contents recursively, and following symbolic links. Unlike
+ QDir::entryList(), QDirListing does not support sorting.
+
+ The QDirListing constructor takes a QDir or a directory path as
+ argument. Here's how to iterate over all entries recursively:
+
+ \snippet code/src_corelib_io_qdirlisting.cpp 0
+
+ Here's how to find and read all files filtered by name, recursively:
+
+ \snippet code/src_corelib_io_qdirlisting.cpp 1
+
+ Iterators constructed by QDirListing (QDirListing::const_iterator) are
+ forward-only (you cannot iterate directories in reverse order) and don't
+ allow random access. They can be used in ranged-for loops (or with STL
+ alogrithms that don't require random access iterators). Dereferencing
+ a valid iterator returns a QDirListing::DirEntry object. The (c)end()
+ iterator marks the end of the iteration. Dereferencing the end iterator
+ is undefiend behavior.
+
+ QDirListing::DirEntry offers a subset of QFileInfo's API (for example,
+ fileName(), filePath(), exists()). Internally, DirEntry only constructs
+ a QFileInfo object if needed, that is, if the info hasn't been already
+ fetched by other system functions. You can use DirEntry::fileInfo()
+ to get a QFileInfo. For example:
+
+ \snippet code/src_corelib_io_qdirlisting.cpp 3
+ \snippet code/src_corelib_io_qdirlisting.cpp 4
+
+ \sa QDir, QDir::entryList()
+*/
+
+/*! \enum QDirListing::IteratorFlag
+
+ This enum class describes flags can be used to configure the behavior of
+ QDirListing. These flags can be bitwise OR'ed together.
+
+ \value NoFlag The default value, representing no flags. The iterator
+ will return entries for the assigned path.
+
+ \value FollowSymlinks When combined with Recursive, this flag enables
+ iterating through all subdirectories of the assigned path, following
+ all symbolic links. Symbolic link loops (e.g., link => . or link =>
+ ..) are automatically detected and ignored.
+
+ \value Recursive List entries inside all subdirectories as well.
+*/
+
+#include "qdirlisting.h"
+#include "qdirentryinfo_p.h"
+
+#include "qdir_p.h"
+#include "qabstractfileengine_p.h"
+
+#include <QtCore/qset.h>
+
+#if QT_CONFIG(regularexpression)
+#include <QtCore/qregularexpression.h>
+#endif
+
+#include <QtCore/private/qfilesystemiterator_p.h>
+#include <QtCore/private/qfilesystementry_p.h>
+#include <QtCore/private/qfilesystemmetadata_p.h>
+#include <QtCore/private/qfilesystemengine_p.h>
+#include <QtCore/private/qfileinfo_p.h>
+#include <QtCore/private/qduplicatetracker_p.h>
+
+#include <memory>
+#include <stack>
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+class QDirListingPrivate
+{
+public:
+ void init(bool resolveEngine);
+ void advance();
+
+ bool entryMatches(QDirEntryInfo &info);
+ void pushDirectory(QDirEntryInfo &info);
+ void pushInitialDirectory();
+
+ void checkAndPushDirectory(QDirEntryInfo &info);
+ bool matchesFilters(QDirEntryInfo &data) const;
+ bool hasIterators() const;
+
+ std::unique_ptr<QAbstractFileEngine> engine;
+ QDirEntryInfo initialEntryInfo;
+ QStringList nameFilters;
+ QDir::Filters filters;
+ QDirListing::IteratorFlags iteratorFlags;
+ QDirEntryInfo currentEntryInfo;
+
+#if QT_CONFIG(regularexpression)
+ QList<QRegularExpression> nameRegExps;
+#endif
+
+ using FEngineIteratorPtr = std::unique_ptr<QAbstractFileEngineIterator>;
+ std::stack<FEngineIteratorPtr, std::vector<FEngineIteratorPtr>> fileEngineIterators;
+#ifndef QT_NO_FILESYSTEMITERATOR
+ using FsIteratorPtr = std::unique_ptr<QFileSystemIterator>;
+ std::stack<FsIteratorPtr, std::vector<FsIteratorPtr>> nativeIterators;
+#endif
+
+ // Loop protection
+ QDuplicateTracker<QString> visitedLinks;
+};
+
+void QDirListingPrivate::init(bool resolveEngine = true)
+{
+ if (nameFilters.contains("*"_L1))
+ nameFilters.clear();
+
+ if (filters == QDir::NoFilter)
+ filters = QDir::AllEntries;
+
+#if QT_CONFIG(regularexpression)
+ nameRegExps.reserve(nameFilters.size());
+ const auto cs = filters.testAnyFlags(QDir::CaseSensitive) ? Qt::CaseSensitive
+ : Qt::CaseInsensitive;
+ for (const auto &filter : nameFilters)
+ nameRegExps.emplace_back(QRegularExpression::fromWildcard(filter, cs));
+#endif
+
+ if (resolveEngine) {
+ engine = QFileSystemEngine::createLegacyEngine(initialEntryInfo.entry,
+ initialEntryInfo.metaData);
+ }
+
+ pushDirectory(initialEntryInfo);
+}
+
+void QDirListingPrivate::pushDirectory(QDirEntryInfo &entryInfo)
+{
+ const QString path = [&entryInfo] {
+#ifdef Q_OS_WIN
+ if (entryInfo.isSymLink())
+ return entryInfo.canonicalFilePath();
+#endif
+ return entryInfo.filePath();
+ }();
+
+
+ if (iteratorFlags.testAnyFlags(QDirListing::IteratorFlag::FollowSymlinks)) {
+ // Stop link loops
+ if (visitedLinks.hasSeen(entryInfo.canonicalFilePath()))
+ return;
+ }
+
+ if (engine) {
+ engine->setFileName(path);
+ if (auto it = engine->beginEntryList(path, filters, nameFilters)) {
+ fileEngineIterators.emplace(std::move(it));
+ } else {
+ // No iterator; no entry list.
+ }
+ } else {
+#ifndef QT_NO_FILESYSTEMITERATOR
+ QFileSystemEntry *fentry = nullptr;
+ if (entryInfo.fileInfoOpt)
+ fentry = &entryInfo.fileInfoOpt->d_ptr->fileEntry;
+ else
+ fentry = &entryInfo.entry;
+ nativeIterators.emplace(std::make_unique<QFileSystemIterator>(*fentry, filters));
+#else
+ qWarning("Qt was built with -no-feature-filesystemiterator: no files/plugins will be found!");
+#endif
+ }
+}
+
+bool QDirListingPrivate::entryMatches(QDirEntryInfo &entryInfo)
+{
+ checkAndPushDirectory(entryInfo);
+ return matchesFilters(entryInfo);
+}
+
+/*!
+ \internal
+
+ Advances the internal iterator, either a QAbstractFileEngineIterator (e.g.
+ QResourceFileEngineIterator) or a QFileSystemIterator (which uses low-level
+ system methods, e.g. readdir() on Unix).
+
+ An iterator stack is used for holding the iterators.
+
+ A typical example of doing recursive iteration:
+ - while iterating directory A we find a sub-dir B
+ - an iterator for B is added to the iterator stack
+ - B's iterator is processed (the top() of the stack) first; then loop
+ goes back to processing A's iterator
+*/
+void QDirListingPrivate::advance()
+{
+ // Use get() in both code paths below because the iterator returned by top()
+ // may be invalidated due to reallocation when appending new iterators in
+ // pushDirectory().
+
+ if (engine) {
+ while (!fileEngineIterators.empty()) {
+ // Find the next valid iterator that matches the filters.
+ QAbstractFileEngineIterator *it;
+ while (it = fileEngineIterators.top().get(), it->advance()) {
+ QDirEntryInfo entryInfo;
+ entryInfo.fileInfoOpt = it->currentFileInfo();
+ if (entryMatches(entryInfo)) {
+ currentEntryInfo = std::move(entryInfo);
+ return;
+ }
+ }
+
+ fileEngineIterators.pop();
+ }
+ } else {
+#ifndef QT_NO_FILESYSTEMITERATOR
+ QDirEntryInfo entryInfo;
+ while (!nativeIterators.empty()) {
+ // Find the next valid iterator that matches the filters.
+ QFileSystemIterator *it;
+ while (it = nativeIterators.top().get(), it->advance(entryInfo.entry, entryInfo.metaData)) {
+ if (entryMatches(entryInfo)) {
+ currentEntryInfo = std::move(entryInfo);
+ return;
+ }
+ entryInfo = {};
+ }
+
+ nativeIterators.pop();
+ }
+#endif
+ }
+}
+
+void QDirListingPrivate::checkAndPushDirectory(QDirEntryInfo &entryInfo)
+{
+ using F = QDirListing::IteratorFlag;
+ // If we're doing flat iteration, we're done.
+ if (!iteratorFlags.testAnyFlags(F::Recursive))
+ return;
+
+ // Never follow non-directory entries
+ if (!entryInfo.isDir())
+ return;
+
+ // Follow symlinks only when asked
+ if (!iteratorFlags.testAnyFlags(F::FollowSymlinks) && entryInfo.isSymLink())
+ return;
+
+ // Never follow . and ..
+ const QString &fileName = entryInfo.fileName();
+ if ("."_L1 == fileName || ".."_L1 == fileName)
+ return;
+
+ // No hidden directories unless requested
+ if (!filters.testAnyFlags(QDir::AllDirs | QDir::Hidden) && entryInfo.isHidden())
+ return;
+
+ pushDirectory(entryInfo);
+}
+
+/*!
+ \internal
+
+ This functions returns \c true if the current entry matches the filters
+ (i.e., the current entry will be returned as part of the directory
+ iteration); otherwise, \c false is returned.
+*/
+bool QDirListingPrivate::matchesFilters(QDirEntryInfo &entryInfo) const
+{
+ const QString &fileName = entryInfo.fileName();
+ if (fileName.isEmpty())
+ return false;
+
+ // filter . and ..?
+ const qsizetype fileNameSize = fileName.size();
+ const bool dotOrDotDot = fileName[0] == u'.'
+ && ((fileNameSize == 1)
+ ||(fileNameSize == 2 && fileName[1] == u'.'));
+ if ((filters & QDir::NoDot) && dotOrDotDot && fileNameSize == 1)
+ return false;
+ if ((filters & QDir::NoDotDot) && dotOrDotDot && fileNameSize == 2)
+ return false;
+
+ // name filter
+#if QT_CONFIG(regularexpression)
+ // Pass all entries through name filters, except dirs if AllDirs is set
+ if (!nameRegExps.isEmpty() && !(filters.testAnyFlags(QDir::AllDirs) && entryInfo.isDir())) {
+ auto regexMatchesName = [&fileName](const auto &re) {
+ return re.match(fileName).hasMatch();
+ };
+ if (std::none_of(nameRegExps.cbegin(), nameRegExps.cend(), regexMatchesName))
+ return false;
+ }
+#endif
+ // skip symlinks
+ const bool skipSymlinks = filters.testAnyFlag(QDir::NoSymLinks);
+ const bool includeSystem = filters.testAnyFlag(QDir::System);
+ if (skipSymlinks && entryInfo.isSymLink()) {
+ // The only reason to save this file is if it is a broken link and we are requesting system files.
+ if (!includeSystem || entryInfo.exists())
+ return false;
+ }
+
+ // filter hidden
+ const bool includeHidden = filters.testAnyFlag(QDir::Hidden);
+ if (!includeHidden && !dotOrDotDot && entryInfo.isHidden())
+ return false;
+
+ // filter system files
+ if (!includeSystem) {
+ if (!entryInfo.isFile() && !entryInfo.isDir() && !entryInfo.isSymLink())
+ return false;
+ if (entryInfo.isSymLink() && !entryInfo.exists())
+ return false;
+ }
+
+ // skip directories
+ const bool skipDirs = !(filters & (QDir::Dirs | QDir::AllDirs));
+ if (skipDirs && entryInfo.isDir())
+ return false;
+
+ // skip files
+ const bool skipFiles = !(filters & QDir::Files);
+ if (skipFiles && entryInfo.isFile())
+ // Basically we need a reason not to exclude this file otherwise we just eliminate it.
+ return false;
+
+ // filter permissions
+ const auto perms = filters & QDir::PermissionMask;
+ const bool filterPermissions = perms != 0 && perms != QDir::PermissionMask;
+ if (filterPermissions) {
+ const bool doWritable = filters.testAnyFlags(QDir::Writable);
+ const bool doExecutable = filters.testAnyFlags(QDir::Executable);
+ const bool doReadable = filters.testAnyFlags(QDir::Readable);
+ if ((doReadable && !entryInfo.isReadable())
+ || (doWritable && !entryInfo.isWritable())
+ || (doExecutable && !entryInfo.isExecutable())) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool QDirListingPrivate::hasIterators() const
+{
+ if (engine)
+ return !fileEngineIterators.empty();
+
+#if !defined(QT_NO_FILESYSTEMITERATOR)
+ return !nativeIterators.empty();
+#endif
+
+ return false;
+}
+
+/*!
+ Constructs a QDirListing that can iterate over \a dir's entries, using
+ \a dir's name filters and the QDir::Filters set in \a dir. You can pass
+ options via \a flags to decide how the directory should be iterated.
+
+ By default, \a flags is NoIteratorFlags, which provides the same behavior
+ as in QDir::entryList().
+
+ The sorting in \a dir is ignored.
+
+ \note To list symlinks that point to non existing files, QDir::System
+ must be set in \a dir's QDir::Filters.
+
+ \sa hasNext(), next(), IteratorFlags
+*/
+QDirListing::QDirListing(const QDir &dir, IteratorFlags flags)
+ : d(new QDirListingPrivate)
+{
+ const QDirPrivate *other = dir.d_ptr.constData();
+ d->initialEntryInfo.entry = other->dirEntry;
+ d->nameFilters = other->nameFilters;
+ d->filters = other->filters;
+ d->iteratorFlags = flags;
+ const bool resolveEngine = other->fileEngine ? true : false;
+ d->init(resolveEngine);
+}
+
+/*!
+ Constructs a QDirListing that can iterate over \a path. Entries are
+ filtered according to \a filters. You can pass options via \a flags to
+ decide how the directory should be iterated.
+
+ By default, \a filters is QDir::NoFilter, and \a flags is NoIteratorFlags,
+ which provides the same behavior as in QDir::entryList().
+
+ \note To list symlinks that point to non existing files, QDir::System
+ must be set in \a filters.
+
+ \sa hasNext(), next(), IteratorFlags
+*/
+QDirListing::QDirListing(const QString &path, QDir::Filters filters, IteratorFlags flags)
+ : d(new QDirListingPrivate)
+{
+ d->initialEntryInfo.entry = QFileSystemEntry(path);
+ d->filters = filters;
+ d->iteratorFlags = flags;
+ d->init();
+}
+
+/*!
+ Constructs a QDirListing that can iterate over \a path. You can pass
+ options via \a flags to decide how the directory should be iterated.
+
+ By default, \a flags is NoIteratorFlags, which provides the same behavior
+ as in QDir::entryList().
+
+ \sa hasNext(), next(), IteratorFlags
+*/
+QDirListing::QDirListing(const QString &path, IteratorFlags flags)
+ : d(new QDirListingPrivate)
+{
+ d->initialEntryInfo.entry = QFileSystemEntry(path);
+ d->filters = QDir::NoFilter;
+ d->iteratorFlags = flags;
+ d->init();
+}
+
+/*!
+ Constructs a QDirListing that can iterate over \a path, using \a
+ nameFilters and \a filters. You can pass options via \a flags to decide
+ how the directory should be iterated.
+
+ By default, \a flags is NoIteratorFlags, which provides the same behavior
+ as QDir::entryList().
+
+ For example, the following iterator could be used to iterate over audio
+ files:
+
+ \snippet code/src_corelib_io_qdirlisting.cpp 2
+
+ \note To list symlinks that point to non existing files, QDir::System
+ must be set in \a flags.
+
+ \sa hasNext(), next(), IteratorFlags, QDir::setNameFilters()
+*/
+QDirListing::QDirListing(const QString &path, const QStringList &nameFilters, QDir::Filters filters,
+ IteratorFlags flags)
+ : d(new QDirListingPrivate)
+{
+ d->initialEntryInfo.entry = QFileSystemEntry(path);
+ d->nameFilters = nameFilters;
+ d->filters = filters;
+ d->iteratorFlags = flags;
+ d->init();
+}
+
+/*!
+ Destroys the QDirListing.
+*/
+QDirListing::~QDirListing() = default;
+
+/*!
+ Returns the directory path used to construct this QDirListing.
+*/
+QString QDirListing::iteratorPath() const
+{
+ return d->initialEntryInfo.filePath();
+}
+
+/*!
+ \fn QDirListing::const_iterator QDirListing::begin() const
+ \fn QDirListing::const_iterator QDirListing::cbegin() const
+ \fn QDirListing::const_iterator QDirListing::end() const
+ \fn QDirListing::const_iterator QDirListing::cend() const
+
+ begin()/cbegin() returns a QDirListing::const_iterator that enables
+ iterating over directory entries using a ranged-for loop; dereferencing
+ this iterator returns a \c{const QFileInfo &}.
+
+ end()/cend() return a sentinel const_iterator that signals the end of
+ the iteration. Dereferencing this iterator is undefined behavior.
+
+ For example:
+ \snippet code/src_corelib_io_qdirlisting.cpp 0
+
+ Here's how to find and read all files filtered by name, recursively:
+ \snippet code/src_corelib_io_qdirlisting.cpp 1
+
+ \note As this is a unidirectional (forward-only) iterator, calling
+ begin()/cbegin() more than once on the same QDirListing object could
+ result in unexpected behavior (for example, some entries being skipped).
+
+ \sa fileInfo(), fileName(), filePath()
+*/
+QDirListing::const_iterator QDirListing::begin() const
+{
+ const_iterator it{d.get()};
+ return ++it;
+}
+
+/*!
+ \fn const QDirListing::DirEntry &QDirListing::const_iterator::operator*() const
+
+ Returns a \c{const QDirListing::DirEntry &} of the directory entry this
+ iterator points to.
+*/
+
+/*!
+ \fn const QDirListing::DirEntry *QDirListing::const_iterator::operator->() const
+
+ Returns a \c{const QDirListing::DirEntry *} to the directory entry this
+ iterator points to.
+*/
+
+/*!
+ Advances the iterator and returns a reference to it.
+*/
+QDirListing::const_iterator &QDirListing::const_iterator::operator++()
+{
+ dirListPtr->advance();
+ if (!dirListPtr->hasIterators())
+ *this = {}; // All done, make `this` the end() iterator
+ return *this;
+}
+
+/*!
+ \fn QFileInfo QDirListing::DirEntry::fileInfo() const
+ \fn QString QDirListing::DirEntry::fileName() const
+ \fn QString QDirListing::DirEntry::baseName() const
+ \fn QString QDirListing::DirEntry::completeBaseName() const
+ \fn QString QDirListing::DirEntry::suffix() const
+ \fn QString QDirListing::DirEntry::bundleName() const
+ \fn QString QDirListing::DirEntry::completeSuffix() const
+ \fn QString QDirListing::DirEntry::filePath() const
+ \fn QString QDirListing::DirEntry::canonicalFilePath() const
+ \fn QString QDirListing::DirEntry::absoluteFilePath() const
+ \fn QString QDirListing::DirEntry::absolutePath() const
+ \fn bool QDirListing::DirEntry::isDir() const
+ \fn bool QDirListing::DirEntry::isFile() const
+ \fn bool QDirListing::DirEntry::isSymLink() const
+ \fn bool QDirListing::DirEntry::exists() const
+ \fn bool QDirListing::DirEntry::isHidden() const
+ \fn bool QDirListing::DirEntry::isReadable() const
+ \fn bool QDirListing::DirEntry::isWritable() const
+ \fn bool QDirListing::DirEntry::isExecutable() const
+ \fn qint64 QDirListing::DirEntry::size() const
+ \fn QDateTime QDirListing::DirEntry::fileTime(QFile::FileTime type, const QTimeZone &tz) const
+ \fn QDateTime QDirListing::DirEntry::birthTime(const QTimeZone &tz) const;
+ \fn QDateTime QDirListing::DirEntry::metadataChangeTime(const QTimeZone &tz) const;
+ \fn QDateTime QDirListing::DirEntry::lastModified(const QTimeZone &tz) const;
+ \fn QDateTime QDirListing::DirEntry::lastRead(const QTimeZone &tz) const;
+
+ See the QFileInfo methods with the same names.
+*/
+
+QFileInfo QDirListing::DirEntry::fileInfo() const
+{
+ return dirListPtr->currentEntryInfo.fileInfo();
+}
+
+QString QDirListing::DirEntry::fileName() const
+{
+ return dirListPtr->currentEntryInfo.fileName();
+}
+
+QString QDirListing::DirEntry::baseName() const
+{
+ return dirListPtr->currentEntryInfo.baseName();
+}
+
+QString QDirListing::DirEntry::completeBaseName() const
+{
+ return dirListPtr->currentEntryInfo.completeBaseName();
+}
+
+QString QDirListing::DirEntry::suffix() const
+{
+ return dirListPtr->currentEntryInfo.suffix();
+}
+
+QString QDirListing::DirEntry::bundleName() const
+{
+ return dirListPtr->currentEntryInfo.bundleName();
+}
+
+QString QDirListing::DirEntry::completeSuffix() const
+{
+ return dirListPtr->currentEntryInfo.completeSuffix();
+}
+
+QString QDirListing::DirEntry::filePath() const
+{
+ return dirListPtr->currentEntryInfo.filePath();
+}
+
+QString QDirListing::DirEntry::canonicalFilePath() const
+{
+ return dirListPtr->currentEntryInfo.canonicalFilePath();
+}
+
+QString QDirListing::DirEntry::absoluteFilePath() const
+{
+ return dirListPtr->currentEntryInfo.absoluteFilePath();
+}
+
+QString QDirListing::DirEntry::absolutePath() const
+{
+ return dirListPtr->currentEntryInfo.absolutePath();
+}
+
+bool QDirListing::DirEntry::isDir() const
+{
+ return dirListPtr->currentEntryInfo.isDir();
+}
+
+bool QDirListing::DirEntry::isFile() const
+{
+ return dirListPtr->currentEntryInfo.isFile();
+}
+
+bool QDirListing::DirEntry::isSymLink() const
+{
+ return dirListPtr->currentEntryInfo.isSymLink();
+}
+
+bool QDirListing::DirEntry::exists() const
+{
+ return dirListPtr->currentEntryInfo.exists();
+}
+
+bool QDirListing::DirEntry::isHidden() const
+{
+ return dirListPtr->currentEntryInfo.isHidden();
+}
+
+bool QDirListing::DirEntry::isReadable() const
+{
+ return dirListPtr->currentEntryInfo.isReadable();
+}
+
+bool QDirListing::DirEntry::isWritable() const
+{
+ return dirListPtr->currentEntryInfo.isWritable();
+}
+
+bool QDirListing::DirEntry::isExecutable() const
+{
+ return dirListPtr->currentEntryInfo.isExecutable();
+}
+
+qint64 QDirListing::DirEntry::size() const
+{
+ return dirListPtr->currentEntryInfo.size();
+}
+
+QDateTime QDirListing::DirEntry::fileTime(QFile::FileTime type, const QTimeZone &tz) const
+{
+ return dirListPtr->currentEntryInfo.fileTime(type, tz);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qdirlisting.h b/src/corelib/io/qdirlisting.h
new file mode 100644
index 0000000000..d19fe3c666
--- /dev/null
+++ b/src/corelib/io/qdirlisting.h
@@ -0,0 +1,119 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2024 Ahmad Samir <a.samirh78@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QDILISTING_H
+#define QDILISTING_H
+
+#include <QtCore/qdir.h>
+
+#include <iterator>
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+class QDirListingPrivate;
+
+class Q_CORE_EXPORT QDirListing
+{
+public:
+ enum class IteratorFlag {
+ NoFlag = 0x0,
+ FollowSymlinks = 0x1,
+ Recursive = 0x2
+ };
+ Q_DECLARE_FLAGS(IteratorFlags, IteratorFlag)
+
+ QDirListing(const QDir &dir, IteratorFlags flags = IteratorFlag::NoFlag);
+ QDirListing(const QString &path, IteratorFlags flags = IteratorFlag::NoFlag);
+ QDirListing(const QString &path, QDir::Filters filter,
+ IteratorFlags flags = IteratorFlag::NoFlag);
+ QDirListing(const QString &path, const QStringList &nameFilters,
+ QDir::Filters filters = QDir::NoFilter,
+ IteratorFlags flags = IteratorFlag::NoFlag);
+
+ ~QDirListing();
+
+ QString iteratorPath() const;
+
+ class Q_CORE_EXPORT DirEntry
+ {
+ friend class QDirListing;
+ QDirListingPrivate *dirListPtr = nullptr;
+ public:
+ QString fileName() const;
+ QString baseName() const;
+ QString completeBaseName() const;
+ QString suffix() const;
+ QString bundleName() const;
+ QString completeSuffix() const;
+ QString filePath() const;
+ bool isDir() const;
+ bool isFile() const;
+ bool isSymLink() const;
+ bool exists() const;
+ bool isHidden() const;
+ bool isReadable() const;
+ bool isWritable() const;
+ bool isExecutable() const;
+ QFileInfo fileInfo() const;
+ QString canonicalFilePath() const;
+ QString absoluteFilePath() const;
+ QString absolutePath() const;
+ qint64 size() const;
+
+ QDateTime birthTime(const QTimeZone &tz) const { return fileTime(QFile::FileBirthTime, tz); }
+ QDateTime metadataChangeTime(const QTimeZone &tz) const { return fileTime(QFile::FileMetadataChangeTime, tz); }
+ QDateTime lastModified(const QTimeZone &tz) const { return fileTime(QFile::FileModificationTime, tz); }
+ QDateTime lastRead(const QTimeZone &tz) const { return fileTime(QFile::FileAccessTime, tz); }
+ QDateTime fileTime(QFile::FileTime type, const QTimeZone &tz) const;
+ };
+
+ class const_iterator
+ {
+ friend class QDirListing;
+ const_iterator(QDirListingPrivate *dp) : dirListPtr(dp) { dirEntry.dirListPtr = dp; }
+ QDirListingPrivate *dirListPtr = nullptr;
+ DirEntry dirEntry;
+ public:
+ using iterator_category = std::input_iterator_tag;
+ using value_type = DirEntry;
+ using difference_type = qint64;
+ using pointer = const value_type *;
+ using reference = const value_type &;
+
+ const_iterator() = default;
+ reference operator*() const { return dirEntry; }
+ pointer operator->() const { return &dirEntry; }
+ Q_CORE_EXPORT const_iterator &operator++();
+ const_iterator operator++(int) { auto tmp = *this; operator++(); return tmp; };
+ friend bool operator==(const const_iterator &lhs, const const_iterator &rhs)
+ {
+ // This is only used for the sentinel end iterator
+ return lhs.dirListPtr == nullptr && rhs.dirListPtr == nullptr;
+ }
+ friend bool operator!=(const const_iterator &lhs, const const_iterator &rhs)
+ { return !(lhs == rhs); }
+ };
+
+ const_iterator begin() const;
+ const_iterator cbegin() const { return begin(); }
+ const_iterator end() const { return {}; }
+ const_iterator cend() const { return end(); }
+
+ // Qt compatibility
+ const_iterator constBegin() const { return begin(); }
+ const_iterator constEnd() const { return end(); }
+
+private:
+ Q_DISABLE_COPY(QDirListing)
+
+ std::unique_ptr<QDirListingPrivate> d;
+ friend class QDir;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDirListing::IteratorFlags)
+
+QT_END_NAMESPACE
+
+#endif // QDILISTING_H
diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp
index ec67ca6f48..52188dde51 100644
--- a/src/corelib/io/qfile.cpp
+++ b/src/corelib/io/qfile.cpp
@@ -76,7 +76,7 @@ QFilePrivate::openExternalFile(QIODevice::OpenMode flags, FILE *fh, QFile::FileH
QAbstractFileEngine *QFilePrivate::engine() const
{
if (!fileEngine)
- fileEngine.reset(QAbstractFileEngine::create(fileName));
+ fileEngine = QAbstractFileEngine::create(fileName);
return fileEngine.get();
}
@@ -459,6 +459,24 @@ QFile::remove(const QString &fileName)
and sets the fileName() to the path at which the file can be found within the trash;
otherwise returns \c false.
+//! [move-to-trash-common]
+ The time for this function to run is independent of the size of the file
+ being trashed. If this function is called on a directory, it may be
+ proportional to the number of files being trashed.
+
+ This function uses the Windows and \macos APIs to perform the trashing on
+ those two operating systems. Elsewhere (Unix systems), this function
+ implements the \l{FreeDesktop.org Trash specification version 1.0}.
+
+ \note When using the FreeDesktop.org Trash implementation, this function
+ will fail if it is unable to move the files to the trash location by way of
+ file renames and hardlinks. This condition arises if the file being trashed
+ resides on a volume (mount point) on which the current user does not have
+ permission to create the \c{.Trash} directory, or with some unusual
+ filesystem types or configurations (such as sub-volumes that aren't
+ themselves mount points).
+//! [move-to-trash-common]
+
\note On systems where the system API doesn't report the location of the file in the
trash, fileName() will be set to the null string once the file has been moved. On
systems that don't have a trash can, this function always returns false.
@@ -496,9 +514,12 @@ QFile::moveToTrash()
and sets \a pathInTrash (if provided) to the path at which the file can be found within
the trash; otherwise returns \c false.
+ \include qfile.cpp move-to-trash-common
+
\note On systems where the system API doesn't report the path of the file in the
trash, \a pathInTrash will be set to the null string once the file has been moved.
On systems that don't have a trash can, this function always returns false.
+
*/
bool
QFile::moveToTrash(const QString &fileName, QString *pathInTrash)
@@ -563,7 +584,7 @@ QFile::rename(const QString &newName)
return false;
}
-#ifdef Q_OS_LINUX
+#if defined(Q_OS_LINUX) && QT_CONFIG(temporaryfile)
// rename() on Linux simply does nothing when renaming "foo" to "Foo" on a case-insensitive
// FS, such as FAT32. Move the file away and rename in 2 steps to work around.
QTemporaryFileName tfn(d->fileName);
@@ -768,7 +789,7 @@ QFile::copy(const QString &newName)
d->setError(QFile::CopyError, tr("Cannot open %1 for input").arg(d->fileName));
} else {
const auto fileTemplate = "%1/qt_temp.XXXXXX"_L1;
-#ifdef QT_NO_TEMPORARYFILE
+#if !QT_CONFIG(temporaryfile)
QFile out(fileTemplate.arg(QFileInfo(newName).path()));
if (!out.open(QIODevice::ReadWrite))
error = true;
@@ -781,9 +802,9 @@ QFile::copy(const QString &newName)
}
#endif
if (error) {
+ d->setError(QFile::CopyError, tr("Cannot open for output: %1").arg(out.errorString()));
out.close();
close();
- d->setError(QFile::CopyError, tr("Cannot open for output: %1").arg(out.errorString()));
} else {
if (!d->engine()->cloneTo(out.d_func()->engine())) {
char block[4096];
@@ -820,7 +841,7 @@ QFile::copy(const QString &newName)
.arg(newName, out.errorString()));
}
}
-#ifdef QT_NO_TEMPORARYFILE
+#if !QT_CONFIG(temporaryfile)
if (error)
out.remove();
#else
@@ -876,6 +897,8 @@ QFile::copy(const QString &fileName, const QString &newName)
of the file name, otherwise, it won't be possible to create this
non-existing file.
+ \sa QT_USE_NODISCARD_FILE_OPEN
+
\sa QIODevice::OpenMode, setFileName()
*/
bool QFile::open(OpenMode mode)
@@ -920,7 +943,7 @@ bool QFile::open(OpenMode mode)
such permissions will generate warnings when the Security tab of the Properties dialog
is opened. Granting the group all permissions granted to others avoids such warnings.
- \sa QIODevice::OpenMode, setFileName()
+ \sa QIODevice::OpenMode, setFileName(), QT_USE_NODISCARD_FILE_OPEN
\since 6.3
*/
bool QFile::open(OpenMode mode, QFile::Permissions permissions)
@@ -977,7 +1000,7 @@ bool QFile::open(OpenMode mode, QFile::Permissions permissions)
you cannot use this QFile with a QFileInfo.
\endlist
- \sa close()
+ \sa close(), QT_USE_NODISCARD_FILE_OPEN
\b{Note for the Windows Platform}
@@ -1043,7 +1066,7 @@ bool QFile::open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
\warning Since this function opens the file without specifying the file name,
you cannot use this QFile with a QFileInfo.
- \sa close()
+ \sa close(), QT_USE_NODISCARD_FILE_OPEN
*/
bool QFile::open(int fd, OpenMode mode, FileHandleFlags handleFlags)
{
@@ -1250,6 +1273,107 @@ qint64 QFile::size() const
*/
+/*!
+ \class QNtfsPermissionCheckGuard
+ \since 6.6
+ \inmodule QtCore
+ \brief The QNtfsPermissionCheckGuard class is a RAII class to manage NTFS
+ permission checking.
+
+ \ingroup io
+
+ For performance reasons, QFile, QFileInfo, and related classes do not
+ perform full ownership and permission (ACL) checking on NTFS file systems
+ by default. During the lifetime of any instance of this class, that
+ default is overridden and advanced checking is performed. This provides
+ a safe and easy way to manage enabling and disabling this change to the
+ default behavior.
+
+ Example:
+
+ \snippet ntfsp.cpp raii
+
+ This class is available only on Windows.
+
+ \section1 qt_ntfs_permission_lookup
+
+ Prior to Qt 6.6, the user had to directly manipulate the global variable
+ \c qt_ntfs_permission_lookup. However, this was a non-atomic global
+ variable and as such it was prone to data races.
+
+ The variable \c qt_ntfs_permission_lookup is therefore deprecated since Qt
+ 6.6.
+*/
+
+/*!
+ \fn QNtfsPermissionCheckGuard::QNtfsPermissionCheckGuard()
+
+ Creates a guard and calls the function qEnableNtfsPermissionChecks().
+*/
+
+/*!
+ \fn QNtfsPermissionCheckGuard::~QNtfsPermissionCheckGuard()
+
+ Destroys the guard and calls the function qDisableNtfsPermissionChecks().
+*/
+
+
+/*!
+ \fn bool qEnableNtfsPermissionChecks()
+ \since 6.6
+ \threadsafe
+ \relates QNtfsPermissionCheckGuard
+
+ Enables permission checking on NTFS file systems. Returns \c true if the check
+ was already enabled before the call to this function, meaning that there
+ are other users.
+
+ This function is only available on Windows and makes the direct
+ manipulation of \l qt_ntfs_permission_lookup obsolete.
+
+ This is a low-level function, please consider the RAII class
+ \l QNtfsPermissionCheckGuard instead.
+
+ \note The thread-safety of this function holds only as long as there are no
+ concurrent updates to \l qt_ntfs_permission_lookup.
+*/
+
+/*!
+ \fn bool qDisableNtfsPermissionChecks()
+ \since 6.6
+ \threadsafe
+ \relates QNtfsPermissionCheckGuard
+
+ Disables permission checking on NTFS file systems. Returns \c true if the
+ check is disabled, meaning that there are no more users.
+
+ This function is only available on Windows and makes the direct
+ manipulation of \l qt_ntfs_permission_lookup obsolete.
+
+ This is a low-level function and must (only) be called to match one earlier
+ call to qEnableNtfsPermissionChecks(). Please consider the RAII class
+ \l QNtfsPermissionCheckGuard instead.
+
+ \note The thread-safety of this function holds only as long as there are no
+ concurrent updates to \l qt_ntfs_permission_lookup.
+*/
+
+/*!
+ \fn bool qAreNtfsPermissionChecksEnabled()
+ \since 6.6
+ \threadsafe
+ \relates QNtfsPermissionCheckGuard
+
+ Checks the status of the permission checks on NTFS file systems. Returns
+ \c true if the check is enabled.
+
+ This function is only available on Windows and makes the direct
+ manipulation of \l qt_ntfs_permission_lookup obsolete.
+
+ \note The thread-safety of this function holds only as long as there are no
+ concurrent updates to \l qt_ntfs_permission_lookup.
+*/
+
QT_END_NAMESPACE
#ifndef QT_NO_QOBJECT
diff --git a/src/corelib/io/qfile.h b/src/corelib/io/qfile.h
index cb06665a9f..058b2fa236 100644
--- a/src/corelib/io/qfile.h
+++ b/src/corelib/io/qfile.h
@@ -26,7 +26,7 @@ namespace std {
QT_BEGIN_NAMESPACE
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) || defined(Q_QDOC)
#if QT_DEPRECATED_SINCE(6,6)
QT_DEPRECATED_VERSION_X_6_6("Use QNtfsPermissionCheckGuard RAII class instead.")
@@ -37,10 +37,11 @@ Q_CORE_EXPORT bool qEnableNtfsPermissionChecks() noexcept;
Q_CORE_EXPORT bool qDisableNtfsPermissionChecks() noexcept;
Q_CORE_EXPORT bool qAreNtfsPermissionChecksEnabled() noexcept;
-class [[nodiscard]] QNtfsPermissionCheckGuard
+class QNtfsPermissionCheckGuard
{
Q_DISABLE_COPY_MOVE(QNtfsPermissionCheckGuard)
public:
+ Q_NODISCARD_CTOR
QNtfsPermissionCheckGuard()
{
qEnableNtfsPermissionChecks();
@@ -281,10 +282,10 @@ public:
}
#endif // QT_CONFIG(cxx17_filesystem)
- bool open(OpenMode flags) override;
- bool open(OpenMode flags, Permissions permissions);
- bool open(FILE *f, OpenMode ioFlags, FileHandleFlags handleFlags=DontCloseHandle);
- bool open(int fd, OpenMode ioFlags, FileHandleFlags handleFlags=DontCloseHandle);
+ QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override;
+ QFILE_MAYBE_NODISCARD bool open(OpenMode flags, Permissions permissions);
+ QFILE_MAYBE_NODISCARD bool open(FILE *f, OpenMode ioFlags, FileHandleFlags handleFlags=DontCloseHandle);
+ QFILE_MAYBE_NODISCARD bool open(int fd, OpenMode ioFlags, FileHandleFlags handleFlags=DontCloseHandle);
qint64 size() const override;
diff --git a/src/corelib/io/qfiledevice.cpp b/src/corelib/io/qfiledevice.cpp
index 092b09ae05..431dc65f5b 100644
--- a/src/corelib/io/qfiledevice.cpp
+++ b/src/corelib/io/qfiledevice.cpp
@@ -168,6 +168,35 @@ void QFileDevicePrivate::setError(QFileDevice::FileError err, int errNum)
handle is left open when the QFile object is destroyed.
*/
+/*!
+ \macro QT_USE_NODISCARD_FILE_OPEN
+ \macro QT_NO_USE_NODISCARD_FILE_OPEN
+ \relates QFileDevice
+ \since 6.8
+
+ File-related I/O classes (such as QFile, QSaveFile, QTemporaryFile)
+ have an \c{open()} method to open the file they act upon. It is
+ important to check the return value of the call to \c{open()}
+ before proceeding with reading or writing data into the file.
+
+ For this reason, starting with Qt 6.8, some overloads of \c{open()}
+ have been marked with the \c{[[nodiscard]]} attribute. Since this
+ change may raise warnings in existing codebases, user code can
+ opt-in or opt-out from having the attribute applied by defining
+ certain macros:
+
+ \list
+ \li If the \c{QT_USE_NODISCARD_FILE_OPEN} macro is defined,
+ overloads of \c{open()} are marked as \c{[[nodiscard]]}.
+ \li If the \c{QT_NO_USE_NODISCARD_FILE_OPEN} is defined, the
+ overloads of \c{open()} are \e{not} marked as \c{[[nodiscard]]}.
+ \li If neither macro is defined, then the default up to and
+ including Qt 6.9 is not to have the attribute. Starting from Qt 6.10,
+ the attribute is automatically applied.
+ \li If both macros are defined, the program is ill-formed.
+ \endlist
+*/
+
#ifdef QT_NO_QOBJECT
QFileDevice::QFileDevice()
: QIODevice(*new QFileDevicePrivate)
@@ -734,15 +763,6 @@ bool QFileDevice::unmap(uchar *address)
\sa setFileTime(), fileTime(), QFileInfo::fileTime()
*/
-static inline QAbstractFileEngine::FileTime FileDeviceTimeToAbstractFileEngineTime(QFileDevice::FileTime time)
-{
- static_assert(int(QFileDevice::FileAccessTime) == int(QAbstractFileEngine::AccessTime));
- static_assert(int(QFileDevice::FileBirthTime) == int(QAbstractFileEngine::BirthTime));
- static_assert(int(QFileDevice::FileMetadataChangeTime) == int(QAbstractFileEngine::MetadataChangeTime));
- static_assert(int(QFileDevice::FileModificationTime) == int(QAbstractFileEngine::ModificationTime));
- return QAbstractFileEngine::FileTime(time);
-}
-
/*!
\since 5.10
Returns the file time specified by \a time.
@@ -756,7 +776,7 @@ QDateTime QFileDevice::fileTime(QFileDevice::FileTime time) const
Q_D(const QFileDevice);
if (d->engine())
- return d->engine()->fileTime(FileDeviceTimeToAbstractFileEngineTime(time));
+ return d->engine()->fileTime(time);
return QDateTime();
}
@@ -779,7 +799,7 @@ bool QFileDevice::setFileTime(const QDateTime &newDate, QFileDevice::FileTime fi
return false;
}
- if (!d->fileEngine->setFileTime(newDate, FileDeviceTimeToAbstractFileEngineTime(fileTime))) {
+ if (!d->fileEngine->setFileTime(newDate, fileTime)) {
d->setError(d->fileEngine->error(), d->fileEngine->errorString());
return false;
}
diff --git a/src/corelib/io/qfiledevice.h b/src/corelib/io/qfiledevice.h
index 79788e2aaf..5274025715 100644
--- a/src/corelib/io/qfiledevice.h
+++ b/src/corelib/io/qfiledevice.h
@@ -12,6 +12,22 @@ QT_BEGIN_NAMESPACE
class QDateTime;
class QFileDevicePrivate;
+#if !defined(QT_USE_NODISCARD_FILE_OPEN) && !defined(QT_NO_USE_NODISCARD_FILE_OPEN)
+# if QT_VERSION < QT_VERSION_CHECK(6, 10, 0)
+# define QT_NO_USE_NODISCARD_FILE_OPEN
+# else
+# define QT_USE_NODISCARD_FILE_OPEN
+# endif
+#endif
+
+#if defined(QT_USE_NODISCARD_FILE_OPEN) && defined(QT_NO_USE_NODISCARD_FILE_OPEN)
+#error "Inconsistent macro definition for nodiscard QFile::open"
+#elif defined(QT_USE_NODISCARD_FILE_OPEN)
+#define QFILE_MAYBE_NODISCARD [[nodiscard]]
+#else /* QT_NO_USE_NODISCARD_FILE_OPEN */
+#define QFILE_MAYBE_NODISCARD
+#endif
+
class Q_CORE_EXPORT QFileDevice : public QIODevice
{
#ifndef QT_NO_QOBJECT
diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp
index aa1bde6a4a..6bc0128aff 100644
--- a/src/corelib/io/qfileinfo.cpp
+++ b/src/corelib/io/qfileinfo.cpp
@@ -157,7 +157,7 @@ uint QFileInfoPrivate::getFileFlags(QAbstractFileEngine::FileFlags request) cons
return fileFlags & request.toInt();
}
-QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request) const
+QDateTime &QFileInfoPrivate::getFileTime(QFile::FileTime request) const
{
Q_ASSERT(fileEngine); // should never be called when using the native FS
if (!cache_enabled)
@@ -165,16 +165,16 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request)
uint cf = 0;
switch (request) {
- case QAbstractFileEngine::AccessTime:
+ case QFile::FileAccessTime:
cf = CachedATime;
break;
- case QAbstractFileEngine::BirthTime:
+ case QFile::FileBirthTime:
cf = CachedBTime;
break;
- case QAbstractFileEngine::MetadataChangeTime:
+ case QFile::FileMetadataChangeTime:
cf = CachedMCTime;
break;
- case QAbstractFileEngine::ModificationTime:
+ case QFile::FileModificationTime:
cf = CachedMTime;
break;
}
@@ -192,46 +192,53 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request)
\class QFileInfo
\inmodule QtCore
\reentrant
- \brief The QFileInfo class provides system-independent file information.
+ \brief The QFileInfo class provides an OS-independent API to retrieve
+ information about file system entries.
\ingroup io
\ingroup shared
- QFileInfo provides information about a file's name and position
- (path) in the file system, its access rights and whether it is a
- directory or symbolic link, etc. The file's size and last
- modified/read times are also available. QFileInfo can also be
- used to obtain information about a Qt \l{resource
- system}{resource}.
-
- A QFileInfo can point to a file with either a relative or an
- absolute file path. Absolute file paths begin with the directory
- separator "/" (or with a drive specification on Windows). Relative
- file names begin with a directory name or a file name and specify
- a path relative to the current working directory. An example of an
- absolute path is the string "/tmp/quartz". A relative path might
- look like "src/fatlib". You can use the function isRelative() to
- check whether a QFileInfo is using a relative or an absolute file
- path. You can call the function makeAbsolute() to convert a
- relative QFileInfo's path to an absolute path.
+ \compares equality
- \note Paths starting with a colon (\e{:}) are always considered
- absolute, as they denote a QResource.
+ QFileInfo provides information about a file system entry, such as its
+ name, path, access rights and whether it is a regular file, directory or
+ symbolic link. The entry's size and last modified/read times are also
+ available. QFileInfo can also be used to obtain information about a Qt
+ \l{resource system}{resource}.
+
+ A QFileInfo can point to a file system entry with either an absolute or
+ a relative path:
+ \list
+ \li \include qfileinfo.cpp absolute-path-unix-windows
- The file that the QFileInfo works on is set in the constructor or
- later with setFile(). Use exists() to see if the file exists and
- size() to get its size.
+ \li \include qfileinfo.cpp relative-path-note
+ \endlist
- The file's type is obtained with isFile(), isDir() and
- isSymLink(). The symLinkTarget() function provides the name of the file
- the symlink points to.
+ An example of an absolute path is the string \c {"/tmp/quartz"}. A relative
+ path may look like \c {"src/fatlib"}. You can use the function isRelative()
+ to check whether a QFileInfo is using a relative or an absolute path. You
+ can call the function makeAbsolute() to convert a relative QFileInfo's
+ path to an absolute path.
- Elements of the file's name can be extracted with path() and
- fileName(). The fileName()'s parts can be extracted with
- baseName(), suffix() or completeSuffix(). QFileInfo objects to
- directories created by Qt classes will not have a trailing file
- separator. If you wish to use trailing separators in your own file
- info objects, just append one to the file name given to the constructors
+//! [qresource-virtual-fs-colon]
+ \note Paths starting with a colon (\e{:}) are always considered
+ absolute, as they denote a QResource.
+//! [qresource-virtual-fs-colon]
+
+ The file system entry path that the QFileInfo works on is set in the
+ constructor or later with setFile(). Use exists() to see if the entry
+ actually exists and size() to get its size.
+
+ The file system entry's type is obtained with isFile(), isDir(), and
+ isSymLink(). The symLinkTarget() function provides the absolute path of
+ the target the symlink points to.
+
+ The path elements of the file system entry can be extracted with path()
+ and fileName(). The fileName()'s parts can be extracted with baseName(),
+ suffix(), or completeSuffix(). QFileInfo objects referring to directories
+ created by Qt classes will not have a trailing directory separator
+ \c{'/'}. If you wish to use trailing separators in your own file info
+ objects, just append one to the entry's path given to the constructors
or setFile().
Date and time related information are returned by birthTime(), fileTime(),
@@ -245,18 +252,18 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request)
\section1 Symbolic Links and Shortcuts
- On Unix (including \macos and iOS), the property getter functions in this
- class return the properties such as times and size of the target file, not
- the symlink, because Unix handles symlinks transparently. Opening a symlink
- using QFile effectively opens the link's target. For example:
+ On Unix (including \macos and iOS), the property getter functions in
+ this class return the properties such as times and size of the target,
+ not the symlink, because Unix handles symlinks transparently. Opening
+ a symlink using QFile effectively opens the link's target. For example:
\snippet code/src_corelib_io_qfileinfo.cpp 0
On Windows, shortcuts (\c .lnk files) are currently treated as symlinks. As
- on Unix systems, the property getters return the size of the targeted file,
- not the \c .lnk file itself. This behavior is deprecated and will likely be
- removed in a future version of Qt, after which \c .lnk files will be treated
- as regular files.
+ on Unix systems, the property getters return the size of the target,
+ not the \c .lnk file itself. This behavior is deprecated and will likely
+ be removed in a future version of Qt, after which \c .lnk files will be
+ treated as regular files.
\snippet code/src_corelib_io_qfileinfo.cpp 1
@@ -293,21 +300,24 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request)
\section1 Performance Considerations
- Some of QFileInfo's functions query the file system, but for
- performance reasons, some functions only operate on the
- file name itself. For example: To return the absolute path of
- a relative file name, absolutePath() has to query the file system.
- The path() function, however, can work on the file name directly,
- and so it is faster.
-
- To speed up performance, QFileInfo also caches information about
- the file. Because files can be changed by other users or programs, or
- even by other parts of the same program, there is a function that
- refreshes the file information: refresh(). If you want to switch
- off a QFileInfo's caching and force it to access the file system
- every time you request information from it call setCaching(false).
- If you want to make sure that all information is read from the
- file system, use stat().
+ Some of QFileInfo's functions have to query the file system, but for
+ performance reasons, some functions only operate on the path string.
+ For example: To return the absolute path of a relative entry's path,
+ absolutePath() has to query the file system. The path() function, however,
+ can work on the file name directly, and so it is faster.
+
+ QFileInfo also caches information about the file system entry it refers
+ to. Because the file system can be changed by other users or programs,
+ or even by other parts of the same program, there is a function that
+ refreshes the information stored in QFileInfo, namely refresh(). To switch
+ off a QFileInfo's caching (that is, force it to query the underlying file
+ system every time you request information from it), call setCaching(false).
+
+ Fetching information from the file system is typically done by calling
+ (possibly) expensive system functions, so QFileInfo (depending on the
+ implementation) might not fetch all the information from the file system
+ at construction. To make sure that all information is read from the file
+ system immediately, use the stat() member function.
\l{birthTime()}, \l{fileTime()}, \l{lastModified()}, \l{lastRead()},
and \l{metadataChangeTime()} return times in \e{local time} by default.
@@ -338,9 +348,8 @@ QFileInfo::QFileInfo(QFileInfoPrivate *p) : d_ptr(p)
}
/*!
- Constructs an empty QFileInfo object.
-
- Note that an empty QFileInfo object contain no file reference.
+ Constructs an empty QFileInfo object that doesn't refer to any file
+ system entry.
\sa setFile()
*/
@@ -349,12 +358,16 @@ QFileInfo::QFileInfo() : d_ptr(new QFileInfoPrivate())
}
/*!
- Constructs a new QFileInfo that gives information about the given
- file. The \a file can also include an absolute or relative path.
+ Constructs a QFileInfo that gives information about a file system entry
+ located at \a path that can be absolute or relative.
+
+//! [preserve-relative-path]
+ If \a path is relative, the QFileInfo will also have a relative path.
+//! [preserve-relative-path]
\sa setFile(), isRelative(), QDir::setCurrent(), QDir::isRelativePath()
*/
-QFileInfo::QFileInfo(const QString &file) : d_ptr(new QFileInfoPrivate(file))
+QFileInfo::QFileInfo(const QString &path) : d_ptr(new QFileInfoPrivate(path))
{
}
@@ -373,18 +386,20 @@ QFileInfo::QFileInfo(const QFileDevice &file) : d_ptr(new QFileInfoPrivate(file.
/*!
Constructs a new QFileInfo that gives information about the given
- \a file relative to the directory \a dir.
+ file system entry \a path that is relative to the directory \a dir.
+//! [preserve-relative-or-absolute]
If \a dir has a relative path, the QFileInfo will also have a
relative path.
- If \a file is an absolute path, then the directory specified
- by \a dir will be disregarded.
+ If \a path is absolute, then the directory specified by \a dir
+ will be disregarded.
+//! [preserve-relative-or-absolute]
\sa isRelative()
*/
-QFileInfo::QFileInfo(const QDir &dir, const QString &file)
- : d_ptr(new QFileInfoPrivate(dir.filePath(file)))
+QFileInfo::QFileInfo(const QDir &dir, const QString &path)
+ : d_ptr(new QFileInfoPrivate(dir.filePath(path)))
{
}
@@ -406,58 +421,57 @@ QFileInfo::~QFileInfo()
}
/*!
- \fn bool QFileInfo::operator!=(const QFileInfo &fileinfo) const
+ \fn bool QFileInfo::operator!=(const QFileInfo &lhs, const QFileInfo &rhs)
- Returns \c true if this QFileInfo object refers to a different file
- than the one specified by \a fileinfo; otherwise returns \c false.
+ Returns \c true if QFileInfo \a lhs refers to a different file system
+ entry than the one referred to by \a rhs; otherwise returns \c false.
\sa operator==()
*/
/*!
- Returns \c true if this QFileInfo object refers to a file in the same
- location as \a fileinfo; otherwise returns \c false.
+ \fn bool QFileInfo::operator==(const QFileInfo &lhs, const QFileInfo &rhs)
+
+ Returns \c true if QFileInfo \a lhs and QFileInfo \a rhs refer to the same
+ entry on the file system; otherwise returns \c false.
- Note that the result of comparing two empty QFileInfo objects,
- containing no file references (file paths that do not exist or
- are empty), is undefined.
+ Note that the result of comparing two empty QFileInfo objects, containing
+ no file system entry references (paths that do not exist or are empty),
+ is undefined.
- \warning This will not compare two different symbolic links
- pointing to the same file.
+ \warning This will not compare two different symbolic links pointing to
+ the same target.
- \warning Long and short file names that refer to the same file on Windows
- are treated as if they referred to different files.
+ \warning On Windows, long and short paths that refer to the same file
+ system entry are treated as if they referred to different entries.
\sa operator!=()
*/
-bool QFileInfo::operator==(const QFileInfo &fileinfo) const
+bool comparesEqual(const QFileInfo &lhs, const QFileInfo &rhs)
{
- Q_D(const QFileInfo);
- // ### Qt 5: understand long and short file names on Windows
- // ### (GetFullPathName()).
- if (fileinfo.d_ptr == d_ptr)
+ if (rhs.d_ptr == lhs.d_ptr)
return true;
- if (d->isDefaultConstructed || fileinfo.d_ptr->isDefaultConstructed)
+ if (lhs.d_ptr->isDefaultConstructed || rhs.d_ptr->isDefaultConstructed)
return false;
// Assume files are the same if path is the same
- if (d->fileEntry.filePath() == fileinfo.d_ptr->fileEntry.filePath())
+ if (lhs.d_ptr->fileEntry.filePath() == rhs.d_ptr->fileEntry.filePath())
return true;
Qt::CaseSensitivity sensitive;
- if (d->fileEngine == nullptr || fileinfo.d_ptr->fileEngine == nullptr) {
- if (d->fileEngine != fileinfo.d_ptr->fileEngine) // one is native, the other is a custom file-engine
+ if (lhs.d_ptr->fileEngine == nullptr || rhs.d_ptr->fileEngine == nullptr) {
+ if (lhs.d_ptr->fileEngine != rhs.d_ptr->fileEngine) // one is native, the other is a custom file-engine
return false;
sensitive = QFileSystemEngine::isCaseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
} else {
- if (d->fileEngine->caseSensitive() != fileinfo.d_ptr->fileEngine->caseSensitive())
+ if (lhs.d_ptr->fileEngine->caseSensitive() != rhs.d_ptr->fileEngine->caseSensitive())
return false;
- sensitive = d->fileEngine->caseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ sensitive = lhs.d_ptr->fileEngine->caseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive;
}
// Fallback to expensive canonical path computation
- return canonicalFilePath().compare(fileinfo.canonicalFilePath(), sensitive) == 0;
+ return lhs.canonicalFilePath().compare(rhs.canonicalFilePath(), sensitive) == 0;
}
/*!
@@ -478,24 +492,30 @@ QFileInfo &QFileInfo::operator=(const QFileInfo &fileinfo)
*/
/*!
- Sets the file that the QFileInfo provides information about to \a
- file.
+ Sets the path of the file system entry that this QFileInfo provides
+ information about to \a path that can be absolute or relative.
+
+//! [absolute-path-unix-windows]
+ On Unix, absolute paths begin with the directory separator \c {'/'}.
+ On Windows, absolute paths begin with a drive specification (for example,
+ \c {D:/}).
+//! [ absolute-path-unix-windows]
- The \a file can also include an absolute or relative file path.
- Absolute paths begin with the directory separator (e.g. "/" under
- Unix) or a drive specification (under Windows). Relative file
- names begin with a directory name or a file name and specify a
- path relative to the current directory.
+//! [relative-path-note]
+ Relative paths begin with a directory name or a regular file name and
+ specify a file system entry's path relative to the current working
+ directory.
+//! [relative-path-note]
Example:
\snippet code/src_corelib_io_qfileinfo.cpp 2
\sa isRelative(), QDir::setCurrent(), QDir::isRelativePath()
*/
-void QFileInfo::setFile(const QString &file)
+void QFileInfo::setFile(const QString &path)
{
bool caching = d_ptr.constData()->cache_enabled;
- *this = QFileInfo(file);
+ *this = QFileInfo(path);
d_ptr->cache_enabled = caching;
}
@@ -518,27 +538,29 @@ void QFileInfo::setFile(const QFileDevice &file)
/*!
\overload
- Sets the file that the QFileInfo provides information about to \a
- file in directory \a dir.
+ Sets the path of the file system entry that this QFileInfo provides
+ information about to \a path in directory \a dir.
- If \a file includes a relative path, the QFileInfo will also
- have a relative path.
+ \include qfileinfo.cpp preserve-relative-or-absolute
\sa isRelative()
*/
-void QFileInfo::setFile(const QDir &dir, const QString &file)
+void QFileInfo::setFile(const QDir &dir, const QString &path)
{
- setFile(dir.filePath(file));
+ setFile(dir.filePath(path));
}
/*!
- Returns an absolute path including the file name.
+ Returns the absolute full path to the file system entry this QFileInfo
+ refers to, including the entry's name.
+
+ \include qfileinfo.cpp absolute-path-unix-windows
+
+//! [windows-network-shares]
+ On Windows, the paths of network shares that are not mapped to a drive
+ letter begin with \c{//sharename/}.
+//! [windows-network-shares]
- The absolute path name consists of the full path and the file
- name. On Unix this will always begin with the root, '/',
- directory. On Windows this will always begin 'D:/' where D is a
- drive letter, except for network shares that are not mapped to a
- drive letter, in which case the path will begin '//sharename/'.
QFileInfo will uppercase drive letters. Note that QDir does not do
this. The code snippet below shows this.
@@ -562,10 +584,11 @@ QString QFileInfo::absoluteFilePath() const
}
/*!
- Returns the canonical path including the file name, i.e. an absolute
- path without symbolic links or redundant "." or ".." elements.
+ Returns the file system entry's canonical path, including the entry's
+ name, that is, an absolute path without symbolic links or redundant
+ \c{'.'} or \c{'..'} elements.
- If the file does not exist, canonicalFilePath() returns an empty
+ If the entry does not exist, canonicalFilePath() returns an empty
string.
\sa filePath(), absoluteFilePath(), dir()
@@ -580,13 +603,12 @@ QString QFileInfo::canonicalFilePath() const
/*!
- Returns a file's path absolute path. This doesn't include the
- file name.
+ Returns the absolute path of the file system entry this QFileInfo refers to,
+ excluding the entry's name.
+
+ \include qfileinfo.cpp absolute-path-unix-windows
- On Unix the absolute path will always begin with the root, '/',
- directory. On Windows this will always begin 'D:/' where D is a
- drive letter, except for network shares that are not mapped to a
- drive letter, in which case the path will begin '//sharename/'.
+ \include qfileinfo.cpp windows-network-shares
In contrast to canonicalPath() symbolic links or redundant "." or
".." elements are not necessarily removed.
@@ -606,10 +628,10 @@ QString QFileInfo::absolutePath() const
}
/*!
- Returns the file's path canonical path (excluding the file name),
+ Returns the file system entry's canonical path (excluding the entry's name),
i.e. an absolute path without symbolic links or redundant "." or ".." elements.
- If the file does not exist, canonicalPath() returns an empty string.
+ If the entry does not exist, this method returns an empty string.
\sa path(), absolutePath()
*/
@@ -622,11 +644,11 @@ QString QFileInfo::canonicalPath() const
}
/*!
- Returns the file's path. This doesn't include the file name.
+ Returns the path of the file system entry this QFileInfo refers to,
+ excluding the entry's name.
- Note that, if this QFileInfo object is given a path ending in a
- slash, the name of the file is considered empty and this function
- will return the entire path.
+ \include qfileinfo.cpp path-ends-with-slash-empty-name-component
+ In this case, this function will return the entire path.
\sa filePath(), absolutePath(), canonicalPath(), dir(), fileName(), isRelative()
*/
@@ -641,22 +663,21 @@ QString QFileInfo::path() const
/*!
\fn bool QFileInfo::isAbsolute() const
- Returns \c true if the file path is absolute, otherwise returns \c false (i.e.
- the path is relative).
+ Returns \c true if the file system entry's path is absolute, otherwise
+ returns \c false (that is, the path is relative).
- \note Paths starting with a colon (\e{:}) are always considered absolute, as
- they denote a QResource.
+ \include qfileinfo.cpp qresource-virtual-fs-colon
\sa isRelative()
*/
/*!
- Returns \c true if the file path is relative, otherwise returns \c
- false (i.e. the path is absolute). (E.g. under Unix a path is absolute
- if it begins with a "/").
+ Returns \c true if the file system entry's path is relative, otherwise
+ returns \c false (that is, the path is absolute).
+
+ \include qfileinfo.cpp absolute-path-unix-windows
- \note Paths starting with a colon (\e{:}) are always considered absolute,
- as they denote a QResource.
+ \include qfileinfo.cpp qresource-virtual-fs-colon
\sa isAbsolute()
*/
@@ -671,9 +692,9 @@ bool QFileInfo::isRelative() const
}
/*!
- Converts the file's path to an absolute path if it is not already in that form.
- Returns \c true to indicate that the path was converted; otherwise returns \c false
- to indicate that the path was already absolute.
+ If the file system entry's path is relative, this method converts it to
+ an absolute path and returns \c true; if the path is already absolute,
+ this method returns \c false.
\sa filePath(), isRelative()
*/
@@ -688,10 +709,11 @@ bool QFileInfo::makeAbsolute()
}
/*!
- Returns \c true if the file exists; otherwise returns \c false.
+ Returns \c true if the file system entry this QFileInfo refers to exists;
+ otherwise returns \c false.
- \note If the file is a symlink that points to a non-existing
- file, false is returned.
+ \note If the entry is a symlink that points to a non-existing
+ target, this method returns \c false.
*/
bool QFileInfo::exists() const
{
@@ -709,24 +731,23 @@ bool QFileInfo::exists() const
/*!
\since 5.2
- Returns \c true if the \a file exists; otherwise returns \c false.
+ Returns \c true if the file system entry \a path exists; otherwise
+ returns \c false.
- \note If \a file is a symlink that points to a non-existing
- file, false is returned.
+ \note If \a path is a symlink that points to a non-existing
+ target, this method returns \c false.
\note Using this function is faster than using
- \c QFileInfo(file).exists() for file system access.
+ \c QFileInfo(path).exists() for file system access.
*/
-bool QFileInfo::exists(const QString &file)
+bool QFileInfo::exists(const QString &path)
{
- if (file.isEmpty())
+ if (path.isEmpty())
return false;
- QFileSystemEntry entry(file);
+ QFileSystemEntry entry(path);
QFileSystemMetaData data;
- std::unique_ptr<QAbstractFileEngine> engine
- {QFileSystemEngine::resolveEntryAndCreateLegacyEngine(entry, data)};
// Expensive fallback to non-QFileSystemEngine implementation
- if (engine)
+ if (auto engine = QFileSystemEngine::createLegacyEngine(entry, data))
return QFileInfo(new QFileInfoPrivate(entry, data, std::move(engine))).exists();
QFileSystemEngine::fillMetaData(entry, data, QFileSystemMetaData::ExistsAttribute);
@@ -734,8 +755,9 @@ bool QFileInfo::exists(const QString &file)
}
/*!
- Refreshes the information about the file, i.e. reads in information
- from the file system the next time a cached property is fetched.
+ Refreshes the information about the file system entry this QFileInfo
+ refers to, that is, reads in information from the file system the next
+ time a cached property is fetched.
*/
void QFileInfo::refresh()
{
@@ -744,8 +766,8 @@ void QFileInfo::refresh()
}
/*!
- Returns the file name, including the path (which may be absolute
- or relative).
+ Returns the path of the file system entry this QFileInfo refers to;
+ the path may be absolute or relative.
\sa absoluteFilePath(), canonicalFilePath(), isRelative()
*/
@@ -758,13 +780,16 @@ QString QFileInfo::filePath() const
}
/*!
- Returns the name of the file, excluding the path.
+ Returns the name of the file system entry this QFileInfo refers to,
+ excluding the path.
Example:
\snippet code/src_corelib_io_qfileinfo.cpp 3
- Note that, if this QFileInfo object is given a path ending in a
- slash, the name of the file is considered empty.
+//! [path-ends-with-slash-empty-name-component]
+ \note If this QFileInfo is given a path ending with a directory separator
+ \c{'/'}, the entry's name part is considered empty.
+//! [path-ends-with-slash-empty-name-component]
\sa isRelative(), filePath(), baseName(), suffix()
*/
@@ -890,9 +915,10 @@ QString QFileInfo::suffix() const
/*!
- Returns the path of the object's parent directory as a QDir object.
+ Returns a QDir object representing the path of the parent directory of the
+ file system entry that this QFileInfo refers to.
- \b{Note:} The QDir returned always corresponds to the object's
+ \note The QDir returned always corresponds to the object's
parent directory, even if the QFileInfo represents a directory.
For each of the following, dir() returns the QDir
@@ -914,7 +940,10 @@ QDir QFileInfo::dir() const
}
/*!
- Returns the file's absolute path as a QDir object.
+ Returns a QDir object representing the absolute path of the parent
+ directory of the file system entry that this QFileInfo refers to.
+
+ \snippet code/src_corelib_io_qfileinfo.cpp 11
\sa dir(), filePath(), fileName(), isRelative()
*/
@@ -924,13 +953,13 @@ QDir QFileInfo::absoluteDir() const
}
/*!
- Returns \c true if the user can read the file; otherwise returns \c false.
+ Returns \c true if the user can read the file system entry this QFileInfo
+ refers to; otherwise returns \c false.
- If the file is a symlink, this function returns true if the target is
- readable (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\note If the \l{NTFS permissions} check has not been enabled, the result
- on Windows will merely reflect whether the file exists.
+ on Windows will merely reflect whether the entry exists.
\sa isWritable(), isExecutable(), permission()
*/
@@ -939,18 +968,18 @@ bool QFileInfo::isReadable() const
Q_D(const QFileInfo);
return d->checkAttribute<bool>(
QFileSystemMetaData::UserReadPermission,
- [d]() { return (d->metaData.permissions() & QFile::ReadUser) != 0; },
+ [d]() { return d->metaData.isReadable(); },
[d]() { return d->getFileFlags(QAbstractFileEngine::ReadUserPerm); });
}
/*!
- Returns \c true if the user can write to the file; otherwise returns \c false.
+ Returns \c true if the user can write to the file system entry this
+ QFileInfo refers to; otherwise returns \c false.
- If the file is a symlink, this function returns true if the target is
- writeable (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\note If the \l{NTFS permissions} check has not been enabled, the result on
- Windows will merely reflect whether the file is marked as Read Only.
+ Windows will merely reflect whether the entry is marked as Read Only.
\sa isReadable(), isExecutable(), permission()
*/
@@ -959,15 +988,18 @@ bool QFileInfo::isWritable() const
Q_D(const QFileInfo);
return d->checkAttribute<bool>(
QFileSystemMetaData::UserWritePermission,
- [d]() { return (d->metaData.permissions() & QFile::WriteUser) != 0; },
+ [d]() { return d->metaData.isWritable(); },
[d]() { return d->getFileFlags(QAbstractFileEngine::WriteUserPerm); });
}
/*!
- Returns \c true if the file is executable; otherwise returns \c false.
+ Returns \c true if the file system entry this QFileInfo refers to is
+ executable; otherwise returns \c false.
- If the file is a symlink, this function returns true if the target is
- executable (not the symlink).
+//! [info-about-target-not-symlink]
+ If the file is a symlink, this function returns information about the
+ target, not the symlink.
+//! [info-about-target-not-symlink]
\sa isReadable(), isWritable(), permission()
*/
@@ -976,15 +1008,16 @@ bool QFileInfo::isExecutable() const
Q_D(const QFileInfo);
return d->checkAttribute<bool>(
QFileSystemMetaData::UserExecutePermission,
- [d]() { return (d->metaData.permissions() & QFile::ExeUser) != 0; },
+ [d]() { return d->metaData.isExecutable(); },
[d]() { return d->getFileFlags(QAbstractFileEngine::ExeUserPerm); });
}
/*!
- Returns \c true if this is a `hidden' file; otherwise returns \c false.
+ Returns \c true if the file system entry this QFileInfo refers to is
+ `hidden'; otherwise returns \c false.
\b{Note:} This function returns \c true for the special entries "." and
- ".." on Unix, even though QDir::entryList threats them as shown. And note
+ ".." on Unix, even though QDir::entryList treats them as shown. And note
that, since this function inspects the file name, on Unix it will inspect
the name of the symlink, if this file is a symlink, not the target's name.
@@ -1029,8 +1062,7 @@ bool QFileInfo::isNativePath() const
object points to something that is not a file (such as a directory)
or that does not exist.
- If the file is a symlink, this function returns true if the target is a
- regular file (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\sa isDir(), isSymLink(), isBundle()
*/
@@ -1049,8 +1081,7 @@ bool QFileInfo::isFile() const
object points to something that is not a directory (such as a file)
or that does not exist.
- If the file is a symlink, this function returns true if the target is a
- directory (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\sa isFile(), isSymLink(), isBundle()
*/
@@ -1069,8 +1100,7 @@ bool QFileInfo::isDir() const
Returns \c true if this object points to a bundle or to a symbolic
link to a bundle on \macos and iOS; otherwise returns \c false.
- If the file is a symlink, this function returns true if the target is a
- bundle (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\sa isDir(), isSymLink(), isFile()
*/
@@ -1101,8 +1131,10 @@ bool QFileInfo::isBundle() const
\snippet code/src_corelib_io_qfileinfo.cpp 9
- \note If the symlink points to a non existing file, exists() returns
- false.
+//! [symlink-target-exists-behavior]
+ \note exists() returns \c true if the symlink points to an existing
+ target, otherwise it returns \c false.
+//! [symlink-target-exists-behavior]
\sa isFile(), isDir(), symLinkTarget()
*/
@@ -1130,8 +1162,7 @@ bool QFileInfo::isSymLink() const
(\c *.lnk files) on Windows and aliases on \macos. Use QFileInfo::isShortcut()
and QFileInfo::isAlias() instead.
- \note If the symlink points to a non existing file, exists() returns
- false.
+ \include qfileinfo.cpp symlink-target-exists-behavior
\sa isFile(), isDir(), isShortcut(), symLinkTarget()
*/
@@ -1250,8 +1281,8 @@ bool QFileInfo::isRoot() const
link.
This name may not represent an existing file; it is only a string.
- QFileInfo::exists() returns \c true if the symlink points to an
- existing file.
+
+ \include qfileinfo.cpp symlink-target-exists-behavior
\sa exists(), isSymLink(), isDir(), isFile()
*/
@@ -1313,8 +1344,7 @@ QString QFileInfo::junctionTarget() const
milliseconds). On Windows, it will return an empty string unless
the \l{NTFS permissions} check has been enabled.
- If the file is a symlink, this function returns the owner of the target
- (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\sa ownerId(), group(), groupId()
*/
@@ -1332,8 +1362,7 @@ QString QFileInfo::owner() const
On Windows and on systems where files do not have owners this
function returns ((uint) -2).
- If the file is a symlink, this function returns the id of the owner of the target
- (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\sa owner(), group(), groupId()
*/
@@ -1354,8 +1383,7 @@ uint QFileInfo::ownerId() const
This function can be time consuming under Unix (in the order of
milliseconds).
- If the file is a symlink, this function returns the owning group of the
- target (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\sa groupId(), owner(), ownerId()
*/
@@ -1373,8 +1401,7 @@ QString QFileInfo::group() const
On Windows and on systems where files do not have groups this
function always returns (uint) -2.
- If the file is a symlink, this function returns the id of the group owning the
- target (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\sa group(), owner(), ownerId()
*/
@@ -1401,8 +1428,7 @@ uint QFileInfo::groupId() const
Example:
\snippet code/src_corelib_io_qfileinfo.cpp 10
- If the file is a symlink, this function checks the permissions of the
- target (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\sa isReadable(), isWritable(), isExecutable()
*/
@@ -1427,8 +1453,7 @@ bool QFileInfo::permission(QFile::Permissions permissions) const
\note The result might be inaccurate on Windows if the
\l{NTFS permissions} check has not been enabled.
- If the file is a symlink, this function returns the permissions of the
- target (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
*/
QFile::Permissions QFileInfo::permissions() const
{
@@ -1446,8 +1471,7 @@ QFile::Permissions QFileInfo::permissions() const
Returns the file size in bytes. If the file does not exist or cannot be
fetched, 0 is returned.
- If the file is a symlink, the size of the target file is returned
- (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\sa exists()
*/
@@ -1473,7 +1497,7 @@ qint64 QFileInfo::size() const
If the file birth time is not available, this function returns an invalid QDateTime.
- If the file is a symlink, the time of the target file is returned (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
This function overloads QFileInfo::birthTime(const QTimeZone &tz), and
returns the same as \c{birthTime(QTimeZone::LocalTime)}.
@@ -1492,11 +1516,12 @@ qint64 QFileInfo::size() const
If the file birth time is not available, this function returns an invalid
QDateTime.
- If the file is a symlink, the time of the target file is returned
- (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\since 6.6
- \sa lastModified(const QTimeZone &), lastRead(const QTimeZone &), metadataChangeTime(const QTimeZone &), fileTime(QFile::FileTime, const QTimeZone &)
+ \sa lastModified(const QTimeZone &), lastRead(const QTimeZone &),
+ metadataChangeTime(const QTimeZone &),
+ fileTime(QFileDevice::FileTime, const QTimeZone &)
*/
/*!
@@ -1509,8 +1534,7 @@ qint64 QFileInfo::size() const
occurs whenever the user writes or sets inode information (for example,
changing the file permissions).
- If the file is a symlink, the time of the target file is returned
- (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
This function overloads QFileInfo::metadataChangeTime(const QTimeZone &tz),
and returns the same as \c{metadataChangeTime(QTimeZone::LocalTime)}.
@@ -1529,11 +1553,12 @@ qint64 QFileInfo::size() const
\include qfileinfo.cpp file-times-in-time-zone
- If the file is a symlink, the time of the target file is returned
- (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\since 6.6
- \sa birthTime(const QTimeZone &), lastModified(const QTimeZone &), lastRead(const QTimeZone &), metadataChangeTime(const QTimeZone &), fileTime(QFile::FileTime time, const QTimeZone &)
+ \sa birthTime(const QTimeZone &), lastModified(const QTimeZone &),
+ lastRead(const QTimeZone &),
+ fileTime(QFileDevice::FileTime time, const QTimeZone &)
*/
/*!
@@ -1541,8 +1566,7 @@ qint64 QFileInfo::size() const
Returns the date and time when the file was last modified.
- If the file is a symlink, the time of the target file is returned
- (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
This function overloads \l{QFileInfo::lastModified(const QTimeZone &)},
and returns the same as \c{lastModified(QTimeZone::LocalTime)}.
@@ -1557,11 +1581,12 @@ qint64 QFileInfo::size() const
\include qfileinfo.cpp file-times-in-time-zone
- If the file is a symlink, the time of the target file is returned
- (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\since 6.6
- \sa birthTime(const QTimeZone &), lastRead(const QTimeZone &), metadataChangeTime(const QTimeZone &), fileTime(QFile::FileTime, const QTimeZone &)
+ \sa birthTime(const QTimeZone &), lastRead(const QTimeZone &),
+ metadataChangeTime(const QTimeZone &),
+ fileTime(QFileDevice::FileTime, const QTimeZone &)
*/
/*!
@@ -1572,8 +1597,7 @@ qint64 QFileInfo::size() const
On platforms where this information is not available, returns the same
time as lastModified().
- If the file is a symlink, the time of the target file is returned
- (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
This function overloads \l{QFileInfo::lastRead(const QTimeZone &)},
and returns the same as \c{lastRead(QTimeZone::LocalTime)}.
@@ -1591,11 +1615,12 @@ qint64 QFileInfo::size() const
On platforms where this information is not available, returns the same
time as lastModified().
- If the file is a symlink, the time of the target file is returned
- (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\since 6.6
- \sa birthTime(const QTimeZone &), lastModified(const QTimeZone &), metadataChangeTime(const QTimeZone &), fileTime(QFile::FileTime, const QTimeZone &)
+ \sa birthTime(const QTimeZone &), lastModified(const QTimeZone &),
+ metadataChangeTime(const QTimeZone &),
+ fileTime(QFileDevice::FileTime, const QTimeZone &)
*/
#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
@@ -1604,11 +1629,10 @@ qint64 QFileInfo::size() const
If the time cannot be determined, an invalid date time is returned.
- If the file is a symlink, the time of the target file is returned
- (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
This function overloads
- \l{QFileInfo::fileTime(QFile::FileTime, const QTimeZone &)},
+ \l{QFileInfo::fileTime(QFileDevice::FileTime, const QTimeZone &)},
and returns the same as \c{fileTime(time, QTimeZone::LocalTime)}.
\since 5.10
@@ -1632,21 +1656,16 @@ QDateTime QFileInfo::fileTime(QFile::FileTime time) const {
If the time cannot be determined, an invalid date time is returned.
- If the file is a symlink, the time of the target file is returned
- (not the symlink).
+ \include qfileinfo.cpp info-about-target-not-symlink
\since 6.6
- \sa birthTime(const QTimeZone &), lastModified(const QTimeZone &), lastRead(const QTimeZone &), metadataChangeTime(const QTimeZone &), QDateTime::isValid()
+ \sa birthTime(const QTimeZone &), lastModified(const QTimeZone &),
+ lastRead(const QTimeZone &), metadataChangeTime(const QTimeZone &),
+ QDateTime::isValid()
*/
QDateTime QFileInfo::fileTime(QFile::FileTime time, const QTimeZone &tz) const
{
- static_assert(int(QFile::FileAccessTime) == int(QAbstractFileEngine::AccessTime));
- static_assert(int(QFile::FileBirthTime) == int(QAbstractFileEngine::BirthTime));
- static_assert(int(QFile::FileMetadataChangeTime) == int(QAbstractFileEngine::MetadataChangeTime));
- static_assert(int(QFile::FileModificationTime) == int(QAbstractFileEngine::ModificationTime));
-
Q_D(const QFileInfo);
- auto fetime = QAbstractFileEngine::FileTime(time);
QFileSystemMetaData::MetaDataFlags flag;
switch (time) {
case QFile::FileAccessTime:
@@ -1663,9 +1682,10 @@ QDateTime QFileInfo::fileTime(QFile::FileTime time, const QTimeZone &tz) const
break;
}
- auto fsLambda = [d, fetime]() { return d->metaData.fileTime(fetime); };
- auto engineLambda = [d, fetime]() { return d->getFileTime(fetime); };
- const QDateTime dt = d->checkAttribute<QDateTime>(flag, fsLambda, engineLambda);
+ auto fsLambda = [d, time]() { return d->metaData.fileTime(time); };
+ auto engineLambda = [d, time]() { return d->getFileTime(time); };
+ const auto dt =
+ d->checkAttribute<QDateTime>(flag, std::move(fsLambda), std::move(engineLambda));
return dt.toTimeZone(tz);
}
@@ -1750,24 +1770,22 @@ QDebug operator<<(QDebug dbg, const QFileInfo &fi)
\sa setFile(), isRelative(), QDir::setCurrent(), QDir::isRelativePath()
*/
/*!
- \fn QFileInfo::QFileInfo(const QDir &dir, const std::filesystem::path &file)
+ \fn QFileInfo::QFileInfo(const QDir &dir, const std::filesystem::path &path)
\since 6.0
- Constructs a new QFileInfo that gives information about the given
- \a file relative to the directory \a dir.
+ Constructs a new QFileInfo that gives information about the file system
+ entry at \a path that is relative to the directory \a dir.
- If \a dir has a relative path, the QFileInfo will also have a
- relative path.
-
- If \a file is an absolute path, then the directory specified
- by \a dir will be disregarded.
+ \include qfileinfo.cpp preserve-relative-or-absolute
*/
/*!
- \fn void QFileInfo::setFile(const std::filesystem::path &file)
+ \fn void QFileInfo::setFile(const std::filesystem::path &path)
\since 6.0
- Sets the file that the QFileInfo provides information about to \a
- file.
+ Sets the path of file system entry that this QFileInfo provides
+ information about to \a path.
+
+ \include qfileinfo.cpp preserve-relative-path
*/
/*!
\fn std::filesystem::path QFileInfo::filesystemFilePath() const
@@ -1819,6 +1837,13 @@ QDebug operator<<(QDebug dbg, const QFileInfo &fi)
\sa symLinkTarget()
*/
/*!
+ \fn std::filesystem::path QFileInfo::filesystemReadSymLink() const
+ \since 6.6
+
+ Returns readSymLink() as a \c{std::filesystem::path}.
+ \sa readSymLink()
+*/
+/*!
\fn std::filesystem::path QFileInfo::filesystemJunctionTarget() const
\since 6.2
diff --git a/src/corelib/io/qfileinfo.h b/src/corelib/io/qfileinfo.h
index 435fba5497..72c8519446 100644
--- a/src/corelib/io/qfileinfo.h
+++ b/src/corelib/io/qfileinfo.h
@@ -4,6 +4,7 @@
#ifndef QFILEINFO_H
#define QFILEINFO_H
+#include <QtCore/qcompare.h>
#include <QtCore/qfile.h>
#include <QtCore/qlist.h>
#include <QtCore/qshareddata.h>
@@ -21,6 +22,7 @@ class QFileInfoPrivate;
class Q_CORE_EXPORT QFileInfo
{
friend class QDirIteratorPrivate;
+ friend class QDirListingPrivate;
public:
explicit QFileInfo(QFileInfoPrivate *d);
@@ -58,8 +60,10 @@ public:
void swap(QFileInfo &other) noexcept
{ d_ptr.swap(other.d_ptr); }
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QFileInfo &fileinfo) const;
inline bool operator!=(const QFileInfo &fileinfo) const { return !(operator==(fileinfo)); }
+#endif
void setFile(const QString &file);
void setFile(const QFileDevice &file);
@@ -151,7 +155,6 @@ public:
qint64 size() const;
-#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
QDateTime birthTime() const { return fileTime(QFile::FileBirthTime); }
QDateTime metadataChangeTime() const { return fileTime(QFile::FileMetadataChangeTime); }
QDateTime lastModified() const { return fileTime(QFile::FileModificationTime); }
@@ -163,25 +166,6 @@ public:
QDateTime lastModified(const QTimeZone &tz) const { return fileTime(QFile::FileModificationTime, tz); }
QDateTime lastRead(const QTimeZone &tz) const { return fileTime(QFile::FileAccessTime, tz); }
QDateTime fileTime(QFile::FileTime time, const QTimeZone &tz) const;
-#else
- QDateTime birthTime(const QTimeZone &tz = QTimeZone::LocalTime) const
- {
- return fileTime(QFile::FileBirthTime, tz);
- }
- QDateTime metadataChangeTime(const QTimeZone &tz = QTimeZone::LocalTime) const
- {
- return fileTime(QFile::FileMetadataChangeTime, tz);
- }
- QDateTime lastModified(const QTimeZone &tz = QTimeZone::LocalTime) const
- {
- return fileTime(QFile::FileModificationTime, tz);
- }
- QDateTime lastRead(const QTimeZone &tz = QTimeZone::LocalTime) const
- {
- return fileTime(QFile::FileAccessTime, tz);
- }
- QDateTime fileTime(QFile::FileTime time, const QTimeZone &tz = QTimeZone::LocalTime) const;
-#endif
bool caching() const;
void setCaching(bool on);
@@ -191,6 +175,8 @@ protected:
QSharedDataPointer<QFileInfoPrivate> d_ptr;
private:
+ friend Q_CORE_EXPORT bool comparesEqual(const QFileInfo &lhs, const QFileInfo &rhs);
+ Q_DECLARE_EQUALITY_COMPARABLE(QFileInfo)
QFileInfoPrivate* d_func();
inline const QFileInfoPrivate* d_func() const
{
diff --git a/src/corelib/io/qfileinfo_p.h b/src/corelib/io/qfileinfo_p.h
index 4da7c60792..4091a7464a 100644
--- a/src/corelib/io/qfileinfo_p.h
+++ b/src/corelib/io/qfileinfo_p.h
@@ -55,7 +55,7 @@ public:
: QSharedData(copy),
fileEntry(copy.fileEntry),
metaData(copy.metaData),
- fileEngine(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(fileEntry, metaData)),
+ fileEngine(QFileSystemEngine::createLegacyEngine(fileEntry, metaData)),
cachedFlags(0),
#ifndef QT_NO_FSFILEENGINE
isDefaultConstructed(false),
@@ -66,7 +66,7 @@ public:
{}
inline QFileInfoPrivate(const QString &file)
: fileEntry(file),
- fileEngine(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(fileEntry, metaData)),
+ fileEngine(QFileSystemEngine::createLegacyEngine(fileEntry, metaData)),
cachedFlags(0),
#ifndef QT_NO_FSFILEENGINE
isDefaultConstructed(file.isEmpty()),
@@ -81,7 +81,7 @@ public:
: QSharedData(),
fileEntry(file),
metaData(data),
- fileEngine(QFileSystemEngine::resolveEntryAndCreateLegacyEngine(fileEntry, metaData)),
+ fileEngine(QFileSystemEngine::createLegacyEngine(fileEntry, metaData)),
cachedFlags(0),
isDefaultConstructed(false),
cache_enabled(true), fileFlags(0), fileSize(0)
@@ -122,7 +122,7 @@ public:
}
uint getFileFlags(QAbstractFileEngine::FileFlags) const;
- QDateTime &getFileTime(QAbstractFileEngine::FileTime) const;
+ QDateTime &getFileTime(QFile::FileTime) const;
QString getFileName(QAbstractFileEngine::FileName) const;
QString getFileOwner(QAbstractFileEngine::FileOwner own) const;
@@ -133,7 +133,7 @@ public:
mutable QString fileNames[QAbstractFileEngine::NFileNames];
mutable QString fileOwners[2]; // QAbstractFileEngine::FileOwner: OwnerUser and OwnerGroup
- mutable QDateTime fileTimes[4]; // QAbstractFileEngine::FileTime: BirthTime, MetadataChangeTime, ModificationTime, AccessTime
+ mutable QDateTime fileTimes[4]; // QFile::FileTime: FileBirthTime, FileMetadataChangeTime, FileModificationTime, FileAccessTime
mutable uint cachedFlags : 30;
bool const isDefaultConstructed : 1; // QFileInfo is a default constructed instance
@@ -146,8 +146,8 @@ public:
{ if (cache_enabled) cachedFlags |= c; }
template <typename Ret, typename FSLambda, typename EngineLambda>
- Ret checkAttribute(Ret defaultValue, QFileSystemMetaData::MetaDataFlags fsFlags, const FSLambda &fsLambda,
- const EngineLambda &engineLambda) const
+ Ret checkAttribute(Ret defaultValue, QFileSystemMetaData::MetaDataFlags fsFlags,
+ FSLambda fsLambda, EngineLambda engineLambda) const
{
if (isDefaultConstructed)
return defaultValue;
@@ -161,10 +161,10 @@ public:
}
template <typename Ret, typename FSLambda, typename EngineLambda>
- Ret checkAttribute(QFileSystemMetaData::MetaDataFlags fsFlags, const FSLambda &fsLambda,
- const EngineLambda &engineLambda) const
+ Ret checkAttribute(QFileSystemMetaData::MetaDataFlags fsFlags, FSLambda fsLambda,
+ EngineLambda engineLambda) const
{
- return checkAttribute(Ret(), fsFlags, fsLambda, engineLambda);
+ return checkAttribute(Ret(), std::move(fsFlags), std::move(fsLambda), engineLambda);
}
};
diff --git a/src/corelib/io/qfilesystemengine.cpp b/src/corelib/io/qfilesystemengine.cpp
index bedace4c79..d8b215816c 100644
--- a/src/corelib/io/qfilesystemengine.cpp
+++ b/src/corelib/io/qfilesystemengine.cpp
@@ -83,12 +83,11 @@ static inline bool _q_checkEntry(QFileSystemEntry &entry, QFileSystemMetaData &d
return true;
}
-static inline bool _q_checkEntry(QAbstractFileEngine *&engine, bool resolvingEntry)
+static inline bool _q_checkEntry(std::unique_ptr<QAbstractFileEngine> &engine, bool resolvingEntry)
{
if (resolvingEntry) {
if (!(engine->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::ExistsFlag)) {
- delete engine;
- engine = nullptr;
+ engine.reset();
return false;
}
}
@@ -96,8 +95,9 @@ static inline bool _q_checkEntry(QAbstractFileEngine *&engine, bool resolvingEnt
return true;
}
-static bool _q_resolveEntryAndCreateLegacyEngine_recursive(QFileSystemEntry &entry, QFileSystemMetaData &data,
- QAbstractFileEngine *&engine, bool resolvingEntry = false)
+static bool _q_createLegacyEngine_recursive(QFileSystemEntry &entry, QFileSystemMetaData &data,
+ std::unique_ptr<QAbstractFileEngine> &engine,
+ bool resolvingEntry = false)
{
QString const &filePath = entry.filePath();
if ((engine = qt_custom_file_engine_handler_create(filePath)))
@@ -111,7 +111,7 @@ static bool _q_resolveEntryAndCreateLegacyEngine_recursive(QFileSystemEntry &ent
if (ch == u':') {
if (prefixSeparator == 0) {
- engine = new QResourceFileEngine(filePath);
+ engine = std::make_unique<QResourceFileEngine>(filePath);
return _q_checkEntry(engine, resolvingEntry);
}
@@ -123,7 +123,7 @@ static bool _q_resolveEntryAndCreateLegacyEngine_recursive(QFileSystemEntry &ent
entry = QFileSystemEntry(QDir::cleanPath(
paths.at(i) % u'/' % QStringView{filePath}.mid(prefixSeparator + 1)));
// Recurse!
- if (_q_resolveEntryAndCreateLegacyEngine_recursive(entry, data, engine, true))
+ if (_q_createLegacyEngine_recursive(entry, data, engine, true))
return true;
}
@@ -153,12 +153,13 @@ static bool _q_resolveEntryAndCreateLegacyEngine_recursive(QFileSystemEntry &ent
QFileSystemEngine API should be used to query and interact with the file
system object.
*/
-QAbstractFileEngine *QFileSystemEngine::resolveEntryAndCreateLegacyEngine(
- QFileSystemEntry &entry, QFileSystemMetaData &data) {
+std::unique_ptr<QAbstractFileEngine>
+QFileSystemEngine::createLegacyEngine(QFileSystemEntry &entry, QFileSystemMetaData &data)
+{
QFileSystemEntry copy = entry;
- QAbstractFileEngine *engine = nullptr;
+ std::unique_ptr<QAbstractFileEngine> engine;
- if (_q_resolveEntryAndCreateLegacyEngine_recursive(copy, data, engine))
+ if (_q_createLegacyEngine_recursive(copy, data, engine))
// Reset entry to resolved copy.
entry = copy;
else
diff --git a/src/corelib/io/qfilesystemengine_p.h b/src/corelib/io/qfilesystemengine_p.h
index c1dddb2e1e..814915407e 100644
--- a/src/corelib/io/qfilesystemengine_p.h
+++ b/src/corelib/io/qfilesystemengine_p.h
@@ -20,6 +20,7 @@
#include "qfilesystemmetadata_p.h"
#include <QtCore/private/qsystemerror_p.h>
+#include <memory>
#include <optional>
QT_BEGIN_NAMESPACE
@@ -94,7 +95,7 @@ public:
static bool fillMetaData(int fd, QFileSystemMetaData &data); // what = PosixStatFlags
static QByteArray id(int fd);
static bool setFileTime(int fd, const QDateTime &newDate,
- QAbstractFileEngine::FileTime whatTime, QSystemError &error);
+ QFile::FileTime whatTime, QSystemError &error);
static bool setPermissions(int fd, QFile::Permissions permissions, QSystemError &error,
QFileSystemMetaData *data = nullptr);
#endif
@@ -109,7 +110,7 @@ public:
QFileSystemMetaData::MetaDataFlags what);
static QByteArray id(HANDLE fHandle);
static bool setFileTime(HANDLE fHandle, const QDateTime &newDate,
- QAbstractFileEngine::FileTime whatTime, QSystemError &error);
+ QFile::FileTime whatTime, QSystemError &error);
static QString owner(const QFileSystemEntry &entry, QAbstractFileEngine::FileOwner own);
static QString nativeAbsoluteFilePath(const QString &path);
static bool isDirPath(const QString &path, bool *existed);
@@ -136,13 +137,14 @@ public:
// unused, therefore not implemented
static bool setFileTime(const QFileSystemEntry &entry, const QDateTime &newDate,
- QAbstractFileEngine::FileTime whatTime, QSystemError &error);
+ QFile::FileTime whatTime, QSystemError &error);
static bool setCurrentPath(const QFileSystemEntry &entry);
static QFileSystemEntry currentPath();
- static QAbstractFileEngine *resolveEntryAndCreateLegacyEngine(QFileSystemEntry &entry,
- QFileSystemMetaData &data);
+ static std::unique_ptr<QAbstractFileEngine>
+ createLegacyEngine(QFileSystemEntry &entry, QFileSystemMetaData &data);
+
private:
static QString slowCanonicalized(const QString &path);
#if defined(Q_OS_WIN)
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
index d94cd452cf..bda2962f8d 100644
--- a/src/corelib/io/qfilesystemengine_unix.cpp
+++ b/src/corelib/io/qfilesystemengine_unix.cpp
@@ -12,11 +12,14 @@
#include <QtCore/qoperatingsystemversion.h>
#include <QtCore/private/qcore_unix_p.h>
#include <QtCore/private/qfiledevice_p.h>
+#include <QtCore/private/qfunctions_p.h>
#include <QtCore/qvarlengtharray.h>
#ifndef QT_BOOTSTRAPPED
# include <QtCore/qstandardpaths.h>
+# include <QtCore/private/qtemporaryfile_p.h>
#endif // QT_BOOTSTRAPPED
+#include <grp.h>
#include <pwd.h>
#include <stdlib.h> // for realpath()
#include <unistd.h>
@@ -36,6 +39,11 @@
#if defined(Q_OS_DARWIN)
# include <QtCore/private/qcore_mac_p.h>
# include <CoreFoundation/CFBundle.h>
+# include <UniformTypeIdentifiers/UTType.h>
+# include <UniformTypeIdentifiers/UTCoreTypes.h>
+# include <Foundation/Foundation.h>
+# include <sys/clonefile.h>
+# include <copyfile.h>
#endif
#ifdef Q_OS_MACOS
@@ -46,15 +54,6 @@
#include <MobileCoreServices/MobileCoreServices.h>
#endif
-#if defined(Q_OS_DARWIN)
-# include <sys/clonefile.h>
-# include <copyfile.h>
-// We cannot include <Foundation/Foundation.h> (it's an Objective-C header), but
-// we need these declarations:
-Q_FORWARD_DECLARE_OBJC_CLASS(NSString);
-extern "C" NSString *NSTemporaryDirectory();
-#endif
-
#if defined(Q_OS_LINUX)
# include <sys/ioctl.h>
# include <sys/sendfile.h>
@@ -124,10 +123,9 @@ static bool isPackage(const QFileSystemMetaData &data, const QFileSystemEntry &e
QString suffix = info.suffix();
if (suffix.length() > 0) {
- // First step: is the extension known ?
- QCFType<CFStringRef> extensionRef = suffix.toCFString();
- QCFType<CFStringRef> uniformTypeIdentifier = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, extensionRef, NULL);
- if (UTTypeConformsTo(uniformTypeIdentifier, kUTTypeBundle))
+ // First step: is it a bundle?
+ const auto *utType = [UTType typeWithFilenameExtension:suffix.toNSString()];
+ if ([utType conformsToType:UTTypeBundle])
return true;
// Second step: check if an application knows the package type
@@ -819,7 +817,7 @@ QString QFileSystemEngine::resolveGroupName(uint groupId)
#endif
if (gr)
return QFile::decodeName(QByteArray(gr->gr_name));
-#else // Integrity || WASM
+#else // Integrity || WASM || VxWorks
Q_UNUSED(groupId);
#endif
return QString();
@@ -1122,7 +1120,7 @@ static bool createDirectoryWithParents(const QByteArray &nativeName, mode_t mode
bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool createParents,
std::optional<QFile::Permissions> permissions)
{
- QString dirName = entry.filePath();
+ QByteArray dirName = entry.nativeFilePath();
Q_CHECK_FILE_NAME(dirName, false);
// Darwin doesn't support trailing /'s, so remove for everyone
@@ -1130,14 +1128,13 @@ bool QFileSystemEngine::createDirectory(const QFileSystemEntry &entry, bool crea
dirName.chop(1);
// try to mkdir this directory
- QByteArray nativeName = QFile::encodeName(dirName);
mode_t mode = permissions ? QtPrivate::toMode_t(*permissions) : 0777;
- if (QT_MKDIR(nativeName, mode) == 0)
+ if (QT_MKDIR(dirName, mode) == 0)
return true;
if (!createParents)
return false;
- return createDirectoryWithParents(nativeName, mode, false);
+ return createDirectoryWithParents(dirName, mode, false);
}
//static
@@ -1177,42 +1174,169 @@ bool QFileSystemEngine::createLink(const QFileSystemEntry &source, const QFileSy
return false;
}
-#ifndef Q_OS_DARWIN
+#ifdef Q_OS_DARWIN
+// see qfilesystemengine_mac.mm
+#elif defined(QT_BOOTSTRAPPED) || !defined(AT_FDCWD)
+// bootstrapped tools don't need this, and we don't want QStorageInfo
+//static
+bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &, QFileSystemEntry &,
+ QSystemError &error)
+{
+ error = QSystemError(ENOSYS, QSystemError::StandardLibraryError);
+ return false;
+}
+#else
/*
Implementing as per https://specifications.freedesktop.org/trash-spec/trashspec-1.0.html
*/
-// bootstrapped tools don't need this, and we don't want QStorageInfo
-#ifndef QT_BOOTSTRAPPED
-static QString freeDesktopTrashLocation(const QString &sourcePath)
+namespace {
+struct FreeDesktopTrashOperation
{
- auto makeTrashDir = [](const QDir &topDir, const QString &trashDir) -> QString {
- auto ownerPerms = QFileDevice::ReadOwner
- | QFileDevice::WriteOwner
- | QFileDevice::ExeOwner;
- QString targetDir = topDir.filePath(trashDir);
- // deliberately not using mkpath, since we want to fail if topDir doesn't exist
- if (topDir.mkdir(trashDir))
- QFile::setPermissions(targetDir, ownerPerms);
- if (QFileInfo(targetDir).isDir())
- return targetDir;
- return QString();
- };
- auto isSticky = [](const QFileInfo &fileInfo) -> bool {
- struct stat st;
- if (stat(QFile::encodeName(fileInfo.absoluteFilePath()).constData(), &st) == 0)
- return st.st_mode & S_ISVTX;
+ /*
+ "A trash directory contains two subdirectories, named info and files."
+ */
+ QString trashPath;
+ int filesDirFd = -1;
+ int infoDirFd = -1;
+ qsizetype volumePrefixLength = 0;
- return false;
- };
+ // relative file paths to the filesDirFd and infoDirFd from above
+ QByteArray tempTrashFileName;
+ QByteArray infoFilePath;
+
+ int infoFileFd = -1; // if we've already opened it
+ ~FreeDesktopTrashOperation()
+ {
+ close();
+ }
+
+ constexpr bool isTrashDirOpen() const { return filesDirFd != -1 && infoDirFd != -1; }
+
+ void close()
+ {
+ int savedErrno = errno;
+ if (infoFileFd != -1) {
+ Q_ASSERT(infoDirFd != -1);
+ Q_ASSERT(!infoFilePath.isEmpty());
+ Q_ASSERT(!trashPath.isEmpty());
+
+ QT_CLOSE(infoFileFd);
+ unlinkat(infoDirFd, infoFilePath, 0);
+ infoFileFd = -1;
+ }
+ if (!tempTrashFileName.isEmpty()) {
+ Q_ASSERT(filesDirFd != -1);
+ unlinkat(filesDirFd, tempTrashFileName, 0);
+ }
+ if (filesDirFd >= 0)
+ QT_CLOSE(filesDirFd);
+ if (infoDirFd >= 0)
+ QT_CLOSE(infoDirFd);
+ filesDirFd = infoDirFd = -1;
+ errno = savedErrno;
+ }
+
+ bool tryCreateInfoFile(const QString &filePath, QSystemError &error)
+ {
+ QByteArray p = QFile::encodeName(filePath) + ".trashinfo";
+ infoFileFd = qt_safe_openat(infoDirFd, p, QT_OPEN_RDWR | QT_OPEN_CREAT | QT_OPEN_EXCL, 0666);
+ if (infoFileFd < 0) {
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+ }
+ infoFilePath = std::move(p);
+ return true;
+ }
+
+ void commit()
+ {
+ QT_CLOSE(infoFileFd);
+ infoFileFd = -1;
+ tempTrashFileName = {};
+ }
+
+ // opens a directory and returns the file descriptor
+ static int openDirFd(int dfd, const char *path, int mode = 0)
+ {
+ mode |= QT_OPEN_RDONLY | O_NOFOLLOW | O_DIRECTORY;
+ return qt_safe_openat(dfd, path, mode);
+ }
+
+ // opens an XDG Trash directory that is a subdirectory of dfd, creating if necessary
+ static int openOrCreateDir(int dfd, const char *path)
+ {
+ // try to open it as a dir, first
+ int fd = openDirFd(dfd, path);
+ if (fd >= 0 || errno != ENOENT)
+ return fd;
+
+ // try to mkdirat
+ if (mkdirat(dfd, path, 0700) < 0)
+ return -1;
+
+ // try to open it again
+ return openDirFd(dfd, path);
+ }
+
+ // opens or makes the XDG Trash hierarchy on parentfd (may be -1) called targetDir
+ bool getTrashDir(int parentfd, QString targetDir, const QFileSystemEntry &source,
+ QSystemError &error)
+ {
+ if (parentfd == AT_FDCWD)
+ trashPath = targetDir;
+ QByteArray nativePath = QFile::encodeName(targetDir);
+
+ // open the directory
+ int trashfd = openOrCreateDir(parentfd, nativePath);
+ if (trashfd < 0 && errno != ENOENT) {
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+ }
+
+ // check if it is ours (even if we've just mkdirat'ed it)
+ if (QT_STATBUF st; QT_FSTAT(trashfd, &st) < 0) {
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+ } else if (st.st_uid != getuid()) {
+ error = QSystemError(EPERM, QSystemError::StandardLibraryError);
+ return false;
+ }
+
+ filesDirFd = openOrCreateDir(trashfd, "files");
+ if (filesDirFd >= 0) {
+ // try to link our file-to-be-trashed here
+ QTemporaryFileName tfn("XXXXXX"_L1);
+ for (int i = 0; i < 16; ++i) {
+ QByteArray attempt = tfn.generateNext();
+ if (linkat(AT_FDCWD, source.nativeFilePath(), filesDirFd, attempt, 0) == 0) {
+ tempTrashFileName = std::move(attempt);
+ break;
+ }
+ if (errno != EEXIST)
+ break;
+ }
+
+ // man 2 link on Linux has:
+ // EPERM The filesystem containing oldpath and newpath does not
+ // support the creation of hard links.
+ // EPERM oldpath is a directory.
+ // EPERM oldpath is marked immutable or append‐only.
+ // EMLINK The file referred to by oldpath already has the maximum
+ // number of links to it.
+ if (!tempTrashFileName.isEmpty() || errno == EPERM || errno == EMLINK)
+ infoDirFd = openOrCreateDir(trashfd, "info");
+ }
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ if (infoDirFd < 0)
+ close();
+ QT_CLOSE(trashfd);
+ return infoDirFd >= 0;
+ }
- QString trash;
- const QStorageInfo sourceStorage(sourcePath);
- const QStorageInfo homeStorage(QDir::home());
- // We support trashing of files outside the users home partition
- if (sourceStorage != homeStorage) {
- const auto dotTrash = ".Trash"_L1;
- QDir topDir(sourceStorage.rootPath());
+ bool openMountPointTrashLocation(const QFileSystemEntry &source,
+ const QStorageInfo &sourceStorage, QSystemError &error)
+ {
/*
Method 1:
"An administrator can create an $topdir/.Trash directory. The permissions on this
@@ -1223,21 +1347,31 @@ static QString freeDesktopTrashLocation(const QString &sourcePath)
(if it supports trashing in top directories) MUST check for the presence
of $topdir/.Trash."
*/
- const QString userID = QString::number(::getuid());
- if (topDir.cd(dotTrash)) {
- const QFileInfo trashInfo(topDir.path());
- // we MUST check that the sticky bit is set, and that it is not a symlink
- if (trashInfo.isSymLink()) {
+ const auto dotTrash = "/.Trash"_L1;
+ const QString userID = QString::number(::getuid());
+ QFileSystemEntry dotTrashDir(sourceStorage.rootPath() + dotTrash);
+
+ // we MUST check that the sticky bit is set, and that it is not a symlink
+ int genericTrashFd = openDirFd(AT_FDCWD, dotTrashDir.nativeFilePath());
+ QT_STATBUF st = {};
+ if (genericTrashFd < 0 && errno != ENOENT && errno != EACCES) {
+ // O_DIRECTORY + O_NOFOLLOW produces ENOTDIR on Linux
+ if (QT_LSTAT(dotTrashDir.nativeFilePath(), &st) == 0 && S_ISLNK(st.st_mode)) {
// we SHOULD report the failed check to the administrator
qCritical("Warning: '%s' is a symlink to '%s'",
- trashInfo.absoluteFilePath().toLocal8Bit().constData(),
- trashInfo.symLinkTarget().toLatin1().constData());
- } else if (!isSticky(trashInfo)) {
+ dotTrashDir.nativeFilePath().constData(),
+ qt_readlink(dotTrashDir.nativeFilePath()).constData());
+ error = QSystemError(ELOOP, QSystemError::StandardLibraryError);
+ }
+ } else if (genericTrashFd >= 0) {
+ QT_FSTAT(genericTrashFd, &st);
+ if ((st.st_mode & S_ISVTX) == 0) {
// we SHOULD report the failed check to the administrator
qCritical("Warning: '%s' doesn't have sticky bit set!",
- trashInfo.absoluteFilePath().toLocal8Bit().constData());
- } else if (trashInfo.isDir()) {
+ dotTrashDir.nativeFilePath().constData());
+ error = QSystemError(EPERM, QSystemError::StandardLibraryError);
+ } else {
/*
"If the directory exists and passes the checks, a subdirectory of the
$topdir/.Trash directory is to be used as the user's trash directory
@@ -1247,9 +1381,14 @@ static QString freeDesktopTrashLocation(const QString &sourcePath)
the implementation MUST immediately create it, without any warnings or
delays for the user."
*/
- trash = makeTrashDir(topDir, userID);
+ if (getTrashDir(genericTrashFd, userID, source, error)) {
+ // recreate the resulting path
+ trashPath = dotTrashDir.filePath() + u'/' + userID;
+ }
}
+ QT_CLOSE(genericTrashFd);
}
+
/*
Method 2:
"If an $topdir/.Trash directory is absent, an $topdir/.Trash-$uid directory is to be
@@ -1257,145 +1396,146 @@ static QString freeDesktopTrashLocation(const QString &sourcePath)
file, if an $topdir/.Trash-$uid directory does not exist, the implementation MUST
immediately create it, without any warnings or delays for the user."
*/
- if (trash.isEmpty()) {
- topDir = QDir(sourceStorage.rootPath());
- const QString userTrashDir = dotTrash + u'-' + userID;
- trash = makeTrashDir(topDir, userTrashDir);
+ if (!isTrashDirOpen())
+ getTrashDir(AT_FDCWD, sourceStorage.rootPath() + dotTrash + u'-' + userID, source, error);
+
+ if (isTrashDirOpen()) {
+ volumePrefixLength = sourceStorage.rootPath().size();
+ if (volumePrefixLength == 1)
+ volumePrefixLength = 0; // isRoot
+ else
+ ++volumePrefixLength; // to include the slash
}
+ return isTrashDirOpen();
}
- /*
- "If both (1) and (2) fail [...], the implementation MUST either trash the
- file into the user's “home trash” or refuse to trash it."
-
- We trash the file into the user's home trash.
- "Its name and location are $XDG_DATA_HOME/Trash"; $XDG_DATA_HOME is what
- QStandardPaths returns for GenericDataLocation. If that doesn't exist, then
- we are not running on a freedesktop.org-compliant environment, and give up.
- */
- if (trash.isEmpty()) {
- QDir topDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
- trash = makeTrashDir(topDir, "Trash"_L1);
- if (!QFileInfo(trash).isDir()) {
- qWarning("Unable to establish trash directory in %s",
- topDir.path().toLocal8Bit().constData());
- }
+ bool openHomeTrashLocation(const QFileSystemEntry &source, QSystemError &error)
+ {
+ QString topDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
+ return getTrashDir(AT_FDCWD, topDir + "/Trash"_L1, source, error);
}
- return trash;
-}
-#endif // QT_BOOTSTRAPPED
+ bool findTrashFor(const QFileSystemEntry &source, QSystemError &error)
+ {
+ /*
+ First, try the standard Trash in $XDG_DATA_DIRS:
+ "Its name and location are $XDG_DATA_HOME/Trash"; $XDG_DATA_HOME is what
+ QStandardPaths returns for GenericDataLocation. If that doesn't exist, then
+ we are not running on a freedesktop.org-compliant environment, and give up.
+ */
+ if (openHomeTrashLocation(source, error))
+ return true;
+ if (error.errorCode != EXDEV)
+ return false;
+
+ // didn't work, try to find the trash outside the home filesystem
+ const QStorageInfo sourceStorage(source.filePath());
+ if (!sourceStorage.isValid())
+ return false;
+ return openMountPointTrashLocation(source, sourceStorage, error);
+ }
+};
+} // unnamed namespace
//static
bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source,
QFileSystemEntry &newLocation, QSystemError &error)
{
-#ifdef QT_BOOTSTRAPPED
- Q_UNUSED(source);
- Q_UNUSED(newLocation);
- error = QSystemError(ENOSYS, QSystemError::StandardLibraryError);
- return false;
-#else
- const QFileInfo sourceInfo(source.filePath());
- if (!sourceInfo.exists()) {
- error = QSystemError(ENOENT, QSystemError::StandardLibraryError);
+ const QFileSystemEntry sourcePath = [&] {
+ if (QString path = source.filePath(); path.size() > 1 && path.endsWith(u'/')) {
+ path.chop(1);
+ return absoluteName(QFileSystemEntry(path));
+ }
+ return absoluteName(source);
+ }();
+ FreeDesktopTrashOperation op;
+ if (!op.findTrashFor(sourcePath, error))
return false;
- }
- const QString sourcePath = sourceInfo.absoluteFilePath();
- QDir trashDir(freeDesktopTrashLocation(sourcePath));
- if (!trashDir.exists())
- return false;
- /*
- "A trash directory contains two subdirectories, named info and files."
- */
- const auto filesDir = "files"_L1;
- const auto infoDir = "info"_L1;
- trashDir.mkdir(filesDir);
- int savedErrno = errno;
- trashDir.mkdir(infoDir);
- if (!savedErrno)
- savedErrno = errno;
- if (!trashDir.exists(filesDir) || !trashDir.exists(infoDir)) {
- error = QSystemError(savedErrno, QSystemError::StandardLibraryError);
- return false;
- }
/*
"The $trash/files directory contains the files and directories that were trashed.
The names of files in this directory are to be determined by the implementation;
the only limitation is that they must be unique within the directory. Even if a
file with the same name and location gets trashed many times, each subsequent
trashing must not overwrite a previous copy."
- */
- const QString trashedName = sourceInfo.isDir()
- ? QDir(sourcePath).dirName()
- : sourceInfo.fileName();
- QString uniqueTrashedName = u'/' + trashedName;
- QString infoFileName;
- int counter = 0;
- QFile infoFile;
- auto makeUniqueTrashedName = [trashedName, &counter]() -> QString {
- return QString::asprintf("/%ls-%04d", qUtf16Printable(trashedName), ++counter);
- };
- do {
- while (QFile::exists(trashDir.filePath(filesDir) + uniqueTrashedName))
- uniqueTrashedName = makeUniqueTrashedName();
- /*
- "The $trash/info directory contains an "information file" for every file and directory
- in $trash/files. This file MUST have exactly the same name as the file or directory in
- $trash/files, plus the extension ".trashinfo"
- [...]
- When trashing a file or directory, the implementation MUST create the corresponding
- file in $trash/info first. Moreover, it MUST try to do this in an atomic fashion,
- so that if two processes try to trash files with the same filename this will result
- in two different trash files. On Unix-like systems this is done by generating a
- filename, and then opening with O_EXCL. If that succeeds the creation was atomic
- (at least on the same machine), if it fails you need to pick another filename."
- */
- infoFileName = trashDir.filePath(infoDir)
- + uniqueTrashedName + ".trashinfo"_L1;
- infoFile.setFileName(infoFileName);
- if (!infoFile.open(QIODevice::NewOnly | QIODevice::WriteOnly | QIODevice::Text))
- uniqueTrashedName = makeUniqueTrashedName();
- } while (!infoFile.isOpen());
-
- const QString targetPath = trashDir.filePath(filesDir) + uniqueTrashedName;
- const QFileSystemEntry target(targetPath);
-
- QString infoPath;
- const QStorageInfo storageInfo(sourcePath);
- if (storageInfo.isValid() && storageInfo.rootPath() != rootPath() && storageInfo != QStorageInfo(QDir::home())) {
- infoPath = sourcePath.mid(storageInfo.rootPath().length());
- if (infoPath.front() == u'/')
- infoPath = infoPath.mid(1);
- } else {
- infoPath = sourcePath;
- }
- /*
- We might fail to rename if source and target are on different file systems.
- In that case, we don't try further, i.e. copying and removing the original
- is usually not what the user would expect to happen.
+ We first try the unchanged base name, then try something different if it collides.
+
+ "The $trash/info directory contains an "information file" for every file and directory
+ in $trash/files. This file MUST have exactly the same name as the file or directory in
+ $trash/files, plus the extension ".trashinfo"
+ [...]
+ When trashing a file or directory, the implementation MUST create the corresponding
+ file in $trash/info first. Moreover, it MUST try to do this in an atomic fashion,
+ so that if two processes try to trash files with the same filename this will result
+ in two different trash files. On Unix-like systems this is done by generating a
+ filename, and then opening with O_EXCL. If that succeeds the creation was atomic
+ (at least on the same machine), if it fails you need to pick another filename."
*/
- if (!renameFile(source, target, error)) {
- infoFile.close();
- infoFile.remove();
- return false;
+ QString uniqueTrashedName = sourcePath.fileName();
+ if (!op.tryCreateInfoFile(uniqueTrashedName, error) && error.errorCode == EEXIST) {
+ // we'll use a counter, starting with the file's inode number to avoid
+ // collisions
+ qulonglong counter;
+ if (QT_STATBUF st; Q_LIKELY(QT_STAT(source.nativeFilePath(), &st) == 0)) {
+ counter = st.st_ino;
+ } else {
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+ }
+
+ QString uniqueTrashBase = std::move(uniqueTrashedName);
+ for (;;) {
+ uniqueTrashedName = QString::asprintf("%ls-%llu", qUtf16Printable(uniqueTrashBase),
+ counter++);
+ if (op.tryCreateInfoFile(uniqueTrashedName, error))
+ break;
+ if (error.errorCode != EEXIST)
+ return false;
+ };
}
QByteArray info =
"[Trash Info]\n"
- "Path=" + QUrl::toPercentEncoding(infoPath, "/") + "\n"
- "DeletionDate=" + QDateTime::currentDateTime().toString("yyyy-MM-ddThh:mm:ss"_L1).toUtf8()
+ "Path=" + QUrl::toPercentEncoding(source.filePath().mid(op.volumePrefixLength), "/") + "\n"
+ "DeletionDate=" + QDateTime::currentDateTime().toString(Qt::ISODate).toUtf8()
+ "\n";
- infoFile.write(info);
- infoFile.close();
+ if (QT_WRITE(op.infoFileFd, info.data(), info.size()) < 0) {
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+ }
+
+ /*
+ If we've already linked the file-to-be-trashed into the trash
+ directory, we know it's in the same mountpoint and we won't get ENOSPC
+ renaming the temporary file to the target name either.
+ */
+ bool renamed;
+ if (op.tempTrashFileName.isEmpty()) {
+ /*
+ We did not get a link (we're trying to trash a directory or on a
+ filesystem that doesn't support hardlinking), so rename straight
+ from the original name. We might fail to rename if source and target
+ are on different file systems.
+ */
+ renamed = renameat(AT_FDCWD, source.nativeFilePath(), op.filesDirFd,
+ QFile::encodeName(uniqueTrashedName)) == 0;
+ } else {
+ renamed = renameat(op.filesDirFd, op.tempTrashFileName, op.filesDirFd,
+ QFile::encodeName(uniqueTrashedName)) == 0;
+ if (renamed)
+ removeFile(source, error); // success, delete the original file
+ }
+ if (!renamed) {
+ error = QSystemError(errno, QSystemError::StandardLibraryError);
+ return false;
+ }
- newLocation = QFileSystemEntry(targetPath);
+ op.commit();
+ newLocation = QFileSystemEntry(op.trashPath + "/files/"_L1 + uniqueTrashedName);
return true;
-#endif // QT_BOOTSTRAPPED
}
-#endif // Q_OS_DARWIN
+#endif // !Q_OS_DARWIN && !QT_BOOTSTRAPPED
//static
bool QFileSystemEngine::copyFile(const QFileSystemEntry &source, const QFileSystemEntry &target, QSystemError &error)
@@ -1543,10 +1683,10 @@ bool QFileSystemEngine::setPermissions(int fd, QFile::Permissions permissions, Q
}
//static
-bool QFileSystemEngine::setFileTime(int fd, const QDateTime &newDate, QAbstractFileEngine::FileTime time, QSystemError &error)
+bool QFileSystemEngine::setFileTime(int fd, const QDateTime &newDate, QFile::FileTime time, QSystemError &error)
{
- if (!newDate.isValid() || time == QAbstractFileEngine::BirthTime ||
- time == QAbstractFileEngine::MetadataChangeTime) {
+ if (!newDate.isValid()
+ || time == QFile::FileBirthTime || time == QFile::FileMetadataChangeTime) {
error = QSystemError(EINVAL, QSystemError::StandardLibraryError);
return false;
}
@@ -1555,8 +1695,8 @@ bool QFileSystemEngine::setFileTime(int fd, const QDateTime &newDate, QAbstractF
// UTIME_OMIT: leave file timestamp unchanged
struct timespec ts[2] = {{0, UTIME_OMIT}, {0, UTIME_OMIT}};
- if (time == QAbstractFileEngine::AccessTime || time == QAbstractFileEngine::ModificationTime) {
- const int idx = time == QAbstractFileEngine::AccessTime ? 0 : 1;
+ if (time == QFile::FileAccessTime || time == QFile::FileModificationTime) {
+ const int idx = time == QFile::FileAccessTime ? 0 : 1;
const std::chrono::milliseconds msecs{newDate.toMSecsSinceEpoch()};
ts[idx] = durationToTimespec(msecs);
}
diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp
index 49f375c4bb..3ec32e31a1 100644
--- a/src/corelib/io/qfilesystemengine_win.cpp
+++ b/src/corelib/io/qfilesystemengine_win.cpp
@@ -390,12 +390,6 @@ static QBasicAtomicInt qt_ntfs_permission_lookup_v2 = Q_BASIC_ATOMIC_INITIALIZER
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
-/*!
- \internal
-
- Returns true if the check was previously enabled.
-*/
-
bool qEnableNtfsPermissionChecks() noexcept
{
return qt_ntfs_permission_lookup_v2.fetchAndAddRelaxed(1)
@@ -403,12 +397,6 @@ QT_IF_DEPRECATED_SINCE(6, 6, /*nothing*/, + qt_ntfs_permission_lookup)
!= 0;
}
-/*!
- \internal
-
- Returns true if the check is disabled, i.e. there are no more users.
-*/
-
bool qDisableNtfsPermissionChecks() noexcept
{
return qt_ntfs_permission_lookup_v2.fetchAndSubRelaxed(1)
@@ -416,12 +404,6 @@ QT_IF_DEPRECATED_SINCE(6, 6, /*nothing*/, + qt_ntfs_permission_lookup)
== 1;
}
-/*!
- \internal
-
- Returns true if the check is enabled.
-*/
-
bool qAreNtfsPermissionChecksEnabled() noexcept
{
return qt_ntfs_permission_lookup_v2.loadRelaxed()
@@ -840,9 +822,10 @@ public:
return (dwFlags & TSF_DELETE_RECYCLE_IF_POSSIBLE) ? S_OK : E_FAIL;
}
HRESULT STDMETHODCALLTYPE PostDeleteItem(DWORD /* dwFlags */, IShellItem * /* psiItem */,
- HRESULT /* hrDelete */,
+ HRESULT hrDelete,
IShellItem *psiNewlyCreated) override
{
+ deleteResult = hrDelete;
if (psiNewlyCreated) {
wchar_t *pszName = nullptr;
psiNewlyCreated->GetDisplayName(SIGDN_FILESYSPATH, &pszName);
@@ -863,6 +846,7 @@ public:
HRESULT STDMETHODCALLTYPE ResumeTimer() override { return S_OK; }
QString targetPath;
+ HRESULT deleteResult = S_OK;
private:
ULONG ref;
};
@@ -1085,7 +1069,7 @@ QByteArray QFileSystemEngine::id(HANDLE fHandle)
//static
bool QFileSystemEngine::setFileTime(HANDLE fHandle, const QDateTime &newDate,
- QAbstractFileEngine::FileTime time, QSystemError &error)
+ QFile::FileTime time, QSystemError &error)
{
FILETIME fTime;
FILETIME *pLastWrite = nullptr;
@@ -1093,15 +1077,15 @@ bool QFileSystemEngine::setFileTime(HANDLE fHandle, const QDateTime &newDate,
FILETIME *pCreationTime = nullptr;
switch (time) {
- case QAbstractFileEngine::ModificationTime:
+ case QFile::FileModificationTime:
pLastWrite = &fTime;
break;
- case QAbstractFileEngine::AccessTime:
+ case QFile::FileAccessTime:
pLastAccess = &fTime;
break;
- case QAbstractFileEngine::BirthTime:
+ case QFile::FileBirthTime:
pCreationTime = &fTime;
break;
@@ -1833,8 +1817,12 @@ bool QFileSystemEngine::moveFileToTrash(const QFileSystemEntry &source,
hres = pfo->PerformOperations();
if (!SUCCEEDED(hres))
return false;
- newLocation = QFileSystemEntry(sink->targetPath);
+ if (!SUCCEEDED(sink->deleteResult)) {
+ error = QSystemError(sink->deleteResult, QSystemError::NativeError);
+ return false;
+ }
+ newLocation = QFileSystemEntry(sink->targetPath);
return true;
}
diff --git a/src/corelib/io/qfilesystementry.cpp b/src/corelib/io/qfilesystementry.cpp
index 6a655391be..ac1691d30e 100644
--- a/src/corelib/io/qfilesystementry.cpp
+++ b/src/corelib/io/qfilesystementry.cpp
@@ -14,6 +14,10 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
+// Assigned to m_lastSeparator and m_firstDotInFileName to indicate resolveFilePath()
+// hasn't been called yet
+constexpr int Uninitialized = -2;
+
#ifdef Q_OS_WIN
static bool isUncRoot(const QString &server)
{
@@ -51,8 +55,8 @@ QFileSystemEntry::QFileSystemEntry()
*/
QFileSystemEntry::QFileSystemEntry(const QString &filePath)
: m_filePath(QDir::fromNativeSeparators(filePath)),
- m_lastSeparator(-2),
- m_firstDotInFileName(-2),
+ m_lastSeparator(Uninitialized),
+ m_firstDotInFileName(Uninitialized),
m_lastDotInFileName(0)
{
}
@@ -64,8 +68,8 @@ QFileSystemEntry::QFileSystemEntry(const QString &filePath)
*/
QFileSystemEntry::QFileSystemEntry(const QString &filePath, FromInternalPath /* dummy */)
: m_filePath(filePath),
- m_lastSeparator(-2),
- m_firstDotInFileName(-2),
+ m_lastSeparator(Uninitialized),
+ m_firstDotInFileName(Uninitialized),
m_lastDotInFileName(0)
{
}
@@ -76,8 +80,8 @@ QFileSystemEntry::QFileSystemEntry(const QString &filePath, FromInternalPath /*
*/
QFileSystemEntry::QFileSystemEntry(const NativePath &nativeFilePath, FromNativePath /* dummy */)
: m_nativeFilePath(nativeFilePath),
- m_lastSeparator(-2),
- m_firstDotInFileName(-2),
+ m_lastSeparator(Uninitialized),
+ m_firstDotInFileName(Uninitialized),
m_lastDotInFileName(0)
{
}
@@ -85,8 +89,8 @@ QFileSystemEntry::QFileSystemEntry(const NativePath &nativeFilePath, FromNativeP
QFileSystemEntry::QFileSystemEntry(const QString &filePath, const NativePath &nativeFilePath)
: m_filePath(QDir::fromNativeSeparators(filePath)),
m_nativeFilePath(nativeFilePath),
- m_lastSeparator(-2),
- m_firstDotInFileName(-2),
+ m_lastSeparator(Uninitialized),
+ m_firstDotInFileName(Uninitialized),
m_lastDotInFileName(0)
{
}
@@ -312,7 +316,7 @@ bool QFileSystemEntry::isEmpty() const
void QFileSystemEntry::findLastSeparator() const
{
- if (m_lastSeparator == -2) {
+ if (m_lastSeparator == Uninitialized) {
resolveFilePath();
m_lastSeparator = m_filePath.lastIndexOf(u'/');
}
@@ -320,7 +324,7 @@ void QFileSystemEntry::findLastSeparator() const
void QFileSystemEntry::findFileNameSeparators() const
{
- if (m_firstDotInFileName == -2) {
+ if (m_firstDotInFileName == Uninitialized) {
resolveFilePath();
int firstDotInFileName = -1;
int lastDotInFileName = -1;
diff --git a/src/corelib/io/qfilesystemiterator_p.h b/src/corelib/io/qfilesystemiterator_p.h
index 2792340637..2973b85cd2 100644
--- a/src/corelib/io/qfilesystemiterator_p.h
+++ b/src/corelib/io/qfilesystemiterator_p.h
@@ -20,44 +20,48 @@
#ifndef QT_NO_FILESYSTEMITERATOR
#include <QtCore/qdir.h>
-#include <QtCore/qdiriterator.h>
#include <QtCore/qstringlist.h>
#include <QtCore/private/qfilesystementry_p.h>
#include <QtCore/private/qfilesystemmetadata_p.h>
-// Platform-specific headers
#if !defined(Q_OS_WIN)
-#include <QtCore/qscopedpointer.h>
+#include <private/qstringconverter_p.h>
#endif
+#include <memory>
+
QT_BEGIN_NAMESPACE
class QFileSystemIterator
{
public:
- QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters,
- const QStringList &nameFilters, QDirIterator::IteratorFlags flags
- = QDirIterator::FollowSymlinks | QDirIterator::Subdirectories);
+ QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters);
~QFileSystemIterator();
bool advance(QFileSystemEntry &fileEntry, QFileSystemMetaData &metaData);
private:
- QFileSystemEntry::NativePath nativePath;
+ QString dirPath;
// Platform-specific data
#if defined(Q_OS_WIN)
- QString dirPath;
+ QFileSystemEntry::NativePath nativePath;
HANDLE findFileHandle;
QStringList uncShares;
bool uncFallback;
int uncShareIndex;
bool onlyDirs;
#else
- QT_DIR *dir;
- QT_DIRENT *dirEntry;
- int lastError;
+ struct DirStreamCloser {
+ void operator()(QT_DIR *dir) { if (dir) QT_CLOSEDIR(dir); }
+ };
+ using DirPtr = std::unique_ptr<QT_DIR, DirStreamCloser>;
+ DirPtr dir;
+
+ QT_DIRENT *dirEntry = nullptr;
+ int lastError = 0;
+ QStringDecoder toUtf16;
#endif
Q_DISABLE_COPY_MOVE(QFileSystemIterator)
diff --git a/src/corelib/io/qfilesystemiterator_unix.cpp b/src/corelib/io/qfilesystemiterator_unix.cpp
index 6d6878efda..a1130728ef 100644
--- a/src/corelib/io/qfilesystemiterator_unix.cpp
+++ b/src/corelib/io/qfilesystemiterator_unix.cpp
@@ -4,10 +4,10 @@
#include "qplatformdefs.h"
#include "qfilesystemiterator_p.h"
-#include <private/qstringconverter_p.h>
-
#ifndef QT_NO_FILESYSTEMITERATOR
+#include <qvarlengtharray.h>
+
#include <memory>
#include <stdlib.h>
@@ -15,53 +15,66 @@
QT_BEGIN_NAMESPACE
-static bool checkNameDecodable(const char *d_name, qsizetype len)
-{
- // This function is called in a loop from advance() below, but the loop is
- // usually run only once.
-
- return QUtf8::isValidUtf8(QByteArrayView(d_name, len)).isValidUtf8;
-}
-
-QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters,
- const QStringList &nameFilters, QDirIterator::IteratorFlags flags)
- : nativePath(entry.nativeFilePath())
- , dir(nullptr)
- , dirEntry(nullptr)
- , lastError(0)
+/*
+ Native filesystem iterator, which uses ::opendir()/readdir()/dirent from the system
+ libraries to iterate over the directory represented by \a entry.
+*/
+QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters)
+ : dirPath(entry.filePath()),
+ toUtf16(QStringDecoder::Utf8)
{
Q_UNUSED(filters);
- Q_UNUSED(nameFilters);
- Q_UNUSED(flags);
- if ((dir = QT_OPENDIR(nativePath.constData())) == nullptr) {
+ dir.reset(QT_OPENDIR(entry.nativeFilePath().constData()));
+ if (!dir) {
lastError = errno;
} else {
- if (!nativePath.endsWith('/'))
- nativePath.append('/');
+ if (!dirPath.endsWith(u'/'))
+ dirPath.append(u'/');
}
}
-QFileSystemIterator::~QFileSystemIterator()
-{
- if (dir)
- QT_CLOSEDIR(dir);
-}
+QFileSystemIterator::~QFileSystemIterator() = default;
bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaData &metaData)
{
+ auto asFileEntry = [this](QStringView name) {
+#ifdef Q_OS_DARWIN
+ // must match QFile::decodeName
+ QString normalized = name.toString().normalized(QString::NormalizationForm_C);
+ name = normalized;
+#endif
+ return QFileSystemEntry(dirPath + name, QFileSystemEntry::FromInternalPath());
+ };
if (!dir)
return false;
for (;;) {
- dirEntry = QT_READDIR(dir);
+ // From readdir man page:
+ // If the end of the directory stream is reached, NULL is returned and errno is
+ // not changed. If an error occurs, NULL is returned and errno is set to indicate
+ // the error. To distinguish end of stream from an error, set errno to zero before
+ // calling readdir() and then check the value of errno if NULL is returned.
+ errno = 0;
+ dirEntry = QT_READDIR(dir.get());
if (dirEntry) {
- qsizetype len = strlen(dirEntry->d_name);
- if (checkNameDecodable(dirEntry->d_name, len)) {
- fileEntry = QFileSystemEntry(nativePath + QByteArray(dirEntry->d_name, len), QFileSystemEntry::FromNativePath());
+ // POSIX allows readdir() to return a file name in struct dirent that
+ // extends past the end of the d_name array (it's a char[1] array on QNX, for
+ // example). Therefore, we *must* call strlen() on it to get the actual length
+ // of the file name. See:
+ // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/dirent.h.html#tag_13_07_05
+ QByteArrayView name(dirEntry->d_name, strlen(dirEntry->d_name));
+ // name.size() is sufficient here, see QUtf8::convertToUnicode() for details
+ QVarLengthArray<char16_t> buffer(name.size());
+ auto *end = toUtf16.appendToBuffer(buffer.data(), name);
+ buffer.resize(end - buffer.constData());
+ if (!toUtf16.hasError()) {
+ fileEntry = asFileEntry(buffer);
metaData.fillFromDirEnt(*dirEntry);
return true;
+ } else {
+ errno = EILSEQ; // Invalid or incomplete multibyte or wide character
}
} else {
break;
diff --git a/src/corelib/io/qfilesystemiterator_win.cpp b/src/corelib/io/qfilesystemiterator_win.cpp
index 2c16cc7f6b..7644a1a078 100644
--- a/src/corelib/io/qfilesystemiterator_win.cpp
+++ b/src/corelib/io/qfilesystemiterator_win.cpp
@@ -14,17 +14,14 @@ using namespace Qt::StringLiterals;
bool done = true;
-QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters,
- const QStringList &nameFilters, QDirIterator::IteratorFlags flags)
- : nativePath(entry.nativeFilePath())
- , dirPath(entry.filePath())
+QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters)
+ : dirPath(entry.filePath())
+ , nativePath(entry.nativeFilePath())
, findFileHandle(INVALID_HANDLE_VALUE)
, uncFallback(false)
, uncShareIndex(0)
, onlyDirs(false)
{
- Q_UNUSED(nameFilters);
- Q_UNUSED(flags);
if (nativePath.endsWith(u".lnk"_s) && !QFileSystemEngine::isDirPath(dirPath, nullptr)) {
QFileSystemMetaData metaData;
QFileSystemEntry link = QFileSystemEngine::getLinkTarget(entry, metaData);
diff --git a/src/corelib/io/qfilesystemmetadata_p.h b/src/corelib/io/qfilesystemmetadata_p.h
index cb19b98c33..c10b66afaf 100644
--- a/src/corelib/io/qfilesystemmetadata_p.h
+++ b/src/corelib/io/qfilesystemmetadata_p.h
@@ -186,11 +186,15 @@ public:
QDateTime metadataChangeTime() const;
QDateTime modificationTime() const;
- QDateTime fileTime(QAbstractFileEngine::FileTime time) const;
+ QDateTime fileTime(QFile::FileTime time) const;
uint userId() const;
uint groupId() const;
uint ownerId(QAbstractFileEngine::FileOwner owner) const;
+ bool isReadable() const { return permissions().testAnyFlags(QFile::ReadUser); }
+ bool isWritable() const { return permissions().testAnyFlags(QFile::WriteUser); }
+ bool isExecutable() const { return permissions().testAnyFlags(QFile::ExeUser); }
+
#ifdef Q_OS_UNIX
void fillFromStatxBuf(const struct statx &statBuffer);
void fillFromStatBuf(const QT_STATBUF &statBuffer);
@@ -243,19 +247,19 @@ inline bool QFileSystemMetaData::isAlias() const { return fal
#endif
#if defined(Q_OS_UNIX) || defined (Q_OS_WIN)
-inline QDateTime QFileSystemMetaData::fileTime(QAbstractFileEngine::FileTime time) const
+inline QDateTime QFileSystemMetaData::fileTime(QFile::FileTime time) const
{
switch (time) {
- case QAbstractFileEngine::ModificationTime:
+ case QFile::FileModificationTime:
return modificationTime();
- case QAbstractFileEngine::AccessTime:
+ case QFile::FileAccessTime:
return accessTime();
- case QAbstractFileEngine::BirthTime:
+ case QFile::FileBirthTime:
return birthTime();
- case QAbstractFileEngine::MetadataChangeTime:
+ case QFile::FileMetadataChangeTime:
return metadataChangeTime();
}
diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp
index 9ffbe31d3d..7138f8260b 100644
--- a/src/corelib/io/qfilesystemwatcher.cpp
+++ b/src/corelib/io/qfilesystemwatcher.cpp
@@ -58,29 +58,29 @@ QFileSystemWatcherPrivate::QFileSystemWatcherPrivate()
{
}
+void QFileSystemWatcherPrivate::connectEngine(QFileSystemWatcherEngine *engine)
+{
+ QObjectPrivate::connect(engine, &QFileSystemWatcherEngine::fileChanged,
+ this, &QFileSystemWatcherPrivate::fileChanged);
+ QObjectPrivate::connect(engine, &QFileSystemWatcherEngine::directoryChanged,
+ this, &QFileSystemWatcherPrivate::directoryChanged);
+}
+
void QFileSystemWatcherPrivate::init()
{
Q_Q(QFileSystemWatcher);
native = createNativeEngine(q);
if (native) {
- QObject::connect(native,
- SIGNAL(fileChanged(QString,bool)),
- q,
- SLOT(_q_fileChanged(QString,bool)));
- QObject::connect(native,
- SIGNAL(directoryChanged(QString,bool)),
- q,
- SLOT(_q_directoryChanged(QString,bool)));
+ connectEngine(native);
#if defined(Q_OS_WIN)
- 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); });
+ auto *windowsWatcher = static_cast<QWindowsFileSystemWatcherEngine *>(native);
+ using WinE = QWindowsFileSystemWatcherEngine;
+ QObjectPrivate::connect(windowsWatcher, &WinE::driveLockForRemoval,
+ this, &QFileSystemWatcherPrivate::winDriveLockForRemoval);
+ QObjectPrivate::connect(windowsWatcher, &WinE::driveLockForRemovalFailed,
+ this, &QFileSystemWatcherPrivate::winDriveLockForRemovalFailed);
+ QObjectPrivate::connect(windowsWatcher, &WinE::driveRemoved,
+ this, &QFileSystemWatcherPrivate::winDriveRemoved);
#endif // Q_OS_WIN
}
}
@@ -92,17 +92,10 @@ void QFileSystemWatcherPrivate::initPollerEngine()
Q_Q(QFileSystemWatcher);
poller = new QPollingFileSystemWatcherEngine(q); // that was a mouthful
- QObject::connect(poller,
- SIGNAL(fileChanged(QString,bool)),
- q,
- SLOT(_q_fileChanged(QString,bool)));
- QObject::connect(poller,
- SIGNAL(directoryChanged(QString,bool)),
- q,
- SLOT(_q_directoryChanged(QString,bool)));
+ connectEngine(poller);
}
-void QFileSystemWatcherPrivate::_q_fileChanged(const QString &path, bool removed)
+void QFileSystemWatcherPrivate::fileChanged(const QString &path, bool removed)
{
Q_Q(QFileSystemWatcher);
qCDebug(lcWatcher) << "file changed" << path << "removed?" << removed << "watching?" << files.contains(path);
@@ -115,7 +108,7 @@ void QFileSystemWatcherPrivate::_q_fileChanged(const QString &path, bool removed
emit q->fileChanged(path, QFileSystemWatcher::QPrivateSignal());
}
-void QFileSystemWatcherPrivate::_q_directoryChanged(const QString &path, bool removed)
+void QFileSystemWatcherPrivate::directoryChanged(const QString &path, bool removed)
{
Q_Q(QFileSystemWatcher);
qCDebug(lcWatcher) << "directory changed" << path << "removed?" << removed << "watching?" << directories.contains(path);
@@ -130,7 +123,7 @@ void QFileSystemWatcherPrivate::_q_directoryChanged(const QString &path, bool re
#if defined(Q_OS_WIN)
-void QFileSystemWatcherPrivate::_q_winDriveLockForRemoval(const QString &path)
+void QFileSystemWatcherPrivate::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.
@@ -147,7 +140,7 @@ void QFileSystemWatcherPrivate::_q_winDriveLockForRemoval(const QString &path)
}
}
-void QFileSystemWatcherPrivate::_q_winDriveLockForRemovalFailed(const QString &path)
+void QFileSystemWatcherPrivate::winDriveLockForRemovalFailed(const QString &path)
{
// Windows: Request to lock a (removable/USB) drive failed (blocked by other
// application), restore the watched paths.
@@ -161,7 +154,7 @@ void QFileSystemWatcherPrivate::_q_winDriveLockForRemovalFailed(const QString &p
}
}
-void QFileSystemWatcherPrivate::_q_winDriveRemoved(const QString &path)
+void QFileSystemWatcherPrivate::winDriveRemoved(const QString &path)
{
// Windows: Drive finally removed, clear out paths stored in lock request.
if (!path.isEmpty())
diff --git a/src/corelib/io/qfilesystemwatcher.h b/src/corelib/io/qfilesystemwatcher.h
index f5400bc9d8..668bc143b2 100644
--- a/src/corelib/io/qfilesystemwatcher.h
+++ b/src/corelib/io/qfilesystemwatcher.h
@@ -34,10 +34,6 @@ public:
Q_SIGNALS:
void fileChanged(const QString &path, QPrivateSignal);
void directoryChanged(const QString &path, QPrivateSignal);
-
-private:
- Q_PRIVATE_SLOT(d_func(), void _q_fileChanged(const QString &path, bool removed))
- Q_PRIVATE_SLOT(d_func(), void _q_directoryChanged(const QString &path, bool removed))
};
QT_END_NAMESPACE
diff --git a/src/corelib/io/qfilesystemwatcher_inotify.cpp b/src/corelib/io/qfilesystemwatcher_inotify.cpp
index 3b53b490f5..e60f688110 100644
--- a/src/corelib/io/qfilesystemwatcher_inotify.cpp
+++ b/src/corelib/io/qfilesystemwatcher_inotify.cpp
@@ -217,7 +217,8 @@ QInotifyFileSystemWatcherEngine::QInotifyFileSystemWatcherEngine(int fd, QObject
notifier(fd, QSocketNotifier::Read, this)
{
fcntl(inotifyFd, F_SETFD, FD_CLOEXEC);
- connect(&notifier, SIGNAL(activated(QSocketDescriptor)), SLOT(readFromInotify()));
+ QObject::connect(&notifier, &QSocketNotifier::activated,
+ this, &QInotifyFileSystemWatcherEngine::readFromInotify);
}
QInotifyFileSystemWatcherEngine::~QInotifyFileSystemWatcherEngine()
@@ -334,7 +335,7 @@ void QInotifyFileSystemWatcherEngine::readFromInotify()
return;
QVarLengthArray<char, 4096> buffer(buffSize);
- buffSize = read(inotifyFd, buffer.data(), buffSize);
+ buffSize = int(read(inotifyFd, buffer.data(), buffSize));
char *at = buffer.data();
char * const end = at + buffSize;
diff --git a/src/corelib/io/qfilesystemwatcher_kqueue.cpp b/src/corelib/io/qfilesystemwatcher_kqueue.cpp
index 40d4c1f150..7a9be337bf 100644
--- a/src/corelib/io/qfilesystemwatcher_kqueue.cpp
+++ b/src/corelib/io/qfilesystemwatcher_kqueue.cpp
@@ -165,7 +165,7 @@ void QKqueueFileSystemWatcherEngine::readFromKqueue()
int r;
struct kevent kev;
struct timespec ts = { 0, 0 }; // 0 ts, because we want to poll
- EINTR_LOOP(r, kevent(kqfd, 0, 0, &kev, 1, &ts));
+ QT_EINTR_LOOP(r, kevent(kqfd, 0, 0, &kev, 1, &ts));
if (r < 0) {
perror("QKqueueFileSystemWatcherEngine: error during kevent wait");
return;
@@ -218,3 +218,5 @@ void QKqueueFileSystemWatcherEngine::readFromKqueue()
}
QT_END_NAMESPACE
+
+#include "moc_qfilesystemwatcher_kqueue_p.cpp"
diff --git a/src/corelib/io/qfilesystemwatcher_p.h b/src/corelib/io/qfilesystemwatcher_p.h
index 34fef20704..c34e3e2408 100644
--- a/src/corelib/io/qfilesystemwatcher_p.h
+++ b/src/corelib/io/qfilesystemwatcher_p.h
@@ -69,13 +69,15 @@ public:
QStringList files, directories;
// private slots
- void _q_fileChanged(const QString &path, bool removed);
- void _q_directoryChanged(const QString &path, bool removed);
+ void fileChanged(const QString &path, bool removed);
+ void directoryChanged(const QString &path, bool removed);
+
+ void connectEngine(QFileSystemWatcherEngine *e);
#if defined(Q_OS_WIN)
- void _q_winDriveLockForRemoval(const QString &);
- void _q_winDriveLockForRemovalFailed(const QString &);
- void _q_winDriveRemoved(const QString &);
+ void winDriveLockForRemoval(const QString &);
+ void winDriveLockForRemovalFailed(const QString &);
+ void winDriveRemoved(const QString &);
private:
QHash<QChar, QStringList> temporarilyRemovedPaths;
diff --git a/src/corelib/io/qfilesystemwatcher_polling.cpp b/src/corelib/io/qfilesystemwatcher_polling.cpp
index 03425ac212..d34c8c49e8 100644
--- a/src/corelib/io/qfilesystemwatcher_polling.cpp
+++ b/src/corelib/io/qfilesystemwatcher_polling.cpp
@@ -2,16 +2,24 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qfilesystemwatcher_polling_p.h"
+
+#include <QtCore/qlatin1stringview.h>
#include <QtCore/qscopeguard.h>
#include <QtCore/qtimer.h>
+#include <chrono>
+
+using namespace std::chrono_literals;
+
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
+static constexpr auto PollingInterval = 1s;
+
QPollingFileSystemWatcherEngine::QPollingFileSystemWatcherEngine(QObject *parent)
- : QFileSystemWatcherEngine(parent),
- timer(this)
+ : QFileSystemWatcherEngine(parent)
{
- connect(&timer, SIGNAL(timeout()), SLOT(timeout()));
}
QStringList QPollingFileSystemWatcherEngine::addPaths(const QStringList &paths,
@@ -40,10 +48,17 @@ QStringList QPollingFileSystemWatcherEngine::addPaths(const QStringList &paths,
sg.dismiss();
}
+ std::chrono::milliseconds interval = PollingInterval;
+#ifdef QT_BUILD_INTERNAL
+ if (Q_UNLIKELY(parent()->objectName().startsWith("_qt_autotest_force_engine_"_L1))) {
+ interval = 10ms; // Special case to speed up the unittests
+ }
+#endif
+
if ((!this->files.isEmpty() ||
!this->directories.isEmpty()) &&
!timer.isActive()) {
- timer.start(PollingInterval);
+ timer.start(interval, this);
}
return unhandled;
@@ -72,8 +87,11 @@ QStringList QPollingFileSystemWatcherEngine::removePaths(const QStringList &path
return unhandled;
}
-void QPollingFileSystemWatcherEngine::timeout()
+void QPollingFileSystemWatcherEngine::timerEvent(QTimerEvent *e)
{
+ if (e->timerId() != timer.timerId())
+ return QFileSystemWatcherEngine::timerEvent(e);
+
for (auto it = files.begin(), end = files.end(); it != end; /*erasing*/) {
QString path = it.key();
QFileInfo fi(path);
diff --git a/src/corelib/io/qfilesystemwatcher_polling_p.h b/src/corelib/io/qfilesystemwatcher_polling_p.h
index 2d7423b39d..b65ff05575 100644
--- a/src/corelib/io/qfilesystemwatcher_polling_p.h
+++ b/src/corelib/io/qfilesystemwatcher_polling_p.h
@@ -15,11 +15,11 @@
// We mean it.
//
+#include <QtCore/qbasictimer.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qmutex.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qdir.h>
-#include <QtCore/qtimer.h>
#include <QtCore/qhash.h>
#include "qfilesystemwatcher_p.h"
@@ -27,8 +27,6 @@
QT_REQUIRE_CONFIG(filesystemwatcher);
QT_BEGIN_NAMESPACE
-enum { PollingInterval = 1000 };
-
class QPollingFileSystemWatcherEngine : public QFileSystemWatcherEngine
{
Q_OBJECT
@@ -77,11 +75,11 @@ public:
QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories) override;
QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories) override;
-private Q_SLOTS:
- void timeout();
+private:
+ void timerEvent(QTimerEvent *) final;
private:
- QTimer timer;
+ QBasicTimer timer;
};
QT_END_NAMESPACE
diff --git a/src/corelib/io/qfilesystemwatcher_win.cpp b/src/corelib/io/qfilesystemwatcher_win.cpp
index a0b2b006d6..5418265ba2 100644
--- a/src/corelib/io/qfilesystemwatcher_win.cpp
+++ b/src/corelib/io/qfilesystemwatcher_win.cpp
@@ -708,3 +708,4 @@ void QWindowsFileSystemWatcherEngineThread::wakeup()
QT_END_NAMESPACE
# include "qfilesystemwatcher_win.moc"
+# include "moc_qfilesystemwatcher_win_p.cpp"
diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp
index 0ff7da1ac4..f49106edd4 100644
--- a/src/corelib/io/qfsfileengine.cpp
+++ b/src/corelib/io/qfsfileengine.cpp
@@ -6,7 +6,6 @@
#include "qfsfileengine_iterator_p.h"
#include "qfilesystemengine_p.h"
#include "qdatetime.h"
-#include "qdiriterator.h"
#include "qset.h"
#include <QtCore/qdebug.h>
@@ -273,7 +272,7 @@ bool QFSFileEnginePrivate::openFh(QIODevice::OpenMode openMode, FILE *fh)
if (ret != 0) {
q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
- QSystemError::stdString());
+ QSystemError::stdString(errno));
this->openMode = QIODevice::NotOpen;
this->fh = nullptr;
@@ -335,7 +334,7 @@ bool QFSFileEnginePrivate::openFd(QIODevice::OpenMode openMode, int fd)
if (ret == -1) {
q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
- QSystemError::stdString());
+ QSystemError::stdString(errno));
this->openMode = QIODevice::NotOpen;
this->fd = -1;
@@ -394,7 +393,7 @@ bool QFSFileEnginePrivate::closeFdFh()
if (!flushed || !closed) {
if (flushed) {
// If not flushed, we want the flush error to fall through.
- q->setError(QFile::UnspecifiedError, QSystemError::stdString());
+ q->setError(QFile::UnspecifiedError, QSystemError::stdString(errno));
}
return false;
}
@@ -446,7 +445,7 @@ bool QFSFileEnginePrivate::flushFh()
if (ret != 0) {
q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError,
- QSystemError::stdString());
+ QSystemError::stdString(errno));
return false;
}
return true;
@@ -521,11 +520,11 @@ bool QFSFileEngine::seek(qint64 pos)
/*!
\reimp
*/
-QDateTime QFSFileEngine::fileTime(FileTime time) const
+QDateTime QFSFileEngine::fileTime(QFile::FileTime time) const
{
Q_D(const QFSFileEngine);
- if (time == AccessTime) {
+ if (time == QFile::FileAccessTime) {
// always refresh for the access time
d->metaData.clearFlags(QFileSystemMetaData::AccessTime);
}
@@ -561,14 +560,14 @@ bool QFSFileEnginePrivate::seekFdFh(qint64 pos)
} while (ret != 0 && errno == EINTR);
if (ret != 0) {
- q->setError(QFile::ReadError, QSystemError::stdString());
+ q->setError(QFile::ReadError, QSystemError::stdString(errno));
return false;
}
} else {
// Unbuffered stdio mode.
if (QT_LSEEK(fd, QT_OFF_T(pos), SEEK_SET) == -1) {
+ q->setError(QFile::PositionError, QSystemError::stdString(errno));
qWarning("QFile::at: Cannot set file position %lld", pos);
- q->setError(QFile::PositionError, QSystemError::stdString());
return false;
}
}
@@ -621,17 +620,15 @@ qint64 QFSFileEnginePrivate::readFdFh(char *data, qint64 len)
// Buffered stdlib mode.
size_t result;
- bool retry = true;
do {
result = fread(data + readBytes, 1, size_t(len - readBytes), fh);
- eof = feof(fh);
- if (retry && eof && result == 0) {
+ eof = feof(fh); // Doesn't change errno
+ if (eof && result == 0) {
// On OS X, this is needed, e.g., if a file was written to
// through another stream since our last read. See test
// tst_QFile::appendAndRead
QT_FSEEK(fh, QT_FTELL(fh), SEEK_SET); // re-sync stream.
- retry = false;
- continue;
+ break;
}
readBytes += result;
} while (!eof && (result == 0 ? errno == EINTR : readBytes < len));
@@ -651,12 +648,13 @@ qint64 QFSFileEnginePrivate::readFdFh(char *data, qint64 len)
result = QT_READ(fd, data + readBytes, chunkSize);
} while (result > 0 && (readBytes += result) < len);
- eof = !(result == -1);
+ // QT_READ (::read()) returns 0 to indicate end-of-file
+ eof = result == 0;
}
if (!eof && readBytes == 0) {
readBytes = -1;
- q->setError(QFile::ReadError, QSystemError::stdString());
+ q->setError(QFile::ReadError, QSystemError::stdString(errno));
}
return readBytes;
@@ -701,8 +699,8 @@ qint64 QFSFileEnginePrivate::readLineFdFh(char *data, qint64 maxlen)
// does the same, so we'd get two '\0' at the end - passing maxlen + 1
// solves this.
if (!fgets(data, int(maxlen + 1), fh)) {
- if (!feof(fh))
- q->setError(QFile::ReadError, QSystemError::stdString());
+ if (!feof(fh)) // Doesn't change errno
+ q->setError(QFile::ReadError, QSystemError::stdString(errno));
return -1; // error
}
@@ -779,7 +777,8 @@ qint64 QFSFileEnginePrivate::writeFdFh(const char *data, qint64 len)
if (len && writtenBytes == 0) {
writtenBytes = -1;
- q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError, QSystemError::stdString());
+ q->setError(errno == ENOSPC ? QFile::ResourceError : QFile::WriteError,
+ QSystemError::stdString(errno));
} else {
// reset the cached size, if any
metaData.clearFlags(QFileSystemMetaData::SizeAttribute);
@@ -792,18 +791,13 @@ qint64 QFSFileEnginePrivate::writeFdFh(const char *data, qint64 len)
/*!
\internal
*/
-QAbstractFileEngine::Iterator *QFSFileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames)
+QAbstractFileEngine::IteratorUniquePtr
+QFSFileEngine::beginEntryList(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames)
{
- return new QFSFileEngineIterator(filters, filterNames);
+ return std::make_unique<QFSFileEngineIterator>(path, filters, filterNames);
}
-/*!
- \internal
-*/
-QAbstractFileEngine::Iterator *QFSFileEngine::endEntryList()
-{
- return nullptr;
-}
#endif // QT_NO_FILESYSTEMITERATOR
/*!
@@ -906,7 +900,7 @@ bool QFSFileEngine::supportsExtension(Extension extension) const
\reimp
*/
-/*! \fn bool QFSFileEngine::setFileTime(const QDateTime &newDate, QAbstractFileEngine::FileTime time)
+/*! \fn bool QFSFileEngine::setFileTime(const QDateTime &newDate, QFile::FileTime time)
\reimp
*/
@@ -996,29 +990,32 @@ bool QFSFileEngine::remove()
return ret;
}
-/*!
- \reimp
+/*
+ An alternative to setFileName() when you have already constructed
+ a QFileSystemEntry.
*/
-bool QFSFileEngine::rename(const QString &newName)
+void QFSFileEngine::setFileEntry(QFileSystemEntry &&entry)
{
Q_D(QFSFileEngine);
- QSystemError error;
- bool ret = QFileSystemEngine::renameFile(d->fileEntry, QFileSystemEntry(newName), error);
- if (!ret)
- setError(QFile::RenameError, error.toString());
- return ret;
+ d->init();
+ d->fileEntry = std::move(entry);
}
-/*!
- \reimp
-*/
-bool QFSFileEngine::renameOverwrite(const QString &newName)
+
+bool QFSFileEngine::rename_helper(const QString &newName, RenameMode mode)
{
Q_D(QFSFileEngine);
+
+ auto func = mode == Rename ? QFileSystemEngine::renameFile
+ : QFileSystemEngine::renameOverwriteFile;
QSystemError error;
- bool ret = QFileSystemEngine::renameOverwriteFile(d->fileEntry, QFileSystemEntry(newName), error);
- if (!ret)
+ auto newEntry = QFileSystemEntry(newName);
+ const bool ret = func(d->fileEntry, newEntry, error);
+ if (!ret) {
setError(QFile::RenameError, error.toString());
- return ret;
+ return false;
+ }
+ setFileEntry(std::move(newEntry));
+ return true;
}
/*!
diff --git a/src/corelib/io/qfsfileengine_iterator.cpp b/src/corelib/io/qfsfileengine_iterator.cpp
index 7f43579a8f..fb0332f7f3 100644
--- a/src/corelib/io/qfsfileengine_iterator.cpp
+++ b/src/corelib/io/qfsfileengine_iterator.cpp
@@ -9,9 +9,10 @@
QT_BEGIN_NAMESPACE
-QFSFileEngineIterator::QFSFileEngineIterator(QDir::Filters filters, const QStringList &filterNames)
- : QAbstractFileEngineIterator(filters, filterNames)
- , done(false)
+QFSFileEngineIterator::QFSFileEngineIterator(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames)
+ : QAbstractFileEngineIterator(path, filters, filterNames),
+ nativeIterator(new QFileSystemIterator(QFileSystemEntry(path), filters))
{
}
@@ -19,48 +20,30 @@ QFSFileEngineIterator::~QFSFileEngineIterator()
{
}
-bool QFSFileEngineIterator::hasNext() const
+bool QFSFileEngineIterator::advance()
{
- if (!done && !nativeIterator) {
- nativeIterator.reset(new QFileSystemIterator(QFileSystemEntry(path()),
- filters(), nameFilters()));
- advance();
- }
-
- return !done;
-}
-
-QString QFSFileEngineIterator::next()
-{
- if (!hasNext())
- return QString();
-
- advance();
- return currentFilePath();
-}
-
-void QFSFileEngineIterator::advance() const
-{
- currentInfo = nextInfo;
+ if (!nativeIterator)
+ return false;
QFileSystemEntry entry;
QFileSystemMetaData data;
if (nativeIterator->advance(entry, data)) {
- nextInfo = QFileInfo(new QFileInfoPrivate(entry, data));
+ m_fileInfo = QFileInfo(new QFileInfoPrivate(entry, data));
+ return true;
} else {
- done = true;
nativeIterator.reset();
+ return false;
}
}
QString QFSFileEngineIterator::currentFileName() const
{
- return currentInfo.fileName();
+ return m_fileInfo.fileName();
}
QFileInfo QFSFileEngineIterator::currentFileInfo() const
{
- return currentInfo;
+ return m_fileInfo;
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qfsfileengine_iterator_p.h b/src/corelib/io/qfsfileengine_iterator_p.h
index 8281609ff2..b91c5d9973 100644
--- a/src/corelib/io/qfsfileengine_iterator_p.h
+++ b/src/corelib/io/qfsfileengine_iterator_p.h
@@ -23,27 +23,19 @@
QT_BEGIN_NAMESPACE
-class QFSFileEngineIteratorPrivate;
-class QFSFileEngineIteratorPlatformSpecificData;
-
class QFSFileEngineIterator : public QAbstractFileEngineIterator
{
public:
- QFSFileEngineIterator(QDir::Filters filters, const QStringList &filterNames);
+ QFSFileEngineIterator(const QString &path, QDir::Filters filters, const QStringList &filterNames);
~QFSFileEngineIterator();
- QString next() override;
- bool hasNext() const override;
+ bool advance() override;
QString currentFileName() const override;
QFileInfo currentFileInfo() const override;
private:
- void advance() const;
mutable QScopedPointer<QFileSystemIterator> nativeIterator;
- mutable QFileInfo currentInfo;
- mutable QFileInfo nextInfo;
- mutable bool done;
};
QT_END_NAMESPACE
diff --git a/src/corelib/io/qfsfileengine_p.h b/src/corelib/io/qfsfileengine_p.h
index 3cc58ea993..dfc40e20b6 100644
--- a/src/corelib/io/qfsfileengine_p.h
+++ b/src/corelib/io/qfsfileengine_p.h
@@ -60,8 +60,12 @@ public:
bool isSequential() const override;
bool remove() override;
bool copy(const QString &newName) override;
- bool rename(const QString &newName) override;
- bool renameOverwrite(const QString &newName) override;
+
+ bool rename(const QString &newName) override
+ { return rename_helper(newName, Rename); }
+ bool renameOverwrite(const QString &newName) override
+ { return rename_helper(newName, RenameOverwrite); }
+
bool link(const QString &newName) override;
bool mkdir(const QString &dirName, bool createParentDirectories,
std::optional<QFile::Permissions> permissions) const override;
@@ -76,14 +80,15 @@ public:
QString fileName(FileName file) const override;
uint ownerId(FileOwner) const override;
QString owner(FileOwner) const override;
- bool setFileTime(const QDateTime &newDate, FileTime time) override;
- QDateTime fileTime(FileTime time) const override;
+ bool setFileTime(const QDateTime &newDate, QFile::FileTime time) override;
+ QDateTime fileTime(QFile::FileTime time) const override;
void setFileName(const QString &file) override;
+ void setFileEntry(QFileSystemEntry &&entry);
int handle() const override;
#ifndef QT_NO_FILESYSTEMITERATOR
- Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override;
- Iterator *endEntryList() override;
+ IteratorUniquePtr beginEntryList(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames) override;
#endif
qint64 read(char *data, qint64 maxlen) override;
@@ -110,6 +115,10 @@ public:
protected:
QFSFileEngine(QFSFileEnginePrivate &dd);
+
+private:
+ enum RenameMode : int { Rename, RenameOverwrite };
+ bool rename_helper(const QString &newName, RenameMode mode);
};
class Q_AUTOTEST_EXPORT QFSFileEnginePrivate : public QAbstractFileEnginePrivate
@@ -151,6 +160,9 @@ public:
#ifndef Q_OS_WIN
bool isSequentialFdFh() const;
#endif
+#ifdef Q_OS_WIN
+ bool nativeRenameOverwrite(const QFileSystemEntry &newEntry);
+#endif
uchar *map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags);
bool unmap(uchar *ptr);
diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp
index 217474cb7f..5806689182 100644
--- a/src/corelib/io/qfsfileengine_unix.cpp
+++ b/src/corelib/io/qfsfileengine_unix.cpp
@@ -160,9 +160,9 @@ bool QFSFileEnginePrivate::nativeSyncToDisk()
Q_Q(QFSFileEngine);
int ret;
#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
- EINTR_LOOP(ret, fdatasync(nativeHandle()));
+ QT_EINTR_LOOP(ret, fdatasync(nativeHandle()));
#else
- EINTR_LOOP(ret, fsync(nativeHandle()));
+ QT_EINTR_LOOP(ret, fsync(nativeHandle()));
#endif
if (ret != 0)
q->setError(QFile::WriteError, qt_error_string(errno));
@@ -525,7 +525,7 @@ bool QFSFileEngine::setSize(qint64 size)
return ret;
}
-bool QFSFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
+bool QFSFileEngine::setFileTime(const QDateTime &newDate, QFile::FileTime time)
{
Q_D(QFSFileEngine);
@@ -565,11 +565,11 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla
}
if (offset < 0 || offset > maxFileOffset
- || size < 0 || quint64(size) > quint64(size_t(-1))) {
+ || size <= 0
+ || quint64(size) > quint64(size_t(-1))) {
q->setError(QFile::UnspecifiedError, qt_error_string(EINVAL));
return nullptr;
}
-
// If we know the mapping will extend beyond EOF, fail early to avoid
// undefined behavior. Otherwise, let mmap have its say.
if (doStat(QFileSystemMetaData::SizeAttribute)
diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp
index daa4326212..4ac305f49b 100644
--- a/src/corelib/io/qfsfileengine_win.cpp
+++ b/src/corelib/io/qfsfileengine_win.cpp
@@ -27,6 +27,8 @@
#define SECURITY_WIN32
#include <security.h>
+#include <memory>
+
#ifndef PATH_MAX
#define PATH_MAX FILENAME_MAX
#endif
@@ -394,6 +396,35 @@ bool QFSFileEnginePrivate::nativeIsSequential() const
|| (fileType == FILE_TYPE_PIPE);
}
+bool QFSFileEnginePrivate::nativeRenameOverwrite(const QFileSystemEntry &newEntry)
+{
+ if (fileHandle == INVALID_HANDLE_VALUE)
+ return false;
+ const QString newFilePath = newEntry.nativeFilePath();
+ const size_t nameByteLength = newFilePath.length() * sizeof(wchar_t);
+ if (nameByteLength + sizeof(wchar_t) > std::numeric_limits<DWORD>::max())
+ return false;
+
+ constexpr size_t RenameInfoSize = sizeof(FILE_RENAME_INFO);
+ const size_t renameDataSize = RenameInfoSize + nameByteLength + sizeof(wchar_t);
+ QVarLengthArray<char> v(qsizetype(renameDataSize), 0);
+
+ auto *renameInfo = q20::construct_at(reinterpret_cast<FILE_RENAME_INFO *>(v.data()));
+ auto renameInfoRAII = qScopeGuard([&] { std::destroy_at(renameInfo); });
+ renameInfo->ReplaceIfExists = TRUE;
+ renameInfo->RootDirectory = nullptr;
+ renameInfo->FileNameLength = DWORD(nameByteLength);
+ memcpy(renameInfo->FileName, newFilePath.data(), nameByteLength);
+
+ bool res = SetFileInformationByHandle(fileHandle, FileRenameInfo, renameInfo,
+ DWORD(renameDataSize));
+ if (!res) {
+ DWORD error = GetLastError();
+ q_func()->setError(QFile::RenameError, qt_error_string(int(error)));
+ }
+ return res;
+}
+
bool QFSFileEngine::caseSensitive() const
{
return false;
@@ -706,7 +737,7 @@ bool QFSFileEngine::setSize(qint64 size)
return false;
}
-bool QFSFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
+bool QFSFileEngine::setFileTime(const QDateTime &newDate, QFile::FileTime time)
{
Q_D(QFSFileEngine);
@@ -715,7 +746,7 @@ bool QFSFileEngine::setFileTime(const QDateTime &newDate, FileTime time)
return false;
}
- if (!newDate.isValid() || time == QAbstractFileEngine::MetadataChangeTime) {
+ if (!newDate.isValid() || time == QFile::FileMetadataChangeTime) {
setError(QFile::UnspecifiedError, qt_error_string(ERROR_INVALID_PARAMETER));
return false;
}
diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp
index 29752c8e4c..b0029e2af7 100644
--- a/src/corelib/io/qiodevice.cpp
+++ b/src/corelib/io/qiodevice.cpp
@@ -9,7 +9,6 @@
#include "qfile.h"
#include "qstringlist.h"
#include "qdir.h"
-#include "private/qbytearray_p.h"
#include "private/qtools_p.h"
#include <algorithm>
@@ -45,6 +44,7 @@ static void debugBinaryString(const char *input, qint64 maxlen)
#define Q_VOID
+Q_DECL_COLD_FUNCTION
static void checkWarnMessage(const QIODevice *device, const char *function, const char *what)
{
#ifndef QT_NO_WARNING_OUTPUT
@@ -88,9 +88,9 @@ static void checkWarnMessage(const QIODevice *device, const char *function, cons
#define CHECK_MAXBYTEARRAYSIZE(function) \
do { \
- if (maxSize >= MaxByteArraySize) { \
+ if (maxSize >= QByteArray::max_size()) { \
checkWarnMessage(this, #function, "maxSize argument exceeds QByteArray size limit"); \
- maxSize = MaxByteArraySize - 1; \
+ maxSize = QByteArray::max_size() - 1; \
} \
} while (0)
@@ -1242,7 +1242,7 @@ QByteArray QIODevice::readAll()
: d->buffer.size());
qint64 readResult;
do {
- if (readBytes + readChunkSize >= MaxByteArraySize) {
+ if (readBytes + readChunkSize >= QByteArray::max_size()) {
// If resize would fail, don't read more, return what we have.
break;
}
@@ -1256,8 +1256,8 @@ QByteArray QIODevice::readAll()
} else {
// Read it all in one go.
readBytes -= d->pos;
- if (readBytes >= MaxByteArraySize)
- readBytes = MaxByteArraySize;
+ if (readBytes >= QByteArray::max_size())
+ readBytes = QByteArray::max_size();
result.resize(readBytes);
readBytes = d->read(result.data(), readBytes);
}
@@ -1448,7 +1448,7 @@ QByteArray QIODevice::readLine(qint64 maxSize)
qint64 readBytes = 0;
if (maxSize == 0) {
// Size is unknown, read incrementally.
- maxSize = MaxByteArraySize - 1;
+ maxSize = QByteArray::max_size() - 1;
// The first iteration needs to leave an extra byte for the terminating null
result.resize(1);
@@ -1500,7 +1500,7 @@ qint64 QIODevice::readLineData(char *data, qint64 maxSize)
Q_D(QIODevice);
qint64 readSoFar = 0;
char c;
- int lastReadReturn = 0;
+ qint64 lastReadReturn = 0;
d->baseReadLineDataCalled = true;
while (readSoFar < maxSize && (lastReadReturn = read(&c, 1)) == 1) {
diff --git a/src/corelib/io/qipaddress.cpp b/src/corelib/io/qipaddress.cpp
index 9956f03738..c2b274f8b5 100644
--- a/src/corelib/io/qipaddress.cpp
+++ b/src/corelib/io/qipaddress.cpp
@@ -61,7 +61,7 @@ static bool parseIp4Internal(IPv4Address &address, const char *ptr, bool acceptL
return false;
auto [ll, used] = qstrntoull(ptr, stop - ptr, 0);
- quint32 x = ll;
+ const quint32 x = quint32(ll);
if (used <= 0 || ll != x)
return false;
diff --git a/src/corelib/io/qlockfile.cpp b/src/corelib/io/qlockfile.cpp
index c90d2886c2..0eb6acb694 100644
--- a/src/corelib/io/qlockfile.cpp
+++ b/src/corelib/io/qlockfile.cpp
@@ -257,7 +257,7 @@ bool QLockFile::tryLock(int timeout)
return tryLock(std::chrono::milliseconds{ timeout });
}
-/*! \fn bool QLockFile::tryLock(std::chrono::milliseconds timeout)
+/*!
\overload
\since 6.2
@@ -275,11 +275,7 @@ bool QLockFile::tryLock(int timeout)
\sa lock(), unlock()
*/
-#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
bool QLockFile::tryLock(std::chrono::milliseconds timeout)
-#else
-bool QLockFile::tryLock_impl(std::chrono::milliseconds timeout)
-#endif
{
using namespace std::chrono_literals;
using Msec = std::chrono::milliseconds;
diff --git a/src/corelib/io/qlockfile.h b/src/corelib/io/qlockfile.h
index ecc26d137f..af481ab59b 100644
--- a/src/corelib/io/qlockfile.h
+++ b/src/corelib/io/qlockfile.h
@@ -28,14 +28,7 @@ public:
void setStaleLockTime(int);
int staleLockTime() const;
-#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
bool tryLock(std::chrono::milliseconds timeout = std::chrono::milliseconds::zero());
-#else
- bool tryLock(std::chrono::milliseconds timeout = std::chrono::milliseconds::zero())
- {
- return tryLock_impl(timeout);
- }
-#endif
void setStaleLockTime(std::chrono::milliseconds value);
std::chrono::milliseconds staleLockTimeAsDuration() const;
@@ -58,10 +51,6 @@ protected:
private:
Q_DECLARE_PRIVATE(QLockFile)
Q_DISABLE_COPY(QLockFile)
-
-#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
- bool tryLock_impl(std::chrono::milliseconds timeout);
-#endif
};
QT_END_NAMESPACE
diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp
index 34aa3b65ec..47aff8b973 100644
--- a/src/corelib/io/qlockfile_unix.cpp
+++ b/src/corelib/io/qlockfile_unix.cpp
@@ -170,7 +170,7 @@ bool QLockFilePrivate::removeStaleLock()
bool QLockFilePrivate::isProcessRunning(qint64 pid, const QString &appname)
{
- if (::kill(pid, 0) == -1 && errno == ESRCH)
+ if (::kill(pid_t(pid), 0) == -1 && errno == ESRCH)
return false; // PID doesn't exist anymore
const QString processName = processNameByPid(pid);
diff --git a/src/corelib/io/qloggingcategory.h b/src/corelib/io/qloggingcategory.h
index 5e0082e2aa..7c32beea1a 100644
--- a/src/corelib/io/qloggingcategory.h
+++ b/src/corelib/io/qloggingcategory.h
@@ -67,11 +67,6 @@ template <QtMsgType Which> struct QLoggingCategoryMacroHolder
if (IsOutputEnabled)
init(cat);
}
- explicit QLoggingCategoryMacroHolder(QMessageLogger::CategoryFunction catfunc)
- {
- if (IsOutputEnabled)
- init(catfunc());
- }
void init(const QLoggingCategory &cat) noexcept
{
category = &cat;
@@ -122,7 +117,7 @@ template <> const bool QLoggingCategoryMacroHolder<QtWarningMsg>::IsOutputEnable
}
#define QT_MESSAGE_LOGGER_COMMON(category, level) \
- for (QLoggingCategoryMacroHolder<level> qt_category(category); qt_category; qt_category.control = false) \
+ for (QLoggingCategoryMacroHolder<level> qt_category((category)()); qt_category; qt_category.control = false) \
QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC, qt_category.name())
#define qCDebug(category, ...) QT_MESSAGE_LOGGER_COMMON(category, QtDebugMsg).debug(__VA_ARGS__)
diff --git a/src/corelib/io/qloggingregistry.cpp b/src/corelib/io/qloggingregistry.cpp
index 3c835cce5a..b4181a2fa6 100644
--- a/src/corelib/io/qloggingregistry.cpp
+++ b/src/corelib/io/qloggingregistry.cpp
@@ -32,8 +32,7 @@ Q_GLOBAL_STATIC(QLoggingRegistry, qtLoggingRegistry)
\internal
Constructs a logging rule with default values.
*/
-QLoggingRule::QLoggingRule() :
- enabled(false)
+QLoggingRule::QLoggingRule()
{
}
@@ -41,9 +40,7 @@ QLoggingRule::QLoggingRule() :
\internal
Constructs a logging rule.
*/
-QLoggingRule::QLoggingRule(QStringView pattern, bool enabled) :
- messageType(-1),
- enabled(enabled)
+QLoggingRule::QLoggingRule(QStringView pattern, bool enabled) : enabled(enabled)
{
parse(pattern);
}
@@ -244,20 +241,29 @@ QLoggingRegistry::QLoggingRegistry()
static bool qtLoggingDebug()
{
- static const bool debugEnv = qEnvironmentVariableIsSet("QT_LOGGING_DEBUG");
+ static const bool debugEnv = [] {
+ bool debug = qEnvironmentVariableIsSet("QT_LOGGING_DEBUG");
+ if (debug)
+ debugMsg("QT_LOGGING_DEBUG environment variable is set.");
+ return debug;
+ }();
return debugEnv;
}
static QList<QLoggingRule> loadRulesFromFile(const QString &filePath)
{
+ if (qtLoggingDebug()) {
+ debugMsg("Checking \"%s\" for rules",
+ QDir::toNativeSeparators(filePath).toUtf8().constData());
+ }
+
QFile file(filePath);
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
- if (qtLoggingDebug())
- debugMsg("Loading \"%s\" ...",
- QDir::toNativeSeparators(file.fileName()).toUtf8().constData());
QTextStream stream(&file);
QLoggingSettingsParser parser;
parser.setContent(stream);
+ if (qtLoggingDebug())
+ debugMsg("Loaded %td rules", static_cast<ptrdiff_t>(parser.rules().size()));
return parser.rules();
}
return QList<QLoggingRule>();
@@ -270,19 +276,30 @@ static QList<QLoggingRule> loadRulesFromFile(const QString &filePath)
*/
void QLoggingRegistry::initializeRules()
{
+ if (qtLoggingDebug()) {
+ debugMsg("Initializing the rules database ...");
+ debugMsg("Checking %s environment variable", "QTLOGGING_CONF");
+ }
QList<QLoggingRule> er, qr, cr;
// get rules from environment
const QByteArray rulesFilePath = qgetenv("QT_LOGGING_CONF");
if (!rulesFilePath.isEmpty())
er = loadRulesFromFile(QFile::decodeName(rulesFilePath));
+ if (qtLoggingDebug())
+ debugMsg("Checking %s environment variable", "QT_LOGGING_RULES");
+
const QByteArray rulesSrc = qgetenv("QT_LOGGING_RULES").replace(';', '\n');
if (!rulesSrc.isEmpty()) {
- QTextStream stream(rulesSrc);
- QLoggingSettingsParser parser;
- parser.setImplicitRulesSection(true);
- parser.setContent(stream);
- er += parser.rules();
+ QTextStream stream(rulesSrc);
+ QLoggingSettingsParser parser;
+ parser.setImplicitRulesSection(true);
+ parser.setContent(stream);
+
+ if (qtLoggingDebug())
+ debugMsg("Loaded %td rules", static_cast<ptrdiff_t>(parser.rules().size()));
+
+ er += parser.rules();
}
const QString configFileName = QStringLiteral("qtlogging.ini");
@@ -347,10 +364,10 @@ void QLoggingRegistry::unregisterCategory(QLoggingCategory *cat)
for enabling debugging by default for category \a categoryName. The
category name must start with "qt."
*/
-void QLoggingRegistry::registerEnvironmentOverrideForCategory(QByteArrayView categoryName,
- QByteArrayView environment)
+void QLoggingRegistry::registerEnvironmentOverrideForCategory(const char *categoryName,
+ const char *environment)
{
- qtCategoryEnvironmentOverrides.insert(categoryName, environment);
+ qtCategoryEnvironmentOverrides.insert_or_assign(categoryName, environment);
}
/*!
@@ -442,7 +459,7 @@ void QLoggingRegistry::defaultCategoryFilter(QLoggingCategory *cat)
if (it == reg->qtCategoryEnvironmentOverrides.end())
debug = false;
else
- debug = qEnvironmentVariableIntValue(it.value().data());
+ debug = qEnvironmentVariableIntValue(it->second);
}
}
diff --git a/src/corelib/io/qloggingregistry_p.h b/src/corelib/io/qloggingregistry_p.h
index 4f18f6adf4..92b96f0ba4 100644
--- a/src/corelib/io/qloggingregistry_p.h
+++ b/src/corelib/io/qloggingregistry_p.h
@@ -19,11 +19,12 @@
#include <QtCore/qloggingcategory.h>
#include <QtCore/qlist.h>
#include <QtCore/qhash.h>
-#include <QtCore/qmap.h>
#include <QtCore/qmutex.h>
#include <QtCore/qstring.h>
#include <QtCore/qtextstream.h>
+#include <map>
+
class tst_QLoggingRegistry;
QT_BEGIN_NAMESPACE
@@ -54,9 +55,9 @@ public:
Q_DECLARE_FLAGS(PatternFlags, PatternFlag)
QString category;
- int messageType;
+ int messageType = -1;
PatternFlags flags;
- bool enabled;
+ bool enabled = false;
private:
void parse(QStringView pattern);
@@ -85,6 +86,7 @@ private:
class Q_AUTOTEST_EXPORT QLoggingRegistry
{
+ Q_DISABLE_COPY_MOVE(QLoggingRegistry)
public:
QLoggingRegistry();
@@ -96,7 +98,7 @@ public:
#ifndef QT_BUILD_INTERNAL
Q_CORE_EXPORT // always export from QtCore
#endif
- void registerEnvironmentOverrideForCategory(QByteArrayView categoryName, QByteArrayView environment);
+ void registerEnvironmentOverrideForCategory(const char *categoryName, const char *environment);
void setApiRules(const QString &content);
@@ -126,7 +128,7 @@ private:
QList<QLoggingRule> ruleSets[NumRuleSets];
QHash<QLoggingCategory *, QtMsgType> categories;
QLoggingCategory::CategoryFilter categoryFilter;
- QMap<QByteArrayView, QByteArrayView> qtCategoryEnvironmentOverrides;
+ std::map<QByteArrayView, const char *> qtCategoryEnvironmentOverrides;
friend class ::tst_QLoggingRegistry;
};
@@ -139,12 +141,12 @@ public:
{}
private:
- static const char *registerOverride(QByteArrayView categoryName, QByteArrayView environment)
+ static const char *registerOverride(const char *categoryName, const char *environment)
{
QLoggingRegistry *c = QLoggingRegistry::instance();
if (c)
c->registerEnvironmentOverrideForCategory(categoryName, environment);
- return categoryName.data();
+ return categoryName;
}
};
diff --git a/src/corelib/io/qnoncontiguousbytedevice.cpp b/src/corelib/io/qnoncontiguousbytedevice.cpp
index 87fa6f02bd..260fea7969 100644
--- a/src/corelib/io/qnoncontiguousbytedevice.cpp
+++ b/src/corelib/io/qnoncontiguousbytedevice.cpp
@@ -100,14 +100,18 @@ QNonContiguousByteDevice::~QNonContiguousByteDevice()
}
// FIXME we should scrap this whole implementation and instead change the ByteArrayImpl to be able to cope with sub-arrays?
-QNonContiguousByteDeviceBufferImpl::QNonContiguousByteDeviceBufferImpl(QBuffer *b) : QNonContiguousByteDevice()
+QNonContiguousByteDeviceBufferImpl::QNonContiguousByteDeviceBufferImpl(QBuffer *b)
+ : QNonContiguousByteDevice(),
+ buffer(b),
+ byteArray(QByteArray::fromRawData(buffer->buffer().constData() + buffer->pos(),
+ buffer->size() - buffer->pos())),
+ arrayImpl(new QNonContiguousByteDeviceByteArrayImpl(&byteArray))
{
- buffer = b;
- byteArray = QByteArray::fromRawData(buffer->buffer().constData() + buffer->pos(), buffer->size() - buffer->pos());
- arrayImpl = new QNonContiguousByteDeviceByteArrayImpl(&byteArray);
arrayImpl->setParent(this);
- connect(arrayImpl, SIGNAL(readyRead()), SIGNAL(readyRead()));
- connect(arrayImpl, SIGNAL(readProgress(qint64,qint64)), SIGNAL(readProgress(qint64,qint64)));
+ connect(arrayImpl, &QNonContiguousByteDevice::readyRead, this,
+ &QNonContiguousByteDevice::readyRead);
+ connect(arrayImpl, &QNonContiguousByteDevice::readProgress, this,
+ &QNonContiguousByteDevice::readProgress);
}
QNonContiguousByteDeviceBufferImpl::~QNonContiguousByteDeviceBufferImpl()
@@ -139,9 +143,9 @@ qint64 QNonContiguousByteDeviceBufferImpl::size() const
return arrayImpl->size();
}
-QNonContiguousByteDeviceByteArrayImpl::QNonContiguousByteDeviceByteArrayImpl(QByteArray *ba) : QNonContiguousByteDevice(), currentPosition(0)
+QNonContiguousByteDeviceByteArrayImpl::QNonContiguousByteDeviceByteArrayImpl(QByteArray *ba)
+ : QNonContiguousByteDevice(), byteArray(ba), currentPosition(0)
{
- byteArray = ba;
}
QNonContiguousByteDeviceByteArrayImpl::~QNonContiguousByteDeviceByteArrayImpl()
@@ -245,14 +249,19 @@ qint64 QNonContiguousByteDeviceRingBufferImpl::size() const
QNonContiguousByteDeviceIoDeviceImpl::QNonContiguousByteDeviceIoDeviceImpl(QIODevice *d)
: QNonContiguousByteDevice(),
- currentReadBuffer(nullptr), currentReadBufferSize(16*1024),
- currentReadBufferAmount(0), currentReadBufferPosition(0), totalAdvancements(0),
- eof(false)
+ device(d),
+ currentReadBuffer(nullptr),
+ currentReadBufferSize(16 * 1024),
+ currentReadBufferAmount(0),
+ currentReadBufferPosition(0),
+ totalAdvancements(0),
+ eof(false),
+ initialPosition(d->pos())
{
- device = d;
- initialPosition = d->pos();
- connect(device, SIGNAL(readyRead()), this, SIGNAL(readyRead()), Qt::QueuedConnection);
- connect(device, SIGNAL(readChannelFinished()), this, SIGNAL(readyRead()), Qt::QueuedConnection);
+ connect(device, &QIODevice::readyRead, this,
+ &QNonContiguousByteDevice::readyRead);
+ connect(device, &QIODevice::readChannelFinished, this,
+ &QNonContiguousByteDevice::readyRead);
}
QNonContiguousByteDeviceIoDeviceImpl::~QNonContiguousByteDeviceIoDeviceImpl()
@@ -262,7 +271,7 @@ QNonContiguousByteDeviceIoDeviceImpl::~QNonContiguousByteDeviceIoDeviceImpl()
const char *QNonContiguousByteDeviceIoDeviceImpl::readPointer(qint64 maximumLength, qint64 &len)
{
- if (eof == true) {
+ if (eof) {
len = -1;
return nullptr;
}
@@ -278,7 +287,8 @@ const char *QNonContiguousByteDeviceIoDeviceImpl::readPointer(qint64 maximumLeng
return currentReadBuffer->data() + currentReadBufferPosition;
}
- qint64 haveRead = device->read(currentReadBuffer->data(), qMin(maximumLength, currentReadBufferSize));
+ qint64 haveRead = device->read(currentReadBuffer->data(),
+ qMin(maximumLength, currentReadBufferSize));
if ((haveRead == -1) || (haveRead == 0 && device->atEnd() && !device->isSequential())) {
eof = true;
@@ -312,7 +322,7 @@ bool QNonContiguousByteDeviceIoDeviceImpl::advanceReadPointer(qint64 amount)
if (currentReadBufferPosition > currentReadBufferAmount) {
qint64 i = currentReadBufferPosition - currentReadBufferAmount;
while (i > 0) {
- if (device->getChar(nullptr) == false) {
+ if (!device->getChar(nullptr)) {
emit readProgress(totalAdvancements - i, size());
return false; // ### FIXME handle eof
}
@@ -328,7 +338,7 @@ bool QNonContiguousByteDeviceIoDeviceImpl::advanceReadPointer(qint64 amount)
bool QNonContiguousByteDeviceIoDeviceImpl::atEnd() const
{
- return eof == true;
+ return eof;
}
bool QNonContiguousByteDeviceIoDeviceImpl::reset()
@@ -367,18 +377,16 @@ qint64 QNonContiguousByteDeviceIoDeviceImpl::pos() const
return device->pos();
}
-QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd) : QIODevice((QObject*)nullptr)
+QByteDeviceWrappingIoDevice::QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd)
+ : QIODevice(nullptr), byteDevice(bd)
{
- byteDevice = bd;
- connect(bd, SIGNAL(readyRead()), SIGNAL(readyRead()));
+ connect(bd, &QNonContiguousByteDevice::readyRead, this, &QIODevice::readyRead);
open(ReadOnly);
}
QByteDeviceWrappingIoDevice::~QByteDeviceWrappingIoDevice()
-{
-
-}
+ = default;
bool QByteDeviceWrappingIoDevice::isSequential() const
{
@@ -483,9 +491,10 @@ std::shared_ptr<QNonContiguousByteDevice> QNonContiguousByteDeviceFactory::creat
\internal
*/
-QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(std::shared_ptr<QRingBuffer> ringBuffer)
+QNonContiguousByteDevice *
+QNonContiguousByteDeviceFactory::create(std::shared_ptr<QRingBuffer> ringBuffer)
{
- return new QNonContiguousByteDeviceRingBufferImpl(ringBuffer);
+ return new QNonContiguousByteDeviceRingBufferImpl(std::move(ringBuffer));
}
/*!
@@ -493,7 +502,8 @@ QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(std::shared_pt
\internal
*/
-std::shared_ptr<QNonContiguousByteDevice> QNonContiguousByteDeviceFactory::createShared(std::shared_ptr<QRingBuffer> ringBuffer)
+std::shared_ptr<QNonContiguousByteDevice>
+QNonContiguousByteDeviceFactory::createShared(std::shared_ptr<QRingBuffer> ringBuffer)
{
return std::make_shared<QNonContiguousByteDeviceRingBufferImpl>(std::move(ringBuffer));
}
@@ -515,7 +525,8 @@ QNonContiguousByteDevice* QNonContiguousByteDeviceFactory::create(QByteArray *by
\internal
*/
-std::shared_ptr<QNonContiguousByteDevice> QNonContiguousByteDeviceFactory::createShared(QByteArray *byteArray)
+std::shared_ptr<QNonContiguousByteDevice>
+QNonContiguousByteDeviceFactory::createShared(QByteArray *byteArray)
{
return std::make_shared<QNonContiguousByteDeviceByteArrayImpl>(byteArray);
}
diff --git a/src/corelib/io/qnoncontiguousbytedevice_p.h b/src/corelib/io/qnoncontiguousbytedevice_p.h
index 0daadbb714..eb75034c6a 100644
--- a/src/corelib/io/qnoncontiguousbytedevice_p.h
+++ b/src/corelib/io/qnoncontiguousbytedevice_p.h
@@ -66,6 +66,7 @@ public:
class QNonContiguousByteDeviceByteArrayImpl : public QNonContiguousByteDevice
{
+ Q_OBJECT
public:
explicit QNonContiguousByteDeviceByteArrayImpl(QByteArray *ba);
~QNonContiguousByteDeviceByteArrayImpl();
@@ -83,6 +84,7 @@ protected:
class QNonContiguousByteDeviceRingBufferImpl : public QNonContiguousByteDevice
{
+ Q_OBJECT
public:
explicit QNonContiguousByteDeviceRingBufferImpl(std::shared_ptr<QRingBuffer> rb);
~QNonContiguousByteDeviceRingBufferImpl();
@@ -143,6 +145,7 @@ protected:
// ... and the reverse thing
class QByteDeviceWrappingIoDevice : public QIODevice
{
+ Q_OBJECT
public:
explicit QByteDeviceWrappingIoDevice(QNonContiguousByteDevice *bd);
~QByteDeviceWrappingIoDevice();
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index a64f9c9cb5..108ee0b7c3 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -35,6 +35,8 @@ QT_BEGIN_NAMESPACE
\reentrant
\since 4.6
+ \compares equality
+
A process's environment is composed of a set of key=value pairs known as
environment variables. The QProcessEnvironment class wraps that concept
and allows easy manipulation of those variables. It's meant to be used
@@ -184,15 +186,17 @@ QProcessEnvironment &QProcessEnvironment::operator=(const QProcessEnvironment &o
*/
/*!
- \fn bool QProcessEnvironment::operator !=(const QProcessEnvironment &other) const
+ \fn bool QProcessEnvironment::operator!=(const QProcessEnvironment &lhs, const QProcessEnvironment &rhs)
- Returns \c true if this and the \a other QProcessEnvironment objects are different.
+ Returns \c true if the process environment objects \a lhs and \a rhs are different.
\sa operator==()
*/
/*!
- Returns \c true if this and the \a other QProcessEnvironment objects are equal.
+ \fn bool QProcessEnvironment::operator==(const QProcessEnvironment &lhs, const QProcessEnvironment &rhs)
+
+ Returns \c true if the process environment objects \a lhs and \a rhs are equal.
Two QProcessEnvironment objects are considered equal if they have the same
set of key=value pairs. The comparison of keys is done case-sensitive on
@@ -200,12 +204,12 @@ QProcessEnvironment &QProcessEnvironment::operator=(const QProcessEnvironment &o
\sa operator!=(), contains()
*/
-bool QProcessEnvironment::operator==(const QProcessEnvironment &other) const
+bool comparesEqual(const QProcessEnvironment &lhs, const QProcessEnvironment &rhs)
{
- if (d == other.d)
+ if (lhs.d == rhs.d)
return true;
- return d && other.d && d->vars == other.d->vars;
+ return lhs.d && rhs.d && lhs.d->vars == rhs.d->vars;
}
/*!
@@ -591,11 +595,6 @@ void QProcessPrivate::Channel::clear()
command line option; X11 applications generally accept a
\c{-geometry} command line option.
- \note On QNX, setting the working directory may cause all
- application threads, with the exception of the QProcess caller
- thread, to temporarily freeze during the spawning process,
- owing to a limitation in the operating system.
-
\section1 Synchronous Process API
QProcess provides a set of functions which allow it to be used
@@ -810,6 +809,98 @@ void QProcessPrivate::Channel::clear()
*/
/*!
+ \class QProcess::UnixProcessParameters
+ \inmodule QtCore
+ \note This struct is only available on Unix platforms
+ \since 6.6
+
+ This struct can be used to pass extra, Unix-specific configuration for the
+ child process using QProcess::setUnixProcessParameters().
+
+ Its members are:
+ \list
+ \li UnixProcessParameters::flags Flags, see QProcess::UnixProcessFlags
+ \li UnixProcessParameters::lowestFileDescriptorToClose The lowest file
+ descriptor to close.
+ \endlist
+
+ When the QProcess::UnixProcessFlags::CloseFileDescriptors flag is set in
+ the \c flags field, QProcess closes the application's open file descriptors
+ before executing the child process. The descriptors 0, 1, and 2 (that is,
+ \c stdin, \c stdout, and \c stderr) are left alone, along with the ones
+ numbered lower than the value of the \c lowestFileDescriptorToClose field.
+
+ All of the settings above can also be manually achieved by calling the
+ respective POSIX function from a handler set with
+ QProcess::setChildProcessModifier(). This structure allows QProcess to deal
+ with any platform-specific differences, benefit from certain optimizations,
+ and reduces code duplication. Moreover, if any of those functions fail,
+ QProcess will enter QProcess::FailedToStart state, while the child process
+ modifier callback is not allowed to fail.
+
+ \sa QProcess::setUnixProcessParameters(), QProcess::setChildProcessModifier()
+*/
+
+/*!
+ \enum QProcess::UnixProcessFlag
+ \since 6.6
+
+ These flags can be used in the \c flags field of \l UnixProcessParameters.
+
+ \value CloseFileDescriptors Close all file descriptors above the threshold
+ defined by \c lowestFileDescriptorToClose, preventing any currently
+ open descriptor in the parent process from accidentally leaking to the
+ child. The \c stdin, \c stdout, and \c stderr file descriptors are
+ never closed.
+
+ \value [since 6.7] CreateNewSession Starts a new process session, by calling
+ \c{setsid(2)}. This allows the child process to outlive the session
+ the current process is in. This is one of the steps that
+ startDetached() takes to allow the process to detach, and is also one
+ of the steps to daemonize a process.
+
+ \value [since 6.7] DisconnectControllingTerminal Requests that the process
+ disconnect from its controlling terminal, if it has one. If it has
+ none, nothing happens. Processes still connected to a controlling
+ terminal may get a Hang Up (\c SIGHUP) signal if the terminal
+ closes, or one of the other terminal-control signals (\c SIGTSTP, \c
+ SIGTTIN, \c SIGTTOU). Note that on some operating systems, a process
+ may only disconnect from the controlling terminal if it is the
+ session leader, meaning the \c CreateNewSession flag may be
+ required. Like it, this is one of the steps to daemonize a process.
+
+ \value IgnoreSigPipe Always sets the \c SIGPIPE signal to ignored
+ (\c SIG_IGN), even if the \c ResetSignalHandlers flag was set. By
+ default, if the child attempts to write to its standard output or
+ standard error after the respective channel was closed with
+ QProcess::closeReadChannel(), it would get the \c SIGPIPE signal and
+ terminate immediately; with this flag, the write operation fails
+ without a signal and the child may continue executing.
+
+ \value [since 6.7] ResetIds Drops any retained, effective user or group
+ ID the current process may still have (see \c{setuid(2)} and
+ \c{setgid(2)}, plus QCoreApplication::setSetuidAllowed()). This is
+ useful if the current process was setuid or setgid and does not wish
+ the child process to retain the elevated privileges.
+
+ \value ResetSignalHandlers Resets all Unix signal handlers back to their
+ default state (that is, pass \c SIG_DFL to \c{signal(2)}). This flag
+ is useful to ensure any ignored (\c SIG_IGN) signal does not affect
+ the child's behavior.
+
+ \value UseVFork Requests that QProcess use \c{vfork(2)} to start the child
+ process. Use this flag to indicate that the callback function set
+ with setChildProcessModifier() is safe to execute in the child side of
+ a \c{vfork(2)}; that is, the callback does not modify any non-local
+ variables (directly or through any function it calls), nor attempts
+ to communicate with the parent process. It is implementation-defined
+ if QProcess will actually use \c{vfork(2)} and if \c{vfork(2)} is
+ different from standard \c{fork(2)}.
+
+ \sa setUnixProcessParameters(), unixProcessParameters()
+*/
+
+/*!
\fn void QProcess::errorOccurred(QProcess::ProcessError error)
\since 5.6
@@ -927,7 +1018,7 @@ void QProcessPrivate::setErrorAndEmit(QProcess::ProcessError error, const QStrin
Q_Q(QProcess);
Q_ASSERT(error != QProcess::UnknownError);
setError(error, description);
- emit q->errorOccurred(processError);
+ emit q->errorOccurred(QProcess::ProcessError(processError));
}
/*!
@@ -1150,10 +1241,8 @@ void QProcessPrivate::processFinished()
cleanup();
- if (crashed) {
- exitStatus = QProcess::CrashExit;
+ if (exitStatus == QProcess::CrashExit)
setErrorAndEmit(QProcess::Crashed);
- }
// we received EOF now:
emit q->readChannelFinished();
@@ -1161,7 +1250,7 @@ void QProcessPrivate::processFinished()
//emit q->standardOutputClosed();
//emit q->standardErrorClosed();
- emit q->finished(exitCode, exitStatus);
+ emit q->finished(exitCode, QProcess::ExitStatus(exitStatus));
#if defined QPROCESS_DEBUG
qDebug("QProcessPrivate::processFinished(): process is dead");
@@ -1246,7 +1335,7 @@ QProcess::~QProcess()
QProcess::ProcessChannelMode QProcess::processChannelMode() const
{
Q_D(const QProcess);
- return d->processChannelMode;
+ return ProcessChannelMode(d->processChannelMode);
}
/*!
@@ -1276,7 +1365,7 @@ void QProcess::setProcessChannelMode(ProcessChannelMode mode)
QProcess::InputChannelMode QProcess::inputChannelMode() const
{
Q_D(const QProcess);
- return d->inputChannelMode;
+ return InputChannelMode(d->inputChannelMode);
}
/*!
@@ -1560,12 +1649,12 @@ void QProcess::setCreateProcessArgumentsModifier(CreateProcessArgumentModifier m
\note This function is only available on Unix platforms.
- \sa setChildProcessModifier()
+ \sa setChildProcessModifier(), unixProcessParameters()
*/
std::function<void(void)> QProcess::childProcessModifier() const
{
Q_D(const QProcess);
- return d->childProcessModifier;
+ return d->unixExtras ? d->unixExtras->childProcessModifier : std::function<void(void)>();
}
/*!
@@ -1574,20 +1663,28 @@ std::function<void(void)> QProcess::childProcessModifier() const
Sets the \a modifier function for the child process, for Unix systems
(including \macos; for Windows, see setCreateProcessArgumentsModifier()).
The function contained by the \a modifier argument will be invoked in the
- child process after \c{fork()} or \c{vfork()} is completed and QProcess has set up the
- standard file descriptors for the child process, but before \c{execve()},
- inside start(). The modifier is useful to change certain properties of the
- child process, such as setting up additional file descriptors or closing
- others, changing the nice level, disconnecting from the controlling TTY,
- etc.
+ child process after \c{fork()} or \c{vfork()} is completed and QProcess has
+ set up the standard file descriptors for the child process, but before
+ \c{execve()}, inside start().
The following shows an example of setting up a child process to run without
privileges:
\snippet code/src_corelib_io_qprocess.cpp 4
- If the modifier function needs to exit the process, remember to use
- \c{_exit()}, not \c{exit()}.
+ If the modifier function experiences a failure condition, it can use
+ failChildProcessModifier() to report the situation to the QProcess caller.
+ Alternatively, it may use other methods of stopping the process, like
+ \c{_exit()}, or \c{abort()}.
+
+ Certain properties of the child process, such as closing all extraneous
+ file descriptors or disconnecting from the controlling TTY, can be more
+ readily achieved by using setUnixProcessParameters(), which can detect
+ failure and report a \l{QProcess::}{FailedToStart} condition. The modifier
+ is useful to change certain uncommon properties of the child process, such
+ as setting up additional file descriptors. If both a child process modifier
+ and Unix process parameters are set, the modifier is run before these
+ parameters are applied.
\note In multithreaded applications, this function must be careful not to
call any functions that may lock mutexes that may have been in use in
@@ -1595,21 +1692,125 @@ std::function<void(void)> QProcess::childProcessModifier() const
"async-signal-safe" is advised). Most of the Qt API is unsafe inside this
callback, including qDebug(), and may lead to deadlocks.
- \note On some systems (notably, Linux), QProcess will use \c{vfork()}
- semantics to start the child process, so this function must obey even
- stricter constraints. First, because it is still sharing memory with the
- parent process, it must not write to any non-local variable and must obey
- proper ordering semantics when reading from them, to avoid data races.
- Second, even more library functions may misbehave; therefore, this function
- should only make use of low-level system calls, such as \c{read()},
+ \note If the UnixProcessParameters::UseVFork flag is set via
+ setUnixProcessParameters(), QProcess may use \c{vfork()} semantics to
+ start the child process, so this function must obey even stricter
+ constraints. First, because it is still sharing memory with the parent
+ process, it must not write to any non-local variable and must obey proper
+ ordering semantics when reading from them, to avoid data races. Second,
+ even more library functions may misbehave; therefore, this function should
+ only make use of low-level system calls, such as \c{read()},
\c{write()}, \c{setsid()}, \c{nice()}, and similar.
- \sa childProcessModifier()
+ \sa childProcessModifier(), failChildProcessModifier(), setUnixProcessParameters()
*/
void QProcess::setChildProcessModifier(const std::function<void(void)> &modifier)
{
Q_D(QProcess);
- d->childProcessModifier = modifier;
+ if (!d->unixExtras)
+ d->unixExtras.reset(new QProcessPrivate::UnixExtras);
+ d->unixExtras->childProcessModifier = modifier;
+}
+
+/*!
+ \fn void QProcess::failChildProcessModifier(const char *description, int error) noexcept
+ \since 6.7
+
+ This functions can be used inside the modifier set with
+ setChildProcessModifier() to indicate an error condition was encountered.
+ When the modifier calls these functions, QProcess will emit errorOccurred()
+ with code QProcess::FailedToStart in the parent process. The \a description
+ can be used to include some information in errorString() to help diagnose
+ the problem, usually the name of the call that failed, similar to the C
+ Library function \c{perror()}. Additionally, the \a error parameter can be
+ an \c{<errno.h>} error code whose text form will also be included.
+
+ For example, a child modifier could prepare an extra file descriptor for
+ the child process this way:
+
+ \code
+ process.setChildProcessModifier([fd, &process]() {
+ if (dup2(fd, TargetFileDescriptor) < 0)
+ process.failChildProcessModifier(errno, "aux comm channel");
+ });
+ process.start();
+ \endcode
+
+ Where \c{fd} is a file descriptor currently open in the parent process. If
+ the \c{dup2()} system call resulted in an \c EBADF condition, the process
+ errorString() could be "Child process modifier reported error: aux comm
+ channel: Bad file descriptor".
+
+ This function does not return to the caller. Using it anywhere except in
+ the child modifier and with the correct QProcess object is undefined
+ behavior.
+
+ \note The implementation imposes a length limit to the \a description
+ parameter to about 500 characters. This does not include the text from the
+ \a error code.
+
+ \sa setChildProcessModifier(), setUnixProcessParameters()
+*/
+
+/*!
+ \since 6.6
+ Returns the \l UnixProcessParameters object describing extra flags and
+ settings that will be applied to the child process on Unix systems. The
+ default settings correspond to a default-constructed UnixProcessParameters.
+
+ \note This function is only available on Unix platforms.
+
+ \sa childProcessModifier()
+*/
+auto QProcess::unixProcessParameters() const noexcept -> UnixProcessParameters
+{
+ Q_D(const QProcess);
+ return d->unixExtras ? d->unixExtras->processParameters : UnixProcessParameters{};
+}
+
+/*!
+ \since 6.6
+ Sets the extra settings and parameters for the child process on Unix
+ systems to be \a params. This function can be used to ask QProcess to
+ modify the child process before launching the target executable.
+
+ This function can be used to change certain properties of the child
+ process, such as closing all extraneous file descriptors, changing the nice
+ level of the child, or disconnecting from the controlling TTY. For more
+ fine-grained control of the child process or to modify it in other ways,
+ use the setChildProcessModifier() function. If both a child process
+ modifier and Unix process parameters are set, the modifier is run before
+ these parameters are applied.
+
+ \note This function is only available on Unix platforms.
+
+ \sa unixProcessParameters(), setChildProcessModifier()
+*/
+void QProcess::setUnixProcessParameters(const UnixProcessParameters &params)
+{
+ Q_D(QProcess);
+ if (!d->unixExtras)
+ d->unixExtras.reset(new QProcessPrivate::UnixExtras);
+ d->unixExtras->processParameters = params;
+}
+
+/*!
+ \since 6.6
+ \overload
+
+ Sets the extra settings for the child process on Unix systems to \a
+ flagsOnly. This is the same as the overload with just the \c flags field
+ set.
+ \note This function is only available on Unix platforms.
+
+ \sa unixProcessParameters(), setChildProcessModifier()
+*/
+void QProcess::setUnixProcessParameters(UnixProcessFlags flagsOnly)
+{
+ Q_D(QProcess);
+ if (!d->unixExtras)
+ d->unixExtras.reset(new QProcessPrivate::UnixExtras);
+ d->unixExtras->processParameters = { flagsOnly };
}
#endif
@@ -1633,9 +1834,6 @@ QString QProcess::workingDirectory() const
process in this directory. The default behavior is to start the
process in the working directory of the calling process.
- \note On QNX, this may cause all application threads to
- temporarily freeze.
-
\sa workingDirectory(), start()
*/
void QProcess::setWorkingDirectory(const QString &dir)
@@ -1703,7 +1901,7 @@ qint64 QProcess::bytesToWrite() const
QProcess::ProcessError QProcess::error() const
{
Q_D(const QProcess);
- return d->processError;
+ return ProcessError(d->processError);
}
/*!
@@ -1714,7 +1912,7 @@ QProcess::ProcessError QProcess::error() const
QProcess::ProcessState QProcess::state() const
{
Q_D(const QProcess);
- return d->processState;
+ return ProcessState(d->processState);
}
/*!
@@ -1791,7 +1989,8 @@ QProcessEnvironment QProcess::processEnvironment() const
Returns \c true if the process was started successfully; otherwise
returns \c false (if the operation timed out or if an error
- occurred).
+ occurred). If the process had already started successfully before this
+ function, it returns immediately.
This function can operate without an event loop. It is
useful when writing non-GUI applications and when performing
@@ -1802,9 +2001,6 @@ QProcessEnvironment QProcess::processEnvironment() const
If msecs is -1, this function will not time out.
- \note On some UNIX operating systems, this function may return true but
- the process may later report a QProcess::FailedToStart error.
-
\sa started(), waitForReadyRead(), waitForBytesWritten(), waitForFinished()
*/
bool QProcess::waitForStarted(int msecs)
@@ -1970,18 +2166,22 @@ QByteArray QProcess::readAllStandardError()
/*!
Starts the given \a program in a new process, passing the command line
arguments in \a arguments. See setProgram() for information about how
- QProcess searches for the executable to be run.
+ QProcess searches for the executable to be run. The OpenMode is set to \a
+ mode. No further splitting of the arguments is performed.
The QProcess object will immediately enter the Starting state. If the
process starts successfully, QProcess will emit started(); otherwise,
- errorOccurred() will be emitted.
-
- \note Processes are started asynchronously, which means the started()
- and errorOccurred() signals may be delayed. Call waitForStarted() to make
- sure the process has started (or has failed to start) and those signals
- have been emitted.
-
- \note No further splitting of the arguments is performed.
+ errorOccurred() will be emitted. Do note that on platforms that are able to
+ start child processes synchronously (notably Windows), those signals will
+ be emitted before this function returns and this QProcess object will
+ transition to either QProcess::Running or QProcess::NotRunning state,
+ respectively. On others paltforms, the started() and errorOccurred()
+ signals will be delayed.
+
+ Call waitForStarted() to make sure the process has started (or has failed
+ to start) and those signals have been emitted. It is safe to call that
+ function even if the process starting state is already known, though the
+ signal will not be emitted again.
\b{Windows:} The arguments are quoted and joined into a command line
that is compatible with the \c CommandLineToArgvW() Windows function.
@@ -1990,12 +2190,16 @@ QByteArray QProcess::readAllStandardError()
not follow the \c CommandLineToArgvW() rules is cmd.exe and, by
consequence, all batch scripts.
- The OpenMode is set to \a mode.
-
If the QProcess object is already running a process, a warning may be
printed at the console, and the existing process will continue running
unaffected.
+ \note Success at starting the child process only implies the operating
+ system has successfully created the process and assigned the resources
+ every process has, such as its process ID. The child process may crash or
+ otherwise fail very early and thus not produce its expected output. On most
+ operating systems, this may include dynamic linking errors.
+
\sa processId(), started(), waitForStarted(), setNativeArguments()
*/
void QProcess::start(const QString &program, const QStringList &arguments, OpenMode mode)
@@ -2077,6 +2281,10 @@ void QProcess::start(OpenMode mode)
void QProcess::startCommand(const QString &command, OpenMode mode)
{
QStringList args = splitCommand(command);
+ if (args.isEmpty()) {
+ qWarning("QProcess::startCommand: empty or whitespace-only command was provided");
+ return;
+ }
const QString program = args.takeFirst();
start(program, args, mode);
}
@@ -2096,9 +2304,6 @@ void QProcess::startCommand(const QString &command, OpenMode mode)
If workingDirectory() is empty, the working directory is inherited
from the calling process.
- \note On QNX, this may cause all application threads to
- temporarily freeze.
-
If the function is successful then *\a pid is set to the process identifier
of the started process; otherwise, it's set to -1. Note that the child
process may exit and the PID may become invalid without notice.
@@ -2386,7 +2591,7 @@ int QProcess::exitCode() const
QProcess::ExitStatus QProcess::exitStatus() const
{
Q_D(const QProcess);
- return d->exitStatus;
+ return ExitStatus(d->exitStatus);
}
/*!
diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h
index 4fa1037b38..34724a6794 100644
--- a/src/corelib/io/qprocess.h
+++ b/src/corelib/io/qprocess.h
@@ -1,9 +1,11 @@
// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2023 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPROCESS_H
#define QPROCESS_H
+#include <QtCore/qcompare.h>
#include <QtCore/qiodevice.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qshareddata.h>
@@ -40,9 +42,11 @@ public:
void swap(QProcessEnvironment &other) noexcept { d.swap(other.d); }
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QProcessEnvironment &other) const;
inline bool operator!=(const QProcessEnvironment &other) const
- { return !(*this == other); }
+ { return !operator==(other); }
+#endif
bool isEmpty() const;
[[nodiscard]] bool inheritsFromParent() const;
@@ -62,6 +66,9 @@ public:
static QProcessEnvironment systemEnvironment();
private:
+ friend Q_CORE_EXPORT bool comparesEqual(const QProcessEnvironment &lhs,
+ const QProcessEnvironment &rhs);
+ Q_DECLARE_EQUALITY_COMPARABLE(QProcessEnvironment)
friend class QProcessPrivate;
friend class QProcessEnvironmentPrivate;
QSharedDataPointer<QProcessEnvironmentPrivate> d;
@@ -173,6 +180,29 @@ public:
#if defined(Q_OS_UNIX) || defined(Q_QDOC)
std::function<void(void)> childProcessModifier() const;
void setChildProcessModifier(const std::function<void(void)> &modifier);
+ Q_NORETURN void failChildProcessModifier(const char *description, int error = 0) noexcept;
+
+ enum class UnixProcessFlag : quint32 {
+ ResetSignalHandlers = 0x0001, // like POSIX_SPAWN_SETSIGDEF
+ IgnoreSigPipe = 0x0002,
+ // some room if we want to add IgnoreSigHup or so
+ CloseFileDescriptors = 0x0010,
+ UseVFork = 0x0020, // like POSIX_SPAWN_USEVFORK
+ CreateNewSession = 0x0040, // like POSIX_SPAWN_SETSID
+ DisconnectControllingTerminal = 0x0080,
+ ResetIds = 0x0100, // like POSIX_SPAWN_RESETIDS
+ };
+ Q_DECLARE_FLAGS(UnixProcessFlags, UnixProcessFlag)
+ struct UnixProcessParameters
+ {
+ UnixProcessFlags flags = {};
+ int lowestFileDescriptorToClose = 0;
+
+ quint32 _reserved[6] {};
+ };
+ UnixProcessParameters unixProcessParameters() const noexcept;
+ void setUnixProcessParameters(const UnixProcessParameters &params);
+ void setUnixProcessParameters(UnixProcessFlags flagsOnly);
#endif
QString workingDirectory() const;
@@ -256,6 +286,10 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_processDied())
};
+#ifdef Q_OS_UNIX
+Q_DECLARE_OPERATORS_FOR_FLAGS(QProcess::UnixProcessFlags)
+#endif
+
#endif // QT_CONFIG(process)
QT_END_NAMESPACE
diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h
index 929c06480b..9510101e74 100644
--- a/src/corelib/io/qprocess_p.h
+++ b/src/corelib/io/qprocess_p.h
@@ -259,20 +259,6 @@ public:
bool _q_startupNotification();
void _q_processDied();
- QProcess::ProcessChannelMode processChannelMode = QProcess::SeparateChannels;
- QProcess::InputChannelMode inputChannelMode = QProcess::ManagedInputChannel;
- QProcess::ProcessError processError = QProcess::UnknownError;
- QProcess::ProcessState processState = QProcess::NotRunning;
- QString workingDirectory;
-#ifdef Q_OS_WIN
- Q_PROCESS_INFORMATION *pid = nullptr;
-#else
- qint64 pid = 0;
-#endif
-
- bool emittedReadyRead = false;
- bool emittedBytesWritten = false;
-
Channel stdinChannel;
Channel stdoutChannel;
Channel stderrChannel;
@@ -286,27 +272,38 @@ public:
QString program;
QStringList arguments;
+ QString workingDirectory;
+ QProcessEnvironment environment = QProcessEnvironment::InheritFromParent;
#if defined(Q_OS_WIN)
QString nativeArguments;
QProcess::CreateProcessArgumentModifier modifyCreateProcessArgs;
+ QWinEventNotifier *processFinishedNotifier = nullptr;
+ Q_PROCESS_INFORMATION *pid = nullptr;
#else
- std::function<void(void)> childProcessModifier;
-#endif
- QProcessEnvironment environment = QProcessEnvironment::InheritFromParent;
-
-#ifdef Q_OS_UNIX
- Q_PIPE childStartedPipe[2] = {INVALID_Q_PIPE, INVALID_Q_PIPE};
+ struct UnixExtras {
+ std::function<void(void)> childProcessModifier;
+ QProcess::UnixProcessParameters processParameters;
+ };
+ std::unique_ptr<UnixExtras> unixExtras;
QSocketNotifier *stateNotifier = nullptr;
+ Q_PIPE childStartedPipe[2] = {INVALID_Q_PIPE, INVALID_Q_PIPE};
+ pid_t pid = 0;
int forkfd = -1;
-#else
- QWinEventNotifier *processFinishedNotifier = nullptr;
#endif
+ int exitCode = 0;
+ quint8 processState = QProcess::NotRunning;
+ quint8 exitStatus = QProcess::NormalExit;
+ quint8 processError = QProcess::UnknownError;
+ quint8 processChannelMode = QProcess::SeparateChannels;
+ quint8 inputChannelMode = QProcess::ManagedInputChannel;
+ bool emittedReadyRead = false;
+ bool emittedBytesWritten = false;
+
void start(QIODevice::OpenMode mode);
void startProcess();
#if defined(Q_OS_UNIX)
void commitChannels() const;
- void execChild(const char *workingDirectory, char **argv, char **envp) const;
#endif
bool processStarted(QString *errorMessage = nullptr);
void processFinished();
@@ -325,10 +322,6 @@ public:
bool startDetached(qint64 *pPid);
- int exitCode = 0;
- QProcess::ExitStatus exitStatus = QProcess::NormalExit;
- bool crashed = false;
-
bool waitForStarted(const QDeadlineTimer &deadline);
bool waitForReadyRead(const QDeadlineTimer &deadline);
bool waitForBytesWritten(const QDeadlineTimer &deadline);
@@ -341,6 +334,9 @@ public:
void cleanup();
void setError(QProcess::ProcessError error, const QString &description = QString());
void setErrorAndEmit(QProcess::ProcessError error, const QString &description = QString());
+
+ const QProcessEnvironmentPrivate *environmentPrivate() const
+ { return environment.d.constData(); }
};
#endif // QT_CONFIG(process)
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp
index 27c1403226..5c696433fd 100644
--- a/src/corelib/io/qprocess_unix.cpp
+++ b/src/corelib/io/qprocess_unix.cpp
@@ -36,21 +36,43 @@
#include <limits.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/resource.h>
+#include <termios.h>
+#include <unistd.h>
+
+#if __has_include(<paths.h>)
+# include <paths.h>
+#endif
+#if __has_include(<linux/close_range.h>)
+// FreeBSD's is in <unistd.h>
+# include <linux/close_range.h>
+#endif
#if QT_CONFIG(process)
#include <forkfd.h>
#endif
+#ifndef O_PATH
+# define O_PATH 0
+#endif
+#ifndef _PATH_DEV
+# define _PATH_DEV "/dev/"
+#endif
+#ifndef _PATH_TTY
+# define _PATH_TTY _PATH_DEV "tty"
+#endif
+
+#ifdef Q_OS_FREEBSD
+__attribute__((weak))
+#endif
+extern char **environ;
+
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
#if !defined(Q_OS_DARWIN)
-QT_BEGIN_INCLUDE_NAMESPACE
-extern char **environ;
-QT_END_INCLUDE_NAMESPACE
-
QProcessEnvironment QProcessEnvironment::systemEnvironment()
{
QProcessEnvironment env;
@@ -72,6 +94,70 @@ QProcessEnvironment QProcessEnvironment::systemEnvironment()
#if QT_CONFIG(process)
+namespace QtVforkSafe {
+// Certain libc functions we need to call in the child process scenario aren't
+// safe under vfork() because they do more than just place the system call to
+// the kernel and set errno on return. For those, we'll create a function
+// pointer like:
+// static constexpr auto foobar = __libc_foobar;
+// while for all other OSes, it'll be
+// using ::foobar;
+// allowing the code for the child side of the vfork to simply use
+// QtVforkSafe::foobar(args);
+//
+// Currently known issues are:
+//
+// - FreeBSD's libthr sigaction() wrapper locks a rwlock
+// https://github.com/freebsd/freebsd-src/blob/8dad5ece49479ba6cdcd5bb4c2799bbd61add3e6/lib/libthr/thread/thr_sig.c#L575-L641
+// - MUSL's sigaction() locks a mutex if the signal is SIGABR
+// https://github.com/bminor/musl/blob/718f363bc2067b6487900eddc9180c84e7739f80/src/signal/sigaction.c#L63-L85
+//
+// All other functions called in the child side are vfork-safe, provided that
+// PThread cancellation is disabled and Unix signals are blocked.
+#if defined(__MUSL__)
+# define LIBC_PREFIX __libc_
+#elif defined(Q_OS_FREEBSD)
+// will cause QtCore to link to ELF version "FBSDprivate_1.0"
+# define LIBC_PREFIX _
+#endif
+
+#ifdef LIBC_PREFIX
+# define CONCAT(x, y) CONCAT2(x, y)
+# define CONCAT2(x, y) x ## y
+# define DECLARE_FUNCTIONS(NAME) \
+ extern decltype(::NAME) CONCAT(LIBC_PREFIX, NAME); \
+ static constexpr auto NAME = std::addressof(CONCAT(LIBC_PREFIX, NAME));
+#else // LIBC_PREFIX
+# define DECLARE_FUNCTIONS(NAME) using ::NAME;
+#endif // LIBC_PREFIX
+
+extern "C" {
+DECLARE_FUNCTIONS(sigaction)
+}
+
+#undef LIBC_PREFIX
+#undef DECLARE_FUNCTIONS
+
+// similar to qt_ignore_sigpipe() in qcore_unix_p.h, but vfork-safe
+static void change_sigpipe(decltype(SIG_DFL) new_handler)
+{
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = new_handler;
+ sigaction(SIGPIPE, &sa, nullptr);
+}
+} // namespace QtVforkSafe
+
+static int opendirfd(QByteArray encodedName)
+{
+ // We append "/." to the name to ensure that the directory is actually
+ // traversable (i.e., has the +x bit set). This avoids later problems
+ // with fchdir().
+ if (encodedName != "/" && !encodedName.endsWith("/."))
+ encodedName += "/.";
+ return qt_safe_open(encodedName, QT_OPEN_RDONLY | O_DIRECTORY | O_PATH);
+}
+
namespace {
struct AutoPipe
{
@@ -95,22 +181,13 @@ struct AutoPipe
struct ChildError
{
- qint64 code;
- char function[8];
-};
-
-// Used for argv and envp arguments to execve()
-struct CharPointerList
-{
- std::unique_ptr<char *[]> pointers;
-
- CharPointerList(const QString &argv0, const QStringList &args);
- explicit CharPointerList(const QProcessEnvironmentPrivate *env);
-
-private:
- QByteArray data;
- void updatePointers(qsizetype count);
+ int code;
+ char function[_POSIX_PIPE_BUF - sizeof(code)];
};
+static_assert(std::is_trivial_v<ChildError>);
+#ifdef PIPE_BUF
+static_assert(PIPE_BUF >= sizeof(ChildError)); // PIPE_BUF may be bigger
+#endif
struct QProcessPoller
{
@@ -145,10 +222,139 @@ QProcessPoller::QProcessPoller(const QProcessPrivate &proc)
int QProcessPoller::poll(const QDeadlineTimer &deadline)
{
- return qt_poll_msecs(pfds, n_pfds, deadline.remainingTime());
+ return qt_safe_poll(pfds, n_pfds, deadline);
}
-CharPointerList::CharPointerList(const QString &program, const QStringList &args)
+struct QChildProcess
+{
+ // Used for argv and envp arguments to execve()
+ struct CharPointerList
+ {
+ std::unique_ptr<char *[]> pointers;
+
+ CharPointerList(const QString &argv0, const QStringList &args);
+ explicit CharPointerList(const QProcessEnvironmentPrivate *env);
+ /*implicit*/ operator char **() const { return pointers.get(); }
+
+ private:
+ QByteArray data;
+ void updatePointers(qsizetype count);
+ };
+
+ const QProcessPrivate *d;
+ CharPointerList argv;
+ CharPointerList envp;
+ sigset_t oldsigset;
+ int workingDirectory = -2;
+ bool isUsingVfork = usingVfork();
+
+ bool ok() const
+ {
+ return workingDirectory != -1;
+ }
+
+ QChildProcess(QProcessPrivate *d)
+ : d(d), argv(resolveExecutable(d->program), d->arguments),
+ envp(d->environmentPrivate())
+ {
+ // Block Unix signals, to ensure the user's handlers aren't run in the
+ // child side and do something weird, especially if the handler and the
+ // user of QProcess are completely different codebases.
+ maybeBlockSignals();
+
+ // Disable PThread cancellation until the child has successfully been
+ // executed. We make a number of POSIX calls in the child that are thread
+ // cancellation points and could cause an unexpected stack unwind. That
+ // would be bad enough with regular fork(), but it's likely fatal with
+ // vfork().
+ disableThreadCancellations();
+
+ if (!d->workingDirectory.isEmpty()) {
+ workingDirectory = opendirfd(QFile::encodeName(d->workingDirectory));
+ if (workingDirectory < 0) {
+ d->setErrorAndEmit(QProcess::FailedToStart, "chdir: "_L1 + qt_error_string());
+ d->cleanup();
+ }
+ }
+
+ }
+ ~QChildProcess() noexcept(false)
+ {
+ if (workingDirectory >= 0)
+ close(workingDirectory);
+
+ restoreThreadCancellations();
+ restoreSignalMask();
+ }
+
+ void maybeBlockSignals() noexcept
+ {
+ // We only block Unix signals if we're using vfork(), to avoid a
+ // changing behavior to the user's modifier and because in some OSes
+ // this action would block crashing signals too.
+ if (isUsingVfork) {
+ sigset_t emptyset;
+ sigfillset(&emptyset);
+ pthread_sigmask(SIG_SETMASK, &emptyset, &oldsigset);
+ }
+ }
+
+ void restoreSignalMask() const noexcept
+ {
+ if (isUsingVfork)
+ pthread_sigmask(SIG_SETMASK, &oldsigset, nullptr);
+ }
+
+ bool usingVfork() const noexcept;
+
+ template <typename Lambda> int doFork(Lambda &&childLambda)
+ {
+ pid_t pid;
+ if (isUsingVfork) {
+ QT_IGNORE_DEPRECATIONS(pid = vfork();)
+ } else {
+ pid = fork();
+ }
+ if (pid == 0)
+ _exit(childLambda());
+ return pid;
+ }
+
+ int startChild(pid_t *pid)
+ {
+ int ffdflags = FFD_CLOEXEC | (isUsingVfork ? 0 : FFD_USE_FORK);
+ return ::vforkfd(ffdflags, pid, &QChildProcess::startProcess, this);
+ }
+
+private:
+ Q_NORETURN void startProcess() const noexcept;
+ static int startProcess(void *self) noexcept
+ {
+ static_cast<QChildProcess *>(self)->startProcess();
+ Q_UNREACHABLE_RETURN(-1);
+ }
+
+#if defined(PTHREAD_CANCEL_DISABLE)
+ int oldstate;
+ void disableThreadCancellations() noexcept
+ {
+ // the following is *not* noexcept, but it won't throw while disabling
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
+ }
+ void restoreThreadCancellations() noexcept(false)
+ {
+ // this doesn't touch errno
+ pthread_setcancelstate(oldstate, nullptr);
+ }
+#else
+ void disableThreadCancellations() noexcept {}
+ void restoreThreadCancellations() {}
+#endif
+
+ static QString resolveExecutable(const QString &program);
+};
+
+QChildProcess::CharPointerList::CharPointerList(const QString &program, const QStringList &args)
{
qsizetype count = 1 + args.size();
pointers.reset(new char *[count + 1]);
@@ -171,7 +377,7 @@ CharPointerList::CharPointerList(const QString &program, const QStringList &args
updatePointers(count);
}
-CharPointerList::CharPointerList(const QProcessEnvironmentPrivate *environment)
+QChildProcess::CharPointerList::CharPointerList(const QProcessEnvironmentPrivate *environment)
{
if (!environment)
return;
@@ -197,7 +403,7 @@ CharPointerList::CharPointerList(const QProcessEnvironmentPrivate *environment)
updatePointers(count);
}
-void CharPointerList::updatePointers(qsizetype count)
+void QChildProcess::CharPointerList::updatePointers(qsizetype count)
{
char *const base = const_cast<char *>(data.constBegin());
for (qsizetype i = 0; i < count; ++i)
@@ -218,7 +424,8 @@ static int qt_create_pipe(int *pipe)
qt_safe_close(pipe[1]);
int pipe_ret = qt_safe_pipe(pipe);
if (pipe_ret != 0) {
- qErrnoWarning("QProcessPrivate::createPipe: Cannot create pipe %p", pipe);
+ QScopedValueRollback rollback(errno);
+ qErrnoWarning("QProcess: Cannot create pipe");
}
return pipe_ret;
}
@@ -267,8 +474,10 @@ bool QProcessPrivate::openChannel(Channel &channel)
if (channel.type == Channel::Normal) {
// we're piping this channel to our own process
- if (qt_create_pipe(channel.pipe) != 0)
+ if (qt_create_pipe(channel.pipe) != 0) {
+ setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
return false;
+ }
// create the socket notifiers
if (threadData.loadRelaxed()->hasEventDispatcher()) {
@@ -316,7 +525,6 @@ bool QProcessPrivate::openChannel(Channel &channel)
setErrorAndEmit(QProcess::FailedToStart,
QProcess::tr("Could not open input redirection for reading"));
}
- cleanup();
return false;
} else {
Q_ASSERT_X(channel.process, "QProcess::start", "Internal error");
@@ -348,8 +556,10 @@ bool QProcessPrivate::openChannel(Channel &channel)
Q_ASSERT(sink->pipe[0] == INVALID_Q_PIPE && sink->pipe[1] == INVALID_Q_PIPE);
Q_PIPE pipe[2] = { -1, -1 };
- if (qt_create_pipe(pipe) != 0)
+ if (qt_create_pipe(pipe) != 0) {
+ setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
return false;
+ }
sink->pipe[0] = pipe[0];
source->pipe[1] = pipe[1];
@@ -376,7 +586,7 @@ void QProcessPrivate::commitChannels() const
}
}
-static QString resolveExecutable(const QString &program)
+inline QString QChildProcess::resolveExecutable(const QString &program)
{
#ifdef Q_OS_DARWIN
// allow invoking of .app bundles on the Mac.
@@ -412,17 +622,77 @@ static QString resolveExecutable(const QString &program)
return program;
}
+extern "C" {
+__attribute__((weak)) pid_t __interceptor_vfork();
+}
+
+inline bool globalUsingVfork() noexcept
+{
+#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer)
+ // ASan writes to global memory, so we mustn't use vfork().
+ return false;
+#endif
+#if defined(__SANITIZE_THREAD__) || __has_feature(thread_sanitizer)
+ // Ditto, apparently
+ return false;
+#endif
+#if defined(Q_OS_LINUX) && !QT_CONFIG(forkfd_pidfd)
+ // some broken environments are known to have problems with the new Linux
+ // API, so we have a way for users to opt-out during configure time (see
+ // QTBUG-86285)
+ return false;
+#endif
+#if defined(Q_OS_DARWIN)
+ // Using vfork() for startDetached() is causing problems. We don't know
+ // why: without the tools to investigate why it happens, we didn't bother.
+ return false;
+#endif
+
+ // Dynamically detect whether libasan or libtsan are loaded into the
+ // process' memory. We need this because the user's code may be compiled
+ // with ASan or TSan, but not Qt.
+ return __interceptor_vfork == nullptr;
+}
+
+inline bool QChildProcess::usingVfork() const noexcept
+{
+ if (!globalUsingVfork())
+ return false;
+
+ if (!d->unixExtras || !d->unixExtras->childProcessModifier)
+ return true; // no modifier was supplied
+
+ // if a modifier was supplied, use fork() unless the user opts in to
+ // vfork()
+ auto flags = d->unixExtras->processParameters.flags;
+ return flags.testFlag(QProcess::UnixProcessFlag::UseVFork);
+}
+
+#ifdef QT_BUILD_INTERNAL
+Q_AUTOTEST_EXPORT bool _qprocessUsingVfork() noexcept
+{
+ return globalUsingVfork();
+}
+#endif
+
void QProcessPrivate::startProcess()
{
Q_Q(QProcess);
+ q->setProcessState(QProcess::Starting);
#if defined (QPROCESS_DEBUG)
qDebug("QProcessPrivate::startProcess()");
#endif
// Initialize pipes
- if (!openChannels() || qt_create_pipe(childStartedPipe) != 0) {
- setErrorAndEmit(QProcess::FailedToStart, qt_error_string(errno));
+ if (!openChannels()) {
+ // openChannel sets the error string
+ Q_ASSERT(!errorString.isEmpty());
+ cleanup();
+ return;
+ }
+ if (qt_create_pipe(childStartedPipe) != 0) {
+ setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
cleanup();
return;
}
@@ -437,39 +707,15 @@ void QProcessPrivate::startProcess()
q, SLOT(_q_startupNotification()));
}
- // Start the process (platform dependent)
- q->setProcessState(QProcess::Starting);
-
// Prepare the arguments and the environment
- const CharPointerList argv(resolveExecutable(program), arguments);
- const CharPointerList envp(environment.d.constData());
-
- // Encode the working directory if it's non-empty, otherwise just pass 0.
- const char *workingDirPtr = nullptr;
- QByteArray encodedWorkingDirectory;
- if (!workingDirectory.isEmpty()) {
- encodedWorkingDirectory = QFile::encodeName(workingDirectory);
- workingDirPtr = encodedWorkingDirectory.constData();
+ QChildProcess childProcess(this);
+ if (!childProcess.ok()) {
+ Q_ASSERT(processError != QProcess::UnknownError);
+ return;
}
// Start the child.
- auto execChild1 = [this, workingDirPtr, &argv, &envp]() {
- execChild(workingDirPtr, argv.pointers.get(), envp.pointers.get());
- };
- auto execChild2 = [](void *lambda) {
- static_cast<decltype(execChild1) *>(lambda)->operator()();
- return -1;
- };
-
- int ffdflags = FFD_CLOEXEC;
-
- // QTBUG-86285
-#if defined(Q_OS_LINUX) && !QT_CONFIG(forkfd_pidfd)
- ffdflags |= FFD_USE_FORK;
-#endif
-
- pid_t childPid;
- forkfd = ::vforkfd(ffdflags , &childPid, execChild2, &execChild1);
+ forkfd = childProcess.startChild(&pid);
int lastForkErrno = errno;
if (forkfd == -1) {
@@ -484,7 +730,6 @@ void QProcessPrivate::startProcess()
return;
}
- pid = qint64(childPid);
Q_ASSERT(pid > 0);
// parent
@@ -516,51 +761,187 @@ void QProcessPrivate::startProcess()
::fcntl(stderrChannel.pipe[0], F_SETFL, ::fcntl(stderrChannel.pipe[0], F_GETFL) | O_NONBLOCK);
}
+// we need an errno number to use to indicate the child process modifier threw,
+// something the regular operations shouldn't set.
+static constexpr int FakeErrnoForThrow = std::numeric_limits<int>::max();
+
+static QString startFailureErrorMessage(ChildError &err, [[maybe_unused]] ssize_t bytesRead)
+{
+ // ChildError is less than the POSIX pipe buffer atomic size, so the read
+ // must not have been truncated
+ Q_ASSERT(bytesRead == sizeof(err));
+
+ qsizetype len = qstrnlen(err.function, sizeof(err.function));
+ QString complement = QString::fromUtf8(err.function, len);
+ if (err.code == FakeErrnoForThrow)
+ return QProcess::tr("Child process modifier threw an exception: %1")
+ .arg(std::move(complement));
+ if (err.code == 0)
+ return QProcess::tr("Child process modifier reported error: %1")
+ .arg(std::move(complement));
+ if (err.code < 0)
+ return QProcess::tr("Child process modifier reported error: %1: %2")
+ .arg(std::move(complement), qt_error_string(-err.code));
+ return QProcess::tr("Child process set up failed: %1: %2")
+ .arg(std::move(complement), qt_error_string(err.code));
+}
+
+Q_NORETURN void
+failChildProcess(const QProcessPrivate *d, const char *description, int code) noexcept
+{
+ ChildError error = {};
+ error.code = code;
+ qstrncpy(error.function, description, sizeof(error.function));
+ qt_safe_write(d->childStartedPipe[1], &error, sizeof(error));
+ _exit(-1);
+}
+
+void QProcess::failChildProcessModifier(const char *description, int error) noexcept
+{
+ // We signal user errors with negative errnos
+ failChildProcess(d_func(), description, -error);
+}
+
+// See IMPORTANT notice below
+static const char *applyProcessParameters(const QProcess::UnixProcessParameters &params)
+{
+ // Apply Unix signal handler parameters.
+ // We don't expect signal() to fail, so we ignore its return value
+ bool ignore_sigpipe = params.flags.testFlag(QProcess::UnixProcessFlag::IgnoreSigPipe);
+ if (ignore_sigpipe)
+ QtVforkSafe::change_sigpipe(SIG_IGN);
+ if (params.flags.testFlag(QProcess::UnixProcessFlag::ResetSignalHandlers)) {
+ struct sigaction sa = {};
+ sa.sa_handler = SIG_DFL;
+ for (int sig = 1; sig < NSIG; ++sig) {
+ if (!ignore_sigpipe || sig != SIGPIPE)
+ QtVforkSafe::sigaction(sig, &sa, nullptr);
+ }
+
+ // and unmask all signals
+ sigset_t set;
+ sigemptyset(&set);
+ sigprocmask(SIG_SETMASK, &set, nullptr);
+ }
+
+ // Close all file descriptors above stderr.
+ // This isn't expected to fail, so we ignore close()'s return value.
+ if (params.flags.testFlag(QProcess::UnixProcessFlag::CloseFileDescriptors)) {
+ int r = -1;
+ int fd = qMax(STDERR_FILENO + 1, params.lowestFileDescriptorToClose);
+#if QT_CONFIG(close_range)
+ // On FreeBSD, this probably won't fail.
+ // On Linux, this will fail with ENOSYS before kernel 5.9.
+ r = close_range(fd, INT_MAX, 0);
+#endif
+ if (r == -1) {
+ // We *could* read /dev/fd to find out what file descriptors are
+ // open, but we won't. We CANNOT use opendir() here because it
+ // allocates memory. Using getdents(2) plus either strtoul() or
+ // std::from_chars() would be acceptable.
+ int max_fd = INT_MAX;
+ if (struct rlimit limit; getrlimit(RLIMIT_NOFILE, &limit) == 0)
+ max_fd = limit.rlim_cur;
+ for ( ; fd < max_fd; ++fd)
+ close(fd);
+ }
+ }
+
+ // Apply session and process group settings. This may fail.
+ if (params.flags.testFlag(QProcess::UnixProcessFlag::CreateNewSession)) {
+ if (setsid() < 0)
+ return "setsid";
+ }
+
+ // Disconnect from the controlling TTY. This probably won't fail. Must be
+ // done after the session settings from above.
+ if (params.flags.testFlag(QProcess::UnixProcessFlag::DisconnectControllingTerminal)) {
+ if (int fd = open(_PATH_TTY, O_RDONLY | O_NOCTTY); fd >= 0) {
+ // we still have a controlling TTY; give it up
+ int r = ioctl(fd, TIOCNOTTY);
+ int savedErrno = errno;
+ close(fd);
+ if (r != 0) {
+ errno = savedErrno;
+ return "ioctl";
+ }
+ }
+ }
+
+ // Apply UID and GID parameters last. This isn't expected to fail either:
+ // either we're trying to impersonate what we already are, or we're EUID or
+ // EGID root, in which case we are allowed to do this.
+ if (params.flags.testFlag(QProcess::UnixProcessFlag::ResetIds)) {
+ int r = setgid(getgid());
+ r = setuid(getuid());
+ (void) r;
+ }
+
+ return nullptr;
+}
+
+// the noexcept here adds an extra layer of protection
+static void callChildProcessModifier(const QProcessPrivate *d) noexcept
+{
+ QT_TRY {
+ if (d->unixExtras->childProcessModifier)
+ d->unixExtras->childProcessModifier();
+ } QT_CATCH (std::exception &e) {
+ failChildProcess(d, e.what(), FakeErrnoForThrow);
+ } QT_CATCH (...) {
+ failChildProcess(d, "throw", FakeErrnoForThrow);
+ }
+}
+
// IMPORTANT:
//
// This function is called in a vfork() context on some OSes (notably, Linux
// with forkfd), so it MUST NOT modify any non-local variable because it's
// still sharing memory with the parent process.
-void QProcessPrivate::execChild(const char *workingDir, char **argv, char **envp) const
+void QChildProcess::startProcess() const noexcept
{
- ::signal(SIGPIPE, SIG_DFL); // reset the signal that we ignored
-
- ChildError error = { 0, {} }; // force zeroing of function[8]
-
// Render channels configuration.
- commitChannels();
+ d->commitChannels();
// make sure this fd is closed if execv() succeeds
- qt_safe_close(childStartedPipe[0]);
+ qt_safe_close(d->childStartedPipe[0]);
// enter the working directory
- if (workingDir && QT_CHDIR(workingDir) == -1) {
- // failed, stop the process
- strcpy(error.function, "chdir");
- goto report_errno;
+ if (workingDirectory >= 0 && fchdir(workingDirectory) == -1)
+ failChildProcess(d, "fchdir", errno);
+
+ bool sigpipeHandled = false;
+ bool sigmaskHandled = false;
+ if (d->unixExtras) {
+ // FIRST we call the user modifier function, before we dropping
+ // privileges or closing non-standard file descriptors
+ callChildProcessModifier(d);
+
+ // then we apply our other user-provided parameters
+ if (const char *what = applyProcessParameters(d->unixExtras->processParameters))
+ failChildProcess(d, what, errno);
+
+ auto flags = d->unixExtras->processParameters.flags;
+ using P = QProcess::UnixProcessFlag;
+ sigpipeHandled = flags.testAnyFlags(P::ResetSignalHandlers | P::IgnoreSigPipe);
+ sigmaskHandled = flags.testFlag(P::ResetSignalHandlers);
+ }
+ if (!sigpipeHandled) {
+ // reset the signal that we ignored
+ QtVforkSafe::change_sigpipe(SIG_DFL); // reset the signal that we ignored
+ }
+ if (!sigmaskHandled) {
+ // restore the signal mask from the parent, if applyProcessParameters()
+ // hasn't completely reset it
+ restoreSignalMask();
}
-
- if (childProcessModifier)
- childProcessModifier();
// execute the process
- if (!envp) {
+ if (!envp.pointers)
qt_safe_execv(argv[0], argv);
- strcpy(error.function, "execvp");
- } else {
-#if defined (QPROCESS_DEBUG)
- fprintf(stderr, "QProcessPrivate::execChild() starting %s\n", argv[0]);
-#endif
+ else
qt_safe_execve(argv[0], argv, envp);
- strcpy(error.function, "execve");
- }
-
- // notify failure
- // don't use strerror or any other routines that may allocate memory, since
- // some buggy libc versions can deadlock on locked mutexes.
-report_errno:
- error.code = errno;
- qt_safe_write(childStartedPipe[1], &error, sizeof(error));
+ failChildProcess(d, "execve", errno);
}
bool QProcessPrivate::processStarted(QString *errorMessage)
@@ -568,7 +949,7 @@ bool QProcessPrivate::processStarted(QString *errorMessage)
Q_Q(QProcess);
ChildError buf;
- int ret = qt_safe_read(childStartedPipe[0], &buf, sizeof(buf));
+ ssize_t ret = qt_safe_read(childStartedPipe[0], &buf, sizeof(buf));
if (stateNotifier) {
stateNotifier->setEnabled(false);
@@ -598,7 +979,7 @@ bool QProcessPrivate::processStarted(QString *errorMessage)
// did we read an error message?
if (errorMessage)
- *errorMessage = QLatin1StringView(buf.function) + ": "_L1 + qt_error_string(buf.code);
+ *errorMessage = startFailureErrorMessage(buf, ret);
return false;
}
@@ -716,7 +1097,7 @@ void QProcessPrivate::terminateProcess()
qDebug("QProcessPrivate::terminateProcess() pid=%jd", intmax_t(pid));
#endif
if (pid > 0)
- ::kill(pid_t(pid), SIGTERM);
+ ::kill(pid, SIGTERM);
}
void QProcessPrivate::killProcess()
@@ -725,20 +1106,20 @@ void QProcessPrivate::killProcess()
qDebug("QProcessPrivate::killProcess() pid=%jd", intmax_t(pid));
#endif
if (pid > 0)
- ::kill(pid_t(pid), SIGKILL);
+ ::kill(pid, SIGKILL);
}
bool QProcessPrivate::waitForStarted(const QDeadlineTimer &deadline)
{
- const qint64 msecs = deadline.remainingTime();
#if defined (QPROCESS_DEBUG)
+ const qint64 msecs = deadline.remainingTime();
qDebug("QProcessPrivate::waitForStarted(%lld) waiting for child to start (fd = %d)",
msecs, childStartedPipe[0]);
#endif
pollfd pfd = qt_make_pollfd(childStartedPipe[0], POLLIN);
- if (qt_poll_msecs(&pfd, 1, msecs) == 0) {
+ if (qt_safe_poll(&pfd, 1, deadline) == 0) {
setError(QProcess::Timedout);
#if defined (QPROCESS_DEBUG)
qDebug("QProcessPrivate::waitForStarted(%lld) == false (timed out)", msecs);
@@ -887,36 +1268,28 @@ void QProcessPrivate::waitForDeadChild()
Q_ASSERT(forkfd != -1);
// read the process information from our fd
- forkfd_info info;
+ forkfd_info info = {}; // Silence -Wmaybe-uninitialized; Thiago says forkfd_wait cannot fail here
+ // (QTBUG-119081)
int ret;
- EINTR_LOOP(ret, forkfd_wait(forkfd, &info, nullptr));
+ QT_EINTR_LOOP(ret, forkfd_wait(forkfd, &info, nullptr));
exitCode = info.status;
- crashed = info.code != CLD_EXITED;
+ exitStatus = info.code == CLD_EXITED ? QProcess::NormalExit : QProcess::CrashExit;
delete stateNotifier;
stateNotifier = nullptr;
- EINTR_LOOP(ret, forkfd_close(forkfd));
+ QT_EINTR_LOOP(ret, forkfd_close(forkfd));
forkfd = -1; // Child is dead, don't try to kill it anymore
#if defined QPROCESS_DEBUG
qDebug() << "QProcessPrivate::waitForDeadChild() dead with exitCode"
- << exitCode << ", crashed?" << crashed;
+ << exitCode << ", crashed?" << (info.code != CLD_EXITED);
#endif
}
bool QProcessPrivate::startDetached(qint64 *pid)
{
- QByteArray encodedWorkingDirectory = QFile::encodeName(workingDirectory);
-
-#ifdef PIPE_BUF
- static_assert(PIPE_BUF >= sizeof(ChildError));
-#else
- static_assert(_POSIX_PIPE_BUF >= sizeof(ChildError));
-#endif
- ChildError childStatus = { 0, {} };
-
AutoPipe startedPipe, pidPipe;
if (!startedPipe || !pidPipe) {
setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
@@ -929,48 +1302,29 @@ bool QProcessPrivate::startDetached(qint64 *pid)
return false;
}
- const CharPointerList argv(resolveExecutable(program), arguments);
- const CharPointerList envp(environment.d.constData());
+ // see startProcess() for more information
+ QChildProcess childProcess(this);
+ if (!childProcess.ok()) {
+ Q_ASSERT(processError != QProcess::UnknownError);
+ return false;
+ }
- pid_t childPid = fork();
- if (childPid == 0) {
- ::signal(SIGPIPE, SIG_DFL); // reset the signal that we ignored
+ childStartedPipe[1] = startedPipe[1]; // for failChildProcess()
+ pid_t childPid = childProcess.doFork([&] {
::setsid();
qt_safe_close(startedPipe[0]);
qt_safe_close(pidPipe[0]);
- auto reportFailed = [&](const char *function) {
- childStatus.code = errno;
- strcpy(childStatus.function, function);
- qt_safe_write(startedPipe[1], &childStatus, sizeof(childStatus));
- ::_exit(1);
- };
-
- if (!encodedWorkingDirectory.isEmpty()) {
- if (QT_CHDIR(encodedWorkingDirectory.constData()) < 0)
- reportFailed("chdir: ");
- }
-
- pid_t doubleForkPid = fork();
- if (doubleForkPid == 0) {
- // Render channels configuration.
- commitChannels();
-
- if (envp.pointers)
- qt_safe_execve(argv.pointers[0], argv.pointers.get(), envp.pointers.get());
- else
- qt_safe_execv(argv.pointers[0], argv.pointers.get());
-
- reportFailed("execv: ");
- } else if (doubleForkPid == -1) {
- reportFailed("fork: ");
- }
+ pid_t doubleForkPid;
+ if (childProcess.startChild(&doubleForkPid) == -1)
+ failChildProcess(this, "fork", errno);
// success
qt_safe_write(pidPipe[1], &doubleForkPid, sizeof(pid_t));
- ::_exit(1);
- }
+ return 0;
+ });
+ childStartedPipe[1] = -1;
int savedErrno = errno;
closeChannels();
@@ -990,6 +1344,7 @@ bool QProcessPrivate::startDetached(qint64 *pid)
// successfully execve()'d the target process. If it returns any positive
// result, it means one of the two children wrote an error result. Negative
// values should not happen.
+ ChildError childStatus;
ssize_t startResult = qt_safe_read(startedPipe[0], &childStatus, sizeof(childStatus));
// reap the intermediate child
@@ -1005,10 +1360,8 @@ bool QProcessPrivate::startDetached(qint64 *pid)
} else if (!success) {
if (pid)
*pid = -1;
- QString msg;
- if (startResult == sizeof(childStatus))
- msg = QLatin1StringView(childStatus.function) + qt_error_string(childStatus.code);
- setErrorAndEmit(QProcess::FailedToStart, msg);
+ setErrorAndEmit(QProcess::FailedToStart,
+ startFailureErrorMessage(childStatus, startResult));
}
return success;
}
diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp
index 04c67b4070..e64b133815 100644
--- a/src/corelib/io/qprocess_win.cpp
+++ b/src/corelib/io/qprocess_win.cpp
@@ -28,6 +28,8 @@
QT_BEGIN_NAMESPACE
+constexpr UINT KillProcessExitCode = 0xf291;
+
using namespace Qt::StringLiterals;
QProcessEnvironment QProcessEnvironment::systemEnvironment()
@@ -138,6 +140,7 @@ static bool qt_create_pipe(Q_PIPE *pipe, bool isInputPipe, BOOL defInheritFlag)
DWORD dwError = GetLastError();
if (dwError != ERROR_PIPE_BUSY || !--attempts) {
qErrnoWarning(dwError, "QProcess: CreateNamedPipe failed.");
+ SetLastError(dwError);
return false;
}
}
@@ -152,8 +155,10 @@ static bool qt_create_pipe(Q_PIPE *pipe, bool isInputPipe, BOOL defInheritFlag)
FILE_FLAG_OVERLAPPED,
NULL);
if (hClient == INVALID_HANDLE_VALUE) {
+ DWORD dwError = GetLastError();
qErrnoWarning("QProcess: CreateFile failed.");
CloseHandle(hServer);
+ SetLastError(dwError);
return false;
}
@@ -170,10 +175,12 @@ static bool qt_create_pipe(Q_PIPE *pipe, bool isInputPipe, BOOL defInheritFlag)
WaitForSingleObject(overlapped.hEvent, INFINITE);
break;
default:
+ dwError = GetLastError();
qErrnoWarning(dwError, "QProcess: ConnectNamedPipe failed.");
CloseHandle(overlapped.hEvent);
CloseHandle(hClient);
CloseHandle(hServer);
+ SetLastError(dwError);
return false;
}
}
@@ -199,8 +206,13 @@ bool QProcessPrivate::openChannel(Channel &channel)
switch (channel.type) {
case Channel::Normal: {
// we're piping this channel to our own process
- if (&channel == &stdinChannel)
- return qt_create_pipe(channel.pipe, true, FALSE);
+ if (&channel == &stdinChannel) {
+ if (!qt_create_pipe(channel.pipe, true, FALSE)) {
+ setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
+ return false;
+ }
+ return true;
+ }
if (&channel == &stdoutChannel) {
if (!stdoutChannel.reader) {
@@ -213,8 +225,10 @@ bool QProcessPrivate::openChannel(Channel &channel)
q->connect(stderrChannel.reader, SIGNAL(readyRead()), SLOT(_q_canReadStandardError()));
}
}
- if (!qt_create_pipe(channel.pipe, false, FALSE))
+ if (!qt_create_pipe(channel.pipe, false, FALSE)) {
+ setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
return false;
+ }
channel.reader->setHandle(channel.pipe[0]);
channel.reader->startAsyncRead();
@@ -263,7 +277,6 @@ bool QProcessPrivate::openChannel(Channel &channel)
setErrorAndEmit(QProcess::FailedToStart,
QProcess::tr("Could not open output redirection for writing"));
}
- cleanup();
return false;
}
case Channel::PipeSource: {
@@ -280,8 +293,10 @@ bool QProcessPrivate::openChannel(Channel &channel)
Q_ASSERT(source == &stdoutChannel);
Q_ASSERT(sink->process == this && sink->type == Channel::PipeSink);
- if (!qt_create_pipe(source->pipe, /* in = */ false, TRUE)) // source is stdout
+ if (!qt_create_pipe(source->pipe, /* in = */ false, TRUE)) { // source is stdout
+ setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
return false;
+ }
sink->pipe[0] = source->pipe[0];
source->pipe[0] = INVALID_Q_PIPE;
@@ -300,8 +315,10 @@ bool QProcessPrivate::openChannel(Channel &channel)
Q_ASSERT(sink == &stdinChannel);
Q_ASSERT(source->process == this && source->type == Channel::PipeSource);
- if (!qt_create_pipe(sink->pipe, /* in = */ true, TRUE)) // sink is stdin
+ if (!qt_create_pipe(sink->pipe, /* in = */ true, TRUE)) { // sink is stdin
+ setErrorAndEmit(QProcess::FailedToStart, "pipe: "_L1 + qt_error_string(errno));
return false;
+ }
source->pipe[1] = sink->pipe[1];
sink->pipe[1] = INVALID_Q_PIPE;
@@ -521,9 +538,9 @@ void QProcessPrivate::startProcess()
q->setProcessState(QProcess::Starting);
if (!openChannels()) {
- QString errorString = QProcess::tr("Process failed to start: %1").arg(qt_error_string());
+ // openChannel sets the error string
+ Q_ASSERT(!errorString.isEmpty());
cleanup();
- setErrorAndEmit(QProcess::FailedToStart, errorString);
return;
}
@@ -632,7 +649,7 @@ void QProcessPrivate::terminateProcess()
void QProcessPrivate::killProcess()
{
if (pid)
- TerminateProcess(pid->hProcess, 0xf291);
+ TerminateProcess(pid->hProcess, KillProcessExitCode);
}
bool QProcessPrivate::waitForStarted(const QDeadlineTimer &)
@@ -782,8 +799,11 @@ void QProcessPrivate::findExitCode()
Q_ASSERT(pid);
if (GetExitCodeProcess(pid->hProcess, &theExitCode)) {
exitCode = theExitCode;
- crashed = (exitCode == 0xf291 // our magic number, see killProcess
- || (theExitCode >= 0x80000000 && theExitCode < 0xD0000000));
+ if (exitCode == KillProcessExitCode
+ || (theExitCode >= 0x80000000 && theExitCode < 0xD0000000))
+ exitStatus = QProcess::CrashExit;
+ else
+ exitStatus = QProcess::NormalExit;
}
}
diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp
index a3237f25bc..df57d12efc 100644
--- a/src/corelib/io/qresource.cpp
+++ b/src/corelib/io/qresource.cpp
@@ -33,10 +33,13 @@
# include <zstd.h>
#endif
-#if defined(Q_OS_UNIX) && !defined(Q_OS_NACL) && !defined(Q_OS_INTEGRITY)
+#if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY)
# define QT_USE_MMAP
# include <sys/mman.h>
#endif
+#ifdef Q_OS_WIN
+# include <qt_windows.h>
+#endif
//#define DEBUG_RESOURCE_MATCH
@@ -65,6 +68,7 @@ RCC_FEATURE_SYMBOL(Zstd)
#undef RCC_FEATURE_SYMBOL
+namespace {
class QStringSplitter
{
public:
@@ -130,7 +134,7 @@ public:
return QResource::NoCompression;
}
const uchar *data(int node, qint64 *size) const;
- quint64 lastModified(int node) const;
+ qint64 lastModified(int node) const;
QStringList children(int node) const;
virtual QString mappingRoot() const { return QString(); }
bool mappingRootSubdir(const QString &path, QString *match = nullptr) const;
@@ -159,15 +163,18 @@ static QString cleanPath(const QString &_path)
path.remove(0, 1);
return path;
}
+} // unnamed namespace
Q_DECLARE_TYPEINFO(QResourceRoot, Q_RELOCATABLE_TYPE);
typedef QList<QResourceRoot*> ResourceList;
+namespace {
struct QResourceGlobalData
{
QRecursiveMutex resourceMutex;
ResourceList resourceList;
};
+}
Q_GLOBAL_STATIC(QResourceGlobalData, resourceGlobalData)
static inline QRecursiveMutex &resourceMutex()
@@ -233,6 +240,19 @@ static inline ResourceList *resourceList()
itself will be unmapped from memory when the last QResource that points
to it is destroyed.
+ \section2 Corruption and Security
+
+ The QResource class performs some checks on the file passed to determine
+ whether it is supported by the current version of Qt. Those tests are only
+ to check the file header does not request features (such as Zstandard
+ decompression) that have not been compiled in or that the file is not of a
+ future version of Qt. They do not confirm the validity of the entire file.
+
+ QResource should not be used on files whose provenance cannot be trusted.
+ Applications should be designed to attempt to load only resource files
+ whose provenance is at least as trustworthy as that of the application
+ itself or its plugins.
+
\sa {The Qt Resource System}, QFile, QDir, QFileInfo
*/
@@ -269,11 +289,11 @@ public:
QLocale locale;
QString fileName, absoluteFilePath;
QList<QResourceRoot *> related;
- mutable qint64 size;
- mutable quint64 lastModified;
- mutable const uchar *data;
+ qint64 size;
+ qint64 lastModified;
+ const uchar *data;
mutable QStringList children;
- mutable quint8 compressionAlgo;
+ quint8 compressionAlgo;
bool container;
/* 2 or 6 padding bytes */
@@ -915,14 +935,14 @@ const uchar *QResourceRoot::data(int node, qint64 *size) const
return nullptr;
}
-quint64 QResourceRoot::lastModified(int node) const
+qint64 QResourceRoot::lastModified(int node) const
{
if (node == -1 || version < 0x02)
return 0;
const int offset = findOffset(node) + 14;
- return qFromBigEndian<quint64>(tree + offset);
+ return qFromBigEndian<qint64>(tree + offset);
}
QStringList QResourceRoot::children(int node) const
@@ -1018,8 +1038,8 @@ Q_CORE_EXPORT bool qUnregisterResourceData(int version, const unsigned char *tre
return false;
}
+namespace {
// run time resource creation
-
class QDynamicBufferResourceRoot : public QResourceRoot
{
QString root;
@@ -1092,6 +1112,11 @@ public:
class QDynamicFileResourceRoot : public QDynamicBufferResourceRoot
{
+public:
+ static uchar *map_sys(QFile &file, qint64 base, qsizetype size);
+ static void unmap_sys(void *base, qsizetype size);
+
+private:
QString fileName;
// for mmap'ed files, this is what needs to be unmapped.
uchar *unmapPointer;
@@ -1102,22 +1127,17 @@ public:
: QDynamicBufferResourceRoot(_root), unmapPointer(nullptr), unmapLength(0)
{ }
~QDynamicFileResourceRoot() {
-#if defined(QT_USE_MMAP)
- if (unmapPointer) {
- munmap(reinterpret_cast<char *>(unmapPointer), unmapLength);
- unmapPointer = nullptr;
- unmapLength = 0;
- } else
-#endif
- {
+ if (unmapPointer)
+ unmap_sys(unmapPointer, unmapLength);
+ else
delete[] mappingBuffer();
- }
}
QString mappingFile() const { return fileName; }
ResourceRootType type() const override { return Resource_File; }
bool registerSelf(const QString &f);
};
+} // unnamed namespace
#ifndef MAP_FILE
# define MAP_FILE 0
@@ -1126,49 +1146,69 @@ public:
# define MAP_FAILED reinterpret_cast<void *>(-1)
#endif
-bool QDynamicFileResourceRoot::registerSelf(const QString &f)
+void QDynamicFileResourceRoot::unmap_sys(void *base, qsizetype size)
{
- bool fromMM = false;
- uchar *data = nullptr;
- qsizetype data_len = 0;
+#if defined(QT_USE_MMAP)
+ munmap(base, size);
+#elif defined(Q_OS_WIN)
+ Q_UNUSED(size)
+ UnmapViewOfFile(reinterpret_cast<void *>(base));
+#endif
+}
+// Note: caller must ensure \a offset and \a size are acceptable to the OS.
+uchar *QDynamicFileResourceRoot::map_sys(QFile &file, qint64 offset, qsizetype size)
+{
+ Q_ASSERT(file.isOpen());
+ void *ptr = nullptr;
+ if (size < 0)
+ size = qMin(file.size() - offset, (std::numeric_limits<qsizetype>::max)());
+
+ // We don't use QFile::map() here because we want to dispose of the QFile object
#if defined(QT_USE_MMAP)
- int fd = QT_OPEN(QFile::encodeName(f), O_RDONLY);
- if (fd >= 0) {
- QT_STATBUF st;
- if (!QT_FSTAT(fd, &st) && st.st_size <= std::numeric_limits<qsizetype>::max()) {
- int protection = PROT_READ; // read-only memory
- int flags = MAP_FILE | MAP_PRIVATE; // swap-backed map from file
- void *ptr = QT_MMAP(nullptr, st.st_size, // any address, whole file
- protection, flags,
- fd, 0); // from offset 0 of fd
- if (ptr != MAP_FAILED) {
- data = static_cast<uchar *>(ptr);
- data_len = st.st_size;
- fromMM = true;
- }
+ int fd = file.handle();
+ int protection = PROT_READ; // read-only memory
+ int flags = MAP_FILE | MAP_PRIVATE; // swap-backed map from file
+ ptr = QT_MMAP(nullptr, size, protection, flags, fd, offset);
+ if (ptr == MAP_FAILED)
+ ptr = nullptr;
+#elif defined(Q_OS_WIN)
+ int fd = file.handle();
+ HANDLE fileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
+ if (fileHandle != INVALID_HANDLE_VALUE) {
+ HANDLE mapHandle = CreateFileMapping(fileHandle, 0, PAGE_WRITECOPY, 0, 0, 0);
+ if (mapHandle) {
+ ptr = MapViewOfFile(mapHandle, FILE_MAP_COPY, DWORD(offset >> 32), DWORD(offset), size);
+ CloseHandle(mapHandle);
}
- QT_CLOSE(fd);
}
#endif // QT_USE_MMAP
- if (!data) {
- QFile file(f);
+ return static_cast<uchar *>(ptr);
+}
+
+bool QDynamicFileResourceRoot::registerSelf(const QString &f)
+{
+ QFile file(f);
+ if (!file.open(QIODevice::ReadOnly))
+ return false;
+
+ qint64 data_len = file.size();
+ if (data_len > std::numeric_limits<qsizetype>::max())
+ return false;
+
+ uchar *data = map_sys(file, 0, data_len);
+ bool fromMM = !!data;
+
+ if (!fromMM) {
bool ok = false;
- if (file.open(QIODevice::ReadOnly)) {
- qint64 fsize = file.size();
- if (fsize <= std::numeric_limits<qsizetype>::max()) {
- data_len = file.size();
- data = new uchar[data_len];
- ok = (data_len == file.read(reinterpret_cast<char *>(data), data_len));
- }
- }
+ data = new uchar[data_len];
+ ok = (data_len == file.read(reinterpret_cast<char *>(data), data_len));
if (!ok) {
delete[] data;
data = nullptr;
data_len = 0;
return false;
}
- fromMM = false;
}
if (data && QDynamicBufferResourceRoot::registerSelf(data, data_len)) {
if (fromMM) {
@@ -1336,6 +1376,7 @@ private:
uchar *map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags);
bool unmap(uchar *ptr);
void uncompress() const;
+ void mapUncompressed();
qint64 offset;
QResource resource;
mutable QByteArray uncompressed;
@@ -1510,10 +1551,10 @@ uint QResourceFileEngine::ownerId(FileOwner) const
return nobodyID;
}
-QDateTime QResourceFileEngine::fileTime(FileTime time) const
+QDateTime QResourceFileEngine::fileTime(QFile::FileTime time) const
{
Q_D(const QResourceFileEngine);
- if (time == ModificationTime)
+ if (time == QFile::FileModificationTime)
return d->resource.lastModified();
return QDateTime();
}
@@ -1521,18 +1562,11 @@ QDateTime QResourceFileEngine::fileTime(FileTime time) const
/*!
\internal
*/
-QAbstractFileEngine::Iterator *QResourceFileEngine::beginEntryList(QDir::Filters filters,
- const QStringList &filterNames)
-{
- return new QResourceFileEngineIterator(filters, filterNames);
-}
-
-/*!
- \internal
-*/
-QAbstractFileEngine::Iterator *QResourceFileEngine::endEntryList()
+QAbstractFileEngine::IteratorUniquePtr
+QResourceFileEngine::beginEntryList(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames)
{
- return nullptr;
+ return std::make_unique<QResourceFileEngineIterator>(path, filters, filterNames);
}
bool QResourceFileEngine::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output)
@@ -1559,21 +1593,27 @@ bool QResourceFileEngine::supportsExtension(Extension extension) const
uchar *QResourceFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags)
{
Q_Q(QResourceFileEngine);
- Q_UNUSED(flags);
+ Q_ASSERT_X(resource.compressionAlgorithm() == QResource::NoCompression
+ || !uncompressed.isNull(), "QFile::map()",
+ "open() should have uncompressed compressed resources");
qint64 max = resource.uncompressedSize();
qint64 end;
if (offset < 0 || size <= 0 || !resource.isValid() ||
- add_overflow(offset, size, &end) || end > max) {
+ qAddOverflow(offset, size, &end) || end > max) {
q->setError(QFile::UnspecifiedError, QString());
return nullptr;
}
- const uchar *address = resource.data();
- if (resource.compressionAlgorithm() != QResource::NoCompression) {
- uncompress();
- if (uncompressed.isNull())
- return nullptr;
+ const uchar *address = reinterpret_cast<const uchar *>(uncompressed.constBegin());
+ if (!uncompressed.isNull())
+ return const_cast<uchar *>(address) + offset;
+
+ // resource was not compressed
+ address = resource.data();
+ if (flags & QFile::MapPrivateOption) {
+ // We need to provide read-write memory
+ mapUncompressed();
address = reinterpret_cast<const uchar *>(uncompressed.constData());
}
@@ -1594,6 +1634,15 @@ void QResourceFileEnginePrivate::uncompress() const
uncompressed = resource.uncompressedData();
}
+void QResourceFileEnginePrivate::mapUncompressed()
+{
+ Q_ASSERT(resource.compressionAlgorithm() == QResource::NoCompression);
+ if (!uncompressed.isNull())
+ return; // nothing to do
+ uncompressed = resource.uncompressedData();
+ uncompressed.detach();
+}
+
#endif // !defined(QT_BOOTSTRAPPED)
QT_END_NAMESPACE
diff --git a/src/corelib/io/qresource_iterator.cpp b/src/corelib/io/qresource_iterator.cpp
index 58bdefdd20..abb61d3b46 100644
--- a/src/corelib/io/qresource_iterator.cpp
+++ b/src/corelib/io/qresource_iterator.cpp
@@ -8,9 +8,10 @@
QT_BEGIN_NAMESPACE
-QResourceFileEngineIterator::QResourceFileEngineIterator(QDir::Filters filters,
+QResourceFileEngineIterator::QResourceFileEngineIterator(const QString &path, QDir::Filters filters,
const QStringList &filterNames)
- : QAbstractFileEngineIterator(filters, filterNames), index(-1)
+ : QAbstractFileEngineIterator(path, filters, filterNames),
+ index(-1)
{
}
@@ -18,15 +19,7 @@ QResourceFileEngineIterator::~QResourceFileEngineIterator()
{
}
-QString QResourceFileEngineIterator::next()
-{
- if (!hasNext())
- return QString();
- ++index;
- return currentFilePath();
-}
-
-bool QResourceFileEngineIterator::hasNext() const
+bool QResourceFileEngineIterator::advance()
{
if (index == -1) {
// Lazy initialization of the iterator
@@ -34,19 +27,34 @@ bool QResourceFileEngineIterator::hasNext() const
if (!resource.isValid())
return false;
- // Initialize and move to the next entry.
+ // Initialize and move to the first entry.
entries = resource.children();
+ if (entries.isEmpty())
+ return false;
+
index = 0;
+ return true;
}
- return index < entries.size();
+ if (index < entries.size() - 1) {
+ ++index;
+ return true;
+ }
+
+ return false;
}
QString QResourceFileEngineIterator::currentFileName() const
{
- if (index <= 0 || index > entries.size())
+ if (index < 0 || index > entries.size())
return QString();
- return entries.at(index - 1);
+ return entries.at(index);
+}
+
+QFileInfo QResourceFileEngineIterator::currentFileInfo() const
+{
+ m_fileInfo = QFileInfo(currentFilePath());
+ return m_fileInfo;
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qresource_iterator_p.h b/src/corelib/io/qresource_iterator_p.h
index 7bc546e44a..bcbbc46b51 100644
--- a/src/corelib/io/qresource_iterator_p.h
+++ b/src/corelib/io/qresource_iterator_p.h
@@ -24,13 +24,14 @@ class QResourceFileEngineIteratorPrivate;
class QResourceFileEngineIterator : public QAbstractFileEngineIterator
{
public:
- QResourceFileEngineIterator(QDir::Filters filters, const QStringList &filterNames);
+ QResourceFileEngineIterator(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames);
~QResourceFileEngineIterator();
- QString next() override;
- bool hasNext() const override;
+ bool advance() override;
QString currentFileName() const override;
+ QFileInfo currentFileInfo() const override;
private:
mutable QStringList entries;
diff --git a/src/corelib/io/qresource_p.h b/src/corelib/io/qresource_p.h
index 0844e6579a..37fddd7a41 100644
--- a/src/corelib/io/qresource_p.h
+++ b/src/corelib/io/qresource_p.h
@@ -47,10 +47,10 @@ public:
uint ownerId(FileOwner) const override;
- QDateTime fileTime(FileTime time) const override;
+ QDateTime fileTime(QFile::FileTime time) const override;
- Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override;
- Iterator *endEntryList() override;
+ IteratorUniquePtr beginEntryList(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames) override;
bool extension(Extension extension, const ExtensionOption *option = nullptr, ExtensionReturn *output = nullptr) override;
bool supportsExtension(Extension extension) const override;
diff --git a/src/corelib/io/qsavefile.cpp b/src/corelib/io/qsavefile.cpp
index aa7fb21390..cc59bb3725 100644
--- a/src/corelib/io/qsavefile.cpp
+++ b/src/corelib/io/qsavefile.cpp
@@ -3,7 +3,7 @@
#include "qsavefile.h"
-#ifndef QT_NO_TEMPORARYFILE
+#if QT_CONFIG(temporaryfile)
#include "qplatformdefs.h"
#include "private/qsavefile_p.h"
@@ -113,10 +113,10 @@ QSaveFile::QSaveFile(const QString &name, QObject *parent)
QSaveFile::~QSaveFile()
{
Q_D(QSaveFile);
- QFileDevice::close();
- if (d->fileEngine) {
+ if (isOpen()) {
+ QFileDevice::close();
+ Q_ASSERT(d->fileEngine);
d->fileEngine->remove();
- d->fileEngine.reset();
}
}
@@ -152,7 +152,7 @@ void QSaveFile::setFileName(const QString &name)
QIODevice::ReadWrite, QIODevice::Append, QIODevice::NewOnly and
QIODevice::ExistingOnly are not supported at the moment.
- \sa QIODevice::OpenMode, setFileName()
+ \sa QIODevice::OpenMode, setFileName(), QT_USE_NODISCARD_FILE_OPEN
*/
bool QSaveFile::open(OpenMode mode)
{
@@ -200,7 +200,7 @@ bool QSaveFile::open(OpenMode mode)
}
auto openDirectly = [&]() {
- d->fileEngine.reset(QAbstractFileEngine::create(d->finalFileName));
+ d->fileEngine = QAbstractFileEngine::create(d->finalFileName);
if (d->fileEngine->open(mode | QIODevice::Unbuffered)) {
d->useTemporaryFile = false;
QFileDevice::open(mode);
@@ -298,7 +298,7 @@ bool QSaveFile::commit()
}
QFileDevice::close(); // calls flush()
- const auto fe = std::move(d->fileEngine);
+ const auto &fe = d->fileEngine;
// Sync to disk if possible. Ignore errors (e.g. not supported).
fe->syncToDisk();
@@ -412,4 +412,4 @@ QT_END_NAMESPACE
#include "moc_qsavefile.cpp"
#endif
-#endif // QT_NO_TEMPORARYFILE
+#endif // QT_CONFIG(temporaryfile)
diff --git a/src/corelib/io/qsavefile.h b/src/corelib/io/qsavefile.h
index 9ea4887c3c..4dd712d4b6 100644
--- a/src/corelib/io/qsavefile.h
+++ b/src/corelib/io/qsavefile.h
@@ -6,7 +6,7 @@
#include <QtCore/qglobal.h>
-#ifndef QT_NO_TEMPORARYFILE
+#if QT_CONFIG(temporaryfile)
#include <QtCore/qfiledevice.h>
#include <QtCore/qstring.h>
@@ -39,7 +39,7 @@ public:
QString fileName() const override;
void setFileName(const QString &name);
- bool open(OpenMode flags) override;
+ QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override;
bool commit();
void cancelWriting();
@@ -62,6 +62,6 @@ private:
QT_END_NAMESPACE
-#endif // QT_NO_TEMPORARYFILE
+#endif // QT_CONFIG(temporaryfile)
#endif // QSAVEFILE_H
diff --git a/src/corelib/io/qsavefile_p.h b/src/corelib/io/qsavefile_p.h
index 50de9e4e68..4d0f40fbb0 100644
--- a/src/corelib/io/qsavefile_p.h
+++ b/src/corelib/io/qsavefile_p.h
@@ -17,7 +17,7 @@
#include <QtCore/qglobal.h>
-#ifndef QT_NO_TEMPORARYFILE
+#if QT_CONFIG(temporaryfile)
#include "private/qfiledevice_p.h"
@@ -42,6 +42,6 @@ protected:
QT_END_NAMESPACE
-#endif // QT_NO_TEMPORARYFILE
+#endif // QT_CONFIG(temporaryfile)
#endif // QSAVEFILE_P_H
diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp
index 0b28690a4e..6934ca4404 100644
--- a/src/corelib/io/qsettings.cpp
+++ b/src/corelib/io/qsettings.cpp
@@ -129,12 +129,12 @@ bool QConfFile::isWritable() const
{
QFileInfo fileInfo(name);
-#ifndef QT_NO_TEMPORARYFILE
+#if QT_CONFIG(temporaryfile)
if (fileInfo.exists()) {
#endif
QFile file(name);
return file.open(QFile::ReadWrite);
-#ifndef QT_NO_TEMPORARYFILE
+#if QT_CONFIG(temporaryfile)
} else {
// Create the directories to the file.
QDir dir(fileInfo.absolutePath());
@@ -878,7 +878,13 @@ QStringList QSettingsPrivate::splitArgs(const QString &s, qsizetype idx)
void QConfFileSettingsPrivate::initFormat()
{
+#if defined(Q_OS_WASM)
+ extension = (format == QSettings::NativeFormat || format == QSettings::WebIndexedDBFormat)
+ ? ".conf"_L1
+ : ".ini"_L1;
+#else
extension = (format == QSettings::NativeFormat) ? ".conf"_L1 : ".ini"_L1;
+#endif
readFunc = nullptr;
writeFunc = nullptr;
#if defined(Q_OS_DARWIN)
@@ -887,7 +893,11 @@ void QConfFileSettingsPrivate::initFormat()
caseSensitivity = IniCaseSensitivity;
#endif
+#if defined Q_OS_WASM
+ if (format > QSettings::IniFormat && format != QSettings::WebIndexedDBFormat) {
+#else
if (format > QSettings::IniFormat) {
+#endif
const auto locker = qt_scoped_lock(settingsGlobalMutex);
const CustomFormatVector *customFormatVector = customFormatVectorFunc();
@@ -905,7 +915,11 @@ void QConfFileSettingsPrivate::initFormat()
void QConfFileSettingsPrivate::initAccess()
{
if (!confFiles.isEmpty()) {
+#if defined Q_OS_WASM
+ if (format > QSettings::IniFormat && format != QSettings::WebIndexedDBFormat) {
+#else
if (format > QSettings::IniFormat) {
+#endif
if (!readFunc)
setStatus(QSettings::AccessError);
}
@@ -943,26 +957,43 @@ static inline int pathHashKey(QSettings::Format format, QSettings::Scope scope)
}
#ifndef Q_OS_WIN
-static QString make_user_path()
+static constexpr QChar sep = u'/';
+
+#if !defined(QSETTINGS_USE_QSTANDARDPATHS) || defined(Q_OS_ANDROID)
+static QString make_user_path_without_qstandard_paths()
{
- static constexpr QChar sep = u'/';
-#ifndef QSETTINGS_USE_QSTANDARDPATHS
- // Non XDG platforms (OS X, iOS, Android...) have used this code path erroneously
- // for some time now. Moving away from that would require migrating existing settings.
QByteArray env = qgetenv("XDG_CONFIG_HOME");
if (env.isEmpty()) {
return QDir::homePath() + "/.config/"_L1;
} else if (env.startsWith('/')) {
return QFile::decodeName(env) + sep;
- } else {
- return QDir::homePath() + sep + QFile::decodeName(env) + sep;
}
+
+ return QDir::homePath() + sep + QFile::decodeName(env) + sep;
+}
+#endif // !QSETTINGS_USE_QSTANDARDPATHS || Q_OS_ANDROID
+
+static QString make_user_path()
+{
+#ifndef QSETTINGS_USE_QSTANDARDPATHS
+ // Non XDG platforms (OS X, iOS, Android...) have used this code path erroneously
+ // for some time now. Moving away from that would require migrating existing settings.
+ // The migration has already been done for Android.
+ return make_user_path_without_qstandard_paths();
#else
- // When using a proper XDG platform, use QStandardPaths rather than the above hand-written code;
- // it makes the use of test mode from unit tests possible.
+
+#ifdef Q_OS_ANDROID
+ // If an old settings path exists, use it instead of creating a new one
+ QString ret = make_user_path_without_qstandard_paths();
+ if (QFile(ret).exists())
+ return ret;
+#endif // Q_OS_ANDROID
+
+ // When using a proper XDG platform or Android platform, use QStandardPaths rather than the
+ // above hand-written code. It makes the use of test mode from unit tests possible.
// Ideally all platforms should use this, but see above for the migration issue.
return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + sep;
-#endif
+#endif // !QSETTINGS_USE_QSTANDARDPATHS
}
#endif // !Q_OS_WIN
@@ -1093,9 +1124,7 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
confFiles.append(QConfFile::fromName(systemPath.path + orgFile, false));
}
-#ifndef Q_OS_WASM // wasm needs to delay access until after file sync
initAccess();
-#endif
}
QConfFileSettingsPrivate::QConfFileSettingsPrivate(const QString &fileName,
@@ -1227,17 +1256,17 @@ QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec
else
ensureSectionParsed(confFile, thePrefix);
- auto 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(QStringView{j.key().originalCaseKey()}.sliced(startPos), spec, result);
- ++j;
+ const auto &originalKeys = confFile->originalKeys;
+ auto i = originalKeys.lowerBound(thePrefix);
+ while (i != originalKeys.end() && i.key().startsWith(thePrefix)) {
+ if (!confFile->removedKeys.contains(i.key()))
+ processChild(QStringView{i.key().originalCaseKey()}.sliced(startPos), spec, result);
+ ++i;
}
- j = const_cast<const ParsedSettingsMap *>(
- &confFile->addedKeys)->lowerBound(thePrefix);
- while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) {
+ const auto &addedKeys = confFile->addedKeys;
+ auto j = addedKeys.lowerBound(thePrefix);
+ while (j != addedKeys.end() && j.key().startsWith(thePrefix)) {
processChild(QStringView{j.key().originalCaseKey()}.sliced(startPos), spec, result);
++j;
}
@@ -1292,7 +1321,11 @@ QString QConfFileSettingsPrivate::fileName() const
bool QConfFileSettingsPrivate::isWritable() const
{
+#if defined(Q_OS_WASM)
+ if (format > QSettings::IniFormat && format != QSettings::WebIndexedDBFormat && !writeFunc)
+#else
if (format > QSettings::IniFormat && !writeFunc)
+#endif
return false;
if (confFiles.isEmpty())
@@ -1327,8 +1360,7 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
// On android and if it is a content URL put the lock file in a
// writable location to prevent permissions issues and invalid paths.
if (confFile->name.startsWith("content:"_L1))
- lockFileName = QStandardPaths::writableLocation(QStandardPaths::CacheLocation)
- + QFileInfo(lockFileName).fileName();
+ lockFileName = make_user_path() + QFileInfo(lockFileName).fileName();
# endif
/*
Use a lockfile in order to protect us against other QSettings instances
@@ -1372,6 +1404,13 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
*/
if (file.isReadable() && file.size() != 0) {
bool ok = false;
+
+#ifdef Q_OS_WASM
+ if (format == QSettings::WebIndexedDBFormat) {
+ QByteArray data = file.readAll();
+ ok = readIniFile(data, &confFile->unparsedIniSections);
+ } else
+#endif
#ifdef Q_OS_DARWIN
if (format == QSettings::NativeFormat) {
QByteArray data = file.readAll();
@@ -1428,6 +1467,11 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
return;
}
+#ifdef Q_OS_WASM
+ if (format == QSettings::WebIndexedDBFormat) {
+ ok = writeIniFile(sf, mergedKeys);
+ } else
+#endif
#ifdef Q_OS_DARWIN
if (format == QSettings::NativeFormat) {
ok = writePlistFile(sf, mergedKeys);
@@ -1474,6 +1518,8 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
}
}
+namespace SettingsImpl {
+
enum { Space = 0x1, Special = 0x2 };
static const char charTraits[256] =
@@ -1500,10 +1546,15 @@ static const char charTraits[256] =
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
+} // namespace SettingsImpl
+
+using SettingsImpl::charTraits;
+
bool QConfFileSettingsPrivate::readIniLine(QByteArrayView data, qsizetype &dataPos,
qsizetype &lineStart, qsizetype &lineLen,
qsizetype &equalsPos)
{
+ using namespace SettingsImpl;
qsizetype dataLen = data.size();
bool inQuotes = false;
@@ -2077,10 +2128,6 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
as QString. The numeric value can be recovered using \l QString::toInt(), \l
QString::toDouble() and related functions.
- The \l{tools/settingseditor}{Settings Editor} example lets you
- experiment with different settings location and with fallbacks
- turned on or off.
-
\section1 Restoring the State of a GUI Application
QSettings is often used to store the state of a GUI
@@ -2106,9 +2153,6 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
\codeline
\snippet settings/settings.cpp 21
- See the \l{mainwindows/application}{Application} example for a
- self-contained example that uses QSettings.
-
\section1 Accessing Settings from Multiple Threads or Processes Simultaneously
QSettings is \l{reentrant}. This means that you can use
@@ -2150,8 +2194,8 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
following files are used by default:
\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{$HOME/.config/MySoft/Star Runner.conf}
+ \li \c{$HOME/.config/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
@@ -2188,8 +2232,8 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
used on Unix, \macos, and iOS:
\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{$HOME/.config/MySoft/Star Runner.ini}
+ \li \c{$HOME/.config/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
@@ -2324,7 +2368,7 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
\endlist
- \sa QVariant, QSessionManager, {Settings Editor Example}, {Qt Widgets - Application Example}
+ \sa QVariant, QSessionManager
*/
/*! \enum QSettings::Status
@@ -2362,6 +2406,16 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
lose the distinction between numeric data and the
strings used to encode them, so values written as
numbers shall be read back as QString.
+ \value WebLocalStorageFormat
+ WASM only: Store the settings in window.localStorage for the current
+ origin. If cookies are not allowed, this falls back to the INI format.
+ This provides up to 5MiB storage per origin, but access to it is
+ synchronous and JSPI is not required.
+ \value WebIndexedDBFormat
+ WASM only: Store the settings in an Indexed DB for the current
+ origin. If cookies are not allowed, this falls back to the INI format.
+ This requires JSPI, but provides more storage than
+ WebLocalStorageFormat.
\value InvalidFormat Special value returned by registerFormat().
\omitvalue CustomFormat1
@@ -3360,8 +3414,6 @@ QSettings::Format QSettings::defaultFormat()
\row \li SystemScope \li \c FOLDERID_ProgramData
\row \li{1,2} Unix \li{1,2} NativeFormat, IniFormat \li UserScope \li \c $HOME/.config
\row \li SystemScope \li \c /etc/xdg
- \row \li{1,2} Qt for Embedded Linux \li{1,2} NativeFormat, IniFormat \li UserScope \li \c $HOME/Settings
- \row \li SystemScope \li \c /etc/xdg
\row \li{1,2} \macos and iOS \li{1,2} IniFormat \li UserScope \li \c $HOME/.config
\row \li SystemScope \li \c /etc/xdg
\endtable
diff --git a/src/corelib/io/qsettings.h b/src/corelib/io/qsettings.h
index 86b55ea241..8bc73eb016 100644
--- a/src/corelib/io/qsettings.h
+++ b/src/corelib/io/qsettings.h
@@ -46,18 +46,17 @@ public:
#endif
enum Format {
- NativeFormat,
- IniFormat,
+ NativeFormat = 0,
+ IniFormat = 1,
#if defined(Q_OS_WIN) || defined(Q_QDOC)
- Registry32Format,
- Registry64Format,
+ Registry32Format = 2,
+ Registry64Format = 3,
#endif
-#if defined(Q_OS_WASM)
- // FIXME: add public API in next minor release.
- // WebLocalStorageFormat (IniFormat + 1)
- // WebIDBSFormat (IniFormat + 2)
+#if defined(Q_OS_WASM) || defined(Q_QDOC)
+ WebLocalStorageFormat = 4,
+ WebIndexedDBFormat = 5,
#endif
InvalidFormat = 16,
diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h
index d79c10e643..4229abd874 100644
--- a/src/corelib/io/qsettings_p.h
+++ b/src/corelib/io/qsettings_p.h
@@ -243,6 +243,9 @@ public:
qsizetype &lineStart, qsizetype &lineLen,
qsizetype &equalsPos);
+protected:
+ const QList<QConfFile *> &getConfFiles() const { return confFiles; }
+
private:
void initFormat();
virtual void initAccess();
diff --git a/src/corelib/io/qsettings_wasm.cpp b/src/corelib/io/qsettings_wasm.cpp
index 15ab688abe..7d80ff82d3 100644
--- a/src/corelib/io/qsettings_wasm.cpp
+++ b/src/corelib/io/qsettings_wasm.cpp
@@ -10,19 +10,33 @@
#include <QFile>
#endif // QT_NO_QOBJECT
#include <QDebug>
+#include <QtCore/private/qstdweb_p.h>
#include <QFileInfo>
#include <QDir>
#include <QList>
+#include <QSet>
#include <emscripten.h>
-#include <emscripten/val.h>
+# include <emscripten/proxying.h>
+# include <emscripten/threading.h>
+# include <emscripten/val.h>
QT_BEGIN_NAMESPACE
using emscripten::val;
using namespace Qt::StringLiterals;
+namespace {
+QStringView keyNameFromPrefixedStorageName(QStringView prefix, QStringView prefixedStorageName)
+{
+ // Return the key slice after m_keyPrefix, or an empty string view if no match
+ if (!prefixedStorageName.startsWith(prefix))
+ return QStringView();
+ return prefixedStorageName.sliced(prefix.length());
+}
+} // namespace
+
//
// Native settings implementation for WebAssembly using window.localStorage
// as the storage backend. localStorage is a key-value store with a synchronous
@@ -33,6 +47,7 @@ class QWasmLocalStorageSettingsPrivate final : public QSettingsPrivate
public:
QWasmLocalStorageSettingsPrivate(QSettings::Scope scope, const QString &organization,
const QString &application);
+ ~QWasmLocalStorageSettingsPrivate() final = default;
void remove(const QString &key) final;
void set(const QString &key, const QVariant &value) final;
@@ -45,10 +60,7 @@ public:
QString fileName() const final;
private:
- QString prependStoragePrefix(const QString &key) const;
- QStringView removeStoragePrefix(QStringView key) const;
- val m_localStorage = val::global("window")["localStorage"];
- QString m_keyPrefix;
+ QStringList m_keyPrefixes;
};
QWasmLocalStorageSettingsPrivate::QWasmLocalStorageSettingsPrivate(QSettings::Scope scope,
@@ -56,88 +68,147 @@ QWasmLocalStorageSettingsPrivate::QWasmLocalStorageSettingsPrivate(QSettings::Sc
const QString &application)
: QSettingsPrivate(QSettings::NativeFormat, scope, organization, application)
{
+ if (organization.isEmpty()) {
+ setStatus(QSettings::AccessError);
+ return;
+ }
+
// The key prefix contians "qt" to separate Qt keys from other keys on localStorage, a
// version tag to allow for making changes to the key format in the future, the org
// and app names.
//
// User code could could create separate settings object with different org and app names,
- // and would expect them to have separate settings. Also, different webassembly instanaces
+ // and would expect them to have separate settings. Also, different webassembly instances
// on the page could write to the same window.localStorage. Add the org and app name
- // to the key prefix to differentiate, even if that leads to keys with redundant sectons
+ // to the key prefix to differentiate, even if that leads to keys with redundant sections
// for the common case of a single org and app name.
+ //
+ // Also, the common Qt mechanism for user/system scope and all-application settings are
+ // implemented, using different prefixes.
+ const QString allAppsSetting = QStringLiteral("all-apps");
+ const QString systemSetting = QStringLiteral("sys-tem");
+
const QLatin1String separator("-");
const QLatin1String doubleSeparator("--");
const QString escapedOrganization = QString(organization).replace(separator, doubleSeparator);
const QString escapedApplication = QString(application).replace(separator, doubleSeparator);
- const QLatin1String prefix("qt-v0-");
- m_keyPrefix.reserve(prefix.length() + escapedOrganization.length() +
- escapedApplication.length() + separator.length() * 2);
- m_keyPrefix = prefix + escapedOrganization + separator + escapedApplication + separator;
+ const QString prefix = "qt-v0-" + escapedOrganization + separator;
+ if (scope == QSettings::Scope::UserScope) {
+ if (!escapedApplication.isEmpty())
+ m_keyPrefixes.push_back(prefix + escapedApplication + separator);
+ m_keyPrefixes.push_back(prefix + allAppsSetting + separator);
+ }
+ if (!escapedApplication.isEmpty()) {
+ m_keyPrefixes.push_back(prefix + escapedApplication + separator + systemSetting
+ + separator);
+ }
+ m_keyPrefixes.push_back(prefix + allAppsSetting + separator + systemSetting + separator);
}
void QWasmLocalStorageSettingsPrivate::remove(const QString &key)
{
- const std::string keyString = prependStoragePrefix(key).toStdString();
- m_localStorage.call<val>("removeItem", keyString);
+ const std::string removed = QString(m_keyPrefixes.first() + key).toStdString();
+
+ qstdweb::runTaskOnMainThread<void>([this, &removed, &key]() {
+ std::vector<std::string> children = { removed };
+ const int length = val::global("window")["localStorage"]["length"].as<int>();
+ for (int i = 0; i < length; ++i) {
+ const QString storedKeyWithPrefix = QString::fromStdString(
+ val::global("window")["localStorage"].call<val>("key", i).as<std::string>());
+
+ const QStringView storedKey = keyNameFromPrefixedStorageName(
+ m_keyPrefixes.first(), QStringView(storedKeyWithPrefix));
+ if (storedKey.isEmpty() || !storedKey.startsWith(key))
+ continue;
+
+ children.push_back(storedKeyWithPrefix.toStdString());
+ }
+
+ for (const auto &child : children)
+ val::global("window")["localStorage"].call<val>("removeItem", child);
+ });
}
void QWasmLocalStorageSettingsPrivate::set(const QString &key, const QVariant &value)
{
- const std::string keyString = prependStoragePrefix(key).toStdString();
- const std::string valueString = QSettingsPrivate::variantToString(value).toStdString();
- m_localStorage.call<void>("setItem", keyString, valueString);
+ qstdweb::runTaskOnMainThread<void>([this, &key, &value]() {
+ const std::string keyString = QString(m_keyPrefixes.first() + key).toStdString();
+ const std::string valueString = QSettingsPrivate::variantToString(value).toStdString();
+ val::global("window")["localStorage"].call<void>("setItem", keyString, valueString);
+ });
}
std::optional<QVariant> QWasmLocalStorageSettingsPrivate::get(const QString &key) const
{
- const std::string keyString = prependStoragePrefix(key).toStdString();
- const emscripten::val value = m_localStorage.call<val>("getItem", keyString);
- if (value.isNull())
- return std::nullopt;
- const QString valueString = QString::fromStdString(value.as<std::string>());
- return QSettingsPrivate::stringToVariant(valueString);
+ return qstdweb::runTaskOnMainThread<std::optional<QVariant>>(
+ [this, &key]() -> std::optional<QVariant> {
+ for (const auto &prefix : m_keyPrefixes) {
+ const std::string keyString = QString(prefix + key).toStdString();
+ const emscripten::val value =
+ val::global("window")["localStorage"].call<val>("getItem", keyString);
+ if (!value.isNull()) {
+ return QSettingsPrivate::stringToVariant(
+ QString::fromStdString(value.as<std::string>()));
+ }
+ if (!fallbacks) {
+ return std::nullopt;
+ }
+ }
+ return std::nullopt;
+ });
}
QStringList QWasmLocalStorageSettingsPrivate::children(const QString &prefix, ChildSpec spec) const
{
- // Loop through all keys on window.localStorage, return Qt keys belonging to
- // this application, with the correct prefix, and according to ChildSpec.
- QStringList children;
- const int length = m_localStorage["length"].as<int>();
- for (int i = 0; i < length; ++i) {
- const QString keyString =
- QString::fromStdString(m_localStorage.call<val>("key", i).as<std::string>());
-
- const QStringView key = removeStoragePrefix(QStringView(keyString));
- if (key.isEmpty())
- continue;
- if (!key.startsWith(prefix))
- continue;
-
- QSettingsPrivate::processChild(key.sliced(prefix.length()), spec, children);
- }
-
- return children;
+ return qstdweb::runTaskOnMainThread<QStringList>([this, &prefix, &spec]() -> QStringList {
+ QSet<QString> nodes;
+ // Loop through all keys on window.localStorage, return Qt keys belonging to
+ // this application, with the correct prefix, and according to ChildSpec.
+ QStringList children;
+ const int length = val::global("window")["localStorage"]["length"].as<int>();
+ for (int i = 0; i < length; ++i) {
+ for (const auto &storagePrefix : m_keyPrefixes) {
+ const QString keyString =
+ QString::fromStdString(val::global("window")["localStorage"]
+ .call<val>("key", i)
+ .as<std::string>());
+
+ const QStringView key =
+ keyNameFromPrefixedStorageName(storagePrefix, QStringView(keyString));
+ if (!key.isEmpty() && key.startsWith(prefix)) {
+ QStringList children;
+ QSettingsPrivate::processChild(key.sliced(prefix.length()), spec, children);
+ if (!children.isEmpty())
+ nodes.insert(children.first());
+ }
+ if (!fallbacks)
+ break;
+ }
+ }
+
+ return QStringList(nodes.begin(), nodes.end());
+ });
}
void QWasmLocalStorageSettingsPrivate::clear()
{
- // Get all Qt keys from window.localStorage
- const int length = m_localStorage["length"].as<int>();
- std::vector<std::string> keys;
- keys.reserve(length);
- for (int i = 0; i < length; ++i) {
- std::string key = (m_localStorage.call<val>("key", i).as<std::string>());
- keys.push_back(std::move(key));
- }
-
- // Remove all Qt keys. Note that localStorage does not guarantee a stable
- // iteration order when the storage is mutated, which is why removal is done
- // in a second step after getting all keys.
- for (std::string key: keys) {
- if (removeStoragePrefix(QString::fromStdString(key)).isEmpty() == false)
- m_localStorage.call<val>("removeItem", key);
- }
+ qstdweb::runTaskOnMainThread<void>([this]() {
+ // Get all Qt keys from window.localStorage
+ const int length = val::global("window")["localStorage"]["length"].as<int>();
+ QStringList keys;
+ keys.reserve(length);
+ for (int i = 0; i < length; ++i)
+ keys.append(QString::fromStdString(
+ (val::global("window")["localStorage"].call<val>("key", i).as<std::string>())));
+
+ // Remove all Qt keys. Note that localStorage does not guarantee a stable
+ // iteration order when the storage is mutated, which is why removal is done
+ // in a second step after getting all keys.
+ for (const QString &key : keys) {
+ if (!keyNameFromPrefixedStorageName(m_keyPrefixes.first(), key).isEmpty())
+ val::global("window")["localStorage"].call<val>("removeItem", key.toStdString());
+ }
+ });
}
void QWasmLocalStorageSettingsPrivate::sync() { }
@@ -154,19 +225,6 @@ QString QWasmLocalStorageSettingsPrivate::fileName() const
return QString();
}
-QString QWasmLocalStorageSettingsPrivate::prependStoragePrefix(const QString &key) const
-{
- return m_keyPrefix + key;
-}
-
-QStringView QWasmLocalStorageSettingsPrivate::removeStoragePrefix(QStringView key) const
-{
- // Return the key slice after m_keyPrefix, or an empty string view if no match
- if (!key.startsWith(m_keyPrefix))
- return QStringView();
- return key.sliced(m_keyPrefix.length());
-}
-
//
// Native settings implementation for WebAssembly using the indexed database as
// the storage backend
@@ -177,225 +235,168 @@ public:
QWasmIDBSettingsPrivate(QSettings::Scope scope, const QString &organization,
const QString &application);
~QWasmIDBSettingsPrivate();
- static QWasmIDBSettingsPrivate *get(void *userData);
- std::optional<QVariant> get(const QString &key) const override;
- QStringList children(const QString &prefix, ChildSpec spec) const override;
void clear() override;
void sync() override;
- void flush() override;
- bool isWritable() const override;
-
- void syncToLocal(const char *data, int size);
- void loadLocal(const QByteArray &filename);
- void setReady();
- void initAccess() override;
private:
+ bool writeSettingsToTemporaryFile(const QString &fileName, void *dataPtr, int size);
+ void loadIndexedDBFiles();
+
+
QString databaseName;
QString id;
- static QList<QWasmIDBSettingsPrivate *> liveSettings;
};
-QList<QWasmIDBSettingsPrivate *> QWasmIDBSettingsPrivate::liveSettings;
-static bool isReadReady = false;
-
-static void QWasmIDBSettingsPrivate_onLoad(void *userData, void *dataPtr, int size)
-{
- QWasmIDBSettingsPrivate *settings = QWasmIDBSettingsPrivate::get(userData);
- if (!settings)
- return;
-
- QFile file(settings->fileName());
- QFileInfo fileInfo(settings->fileName());
- QDir dir(fileInfo.path());
- if (!dir.exists())
- dir.mkpath(fileInfo.path());
-
- if (file.open(QFile::WriteOnly)) {
- file.write(reinterpret_cast<char *>(dataPtr), size);
- file.close();
- settings->setReady();
- }
-}
-
-static void QWasmIDBSettingsPrivate_onError(void *userData)
-{
- if (QWasmIDBSettingsPrivate *settings = QWasmIDBSettingsPrivate::get(userData))
- settings->setStatus(QSettings::AccessError);
-}
-
-static void QWasmIDBSettingsPrivate_onStore(void *userData)
-{
- if (QWasmIDBSettingsPrivate *settings = QWasmIDBSettingsPrivate::get(userData))
- settings->setStatus(QSettings::NoError);
-}
-
-static void QWasmIDBSettingsPrivate_onCheck(void *userData, int exists)
-{
- if (QWasmIDBSettingsPrivate *settings = QWasmIDBSettingsPrivate::get(userData)) {
- if (exists)
- settings->loadLocal(settings->fileName().toLocal8Bit());
- else
- settings->setReady();
- }
-}
+constexpr char DbName[] = "/home/web_user";
QWasmIDBSettingsPrivate::QWasmIDBSettingsPrivate(QSettings::Scope scope,
const QString &organization,
const QString &application)
- : QConfFileSettingsPrivate(QSettings::NativeFormat, scope, organization, application)
+ : QConfFileSettingsPrivate(QSettings::WebIndexedDBFormat, scope, organization, application)
{
- liveSettings.push_back(this);
+ Q_ASSERT_X(qstdweb::haveJspi(), Q_FUNC_INFO, "QWasmIDBSettingsPrivate needs JSPI to work");
+
+ if (organization.isEmpty()) {
+ setStatus(QSettings::AccessError);
+ return;
+ }
- setStatus(QSettings::AccessError); // access error until sandbox gets loaded
databaseName = organization;
id = application;
- emscripten_idb_async_exists("/home/web_user",
- fileName().toLocal8Bit(),
- reinterpret_cast<void*>(this),
- QWasmIDBSettingsPrivate_onCheck,
- QWasmIDBSettingsPrivate_onError);
-}
-
-QWasmIDBSettingsPrivate::~QWasmIDBSettingsPrivate()
-{
- liveSettings.removeAll(this);
-}
+ loadIndexedDBFiles();
-QWasmIDBSettingsPrivate *QWasmIDBSettingsPrivate::get(void *userData)
-{
- if (QWasmIDBSettingsPrivate::liveSettings.contains(userData))
- return reinterpret_cast<QWasmIDBSettingsPrivate *>(userData);
- return nullptr;
+ QConfFileSettingsPrivate::initAccess();
}
-void QWasmIDBSettingsPrivate::initAccess()
-{
- if (isReadReady)
- QConfFileSettingsPrivate::initAccess();
-}
+QWasmIDBSettingsPrivate::~QWasmIDBSettingsPrivate() = default;
-std::optional<QVariant> QWasmIDBSettingsPrivate::get(const QString &key) const
+bool QWasmIDBSettingsPrivate::writeSettingsToTemporaryFile(const QString &fileName, void *dataPtr,
+ int size)
{
- if (isReadReady)
- return QConfFileSettingsPrivate::get(key);
+ QFile file(fileName);
+ QFileInfo fileInfo(fileName);
+ QDir dir(fileInfo.path());
+ if (!dir.exists())
+ dir.mkpath(fileInfo.path());
- return std::nullopt;
-}
+ if (!file.open(QFile::WriteOnly))
+ return false;
-QStringList QWasmIDBSettingsPrivate::children(const QString &prefix, ChildSpec spec) const
-{
- return QConfFileSettingsPrivate::children(prefix, spec);
+ return size == file.write(reinterpret_cast<char *>(dataPtr), size);
}
void QWasmIDBSettingsPrivate::clear()
{
QConfFileSettingsPrivate::clear();
- emscripten_idb_async_delete("/home/web_user",
- fileName().toLocal8Bit(),
- reinterpret_cast<void*>(this),
- QWasmIDBSettingsPrivate_onStore,
- QWasmIDBSettingsPrivate_onError);
+
+ int error = 0;
+ emscripten_idb_delete(DbName, fileName().toLocal8Bit(), &error);
+ setStatus(!!error ? QSettings::AccessError : QSettings::NoError);
}
void QWasmIDBSettingsPrivate::sync()
{
+ // Reload the files, in case there were any changes in IndexedDB, and flush them to disk.
+ // Thanks to this, QConfFileSettingsPrivate::sync will handle key merging correctly.
+ loadIndexedDBFiles();
+
QConfFileSettingsPrivate::sync();
QFile file(fileName());
if (file.open(QFile::ReadOnly)) {
QByteArray dataPointer = file.readAll();
- emscripten_idb_async_store("/home/web_user",
- fileName().toLocal8Bit(),
- reinterpret_cast<void *>(dataPointer.data()),
- dataPointer.length(),
- reinterpret_cast<void*>(this),
- QWasmIDBSettingsPrivate_onStore,
- QWasmIDBSettingsPrivate_onError);
+ int error = 0;
+ emscripten_idb_store(DbName, fileName().toLocal8Bit(),
+ reinterpret_cast<void *>(dataPointer.data()), dataPointer.length(),
+ &error);
+ setStatus(!!error ? QSettings::AccessError : QSettings::NoError);
}
}
-void QWasmIDBSettingsPrivate::flush()
-{
- sync();
-}
-
-bool QWasmIDBSettingsPrivate::isWritable() const
+void QWasmIDBSettingsPrivate::loadIndexedDBFiles()
{
- return isReadReady && QConfFileSettingsPrivate::isWritable();
-}
-
-void QWasmIDBSettingsPrivate::syncToLocal(const char *data, int size)
-{
- QFile file(fileName());
-
- if (file.open(QFile::WriteOnly)) {
- file.write(data, size + 1);
- QByteArray data = file.readAll();
-
- emscripten_idb_async_store("/home/web_user",
- fileName().toLocal8Bit(),
- reinterpret_cast<void *>(data.data()),
- data.length(),
- reinterpret_cast<void*>(this),
- QWasmIDBSettingsPrivate_onStore,
- QWasmIDBSettingsPrivate_onError);
- setReady();
+ for (const auto *confFile : getConfFiles()) {
+ int exists = 0;
+ int error = 0;
+ emscripten_idb_exists(DbName, confFile->name.toLocal8Bit(), &exists, &error);
+ if (error) {
+ setStatus(QSettings::AccessError);
+ return;
+ }
+ if (exists) {
+ void *contents;
+ int size;
+ emscripten_idb_load(DbName, confFile->name.toLocal8Bit(), &contents, &size, &error);
+ if (error || !writeSettingsToTemporaryFile(confFile->name, contents, size)) {
+ setStatus(QSettings::AccessError);
+ return;
+ }
+ }
}
}
-void QWasmIDBSettingsPrivate::loadLocal(const QByteArray &filename)
-{
- emscripten_idb_async_load("/home/web_user",
- filename.data(),
- reinterpret_cast<void*>(this),
- QWasmIDBSettingsPrivate_onLoad,
- QWasmIDBSettingsPrivate_onError);
-}
-
-void QWasmIDBSettingsPrivate::setReady()
-{
- isReadReady = true;
- setStatus(QSettings::NoError);
- QConfFileSettingsPrivate::initAccess();
-}
-
QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope,
const QString &organization, const QString &application)
{
- const auto WebLocalStorageFormat = QSettings::IniFormat + 1;
- const auto WebIdbFormat = QSettings::IniFormat + 2;
-
// Make WebLocalStorageFormat the default native format
if (format == QSettings::NativeFormat)
- format = QSettings::Format(WebLocalStorageFormat);
+ format = QSettings::WebLocalStorageFormat;
// Check if cookies are enabled (required for using persistent storage)
- const bool cookiesEnabled = val::global("navigator")["cookieEnabled"].as<bool>();
- constexpr QLatin1StringView cookiesWarningMessage
- ("QSettings::%1 requires cookies, falling back to IniFormat with temporary file");
- if (format == WebLocalStorageFormat && !cookiesEnabled) {
- qWarning() << cookiesWarningMessage.arg("WebLocalStorageFormat");
- format = QSettings::IniFormat;
- } else if (format == WebIdbFormat && !cookiesEnabled) {
- qWarning() << cookiesWarningMessage.arg("WebIdbFormat");
+
+ const bool cookiesEnabled = qstdweb::runTaskOnMainThread<bool>(
+ []() { return val::global("navigator")["cookieEnabled"].as<bool>(); });
+
+ constexpr QLatin1StringView cookiesWarningMessage(
+ "QSettings::%1 requires cookies, falling back to IniFormat with temporary file");
+ if (!cookiesEnabled) {
+ if (format == QSettings::WebLocalStorageFormat) {
+ qWarning() << cookiesWarningMessage.arg("WebLocalStorageFormat");
+ format = QSettings::IniFormat;
+ } else if (format == QSettings::WebIndexedDBFormat) {
+ qWarning() << cookiesWarningMessage.arg("WebIndexedDBFormat");
+ format = QSettings::IniFormat;
+ }
+ }
+ if (format == QSettings::WebIndexedDBFormat && !qstdweb::haveJspi()) {
+ qWarning() << "QSettings::WebIndexedDBFormat requires JSPI, falling back to IniFormat with "
+ "temporary file";
format = QSettings::IniFormat;
}
// Create settings backend according to selected format
- if (format == WebLocalStorageFormat) {
+ switch (format) {
+ case QSettings::Format::WebLocalStorageFormat:
return new QWasmLocalStorageSettingsPrivate(scope, organization, application);
- } else if (format == WebIdbFormat) {
+ case QSettings::Format::WebIndexedDBFormat:
return new QWasmIDBSettingsPrivate(scope, organization, application);
- } else if (format == QSettings::IniFormat) {
+ case QSettings::Format::IniFormat:
+ case QSettings::Format::CustomFormat1:
+ case QSettings::Format::CustomFormat2:
+ case QSettings::Format::CustomFormat3:
+ case QSettings::Format::CustomFormat4:
+ case QSettings::Format::CustomFormat5:
+ case QSettings::Format::CustomFormat6:
+ case QSettings::Format::CustomFormat7:
+ case QSettings::Format::CustomFormat8:
+ case QSettings::Format::CustomFormat9:
+ case QSettings::Format::CustomFormat10:
+ case QSettings::Format::CustomFormat11:
+ case QSettings::Format::CustomFormat12:
+ case QSettings::Format::CustomFormat13:
+ case QSettings::Format::CustomFormat14:
+ case QSettings::Format::CustomFormat15:
+ case QSettings::Format::CustomFormat16:
return new QConfFileSettingsPrivate(format, scope, organization, application);
+ case QSettings::Format::InvalidFormat:
+ return nullptr;
+ case QSettings::Format::NativeFormat:
+ Q_UNREACHABLE();
+ break;
}
-
- qWarning() << "Unsupported settings format" << format;
- return nullptr;
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp
index 9a14ae0717..792721f50d 100644
--- a/src/corelib/io/qstandardpaths.cpp
+++ b/src/corelib/io/qstandardpaths.cpp
@@ -126,6 +126,12 @@ using namespace Qt::StringLiterals;
template files can be stored. This is a generic value. Note that the returned path may be
empty if the system has no concept of a templates location.
This enum value was added in Qt 6.4.
+ \value [since 6.7] StateLocation Returns a directory location where user-specific application
+ state data files should be written. This is an application-specific directory,
+ and the returned path is never empty.
+ \value [since 6.7] GenericStateLocation Returns a directory location where shared state data files
+ across applications should be written. This value might be generic or application-specific,
+ but the returned path is never empty.
The following table gives examples of paths on different operating systems.
The first path is the writable path (unless noted). Other, additional
@@ -166,6 +172,9 @@ using namespace Qt::StringLiterals;
\row \li CacheLocation
\li "~/Library/Caches/<APPNAME>", "/Library/Caches/<APPNAME>"
\li "C:/Users/<USER>/AppData/Local/<APPNAME>/cache"
+ \row \li StateLocation
+ \li "~/Library/Preferences/<APPNAME>/State"
+ \li "C:/Users/<USER>/AppData/Local/<APPNAME>/State", "C:/ProgramData/<APPNAME>/State"
\row \li GenericDataLocation
\li "~/Library/Application Support", "/Library/Application Support"
\li "C:/Users/<USER>/AppData/Local", "C:/ProgramData", "<APPDIR>", "<APPDIR>/data"
@@ -184,6 +193,9 @@ using namespace Qt::StringLiterals;
\row \li GenericCacheLocation
\li "~/Library/Caches", "/Library/Caches"
\li "C:/Users/<USER>/AppData/Local/cache"
+ \row \li GenericStateLocation
+ \li "~/Library/Preferences/State"
+ \li "C:/Users/<USER>/AppData/Local/State", "C:/ProgramData/State"
\row \li AppDataLocation
\li "~/Library/Application Support/<APPNAME>", "/Library/Application Support/<APPNAME>". "<APPDIR>/../Resources"
\li "C:/Users/<USER>/AppData/Roaming/<APPNAME>", "C:/ProgramData/<APPNAME>", "<APPDIR>", "<APPDIR>/data", "<APPDIR>/data/<APPNAME>"
@@ -222,6 +234,8 @@ using namespace Qt::StringLiterals;
\li "~/.local/share/<APPNAME>", "/usr/local/share/<APPNAME>", "/usr/share/<APPNAME>"
\row \li CacheLocation
\li "~/.cache/<APPNAME>"
+ \row \li StateLocation
+ \li "~/.local/state/<APPNAME>"
\row \li GenericDataLocation
\li "~/.local/share", "/usr/local/share", "/usr/share"
\row \li RuntimeLocation
@@ -234,6 +248,8 @@ using namespace Qt::StringLiterals;
\li "~/Downloads"
\row \li GenericCacheLocation
\li "~/.cache"
+ \row \li GenericStateLocation
+ \li "~/.local/state"
\row \li AppDataLocation
\li "~/.local/share/<APPNAME>", "/usr/local/share/<APPNAME>", "/usr/share/<APPNAME>"
\row \li AppConfigLocation
@@ -279,6 +295,10 @@ using namespace Qt::StringLiterals;
\row \li CacheLocation
\li "<APPROOT>/cache", "<USER>/<APPNAME>/cache"
\li "<APPROOT>/Library/Caches"
+ \row \li StateLocation
+ \li "<APPROOT>/files/state"
+ \row \li GenericStateLocation (there is shared state)
+ \li "<APPROOT>/files/state"
\row \li GenericDataLocation
\li "<USER>" [*] or "<USER>/<APPNAME>/files"
\li "<APPROOT>/Library/Application Support"
@@ -520,6 +540,8 @@ QString QStandardPaths::findExecutable(const QString &executableName, const QStr
}
/*!
+ \fn QString QStandardPaths::displayName(StandardLocation type)
+
\include standardpath/functiondocs.qdocinc displayName
*/
@@ -549,6 +571,8 @@ QString QStandardPaths::displayName(StandardLocation type)
return QCoreApplication::translate("QStandardPaths", "Application Data");
case CacheLocation:
return QCoreApplication::translate("QStandardPaths", "Cache");
+ case StateLocation:
+ return QCoreApplication::translate("QStandardPaths", "State");
case GenericDataLocation:
return QCoreApplication::translate("QStandardPaths", "Shared Data");
case RuntimeLocation:
@@ -559,6 +583,8 @@ QString QStandardPaths::displayName(StandardLocation type)
return QCoreApplication::translate("QStandardPaths", "Shared Configuration");
case GenericCacheLocation:
return QCoreApplication::translate("QStandardPaths", "Shared Cache");
+ case GenericStateLocation:
+ return QCoreApplication::translate("QStandardPaths", "Shared State");
case DownloadLocation:
return QCoreApplication::translate("QStandardPaths", "Download");
case AppDataLocation:
diff --git a/src/corelib/io/qstandardpaths.h b/src/corelib/io/qstandardpaths.h
index ca1e37d92c..56aa2b100c 100644
--- a/src/corelib/io/qstandardpaths.h
+++ b/src/corelib/io/qstandardpaths.h
@@ -38,7 +38,9 @@ public:
AppDataLocation,
AppConfigLocation,
PublicShareLocation,
- TemplatesLocation
+ TemplatesLocation,
+ StateLocation,
+ GenericStateLocation,
};
Q_ENUM(StandardLocation)
diff --git a/src/corelib/io/qstandardpaths_android.cpp b/src/corelib/io/qstandardpaths_android.cpp
index e058f379c2..f39b6855b6 100644
--- a/src/corelib/io/qstandardpaths_android.cpp
+++ b/src/corelib/io/qstandardpaths_android.cpp
@@ -13,7 +13,7 @@
QT_BEGIN_NAMESPACE
Q_DECLARE_JNI_CLASS(Environment, "android/os/Environment");
-Q_DECLARE_JNI_TYPE(File, "Ljava/io/File;");
+Q_DECLARE_JNI_CLASS(File, "java/io/File");
using namespace QNativeInterface;
using namespace Qt::StringLiterals;
@@ -195,6 +195,9 @@ QString QStandardPaths::writableLocation(StandardLocation type)
case QStandardPaths::ConfigLocation:
case QStandardPaths::AppConfigLocation:
return getFilesDir() + testDir() + "/settings"_L1;
+ case QStandardPaths::StateLocation:
+ case QStandardPaths::GenericStateLocation:
+ return getFilesDir() + testDir() + "/state"_L1;
case QStandardPaths::GenericDataLocation:
{
return QAndroidApplication::sdkVersion() >= 30 ?
diff --git a/src/corelib/io/qstandardpaths_haiku.cpp b/src/corelib/io/qstandardpaths_haiku.cpp
index 6122e5f6f9..93eba134f3 100644
--- a/src/corelib/io/qstandardpaths_haiku.cpp
+++ b/src/corelib/io/qstandardpaths_haiku.cpp
@@ -120,8 +120,10 @@ QString QStandardPaths::writableLocation(StandardLocation type)
return haikuAppStandardPath(B_USER_CACHE_DIRECTORY);
case GenericCacheLocation:
return haikuStandardPath(B_USER_CACHE_DIRECTORY);
- case ConfigLocation: // fall through
+ case ConfigLocation:
case AppConfigLocation:
+ case StateLocation:
+ case GenericStateLocation:
return haikuAppStandardPath(B_USER_SETTINGS_DIRECTORY);
case GenericConfigLocation:
return haikuStandardPath(B_USER_SETTINGS_DIRECTORY);
diff --git a/src/corelib/io/qstandardpaths_mac.mm b/src/corelib/io/qstandardpaths_mac.mm
index 5a41ae8e92..2acbe92736 100644
--- a/src/corelib/io/qstandardpaths_mac.mm
+++ b/src/corelib/io/qstandardpaths_mac.mm
@@ -120,6 +120,12 @@ static QString baseWritableLocation(QStandardPaths::StandardLocation type,
case QStandardPaths::AppConfigLocation:
path = pathForDirectory(NSLibraryDirectory, mask) + "/Preferences"_L1;
break;
+ case QStandardPaths::StateLocation:
+ if (appendOrgAndApp) { break; }
+ Q_FALLTHROUGH();
+ case QStandardPaths::GenericStateLocation:
+ path = pathForDirectory(NSLibraryDirectory, mask) + "/Preferences/State"_L1;
+ break;
default:
path = pathForDirectory(dir, mask);
break;
@@ -133,6 +139,11 @@ static QString baseWritableLocation(QStandardPaths::StandardLocation type,
case QStandardPaths::CacheLocation:
appendOrganizationAndApp(path);
break;
+ case QStandardPaths::StateLocation:
+ path = pathForDirectory(NSLibraryDirectory, mask) + "/Preferences"_L1;
+ appendOrganizationAndApp(path);
+ path += "/State"_L1;
+ break;
default:
break;
}
diff --git a/src/corelib/io/qstandardpaths_unix.cpp b/src/corelib/io/qstandardpaths_unix.cpp
index 55150f9e93..e38f670895 100644
--- a/src/corelib/io/qstandardpaths_unix.cpp
+++ b/src/corelib/io/qstandardpaths_unix.cpp
@@ -180,33 +180,56 @@ QString QStandardPaths::writableLocation(StandardLocation type)
case CacheLocation:
case GenericCacheLocation:
{
- if (isTestModeEnabled())
- return QDir::homePath() + "/.qttest/cache"_L1;
-
- // http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
- QString xdgCacheHome = QFile::decodeName(qgetenv("XDG_CACHE_HOME"));
- if (!xdgCacheHome.startsWith(u'/'))
- xdgCacheHome.clear(); // spec says relative paths should be ignored
-
- if (xdgCacheHome.isEmpty())
- xdgCacheHome = QDir::homePath() + "/.cache"_L1;
+ QString xdgCacheHome;
+ if (isTestModeEnabled()) {
+ xdgCacheHome = QDir::homePath() + "/.qttest/cache"_L1;
+ } else {
+ // http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
+ xdgCacheHome = QFile::decodeName(qgetenv("XDG_CACHE_HOME"));
+ if (!xdgCacheHome.startsWith(u'/'))
+ xdgCacheHome.clear(); // spec says relative paths should be ignored
+
+ if (xdgCacheHome.isEmpty())
+ xdgCacheHome = QDir::homePath() + "/.cache"_L1;
+ }
if (type == QStandardPaths::CacheLocation)
appendOrganizationAndApp(xdgCacheHome);
return xdgCacheHome;
}
+ case StateLocation:
+ case GenericStateLocation:
+ {
+ QString xdgStateHome;
+ if (isTestModeEnabled()) {
+ xdgStateHome = QDir::homePath() + "/.qttest/state"_L1;
+ } else {
+ // http://standards.freedesktop.org/basedir-spec/basedir-spec-0.8.html
+ xdgStateHome = QFile::decodeName(qgetenv("XDG_STATE_HOME"));
+ if (!xdgStateHome.startsWith(u'/'))
+ xdgStateHome.clear(); // spec says relative paths should be ignored
+
+ if (xdgStateHome.isEmpty())
+ xdgStateHome = QDir::homePath() + "/.local/state"_L1;
+ }
+ if (type == QStandardPaths::StateLocation)
+ appendOrganizationAndApp(xdgStateHome);
+ return xdgStateHome;
+ }
case AppDataLocation:
case AppLocalDataLocation:
case GenericDataLocation:
{
- if (isTestModeEnabled())
- return QDir::homePath() + "/.qttest/share"_L1;
-
- QString xdgDataHome = QFile::decodeName(qgetenv("XDG_DATA_HOME"));
- if (!xdgDataHome.startsWith(u'/'))
- xdgDataHome.clear(); // spec says relative paths should be ignored
-
- if (xdgDataHome.isEmpty())
- xdgDataHome = QDir::homePath() + "/.local/share"_L1;
+ QString xdgDataHome;
+ if (isTestModeEnabled()) {
+ xdgDataHome = QDir::homePath() + "/.qttest/share"_L1;
+ } else {
+ xdgDataHome = QFile::decodeName(qgetenv("XDG_DATA_HOME"));
+ if (!xdgDataHome.startsWith(u'/'))
+ xdgDataHome.clear(); // spec says relative paths should be ignored
+
+ if (xdgDataHome.isEmpty())
+ xdgDataHome = QDir::homePath() + "/.local/share"_L1;
+ }
if (type == AppDataLocation || type == AppLocalDataLocation)
appendOrganizationAndApp(xdgDataHome);
return xdgDataHome;
@@ -215,16 +238,18 @@ QString QStandardPaths::writableLocation(StandardLocation type)
case GenericConfigLocation:
case AppConfigLocation:
{
- if (isTestModeEnabled())
- return QDir::homePath() + "/.qttest/config"_L1;
-
- // http://standards.freedesktop.org/basedir-spec/latest/
- QString xdgConfigHome = QFile::decodeName(qgetenv("XDG_CONFIG_HOME"));
- if (!xdgConfigHome.startsWith(u'/'))
- xdgConfigHome.clear(); // spec says relative paths should be ignored
-
- if (xdgConfigHome.isEmpty())
- xdgConfigHome = QDir::homePath() + "/.config"_L1;
+ QString xdgConfigHome;
+ if (isTestModeEnabled()) {
+ xdgConfigHome = QDir::homePath() + "/.qttest/config"_L1;
+ } else {
+ // http://standards.freedesktop.org/basedir-spec/latest/
+ xdgConfigHome = QFile::decodeName(qgetenv("XDG_CONFIG_HOME"));
+ if (!xdgConfigHome.startsWith(u'/'))
+ xdgConfigHome.clear(); // spec says relative paths should be ignored
+
+ if (xdgConfigHome.isEmpty())
+ xdgConfigHome = QDir::homePath() + "/.config"_L1;
+ }
if (type == AppConfigLocation)
appendOrganizationAndApp(xdgConfigHome);
return xdgConfigHome;
@@ -351,9 +376,9 @@ static QStringList dirsList(const QString &xdgEnvVar)
if (dir.startsWith(u'/'))
dirs.push_back(QDir::cleanPath(dir.toString()));
- // Remove duplicates from the list, there's no use for duplicated
- // paths in XDG_DATA_DIRS - if it's not found in the given
- // directory the first time, it won't be there the second time.
+ // Remove duplicates from the list, there's no use for duplicated paths
+ // in XDG_* env vars - if whatever is being looked for is not found in
+ // the given directory the first time, it won't be there the second time.
// Plus duplicate paths causes problems for example for mimetypes,
// where duplicate paths here lead to duplicated mime types returned
// for a file, eg "text/plain,text/plain" instead of "text/plain"
diff --git a/src/corelib/io/qstandardpaths_win.cpp b/src/corelib/io/qstandardpaths_win.cpp
index 13b8fe224a..805ce65a5a 100644
--- a/src/corelib/io/qstandardpaths_win.cpp
+++ b/src/corelib/io/qstandardpaths_win.cpp
@@ -105,8 +105,10 @@ static GUID writableSpecialFolderId(QStandardPaths::StandardLocation type)
FOLDERID_LocalAppData, // AppConfigLocation ("Local" path)
FOLDERID_Public, // PublicShareLocation
FOLDERID_Templates, // TemplatesLocation
+ GUID(), // StateLocation
+ GUID(), // GenericStateLocation
};
- static_assert(sizeof(folderIds) / sizeof(folderIds[0]) == size_t(QStandardPaths::TemplatesLocation + 1));
+ static_assert(sizeof(folderIds) / sizeof(folderIds[0]) == size_t(QStandardPaths::GenericStateLocation + 1));
// folders for low integrity processes
static const GUID folderIds_li[] = {
@@ -130,6 +132,8 @@ static GUID writableSpecialFolderId(QStandardPaths::StandardLocation type)
FOLDERID_LocalAppDataLow,// AppConfigLocation ("Local" path)
FOLDERID_Public, // PublicShareLocation
FOLDERID_Templates, // TemplatesLocation
+ GUID(), // StateLocation
+ GUID(), // GenericStateLocation
};
static_assert(sizeof(folderIds_li) == sizeof(folderIds));
@@ -184,6 +188,23 @@ QString QStandardPaths::writableLocation(StandardLocation type)
result = QDir::tempPath();
break;
+ case StateLocation:
+ result = sHGetKnownFolderPath(writableSpecialFolderId(AppLocalDataLocation));
+ if (!result.isEmpty()) {
+ appendTestMode(result);
+ appendOrganizationAndApp(result);
+ result += "/State"_L1;
+ }
+ break;
+
+ case GenericStateLocation:
+ result = sHGetKnownFolderPath(writableSpecialFolderId(GenericDataLocation));
+ if (!result.isEmpty()) {
+ appendTestMode(result);
+ result += "/State"_L1;
+ }
+ break;
+
default:
result = sHGetKnownFolderPath(writableSpecialFolderId(type));
if (!result.isEmpty() && isConfigLocation(type)) {
diff --git a/src/corelib/io/qstorageinfo.cpp b/src/corelib/io/qstorageinfo.cpp
index 25b11103b9..b7a17febaf 100644
--- a/src/corelib/io/qstorageinfo.cpp
+++ b/src/corelib/io/qstorageinfo.cpp
@@ -20,6 +20,8 @@ QT_IMPL_METATYPE_EXTERN(QStorageInfo)
\ingroup io
\ingroup shared
+ \compares equality
+
Allows retrieving information about the volume's space, its mount point,
label, and filesystem name.
@@ -37,6 +39,11 @@ QT_IMPL_METATYPE_EXTERN(QStorageInfo)
\snippet code/src_corelib_io_qstorageinfo.cpp 2
*/
+QStorageInfo::QStorageInfo(QStorageInfoPrivate &dd)
+ : d(&dd)
+{
+}
+
/*!
Constructs an empty QStorageInfo object.
@@ -241,9 +248,10 @@ QByteArray QStorageInfo::device() const
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.
+ may be mounted in different paths (e.g. 'bind' mounts on Unix, or Btrfs
+ filesystem subvolumes). If the subvolume could be detected, its name is
+ returned by this function. 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
@@ -380,22 +388,29 @@ QStorageInfo QStorageInfo::root()
}
/*!
- \fn bool QStorageInfo::operator==(const QStorageInfo &first, const QStorageInfo &second)
+ \fn bool QStorageInfo::operator==(const QStorageInfo &lhs, const QStorageInfo &rhs)
- Returns true if the \a first QStorageInfo object refers to the same drive or volume
- as the \a second; otherwise it returns false.
+ Returns \c true if the QStorageInfo object \a lhs refers to the same drive or
+ volume as the QStorageInfo object \a rhs; otherwise it returns \c false.
Note that the result of comparing two invalid QStorageInfo objects is always
positive.
*/
/*!
- \fn bool QStorageInfo::operator!=(const QStorageInfo &first, const QStorageInfo &second)
+ \fn bool QStorageInfo::operator!=(const QStorageInfo &lhs, const QStorageInfo &rhs)
- Returns true if the \a first QStorageInfo object refers to a different drive or
- volume than the \a second; otherwise returns false.
+ Returns \c true if the QStorageInfo object \a lhs refers to a different drive or
+ volume than the QStorageInfo object \a rhs; otherwise returns \c false.
*/
+bool comparesEqual(const QStorageInfo &lhs, const QStorageInfo &rhs)
+{
+ if (lhs.d == rhs.d)
+ return true;
+ return lhs.device() == rhs.device() && lhs.rootPath() == rhs.rootPath();
+}
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug debug, const QStorageInfo &s)
{
diff --git a/src/corelib/io/qstorageinfo.h b/src/corelib/io/qstorageinfo.h
index d25eee1840..3784fe8e47 100644
--- a/src/corelib/io/qstorageinfo.h
+++ b/src/corelib/io/qstorageinfo.h
@@ -5,6 +5,7 @@
#define QSTORAGEINFO_H
#include <QtCore/qbytearray.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qdir.h>
#include <QtCore/qlist.h>
#include <QtCore/qmetatype.h>
@@ -56,18 +57,10 @@ public:
static QStorageInfo root();
private:
+ explicit QStorageInfo(QStorageInfoPrivate &dd);
friend class QStorageInfoPrivate;
- friend inline bool operator==(const QStorageInfo &first, const QStorageInfo &second)
- {
- if (first.d == second.d)
- return true;
- return first.device() == second.device() && first.rootPath() == second.rootPath();
- }
-
- friend inline bool operator!=(const QStorageInfo &first, const QStorageInfo &second)
- {
- return !(first == second);
- }
+ friend Q_CORE_EXPORT bool comparesEqual(const QStorageInfo &lhs, const QStorageInfo &rhs);
+ Q_DECLARE_EQUALITY_COMPARABLE(QStorageInfo)
friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QStorageInfo &);
QExplicitlySharedDataPointer<QStorageInfoPrivate> d;
diff --git a/src/corelib/io/qstorageinfo_linux.cpp b/src/corelib/io/qstorageinfo_linux.cpp
new file mode 100644
index 0000000000..a9d46e7395
--- /dev/null
+++ b/src/corelib/io/qstorageinfo_linux.cpp
@@ -0,0 +1,288 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
+// Copyright (C) 2016 Intel Corporation.
+// Copyright (C) 2023 Ahmad Samir <a.samirh78@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qstorageinfo_linux_p.h"
+
+#include "qdirlisting.h"
+#include <private/qcore_unix_p.h>
+#include <private/qtools_p.h>
+
+#include <q20memory.h>
+
+#include <sys/ioctl.h>
+#include <sys/statfs.h>
+
+// so we don't have to #include <linux/fs.h>, which is known to cause conflicts
+#ifndef FSLABEL_MAX
+# define FSLABEL_MAX 256
+#endif
+#ifndef FS_IOC_GETFSLABEL
+# define FS_IOC_GETFSLABEL _IOR(0x94, 49, char[FSLABEL_MAX])
+#endif
+
+// or <linux/statfs.h>
+#ifndef ST_RDONLY
+# define ST_RDONLY 0x0001 /* mount read-only */
+#endif
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+// udev encodes the labels with ID_LABEL_FS_ENC which is done with
+// blkid_encode_string(). Within this function some 1-byte utf-8
+// characters not considered safe (e.g. '\' or ' ') are encoded as hex
+static QString decodeFsEncString(QString &&str)
+{
+ using namespace QtMiscUtils;
+ qsizetype start = str.indexOf(u'\\');
+ if (start < 0)
+ return std::move(str);
+
+ // decode in-place
+ QString decoded = std::move(str);
+ auto ptr = reinterpret_cast<char16_t *>(decoded.begin());
+ qsizetype in = start;
+ qsizetype out = start;
+ qsizetype size = decoded.size();
+
+ while (in < size) {
+ Q_ASSERT(ptr[in] == u'\\');
+ if (size - in >= 4 && ptr[in + 1] == u'x') { // we need four characters: \xAB
+ int c = fromHex(ptr[in + 2]) << 4;
+ c |= fromHex(ptr[in + 3]);
+ if (Q_UNLIKELY(c < 0))
+ c = QChar::ReplacementCharacter; // bad hex sequence
+ ptr[out++] = c;
+ in += 4;
+ }
+
+ for ( ; in < size; ++in) {
+ char16_t c = ptr[in];
+ if (c == u'\\')
+ break;
+ ptr[out++] = c;
+ }
+ }
+ decoded.resize(out);
+ return decoded;
+}
+
+static inline dev_t deviceIdForPath(const QString &device)
+{
+ QT_STATBUF st;
+ if (QT_STAT(QFile::encodeName(device), &st) < 0)
+ return 0;
+ return st.st_dev;
+}
+
+static inline quint64 retrieveDeviceId(const QByteArray &device, quint64 deviceId = 0)
+{
+ // major = 0 implies an anonymous block device, so we need to stat() the
+ // actual device to get its dev_t. This is required for btrfs (and possibly
+ // others), which always uses them for all the subvolumes (including the
+ // root):
+ // https://codebrowser.dev/linux/linux/fs/btrfs/disk-io.c.html#btrfs_init_fs_root
+ // https://codebrowser.dev/linux/linux/fs/super.c.html#get_anon_bdev
+ // For everything else, we trust the parameter.
+ if (major(deviceId) != 0)
+ return deviceId;
+
+ // don't even try to stat() a relative path or "/"
+ if (device.size() < 2 || !device.startsWith('/'))
+ return 0;
+
+ QT_STATBUF st;
+ if (QT_STAT(device, &st) < 0)
+ return 0;
+ if (!S_ISBLK(st.st_mode))
+ return 0;
+ return st.st_rdev;
+}
+
+static QDirListing devicesByLabel()
+{
+ static const char pathDiskByLabel[] = "/dev/disk/by-label";
+ static constexpr auto LabelFileFilter =
+ QDir::AllEntries | QDir::System | QDir::Hidden | QDir::NoDotAndDotDot;
+
+ return QDirListing(QLatin1StringView(pathDiskByLabel), LabelFileFilter);
+}
+
+static inline auto retrieveLabels()
+{
+ struct Entry {
+ QString label;
+ quint64 deviceId;
+ };
+ QList<Entry> result;
+
+ for (const auto &dirEntry : devicesByLabel()) {
+ quint64 deviceId = retrieveDeviceId(QFile::encodeName(dirEntry.filePath()));
+ if (!deviceId)
+ continue;
+ result.emplaceBack(Entry{ decodeFsEncString(dirEntry.fileName()), deviceId });
+ }
+ return result;
+}
+
+static std::optional<QString> retrieveLabelViaIoctl(const QString &path)
+{
+ // FS_IOC_GETFSLABEL was introduced in v4.18; previously it was btrfs-specific.
+ int fd = qt_safe_open(QFile::encodeName(path).constData(), QT_OPEN_RDONLY);
+ if (fd < 0)
+ return std::nullopt;
+
+ // Note: it doesn't append the null terminator (despite what the man page
+ // says) and the return code on success (0) does not indicate the length.
+ char label[FSLABEL_MAX] = {};
+ int r = ioctl(fd, FS_IOC_GETFSLABEL, &label);
+ close(fd);
+ if (r < 0)
+ return std::nullopt;
+ return QString::fromUtf8(label);
+}
+
+static inline QString retrieveLabel(const QStorageInfoPrivate &d, quint64 deviceId)
+{
+ if (auto label = retrieveLabelViaIoctl(d.rootPath))
+ return *label;
+
+ deviceId = retrieveDeviceId(d.device, deviceId);
+ if (!deviceId)
+ return QString();
+
+ for (const auto &dirEntry : devicesByLabel()) {
+ if (retrieveDeviceId(QFile::encodeName(dirEntry.filePath())) == deviceId)
+ return decodeFsEncString(dirEntry.fileName());
+ }
+ return QString();
+}
+
+void QStorageInfoPrivate::retrieveVolumeInfo()
+{
+ struct statfs64 statfs_buf;
+ int result;
+ QT_EINTR_LOOP(result, statfs64(QFile::encodeName(rootPath).constData(), &statfs_buf));
+ if (result == 0) {
+ valid = true;
+ ready = true;
+
+ bytesTotal = statfs_buf.f_blocks * statfs_buf.f_frsize;
+ bytesFree = statfs_buf.f_bfree * statfs_buf.f_frsize;
+ bytesAvailable = statfs_buf.f_bavail * statfs_buf.f_frsize;
+ blockSize = int(statfs_buf.f_bsize);
+ readOnly = (statfs_buf.f_flags & ST_RDONLY) != 0;
+ }
+}
+
+static std::vector<MountInfo> parseMountInfo(FilterMountInfo filter = FilterMountInfo::All)
+{
+ QFile file(u"/proc/self/mountinfo"_s);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
+ return {};
+
+ QByteArray mountinfo = file.readAll();
+ file.close();
+
+ return doParseMountInfo(mountinfo, filter);
+}
+
+void QStorageInfoPrivate::doStat()
+{
+ retrieveVolumeInfo();
+ if (!ready)
+ return;
+
+ rootPath = QFileInfo(rootPath).canonicalFilePath();
+ if (rootPath.isEmpty())
+ return;
+
+ std::vector<MountInfo> infos = parseMountInfo();
+ if (infos.empty()) {
+ rootPath = u'/';
+ return;
+ }
+
+ // We iterate over the /proc/self/mountinfo list backwards because then any
+ // matching isParentOf must be the actual mount point because it's the most
+ // recent mount on that path. Linux does allow mounting over non-empty
+ // directories, such as in:
+ // # mount | tail -2
+ // tmpfs on /tmp/foo/bar type tmpfs (rw,relatime,inode64)
+ // tmpfs on /tmp/foo type tmpfs (rw,relatime,inode64)
+ //
+ // We try to match the device ID in case there's a mount --move.
+ // We can't *rely* on it because some filesystems like btrfs will assign
+ // device IDs to subvolumes that aren't listed in /proc/self/mountinfo.
+
+ const QString oldRootPath = std::exchange(rootPath, QString());
+ const dev_t rootPathDevId = deviceIdForPath(oldRootPath);
+ MountInfo *best = nullptr;
+ for (auto it = infos.rbegin(); it != infos.rend(); ++it) {
+ if (!isParentOf(it->mountPoint, oldRootPath))
+ continue;
+ if (rootPathDevId == it->stDev) {
+ // device ID matches; this is definitely the best option
+ best = q20::to_address(it);
+ break;
+ }
+ if (!best) {
+ // if we can't find a device ID match, this parent path is probably
+ // the correct one
+ best = q20::to_address(it);
+ }
+ }
+ if (best) {
+ auto stDev = best->stDev;
+ setFromMountInfo(std::move(*best));
+ name = retrieveLabel(*this, stDev);
+ }
+}
+
+QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
+{
+ std::vector<MountInfo> infos = parseMountInfo(FilterMountInfo::Filtered);
+ if (infos.empty())
+ return QList{root()};
+
+ std::optional<decltype(retrieveLabels())> labelMap;
+ auto labelForDevice = [&labelMap](const QStorageInfoPrivate &d, quint64 devid) {
+ if (d.fileSystemType == "tmpfs")
+ return QString();
+
+ if (auto label = retrieveLabelViaIoctl(d.rootPath))
+ return *label;
+
+ devid = retrieveDeviceId(d.device, devid);
+ if (!devid)
+ return QString();
+
+ if (!labelMap)
+ labelMap = retrieveLabels();
+ for (auto &[deviceLabel, deviceId] : std::as_const(*labelMap)) {
+ if (devid == deviceId)
+ return deviceLabel;
+ }
+ return QString();
+ };
+
+ QList<QStorageInfo> volumes;
+ for (MountInfo &info : infos) {
+ const auto infoStDev = info.stDev;
+ QStorageInfoPrivate d(std::move(info));
+ d.retrieveVolumeInfo();
+ if (d.bytesTotal <= 0 && d.rootPath != u'/')
+ continue;
+ if (infoStDev != deviceIdForPath(d.rootPath))
+ continue; // probably something mounted over this mountpoint
+ d.name = labelForDevice(d, infoStDev);
+ volumes.emplace_back(QStorageInfo(*new QStorageInfoPrivate(std::move(d))));
+ }
+ return volumes;
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qstorageinfo_linux_p.h b/src/corelib/io/qstorageinfo_linux_p.h
new file mode 100644
index 0000000000..6f5e107ec6
--- /dev/null
+++ b/src/corelib/io/qstorageinfo_linux_p.h
@@ -0,0 +1,244 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2014 Ivan Komissarov <ABBAPOH@gmail.com>
+// Copyright (C) 2016 Intel Corporation.
+// Copyright (C) 2023 Ahmad Samir <a.samirh78@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSTORAGEINFO_LINUX_P_H
+#define QSTORAGEINFO_LINUX_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API.
+// This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qstorageinfo_p.h"
+
+#include <QtCore/qsystemdetection.h>
+#include <QtCore/private/qlocale_tools_p.h>
+
+#include <sys/sysmacros.h> // makedev()
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+using MountInfo = QStorageInfoPrivate::MountInfo;
+
+static const char MountInfoPath[] = "/proc/self/mountinfo";
+
+static std::optional<dev_t> deviceNumber(QByteArrayView devno)
+{
+ // major:minor
+ auto it = devno.cbegin();
+ auto r = qstrntoll(it, devno.size(), 10);
+ if (!r.ok())
+ return std::nullopt;
+ int rdevmajor = int(r.result);
+ it += r.used;
+
+ if (*it != ':')
+ return std::nullopt;
+
+ r = qstrntoll(++it, devno.size() - r.used + 1, 10);
+ if (!r.ok())
+ return std::nullopt;
+
+ return makedev(rdevmajor, r.result);
+}
+
+// Helper function to parse paths that the kernel inserts escape sequences
+// for.
+static QByteArray parseMangledPath(QByteArrayView path)
+{
+ // The kernel escapes with octal the following characters:
+ // space ' ', tab '\t', backslash '\\', and newline '\n'
+ // See:
+ // https://codebrowser.dev/linux/linux/fs/proc_namespace.c.html#show_mountinfo
+ // https://codebrowser.dev/linux/linux/fs/seq_file.c.html#mangle_path
+
+ QByteArray ret(path.size(), '\0');
+ char *dst = ret.data();
+ const char *src = path.data();
+ const char *srcEnd = path.data() + path.size();
+ while (src != srcEnd) {
+ switch (*src) {
+ case ' ': // Shouldn't happen
+ return {};
+
+ case '\\': {
+ // It always uses exactly three octal characters.
+ ++src;
+ char c = (*src++ - '0') << 6;
+ c |= (*src++ - '0') << 3;
+ c |= (*src++ - '0');
+ *dst++ = c;
+ break;
+ }
+
+ default:
+ *dst++ = *src++;
+ break;
+ }
+ }
+ // If "path" contains any of the characters this method is demangling,
+ // "ret" would be oversized with extra '\0' characters at the end.
+ ret.resize(dst - ret.data());
+ return ret;
+}
+
+// Indexes into the "fields" std::array in parseMountInfo()
+// static constexpr short MountId = 0;
+// static constexpr short ParentId = 1;
+static constexpr short DevNo = 2;
+static constexpr short FsRoot = 3;
+static constexpr short MountPoint = 4;
+static constexpr short MountOptions = 5;
+// static constexpr short OptionalFields = 6;
+// static constexpr short Separator = 7;
+static constexpr short FsType = 8;
+static constexpr short MountSource = 9;
+static constexpr short SuperOptions = 10;
+static constexpr short FieldCount = 11;
+
+// Splits a line from /proc/self/mountinfo into fields; fields are separated
+// by a single space.
+static void tokenizeLine(std::array<QByteArrayView, FieldCount> &fields, QByteArrayView line)
+{
+ size_t fieldIndex = 0;
+ qsizetype from = 0;
+ const char *begin = line.data();
+ const qsizetype len = line.size();
+ qsizetype spaceIndex = -1;
+ while ((spaceIndex = line.indexOf(' ', from)) != -1 && fieldIndex < FieldCount) {
+ fields[fieldIndex] = QByteArrayView{begin + from, begin + spaceIndex};
+ from = spaceIndex;
+
+ // Skip "OptionalFields" and Separator fields
+ if (fieldIndex == MountOptions) {
+ static constexpr char separatorField[] = " - ";
+ const qsizetype sepIndex = line.indexOf(separatorField, from);
+ if (sepIndex == -1) {
+ qCWarning(lcStorageInfo,
+ "Malformed line (missing '-' separator field) while parsing '%s':\n%s",
+ MountInfoPath, line.constData());
+ fields.fill({});
+ return;
+ }
+
+ from = sepIndex + strlen(separatorField);
+ // Continue parsing at FsType field
+ fieldIndex = FsType;
+ continue;
+ }
+
+ if (from + 1 < len)
+ ++from; // Skip the space at spaceIndex
+
+ ++fieldIndex;
+ }
+
+ // Currently we don't use the last field, so just check the index
+ if (fieldIndex != SuperOptions) {
+ qCInfo(lcStorageInfo,
+ "Expected %d fields while parsing line from '%s', but found %zu instead:\n%.*s",
+ FieldCount, MountInfoPath, fieldIndex, int(line.size()), line.data());
+ fields.fill({});
+ }
+}
+
+// parseMountInfo() is called from:
+// - QStorageInfoPrivate::initRootPath(), where a list of all mounted volumes is needed
+// - QStorageInfoPrivate::mountedVolumes(), where some filesystem types are ignored
+// (see shouldIncludefs())
+enum class FilterMountInfo {
+ All,
+ Filtered,
+};
+
+[[maybe_unused]] static std::vector<MountInfo>
+doParseMountInfo(const QByteArray &mountinfo, FilterMountInfo filter = FilterMountInfo::All)
+{
+ // https://www.kernel.org/doc/Documentation/filesystems/proc.txt:
+ // 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
+ // (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
+
+ auto it = mountinfo.cbegin();
+ const auto end = mountinfo.cend();
+ auto nextLine = [&it, &end]() -> QByteArrayView {
+ auto nIt = std::find(it, end, '\n');
+ if (nIt != end) {
+ QByteArrayView ba(it, nIt);
+ it = ++nIt; // Advance
+ return ba;
+ }
+ return {};
+ };
+
+ std::vector<MountInfo> infos;
+ std::array<QByteArrayView, FieldCount> fields;
+ QByteArrayView line;
+
+ auto checkField = [&line](QByteArrayView field) {
+ if (field.isEmpty()) {
+ qDebug("Failed to parse line from %s:\n%.*s", MountInfoPath, int(line.size()),
+ line.data());
+ return false;
+ }
+ return true;
+ };
+
+ // mountinfo has a stable format, no empty lines
+ while (!(line = nextLine()).isEmpty()) {
+ fields.fill({});
+ tokenizeLine(fields, line);
+
+ MountInfo info;
+ QByteArray mountP = parseMangledPath(fields[MountPoint]);
+ if (!checkField(mountP))
+ continue;
+ info.mountPoint = QFile::decodeName(mountP);
+
+ if (!checkField(fields[FsType]))
+ continue;
+ info.fsType = fields[FsType].toByteArray();
+
+ if (filter == FilterMountInfo::Filtered && !shouldIncludeFs(info.mountPoint, info.fsType))
+ continue;
+
+ std::optional<dev_t> devno = deviceNumber(fields[DevNo]);
+ if (!devno) {
+ checkField({});
+ continue;
+ }
+ info.stDev = *devno;
+
+ QByteArrayView fsRootView = fields[FsRoot];
+ if (!checkField(fsRootView))
+ continue;
+
+ // If the filesystem root is "/" -- it's not a *sub*-volume/bind-mount,
+ // in that case we leave info.fsRoot empty
+ if (fsRootView != "/") {
+ info.fsRoot = parseMangledPath(fsRootView);
+ if (!checkField(info.fsRoot))
+ continue;
+ }
+
+ info.device = parseMangledPath(fields[MountSource]);
+ if (!checkField(info.device))
+ continue;
+
+ infos.push_back(std::move(info));
+ }
+ return infos;
+}
+
+QT_END_NAMESPACE
+
+#endif // QSTORAGEINFO_LINUX_P_H
diff --git a/src/corelib/io/qstorageinfo_mac.cpp b/src/corelib/io/qstorageinfo_mac.cpp
index 690e7212d1..c6c0f501da 100644
--- a/src/corelib/io/qstorageinfo_mac.cpp
+++ b/src/corelib/io/qstorageinfo_mac.cpp
@@ -43,9 +43,9 @@ void QStorageInfoPrivate::retrievePosixInfo()
QT_STATFSBUF statfs_buf;
int result = QT_STATFS(QFile::encodeName(rootPath).constData(), &statfs_buf);
if (result == 0) {
- device = QByteArray(statfs_buf.f_mntfromname);
+ device.assign(statfs_buf.f_mntfromname);
readOnly = (statfs_buf.f_flags & MNT_RDONLY) != 0;
- fileSystemType = QByteArray(statfs_buf.f_fstypename);
+ fileSystemType.assign(statfs_buf.f_fstypename);
blockSize = statfs_buf.f_bsize;
}
}
@@ -160,9 +160,4 @@ QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
return volumes;
}
-QStorageInfo QStorageInfoPrivate::root()
-{
- return QStorageInfo(QStringLiteral("/"));
-}
-
QT_END_NAMESPACE
diff --git a/src/corelib/io/qstorageinfo_p.h b/src/corelib/io/qstorageinfo_p.h
index af323b4ddc..3af4b81ca4 100644
--- a/src/corelib/io/qstorageinfo_p.h
+++ b/src/corelib/io/qstorageinfo_p.h
@@ -15,36 +15,77 @@
// We mean it.
//
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qsystemdetection.h>
+#include <QtCore/qtenvironmentvariables.h>
#include <QtCore/private/qglobal_p.h>
#include "qstorageinfo.h"
+#ifdef Q_OS_UNIX
+#include <sys/types.h> // dev_t
+#endif
+
QT_BEGIN_NAMESPACE
+inline Q_LOGGING_CATEGORY(lcStorageInfo, "qt.core.qstorageinfo", QtWarningMsg)
+
class QStorageInfoPrivate : public QSharedData
{
public:
- inline QStorageInfoPrivate() : QSharedData(),
- bytesTotal(-1), bytesFree(-1), bytesAvailable(-1), blockSize(-1),
- readOnly(false), ready(false), valid(false)
- {}
+ QStorageInfoPrivate() = default;
- void initRootPath();
void doStat();
static QList<QStorageInfo> mountedVolumes();
- static QStorageInfo root();
+
+ static QStorageInfo root()
+ {
+#ifdef Q_OS_WIN
+ return QStorageInfo(QDir::fromNativeSeparators(QFile::decodeName(qgetenv("SystemDrive"))));
+#else
+ return QStorageInfo(QStringLiteral("/"));
+#endif
+ };
protected:
#if defined(Q_OS_WIN)
+ void initRootPath();
void retrieveVolumeInfo();
void retrieveDiskFreeSpace();
bool queryStorageProperty();
void queryFileFsSectorSizeInformation();
#elif defined(Q_OS_DARWIN)
+ void initRootPath();
void retrievePosixInfo();
void retrieveUrlProperties(bool initRootPath = false);
void retrieveLabel();
+#elif defined(Q_OS_LINUX)
+ void retrieveVolumeInfo();
+
+public:
+ struct MountInfo {
+ QString mountPoint;
+ QByteArray fsType;
+ QByteArray device;
+ QByteArray fsRoot;
+ dev_t stDev = 0;
+ };
+
+ void setFromMountInfo(MountInfo &&info)
+ {
+ rootPath = std::move(info.mountPoint);
+ fileSystemType = std::move(info.fsType);
+ device = std::move(info.device);
+ subvolume = std::move(info.fsRoot);
+ }
+
+ QStorageInfoPrivate(MountInfo &&info)
+ {
+ setFromMountInfo(std::move(info));
+ }
+
#elif defined(Q_OS_UNIX)
+ void initRootPath();
void retrieveVolumeInfo();
#endif
@@ -55,16 +96,68 @@ public:
QByteArray fileSystemType;
QString name;
- qint64 bytesTotal;
- qint64 bytesFree;
- qint64 bytesAvailable;
- ulong blockSize;
+ qint64 bytesTotal = -1;
+ qint64 bytesFree = -1;
+ qint64 bytesAvailable = -1;
+ int blockSize = -1;
- bool readOnly;
- bool ready;
- bool valid;
+ bool readOnly = false;
+ bool ready = false;
+ bool valid = false;
};
+// Common helper functions
+template <typename String>
+static bool isParentOf(const String &parent, const QString &dirName)
+{
+ return dirName.startsWith(parent) &&
+ (dirName.size() == parent.size() || dirName.at(parent.size()) == u'/' ||
+ parent.size() == 1);
+}
+
+static inline bool shouldIncludeFs(const QString &mountDir, const QByteArray &fsType)
+{
+#if defined(Q_OS_ANDROID)
+ // "rootfs" is the filesystem type of "/" on Android
+ static constexpr char RootFsStr[] = "";
+#else
+ // "rootfs" is a type of ramfs on Linux, used in the initrd on some distros
+ static constexpr char RootFsStr[] = "rootfs";
+#endif
+
+ using namespace Qt::StringLiterals;
+ /*
+ * This function implements a heuristic algorithm to determine whether a
+ * given mount should be reported to the user. Our objective is to list
+ * only entries that the end-user would find useful.
+ *
+ * We therefore ignore:
+ * - mounted in /dev, /proc, /sys: special mounts
+ * (this will catch /sys/fs/cgroup, /proc/sys/fs/binfmt_misc, /dev/pts,
+ * some of which are tmpfs on Linux)
+ * - mounted in /var/run or /var/lock: most likely pseudofs
+ * (on earlier systemd versions, /var/run was a bind-mount of /run, so
+ * everything would be unnecessarily duplicated)
+ * - filesystem type is "rootfs": artifact of the root-pivot on some Linux
+ * initrd
+ * - if the filesystem total size is zero, it's a pseudo-fs (not checked here).
+ */
+
+ if (isParentOf("/dev"_L1, mountDir)
+ || isParentOf("/proc"_L1, mountDir)
+ || isParentOf("/sys"_L1, mountDir)
+ || isParentOf("/var/run"_L1, mountDir)
+ || isParentOf("/var/lock"_L1, mountDir)) {
+ return false;
+ }
+
+ if (!fsType.isEmpty() && fsType == RootFsStr)
+ return false;
+
+ // size checking in QStorageInfo::mountedVolumes()
+ return true;
+}
+
QT_END_NAMESPACE
#endif // QSTORAGEINFO_P_H
diff --git a/src/corelib/io/qstorageinfo_stub.cpp b/src/corelib/io/qstorageinfo_stub.cpp
new file mode 100644
index 0000000000..f2f7d2eb65
--- /dev/null
+++ b/src/corelib/io/qstorageinfo_stub.cpp
@@ -0,0 +1,25 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qstorageinfo_p.h"
+
+QT_BEGIN_NAMESPACE
+
+void QStorageInfoPrivate::initRootPath()
+{
+ Q_UNIMPLEMENTED();
+ rootPath = QString();
+}
+
+void QStorageInfoPrivate::doStat()
+{
+ Q_UNIMPLEMENTED();
+}
+
+QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
+{
+ Q_UNIMPLEMENTED();
+ return QList<QStorageInfo>();
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp
index c58b7ce87d..9df098a389 100644
--- a/src/corelib/io/qstorageinfo_unix.cpp
+++ b/src/corelib/io/qstorageinfo_unix.cpp
@@ -5,7 +5,6 @@
#include "qstorageinfo_p.h"
-#include <QtCore/qdiriterator.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qtextstream.h>
@@ -18,11 +17,7 @@
#if defined(Q_OS_BSD4)
# include <sys/mount.h>
# include <sys/statvfs.h>
-#elif defined(Q_OS_ANDROID)
-# include <sys/mount.h>
-# include <sys/vfs.h>
-# include <mntent.h>
-#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
+#elif defined(Q_OS_HURD)
# include <mntent.h>
# include <sys/statvfs.h>
# include <sys/sysmacros.h>
@@ -55,12 +50,6 @@
# if !defined(_STATFS_F_FLAGS) && !defined(Q_OS_NETBSD)
# define _STATFS_F_FLAGS 1
# endif
-#elif defined(Q_OS_ANDROID)
-# define QT_STATFS ::statfs
-# define QT_STATFSBUF struct statfs
-# if !defined(ST_RDONLY)
-# define ST_RDONLY 1 // hack for missing define on Android
-# endif
#elif defined(Q_OS_HAIKU)
# define QT_STATFSBUF struct statvfs
# define QT_STATFS ::statvfs
@@ -106,43 +95,10 @@ private:
#elif defined(Q_OS_SOLARIS)
FILE *fp;
mnttab mnt;
-#elif defined(Q_OS_ANDROID)
- QFile file;
- QByteArray m_rootPath;
- QByteArray m_fileSystemType;
- QByteArray m_device;
- QByteArray m_options;
-#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
- struct mountinfoent : public mntent {
- // Details from proc(5) section from /proc/<pid>/mountinfo:
- //(1) mount ID: a unique ID for the mount (may be reused after umount(2)).
- int mount_id;
- //(2) parent ID: the ID of the parent mount (or of self for the top of the mount tree).
-// int parent_id;
- //(3) major:minor: the value of st_dev for files on this filesystem (see stat(2)).
- dev_t rdev;
- //(4) root: the pathname of the directory in the filesystem which forms the root of this mount.
- char *subvolume;
- //(5) mount point: the pathname of the mount point relative to the process's root directory.
-// char *mnt_dir; // in mntent
- //(6) mount options: per-mount options.
-// char *mnt_opts; // in mntent
- //(7) optional fields: zero or more fields of the form "tag[:value]"; see below.
-// int flags;
- //(8) separator: the end of the optional fields is marked by a single hyphen.
-
- //(9) filesystem type: the filesystem type in the form "type[.subtype]".
-// char *mnt_type; // in mntent
- //(10) mount source: filesystem-specific information or "none".
-// char *mnt_fsname; // in mntent
- //(11) super options: per-superblock options.
- char *superopts;
- };
-
+#elif defined(Q_OS_HURD)
FILE *fp;
QByteArray buffer;
mountinfoent mnt;
- bool usingMountinfo;
#elif defined(Q_OS_HAIKU)
BVolumeRoster m_volumeRoster;
@@ -152,51 +108,6 @@ private:
#endif
};
-template <typename String>
-static bool isParentOf(const String &parent, const QString &dirName)
-{
- return dirName.startsWith(parent) &&
- (dirName.size() == parent.size() || dirName.at(parent.size()) == u'/' ||
- parent.size() == 1);
-}
-
-static bool shouldIncludeFs(const QStorageIterator &it)
-{
- /*
- * This function implements a heuristic algorithm to determine whether a
- * given mount should be reported to the user. Our objective is to list
- * only entries that the end-user would find useful.
- *
- * We therefore ignore:
- * - mounted in /dev, /proc, /sys: special mounts
- * (this will catch /sys/fs/cgroup, /proc/sys/fs/binfmt_misc, /dev/pts,
- * some of which are tmpfs on Linux)
- * - mounted in /var/run or /var/lock: most likely pseudofs
- * (on earlier systemd versions, /var/run was a bind-mount of /run, so
- * everything would be unnecessarily duplicated)
- * - filesystem type is "rootfs": artifact of the root-pivot on some Linux
- * initrd
- * - if the filesystem total size is zero, it's a pseudo-fs (not checked here).
- */
-
- QString mountDir = it.rootPath();
- if (isParentOf("/dev"_L1, mountDir)
- || isParentOf("/proc"_L1, mountDir)
- || isParentOf("/sys"_L1, mountDir)
- || isParentOf("/var/run"_L1, mountDir)
- || isParentOf("/var/lock"_L1, mountDir)) {
- return false;
- }
-
-#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
- if (it.fileSystemType() == "rootfs")
- return false;
-#endif
-
- // size checking in mountedVolumes()
- return true;
-}
-
#if defined(Q_OS_BSD4)
#ifndef MNT_NOWAIT
@@ -290,67 +201,8 @@ inline QByteArray QStorageIterator::subvolume() const
{
return QByteArray();
}
-#elif defined(Q_OS_ANDROID)
-inline QStorageIterator::QStorageIterator()
-{
- file.setFileName(QString::fromUtf8(_PATH_MOUNTED));
- file.open(QIODevice::ReadOnly | QIODevice::Text);
-}
-
-inline QStorageIterator::~QStorageIterator()
-{
-}
-
-inline bool QStorageIterator::isValid() const
-{
- return file.isOpen();
-}
-
-inline bool QStorageIterator::next()
-{
- QList<QByteArray> data;
- // If file is virtual, file.readLine() may succeed even when file.atEnd().
- do {
- const QByteArray line = file.readLine();
- if (line.isEmpty() && file.atEnd())
- return false;
- data = line.split(' ');
- } while (data.count() < 4);
-
- m_device = data.at(0);
- m_rootPath = data.at(1);
- m_fileSystemType = data.at(2);
- m_options = data.at(3);
-
- return true;
-}
-
-inline QString QStorageIterator::rootPath() const
-{
- return QFile::decodeName(m_rootPath);
-}
-
-inline QByteArray QStorageIterator::fileSystemType() const
-{
- return m_fileSystemType;
-}
-
-inline QByteArray QStorageIterator::device() const
-{
- return m_device;
-}
-
-inline QByteArray QStorageIterator::options() const
-{
- return m_options;
-}
-
-inline QByteArray QStorageIterator::subvolume() const
-{
- return QByteArray();
-}
-#elif defined(Q_OS_LINUX) || defined(Q_OS_HURD)
+#elif defined(Q_OS_HURD)
static const int bufferSize = 1024; // 2 paths (mount point+device) and metainfo;
// should be enough
@@ -358,28 +210,13 @@ static const int bufferSize = 1024; // 2 paths (mount point+device) and metainfo
inline QStorageIterator::QStorageIterator() :
buffer(QByteArray(bufferSize, 0))
{
- fp = nullptr;
-
-#ifdef Q_OS_LINUX
- // first, try to open /proc/self/mountinfo, which has more details
- fp = ::fopen("/proc/self/mountinfo", "re");
-#endif
- if (fp) {
- usingMountinfo = true;
- } else {
- usingMountinfo = false;
- fp = ::setmntent(_PATH_MOUNTED, "r");
- }
+ fp = ::setmntent(_PATH_MOUNTED, "r");
}
inline QStorageIterator::~QStorageIterator()
{
- if (fp) {
- if (usingMountinfo)
- ::fclose(fp);
- else
- ::endmntent(fp);
- }
+ if (fp)
+ ::endmntent(fp);
}
inline bool QStorageIterator::isValid() const
@@ -389,143 +226,7 @@ inline bool QStorageIterator::isValid() const
inline bool QStorageIterator::next()
{
- mnt.subvolume = nullptr;
- mnt.superopts = nullptr;
- if (!usingMountinfo)
- return ::getmntent_r(fp, &mnt, buffer.data(), buffer.size()) != nullptr;
-
- // Helper function to parse paths that the kernel inserts escape sequences
- // for. The unescaped string is left at \a src and is properly
- // NUL-terminated. Returns a pointer to the delimiter that terminated the
- // path, or nullptr if it failed.
- auto parseMangledPath = [](char *src) {
- // The kernel escapes with octal the following characters:
- // space ' ', tab '\t', backslask '\\', and newline '\n'
- char *dst = src;
- while (*src) {
- switch (*src) {
- case ' ':
- // Unescaped space: end of the field.
- *dst = '\0';
- return src;
-
- default:
- *dst++ = *src++;
- break;
-
- case '\\':
- // It always uses exactly three octal characters.
- ++src;
- char c = (*src++ - '0') << 6;
- c |= (*src++ - '0') << 3;
- c |= (*src++ - '0');
- *dst++ = c;
- break;
- }
- }
-
- // Found a NUL before the end of the field.
- src = nullptr;
- return src;
- };
-
- char *ptr = buffer.data();
- if (fgets(ptr, buffer.size(), fp) == nullptr)
- return false;
-
- size_t len = strlen(ptr);
- if (len == 0)
- return false;
- while (Q_UNLIKELY(ptr[len - 1] != '\n' && !feof(fp))) {
- // buffer wasn't large enough. Enlarge and try again.
- // (we're readidng from the kernel, so OOM is unlikely)
- buffer.resize((buffer.size() + 4096) & ~4095);
- ptr = buffer.data();
- if (fgets(ptr + len, buffer.size() - len, fp) == nullptr)
- return false;
-
- len += strlen(ptr + len);
- Q_ASSERT(len < size_t(buffer.size()));
- }
- ptr[len - 1] = '\0';
- const char *const stop = ptr + len - 1;
-
- // parse the line
- mnt.mnt_freq = 0;
- mnt.mnt_passno = 0;
-
- auto r = qstrntoll(ptr, stop - ptr, 10);
- if (!r.ok())
- return false;
- mnt.mount_id = r.result;
-
- ptr += r.used;
- r = qstrntoll(ptr, stop - ptr, 10);
- if (!r.ok())
- return false;
- // parent_id = r.result; // member currently not in use
-
- ptr += r.used;
- r = qstrntoll(ptr, stop - ptr, 10);
- if (!r.ok())
- return false;
- ptr += r.used;
- if (*ptr != ':')
- return false;
- int rdevmajor = r.result;
- ++ptr; // Skip over the ':'
- r = qstrntoll(ptr, stop - ptr, 10);
- if (!r.ok())
- return false;
- mnt.rdev = makedev(rdevmajor, r.result);
-
- ptr += r.used;
- if (*ptr != ' ')
- return false;
-
- mnt.subvolume = ++ptr;
- ptr = parseMangledPath(ptr);
- if (!ptr)
- return false;
-
- // unset a subvolume of "/" -- it's not a *sub* volume
- if (mnt.subvolume + 1 == ptr)
- *mnt.subvolume = '\0';
-
- mnt.mnt_dir = ++ptr;
- ptr = parseMangledPath(ptr);
- if (!ptr)
- return false;
-
- mnt.mnt_opts = ++ptr;
- ptr = strchr(ptr, ' ');
- if (!ptr)
- return false;
-
- // we don't parse the flags, so just find the separator
- if (char *const dashed = strstr(ptr, " - ")) {
- *ptr = '\0';
- ptr = dashed + strlen(" - ") - 1;
- } else {
- return false;
- }
-
- mnt.mnt_type = ++ptr;
- ptr = strchr(ptr, ' ');
- if (!ptr)
- return false;
- *ptr = '\0';
-
- mnt.mnt_fsname = ++ptr;
- ptr = parseMangledPath(ptr);
- if (!ptr)
- return false;
-
- mnt.superopts = ++ptr;
- ptr += strcspn(ptr, " \n");
- *ptr = '\0';
-
- return true;
+ return ::getmntent_r(fp, &mnt, buffer.data(), buffer.size()) != nullptr;
}
inline QString QStorageIterator::rootPath() const
@@ -540,49 +241,17 @@ inline QByteArray QStorageIterator::fileSystemType() const
inline QByteArray QStorageIterator::device() const
{
-#ifdef Q_OS_LINUX
- // check that the device exists
- if (mnt.mnt_fsname[0] == '/' && access(mnt.mnt_fsname, F_OK) != 0) {
- // It doesn't, so let's try to resolve the dev_t from /dev/block.
- // Note how strlen("4294967295") == digits10 + 1, so we need to add 1
- // for each number, plus the ':'.
- char buf[sizeof("/dev/block/") + 2 * std::numeric_limits<unsigned>::digits10 + 3];
- QByteArray dev(PATH_MAX, Qt::Uninitialized);
- char *devdata = dev.data();
-
- snprintf(buf, sizeof(buf), "/dev/block/%u:%u", major(mnt.rdev), minor(mnt.rdev));
- if (realpath(buf, devdata)) {
- dev.truncate(strlen(devdata));
- return dev;
- }
- }
-#endif
return QByteArray(mnt.mnt_fsname);
}
inline QByteArray QStorageIterator::options() const
{
- // Merge the two options, starting with the superblock options and letting
- // the per-mount options override.
- const char *superopts = mnt.superopts;
-
- // Both mnt_opts and superopts start with "ro" or "rw", so we can skip the
- // superblock's field (see show_mountinfo() in fs/proc_namespace.c).
- if (superopts && superopts[0] == 'r') {
- if (superopts[2] == '\0') // no other superopts besides "ro" / "rw"?
- superopts = nullptr;
- else if (superopts[2] == ',')
- superopts += 3;
- }
-
- if (superopts)
- return QByteArray(superopts) + ',' + mnt.mnt_opts;
return QByteArray(mnt.mnt_opts);
}
inline QByteArray QStorageIterator::subvolume() const
{
- return QByteArray(mnt.subvolume);
+ return QByteArray();
}
#elif defined(Q_OS_HAIKU)
inline QStorageIterator::QStorageIterator()
@@ -650,6 +319,7 @@ inline QByteArray QStorageIterator::subvolume() const
{
return QByteArray();
}
+
#else
inline QStorageIterator::QStorageIterator()
@@ -696,83 +366,9 @@ inline QByteArray QStorageIterator::subvolume() const
}
#endif
-void QStorageInfoPrivate::initRootPath()
-{
- rootPath = QFileInfo(rootPath).canonicalFilePath();
-
- if (rootPath.isEmpty())
- return;
-
- QStorageIterator it;
- if (!it.isValid()) {
- rootPath = QStringLiteral("/");
- return;
- }
-
- int maxLength = 0;
- const QString oldRootPath = rootPath;
- rootPath.clear();
-
- while (it.next()) {
- const QString mountDir = it.rootPath();
- const QByteArray fsName = it.fileSystemType();
- // we try to find most suitable entry
- if (isParentOf(mountDir, oldRootPath) && maxLength < mountDir.size()) {
- maxLength = mountDir.size();
- rootPath = mountDir;
- device = it.device();
- fileSystemType = fsName;
- subvolume = it.subvolume();
- }
- }
-}
-
-#ifdef Q_OS_LINUX
-// udev encodes the labels with ID_LABEL_FS_ENC which is done with
-// blkid_encode_string(). Within this function some 1-byte utf-8
-// characters not considered safe (e.g. '\' or ' ') are encoded as hex
-static QString decodeFsEncString(const QString &str)
-{
- QString decoded;
- decoded.reserve(str.size());
-
- int i = 0;
- while (i < str.size()) {
- if (i <= str.size() - 4) { // we need at least four characters \xAB
- if (QStringView{str}.sliced(i).startsWith("\\x"_L1)) {
- bool bOk;
- const int code = QStringView{str}.mid(i+2, 2).toInt(&bOk, 16);
- // only decode characters between 0x20 and 0x7f but not
- // the backslash to prevent collisions
- if (bOk && code >= 0x20 && code < 0x80 && code != '\\') {
- decoded += QChar(code);
- i += 4;
- continue;
- }
- }
- }
- decoded += str.at(i);
- ++i;
- }
- return decoded;
-}
-#endif
-
static inline QString retrieveLabel(const QByteArray &device)
{
-#ifdef Q_OS_LINUX
- static const char pathDiskByLabel[] = "/dev/disk/by-label";
-
- QFileInfo devinfo(QFile::decodeName(device));
- QString devicePath = devinfo.canonicalFilePath();
-
- QDirIterator it(QLatin1StringView(pathDiskByLabel), QDir::NoDotAndDotDot);
- while (it.hasNext()) {
- QFileInfo fileInfo = it.nextFileInfo();
- if (fileInfo.isSymLink() && fileInfo.symLinkTarget() == devicePath)
- return decodeFsEncString(fileInfo.fileName());
- }
-#elif defined Q_OS_HAIKU
+#if defined Q_OS_HAIKU
fs_info fsInfo;
memset(&fsInfo, 0, sizeof(fsInfo));
@@ -806,7 +402,7 @@ void QStorageInfoPrivate::retrieveVolumeInfo()
{
QT_STATFSBUF statfs_buf;
int result;
- EINTR_LOOP(result, QT_STATFS(QFile::encodeName(rootPath).constData(), &statfs_buf));
+ QT_EINTR_LOOP(result, QT_STATFS(QFile::encodeName(rootPath).constData(), &statfs_buf));
if (result == 0) {
valid = true;
ready = true;
@@ -820,7 +416,7 @@ void QStorageInfoPrivate::retrieveVolumeInfo()
bytesFree = statfs_buf.f_bfree * statfs_buf.f_frsize;
bytesAvailable = statfs_buf.f_bavail * statfs_buf.f_frsize;
#endif
- blockSize = statfs_buf.f_bsize;
+ blockSize = int(statfs_buf.f_bsize);
#if defined(Q_OS_ANDROID) || defined(Q_OS_BSD4) || defined(Q_OS_INTEGRITY) || defined(Q_OS_RTEMS)
#if defined(_STATFS_F_FLAGS)
readOnly = (statfs_buf.f_flags & ST_RDONLY) != 0;
@@ -831,6 +427,37 @@ void QStorageInfoPrivate::retrieveVolumeInfo()
}
}
+void QStorageInfoPrivate::initRootPath()
+{
+ rootPath = QFileInfo(rootPath).canonicalFilePath();
+
+ if (rootPath.isEmpty())
+ return;
+
+ QStorageIterator it;
+ if (!it.isValid()) {
+ rootPath = QStringLiteral("/");
+ return;
+ }
+
+ int maxLength = 0;
+ const QString oldRootPath = rootPath;
+ rootPath.clear();
+
+ while (it.next()) {
+ const QString mountDir = it.rootPath();
+ const QByteArray fsName = it.fileSystemType();
+ // we try to find most suitable entry
+ if (maxLength < mountDir.size() && isParentOf(mountDir, oldRootPath)) {
+ maxLength = mountDir.size();
+ rootPath = mountDir;
+ device = it.device();
+ fileSystemType = fsName;
+ subvolume = it.subvolume();
+ }
+ }
+}
+
QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
{
QStorageIterator it;
@@ -840,7 +467,7 @@ QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
QList<QStorageInfo> volumes;
while (it.next()) {
- if (!shouldIncludeFs(it))
+ if (!shouldIncludeFs(it.rootPath(), it.fileSystemType()))
continue;
const QString mountDir = it.rootPath();
@@ -848,7 +475,7 @@ QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
info.d->device = it.device();
info.d->fileSystemType = it.fileSystemType();
info.d->subvolume = it.subvolume();
- if (info.bytesTotal() == 0 && info != root())
+ if (info.bytesTotal() <= 0 && info != root())
continue;
volumes.append(info);
}
@@ -856,9 +483,4 @@ QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
return volumes;
}
-QStorageInfo QStorageInfoPrivate::root()
-{
- return QStorageInfo(QStringLiteral("/"));
-}
-
QT_END_NAMESPACE
diff --git a/src/corelib/io/qstorageinfo_win.cpp b/src/corelib/io/qstorageinfo_win.cpp
index 418a8b77f8..3ee1df9f3c 100644
--- a/src/corelib/io/qstorageinfo_win.cpp
+++ b/src/corelib/io/qstorageinfo_win.cpp
@@ -170,11 +170,6 @@ QList<QStorageInfo> QStorageInfoPrivate::mountedVolumes()
return volumes;
}
-QStorageInfo QStorageInfoPrivate::root()
-{
- return QStorageInfo(QDir::fromNativeSeparators(QFile::decodeName(qgetenv("SystemDrive"))));
-}
-
bool QStorageInfoPrivate::queryStorageProperty()
{
QString path = QDir::toNativeSeparators(uR"(\\.\)" + rootPath);
@@ -208,7 +203,7 @@ bool QStorageInfoPrivate::queryStorageProperty()
nullptr);
CloseHandle(handle);
if (result)
- blockSize = saad.BytesPerPhysicalSector;
+ blockSize = int(saad.BytesPerPhysicalSector);
return result;
}
diff --git a/src/corelib/io/qtemporarydir.cpp b/src/corelib/io/qtemporarydir.cpp
index 433ec57383..8187524067 100644
--- a/src/corelib/io/qtemporarydir.cpp
+++ b/src/corelib/io/qtemporarydir.cpp
@@ -4,11 +4,9 @@
#include "qtemporarydir.h"
-#ifndef QT_NO_TEMPORARYFILE
+#if QT_CONFIG(temporaryfile)
#include "qdebug.h"
-#include "qdiriterator.h"
-#include "qpair.h"
#include "qplatformdefs.h"
#include "qrandom.h"
#include "private/qtemporaryfile_p.h"
@@ -326,4 +324,4 @@ bool QTemporaryDir::remove()
QT_END_NAMESPACE
-#endif // QT_NO_TEMPORARYFILE
+#endif // QT_CONFIG(temporaryfile)
diff --git a/src/corelib/io/qtemporarydir.h b/src/corelib/io/qtemporarydir.h
index 1fdaa83fb0..8737bf9e26 100644
--- a/src/corelib/io/qtemporarydir.h
+++ b/src/corelib/io/qtemporarydir.h
@@ -11,7 +11,7 @@
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_TEMPORARYFILE
+#if QT_CONFIG(temporaryfile)
class QTemporaryDirPrivate;
@@ -52,7 +52,7 @@ inline void swap(QTemporaryDir &lhs, QTemporaryDir &rhs) noexcept
lhs.swap(rhs);
}
-#endif // QT_NO_TEMPORARYFILE
+#endif // QT_CONFIG(temporaryfile)
QT_END_NAMESPACE
diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp
index 07d8c0469d..4e48a18d91 100644
--- a/src/corelib/io/qtemporaryfile.cpp
+++ b/src/corelib/io/qtemporaryfile.cpp
@@ -45,8 +45,8 @@ QTemporaryFileName::QTemporaryFileName(const QString &templateName)
{
// Ensure there is a placeholder mask
QString qfilename = QDir::fromNativeSeparators(templateName);
- uint phPos = qfilename.size();
- uint phLength = 0;
+ qsizetype phPos = qfilename.size();
+ qsizetype phLength = 0;
while (phPos != 0) {
--phPos;
@@ -70,9 +70,8 @@ QTemporaryFileName::QTemporaryFileName(const QString &templateName)
qfilename.append(".XXXXXX"_L1);
// "Nativify" :-)
- QFileSystemEntry::NativePath filename = QFileSystemEngine::absoluteName(
- QFileSystemEntry(qfilename, QFileSystemEntry::FromInternalPath()))
- .nativeFilePath();
+ QFileSystemEntry::NativePath filename =
+ QFileSystemEntry(QDir::cleanPath(qfilename)).nativeFilePath();
// Find mask in native path
phPos = filename.size();
@@ -157,7 +156,7 @@ QFileSystemEntry::NativePath QTemporaryFileName::generateNext()
return path;
}
-#ifndef QT_NO_TEMPORARYFILE
+#if QT_CONFIG(temporaryfile)
/*!
\internal
@@ -185,8 +184,9 @@ static bool createFileFromTemplate(NativeFileHandle &file, QTemporaryFileName &t
const DWORD shareMode = (flags & QTemporaryFileEngine::Win32NonShared)
? 0u : (FILE_SHARE_READ | FILE_SHARE_WRITE);
+ const DWORD extraAccessFlags = (flags & QTemporaryFileEngine::Win32NonShared) ? DELETE : 0;
file = CreateFile((const wchar_t *)path.constData(),
- GENERIC_READ | GENERIC_WRITE,
+ GENERIC_READ | GENERIC_WRITE | extraAccessFlags,
shareMode, NULL, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL, NULL);
@@ -391,6 +391,18 @@ bool QTemporaryFileEngine::renameOverwrite(const QString &newName)
QFSFileEngine::close();
return ok;
}
+#ifdef Q_OS_WIN
+ if (flags & Win32NonShared) {
+ QFileSystemEntry newEntry(newName, QFileSystemEntry::FromInternalPath());
+ bool ok = d_func()->nativeRenameOverwrite(newEntry);
+ QFSFileEngine::close();
+ if (ok) {
+ // Match what QFSFileEngine::renameOverwrite() does
+ setFileEntry(std::move(newEntry));
+ }
+ return ok;
+ }
+#endif
QFSFileEngine::close();
return QFSFileEngine::renameOverwrite(newName);
}
@@ -631,6 +643,12 @@ QTemporaryFile::QTemporaryFile()
}
/*!
+ \fn QTemporaryFile::QTemporaryFile(const std::filesystem::path &templateName, QObject *parent)
+ \overload
+ \since 6.7
+*/
+
+/*!
Constructs a QTemporaryFile with a template filename of \a
templateName. Upon opening the temporary file this will be used to create
a unique filename.
@@ -713,7 +731,7 @@ QTemporaryFile::~QTemporaryFile()
return true upon success and will set the fileName() to the unique
filename used.
- \sa fileName()
+ \sa fileName(), QT_USE_NODISCARD_FILE_OPEN
*/
/*!
@@ -792,6 +810,12 @@ QString QTemporaryFile::fileTemplate() const
}
/*!
+ \fn void QTemporaryFile::setFileTemplate(const std::filesystem::path &name)
+ \overload
+ \since 6.7
+*/
+
+/*!
Sets the static portion of the file name to \a name. If the file
template contains XXXXXX that will automatically be replaced with
the unique part of the filename, otherwise a filename will be
@@ -813,6 +837,12 @@ void QTemporaryFile::setFileTemplate(const QString &name)
}
/*!
+ \fn bool QTemporaryFile::rename(const std::filesystem::path &newName)
+ \overload
+ \since 6.7
+*/
+
+/*!
Renames the current temporary file to \a newName and returns true if it
succeeded.
@@ -843,7 +873,6 @@ bool QTemporaryFile::rename(const QString &newName)
if (tef->rename(newName)) {
unsetError();
// engine was able to handle the new name so we just reset it
- tef->setFileName(newName);
d->fileName = newName;
return true;
}
@@ -860,7 +889,11 @@ bool QTemporaryFile::rename(const QString &newName)
Works on the given \a fileName rather than an existing QFile
object.
*/
-
+/*!
+ \fn QTemporaryFile *QTemporaryFile::createNativeFile(const std::filesystem::path &fileName)
+ \overload
+ \since 6.7
+*/
/*!
If \a file is not already a native file, then a QTemporaryFile is created
@@ -948,7 +981,7 @@ bool QTemporaryFile::open(OpenMode flags)
return false;
}
-#endif // QT_NO_TEMPORARYFILE
+#endif // QT_CONFIG(temporaryfile)
QT_END_NAMESPACE
diff --git a/src/corelib/io/qtemporaryfile.h b/src/corelib/io/qtemporaryfile.h
index e1058e566c..9a4476f9d2 100644
--- a/src/corelib/io/qtemporaryfile.h
+++ b/src/corelib/io/qtemporaryfile.h
@@ -14,7 +14,7 @@
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_TEMPORARYFILE
+#if QT_CONFIG(temporaryfile)
class QTemporaryFilePrivate;
class QLockFilePrivate;
@@ -32,26 +32,59 @@ public:
#ifndef QT_NO_QOBJECT
explicit QTemporaryFile(QObject *parent);
QTemporaryFile(const QString &templateName, QObject *parent);
-#endif
+
+# if QT_CONFIG(cxx17_filesystem) || defined(Q_QDOC)
+ Q_WEAK_OVERLOAD
+ explicit QTemporaryFile(const std::filesystem::path &templateName, QObject *parent = nullptr)
+ : QTemporaryFile(QtPrivate::fromFilesystemPath(templateName), parent)
+ {
+ }
+# endif // QT_CONFIG(cxx17_filesystem)
+#endif // !QT_NO_QOBJECT
+
~QTemporaryFile();
bool autoRemove() const;
void setAutoRemove(bool b);
// ### Hides open(flags)
- bool open() { return open(QIODevice::ReadWrite); }
+ QFILE_MAYBE_NODISCARD bool open() { return open(QIODevice::ReadWrite); }
QString fileName() const override;
QString fileTemplate() const;
void setFileTemplate(const QString &name);
+#if QT_CONFIG(cxx17_filesystem) || defined(Q_QDOC)
+ Q_WEAK_OVERLOAD
+ void setFileTemplate(const std::filesystem::path &name)
+ {
+ return setFileTemplate(QtPrivate::fromFilesystemPath(name));
+ }
+#endif // QT_CONFIG(cxx17_filesystem)
// Hides QFile::rename
bool rename(const QString &newName);
+#if QT_CONFIG(cxx17_filesystem) || defined(Q_QDOC)
+ Q_WEAK_OVERLOAD
+ bool rename(const std::filesystem::path &newName)
+ {
+ return rename(QtPrivate::fromFilesystemPath(newName));
+ }
+#endif // QT_CONFIG(cxx17_filesystem)
+
inline static QTemporaryFile *createNativeFile(const QString &fileName)
{ QFile file(fileName); return createNativeFile(file); }
static QTemporaryFile *createNativeFile(QFile &file);
+#if QT_CONFIG(cxx17_filesystem) || defined(Q_QDOC)
+ Q_WEAK_OVERLOAD
+ static QTemporaryFile *createNativeFile(const std::filesystem::path &fileName)
+ {
+ QFile file(fileName);
+ return createNativeFile(file);
+ }
+#endif // QT_CONFIG(cxx17_filesystem)
+
protected:
bool open(OpenMode flags) override;
@@ -61,7 +94,7 @@ private:
Q_DISABLE_COPY(QTemporaryFile)
};
-#endif // QT_NO_TEMPORARYFILE
+#endif // QT_CONFIG(temporaryfile)
QT_END_NAMESPACE
diff --git a/src/corelib/io/qtemporaryfile_p.h b/src/corelib/io/qtemporaryfile_p.h
index 3a2ed73cf9..d160afe41e 100644
--- a/src/corelib/io/qtemporaryfile_p.h
+++ b/src/corelib/io/qtemporaryfile_p.h
@@ -45,7 +45,7 @@ struct QTemporaryFileName
QFileSystemEntry::NativePath generateNext();
};
-#ifndef QT_NO_TEMPORARYFILE
+#if QT_CONFIG(temporaryfile)
class QTemporaryFilePrivate : public QFilePrivate
{
@@ -88,8 +88,7 @@ public:
if (filePathIsTemplate) {
d->fileEntry.clear();
} else {
- d->fileEntry = QFileSystemEntry(file);
- QFSFileEngine::setFileName(file);
+ QFSFileEngine::setFileEntry(QFileSystemEntry(file));
}
}
~QTemporaryFileEngine();
@@ -116,7 +115,7 @@ public:
bool unnamedFile = false;
};
-#endif // QT_NO_TEMPORARYFILE
+#endif // QT_CONFIG(temporaryfile)
QT_END_NAMESPACE
diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp
index b6f4d00c15..4360b5b076 100644
--- a/src/corelib/io/qurl.cpp
+++ b/src/corelib/io/qurl.cpp
@@ -14,6 +14,8 @@
\ingroup network
\ingroup shared
+ \compares weak
+
It can parse and construct URLs in both encoded and unencoded
form. QUrl also has support for internationalized domain names
(IDNs).
@@ -2968,19 +2970,23 @@ QByteArray QUrl::toEncoded(FormattingOptions options) const
}
/*!
- \fn QUrl QUrl::fromEncoded(const QByteArray &input, ParsingMode parsingMode)
-
Parses \a input and returns the corresponding QUrl. \a input is
assumed to be in encoded form, containing only ASCII characters.
- Parses the URL using \a parsingMode. See setUrl() for more information on
+ Parses the URL using \a mode. See setUrl() for more information on
this parameter. QUrl::DecodedMode is not permitted in this context.
+ \note In Qt versions prior to 6.7, this function took a QByteArray, not
+ QByteArrayView. If you experience compile errors, it's because your code
+ is passing objects that are implicitly convertible to QByteArray, but not
+ QByteArrayView. Wrap the corresponding argument in \c{QByteArray{~~~}} to
+ make the cast explicit. This is backwards-compatible with old Qt versions.
+
\sa toEncoded(), setUrl()
*/
-QUrl QUrl::fromEncoded(const QByteArray &input, ParsingMode mode)
+QUrl QUrl::fromEncoded(QByteArrayView input, ParsingMode mode)
{
- return QUrl(QString::fromUtf8(input.constData(), input.size()), mode);
+ return QUrl(QString::fromUtf8(input), mode);
}
/*!
@@ -3063,88 +3069,101 @@ QByteArray QUrl::toAce(const QString &domain, AceProcessingOptions options)
/*!
\internal
- Returns \c true if this URL is "less than" the given \a url. This
+ \fn bool QUrl::operator<(const QUrl &lhs, const QUrl &rhs)
+
+ Returns \c true if URL \a lhs is "less than" URL \a rhs. This
provides a means of ordering URLs.
*/
-bool QUrl::operator <(const QUrl &url) const
+
+Qt::weak_ordering compareThreeWay(const QUrl &lhs, const QUrl &rhs)
{
- if (!d || !url.d) {
- bool thisIsEmpty = !d || d->isEmpty();
- bool thatIsEmpty = !url.d || url.d->isEmpty();
+ if (!lhs.d || !rhs.d) {
+ bool thisIsEmpty = !lhs.d || lhs.d->isEmpty();
+ bool thatIsEmpty = !rhs.d || rhs.d->isEmpty();
// sort an empty URL first
- return thisIsEmpty && !thatIsEmpty;
+ if (thisIsEmpty) {
+ if (!thatIsEmpty)
+ return Qt::weak_ordering::less;
+ else
+ return Qt::weak_ordering::equivalent;
+ } else {
+ return Qt::weak_ordering::greater;
+ }
}
int cmp;
- cmp = d->scheme.compare(url.d->scheme);
+ cmp = lhs.d->scheme.compare(rhs.d->scheme);
if (cmp != 0)
- return cmp < 0;
+ return Qt::compareThreeWay(cmp, 0);
- cmp = d->userName.compare(url.d->userName);
+ cmp = lhs.d->userName.compare(rhs.d->userName);
if (cmp != 0)
- return cmp < 0;
+ return Qt::compareThreeWay(cmp, 0);
- cmp = d->password.compare(url.d->password);
+ cmp = lhs.d->password.compare(rhs.d->password);
if (cmp != 0)
- return cmp < 0;
+ return Qt::compareThreeWay(cmp, 0);
- cmp = d->host.compare(url.d->host);
+ cmp = lhs.d->host.compare(rhs.d->host);
if (cmp != 0)
- return cmp < 0;
+ return Qt::compareThreeWay(cmp, 0);
- if (d->port != url.d->port)
- return d->port < url.d->port;
+ if (lhs.d->port != rhs.d->port)
+ return Qt::compareThreeWay(lhs.d->port, rhs.d->port);
- cmp = d->path.compare(url.d->path);
+ cmp = lhs.d->path.compare(rhs.d->path);
if (cmp != 0)
- return cmp < 0;
+ return Qt::compareThreeWay(cmp, 0);
- if (d->hasQuery() != url.d->hasQuery())
- return url.d->hasQuery();
+ if (lhs.d->hasQuery() != rhs.d->hasQuery())
+ return rhs.d->hasQuery() ? Qt::weak_ordering::less : Qt::weak_ordering::greater;
- cmp = d->query.compare(url.d->query);
+ cmp = lhs.d->query.compare(rhs.d->query);
if (cmp != 0)
- return cmp < 0;
+ return Qt::compareThreeWay(cmp, 0);
- if (d->hasFragment() != url.d->hasFragment())
- return url.d->hasFragment();
+ if (lhs.d->hasFragment() != rhs.d->hasFragment())
+ return rhs.d->hasFragment() ? Qt::weak_ordering::less : Qt::weak_ordering::greater;
- cmp = d->fragment.compare(url.d->fragment);
- return cmp < 0;
+ cmp = lhs.d->fragment.compare(rhs.d->fragment);
+ return Qt::compareThreeWay(cmp, 0);
}
/*!
- Returns \c true if this URL and the given \a url are equal;
+ \fn bool QUrl::operator==(const QUrl &lhs, const QUrl &rhs)
+
+ Returns \c true if \a lhs and \a rhs URLs are equivalent;
otherwise returns \c false.
\sa matches()
*/
-bool QUrl::operator ==(const QUrl &url) const
+
+bool comparesEqual(const QUrl &lhs, const QUrl &rhs)
{
- if (!d && !url.d)
+ if (!lhs.d && !rhs.d)
return true;
- if (!d)
- return url.d->isEmpty();
- if (!url.d)
- return d->isEmpty();
+ if (!lhs.d)
+ return rhs.d->isEmpty();
+ if (!rhs.d)
+ return lhs.d->isEmpty();
// First, compare which sections are present, since it speeds up the
// processing considerably. We just have to ignore the host-is-present flag
// for local files (the "file" protocol), due to the requirements of the
// XDG file URI specification.
int mask = QUrlPrivate::FullUrl;
- if (isLocalFile())
+ if (lhs.isLocalFile())
mask &= ~QUrlPrivate::Host;
- return (d->sectionIsPresent & mask) == (url.d->sectionIsPresent & mask) &&
- d->scheme == url.d->scheme &&
- d->userName == url.d->userName &&
- d->password == url.d->password &&
- d->host == url.d->host &&
- d->port == url.d->port &&
- d->path == url.d->path &&
- d->query == url.d->query &&
- d->fragment == url.d->fragment;
+ return (lhs.d->sectionIsPresent & mask) == (rhs.d->sectionIsPresent & mask) &&
+ lhs.d->scheme == rhs.d->scheme &&
+ lhs.d->userName == rhs.d->userName &&
+ lhs.d->password == rhs.d->password &&
+ lhs.d->host == rhs.d->host &&
+ lhs.d->port == rhs.d->port &&
+ lhs.d->path == rhs.d->path &&
+ lhs.d->query == rhs.d->query &&
+ lhs.d->fragment == rhs.d->fragment;
}
/*!
@@ -3224,15 +3243,13 @@ bool QUrl::matches(const QUrl &url, FormattingOptions options) const
}
/*!
- Returns \c true if this URL and the given \a url are not equal;
+ \fn bool QUrl::operator !=(const QUrl &lhs, const QUrl &rhs)
+
+ Returns \c true if \a lhs and \a rhs URLs are not equal;
otherwise returns \c false.
\sa matches()
*/
-bool QUrl::operator !=(const QUrl &url) const
-{
- return !(*this == url);
-}
/*!
Assigns the specified \a url to this object.
diff --git a/src/corelib/io/qurl.h b/src/corelib/io/qurl.h
index 7922149bd8..d6779cf485 100644
--- a/src/corelib/io/qurl.h
+++ b/src/corelib/io/qurl.h
@@ -6,10 +6,10 @@
#define QURL_H
#include <QtCore/qbytearray.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qobjectdefs.h>
#include <QtCore/qstring.h>
#include <QtCore/qlist.h>
-#include <QtCore/qpair.h>
#include <QtCore/qglobal.h>
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
@@ -165,7 +165,10 @@ public:
[[nodiscard]] QUrl adjusted(FormattingOptions options) const;
QByteArray toEncoded(FormattingOptions options = FullyEncoded) const;
+#if QT_CORE_REMOVED_SINCE(6, 7)
static QUrl fromEncoded(const QByteArray &url, ParsingMode mode = TolerantMode);
+#endif
+ static QUrl fromEncoded(QByteArrayView input, ParsingMode mode = TolerantMode);
enum UserInputResolutionOption {
DefaultResolution,
@@ -228,9 +231,11 @@ public:
void detach();
bool isDetached() const;
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator <(const QUrl &url) const;
bool operator ==(const QUrl &url) const;
bool operator !=(const QUrl &url) const;
+#endif
bool matches(const QUrl &url, FormattingOptions options) const;
@@ -266,6 +271,11 @@ public:
friend Q_CORE_EXPORT size_t qHash(const QUrl &url, size_t seed) noexcept;
private:
+ friend Q_CORE_EXPORT bool comparesEqual(const QUrl &lhs, const QUrl &rhs);
+ friend Q_CORE_EXPORT Qt::weak_ordering
+ compareThreeWay(const QUrl &lhs, const QUrl &rhs);
+ Q_DECLARE_WEAKLY_ORDERED(QUrl)
+
QUrlPrivate *d;
friend class QUrlQuery;
diff --git a/src/corelib/io/qurl_p.h b/src/corelib/io/qurl_p.h
index 43dcdf82fb..9562d1993d 100644
--- a/src/corelib/io/qurl_p.h
+++ b/src/corelib/io/qurl_p.h
@@ -29,8 +29,8 @@ extern Q_AUTOTEST_EXPORT qsizetype qt_urlRecode(QString &appendTo, QStringView u
// in qurlidna.cpp
enum AceLeadingDot { AllowLeadingDot, ForbidLeadingDot };
enum AceOperation { ToAceOnly, NormalizeAce };
-extern QString qt_ACE_do(const QString &domain, AceOperation op, AceLeadingDot dot,
- QUrl::AceProcessingOptions options);
+QString Q_CORE_EXPORT qt_ACE_do(const QString &domain, AceOperation op, AceLeadingDot dot,
+ QUrl::AceProcessingOptions options = {});
extern Q_AUTOTEST_EXPORT void qt_punycodeEncoder(QStringView in, QString *output);
extern Q_AUTOTEST_EXPORT QString qt_punycodeDecoder(const QString &pc);
diff --git a/src/corelib/io/qurlidna.cpp b/src/corelib/io/qurlidna.cpp
index da592eb81b..a2a81c7605 100644
--- a/src/corelib/io/qurlidna.cpp
+++ b/src/corelib/io/qurlidna.cpp
@@ -132,7 +132,7 @@ Q_AUTOTEST_EXPORT void qt_punycodeEncoder(QStringView in, QString *output)
// delta = delta + (m - n) * (h + 1), fail on overflow
uint tmp;
- if (mul_overflow<uint>(m - n, h + 1, &tmp) || add_overflow<uint>(delta, tmp, &delta)) {
+ if (qMulOverflow<uint>(m - n, h + 1, &tmp) || qAddOverflow<uint>(delta, tmp, &delta)) {
output->truncate(outLen);
return; // punycode_overflow
}
@@ -144,7 +144,7 @@ Q_AUTOTEST_EXPORT void qt_punycodeEncoder(QStringView in, QString *output)
// increase delta until we reach the character processed in this iteration;
// fail if delta overflows.
if (c < n) {
- if (add_overflow<uint>(delta, 1, &delta)) {
+ if (qAddOverflow<uint>(delta, 1, &delta)) {
output->truncate(outLen);
return; // punycode_overflow
}
@@ -219,7 +219,7 @@ Q_AUTOTEST_EXPORT QString qt_punycodeDecoder(const QString &pc)
// i = i + digit * w, fail on overflow
uint tmp;
- if (mul_overflow<uint>(digit, w, &tmp) || add_overflow<uint>(i, tmp, &i))
+ if (qMulOverflow<uint>(digit, w, &tmp) || qAddOverflow<uint>(i, tmp, &i))
return QString();
// detect threshold to stop reading delta digits
@@ -231,7 +231,7 @@ Q_AUTOTEST_EXPORT QString qt_punycodeDecoder(const QString &pc)
if (digit < t) break;
// w = w * (base - t), fail on overflow
- if (mul_overflow<uint>(w, base - t, &w))
+ if (qMulOverflow<uint>(w, base - t, &w))
return QString();
}
@@ -241,7 +241,7 @@ Q_AUTOTEST_EXPORT QString qt_punycodeDecoder(const QString &pc)
bias = adapt(i - oldi, outputLength + 1, oldi == 0);
// n = n + i div (length(output) + 1), fail on overflow
- if (add_overflow<uint>(n, i / (outputLength + 1), &n))
+ if (qAddOverflow<uint>(n, i / (outputLength + 1), &n))
return QString();
// allow the deltas to wrap around
@@ -423,13 +423,19 @@ static QString mapDomainName(const QString &in, QUrl::AceProcessingOptions optio
if (uc >= U'A' && uc <= U'Z')
uc |= 0x20; // lower-case it
- if (!isValidInNormalizedAsciiName(uc))
- return {};
+ if (isValidInNormalizedAsciiName(uc)) {
+ result.append(static_cast<char16_t>(uc));
+ continue;
+ }
+ }
+
+ allAscii = false;
- result.append(static_cast<char16_t>(uc));
+ // Capital sharp S is a special case since UTR #46 revision 31 (Unicode 15.1)
+ if (uc == 0x1E9E && options.testFlag(QUrl::AceTransitionalProcessing)) {
+ result.append(u"ss"_s);
continue;
}
- allAscii = false;
QUnicodeTables::IdnaStatus status = QUnicodeTables::idnaStatus(uc);
@@ -442,14 +448,13 @@ static QString mapDomainName(const QString &in, QUrl::AceProcessingOptions optio
case QUnicodeTables::IdnaStatus::Ignored:
continue;
case QUnicodeTables::IdnaStatus::Valid:
+ case QUnicodeTables::IdnaStatus::Disallowed:
for (auto c : QChar::fromUcs4(uc))
result.append(c);
break;
case QUnicodeTables::IdnaStatus::Mapped:
result.append(QUnicodeTables::idnaMapping(uc));
break;
- case QUnicodeTables::IdnaStatus::Disallowed:
- return {};
default:
Q_UNREACHABLE();
}
@@ -483,12 +488,13 @@ class DomainValidityChecker
{
bool domainNameIsBidi = false;
bool hadBidiErrors = false;
+ bool ignoreBidiErrors;
static constexpr char32_t ZWNJ = U'\u200C';
static constexpr char32_t ZWJ = U'\u200D';
public:
- DomainValidityChecker() { }
+ DomainValidityChecker(bool ignoreBidiErrors = false) : ignoreBidiErrors(ignoreBidiErrors) { }
bool checkLabel(const QString &label, QUrl::AceProcessingOptions options);
private:
@@ -714,7 +720,7 @@ bool DomainValidityChecker::checkLabel(const QString &label, QUrl::AceProcessing
// because non-BMP characters are unlikely to be used for specifying
// future extensions.
if (label[2] == u'-' && label[3] == u'-')
- return false;
+ return ignoreBidiErrors && label.startsWith(u"xn") && validateAsciiLabel(label);
}
if (label.startsWith(u'-') || label.endsWith(u'-'))
@@ -736,7 +742,7 @@ bool DomainValidityChecker::checkLabel(const QString &label, QUrl::AceProcessing
for (;;) {
hasJoiners = hasJoiners || c == ZWNJ || c == ZWJ;
- if (!domainNameIsBidi) {
+ if (!ignoreBidiErrors && !domainNameIsBidi) {
switch (QChar::direction(c)) {
case QChar::DirR:
case QChar::DirAL:
@@ -777,25 +783,20 @@ bool DomainValidityChecker::checkLabel(const QString &label, QUrl::AceProcessing
return true;
}
-static QString convertToAscii(const QString &normalizedDomain, AceLeadingDot dot)
+static QString convertToAscii(QStringView normalizedDomain, AceLeadingDot dot)
{
qsizetype lastIdx = 0;
QString aceForm; // this variable is here for caching
QString aceResult;
while (true) {
- auto idx = normalizedDomain.indexOf(u'.', lastIdx);
+ qsizetype idx = normalizedDomain.indexOf(u'.', lastIdx);
if (idx == -1)
idx = normalizedDomain.size();
- const auto labelLength = idx - lastIdx;
- if (labelLength == 0) {
- if (idx == normalizedDomain.size())
- break;
- if (dot == ForbidLeadingDot || idx > 0)
- return {}; // two delimiters in a row -- empty label not allowed
- } else {
- const auto label = QStringView(normalizedDomain).sliced(lastIdx, labelLength);
+ const qsizetype labelLength = idx - lastIdx;
+ if (labelLength) {
+ const auto label = normalizedDomain.sliced(lastIdx, labelLength);
aceForm.clear();
qt_punycodeEncoder(label, &aceForm);
if (aceForm.isEmpty())
@@ -807,6 +808,9 @@ static QString convertToAscii(const QString &normalizedDomain, AceLeadingDot dot
if (idx == normalizedDomain.size())
break;
+ if (labelLength == 0 && (dot == ForbidLeadingDot || idx > 0))
+ return {}; // two delimiters in a row -- empty label not allowed
+
lastIdx = idx + 1;
aceResult += u'.';
}
@@ -814,7 +818,7 @@ static QString convertToAscii(const QString &normalizedDomain, AceLeadingDot dot
return aceResult;
}
-static bool checkAsciiDomainName(const QString &normalizedDomain, AceLeadingDot dot,
+static bool checkAsciiDomainName(QStringView normalizedDomain, AceLeadingDot dot,
bool *usesPunycode)
{
qsizetype lastIdx = 0;
@@ -833,7 +837,7 @@ static bool checkAsciiDomainName(const QString &normalizedDomain, AceLeadingDot
if (dot == ForbidLeadingDot || idx > 0)
return false; // two delimiters in a row -- empty label not allowed
} else {
- const auto label = QStringView(normalizedDomain).sliced(lastIdx, labelLength);
+ const auto label = normalizedDomain.sliced(lastIdx, labelLength);
if (!validateAsciiLabel(label))
return false;
@@ -886,6 +890,33 @@ static QString convertToUnicode(const QString &asciiDomain, QUrl::AceProcessingO
return result;
}
+static bool checkUnicodeName(const QString &domainName, QUrl::AceProcessingOptions options)
+{
+ qsizetype lastIdx = 0;
+
+ DomainValidityChecker checker(true);
+
+ while (true) {
+ qsizetype idx = domainName.indexOf(u'.', lastIdx);
+ if (idx == -1)
+ idx = domainName.size();
+
+ const qsizetype labelLength = idx - lastIdx;
+ if (labelLength) {
+ const auto label = domainName.sliced(lastIdx, labelLength);
+
+ if (!checker.checkLabel(label, options))
+ return false;
+ }
+
+ if (idx == domainName.size())
+ break;
+
+ lastIdx = idx + 1;
+ }
+ return true;
+}
+
QString qt_ACE_do(const QString &domain, AceOperation op, AceLeadingDot dot,
QUrl::AceProcessingOptions options)
{
@@ -900,12 +931,15 @@ QString qt_ACE_do(const QString &domain, AceOperation op, AceLeadingDot dot,
if (normalized.isEmpty())
return {};
- bool needsCoversionToUnicode;
+ if (!mappedToAscii && !checkUnicodeName(normalized, options))
+ return {};
+
+ bool needsConversionToUnicode;
const QString aceResult = mappedToAscii ? normalized : convertToAscii(normalized, dot);
- if (aceResult.isEmpty() || !checkAsciiDomainName(aceResult, dot, &needsCoversionToUnicode))
+ if (aceResult.isEmpty() || !checkAsciiDomainName(aceResult, dot, &needsConversionToUnicode))
return {};
- if (op == ToAceOnly || !needsCoversionToUnicode
+ if (op == ToAceOnly || !needsConversionToUnicode
|| (!options.testFlag(QUrl::IgnoreIDNWhitelist) && !qt_is_idn_enabled(aceResult))) {
return aceResult;
}
diff --git a/src/corelib/io/qurlquery.cpp b/src/corelib/io/qurlquery.cpp
index c707e8a2e6..31f3ee1d90 100644
--- a/src/corelib/io/qurlquery.cpp
+++ b/src/corelib/io/qurlquery.cpp
@@ -24,6 +24,8 @@ QT_BEGIN_NAMESPACE
\ingroup network
\ingroup shared
+ \compares equality
+
It is used to parse the query strings found in URLs like the following:
\image qurl-querystring.png
@@ -123,14 +125,14 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn QUrlQuery::QUrlQuery(std::initializer_list<QPair<QString, QString>> list)
+ \fn QUrlQuery::QUrlQuery(std::initializer_list<std::pair<QString, QString>> list)
\since 5.13
Constructs a QUrlQuery object from the \a list of key/value pair.
*/
-typedef QList<QPair<QString, QString> > Map;
+typedef QList<std::pair<QString, QString> > Map;
class QUrlQueryPrivate : public QSharedData
{
@@ -146,7 +148,7 @@ public:
void setQuery(const QString &query);
void addQueryItem(const QString &key, const QString &value)
- { itemList.append(qMakePair(recodeFromUser(key), recodeFromUser(value))); }
+ { itemList.append(std::make_pair(recodeFromUser(key), recodeFromUser(value))); }
int findRecodedKey(const QString &key, int from = 0) const
{
for (int i = from; i < itemList.size(); ++i)
@@ -290,17 +292,17 @@ void QUrlQueryPrivate::setQuery(const QString &query)
if (delimiter == pos) {
// the value delimiter wasn't found, store a null value
- itemList.append(qMakePair(key, QString()));
+ itemList.append(std::make_pair(key, QString()));
} else if (delimiter + 1 == pos) {
// if the delimiter was found but the value is empty, store empty-but-not-null
- itemList.append(qMakePair(key, QString(0, Qt::Uninitialized)));
+ itemList.append(std::make_pair(key, QString(0, Qt::Uninitialized)));
} else {
QString value;
if (!qt_urlRecode(value, QStringView{delimiter + 1, pos},
QUrl::DecodeReserved,
prettyDecodedActions))
value = QString(delimiter + 1, pos - delimiter - 1);
- itemList.append(qMakePair(key, value));
+ itemList.append(std::make_pair(key, value));
}
if (pos != end)
@@ -399,22 +401,25 @@ QUrlQuery::~QUrlQuery()
}
/*!
- Returns \c true if this object and the \a other object contain the same
+ \fn bool QUrlQuery::operator==(const QUrlQuery &lhs, const QUrlQuery &rhs)
+
+ Returns \c true if QUrlQuery objects \a lhs and \a rhs contain the same
contents, in the same order, and use the same query delimiters.
*/
-bool QUrlQuery::operator ==(const QUrlQuery &other) const
+
+bool comparesEqual(const QUrlQuery &lhs, const QUrlQuery &rhs)
{
- if (d == other.d)
+ if (lhs.d == rhs.d)
return true;
- if (d && other.d)
+ if (lhs.d && rhs.d)
// keep in sync with qHash(QUrlQuery):
- return d->valueDelimiter == other.d->valueDelimiter &&
- d->pairDelimiter == other.d->pairDelimiter &&
- d->itemList == other.d->itemList;
+ return lhs.d->valueDelimiter == rhs.d->valueDelimiter &&
+ lhs.d->pairDelimiter == rhs.d->pairDelimiter &&
+ lhs.d->itemList == rhs.d->itemList;
- const QUrlQueryPrivate *x = d ? d.data() : other.d.data();
- return x->valueDelimiter == defaultQueryValueDelimiter() &&
- x->pairDelimiter == defaultQueryPairDelimiter() &&
+ const QUrlQueryPrivate *x = lhs.d ? lhs.d.data() : rhs.d.data();
+ return x->valueDelimiter == QUrlQuery::defaultQueryValueDelimiter() &&
+ x->pairDelimiter == QUrlQuery::defaultQueryPairDelimiter() &&
x->itemList.isEmpty();
}
@@ -558,7 +563,7 @@ QString QUrlQuery::query(QUrl::ComponentFormattingOptions encoding) const
representation of the keys and values of the query string are
percent encoded when returned in query().
- If \a valueDelimiter is set to '(' and \a pairDelimiter is ')',
+ If \a valueDelimiter is set to ',' and \a pairDelimiter is ';',
the above query string would instead be represented like this:
\snippet code/src_corelib_io_qurl.cpp 4
@@ -569,7 +574,7 @@ QString QUrlQuery::query(QUrl::ComponentFormattingOptions encoding) const
\snippet code/src_corelib_io_qurlquery.cpp 0
Use of other characters is not supported and may result in unexpected
- behaviour. This method does not verify that you passed a valid delimiter.
+ behavior. This method does not verify that you passed a valid delimiter.
\sa queryValueDelimiter(), queryPairDelimiter()
*/
@@ -613,14 +618,14 @@ QChar QUrlQuery::queryPairDelimiter() const
\sa queryItems(), isEmpty()
*/
-void QUrlQuery::setQueryItems(const QList<QPair<QString, QString> > &query)
+void QUrlQuery::setQueryItems(const QList<std::pair<QString, QString> > &query)
{
clear();
if (query.isEmpty())
return;
QUrlQueryPrivate *dd = d;
- QList<QPair<QString, QString> >::const_iterator it = query.constBegin(),
+ QList<std::pair<QString, QString> >::const_iterator it = query.constBegin(),
end = query.constEnd();
for ( ; it != end; ++it)
dd->addQueryItem(it->first, it->second);
@@ -634,20 +639,20 @@ void QUrlQuery::setQueryItems(const QList<QPair<QString, QString> > &query)
\sa setQueryItems(), {encoding}{Encoding}
*/
-QList<QPair<QString, QString> > QUrlQuery::queryItems(QUrl::ComponentFormattingOptions encoding) const
+QList<std::pair<QString, QString> > QUrlQuery::queryItems(QUrl::ComponentFormattingOptions encoding) const
{
if (!d)
- return QList<QPair<QString, QString> >();
+ return QList<std::pair<QString, QString> >();
if (idempotentRecodeToUser(encoding))
return d->itemList;
- QList<QPair<QString, QString> > result;
+ QList<std::pair<QString, QString> > result;
Map::const_iterator it = d->itemList.constBegin();
Map::const_iterator end = d->itemList.constEnd();
result.reserve(d->itemList.size());
for ( ; it != end; ++it)
- result << qMakePair(d->recodeToUser(it->first, encoding),
- d->recodeToUser(it->second, encoding));
+ result << std::make_pair(d->recodeToUser(it->first, encoding),
+ d->recodeToUser(it->second, encoding));
return result;
}
@@ -766,7 +771,7 @@ void QUrlQuery::removeAllQueryItems(const QString &key)
if (d.constData()) {
auto *p = d.data();
const QString encodedKey = p->recodeFromUser(key);
- auto firstEqualsEncodedKey = [&encodedKey](const QPair<QString, QString> &item) {
+ auto firstEqualsEncodedKey = [&encodedKey](const std::pair<QString, QString> &item) {
return item.first == encodedKey;
};
p->itemList.removeIf(firstEqualsEncodedKey);
@@ -810,9 +815,10 @@ void QUrlQuery::removeAllQueryItems(const QString &key)
*/
/*!
- \fn bool QUrlQuery::operator!=(const QUrlQuery &other) const
+ \fn bool QUrlQuery::operator!=(const QUrlQuery &lhs, const QUrlQuery &rhs)
- Returns \c true if \a other is not equal to this QUrlQuery. Otherwise, returns \c false.
+ Returns \c true if the QUrlQuery object \a rhs is not equal to \a lhs.
+ Otherwise, returns \c false.
\sa operator==()
*/
diff --git a/src/corelib/io/qurlquery.h b/src/corelib/io/qurlquery.h
index 411f19a4c8..061107606e 100644
--- a/src/corelib/io/qurlquery.h
+++ b/src/corelib/io/qurlquery.h
@@ -5,7 +5,7 @@
#ifndef QURLQUERY_H
#define QURLQUERY_H
-#include <QtCore/qpair.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qurl.h>
@@ -22,10 +22,10 @@ public:
QUrlQuery();
explicit QUrlQuery(const QUrl &url);
explicit QUrlQuery(const QString &queryString);
- QUrlQuery(std::initializer_list<QPair<QString, QString>> list)
+ QUrlQuery(std::initializer_list<std::pair<QString, QString>> list)
: QUrlQuery()
{
- for (const QPair<QString, QString> &item : list)
+ for (const std::pair<QString, QString> &item : list)
addQueryItem(item.first, item.second);
}
@@ -35,9 +35,11 @@ public:
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QUrlQuery)
~QUrlQuery();
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QUrlQuery &other) const;
bool operator!=(const QUrlQuery &other) const
- { return !(*this == other); }
+ { return !operator==(other); }
+#endif
void swap(QUrlQuery &other) noexcept { d.swap(other.d); }
@@ -54,8 +56,8 @@ public:
QChar queryValueDelimiter() const;
QChar queryPairDelimiter() const;
- void setQueryItems(const QList<QPair<QString, QString> > &query);
- QList<QPair<QString, QString> > queryItems(QUrl::ComponentFormattingOptions encoding = QUrl::PrettyDecoded) const;
+ void setQueryItems(const QList<std::pair<QString, QString> > &query);
+ QList<std::pair<QString, QString> > queryItems(QUrl::ComponentFormattingOptions encoding = QUrl::PrettyDecoded) const;
bool hasQueryItem(const QString &key) const;
void addQueryItem(const QString &key, const QString &value);
@@ -68,6 +70,8 @@ public:
static constexpr char16_t defaultQueryPairDelimiter() noexcept { return u'&'; }
private:
+ friend Q_CORE_EXPORT bool comparesEqual(const QUrlQuery &lhs, const QUrlQuery &rhs);
+ Q_DECLARE_EQUALITY_COMPARABLE(QUrlQuery)
friend class QUrl;
friend Q_CORE_EXPORT size_t qHash(const QUrlQuery &key, size_t seed) noexcept;
QSharedDataPointer<QUrlQueryPrivate> d;
diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp
index e0ae9607c8..31d0dc1417 100644
--- a/src/corelib/io/qwindowspipereader.cpp
+++ b/src/corelib/io/qwindowspipereader.cpp
@@ -511,3 +511,5 @@ bool QWindowsPipeReader::waitForNotification()
}
QT_END_NAMESPACE
+
+#include "moc_qwindowspipereader_p.cpp"
diff --git a/src/corelib/io/qwindowspipewriter.cpp b/src/corelib/io/qwindowspipewriter.cpp
index 24f8981042..9d0f6a8a3e 100644
--- a/src/corelib/io/qwindowspipewriter.cpp
+++ b/src/corelib/io/qwindowspipewriter.cpp
@@ -314,3 +314,5 @@ bool QWindowsPipeWriter::consumePendingAndEmit(bool allowWinActPosting)
}
QT_END_NAMESPACE
+
+#include "moc_qwindowspipewriter_p.cpp"
diff --git a/src/gui/text/qzip.cpp b/src/corelib/io/qzip.cpp
index 7fd96363df..173563ec29 100644
--- a/src/gui/text/qzip.cpp
+++ b/src/corelib/io/qzip.cpp
@@ -1,12 +1,9 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <qglobal.h>
-
-#ifndef QT_NO_TEXTODFWRITER
-
#include "qzipreader_p.h"
#include "qzipwriter_p.h"
+
#include <qdatetime.h>
#include <qendian.h>
#include <qdebug.h>
@@ -733,37 +730,37 @@ void QZipWriterPrivate::addEntry(EntryType type, const QString &fileName, const
*/
/*!
- \variable FileInfo::filePath
+ \variable QZipReader::FileInfo::filePath
The full filepath inside the archive.
*/
/*!
- \variable FileInfo::isDir
+ \variable QZipReader::FileInfo::isDir
A boolean type indicating if the entry is a directory.
*/
/*!
- \variable FileInfo::isFile
+ \variable QZipReader::FileInfo::isFile
A boolean type, if it is one this entry is a file.
*/
/*!
- \variable FileInfo::isSymLink
+ \variable QZipReader::FileInfo::isSymLink
A boolean type, if it is one this entry is symbolic link.
*/
/*!
- \variable FileInfo::permissions
+ \variable QZipReader::FileInfo::permissions
A list of flags for the permissions of this entry.
*/
/*!
- \variable FileInfo::crc
+ \variable QZipReader::FileInfo::crc
The calculated checksum as a crc type.
*/
/*!
- \variable FileInfo::size
+ \variable QZipReader::FileInfo::size
The total size of the unpacked content.
*/
@@ -1348,5 +1345,3 @@ void QZipWriter::close()
}
QT_END_NAMESPACE
-
-#endif // QT_NO_TEXTODFWRITER
diff --git a/src/gui/text/qzipreader_p.h b/src/corelib/io/qzipreader_p.h
index 2e8d6bc951..e6ddd0dc99 100644
--- a/src/gui/text/qzipreader_p.h
+++ b/src/corelib/io/qzipreader_p.h
@@ -4,10 +4,7 @@
#ifndef QZIPREADER_H
#define QZIPREADER_H
-#include <QtGui/private/qtguiglobal_p.h>
-#include <QtCore/qglobal.h>
-
-#ifndef QT_NO_TEXTODFWRITER
+#include <QtCore/private/qglobal_p.h>
//
// W A R N I N G
@@ -28,7 +25,7 @@ QT_BEGIN_NAMESPACE
class QZipReaderPrivate;
-class Q_GUI_EXPORT QZipReader
+class Q_CORE_EXPORT QZipReader
{
public:
explicit QZipReader(const QString &fileName, QIODevice::OpenMode mode = QIODevice::ReadOnly );
@@ -87,5 +84,4 @@ Q_DECLARE_TYPEINFO(QZipReader::Status, Q_PRIMITIVE_TYPE);
QT_END_NAMESPACE
-#endif // QT_NO_TEXTODFWRITER
#endif // QZIPREADER_H
diff --git a/src/gui/text/qzipwriter_p.h b/src/corelib/io/qzipwriter_p.h
index 6c1ef5d848..770e6118b6 100644
--- a/src/gui/text/qzipwriter_p.h
+++ b/src/corelib/io/qzipwriter_p.h
@@ -3,9 +3,7 @@
#ifndef QZIPWRITER_H
#define QZIPWRITER_H
-#include <QtGui/private/qtguiglobal_p.h>
-
-#ifndef QT_NO_TEXTODFWRITER
+#include <QtCore/private/qglobal_p.h>
//
// W A R N I N G
@@ -25,8 +23,7 @@ QT_BEGIN_NAMESPACE
class QZipWriterPrivate;
-
-class Q_GUI_EXPORT QZipWriter
+class Q_CORE_EXPORT QZipWriter
{
public:
explicit QZipWriter(const QString &fileName, QIODevice::OpenMode mode = (QIODevice::WriteOnly | QIODevice::Truncate) );
@@ -77,5 +74,4 @@ private:
QT_END_NAMESPACE
-#endif // QT_NO_TEXTODFWRITER
#endif // QZIPWRITER_H
diff --git a/src/corelib/ipc/qsharedmemory.cpp b/src/corelib/ipc/qsharedmemory.cpp
index 9e33b1d995..02761c0263 100644
--- a/src/corelib/ipc/qsharedmemory.cpp
+++ b/src/corelib/ipc/qsharedmemory.cpp
@@ -7,6 +7,7 @@
#include "qtipccommon_p.h"
#include "qsystemsemaphore.h"
+#include <q20memory.h>
#include <qdebug.h>
#ifdef Q_OS_WIN
# include <qt_windows.h>
@@ -23,15 +24,6 @@ QT_BEGIN_NAMESPACE
using namespace QtIpcCommon;
using namespace Qt::StringLiterals;
-#if __cplusplus >= 202002L
-using std::construct_at;
-#else
-template <typename T> static void construct_at(T *ptr)
-{
- new (ptr) T;
-}
-#endif
-
QSharedMemoryPrivate::~QSharedMemoryPrivate()
{
destructBackend();
@@ -39,6 +31,7 @@ QSharedMemoryPrivate::~QSharedMemoryPrivate()
inline void QSharedMemoryPrivate::constructBackend()
{
+ using namespace q20;
visit([](auto p) { construct_at(p); });
}
@@ -132,24 +125,17 @@ QSharedMemory::QSharedMemory(const QNativeIpcKey &key, QObject *parent)
setNativeKey(key);
}
-#if QT_DEPRECATED_SINCE(6, 10)
/*!
- \deprecated
-
Constructs a shared memory object with the given \a parent and with
the legacy key set to \a key. Because its key is set, its create() and
attach() functions can be called.
- Legacy keys are deprecated. See \l{Native IPC Keys} for more information.
-
\sa setKey(), create(), attach()
*/
QSharedMemory::QSharedMemory(const QString &key, QObject *parent)
: QSharedMemory(legacyNativeKey(key), parent)
{
- d_func()->legacyKey = key;
}
-#endif
/*!
The destructor clears the key, which forces the shared memory object
@@ -168,9 +154,7 @@ QSharedMemory::~QSharedMemory()
d->cleanHandle();
}
-#if QT_DEPRECATED_SINCE(6, 10)
/*!
- \deprecated
\overload
Sets the legacy \a key for this shared memory object. If \a key is the same
@@ -192,11 +176,8 @@ QSharedMemory::~QSharedMemory()
*/
void QSharedMemory::setKey(const QString &key)
{
- Q_D(QSharedMemory);
setNativeKey(legacyNativeKey(key));
- d->legacyKey = key;
}
-#endif
/*!
\since 4.8
@@ -252,7 +233,6 @@ void QSharedMemory::setNativeKey(const QNativeIpcKey &key)
if (isAttached())
detach();
d->cleanHandle();
- d->legacyKey = QString();
if (key.type() == d->nativeKey.type()) {
// we can reuse the backend
d->nativeKey = key;
@@ -269,7 +249,11 @@ bool QSharedMemoryPrivate::initKey(SemaphoreAccessMode mode)
if (!cleanHandle())
return false;
#if QT_CONFIG(systemsemaphore)
- systemSemaphore.setNativeKey(semaphoreNativeKey(), 1, mode);
+ const QString legacyKey = QNativeIpcKeyPrivate::legacyKey(nativeKey);
+ const QNativeIpcKey semKey = legacyKey.isEmpty()
+ ? semaphoreNativeKey()
+ : QSystemSemaphore::legacyNativeKey(legacyKey, nativeKey.type());
+ systemSemaphore.setNativeKey(semKey, 1, mode);
if (systemSemaphore.error() != QSystemSemaphore::NoError) {
QString function = "QSharedMemoryPrivate::initKey"_L1;
errorString = QSharedMemory::tr("%1: unable to set key on lock (%2)")
@@ -305,9 +289,7 @@ bool QSharedMemoryPrivate::initKey(SemaphoreAccessMode mode)
return true;
}
-#if QT_DEPRECATED_SINCE(6, 10)
/*!
- \deprecated
Returns the legacy key assigned with setKey() to this shared memory, or a null key
if no key has been assigned, or if the segment is using a nativeKey(). The
key is the identifier used by Qt applications to identify the shared memory
@@ -321,9 +303,8 @@ bool QSharedMemoryPrivate::initKey(SemaphoreAccessMode mode)
QString QSharedMemory::key() const
{
Q_D(const QSharedMemory);
- return d->legacyKey;
+ return QNativeIpcKeyPrivate::legacyKey(d->nativeKey);
}
-#endif
/*!
\since 4.8
@@ -693,12 +674,12 @@ bool QSharedMemory::isKeyTypeSupported(QNativeIpcKey::Type type)
QNativeIpcKey QSharedMemory::platformSafeKey(const QString &key, QNativeIpcKey::Type type)
{
- return { QtIpcCommon::platformSafeKey(key, IpcType::SharedMemory, type), type };
+ return QtIpcCommon::platformSafeKey(key, IpcType::SharedMemory, type);
}
QNativeIpcKey QSharedMemory::legacyNativeKey(const QString &key, QNativeIpcKey::Type type)
{
- return { legacyPlatformSafeKey(key, IpcType::SharedMemory, type), type };
+ return QtIpcCommon::legacyPlatformSafeKey(key, IpcType::SharedMemory, type);
}
#endif // QT_CONFIG(sharedmemory)
diff --git a/src/corelib/ipc/qsharedmemory.h b/src/corelib/ipc/qsharedmemory.h
index f8218cb0fe..ab448b15c1 100644
--- a/src/corelib/ipc/qsharedmemory.h
+++ b/src/corelib/ipc/qsharedmemory.h
@@ -50,14 +50,9 @@ public:
QSharedMemory(const QNativeIpcKey &key, QObject *parent = nullptr);
~QSharedMemory();
-#if QT_DEPRECATED_SINCE(6, 10)
- QT_DEPRECATED_VERSION_X_6_10("Please refer to 'Native IPC Key' documentation")
QSharedMemory(const QString &key, QObject *parent = nullptr);
- QT_DEPRECATED_VERSION_X_6_10("Please refer to 'Native IPC Key' documentation")
void setKey(const QString &key);
- QT_DEPRECATED_VERSION_X_6_10("Please refer to 'Native IPC Key' documentation")
QString key() const;
-#endif
void setNativeKey(const QNativeIpcKey &key);
void setNativeKey(const QString &key, QNativeIpcKey::Type type = QNativeIpcKey::legacyDefaultTypeForOs())
diff --git a/src/corelib/ipc/qsharedmemory_p.h b/src/corelib/ipc/qsharedmemory_p.h
index 3a6cd8c137..987bb38642 100644
--- a/src/corelib/ipc/qsharedmemory_p.h
+++ b/src/corelib/ipc/qsharedmemory_p.h
@@ -43,7 +43,7 @@ class QSharedMemoryLocker
{
public:
- inline QSharedMemoryLocker(QSharedMemory *sharedMemory) : q_sm(sharedMemory)
+ Q_NODISCARD_CTOR QSharedMemoryLocker(QSharedMemory *sharedMemory) : q_sm(sharedMemory)
{
Q_ASSERT(q_sm);
}
@@ -205,8 +205,6 @@ public:
}
QNativeIpcKey semaphoreNativeKey() const;
#endif // QT_CONFIG(systemsemaphore)
-
- QString legacyKey; // deprecated
};
QT_END_NAMESPACE
diff --git a/src/corelib/ipc/qsharedmemory_posix.cpp b/src/corelib/ipc/qsharedmemory_posix.cpp
index 744a6d67a4..582c6628e1 100644
--- a/src/corelib/ipc/qsharedmemory_posix.cpp
+++ b/src/corelib/ipc/qsharedmemory_posix.cpp
@@ -10,6 +10,7 @@
#include <errno.h>
+#if QT_CONFIG(sharedmemory)
#if QT_CONFIG(posix_shm)
#include <sys/types.h>
#include <sys/mman.h>
@@ -66,7 +67,7 @@ bool QSharedMemoryPosix::create(QSharedMemoryPrivate *self, qsizetype size)
const QByteArray shmName = QFile::encodeName(self->nativeKey.nativeKey());
int fd;
- EINTR_LOOP(fd, ::shm_open(shmName.constData(), O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0600));
+ QT_EINTR_LOOP(fd, ::shm_open(shmName.constData(), O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0600));
if (fd == -1) {
const int errorNumber = errno;
const auto function = "QSharedMemory::attach (shm_open)"_L1;
@@ -83,7 +84,7 @@ bool QSharedMemoryPosix::create(QSharedMemoryPrivate *self, qsizetype size)
// the size may only be set once
int ret;
- EINTR_LOOP(ret, QT_FTRUNCATE(fd, size));
+ QT_EINTR_LOOP(ret, QT_FTRUNCATE(fd, size));
if (ret == -1) {
self->setUnixErrorString("QSharedMemory::create (ftruncate)"_L1);
qt_safe_close(fd);
@@ -102,7 +103,7 @@ bool QSharedMemoryPosix::attach(QSharedMemoryPrivate *self, QSharedMemory::Acces
const int oflag = (mode == QSharedMemory::ReadOnly ? O_RDONLY : O_RDWR);
const mode_t omode = (mode == QSharedMemory::ReadOnly ? 0400 : 0600);
- EINTR_LOOP(hand, ::shm_open(shmName.constData(), oflag | O_CLOEXEC, omode));
+ QT_EINTR_LOOP(hand, ::shm_open(shmName.constData(), oflag | O_CLOEXEC, omode));
if (hand == -1) {
const int errorNumber = errno;
const auto function = "QSharedMemory::attach (shm_open)"_L1;
@@ -192,3 +193,4 @@ bool QSharedMemoryPosix::detach(QSharedMemoryPrivate *self)
QT_END_NAMESPACE
#endif // QT_CONFIG(posix_shm)
+#endif // QT_CONFIG(sharedmemory)
diff --git a/src/corelib/ipc/qsharedmemory_systemv.cpp b/src/corelib/ipc/qsharedmemory_systemv.cpp
index cc98b560ae..dc9de11091 100644
--- a/src/corelib/ipc/qsharedmemory_systemv.cpp
+++ b/src/corelib/ipc/qsharedmemory_systemv.cpp
@@ -11,6 +11,7 @@
#include <errno.h>
+#if QT_CONFIG(sharedmemory)
#if QT_CONFIG(sysv_shm)
#include <sys/types.h>
#include <sys/ipc.h>
@@ -75,6 +76,7 @@ key_t QSharedMemorySystemV::handle(QSharedMemoryPrivate *self)
unix_key = ftok(nativeKeyFile, int(self->nativeKey.type()));
if (unix_key < 0) {
self->setUnixErrorString("QSharedMemory::handle"_L1);
+ nativeKeyFile.clear();
unix_key = 0;
}
return unix_key;
@@ -158,6 +160,8 @@ bool QSharedMemorySystemV::attach(QSharedMemoryPrivate *self, QSharedMemory::Acc
int id = shmget(unix_key, 0, (mode == QSharedMemory::ReadOnly ? 0400 : 0600));
if (-1 == id) {
self->setUnixErrorString("QSharedMemory::attach (shmget)"_L1);
+ unix_key = 0;
+ nativeKeyFile.clear();
return false;
}
@@ -205,3 +209,4 @@ bool QSharedMemorySystemV::detach(QSharedMemoryPrivate *self)
QT_END_NAMESPACE
#endif // QT_CONFIG(sysv_shm)
+#endif // QT_CONFIG(sharedmemory)
diff --git a/src/corelib/ipc/qsystemsemaphore.cpp b/src/corelib/ipc/qsystemsemaphore.cpp
index 0f59b378a3..4c24ef6043 100644
--- a/src/corelib/ipc/qsystemsemaphore.cpp
+++ b/src/corelib/ipc/qsystemsemaphore.cpp
@@ -68,25 +68,13 @@ inline void QSystemSemaphorePrivate::destructBackend()
\sa {Inter-Process Communication}, QSharedMemory, QSemaphore
*/
-#if QT_DEPRECATED_SINCE(6, 10)
/*!
- \deprecated
-
- Requests a system semaphore identified by the legacy key \a key. This
- constructor does the same as:
-
- \code
- QSystemSemaphore(QSystemSemaphore::legacyNativeKey(key), initialValue, mode)
- \endcode
-
- except that it stores the legacy native key to retrieve using key().
+ Requests a system semaphore identified by the legacy key \a key.
*/
QSystemSemaphore::QSystemSemaphore(const QString &key, int initialValue, AccessMode mode)
: QSystemSemaphore(legacyNativeKey(key), initialValue, mode)
{
- d->legacyKey = key;
}
-#endif
/*!
Requests a system semaphore for the specified \a key. The parameters
@@ -210,8 +198,6 @@ void QSystemSemaphore::setNativeKey(const QNativeIpcKey &key, int initialValue,
}
d->initialValue = initialValue;
d->handle(mode);
-
- d->legacyKey.clear();
}
/*!
@@ -229,9 +215,7 @@ QNativeIpcKey QSystemSemaphore::nativeIpcKey() const
return d->nativeKey;
}
-#if QT_DEPRECATED_SINCE(6, 10)
/*!
- \deprecated
This function works the same as the constructor. It reconstructs
this QSystemSemaphore object. If the new \a key is different from
the old key, calling this function is like calling the destructor of
@@ -244,11 +228,9 @@ QNativeIpcKey QSystemSemaphore::nativeIpcKey() const
void QSystemSemaphore::setKey(const QString &key, int initialValue, AccessMode mode)
{
setNativeKey(legacyNativeKey(key), initialValue, mode);
- d->legacyKey = key;
}
/*!
- \deprecated
Returns the legacy key assigned to this system semaphore. The key is the
name by which the semaphore can be accessed from other processes.
@@ -256,9 +238,8 @@ void QSystemSemaphore::setKey(const QString &key, int initialValue, AccessMode m
*/
QString QSystemSemaphore::key() const
{
- return d->legacyKey;
+ return QNativeIpcKeyPrivate::legacyKey(d->nativeKey);
}
-#endif
/*!
Acquires one of the resources guarded by this semaphore, if there is
@@ -406,12 +387,12 @@ bool QSystemSemaphore::isKeyTypeSupported(QNativeIpcKey::Type type)
QNativeIpcKey QSystemSemaphore::platformSafeKey(const QString &key, QNativeIpcKey::Type type)
{
- return { QtIpcCommon::platformSafeKey(key, IpcType::SystemSemaphore, type), type };
+ return QtIpcCommon::platformSafeKey(key, IpcType::SystemSemaphore, type);
}
QNativeIpcKey QSystemSemaphore::legacyNativeKey(const QString &key, QNativeIpcKey::Type type)
{
- return { legacyPlatformSafeKey(key, IpcType::SystemSemaphore, type), type };
+ return QtIpcCommon::legacyPlatformSafeKey(key, IpcType::SystemSemaphore, type);
}
QT_END_NAMESPACE
diff --git a/src/corelib/ipc/qsystemsemaphore.h b/src/corelib/ipc/qsystemsemaphore.h
index bd0057e6b7..df6fd28342 100644
--- a/src/corelib/ipc/qsystemsemaphore.h
+++ b/src/corelib/ipc/qsystemsemaphore.h
@@ -47,14 +47,9 @@ public:
{ setNativeKey({ key, type }, initialValue, mode); }
QNativeIpcKey nativeIpcKey() const;
-#if QT_DEPRECATED_SINCE(6, 10)
- QT_DEPRECATED_VERSION_X_6_10("Please refer to 'Native IPC Key' documentation")
QSystemSemaphore(const QString &key, int initialValue = 0, AccessMode mode = Open);
- QT_DEPRECATED_VERSION_X_6_10("Please refer to 'Native IPC Key' documentation")
void setKey(const QString &key, int initialValue = 0, AccessMode mode = Open);
- QT_DEPRECATED_VERSION_X_6_10("Please refer to 'Native IPC Key' documentation")
QString key() const;
-#endif
bool acquire();
bool release(int n = 1);
diff --git a/src/corelib/ipc/qsystemsemaphore_p.h b/src/corelib/ipc/qsystemsemaphore_p.h
index f63315ee81..788c4fb784 100644
--- a/src/corelib/ipc/qsystemsemaphore_p.h
+++ b/src/corelib/ipc/qsystemsemaphore_p.h
@@ -142,8 +142,6 @@ public:
{
return visit([&](auto p) { return p->modifySemaphore(this, count); });
}
-
- QString legacyKey; // deprecated
};
QT_END_NAMESPACE
diff --git a/src/corelib/ipc/qsystemsemaphore_posix.cpp b/src/corelib/ipc/qsystemsemaphore_posix.cpp
index b290e14de4..7df9593513 100644
--- a/src/corelib/ipc/qsystemsemaphore_posix.cpp
+++ b/src/corelib/ipc/qsystemsemaphore_posix.cpp
@@ -20,9 +20,9 @@
#ifdef Q_OS_UNIX
# include "private/qcore_unix_p.h"
#else
-#define EINTR_LOOP_VAL(var, val, cmd) \
+# define QT_EINTR_LOOP_VAL(var, val, cmd) \
(void)var; var = cmd
-#define EINTR_LOOP(var, cmd) EINTR_LOOP_VAL(var, -1, cmd)
+# define QT_EINTR_LOOP(var, cmd) QT_EINTR_LOOP_VAL(var, -1, cmd)
#endif
// OpenBSD 4.2 doesn't define EIDRM, see BUGS section:
@@ -126,6 +126,12 @@ bool QSystemSemaphorePosix::modifySemaphore(QSystemSemaphorePrivate *self, int c
int cnt = count;
do {
if (::sem_post(semaphore) == -1) {
+#if defined(Q_OS_VXWORKS)
+ if (errno == EINVAL) {
+ semaphore = SEM_FAILED;
+ return modifySemaphore(self, cnt);
+ }
+#endif
self->setUnixErrorString("QSystemSemaphore::modifySemaphore (sem_post)"_L1);
#if defined QSYSTEMSEMAPHORE_DEBUG
qDebug("QSystemSemaphorePosix::modify sem_post failed %d %d", count, errno);
@@ -133,7 +139,7 @@ bool QSystemSemaphorePosix::modifySemaphore(QSystemSemaphorePrivate *self, int c
// rollback changes to preserve the SysV semaphore behavior
for ( ; cnt < count; ++cnt) {
int res;
- EINTR_LOOP(res, ::sem_wait(semaphore));
+ QT_EINTR_LOOP(res, ::sem_wait(semaphore));
}
return false;
}
@@ -141,7 +147,7 @@ bool QSystemSemaphorePosix::modifySemaphore(QSystemSemaphorePrivate *self, int c
} while (cnt > 0);
} else {
int res;
- EINTR_LOOP(res, ::sem_wait(semaphore));
+ QT_EINTR_LOOP(res, ::sem_wait(semaphore));
if (res == -1) {
// If the semaphore was removed be nice and create it and then modifySemaphore again
if (errno == EINVAL || errno == EIDRM) {
diff --git a/src/corelib/ipc/qsystemsemaphore_systemv.cpp b/src/corelib/ipc/qsystemsemaphore_systemv.cpp
index cdfa6adfd4..e5d231d1d4 100644
--- a/src/corelib/ipc/qsystemsemaphore_systemv.cpp
+++ b/src/corelib/ipc/qsystemsemaphore_systemv.cpp
@@ -53,6 +53,9 @@ bool QSystemSemaphoreSystemV::runtimeSupportCheck()
*/
key_t QSystemSemaphoreSystemV::handle(QSystemSemaphorePrivate *self, QSystemSemaphore::AccessMode mode)
{
+ if (unix_key != -1)
+ return unix_key; // we already have a semaphore
+
#if defined(Q_OS_DARWIN)
if (qt_apple_isSandboxed()) {
// attempting to use System V semaphores will get us a SIGSYS
@@ -73,9 +76,6 @@ key_t QSystemSemaphoreSystemV::handle(QSystemSemaphorePrivate *self, QSystemSema
return -1;
}
- if (-1 != unix_key)
- return unix_key;
-
// ftok requires that an actual file exists somewhere
int built = QtIpcCommon::createUnixKeyFile(nativeKeyFile);
if (-1 == built) {
@@ -174,7 +174,7 @@ bool QSystemSemaphoreSystemV::modifySemaphore(QSystemSemaphorePrivate *self, int
operation.sem_flg = SEM_UNDO;
int res;
- EINTR_LOOP(res, semop(semaphore, &operation, 1));
+ QT_EINTR_LOOP(res, semop(semaphore, &operation, 1));
if (-1 == res) {
// If the semaphore was removed be nice and create it and then modifySemaphore again
if (errno == EINVAL || errno == EIDRM) {
diff --git a/src/corelib/ipc/qtipccommon.cpp b/src/corelib/ipc/qtipccommon.cpp
index 46a4777104..b2ae9172fa 100644
--- a/src/corelib/ipc/qtipccommon.cpp
+++ b/src/corelib/ipc/qtipccommon.cpp
@@ -7,7 +7,8 @@
#include <qcryptographichash.h>
#include <qstandardpaths.h>
#include <qstringconverter.h>
-#include <private/qurl_p.h>
+#include <qurl.h>
+#include <qurlquery.h>
#if defined(Q_OS_DARWIN)
# include "private/qcore_mac_p.h"
@@ -18,6 +19,8 @@
// by-one bug in the kernel) the usable bytes are only 30.
# define SHM_NAME_MAX 30
# endif
+#elif defined(Q_OS_WINDOWS)
+# include "qt_windows.h"
#endif
#if QT_CONFIG(sharedmemory) || QT_CONFIG(systemsemaphore)
@@ -91,16 +94,18 @@ static QNativeIpcKey::Type stringToType(QStringView typeString)
Legacy: this exists for compatibility with QSharedMemory and
QSystemSemaphore between 4.4 and 6.6.
- Generate a string from the key which can be any unicode string into
- the subset that the win/unix kernel allows.
-
- On Unix this will be a file name
+ Returns a QNativeIpcKey that contains a platform-safe key using rules
+ similar to QtIpcCommon::platformSafeKey() below, but using an algorithm
+ that is compatible with Qt 4.4 to 6.6. Additionally, the returned
+ QNativeIpcKey will record the input \a key so it can be included in the
+ string form if necessary to pass to other processes.
*/
-QString QtIpcCommon::legacyPlatformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType,
- QNativeIpcKey::Type type)
+QNativeIpcKey QtIpcCommon::legacyPlatformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType,
+ QNativeIpcKey::Type type)
{
+ QNativeIpcKey k(type);
if (key.isEmpty())
- return QString();
+ return k;
QByteArray hex = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha1).toHex();
@@ -111,13 +116,16 @@ QString QtIpcCommon::legacyPlatformSafeKey(const QString &key, QtIpcCommon::IpcT
// to be in the form <application group identifier>/<custom identifier>.
// Since we don't know which application group identifier the user wants
// to apply, we instead document that requirement, and use the key directly.
- return key;
+ QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, key, key);
+ } else {
+ // The shared memory name limit on Apple platforms is very low (30 characters),
+ // so we can't use the logic below of combining the prefix, key, and a hash,
+ // to ensure a unique and valid name. Instead we use the first part of the
+ // hash, which should still long enough to avoid collisions in practice.
+ QString native = u'/' + QLatin1StringView(hex).left(SHM_NAME_MAX - 1);
+ QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, native, key);
}
- // The shared memory name limit on Apple platforms is very low (30 characters),
- // so we can't use the logic below of combining the prefix, key, and a hash,
- // to ensure a unique and valid name. Instead we use the first part of the
- // hash, which should still long enough to avoid collisions in practice.
- return u'/' + QLatin1StringView(hex).left(SHM_NAME_MAX - 1);
+ return k;
#endif
}
@@ -141,38 +149,51 @@ QString QtIpcCommon::legacyPlatformSafeKey(const QString &key, QtIpcCommon::IpcT
switch (type) {
case QNativeIpcKey::Type::Windows:
- if (!isIpcSupported(ipcType, QNativeIpcKey::Type::Windows))
- return QString();
- return result;
+ if (isIpcSupported(ipcType, QNativeIpcKey::Type::Windows))
+ QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, result, key);
+ return k;
case QNativeIpcKey::Type::PosixRealtime:
- if (!isIpcSupported(ipcType, QNativeIpcKey::Type::PosixRealtime))
- return QString();
- return result.prepend(u'/');
+ result.prepend(u'/');
+ if (isIpcSupported(ipcType, QNativeIpcKey::Type::PosixRealtime))
+ QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, result, key);
+ return k;
case QNativeIpcKey::Type::SystemV:
break;
}
- if (!isIpcSupported(ipcType, QNativeIpcKey::Type::SystemV))
- return QString();
- return QStandardPaths::writableLocation(QStandardPaths::TempLocation) + u'/' + result;
+ if (isIpcSupported(ipcType, QNativeIpcKey::Type::SystemV)) {
+ result = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + u'/' + result;
+ QNativeIpcKeyPrivate::setNativeAndLegacyKeys(k, result, key);
+ }
+ return k;
}
-QString QtIpcCommon::platformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType,
- QNativeIpcKey::Type type)
+/*!
+ \internal
+ Returns a QNativeIpcKey of type \a type, suitable for QSystemSemaphore or
+ QSharedMemory depending on \a ipcType. The returned native key is generated
+ from the Unicode input \a key and is safe for use on for the key type in
+ question in the current OS.
+*/
+QNativeIpcKey QtIpcCommon::platformSafeKey(const QString &key, QtIpcCommon::IpcType ipcType,
+ QNativeIpcKey::Type type)
{
+ QNativeIpcKey k(type);
if (key.isEmpty())
- return key;
+ return k;
switch (type) {
case QNativeIpcKey::Type::PosixRealtime:
- if (!isIpcSupported(ipcType, QNativeIpcKey::Type::PosixRealtime))
- return QString();
+ if (isIpcSupported(ipcType, QNativeIpcKey::Type::PosixRealtime)) {
#ifdef SHM_NAME_MAX
- // The shared memory name limit on Apple platforms is very low (30
- // characters), so we have to cut it down to avoid ENAMETOOLONG. We
- // hope that there won't be too many collisions...
- return u'/' + QStringView(key).left(SHM_NAME_MAX - 1);
+ // The shared memory name limit on Apple platforms is very low (30
+ // characters), so we have to cut it down to avoid ENAMETOOLONG. We
+ // hope that there won't be too many collisions...
+ k.setNativeKey(u'/' + QStringView(key).left(SHM_NAME_MAX - 1));
+#else
+ k.setNativeKey(u'/' + key);
#endif
- return u'/' + key;
+ }
+ return k;
case QNativeIpcKey::Type::Windows:
if (isIpcSupported(ipcType, QNativeIpcKey::Type::Windows)) {
@@ -194,25 +215,27 @@ QString QtIpcCommon::platformSafeKey(const QString &key, QtIpcCommon::IpcType ip
}
QString result = prefix + mid + payload;
-#ifdef MAX_PATH
+#ifdef Q_OS_WINDOWS
result.truncate(MAX_PATH);
#endif
- return result;
+ k.setNativeKey(result);
}
- return QString();
+ return k;
case QNativeIpcKey::Type::SystemV:
break;
}
// System V
- if (!isIpcSupported(ipcType, QNativeIpcKey::Type::SystemV))
- return QString();
- if (key.startsWith(u'/'))
- return key;
-
- QString baseDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
- return baseDir + u'/' + key;
+ if (isIpcSupported(ipcType, QNativeIpcKey::Type::SystemV)) {
+ if (key.startsWith(u'/')) {
+ k.setNativeKey(key);
+ } else {
+ QString baseDir = QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation);
+ k.setNativeKey(baseDir + u'/' + key);
+ }
+ }
+ return k;
}
/*!
@@ -221,6 +244,8 @@ QString QtIpcCommon::platformSafeKey(const QString &key, QtIpcCommon::IpcType ip
\since 6.6
\brief The QNativeIpcKey class holds a native key used by QSystemSemaphore and QSharedMemory.
+ \compares equality
+
The \l QSharedMemory and \l QSystemSemaphore classes identify their
resource using a system-wide identifier known as a "key". The low-level key
value as well as the key type are encapsulated in Qt using the \l
@@ -343,6 +368,11 @@ QNativeIpcKey::Type QNativeIpcKey::defaultTypeForOs_internal() noexcept
}
#endif
+/*!
+ \fn QNativeIpcKey::QNativeIpcKey() noexcept
+
+ Constructs a QNativeIpcKey object of type \l DefaultTypeForOs with an empty key.
+*/
/*!
\fn QNativeIpcKey::QNativeIpcKey(Type type) noexcept
@@ -360,19 +390,26 @@ QNativeIpcKey::Type QNativeIpcKey::defaultTypeForOs_internal() noexcept
Copies or moves the content of \a other.
*/
-void QNativeIpcKey::copy_internal(const QNativeIpcKey &)
+void QNativeIpcKey::copy_internal(const QNativeIpcKey &other)
{
- Q_UNREACHABLE();
+ d = new QNativeIpcKeyPrivate(*other.d);
}
void QNativeIpcKey::move_internal(QNativeIpcKey &&) noexcept
{
- Q_UNREACHABLE();
+ // inline code already moved properly, nothing for us to do here
}
-QNativeIpcKey &QNativeIpcKey::assign_internal(const QNativeIpcKey &)
+QNativeIpcKey &QNativeIpcKey::assign_internal(const QNativeIpcKey &other)
{
- Q_UNREACHABLE_RETURN(*this);
+ Q_ASSERT(d || other.d); // only 3 cases to handle
+ if (d && !other.d)
+ *d = {};
+ else if (d)
+ *d = *other.d;
+ else
+ d = new QNativeIpcKeyPrivate(*other.d);
+ return *this;
}
/*!
@@ -382,16 +419,22 @@ QNativeIpcKey &QNativeIpcKey::assign_internal(const QNativeIpcKey &)
*/
void QNativeIpcKey::destroy_internal() noexcept
{
- Q_ASSERT(isSlowPath());
- Q_UNREACHABLE();
+ delete d;
}
/*!
\fn QNativeIpcKey::swap(QNativeIpcKey &other) noexcept
- \fn swap(QNativeIpcKey &lhs, QNativeIpcKey &rhs) noexcept
- Swaps the native IPC key and type \a other with this object, or \a lhs with
- \a rhs. This operation is very fast and never fails.
+ Swaps the native IPC key and type \a other with this object.
+ This operation is very fast and never fails.
+*/
+
+/*!
+ \fn swap(QNativeIpcKey &value1, QNativeIpcKey &value2) noexcept
+ \relates QNativeIpcKey
+
+ Swaps the native IPC key and type \a value1 with \a value2.
+ This operation is very fast and never fails.
*/
/*!
@@ -422,11 +465,6 @@ void QNativeIpcKey::destroy_internal() noexcept
\sa nativeKey(), setType()
*/
-QNativeIpcKey::Type QNativeIpcKey::type_internal() const noexcept
-{
- Q_ASSERT(isSlowPath());
- Q_UNREACHABLE_RETURN({});
-}
/*!
\fn QNativeIpcKey::setType(Type type)
@@ -435,9 +473,9 @@ QNativeIpcKey::Type QNativeIpcKey::type_internal() const noexcept
\sa type(), setNativeKey()
*/
-void QNativeIpcKey::setType_internal(Type)
+void QNativeIpcKey::setType_internal(Type type)
{
- Q_UNREACHABLE();
+ Q_UNUSED(type);
}
/*!
@@ -455,6 +493,28 @@ void QNativeIpcKey::setType_internal(Type)
\sa nativeKey(), setType()
*/
+void QNativeIpcKey::setNativeKey_internal(const QString &)
+{
+ d->legacyKey_.clear();
+}
+
+/*!
+ \fn size_t QNativeIpcKey::qHash(const QNativeIpcKey &ipcKey) noexcept
+
+ Returns the hash value for \a ipcKey, using a default seed of \c 0.
+*/
+
+/*!
+ \fn size_t QNativeIpcKey::qHash(const QNativeIpcKey &ipcKey, size_t seed) noexcept
+
+ Returns the hash value for \a ipcKey, using \a seed to seed the calculation.
+*/
+size_t qHash(const QNativeIpcKey &ipcKey, size_t seed) noexcept
+{
+ // by *choice*, we're not including d->legacyKey_ in the hash -- it's
+ // already partially encoded in the key
+ return qHashMulti(seed, ipcKey.key, ipcKey.type());
+}
/*!
\fn bool QNativeIpcKey::operator==(const QNativeIpcKey &lhs, const QNativeIpcKey &rhs) noexcept
@@ -462,9 +522,9 @@ void QNativeIpcKey::setType_internal(Type)
Returns true if the \a lhs and \a rhs objects hold the same (or different) contents.
*/
-int QNativeIpcKey::compare_internal(const QNativeIpcKey &, const QNativeIpcKey &) noexcept
+int QNativeIpcKey::compare_internal(const QNativeIpcKey &lhs, const QNativeIpcKey &rhs) noexcept
{
- Q_UNREACHABLE_RETURN(0);
+ return (QNativeIpcKeyPrivate::legacyKey(lhs) == QNativeIpcKeyPrivate::legacyKey(rhs)) ? 0 : 1;
}
/*!
@@ -479,28 +539,27 @@ int QNativeIpcKey::compare_internal(const QNativeIpcKey &, const QNativeIpcKey &
*/
QString QNativeIpcKey::toString() const
{
- Q_ASSERT(!isSlowPath());
- QString prefix = typeToString(typeAndFlags.type);
+ QString prefix = typeToString(type());
if (prefix.isEmpty()) {
Q_ASSERT(prefix.isNull());
return prefix;
}
- prefix += u':';
QString copy = nativeKey();
copy.replace(u'%', "%25"_L1);
if (copy.startsWith("//"_L1))
copy.replace(0, 2, u"/%2F"_s); // ensure it's parsed as a URL path
- const ushort recodeActions[] = {
- '\\' | 0, // decode
- '?' | 0x200, // encode
- '#' | 0x200, // encode
- 0
- };
- if (!qt_urlRecode(prefix, copy, QUrl::DecodeReserved, recodeActions))
- prefix += copy;
- return prefix;
+ QUrl u;
+ u.setScheme(prefix);
+ u.setPath(copy, QUrl::TolerantMode);
+ if (isSlowPath()) {
+ QUrlQuery q;
+ if (!d->legacyKey_.isEmpty())
+ q.addQueryItem(u"legacyKey"_s, QString(d->legacyKey_).replace(u'%', "%25"_L1));
+ u.setQuery(q);
+ }
+ return u.toString(QUrl::DecodeReserved);
}
/*!
@@ -515,14 +574,11 @@ QString QNativeIpcKey::toString() const
*/
QNativeIpcKey QNativeIpcKey::fromString(const QString &text)
{
- // this duplicates QUrlPrivate::parse a little
+ QUrl u(text, QUrl::TolerantMode);
Type invalidType = {};
- qsizetype colon = text.indexOf(u':');
- if (colon < 0)
- return QNativeIpcKey(invalidType);
-
- Type type = stringToType(QStringView(text).left(colon));
- if (type == invalidType)
+ Type type = stringToType(u.scheme());
+ if (type == invalidType || !u.isValid() || !u.userInfo().isEmpty() || !u.host().isEmpty()
+ || u.port() != -1)
return QNativeIpcKey(invalidType);
QNativeIpcKey result(QString(), type);
@@ -530,20 +586,20 @@ QNativeIpcKey QNativeIpcKey::fromString(const QString &text)
return QNativeIpcKey(invalidType);
// decode the payload
- QStringView payload = QStringView(text).sliced(colon + 1);
- if (qsizetype pos = payload.indexOf(u'?'); pos >= 0)
- payload.truncate(pos);
- if (qsizetype pos = payload.indexOf(u'#'); pos >= 0)
- payload.truncate(pos);
-
- // qt_urlRecode requires a two-step decoding for non-ASCII content
- QString nativeKey, intermediate;
- if (qt_urlRecode(intermediate, payload, QUrl::PrettyDecoded))
- payload = intermediate;
- if (!qt_urlRecode(nativeKey, payload, QUrl::FullyDecoded))
- nativeKey = payload.toString();
-
- result.setNativeKey(nativeKey);
+ result.setNativeKey(u.path());
+
+ if (u.hasQuery()) {
+ const QList items = QUrlQuery(u).queryItems();
+ for (const auto &item : items) {
+ if (item.first == u"legacyKey"_s) {
+ QString legacyKey = QUrl::fromPercentEncoding(item.second.toUtf8());
+ QNativeIpcKeyPrivate::setLegacyKey(result, std::move(legacyKey));
+ } else {
+ // unknown query item
+ return QNativeIpcKey(invalidType);
+ }
+ }
+ }
return result;
}
diff --git a/src/corelib/ipc/qtipccommon.h b/src/corelib/ipc/qtipccommon.h
index 7b85c43237..74f30cb6a4 100644
--- a/src/corelib/ipc/qtipccommon.h
+++ b/src/corelib/ipc/qtipccommon.h
@@ -37,27 +37,28 @@ public:
;
static Type legacyDefaultTypeForOs() noexcept;
- explicit constexpr QNativeIpcKey(Type type = DefaultTypeForOs) noexcept
- : d()
+ constexpr QNativeIpcKey() noexcept = default;
+
+ explicit constexpr QNativeIpcKey(Type type) noexcept
+ : typeAndFlags{type}
{
- typeAndFlags.type = type;
}
Q_IMPLICIT QNativeIpcKey(const QString &k, Type type = DefaultTypeForOs)
- : d(), key(k)
+ : key(k), typeAndFlags{type}
{
- typeAndFlags.type = type;
}
QNativeIpcKey(const QNativeIpcKey &other)
- : d(other.d), key(other.key)
+ : d(other.d), key(other.key), typeAndFlags(other.typeAndFlags)
{
if (isSlowPath())
copy_internal(other);
}
QNativeIpcKey(QNativeIpcKey &&other) noexcept
- : d(other.d), key(std::move(other.key))
+ : d(std::exchange(other.d, nullptr)), key(std::move(other.key)),
+ typeAndFlags(std::move(other.typeAndFlags))
{
if (isSlowPath())
move_internal(std::move(other));
@@ -71,34 +72,34 @@ public:
QNativeIpcKey &operator=(const QNativeIpcKey &other)
{
+ typeAndFlags = other.typeAndFlags;
+ key = other.key;
if (isSlowPath() || other.isSlowPath())
return assign_internal(other);
- d = other.d;
- key = other.key;
+ Q_ASSERT(!d);
return *this;
}
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QNativeIpcKey)
- void swap(QNativeIpcKey &other)
+ void swap(QNativeIpcKey &other) noexcept
{
- qt_ptr_swap(d, other.d);
+ std::swap(d, other.d);
key.swap(other.key);
+ typeAndFlags.swap(other.typeAndFlags);
}
- bool isEmpty() const
+ bool isEmpty() const noexcept
{
return key.isEmpty();
}
- bool isValid() const
+ bool isValid() const noexcept
{
return type() != Type{};
}
constexpr Type type() const noexcept
{
- if (isSlowPath())
- return type_internal();
return typeAndFlags.type;
}
@@ -110,60 +111,75 @@ public:
}
QString nativeKey() const noexcept
- { return key; }
+ {
+ return key;
+ }
void setNativeKey(const QString &newKey)
- { key = newKey; }
+ {
+ key = newKey;
+ if (isSlowPath())
+ setNativeKey_internal(newKey);
+ }
Q_CORE_EXPORT QString toString() const;
Q_CORE_EXPORT static QNativeIpcKey fromString(const QString &string);
private:
struct TypeAndFlags {
- quint16 isExtended : 1;
- Type type : 15;
- quint16 reserved;
- };
-
- // Bit 0: if set, holds a pointer (with the LSB set); if clear, holds the
- // the TypeAndFlags structure.
- union {
- QNativeIpcKeyPrivate *d = nullptr;
- TypeAndFlags typeAndFlags;
- static_assert(sizeof(typeAndFlags) <= sizeof(d));
+ Type type = DefaultTypeForOs;
+ quint16 reserved1 = {};
+ quint32 reserved2 = {};
+
+ void swap(TypeAndFlags &other) noexcept
+ {
+ std::swap(type, other.type);
+ std::swap(reserved1, other.reserved1);
+ std::swap(reserved2, other.reserved2);
+ }
+
+ friend constexpr bool operator==(const TypeAndFlags &lhs, const TypeAndFlags &rhs) noexcept
+ {
+ return lhs.type == rhs.type &&
+ lhs.reserved1 == rhs.reserved1 &&
+ lhs.reserved2 == rhs.reserved2;
+ }
};
+ QNativeIpcKeyPrivate *d = nullptr;
QString key;
+ TypeAndFlags typeAndFlags;
+ friend class QNativeIpcKeyPrivate;
constexpr bool isSlowPath() const noexcept
- { return Q_UNLIKELY(typeAndFlags.isExtended); }
+ { return Q_UNLIKELY(d); }
- friend bool operator==(const QNativeIpcKey &lhs, const QNativeIpcKey &rhs) noexcept
- {
- if (lhs.key != rhs.key)
- return false;
- if (lhs.d == rhs.d)
- return true;
- if (lhs.isSlowPath() && rhs.isSlowPath())
- return compare_internal(lhs, rhs) == 0;
- return lhs.d == rhs.d;
- }
- friend bool operator!=(const QNativeIpcKey &lhs, const QNativeIpcKey &rhs) noexcept
- {
- return !(lhs == rhs);
- }
+ friend Q_CORE_EXPORT size_t qHash(const QNativeIpcKey &ipcKey, size_t seed) noexcept;
+ friend size_t qHash(const QNativeIpcKey &ipcKey) noexcept
+ { return qHash(ipcKey, 0); }
Q_CORE_EXPORT void copy_internal(const QNativeIpcKey &other);
Q_CORE_EXPORT void move_internal(QNativeIpcKey &&other) noexcept;
Q_CORE_EXPORT QNativeIpcKey &assign_internal(const QNativeIpcKey &other);
Q_CORE_EXPORT void destroy_internal() noexcept;
- Q_DECL_PURE_FUNCTION Q_CORE_EXPORT Type type_internal() const noexcept;
Q_CORE_EXPORT void setType_internal(Type);
+ Q_CORE_EXPORT void setNativeKey_internal(const QString &);
Q_DECL_PURE_FUNCTION Q_CORE_EXPORT static int
compare_internal(const QNativeIpcKey &lhs, const QNativeIpcKey &rhs) noexcept;
#ifdef Q_OS_DARWIN
Q_DECL_CONST_FUNCTION Q_CORE_EXPORT static Type defaultTypeForOs_internal() noexcept;
#endif
+ friend bool comparesEqual(const QNativeIpcKey &lhs, const QNativeIpcKey &rhs) noexcept
+ {
+ if (!(lhs.typeAndFlags == rhs.typeAndFlags))
+ return false;
+ if (lhs.key != rhs.key)
+ return false;
+ if (lhs.d == rhs.d)
+ return true;
+ return compare_internal(lhs, rhs) == 0;
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QNativeIpcKey)
};
// not a shared type, exactly, but this works too
@@ -182,8 +198,9 @@ inline auto QNativeIpcKey::legacyDefaultTypeForOs() noexcept -> Type
#endif
}
+QT_END_NAMESPACE
+
#endif // QT_CONFIG(sharedmemory) || QT_CONFIG(systemsemaphore)
-QT_END_NAMESPACE
#endif // QNATIVEIPCKEY_H
diff --git a/src/corelib/ipc/qtipccommon_p.h b/src/corelib/ipc/qtipccommon_p.h
index bdcdaabd53..72762c5ba7 100644
--- a/src/corelib/ipc/qtipccommon_p.h
+++ b/src/corelib/ipc/qtipccommon_p.h
@@ -28,6 +28,37 @@
QT_BEGIN_NAMESPACE
+class QNativeIpcKeyPrivate
+{
+public:
+ QString legacyKey_;
+
+ static QString legacyKey(const QNativeIpcKey &key)
+ {
+ if (key.isSlowPath())
+ return key.d->legacyKey_;
+ return QString();
+ }
+ static void setLegacyKey(QNativeIpcKey &key, const QString &legacyKey)
+ {
+ QNativeIpcKeyPrivate::makeExtended(key)->legacyKey_ = legacyKey;
+ }
+ static void setNativeAndLegacyKeys(QNativeIpcKey &key, const QString &nativeKey,
+ const QString &legacyKey)
+ {
+ key.setNativeKey(nativeKey);
+ setLegacyKey(key, legacyKey);
+ }
+
+private:
+ static QNativeIpcKeyPrivate *makeExtended(QNativeIpcKey &key)
+ {
+ if (!key.isSlowPath())
+ key.d = new QNativeIpcKeyPrivate;
+ return key.d;
+ }
+};
+
namespace QtIpcCommon {
enum class IpcType {
SharedMemory,
@@ -113,10 +144,8 @@ public:
}
};
-Q_AUTOTEST_EXPORT QString
-legacyPlatformSafeKey(const QString &key, IpcType ipcType,
- QNativeIpcKey::Type type = QNativeIpcKey::legacyDefaultTypeForOs());
-Q_AUTOTEST_EXPORT QString platformSafeKey(const QString &key, IpcType ipcType, QNativeIpcKey::Type type);
+QNativeIpcKey legacyPlatformSafeKey(const QString &key, IpcType ipcType, QNativeIpcKey::Type type);
+QNativeIpcKey platformSafeKey(const QString &key, IpcType ipcType, QNativeIpcKey::Type type);
#ifdef Q_OS_UNIX
// Convenience function to create the file if needed
diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp
index aa3fc82b6e..cd29f2fcc2 100644
--- a/src/corelib/itemmodels/qabstractitemmodel.cpp
+++ b/src/corelib/itemmodels/qabstractitemmodel.cpp
@@ -19,6 +19,8 @@
#include <qdatetime.h>
#include <qloggingcategory.h>
+#include <functional>
+
#include <limits.h>
QT_BEGIN_NAMESPACE
@@ -210,7 +212,7 @@ void QPersistentModelIndexData::destroy(QPersistentModelIndexData *data)
*/
/*!
- \fn template <typename Container> QModelRoleDataSpan::QModelRoleDataSpan(Container &c) noexcept
+ \fn template <typename Container, QModelRoleDataSpan::if_compatible_container<Container> = true> QModelRoleDataSpan::QModelRoleDataSpan(Container &c) noexcept
Constructs an QModelRoleDataSpan spanning over the container \a c,
which can be any contiguous container of QModelRoleData objects.
@@ -380,7 +382,7 @@ QPersistentModelIndex::~QPersistentModelIndex()
model index are used when comparing with another persistent model index.
*/
-bool QPersistentModelIndex::operator==(const QPersistentModelIndex &other) const
+bool QPersistentModelIndex::operator==(const QPersistentModelIndex &other) const noexcept
{
if (d && other.d)
return d->index == other.d->index;
@@ -397,12 +399,12 @@ bool QPersistentModelIndex::operator==(const QPersistentModelIndex &other) const
model index are used when comparing with another persistent model index.
*/
-bool QPersistentModelIndex::operator<(const QPersistentModelIndex &other) const
+bool QPersistentModelIndex::operator<(const QPersistentModelIndex &other) const noexcept
{
if (d && other.d)
return d->index < other.d->index;
- return d < other.d;
+ return std::less<>{}(d, other.d);
}
/*!
@@ -475,7 +477,7 @@ QPersistentModelIndex::operator QModelIndex() const
model index are used when comparing with another model index.
*/
-bool QPersistentModelIndex::operator==(const QModelIndex &other) const
+bool QPersistentModelIndex::operator==(const QModelIndex &other) const noexcept
{
if (d)
return d->index == other;
@@ -489,7 +491,7 @@ bool QPersistentModelIndex::operator==(const QModelIndex &other) const
location as the \a other model index; otherwise returns \c{false}.
*/
-bool QPersistentModelIndex::operator!=(const QModelIndex &other) const
+bool QPersistentModelIndex::operator!=(const QModelIndex &other) const noexcept
{
if (d)
return d->index != other;
@@ -684,6 +686,7 @@ QDebug operator<<(QDebug dbg, const QPersistentModelIndex &idx)
class QEmptyItemModel : public QAbstractItemModel
{
+ Q_OBJECT
public:
explicit QEmptyItemModel(QObject *parent = nullptr) : QAbstractItemModel(parent) {}
QModelIndex index(int, int, const QModelIndex &) const override { return QModelIndex(); }
@@ -1497,10 +1500,12 @@ void QAbstractItemModel::resetInternalData()
rows to the model, \l{QAbstractItemModel::}{beginInsertRows()} and
\l{QAbstractItemModel::}{endInsertRows()} must be called.
+ \include models.qdocinc {thread-safety-section1}{QAbstractItemModel}
+
\sa {Model Classes}, {Model Subclassing Reference}, QModelIndex,
QAbstractItemView, {Using drag and drop with item views},
- {Simple DOM Model Example}, {Simple Tree Model Example},
- {Editable Tree Model Example}, {Fetch More Example}
+ {Simple Tree Model Example}, {Editable Tree Model Example},
+ {Fetch More Example}
*/
/*!
@@ -1739,7 +1744,13 @@ QAbstractItemModel::~QAbstractItemModel()
For example:
- \snippet ../widgets/itemviews/simpledommodel/dommodel.cpp 2
+ \code
+ int MyModel::columnCount(const QModelIndex &parent) const
+ {
+ Q_UNUSED(parent);
+ return 3;
+ }
+ \endcode
\note When implementing a table based model, columnCount() should return 0
when the parent is valid.
@@ -3728,10 +3739,9 @@ void QAbstractItemModel::multiData(const QModelIndex &index, QModelRoleDataSpan
\note Some general guidelines for subclassing models are available in the
\l{Model Subclassing Reference}.
- \note
+ \include models.qdocinc {thread-safety-section1}{QAbstractTableModel}
- \sa {Model Classes}, QAbstractItemModel, QAbstractListModel,
- {Pixelator Example}
+ \sa {Model Classes}, QAbstractItemModel, QAbstractListModel
*/
/*!
@@ -3882,7 +3892,7 @@ Qt::ItemFlags QAbstractTableModel::flags(const QModelIndex &index) const
\l{Model Subclassing Reference}.
\sa {Model Classes}, {Model Subclassing Reference}, QAbstractItemView,
- QAbstractTableModel, {Item Views Puzzle Example}
+ QAbstractTableModel
*/
/*!
@@ -4160,3 +4170,4 @@ void QAbstractItemModelPrivate::Persistent::insertMultiAtEnd(const QModelIndex&
QT_END_NAMESPACE
#include "moc_qabstractitemmodel.cpp"
+#include "qabstractitemmodel.moc"
diff --git a/src/corelib/itemmodels/qabstractitemmodel.h b/src/corelib/itemmodels/qabstractitemmodel.h
index e56412241a..8f22f14989 100644
--- a/src/corelib/itemmodels/qabstractitemmodel.h
+++ b/src/corelib/itemmodels/qabstractitemmodel.h
@@ -178,17 +178,17 @@ public:
QPersistentModelIndex(const QModelIndex &index);
QPersistentModelIndex(const QPersistentModelIndex &other);
~QPersistentModelIndex();
- bool operator<(const QPersistentModelIndex &other) const;
- bool operator==(const QPersistentModelIndex &other) const;
- inline bool operator!=(const QPersistentModelIndex &other) const
+ bool operator<(const QPersistentModelIndex &other) const noexcept;
+ bool operator==(const QPersistentModelIndex &other) const noexcept;
+ inline bool operator!=(const QPersistentModelIndex &other) const noexcept
{ return !operator==(other); }
QPersistentModelIndex &operator=(const QPersistentModelIndex &other);
inline QPersistentModelIndex(QPersistentModelIndex &&other) noexcept
: d(std::exchange(other.d, nullptr)) {}
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QPersistentModelIndex)
void swap(QPersistentModelIndex &other) noexcept { qt_ptr_swap(d, other.d); }
- bool operator==(const QModelIndex &other) const;
- bool operator!=(const QModelIndex &other) const;
+ bool operator==(const QModelIndex &other) const noexcept;
+ bool operator!=(const QModelIndex &other) const noexcept;
QPersistentModelIndex &operator=(const QModelIndex &other);
operator QModelIndex() const;
int row() const;
@@ -499,7 +499,13 @@ inline Qt::ItemFlags QModelIndex::flags() const
{ return m ? m->flags(*this) : Qt::ItemFlags(); }
inline size_t qHash(const QModelIndex &index, size_t seed = 0) noexcept
-{ return size_t((size_t(index.row()) << 4) + size_t(index.column()) + index.internalId()) ^ seed; }
+{
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+ return qHashMulti(seed, index.row(), index.column(), index.internalId());
+#else
+ return size_t((size_t(index.row()) << 4) + size_t(index.column()) + index.internalId()) ^ seed;
+#endif
+}
QT_END_NAMESPACE
diff --git a/src/corelib/itemmodels/qabstractproxymodel.cpp b/src/corelib/itemmodels/qabstractproxymodel.cpp
index c0321ee282..abdeefb4da 100644
--- a/src/corelib/itemmodels/qabstractproxymodel.cpp
+++ b/src/corelib/itemmodels/qabstractproxymodel.cpp
@@ -55,6 +55,41 @@ void QAbstractProxyModelPrivate::_q_sourceModelDestroyed()
model = QAbstractItemModelPrivate::staticEmptyModel();
}
+void QAbstractProxyModelPrivate::emitHeaderDataChanged()
+{
+ Q_Q(QAbstractProxyModel);
+
+ if (updateHorizontalHeader) {
+ if (auto columnCount = q->columnCount(); columnCount > 0)
+ emit q->headerDataChanged(Qt::Horizontal, 0, columnCount - 1);
+ }
+
+ if (updateVerticalHeader) {
+ if (auto rowCount = q->rowCount(); rowCount > 0)
+ emit q->headerDataChanged(Qt::Vertical, 0, rowCount - 1);
+ }
+
+ updateHorizontalHeader = false;
+ updateVerticalHeader = false;
+}
+
+void QAbstractProxyModelPrivate::scheduleHeaderUpdate(Qt::Orientation orientation)
+{
+ const bool isUpdateScheduled = updateHorizontalHeader || updateVerticalHeader;
+
+ if (orientation == Qt::Horizontal && !updateHorizontalHeader)
+ updateHorizontalHeader = true;
+ else if (orientation == Qt::Vertical && !updateVerticalHeader)
+ updateVerticalHeader = true;
+ else
+ return;
+
+ if (!isUpdateScheduled) {
+ Q_Q(QAbstractProxyModel);
+ QMetaObject::invokeMethod(q, [this]() { emitHeaderDataChanged(); }, Qt::QueuedConnection);
+ }
+}
+
void QAbstractProxyModelPrivate::_q_sourceModelRowsAboutToBeInserted(const QModelIndex &parent, int, int)
{
if (parent.isValid())
@@ -66,25 +101,16 @@ void QAbstractProxyModelPrivate::_q_sourceModelRowsInserted(const QModelIndex &p
{
if (parent.isValid())
return;
- if (sourceHadZeroRows) {
- Q_Q(QAbstractProxyModel);
- const int columnCount = q->columnCount();
- if (columnCount > 0)
- emit q->headerDataChanged(Qt::Horizontal, 0, columnCount - 1);
- }
+ if (sourceHadZeroRows)
+ scheduleHeaderUpdate(Qt::Horizontal);
}
-
void QAbstractProxyModelPrivate::_q_sourceModelRowsRemoved(const QModelIndex &parent, int, int)
{
if (parent.isValid())
return;
- if (model->rowCount() == 0) {
- Q_Q(QAbstractProxyModel);
- const int columnCount = q->columnCount();
- if (columnCount > 0)
- emit q->headerDataChanged(Qt::Horizontal, 0, columnCount - 1);
- }
+ if (model->rowCount() == 0)
+ scheduleHeaderUpdate(Qt::Horizontal);
}
void QAbstractProxyModelPrivate::_q_sourceModelColumnsAboutToBeInserted(const QModelIndex &parent, int, int)
@@ -98,24 +124,16 @@ void QAbstractProxyModelPrivate::_q_sourceModelColumnsInserted(const QModelIndex
{
if (parent.isValid())
return;
- if (sourceHadZeroColumns) {
- Q_Q(QAbstractProxyModel);
- const int rowCount = q->rowCount();
- if (rowCount > 0)
- emit q->headerDataChanged(Qt::Vertical, 0, rowCount - 1);
- }
+ if (sourceHadZeroColumns)
+ scheduleHeaderUpdate(Qt::Vertical);
}
void QAbstractProxyModelPrivate::_q_sourceModelColumnsRemoved(const QModelIndex &parent, int, int)
{
if (parent.isValid())
return;
- if (model->columnCount() == 0) {
- Q_Q(QAbstractProxyModel);
- const int rowCount = q->rowCount();
- if (rowCount > 0)
- emit q->headerDataChanged(Qt::Vertical, 0, rowCount - 1);
- }
+ if (model->columnCount() == 0)
+ scheduleHeaderUpdate(Qt::Vertical);
}
/*!
@@ -159,7 +177,8 @@ void QAbstractProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
d->model.removeBindingUnlessInWrapper();
// Special case to handle nullptr models. Otherwise we will have unwanted
// notifications.
- if (!sourceModel && d->model == QAbstractItemModelPrivate::staticEmptyModel())
+ const QAbstractItemModel *currentModel = d->model.valueBypassingBindings();
+ if (!sourceModel && currentModel == QAbstractItemModelPrivate::staticEmptyModel())
return;
static const struct {
const char *signalName;
@@ -176,16 +195,16 @@ void QAbstractProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
// clang-format on
};
- if (sourceModel != d->model) {
- if (d->model) {
+ if (sourceModel != currentModel) {
+ if (currentModel) {
for (const auto &c : connectionTable)
- disconnect(d->model, c.signalName, this, c.slotName);
+ disconnect(currentModel, c.signalName, this, c.slotName);
}
if (sourceModel) {
d->model.setValueBypassingBindings(sourceModel);
for (const auto &c : connectionTable)
- connect(d->model, c.signalName, this, c.slotName);
+ connect(sourceModel, c.signalName, this, c.slotName);
} else {
d->model.setValueBypassingBindings(QAbstractItemModelPrivate::staticEmptyModel());
}
diff --git a/src/corelib/itemmodels/qabstractproxymodel_p.h b/src/corelib/itemmodels/qabstractproxymodel_p.h
index 678ec4804f..d33666d00b 100644
--- a/src/corelib/itemmodels/qabstractproxymodel_p.h
+++ b/src/corelib/itemmodels/qabstractproxymodel_p.h
@@ -16,6 +16,7 @@
//
//
+#include "qabstractproxymodel.h"
#include "private/qabstractitemmodel_p.h"
#include "private/qproperty_p.h"
@@ -30,7 +31,9 @@ public:
QAbstractProxyModelPrivate()
: QAbstractItemModelPrivate(),
sourceHadZeroRows(false),
- sourceHadZeroColumns(false)
+ sourceHadZeroColumns(false),
+ updateVerticalHeader(false),
+ updateHorizontalHeader(false)
{}
void setModelForwarder(QAbstractItemModel *sourceModel)
{
@@ -57,8 +60,13 @@ public:
void mapDropCoordinatesToSource(int row, int column, const QModelIndex &parent,
int *source_row, int *source_column, QModelIndex *source_parent) const;
+ void scheduleHeaderUpdate(Qt::Orientation orientation);
+ void emitHeaderDataChanged();
+
unsigned int sourceHadZeroRows : 1;
unsigned int sourceHadZeroColumns : 1;
+ unsigned int updateVerticalHeader : 1;
+ unsigned int updateHorizontalHeader : 1;
};
QT_END_NAMESPACE
diff --git a/src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp b/src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp
index 44cf28b47a..3a49d37cff 100644
--- a/src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp
+++ b/src/corelib/itemmodels/qconcatenatetablesproxymodel.cpp
@@ -26,26 +26,43 @@ public:
};
SourceModelForRowResult sourceModelForRow(int row) const;
- void _q_slotRowsAboutToBeInserted(const QModelIndex &, int start, int end);
- void _q_slotRowsInserted(const QModelIndex &, int start, int end);
- void _q_slotRowsAboutToBeRemoved(const QModelIndex &, int start, int end);
- void _q_slotRowsRemoved(const QModelIndex &, int start, int end);
- void _q_slotColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end);
- void _q_slotColumnsInserted(const QModelIndex &parent, int, int);
- void _q_slotColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
- void _q_slotColumnsRemoved(const QModelIndex &parent, int, int);
- void _q_slotDataChanged(const QModelIndex &from, const QModelIndex &to, const QList<int> &roles);
- void _q_slotSourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint);
- void _q_slotSourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint);
- void _q_slotModelAboutToBeReset();
- void _q_slotModelReset();
+ void slotRowsAboutToBeInserted(const QModelIndex &, int start, int end);
+ void slotRowsInserted(const QModelIndex &, int start, int end);
+ void slotRowsAboutToBeRemoved(const QModelIndex &, int start, int end);
+ void slotRowsRemoved(const QModelIndex &, int start, int end);
+ void slotColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end);
+ void slotColumnsInserted(const QModelIndex &parent, int, int);
+ void slotColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
+ void slotColumnsRemoved(const QModelIndex &parent, int, int);
+ void slotDataChanged(const QModelIndex &from, const QModelIndex &to, const QList<int> &roles);
+ void slotSourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint);
+ void slotSourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint);
+ void slotModelAboutToBeReset();
+ void slotModelReset();
int columnCountAfterChange(const QAbstractItemModel *model, int newCount) const;
int calculatedColumnCount() const;
void updateColumnCount();
bool mapDropCoordinatesToSource(int row, int column, const QModelIndex &parent,
int *sourceRow, int *sourceColumn, QModelIndex *sourceParent, QAbstractItemModel **sourceModel) const;
- QList<QAbstractItemModel *> m_models;
+ struct ModelInfo {
+ using ConnArray = std::array<QMetaObject::Connection, 13>;
+ ModelInfo(QAbstractItemModel *m, ConnArray &&con)
+ : model(m), connections(std::move(con)) {}
+ QAbstractItemModel *model = nullptr;
+ ConnArray connections;
+ };
+ QList<ModelInfo> m_models;
+
+ QList<ModelInfo>::const_iterator findSourceModel(const QAbstractItemModel *m) const
+ {
+ auto byModelPtr = [m](const auto &modInfo) { return modInfo.model == m; };
+ return std::find_if(m_models.cbegin(), m_models.cend(), byModelPtr);
+ }
+
+ bool containsSourceModel(const QAbstractItemModel *m) const
+ { return findSourceModel(m) != m_models.cend(); }
+
int m_rowCount; // have to maintain it here since we can't compute during model destruction
int m_columnCount;
@@ -116,7 +133,7 @@ QModelIndex QConcatenateTablesProxyModel::mapFromSource(const QModelIndex &sourc
if (!sourceIndex.isValid())
return QModelIndex();
const QAbstractItemModel *sourceModel = sourceIndex.model();
- if (!d->m_models.contains(const_cast<QAbstractItemModel *>(sourceModel))) {
+ if (!d->containsSourceModel(sourceModel)) {
qWarning("QConcatenateTablesProxyModel: index from wrong model passed to mapFromSource");
Q_ASSERT(!"QConcatenateTablesProxyModel: index from wrong model passed to mapFromSource");
return QModelIndex();
@@ -208,7 +225,7 @@ Qt::ItemFlags QConcatenateTablesProxyModel::flags(const QModelIndex &index) cons
return Qt::NoItemFlags;
Q_ASSERT(checkIndex(index));
if (!index.isValid())
- return d->m_models.at(0)->flags(index);
+ return d->m_models.at(0).model->flags(index);
const QModelIndex sourceIndex = mapToSource(index);
Q_ASSERT(sourceIndex.isValid());
return sourceIndex.model()->flags(sourceIndex);
@@ -226,7 +243,7 @@ QVariant QConcatenateTablesProxyModel::headerData(int section, Qt::Orientation o
return QVariant();
switch (orientation) {
case Qt::Horizontal:
- return d->m_models.at(0)->headerData(section, orientation, role);
+ return d->m_models.at(0).model->headerData(section, orientation, role);
case Qt::Vertical: {
const auto result = d->sourceModelForRow(section);
Q_ASSERT(result.sourceModel);
@@ -292,7 +309,7 @@ QStringList QConcatenateTablesProxyModel::mimeTypes() const
Q_D(const QConcatenateTablesProxyModel);
if (d->m_models.isEmpty())
return QStringList();
- return d->m_models.at(0)->mimeTypes();
+ return d->m_models.at(0).model->mimeTypes();
}
/*!
@@ -334,7 +351,7 @@ bool QConcatenateTablesProxyModelPrivate::mapDropCoordinatesToSource(int row, in
// Drop after the last item
if (row == -1 || row == m_rowCount) {
*sourceRow = -1;
- *sourceModel = m_models.constLast();
+ *sourceModel = m_models.constLast().model;
return true;
}
// Drop between toplevel items
@@ -420,7 +437,11 @@ QSize QConcatenateTablesProxyModel::span(const QModelIndex &index) const
QList<QAbstractItemModel *> QConcatenateTablesProxyModel::sourceModels() const
{
Q_D(const QConcatenateTablesProxyModel);
- return d->m_models.toList();
+ QList<QAbstractItemModel *> ret;
+ ret.reserve(d->m_models.size());
+ for (const auto &info : d->m_models)
+ ret.push_back(info.model);
+ return ret;
}
/*!
@@ -434,30 +455,42 @@ void QConcatenateTablesProxyModel::addSourceModel(QAbstractItemModel *sourceMode
{
Q_D(QConcatenateTablesProxyModel);
Q_ASSERT(sourceModel);
- Q_ASSERT(!d->m_models.contains(sourceModel));
- connect(sourceModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QList<int>)), this, SLOT(_q_slotDataChanged(QModelIndex,QModelIndex,QList<int>)));
- connect(sourceModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(_q_slotRowsInserted(QModelIndex,int,int)));
- connect(sourceModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(_q_slotRowsRemoved(QModelIndex,int,int)));
- connect(sourceModel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(_q_slotRowsAboutToBeInserted(QModelIndex,int,int)));
- connect(sourceModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(_q_slotRowsAboutToBeRemoved(QModelIndex,int,int)));
-
- connect(sourceModel, SIGNAL(columnsInserted(QModelIndex,int,int)), this, SLOT(_q_slotColumnsInserted(QModelIndex,int,int)));
- connect(sourceModel, SIGNAL(columnsRemoved(QModelIndex,int,int)), this, SLOT(_q_slotColumnsRemoved(QModelIndex,int,int)));
- connect(sourceModel, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(_q_slotColumnsAboutToBeInserted(QModelIndex,int,int)));
- connect(sourceModel, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(_q_slotColumnsAboutToBeRemoved(QModelIndex,int,int)));
-
- connect(sourceModel, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>, QAbstractItemModel::LayoutChangeHint)),
- this, SLOT(_q_slotSourceLayoutAboutToBeChanged(QList<QPersistentModelIndex>, QAbstractItemModel::LayoutChangeHint)));
- connect(sourceModel, SIGNAL(layoutChanged(QList<QPersistentModelIndex>, QAbstractItemModel::LayoutChangeHint)),
- this, SLOT(_q_slotSourceLayoutChanged(QList<QPersistentModelIndex>, QAbstractItemModel::LayoutChangeHint)));
- connect(sourceModel, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_slotModelAboutToBeReset()));
- connect(sourceModel, SIGNAL(modelReset()), this, SLOT(_q_slotModelReset()));
+ Q_ASSERT(!d->containsSourceModel(sourceModel));
const int newRows = sourceModel->rowCount();
if (newRows > 0)
beginInsertRows(QModelIndex(), d->m_rowCount, d->m_rowCount + newRows - 1);
d->m_rowCount += newRows;
- d->m_models.append(sourceModel);
+ d->m_models.emplace_back(sourceModel, std::array{
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::dataChanged,
+ d, &QConcatenateTablesProxyModelPrivate::slotDataChanged),
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::rowsInserted,
+ d, &QConcatenateTablesProxyModelPrivate::slotRowsInserted),
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::rowsRemoved,
+ d, &QConcatenateTablesProxyModelPrivate::slotRowsRemoved),
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::rowsAboutToBeInserted,
+ d, &QConcatenateTablesProxyModelPrivate::slotRowsAboutToBeInserted),
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved,
+ d, &QConcatenateTablesProxyModelPrivate::slotRowsAboutToBeRemoved),
+
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::columnsInserted,
+ d, &QConcatenateTablesProxyModelPrivate::slotColumnsInserted),
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::columnsRemoved,
+ d, &QConcatenateTablesProxyModelPrivate::slotColumnsRemoved),
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::columnsAboutToBeInserted,
+ d, &QConcatenateTablesProxyModelPrivate::slotColumnsAboutToBeInserted),
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::columnsAboutToBeRemoved,
+ d, &QConcatenateTablesProxyModelPrivate::slotColumnsAboutToBeRemoved),
+
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::layoutAboutToBeChanged,
+ d, &QConcatenateTablesProxyModelPrivate::slotSourceLayoutAboutToBeChanged),
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::layoutChanged,
+ d, &QConcatenateTablesProxyModelPrivate::slotSourceLayoutChanged),
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::modelAboutToBeReset,
+ d, &QConcatenateTablesProxyModelPrivate::slotModelAboutToBeReset),
+ QObjectPrivate::connect(sourceModel, &QAbstractItemModel::modelReset,
+ d, &QConcatenateTablesProxyModelPrivate::slotModelReset),
+ });
if (newRows > 0)
endInsertRows();
@@ -472,15 +505,18 @@ void QConcatenateTablesProxyModel::addSourceModel(QAbstractItemModel *sourceMode
void QConcatenateTablesProxyModel::removeSourceModel(QAbstractItemModel *sourceModel)
{
Q_D(QConcatenateTablesProxyModel);
- Q_ASSERT(d->m_models.contains(sourceModel));
- disconnect(sourceModel, nullptr, this, nullptr);
+
+ auto it = d->findSourceModel(sourceModel);
+ Q_ASSERT(it != d->m_models.cend());
+ for (auto &c : it->connections)
+ disconnect(c);
const int rowsRemoved = sourceModel->rowCount();
const int rowsPrior = d->computeRowsPrior(sourceModel); // location of removed section
if (rowsRemoved > 0)
beginRemoveRows(QModelIndex(), rowsPrior, rowsPrior + rowsRemoved - 1);
- d->m_models.removeOne(sourceModel);
+ d->m_models.erase(it);
d->m_rowCount -= rowsRemoved;
if (rowsRemoved > 0)
endRemoveRows();
@@ -488,7 +524,8 @@ void QConcatenateTablesProxyModel::removeSourceModel(QAbstractItemModel *sourceM
d->updateColumnCount();
}
-void QConcatenateTablesProxyModelPrivate::_q_slotRowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
+void QConcatenateTablesProxyModelPrivate::slotRowsAboutToBeInserted(const QModelIndex &parent,
+ int start, int end)
{
Q_Q(QConcatenateTablesProxyModel);
if (parent.isValid()) // not supported, the proxy is a flat model
@@ -498,7 +535,8 @@ void QConcatenateTablesProxyModelPrivate::_q_slotRowsAboutToBeInserted(const QMo
q->beginInsertRows(QModelIndex(), rowsPrior + start, rowsPrior + end);
}
-void QConcatenateTablesProxyModelPrivate::_q_slotRowsInserted(const QModelIndex &parent, int start, int end)
+void QConcatenateTablesProxyModelPrivate::slotRowsInserted(const QModelIndex &parent, int start,
+ int end)
{
Q_Q(QConcatenateTablesProxyModel);
if (parent.isValid()) // flat model
@@ -507,7 +545,8 @@ void QConcatenateTablesProxyModelPrivate::_q_slotRowsInserted(const QModelIndex
q->endInsertRows();
}
-void QConcatenateTablesProxyModelPrivate::_q_slotRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
+void QConcatenateTablesProxyModelPrivate::slotRowsAboutToBeRemoved(const QModelIndex &parent,
+ int start, int end)
{
Q_Q(QConcatenateTablesProxyModel);
if (parent.isValid()) // flat model
@@ -517,7 +556,7 @@ void QConcatenateTablesProxyModelPrivate::_q_slotRowsAboutToBeRemoved(const QMod
q->beginRemoveRows(QModelIndex(), rowsPrior + start, rowsPrior + end);
}
-void QConcatenateTablesProxyModelPrivate::_q_slotRowsRemoved(const QModelIndex &parent, int start, int end)
+void QConcatenateTablesProxyModelPrivate::slotRowsRemoved(const QModelIndex &parent, int start, int end)
{
Q_Q(QConcatenateTablesProxyModel);
if (parent.isValid()) // flat model
@@ -526,7 +565,8 @@ void QConcatenateTablesProxyModelPrivate::_q_slotRowsRemoved(const QModelIndex &
q->endRemoveRows();
}
-void QConcatenateTablesProxyModelPrivate::_q_slotColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end)
+void QConcatenateTablesProxyModelPrivate::slotColumnsAboutToBeInserted(const QModelIndex &parent,
+ int start, int end)
{
Q_Q(QConcatenateTablesProxyModel);
if (parent.isValid()) // flat model
@@ -542,7 +582,8 @@ void QConcatenateTablesProxyModelPrivate::_q_slotColumnsAboutToBeInserted(const
m_newColumnCount = newColCount;
}
-void QConcatenateTablesProxyModelPrivate::_q_slotColumnsInserted(const QModelIndex &parent, int start, int end)
+void QConcatenateTablesProxyModelPrivate::slotColumnsInserted(const QModelIndex &parent, int start,
+ int end)
{
Q_UNUSED(start);
Q_UNUSED(end);
@@ -555,7 +596,8 @@ void QConcatenateTablesProxyModelPrivate::_q_slotColumnsInserted(const QModelInd
}
}
-void QConcatenateTablesProxyModelPrivate::_q_slotColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
+void QConcatenateTablesProxyModelPrivate::slotColumnsAboutToBeRemoved(const QModelIndex &parent,
+ int start, int end)
{
Q_Q(QConcatenateTablesProxyModel);
if (parent.isValid()) // flat model
@@ -569,7 +611,8 @@ void QConcatenateTablesProxyModelPrivate::_q_slotColumnsAboutToBeRemoved(const Q
m_newColumnCount = newColCount;
}
-void QConcatenateTablesProxyModelPrivate::_q_slotColumnsRemoved(const QModelIndex &parent, int start, int end)
+void QConcatenateTablesProxyModelPrivate::slotColumnsRemoved(const QModelIndex &parent, int start,
+ int end)
{
Q_Q(QConcatenateTablesProxyModel);
Q_UNUSED(start);
@@ -582,7 +625,9 @@ void QConcatenateTablesProxyModelPrivate::_q_slotColumnsRemoved(const QModelInde
}
}
-void QConcatenateTablesProxyModelPrivate::_q_slotDataChanged(const QModelIndex &from, const QModelIndex &to, const QList<int> &roles)
+void QConcatenateTablesProxyModelPrivate::slotDataChanged(const QModelIndex &from,
+ const QModelIndex &to,
+ const QList<int> &roles)
{
Q_Q(QConcatenateTablesProxyModel);
Q_ASSERT(from.isValid());
@@ -599,7 +644,8 @@ void QConcatenateTablesProxyModelPrivate::_q_slotDataChanged(const QModelIndex &
emit q->dataChanged(myFrom, myTo, roles);
}
-void QConcatenateTablesProxyModelPrivate::_q_slotSourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint)
+void QConcatenateTablesProxyModelPrivate::slotSourceLayoutAboutToBeChanged(
+ const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint)
{
Q_Q(QConcatenateTablesProxyModel);
@@ -621,7 +667,8 @@ void QConcatenateTablesProxyModelPrivate::_q_slotSourceLayoutAboutToBeChanged(co
}
}
-void QConcatenateTablesProxyModelPrivate::_q_slotSourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint)
+void QConcatenateTablesProxyModelPrivate::slotSourceLayoutChanged(
+ const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint)
{
Q_Q(QConcatenateTablesProxyModel);
if (!sourceParents.isEmpty() && !sourceParents.contains(QModelIndex()))
@@ -638,20 +685,20 @@ void QConcatenateTablesProxyModelPrivate::_q_slotSourceLayoutChanged(const QList
emit q->layoutChanged({}, hint);
}
-void QConcatenateTablesProxyModelPrivate::_q_slotModelAboutToBeReset()
+void QConcatenateTablesProxyModelPrivate::slotModelAboutToBeReset()
{
Q_Q(QConcatenateTablesProxyModel);
- Q_ASSERT(m_models.contains(const_cast<QAbstractItemModel *>(static_cast<const QAbstractItemModel *>(q->sender()))));
+ Q_ASSERT(containsSourceModel(static_cast<QAbstractItemModel *>(q->sender())));
q->beginResetModel();
// A reset might reduce both rowCount and columnCount, and we can't notify of both at the same time,
// and notifying of one after the other leaves an intermediary invalid situation.
// So the only safe choice is to forward it as a full reset.
}
-void QConcatenateTablesProxyModelPrivate::_q_slotModelReset()
+void QConcatenateTablesProxyModelPrivate::slotModelReset()
{
Q_Q(QConcatenateTablesProxyModel);
- Q_ASSERT(m_models.contains(const_cast<QAbstractItemModel *>(static_cast<const QAbstractItemModel *>(q->sender()))));
+ Q_ASSERT(containsSourceModel(static_cast<QAbstractItemModel *>(q->sender())));
m_columnCount = calculatedColumnCount();
m_rowCount = computeRowsPrior(nullptr);
q->endResetModel();
@@ -662,10 +709,11 @@ int QConcatenateTablesProxyModelPrivate::calculatedColumnCount() const
if (m_models.isEmpty())
return 0;
- const auto it = std::min_element(m_models.begin(), m_models.end(), [](const QAbstractItemModel* model1, const QAbstractItemModel* model2) {
- return model1->columnCount() < model2->columnCount();
- });
- return (*it)->columnCount();
+ auto byColumnCount = [](const auto &a, const auto &b) {
+ return a.model->columnCount() < b.model->columnCount();
+ };
+ const auto it = std::min_element(m_models.begin(), m_models.end(), byColumnCount);
+ return it->model->columnCount();
}
void QConcatenateTablesProxyModelPrivate::updateColumnCount()
@@ -688,8 +736,8 @@ void QConcatenateTablesProxyModelPrivate::updateColumnCount()
int QConcatenateTablesProxyModelPrivate::columnCountAfterChange(const QAbstractItemModel *model, int newCount) const
{
int newColumnCount = 0;
- for (int i = 0; i < m_models.size(); ++i) {
- const QAbstractItemModel *mod = m_models.at(i);
+ for (qsizetype i = 0; i < m_models.size(); ++i) {
+ const QAbstractItemModel *mod = m_models.at(i).model;
const int colCount = mod == model ? newCount : mod->columnCount();
if (i == 0)
newColumnCount = colCount;
@@ -702,7 +750,7 @@ int QConcatenateTablesProxyModelPrivate::columnCountAfterChange(const QAbstractI
int QConcatenateTablesProxyModelPrivate::computeRowsPrior(const QAbstractItemModel *sourceModel) const
{
int rowsPrior = 0;
- for (const QAbstractItemModel *model : m_models) {
+ for (const auto &[model, _] : m_models) {
if (model == sourceModel)
break;
rowsPrior += model->rowCount();
@@ -714,7 +762,7 @@ QConcatenateTablesProxyModelPrivate::SourceModelForRowResult QConcatenateTablesP
{
QConcatenateTablesProxyModelPrivate::SourceModelForRowResult result;
int rowCount = 0;
- for (QAbstractItemModel *model : m_models) {
+ for (const auto &[model, _] : m_models) {
const int subRowCount = model->rowCount();
if (rowCount + subRowCount > row) {
result.sourceModel = model;
diff --git a/src/corelib/itemmodels/qconcatenatetablesproxymodel.h b/src/corelib/itemmodels/qconcatenatetablesproxymodel.h
index 3d924fb18b..9dbebd7b88 100644
--- a/src/corelib/itemmodels/qconcatenatetablesproxymodel.h
+++ b/src/corelib/itemmodels/qconcatenatetablesproxymodel.h
@@ -46,21 +46,6 @@ public:
private:
Q_DECLARE_PRIVATE(QConcatenateTablesProxyModel)
Q_DISABLE_COPY(QConcatenateTablesProxyModel)
-
- Q_PRIVATE_SLOT(d_func(), void _q_slotRowsAboutToBeInserted(const QModelIndex &, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_slotRowsInserted(const QModelIndex &, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_slotRowsAboutToBeRemoved(const QModelIndex &, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_slotRowsRemoved(const QModelIndex &, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_slotColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_slotColumnsInserted(const QModelIndex &parent, int, int))
- Q_PRIVATE_SLOT(d_func(), void _q_slotColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_slotColumnsRemoved(const QModelIndex &parent, int, int))
- Q_PRIVATE_SLOT(d_func(),
- void _q_slotDataChanged(const QModelIndex &from, const QModelIndex &to, const QList<int> &roles))
- Q_PRIVATE_SLOT(d_func(), void _q_slotSourceLayoutAboutToBeChanged(QList<QPersistentModelIndex>, QAbstractItemModel::LayoutChangeHint))
- Q_PRIVATE_SLOT(d_func(), void _q_slotSourceLayoutChanged(const QList<QPersistentModelIndex> &, QAbstractItemModel::LayoutChangeHint))
- Q_PRIVATE_SLOT(d_func(), void _q_slotModelAboutToBeReset())
- Q_PRIVATE_SLOT(d_func(), void _q_slotModelReset())
};
QT_END_NAMESPACE
diff --git a/src/corelib/itemmodels/qidentityproxymodel.cpp b/src/corelib/itemmodels/qidentityproxymodel.cpp
index cc0730d769..89fa7e5c07 100644
--- a/src/corelib/itemmodels/qidentityproxymodel.cpp
+++ b/src/corelib/itemmodels/qidentityproxymodel.cpp
@@ -290,97 +290,108 @@ void QIdentityProxyModel::setSourceModel(QAbstractItemModel* newSourceModel)
{
beginResetModel();
- if (sourceModel()) {
- disconnect(sourceModel(), SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)));
- disconnect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int)));
- disconnect(sourceModel(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
- disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int)));
- disconnect(sourceModel(), SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
- disconnect(sourceModel(), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
- disconnect(sourceModel(), SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)));
- disconnect(sourceModel(), SIGNAL(columnsInserted(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsInserted(QModelIndex,int,int)));
- disconnect(sourceModel(), SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)));
- disconnect(sourceModel(), SIGNAL(columnsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sourceColumnsRemoved(QModelIndex,int,int)));
- disconnect(sourceModel(), SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
- disconnect(sourceModel(), SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int)));
- disconnect(sourceModel(), SIGNAL(modelAboutToBeReset()),
- this, SLOT(_q_sourceModelAboutToBeReset()));
- disconnect(sourceModel(), SIGNAL(modelReset()),
- this, SLOT(_q_sourceModelReset()));
- disconnect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex,QList<int>)),
- this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex,QList<int>)));
- disconnect(sourceModel(), SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
- this, SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int)));
- disconnect(sourceModel(), SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- this, SLOT(_q_sourceLayoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
- disconnect(sourceModel(), SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- this, SLOT(_q_sourceLayoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
- }
+ Q_D(QIdentityProxyModel);
+
+ // Call QObject::disconnect() unconditionally, if there is an existing source
+ // model, it's disconnected, and if there isn't, then calling disconnect() on
+ // a default-constructed Connection does nothing
+ for (const auto &c : d->m_sourceModelConnections)
+ QObject::disconnect(c);
QAbstractProxyModel::setSourceModel(newSourceModel);
if (sourceModel()) {
- connect(sourceModel(), SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
- SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)));
- connect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)),
- SLOT(_q_sourceRowsInserted(QModelIndex,int,int)));
- connect(sourceModel(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)));
- connect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)),
- SLOT(_q_sourceRowsRemoved(QModelIndex,int,int)));
- connect(sourceModel(), SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- SLOT(_q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
- connect(sourceModel(), SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
- SLOT(_q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int)));
- connect(sourceModel(), SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
- SLOT(_q_sourceColumnsAboutToBeInserted(QModelIndex,int,int)));
- connect(sourceModel(), SIGNAL(columnsInserted(QModelIndex,int,int)),
- SLOT(_q_sourceColumnsInserted(QModelIndex,int,int)));
- connect(sourceModel(), SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
- SLOT(_q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int)));
- connect(sourceModel(), SIGNAL(columnsRemoved(QModelIndex,int,int)),
- SLOT(_q_sourceColumnsRemoved(QModelIndex,int,int)));
- connect(sourceModel(), SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- SLOT(_q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
- connect(sourceModel(), SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
- SLOT(_q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int)));
- connect(sourceModel(), SIGNAL(modelAboutToBeReset()),
- SLOT(_q_sourceModelAboutToBeReset()));
- connect(sourceModel(), SIGNAL(modelReset()),
- SLOT(_q_sourceModelReset()));
- connect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex,QList<int>)),
- SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex,QList<int>)));
- connect(sourceModel(), SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
- SLOT(_q_sourceHeaderDataChanged(Qt::Orientation,int,int)));
- connect(sourceModel(), SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- SLOT(_q_sourceLayoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
- connect(sourceModel(), SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- SLOT(_q_sourceLayoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
+ auto *m = sourceModel();
+ d->m_sourceModelConnections = {
+ QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeInserted, d,
+ &QIdentityProxyModelPrivate::sourceRowsAboutToBeInserted),
+ QObjectPrivate::connect(m, &QAbstractItemModel::rowsInserted, d,
+ &QIdentityProxyModelPrivate::sourceRowsInserted),
+ QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeRemoved, d,
+ &QIdentityProxyModelPrivate::sourceRowsAboutToBeRemoved),
+ QObjectPrivate::connect(m, &QAbstractItemModel::rowsRemoved, d,
+ &QIdentityProxyModelPrivate::sourceRowsRemoved),
+ QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeMoved, d,
+ &QIdentityProxyModelPrivate::sourceRowsAboutToBeMoved),
+ QObjectPrivate::connect(m, &QAbstractItemModel::rowsMoved, d,
+ &QIdentityProxyModelPrivate::sourceRowsMoved),
+ QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeInserted, d,
+ &QIdentityProxyModelPrivate::sourceColumnsAboutToBeInserted),
+ QObjectPrivate::connect(m, &QAbstractItemModel::columnsInserted, d,
+ &QIdentityProxyModelPrivate::sourceColumnsInserted),
+ QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeRemoved, d,
+ &QIdentityProxyModelPrivate::sourceColumnsAboutToBeRemoved),
+ QObjectPrivate::connect(m, &QAbstractItemModel::columnsRemoved, d,
+ &QIdentityProxyModelPrivate::sourceColumnsRemoved),
+ QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeMoved, d,
+ &QIdentityProxyModelPrivate::sourceColumnsAboutToBeMoved),
+ QObjectPrivate::connect(m, &QAbstractItemModel::columnsMoved, d,
+ &QIdentityProxyModelPrivate::sourceColumnsMoved),
+ QObjectPrivate::connect(m, &QAbstractItemModel::modelAboutToBeReset, d,
+ &QIdentityProxyModelPrivate::sourceModelAboutToBeReset),
+ QObjectPrivate::connect(m, &QAbstractItemModel::modelReset, d,
+ &QIdentityProxyModelPrivate::sourceModelReset),
+ QObjectPrivate::connect(m, &QAbstractItemModel::dataChanged, d,
+ &QIdentityProxyModelPrivate::sourceDataChanged),
+ QObjectPrivate::connect(m, &QAbstractItemModel::headerDataChanged, d,
+ &QIdentityProxyModelPrivate::sourceHeaderDataChanged),
+ };
+
+ if (d->m_handleLayoutChanges) {
+ d->m_sourceModelConnections.emplace_back(
+ QObjectPrivate::connect(m, &QAbstractItemModel::layoutAboutToBeChanged, d,
+ &QIdentityProxyModelPrivate::sourceLayoutAboutToBeChanged));
+ d->m_sourceModelConnections.emplace_back(
+ QObjectPrivate::connect(m, &QAbstractItemModel::layoutChanged, d,
+ &QIdentityProxyModelPrivate::sourceLayoutChanged));
+ }
}
endResetModel();
}
-void QIdentityProxyModelPrivate::_q_sourceColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end)
+/*!
+ \since 6.7
+
+ If \a b is \c true, this proxy model will handle the source model layout
+ changes (by connecting to \c QAbstractItemModel::layoutAboutToBeChanged
+ and \c QAbstractItemModel::layoutChanged singals).
+
+ The default is for this proxy model to handle the source model layout
+ changes.
+
+ In sub-classes of QIdentityProxyModel, it may be useful to set this to
+ \c false if you need to specially handle the source model layout changes.
+
+ \note Calling this method will only have an effect after calling setSourceModel().
+*/
+void QIdentityProxyModel::setHandleSourceLayoutChanges(bool b)
+{
+ d_func()->m_handleLayoutChanges = b;
+}
+
+/*!
+ \since 6.7
+
+ Returns \c true if this proxy model handles the source model layout
+ changes, otherwise returns \c false.
+*/
+bool QIdentityProxyModel::isHandleSourceLayoutChanges() const
+{
+ return d_func()->m_handleLayoutChanges;
+}
+
+void QIdentityProxyModelPrivate::sourceColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end)
{
Q_ASSERT(parent.isValid() ? parent.model() == model : true);
Q_Q(QIdentityProxyModel);
q->beginInsertColumns(q->mapFromSource(parent), start, end);
}
-void QIdentityProxyModelPrivate::_q_sourceColumnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest)
+void QIdentityProxyModelPrivate::sourceColumnsAboutToBeMoved(const QModelIndex &sourceParent,
+ int sourceStart, int sourceEnd,
+ const QModelIndex &destParent,
+ int dest)
{
Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model : true);
Q_ASSERT(destParent.isValid() ? destParent.model() == model : true);
@@ -388,14 +399,14 @@ void QIdentityProxyModelPrivate::_q_sourceColumnsAboutToBeMoved(const QModelInde
q->beginMoveColumns(q->mapFromSource(sourceParent), sourceStart, sourceEnd, q->mapFromSource(destParent), dest);
}
-void QIdentityProxyModelPrivate::_q_sourceColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
+void QIdentityProxyModelPrivate::sourceColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
{
Q_ASSERT(parent.isValid() ? parent.model() == model : true);
Q_Q(QIdentityProxyModel);
q->beginRemoveColumns(q->mapFromSource(parent), start, end);
}
-void QIdentityProxyModelPrivate::_q_sourceColumnsInserted(const QModelIndex &parent, int start, int end)
+void QIdentityProxyModelPrivate::sourceColumnsInserted(const QModelIndex &parent, int start, int end)
{
Q_ASSERT(parent.isValid() ? parent.model() == model : true);
Q_Q(QIdentityProxyModel);
@@ -405,7 +416,9 @@ void QIdentityProxyModelPrivate::_q_sourceColumnsInserted(const QModelIndex &par
q->endInsertColumns();
}
-void QIdentityProxyModelPrivate::_q_sourceColumnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest)
+void QIdentityProxyModelPrivate::sourceColumnsMoved(const QModelIndex &sourceParent,
+ int sourceStart, int sourceEnd,
+ const QModelIndex &destParent, int dest)
{
Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model : true);
Q_ASSERT(destParent.isValid() ? destParent.model() == model : true);
@@ -418,7 +431,7 @@ void QIdentityProxyModelPrivate::_q_sourceColumnsMoved(const QModelIndex &source
q->endMoveColumns();
}
-void QIdentityProxyModelPrivate::_q_sourceColumnsRemoved(const QModelIndex &parent, int start, int end)
+void QIdentityProxyModelPrivate::sourceColumnsRemoved(const QModelIndex &parent, int start, int end)
{
Q_ASSERT(parent.isValid() ? parent.model() == model : true);
Q_Q(QIdentityProxyModel);
@@ -428,7 +441,9 @@ void QIdentityProxyModelPrivate::_q_sourceColumnsRemoved(const QModelIndex &pare
q->endRemoveColumns();
}
-void QIdentityProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles)
+void QIdentityProxyModelPrivate::sourceDataChanged(const QModelIndex &topLeft,
+ const QModelIndex &bottomRight,
+ const QList<int> &roles)
{
Q_ASSERT(topLeft.isValid() ? topLeft.model() == model : true);
Q_ASSERT(bottomRight.isValid() ? bottomRight.model() == model : true);
@@ -436,13 +451,15 @@ void QIdentityProxyModelPrivate::_q_sourceDataChanged(const QModelIndex &topLeft
emit q->dataChanged(q->mapFromSource(topLeft), q->mapFromSource(bottomRight), roles);
}
-void QIdentityProxyModelPrivate::_q_sourceHeaderDataChanged(Qt::Orientation orientation, int first, int last)
+void QIdentityProxyModelPrivate::sourceHeaderDataChanged(Qt::Orientation orientation, int first,
+ int last)
{
Q_Q(QIdentityProxyModel);
emit q->headerDataChanged(orientation, first, last);
}
-void QIdentityProxyModelPrivate::_q_sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint)
+void QIdentityProxyModelPrivate::sourceLayoutAboutToBeChanged(
+ const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint)
{
Q_Q(QIdentityProxyModel);
@@ -470,7 +487,8 @@ void QIdentityProxyModelPrivate::_q_sourceLayoutAboutToBeChanged(const QList<QPe
}
}
-void QIdentityProxyModelPrivate::_q_sourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint)
+void QIdentityProxyModelPrivate::sourceLayoutChanged(
+ const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint)
{
Q_Q(QIdentityProxyModel);
@@ -496,26 +514,29 @@ void QIdentityProxyModelPrivate::_q_sourceLayoutChanged(const QList<QPersistentM
emit q->layoutChanged(parents, hint);
}
-void QIdentityProxyModelPrivate::_q_sourceModelAboutToBeReset()
+void QIdentityProxyModelPrivate::sourceModelAboutToBeReset()
{
Q_Q(QIdentityProxyModel);
q->beginResetModel();
}
-void QIdentityProxyModelPrivate::_q_sourceModelReset()
+void QIdentityProxyModelPrivate::sourceModelReset()
{
Q_Q(QIdentityProxyModel);
q->endResetModel();
}
-void QIdentityProxyModelPrivate::_q_sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
+void QIdentityProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &parent, int start,
+ int end)
{
Q_ASSERT(parent.isValid() ? parent.model() == model : true);
Q_Q(QIdentityProxyModel);
q->beginInsertRows(q->mapFromSource(parent), start, end);
}
-void QIdentityProxyModelPrivate::_q_sourceRowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest)
+void QIdentityProxyModelPrivate::sourceRowsAboutToBeMoved(const QModelIndex &sourceParent,
+ int sourceStart, int sourceEnd,
+ const QModelIndex &destParent, int dest)
{
Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model : true);
Q_ASSERT(destParent.isValid() ? destParent.model() == model : true);
@@ -523,14 +544,15 @@ void QIdentityProxyModelPrivate::_q_sourceRowsAboutToBeMoved(const QModelIndex &
q->beginMoveRows(q->mapFromSource(sourceParent), sourceStart, sourceEnd, q->mapFromSource(destParent), dest);
}
-void QIdentityProxyModelPrivate::_q_sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
+void QIdentityProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start,
+ int end)
{
Q_ASSERT(parent.isValid() ? parent.model() == model : true);
Q_Q(QIdentityProxyModel);
q->beginRemoveRows(q->mapFromSource(parent), start, end);
}
-void QIdentityProxyModelPrivate::_q_sourceRowsInserted(const QModelIndex &parent, int start, int end)
+void QIdentityProxyModelPrivate::sourceRowsInserted(const QModelIndex &parent, int start, int end)
{
Q_ASSERT(parent.isValid() ? parent.model() == model : true);
Q_Q(QIdentityProxyModel);
@@ -540,7 +562,9 @@ void QIdentityProxyModelPrivate::_q_sourceRowsInserted(const QModelIndex &parent
q->endInsertRows();
}
-void QIdentityProxyModelPrivate::_q_sourceRowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest)
+void QIdentityProxyModelPrivate::sourceRowsMoved(const QModelIndex &sourceParent, int sourceStart,
+ int sourceEnd, const QModelIndex &destParent,
+ int dest)
{
Q_ASSERT(sourceParent.isValid() ? sourceParent.model() == model : true);
Q_ASSERT(destParent.isValid() ? destParent.model() == model : true);
@@ -553,7 +577,7 @@ void QIdentityProxyModelPrivate::_q_sourceRowsMoved(const QModelIndex &sourcePar
q->endMoveRows();
}
-void QIdentityProxyModelPrivate::_q_sourceRowsRemoved(const QModelIndex &parent, int start, int end)
+void QIdentityProxyModelPrivate::sourceRowsRemoved(const QModelIndex &parent, int start, int end)
{
Q_ASSERT(parent.isValid() ? parent.model() == model : true);
Q_Q(QIdentityProxyModel);
diff --git a/src/corelib/itemmodels/qidentityproxymodel.h b/src/corelib/itemmodels/qidentityproxymodel.h
index 42b87d30a2..c8fc9d21b7 100644
--- a/src/corelib/itemmodels/qidentityproxymodel.h
+++ b/src/corelib/itemmodels/qidentityproxymodel.h
@@ -44,34 +44,15 @@ public:
bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) override;
bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count, const QModelIndex &destinationParent, int destinationChild) override;
+ bool isHandleSourceLayoutChanges() const;
+
protected:
QIdentityProxyModel(QIdentityProxyModelPrivate &dd, QObject* parent);
+ void setHandleSourceLayoutChanges(bool);
private:
Q_DECLARE_PRIVATE(QIdentityProxyModel)
Q_DISABLE_COPY(QIdentityProxyModel)
-
- Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeInserted(QModelIndex,int,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsInserted(QModelIndex,int,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeRemoved(QModelIndex,int,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsRemoved(QModelIndex,int,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceRowsMoved(QModelIndex,int,int,QModelIndex,int))
-
- Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeInserted(QModelIndex,int,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsInserted(QModelIndex,int,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeRemoved(QModelIndex,int,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsRemoved(QModelIndex,int,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceColumnsMoved(QModelIndex,int,int,QModelIndex,int))
-
- Q_PRIVATE_SLOT(d_func(), void _q_sourceDataChanged(QModelIndex, QModelIndex, QList<int>))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int first, int last))
-
- Q_PRIVATE_SLOT(d_func(), void _q_sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint))
- Q_PRIVATE_SLOT(d_func(), void _q_sourceModelAboutToBeReset())
- Q_PRIVATE_SLOT(d_func(), void _q_sourceModelReset())
};
QT_END_NAMESPACE
diff --git a/src/corelib/itemmodels/qidentityproxymodel_p.h b/src/corelib/itemmodels/qidentityproxymodel_p.h
index 0aa0624ab0..78e1f5316c 100644
--- a/src/corelib/itemmodels/qidentityproxymodel_p.h
+++ b/src/corelib/itemmodels/qidentityproxymodel_p.h
@@ -33,28 +33,38 @@ public:
QList<QPersistentModelIndex> layoutChangePersistentIndexes;
QModelIndexList proxyIndexes;
- void _q_sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end);
- void _q_sourceRowsInserted(const QModelIndex &parent, int start, int end);
- void _q_sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
- void _q_sourceRowsRemoved(const QModelIndex &parent, int start, int end);
- void _q_sourceRowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest);
- void _q_sourceRowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest);
-
- void _q_sourceColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end);
- void _q_sourceColumnsInserted(const QModelIndex &parent, int start, int end);
- void _q_sourceColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
- void _q_sourceColumnsRemoved(const QModelIndex &parent, int start, int end);
- void _q_sourceColumnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest);
- void _q_sourceColumnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd, const QModelIndex &destParent, int dest);
-
- void _q_sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles);
- void _q_sourceHeaderDataChanged(Qt::Orientation orientation, int first, int last);
-
- void _q_sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint);
- void _q_sourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents, QAbstractItemModel::LayoutChangeHint hint);
- void _q_sourceModelAboutToBeReset();
- void _q_sourceModelReset();
+ void sourceRowsAboutToBeInserted(const QModelIndex &parent, int start, int end);
+ void sourceRowsInserted(const QModelIndex &parent, int start, int end);
+ void sourceRowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
+ void sourceRowsRemoved(const QModelIndex &parent, int start, int end);
+ void sourceRowsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd,
+ const QModelIndex &destParent, int dest);
+ void sourceRowsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd,
+ const QModelIndex &destParent, int dest);
+ void sourceColumnsAboutToBeInserted(const QModelIndex &parent, int start, int end);
+ void sourceColumnsInserted(const QModelIndex &parent, int start, int end);
+ void sourceColumnsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
+ void sourceColumnsRemoved(const QModelIndex &parent, int start, int end);
+ void sourceColumnsAboutToBeMoved(const QModelIndex &sourceParent, int sourceStart,
+ int sourceEnd, const QModelIndex &destParent, int dest);
+ void sourceColumnsMoved(const QModelIndex &sourceParent, int sourceStart, int sourceEnd,
+ const QModelIndex &destParent, int dest);
+
+ void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
+ const QList<int> &roles);
+ void sourceHeaderDataChanged(Qt::Orientation orientation, int first, int last);
+
+ void sourceLayoutAboutToBeChanged(const QList<QPersistentModelIndex> &sourceParents,
+ QAbstractItemModel::LayoutChangeHint hint);
+ void sourceLayoutChanged(const QList<QPersistentModelIndex> &sourceParents,
+ QAbstractItemModel::LayoutChangeHint hint);
+ void sourceModelAboutToBeReset();
+ void sourceModelReset();
+
+private:
+ bool m_handleLayoutChanges = true;
+ QVarLengthArray<QMetaObject::Connection, 18> m_sourceModelConnections;
};
QT_END_NAMESPACE
diff --git a/src/corelib/itemmodels/qitemselectionmodel.cpp b/src/corelib/itemmodels/qitemselectionmodel.cpp
index 0f3cbadca5..6df60aaf61 100644
--- a/src/corelib/itemmodels/qitemselectionmodel.cpp
+++ b/src/corelib/itemmodels/qitemselectionmodel.cpp
@@ -27,6 +27,8 @@ QT_IMPL_METATYPE_EXTERN(QItemSelection)
\ingroup model-view
+ \compares equality
+
A QItemSelectionRange contains information about a range of
selected items in a model. A range of items is a contiguous array
of model items, extending to cover a number of adjacent rows and
@@ -216,17 +218,17 @@ QItemSelectionRange QItemSelectionRange::intersected(const QItemSelectionRange &
}
/*!
- \fn bool QItemSelectionRange::operator==(const QItemSelectionRange &other) const
+ \fn bool QItemSelectionRange::operator==(const QItemSelectionRange &lhs, const QItemSelectionRange &rhs)
- Returns \c true if the selection range is exactly the same as the \a other
+ Returns \c true if \a lhs selection range is exactly the same as the \a rhs
range given; otherwise returns \c false.
*/
/*!
- \fn bool QItemSelectionRange::operator!=(const QItemSelectionRange &other) const
+ \fn bool QItemSelectionRange::operator!=(const QItemSelectionRange &lhs, const QItemSelectionRange &rhs)
- Returns \c true if the selection range differs from the \a other range given;
+ Returns \c true if \a lhs selection range differs from the \a rhs range given;
otherwise returns \c false.
*/
@@ -238,7 +240,7 @@ QItemSelectionRange QItemSelectionRange::intersected(const QItemSelectionRange &
*/
-static void rowLengthsFromRange(const QItemSelectionRange &range, QList<QPair<QPersistentModelIndex, uint>> &result)
+static void rowLengthsFromRange(const QItemSelectionRange &range, QList<std::pair<QPersistentModelIndex, uint>> &result)
{
if (range.isValid() && range.model()) {
const QModelIndex topLeft = range.topLeft();
@@ -249,7 +251,7 @@ static void rowLengthsFromRange(const QItemSelectionRange &range, QList<QPair<QP
// We don't need to keep track of ItemIsSelectable and ItemIsEnabled here. That is
// required in indexesFromRange() because that method is called from public API
// which requires the limitation.
- result.push_back(qMakePair(QPersistentModelIndex(topLeft.sibling(row, column)), width));
+ result.emplace_back(topLeft.sibling(row, column), width);
}
}
}
@@ -432,9 +434,9 @@ QModelIndexList QItemSelection::indexes() const
return qSelectionIndexes<QModelIndexList>(*this);
}
-static QList<QPair<QPersistentModelIndex, uint>> qSelectionPersistentRowLengths(const QItemSelection &sel)
+static QList<std::pair<QPersistentModelIndex, uint>> qSelectionPersistentRowLengths(const QItemSelection &sel)
{
- QList<QPair<QPersistentModelIndex, uint>> result;
+ QList<std::pair<QPersistentModelIndex, uint>> result;
for (const QItemSelectionRange &range : sel)
rowLengthsFromRange(range, result);
return result;
@@ -550,52 +552,55 @@ void QItemSelection::split(const QItemSelectionRange &range,
void QItemSelectionModelPrivate::initModel(QAbstractItemModel *m)
{
- static constexpr auto connections = qOffsetStringArray(
- QT_STRINGIFY_SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- QT_STRINGIFY_SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)),
- QT_STRINGIFY_SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
- QT_STRINGIFY_SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int)),
- QT_STRINGIFY_SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
- QT_STRINGIFY_SLOT(_q_rowsAboutToBeInserted(QModelIndex,int,int)),
- QT_STRINGIFY_SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
- QT_STRINGIFY_SLOT(_q_columnsAboutToBeInserted(QModelIndex,int,int)),
- QT_STRINGIFY_SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- QT_STRINGIFY_SLOT(_q_layoutAboutToBeChanged()),
- QT_STRINGIFY_SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- QT_STRINGIFY_SLOT(_q_layoutAboutToBeChanged()),
- QT_STRINGIFY_SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
- QT_STRINGIFY_SLOT(_q_layoutChanged()),
- QT_STRINGIFY_SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
- QT_STRINGIFY_SLOT(_q_layoutChanged()),
- QT_STRINGIFY_SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- QT_STRINGIFY_SLOT(_q_layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- QT_STRINGIFY_SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- QT_STRINGIFY_SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- QT_STRINGIFY_SIGNAL(modelReset()),
- QT_STRINGIFY_SLOT(reset()),
- QT_STRINGIFY_SIGNAL(destroyed(QObject*)),
- QT_STRINGIFY_SLOT(_q_modelDestroyed())
- );
-
- if (model == m)
+ Q_Q(QItemSelectionModel);
+ const QAbstractItemModel *oldModel = model.valueBypassingBindings();
+ if (oldModel == m)
return;
- Q_Q(QItemSelectionModel);
- if (model.value()) {
- for (int i = 0; i < connections.count(); i += 2)
- QObject::disconnect(model.value(), connections.at(i), q, connections.at(i + 1));
+ if (oldModel) {
q->reset();
+ disconnectModel();
}
// Caller has to call notify(), unless calling during construction (the common case).
model.setValueBypassingBindings(m);
- if (model.value()) {
- for (int i = 0; i < connections.count(); i += 2)
- QObject::connect(model.value(), connections.at(i), q, connections.at(i + 1));
+ if (m) {
+ connections = std::array<QMetaObject::Connection, 12> {
+ QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeRemoved,
+ this, &QItemSelectionModelPrivate::rowsAboutToBeRemoved),
+ QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeRemoved,
+ this, &QItemSelectionModelPrivate::columnsAboutToBeRemoved),
+ QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeInserted,
+ this, &QItemSelectionModelPrivate::rowsAboutToBeInserted),
+ QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeInserted,
+ this, &QItemSelectionModelPrivate::columnsAboutToBeInserted),
+ QObjectPrivate::connect(m, &QAbstractItemModel::rowsAboutToBeMoved,
+ this, &QItemSelectionModelPrivate::triggerLayoutToBeChanged),
+ QObjectPrivate::connect(m, &QAbstractItemModel::columnsAboutToBeMoved,
+ this, &QItemSelectionModelPrivate::triggerLayoutToBeChanged),
+ QObjectPrivate::connect(m, &QAbstractItemModel::rowsMoved,
+ this, &QItemSelectionModelPrivate::triggerLayoutChanged),
+ QObjectPrivate::connect(m, &QAbstractItemModel::columnsMoved,
+ this, &QItemSelectionModelPrivate::triggerLayoutChanged),
+ QObjectPrivate::connect(m, &QAbstractItemModel::layoutAboutToBeChanged,
+ this, &QItemSelectionModelPrivate::layoutAboutToBeChanged),
+ QObjectPrivate::connect(m, &QAbstractItemModel::layoutChanged,
+ this, &QItemSelectionModelPrivate::layoutChanged),
+ QObject::connect(m, &QAbstractItemModel::modelReset,
+ q, &QItemSelectionModel::reset),
+ QObjectPrivate::connect(m, &QAbstractItemModel::destroyed,
+ this, &QItemSelectionModelPrivate::modelDestroyed)
+ };
}
}
+void QItemSelectionModelPrivate::disconnectModel()
+{
+ for (auto &connection : connections)
+ QObject::disconnect(connection);
+}
+
/*!
\internal
@@ -638,7 +643,7 @@ QItemSelection QItemSelectionModelPrivate::expandSelection(const QItemSelection
/*!
\internal
*/
-void QItemSelectionModelPrivate::_q_rowsAboutToBeRemoved(const QModelIndex &parent,
+void QItemSelectionModelPrivate::rowsAboutToBeRemoved(const QModelIndex &parent,
int start, int end)
{
Q_Q(QItemSelectionModel);
@@ -721,7 +726,7 @@ void QItemSelectionModelPrivate::_q_rowsAboutToBeRemoved(const QModelIndex &pare
/*!
\internal
*/
-void QItemSelectionModelPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &parent,
+void QItemSelectionModelPrivate::columnsAboutToBeRemoved(const QModelIndex &parent,
int start, int end)
{
Q_Q(QItemSelectionModel);
@@ -758,7 +763,7 @@ void QItemSelectionModelPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &p
Split selection ranges if columns are about to be inserted in the middle.
*/
-void QItemSelectionModelPrivate::_q_columnsAboutToBeInserted(const QModelIndex &parent,
+void QItemSelectionModelPrivate::columnsAboutToBeInserted(const QModelIndex &parent,
int start, int end)
{
Q_UNUSED(end);
@@ -788,7 +793,7 @@ void QItemSelectionModelPrivate::_q_columnsAboutToBeInserted(const QModelIndex &
Split selection ranges if rows are about to be inserted in the middle.
*/
-void QItemSelectionModelPrivate::_q_rowsAboutToBeInserted(const QModelIndex &parent,
+void QItemSelectionModelPrivate::rowsAboutToBeInserted(const QModelIndex &parent,
int start, int end)
{
Q_Q(QItemSelectionModel);
@@ -829,7 +834,8 @@ void QItemSelectionModelPrivate::_q_rowsAboutToBeInserted(const QModelIndex &par
preparation for the layoutChanged() signal, where the indexes can be
merged again.
*/
-void QItemSelectionModelPrivate::_q_layoutAboutToBeChanged(const QList<QPersistentModelIndex> &, QAbstractItemModel::LayoutChangeHint hint)
+void QItemSelectionModelPrivate::layoutAboutToBeChanged(const QList<QPersistentModelIndex> &,
+ QAbstractItemModel::LayoutChangeHint hint)
{
savedPersistentIndexes.clear();
savedPersistentCurrentIndexes.clear();
@@ -871,7 +877,7 @@ void QItemSelectionModelPrivate::_q_layoutAboutToBeChanged(const QList<QPersiste
/*!
\internal
*/
-static QItemSelection mergeRowLengths(const QList<QPair<QPersistentModelIndex, uint>> &rowLengths)
+static QItemSelection mergeRowLengths(const QList<std::pair<QPersistentModelIndex, uint>> &rowLengths)
{
if (rowLengths.isEmpty())
return QItemSelection();
@@ -976,7 +982,7 @@ static QItemSelection mergeIndexes(const QList<QPersistentModelIndex> &indexes)
/*!
\internal
- Sort predicate function for QItemSelectionModelPrivate::_q_layoutChanged(),
+ Sort predicate function for QItemSelectionModelPrivate::layoutChanged(),
sorting by parent first in addition to operator<(). This is to prevent
fragmentation of the selection by grouping indexes with the same row, column
of different parents next to each other, which may happen when a selection
@@ -994,7 +1000,7 @@ static bool qt_PersistentModelIndexLessThan(const QPersistentModelIndex &i1, con
Merge the selected indexes into selection ranges again.
*/
-void QItemSelectionModelPrivate::_q_layoutChanged(const QList<QPersistentModelIndex> &, QAbstractItemModel::LayoutChangeHint hint)
+void QItemSelectionModelPrivate::layoutChanged(const QList<QPersistentModelIndex> &, QAbstractItemModel::LayoutChangeHint hint)
{
// special case for when all indexes are selected
if (tableSelected && tableColCount == model->columnCount(tableParent)
@@ -1078,9 +1084,10 @@ void QItemSelectionModelPrivate::_q_layoutChanged(const QList<QPersistentModelIn
We decide to break the new rule, imposed by bindable properties, and not break the old
rule, because that may break existing code.
*/
-void QItemSelectionModelPrivate::_q_modelDestroyed()
+void QItemSelectionModelPrivate::modelDestroyed()
{
model.setValueBypassingBindings(nullptr);
+ disconnectModel();
model.notify();
}
@@ -1120,7 +1127,7 @@ void QItemSelectionModelPrivate::_q_modelDestroyed()
\l{QItemSelectionModel::hasSelection()}{hasSelection}, and
\l{QItemSelectionModel::currentIndex()}{currentIndex} are meta-object properties.
- \sa {Model/View Programming}, QAbstractItemModel, {Chart Example}
+ \sa {Model/View Programming}, QAbstractItemModel
*/
/*!
@@ -1289,7 +1296,7 @@ void QItemSelectionModel::select(const QItemSelection &selection, QItemSelection
// If d->ranges is non-empty when the source model is reset the persistent indexes
// it contains will be invalid. We can't clear them in a modelReset slot because that might already
// be too late if another model observer is connected to the same modelReset slot and is invoked first
- // it might call select() on this selection model before any such QItemSelectionModelPrivate::_q_modelReset() slot
+ // it might call select() on this selection model before any such QItemSelectionModelPrivate::modelReset() slot
// is invoked, so it would not be cleared yet. We clear it invalid ranges in it here.
d->ranges.removeIf(QtFunctionObjects::IsNotValid());
@@ -1881,9 +1888,8 @@ void QItemSelectionModel::setModel(QAbstractItemModel *model)
{
Q_D(QItemSelectionModel);
d->model.removeBindingUnlessInWrapper();
- if (d->model == model)
+ if (d->model.valueBypassingBindings() == model)
return;
-
d->initModel(model);
d->model.notify();
}
diff --git a/src/corelib/itemmodels/qitemselectionmodel.h b/src/corelib/itemmodels/qitemselectionmodel.h
index 4237e7f74f..c4b8dadc97 100644
--- a/src/corelib/itemmodels/qitemselectionmodel.h
+++ b/src/corelib/itemmodels/qitemselectionmodel.h
@@ -57,12 +57,12 @@ public:
bool intersects(const QItemSelectionRange &other) const;
QItemSelectionRange intersected(const QItemSelectionRange &other) const;
-
+#if QT_CORE_REMOVED_SINCE(6, 8)
inline bool operator==(const QItemSelectionRange &other) const
- { return (tl == other.tl && br == other.br); }
+ { return comparesEqual(*this, other); }
inline bool operator!=(const QItemSelectionRange &other) const
- { return !operator==(other); }
-
+ { return !operator==(other); }
+#endif
inline bool isValid() const
{
return (tl.isValid() && br.isValid() && tl.parent() == br.parent()
@@ -74,6 +74,12 @@ public:
QModelIndexList indexes() const;
private:
+ friend bool comparesEqual(const QItemSelectionRange &lhs,
+ const QItemSelectionRange &rhs) noexcept
+ {
+ return (lhs.tl == rhs.tl && lhs.br == rhs.br);
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QItemSelectionRange)
QPersistentModelIndex tl, br;
};
Q_DECLARE_TYPEINFO(QItemSelectionRange, Q_RELOCATABLE_TYPE);
@@ -165,13 +171,6 @@ protected:
private:
Q_DISABLE_COPY(QItemSelectionModel)
- Q_PRIVATE_SLOT(d_func(), void _q_columnsAboutToBeRemoved(const QModelIndex&, int, int))
- Q_PRIVATE_SLOT(d_func(), void _q_rowsAboutToBeRemoved(const QModelIndex&, int, int))
- Q_PRIVATE_SLOT(d_func(), void _q_columnsAboutToBeInserted(const QModelIndex&, int, int))
- Q_PRIVATE_SLOT(d_func(), void _q_rowsAboutToBeInserted(const QModelIndex&, int, int))
- Q_PRIVATE_SLOT(d_func(), void _q_layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoHint))
- Q_PRIVATE_SLOT(d_func(), void _q_layoutChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoHint))
- Q_PRIVATE_SLOT(d_func(), void _q_modelDestroyed())
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QItemSelectionModel::SelectionFlags)
diff --git a/src/corelib/itemmodels/qitemselectionmodel_p.h b/src/corelib/itemmodels/qitemselectionmodel_p.h
index f63526e8ae..689cd26bd2 100644
--- a/src/corelib/itemmodels/qitemselectionmodel_p.h
+++ b/src/corelib/itemmodels/qitemselectionmodel_p.h
@@ -15,8 +15,10 @@
// We mean it.
//
+#include "qitemselectionmodel.h"
#include "private/qobject_p.h"
#include "private/qproperty_p.h"
+#include <array>
QT_REQUIRE_CONFIG(itemmodel);
@@ -35,13 +37,23 @@ public:
void initModel(QAbstractItemModel *model);
- void _q_rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
- void _q_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
- void _q_rowsAboutToBeInserted(const QModelIndex &parent, int start, int end);
- void _q_columnsAboutToBeInserted(const QModelIndex &parent, int start, int end);
- void _q_layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint);
- void _q_layoutChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(), QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint);
- void _q_modelDestroyed();
+ void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
+ void columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
+ void rowsAboutToBeInserted(const QModelIndex &parent, int start, int end);
+ void columnsAboutToBeInserted(const QModelIndex &parent, int start, int end);
+ void layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint);
+ void triggerLayoutToBeChanged()
+ {
+ layoutAboutToBeChanged(QList<QPersistentModelIndex>(), QAbstractItemModel::NoLayoutChangeHint);
+ }
+
+ void layoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint);
+ void triggerLayoutChanged()
+ {
+ layoutChanged(QList<QPersistentModelIndex>(), QAbstractItemModel::NoLayoutChangeHint);
+ }
+
+ void modelDestroyed();
inline void remove(QList<QItemSelectionRange> &r)
{
@@ -58,7 +70,8 @@ public:
}
void setModel(QAbstractItemModel *mod) { q_func()->setModel(mod); }
- void modelChanged(QAbstractItemModel *mod) { q_func()->modelChanged(mod); }
+ void disconnectModel();
+ void modelChanged(QAbstractItemModel *mod) { emit q_func()->modelChanged(mod); }
Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QItemSelectionModelPrivate, QAbstractItemModel *, model,
&QItemSelectionModelPrivate::setModel,
&QItemSelectionModelPrivate::modelChanged, nullptr)
@@ -69,12 +82,13 @@ public:
QItemSelectionModel::SelectionFlags currentCommand;
QList<QPersistentModelIndex> savedPersistentIndexes;
QList<QPersistentModelIndex> savedPersistentCurrentIndexes;
- QList<QPair<QPersistentModelIndex, uint>> savedPersistentRowLengths;
- QList<QPair<QPersistentModelIndex, uint>> savedPersistentCurrentRowLengths;
+ QList<std::pair<QPersistentModelIndex, uint>> savedPersistentRowLengths;
+ QList<std::pair<QPersistentModelIndex, uint>> savedPersistentCurrentRowLengths;
// optimization when all indexes are selected
bool tableSelected;
QPersistentModelIndex tableParent;
int tableColCount, tableRowCount;
+ std::array<QMetaObject::Connection, 12> connections;
};
QT_END_NAMESPACE
diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/src/corelib/itemmodels/qsortfilterproxymodel.cpp
index db1ed95182..a5284dbad4 100644
--- a/src/corelib/itemmodels/qsortfilterproxymodel.cpp
+++ b/src/corelib/itemmodels/qsortfilterproxymodel.cpp
@@ -6,7 +6,6 @@
#include <qsize.h>
#include <qdebug.h>
#include <qdatetime.h>
-#include <qpair.h>
#include <qstringlist.h>
#include <private/qabstractitemmodel_p.h>
#include <private/qabstractproxymodel_p.h>
@@ -16,7 +15,7 @@
QT_BEGIN_NAMESPACE
-typedef QList<QPair<QModelIndex, QPersistentModelIndex>> QModelIndexPairList;
+using QModelIndexPairList = QList<std::pair<QModelIndex, QPersistentModelIndex>>;
struct QSortFilterProxyModelDataChanged
{
@@ -256,7 +255,7 @@ public:
*/
void set_filter_pattern(const QString &pattern)
{
- QRegularExpression re = filter_regularexpression.value();
+ QRegularExpression re = filter_regularexpression.valueBypassingBindings();
const auto cs = re.patternOptions() & QRegularExpression::CaseInsensitiveOption;
re.setPattern(pattern);
re.setPatternOptions(cs);
@@ -333,10 +332,10 @@ public:
int find_source_sort_column() const;
void sort_source_rows(QList<int> &source_rows,
const QModelIndex &source_parent) const;
- QList<QPair<int, QList<int>>> proxy_intervals_for_source_items_to_add(
+ QList<std::pair<int, QList<int>>> proxy_intervals_for_source_items_to_add(
const QList<int> &proxy_to_source, const QList<int> &source_items,
const QModelIndex &source_parent, Qt::Orientation orient) const;
- QList<QPair<int, int>> proxy_intervals_for_source_items(
+ QList<std::pair<int, int>> proxy_intervals_for_source_items(
const QList<int> &source_to_proxy, const QList<int> &source_items) const;
void insert_source_items(
QList<int> &source_to_proxy, QList<int> &proxy_to_source,
@@ -689,8 +688,10 @@ void QSortFilterProxyModelPrivate::sort_source_rows(
QSortFilterProxyModelGreaterThan gt(source_sort_column, source_parent, model, q);
std::stable_sort(source_rows.begin(), source_rows.end(), gt);
}
- } else { // restore the source model order
- std::stable_sort(source_rows.begin(), source_rows.end());
+ } else if (sort_order == Qt::AscendingOrder) {
+ std::stable_sort(source_rows.begin(), source_rows.end(), std::less{});
+ } else {
+ std::stable_sort(source_rows.begin(), source_rows.end(), std::greater{});
}
}
@@ -705,10 +706,10 @@ void QSortFilterProxyModelPrivate::sort_source_rows(
The result is a vector of pairs, where each pair represents a
(start, end) tuple, sorted in ascending order.
*/
-QList<QPair<int, int>> QSortFilterProxyModelPrivate::proxy_intervals_for_source_items(
+QList<std::pair<int, int>> QSortFilterProxyModelPrivate::proxy_intervals_for_source_items(
const QList<int> &source_to_proxy, const QList<int> &source_items) const
{
- QList<QPair<int, int>> proxy_intervals;
+ QList<std::pair<int, int>> proxy_intervals;
if (source_items.isEmpty())
return proxy_intervals;
@@ -725,19 +726,19 @@ QList<QPair<int, int>> QSortFilterProxyModelPrivate::proxy_intervals_for_source_
++source_items_index;
}
// Add interval to result
- proxy_intervals.append(QPair<int, int>(first_proxy_item, last_proxy_item));
+ proxy_intervals.emplace_back(first_proxy_item, last_proxy_item);
}
std::stable_sort(proxy_intervals.begin(), proxy_intervals.end());
// Consolidate adjacent intervals
for (int i = proxy_intervals.size()-1; i > 0; --i) {
- QPair<int, int> &interval = proxy_intervals[i];
- QPair<int, int> &preceeding_interval = proxy_intervals[i - 1];
+ std::pair<int, int> &interval = proxy_intervals[i];
+ std::pair<int, int> &preceeding_interval = proxy_intervals[i - 1];
if (interval.first == preceeding_interval.second + 1) {
preceeding_interval.second = interval.second;
interval.first = interval.second = -1;
}
}
- proxy_intervals.removeIf([](QPair<int, int> interval) { return interval.first < 0; });
+ proxy_intervals.removeIf([](std::pair<int, int> interval) { return interval.first < 0; });
return proxy_intervals;
}
@@ -766,7 +767,7 @@ void QSortFilterProxyModelPrivate::remove_source_items(
const auto end = proxy_intervals.rend();
for (auto it = proxy_intervals.rbegin(); it != end; ++it) {
- const QPair<int, int> &interval = *it;
+ const std::pair<int, int> &interval = *it;
const int proxy_start = interval.first;
const int proxy_end = interval.second;
remove_proxy_interval(source_to_proxy, proxy_to_source, proxy_start, proxy_end,
@@ -820,22 +821,21 @@ void QSortFilterProxyModelPrivate::remove_proxy_interval(
items), where items is a vector containing the (sorted) source items that
should be inserted at that proxy model location.
*/
-QList<QPair<int, QList<int>>> QSortFilterProxyModelPrivate::proxy_intervals_for_source_items_to_add(
+QList<std::pair<int, QList<int>>> QSortFilterProxyModelPrivate::proxy_intervals_for_source_items_to_add(
const QList<int> &proxy_to_source, const QList<int> &source_items,
const QModelIndex &source_parent, Qt::Orientation orient) const
{
Q_Q(const QSortFilterProxyModel);
- QList<QPair<int, QList<int>>> proxy_intervals;
+ QList<std::pair<int, QList<int>>> proxy_intervals;
if (source_items.isEmpty())
return proxy_intervals;
int proxy_low = 0;
int proxy_item = 0;
int source_items_index = 0;
- QList<int> source_items_in_interval;
bool compare = (orient == Qt::Vertical && source_sort_column >= 0 && dynamic_sortfilter);
while (source_items_index < source_items.size()) {
- source_items_in_interval.clear();
+ QList<int> source_items_in_interval;
int first_new_source_item = source_items.at(source_items_index);
source_items_in_interval.append(first_new_source_item);
++source_items_index;
@@ -881,7 +881,7 @@ QList<QPair<int, QList<int>>> QSortFilterProxyModelPrivate::proxy_intervals_for_
}
// Add interval to result
- proxy_intervals.append(QPair<int, QList<int>>(proxy_item, source_items_in_interval));
+ proxy_intervals.emplace_back(proxy_item, std::move(source_items_in_interval));
}
return proxy_intervals;
}
@@ -909,7 +909,7 @@ void QSortFilterProxyModelPrivate::insert_source_items(
const auto end = proxy_intervals.rend();
for (auto it = proxy_intervals.rbegin(); it != end; ++it) {
- const QPair<int, QList<int>> &interval = *it;
+ const std::pair<int, QList<int>> &interval = *it;
const int proxy_start = interval.first;
const QList<int> &source_items = interval.second;
const int proxy_end = proxy_start + source_items.size() - 1;
@@ -1138,7 +1138,7 @@ void QSortFilterProxyModelPrivate::updateChildrenMapping(const QModelIndex &sour
Qt::Orientation orient, int start, int end, int delta_item_count, bool remove)
{
// see if any mapped children should be (re)moved
- QList<QPair<QModelIndex, Mapping *>> moved_source_index_mappings;
+ QList<std::pair<QModelIndex, Mapping *>> moved_source_index_mappings;
auto it2 = parent_mapping->mapped_children.begin();
for ( ; it2 != parent_mapping->mapped_children.end();) {
const QModelIndex source_child_index = *it2;
@@ -1172,7 +1172,7 @@ void QSortFilterProxyModelPrivate::updateChildrenMapping(const QModelIndex &sour
Mapping *cm = source_index_mapping.take(source_child_index);
Q_ASSERT(cm);
// we do not reinsert right away, because the new index might be identical with another, old index
- moved_source_index_mappings.append(QPair<QModelIndex, Mapping*>(new_index, cm));
+ moved_source_index_mappings.emplace_back(new_index, cm);
}
}
@@ -1229,7 +1229,7 @@ QModelIndexPairList QSortFilterProxyModelPrivate::store_persistent_indexes() con
for (const QPersistentModelIndexData *data : std::as_const(persistent.indexes)) {
const QModelIndex &proxy_index = data->index;
QModelIndex source_index = q->mapToSource(proxy_index);
- source_indexes.append(qMakePair(proxy_index, QPersistentModelIndex(source_index)));
+ source_indexes.emplace_back(proxy_index, source_index);
}
return source_indexes;
}
@@ -1267,7 +1267,7 @@ void QSortFilterProxyModelPrivate::update_persistent_indexes(
*/
void QSortFilterProxyModelPrivate::filter_about_to_be_changed(const QModelIndex &source_parent)
{
- if (!filter_regularexpression.value().pattern().isEmpty()
+ if (!filter_regularexpression.valueBypassingBindings().pattern().isEmpty()
&& source_index_mapping.constFind(source_parent) == source_index_mapping.constEnd()) {
create_mapping(source_parent);
}
@@ -2009,7 +2009,7 @@ QSortFilterProxyModel::QSortFilterProxyModel(QObject *parent)
: QAbstractProxyModel(*new QSortFilterProxyModelPrivate, parent)
{
Q_D(QSortFilterProxyModel);
- QObjectPrivate::connect(this, &QSortFilterProxyModel::modelReset, d,
+ QObjectPrivate::connect(this, &QAbstractItemModel::modelReset, d,
&QSortFilterProxyModelPrivate::_q_clearMapping);
}
@@ -2047,58 +2047,58 @@ void QSortFilterProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
QAbstractProxyModel::setSourceModel(sourceModel);
d->sourceConnections = std::array<QMetaObject::Connection, 18>{
- QObjectPrivate::connect(d->model, &QSortFilterProxyModel::dataChanged, d,
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::dataChanged, d,
&QSortFilterProxyModelPrivate::_q_sourceDataChanged),
- QObjectPrivate::connect(d->model, &QSortFilterProxyModel::headerDataChanged, d,
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::headerDataChanged, d,
&QSortFilterProxyModelPrivate::_q_sourceHeaderDataChanged),
- QObjectPrivate::connect(d->model, &QSortFilterProxyModel::rowsAboutToBeInserted, d,
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsAboutToBeInserted, d,
&QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeInserted),
- QObjectPrivate::connect(d->model, &QSortFilterProxyModel::rowsInserted, d,
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsInserted, d,
&QSortFilterProxyModelPrivate::_q_sourceRowsInserted),
- QObjectPrivate::connect(d->model, &QSortFilterProxyModel::columnsAboutToBeInserted, d,
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsAboutToBeInserted, d,
&QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeInserted),
- QObjectPrivate::connect(d->model, &QSortFilterProxyModel::columnsInserted, d,
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsInserted, d,
&QSortFilterProxyModelPrivate::_q_sourceColumnsInserted),
- QObjectPrivate::connect(d->model, &QSortFilterProxyModel::rowsAboutToBeRemoved, d,
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsAboutToBeRemoved, d,
&QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeRemoved),
- QObjectPrivate::connect(d->model, &QSortFilterProxyModel::rowsRemoved, d,
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsRemoved, d,
&QSortFilterProxyModelPrivate::_q_sourceRowsRemoved),
- QObjectPrivate::connect(d->model, &QSortFilterProxyModel::columnsAboutToBeRemoved, d,
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsAboutToBeRemoved, d,
&QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeRemoved),
- QObjectPrivate::connect(d->model, &QSortFilterProxyModel::columnsRemoved, d,
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsRemoved, d,
&QSortFilterProxyModelPrivate::_q_sourceColumnsRemoved),
- QObjectPrivate::connect(d->model, &QSortFilterProxyModel::rowsAboutToBeMoved, d,
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsAboutToBeMoved, d,
&QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeMoved),
- QObjectPrivate::connect(d->model, &QSortFilterProxyModel::rowsMoved, d,
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsMoved, d,
&QSortFilterProxyModelPrivate::_q_sourceRowsMoved),
- QObjectPrivate::connect(d->model, &QSortFilterProxyModel::columnsAboutToBeMoved, d,
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsAboutToBeMoved, d,
&QSortFilterProxyModelPrivate::_q_sourceColumnsAboutToBeMoved),
- QObjectPrivate::connect(d->model, &QSortFilterProxyModel::columnsMoved, d,
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsMoved, d,
&QSortFilterProxyModelPrivate::_q_sourceColumnsMoved),
- QObjectPrivate::connect(d->model, &QSortFilterProxyModel::layoutAboutToBeChanged, d,
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::layoutAboutToBeChanged, d,
&QSortFilterProxyModelPrivate::_q_sourceLayoutAboutToBeChanged),
- QObjectPrivate::connect(d->model, &QSortFilterProxyModel::layoutChanged, d,
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::layoutChanged, d,
&QSortFilterProxyModelPrivate::_q_sourceLayoutChanged),
- QObjectPrivate::connect(d->model, &QSortFilterProxyModel::modelAboutToBeReset, d,
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::modelAboutToBeReset, d,
&QSortFilterProxyModelPrivate::_q_sourceAboutToBeReset),
- QObjectPrivate::connect(d->model, &QSortFilterProxyModel::modelReset, d,
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::modelReset, d,
&QSortFilterProxyModelPrivate::_q_sourceReset)
};
endResetModel();
@@ -2435,11 +2435,7 @@ bool QSortFilterProxyModel::removeColumns(int column, int count, const QModelInd
*/
void QSortFilterProxyModel::fetchMore(const QModelIndex &parent)
{
- Q_D(QSortFilterProxyModel);
- QModelIndex source_parent;
- if (d->indexValid(parent))
- source_parent = mapToSource(parent);
- d->model->fetchMore(source_parent);
+ QAbstractProxyModel::fetchMore(parent);
}
/*!
@@ -2447,11 +2443,7 @@ void QSortFilterProxyModel::fetchMore(const QModelIndex &parent)
*/
bool QSortFilterProxyModel::canFetchMore(const QModelIndex &parent) const
{
- Q_D(const QSortFilterProxyModel);
- QModelIndex source_parent;
- if (d->indexValid(parent))
- source_parent = mapToSource(parent);
- return d->model->canFetchMore(source_parent);
+ return QAbstractProxyModel::canFetchMore(parent);
}
/*!
@@ -2459,11 +2451,7 @@ bool QSortFilterProxyModel::canFetchMore(const QModelIndex &parent) const
*/
Qt::ItemFlags QSortFilterProxyModel::flags(const QModelIndex &index) const
{
- Q_D(const QSortFilterProxyModel);
- QModelIndex source_index;
- if (d->indexValid(index))
- source_index = mapToSource(index);
- return d->model->flags(source_index);
+ return QAbstractProxyModel::flags(index);
}
/*!
@@ -2504,7 +2492,10 @@ QSize QSortFilterProxyModel::span(const QModelIndex &index) const
}
/*!
- \reimp
+ \reimp
+ Sorts the model by \a column in the given \a order.
+ If the sort \a column is less than zero, the model will be sorted by source model row
+ in the given \a order.
*/
void QSortFilterProxyModel::sort(int column, Qt::SortOrder order)
{
@@ -2583,10 +2574,11 @@ void QSortFilterProxyModel::setFilterRegularExpression(const QRegularExpression
{
Q_D(QSortFilterProxyModel);
const QScopedPropertyUpdateGroup guard;
- const bool regExpChanged = regularExpression != d->filter_regularexpression.value();
+ const bool regExpChanged =
+ regularExpression != d->filter_regularexpression.valueBypassingBindings();
d->filter_regularexpression.removeBindingUnlessInWrapper();
d->filter_casesensitive.removeBindingUnlessInWrapper();
- const Qt::CaseSensitivity cs = filterCaseSensitivity();
+ const Qt::CaseSensitivity cs = d->filter_casesensitive.valueBypassingBindings();
d->filter_about_to_be_changed();
const Qt::CaseSensitivity updatedCs =
regularExpression.patternOptions() & QRegularExpression::CaseInsensitiveOption
@@ -2627,7 +2619,7 @@ void QSortFilterProxyModel::setFilterKeyColumn(int column)
Q_D(QSortFilterProxyModel);
d->filter_column.removeBindingUnlessInWrapper();
d->filter_about_to_be_changed();
- const auto oldColumn = d->filter_column.value();
+ const auto oldColumn = d->filter_column.valueBypassingBindings();
d->filter_column.setValueBypassingBindings(column);
d->filter_changed(QSortFilterProxyModelPrivate::Direction::Rows);
if (oldColumn != column)
@@ -2925,7 +2917,7 @@ void QSortFilterProxyModel::setSortRole(int role)
{
Q_D(QSortFilterProxyModel);
d->sort_role.removeBindingUnlessInWrapper();
- if (d->sort_role == role)
+ if (d->sort_role.valueBypassingBindings() == role)
return;
d->sort_role.setValueBypassingBindings(role);
d->sort();
@@ -2964,7 +2956,7 @@ void QSortFilterProxyModel::setFilterRole(int role)
{
Q_D(QSortFilterProxyModel);
d->filter_role.removeBindingUnlessInWrapper();
- if (d->filter_role == role)
+ if (d->filter_role.valueBypassingBindings() == role)
return;
d->filter_about_to_be_changed();
d->filter_role.setValueBypassingBindings(role);
diff --git a/src/corelib/itemmodels/qstringlistmodel.cpp b/src/corelib/itemmodels/qstringlistmodel.cpp
index 002f500263..dfbe72b289 100644
--- a/src/corelib/itemmodels/qstringlistmodel.cpp
+++ b/src/corelib/itemmodels/qstringlistmodel.cpp
@@ -292,12 +292,12 @@ bool QStringListModel::moveRows(const QModelIndex &sourceParent, int sourceRow,
return true;
}
-static bool ascendingLessThan(const QPair<QString, int> &s1, const QPair<QString, int> &s2)
+static bool ascendingLessThan(const std::pair<QString, int> &s1, const std::pair<QString, int> &s2)
{
return s1.first < s2.first;
}
-static bool decendingLessThan(const QPair<QString, int> &s1, const QPair<QString, int> &s2)
+static bool decendingLessThan(const std::pair<QString, int> &s1, const std::pair<QString, int> &s2)
{
return s1.first > s2.first;
}
@@ -309,11 +309,11 @@ void QStringListModel::sort(int, Qt::SortOrder order)
{
emit layoutAboutToBeChanged(QList<QPersistentModelIndex>(), VerticalSortHint);
- QList<QPair<QString, int>> list;
+ QList<std::pair<QString, int>> list;
const int lstCount = lst.size();
list.reserve(lstCount);
for (int i = 0; i < lstCount; ++i)
- list.append(QPair<QString, int>(lst.at(i), i));
+ list.emplace_back(lst.at(i), i);
if (order == Qt::AscendingOrder)
std::sort(list.begin(), list.end(), ascendingLessThan);
diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp
index 3001e3269b..f3056a399c 100644
--- a/src/corelib/kernel/qabstracteventdispatcher.cpp
+++ b/src/corelib/kernel/qabstracteventdispatcher.cpp
@@ -9,9 +9,12 @@
#include <private/qthread_p.h>
#include <private/qcoreapplication_p.h>
#include <private/qfreelist_p.h>
+#include <private/qnumeric_p.h>
QT_BEGIN_NAMESPACE
+using namespace std::chrono_literals;
+
// we allow for 2^24 = 8^8 = 16777216 simultaneously running timers
struct QtTimerIdFreeListConstants : public QFreeListDefaultConstants
{
@@ -52,6 +55,38 @@ Q_CONSTINIT const int QtTimerIdFreeListConstants::Sizes[QtTimerIdFreeListConstan
typedef QFreeList<void, QtTimerIdFreeListConstants> QtTimerIdFreeList;
Q_GLOBAL_STATIC(QtTimerIdFreeList, timerIdFreeList)
+template <typename T> static T fromDuration(std::chrono::nanoseconds interval)
+{
+ using namespace std::chrono;
+ qint64 value = ceil<milliseconds>(interval).count();
+ return qt_saturate<T>(value);
+}
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+static inline QAbstractEventDispatcherV2 *v2(QAbstractEventDispatcher *self)
+{
+ if (QAbstractEventDispatcherPrivate::get(self)->isV2)
+ return static_cast<QAbstractEventDispatcherV2 *>(self);
+ return nullptr;
+}
+
+static inline const QAbstractEventDispatcherV2 *v2(const QAbstractEventDispatcher *self)
+{
+ if (QAbstractEventDispatcherPrivate::get(self)->isV2)
+ return static_cast<const QAbstractEventDispatcherV2 *>(self);
+ return nullptr;
+}
+#endif // Qt 7
+
+QAbstractEventDispatcherPrivate::QAbstractEventDispatcherPrivate()
+{
+ // Create the timer ID free list here to make sure that it is destroyed
+ // after any global static thread that may be using it.
+ // See also QTBUG-58732.
+ if (!timerIdFreeList.isDestroyed())
+ (void)timerIdFreeList();
+}
+
QAbstractEventDispatcherPrivate::~QAbstractEventDispatcherPrivate()
= default;
@@ -112,6 +147,15 @@ void QAbstractEventDispatcherPrivate::releaseTimerId(int timerId)
\sa QEventLoop, QCoreApplication, QThread
*/
+/*!
+ \typedef QAbstractEventDispatcher::Duration
+
+ A \c{std::chrono::duration} type that is used in various API in this class.
+ This type exists to facilitate a possible transition to a higher or lower
+ granularity.
+
+ In all current platforms, it is \c nanoseconds.
+*/
/*!
Constructs a new event dispatcher with the given \a parent.
@@ -205,16 +249,39 @@ QAbstractEventDispatcher *QAbstractEventDispatcher::instance(QThread *thread)
*/
/*!
+ \obsolete [6.8] This function will be removed in Qt 7. Use the overload taking \l Duration.
+
Registers a timer with the specified \a interval and \a timerType for the
given \a object and returns the timer id.
*/
int QAbstractEventDispatcher::registerTimer(qint64 interval, Qt::TimerType timerType, QObject *object)
{
- int id = QAbstractEventDispatcherPrivate::allocateTimerId();
+ return int(registerTimer(interval * 1ms, timerType, object));
+}
+
+/*!
+ \since 6.8
+ \overload
+
+ Registers a timer with the specified \a interval and \a timerType for the
+ given \a object and returns the timer id.
+*/
+Qt::TimerId QAbstractEventDispatcher::registerTimer(Duration interval, Qt::TimerType timerType,
+ QObject *object)
+{
+ auto id = Qt::TimerId(QAbstractEventDispatcherPrivate::allocateTimerId());
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ if (QAbstractEventDispatcherV2 *self = v2(this))
+ self->registerTimer(id, interval, timerType, object);
+ else
+ registerTimer(qToUnderlying(id), fromDuration<qint64>(interval), timerType, object);
+#else
registerTimer(id, interval, timerType, object);
+#endif
return id;
}
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
/*!
\fn void QAbstractEventDispatcher::registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object)
@@ -232,15 +299,6 @@ int QAbstractEventDispatcher::registerTimer(qint64 interval, Qt::TimerType timer
*/
/*!
- \fn bool QAbstractEventDispatcher::unregisterTimers(QObject *object)
-
- Unregisters all the timers associated with the given \a object.
- Returns \c true if all timers were successful removed; otherwise returns \c false.
-
- \sa unregisterTimer(), registeredTimers()
-*/
-
-/*!
\fn QList<TimerInfo> QAbstractEventDispatcher::registeredTimers(QObject *object) const
Returns a list of registered timers for \a object. The TimerInfo struct has
@@ -258,6 +316,57 @@ int QAbstractEventDispatcher::registerTimer(qint64 interval, Qt::TimerType timer
\sa Qt::TimerType
*/
+#else // Qt 7
+/*!
+ \fn void QAbstractEventDispatcher::registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType, QObject *object)
+ \since 6.8
+
+ Register a timer with the specified \a timerId, \a interval, and \a
+ timerType for the given \a object.
+
+ \sa unregisterTimer(), timersForObject()
+*/
+
+/*!
+ \fn bool QAbstractEventDispatcher::unregisterTimer(Qt::TimerId timerId)
+ \since 6.8
+
+ Unregisters the timer with the given \a timerId.
+ Returns \c true if successful; otherwise returns \c false.
+
+ \sa registerTimer(), unregisterTimers()
+*/
+
+/*!
+ \fn QList<TimerInfoV2> QAbstractEventDispatcher::timersForObject(QObject *object) const
+ \since 6.8
+
+ Returns a list of registered timers for \a object. The TimerInfoV2 struct has
+ \c timerId, \c interval, and \c timerType members.
+
+ \sa Qt::TimerType, registerTimer(), unregisterTimer()
+*/
+
+/*!
+ \fn QAbstractEventDispatcher::remainingTime(Qt::TimerId timerId) const
+
+ Returns the remaining time of the timer with the given \a timerId.
+ If the timer is inactive, the returned value will be negative. If the timer
+ is overdue, the returned value will be 0.
+
+ \sa Qt::TimerType, registerTimer(), unregisterTimer()
+*/
+#endif
+
+/*!
+ \fn bool QAbstractEventDispatcher::unregisterTimers(QObject *object)
+
+ Unregisters all the timers associated with the given \a object. Returns \c
+ true if all timers were successfully removed; otherwise returns \c false.
+
+ \sa unregisterTimer(), registeredTimers()
+*/
+
/*! \fn void QAbstractEventDispatcher::wakeUp()
\threadsafe
@@ -299,6 +408,7 @@ void QAbstractEventDispatcher::closingDown()
/*!
\class QAbstractEventDispatcher::TimerInfo
+ \deprecated [6.8] Use TimerInfoV2
\inmodule QtCore
This struct represents information about a timer:
@@ -306,7 +416,7 @@ void QAbstractEventDispatcher::closingDown()
\l{QAbstractEventDispatcher::TimerInfo::interval}{interval}, and
\l{QAbstractEventDispatcher::TimerInfo::timerType}{timerType}.
- \sa registeredTimers()
+ \sa registeredTimers(), QAbstractEventDispatcher::TimerInfoV2, timersForObject()
*/
/*! \fn QAbstractEventDispatcher::TimerInfo::TimerInfo(int timerId, int interval, Qt::TimerType timerType)
@@ -332,6 +442,37 @@ void QAbstractEventDispatcher::closingDown()
*/
/*!
+ \class QAbstractEventDispatcher::TimerInfoV2
+ \inmodule QtCore
+
+ This struct represents information about a timer:
+ \l{QAbstractEventDispatcher::TimerInfoV2::timerId}{timerId},
+ \l{QAbstractEventDispatcher::TimerInfoV2::interval}{interval}, and
+ \l{QAbstractEventDispatcher::TimerInfoV2::timerType}{timerType}.
+
+ \sa timersForObject()
+*/
+/*!
+ \variable QAbstractEventDispatcher::TimerInfoV2::timerId
+
+ The timer's unique id. This is created by registerTimer() upon creation and
+ uniquely identifies a timer while it is active. It is also used by
+ QTimer::id() and returned by QObject::startTimer().
+*/
+/*!
+ \variable QAbstractEventDispatcher::TimerInfoV2::interval
+
+ The timer's interval.
+*/
+/*!
+ \variable QAbstractEventDispatcher::TimerInfoV2::timerType
+
+ The timer's type
+
+ \sa Qt::TimerType
+*/
+
+/*!
Installs an event filter \a filterObj for all native events received by the application.
The event filter \a filterObj receives events via its \l {QAbstractNativeEventFilter::}{nativeEventFilter()}
@@ -443,6 +584,126 @@ bool QAbstractEventDispatcher::filterNativeEvent(const QByteArray &eventType, vo
\sa awake()
*/
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+void QAbstractEventDispatcher::registerTimer(Qt::TimerId timerId, Duration interval,
+ Qt::TimerType timerType, QObject *object)
+{
+ if (QAbstractEventDispatcherV2 *self = v2(this))
+ self->registerTimer(timerId, interval, timerType, object);
+ else
+ registerTimer(int(timerId), fromDuration<qint64>(interval), timerType, object);
+}
+
+bool QAbstractEventDispatcher::unregisterTimer(Qt::TimerId timerId)
+{
+ if (QAbstractEventDispatcherV2 *self = v2(this))
+ return self->unregisterTimer(timerId);
+ return unregisterTimer(int(timerId));
+}
+
+QList<QAbstractEventDispatcher::TimerInfoV2>
+QAbstractEventDispatcher::timersForObject(QObject *object) const
+{
+ if (const QAbstractEventDispatcherV2 *self = v2(this))
+ return self->timersForObject(object);
+ QList<TimerInfo> timers = registeredTimers(object);
+ QList<TimerInfoV2> result;
+ result.reserve(timers.size());
+ for (const TimerInfo &t : timers)
+ result.emplaceBack(TimerInfoV2{ t.interval * 1ms, Qt::TimerId(t.timerId), t.timerType });
+ return result;
+}
+
+QAbstractEventDispatcher::Duration
+QAbstractEventDispatcher::remainingTime(Qt::TimerId timerId) const
+{
+ if (const QAbstractEventDispatcherV2 *self = v2(this))
+ return self->remainingTime(timerId);
+ return const_cast<QAbstractEventDispatcher *>(this)->remainingTime(int(timerId)) * 1ms;
+}
+
+/*!
+ \class QAbstractEventDispatcherV2
+ \inmodule QtCore
+
+ This class is a temporary hack to enable transition to an API based on
+ \c{std::chrono} for the Qt event dispatcher. In Qt 7, it will be merged
+ with QAbstractEventDispatcher, replacing the pure virtuals there with the
+ ones defined here.
+
+ It is recommended applications and libraries port to the new API before
+ that future release to simplify work when the time comes.
+*/
+
+/*!
+ Constructs a new event dispatcher with the given \a parent.
+*/
+QAbstractEventDispatcherV2::QAbstractEventDispatcherV2(QObject *parent)
+ : QAbstractEventDispatcherV2(*new QAbstractEventDispatcherPrivate, parent)
+{
+}
+
+/*!
+ \internal
+*/
+QAbstractEventDispatcherV2::QAbstractEventDispatcherV2(QAbstractEventDispatcherPrivate &dd,
+ QObject *parent)
+ : QAbstractEventDispatcher((dd.isV2 = true, dd), parent)
+{
+}
+
+/*!
+ Destroys the event dispatcher.
+*/
+QAbstractEventDispatcherV2::~QAbstractEventDispatcherV2() = default;
+
+/*!
+ \internal
+ Temporary compatibility override.
+*/
+void QAbstractEventDispatcherV2::registerTimer(int timerId, qint64 interval,
+ Qt::TimerType timerType, QObject *object)
+{
+ auto self = static_cast<QAbstractEventDispatcherV2 *>(this);
+ self->registerTimer(Qt::TimerId(timerId), interval * 1ms, timerType, object);
+}
+
+/*!
+ \internal
+ Temporary compatibility override.
+*/
+bool QAbstractEventDispatcherV2::unregisterTimer(int timerId)
+{
+ auto self = static_cast<QAbstractEventDispatcherV2 *>(this);
+ return self->unregisterTimer(Qt::TimerId(timerId));
+}
+
+/*!
+ \internal
+ Temporary compatibility override.
+*/
+auto QAbstractEventDispatcherV2::registeredTimers(QObject *object) const -> QList<TimerInfo>
+{
+ auto self = static_cast<const QAbstractEventDispatcherV2 *>(this);
+ QList<TimerInfoV2> timers = self->timersForObject(object);
+ QList<TimerInfo> result;
+ result.reserve(timers.size());
+ for (const TimerInfoV2 &t : timers)
+ result.emplaceBack(qToUnderlying(t.timerId), fromDuration<int>(t.interval), t.timerType);
+ return result;
+}
+
+/*!
+ \internal
+ Temporary compatibility override.
+*/
+int QAbstractEventDispatcherV2::remainingTime(int timerId)
+{
+ auto self = static_cast<QAbstractEventDispatcherV2 *>(this);
+ return fromDuration<int>(self->remainingTime(Qt::TimerId(timerId)));
+}
+#endif // ! Qt 7
+
QT_END_NAMESPACE
#include "moc_qabstracteventdispatcher.cpp"
diff --git a/src/corelib/kernel/qabstracteventdispatcher.h b/src/corelib/kernel/qabstracteventdispatcher.h
index 4026bde347..ad97a93ba2 100644
--- a/src/corelib/kernel/qabstracteventdispatcher.h
+++ b/src/corelib/kernel/qabstracteventdispatcher.h
@@ -19,6 +19,7 @@ class Q_CORE_EXPORT QAbstractEventDispatcher : public QObject
Q_DECLARE_PRIVATE(QAbstractEventDispatcher)
public:
+ using Duration = std::chrono::nanoseconds;
struct TimerInfo
{
int timerId;
@@ -28,6 +29,12 @@ public:
inline TimerInfo(int id, int i, Qt::TimerType t)
: timerId(id), interval(i), timerType(t) { }
};
+ struct TimerInfoV2
+ {
+ Duration interval;
+ Qt::TimerId timerId;
+ Qt::TimerType timerType;
+ };
explicit QAbstractEventDispatcher(QObject *parent = nullptr);
~QAbstractEventDispatcher();
@@ -39,14 +46,29 @@ public:
virtual void registerSocketNotifier(QSocketNotifier *notifier) = 0;
virtual void unregisterSocketNotifier(QSocketNotifier *notifier) = 0;
+ Qt::TimerId registerTimer(Duration interval, Qt::TimerType timerType, QObject *object);
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
int registerTimer(qint64 interval, Qt::TimerType timerType, QObject *object);
+
+ // old, integer-based API
virtual void registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object) = 0;
virtual bool unregisterTimer(int timerId) = 0;
- virtual bool unregisterTimers(QObject *object) = 0;
virtual QList<TimerInfo> registeredTimers(QObject *object) const = 0;
-
virtual int remainingTime(int timerId) = 0;
+ void registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType, QObject *object);
+ bool unregisterTimer(Qt::TimerId timerId);
+ QList<TimerInfoV2> timersForObject(QObject *object) const;
+ Duration remainingTime(Qt::TimerId timerId) const;
+#else
+ virtual void registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType, QObject *object) = 0;
+ virtual bool unregisterTimer(Qt::TimerId timerId) = 0;
+ virtual QList<TimerInfoV2> timersForObject(QObject *object) const = 0;
+ virtual Duration remainingTime(Qt::TimerId timerId) const = 0;
+#endif
+ virtual bool unregisterTimers(QObject *object) = 0;
+
virtual void wakeUp() = 0;
virtual void interrupt() = 0;
@@ -67,6 +89,40 @@ protected:
};
Q_DECLARE_TYPEINFO(QAbstractEventDispatcher::TimerInfo, Q_PRIMITIVE_TYPE);
+Q_DECLARE_TYPEINFO(QAbstractEventDispatcher::TimerInfoV2, Q_PRIMITIVE_TYPE);
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+class Q_CORE_EXPORT QAbstractEventDispatcherV2 : public QAbstractEventDispatcher
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QAbstractEventDispatcher) // not V2
+
+public:
+ explicit QAbstractEventDispatcherV2(QObject *parent = nullptr);
+ ~QAbstractEventDispatcherV2();
+
+ // new virtuals
+ virtual void registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType,
+ QObject *object) = 0;
+ virtual bool unregisterTimer(Qt::TimerId timerId) = 0;
+ virtual QList<TimerInfoV2> timersForObject(QObject *object) const = 0;
+ virtual Duration remainingTime(Qt::TimerId timerId) const = 0;
+
+protected:
+ QAbstractEventDispatcherV2(QAbstractEventDispatcherPrivate &, QObject *parent);
+
+private:
+ // final overrides from V1
+ virtual void registerTimer(int timerId, qint64 interval, Qt::TimerType timerType,
+ QObject *object) override final;
+ virtual bool unregisterTimer(int timerId) override final;
+ virtual QList<TimerInfo> registeredTimers(QObject *object) const override final;
+
+ virtual int remainingTime(int timerId) override final;
+};
+#else
+using QAbstractEventDispatcherV2 = QAbstractEventDispatcher;
+#endif // Qt 7
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qabstracteventdispatcher_p.h b/src/corelib/kernel/qabstracteventdispatcher_p.h
index e7b1ac3b24..2576027d52 100644
--- a/src/corelib/kernel/qabstracteventdispatcher_p.h
+++ b/src/corelib/kernel/qabstracteventdispatcher_p.h
@@ -16,7 +16,9 @@
//
#include "QtCore/qabstracteventdispatcher.h"
+#include "QtCore/qnamespace.h"
#include "private/qobject_p.h"
+#include "QtCore/qttypetraits.h"
QT_BEGIN_NAMESPACE
@@ -26,14 +28,22 @@ class Q_CORE_EXPORT QAbstractEventDispatcherPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QAbstractEventDispatcher)
public:
- inline QAbstractEventDispatcherPrivate()
- { }
+ QAbstractEventDispatcherPrivate();
~QAbstractEventDispatcherPrivate() override;
QList<QAbstractNativeEventFilter *> eventFilters;
+ bool isV2 = false;
+
static int allocateTimerId();
static void releaseTimerId(int id);
+ static void releaseTimerId(Qt::TimerId id)
+ { releaseTimerId(qToUnderlying(id)); }
+
+ static QAbstractEventDispatcherPrivate *get(QAbstractEventDispatcher *o)
+ { return o->d_func(); }
+ static const QAbstractEventDispatcherPrivate *get(const QAbstractEventDispatcher *o)
+ { return o->d_func(); }
};
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qapplicationstatic.h b/src/corelib/kernel/qapplicationstatic.h
index 2f2cab9174..bf5e79b8bf 100644
--- a/src/corelib/kernel/qapplicationstatic.h
+++ b/src/corelib/kernel/qapplicationstatic.h
@@ -30,7 +30,8 @@ template <typename QAS> struct ApplicationHolder
Q_DISABLE_COPY_MOVE(ApplicationHolder)
~ApplicationHolder()
{
- if (guard.loadRelaxed() == QtGlobalStatic::Initialized) {
+ if (guard.loadAcquire() == QtGlobalStatic::Initialized) {
+ // No mutex! Up to external code to ensure no race happens.
guard.storeRelease(QtGlobalStatic::Destroyed);
realPointer()->~PlainType();
}
@@ -44,24 +45,26 @@ template <typename QAS> struct ApplicationHolder
// called from QGlobalStatic::instance()
PlainType *pointer() noexcept(MutexLockIsNoexcept && ConstructionIsNoexcept)
{
- if (guard.loadRelaxed() == QtGlobalStatic::Initialized)
+ if (guard.loadAcquire() == QtGlobalStatic::Initialized)
return realPointer();
QMutexLocker locker(&mutex);
if (guard.loadRelaxed() == QtGlobalStatic::Uninitialized) {
QAS::innerFunction(&storage);
- QObject::connect(QCoreApplication::instance(), &QObject::destroyed, reset);
- guard.storeRelaxed(QtGlobalStatic::Initialized);
+ const auto *app = QCoreApplication::instance();
+ Q_ASSERT_X(app, Q_FUNC_INFO,
+ "The application static was used without a QCoreApplication instance");
+ QObject::connect(app, &QObject::destroyed, app, reset, Qt::DirectConnection);
+ guard.storeRelease(QtGlobalStatic::Initialized);
}
return realPointer();
}
static void reset()
{
- if (guard.loadRelaxed() == QtGlobalStatic::Initialized) {
- QMutexLocker locker(&mutex);
- realPointer()->~PlainType();
- guard.storeRelaxed(QtGlobalStatic::Uninitialized);
- }
+ // we only synchronize using the mutex here, not the guard
+ QMutexLocker locker(&mutex);
+ realPointer()->~PlainType();
+ guard.storeRelaxed(QtGlobalStatic::Uninitialized);
}
};
} // namespace QtGlobalStatic
diff --git a/src/corelib/kernel/qapplicationstatic.qdoc b/src/corelib/kernel/qapplicationstatic.qdoc
index 82eb7265ff..5cbac65df9 100644
--- a/src/corelib/kernel/qapplicationstatic.qdoc
+++ b/src/corelib/kernel/qapplicationstatic.qdoc
@@ -20,9 +20,8 @@
the QCoreApplication. This makes it ideal to store semi-static QObjects, which
should also be destroyed once the QCoreApplication is destroyed. This means the
type will get deleted once the QCoreApplication emits the destroyed signal.
- However, as long as the actual holder is still in the initialized state, the
- type will be recreated when it's accessed again once a new QCoreApplication
- has been created.
+ It is permitted for the object to be recreated when it's accessed again, if
+ a new QCoreApplication has also been created.
Since the value is bound to the QCoreApplication, it should only ever be
accessed if there is a valid QCoreApplication::instance(). Accessing this
@@ -45,6 +44,31 @@
this macro behaves identically to Q_GLOBAL_STATIC(). Please see that macro's
documentation for more information.
+ \section1 Threading guarantees
+
+ The Q_APPLICATION_STATIC macro ensures that the object is initialized only
+ once (per lifetime of a QCoreApplication), even if multiple threads try to
+ concurrently access the object. This is done by providing a per-object
+ mutex; application and library developers need to be aware that their
+ object will be constructed with this mutex locked and therefore must not
+ reenter the same object's initialization, or a deadlock will occur.
+
+ There is no thread-safety on the destruction of the object: user code must
+ not access this object once the QCoreApplication destructor starts to run.
+ User code must arrange to ensure this does not happen, such as by not
+ accessing it once the main thread's event loop has exited.
+
+ Like Q_GLOBAL_STATIC, Q_APPLICATION_STATIC provides no thread-safety
+ guarantees for accesses to the object once creation is finished. It is up
+ to user code to ensure that no racy data accesses happen.
+
+ In case the object created by this operation is a QObject, its associated
+ thread will be the one that succeeded in creating it. It will be destroyed
+ by the main thread, so a \l{QObject::}{moveToThread()} to the main thread
+ or to no thread before destruction is adviseable. Doing so from the
+ constructor of the class in question is a sensible solution if one can't
+ guarantee that the main thread will be the one to initialize the object.
+
\omit
\section1 Implementation details
See \l Q_GLOBAL_STATIC implementation details for an introduction.
diff --git a/src/corelib/kernel/qbasictimer.cpp b/src/corelib/kernel/qbasictimer.cpp
index b843ec1ecf..17711a355e 100644
--- a/src/corelib/kernel/qbasictimer.cpp
+++ b/src/corelib/kernel/qbasictimer.cpp
@@ -33,10 +33,8 @@ QT_BEGIN_NAMESPACE
can maintain a list of basic timers by holding them in container
that supports move-only types, e.g. std::vector.
- The \l{widgets/tetrix}{Tetrix} example uses QBasicTimer to control
- the rate at which pieces fall.
-
- \sa QTimer, QTimerEvent, QObject::timerEvent(), Timers, {Affine Transformations}
+ \sa QTimer, QChronoTimer, QTimerEvent, QObject::timerEvent(),
+ Timers, {Affine Transformations}
*/
@@ -86,10 +84,18 @@ QT_BEGIN_NAMESPACE
/*!
\fn QBasicTimer::swap(QBasicTimer &other)
+ \since 5.14
+
+ Swaps the timer \a other with this timer.
+ This operation is very fast and never fails.
+*/
+
+/*!
\fn swap(QBasicTimer &lhs, QBasicTimer &rhs)
+ \relates QBasicTimer
\since 5.14
- Swaps string \a other with this string, or \a lhs with \a rhs.
+ Swaps the timer \a lhs with \a rhs.
This operation is very fast and never fails.
*/
@@ -159,7 +165,7 @@ void QBasicTimer::start(std::chrono::milliseconds duration, Qt::TimerType timerT
}
stop();
if (obj)
- id = eventDispatcher->registerTimer(duration.count(), timerType, obj);
+ id = int(eventDispatcher->registerTimer(duration, timerType, obj));
}
/*!
@@ -171,7 +177,7 @@ void QBasicTimer::stop()
{
if (id) {
QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance();
- if (eventDispatcher && !eventDispatcher->unregisterTimer(id)) {
+ if (eventDispatcher && !eventDispatcher->unregisterTimer(Qt::TimerId(id))) {
qWarning("QBasicTimer::stop: Failed. Possibly trying to stop from a different thread");
return;
}
diff --git a/src/corelib/kernel/qchronotimer.cpp b/src/corelib/kernel/qchronotimer.cpp
new file mode 100644
index 0000000000..a517c4446b
--- /dev/null
+++ b/src/corelib/kernel/qchronotimer.cpp
@@ -0,0 +1,452 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qchronotimer.h"
+#include "qtimer_p.h"
+#include "qsingleshottimer_p.h"
+
+#include "qabstracteventdispatcher.h"
+#include "qcoreapplication.h"
+#include "qcoreapplication_p.h"
+#include "qdeadlinetimer.h"
+#include "qmetaobject_p.h"
+#include "qobject_p.h"
+#include "qproperty_p.h"
+#include "qthread.h"
+
+using namespace std::chrono_literals;
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QChronoTimer
+ \inmodule QtCore
+ \since 6.8
+ \ingroup events
+
+ \brief The QChronoTimer class provides repetitive and single-shot timers.
+
+ The QChronoTimer class provides a high-level programming interface for
+ timers. To use it, create a QChronoTimer, either passing the interval to the
+ constructor, or setting it after construction using setInterval(), connect
+ its timeout() signal to the appropriate slots, and call start(). From then
+ on, it will emit the timeout() signal at constant intervals. For example:
+
+ \snippet timers/timers.cpp timer-interval-in-ctor
+ \snippet timers/timers.cpp timer-setinterval
+
+ You can set a timer to time out only once by calling setSingleShot(true).
+
+ QChronoTimer also has singleShot() static methods:
+
+ \snippet timers/timers.cpp qchronotimer-singleshot
+
+ In multithreaded applications, you can use QChronoTimer in any thread
+ that has an event loop. To start an event loop from a non-GUI
+ thread, use QThread::exec(). Qt uses the timer's
+ \l{QObject::thread()}{thread affinity} to determine which thread
+ will emit the \l{QChronoTimer::}{timeout()} signal. Because of this, you
+ must start and stop the timer in its thread; it is not possible to
+ start a timer from another thread.
+
+ As a special case, a QChronoTimer with a timeout of \c 0ns will time out
+ as soon as possible, though the ordering between zero timers and other
+ sources of events is unspecified. Zero timers can be used to do some
+ work while still providing a responsive user interface:
+
+ \snippet timers/timers.cpp zero-timer
+
+ From then on, \c processOneThing() will be called repeatedly. It should
+ be written in such a way that it always returns quickly (for example,
+ after processing one data item) so that Qt can deliver events to the user
+ interface and stop the timer as soon as it has done all its work. This
+ is the traditional way of implementing heavy work in GUI applications,
+ but as multithreading is becoming available on more platforms, a modern
+ alternative is doing the heavy work in a thread other than the GUI (main)
+ thread. Qt has the QThread class, which can be used to achieve that.
+
+ \section1 Accuracy and Timer Resolution
+
+ The accuracy of timers depends on the underlying operating system and
+ hardware. Most platforms support requesting nano-second precision for
+ timers (for example, libc's \c nanosleep), though the accuracy of the
+ timer will not equal this resolution in many real-world situations.
+
+ You can set the \l{Qt::TimerType}{timer type} to tell QChronoTimer which
+ precision to request from the system.
+
+ For Qt::PreciseTimer, QChronoTimer will try to keep the precision at
+ \c 1ns. Precise timers will never time out earlier than expected.
+
+ For Qt::CoarseTimer and Qt::VeryCoarseTimer types, QChronoTimer may wake
+ up earlier than expected, within the margins for those types:
+ \list
+ \li 5% of the interval for Qt::CoarseTimer
+ \li \c 500ms for Qt::VeryCoarseTimer
+ \endlist
+
+ All timer types may time out later than expected if the system is busy or
+ unable to provide the requested accuracy. In such a case of timeout
+ overrun, Qt will emit timeout() only once, even if multiple timeouts have
+ expired, and then will resume the original interval.
+
+ \section1 Alternatives to QChronoTimer
+
+ An alternative to using QChronoTimer is to call QObject::startTimer()
+ for your object and reimplement the QObject::timerEvent() event handler
+ in your class (which must be a sub-class of QObject). The disadvantage
+ is that timerEvent() does not support such high-level features as
+ single-shot timers or signals.
+
+ Another alternative is QBasicTimer. It is typically less cumbersome
+ than using QObject::startTimer() directly. See \l{Timers} for an
+ overview of all three approaches.
+
+ Some operating systems limit the number of timers that may be used;
+ Qt does its best to work around these limitations.
+
+ \sa QBasicTimer, QTimerEvent, QObject::timerEvent(), Timers,
+ {Analog Clock}
+*/
+
+/*!
+ Constructs a timer with the given \a parent, using the default interval,
+ \c 0ns.
+*/
+QChronoTimer::QChronoTimer(QObject *parent)
+ : QChronoTimer(0ns, parent)
+{
+}
+
+/*!
+ Constructs a timer with the given \a parent, using an interval of \a nsec.
+*/
+QChronoTimer::QChronoTimer(std::chrono::nanoseconds nsec, QObject *parent)
+ : QObject(*new QTimerPrivate(nsec, this), parent)
+{
+ Q_ASSERT(!d_func()->isQTimer);
+}
+
+/*!
+ Destroys the timer.
+*/
+QChronoTimer::~QChronoTimer()
+{
+ if (d_func()->isActive()) // stop running timer
+ stop();
+}
+
+/*!
+ \fn void QChronoTimer::timeout()
+
+ This signal is emitted when the timer times out.
+
+ \sa interval, start(), stop()
+*/
+
+/*!
+ \property QChronoTimer::active
+
+ This boolean property is \c true if the timer is running; otherwise
+ \c false.
+*/
+
+/*!
+ Returns \c true if the timer is running (pending); otherwise returns
+ false.
+*/
+bool QChronoTimer::isActive() const
+{
+ return d_func()->isActiveData.value();
+}
+
+QBindable<bool> QChronoTimer::bindableActive()
+{
+ return QBindable<bool>(&d_func()->isActiveData);
+}
+
+/*!
+ Returns a Qt::TimerId representing the timer ID if the timer is running;
+ otherwise returns \c Qt::TimerId::Invalid.
+
+ \sa Qt::TimerId
+*/
+Qt::TimerId QChronoTimer::id() const
+{
+ return d_func()->id;
+}
+
+/*! \overload start()
+
+ Starts or restarts the timer with the timeout specified in \l interval.
+
+ If the timer is already running, it will be
+ \l{QChronoTimer::stop()}{stopped} and restarted.
+
+ If \l singleShot is true, the timer will be activated only once.
+*/
+void QChronoTimer::start()
+{
+ auto *d = d_func();
+ if (d->isActive()) // stop running timer
+ stop();
+ const auto id = Qt::TimerId{QObject::startTimer(d->intervalDuration, d->type)};
+ if (id > Qt::TimerId::Invalid) {
+ d->id = id;
+ d->isActiveData.notify();
+ }
+}
+
+/*!
+ Stops the timer.
+
+ \sa start()
+*/
+void QChronoTimer::stop()
+{
+ auto *d = d_func();
+ if (d->isActive()) {
+ QObject::killTimer(d->id);
+ d->id = Qt::TimerId::Invalid;
+ d->isActiveData.notify();
+ }
+}
+
+/*!
+ \reimp
+*/
+void QChronoTimer::timerEvent(QTimerEvent *e)
+{
+ auto *d = d_func();
+ if (Qt::TimerId{e->timerId()} == d->id) {
+ if (d->single)
+ stop();
+ Q_EMIT timeout(QPrivateSignal());
+ }
+}
+
+/*!
+ \fn template <typename Functor> QMetaObject::Connection QChronoTimer::callOnTimeout(const QObject *context, Functor &&slot, Qt::ConnectionType connectionType = Qt::AutoConnection)
+ \overload callOnTimeout()
+
+ Creates a connection from the timeout() signal to \a slot to be placed in a
+ specific event loop of \a context, with connection type \a connectionType,
+ and returns a handle to the connection.
+
+ This method is provided as a convenience. It's equivalent to calling:
+ \code
+ QObject::connect(timer, &QChronoTimer::timeout, context, slot, connectionType);
+ \endcode
+
+ \sa QObject::connect(), timeout()
+*/
+
+/*!
+ \property QChronoTimer::singleShot
+ \brief Whether the timer is a single-shot timer
+
+ A single-shot timer fires only once, non-single-shot timers fire every
+ \l interval.
+
+ The default value for this property is \c false.
+
+ \sa interval, singleShot()
+*/
+void QChronoTimer::setSingleShot(bool singleShot)
+{
+ d_func()->single = singleShot;
+}
+
+bool QChronoTimer::isSingleShot() const
+{
+ return d_func()->single;
+}
+
+QBindable<bool> QChronoTimer::bindableSingleShot()
+{
+ return QBindable<bool>(&d_func()->single);
+}
+
+/*!
+ \property QChronoTimer::interval
+ \brief The timeout interval
+
+ The default value for this property is \c 0ns.
+
+ A QChronoTimer with a timeout of \c 0ns will time out as soon as all
+ the events in the window system's event queue have been processed.
+
+ Setting the interval of an active timer changes the interval and acquires
+ a new id(). If the timer is not active, only the interval is changed.
+
+ \sa singleShot
+*/
+void QChronoTimer::setInterval(std::chrono::nanoseconds nsec)
+{
+ auto *d = d_func();
+ d->intervalDuration.removeBindingUnlessInWrapper();
+ const bool intervalChanged = nsec != d->intervalDuration.valueBypassingBindings();
+ d->intervalDuration.setValueBypassingBindings(nsec);
+ if (d->isActive()) { // Create new timer
+ QObject::killTimer(d->id); // Restart timer
+ const auto newId = Qt::TimerId{QObject::startTimer(nsec, d->type)};
+ if (newId > Qt::TimerId::Invalid) {
+ // Restarted successfully. No need to update the active state.
+ d->id = newId;
+ } else {
+ // Failed to start the timer.
+ // Need to notify about active state change.
+ d->id = Qt::TimerId::Invalid;
+ d->isActiveData.notify();
+ }
+ }
+ if (intervalChanged)
+ d->intervalDuration.notify();
+}
+
+std::chrono::nanoseconds QChronoTimer::interval() const
+{
+ return d_func()->intervalDuration.value();
+}
+
+QBindable<std::chrono::nanoseconds> QChronoTimer::bindableInterval()
+{
+ return {&d_func()->intervalDuration};
+}
+
+/*!
+ \property QChronoTimer::remainingTime
+ \brief The remaining time
+
+ Returns the remaining duration until the timeout.
+
+ If the timer is inactive, the returned duration will be negative.
+
+ If the timer is overdue, the returned duration will be \c 0ns.
+
+ \sa interval
+*/
+std::chrono::nanoseconds QChronoTimer::remainingTime() const
+{
+ if (isActive())
+ return QAbstractEventDispatcher::instance()->remainingTime(d_func()->id);
+ return std::chrono::nanoseconds::min();
+}
+
+/*!
+ \property QChronoTimer::timerType
+ \brief Controls the accuracy of the timer
+
+ The default value for this property is \c Qt::CoarseTimer.
+
+ \sa Qt::TimerType
+*/
+void QChronoTimer::setTimerType(Qt::TimerType atype)
+{
+ d_func()->type = atype;
+}
+
+Qt::TimerType QChronoTimer::timerType() const
+{
+ return d_func()->type;
+}
+
+QBindable<Qt::TimerType> QChronoTimer::bindableTimerType()
+{
+ return {&d_func()->type};
+}
+
+/*!
+ \overload
+ \reentrant
+
+ This static function calls the slot \a member, on object \a receiver, after
+ time interval \a interval. \a timerType affects the precision of the timer
+
+ \a member has to be a member function of \a receiver; you need to use the
+ \c SLOT() macro to get this parameter.
+
+ This function is provided as a convenience to save the need to use a
+ \l{QObject::timerEvent()}{timerEvent} or create a local QChronoTimer
+ object.
+
+ \sa start(), Qt::TimerType
+*/
+void QChronoTimer::singleShot(std::chrono::nanoseconds interval, Qt::TimerType timerType,
+ const QObject *receiver, const char *member)
+{
+ if (Q_UNLIKELY(interval < 0ns)) {
+ qWarning("QChronoTimer::singleShot: Timers cannot have negative timeouts");
+ return;
+ }
+ if (receiver && member) {
+ if (interval == 0ns) {
+ // special code shortpath for 0-timers
+ const char* bracketPosition = strchr(member, '(');
+ if (!bracketPosition || !(member[0] >= '0' && member[0] <= '2')) {
+ qWarning("QChronoTimer::singleShot: Invalid slot specification");
+ return;
+ }
+ const auto methodName = QByteArrayView(member + 1, // extract method name
+ bracketPosition - 1 - member).trimmed();
+ QMetaObject::invokeMethod(const_cast<QObject *>(receiver),
+ methodName.toByteArray().constData(),
+ Qt::QueuedConnection);
+ return;
+ }
+ (void) new QSingleShotTimer(interval, timerType, receiver, member);
+ }
+}
+
+/*!
+ \internal
+
+ \list
+ \li \a interval the time interval
+ \li \a timerType the type of the timer; this affects the precision of
+ the timer
+ \li \a receiver the receiver or context object; if this is \c nullptr,
+ this method will figure out a context object to use, see code
+ comments below
+ \li \a slotObj a callable, for example a lambda
+ \endlist
+*/
+void QChronoTimer::singleShotImpl(std::chrono::nanoseconds interval, Qt::TimerType timerType,
+ const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj)
+{
+ if (interval == 0ns) {
+ bool deleteReceiver = false;
+ // Optimize: set a receiver context when none is given, such that we can use
+ // QMetaObject::invokeMethod which is more efficient than going through a timer.
+ // We need a QObject living in the current thread. But the QThread itself lives
+ // in a different thread - with the exception of the main QThread which lives in
+ // itself. And QThread::currentThread() is among the few QObjects we know that will
+ // most certainly be there. Note that one can actually call singleShot before the
+ // QApplication is created!
+ if (!receiver && QThread::currentThread() == QCoreApplicationPrivate::mainThread()) {
+ // reuse main thread as context object
+ receiver = QThread::currentThread();
+ } else if (!receiver) {
+ // Create a receiver context object on-demand. According to the benchmarks,
+ // this is still more efficient than going through a timer.
+ receiver = new QObject;
+ deleteReceiver = true;
+ }
+
+ auto h = QtPrivate::invokeMethodHelper({});
+ QMetaObject::invokeMethodImpl(const_cast<QObject *>(receiver), slotObj,
+ Qt::QueuedConnection, h.parameterCount(), h.parameters.data(), h.typeNames.data(),
+ h.metaTypes.data());
+
+ if (deleteReceiver)
+ const_cast<QObject *>(receiver)->deleteLater();
+ return;
+ }
+
+ new QSingleShotTimer(interval, timerType, receiver, slotObj);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qchronotimer.cpp"
diff --git a/src/corelib/kernel/qchronotimer.h b/src/corelib/kernel/qchronotimer.h
new file mode 100644
index 0000000000..79c475e93c
--- /dev/null
+++ b/src/corelib/kernel/qchronotimer.h
@@ -0,0 +1,149 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QCHRONOTIMER_H
+#define QCHRONOTIMER_H
+
+#ifndef QT_NO_QOBJECT
+
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qnamespace.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qproperty.h>
+
+#include <chrono>
+
+QT_BEGIN_NAMESPACE
+
+class QTimerPrivate;
+class Q_CORE_EXPORT QChronoTimer : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool singleShot READ isSingleShot WRITE setSingleShot
+ BINDABLE bindableSingleShot FINAL)
+ Q_PROPERTY(std::chrono::nanoseconds interval READ interval WRITE setInterval
+ BINDABLE bindableInterval FINAL)
+ Q_PROPERTY(std::chrono::nanoseconds remainingTime READ remainingTime FINAL)
+ Q_PROPERTY(Qt::TimerType timerType READ timerType WRITE setTimerType
+ BINDABLE bindableTimerType FINAL)
+ Q_PROPERTY(bool active READ isActive STORED false BINDABLE bindableActive FINAL)
+
+ template <typename Functor>
+ using FunctorContext = typename QtPrivate::ContextTypeForFunctor<Functor>::ContextType;
+
+public:
+ explicit QChronoTimer(std::chrono::nanoseconds nsec, QObject *parent = nullptr);
+ explicit QChronoTimer(QObject *parent = nullptr);
+ ~QChronoTimer() override;
+
+ bool isActive() const;
+ QBindable<bool> bindableActive();
+ Qt::TimerId id() const;
+
+ void setInterval(std::chrono::nanoseconds nsec);
+ std::chrono::nanoseconds interval() const;
+ QBindable<std::chrono::nanoseconds> bindableInterval();
+
+ std::chrono::nanoseconds remainingTime() const;
+
+ void setTimerType(Qt::TimerType atype);
+ Qt::TimerType timerType() const;
+ QBindable<Qt::TimerType> bindableTimerType();
+
+ void setSingleShot(bool singleShot);
+ bool isSingleShot() const;
+ QBindable<bool> bindableSingleShot();
+
+ // singleShot with context
+#ifdef Q_QDOC
+ template <typename Functor>
+ static inline void singleShot(std::chrono::nanoseconds interval,
+ const QObject *receiver, Functor &&slot);
+ template <typename Functor>
+ static inline void singleShot(std::chrono::nanoseconds interval interval,
+ Qt::TimerType timerType,
+ const QObject *receiver, Functor &&slot);
+#else
+ template <typename Functor>
+ static void singleShot(std::chrono::nanoseconds interval,
+ const FunctorContext<Functor> *receiver, Functor &&slot)
+ {
+ singleShot(interval, defaultTimerTypeFor(interval), receiver, std::forward<Functor>(slot));
+ }
+ template <typename Functor>
+ static void singleShot(std::chrono::nanoseconds interval, Qt::TimerType timerType,
+ const FunctorContext<Functor> *receiver, Functor &&slot)
+ {
+ using Prototype = void(*)();
+ auto *slotObj = QtPrivate::makeCallableObject<Prototype>(std::forward<Functor>(slot));
+ singleShotImpl(interval, timerType, receiver, slotObj);
+ }
+#endif
+
+ template <typename Functor>
+ static void singleShot(std::chrono::nanoseconds interval, Qt::TimerType timerType,
+ Functor &&slot)
+ { singleShot(interval, timerType, nullptr, std::forward<Functor>(slot)); }
+
+ template <typename Functor>
+ static void singleShot(std::chrono::nanoseconds interval, Functor &&slot)
+ {
+ singleShot(interval, defaultTimerTypeFor(interval), nullptr, std::forward<Functor>(slot));
+ }
+
+ static void singleShot(std::chrono::nanoseconds interval, Qt::TimerType timerType,
+ const QObject *receiver, const char *member);
+ static void singleShot(std::chrono::nanoseconds interval, const QObject *receiver,
+ const char *member)
+ { singleShot(interval, defaultTimerTypeFor(interval), receiver, member); }
+
+#ifdef Q_QDOC
+ template <typename Functor>
+ QMetaObject::Connection callOnTimeout(const QObject *context, Functor &&slot,
+ Qt::ConnectionType connectionType = Qt::AutoConnection);
+#else
+ template <typename ... Args>
+ QMetaObject::Connection callOnTimeout(Args && ...args)
+ {
+ return QObject::connect(this, &QChronoTimer::timeout, std::forward<Args>(args)... );
+ }
+#endif
+
+public Q_SLOTS:
+ void start();
+ void stop();
+
+Q_SIGNALS:
+ void timeout(QPrivateSignal);
+
+protected:
+ void timerEvent(QTimerEvent *) override;
+
+private:
+ Q_DISABLE_COPY(QChronoTimer)
+
+ // QChronoTimer uses QTimerPrivate
+ inline QTimerPrivate *d_func() noexcept
+ { Q_CAST_IGNORE_ALIGN(return reinterpret_cast<QTimerPrivate *>(qGetPtrHelper(d_ptr));) }
+ inline const QTimerPrivate *d_func() const noexcept
+ { Q_CAST_IGNORE_ALIGN(return reinterpret_cast<const QTimerPrivate *>(qGetPtrHelper(d_ptr));) }
+
+ // These two functions are inherited from QObject
+ int startTimer(std::chrono::nanoseconds) = delete;
+ void killTimer(int) = delete;
+
+ static constexpr Qt::TimerType defaultTimerTypeFor(std::chrono::nanoseconds interval) noexcept
+ {
+ using namespace std::chrono_literals;
+ return interval >= 2s ? Qt::CoarseTimer : Qt::PreciseTimer;
+ }
+
+ static void singleShotImpl(std::chrono::nanoseconds interval, Qt::TimerType timerType,
+ const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj);
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_QOBJECT
+
+#endif // QCHRONOTIMER_H
diff --git a/src/corelib/kernel/qcore_foundation.mm b/src/corelib/kernel/qcore_foundation.mm
index cf15e24917..a31040944f 100644
--- a/src/corelib/kernel/qcore_foundation.mm
+++ b/src/corelib/kernel/qcore_foundation.mm
@@ -10,7 +10,7 @@
#include <QtCore/qbytearray.h>
#include <QtCore/qrect.h>
-#if QT_CONFIG(timezone) && !defined(QT_NO_SYSTEMLOCALE)
+#if QT_CONFIG(timezone)
#include <QtCore/qtimezone.h>
#include <QtCore/private/qtimezoneprivate_p.h>
#include <QtCore/private/qcore_mac_p.h>
@@ -466,7 +466,7 @@ NSDate *QDateTime::toNSDate() const
// ----------------------------------------------------------------------------
-#if QT_CONFIG(timezone) && !defined(QT_NO_SYSTEMLOCALE)
+#if QT_CONFIG(timezone)
/*!
\brief Constructs a new QTimeZone containing a copy of the CFTimeZone \a timeZone.
diff --git a/src/corelib/kernel/qcore_mac.mm b/src/corelib/kernel/qcore_mac.mm
index 17cd03d975..54c4373aed 100644
--- a/src/corelib/kernel/qcore_mac.mm
+++ b/src/corelib/kernel/qcore_mac.mm
@@ -25,11 +25,14 @@
#include "qendian.h"
#include "qhash.h"
-#include "qpair.h"
#include "qmutex.h"
#include "qvarlengtharray.h"
#include "private/qlocking_p.h"
+#if !defined(QT_BOOTSTRAPPED)
+#include <thread>
+#endif
+
#if !defined(QT_APPLE_NO_PRIVATE_APIS)
extern "C" {
typedef uint32_t csr_config_t;
@@ -49,6 +52,7 @@ QT_BEGIN_NAMESPACE
// --------------------------------------------------------------------------
+#if defined(Q_OS_MACOS)
static void initializeStandardUserDefaults()
{
// The standard user defaults are initialized from an ordered list of domains,
@@ -61,6 +65,7 @@ static void initializeStandardUserDefaults()
Q_UNUSED(NSUserDefaults.standardUserDefaults);
}
Q_CONSTRUCTOR_FUNCTION(initializeStandardUserDefaults);
+#endif
// --------------------------------------------------------------------------
@@ -82,17 +87,35 @@ QCFString::operator CFStringRef() const
#if defined(QT_USE_APPLE_UNIFIED_LOGGING)
-bool AppleUnifiedLogger::willMirrorToStderr()
+bool AppleUnifiedLogger::preventsStderrLogging()
{
- // When running under Xcode or LLDB, one or more of these variables will
- // be set, which triggers libsystem_trace.dyld to log messages to stderr
- // as well, via_os_log_impl_mirror_to_stderr. Un-setting these variables
- // is not an option, as that would silence normal NSLog or os_log calls,
- // so instead we skip our own stderr output. See rdar://36919139.
+ // os_log will mirror to stderr if OS_ACTIVITY_DT_MODE is set,
+ // regardless of its value. OS_ACTIVITY_MODE then controls whether
+ // to include info and/or debug messages in this mirroring.
+ // For some reason, when launched under lldb (via Xcode or not),
+ // all levels are included.
+
+ // CFLog will normally log to both stderr, and via os_log.
+ // Setting CFLOG_FORCE_DISABLE_STDERR disables the stderr
+ // logging. Setting CFLOG_FORCE_STDERR will both duplicate
+ // CFLog's output to stderr, and trigger OS_ACTIVITY_DT_MODE,
+ // resulting in os_log calls also being mirrored to stderr.
+ // Setting ACTIVITY_LOG_STDERR has the same effect.
+
+ // NSLog is plumbed to CFLog, and will respond to the same
+ // environment variables as CFLog.
+
+ // We want to disable Qt's default stderr log handler when
+ // os_log has already mirrored to stderr.
static bool willMirror = qEnvironmentVariableIsSet("OS_ACTIVITY_DT_MODE")
- || qEnvironmentVariableIsSet("ACTIVITY_LOG_STDERR")
- || qEnvironmentVariableIsSet("CFLOG_FORCE_STDERR");
- return willMirror;
+ || qEnvironmentVariableIsSet("ACTIVITY_LOG_STDERR")
+ || qEnvironmentVariableIsSet("CFLOG_FORCE_STDERR");
+
+ // As well as when we suspect that Xcode is going to present os_log
+ // as structured log messages.
+ static bool disableStderr = qEnvironmentVariableIsSet("CFLOG_FORCE_DISABLE_STDERR");
+
+ return willMirror || disableStderr;
}
QT_MAC_WEAK_IMPORT(_os_log_default);
@@ -133,7 +156,7 @@ bool AppleUnifiedLogger::messageHandler(QtMsgType msgType, const QMessageLogCont
// system from redacting our log message.
os_log_with_type(log, logType, "%{public}s", qPrintable(message));
- return willMirrorToStderr();
+ return preventsStderrLogging();
}
os_log_type_t AppleUnifiedLogger::logTypeForMessageType(QtMsgType msgType)
@@ -210,52 +233,38 @@ QT_FOR_EACH_MUTABLE_CORE_GRAPHICS_TYPE(QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TY
QT_END_NAMESPACE
QT_USE_NAMESPACE
+
+#ifdef QT_DEBUG
@interface QT_MANGLE_NAMESPACE(QMacAutoReleasePoolTracker) : NSObject
@end
-@implementation QT_MANGLE_NAMESPACE(QMacAutoReleasePoolTracker) {
- NSAutoreleasePool **m_pool;
-}
-
-- (instancetype)initWithPool:(NSAutoreleasePool **)pool
-{
- if ((self = [self init]))
- m_pool = pool;
- return self;
-}
-
-- (void)dealloc
-{
- if (*m_pool) {
- // The pool is still valid, which means we're not being drained from
- // the corresponding QMacAutoReleasePool (see below).
-
- // QMacAutoReleasePool has only a single member, the NSAutoreleasePool*
- // so the address of that member is also the QMacAutoReleasePool itself.
- QMacAutoReleasePool *pool = reinterpret_cast<QMacAutoReleasePool *>(m_pool);
- qWarning() << "Premature drain of" << pool << "This can happen if you've allocated"
- << "the pool on the heap, or as a member of a heap-allocated object. This is not a"
- << "supported use of QMacAutoReleasePool, and might result in crashes when objects"
- << "in the pool are deallocated and then used later on under the assumption they"
- << "will be valid until" << pool << "has been drained.";
+@implementation QT_MANGLE_NAMESPACE(QMacAutoReleasePoolTracker)
+@end
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAutoReleasePoolTracker);
+#endif // QT_DEBUG
- // Reset the pool so that it's not drained again later on
- *m_pool = nullptr;
- }
+// Use the direct runtime interface to manage autorelease pools, as it
+// has less overhead then allocating NSAutoreleasePools, and allows for
+// a future where we use ARC (where NSAutoreleasePool is not allowed).
+// https://clang.llvm.org/docs/AutomaticReferenceCounting.html#runtime-support
- [super dealloc];
+extern "C" {
+void *objc_autoreleasePoolPush(void);
+void objc_autoreleasePoolPop(void *pool);
}
-@end
-QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAutoReleasePoolTracker);
QT_BEGIN_NAMESPACE
QMacAutoReleasePool::QMacAutoReleasePool()
- : pool([[NSAutoreleasePool alloc] init])
+ : pool(objc_autoreleasePoolPush())
{
+#ifdef QT_DEBUG
+ static const bool debugAutoReleasePools = qEnvironmentVariableIsSet("QT_DARWIN_DEBUG_AUTORELEASEPOOLS");
+ if (!debugAutoReleasePools)
+ return;
+
Class trackerClass = [QMacAutoReleasePoolTracker class];
-#ifdef QT_DEBUG
void *poolFrame = nullptr;
void *frames[2];
if (backtrace_from_fp(__builtin_frame_address(0), frames, 2))
@@ -285,30 +294,14 @@ QMacAutoReleasePool::QMacAutoReleasePool()
free((char*)symbolName);
}
}
-#endif
- [[[trackerClass alloc] initWithPool:
- reinterpret_cast<NSAutoreleasePool **>(&pool)] autorelease];
+ [[trackerClass new] autorelease];
+#endif // QT_DEBUG
}
QMacAutoReleasePool::~QMacAutoReleasePool()
{
- if (!pool) {
- qWarning() << "Prematurely drained pool" << this << "finally drained. Any objects belonging"
- << "to this pool have already been released, and have potentially been invalid since the"
- << "premature drain earlier on.";
- return;
- }
-
- // Save and reset pool before draining, so that the pool tracker can know
- // that it's being drained by its owning pool.
- NSAutoreleasePool *savedPool = static_cast<NSAutoreleasePool*>(pool);
- pool = nullptr;
-
- // Drain behaves the same as release, with the advantage that
- // if we're ever used in a garbage-collected environment, the
- // drain acts as a hint to the garbage collector to collect.
- [savedPool drain];
+ objc_autoreleasePoolPop(pool);
}
#ifndef QT_NO_DEBUG_STREAM
@@ -353,7 +346,7 @@ std::optional<uint32_t> qt_mac_sipConfiguration()
return config;
#endif
- QIOType<io_registry_entry_t> nvram = IORegistryEntryFromPath(kIOMasterPortDefault, "IODeviceTree:/options");
+ QIOType<io_registry_entry_t> nvram = IORegistryEntryFromPath(kIOMainPortDefault, "IODeviceTree:/options");
if (!nvram) {
qWarning("Failed to locate NVRAM entry in IO registry");
return {};
@@ -456,36 +449,64 @@ AppleApplication *qt_apple_sharedApplication()
}
#endif
+#if !defined(QT_BOOTSTRAPPED)
+
+#if defined(Q_OS_MACOS)
+namespace {
+struct SandboxChecker
+{
+ SandboxChecker() : m_thread([this]{
+ m_isSandboxed = []{
+ QCFType<SecStaticCodeRef> staticCode = nullptr;
+ NSURL *executableUrl = NSBundle.mainBundle.executableURL;
+ if (SecStaticCodeCreateWithPath((__bridge CFURLRef)executableUrl,
+ kSecCSDefaultFlags, &staticCode) != errSecSuccess)
+ return false;
+
+ QCFType<SecRequirementRef> sandboxRequirement;
+ if (SecRequirementCreateWithString(CFSTR("entitlement[\"com.apple.security.app-sandbox\"] exists"),
+ kSecCSDefaultFlags, &sandboxRequirement) != errSecSuccess)
+ return false;
+
+ if (SecStaticCodeCheckValidityWithErrors(staticCode,
+ kSecCSBasicValidateOnly, sandboxRequirement, nullptr) != errSecSuccess)
+ return false;
+
+ return true;
+ }();
+ })
+ {}
+ ~SandboxChecker() {
+ std::scoped_lock lock(m_mutex);
+ if (m_thread.joinable())
+ m_thread.detach();
+ }
+ bool isSandboxed() const {
+ std::scoped_lock lock(m_mutex);
+ if (m_thread.joinable())
+ m_thread.join();
+ return m_isSandboxed;
+ }
+private:
+ bool m_isSandboxed;
+ mutable std::thread m_thread;
+ mutable std::mutex m_mutex;
+};
+} // namespace
+static SandboxChecker sandboxChecker;
+#endif // Q_OS_MACOS
+
bool qt_apple_isSandboxed()
{
#if defined(Q_OS_MACOS)
- static bool isSandboxed = []() {
- QCFType<SecStaticCodeRef> staticCode = nullptr;
- NSURL *executableUrl = NSBundle.mainBundle.executableURL;
- if (SecStaticCodeCreateWithPath((__bridge CFURLRef)executableUrl,
- kSecCSDefaultFlags, &staticCode) != errSecSuccess)
- return false;
-
- QCFType<SecRequirementRef> sandboxRequirement;
- if (SecRequirementCreateWithString(CFSTR("entitlement[\"com.apple.security.app-sandbox\"] exists"),
- kSecCSDefaultFlags, &sandboxRequirement) != errSecSuccess)
- return false;
-
- if (SecStaticCodeCheckValidityWithErrors(staticCode,
- kSecCSBasicValidateOnly, sandboxRequirement, nullptr) != errSecSuccess)
- return false;
-
- return true;
- }();
- return isSandboxed;
+ return sandboxChecker.isSandboxed();
#else
return true; // All other Apple platforms
#endif
}
-#if !defined(QT_BOOTSTRAPPED)
QT_END_NAMESPACE
-@implementation NSObject (QtSandboxHelpers)
+@implementation NSObject (QtExtras)
- (id)qt_valueForPrivateKey:(NSString *)key
{
if (qt_apple_isSandboxed())
@@ -495,7 +516,7 @@ QT_END_NAMESPACE
}
@end
QT_BEGIN_NAMESPACE
-#endif
+#endif // !QT_BOOTSTRAPPED
#ifdef Q_OS_MACOS
/*
@@ -546,6 +567,9 @@ void qt_apple_check_os_version()
#elif defined(__TV_OS_VERSION_MIN_REQUIRED)
const char *os = "tvOS";
const int version = __TV_OS_VERSION_MIN_REQUIRED;
+#elif defined(__VISION_OS_VERSION_MIN_REQUIRED)
+ const char *os = "visionOS";
+ const int version = __VISION_OS_VERSION_MIN_REQUIRED;
#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
const char *os = "iOS";
const int version = __IPHONE_OS_VERSION_MIN_REQUIRED;
@@ -695,7 +719,7 @@ QMacVersion::VersionTuple QMacVersion::versionsForImage(const mach_header *machH
};
static auto makeVersionTuple = [](uint32_t dt, uint32_t sdk, QOperatingSystemVersion::OSType osType) {
- return qMakePair(
+ return std::pair(
QOperatingSystemVersion(osType, dt >> 16 & 0xffff, dt >> 8 & 0xff, dt & 0xff),
QOperatingSystemVersion(osType, sdk >> 16 & 0xffff, sdk >> 8 & 0xff, sdk & 0xff)
);
diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h
index aee5fcb604..e63c320805 100644
--- a/src/corelib/kernel/qcore_mac_p.h
+++ b/src/corelib/kernel/qcore_mac_p.h
@@ -85,15 +85,18 @@ template <typename T, typename U, auto RetainFunction, auto ReleaseFunction>
class QAppleRefCounted
{
public:
- QAppleRefCounted() : value() {}
- QAppleRefCounted(const T &t) : value(t) {}
- QAppleRefCounted(T &&t) noexcept(std::is_nothrow_move_constructible<T>::value)
+ Q_NODISCARD_CTOR QAppleRefCounted() : value() {}
+ Q_NODISCARD_CTOR QAppleRefCounted(const T &t) : value(t) {}
+ Q_NODISCARD_CTOR QAppleRefCounted(T &&t)
+ noexcept(std::is_nothrow_move_constructible<T>::value)
: value(std::move(t)) {}
- QAppleRefCounted(QAppleRefCounted &&other)
+ Q_NODISCARD_CTOR QAppleRefCounted(QAppleRefCounted &&other)
noexcept(std::is_nothrow_move_assignable<T>::value &&
std::is_nothrow_move_constructible<T>::value)
: value(std::exchange(other.value, T())) {}
- QAppleRefCounted(const QAppleRefCounted &other) : value(other.value) { if (value) RetainFunction(value); }
+ Q_NODISCARD_CTOR QAppleRefCounted(const QAppleRefCounted &other)
+ : value(other.value)
+ { if (value) RetainFunction(value); }
~QAppleRefCounted() { if (value) ReleaseFunction(value); }
operator T() const { return value; }
void swap(QAppleRefCounted &other) noexcept(noexcept(qSwap(value, other.value)))
@@ -109,11 +112,11 @@ protected:
T value;
};
-class Q_CORE_EXPORT QMacAutoReleasePool
+class QMacAutoReleasePool
{
public:
- QMacAutoReleasePool();
- ~QMacAutoReleasePool();
+ Q_NODISCARD_CTOR Q_CORE_EXPORT QMacAutoReleasePool();
+ Q_CORE_EXPORT ~QMacAutoReleasePool();
private:
Q_DISABLE_COPY(QMacAutoReleasePool)
void *pool;
@@ -123,7 +126,7 @@ private:
class QMacRootLevelAutoReleasePool
{
public:
- QMacRootLevelAutoReleasePool();
+ Q_NODISCARD_CTOR QMacRootLevelAutoReleasePool();
~QMacRootLevelAutoReleasePool();
private:
QScopedPointer<QMacAutoReleasePool> pool;
@@ -148,7 +151,7 @@ class QCFType : public QAppleRefCounted<T, CFTypeRef, CFRetain, CFRelease>
using Base = QAppleRefCounted<T, CFTypeRef, CFRetain, CFRelease>;
public:
using Base::Base;
- explicit QCFType(CFTypeRef r) : Base(static_cast<T>(r)) {}
+ Q_NODISCARD_CTOR explicit QCFType(CFTypeRef r) : Base(static_cast<T>(r)) {}
template <typename X> X as() const { return reinterpret_cast<X>(this->value); }
static QCFType constructFromGet(const T &t)
{
@@ -166,15 +169,15 @@ class QIOType : public QAppleRefCounted<T, io_object_t, IOObjectRetain, IOObject
};
#endif
-class Q_CORE_EXPORT QCFString : public QCFType<CFStringRef>
+class QCFString : public QCFType<CFStringRef>
{
public:
using QCFType<CFStringRef>::QCFType;
- inline QCFString(const QString &str) : QCFType<CFStringRef>(0), string(str) {}
- inline QCFString(const CFStringRef cfstr = 0) : QCFType<CFStringRef>(cfstr) {}
- inline QCFString(const QCFType<CFStringRef> &other) : QCFType<CFStringRef>(other) {}
- operator QString() const;
- operator CFStringRef() const;
+ Q_NODISCARD_CTOR QCFString(const QString &str) : QCFType<CFStringRef>(0), string(str) {}
+ Q_NODISCARD_CTOR QCFString(const CFStringRef cfstr = 0) : QCFType<CFStringRef>(cfstr) {}
+ Q_NODISCARD_CTOR QCFString(const QCFType<CFStringRef> &other) : QCFType<CFStringRef>(other) {}
+ Q_CORE_EXPORT operator QString() const;
+ Q_CORE_EXPORT operator CFStringRef() const;
private:
QString string;
@@ -195,15 +198,18 @@ Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QCFString &string);
#endif
Q_CORE_EXPORT bool qt_apple_isApplicationExtension();
+
+#if !defined(QT_BOOTSTRAPPED)
Q_CORE_EXPORT bool qt_apple_isSandboxed();
-#if !defined(QT_BOOTSTRAPPED) && defined(__OBJC__)
+#if defined(__OBJC__)
QT_END_NAMESPACE
-@interface NSObject (QtSandboxHelpers)
+@interface NSObject (QtExtras)
- (id)qt_valueForPrivateKey:(NSString *)key;
@end
QT_BEGIN_NAMESPACE
#endif
+#endif // !QT_BOOTSTRAPPED
#if !defined(QT_BOOTSTRAPPED) && !defined(Q_OS_WATCHOS)
QT_END_NAMESPACE
@@ -230,9 +236,12 @@ QT_BEGIN_NAMESPACE
class Q_CORE_EXPORT AppleUnifiedLogger
{
public:
- static bool messageHandler(QtMsgType msgType, const QMessageLogContext &context, const QString &message,
- const QString &subsystem = QString());
- static bool willMirrorToStderr();
+ static bool messageHandler(QtMsgType msgType, const QMessageLogContext &context,
+ const QString &message)
+ { return messageHandler(msgType, context, message, QString()); }
+ static bool messageHandler(QtMsgType msgType, const QMessageLogContext &context,
+ const QString &message, const QString &subsystem);
+ static bool preventsStderrLogging();
private:
static os_log_type_t logTypeForMessageType(QtMsgType msgType);
static os_log_t cachedLog(const QString &subsystem, const QString &category);
@@ -427,7 +436,7 @@ public:
private:
QMacVersion() = default;
- using VersionTuple = QPair<QOperatingSystemVersion, QOperatingSystemVersion>;
+ using VersionTuple = std::pair<QOperatingSystemVersion, QOperatingSystemVersion>;
static VersionTuple versionsForImage(const mach_header *machHeader);
static VersionTuple applicationVersion();
static VersionTuple libraryVersion();
@@ -435,6 +444,20 @@ private:
// -------------------------------------------------------------------------
+#ifdef __OBJC__
+template <typename T>
+typename std::enable_if<std::is_pointer<T>::value, T>::type
+qt_objc_cast(id object)
+{
+ if ([object isKindOfClass:[typename std::remove_pointer<T>::type class]])
+ return static_cast<T>(object);
+
+ return nil;
+}
+#endif
+
+// -------------------------------------------------------------------------
+
QT_END_NAMESPACE
#endif // QCORE_MAC_P_H
diff --git a/src/corelib/kernel/qcore_unix.cpp b/src/corelib/kernel/qcore_unix.cpp
index 4a95080c19..6861251bc2 100644
--- a/src/corelib/kernel/qcore_unix.cpp
+++ b/src/corelib/kernel/qcore_unix.cpp
@@ -3,8 +3,8 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/private/qglobal_p.h>
+#include <QtCore/qbasicatomic.h>
#include "qcore_unix_p.h"
-#include "qelapsedtimer.h"
#include <stdlib.h>
@@ -20,6 +20,21 @@
QT_BEGIN_NAMESPACE
+void qt_ignore_sigpipe() noexcept // noexcept: sigaction(2) is not a Posix Cancellation Point
+{
+ // Set to ignore SIGPIPE once only.
+ Q_CONSTINIT static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0);
+ if (!atom.loadRelaxed()) {
+ // More than one thread could turn off SIGPIPE at the same time
+ // But that's acceptable because they all would be doing the same
+ // action
+ struct sigaction noaction = {};
+ noaction.sa_handler = SIG_IGN;
+ ::sigaction(SIGPIPE, &noaction, nullptr);
+ atom.storeRelaxed(1);
+ }
+}
+
QByteArray qt_readlink(const char *path)
{
#ifndef PATH_MAX
@@ -69,23 +84,15 @@ int qt_open64(const char *pathname, int flags, mode_t mode)
# define ppoll pollts
#endif
-static inline bool time_update(struct timespec *tv, const struct timespec &start,
- const struct timespec &timeout)
-{
- // clock source is (hopefully) monotonic, so we can recalculate how much timeout is left;
- // if it isn't monotonic, we'll simply hope that it hasn't jumped, because we have no alternative
- struct timespec now = qt_gettime();
- *tv = timeout + start - now;
- return tv->tv_sec >= 0;
-}
-
-#if QT_CONFIG(poll_poll)
+[[maybe_unused]]
static inline int timespecToMillisecs(const struct timespec *ts)
{
- return (ts == NULL) ? -1 :
- (ts->tv_sec * 1000) + (ts->tv_nsec / 1000000);
+ using namespace std::chrono;
+ if (!ts)
+ return -1;
+ auto ms = ceil<milliseconds>(timespecToChrono<nanoseconds>(*ts));
+ return int(ms.count());
}
-#endif
// defined in qpoll.cpp
int qt_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts);
@@ -111,31 +118,27 @@ static inline int qt_ppoll(struct pollfd *fds, nfds_t nfds, const struct timespe
using select(2) where necessary. In that case, returns -1 and sets errno
to EINVAL if passed any descriptor greater than or equal to FD_SETSIZE.
*/
-int qt_safe_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts)
+int qt_safe_poll(struct pollfd *fds, nfds_t nfds, QDeadlineTimer deadline)
{
- if (!timeout_ts) {
+ if (deadline.isForever()) {
// no timeout -> block forever
int ret;
- EINTR_LOOP(ret, qt_ppoll(fds, nfds, nullptr));
+ QT_EINTR_LOOP(ret, qt_ppoll(fds, nfds, nullptr));
return ret;
}
- timespec start = qt_gettime();
- timespec timeout = *timeout_ts;
-
+ using namespace std::chrono;
+ nanoseconds remaining = deadline.remainingTimeAsDuration();
// loop and recalculate the timeout as needed
- forever {
- const int ret = qt_ppoll(fds, nfds, &timeout);
+ do {
+ timespec ts = durationToTimespec(remaining);
+ const int ret = qt_ppoll(fds, nfds, &ts);
if (ret != -1 || errno != EINTR)
return ret;
+ remaining = deadline.remainingTimeAsDuration();
+ } while (remaining > 0ns);
- // recalculate the timeout
- if (!time_update(&timeout, start, *timeout_ts)) {
- // timeout during update
- // or clock reset, fake timeout error
- return 0;
- }
- }
+ return 0;
}
#endif // QT_BOOTSTRAPPED
diff --git a/src/corelib/kernel/qcore_unix_p.h b/src/corelib/kernel/qcore_unix_p.h
index ed64a5d86b..fd834cb2d9 100644
--- a/src/corelib/kernel/qcore_unix_p.h
+++ b/src/corelib/kernel/qcore_unix_p.h
@@ -18,8 +18,8 @@
#include "qplatformdefs.h"
#include <QtCore/private/qglobal_p.h>
-#include "qatomic.h"
#include "qbytearray.h"
+#include "qdeadlinetimer.h"
#ifndef Q_OS_UNIX
# error "qcore_unix_p.h included on a non-Unix system"
@@ -44,10 +44,6 @@
#include <errno.h>
#include <fcntl.h>
-#if !defined(QT_POSIX_IPC) && !defined(QT_NO_SHAREDMEMORY) && !defined(Q_OS_ANDROID)
-# include <sys/ipc.h>
-#endif
-
#if defined(Q_OS_VXWORKS)
# include <ioLib.h>
#endif
@@ -60,7 +56,7 @@
struct sockaddr;
-#define EINTR_LOOP(var, cmd) \
+#define QT_EINTR_LOOP(var, cmd) \
do { \
var = cmd; \
} while (var == -1 && errno == EINTR)
@@ -184,21 +180,7 @@ inline timespec qAbsTimespec(timespec ts)
return normalizedTimespec(ts);
}
-inline void qt_ignore_sigpipe()
-{
- // Set to ignore SIGPIPE once only.
- Q_CONSTINIT static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0);
- if (!atom.loadRelaxed()) {
- // More than one thread could turn off SIGPIPE at the same time
- // But that's acceptable because they all would be doing the same
- // action
- struct sigaction noaction;
- memset(&noaction, 0, sizeof(noaction));
- noaction.sa_handler = SIG_IGN;
- ::sigaction(SIGPIPE, &noaction, nullptr);
- atom.storeRelaxed(1);
- }
-}
+Q_CORE_EXPORT void qt_ignore_sigpipe() noexcept;
#if defined(Q_PROCESSOR_X86_32) && defined(__GLIBC__)
# if !__GLIBC_PREREQ(2, 22)
@@ -208,6 +190,16 @@ Q_CORE_EXPORT int qt_open64(const char *pathname, int flags, mode_t);
# endif
#endif
+#ifdef AT_FDCWD
+static inline int qt_safe_openat(int dfd, const char *pathname, int flags, mode_t mode = 0777)
+{
+ // everyone already has O_CLOEXEC
+ int fd;
+ QT_EINTR_LOOP(fd, openat(dfd, pathname, flags | O_CLOEXEC, mode));
+ return fd;
+}
+#endif
+
// don't call QT_OPEN or ::open
// call qt_safe_open
static inline int qt_safe_open(const char *pathname, int flags, mode_t mode = 0777)
@@ -216,7 +208,7 @@ static inline int qt_safe_open(const char *pathname, int flags, mode_t mode = 07
flags |= O_CLOEXEC;
#endif
int fd;
- EINTR_LOOP(fd, QT_OPEN(pathname, flags, mode));
+ QT_EINTR_LOOP(fd, QT_OPEN(pathname, flags, mode));
#ifndef O_CLOEXEC
if (fd != -1)
@@ -288,10 +280,10 @@ static inline int qt_safe_dup2(int oldfd, int newfd, int flags = FD_CLOEXEC)
int ret;
#ifdef QT_THREADSAFE_CLOEXEC
// use dup3
- EINTR_LOOP(ret, ::dup3(oldfd, newfd, flags ? O_CLOEXEC : 0));
+ QT_EINTR_LOOP(ret, ::dup3(oldfd, newfd, flags ? O_CLOEXEC : 0));
return ret;
#else
- EINTR_LOOP(ret, ::dup2(oldfd, newfd));
+ QT_EINTR_LOOP(ret, ::dup2(oldfd, newfd));
if (ret == -1)
return -1;
@@ -304,7 +296,7 @@ static inline int qt_safe_dup2(int oldfd, int newfd, int flags = FD_CLOEXEC)
static inline qint64 qt_safe_read(int fd, void *data, qint64 maxlen)
{
qint64 ret = 0;
- EINTR_LOOP(ret, QT_READ(fd, data, maxlen));
+ QT_EINTR_LOOP(ret, QT_READ(fd, data, maxlen));
return ret;
}
#undef QT_READ
@@ -313,7 +305,7 @@ static inline qint64 qt_safe_read(int fd, void *data, qint64 maxlen)
static inline qint64 qt_safe_write(int fd, const void *data, qint64 len)
{
qint64 ret = 0;
- EINTR_LOOP(ret, QT_WRITE(fd, data, len));
+ QT_EINTR_LOOP(ret, QT_WRITE(fd, data, len));
return ret;
}
#undef QT_WRITE
@@ -328,7 +320,7 @@ static inline qint64 qt_safe_write_nosignal(int fd, const void *data, qint64 len
static inline int qt_safe_close(int fd)
{
int ret;
- EINTR_LOOP(ret, QT_CLOSE(fd));
+ QT_EINTR_LOOP(ret, QT_CLOSE(fd));
return ret;
}
#undef QT_CLOSE
@@ -340,28 +332,28 @@ static inline int qt_safe_execve(const char *filename, char *const argv[],
char *const envp[])
{
int ret;
- EINTR_LOOP(ret, ::execve(filename, argv, envp));
+ QT_EINTR_LOOP(ret, ::execve(filename, argv, envp));
return ret;
}
static inline int qt_safe_execv(const char *path, char *const argv[])
{
int ret;
- EINTR_LOOP(ret, ::execv(path, argv));
+ QT_EINTR_LOOP(ret, ::execv(path, argv));
return ret;
}
static inline int qt_safe_execvp(const char *file, char *const argv[])
{
int ret;
- EINTR_LOOP(ret, ::execvp(file, argv));
+ QT_EINTR_LOOP(ret, ::execvp(file, argv));
return ret;
}
static inline pid_t qt_safe_waitpid(pid_t pid, int *status, int options)
{
int ret;
- EINTR_LOOP(ret, ::waitpid(pid, status, options));
+ QT_EINTR_LOOP(ret, ::waitpid(pid, status, options));
return ret;
}
#endif // QT_CONFIG(process)
@@ -370,8 +362,6 @@ static inline pid_t qt_safe_waitpid(pid_t pid, int *status, int options)
# define _POSIX_MONOTONIC_CLOCK -1
#endif
-// in qelapsedtimer_mac.cpp or qtimestamp_unix.cpp
-timespec qt_gettime() noexcept;
QByteArray qt_readlink(const char *path);
/* non-static */
@@ -389,20 +379,7 @@ inline bool qt_haveLinuxProcfs()
#endif
}
-Q_CORE_EXPORT int qt_safe_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts);
-
-static inline int qt_poll_msecs(struct pollfd *fds, nfds_t nfds, int timeout)
-{
- timespec ts, *pts = nullptr;
-
- if (timeout >= 0) {
- ts.tv_sec = timeout / 1000;
- ts.tv_nsec = (timeout % 1000) * 1000 * 1000;
- pts = &ts;
- }
-
- return qt_safe_poll(fds, nfds, pts);
-}
+Q_CORE_EXPORT int qt_safe_poll(struct pollfd *fds, nfds_t nfds, QDeadlineTimer deadline);
static inline struct pollfd qt_make_pollfd(int fd, short events)
{
diff --git a/src/corelib/kernel/qcore_wasm.cpp b/src/corelib/kernel/qcore_wasm.cpp
index 79b5b01cc1..fb12ae50c3 100644
--- a/src/corelib/kernel/qcore_wasm.cpp
+++ b/src/corelib/kernel/qcore_wasm.cpp
@@ -49,9 +49,9 @@ emscripten::val QRectF::toDOMRect() const
\since 6.6
\ingroup platform-type-conversions
- \sa toJsString()
+ \sa toEcmaString()
*/
-QString QString::fromJsString(emscripten::val jsString)
+QString QString::fromEcmaString(emscripten::val jsString)
{
Q_ASSERT_X(jsString.isString(), Q_FUNC_INFO, "Passed object is not a string");
@@ -86,9 +86,9 @@ QString QString::fromJsString(emscripten::val jsString)
\since 6.6
\ingroup platform-type-conversions
- \sa fromJsString()
+ \sa fromEcmaString()
*/
-emscripten::val QString::toJsString() const
+emscripten::val QString::toEcmaString() const
{
static const emscripten::val UTF16ToString(emscripten::val::module_property("UTF16ToString"));
return UTF16ToString(emscripten::val(quintptr(utf16())));
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index e40cab05ba..bd00f69c1c 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -8,6 +8,7 @@
#ifndef QT_NO_QOBJECT
#include "qabstracteventdispatcher.h"
#include "qcoreevent.h"
+#include "qcoreevent_p.h"
#include "qeventloop.h"
#endif
#include "qmetaobject.h"
@@ -34,8 +35,8 @@
#include <private/qthreadpool_p.h>
#endif
#endif
-#include <qelapsedtimer.h>
#include <qlibraryinfo.h>
+#include <qpointer.h>
#include <qvarlengtharray.h>
#include <private/qfactoryloader_p.h>
#include <private/qfunctions_p.h>
@@ -56,7 +57,9 @@
# include "qeventdispatcher_glib_p.h"
# endif
# endif
-# include "qeventdispatcher_unix_p.h"
+# if !defined(Q_OS_WASM)
+# include "qeventdispatcher_unix_p.h"
+# endif
#endif
#ifdef Q_OS_WIN
#include "qeventdispatcher_win_p.h"
@@ -104,9 +107,14 @@
#include <algorithm>
#include <memory>
+#include <string>
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_QOBJECT
+Q_LOGGING_CATEGORY(lcDeleteLater, "qt.core.qobject.deletelater")
+#endif
+
using namespace Qt::StringLiterals;
Q_TRACE_PREFIX(qtcore,
@@ -233,7 +241,11 @@ void QCoreApplicationPrivate::processCommandLineArguments()
// Support for introspection
-extern "C" void Q_DECL_EXPORT_OVERRIDABLE qt_startup_hook()
+extern "C" void
+#ifdef QT_SHARED
+Q_DECL_EXPORT_OVERRIDABLE
+#endif
+qt_startup_hook()
{
}
@@ -293,15 +305,15 @@ static void qt_call_pre_routines()
if (!preRList.exists())
return;
- QVFuncList list;
- {
+ const QStartUpFuncList list = [] {
const auto locker = qt_scoped_lock(globalRoutinesMutex);
// Unlike qt_call_post_routines, we don't empty the list, because
// Q_COREAPP_STARTUP_FUNCTION is a macro, so the user expects
// the function to be executed every time QCoreApplication is created.
- list = *preRList;
- }
- for (QtCleanUpFunction f : std::as_const(list))
+ return *preRList;
+ }();
+
+ for (QtStartUpFunction f : list)
f();
}
@@ -513,6 +525,7 @@ void QCoreApplicationPrivate::eventDispatcherReady()
}
Q_CONSTINIT QBasicAtomicPointer<QThread> QCoreApplicationPrivate::theMainThread = Q_BASIC_ATOMIC_INITIALIZER(nullptr);
+Q_CONSTINIT QBasicAtomicPointer<void> QCoreApplicationPrivate::theMainThreadId = Q_BASIC_ATOMIC_INITIALIZER(nullptr);
QThread *QCoreApplicationPrivate::mainThread()
{
Q_ASSERT(theMainThread.loadRelaxed() != nullptr);
@@ -576,7 +589,9 @@ void QCoreApplicationPrivate::initConsole()
return;
consoleAllocated = true;
} else if (env.compare(u"attach"_s, Qt::CaseInsensitive) == 0) {
- if (AttachConsole(ATTACH_PARENT_PROCESS) == FALSE)
+ // If the calling process is already attached to a console,
+ // the error code returned is ERROR_ACCESS_DENIED.
+ if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::GetLastError() != ERROR_ACCESS_DENIED)
return;
} else {
// Unknown input, don't make any decision for the user.
@@ -621,9 +636,13 @@ void QCoreApplicationPrivate::initLocale()
# elif defined(Q_OS_ANDROID) && __ANDROID_API__ < __ANDROID_API_O__
// Android 6 still lacks nl_langinfo(), so we can't check.
// FIXME: Shouldn't we still setlocale("UTF-8")?
+# elif defined(Q_OS_VXWORKS)
+ // VxWorks has no nl_langinfo, so we can't check.
# else
- const char *charEncoding = nl_langinfo(CODESET);
- if (Q_UNLIKELY(qstricmp(charEncoding, "UTF-8") != 0 && qstricmp(charEncoding, "utf8") != 0)) {
+ // std::string's SSO usually saves this the need to allocate:
+ const std::string oldEncoding = nl_langinfo(CODESET);
+ if (!Q_LIKELY(qstricmp(oldEncoding.data(), "UTF-8") == 0
+ || qstricmp(oldEncoding.data(), "utf8") == 0)) {
const QByteArray oldLocale = setlocale(LC_ALL, nullptr);
QByteArray newLocale;
bool warnOnOverride = true;
@@ -658,14 +677,14 @@ void QCoreApplicationPrivate::initLocale()
qWarning("Detected locale \"%s\" with character encoding \"%s\", which is not UTF-8.\n"
"Qt depends on a UTF-8 locale, but has failed to switch to one.\n"
"If this causes problems, reconfigure your locale. See the locale(1) manual\n"
- "for more information.", oldLocale.constData(), charEncoding);
+ "for more information.", oldLocale.constData(), oldEncoding.data());
} else if (warnOnOverride) {
// Let the user know we over-rode their configuration.
qWarning("Detected locale \"%s\" with character encoding \"%s\", which is not UTF-8.\n"
"Qt depends on a UTF-8 locale, and has switched to \"%s\" instead.\n"
"If this causes problems, reconfigure your locale. See the locale(1) manual\n"
"for more information.",
- oldLocale.constData(), charEncoding, newLocale.constData());
+ oldLocale.constData(), oldEncoding.data(), newLocale.constData());
}
}
# endif // Platform choice
@@ -745,7 +764,8 @@ void QCoreApplicationPrivate::initLocale()
to reset the locale that is used for number formatting to "C"-locale.
\sa QGuiApplication, QAbstractEventDispatcher, QEventLoop,
- {Semaphores Example}, {Wait Conditions Example}
+ {Producer and Consumer using Semaphores},
+ {Producer and Consumer using Wait Conditions}
*/
/*!
@@ -984,7 +1004,10 @@ QCoreApplication::~QCoreApplication()
and must be set before a QCoreApplication instance is created.
\note It is strongly recommended not to enable this option since
- it introduces security risks.
+ it introduces security risks. If this application does enable the flag and
+ starts child processes, it should drop the privileges as early as possible
+ by calling \c{setuid(2)} for itself, or at the latest by using the
+ QProcess::UnixProcessParameters::ResetIds flag.
*/
void QCoreApplication::setSetuidAllowed(bool allow)
{
@@ -1004,7 +1027,6 @@ bool QCoreApplication::isSetuidAllowed()
return QCoreApplicationPrivate::setuidAllowed;
}
-
/*!
Sets the attribute \a attribute if \a on is true;
otherwise clears the attribute.
@@ -1017,6 +1039,10 @@ bool QCoreApplication::isSetuidAllowed()
*/
void QCoreApplication::setAttribute(Qt::ApplicationAttribute attribute, bool on)
{
+ // Since we bit-shift these values, we can't go higher than 32 on 32 bit operating systems
+ // without changing the storage type of QCoreApplicationPrivate::attribs to quint64.
+ static_assert(Qt::AA_AttributeCount <= sizeof(QCoreApplicationPrivate::attribs) * CHAR_BIT);
+
if (on)
QCoreApplicationPrivate::attribs |= 1 << attribute;
else
@@ -1065,6 +1091,14 @@ bool QCoreApplication::testAttribute(Qt::ApplicationAttribute attribute)
\brief Whether the use of the QEventLoopLocker feature can cause the
application to quit.
+ When this property is \c true the release of the last remaining
+ QEventLoopLocker operating on the application will attempt to
+ quit the application.
+
+ Note that attempting a quit may not necessarily result in the
+ application quitting, for example if there still are open windows,
+ or the QEvent::Quit event is ignored.
+
The default is \c true.
\sa QEventLoopLocker
@@ -1092,7 +1126,7 @@ void QCoreApplication::setQuitLockEnabled(bool enabled)
bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event)
{
bool selfRequired = QCoreApplicationPrivate::threadRequiresCoreApplication();
- if (!self && selfRequired)
+ if (selfRequired && !self)
return false;
// Make it possible for Qt Script to hook into events even
@@ -1112,6 +1146,11 @@ bool QCoreApplication::notifyInternal2(QObject *receiver, QEvent *event)
QScopedScopeLevelCounter scopeLevelCounter(threadData);
if (!selfRequired)
return doNotify(receiver, event);
+
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+ if (threadData->thread.loadRelaxed() != QCoreApplicationPrivate::mainThread())
+ return false;
+#endif
return self->notify(receiver, event);
}
@@ -1170,7 +1209,7 @@ bool QCoreApplication::forwardEvent(QObject *receiver, QEvent *event, QEvent *or
\endlist
\b{Future direction:} This function will not be called for objects that live
- outside the main thread in Qt 6. Applications that need that functionality
+ outside the main thread in Qt 7. Applications that need that functionality
should find other solutions for their event inspection needs in the meantime.
The change may be extended to the main thread, causing this function to be
deprecated.
@@ -1188,6 +1227,11 @@ bool QCoreApplication::notify(QObject *receiver, QEvent *event)
Q_ASSERT(receiver);
Q_ASSERT(event);
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+ Q_ASSERT(receiver->d_func()->threadData.loadAcquire()->thread.loadRelaxed()
+ == QCoreApplicationPrivate::mainThread());
+#endif
+
// no events are delivered after ~QCoreApplication() has started
if (QCoreApplicationPrivate::is_app_closing)
return true;
@@ -1235,7 +1279,9 @@ bool QCoreApplicationPrivate::sendThroughApplicationEventFilters(QObject *receiv
bool QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject *receiver, QEvent *event)
{
- if (receiver != QCoreApplication::instance() && receiver->d_func()->extraData) {
+ if ((receiver->d_func()->threadData.loadRelaxed()->thread.loadAcquire() != mainThread()
+ || receiver != QCoreApplication::instance())
+ && receiver->d_func()->extraData) {
for (qsizetype i = 0; i < receiver->d_func()->extraData->eventFilters.size(); ++i) {
QObject *obj = receiver->d_func()->extraData->eventFilters.at(i);
if (!obj)
@@ -1266,8 +1312,8 @@ bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event)
Q_TRACE_EXIT(QCoreApplication_notify_exit, consumed, filtered);
// send to all application event filters (only does anything in the main thread)
- if (QCoreApplication::self
- && receiver->d_func()->threadData.loadRelaxed()->thread.loadAcquire() == mainThread()
+ if (receiver->d_func()->threadData.loadRelaxed()->thread.loadAcquire() == mainThread()
+ && QCoreApplication::self
&& QCoreApplication::self->d_func()->sendThroughApplicationEventFilters(receiver, event)) {
filtered = true;
return filtered;
@@ -1334,7 +1380,8 @@ bool QCoreApplication::closingDown()
\threadsafe
- \sa exec(), QTimer, QEventLoop::processEvents(), sendPostedEvents()
+ \sa exec(), QTimer, QChronoTimer, QEventLoop::processEvents(),
+ sendPostedEvents()
*/
void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags)
{
@@ -1345,12 +1392,29 @@ void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags)
}
/*!
- \overload processEvents()
+ \overload
Processes pending events for the calling thread for \a ms
milliseconds or until there are no more events to process,
whichever is shorter.
+ This is equivalent to calling:
+ \code
+ QCoreApplication::processEvents(flags, QDeadlineTimer(ms));
+ \endcode
+*/
+void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags, int ms)
+{
+ QCoreApplication::processEvents(flags, QDeadlineTimer(ms));
+}
+
+/*!
+ \since 6.7
+ \overload
+
+ Processes pending events for the calling thread untile \a deadline has expired,
+ or until there are no more events to process, whichever happens first.
+
Use of this function is discouraged. Instead, prefer to move long
operations out of the GUI thread into an auxiliary one and to completely
avoid nested event loop processing. If event processing is really
@@ -1366,9 +1430,9 @@ void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags)
\threadsafe
- \sa exec(), QTimer, QEventLoop::processEvents()
+ \sa exec(), QTimer, QChronoTimer, QEventLoop::processEvents()
*/
-void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags, int ms)
+void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags, QDeadlineTimer deadline)
{
// ### TODO: consider splitting this method into a public and a private
// one, so that a user-invoked processEvents can be detected
@@ -1376,10 +1440,9 @@ void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags, int m
QThreadData *data = QThreadData::current();
if (!data->hasEventDispatcher())
return;
- QElapsedTimer start;
- start.start();
+
while (data->eventDispatcher.loadRelaxed()->processEvents(flags & ~QEventLoop::WaitForMoreEvents)) {
- if (start.elapsed() > ms)
+ if (deadline.hasExpired())
break;
}
}
@@ -1397,10 +1460,10 @@ void QCoreApplication::processEvents(QEventLoop::ProcessEventsFlags flags, int m
main event loop receives events from the window system and
dispatches these to the application widgets.
- To make your application perform idle processing (by executing a
- special function whenever there are no pending events), use a
- QTimer with 0 timeout. More advanced idle processing schemes can
- be achieved using processEvents().
+ To make your application perform idle processing (by executing a special
+ function whenever there are no pending events), use a QChronoTimer
+ with 0ns timeout. More advanced idle processing schemes can be achieved
+ using processEvents().
We recommend that you connect clean-up code to the
\l{QCoreApplication::}{aboutToQuit()} signal, instead of putting it in
@@ -1452,6 +1515,8 @@ void QCoreApplicationPrivate::execCleanup()
{
threadData.loadRelaxed()->quitNow = false;
in_exec = false;
+
+ qCDebug(lcDeleteLater) << "Sending deferred delete events as part of exec cleanup";
QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
}
@@ -1635,31 +1700,6 @@ void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority)
return;
}
- if (event->type() == QEvent::DeferredDelete)
- receiver->d_ptr->deleteLaterCalled = true;
-
- if (event->type() == QEvent::DeferredDelete && data == QThreadData::current()) {
- // remember the current running eventloop for DeferredDelete
- // events posted in the receiver's thread.
-
- // Events sent by non-Qt event handlers (such as glib) may not
- // have the scopeLevel set correctly. The scope level makes sure that
- // code like this:
- // foo->deleteLater();
- // qApp->processEvents(); // without passing QEvent::DeferredDelete
- // will not cause "foo" to be deleted before returning to the event loop.
-
- // If the scope level is 0 while loopLevel != 0, we are called from a
- // non-conformant code path, and our best guess is that the scope level
- // should be 1. (Loop level 0 is special: it means that no event loops
- // are running.)
- int loopLevel = data->loopLevel;
- int scopeLevel = data->scopeLevel;
- if (scopeLevel == 0 && loopLevel != 0)
- scopeLevel = 1;
- static_cast<QDeferredDeleteEvent *>(event)->level = loopLevel + scopeLevel;
- }
-
// delete the event on exceptions to protect against memory leaks till the event is
// properly owned in the postEventList
std::unique_ptr<QEvent> eventDeleter(event);
@@ -1686,33 +1726,26 @@ bool QCoreApplication::compressEvent(QEvent *event, QObject *receiver, QPostEven
Q_ASSERT(receiver);
Q_ASSERT(postedEvents);
-#ifdef Q_OS_WIN
+ int receiverPostedEvents = receiver->d_func()->postedEvents.loadRelaxed();
// compress posted timers to this object.
- if (event->type() == QEvent::Timer && receiver->d_func()->postedEvents > 0) {
- int timerId = ((QTimerEvent *) event)->timerId();
- for (const QPostEvent &e : std::as_const(*postedEvents)) {
- if (e.receiver == receiver && e.event && e.event->type() == QEvent::Timer
- && ((QTimerEvent *) e.event)->timerId() == timerId) {
+ if (event->type() == QEvent::Timer && receiverPostedEvents > 0) {
+ int timerId = static_cast<QTimerEvent *>(event)->timerId();
+ auto sameReceiver = [receiver](const QPostEvent &e) { return e.receiver == receiver; };
+ auto it = std::find_if(postedEvents->cbegin(), postedEvents->cend(), sameReceiver);
+ while (receiverPostedEvents > 0 && it != postedEvents->cend()) {
+ if (it->event && it->event->type() == QEvent::Timer
+ && static_cast<QTimerEvent *>(it->event)->timerId() == timerId) {
delete event;
return true;
}
- }
- return false;
- }
-#endif
- if (event->type() == QEvent::DeferredDelete) {
- if (receiver->d_ptr->deleteLaterCalled) {
- // there was a previous DeferredDelete event, so we can drop the new one
- delete event;
- return true;
+ if (--receiverPostedEvents)
+ it = std::find_if(it + 1, postedEvents->cend(), sameReceiver);
}
- // deleteLaterCalled is set to true in postedEvents when queueing the very first
- // deferred deletion event.
return false;
}
- if (event->type() == QEvent::Quit && receiver->d_func()->postedEvents > 0) {
+ if (event->type() == QEvent::Quit && receiverPostedEvents > 0) {
for (const QPostEvent &cur : std::as_const(*postedEvents)) {
if (cur.receiver != receiver
|| cur.event == nullptr
@@ -1846,14 +1879,37 @@ void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type
// events posted by the current event loop; or
// 3) if the event was posted before the outermost event loop.
- int eventLevel = static_cast<QDeferredDeleteEvent *>(pe.event)->loopLevel();
- int loopLevel = data->loopLevel + data->scopeLevel;
- const bool allowDeferredDelete =
- (eventLevel > loopLevel
- || (!eventLevel && loopLevel > 0)
- || (event_type == QEvent::DeferredDelete
- && eventLevel == loopLevel));
+ const auto *event = static_cast<QDeferredDeleteEvent *>(pe.event);
+ qCDebug(lcDeleteLater) << "Processing deferred delete event for" << pe.receiver
+ << "with loop level" << event->loopLevel() << "and scope level" << event->scopeLevel();
+
+ qCDebug(lcDeleteLater) << "Checking" << data->thread << "with loop level"
+ << data->loopLevel << "and scope level" << data->scopeLevel;
+
+ bool allowDeferredDelete = false;
+ if (event->loopLevel() == 0 && data->loopLevel > 0) {
+ qCDebug(lcDeleteLater) << "Event was posted outside outermost event loop"
+ << "and current thread has an event loop running.";
+ allowDeferredDelete = true;
+ } else {
+ const int totalEventLevel = event->loopLevel() + event->scopeLevel();
+ const int totalThreadLevel = data->loopLevel + data->scopeLevel;
+
+ if (totalEventLevel > totalThreadLevel) {
+ qCDebug(lcDeleteLater) << "Combined levels of event" << totalEventLevel
+ << "is higher than thread" << totalThreadLevel;
+ allowDeferredDelete = true;
+ } else if (event_type == QEvent::DeferredDelete && totalEventLevel == totalThreadLevel) {
+ qCDebug(lcDeleteLater) << "Explicit send of DeferredDelete and"
+ << "levels of event" << totalEventLevel
+ << "is same as thread" << totalThreadLevel;
+ allowDeferredDelete = true;
+ }
+ }
+
if (!allowDeferredDelete) {
+ qCDebug(lcDeleteLater) << "Failed conditions for deferred delete. Deferring again";
+
// cannot send deferred delete
if (!event_type && !receiver) {
// we must copy it first; we want to re-post the event
@@ -1870,6 +1926,8 @@ void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type
data->postEventList.addEvent(pe_copy);
}
continue;
+ } else {
+ qCDebug(lcDeleteLater) << "Sending deferred delete to" << pe.receiver;
}
}
@@ -2044,7 +2102,13 @@ bool QCoreApplicationPrivate::canQuitAutomatically()
if (!in_exec)
return false;
- if (quitLockEnabled && quitLockRef.loadRelaxed())
+ // The automatic quit functionality is triggered by
+ // both QEventLoopLocker and maybeLastWindowClosed.
+ // In either case, we don't want to quit if there
+ // are active QEventLoopLockers, even if quitLockEnabled
+ // is not enabled, as the property signals whether to
+ // trigger the automatic quit, not whether to block it.
+ if (quitLockRef.loadRelaxed())
return false;
return true;
@@ -2132,6 +2196,12 @@ void QCoreApplicationPrivate::quit()
last-second cleanup. Note that no user interaction is possible in
this state.
+ \note At this point the main event loop is still running, but will
+ not process further events on return except QEvent::DeferredDelete
+ events for objects deleted via deleteLater(). If event processing is
+ needed, use a nested event loop or call QCoreApplication::processEvents()
+ manually.
+
\sa quit()
*/
@@ -2155,7 +2225,7 @@ void QCoreApplicationPrivate::quit()
to all toplevel widgets, where a reimplementation of changeEvent can
re-translate the user interface by passing user-visible strings via the
tr() function to the respective property setters. User-interface classes
- generated by Qt Designer provide a \c retranslateUi() function that can be
+ generated by \QD provide a \c retranslateUi() function that can be
called.
The function returns \c true on success and false on failure.
@@ -2281,7 +2351,8 @@ static void replacePercentN(QString *result, int n)
This function is not virtual. You can use alternative translation
techniques by subclassing \l QTranslator.
- \sa QObject::tr(), installTranslator(), removeTranslator(), translate()
+ \sa QObject::tr(), installTranslator(), removeTranslator(),
+ {Internationalization and Translations}
*/
QString QCoreApplication::translate(const char *context, const char *sourceText,
const char *disambiguation, int n)
@@ -2439,10 +2510,10 @@ QString QCoreApplication::applicationFilePath()
if (d->argc) {
static QByteArray procName = QByteArray(d->argv[0]);
- if (procName != d->argv[0]) {
+ if (procName != QByteArrayView(d->argv[0])) {
// clear the cache if the procname changes, so we reprocess it.
QCoreApplicationPrivate::clearApplicationFilePath();
- procName = QByteArray(d->argv[0]);
+ procName.assign(d->argv[0]);
}
}
@@ -2586,7 +2657,7 @@ QStringList QCoreApplication::arguments()
\brief the name of the organization that wrote this application
The value is used by the QSettings class when it is constructed
- using the empty constructor. This saves having to repeat this
+ using the default constructor. This saves having to repeat this
information each time a QSettings object is created.
On Mac, QSettings uses \l {QCoreApplication::}{organizationDomain()} as the organization
@@ -2626,7 +2697,7 @@ QString QCoreApplication::organizationName()
\brief the Internet domain of the organization that wrote this application
The value is used by the QSettings class when it is constructed
- using the empty constructor. This saves having to repeat this
+ using the default constructor. This saves having to repeat this
information each time a QSettings object is created.
On Mac, QSettings uses organizationDomain() as the organization
@@ -2662,11 +2733,15 @@ QString QCoreApplication::organizationDomain()
\property QCoreApplication::applicationName
\brief the name of this application
- The value is used by the QSettings class when it is constructed
- using the empty constructor. This saves having to repeat this
- information each time a QSettings object is created.
+ The application name is used in various Qt classes and modules,
+ most prominently in \l{QSettings} when it is constructed using the default constructor.
+ Other uses are in formatted logging output (see \l{qSetMessagePattern()}),
+ in output by \l{QCommandLineParser}, in \l{QTemporaryDir} and \l{QTemporaryFile}
+ default paths, and in some file locations of \l{QStandardPaths}.
+ \l{Qt D-Bus}, \l{Accessibility}, and the XCB platform integration make use
+ of the application name, too.
- If not set, the application name defaults to the executable name (since 5.0).
+ If not set, the application name defaults to the executable name.
\sa organizationName, organizationDomain, applicationVersion, applicationFilePath()
*/
@@ -2766,8 +2841,8 @@ Qt::PermissionStatus QCoreApplication::checkPermission(const QPermission &permis
}
/*!
- \fn template<typename Functor> void QCoreApplication::requestPermission(
- const QPermission &permission, Functor functor)
+ \fn template <typename Functor> void QCoreApplication::requestPermission(
+ const QPermission &permission, Functor &&functor)
Requests the given \a permission.
@@ -2820,8 +2895,9 @@ Qt::PermissionStatus QCoreApplication::checkPermission(const QPermission &permis
qApp->requestPermission(QCameraPermission{}, this, &CamerWidget::permissionUpdated);
\endcode
- If \a context is destroyed before the request completes,
- the \a functor will not be called.
+ The \a functor will be called in the thread of the \a context object. If
+ \a context is destroyed before the request completes, the \a functor will
+ not be called.
\include permissions.qdocinc requestPermission-postamble
@@ -2835,34 +2911,63 @@ Qt::PermissionStatus QCoreApplication::checkPermission(const QPermission &permis
Called by the various requestPermission overloads to perform the request.
- Calls the functor encapsulated in the \a slotObj in the given \a context
+ Calls the functor encapsulated in the \a slotObjRaw in the given \a context
(which may be \c nullptr).
*/
void QCoreApplication::requestPermission(const QPermission &requestedPermission,
- QtPrivate::QSlotObjectBase *slotObj, const QObject *context)
+ QtPrivate::QSlotObjectBase *slotObjRaw, const QObject *context)
{
+ QtPrivate::SlotObjUniquePtr slotObj{slotObjRaw}; // adopts
+ Q_ASSERT(slotObj);
+
if (QThread::currentThread() != QCoreApplicationPrivate::mainThread()) {
qWarning(lcPermissions, "Permissions can only be requested from the GUI (main) thread");
return;
}
- Q_ASSERT(slotObj);
+ class PermissionReceiver : public QObject
+ {
+ public:
+ explicit PermissionReceiver(QtPrivate::SlotObjUniquePtr &&slotObject, const QObject *context)
+ : slotObject(std::move(slotObject)), context(context ? context : this)
+ {
+ Q_ASSERT(this->context);
+ moveToThread(this->context->thread());
+ }
+
+ void finalizePermissionRequest(const QPermission &permission)
+ {
+ Q_ASSERT(slotObject);
+ // only execute if context object is still alive
+ if (context) {
+ void *args[] = { nullptr, const_cast<QPermission *>(&permission) };
+ slotObject->call(const_cast<QObject *>(context.data()), args);
+ }
+ deleteLater();
+ }
+
+ private:
+ QtPrivate::SlotObjSharedPtr slotObject;
+ QPointer<const QObject> context;
+ };
+
+ PermissionReceiver *receiver = new PermissionReceiver(std::move(slotObj), context);
QPermissions::Private::requestPermission(requestedPermission, [=](Qt::PermissionStatus status) {
- Q_ASSERT_X(status != Qt::PermissionStatus::Undetermined, "QPermission",
- "QCoreApplication::requestPermission() should never return Undetermined");
- if (status == Qt::PermissionStatus::Undetermined)
+ if (status == Qt::PermissionStatus::Undetermined) {
+ Q_ASSERT_X(false, "QPermission",
+ "Internal error: requestPermission() should never return Undetermined");
status = Qt::PermissionStatus::Denied;
+ }
if (QCoreApplication::self) {
QPermission permission = requestedPermission;
permission.m_status = status;
-
- void *argv[] = { nullptr, &permission };
- slotObj->call(const_cast<QObject*>(context), argv);
+ QMetaObject::invokeMethod(receiver,
+ &PermissionReceiver::finalizePermissionRequest,
+ Qt::QueuedConnection,
+ permission);
}
-
- slotObj->destroyIfLastRef();
});
}
@@ -2898,11 +3003,6 @@ Q_GLOBAL_STATIC(QRecursiveMutex, libraryPathMutex)
directory (and its existence) may change when the directory of
the application executable becomes known.
- If you want to iterate over the list, you can use the \l foreach
- pseudo-keyword:
-
- \snippet code/src_corelib_kernel_qcoreapplication.cpp 2
-
\sa setLibraryPaths(), addLibraryPath(), removeLibraryPath(), QLibrary,
{How to Create Qt Plugins}
*/
diff --git a/src/corelib/kernel/qcoreapplication.h b/src/corelib/kernel/qcoreapplication.h
index 82580ceb34..0078dc3295 100644
--- a/src/corelib/kernel/qcoreapplication.h
+++ b/src/corelib/kernel/qcoreapplication.h
@@ -8,6 +8,7 @@
#include <QtCore/qstring.h>
#ifndef QT_NO_QOBJECT
#include <QtCore/qcoreevent.h>
+#include <QtCore/qdeadlinetimer.h>
#include <QtCore/qeventloop.h>
#include <QtCore/qobject.h>
#else
@@ -32,6 +33,7 @@ class QTranslator;
class QPostEventList;
class QAbstractEventDispatcher;
class QAbstractNativeEventFilter;
+class QEventLoopLocker;
#if QT_CONFIG(permissions) || defined(Q_QDOC)
class QPermission;
@@ -58,6 +60,11 @@ class Q_CORE_EXPORT QCoreApplication
#endif
Q_DECLARE_PRIVATE(QCoreApplication)
+ friend class QEventLoopLocker;
+#if QT_CONFIG(permissions)
+ using RequestPermissionPrototype = void(*)(QPermission);
+#endif
+
public:
enum { ApplicationFlags = QT_VERSION
};
@@ -87,12 +94,13 @@ public:
static void setSetuidAllowed(bool allow);
static bool isSetuidAllowed();
- static QCoreApplication *instance() { return self; }
+ static QCoreApplication *instance() noexcept { return self; }
#ifndef QT_NO_QOBJECT
static int exec();
static void processEvents(QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents);
static void processEvents(QEventLoop::ProcessEventsFlags flags, int maxtime);
+ static void processEvents(QEventLoop::ProcessEventsFlags flags, QDeadlineTimer deadline);
static bool sendEvent(QObject *receiver, QEvent *event);
static void postEvent(QObject *receiver, QEvent *event, int priority = Qt::NormalEventPriority);
@@ -116,66 +124,45 @@ public:
# ifdef Q_QDOC
template <typename Functor>
- void requestPermission(const QPermission &permission, Functor functor);
- template <typename Functor>
void requestPermission(const QPermission &permission, const QObject *context, Functor functor);
# else
- template <typename Slot> // requestPermission to a QObject slot
+ // requestPermission with context or receiver object; need to require here that receiver is the
+ // right type to avoid ambiguity with the private implementation function.
+ template <typename Functor,
+ std::enable_if_t<
+ QtPrivate::AreFunctionsCompatible<RequestPermissionPrototype, Functor>::value,
+ bool> = true>
void requestPermission(const QPermission &permission,
- const typename QtPrivate::FunctionPointer<Slot>::Object *receiver, Slot slot)
+ const typename QtPrivate::ContextTypeForFunctor<Functor>::ContextType *receiver,
+ Functor &&func)
{
- using CallbackSignature = QtPrivate::FunctionPointer<void (*)(QPermission)>;
- using SlotSignature = QtPrivate::FunctionPointer<Slot>;
-
- static_assert(int(SlotSignature::ArgumentCount) <= int(CallbackSignature::ArgumentCount),
- "Slot requires more arguments than what can be provided.");
- static_assert((QtPrivate::CheckCompatibleArguments<typename CallbackSignature::Arguments, typename SlotSignature::Arguments>::value),
- "Slot arguments are not compatible (must be QPermission)");
-
- auto slotObj = new QtPrivate::QSlotObject<Slot, typename SlotSignature::Arguments, void>(slot);
- requestPermission(permission, slotObj, receiver);
- }
-
- // requestPermission to a functor or function pointer (with context)
- template <typename Func, std::enable_if_t<
- !QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
- && !std::is_same<const char *, Func>::value, bool> = true>
- void requestPermission(const QPermission &permission, const QObject *context, Func func)
- {
- using CallbackSignature = QtPrivate::FunctionPointer<void (*)(QPermission)>;
- constexpr int MatchingArgumentCount = QtPrivate::ComputeFunctorArgumentCount<
- Func, CallbackSignature::Arguments>::Value;
-
- static_assert(MatchingArgumentCount == 0
- || MatchingArgumentCount == CallbackSignature::ArgumentCount,
- "Functor arguments are not compatible (must be QPermission)");
-
- QtPrivate::QSlotObjectBase *slotObj = nullptr;
- if constexpr (MatchingArgumentCount == CallbackSignature::ArgumentCount) {
- slotObj = new QtPrivate::QFunctorSlotObject<Func, 1,
- typename CallbackSignature::Arguments, void>(std::move(func));
- } else {
- slotObj = new QtPrivate::QFunctorSlotObject<Func, 0,
- typename QtPrivate::List_Left<void, 0>::Value, void>(std::move(func));
- }
-
- requestPermission(permission, slotObj, context);
+ requestPermission(permission,
+ QtPrivate::makeCallableObject<RequestPermissionPrototype>(std::forward<Functor>(func)),
+ receiver);
}
+# endif // Q_QDOC
+#ifndef QT_NO_CONTEXTLESS_CONNECT
+ #ifdef Q_QDOC
+ template <typename Functor>
+ #else
// requestPermission to a functor or function pointer (without context)
- template <typename Func, std::enable_if_t<
- !QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
- && !std::is_same<const char *, Func>::value, bool> = true>
- void requestPermission(const QPermission &permission, Func func)
+ template <typename Functor,
+ std::enable_if_t<
+ QtPrivate::AreFunctionsCompatible<RequestPermissionPrototype, Functor>::value,
+ bool> = true>
+ #endif
+ void requestPermission(const QPermission &permission, Functor &&func)
{
- requestPermission(permission, nullptr, std::move(func));
+ requestPermission(permission, nullptr, std::forward<Functor>(func));
}
+#endif // QT_NO_CONTEXTLESS_CONNECT
private:
+ // ### Qt 7: rename to requestPermissionImpl to avoid ambiguity
void requestPermission(const QPermission &permission,
QtPrivate::QSlotObjectBase *slotObj, const QObject *context);
public:
-# endif // Q_QDOC
#endif // QT_CONFIG(permission)
diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h
index 56d726cff5..bfd65d2c9a 100644
--- a/src/corelib/kernel/qcoreapplication_p.h
+++ b/src/corelib/kernel/qcoreapplication_p.h
@@ -25,6 +25,7 @@
#include "QtCore/qsettings.h"
#endif
#ifndef QT_NO_QOBJECT
+#include <qloggingcategory.h>
#include "private/qobject_p.h"
#include "private/qlocking_p.h"
#endif
@@ -35,6 +36,10 @@
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_QOBJECT
+Q_DECLARE_LOGGING_CATEGORY(lcDeleteLater)
+#endif
+
typedef QList<QTranslator*> QTranslatorList;
class QAbstractEventDispatcher;
@@ -103,6 +108,7 @@ public:
virtual void quit();
static QBasicAtomicPointer<QThread> theMainThread;
+ static QBasicAtomicPointer<void> theMainThreadId;
static QThread *mainThread();
static bool threadRequiresCoreApplication();
diff --git a/src/corelib/kernel/qcoreapplication_platform.h b/src/corelib/kernel/qcoreapplication_platform.h
index 5a2543146a..d5f266179e 100644
--- a/src/corelib/kernel/qcoreapplication_platform.h
+++ b/src/corelib/kernel/qcoreapplication_platform.h
@@ -33,7 +33,7 @@ typedef _jobject* jobject;
QT_BEGIN_NAMESPACE
#if defined(Q_OS_ANDROID)
-Q_DECLARE_JNI_TYPE(Context, "Landroid/content/Context;")
+Q_DECLARE_JNI_CLASS(Context, "android/content/Context")
#endif
namespace QNativeInterface
@@ -43,7 +43,7 @@ struct Q_CORE_EXPORT QAndroidApplication
{
QT_DECLARE_NATIVE_INTERFACE(QAndroidApplication, 1, QCoreApplication)
#ifdef Q_QDOC
- static jobject context();
+ static QJniObject context();
#else
static QtJniTypes::Context context();
#endif
diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp
index b01f1c2a69..9c99530268 100644
--- a/src/corelib/kernel/qcoreevent.cpp
+++ b/src/corelib/kernel/qcoreevent.cpp
@@ -3,6 +3,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcoreevent.h"
+#include "qcoreevent_p.h"
#include "qcoreapplication.h"
#include "qcoreapplication_p.h"
@@ -78,6 +79,8 @@ Q_TRACE_POINT(qtcore, QEvent_dtor, QEvent *event, QEvent::Type type);
\value ChildAdded An object gets a child (QChildEvent).
\value ChildPolished A widget child gets polished (QChildEvent).
\value ChildRemoved An object loses a child (QChildEvent).
+ \value [since 6.7] ChildWindowAdded A child window was added to the window.
+ \value [since 6.7] ChildWindowRemoved A child window was removed from the window.
\value Clipboard The clipboard contents have changed.
\value Close Widget was closed (QCloseEvent).
\value CloseSoftwareInputPanel A widget wants to close the software input panel (SIP).
@@ -85,7 +88,8 @@ Q_TRACE_POINT(qtcore, QEvent_dtor, QEvent *event, QEvent::Type type);
\value ContextMenu Context popup menu (QContextMenuEvent).
\value CursorChange The widget's cursor has changed.
\value DeferredDelete The object will be deleted after it has cleaned up (QDeferredDeleteEvent)
- \value DevicePixelRatioChange The devicePixelRatio has changed for this widget's or window's underlying backing store
+ \value [since 6.6] DevicePixelRatioChange
+ The devicePixelRatio has changed for this widget's or window's underlying backing store.
\value DragEnter The cursor enters a widget during a drag and drop operation (QDragEnterEvent).
\value DragLeave The cursor leaves a widget during a drag and drop operation (QDragLeaveEvent).
\value DragMove A drag and drop operation is in progress (QDragMoveEvent).
@@ -158,8 +162,12 @@ Q_TRACE_POINT(qtcore, QEvent_dtor, QEvent *event, QEvent::Type type);
\value OrientationChange The screens orientation has changes (QScreenOrientationChangeEvent).
\value Paint Screen update necessary (QPaintEvent).
\value PaletteChange Palette of the widget changed.
- \value ParentAboutToChange The widget parent is about to change.
- \value ParentChange The widget parent has changed.
+ \value ParentAboutToChange The object parent is about to change.
+ Only sent to some object types, such as QWidget.
+ \value ParentChange The object parent has changed.
+ Only sent to some object types, such as QWidget.
+ \value [since 6.7] ParentWindowAboutToChange The parent window is about to change.
+ \value [since 6.7] ParentWindowChange The parent window has changed.
\value PlatformPanel A platform specific panel has been requested.
\value PlatformSurface A native platform surface has been created or is about to be destroyed (QPlatformSurfaceEvent).
\omitvalue Pointer
@@ -432,8 +440,9 @@ struct QBasicAtomicBitField {
QBasicAtomicInteger<uint> &entry = data[which / BitsPerInt];
const uint old = entry.loadRelaxed();
const uint bit = 1U << (which % BitsPerInt);
- return !(old & bit) // wasn't taken
- && entry.testAndSetRelaxed(old, old | bit); // still wasn't taken
+ if (old & bit)
+ return false; // already taken
+ return (entry.fetchAndOrRelaxed(bit) & bit) == 0;
// don't update 'next' here - it's unlikely that it will need
// to be updated, in the general case, and having 'next'
@@ -510,12 +519,12 @@ int QEvent::registerEventType(int hint) noexcept
started one or more timers. Each timer has a unique identifier. A
timer is started with QObject::startTimer().
- The QTimer class provides a high-level programming interface that
+ The QChronoTimer class provides a high-level programming interface that
uses signals instead of events. It also provides single-shot timers.
The event handler QObject::timerEvent() receives timer events.
- \sa QTimer, QObject::timerEvent(), QObject::startTimer(),
+ \sa QChronoTimer, QObject::timerEvent(), QObject::startTimer(),
QObject::killTimer()
*/
@@ -633,23 +642,14 @@ Q_IMPL_EVENT_COMMON(QDynamicPropertyChangeEvent)
*/
/*!
- Constructs a deferred delete event with an initial loopLevel() of zero.
+ Constructs a deferred delete event with the given loop and scope level.
*/
-QDeferredDeleteEvent::QDeferredDeleteEvent()
- : QEvent(QEvent::DeferredDelete)
- , level(0)
+QDeferredDeleteEvent::QDeferredDeleteEvent(int loopLevel, int scopeLevel)
+ : QEvent(QEvent::DeferredDelete), m_loopLevel(loopLevel), m_scopeLevel(scopeLevel)
{ }
Q_IMPL_EVENT_COMMON(QDeferredDeleteEvent)
-/*! \fn int QDeferredDeleteEvent::loopLevel() const
-
- Returns the loop-level in which the event was posted. The
- loop-level is set by QCoreApplication::postEvent().
-
- \sa QObject::deleteLater()
-*/
-
QT_END_NAMESPACE
#include "moc_qcoreevent.cpp"
diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h
index 0c83919bc5..a65dbee7da 100644
--- a/src/corelib/kernel/qcoreevent.h
+++ b/src/corelib/kernel/qcoreevent.h
@@ -34,7 +34,7 @@ protected: \
Class* Class::clone() const \
{ \
auto c = new Class(*this); \
- QEvent *e = c; \
+ [[maybe_unused]] QEvent *e = c; \
/* check that covariant return is safe to add */ \
Q_ASSERT(reinterpret_cast<quintptr>(c) == reinterpret_cast<quintptr>(e)); \
return c; \
@@ -77,7 +77,7 @@ public:
Hide = 18, // widget is hidden
Close = 19, // request to close widget
Quit = 20, // request to quit application
- ParentChange = 21, // widget has been reparented
+ ParentChange = 21, // object has been reparented
ParentAboutToChange = 131, // sent just before the parent change is done
ThreadChange = 22, // object has changed threads
WindowActivate = 24, // window was activated
@@ -286,6 +286,11 @@ public:
DevicePixelRatioChange = 222,
+ ChildWindowAdded = 223,
+ ChildWindowRemoved = 224,
+ ParentWindowAboutToChange = 225,
+ ParentWindowChange = 226,
+
// 512 reserved for Qt Jambi's MetaCall event
// 513 reserved for Qt Jambi's DeleteOnMainThread event
@@ -349,6 +354,8 @@ private:
friend class QApplication;
friend class QGraphicsScenePrivate;
// from QtTest:
+ // QtWebEngine event handling requires forwarding events as spontaneous.
+ // Impersonated QSpontaneKeyEvent in QtWebEngine to handle such cases.
friend class QSpontaneKeyEvent;
// needs this:
Q_ALWAYS_INLINE
@@ -395,18 +402,6 @@ private:
QByteArray n;
};
-class Q_CORE_EXPORT QDeferredDeleteEvent : public QEvent
-{
- Q_DECL_EVENT_COMMON(QDeferredDeleteEvent)
-public:
- explicit QDeferredDeleteEvent();
- int loopLevel() const { return level; }
-
-private:
- int level;
- friend class QCoreApplication;
-};
-
QT_END_NAMESPACE
#endif // QCOREEVENT_H
diff --git a/src/corelib/kernel/qcoreevent_p.h b/src/corelib/kernel/qcoreevent_p.h
new file mode 100644
index 0000000000..ac90baad9b
--- /dev/null
+++ b/src/corelib/kernel/qcoreevent_p.h
@@ -0,0 +1,39 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QCOREEVENT_P_H
+#define QCOREEVENT_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/qcoreevent.h"
+
+QT_BEGIN_NAMESPACE
+
+class QCoreApplication;
+
+class QDeferredDeleteEvent : public QEvent
+{
+ Q_DECL_EVENT_COMMON(QDeferredDeleteEvent)
+public:
+ explicit QDeferredDeleteEvent(int loopLevel, int scopeLevel);
+ int loopLevel() const { return m_loopLevel; }
+ int scopeLevel() const { return m_scopeLevel; }
+
+private:
+ int m_loopLevel = 0;
+ int m_scopeLevel = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QCOREEVENT_P_H
diff --git a/src/corelib/kernel/qdeadlinetimer.cpp b/src/corelib/kernel/qdeadlinetimer.cpp
index a5d16ddf65..f99e68f990 100644
--- a/src/corelib/kernel/qdeadlinetimer.cpp
+++ b/src/corelib/kernel/qdeadlinetimer.cpp
@@ -2,298 +2,47 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdeadlinetimer.h"
-#include "qdeadlinetimer_p.h"
#include "private/qnumeric_p.h"
QT_BEGIN_NAMESPACE
QT_IMPL_METATYPE_EXTERN(QDeadlineTimer)
-namespace {
- class TimeReference
- {
- enum : unsigned {
- umega = 1000 * 1000,
- ugiga = umega * 1000
- };
-
- enum : qint64 {
- kilo = 1000,
- mega = kilo * 1000,
- giga = mega * 1000
- };
-
- public:
- enum RoundingStrategy {
- RoundDown,
- RoundUp,
- RoundDefault = RoundDown
- };
-
- static constexpr qint64 Min = std::numeric_limits<qint64>::min();
- static constexpr qint64 Max = std::numeric_limits<qint64>::max();
-
- inline TimeReference(qint64 = 0, unsigned = 0);
- inline void updateTimer(qint64 &, unsigned &);
-
- inline bool addNanoseconds(qint64);
- inline bool addMilliseconds(qint64);
- bool addSecsAndNSecs(qint64, qint64);
-
- inline bool subtract(const qint64, const unsigned);
-
- inline bool toMilliseconds(qint64 *, RoundingStrategy = RoundDefault) const;
- inline bool toNanoseconds(qint64 *) const;
-
- inline void saturate(bool toMax);
- static bool sign(qint64, qint64);
-
- private:
- bool adjust(const qint64, const unsigned, qint64 = 0);
-
- private:
- qint64 secs;
- unsigned nsecs;
- };
-}
-
-inline TimeReference::TimeReference(qint64 t1, unsigned t2)
- : secs(t1), nsecs(t2)
-{
-}
-
-inline void TimeReference::updateTimer(qint64 &t1, unsigned &t2)
-{
- t1 = secs;
- t2 = nsecs;
-}
-
-inline void TimeReference::saturate(bool toMax)
-{
- secs = toMax ? Max : Min;
-}
-
-/*!
- * \internal
- *
- * Determines the sign of a (seconds, nanoseconds) pair
- * for differentiating overflow from underflow. It doesn't
- * deal with equality as it shouldn't ever be called in that case.
- *
- * Returns true if the pair represents a positive time offset
- * false otherwise.
- */
-bool TimeReference::sign(qint64 secs, qint64 nsecs)
-{
- if (secs > 0) {
- if (nsecs > 0)
- return true;
- } else {
- if (nsecs < 0)
- return false;
- }
+using namespace std::chrono;
- // They are different in sign
- secs += nsecs / giga;
- if (secs > 0)
- return true;
- else if (secs < 0)
- return false;
-
- // We should never get over|underflow out of
- // the case: secs * giga == -nsecs
- // So the sign of nsecs is the deciding factor
- Q_ASSERT(nsecs % giga != 0);
- return nsecs > 0;
-}
-
-#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
-inline bool TimeReference::addNanoseconds(qint64 arg)
+namespace {
+struct TimeReference : std::numeric_limits<qint64>
{
- return addSecsAndNSecs(arg / giga, arg % giga);
+ static constexpr qint64 Min = min();
+ static constexpr qint64 Max = max();
+};
}
-inline bool TimeReference::addMilliseconds(qint64 arg)
+template <typename Duration1, typename... Durations>
+static qint64 add_saturate(qint64 t1, Duration1 dur, Durations... extra)
{
- return addSecsAndNSecs(arg / kilo, (arg % kilo) * mega);
-}
+ qint64 v = dur.count();
+ qint64 saturated = std::numeric_limits<qint64>::max();
+ if (v < 0)
+ saturated = std::numeric_limits<qint64>::min();
-/*!
- * \internal
- *
- * Adds \a t1 addSecs seconds and \a addNSecs nanoseconds to the
- * time reference. The arguments are normalized to seconds (qint64)
- * and nanoseconds (unsigned) before the actual calculation is
- * delegated to adjust(). If the nanoseconds are negative the
- * owed second used for the normalization is passed on to adjust()
- * as third argument.
- *
- * Returns true if operation was successful, false on over|underflow
- */
-bool TimeReference::addSecsAndNSecs(qint64 addSecs, qint64 addNSecs)
-{
- // Normalize the arguments
- if (qAbs(addNSecs) >= giga) {
- if (add_overflow<qint64>(addSecs, addNSecs / giga, &addSecs))
- return false;
+ // convert to nanoseconds with saturation
+ using Ratio = std::ratio_divide<typename Duration1::period, nanoseconds::period>;
+ static_assert(Ratio::den == 1, "sub-multiples of nanosecond are not supported");
+ if (qMulOverflow<Ratio::num>(v, &v))
+ return saturated;
- addNSecs %= giga;
+ qint64 r;
+ if (qAddOverflow(t1, v, &r))
+ return saturated;
+ if constexpr (sizeof...(Durations)) {
+ // chain more additions
+ return add_saturate(r, extra...);
}
-
- if (addNSecs < 0)
- return adjust(addSecs, ugiga - unsigned(-addNSecs), -1);
-
- return adjust(addSecs, unsigned(addNSecs));
+ return r;
}
/*!
- * \internal
- *
- * Adds \a t1 seconds and \a t2 nanoseconds to the internal members.
- * Takes into account the additional \a carrySeconds we may owe or need to carry over.
- *
- * Returns true if operation was successful, false on over|underflow
- */
-bool TimeReference::adjust(const qint64 t1, const unsigned t2, qint64 carrySeconds)
-{
- static_assert(QDeadlineTimerNanosecondsInT2);
- nsecs += t2;
- if (nsecs >= ugiga) {
- nsecs -= ugiga;
- carrySeconds++;
- }
-
- // We don't worry about the order of addition, because the result returned by
- // callers of this function is unchanged regardless of us over|underflowing.
- // If we do, we do so by no more than a second, thus saturating the timer to
- // Forever has the same effect as if we did the arithmetic exactly and salvaged
- // the overflow.
- return !add_overflow<qint64>(secs, t1, &secs) && !add_overflow<qint64>(secs, carrySeconds, &secs);
-}
-
-/*!
- * \internal
- *
- * Subtracts \a t1 seconds and \a t2 nanoseconds from the time reference.
- * When normalizing the nanoseconds to a positive number the owed seconds is
- * passed as third argument to adjust() as the seconds may over|underflow
- * if we do the calculation directly. There is little sense to check the
- * seconds for over|underflow here in case we are going to need to carry
- * over a second _after_ we add the nanoseconds.
- *
- * Returns true if operation was successful, false on over|underflow
- */
-inline bool TimeReference::subtract(const qint64 t1, const unsigned t2)
-{
- Q_ASSERT(t2 < ugiga);
- return adjust(-t1, ugiga - t2, -1);
-}
-
-/*!
- * \internal
- *
- * Converts the time reference to milliseconds.
- *
- * Checks are done without making use of mul_overflow because it may
- * not be implemented on some 32bit platforms.
- *
- * Returns true if operation was successful, false on over|underflow
- */
-inline bool TimeReference::toMilliseconds(qint64 *result, RoundingStrategy rounding) const
-{
- static constexpr qint64 maxSeconds = Max / kilo;
- static constexpr qint64 minSeconds = Min / kilo;
- if (secs > maxSeconds || secs < minSeconds)
- return false;
-
- unsigned ns = rounding == RoundDown ? nsecs : nsecs + umega - 1;
-
- return !add_overflow<qint64>(secs * kilo, ns / umega, result);
-}
-
-/*!
- * \internal
- *
- * Converts the time reference to nanoseconds.
- *
- * Checks are done without making use of mul_overflow because it may
- * not be implemented on some 32bit platforms.
- *
- * Returns true if operation was successful, false on over|underflow
- */
-inline bool TimeReference::toNanoseconds(qint64 *result) const
-{
- static constexpr qint64 maxSeconds = Max / giga;
- static constexpr qint64 minSeconds = Min / giga;
- if (secs > maxSeconds || secs < minSeconds)
- return false;
-
- return !add_overflow<qint64>(secs * giga, nsecs, result);
-}
-#else
-inline bool TimeReference::addNanoseconds(qint64 arg)
-{
- return adjust(arg, 0);
-}
-
-inline bool TimeReference::addMilliseconds(qint64 arg)
-{
- static constexpr qint64 maxMilliseconds = Max / mega;
- if (qAbs(arg) > maxMilliseconds)
- return false;
-
- return addNanoseconds(arg * mega);
-}
-
-inline bool TimeReference::addSecsAndNSecs(qint64 addSecs, qint64 addNSecs)
-{
- static constexpr qint64 maxSeconds = Max / giga;
- static constexpr qint64 minSeconds = Min / giga;
- if (addSecs > maxSeconds || addSecs < minSeconds || add_overflow<qint64>(addSecs * giga, addNSecs, &addNSecs))
- return false;
-
- return addNanoseconds(addNSecs);
-}
-
-inline bool TimeReference::adjust(const qint64 t1, const unsigned t2, qint64 carrySeconds)
-{
- static_assert(!QDeadlineTimerNanosecondsInT2);
- Q_UNUSED(t2);
- Q_UNUSED(carrySeconds);
-
- return !add_overflow<qint64>(secs, t1, &secs);
-}
-
-inline bool TimeReference::subtract(const qint64 t1, const unsigned t2)
-{
- Q_UNUSED(t2);
-
- return addNanoseconds(-t1);
-}
-
-inline bool TimeReference::toMilliseconds(qint64 *result, RoundingStrategy rounding) const
-{
- // Force QDeadlineTimer to treat the border cases as
- // over|underflow and saturate the results returned to the user.
- // We don't want to get valid milliseconds out of saturated timers.
- if (secs == Max || secs == Min)
- return false;
-
- *result = secs / mega;
- if (rounding == RoundUp && secs > *result * mega)
- (*result)++;
-
- return true;
-}
-
-inline bool TimeReference::toNanoseconds(qint64 *result) const
-{
- *result = secs;
- return true;
-}
-#endif
-
-/*!
\class QDeadlineTimer
\inmodule QtCore
\brief The QDeadlineTimer class marks a deadline in the future.
@@ -302,6 +51,8 @@ inline bool TimeReference::toNanoseconds(qint64 *result) const
\reentrant
\ingroup tools
+ \compares strong
+
The QDeadlineTimer class is usually used to calculate future deadlines and
verify whether the deadline has expired. QDeadlineTimer can also be used
for deadlines without expiration ("forever"). It forms a counterpart to
@@ -335,11 +86,12 @@ inline bool TimeReference::toNanoseconds(qint64 *result) const
\section1 Timer types
- Like QTimer, QDeadlineTimer can select among different levels of coarseness
- on the timers. You can select precise timing by passing Qt::PreciseTimer to
- the functions that set of change the timer, or you can select coarse timing
- by passing Qt::CoarseTimer. Qt::VeryCoarseTimer is currently interpreted
- the same way as Qt::CoarseTimer.
+ Like QTimer and QChronoTimer, QDeadlineTimer can select among
+ different levels of coarseness on the timers. You can select
+ precise timing by passing Qt::PreciseTimer to the functions that
+ set of change the timer, or you can select coarse timing by passing
+ Qt::CoarseTimer. Qt::VeryCoarseTimer is currently interpreted the same
+ way as Qt::CoarseTimer.
This feature is dependent on support from the operating system: if the OS
does not support a coarse timer functionality, then QDeadlineTimer will
@@ -371,7 +123,7 @@ inline bool TimeReference::toNanoseconds(qint64 *result) const
\snippet code/src_corelib_kernel_qdeadlinetimer.cpp 2
- \sa QTime, QTimer, QDeadlineTimer, Qt::TimerType
+ \sa QTime, QChronoTimer, QDeadlineTimer, Qt::TimerType
*/
/*!
@@ -382,10 +134,12 @@ inline bool TimeReference::toNanoseconds(qint64 *result) const
*/
/*!
+ \fn QDeadlineTimer::QDeadlineTimer()
\fn QDeadlineTimer::QDeadlineTimer(Qt::TimerType timerType)
Constructs an expired QDeadlineTimer object. For this object,
- remainingTime() will return 0.
+ remainingTime() will return 0. If \a timerType is not set, then the object
+ will use the \l{Qt::CoarseTimer}{coarse} \l{QDeadlineTimer#Timer types}{timer type}.
The timer type \a timerType may be ignored, since the timer is already
expired. Similarly, for optimization purposes, this function will not
@@ -415,7 +169,7 @@ inline bool TimeReference::toNanoseconds(qint64 *result) const
from the moment of the creation of this object, if msecs is positive. If \a
msecs is zero, this QDeadlineTimer will be marked as expired, causing
remainingTime() to return zero and deadline() to return an indeterminate
- time point in the past. If \a msecs is -1, the timer will be set to never
+ time point in the past. If \a msecs is negative, the timer will be set to never
expire, causing remainingTime() to return -1 and deadline() to return the
maximum value.
@@ -428,6 +182,9 @@ inline bool TimeReference::toNanoseconds(qint64 *result) const
functionality is required, use QDeadlineTimer::current() and add time to
it.
+ \note Prior to Qt 6.6, the only value that caused the timer to never expire
+ was -1.
+
\sa hasExpired(), isForever(), remainingTime(), setRemainingTime()
*/
QDeadlineTimer::QDeadlineTimer(qint64 msecs, Qt::TimerType type) noexcept
@@ -494,51 +251,70 @@ QDeadlineTimer::QDeadlineTimer(qint64 msecs, Qt::TimerType type) noexcept
/*!
Sets the remaining time for this QDeadlineTimer object to \a msecs
milliseconds from now, if \a msecs has a positive value. If \a msecs is
- zero, this QDeadlineTimer object will be marked as expired, whereas a value
- of -1 will set it to never expire.
+ zero, this QDeadlineTimer object will be marked as expired, whereas a
+ negative value will set it to never expire.
+
+ For optimization purposes, if \a msecs is zero, this function may skip
+ obtaining the current time and may instead use a value known to be in the
+ past. If that happens, deadline() may return an unexpected value and this
+ object cannot be used in calculation of how long it is overdue. If that
+ functionality is required, use QDeadlineTimer::current() and add time to
+ it.
The timer type for this QDeadlineTimer object will be set to the specified \a timerType.
+ \note Prior to Qt 6.6, the only value that caused the timer to never expire
+ was -1.
+
\sa setPreciseRemainingTime(), hasExpired(), isForever(), remainingTime()
*/
void QDeadlineTimer::setRemainingTime(qint64 msecs, Qt::TimerType timerType) noexcept
{
- if (msecs == -1) {
+ if (msecs < 0) {
*this = QDeadlineTimer(Forever, timerType);
- return;
+ } else if (msecs == 0) {
+ *this = QDeadlineTimer(timerType);
+ t1 = std::numeric_limits<qint64>::min();
+ } else {
+ *this = current(timerType);
+ milliseconds ms(msecs);
+ t1 = add_saturate(t1, ms);
}
-
- *this = current(timerType);
-
- TimeReference ref(t1, t2);
- if (!ref.addMilliseconds(msecs))
- ref.saturate(msecs > 0);
- ref.updateTimer(t1, t2);
}
/*!
Sets the remaining time for this QDeadlineTimer object to \a secs seconds
plus \a nsecs nanoseconds from now, if \a secs has a positive value. If \a
- secs is -1, this QDeadlineTimer will be set it to never expire. If both
- parameters are zero, this QDeadlineTimer will be marked as expired.
+ secs is negative, this QDeadlineTimer will be set it to never expire (this
+ behavior does not apply to \a nsecs). If both parameters are zero, this
+ QDeadlineTimer will be marked as expired.
+
+ For optimization purposes, if both \a secs and \a nsecs are zero, this
+ function may skip obtaining the current time and may instead use a value
+ known to be in the past. If that happens, deadline() may return an
+ unexpected value and this object cannot be used in calculation of how long
+ it is overdue. If that functionality is required, use
+ QDeadlineTimer::current() and add time to it.
The timer type for this QDeadlineTimer object will be set to the specified
\a timerType.
+ \note Prior to Qt 6.6, the only condition that caused the timer to never
+ expire was when \a secs was -1.
+
\sa setRemainingTime(), hasExpired(), isForever(), remainingTime()
*/
void QDeadlineTimer::setPreciseRemainingTime(qint64 secs, qint64 nsecs, Qt::TimerType timerType) noexcept
{
- if (secs == -1) {
+ if (secs < 0) {
*this = QDeadlineTimer(Forever, timerType);
- return;
+ } else if (secs == 0 && nsecs == 0) {
+ *this = QDeadlineTimer(timerType);
+ t1 = std::numeric_limits<qint64>::min();
+ } else {
+ *this = current(timerType);
+ t1 = add_saturate(t1, seconds{secs}, nanoseconds{nsecs});
}
-
- *this = current(timerType);
- TimeReference ref(t1, t2);
- if (!ref.addSecsAndNSecs(secs, nsecs))
- ref.saturate(TimeReference::sign(secs, nsecs));
- ref.updateTimer(t1, t2);
}
/*!
@@ -588,6 +364,8 @@ bool QDeadlineTimer::hasExpired() const noexcept
{
if (isForever())
return false;
+ if (t1 == std::numeric_limits<qint64>::min())
+ return true;
return *this <= current(timerType());
}
@@ -636,19 +414,8 @@ qint64 QDeadlineTimer::remainingTime() const noexcept
if (isForever())
return -1;
- QDeadlineTimer now = current(timerType());
- TimeReference ref(t1, t2);
-
- qint64 msecs;
- if (!ref.subtract(now.t1, now.t2))
- return 0; // We can only underflow here
-
- // If we fail the conversion, t1 < now.t1 means we underflowed,
- // thus the deadline had long expired
- if (!ref.toMilliseconds(&msecs, TimeReference::RoundUp))
- return t1 < now.t1 ? 0 : -1;
-
- return msecs < 0 ? 0 : msecs;
+ nanoseconds nsecs(remainingTimeNSecs());
+ return ceil<milliseconds>(nsecs).count();
}
/*!
@@ -670,23 +437,19 @@ qint64 QDeadlineTimer::remainingTimeNSecs() const noexcept
/*!
\internal
Same as remainingTimeNSecs, but may return negative remaining times. Does
- not deal with Forever. In case of underflow the result is saturated to
- the minimum possible value, on overflow - the maximum possible value.
+ not deal with Forever. In case of underflow, which is only possible if the
+ timer has expired, an arbitrary negative value is returned.
*/
qint64 QDeadlineTimer::rawRemainingTimeNSecs() const noexcept
{
- QDeadlineTimer now = current(timerType());
- TimeReference ref(t1, t2);
+ if (t1 == std::numeric_limits<qint64>::min())
+ return t1; // we'd saturate to this anyway
- qint64 nsecs;
- if (!ref.subtract(now.t1, now.t2))
- return TimeReference::Min; // We can only underflow here
-
- // If we fail the conversion, t1 < now.t1 means we underflowed,
- // thus the deadline had long expired
- if (!ref.toNanoseconds(&nsecs))
- return t1 < now.t1 ? TimeReference::Min : TimeReference::Max;
- return nsecs;
+ QDeadlineTimer now = current(timerType());
+ qint64 r;
+ if (qSubOverflow(t1, now.t1, &r))
+ return -1; // any negative number is fine
+ return r;
}
/*!
@@ -713,12 +476,11 @@ qint64 QDeadlineTimer::deadline() const noexcept
{
if (isForever())
return TimeReference::Max;
+ if (t1 == TimeReference::Min)
+ return t1;
- qint64 result;
- if (!TimeReference(t1, t2).toMilliseconds(&result))
- return t1 < 0 ? TimeReference::Min : TimeReference::Max;
-
- return result;
+ nanoseconds ns(t1);
+ return duration_cast<milliseconds>(ns).count();
}
/*!
@@ -747,11 +509,7 @@ qint64 QDeadlineTimer::deadlineNSecs() const noexcept
if (isForever())
return TimeReference::Max;
- qint64 result;
- if (!TimeReference(t1, t2).toNanoseconds(&result))
- return t1 < 0 ? TimeReference::Min : TimeReference::Max;
-
- return result;
+ return t1;
}
/*!
@@ -775,11 +533,7 @@ void QDeadlineTimer::setDeadline(qint64 msecs, Qt::TimerType timerType) noexcept
}
type = timerType;
-
- TimeReference ref;
- if (!ref.addMilliseconds(msecs))
- ref.saturate(msecs > 0);
- ref.updateTimer(t1, t2);
+ t1 = add_saturate(0, milliseconds{msecs});
}
/*!
@@ -797,13 +551,7 @@ void QDeadlineTimer::setDeadline(qint64 msecs, Qt::TimerType timerType) noexcept
void QDeadlineTimer::setPreciseDeadline(qint64 secs, qint64 nsecs, Qt::TimerType timerType) noexcept
{
type = timerType;
-
- // We don't pass the seconds to the constructor, because we don't know
- // at this point if t1 holds the seconds or nanoseconds; it's platform specific.
- TimeReference ref;
- if (!ref.addSecsAndNSecs(secs, nsecs))
- ref.saturate(TimeReference::sign(secs, nsecs));
- ref.updateTimer(t1, t2);
+ t1 = add_saturate(0, seconds{secs}, nanoseconds{nsecs});
}
/*!
@@ -819,11 +567,7 @@ QDeadlineTimer QDeadlineTimer::addNSecs(QDeadlineTimer dt, qint64 nsecs) noexcep
if (dt.isForever())
return dt;
- TimeReference ref(dt.t1, dt.t2);
- if (!ref.addNanoseconds(nsecs))
- ref.saturate(nsecs > 0);
- ref.updateTimer(dt.t1, dt.t2);
-
+ dt.t1 = add_saturate(dt.t1, nanoseconds{nsecs});
return dt;
}
@@ -836,11 +580,22 @@ QDeadlineTimer QDeadlineTimer::addNSecs(QDeadlineTimer dt, qint64 nsecs) noexcep
The QDeadlineTimer object will be constructed with the specified \a timerType.
*/
+QDeadlineTimer QDeadlineTimer::current(Qt::TimerType timerType) noexcept
+{
+ // ensure we get nanoseconds; this will work so long as steady_clock's
+ // time_point isn't of finer resolution (picoseconds)
+ std::chrono::nanoseconds ns = std::chrono::steady_clock::now().time_since_epoch();
+
+ QDeadlineTimer result;
+ result.t1 = ns.count();
+ result.type = timerType;
+ return result;
+}
/*!
- \fn bool QDeadlineTimer::operator==(QDeadlineTimer d1, QDeadlineTimer d2)
+ \fn bool QDeadlineTimer::operator==(const QDeadlineTimer &lhs, const QDeadlineTimer &rhs)
- Returns true if the deadline on \a d1 and the deadline in \a d2 are the
+ Returns true if the deadline on \a lhs and the deadline in \a rhs are the
same, false otherwise. The timer type used to create the two deadlines is
ignored. This function is equivalent to:
@@ -851,9 +606,9 @@ QDeadlineTimer QDeadlineTimer::addNSecs(QDeadlineTimer dt, qint64 nsecs) noexcep
*/
/*!
- \fn bool QDeadlineTimer::operator!=(QDeadlineTimer d1, QDeadlineTimer d2)
+ \fn bool QDeadlineTimer::operator!=(const QDeadlineTimer &lhs, const QDeadlineTimer &rhs)
- Returns true if the deadline on \a d1 and the deadline in \a d2 are
+ Returns true if the deadline on \a lhs and the deadline in \a rhs are
different, false otherwise. The timer type used to create the two deadlines
is ignored. This function is equivalent to:
@@ -864,10 +619,10 @@ QDeadlineTimer QDeadlineTimer::addNSecs(QDeadlineTimer dt, qint64 nsecs) noexcep
*/
/*!
- \fn bool QDeadlineTimer::operator<(QDeadlineTimer d1, QDeadlineTimer d2)
+ \fn bool QDeadlineTimer::operator<(const QDeadlineTimer &lhs, const QDeadlineTimer &rhs)
- Returns true if the deadline on \a d1 is earlier than the deadline in \a
- d2, false otherwise. The timer type used to create the two deadlines is
+ Returns true if the deadline on \a lhs is earlier than the deadline in \a
+ rhs, false otherwise. The timer type used to create the two deadlines is
ignored. This function is equivalent to:
\snippet code/src_corelib_kernel_qdeadlinetimer.cpp 10
@@ -877,10 +632,10 @@ QDeadlineTimer QDeadlineTimer::addNSecs(QDeadlineTimer dt, qint64 nsecs) noexcep
*/
/*!
- \fn bool QDeadlineTimer::operator<=(QDeadlineTimer d1, QDeadlineTimer d2)
+ \fn bool QDeadlineTimer::operator<=(const QDeadlineTimer &lhs, const QDeadlineTimer &rhs)
- Returns true if the deadline on \a d1 is earlier than or the same as the
- deadline in \a d2, false otherwise. The timer type used to create the two
+ Returns true if the deadline on \a lhs is earlier than or the same as the
+ deadline in \a rhs, false otherwise. The timer type used to create the two
deadlines is ignored. This function is equivalent to:
\snippet code/src_corelib_kernel_qdeadlinetimer.cpp 11
@@ -890,10 +645,10 @@ QDeadlineTimer QDeadlineTimer::addNSecs(QDeadlineTimer dt, qint64 nsecs) noexcep
*/
/*!
- \fn bool QDeadlineTimer::operator>(QDeadlineTimer d1, QDeadlineTimer d2)
+ \fn bool QDeadlineTimer::operator>(const QDeadlineTimer &lhs, const QDeadlineTimer &rhs)
- Returns true if the deadline on \a d1 is later than the deadline in \a
- d2, false otherwise. The timer type used to create the two deadlines is
+ Returns true if the deadline on \a lhs is later than the deadline in \a
+ rhs, false otherwise. The timer type used to create the two deadlines is
ignored. This function is equivalent to:
\snippet code/src_corelib_kernel_qdeadlinetimer.cpp 12
@@ -903,10 +658,10 @@ QDeadlineTimer QDeadlineTimer::addNSecs(QDeadlineTimer dt, qint64 nsecs) noexcep
*/
/*!
- \fn bool QDeadlineTimer::operator>=(QDeadlineTimer d1, QDeadlineTimer d2)
+ \fn bool QDeadlineTimer::operator>=(const QDeadlineTimer &lhs, const QDeadlineTimer &rhs)
- Returns true if the deadline on \a d1 is later than or the same as the
- deadline in \a d2, false otherwise. The timer type used to create the two
+ Returns true if the deadline on \a lhs is later than or the same as the
+ deadline in \a rhs, false otherwise. The timer type used to create the two
deadlines is ignored. This function is equivalent to:
\snippet code/src_corelib_kernel_qdeadlinetimer.cpp 13
@@ -930,11 +685,7 @@ QDeadlineTimer operator+(QDeadlineTimer dt, qint64 msecs)
if (dt.isForever())
return dt;
- TimeReference ref(dt.t1, dt.t2);
- if (!ref.addMilliseconds(msecs))
- ref.saturate(msecs > 0);
- ref.updateTimer(dt.t1, dt.t2);
-
+ dt.t1 = add_saturate(dt.t1, milliseconds{msecs});
return dt;
}
@@ -1000,11 +751,4 @@ QDeadlineTimer operator+(QDeadlineTimer dt, qint64 msecs)
Returns the time remaining before the deadline.
*/
-/*!
- \fn QPair<qint64, unsigned> QDeadlineTimer::_q_data() const
- \internal
-*/
-
-// 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 253e98de90..515cdb5387 100644
--- a/src/corelib/kernel/qdeadlinetimer.h
+++ b/src/corelib/kernel/qdeadlinetimer.h
@@ -7,7 +7,6 @@
#include <QtCore/qelapsedtimer.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qnamespace.h>
-#include <QtCore/qpair.h>
#ifdef max
// un-pollute the namespace. We need std::numeric_limits::max() and std::chrono::duration::max()
@@ -23,16 +22,18 @@ QT_BEGIN_NAMESPACE
class Q_CORE_EXPORT QDeadlineTimer
{
public:
- enum ForeverConstant { Forever };
+ enum class ForeverConstant { Forever };
+ static constexpr ForeverConstant Forever = ForeverConstant::Forever;
- constexpr QDeadlineTimer(Qt::TimerType type_ = Qt::CoarseTimer) noexcept
+ constexpr QDeadlineTimer() noexcept = default;
+ constexpr explicit QDeadlineTimer(Qt::TimerType type_) noexcept
: type(type_) {}
constexpr QDeadlineTimer(ForeverConstant, Qt::TimerType type_ = Qt::CoarseTimer) noexcept
: t1((std::numeric_limits<qint64>::max)()), type(type_) {}
explicit QDeadlineTimer(qint64 msecs, Qt::TimerType type = Qt::CoarseTimer) noexcept;
void swap(QDeadlineTimer &other) noexcept
- { std::swap(t1, other.t1); std::swap(t2, other.t2); std::swap(type, other.type); }
+ { std::swap(t1, other.t1); std::swap(type, other.type); }
constexpr bool isForever() const noexcept
{ return t1 == (std::numeric_limits<qint64>::max)(); }
@@ -57,19 +58,6 @@ public:
static QDeadlineTimer addNSecs(QDeadlineTimer dt, qint64 nsecs) noexcept Q_DECL_PURE_FUNCTION;
static QDeadlineTimer current(Qt::TimerType timerType = Qt::CoarseTimer) noexcept;
- friend bool operator==(QDeadlineTimer d1, QDeadlineTimer d2) noexcept
- { return d1.t1 == d2.t1 && d1.t2 == d2.t2; }
- friend bool operator!=(QDeadlineTimer d1, QDeadlineTimer d2) noexcept
- { return !(d1 == d2); }
- friend bool operator<(QDeadlineTimer d1, QDeadlineTimer d2) noexcept
- { return d1.t1 < d2.t1 || (d1.t1 == d2.t1 && d1.t2 < d2.t2); }
- friend bool operator<=(QDeadlineTimer d1, QDeadlineTimer d2) noexcept
- { return d1 == d2 || d1 < d2; }
- friend bool operator>(QDeadlineTimer d1, QDeadlineTimer d2) noexcept
- { return d2 < d1; }
- friend bool operator>=(QDeadlineTimer d1, QDeadlineTimer d2) noexcept
- { return !(d1 < d2); }
-
friend Q_CORE_EXPORT QDeadlineTimer operator+(QDeadlineTimer dt, qint64 msecs);
friend QDeadlineTimer operator+(qint64 msecs, QDeadlineTimer dt)
{ return dt + msecs; }
@@ -91,16 +79,11 @@ public:
{ setDeadline(deadline_); return *this; }
template <class Clock, class Duration = typename Clock::duration>
- void setDeadline(std::chrono::time_point<Clock, Duration> deadline_,
- Qt::TimerType type_ = Qt::CoarseTimer)
- { setRemainingTime(deadline_ == deadline_.max() ? Duration::max() : deadline_ - Clock::now(), type_); }
+ void setDeadline(std::chrono::time_point<Clock, Duration> tp,
+ Qt::TimerType type_ = Qt::CoarseTimer);
template <class Clock, class Duration = typename Clock::duration>
- std::chrono::time_point<Clock, Duration> deadline() const
- {
- auto val = std::chrono::nanoseconds(rawRemainingTimeNSecs()) + Clock::now();
- return std::chrono::time_point_cast<Duration>(val);
- }
+ std::chrono::time_point<Clock, Duration> deadline() const;
template <class Rep, class Period>
QDeadlineTimer(std::chrono::duration<Rep, Period> remaining, Qt::TimerType type_ = Qt::CoarseTimer)
@@ -114,10 +97,11 @@ public:
template <class Rep, class Period>
void setRemainingTime(std::chrono::duration<Rep, Period> remaining, Qt::TimerType type_ = Qt::CoarseTimer)
{
+ using namespace std::chrono;
if (remaining == remaining.max())
*this = QDeadlineTimer(Forever, type_);
else
- setPreciseRemainingTime(0, std::chrono::nanoseconds(remaining).count(), type_);
+ setPreciseRemainingTime(0, ceil<nanoseconds>(remaining).count(), type_);
}
std::chrono::nanoseconds remainingTimeAsDuration() const noexcept
@@ -141,44 +125,55 @@ public:
{ return dt = dt + value; }
private:
+ friend bool comparesEqual(const QDeadlineTimer &lhs,
+ const QDeadlineTimer &rhs) noexcept
+ {
+ return lhs.t1 == rhs.t1;
+ }
+ friend Qt::strong_ordering compareThreeWay(const QDeadlineTimer &lhs,
+ const QDeadlineTimer &rhs) noexcept
+ {
+ return Qt::compareThreeWay(lhs.t1, rhs.t1);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QDeadlineTimer)
+
qint64 t1 = 0;
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
unsigned t2 = 0;
- unsigned type;
+#endif
+ unsigned type = Qt::CoarseTimer;
qint64 rawRemainingTimeNSecs() const noexcept;
-
-public:
- // This is not a public function, it's here only for Qt's internal convenience...
- QPair<qint64, unsigned> _q_data() const { return qMakePair(t1, t2); }
};
-#if defined(Q_OS_DARWIN) || defined(Q_OS_LINUX) || (defined(Q_CC_MSVC) && Q_CC_MSVC >= 1900)
-// We know for these OS/compilers that the std::chrono::steady_clock uses the same
-// reference time as QDeadlineTimer
-
-template <> inline std::chrono::steady_clock::time_point
-QDeadlineTimer::deadline<std::chrono::steady_clock, std::chrono::steady_clock::duration>() const
+template<class Clock, class Duration>
+std::chrono::time_point<Clock, Duration> QDeadlineTimer::deadline() const
{
- return std::chrono::steady_clock::time_point(std::chrono::nanoseconds(deadlineNSecs()));
+ using namespace std::chrono;
+ if constexpr (std::is_same_v<Clock, steady_clock>) {
+ auto val = duration_cast<Duration>(nanoseconds(deadlineNSecs()));
+ return time_point<Clock, Duration>(val);
+ } else {
+ auto val = nanoseconds(rawRemainingTimeNSecs()) + Clock::now();
+ return time_point_cast<Duration>(val);
+ }
}
-template <> inline void
-QDeadlineTimer::setDeadline<std::chrono::steady_clock, std::chrono::steady_clock::duration>(std::chrono::steady_clock::time_point tp, Qt::TimerType type_)
+template<class Clock, class Duration>
+void QDeadlineTimer::setDeadline(std::chrono::time_point<Clock, Duration> tp, Qt::TimerType type_)
{
using namespace std::chrono;
if (tp == tp.max()) {
*this = Forever;
type = type_;
- } else if (type_ != Qt::PreciseTimer) {
- // if we aren't using PreciseTimer, then we need to convert
- setPreciseRemainingTime(0, duration_cast<nanoseconds>(tp - steady_clock::now()).count(), type_);
- } else {
+ } else if constexpr (std::is_same_v<Clock, steady_clock>) {
setPreciseDeadline(0,
duration_cast<nanoseconds>(tp.time_since_epoch()).count(),
type_);
+ } else {
+ setPreciseRemainingTime(0, duration_cast<nanoseconds>(tp - Clock::now()).count(), type_);
}
}
-#endif
Q_DECLARE_SHARED(QDeadlineTimer)
diff --git a/src/corelib/kernel/qdeadlinetimer_p.h b/src/corelib/kernel/qdeadlinetimer_p.h
deleted file mode 100644
index 41054435ba..0000000000
--- a/src/corelib/kernel/qdeadlinetimer_p.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QDEADLINETIMER_P_H
-#define QDEADLINETIMER_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/private/qglobal_p.h>
-
-QT_BEGIN_NAMESPACE
-
-enum {
-#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
- // t1 contains seconds and t2 contains nanoseconds
- QDeadlineTimerNanosecondsInT2 = 1
-#else
- // t1 contains nanoseconds, t2 is always zero
- QDeadlineTimerNanosecondsInT2 = 0
-#endif
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/corelib/kernel/qelapsedtimer.cpp b/src/corelib/kernel/qelapsedtimer.cpp
index 39ddb3491c..511b81a04e 100644
--- a/src/corelib/kernel/qelapsedtimer.cpp
+++ b/src/corelib/kernel/qelapsedtimer.cpp
@@ -75,7 +75,7 @@ QT_BEGIN_NAMESPACE
that the clock used is the same as QElapsedTimer (see
QElapsedTimer::clockType()).
- \sa QTime, QTimer, QDeadlineTimer
+ \sa QTime, QChronoTimer, QDeadlineTimer
*/
/*!
@@ -165,9 +165,229 @@ QT_BEGIN_NAMESPACE
function will return false.
*/
+/*!
+ \fn QElapsedTimer::clockType() noexcept
+
+ Returns the clock type that this QElapsedTimer implementation uses.
+
+ Since Qt 6.6, QElapsedTimer uses \c{std::chrono::steady_clock}, so the
+ clock type is always \l MonotonicClock.
+
+ \sa isMonotonic()
+*/
+
+QElapsedTimer::ClockType QElapsedTimer::clockType() noexcept
+{
+ // we use std::chrono::steady_clock
+ return MonotonicClock;
+}
+
+/*!
+ \fn QElapsedTimer::isMonotonic() noexcept
+
+ Returns \c true if this is a monotonic clock, false otherwise. See the
+ information on the different clock types to understand which ones are
+ monotonic.
+
+ Since Qt 6.6, QElapsedTimer uses \c{std::chrono::steady_clock}, so this
+ function now always returns true.
+
+ \sa clockType(), QElapsedTimer::ClockType
+*/
+bool QElapsedTimer::isMonotonic() noexcept
+{
+ // We trust std::chrono::steady_clock to be steady (monotonic); if the
+ // Standard Library is lying to us, users must complain to their vendor.
+ return true;
+}
+
+/*!
+ \typealias QElapsedTimer::Duration
+ Synonym for \c std::chrono::nanoseconds.
+*/
+
+/*!
+ \typealias QElapsedTimer::TimePoint
+ Synonym for \c {std::chrono::time_point<std::chrono::steady_clock, Duration>}.
+*/
+
+/*!
+ Starts this timer. Once started, a timer value can be checked with elapsed() or msecsSinceReference().
+
+ Normally, a timer is started just before a lengthy operation, such as:
+ \snippet qelapsedtimer/main.cpp 0
+
+ Also, starting a timer makes it valid again.
+
+ \sa restart(), invalidate(), elapsed()
+*/
+void QElapsedTimer::start() noexcept
+{
+ static_assert(sizeof(t1) == sizeof(Duration::rep));
+
+ // This assignment will work so long as TimePoint uses the same time
+ // duration or one of finer granularity than steady_clock::time_point. That
+ // means it will work until the first steady_clock using picoseconds.
+ TimePoint now = std::chrono::steady_clock::now();
+ t1 = now.time_since_epoch().count();
+ QT6_ONLY(t2 = 0);
+}
+
+/*!
+ Restarts the timer and returns the number of milliseconds elapsed since
+ the previous start.
+ This function is equivalent to obtaining the elapsed time with elapsed()
+ and then starting the timer again with start(), but it does so in one
+ single operation, avoiding the need to obtain the clock value twice.
+
+ Calling this function on a QElapsedTimer that is invalid
+ results in undefined behavior.
+
+ The following example illustrates how to use this function to calibrate a
+ parameter to a slow operation (for example, an iteration count) so that
+ this operation takes at least 250 milliseconds:
+
+ \snippet qelapsedtimer/main.cpp 3
+
+ \sa start(), invalidate(), elapsed(), isValid()
+*/
+qint64 QElapsedTimer::restart() noexcept
+{
+ QElapsedTimer old = *this;
+ start();
+ return old.msecsTo(*this);
+}
+
+/*!
+ \since 6.6
+
+ Returns a \c{std::chrono::nanoseconds} with the time since this QElapsedTimer was last
+ started.
+
+ Calling this function on a QElapsedTimer that is invalid
+ results in undefined behavior.
+
+ On platforms that do not provide nanosecond resolution, the value returned
+ will be the best estimate available.
+
+ \sa start(), restart(), hasExpired(), invalidate()
+*/
+auto QElapsedTimer::durationElapsed() const noexcept -> Duration
+{
+ TimePoint then{Duration(t1)};
+ return std::chrono::steady_clock::now() - then;
+}
+
+/*!
+ \since 4.8
+
+ Returns the number of nanoseconds since this QElapsedTimer was last
+ started.
+
+ Calling this function on a QElapsedTimer that is invalid
+ results in undefined behavior.
+
+ On platforms that do not provide nanosecond resolution, the value returned
+ will be the best estimate available.
+
+ \sa start(), restart(), hasExpired(), invalidate()
+*/
+qint64 QElapsedTimer::nsecsElapsed() const noexcept
+{
+ return durationElapsed().count();
+}
+
+/*!
+ Returns the number of milliseconds since this QElapsedTimer was last
+ started.
+
+ Calling this function on a QElapsedTimer that is invalid
+ results in undefined behavior.
+
+ \sa start(), restart(), hasExpired(), isValid(), invalidate()
+*/
+qint64 QElapsedTimer::elapsed() const noexcept
+{
+ using namespace std::chrono;
+ return duration_cast<milliseconds>(durationElapsed()).count();
+}
+
+/*!
+ Returns the number of milliseconds between last time this QElapsedTimer
+ object was started and its reference clock's start.
+
+ This number is usually arbitrary for all clocks except the
+ QElapsedTimer::SystemTime clock. For that clock type, this number is the
+ number of milliseconds since January 1st, 1970 at 0:00 UTC (that is, it
+ is the Unix time expressed in milliseconds).
+
+ On Linux, Windows and Apple platforms, this value is usually the time
+ since the system boot, though it usually does not include the time the
+ system has spent in sleep states.
+
+ \sa clockType(), elapsed()
+*/
+qint64 QElapsedTimer::msecsSinceReference() const noexcept
+{
+ using namespace std::chrono;
+ return duration_cast<milliseconds>(Duration(t1)).count();
+}
+
+/*!
+ \since 6.6
+
+ Returns the time difference between this QElapsedTimer and \a other as a
+ \c{std::chrono::nanoseconds}. If \a other was started before this object,
+ the returned value will be negative. If it was started later, the returned
+ value will be positive.
+
+ The return value is undefined if this object or \a other were invalidated.
+
+ \sa secsTo(), elapsed()
+*/
+auto QElapsedTimer::durationTo(const QElapsedTimer &other) const noexcept -> Duration
+{
+ Duration d1(t1);
+ Duration d2(other.t1);
+ return d2 - d1;
+}
+
+/*!
+ Returns the number of milliseconds between this QElapsedTimer and \a
+ other. If \a other was started before this object, the returned value
+ will be negative. If it was started later, the returned value will be
+ positive.
+
+ The return value is undefined if this object or \a other were invalidated.
+
+ \sa secsTo(), elapsed()
+*/
+qint64 QElapsedTimer::msecsTo(const QElapsedTimer &other) const noexcept
+{
+ using namespace std::chrono;
+ return duration_cast<milliseconds>(durationTo(other)).count();
+}
+
+/*!
+ Returns the number of seconds between this QElapsedTimer and \a other. If
+ \a other was started before this object, the returned value will be
+ negative. If it was started later, the returned value will be positive.
+
+ Calling this function on or with a QElapsedTimer that is invalid
+ results in undefined behavior.
+
+ \sa msecsTo(), elapsed()
+*/
+qint64 QElapsedTimer::secsTo(const QElapsedTimer &other) const noexcept
+{
+ using namespace std::chrono;
+ return duration_cast<seconds>(durationTo(other)).count();
+}
+
static const qint64 invalidData = Q_INT64_C(0x8000000000000000);
/*!
+ \fn QElapsedTimer::invalidate() noexcept
Marks this QElapsedTimer object as invalid.
An invalid object can be checked with isValid(). Calculations of timer
@@ -193,10 +413,12 @@ bool QElapsedTimer::isValid() const noexcept
}
/*!
- Returns \c true if this QElapsedTimer has already expired by \a timeout
- milliseconds (that is, more than \a timeout milliseconds have elapsed).
- The value of \a timeout can be -1 to indicate that this timer does not
- expire, in which case this function will always return false.
+ Returns \c true if elapsed() exceeds the given \a timeout, otherwise \c false.
+
+ A negative \a timeout is interpreted as infinite, so \c false is returned in
+ this case. Otherwise, this is equivalent to \c {elapsed() > timeout}. You
+ can do the same for a duration by comparing durationElapsed() to a duration
+ timeout.
\sa elapsed(), QDeadlineTimer
*/
@@ -207,4 +429,9 @@ bool QElapsedTimer::hasExpired(qint64 timeout) const noexcept
return quint64(elapsed()) > quint64(timeout);
}
+bool operator<(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept
+{
+ return lhs.t1 < rhs.t1;
+}
+
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qelapsedtimer.h b/src/corelib/kernel/qelapsedtimer.h
index ab32265cba..7d8b889f61 100644
--- a/src/corelib/kernel/qelapsedtimer.h
+++ b/src/corelib/kernel/qelapsedtimer.h
@@ -6,8 +6,9 @@
#include <QtCore/qglobal.h>
-QT_BEGIN_NAMESPACE
+#include <chrono>
+QT_BEGIN_NAMESPACE
class Q_CORE_EXPORT QElapsedTimer
{
@@ -21,6 +22,10 @@ public:
PerformanceCounter
};
+ // similar to std::chrono::*_clock
+ using Duration = std::chrono::nanoseconds;
+ using TimePoint = std::chrono::time_point<std::chrono::steady_clock, Duration>;
+
constexpr QElapsedTimer() = default;
static ClockType clockType() noexcept;
@@ -31,11 +36,13 @@ public:
void invalidate() noexcept;
bool isValid() const noexcept;
+ Duration durationElapsed() const noexcept;
qint64 nsecsElapsed() const noexcept;
qint64 elapsed() const noexcept;
bool hasExpired(qint64 timeout) const noexcept;
qint64 msecsSinceReference() const noexcept;
+ Duration durationTo(const QElapsedTimer &other) const noexcept;
qint64 msecsTo(const QElapsedTimer &other) const noexcept;
qint64 secsTo(const QElapsedTimer &other) const noexcept;
diff --git a/src/corelib/kernel/qelapsedtimer_generic.cpp b/src/corelib/kernel/qelapsedtimer_generic.cpp
deleted file mode 100644
index 874122f493..0000000000
--- a/src/corelib/kernel/qelapsedtimer_generic.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include "qelapsedtimer.h"
-#include "qdeadlinetimer.h"
-#include "qdatetime.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- Returns the clock type that this QElapsedTimer implementation uses.
-
- \sa isMonotonic()
-*/
-QElapsedTimer::ClockType QElapsedTimer::clockType() noexcept
-{
- return SystemTime;
-}
-
-/*!
- Returns \c true if this is a monotonic clock, false otherwise. See the
- information on the different clock types to understand which ones are
- monotonic.
-
- \sa clockType(), QElapsedTimer::ClockType
-*/
-bool QElapsedTimer::isMonotonic() noexcept
-{
- return false;
-}
-
-/*!
- Starts this timer. Once started, a timer value can be checked with elapsed() or msecsSinceReference().
-
- Normally, a timer is started just before a lengthy operation, such as:
- \snippet qelapsedtimer/main.cpp 0
-
- Also, starting a timer makes it valid again.
-
- \sa restart(), invalidate(), elapsed()
-*/
-void QElapsedTimer::start() noexcept
-{
- restart();
-}
-
-/*!
- Restarts the timer and returns the number of milliseconds elapsed since
- the previous start.
- This function is equivalent to obtaining the elapsed time with elapsed()
- and then starting the timer again with start(), but it does so in one
- single operation, avoiding the need to obtain the clock value twice.
-
- Calling this function on a QElapsedTimer that is invalid
- results in undefined behavior.
-
- The following example illustrates how to use this function to calibrate a
- parameter to a slow operation (for example, an iteration count) so that
- this operation takes at least 250 milliseconds:
-
- \snippet qelapsedtimer/main.cpp 3
-
- \sa start(), invalidate(), elapsed(), isValid()
-*/
-qint64 QElapsedTimer::restart() noexcept
-{
- qint64 old = t1;
- t1 = QDateTime::currentMSecsSinceEpoch();
- t2 = 0;
- return t1 - old;
-}
-
-/*! \since 4.8
-
- Returns the number of nanoseconds since this QElapsedTimer was last
- started.
-
- Calling this function on a QElapsedTimer that is invalid
- results in undefined behavior.
-
- On platforms that do not provide nanosecond resolution, the value returned
- will be the best estimate available.
-
- \sa start(), restart(), hasExpired(), invalidate()
-*/
-qint64 QElapsedTimer::nsecsElapsed() const noexcept
-{
- return elapsed() * 1000000;
-}
-
-/*!
- Returns the number of milliseconds since this QElapsedTimer was last
- started.
-
- Calling this function on a QElapsedTimer that is invalid
- results in undefined behavior.
-
- \sa start(), restart(), hasExpired(), isValid(), invalidate()
-*/
-qint64 QElapsedTimer::elapsed() const noexcept
-{
- return QDateTime::currentMSecsSinceEpoch() - t1;
-}
-
-/*!
- Returns the number of milliseconds between last time this QElapsedTimer
- object was started and its reference clock's start.
-
- This number is usually arbitrary for all clocks except the
- QElapsedTimer::SystemTime clock. For that clock type, this number is the
- number of milliseconds since January 1st, 1970 at 0:00 UTC (that is, it
- is the Unix time expressed in milliseconds).
-
- On Linux, Windows and Apple platforms, this value is usually the time
- since the system boot, though it usually does not include the time the
- system has spent in sleep states.
-
- \sa clockType(), elapsed()
-*/
-qint64 QElapsedTimer::msecsSinceReference() const noexcept
-{
- return t1;
-}
-
-/*!
- Returns the number of milliseconds between this QElapsedTimer and \a
- other. If \a other was started before this object, the returned value
- will be negative. If it was started later, the returned value will be
- positive.
-
- The return value is undefined if this object or \a other were invalidated.
-
- \sa secsTo(), elapsed()
-*/
-qint64 QElapsedTimer::msecsTo(const QElapsedTimer &other) const noexcept
-{
- qint64 diff = other.t1 - t1;
- return diff;
-}
-
-/*!
- Returns the number of seconds between this QElapsedTimer and \a other. If
- \a other was started before this object, the returned value will be
- negative. If it was started later, the returned value will be positive.
-
- Calling this function on or with a QElapsedTimer that is invalid
- results in undefined behavior.
-
- \sa msecsTo(), elapsed()
-*/
-qint64 QElapsedTimer::secsTo(const QElapsedTimer &other) const noexcept
-{
- return msecsTo(other) / 1000;
-}
-
-bool operator<(const QElapsedTimer &lhs, const QElapsedTimer &rhs) noexcept
-{
- return lhs.t1 < rhs.t1;
-}
-
-QDeadlineTimer QDeadlineTimer::current(Qt::TimerType timerType) noexcept
-{
- QDeadlineTimer result;
- result.t1 = QDateTime::currentMSecsSinceEpoch() * 1000 * 1000;
- result.type = timerType;
- return result;
-}
-
-QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qelapsedtimer_mac.cpp b/src/corelib/kernel/qelapsedtimer_mac.cpp
deleted file mode 100644
index bc87202d65..0000000000
--- a/src/corelib/kernel/qelapsedtimer_mac.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-// ask for the latest POSIX, just in case
-#define _POSIX_C_SOURCE 200809L
-
-#include "qelapsedtimer.h"
-#include "qdeadlinetimer.h"
-#include "qdeadlinetimer_p.h"
-#include <sys/time.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <mach/mach_time.h>
-#include <private/qcore_unix_p.h>
-
-QT_BEGIN_NAMESPACE
-
-#ifdef __LP64__
-typedef __int128_t LargeInt;
-#else
-typedef qint64 LargeInt;
-#endif
-
-QElapsedTimer::ClockType QElapsedTimer::clockType() noexcept
-{
- return MachAbsoluteTime;
-}
-
-bool QElapsedTimer::isMonotonic() noexcept
-{
- return true;
-}
-
-static mach_timebase_info_data_t info = { 0, 0 };
-static qint64 absoluteToNSecs(qint64 cpuTime)
-{
- if (info.denom == 0)
- mach_timebase_info(&info);
-
- // don't do multiplication & division if those are equal
- // (mathematically it would be the same, but it's computationally expensive)
- if (info.numer == info.denom)
- return cpuTime;
- qint64 nsecs = LargeInt(cpuTime) * info.numer / info.denom;
- return nsecs;
-}
-
-static qint64 absoluteToMSecs(qint64 cpuTime)
-{
- return absoluteToNSecs(cpuTime) / 1000000;
-}
-
-timespec qt_gettime() noexcept
-{
- timespec tv;
-
- uint64_t cpu_time = mach_absolute_time();
- uint64_t nsecs = absoluteToNSecs(cpu_time);
- tv.tv_sec = nsecs / 1000000000ull;
- tv.tv_nsec = nsecs - (tv.tv_sec * 1000000000ull);
- return tv;
-}
-
-void qt_nanosleep(timespec amount)
-{
- // Mac doesn't have clock_nanosleep, but it does have nanosleep.
- // nanosleep is POSIX.1-1993
-
- int r;
- EINTR_LOOP(r, nanosleep(&amount, &amount));
-}
-
-void QElapsedTimer::start() noexcept
-{
- t1 = mach_absolute_time();
- t2 = 0;
-}
-
-qint64 QElapsedTimer::restart() noexcept
-{
- qint64 old = t1;
- t1 = mach_absolute_time();
- t2 = 0;
-
- return absoluteToMSecs(t1 - old);
-}
-
-qint64 QElapsedTimer::nsecsElapsed() const noexcept
-{
- uint64_t cpu_time = mach_absolute_time();
- return absoluteToNSecs(cpu_time - t1);
-}
-
-qint64 QElapsedTimer::elapsed() const noexcept
-{
- uint64_t cpu_time = mach_absolute_time();
- return absoluteToMSecs(cpu_time - t1);
-}
-
-qint64 QElapsedTimer::msecsSinceReference() const noexcept
-{
- return absoluteToMSecs(t1);
-}
-
-qint64 QElapsedTimer::msecsTo(const QElapsedTimer &other) const noexcept
-{
- return absoluteToMSecs(other.t1 - t1);
-}
-
-qint64 QElapsedTimer::secsTo(const QElapsedTimer &other) const noexcept
-{
- return msecsTo(other) / 1000;
-}
-
-bool operator<(const QElapsedTimer &v1, const QElapsedTimer &v2) noexcept
-{
- return v1.t1 < v2.t1;
-}
-
-QDeadlineTimer QDeadlineTimer::current(Qt::TimerType timerType) noexcept
-{
- static_assert(!QDeadlineTimerNanosecondsInT2);
- QDeadlineTimer result;
- result.type = timerType;
- result.t1 = absoluteToNSecs(mach_absolute_time());
- return result;
-}
-
-QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qelapsedtimer_unix.cpp b/src/corelib/kernel/qelapsedtimer_unix.cpp
deleted file mode 100644
index f11ebc00a4..0000000000
--- a/src/corelib/kernel/qelapsedtimer_unix.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// Copyright (C) 2016 Intel Corporation.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include "qelapsedtimer.h"
-#include "qdeadlinetimer.h"
-#include "qdeadlinetimer_p.h"
-#if defined(Q_OS_VXWORKS)
-#include "qfunctions_vxworks.h"
-#else
-#include <sys/time.h>
-#include <time.h>
-#endif
-#include <unistd.h>
-
-#include <qatomic.h>
-#include "private/qcore_unix_p.h"
-
-#if defined(QT_NO_CLOCK_MONOTONIC) || defined(QT_BOOTSTRAPPED)
-// turn off the monotonic clock
-# ifdef _POSIX_MONOTONIC_CLOCK
-# undef _POSIX_MONOTONIC_CLOCK
-# endif
-# define _POSIX_MONOTONIC_CLOCK -1
-#endif
-
-QT_BEGIN_NAMESPACE
-
-/*
- * Design:
- *
- * POSIX offers a facility to select the system's monotonic clock when getting
- * the current timestamp. Whereas the functions are mandatory in POSIX.1-2008,
- * the presence of a monotonic clock is a POSIX Option (see the document
- * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap02.html#tag_02_01_06 )
- *
- * The macro _POSIX_MONOTONIC_CLOCK can therefore assume the following values:
- * -1 monotonic clock is never supported on this system
- * 0 monotonic clock might be supported, runtime check is needed
- * >1 (such as 200809L) monotonic clock is always supported
- *
- * The unixCheckClockType() function will return the clock to use: either
- * CLOCK_MONOTONIC or CLOCK_REALTIME. In the case the POSIX option has a value
- * of zero, then this function stores a static that contains the clock to be
- * used.
- *
- * There's one extra case, which is when CLOCK_REALTIME isn't defined. When
- * that's the case, we'll emulate the clock_gettime function with gettimeofday.
- *
- * Conforming to:
- * POSIX.1b-1993 section "Clocks and Timers"
- * included in UNIX98 (Single Unix Specification v2)
- * included in POSIX.1-2001
- * see http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html
- */
-
-#if !defined(CLOCK_REALTIME)
-# define CLOCK_REALTIME 0
-static inline void qt_clock_gettime(int, struct timespec *ts)
-{
- // support clock_gettime with gettimeofday
- struct timeval tv;
- gettimeofday(&tv, 0);
- ts->tv_sec = tv.tv_sec;
- ts->tv_nsec = tv.tv_usec * 1000;
-}
-
-static inline int regularClock()
-{
- return 0;
-}
-#else
-static inline void qt_clock_gettime(clockid_t clock, struct timespec *ts)
-{
- clock_gettime(clock, ts);
-}
-
-static inline clock_t regularClockCheck()
-{
- struct timespec regular_clock_resolution;
- int r = -1;
-
-# ifdef CLOCK_MONOTONIC
- // try the monotonic clock
- r = clock_getres(CLOCK_MONOTONIC, &regular_clock_resolution);
-
-# ifdef Q_OS_LINUX
- // Despite glibc claiming that we should check at runtime, the Linux kernel
- // always supports the monotonic clock
- Q_ASSERT(r == 0);
- return CLOCK_MONOTONIC;
-# endif
-
- if (r == 0)
- return CLOCK_MONOTONIC;
-# endif
-
- // no monotonic, try the realtime clock
- r = clock_getres(CLOCK_REALTIME, &regular_clock_resolution);
- Q_ASSERT(r == 0);
- return CLOCK_REALTIME;
-}
-
-static inline clock_t regularClock()
-{
- static const clock_t clock = regularClockCheck();
- return clock;
-}
-#endif
-
-bool QElapsedTimer::isMonotonic() noexcept
-{
- return clockType() == MonotonicClock;
-}
-
-QElapsedTimer::ClockType QElapsedTimer::clockType() noexcept
-{
- return regularClock() == CLOCK_REALTIME ? SystemTime : MonotonicClock;
-}
-
-static inline void do_gettime(qint64 *sec, qint64 *frac)
-{
- timespec ts;
- qt_clock_gettime(regularClock(), &ts);
- *sec = ts.tv_sec;
- *frac = ts.tv_nsec;
-}
-
-// used in qcore_unix.cpp and qeventdispatcher_unix.cpp
-struct timespec qt_gettime() noexcept
-{
- qint64 sec, frac;
- do_gettime(&sec, &frac);
-
- timespec tv;
- tv.tv_sec = sec;
- tv.tv_nsec = frac;
-
- return tv;
-}
-
-static qint64 elapsedAndRestart(qint64 sec, qint64 frac,
- qint64 *nowsec, qint64 *nowfrac)
-{
- do_gettime(nowsec, nowfrac);
- sec = *nowsec - sec;
- frac = *nowfrac - frac;
- return (sec * Q_INT64_C(1000000000) + frac) / Q_INT64_C(1000000);
-}
-
-void QElapsedTimer::start() noexcept
-{
- do_gettime(&t1, &t2);
-}
-
-qint64 QElapsedTimer::restart() noexcept
-{
- return elapsedAndRestart(t1, t2, &t1, &t2);
-}
-
-qint64 QElapsedTimer::nsecsElapsed() const noexcept
-{
- qint64 sec, frac;
- do_gettime(&sec, &frac);
- sec = sec - t1;
- frac = frac - t2;
- return sec * Q_INT64_C(1000000000) + frac;
-}
-
-qint64 QElapsedTimer::elapsed() const noexcept
-{
- return nsecsElapsed() / Q_INT64_C(1000000);
-}
-
-qint64 QElapsedTimer::msecsSinceReference() const noexcept
-{
- return t1 * Q_INT64_C(1000) + t2 / Q_INT64_C(1000000);
-}
-
-qint64 QElapsedTimer::msecsTo(const QElapsedTimer &other) const noexcept
-{
- qint64 secs = other.t1 - t1;
- qint64 fraction = other.t2 - t2;
- return (secs * Q_INT64_C(1000000000) + fraction) / Q_INT64_C(1000000);
-}
-
-qint64 QElapsedTimer::secsTo(const QElapsedTimer &other) const noexcept
-{
- return other.t1 - t1;
-}
-
-bool operator<(const QElapsedTimer &v1, const QElapsedTimer &v2) noexcept
-{
- return v1.t1 < v2.t1 || (v1.t1 == v2.t1 && v1.t2 < v2.t2);
-}
-
-QDeadlineTimer QDeadlineTimer::current(Qt::TimerType timerType) noexcept
-{
- static_assert(QDeadlineTimerNanosecondsInT2);
- QDeadlineTimer result;
- qint64 cursec, curnsec;
- do_gettime(&cursec, &curnsec);
- result.t1 = cursec;
- result.t2 = curnsec;
- result.type = timerType;
- return result;
-}
-
-QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qelapsedtimer_win.cpp b/src/corelib/kernel/qelapsedtimer_win.cpp
deleted file mode 100644
index bbd5b220fe..0000000000
--- a/src/corelib/kernel/qelapsedtimer_win.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include "qelapsedtimer.h"
-#include "qdeadlinetimer.h"
-#include "qdeadlinetimer_p.h"
-#include <qt_windows.h>
-
-QT_BEGIN_NAMESPACE
-
-// Result of QueryPerformanceFrequency
-static quint64 counterFrequency = 0;
-
-static void resolveCounterFrequency()
-{
- static bool done = false;
- if (done)
- return;
-
- // Retrieve the number of high-resolution performance counter ticks per second
- LARGE_INTEGER frequency;
- if (!QueryPerformanceFrequency(&frequency) || frequency.QuadPart == 0)
- qFatal("QueryPerformanceFrequency failed, even though Microsoft documentation promises it wouldn't.");
- counterFrequency = frequency.QuadPart;
-
- done = true;
-}
-
-static inline qint64 ticksToNanoseconds(qint64 ticks)
-{
- // QueryPerformanceCounter uses an arbitrary frequency
- qint64 seconds = ticks / counterFrequency;
- qint64 nanoSeconds = (ticks - seconds * counterFrequency) * 1000000000 / counterFrequency;
- return seconds * 1000000000 + nanoSeconds;
-}
-
-
-static quint64 getTickCount()
-{
- resolveCounterFrequency();
-
- LARGE_INTEGER counter;
- bool ok = QueryPerformanceCounter(&counter);
- Q_ASSERT_X(ok, "QElapsedTimer::start()",
- "QueryPerformanceCounter failed, although QueryPerformanceFrequency succeeded.");
- Q_UNUSED(ok);
- return counter.QuadPart;
-}
-
-quint64 qt_msectime()
-{
- return ticksToNanoseconds(getTickCount()) / 1000000;
-}
-
-QElapsedTimer::ClockType QElapsedTimer::clockType() noexcept
-{
- resolveCounterFrequency();
-
- return PerformanceCounter;
-}
-
-bool QElapsedTimer::isMonotonic() noexcept
-{
- return true;
-}
-
-void QElapsedTimer::start() noexcept
-{
- t1 = getTickCount();
- t2 = 0;
-}
-
-qint64 QElapsedTimer::restart() noexcept
-{
- qint64 oldt1 = t1;
- t1 = getTickCount();
- t2 = 0;
- return ticksToNanoseconds(t1 - oldt1) / 1000000;
-}
-
-qint64 QElapsedTimer::nsecsElapsed() const noexcept
-{
- qint64 elapsed = getTickCount() - t1;
- return ticksToNanoseconds(elapsed);
-}
-
-qint64 QElapsedTimer::elapsed() const noexcept
-{
- qint64 elapsed = getTickCount() - t1;
- return ticksToNanoseconds(elapsed) / 1000000;
-}
-
-qint64 QElapsedTimer::msecsSinceReference() const noexcept
-{
- return ticksToNanoseconds(t1) / 1000000;
-}
-
-qint64 QElapsedTimer::msecsTo(const QElapsedTimer &other) const noexcept
-{
- qint64 difference = other.t1 - t1;
- return ticksToNanoseconds(difference) / 1000000;
-}
-
-qint64 QElapsedTimer::secsTo(const QElapsedTimer &other) const noexcept
-{
- return msecsTo(other) / 1000;
-}
-
-bool operator<(const QElapsedTimer &v1, const QElapsedTimer &v2) noexcept
-{
- return (v1.t1 - v2.t1) < 0;
-}
-
-QDeadlineTimer QDeadlineTimer::current(Qt::TimerType timerType) noexcept
-{
- static_assert(!QDeadlineTimerNanosecondsInT2);
- QDeadlineTimer result;
- result.t1 = ticksToNanoseconds(getTickCount());
- result.type = timerType;
- return result;
-}
-
-QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qeventdispatcher_cf.mm b/src/corelib/kernel/qeventdispatcher_cf.mm
index 770cb87e69..042b0651f4 100644
--- a/src/corelib/kernel/qeventdispatcher_cf.mm
+++ b/src/corelib/kernel/qeventdispatcher_cf.mm
@@ -169,7 +169,7 @@ static const CFTimeInterval kCFTimeIntervalDistantFuture = std::numeric_limits<C
#pragma mark - Class definition
QEventDispatcherCoreFoundation::QEventDispatcherCoreFoundation(QObject *parent)
- : QAbstractEventDispatcher(parent)
+ : QAbstractEventDispatcherV2(parent)
, m_processEvents(QEventLoop::EventLoopExec)
, m_postedEventsRunLoopSource(this, &QEventDispatcherCoreFoundation::processPostedEvents)
, m_runLoopActivityObserver(this, &QEventDispatcherCoreFoundation::handleRunLoopActivity, kCFRunLoopAllActivities)
@@ -195,7 +195,7 @@ void QEventDispatcherCoreFoundation::startingUp()
QEventDispatcherCoreFoundation::~QEventDispatcherCoreFoundation()
{
invalidateTimer();
- qDeleteAll(m_timerInfoList);
+ m_timerInfoList.clearTimers();
m_cfSocketNotifier.removeSocketNotifiers();
}
@@ -506,26 +506,28 @@ void QEventDispatcherCoreFoundation::unregisterSocketNotifier(QSocketNotifier *n
#pragma mark - Timers
-void QEventDispatcherCoreFoundation::registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object)
+void QEventDispatcherCoreFoundation::registerTimer(Qt::TimerId timerId, Duration interval,
+ Qt::TimerType timerType, QObject *object)
{
- qCDebug(lcEventDispatcherTimers) << "Registering timer with id =" << timerId << "interval =" << interval
+ qCDebug(lcEventDispatcherTimers) << "Registering timer with id =" << int(timerId) << "interval =" << interval
<< "type =" << timerType << "object =" << object;
- Q_ASSERT(timerId > 0 && interval >= 0 && object);
+ Q_ASSERT(qToUnderlying(timerId) > 0 && interval.count() >= 0 && object);
Q_ASSERT(object->thread() == thread() && thread() == QThread::currentThread());
m_timerInfoList.registerTimer(timerId, interval, timerType, object);
updateTimers();
}
-bool QEventDispatcherCoreFoundation::unregisterTimer(int timerId)
+bool QEventDispatcherCoreFoundation::unregisterTimer(Qt::TimerId timerId)
{
- Q_ASSERT(timerId > 0);
+ Q_ASSERT(qToUnderlying(timerId) > 0);
Q_ASSERT(thread() == QThread::currentThread());
bool returnValue = m_timerInfoList.unregisterTimer(timerId);
- qCDebug(lcEventDispatcherTimers) << "Unegistered timer with id =" << timerId << "Timers left:" << m_timerInfoList.size();
+ qCDebug(lcEventDispatcherTimers) << "Unegistered timer with id =" << qToUnderlying(timerId)
+ << "Timers left:" << m_timerInfoList.size();
updateTimers();
return returnValue;
@@ -543,22 +545,18 @@ bool QEventDispatcherCoreFoundation::unregisterTimers(QObject *object)
return returnValue;
}
-QList<QAbstractEventDispatcher::TimerInfo> QEventDispatcherCoreFoundation::registeredTimers(QObject *object) const
+QList<QAbstractEventDispatcher::TimerInfoV2>
+QEventDispatcherCoreFoundation::timersForObject(QObject *object) const
{
Q_ASSERT(object);
return m_timerInfoList.registeredTimers(object);
}
-int QEventDispatcherCoreFoundation::remainingTime(int timerId)
+QEventDispatcherCoreFoundation::Duration
+QEventDispatcherCoreFoundation::remainingTime(Qt::TimerId timerId) const
{
- Q_ASSERT(timerId > 0);
- return m_timerInfoList.timerRemainingTime(timerId);
-}
-
-static double timespecToSeconds(const timespec &spec)
-{
- static double nanosecondsPerSecond = 1.0 * 1000 * 1000 * 1000;
- return spec.tv_sec + (spec.tv_nsec / nanosecondsPerSecond);
+ Q_ASSERT(qToUnderlying(timerId) > 0);
+ return m_timerInfoList.remainingDuration(timerId);
}
void QEventDispatcherCoreFoundation::updateTimers()
@@ -566,12 +564,20 @@ void QEventDispatcherCoreFoundation::updateTimers()
if (m_timerInfoList.size() > 0) {
// We have Qt timers registered, so create or reschedule CF timer to match
- timespec tv = { -1, -1 };
- CFAbsoluteTime timeToFire = m_timerInfoList.timerWait(tv) ?
+ using namespace std::chrono_literals;
+ using DoubleSeconds = std::chrono::duration<double, std::ratio<1>>;
+
+ CFAbsoluteTime timeToFire;
+ auto opt = m_timerInfoList.timerWait();
+ DoubleSeconds secs{};
+ if (opt) {
// We have a timer ready to fire right now, or some time in the future
- CFAbsoluteTimeGetCurrent() + timespecToSeconds(tv)
+ secs = DoubleSeconds{*opt};
+ timeToFire = CFAbsoluteTimeGetCurrent() + secs.count();
+ } else {
// We have timers, but they are all currently blocked by callbacks
- : kCFTimeIntervalDistantFuture;
+ timeToFire = kCFTimeIntervalDistantFuture;
+ }
if (!m_runLoopTimer) {
m_runLoopTimer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault,
@@ -587,9 +593,9 @@ void QEventDispatcherCoreFoundation::updateTimers()
qCDebug(lcEventDispatcherTimers) << "Re-scheduled CFRunLoopTimer" << m_runLoopTimer;
}
- m_overdueTimerScheduled = !timespecToSeconds(tv);
+ m_overdueTimerScheduled = secs > 0s;
- qCDebug(lcEventDispatcherTimers) << "Next timeout in" << tv << "seconds";
+ qCDebug(lcEventDispatcherTimers) << "Next timeout in" << secs;
} else {
// No Qt timers are registered, so make sure we're not running any CF timers
diff --git a/src/corelib/kernel/qeventdispatcher_cf_p.h b/src/corelib/kernel/qeventdispatcher_cf_p.h
index c4c0d14027..3575a6fb39 100644
--- a/src/corelib/kernel/qeventdispatcher_cf_p.h
+++ b/src/corelib/kernel/qeventdispatcher_cf_p.h
@@ -168,7 +168,7 @@ private:
CFRunLoopObserverRef m_observer;
};
-class Q_CORE_EXPORT QEventDispatcherCoreFoundation : public QAbstractEventDispatcher
+class Q_CORE_EXPORT QEventDispatcherCoreFoundation : public QAbstractEventDispatcherV2
{
Q_OBJECT
@@ -182,12 +182,12 @@ public:
void registerSocketNotifier(QSocketNotifier *notifier) override;
void unregisterSocketNotifier(QSocketNotifier *notifier) override;
- void registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object) override;
- bool unregisterTimer(int timerId) override;
- bool unregisterTimers(QObject *object) override;
- QList<QAbstractEventDispatcher::TimerInfo> registeredTimers(QObject *object) const override;
-
- int remainingTime(int timerId) override;
+ void registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType,
+ QObject *object) override final;
+ bool unregisterTimer(Qt::TimerId timerId) override final;
+ bool unregisterTimers(QObject *object) override final;
+ QList<TimerInfoV2> timersForObject(QObject *object) const override final;
+ Duration remainingTime(Qt::TimerId timerId) const override final;
void wakeUp() override;
void interrupt() override;
@@ -204,6 +204,25 @@ protected:
, processedPostedEvents(false), processedTimers(false)
, deferredWakeUp(false), deferredUpdateTimers(false) {}
+ ProcessEventsState(const ProcessEventsState &other)
+ : flags(other.flags.loadAcquire())
+ , wasInterrupted(other.wasInterrupted.loadAcquire())
+ , processedPostedEvents(other.processedPostedEvents.loadAcquire())
+ , processedTimers(other.processedTimers.loadAcquire())
+ , deferredWakeUp(other.deferredWakeUp.loadAcquire())
+ , deferredUpdateTimers(other.deferredUpdateTimers) {}
+
+ ProcessEventsState &operator=(const ProcessEventsState &other)
+ {
+ flags.storeRelease(other.flags.loadAcquire());
+ wasInterrupted.storeRelease(other.wasInterrupted.loadAcquire());
+ processedPostedEvents.storeRelease(other.processedPostedEvents.loadAcquire());
+ processedTimers.storeRelease(other.processedTimers.loadAcquire());
+ deferredWakeUp.storeRelease(other.deferredWakeUp.loadAcquire());
+ deferredUpdateTimers = other.deferredUpdateTimers;
+ return *this;
+ }
+
QAtomicInt flags;
QAtomicInteger<char> wasInterrupted;
QAtomicInteger<char> processedPostedEvents;
diff --git a/src/corelib/kernel/qeventdispatcher_glib.cpp b/src/corelib/kernel/qeventdispatcher_glib.cpp
index eeb175c374..1e906c4b27 100644
--- a/src/corelib/kernel/qeventdispatcher_glib.cpp
+++ b/src/corelib/kernel/qeventdispatcher_glib.cpp
@@ -4,16 +4,19 @@
#include "qeventdispatcher_glib_p.h"
#include "qeventdispatcher_unix_p.h"
+#include <private/qnumeric_p.h>
#include <private/qthread_p.h>
#include "qcoreapplication.h"
#include "qsocketnotifier.h"
#include <QtCore/qlist.h>
-#include <QtCore/qpair.h>
#include <glib.h>
+using namespace std::chrono;
+using namespace std::chrono_literals;
+
QT_BEGIN_NAMESPACE
struct GPollFDWithQSocketNotifier
@@ -95,11 +98,13 @@ struct GTimerSource
static gboolean timerSourcePrepareHelper(GTimerSource *src, gint *timeout)
{
- timespec tv = { 0l, 0l };
- if (!(src->processEventsFlags & QEventLoop::X11ExcludeTimers) && src->timerList.timerWait(tv))
- *timeout = (tv.tv_sec * 1000) + ((tv.tv_nsec + 999999) / 1000 / 1000);
- else
+ if (src->processEventsFlags & QEventLoop::X11ExcludeTimers) {
*timeout = -1;
+ return true;
+ }
+
+ auto remaining = src->timerList.timerWait().value_or(-1ms);
+ *timeout = qt_saturate<gint>(ceil<milliseconds>(remaining).count());
return (*timeout == 0);
}
@@ -110,10 +115,7 @@ static gboolean timerSourceCheckHelper(GTimerSource *src)
|| (src->processEventsFlags & QEventLoop::X11ExcludeTimers))
return false;
- if (src->timerList.updateCurrentTime() < src->timerList.constFirst()->timeout)
- return false;
-
- return true;
+ return !src->timerList.hasPendingTimers();
}
static gboolean timerSourcePrepare(GSource *source, gint *timeout)
@@ -325,12 +327,12 @@ void QEventDispatcherGlibPrivate::runTimersOnceWithNormalPriority()
}
QEventDispatcherGlib::QEventDispatcherGlib(QObject *parent)
- : QAbstractEventDispatcher(*(new QEventDispatcherGlibPrivate), parent)
+ : QAbstractEventDispatcherV2(*(new QEventDispatcherGlibPrivate), parent)
{
}
QEventDispatcherGlib::QEventDispatcherGlib(GMainContext *mainContext, QObject *parent)
- : QAbstractEventDispatcher(*(new QEventDispatcherGlibPrivate(mainContext)), parent)
+ : QAbstractEventDispatcherV2(*(new QEventDispatcherGlibPrivate(mainContext)), parent)
{ }
QEventDispatcherGlib::~QEventDispatcherGlib()
@@ -338,7 +340,7 @@ QEventDispatcherGlib::~QEventDispatcherGlib()
Q_D(QEventDispatcherGlib);
// destroy all timer sources
- qDeleteAll(d->timerSource->timerList);
+ d->timerSource->timerList.clearTimers();
d->timerSource->timerList.~QTimerInfoList();
g_source_destroy(&d->timerSource->source);
g_source_unref(&d->timerSource->source);
@@ -405,7 +407,7 @@ bool QEventDispatcherGlib::processEvents(QEventLoop::ProcessEventsFlags flags)
void QEventDispatcherGlib::registerSocketNotifier(QSocketNotifier *notifier)
{
Q_ASSERT(notifier);
- int sockfd = notifier->socket();
+ int sockfd = int(notifier->socket());
int type = notifier->type();
#ifndef QT_NO_DEBUG
if (sockfd < 0) {
@@ -445,8 +447,7 @@ void QEventDispatcherGlib::unregisterSocketNotifier(QSocketNotifier *notifier)
{
Q_ASSERT(notifier);
#ifndef QT_NO_DEBUG
- int sockfd = notifier->socket();
- if (sockfd < 0) {
+ if (notifier->socket() < 0) {
qWarning("QSocketNotifier: Internal error");
return;
} else if (notifier->thread() != thread()
@@ -476,10 +477,11 @@ void QEventDispatcherGlib::unregisterSocketNotifier(QSocketNotifier *notifier)
}
}
-void QEventDispatcherGlib::registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object)
+void QEventDispatcherGlib::registerTimer(Qt::TimerId timerId, Duration interval,
+ Qt::TimerType timerType, QObject *object)
{
#ifndef QT_NO_DEBUG
- if (timerId < 1 || interval < 0 || !object) {
+ if (qToUnderlying(timerId) < 1 || interval < 0ns || !object) {
qWarning("QEventDispatcherGlib::registerTimer: invalid arguments");
return;
} else if (object->thread() != thread() || thread() != QThread::currentThread()) {
@@ -489,14 +491,13 @@ void QEventDispatcherGlib::registerTimer(int timerId, qint64 interval, Qt::Timer
#endif
Q_D(QEventDispatcherGlib);
- d->timerSource->timerList.registerTimer(timerId, std::chrono::milliseconds{ interval },
- timerType, object);
+ d->timerSource->timerList.registerTimer(timerId, interval, timerType, object);
}
-bool QEventDispatcherGlib::unregisterTimer(int timerId)
+bool QEventDispatcherGlib::unregisterTimer(Qt::TimerId timerId)
{
#ifndef QT_NO_DEBUG
- if (timerId < 1) {
+ if (qToUnderlying(timerId) < 1) {
qWarning("QEventDispatcherGlib::unregisterTimer: invalid argument");
return false;
} else if (thread() != QThread::currentThread()) {
@@ -525,28 +526,30 @@ bool QEventDispatcherGlib::unregisterTimers(QObject *object)
return d->timerSource->timerList.unregisterTimers(object);
}
-QList<QEventDispatcherGlib::TimerInfo> QEventDispatcherGlib::registeredTimers(QObject *object) const
+QList<QEventDispatcherGlib::TimerInfoV2> QEventDispatcherGlib::timersForObject(QObject *object) const
{
+#ifndef QT_NO_DEBUG
if (!object) {
- qWarning("QEventDispatcherUNIX:registeredTimers: invalid argument");
- return QList<TimerInfo>();
+ qWarning("QEventDispatcherGlib:timersForObject: invalid argument");
+ return {};
}
+#endif
Q_D(const QEventDispatcherGlib);
return d->timerSource->timerList.registeredTimers(object);
}
-int QEventDispatcherGlib::remainingTime(int timerId)
+QEventDispatcherGlib::Duration QEventDispatcherGlib::remainingTime(Qt::TimerId timerId) const
{
#ifndef QT_NO_DEBUG
- if (timerId < 1) {
+ if (qToUnderlying(timerId) < 1) {
qWarning("QEventDispatcherGlib::remainingTimeTime: invalid argument");
- return -1;
+ return Duration::min();
}
#endif
- Q_D(QEventDispatcherGlib);
- return d->timerSource->timerList.timerRemainingTime(timerId);
+ Q_D(const QEventDispatcherGlib);
+ return d->timerSource->timerList.remainingDuration(timerId);
}
void QEventDispatcherGlib::interrupt()
@@ -571,7 +574,7 @@ bool QEventDispatcherGlib::versionSupported()
}
QEventDispatcherGlib::QEventDispatcherGlib(QEventDispatcherGlibPrivate &dd, QObject *parent)
- : QAbstractEventDispatcher(dd, parent)
+ : QAbstractEventDispatcherV2(dd, parent)
{
}
diff --git a/src/corelib/kernel/qeventdispatcher_glib_p.h b/src/corelib/kernel/qeventdispatcher_glib_p.h
index 4881a8543f..30783d3858 100644
--- a/src/corelib/kernel/qeventdispatcher_glib_p.h
+++ b/src/corelib/kernel/qeventdispatcher_glib_p.h
@@ -24,7 +24,7 @@ QT_BEGIN_NAMESPACE
class QEventDispatcherGlibPrivate;
-class Q_CORE_EXPORT QEventDispatcherGlib : public QAbstractEventDispatcher
+class Q_CORE_EXPORT QEventDispatcherGlib : public QAbstractEventDispatcherV2
{
Q_OBJECT
Q_DECLARE_PRIVATE(QEventDispatcherGlib)
@@ -39,12 +39,12 @@ public:
void registerSocketNotifier(QSocketNotifier *socketNotifier) final;
void unregisterSocketNotifier(QSocketNotifier *socketNotifier) final;
- void registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object) final;
- bool unregisterTimer(int timerId) final;
- bool unregisterTimers(QObject *object) final;
- QList<TimerInfo> registeredTimers(QObject *object) const final;
-
- int remainingTime(int timerId) final;
+ void registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType,
+ QObject *object) override final;
+ bool unregisterTimer(Qt::TimerId timerId) override final;
+ bool unregisterTimers(QObject *object) override final;
+ QList<TimerInfoV2> timersForObject(QObject *object) const override final;
+ Duration remainingTime(Qt::TimerId timerId) const override final;
void wakeUp() final;
void interrupt() final;
diff --git a/src/corelib/kernel/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp
index c75b59acfe..21bd224415 100644
--- a/src/corelib/kernel/qeventdispatcher_unix.cpp
+++ b/src/corelib/kernel/qeventdispatcher_unix.cpp
@@ -5,7 +5,6 @@
#include "qplatformdefs.h"
#include "qcoreapplication.h"
-#include "qpair.h"
#include "qhash.h"
#include "qsocketnotifier.h"
#include "qthread.h"
@@ -19,23 +18,19 @@
#include <stdio.h>
#include <stdlib.h>
-#ifndef QT_NO_EVENTFD
+#if __has_include(<sys/eventfd.h>)
# include <sys/eventfd.h>
+static constexpr bool UsingEventfd = true;
+#else
+static constexpr bool UsingEventfd = false;
#endif
-// VxWorks doesn't correctly set the _POSIX_... options
#if defined(Q_OS_VXWORKS)
-# if defined(_POSIX_MONOTONIC_CLOCK) && (_POSIX_MONOTONIC_CLOCK <= 0)
-# undef _POSIX_MONOTONIC_CLOCK
-# define _POSIX_MONOTONIC_CLOCK 1
-# endif
# include <pipeDrv.h>
-# include <sys/time.h>
#endif
-#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) || defined(QT_BOOTSTRAPPED)
-# include <sys/times.h>
-#endif
+using namespace std::chrono;
+using namespace std::chrono_literals;
QT_BEGIN_NAMESPACE
@@ -55,11 +50,6 @@ static const char *socketType(QSocketNotifier::Type type)
QThreadPipe::QThreadPipe()
{
- fds[0] = -1;
- fds[1] = -1;
-#if defined(Q_OS_VXWORKS)
- name[0] = '\0';
-#endif
}
QThreadPipe::~QThreadPipe()
@@ -67,7 +57,7 @@ QThreadPipe::~QThreadPipe()
if (fds[0] >= 0)
close(fds[0]);
- if (fds[1] >= 0)
+ if (!UsingEventfd && fds[1] >= 0)
close(fds[1]);
#if defined(Q_OS_VXWORKS)
@@ -104,23 +94,25 @@ bool QThreadPipe::init()
// create the pipe
if (pipeDevCreate(name, 128 /*maxMsg*/, 1 /*maxLength*/) != OK) {
- perror("QThreadPipe: Unable to create thread pipe device %s", name);
+ perror("QThreadPipe: Unable to create thread pipe device");
return false;
}
if ((fds[0] = open(name, O_RDWR, 0)) < 0) {
- perror("QThreadPipe: Unable to open pipe device %s", name);
+ perror("QThreadPipe: Unable to open pipe device");
return false;
}
initThreadPipeFD(fds[0]);
fds[1] = fds[0];
#else
-# ifndef QT_NO_EVENTFD
- if ((fds[0] = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC)) >= 0)
- return true;
+ int ret;
+# ifdef EFD_CLOEXEC
+ ret = fds[0] = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
# endif
- if (qt_safe_pipe(fds, O_NONBLOCK) == -1) {
+ if (!UsingEventfd)
+ ret = qt_safe_pipe(fds, O_NONBLOCK);
+ if (ret == -1) {
perror("QThreadPipe: Unable to create pipe");
return false;
}
@@ -136,15 +128,10 @@ pollfd QThreadPipe::prepare() const
void QThreadPipe::wakeUp()
{
- if (wakeUps.testAndSetAcquire(0, 1)) {
-#ifndef QT_NO_EVENTFD
- if (fds[1] == -1) {
- // eventfd
- eventfd_t value = 1;
- int ret;
- EINTR_LOOP(ret, eventfd_write(fds[0], value));
- return;
- }
+ if ((wakeUps.fetchAndOrAcquire(1) & 1) == 0) {
+# ifdef EFD_CLOEXEC
+ eventfd_write(fds[0], 1);
+ return;
#endif
char c = 0;
qt_safe_write(fds[1], &c, 1);
@@ -165,14 +152,11 @@ int QThreadPipe::check(const pollfd &pfd)
::read(fds[0], c, sizeof(c));
::ioctl(fds[0], FIOFLUSH, 0);
#else
-# ifndef QT_NO_EVENTFD
- if (fds[1] == -1) {
- // eventfd
- eventfd_t value;
- eventfd_read(fds[0], &value);
- } else
+# ifdef EFD_CLOEXEC
+ eventfd_t value;
+ eventfd_read(fds[0], &value);
# endif
- {
+ if (!UsingEventfd) {
while (::read(fds[0], c, sizeof(c)) > 0) {}
}
#endif
@@ -195,7 +179,7 @@ QEventDispatcherUNIXPrivate::QEventDispatcherUNIXPrivate()
QEventDispatcherUNIXPrivate::~QEventDispatcherUNIXPrivate()
{
// cleanup timers
- qDeleteAll(timerList);
+ timerList.clearTimers();
}
void QEventDispatcherUNIXPrivate::setSocketNotifierPending(QSocketNotifier *notifier)
@@ -273,11 +257,11 @@ int QEventDispatcherUNIXPrivate::activateSocketNotifiers()
}
QEventDispatcherUNIX::QEventDispatcherUNIX(QObject *parent)
- : QAbstractEventDispatcher(*new QEventDispatcherUNIXPrivate, parent)
+ : QAbstractEventDispatcherV2(*new QEventDispatcherUNIXPrivate, parent)
{ }
QEventDispatcherUNIX::QEventDispatcherUNIX(QEventDispatcherUNIXPrivate &dd, QObject *parent)
- : QAbstractEventDispatcher(dd, parent)
+ : QAbstractEventDispatcherV2(dd, parent)
{ }
QEventDispatcherUNIX::~QEventDispatcherUNIX()
@@ -286,10 +270,10 @@ QEventDispatcherUNIX::~QEventDispatcherUNIX()
/*!
\internal
*/
-void QEventDispatcherUNIX::registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *obj)
+void QEventDispatcherUNIX::registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType, QObject *obj)
{
#ifndef QT_NO_DEBUG
- if (timerId < 1 || interval < 0 || !obj) {
+ if (qToUnderlying(timerId) < 1 || interval.count() < 0 || !obj) {
qWarning("QEventDispatcherUNIX::registerTimer: invalid arguments");
return;
} else if (obj->thread() != thread() || thread() != QThread::currentThread()) {
@@ -299,16 +283,16 @@ void QEventDispatcherUNIX::registerTimer(int timerId, qint64 interval, Qt::Timer
#endif
Q_D(QEventDispatcherUNIX);
- d->timerList.registerTimer(timerId, std::chrono::milliseconds{ interval }, timerType, obj);
+ d->timerList.registerTimer(timerId, interval, timerType, obj);
}
/*!
\internal
*/
-bool QEventDispatcherUNIX::unregisterTimer(int timerId)
+bool QEventDispatcherUNIX::unregisterTimer(Qt::TimerId timerId)
{
#ifndef QT_NO_DEBUG
- if (timerId < 1) {
+ if (qToUnderlying(timerId) < 1) {
qWarning("QEventDispatcherUNIX::unregisterTimer: invalid argument");
return false;
} else if (thread() != QThread::currentThread()) {
@@ -340,12 +324,12 @@ bool QEventDispatcherUNIX::unregisterTimers(QObject *object)
return d->timerList.unregisterTimers(object);
}
-QList<QEventDispatcherUNIX::TimerInfo>
-QEventDispatcherUNIX::registeredTimers(QObject *object) const
+QList<QEventDispatcherUNIX::TimerInfoV2>
+QEventDispatcherUNIX::timersForObject(QObject *object) const
{
if (!object) {
qWarning("QEventDispatcherUNIX:registeredTimers: invalid argument");
- return QList<TimerInfo>();
+ return QList<TimerInfoV2>();
}
Q_D(const QEventDispatcherUNIX);
@@ -445,11 +429,19 @@ bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags)
if (d->interrupt.loadRelaxed())
return false;
- timespec *tm = nullptr;
- timespec wait_tm = { 0, 0 };
-
- if (!canWait || (include_timers && d->timerList.timerWait(wait_tm)))
- tm = &wait_tm;
+ QDeadlineTimer deadline;
+ if (canWait) {
+ if (include_timers) {
+ std::optional<nanoseconds> remaining = d->timerList.timerWait();
+ deadline = remaining ? QDeadlineTimer{*remaining}
+ : QDeadlineTimer(QDeadlineTimer::Forever);
+ } else {
+ deadline = QDeadlineTimer(QDeadlineTimer::Forever);
+ }
+ } else {
+ // Using the default-constructed `deadline`, which is already expired,
+ // ensures the code in the do-while loop in qt_safe_poll runs at least once.
+ }
d->pollfds.clear();
d->pollfds.reserve(1 + (include_notifiers ? d->socketNotifiers.size() : 0));
@@ -462,8 +454,7 @@ bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags)
d->pollfds.append(d->threadPipe.prepare());
int nevents = 0;
-
- switch (qt_safe_poll(d->pollfds.data(), d->pollfds.size(), tm)) {
+ switch (qt_safe_poll(d->pollfds.data(), d->pollfds.size(), deadline)) {
case -1:
qErrnoWarning("qt_safe_poll");
if (QT_CONFIG(poll_exit_on_error))
@@ -485,17 +476,17 @@ bool QEventDispatcherUNIX::processEvents(QEventLoop::ProcessEventsFlags flags)
return (nevents > 0);
}
-int QEventDispatcherUNIX::remainingTime(int timerId)
+auto QEventDispatcherUNIX::remainingTime(Qt::TimerId timerId) const -> Duration
{
#ifndef QT_NO_DEBUG
- if (timerId < 1) {
+ if (int(timerId) < 1) {
qWarning("QEventDispatcherUNIX::remainingTime: invalid argument");
- return -1;
+ return Duration::min();
}
#endif
- Q_D(QEventDispatcherUNIX);
- return d->timerList.timerRemainingTime(timerId);
+ Q_D(const QEventDispatcherUNIX);
+ return d->timerList.remainingDuration(timerId);
}
void QEventDispatcherUNIX::wakeUp()
diff --git a/src/corelib/kernel/qeventdispatcher_unix_p.h b/src/corelib/kernel/qeventdispatcher_unix_p.h
index 4e9a360f3e..6596e998c9 100644
--- a/src/corelib/kernel/qeventdispatcher_unix_p.h
+++ b/src/corelib/kernel/qeventdispatcher_unix_p.h
@@ -51,17 +51,17 @@ struct QThreadPipe
int check(const pollfd &pfd);
// note for eventfd(7) support:
- // if fds[1] is -1, then eventfd(7) is in use and is stored in fds[0]
- int fds[2];
+ // fds[0] stores the eventfd, fds[1] is unused
+ int fds[2] = { -1, -1 };
QAtomicInt wakeUps;
#if defined(Q_OS_VXWORKS)
- static const int len_name = 20;
- char name[len_name];
+ static constexpr int len_name = 20;
+ char name[len_name] = {};
#endif
};
-class Q_CORE_EXPORT QEventDispatcherUNIX : public QAbstractEventDispatcher
+class Q_CORE_EXPORT QEventDispatcherUNIX : public QAbstractEventDispatcherV2
{
Q_OBJECT
Q_DECLARE_PRIVATE(QEventDispatcherUNIX)
@@ -75,12 +75,12 @@ public:
void registerSocketNotifier(QSocketNotifier *notifier) final;
void unregisterSocketNotifier(QSocketNotifier *notifier) final;
- void registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object) final;
- bool unregisterTimer(int timerId) final;
- bool unregisterTimers(QObject *object) final;
- QList<TimerInfo> registeredTimers(QObject *object) const final;
-
- int remainingTime(int timerId) final;
+ void registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType,
+ QObject *object) override final;
+ bool unregisterTimer(Qt::TimerId timerId) override final;
+ bool unregisterTimers(QObject *object) override final;
+ QList<TimerInfoV2> timersForObject(QObject *object) const override final;
+ Duration remainingTime(Qt::TimerId timerId) const override final;
void wakeUp() override;
void interrupt() final;
diff --git a/src/corelib/kernel/qeventdispatcher_wasm.cpp b/src/corelib/kernel/qeventdispatcher_wasm.cpp
index 8b64856621..4aa435b64b 100644
--- a/src/corelib/kernel/qeventdispatcher_wasm.cpp
+++ b/src/corelib/kernel/qeventdispatcher_wasm.cpp
@@ -14,6 +14,9 @@
#include <emscripten/threading.h>
#include <emscripten/val.h>
+using namespace std::chrono;
+using namespace std::chrono_literals;
+
QT_BEGIN_NAMESPACE
// using namespace emscripten;
@@ -40,6 +43,50 @@ static bool useAsyncify()
return qstdweb::haveAsyncify();
}
+static bool useJspi()
+{
+ return qstdweb::haveJspi();
+}
+
+// clang-format off
+EM_ASYNC_JS(void, qt_jspi_suspend_js, (), {
+ ++Module.qtJspiSuspensionCounter;
+
+ await new Promise(resolve => {
+ Module.qtAsyncifyWakeUp.push(resolve);
+ });
+});
+
+EM_JS(bool, qt_jspi_resume_js, (), {
+ if (!Module.qtJspiSuspensionCounter)
+ return false;
+
+ --Module.qtJspiSuspensionCounter;
+
+ setTimeout(() => {
+ const wakeUp = (Module.qtAsyncifyWakeUp ?? []).pop();
+ if (wakeUp) wakeUp();
+ });
+ return true;
+});
+
+EM_JS(bool, qt_jspi_can_resume_js, (), {
+ return Module.qtJspiSuspensionCounter > 0;
+});
+
+EM_JS(void, init_jspi_support_js, (), {
+ Module.qtAsyncifyWakeUp = [];
+ Module.qtJspiSuspensionCounter = 0;
+});
+// clang-format on
+
+void initJspiSupport() {
+ init_jspi_support_js();
+}
+
+Q_CONSTRUCTOR_FUNCTION(initJspiSupport);
+
+// clang-format off
EM_JS(void, qt_asyncify_suspend_js, (), {
if (Module.qtSuspendId === undefined)
Module.qtSuspendId = 0;
@@ -66,6 +113,7 @@ EM_JS(void, qt_asyncify_resume_js, (), {
wakeUp();
});
});
+// clang-format on
#else
@@ -76,6 +124,28 @@ static bool useAsyncify()
return false;
}
+static bool useJspi()
+{
+ return false;
+}
+
+void qt_jspi_suspend_js()
+{
+ Q_UNREACHABLE();
+}
+
+bool qt_jspi_resume_js()
+{
+ Q_UNREACHABLE();
+ return false;
+}
+
+bool qt_jspi_can_resume_js()
+{
+ Q_UNREACHABLE();
+ return false;
+}
+
void qt_asyncify_suspend_js()
{
Q_UNREACHABLE();
@@ -103,15 +173,15 @@ bool qt_asyncify_suspend()
// Wakes any currently suspended main thread. Returns true if the main
// thread was suspended, in which case it will now be asynchronously woken.
-bool qt_asyncify_resume()
+void qt_asyncify_resume()
{
if (!g_is_asyncify_suspended)
- return false;
+ return;
g_is_asyncify_suspended = false;
qt_asyncify_resume_js();
- return true;
}
+
Q_CONSTINIT QEventDispatcherWasm *QEventDispatcherWasm::g_mainThreadEventDispatcher = nullptr;
#if QT_CONFIG(thread)
Q_CONSTINIT QVector<QEventDispatcherWasm *> QEventDispatcherWasm::g_secondaryThreadEventDispatchers;
@@ -124,7 +194,6 @@ std::multimap<int, QSocketNotifier *> QEventDispatcherWasm::g_socketNotifiers;
std::map<int, QEventDispatcherWasm::SocketReadyState> QEventDispatcherWasm::g_socketState;
QEventDispatcherWasm::QEventDispatcherWasm()
- : QAbstractEventDispatcher()
{
// QEventDispatcherWasm operates in two main modes:
// - On the main thread:
@@ -149,6 +218,12 @@ QEventDispatcherWasm::QEventDispatcherWasm()
#if QT_CONFIG(thread)
g_mainThread = pthread_self();
#endif
+
+ // Call the "onLoaded" JavaScript callback, unless startup tasks
+ // have been registered which should complete first. Run async
+ // to make sure event dispatcher construction (in particular any
+ // subclass construction) has completed first.
+ runAsync(callOnLoadedIfRequired);
} else {
#if QT_CONFIG(thread)
std::lock_guard<std::mutex> lock(g_staticDataMutex);
@@ -203,7 +278,6 @@ bool QEventDispatcherWasm::isValidEventDispatcherPointer(QEventDispatcherWasm *e
if (eventDispatcher == g_mainThreadEventDispatcher)
return true;
#if QT_CONFIG(thread)
- Q_ASSERT(!g_staticDataMutex.try_lock()); // caller must lock mutex
if (g_secondaryThreadEventDispatchers.contains(eventDispatcher))
return true;
#endif
@@ -212,12 +286,9 @@ bool QEventDispatcherWasm::isValidEventDispatcherPointer(QEventDispatcherWasm *e
bool QEventDispatcherWasm::processEvents(QEventLoop::ProcessEventsFlags flags)
{
- emit awake();
-
- bool hasPendingEvents = qGlobalPostedEventsCount() > 0;
+ qCDebug(lcEventDispatcher) << "QEventDispatcherWasm::processEvents flags" << flags;
- qCDebug(lcEventDispatcher) << "QEventDispatcherWasm::processEvents flags" << flags
- << "pending events" << hasPendingEvents;
+ emit awake();
if (isMainThreadEventDispatcher()) {
if (flags & QEventLoop::DialogExec)
@@ -226,28 +297,36 @@ bool QEventDispatcherWasm::processEvents(QEventLoop::ProcessEventsFlags flags)
handleApplicationExec();
}
- if (!hasPendingEvents && (flags & QEventLoop::WaitForMoreEvents))
- wait();
+#if QT_CONFIG(thread)
+ {
+ // Reset wakeUp state: if wakeUp() was called at some point before
+ // this then processPostedEvents() below will service that call.
+ std::unique_lock<std::mutex> lock(m_mutex);
+ m_wakeUpCalled = false;
+ }
+#endif
+
+ processPostedEvents();
+
+ // The processPostedEvents() call above may process an event which deletes the
+ // application object and the event dispatcher; stop event processing in that case.
+ if (!isValidEventDispatcherPointer(this))
+ return false;
if (m_interrupted) {
m_interrupted = false;
return false;
}
+ if (flags & QEventLoop::WaitForMoreEvents)
+ wait();
+
if (m_processTimers) {
m_processTimers = false;
processTimers();
}
- QCoreApplication::sendPostedEvents();
- processWindowSystemEvents(flags);
-
- return qGlobalPostedEventsCount() > 0;
-}
-
-void QEventDispatcherWasm::processWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
-{
- Q_UNUSED(flags);
+ return false;
}
void QEventDispatcherWasm::registerSocketNotifier(QSocketNotifier *notifier)
@@ -257,7 +336,7 @@ void QEventDispatcherWasm::registerSocketNotifier(QSocketNotifier *notifier)
bool wasEmpty = g_socketNotifiers.empty();
g_socketNotifiers.insert({notifier->socket(), notifier});
if (wasEmpty)
- runOnMainThread([]{ setEmscriptenSocketCallbacks(); });
+ runOnMainThread([] { setEmscriptenSocketCallbacks(); });
}
void QEventDispatcherWasm::unregisterSocketNotifier(QSocketNotifier *notifier)
@@ -273,13 +352,13 @@ void QEventDispatcherWasm::unregisterSocketNotifier(QSocketNotifier *notifier)
}
if (g_socketNotifiers.empty())
- runOnMainThread([]{ clearEmscriptenSocketCallbacks(); });
+ runOnMainThread([] { clearEmscriptenSocketCallbacks(); });
}
-void QEventDispatcherWasm::registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object)
+void QEventDispatcherWasm::registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType, QObject *object)
{
#ifndef QT_NO_DEBUG
- if (timerId < 1 || interval < 0 || !object) {
+ if (qToUnderlying(timerId) < 1 || interval < 0ns || !object) {
qWarning("QEventDispatcherWasm::registerTimer: invalid arguments");
return;
} else if (object->thread() != thread() || thread() != QThread::currentThread()) {
@@ -288,16 +367,16 @@ void QEventDispatcherWasm::registerTimer(int timerId, qint64 interval, Qt::Timer
return;
}
#endif
- qCDebug(lcEventDispatcherTimers) << "registerTimer" << timerId << interval << timerType << object;
+ qCDebug(lcEventDispatcherTimers) << "registerTimer" << int(timerId) << interval << timerType << object;
m_timerInfo->registerTimer(timerId, interval, timerType, object);
updateNativeTimer();
}
-bool QEventDispatcherWasm::unregisterTimer(int timerId)
+bool QEventDispatcherWasm::unregisterTimer(Qt::TimerId timerId)
{
#ifndef QT_NO_DEBUG
- if (timerId < 1) {
+ if (qToUnderlying(timerId) < 1) {
qWarning("QEventDispatcherWasm::unregisterTimer: invalid argument");
return false;
} else if (thread() != QThread::currentThread()) {
@@ -307,7 +386,7 @@ bool QEventDispatcherWasm::unregisterTimer(int timerId)
}
#endif
- qCDebug(lcEventDispatcherTimers) << "unregisterTimer" << timerId;
+ qCDebug(lcEventDispatcherTimers) << "unregisterTimer" << int(timerId);
bool ans = m_timerInfo->unregisterTimer(timerId);
updateNativeTimer();
@@ -334,22 +413,22 @@ bool QEventDispatcherWasm::unregisterTimers(QObject *object)
return ans;
}
-QList<QAbstractEventDispatcher::TimerInfo>
-QEventDispatcherWasm::registeredTimers(QObject *object) const
+QList<QAbstractEventDispatcher::TimerInfoV2>
+QEventDispatcherWasm::timersForObject(QObject *object) const
{
#ifndef QT_NO_DEBUG
if (!object) {
qWarning("QEventDispatcherWasm:registeredTimers: invalid argument");
- return QList<TimerInfo>();
+ return {};
}
#endif
return m_timerInfo->registeredTimers(object);
}
-int QEventDispatcherWasm::remainingTime(int timerId)
+QEventDispatcherWasm::Duration QEventDispatcherWasm::remainingTime(Qt::TimerId timerId) const
{
- return m_timerInfo->timerRemainingTime(timerId);
+ return m_timerInfo->remainingDuration(timerId);
}
void QEventDispatcherWasm::interrupt()
@@ -365,7 +444,9 @@ void QEventDispatcherWasm::wakeUp()
// event loop. Make sure the thread is unblocked or make it
// process events.
bool wasBlocked = wakeEventDispatcherThread();
- if (!wasBlocked && isMainThreadEventDispatcher()) {
+ // JSPI does not need a scheduled call to processPostedEvents, as the stack is not unwound
+ // at startup.
+ if (!qstdweb::haveJspi() && !wasBlocked && isMainThreadEventDispatcher()) {
{
LOCK_GUARD(m_mutex);
if (m_pendingProcessEvents)
@@ -373,7 +454,7 @@ void QEventDispatcherWasm::wakeUp()
m_pendingProcessEvents = true;
}
runOnMainThreadAsync([this](){
- QEventDispatcherWasm::callProcessEvents(this);
+ QEventDispatcherWasm::callProcessPostedEvents(this);
});
}
}
@@ -388,10 +469,14 @@ void QEventDispatcherWasm::handleApplicationExec()
// Note that we don't use asyncify here: Emscripten supports one level of
// asyncify only and we want to reserve that for dialog exec() instead of
// using it for the one qApp exec().
- const bool simulateInfiniteLoop = true;
- emscripten_set_main_loop([](){
- emscripten_pause_main_loop();
- }, 0, simulateInfiniteLoop);
+ // When JSPI is used, awaited async calls are allowed to be nested, so we
+ // proceed normally.
+ if (!qstdweb::haveJspi()) {
+ const bool simulateInfiniteLoop = true;
+ emscripten_set_main_loop([](){
+ emscripten_pause_main_loop();
+ }, 0, simulateInfiniteLoop);
+ }
}
void QEventDispatcherWasm::handleDialogExec()
@@ -417,7 +502,12 @@ bool QEventDispatcherWasm::wait(int timeout)
if (isSecondaryThreadEventDispatcher()) {
std::unique_lock<std::mutex> lock(m_mutex);
- m_wakeUpCalled = false;
+ // If wakeUp() was called there might be pending events in the event
+ // queue which should be processed. Don't block, instead return
+ // so that the event loop can spin and call processEvents() again.
+ if (m_wakeUpCalled)
+ return true;
+
auto wait_time = timeout > 0 ? timeout * 1ms : std::chrono::duration<int, std::micro>::max();
bool wakeUpCalled = m_moreEvents.wait_for(lock, wait_time, [=] { return m_wakeUpCalled; });
return wakeUpCalled;
@@ -429,10 +519,14 @@ bool QEventDispatcherWasm::wait(int timeout)
if (timeout > 0)
qWarning() << "QEventDispatcherWasm asyncify wait with timeout is not supported; timeout will be ignored"; // FIXME
- bool didSuspend = qt_asyncify_suspend();
- if (!didSuspend) {
- qWarning("QEventDispatcherWasm: current thread is already suspended; could not asyncify wait for events");
- return false;
+ if (useJspi()) {
+ qt_jspi_suspend_js();
+ } else {
+ bool didSuspend = qt_asyncify_suspend();
+ if (!didSuspend) {
+ qWarning("QEventDispatcherWasm: current thread is already suspended; could not asyncify wait for events");
+ return false;
+ }
}
return true;
} else {
@@ -456,16 +550,27 @@ bool QEventDispatcherWasm::wakeEventDispatcherThread()
}
#endif
Q_ASSERT(isMainThreadEventDispatcher());
- if (g_is_asyncify_suspended) {
- runOnMainThread([]{ qt_asyncify_resume(); });
- return true;
+ if (useJspi()) {
+
+#if QT_CONFIG(thread)
+ return qstdweb::runTaskOnMainThread<bool>(
+ []() { return qt_jspi_can_resume_js() && qt_jspi_resume_js(); }, &g_proxyingQueue);
+#else
+ return qstdweb::runTaskOnMainThread<bool>(
+ []() { return qt_jspi_can_resume_js() && qt_jspi_resume_js(); });
+#endif
+
+ } else {
+ if (!g_is_asyncify_suspended)
+ return false;
+ runOnMainThread([]() { qt_asyncify_resume(); });
}
- return false;
+ return true;
}
// Process event activation callbacks for the main thread event dispatcher.
// Must be called on the main thread.
-void QEventDispatcherWasm::callProcessEvents(void *context)
+void QEventDispatcherWasm::callProcessPostedEvents(void *context)
{
Q_ASSERT(emscripten_is_main_runtime_thread());
@@ -473,7 +578,7 @@ void QEventDispatcherWasm::callProcessEvents(void *context)
if (!g_mainThreadEventDispatcher)
return;
- // In the unlikely event that we get a callProcessEvents() call for
+ // In the unlikely event that we get a callProcessPostedEvents() call for
// a previous main thread event dispatcher (i.e. the QApplication
// object was deleted and created again): just ignore it and return.
if (context != g_mainThreadEventDispatcher)
@@ -483,7 +588,14 @@ void QEventDispatcherWasm::callProcessEvents(void *context)
LOCK_GUARD(g_mainThreadEventDispatcher->m_mutex);
g_mainThreadEventDispatcher->m_pendingProcessEvents = false;
}
- g_mainThreadEventDispatcher->processEvents(QEventLoop::AllEvents);
+
+ g_mainThreadEventDispatcher->processPostedEvents();
+}
+
+bool QEventDispatcherWasm::processPostedEvents()
+{
+ QCoreApplication::sendPostedEvents();
+ return false;
}
void QEventDispatcherWasm::processTimers()
@@ -507,34 +619,32 @@ void QEventDispatcherWasm::updateNativeTimer()
// access to m_timerInfo), and then call native API to set the new
// wakeup time on the main thread.
- auto timespecToNanosec = [](timespec ts) -> uint64_t {
- return ts.tv_sec * 1000 + ts.tv_nsec / (1000 * 1000);
- };
- timespec toWait;
- bool hasTimer = m_timerInfo->timerWait(toWait);
- uint64_t currentTime = timespecToNanosec(m_timerInfo->currentTime);
- uint64_t toWaitDuration = timespecToNanosec(toWait);
- uint64_t newTargetTime = currentTime + toWaitDuration;
-
- auto maintainNativeTimer = [this, hasTimer, toWaitDuration, newTargetTime]() {
+ const std::optional<std::chrono::nanoseconds> wait = m_timerInfo->timerWait();
+ const auto toWaitDuration = duration_cast<milliseconds>(wait.value_or(0ms));
+ const auto newTargetTimePoint = m_timerInfo->currentTime + toWaitDuration;
+ auto epochNsecs = newTargetTimePoint.time_since_epoch();
+ auto newTargetTime = std::chrono::duration_cast<std::chrono::milliseconds>(epochNsecs);
+ auto maintainNativeTimer = [this, wait, toWaitDuration, newTargetTime]() {
Q_ASSERT(emscripten_is_main_runtime_thread());
- if (!hasTimer) {
+ if (!wait) {
if (m_timerId > 0) {
emscripten_clear_timeout(m_timerId);
m_timerId = 0;
- m_timerTargetTime = 0;
+ m_timerTargetTime = 0ms;
}
return;
}
- if (m_timerTargetTime != 0 && newTargetTime >= m_timerTargetTime)
+ if (m_timerTargetTime != 0ms && newTargetTime >= m_timerTargetTime)
return; // existing timer is good
qCDebug(lcEventDispatcherTimers)
- << "Created new native timer with wait" << toWaitDuration << "timeout" << newTargetTime;
+ << "Created new native timer with wait" << toWaitDuration.count() << "ms"
+ << "timeout" << newTargetTime.count() << "ms";
emscripten_clear_timeout(m_timerId);
- m_timerId = emscripten_set_timeout(&QEventDispatcherWasm::callProcessTimers, toWaitDuration, this);
+ m_timerId = emscripten_set_timeout(&QEventDispatcherWasm::callProcessTimers,
+ toWaitDuration.count(), this);
m_timerTargetTime = newTargetTime;
};
@@ -548,8 +658,8 @@ void QEventDispatcherWasm::updateNativeTimer()
// and keep the mutex locked while updating the native timer to
// prevent it from being deleted.
LOCK_GUARD(g_staticDataMutex);
- if (isValidEventDispatcherPointer(this))
- maintainNativeTimer();
+ if (isValidEventDispatcherPointer(this))
+ maintainNativeTimer();
});
}
@@ -565,7 +675,7 @@ void QEventDispatcherWasm::callProcessTimers(void *context)
// Process timers on this thread if this is the main event dispatcher
if (reinterpret_cast<QEventDispatcherWasm *>(context) == g_mainThreadEventDispatcher) {
- g_mainThreadEventDispatcher->m_timerTargetTime = 0;
+ g_mainThreadEventDispatcher->m_timerTargetTime = 0ms;
g_mainThreadEventDispatcher->processTimers();
return;
}
@@ -575,7 +685,7 @@ void QEventDispatcherWasm::callProcessTimers(void *context)
std::lock_guard<std::mutex> lock(g_staticDataMutex);
if (g_secondaryThreadEventDispatchers.contains(context)) {
QEventDispatcherWasm *eventDispatcher = reinterpret_cast<QEventDispatcherWasm *>(context);
- eventDispatcher->m_timerTargetTime = 0;
+ eventDispatcher->m_timerTargetTime = 0ms;
eventDispatcher->m_processTimers = true;
eventDispatcher->wakeUp();
}
@@ -792,6 +902,50 @@ void QEventDispatcherWasm::socketSelect(int timeout, int socket, bool waitForRea
}
namespace {
+ int g_startupTasks = 0;
+}
+
+// The following functions manages sending the "qtLoaded" event/callback
+// from qtloader.js on startup, once Qt initialization has been completed
+// and the application is ready to display the first frame. This can be
+// either as soon as the event loop is running, or later, if additional
+// startup tasks (e.g. local font loading) have been registered.
+
+void QEventDispatcherWasm::registerStartupTask()
+{
+ ++g_startupTasks;
+}
+
+void QEventDispatcherWasm::completeStarupTask()
+{
+ --g_startupTasks;
+ callOnLoadedIfRequired();
+}
+
+void QEventDispatcherWasm::callOnLoadedIfRequired()
+{
+ if (g_startupTasks > 0)
+ return;
+
+ static bool qtLoadedCalled = false;
+ if (qtLoadedCalled)
+ return;
+ qtLoadedCalled = true;
+
+ Q_ASSERT(g_mainThreadEventDispatcher);
+ g_mainThreadEventDispatcher->onLoaded();
+}
+
+void QEventDispatcherWasm::onLoaded()
+{
+ // TODO: call qtloader.js onLoaded from here, in order to delay
+ // hiding the "Loading..." message until the app is ready to paint
+ // the first frame. Currently onLoaded must be called early before
+ // main() in order to ensure that the screen/container elements
+ // have valid geometry at startup.
+}
+
+namespace {
void trampoline(void *context) {
auto async_fn = [](void *context){
@@ -810,26 +964,19 @@ void QEventDispatcherWasm::run(std::function<void(void)> fn)
fn();
}
-// Runs a function asynchronously. Main thread only.
-void QEventDispatcherWasm::runAsync(std::function<void(void)> fn)
-{
- trampoline(new std::function<void(void)>(fn));
-}
-
-// Runs a function on the main thread. The function runs synchronusly if
-// the calling thread is then main thread.
void QEventDispatcherWasm::runOnMainThread(std::function<void(void)> fn)
{
#if QT_CONFIG(thread)
- if (!emscripten_is_main_runtime_thread()) {
- void *context = new std::function<void(void)>(fn);
- g_proxyingQueue.proxyAsync(g_mainThread, [context]{
- trampoline(context);
- });
- return;
- }
+ qstdweb::runTaskOnMainThread<void>(fn, &g_proxyingQueue);
+#else
+ qstdweb::runTaskOnMainThread<void>(fn);
#endif
- fn();
+}
+
+// Runs a function asynchronously. Main thread only.
+void QEventDispatcherWasm::runAsync(std::function<void(void)> fn)
+{
+ trampoline(new std::function<void(void)>(fn));
}
// Runs a function on the main thread. The function always runs asynchronously,
@@ -849,3 +996,5 @@ void QEventDispatcherWasm::runOnMainThreadAsync(std::function<void(void)> fn)
}
QT_END_NAMESPACE
+
+#include "moc_qeventdispatcher_wasm_p.cpp"
diff --git a/src/corelib/kernel/qeventdispatcher_wasm_p.h b/src/corelib/kernel/qeventdispatcher_wasm_p.h
index f253a1a95f..7b257e02ad 100644
--- a/src/corelib/kernel/qeventdispatcher_wasm_p.h
+++ b/src/corelib/kernel/qeventdispatcher_wasm_p.h
@@ -20,6 +20,7 @@
#include <QtCore/qloggingcategory.h>
#include <QtCore/qwaitcondition.h>
+#include <chrono>
#include <mutex>
#include <optional>
#include <tuple>
@@ -31,7 +32,7 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcEventDispatcher);
Q_DECLARE_LOGGING_CATEGORY(lcEventDispatcherTimers)
-class Q_CORE_EXPORT QEventDispatcherWasm : public QAbstractEventDispatcher
+class Q_CORE_EXPORT QEventDispatcherWasm : public QAbstractEventDispatcherV2
{
Q_OBJECT
public:
@@ -43,19 +44,27 @@ public:
void registerSocketNotifier(QSocketNotifier *notifier) override;
void unregisterSocketNotifier(QSocketNotifier *notifier) override;
- void registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object) override;
- bool unregisterTimer(int timerId) override;
- bool unregisterTimers(QObject *object) override;
- QList<QAbstractEventDispatcher::TimerInfo> registeredTimers(QObject *object) const override;
- int remainingTime(int timerId) override;
+ void registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType,
+ QObject *object) override final;
+ bool unregisterTimer(Qt::TimerId timerId) override final;
+ bool unregisterTimers(QObject *object) override final;
+ QList<TimerInfoV2> timersForObject(QObject *object) const override final;
+ Duration remainingTime(Qt::TimerId timerId) const override final;
void interrupt() override;
void wakeUp() override;
+ static void runOnMainThread(std::function<void(void)> fn);
static void socketSelect(int timeout, int socket, bool waitForRead, bool waitForWrite,
bool *selectForRead, bool *selectForWrite, bool *socketDisconnect);
+
+ static void registerStartupTask();
+ static void completeStarupTask();
+ static void callOnLoadedIfRequired();
+ virtual void onLoaded();
+
protected:
- virtual void processWindowSystemEvents(QEventLoop::ProcessEventsFlags flags);
+ virtual bool processPostedEvents();
private:
bool isMainThreadEventDispatcher();
@@ -66,7 +75,7 @@ private:
void handleDialogExec();
bool wait(int timeout = -1);
bool wakeEventDispatcherThread();
- static void callProcessEvents(void *eventDispatcher);
+ static void callProcessPostedEvents(void *eventDispatcher);
void processTimers();
void updateNativeTimer();
@@ -88,7 +97,6 @@ private:
static void run(std::function<void(void)> fn);
static void runAsync(std::function<void(void)> fn);
- static void runOnMainThread(std::function<void(void)> fn);
static void runOnMainThreadAsync(std::function<void(void)> fn);
static QEventDispatcherWasm *g_mainThreadEventDispatcher;
@@ -99,7 +107,7 @@ private:
QTimerInfoList *m_timerInfo = new QTimerInfoList();
long m_timerId = 0;
- uint64_t m_timerTargetTime = 0;
+ std::chrono::milliseconds m_timerTargetTime{};
#if QT_CONFIG(thread)
std::mutex m_mutex;
diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp
index 1c54c97514..a7663b2481 100644
--- a/src/corelib/kernel/qeventdispatcher_win.cpp
+++ b/src/corelib/kernel/qeventdispatcher_win.cpp
@@ -7,7 +7,6 @@
#include "qcoreapplication.h"
#include <private/qsystemlibrary_p.h>
#include "qoperatingsystemversion.h"
-#include "qpair.h"
#include "qset.h"
#include "qsocketnotifier.h"
#include "qvarlengtharray.h"
@@ -56,6 +55,13 @@ class QEventDispatcherWin32Private;
LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);
+static quint64 qt_msectime()
+{
+ using namespace std::chrono;
+ auto t = duration_cast<milliseconds>(steady_clock::now().time_since_epoch());
+ return t.count();
+}
+
QEventDispatcherWin32Private::QEventDispatcherWin32Private()
: interrupt(false), internalHwnd(0),
sendPostedEventsTimerId(0), wakeUps(0),
@@ -129,7 +135,7 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
QSNDict *sn_vec[4] = { &d->sn_read, &d->sn_write, &d->sn_except, &d->sn_read };
QSNDict *dict = sn_vec[type];
- QSockNot *sn = dict ? dict->value(wp) : 0;
+ QSockNot *sn = dict ? dict->value(qintptr(wp)) : 0;
if (sn == nullptr) {
d->postActivateSocketNotifiers();
} else {
@@ -402,7 +408,7 @@ void QEventDispatcherWin32Private::sendTimerEvent(int timerId)
}
}
-void QEventDispatcherWin32Private::doWsaAsyncSelect(int socket, long event)
+void QEventDispatcherWin32Private::doWsaAsyncSelect(qintptr socket, long event)
{
Q_ASSERT(internalHwnd);
// BoundsChecker may emit a warning for WSAAsyncSelect when event == 0
@@ -551,7 +557,7 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
{
Q_ASSERT(notifier);
- int sockfd = notifier->socket();
+ qintptr sockfd = notifier->socket();
int type = notifier->type();
#ifndef QT_NO_DEBUG
if (sockfd < 0) {
@@ -575,7 +581,7 @@ void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)
const char *t[] = { "Read", "Write", "Exception" };
/* Variable "socket" below is a function pointer. */
qWarning("QSocketNotifier: Multiple socket notifiers for "
- "same socket %d and type %s", sockfd, t[type]);
+ "same socket %" PRIdQINTPTR " and type %s", sockfd, t[type]);
}
QSockNot *sn = new QSockNot;
@@ -619,7 +625,7 @@ void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier)
{
Q_ASSERT(notifier);
#ifndef QT_NO_DEBUG
- int sockfd = notifier->socket();
+ qintptr sockfd = notifier->socket();
if (sockfd < 0) {
qWarning("QEventDispatcherWin32::unregisterSocketNotifier: invalid socket identifier");
return;
@@ -636,7 +642,7 @@ void QEventDispatcherWin32::doUnregisterSocketNotifier(QSocketNotifier *notifier
{
Q_D(QEventDispatcherWin32);
int type = notifier->type();
- int sockfd = notifier->socket();
+ qintptr sockfd = notifier->socket();
Q_ASSERT(sockfd >= 0);
QSFDict::iterator it = d->active_fd.find(sockfd);
@@ -899,3 +905,5 @@ HWND QEventDispatcherWin32::internalHwnd()
}
QT_END_NAMESPACE
+
+#include "moc_qeventdispatcher_win_p.cpp"
diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h
index ecd4bcb27b..558490a85e 100644
--- a/src/corelib/kernel/qeventdispatcher_win_p.h
+++ b/src/corelib/kernel/qeventdispatcher_win_p.h
@@ -28,7 +28,6 @@ class QEventDispatcherWin32Private;
// forward declaration
LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);
-quint64 qt_msectime();
class Q_CORE_EXPORT QEventDispatcherWin32 : public QAbstractEventDispatcher
{
@@ -72,9 +71,9 @@ private:
struct QSockNot {
QSocketNotifier *obj;
- int fd;
+ qintptr fd;
};
-typedef QHash<int, QSockNot *> QSNDict;
+typedef QHash<qintptr, QSockNot *> QSNDict;
struct QSockFd {
long event;
@@ -83,7 +82,7 @@ struct QSockFd {
explicit inline QSockFd(long ev = 0, long ma = 0) : event(ev), mask(ma), selected(false) { }
};
-typedef QHash<int, QSockFd> QSFDict;
+typedef QHash<qintptr, QSockFd> QSFDict;
struct WinTimerInfo { // internal timer info
QObject *dispatcher;
@@ -136,7 +135,7 @@ public:
QSFDict active_fd;
bool activateNotifiersPosted;
void postActivateSocketNotifiers();
- void doWsaAsyncSelect(int socket, long event);
+ void doWsaAsyncSelect(qintptr socket, long event);
bool closingDown = false;
diff --git a/src/corelib/kernel/qeventloop.cpp b/src/corelib/kernel/qeventloop.cpp
index 7001bfa5bd..e314a17ff8 100644
--- a/src/corelib/kernel/qeventloop.cpp
+++ b/src/corelib/kernel/qeventloop.cpp
@@ -6,7 +6,7 @@
#include "qabstracteventdispatcher.h"
#include "qcoreapplication.h"
#include "qcoreapplication_p.h"
-#include "qelapsedtimer.h"
+#include "qdeadlinetimer.h"
#include "qobject_p.h"
#include "qeventloop_p.h"
@@ -116,10 +116,10 @@ bool QEventLoop::processEvents(ProcessEventsFlags flags)
can be used before calling exec(), because modal widgets
use their own local event loop.
- To make your application perform idle processing (i.e. executing a
- special function whenever there are no pending events), use a
- QTimer with 0 timeout. More sophisticated idle processing schemes
- can be achieved using processEvents().
+ To make your application perform idle processing (i.e. executing a special
+ function whenever there are no pending events), use a QChronoTimer with
+ 0ns timeout. More sophisticated idle processing schemes can be achieved
+ using processEvents().
\sa QCoreApplication::quit(), exit(), processEvents()
*/
@@ -151,6 +151,9 @@ int QEventLoop::exec(ProcessEventsFlags flags)
auto threadData = d->threadData.loadRelaxed();
++threadData->loopLevel;
threadData->eventLoops.push(d->q_func());
+ qCDebug(lcDeleteLater) << "Increased" << threadData->thread
+ << "loop level to" << threadData->loopLevel
+ << "with leaf loop now" << threadData->eventLoops.last();
locker.unlock();
}
@@ -169,6 +172,12 @@ int QEventLoop::exec(ProcessEventsFlags flags)
Q_UNUSED(eventLoop); // --release warning
d->inExec = false;
--threadData->loopLevel;
+
+ qCDebug(lcDeleteLater) << "Decreased" << threadData->thread
+ << "loop level to" << threadData->loopLevel
+ << "with leaf loop now" << (threadData->eventLoops.isEmpty()
+ ? nullptr : threadData->eventLoops.last());
+
}
};
LoopReference ref(d, locker);
@@ -186,9 +195,27 @@ int QEventLoop::exec(ProcessEventsFlags flags)
}
/*!
+ \overload
+
Process pending events that match \a flags for a maximum of \a
maxTime milliseconds, or until there are no more events to
process, whichever is shorter.
+
+ Equivalent to calling:
+ \code
+ processEvents(flags, QDeadlineTimer(maxTime));
+ \endcode
+*/
+void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime)
+{
+ processEvents(flags, QDeadlineTimer(maxTime));
+}
+
+/*!
+ \since 6.7
+
+ Process pending events that match \a flags until \a deadline has expired,
+ or until there are no more events to process, whichever happens first.
This function is especially useful if you have a long running
operation and want to show its progress without allowing user
input, i.e. by using the \l ExcludeUserInputEvents flag.
@@ -201,16 +228,14 @@ int QEventLoop::exec(ProcessEventsFlags flags)
and will be ignored.
\endlist
*/
-void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime)
+void QEventLoop::processEvents(ProcessEventsFlags flags, QDeadlineTimer deadline)
{
Q_D(QEventLoop);
if (!d->threadData.loadRelaxed()->hasEventDispatcher())
return;
- QElapsedTimer start;
- start.start();
while (processEvents(flags & ~WaitForMoreEvents)) {
- if (start.elapsed() > maxTime)
+ if (deadline.hasExpired())
break;
}
}
@@ -293,57 +318,10 @@ bool QEventLoop::event(QEvent *event)
void QEventLoop::quit()
{ exit(0); }
-
-class QEventLoopLockerPrivate
-{
-public:
- explicit QEventLoopLockerPrivate(QEventLoopPrivate *loop)
- : loop(loop), type(EventLoop)
- {
- loop->ref();
- }
-
- explicit QEventLoopLockerPrivate(QThreadPrivate *thread)
- : thread(thread), type(Thread)
- {
- thread->ref();
- }
-
- explicit QEventLoopLockerPrivate(QCoreApplicationPrivate *app)
- : app(app), type(Application)
- {
- app->ref();
- }
-
- ~QEventLoopLockerPrivate()
- {
- switch (type)
- {
- case EventLoop:
- loop->deref();
- break;
- case Thread:
- thread->deref();
- break;
- default:
- app->deref();
- break;
- }
- }
-
-private:
- union {
- QEventLoopPrivate * loop;
- QThreadPrivate * thread;
- QCoreApplicationPrivate * app;
- };
- enum Type {
- EventLoop,
- Thread,
- Application
- };
- const Type type;
-};
+// If any of these trigger, the Type bits will interfere with the pointer values:
+static_assert(alignof(QEventLoop) >= 4);
+static_assert(alignof(QThread) >= 4);
+static_assert(alignof(QCoreApplication) >= 4);
/*!
\class QEventLoopLocker
@@ -368,12 +346,16 @@ private:
/*!
Creates an event locker operating on the QCoreApplication.
- The application will quit when there are no more QEventLoopLockers operating on it.
+ The application will attempt to quit when there are no more QEventLoopLockers
+ operating on it, as long as QCoreApplication::isQuitLockEnabled() is \c true.
+
+ Note that attempting a quit may not necessarily result in the application quitting,
+ if there for example are open windows, or the QEvent::Quit event is ignored.
\sa QCoreApplication::quit(), QCoreApplication::isQuitLockEnabled()
*/
-QEventLoopLocker::QEventLoopLocker()
- : d_ptr(new QEventLoopLockerPrivate(static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(QCoreApplication::instance()))))
+QEventLoopLocker::QEventLoopLocker() noexcept
+ : QEventLoopLocker{QCoreApplication::instance(), Type::Application}
{
}
@@ -385,8 +367,8 @@ QEventLoopLocker::QEventLoopLocker()
\sa QEventLoop::quit()
*/
-QEventLoopLocker::QEventLoopLocker(QEventLoop *loop)
- : d_ptr(new QEventLoopLockerPrivate(static_cast<QEventLoopPrivate*>(QObjectPrivate::get(loop))))
+QEventLoopLocker::QEventLoopLocker(QEventLoop *loop) noexcept
+ : QEventLoopLocker{loop, Type::EventLoop}
{
}
@@ -398,18 +380,80 @@ QEventLoopLocker::QEventLoopLocker(QEventLoop *loop)
\sa QThread::quit()
*/
-QEventLoopLocker::QEventLoopLocker(QThread *thread)
- : d_ptr(new QEventLoopLockerPrivate(static_cast<QThreadPrivate*>(QObjectPrivate::get(thread))))
+QEventLoopLocker::QEventLoopLocker(QThread *thread) noexcept
+ : QEventLoopLocker{thread, Type::Thread}
{
}
/*!
+ \fn QEventLoopLocker::QEventLoopLocker(QEventLoopLocker &&other)
+ \since 6.7
+
+ Move-constructs an event-loop locker from \a other. \a other will have a
+ no-op destructor, while responsibility for preventing the
+ QEventLoop/QThread/QCoreApplication from quitting is transferred to the new
+ object.
+*/
+
+/*!
+ \fn QEventLoopLocker &QEventLoopLocker::operator=(QEventLoopLocker &&other)
+ \since 6.7
+
+ Move-assigns this event-loop locker from \a other. \a other will have a
+ no-op destructor, while responsibility for preventing the
+ QEventLoop/QThread/QCoreApplication from quitting is transferred to this
+ object.
+*/
+
+/*!
+ \fn QEventLoopLocker::swap(QEventLoopLocker &other)
+ \since 6.7
+
+ Swaps the object and the state of this QEventLoopLocker with \a other.
+ This operation is very fast and never fails.
+*/
+
+/*!
+ \fn QEventLoopLocker::swap(QEventLoopLocker &lhs, QEventLoopLocker &rhs)
+ \since 6.7
+
+ Swaps the object and the state of \a lhs with \a rhs.
+ This operation is very fast and never fails.
+*/
+
+/*!
Destroys this event loop locker object
*/
QEventLoopLocker::~QEventLoopLocker()
{
- delete d_ptr;
+ visit([](auto p) { p->d_func()->deref(); });
+}
+
+/*!
+ \internal
+*/
+QEventLoopLocker::QEventLoopLocker(void *ptr, Type t) noexcept
+ : p{quintptr(ptr) | quintptr(t)}
+{
+ visit([](auto p) { p->d_func()->ref(); });
+}
+
+/*!
+ \internal
+*/
+template <typename Func>
+void QEventLoopLocker::visit(Func f) const
+{
+ const auto ptr = pointer();
+ if (!ptr)
+ return;
+ switch (type()) {
+ case Type::EventLoop: return f(static_cast<QEventLoop *>(ptr));
+ case Type::Thread: return f(static_cast<QThread *>(ptr));
+ case Type::Application: return f(static_cast<QCoreApplication *>(ptr));
+ }
+ Q_UNREACHABLE();
}
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qeventloop.h b/src/corelib/kernel/qeventloop.h
index 1da1d2336e..ec79c07cd7 100644
--- a/src/corelib/kernel/qeventloop.h
+++ b/src/corelib/kernel/qeventloop.h
@@ -5,15 +5,18 @@
#define QEVENTLOOP_H
#include <QtCore/qobject.h>
+#include <QtCore/qdeadlinetimer.h>
QT_BEGIN_NAMESPACE
+class QEventLoopLocker;
class QEventLoopPrivate;
class Q_CORE_EXPORT QEventLoop : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QEventLoop)
+ friend class QEventLoopLocker;
public:
explicit QEventLoop(QObject *parent = nullptr);
@@ -34,6 +37,7 @@ public:
bool processEvents(ProcessEventsFlags flags = AllEvents);
void processEvents(ProcessEventsFlags flags, int maximumTime);
+ void processEvents(ProcessEventsFlags flags, QDeadlineTimer deadline);
int exec(ProcessEventsFlags flags = AllEvents);
bool isRunning() const;
@@ -51,17 +55,41 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QEventLoop::ProcessEventsFlags)
class QEventLoopLockerPrivate;
-class Q_CORE_EXPORT QEventLoopLocker
+class QEventLoopLocker
{
public:
- QEventLoopLocker();
- explicit QEventLoopLocker(QEventLoop *loop);
- explicit QEventLoopLocker(QThread *thread);
- ~QEventLoopLocker();
+ Q_NODISCARD_CTOR Q_CORE_EXPORT QEventLoopLocker() noexcept;
+ Q_NODISCARD_CTOR Q_CORE_EXPORT explicit QEventLoopLocker(QEventLoop *loop) noexcept;
+ Q_NODISCARD_CTOR Q_CORE_EXPORT explicit QEventLoopLocker(QThread *thread) noexcept;
+ Q_CORE_EXPORT ~QEventLoopLocker();
+
+ Q_NODISCARD_CTOR QEventLoopLocker(QEventLoopLocker &&other) noexcept
+ : p{std::exchange(other.p, 0)} {}
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QEventLoopLocker)
+
+ void swap(QEventLoopLocker &other) noexcept { std::swap(p, other.p); }
+ friend void swap(QEventLoopLocker &lhs, QEventLoopLocker &rhs) noexcept { lhs.swap(rhs); }
private:
Q_DISABLE_COPY(QEventLoopLocker)
- QEventLoopLockerPrivate *d_ptr;
+ friend class QEventLoopLockerPrivate;
+
+ //
+ // Private implementation details.
+ // Do not call from public inline API!
+ //
+ enum class Type : quintptr {
+ EventLoop,
+ Thread,
+ Application,
+ };
+ explicit QEventLoopLocker(void *ptr, Type t) noexcept;
+ quintptr p;
+ static constexpr quintptr TypeMask = 0x3;
+ Type type() const { return Type(p & TypeMask); }
+ void *pointer() const { return reinterpret_cast<void *>(p & ~TypeMask); }
+ template <typename Func>
+ void visit(Func func) const;
};
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qfunctions_p.h b/src/corelib/kernel/qfunctions_p.h
index f1ae1f3c9c..58afc207e6 100644
--- a/src/corelib/kernel/qfunctions_p.h
+++ b/src/corelib/kernel/qfunctions_p.h
@@ -17,9 +17,5 @@
#include <QtCore/private/qglobal_p.h>
-#if defined(Q_OS_VXWORKS)
-# include "QtCore/qfunctions_vxworks.h"
-#endif
-
#endif
diff --git a/src/corelib/kernel/qfunctions_vxworks.cpp b/src/corelib/kernel/qfunctions_vxworks.cpp
deleted file mode 100644
index 0ada99701c..0000000000
--- a/src/corelib/kernel/qfunctions_vxworks.cpp
+++ /dev/null
@@ -1,172 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include "qglobal.h"
-
-#ifdef Q_OS_VXWORKS
-
-#include "qplatformdefs.h"
-#include "qfunctions_vxworks.h"
-
-#if defined(_WRS_KERNEL)
-#include <vmLib.h>
-#endif
-#include <selectLib.h>
-#include <ioLib.h>
-
-QT_USE_NAMESPACE
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// no lfind() - used by the TIF image format
-void *lfind(const void* key, const void* base, size_t* elements, size_t size,
- int (*compare)(const void*, const void*))
-{
- const char* current = (char*) base;
- const char* const end = (char*) (current + (*elements) * size);
- while (current != end) {
- if (compare(current, key) == 0)
- return (void*)current;
- current += size;
- }
- return 0;
-}
-
-
-// no rand_r(), but rand()
-// NOTE: this implementation is wrong for multi threaded applications,
-// but there is no way to get it right on VxWorks (in kernel mode)
-#if defined(_WRS_KERNEL)
-int rand_r(unsigned int * /*seedp*/)
-{
- return rand();
-}
-#endif
-
-// no usleep() support
-int usleep(unsigned int usec)
-{
- div_t dt = div(usec, 1000000);
- struct timespec ts = { dt.quot, dt.rem * 1000 };
-
- return nanosleep(&ts, 0);
-}
-
-
-// gettimeofday() is declared, but is missing from the library
-// It IS however defined in the Curtis-Wright X11 libraries, so
-// we have to make the symbol 'weak'
-#if defined(Q_CC_DIAB) && !defined(VXWORKS_DKM) && !defined(VXWORKS_RTP)
-# pragma weak gettimeofday
-#endif
-int gettimeofday(struct timeval *tv, void /*struct timezone*/ *)
-{
- // the compiler will optimize this and will only use one code path
- if (sizeof(struct timeval) == sizeof(struct timespec)) {
- int res = clock_gettime(CLOCK_REALTIME, (struct timespec *) tv);
- if (!res)
- tv->tv_usec /= 1000;
- return res;
- } else {
- struct timespec ts;
-
- int res = clock_gettime(CLOCK_REALTIME, &ts);
- if (!res) {
- tv->tv_sec = ts.tv_sec;
- tv->tv_usec = ts.tv_nsec / 1000;
- }
- return res;
- }
-}
-
-// neither getpagesize() or sysconf(_SC_PAGESIZE) are available
-int getpagesize()
-{
-#if defined(_WRS_KERNEL)
- return vmPageSizeGet();
-#else
- return sysconf(_SC_PAGESIZE);
-#endif
-}
-
-// symlinks are not supported (lstat is now just a call to stat - see qplatformdefs.h)
-int symlink(const char *, const char *)
-{
- errno = EIO;
- return -1;
-}
-
-ssize_t readlink(const char *, char *, size_t)
-{
- errno = EIO;
- return -1;
-}
-
-// there's no truncate(), but ftruncate() support...
-int truncate(const char *path, off_t length)
-{
- int fd = open(path, O_WRONLY, 00777);
- if (fd >= 0) {
- int res = ftruncate(fd, length);
- int en = errno;
- close(fd);
- errno = en;
- return res;
- }
- // errno is already set by open
- return -1;
-}
-
-
-
-// VxWorks doesn't know about passwd & friends.
-// in order to avoid patching the unix fs path everywhere
-// we introduce some dummy functions that simulate a single
-// 'root' user on the system.
-
-uid_t getuid()
-{
- return 0;
-}
-
-gid_t getgid()
-{
- return 0;
-}
-
-uid_t geteuid()
-{
- return 0;
-}
-
-struct passwd *getpwuid(uid_t uid)
-{
- static struct passwd pwbuf = { "root", 0, 0, 0, 0, 0, 0 };
-
- if (uid == 0) {
- return &pwbuf;
- } else {
- errno = ENOENT;
- return 0;
- }
-}
-
-struct group *getgrgid(gid_t gid)
-{
- static struct group grbuf = { "root", 0, 0, 0 };
-
- if (gid == 0) {
- return &grbuf;
- } else {
- errno = ENOENT;
- return 0;
- }
-}
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // Q_OS_VXWORKS
diff --git a/src/corelib/kernel/qfunctions_vxworks.h b/src/corelib/kernel/qfunctions_vxworks.h
deleted file mode 100644
index 26006bd564..0000000000
--- a/src/corelib/kernel/qfunctions_vxworks.h
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QFUNCTIONS_VXWORKS_H
-#define QFUNCTIONS_VXWORKS_H
-
-#include <QtCore/qglobal.h>
-
-#ifdef Q_OS_VXWORKS
-
-#include <unistd.h>
-#include <pthread.h>
-#include <dirent.h>
-#include <signal.h>
-#include <string.h>
-#include <strings.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#if defined(_WRS_KERNEL)
-#include <sys/times.h>
-#else
-#include <sys/time.h>
-#endif
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <netinet/in.h>
-
-// VxWorks has public header mbuf.h which defines following variables for DKM.
-// Let's undef those to because they overlap with Qt variable names-
-// File mbuf.h is included in headers <netinet/in.h> <net/if.h>, so make sure
-// that those are included before undef's.
-#if defined(mbuf)
-# undef mbuf
-#endif
-#if defined(m_data)
-# undef m_data
-#endif
-#if defined(m_type)
-# undef m_type
-#endif
-#if defined(m_next)
-# undef m_next
-#endif
-#if defined(m_len)
-# undef m_len
-#endif
-#if defined(m_flags)
-# undef m_flags
-#endif
-#if defined(m_hdr)
-# undef m_hdr
-#endif
-#if defined(m_ext)
-# undef m_ext
-#endif
-#if defined(m_act)
-# undef m_act
-#endif
-#if defined(m_nextpkt)
-# undef m_nextpkt
-#endif
-#if defined(m_pkthdr)
-# undef m_pkthdr
-#endif
-
-QT_BEGIN_NAMESPACE
-
-#ifdef QT_BUILD_CORE_LIB
-#endif
-
-QT_END_NAMESPACE
-
-#ifndef RTLD_LOCAL
-#define RTLD_LOCAL 0
-#endif
-
-#ifndef NSIG
-#define NSIG _NSIGS
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// isascii is missing (sometimes!!)
-#ifndef isascii
-inline int isascii(int c) { return (c & 0x7f); }
-#endif
-
-// no lfind() - used by the TIF image format
-void *lfind(const void* key, const void* base, size_t* elements, size_t size,
- int (*compare)(const void*, const void*));
-
-// no rand_r(), but rand()
-// NOTE: this implementation is wrong for multi threaded applications,
-// but there is no way to get it right on VxWorks (in kernel mode)
-#if defined(_WRS_KERNEL)
-int rand_r(unsigned int * /*seedp*/);
-#endif
-
-// no usleep() support
-int usleep(unsigned int);
-
-#if defined(VXWORKS_DKM) || defined(VXWORKS_RTP)
-int gettimeofday(struct timeval *, void *);
-#else
-// gettimeofday() is declared, but is missing from the library.
-// It IS however defined in the Curtis-Wright X11 libraries, so
-// we have to make the symbol 'weak'
-int gettimeofday(struct timeval *tv, void /*struct timezone*/ *) __attribute__((weak));
-#endif
-
-// getpagesize() not available
-int getpagesize();
-
-// symlinks are not supported (lstat is now just a call to stat - see qplatformdefs.h)
-int symlink(const char *, const char *);
-ssize_t readlink(const char *, char *, size_t);
-
-// there's no truncate(), but ftruncate() support...
-int truncate(const char *path, off_t length);
-
-// VxWorks doesn't know about passwd & friends.
-// in order to avoid patching the unix fs path everywhere
-// we introduce some dummy functions that simulate a single
-// 'root' user on the system.
-
-uid_t getuid();
-gid_t getgid();
-uid_t geteuid();
-
-struct passwd {
- char *pw_name; /* user name */
- char *pw_passwd; /* user password */
- uid_t pw_uid; /* user ID */
- gid_t pw_gid; /* group ID */
- char *pw_gecos; /* real name */
- char *pw_dir; /* home directory */
- char *pw_shell; /* shell program */
-};
-
-struct group {
- char *gr_name; /* group name */
- char *gr_passwd; /* group password */
- gid_t gr_gid; /* group ID */
- char **gr_mem; /* group members */
-};
-
-struct passwd *getpwuid(uid_t uid);
-struct group *getgrgid(gid_t gid);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif // Q_OS_VXWORKS
-#endif // QFUNCTIONS_VXWORKS_H
diff --git a/src/corelib/kernel/qfunctions_win.cpp b/src/corelib/kernel/qfunctions_win.cpp
index ed0e25467c..048fdbc934 100644
--- a/src/corelib/kernel/qfunctions_win.cpp
+++ b/src/corelib/kernel/qfunctions_win.cpp
@@ -28,11 +28,13 @@ QComHelper::QComHelper(COINIT concurrencyModel)
QComHelper::~QComHelper()
{
+ Q_ASSERT(m_threadId == GetCurrentThreadId());
if (SUCCEEDED(m_initResult))
CoUninitialize();
}
/*!
+ \internal
Checks if the application has a \e{package identity}
Having a \e{package identity} is required to use many modern
diff --git a/src/corelib/kernel/qfunctions_win_p.h b/src/corelib/kernel/qfunctions_win_p.h
index 540405bd2f..ab5417f8a2 100644
--- a/src/corelib/kernel/qfunctions_win_p.h
+++ b/src/corelib/kernel/qfunctions_win_p.h
@@ -39,6 +39,7 @@ public:
private:
HRESULT m_initResult = E_FAIL;
+ DWORD m_threadId{ GetCurrentThreadId() };
};
Q_CORE_EXPORT bool qt_win_hasPackageIdentity();
diff --git a/src/corelib/kernel/qiterable.cpp b/src/corelib/kernel/qiterable.cpp
index 80715b2347..a8c93fbc1c 100644
--- a/src/corelib/kernel/qiterable.cpp
+++ b/src/corelib/kernel/qiterable.cpp
@@ -240,6 +240,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn template<class Container> qsizetype QIterator<Container>::operator-(const QIterator<Container> &j) const
+ \overload
Returns the distance between the two iterators.
@@ -377,6 +378,8 @@ QT_BEGIN_NAMESPACE
/*!
\fn template <class Container> qsizetype QConstIterator<Container>::operator-(const QConstIterator<Container> &j) const
+ \overload
+
Returns the distance between the two iterators.
\sa operator+(), operator-=(), QIterable::canReverseIterate()
diff --git a/src/corelib/kernel/qiterable.h b/src/corelib/kernel/qiterable.h
index 11bf82dc04..4adcdfd76f 100644
--- a/src/corelib/kernel/qiterable.h
+++ b/src/corelib/kernel/qiterable.h
@@ -19,16 +19,16 @@ namespace QtPrivate {
QTaggedPointer<Storage, Tag> m_pointer;
public:
- QConstPreservingPointer(std::nullptr_t) : m_pointer(nullptr, Const) {}
+ Q_NODISCARD_CTOR QConstPreservingPointer(std::nullptr_t) : m_pointer(nullptr, Const) {}
- QConstPreservingPointer(const void *pointer, qsizetype alignment)
+ Q_NODISCARD_CTOR QConstPreservingPointer(const void *pointer, qsizetype alignment)
: m_pointer(reinterpret_cast<Storage *>(const_cast<void *>(pointer)), Const)
{
Q_UNUSED(alignment);
Q_ASSERT(alignment > qsizetype(alignof(Storage)));
}
- QConstPreservingPointer(void *pointer, qsizetype alignment)
+ Q_NODISCARD_CTOR QConstPreservingPointer(void *pointer, qsizetype alignment)
: m_pointer(reinterpret_cast<Storage *>(pointer), Mutable)
{
Q_UNUSED(alignment);
@@ -36,20 +36,20 @@ namespace QtPrivate {
}
template<typename InputType>
- QConstPreservingPointer(const InputType *pointer)
+ Q_NODISCARD_CTOR QConstPreservingPointer(const InputType *pointer)
: m_pointer(reinterpret_cast<Storage *>(const_cast<InputType *>(pointer)), Const)
{
static_assert(alignof(InputType) >= alignof(Storage));
}
template<typename InputType>
- QConstPreservingPointer(InputType *pointer)
+ Q_NODISCARD_CTOR QConstPreservingPointer(InputType *pointer)
: m_pointer(reinterpret_cast<Storage *>(pointer), Mutable)
{
static_assert(alignof(InputType) >= alignof(Storage));
}
- QConstPreservingPointer() = default;
+ Q_NODISCARD_CTOR QConstPreservingPointer() = default;
const Type *constPointer() const
{
@@ -71,28 +71,32 @@ public:
QTaggedIterator(Iterator &&it) : Iterator(std::move(it))
{
const QMetaContainer metaContainer = this->metaContainer();
- if (std::is_base_of_v<std::random_access_iterator_tag, IteratorCategory>
- && !metaContainer.hasRandomAccessIterator()) {
- qFatal("You cannot use this iterator as a random access iterator");
- this->clearIterator();
+ if constexpr (std::is_base_of_v<std::random_access_iterator_tag, IteratorCategory>) {
+ if (!metaContainer.hasRandomAccessIterator()) {
+ qFatal("You cannot use this iterator as a random access iterator");
+ this->clearIterator();
+ }
}
- if (std::is_base_of_v<std::bidirectional_iterator_tag, IteratorCategory>
- && !metaContainer.hasBidirectionalIterator()) {
- qFatal("You cannot use this iterator as a bidirectional iterator");
- this->clearIterator();
+ if constexpr (std::is_base_of_v<std::bidirectional_iterator_tag, IteratorCategory>) {
+ if (!metaContainer.hasBidirectionalIterator()) {
+ qFatal("You cannot use this iterator as a bidirectional iterator");
+ this->clearIterator();
+ }
}
- if (std::is_base_of_v<std::forward_iterator_tag, IteratorCategory>
- && !metaContainer.hasForwardIterator()) {
- qFatal("You cannot use this iterator as a forward iterator");
- this->clearIterator();
+ if constexpr (std::is_base_of_v<std::forward_iterator_tag, IteratorCategory>) {
+ if (!metaContainer.hasForwardIterator()) {
+ qFatal("You cannot use this iterator as a forward iterator");
+ this->clearIterator();
+ }
}
- if (std::is_base_of_v<std::input_iterator_tag, IteratorCategory>
- && !metaContainer.hasInputIterator()) {
- qFatal("You cannot use this iterator as an input iterator");
- this->clearIterator();
+ if constexpr (std::is_base_of_v<std::input_iterator_tag, IteratorCategory>) {
+ if (!metaContainer.hasInputIterator()) {
+ qFatal("You cannot use this iterator as an input iterator");
+ this->clearIterator();
+ }
}
}
diff --git a/src/corelib/kernel/qjniarray.h b/src/corelib/kernel/qjniarray.h
new file mode 100644
index 0000000000..976b4e92e3
--- /dev/null
+++ b/src/corelib/kernel/qjniarray.h
@@ -0,0 +1,464 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QJNIARRAY_H
+#define QJNIARRAY_H
+
+#include <QtCore/qlist.h>
+
+#if defined(Q_QDOC) || defined(Q_OS_ANDROID)
+#include <QtCore/qbytearray.h>
+#include <QtCore/qjniobject.h>
+
+#include <iterator>
+#include <utility>
+#include <QtCore/q20type_traits.h>
+
+QT_BEGIN_NAMESPACE
+
+template <typename T> class QJniArray;
+template <typename T>
+struct QJniArrayIterator
+{
+ QJniArrayIterator() = default;
+
+ constexpr QJniArrayIterator(const QJniArrayIterator &other) noexcept = default;
+ constexpr QJniArrayIterator(QJniArrayIterator &&other) noexcept = default;
+ constexpr QJniArrayIterator &operator=(const QJniArrayIterator &other) noexcept = default;
+ constexpr QJniArrayIterator &operator=(QJniArrayIterator &&other) noexcept = default;
+
+ using difference_type = jsize;
+ using value_type = T;
+ using pointer = T *;
+ using reference = T; // difference to container requirements
+ using const_reference = reference;
+ using iterator_category = std::bidirectional_iterator_tag;
+
+ friend bool operator==(const QJniArrayIterator &lhs, const QJniArrayIterator &rhs) noexcept
+ {
+ return lhs.m_array == rhs.m_array && lhs.m_index == rhs.m_index;
+ }
+ friend bool operator!=(const QJniArrayIterator &lhs, const QJniArrayIterator &rhs) noexcept
+ {
+ return !(lhs == rhs);
+ }
+ const_reference operator*() const
+ {
+ return m_array->at(m_index);
+ }
+ friend QJniArrayIterator &operator++(QJniArrayIterator &that) noexcept
+ {
+ ++that.m_index;
+ return that;
+ }
+ friend QJniArrayIterator operator++(QJniArrayIterator &that, int) noexcept
+ {
+ auto copy = that;
+ ++that;
+ return copy;
+ }
+ friend QJniArrayIterator &operator--(QJniArrayIterator &that) noexcept
+ {
+ --that.m_index;
+ return that;
+ }
+ friend QJniArrayIterator operator--(QJniArrayIterator &that, int) noexcept
+ {
+ auto copy = that;
+ --that;
+ return copy;
+ }
+ void swap(QJniArrayIterator &other) noexcept
+ {
+ std::swap(m_index, other.m_index);
+ qt_ptr_swap(m_array, other.m_array);
+ }
+
+private:
+ using VT = std::remove_const_t<T>;
+ friend class QJniArray<VT>;
+
+ qsizetype m_index = 0;
+ const QJniArray<VT> *m_array = nullptr;
+
+ QJniArrayIterator(qsizetype index, const QJniArray<VT> *array)
+ : m_index(index), m_array(array)
+ {}
+};
+
+class QJniArrayBase
+{
+ // for SFINAE'ing out the fromContainer named constructor
+ template <typename Container, typename = void> struct CanConvertHelper : std::false_type {};
+ template <typename Container>
+ struct CanConvertHelper<Container, std::void_t<decltype(std::data(std::declval<Container>())),
+ decltype(std::size(std::declval<Container>())),
+ typename Container::value_type
+ >
+ > : std::true_type {};
+
+public:
+ using size_type = jsize;
+ using difference_type = size_type;
+
+ operator QJniObject() const { return m_object; }
+
+ template <typename T = jobject>
+ T object() const { return m_object.object<T>(); }
+ bool isValid() const { return m_object.isValid(); }
+
+ size_type size() const
+ {
+ if (jarray array = m_object.object<jarray>())
+ return jniEnv()->GetArrayLength(array);
+ return 0;
+ }
+
+ template <typename Container>
+ static constexpr bool canConvert = CanConvertHelper<q20::remove_cvref_t<Container>>::value;
+ template <typename Container>
+ using IfCanConvert = std::enable_if_t<canConvert<Container>, bool>;
+ template <typename Container
+ , IfCanConvert<Container> = true
+ >
+ static auto fromContainer(Container &&container)
+ {
+ Q_ASSERT_X(size_t(std::size(container)) <= size_t((std::numeric_limits<size_type>::max)()),
+ "QJniArray::fromContainer", "Container is too large for a Java array");
+
+ using ElementType = typename std::remove_reference_t<Container>::value_type;
+ if constexpr (std::disjunction_v<std::is_same<ElementType, jobject>,
+ std::is_same<ElementType, QJniObject>,
+ std::is_same<ElementType, QString>,
+ std::is_base_of<QtJniTypes::JObjectBase, ElementType>
+ >) {
+ return makeObjectArray(std::forward<Container>(container));
+ } else if constexpr (std::is_same_v<ElementType, jfloat>) {
+ return makeArray<jfloat>(std::forward<Container>(container), &JNIEnv::NewFloatArray,
+ &JNIEnv::SetFloatArrayRegion);
+ } else if constexpr (std::is_same_v<ElementType, jdouble>) {
+ return makeArray<jdouble>(std::forward<Container>(container), &JNIEnv::NewDoubleArray,
+ &JNIEnv::SetDoubleArrayRegion);
+ } else if constexpr (std::disjunction_v<std::is_same<ElementType, jboolean>,
+ std::is_same<ElementType, bool>>) {
+ return makeArray<jboolean>(std::forward<Container>(container), &JNIEnv::NewBooleanArray,
+ &JNIEnv::SetBooleanArrayRegion);
+ } else if constexpr (std::disjunction_v<std::is_same<ElementType, jbyte>,
+ std::is_same<ElementType, char>>) {
+ return makeArray<jbyte>(std::forward<Container>(container), &JNIEnv::NewByteArray,
+ &JNIEnv::SetByteArrayRegion);
+ } else if constexpr (std::disjunction_v<std::is_same<ElementType, jchar>,
+ std::is_same<ElementType, QChar>>) {
+ return makeArray<jchar>(std::forward<Container>(container), &JNIEnv::NewCharArray,
+ &JNIEnv::SetCharArrayRegion);
+ } else if constexpr (std::is_same_v<ElementType, jshort>
+ || sizeof(ElementType) == sizeof(jshort)) {
+ return makeArray<jshort>(std::forward<Container>(container), &JNIEnv::NewShortArray,
+ &JNIEnv::SetShortArrayRegion);
+ } else if constexpr (std::is_same_v<ElementType, jint>
+ || sizeof(ElementType) == sizeof(jint)) {
+ return makeArray<jint>(std::forward<Container>(container), &JNIEnv::NewIntArray,
+ &JNIEnv::SetIntArrayRegion);
+ } else if constexpr (std::is_same_v<ElementType, jlong>
+ || sizeof(ElementType) == sizeof(jlong)) {
+ return makeArray<jlong>(std::forward<Container>(container), &JNIEnv::NewLongArray,
+ &JNIEnv::SetLongArrayRegion);
+ }
+ }
+
+protected:
+ QJniArrayBase() = default;
+ ~QJniArrayBase() = default;
+
+ explicit QJniArrayBase(jarray array)
+ : m_object(static_cast<jobject>(array))
+ {
+ }
+ explicit QJniArrayBase(const QJniObject &object)
+ : m_object(object)
+ {}
+ explicit QJniArrayBase(QJniObject &&object) noexcept
+ : m_object(std::move(object))
+ {}
+
+ JNIEnv *jniEnv() const noexcept { return QJniEnvironment::getJniEnv(); }
+
+ template <typename ElementType, typename List, typename NewFn, typename SetFn>
+ static auto makeArray(List &&list, NewFn &&newArray, SetFn &&setRegion);
+ template <typename List>
+ static auto makeObjectArray(List &&list);
+
+private:
+ QJniObject m_object;
+};
+
+template <typename T>
+class QJniArray : public QJniArrayBase
+{
+ friend struct QJniArrayIterator<T>;
+public:
+ using Type = T;
+
+ using value_type = T;
+ using reference = T;
+ using const_reference = const reference;
+
+ // read-only container, so no iterator typedef
+ using const_iterator = QJniArrayIterator<const T>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ QJniArray() = default;
+ explicit QJniArray(jarray array) : QJniArrayBase(array) {}
+ explicit QJniArray(const QJniObject &object) : QJniArrayBase(object) {}
+ explicit QJniArray(QJniObject &&object) noexcept : QJniArrayBase(std::move(object)) {}
+
+ // base class destructor is protected, so need to provide all SMFs
+ QJniArray(const QJniArray &other) = default;
+ QJniArray(QJniArray &&other) noexcept = default;
+ QJniArray &operator=(const QJniArray &other) = default;
+ QJniArray &operator=(QJniArray &&other) noexcept = default;
+
+ template <typename Container
+ , IfCanConvert<Container> = true
+ >
+ explicit QJniArray(Container &&container)
+ : QJniArrayBase(QJniArrayBase::fromContainer(std::forward<Container>(container)))
+ {
+ }
+
+ template <typename E = T
+ , IfCanConvert<std::initializer_list<E>> = true
+ >
+ Q_IMPLICIT inline QJniArray(std::initializer_list<T> list)
+ : QJniArrayBase(QJniArrayBase::fromContainer(list))
+ {
+ }
+
+ template <typename Other, std::enable_if_t<std::is_convertible_v<Other, Type>, bool> = true>
+ QJniArray(QJniArray<Other> &&other)
+ : QJniArrayBase(std::forward<QJniArray<Other>>(other))
+ {
+ }
+ ~QJniArray() = default;
+
+ auto arrayObject() const
+ {
+ if constexpr (std::is_convertible_v<jobject, T>)
+ return object<jobjectArray>();
+ else if constexpr (std::is_same_v<T, jbyte>)
+ return object<jbyteArray>();
+ else if constexpr (std::is_same_v<T, jchar>)
+ return object<jcharArray>();
+ else if constexpr (std::is_same_v<T, jboolean>)
+ return object<jbooleanArray>();
+ else if constexpr (std::is_same_v<T, jshort>)
+ return object<jshortArray>();
+ else if constexpr (std::is_same_v<T, jint>)
+ return object<jintArray>();
+ else if constexpr (std::is_same_v<T, jlong>)
+ return object<jlongArray>();
+ else if constexpr (std::is_same_v<T, jfloat>)
+ return object<jfloatArray>();
+ else if constexpr (std::is_same_v<T, jdouble>)
+ return object<jdoubleArray>();
+ else
+ return object<jarray>();
+ }
+
+ const_iterator begin() const noexcept { return {0, this}; }
+ const_iterator constBegin() const noexcept { return begin(); }
+ const_iterator cbegin() const noexcept { return begin(); }
+ const_iterator end() const noexcept { return {size(), this}; }
+ const_iterator constEnd() const noexcept { return {end()}; }
+ const_iterator cend() const noexcept { return {end()}; }
+
+ const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
+ const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
+ const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); }
+ const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); }
+
+ const_reference operator[](size_type i) const { return at(i); }
+ const_reference at(size_type i) const
+ {
+ JNIEnv *env = jniEnv();
+ if constexpr (std::is_convertible_v<jobject, T>) {
+ jobject element = env->GetObjectArrayElement(object<jobjectArray>(), i);
+ if constexpr (std::is_base_of_v<QJniObject, T>)
+ return QJniObject::fromLocalRef(element);
+ else if constexpr (std::is_base_of_v<QtJniTypes::JObjectBase, T>)
+ return T::fromLocalRef(element);
+ else
+ return T{element};
+ } else if constexpr (std::is_base_of_v<std::remove_pointer_t<jobject>, std::remove_pointer_t<T>>) {
+ // jstring, jclass etc
+ return static_cast<T>(env->GetObjectArrayElement(object<jobjectArray>(), i));
+ } else {
+ T res = {};
+ if constexpr (std::is_same_v<T, jbyte>)
+ env->GetByteArrayRegion(object<jbyteArray>(), i, 1, &res);
+ else if constexpr (std::is_same_v<T, jchar>)
+ env->GetCharArrayRegion(object<jcharArray>(), i, 1, &res);
+ else if constexpr (std::is_same_v<T, jboolean>)
+ env->GetBooleanArrayRegion(object<jbooleanArray>(), i, 1, &res);
+ else if constexpr (std::is_same_v<T, jshort>)
+ env->GetShortArrayRegion(object<jshortArray>(), i, 1, &res);
+ else if constexpr (std::is_same_v<T, jint>)
+ env->GetIntArrayRegion(object<jbyteArray>(), i, 1, &res);
+ else if constexpr (std::is_same_v<T, jlong>)
+ env->GetLongArrayRegion(object<jlongArray>(), i, 1, &res);
+ else if constexpr (std::is_same_v<T, jfloat>)
+ env->GetFloatArrayRegion(object<jfloatArray>(), i, 1, &res);
+ else if constexpr (std::is_same_v<T, jdouble>)
+ env->GetDoubleArrayRegion(object<jdoubleArray>(), i, 1, &res);
+ return res;
+ }
+ }
+ auto toContainer() const
+ {
+ JNIEnv *env = jniEnv();
+ if constexpr (std::is_same_v<T, jobject>) {
+ QList<jobject> res;
+ res.reserve(size());
+ for (auto element : *this)
+ res.append(element);
+ return res;
+ } else if constexpr (std::is_same_v<T, jstring>) {
+ QStringList res;
+ res.reserve(size());
+ for (auto element : *this)
+ res.append(QJniObject(element).toString());
+ return res;
+ } else if constexpr (std::is_same_v<T, jbyte>) {
+ const qsizetype bytecount = size();
+ QByteArray res(bytecount, Qt::Initialization::Uninitialized);
+ env->GetByteArrayRegion(object<jbyteArray>(),
+ 0, bytecount, reinterpret_cast<jbyte *>(res.data()));
+ return res;
+ } else {
+ QList<T> res;
+ res.resize(size());
+ if constexpr (std::is_same_v<T, jchar>) {
+ env->GetCharArrayRegion(object<jcharArray>(),
+ 0, res.size(), res.data());
+ } else if constexpr (std::is_same_v<T, jboolean>) {
+ env->GetBooleanArrayRegion(object<jbooleanArray>(),
+ 0, res.size(), res.data());
+ } else if constexpr (std::is_same_v<T, jshort>) {
+ env->GetShortArrayRegion(object<jshortArray>(),
+ 0, res.size(), res.data());
+ } else if constexpr (std::is_same_v<T, jint>) {
+ env->GetIntArrayRegion(object<jintArray>(),
+ 0, res.size(), res.data());
+ } else if constexpr (std::is_same_v<T, jlong>) {
+ env->GetLongArrayRegion(object<jlongArray>(),
+ 0, res.size(), res.data());
+ } else if constexpr (std::is_same_v<T, jfloat>) {
+ env->GetFloatArrayRegion(object<jfloatArray>(),
+ 0, res.size(), res.data());
+ } else if constexpr (std::is_same_v<T, jdouble>) {
+ env->GetDoubleArrayRegion(object<jdoubleArray>(),
+ 0, res.size(), res.data());
+ } else {
+ res.clear();
+ }
+ return res;
+ }
+ }
+};
+
+template <typename ElementType, typename List, typename NewFn, typename SetFn>
+auto QJniArrayBase::makeArray(List &&list, NewFn &&newArray, SetFn &&setRegion)
+{
+ const size_type length = size_type(std::size(list));
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ auto localArray = (env->*newArray)(length);
+ if (QJniEnvironment::checkAndClearExceptions(env))
+ return QJniArray<ElementType>();
+
+ // can't use static_cast here because we have signed/unsigned mismatches
+ if (length) {
+ (env->*setRegion)(localArray, 0, length,
+ reinterpret_cast<const ElementType *>(std::data(std::as_const(list))));
+ }
+ return QJniArray<ElementType>(localArray);
+};
+
+template <typename List>
+auto QJniArrayBase::makeObjectArray(List &&list)
+{
+ using ElementType = typename q20::remove_cvref_t<List>::value_type;
+ using ResultType = QJniArray<decltype(std::declval<QJniObject::LocalFrame<>>().convertToJni(
+ std::declval<ElementType>()))
+ >;
+
+ if (std::size(list) == 0)
+ return ResultType();
+
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ const size_type length = size_type(std::size(list));
+
+ // this assumes that all objects in the list have the same class
+ jclass elementClass = nullptr;
+ if constexpr (std::disjunction_v<std::is_same<ElementType, QJniObject>,
+ std::is_base_of<QtJniTypes::JObjectBase, ElementType>>) {
+ elementClass = std::begin(list)->objectClass();
+ } else if constexpr (std::is_same_v<ElementType, QString>) {
+ elementClass = env->FindClass("java/lang/String");
+ } else {
+ elementClass = env->GetObjectClass(*std::begin(list));
+ }
+ auto localArray = env->NewObjectArray(length, elementClass, nullptr);
+ if (QJniEnvironment::checkAndClearExceptions(env))
+ return ResultType();
+
+ // explicitly manage the frame for local references in chunks of 100
+ QJniObject::LocalFrame frame(env);
+ constexpr jint frameCapacity = 100;
+ qsizetype i = 0;
+ for (const auto &element : std::as_const(list)) {
+ if (i % frameCapacity == 0) {
+ if (i)
+ env->PopLocalFrame(nullptr);
+ if (env->PushLocalFrame(frameCapacity) != 0)
+ return ResultType{};
+ }
+ jobject object = frame.convertToJni(element);
+ env->SetObjectArrayElement(localArray, i, object);
+ ++i;
+ }
+ if (i)
+ env->PopLocalFrame(nullptr);
+ return ResultType(localArray);
+}
+
+namespace QtJniTypes
+{
+template <typename T> struct IsJniArray: std::false_type {};
+template <typename T> struct IsJniArray<QJniArray<T>> : std::true_type {};
+template <typename T> struct Traits<QJniArray<T>> {
+ template <IfValidFieldType<T> = true>
+ static constexpr auto signature()
+ {
+ return CTString("[") + Traits<T>::signature();
+ }
+};
+template <typename T> struct Traits<QList<T>> {
+ template <IfValidFieldType<T> = true>
+ static constexpr auto signature()
+ {
+ return CTString("[") + Traits<T>::signature();
+ }
+};
+template <> struct Traits<QByteArray> {
+ static constexpr auto signature()
+ {
+ return CTString("[B");
+ }
+};
+}
+
+QT_END_NAMESPACE
+
+#endif
+
+#endif // QJNIARRAY_H
diff --git a/src/corelib/kernel/qjnienvironment.cpp b/src/corelib/kernel/qjnienvironment.cpp
index 7fda44a21e..1e2826e76b 100644
--- a/src/corelib/kernel/qjnienvironment.cpp
+++ b/src/corelib/kernel/qjnienvironment.cpp
@@ -29,8 +29,6 @@ QT_BEGIN_NAMESPACE
It has not been tested for other platforms.
*/
-static const char qJniThreadName[] = "QtThread";
-
class QJniEnvironmentPrivate
{
public:
@@ -46,47 +44,42 @@ public:
}
};
-struct QJniLocalRefDeleterPrivate
-{
- static void cleanup(jobject obj)
- {
- if (!obj)
- return;
-
- QJniEnvironment env;
- env->DeleteLocalRef(obj);
- }
-};
-
-// To simplify this we only define it for jobjects.
-typedef QScopedPointer<_jobject, QJniLocalRefDeleterPrivate> QJniScopedLocalRefPrivate;
-
-
Q_GLOBAL_STATIC(QThreadStorage<QJniEnvironmentPrivateTLS *>, jniEnvTLS)
-
/*!
- \fn QJniEnvironment::QJniEnvironment()
-
Constructs a new JNI Environment object and attaches the current thread to the Java VM.
*/
QJniEnvironment::QJniEnvironment()
: d(new QJniEnvironmentPrivate{})
{
+ d->jniEnv = getJniEnv();
+}
+
+/*!
+ Returns the JNIEnv pointer for the current thread.
+
+ The current thread will be attached to the Java VM.
+*/
+JNIEnv *QJniEnvironment::getJniEnv()
+{
+ JNIEnv *jniEnv = nullptr;
+
JavaVM *vm = QtAndroidPrivate::javaVM();
- const jint ret = vm->GetEnv((void**)&d->jniEnv, JNI_VERSION_1_6);
- if (ret == JNI_OK) // Already attached
- return;
+ const jint ret = vm->GetEnv((void**)&jniEnv, JNI_VERSION_1_6);
if (ret == JNI_EDETACHED) { // We need to (re-)attach
- JavaVMAttachArgs args = { JNI_VERSION_1_6, qJniThreadName, nullptr };
- if (vm->AttachCurrentThread(&d->jniEnv, &args) != JNI_OK)
- return;
-
- if (!jniEnvTLS->hasLocalData()) // If we attached the thread we own it.
- jniEnvTLS->setLocalData(new QJniEnvironmentPrivateTLS);
+ const QByteArray threadName = QThread::currentThread()->objectName().toUtf8();
+ JavaVMAttachArgs args = { JNI_VERSION_1_6,
+ threadName.isEmpty() ? "QtThread" : threadName.constData(),
+ nullptr
+ };
+ if (vm->AttachCurrentThread(&jniEnv, &args) == JNI_OK) {
+ if (!jniEnvTLS->hasLocalData()) // If we attached the thread we own it.
+ jniEnvTLS->setLocalData(new QJniEnvironmentPrivateTLS);
+ }
}
+ return jniEnv;
}
/*!
@@ -111,8 +104,6 @@ bool QJniEnvironment::isValid() const
}
/*!
- \fn JNIEnv *QJniEnvironment::operator->() const
-
Provides access to the JNI Environment's \c JNIEnv pointer.
*/
JNIEnv *QJniEnvironment::operator->() const
@@ -121,8 +112,6 @@ JNIEnv *QJniEnvironment::operator->() const
}
/*!
- \fn JNIEnv &QJniEnvironment::operator*() const
-
Returns the JNI Environment's \c JNIEnv object.
*/
JNIEnv &QJniEnvironment::operator*() const
@@ -131,8 +120,6 @@ JNIEnv &QJniEnvironment::operator*() const
}
/*!
- \fn JNIEnv *QJniEnvironment::jniEnv() const
-
Returns the JNI Environment's \c JNIEnv pointer.
*/
JNIEnv *QJniEnvironment::jniEnv() const
@@ -323,8 +310,6 @@ jfieldID QJniEnvironment::findStaticField(jclass clazz, const char *fieldName, c
*/
/*!
- \fn JavaVM *QJniEnvironment::javaVM()
-
Returns the Java VM interface for the current process. Although it might
be possible to have multiple Java VMs per process, Android allows only one.
@@ -366,6 +351,15 @@ bool QJniEnvironment::registerNativeMethods(const char *className, const JNINati
return registerNativeMethods(clazz, methods, size);
}
+
+/*!
+ \fn bool QJniEnvironment::registerNativeMethods(const char *className, std::initializer_list<JNINativeMethod> methods)
+ \overload
+
+ Registers the native functions methods in \a methods for the Java class \a className.
+ Returns \c true if the registration is successful, otherwise \c false.
+*/
+
#if QT_DEPRECATED_SINCE(6, 2)
/*!
\overload
@@ -421,6 +415,14 @@ bool QJniEnvironment::registerNativeMethods(jclass clazz, const JNINativeMethod
}
/*!
+ \fn bool QJniEnvironment::registerNativeMethods(jclass clazz, std::initializer_list<JNINativeMethod> methods)
+ \overload
+
+ Registers the native functions methods in \a methods for the Java class \a clazz.
+ Returns \c true if the registration is successful, otherwise \c false.
+*/
+
+/*!
\enum QJniEnvironment::OutputMode
\value Silent The exceptions are cleaned silently
@@ -448,7 +450,7 @@ bool QJniEnvironment::checkAndClearExceptions(QJniEnvironment::OutputMode output
namespace {
// Any pending exception need to be cleared before calling this
- QString exceptionMessage(JNIEnv *env, const jthrowable &exception)
+ QString exceptionMessage(JNIEnv *env, jthrowable exception)
{
if (!exception)
return {};
@@ -496,8 +498,6 @@ namespace {
} // end namespace
/*!
- \fn QJniEnvironment::checkAndClearExceptions(JNIEnv *env, OutputMode outputMode = OutputMode::Verbose)
-
Cleans any pending exceptions for \a env, either silently or reporting
stack backtrace, depending on the \a outputMode. This is useful when you
already have a \c JNIEnv pointer such as in a native function implementation.
diff --git a/src/corelib/kernel/qjnienvironment.h b/src/corelib/kernel/qjnienvironment.h
index f7ffa836c2..dda8dc0950 100644
--- a/src/corelib/kernel/qjnienvironment.h
+++ b/src/corelib/kernel/qjnienvironment.h
@@ -8,7 +8,7 @@
#if defined(Q_QDOC) || defined(Q_OS_ANDROID)
#include <jni.h>
-#include <QtCore/qjnitypes.h>
+#include <QtCore/qjnitypes_impl.h>
QT_BEGIN_NAMESPACE
@@ -25,7 +25,7 @@ public:
JNIEnv *jniEnv() const;
jclass findClass(const char *className);
template<typename Class>
- jclass findClass() { return findClass(QtJniTypes::className<Class>().data()); }
+ jclass findClass() { return findClass(QtJniTypes::Traits<Class>::className().data()); }
jmethodID findMethod(jclass clazz, const char *methodName, const char *signature);
template<typename ...Args>
jmethodID findMethod(jclass clazz, const char *methodName) {
@@ -64,6 +64,16 @@ public:
return registerNativeMethods(clazz, std::data(methods), methods.size());
}
+ template<typename Class
+#ifndef Q_QDOC
+ , std::enable_if_t<QtJniTypes::isObjectType<Class>(), bool> = true
+#endif
+ >
+ bool registerNativeMethods(std::initializer_list<JNINativeMethod> methods)
+ {
+ return registerNativeMethods(QtJniTypes::Traits<Class>::className().data(), methods);
+ }
+
#if QT_DEPRECATED_SINCE(6, 2)
// ### Qt 7: remove
QT_DEPRECATED_VERSION_X_6_2("Use the overload with a const JNINativeMethod[] instead.")
@@ -78,6 +88,8 @@ public:
bool checkAndClearExceptions(OutputMode outputMode = OutputMode::Verbose);
static bool checkAndClearExceptions(JNIEnv *env, OutputMode outputMode = OutputMode::Verbose);
+ static JNIEnv *getJniEnv();
+
private:
Q_DISABLE_COPY_MOVE(QJniEnvironment)
QScopedPointer<QJniEnvironmentPrivate> d;
diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp
index 78d05261e5..d900b74d37 100644
--- a/src/corelib/kernel/qjnihelpers.cpp
+++ b/src/corelib/kernel/qjnihelpers.cpp
@@ -26,8 +26,6 @@ namespace QtAndroidPrivate {
ResumePauseListener::~ResumePauseListener() {}
void ResumePauseListener::handlePause() {}
void ResumePauseListener::handleResume() {}
- GenericMotionEventListener::~GenericMotionEventListener() {}
- KeyEventListener::~KeyEventListener() {}
}
static JavaVM *g_javaVM = nullptr;
@@ -42,40 +40,6 @@ Q_CONSTINIT static QBasicAtomicInt g_serviceSetupLockers = Q_BASIC_ATOMIC_INITIA
Q_GLOBAL_STATIC(QReadWriteLock, g_updateMutex);
-namespace {
- struct GenericMotionEventListeners {
- QMutex mutex;
- QList<QtAndroidPrivate::GenericMotionEventListener *> listeners;
- };
-}
-Q_GLOBAL_STATIC(GenericMotionEventListeners, g_genericMotionEventListeners)
-
-static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, jobject event)
-{
- jboolean ret = JNI_FALSE;
- QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
- for (auto *listener : std::as_const(g_genericMotionEventListeners()->listeners))
- ret |= listener->handleGenericMotionEvent(event);
- return ret;
-}
-
-namespace {
- struct KeyEventListeners {
- QMutex mutex;
- QList<QtAndroidPrivate::KeyEventListener *> listeners;
- };
-}
-Q_GLOBAL_STATIC(KeyEventListeners, g_keyEventListeners)
-
-static jboolean dispatchKeyEvent(JNIEnv *, jclass, jobject event)
-{
- jboolean ret = JNI_FALSE;
- QMutexLocker locker(&g_keyEventListeners()->mutex);
- for (auto *listener : std::as_const(g_keyEventListeners()->listeners))
- ret |= listener->handleKeyEvent(event);
- return ret;
-}
-
static jboolean updateNativeActivity(JNIEnv *env, jclass = nullptr)
{
@@ -272,8 +236,6 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
}
static const JNINativeMethod methods[] = {
- {"dispatchGenericMotionEvent", "(Landroid/view/MotionEvent;)Z", reinterpret_cast<void *>(dispatchGenericMotionEvent)},
- {"dispatchKeyEvent", "(Landroid/view/KeyEvent;)Z", reinterpret_cast<void *>(dispatchKeyEvent)},
{"updateNativeActivity", "()Z", reinterpret_cast<void *>(updateNativeActivity) },
};
@@ -282,21 +244,37 @@ jint QtAndroidPrivate::initJNI(JavaVM *vm, JNIEnv *env)
if (!regOk && QJniEnvironment::checkAndClearExceptions(env))
return JNI_ERR;
- if (!registerPermissionNatives())
+ QJniEnvironment qJniEnv;
+ if (!registerPermissionNatives(qJniEnv))
+ return JNI_ERR;
+
+ if (!registerNativeInterfaceNatives(qJniEnv))
return JNI_ERR;
- if (!registerNativeInterfaceNatives())
+ if (!registerExtrasNatives(qJniEnv))
return JNI_ERR;
return JNI_OK;
}
+Q_CORE_EXPORT jobject qt_androidActivity()
+{
+ QReadLocker locker(g_updateMutex());
+ return g_jActivity;
+}
+
+
QtJniTypes::Activity QtAndroidPrivate::activity()
{
QReadLocker locker(g_updateMutex());
return g_jActivity;
}
+Q_CORE_EXPORT jobject qt_androidService()
+{
+ return g_jService;
+}
+
QtJniTypes::Service QtAndroidPrivate::service()
{
return g_jService;
@@ -331,30 +309,6 @@ jint QtAndroidPrivate::androidSdkVersion()
return sdkVersion;
}
-void QtAndroidPrivate::registerGenericMotionEventListener(QtAndroidPrivate::GenericMotionEventListener *listener)
-{
- QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
- g_genericMotionEventListeners()->listeners.push_back(listener);
-}
-
-void QtAndroidPrivate::unregisterGenericMotionEventListener(QtAndroidPrivate::GenericMotionEventListener *listener)
-{
- QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
- g_genericMotionEventListeners()->listeners.removeOne(listener);
-}
-
-void QtAndroidPrivate::registerKeyEventListener(QtAndroidPrivate::KeyEventListener *listener)
-{
- QMutexLocker locker(&g_keyEventListeners()->mutex);
- g_keyEventListeners()->listeners.push_back(listener);
-}
-
-void QtAndroidPrivate::unregisterKeyEventListener(QtAndroidPrivate::KeyEventListener *listener)
-{
- QMutexLocker locker(&g_keyEventListeners()->mutex);
- g_keyEventListeners()->listeners.removeOne(listener);
-}
-
void QtAndroidPrivate::waitForServiceSetup()
{
g_waitForServiceSetupSemaphore->acquire();
diff --git a/src/corelib/kernel/qjnihelpers_p.h b/src/corelib/kernel/qjnihelpers_p.h
index bce2b782de..b5e05fcaf1 100644
--- a/src/corelib/kernel/qjnihelpers_p.h
+++ b/src/corelib/kernel/qjnihelpers_p.h
@@ -22,8 +22,8 @@
QT_BEGIN_NAMESPACE
-Q_DECLARE_JNI_TYPE(Activity, "Landroid/app/Activity;")
-Q_DECLARE_JNI_TYPE(Service, "Landroid/app/Service;")
+Q_DECLARE_JNI_CLASS(Activity, "android/app/Activity")
+Q_DECLARE_JNI_CLASS(Service, "android/app/Service")
namespace QtAndroidPrivate
{
@@ -49,20 +49,6 @@ namespace QtAndroidPrivate
virtual void handleResume();
};
- class Q_CORE_EXPORT GenericMotionEventListener
- {
- public:
- virtual ~GenericMotionEventListener();
- virtual bool handleGenericMotionEvent(jobject event) = 0;
- };
-
- class Q_CORE_EXPORT KeyEventListener
- {
- public:
- virtual ~KeyEventListener();
- virtual bool handleKeyEvent(jobject event) = 0;
- };
-
class Q_CORE_EXPORT OnBindListener
{
public:
@@ -79,8 +65,9 @@ namespace QtAndroidPrivate
jobject classLoader();
Q_CORE_EXPORT jint androidSdkVersion();
- bool registerPermissionNatives();
- bool registerNativeInterfaceNatives();
+ bool registerPermissionNatives(QJniEnvironment &env);
+ bool registerNativeInterfaceNatives(QJniEnvironment &env);
+ bool registerExtrasNatives(QJniEnvironment &env);
Q_CORE_EXPORT void handleActivityResult(jint requestCode, jint resultCode, jobject data);
Q_CORE_EXPORT void registerActivityResultListener(ActivityResultListener *listener);
@@ -95,12 +82,6 @@ namespace QtAndroidPrivate
Q_CORE_EXPORT void registerResumePauseListener(ResumePauseListener *listener);
Q_CORE_EXPORT void unregisterResumePauseListener(ResumePauseListener *listener);
- Q_CORE_EXPORT void registerGenericMotionEventListener(GenericMotionEventListener *listener);
- Q_CORE_EXPORT void unregisterGenericMotionEventListener(GenericMotionEventListener *listener);
-
- Q_CORE_EXPORT void registerKeyEventListener(KeyEventListener *listener);
- Q_CORE_EXPORT void unregisterKeyEventListener(KeyEventListener *listener);
-
Q_CORE_EXPORT void waitForServiceSetup();
Q_CORE_EXPORT int acuqireServiceSetup(int flags);
Q_CORE_EXPORT void setOnBindListener(OnBindListener *listener);
diff --git a/src/corelib/kernel/qjniobject.cpp b/src/corelib/kernel/qjniobject.cpp
index df4335092e..8244a4390f 100644
--- a/src/corelib/kernel/qjniobject.cpp
+++ b/src/corelib/kernel/qjniobject.cpp
@@ -8,9 +8,13 @@
#include <QtCore/qbytearray.h>
#include <QtCore/qhash.h>
#include <QtCore/qreadwritelock.h>
+#include <QtCore/qloggingcategory.h>
+
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcJniThreadCheck, "qt.core.jni.threadcheck")
+
using namespace Qt::StringLiterals;
/*!
@@ -20,7 +24,7 @@ using namespace Qt::StringLiterals;
\brief A convenience wrapper around the Java Native Interface (JNI).
The QJniObject class wraps a reference to a Java object, ensuring it isn't
- gargage-collected and providing access to most \c JNIEnv method calls
+ garbage-collected and providing access to most \c JNIEnv method calls
(member, static) and fields (setter, getter). It eliminates much
boiler-plate that would normally be needed, with direct JNI access, for
every operation, including exception-handling.
@@ -108,7 +112,7 @@ using namespace Qt::StringLiterals;
string2.object<jstring>());
\endcode
- Note that while he first template parameter specifies the return type of the Java
+ Note that while the first template parameter specifies the return type of the Java
function, the method will still return a QJniObject.
\section1 Handling Java Exception
@@ -277,100 +281,151 @@ using namespace Qt::StringLiterals;
class QJniObjectPrivate
{
public:
- QJniObjectPrivate() = default;
+ QJniObjectPrivate()
+ {
+ }
~QJniObjectPrivate() {
- QJniEnvironment env;
+ JNIEnv *env = QJniEnvironment::getJniEnv();
if (m_jobject)
env->DeleteGlobalRef(m_jobject);
if (m_jclass && m_own_jclass)
env->DeleteGlobalRef(m_jclass);
}
- friend jclass QtAndroidPrivate::findClass(const char *className, JNIEnv *env);
- static jclass loadClass(const QByteArray &className, JNIEnv *env, bool binEncoded = false)
+ template <typename ...Args>
+ void construct(const char *signature = nullptr, Args &&...args)
{
- return QJniObject::loadClass(className, env, binEncoded);
- }
-
- static QByteArray toBinaryEncClassName(const QByteArray &className)
- {
- return QJniObject::toBinaryEncClassName(className);
+ if (m_jclass) {
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ // get default constructor
+ jmethodID constructorId = QJniObject::getCachedMethodID(env, m_jclass, m_className, "<init>",
+ signature ? signature : "()V");
+ if (constructorId) {
+ jobject obj = nullptr;
+ if constexpr (sizeof...(Args) == 0)
+ obj = env->NewObject(m_jclass, constructorId);
+ else
+ obj = env->NewObjectV(m_jclass, constructorId, std::forward<Args>(args)...);
+ if (obj) {
+ m_jobject = env->NewGlobalRef(obj);
+ env->DeleteLocalRef(obj);
+ }
+ }
+ }
}
+ QByteArray m_className;
jobject m_jobject = nullptr;
jclass m_jclass = nullptr;
bool m_own_jclass = true;
- QByteArray m_className;
};
-static inline QLatin1StringView keyBase()
-{
- return "%1%2:%3"_L1;
-}
-
-static QString qt_convertJString(jstring string)
+template <typename ...Args>
+static inline QByteArray cacheKey(Args &&...args)
{
- QJniEnvironment env;
- int strLength = env->GetStringLength(string);
- QString res(strLength, Qt::Uninitialized);
- env->GetStringRegion(string, 0, strLength, reinterpret_cast<jchar *>(res.data()));
- return res;
+ return (QByteArrayView(":") + ... + QByteArrayView(args));
}
-typedef QHash<QString, jclass> JClassHash;
+typedef QHash<QByteArray, jclass> JClassHash;
Q_GLOBAL_STATIC(JClassHash, cachedClasses)
Q_GLOBAL_STATIC(QReadWriteLock, cachedClassesLock)
-static jclass getCachedClass(const QByteArray &classBinEnc, bool *isCached = nullptr)
+static jclass getCachedClass(const QByteArray &className)
{
QReadLocker locker(cachedClassesLock);
- const QHash<QString, jclass>::const_iterator &it = cachedClasses->constFind(QString::fromLatin1(classBinEnc));
- const bool found = (it != cachedClasses->constEnd());
-
- if (isCached)
- *isCached = found;
-
- return found ? it.value() : 0;
+ const auto &it = cachedClasses->constFind(className);
+ return it != cachedClasses->constEnd() ? it.value() : nullptr;
}
-QByteArray QJniObject::toBinaryEncClassName(const QByteArray &className)
+/*!
+ \internal
+
+ Get a JNI object from a jobject variant and do the necessary
+ exception clearing and delete the local reference before returning.
+ The JNI object can be null if there was an exception.
+*/
+static QJniObject getCleanJniObject(jobject object, JNIEnv *env)
{
- return QByteArray(className).replace('/', '.');
+ if (QJniEnvironment::checkAndClearExceptions(env) || !object) {
+ if (object)
+ env->DeleteLocalRef(object);
+ return QJniObject();
+ }
+
+ QJniObject res(object);
+ env->DeleteLocalRef(object);
+ return res;
}
-jclass QJniObject::loadClass(const QByteArray &className, JNIEnv *env, bool binEncoded)
+/*!
+ \internal
+ \a className must be slash-encoded
+*/
+jclass QtAndroidPrivate::findClass(const char *className, JNIEnv *env)
{
- const QByteArray &binEncClassName = binEncoded ? className : QJniObject::toBinaryEncClassName(className);
-
- bool isCached = false;
- jclass clazz = getCachedClass(binEncClassName, &isCached);
- if (clazz || isCached)
+ Q_ASSERT(env);
+ QByteArray classNameArray(className);
+#ifdef QT_DEBUG
+ if (classNameArray.contains('.')) {
+ qWarning("QtAndroidPrivate::findClass: className '%s' should use slash separators!",
+ className);
+ }
+#endif
+ classNameArray.replace('.', '/');
+ jclass clazz = getCachedClass(classNameArray);
+ if (clazz)
return clazz;
- QJniObject classLoader(QtAndroidPrivate::classLoader());
- if (!classLoader.isValid())
- return nullptr;
-
QWriteLocker locker(cachedClassesLock);
- // did we lose the race?
- const QLatin1StringView key(binEncClassName);
- const QHash<QString, jclass>::const_iterator &it = cachedClasses->constFind(key);
+ // Check again; another thread might have added the class to the cache after
+ // our call to getCachedClass and before we acquired the lock.
+ const auto &it = cachedClasses->constFind(classNameArray);
if (it != cachedClasses->constEnd())
return it.value();
- QJniObject stringName = QJniObject::fromString(key);
- QJniObject classObject = classLoader.callObjectMethod("loadClass",
- "(Ljava/lang/String;)Ljava/lang/Class;",
- stringName.object());
+ // JNIEnv::FindClass wants "a fully-qualified class name or an array type signature"
+ // which is a slash-separated class name.
+ jclass localClazz = env->FindClass(classNameArray.constData());
+ if (localClazz) {
+ clazz = static_cast<jclass>(env->NewGlobalRef(localClazz));
+ env->DeleteLocalRef(localClazz);
+ } else {
+ // Clear the exception silently; we are going to try the ClassLoader next,
+ // so no need for warning unless that fails as well.
+ env->ExceptionClear();
+ }
+
+ if (!clazz) {
+ // Wrong class loader, try our own
+ QJniObject classLoader(QtAndroidPrivate::classLoader());
+ if (!classLoader.isValid())
+ return nullptr;
+
+ // ClassLoader::loadClass on the other hand wants the binary name of the class,
+ // e.g. dot-separated. In testing it works also with /, but better to stick to
+ // the specification.
+ const QString binaryClassName = QString::fromLatin1(className).replace(u'/', u'.');
+ jstring classNameObject = env->NewString(reinterpret_cast<const jchar*>(binaryClassName.constData()),
+ binaryClassName.length());
+ QJniObject classObject = classLoader.callMethod<jclass>("loadClass", classNameObject);
+ env->DeleteLocalRef(classNameObject);
+
+ if (!QJniEnvironment::checkAndClearExceptions(env) && classObject.isValid())
+ clazz = static_cast<jclass>(env->NewGlobalRef(classObject.object()));
+ }
- if (!QJniEnvironment::checkAndClearExceptions(env) && classObject.isValid())
- clazz = static_cast<jclass>(env->NewGlobalRef(classObject.object()));
+ if (clazz)
+ cachedClasses->insert(classNameArray, clazz);
- cachedClasses->insert(key, clazz);
return clazz;
}
-typedef QHash<QString, jmethodID> JMethodIDHash;
+jclass QJniObject::loadClass(const QByteArray &className, JNIEnv *env)
+{
+ return QtAndroidPrivate::findClass(className, env);
+}
+
+typedef QHash<QByteArray, jmethodID> JMethodIDHash;
Q_GLOBAL_STATIC(JMethodIDHash, cachedMethodID)
Q_GLOBAL_STATIC(QReadWriteLock, cachedMethodIDLock)
@@ -393,13 +448,8 @@ void QJniObject::callVoidMethodV(JNIEnv *env, jmethodID id, ...) const
{
va_list args;
va_start(args, id);
- callVoidMethodV(env, id, args);
- va_end(args);
-}
-
-void QJniObject::callVoidMethodV(JNIEnv *env, jmethodID id, va_list args) const
-{
env->CallVoidMethodV(d->m_jobject, id, args);
+ va_end(args);
}
jmethodID QJniObject::getCachedMethodID(JNIEnv *env,
@@ -412,10 +462,8 @@ jmethodID QJniObject::getCachedMethodID(JNIEnv *env,
if (className.isEmpty())
return getMethodID(env, clazz, name, signature, isStatic);
- const QString key = keyBase().arg(QLatin1StringView(className),
- QLatin1StringView(name),
- QLatin1StringView(signature));
- QHash<QString, jmethodID>::const_iterator it;
+ const QByteArray key = cacheKey(className, name, signature);
+ QHash<QByteArray, jmethodID>::const_iterator it;
{
QReadLocker locker(cachedMethodIDLock);
@@ -443,7 +491,7 @@ jmethodID QJniObject::getCachedMethodID(JNIEnv *env, const char *name,
return QJniObject::getCachedMethodID(env, d->m_jclass, d->m_className, name, signature, isStatic);
}
-typedef QHash<QString, jfieldID> JFieldIDHash;
+typedef QHash<QByteArray, jfieldID> JFieldIDHash;
Q_GLOBAL_STATIC(JFieldIDHash, cachedFieldID)
Q_GLOBAL_STATIC(QReadWriteLock, cachedFieldIDLock)
@@ -472,10 +520,8 @@ jfieldID QJniObject::getCachedFieldID(JNIEnv *env,
if (className.isNull())
return getFieldID(env, clazz, name, signature, isStatic);
- const QString key = keyBase().arg(QLatin1StringView(className),
- QLatin1StringView(name),
- QLatin1StringView(signature));
- QHash<QString, jfieldID>::const_iterator it;
+ const QByteArray key = cacheKey(className, name, signature);
+ QHash<QByteArray, jfieldID>::const_iterator it;
{
QReadLocker locker(cachedFieldIDLock);
@@ -505,39 +551,6 @@ jfieldID QJniObject::getCachedFieldID(JNIEnv *env,
return QJniObject::getCachedFieldID(env, d->m_jclass, d->m_className, name, signature, isStatic);
}
-jclass QtAndroidPrivate::findClass(const char *className, JNIEnv *env)
-{
- const QByteArray &classDotEnc = QJniObjectPrivate::toBinaryEncClassName(className);
- bool isCached = false;
- jclass clazz = getCachedClass(classDotEnc, &isCached);
-
- if (clazz || isCached)
- return clazz;
-
- const QLatin1StringView key(classDotEnc);
- if (env) { // We got an env. pointer (We expect this to be the right env. and call FindClass())
- QWriteLocker locker(cachedClassesLock);
- const QHash<QString, jclass>::const_iterator &it = cachedClasses->constFind(key);
- // Did we lose the race?
- if (it != cachedClasses->constEnd())
- return it.value();
-
- jclass fclazz = env->FindClass(className);
- if (!QJniEnvironment::checkAndClearExceptions(env)) {
- clazz = static_cast<jclass>(env->NewGlobalRef(fclazz));
- env->DeleteLocalRef(fclazz);
- }
-
- if (clazz)
- cachedClasses->insert(key, clazz);
- }
-
- if (!clazz) // We didn't get an env. pointer or we got one with the WRONG class loader...
- clazz = QJniObjectPrivate::loadClass(classDotEnc, QJniEnvironment().jniEnv(), true);
-
- return clazz;
-}
-
/*!
\fn QJniObject::QJniObject()
@@ -562,21 +575,11 @@ QJniObject::QJniObject()
QJniObject::QJniObject(const char *className)
: d(new QJniObjectPrivate())
{
- QJniEnvironment env;
- d->m_className = toBinaryEncClassName(className);
- d->m_jclass = loadClass(d->m_className, env.jniEnv(), true);
+ d->m_className = className;
+ d->m_jclass = loadClass(d->m_className, jniEnv());
d->m_own_jclass = false;
- if (d->m_jclass) {
- // get default constructor
- jmethodID constructorId = getCachedMethodID(env.jniEnv(), "<init>", "()V");
- if (constructorId) {
- jobject obj = env->NewObject(d->m_jclass, constructorId);
- if (obj) {
- d->m_jobject = env->NewGlobalRef(obj);
- env->DeleteLocalRef(obj);
- }
- }
- }
+
+ d->construct();
}
/*!
@@ -595,23 +598,14 @@ QJniObject::QJniObject(const char *className)
QJniObject::QJniObject(const char *className, const char *signature, ...)
: d(new QJniObjectPrivate())
{
- QJniEnvironment env;
- d->m_className = toBinaryEncClassName(className);
- d->m_jclass = loadClass(d->m_className, env.jniEnv(), true);
+ d->m_className = className;
+ d->m_jclass = loadClass(d->m_className, jniEnv());
d->m_own_jclass = false;
- if (d->m_jclass) {
- jmethodID constructorId = getCachedMethodID(env.jniEnv(), "<init>", signature);
- if (constructorId) {
- va_list args;
- va_start(args, signature);
- jobject obj = env->NewObjectV(d->m_jclass, constructorId, args);
- va_end(args);
- if (obj) {
- d->m_jobject = env->NewGlobalRef(obj);
- env->DeleteLocalRef(obj);
- }
- }
- }
+
+ va_list args;
+ va_start(args, signature);
+ d->construct(signature, args);
+ va_end(args);
}
/*!
@@ -630,25 +624,6 @@ QJniObject::QJniObject(const char *className, const char *signature, ...)
\endcode
*/
-QJniObject::QJniObject(const char *className, const char *signature, const QVaListPrivate &args)
- : d(new QJniObjectPrivate())
-{
- QJniEnvironment env;
- d->m_className = toBinaryEncClassName(className);
- d->m_jclass = loadClass(d->m_className, env.jniEnv(), true);
- d->m_own_jclass = false;
- if (d->m_jclass) {
- jmethodID constructorId = getCachedMethodID(env.jniEnv(), "<init>", signature);
- if (constructorId) {
- jobject obj = env->NewObjectV(d->m_jclass, constructorId, args);
- if (obj) {
- d->m_jobject = env->NewGlobalRef(obj);
- env->DeleteLocalRef(obj);
- }
- }
- }
-}
-
/*!
Constructs a new JNI object from \a clazz by calling the constructor with
\a signature specifying the types of any subsequent arguments.
@@ -662,22 +637,12 @@ QJniObject::QJniObject(const char *className, const char *signature, const QVaLi
QJniObject::QJniObject(jclass clazz, const char *signature, ...)
: d(new QJniObjectPrivate())
{
- QJniEnvironment env;
if (clazz) {
- d->m_jclass = static_cast<jclass>(env->NewGlobalRef(clazz));
- if (d->m_jclass) {
- jmethodID constructorId = getMethodID(env.jniEnv(), d->m_jclass, "<init>", signature);
- if (constructorId) {
- va_list args;
- va_start(args, signature);
- jobject obj = env->NewObjectV(d->m_jclass, constructorId, args);
- va_end(args);
- if (obj) {
- d->m_jobject = env->NewGlobalRef(obj);
- env->DeleteLocalRef(obj);
- }
- }
- }
+ d->m_jclass = static_cast<jclass>(jniEnv()->NewGlobalRef(clazz));
+ va_list args;
+ va_start(args, signature);
+ d->construct(signature, args);
+ va_end(args);
}
}
@@ -705,40 +670,8 @@ QJniObject::QJniObject(jclass clazz, const char *signature, ...)
*/
QJniObject::QJniObject(jclass clazz)
- : d(new QJniObjectPrivate())
+ : QJniObject(clazz, "()V")
{
- QJniEnvironment env;
- d->m_jclass = static_cast<jclass>(env->NewGlobalRef(clazz));
- if (d->m_jclass) {
- // get default constructor
- jmethodID constructorId = getMethodID(env.jniEnv(), d->m_jclass, "<init>", "()V");
- if (constructorId) {
- jobject obj = env->NewObject(d->m_jclass, constructorId);
- if (obj) {
- d->m_jobject = env->NewGlobalRef(obj);
- env->DeleteLocalRef(obj);
- }
- }
- }
-}
-
-QJniObject::QJniObject(jclass clazz, const char *signature, const QVaListPrivate &args)
- : d(new QJniObjectPrivate())
-{
- QJniEnvironment env;
- if (clazz) {
- d->m_jclass = static_cast<jclass>(env->NewGlobalRef(clazz));
- if (d->m_jclass) {
- jmethodID constructorId = getMethodID(env.jniEnv(), d->m_jclass, "<init>", signature);
- if (constructorId) {
- jobject obj = env->NewObjectV(d->m_jclass, constructorId, args);
- if (obj) {
- d->m_jobject = env->NewGlobalRef(obj);
- env->DeleteLocalRef(obj);
- }
- }
- }
- }
}
/*!
@@ -759,7 +692,7 @@ QJniObject::QJniObject(jobject object)
if (!object)
return;
- QJniEnvironment env;
+ JNIEnv *env = QJniEnvironment::getJniEnv();
d->m_jobject = env->NewGlobalRef(object);
jclass cls = env->GetObjectClass(object);
d->m_jclass = static_cast<jclass>(env->NewGlobalRef(cls));
@@ -782,27 +715,6 @@ QJniObject::QJniObject(jobject object)
*/
/*!
- \brief Get a JNI object from a jobject variant and do the necessary
- exception clearing and delete the local reference before returning.
- The JNI object can be null if there was an exception.
-*/
-QJniObject QJniObject::getCleanJniObject(jobject object)
-{
- if (!object)
- return QJniObject();
-
- QJniEnvironment env;
- if (env.checkAndClearExceptions()) {
- env->DeleteLocalRef(object);
- return QJniObject();
- }
-
- QJniObject res(object);
- env->DeleteLocalRef(object);
- return res;
-}
-
-/*!
\fn QJniObject::~QJniObject()
Destroys the JNI object and releases any references held by the JNI object.
@@ -810,7 +722,37 @@ QJniObject QJniObject::getCleanJniObject(jobject object)
QJniObject::~QJniObject()
{}
+namespace {
+QByteArray getClassNameHelper(JNIEnv *env, const QJniObjectPrivate *d)
+{
+ if (env->PushLocalFrame(3) != JNI_OK) // JVM out of memory
+ return QByteArray();
+
+ jmethodID mid = env->GetMethodID(d->m_jclass, "getClass", "()Ljava/lang/Class;");
+ jobject classObject = env->CallObjectMethod(d->m_jobject, mid);
+ jclass classObjectClass = env->GetObjectClass(classObject);
+ mid = env->GetMethodID(classObjectClass, "getName", "()Ljava/lang/String;");
+ jstring stringObject = static_cast<jstring>(env->CallObjectMethod(classObject, mid));
+ const jsize length = env->GetStringUTFLength(stringObject);
+ const char* nameString = env->GetStringUTFChars(stringObject, NULL);
+ const QByteArray result = QByteArray::fromRawData(nameString, length).replace('.', '/');
+ env->ReleaseStringUTFChars(stringObject, nameString);
+ env->PopLocalFrame(nullptr);
+ return result;
+}
+}
+
+/*! \internal
+
+ Returns the JNIEnv of the calling thread.
+*/
+JNIEnv *QJniObject::jniEnv() const noexcept
+{
+ return QJniEnvironment::getJniEnv();
+}
+
/*!
+ \fn jobject QJniObject::object() const
\fn template <typename T> T QJniObject::object() const
Returns the object held by the QJniObject either as jobject or as type T.
@@ -861,65 +803,11 @@ jclass QJniObject::objectClass() const
*/
QByteArray QJniObject::className() const
{
- return d->m_className;
-}
-
-QJniObject QJniObject::callObjectMethodV(const char *methodName,
- const char *signature,
- va_list args) const
-{
- QJniEnvironment env;
- jobject res = nullptr;
- jmethodID id = getCachedMethodID(env.jniEnv(), methodName, signature);
- if (id) {
- res = env->CallObjectMethodV(d->m_jobject, id, args);
- if (env.checkAndClearExceptions()) {
- env->DeleteLocalRef(res);
- res = nullptr;
- }
+ if (d->m_className.isEmpty() && d->m_jclass && d->m_jobject) {
+ JNIEnv *env = jniEnv();
+ d->m_className = getClassNameHelper(env, d.get());
}
-
- QJniObject obj(res);
- env->DeleteLocalRef(res);
- return obj;
-}
-
-QJniObject QJniObject::callStaticObjectMethodV(const char *className,
- const char *methodName,
- const char *signature,
- va_list args)
-{
- QJniEnvironment env;
- jobject res = nullptr;
- jclass clazz = loadClass(className, env.jniEnv());
- if (clazz) {
- jmethodID id = QJniObject::getCachedMethodID(env.jniEnv(), clazz, toBinaryEncClassName(className),
- methodName, signature, true);
- if (id) {
- res = env->CallStaticObjectMethodV(clazz, id, args);
- if (env.checkAndClearExceptions()) {
- env->DeleteLocalRef(res);
- res = nullptr;
- }
- }
- }
-
- QJniObject obj(res);
- env->DeleteLocalRef(res);
- return obj;
-}
-
-QJniObject QJniObject::callStaticObjectMethodV(jclass clazz,
- const char *methodName,
- const char *signature,
- va_list args)
-{
- QJniEnvironment env;
- jmethodID id = getMethodID(env.jniEnv(), clazz, methodName, signature, true);
- if (!id)
- return QJniObject();
-
- return getCleanJniObject(env->CallStaticObjectMethodV(clazz, id, args));
+ return d->m_className;
}
/*!
@@ -1028,7 +916,7 @@ QJniObject QJniObject::callStaticObjectMethodV(jclass clazz,
\since 6.4
Calls the static method \a methodName on \a clazz and returns the value of type \c Ret
- (unless c Ret is \c void). If \c Ret if a jobject type, then the returned value will
+ (unless \c Ret is \c void). If \c Ret is a jobject type, then the returned value will
be a QJniObject.
\code
@@ -1041,6 +929,18 @@ QJniObject QJniObject::callStaticObjectMethodV(jclass clazz,
*/
/*!
+ \fn template <typename Klass, typename Ret, typename ...Args> auto QJniObject::callStaticMethod(const char *methodName, Args &&...args)
+ \since 6.7
+
+ Calls the static method \a methodName on the class \c Klass and returns the value of type
+ \c Ret (unless \c Ret is \c void). If \c Ret is a jobject type, then the returned value will
+ be a QJniObject.
+
+ The method signature is deduced at compile time from \c Ret and the types of \a args.
+ \c Klass needs to be a C++ type with a registered type mapping to a Java type.
+*/
+
+/*!
\fn QJniObject QJniObject::callObjectMethod(const char *methodName, const char *signature, ...) const
Calls the Java object's method \a methodName with \a signature specifying
@@ -1054,12 +954,11 @@ QJniObject QJniObject::callStaticObjectMethodV(jclass clazz,
*/
QJniObject QJniObject::callObjectMethod(const char *methodName, const char *signature, ...) const
{
- QJniEnvironment env;
- jmethodID id = getCachedMethodID(env.jniEnv(), methodName, signature);
+ jmethodID id = getCachedMethodID(jniEnv(), methodName, signature);
if (id) {
va_list args;
va_start(args, signature);
- QJniObject res = getCleanJniObject(env->CallObjectMethodV(d->m_jobject, id, args));
+ QJniObject res = getCleanJniObject(jniEnv()->CallObjectMethodV(d->m_jobject, id, args), jniEnv());
va_end(args);
return res;
}
@@ -1083,16 +982,16 @@ QJniObject QJniObject::callObjectMethod(const char *methodName, const char *sign
QJniObject QJniObject::callStaticObjectMethod(const char *className, const char *methodName,
const char *signature, ...)
{
- QJniEnvironment env;
- jclass clazz = QJniObject::loadClass(className, env.jniEnv());
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ jclass clazz = QJniObject::loadClass(className, env);
if (clazz) {
- jmethodID id = QJniObject::getCachedMethodID(env.jniEnv(), clazz,
- QJniObject::toBinaryEncClassName(className),
+ jmethodID id = QJniObject::getCachedMethodID(env, clazz,
+ className,
methodName, signature, true);
if (id) {
va_list args;
va_start(args, signature);
- QJniObject res = getCleanJniObject(env->CallStaticObjectMethodV(clazz, id, args));
+ QJniObject res = getCleanJniObject(env->CallStaticObjectMethodV(clazz, id, args), env);
va_end(args);
return res;
}
@@ -1110,13 +1009,13 @@ QJniObject QJniObject::callStaticObjectMethod(const char *className, const char
QJniObject QJniObject::callStaticObjectMethod(jclass clazz, const char *methodName,
const char *signature, ...)
{
- QJniEnvironment env;
if (clazz) {
+ QJniEnvironment env;
jmethodID id = getMethodID(env.jniEnv(), clazz, methodName, signature, true);
if (id) {
va_list args;
va_start(args, signature);
- QJniObject res = getCleanJniObject(env->CallStaticObjectMethodV(clazz, id, args));
+ QJniObject res = getCleanJniObject(env->CallStaticObjectMethodV(clazz, id, args), env.jniEnv());
va_end(args);
return res;
}
@@ -1142,11 +1041,11 @@ QJniObject QJniObject::callStaticObjectMethod(jclass clazz, const char *methodNa
*/
QJniObject QJniObject::callStaticObjectMethod(jclass clazz, jmethodID methodId, ...)
{
- QJniEnvironment env;
if (clazz && methodId) {
+ QJniEnvironment env;
va_list args;
va_start(args, methodId);
- QJniObject res = getCleanJniObject(env->CallStaticObjectMethodV(clazz, methodId, args));
+ QJniObject res = getCleanJniObject(env->CallStaticObjectMethodV(clazz, methodId, args), env.jniEnv());
va_end(args);
return res;
}
@@ -1192,7 +1091,7 @@ QJniObject QJniObject::callStaticObjectMethod(jclass clazz, jmethodID methodId,
*/
/*!
- \fn template <typename T> QJniObject &QJniObject::operator=(T object)
+ \fn template <typename T, std::enable_if_t<std::is_convertible_v<T, jobject>, bool> = true> QJniObject &QJniObject::operator=(T object)
Replace the current object with \a object. The old Java object will be released.
*/
@@ -1213,7 +1112,7 @@ QJniObject QJniObject::callStaticObjectMethod(jclass clazz, jmethodID methodId,
*/
/*!
- \fn T QJniObject::getField(const char *fieldName) const
+ \fn template<typename T> T QJniObject::getField(const char *fieldName) const
Retrieves the value of the field \a fieldName.
@@ -1224,13 +1123,13 @@ QJniObject QJniObject::callStaticObjectMethod(jclass clazz, jmethodID methodId,
*/
/*!
- \fn T QJniObject::getStaticField(const char *className, const char *fieldName)
+ \fn template<typename T> T QJniObject::getStaticField(const char *className, const char *fieldName)
Retrieves the value from the static field \a fieldName on the class \a className.
*/
/*!
- \fn T QJniObject::getStaticField(jclass clazz, const char *fieldName)
+ \fn template<typename T> T QJniObject::getStaticField(jclass clazz, const char *fieldName)
Retrieves the value from the static field \a fieldName on \a clazz.
*/
@@ -1280,18 +1179,18 @@ QJniObject QJniObject::getStaticObjectField(const char *className,
const char *fieldName,
const char *signature)
{
- QJniEnvironment env;
- jclass clazz = QJniObject::loadClass(className, env.jniEnv());
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ jclass clazz = QJniObject::loadClass(className, env);
if (!clazz)
return QJniObject();
- jfieldID id = QJniObject::getCachedFieldID(env.jniEnv(), clazz,
- QJniObject::toBinaryEncClassName(className),
+ jfieldID id = QJniObject::getCachedFieldID(env, clazz,
+ className,
fieldName,
signature, true);
if (!id)
return QJniObject();
- return getCleanJniObject(env->GetStaticObjectField(clazz, id));
+ return getCleanJniObject(env->GetStaticObjectField(clazz, id), env);
}
/*!
@@ -1309,12 +1208,9 @@ QJniObject QJniObject::getStaticObjectField(const char *className,
QJniObject QJniObject::getStaticObjectField(jclass clazz, const char *fieldName,
const char *signature)
{
- QJniEnvironment env;
- jfieldID id = getFieldID(env.jniEnv(), clazz, fieldName, signature, true);
- if (!id)
- return QJniObject();
-
- return getCleanJniObject(env->GetStaticObjectField(clazz, id));
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ jfieldID id = getFieldID(env, clazz, fieldName, signature, true);
+ return getCleanJniObject(env->GetStaticObjectField(clazz, id), env);
}
/*!
@@ -1331,7 +1227,7 @@ QJniObject QJniObject::getStaticObjectField(jclass clazz, const char *fieldName,
*/
/*!
- \fn QJniObject QJniObject::getObjectField(const char *fieldName) const
+ \fn template<typename T> QJniObject QJniObject::getObjectField(const char *fieldName) const
Retrieves a JNI object from the field \a fieldName.
@@ -1353,12 +1249,11 @@ QJniObject QJniObject::getStaticObjectField(jclass clazz, const char *fieldName,
*/
QJniObject QJniObject::getObjectField(const char *fieldName, const char *signature) const
{
- QJniEnvironment env;
- jfieldID id = getCachedFieldID(env.jniEnv(), fieldName, signature);
+ jfieldID id = getCachedFieldID(jniEnv(), fieldName, signature);
if (!id)
return QJniObject();
- return getCleanJniObject(env->GetObjectField(d->m_jobject, id));
+ return getCleanJniObject(jniEnv()->GetObjectField(d->m_jobject, id), jniEnv());
}
/*!
@@ -1375,7 +1270,7 @@ QJniObject QJniObject::getObjectField(const char *fieldName, const char *signatu
*/
/*!
- \fn QJniObject QJniObject::getStaticObjectField(const char *className, const char *fieldName)
+ \fn template<typename T> QJniObject QJniObject::getStaticObjectField(const char *className, const char *fieldName)
Retrieves the object from the field \a fieldName on the class \a className.
@@ -1385,7 +1280,7 @@ QJniObject QJniObject::getObjectField(const char *fieldName, const char *signatu
*/
/*!
- \fn QJniObject QJniObject::getStaticObjectField(jclass clazz, const char *fieldName)
+ \fn template<typename T> QJniObject QJniObject::getStaticObjectField(jclass clazz, const char *fieldName)
Retrieves the object from the field \a fieldName on \a clazz.
@@ -1409,8 +1304,11 @@ QJniObject QJniObject::getObjectField(const char *fieldName, const char *signatu
QJniObject QJniObject::fromString(const QString &string)
{
QJniEnvironment env;
- return getCleanJniObject(env->NewString(reinterpret_cast<const jchar*>(string.constData()),
- string.length()));
+ jstring stringRef = env->NewString(reinterpret_cast<const jchar*>(string.constData()),
+ string.length());
+ QJniObject stringObject = getCleanJniObject(stringRef, env.jniEnv());
+ stringObject.d->m_className = "java/lang/String";
+ return stringObject;
}
/*!
@@ -1433,7 +1331,10 @@ QString QJniObject::toString() const
return QString();
QJniObject string = callObjectMethod<jstring>("toString");
- return qt_convertJString(static_cast<jstring>(string.object()));
+ const int strLength = string.jniEnv()->GetStringLength(string.object<jstring>());
+ QString res(strLength, Qt::Uninitialized);
+ string.jniEnv()->GetStringRegion(string.object<jstring>(), 0, strLength, reinterpret_cast<jchar *>(res.data()));
+ return res;
}
/*!
@@ -1454,7 +1355,7 @@ bool QJniObject::isClassAvailable(const char *className)
if (!env.jniEnv())
return false;
- return loadClass(className, env.jniEnv());;
+ return loadClass(className, env.jniEnv());
}
/*!
@@ -1490,13 +1391,17 @@ bool QJniObject::isValid() const
QJniObject QJniObject::fromLocalRef(jobject lref)
{
QJniObject obj(lref);
- QJniEnvironment()->DeleteLocalRef(lref);
+ obj.jniEnv()->DeleteLocalRef(lref);
return obj;
}
bool QJniObject::isSameObject(jobject obj) const
{
- return QJniEnvironment()->IsSameObject(d->m_jobject, obj);
+ if (d->m_jobject == obj)
+ return true;
+ if (!d->m_jobject || !obj)
+ return false;
+ return jniEnv()->IsSameObject(d->m_jobject, obj);
}
bool QJniObject::isSameObject(const QJniObject &other) const
@@ -1506,15 +1411,14 @@ bool QJniObject::isSameObject(const QJniObject &other) const
void QJniObject::assign(jobject obj)
{
- if (isSameObject(obj))
+ if (d && isSameObject(obj))
return;
- jobject jobj = static_cast<jobject>(obj);
d = QSharedPointer<QJniObjectPrivate>::create();
if (obj) {
- QJniEnvironment env;
- d->m_jobject = env->NewGlobalRef(jobj);
- jclass objectClass = env->GetObjectClass(jobj);
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ d->m_jobject = env->NewGlobalRef(obj);
+ jclass objectClass = env->GetObjectClass(obj);
d->m_jclass = static_cast<jclass>(env->NewGlobalRef(objectClass));
env->DeleteLocalRef(objectClass);
}
diff --git a/src/corelib/kernel/qjniobject.h b/src/corelib/kernel/qjniobject.h
index 2e1ed4add2..589f6489f7 100644
--- a/src/corelib/kernel/qjniobject.h
+++ b/src/corelib/kernel/qjniobject.h
@@ -9,7 +9,6 @@
#if defined(Q_QDOC) || defined(Q_OS_ANDROID)
#include <jni.h>
#include <QtCore/qjnienvironment.h>
-#include <QtCore/qjnitypes.h>
QT_BEGIN_NAMESPACE
@@ -17,6 +16,51 @@ class QJniObjectPrivate;
class Q_CORE_EXPORT QJniObject
{
+ friend class QJniArrayBase;
+
+ template <typename ...Args>
+ struct LocalFrame {
+ mutable JNIEnv *env;
+ bool hasFrame = false;
+ explicit LocalFrame(JNIEnv *env = nullptr) noexcept
+ : env(env)
+ {
+ }
+ ~LocalFrame()
+ {
+ if (hasFrame)
+ env->PopLocalFrame(nullptr);
+ }
+ template <typename T>
+ auto newLocalRef(jobject object)
+ {
+ if (!hasFrame) {
+ if (jniEnv()->PushLocalFrame(sizeof...(Args)) < 0)
+ return T{}; // JVM is out of memory, avoid making matters worse
+ hasFrame = true;
+ }
+ return static_cast<T>(jniEnv()->NewLocalRef(object));
+ }
+ template <typename T>
+ auto newLocalRef(const QJniObject &object)
+ {
+ return newLocalRef<T>(object.template object<T>());
+ }
+ JNIEnv *jniEnv() const
+ {
+ if (!env)
+ env = QJniEnvironment::getJniEnv();
+ return env;
+ }
+ bool checkAndClearExceptions()
+ {
+ return env ? QJniEnvironment::checkAndClearExceptions(env) : false;
+ }
+ template <typename T>
+ auto convertToJni(T &&value);
+ template <typename T>
+ auto convertFromJni(QJniObject &&object);
+ };
public:
QJniObject();
explicit QJniObject(const char *className);
@@ -27,9 +71,17 @@ public:
#endif
>
explicit QJniObject(const char *className, Args &&...args)
+ : QJniObject(LocalFrame<Args...>{}, className, std::forward<Args>(args)...)
+ {
+ }
+private:
+ template<typename ...Args>
+ explicit QJniObject(LocalFrame<Args...> localFrame, const char *className, Args &&...args)
: QJniObject(className, QtJniTypes::constructorSignature<Args...>().data(),
- std::forward<Args>(args)...)
- {}
+ localFrame.convertToJni(std::forward<Args>(args))...)
+ {
+ }
+public:
explicit QJniObject(jclass clazz);
explicit QJniObject(jclass clazz, const char *signature, ...);
template<typename ...Args
@@ -42,15 +94,21 @@ public:
std::forward<Args>(args)...)
{}
QJniObject(jobject globalRef);
- inline QJniObject(QtJniTypes::Object wrapper) noexcept : QJniObject(jobject(wrapper)) {}
+
+ QJniObject(const QJniObject &other) noexcept = default;
+ QJniObject(QJniObject &&other) noexcept = default;
+ QJniObject &operator=(const QJniObject &other) noexcept = default;
+ QJniObject &operator=(QJniObject &&other) noexcept = default;
+
~QJniObject();
template<typename Class, typename ...Args>
static inline QJniObject construct(Args &&...args)
{
- return QJniObject(QtJniTypes::className<Class>().data(),
+ LocalFrame<Args...> frame;
+ return QJniObject(QtJniTypes::Traits<Class>::className().data(),
QtJniTypes::constructorSignature<Args...>().data(),
- std::forward<Args>(args)...);
+ frame.convertToJni(std::forward<Args>(args))...);
}
jobject object() const;
@@ -63,49 +121,61 @@ public:
jclass objectClass() const;
QByteArray className() const;
- template <typename Ret, typename ...Args>
+ template <typename Ret, typename ...Args
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidFieldType<Ret> = true
+#endif
+ >
auto callMethod(const char *methodName, const char *signature, Args &&...args) const
{
+ LocalFrame<Args...> frame(jniEnv());
if constexpr (QtJniTypes::isObjectType<Ret>()) {
- return callObjectMethod(methodName, signature, std::forward<Args>(args)...);
+ return frame.template convertFromJni<Ret>(callObjectMethod(methodName, signature,
+ frame.convertToJni(std::forward<Args>(args))...));
} else {
- QtJniTypes::assertPrimitiveType<Ret>();
- QJniEnvironment env;
- jmethodID id = getCachedMethodID(env.jniEnv(), methodName, signature);
+ jmethodID id = getCachedMethodID(frame.jniEnv(), methodName, signature);
if (id) {
- if constexpr (std::is_same<Ret, void>::value) {
- callVoidMethodV(env.jniEnv(), id, std::forward<Args>(args)...);
- env.checkAndClearExceptions();
+ if constexpr (std::is_same_v<Ret, void>) {
+ callVoidMethodV(frame.jniEnv(), id,
+ frame.convertToJni(std::forward<Args>(args))...);
+ frame.checkAndClearExceptions();
} else {
Ret res{};
- callMethodForType<Ret>(env.jniEnv(), res, object(), id, std::forward<Args>(args)...);
- if (env.checkAndClearExceptions())
+ callMethodForType<Ret>(frame.jniEnv(), res, object(), id,
+ frame.convertToJni(std::forward<Args>(args))...);
+ if (frame.checkAndClearExceptions())
res = {};
return res;
}
}
- if constexpr (!std::is_same<Ret, void>::value)
+ if constexpr (!std::is_same_v<Ret, void>)
return Ret{};
}
}
- template <typename Ret, typename ...Args>
+ template <typename Ret, typename ...Args
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
+#endif
+ >
auto callMethod(const char *methodName, Args &&...args) const
{
constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>();
- if constexpr (std::is_same<Ret, void>::value) {
- callMethod<void>(methodName, signature.data(), std::forward<Args>(args)...);
- } else {
- return callMethod<Ret>(methodName, signature.data(), std::forward<Args>(args)...);
- }
+ return callMethod<Ret>(methodName, signature.data(), std::forward<Args>(args)...);
}
- template <typename Ret, typename ...Args>
+ template <typename Ret, typename ...Args
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
+#endif
+ >
QJniObject callObjectMethod(const char *methodName, Args &&...args) const
{
QtJniTypes::assertObjectType<Ret>();
constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>();
- return callObjectMethod(methodName, signature.data(), std::forward<Args>(args)...);
+ LocalFrame<Args...> frame(jniEnv());
+ return frame.template convertFromJni<Ret>(callObjectMethod(methodName, signature,
+ frame.convertToJni(std::forward<Args>(args))...));
}
QJniObject callObjectMethod(const char *methodName, const char *signature, ...) const;
@@ -113,58 +183,91 @@ public:
template <typename Ret, typename ...Args>
static auto callStaticMethod(const char *className, const char *methodName, const char *signature, Args &&...args)
{
- QJniEnvironment env;
- jclass clazz = QJniObject::loadClass(className, env.jniEnv());
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ jclass clazz = QJniObject::loadClass(className, env);
return callStaticMethod<Ret>(clazz, methodName, signature, std::forward<Args>(args)...);
}
template <typename Ret, typename ...Args>
static auto callStaticMethod(jclass clazz, const char *methodName, const char *signature, Args &&...args)
{
- QJniEnvironment env;
- jmethodID id = getMethodID(env.jniEnv(), clazz, methodName, signature, true);
- return callStaticMethod<Ret, Args...>(clazz, id, std::forward<Args>(args)...);
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ jmethodID id = clazz ? getMethodID(env, clazz, methodName, signature, true)
+ : 0;
+ return callStaticMethod<Ret>(clazz, id, std::forward<Args>(args)...);
}
- template <typename Ret, typename ...Args>
+ template <typename Ret, typename ...Args
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidFieldType<Ret> = true
+#endif
+ >
static auto callStaticMethod(jclass clazz, jmethodID methodId, Args &&...args)
{
+ LocalFrame<Args...> frame;
if constexpr (QtJniTypes::isObjectType<Ret>()) {
- return callStaticObjectMethod(clazz, methodId, std::forward<Args>(args)...);
+ return frame.template convertFromJni<Ret>(callStaticObjectMethod(clazz, methodId,
+ frame.convertToJni(std::forward<Args>(args))...));
} else {
- QtJniTypes::assertPrimitiveType<Ret>();
- QJniEnvironment env;
if (clazz && methodId) {
- if constexpr (std::is_same<Ret, void>::value) {
- callStaticMethodForVoid(env.jniEnv(), clazz, methodId, std::forward<Args>(args)...);
- env.checkAndClearExceptions();
+ if constexpr (std::is_same_v<Ret, void>) {
+ callStaticMethodForVoid(frame.jniEnv(), clazz, methodId,
+ frame.convertToJni(std::forward<Args>(args))...);
+ frame.checkAndClearExceptions();
} else {
Ret res{};
- callStaticMethodForType<Ret>(env.jniEnv(), res, clazz, methodId, std::forward<Args>(args)...);
- if (env.checkAndClearExceptions())
+ callStaticMethodForType<Ret>(frame.jniEnv(), res, clazz, methodId,
+ frame.convertToJni(std::forward<Args>(args))...);
+ if (frame.checkAndClearExceptions())
res = {};
return res;
}
}
- if constexpr (!std::is_same<Ret, void>::value)
+ if constexpr (!std::is_same_v<Ret, void>)
return Ret{};
}
}
- template <typename Ret, typename ...Args>
+ template <typename Ret, typename ...Args
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
+#endif
+ >
static auto callStaticMethod(const char *className, const char *methodName, Args &&...args)
{
- QJniEnvironment env;
- jclass clazz = QJniObject::loadClass(className, env.jniEnv());
- return callStaticMethod<Ret, Args...>(clazz, methodName, std::forward<Args>(args)...);
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ jclass clazz = QJniObject::loadClass(className, env);
+ const jmethodID id = clazz ? getMethodID(env, clazz, methodName,
+ QtJniTypes::methodSignature<Ret, Args...>().data(), true)
+ : 0;
+ return callStaticMethod<Ret>(clazz, id, std::forward<Args>(args)...);
}
- template <typename Ret, typename ...Args>
+ template <typename Ret, typename ...Args
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
+#endif
+ >
static auto callStaticMethod(jclass clazz, const char *methodName, Args &&...args)
{
constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>();
return callStaticMethod<Ret>(clazz, methodName, signature.data(), std::forward<Args>(args)...);
}
+ template <typename Klass, typename Ret, typename ...Args
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
+#endif
+ >
+ static auto callStaticMethod(const char *methodName, Args &&...args)
+ {
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ const jclass clazz = QJniObject::loadClass(QtJniTypes::Traits<Klass>::className().data(),
+ env);
+ const jmethodID id = clazz ? getMethodID(env, clazz, methodName,
+ QtJniTypes::methodSignature<Ret, Args...>().data(), true)
+ : 0;
+ return callStaticMethod<Ret>(clazz, id, std::forward<Args>(args)...);
+ }
static QJniObject callStaticObjectMethod(const char *className, const char *methodName,
const char *signature, ...);
@@ -175,109 +278,128 @@ public:
static QJniObject callStaticObjectMethod(jclass clazz, jmethodID methodId, ...);
- template <typename Ret, typename ...Args>
+ template <typename Ret, typename ...Args
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
+#endif
+ >
static QJniObject callStaticObjectMethod(const char *className, const char *methodName, Args &&...args)
{
QtJniTypes::assertObjectType<Ret>();
constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>();
- return callStaticObjectMethod(className, methodName, signature.data(), std::forward<Args>(args)...);
+ LocalFrame<Args...> frame;
+ return frame.template convertFromJni<Ret>(callStaticObjectMethod(className, methodName, signature.data(),
+ frame.convertToJni(std::forward<Args>(args))...));
}
- template <typename Ret, typename ...Args>
+ template <typename Ret, typename ...Args
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
+#endif
+ >
static QJniObject callStaticObjectMethod(jclass clazz, const char *methodName, Args &&...args)
{
QtJniTypes::assertObjectType<Ret>();
constexpr auto signature = QtJniTypes::methodSignature<Ret, Args...>();
- return callStaticObjectMethod(clazz, methodName, signature.data(), std::forward<Args>(args)...);
+ LocalFrame<Args...> frame;
+ return frame.template convertFromJni<Ret>(callStaticObjectMethod(clazz, methodName, signature.data(),
+ frame.convertToJni(std::forward<Args>(args))...));
}
- template <typename T> auto getField(const char *fieldName) const
+ template <typename T
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidFieldType<T> = true
+#endif
+ >
+ auto getField(const char *fieldName) const
{
+ LocalFrame<T> frame(jniEnv());
if constexpr (QtJniTypes::isObjectType<T>()) {
- return getObjectField<T>(fieldName);
+ return frame.template convertFromJni<T>(getObjectField<T>(fieldName));
} else {
- QtJniTypes::assertPrimitiveType<T>();
- QJniEnvironment env;
T res{};
constexpr auto signature = QtJniTypes::fieldSignature<T>();
- jfieldID id = getCachedFieldID(env.jniEnv(), fieldName, signature);
+ jfieldID id = getCachedFieldID(frame.jniEnv(), fieldName, signature);
if (id) {
- getFieldForType<T>(env.jniEnv(), res, object(), id);
- if (env.checkAndClearExceptions())
+ getFieldForType<T>(frame.jniEnv(), res, object(), id);
+ if (frame.checkAndClearExceptions())
res = {};
}
return res;
}
}
- template <typename T>
+ template <typename T
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidFieldType<T> = true
+#endif
+ >
static auto getStaticField(const char *className, const char *fieldName)
{
+ LocalFrame<T> frame;
if constexpr (QtJniTypes::isObjectType<T>()) {
- return getStaticObjectField<T>(className, fieldName);
+ return frame.template convertFromJni<T>(getStaticObjectField<T>(className, fieldName));
} else {
- QtJniTypes::assertPrimitiveType<T>();
- QJniEnvironment env;
- jclass clazz = QJniObject::loadClass(className, env.jniEnv());
- T res{};
+ jclass clazz = QJniObject::loadClass(className, frame.jniEnv());
if (!clazz)
- return res;
-
- constexpr auto signature = QtJniTypes::fieldSignature<T>();
- jfieldID id = getCachedFieldID(env.jniEnv(), clazz,
- QJniObject::toBinaryEncClassName(className),
- fieldName,
- signature, true);
- if (!id)
- return res;
-
- getStaticFieldForType<T>(env.jniEnv(), res, clazz, id);
- if (env.checkAndClearExceptions())
- res = {};
- return res;
+ return T{};
+ return getStaticField<T>(clazz, fieldName);
}
}
- template <typename T>
+ template <typename T
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidFieldType<T> = true
+#endif
+ >
static auto getStaticField(jclass clazz, const char *fieldName)
{
+ LocalFrame<T> frame;
if constexpr (QtJniTypes::isObjectType<T>()) {
- return getStaticObjectField<T>(clazz, fieldName);
+ return frame.template convertFromJni<T>(getStaticObjectField<T>(clazz, fieldName));
} else {
- QtJniTypes::assertPrimitiveType<T>();
- QJniEnvironment env;
T res{};
constexpr auto signature = QtJniTypes::fieldSignature<T>();
- jfieldID id = getFieldID(env.jniEnv(), clazz, fieldName, signature, true);
+ jfieldID id = getFieldID(frame.jniEnv(), clazz, fieldName, signature, true);
if (id) {
- getStaticFieldForType<T>(env.jniEnv(), res, clazz, id);
- if (env.checkAndClearExceptions())
+ getStaticFieldForType<T>(frame.jniEnv(), res, clazz, id);
+ if (frame.checkAndClearExceptions())
res = {};
}
return res;
}
}
- template <typename Klass, typename T>
+ template <typename Klass, typename T
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidFieldType<T> = true
+#endif
+ >
static auto getStaticField(const char *fieldName)
{
- return getStaticField<T>(QtJniTypes::className<Klass>(), fieldName);
+ return getStaticField<T>(QtJniTypes::Traits<Klass>::className(), fieldName);
}
- template <typename T>
+ template <typename T
+#ifndef Q_QDOC
+ , std::enable_if_t<QtJniTypes::isObjectType<T>(), bool> = true
+#endif
+ >
QJniObject getObjectField(const char *fieldName) const
{
- QtJniTypes::assertObjectType<T>();
constexpr auto signature = QtJniTypes::fieldSignature<T>();
return getObjectField(fieldName, signature);
}
QJniObject getObjectField(const char *fieldName, const char *signature) const;
- template <typename T>
+ template <typename T
+#ifndef Q_QDOC
+ , std::enable_if_t<QtJniTypes::isObjectType<T>(), bool> = true
+#endif
+ >
static QJniObject getStaticObjectField(const char *className, const char *fieldName)
{
- QtJniTypes::assertObjectType<T>();
constexpr auto signature = QtJniTypes::fieldSignature<T>();
return getStaticObjectField(className, fieldName, signature);
}
@@ -286,10 +408,13 @@ public:
const char *fieldName,
const char *signature);
- template <typename T>
+ template <typename T
+#ifndef Q_QDOC
+ , std::enable_if_t<QtJniTypes::isObjectType<T>(), bool> = true
+#endif
+ >
static QJniObject getStaticObjectField(jclass clazz, const char *fieldName)
{
- QtJniTypes::assertObjectType<T>();
constexpr auto signature = QtJniTypes::fieldSignature<T>();
return getStaticObjectField(clazz, fieldName, signature);
}
@@ -297,99 +422,114 @@ public:
static QJniObject getStaticObjectField(jclass clazz, const char *fieldName,
const char *signature);
- template <typename T> void setField(const char *fieldName, T value)
+ template <typename T
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidFieldType<T> = true
+#endif
+ >
+ void setField(const char *fieldName, T value)
{
- QtJniTypes::assertType<T>();
- QJniEnvironment env;
constexpr auto signature = QtJniTypes::fieldSignature<T>();
- jfieldID id = getCachedFieldID(env.jniEnv(), fieldName, signature);
+ jfieldID id = getCachedFieldID(jniEnv(), fieldName, signature);
if (id) {
- setFieldForType<T>(env.jniEnv(), object(), id, value);
- env.checkAndClearExceptions();
+ setFieldForType<T>(jniEnv(), object(), id, value);
+ QJniEnvironment::checkAndClearExceptions(jniEnv());
}
}
- template <typename T>
+ template <typename T
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidFieldType<T> = true
+#endif
+ >
void setField(const char *fieldName, const char *signature, T value)
{
- QtJniTypes::assertType<T>();
- QJniEnvironment env;
- jfieldID id = getCachedFieldID(env.jniEnv(), fieldName, signature);
+ jfieldID id = getCachedFieldID(jniEnv(), fieldName, signature);
if (id) {
- setFieldForType<T>(env.jniEnv(), object(), id, value);
- env.checkAndClearExceptions();
+ setFieldForType<T>(jniEnv(), object(), id, value);
+ QJniEnvironment::checkAndClearExceptions(jniEnv());
}
}
- template <typename T>
+ template <typename T
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidFieldType<T> = true
+#endif
+ >
static void setStaticField(const char *className, const char *fieldName, T value)
{
- QtJniTypes::assertType<T>();
- QJniEnvironment env;
- jclass clazz = QJniObject::loadClass(className, env.jniEnv());
+ LocalFrame<T> frame;
+ jclass clazz = QJniObject::loadClass(className, frame.jniEnv());
if (!clazz)
return;
constexpr auto signature = QtJniTypes::fieldSignature<T>();
- jfieldID id = getCachedFieldID(env.jniEnv(), clazz, className, fieldName,
+ jfieldID id = getCachedFieldID(frame.jniEnv(), clazz, className, fieldName,
signature, true);
if (!id)
return;
- setStaticFieldForType<T>(env.jniEnv(), clazz, id, value);
- env.checkAndClearExceptions();
+ setStaticFieldForType<T>(frame.jniEnv(), clazz, id, value);
+ frame.checkAndClearExceptions();
}
- template <typename T>
+ template <typename T
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidFieldType<T> = true
+#endif
+ >
static void setStaticField(const char *className, const char *fieldName,
const char *signature, T value)
{
- QtJniTypes::assertType<T>();
- QJniEnvironment env;
- jclass clazz = QJniObject::loadClass(className, env.jniEnv());
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ jclass clazz = QJniObject::loadClass(className, env);
if (!clazz)
return;
- jfieldID id = getCachedFieldID(env.jniEnv(), clazz, className, fieldName,
+ jfieldID id = getCachedFieldID(env, clazz, className, fieldName,
signature, true);
if (id) {
- setStaticFieldForType<T>(env.jniEnv(), clazz, id, value);
- env.checkAndClearExceptions();
+ setStaticFieldForType<T>(env, clazz, id, value);
+ QJniEnvironment::checkAndClearExceptions(env);
}
}
- template <typename T>
+ template <typename T
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidFieldType<T> = true
+#endif
+ >
static void setStaticField(jclass clazz, const char *fieldName,
const char *signature, T value)
{
- QtJniTypes::assertType<T>();
- QJniEnvironment env;
- jfieldID id = getFieldID(env.jniEnv(), clazz, fieldName, signature, true);
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ jfieldID id = getFieldID(env, clazz, fieldName, signature, true);
if (id) {
- setStaticFieldForType<T>(env.jniEnv(), clazz, id, value);
- env.checkAndClearExceptions();
+ setStaticFieldForType<T>(env, clazz, id, value);
+ QJniEnvironment::checkAndClearExceptions(env);
}
}
- template <typename T>
+ template <typename T
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidFieldType<T> = true
+#endif
+ >
static void setStaticField(jclass clazz, const char *fieldName, T value)
{
- QtJniTypes::assertType<T>();
- QJniEnvironment env;
- constexpr auto signature = QtJniTypes::fieldSignature<T>();
- jfieldID id = getFieldID(env.jniEnv(), clazz, fieldName, signature, true);
- if (id) {
- setStaticFieldForType<T>(env.jniEnv(), clazz, id, value);
- env.checkAndClearExceptions();
- }
+ setStaticField(clazz, fieldName, QtJniTypes::fieldSignature<T>(), value);
}
- template <typename Klass, typename T>
+ template <typename Klass, typename T
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidFieldType<T> = true
+#endif
+ >
static void setStaticField(const char *fieldName, T value)
{
- setStaticField(QtJniTypes::className<Klass>(), fieldName, value);
+ setStaticField(QtJniTypes::Traits<Klass>::className(), fieldName, value);
}
static QJniObject fromString(const QString &string);
@@ -401,21 +541,27 @@ public:
// This function takes ownership of the jobject and releases the local ref. before returning.
static QJniObject fromLocalRef(jobject lref);
- template <typename T> QJniObject &operator=(T obj)
+ template <typename T,
+ std::enable_if_t<std::is_convertible_v<T, jobject>, bool> = true>
+ QJniObject &operator=(T obj)
{
- QtJniTypes::assertType<T>();
assign(static_cast<T>(obj));
return *this;
}
+protected:
+ QJniObject(Qt::Initialization) {}
+ JNIEnv *jniEnv() const noexcept;
+
private:
- struct QVaListPrivate { operator va_list &() const { return m_args; } va_list &m_args; };
- QJniObject(const char *className, const char *signature, const QVaListPrivate &args);
- QJniObject(jclass clazz, const char *signature, const QVaListPrivate &args);
+ static jclass loadClass(const QByteArray &className, JNIEnv *env);
- static jclass loadClass(const QByteArray &className, JNIEnv *env, bool binEncoded = false);
+#if QT_CORE_REMOVED_SINCE(6, 7)
+ // these need to stay in the ABI as they were used in inline methods before 6.7
+ static jclass loadClass(const QByteArray &className, JNIEnv *env, bool binEncoded);
static QByteArray toBinaryEncClassName(const QByteArray &className);
- static QJniObject getCleanJniObject(jobject obj);
+ void callVoidMethodV(JNIEnv *env, jmethodID id, va_list args) const;
+#endif
static jfieldID getCachedFieldID(JNIEnv *env, jclass clazz, const QByteArray &className,
const char *name, const char *signature,
@@ -434,17 +580,6 @@ private:
const char *signature, bool isStatic = false);
void callVoidMethodV(JNIEnv *env, jmethodID id, ...) const;
- // ### Qt 7: merge into ... overload
- void callVoidMethodV(JNIEnv *env, jmethodID id, va_list args) const;
- // ### Qt 7: remove unused
- QJniObject callObjectMethodV(const char *methodName, const char *signature,
- va_list args) const;
- // ### Qt 7: remove unused
- static QJniObject callStaticObjectMethodV(const char *className, const char *methodName,
- const char *signature, va_list args);
- // ### Qt 7: remove unused
- static QJniObject callStaticObjectMethodV(jclass clazz, const char *methodName,
- const char *signature, va_list args);
bool isSameObject(jobject obj) const;
bool isSameObject(const QJniObject &other) const;
@@ -455,30 +590,11 @@ private:
friend bool operator!=(const QJniObject&, const QJniObject&);
template<typename T>
- static constexpr void callMethodForType(JNIEnv *env, T &res, jobject obj,
- jmethodID id, ...)
+ static constexpr void callMethodForType(JNIEnv *env, T &res, jobject obj, jmethodID id, ...)
{
va_list args = {};
va_start(args, id);
-
- if constexpr(std::is_same<T, jboolean>::value)
- res = env->CallBooleanMethodV(obj, id, args);
- else if constexpr(std::is_same<T, jbyte>::value)
- res = env->CallByteMethodV(obj, id, args);
- else if constexpr(std::is_same<T, jchar>::value)
- res = env->CallCharMethodV(obj, id, args);
- else if constexpr(std::is_same<T, jshort>::value)
- res = env->CallShortMethodV(obj, id, args);
- else if constexpr(std::is_same<T, jint>::value)
- res = env->CallIntMethodV(obj, id, args);
- else if constexpr(std::is_same<T, jlong>::value)
- res = env->CallLongMethodV(obj, id, args);
- else if constexpr(std::is_same<T, jfloat>::value)
- res = env->CallFloatMethodV(obj, id, args);
- else if constexpr(std::is_same<T, jdouble>::value)
- res = env->CallDoubleMethodV(obj, id, args);
- else
- QtJniTypes::staticAssertTypeMismatch();
+ QtJniTypes::Caller<T>::callMethodForType(env, res, obj, id, args);
va_end(args);
}
@@ -486,31 +602,18 @@ private:
static constexpr void callStaticMethodForType(JNIEnv *env, T &res, jclass clazz,
jmethodID id, ...)
{
+ if (!clazz || !id)
+ return;
va_list args = {};
va_start(args, id);
- if constexpr(std::is_same<T, jboolean>::value)
- res = env->CallStaticBooleanMethodV(clazz, id, args);
- else if constexpr(std::is_same<T, jbyte>::value)
- res = env->CallStaticByteMethodV(clazz, id, args);
- else if constexpr(std::is_same<T, jchar>::value)
- res = env->CallStaticCharMethodV(clazz, id, args);
- else if constexpr(std::is_same<T, jshort>::value)
- res = env->CallStaticShortMethodV(clazz, id, args);
- else if constexpr(std::is_same<T, jint>::value)
- res = env->CallStaticIntMethodV(clazz, id, args);
- else if constexpr(std::is_same<T, jlong>::value)
- res = env->CallStaticLongMethodV(clazz, id, args);
- else if constexpr(std::is_same<T, jfloat>::value)
- res = env->CallStaticFloatMethodV(clazz, id, args);
- else if constexpr(std::is_same<T, jdouble>::value)
- res = env->CallStaticDoubleMethodV(clazz, id, args);
- else
- QtJniTypes::staticAssertTypeMismatch();
+ QtJniTypes::Caller<T>::callStaticMethodForType(env, res, clazz, id, args);
va_end(args);
}
static void callStaticMethodForVoid(JNIEnv *env, jclass clazz, jmethodID id, ...)
{
+ if (!clazz || !id)
+ return;
va_list args;
va_start(args, id);
env->CallStaticVoidMethodV(clazz, id, args);
@@ -519,103 +622,37 @@ private:
template<typename T>
- static constexpr void getFieldForType(JNIEnv *env, T &res, jobject obj,
- jfieldID id)
- {
- if constexpr(std::is_same<T, jboolean>::value)
- res = env->GetBooleanField(obj, id);
- else if constexpr(std::is_same<T, jbyte>::value)
- res = env->GetByteField(obj, id);
- else if constexpr(std::is_same<T, jchar>::value)
- res = env->GetCharField(obj, id);
- else if constexpr(std::is_same<T, jshort>::value)
- res = env->GetShortField(obj, id);
- else if constexpr(std::is_same<T, jint>::value)
- res = env->GetIntField(obj, id);
- else if constexpr(std::is_same<T, jlong>::value)
- res = env->GetLongField(obj, id);
- else if constexpr(std::is_same<T, jfloat>::value)
- res = env->GetFloatField(obj, id);
- else if constexpr(std::is_same<T, jdouble>::value)
- res = env->GetDoubleField(obj, id);
- else
- QtJniTypes::staticAssertTypeMismatch();
+ static constexpr void getFieldForType(JNIEnv *env, T &res, jobject obj, jfieldID id)
+ {
+ QtJniTypes::Caller<T>::getFieldForType(env, res, obj, id);
}
template<typename T>
- static constexpr void getStaticFieldForType(JNIEnv *env, T &res, jclass clazz,
- jfieldID id)
- {
- if constexpr(std::is_same<T, jboolean>::value)
- res = env->GetStaticBooleanField(clazz, id);
- else if constexpr(std::is_same<T, jbyte>::value)
- res = env->GetStaticByteField(clazz, id);
- else if constexpr(std::is_same<T, jchar>::value)
- res = env->GetStaticCharField(clazz, id);
- else if constexpr(std::is_same<T, jshort>::value)
- res = env->GetStaticShortField(clazz, id);
- else if constexpr(std::is_same<T, jint>::value)
- res = env->GetStaticIntField(clazz, id);
- else if constexpr(std::is_same<T, jlong>::value)
- res = env->GetStaticLongField(clazz, id);
- else if constexpr(std::is_same<T, jfloat>::value)
- res = env->GetStaticFloatField(clazz, id);
- else if constexpr(std::is_same<T, jdouble>::value)
- res = env->GetStaticDoubleField(clazz, id);
- else
- QtJniTypes::staticAssertTypeMismatch();
+ static constexpr void getStaticFieldForType(JNIEnv *env, T &res, jclass clazz, jfieldID id)
+ {
+ QtJniTypes::Caller<T>::getStaticFieldForType(env, res, clazz, id);
}
template<typename T>
- static constexpr void setFieldForType(JNIEnv *env, jobject obj,
- jfieldID id, T value)
- {
- if constexpr(std::is_same<T, jboolean>::value)
- env->SetBooleanField(obj, id, value);
- else if constexpr(std::is_same<T, jbyte>::value)
- env->SetByteField(obj, id, value);
- else if constexpr(std::is_same<T, jchar>::value)
- env->SetCharField(obj, id, value);
- else if constexpr(std::is_same<T, jshort>::value)
- env->SetShortField(obj, id, value);
- else if constexpr(std::is_same<T, jint>::value)
- env->SetIntField(obj, id, value);
- else if constexpr(std::is_same<T, jlong>::value)
- env->SetLongField(obj, id, value);
- else if constexpr(std::is_same<T, jfloat>::value)
- env->SetFloatField(obj, id, value);
- else if constexpr(std::is_same<T, jdouble>::value)
- env->SetDoubleField(obj, id, value);
- else if constexpr(std::is_convertible<T, jobject>::value)
- env->SetObjectField(obj, id, value);
- else
- QtJniTypes::staticAssertTypeMismatch();
+ static constexpr void setFieldForType(JNIEnv *env, jobject obj, jfieldID id, T value)
+ {
+ if constexpr (QtJniTypes::isObjectType<T>()) {
+ LocalFrame<T> frame(env);
+ env->SetObjectField(obj, id, static_cast<jobject>(frame.convertToJni(value)));
+ } else {
+ QtJniTypes::Caller<T>::setFieldForType(env, obj, id, value);
+ }
}
template<typename T>
- static constexpr void setStaticFieldForType(JNIEnv *env, jclass clazz,
- jfieldID id, T value)
- {
- if constexpr(std::is_same<T, jboolean>::value)
- env->SetStaticBooleanField(clazz, id, value);
- else if constexpr(std::is_same<T, jbyte>::value)
- env->SetStaticByteField(clazz, id, value);
- else if constexpr(std::is_same<T, jchar>::value)
- env->SetStaticCharField(clazz, id, value);
- else if constexpr(std::is_same<T, jshort>::value)
- env->SetStaticShortField(clazz, id, value);
- else if constexpr(std::is_same<T, jint>::value)
- env->SetStaticIntField(clazz, id, value);
- else if constexpr(std::is_same<T, jlong>::value)
- env->SetStaticLongField(clazz, id, value);
- else if constexpr(std::is_same<T, jfloat>::value)
- env->SetStaticFloatField(clazz, id, value);
- else if constexpr(std::is_same<T, jdouble>::value)
- env->SetStaticDoubleField(clazz, id, value);
- else if constexpr(std::is_convertible<T, jobject>::value)
- env->SetStaticObjectField(clazz, id, value);
- else
- QtJniTypes::staticAssertTypeMismatch();
+ static constexpr void setStaticFieldForType(JNIEnv *env, jclass clazz, jfieldID id, T value)
+ {
+ if constexpr (QtJniTypes::isObjectType<T>()) {
+ LocalFrame<T> frame(env);
+ env->SetStaticObjectField(clazz, id, static_cast<jobject>(frame.convertToJni(value)));
+ } else {
+ QtJniTypes::Caller<T>::setStaticFieldForType(env, clazz, id, value);
+ }
}
friend QJniObjectPrivate;
@@ -632,6 +669,201 @@ inline bool operator!=(const QJniObject &obj1, const QJniObject &obj2)
return !obj1.isSameObject(obj2);
}
+namespace QtJniTypes {
+struct JObjectBase
+{
+ operator QJniObject() const { return m_object; }
+
+ bool isValid() const { return m_object.isValid(); }
+ jclass objectClass() const { return m_object.objectClass(); }
+ QString toString() const { return m_object.toString(); }
+
+ template <typename T = jobject>
+ T object() const {
+ return m_object.object<T>();
+ }
+
+protected:
+ JObjectBase() = default;
+ ~JObjectBase() = default;
+
+ Q_IMPLICIT JObjectBase(jobject object) : m_object(object) {}
+ Q_IMPLICIT JObjectBase(const QJniObject &object) : m_object(object) {}
+ Q_IMPLICIT JObjectBase(QJniObject &&object) noexcept : m_object(std::move(object)) {}
+
+ QJniObject m_object;
+};
+
+template<typename Type>
+class JObject : public JObjectBase
+{
+public:
+ using Class = Type;
+
+ JObject()
+ : JObjectBase{QJniObject(QtJniTypes::Traits<Class>::className())}
+ {}
+ Q_IMPLICIT JObject(jobject object) : JObjectBase(object) {}
+ Q_IMPLICIT JObject(const QJniObject &object) : JObjectBase(object) {}
+ Q_IMPLICIT JObject(QJniObject &&object) noexcept : JObjectBase(std::move(object)) {}
+
+ // base class destructor is protected, so need to provide all SMFs
+ JObject(const JObject &other) = default;
+ JObject(JObject &&other) noexcept = default;
+ JObject &operator=(const JObject &other) = default;
+ JObject &operator=(JObject &&other) noexcept = default;
+
+ ~JObject() = default;
+
+ template<typename Arg, typename ...Args
+ , std::enable_if_t<!std::is_same_v<Arg, JObject>, bool> = true
+ , IfValidSignatureTypes<Arg, Args...> = true
+ >
+ explicit JObject(Arg && arg, Args &&...args)
+ : JObjectBase{QJniObject(QtJniTypes::Traits<Class>::className(),
+ std::forward<Arg>(arg), std::forward<Args>(args)...)}
+ {}
+
+ // named constructors avoid ambiguities
+ static Type fromJObject(jobject object) { return Type(object); }
+ template <typename ...Args>
+ static Type construct(Args &&...args) { return Type(std::forward<Args>(args)...); }
+ static Type fromLocalRef(jobject lref) { return Type(QJniObject::fromLocalRef(lref)); }
+
+ static bool registerNativeMethods(std::initializer_list<JNINativeMethod> methods)
+ {
+ QJniEnvironment env;
+ return env.registerNativeMethods<Class>(methods);
+ }
+
+ // public API forwarding to QJniObject, with the implicit Class template parameter
+ template <typename Ret, typename ...Args
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
+#endif
+ >
+ static auto callStaticMethod(const char *name, Args &&...args)
+ {
+ return QJniObject::callStaticMethod<Class, Ret, Args...>(name,
+ std::forward<Args>(args)...);
+ }
+ template <typename T
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidFieldType<T> = true
+#endif
+ >
+ static auto getStaticField(const char *field)
+ {
+ return QJniObject::getStaticField<Class, T>(field);
+ }
+ template <typename T
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidFieldType<T> = true
+#endif
+ >
+ static void setStaticField(const char *field, T &&value)
+ {
+ QJniObject::setStaticField<Class, T>(field, std::forward<T>(value));
+ }
+
+ // keep only these overloads, the rest is made private
+ template <typename Ret, typename ...Args
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidSignatureTypes<Ret, Args...> = true
+#endif
+ >
+ auto callMethod(const char *method, Args &&...args) const
+ {
+ return m_object.callMethod<Ret>(method, std::forward<Args>(args)...);
+ }
+ template <typename T
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidFieldType<T> = true
+#endif
+ >
+ auto getField(const char *fieldName) const
+ {
+ return m_object.getField<T>(fieldName);
+ }
+
+ template <typename T
+#ifndef Q_QDOC
+ , QtJniTypes::IfValidFieldType<T> = true
+#endif
+ >
+ void setField(const char *fieldName, T &&value)
+ {
+ m_object.setField(fieldName, std::forward<T>(value));
+ }
+
+ QByteArray className() const {
+ return QtJniTypes::Traits<Class>::className().data();
+ }
+
+private:
+ friend bool comparesEqual(const JObject &lhs, const JObject &rhs) noexcept
+ { return lhs.m_object == rhs.m_object; }
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(JObject);
+};
+}
+
+// This cannot be included earlier as QJniArray is a QJniObject subclass, but it
+// must be included so that we can implement QJniObject::LocalFrame conversion.
+QT_END_NAMESPACE
+#include <QtCore/qjniarray.h>
+QT_BEGIN_NAMESPACE
+
+template <typename ...Args>
+template <typename T>
+auto QJniObject::LocalFrame<Args...>::convertToJni(T &&value)
+{
+ using Type = q20::remove_cvref_t<T>;
+ if constexpr (std::is_same_v<Type, QString>) {
+ return newLocalRef<jstring>(QJniObject::fromString(value));
+ } else if constexpr (QtJniTypes::IsJniArray<Type>::value) {
+ return value.arrayObject();
+ } else if constexpr (QJniArrayBase::canConvert<T>) {
+ using QJniArrayType = decltype(QJniArrayBase::fromContainer(std::forward<T>(value)));
+ using ArrayType = decltype(std::declval<QJniArrayType>().arrayObject());
+ return newLocalRef<ArrayType>(QJniArrayBase::fromContainer(std::forward<T>(value)).template object<jobject>());
+ } else if constexpr (std::is_base_of_v<QJniObject, Type>
+ || std::is_base_of_v<QtJniTypes::JObjectBase, Type>) {
+ return value.object();
+ } else {
+ return std::forward<T>(value);
+ }
+}
+
+template <typename ...Args>
+template <typename T>
+auto QJniObject::LocalFrame<Args...>::convertFromJni(QJniObject &&object)
+{
+ using Type = q20::remove_cvref_t<T>;
+ if constexpr (std::is_same_v<Type, QString>) {
+ return object.toString();
+ } else if constexpr (QtJniTypes::IsJniArray<Type>::value) {
+ return T(std::move(object));
+ } else if constexpr (QJniArrayBase::canConvert<Type>) {
+ // if we were to create a QJniArray from Type...
+ using QJniArrayType = decltype(QJniArrayBase::fromContainer(std::declval<Type>()));
+ // then that QJniArray would have elements of type
+ using ElementType = typename QJniArrayType::Type;
+ // construct a QJniArray from a jobject pointer of that type
+ return QJniArray<ElementType>(object.template object<jarray>()).toContainer();
+ } else if constexpr (std::is_array_v<Type>) {
+ using ElementType = std::remove_extent_t<Type>;
+ return QJniArray<ElementType>(std::move(object));
+ } else if constexpr (std::is_base_of_v<QJniObject, Type>
+ && !std::is_same_v<QJniObject, Type>) {
+ return T{std::move(object)};
+ } else if constexpr (std::is_base_of_v<QtJniTypes::JObjectBase, Type>) {
+ return T{std::move(object)};
+ } else {
+ return std::move(object);
+ }
+}
+
+
QT_END_NAMESPACE
#endif
diff --git a/src/corelib/kernel/qjnitypes.h b/src/corelib/kernel/qjnitypes.h
index 9c2e1efb77..1eaae6312b 100644
--- a/src/corelib/kernel/qjnitypes.h
+++ b/src/corelib/kernel/qjnitypes.h
@@ -4,374 +4,190 @@
#ifndef QJNITYPES_H
#define QJNITYPES_H
-#include <QtCore/qglobal.h>
-
#if defined(Q_QDOC) || defined(Q_OS_ANDROID)
-#include <jni.h>
-QT_BEGIN_NAMESPACE
+#include <QtCore/qjnitypes_impl.h>
+#include <QtCore/qjniobject.h>
-namespace QtJniTypes
-{
+QT_BEGIN_NAMESPACE
-// a constexpr type for string literals of any character width, aware of the length
-// of the string.
-template<size_t N_WITH_NULL, typename BaseType = char>
-struct String
-{
- BaseType m_data[N_WITH_NULL] = {};
+#define Q_DECLARE_JNI_TYPE_HELPER(Type) \
+namespace QtJniTypes { \
+struct Type : JObject<Type> \
+{ \
+ using JObject::JObject; \
+}; \
+} \
- constexpr String() noexcept {}
- // Can be instantiated (only) with a string literal
- constexpr explicit String(const BaseType (&data)[N_WITH_NULL]) noexcept
- {
- for (size_t i = 0; i < N_WITH_NULL - 1; ++i)
- m_data[i] = data[i];
- }
- constexpr BaseType at(size_t i) const { return m_data[i]; }
- constexpr BaseType operator[](size_t i) const { return at(i); }
- static constexpr size_t size() noexcept { return N_WITH_NULL; }
- constexpr operator const BaseType *() const noexcept { return m_data; }
- constexpr const BaseType *data() const noexcept { return m_data; }
- template<size_t N2_WITH_NULL>
- constexpr bool startsWith(const BaseType (&lit)[N2_WITH_NULL]) const noexcept
- {
- if constexpr (N2_WITH_NULL > N_WITH_NULL) {
- return false;
- } else {
- for (size_t i = 0; i < N2_WITH_NULL - 1; ++i) {
- if (m_data[i] != lit[i])
- return false;
- }
- }
- return true;
- }
- constexpr bool startsWith(BaseType c) const noexcept
- {
- return N_WITH_NULL > 1 && m_data[0] == c;
- }
- template<size_t N2_WITH_NULL>
- constexpr bool endsWith(const BaseType (&lit)[N2_WITH_NULL]) const noexcept
- {
- if constexpr (N2_WITH_NULL > N_WITH_NULL) {
- return false;
- } else {
- for (size_t i = 0; i < N2_WITH_NULL; ++i) {
- if (m_data[N_WITH_NULL - i - 1] != lit[N2_WITH_NULL - i - 1])
- return false;
- }
- }
- return true;
- }
- constexpr bool endsWith(BaseType c) const noexcept
- {
- return N_WITH_NULL > 1 && m_data[N_WITH_NULL - 2] == c;
- }
-
- template<size_t N2_WITH_NULL>
- friend inline constexpr bool operator==(const String<N_WITH_NULL> &lhs,
- const String<N2_WITH_NULL> &rhs) noexcept
- {
- if constexpr (N_WITH_NULL != N2_WITH_NULL) {
- return false;
- } else {
- for (size_t i = 0; i < N_WITH_NULL - 1; ++i) {
- if (lhs.at(i) != rhs.at(i))
- return false;
- }
- }
- return true;
- }
+#define Q_DECLARE_JNI_TYPE(Type, Signature) \
+Q_DECLARE_JNI_TYPE_HELPER(Type) \
+template<> \
+struct QtJniTypes::Traits<QtJniTypes::Type> { \
+ static constexpr auto signature() \
+ { \
+ static_assert((Signature[0] == 'L' \
+ || Signature[0] == '[') \
+ && Signature[sizeof(Signature) - 2] == ';', \
+ "Type signature needs to start with 'L' or" \
+ " '[' and end with ';'"); \
+ return QtJniTypes::CTString(Signature); \
+ } \
+}; \
- template<size_t N2_WITH_NULL>
- friend inline constexpr bool operator!=(const String<N_WITH_NULL> &lhs,
- const String<N2_WITH_NULL> &rhs) noexcept
- {
- return !operator==(lhs, rhs);
- }
+#define Q_DECLARE_JNI_CLASS(Type, Signature) \
+Q_DECLARE_JNI_TYPE_HELPER(Type) \
+template<> \
+struct QtJniTypes::Traits<QtJniTypes::Type> { \
+ static constexpr auto className() \
+ { \
+ return QtJniTypes::CTString(Signature); \
+ } \
+ static constexpr auto signature() \
+ { \
+ return QtJniTypes::CTString("L") \
+ + className() \
+ + QtJniTypes::CTString(";"); \
+ } \
+}; \
- template<size_t N2_WITH_NULL>
- friend inline constexpr bool operator==(const String<N_WITH_NULL> &lhs,
- const BaseType (&rhs)[N2_WITH_NULL]) noexcept
- {
- return operator==(lhs, String<N2_WITH_NULL>(rhs));
- }
- template<size_t N2_WITH_NULL>
- friend inline constexpr bool operator==(const BaseType (&lhs)[N2_WITH_NULL],
- const String<N_WITH_NULL> &rhs) noexcept
+// Macros for native methods
+
+namespace QtJniMethods {
+namespace Detail {
+// Various helpers to forward a call from a variadic argument function to
+// the real function with proper type conversion. This is needed because we
+// want to write functions that take QJniObjects (subclasses), while Java
+// can only call functions that take jobjects.
+
+// In Var-arg functions, any argument narrower than (unsigned) int or double
+// is promoted to (unsigned) int or double.
+template <typename Arg> struct PromotedType { using Type = Arg; };
+template <> struct PromotedType<bool> { using Type = int; };
+template <> struct PromotedType<char> { using Type = int; };
+template <> struct PromotedType<signed char> { using Type = int; };
+template <> struct PromotedType<unsigned char> { using Type = unsigned int; };
+template <> struct PromotedType<short> { using Type = int; };
+template <> struct PromotedType<unsigned short> { using Type = unsigned int; };
+template <> struct PromotedType<float> { using Type = double; };
+
+// Map any QJniObject type to jobject; that's what's on the va_list
+template <typename Arg>
+struct JNITypeForArgImpl
+{
+ using Type = std::conditional_t<std::disjunction_v<std::is_base_of<QJniObject, Arg>,
+ std::is_base_of<QtJniTypes::JObjectBase, Arg>>,
+ jobject, typename PromotedType<Arg>::Type>;
+ static Arg fromVarArg(Type t)
{
- return operator==(String<N2_WITH_NULL>(lhs), rhs);
+ return static_cast<Arg>(t);
}
+};
- template<size_t N2_WITH_NULL>
- friend inline constexpr bool operator!=(const String<N_WITH_NULL> &lhs,
- const BaseType (&rhs)[N2_WITH_NULL]) noexcept
- {
- return operator!=(lhs, String<N2_WITH_NULL>(rhs));
- }
- template<size_t N2_WITH_NULL>
- friend inline constexpr bool operator!=(const BaseType (&lhs)[N2_WITH_NULL],
- const String<N_WITH_NULL> &rhs) noexcept
- {
- return operator!=(String<N2_WITH_NULL>(lhs), rhs);
- }
+template <>
+struct JNITypeForArgImpl<QString>
+{
+ using Type = jstring;
- template<size_t N2_WITH_NULL>
- friend inline constexpr auto operator+(const String<N_WITH_NULL> &lhs,
- const String<N2_WITH_NULL> &rhs) noexcept
+ static QString fromVarArg(Type t)
{
- char data[N_WITH_NULL + N2_WITH_NULL - 1] = {};
- for (size_t i = 0; i < N_WITH_NULL - 1; ++i)
- data[i] = lhs[i];
- for (size_t i = 0; i < N2_WITH_NULL - 1; ++i)
- data[N_WITH_NULL - 1 + i] = rhs[i];
- return String<N_WITH_NULL + N2_WITH_NULL - 1>(data);
+ return QJniObject(t).toString();
}
};
-
-// Helper types that allow us to disable variadic overloads that would conflict
-// with overloads that take a const char*.
-template<typename T, size_t N = 0> struct IsStringType : std::false_type {};
-template<> struct IsStringType<const char*, 0> : std::true_type {};
-template<size_t N> struct IsStringType<String<N>> : std::true_type {};
-template<size_t N> struct IsStringType<const char[N]> : std::true_type {};
-
-template<bool flag = false>
-static void staticAssertTypeMismatch()
+template <typename T>
+struct JNITypeForArgImpl<QJniArray<T>>
{
- static_assert(flag, "The used type is not supported by this template call. "
- "Use a JNI based type instead.");
-}
+ using Type = jobject;
-template<typename T>
-constexpr auto typeSignature()
-{
- if constexpr(std::is_array_v<T>) {
- using UnderlyingType = typename std::remove_extent<T>::type;
- static_assert(!std::is_array_v<UnderlyingType>,
- "typeSignature() does not handle multi-dimensional arrays");
- return String("[") + typeSignature<UnderlyingType>();
- } else if constexpr(std::is_same_v<T, jobject>) {
- return String("Ljava/lang/Object;");
- } else if constexpr(std::is_same_v<T, jclass>) {
- return String("Ljava/lang/Class;");
- } else if constexpr(std::is_same_v<T, jstring>) {
- return String("Ljava/lang/String;");
- } else if constexpr(std::is_same_v<T, jobjectArray>) {
- return String("[Ljava/lang/Object;");
- } else if constexpr(std::is_same_v<T, jthrowable>) {
- return String("Ljava/lang/Throwable;");
- } else if constexpr(std::is_same_v<T, jbooleanArray>) {
- return String("[Z");
- } else if constexpr(std::is_same_v<T, jbyteArray>) {
- return String("[B");
- } else if constexpr(std::is_same_v<T, jshortArray>) {
- return String("[S");
- } else if constexpr(std::is_same_v<T, jintArray>) {
- return String("[I");
- } else if constexpr(std::is_same_v<T, jlongArray>) {
- return String("[J");
- } else if constexpr(std::is_same_v<T, jfloatArray>) {
- return String("[F");
- } else if constexpr(std::is_same_v<T, jdoubleArray>) {
- return String("[D");
- } else if constexpr(std::is_same_v<T, jcharArray>) {
- return String("[C");
- } else if constexpr(std::is_same_v<T, jboolean>) {
- return String("Z");
- } else if constexpr(std::is_same_v<T, bool>) {
- return String("Z");
- } else if constexpr(std::is_same_v<T, jbyte>) {
- return String("B");
- } else if constexpr(std::is_same_v<T, jchar>) {
- return String("C");
- } else if constexpr(std::is_same_v<T, char>) {
- return String("C");
- } else if constexpr(std::is_same_v<T, jshort>) {
- return String("S");
- } else if constexpr(std::is_same_v<T, short>) {
- return String("S");
- } else if constexpr(std::is_same_v<T, jint>) {
- return String("I");
- } else if constexpr(std::is_same_v<T, int>) {
- return String("I");
- } else if constexpr(std::is_same_v<T, uint>) {
- return String("I");
- } else if constexpr(std::is_same_v<T, jlong>) {
- return String("J");
- } else if constexpr(std::is_same_v<T, long>) {
- return String("J");
- } else if constexpr(std::is_same_v<T, jfloat>) {
- return String("F");
- } else if constexpr(std::is_same_v<T, float>) {
- return String("F");
- } else if constexpr(std::is_same_v<T, jdouble>) {
- return String("D");
- } else if constexpr(std::is_same_v<T, double>) {
- return String("D");
- } else if constexpr(std::is_same_v<T, void>) {
- return String("V");
- } else if constexpr(IsStringType<T>::value) {
- static_assert(!IsStringType<T>::value, "Don't use a literal type, call data!");
- } else {
- staticAssertTypeMismatch();
+ static QJniArray<T> fromVarArg(Type t)
+ {
+ return QJniArray<T>(t);
}
-}
-
-template<bool flag = false>
-static void staticAssertClassNotRegistered()
-{
- static_assert(flag, "Class not registered, use Q_DECLARE_JNI_CLASS");
-}
-
-template<typename T>
-constexpr auto className()
-{
- if constexpr(std::is_same<T, jstring>::value)
- return String("java/lang/String");
- else
- staticAssertClassNotRegistered();
-}
+};
-template<typename T>
-static constexpr bool isPrimitiveType()
+template <typename T>
+struct JNITypeForArgImpl<QList<T>>
{
- return typeSignature<T>().size() == 2;
-}
+private:
+ using ArrayType = decltype(QJniArrayBase::fromContainer(std::declval<QList<T>>()));
+ using ArrayObjectType = decltype(std::declval<ArrayType>().arrayObject());
+ using ElementType = typename ArrayType::value_type;
+public:
+ using Type = ArrayObjectType;
-template<typename T>
-static constexpr bool isObjectType()
-{
- if constexpr(std::is_convertible<T, jobject>::value) {
- return true;
- } else {
- constexpr auto signature = typeSignature<T>();
- return (signature.startsWith('L') || signature.startsWith('['))
- && signature.endsWith(';');
+ static QList<T> fromVarArg(Type t)
+ {
+ return QJniArray<ElementType>(t).toContainer();
}
-}
-
-template<typename T>
-static constexpr bool isArrayType()
-{
- constexpr auto signature = typeSignature<T>();
- return signature.startsWith('[');
-}
-
-template<typename T>
-static constexpr void assertPrimitiveType()
-{
- static_assert(isPrimitiveType<T>(), "Type needs to be a primitive JNI type!");
-}
-
-template<typename T>
-static constexpr void assertObjectType()
-{
- static_assert(isObjectType<T>(),
- "Type needs to be a JNI object type (convertible to jobject, or with "
- "an object type signature registered)!");
-}
-
-template<typename T>
-static constexpr void assertType()
-{
- static_assert(isPrimitiveType<T>() || isObjectType<T>(),
- "Type needs to be a JNI type!");
-}
+};
-template<typename R, typename ...Args>
-static constexpr auto methodSignature()
+template <typename Arg>
+using JNITypeForArg = typename JNITypeForArgImpl<std::decay_t<Arg>>::Type;
+template <typename Arg, typename Type>
+static inline auto methodArgFromVarArg(Type t) // Type comes from a va_arg, so is always POD
{
- return (String("(") +
- ... + typeSignature<std::decay_t<Args>>())
- + String(")")
- + typeSignature<R>();
+ return JNITypeForArgImpl<std::decay_t<Arg>>::fromVarArg(t);
}
-template<typename T>
-static constexpr auto fieldSignature()
+// Turn a va_list into a tuple of typed arguments
+template <typename ...Args>
+static constexpr auto makeTupleFromArgsHelper(va_list args)
{
- return QtJniTypes::typeSignature<T>();
+ return std::tuple(methodArgFromVarArg<Args>(va_arg(args, JNITypeForArg<Args>))...);
}
-template<typename ...Args>
-static constexpr auto constructorSignature()
+template <typename Ret, typename ...Args>
+static constexpr auto makeTupleFromArgs(Ret (*)(JNIEnv *, jobject, Args...), va_list args)
{
- return methodSignature<void, Args...>();
+ return makeTupleFromArgsHelper<Args...>(args);
}
-
-template<typename Ret, typename ...Args>
-static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jobject, Args...))
+template <typename Ret, typename ...Args>
+static constexpr auto makeTupleFromArgs(Ret (*)(JNIEnv *, jclass, Args...), va_list args)
{
- return methodSignature<Ret, Args...>();
+ return makeTupleFromArgsHelper<Args...>(args);
}
-template<typename Ret, typename ...Args>
-static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jclass, Args...))
+// Get the return type of a function point
+template <typename Ret, typename ...Args>
+auto nativeFunctionReturnType(Ret(*function)(Args...))
{
- return methodSignature<Ret, Args...>();
+ return function(std::declval<Args>()...);
}
-// A generic thin wrapper around jobject, convertible to jobject.
-// We need this as a baseclass so that QJniObject can be implicitly
-// constructed from the various subclasses - we can't provide an
-// operator QJniObject() here as the class is not declared.
-struct Object
-{
- jobject _object;
- constexpr operator jobject() const { return _object; }
-};
-
-} // namespace QtJniTypes
-
-#define Q_DECLARE_JNI_TYPE_HELPER(Type) \
-namespace QtJniTypes { \
-struct Type : Object \
-{ \
- constexpr Type(jobject o) noexcept : Object{o} {} \
-}; \
-} \
-
-
-#define Q_DECLARE_JNI_TYPE(Type, Signature) \
-Q_DECLARE_JNI_TYPE_HELPER(Type) \
-template<> \
-constexpr auto QtJniTypes::typeSignature<QtJniTypes::Type>() \
-{ \
- static_assert((Signature[0] == 'L' || Signature[0] == '[') \
- && Signature[sizeof(Signature) - 2] == ';', \
- "Type signature needs to start with 'L' or '['" \
- " and end with ';'"); \
- return QtJniTypes::String(Signature); \
-} \
-
-#define Q_DECLARE_JNI_CLASS(Type, Signature) \
-Q_DECLARE_JNI_TYPE_HELPER(Type) \
-template<> \
-constexpr auto QtJniTypes::className<QtJniTypes::Type>() \
-{ \
- return QtJniTypes::String(Signature); \
-} \
-template<> \
-constexpr auto QtJniTypes::typeSignature<QtJniTypes::Type>() \
-{ \
- return QtJniTypes::String("L") \
- + QtJniTypes::String(Signature) \
- + QtJniTypes::String(";"); \
-} \
-
-#define Q_DECLARE_JNI_NATIVE_METHOD(...) \
+} // namespace Detail
+} // namespace QtJniMethods
+
+// A va_ variadic arguments function that we register with JNI as a proxy
+// for the function we have. This function uses the helpers to unpack the
+// variadic arguments into a tuple of typed arguments, which we then call
+// the actual function with. This then takes care of implicit conversions,
+// e.g. a jobject becomes a QJniObject.
+#define Q_DECLARE_JNI_NATIVE_METHOD_HELPER(Method) \
+static decltype(QtJniMethods::Detail::nativeFunctionReturnType(Method)) \
+va_##Method(JNIEnv *env, jclass thiz, ...) \
+{ \
+ va_list args; \
+ va_start(args, thiz); \
+ auto va_cleanup = qScopeGuard([&args]{ va_end(args); }); \
+ auto argTuple = QtJniMethods::Detail::makeTupleFromArgs(Method, args); \
+ return std::apply([env, thiz](auto &&... args) { \
+ return Method(env, thiz, args...); \
+ }, argTuple); \
+} \
+
+
+#define Q_DECLARE_JNI_NATIVE_METHOD(...) \
QT_OVERLOADED_MACRO(QT_DECLARE_JNI_NATIVE_METHOD, __VA_ARGS__) \
#define QT_DECLARE_JNI_NATIVE_METHOD_2(Method, Name) \
namespace QtJniMethods { \
+Q_DECLARE_JNI_NATIVE_METHOD_HELPER(Method) \
static constexpr auto Method##_signature = \
QtJniTypes::nativeMethodSignature(Method); \
static const JNINativeMethod Method##_method = { \
#Name, Method##_signature.data(), \
- reinterpret_cast<void *>(Method) \
+ reinterpret_cast<void *>(va_##Method) \
}; \
} \
@@ -384,9 +200,10 @@ static const JNINativeMethod Method##_method = { \
QT_OVERLOADED_MACRO(QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE, __VA_ARGS__) \
#define QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_2(Method, Name) \
+ Q_DECLARE_JNI_NATIVE_METHOD_HELPER(Method) \
static inline constexpr auto Method##_signature = QtJniTypes::nativeMethodSignature(Method); \
static inline const JNINativeMethod Method##_method = { \
- #Name, Method##_signature.data(), reinterpret_cast<void *>(Method) \
+ #Name, Method##_signature.data(), reinterpret_cast<void *>(va_##Method) \
};
#define QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_1(Method) \
@@ -396,6 +213,6 @@ static const JNINativeMethod Method##_method = { \
QT_END_NAMESPACE
-#endif
+#endif // defined(Q_QDOC) || defined(Q_OS_ANDROID)
#endif // QJNITYPES_H
diff --git a/src/corelib/kernel/qjnitypes_impl.h b/src/corelib/kernel/qjnitypes_impl.h
new file mode 100644
index 0000000000..d963509023
--- /dev/null
+++ b/src/corelib/kernel/qjnitypes_impl.h
@@ -0,0 +1,373 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QJNITYPES_IMPL_H
+#define QJNITYPES_IMPL_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/q20type_traits.h>
+
+#if defined(Q_QDOC) || defined(Q_OS_ANDROID)
+#include <jni.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtJniTypes
+{
+
+// a constexpr type for string literals of any character width, aware of the length
+// of the string.
+template<size_t N_WITH_NULL, typename BaseType = char>
+struct CTString
+{
+ BaseType m_data[N_WITH_NULL] = {};
+
+ constexpr CTString() noexcept {}
+ // Can be instantiated (only) with a string literal
+ constexpr explicit CTString(const BaseType (&data)[N_WITH_NULL]) noexcept
+ {
+ for (size_t i = 0; i < N_WITH_NULL - 1; ++i)
+ m_data[i] = data[i];
+ }
+
+ constexpr BaseType at(size_t i) const { return m_data[i]; }
+ constexpr BaseType operator[](size_t i) const { return at(i); }
+ static constexpr size_t size() noexcept { return N_WITH_NULL; }
+ constexpr operator const BaseType *() const noexcept { return m_data; }
+ constexpr const BaseType *data() const noexcept { return m_data; }
+ template<size_t N2_WITH_NULL>
+ constexpr bool startsWith(const BaseType (&lit)[N2_WITH_NULL]) const noexcept
+ {
+ if constexpr (N2_WITH_NULL > N_WITH_NULL) {
+ return false;
+ } else {
+ for (size_t i = 0; i < N2_WITH_NULL - 1; ++i) {
+ if (m_data[i] != lit[i])
+ return false;
+ }
+ }
+ return true;
+ }
+ constexpr bool startsWith(BaseType c) const noexcept
+ {
+ return N_WITH_NULL > 1 && m_data[0] == c;
+ }
+ template<size_t N2_WITH_NULL>
+ constexpr bool endsWith(const BaseType (&lit)[N2_WITH_NULL]) const noexcept
+ {
+ if constexpr (N2_WITH_NULL > N_WITH_NULL) {
+ return false;
+ } else {
+ for (size_t i = 0; i < N2_WITH_NULL; ++i) {
+ if (m_data[N_WITH_NULL - i - 1] != lit[N2_WITH_NULL - i - 1])
+ return false;
+ }
+ }
+ return true;
+ }
+ constexpr bool endsWith(BaseType c) const noexcept
+ {
+ return N_WITH_NULL > 1 && m_data[N_WITH_NULL - 2] == c;
+ }
+
+ template<size_t N2_WITH_NULL>
+ friend inline constexpr bool operator==(const CTString<N_WITH_NULL> &lhs,
+ const CTString<N2_WITH_NULL> &rhs) noexcept
+ {
+ if constexpr (N_WITH_NULL != N2_WITH_NULL) {
+ return false;
+ } else {
+ for (size_t i = 0; i < N_WITH_NULL - 1; ++i) {
+ if (lhs.at(i) != rhs.at(i))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ template<size_t N2_WITH_NULL>
+ friend inline constexpr bool operator!=(const CTString<N_WITH_NULL> &lhs,
+ const CTString<N2_WITH_NULL> &rhs) noexcept
+ {
+ return !operator==(lhs, rhs);
+ }
+
+ template<size_t N2_WITH_NULL>
+ friend inline constexpr bool operator==(const CTString<N_WITH_NULL> &lhs,
+ const BaseType (&rhs)[N2_WITH_NULL]) noexcept
+ {
+ return operator==(lhs, CTString<N2_WITH_NULL>(rhs));
+ }
+ template<size_t N2_WITH_NULL>
+ friend inline constexpr bool operator==(const BaseType (&lhs)[N2_WITH_NULL],
+ const CTString<N_WITH_NULL> &rhs) noexcept
+ {
+ return operator==(CTString<N2_WITH_NULL>(lhs), rhs);
+ }
+
+ template<size_t N2_WITH_NULL>
+ friend inline constexpr bool operator!=(const CTString<N_WITH_NULL> &lhs,
+ const BaseType (&rhs)[N2_WITH_NULL]) noexcept
+ {
+ return operator!=(lhs, CTString<N2_WITH_NULL>(rhs));
+ }
+ template<size_t N2_WITH_NULL>
+ friend inline constexpr bool operator!=(const BaseType (&lhs)[N2_WITH_NULL],
+ const CTString<N_WITH_NULL> &rhs) noexcept
+ {
+ return operator!=(CTString<N2_WITH_NULL>(lhs), rhs);
+ }
+
+ template<size_t N2_WITH_NULL>
+ friend inline constexpr auto operator+(const CTString<N_WITH_NULL> &lhs,
+ const CTString<N2_WITH_NULL> &rhs) noexcept
+ {
+ char data[N_WITH_NULL + N2_WITH_NULL - 1] = {};
+ for (size_t i = 0; i < N_WITH_NULL - 1; ++i)
+ data[i] = lhs[i];
+ for (size_t i = 0; i < N2_WITH_NULL - 1; ++i)
+ data[N_WITH_NULL - 1 + i] = rhs[i];
+ return CTString<N_WITH_NULL + N2_WITH_NULL - 1>(data);
+ }
+};
+
+// Helper types that allow us to disable variadic overloads that would conflict
+// with overloads that take a const char*.
+template<typename T, size_t N = 0> struct IsStringType : std::false_type {};
+template<> struct IsStringType<const char *, 0> : std::true_type {};
+template<> struct IsStringType<const char *&, 0> : std::true_type {};
+template<size_t N> struct IsStringType<CTString<N>> : std::true_type {};
+template<size_t N> struct IsStringType<const char[N]> : std::true_type {};
+template<size_t N> struct IsStringType<const char(&)[N]> : std::true_type {};
+template<size_t N> struct IsStringType<char[N]> : std::true_type {};
+
+template <typename T>
+struct Traits {
+ // The return type of className/signature becomes void for any type
+ // not handled here. This indicates that the Traits type is not specialized
+ // for the respective type, which we use to detect invalid types in the
+ // IfValidSignatureTypes and IfValidFieldType predicates below.
+
+ static constexpr auto className()
+ {
+ if constexpr (std::is_same_v<T, jstring>)
+ return CTString("java/lang/String");
+ else if constexpr (std::is_same_v<T, jobject>)
+ return CTString("java/lang/Object");
+ else if constexpr (std::is_same_v<T, jclass>)
+ return CTString("java/lang/Class");
+ else if constexpr (std::is_same_v<T, jthrowable>)
+ return CTString("java/lang/Throwable");
+ // else: return void -> not implemented
+ }
+
+ static constexpr auto signature()
+ {
+ if constexpr (!std::is_same_v<decltype(className()), void>) {
+ // the type signature of any object class is L<className>;
+ return CTString("L") + className() + CTString(";");
+ } else if constexpr (std::is_array_v<T>) {
+ using UnderlyingType = typename std::remove_extent_t<T>;
+ static_assert(!std::is_array_v<UnderlyingType>,
+ "Traits::signature() does not handle multi-dimensional arrays");
+ return CTString("[") + Traits<UnderlyingType>::signature();
+ } else if constexpr (std::is_same_v<T, jobjectArray>) {
+ return CTString("[Ljava/lang/Object;");
+ } else if constexpr (std::is_same_v<T, jbooleanArray>) {
+ return CTString("[Z");
+ } else if constexpr (std::is_same_v<T, jbyteArray>) {
+ return CTString("[B");
+ } else if constexpr (std::is_same_v<T, jshortArray>) {
+ return CTString("[S");
+ } else if constexpr (std::is_same_v<T, jintArray>) {
+ return CTString("[I");
+ } else if constexpr (std::is_same_v<T, jlongArray>) {
+ return CTString("[J");
+ } else if constexpr (std::is_same_v<T, jfloatArray>) {
+ return CTString("[F");
+ } else if constexpr (std::is_same_v<T, jdoubleArray>) {
+ return CTString("[D");
+ } else if constexpr (std::is_same_v<T, jcharArray>) {
+ return CTString("[C");
+ } else if constexpr (std::is_same_v<T, jboolean>) {
+ return CTString("Z");
+ } else if constexpr (std::is_same_v<T, bool>) {
+ return CTString("Z");
+ } else if constexpr (std::is_same_v<T, jbyte>) {
+ return CTString("B");
+ } else if constexpr (std::is_same_v<T, jchar>) {
+ return CTString("C");
+ } else if constexpr (std::is_same_v<T, char>) {
+ return CTString("C");
+ } else if constexpr (std::is_same_v<T, jshort>) {
+ return CTString("S");
+ } else if constexpr (std::is_same_v<T, short>) {
+ return CTString("S");
+ } else if constexpr (std::is_same_v<T, jint>) {
+ return CTString("I");
+ } else if constexpr (std::is_same_v<T, int>) {
+ return CTString("I");
+ } else if constexpr (std::is_same_v<T, uint>) {
+ return CTString("I");
+ } else if constexpr (std::is_same_v<T, jlong>) {
+ return CTString("J");
+ } else if constexpr (std::is_same_v<T, quint64>) {
+ return CTString("J");
+ } else if constexpr (std::is_same_v<T, jfloat>) {
+ return CTString("F");
+ } else if constexpr (std::is_same_v<T, float>) {
+ return CTString("F");
+ } else if constexpr (std::is_same_v<T, jdouble>) {
+ return CTString("D");
+ } else if constexpr (std::is_same_v<T, double>) {
+ return CTString("D");
+ } else if constexpr (std::is_same_v<T, void>) {
+ return CTString("V");
+ } else if constexpr (std::is_enum_v<T>) {
+ return Traits<std::underlying_type_t<T>>::signature();
+ } else if constexpr (std::is_same_v<T, QString>) {
+ return CTString("Ljava/lang/String;");
+ }
+ // else: return void -> not implemented
+ }
+};
+
+template <typename Have, typename Want>
+static constexpr bool sameTypeForJni = (QtJniTypes::Traits<Have>::signature()
+ == QtJniTypes::Traits<Want>::signature())
+ && (sizeof(Have) == sizeof(Want));
+
+template <typename, typename = void>
+struct Caller
+{};
+
+#define MAKE_CALLER(Type, Method) \
+template <typename T> \
+struct Caller<T, std::enable_if_t<sameTypeForJni<T, Type>>> \
+{ \
+ static constexpr void callMethodForType(JNIEnv *env, T &res, jobject obj, jmethodID id, va_list args) \
+ { \
+ res = T(env->Call##Method##MethodV(obj, id, args)); \
+ } \
+ static constexpr void callStaticMethodForType(JNIEnv *env, T &res, jclass clazz, jmethodID id, va_list args) \
+ { \
+ res = T(env->CallStatic##Method##MethodV(clazz, id, args)); \
+ } \
+ static constexpr void getFieldForType(JNIEnv *env, T &res, jobject obj, jfieldID id) \
+ { \
+ res = T(env->Get##Method##Field(obj, id)); \
+ } \
+ static constexpr void getStaticFieldForType(JNIEnv *env, T &res, jclass clazz, jfieldID id) \
+ { \
+ res = T(env->GetStatic##Method##Field(clazz, id)); \
+ } \
+ static constexpr void setFieldForType(JNIEnv *env, jobject obj, jfieldID id, T value) \
+ { \
+ env->Set##Method##Field(obj, id, static_cast<Type>(value)); \
+ } \
+ static constexpr void setStaticFieldForType(JNIEnv *env, jclass clazz, jfieldID id, T value) \
+ { \
+ env->SetStatic##Method##Field(clazz, id, static_cast<Type>(value)); \
+ } \
+}
+
+MAKE_CALLER(jboolean, Boolean);
+MAKE_CALLER(jbyte, Byte);
+MAKE_CALLER(jchar, Char);
+MAKE_CALLER(jshort, Short);
+MAKE_CALLER(jint, Int);
+MAKE_CALLER(jlong, Long);
+MAKE_CALLER(jfloat, Float);
+MAKE_CALLER(jdouble, Double);
+
+#undef MAKE_CALLER
+
+template<typename T>
+static constexpr bool isPrimitiveType()
+{
+ return Traits<T>::signature().size() == 2;
+}
+
+template<typename T>
+static constexpr bool isArrayType()
+{
+ constexpr auto signature = Traits<T>::signature();
+ return signature.startsWith('[') && signature.size() > 2;
+}
+
+template<typename T>
+static constexpr bool isObjectType()
+{
+ if constexpr (std::is_convertible_v<T, jobject>) {
+ return true;
+ } else {
+ constexpr auto signature = Traits<T>::signature();
+ return (signature.startsWith('L') && signature.endsWith(';')) || isArrayType<T>();
+ }
+}
+
+template<typename T>
+static constexpr void assertObjectType()
+{
+ static_assert(isObjectType<T>(),
+ "Type needs to be a JNI object type (convertible to jobject, or with "
+ "an object type signature registered)!");
+}
+
+// A set of types is valid if Traits::signature is implemented for all of them
+template<typename ...Types>
+constexpr bool ValidSignatureTypesDetail = !std::disjunction<std::is_same<
+ decltype(Traits<Types>::signature()),
+ void>...,
+ IsStringType<Types>...>::value;
+template<typename ...Types>
+using IfValidSignatureTypes = std::enable_if_t<
+ ValidSignatureTypesDetail<q20::remove_cvref_t<Types>...>, bool>;
+
+template<typename Type>
+constexpr bool ValidFieldTypeDetail = isObjectType<Type>() || isPrimitiveType<Type>();
+template<typename Type>
+using IfValidFieldType = std::enable_if_t<
+ ValidFieldTypeDetail<q20::remove_cvref_t<Type>>, bool>;
+
+
+template<typename R, typename ...Args, IfValidSignatureTypes<R, Args...> = true>
+static constexpr auto methodSignature()
+{
+ return (CTString("(") +
+ ... + Traits<q20::remove_cvref_t<Args>>::signature())
+ + CTString(")")
+ + Traits<R>::signature();
+}
+
+template<typename T, IfValidSignatureTypes<T> = true>
+static constexpr auto fieldSignature()
+{
+ return QtJniTypes::Traits<T>::signature();
+}
+
+template<typename ...Args, IfValidSignatureTypes<Args...> = true>
+static constexpr auto constructorSignature()
+{
+ return methodSignature<void, Args...>();
+}
+
+template<typename Ret, typename ...Args, IfValidSignatureTypes<Ret, Args...> = true>
+static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jobject, Args...))
+{
+ return methodSignature<Ret, Args...>();
+}
+
+template<typename Ret, typename ...Args, IfValidSignatureTypes<Ret, Args...> = true>
+static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jclass, Args...))
+{
+ return methodSignature<Ret, Args...>();
+}
+
+} // namespace QtJniTypes
+
+QT_END_NAMESPACE
+
+#endif
+
+#endif // QJNITYPES_IMPL_H
diff --git a/src/corelib/kernel/qmath.qdoc b/src/corelib/kernel/qmath.qdoc
index c15a20d94f..bc365f26fa 100644
--- a/src/corelib/kernel/qmath.qdoc
+++ b/src/corelib/kernel/qmath.qdoc
@@ -132,7 +132,7 @@
\since 6.1
\overload
\fn template <typename Tx, typename Ty> auto qHypot(Tx x, Ty y)
- Returns the distance of a point (x, y) from the origin (0, 0).
+ Returns the distance of a point (\a x, \a y) from the origin (0, 0).
This is qSqrt(x * x + y * y), optimized.
In particular, underflow and overflow may be avoided.
diff --git a/src/corelib/kernel/qmetacontainer.cpp b/src/corelib/kernel/qmetacontainer.cpp
index 200724c9f4..5f68f8fe74 100644
--- a/src/corelib/kernel/qmetacontainer.cpp
+++ b/src/corelib/kernel/qmetacontainer.cpp
@@ -14,6 +14,8 @@ QT_BEGIN_NAMESPACE
\ingroup objectmodel
+ \compares equality
+
The class provides a number of primitive container operations, using void*
as operands. This way, you can manipulate a generic container retrieved from
a Variant without knowing its type.
@@ -790,21 +792,19 @@ void QMetaSequence::valueAtConstIterator(const void *iterator, void *result) con
}
/*!
- \fn bool operator==(QMetaSequence a, QMetaSequence b)
+ \fn bool QMetaSequence::operator==(const QMetaSequence &lhs, const QMetaSequence &rhs)
\since 6.0
- \relates QMetaSequence
- Returns \c true if the QMetaSequence \a a represents the same container type
- as the QMetaSequence \a b, otherwise returns \c false.
+ Returns \c true if the QMetaSequence \a lhs represents the same container type
+ as the QMetaSequence \a rhs, otherwise returns \c false.
*/
/*!
- \fn bool operator!=(QMetaSequence a, QMetaSequence b)
+ \fn bool QMetaSequence::operator!=(const QMetaSequence &lhs, const QMetaSequence &rhs)
\since 6.0
- \relates QMetaSequence
- Returns \c true if the QMetaSequence \a a represents a different container
- type than the QMetaSequence \a b, otherwise returns \c false.
+ Returns \c true if the QMetaSequence \a lhs represents a different container
+ type than the QMetaSequence \a rhs, otherwise returns \c false.
*/
diff --git a/src/corelib/kernel/qmetacontainer.h b/src/corelib/kernel/qmetacontainer.h
index 68d62bd2ea..1bed7f9f7b 100644
--- a/src/corelib/kernel/qmetacontainer.h
+++ b/src/corelib/kernel/qmetacontainer.h
@@ -5,9 +5,12 @@
#define QMETACONTAINER_H
#include <QtCore/qcontainerinfo.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qflags.h>
#include <QtCore/qglobal.h>
+#include <iterator>
+
QT_BEGIN_NAMESPACE
class QMetaType;
@@ -973,16 +976,15 @@ public:
bool canGetValueAtConstIterator() const;
void valueAtConstIterator(const void *iterator, void *result) const;
- friend bool operator==(const QMetaSequence &a, const QMetaSequence &b)
- {
- return a.d() == b.d();
- }
- friend bool operator!=(const QMetaSequence &a, const QMetaSequence &b)
+ const QtMetaContainerPrivate::QMetaSequenceInterface *iface() const { return d(); }
+
+private:
+ friend bool comparesEqual(const QMetaSequence &lhs, const QMetaSequence &rhs) noexcept
{
- return a.d() != b.d();
+ return lhs.d() == rhs.d();
}
+ Q_DECLARE_EQUALITY_COMPARABLE(QMetaSequence)
-private:
template<typename T>
struct MetaSequence
{
@@ -1167,16 +1169,15 @@ public:
return nullptr;
}
- friend bool operator==(const QMetaAssociation &a, const QMetaAssociation &b)
- {
- return a.d() == b.d();
- }
- friend bool operator!=(const QMetaAssociation &a, const QMetaAssociation &b)
+ const QtMetaContainerPrivate::QMetaAssociationInterface *iface() const { return d(); }
+
+private:
+ friend bool comparesEqual(const QMetaAssociation &lhs, const QMetaAssociation &rhs) noexcept
{
- return a.d() != b.d();
+ return lhs.d() == rhs.d();
}
+ Q_DECLARE_EQUALITY_COMPARABLE(QMetaAssociation)
-private:
template<typename T>
struct MetaAssociation
{
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index 09692600c3..148983f126 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -3,26 +3,23 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qmetaobject.h"
-#include "qmetatype.h"
-#include "qobject.h"
#include "qmetaobject_p.h"
+#include "qmetatype.h"
#include "qmetatype_p.h"
+#include "qobject.h"
+#include "qobject_p.h"
#include <qcoreapplication.h>
-#include <qcoreevent.h>
-#include <qdatastream.h>
-#include <qstringlist.h>
-#include <qthread.h>
#include <qvariant.h>
-#include <qdebug.h>
+
+// qthread(_p).h uses QT_CONFIG(thread) internally and has a dummy
+// interface for the non-thread support case
+#include <qthread.h>
+#include "private/qthread_p.h"
#if QT_CONFIG(thread)
#include <qsemaphore.h>
#endif
-#include "private/qobject_p.h"
-#include "private/qmetaobject_p.h"
-#include "private/qthread_p.h"
-
// for normalizeTypeInternal
#include "private/qmetaobject_moc_p.h"
@@ -130,7 +127,7 @@ static inline const char *rawStringData(const QMetaObject *mo, int index)
return reinterpret_cast<const char *>(mo->d.stringdata) + offset;
}
-static inline QLatin1StringView stringDataView(const QMetaObject *mo, int index)
+static inline QByteArrayView stringDataView(const QMetaObject *mo, int index)
{
Q_ASSERT(priv(mo->d.data)->revision >= 7);
uint offset = mo->d.stringdata[2*index];
@@ -145,22 +142,12 @@ static inline QByteArray stringData(const QMetaObject *mo, int index)
return QByteArray::fromRawData(view.data(), view.size());
}
-static inline const char *rawTypeNameFromTypeInfo(const QMetaObject *mo, uint typeInfo)
+static inline QByteArrayView typeNameFromTypeInfo(const QMetaObject *mo, uint typeInfo)
{
- if (typeInfo & IsUnresolvedType) {
- return rawStringData(mo, typeInfo & TypeNameIndexMask);
- } else {
- return QMetaType(typeInfo).name();
- }
-}
-
-static inline QByteArray typeNameFromTypeInfo(const QMetaObject *mo, uint typeInfo)
-{
- if (typeInfo & IsUnresolvedType) {
- return stringData(mo, typeInfo & TypeNameIndexMask);
- } else {
- return QMetaType(typeInfo).name();
- }
+ if (typeInfo & IsUnresolvedType)
+ return stringDataView(mo, typeInfo & TypeNameIndexMask);
+ else
+ return QByteArrayView(QMetaType(typeInfo).name());
}
static inline int typeFromTypeInfo(const QMetaObject *mo, uint typeInfo)
@@ -170,6 +157,19 @@ static inline int typeFromTypeInfo(const QMetaObject *mo, uint typeInfo)
return QMetaType::fromName(rawStringData(mo, typeInfo & TypeNameIndexMask)).id();
}
+static auto parse_scope(QByteArrayView qualifiedKey) noexcept
+{
+ struct R {
+ std::optional<QByteArrayView> scope;
+ QByteArrayView key;
+ };
+ const auto scopePos = qualifiedKey.lastIndexOf("::"_L1);
+ if (scopePos < 0)
+ return R{std::nullopt, qualifiedKey};
+ else
+ return R{qualifiedKey.first(scopePos), qualifiedKey.sliced(scopePos + 2)};
+}
+
namespace {
class QMetaMethodPrivate : public QMetaMethodInvoker
{
@@ -334,9 +334,9 @@ int QMetaObject::metacall(QObject *object, Call cl, int idx, void **argv)
return object->qt_metacall(cl, idx, argv);
}
-static inline const char *objectClassName(const QMetaObject *m)
+static inline QByteArrayView objectClassName(const QMetaObject *m)
{
- return rawStringData(m, priv(m->d.data)->className);
+ return stringDataView(m, priv(m->d.data)->className);
}
/*!
@@ -346,7 +346,7 @@ static inline const char *objectClassName(const QMetaObject *m)
*/
const char *QMetaObject::className() const
{
- return objectClassName(this);
+ return objectClassName(this).constData();
}
/*!
@@ -401,7 +401,7 @@ const QObject *QMetaObject::cast(const QObject *obj) const
*/
QString QMetaObject::tr(const char *s, const char *c, int n) const
{
- return QCoreApplication::translate(objectClassName(this), s, c, n);
+ return QCoreApplication::translate(className(), s, c, n);
}
#endif // QT_NO_TRANSLATION
@@ -419,10 +419,30 @@ QMetaType QMetaObject::metaType() const
return QMetaType::fromName(className());
} else {
/* in the metatype array, we store
- idx: 0 propertyCount - 1 propertyCount
- data:QMetaType(prop0), ..., QMetaType(propPropCount-1), QMetaType(class),...
- */
- auto iface = this->d.metaTypes[d->propertyCount];
+
+ | index | data |
+ |----------------------------------------------------------------------|
+ | 0 | QMetaType(property0) |
+ | ... | ... |
+ | propertyCount - 1 | QMetaType(propertyCount - 1) |
+ | propertyCount | QMetaType(enumerator0) |
+ | ... | ... |
+ | propertyCount + enumeratorCount - 1 | QMetaType(enumeratorCount - 1) |
+ | propertyCount + enumeratorCount | QMetaType(class) |
+
+ */
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ // Before revision 12 we only stored metatypes for enums if they showed
+ // up as types of properties or method arguments or return values.
+ // From revision 12 on, we always store them in a predictable place.
+ const qsizetype offset = d->revision < 12
+ ? d->propertyCount
+ : d->propertyCount + d->enumeratorCount;
+#else
+ const qsizetype offset = d->propertyCount + d->enumeratorCount;
+#endif
+
+ auto iface = this->d.metaTypes[offset];
if (iface && QtMetaTypePrivate::isInterfaceFor<void>(iface))
return QMetaType(); // return invalid meta-type for namespaces
if (iface)
@@ -813,7 +833,7 @@ int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject,
QMetaMethod conflictMethod = m->d.superdata->method(conflict);
qWarning("QMetaObject::indexOfSignal: signal %s from %s redefined in %s",
conflictMethod.methodSignature().constData(),
- objectClassName(m->d.superdata), objectClassName(m));
+ m->d.superdata->className(), m->className());
}
}
#endif
@@ -998,8 +1018,8 @@ bool QMetaObjectPrivate::checkConnectArgs(const QMetaMethodPrivate *signal,
uint targetTypeInfo = method->parameterTypeInfo(i);
if ((sourceTypeInfo & IsUnresolvedType)
|| (targetTypeInfo & IsUnresolvedType)) {
- QByteArray sourceName = typeNameFromTypeInfo(smeta, sourceTypeInfo);
- QByteArray targetName = typeNameFromTypeInfo(rmeta, targetTypeInfo);
+ QByteArrayView sourceName = typeNameFromTypeInfo(smeta, sourceTypeInfo);
+ QByteArrayView targetName = typeNameFromTypeInfo(rmeta, targetTypeInfo);
if (sourceName != targetName)
return false;
} else {
@@ -1012,10 +1032,10 @@ bool QMetaObjectPrivate::checkConnectArgs(const QMetaMethodPrivate *signal,
return true;
}
-static const QMetaObject *QMetaObject_findMetaObject(const QMetaObject *self, const char *name)
+static const QMetaObject *QMetaObject_findMetaObject(const QMetaObject *self, QByteArrayView name)
{
while (self) {
- if (strcmp(objectClassName(self), name) == 0)
+ if (objectClassName(self) == name)
return self;
if (self->d.relatedMetaObjects) {
Q_ASSERT(priv(self->d.data)->revision >= 2);
@@ -1041,27 +1061,28 @@ static const QMetaObject *QMetaObject_findMetaObject(const QMetaObject *self, co
*/
int QMetaObject::indexOfEnumerator(const char *name) const
{
- const QMetaObject *m = this;
- while (m) {
- const QMetaObjectPrivate *d = priv(m->d.data);
- for (int i = 0; i < d->enumeratorCount; ++i) {
- const QMetaEnum e(m, i);
- const char *prop = rawStringData(m, e.data.name());
- if (strcmp(name, prop) == 0) {
- i += m->enumeratorOffset();
- return i;
- }
- }
- m = m->d.superdata;
+ return QMetaObjectPrivate::indexOfEnumerator(this, name);
+}
+
+int QMetaObjectPrivate::indexOfEnumerator(const QMetaObject *m, QByteArrayView name)
+{
+ using W = QMetaObjectPrivate::Which;
+ for (auto which : { W::Name, W::Alias }) {
+ if (int index = indexOfEnumerator(m, name, which); index != -1)
+ return index;
}
- // Check alias names:
- m = this;
+ return -1;
+}
+
+int QMetaObjectPrivate::indexOfEnumerator(const QMetaObject *m, QByteArrayView name, Which which)
+{
while (m) {
const QMetaObjectPrivate *d = priv(m->d.data);
for (int i = 0; i < d->enumeratorCount; ++i) {
const QMetaEnum e(m, i);
- const char *prop = rawStringData(m, e.data.alias());
- if (strcmp(name, prop) == 0) {
+ const quint32 id = which == Which::Name ? e.data.name() : e.data.alias();
+ QByteArrayView prop = stringDataView(m, id);
+ if (name == prop) {
i += m->enumeratorOffset();
return i;
}
@@ -1371,7 +1392,7 @@ QByteArray QMetaObject::normalizedSignature(const char *method)
}
Q_DECL_COLD_FUNCTION static inline bool
-printMethodNotFoundWarning(const QMetaObject *meta, QLatin1StringView name, qsizetype paramCount,
+printMethodNotFoundWarning(const QMetaObject *meta, QByteArrayView name, qsizetype paramCount,
const char *const *names,
const QtPrivate::QMetaTypeInterface * const *metaTypes)
{
@@ -1379,7 +1400,7 @@ printMethodNotFoundWarning(const QMetaObject *meta, QLatin1StringView name, qsiz
QByteArray candidateMessage;
for (int i = 0; i < meta->methodCount(); ++i) {
const QMetaMethod method = meta->method(i);
- if (method.name() == QByteArrayView(name))
+ if (method.name() == name)
candidateMessage += " " + method.methodSignature() + '\n';
}
if (!candidateMessage.isEmpty()) {
@@ -1406,8 +1427,8 @@ printMethodNotFoundWarning(const QMetaObject *meta, QLatin1StringView name, qsiz
}
/*!
- \fn template <typename... Args> bool QMetaObject::invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QMetaMethodReturnArgument r, Args &&... args)
- \fn template <typename... Args> bool QMetaObject::invokeMethod(QObject *obj, const char *member, QMetaMethodReturnArgument r, Args &&... args)
+ \fn template <typename ReturnArg, typename... Args> bool QMetaObject::invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QTemplatedMetaMethodReturnArgument<ReturnArg> ret, Args &&... args)
+ \fn template <typename ReturnArg, typename... Args> bool QMetaObject::invokeMethod(QObject *obj, const char *member, QTemplatedMetaMethodReturnArgument<ReturnArg> ret, Args &&... args)
\fn template <typename... Args> bool QMetaObject::invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, Args &&... args)
\fn template <typename... Args> bool QMetaObject::invokeMethod(QObject *obj, const char *member, Args &&... args)
\since 6.5
@@ -1417,11 +1438,12 @@ printMethodNotFoundWarning(const QMetaObject *meta, QLatin1StringView name, qsiz
obj. Returns \c true if the member could be invoked. Returns \c false
if there is no such member or the parameters did not match.
- For the overloads with a QMetaMethodReturnArgument parameter, the return
- value of the \a member function call is placed in \a ret. For the overloads
- without such a member, the return value of the called function (if any)
- will be discarded. QMetaMethodReturnArgument is an internal type you should
- not use directly. Instead, use the qReturnArg() function.
+ For the overloads with a QTemplatedMetaMethodReturnArgument parameter, the
+ return value of the \a member function call is placed in \a ret. For the
+ overloads without such a member, the return value of the called function
+ (if any) will be discarded. QTemplatedMetaMethodReturnArgument is an
+ internal type you should not use directly. Instead, use the qReturnArg()
+ function.
The overloads with a Qt::ConnectionType \a type parameter allow explicitly
selecting whether the invocation will be synchronous or not:
@@ -1564,7 +1586,7 @@ bool QMetaObject::invokeMethodImpl(QObject *obj, const char *member, Qt::Connect
Q_ASSERT(typeNames);
// find the method
- QLatin1StringView name(member);
+ QByteArrayView name(member);
if (name.isEmpty())
return false;
@@ -1591,15 +1613,16 @@ bool QMetaObject::invokeMethodImpl(QObject *obj, const char *member, Qt::Connect
return printMethodNotFoundWarning(obj->metaObject(), name, paramCount, typeNames, metaTypes);
}
-bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type, void *ret)
+bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
+ qsizetype parameterCount, const void *const *params, const char *const *names,
+ const QtPrivate::QMetaTypeInterface * const *metaTypes)
{
- struct Holder {
- QtPrivate::QSlotObjectBase *obj;
- ~Holder() { obj->destroyIfLastRef(); }
- } holder = { slot };
- Q_UNUSED(holder);
+ // We don't need this now but maybe we want it later, or we may be able to
+ // share more code between the two invokeMethodImpl() overloads:
+ Q_UNUSED(names);
+ auto slot = QtPrivate::SlotObjUniquePtr(slotObj);
- if (! object)
+ if (! object) // ### only if the slot requires the object + not queued?
return false;
Qt::HANDLE currentThreadId = QThread::currentThreadId();
@@ -1611,8 +1634,7 @@ bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *
if (type == Qt::AutoConnection)
type = receiverInSameThread ? Qt::DirectConnection : Qt::QueuedConnection;
- void *argv[] = { ret };
-
+ void **argv = const_cast<void **>(params);
if (type == Qt::DirectConnection) {
slot->call(object, argv);
} else if (type == Qt::QueuedConnection) {
@@ -1621,15 +1643,23 @@ bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *
"queued connections");
return false;
}
+ auto event = std::make_unique<QMetaCallEvent>(std::move(slot), nullptr, -1, parameterCount);
+ void **args = event->args();
+ QMetaType *types = event->types();
+
+ for (int i = 1; i < parameterCount; ++i) {
+ types[i] = QMetaType(metaTypes[i]);
+ args[i] = types[i].create(argv[i]);
+ }
- QCoreApplication::postEvent(object, new QMetaCallEvent(slot, nullptr, -1, 1));
+ QCoreApplication::postEvent(object, event.release());
} else if (type == Qt::BlockingQueuedConnection) {
#if QT_CONFIG(thread)
if (receiverInSameThread)
qWarning("QMetaObject::invokeMethod: Dead lock detected");
QSemaphore semaphore;
- QCoreApplication::postEvent(object, new QMetaCallEvent(slot, nullptr, -1, argv, &semaphore));
+ QCoreApplication::postEvent(object, new QMetaCallEvent(std::move(slot), nullptr, -1, argv, &semaphore));
semaphore.acquire();
#endif // QT_CONFIG(thread)
} else {
@@ -1700,31 +1730,44 @@ bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *
*/
/*!
- \fn template<typename Functor, typename FunctorReturnType> bool QMetaObject::invokeMethod(QObject *context, Functor function, Qt::ConnectionType type, FunctorReturnType *ret)
+ \fn template<typename Functor, typename FunctorReturnType> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type, FunctorReturnType *ret)
+ \fn template<typename Functor, typename FunctorReturnType> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, FunctorReturnType *ret)
\since 5.10
-
\threadsafe
- \overload
Invokes the \a function in the event loop of \a context. \a function can be a functor
or a pointer to a member function. Returns \c true if the function could be invoked.
Returns \c false if there is no such function or the parameters did not match.
The return value of the function call is placed in \a ret.
+
+ If \a type is set, then the function is invoked using that connection type. Otherwise,
+ Qt::AutoConnection will be used.
*/
/*!
- \fn template<typename Functor, typename FunctorReturnType> bool QMetaObject::invokeMethod(QObject *context, Functor function, FunctorReturnType *ret)
-
- \since 5.10
+ \fn template<typename Functor, typename FunctorReturnType, typename... Args> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type, QTemplatedMetaMethodReturnArgument<FunctorReturnType> ret, Args &&...arguments)
+ \fn template<typename Functor, typename FunctorReturnType, typename... Args> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, QTemplatedMetaMethodReturnArgument<FunctorReturnType> ret, Args &&...arguments)
+ \fn template<typename Functor, typename... Args> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type, Args &&...arguments)
+ \fn template<typename Functor, typename... Args> bool QMetaObject::invokeMethod(QObject *context, Functor &&function, Args &&...arguments)
+ \since 6.7
\threadsafe
- \overload
- Invokes the \a function in the event loop of \a context using the connection type Qt::AutoConnection.
- \a function can be a functor or a pointer to a member function. Returns \c true if the function could
- be invoked. Returns \c false if there is no such member or the parameters did not match.
- The return value of the function call is placed in \a ret.
+ Invokes the \a function with \a arguments in the event loop of \a context.
+ \a function can be a functor or a pointer to a member function. Returns
+ \c true if the function could be invoked. The return value of the
+ function call is placed in \a ret. The object used for the \a ret argument
+ should be obtained by passing your object to qReturnArg(). For example:
+
+ \badcode
+ MyClass *obj = ...;
+ int result = 0;
+ QMetaObject::invokeMethod(obj, &MyClass::myMethod, qReturnArg(result), parameter);
+ \endcode
+
+ If \a type is set, then the function is invoked using that connection type.
+ Otherwise, Qt::AutoConnection will be used.
*/
/*!
@@ -1755,6 +1798,7 @@ bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *
function.
\ingroup objectmodel
+ \compares equality
A QMetaMethod has a methodType(), a methodSignature(), a list of
parameterTypes() and parameterNames(), a return typeName(), a
@@ -1782,19 +1826,19 @@ bool QMetaObject::invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *
invoked), otherwise returns \c false.
*/
-/*! \fn bool QMetaMethod::operator==(const QMetaMethod &m1, const QMetaMethod &m2)
+/*! \fn bool QMetaMethod::operator==(const QMetaMethod &lhs, const QMetaMethod &rhs)
\since 5.0
\overload
- Returns \c true if method \a m1 is equal to method \a m2,
+ Returns \c true if method \a lhs is equal to method \a rhs,
otherwise returns \c false.
*/
-/*! \fn bool QMetaMethod::operator!=(const QMetaMethod &m1, const QMetaMethod &m2)
+/*! \fn bool QMetaMethod::operator!=(const QMetaMethod &lhs, const QMetaMethod &rhs)
\since 5.0
\overload
- Returns \c true if method \a m1 is not equal to method \a m2,
+ Returns \c true if method \a lhs is not equal to method \a rhs,
otherwise returns \c false.
*/
@@ -1980,7 +2024,7 @@ void QMetaMethodPrivate::getParameterTypes(int *types) const
QByteArray QMetaMethodPrivate::parameterTypeName(int index) const
{
int paramsIndex = parametersDataIndex();
- return typeNameFromTypeInfo(mobj, mobj->d.data[paramsIndex + index]);
+ return typeNameFromTypeInfo(mobj, mobj->d.data[paramsIndex + index]).toByteArray();
}
QList<QByteArray> QMetaMethodPrivate::parameterTypes() const
@@ -1990,8 +2034,10 @@ QList<QByteArray> QMetaMethodPrivate::parameterTypes() const
QList<QByteArray> list;
list.reserve(argc);
int paramsIndex = parametersDataIndex();
- for (int i = 0; i < argc; ++i)
- list += typeNameFromTypeInfo(mobj, mobj->d.data[paramsIndex + i]);
+ for (int i = 0; i < argc; ++i) {
+ QByteArrayView name = typeNameFromTypeInfo(mobj, mobj->d.data[paramsIndex + i]);
+ list.emplace_back(name.toByteArray());
+ }
return list;
}
@@ -2229,10 +2275,9 @@ const char *QMetaMethod::typeName() const
differently, and treat them according to the specific needs of your
application.
- \note Since Qt 5.0, \c moc expands preprocessor macros, so it is necessary
+ \note \c moc expands preprocessor macros, so it is necessary
to surround the definition with \c #ifndef \c Q_MOC_RUN, as shown in the
- example above. This was not required in Qt 4. The code as shown above works
- with Qt 4 too.
+ example above.
*/
const char *QMetaMethod::tag() const
{
@@ -2346,7 +2391,7 @@ QMetaMethod::MethodType QMetaMethod::methodType() const
\since 5.0
Returns the meta-method that corresponds to the given \a signal, or an
- invalid QMetaMethod if \a signal is not a signal of the class.
+ invalid QMetaMethod if \a signal is \c{nullptr} or not a signal of the class.
Example:
@@ -2374,20 +2419,21 @@ QMetaMethod QMetaMethod::fromSignalImpl(const QMetaObject *metaObject, void **si
}
/*!
- \fn template <typename... Args> bool QMetaMethod::invoke(QObject *obj, Qt::ConnectionType type, QMetaMethodReturnArgument ret, Args &&... arguments) const
+ \fn template <typename ReturnArg, typename... Args> bool QMetaMethod::invoke(QObject *obj, Qt::ConnectionType type, QTemplatedMetaMethodReturnArgument<ReturnArg> ret, Args &&... arguments) const
\fn template <typename... Args> bool QMetaMethod::invoke(QObject *obj, Qt::ConnectionType type, Args &&... arguments) const
- \fn template <typename... Args> bool QMetaMethod::invoke(QObject *obj, QMetaMethodReturnArgument ret, Args &&... arguments) const
+ \fn template <typename ReturnArg, typename... Args> bool QMetaMethod::invoke(QObject *obj, QTemplatedMetaMethodReturnArgument<ReturnArg> ret, Args &&... arguments) const
\fn template <typename... Args> bool QMetaMethod::invoke(QObject *obj, Args &&... arguments) const
\since 6.5
Invokes this method on the object \a object. Returns \c true if the member could be invoked.
Returns \c false if there is no such member or the parameters did not match.
- For the overloads with a QMetaMethodReturnArgument parameter, the return
- value of the \a member function call is placed in \a ret. For the overloads
- without such a member, the return value of the called function (if any)
- will be discarded. QMetaMethodReturnArgument is an internal type you should
- not use directly. Instead, use the qReturnArg() function.
+ For the overloads with a QTemplatedMetaMethodReturnArgument parameter, the
+ return value of the \a member function call is placed in \a ret. For the
+ overloads without such a member, the return value of the called function
+ (if any) will be discarded. QTemplatedMetaMethodReturnArgument is an
+ internal type you should not use directly. Instead, use the qReturnArg()
+ function.
The overloads with a Qt::ConnectionType \a type parameter allow explicitly
selecting whether the invocation will be synchronous or not:
@@ -2590,7 +2636,7 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target,
// 0 is the return type, 1 is the first formal parameter
auto checkTypesAreCompatible = [=](int idx) {
uint typeInfo = priv->parameterTypeInfo(idx - 1);
- QLatin1StringView userTypeName(typeNames[idx] ? typeNames[idx] : metaTypes[idx]->name);
+ QByteArrayView userTypeName(typeNames[idx] ? typeNames[idx] : metaTypes[idx]->name);
if ((typeInfo & IsUnresolvedType) == 0) {
// this is a built-in type
@@ -2599,7 +2645,7 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target,
return int(typeInfo) == metaTypes[idx]->typeId;
}
- QLatin1StringView methodTypeName = stringDataView(priv->mobj, typeInfo & TypeNameIndexMask);
+ QByteArrayView methodTypeName = stringDataView(priv->mobj, typeInfo & TypeNameIndexMask);
if ((MetaTypesAreOptional && !metaTypes) || !metaTypes[idx]) {
// compatibility call, compare strings
if (methodTypeName == userTypeName)
@@ -2607,7 +2653,7 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target,
// maybe the user type needs normalization
QByteArray normalized = normalizeTypeInternal(userTypeName.begin(), userTypeName.end());
- return methodTypeName == QLatin1StringView(normalized);
+ return methodTypeName == normalized;
}
QMetaType userType(metaTypes[idx]);
@@ -2814,7 +2860,7 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target,
*/
/*!
- \fn template <typename... Args> bool QMetaMethod::invokeOnGadget(void *gadget, QMetaMethodReturnArgument ret, Args &&... arguments) const
+ \fn template <typename ReturnArg, typename... Args> bool QMetaMethod::invokeOnGadget(void *gadget, QTemplatedMetaMethodReturnArgument<ReturnArg> ret, Args &&... arguments) const
\fn template <typename... Args> bool QMetaMethod::invokeOnGadget(void *gadget, Args &&... arguments) const
\since 6.5
@@ -2825,11 +2871,11 @@ auto QMetaMethodInvoker::invokeImpl(QMetaMethod self, void *target,
The invocation is always synchronous.
- For the overload with a QMetaMethodReturnArgument parameter, the return
- value of the \a member function call is placed in \a ret. For the overload
- without it, the return value of the called function (if any) will be
- discarded. QMetaMethodReturnArgument is an internal type you should not use
- directly. Instead, use the qReturnArg() function.
+ For the overload with a QTemplatedMetaMethodReturnArgument parameter, the
+ return value of the \a member function call is placed in \a ret. For the
+ overload without it, the return value of the called function (if any) will
+ be discarded. QTemplatedMetaMethodReturnArgument is an internal type you
+ should not use directly. Instead, use the qReturnArg() function.
\warning this method will not test the validity of the arguments: \a gadget
must be an instance of the class of the QMetaObject of which this QMetaMethod
@@ -3037,6 +3083,32 @@ const char *QMetaEnum::enumName() const
}
/*!
+ Returns the meta type of the enum.
+
+ If the QMetaObject that this enum is part of was generated with Qt 6.5 or
+ earlier, this will be an invalid meta type.
+
+ \note This is the meta type of the enum itself, not of its underlying
+ integral type. You can retrieve the meta type of the underlying type of the
+ enum using \l{QMetaType::underlyingType()}.
+
+ \since 6.6
+*/
+QMetaType QMetaEnum::metaType() const
+{
+ if (!mobj)
+ return {};
+
+ const QMetaObjectPrivate *p = priv(mobj->d.data);
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ if (p->revision < 12)
+ QMetaType();
+#endif
+
+ return QMetaType(mobj->d.metaTypes[data.index(mobj) + p->propertyCount]);
+}
+
+/*!
Returns the number of keys.
\sa key()
@@ -3116,7 +3188,34 @@ bool QMetaEnum::isScoped() const
*/
const char *QMetaEnum::scope() const
{
- return mobj ? objectClassName(mobj) : nullptr;
+ return mobj ? mobj->className() : nullptr;
+}
+
+static bool isScopeMatch(QByteArrayView scope, const QMetaEnum *e)
+{
+ const QByteArrayView className = e->enclosingMetaObject()->className();
+
+ // Typical use-cases:
+ // a) Unscoped: namespace N { class C { enum E { F }; }; }; key == "N::C::F"
+ // b) Scoped: namespace N { class C { enum class E { F }; }; }; key == "N::C::E::F"
+ if (scope == className)
+ return true;
+
+ // Not using name() because if isFlag() is true, we want the actual name
+ // of the enum, e.g. "MyFlag", not "MyFlags", e.g.
+ // enum MyFlag { F1, F2 }; Q_DECLARE_FLAGS(MyFlags, MyFlag);
+ QByteArrayView name = e->enumName();
+
+ // Match fully qualified enumerator in unscoped enums, key == "N::C::E::F"
+ // equivalent to use-case "a" above
+ const auto sz = className.size();
+ if (scope.size() == sz + qsizetype(qstrlen("::")) + name.size()
+ && scope.startsWith(className)
+ && scope.sliced(sz, 2) == "::"
+ && scope.sliced(sz + 2) == name)
+ return true;
+
+ return false;
}
/*!
@@ -3136,19 +3235,11 @@ int QMetaEnum::keyToValue(const char *key, bool *ok) const
*ok = false;
if (!mobj || !key)
return -1;
- uint scope = 0;
- const char *qualified_key = key;
- const char *s = key + qstrlen(key);
- while (s > key && *s != ':')
- --s;
- if (s > key && *(s - 1) == ':') {
- scope = s - key - 1;
- key += scope + 2;
- }
+
+ const auto [scope, enumKey] = parse_scope(QLatin1StringView(key));
for (int i = 0; i < int(data.keyCount()); ++i) {
- const QByteArray className = stringData(mobj, priv(mobj->d.data)->className);
- if ((!scope || (className.size() == int(scope) && strncmp(qualified_key, className.constData(), scope) == 0))
- && strcmp(key, rawStringData(mobj, mobj->d.data[data.data() + 2*i])) == 0) {
+ if ((!scope || isScopeMatch(*scope, this))
+ && enumKey == stringDataView(mobj, mobj->d.data[data.data() + 2 * i])) {
if (ok != nullptr)
*ok = true;
return mobj->d.data[data.data() + 2 * i + 1];
@@ -3175,17 +3266,49 @@ const char *QMetaEnum::valueToKey(int value) const
return nullptr;
}
-static auto parse_scope(QLatin1StringView qualifiedKey) noexcept
+static bool parseEnumFlags(QByteArrayView v, QVarLengthArray<QByteArrayView, 10> &list)
{
- struct R {
- std::optional<QLatin1StringView> scope;
- QLatin1StringView key;
- };
- const auto scopePos = qualifiedKey.lastIndexOf("::"_L1);
- if (scopePos < 0)
- return R{std::nullopt, qualifiedKey};
- else
- return R{qualifiedKey.first(scopePos), qualifiedKey.sliced(scopePos + 2)};
+ v = v.trimmed();
+ if (v.empty()) {
+ qWarning("QMetaEnum::keysToValue: empty keys string.");
+ return false;
+ }
+
+ qsizetype sep = v.indexOf('|', 0);
+ if (sep == 0) {
+ qWarning("QMetaEnum::keysToValue: malformed keys string, starts with '|', \"%s\"",
+ v.constData());
+ return false;
+ }
+
+ if (sep == -1) { // One flag
+ list.push_back(v);
+ return true;
+ }
+
+ if (v.endsWith('|')) {
+ qWarning("QMetaEnum::keysToValue: malformed keys string, ends with '|', \"%s\"",
+ v.constData());
+ return false;
+ }
+
+ const auto begin = v.begin();
+ const auto end = v.end();
+ auto b = begin;
+ for (; b != end && sep != -1; sep = v.indexOf('|', sep)) {
+ list.push_back({b, begin + sep});
+ ++sep; // Skip over '|'
+ b = begin + sep;
+ if (*b == '|') {
+ qWarning("QMetaEnum::keysToValue: malformed keys string, has two consecutive '|': "
+ "\"%s\"", v.constData());
+ return false;
+ }
+ }
+
+ // The rest of the string
+ list.push_back({b, end});
+ return true;
}
/*!
@@ -3205,19 +3328,22 @@ int QMetaEnum::keysToValue(const char *keys, bool *ok) const
if (!mobj || !keys)
return -1;
- auto lookup = [&] (QLatin1StringView key) -> std::optional<int> {
+ auto lookup = [&] (QByteArrayView key) -> std::optional<int> {
for (int i = data.keyCount() - 1; i >= 0; --i) {
if (key == stringDataView(mobj, mobj->d.data[data.data() + 2*i]))
return mobj->d.data[data.data() + 2*i + 1];
}
return std::nullopt;
};
- auto className = [&] { return stringDataView(mobj, priv(mobj->d.data)->className); };
int value = 0;
- for (const QLatin1StringView &untrimmed : qTokenize(QLatin1StringView{keys}, u'|')) {
+ QVarLengthArray<QByteArrayView, 10> list;
+ const bool r = parseEnumFlags(QByteArrayView{keys}, list);
+ if (!r)
+ return -1;
+ for (const auto &untrimmed : list) {
const auto parsed = parse_scope(untrimmed.trimmed());
- if (parsed.scope && *parsed.scope != className())
+ if (parsed.scope && !isScopeMatch(*parsed.scope, this))
return -1; // wrong type name in qualified name
if (auto thisValue = lookup(parsed.key))
value |= *thisValue;
@@ -3262,7 +3388,7 @@ QByteArray QMetaEnum::valueToKeys(int value) const
QByteArray keys;
if (!mobj)
return keys;
- QVarLengthArray<QLatin1StringView, sizeof(int) * CHAR_BIT> parts;
+ QVarLengthArray<QByteArrayView, sizeof(int) * CHAR_BIT> parts;
int v = value;
// reverse iterate to ensure values like Qt::Dialog=0x2|Qt::Window are processed first.
for (int i = data.keyCount() - 1; i >= 0; --i) {
@@ -3285,8 +3411,13 @@ QMetaEnum::QMetaEnum(const QMetaObject *mobj, int index)
Q_ASSERT(index >= 0 && index < priv(mobj->d.data)->enumeratorCount);
}
+int QMetaEnum::Data::index(const QMetaObject *mobj) const
+{
+ return (d - mobj->d.data - priv(mobj->d.data)->enumeratorData) / Size;
+}
+
/*!
- \fn QMetaEnum QMetaEnum::fromType()
+ \fn template<typename T> QMetaEnum QMetaEnum::fromType()
\since 5.5
Returns the QMetaEnum corresponding to the type in the template parameter.
@@ -3372,7 +3503,7 @@ const char *QMetaProperty::typeName() const
// TODO: can the metatype be invalid for dynamic metaobjects?
if (const auto mt = metaType(); mt.isValid())
return mt.name();
- return rawTypeNameFromTypeInfo(mobj, data.type());
+ return typeNameFromTypeInfo(mobj, data.type()).constData();
}
/*! \fn QVariant::Type QMetaProperty::type() const
@@ -3528,35 +3659,28 @@ QMetaProperty::QMetaProperty(const QMetaObject *mobj, int index)
if (!(data.flags() & EnumOrFlag))
return;
- const char *type = rawTypeNameFromTypeInfo(mobj, data.type());
- menum = mobj->enumerator(mobj->indexOfEnumerator(type));
+ QByteArrayView enum_name = typeNameFromTypeInfo(mobj, data.type());
+ menum = mobj->enumerator(QMetaObjectPrivate::indexOfEnumerator(mobj, enum_name));
if (menum.isValid())
return;
- const char *enum_name = type;
- const char *scope_name = objectClassName(mobj);
- char *scope_buffer = nullptr;
-
- const char *colon = strrchr(enum_name, ':');
- // ':' will always appear in pairs
- Q_ASSERT(colon <= enum_name || *(colon - 1) == ':');
- if (colon > enum_name) {
- int len = colon - enum_name - 1;
- scope_buffer = (char *)malloc(len + 1);
- memcpy(scope_buffer, enum_name, len);
- scope_buffer[len] = '\0';
- scope_name = scope_buffer;
- enum_name = colon + 1;
+
+ QByteArrayView scope_name;
+ const auto parsed = parse_scope(enum_name);
+ if (parsed.scope) {
+ scope_name = *parsed.scope;
+ enum_name = parsed.key;
+ } else {
+ scope_name = objectClassName(mobj);
}
const QMetaObject *scope = nullptr;
- if (qstrcmp(scope_name, "Qt") == 0)
+ if (scope_name == "Qt")
scope = &Qt::staticMetaObject;
else
- scope = QMetaObject_findMetaObject(mobj, scope_name);
+ scope = QMetaObject_findMetaObject(mobj, QByteArrayView(scope_name));
+
if (scope)
- menum = scope->enumerator(scope->indexOfEnumerator(enum_name));
- if (scope_buffer)
- free(scope_buffer);
+ menum = scope->enumerator(QMetaObjectPrivate::indexOfEnumerator(scope, enum_name));
}
/*!
@@ -3629,26 +3753,38 @@ QVariant QMetaProperty::read(const QObject *object) const
if this property is resettable, or setting a default-constructed object
otherwise.
+ \note This function internally makes a copy of \a value. Prefer to use the
+ rvalue overload when possible.
+
\sa read(), reset(), isWritable()
*/
bool QMetaProperty::write(QObject *object, const QVariant &value) const
{
if (!object || !isWritable())
return false;
+ return write(object, QVariant(value));
+}
- QVariant v = value;
+/*!
+ \overload
+ \since 6.6
+*/
+bool QMetaProperty::write(QObject *object, QVariant &&v) const
+{
+ if (!object || !isWritable())
+ return false;
QMetaType t(mobj->d.metaTypes[data.index(mobj)]);
if (t != QMetaType::fromType<QVariant>() && t != v.metaType()) {
if (isEnumType() && !t.metaObject() && v.metaType().id() == QMetaType::QString) {
// Assigning a string to a property of type Q_ENUMS (instead of Q_ENUM)
bool ok;
if (isFlagType())
- v = QVariant(menum.keysToValue(value.toByteArray(), &ok));
+ v = QVariant(menum.keysToValue(v.toByteArray(), &ok));
else
- v = QVariant(menum.keyToValue(value.toByteArray(), &ok));
+ v = QVariant(menum.keyToValue(v.toByteArray(), &ok));
if (!ok)
return false;
- } else if (!value.isValid()) {
+ } else if (!v.isValid()) {
if (isResettable())
return reset(object);
v = QVariant(t, nullptr);
@@ -3743,6 +3879,16 @@ bool QMetaProperty::writeOnGadget(void *gadget, const QVariant &value) const
}
/*!
+ \overload
+ \since 6.6
+*/
+bool QMetaProperty::writeOnGadget(void *gadget, QVariant &&value) const
+{
+ Q_ASSERT(priv(mobj->d.data)->flags & PropertyAccessInStaticMetaCall && mobj->d.static_metacall);
+ return write(reinterpret_cast<QObject*>(gadget), std::move(value));
+}
+
+/*!
\since 5.5
Resets the property for the given \a gadget with a reset method.
@@ -3826,20 +3972,23 @@ int QMetaProperty::notifySignalIndex() const
if (!mobj || data.notifyIndex() == std::numeric_limits<uint>::max())
return -1;
uint methodIndex = data.notifyIndex();
- if (methodIndex & IsUnresolvedSignal) {
- methodIndex &= ~IsUnresolvedSignal;
- const QByteArray signalName = stringData(mobj, methodIndex);
- const QMetaObject *m = mobj;
- const int idx = QMetaObjectPrivate::indexOfMethodRelative<MethodSignal>(&m, signalName, 0, nullptr);
- if (idx >= 0) {
- return idx + m->methodOffset();
- } else {
- qWarning("QMetaProperty::notifySignal: cannot find the NOTIFY signal %s in class %s for property '%s'",
- signalName.constData(), objectClassName(mobj), name());
- return -1;
- }
- }
- return methodIndex + mobj->methodOffset();
+ if (!(methodIndex & IsUnresolvedSignal))
+ return methodIndex + mobj->methodOffset();
+ methodIndex &= ~IsUnresolvedSignal;
+ const QByteArray signalName = stringData(mobj, methodIndex);
+ const QMetaObject *m = mobj;
+ // try 0-arg signal
+ int idx = QMetaObjectPrivate::indexOfMethodRelative<MethodSignal>(&m, signalName, 0, nullptr);
+ if (idx >= 0)
+ return idx + m->methodOffset();
+ // try 1-arg signal
+ QArgumentType argType(typeId());
+ idx = QMetaObjectPrivate::indexOfMethodRelative<MethodSignal>(&m, signalName, 1, &argType);
+ if (idx >= 0)
+ return idx + m->methodOffset();
+ qWarning("QMetaProperty::notifySignal: cannot find the NOTIFY signal %s in class %s for property '%s'",
+ signalName.constData(), mobj->className(), name());
+ return -1;
}
// This method has been around for a while, but the documentation was marked \internal until 5.1
@@ -4000,8 +4149,11 @@ bool QMetaProperty::isBindable() const
\snippet code/src_corelib_kernel_qmetaobject.cpp 5
- This mechanism is free for you to use in your Qt applications. Qt
- doesn't use it for any of its classes.
+ This mechanism is free for you to use in your Qt applications.
+
+ \note It's also used by the \l[ActiveQt]{Active Qt},
+ \l[QtDBus]{Qt D-Bus}, \l[QtQml]{Qt Qml}, and \l{Qt Remote Objects}
+ modules. Some keys might be set when using these modules.
\sa QMetaObject
*/
@@ -4055,23 +4207,24 @@ const char *QMetaClassInfo::value() const
*/
/*!
- \macro QGenericArgument Q_ARG(Type, const Type &value)
+ \macro QMetaMethodArgument Q_ARG(Type, const Type &value)
\relates QMetaObject
This macro takes a \a Type and a \a value of that type and
- returns a \l QGenericArgument object that can be passed to
- QMetaObject::invokeMethod().
+ returns a QMetaMethodArgument, which can be passed to the template
+ QMetaObject::invokeMethod() with the \c {Args &&...} arguments.
\sa Q_RETURN_ARG()
*/
/*!
- \macro QGenericReturnArgument Q_RETURN_ARG(Type, Type &value)
+ \macro QMetaMethodReturnArgument Q_RETURN_ARG(Type, Type &value)
\relates QMetaObject
This macro takes a \a Type and a non-const reference to a \a
- value of that type and returns a QGenericReturnArgument object
- that can be passed to QMetaObject::invokeMethod().
+ value of that type and returns a QMetaMethodReturnArgument, which can be
+ passed to the template QMetaObject::invokeMethod() with the \c {Args &&...}
+ arguments.
\sa Q_ARG()
*/
diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h
index 3aa3a687c4..91f287a8d3 100644
--- a/src/corelib/kernel/qmetaobject.h
+++ b/src/corelib/kernel/qmetaobject.h
@@ -6,6 +6,7 @@
#define QMETAOBJECT_H
#include <QtCore/qobjectdefs.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qvariant.h>
QT_BEGIN_NAMESPACE
@@ -135,13 +136,13 @@ public:
}
#endif
- template <typename... Args>
+ template <typename ReturnArg, typename... Args>
#ifdef Q_QDOC
bool
#else
QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
#endif
- invoke(QObject *obj, Qt::ConnectionType c, QMetaMethodReturnArgument r,
+ invoke(QObject *obj, Qt::ConnectionType c, QTemplatedMetaMethodReturnArgument<ReturnArg> r,
Args &&... arguments) const
{
auto h = QtPrivate::invokeMethodHelper(r, std::forward<Args>(arguments)...);
@@ -157,16 +158,16 @@ public:
#endif
invoke(QObject *obj, Qt::ConnectionType c, Args &&... arguments) const
{
- return invoke(obj, c, QMetaMethodReturnArgument{}, std::forward<Args>(arguments)...);
+ return invoke(obj, c, QTemplatedMetaMethodReturnArgument<void>{}, std::forward<Args>(arguments)...);
}
- template <typename... Args>
+ template <typename ReturnArg, typename... Args>
#ifdef Q_QDOC
bool
#else
QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
#endif
- invoke(QObject *obj, QMetaMethodReturnArgument r, Args &&... arguments) const
+ invoke(QObject *obj, QTemplatedMetaMethodReturnArgument<ReturnArg> r, Args &&... arguments) const
{
return invoke(obj, Qt::AutoConnection, r, std::forward<Args>(arguments)...);
}
@@ -182,13 +183,13 @@ public:
return invoke(obj, Qt::AutoConnection, std::forward<Args>(arguments)...);
}
- template <typename... Args>
+ template <typename ReturnArg, typename... Args>
#ifdef Q_QDOC
bool
#else
QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
#endif
- invokeOnGadget(void *gadget, QMetaMethodReturnArgument r, Args &&... arguments) const
+ invokeOnGadget(void *gadget, QTemplatedMetaMethodReturnArgument<ReturnArg> r, Args &&... arguments) const
{
auto h = QtPrivate::invokeMethodHelper(r, std::forward<Args>(arguments)...);
return invokeImpl(*this, gadget, Qt::ConnectionType(-1), h.parameterCount(),
@@ -203,7 +204,7 @@ public:
#endif
invokeOnGadget(void *gadget, Args &&... arguments) const
{
- return invokeOnGadget(gadget, QMetaMethodReturnArgument{}, std::forward<Args>(arguments)...);
+ return invokeOnGadget(gadget, QTemplatedMetaMethodReturnArgument<void>{}, std::forward<Args>(arguments)...);
}
inline bool isValid() const { return mobj != nullptr; }
@@ -251,10 +252,11 @@ protected:
friend struct QMetaObject;
friend struct QMetaObjectPrivate;
friend class QObject;
- friend bool operator==(const QMetaMethod &m1, const QMetaMethod &m2) noexcept
- { return m1.data == m2.data; }
- friend bool operator!=(const QMetaMethod &m1, const QMetaMethod &m2) noexcept
- { return !(m1 == m2); }
+
+private:
+ friend bool comparesEqual(const QMetaMethod &lhs, const QMetaMethod &rhs) noexcept
+ { return lhs.data == rhs.data; }
+ Q_DECLARE_EQUALITY_COMPARABLE(QMetaMethod)
};
Q_DECLARE_TYPEINFO(QMetaMethod, Q_RELOCATABLE_TYPE);
@@ -265,6 +267,8 @@ public:
const char *name() const;
const char *enumName() const;
+ QMetaType metaType() const;
+
bool isFlag() const;
bool isScoped() const;
@@ -302,6 +306,7 @@ private:
quint32 flags() const { return d[2]; }
qint32 keyCount() const { return static_cast<qint32>(d[3]); }
quint32 data() const { return d[4]; }
+ int index(const QMetaObject *mobj) const;
const uint *d;
};
@@ -360,12 +365,14 @@ public:
QVariant read(const QObject *obj) const;
bool write(QObject *obj, const QVariant &value) const;
+ bool write(QObject *obj, QVariant &&value) const;
bool reset(QObject *obj) const;
QUntypedBindable bindable(QObject *object) const;
QVariant readOnGadget(const void *gadget) const;
bool writeOnGadget(void *gadget, const QVariant &value) const;
+ bool writeOnGadget(void *gadget, QVariant &&value) const;
bool resetOnGadget(void *gadget) const;
bool hasStdCppSet() const;
diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h
index d05b727f52..d2c36fceb4 100644
--- a/src/corelib/kernel/qmetaobject_p.h
+++ b/src/corelib/kernel/qmetaobject_p.h
@@ -175,7 +175,8 @@ struct QMetaObjectPrivate
// revision 10 is Qt 6.2: The metatype of the metaobject is stored in the metatypes array
// and metamethods store a flag stating whether they are const
// revision 11 is Qt 6.5: The metatype for void is stored in the metatypes array
- enum { OutputRevision = 11 }; // Used by moc, qmetaobjectbuilder and qdbus
+ // revision 12 is Qt 6.6: It adds the metatype for enums
+ enum { OutputRevision = 12 }; // Used by moc, qmetaobjectbuilder and qdbus
enum { IntsPerMethod = QMetaMethod::Data::Size };
enum { IntsPerEnum = QMetaEnum::Data::Size };
enum { IntsPerProperty = QMetaProperty::Data::Size };
@@ -211,6 +212,11 @@ struct QMetaObjectPrivate
int argc, const QArgumentType *types);
static int indexOfConstructor(const QMetaObject *m, const QByteArray &name,
int argc, const QArgumentType *types);
+
+ enum class Which { Name, Alias };
+ static int indexOfEnumerator(const QMetaObject *m, QByteArrayView name, Which which);
+ static int indexOfEnumerator(const QMetaObject *m, QByteArrayView name);
+
Q_CORE_EXPORT static QMetaMethod signal(const QMetaObject *m, int signal_index);
static inline int signalOffset(const QMetaObject *m)
{
diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp
index e61065f42f..c2b44a4f00 100644
--- a/src/corelib/kernel/qmetaobjectbuilder.cpp
+++ b/src/corelib/kernel/qmetaobjectbuilder.cpp
@@ -159,6 +159,7 @@ public:
QByteArray name;
QByteArray enumName;
+ QMetaType metaType;
bool isFlag;
bool isScoped;
QList<QByteArray> keys;
@@ -597,6 +598,7 @@ QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QMetaEnum &prototype)
{
QMetaEnumBuilder en = addEnumerator(prototype.name());
en.setEnumName(prototype.enumName());
+ en.setMetaType(prototype.metaType());
en.setIsFlag(prototype.isFlag());
en.setIsScoped(prototype.isScoped());
int count = prototype.keyCount();
@@ -1160,8 +1162,8 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
}
// Populate the QMetaObjectPrivate structure.
- QMetaObjectPrivate *pmeta
- = reinterpret_cast<QMetaObjectPrivate *>(buf + size);
+ QMetaObjectPrivate *pmeta = buf ? reinterpret_cast<QMetaObjectPrivate *>(buf + size)
+ : nullptr;
//int pmetaSize = size;
dataIndex = MetaObjectPrivateFieldCount;
int methodParametersDataSize =
@@ -1170,7 +1172,7 @@ static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
- int(d->methods.size()) // return "parameters" don't have names
- int(d->constructors.size()); // "this" parameters don't have names
if constexpr (mode == Construct) {
- static_assert(QMetaObjectPrivate::OutputRevision == 11, "QMetaObjectBuilder should generate the same version as moc");
+ static_assert(QMetaObjectPrivate::OutputRevision == 12, "QMetaObjectBuilder should generate the same version as moc");
pmeta->revision = QMetaObjectPrivate::OutputRevision;
pmeta->flags = d->flags.toInt();
pmeta->className = 0; // Class name is always the first string.
@@ -2306,6 +2308,31 @@ void QMetaEnumBuilder::setEnumName(const QByteArray &alias)
}
/*!
+ Returns the meta type of the enumerator.
+
+ \since 6.6
+*/
+QMetaType QMetaEnumBuilder::metaType() const
+{
+ if (QMetaEnumBuilderPrivate *d = d_func())
+ return d->metaType;
+ return QMetaType();
+}
+
+/*!
+ Sets this enumerator to have the given \c metaType.
+
+ \since 6.6
+ \sa metaType()
+*/
+void QMetaEnumBuilder::setMetaType(QMetaType metaType)
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d)
+ d->metaType = metaType;
+}
+
+/*!
Returns \c true if this enumerator is used as a flag; otherwise returns
false.
diff --git a/src/corelib/kernel/qmetaobjectbuilder_p.h b/src/corelib/kernel/qmetaobjectbuilder_p.h
index 99eaca2ac9..b52487986c 100644
--- a/src/corelib/kernel/qmetaobjectbuilder_p.h
+++ b/src/corelib/kernel/qmetaobjectbuilder_p.h
@@ -258,6 +258,9 @@ public:
QByteArray enumName() const;
void setEnumName(const QByteArray &alias);
+ QMetaType metaType() const;
+ void setMetaType(QMetaType metaType);
+
bool isFlag() const;
void setIsFlag(bool value);
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 481d409deb..387c0f49ab 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -5,7 +5,6 @@
#include "qmetatype.h"
#include "qmetatype_p.h"
-#include "qobject.h"
#include "qobjectdefs.h"
#include "qdatetime.h"
#include "qbytearray.h"
@@ -21,14 +20,14 @@
#include "qeasingcurve.h"
#endif
#include "quuid.h"
-#include "qvariant.h"
-#include "qdatastream.h"
#if QT_CONFIG(regularexpression)
# include "qregularexpression.h"
#endif
#ifndef QT_BOOTSTRAPPED
+# include "qdatastream.h"
+
# include "qbitarray.h"
# include "qurl.h"
# include "qvariant.h"
@@ -43,6 +42,7 @@
# include "qmetaobject.h"
# include "qsequentialiterable.h"
# include "qassociativeiterable.h"
+# include "qobject.h"
#endif
#if QT_CONFIG(itemmodel)
@@ -56,7 +56,6 @@
# include "qline.h"
#endif
-#include <bitset>
#include <new>
#include <cstring>
@@ -151,13 +150,7 @@ struct QMetaTypeCustomRegistry
auto &ti = registry[idx];
// We must unregister all names.
- auto it = aliases.begin();
- while (it != aliases.end()) {
- if (it.value() == ti)
- it = aliases.erase(it);
- else
- ++it;
- }
+ aliases.removeIf([ti] (const auto &kv) { return kv.value() == ti; });
ti = nullptr;
@@ -269,7 +262,7 @@ const char *QtMetaTypePrivate::typedefNameForType(const QtPrivate::QMetaTypeInte
\li Pointers to classes derived from QObject
\li QList<T>, QQueue<T>, QStack<T> or QSet<T>
where T is a registered meta type
- \li QHash<T1, T2>, QMap<T1, T2> or QPair<T1, T2> where T1 and T2 are
+ \li QHash<T1, T2>, QMap<T1, T2> or std::pair<T1, T2> where T1 and T2 are
registered meta types
\li QPointer<T>, QSharedPointer<T>, QWeakPointer<T>, where T is a class that derives from QObject
\li Enumerations registered with Q_ENUM or Q_FLAG
@@ -448,22 +441,22 @@ const char *QtMetaTypePrivate::typedefNameForType(const QtPrivate::QMetaTypeInte
The enum describes attributes of a type supported by QMetaType.
\value NeedsConstruction This type has a default constructor. If the flag is not set, instances can be safely initialized with memset to 0.
- \value NeedsCopyConstruction (since 6.5) This type has a non-trivial copy construtcor. If the flag is not set, instances can be copied with memcpy.
+ \value NeedsCopyConstruction (since 6.5) This type has a non-trivial copy constructor. If the flag is not set, instances can be copied with memcpy.
\value NeedsMoveConstruction (since 6.5) This type has a non-trivial move constructor. If the flag is not set, instances can be moved with memcpy.
- \value NeedsDestruction This type has a non-trivial destructor. If the flag is not set calls to the destructor are not necessary before discarding objects.
+ \value NeedsDestruction This type has a non-trivial destructor. If the flag is not set, calls to the destructor are not necessary before discarding objects.
\value RelocatableType An instance of a type having this attribute can be safely moved to a different memory location using memcpy.
\omitvalue MovableType
\omitvalue SharedPointerToQObject
\value IsEnumeration This type is an enumeration.
\value IsUnsignedEnumeration If the type is an Enumeration, its underlying type is unsigned.
- \value PointerToQObject This type is a pointer to a derived of QObject.
+ \value PointerToQObject This type is a pointer to a class derived from QObject.
\value IsPointer This type is a pointer to another type.
\omitvalue WeakPointerToQObject
\omitvalue TrackingPointerToQObject
- \omitvalue IsGadget \omit This type is a Q_GADGET and it's corresponding QMetaObject can be accessed with QMetaType::metaObject Since 5.5. \endomit
+ \omitvalue IsGadget \omit (since Qt 5.5) This type is a Q_GADGET and its corresponding QMetaObject can be accessed with QMetaType::metaObject. \endomit
\omitvalue PointerToGadget
\omitvalue IsQmlList
- \value IsConst Indicates that values of this types are immutable; for instance because they are pointers to const objects.
+ \value IsConst Indicates that values of this type are immutable; for instance, because they are pointers to const objects.
\note Before Qt 6.5, both the NeedsConstruction and NeedsDestruction flags
were incorrectly set if the either copy construtor or destructor were
@@ -907,13 +900,22 @@ bool QMetaType::isOrdered() const
*/
void QMetaType::unregisterMetaType(QMetaType type)
{
- if (type.d_ptr && type.d_ptr->typeId.loadRelaxed() >= QMetaType::User) {
- // this is a custom meta type (not read-only)
- auto d = const_cast<QtPrivate::QMetaTypeInterface *>(type.d_ptr);
- if (auto reg = customTypeRegistry())
- reg->unregisterDynamicType(d->typeId.loadRelaxed());
- d->typeId.storeRelease(0);
+ const QtPrivate::QMetaTypeInterface *d_ptr = type.d_ptr;
+ if (!d_ptr)
+ return;
+
+ const int typeId = d_ptr->typeId.loadRelaxed();
+ if (typeId < QMetaType::User)
+ return;
+
+ // this is a custom meta type (not read-only)
+
+ if (auto reg = customTypeRegistry()) {
+ Q_ASSERT(reg->getCustomType(typeId) == d_ptr);
+ reg->unregisterDynamicType(typeId);
}
+
+ const_cast<QtPrivate::QMetaTypeInterface *>(d_ptr)->typeId.storeRelease(0);
}
/*!
@@ -939,6 +941,12 @@ void QMetaType::unregisterMetaType(QMetaType type)
than the QMetaType \a b, otherwise returns \c false.
*/
+/*! \internal */
+bool QMetaTypeModuleHelper::convert(const void *, int, void *, int) const
+{
+ return false;
+}
+
#define QT_ADD_STATIC_METATYPE(MetaTypeName, MetaTypeId, RealName) \
{ #RealName, sizeof(#RealName) - 1, MetaTypeId },
@@ -954,7 +962,8 @@ static const struct { const char * typeName; int typeNameLength; int type; } typ
{nullptr, 0, QMetaType::UnknownType}
};
-static const struct : QMetaTypeModuleHelper
+// NOLINTNEXTLINE(cppcoreguidelines-virtual-class-destructor): this is not a base class
+static constexpr struct : QMetaTypeModuleHelper
{
template<typename T, typename LiteralWrapper =
std::conditional_t<std::is_same_v<T, QString>, QLatin1StringView, const char *>>
@@ -1001,6 +1010,8 @@ static const struct : QMetaTypeModuleHelper
using Double = double;
using Bool = bool;
using Nullptr = std::nullptr_t;
+ using Char16 = char16_t;
+ using Char32 = char32_t;
#define QMETATYPE_CONVERTER_ASSIGN_DOUBLE(To, From) \
QMETATYPE_CONVERTER(To, From, result = double(source); return true;)
@@ -1155,6 +1166,9 @@ static const struct : QMetaTypeModuleHelper
QMETATYPE_CONVERTER_ASSIGN_QCHAR(ULong);
QMETATYPE_CONVERTER_ASSIGN_QCHAR(UInt);
QMETATYPE_CONVERTER_ASSIGN_QCHAR(ULongLong);
+ QMETATYPE_CONVERTER_ASSIGN_QCHAR(Char16);
+
+ QMETATYPE_CONVERTER(Char16, QChar, result = source.unicode(); return true;)
// conversions to QString
QMETATYPE_CONVERTER_ASSIGN(QString, QChar);
@@ -1192,6 +1206,14 @@ static const struct : QMetaTypeModuleHelper
result = QString::fromLatin1(&s, 1);
return true;
);
+ QMETATYPE_CONVERTER(QString, Char16,
+ result = QChar(source);
+ return true;
+ );
+ QMETATYPE_CONVERTER(QString, Char32,
+ result = QChar::fromUcs4(source).operator QStringView().toString();
+ return true;
+ );
#if QT_CONFIG(datestring)
QMETATYPE_CONVERTER(QString, QDate, result = source.toString(Qt::ISODate); return true;);
QMETATYPE_CONVERTER(QString, QTime, result = source.toString(Qt::ISODateWithMs); return true;);
@@ -1254,8 +1276,11 @@ static const struct : QMetaTypeModuleHelper
QMETATYPE_CONVERTER_ASSIGN(QRectF, QRect);
QMETATYPE_CONVERTER(QPoint, QPointF, result = source.toPoint(); return true;);
QMETATYPE_CONVERTER_ASSIGN(QPointF, QPoint);
- #endif
+#endif
+
+ QMETATYPE_CONVERTER(QStringList, QString, result = QStringList() << source; return true;);
+#ifndef QT_NO_VARIANT
QMETATYPE_CONVERTER(QByteArrayList, QVariantList,
result.reserve(source.size());
for (const auto &v: source)
@@ -1281,7 +1306,6 @@ static const struct : QMetaTypeModuleHelper
result.append(QVariant(v));
return true;
);
- QMETATYPE_CONVERTER(QStringList, QString, result = QStringList() << source; return true;);
QMETATYPE_CONVERTER(QVariantHash, QVariantMap,
for (auto it = source.begin(); it != source.end(); ++it)
@@ -1293,7 +1317,7 @@ static const struct : QMetaTypeModuleHelper
result.insert(it.key(), it.value());
return true;
);
-
+#endif // !QT_NO_VARIANT
#ifndef QT_BOOTSTRAPPED
QMETATYPE_CONVERTER_ASSIGN(QCborValue, QString);
QMETATYPE_CONVERTER(QString, QCborValue,
@@ -1693,17 +1717,17 @@ private:
QHash<Key, T> map;
};
-typedef QMetaTypeFunctionRegistry<QMetaType::ConverterFunction,QPair<int,int> >
-QMetaTypeConverterRegistry;
+using QMetaTypeConverterRegistry
+ = QMetaTypeFunctionRegistry<QMetaType::ConverterFunction, std::pair<int,int>>;
Q_GLOBAL_STATIC(QMetaTypeConverterRegistry, customTypesConversionRegistry)
using QMetaTypeMutableViewRegistry
- = QMetaTypeFunctionRegistry<QMetaType::MutableViewFunction, QPair<int,int>>;
+ = QMetaTypeFunctionRegistry<QMetaType::MutableViewFunction, std::pair<int,int>>;
Q_GLOBAL_STATIC(QMetaTypeMutableViewRegistry, customTypesMutableViewRegistry)
/*!
- \fn bool QMetaType::registerConverter()
+ \fn template<typename From, typename To> bool QMetaType::registerConverter()
\since 5.2
Registers the possibility of an implicit conversion from type From to type To in the meta
type system. Returns \c true if the registration succeeded, otherwise false.
@@ -1755,7 +1779,7 @@ Q_GLOBAL_STATIC(QMetaTypeMutableViewRegistry, customTypesMutableViewRegistry)
*/
bool QMetaType::registerConverterFunction(const ConverterFunction &f, QMetaType from, QMetaType to)
{
- if (!customTypesConversionRegistry()->insertIfNotContains(qMakePair(from.id(), to.id()), f)) {
+ if (!customTypesConversionRegistry()->insertIfNotContains({from.id(), to.id()}, f)) {
qWarning("Type conversion already registered from type %s to type %s",
from.name(), to.name());
return false;
@@ -1788,7 +1812,7 @@ bool QMetaType::registerConverterFunction(const ConverterFunction &f, QMetaType
*/
bool QMetaType::registerMutableViewFunction(const MutableViewFunction &f, QMetaType from, QMetaType to)
{
- if (!customTypesMutableViewRegistry()->insertIfNotContains(qMakePair(from.id(), to.id()), f)) {
+ if (!customTypesMutableViewRegistry()->insertIfNotContains({from.id(), to.id()}, f)) {
qWarning("Mutable view on type already registered from type %s to type %s",
from.name(), to.name());
return false;
@@ -1856,7 +1880,7 @@ bool QMetaType::debugStream(QDebug& dbg, const void *rhs)
*/
/*!
- \fn bool QMetaType::hasRegisteredDebugStreamOperator()
+ \fn template<typename T> bool QMetaType::hasRegisteredDebugStreamOperator()
\deprecated
\since 5.2
@@ -2075,13 +2099,12 @@ static bool convertIterableToVariantHash(QMetaType fromType, const void *from, v
h.insert(it.key().toString(), it.value());
return true;
}
-#endif
static bool convertIterableToVariantPair(QMetaType fromType, const void *from, void *to)
{
- const QMetaType::ConverterFunction * const f =
- customTypesConversionRegistry()->function(qMakePair(fromType.id(),
- qMetaTypeId<QtMetaTypePrivate::QPairVariantInterfaceImpl>()));
+ const int targetId = qMetaTypeId<QtMetaTypePrivate::QPairVariantInterfaceImpl>();
+ const auto f = customTypesConversionRegistry()->function({fromType.id(), targetId});
+
if (!f)
return false;
@@ -2107,7 +2130,6 @@ static bool convertIterableToVariantPair(QMetaType fromType, const void *from, v
return true;
}
-#ifndef QT_BOOTSTRAPPED
static bool convertToSequentialIterable(QMetaType fromType, const void *from, void *to)
{
using namespace QtMetaTypePrivate;
@@ -2233,6 +2255,9 @@ static bool convertToAssociativeIterable(QMetaType fromType, const void *from, v
static bool canConvertMetaObject(QMetaType fromType, QMetaType toType)
{
+ if ((fromType.flags() & QMetaType::IsPointer) != (toType.flags() & QMetaType::IsPointer))
+ return false; // Can not convert between pointer and value
+
const QMetaObject *f = fromType.metaObject();
const QMetaObject *t = toType.metaObject();
if (f && t) {
@@ -2303,7 +2328,8 @@ static bool convertMetaObject(QMetaType fromType, const void *from, QMetaType to
*static_cast<void **>(to) = nullptr;
return fromType.metaObject()->inherits(toType.metaObject());
}
- } else {
+ } else if ((fromType.flags() & QMetaType::IsPointer) == (toType.flags() & QMetaType::IsPointer)) {
+ // fromType and toType are of same 'pointedness'
const QMetaObject *f = fromType.metaObject();
const QMetaObject *t = toType.metaObject();
if (f && t && f->inherits(t)) {
@@ -2314,7 +2340,7 @@ static bool convertMetaObject(QMetaType fromType, const void *from, QMetaType to
}
return false;
}
-#endif
+#endif // !QT_BOOTSTRAPPED
/*!
\fn bool QMetaType::convert(const void *from, int fromTypeId, void *to, int toTypeId)
@@ -2355,8 +2381,7 @@ bool QMetaType::convert(QMetaType fromType, const void *from, QMetaType toType,
if (moduleHelper->convert(from, fromTypeId, to, toTypeId))
return true;
}
- const QMetaType::ConverterFunction * const f =
- customTypesConversionRegistry()->function(qMakePair(fromTypeId, toTypeId));
+ const auto f = customTypesConversionRegistry()->function({fromTypeId, toTypeId});
if (f)
return (*f)(from, to);
@@ -2372,10 +2397,11 @@ bool QMetaType::convert(QMetaType fromType, const void *from, QMetaType toType,
}
}
+#ifndef QT_BOOTSTRAPPED
+# ifndef QT_NO_VARIANT
if (toTypeId == QVariantPair && convertIterableToVariantPair(fromType, from, to))
return true;
-#ifndef QT_BOOTSTRAPPED
// handle iterables
if (toTypeId == QVariantList && convertIterableToVariantList(fromType, from, to))
return true;
@@ -2385,6 +2411,7 @@ bool QMetaType::convert(QMetaType fromType, const void *from, QMetaType toType,
if (toTypeId == QVariantHash && convertIterableToVariantHash(fromType, from, to))
return true;
+# endif
if (toTypeId == qMetaTypeId<QSequentialIterable>())
return convertToSequentialIterable(fromType, from, to);
@@ -2411,8 +2438,7 @@ bool QMetaType::view(QMetaType fromType, void *from, QMetaType toType, void *to)
int fromTypeId = fromType.id();
int toTypeId = toType.id();
- const QMetaType::MutableViewFunction * const f =
- customTypesMutableViewRegistry()->function(qMakePair(fromTypeId, toTypeId));
+ const auto f = customTypesMutableViewRegistry()->function({fromTypeId, toTypeId});
if (f)
return (*f)(from, to);
@@ -2454,8 +2480,7 @@ bool QMetaType::canView(QMetaType fromType, QMetaType toType)
if (fromTypeId == UnknownType || toTypeId == UnknownType)
return false;
- const MutableViewFunction * const f =
- customTypesMutableViewRegistry()->function(qMakePair(fromTypeId, toTypeId));
+ const auto f = customTypesMutableViewRegistry()->function({fromTypeId, toTypeId});
if (f)
return true;
@@ -2570,7 +2595,8 @@ bool QMetaType::canConvert(QMetaType fromType, QMetaType toType)
if (toTypeId == qMetaTypeId<QAssociativeIterable>())
return canConvertToAssociativeIterable(fromType);
-
+#endif
+#ifndef QT_NO_VARIANT
if (toTypeId == QVariantList
&& canConvert(fromType, QMetaType::fromType<QSequentialIterable>())) {
return true;
@@ -2580,11 +2606,11 @@ bool QMetaType::canConvert(QMetaType fromType, QMetaType toType)
&& canConvert(fromType, QMetaType::fromType<QAssociativeIterable>())) {
return true;
}
-#endif
if (toTypeId == QVariantPair && hasRegisteredConverterFunction(
fromType, QMetaType::fromType<QtMetaTypePrivate::QPairVariantInterfaceImpl>()))
return true;
+#endif
if (fromType.flags() & IsEnumeration) {
if (toTypeId == QString || toTypeId == QByteArray)
@@ -2616,7 +2642,7 @@ bool QMetaType::canConvert(QMetaType fromType, QMetaType toType)
*/
/*!
- \fn bool QMetaType::hasRegisteredConverterFunction()
+ \fn template<typename From, typename To> bool QMetaType::hasRegisteredConverterFunction()
Returns \c true, if the meta type system has a registered conversion from type From to type To.
\since 5.2
\overload
@@ -2629,11 +2655,11 @@ bool QMetaType::canConvert(QMetaType fromType, QMetaType toType)
*/
bool QMetaType::hasRegisteredConverterFunction(QMetaType fromType, QMetaType toType)
{
- return customTypesConversionRegistry()->contains(qMakePair(fromType.id(), toType.id()));
+ return customTypesConversionRegistry()->contains({fromType.id(), toType.id()});
}
/*!
- \fn bool QMetaType::hasRegisteredMutableViewFunction()
+ \fn template<typename From, typename To> bool QMetaType::hasRegisteredMutableViewFunction()
Returns \c true, if the meta type system has a registered mutable view on type From of type To.
\since 6.0
\overload
@@ -2646,7 +2672,7 @@ bool QMetaType::hasRegisteredConverterFunction(QMetaType fromType, QMetaType toT
*/
bool QMetaType::hasRegisteredMutableViewFunction(QMetaType fromType, QMetaType toType)
{
- return customTypesMutableViewRegistry()->contains(qMakePair(fromType.id(), toType.id()));
+ return customTypesMutableViewRegistry()->contains({fromType.id(), toType.id()});
}
/*!
@@ -2897,6 +2923,59 @@ bool QMetaType::hasRegisteredDataStreamOperators() const
}
/*!
+ \since 6.6
+
+ If this metatype represents an enumeration, this method returns a
+ metatype of a numeric class of the same signedness and size as the
+ enums underlying type.
+ If it represents a QFlags type, it returns QMetaType::Int.
+ In all other cases an invalid QMetaType is returned.
+ */
+QMetaType QMetaType::underlyingType() const
+{
+ if (!d_ptr || !(flags() & IsEnumeration))
+ return {};
+ /* QFlags has enumeration set so that's handled here (qint32
+ case), as QFlags uses int as the underlying type
+ Note that we do some approximation here, as we cannot
+ differentiate between different underlying types of the
+ same size and signedness (consider char <-> (un)signed char,
+ int <-> long <-> long long).
+
+ ### TODO PENDING: QTBUG-111926 - QFlags supporting >32 bit int
+ */
+ if (flags() & IsUnsignedEnumeration) {
+ switch (sizeOf()) {
+ case 1:
+ return QMetaType::fromType<quint8>();
+ case 2:
+ return QMetaType::fromType<quint16>();
+ case 4:
+ return QMetaType::fromType<quint32>();
+ case 8:
+ return QMetaType::fromType<quint64>();
+ default:
+ break;
+ }
+ } else {
+ switch (sizeOf()) {
+ case 1:
+ return QMetaType::fromType<qint8>();
+ case 2:
+ return QMetaType::fromType<qint16>();
+ case 4:
+ return QMetaType::fromType<qint32>();
+ case 8:
+ return QMetaType::fromType<qint64>();
+ default:
+ break;
+ }
+ }
+ // int128 can be handled above once we have qint128
+ return QMetaType();
+}
+
+/*!
\fn bool QMetaType::load(QDataStream &stream, int type, void *data)
\overload
\deprecated
@@ -3008,7 +3087,7 @@ QMetaType QMetaType::fromName(QByteArrayView typeName)
*/
/*!
- \fn int qRegisterMetaType(const char *typeName)
+ \fn template <typename T> int qRegisterMetaType(const char *typeName)
\relates QMetaType
\obsolete
\threadsafe
@@ -3042,7 +3121,7 @@ QMetaType QMetaType::fromName(QByteArrayView typeName)
*/
/*!
- \fn int qRegisterMetaType()
+ \fn template <typename T> int qRegisterMetaType()
\relates QMetaType
\threadsafe
\since 4.2
@@ -3098,7 +3177,7 @@ QMetaType QMetaType::fromName(QByteArrayView typeName)
*/
/*!
- \fn int qMetaTypeId()
+ \fn template <typename T> int qMetaTypeId()
\relates QMetaType
\threadsafe
\since 4.1
@@ -3163,6 +3242,7 @@ QT_FOR_EACH_STATIC_PRIMITIVE_POINTER(QT_METATYPE_DECLARE_TEMPLATE_ITER)
QT_FOR_EACH_STATIC_CORE_CLASS(QT_METATYPE_DECLARE_TEMPLATE_ITER)
QT_FOR_EACH_STATIC_CORE_POINTER(QT_METATYPE_DECLARE_TEMPLATE_ITER)
QT_FOR_EACH_STATIC_CORE_TEMPLATE(QT_METATYPE_DECLARE_TEMPLATE_ITER)
+
#undef QT_METATYPE_DECLARE_TEMPLATE_ITER
#endif
}
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index 54341170d1..e3ef1474da 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -92,6 +92,12 @@ inline constexpr int qMetaTypeId();
#else
# define QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F)
#endif
+#ifndef QT_NO_VARIANT
+# define QT_FOR_EACH_STATIC_QVARIANT(F) \
+ F(QVariant, 41, QVariant)
+#else
+# define QT_FOR_EACH_STATIC_QVARIANT(F)
+#endif
#define QT_FOR_EACH_STATIC_CORE_CLASS(F)\
F(QChar, 7, QChar) \
@@ -113,7 +119,7 @@ inline constexpr int qMetaTypeId();
F(QPointF, 26, QPointF) \
QT_FOR_EACH_STATIC_EASINGCURVE(F) \
F(QUuid, 30, QUuid) \
- F(QVariant, 41, QVariant) \
+ QT_FOR_EACH_STATIC_QVARIANT(F) \
QT_FOR_EACH_STATIC_REGULAR_EXPRESSION(F) \
F(QJsonValue, 45, QJsonValue) \
F(QJsonObject, 46, QJsonObject) \
@@ -128,13 +134,20 @@ inline constexpr int qMetaTypeId();
#define QT_FOR_EACH_STATIC_CORE_POINTER(F)\
F(QObjectStar, 39, QObject*)
-#define QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\
+#ifndef QT_NO_VARIANT
+# define QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\
F(QVariantMap, 8, QVariantMap) \
F(QVariantList, 9, QVariantList) \
F(QVariantHash, 28, QVariantHash) \
F(QVariantPair, 58, QVariantPair) \
F(QByteArrayList, 49, QByteArrayList) \
F(QStringList, 11, QStringList) \
+ /**/
+#else
+# define QT_FOR_EACH_STATIC_CORE_TEMPLATE(F)\
+ F(QByteArrayList, 49, QByteArrayList) \
+ F(QStringList, 11, QStringList)
+#endif
#if QT_CONFIG(shortcut)
#define QT_FOR_EACH_STATIC_KEYSEQUENCE_CLASS(F)\
@@ -188,12 +201,20 @@ inline constexpr int qMetaTypeId();
F(UInt, -1, uint, "quint32") \
F(LongLong, -1, qlonglong, "qint64") \
F(ULongLong, -1, qulonglong, "quint64") \
+ F(QByteArrayList, -1, QByteArrayList, "QList<QByteArray>") \
+ F(QStringList, -1, QStringList, "QList<QString>") \
+ QT_FOR_EACH_STATIC_VARIANT_ALIAS_TYPE(F)
+
+#ifndef QT_NO_VARIANT
+#define QT_FOR_EACH_STATIC_VARIANT_ALIAS_TYPE(F) \
F(QVariantList, -1, QVariantList, "QList<QVariant>") \
F(QVariantMap, -1, QVariantMap, "QMap<QString,QVariant>") \
F(QVariantHash, -1, QVariantHash, "QHash<QString,QVariant>") \
F(QVariantPair, -1, QVariantPair, "QPair<QVariant,QVariant>") \
- F(QByteArrayList, -1, QByteArrayList, "QList<QByteArray>") \
- F(QStringList, -1, QStringList, "QList<QString>") \
+ /**/
+#else
+#define QT_FOR_EACH_STATIC_VARIANT_ALIAS_TYPE(F)
+#endif
#define QT_FOR_EACH_STATIC_TYPE(F)\
QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\
@@ -246,7 +267,14 @@ using NonConstMetaTypeInterface = const QMetaTypeInterface;
class QMetaTypeInterface
{
public:
- ushort revision; // 0 in Qt 6.0. Can increase if new field are added
+
+ /* Revision: Can increase if new field are added, or if semantics changes
+ 0: Initial Revision
+ 1: the meaning of the NeedsDestruction flag changed
+ */
+ static inline constexpr ushort CurrentRevision = 1;
+
+ ushort revision;
ushort alignment;
uint size;
uint flags;
@@ -485,6 +513,8 @@ public:
#endif
#endif
+ QMetaType underlyingType() const;
+
template<typename T>
constexpr static QMetaType fromType();
static QMetaType fromName(QByteArrayView name);
@@ -2226,6 +2256,7 @@ struct is_std_pair<std::pair<T1_, T2_>> : std::true_type {
using T2 = T2_;
};
+namespace TypeNameHelper {
template<typename T>
constexpr auto typenameHelper()
{
@@ -2267,15 +2298,15 @@ constexpr auto typenameHelper()
QT_STRINGIFY(QT_NAMESPACE) "::"
#endif
#if defined(Q_CC_MSVC) && defined(Q_CC_CLANG)
- "auto __cdecl QtPrivate::typenameHelper(void) [T = "
+ "auto __cdecl QtPrivate::TypeNameHelper::typenameHelper(void) [T = "
#elif defined(Q_CC_MSVC)
- "auto __cdecl QtPrivate::typenameHelper<"
+ "auto __cdecl QtPrivate::TypeNameHelper::typenameHelper<"
#elif defined(Q_CC_CLANG)
- "auto QtPrivate::typenameHelper() [T = "
+ "auto QtPrivate::TypeNameHelper::typenameHelper() [T = "
#elif defined(Q_CC_GHS)
- "auto QtPrivate::typenameHelper<T>()[with T="
+ "auto QtPrivate::TypeNameHelper::typenameHelper<T>()[with T="
#else
- "constexpr auto QtPrivate::typenameHelper() [with T = "
+ "constexpr auto QtPrivate::TypeNameHelper::typenameHelper() [with T = "
#endif
) - 1;
#if defined(Q_CC_MSVC) && !defined(Q_CC_CLANG)
@@ -2301,6 +2332,8 @@ constexpr auto typenameHelper()
return result;
}
}
+} // namespace TypeNameHelper
+using TypeNameHelper::typenameHelper;
template<typename T, typename = void>
struct BuiltinMetaType : std::integral_constant<int, 0>
@@ -2357,18 +2390,20 @@ struct QDebugStreamOperatorForType <T, false>
template<typename T, bool = QTypeTraits::has_stream_operator_v<QDataStream, T>>
struct QDataStreamOperatorForType
{
- static void dataStreamOut(const QMetaTypeInterface *, QDataStream &ds, const void *a)
- { ds << *reinterpret_cast<const T *>(a); }
- static void dataStreamIn(const QMetaTypeInterface *, QDataStream &ds, void *a)
- { ds >> *reinterpret_cast<T *>(a); }
+ static constexpr QMetaTypeInterface::DataStreamOutFn dataStreamOut = nullptr;
+ static constexpr QMetaTypeInterface::DataStreamInFn dataStreamIn = nullptr;
};
+#ifndef QT_NO_DATASTREAM
template<typename T>
-struct QDataStreamOperatorForType <T, false>
+struct QDataStreamOperatorForType <T, true>
{
- static constexpr QMetaTypeInterface::DataStreamOutFn dataStreamOut = nullptr;
- static constexpr QMetaTypeInterface::DataStreamInFn dataStreamIn = nullptr;
+ static void dataStreamOut(const QMetaTypeInterface *, QDataStream &ds, const void *a)
+ { ds << *reinterpret_cast<const T *>(a); }
+ static void dataStreamIn(const QMetaTypeInterface *, QDataStream &ds, void *a)
+ { ds >> *reinterpret_cast<T *>(a); }
};
+#endif
// Performance optimization:
//
@@ -2461,7 +2496,7 @@ struct QMetaTypeInterfaceWrapper
using InterfaceType = std::conditional_t<IsConstMetaTypeInterface, const QMetaTypeInterface, NonConstMetaTypeInterface>;
static inline InterfaceType metaType = {
- /*.revision=*/ 0,
+ /*.revision=*/ QMetaTypeInterface::CurrentRevision,
/*.alignment=*/ alignof(T),
/*.size=*/ sizeof(T),
/*.flags=*/ QMetaTypeForType<T>::Flags,
diff --git a/src/corelib/kernel/qmetatype_p.h b/src/corelib/kernel/qmetatype_p.h
index 3defbc70ef..7e0457771f 100644
--- a/src/corelib/kernel/qmetatype_p.h
+++ b/src/corelib/kernel/qmetatype_p.h
@@ -38,20 +38,21 @@ QT_BEGIN_NAMESPACE
assign_and_return \
}
-class QMetaTypeModuleHelper
+class Q_CORE_EXPORT QMetaTypeModuleHelper
{
Q_DISABLE_COPY_MOVE(QMetaTypeModuleHelper)
protected:
QMetaTypeModuleHelper() = default;
~QMetaTypeModuleHelper() = default;
public:
+ Q_WEAK_OVERLOAD // prevent it from entering the ABI and rendering constexpr useless
static constexpr auto makePair(int from, int to) -> quint64
{
return (quint64(from) << 32) + quint64(to);
}
virtual const QtPrivate::QMetaTypeInterface *interfaceForType(int) const = 0;
- virtual bool convert(const void *, int, void *, int) const { return false; }
+ virtual bool convert(const void *, int, void *, int) const;
};
extern Q_CORE_EXPORT const QMetaTypeModuleHelper *qMetaTypeGuiHelper;
@@ -152,7 +153,12 @@ inline bool isMoveConstructible(const QtPrivate::QMetaTypeInterface *iface) noex
inline bool isDestructible(const QtPrivate::QMetaTypeInterface *iface) noexcept
{
- return checkMetaTypeFlagOrPointer(iface, iface->dtor, QMetaType::NeedsDestruction);
+ /* For metatypes of revision 1, the NeedsDestruction was set even for trivially
+ destructible types, but their dtor pointer would be null.
+ For that reason, we need the additional check here.
+ */
+ return iface->revision < 1 ||
+ checkMetaTypeFlagOrPointer(iface, iface->dtor, QMetaType::NeedsDestruction);
}
inline void defaultConstruct(const QtPrivate::QMetaTypeInterface *iface, void *where)
@@ -173,6 +179,15 @@ inline void copyConstruct(const QtPrivate::QMetaTypeInterface *iface, void *wher
memcpy(where, copy, iface->size);
}
+inline void moveConstruct(const QtPrivate::QMetaTypeInterface *iface, void *where, void *copy)
+{
+ Q_ASSERT(isMoveConstructible(iface));
+ if (iface->moveCtr)
+ iface->moveCtr(iface, where, copy);
+ else
+ memcpy(where, copy, iface->size);
+}
+
inline void construct(const QtPrivate::QMetaTypeInterface *iface, void *where, const void *copy)
{
if (copy)
diff --git a/src/corelib/kernel/qmimedata.cpp b/src/corelib/kernel/qmimedata.cpp
index 6650d2f626..2c0a89dbd7 100644
--- a/src/corelib/kernel/qmimedata.cpp
+++ b/src/corelib/kernel/qmimedata.cpp
@@ -12,12 +12,12 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-static inline QString textUriListLiteral() { return QStringLiteral("text/uri-list"); }
-static inline QString textHtmlLiteral() { return QStringLiteral("text/html"); }
-static inline QString textPlainLiteral() { return QStringLiteral("text/plain"); }
-static inline QString textPlainUtf8Literal() { return QStringLiteral("text/plain;charset=utf-8"); }
-static inline QString applicationXColorLiteral() { return QStringLiteral("application/x-color"); }
-static inline QString applicationXQtImageLiteral() { return QStringLiteral("application/x-qt-image"); }
+static inline QString textUriListLiteral() { return u"text/uri-list"_s; }
+static inline QString textHtmlLiteral() { return u"text/html"_s; }
+static inline QString textPlainLiteral() { return u"text/plain"_s; }
+static inline QString textPlainUtf8Literal() { return u"text/plain;charset=utf-8"_s; }
+static inline QString applicationXColorLiteral() { return u"application/x-color"_s; }
+static inline QString applicationXQtImageLiteral() { return u"application/x-qt-image"_s; }
struct QMimeDataStruct
{
@@ -76,6 +76,28 @@ QVariant QMimeDataPrivate::getData(const QString &format) const
return it->data;
}
+static QList<QVariant> dataToUrls(QByteArrayView text)
+{
+ QList<QVariant> list;
+ qsizetype newLineIndex = -1;
+ qsizetype from = 0;
+ const char *begin = text.data();
+ while ((newLineIndex = text.indexOf('\n', from)) != -1) {
+ const auto bav = QByteArrayView(begin + from, begin + newLineIndex).trimmed();
+ if (!bav.isEmpty())
+ list.push_back(QUrl::fromEncoded(bav));
+ from = newLineIndex + 1;
+ if (from >= text.size())
+ break;
+ }
+ if (from != text.size()) {
+ const auto bav = QByteArrayView(begin + from, text.end()).trimmed();
+ if (!bav.isEmpty())
+ list.push_back(QUrl::fromEncoded(bav));
+ }
+ return list;
+}
+
QVariant QMimeDataPrivate::retrieveTypedData(const QString &format, QMetaType type) const
{
Q_Q(const QMimeData);
@@ -92,9 +114,10 @@ QVariant QMimeDataPrivate::retrieveTypedData(const QString &format, QMetaType ty
QString text;
int numUrls = 0;
const QList<QVariant> list = data.toList();
- for (int i = 0; i < list.size(); ++i) {
- if (list.at(i).metaType().id() == QMetaType::QUrl) {
- text += list.at(i).toUrl().toDisplayString() + u'\n';
+ for (const auto &element : list) {
+ if (element.metaType().id() == QMetaType::QUrl) {
+ text += element.toUrl().toDisplayString();
+ text += u'\n';
++numUrls;
}
}
@@ -146,21 +169,13 @@ QVariant QMimeDataPrivate::retrieveTypedData(const QString &format, QMetaType ty
Q_FALLTHROUGH();
}
case QMetaType::QUrl: {
- QByteArray ba = data.toByteArray();
+ auto bav = data.view<QByteArrayView>();
// Qt 3.x will send text/uri-list with a trailing
// null-terminator (that is *not* sent for any other
// text/* mime-type), so chop it off
- if (ba.endsWith('\0'))
- ba.chop(1);
-
- QList<QByteArray> urls = ba.split('\n');
- QList<QVariant> list;
- for (int i = 0; i < urls.size(); ++i) {
- QByteArray ba = urls.at(i).trimmed();
- if (!ba.isEmpty())
- list.append(QUrl::fromEncoded(ba));
- }
- return list;
+ if (bav.endsWith('\0'))
+ bav.chop(1);
+ return dataToUrls(bav);
}
default:
break;
@@ -180,10 +195,10 @@ QVariant QMimeDataPrivate::retrieveTypedData(const QString &format, QMetaType ty
case QMetaType::QVariantList: {
// has to be list of URLs
QByteArray result;
- QList<QVariant> list = data.toList();
- for (int i = 0; i < list.size(); ++i) {
- if (list.at(i).metaType().id() == QMetaType::QUrl) {
- result += list.at(i).toUrl().toEncoded();
+ const QList<QVariant> list = data.toList();
+ for (const auto &element : list) {
+ if (element.metaType().id() == QMetaType::QUrl) {
+ result += element.toUrl().toEncoded();
result += "\r\n";
}
}
@@ -318,10 +333,10 @@ QList<QUrl> QMimeData::urls() const
if (data.metaType().id() == QMetaType::QUrl)
urls.append(data.toUrl());
else if (data.metaType().id() == QMetaType::QVariantList) {
- QList<QVariant> list = data.toList();
- for (int i = 0; i < list.size(); ++i) {
- if (list.at(i).metaType().id() == QMetaType::QUrl)
- urls.append(list.at(i).toUrl());
+ const QList<QVariant> list = data.toList();
+ for (const auto &element : list) {
+ if (element.metaType().id() == QMetaType::QUrl)
+ urls.append(element.toUrl());
}
}
return urls;
@@ -341,13 +356,7 @@ QList<QUrl> QMimeData::urls() const
void QMimeData::setUrls(const QList<QUrl> &urls)
{
Q_D(QMimeData);
- QList<QVariant> list;
- const int numUrls = urls.size();
- list.reserve(numUrls);
- for (int i = 0; i < numUrls; ++i)
- list.append(urls.at(i));
-
- d->setData(textUriListLiteral(), list);
+ d->setData(textUriListLiteral(), QList<QVariant>(urls.cbegin(), urls.cend()));
}
/*!
@@ -560,17 +569,10 @@ void QMimeData::setData(const QString &mimeType, const QByteArray &data)
Q_D(QMimeData);
if (mimeType == "text/uri-list"_L1) {
- QByteArray ba = data;
+ auto ba = QByteArrayView(data);
if (ba.endsWith('\0'))
ba.chop(1);
- QList<QByteArray> urls = ba.split('\n');
- QList<QVariant> list;
- for (int i = 0; i < urls.size(); ++i) {
- QByteArray ba = urls.at(i).trimmed();
- if (!ba.isEmpty())
- list.append(QUrl::fromEncoded(ba));
- }
- d->setData(mimeType, list);
+ d->setData(mimeType, dataToUrls(ba));
} else {
d->setData(mimeType, QVariant(data));
}
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 8293b819a0..e1129c5d25 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -12,6 +12,7 @@
#include "qabstracteventdispatcher_p.h"
#include "qcoreapplication.h"
#include "qcoreapplication_p.h"
+#include "qcoreevent_p.h"
#include "qloggingcategory.h"
#include "qvariant.h"
#include "qmetaobject.h"
@@ -21,7 +22,6 @@
#include <qthread.h>
#include <private/qthread_p.h>
#include <qdebug.h>
-#include <qpair.h>
#include <qvarlengtharray.h>
#include <qscopeguard.h>
#include <qset.h>
@@ -178,6 +178,7 @@ QObjectPrivate::QObjectPrivate(int version)
isQuickItem = false;
willBeWidget = false;
wasWidget = false;
+ receiveParentEvents = false; // If object wants ParentAboutToChange and ParentChange
}
QObjectPrivate::~QObjectPrivate()
@@ -190,8 +191,8 @@ QObjectPrivate::~QObjectPrivate()
thisThreadData->eventDispatcher.loadRelaxed()->unregisterTimers(q_ptr);
// release the timer ids back to the pool
- for (int i = 0; i < extraData->runningTimers.size(); ++i)
- QAbstractEventDispatcherPrivate::releaseTimerId(extraData->runningTimers.at(i));
+ for (auto id : std::as_const(extraData->runningTimers))
+ QAbstractEventDispatcherPrivate::releaseTimerId(id);
} else {
qWarning("QObject::~QObject: Timers cannot be stopped from another thread");
}
@@ -226,32 +227,11 @@ static void computeOffsets(const QMetaObject *metaobject, int *signalOffset, int
}
// Used by QAccessibleWidget
-bool QObjectPrivate::isSender(const QObject *receiver, const char *signal) const
-{
- Q_Q(const QObject);
- int signal_index = signalIndex(signal);
- ConnectionData *cd = connections.loadRelaxed();
- if (signal_index < 0 || !cd)
- return false;
- QBasicMutexLocker locker(signalSlotLock(q));
- if (signal_index < cd->signalVectorCount()) {
- const QObjectPrivate::Connection *c = cd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
-
- while (c) {
- if (c->receiver.loadRelaxed() == receiver)
- return true;
- c = c->nextConnectionList.loadRelaxed();
- }
- }
- return false;
-}
-
-// Used by QAccessibleWidget
QObjectList QObjectPrivate::receiverList(const char *signal) const
{
QObjectList returnValue;
int signal_index = signalIndex(signal);
- ConnectionData *cd = connections.loadRelaxed();
+ ConnectionData *cd = connections.loadAcquire();
if (signal_index < 0 || !cd)
return returnValue;
if (signal_index < cd->signalVectorCount()) {
@@ -267,26 +247,17 @@ QObjectList QObjectPrivate::receiverList(const char *signal) const
return returnValue;
}
-// Used by QAccessibleWidget
-QObjectList QObjectPrivate::senderList() const
-{
- QObjectList returnValue;
- ConnectionData *cd = connections.loadRelaxed();
- if (cd) {
- QBasicMutexLocker locker(signalSlotLock(q_func()));
- for (Connection *c = cd->senders; c; c = c->next)
- returnValue << c->sender;
- }
- return returnValue;
-}
-
+/*!
+ \internal
+ The signalSlotLock() of the sender must be locked while calling this function
+*/
inline void QObjectPrivate::ensureConnectionData()
{
if (connections.loadRelaxed())
return;
ConnectionData *cd = new ConnectionData;
cd->ref.ref();
- connections.storeRelaxed(cd);
+ connections.storeRelease(cd);
}
/*!
@@ -451,7 +422,7 @@ bool QObjectPrivate::isSignalConnected(uint signalIndex, bool checkDeclarative)
if (checkDeclarative && isDeclarativeSignalConnected(signalIndex))
return true;
- ConnectionData *cd = connections.loadRelaxed();
+ ConnectionData *cd = connections.loadAcquire();
if (!cd)
return false;
SignalVector *signalVector = cd->signalVector.loadRelaxed();
@@ -474,7 +445,7 @@ bool QObjectPrivate::isSignalConnected(uint signalIndex, bool checkDeclarative)
bool QObjectPrivate::maybeSignalConnected(uint signalIndex) const
{
- ConnectionData *cd = connections.loadRelaxed();
+ ConnectionData *cd = connections.loadAcquire();
if (!cd)
return false;
SignalVector *signalVector = cd->signalVector.loadRelaxed();
@@ -551,7 +522,7 @@ QMetaCallEvent::QMetaCallEvent(QtPrivate::QSlotObjectBase *slotO,
const QObject *sender, int signalId,
void **args, QSemaphore *semaphore)
: QAbstractMetaCallEvent(sender, signalId, semaphore),
- d({slotO, args, nullptr, 0, 0, ushort(-1)}),
+ d({QtPrivate::SlotObjUniquePtr{slotO}, args, nullptr, 0, 0, ushort(-1)}),
prealloc_()
{
if (d.slotObj_)
@@ -561,6 +532,21 @@ QMetaCallEvent::QMetaCallEvent(QtPrivate::QSlotObjectBase *slotO,
/*!
\internal
+ Used for blocking queued connections, just passes \a args through without
+ allocating any memory.
+ */
+QMetaCallEvent::QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotO,
+ const QObject *sender, int signalId,
+ void **args, QSemaphore *semaphore)
+ : QAbstractMetaCallEvent(sender, signalId, semaphore),
+ d{std::move(slotO), args, nullptr, 0, 0, ushort(-1)},
+ prealloc_()
+{
+}
+
+/*!
+ \internal
+
Allocates memory for \a nargs; code creating an event needs to initialize
the void* and int arrays by accessing \a args() and \a types(), respectively.
*/
@@ -585,7 +571,7 @@ QMetaCallEvent::QMetaCallEvent(QtPrivate::QSlotObjectBase *slotO,
const QObject *sender, int signalId,
int nargs)
: QAbstractMetaCallEvent(sender, signalId),
- d({slotO, nullptr, nullptr, nargs, 0, ushort(-1)}),
+ d({QtPrivate::SlotObjUniquePtr(slotO), nullptr, nullptr, nargs, 0, ushort(-1)}),
prealloc_()
{
if (d.slotObj_)
@@ -595,6 +581,22 @@ QMetaCallEvent::QMetaCallEvent(QtPrivate::QSlotObjectBase *slotO,
/*!
\internal
+
+ Allocates memory for \a nargs; code creating an event needs to initialize
+ the void* and int arrays by accessing \a args() and \a types(), respectively.
+ */
+QMetaCallEvent::QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotO,
+ const QObject *sender, int signalId,
+ int nargs)
+ : QAbstractMetaCallEvent(sender, signalId),
+ d{std::move(slotO), nullptr, nullptr, nargs, 0, ushort(-1)},
+ prealloc_()
+{
+ allocArgs();
+}
+
+/*!
+ \internal
*/
QMetaCallEvent::~QMetaCallEvent()
{
@@ -607,8 +609,6 @@ QMetaCallEvent::~QMetaCallEvent()
if (reinterpret_cast<void *>(d.args_) != reinterpret_cast<void *>(prealloc_))
free(d.args_);
}
- if (d.slotObj_)
- d.slotObj_->destroyIfLastRef();
}
/*!
@@ -626,6 +626,25 @@ void QMetaCallEvent::placeMetaCall(QObject *object)
}
}
+QMetaCallEvent* QMetaCallEvent::create_impl(QtPrivate::SlotObjUniquePtr slotObj,
+ const QObject *sender, int signal_index,
+ size_t argc, const void* const argp[],
+ const QMetaType metaTypes[])
+{
+ auto metaCallEvent = std::make_unique<QMetaCallEvent>(std::move(slotObj), sender,
+ signal_index, int(argc));
+
+ void **args = metaCallEvent->args();
+ QMetaType *types = metaCallEvent->types();
+ for (size_t i = 0; i < argc; ++i) {
+ types[i] = metaTypes[i];
+ args[i] = types[i].create(argp[i]);
+ Q_CHECK_PTR(!i || args[i]);
+ }
+
+ return metaCallEvent.release();
+}
+
/*!
\class QSignalBlocker
\brief Exception-safe wrapper around QObject::blockSignals().
@@ -713,6 +732,14 @@ void QMetaCallEvent::placeMetaCall(QObject *object)
*/
/*!
+ \fn void QSignalBlocker::dismiss()
+ \since 6.7
+ Dismisses the QSignalBlocker. It will no longer access the QObject
+ passed to its constructor. unblock(), reblock(), as well as
+ ~QSignalBlocker() will have no effect.
+*/
+
+/*!
\class QObject
\inmodule QtCore
\brief The QObject class is the base class of all Qt objects.
@@ -753,7 +780,7 @@ void QMetaCallEvent::placeMetaCall(QObject *object)
to catch child events.
Last but not least, QObject provides the basic timer support in
- Qt; see QTimer for high-level support for timers.
+ Qt; see QChronoTimer for high-level support for timers.
Notice that the Q_OBJECT macro is mandatory for any object that
implements signals, slots or properties. You also need to run the
@@ -836,20 +863,20 @@ void QMetaCallEvent::placeMetaCall(QObject *object)
\l uic generates code that invokes this function to enable
auto-connection to be performed between widgets on forms created
- with \e{Qt Designer}. More information about using auto-connection with \e{Qt Designer} is
+ with \e{\QD}. More information about using auto-connection with \e{\QD} is
given in the \l{Using a Designer UI File in Your Application} section of
- the \e{Qt Designer} manual.
+ the \l{Qt Widgets Designer Manual}{\QD} manual.
\section1 Dynamic Properties
- From Qt 4.2, dynamic properties can be added to and removed from QObject
+ Dynamic properties can be added to and removed from QObject
instances at run-time. Dynamic properties do not need to be declared at
compile-time, yet they provide the same advantages as static properties
and are manipulated using the same API - using property() to read them
and setProperty() to write them.
- From Qt 4.3, dynamic properties are supported by
- \l{Qt Designer's Widget Editing Mode#The Property Editor}{Qt Designer},
+ Dynamic properties are supported by
+ \l{Qt Widgets Designer's Widget Editing Mode#The Property Editor}{\QD},
and both standard Qt widgets and user-created forms can be given dynamic
properties.
@@ -966,8 +993,8 @@ void QObjectPrivate::clearBindingStorage()
outside the parent. If you still do, the destroyed() signal gives
you an opportunity to detect when an object is destroyed.
- \warning Deleting a QObject while pending events are waiting to
- be delivered can cause a crash. You must not delete the QObject
+ \warning Deleting a QObject while it is handling an event
+ delivered to it can cause a crash. You must not delete the QObject
directly if it exists in a different thread than the one currently
executing. Use deleteLater() instead, which will cause the event
loop to delete the object after all pending events have been
@@ -1016,7 +1043,7 @@ QObject::~QObject()
if (!d->isDeletingChildren && d->declarativeData && QAbstractDeclarativeData::destroyed)
QAbstractDeclarativeData::destroyed(d->declarativeData, this);
- QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
+ QObjectPrivate::ConnectionData *cd = d->connections.loadAcquire();
if (cd) {
if (cd->currentSender) {
cd->currentSender->receiverDeleted();
@@ -1024,7 +1051,7 @@ QObject::~QObject()
}
QBasicMutex *signalSlotMutex = signalSlotLock(this);
- QBasicMutexLocker locker(signalSlotMutex);
+ QMutexLocker locker(signalSlotMutex);
// disconnect all receivers
int receiverCount = cd->signalVectorCount();
@@ -1202,8 +1229,7 @@ inline QObjectPrivate::Connection::~Connection()
\c dynamic_cast(), with the advantages that it doesn't require
RTTI support and it works across dynamic library boundaries.
- qobject_cast() can also be used in conjunction with interfaces;
- see the \l{tools/plugandpaint/app}{Plug & Paint} example for details.
+ qobject_cast() can also be used in conjunction with interfaces.
\warning If T isn't declared with the Q_OBJECT macro, this
function's return value is undefined.
@@ -1273,7 +1299,7 @@ void QObject::doSetObjectName(const QString &name)
d->extraData->objectName.removeBindingUnlessInWrapper();
- if (d->extraData->objectName != name) {
+ if (d->extraData->objectName.valueBypassingBindings() != name) {
d->extraData->objectName.setValueBypassingBindings(name);
d->extraData->objectName.notify(); // also emits a signal
}
@@ -1291,7 +1317,7 @@ void QObject::setObjectName(QAnyStringView name)
d->extraData->objectName.removeBindingUnlessInWrapper();
- if (d->extraData->objectName != name) {
+ if (d->extraData->objectName.valueBypassingBindings() != name) {
d->extraData->objectName.setValueBypassingBindings(name.toString());
d->extraData->objectName.notify(); // also emits a signal
}
@@ -1374,18 +1400,21 @@ bool QObject::event(QEvent *e)
break;
case QEvent::DeferredDelete:
- qDeleteInEventHandler(this);
+ qCDebug(lcDeleteLater) << "Deferred deleting" << this;
+ delete this;
break;
case QEvent::MetaCall:
{
QAbstractMetaCallEvent *mce = static_cast<QAbstractMetaCallEvent*>(e);
- if (!d_func()->connections.loadRelaxed()) {
- QBasicMutexLocker locker(signalSlotLock(this));
+ QObjectPrivate::ConnectionData *connections = d_func()->connections.loadAcquire();
+ if (!connections) {
+ QMutexLocker locker(signalSlotLock(this));
d_func()->ensureConnectionData();
+ connections = d_func()->connections.loadRelaxed();
}
- QObjectPrivate::Sender sender(this, const_cast<QObject*>(mce->sender()), mce->signalId());
+ QObjectPrivate::Sender sender(this, const_cast<QObject*>(mce->sender()), mce->signalId(), connections);
mce->placeMetaCall(this);
break;
@@ -1396,12 +1425,20 @@ bool QObject::event(QEvent *e)
QThreadData *threadData = d->threadData.loadRelaxed();
QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed();
if (eventDispatcher) {
- QList<QAbstractEventDispatcher::TimerInfo> timers = eventDispatcher->registeredTimers(this);
+ QList<QAbstractEventDispatcher::TimerInfoV2> timers = eventDispatcher->timersForObject(this);
if (!timers.isEmpty()) {
+ const bool res = eventDispatcher->unregisterTimers(this);
// do not to release our timer ids back to the pool (since the timer ids are moving to a new thread).
- eventDispatcher->unregisterTimers(this);
- QMetaObject::invokeMethod(this, "_q_reregisterTimers", Qt::QueuedConnection,
- Q_ARG(void*, (new QList<QAbstractEventDispatcher::TimerInfo>(timers))));
+ Q_ASSERT_X(res, Q_FUNC_INFO,
+ "QAbstractEventDispatcher::unregisterTimers() returned false,"
+ " but there are timers associated with this object.");
+ auto reRegisterTimers = [this, timers = std::move(timers)]() {
+ QAbstractEventDispatcher *eventDispatcher =
+ d_func()->threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
+ for (const auto &ti : timers)
+ eventDispatcher->registerTimer(ti.timerId, ti.interval, ti.timerType, this);
+ };
+ QMetaObject::invokeMethod(this, std::move(reRegisterTimers), Qt::QueuedConnection);
}
}
break;
@@ -1423,9 +1460,9 @@ bool QObject::event(QEvent *e)
This event handler can be reimplemented in a subclass to receive
timer events for the object.
- QTimer provides a higher-level interface to the timer
- functionality, and also more general information about timers. The
- timer event is passed in the \a event parameter.
+ QChronoTimer provides higher-level interfaces to the timer functionality,
+ and also more general information about timers. The timer event is passed
+ in the \a event parameter.
\sa startTimer(), killTimer(), event()
*/
@@ -1564,9 +1601,9 @@ QThread *QObject::thread() const
}
/*!
- Changes the thread affinity for this object and its children. The
- object cannot be moved if it has a parent. Event processing will
- continue in the \a targetThread.
+ Changes the thread affinity for this object and its children and
+ returns \c true on success. The object cannot be moved if it has a
+ parent. Event processing will continue in the \a targetThread.
To move an object to the main thread, use QApplication::instance()
to retrieve a pointer to the current application, and then use
@@ -1603,26 +1640,26 @@ QThread *QObject::thread() const
\sa thread()
*/
-void QObject::moveToThread(QThread *targetThread)
+bool QObject::moveToThread(QThread *targetThread QT6_IMPL_NEW_OVERLOAD_TAIL)
{
Q_D(QObject);
if (d->threadData.loadRelaxed()->thread.loadAcquire() == targetThread) {
// object is already in this thread
- return;
+ return true;
}
if (d->parent != nullptr) {
qWarning("QObject::moveToThread: Cannot move objects with a parent");
- return;
+ return false;
}
if (d->isWidget) {
qWarning("QObject::moveToThread: Widgets cannot be moved to a new thread");
- return;
+ return false;
}
if (!d->bindingStorage.isEmpty()) {
qWarning("QObject::moveToThread: Can not move objects that contain bindings or are used in bindings to a new thread.");
- return;
+ return false;
}
QThreadData *currentData = QThreadData::current();
@@ -1642,7 +1679,7 @@ void QObject::moveToThread(QThread *targetThread)
"DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded.");
#endif
- return;
+ return false;
}
// prepare to move
@@ -1676,6 +1713,7 @@ void QObject::moveToThread(QThread *targetThread)
// now currentData can commit suicide if it wants to
currentData->deref();
+ return true;
}
void QObjectPrivate::moveToThread_helper()
@@ -1718,7 +1756,7 @@ void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData
}
// the current emitting thread shouldn't restore currentSender after calling moveToThread()
- ConnectionData *cd = connections.loadRelaxed();
+ ConnectionData *cd = connections.loadAcquire();
if (cd) {
if (cd->currentSender) {
cd->currentSender->receiverDeleted();
@@ -1757,19 +1795,6 @@ void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData
}
}
-void QObjectPrivate::_q_reregisterTimers(void *pointer)
-{
- Q_Q(QObject);
- QList<QAbstractEventDispatcher::TimerInfo> *timerList = reinterpret_cast<QList<QAbstractEventDispatcher::TimerInfo> *>(pointer);
- QAbstractEventDispatcher *eventDispatcher = threadData.loadRelaxed()->eventDispatcher.loadRelaxed();
- for (int i = 0; i < timerList->size(); ++i) {
- const QAbstractEventDispatcher::TimerInfo &ti = timerList->at(i);
- eventDispatcher->registerTimer(ti.timerId, ti.interval, ti.timerType, q);
- }
- delete timerList;
-}
-
-
//
// The timer flag hasTimer is set when startTimer is called.
// It is not reset when killing the timer because more than
@@ -1786,18 +1811,19 @@ void QObjectPrivate::_q_reregisterTimers(void *pointer)
startTimer(std::chrono::milliseconds{interval}, timerType);
\endcode
- \sa timerEvent(), killTimer(), QTimer::singleShot()
+ \sa timerEvent(), killTimer(), QChronoTimer::singleShot()
*/
int QObject::startTimer(int interval, Qt::TimerType timerType)
{
+ // no overflow can happen here:
+ // 2^31 ms * 1,000,000 always fits a 64-bit signed integer type
return startTimer(std::chrono::milliseconds{interval}, timerType);
}
/*!
\since 5.9
\overload
- \fn int QObject::startTimer(std::chrono::milliseconds interval, Qt::TimerType timerType)
Starts a timer and returns a timer identifier, or returns zero if
it could not start a timer.
@@ -1818,27 +1844,41 @@ int QObject::startTimer(int interval, Qt::TimerType timerType)
\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
+ Note that the accuracy of QChronoTimer 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.
+ The QTimer and QChronoTimer classes provide 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
+ QChronoTimer but less clumsy than using timer IDs directly.
+
+ \sa timerEvent(), killTimer(), QChronoTimer::singleShot()
+
+ \note Starting from Qt 6.8 the type of \a interval
+ is \c std::chrono::nanoseconds, prior to that it was \c
+ std::chrono::milliseconds. This change is backwards compatible with
+ older releases of Qt.
+
+ \note In Qt 6.8, QObject was changed to use Qt::TimerId to represent timer
+ IDs. This method converts the TimerId to int for backwards compatibility
+ reasons, however you can use Qt::TimerId to check the value returned by
+ this method, for example:
+ \snippet code/src_corelib_kernel_qobject.cpp invalid-timer-id
- \sa timerEvent(), killTimer(), QTimer::singleShot()
*/
-int QObject::startTimer(std::chrono::milliseconds interval, Qt::TimerType timerType)
+int QObject::startTimer(std::chrono::nanoseconds interval, Qt::TimerType timerType)
{
Q_D(QObject);
using namespace std::chrono_literals;
- if (Q_UNLIKELY(interval < 0ms)) {
+ if (Q_UNLIKELY(interval < 0ns)) {
qWarning("QObject::startTimer: Timers cannot have negative intervals");
return 0;
}
@@ -1854,10 +1894,10 @@ int QObject::startTimer(std::chrono::milliseconds interval, Qt::TimerType timerT
}
auto dispatcher = thisThreadData->eventDispatcher.loadRelaxed();
- int timerId = dispatcher->registerTimer(interval.count(), timerType, this);
+ Qt::TimerId timerId = dispatcher->registerTimer(interval, timerType, this);
d->ensureExtraData();
d->extraData->runningTimers.append(timerId);
- return timerId;
+ return int(timerId);
}
/*!
@@ -1871,17 +1911,26 @@ int QObject::startTimer(std::chrono::milliseconds interval, Qt::TimerType timerT
void QObject::killTimer(int id)
{
+ killTimer(Qt::TimerId{id});
+}
+
+/*!
+ \since 6.8
+ \overload
+*/
+void QObject::killTimer(Qt::TimerId id)
+{
Q_D(QObject);
if (Q_UNLIKELY(thread() != QThread::currentThread())) {
qWarning("QObject::killTimer: Timers cannot be stopped from another thread");
return;
}
- if (id) {
+ if (id > Qt::TimerId::Invalid) {
int at = d->extraData ? d->extraData->runningTimers.indexOf(id) : -1;
if (at == -1) {
// timer isn't owned by this object
qWarning("QObject::killTimer(): Error: timer id %d is not valid for object %p (%s, %ls), timer has not been killed",
- id,
+ qToUnderlying(id),
this,
metaObject()->className(),
qUtf16Printable(objectName()));
@@ -1897,7 +1946,6 @@ void QObject::killTimer(int id)
}
}
-
/*!
\fn QObject *QObject::parent() const
@@ -1931,18 +1979,19 @@ void QObject::killTimer(int id)
/*!
- \fn template<typename T> T *QObject::findChild(const QString &name, Qt::FindChildOptions options) const
+ \fn template<typename T> T *QObject::findChild(QAnyStringView name, Qt::FindChildOptions options) const
Returns the child of this object that can be cast into type T and
that is called \a name, or \nullptr if there is no such object.
- Omitting the \a name argument causes all object names to be matched.
+ A null \a name argument causes all objects to be matched. An empty,
+ non-null \a name matches only objects whose \l objectName is empty.
The search is performed recursively, unless \a options specifies the
option FindDirectChildrenOnly.
- If there is more than one child matching the search, the most
- direct ancestor is returned. If there are several direct
- ancestors, it is undefined which one will be returned. In that
- case, findChildren() should be used.
+ If there is more than one child matching the search, the most-direct
+ ancestor is returned. If there are several most-direct ancestors, the
+ first child in children() will be returned. In that case, it's better
+ to use findChildren() to get the complete list of all children.
This example returns a child \c{QPushButton} of \c{parentWidget}
named \c{"button1"}, even if the button isn't a direct child of
@@ -1964,11 +2013,32 @@ void QObject::killTimer(int id)
\snippet code/src_corelib_kernel_qobject.cpp 42
+ \note In Qt versions prior to 6.7, this function took \a name as
+ \c{QString}, not \c{QAnyStringView}.
+
\sa findChildren()
*/
/*!
- \fn template<typename T> QList<T> QObject::findChildren(const QString &name, Qt::FindChildOptions options) const
+ \fn template<typename T> T *QObject::findChild(Qt::FindChildOptions options) const
+ \overload
+ \since 6.7
+
+ Returns the child of this object that can be cast into type T, or
+ \nullptr if there is no such object.
+ The search is performed recursively, unless \a options specifies the
+ option FindDirectChildrenOnly.
+
+ If there is more than one child matching the search, the most-direct ancestor
+ is returned. If there are several most-direct ancestors, the first child in
+ children() will be returned. In that case, it's better to use findChildren()
+ to get the complete list of all children.
+
+ \sa findChildren()
+*/
+
+/*!
+ \fn template<typename T> QList<T> QObject::findChildren(QAnyStringView name, Qt::FindChildOptions options) const
Returns all children of this object with the given \a name that can be
cast to type T, or an empty list if there are no such objects.
@@ -1990,6 +2060,9 @@ void QObject::killTimer(int id)
\snippet code/src_corelib_kernel_qobject.cpp 43
+ \note In Qt versions prior to 6.7, this function took \a name as
+ \c{QString}, not \c{QAnyStringView}.
+
\sa findChild()
*/
@@ -2007,7 +2080,7 @@ void QObject::killTimer(int id)
*/
/*!
- \fn QList<T> QObject::findChildren(const QRegularExpression &re, Qt::FindChildOptions options) const
+ \fn template<typename T> QList<T> QObject::findChildren(const QRegularExpression &re, Qt::FindChildOptions options) const
\overload findChildren()
\since 5.0
@@ -2051,46 +2124,26 @@ void QObject::killTimer(int id)
\sa QObject::findChildren()
*/
-static void qt_qFindChildren_with_name(const QObject *parent, const QString &name,
- const QMetaObject &mo, QList<void *> *list,
- Qt::FindChildOptions options)
+static bool matches_objectName_non_null(QObject *obj, QAnyStringView name)
{
- Q_ASSERT(parent);
- Q_ASSERT(list);
- Q_ASSERT(!name.isNull());
- for (QObject *obj : parent->children()) {
- if (mo.cast(obj) && obj->objectName() == name)
- list->append(obj);
- if (options & Qt::FindChildrenRecursively)
- qt_qFindChildren_with_name(obj, name, mo, list, options);
- }
+ if (auto ext = QObjectPrivate::get(obj)->extraData)
+ return ext ->objectName.valueBypassingBindings() == name;
+ return name.isEmpty();
}
/*!
\internal
*/
-void qt_qFindChildren_helper(const QObject *parent, const QString &name,
+void qt_qFindChildren_helper(const QObject *parent, QAnyStringView name,
const QMetaObject &mo, QList<void*> *list, Qt::FindChildOptions options)
{
- if (name.isNull())
- return qt_qFindChildren_helper(parent, mo, list, options);
- else
- return qt_qFindChildren_with_name(parent, name, mo, list, options);
-}
-
-/*!
- \internal
-*/
-void qt_qFindChildren_helper(const QObject *parent, const QMetaObject &mo,
- QList<void*> *list, Qt::FindChildOptions options)
-{
Q_ASSERT(parent);
Q_ASSERT(list);
for (QObject *obj : parent->children()) {
- if (mo.cast(obj))
+ if (mo.cast(obj) && (name.isNull() || matches_objectName_non_null(obj, name)))
list->append(obj);
if (options & Qt::FindChildrenRecursively)
- qt_qFindChildren_helper(obj, mo, list, options);
+ qt_qFindChildren_helper(obj, name, mo, list, options);
}
}
@@ -2117,13 +2170,13 @@ void qt_qFindChildren_helper(const QObject *parent, const QRegularExpression &re
/*!
\internal
- */
-QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options)
+*/
+QObject *qt_qFindChild_helper(const QObject *parent, QAnyStringView name, const QMetaObject &mo, Qt::FindChildOptions options)
{
Q_ASSERT(parent);
for (QObject *obj : parent->children()) {
- if (mo.cast(obj) && (name.isNull() || obj->objectName() == name))
- return obj;
+ if (mo.cast(obj) && (name.isNull() || matches_objectName_non_null(obj, name)))
+ return obj;
}
if (options & Qt::FindChildrenRecursively) {
for (QObject *child : parent->children()) {
@@ -2206,7 +2259,15 @@ void QObjectPrivate::setParent_helper(QObject *o)
}
}
}
+
+ if (receiveParentEvents) {
+ Q_ASSERT(!isWidget); // Handled in QWidget
+ QEvent e(QEvent::ParentAboutToChange);
+ QCoreApplication::sendEvent(q, &e);
+ }
+
parent = o;
+
if (parent) {
// object hierarchies are constrained to a single thread
if (threadData.loadRelaxed() != parent->d_func()->threadData.loadRelaxed()) {
@@ -2222,6 +2283,12 @@ void QObjectPrivate::setParent_helper(QObject *o)
}
}
}
+
+ if (receiveParentEvents) {
+ Q_ASSERT(!isWidget); // Handled in QWidget
+ QEvent e(QEvent::ParentChange);
+ QCoreApplication::sendEvent(q, &e);
+ }
}
/*!
@@ -2240,6 +2307,9 @@ void QObjectPrivate::setParent_helper(QObject *o)
If multiple event filters are installed on a single object, the
filter that was installed last is activated first.
+ If \a filterObj has already been installed for this object,
+ this function moves it so it acts as if it was installed last.
+
Here's a \c KeyPressEater class that eats the key presses of its
monitored objects:
@@ -2278,9 +2348,9 @@ void QObject::installEventFilter(QObject *obj)
d->ensureExtraData();
- // clean up unused items in the list
- d->extraData->eventFilters.removeAll((QObject *)nullptr);
- d->extraData->eventFilters.removeAll(obj);
+ // clean up unused items in the list along the way:
+ auto isNullOrEquals = [](auto obj) { return [obj](const auto &p) { return !p || p == obj; }; };
+ d->extraData->eventFilters.removeIf(isNullOrEquals(obj));
d->extraData->eventFilters.prepend(obj);
}
@@ -2301,9 +2371,11 @@ void QObject::removeEventFilter(QObject *obj)
{
Q_D(QObject);
if (d->extraData) {
- for (int i = 0; i < d->extraData->eventFilters.size(); ++i) {
- if (d->extraData->eventFilters.at(i) == obj)
- d->extraData->eventFilters[i] = nullptr;
+ for (auto &filter : d->extraData->eventFilters) {
+ if (filter == obj) {
+ filter = nullptr;
+ break;
+ }
}
}
}
@@ -2332,7 +2404,7 @@ void QObject::removeEventFilter(QObject *obj)
QCoreApplication::exec()), the object will be deleted once the
event loop is started. If deleteLater() is called after the main event loop
has stopped, the object will not be deleted.
- Since Qt 4.8, if deleteLater() is called on an object that lives in a
+ If deleteLater() is called on an object that lives in a
thread with no running event loop, the object will be destroyed when the
thread finishes.
@@ -2343,9 +2415,20 @@ void QObject::removeEventFilter(QObject *obj)
event loop was still running: the Qt event loop will delete those objects
as soon as the new nested event loop starts.
- \note It is safe to call this function more than once; when the
- first deferred deletion event is delivered, any pending events for the
- object are removed from the event queue.
+ In situations where Qt is not driving the event dispatcher via e.g.
+ QCoreApplication::exec() or QEventLoop::exec(), deferred deletes
+ will not be processed automatically. To ensure deferred deletion in
+ this scenario, the following workaround can be used:
+
+ \code
+ const auto *eventDispatcher = QThread::currentThread()->eventDispatcher();
+ QObject::connect(eventDispatcher, &QAbstractEventDispatcher::aboutToBlock,
+ QThread::currentThread(), []{
+ if (QThread::currentThread()->loopLevel() == 0)
+ QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
+ }
+ );
+ \endcode
\sa destroyed(), QPointer
*/
@@ -2355,7 +2438,62 @@ void QObject::deleteLater()
if (qApp == this)
qWarning("You are deferring the delete of QCoreApplication, this may not work as expected.");
#endif
- QCoreApplication::postEvent(this, new QDeferredDeleteEvent());
+
+
+ // De-bounce QDeferredDeleteEvents. Use the post event list mutex
+ // to guard access to deleteLaterCalled, so we don't need a separate
+ // mutex in QObjectData.
+ auto eventListLocker = QCoreApplicationPrivate::lockThreadPostEventList(this);
+ if (!eventListLocker.threadData)
+ return;
+
+ // FIXME: The deleteLaterCalled flag is part of a bit field,
+ // so we likely have data races here, even with the mutex above,
+ // as long as we're not guarding every access to the bit field.
+
+ Q_D(QObject);
+ if (d->deleteLaterCalled) {
+ qCDebug(lcDeleteLater) << "Skipping deleteLater for already deferred object" << this;
+ return;
+ }
+
+ d->deleteLaterCalled = true;
+
+ int loopLevel = 0;
+ int scopeLevel = 0;
+
+ auto *objectThreadData = eventListLocker.threadData;
+ if (objectThreadData == QThreadData::current()) {
+ // Remember the current running eventloop for deleteLater
+ // calls in the object's own thread.
+
+ // Events sent by non-Qt event handlers (such as glib) may not
+ // have the scopeLevel set correctly. The scope level makes sure that
+ // code like this:
+ // foo->deleteLater();
+ // qApp->processEvents(); // without passing QEvent::DeferredDelete
+ // will not cause "foo" to be deleted before returning to the event loop.
+
+ loopLevel = objectThreadData->loopLevel;
+ scopeLevel = objectThreadData->scopeLevel;
+
+ // If the scope level is 0 while loopLevel != 0, we are called from a
+ // non-conformant code path, and our best guess is that the scope level
+ // should be 1. (Loop level 0 is special: it means that no event loops
+ // are running.)
+ if (scopeLevel == 0 && loopLevel != 0) {
+ qCDebug(lcDeleteLater) << "Delete later called with scope level 0"
+ << "but loop level is > 0. Assuming scope is 1";
+ scopeLevel = 1;
+ }
+ }
+
+ qCDebug(lcDeleteLater) << "Posting deferred delete for" << this
+ << "with loop level" << loopLevel << "and scope level" << scopeLevel;
+
+ eventListLocker.unlock();
+ QCoreApplication::postEvent(this,
+ new QDeferredDeleteEvent(loopLevel, scopeLevel));
}
/*!
@@ -2373,8 +2511,7 @@ void QObject::deleteLater()
If the same \a sourceText is used in different roles within the
same context, an additional identifying string may be passed in
- \a disambiguation (\nullptr by default). In Qt 4.4 and earlier, this was
- the preferred way to pass comments to translators.
+ \a disambiguation (\nullptr by default).
Example:
@@ -2522,7 +2659,7 @@ QObject *QObject::sender() const
{
Q_D(const QObject);
- QBasicMutexLocker locker(signalSlotLock(this));
+ QMutexLocker locker(signalSlotLock(this));
QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
if (!cd || !cd->currentSender)
return nullptr;
@@ -2564,7 +2701,7 @@ int QObject::senderSignalIndex() const
{
Q_D(const QObject);
- QBasicMutexLocker locker(signalSlotLock(this));
+ QMutexLocker locker(signalSlotLock(this));
QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
if (!cd || !cd->currentSender)
return -1;
@@ -2628,8 +2765,8 @@ int QObject::receivers(const char *signal) const
signal_index);
}
+ QMutexLocker locker(signalSlotLock(this));
QObjectPrivate::ConnectionData *cd = d->connections.loadRelaxed();
- QBasicMutexLocker locker(signalSlotLock(this));
if (cd && signal_index < cd->signalVectorCount()) {
const QObjectPrivate::Connection *c = cd->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
while (c) {
@@ -2676,7 +2813,7 @@ bool QObject::isSignalConnected(const QMetaMethod &signal) const
signalIndex += QMetaObjectPrivate::signalOffset(signal.mobj);
- QBasicMutexLocker locker(signalSlotLock(this));
+ QMutexLocker locker(signalSlotLock(this));
return d->isSignalConnected(signalIndex, true);
}
@@ -3582,7 +3719,7 @@ bool QMetaObjectPrivate::disconnect(const QObject *sender,
QObject *s = const_cast<QObject *>(sender);
QBasicMutex *senderMutex = signalSlotLock(sender);
- QBasicMutexLocker locker(senderMutex);
+ QMutexLocker locker(senderMutex);
QObjectPrivate::ConnectionData *scd = QObjectPrivate::get(s)->connections.loadRelaxed();
if (!scd)
@@ -3763,7 +3900,7 @@ struct SlotObjectGuard {
SlotObjectGuard() = default;
// move would be fine, but we do not need it currently
Q_DISABLE_COPY_MOVE(SlotObjectGuard)
- explicit SlotObjectGuard(QtPrivate::QSlotObjectBase *slotObject)
+ Q_NODISCARD_CTOR explicit SlotObjectGuard(QtPrivate::QSlotObjectBase *slotObject)
: m_slotObject(slotObject)
{
if (m_slotObject)
@@ -3771,17 +3908,14 @@ struct SlotObjectGuard {
}
QtPrivate::QSlotObjectBase const *operator->() const
- { return m_slotObject; }
+ { return m_slotObject.get(); }
QtPrivate::QSlotObjectBase *operator->()
- { return m_slotObject; }
+ { return m_slotObject.get(); }
- ~SlotObjectGuard() {
- if (m_slotObject)
- m_slotObject->destroyIfLastRef();
- }
+ ~SlotObjectGuard() = default;
private:
- QtPrivate::QSlotObjectBase *m_slotObject = nullptr;
+ QtPrivate::SlotObjUniquePtr m_slotObject;
};
/*!
@@ -3809,7 +3943,7 @@ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connect
while (argumentTypes[nargs - 1])
++nargs;
- QBasicMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));
+ QMutexLocker locker(signalSlotLock(c->receiver.loadRelaxed()));
QObject *receiver = c->receiver.loadRelaxed();
if (!receiver) {
// the connection has been disconnected before we got the lock
@@ -3890,8 +4024,8 @@ void doActivate(QObject *sender, int signal_index, void **argv)
bool senderDeleted = false;
{
- Q_ASSERT(sp->connections.loadAcquire());
- QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadRelaxed());
+ Q_ASSERT(sp->connections.loadRelaxed());
+ QObjectPrivate::ConnectionDataPointer connections(sp->connections.loadAcquire());
QObjectPrivate::SignalVector *signalVector = connections->signalVector.loadRelaxed();
const QObjectPrivate::ConnectionList *list;
@@ -3950,7 +4084,7 @@ void doActivate(QObject *sender, int signal_index, void **argv)
QSemaphore semaphore;
{
- QBasicMutexLocker locker(signalSlotLock(receiver));
+ QMutexLocker locker(signalSlotLock(receiver));
if (!c->isSingleShot && !c->receiver.loadAcquire())
continue;
QMetaCallEvent *ev = c->isSlotObject ?
@@ -3967,7 +4101,9 @@ void doActivate(QObject *sender, int signal_index, void **argv)
if (c->isSingleShot && !QObjectPrivate::removeConnection(c))
continue;
- QObjectPrivate::Sender senderData(receiverInSameThread ? receiver : nullptr, sender, signal_index);
+ QObjectPrivate::Sender senderData(
+ receiverInSameThread ? receiver : nullptr, sender, signal_index,
+ receiverInSameThread ? QObjectPrivate::get(receiver)->connections.loadAcquire() : nullptr);
if (c->isSlotObject) {
SlotObjectGuard obj{c->slotObj};
@@ -4016,7 +4152,7 @@ void doActivate(QObject *sender, int signal_index, void **argv)
senderDeleted = true;
}
if (!senderDeleted) {
- sp->connections.loadRelaxed()->cleanOrphanedConnections(sender);
+ sp->connections.loadAcquire()->cleanOrphanedConnections(sender);
if (callbacks_enabled && signal_spy_set->signal_end_callback != nullptr)
signal_spy_set->signal_end_callback(sender, signal_index);
@@ -4094,6 +4230,8 @@ int QObjectPrivate::signalIndex(const char *signalName,
*****************************************************************************/
/*!
+ \fn bool QObject::setProperty(const char *name, const QVariant &value)
+
Sets the value of the object's \a name property to \a value.
If the property is defined in the class using Q_PROPERTY then
@@ -4114,9 +4252,17 @@ int QObjectPrivate::signalIndex(const char *signalName,
\sa property(), metaObject(), dynamicPropertyNames(), QMetaProperty::write()
*/
-bool QObject::setProperty(const char *name, const QVariant &value)
+
+/*!
+ \fn bool QObject::setProperty(const char *name, QVariant &&value)
+ \since 6.6
+ \overload setProperty
+*/
+
+bool QObject::doSetProperty(const char *name, const QVariant *lvalue, QVariant *rvalue)
{
Q_D(QObject);
+ const auto &value =*lvalue;
const QMetaObject *meta = metaObject();
if (!name || !meta)
return false;
@@ -4135,12 +4281,18 @@ bool QObject::setProperty(const char *name, const QVariant &value)
} else {
if (idx == -1) {
d->extraData->propertyNames.append(name);
- d->extraData->propertyValues.append(value);
+ if (rvalue)
+ d->extraData->propertyValues.append(std::move(*rvalue));
+ else
+ d->extraData->propertyValues.append(*lvalue);
} else {
if (value.userType() == d->extraData->propertyValues.at(idx).userType()
&& value == d->extraData->propertyValues.at(idx))
return false;
- d->extraData->propertyValues[idx] = value;
+ if (rvalue)
+ d->extraData->propertyValues[idx] = std::move(*rvalue);
+ else
+ d->extraData->propertyValues[idx] = *lvalue;
}
}
@@ -4155,7 +4307,7 @@ bool QObject::setProperty(const char *name, const QVariant &value)
qWarning("%s::setProperty: Property \"%s\" invalid,"
" read-only or does not exist", metaObject()->className(), name);
#endif
- return p.write(this, value);
+ return rvalue ? p.write(this, std::move(*rvalue)) : p.write(this, *lvalue);
}
/*!
@@ -4255,7 +4407,7 @@ void QObject::dumpObjectInfo() const
objectName().isEmpty() ? "unnamed" : objectName().toLocal8Bit().data());
Q_D(const QObject);
- QBasicMutexLocker locker(signalSlotLock(this));
+ QMutexLocker locker(signalSlotLock(this));
// first, look for connections where this object is the sender
qDebug(" SIGNALS OUT");
@@ -4317,15 +4469,23 @@ void QObject::dumpObjectInfo() const
#ifndef QT_NO_DEBUG_STREAM
+void QObjectPrivate::writeToDebugStream(QDebug &dbg) const
+{
+ Q_Q(const QObject);
+ dbg.nospace() << q->metaObject()->className() << '(' << (const void *)q;
+ if (!q->objectName().isEmpty())
+ dbg << ", name = " << q->objectName();
+ dbg << ')';
+}
+
QDebug operator<<(QDebug dbg, const QObject *o)
{
QDebugStateSaver saver(dbg);
if (!o)
return dbg << "QObject(0x0)";
- dbg.nospace() << o->metaObject()->className() << '(' << (const void *)o;
- if (!o->objectName().isEmpty())
- dbg << ", name = " << o->objectName();
- dbg << ')';
+
+ const QObjectPrivate *d = QObjectPrivate::get(o);
+ d->writeToDebugStream(dbg);
return dbg;
}
#endif
@@ -4335,19 +4495,22 @@ QDebug operator<<(QDebug dbg, const QObject *o)
\relates QObject
This macro associates extra information to the class, which is available
- using QObject::metaObject(). Qt makes only limited use of this feature in
- \l{Qt D-Bus} and \l{Qt QML} modules.
-
- The extra information takes the form of a \a Name string and a \a Value
- literal string.
+ using QObject::metaObject(). The extra information takes the form of a
+ \a Name string and a \a Value literal string.
Example:
\snippet code/src_corelib_kernel_qobject.cpp 35
+ Qt makes use of the macro in \l{Qt D-Bus} and \l{Qt Qml} modules.
+ For instance, when defining \l{QML Object Types} in C++, you can
+ designate a property as the \e default one:
+
+ \snippet code/doc_src_properties.cpp 7
+
\sa QMetaObject::classInfo()
\sa {Using Qt D-Bus Adaptors}
- \sa {Extending QML}
+ \sa {Defining QML Types from C++}
*/
/*!
@@ -4357,15 +4520,6 @@ QDebug operator<<(QDebug dbg, const QObject *o)
This macro tells Qt which interfaces the class implements. This
is used when implementing plugins.
- Example:
-
- \snippet ../widgets/tools/plugandpaint/plugins/basictools/basictoolsplugin.h 1
- \dots
- \snippet ../widgets/tools/plugandpaint/plugins/basictools/basictoolsplugin.h 3
-
- See the \l{tools/plugandpaint/plugins/basictools}{Plug & Paint
- Basic Tools} example for details.
-
\sa Q_DECLARE_INTERFACE(), Q_PLUGIN_METADATA(), {How to Create Qt Plugins}
*/
@@ -4564,6 +4718,13 @@ QDebug operator<<(QDebug dbg, const QObject *o)
Q_GADGET or Q_GADGET_EXPORT instead of Q_OBJECT to enable the meta object system's support
for enums in a class that is not a QObject subclass.
+//! [qobject-macros-private-access-specifier]
+ \note This macro expansion ends with a \c private: access specifier, which makes member
+ declarations immediately after the macro private, too. If you want add public (or protected)
+ members immediately after the macro, you need to use a \c public: (or \c protected:)
+ access specifier.
+//! [qobject-macros-private-access-specifier]
+
\sa {Meta-Object System}, {Signals and Slots}, {Qt's Property System}
*/
@@ -4581,7 +4742,9 @@ QDebug operator<<(QDebug dbg, const QObject *o)
Q_GADGET makes a class member, \c{staticMetaObject}, available.
\c{staticMetaObject} is of type QMetaObject and provides access to the
- enums declared with Q_ENUMS.
+ enums declared with Q_ENUM.
+
+ \include qobject.cpp qobject-macros-private-access-specifier
\sa Q_GADGET_EXPORT
*/
@@ -4608,6 +4771,8 @@ QDebug operator<<(QDebug dbg, const QObject *o)
~~~
\endcode
+ \include qobject.cpp qobject-macros-private-access-specifier
+
\sa Q_GADGET, {Creating Shared Libraries}
*/
@@ -4838,17 +5003,34 @@ QDebug operator<<(QDebug dbg, const QObject *o)
*/
/*!
+ \macro QT_NO_CONTEXTLESS_CONNECT
+ \relates QObject
+ \since 6.7
+
+ Defining this macro will disable the overload of QObject::connect() that
+ connects a signal to a functor, without also specifying a QObject
+ as a receiver/context object (that is, the 3-arguments overload
+ of QObject::connect()).
+
+ Using the context-less overload is error prone, because it is easy
+ to connect to functors that depend on some local state of the
+ receiving end. If such local state gets destroyed, the connection
+ does not get automatically disconnected.
+
+ Moreover, such connections are always direct connections, which may
+ cause issues in multithreaded scenarios (for instance, if the
+ signal is emitted from another thread).
+
+ \sa QObject::connect, Qt::ConnectionType
+*/
+
+/*!
\typedef QObjectList
\relates QObject
Synonym for QList<QObject *>.
*/
-void qDeleteInEventHandler(QObject *o)
-{
- delete o;
-}
-
/*!
\fn template<typename PointerToMemberFunction> QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type)
\overload connect()
@@ -4942,6 +5124,11 @@ void qDeleteInEventHandler(QObject *o)
However, you should take care that any objects used within the functor
are still alive when the signal is emitted.
+ For this reason, it is recommended to use the overload of connect()
+ that also takes a QObject as a receiver/context. It is possible
+ to disable the usage of the context-less overload by defining the
+ \c{QT_NO_CONTEXTLESS_CONNECT} macro.
+
Overloaded functions can be resolved with help of \l qOverload.
*/
@@ -5007,13 +5194,12 @@ void qDeleteInEventHandler(QObject *o)
*/
QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal,
const QObject *receiver, void **slot,
- QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
+ QtPrivate::QSlotObjectBase *slotObjRaw, Qt::ConnectionType type,
const int *types, const QMetaObject *senderMetaObject)
{
+ QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
if (!signal) {
qCWarning(lcConnect, "QObject::connect: invalid nullptr parameter");
- if (slotObj)
- slotObj->destroyIfLastRef();
return QMetaObject::Connection();
}
@@ -5026,11 +5212,10 @@ QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signa
}
if (!senderMetaObject) {
qCWarning(lcConnect, "QObject::connect: signal not found in %s", sender->metaObject()->className());
- slotObj->destroyIfLastRef();
return QMetaObject::Connection(nullptr);
}
signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
- return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj, type, types, senderMetaObject);
+ return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj.release(), type, types, senderMetaObject);
}
static void connectWarning(const QObject *sender,
@@ -5055,14 +5240,10 @@ static void connectWarning(const QObject *sender,
*/
QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int signal_index,
const QObject *receiver, void **slot,
- QtPrivate::QSlotObjectBase *slotObj, int type,
+ QtPrivate::QSlotObjectBase *slotObjRaw, int type,
const int *types, const QMetaObject *senderMetaObject)
{
- auto connectFailureGuard = qScopeGuard([&]()
- {
- if (slotObj)
- slotObj->destroyIfLastRef();
- });
+ QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
if (!sender || !receiver || !slotObj || !senderMetaObject) {
connectWarning(sender, senderMetaObject, receiver, "invalid nullptr parameter");
@@ -5074,24 +5255,20 @@ QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int s
return QMetaObject::Connection();
}
- connectFailureGuard.dismiss();
-
QObject *s = const_cast<QObject *>(sender);
QObject *r = const_cast<QObject *>(receiver);
QOrderedMutexLocker locker(signalSlotLock(sender),
signalSlotLock(receiver));
- if (type & Qt::UniqueConnection && slot && QObjectPrivate::get(s)->connections.loadRelaxed()) {
+ if (type & Qt::UniqueConnection && slot) {
QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed();
- if (connections->signalVectorCount() > signal_index) {
+ if (connections && connections->signalVectorCount() > signal_index) {
const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
while (c2) {
- if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot)) {
- slotObj->destroyIfLastRef();
+ if (c2->receiver.loadRelaxed() == receiver && c2->isSlotObject && c2->slotObj->compare(slot))
return QMetaObject::Connection();
- }
c2 = c2->nextConnectionList.loadRelaxed();
}
}
@@ -5111,9 +5288,9 @@ QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int s
td->ref();
c->receiverThreadData.storeRelaxed(td);
c->receiver.storeRelaxed(r);
- c->slotObj = slotObj;
c->connectionType = type;
c->isSlotObject = true;
+ c->slotObj = slotObj.release();
if (types) {
c->argumentTypes.storeRelaxed(types);
c->ownArgumentTypes = false;
@@ -5262,20 +5439,19 @@ QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signa
*/
QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signal_index,
const QObject *receiver,
- QtPrivate::QSlotObjectBase *slotObj,
+ QtPrivate::QSlotObjectBase *slotObjRaw,
Qt::ConnectionType type)
{
+ QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
if (!sender) {
qCWarning(lcConnect, "QObject::connect: invalid nullptr parameter");
- if (slotObj)
- slotObj->destroyIfLastRef();
return QMetaObject::Connection();
}
const QMetaObject *senderMetaObject = sender->metaObject();
signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index);
- return QObjectPrivate::connectImpl(sender, signal_index, receiver, /*slot*/ nullptr, slotObj,
- type, /*types*/ nullptr, senderMetaObject);
+ return connectImpl(sender, signal_index, receiver, /*slot*/ nullptr, slotObj.release(),
+ type, /*types*/ nullptr, senderMetaObject);
}
/*!
@@ -5364,11 +5540,13 @@ inline bool QObjectPrivate::removeConnection(QObjectPrivate::Connection *c)
QtPrivate::QPropertyAdaptorSlotObject *
QObjectPrivate::getPropertyAdaptorSlotObject(const QMetaProperty &property)
{
- if (auto conns = connections.loadRelaxed()) {
+ if (auto conns = connections.loadAcquire()) {
Q_Q(QObject);
const QMetaObject *metaObject = q->metaObject();
int signal_index = methodIndexToSignalIndex(&metaObject, property.notifySignalIndex());
- auto connectionList = conns->connectionsForSignal(signal_index);
+ if (signal_index >= conns->signalVectorCount())
+ return nullptr;
+ const auto &connectionList = conns->connectionsForSignal(signal_index);
for (auto c = connectionList.first.loadRelaxed(); c;
c = c->nextConnectionList.loadRelaxed()) {
if (c->isSlotObject) {
diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h
index 7f3720df1f..06cfefd61b 100644
--- a/src/corelib/kernel/qobject.h
+++ b/src/corelib/kernel/qobject.h
@@ -19,6 +19,7 @@
#include <QtCore/qobject_impl.h>
#include <QtCore/qbindingstorage.h>
+#include <QtCore/qtcoreexports.h>
#include <chrono>
@@ -43,13 +44,24 @@ struct QDynamicMetaObjectData;
typedef QList<QObject*> QObjectList;
+#if QT_CORE_REMOVED_SINCE(6, 7)
Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QString &name,
const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);
+#endif
+Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, QAnyStringView name,
+ const QMetaObject &mo, QList<void *> *list,
+ Qt::FindChildOptions options);
+#if QT_CORE_REMOVED_SINCE(6, 7)
Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QMetaObject &mo,
QList<void *> *list, Qt::FindChildOptions options);
+#endif
Q_CORE_EXPORT void qt_qFindChildren_helper(const QObject *parent, const QRegularExpression &re,
const QMetaObject &mo, QList<void *> *list, Qt::FindChildOptions options);
+#if QT_CORE_REMOVED_SINCE(6, 7)
Q_CORE_EXPORT QObject *qt_qFindChild_helper(const QObject *parent, const QString &name, const QMetaObject &mo, Qt::FindChildOptions options);
+#endif
+Q_CORE_EXPORT QObject *qt_qFindChild_helper(const QObject *parent, QAnyStringView name,
+ const QMetaObject &mo, Qt::FindChildOptions options);
class Q_CORE_EXPORT QObjectData
{
@@ -72,7 +84,8 @@ public:
uint isQuickItem : 1;
uint willBeWidget : 1; // for handling widget-specific bits in QObject's ctor
uint wasWidget : 1; // for properly cleaning up in QObject's dtor
- uint unused : 21;
+ uint receiveParentEvents: 1;
+ uint unused : 20;
QAtomicInt postedEvents;
QDynamicMetaObjectData *metaObject;
QBindingStorage bindingStorage;
@@ -123,23 +136,36 @@ public:
bool blockSignals(bool b) noexcept;
QThread *thread() const;
+#if QT_CORE_REMOVED_SINCE(6, 7)
void moveToThread(QThread *thread);
+#endif
+ bool moveToThread(QThread *thread QT6_DECL_NEW_OVERLOAD_TAIL);
int startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer);
+
+#if QT_CORE_REMOVED_SINCE(6, 8)
int startTimer(std::chrono::milliseconds time, Qt::TimerType timerType = Qt::CoarseTimer);
+#endif
+ int startTimer(std::chrono::nanoseconds time, Qt::TimerType timerType = Qt::CoarseTimer);
+
void killTimer(int id);
+ void killTimer(Qt::TimerId id);
template<typename T>
- inline T findChild(const QString &aName = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
+ T findChild(QAnyStringView aName, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
{
typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
+ static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,
+ "No Q_OBJECT in the class passed to QObject::findChild");
return static_cast<T>(qt_qFindChild_helper(this, aName, ObjType::staticMetaObject, options));
}
template<typename T>
- inline QList<T> findChildren(const QString &aName, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
+ QList<T> findChildren(QAnyStringView aName, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
{
typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
+ static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,
+ "No Q_OBJECT in the class passed to QObject::findChildren");
QList<T> list;
qt_qFindChildren_helper(this, aName, ObjType::staticMetaObject,
reinterpret_cast<QList<void *> *>(&list), options);
@@ -147,13 +173,15 @@ public:
}
template<typename T>
+ T findChild(Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
+ {
+ return findChild<T>({}, options);
+ }
+
+ template<typename T>
QList<T> findChildren(Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
{
- typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
- QList<T> list;
- qt_qFindChildren_helper(this, ObjType::staticMetaObject,
- reinterpret_cast<QList<void *> *>(&list), options);
- return list;
+ return findChildren<T>(QAnyStringView{}, options);
}
#if QT_CONFIG(regularexpression)
@@ -161,6 +189,8 @@ public:
inline QList<T> findChildren(const QRegularExpression &re, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
{
typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
+ static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,
+ "No Q_OBJECT in the class passed to QObject::findChildren");
QList<T> list;
qt_qFindChildren_helper(this, re, ObjType::staticMetaObject,
reinterpret_cast<QList<void *> *>(&list), options);
@@ -192,54 +222,28 @@ public:
template<typename PointerToMemberFunction, typename Functor>
static QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection);
#else
- //Connect a signal to a pointer to qobject member function
+ //connect with context
template <typename Func1, typename Func2>
- static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
- const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot,
- Qt::ConnectionType type = Qt::AutoConnection)
+ static inline QMetaObject::Connection
+ connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
+ const typename QtPrivate::ContextTypeForFunctor<Func2>::ContextType *context, Func2 &&slot,
+ Qt::ConnectionType type = Qt::AutoConnection)
{
typedef QtPrivate::FunctionPointer<Func1> SignalType;
- typedef QtPrivate::FunctionPointer<Func2> SlotType;
+ typedef QtPrivate::FunctionPointer<std::decay_t<Func2>> SlotType;
- static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
- "No Q_OBJECT in the class with the signal");
-
- //compilation error if the arguments does not match.
- static_assert(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
- "The slot requires more arguments than the signal provides.");
- static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
- "Signal and slot arguments are not compatible.");
- static_assert((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
- "Return type of the slot is not compatible with the return type of the signal.");
-
- const int *types = nullptr;
- if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
- types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
-
- return connectImpl(sender, reinterpret_cast<void **>(&signal),
- receiver, reinterpret_cast<void **>(&slot),
- new QtPrivate::QSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
- typename SignalType::ReturnType>(slot),
- type, types, &SignalType::Object::staticMetaObject);
- }
-
- //connect to a function pointer (not a member)
- template <typename Func1, typename Func2>
- 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);
- }
+ if constexpr (SlotType::ArgumentCount != -1) {
+ static_assert((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
+ "Return type of the slot is not compatible with the return type of the signal.");
+ } else {
+ constexpr int FunctorArgumentCount = QtPrivate::ComputeFunctorArgumentCount<std::decay_t<Func2>, typename SignalType::Arguments>::Value;
+ [[maybe_unused]]
+ constexpr int SlotArgumentCount = (FunctorArgumentCount >= 0) ? FunctorArgumentCount : 0;
+ typedef typename QtPrivate::FunctorReturnType<std::decay_t<Func2>, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value>::Value SlotReturnType;
- //connect to a function pointer (not a member)
- template <typename Func1, typename Func2>
- 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)
- {
- typedef QtPrivate::FunctionPointer<Func1> SignalType;
- typedef QtPrivate::FunctionPointer<Func2> SlotType;
+ static_assert((QtPrivate::AreArgumentsCompatible<SlotReturnType, typename SignalType::ReturnType>::value),
+ "Return type of the slot is not compatible with the return type of the signal.");
+ }
static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
"No Q_OBJECT in the class with the signal");
@@ -247,66 +251,34 @@ public:
//compilation error if the arguments does not match.
static_assert(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
"The slot requires more arguments than the signal provides.");
- static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value),
- "Signal and slot arguments are not compatible.");
- static_assert((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value),
- "Return type of the slot is not compatible with the return type of the signal.");
const int *types = nullptr;
if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
- return connectImpl(sender, reinterpret_cast<void **>(&signal), context, nullptr,
- new QtPrivate::QStaticSlotObject<Func2,
- typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
- typename SignalType::ReturnType>(slot),
+ void **pSlot = nullptr;
+ if constexpr (std::is_member_function_pointer_v<std::decay_t<Func2>>) {
+ pSlot = const_cast<void **>(reinterpret_cast<void *const *>(&slot));
+ } else {
+ Q_ASSERT_X((type & Qt::UniqueConnection) == 0, "",
+ "QObject::connect: Unique connection requires the slot to be a pointer to "
+ "a member function of a QObject subclass.");
+ }
+
+ return connectImpl(sender, reinterpret_cast<void **>(&signal), context, pSlot,
+ QtPrivate::makeCallableObject<Func1>(std::forward<Func2>(slot)),
type, types, &SignalType::Object::staticMetaObject);
}
- //connect to a functor
+#ifndef QT_NO_CONTEXTLESS_CONNECT
+ //connect without context
template <typename Func1, typename Func2>
- static inline typename std::enable_if<
- QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1 &&
- !std::is_convertible_v<Func2, const char*>, // don't match old-style connect
- QMetaObject::Connection>::type
- connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot)
+ static inline QMetaObject::Connection
+ connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 &&slot)
{
- return connect(sender, signal, sender, std::move(slot), Qt::DirectConnection);
- }
-
- //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 std::enable_if<
- QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1 &&
- !std::is_convertible_v<Func2, const char*>, // don't match old-style connect
- QMetaObject::Connection>::type
- connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot,
- Qt::ConnectionType type = Qt::AutoConnection)
- {
- typedef QtPrivate::FunctionPointer<Func1> SignalType;
- const int FunctorArgumentCount = QtPrivate::ComputeFunctorArgumentCount<Func2 , typename SignalType::Arguments>::Value;
-
- static_assert((FunctorArgumentCount >= 0),
- "Signal and slot arguments are not compatible.");
- const int SlotArgumentCount = (FunctorArgumentCount >= 0) ? FunctorArgumentCount : 0;
- typedef typename QtPrivate::FunctorReturnType<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value>::Value SlotReturnType;
-
- static_assert((QtPrivate::AreArgumentsCompatible<SlotReturnType, typename SignalType::ReturnType>::value),
- "Return type of the slot is not compatible with the return type of the signal.");
-
- static_assert(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
- "No Q_OBJECT in the class with the signal");
-
- const int *types = nullptr;
- if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection)
- types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types();
-
- return connectImpl(sender, reinterpret_cast<void **>(&signal), context, nullptr,
- new QtPrivate::QFunctorSlotObject<Func2, SlotArgumentCount,
- typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value,
- typename SignalType::ReturnType>(std::move(slot)),
- type, types, &SignalType::Object::staticMetaObject);
+ return connect(sender, signal, sender, std::forward<Func2>(slot), Qt::DirectConnection);
}
+#endif // QT_NO_CONTEXTLESS_CONNECT
#endif //Q_QDOC
static bool disconnect(const QObject *sender, const char *signal,
@@ -358,7 +330,9 @@ public:
void dumpObjectTree() const;
void dumpObjectInfo() const;
+ QT_CORE_INLINE_SINCE(6, 6)
bool setProperty(const char *name, const QVariant &value);
+ inline bool setProperty(const char *name, QVariant &&value);
QVariant property(const char *name) const;
QList<QByteArray> dynamicPropertyNames() const;
QBindingStorage *bindingStorage() { return &d_ptr->bindingStorage; }
@@ -411,8 +385,9 @@ protected:
private:
void doSetObjectName(const QString &name);
+ bool doSetProperty(const char *name, const QVariant *lvalue, QVariant *rvalue);
+
Q_DISABLE_COPY(QObject)
- Q_PRIVATE_SLOT(d_func(), void _q_reregisterTimers(void *))
private:
static QMetaObject::Connection connectImpl(const QObject *sender, void **signal,
@@ -429,9 +404,22 @@ inline QMetaObject::Connection QObject::connect(const QObject *asender, const ch
const char *amember, Qt::ConnectionType atype) const
{ return connect(asender, asignal, this, amember, atype); }
+#if QT_CORE_INLINE_IMPL_SINCE(6, 6)
+bool QObject::setProperty(const char *name, const QVariant &value)
+{
+ return doSetProperty(name, &value, nullptr);
+}
+#endif // inline since 6.6
+bool QObject::setProperty(const char *name, QVariant &&value)
+{
+ return doSetProperty(name, &value, &value);
+}
+
template <class T>
inline T qobject_cast(QObject *object)
{
+ static_assert(std::is_pointer_v<T>,
+ "qobject_cast requires to cast towards a pointer type");
typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,
"qobject_cast requires the type to have a Q_OBJECT macro");
@@ -441,6 +429,10 @@ inline T qobject_cast(QObject *object)
template <class T>
inline T qobject_cast(const QObject *object)
{
+ static_assert(std::is_pointer_v<T>,
+ "qobject_cast requires to cast towards a pointer type");
+ static_assert(std::is_const_v<std::remove_pointer_t<T>>,
+ "qobject_cast cannot cast away constness (use const_cast)");
typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
static_assert(QtPrivate::HasQ_OBJECT_Macro<ObjType>::Value,
"qobject_cast requires the type to have a Q_OBJECT macro");
@@ -490,15 +482,19 @@ Q_CORE_EXPORT QDebug operator<<(QDebug, const QObject *);
class QSignalBlocker
{
public:
+ Q_NODISCARD_CTOR
inline explicit QSignalBlocker(QObject *o) noexcept;
+ Q_NODISCARD_CTOR
inline explicit QSignalBlocker(QObject &o) noexcept;
inline ~QSignalBlocker();
+ Q_NODISCARD_CTOR
inline QSignalBlocker(QSignalBlocker &&other) noexcept;
inline QSignalBlocker &operator=(QSignalBlocker &&other) noexcept;
inline void reblock() noexcept;
inline void unblock() noexcept;
+ inline void dismiss() noexcept;
private:
Q_DISABLE_COPY(QSignalBlocker)
@@ -563,6 +559,11 @@ void QSignalBlocker::unblock() noexcept
m_inhibited = true;
}
+void QSignalBlocker::dismiss() noexcept
+{
+ m_o = nullptr;
+}
+
namespace QtPrivate {
inline QObject & deref_for_methodcall(QObject &o) { return o; }
inline QObject & deref_for_methodcall(QObject *o) { return *o; }
diff --git a/src/corelib/kernel/qobject_impl.h b/src/corelib/kernel/qobject_impl.h
index 4d6830a3cc..b57d7e50cc 100644
--- a/src/corelib/kernel/qobject_impl.h
+++ b/src/corelib/kernel/qobject_impl.h
@@ -37,30 +37,6 @@ namespace QtPrivate {
{ static const int *types() { return nullptr; } };
template <typename... Args> struct ConnectionTypes<List<Args...>, true>
{ static const int *types() { static const int t[sizeof...(Args) + 1] = { (QtPrivate::QMetaTypeIdHelper<Args>::qt_metatype_id())..., 0 }; return t; } };
-
- // implementation of QSlotObjectBase for which the slot is a static function
- // Args and R are the List of arguments and the return type of the signal to which the slot is connected.
- template<typename Func, typename Args, typename R> class QStaticSlotObject : public QSlotObjectBase
- {
- typedef QtPrivate::FunctionPointer<Func> FuncType;
- Func function;
- static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
- {
- switch (which) {
- case Destroy:
- delete static_cast<QStaticSlotObject*>(this_);
- break;
- case Call:
- FuncType::template call<Args, R>(static_cast<QStaticSlotObject*>(this_)->function, r, a);
- break;
- case Compare: // not implemented
- case NumOperations:
- Q_UNUSED(ret);
- }
- }
- public:
- explicit QStaticSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {}
- };
}
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h
index f9bb93f960..0ab9bf02ed 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -18,6 +18,7 @@
#include <QtCore/private/qglobal_p.h>
#include "QtCore/qcoreevent.h"
+#include <QtCore/qfunctionaltools_impl.h>
#include "QtCore/qlist.h"
#include "QtCore/qobject.h"
#include "QtCore/qpointer.h"
@@ -90,7 +91,7 @@ public:
QList<QByteArray> propertyNames;
QList<QVariant> propertyValues;
- QList<int> runningTimers;
+ QList<Qt::TimerId> runningTimers;
QList<QPointer<QObject>> eventFilters;
Q_OBJECT_COMPAT_PROPERTY(QObjectPrivate::ExtraData, QString, objectName,
&QObjectPrivate::ExtraData::setObjectNameForwarder,
@@ -139,11 +140,8 @@ public:
void setParent_helper(QObject *);
void moveToThread_helper();
void setThreadData_helper(QThreadData *currentData, QThreadData *targetData, QBindingStatus *status);
- void _q_reregisterTimers(void *pointer);
- bool isSender(const QObject *receiver, const char *signal) const;
QObjectList receiverList(const char *signal) const;
- QObjectList senderList() const;
inline void ensureConnectionData();
inline void addConnection(int signal, Connection *c);
@@ -188,6 +186,10 @@ public:
virtual std::string flagsForDumping() const;
+#ifndef QT_NO_DEBUG_STREAM
+ virtual void writeToDebugStream(QDebug &) const;
+#endif
+
QtPrivate::QPropertyAdaptorSlotObject *
getPropertyAdaptorSlotObject(const QMetaProperty &property);
@@ -255,28 +257,7 @@ namespace QtPrivate {
inline const QObject *getQObject(const QObjectPrivate *d) { return d->q_func(); }
template <typename Func>
-struct FunctionStorageByValue
-{
- Func f;
- Func &func() noexcept { return f; }
-};
-
-template <typename Func>
-struct FunctionStorageEmptyBaseClassOptimization : Func
-{
- Func &func() noexcept { return *this; }
- using Func::Func;
-};
-
-template <typename Func>
-using FunctionStorage = typename std::conditional_t<
- std::conjunction_v<
- std::is_empty<Func>,
- std::negation<std::is_final<Func>>
- >,
- FunctionStorageEmptyBaseClassOptimization<Func>,
- FunctionStorageByValue<Func>
- >;
+using FunctionStorage = QtPrivate::CompactStorage<Func>;
template <typename ObjPrivate> inline void assertObjectType(QObjectPrivate *d)
{
@@ -288,18 +269,23 @@ template<typename Func, typename Args, typename R>
class QPrivateSlotObject : public QSlotObjectBase, private FunctionStorage<Func>
{
typedef QtPrivate::FunctionPointer<Func> FuncType;
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
+#else
+ static void impl(QSlotObjectBase *this_, QObject *r, void **a, int which, bool *ret)
+#endif
{
+ const auto that = static_cast<QPrivateSlotObject*>(this_);
switch (which) {
case Destroy:
- delete static_cast<QPrivateSlotObject*>(this_);
+ delete that;
break;
case Call:
- FuncType::template call<Args, R>(static_cast<QPrivateSlotObject*>(this_)->func(),
+ FuncType::template call<Args, R>(that->object(),
static_cast<typename FuncType::Object *>(QObjectPrivate::get(r)), a);
break;
case Compare:
- *ret = *reinterpret_cast<Func *>(a) == static_cast<QPrivateSlotObject*>(this_)->func();
+ *ret = *reinterpret_cast<Func *>(a) == that->object();
break;
case NumOperations: ;
}
@@ -390,6 +376,9 @@ public:
QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,
const QObject *sender, int signalId,
void **args, QSemaphore *semaphore);
+ QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj,
+ const QObject *sender, int signalId,
+ void **args, QSemaphore *semaphore);
// queued - args allocated by event, copied by caller
QMetaCallEvent(ushort method_offset, ushort method_relative,
@@ -399,9 +388,31 @@ public:
QMetaCallEvent(QtPrivate::QSlotObjectBase *slotObj,
const QObject *sender, int signalId,
int nargs);
+ QMetaCallEvent(QtPrivate::SlotObjUniquePtr slotObj,
+ const QObject *sender, int signalId,
+ int nargs);
~QMetaCallEvent() override;
+ template<typename ...Args>
+ static QMetaCallEvent *create(QtPrivate::QSlotObjectBase *slotObj, const QObject *sender,
+ int signal_index, const Args &...argv)
+ {
+ const void* const argp[] = { nullptr, std::addressof(argv)... };
+ const QMetaType metaTypes[] = { QMetaType::fromType<void>(), QMetaType::fromType<Args>()... };
+ constexpr auto argc = sizeof...(Args) + 1;
+ return create_impl(slotObj, sender, signal_index, argc, argp, metaTypes);
+ }
+ template<typename ...Args>
+ static QMetaCallEvent *create(QtPrivate::SlotObjUniquePtr slotObj, const QObject *sender,
+ int signal_index, const Args &...argv)
+ {
+ const void* const argp[] = { nullptr, std::addressof(argv)... };
+ const QMetaType metaTypes[] = { QMetaType::fromType<void>(), QMetaType::fromType<Args>()... };
+ constexpr auto argc = sizeof...(Args) + 1;
+ return create_impl(std::move(slotObj), sender, signal_index, argc, argp, metaTypes);
+ }
+
inline int id() const { return d.method_offset_ + d.method_relative_; }
inline const void * const* args() const { return d.args_; }
inline void ** args() { return d.args_; }
@@ -411,10 +422,22 @@ public:
virtual void placeMetaCall(QObject *object) override;
private:
+ static QMetaCallEvent *create_impl(QtPrivate::QSlotObjectBase *slotObj, const QObject *sender,
+ int signal_index, size_t argc, const void * const argp[],
+ const QMetaType metaTypes[])
+ {
+ if (slotObj)
+ slotObj->ref();
+ return create_impl(QtPrivate::SlotObjUniquePtr{slotObj}, sender,
+ signal_index, argc, argp, metaTypes);
+ }
+ static QMetaCallEvent *create_impl(QtPrivate::SlotObjUniquePtr slotObj, const QObject *sender,
+ int signal_index, size_t argc, const void * const argp[],
+ const QMetaType metaTypes[]);
inline void allocArgs();
struct Data {
- QtPrivate::QSlotObjectBase *slotObj_;
+ QtPrivate::SlotObjUniquePtr slotObj_;
void **args_;
QObjectPrivate::StaticMetaCallFunction callFunction_;
int nargs_;
@@ -429,7 +452,9 @@ class QBoolBlocker
{
Q_DISABLE_COPY_MOVE(QBoolBlocker)
public:
- explicit inline QBoolBlocker(bool &b, bool value = true) : block(b), reset(b) { block = value; }
+ Q_NODISCARD_CTOR explicit QBoolBlocker(bool &b, bool value = true)
+ : block(b), reset(b)
+ { block = value; }
inline ~QBoolBlocker() { block = reset; }
private:
@@ -437,8 +462,6 @@ private:
bool reset;
};
-void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o);
-
struct QAbstractDynamicMetaObject;
struct Q_CORE_EXPORT QDynamicMetaObjectData
{
diff --git a/src/corelib/kernel/qobject_p_p.h b/src/corelib/kernel/qobject_p_p.h
index a9bd290d37..2277af0497 100644
--- a/src/corelib/kernel/qobject_p_p.h
+++ b/src/corelib/kernel/qobject_p_p.h
@@ -224,19 +224,18 @@ struct QObjectPrivate::ConnectionData
struct QObjectPrivate::Sender
{
- Sender(QObject *receiver, QObject *sender, int signal)
+ Sender(QObject *receiver, QObject *sender, int signal, ConnectionData *receiverConnections)
: receiver(receiver), sender(sender), signal(signal)
{
- if (receiver) {
- ConnectionData *cd = receiver->d_func()->connections.loadRelaxed();
- previous = cd->currentSender;
- cd->currentSender = this;
+ if (receiverConnections) {
+ previous = receiverConnections->currentSender;
+ receiverConnections->currentSender = this;
}
}
~Sender()
{
if (receiver)
- receiver->d_func()->connections.loadRelaxed()->currentSender = previous;
+ receiver->d_func()->connections.loadAcquire()->currentSender = previous;
}
void receiverDeleted()
{
@@ -246,7 +245,7 @@ struct QObjectPrivate::Sender
s = s->previous;
}
}
- Sender *previous;
+ Sender *previous = nullptr;
QObject *receiver;
QObject *sender;
int signal;
diff --git a/src/corelib/kernel/qobjectcleanuphandler.cpp b/src/corelib/kernel/qobjectcleanuphandler.cpp
index aae93ecc00..f46afc2f07 100644
--- a/src/corelib/kernel/qobjectcleanuphandler.cpp
+++ b/src/corelib/kernel/qobjectcleanuphandler.cpp
@@ -60,7 +60,7 @@ QObject *QObjectCleanupHandler::add(QObject *object)
if (!object)
return nullptr;
- connect(object, SIGNAL(destroyed(QObject *)), this, SLOT(objectDestroyed(QObject *)));
+ connect(object, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*)));
cleanupObjects.insert(0, object);
return object;
}
@@ -76,7 +76,7 @@ void QObjectCleanupHandler::remove(QObject *object)
int index;
if ((index = cleanupObjects.indexOf(object)) != -1) {
cleanupObjects.removeAt(index);
- disconnect(object, SIGNAL(destroyed(QObject *)), this, SLOT(objectDestroyed(QObject *)));
+ disconnect(object, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*)));
}
}
diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h
index 28b4e368fe..190901d5d1 100644
--- a/src/corelib/kernel/qobjectdefs.h
+++ b/src/corelib/kernel/qobjectdefs.h
@@ -11,6 +11,7 @@
#include <QtCore/qnamespace.h>
#include <QtCore/qobjectdefs_impl.h>
+#include <QtCore/qtcoreexports.h>
#include <QtCore/qtmetamacros.h>
QT_BEGIN_NAMESPACE
@@ -142,6 +143,12 @@ struct QMetaMethodReturnArgument
void *data;
};
+template <typename T>
+struct QTemplatedMetaMethodReturnArgument : QMetaMethodReturnArgument
+{
+ using Type = T;
+};
+
namespace QtPrivate {
namespace Invoke {
#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
@@ -164,7 +171,8 @@ template <typename T> inline QMetaMethodArgument argument(const char *name, cons
}
}
-template <typename T> inline QMetaMethodReturnArgument returnArgument(const char *name, T &t)
+template <typename T>
+inline QTemplatedMetaMethodReturnArgument<T> returnArgument(const char *name, T &t)
{
return { qMetaTypeInterfaceForType<T>(), name, std::addressof(t) };
}
@@ -217,7 +225,7 @@ template <typename... Args> inline auto invokeMethodHelper(QMetaMethodReturnArgu
} // namespace QtPrivate
template <typename T> void qReturnArg(const T &&) = delete;
-template <typename T> inline QMetaMethodReturnArgument qReturnArg(T &data)
+template <typename T> inline QTemplatedMetaMethodReturnArgument<T> qReturnArg(T &data)
{
return QtPrivate::Invoke::returnArgument(nullptr, data);
}
@@ -255,6 +263,7 @@ struct Q_CORE_EXPORT QMetaObject
int indexOfSignal(const char *signal) const;
int indexOfSlot(const char *slot) const;
int indexOfEnumerator(const char *name) const;
+
int indexOfProperty(const char *name) const;
int indexOfClassInfo(const char *name) const;
@@ -354,14 +363,14 @@ struct Q_CORE_EXPORT QMetaObject
}
#endif // Qt < 7.0
- template <typename... Args> static
+ template <typename ReturnArg, typename... Args> static
#ifdef Q_QDOC
bool
#else
QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
#endif
invokeMethod(QObject *obj, const char *member, Qt::ConnectionType c,
- QMetaMethodReturnArgument r, Args &&... arguments)
+ QTemplatedMetaMethodReturnArgument<ReturnArg> r, Args &&... arguments)
{
auto h = QtPrivate::invokeMethodHelper(r, std::forward<Args>(arguments)...);
return invokeMethodImpl(obj, member, c, h.parameterCount(), h.parameters.data(),
@@ -376,17 +385,17 @@ struct Q_CORE_EXPORT QMetaObject
#endif
invokeMethod(QObject *obj, const char *member, Qt::ConnectionType c, Args &&... arguments)
{
- QMetaMethodReturnArgument r = {};
+ QTemplatedMetaMethodReturnArgument<void> r = {};
return invokeMethod(obj, member, c, r, std::forward<Args>(arguments)...);
}
- template <typename... Args> static
+ template <typename ReturnArg, typename... Args> static
#ifdef Q_QDOC
bool
#else
QtPrivate::Invoke::IfNotOldStyleArgs<bool, Args...>
#endif
- invokeMethod(QObject *obj, const char *member, QMetaMethodReturnArgument r,
+ invokeMethod(QObject *obj, const char *member, QTemplatedMetaMethodReturnArgument<ReturnArg> r,
Args &&... arguments)
{
return invokeMethod(obj, member, Qt::AutoConnection, r, std::forward<Args>(arguments)...);
@@ -400,87 +409,108 @@ struct Q_CORE_EXPORT QMetaObject
#endif
invokeMethod(QObject *obj, const char *member, Args &&... arguments)
{
- QMetaMethodReturnArgument r = {};
+ QTemplatedMetaMethodReturnArgument<void> r = {};
return invokeMethod(obj, member, Qt::AutoConnection, r, std::forward<Args>(arguments)...);
}
#ifdef Q_QDOC
template<typename Functor, typename FunctorReturnType>
- static bool invokeMethod(QObject *context, Functor function, Qt::ConnectionType type = Qt::AutoConnection, FunctorReturnType *ret = nullptr);
+ static bool invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type = Qt::AutoConnection, FunctorReturnType *ret = nullptr);
template<typename Functor, typename FunctorReturnType>
- static bool invokeMethod(QObject *context, Functor function, FunctorReturnType *ret);
+ static bool invokeMethod(QObject *context, Functor &&function, FunctorReturnType *ret);
+
+ template<typename Functor, typename FunctorReturnType, typename... Args>
+ static bool invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type, QTemplatedMetaMethodReturnArgument<FunctorReturnType> ret, Args &&...arguments);
+ template<typename Functor, typename FunctorReturnType, typename... Args>
+ static bool invokeMethod(QObject *context, Functor &&function, QTemplatedMetaMethodReturnArgument<FunctorReturnType> ret, Args &&...arguments);
+ template<typename Functor, typename... Args>
+ static bool invokeMethod(QObject *context, Functor &&function, Qt::ConnectionType type, Args &&...arguments);
+ template<typename Functor, typename... Args>
+ static bool invokeMethod(QObject *context, Functor &&function, Args &&...arguments);
#else
-
- // invokeMethod() for member function pointer
template <typename Func>
- static typename std::enable_if<QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
- && !std::is_convertible<Func, const char*>::value
- && QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type
- invokeMethod(typename QtPrivate::FunctionPointer<Func>::Object *object,
- Func function,
- Qt::ConnectionType type = Qt::AutoConnection,
- typename QtPrivate::FunctionPointer<Func>::ReturnType *ret = nullptr)
+ static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>,
+ QtPrivate::Invoke::AreOldStyleArgs<Func>>,
+ bool>
+ invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object,
+ Func &&function, Qt::ConnectionType type,
+ typename QtPrivate::Callable<Func>::ReturnType *ret)
{
- return invokeMethodImpl(object, new QtPrivate::QSlotObjectWithNoArgs<Func>(function), type, ret);
+ using R = typename QtPrivate::Callable<Func>::ReturnType;
+ const auto getReturnArg = [ret]() -> QTemplatedMetaMethodReturnArgument<R> {
+ if constexpr (std::is_void_v<R>)
+ return {};
+ else
+ return ret ? qReturnArg(*ret) : QTemplatedMetaMethodReturnArgument<R>{};
+ };
+ return invokeMethod(object, std::forward<Func>(function), type, getReturnArg());
}
-
template <typename Func>
- static typename std::enable_if<QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
- && !std::is_convertible<Func, const char*>::value
- && QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type
- invokeMethod(typename QtPrivate::FunctionPointer<Func>::Object *object,
- Func function,
- typename QtPrivate::FunctionPointer<Func>::ReturnType *ret)
+ static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>,
+ QtPrivate::Invoke::AreOldStyleArgs<Func>>,
+ bool>
+ invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object,
+ Func &&function, typename QtPrivate::Callable<Func>::ReturnType *ret)
{
- return invokeMethodImpl(object, new QtPrivate::QSlotObjectWithNoArgs<Func>(function), Qt::AutoConnection, ret);
+ return invokeMethod(object, std::forward<Func>(function), Qt::AutoConnection, ret);
}
- // invokeMethod() for function pointer (not member)
- template <typename Func>
- static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
- && !std::is_convertible<Func, const char*>::value
- && QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type
- invokeMethod(QObject *context, Func function,
- Qt::ConnectionType type = Qt::AutoConnection,
- typename QtPrivate::FunctionPointer<Func>::ReturnType *ret = nullptr)
+ template <typename Func, typename... Args>
+ static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>,
+ QtPrivate::Invoke::AreOldStyleArgs<Args...>>,
+ bool>
+ invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object,
+ Func &&function, Qt::ConnectionType type,
+ QTemplatedMetaMethodReturnArgument<
+ typename QtPrivate::Callable<Func, Args...>::ReturnType>
+ ret,
+ Args &&...args)
{
- return invokeMethodImpl(context, new QtPrivate::QFunctorSlotObjectWithNoArgsImplicitReturn<Func>(function), type, ret);
+ return invokeMethodCallableHelper(object, std::forward<Func>(function), type, ret,
+ std::forward<Args>(args)...);
}
- template <typename Func>
- static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
- && !std::is_convertible<Func, const char*>::value
- && QtPrivate::FunctionPointer<Func>::ArgumentCount == 0, bool>::type
- invokeMethod(QObject *context, Func function,
- typename QtPrivate::FunctionPointer<Func>::ReturnType *ret)
+ template <typename Func, typename... Args>
+ static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>,
+ QtPrivate::Invoke::AreOldStyleArgs<Args...>>,
+ bool>
+ invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object,
+ Func &&function, Qt::ConnectionType type, Args &&...args)
{
- return invokeMethodImpl(context, new QtPrivate::QFunctorSlotObjectWithNoArgsImplicitReturn<Func>(function), Qt::AutoConnection, ret);
+ using R = typename QtPrivate::Callable<Func, Args...>::ReturnType;
+ QTemplatedMetaMethodReturnArgument<R> r{ QtPrivate::qMetaTypeInterfaceForType<R>(), nullptr,
+ nullptr };
+ return invokeMethod(object, std::forward<Func>(function), type, r,
+ std::forward<Args>(args)...);
}
- // invokeMethod() for Functor
- template <typename Func>
- static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
- && QtPrivate::FunctionPointer<Func>::ArgumentCount == -1
- && !std::is_convertible<Func, const char*>::value, bool>::type
- invokeMethod(QObject *context, Func function,
- Qt::ConnectionType type = Qt::AutoConnection, decltype(function()) *ret = nullptr)
+ template <typename Func, typename... Args>
+ static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>,
+ QtPrivate::Invoke::AreOldStyleArgs<Args...>>,
+ bool>
+ invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object,
+ Func &&function,
+ QTemplatedMetaMethodReturnArgument<
+ typename QtPrivate::Callable<Func, Args...>::ReturnType>
+ ret,
+ Args &&...args)
{
- return invokeMethodImpl(context,
- new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(std::move(function)),
- type,
- ret);
+ return invokeMethod(object, std::forward<Func>(function), Qt::AutoConnection, ret,
+ std::forward<Args>(args)...);
}
- template <typename Func>
- static typename std::enable_if<!QtPrivate::FunctionPointer<Func>::IsPointerToMemberFunction
- && QtPrivate::FunctionPointer<Func>::ArgumentCount == -1
- && !std::is_convertible<Func, const char*>::value, bool>::type
- invokeMethod(QObject *context, Func function, decltype(function()) *ret)
+ template <typename Func, typename... Args>
+ static std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>,
+ QtPrivate::Invoke::AreOldStyleArgs<Args...>>,
+ bool>
+ invokeMethod(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object,
+ Func &&function, Args &&...args)
{
- return invokeMethodImpl(context,
- new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(std::move(function)),
- Qt::AutoConnection,
- ret);
+ using R = typename QtPrivate::Callable<Func, Args...>::ReturnType;
+ QTemplatedMetaMethodReturnArgument<R> r{ QtPrivate::qMetaTypeInterfaceForType<R>(), nullptr,
+ nullptr };
+ return invokeMethod(object, std::forward<Func>(function), Qt::AutoConnection, r,
+ std::forward<Args>(args)...);
}
#endif
@@ -570,14 +600,46 @@ struct Q_CORE_EXPORT QMetaObject
} d;
private:
+ // Just need to have this here with a separate name so the other inline
+ // functions can call this without any ambiguity
+ template <typename Func, typename... Args>
+ static bool
+ invokeMethodCallableHelper(typename QtPrivate::ContextTypeForFunctor<Func>::ContextType *object,
+ Func &&function, Qt::ConnectionType type, const QMetaMethodReturnArgument &ret,
+ Args &&...args)
+ {
+ using Callable = QtPrivate::Callable<Func, Args...>;
+ using ExpectedArguments = typename Callable::Arguments;
+ static_assert(sizeof...(Args) <= ExpectedArguments::size, "Too many arguments");
+ using ActualArguments = QtPrivate::List<Args...>;
+ static_assert(QtPrivate::CheckCompatibleArguments<ActualArguments,
+ ExpectedArguments>::value,
+ "Incompatible arguments");
+
+ auto h = QtPrivate::invokeMethodHelper(ret, std::forward<Args>(args)...);
+
+ // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
+ auto callable = new QtPrivate::QCallableObject<std::decay_t<Func>, ActualArguments,
+ typename Callable::ReturnType>(std::forward<Func>(function));
+ return invokeMethodImpl(object, callable, type, h.parameterCount(), h.parameters.data(),
+ h.typeNames.data(), h.metaTypes.data());
+ }
+
static bool invokeMethodImpl(QObject *object, const char *member, Qt::ConnectionType type,
qsizetype parameterCount, const void *const *parameters, const char *const *names,
const QtPrivate::QMetaTypeInterface * const *metaTypes);
+ static bool invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slotObj,
+ Qt::ConnectionType type, qsizetype parameterCount,
+ const void *const *params, const char *const *names,
+ const QtPrivate::QMetaTypeInterface *const *metaTypes);
+#if QT_CORE_REMOVED_SINCE(6, 7)
static bool invokeMethodImpl(QObject *object, QtPrivate::QSlotObjectBase *slot, Qt::ConnectionType type, void *ret);
+#endif
static QObject *newInstanceImpl(const QMetaObject *mobj, qsizetype parameterCount,
const void **parameters, const char **typeNames,
const QtPrivate::QMetaTypeInterface **metaTypes);
friend class QTimer;
+ friend class QChronoTimer;
};
class Q_CORE_EXPORT QMetaObject::Connection {
@@ -615,7 +677,7 @@ inline const QMetaObject *QMetaObject::superClass() const
{ return d.superdata; }
namespace QtPrivate {
- /* Trait that tells is a the Object has a Q_OBJECT macro */
+ // Trait that tells if a QObject has a Q_OBJECT macro
template <typename Object> struct HasQ_OBJECT_Macro {
template <typename T>
static char test(int (T::*)(QMetaObject::Call, int, void **));
diff --git a/src/corelib/kernel/qobjectdefs_impl.h b/src/corelib/kernel/qobjectdefs_impl.h
index 10f06609ec..1e953f29b6 100644
--- a/src/corelib/kernel/qobjectdefs_impl.h
+++ b/src/corelib/kernel/qobjectdefs_impl.h
@@ -12,9 +12,15 @@
#pragma qt_sync_stop_processing
#endif
+#include <QtCore/qfunctionaltools_impl.h>
+
+#include <memory>
+
QT_BEGIN_NAMESPACE
class QObject;
class QObjectPrivate;
+class QMetaMethod;
+class QByteArray;
namespace QtPrivate {
template <typename T> struct RemoveRef { typedef T Type; };
@@ -29,37 +35,43 @@ namespace QtPrivate {
the list composed of the first N element of the list
*/
// With variadic template, lists are represented using a variadic template argument instead of the lisp way
- template <typename...> struct List {};
- template <typename Head, typename... Tail> struct List<Head, Tail...> { typedef Head Car; typedef List<Tail...> Cdr; };
+ template <typename... Ts> struct List { static constexpr size_t size = sizeof...(Ts); };
+ template<typename T> struct SizeOfList { static constexpr size_t value = 1; };
+ template<> struct SizeOfList<List<>> { static constexpr size_t value = 0; };
+ template<typename ...Ts> struct SizeOfList<List<Ts...>> { static constexpr size_t value = List<Ts...>::size; };
+ template <typename Head, typename... Tail> struct List<Head, Tail...> {
+ static constexpr size_t size = 1 + sizeof...(Tail);
+ typedef Head Car; typedef List<Tail...> Cdr;
+ };
template <typename, typename> struct List_Append;
template <typename... L1, typename...L2> struct List_Append<List<L1...>, List<L2...>> { typedef List<L1..., L2...> Value; };
template <typename L, int N> struct List_Left {
typedef typename List_Append<List<typename L::Car>,typename List_Left<typename L::Cdr, N - 1>::Value>::Value Value;
};
template <typename L> struct List_Left<L, 0> { typedef List<> Value; };
- // List_Select<L,N> returns (via typedef Value) the Nth element of the list L
- template <typename L, int N> struct List_Select { typedef typename List_Select<typename L::Cdr, N - 1>::Value Value; };
- template <typename L> struct List_Select<L,0> { typedef typename L::Car Value; };
/*
- trick to set the return value of a slot that works even if the signal or the slot returns void
- to be used like function(), ApplyReturnValue<ReturnType>(&return_value)
- if function() returns a value, the operator,(T, ApplyReturnValue<ReturnType>) is called, but if it
- returns void, the builtin one is used without an error.
- */
- template <typename T>
- struct ApplyReturnValue {
- void *data;
- explicit ApplyReturnValue(void *data_) : data(data_) {}
+ This is used to store the return value from a slot, whether the caller
+ wants to store this value (QMetaObject::invokeMethod() with
+ qReturnArg() or non-void signal ) or not.
+ */
+ struct FunctorCallBase
+ {
+ template <typename R, typename Lambda>
+ static void call_internal(void **args, Lambda &&fn) noexcept(noexcept(fn()))
+ {
+ using SlotRet = decltype(fn());
+ if constexpr (std::is_void_v<R> || std::is_void_v<SlotRet>) {
+ Q_UNUSED(args);
+ } else {
+ if (args[0]) {
+ *reinterpret_cast<R *>(args[0]) = fn();
+ return;
+ }
+ }
+ fn();
+ }
};
- template<typename T, typename U>
- void operator,(T &&value, const ApplyReturnValue<U> &container) {
- if (container.data)
- *reinterpret_cast<U *>(container.data) = std::forward<T>(value);
- }
- template<typename T>
- void operator,(T, const ApplyReturnValue<void> &) {}
-
/*
The FunctionPointer<Func> struct is a type trait for function pointer.
@@ -75,7 +87,7 @@ namespace QtPrivate {
and args is the array of pointer to arguments, as used in qt_metacall
The Functor<Func,N> struct is the helper to call a functor of N argument.
- its call function is the same as the FunctionPointer::call function.
+ Its call function is the same as the FunctionPointer::call function.
*/
template<class T> using InvokeGenSeq = typename T::Type;
@@ -122,41 +134,57 @@ namespace QtPrivate {
template <typename, typename, typename, typename> struct FunctorCall;
template <int... II, typename... SignalArgs, typename R, typename Function>
- struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, Function> {
- static void call(Function &f, void **arg) {
- f((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
+ struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, Function> : FunctorCallBase
+ {
+ static void call(Function &f, void **arg)
+ {
+ call_internal<R>(arg, [&] {
+ return f((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...);
+ });
}
};
template <int... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
- struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...)> {
+ struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...)> : FunctorCallBase
+ {
static void call(SlotRet (Obj::*f)(SlotArgs...), Obj *o, void **arg)
{
assertObjectType<Obj>(o);
- (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
+ call_internal<R>(arg, [&] {
+ return (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...);
+ });
}
};
template <int... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
- struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...) const> {
+ struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...) const> : FunctorCallBase
+ {
static void call(SlotRet (Obj::*f)(SlotArgs...) const, Obj *o, void **arg)
{
assertObjectType<Obj>(o);
- (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
+ call_internal<R>(arg, [&] {
+ return (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...);
+ });
}
};
template <int... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
- struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...) noexcept> {
+ struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...) noexcept> : FunctorCallBase
+ {
static void call(SlotRet (Obj::*f)(SlotArgs...) noexcept, Obj *o, void **arg)
{
assertObjectType<Obj>(o);
- (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
+ call_internal<R>(arg, [&]() noexcept {
+ return (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...);
+ });
}
};
template <int... II, typename... SignalArgs, typename R, typename... SlotArgs, typename SlotRet, class Obj>
- struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...) const noexcept> {
+ struct FunctorCall<IndexesList<II...>, List<SignalArgs...>, R, SlotRet (Obj::*)(SlotArgs...) const noexcept> : FunctorCallBase
+ {
static void call(SlotRet (Obj::*f)(SlotArgs...) const noexcept, Obj *o, void **arg)
{
assertObjectType<Obj>(o);
- (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...), ApplyReturnValue<R>(arg[0]);
+ call_internal<R>(arg, [&]() noexcept {
+ return (o->*f)((*reinterpret_cast<typename RemoveRef<SignalArgs>::Type *>(arg[II+1]))...);
+ });
}
};
@@ -234,14 +262,6 @@ namespace QtPrivate {
}
};
- template<typename Function, int N> struct Functor
- {
- template <typename SignalArgs, typename R>
- static void call(Function &f, void *, void **arg) {
- FunctorCall<typename Indexes<N>::Value, SignalArgs, R, Function>::call(f, arg);
- }
- };
-
// Traits to detect if there is a conversion between two types,
// and that conversion does not include a narrowing conversion.
template <typename T>
@@ -275,10 +295,9 @@ namespace QtPrivate {
static_assert(CheckCompatibleArguments<FunctionPointer<Signal>::Arguments, FunctionPointer<Slot>::Arguments>::value)
*/
template<typename A1, typename A2> struct AreArgumentsCompatible {
- static int test(const typename RemoveRef<A2>::Type&);
+ static int test(const std::remove_reference_t<A2>&);
static char test(...);
- static const typename RemoveRef<A1>::Type &dummy();
- enum { value = sizeof(test(dummy())) == sizeof(int) };
+ enum { value = sizeof(test(std::declval<std::remove_reference_t<A1>>())) == sizeof(int) };
#ifdef QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
using AreArgumentsConvertibleWithoutNarrowing = AreArgumentsConvertibleWithoutNarrowingBase<std::decay_t<A1>, std::decay_t<A2>>;
static_assert(AreArgumentsConvertibleWithoutNarrowing::value, "Signal and slot arguments are not compatible (narrowing)");
@@ -317,11 +336,10 @@ namespace QtPrivate {
template <typename Functor, typename... ArgList> struct ComputeFunctorArgumentCount<Functor, List<ArgList...>>
{
- template <typename D> static D dummy();
- template <typename F> static auto test(F f) -> decltype(((f.operator()((dummy<ArgList>())...)), int()));
+ template <typename F> static auto test(F f) -> decltype(((f.operator()((std::declval<ArgList>())...)), int()));
static char test(...);
enum {
- Ok = sizeof(test(dummy<Functor>())) == sizeof(int),
+ Ok = sizeof(test(std::declval<Functor>())) == sizeof(int),
Value = Ok ? int(sizeof...(ArgList)) : int(ComputeFunctorArgumentCountHelper<Functor, List<ArgList...>, Ok>::Value)
};
};
@@ -329,19 +347,115 @@ namespace QtPrivate {
/* get the return type of a functor, given the signal argument list */
template <typename Functor, typename ArgList> struct FunctorReturnType;
template <typename Functor, typename ... ArgList> struct FunctorReturnType<Functor, List<ArgList...>> {
- template <typename D> static D dummy();
- typedef decltype(dummy<Functor>().operator()((dummy<ArgList>())...)) Value;
+ typedef decltype(std::declval<Functor>().operator()((std::declval<ArgList>())...)) Value;
};
+ template<typename Func, typename... Args>
+ struct FunctorCallable
+ {
+ using ReturnType = decltype(std::declval<Func>()(std::declval<Args>()...));
+ using Function = ReturnType(*)(Args...);
+ enum {ArgumentCount = sizeof...(Args)};
+ using Arguments = QtPrivate::List<Args...>;
+
+ template <typename SignalArgs, typename R>
+ static void call(Func &f, void *, void **arg) {
+ FunctorCall<typename Indexes<ArgumentCount>::Value, SignalArgs, R, Func>::call(f, arg);
+ }
+ };
+
+ template <typename Functor, typename... Args>
+ struct HasCallOperatorAcceptingArgs
+ {
+ private:
+ template <typename F, typename = void>
+ struct Test : std::false_type
+ {
+ };
+ // We explicitly use .operator() to not return true for pointers to free/static function
+ template <typename F>
+ struct Test<F, std::void_t<decltype(std::declval<F>().operator()(std::declval<Args>()...))>>
+ : std::true_type
+ {
+ };
+
+ public:
+ using Type = Test<Functor>;
+ static constexpr bool value = Type::value;
+ };
+
+ template <typename Functor, typename... Args>
+ constexpr bool
+ HasCallOperatorAcceptingArgs_v = HasCallOperatorAcceptingArgs<Functor, Args...>::value;
+
+ template <typename Func, typename... Args>
+ struct CallableHelper
+ {
+ private:
+ // Could've been std::conditional_t, but that requires all branches to
+ // be valid
+ static auto Resolve(std::true_type CallOperator) -> FunctorCallable<Func, Args...>;
+ static auto Resolve(std::false_type CallOperator) -> FunctionPointer<std::decay_t<Func>>;
+
+ public:
+ using Type = decltype(Resolve(typename HasCallOperatorAcceptingArgs<std::decay_t<Func>,
+ Args...>::Type{}));
+ };
+
+ template<typename Func, typename... Args>
+ struct Callable : CallableHelper<Func, Args...>::Type
+ {};
+ template<typename Func, typename... Args>
+ struct Callable<Func, List<Args...>> : CallableHelper<Func, Args...>::Type
+ {};
+
+ /*
+ Wrapper around ComputeFunctorArgumentCount and CheckCompatibleArgument,
+ depending on whether \a Functor is a PMF or not. Returns -1 if \a Func is
+ not compatible with the \a ExpectedArguments, otherwise returns >= 0.
+ */
+ template<typename Prototype, typename Functor>
+ inline constexpr std::enable_if_t<!std::disjunction_v<std::is_convertible<Prototype, const char *>,
+ std::is_same<std::decay_t<Prototype>, QMetaMethod>,
+ std::is_convertible<Functor, const char *>,
+ std::is_same<std::decay_t<Functor>, QMetaMethod>
+ >,
+ int>
+ countMatchingArguments()
+ {
+ using ExpectedArguments = typename QtPrivate::FunctionPointer<Prototype>::Arguments;
+ using Actual = std::decay_t<Functor>;
+
+ if constexpr (QtPrivate::FunctionPointer<Actual>::IsPointerToMemberFunction
+ || QtPrivate::FunctionPointer<Actual>::ArgumentCount >= 0) {
+ // PMF or free function
+ using ActualArguments = typename QtPrivate::FunctionPointer<Actual>::Arguments;
+ if constexpr (QtPrivate::CheckCompatibleArguments<ExpectedArguments, ActualArguments>::value)
+ return QtPrivate::FunctionPointer<Actual>::ArgumentCount;
+ else
+ return -1;
+ } else {
+ // lambda or functor
+ return QtPrivate::ComputeFunctorArgumentCount<Actual, ExpectedArguments>::Value;
+ }
+ }
+
// internal base class (interface) containing functions required to call a slot managed by a pointer to function.
- class QSlotObjectBase {
- QAtomicInt m_ref;
- // don't use virtual functions here; we don't want the
+ class QSlotObjectBase
+ {
+ // Don't use virtual functions here; we don't want the
// compiler to create tons of per-polymorphic-class stuff that
// we'll never need. We just use one function pointer, and the
// Operations enum below to distinguish requests
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ QAtomicInt m_ref = 1;
typedef void (*ImplFn)(int which, QSlotObjectBase* this_, QObject *receiver, void **args, bool *ret);
const ImplFn m_impl;
+#else
+ using ImplFn = void (*)(QSlotObjectBase* this_, QObject *receiver, void **args, int which, bool *ret);
+ const ImplFn m_impl;
+ QAtomicInt m_ref = 1;
+#endif
protected:
// The operations that can be requested by calls to m_impl,
// see the member functions that call m_impl below for details
@@ -353,14 +467,36 @@ namespace QtPrivate {
NumOperations
};
public:
- explicit QSlotObjectBase(ImplFn fn) : m_ref(1), m_impl(fn) {}
+ explicit QSlotObjectBase(ImplFn fn) : m_impl(fn) {}
+
+ // A custom deleter compatible with std protocols (op()()) we well as
+ // the legacy QScopedPointer protocol (cleanup()).
+ struct Deleter {
+ void operator()(QSlotObjectBase *p) const noexcept
+ { if (p) p->destroyIfLastRef(); }
+ // for the non-standard QScopedPointer protocol:
+ static void cleanup(QSlotObjectBase *p) noexcept { Deleter{}(p); }
+ };
- inline int ref() noexcept { return m_ref.ref(); }
+ bool ref() noexcept { return m_ref.ref(); }
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
inline void destroyIfLastRef() noexcept
{ if (!m_ref.deref()) m_impl(Destroy, this, nullptr, nullptr, nullptr); }
inline bool compare(void **a) { bool ret = false; m_impl(Compare, this, nullptr, a, &ret); return ret; }
- inline void call(QObject *r, void **a) { m_impl(Call, this, r, a, nullptr); }
+ inline void call(QObject *r, void **a) { m_impl(Call, this, r, a, nullptr); }
+#else
+ inline void destroyIfLastRef() noexcept
+ { if (!m_ref.deref()) m_impl(this, nullptr, nullptr, Destroy, nullptr); }
+
+ inline bool compare(void **a)
+ {
+ bool ret = false;
+ m_impl(this, nullptr, a, Compare, &ret);
+ return ret;
+ }
+ inline void call(QObject *r, void **a) { m_impl(this, r, a, Call, nullptr); }
+#endif
bool isImpl(ImplFn f) const { return m_impl == f; }
protected:
~QSlotObjectBase() {}
@@ -368,66 +504,160 @@ namespace QtPrivate {
Q_DISABLE_COPY_MOVE(QSlotObjectBase)
};
- // implementation of QSlotObjectBase for which the slot is a pointer to member function of a QObject
- // Args and R are the List of arguments and the return type of the signal to which the slot is connected.
- template<typename Func, typename Args, typename R> class QSlotObject : public QSlotObjectBase
+ using SlotObjUniquePtr = std::unique_ptr<QSlotObjectBase,
+ QSlotObjectBase::Deleter>;
+ inline SlotObjUniquePtr copy(const SlotObjUniquePtr &other) noexcept
{
- typedef QtPrivate::FunctionPointer<Func> FuncType;
- Func function;
- static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
+ if (other)
+ other->ref();
+ return SlotObjUniquePtr{other.get()};
+ }
+
+ class SlotObjSharedPtr {
+ SlotObjUniquePtr obj;
+ public:
+ Q_NODISCARD_CTOR Q_IMPLICIT SlotObjSharedPtr() noexcept = default;
+ Q_NODISCARD_CTOR Q_IMPLICIT SlotObjSharedPtr(std::nullptr_t) noexcept : SlotObjSharedPtr() {}
+ Q_NODISCARD_CTOR explicit SlotObjSharedPtr(SlotObjUniquePtr o)
+ : obj(std::move(o))
{
- switch (which) {
- case Destroy:
- delete static_cast<QSlotObject*>(this_);
- break;
- case Call:
- FuncType::template call<Args, R>(static_cast<QSlotObject*>(this_)->function, static_cast<typename FuncType::Object *>(r), a);
- break;
- case Compare:
- *ret = *reinterpret_cast<Func *>(a) == static_cast<QSlotObject*>(this_)->function;
- break;
- case NumOperations: ;
- }
+ // does NOT ref() (takes unique_ptr by value)
+ // (that's why (QSlotObjectBase*) ctor doesn't exisit: don't know whether that one _should_)
}
- public:
- explicit QSlotObject(Func f) : QSlotObjectBase(&impl), function(f) {}
+ Q_NODISCARD_CTOR SlotObjSharedPtr(const SlotObjSharedPtr &other) noexcept
+ : obj{copy(other.obj)} {}
+ SlotObjSharedPtr &operator=(const SlotObjSharedPtr &other) noexcept
+ { auto copy = other; swap(copy); return *this; }
+
+ Q_NODISCARD_CTOR SlotObjSharedPtr(SlotObjSharedPtr &&other) noexcept = default;
+ SlotObjSharedPtr &operator=(SlotObjSharedPtr &&other) noexcept = default;
+ ~SlotObjSharedPtr() = default;
+
+ void swap(SlotObjSharedPtr &other) noexcept { obj.swap(other.obj); }
+
+ auto get() const noexcept { return obj.get(); }
+ auto operator->() const noexcept { return get(); }
+
+ explicit operator bool() const noexcept { return bool(obj); }
};
- // implementation of QSlotObjectBase for which the slot is a functor (or lambda)
- // N is the number of arguments
+
+
+ // Implementation of QSlotObjectBase for which the slot is a callable (function, PMF, functor, or lambda).
// Args and R are the List of arguments and the return type of the signal to which the slot is connected.
- template<typename Func, int N, typename Args, typename R> class QFunctorSlotObject : public QSlotObjectBase
+ template <typename Func, typename Args, typename R>
+ class QCallableObject : public QSlotObjectBase,
+ private QtPrivate::CompactStorage<std::decay_t<Func>>
{
- typedef QtPrivate::Functor<Func, N> FuncType;
- Func function;
- static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
+ using FunctorValue = std::decay_t<Func>;
+ using Storage = QtPrivate::CompactStorage<FunctorValue>;
+ using FuncType = Callable<Func, Args>;
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ Q_DECL_HIDDEN static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret)
+#else
+ // Design note: the first three arguments match those for typical Call
+ // and Destroy uses. We return void to enable tail call optimization
+ // for those too.
+ Q_DECL_HIDDEN static void impl(QSlotObjectBase *this_, QObject *r, void **a, int which, bool *ret)
+#endif
{
+ const auto that = static_cast<QCallableObject*>(this_);
switch (which) {
case Destroy:
- delete static_cast<QFunctorSlotObject*>(this_);
+ delete that;
break;
case Call:
- FuncType::template call<Args, R>(static_cast<QFunctorSlotObject*>(this_)->function, r, a);
+ if constexpr (std::is_member_function_pointer_v<FunctorValue>)
+ FuncType::template call<Args, R>(that->object(), static_cast<typename FuncType::Object *>(r), a);
+ else
+ FuncType::template call<Args, R>(that->object(), r, a);
break;
- case Compare: // not implemented
+ case Compare:
+ if constexpr (std::is_member_function_pointer_v<FunctorValue>) {
+ *ret = *reinterpret_cast<FunctorValue *>(a) == that->object();
+ break;
+ }
+ // not implemented otherwise
+ Q_FALLTHROUGH();
case NumOperations:
Q_UNUSED(ret);
}
}
public:
- explicit QFunctorSlotObject(Func f) : QSlotObjectBase(&impl), function(std::move(f)) {}
+ explicit QCallableObject(Func &&f) : QSlotObjectBase(&impl), Storage{std::move(f)} {}
+ explicit QCallableObject(const Func &f) : QSlotObjectBase(&impl), Storage{f} {}
};
- // typedefs for readability for when there are no parameters
+ // Helper to detect the context object type based on the functor type:
+ // QObject for free functions and lambdas; the callee for member function
+ // pointers. The default declaration doesn't have the ContextType typedef,
+ // and so non-functor APIs (like old-style string-based slots) are removed
+ // from the overload set.
+ template <typename Func, typename = void>
+ struct ContextTypeForFunctor {};
+
+ template <typename Func>
+ struct ContextTypeForFunctor<Func,
+ std::enable_if_t<!std::disjunction_v<std::is_convertible<Func, const char *>,
+ std::is_member_function_pointer<Func>
+ >
+ >
+ >
+ {
+ using ContextType = QObject;
+ };
template <typename Func>
- using QSlotObjectWithNoArgs = QSlotObject<Func,
- QtPrivate::List<>,
- typename QtPrivate::FunctionPointer<Func>::ReturnType>;
+ struct ContextTypeForFunctor<Func,
+ std::enable_if_t<std::conjunction_v<std::negation<std::is_convertible<Func, const char *>>,
+ std::is_member_function_pointer<Func>,
+ std::is_convertible<typename QtPrivate::FunctionPointer<Func>::Object *, QObject *>
+ >
+ >
+ >
+ {
+ using ContextType = typename QtPrivate::FunctionPointer<Func>::Object;
+ };
- template <typename Func, typename R>
- using QFunctorSlotObjectWithNoArgs = QFunctorSlotObject<Func, 0, QtPrivate::List<>, R>;
+ /*
+ Returns a suitable QSlotObjectBase object that holds \a func, if possible.
- template <typename Func>
- using QFunctorSlotObjectWithNoArgsImplicitReturn = QFunctorSlotObjectWithNoArgs<Func, typename QtPrivate::FunctionPointer<Func>::ReturnType>;
+ Not available (and thus produces compile-time errors) if the Functor provided is
+ not compatible with the expected Prototype.
+ */
+ template <typename Prototype, typename Functor>
+ static constexpr std::enable_if_t<QtPrivate::countMatchingArguments<Prototype, Functor>() >= 0,
+ QtPrivate::QSlotObjectBase *>
+ makeCallableObject(Functor &&func)
+ {
+ using ExpectedSignature = QtPrivate::FunctionPointer<Prototype>;
+ using ExpectedReturnType = typename ExpectedSignature::ReturnType;
+ using ExpectedArguments = typename ExpectedSignature::Arguments;
+
+ using ActualSignature = QtPrivate::FunctionPointer<Functor>;
+ constexpr int MatchingArgumentCount = QtPrivate::countMatchingArguments<Prototype, Functor>();
+ using ActualArguments = typename QtPrivate::List_Left<ExpectedArguments, MatchingArgumentCount>::Value;
+
+ static_assert(int(ActualSignature::ArgumentCount) <= int(ExpectedSignature::ArgumentCount),
+ "Functor requires more arguments than what can be provided.");
+
+ // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
+ return new QtPrivate::QCallableObject<std::decay_t<Functor>, ActualArguments, ExpectedReturnType>(std::forward<Functor>(func));
+ }
+
+ template<typename Prototype, typename Functor, typename = void>
+ struct AreFunctionsCompatible : std::false_type {};
+ template<typename Prototype, typename Functor>
+ struct AreFunctionsCompatible<Prototype, Functor, std::enable_if_t<
+ std::is_same_v<decltype(QtPrivate::makeCallableObject<Prototype>(std::forward<Functor>(std::declval<Functor>()))),
+ QtPrivate::QSlotObjectBase *>>
+ > : std::true_type {};
+
+ template<typename Prototype, typename Functor>
+ inline constexpr bool AssertCompatibleFunctions() {
+ static_assert(AreFunctionsCompatible<Prototype, Functor>::value,
+ "Functor is not compatible with expected prototype!");
+ return true;
+ }
}
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qpermissions.cpp b/src/corelib/kernel/qpermissions.cpp
index 4667896f4e..d0d2d9eb10 100644
--- a/src/corelib/kernel/qpermissions.cpp
+++ b/src/corelib/kernel/qpermissions.cpp
@@ -46,7 +46,6 @@ Q_LOGGING_CATEGORY(lcPermissions, "qt.permissions", QtWarningMsg);
\code
void VoiceMemoWidget::onRecordingInitiated()
{
- #if QT_CONFIG(permissions)
QMicrophonePermission microphonePermission;
switch (qApp->checkPermission(microphonePermission)) {
case Qt::PermissionStatus::Undetermined:
@@ -57,10 +56,8 @@ Q_LOGGING_CATEGORY(lcPermissions, "qt.permissions", QtWarningMsg);
m_permissionInstructionsDialog->show();
return;
case Qt::PermissionStatus::Granted:
- break; // Proceed
+ m_microphone->startRecording();
}
- #endif
- m_microphone->startRecording();
}
\endcode
@@ -76,8 +73,8 @@ Q_LOGGING_CATEGORY(lcPermissions, "qt.permissions", QtWarningMsg);
why we can not record voice memos at this time (if the permission was denied),
or proceed to using the microphone (if permission was granted).
- The use of the \c{QT_CONFIG(permissions)} macro ensures that the code
- will work as before on platforms where permissions are not available.
+ \note On \macOS and iOS permissions can currently only be requested for
+ GUI applications.
\section2 Declaring Permissions
@@ -198,7 +195,7 @@ Q_LOGGING_CATEGORY(lcPermissions, "qt.permissions", QtWarningMsg);
\endcode
To inspect the properties of the original, typed permission,
- use the data() function:
+ use the \l {QPermission::}{value()} function:
\code
QLocationPermission locationPermission;
@@ -229,7 +226,7 @@ Q_LOGGING_CATEGORY(lcPermissions, "qt.permissions", QtWarningMsg);
*/
/*!
- \fn template <typename T, if_permission<T>> QPermission::QPermission(const T &type)
+ \fn template <typename T, QPermission::if_permission<T>> QPermission::QPermission(const T &type)
Constructs a permission from the given \l{typed permission} \a type.
@@ -243,7 +240,7 @@ Q_LOGGING_CATEGORY(lcPermissions, "qt.permissions", QtWarningMsg);
*/
/*!
- \fn template <typename T, if_permission<T>> std::optional<T> QPermission::value() const
+ \fn template <typename T, QPermission::if_permission<T>> std::optional<T> QPermission::value() const
Returns the \l{typed permission} of type \c T, or \c{std::nullopt} if this
QPermission object doesn't contain one.
@@ -358,17 +355,87 @@ QT_PERMISSION_IMPL_COMMON(QMicrophonePermission)
\row
\li Android
\li \l{android-uses-permission}{\c{uses-permission}}
- \li \c android.permission.BLUETOOTH
+ \li Up to Android 11 (API Level < 31):
+ \list
+ \li \c android.permission.BLUETOOTH
+ \li \c android.permission.ACCESS_FINE_LOCATION
+ \endlist
+
+ Starting from Android 12 (API Level >= 31):
+ \list
+ \li \c android.permission.BLUETOOTH_ADVERTISE
+ \li \c android.permission.BLUETOOTH_CONNECT
+ \li \c android.permission.BLUETOOTH_SCAN
+ \li \c android.permission.ACCESS_FINE_LOCATION
+ \endlist
\include permissions.qdocinc end-usage-declarations
+ \note Currently on Android the \c android.permission.ACCESS_FINE_LOCATION
+ permission is requested together with Bluetooth permissions. This is
+ required for Bluetooth to work properly, unless the application provides a
+ strong assertion in the application manifest that it does not use Bluetooth
+ to derive a physical location. This permission coupling may change in
+ future.
+
\include permissions.qdocinc permission-metadata
*/
QT_PERMISSION_IMPL_COMMON(QBluetoothPermission)
- : u{} // stateless, atm
+ : u{ShortData{CommunicationMode::Default, {}}}
{}
/*!
+ \enum QBluetoothPermission::CommunicationMode
+ \since 6.6
+
+ This enum is used to control the allowed Bluetooth communication modes.
+
+ \value Access Allow this device to access other Bluetooth devices. This
+ includes scanning for nearby devices and connecting to them.
+ \value Advertise Allow other Bluetooth devices to discover this device.
+ \value Default This configuration is used by default.
+
+ \note The fine-grained permissions are currently supported only on
+ Android 12 and newer. On older Android versions, as well as on Apple
+ operating systems, any mode results in full Bluetooth access.
+
+ \note For now the \c Access mode on Android also requests the
+ \l {QLocationPermission::Precise}{precise location} permission.
+ This permission coupling may change in the future.
+*/
+
+/*!
+ \since 6.6
+
+ Sets the allowed Bluetooth communication modes to \a modes.
+
+ \note A default-constructed instance of \l {QBluetoothPermission::}
+ {CommunicationModes} has no sense, so an attempt to set such a mode will
+ raise a \c {qWarning()} and fall back to using the
+ \l {QBluetoothPermission::}{Default} mode.
+*/
+void QBluetoothPermission::setCommunicationModes(CommunicationModes modes)
+{
+ if (modes == CommunicationModes{}) {
+ qCWarning(lcPermissions, "QBluetoothPermission: trying to set an invalid empty mode. "
+ "Falling back to CommunicationMode::Default.");
+ u.data.mode = Default;
+ } else {
+ u.data.mode = static_cast<CommunicationMode>(modes.toInt());
+ }
+}
+
+/*!
+ \since 6.6
+
+ Returns the allowed Bluetooth communication modes.
+*/
+QBluetoothPermission::CommunicationModes QBluetoothPermission::communicationModes() const
+{
+ return u.data.mode;
+}
+
+/*!
\class QLocationPermission
\brief Access the user's location.
@@ -599,6 +666,28 @@ QDebug operator<<(QDebug debug, const QPermission &permission)
#undef QT_PERMISSION_IMPL_COMMON
+#if !defined(Q_OS_DARWIN) && !defined(Q_OS_ANDROID) && !defined(Q_OS_WASM)
+// Default backend for platforms without a permission implementation.
+// Always returns Granted, to match behavior when not using permission APIs
+// https://bugreports.qt.io/browse/QTBUG-90498?focusedCommentId=725085#comment-725085
+namespace QPermissions::Private
+{
+ Qt::PermissionStatus checkPermission(const QPermission &permission)
+ {
+ qCDebug(lcPermissions) << "No permission backend on this platform."
+ << "Optimistically returning Granted for" << permission;
+ return Qt::PermissionStatus::Granted;
+ }
+
+ void requestPermission(const QPermission &permission, const PermissionCallback &callback)
+ {
+ qCDebug(lcPermissions) << "No permission backend on this platform."
+ << "Optimistically returning Granted for" << permission;
+ callback(Qt::PermissionStatus::Granted);
+ }
+}
+#endif
+
QT_END_NAMESPACE
#include "moc_qpermissions.cpp"
diff --git a/src/corelib/kernel/qpermissions.h b/src/corelib/kernel/qpermissions.h
index 3bd1fda461..9573e377e5 100644
--- a/src/corelib/kernel/qpermissions.h
+++ b/src/corelib/kernel/qpermissions.h
@@ -37,9 +37,6 @@ class QPermission
static constexpr inline bool is_permission_v = false;
template <typename T>
- static constexpr inline bool is_permission_v<T, typename T::QtPermissionHelper> = true;
-
- template <typename T>
using if_permission = std::enable_if_t<is_permission_v<T>, bool>;
public:
explicit QPermission() = default;
@@ -72,6 +69,9 @@ private:
friend class QCoreApplication;
};
+template <typename T>
+constexpr bool QPermission::is_permission_v<T, typename T::QtPermissionHelper> = true;
+
#define QT_PERMISSION(ClassName) \
using QtPermissionHelper = void; \
friend class QPermission; \
@@ -173,6 +173,32 @@ private:
};
Q_DECLARE_SHARED(QContactsPermission)
+class QBluetoothPermissionPrivate;
+class QBluetoothPermission
+{
+ Q_GADGET_EXPORT(Q_CORE_EXPORT)
+public:
+ enum CommunicationMode : quint8 {
+ Access = 0x01,
+ Advertise = 0x02,
+ Default = Access | Advertise,
+ };
+ Q_DECLARE_FLAGS(CommunicationModes, CommunicationMode)
+ Q_FLAG(CommunicationModes)
+
+ Q_CORE_EXPORT void setCommunicationModes(CommunicationModes modes);
+ Q_CORE_EXPORT CommunicationModes communicationModes() const;
+
+private:
+ struct ShortData {
+ CommunicationMode mode;
+ char reserved[sizeof(void*) - sizeof(mode)];
+ };
+ QT_PERMISSION(QBluetoothPermission)
+};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QBluetoothPermission::CommunicationModes)
+Q_DECLARE_SHARED(QBluetoothPermission)
+
#define Q_DECLARE_MINIMAL_PERMISSION(ClassName) \
class ClassName##Private; \
class ClassName \
@@ -184,7 +210,6 @@ Q_DECLARE_SHARED(QContactsPermission)
Q_DECLARE_MINIMAL_PERMISSION(QCameraPermission)
Q_DECLARE_MINIMAL_PERMISSION(QMicrophonePermission)
-Q_DECLARE_MINIMAL_PERMISSION(QBluetoothPermission)
#undef QT_PERMISSION
#undef Q_DECLARE_MINIMAL_PERMISSION
diff --git a/src/corelib/kernel/qpermissions_android.cpp b/src/corelib/kernel/qpermissions_android.cpp
index 25ae111bec..6c21ded72c 100644
--- a/src/corelib/kernel/qpermissions_android.cpp
+++ b/src/corelib/kernel/qpermissions_android.cpp
@@ -49,6 +49,34 @@ static QStringList nativeLocationPermission(const QLocationPermission &permissio
return nativeLocationPermissionList;
}
+static QStringList nativeBluetoothPermission(const QBluetoothPermission &permission)
+{
+ // See https://developer.android.com/guide/topics/connectivity/bluetooth/permissions
+ // for the details.
+
+ // API Level < 31
+ static QString bluetoothGeneral = u"android.permission.BLUETOOTH"_s;
+ // API Level >= 31
+ static QString bluetoothScan = u"android.permission.BLUETOOTH_SCAN"_s;
+ static QString bluetoothAdvertise = u"android.permission.BLUETOOTH_ADVERTISE"_s;
+ static QString bluetoothConnect = u"android.permission.BLUETOOTH_CONNECT"_s;
+ // Fine location is currently required for ALL API levels, but that is not
+ // strictly necessary for API Level >= 31. See QTBUG-112164.
+ static QString fineLocation = u"android.permission.ACCESS_FINE_LOCATION"_s;
+
+ if (QtAndroidPrivate::androidSdkVersion() < 31) {
+ return {bluetoothGeneral, fineLocation};
+ } else {
+ const auto modes = permission.communicationModes();
+ QStringList permissionList;
+ if (modes & QBluetoothPermission::Advertise)
+ permissionList << bluetoothAdvertise;
+ if (modes & QBluetoothPermission::Access)
+ permissionList << bluetoothScan << bluetoothConnect << fineLocation;
+ return permissionList;
+ }
+}
+
static QStringList nativeStringsFromPermission(const QPermission &permission)
{
const auto id = permission.type().id();
@@ -59,8 +87,7 @@ static QStringList nativeStringsFromPermission(const QPermission &permission)
} else if (id == qMetaTypeId<QMicrophonePermission>()) {
return { u"android.permission.RECORD_AUDIO"_s };
} else if (id == qMetaTypeId<QBluetoothPermission>()) {
- // TODO: handle Android 12 new bluetooth permissions
- return { u"android.permission.BLUETOOTH"_s };
+ return nativeBluetoothPermission(*permission.value<QBluetoothPermission>());
} else if (id == qMetaTypeId<QContactsPermission>()) {
const auto readContactsString = u"android.permission.READ_CONTACTS"_s;
switch (permission.value<QContactsPermission>()->accessMode()) {
@@ -104,6 +131,18 @@ Q_GLOBAL_STATIC_WITH_ARGS(PermissionStatusHash, g_permissionStatusHash, ({
{ qMetaTypeId<QLocationPermission>(), Qt::PermissionStatus::Undetermined }
}));
+static Qt::PermissionStatus
+getCombinedStatus(const QList<QtAndroidPrivate::PermissionResult> &androidResults)
+{
+ // Android returns only Denied or Granted
+ for (const auto &result : androidResults) {
+ const auto status = permissionStatusForAndroidResult(result);
+ if (status == Qt::PermissionStatus::Denied)
+ return status;
+ }
+ return Qt::PermissionStatus::Granted;
+}
+
namespace QPermissions::Private
{
Qt::PermissionStatus checkPermission(const QPermission &permission)
@@ -112,8 +151,12 @@ namespace QPermissions::Private
if (nativePermissionList.isEmpty())
return Qt::PermissionStatus::Granted;
- const auto result = QtAndroidPrivate::checkPermission(nativePermissionList.first()).result();
- const auto status = permissionStatusForAndroidResult(result);
+ QList<QtAndroidPrivate::PermissionResult> androidResults;
+ androidResults.reserve(nativePermissionList.size());
+ for (const auto &nativePermission : nativePermissionList)
+ androidResults.push_back(QtAndroidPrivate::checkPermission(nativePermission).result());
+
+ const auto status = getCombinedStatus(androidResults);
const auto it = g_permissionStatusHash->constFind(permission.type().id());
const bool foundStatus = (it != g_permissionStatusHash->constEnd());
const bool itUndetermined = foundStatus && (*it) == Qt::PermissionStatus::Undetermined;
@@ -133,8 +176,9 @@ namespace QPermissions::Private
QtAndroidPrivate::requestPermissions(nativePermissionList).then(qApp,
[callback, permission](QFuture<QtAndroidPrivate::PermissionResult> future) {
- const auto result = future.isValid() ? future.result() : QtAndroidPrivate::Denied;
- const auto status = permissionStatusForAndroidResult(result);
+ const auto androidResults = future.isValid() ? future.results()
+ : QList{QtAndroidPrivate::Denied};
+ const auto status = getCombinedStatus(androidResults);
g_permissionStatusHash->insert(permission.type().id(), status);
callback(status);
}
diff --git a/src/corelib/kernel/qpermissions_wasm.cpp b/src/corelib/kernel/qpermissions_wasm.cpp
index 175fc89dd0..846e62ccf7 100644
--- a/src/corelib/kernel/qpermissions_wasm.cpp
+++ b/src/corelib/kernel/qpermissions_wasm.cpp
@@ -131,11 +131,8 @@ namespace
return cb(Qt::PermissionStatus::Denied);
qstdweb::PromiseCallbacks queryCallbacks;
- queryCallbacks.thenFunc = [device, cb](val mediaStream)
+ queryCallbacks.thenFunc = [device, cb](val)
{
- val tracks = mediaStream.call<val>("getTracks");
- if (!tracks.isUndefined() && !tracks.isNull())
- tracks[0].call<void>("stop");
updatePermission(device, wapiGranted, cb);
};
queryCallbacks.catchFunc = [device, cb](val error)
diff --git a/src/corelib/kernel/qpointer.h b/src/corelib/kernel/qpointer.h
index 2c82441164..39e4ba3e0f 100644
--- a/src/corelib/kernel/qpointer.h
+++ b/src/corelib/kernel/qpointer.h
@@ -18,15 +18,48 @@ class QPointer
{
static_assert(!std::is_pointer<T>::value, "QPointer's template type must not be a pointer type");
+ template <typename X>
+ using if_convertible = std::enable_if_t<std::is_convertible_v<X*, T*>, bool>;
+ template <typename X>
+ friend class QPointer;
+
using QObjectType =
typename std::conditional<std::is_const<T>::value, const QObject, QObject>::type;
QWeakPointer<QObjectType> wp;
public:
- QPointer() = default;
+ Q_NODISCARD_CTOR
+ QPointer() noexcept = default;
+ Q_NODISCARD_CTOR
+ constexpr QPointer(std::nullptr_t) noexcept : QPointer{} {}
+ Q_WEAK_OVERLOAD
+ Q_NODISCARD_CTOR
inline QPointer(T *p) : wp(p, true) { }
// compiler-generated copy/move ctor/assignment operators are fine!
// compiler-generated dtor is fine!
+ template <typename X, if_convertible<X> = true>
+ Q_NODISCARD_CTOR
+ QPointer(QPointer<X> &&other) noexcept
+ : wp(std::exchange(other.wp, nullptr).internalData(), true) {}
+ template <typename X, if_convertible<X> = true>
+ Q_NODISCARD_CTOR
+ QPointer(const QPointer<X> &other) noexcept
+ : wp(other.wp.internalData(), true) {}
+
+ template <typename X, if_convertible<X> = true>
+ QPointer &operator=(const QPointer<X> &other) noexcept
+ {
+ QPointer(other).swap(*this);
+ return *this;
+ }
+
+ template <typename X, if_convertible<X> = true>
+ QPointer &operator=(QPointer<X> &&other) noexcept
+ {
+ QPointer(std::move(other)).swap(*this);
+ return *this;
+ }
+
#ifdef Q_QDOC
// Stop qdoc from complaining about missing function
~QPointer();
@@ -37,27 +70,30 @@ public:
inline QPointer<T> &operator=(T* p)
{ wp.assign(static_cast<QObjectType*>(p)); return *this; }
- inline T* data() const
+ T* data() const noexcept
{ return static_cast<T*>(wp.internalData()); }
- inline T* get() const
+ T* get() const noexcept
{ return data(); }
- inline T* operator->() const
+ T* operator->() const noexcept
{ return data(); }
- inline T& operator*() const
+ T& operator*() const noexcept
{ return *data(); }
- inline operator T*() const
+ operator T*() const noexcept
{ return data(); }
- inline bool isNull() const
+ bool isNull() const noexcept
{ return wp.isNull(); }
- inline void clear()
+ void clear() noexcept
{ wp.clear(); }
+ friend void swap(QPointer &lhs, QPointer &rhs) noexcept
+ { lhs.swap(rhs); }
+
#define DECLARE_COMPARE_SET(T1, A1, T2, A2) \
- friend bool operator==(T1, T2) \
+ friend bool operator==(T1, T2) noexcept \
{ return A1 == A2; } \
- friend bool operator!=(T1, T2) \
+ friend bool operator!=(T1, T2) noexcept \
{ return A1 != A2; }
#define DECLARE_TEMPLATE_COMPARE_SET(T1, A1, T2, A2) \
@@ -86,10 +122,6 @@ qPointerFromVariant(const QVariant &variant)
return QPointer<T>{qobject_cast<T*>(QtPrivate::EnableInternalData::internalData(wp))};
}
-template <class T>
-inline void swap(QPointer<T> &p1, QPointer<T> &p2) noexcept
-{ p1.swap(p2); }
-
QT_END_NAMESPACE
#endif // QT_NO_QOBJECT
diff --git a/src/corelib/kernel/qpointer.cpp b/src/corelib/kernel/qpointer.qdoc
index aebdd68428..9e4c9b2658 100644
--- a/src/corelib/kernel/qpointer.cpp
+++ b/src/corelib/kernel/qpointer.qdoc
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\class QPointer
@@ -76,6 +76,7 @@
/*!
\fn template <class T> QPointer<T>::QPointer()
+ \fn template <class T> QPointer<T>::QPointer(std::nullptr_t)
Constructs a guarded pointer with value \nullptr.
@@ -98,6 +99,42 @@
*/
/*!
+ \fn template <class T> template <typename X, QPointer<T>::if_convertible<X> = true> QPointer<T>::QPointer(QPointer<X> &&other)
+ \fn template <class T> template <typename X, QPointer<T>::if_convertible<X> = true> QPointer<T>::QPointer(const QPointer<X> &other)
+ \since 6.6
+
+ Conversion constructor. Constructs a new QPointer by moving or copying from
+ \a other.
+
+ The moved-from QPointer is reset to nullptr.
+
+ \note These constructors participate in overload resolution only if \c{X*}
+ is convertible to \c{T*}.
+*/
+
+/*!
+ \fn template <class T> template <typename X, QPointer<T>::if_convertible<X> = true> QPointer<T> &QPointer<T>::operator=(const QPointer<X> &other)
+ \since 6.6
+
+ Conversion assignment operator. Makes this guarded pointer guard the
+ same object guarded by \a other.
+
+ \note This operator participates in overload resolution only if \c{X*}
+ is convertible to \c{T*}.
+*/
+
+/*!
+ \fn template <class T> template <typename X, QPointer<T>::if_convertible<X> = true> &QPointer<T>::operator=(QPointer<X> &&other)
+ \since 6.6.1
+
+ Conversion move-assignment operator. Makes this guarded pointer guard the
+ same object guarded by \a other and resets \a other to nullptr.
+
+ \note This operator participates in overload resolution only if \c{X*}
+ is convertible to \c{T*}.
+*/
+
+/*!
\fn template <class T> void QPointer<T>::swap(QPointer &other)
\since 5.6
@@ -165,7 +202,7 @@
*/
/*!
- \fn template <typename T, typename X> bool QPointer<T>::operator==(X *o, const QPointer<T> &p)
+ \fn template <typename T> template<typename X> bool QPointer<T>::operator==(X *o, const QPointer<T> &p)
Equality operator. Returns \c true if \a o and the guarded
pointer \a p are pointing to the same object, otherwise
@@ -173,7 +210,7 @@
*/
/*!
- \fn template <typename T, typename X> bool QPointer<T>::operator==(const QPointer<T> &p, X *o)
+ \fn template <typename T> template<typename X> bool QPointer<T>::operator==(const QPointer<T> &p, X *o)
Equality operator. Returns \c true if \a o and the guarded
pointer \a p are pointing to the same object, otherwise
@@ -181,7 +218,7 @@
*/
/*!
- \fn template <typename T, typename X> bool QPointer<T>::operator==(const QPointer<T> &p1, const QPointer<X> &p2)
+ \fn template <typename T> template<typename X> bool QPointer<T>::operator==(const QPointer<T> &p1, const QPointer<X> &p2)
Equality operator. Returns \c true if the guarded pointers \a p1 and \a p2
are pointing to the same object, otherwise
@@ -204,21 +241,21 @@
*/
/*!
- \fn template <typename T, typename X> bool QPointer<T>::operator!=(const QPointer<T> &p, X *o)
+ \fn template <typename T> template<typename X> bool QPointer<T>::operator!=(const QPointer<T> &p, X *o)
Inequality operator. Returns \c true if \a o and the guarded
pointer \a p are not pointing to the same object, otherwise
returns \c false.
*/
/*!
- \fn template <typename T, typename X> bool QPointer<T>::operator!=(X *o, const QPointer<T> &p)
+ \fn template <typename T> template<typename X> bool QPointer<T>::operator!=(X *o, const QPointer<T> &p)
Inequality operator. Returns \c true if \a o and the guarded
pointer \a p are not pointing to the same object, otherwise
returns \c false.
*/
/*!
- \fn template <typename T, typename X> bool QPointer<T>::operator!=(const QPointer<T> &p1, const QPointer<X> &p2)
+ \fn template <typename T> template<typename X> bool QPointer<T>::operator!=(const QPointer<T> &p1, const QPointer<X> &p2)
Inequality operator. Returns \c true if the guarded pointers \a p1 and
\a p2 are not pointing to the same object, otherwise
diff --git a/src/corelib/kernel/qpoll.cpp b/src/corelib/kernel/qpoll.cpp
index bbd197f292..58fb0234b4 100644
--- a/src/corelib/kernel/qpoll.cpp
+++ b/src/corelib/kernel/qpoll.cpp
@@ -54,7 +54,7 @@ static inline void qt_poll_examine_ready_read(struct pollfd &pfd)
int res;
char data;
- EINTR_LOOP(res, ::recv(pfd.fd, &data, sizeof(data), MSG_PEEK));
+ QT_EINTR_LOOP(res, ::recv(pfd.fd, &data, sizeof(data), MSG_PEEK));
const int error = (res < 0) ? errno : 0;
if (res == 0) {
@@ -109,7 +109,7 @@ static inline bool qt_poll_is_bad_fd(int fd)
#endif
int ret;
- EINTR_LOOP(ret, fcntl(fd, F_GETFD));
+ QT_EINTR_LOOP(ret, fcntl(fd, F_GETFD));
return (ret == -1 && errno == EBADF);
}
diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp
index cfb289fc1b..caa9fce787 100644
--- a/src/corelib/kernel/qproperty.cpp
+++ b/src/corelib/kernel/qproperty.cpp
@@ -27,9 +27,9 @@ void QPropertyBindingPrivatePtr::reset(QtPrivate::RefCounted *ptr) noexcept
{
if (ptr != d) {
if (ptr)
- ptr->ref++;
+ ptr->addRef();
auto *old = std::exchange(d, ptr);
- if (old && (--old->ref == 0))
+ if (old && !old->deref())
QPropertyBindingPrivate::destroyAndFreeMemory(static_cast<QPropertyBindingPrivate *>(d));
}
}
@@ -310,7 +310,7 @@ void QPropertyBindingPrivate::unlinkAndDeref()
{
clearDependencyObservers();
propertyDataPtr = nullptr;
- if (--ref == 0)
+ if (!deref())
destroyAndFreeMemory(this);
}
@@ -455,7 +455,7 @@ QPropertyBindingError QUntypedPropertyBinding::error() const
/*!
Returns the meta-type of the binding.
- If the QUntypedProperyBinding is null, an invalid QMetaType is returned.
+ If the QUntypedPropertyBinding is null, an invalid QMetaType is returned.
*/
QMetaType QUntypedPropertyBinding::valueMetaType() const
{
@@ -603,6 +603,11 @@ void QPropertyBindingData::registerWithCurrentlyEvaluatingBinding_helper(Binding
{
QPropertyBindingDataPointer d{this};
+ if (currentState->alreadyCaptureProperties.contains(this))
+ return;
+ else
+ currentState->alreadyCaptureProperties.push_back(this);
+
QPropertyObserverPointer dependencyObserver = currentState->binding->allocateDependencyObserver();
Q_ASSERT(QPropertyObserver::ObserverNotifiesBinding == 0);
dependencyObserver.setBindingToNotify_unsafe(currentState->binding);
@@ -673,8 +678,10 @@ QPropertyObserver::QPropertyObserver(ChangeHandler changeHandler)
#if QT_DEPRECATED_SINCE(6, 6)
QPropertyObserver::QPropertyObserver(QUntypedPropertyData *data)
{
+ QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
aliasData = data;
next.setTag(ObserverIsAlias);
+ QT_WARNING_POP
}
#endif
@@ -746,13 +753,6 @@ void QPropertyObserverPointer::setChangeHandler(QPropertyObserver::ChangeHandler
ptr->next.setTag(QPropertyObserver::ObserverNotifiesChangeHandler);
}
-void QPropertyObserverPointer::setBindingToNotify(QPropertyBindingPrivate *binding)
-{
- Q_ASSERT(ptr->next.tag() != QPropertyObserver::ObserverIsPlaceholder);
- ptr->binding = binding;
- ptr->next.setTag(QPropertyObserver::ObserverNotifiesBinding);
-}
-
/*!
\internal
The same as setBindingToNotify, but assumes that the tag is already correct.
@@ -1185,13 +1185,20 @@ QString QPropertyBindingError::description() const
usable directly without reading through a QBindable use \l QProperty or
\l QObjectBindableProperty.
+ \code
+ QProperty<QString> displayText;
+ QDateTimeEdit *dateTimeEdit = findDateTimeEdit();
+ QBindable<QDateTime> dateTimeBindable(dateTimeEdit, "dateTime");
+ displayText.setBinding([dateTimeBindable](){ return dateTimeBindable.value().toString(); });
+ \endcode
+
\sa QProperty, QObjectBindableProperty, {Qt Bindable Properties}
*/
/*!
\fn template<typename T> QBindable<T>::QBindable(QObject *obj, const QMetaProperty &property)
- See \c \l QBindable::QBindable(QObject *obj, const char *property)
+ See \l QBindable::QBindable(QObject *obj, const char *property)
*/
/*!
@@ -1273,15 +1280,13 @@ QString QPropertyBindingError::description() const
can be used to express relationships between different properties in your
application.
- \note In the case of QML it is important that \l QProperty needs to be exposed
- in \l Q_PROPERTY with the BINDABLE keyword. As a result the QML engine, uses it
- as the bindable interface to set up the property binding. In turn, the binding
- can be then interacted with C++ via the normal API like:
-
+ \note For QML, it's important to expose the \l QProperty in \l Q_PROPERTY
+ with the BINDABLE keyword. As a result, the QML engine uses
+ it as the bindable interface to set up the property binding. In turn, the
+ binding can then be interacted with C++ via the normal API:
QProperty<T>::onValueChanged, QProperty::takeBinding and QBindable::hasBinding
-
- If the property is BINDABLE, then the engine will use the change-tracking
- inherent to the C++ property system for getting notified about changes; and
+ If the property is BINDABLE, the engine will use the change-tracking
+ inherent to the C++ property system for getting notified about changes, and it
won't rely on signals being emitted.
*/
@@ -2472,8 +2477,13 @@ QPropertyAdaptorSlotObject::QPropertyAdaptorSlotObject(QObject *o, const QMetaPr
{
}
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
void QPropertyAdaptorSlotObject::impl(int which, QSlotObjectBase *this_, QObject *r, void **a,
bool *ret)
+#else
+void QPropertyAdaptorSlotObject::impl(QSlotObjectBase *this_, QObject *r, void **a, int which,
+ bool *ret)
+#endif
{
auto self = static_cast<QPropertyAdaptorSlotObject *>(this_);
switch (which) {
diff --git a/src/corelib/kernel/qproperty.h b/src/corelib/kernel/qproperty.h
index e45d532fb9..0373867a66 100644
--- a/src/corelib/kernel/qproperty.h
+++ b/src/corelib/kernel/qproperty.h
@@ -53,10 +53,11 @@ Q_CORE_EXPORT void beginPropertyUpdateGroup();
Q_CORE_EXPORT void endPropertyUpdateGroup();
}
-class [[nodiscard]] QScopedPropertyUpdateGroup
+class QScopedPropertyUpdateGroup
{
Q_DISABLE_COPY_MOVE(QScopedPropertyUpdateGroup)
public:
+ Q_NODISCARD_CTOR
QScopedPropertyUpdateGroup()
{ Qt::beginPropertyUpdateGroup(); }
~QScopedPropertyUpdateGroup() noexcept(false)
@@ -228,7 +229,7 @@ public:
ObserverNotifiesChangeHandler, // observer is a change handler, which runs on every change
ObserverIsPlaceholder, // the observer before this one is currently evaluated in QPropertyObserver::notifyObservers.
#if QT_DEPRECATED_SINCE(6, 6)
- ObserverIsAlias
+ ObserverIsAlias QT_DEPRECATED_VERSION_X_6_6("Use QProperty and add a binding to the target.")
#endif
};
protected:
@@ -262,7 +263,7 @@ public:
QPropertyObserver &operator=(QPropertyObserver &&other) noexcept;
~QPropertyObserver();
- template<typename Property, typename = typename Property::InheritsQUntypedPropertyData>
+ template <typename Property, QtPrivate::IsUntypedPropertyData<Property> = true>
void setSource(const Property &property)
{ setSource(property.bindingData()); }
void setSource(const QtPrivate::QPropertyBindingData &property);
@@ -270,7 +271,8 @@ public:
protected:
QPropertyObserver(ChangeHandler changeHandler);
#if QT_DEPRECATED_SINCE(6, 6)
- QT_DEPRECATED QPropertyObserver(QUntypedPropertyData *aliasedPropertyPtr);
+ QT_DEPRECATED_VERSION_X_6_6("This constructor was only meant for internal use. Use QProperty and add a binding to the target.")
+ QPropertyObserver(QUntypedPropertyData *aliasedPropertyPtr);
#endif
QUntypedPropertyData *aliasedProperty() const
@@ -286,10 +288,11 @@ private:
};
template <typename Functor>
-class [[nodiscard]] QPropertyChangeHandler : public QPropertyObserver
+class QPropertyChangeHandler : public QPropertyObserver
{
Functor m_handler;
public:
+ Q_NODISCARD_CTOR
QPropertyChangeHandler(Functor handler)
: QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {
auto This = static_cast<QPropertyChangeHandler<Functor>*>(self);
@@ -299,7 +302,8 @@ public:
{
}
- template<typename Property, typename = typename Property::InheritsQUntypedPropertyData>
+ template <typename Property, QtPrivate::IsUntypedPropertyData<Property> = true>
+ Q_NODISCARD_CTOR
QPropertyChangeHandler(const Property &property, Functor handler)
: QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {
auto This = static_cast<QPropertyChangeHandler<Functor>*>(self);
@@ -311,12 +315,14 @@ public:
}
};
-class [[nodiscard]] QPropertyNotifier : public QPropertyObserver
+class QPropertyNotifier : public QPropertyObserver
{
std::function<void()> m_handler;
public:
+ Q_NODISCARD_CTOR
QPropertyNotifier() = default;
template<typename Functor>
+ Q_NODISCARD_CTOR
QPropertyNotifier(Functor handler)
: QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {
auto This = static_cast<QPropertyNotifier *>(self);
@@ -326,7 +332,9 @@ public:
{
}
- template<typename Functor, typename Property, typename = typename Property::InheritsQUntypedPropertyData>
+ template <typename Functor, typename Property,
+ QtPrivate::IsUntypedPropertyData<Property> = true>
+ Q_NODISCARD_CTOR
QPropertyNotifier(const Property &property, Functor handler)
: QPropertyObserver([](QPropertyObserver *self, QUntypedPropertyData *) {
auto This = static_cast<QPropertyNotifier *>(self);
@@ -883,7 +891,7 @@ public:
#if QT_DEPRECATED_SINCE(6, 6)
template<typename T>
-class QT_DEPRECATED_X("Class was only meant for internal use, use a QProperty and add a binding to the target")
+class QT_DEPRECATED_VERSION_X_6_6("Class was only meant for internal use, use a QProperty and add a binding to the target")
QPropertyAlias : public QPropertyObserver
{
Q_DISABLE_COPY_MOVE(QPropertyAlias)
@@ -899,7 +907,7 @@ public:
iface->setObserver(aliasedProperty(), this);
}
- template<typename Property, typename = typename Property::InheritsQUntypedPropertyData>
+ template <typename Property, QtPrivate::IsUntypedPropertyData<Property> = true>
QPropertyAlias(Property *property)
: QPropertyObserver(property),
iface(&QtPrivate::QBindableInterfaceForProperty<Property>::iface)
@@ -1008,7 +1016,7 @@ public:
}
QT_WARNING_POP
};
-#endif
+#endif // QT_DEPRECATED_SINCE(6, 6)
template<typename Class, typename T, auto Offset, auto Signal = nullptr>
class QObjectBindableProperty : public QPropertyData<T>
diff --git a/src/corelib/kernel/qproperty_p.h b/src/corelib/kernel/qproperty_p.h
index dbf5535143..8ae6664a2b 100644
--- a/src/corelib/kernel/qproperty_p.h
+++ b/src/corelib/kernel/qproperty_p.h
@@ -94,11 +94,12 @@ struct QPropertyBindingDataPointer
}
};
-struct [[nodiscard]] QPropertyObserverNodeProtector
+struct QPropertyObserverNodeProtector
{
Q_DISABLE_COPY_MOVE(QPropertyObserverNodeProtector)
QPropertyObserverBase m_placeHolder;
+ Q_NODISCARD_CTOR
QPropertyObserverNodeProtector(QPropertyObserver *observer)
{
// insert m_placeholder after observer into the linked list
@@ -125,20 +126,30 @@ struct QPropertyObserverPointer
{
unlink_common();
#if QT_DEPRECATED_SINCE(6, 6)
+ QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
if (ptr->next.tag() == QPropertyObserver::ObserverIsAlias)
ptr->aliasData = nullptr;
+ QT_WARNING_POP
#endif
}
void unlink_fast()
{
#if QT_DEPRECATED_SINCE(6, 6)
+ QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
Q_ASSERT(ptr->next.tag() != QPropertyObserver::ObserverIsAlias);
+ QT_WARNING_POP
#endif
unlink_common();
}
- void setBindingToNotify(QPropertyBindingPrivate *binding);
+ void setBindingToNotify(QPropertyBindingPrivate *binding)
+ {
+ Q_ASSERT(ptr->next.tag() != QPropertyObserver::ObserverIsPlaceholder);
+ ptr->binding = binding;
+ ptr->next.setTag(QPropertyObserver::ObserverNotifiesBinding);
+ }
+
void setBindingToNotify_unsafe(QPropertyBindingPrivate *binding);
void setChangeHandler(QPropertyObserver::ChangeHandler changeHandler);
@@ -161,7 +172,7 @@ struct QPropertyObserverPointer
{
Q_ASSERT(ptr->next.tag() == QPropertyObserver::ObserverNotifiesBinding);
return ptr->binding;
- };
+ }
private:
void unlink_common()
@@ -195,6 +206,7 @@ struct BindingEvaluationState
QPropertyBindingPrivate *binding;
BindingEvaluationState *previousState = nullptr;
BindingEvaluationState **currentState = nullptr;
+ QVarLengthArray<const QPropertyBindingData *, 8> alreadyCaptureProperties;
};
/*!
@@ -219,6 +231,33 @@ struct CompatPropertySafePoint
QtPrivate::BindingEvaluationState *bindingState = nullptr;
};
+/*!
+ * \internal
+ * While the regular QProperty notification for a compat property runs we
+ * don't want to have any currentCompatProperty set. This would be a _different_
+ * one than the one we are current evaluating. Therefore it's misleading and
+ * prevents the registering of actual dependencies.
+ */
+struct CurrentCompatPropertyThief
+{
+ Q_DISABLE_COPY_MOVE(CurrentCompatPropertyThief)
+public:
+ CurrentCompatPropertyThief(QBindingStatus *status)
+ : status(&status->currentCompatProperty)
+ , stolen(std::exchange(status->currentCompatProperty, nullptr))
+ {
+ }
+
+ ~CurrentCompatPropertyThief()
+ {
+ *status = stolen;
+ }
+
+private:
+ CompatPropertySafePoint **status = nullptr;
+ CompatPropertySafePoint *stolen = nullptr;
+};
+
}
class Q_CORE_EXPORT QPropertyBindingPrivate : public QtPrivate::RefCounted
@@ -487,13 +526,16 @@ class QObjectCompatProperty : public QPropertyData<T>
static bool bindingWrapper(QMetaType type, QUntypedPropertyData *dataPtr, QtPrivate::QPropertyBindingFunction binding)
{
auto *thisData = static_cast<ThisType *>(dataPtr);
+ QBindingStorage *storage = qGetBindingStorage(thisData->owner());
QPropertyData<T> copy;
- binding.vtable->call(type, &copy, binding.functor);
- if constexpr (QTypeTraits::has_operator_equal_v<T>)
- if (copy.valueBypassingBindings() == thisData->valueBypassingBindings())
- return false;
+ {
+ QtPrivate::CurrentCompatPropertyThief thief(storage->bindingStatus);
+ binding.vtable->call(type, &copy, binding.functor);
+ if constexpr (QTypeTraits::has_operator_equal_v<T>)
+ if (copy.valueBypassingBindings() == thisData->valueBypassingBindings())
+ return false;
+ }
// ensure value and setValue know we're currently evaluating our binding
- QBindingStorage *storage = qGetBindingStorage(thisData->owner());
QtPrivate::CompatPropertySafePoint guardThis(storage->bindingStatus, thisData);
(thisData->owner()->*Setter)(copy.valueBypassingBindings());
return true;
@@ -882,8 +924,10 @@ inline void QPropertyObserverPointer::notify(QUntypedPropertyData *propertyDataP
// recursion is already properly handled somewhere else
break;
#if QT_DEPRECATED_SINCE(6, 6)
+ QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
case QPropertyObserver::ObserverIsAlias:
break;
+ QT_WARNING_POP
#endif
default: Q_UNREACHABLE();
}
@@ -903,7 +947,15 @@ QBindingObserverPtr::QBindingObserverPtr(QPropertyObserver *observer) noexcept :
QPropertyObserverPointer{d}.binding()->addRef();
}
-QBindingObserverPtr::~QBindingObserverPtr() { if (d) QPropertyObserverPointer{d}.binding()->deref(); }
+QBindingObserverPtr::~QBindingObserverPtr()
+{
+ if (!d)
+ return;
+
+ QPropertyBindingPrivate *bindingPrivate = binding();
+ if (!bindingPrivate->deref())
+ QPropertyBindingPrivate::destroyAndFreeMemory(bindingPrivate);
+}
QPropertyBindingPrivate *QBindingObserverPtr::binding() const noexcept { return QPropertyObserverPointer{d}.binding(); }
@@ -916,7 +968,11 @@ class QPropertyAdaptorSlotObject : public QUntypedPropertyData, public QSlotObje
QObject *obj;
QMetaProperty metaProperty_;
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
static void impl(int which, QSlotObjectBase *this_, QObject *r, void **a, bool *ret);
+#else
+ static void impl(QSlotObjectBase *this_, QObject *r, void **a, int which, bool *ret);
+#endif
QPropertyAdaptorSlotObject(QObject *o, const QMetaProperty& p);
diff --git a/src/corelib/kernel/qpropertyprivate.h b/src/corelib/kernel/qpropertyprivate.h
index aca6d14c96..86dc08a6bc 100644
--- a/src/corelib/kernel/qpropertyprivate.h
+++ b/src/corelib/kernel/qpropertyprivate.h
@@ -36,9 +36,13 @@ namespace QtPrivate {
// QPropertyBindingPrivatePtr operates on a RefCountingMixin solely so that we can inline
// the constructor and copy constructor
struct RefCounted {
+
+ int refCount() const { return ref; }
+ void addRef() { ++ref; }
+ bool deref() { return --ref != 0; }
+
+private:
int ref = 0;
- void addRef() {++ref;}
- bool deref() {--ref; return ref;}
};
}
@@ -61,7 +65,7 @@ public:
QPropertyBindingPrivatePtr() noexcept : d(nullptr) { }
~QPropertyBindingPrivatePtr()
{
- if (d && (--d->ref == 0))
+ if (d && !d->deref())
destroyAndFreeMemory();
}
Q_CORE_EXPORT void destroyAndFreeMemory();
@@ -124,11 +128,13 @@ struct QPropertyObserverPointer;
class QUntypedPropertyData
{
-public:
- // sentinel to check whether a class inherits QUntypedPropertyData
- struct InheritsQUntypedPropertyData {};
};
+namespace QtPrivate {
+template <typename T>
+using IsUntypedPropertyData = std::enable_if_t<std::is_base_of_v<QUntypedPropertyData, T>, bool>;
+}
+
template <typename T>
class QPropertyData;
diff --git a/src/corelib/kernel/qsignalmapper.cpp b/src/corelib/kernel/qsignalmapper.cpp
index 2a3b8149d1..65d766db4a 100644
--- a/src/corelib/kernel/qsignalmapper.cpp
+++ b/src/corelib/kernel/qsignalmapper.cpp
@@ -13,11 +13,6 @@ class QSignalMapperPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QSignalMapper)
public:
- void _q_senderDestroyed()
- {
- Q_Q(QSignalMapper);
- q->removeMappings(q->sender());
- }
template <class Signal, class Container>
void emitMappedValue(QObject *sender, Signal signal, const Container &mappedValues)
@@ -129,7 +124,7 @@ void QSignalMapper::setMapping(QObject *sender, int id)
{
Q_D(QSignalMapper);
d->intHash.insert(sender, id);
- connect(sender, SIGNAL(destroyed()), this, SLOT(_q_senderDestroyed()));
+ connect(sender, &QObject::destroyed, this, &QSignalMapper::removeMappings);
}
/*!
@@ -142,7 +137,7 @@ void QSignalMapper::setMapping(QObject *sender, const QString &text)
{
Q_D(QSignalMapper);
d->stringHash.insert(sender, text);
- connect(sender, SIGNAL(destroyed()), this, SLOT(_q_senderDestroyed()));
+ connect(sender, &QObject::destroyed, this, &QSignalMapper::removeMappings);
}
/*!
@@ -155,7 +150,7 @@ void QSignalMapper::setMapping(QObject *sender, QObject *object)
{
Q_D(QSignalMapper);
d->objectHash.insert(sender, object);
- connect(sender, SIGNAL(destroyed()), this, SLOT(_q_senderDestroyed()));
+ connect(sender, &QObject::destroyed, this, &QSignalMapper::removeMappings);
}
/*!
diff --git a/src/corelib/kernel/qsignalmapper.h b/src/corelib/kernel/qsignalmapper.h
index 3c3005dabd..af0be52ee5 100644
--- a/src/corelib/kernel/qsignalmapper.h
+++ b/src/corelib/kernel/qsignalmapper.h
@@ -38,7 +38,6 @@ public Q_SLOTS:
private:
Q_DISABLE_COPY(QSignalMapper)
- Q_PRIVATE_SLOT(d_func(), void _q_senderDestroyed())
};
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qsingleshottimer_p.h b/src/corelib/kernel/qsingleshottimer_p.h
new file mode 100644
index 0000000000..dd1402f63a
--- /dev/null
+++ b/src/corelib/kernel/qsingleshottimer_p.h
@@ -0,0 +1,141 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSINGLESHOTTIMER_P_H
+#define QSINGLESHOTTIMER_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 "qabstracteventdispatcher.h"
+#include "qcoreapplication.h"
+#include "qmetaobject_p.h"
+#include "private/qnumeric_p.h"
+
+#include <chrono>
+
+QT_BEGIN_NAMESPACE
+
+class QSingleShotTimer : public QObject
+{
+ Q_OBJECT
+
+ Qt::TimerId timerId = Qt::TimerId::Invalid;
+
+public:
+ // use the same duration type
+ using Duration = QAbstractEventDispatcher::Duration;
+
+ inline ~QSingleShotTimer();
+ inline QSingleShotTimer(Duration interval, Qt::TimerType timerType,
+ const QObject *r, const char *member);
+ inline QSingleShotTimer(Duration interval, Qt::TimerType timerType,
+ const QObject *r, QtPrivate::QSlotObjectBase *slotObj);
+
+ inline void startTimerForReceiver(Duration interval, Qt::TimerType timerType,
+ const QObject *receiver);
+
+ static Duration fromMsecs(std::chrono::milliseconds ms)
+ {
+ using namespace std::chrono;
+ using ratio = std::ratio_divide<std::milli, Duration::period>;
+ static_assert(ratio::den == 1);
+
+ Duration::rep r;
+ if (qMulOverflow<ratio::num>(ms.count(), &r)) {
+ qWarning("QTimer::singleShot(std::chrono::milliseconds, ...): "
+ "interval argument overflowed when converted to nanoseconds.");
+ return Duration::max();
+ }
+ return Duration{r};
+ }
+Q_SIGNALS:
+ void timeout();
+
+private:
+ inline void timerEvent(QTimerEvent *) override;
+};
+
+QSingleShotTimer::QSingleShotTimer(Duration interval, Qt::TimerType timerType,
+ const QObject *r, const char *member)
+ : QObject(QAbstractEventDispatcher::instance())
+{
+ connect(this, SIGNAL(timeout()), r, member);
+ startTimerForReceiver(interval, timerType, r);
+}
+
+QSingleShotTimer::QSingleShotTimer(Duration interval, Qt::TimerType timerType,
+ const QObject *r, QtPrivate::QSlotObjectBase *slotObj)
+ : QObject(QAbstractEventDispatcher::instance())
+{
+ int signal_index = QMetaObjectPrivate::signalOffset(&staticMetaObject);
+ Q_ASSERT(QMetaObjectPrivate::signal(&staticMetaObject, signal_index).name() == "timeout");
+ QObjectPrivate::connectImpl(this, signal_index, r ? r : this, nullptr, slotObj,
+ Qt::AutoConnection, nullptr, &staticMetaObject);
+
+ startTimerForReceiver(interval, timerType, r);
+}
+
+QSingleShotTimer::~QSingleShotTimer()
+{
+ if (timerId > Qt::TimerId::Invalid)
+ killTimer(timerId);
+}
+
+/*
+ Move the timer, and the dispatching and handling of the timer event, into
+ the same thread as where it will be handled, so that it fires reliably even
+ if the thread that set up the timer is busy.
+*/
+void QSingleShotTimer::startTimerForReceiver(Duration interval, Qt::TimerType timerType,
+ const QObject *receiver)
+{
+ if (receiver && receiver->thread() != thread()) {
+ // Avoid leaking the QSingleShotTimer instance in case the application exits before the
+ // timer fires
+ connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this,
+ &QObject::deleteLater);
+ setParent(nullptr);
+ moveToThread(receiver->thread());
+
+ QDeadlineTimer deadline(interval, timerType);
+ auto invokable = [this, deadline, timerType] {
+ if (deadline.hasExpired()) {
+ Q_EMIT timeout();
+ } else {
+ timerId = Qt::TimerId{startTimer(deadline.remainingTimeAsDuration(), timerType)};
+ }
+ };
+ QMetaObject::invokeMethod(this, invokable, Qt::QueuedConnection);
+ } else {
+ timerId = Qt::TimerId{startTimer(interval, timerType)};
+ }
+}
+
+void QSingleShotTimer::timerEvent(QTimerEvent *)
+{
+ // need to kill the timer _before_ we emit timeout() in case the
+ // slot connected to timeout calls processEvents()
+ if (timerId > Qt::TimerId::Invalid)
+ killTimer(std::exchange(timerId, Qt::TimerId::Invalid));
+
+ Q_EMIT timeout();
+
+ // we would like to use delete later here, but it feels like a
+ // waste to post a new event to handle this event, so we just unset the flag
+ // and explicitly delete...
+ delete this;
+}
+
+QT_END_NAMESPACE
+
+#endif // QSINGLESHOTTIMER_P_H
diff --git a/src/corelib/kernel/qsocketnotifier.cpp b/src/corelib/kernel/qsocketnotifier.cpp
index 4c5b3812a0..4e4cf3666b 100644
--- a/src/corelib/kernel/qsocketnotifier.cpp
+++ b/src/corelib/kernel/qsocketnotifier.cpp
@@ -16,6 +16,7 @@
#include <private/qthread_p.h>
#include <QtCore/QLoggingCategory>
+#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
diff --git a/src/corelib/kernel/qsystemerror_p.h b/src/corelib/kernel/qsystemerror_p.h
index 66c434cb13..72ced63dc5 100644
--- a/src/corelib/kernel/qsystemerror_p.h
+++ b/src/corelib/kernel/qsystemerror_p.h
@@ -40,12 +40,19 @@ public:
constexpr ErrorScope scope() const { return errorScope; }
constexpr int error() const { return errorCode; }
+ constexpr bool ok() const noexcept { return errorScope == NoError; }
+ static constexpr QSystemError stdError(int error)
+ { return QSystemError(error, StandardLibraryError); }
+
static Q_CORE_EXPORT QString string(ErrorScope errorScope, int errorCode);
static Q_CORE_EXPORT QString stdString(int errorCode = -1);
#ifdef Q_OS_WIN
static Q_CORE_EXPORT QString windowsString(int errorCode = -1);
using HRESULT = long;
static Q_CORE_EXPORT QString windowsComString(HRESULT hr);
+
+ static constexpr QSystemError nativeError(int error)
+ { return QSystemError(error, NativeError); }
#endif
// data members
diff --git a/src/corelib/kernel/qt_attribution.json b/src/corelib/kernel/qt_attribution.json
index c3075c0a52..86ca3a2664 100644
--- a/src/corelib/kernel/qt_attribution.json
+++ b/src/corelib/kernel/qt_attribution.json
@@ -5,7 +5,7 @@
"QtUsage": "Used in Qt Core on macOS.",
"Files": "qeventdispatcher_cf_p.h",
- "Description": "Treat as final version; no upstream known",
+ "Comment": "Treat as final version; no upstream known",
"Description": "Implementation of QAbstractEventDispatcher for macOS.",
"License": "BSD 3-clause \"New\" or \"Revised\" License",
"LicenseId": "BSD-3-Clause",
diff --git a/src/corelib/kernel/qtestsupport_core.cpp b/src/corelib/kernel/qtestsupport_core.cpp
index 3fa7f346be..2ac44bb13d 100644
--- a/src/corelib/kernel/qtestsupport_core.cpp
+++ b/src/corelib/kernel/qtestsupport_core.cpp
@@ -3,61 +3,101 @@
#include "qtestsupport_core.h"
-#ifdef Q_OS_WIN
-#include <qt_windows.h>
-#endif
+#include <thread>
+
+using namespace std::chrono_literals;
QT_BEGIN_NAMESPACE
/*!
- Sleeps for \a ms milliseconds, blocking execution of the
- test. qSleep() will not do any event processing and leave your test
- unresponsive. Network communication might time out while
- sleeping. Use \l {QTest::qWait()} to do non-blocking sleeping.
+ \overload
+
+ Sleeps for \a ms milliseconds, blocking execution of the test.
+
+ Equivalent to calling:
+ \code
+ QTest::qSleep(std::chrono::milliseconds{ms});
+ \endcode
+*/
+void QTest::qSleep(int ms)
+{
+ QTest::qSleep(std::chrono::milliseconds{ms});
+}
+
+/*!
+ \since 6.7
- \a ms must be greater than 0.
+ Sleeps for \a msecs, blocking execution of the test.
- \b {Note:} The qSleep() function calls either \c nanosleep() on
- unix or \c Sleep() on windows, so the accuracy of time spent in
- qSleep() depends on the operating system.
+ This method will not do any event processing and will leave your test
+ unresponsive. Network communication might time out while sleeping.
+ Use \l {QTest::qWait()} to do non-blocking sleeping.
+
+ \a msecs must be greater than 0ms.
+
+ \note Starting from Qt 6.7, this function is implemented using
+ \c {std::this_thread::sleep_for}, so the accuracy of time spent depends
+ on the Standard Library implementation. Before Qt 6.7 this function called
+ either \c nanosleep() on Unix or \c Sleep() on Windows, so the accuracy of
+ time spent in this function depended on the operating system.
Example:
\snippet code/src_qtestlib_qtestcase.cpp 23
\sa {QTest::qWait()}
*/
-Q_CORE_EXPORT void QTest::qSleep(int ms)
+void QTest::qSleep(std::chrono::milliseconds msecs)
{
- Q_ASSERT(ms > 0);
-
-#if defined(Q_OS_WIN)
- Sleep(uint(ms));
-#else
- struct timespec ts = { time_t(ms / 1000), (ms % 1000) * 1000 * 1000 };
- nanosleep(&ts, nullptr);
-#endif
+ Q_ASSERT(msecs > 0ms);
+ std::this_thread::sleep_for(msecs);
}
/*! \fn template <typename Functor> bool QTest::qWaitFor(Functor predicate, int timeout)
+ \since 5.10
+ \overload
+
Waits for \a timeout milliseconds or until the \a predicate returns true.
- Returns \c true if the \a predicate returned true at any point, otherwise returns \c false.
+ This is equivalent to calling:
+ \code
+ qWaitFor(predicate, QDeadlineTimer(timeout));
+ \endcode
+*/
+
+/*! \fn template <typename Functor> bool QTest::qWaitFor(Functor predicate, QDeadlineTimer deadline)
+ \since 6.7
+
+ Waits until \a deadline has expired, or until \a predicate returns true, whichever
+ happens first.
+
+ Returns \c true if \a predicate returned true at any point, otherwise returns \c false.
Example:
- \snippet code/src_corelib_kernel_qtestsupport_core_snippet.cpp 0
+ \snippet code/src_corelib_kernel_qtestsupport_core.cpp 2
The code above will wait for the object to become ready, for a
maximum of three seconds.
-
- \since 5.10
*/
+/*!
+ \overload
-/*! \fn void QTest::qWait(int ms)
+ Waits for \a msecs. Equivalent to calling:
+ \code
+ QTest::qWait(std::chrono::milliseconds{msecs});
+ \endcode
+*/
+Q_CORE_EXPORT void QTest::qWait(int msecs)
+{
+ qWait(std::chrono::milliseconds{msecs});
+}
- Waits for \a ms milliseconds. While waiting, events will be processed and
+/*!
+ \since 6.7
+
+ Waits for \a msecs. While waiting, events will be processed and
your test will stay responsive to user interface events or network communication.
Example:
@@ -69,7 +109,7 @@ Q_CORE_EXPORT void QTest::qSleep(int ms)
\sa QTest::qSleep(), QSignalSpy::wait()
*/
-Q_CORE_EXPORT void QTest::qWait(int ms)
+Q_CORE_EXPORT void QTest::qWait(std::chrono::milliseconds msecs)
{
// Ideally this method would be implemented in terms of qWaitFor(), with a
// predicate that always returns false, but qWaitFor() uses the 1-arg overload
@@ -79,17 +119,24 @@ Q_CORE_EXPORT void QTest::qWait(int ms)
Q_ASSERT(QCoreApplication::instance());
- QDeadlineTimer timer(ms, Qt::PreciseTimer);
- int remaining = ms;
+ using namespace std::chrono;
+
+ QDeadlineTimer deadline(msecs, Qt::PreciseTimer);
+
do {
- QCoreApplication::processEvents(QEventLoop::AllEvents, remaining);
+ QCoreApplication::processEvents(QEventLoop::AllEvents, deadline);
QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
- remaining = timer.remainingTime();
- if (remaining <= 0)
+
+ // If dealine is Forever, processEvents() has already looped forever
+ if (deadline.isForever())
break;
- QTest::qSleep(qMin(10, remaining));
- remaining = timer.remainingTime();
- } while (remaining > 0);
+
+ msecs = ceil<milliseconds>(deadline.remainingTimeAsDuration());
+ if (msecs == 0ms)
+ break;
+
+ QTest::qSleep(std::min(10ms, msecs));
+ } while (!deadline.hasExpired());
}
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qtestsupport_core.h b/src/corelib/kernel/qtestsupport_core.h
index c9505196a9..27265903af 100644
--- a/src/corelib/kernel/qtestsupport_core.h
+++ b/src/corelib/kernel/qtestsupport_core.h
@@ -6,28 +6,27 @@
#include <QtCore/qcoreapplication.h>
#include <QtCore/qdeadlinetimer.h>
-#include <QtCore/qthread.h>
+
+#include <chrono>
QT_BEGIN_NAMESPACE
namespace QTest {
Q_CORE_EXPORT void qSleep(int ms);
+Q_CORE_EXPORT void qSleep(std::chrono::milliseconds msecs);
template <typename Functor>
-[[nodiscard]] static bool qWaitFor(Functor predicate, int timeout = 5000)
+[[nodiscard]] bool
+qWaitFor(Functor predicate, QDeadlineTimer deadline = QDeadlineTimer(std::chrono::seconds{5}))
{
// We should not spin the event loop in case the predicate is already true,
// otherwise we might send new events that invalidate the predicate.
if (predicate())
return true;
- // qWait() is expected to spin the event loop, even when called with a small
- // timeout like 1ms, so we we can't use a simple while-loop here based on
- // the deadline timer not having timed out. Use do-while instead.
-
- int remaining = timeout;
- QDeadlineTimer deadline(remaining, Qt::PreciseTimer);
+ // qWait() is expected to spin the event loop at least once, even when
+ // called with a small timeout like 1ns.
do {
// We explicitly do not pass the remaining time to processEvents, as
@@ -42,17 +41,26 @@ template <typename Functor>
if (predicate())
return true;
- remaining = int(deadline.remainingTime());
- if (remaining > 0)
- qSleep(qMin(10, remaining));
- remaining = int(deadline.remainingTime());
- } while (remaining > 0);
+ using namespace std::chrono;
+
+ if (const auto remaining = deadline.remainingTimeAsDuration(); remaining > 0ns)
+ qSleep((std::min)(10ms, ceil<milliseconds>(remaining)));
+
+ } while (!deadline.hasExpired());
return predicate(); // Last chance
}
+template <typename Functor>
+[[nodiscard]] bool qWaitFor(Functor predicate, int timeout)
+{
+ return qWaitFor(predicate, QDeadlineTimer{timeout, Qt::PreciseTimer});
+}
+
Q_CORE_EXPORT void qWait(int ms);
+Q_CORE_EXPORT void qWait(std::chrono::milliseconds msecs);
+
} // namespace QTest
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp
index 9c074a064f..294369c1b3 100644
--- a/src/corelib/kernel/qtimer.cpp
+++ b/src/corelib/kernel/qtimer.cpp
@@ -4,15 +4,19 @@
#include "qtimer.h"
#include "qtimer_p.h"
+#include "qsingleshottimer_p.h"
#include "qabstracteventdispatcher.h"
#include "qcoreapplication.h"
#include "qcoreapplication_p.h"
+#include "qdeadlinetimer.h"
#include "qmetaobject_p.h"
#include "qobject_p.h"
#include "qproperty_p.h"
#include "qthread.h"
+using namespace std::chrono_literals;
+
QT_BEGIN_NAMESPACE
/*!
@@ -70,6 +74,13 @@ QT_BEGIN_NAMESPACE
more and more platforms, we expect that zero-millisecond
QTimer objects will gradually be replaced by \l{QThread}s.
+ \note Since Qt 6.7 this class is superseded by \l{QChronoTimer}.
+ The maximum interval QTimer supports is limited by the number of
+ milliseconds that would fit in an \c int (which is around 24 days);
+ whereas QChronoTimer stores its interval as \c std::chrono::nanoseconds
+ (which raises that limit to around 292 million years), that is, there is
+ less chance of integer overflow with QChronoTimer.
+
\section1 Accuracy and Timer Resolution
The accuracy of timers depends on the underlying operating system
@@ -106,7 +117,7 @@ QT_BEGIN_NAMESPACE
used; Qt tries to work around these limitations.
\sa QBasicTimer, QTimerEvent, QObject::timerEvent(), Timers,
- {Analog Clock}, {Tetrix Example}
+ {Analog Clock}
*/
/*!
@@ -114,8 +125,9 @@ QT_BEGIN_NAMESPACE
*/
QTimer::QTimer(QObject *parent)
- : QObject(*new QTimerPrivate, parent)
+ : QObject(*new QTimerPrivate(this), parent)
{
+ Q_ASSERT(d_func()->isQTimer);
}
@@ -125,7 +137,7 @@ QTimer::QTimer(QObject *parent)
QTimer::~QTimer()
{
- if (d_func()->id != QTimerPrivate::INV_TIMER) // stop running timer
+ if (d_func()->isActive()) // stop running timer
stop();
}
@@ -170,9 +182,21 @@ QBindable<bool> QTimer::bindableActive()
*/
int QTimer::timerId() const
{
- return d_func()->id;
+ auto v = qToUnderlying(id());
+ return v == 0 ? -1 : v;
}
+/*!
+ \since 6.8
+ Returns a Qt::TimerId representing the timer ID if the timer is running;
+ otherwise returns \c Qt::TimerId::Invalid.
+
+ \sa Qt::TimerId
+*/
+Qt::TimerId QTimer::id() const
+{
+ return d_func()->id;
+}
/*! \overload start()
@@ -186,10 +210,14 @@ int QTimer::timerId() const
void QTimer::start()
{
Q_D(QTimer);
- if (d->id != QTimerPrivate::INV_TIMER) // stop running timer
+ if (d->isActive()) // stop running timer
stop();
- d->id = QObject::startTimer(std::chrono::milliseconds{d->inter}, d->type);
- d->isActiveData.notify();
+
+ Qt::TimerId newId{ QObject::startTimer(d->inter * 1ms, d->type) }; // overflow impossible
+ if (newId > Qt::TimerId::Invalid) {
+ d->id = newId;
+ d->isActiveData.notify();
+ }
}
/*!
@@ -199,14 +227,28 @@ void QTimer::start()
If the timer is already running, it will be
\l{QTimer::stop()}{stopped} and restarted.
- If \l singleShot is true, the timer will be activated only once.
+ If \l singleShot is true, the timer will be activated only once. This is
+ equivalent to:
+
+ \code
+ timer.setInterval(msec);
+ timer.start();
+ \endcode
\note Keeping the event loop busy with a zero-timer is bound to
cause trouble and highly erratic behavior of the UI.
*/
void QTimer::start(int msec)
{
+ start(msec * 1ms);
+}
+
+void QTimer::start(std::chrono::milliseconds interval)
+{
Q_D(QTimer);
+ // This could be narrowing as the interval is stored in an `int` QProperty,
+ // and the type can't be changed in Qt6.
+ const int msec = interval.count();
const bool intervalChanged = msec != d->inter;
d->inter.setValue(msec);
start();
@@ -225,9 +267,9 @@ void QTimer::start(int msec)
void QTimer::stop()
{
Q_D(QTimer);
- if (d->id != QTimerPrivate::INV_TIMER) {
+ if (d->isActive()) {
QObject::killTimer(d->id);
- d->id = QTimerPrivate::INV_TIMER;
+ d->id = Qt::TimerId::Invalid;
d->isActiveData.notify();
}
}
@@ -239,76 +281,13 @@ void QTimer::stop()
void QTimer::timerEvent(QTimerEvent *e)
{
Q_D(QTimer);
- if (e->timerId() == d->id) {
+ if (Qt::TimerId{e->timerId()} == d->id) {
if (d->single)
stop();
emit timeout(QPrivateSignal());
}
}
-class QSingleShotTimer : public QObject
-{
- Q_OBJECT
- int timerId;
-public:
- ~QSingleShotTimer();
- QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r, const char * m);
- QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r, QtPrivate::QSlotObjectBase *slotObj);
-
-Q_SIGNALS:
- void timeout();
-protected:
- void timerEvent(QTimerEvent *) override;
-};
-
-QSingleShotTimer::QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r, const char *member)
- : QObject(QAbstractEventDispatcher::instance())
-{
- timerId = startTimer(std::chrono::milliseconds{msec}, timerType);
- connect(this, SIGNAL(timeout()), r, member);
-}
-
-QSingleShotTimer::QSingleShotTimer(int msec, Qt::TimerType timerType, const QObject *r, QtPrivate::QSlotObjectBase *slotObj)
- : QObject(QAbstractEventDispatcher::instance())
-{
- timerId = startTimer(std::chrono::milliseconds{msec}, timerType);
-
- int signal_index = QMetaObjectPrivate::signalOffset(&staticMetaObject);
- Q_ASSERT(QMetaObjectPrivate::signal(&staticMetaObject, signal_index).name() == "timeout");
- QObjectPrivate::connectImpl(this, signal_index, r ? r : this, nullptr, slotObj,
- Qt::AutoConnection, nullptr, &staticMetaObject);
-
- // ### Why is this here? Why doesn't the case above need it?
- if (r && thread() != r->thread()) {
- // Avoid leaking the QSingleShotTimer instance in case the application exits before the timer fires
- connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &QObject::deleteLater);
- setParent(nullptr);
- moveToThread(r->thread());
- }
-}
-
-QSingleShotTimer::~QSingleShotTimer()
-{
- if (timerId > 0)
- killTimer(timerId);
-}
-
-void QSingleShotTimer::timerEvent(QTimerEvent *)
-{
- // need to kill the timer _before_ we emit timeout() in case the
- // slot connected to timeout calls processEvents()
- if (timerId > 0)
- killTimer(timerId);
- timerId = -1;
-
- emit timeout();
-
- // we would like to use delete later here, but it feels like a
- // waste to post a new event to handle this event, so we just unset the flag
- // and explicitly delete...
- qDeleteInEventHandler(this);
-}
-
/*!
\internal
@@ -318,14 +297,13 @@ void QSingleShotTimer::timerEvent(QTimerEvent *)
\a timerType is the timer type
\a receiver is the receiver object, can be null. In such a case, it will be the same
as the final sender class.
- \a slot a pointer only used when using Qt::UniqueConnection
\a slotObj the slot object
- */
-void QTimer::singleShotImpl(int msec, Qt::TimerType timerType,
+*/
+void QTimer::singleShotImpl(std::chrono::milliseconds msec, Qt::TimerType timerType,
const QObject *receiver,
QtPrivate::QSlotObjectBase *slotObj)
{
- if (msec == 0) {
+ if (msec == 0ms) {
bool deleteReceiver = false;
// Optimize: set a receiver context when none is given, such that we can use
// QMetaObject::invokeMethod which is more efficient than going through a timer.
@@ -344,19 +322,23 @@ void QTimer::singleShotImpl(int msec, Qt::TimerType timerType,
deleteReceiver = true;
}
+ auto h = QtPrivate::invokeMethodHelper({});
QMetaObject::invokeMethodImpl(const_cast<QObject *>(receiver), slotObj,
- Qt::QueuedConnection, nullptr);
+ Qt::QueuedConnection, h.parameterCount(), h.parameters.data(), h.typeNames.data(),
+ h.metaTypes.data());
if (deleteReceiver)
const_cast<QObject *>(receiver)->deleteLater();
return;
}
- new QSingleShotTimer(msec, timerType, receiver, slotObj);
+ new QSingleShotTimer(QSingleShotTimer::fromMsecs(msec), timerType, receiver, slotObj);
}
/*!
+ \fn void QTimer::singleShot(int msec, const QObject *receiver, const char *member)
\reentrant
+ \deprecated [6.8] Use the chrono overloads.
This static function calls a slot after a given time interval.
It is very convenient to use this function because you do not need
@@ -375,16 +357,11 @@ void QTimer::singleShotImpl(int msec, Qt::TimerType timerType,
\sa start()
*/
-void QTimer::singleShot(int msec, const QObject *receiver, const char *member)
-{
- // coarse timers are worst in their first firing
- // so we prefer a high precision timer for something that happens only once
- // unless the timeout is too big, in which case we go for coarse anyway
- singleShot(msec, msec >= 2000 ? Qt::CoarseTimer : Qt::PreciseTimer, receiver, member);
-}
-
-/*! \overload
+/*!
+ \fn void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, const char *member)
+ \overload
\reentrant
+ \deprecated [6.8] Use the chrono overloads.
This static function calls a slot after a given time interval.
It is very convenient to use this function because you do not need
@@ -397,147 +374,54 @@ void QTimer::singleShot(int msec, const QObject *receiver, const char *member)
\sa start()
*/
-void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, const char *member)
+
+void QTimer::singleShot(std::chrono::milliseconds msec, Qt::TimerType timerType,
+ const QObject *receiver, const char *member)
{
- if (Q_UNLIKELY(msec < 0)) {
+ if (Q_UNLIKELY(msec < 0ms)) {
qWarning("QTimer::singleShot: Timers cannot have negative timeouts");
return;
}
if (receiver && member) {
- if (msec == 0) {
+ if (msec == 0ms) {
// special code shortpath for 0-timers
const char* bracketPosition = strchr(member, '(');
if (!bracketPosition || !(member[0] >= '0' && member[0] <= '2')) {
qWarning("QTimer::singleShot: Invalid slot specification");
return;
}
- QByteArray methodName(member+1, bracketPosition - 1 - member); // extract method name
- QMetaObject::invokeMethod(const_cast<QObject *>(receiver), methodName.constData(), Qt::QueuedConnection);
+ const auto methodName = QByteArrayView(member + 1, // extract method name
+ bracketPosition - 1 - member).trimmed();
+ QMetaObject::invokeMethod(const_cast<QObject *>(receiver), methodName.toByteArray().constData(),
+ Qt::QueuedConnection);
return;
}
- (void) new QSingleShotTimer(msec, timerType, receiver, member);
+ (void) new QSingleShotTimer(QSingleShotTimer::fromMsecs(msec), timerType, receiver, member);
}
}
-/*! \fn template<typename PointerToMemberFunction> void QTimer::singleShot(int msec, const QObject *receiver, PointerToMemberFunction method)
-
+/*! \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration msec, const QObject *context, Functor &&functor)
+ \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration msec, Qt::TimerType timerType, const QObject *context, Functor &&functor)
+ \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration msec, Functor &&functor)
+ \fn template<typename Duration, typename Functor> void QTimer::singleShot(Duration msec, Qt::TimerType timerType, Functor &&functor)
\since 5.4
- \overload
\reentrant
- This static function calls a member function of a QObject after a given time interval.
+ This static function calls \a functor after \a msec milliseconds.
It is very convenient to use this function because you do not need
to bother with a \l{QObject::timerEvent()}{timerEvent} or
create a local QTimer object.
- The \a receiver is the receiving object and the \a method is the member function. The
- time interval is \a msec milliseconds.
-
- If \a receiver is destroyed before the interval occurs, the method will not be called.
- The function will be run in the thread of \a receiver. The receiver's thread must have
- a running Qt event loop.
-
- \sa start()
-*/
-
-/*! \fn template<typename PointerToMemberFunction> void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, PointerToMemberFunction method)
-
- \since 5.4
-
- \overload
- \reentrant
- This static function calls a member function of a QObject after a given time interval.
-
- It is very convenient to use this function because you do not need
- to bother with a \l{QObject::timerEvent()}{timerEvent} or
- create a local QTimer object.
+ If \a context is specified, then the \a functor will be called only if the
+ \a context object has not been destroyed before the interval occurs. The functor
+ will then be run the thread of \a context. The context's thread must have a
+ running Qt event loop.
- The \a receiver is the receiving object and the \a method is the member function. The
- time interval is \a msec milliseconds. The \a timerType affects the
- accuracy of the timer.
+ If \a functor is a member
+ function of \a context, then the function will be called on the object.
- If \a receiver is destroyed before the interval occurs, the method will not be called.
- The function will be run in the thread of \a receiver. The receiver's thread must have
- a running Qt event loop.
-
- \sa start()
-*/
-
-/*! \fn template<typename Functor> void QTimer::singleShot(int msec, Functor functor)
-
- \since 5.4
-
- \overload
- \reentrant
- This static function calls \a functor after a given time interval.
-
- It is very convenient to use this function because you do not need
- to bother with a \l{QObject::timerEvent()}{timerEvent} or
- create a local QTimer object.
-
- The time interval is \a msec milliseconds.
-
- \sa start()
-*/
-
-/*! \fn template<typename Functor> void QTimer::singleShot(int msec, Qt::TimerType timerType, Functor functor)
-
- \since 5.4
-
- \overload
- \reentrant
- This static function calls \a functor after a given time interval.
-
- It is very convenient to use this function because you do not need
- to bother with a \l{QObject::timerEvent()}{timerEvent} or
- create a local QTimer object.
-
- The time interval is \a msec milliseconds. The \a timerType affects the
- accuracy of the timer.
-
- \sa start()
-*/
-
-/*! \fn template<typename Functor> void QTimer::singleShot(int msec, const QObject *context, Functor functor)
-
- \since 5.4
-
- \overload
- \reentrant
- This static function calls \a functor after a given time interval.
-
- It is very convenient to use this function because you do not need
- to bother with a \l{QObject::timerEvent()}{timerEvent} or
- create a local QTimer object.
-
- The time interval is \a msec milliseconds.
-
- If \a context is destroyed before the interval occurs, the method will not be called.
- The function will be run in the thread of \a context. The context's thread must have
- a running Qt event loop.
-
- \sa start()
-*/
-
-/*! \fn template<typename Functor> void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *context, Functor functor)
-
- \since 5.4
-
- \overload
- \reentrant
- This static function calls \a functor after a given time interval.
-
- It is very convenient to use this function because you do not need
- to bother with a \l{QObject::timerEvent()}{timerEvent} or
- create a local QTimer object.
-
- The time interval is \a msec milliseconds. The \a timerType affects the
- accuracy of the timer.
-
- If \a context is destroyed before the interval occurs, the method will not be called.
- The function will be run in the thread of \a context. The context's thread must have
- a running Qt event loop.
+ The \a msec parameter can be an \c int or a \c std::chrono::milliseconds value.
\sa start()
*/
@@ -580,43 +464,35 @@ void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiv
*/
/*!
- \fn template <typename Functor> QMetaObject::Connection QTimer::callOnTimeout(Functor slot, Qt::ConnectionType connectionType = Qt::AutoConnection)
+ \fn template <typename Functor> QMetaObject::Connection QTimer::callOnTimeout(Functor &&slot)
\since 5.12
- \overload
- Creates a connection of type \a connectionType from the timeout() signal
- to \a slot, and returns a handle to the connection.
+ Creates a connection from the timer's timeout() signal to \a slot.
+ Returns a handle to the connection.
- This method is provided for convenience.
- It's equivalent to calling \c {QObject::connect(timer, &QTimer::timeout, timer, slot, connectionType)}.
+ This method is provided for convenience. It's equivalent to calling:
+ \code
+ QObject::connect(timer, &QTimer::timeout, timer, slot, Qt::DirectConnection);
+ \endcode
+
+ \note This overload is not available when \c {QT_NO_CONTEXTLESS_CONNECT} is
+ defined, instead use the callOnTimeout() overload that takes a context object.
\sa QObject::connect(), timeout()
*/
/*!
- \fn template <typename Functor> QMetaObject::Connection QTimer::callOnTimeout(const QObject *context, Functor slot, Qt::ConnectionType connectionType = Qt::AutoConnection)
+ \fn template <typename Functor> QMetaObject::Connection QTimer::callOnTimeout(const QObject *context, Functor &&slot, Qt::ConnectionType connectionType = Qt::AutoConnection)
\since 5.12
\overload callOnTimeout()
Creates a connection from the timeout() signal to \a slot to be placed in a specific
event loop of \a context, and returns a handle to the connection.
- This method is provided for convenience. It's equivalent to calling
- \c {QObject::connect(timer, &QTimer::timeout, context, slot, connectionType)}.
-
- \sa QObject::connect(), timeout()
-*/
-
-/*!
- \fn template <typename MemberFunction> QMetaObject::Connection QTimer::callOnTimeout(const QObject *receiver, MemberFunction *slot, Qt::ConnectionType connectionType = Qt::AutoConnection)
- \since 5.12
- \overload callOnTimeout()
-
- Creates a connection from the timeout() signal to the \a slot in the \a receiver object. Returns
- a handle to the connection.
-
- This method is provided for convenience. It's equivalent to calling
- \c {QObject::connect(timer, &QTimer::timeout, receiver, slot, connectionType)}.
+ This method is provided for convenience. It's equivalent to calling:
+ \code
+ QObject::connect(timer, &QTimer::timeout, context, slot, connectionType);
+ \endcode
\sa QObject::connect(), timeout()
*/
@@ -631,7 +507,13 @@ void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiv
If the timer is already running, it will be
\l{QTimer::stop()}{stopped} and restarted.
- If \l singleShot is true, the timer will be activated only once.
+ If \l singleShot is true, the timer will be activated only once. This is
+ equivalent to:
+
+ \code
+ timer.setInterval(msec);
+ timer.start();
+ \endcode
*/
/*!
@@ -696,14 +578,30 @@ QBindable<bool> QTimer::bindableSingleShot()
*/
void QTimer::setInterval(int msec)
{
+ setInterval(std::chrono::milliseconds{msec});
+}
+
+void QTimer::setInterval(std::chrono::milliseconds interval)
+{
Q_D(QTimer);
- const bool intervalChanged = msec != d->inter;
- d->inter.setValue(msec);
- if (d->id != QTimerPrivate::INV_TIMER) { // create new timer
+ // This could be narrowing as the interval is stored in an `int` QProperty,
+ // and the type can't be changed in Qt6.
+ const int msec = interval.count();
+ d->inter.removeBindingUnlessInWrapper();
+ const bool intervalChanged = msec != d->inter.valueBypassingBindings();
+ d->inter.setValueBypassingBindings(msec);
+ if (d->isActive()) { // create new timer
QObject::killTimer(d->id); // restart timer
- d->id = QObject::startTimer(std::chrono::milliseconds{msec}, d->type);
- // No need to call markDirty() for d->isActiveData here,
- // as timer state actually does not change
+ Qt::TimerId newId{ QObject::startTimer(msec * 1ms, d->type) }; // overflow impossible
+ if (newId > Qt::TimerId::Invalid) {
+ // Restarted successfully. No need to update the active state.
+ d->id = newId;
+ } else {
+ // Failed to start the timer.
+ // Need to notify about active state change.
+ d->id = Qt::TimerId::Invalid;
+ d->isActiveData.notify();
+ }
}
if (intervalChanged)
d->inter.notify();
@@ -733,8 +631,10 @@ QBindable<int> QTimer::bindableInterval()
int QTimer::remainingTime() const
{
Q_D(const QTimer);
- if (d->id != QTimerPrivate::INV_TIMER) {
- return QAbstractEventDispatcher::instance()->remainingTime(d->id);
+ if (d->isActive()) {
+ using namespace std::chrono;
+ auto remaining = QAbstractEventDispatcher::instance()->remainingTime(d->id);
+ return ceil<milliseconds>(remaining).count();
}
return -1;
@@ -765,5 +665,4 @@ QBindable<Qt::TimerType> QTimer::bindableTimerType()
QT_END_NAMESPACE
-#include "qtimer.moc"
#include "moc_qtimer.cpp"
diff --git a/src/corelib/kernel/qtimer.h b/src/corelib/kernel/qtimer.h
index 5599b60bd7..854d9072f2 100644
--- a/src/corelib/kernel/qtimer.h
+++ b/src/corelib/kernel/qtimer.h
@@ -31,6 +31,7 @@ public:
bool isActive() const;
QBindable<bool> bindableActive();
int timerId() const;
+ Qt::TimerId id() const;
void setInterval(int msec);
int interval() const;
@@ -46,85 +47,56 @@ public:
bool isSingleShot() const;
QBindable<bool> bindableSingleShot();
+ QT_CORE_INLINE_SINCE(6, 8)
static void singleShot(int msec, const QObject *receiver, const char *member);
+
+ QT_CORE_INLINE_SINCE(6, 8)
static void singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, const char *member);
+ // singleShot with context
#ifdef Q_QDOC
- template<typename PointerToMemberFunction>
- static void singleShot(int msec, const QObject *receiver, PointerToMemberFunction method);
- template<typename PointerToMemberFunction>
- static void singleShot(int msec, Qt::TimerType timerType, const QObject *receiver, PointerToMemberFunction method);
- template<typename Functor>
- static void singleShot(int msec, Functor functor);
- template<typename Functor>
- static void singleShot(int msec, Qt::TimerType timerType, Functor functor);
- template<typename Functor, int>
- static void singleShot(int msec, const QObject *context, Functor functor);
- template<typename Functor, int>
- static void singleShot(int msec, Qt::TimerType timerType, const QObject *context, Functor functor);
- template <typename Functor>
- QMetaObject::Connection callOnTimeout(Functor slot, Qt::ConnectionType connectionType = Qt::AutoConnection);
- template <typename Functor>
- QMetaObject::Connection callOnTimeout(const QObject *context, Functor slot, Qt::ConnectionType connectionType = Qt::AutoConnection);
- template <typename MemberFunction>
- QMetaObject::Connection callOnTimeout(const QObject *receiver, MemberFunction *slot, Qt::ConnectionType connectionType = Qt::AutoConnection);
+ template <typename Duration, typename Functor>
+ static inline void singleShot(Duration interval, const QObject *receiver, Functor &&slot);
+ template <typename Duration, typename Functor>
+ static inline void singleShot(Duration interval, Qt::TimerType timerType,
+ const QObject *receiver, Functor &&slot);
#else
- // singleShot to a QObject slot
- template <typename Duration, typename Func1>
- static inline void singleShot(Duration interval, const typename QtPrivate::FunctionPointer<Func1>::Object *receiver, Func1 slot)
+ template <typename Duration, typename Functor>
+ static inline void singleShot(Duration interval,
+ const typename QtPrivate::ContextTypeForFunctor<Functor>::ContextType *receiver,
+ Functor &&slot)
{
- singleShot(interval, defaultTypeFor(interval), receiver, slot);
+ singleShot(interval, defaultTypeFor(interval), receiver, std::forward<Functor>(slot));
}
- template <typename Duration, typename Func1>
- static inline void singleShot(Duration interval, Qt::TimerType timerType, const typename QtPrivate::FunctionPointer<Func1>::Object *receiver,
- Func1 slot)
+ template <typename Duration, typename Functor>
+ static inline void singleShot(Duration interval, Qt::TimerType timerType,
+ const typename QtPrivate::ContextTypeForFunctor<Functor>::ContextType *receiver,
+ Functor &&slot)
{
- typedef QtPrivate::FunctionPointer<Func1> SlotType;
-
- //compilation error if the slot has arguments.
- static_assert(int(SlotType::ArgumentCount) == 0,
- "The slot must not have any arguments.");
-
+ using Prototype = void(*)();
singleShotImpl(interval, timerType, receiver,
- new QtPrivate::QSlotObject<Func1, typename SlotType::Arguments, void>(slot));
- }
- // singleShot to a functor or function pointer (without context)
- template <typename Duration, typename Func1>
- 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, std::move(slot));
- }
- template <typename Duration, typename Func1>
- 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, std::move(slot));
+ QtPrivate::makeCallableObject<Prototype>(std::forward<Functor>(slot)));
}
- // singleShot to a functor or function pointer (with context)
- template <typename Duration, typename Func1>
- static inline typename std::enable_if<!QtPrivate::FunctionPointer<Func1>::IsPointerToMemberFunction &&
- !std::is_same<const char*, Func1>::value, void>::type
- singleShot(Duration interval, const QObject *context, Func1 slot)
+#endif
+
+ // singleShot without context
+ template <typename Duration, typename Functor>
+ static inline void singleShot(Duration interval, Functor &&slot)
{
- singleShot(interval, defaultTypeFor(interval), context, std::move(slot));
+ singleShot(interval, defaultTypeFor(interval), nullptr, std::forward<Functor>(slot));
}
- template <typename Duration, typename Func1>
- 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, const QObject *context, Func1 slot)
+ template <typename Duration, typename Functor>
+ static inline void singleShot(Duration interval, Qt::TimerType timerType, Functor &&slot)
{
- //compilation error if the slot has arguments.
- typedef QtPrivate::FunctionPointer<Func1> SlotType;
- static_assert(int(SlotType::ArgumentCount) <= 0, "The slot must not have any arguments.");
-
- singleShotImpl(interval, timerType, context,
- new QtPrivate::QFunctorSlotObject<Func1, 0,
- typename QtPrivate::List_Left<void, 0>::Value, void>(std::move(slot)));
+ singleShot(interval, timerType, nullptr, std::forward<Functor>(slot));
}
+#ifdef Q_QDOC
+ template <typename Functor>
+ QMetaObject::Connection callOnTimeout(Functor &&slot);
+ template <typename Functor>
+ QMetaObject::Connection callOnTimeout(const QObject *context, Functor &&slot, Qt::ConnectionType connectionType = Qt::AutoConnection);
+#else
template <typename ... Args>
QMetaObject::Connection callOnTimeout(Args && ...args)
{
@@ -143,10 +115,7 @@ Q_SIGNALS:
void timeout(QPrivateSignal);
public:
- void setInterval(std::chrono::milliseconds value)
- {
- setInterval(int(value.count()));
- }
+ void setInterval(std::chrono::milliseconds value);
std::chrono::milliseconds intervalAsDuration() const
{
@@ -160,18 +129,12 @@ public:
static void singleShot(std::chrono::milliseconds value, const QObject *receiver, const char *member)
{
- singleShot(int(value.count()), receiver, member);
+ singleShot(value, defaultTypeFor(value), receiver, member);
}
+ static void singleShot(std::chrono::milliseconds interval, Qt::TimerType timerType,
+ const QObject *receiver, const char *member);
- static void singleShot(std::chrono::milliseconds value, Qt::TimerType timerType, const QObject *receiver, const char *member)
- {
- singleShot(int(value.count()), timerType, receiver, member);
- }
-
- void start(std::chrono::milliseconds value)
- {
- start(int(value.count()));
- }
+ void start(std::chrono::milliseconds value);
protected:
void timerEvent(QTimerEvent *) override;
@@ -184,21 +147,40 @@ private:
inline void killTimer(int){}
static constexpr Qt::TimerType defaultTypeFor(int msecs) noexcept
- { return msecs >= 2000 ? Qt::CoarseTimer : Qt::PreciseTimer; }
+ { return defaultTypeFor(std::chrono::milliseconds{msecs}); }
+
+ static constexpr Qt::TimerType defaultTypeFor(std::chrono::milliseconds interval) noexcept
+ {
+ // coarse timers are worst in their first firing
+ // so we prefer a high precision timer for something that happens only once
+ // unless the timeout is too big, in which case we go for coarse anyway
+ using namespace std::chrono_literals;
+ return interval >= 2s ? Qt::CoarseTimer : Qt::PreciseTimer;
+ }
+
+ QT_CORE_INLINE_SINCE(6, 8)
static void singleShotImpl(int msec, Qt::TimerType timerType,
const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj);
- static Qt::TimerType defaultTypeFor(std::chrono::milliseconds interval)
- { return defaultTypeFor(int(interval.count())); }
-
static void singleShotImpl(std::chrono::milliseconds interval, Qt::TimerType timerType,
- const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj)
- {
- singleShotImpl(int(interval.count()),
- timerType, receiver, slotObj);
- }
+ const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj);
};
+#if QT_CORE_INLINE_IMPL_SINCE(6, 8)
+void QTimer::singleShot(int msec, const QObject *receiver, const char *member)
+{ singleShot(std::chrono::milliseconds{msec}, receiver, member); }
+
+void QTimer::singleShot(int msec, Qt::TimerType timerType, const QObject *receiver,
+ const char *member)
+{ singleShot(std::chrono::milliseconds{msec}, timerType, receiver, member); }
+
+void QTimer::singleShotImpl(int msec, Qt::TimerType timerType,
+ const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj)
+{
+ singleShotImpl(std::chrono::milliseconds{msec}, timerType, receiver, slotObj);
+}
+#endif
+
QT_END_NAMESPACE
#endif // QT_NO_QOBJECT
diff --git a/src/corelib/kernel/qtimer_p.h b/src/corelib/kernel/qtimer_p.h
index f283a264fa..9347f6c241 100644
--- a/src/corelib/kernel/qtimer_p.h
+++ b/src/corelib/kernel/qtimer_p.h
@@ -12,27 +12,61 @@
//
// We mean it.
//
+#include "qtimer.h"
+#include "qchronotimer.h"
+
#include "qobject_p.h"
#include "qproperty_p.h"
-#include "qtimer.h"
+#include "qttypetraits.h"
QT_BEGIN_NAMESPACE
class QTimerPrivate : public QObjectPrivate
{
- Q_DECLARE_PUBLIC(QTimer)
public:
+ QTimerPrivate(QTimer *qq)
+ : q(qq),
+ isQTimer(true)
+ {}
+
+ QTimerPrivate(std::chrono::nanoseconds nsec, QChronoTimer *qq)
+ : intervalDuration(nsec),
+ q(qq)
+ {
+ intervalDuration.notify();
+ }
+
static constexpr int INV_TIMER = -1; // invalid timer id
- void setInterval(int msec) { q_func()->setInterval(msec); }
- bool isActiveActualCalculation() const { return id >= 0; }
+ void setIntervalDuration(std::chrono::nanoseconds nsec)
+ {
+ if (isQTimer) {
+ const auto msec = std::chrono::ceil<std::chrono::milliseconds>(nsec);
+ static_cast<QTimer *>(q)->setInterval(msec);
+ } else {
+ static_cast<QChronoTimer *>(q)->setInterval(nsec);
+ }
+ }
+
+ void setInterval(int msec)
+ {
+ Q_ASSERT(isQTimer);
+ static_cast<QTimer *>(q)->setInterval(msec);
+ }
- int id = INV_TIMER;
+ bool isActive() const { return id > Qt::TimerId::Invalid; }
+
+ Qt::TimerId id = Qt::TimerId::Invalid;
Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QTimerPrivate, int, inter, &QTimerPrivate::setInterval, 0)
+ Q_OBJECT_COMPAT_PROPERTY_WITH_ARGS(QTimerPrivate, std::chrono::nanoseconds, intervalDuration,
+ &QTimerPrivate::setIntervalDuration,
+ std::chrono::nanoseconds{0})
Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QTimerPrivate, bool, single, false)
Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(QTimerPrivate, Qt::TimerType, type, Qt::CoarseTimer)
- Q_OBJECT_COMPUTED_PROPERTY(QTimerPrivate, bool, isActiveData,
- &QTimerPrivate::isActiveActualCalculation)
+ Q_OBJECT_COMPUTED_PROPERTY(QTimerPrivate, bool, isActiveData, &QTimerPrivate::isActive)
+
+ QObject *q;
+ const bool isQTimer = false; // true if q is a QTimer*
};
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qtimerinfo_unix.cpp b/src/corelib/kernel/qtimerinfo_unix.cpp
index f3d811a948..b83f0194c2 100644
--- a/src/corelib/kernel/qtimerinfo_unix.cpp
+++ b/src/corelib/kernel/qtimerinfo_unix.cpp
@@ -10,14 +10,11 @@
#include "private/qobject_p.h"
#include "private/qabstracteventdispatcher_p.h"
-#ifdef QTIMERINFO_DEBUG
-# include <QDebug>
-# include <QThread>
-#endif
-
#include <sys/times.h>
using namespace std::chrono;
+// Implied by "using namespace std::chrono", but be explicit about it, for grep-ability
+using namespace std::chrono_literals;
QT_BEGIN_NAMESPACE
@@ -28,131 +25,56 @@ Q_CORE_EXPORT bool qt_disable_lowpriority_timers=false;
* timerBitVec array is used for keeping track of timer identifiers.
*/
-QTimerInfoList::QTimerInfoList()
-{
-#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_DARWIN)
- if (!QElapsedTimer::isMonotonic()) {
- // not using monotonic timers, initialize the timeChanged() machinery
- previousTime = qt_gettime();
-
- tms unused;
- previousTicks = times(&unused);
-
- ticksPerSecond = sysconf(_SC_CLK_TCK);
- msPerTick = 1000/ticksPerSecond;
- } else {
- // detected monotonic timers
- previousTime.tv_sec = previousTime.tv_nsec = 0;
- previousTicks = 0;
- ticksPerSecond = 0;
- msPerTick = 0;
- }
-#endif
-
- firstTimerInfo = nullptr;
-}
+QTimerInfoList::QTimerInfoList() = default;
-timespec QTimerInfoList::updateCurrentTime()
+steady_clock::time_point QTimerInfoList::updateCurrentTime() const
{
- return (currentTime = qt_gettime());
+ currentTime = steady_clock::now();
+ return currentTime;
}
-#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_DARWIN) && !defined(Q_OS_INTEGRITY)) || defined(QT_BOOTSTRAPPED)
-
-/*
- Returns \c true if the real time clock has changed by more than 10%
- relative to the processor time since the last time this function was
- called. This presumably means that the system time has been changed.
+/*! \internal
+ Updates the currentTime member to the current time, and returns \c true if
+ the first timer's timeout is in the future (after currentTime).
- If /a delta is nonzero, delta is set to our best guess at how much the system clock was changed.
+ The list is sorted by timeout, thus it's enough to check the first timer only.
*/
-bool QTimerInfoList::timeChanged(timespec *delta)
-{
- struct tms unused;
- clock_t currentTicks = times(&unused);
-
- clock_t elapsedTicks = currentTicks - previousTicks;
- timespec elapsedTime = currentTime - previousTime;
-
- timespec elapsedTimeTicks;
- elapsedTimeTicks.tv_sec = elapsedTicks / ticksPerSecond;
- elapsedTimeTicks.tv_nsec = (((elapsedTicks * 1000) / ticksPerSecond) % 1000) * 1000 * 1000;
-
- timespec dummy;
- if (!delta)
- delta = &dummy;
- *delta = elapsedTime - elapsedTimeTicks;
-
- previousTicks = currentTicks;
- previousTime = currentTime;
-
- // If tick drift is more than 10% off compared to realtime, we assume that the clock has
- // been set. Of course, we have to allow for the tick granularity as well.
- timespec tickGranularity;
- tickGranularity.tv_sec = 0;
- tickGranularity.tv_nsec = msPerTick * 1000 * 1000;
- return elapsedTimeTicks < ((qAbsTimespec(*delta) - tickGranularity) * 10);
-}
-
-/*
- repair broken timer
-*/
-void QTimerInfoList::timerRepair(const timespec &diff)
-{
- // repair all timers
- for (QTimerInfo *t : std::as_const(*this))
- t->timeout += diff;
-}
-
-void QTimerInfoList::repairTimersIfNeeded()
-{
- if (QElapsedTimer::isMonotonic())
- return;
- timespec delta;
- if (timeChanged(&delta))
- timerRepair(delta);
-}
-
-#else // !(_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(QT_BOOTSTRAPPED)
-
-void QTimerInfoList::repairTimersIfNeeded()
+bool QTimerInfoList::hasPendingTimers()
{
+ if (timers.isEmpty())
+ return false;
+ return updateCurrentTime() < timers.at(0)->timeout;
}
-#endif
+static bool byTimeout(const QTimerInfo *a, const QTimerInfo *b)
+{ return a->timeout < b->timeout; };
/*
insert timer info into list
*/
void QTimerInfoList::timerInsert(QTimerInfo *ti)
{
- int index = size();
- while (index--) {
- const QTimerInfo * const t = at(index);
- if (!(ti->timeout < t->timeout))
- break;
- }
- insert(index+1, ti);
+ timers.insert(std::upper_bound(timers.cbegin(), timers.cend(), ti, byTimeout),
+ ti);
}
-static constexpr timespec roundToMillisecond(timespec val)
+static constexpr milliseconds roundToMillisecond(nanoseconds val)
{
// always round up
// worst case scenario is that the first trigger of a 1-ms timer is 0.999 ms late
-
- int ns = val.tv_nsec % (1000 * 1000);
- if (ns)
- val.tv_nsec += 1000 * 1000 - ns;
- return normalizedTimespec(val);
+ return ceil<milliseconds>(val);
}
-static_assert(roundToMillisecond({0, 0}) == timespec{0, 0});
-static_assert(roundToMillisecond({0, 1}) == timespec{0, 1'000'000});
-static_assert(roundToMillisecond({0, 999'999}) == timespec{0, 1'000'000});
-static_assert(roundToMillisecond({0, 1'000'000}) == timespec{0, 1'000'000});
-static_assert(roundToMillisecond({0, 999'999'999}) == timespec{1, 0});
-static_assert(roundToMillisecond({1, 0}) == timespec{1, 0});
-
-static constexpr seconds roundToSecs(milliseconds msecs)
+
+static_assert(roundToMillisecond(0ns) == 0ms);
+static_assert(roundToMillisecond(1ns) == 1ms);
+static_assert(roundToMillisecond(999'999ns) == 1ms);
+static_assert(roundToMillisecond(1'000'000ns) == 1ms);
+static_assert(roundToMillisecond(999'000'000ns) == 999ms);
+static_assert(roundToMillisecond(999'000'001ns) == 1000ms);
+static_assert(roundToMillisecond(999'999'999ns) == 1000ms);
+static_assert(roundToMillisecond(1s) == 1s);
+
+static constexpr seconds roundToSecs(nanoseconds interval)
{
// The very coarse timer is based on full second precision, so we want to
// round the interval to the closest second, rounding 500ms up to 1s.
@@ -164,30 +86,14 @@ static constexpr seconds roundToSecs(milliseconds msecs)
// 1500 2 2
// 2500 2 3
- auto secs = duration_cast<seconds>(msecs);
- const milliseconds frac = msecs - secs;
+ auto secs = duration_cast<seconds>(interval);
+ const nanoseconds frac = interval - secs;
if (frac >= 500ms)
++secs;
return secs;
}
-#ifdef QTIMERINFO_DEBUG
-QDebug operator<<(QDebug s, timeval tv)
-{
- QDebugStateSaver saver(s);
- s.nospace() << tv.tv_sec << "." << qSetFieldWidth(6) << qSetPadChar(QChar(48)) << tv.tv_usec << Qt::reset;
- return s;
-}
-QDebug operator<<(QDebug s, Qt::TimerType t)
-{
- QDebugStateSaver saver(s);
- s << (t == Qt::PreciseTimer ? "P" :
- t == Qt::CoarseTimer ? "C" : "VC");
- return s;
-}
-#endif
-
-static void calculateCoarseTimerTimeout(QTimerInfo *t, timespec now)
+static void calculateCoarseTimerTimeout(QTimerInfo *t, steady_clock::time_point now)
{
// The coarse timer works like this:
// - interval under 40 ms: round to even
@@ -207,27 +113,24 @@ static void calculateCoarseTimerTimeout(QTimerInfo *t, timespec now)
Q_ASSERT(t->interval >= 20ms);
- auto recalculate = [&](const milliseconds fracMsec) {
- if (fracMsec == 1000ms) {
- ++t->timeout.tv_sec;
- t->timeout.tv_nsec = 0;
- } else {
- t->timeout.tv_nsec = nanoseconds{fracMsec}.count();
- }
+ const auto timeoutInSecs = time_point_cast<seconds>(t->timeout);
+ auto recalculate = [&](const milliseconds frac) {
+ t->timeout = timeoutInSecs + frac;
if (t->timeout < now)
t->timeout += t->interval;
};
// Calculate how much we can round and still keep within 5% error
- const milliseconds absMaxRounding = t->interval / 20;
+ milliseconds interval = roundToMillisecond(t->interval);
+ const milliseconds absMaxRounding = interval / 20;
- auto fracMsec = duration_cast<milliseconds>(nanoseconds{t->timeout.tv_nsec});
+ auto fracMsec = duration_cast<milliseconds>(t->timeout - timeoutInSecs);
- if (t->interval < 100ms && t->interval != 25ms && t->interval != 50ms && t->interval != 75ms) {
+ if (interval < 100ms && interval != 25ms && interval != 50ms && interval != 75ms) {
auto fracCount = fracMsec.count();
// special mode for timers of less than 100 ms
- if (t->interval < 50ms) {
+ if (interval < 50ms) {
// round to even
// round towards multiples of 50 ms
bool roundUp = (fracCount % 50) >= 25;
@@ -269,17 +172,17 @@ static void calculateCoarseTimerTimeout(QTimerInfo *t, timespec now)
// towards a round-to-the-second
// 3) if the interval is a multiple of 500 ms, we'll round towards the nearest
// multiple of 500 ms
- if ((t->interval % 500) == 0ms) {
- if (t->interval >= 5s) {
+ if ((interval % 500) == 0ms) {
+ if (interval >= 5s) {
fracMsec = fracMsec >= 500ms ? max : min;
recalculate(fracMsec);
return;
} else {
wantedBoundaryMultiple = 500ms;
}
- } else if ((t->interval % 50) == 0ms) {
+ } else if ((interval % 50) == 0ms) {
// 4) same for multiples of 250, 200, 100, 50
- milliseconds mult50 = t->interval / 50;
+ milliseconds mult50 = interval / 50;
if ((mult50 % 4) == 0ms) {
// multiple of 200
wantedBoundaryMultiple = 200ms;
@@ -305,7 +208,7 @@ static void calculateCoarseTimerTimeout(QTimerInfo *t, timespec now)
recalculate(fracMsec);
}
-static void calculateNextTimeout(QTimerInfo *t, timespec now)
+static void calculateNextTimeout(QTimerInfo *t, steady_clock::time_point now)
{
switch (t->timerType) {
case Qt::PreciseTimer:
@@ -315,109 +218,79 @@ static void calculateNextTimeout(QTimerInfo *t, timespec now)
t->timeout = now;
t->timeout += t->interval;
}
-#ifdef QTIMERINFO_DEBUG
- t->expected += t->interval;
- if (t->expected < currentTime) {
- t->expected = currentTime;
- t->expected += t->interval;
- }
-#endif
if (t->timerType == Qt::CoarseTimer)
calculateCoarseTimerTimeout(t, now);
return;
case Qt::VeryCoarseTimer:
// t->interval already rounded to full seconds in registerTimer()
- const auto secs = duration_cast<seconds>(t->interval).count();
- t->timeout.tv_sec += secs;
- if (t->timeout.tv_sec <= now.tv_sec)
- t->timeout.tv_sec = now.tv_sec + secs;
-#ifdef QTIMERINFO_DEBUG
- t->expected.tv_sec += t->interval;
- if (t->expected.tv_sec <= currentTime.tv_sec)
- t->expected.tv_sec = currentTime.tv_sec + t->interval;
-#endif
- return;
+ t->timeout += t->interval;
+ if (t->timeout <= now)
+ t->timeout = time_point_cast<seconds>(now + t->interval);
+ break;
}
-
-#ifdef QTIMERINFO_DEBUG
- if (t->timerType != Qt::PreciseTimer)
- qDebug() << "timer" << t->timerType << Qt::hex << t->id << Qt::dec << "interval" << t->interval
- << "originally expected at" << t->expected << "will fire at" << t->timeout
- << "or" << (t->timeout - t->expected) << "s late";
-#endif
}
/*
- Returns the time to wait for the next timer, or null if no timers
- are waiting.
-*/
-bool QTimerInfoList::timerWait(timespec &tm)
+ Returns the time to wait for the first timer that has not been activated yet,
+ otherwise returns std::nullopt.
+ */
+std::optional<QTimerInfoList::Duration> QTimerInfoList::timerWait()
{
- timespec now = updateCurrentTime();
- repairTimersIfNeeded();
+ steady_clock::time_point now = updateCurrentTime();
auto isWaiting = [](QTimerInfo *tinfo) { return !tinfo->activateRef; };
// Find first waiting timer not already active
- auto it = std::find_if(cbegin(), cend(), isWaiting);
- if (it == cend())
- return false;
-
- QTimerInfo *t = *it;
- if (now < t->timeout) // Time to wait
- tm = roundToMillisecond(t->timeout - now);
- else // No time to wait
- tm = {0, 0};
-
- return true;
+ auto it = std::find_if(timers.cbegin(), timers.cend(), isWaiting);
+ if (it == timers.cend())
+ return std::nullopt;
+
+ Duration timeToWait = (*it)->timeout - now;
+ if (timeToWait > 0ns)
+ return roundToMillisecond(timeToWait);
+ return 0ms;
}
/*
Returns the timer's remaining time in milliseconds with the given timerId.
- If the timer id is not found in the list, the returned value will be -1.
+ If the timer id is not found in the list, the returned value will be \c{Duration::min()}.
If the timer is overdue, the returned value will be 0.
*/
-qint64 QTimerInfoList::timerRemainingTime(int timerId)
-{
- return remainingDuration(timerId).count();
-}
-
-milliseconds QTimerInfoList::remainingDuration(int timerId)
+QTimerInfoList::Duration QTimerInfoList::remainingDuration(Qt::TimerId timerId) const
{
- timespec now = updateCurrentTime();
- repairTimersIfNeeded();
+ const steady_clock::time_point now = updateCurrentTime();
auto it = findTimerById(timerId);
- if (it == cend()) {
+ if (it == timers.cend()) {
#ifndef QT_NO_DEBUG
- qWarning("QTimerInfoList::timerRemainingTime: timer id %i not found", timerId);
+ qWarning("QTimerInfoList::timerRemainingTime: timer id %i not found", int(timerId));
#endif
- return milliseconds{-1};
+ return Duration::min();
}
const QTimerInfo *t = *it;
if (now < t->timeout) // time to wait
- return timespecToChronoMs(roundToMillisecond(t->timeout - now));
- else
- return milliseconds{0};
+ return t->timeout - now;
+ return 0ms;
}
-void QTimerInfoList::registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object)
-{
- registerTimer(timerId, milliseconds{interval}, timerType, object);
-}
-
-void QTimerInfoList::registerTimer(int timerId, milliseconds interval,
+void QTimerInfoList::registerTimer(Qt::TimerId timerId, QTimerInfoList::Duration interval,
Qt::TimerType timerType, QObject *object)
{
- QTimerInfo *t = new QTimerInfo;
- t->id = timerId;
- t->interval = interval;
- t->timerType = timerType;
- t->obj = object;
- t->activateRef = nullptr;
+ // correct the timer type first
+ if (timerType == Qt::CoarseTimer) {
+ // this timer has up to 5% coarseness
+ // so our boundaries are 20 ms and 20 s
+ // below 20 ms, 5% inaccuracy is below 1 ms, so we convert to high precision
+ // above 20 s, 5% inaccuracy is above 1 s, so we convert to VeryCoarseTimer
+ if (interval >= 20s)
+ timerType = Qt::VeryCoarseTimer;
+ else if (interval <= 20ms)
+ timerType = Qt::PreciseTimer;
+ }
- timespec expected = updateCurrentTime() + interval;
+ QTimerInfo *t = new QTimerInfo(timerId, interval, timerType, object);
+ QTimerInfo::TimePoint expected = updateCurrentTime() + interval;
switch (timerType) {
case Qt::PreciseTimer:
@@ -427,50 +300,27 @@ void QTimerInfoList::registerTimer(int timerId, milliseconds interval,
break;
case Qt::CoarseTimer:
- // this timer has up to 5% coarseness
- // so our boundaries are 20 ms and 20 s
- // below 20 ms, 5% inaccuracy is below 1 ms, so we convert to high precision
- // above 20 s, 5% inaccuracy is above 1 s, so we convert to VeryCoarseTimer
- if (interval >= 20s) {
- t->timerType = Qt::VeryCoarseTimer;
- } else {
- t->timeout = expected;
- if (interval <= 20ms) {
- t->timerType = Qt::PreciseTimer;
- // no adjustment is necessary
- } else if (interval <= 20s) {
- calculateCoarseTimerTimeout(t, currentTime);
- }
- break;
- }
- Q_FALLTHROUGH();
+ t->timeout = expected;
+ t->interval = roundToMillisecond(interval);
+ calculateCoarseTimerTimeout(t, currentTime);
+ break;
+
case Qt::VeryCoarseTimer:
- const seconds secs = roundToSecs(t->interval);
- t->interval = secs;
- t->timeout.tv_sec = currentTime.tv_sec + secs.count();
- t->timeout.tv_nsec = 0;
-
- // if we're past the half-second mark, increase the timeout again
- if (currentTime.tv_nsec > nanoseconds{500ms}.count())
- ++t->timeout.tv_sec;
+ t->interval = roundToSecs(t->interval);
+ const auto currentTimeInSecs = floor<seconds>(currentTime);
+ t->timeout = currentTimeInSecs + t->interval;
+ // If we're past the half-second mark, increase the timeout again
+ if (currentTime - currentTimeInSecs > 500ms)
+ t->timeout += 1s;
}
timerInsert(t);
-
-#ifdef QTIMERINFO_DEBUG
- t->expected = expected;
- t->cumulativeError = 0;
- t->count = 0;
- if (t->timerType != Qt::PreciseTimer)
- qDebug() << "timer" << t->timerType << Qt::hex <<t->id << Qt::dec << "interval" << t->interval << "expected at"
- << t->expected << "will fire first at" << t->timeout;
-#endif
}
-bool QTimerInfoList::unregisterTimer(int timerId)
+bool QTimerInfoList::unregisterTimer(Qt::TimerId timerId)
{
auto it = findTimerById(timerId);
- if (it == cend())
+ if (it == timers.cend())
return false; // id not found
// set timer inactive
@@ -480,37 +330,39 @@ bool QTimerInfoList::unregisterTimer(int timerId)
if (t->activateRef)
*(t->activateRef) = nullptr;
delete t;
- erase(it);
+ timers.erase(it);
return true;
}
bool QTimerInfoList::unregisterTimers(QObject *object)
{
- if (isEmpty())
+ if (timers.isEmpty())
return false;
- for (int i = 0; i < size(); ++i) {
- QTimerInfo *t = at(i);
- if (t->obj == object) {
- // object found
- removeAt(i);
- if (t == firstTimerInfo)
- firstTimerInfo = nullptr;
- if (t->activateRef)
- *(t->activateRef) = nullptr;
- delete t;
- // move back one so that we don't skip the new current item
- --i;
- }
- }
- return true;
+
+ auto associatedWith = [this](QObject *o) {
+ return [this, o](auto &t) {
+ if (t->obj == o) {
+ if (t == firstTimerInfo)
+ firstTimerInfo = nullptr;
+ if (t->activateRef)
+ *(t->activateRef) = nullptr;
+ delete t;
+ return true;
+ }
+ return false;
+ };
+ };
+
+ qsizetype count = timers.removeIf(associatedWith(object));
+ return count > 0;
}
-QList<QAbstractEventDispatcher::TimerInfo> QTimerInfoList::registeredTimers(QObject *object) const
+auto QTimerInfoList::registeredTimers(QObject *object) const -> QList<TimerInfo>
{
- QList<QAbstractEventDispatcher::TimerInfo> list;
- for (const QTimerInfo *const t : std::as_const(*this)) {
+ QList<TimerInfo> list;
+ for (const auto &t : timers) {
if (t->obj == object)
- list.emplaceBack(t->id, t->interval.count(), t->timerType);
+ list.emplaceBack(TimerInfo{t->interval, t->id, t->timerType});
}
return list;
}
@@ -520,28 +372,26 @@ QList<QAbstractEventDispatcher::TimerInfo> QTimerInfoList::registeredTimers(QObj
*/
int QTimerInfoList::activateTimers()
{
- if (qt_disable_lowpriority_timers || isEmpty())
+ if (qt_disable_lowpriority_timers || timers.isEmpty())
return 0; // nothing to do
firstTimerInfo = nullptr;
- timespec now = updateCurrentTime();
+ const steady_clock::time_point now = updateCurrentTime();
// qDebug() << "Thread" << QThread::currentThreadId() << "woken up at" << now;
- repairTimersIfNeeded();
-
// Find out how many timer have expired
auto stillActive = [&now](const QTimerInfo *t) { return now < t->timeout; };
// Find first one still active (list is sorted by timeout)
- auto it = std::find_if(cbegin(), cend(), stillActive);
- auto maxCount = it - cbegin();
+ auto it = std::find_if(timers.cbegin(), timers.cend(), stillActive);
+ auto maxCount = it - timers.cbegin();
int n_act = 0;
//fire the timers.
while (maxCount--) {
- if (isEmpty())
+ if (timers.isEmpty())
break;
- QTimerInfo *currentTimerInfo = constFirst();
+ QTimerInfo *currentTimerInfo = timers.constFirst();
if (now < currentTimerInfo->timeout)
break; // no timer has expired
@@ -555,34 +405,16 @@ int QTimerInfoList::activateTimers()
firstTimerInfo = currentTimerInfo;
}
- // remove from list
- removeFirst();
-
-#ifdef QTIMERINFO_DEBUG
- float diff;
- if (currentTime < currentTimerInfo->expected) {
- // early
- timeval early = currentTimerInfo->expected - currentTime;
- diff = -(early.tv_sec + early.tv_usec / 1000000.0);
- } else {
- timeval late = currentTime - currentTimerInfo->expected;
- diff = late.tv_sec + late.tv_usec / 1000000.0;
- }
- currentTimerInfo->cumulativeError += diff;
- ++currentTimerInfo->count;
- if (currentTimerInfo->timerType != Qt::PreciseTimer)
- qDebug() << "timer" << currentTimerInfo->timerType << Qt::hex << currentTimerInfo->id << Qt::dec << "interval"
- << currentTimerInfo->interval << "firing at" << currentTime
- << "(orig" << currentTimerInfo->expected << "scheduled at" << currentTimerInfo->timeout
- << ") off by" << diff << "activation" << currentTimerInfo->count
- << "avg error" << (currentTimerInfo->cumulativeError / currentTimerInfo->count);
-#endif
-
// determine next timeout time
calculateNextTimeout(currentTimerInfo, now);
+ if (timers.size() > 1) {
+ // Find where "currentTimerInfo" should be in the list so as
+ // to keep the list ordered by timeout
+ auto afterCurrentIt = timers.begin() + 1;
+ auto iter = std::upper_bound(afterCurrentIt, timers.end(), currentTimerInfo, byTimeout);
+ currentTimerInfo = *std::rotate(timers.begin(), afterCurrentIt, iter);
+ }
- // reinsert timer
- timerInsert(currentTimerInfo);
if (currentTimerInfo->interval > 0ms)
n_act++;
@@ -590,7 +422,7 @@ int QTimerInfoList::activateTimers()
if (!currentTimerInfo->activateRef) {
currentTimerInfo->activateRef = &currentTimerInfo;
- QTimerEvent e(currentTimerInfo->id);
+ QTimerEvent e(qToUnderlying(currentTimerInfo->id));
QCoreApplication::sendEvent(currentTimerInfo->obj, &e);
// Storing currentTimerInfo's address in its activateRef allows the
diff --git a/src/corelib/kernel/qtimerinfo_unix_p.h b/src/corelib/kernel/qtimerinfo_unix_p.h
index c1c1f3474a..293e9c4d4e 100644
--- a/src/corelib/kernel/qtimerinfo_unix_p.h
+++ b/src/corelib/kernel/qtimerinfo_unix_p.h
@@ -15,78 +15,78 @@
// We mean it.
//
-#include "qplatformdefs.h" // _POSIX_MONOTONIC_CLOCK-0
-
#include <QtCore/private/qglobal_p.h>
-// #define QTIMERINFO_DEBUG
-
#include "qabstracteventdispatcher.h"
-#include <sys/time.h> // struct timeval
+#include <sys/time.h> // struct timespec
+#include <chrono>
QT_BEGIN_NAMESPACE
// internal timer info
-struct QTimerInfo {
- int id; // - timer identifier
+struct QTimerInfo
+{
+ using Duration = QAbstractEventDispatcher::Duration;
+ using TimePoint = std::chrono::time_point<std::chrono::steady_clock, Duration>;
+ QTimerInfo(Qt::TimerId timerId, Duration interval, Qt::TimerType type, QObject *obj)
+ : interval(interval), id(timerId), timerType(type), obj(obj)
+ {
+ }
+
+ TimePoint timeout = {}; // - when to actually fire
+ Duration interval = Duration{-1}; // - timer interval
+ Qt::TimerId id = Qt::TimerId::Invalid; // - timer identifier
Qt::TimerType timerType; // - timer type
- std::chrono::milliseconds interval; // - timer interval
- timespec timeout; // - when to actually fire
- QObject *obj; // - object to receive event
- QTimerInfo **activateRef; // - ref from activateTimers
-
-#ifdef QTIMERINFO_DEBUG
- timeval expected; // when timer is expected to fire
- float cumulativeError;
- uint count;
-#endif
+ QObject *obj = nullptr; // - object to receive event
+ QTimerInfo **activateRef = nullptr; // - ref from activateTimers
};
-class Q_CORE_EXPORT QTimerInfoList : public QList<QTimerInfo*>
+class Q_CORE_EXPORT QTimerInfoList
{
-#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_DARWIN)) || defined(QT_BOOTSTRAPPED)
- timespec previousTime;
- clock_t previousTicks;
- int ticksPerSecond;
- int msPerTick;
-
- bool timeChanged(timespec *delta);
- void timerRepair(const timespec &);
-#endif
-
- // state variables used by activateTimers()
- QTimerInfo *firstTimerInfo;
-
public:
+ using Duration = QAbstractEventDispatcher::Duration;
+ using TimerInfo = QAbstractEventDispatcher::TimerInfoV2;
QTimerInfoList();
- timespec currentTime;
- timespec updateCurrentTime();
+ mutable std::chrono::steady_clock::time_point currentTime;
- // must call updateCurrentTime() first!
- void repairTimersIfNeeded();
-
- bool timerWait(timespec &);
+ std::optional<Duration> timerWait();
void timerInsert(QTimerInfo *);
- qint64 timerRemainingTime(int timerId);
- std::chrono::milliseconds remainingDuration(int timerId);
+ Duration remainingDuration(Qt::TimerId timerId) const;
- void registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object);
- void registerTimer(int timerId, std::chrono::milliseconds interval, Qt::TimerType timerType,
- QObject *object);
- bool unregisterTimer(int timerId);
+ void registerTimer(Qt::TimerId timerId, Duration interval,
+ Qt::TimerType timerType, QObject *object);
+ bool unregisterTimer(Qt::TimerId timerId);
bool unregisterTimers(QObject *object);
- QList<QAbstractEventDispatcher::TimerInfo> registeredTimers(QObject *object) const;
+ QList<TimerInfo> registeredTimers(QObject *object) const;
int activateTimers();
+ bool hasPendingTimers();
- QList::const_iterator findTimerById(int timerId) const
+ void clearTimers()
{
- auto matchesId = [timerId](const QTimerInfo *t) { return t->id == timerId; };
- return std::find_if(cbegin(), cend(), matchesId);
+ qDeleteAll(timers);
+ timers.clear();
}
+
+ bool isEmpty() const { return timers.empty(); }
+
+ qsizetype size() const { return timers.size(); }
+
+ auto findTimerById(Qt::TimerId timerId) const
+ {
+ auto matchesId = [timerId](const auto &t) { return t->id == timerId; };
+ return std::find_if(timers.cbegin(), timers.cend(), matchesId);
+ }
+
+private:
+ std::chrono::steady_clock::time_point updateCurrentTime() const;
+
+ // state variables used by activateTimers()
+ QTimerInfo *firstTimerInfo = nullptr;
+ QList<QTimerInfo *> timers;
};
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qtmetamacros.h b/src/corelib/kernel/qtmetamacros.h
index 1ce6a49bde..ae68abcfee 100644
--- a/src/corelib/kernel/qtmetamacros.h
+++ b/src/corelib/kernel/qtmetamacros.h
@@ -103,6 +103,8 @@ QT_BEGIN_NAMESPACE
# endif
#elif defined(Q_CC_GNU) && Q_CC_GNU >= 501
# define Q_OBJECT_NO_OVERRIDE_WARNING QT_WARNING_DISABLE_GCC("-Wsuggest-override")
+#elif defined(Q_CC_MSVC)
+# define Q_OBJECT_NO_OVERRIDE_WARNING QT_WARNING_DISABLE_MSVC(26433)
#else
# define Q_OBJECT_NO_OVERRIDE_WARNING
#endif
diff --git a/src/corelib/kernel/qtmochelpers.h b/src/corelib/kernel/qtmochelpers.h
index b6b7ca6cbd..9d75177645 100644
--- a/src/corelib/kernel/qtmochelpers.h
+++ b/src/corelib/kernel/qtmochelpers.h
@@ -26,37 +26,38 @@
QT_BEGIN_NAMESPACE
namespace QtMocHelpers {
-template <uint... Nx> struct StringData
-{
- static constexpr size_t calculateStringSize()
- {
- // same as:
- // return (0 + ... + Nx);
- // but not using the fold expression to avoid exceeding compiler limits
- size_t total = 0;
- uint sizes[] = { Nx... };
- for (uint n : sizes)
- total += n;
- return total;
- }
+// The maximum Size of a string literal is 2 GB on 32-bit and 4 GB on 64-bit
+// (but the compiler is likely to give up before you get anywhere near that much)
+static constexpr size_t MaxStringSize =
+ (std::min)(size_t((std::numeric_limits<uint>::max)()),
+ size_t((std::numeric_limits<qsizetype>::max)()));
- // The maximum Size of a string literal is 2 GB on 32-bit and 4 GB on 64-bit
- // (but the compiler is likely to give up before you get anywhere near that much)
- static constexpr size_t MaxStringSize =
- (std::min)(size_t((std::numeric_limits<uint>::max)()),
- size_t((std::numeric_limits<qsizetype>::max)()));
+template <uint... Nx> constexpr size_t stringDataSizeHelper(std::integer_sequence<uint, Nx...>)
+{
+ // same as:
+ // return (0 + ... + Nx);
+ // but not using the fold expression to avoid exceeding compiler limits
+ size_t total = 0;
+ uint sizes[] = { Nx... };
+ for (uint n : sizes)
+ total += n;
+ return total;
+}
- static constexpr size_t StringSize = calculateStringSize();
+template <int Count, size_t StringSize> struct StringData
+{
static_assert(StringSize <= MaxStringSize, "Meta Object data is too big");
-
- uint offsetsAndSizes[2 * sizeof...(Nx)] = {};
+ uint offsetsAndSizes[Count] = {};
char stringdata0[StringSize] = {};
constexpr StringData() = default;
};
template <uint... Nx> constexpr auto stringData(const char (&...strings)[Nx])
{
- StringData<Nx...> result;
+ constexpr size_t StringSize = stringDataSizeHelper<Nx...>({});
+ constexpr size_t Count = 2 * sizeof...(Nx);
+
+ StringData<Count, StringSize> result;
const char *inputs[] = { strings... };
uint sizes[] = { Nx... };
@@ -75,10 +76,7 @@ template <uint... Nx> constexpr auto stringData(const char (&...strings)[Nx])
return result;
}
-#if !defined(Q_CC_GNU_ONLY) || Q_CC_GNU_ONLY >= 1000
-// It looks like there's a bug in GCC 9
# define QT_MOC_HAS_STRINGDATA 1
-#endif
} // namespace QtMocHelpers
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp
index 9f9575f517..ec92404a15 100644
--- a/src/corelib/kernel/qtranslator.cpp
+++ b/src/corelib/kernel/qtranslator.cpp
@@ -22,7 +22,7 @@
#include "qendian.h"
#include "qresource.h"
-#if defined(Q_OS_UNIX) && !defined(Q_OS_NACL) && !defined(Q_OS_INTEGRITY)
+#if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY)
# define QT_USE_MMAP
# include "private/qcore_unix_p.h"
// for mmap
@@ -39,8 +39,11 @@
QT_BEGIN_NAMESPACE
+namespace {
enum Tag { Tag_End = 1, Tag_SourceText16, Tag_Translation, Tag_Context16, Tag_Obsolete1,
Tag_SourceText, Tag_Context, Tag_Comment, Tag_Obsolete2 };
+}
+
/*
$ mcookie
3cb86418caef9c95cd211cbf60a1bddd
@@ -627,7 +630,7 @@ static QString find_translation(const QLocale & locale,
// "prefix_en_us.qm" won't be found under the "en_US" locale. Note
// that the Qt resource system is always case-sensitive, even on
// Windows (in other words: this codepath is *not* UNIX-only).
- QStringList languages = locale.uiLanguages();
+ QStringList languages = locale.uiLanguages(QLocale::TagSeparator::Underscore);
for (int i = languages.size()-1; i >= 0; --i) {
QString lang = languages.at(i);
QString lowerLang = lang.toLower();
@@ -636,8 +639,6 @@ static QString find_translation(const QLocale & locale,
}
for (QString localeName : std::as_const(languages)) {
- localeName.replace(u'-', u'_');
-
// try the complete locale name first and progressively truncate from
// the end until a matching language tag is found (with or without suffix)
for (;;) {
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index d799487d3c..92a44c462b 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -47,6 +47,8 @@
#include "qline.h"
#endif
+#include <memory>
+
#include <cmath>
#include <float.h>
#include <cstring>
@@ -171,20 +173,20 @@ static std::optional<qlonglong> qConvertToNumber(const QVariant::Private *d, boo
return std::nullopt;
}
-static std::optional<qreal> qConvertToRealNumber(const QVariant::Private *d)
+static std::optional<double> qConvertToRealNumber(const QVariant::Private *d)
{
bool ok;
switch (d->typeInterface()->typeId) {
case QMetaType::QString:
if (double r = d->get<QString>().toDouble(&ok); ok)
- return qreal(r);
+ return r;
return std::nullopt;
case QMetaType::Double:
- return qreal(d->get<double>());
+ return d->get<double>();
case QMetaType::Float:
- return qreal(d->get<float>());
+ return double(d->get<float>());
case QMetaType::Float16:
- return qreal(d->get<qfloat16>());
+ return double(d->get<qfloat16>());
case QMetaType::ULongLong:
case QMetaType::UInt:
case QMetaType::UChar:
@@ -192,7 +194,7 @@ static std::optional<qreal> qConvertToRealNumber(const QVariant::Private *d)
case QMetaType::Char32:
case QMetaType::UShort:
case QMetaType::ULong:
- return qreal(qMetaTypeUNumber(d));
+ return double(qMetaTypeUNumber(d));
#ifndef QT_BOOTSTRAPPED
case QMetaType::QCborValue:
return d->get<QCborValue>().toDouble();
@@ -202,7 +204,7 @@ static std::optional<qreal> qConvertToRealNumber(const QVariant::Private *d)
default:
// includes enum conversion as well as invalid types
if (std::optional<qlonglong> l = qConvertToNumber(d))
- return qreal(*l);
+ return double(*l);
return std::nullopt;
}
}
@@ -231,9 +233,22 @@ static bool isValidMetaTypeForVariant(const QtPrivate::QMetaTypeInterface *iface
return true;
}
+enum CustomConstructMoveOptions {
+ UseCopy, // custom construct uses the copy ctor unconditionally
+ // future option: TryMove: uses move ctor if available, else copy ctor
+ ForceMove, // custom construct use the move ctor (which must exist)
+};
+
+enum CustomConstructNullabilityOption {
+ MaybeNull, // copy might be null, might be non-null
+ NonNull, // copy is guarantueed to be non-null
+ // future option: AlwaysNull?
+};
+
// the type of d has already been set, but other field are not set
+template <CustomConstructMoveOptions moveOption = UseCopy, CustomConstructNullabilityOption nullability = MaybeNull>
static void customConstruct(const QtPrivate::QMetaTypeInterface *iface, QVariant::Private *d,
- const void *copy)
+ std::conditional_t<moveOption == ForceMove, void *, const void *> copy)
{
using namespace QtMetaTypePrivate;
Q_ASSERT(iface);
@@ -242,6 +257,10 @@ static void customConstruct(const QtPrivate::QMetaTypeInterface *iface, QVariant
Q_ASSERT(isCopyConstructible(iface));
Q_ASSERT(isDestructible(iface));
Q_ASSERT(copy || isDefaultConstructible(iface));
+ if constexpr (moveOption == ForceMove)
+ Q_ASSERT(isMoveConstructible(iface));
+ if constexpr (nullability == NonNull)
+ Q_ASSERT(copy != nullptr);
// need to check for nullptr_t here, as this can get called by fromValue(nullptr). fromValue() uses
// std::addressof(value) which in this case returns the address of the nullptr object.
@@ -251,11 +270,17 @@ static void customConstruct(const QtPrivate::QMetaTypeInterface *iface, QVariant
if (QVariant::Private::canUseInternalSpace(iface)) {
d->is_shared = false;
if (!copy && !iface->defaultCtr)
- return; // default constructor and it's OK to build in 0-filled storage, which we've already done
- construct(iface, d->data.data, copy);
+ return; // trivial default constructor and it's OK to build in 0-filled storage, which we've already done
+ if constexpr (moveOption == ForceMove && nullability == NonNull)
+ moveConstruct(iface, d->data.data, copy);
+ else
+ construct(iface, d->data.data, copy);
} else {
d->data.shared = customConstructShared(iface->size, iface->alignment, [=](void *where) {
- construct(iface, where, copy);
+ if constexpr (moveOption == ForceMove && nullability == NonNull)
+ moveConstruct(iface, where, copy);
+ else
+ construct(iface, where, copy);
});
d->is_shared = true;
}
@@ -299,6 +324,7 @@ static QVariant::Private clonePrivate(const QVariant::Private &other)
\ingroup objectmodel
\ingroup shared
+ \compares equality
Because C++ forbids unions from including types that have
non-default constructors or destructors, most interesting Qt
@@ -491,23 +517,18 @@ void QVariant::create(int type, const void *copy)
*/
void QVariant::create(QMetaType type, const void *copy)
{
- *this = QVariant(type, copy);
+ *this = QVariant::fromMetaType(type, copy);
}
/*!
\fn QVariant::~QVariant()
Destroys the QVariant and the contained object.
-
- Note that subclasses that reimplement clear() should reimplement
- the destructor to call clear(). This destructor calls clear(), but
- because it is the destructor, QVariant::clear() is called rather
- than a subclass's clear().
*/
QVariant::~QVariant()
{
- if ((d.is_shared && !d.data.shared->ref.deref()) || (!d.is_shared))
+ if (!d.is_shared || !d.data.shared->ref.deref())
customClear(&d);
}
@@ -524,6 +545,106 @@ QVariant::QVariant(const QVariant &p)
}
/*!
+ \fn template <typename T, typename... Args, QVariant::if_constructible<T, Args...> = true> QVariant::QVariant(std::in_place_type_t<T>, Args&&... args) noexcept(is_noexcept_constructible<q20::remove_cvref_t<T>, Args...>::value)
+
+ \since 6.6
+ Constructs a new variant containing a value of type \c T. The contained
+ value is is initialized with the arguments
+ \c{std::forward<Args>(args)...}.
+
+ This overload only participates in overload resolution if \c T can be
+ constructed from \a args.
+
+ This constructor is provided for STL/std::any compatibility.
+
+ \overload
+ */
+
+/*!
+
+ \fn template <typename T, typename U, typename... Args, QVariant::if_constructible<T, std::initializer_list<U> &, Args...> = true> explicit QVariant::QVariant(std::in_place_type_t<T>, std::initializer_list<U> il, Args&&... args) noexcept(is_noexcept_constructible<q20::remove_cvref_t<T>, std::initializer_list<U> &, Args... >::value)
+
+ \since 6.6
+ \overload
+ This overload exists to support types with constructors taking an
+ \c initializer_list. It behaves otherwise equivalent to the
+ non-initializer list \c{in_place_type_t} overload.
+*/
+
+
+/*!
+ \fn template <typename T, typename... Args, QVariant::if_constructible<T, Args...> = true> QVariant::emplace(Args&&... args)
+
+ \since 6.6
+ Replaces the object currently held in \c{*this} with an object of
+ type \c{T}, constructed from \a{args}\c{...}. If \c{*this} was non-null,
+ the previously held object is destroyed first.
+ If possible, this method will reuse memory allocated by the QVariant.
+ Returns a reference to the newly-created object.
+ */
+
+/*!
+ \fn template <typename T, typename U, typename... Args, QVariant::if_constructible<T, std::initializer_list<U> &, Args...> = true> QVariant::emplace(std::initializer_list<U> list, Args&&... args)
+
+ \since 6.6
+ \overload
+ This overload exists to support types with constructors taking an
+ \c initializer_list. It behaves otherwise equivalent to the
+ non-initializer list overload.
+*/
+
+QVariant::QVariant(std::in_place_t, QMetaType type) : d(type.iface())
+{
+ // we query the metatype instead of detecting it at compile time
+ // so that we can change relocatability of internal types
+ if (!Private::canUseInternalSpace(type.iface())) {
+ d.data.shared = PrivateShared::create(type.sizeOf(), type.alignOf());
+ d.is_shared = true;
+ }
+}
+
+/*!
+ \internal
+ Returns a pointer to data suitable for placement new
+ of an object of type \a type
+ Changes the variant's metatype to \a type
+ */
+void *QVariant::prepareForEmplace(QMetaType type)
+{
+ /* There are two cases where we can reuse the existing storage
+ (1) The new type fits in QVariant's SBO storage
+ (2) We are using the externally allocated storage, the variant is
+ detached, and the new type fits into the existing storage.
+ In all other cases (3), we cannot reuse the storage.
+ */
+ auto typeFits = [&] {
+ auto newIface = type.iface();
+ auto oldIface = d.typeInterface();
+ auto newSize = PrivateShared::computeAllocationSize(newIface->size, newIface->alignment);
+ auto oldSize = PrivateShared::computeAllocationSize(oldIface->size, oldIface->alignment);
+ return newSize <= oldSize;
+ };
+ if (Private::canUseInternalSpace(type.iface())) { // (1)
+ clear();
+ d.packedType = quintptr(type.iface()) >> 2;
+ return d.data.data;
+ } else if (d.is_shared && isDetached() && typeFits()) { // (2)
+ QtMetaTypePrivate::destruct(d.typeInterface(), d.data.shared->data());
+ // compare QVariant::PrivateShared::create
+ const auto ps = d.data.shared;
+ const auto align = type.alignOf();
+ ps->offset = PrivateShared::computeOffset(ps, align);
+ d.packedType = quintptr(type.iface()) >> 2;
+ return ps->data();
+ }
+ // (3)
+ QVariant newVariant(std::in_place, type);
+ swap(newVariant);
+ // const cast is safe, we're in a non-const method
+ return const_cast<void *>(d.storage());
+}
+
+/*!
\fn QVariant::QVariant(const QString &val) noexcept
Constructs a new variant with a string value, \a val.
@@ -790,27 +911,27 @@ QVariant::QVariant(const QVariant &p)
*/
/*!
- Constructs variant of type \a type, and initializes with
- \a copy if \a copy is not \nullptr.
+ Constructs a variant of type \a type, and initializes it with
+ a copy of \c{*copy} if \a copy is not \nullptr (in which case, \a copy
+ must point to an object of type \a type).
- Note that you have to pass the address of the variable you want stored.
+ Note that you have to pass the address of the object you want stored.
Usually, you never have to use this constructor, use QVariant::fromValue()
instead to construct variants from the pointer types represented by
\c QMetaType::VoidStar, and \c QMetaType::QObjectStar.
- If \a type does not support copy and default construction, the variant will
- be invalid.
+ If \a type does not support copy construction and \a copy is not \nullptr,
+ the variant will be invalid. Similarly, if \a copy is \nullptr and
+ \a type does not support default construction, the variant will be
+ invalid.
- \sa QVariant::fromValue(), QMetaType::Type
+ \sa QVariant::fromMetaType, QVariant::fromValue(), QMetaType::Type
*/
-QVariant::QVariant(QMetaType type, const void *copy) : d(type.iface())
+QVariant::QVariant(QMetaType type, const void *copy)
+ : d()
{
- type.registerType();
- if (isValidMetaTypeForVariant(type.iface(), copy))
- customConstruct(type.iface(), &d, copy);
- else
- d = {};
+ *this = fromMetaType(type, copy);
}
QVariant::QVariant(int val) noexcept : d(std::piecewise_construct_t{}, val) {}
@@ -822,7 +943,9 @@ QVariant::QVariant(double val) noexcept : d(std::piecewise_construct_t{}, val) {
QVariant::QVariant(float val) noexcept : d(std::piecewise_construct_t{}, val) {}
QVariant::QVariant(const QByteArray &val) noexcept : d(std::piecewise_construct_t{}, val) {}
+#ifndef QT_BOOTSTRAPPED
QVariant::QVariant(const QBitArray &val) noexcept : d(std::piecewise_construct_t{}, val) {}
+#endif
QVariant::QVariant(const QString &val) noexcept : d(std::piecewise_construct_t{}, val) {}
QVariant::QVariant(QChar val) noexcept : d(std::piecewise_construct_t{}, val) {}
QVariant::QVariant(const QStringList &val) noexcept : d(std::piecewise_construct_t{}, val) {}
@@ -969,7 +1092,8 @@ void QVariant::detach()
Q_ASSERT(isValidMetaTypeForVariant(d.typeInterface(), constData()));
Private dd(d.typeInterface());
- customConstruct(d.typeInterface(), &dd, constData());
+ // null variant is never shared; anything else is NonNull
+ customConstruct<UseCopy, NonNull>(d.typeInterface(), &dd, constData());
if (!d.data.shared->ref.deref())
customClear(&d);
d.data.shared = dd.data.shared;
@@ -998,7 +1122,7 @@ const char *QVariant::typeName() const
*/
void QVariant::clear()
{
- if ((d.is_shared && !d.data.shared->ref.deref()) || (!d.is_shared))
+ if (!d.is_shared || !d.data.shared->ref.deref())
customClear(&d);
d = {};
}
@@ -1294,12 +1418,14 @@ QDataStream &operator<<(QDataStream &s, const QVariant &p)
}
/*! \fn QDataStream& operator>>(QDataStream &s, QVariant::Type &p)
+ \relates QVariant
\deprecated [6.0] Stream QMetaType::Type instead.
Reads a variant type \a p in enum representation from the stream \a s.
*/
/*! \fn QDataStream& operator<<(QDataStream &s, const QVariant::Type p)
+ \relates QVariant
\deprecated [6.0] Stream QMetaType::Type instead.
Writes a variant type \a p to the stream \a s.
@@ -1720,6 +1846,7 @@ QChar QVariant::toChar() const
return qvariant_cast<QChar>(*this);
}
+#ifndef QT_BOOTSTRAPPED
/*!
Returns the variant as a QBitArray if the variant has userType()
\l QMetaType::QBitArray; otherwise returns an empty bit array.
@@ -1730,6 +1857,7 @@ QBitArray QVariant::toBitArray() const
{
return qvariant_cast<QBitArray>(*this);
}
+#endif // QT_BOOTSTRAPPED
template <typename T>
inline T qNumVariantToHelper(const QVariant::Private &d, bool *ok)
@@ -2025,9 +2153,9 @@ bool QVariant::view(int type, void *ptr)
}
/*!
- \fn bool QVariant::operator==(const QVariant &v1, const QVariant &v2)
+ \fn bool QVariant::operator==(const QVariant &lhs, const QVariant &rhs)
- Returns \c true if \a v1 and \a v2 are equal; otherwise returns \c false.
+ Returns \c true if \a lhs and \a rhs are equal; otherwise returns \c false.
QVariant uses the equality operator of the type() contained to check for
equality.
@@ -2051,9 +2179,9 @@ bool QVariant::view(int type, void *ptr)
*/
/*!
- \fn bool QVariant::operator!=(const QVariant &v1, const QVariant &v2)
+ \fn bool QVariant::operator!=(const QVariant &lhs, const QVariant &rhs)
- Returns \c false if \a v1 and \a v2 are equal; otherwise returns \c true.
+ Returns \c false if \a lhs and \a rhs are equal; otherwise returns \c true.
QVariant uses the equality operator of the type() contained to check for
equality.
@@ -2233,15 +2361,15 @@ static QPartialOrdering numericCompare(const QVariant::Private *d1, const QVaria
if (promotedType != QMetaType::QReal)
return integralCompare(promotedType, d1, d2);
- // qreal comparisons
- std::optional<qreal> r1 = qConvertToRealNumber(d1);
- std::optional<qreal> r2 = qConvertToRealNumber(d2);
+ // floating point comparison
+ const auto r1 = qConvertToRealNumber(d1);
+ const auto r2 = qConvertToRealNumber(d2);
if (!r1 || !r2)
return QPartialOrdering::Unordered;
if (*r1 == *r2)
return QPartialOrdering::Equivalent;
- return spaceShip<qreal>(*r1, *r2);
+ return spaceShip(*r1, *r2);
}
#ifndef QT_BOOTSTRAPPED
@@ -2427,6 +2555,22 @@ QDebug QVariant::qdebugHelper(QDebug dbg) const
return dbg;
}
+QVariant QVariant::moveConstruct(QMetaType type, void *data)
+{
+ QVariant var;
+ var.d = QVariant::Private(type.d_ptr);
+ customConstruct<ForceMove, NonNull>(type.d_ptr, &var.d, data);
+ return var;
+}
+
+QVariant QVariant::copyConstruct(QMetaType type, const void *data)
+{
+ QVariant var;
+ var.d = QVariant::Private(type.d_ptr);
+ customConstruct<UseCopy, NonNull>(type.d_ptr, &var.d, data);
+ return var;
+}
+
#if QT_DEPRECATED_SINCE(6, 0)
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
@@ -2446,7 +2590,7 @@ QT_WARNING_POP
#endif
-/*! \fn template<typename T> void QVariant::setValue(T &&value)
+/*! \fn template<typename T, typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, QVariant>>> void QVariant::setValue(T &&value)
Stores a copy of \a value. If \c{T} is a type that QVariant
doesn't support, QMetaType is used to store the value. A compile
@@ -2459,19 +2603,19 @@ QT_WARNING_POP
\sa value(), fromValue(), canConvert()
*/
-/*! \fn template<typename T> void QVariant::setValue(const QVariant &value)
+/*! \fn void QVariant::setValue(const QVariant &value)
Copies \a value over this QVariant. It is equivalent to simply
assigning \a value to this QVariant.
*/
-/*! \fn template<typename T> void QVariant::setValue(QVariant &&value)
+/*! \fn void QVariant::setValue(QVariant &&value)
Moves \a value over this QVariant. It is equivalent to simply
move assigning \a value to this QVariant.
*/
-/*! \fn template<typename T> T QVariant::value() const
+/*! \fn template<typename T> T QVariant::value() const &
Returns the stored value converted to the template type \c{T}.
Call canConvert() to find out whether a type can be converted.
@@ -2511,7 +2655,7 @@ QT_WARNING_POP
\sa canView(), Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE()
*/
-/*! \fn bool QVariant::canConvert() const
+/*! \fn template<typename T> bool QVariant::canConvert() const
Returns \c true if the variant can be converted to the template type \c{T},
otherwise false.
@@ -2527,7 +2671,7 @@ QT_WARNING_POP
\sa convert()
*/
-/*! \fn bool QVariant::canView() const
+/*! \fn template<typename T> bool QVariant::canView() const
Returns \c true if a mutable view of the template type \c{T} can be created on this variant,
otherwise \c false.
@@ -2547,6 +2691,12 @@ QT_WARNING_POP
\sa setValue(), value()
*/
+/*! \fn template<typename T, QVariant::if_rvalue<T> = true> static QVariant QVariant::fromValue(T &&value)
+
+ \since 6.6
+ \overload
+*/
+
/*! \fn template<typename... Types> QVariant QVariant::fromStdVariant(const std::variant<Types...> &value)
\since 5.11
@@ -2561,6 +2711,47 @@ QT_WARNING_POP
*/
/*!
+ \fn template<typename... Types> QVariant QVariant::fromStdVariant(std::variant<Types...> &&value)
+ \since 6.6
+ \overload
+*/
+
+
+/*!
+ \since 6.7
+
+ Creates a variant of type \a type, and initializes it with
+ a copy of \c{*copy} if \a copy is not \nullptr (in which case, \a copy
+ must point to an object of type \a type).
+
+ Note that you have to pass the address of the object you want stored.
+
+ Usually, you never have to use this constructor, use QVariant::fromValue()
+ instead to construct variants from the pointer types represented by
+ \c QMetaType::VoidStar, and \c QMetaType::QObjectStar.
+
+ If \a type does not support copy construction and \a copy is not \nullptr,
+ the variant will be invalid. Similarly, if \a copy is \nullptr and
+ \a type does not support default construction, the variant will be
+ invalid.
+
+ Returns the QVariant created as described above.
+
+ \sa QVariant::fromValue(), QMetaType::Type
+*/
+QVariant QVariant::fromMetaType(QMetaType type, const void *copy)
+{
+ QVariant result;
+ type.registerType();
+ const auto iface = type.iface();
+ if (isValidMetaTypeForVariant(iface, copy)) {
+ result.d = Private(iface);
+ customConstruct(iface, &result.d, copy);
+ }
+ return result;
+}
+
+/*!
\fn template<typename T> T qvariant_cast(const QVariant &value)
\relates QVariant
@@ -2571,6 +2762,14 @@ QT_WARNING_POP
\sa QVariant::value()
*/
+/*!
+ \fn template<typename T> T QVariant::qvariant_cast(QVariant &&value)
+ \overload
+ \since 6.7
+
+ Returns the given \a value converted to the template type \c{T}.
+*/
+
/*! \fn template<typename T> T qVariantValue(const QVariant &value)
\relates QVariant
\deprecated
diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h
index 50ede63987..d567bcbb7c 100644
--- a/src/corelib/kernel/qvariant.h
+++ b/src/corelib/kernel/qvariant.h
@@ -5,6 +5,7 @@
#define QVARIANT_H
#include <QtCore/qatomic.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qcontainerfwd.h>
#include <QtCore/qmetatype.h>
#ifndef QT_NO_DEBUG_STREAM
@@ -62,6 +63,18 @@ template<> constexpr inline bool qIsRelocatable<QVariant> = true;
}
class Q_CORE_EXPORT QVariant
{
+ template <typename T, typename... Args>
+ using if_constructible = std::enable_if_t<
+ std::conjunction_v<
+ std::is_copy_constructible<q20::remove_cvref_t<T>>,
+ std::is_destructible<q20::remove_cvref_t<T>>,
+ std::is_constructible<q20::remove_cvref_t<T>, Args...>
+ >,
+ bool>;
+
+ template <typename T>
+ using if_rvalue = std::enable_if_t<!std::is_reference_v<T>, bool>;
+
struct CborValueStandIn { qint64 n; void *c; int t; };
public:
struct PrivateShared
@@ -69,6 +82,8 @@ public:
private:
inline PrivateShared() : ref(1) { }
public:
+ static int computeOffset(PrivateShared *ps, size_t align);
+ static size_t computeAllocationSize(size_t size, size_t align);
static PrivateShared *create(size_t size, size_t align);
static void free(PrivateShared *p);
@@ -78,6 +93,7 @@ public:
const void *data() const { return reinterpret_cast<const uchar *>(this) + offset; }
void *data() { return reinterpret_cast<uchar *>(this) + offset; }
};
+
struct Private
{
static constexpr size_t MaxInternalSize = 3 * sizeof(void *);
@@ -204,6 +220,37 @@ public:
explicit QVariant(QMetaType type, const void *copy = nullptr);
QVariant(const QVariant &other);
+private:
+ template <typename T, typename ...Args>
+ using is_noexcept_constructible = std::conjunction<
+ std::bool_constant<Private::CanUseInternalSpace<T>>,
+ std::is_nothrow_constructible<T, Args...>
+ >;
+
+public:
+ template <typename T, typename... Args,
+ if_constructible<T, Args...> = true>
+ explicit QVariant(std::in_place_type_t<T>, Args&&... args)
+ noexcept(is_noexcept_constructible<q20::remove_cvref_t<T>, Args...>::value)
+ : QVariant(std::in_place, QMetaType::fromType<q20::remove_cvref_t<T>>() )
+ {
+ void *data = const_cast<void *>(constData());
+ new (data) T(std::forward<Args>(args)...);
+ }
+
+ template <typename T, typename U, typename... Args,
+ if_constructible<T, std::initializer_list<U> &, Args...> = true>
+ explicit QVariant(std::in_place_type_t<T>, std::initializer_list<U> il, Args&&... args)
+ noexcept(is_noexcept_constructible<q20::remove_cvref_t<T>,
+ std::initializer_list<U> &,
+ Args...
+ >::value)
+ : QVariant(std::in_place, QMetaType::fromType<q20::remove_cvref_t<T>>())
+ {
+ char *data = static_cast<char *>(const_cast<void *>(constData()));
+ new (data) T(il, std::forward<Args>(args)...);
+ }
+
// primitives
QVariant(int i) noexcept;
QVariant(uint ui) noexcept;
@@ -217,7 +264,9 @@ public:
QVariant(QChar qchar) noexcept;
QVariant(QDate date) noexcept;
QVariant(QTime time) noexcept;
+#ifndef QT_BOOTSTRAPPED
QVariant(const QBitArray &bitarray) noexcept;
+#endif
QVariant(const QByteArray &bytearray) noexcept;
QVariant(const QDateTime &datetime) noexcept;
QVariant(const QHash<QString, QVariant> &hash) noexcept;
@@ -326,7 +375,9 @@ public:
float toFloat(bool *ok = nullptr) const;
qreal toReal(bool *ok = nullptr) const;
QByteArray toByteArray() const;
+#ifndef QT_BOOTSTRAPPED
QBitArray toBitArray() const;
+#endif
QString toString() const;
QStringList toStringList() const;
QChar toChar() const;
@@ -401,6 +452,43 @@ public:
{ return d.storage(); }
inline const void *data() const { return constData(); }
+private:
+ template <typename T>
+ void verifySuitableForEmplace()
+ {
+ static_assert(!std::is_reference_v<T>,
+ "QVariant does not support reference types");
+ static_assert(!std::is_const_v<T>,
+ "QVariant does not support const types");
+ static_assert(std::is_copy_constructible_v<T>,
+ "QVariant requires that the type is copyable");
+ static_assert(std::is_destructible_v<T>,
+ "QVariant requires that the type is destructible");
+ }
+
+ template <typename T, typename... Args>
+ T &emplaceImpl(Args&&... args)
+ {
+ verifySuitableForEmplace<T>();
+ auto data = static_cast<T *>(prepareForEmplace(QMetaType::fromType<T>()));
+ return *q20::construct_at(data, std::forward<Args>(args)...);
+ }
+
+public:
+ template <typename T, typename... Args,
+ if_constructible<T, Args...> = true>
+ T &emplace(Args&&... args)
+ {
+ return emplaceImpl<T>(std::forward<Args>(args)...);
+ }
+
+ template <typename T, typename U, typename... Args,
+ if_constructible<T, std::initializer_list<U> &, Args...> = true>
+ T &emplace(std::initializer_list<U> list, Args&&... args)
+ {
+ return emplaceImpl<T>(list, std::forward<Args>(args)...);
+ }
+
template<typename T, typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, QVariant>>>
void setValue(T &&avalue)
{
@@ -425,7 +513,7 @@ public:
}
template<typename T>
- inline T value() const
+ inline T value() const &
{ return qvariant_cast<T>(*this); }
template<typename T>
@@ -437,6 +525,43 @@ public:
}
template<typename T>
+ inline T value() &&
+ { return qvariant_cast<T>(std::move(*this)); }
+
+ template<typename T, if_rvalue<T> = true>
+#ifndef Q_QDOC
+ /* needs is_copy_constructible for variants semantics, is_move_constructible so that moveConstruct works
+ (but copy_constructible implies move_constructble, so don't bother checking)
+ */
+ static inline auto fromValue(T &&value)
+ noexcept(std::is_nothrow_copy_constructible_v<T> && Private::CanUseInternalSpace<T>)
+ -> std::enable_if_t<std::conjunction_v<std::is_copy_constructible<T>,
+ std::is_destructible<T>>, QVariant>
+#else
+ static inline QVariant fromValue(T &&value)
+#endif
+ {
+ // handle special cases
+ using Type = std::remove_cv_t<T>;
+ if constexpr (std::is_null_pointer_v<Type>)
+ return QVariant::fromMetaType(QMetaType::fromType<std::nullptr_t>());
+ else if constexpr (std::is_same_v<Type, QVariant>)
+ return std::forward<T>(value);
+ else if constexpr (std::is_same_v<Type, std::monostate>)
+ return QVariant();
+ QMetaType mt = QMetaType::fromType<Type>();
+ mt.registerType(); // we want the type stored in QVariant to always be registered
+ // T is a forwarding reference, so if T satifies the enable-ifery,
+ // we get this overload even if T is an lvalue reference and thus must check here
+ // Moreover, we only try to move if the type is actually moveable and not if T is const
+ // as in const int i; QVariant::fromValue(std::move(i));
+ if constexpr (std::conjunction_v<std::is_move_constructible<Type>, std::negation<std::is_const<T>>>)
+ return moveConstruct(QMetaType::fromType<Type>(), std::addressof(value));
+ else
+ return copyConstruct(mt, std::addressof(value));
+ }
+
+ template<typename T>
#ifndef Q_QDOC
static inline auto fromValue(const T &value)
noexcept(std::is_nothrow_copy_constructible_v<T> && Private::CanUseInternalSpace<T>)
@@ -447,17 +572,27 @@ public:
{
if constexpr (std::is_null_pointer_v<T>)
return QVariant(QMetaType::fromType<std::nullptr_t>());
+ else if constexpr (std::is_same_v<T, QVariant>)
+ return value;
+ else if constexpr (std::is_same_v<T, std::monostate>)
+ return QVariant();
return QVariant(QMetaType::fromType<T>(), std::addressof(value));
}
template<typename... Types>
static inline QVariant fromStdVariant(const std::variant<Types...> &value)
{
- if (value.valueless_by_exception())
- return QVariant();
- return std::visit([](const auto &arg) { return fromValue(arg); }, value);
+ return fromStdVariantImpl(value);
+ }
+
+ template<typename... Types>
+ static QVariant fromStdVariant(std::variant<Types...> &&value)
+ {
+ return fromStdVariantImpl(std::move(value));
}
+ static QVariant fromMetaType(QMetaType type, const void *copy = nullptr);
+
template<typename T>
bool canConvert() const
{ return canConvert(QMetaType::fromType<T>()); }
@@ -469,10 +604,21 @@ public:
static QPartialOrdering compare(const QVariant &lhs, const QVariant &rhs);
private:
- friend inline bool operator==(const QVariant &a, const QVariant &b)
+ template <typename StdVariant>
+ static QVariant fromStdVariantImpl(StdVariant &&v)
+ {
+ if (Q_UNLIKELY(v.valueless_by_exception()))
+ return QVariant();
+ auto visitor = [](auto &&arg) {
+ return QVariant::fromValue(q23::forward_like<StdVariant>(arg));
+ };
+ return std::visit(visitor, std::forward<StdVariant>(v));
+ }
+
+ friend bool comparesEqual(const QVariant &a, const QVariant &b)
{ return a.equals(b); }
- friend inline bool operator!=(const QVariant &a, const QVariant &b)
- { return !a.equals(b); }
+ Q_DECLARE_EQUALITY_COMPARABLE(QVariant)
+
#ifndef QT_NO_DEBUG_STREAM
template <typename T>
friend auto operator<<(const QDebug &debug, const T &variant) -> std::enable_if_t<std::is_same_v<T, QVariant>, QDebug> {
@@ -514,8 +660,14 @@ private:
Q_MK_GET(const &&)
#undef Q_MK_GET
+ static QVariant moveConstruct(QMetaType type, void *data);
+ static QVariant copyConstruct(QMetaType type, const void *data);
+
template<typename T>
friend inline T qvariant_cast(const QVariant &);
+ template<typename T>
+ friend inline T qvariant_cast(QVariant &&);
+
protected:
Private d;
void create(int type, const void *copy);
@@ -535,6 +687,11 @@ private:
// int variant, so delete this constructor:
QVariant(QMetaType::Type) = delete;
+ // used to setup the QVariant internals for the "real" inplace ctor
+ QVariant(std::in_place_t, QMetaType type);
+ // helper for emplace
+ void *prepareForEmplace(QMetaType type);
+
// These constructors don't create QVariants of the type associated
// with the enum, as expected, but they would create a QVariant of
// type int with the value of the enum value.
@@ -554,18 +711,6 @@ public:
inline const DataPtr &data_ptr() const { return d; }
};
-template<>
-inline QVariant QVariant::fromValue(const QVariant &value)
-{
- return value;
-}
-
-template<>
-inline QVariant QVariant::fromValue(const std::monostate &) noexcept
-{
- return QVariant();
-}
-
inline bool QVariant::isValid() const
{
return d.type().isValid();
@@ -622,14 +767,45 @@ template<typename T> inline T qvariant_cast(const QVariant &v)
return t;
}
+template<typename T> inline T qvariant_cast(QVariant &&v)
+{
+ QMetaType targetType = QMetaType::fromType<T>();
+ if (v.d.type() == targetType) {
+ if constexpr (QVariant::Private::CanUseInternalSpace<T>) {
+ return std::move(*reinterpret_cast<T *>(v.d.data.data));
+ } else {
+ if (v.d.data.shared->ref.loadRelaxed() == 1)
+ return std::move(*reinterpret_cast<T *>(v.d.data.shared->data()));
+ else
+ return v.d.get<T>();
+ }
+ }
+ if constexpr (std::is_same_v<T, QVariant>) {
+ // if the metatype doesn't match, but we want a QVariant, just return the current variant
+ return v;
+ } if constexpr (std::is_same_v<T,std::remove_const_t<std::remove_pointer_t<T>> const *>) {
+ // moving a pointer is pointless, just do the same as the const & overload
+ using nonConstT = std::remove_const_t<std::remove_pointer_t<T>> *;
+ QMetaType nonConstTargetType = QMetaType::fromType<nonConstT>();
+ if (v.d.type() == nonConstTargetType)
+ return v.d.get<nonConstT>();
+ }
+
+ T t{};
+ QMetaType::convert(v.metaType(), v.constData(), targetType, &t);
+ return t;
+}
+
+# ifndef QT_NO_VARIANT
template<> inline QVariant qvariant_cast<QVariant>(const QVariant &v)
{
if (v.metaType().id() == QMetaType::QVariant)
return *reinterpret_cast<const QVariant *>(v.constData());
return v;
}
+# endif
-#endif
+#endif // QT_MOC
#ifndef QT_NO_DEBUG_STREAM
#if QT_DEPRECATED_SINCE(6, 0)
diff --git a/src/corelib/kernel/qvariant_p.h b/src/corelib/kernel/qvariant_p.h
index f5f4d0fb8a..d2a7390938 100644
--- a/src/corelib/kernel/qvariant_p.h
+++ b/src/corelib/kernel/qvariant_p.h
@@ -19,8 +19,7 @@
QT_BEGIN_NAMESPACE
-template <typename F> static QVariant::PrivateShared *
-customConstructShared(size_t size, size_t align, F &&construct)
+inline auto customConstructSharedImpl(size_t size, size_t align)
{
struct Deleter {
void operator()(QVariant::PrivateShared *p) const
@@ -30,11 +29,23 @@ customConstructShared(size_t size, size_t align, F &&construct)
// this is exception-safe
std::unique_ptr<QVariant::PrivateShared, Deleter> ptr;
ptr.reset(QVariant::PrivateShared::create(size, align));
+ return ptr;
+}
+
+template <typename F> static QVariant::PrivateShared *
+customConstructShared(size_t size, size_t align, F &&construct)
+{
+ auto ptr = customConstructSharedImpl(size, align);
construct(ptr->data());
return ptr.release();
}
-inline QVariant::PrivateShared *QVariant::PrivateShared::create(size_t size, size_t align)
+inline int QVariant::PrivateShared::computeOffset(PrivateShared *ps, size_t align)
+{
+ return int(((quintptr(ps) + sizeof(PrivateShared) + align - 1) & ~(align - 1)) - quintptr(ps));
+}
+
+inline size_t QVariant::PrivateShared::computeAllocationSize(size_t size, size_t align)
{
size += sizeof(PrivateShared);
if (align > sizeof(PrivateShared)) {
@@ -44,9 +55,15 @@ inline QVariant::PrivateShared *QVariant::PrivateShared::create(size_t size, siz
// alignment.
size += align - sizeof(PrivateShared);
}
+ return size;
+}
+
+inline QVariant::PrivateShared *QVariant::PrivateShared::create(size_t size, size_t align)
+{
+ size = computeAllocationSize(size, align);
void *data = operator new(size);
auto *ps = new (data) QVariant::PrivateShared();
- ps->offset = int(((quintptr(ps) + sizeof(PrivateShared) + align - 1) & ~(align - 1)) - quintptr(ps));
+ ps->offset = computeOffset(ps, align);
return ps;
}
diff --git a/src/corelib/kernel/qwineventnotifier.cpp b/src/corelib/kernel/qwineventnotifier.cpp
index cac29b68bb..afbf4227dc 100644
--- a/src/corelib/kernel/qwineventnotifier.cpp
+++ b/src/corelib/kernel/qwineventnotifier.cpp
@@ -248,3 +248,5 @@ void QWinEventNotifierPrivate::waitCallback(PTP_CALLBACK_INSTANCE instance, PVOI
}
QT_END_NAMESPACE
+
+#include "moc_qwineventnotifier.cpp"
diff --git a/src/corelib/kernel/qwinregistry.cpp b/src/corelib/kernel/qwinregistry.cpp
index dc5252f9d1..d237316577 100644
--- a/src/corelib/kernel/qwinregistry.cpp
+++ b/src/corelib/kernel/qwinregistry.cpp
@@ -125,10 +125,10 @@ QString QWinRegistryKey::stringValue(QStringView subKey) const
return value<QString>(subKey).value_or(QString());
}
-QPair<DWORD, bool> QWinRegistryKey::dwordValue(QStringView subKey) const
+std::pair<DWORD, bool> QWinRegistryKey::dwordValue(QStringView subKey) const
{
const std::optional<DWORD> val = value<DWORD>(subKey);
- return qMakePair(val.value_or(0), val.has_value());
+ return {val.value_or(0), val.has_value()};
}
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qwinregistry_p.h b/src/corelib/kernel/qwinregistry_p.h
index 0de1bfe0f5..20b2d10dd7 100644
--- a/src/corelib/kernel/qwinregistry_p.h
+++ b/src/corelib/kernel/qwinregistry_p.h
@@ -58,7 +58,7 @@ public:
// ### TODO: Remove once all usages are migrated to new interface.
QString stringValue(QStringView subKey) const;
- QPair<DWORD, bool> dwordValue(QStringView subKey) const;
+ std::pair<DWORD, bool> dwordValue(QStringView subKey) const;
private:
HKEY m_key = nullptr;
diff --git a/src/corelib/mimetypes/mime/packages/freedesktop.org.xml b/src/corelib/mimetypes/mime/packages/freedesktop.org.xml
index c91170b523..b7aa6a1995 100644
--- a/src/corelib/mimetypes/mime/packages/freedesktop.org.xml
+++ b/src/corelib/mimetypes/mime/packages/freedesktop.org.xml
@@ -12,7 +12,7 @@
<!ATTLIST icon name CDATA #REQUIRED>
<!-- a generic icon name as per the Icon Naming Specification, only required if computing
it from the mime-type would not work, See "generic-icon" in the Shared Mime Specification --><!ELEMENT generic-icon EMPTY>
-<!ATTLIST generic-icon name (application-x-executable | audio-x-generic | folder | font-x-generic | image-x-generic | package-x-generic | text-html | text-x-generic | text-x-generic-template | text-x-script | video-x-generic | x-office-address-book | x-office-calendar | x-office-document | x-office-presentation | x-office-spreadsheet) #REQUIRED>
+<!ATTLIST generic-icon name (application-x-executable | audio-x-generic | emblem-symbolic-link | folder | font-x-generic | image-x-generic | media-floppy | media-optical | package-x-generic | text-html | text-x-generic | text-x-generic-template | text-x-script | video-x-generic | x-office-address-book | x-office-calendar | x-office-document | x-office-presentation | x-office-spreadsheet) #REQUIRED>
<!ELEMENT glob EMPTY>
<!ATTLIST glob pattern CDATA #REQUIRED>
<!ATTLIST glob weight CDATA "50">
@@ -67,28 +67,36 @@ command to generate the output files.
<comment xml:lang="tr">Atari 2600 ROM</comment>
<comment xml:lang="sv">Atari 2600-rom</comment>
<comment xml:lang="sr">Атари 2600 РОМ</comment>
+ <comment xml:lang="sq">ROM Atari 2600</comment>
<comment xml:lang="sl">Atari 2600 ROM</comment>
+ <comment xml:lang="si">Atari 2600 ROM</comment>
+ <comment xml:lang="ru">Atari 2600 ROM</comment>
<comment xml:lang="pt_BR">ROM do Atari 2600</comment>
<comment xml:lang="pt">ROM Atari 2600</comment>
<comment xml:lang="pl">Plik ROM konsoli Atari 2600</comment>
+ <comment xml:lang="nl">Atari 2600-ROM</comment>
<comment xml:lang="ko">아타리 2600 롬</comment>
<comment xml:lang="kk">Atari 2600 ROM</comment>
+ <comment xml:lang="ka">Atari 2600 ROM</comment>
<comment xml:lang="ja">Atari 2600 ROM</comment>
<comment xml:lang="it">ROM Atari 2600</comment>
+ <comment xml:lang="is">Atari 2600 ROM</comment>
<comment xml:lang="id">Atari 2600 ROM</comment>
<comment xml:lang="hu">Atari 2600 ROM</comment>
<comment xml:lang="hr">Atari 2600 ROM</comment>
<comment xml:lang="he">Atari 2600 ROM</comment>
+ <comment xml:lang="gl">ROM de Atari 2600</comment>
<comment xml:lang="fur">ROM Atari 2600</comment>
<comment xml:lang="fr">ROM Atari 2600</comment>
<comment xml:lang="fi">Atari 2600 -ROM</comment>
<comment xml:lang="eu">Atari 2600 ROMa</comment>
<comment xml:lang="es">ROM de Atari 2600</comment>
<comment xml:lang="en_GB">Atari 2600 ROM</comment>
- <comment xml:lang="de">Atari 2600 ROM</comment>
+ <comment xml:lang="de">Atari-2600-ROM</comment>
<comment xml:lang="da">Atari 2600-ROM</comment>
<comment xml:lang="ca">ROM d'Atari 2600</comment>
<comment xml:lang="bg">ROM — Atari 2600</comment>
+ <comment xml:lang="be">Atari 2600 ROM</comment>
<comment xml:lang="ar">روم Atari 2600</comment>
<generic-icon name="application-x-executable"/>
<glob pattern="*.a26"/>
@@ -101,28 +109,36 @@ command to generate the output files.
<comment xml:lang="tr">Atari 7800 ROM</comment>
<comment xml:lang="sv">Atari 7800-rom</comment>
<comment xml:lang="sr">Атари 7800 РОМ</comment>
+ <comment xml:lang="sq">ROM Atari 7800</comment>
<comment xml:lang="sl">Atari 7800 ROM</comment>
+ <comment xml:lang="si">Atari 7800 ROM</comment>
+ <comment xml:lang="ru">Atari 7800 ROM</comment>
<comment xml:lang="pt_BR">ROM do Atari 7800</comment>
<comment xml:lang="pt">ROM Atari 7800</comment>
<comment xml:lang="pl">Plik ROM konsoli Atari 7800</comment>
+ <comment xml:lang="nl">Atari 7800-ROM</comment>
<comment xml:lang="ko">아타리 7800 롬</comment>
<comment xml:lang="kk">Atari 7800 ROM</comment>
+ <comment xml:lang="ka">Atari 7800 ROM</comment>
<comment xml:lang="ja">Atari 7800 ROM</comment>
<comment xml:lang="it">ROM Atari 7800</comment>
+ <comment xml:lang="is">Atari 7800 ROM</comment>
<comment xml:lang="id">Atari 7800 ROM</comment>
<comment xml:lang="hu">Atari 7800 ROM</comment>
<comment xml:lang="hr">Atari 7800 ROM</comment>
<comment xml:lang="he">Atari 7800 ROM</comment>
+ <comment xml:lang="gl">ROM de Atari 7800</comment>
<comment xml:lang="fur">ROM Atari 7800</comment>
<comment xml:lang="fr">ROM Atari 7800</comment>
<comment xml:lang="fi">Atari 7800 -ROM</comment>
<comment xml:lang="eu">Atari 7800 ROMa</comment>
<comment xml:lang="es">ROM de Atari 7800</comment>
<comment xml:lang="en_GB">Atari 7800 ROM</comment>
- <comment xml:lang="de">Atari 7800 ROM</comment>
+ <comment xml:lang="de">Atari-7800-ROM</comment>
<comment xml:lang="da">Atari 7800-ROM</comment>
<comment xml:lang="ca">ROM d'Atari 7800</comment>
<comment xml:lang="bg">ROM — Atari 7800</comment>
+ <comment xml:lang="be">Atari 7800 ROM</comment>
<comment xml:lang="ar">روم Atari 7800</comment>
<generic-icon name="application-x-executable"/>
<glob pattern="*.a78"/>
@@ -138,28 +154,36 @@ command to generate the output files.
<comment xml:lang="tr">Atari Lynx ROM</comment>
<comment xml:lang="sv">Atari Lynx-rom</comment>
<comment xml:lang="sr">Атари Линкс РОМ</comment>
+ <comment xml:lang="sq">ROM Atari Lynx</comment>
<comment xml:lang="sl">Atari Lynx ROM</comment>
+ <comment xml:lang="si">Atari Lynx ROM</comment>
+ <comment xml:lang="ru">Atari Lynx ROM</comment>
<comment xml:lang="pt_BR">ROM do Atari Lynx</comment>
<comment xml:lang="pt">ROM Atari Lynx</comment>
<comment xml:lang="pl">Plik ROM konsoli Atari Lynx</comment>
+ <comment xml:lang="nl">Atari Lynx-ROM</comment>
<comment xml:lang="ko">아타리 링스 롬</comment>
<comment xml:lang="kk">Atari Lynx ROM</comment>
+ <comment xml:lang="ka">Atari Lynx ROM</comment>
<comment xml:lang="ja">Atari Lynx ROM</comment>
<comment xml:lang="it">ROM Atari Lynx</comment>
+ <comment xml:lang="is">Atari Lynx ROM</comment>
<comment xml:lang="id">Atari Lynx ROM</comment>
<comment xml:lang="hu">Atari Lynx ROM</comment>
<comment xml:lang="hr">Atari Lynx ROM</comment>
<comment xml:lang="he">Atari Lynx ROM</comment>
+ <comment xml:lang="gl">ROM de Atari Lynx</comment>
<comment xml:lang="fur">ROM Atari Lynx</comment>
<comment xml:lang="fr">ROM Atari Lynx</comment>
<comment xml:lang="fi">Atari Lynx -ROM</comment>
<comment xml:lang="eu">Atari Lynx ROMa</comment>
<comment xml:lang="es">ROM de Atari Lynx</comment>
<comment xml:lang="en_GB">Atari Lynx ROM</comment>
- <comment xml:lang="de">Atari Lynx ROM</comment>
+ <comment xml:lang="de">Atari-Lynx-ROM</comment>
<comment xml:lang="da">Atari Lynx-ROM</comment>
<comment xml:lang="ca">ROM d'Atari Lynx</comment>
<comment xml:lang="bg">ROM — Atari Lynx</comment>
+ <comment xml:lang="be">Atari Lynx ROM</comment>
<comment xml:lang="ar">روم Atari Lynx</comment>
<generic-icon name="application-x-executable"/>
<glob pattern="*.lnx"/>
@@ -176,8 +200,8 @@ command to generate the output files.
<comment xml:lang="tr">ATK iç metni</comment>
<comment xml:lang="sv">ATK-inlägg</comment>
<comment xml:lang="sr">АТК уметак</comment>
- <comment xml:lang="sq">Inset ATK</comment>
<comment xml:lang="sl">Vložka ATK</comment>
+ <comment xml:lang="si">ATK ඇතුළු කිරීම</comment>
<comment xml:lang="sk">Vložka ATK</comment>
<comment xml:lang="ru">Вкладка ATK</comment>
<comment xml:lang="ro">Inset ATK</comment>
@@ -190,10 +214,11 @@ command to generate the output files.
<comment xml:lang="nb">ATK-innsats</comment>
<comment xml:lang="lv">ATK ielaidums</comment>
<comment xml:lang="lt">ATK inset</comment>
- <comment xml:lang="ko">ATK inset</comment>
+ <comment xml:lang="ko">ATK 인세트</comment>
<comment xml:lang="kk">ATK беті</comment>
<comment xml:lang="ja">ATK インセット</comment>
<comment xml:lang="it">Inset ATK</comment>
+ <comment xml:lang="is">ATK innfelling</comment>
<comment xml:lang="id">Inset ATK</comment>
<comment xml:lang="ia">Folio intercalari ATK</comment>
<comment xml:lang="hu">ATK betét</comment>
@@ -215,6 +240,7 @@ command to generate the output files.
<comment xml:lang="ca">ATK inset</comment>
<comment xml:lang="bg">Притурка — ATK</comment>
<comment xml:lang="be@latin">Ustaŭka ATK</comment>
+ <comment xml:lang="be">устаўка ATK</comment>
<comment xml:lang="ar">شكل ATK</comment>
<acronym>ATK</acronym>
<expanded-acronym>Andrew Toolkit</expanded-acronym>
@@ -222,55 +248,21 @@ command to generate the output files.
<glob pattern="*.ez"/>
</mime-type>
<mime-type type="application/epub+zip">
- <comment>electronic book document</comment>
+ <comment>Electronic book document</comment>
<comment xml:lang="zh_TW">電子書文件</comment>
- <comment xml:lang="zh_CN">电子书文档</comment>
- <comment xml:lang="vi">tài liệu cuốn sách điện tử</comment>
<comment xml:lang="uk">документ електронної книги</comment>
- <comment xml:lang="tr">elektronik kitap belgesi</comment>
- <comment xml:lang="sv">elektroniskt bokdokument</comment>
- <comment xml:lang="sr">документ електронске књиге</comment>
+ <comment xml:lang="sv">Elektroniskt bokdokument</comment>
<comment xml:lang="sq">Dokument libri elektronik</comment>
- <comment xml:lang="sl">dokument elektronske knjige</comment>
- <comment xml:lang="sk">Dokument elektronickej knihy</comment>
- <comment xml:lang="ru">Электронная книга</comment>
- <comment xml:lang="ro">document carte electronică</comment>
+ <comment xml:lang="ru">Документ электронной книги</comment>
<comment xml:lang="pt_BR">Documento de livro eletrônico</comment>
- <comment xml:lang="pt">documento de livro eletrónico</comment>
<comment xml:lang="pl">Dokument książki elektronicznej</comment>
- <comment xml:lang="oc">document libre electronic</comment>
- <comment xml:lang="nn">elektronisk bok-dokument</comment>
- <comment xml:lang="nl">elektronisch boek</comment>
- <comment xml:lang="lv">elektroniskās grāmatas dokuments</comment>
- <comment xml:lang="lt">elektroninės knygos dokumentas</comment>
- <comment xml:lang="ko">전자책 문서</comment>
- <comment xml:lang="kk">электронды кітабы</comment>
- <comment xml:lang="ja">電子ブックドキュメント</comment>
+ <comment xml:lang="ja">電子書籍</comment>
<comment xml:lang="it">Documento libro elettronico</comment>
- <comment xml:lang="id">dokumen buku elektronik</comment>
- <comment xml:lang="ia">Documento de libro electronic</comment>
- <comment xml:lang="hu">elektronikus könyvdokumentum</comment>
- <comment xml:lang="hr">Dokument elektroničke knjige</comment>
- <comment xml:lang="he">מסמך מסוג ספר אלקטרוני</comment>
- <comment xml:lang="gl">documento de libro electrónico</comment>
- <comment xml:lang="ga">leabhar leictreonach</comment>
- <comment xml:lang="fur">document libri eletronic</comment>
- <comment xml:lang="fr">document livre électronique</comment>
- <comment xml:lang="fo">elektroniskbóka skjal</comment>
- <comment xml:lang="fi">elektroninen kirja</comment>
- <comment xml:lang="eu">liburu elektronikoaren dokumentua</comment>
+ <comment xml:lang="gl">Documento de libro electrónico</comment>
+ <comment xml:lang="eu">Liburu elektronikoa</comment>
<comment xml:lang="es">documento de libro electrónico</comment>
- <comment xml:lang="en_GB">electronic book document</comment>
- <comment xml:lang="el">Έγγραφο ηλεκτρονικού βιβλίου</comment>
- <comment xml:lang="de">Elektronisches Buch</comment>
- <comment xml:lang="da">elektronisk bogdokument</comment>
- <comment xml:lang="cs">dokument elektronické knihy</comment>
- <comment xml:lang="ca">document de llibre electrònic</comment>
- <comment xml:lang="bg">Документ — електронна книга</comment>
- <comment xml:lang="be@latin">elektronnaja kniha</comment>
- <comment xml:lang="ast">documentu de llibru electrónicu</comment>
- <comment xml:lang="ar">مستند كتاب إلكتروني</comment>
- <comment xml:lang="af">elektronieseboekdokument</comment>
+ <comment xml:lang="de">E-Book</comment>
+ <comment xml:lang="be">электроннай кніга</comment>
<sub-class-of type="application/zip"/>
<generic-icon name="x-office-document"/>
<magic priority="70">
@@ -291,27 +283,35 @@ command to generate the output files.
<comment xml:lang="tr">Kindle kitap belgesi</comment>
<comment xml:lang="sv">Kindle-bokdokument</comment>
<comment xml:lang="sr">Документ Киндл књиге</comment>
+ <comment xml:lang="sq">dokument libri Kindle</comment>
<comment xml:lang="sl">Dokument knjige Kindle</comment>
- <comment xml:lang="ru">Электронная книга Kindle</comment>
+ <comment xml:lang="si">Kindle පොත් ලේඛනය</comment>
+ <comment xml:lang="ru">Документ электронной книги Kindle</comment>
<comment xml:lang="pt_BR">Documento livro do Kindle</comment>
<comment xml:lang="pt">documento de livro eletrónico do Kindle</comment>
<comment xml:lang="pl">Dokument książki Kindle</comment>
+ <comment xml:lang="oc">document libre Kindle</comment>
+ <comment xml:lang="nl">Kindle-boekdocument</comment>
<comment xml:lang="lt">Kindle knygos dokumentas</comment>
<comment xml:lang="ko">Kindle 책 문서</comment>
<comment xml:lang="kk">Kindle кітап құжаты</comment>
<comment xml:lang="ja">キンドルブックドキュメント</comment>
<comment xml:lang="it">Documento libro Kindle</comment>
+ <comment xml:lang="is">Kindle rafbókarskjal</comment>
<comment xml:lang="id">Dokumen buku Kindle</comment>
<comment xml:lang="hu">Kindle könyvdokumentum</comment>
<comment xml:lang="hr">Dokument Kindle knjige</comment>
<comment xml:lang="he">מסמך ספר Kindle</comment>
+ <comment xml:lang="gl">Documento de libro de Kindle</comment>
<comment xml:lang="fr">document livre Kindle</comment>
<comment xml:lang="fi">Kindle book -asiakirja</comment>
+ <comment xml:lang="eu">Kindle liburu-dokumentua</comment>
<comment xml:lang="es">documento de libro de Kindle</comment>
<comment xml:lang="en_GB">Kindle book document</comment>
- <comment xml:lang="de">Kindle-Buch-Dokument</comment>
+ <comment xml:lang="de">Kindle E-Book</comment>
<comment xml:lang="da">Kindle-bogdokument</comment>
<comment xml:lang="ca">document de llibre Kindle</comment>
+ <comment xml:lang="be">дакумент кнігі Kindle</comment>
<comment xml:lang="ar">مستند كتاب كندل</comment>
<sub-class-of type="application/x-mobipocket-ebook"/>
<glob pattern="*.azw3"/>
@@ -327,8 +327,9 @@ command to generate the output files.
<comment xml:lang="tr">Adobe Illustrator belgesi</comment>
<comment xml:lang="sv">Adobe Illustrator-dokument</comment>
<comment xml:lang="sr">документ Адобе илустратора</comment>
- <comment xml:lang="sq">Dokument Adobe Illustrator</comment>
+ <comment xml:lang="sq">dokument Adobe Illustrator</comment>
<comment xml:lang="sl">Dokument Adobe Illustrator</comment>
+ <comment xml:lang="si">Adobe Illustrator ලේඛනය</comment>
<comment xml:lang="sk">Dokument Adobe Illustrator</comment>
<comment xml:lang="ru">Документ Adobe Illustrator</comment>
<comment xml:lang="ro">Document Adobe Illustrator</comment>
@@ -347,6 +348,7 @@ command to generate the output files.
<comment xml:lang="ka">Adobe Illustrator-ის დოკუმენტი</comment>
<comment xml:lang="ja">Adobe Illustrator ドキュメント</comment>
<comment xml:lang="it">Documento Adobe Illustrator</comment>
+ <comment xml:lang="is">Adobe Illustrator skjal</comment>
<comment xml:lang="id">Dokumen Adobe Illustrator</comment>
<comment xml:lang="ia">Documento Adobe Illustrator</comment>
<comment xml:lang="hu">Adobe Illustrator-dokumentum</comment>
@@ -369,6 +371,7 @@ command to generate the output files.
<comment xml:lang="ca">document d'Adobe Illustrator</comment>
<comment xml:lang="bg">Документ — Adobe Illustrator</comment>
<comment xml:lang="be@latin">Dakument Adobe Illustrator</comment>
+ <comment xml:lang="be">дакумент Adobe Illustrator</comment>
<comment xml:lang="ast">Documentu d'Adobe Illustrator</comment>
<comment xml:lang="ar">مستند أدوبي إليستريتور</comment>
<comment xml:lang="af">Adobe Illustrator-dokument</comment>
@@ -385,10 +388,11 @@ command to generate the output files.
<comment xml:lang="tr">Macintosh BinHex-şifreli dosya</comment>
<comment xml:lang="sv">Macintosh BinHex-kodad fil</comment>
<comment xml:lang="sr">Мекинтошова БинХекс-кодирана датотека</comment>
- <comment xml:lang="sq">File Macintosh i kodifikuar BinHex</comment>
+ <comment xml:lang="sq">kartelë Macintosh koduar me BinHex</comment>
<comment xml:lang="sl">Kodirana datoteka Macintosh (BinHex)</comment>
+ <comment xml:lang="si">Macintosh BinHex-කේතනය කළ ගොනුව</comment>
<comment xml:lang="sk">Súbor kódovaný pomocou Macintosh BinHex</comment>
- <comment xml:lang="ru">Файл (закодированный Macintosh BinHex)</comment>
+ <comment xml:lang="ru">Файл Macintosh закодированный BinHex</comment>
<comment xml:lang="ro">Fișier codat Macintosh BinHex</comment>
<comment xml:lang="pt_BR">Arquivo do Macintosh codificado com BinHex</comment>
<comment xml:lang="pt">ficheiro codificado em BinHex de Macintosh</comment>
@@ -404,6 +408,7 @@ command to generate the output files.
<comment xml:lang="kk">Macintosh BinHex кодталған файлы</comment>
<comment xml:lang="ja">Macintosh BinHex エンコードファイル</comment>
<comment xml:lang="it">File Macintosh codificato BinHex</comment>
+ <comment xml:lang="is">Macintosh BinHex-kóðuð skrá</comment>
<comment xml:lang="id">Berkas tersandi Macintosh BinHex</comment>
<comment xml:lang="ia">File codificate in BinHex de Macintosh</comment>
<comment xml:lang="hu">Macintosh BinHex kódolású fájl</comment>
@@ -420,21 +425,25 @@ command to generate the output files.
<comment xml:lang="eo">dosiero kodigita laŭ Macintosh BinHex</comment>
<comment xml:lang="en_GB">Macintosh BinHex-encoded file</comment>
<comment xml:lang="el">Αρχείο Macintosh κωδικοποίησης BinHex</comment>
- <comment xml:lang="de">Macintosh-Datei (BinHex-kodiert)</comment>
+ <comment xml:lang="de">Macintosh-Datei (BinHex-verschlüsselt)</comment>
<comment xml:lang="da">Macintosh BinHex-kodet fil</comment>
<comment xml:lang="cy">Ffeil BinHex-amgodwyd Macintosh</comment>
<comment xml:lang="cs">soubor kódovaný pomocí Macintosh BinHex</comment>
<comment xml:lang="ca">fitxer amb codificació BinHex de Macintosh</comment>
<comment xml:lang="bg">Файл — кодиран във формат BinHex за Macintosh</comment>
<comment xml:lang="be@latin">Fajł Macintosh, BinHex-zakadavany</comment>
+ <comment xml:lang="be">файл з кадаваннем Macintosh BinHex</comment>
<comment xml:lang="az">Macintosh BinHex-kodlanmış fayl</comment>
<comment xml:lang="ast">Ficheru codificáu en BinHex de Machintosh</comment>
<comment xml:lang="ar">ملف Macintosh BinHex مشفر</comment>
<comment xml:lang="af">Macintosh BinHex-geënkodeerde lêer</comment>
+ <sub-class-of type="text/plain"/>
<generic-icon name="package-x-generic"/>
<magic>
- <match type="string" value="must be converted with BinHex" offset="11"/>
+ <match type="string" value="(This file must be converted with BinHex 4.0)" offset="0"/>
+ <match type="string" value="(This file must be converted; you knew that already.)" offset="0"/>
</magic>
+ <glob pattern="*.hqx"/>
</mime-type>
<mime-type type="application/mathematica">
<comment>Mathematica Notebook file</comment>
@@ -443,19 +452,25 @@ command to generate the output files.
<comment xml:lang="uk">файл нотатника Mathematica</comment>
<comment xml:lang="tr">Mathematica Notebook dosyası</comment>
<comment xml:lang="sv">Mathematica-anteckningsboksfil</comment>
+ <comment xml:lang="sq">kartelë Mathematica Notebook</comment>
<comment xml:lang="sl">Datoteka Mathematica Notebook</comment>
+ <comment xml:lang="si">Mathematica Notebook ගොනුව</comment>
<comment xml:lang="ru">Файл Mathematica Notebook</comment>
<comment xml:lang="pt_BR">Arquivo Notebook do Mathematica</comment>
<comment xml:lang="pt">ficheiro de Mathematica Notebook do Wolfram</comment>
<comment xml:lang="pl">Plik notatnika Mathematica</comment>
+ <comment xml:lang="nl">Mathematica Notebook-bestand</comment>
<comment xml:lang="ko">Mathematica 기록장 파일</comment>
<comment xml:lang="kk">Mathematica блокнот файлы</comment>
+ <comment xml:lang="ka">Mathematica Notebook-ის ფაილი</comment>
<comment xml:lang="ja">Mathematica ノートブックファイル</comment>
<comment xml:lang="it">File Mathematica Notebook</comment>
+ <comment xml:lang="is">Mathematica Notebook skrá</comment>
<comment xml:lang="id">Berkas Mathematica Notebook</comment>
<comment xml:lang="hu">Mathematica munkafüzetfájl</comment>
<comment xml:lang="hr">Mathematica Notebook datoteka</comment>
<comment xml:lang="he">קובץ מחברת של Mathematica</comment>
+ <comment xml:lang="gl">Ficheiro de caderno de Mathematica</comment>
<comment xml:lang="fr">fichier carnet Mathematica</comment>
<comment xml:lang="fi">Mathematica Notebook -tiedosto</comment>
<comment xml:lang="eu">Mathematica Notebook fitxategia</comment>
@@ -465,6 +480,7 @@ command to generate the output files.
<comment xml:lang="da">Mathematica Notebook-fil</comment>
<comment xml:lang="ca">llibreta de Mathematica Notebook</comment>
<comment xml:lang="bg">Скицник — Mathematica</comment>
+ <comment xml:lang="be">файл Mathematica Notebook</comment>
<comment xml:lang="ar">ملف دفتر ماثماتيكا</comment>
<sub-class-of type="text/plain"/>
<generic-icon name="x-office-document"/>
@@ -485,8 +501,9 @@ command to generate the output files.
<comment xml:lang="tr">MathML belgesi</comment>
<comment xml:lang="sv">MathML-dokument</comment>
<comment xml:lang="sr">МатМЛ документ</comment>
- <comment xml:lang="sq">Dokument MathML</comment>
+ <comment xml:lang="sq">dokument MathML</comment>
<comment xml:lang="sl">Dokument MathML</comment>
+ <comment xml:lang="si">MathML ලේඛනය</comment>
<comment xml:lang="sk">Dokument MathML</comment>
<comment xml:lang="ru">Документ MathML</comment>
<comment xml:lang="ro">Document MathML</comment>
@@ -505,6 +522,7 @@ command to generate the output files.
<comment xml:lang="ka">MathML-ის დოკუმენტი</comment>
<comment xml:lang="ja">MathML ドキュメント</comment>
<comment xml:lang="it">Documento MathML</comment>
+ <comment xml:lang="is">MathML skjal</comment>
<comment xml:lang="id">Dokumen MathML</comment>
<comment xml:lang="ia">Documento MathML</comment>
<comment xml:lang="hu">MathML-dokumentum</comment>
@@ -528,6 +546,7 @@ command to generate the output files.
<comment xml:lang="ca">document MathML</comment>
<comment xml:lang="bg">Документ — MathML</comment>
<comment xml:lang="be@latin">Dakument MathML</comment>
+ <comment xml:lang="be">дакумент MathML</comment>
<comment xml:lang="az">MathML sənədi</comment>
<comment xml:lang="ast">Documentu MathML</comment>
<comment xml:lang="ar">مستند MathML</comment>
@@ -540,55 +559,20 @@ command to generate the output files.
<root-XML namespaceURI="http://www.w3.org/1998/Math/MathML" localName="math"/>
</mime-type>
<mime-type type="application/mbox">
- <comment>mailbox file</comment>
- <comment xml:lang="zh_TW">郵箱檔</comment>
- <comment xml:lang="zh_CN">邮箱文件</comment>
- <comment xml:lang="vi">tập tin hộp thư</comment>
+ <comment>Mailbox file</comment>
<comment xml:lang="uk">файл поштової скриньки</comment>
- <comment xml:lang="tr">mailbox dosyası</comment>
- <comment xml:lang="sv">brevlådefil</comment>
- <comment xml:lang="sr">датотека поштанског сандучета</comment>
- <comment xml:lang="sq">File mailbox</comment>
- <comment xml:lang="sl">datoteka poštnega predala</comment>
- <comment xml:lang="sk">Súbor mailbox</comment>
+ <comment xml:lang="sv">Brevlådefil</comment>
+ <comment xml:lang="sq">Kartelë kutie email-esh</comment>
<comment xml:lang="ru">Файл почтового ящика</comment>
- <comment xml:lang="ro">fișier căsuță poștală</comment>
<comment xml:lang="pt_BR">Arquivo de caixa de correio</comment>
- <comment xml:lang="pt">ficheiro de caixa de correio</comment>
<comment xml:lang="pl">Plik poczty (Mailbox)</comment>
- <comment xml:lang="oc">fichièr bóstia de letras</comment>
- <comment xml:lang="nn">mailbox-fil</comment>
- <comment xml:lang="nl">mailbox-bestand</comment>
- <comment xml:lang="nb">postboksfil</comment>
- <comment xml:lang="lv">pastkastītes datne</comment>
- <comment xml:lang="lt">pašto dėžutės failas</comment>
- <comment xml:lang="ko">메일함 파일</comment>
- <comment xml:lang="kk">пошта жәшігінің файлы</comment>
- <comment xml:lang="ja">メールボックスファイル</comment>
+ <comment xml:lang="ja">電子郵便</comment>
<comment xml:lang="it">File mailbox</comment>
- <comment xml:lang="id">berkas kotak surat</comment>
- <comment xml:lang="ia">File de cassa postal</comment>
- <comment xml:lang="hu">mailbox fájl</comment>
- <comment xml:lang="hr">Datoteka poštanskog sandučića</comment>
- <comment xml:lang="he">קובץ תיבת דואר</comment>
- <comment xml:lang="gl">ficheiro de caixa de correo</comment>
- <comment xml:lang="ga">comhad bhosca poist</comment>
- <comment xml:lang="fur">file mailbox</comment>
- <comment xml:lang="fr">fichier boîte aux lettres</comment>
- <comment xml:lang="fo">postkassafíla</comment>
- <comment xml:lang="fi">mailbox-tiedosto</comment>
- <comment xml:lang="eu">mailbox fitxategia</comment>
+ <comment xml:lang="gl">Ficheiro Mailbox</comment>
+ <comment xml:lang="eu">Mailbox fitxategia</comment>
<comment xml:lang="es">archivo de buzón de correo</comment>
- <comment xml:lang="en_GB">mailbox file</comment>
- <comment xml:lang="el">Αρχείο mailbox</comment>
<comment xml:lang="de">Mailbox-Datei</comment>
- <comment xml:lang="da">postkassefil</comment>
- <comment xml:lang="cs">soubor mailbox</comment>
- <comment xml:lang="ca">fitxer mailbox</comment>
- <comment xml:lang="bg">Файл — Mailbox</comment>
- <comment xml:lang="be@latin">fajł paštovaj skryni</comment>
- <comment xml:lang="ar">ملف صندوق بريد</comment>
- <comment xml:lang="af">mailbox-lêer</comment>
+ <comment xml:lang="be">файл паштовай скрынкі</comment>
<generic-icon name="text-x-generic"/>
<sub-class-of type="text/plain"/>
<magic priority="20">
@@ -604,7 +588,9 @@ command to generate the output files.
<comment xml:lang="tr">Metalink dosyası</comment>
<comment xml:lang="sv">Metalink-fil</comment>
<comment xml:lang="sr">датотека метавезе</comment>
+ <comment xml:lang="sq">kartelë Metalink</comment>
<comment xml:lang="sl">Datoteka povezave Metalink</comment>
+ <comment xml:lang="si">Metalink ගොනුව</comment>
<comment xml:lang="sk">Súbor Metalink</comment>
<comment xml:lang="ru">Файл Metalink</comment>
<comment xml:lang="ro">Fișier Metalink</comment>
@@ -612,13 +598,15 @@ command to generate the output files.
<comment xml:lang="pt">ficheiro Metalink</comment>
<comment xml:lang="pl">Plik Metalink</comment>
<comment xml:lang="oc">fichièr metalink</comment>
- <comment xml:lang="nl">Metalink bestand</comment>
+ <comment xml:lang="nl">Metalink-bestand</comment>
<comment xml:lang="lv">Metalink datne</comment>
<comment xml:lang="lt">Metalink failas</comment>
<comment xml:lang="ko">Metalink 파일</comment>
<comment xml:lang="kk">Metalink файлы</comment>
+ <comment xml:lang="ka">მეტაბმულის ფაილი</comment>
<comment xml:lang="ja">Metalink ファイル</comment>
<comment xml:lang="it">File Metalink</comment>
+ <comment xml:lang="is">Metalink skrá</comment>
<comment xml:lang="id">Berkas Metalink</comment>
<comment xml:lang="ia">File Metalink</comment>
<comment xml:lang="hu">Metalink fájl</comment>
@@ -640,6 +628,7 @@ command to generate the output files.
<comment xml:lang="cs">soubor metalink</comment>
<comment xml:lang="ca">fitxer Metalink</comment>
<comment xml:lang="bg">Изтегляне — Metalink</comment>
+ <comment xml:lang="be">файл Metalink</comment>
<comment xml:lang="ast">Ficheru d'enllaz meta</comment>
<comment xml:lang="ar">ملف ميتالنك</comment>
<comment xml:lang="af">Metalink-lêer</comment>
@@ -658,7 +647,9 @@ command to generate the output files.
<comment xml:lang="tr">Metalink dosyası</comment>
<comment xml:lang="sv">Metalink-fil</comment>
<comment xml:lang="sr">датотека метавезе</comment>
+ <comment xml:lang="sq">kartelë Metalink</comment>
<comment xml:lang="sl">Datoteka povezave Metalink</comment>
+ <comment xml:lang="si">Metalink ගොනුව</comment>
<comment xml:lang="sk">Súbor Metalink</comment>
<comment xml:lang="ru">Файл Metalink</comment>
<comment xml:lang="ro">Fișier Metalink</comment>
@@ -666,13 +657,15 @@ command to generate the output files.
<comment xml:lang="pt">ficheiro Metalink</comment>
<comment xml:lang="pl">Plik Metalink</comment>
<comment xml:lang="oc">fichièr metalink</comment>
- <comment xml:lang="nl">Metalink bestand</comment>
+ <comment xml:lang="nl">Metalink-bestand</comment>
<comment xml:lang="lv">Metalink datne</comment>
<comment xml:lang="lt">Metalink failas</comment>
<comment xml:lang="ko">Metalink 파일</comment>
<comment xml:lang="kk">Metalink файлы</comment>
+ <comment xml:lang="ka">მეტაბმულის ფაილი</comment>
<comment xml:lang="ja">Metalink ファイル</comment>
<comment xml:lang="it">File Metalink</comment>
+ <comment xml:lang="is">Metalink skrá</comment>
<comment xml:lang="id">Berkas Metalink</comment>
<comment xml:lang="ia">File Metalink</comment>
<comment xml:lang="hu">Metalink fájl</comment>
@@ -694,6 +687,7 @@ command to generate the output files.
<comment xml:lang="cs">soubor metalink</comment>
<comment xml:lang="ca">fitxer Metalink</comment>
<comment xml:lang="bg">Изтегляне — Metalink</comment>
+ <comment xml:lang="be">файл Metalink</comment>
<comment xml:lang="ast">Ficheru d'enllaz meta</comment>
<comment xml:lang="ar">ملف ميتالنك</comment>
<comment xml:lang="af">Metalink-lêer</comment>
@@ -705,59 +699,21 @@ command to generate the output files.
<root-XML namespaceURI="urn:ietf:params:xml:ns:metalink" localName="metalink"/>
</mime-type>
<mime-type type="application/octet-stream">
- <comment>unknown</comment>
- <comment xml:lang="zh_TW">不明</comment>
- <comment xml:lang="zh_CN">未知</comment>
- <comment xml:lang="vi">không rõ</comment>
- <comment xml:lang="uk">невідомо</comment>
- <comment xml:lang="tr">bilinmeyen</comment>
- <comment xml:lang="sv">okänd</comment>
- <comment xml:lang="sr">непознато</comment>
- <comment xml:lang="sq">Nuk njihet</comment>
- <comment xml:lang="sl">neznano</comment>
- <comment xml:lang="sk">Neznámy</comment>
+ <comment>Unknown</comment>
+ <comment xml:lang="zh_TW">未知</comment>
+ <comment xml:lang="uk">невідомий</comment>
+ <comment xml:lang="sv">Okänd</comment>
+ <comment xml:lang="sq">I panjohur</comment>
<comment xml:lang="ru">Неизвестно</comment>
- <comment xml:lang="ro">necunoscut</comment>
<comment xml:lang="pt_BR">Desconhecido</comment>
- <comment xml:lang="pt">desconhecido</comment>
<comment xml:lang="pl">Nieznany typ</comment>
- <comment xml:lang="oc">desconegut</comment>
- <comment xml:lang="nn">ukjend</comment>
- <comment xml:lang="nl">onbekend</comment>
- <comment xml:lang="nb">ukjent</comment>
- <comment xml:lang="ms">Entah</comment>
- <comment xml:lang="lv">nezināms</comment>
- <comment xml:lang="lt">nežinoma</comment>
- <comment xml:lang="ko">알 수 없음</comment>
- <comment xml:lang="kk">белгісіз</comment>
- <comment xml:lang="ka">უცნობი</comment>
<comment xml:lang="ja">不明</comment>
<comment xml:lang="it">Sconosciuto</comment>
- <comment xml:lang="id">tak diketahui</comment>
- <comment xml:lang="ia">incognite</comment>
- <comment xml:lang="hu">ismeretlen</comment>
- <comment xml:lang="hr">Nepoznato</comment>
- <comment xml:lang="he">לא ידוע</comment>
- <comment xml:lang="gl">descoñecido</comment>
- <comment xml:lang="ga">anaithnid</comment>
- <comment xml:lang="fur">no cognossût</comment>
- <comment xml:lang="fr">inconnu</comment>
- <comment xml:lang="fo">ókent</comment>
- <comment xml:lang="fi">tuntematon</comment>
- <comment xml:lang="eu">ezezaguna</comment>
+ <comment xml:lang="gl">Descoñecido</comment>
+ <comment xml:lang="eu">Ezezaguna</comment>
<comment xml:lang="es">desconocido</comment>
- <comment xml:lang="eo">nekonate</comment>
- <comment xml:lang="en_GB">unknown</comment>
- <comment xml:lang="el">Άγνωστο</comment>
- <comment xml:lang="de">unbekannt</comment>
- <comment xml:lang="da">ukendt</comment>
- <comment xml:lang="cs">neznámý</comment>
- <comment xml:lang="ca">desconegut</comment>
- <comment xml:lang="bg">Неизвестен тип</comment>
- <comment xml:lang="be@latin">nieviadomy</comment>
- <comment xml:lang="ast">desconozse</comment>
- <comment xml:lang="ar">مجهول</comment>
- <comment xml:lang="af">onbekend</comment>
+ <comment xml:lang="de">Unbekannt</comment>
+ <comment xml:lang="be">невядома</comment>
</mime-type>
<mime-type type="application/x-partial-download">
<comment>Partially downloaded file</comment>
@@ -767,18 +723,23 @@ command to generate the output files.
<comment xml:lang="tr">Kısmen indirilmiş dosya</comment>
<comment xml:lang="sv">Delvis hämtad fil</comment>
<comment xml:lang="sr">делимично преузета датотека</comment>
+ <comment xml:lang="sq">Kartelë e shkarkuar pjesërisht</comment>
<comment xml:lang="sl">Delno prenesena datoteka</comment>
+ <comment xml:lang="si">අර්ධ වශයෙන් බාගත කළ ගොනුව</comment>
<comment xml:lang="sk">Čiastočne stiahnutý súbor</comment>
<comment xml:lang="ru">Частично загруженный файл</comment>
<comment xml:lang="pt_BR">Arquivo baixado parcialmente</comment>
<comment xml:lang="pt">ficheiro descarregado parcialmente</comment>
<comment xml:lang="pl">Częściowo pobrany plik</comment>
<comment xml:lang="oc">fichièr parcialament telecargat</comment>
+ <comment xml:lang="nl">Gedeeltelijk gedownload bestand</comment>
<comment xml:lang="lt">Dalinai atsiųstas failas</comment>
<comment xml:lang="ko">일부 다운로드한 파일</comment>
<comment xml:lang="kk">Жартылай жүктелген файл</comment>
+ <comment xml:lang="ka">ნაწილობრივ გადმოწერილი ფაილი</comment>
<comment xml:lang="ja">部分的にダウンロードされたファイル</comment>
<comment xml:lang="it">File parzialmente scaricato</comment>
+ <comment xml:lang="is">skrá sótt að hluta</comment>
<comment xml:lang="id">Berkas yang terunduh sebagian</comment>
<comment xml:lang="ia">File partialmente discargate</comment>
<comment xml:lang="hu">Részben letöltött fájl</comment>
@@ -798,6 +759,7 @@ command to generate the output files.
<comment xml:lang="cs">částečně stažený soubor</comment>
<comment xml:lang="ca">fitxer baixat parcialment</comment>
<comment xml:lang="bg">Частично изтеглен файл</comment>
+ <comment xml:lang="be">часткова спампаваны файл</comment>
<comment xml:lang="ast">Ficheru baxáu parcialmente</comment>
<comment xml:lang="ar">ملف منزل جزئياً</comment>
<comment xml:lang="af">Gedeeltelik afgelaaide lêer</comment>
@@ -815,8 +777,9 @@ command to generate the output files.
<comment xml:lang="tr">ODA belgesi</comment>
<comment xml:lang="sv">ODA-dokument</comment>
<comment xml:lang="sr">ОДА документ</comment>
- <comment xml:lang="sq">Dokument ODA</comment>
+ <comment xml:lang="sq">dokument ODA</comment>
<comment xml:lang="sl">Dokument ODA</comment>
+ <comment xml:lang="si">ODA ලේඛනය</comment>
<comment xml:lang="sk">Dokument ODA</comment>
<comment xml:lang="ru">Документ ODA</comment>
<comment xml:lang="ro">Document ODA</comment>
@@ -835,6 +798,7 @@ command to generate the output files.
<comment xml:lang="ka">ODA დოკუმენტი</comment>
<comment xml:lang="ja">ODA ドキュメント</comment>
<comment xml:lang="it">Documento ODA</comment>
+ <comment xml:lang="is">ODA skjal</comment>
<comment xml:lang="id">Dokumen ODA</comment>
<comment xml:lang="ia">Documento ODA</comment>
<comment xml:lang="hu">ODA-dokumentum</comment>
@@ -858,6 +822,7 @@ command to generate the output files.
<comment xml:lang="ca">document ODA</comment>
<comment xml:lang="bg">Документ — ODA</comment>
<comment xml:lang="be@latin">Dakument ODA</comment>
+ <comment xml:lang="be">дакумент ODA</comment>
<comment xml:lang="az">ODA sənədi</comment>
<comment xml:lang="ast">Documentu ODA</comment>
<comment xml:lang="ar">مستند ODA</comment>
@@ -875,14 +840,16 @@ command to generate the output files.
<comment xml:lang="tr">WWF belgesi</comment>
<comment xml:lang="sv">WWF-dokument</comment>
<comment xml:lang="sr">ВВФ документ</comment>
+ <comment xml:lang="sq">dokument WWF</comment>
<comment xml:lang="sl">Dokument WWF</comment>
+ <comment xml:lang="si">WWF ලේඛනය</comment>
<comment xml:lang="sk">Dokument WWF</comment>
<comment xml:lang="ru">Документ WWF</comment>
<comment xml:lang="pt_BR">Documento WWF</comment>
<comment xml:lang="pt">documento WWF</comment>
<comment xml:lang="pl">Dokument WWF</comment>
<comment xml:lang="oc">document WWF</comment>
- <comment xml:lang="nl">WWF document</comment>
+ <comment xml:lang="nl">WWF-document</comment>
<comment xml:lang="lv">WWF dokuments</comment>
<comment xml:lang="lt">WWF dokumentas</comment>
<comment xml:lang="ko">WWF 문서</comment>
@@ -890,6 +857,7 @@ command to generate the output files.
<comment xml:lang="ka">WWF დოკუმენტი</comment>
<comment xml:lang="ja">WWF ドキュメント</comment>
<comment xml:lang="it">Documento WWF</comment>
+ <comment xml:lang="is">WWF skjal</comment>
<comment xml:lang="id">Dokumen WWF</comment>
<comment xml:lang="ia">Documento WWF</comment>
<comment xml:lang="hu">WWF-dokumentum</comment>
@@ -910,6 +878,7 @@ command to generate the output files.
<comment xml:lang="cs">dokument WWF</comment>
<comment xml:lang="ca">document WWF</comment>
<comment xml:lang="bg">Документ — WWF</comment>
+ <comment xml:lang="be">дакумент WWF</comment>
<comment xml:lang="ast">Documentu WWF</comment>
<comment xml:lang="ar">مستند WWF</comment>
<comment xml:lang="af">WWF-dokument</comment>
@@ -927,8 +896,9 @@ command to generate the output files.
<comment xml:lang="tr">PDF belgesi</comment>
<comment xml:lang="sv">PDF-dokument</comment>
<comment xml:lang="sr">ПДФ документ</comment>
- <comment xml:lang="sq">Dokument PDF</comment>
+ <comment xml:lang="sq">dokument PDF</comment>
<comment xml:lang="sl">Dokument PDF</comment>
+ <comment xml:lang="si">PDF ලේඛනය</comment>
<comment xml:lang="sk">Dokument PDF</comment>
<comment xml:lang="ru">Документ PDF</comment>
<comment xml:lang="ro">Document PDF</comment>
@@ -944,8 +914,10 @@ command to generate the output files.
<comment xml:lang="lt">PDF dokumentas</comment>
<comment xml:lang="ko">PDF 문서</comment>
<comment xml:lang="kk">PDF құжаты</comment>
+ <comment xml:lang="ka">PDF დოკუმენტი</comment>
<comment xml:lang="ja">PDF ドキュメント</comment>
<comment xml:lang="it">Documento PDF</comment>
+ <comment xml:lang="is">PDF skjal</comment>
<comment xml:lang="id">Dokumen PDF</comment>
<comment xml:lang="ia">Documento PDF</comment>
<comment xml:lang="hu">PDF-dokumentum</comment>
@@ -969,6 +941,7 @@ command to generate the output files.
<comment xml:lang="ca">document PDF</comment>
<comment xml:lang="bg">Документ — PDF</comment>
<comment xml:lang="be@latin">Dakument PDF</comment>
+ <comment xml:lang="be">дакумент PDF</comment>
<comment xml:lang="ast">Documentu PDF</comment>
<comment xml:lang="ar">مستند PDF</comment>
<comment xml:lang="af">PDF-dokument</comment>
@@ -993,8 +966,9 @@ command to generate the output files.
<comment xml:lang="tr">XSPF çalma listesi</comment>
<comment xml:lang="sv">XSPF-spellista</comment>
<comment xml:lang="sr">ИксСПФ списак нумера</comment>
- <comment xml:lang="sq">Listë titujsh XSPF</comment>
+ <comment xml:lang="sq">luajlistë XSPF</comment>
<comment xml:lang="sl">Seznam predvajanja XSPF</comment>
+ <comment xml:lang="si">XSPF ධාවන ලැයිස්තුව</comment>
<comment xml:lang="sk">Zoznam skladieb XSPF</comment>
<comment xml:lang="ru">Список воспроизведения XSPF</comment>
<comment xml:lang="ro">Listă XSPF</comment>
@@ -1009,8 +983,10 @@ command to generate the output files.
<comment xml:lang="lt">XSPF grojaraštis</comment>
<comment xml:lang="ko">XSPF 재생 목록</comment>
<comment xml:lang="kk">XSPF ойнау тізімі</comment>
+ <comment xml:lang="ka">XSPF დასაკრავი სია</comment>
<comment xml:lang="ja">XSPF プレイリスト</comment>
<comment xml:lang="it">Playlist XSPF</comment>
+ <comment xml:lang="is">XSPF spilunarlisti</comment>
<comment xml:lang="id">Senarai pular XSPF</comment>
<comment xml:lang="ia">Lista de selection XSPF</comment>
<comment xml:lang="hu">XSPF-lejátszólista</comment>
@@ -1033,6 +1009,7 @@ command to generate the output files.
<comment xml:lang="ca">llista de reproducció XSPF</comment>
<comment xml:lang="bg">Списък за изпълнение — XSPF</comment>
<comment xml:lang="be@latin">Śpis piesień XSPF</comment>
+ <comment xml:lang="be">плэй-ліст XSPF</comment>
<comment xml:lang="ast">Llista de reproducción XSPF</comment>
<comment xml:lang="ar">قائمة تشغيل XSPF</comment>
<comment xml:lang="af">XSPF-speellys</comment>
@@ -1056,7 +1033,9 @@ command to generate the output files.
<comment xml:lang="tr">Microsoft Windows tema paketi</comment>
<comment xml:lang="sv">Microsoft Windows-temapaket</comment>
<comment xml:lang="sr">пакет теме Мајкрософт Виндоуза</comment>
+ <comment xml:lang="sq">paketë temash Microsoft Windows</comment>
<comment xml:lang="sl">Datoteka teme Microsoft Windows</comment>
+ <comment xml:lang="si">Microsoft Windows තේමා ඇසුරුම</comment>
<comment xml:lang="sk">Balík tém Microsoft Windows</comment>
<comment xml:lang="ru">Пакет темы Microsoft Windows</comment>
<comment xml:lang="ro">Pachet de teme Microsoft Windows</comment>
@@ -1064,7 +1043,7 @@ command to generate the output files.
<comment xml:lang="pt">pacote de tema Microsoft Windows</comment>
<comment xml:lang="pl">Pakiet motywu Microsoft Windows</comment>
<comment xml:lang="oc">paquet de tèmas Microsoft Windows</comment>
- <comment xml:lang="nl">Microsoft Windows thema pack</comment>
+ <comment xml:lang="nl">Microsoft Windows-themapakket</comment>
<comment xml:lang="lv">Microsoft Windows motīvu paka</comment>
<comment xml:lang="lt">Microsoft Windows temų paketas</comment>
<comment xml:lang="ko">Microsoft Windows 테마 패키지</comment>
@@ -1072,6 +1051,7 @@ command to generate the output files.
<comment xml:lang="ka">Microsoft Windows-ის თემის შეკვრა</comment>
<comment xml:lang="ja">Microsoft Windows テーマパック</comment>
<comment xml:lang="it">Pacchetto temi Microsoft Windows</comment>
+ <comment xml:lang="is">Microsoft Windows þemapakki</comment>
<comment xml:lang="id">Pak tema Microsoft Windows</comment>
<comment xml:lang="ia">Pacchetto de themas Microsoft Windows</comment>
<comment xml:lang="hu">Microsoft Windows témacsomag</comment>
@@ -1092,6 +1072,7 @@ command to generate the output files.
<comment xml:lang="cs">balík motivů Microsoft Windows</comment>
<comment xml:lang="ca">paquet de temes de Microsoft Windows</comment>
<comment xml:lang="bg">Пакет с тема — Microsoft Windows</comment>
+ <comment xml:lang="be">пакет тэмы Microsoft Windows</comment>
<comment xml:lang="ast">Paquete de temes de Microsoft Windows</comment>
<comment xml:lang="ar">حزمة سمات Microsoft Works</comment>
<comment xml:lang="af">Microsoft Windows-temapak</comment>
@@ -1107,18 +1088,23 @@ command to generate the output files.
<comment xml:lang="tr">AmazonMP3 indirme dosyası</comment>
<comment xml:lang="sv">AmazonMP3-hämtningsfil</comment>
<comment xml:lang="sr">датотека преузимања АмазонаМП3</comment>
+ <comment xml:lang="sq">kartelë shkarkimi AmazonMP3</comment>
<comment xml:lang="sl">Datoteka prenosa AmazonMP3</comment>
+ <comment xml:lang="si">AmazonMP3 බාගත කිරීමේ ගොනුව</comment>
<comment xml:lang="sk">Stiahnutý súbor AmazonMP3 </comment>
<comment xml:lang="ru">Файл загрузки AmazonMP3</comment>
<comment xml:lang="pt_BR">Arquivo de download AmazonMP3</comment>
<comment xml:lang="pt">ficheiro transferido AmazonMP3</comment>
<comment xml:lang="pl">Pobrany plik AmazonMP3</comment>
<comment xml:lang="oc">fichièr telecargat AmazonMP3</comment>
+ <comment xml:lang="nl">AmazonMP3-downloadbestand</comment>
<comment xml:lang="lv">AmazonMP3 lejupielādes datne</comment>
<comment xml:lang="ko">AmazonMP3 다운로드 파일</comment>
<comment xml:lang="kk">AmazonMP3 жүктеме файлы</comment>
+ <comment xml:lang="ka">AmazonMP3 გადმოწერის ფაილი</comment>
<comment xml:lang="ja">AmazonMP3 ダウンロードファイル</comment>
<comment xml:lang="it">File scaricamento AmazonMP3</comment>
+ <comment xml:lang="is">AmazonMP3 niðurhalsskrá</comment>
<comment xml:lang="id">Berkas unduh AmazonMP3</comment>
<comment xml:lang="ia">File de discargamento AmazonMP3</comment>
<comment xml:lang="hu">AmazonMP3 letöltésfájl</comment>
@@ -1133,11 +1119,12 @@ command to generate the output files.
<comment xml:lang="es">archivo de descarga de AmazonMP3</comment>
<comment xml:lang="en_GB">AmazonMP3 download file</comment>
<comment xml:lang="el">Αρχείο λήψης AmazonMP3</comment>
- <comment xml:lang="de">AmazonMP3-Herunterladedatei</comment>
+ <comment xml:lang="de">Amazon MP3-Download-Datei</comment>
<comment xml:lang="da">AmazonMP3-downloadfil</comment>
<comment xml:lang="cs">soubor stahování AmazonMP3</comment>
<comment xml:lang="ca">fitxer baixat d'AmazonMP3</comment>
<comment xml:lang="bg">Файл за изтегляне — AmazonMP3</comment>
+ <comment xml:lang="be">файл спампоўвання AmazonMP3</comment>
<comment xml:lang="ast">Ficheru de descarga AmazonMP3</comment>
<comment xml:lang="ar">ملف تنزيل AmazonMP3 </comment>
<comment xml:lang="af">AmazonMP3-aflaailêer</comment>
@@ -1152,7 +1139,9 @@ command to generate the output files.
<comment xml:lang="tr">GSM 06.10 ses dosyası</comment>
<comment xml:lang="sv">GSM 06.10-ljud</comment>
<comment xml:lang="sr">ГСМ 06.10 звук</comment>
+ <comment xml:lang="sq">audio GSM 06.10</comment>
<comment xml:lang="sl">Zvočna datoteka GSM 06.10</comment>
+ <comment xml:lang="si">GSM 06.10 ශ්‍රව්‍ය</comment>
<comment xml:lang="sk">Zvuk GSM 06.10</comment>
<comment xml:lang="ru">Аудио GSM 06.10</comment>
<comment xml:lang="ro">GSM 06.10 audio</comment>
@@ -1168,6 +1157,7 @@ command to generate the output files.
<comment xml:lang="ka">GSM 06.10 აუდიო</comment>
<comment xml:lang="ja">GSM 06.10 オーディオ</comment>
<comment xml:lang="it">Audio GSM 06.10</comment>
+ <comment xml:lang="is">GSM 06.10 hljóð</comment>
<comment xml:lang="id">Audio GSM 06.10</comment>
<comment xml:lang="ia">Audio GSM 06.10</comment>
<comment xml:lang="hu">GSM 06.10 hang</comment>
@@ -1180,7 +1170,7 @@ command to generate the output files.
<comment xml:lang="fo">GSM 06.10 ljóður</comment>
<comment xml:lang="fi">GSM 06.10 -ääni</comment>
<comment xml:lang="eu">GSM 06.10 audioa</comment>
- <comment xml:lang="es">audio GSM 06.10</comment>
+ <comment xml:lang="es">sonido GSM 06.10</comment>
<comment xml:lang="en_GB">GSM 06.10 audio</comment>
<comment xml:lang="el">Ήχος GSM 06.10</comment>
<comment xml:lang="de">GSM-06.10-Audio</comment>
@@ -1188,6 +1178,7 @@ command to generate the output files.
<comment xml:lang="cs">zvuk GSM 06.10</comment>
<comment xml:lang="ca">àudio de GSM 06.10</comment>
<comment xml:lang="bg">Аудио — GSM 06.10</comment>
+ <comment xml:lang="be">аўдыя GSM 06.10</comment>
<comment xml:lang="ast">Audiu GSM 6.10</comment>
<comment xml:lang="ar">صوت GSM 06.10</comment>
<comment xml:lang="af">GSM 06.10-oudio</comment>
@@ -1202,22 +1193,28 @@ command to generate the output files.
<comment xml:lang="uk">список відтворення iRiver</comment>
<comment xml:lang="tr">iRiver çalma listesi</comment>
<comment xml:lang="sv">iRiver-spellista</comment>
+ <comment xml:lang="sq">luajlistë iRiver</comment>
<comment xml:lang="sl">Seznam predvajanja iRiver</comment>
+ <comment xml:lang="si">iRiver ධාවන ලැයිස්තුව</comment>
<comment xml:lang="sk">Zoznam skladieb iRiver</comment>
<comment xml:lang="ru">Список воспроизведения iRiver</comment>
<comment xml:lang="pt_BR">Lista de reprodução do iRiver</comment>
<comment xml:lang="pt">lista de reprodução do iRiver</comment>
<comment xml:lang="pl">Lista odtwarzania iRiver</comment>
<comment xml:lang="oc">lista de lectura iRiver</comment>
+ <comment xml:lang="nl">iRiver-playlist</comment>
<comment xml:lang="lt">iRiver grojaraštis</comment>
<comment xml:lang="ko">아이리버 재생 목록</comment>
<comment xml:lang="kk">iRiver ойнау тізімі</comment>
+ <comment xml:lang="ka">iRiver დასაკრავი სია</comment>
<comment xml:lang="ja">iRiver プレイリスト</comment>
<comment xml:lang="it">Playlist iRiver</comment>
+ <comment xml:lang="is">iRiver spilunarlisti</comment>
<comment xml:lang="id">daftar putar iRiver</comment>
<comment xml:lang="hu">iRiver lejátszólista</comment>
<comment xml:lang="hr">iRiver popis izvođenja</comment>
<comment xml:lang="he">רשימת נגינה של iRiver</comment>
+ <comment xml:lang="gl">Lista de reprodución de iRiver</comment>
<comment xml:lang="fr">liste de lecture iRiver</comment>
<comment xml:lang="fi">iRiver-soittolista</comment>
<comment xml:lang="eu">iRiver erreprodukzio-zerrenda</comment>
@@ -1227,6 +1224,7 @@ command to generate the output files.
<comment xml:lang="da">iRiver-afspilningsliste</comment>
<comment xml:lang="ca">llista de reproducció iRiver</comment>
<comment xml:lang="bg">Списък за изпълнение — iRiver</comment>
+ <comment xml:lang="be">плэй-ліст iRiver</comment>
<comment xml:lang="ar">قائمة تشغيل iRiver</comment>
<magic>
<match type="string" value="iriver UMS PLA" offset="4"/>
@@ -1242,8 +1240,9 @@ command to generate the output files.
<comment xml:lang="tr">PGP/MIME-şifreli ileti başlığı</comment>
<comment xml:lang="sv">PGP/MIME-krypterat meddelandehuvud</comment>
<comment xml:lang="sr">ПГП/МИМЕ шифровано заглавље поруке</comment>
- <comment xml:lang="sq">Header mesazhi të kriptuar PGP/MIME</comment>
+ <comment xml:lang="sq">krye mesazhi fshehtëzuar me PGP/MIME</comment>
<comment xml:lang="sl">Datoteka glave šifriranega sporočila PGP/MIME</comment>
+ <comment xml:lang="si">PGP/MIME-සංකේතනය කළ පණිවිඩ ශීර්ෂකය</comment>
<comment xml:lang="sk">Hlavičke správy zašifrovaná pomocou PGP/MIME</comment>
<comment xml:lang="ru">Заголовок сообщения, зашифрованный PGP/MIME</comment>
<comment xml:lang="ro">Antet de mesaj encriptat PGP/MIME</comment>
@@ -1261,6 +1260,7 @@ command to generate the output files.
<comment xml:lang="kk">PGP/MIME-шифрленген мәлімдеме тақырыптамасы</comment>
<comment xml:lang="ja">PGP/MIME 暗号化メッセージヘッダー</comment>
<comment xml:lang="it">Intestazione messaggio PGP/MIME-encrypted</comment>
+ <comment xml:lang="is">PGP-dulritaður skilaboðahaus</comment>
<comment xml:lang="id">Tajuk pesan terenkripsi PGP/MIME</comment>
<comment xml:lang="ia">Capite de message cryptate con PGP/MIME</comment>
<comment xml:lang="hu">PGP/MIME titkosított üzenetfejléc</comment>
@@ -1283,11 +1283,10 @@ command to generate the output files.
<comment xml:lang="ca">capçalera de missatge amb xifrat PGP/MIME</comment>
<comment xml:lang="bg">Заглавна част на шифрирано съобщение — PGP/MIME</comment>
<comment xml:lang="be@latin">Zahałovak paviedamleńnia, zašyfravany ŭ PGP/MIME</comment>
+ <comment xml:lang="be">загаловак паведамлення з шыфраваннем PGP/MIME</comment>
<comment xml:lang="ast">Testera de mensaxe cifrada en PGP/MIME</comment>
<comment xml:lang="ar">ترويسة رسالة PGP/MIME-مشفرة</comment>
<comment xml:lang="af">Kop van PGP/MIME-geënkripteerde boodskap</comment>
- <sub-class-of type="text/plain"/>
- <generic-icon name="text-x-generic"/>
<magic>
<match type="string" value="-----BEGIN PGP MESSAGE-----" offset="0"/>
</magic>
@@ -1305,8 +1304,9 @@ command to generate the output files.
<comment xml:lang="tr">PGP anahtarları</comment>
<comment xml:lang="sv">PGP-nycklar</comment>
<comment xml:lang="sr">ПГП кључеви</comment>
- <comment xml:lang="sq">Kyçe PGP</comment>
+ <comment xml:lang="sq">kyçe PGP</comment>
<comment xml:lang="sl">Datoteka ključa PGP</comment>
+ <comment xml:lang="si">PGP යතුරු</comment>
<comment xml:lang="sk">Kľúče PGP</comment>
<comment xml:lang="ru">Ключи PGP</comment>
<comment xml:lang="ro">Chei PGP</comment>
@@ -1322,8 +1322,10 @@ command to generate the output files.
<comment xml:lang="lt">PGP raktai</comment>
<comment xml:lang="ko">PGP 키</comment>
<comment xml:lang="kk">PGP кілттері</comment>
+ <comment xml:lang="ka">PGP გასაღები</comment>
<comment xml:lang="ja">PGP 鍵</comment>
<comment xml:lang="it">Chiavi PGP</comment>
+ <comment xml:lang="is">PGP-lyklar</comment>
<comment xml:lang="id">Kunci PGP</comment>
<comment xml:lang="ia">Claves PGP</comment>
<comment xml:lang="hu">PGP-kulcs</comment>
@@ -1347,14 +1349,13 @@ command to generate the output files.
<comment xml:lang="ca">claus PGP</comment>
<comment xml:lang="bg">Ключове — PGP</comment>
<comment xml:lang="be@latin">Klučy PGP</comment>
+ <comment xml:lang="be">ключы PGP</comment>
<comment xml:lang="az">PGP açarları</comment>
<comment xml:lang="ast">Claves PGP</comment>
<comment xml:lang="ar">مفاتيح PGP</comment>
<comment xml:lang="af">PGP-sleutels</comment>
<acronym>PGP</acronym>
<expanded-acronym>Pretty Good Privacy</expanded-acronym>
- <sub-class-of type="text/plain"/>
- <generic-icon name="text-x-generic"/>
<magic>
<match type="string" value="-----BEGIN PGP PUBLIC KEY BLOCK-----" offset="0"/>
<match type="string" value="-----BEGIN PGP PRIVATE KEY BLOCK-----" offset="0"/>
@@ -1371,59 +1372,19 @@ command to generate the output files.
<glob pattern="*.key"/>
</mime-type>
<mime-type type="application/pgp-signature">
- <comment>detached OpenPGP signature</comment>
- <comment xml:lang="zh_TW">分離的 OpenPGP 簽章</comment>
- <comment xml:lang="zh_CN">分离的 OpenPGP 签名</comment>
- <comment xml:lang="vi">chữ ký OpenPGP tách rời</comment>
- <comment xml:lang="uk">відокремлений OpenPGP підпис</comment>
- <comment xml:lang="tr">müstakil OpenPGP imzası</comment>
- <comment xml:lang="sv">frikopplad OpenPGP-signatur</comment>
- <comment xml:lang="sr">одвојени ОпенПГП потпис</comment>
- <comment xml:lang="sq">Firmë e shkëputur OpenPGP</comment>
- <comment xml:lang="sl">odpet podpis OpenPGP</comment>
- <comment xml:lang="sk">Oddelený podpis OpenPGP</comment>
+ <comment>Detached OpenPGP signature</comment>
+ <comment xml:lang="zh_TW">卸離的 OpenGPG 簽章</comment>
+ <comment xml:lang="uk">відокремлений підпис OpenPGP</comment>
+ <comment xml:lang="sv">Frikopplad OpenPGP-signatur</comment>
<comment xml:lang="ru">Отсоединённая подпись OpenPGP</comment>
- <comment xml:lang="ro">semnătură OpenPGP detașată</comment>
<comment xml:lang="pt_BR">Assinatura OpenPGP destacada</comment>
- <comment xml:lang="pt">assinatura OpenPGP solta</comment>
<comment xml:lang="pl">Oddzielony podpis OpenPGP</comment>
- <comment xml:lang="oc">signatura OpenPGP destacada</comment>
- <comment xml:lang="nn">fråkopla OpenPGP-signatur</comment>
- <comment xml:lang="nl">losse OpenPGP-ondertekening</comment>
- <comment xml:lang="nb">frakoblet OpenPGP-signatur</comment>
- <comment xml:lang="ms">Tandatangan OpenPGP terlerai</comment>
- <comment xml:lang="lv">atvienots OpenPGP paraksts</comment>
- <comment xml:lang="lt">neprisegtas OpenPGP parašas</comment>
- <comment xml:lang="ko">분리된 OpenPGP 서명</comment>
- <comment xml:lang="kk">бөлінген OpenPGP қолтаңбасы</comment>
- <comment xml:lang="ja">分離 OpenPGP 署名</comment>
<comment xml:lang="it">Firma staccata OpenPGP</comment>
- <comment xml:lang="id">tanda tangan OpenPGP yang terlepas</comment>
- <comment xml:lang="ia">Signatura OpenPGP distachate</comment>
- <comment xml:lang="hu">leválasztott OpenPGP-aláírás</comment>
- <comment xml:lang="hr">Odvojen OpenPGP potpis</comment>
- <comment xml:lang="he">חתימת OpenPGP מנותקת</comment>
- <comment xml:lang="gl">sinatura de OpenPGP independente</comment>
- <comment xml:lang="ga">síniú OpenPGP scartha</comment>
- <comment xml:lang="fur">firme OpenPGP distacade</comment>
- <comment xml:lang="fr">signature OpenPGP détachée</comment>
- <comment xml:lang="fo">skild OpenPGP undirskrift</comment>
- <comment xml:lang="fi">erillinen OpenPGP-allekirjoitus</comment>
- <comment xml:lang="eu">desuzturtako OpenPGP sinadura</comment>
- <comment xml:lang="es">firma OpenPGP separada</comment>
- <comment xml:lang="eo">dekroĉa OpenPGP-subskribo</comment>
- <comment xml:lang="en_GB">detached OpenPGP signature</comment>
- <comment xml:lang="el">Αποκομμένη υπογραφή OpenPGP</comment>
- <comment xml:lang="de">isolierte OpenPGP-Signatur</comment>
- <comment xml:lang="da">frigjort OpenPGP-signatur</comment>
- <comment xml:lang="cs">oddělený podpis OpenPGP</comment>
- <comment xml:lang="ca">signatura OpenPGP abstreta</comment>
- <comment xml:lang="bg">Отделѐн подпис — OpenPGP</comment>
- <comment xml:lang="be@latin">adłučany podpis OpenPGP</comment>
- <comment xml:lang="ar">إمضاء OpenPGP مفصول</comment>
- <comment xml:lang="af">losstaande OpenPGP-handtekening</comment>
- <sub-class-of type="text/plain"/>
- <generic-icon name="text-x-generic"/>
+ <comment xml:lang="gl">Sinatura OpenPGP desancorada</comment>
+ <comment xml:lang="eu">OpenPGP sinadura askea</comment>
+ <comment xml:lang="es">firma OpenGPG separada</comment>
+ <comment xml:lang="de">Isolierte OpenPGP-Signatur</comment>
+ <comment xml:lang="be">адлучаны подпіс OpenPGP</comment>
<magic>
<match type="string" value="-----BEGIN PGP SIGNATURE-----" offset="0"/>
</magic>
@@ -1440,22 +1401,28 @@ command to generate the output files.
<comment xml:lang="uk">файл PKCS#7</comment>
<comment xml:lang="tr">PKCS#7 dosyası</comment>
<comment xml:lang="sv">PKCS#7-fil</comment>
+ <comment xml:lang="sq">kartelë PKCS#7</comment>
<comment xml:lang="sl">Datoteka PKCS#7</comment>
+ <comment xml:lang="si">PKCS#7 ගොනුව</comment>
<comment xml:lang="sk">Súbor PKCS#7</comment>
<comment xml:lang="ru">Файл PKCS#7</comment>
<comment xml:lang="pt_BR">Arquivo PKCS#7</comment>
<comment xml:lang="pt">ficheiro PKCS#7</comment>
<comment xml:lang="pl">Plik PKCS#7</comment>
<comment xml:lang="oc">fichièr PKCS#7</comment>
+ <comment xml:lang="nl">PKCS#7-bestand</comment>
<comment xml:lang="lt">PKCS#7 failas</comment>
<comment xml:lang="ko">PKCS#7 파일</comment>
<comment xml:lang="kk">PKCS#7 файлы</comment>
+ <comment xml:lang="ka">PKCS#7 ფაილი</comment>
<comment xml:lang="ja">PKCS#7 ファイル</comment>
<comment xml:lang="it">File PKCS#7</comment>
+ <comment xml:lang="is">PKCS#7 skrá</comment>
<comment xml:lang="id">Berkas PKCS#7</comment>
<comment xml:lang="hu">PKCS#7 fájl</comment>
<comment xml:lang="hr">PKCS#7 datoteka</comment>
<comment xml:lang="he">קובץ PKCS#7</comment>
+ <comment xml:lang="gl">Ficheiro PKCS#7</comment>
<comment xml:lang="fr">fichier PKCS#7</comment>
<comment xml:lang="fi">PKCS#7-tiedosto</comment>
<comment xml:lang="eu">PKCS#7 fitxategia</comment>
@@ -1465,6 +1432,7 @@ command to generate the output files.
<comment xml:lang="da">PKCS#7-fil</comment>
<comment xml:lang="ca">fitxer PKCS#7</comment>
<comment xml:lang="bg">Файл за PKCS#7</comment>
+ <comment xml:lang="be">файл PKCS#7</comment>
<comment xml:lang="ar">ملف PKCS#7</comment>
<acronym>PKCS</acronym>
<expanded-acronym>Public-Key Cryptography Standards</expanded-acronym>
@@ -1473,57 +1441,19 @@ command to generate the output files.
<glob pattern="*.p7m"/>
</mime-type>
<mime-type type="application/pkcs7-signature">
- <comment>detached S/MIME signature</comment>
- <comment xml:lang="zh_TW">分離的 S/MIME 簽章</comment>
- <comment xml:lang="zh_CN">分离的 S/MIME 签名</comment>
- <comment xml:lang="vi">chữ ký S/MIME tách rời</comment>
- <comment xml:lang="uk">відокремлений S/MIME підпис</comment>
- <comment xml:lang="tr">müstakil S/MIME imzası</comment>
- <comment xml:lang="sv">frikopplad S/MIME-signatur</comment>
- <comment xml:lang="sr">одвојени С/МИМЕ потпис</comment>
- <comment xml:lang="sq">Firmë e shkëputur S/MIME</comment>
- <comment xml:lang="sl">odpet podpis S/MIME</comment>
- <comment xml:lang="sk">Oddelený podpis S/MIME</comment>
+ <comment>Detached S/MIME signature</comment>
+ <comment xml:lang="zh_TW">卸離的 S/MIME 簽章</comment>
+ <comment xml:lang="uk">відокремлений підпис S/MIME</comment>
+ <comment xml:lang="sv">Frikopplad S/MIME-signatur</comment>
<comment xml:lang="ru">Отсоединённая подпись S/MIME</comment>
- <comment xml:lang="ro">semnătură S/MIME detașată</comment>
<comment xml:lang="pt_BR">Assinatura S/MIME destacada</comment>
- <comment xml:lang="pt">assinatura S/MIME solta</comment>
<comment xml:lang="pl">Oddzielony podpis S/MIME</comment>
- <comment xml:lang="oc">signatura S/MIME destacada</comment>
- <comment xml:lang="nn">fråkopla S/MIME-signatur</comment>
- <comment xml:lang="nl">losse S/MIME-ondertekening</comment>
- <comment xml:lang="nb">frakoblet S/MIME-signatur</comment>
- <comment xml:lang="ms">Tandatangan S/MIME terlerai</comment>
- <comment xml:lang="lv">atvienots S/MIME paraksts</comment>
- <comment xml:lang="lt">neprisegtas S/MIME parašas</comment>
- <comment xml:lang="ko">분리된 S/MIME 서명</comment>
- <comment xml:lang="kk">бөлінген S/MIME қолтаңбасы</comment>
- <comment xml:lang="ja">分離 S/MIME 署名</comment>
<comment xml:lang="it">Firma staccata S/MIME</comment>
- <comment xml:lang="id">tanda tangan S/MIME yang terlepas</comment>
- <comment xml:lang="ia">Signatura S/MIME distachate</comment>
- <comment xml:lang="hu">leválasztott S/MIME-aláírás</comment>
- <comment xml:lang="hr">Odvojen S/MIME potpis</comment>
- <comment xml:lang="he">חתימת S/MIME מנותקת</comment>
- <comment xml:lang="gl">sinatura S/MIME independente</comment>
- <comment xml:lang="ga">síniú S/MIME scartha</comment>
- <comment xml:lang="fur">firme S/MIME distacade</comment>
- <comment xml:lang="fr">signature S/MIME détachée</comment>
- <comment xml:lang="fo">skild S/MIME undirskrift</comment>
- <comment xml:lang="fi">erillinen S/MIME-allekirjoitus</comment>
- <comment xml:lang="eu">desuzturtako S/MIME sinadura</comment>
+ <comment xml:lang="gl">Sinatura S/MIME desancorada</comment>
+ <comment xml:lang="eu">S/MIME sinadura askea</comment>
<comment xml:lang="es">firma S/MIME separada</comment>
- <comment xml:lang="eo">dekroĉa S/MIME-subskribo</comment>
- <comment xml:lang="en_GB">detached S/MIME signature</comment>
- <comment xml:lang="el">Αποκομμένη υπογραφή S/MIME</comment>
- <comment xml:lang="de">isolierte S/MIME-Signatur</comment>
- <comment xml:lang="da">frigjort S/MIME-signatur</comment>
- <comment xml:lang="cs">oddělený podpis S/MIME</comment>
- <comment xml:lang="ca">signatura S/MIME abstreta</comment>
- <comment xml:lang="bg">Отделѐн подпис — S/MIME</comment>
- <comment xml:lang="be@latin">adłučany podpis S/MIME</comment>
- <comment xml:lang="ar">إمضاء S/MIME مفصول</comment>
- <comment xml:lang="af">losstaande S/MIME-handtekening</comment>
+ <comment xml:lang="de">Isolierte S/MIME-Signatur</comment>
+ <comment xml:lang="be">адлучаны подпіс S/MIME</comment>
<acronym>S/MIME</acronym>
<expanded-acronym>Secure/Multipurpose Internet Mail Extensions</expanded-acronym>
<sub-class-of type="text/plain"/>
@@ -1538,7 +1468,9 @@ command to generate the output files.
<comment xml:lang="tr">PKCS#8 özel anahtarı</comment>
<comment xml:lang="sv">Privat PKCS#8-nyckel</comment>
<comment xml:lang="sr">ПКЦС#8 лични кључ</comment>
+ <comment xml:lang="sq">kyç privat PKCS#8</comment>
<comment xml:lang="sl">Datoteka osebnega ključa PKCS#8</comment>
+ <comment xml:lang="si">PKCS#8 පුද්ගලික යතුර</comment>
<comment xml:lang="sk">Súkromný kľúč PKCS#8</comment>
<comment xml:lang="ru">Личный ключ PKCS#8</comment>
<comment xml:lang="ro">Cheie privată PKCS#8</comment>
@@ -1546,13 +1478,14 @@ command to generate the output files.
<comment xml:lang="pt">chave privada PKCS#8</comment>
<comment xml:lang="pl">Klucz prywatny PKCS#8</comment>
<comment xml:lang="oc">clau privada PKCS#8</comment>
- <comment xml:lang="nl">PKCS#8 private sleutel</comment>
+ <comment xml:lang="nl">PKCS#8-privésleutel</comment>
<comment xml:lang="lv">PKCS#8 privātā atslēga</comment>
<comment xml:lang="lt">PKCS#8 asmeninis raktas</comment>
<comment xml:lang="ko">PKCS#8 개인 키</comment>
<comment xml:lang="kk">PKCS#8 меншік кілті</comment>
<comment xml:lang="ja">PKCS#8 秘密鍵</comment>
<comment xml:lang="it">Chiave privata PKCS#8</comment>
+ <comment xml:lang="is">PKCS#8 einkalykill</comment>
<comment xml:lang="id">Kunci privat PKCS#8</comment>
<comment xml:lang="ia">Clave private PKCS#8</comment>
<comment xml:lang="hu">PKCS#8 személyes kulcs</comment>
@@ -1568,11 +1501,12 @@ command to generate the output files.
<comment xml:lang="es">clave privada PCKS#8</comment>
<comment xml:lang="en_GB">PKCS#8 private key</comment>
<comment xml:lang="el">Ιδιωτικό κλειδί PKCS#8</comment>
- <comment xml:lang="de">PKCS#8 privater Schlüssel</comment>
+ <comment xml:lang="de">Privater PKCS#8-Schlüssel</comment>
<comment xml:lang="da">PKCS#8-privat nøgle</comment>
<comment xml:lang="cs">soukromý klíč PKCS#8</comment>
<comment xml:lang="ca">clau privada PKCS#8</comment>
<comment xml:lang="bg">Ключ — PKCS#8, частен</comment>
+ <comment xml:lang="be">закрыты ключ PKCS#8</comment>
<comment xml:lang="ar">رزمة شهادة PKCS#8</comment>
<comment xml:lang="af">PKCS#8- private sleutel</comment>
<acronym>PKCS</acronym>
@@ -1586,20 +1520,25 @@ command to generate the output files.
<comment xml:lang="uk">закритий ключ PKCS#8 (зашифрований)</comment>
<comment xml:lang="tr">PKCS#8 özel anahtar (şifrelenmiş)</comment>
<comment xml:lang="sv">Privat PKCS#8-nyckel (krypterad)</comment>
+ <comment xml:lang="sq">ky privat PKCS#8 (i fshehtëzuar)</comment>
<comment xml:lang="sl">Zasebni ključ PKCS#8 (širfirano)</comment>
+ <comment xml:lang="si">PKCS#8 පුද්ගලික යතුර (සංකේතනය කළ)</comment>
<comment xml:lang="sk">Súkromný kľúč PKCS#8 (šifrovaný)</comment>
<comment xml:lang="ru">Личный ключ PKCS#8 (зашифрованный)</comment>
<comment xml:lang="pt_BR">Chave privada PKCS#8 (criptografada)</comment>
<comment xml:lang="pt">chave privada PKCS#8 (encriptada)</comment>
<comment xml:lang="pl">Klucz prywatny PKCS#8 (zaszyfrowany)</comment>
+ <comment xml:lang="nl">PKCS#8-privésleutel (versleuteld)</comment>
<comment xml:lang="ko">PKCS#8 개인 키(암호화됨)</comment>
<comment xml:lang="kk">PKCS#8 жеке кілті (шифрленген)</comment>
<comment xml:lang="ja">PKCS#8 プライベートキー (暗号化)</comment>
<comment xml:lang="it">Chiave privata PKCS#8 (cifrata)</comment>
+ <comment xml:lang="is">PKCS#8 einkalykill (dulritaður)</comment>
<comment xml:lang="id">Kunci privat PKCS#8 (terenkripsi)</comment>
<comment xml:lang="hu">PKCS#8 személyes kulcs (titkosított)</comment>
<comment xml:lang="hr">PKCS#8 privatni ključ (šifriran)</comment>
<comment xml:lang="he">מפתח פרטי מסוג PKCS#8 (מוצפן)</comment>
+ <comment xml:lang="gl">Chave privada PKCS#8 (cifrada)</comment>
<comment xml:lang="ga">eochair phríobháideach PKCS#8 (criptithe)</comment>
<comment xml:lang="fur">clâf privade PKCS#8 (cifrade)</comment>
<comment xml:lang="fr">clé privée PKCS#8 (chiffrée)</comment>
@@ -1607,11 +1546,12 @@ command to generate the output files.
<comment xml:lang="eu">PKCS#8 gako pribatua (zifratua)</comment>
<comment xml:lang="es">clave privada PKCS#8 (cifrada)</comment>
<comment xml:lang="en_GB">PKCS#8 private key (encrypted)</comment>
- <comment xml:lang="de">PKCS#8 privater Schlüssel (verschlüsselt)</comment>
+ <comment xml:lang="de">Privater PKCS#8-Schlüssel (verschlüsselt)</comment>
<comment xml:lang="da">PKCS#8-privat nøgle (krypteret)</comment>
<comment xml:lang="cs">soukromý klíč PKCS#8 (zašifrovaný)</comment>
<comment xml:lang="ca">clau privada PKCS#8 (xifrada)</comment>
<comment xml:lang="bg">Ключ — PKCS#8, частен, шифриран</comment>
+ <comment xml:lang="be">закрыты ключ PKCS#8 (зашыфраваны)</comment>
<comment xml:lang="ar">مفتاح خاص PKCS#8 (مشفر)</comment>
<comment xml:lang="af">PKCS#8- private sleutel (geënkripteer)</comment>
<acronym>PKCS</acronym>
@@ -1627,8 +1567,9 @@ command to generate the output files.
<comment xml:lang="tr">PKCS#10 sertifika isteği</comment>
<comment xml:lang="sv">PKCS#10-certifikatbegäran</comment>
<comment xml:lang="sr">ПКЦС#10 зхатев уверења</comment>
- <comment xml:lang="sq">Kërkesë çertifikimi PKCS#10</comment>
+ <comment xml:lang="sq">kërkesë certifikimi PKCS#10</comment>
<comment xml:lang="sl">Datoteka potrdila PKCS#10</comment>
+ <comment xml:lang="si">PKCS#10 සහතික කිරීමේ ඉල්ලීම</comment>
<comment xml:lang="sk">Požiadavka na certifikát PKCS#10</comment>
<comment xml:lang="ru">Запрос сертификации PKCS#10</comment>
<comment xml:lang="ro">Cerere de certificat PKCS#10</comment>
@@ -1645,6 +1586,7 @@ command to generate the output files.
<comment xml:lang="kk">PKCS#10 сертификацияға сұранымы</comment>
<comment xml:lang="ja">PKCS#10 証明書署名要求</comment>
<comment xml:lang="it">Richiesta certificazione PKCS#10</comment>
+ <comment xml:lang="is">PKCS#10 skilríkisbeiðni</comment>
<comment xml:lang="id">Permintaan sertifikasi PKCS#10</comment>
<comment xml:lang="ia">Requesta de certification PKCS#10</comment>
<comment xml:lang="hu">PKCS#10-tanúsítványkérés</comment>
@@ -1666,6 +1608,7 @@ command to generate the output files.
<comment xml:lang="ca">sol·licitud de certificació PKCS#10</comment>
<comment xml:lang="bg">Заявка за сертификат — PKCS#10</comment>
<comment xml:lang="be@latin">Zapyt sertyfikacyi PKCS#10</comment>
+ <comment xml:lang="be">запыт сертыфікацыі PKCS#10</comment>
<comment xml:lang="ar">طلب شهادة PKCS#10</comment>
<comment xml:lang="af">PKCS#10-sertifiseringsversoek</comment>
<acronym>PKCS</acronym>
@@ -1681,7 +1624,9 @@ command to generate the output files.
<comment xml:lang="tr">X.509 sertifikası</comment>
<comment xml:lang="sv">X.509-certifikat</comment>
<comment xml:lang="sr">Икс.509 уверење</comment>
+ <comment xml:lang="sq">dëshmi X.509</comment>
<comment xml:lang="sl">Datoteka potrdila X.509</comment>
+ <comment xml:lang="si">X.509 සහතිකය</comment>
<comment xml:lang="sk">Certifikát X.509</comment>
<comment xml:lang="ru">Сертификат X.509</comment>
<comment xml:lang="ro">Certificat X.509</comment>
@@ -1689,13 +1634,15 @@ command to generate the output files.
<comment xml:lang="pt">certificado X.509</comment>
<comment xml:lang="pl">Certyfikat X.509</comment>
<comment xml:lang="oc">certificat X.509</comment>
- <comment xml:lang="nl">X.509 certificaat</comment>
+ <comment xml:lang="nl">X.509-certificaat</comment>
<comment xml:lang="lv">X.509 sertifikāts</comment>
<comment xml:lang="lt">X.509 liudijimas</comment>
<comment xml:lang="ko">X.509 인증서</comment>
<comment xml:lang="kk">X.509 сертификаты</comment>
+ <comment xml:lang="ka">X.509 სერტიფიკატი</comment>
<comment xml:lang="ja">X.509 証明書</comment>
<comment xml:lang="it">Certificato X.509</comment>
+ <comment xml:lang="is">X.509 skilríki</comment>
<comment xml:lang="id">Sertifikat X.509</comment>
<comment xml:lang="ia">Certificato X.509</comment>
<comment xml:lang="hu">X.509 tanúsítvány</comment>
@@ -1716,6 +1663,7 @@ command to generate the output files.
<comment xml:lang="cs">certifikát X.509</comment>
<comment xml:lang="ca">certificat X.509</comment>
<comment xml:lang="bg">Сертификат — X.509</comment>
+ <comment xml:lang="be">сертыфікат X.509</comment>
<comment xml:lang="ast">Certificáu X.509</comment>
<comment xml:lang="ar">شهادة X.509</comment>
<comment xml:lang="af">X.509-sertifikaat</comment>
@@ -1726,35 +1674,18 @@ command to generate the output files.
<glob pattern="*.cer"/>
</mime-type>
<mime-type type="application/pkix-crl">
- <comment>certificate revocation list</comment>
- <comment xml:lang="zh_TW">憑證撤銷清單</comment>
- <comment xml:lang="zh_CN">证书吊销列表</comment>
+ <comment>Certificate revocation list</comment>
<comment xml:lang="uk">список відкликання сертифікатів</comment>
- <comment xml:lang="tr">sertifika iptal listesi</comment>
- <comment xml:lang="sv">certifikatåterkallningslista</comment>
- <comment xml:lang="ru">список аннулирования сертификатов</comment>
- <comment xml:lang="pt_BR">Lista de revogação de certificados</comment>
- <comment xml:lang="pt">lista de revogação de certificados</comment>
+ <comment xml:lang="sv">Certifikatåterkallningslista</comment>
+ <comment xml:lang="sq">listë shfuqizimi dëshmish</comment>
+ <comment xml:lang="ru">Список отзыва сертификатов</comment>
+ <comment xml:lang="pt_BR">Lista de revogação de certificado</comment>
<comment xml:lang="pl">Lista unieważnień certyfikatów</comment>
- <comment xml:lang="oc">lista de revocacion de certificats</comment>
- <comment xml:lang="ko">인증서 철회 목록</comment>
- <comment xml:lang="kk">сертификатты қайта шақыру тізімі</comment>
- <comment xml:lang="ja">証明書失効リスト</comment>
<comment xml:lang="it">Elenco certificati di revoca</comment>
- <comment xml:lang="id">daftar pencabutan sertifikat</comment>
- <comment xml:lang="hu">tanúsítvány visszavonási lista</comment>
- <comment xml:lang="hr">Popis opozvanih vjerodajnica</comment>
- <comment xml:lang="he">רשימת שלילת אישורים</comment>
- <comment xml:lang="fr">liste de révocation de certificat</comment>
- <comment xml:lang="fi">Varmenteiden sulkulista</comment>
- <comment xml:lang="eu">ziurtagiri-errebokatzeen zerrenda</comment>
+ <comment xml:lang="gl">Lista de revogación de certificados</comment>
<comment xml:lang="es">lista de revocación de certificados</comment>
- <comment xml:lang="en_GB">certificate revocation list</comment>
- <comment xml:lang="de">Zertifikatsperrliste</comment>
- <comment xml:lang="da">certifikat tilbagetrækkelsesliste</comment>
- <comment xml:lang="ca">llista de revocació de certificats</comment>
- <comment xml:lang="bg">Списък с отхвърлени сертификати</comment>
- <comment xml:lang="ar">قائمة إبطال شهادات</comment>
+ <comment xml:lang="de">Zertifikat-Widerrufliste</comment>
+ <comment xml:lang="be">спіс адкліканых сертыфікатаў</comment>
<magic>
<match type="string" value="-----BEGIN X509 CRL-----" offset="0"/>
</magic>
@@ -1769,7 +1700,9 @@ command to generate the output files.
<comment xml:lang="tr">PkiPath sertifika yolu</comment>
<comment xml:lang="sv">PkiPath-certifikatsekvens</comment>
<comment xml:lang="sr">путања уверења ПкиПат-а</comment>
+ <comment xml:lang="sq">shteg dëshmish PkiPath</comment>
<comment xml:lang="sl">Datoteka poti potrdila PkiPath</comment>
+ <comment xml:lang="si">PkiPath සහතික කිරීමේ මාර්ගය</comment>
<comment xml:lang="sk">Cesta k certifikátu PkiPath</comment>
<comment xml:lang="ru">Путь сертификации PkiPath</comment>
<comment xml:lang="ro">Cale certificare PkiPath</comment>
@@ -1784,6 +1717,7 @@ command to generate the output files.
<comment xml:lang="kk">PkiPath сертификаттау жолы</comment>
<comment xml:lang="ja">PkiPath 証明書パス</comment>
<comment xml:lang="it">Percorso certificazione PkiPath</comment>
+ <comment xml:lang="is">PkiPath vottunarslóð</comment>
<comment xml:lang="id">Alamat sertifikasi PkiPath</comment>
<comment xml:lang="ia">Cammino de certification PkiPath</comment>
<comment xml:lang="hu">PkiPath tanúsítványútvonal</comment>
@@ -1804,6 +1738,7 @@ command to generate the output files.
<comment xml:lang="cs">cesta k certifikátu PkiPath</comment>
<comment xml:lang="ca">camí cap a la certificació PkiPath</comment>
<comment xml:lang="bg">Сертификационна верига — PkiPath</comment>
+ <comment xml:lang="be">шлях сертыфікацыі PkiPath</comment>
<comment xml:lang="ast">Camín de certificación PkiPath</comment>
<comment xml:lang="ar">مسار شهادة PkiPath</comment>
<comment xml:lang="af">PkiPath-sertifiseringspad</comment>
@@ -1816,22 +1751,28 @@ command to generate the output files.
<comment xml:lang="uk">документ PostScript</comment>
<comment xml:lang="tr">PostScript belgesi</comment>
<comment xml:lang="sv">Postscript-dokument</comment>
+ <comment xml:lang="sq">dokument PostScript</comment>
<comment xml:lang="sl">Dokument PostScript</comment>
+ <comment xml:lang="si">PostScript ලේඛනය</comment>
<comment xml:lang="sk">Dokument PostScript</comment>
<comment xml:lang="ru">Документ PostScript</comment>
<comment xml:lang="pt_BR">Documento PostScript</comment>
<comment xml:lang="pt">documento PostScript</comment>
<comment xml:lang="pl">Dokument PostScript</comment>
<comment xml:lang="oc">document PostScript</comment>
+ <comment xml:lang="nl">PostScript-document</comment>
<comment xml:lang="lt">PostScript dokumentas</comment>
<comment xml:lang="ko">포스트스크립트 문서</comment>
<comment xml:lang="kk">PostScript құжаты</comment>
+ <comment xml:lang="ka">PostScript-ის დოკუმენტი</comment>
<comment xml:lang="ja">PostScript ドキュメント</comment>
<comment xml:lang="it">Documento PostScript</comment>
+ <comment xml:lang="is">PostScript skjal</comment>
<comment xml:lang="id">Dokumen PostScript</comment>
<comment xml:lang="hu">PostScript dokumentum</comment>
<comment xml:lang="hr">PostScript dokument</comment>
<comment xml:lang="he">מסמך PostScript</comment>
+ <comment xml:lang="gl">Documento de PostScript</comment>
<comment xml:lang="fr">document PostScript</comment>
<comment xml:lang="fi">PostScript-asiakirja</comment>
<comment xml:lang="eu">PostScript dokumentua</comment>
@@ -1841,6 +1782,7 @@ command to generate the output files.
<comment xml:lang="da">PostScript-dokument</comment>
<comment xml:lang="ca">document PostScript</comment>
<comment xml:lang="bg">Документ — PostScrip</comment>
+ <comment xml:lang="be">дакумент PostScript</comment>
<comment xml:lang="ar">مستند بوست سكربت</comment>
<sub-class-of type="text/plain"/>
<generic-icon name="x-office-document"/>
@@ -1859,8 +1801,9 @@ command to generate the output files.
<comment xml:lang="tr">Plucker belgesi</comment>
<comment xml:lang="sv">Plucker-dokument</comment>
<comment xml:lang="sr">Плакер документ</comment>
- <comment xml:lang="sq">Dokument Plucker</comment>
+ <comment xml:lang="sq">dokument Plucker</comment>
<comment xml:lang="sl">Dokument Plucker</comment>
+ <comment xml:lang="si">ප්ලකර් ලේඛනය</comment>
<comment xml:lang="sk">Dokument Plucker</comment>
<comment xml:lang="ru">Документ Plucker</comment>
<comment xml:lang="ro">Document Plucker</comment>
@@ -1875,8 +1818,10 @@ command to generate the output files.
<comment xml:lang="lt">Plucker dokumentas</comment>
<comment xml:lang="ko">Plucker 문서</comment>
<comment xml:lang="kk">Plucker құжаты</comment>
+ <comment xml:lang="ka">Plucker-ის დოკუმენტი</comment>
<comment xml:lang="ja">Plucker ドキュメント</comment>
<comment xml:lang="it">Documento Plucker</comment>
+ <comment xml:lang="is">Plucker skjal</comment>
<comment xml:lang="id">Dokumen Plucker</comment>
<comment xml:lang="ia">Documento Plucker</comment>
<comment xml:lang="hu">Plucker dokumentum</comment>
@@ -1899,6 +1844,7 @@ command to generate the output files.
<comment xml:lang="ca">document Plucker</comment>
<comment xml:lang="bg">Документ — Plucker</comment>
<comment xml:lang="be@latin">Dakument Plucker</comment>
+ <comment xml:lang="be">дакумент Plucker</comment>
<comment xml:lang="ast">Documentu Plucker</comment>
<comment xml:lang="ar">مستند Plucker</comment>
<comment xml:lang="af">Plucker-dokument</comment>
@@ -1915,22 +1861,28 @@ command to generate the output files.
<comment xml:lang="tr">RAML belgesi</comment>
<comment xml:lang="sv">RAML-dokument</comment>
<comment xml:lang="sr">РАМЛ документ</comment>
+ <comment xml:lang="sq">dokument RAML</comment>
<comment xml:lang="sl">Dokument RAML</comment>
+ <comment xml:lang="si">RAML ලේඛනය</comment>
<comment xml:lang="sk">Dokument RAML</comment>
<comment xml:lang="ru">Документ RAML</comment>
<comment xml:lang="pt_BR">Documento RAML</comment>
<comment xml:lang="pt">documento RAML</comment>
<comment xml:lang="pl">Dokument RAML</comment>
<comment xml:lang="oc">Document RAML</comment>
+ <comment xml:lang="nl">RAML-document</comment>
<comment xml:lang="lt">RAML dokumentas</comment>
<comment xml:lang="ko">RAML 문서</comment>
<comment xml:lang="kk">RAML құжаты</comment>
+ <comment xml:lang="ka">RAML-ის დოკუმენტი</comment>
<comment xml:lang="ja">RAML ドキュメント</comment>
<comment xml:lang="it">Documento RAML</comment>
+ <comment xml:lang="is">RAML skjal</comment>
<comment xml:lang="id">Dokumen RAML</comment>
<comment xml:lang="hu">RAML dokumentum</comment>
<comment xml:lang="hr">RAML dokument</comment>
<comment xml:lang="he">מסמך RAML</comment>
+ <comment xml:lang="gl">Documento RAML</comment>
<comment xml:lang="ga">cáipéis RAML</comment>
<comment xml:lang="fur">document RAML</comment>
<comment xml:lang="fr">document RAML</comment>
@@ -1943,12 +1895,13 @@ command to generate the output files.
<comment xml:lang="cs">dokument RAML</comment>
<comment xml:lang="ca">document RAML</comment>
<comment xml:lang="bg">Документ — RAML</comment>
+ <comment xml:lang="be">дакумент RAML</comment>
<comment xml:lang="ast">Documentu RAML</comment>
<comment xml:lang="ar">مستند RAML</comment>
<comment xml:lang="af">RAML-dokument</comment>
<acronym>RAML</acronym>
<expanded-acronym>RESTful API Modeling Language</expanded-acronym>
- <sub-class-of type="application/x-yaml"/>
+ <sub-class-of type="application/yaml"/>
<magic>
<match type="string" value="#%RAML " offset="0"/>
</magic>
@@ -1963,6 +1916,7 @@ command to generate the output files.
<comment xml:lang="sv">RELAX NG XML-schema</comment>
<comment xml:lang="sr">РЕЛАКС НГ ИксМЛ шема</comment>
<comment xml:lang="sl">Datoteka shema RELAX NG XML</comment>
+ <comment xml:lang="si">RELAX NG XML ක්‍රමය</comment>
<comment xml:lang="sk">XML schéma RELAX NG</comment>
<comment xml:lang="ru">XML-схема RELAX NG</comment>
<comment xml:lang="ro">Schemă RELAX NG XML</comment>
@@ -1970,13 +1924,14 @@ command to generate the output files.
<comment xml:lang="pt">Esquema RELAX NG XML</comment>
<comment xml:lang="pl">Schemat XML RELAX NG</comment>
<comment xml:lang="oc">esquèma XML RELAX NG</comment>
- <comment xml:lang="nl">RELAX NG XML schema</comment>
+ <comment xml:lang="nl">RELAX NG XML-schema</comment>
<comment xml:lang="lv">RELAX NG XML shēma</comment>
<comment xml:lang="lt">RELAX NG XML schema</comment>
<comment xml:lang="ko">RELAX NG XML 스키마</comment>
<comment xml:lang="kk">RELAX NG XML сұлбасы</comment>
<comment xml:lang="ja">RELAX NG XML スキーマ</comment>
<comment xml:lang="it">Schema XML RELAX NG</comment>
+ <comment xml:lang="is">RELAX NG XML skema</comment>
<comment xml:lang="id">Skema XML RELAX NG</comment>
<comment xml:lang="ia">Schema XML RELAX NG</comment>
<comment xml:lang="hu">RELAX NG XML-séma</comment>
@@ -1996,6 +1951,7 @@ command to generate the output files.
<comment xml:lang="cs">schéma RELAX NG XML</comment>
<comment xml:lang="ca">esquema XML en RELAX NG</comment>
<comment xml:lang="bg">Схема за XML — RELAX NG</comment>
+ <comment xml:lang="be">XML-схема RELAX NG</comment>
<comment xml:lang="ar">مخطط RELAX NG XML</comment>
<comment xml:lang="af">RELAX NG XML-skema</comment>
<acronym>RELAX NG</acronym>
@@ -2014,8 +1970,9 @@ command to generate the output files.
<comment xml:lang="tr">RTF belgesi</comment>
<comment xml:lang="sv">RTF-dokument</comment>
<comment xml:lang="sr">РТФ документ</comment>
- <comment xml:lang="sq">Dokument RTF</comment>
+ <comment xml:lang="sq">dokument RTF</comment>
<comment xml:lang="sl">Dokument RTF</comment>
+ <comment xml:lang="si">RTF ලේඛනය</comment>
<comment xml:lang="sk">Dokument RTF</comment>
<comment xml:lang="ru">Документ RTF</comment>
<comment xml:lang="ro">Document RTF</comment>
@@ -2030,8 +1987,10 @@ command to generate the output files.
<comment xml:lang="lt">RTF dokumentas</comment>
<comment xml:lang="ko">RTF 문서</comment>
<comment xml:lang="kk">RTF құжаты</comment>
+ <comment xml:lang="ka">RTF დოკუმენტი</comment>
<comment xml:lang="ja">RTF ドキュメント</comment>
<comment xml:lang="it">Documento RTF</comment>
+ <comment xml:lang="is">RTF skjal</comment>
<comment xml:lang="id">Dokumen RTF</comment>
<comment xml:lang="ia">Documento RTF</comment>
<comment xml:lang="hu">RTF dokumentum</comment>
@@ -2054,6 +2013,7 @@ command to generate the output files.
<comment xml:lang="ca">document RTF</comment>
<comment xml:lang="bg">Документ — RTF</comment>
<comment xml:lang="be@latin">Dakument RTF</comment>
+ <comment xml:lang="be">дакумент RTF</comment>
<comment xml:lang="ast">Documentu RTF</comment>
<comment xml:lang="ar">مستند RTF</comment>
<comment xml:lang="af">RTF-dokument</comment>
@@ -2076,8 +2036,9 @@ command to generate the output files.
<comment xml:lang="tr">Sieve posta süzgeç betiği</comment>
<comment xml:lang="sv">Sieve-epostfilterskript</comment>
<comment xml:lang="sr">Сјев скрипта пропусника поште</comment>
- <comment xml:lang="sq">Script filtrim poste Sieve</comment>
+ <comment xml:lang="sq">programth filtrimi poste Sieve</comment>
<comment xml:lang="sl">Skriptna datoteka Sieve poštnega filtra</comment>
+ <comment xml:lang="si">තැපැල් පෙරහන් ස්ක්‍රිප්ට් පෙරා ගන්න</comment>
<comment xml:lang="sk">Skript poštového filtra Sieve</comment>
<comment xml:lang="ru">Сценарий почтового фильтра Sieve</comment>
<comment xml:lang="ro">Script filtrare email Sieve</comment>
@@ -2094,6 +2055,7 @@ command to generate the output files.
<comment xml:lang="kk">Sieve пошталық фильтр сценарийі</comment>
<comment xml:lang="ja">Sieve メールフィルタスクリプト</comment>
<comment xml:lang="it">Script filtro posta Sieve</comment>
+ <comment xml:lang="is">Sieve póstsíuskrifta</comment>
<comment xml:lang="id">Skrip filter surat Sieve</comment>
<comment xml:lang="ia">Script de filtration de e-mail Sieve</comment>
<comment xml:lang="hu">Sieve levélszűrő parancsfájl</comment>
@@ -2108,17 +2070,18 @@ command to generate the output files.
<comment xml:lang="es">secuencia de órdenes de filtro en Sieve</comment>
<comment xml:lang="en_GB">Sieve mail filter script</comment>
<comment xml:lang="el">Δέσμη ενεργειών φιλτραρίσματος αλληλογραφίας Sieve</comment>
- <comment xml:lang="de">Sieve-E-Mail-Filterskript</comment>
+ <comment xml:lang="de">Sieve E-Mail-Filterskript</comment>
<comment xml:lang="da">Sieve e-post-filterprogram</comment>
<comment xml:lang="cs">skript poštovního filtru Sieve</comment>
<comment xml:lang="ca">script de filtre de correu Sieve</comment>
<comment xml:lang="bg">Скрипт-филтър за пресяване на поща</comment>
<comment xml:lang="be@latin">Skrypt filtravańnia pošty Sieve</comment>
+ <comment xml:lang="be">скрыпт паштовага фільтра Sieve</comment>
<comment xml:lang="ar">سكربت مرشح بريد Sieve</comment>
<comment xml:lang="af">Sieve-posfiltreerskrip</comment>
- <sub-class-of type="application/xml"/>
<generic-icon name="text-x-script"/>
<glob pattern="*.siv"/>
+ <glob pattern="*.sieve"/>
</mime-type>
<mime-type type="application/smil+xml">
<comment>SMIL document</comment>
@@ -2129,8 +2092,9 @@ command to generate the output files.
<comment xml:lang="tr">SMIL belgesi</comment>
<comment xml:lang="sv">SMIL-dokument</comment>
<comment xml:lang="sr">СМИЛ документ</comment>
- <comment xml:lang="sq">Dokument SMIL</comment>
+ <comment xml:lang="sq">dokument SMIL</comment>
<comment xml:lang="sl">Dokument SMIL</comment>
+ <comment xml:lang="si">SMIL ලේඛනය</comment>
<comment xml:lang="sk">Dokument SMIL</comment>
<comment xml:lang="ru">Документ SMIL</comment>
<comment xml:lang="ro">Document SMIL</comment>
@@ -2145,8 +2109,10 @@ command to generate the output files.
<comment xml:lang="lt">SMIL dokumentas</comment>
<comment xml:lang="ko">SMIL 문서</comment>
<comment xml:lang="kk">SMIL құжаты</comment>
+ <comment xml:lang="ka">SMIL-ის დოკუმენტი</comment>
<comment xml:lang="ja">SMIL ドキュメント</comment>
<comment xml:lang="it">Documento SMIL</comment>
+ <comment xml:lang="is">SMIL skjal</comment>
<comment xml:lang="id">Dokumen SMIL</comment>
<comment xml:lang="ia">Documento SMIL</comment>
<comment xml:lang="hu">SMIL dokumentum</comment>
@@ -2169,6 +2135,7 @@ command to generate the output files.
<comment xml:lang="ca">document SMIL</comment>
<comment xml:lang="bg">Документ — SMIL</comment>
<comment xml:lang="be@latin">Dakument SMIL</comment>
+ <comment xml:lang="be">дакумент SMIL</comment>
<comment xml:lang="ast">Documentu SMIL</comment>
<comment xml:lang="ar">مستند SMIL</comment>
<comment xml:lang="af">SMIL-dokument</comment>
@@ -2197,7 +2164,9 @@ command to generate the output files.
<comment xml:lang="tr">WPL çalma listesi</comment>
<comment xml:lang="sv">WPL-spellista</comment>
<comment xml:lang="sr">ВПЛ списак нумера</comment>
+ <comment xml:lang="sq">luajlistë WPL</comment>
<comment xml:lang="sl">Seznam predvajanja WPL</comment>
+ <comment xml:lang="si">WPL ධාවන ලැයිස්තුව</comment>
<comment xml:lang="sk">Zoznam skladieb WPL</comment>
<comment xml:lang="ru">Список воспроизведения WPL</comment>
<comment xml:lang="ro">Listă redare WPL</comment>
@@ -2210,8 +2179,10 @@ command to generate the output files.
<comment xml:lang="lt">WPL grojaraštis</comment>
<comment xml:lang="ko">WPL 재생 목록</comment>
<comment xml:lang="kk">WPL ойнау тізімі</comment>
+ <comment xml:lang="ka">WPL დასაკრავი სია</comment>
<comment xml:lang="ja">WPL プレイリスト</comment>
<comment xml:lang="it">Playlist WPL</comment>
+ <comment xml:lang="is">WPL spilunarlisti</comment>
<comment xml:lang="id">Senarai putar WPL</comment>
<comment xml:lang="ia">Lista de selection WPL</comment>
<comment xml:lang="hu">WPL-lejátszólista</comment>
@@ -2233,6 +2204,7 @@ command to generate the output files.
<comment xml:lang="cs">seznam k přehrání WPL</comment>
<comment xml:lang="ca">llista de reproducció WPL</comment>
<comment xml:lang="bg">Списък за изпълнение — WPL</comment>
+ <comment xml:lang="be">плэй-ліст WPL</comment>
<comment xml:lang="ar">قائمة تشغيل WPL</comment>
<comment xml:lang="af">WPL-speellys</comment>
<acronym>WPL</acronym>
@@ -2252,8 +2224,9 @@ command to generate the output files.
<comment xml:lang="tr">SQLite2 veri tabanı</comment>
<comment xml:lang="sv">SQLite2-databas</comment>
<comment xml:lang="sr">СКуЛајт2 база података</comment>
- <comment xml:lang="sq">Bazë me të dhëna SQLite2</comment>
+ <comment xml:lang="sq">bazë të dhënash SQLite2</comment>
<comment xml:lang="sl">Podatkovna zbirka SQLite2</comment>
+ <comment xml:lang="si">SQLite2 දත්ත සමුදාය</comment>
<comment xml:lang="sk">Databáza SQLite2</comment>
<comment xml:lang="ru">База данных SQLite2</comment>
<comment xml:lang="ro">Bază de date SQLite2</comment>
@@ -2270,6 +2243,7 @@ command to generate the output files.
<comment xml:lang="kk">SQLite2 дерекқоры</comment>
<comment xml:lang="ja">SQLite2 データベース</comment>
<comment xml:lang="it">Database SQLite2</comment>
+ <comment xml:lang="is">SQLite2 gagnagrunnur</comment>
<comment xml:lang="id">Basis data SQLite2</comment>
<comment xml:lang="ia">Base de datos SQLite2</comment>
<comment xml:lang="hu">SQLite2 adatbázis</comment>
@@ -2292,6 +2266,7 @@ command to generate the output files.
<comment xml:lang="ca">base de dades SQLite2</comment>
<comment xml:lang="bg">База от данни — SQLite2</comment>
<comment xml:lang="be@latin">Baza źviestak SQLite2</comment>
+ <comment xml:lang="be">база даных SQLite2</comment>
<comment xml:lang="ar">قاعدة بيانات SQLite2</comment>
<comment xml:lang="af">SQLite2-databasis</comment>
<glob pattern="*.sqlite2"/>
@@ -2308,8 +2283,9 @@ command to generate the output files.
<comment xml:lang="tr">SQLite3 veri tabanı</comment>
<comment xml:lang="sv">SQLite3-databas</comment>
<comment xml:lang="sr">СКуЛајт3 база података</comment>
- <comment xml:lang="sq">Bazë me të dhëna SQLite3</comment>
+ <comment xml:lang="sq">bazë të dhënash SQLite3</comment>
<comment xml:lang="sl">Podatkovna zbirka SQLite3</comment>
+ <comment xml:lang="si">SQLite3 දත්ත සමුදාය</comment>
<comment xml:lang="sk">Databáza SQLite3</comment>
<comment xml:lang="ru">База данных SQLite3</comment>
<comment xml:lang="ro">Bază de date SQLite3</comment>
@@ -2326,6 +2302,7 @@ command to generate the output files.
<comment xml:lang="kk">SQLite3 дерекқоры</comment>
<comment xml:lang="ja">SQLite3 データベース</comment>
<comment xml:lang="it">Database SQLite3</comment>
+ <comment xml:lang="is">SQLite3 gagnagrunnur</comment>
<comment xml:lang="id">Basis data SQLite3</comment>
<comment xml:lang="ia">Base de datos SQLite3</comment>
<comment xml:lang="hu">SQLite3 adatbázis</comment>
@@ -2348,6 +2325,7 @@ command to generate the output files.
<comment xml:lang="ca">base de dades SQLite3</comment>
<comment xml:lang="bg">База от данни — SQLite3</comment>
<comment xml:lang="be@latin">Baza źviestak SQLite3</comment>
+ <comment xml:lang="be">база даных SQLite3</comment>
<comment xml:lang="ar">قاعدة بيانات SQLite3</comment>
<comment xml:lang="af">SQLite3-databasis</comment>
<glob pattern="*.sqlite3"/>
@@ -2362,23 +2340,32 @@ command to generate the output files.
<comment xml:lang="uk">засіб профілювання системи Apple</comment>
<comment xml:lang="tr">Apple Sistem Profilcisi</comment>
<comment xml:lang="sv">Apple Systeminformation</comment>
+ <comment xml:lang="sq">Apple System Profiler</comment>
+ <comment xml:lang="si">ඇපල් පද්ධති පැතිකඩ</comment>
+ <comment xml:lang="ru">Apple System Profiler</comment>
<comment xml:lang="pt_BR">Apple System Profiler</comment>
<comment xml:lang="pt">Perfilador do sistema Apple</comment>
<comment xml:lang="pl">Profiler komputera Apple</comment>
+ <comment xml:lang="nl">Apple System Profiler</comment>
<comment xml:lang="ko">Apple 시스템 프로파일러</comment>
+ <comment xml:lang="kk">Apple жүйелік профильдеуші</comment>
<comment xml:lang="ja">Apple システムプロファイラー</comment>
<comment xml:lang="it">Profiler di sistema Apple</comment>
+ <comment xml:lang="is">Apple System Profiler</comment>
<comment xml:lang="id">Profiler Sistem Apple</comment>
<comment xml:lang="hu">Apple rendszerprofilozó</comment>
<comment xml:lang="hr">Apple profiler sustava</comment>
<comment xml:lang="he">מאפיין מערכת של Apple</comment>
+ <comment xml:lang="gl">Perfilador de sistema de Appl</comment>
<comment xml:lang="fr">Profileur système Apple</comment>
<comment xml:lang="fi">Applen järjestelmän profiloija</comment>
+ <comment xml:lang="eu">Apple sistemaren profilatzailea</comment>
<comment xml:lang="es">perfil del sistema de Apple</comment>
<comment xml:lang="en_GB">Apple System Profiler</comment>
<comment xml:lang="de">Apple-Systeminformationen</comment>
<comment xml:lang="da">Apple System Profiler</comment>
<comment xml:lang="ca">System Profiler d'Apple</comment>
+ <comment xml:lang="be">Apple System Profiler</comment>
<comment xml:lang="ar">محلل نظام أبل</comment>
<sub-class-of type="application/xml"/>
<magic>
@@ -2389,7 +2376,7 @@ command to generate the output files.
<glob pattern="*.spx" weight="40"/>
<root-XML namespaceURI="http://www.apple.com/DTDs/PropertyList-1.0.dtd" localName="plist"/>
</mime-type>
- <mime-type type="application/x-gedcom">
+ <mime-type type="text/vnd.familysearch.gedcom">
<comment>GEDCOM family history</comment>
<comment xml:lang="zh_TW">GEDCOM 族譜</comment>
<comment xml:lang="zh_CN">GEDCOM 家谱</comment>
@@ -2398,8 +2385,9 @@ command to generate the output files.
<comment xml:lang="tr">GEDCOM aile geçmişi</comment>
<comment xml:lang="sv">GEDCOM-släktträd</comment>
<comment xml:lang="sr">ГЕДКОМ историјат породице</comment>
- <comment xml:lang="sq">Kronollogji familje GEDCOM</comment>
+ <comment xml:lang="sq">historik familjeje GEDCOM</comment>
<comment xml:lang="sl">Datoteka družinske zgodovine GEDCOM</comment>
+ <comment xml:lang="si">GEDCOM පවුලේ ඉතිහාසය</comment>
<comment xml:lang="sk">Rodokmeň GEDCOM</comment>
<comment xml:lang="ru">История семьи GEDCOM</comment>
<comment xml:lang="ro">Tablou genealogic GEDCOM</comment>
@@ -2417,6 +2405,7 @@ command to generate the output files.
<comment xml:lang="ka">GEDCOM ოჯახის ისტორია</comment>
<comment xml:lang="ja">GEDCOM 家系図データ</comment>
<comment xml:lang="it">Cronologia famiglia GEDCOM</comment>
+ <comment xml:lang="is">GEDCOM ættartré</comment>
<comment xml:lang="id">Sejarah keluarga GEDCOM</comment>
<comment xml:lang="ia">Genealogia GEDCOM</comment>
<comment xml:lang="hu">GEDCOM családtörténet</comment>
@@ -2438,6 +2427,7 @@ command to generate the output files.
<comment xml:lang="ca">antecedents familiars GEDCOM</comment>
<comment xml:lang="bg">Родословно дърво — GEDCOM</comment>
<comment xml:lang="be@latin">Siamiejnaja historyja GEDCOM</comment>
+ <comment xml:lang="be">гісторыя сям'і GEDCOM</comment>
<comment xml:lang="ar">تاريخ عائلة GEDCOM</comment>
<comment xml:lang="af">GEDCOM-familiegeskiedenis</comment>
<acronym>GEDCOM</acronym>
@@ -2449,6 +2439,7 @@ command to generate the output files.
</magic>
<glob pattern="*.ged"/>
<glob pattern="*.gedcom"/>
+ <alias type="application/x-gedcom"/>
<alias type="text/gedcom"/>
</mime-type>
<mime-type type="video/x-flv">
@@ -2460,8 +2451,9 @@ command to generate the output files.
<comment xml:lang="tr">Flash video</comment>
<comment xml:lang="sv">Flash-video</comment>
<comment xml:lang="sr">Флеш видео</comment>
- <comment xml:lang="sq">Video Flash</comment>
+ <comment xml:lang="sq">video Flash</comment>
<comment xml:lang="sl">Video datoteka Flash</comment>
+ <comment xml:lang="si">ෆ්ලෑෂ් වීඩියෝව</comment>
<comment xml:lang="sk">Video Flash</comment>
<comment xml:lang="ru">Видео Flash</comment>
<comment xml:lang="ro">Video Flash</comment>
@@ -2479,6 +2471,7 @@ command to generate the output files.
<comment xml:lang="ka">Flash-ის ვიდეო</comment>
<comment xml:lang="ja">Flash 動画</comment>
<comment xml:lang="it">Video Flash</comment>
+ <comment xml:lang="is">Flash myndskeið</comment>
<comment xml:lang="id">Video Flash</comment>
<comment xml:lang="ia">Video Flash</comment>
<comment xml:lang="hu">Flash videó</comment>
@@ -2501,6 +2494,7 @@ command to generate the output files.
<comment xml:lang="ca">vídeo de Flash</comment>
<comment xml:lang="bg">Видео — Flash</comment>
<comment xml:lang="be@latin">Videa Flash</comment>
+ <comment xml:lang="be">відэа Flash</comment>
<comment xml:lang="ast">Videu en Flash</comment>
<comment xml:lang="ar">فيديو فلاش</comment>
<comment xml:lang="af">Flash-video</comment>
@@ -2521,7 +2515,9 @@ command to generate the output files.
<comment xml:lang="tr">JavaFX video</comment>
<comment xml:lang="sv">JavaFX-video</comment>
<comment xml:lang="sr">ЈаваФИкс видео</comment>
+ <comment xml:lang="sq">video JavaFX</comment>
<comment xml:lang="sl">Video JavaFX</comment>
+ <comment xml:lang="si">JavaFX වීඩියෝව</comment>
<comment xml:lang="sk">Video JavaFX</comment>
<comment xml:lang="ru">Видео JavaFX</comment>
<comment xml:lang="ro">Video JavaFX</comment>
@@ -2536,6 +2532,7 @@ command to generate the output files.
<comment xml:lang="kk">JavaFX аудиосы</comment>
<comment xml:lang="ja">JavaFX 動画</comment>
<comment xml:lang="it">Video JavaFX</comment>
+ <comment xml:lang="is">JavaFX myndskeið</comment>
<comment xml:lang="id">Video JavaFX</comment>
<comment xml:lang="ia">Video JavaFX</comment>
<comment xml:lang="hu">JavaFX videó</comment>
@@ -2557,6 +2554,7 @@ command to generate the output files.
<comment xml:lang="cs">video JavaFX</comment>
<comment xml:lang="ca">vídeo de JavaFX</comment>
<comment xml:lang="bg">Видео — JavaFX</comment>
+ <comment xml:lang="be">відэа JavaFX</comment>
<comment xml:lang="ast">Videu en JavaFX</comment>
<comment xml:lang="ar">فيديو JavaFX</comment>
<comment xml:lang="af">JavaFX-video</comment>
@@ -2579,8 +2577,9 @@ command to generate the output files.
<comment xml:lang="tr">SGF kaydı</comment>
<comment xml:lang="sv">SGF-protokoll</comment>
<comment xml:lang="sr">СГФ запис</comment>
- <comment xml:lang="sq">Regjistrim SGF</comment>
+ <comment xml:lang="sq">regjistrim SGF</comment>
<comment xml:lang="sl">Datoteka shranjene igre SGF</comment>
+ <comment xml:lang="si">SGF වාර්තාව</comment>
<comment xml:lang="sk">Záznam SGF</comment>
<comment xml:lang="ru">Запись SGF</comment>
<comment xml:lang="ro">Înregistrare SGF</comment>
@@ -2597,6 +2596,7 @@ command to generate the output files.
<comment xml:lang="kk">SGF жазбасы</comment>
<comment xml:lang="ja">SGF レコード</comment>
<comment xml:lang="it">Registrazione SGF</comment>
+ <comment xml:lang="is">SGF færsla</comment>
<comment xml:lang="id">Catatan SGF</comment>
<comment xml:lang="ia">Partita SGF</comment>
<comment xml:lang="hu">SGF pontszám</comment>
@@ -2618,6 +2618,7 @@ command to generate the output files.
<comment xml:lang="ca">registre SGF</comment>
<comment xml:lang="bg">Запис — SGF</comment>
<comment xml:lang="be@latin">Zapisanaja hulnia SGF</comment>
+ <comment xml:lang="be">запіс SGF</comment>
<comment xml:lang="ar">تسجيلة SGF</comment>
<comment xml:lang="af">SGF-rekord</comment>
<acronym>SGF</acronym>
@@ -2632,11 +2633,62 @@ command to generate the output files.
</mime-type>
<mime-type type="application/x-godot-project">
<comment>Godot Engine project</comment>
+ <comment xml:lang="zh_TW">Godot Engine 專案</comment>
+ <comment xml:lang="zh_CN">Godot Engine 项目</comment>
+ <comment xml:lang="uk">проєкт Godot Engine</comment>
+ <comment xml:lang="tr">Godot Engine projesi</comment>
+ <comment xml:lang="sv">Godot Engine-projekt</comment>
+ <comment xml:lang="sl">Projekt Godot Engine</comment>
+ <comment xml:lang="si">ගොඩොට් එන්ජින් ව්යාපෘතිය</comment>
+ <comment xml:lang="ru">Проект Godot Engine</comment>
+ <comment xml:lang="pt_BR">Projeto do Godot Engine</comment>
+ <comment xml:lang="pt">projeto Godot Engine</comment>
+ <comment xml:lang="pl">Projekt Godot Engine</comment>
+ <comment xml:lang="nl">Godot Engine-project</comment>
+ <comment xml:lang="ko">Godot 엔진 프로젝트</comment>
+ <comment xml:lang="kk">Godot Engine жобасы</comment>
+ <comment xml:lang="ja">Godot Engine プロジェクト</comment>
+ <comment xml:lang="it">Progetto Godot Engine</comment>
+ <comment xml:lang="hr">Godot Engine projekt</comment>
+ <comment xml:lang="he">מיזם של מנוע גודו</comment>
+ <comment xml:lang="gl">Proxecto do motor Godot</comment>
+ <comment xml:lang="fi">Godot Engine -projekti</comment>
+ <comment xml:lang="eu">Godot Engine proiektua</comment>
+ <comment xml:lang="es">proyecto de motor Godot</comment>
+ <comment xml:lang="en_GB">Godot Engine project</comment>
+ <comment xml:lang="de">Godot-Engine-Projekt</comment>
+ <comment xml:lang="be">праект Godot Engine</comment>
+ <comment xml:lang="ar">مشروع محرك جودو</comment>
<sub-class-of type="text/plain"/>
<glob pattern="project.godot"/>
</mime-type>
<mime-type type="application/x-godot-resource">
<comment>Godot Engine resource</comment>
+ <comment xml:lang="zh_CN">Godot Engine 资源</comment>
+ <comment xml:lang="uk">ресурс Godot Engine</comment>
+ <comment xml:lang="tr">Godot Engine kaynağı</comment>
+ <comment xml:lang="sv">Godot Engine-resurs</comment>
+ <comment xml:lang="sl">Vir Godot Engine</comment>
+ <comment xml:lang="si">ගොඩොට් එන්ජින් සම්පත</comment>
+ <comment xml:lang="ru">Ресурс Godot Engine</comment>
+ <comment xml:lang="pt_BR">Recurso do Godot Engine</comment>
+ <comment xml:lang="pt">recurso do Motor Godot</comment>
+ <comment xml:lang="pl">Zasób Godot Engine</comment>
+ <comment xml:lang="nl">Godot Engine-bron</comment>
+ <comment xml:lang="ko">Godot 엔진 자원</comment>
+ <comment xml:lang="kk">Godot Engine ресурсы</comment>
+ <comment xml:lang="ja">Godot Engine リソース</comment>
+ <comment xml:lang="it">Risorsa Godot Engine</comment>
+ <comment xml:lang="hr">Godot Engine resurs</comment>
+ <comment xml:lang="he">משאב של מנוע גודו</comment>
+ <comment xml:lang="gl">Recurso do motor Godot</comment>
+ <comment xml:lang="fi">Godot Engine -resurssi</comment>
+ <comment xml:lang="eu">Godot Engine baliabidea</comment>
+ <comment xml:lang="es">recurso de motor Godot</comment>
+ <comment xml:lang="en_GB">Godot Engine resource</comment>
+ <comment xml:lang="de">Godot-Engine-Ressource</comment>
+ <comment xml:lang="be">рэсурс Godot Engine</comment>
+ <comment xml:lang="ar">مورد محرك جودو</comment>
<glob pattern="*.res"/>
<glob pattern="*.tres"/>
<magic>
@@ -2645,6 +2697,32 @@ command to generate the output files.
</mime-type>
<mime-type type="application/x-godot-scene">
<comment>Godot Engine scene</comment>
+ <comment xml:lang="zh_TW">Godot Engine 場景</comment>
+ <comment xml:lang="zh_CN">Godot Engine 场景</comment>
+ <comment xml:lang="uk">сцена Godot Engine</comment>
+ <comment xml:lang="tr">Godot Engine sahnesi</comment>
+ <comment xml:lang="sv">Godot Engine-scen</comment>
+ <comment xml:lang="sl">Prizor Godot Engine</comment>
+ <comment xml:lang="si">ගොඩෝ එන්ජින් දර්ශනය</comment>
+ <comment xml:lang="ru">Сцена Godot Engine</comment>
+ <comment xml:lang="pt_BR">Cena do Godot Engine</comment>
+ <comment xml:lang="pt">cena do Godot Engine</comment>
+ <comment xml:lang="pl">Scena Godot Engine</comment>
+ <comment xml:lang="nl">Godot Engine-scène</comment>
+ <comment xml:lang="ko">Godot 엔진 장면</comment>
+ <comment xml:lang="kk">Godot Engine сахнасы</comment>
+ <comment xml:lang="ja">Godot Engine シーン</comment>
+ <comment xml:lang="it">Scena Godot Engine</comment>
+ <comment xml:lang="hr">Godot Engine scena</comment>
+ <comment xml:lang="he">סצנה של מנוע גודו</comment>
+ <comment xml:lang="gl">Escena do motor Godot</comment>
+ <comment xml:lang="fi">Godot Engine -näkymä</comment>
+ <comment xml:lang="eu">Godot Engine eszena</comment>
+ <comment xml:lang="es">escena de motor Godot</comment>
+ <comment xml:lang="en_GB">Godot Engine scene</comment>
+ <comment xml:lang="de">Godot-Engine-Szene</comment>
+ <comment xml:lang="be">сцэна Godot Engine</comment>
+ <comment xml:lang="ar">مشهد محرك جودو</comment>
<glob pattern="*.scn"/>
<glob pattern="*.tscn"/>
<glob pattern="*.escn"/>
@@ -2654,14 +2732,83 @@ command to generate the output files.
</mime-type>
<mime-type type="application/x-godot-shader">
<comment>Godot Engine shader</comment>
+ <comment xml:lang="zh_CN">Godot Engine 着色器</comment>
+ <comment xml:lang="uk">шейдер Godot Engine</comment>
+ <comment xml:lang="tr">Godot Engine gölgelendiricisi</comment>
+ <comment xml:lang="sv">Godot Engine-shader</comment>
+ <comment xml:lang="sl">Senčilnik Godot Engine</comment>
+ <comment xml:lang="si">ගොඩොට් එන්ජින් සෙවන</comment>
+ <comment xml:lang="ru">Шейдер Godot Engine</comment>
+ <comment xml:lang="pt_BR">Sombra do Godot Engine</comment>
+ <comment xml:lang="pt">sombra do Godot Engine</comment>
+ <comment xml:lang="pl">Program cieniujący Godot Engine</comment>
+ <comment xml:lang="nl">Godot Engine-shader</comment>
+ <comment xml:lang="ko">Godot 엔진 셰이더</comment>
+ <comment xml:lang="kk">Godot Engine шейдері</comment>
+ <comment xml:lang="ja">Godot Engine シェーダー</comment>
+ <comment xml:lang="it">Shader Godot Engine</comment>
+ <comment xml:lang="hr">Godot Engine shader</comment>
+ <comment xml:lang="he">הצללה של מנוע גודו</comment>
+ <comment xml:lang="gl">Sombreador do motor Godot</comment>
+ <comment xml:lang="fi">Godot Engine -varjostin</comment>
+ <comment xml:lang="eu">Godot Engine itzalgilea</comment>
+ <comment xml:lang="es">sombreador de Godot Engine</comment>
+ <comment xml:lang="en_GB">Godot Engine shader</comment>
+ <comment xml:lang="de">Godot-Engine-Shader</comment>
+ <comment xml:lang="be">шэйдар Godot Engine</comment>
+ <comment xml:lang="ar">مظلل محرك جودو</comment>
<sub-class-of type="text/plain"/>
<glob pattern="*.gdshader"/>
</mime-type>
<mime-type type="application/x-gdscript">
<comment>GDScript script</comment>
+ <comment xml:lang="zh_TW">GDScript 指令稿</comment>
+ <comment xml:lang="zh_CN">GDScript 脚本</comment>
+ <comment xml:lang="uk">скрипт GDScript</comment>
+ <comment xml:lang="tr">GDScript betiği</comment>
+ <comment xml:lang="sv">GDScript-skript</comment>
+ <comment xml:lang="sl">Skript GDScript</comment>
+ <comment xml:lang="si">GDScript පිටපත</comment>
+ <comment xml:lang="ru">Сценарий GDScript</comment>
+ <comment xml:lang="pt_BR">Script GDScript</comment>
+ <comment xml:lang="pl">Skrypt GDScript</comment>
+ <comment xml:lang="nl">GDScript-script</comment>
+ <comment xml:lang="ko">GDScript 스크립트</comment>
+ <comment xml:lang="kk">GDScript скрипті</comment>
+ <comment xml:lang="ka">GDScript-ის სკრიპტი</comment>
+ <comment xml:lang="ja">GDScript スクリプト</comment>
+ <comment xml:lang="it">Script GDScript</comment>
+ <comment xml:lang="hr">GDScript skripta</comment>
+ <comment xml:lang="he">סקריפט GDScript</comment>
+ <comment xml:lang="gl">Script de GDScript</comment>
+ <comment xml:lang="fi">GDScript-skripti</comment>
+ <comment xml:lang="eu">GDScript scripta</comment>
+ <comment xml:lang="es">secuencia de órdenes en GDScript</comment>
+ <comment xml:lang="en_GB">GDScript script</comment>
+ <comment xml:lang="de">GDScript-Skript</comment>
+ <comment xml:lang="be">скрыпт GDScript</comment>
+ <comment xml:lang="ar">سكربت GDScript</comment>
<sub-class-of type="text/plain"/>
<glob pattern="*.gd"/>
</mime-type>
+ <mime-type type="application/its+xml">
+ <comment>ITS translation file</comment>
+ <comment xml:lang="uk">файл перекладу ITS</comment>
+ <comment xml:lang="sv">ITS-översättningsfil</comment>
+ <comment xml:lang="ru">Файл перевода ITS</comment>
+ <comment xml:lang="pl">Plik tłumaczenia ITS</comment>
+ <comment xml:lang="es">archivo de traducción ITS</comment>
+ <comment xml:lang="de">ITS-Übersetzungsdatei</comment>
+ <acronym>ITS</acronym>
+ <expanded-acronym>Internationalization Tag Set</expanded-acronym>
+ <sub-class-of type="application/xml"/>
+ <generic-icon name="text-x-generic"/>
+ <glob pattern="*.its"/>
+ <magic>
+ <match type="string" value="&lt;its" offset="0:256"/>
+ </magic>
+ <root-XML namespaceURI="http://www.w3.org/2005/11/its" localName="its"/>
+ </mime-type>
<mime-type type="application/xliff+xml">
<comment>XLIFF translation file</comment>
<comment xml:lang="zh_TW">XLIFF 翻譯檔</comment>
@@ -2671,8 +2818,9 @@ command to generate the output files.
<comment xml:lang="tr">XLIFF çeviri dosyası</comment>
<comment xml:lang="sv">XLIFF-översättningsfil</comment>
<comment xml:lang="sr">ИксЛИФФ датотека превода</comment>
- <comment xml:lang="sq">File përkthimesh XLIFF</comment>
+ <comment xml:lang="sq">kartelë përkthimesh XLIFF</comment>
<comment xml:lang="sl">Datoteka prevoda XLIFF</comment>
+ <comment xml:lang="si">XLIFF පරිවර්තන ගොනුව</comment>
<comment xml:lang="sk">Súbor prekladu XLIFF</comment>
<comment xml:lang="ru">Файл перевода XLIFF</comment>
<comment xml:lang="ro">Fișier de traducere XLIFF</comment>
@@ -2687,8 +2835,10 @@ command to generate the output files.
<comment xml:lang="lt">XLIFF vertimo failas</comment>
<comment xml:lang="ko">XLIFF 번역 파일</comment>
<comment xml:lang="kk">XLIFF аударма файлы</comment>
+ <comment xml:lang="ka">XLIFF თარგმნის ფაილი</comment>
<comment xml:lang="ja">XLIFF 翻訳ファイル</comment>
<comment xml:lang="it">File traduzione XLIFF</comment>
+ <comment xml:lang="is">XLIFF-þýðingaskrá</comment>
<comment xml:lang="id">Berkas terjemahan XLIFF</comment>
<comment xml:lang="ia">File de traduction XLIFF</comment>
<comment xml:lang="hu">XLIFF fordítási fájl</comment>
@@ -2704,12 +2854,13 @@ command to generate the output files.
<comment xml:lang="es">archivo de traducción XLIFF</comment>
<comment xml:lang="en_GB">XLIFF translation file</comment>
<comment xml:lang="el">Αρχείο μετάφρασης XLIFF</comment>
- <comment xml:lang="de">XLIFF-Übersetzung</comment>
+ <comment xml:lang="de">XLIFF-Übersetzungsdatei</comment>
<comment xml:lang="da">XLIFF-oversættelsesfil</comment>
<comment xml:lang="cs">soubor překladu XLIFF</comment>
<comment xml:lang="ca">fitxer de traducció XLIFF</comment>
<comment xml:lang="bg">Превод — XLIFF</comment>
<comment xml:lang="be@latin">Fajł pierakładu XLIFF</comment>
+ <comment xml:lang="be">файл перакладу XLIFF</comment>
<comment xml:lang="ast">Ficheru de traducciones XLIFF</comment>
<comment xml:lang="ar">ملف ترجمة XLIFF</comment>
<comment xml:lang="af">XLIFF-vertaallêer</comment>
@@ -2727,13 +2878,40 @@ command to generate the output files.
</mime-type>
<mime-type type="application/toml">
<comment>TOML document</comment>
+ <comment xml:lang="zh_CN">TOML 文档</comment>
+ <comment xml:lang="uk">документ TOML</comment>
+ <comment xml:lang="tr">TOML belgesi</comment>
+ <comment xml:lang="sv">TOML-dokument</comment>
+ <comment xml:lang="sq">dokument TOML</comment>
+ <comment xml:lang="sl">Dokument TOML</comment>
+ <comment xml:lang="si">TOML ලේඛනය</comment>
+ <comment xml:lang="ru">Документ TOML</comment>
+ <comment xml:lang="pt_BR">Documento TOML</comment>
+ <comment xml:lang="pl">Dokument TOML</comment>
+ <comment xml:lang="oc">document TOML</comment>
+ <comment xml:lang="nl">TOML-document</comment>
+ <comment xml:lang="ko">TOML 문서</comment>
+ <comment xml:lang="kk">TOML құжаты</comment>
+ <comment xml:lang="ka">TOML დოკუმენტი</comment>
+ <comment xml:lang="ja">TOML ドキュメント</comment>
+ <comment xml:lang="it">Documento TOML</comment>
+ <comment xml:lang="hr">TOML dokument</comment>
+ <comment xml:lang="he">מסמך TOML</comment>
+ <comment xml:lang="gl">Documento TOML</comment>
+ <comment xml:lang="fi">TOML-asiakirja</comment>
+ <comment xml:lang="eu">TOML dokumentua</comment>
+ <comment xml:lang="es">documento TOML</comment>
+ <comment xml:lang="en_GB">TOML document</comment>
+ <comment xml:lang="de">TOML-Dokument</comment>
+ <comment xml:lang="be">дакумент TOML</comment>
+ <comment xml:lang="ar">مستند TOML</comment>
<acronym>TOML</acronym>
<expanded-acronym>Tom's Obvious Minimal Language</expanded-acronym>
<sub-class-of type="text/plain"/>
<generic-icon name="text-x-generic"/>
<glob pattern="*.toml"/>
</mime-type>
- <mime-type type="application/x-yaml">
+ <mime-type type="application/yaml">
<comment>YAML document</comment>
<comment xml:lang="zh_TW">YAML 文件</comment>
<comment xml:lang="zh_CN">YAML 文档</comment>
@@ -2741,7 +2919,9 @@ command to generate the output files.
<comment xml:lang="tr">YAML belgesi</comment>
<comment xml:lang="sv">YAML-dokument</comment>
<comment xml:lang="sr">ЈАМЛ документ</comment>
+ <comment xml:lang="sq">dokument YAML</comment>
<comment xml:lang="sl">Dokument YAML</comment>
+ <comment xml:lang="si">YAML ලේඛනය</comment>
<comment xml:lang="sk">Dokument YAML</comment>
<comment xml:lang="ru">Документ YAML</comment>
<comment xml:lang="ro">Document YAML</comment>
@@ -2749,13 +2929,15 @@ command to generate the output files.
<comment xml:lang="pt">documento YAML</comment>
<comment xml:lang="pl">Dokument YAML</comment>
<comment xml:lang="oc">document YAML</comment>
- <comment xml:lang="nl">YAML document</comment>
+ <comment xml:lang="nl">YAML-document</comment>
<comment xml:lang="lv">YAML dokuments</comment>
<comment xml:lang="lt">YAML dokumentas</comment>
<comment xml:lang="ko">YAML 문서</comment>
<comment xml:lang="kk">YAML құжаты</comment>
+ <comment xml:lang="ka">YAML დოკუმენტი</comment>
<comment xml:lang="ja">YAML ドキュメント</comment>
<comment xml:lang="it">Documento YAML</comment>
+ <comment xml:lang="is">YAML skjal</comment>
<comment xml:lang="id">Dokumen YAML</comment>
<comment xml:lang="ia">Documento YAML</comment>
<comment xml:lang="hu">YAML-dokumentum</comment>
@@ -2777,6 +2959,7 @@ command to generate the output files.
<comment xml:lang="cs">dokument YAML</comment>
<comment xml:lang="ca">document YAML</comment>
<comment xml:lang="bg">Документ — YAML</comment>
+ <comment xml:lang="be">дакумент YAML</comment>
<comment xml:lang="ast">Documentu YAML</comment>
<comment xml:lang="ar">مستند YAML</comment>
<comment xml:lang="af">YAML-dokument</comment>
@@ -2789,6 +2972,7 @@ command to generate the output files.
</magic>
<glob pattern="*.yaml"/>
<glob pattern="*.yml"/>
+ <alias type="application/x-yaml"/>
<alias type="text/yaml"/>
<alias type="text/x-yaml"/>
</mime-type>
@@ -2801,8 +2985,9 @@ command to generate the output files.
<comment xml:lang="tr">Corel Draw çizimi</comment>
<comment xml:lang="sv">Corel Draw-teckning</comment>
<comment xml:lang="sr">Корелов цртеж</comment>
- <comment xml:lang="sq">Vizatim Corel Draw</comment>
+ <comment xml:lang="sq">vizatim Corel Draw</comment>
<comment xml:lang="sl">Datoteka risbe Corel Draw</comment>
+ <comment xml:lang="si">Corel Draw ඇඳීම</comment>
<comment xml:lang="sk">Kresba Corel Draw</comment>
<comment xml:lang="ru">Рисунок Corel Draw</comment>
<comment xml:lang="ro">Desen Corel Draw</comment>
@@ -2821,6 +3006,7 @@ command to generate the output files.
<comment xml:lang="ka">Corel Draw-ის ნახაზი</comment>
<comment xml:lang="ja">Corel Draw ドロー</comment>
<comment xml:lang="it">Disegno Corel Draw</comment>
+ <comment xml:lang="is">Corel Draw teikning</comment>
<comment xml:lang="id">Gambar Corel Draw</comment>
<comment xml:lang="ia">Designo Corel Draw</comment>
<comment xml:lang="hu">Corel Draw-rajz</comment>
@@ -2844,6 +3030,7 @@ command to generate the output files.
<comment xml:lang="ca">dibuix de Corel Draw</comment>
<comment xml:lang="bg">Чертеж — Corel Draw</comment>
<comment xml:lang="be@latin">Rysunak Corel Draw</comment>
+ <comment xml:lang="be">рысунак Corel Draw</comment>
<comment xml:lang="az">Corel Draw çəkimi</comment>
<comment xml:lang="ast">Dibuxu de Corel Draw</comment>
<comment xml:lang="ar">تصميم Corel Draw</comment>
@@ -2870,8 +3057,9 @@ command to generate the output files.
<comment xml:lang="tr">HPGL dosyası</comment>
<comment xml:lang="sv">HPGL-fil</comment>
<comment xml:lang="sr">ХПГЛ датотека</comment>
- <comment xml:lang="sq">File HPGL</comment>
+ <comment xml:lang="sq">kartelë HPGL</comment>
<comment xml:lang="sl">Datoteka HPGL</comment>
+ <comment xml:lang="si">HPGL ගොනුව</comment>
<comment xml:lang="sk">Súbor HPGL</comment>
<comment xml:lang="ru">Файл HPGL</comment>
<comment xml:lang="ro">Fișier HPGL</comment>
@@ -2886,8 +3074,10 @@ command to generate the output files.
<comment xml:lang="lt">HPGL failas</comment>
<comment xml:lang="ko">HPGL 파일</comment>
<comment xml:lang="kk">HPGL файлы</comment>
+ <comment xml:lang="ka">HPGL ფაილი</comment>
<comment xml:lang="ja">HPGL ファイル</comment>
<comment xml:lang="it">File HPGL</comment>
+ <comment xml:lang="is">HPGL skrá</comment>
<comment xml:lang="id">Berkas HPGL</comment>
<comment xml:lang="ia">File HPGL</comment>
<comment xml:lang="hu">HPGL fájl</comment>
@@ -2910,6 +3100,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer HPGL</comment>
<comment xml:lang="bg">Файл — HPGL</comment>
<comment xml:lang="be@latin">Fajł HPGL</comment>
+ <comment xml:lang="be">файл HPGL</comment>
<comment xml:lang="ast">Ficheru HPGL</comment>
<comment xml:lang="ar">ملف HPGL</comment>
<comment xml:lang="af">HPGL-lêer</comment>
@@ -2927,8 +3118,9 @@ command to generate the output files.
<comment xml:lang="tr">PCL dosyası</comment>
<comment xml:lang="sv">PCL-fil</comment>
<comment xml:lang="sr">ПЦЛ датотека</comment>
- <comment xml:lang="sq">File PCL</comment>
+ <comment xml:lang="sq">kartelë PCL</comment>
<comment xml:lang="sl">Datoteka PCL</comment>
+ <comment xml:lang="si">PCL ගොනුව</comment>
<comment xml:lang="sk">Súbor PCL</comment>
<comment xml:lang="ru">Файл PCL</comment>
<comment xml:lang="ro">Fișier PCL</comment>
@@ -2943,8 +3135,10 @@ command to generate the output files.
<comment xml:lang="lt">PCL failas</comment>
<comment xml:lang="ko">PCL 파일</comment>
<comment xml:lang="kk">PCL файлы</comment>
+ <comment xml:lang="ka">PCL ფაილი</comment>
<comment xml:lang="ja">PCL ファイル</comment>
<comment xml:lang="it">File PCL</comment>
+ <comment xml:lang="is">PCL skrá</comment>
<comment xml:lang="id">Berkas PCL</comment>
<comment xml:lang="ia">File PCL</comment>
<comment xml:lang="hu">PCL fájl</comment>
@@ -2967,6 +3161,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer PCL</comment>
<comment xml:lang="bg">Файл — PCL</comment>
<comment xml:lang="be@latin">Fajł PCL</comment>
+ <comment xml:lang="be">файл PCL</comment>
<comment xml:lang="ast">FIcheru PCL</comment>
<comment xml:lang="ar">ملف PCL</comment>
<comment xml:lang="af">PCL-lêer</comment>
@@ -2975,17 +3170,33 @@ command to generate the output files.
<generic-icon name="image-x-generic"/>
<glob pattern="*.pcl"/>
</mime-type>
+ <mime-type type="application/vnd.cups-ppd">
+ <comment>PostScript printer description</comment>
+ <comment xml:lang="uk">опис принтера PostScript</comment>
+ <comment xml:lang="sv">Postscript-skrivarbeskrivning</comment>
+ <comment xml:lang="ru">Описание принтера PostScript</comment>
+ <comment xml:lang="pt_BR">Descrição de impressora PostScript</comment>
+ <comment xml:lang="pl">Opis drukarki PostScript</comment>
+ <comment xml:lang="es">descripción de impresora PostScript</comment>
+ <comment xml:lang="de">PostScript-Druckerbeschreibung</comment>
+ <sub-class-of type="text/plain"/>
+ <magic>
+ <match type="string" value="*PPD-Adobe:" offset="0"/>
+ </magic>
+ <glob pattern="*.ppd"/>
+ </mime-type>
<mime-type type="application/vnd.lotus-1-2-3">
<comment>Lotus 1-2-3 spreadsheet</comment>
<comment xml:lang="zh_TW">Lotus 1-2-3 試算表</comment>
<comment xml:lang="zh_CN">Lotus 1-2-3 电子表格</comment>
<comment xml:lang="vi">Bảng tính Lotus 1-2-3</comment>
- <comment xml:lang="uk">ел. таблиця Lotus 1-2-3</comment>
+ <comment xml:lang="uk">електронна таблиця Lotus 1-2-3</comment>
<comment xml:lang="tr">Lotus 1-2-3 hesap çizelgesi</comment>
<comment xml:lang="sv">Lotus 1-2-3-kalkylblad</comment>
<comment xml:lang="sr">Лотусова 1-2-3 табела</comment>
- <comment xml:lang="sq">Fletë llogaritjesh Lotus 1-2-3</comment>
+ <comment xml:lang="sq">fletëllogaritje Lotus 1-2-3</comment>
<comment xml:lang="sl">Preglednica Lotus 1-2-3</comment>
+ <comment xml:lang="si">නෙළුම් 1-2-3 පැතුරුම්පත</comment>
<comment xml:lang="sk">Zošit Lotus 1-2-3</comment>
<comment xml:lang="ru">Электронная таблица Lotus 1-2-3</comment>
<comment xml:lang="ro">Foaie de calcul Lotus 1-2-3</comment>
@@ -3003,6 +3214,7 @@ command to generate the output files.
<comment xml:lang="kk">Lotus 1-2-3 электрондық кестесі</comment>
<comment xml:lang="ja">Lotus 1-2-3 スプレッドシート</comment>
<comment xml:lang="it">Foglio di calcolo Lotus 1-2-3</comment>
+ <comment xml:lang="is">Lotus 1-2-3 töflureikniskjal</comment>
<comment xml:lang="id">Lembar sebar Lotus 1-2-3</comment>
<comment xml:lang="ia">Folio de calculo Lotus 1-2-3</comment>
<comment xml:lang="hu">Lotus 1-2-3-munkafüzet</comment>
@@ -3026,6 +3238,7 @@ command to generate the output files.
<comment xml:lang="ca">full de càlcul de Lotus 1-2-3</comment>
<comment xml:lang="bg">Таблица — Lotus 1-2-3</comment>
<comment xml:lang="be@latin">Raźlikovy arkuš Lotus 1-2-3</comment>
+ <comment xml:lang="be">электронная табліца Lotus 1-2-3</comment>
<comment xml:lang="az">Lotus 1-2-3 hesab cədvəli</comment>
<comment xml:lang="ast">Fueya de cálculu de Lotus 1-2-3</comment>
<comment xml:lang="ar">جدول Lotus 1-2-3</comment>
@@ -3052,20 +3265,26 @@ command to generate the output files.
<comment xml:lang="uk">документ Lotus Word Pro</comment>
<comment xml:lang="tr">Lotus Word Pro belgesi</comment>
<comment xml:lang="sv">Lotus Word Pro-dokument</comment>
+ <comment xml:lang="sq">dokument Lotus Word Pro</comment>
<comment xml:lang="sl">Dokument Lotus Word Pro</comment>
+ <comment xml:lang="si">Lotus Word Pro ලේඛනය</comment>
<comment xml:lang="sk">Dokument Lotus Word Pro</comment>
<comment xml:lang="ru">Документ Lotus Word Pro</comment>
<comment xml:lang="pt_BR">Documento do Lotus Word Pro</comment>
<comment xml:lang="pt">documento Lotus Word Pro</comment>
<comment xml:lang="pl">Dokument Lotus Word Pro</comment>
+ <comment xml:lang="oc">document Lotus Word Pro</comment>
+ <comment xml:lang="nl">Lotus Word Pro-document</comment>
<comment xml:lang="ko">Lotus 워드 프로 문서</comment>
<comment xml:lang="kk">Lotus Word Pro құжаты</comment>
<comment xml:lang="ja">Lotus Word Pro ドキュメント</comment>
<comment xml:lang="it">Documento Lotus Word Pro</comment>
+ <comment xml:lang="is">Lotus Word Pro skjal</comment>
<comment xml:lang="id">Dokumen Lotus Word Pro</comment>
<comment xml:lang="hu">Lotus Word Pro dokumentum</comment>
<comment xml:lang="hr">Lotus Word Pro dokument</comment>
<comment xml:lang="he">מסמך Lotus Word Pro</comment>
+ <comment xml:lang="gl">Documento de Lotus Word Pro</comment>
<comment xml:lang="fr">document Lotus Word Pro</comment>
<comment xml:lang="fi">Lotus Word Pro -asiakirja</comment>
<comment xml:lang="eu">Lotus Word Pro dokumentua</comment>
@@ -3075,6 +3294,7 @@ command to generate the output files.
<comment xml:lang="da">Lotus Word Pro-dokument</comment>
<comment xml:lang="ca">document de Lotus Word Pro</comment>
<comment xml:lang="bg">Документ — Lotus Word Pro</comment>
+ <comment xml:lang="be">дакумент Lotus Word Pro</comment>
<comment xml:lang="ar">مستند لوتس ورد برو</comment>
<generic-icon name="x-office-document"/>
<magic>
@@ -3082,6 +3302,29 @@ command to generate the output files.
</magic>
<glob pattern="*.lwp"/>
</mime-type>
+ <mime-type type="application/x-lmdb">
+ <comment>LMDB database</comment>
+ <comment xml:lang="uk">база даних LMDB</comment>
+ <comment xml:lang="sv">LMDB-databas</comment>
+ <comment xml:lang="sq">bazë të dhënash LMDB</comment>
+ <comment xml:lang="ru">База данных LMDB</comment>
+ <comment xml:lang="pt_BR">Banco de dados LMDB</comment>
+ <comment xml:lang="pl">Baza danych LMDB</comment>
+ <comment xml:lang="it">Database LMDB</comment>
+ <comment xml:lang="gl">Base de datos LMDB</comment>
+ <comment xml:lang="eu">LMDB datu-basea</comment>
+ <comment xml:lang="es">base de datos LMDB</comment>
+ <comment xml:lang="de">LMDB-Datenbank</comment>
+ <comment xml:lang="be">база даных LMDB</comment>
+ <acronym>LMDB</acronym>
+ <expanded-acronym>Lightning Memory-Mapped Database</expanded-acronym>
+ <generic-icon name="x-office-document"/>
+ <magic>
+ <match offset="16" type="little32" value="0xBEEFC0DE"/>
+ </magic>
+ <glob pattern="*.mdb"/>
+ <glob pattern="*.lmdb"/>
+ </mime-type>
<mime-type type="application/vnd.ms-access">
<comment>JET database</comment>
<comment xml:lang="zh_TW">JET 資料庫</comment>
@@ -3091,8 +3334,9 @@ command to generate the output files.
<comment xml:lang="tr">JET veri tabanı</comment>
<comment xml:lang="sv">JET-databas</comment>
<comment xml:lang="sr">ЈЕТ база података</comment>
- <comment xml:lang="sq">Bazë me të dhëna JET</comment>
+ <comment xml:lang="sq">bazë të dhënash JET</comment>
<comment xml:lang="sl">Podatkovna zbirka JET</comment>
+ <comment xml:lang="si">JET දත්ත සමුදාය</comment>
<comment xml:lang="sk">Databáza JET</comment>
<comment xml:lang="ru">База данных JET</comment>
<comment xml:lang="ro">Bază de date JET</comment>
@@ -3109,6 +3353,7 @@ command to generate the output files.
<comment xml:lang="kk">JET дерекқоры</comment>
<comment xml:lang="ja">JET データベース</comment>
<comment xml:lang="it">Database JET</comment>
+ <comment xml:lang="is">JET gagnagrunnur</comment>
<comment xml:lang="id">Basis data JET</comment>
<comment xml:lang="ia">Base de datos JET</comment>
<comment xml:lang="hu">JET adatbázis</comment>
@@ -3131,6 +3376,7 @@ command to generate the output files.
<comment xml:lang="ca">base de dades JET</comment>
<comment xml:lang="bg">База от данни — JET</comment>
<comment xml:lang="be@latin">Baza źviestak JET</comment>
+ <comment xml:lang="be">база даных JET</comment>
<comment xml:lang="ast">Base de datos JETº</comment>
<comment xml:lang="ar">قاعدة بيانات JET</comment>
<comment xml:lang="af">JET-databasis</comment>
@@ -3140,7 +3386,7 @@ command to generate the output files.
<magic>
<match offset="0" type="string" value="\x00\x01\x00\x00Standard Jet DB"/>
</magic>
- <glob pattern="*.mdb"/>
+ <glob pattern="*.mdb" weight="60"/>
<alias type="application/msaccess"/>
<alias type="application/vnd.msaccess"/>
<alias type="application/x-msaccess"/>
@@ -3157,7 +3403,9 @@ command to generate the output files.
<comment xml:lang="tr">Microsoft Cabinet arşivi</comment>
<comment xml:lang="sv">Microsoft Cabinet-arkiv</comment>
<comment xml:lang="sr">Мајкрософтова кабинет архива</comment>
+ <comment xml:lang="sq">arkiv Microsoft Cabinet</comment>
<comment xml:lang="sl">Datoteka arhiva Microsoft Cabinet</comment>
+ <comment xml:lang="si">Microsoft කැබිනට් සංරක්ෂිතය</comment>
<comment xml:lang="sk">Archív Microsoft Cabinet</comment>
<comment xml:lang="ru">Архив Microsoft Cabinet</comment>
<comment xml:lang="ro">Arhivă Microsoft Cabinet</comment>
@@ -3173,6 +3421,7 @@ command to generate the output files.
<comment xml:lang="ka">Microsoft-ის Cabinet არქივი</comment>
<comment xml:lang="ja">Microsoft Cabinet アーカイブ</comment>
<comment xml:lang="it">Archivio Microsoft Cabinet</comment>
+ <comment xml:lang="is">Microsoft Cabinet safnskrá</comment>
<comment xml:lang="id">Arsip Microsoft Cabinet</comment>
<comment xml:lang="ia">Archivo Microsoft Cabinet</comment>
<comment xml:lang="hu">Microsoft Cabinet archívum</comment>
@@ -3193,6 +3442,7 @@ command to generate the output files.
<comment xml:lang="cs">archiv Microsoft Cabinet</comment>
<comment xml:lang="ca">arxiu de Microsoft Cabinet</comment>
<comment xml:lang="bg">Архив — Microsoft Cabinet</comment>
+ <comment xml:lang="be">архіў Microsoft Cabinet</comment>
<comment xml:lang="ar">أرشيف Microsoft Cabinet</comment>
<comment xml:lang="af">Microsoft Cabinet-argief</comment>
<generic-icon name="package-x-generic"/>
@@ -3207,12 +3457,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">Excel 試算表</comment>
<comment xml:lang="zh_CN">Excel 电子表格</comment>
<comment xml:lang="vi">Bảng tính Excel</comment>
- <comment xml:lang="uk">ел. таблиця Excel</comment>
+ <comment xml:lang="uk">електронна таблиця Excel</comment>
<comment xml:lang="tr">Excel hesap çizelgesi</comment>
<comment xml:lang="sv">Excel-kalkylblad</comment>
<comment xml:lang="sr">Екселова табела</comment>
- <comment xml:lang="sq">Fletë llogaritje Excel</comment>
+ <comment xml:lang="sq">fletëllogaritje Excel</comment>
<comment xml:lang="sl">Razpredelnica Microsoft Excel</comment>
+ <comment xml:lang="si">එක්සෙල් පැතුරුම්පත</comment>
<comment xml:lang="sk">Zošit Excel</comment>
<comment xml:lang="ru">Электронная таблица Excel</comment>
<comment xml:lang="ro">Foaie de calcul Excel</comment>
@@ -3230,6 +3481,7 @@ command to generate the output files.
<comment xml:lang="ka">Excel-ის ცხრილი</comment>
<comment xml:lang="ja">Excel スプレッドシート</comment>
<comment xml:lang="it">Foglio di calcolo Excel</comment>
+ <comment xml:lang="is">Excel töflureikniskjal</comment>
<comment xml:lang="id">Lembar sebar Excel</comment>
<comment xml:lang="ia">Folio de calculo Excel</comment>
<comment xml:lang="hu">Excel táblázat</comment>
@@ -3252,8 +3504,10 @@ command to generate the output files.
<comment xml:lang="ca">full de càlcul d'Excel</comment>
<comment xml:lang="bg">Таблица — Excel</comment>
<comment xml:lang="be@latin">Raźlikovy akruš Excel</comment>
+ <comment xml:lang="be">электронная табліца Excel</comment>
<comment xml:lang="ar">جدول اكسل</comment>
<comment xml:lang="af">Excel-sigblad</comment>
+ <sub-class-of type="application/x-ole-storage"/>
<generic-icon name="x-office-spreadsheet"/>
<magic>
<match type="string" value="Microsoft Excel 5.0 Worksheet" offset="2080"/>
@@ -3278,20 +3532,23 @@ command to generate the output files.
<comment xml:lang="tr">Excel eklentisi</comment>
<comment xml:lang="sv">Excel-tillägg</comment>
<comment xml:lang="sr">Екселов додатак</comment>
+ <comment xml:lang="sq">shtojcë Excel</comment>
<comment xml:lang="sl">Vstavek Excel</comment>
+ <comment xml:lang="si">එක්සෙල් ඇඩෝනය</comment>
<comment xml:lang="sk">Doplnok aplikácie Excel</comment>
<comment xml:lang="ru">Дополнение Excel</comment>
<comment xml:lang="pt_BR">Suplemento do Excel</comment>
<comment xml:lang="pt">Extensão Excel</comment>
<comment xml:lang="pl">Dodatek Excel</comment>
<comment xml:lang="oc">complement Excel</comment>
- <comment xml:lang="nl">Excel add-in</comment>
+ <comment xml:lang="nl">Excel-add-in</comment>
<comment xml:lang="lv">Excel pievienojumprogramma</comment>
<comment xml:lang="ko">Excel 추가 기능</comment>
<comment xml:lang="kk">Excel қосымшасы</comment>
<comment xml:lang="ka">Excel-ის დამატება</comment>
<comment xml:lang="ja">Excel アドイン</comment>
<comment xml:lang="it">Add-in Excel</comment>
+ <comment xml:lang="is">Excel viðbót</comment>
<comment xml:lang="id">Add-in Excel</comment>
<comment xml:lang="ia">Add-in Excel</comment>
<comment xml:lang="hu">Excel bővítmény</comment>
@@ -3306,11 +3563,12 @@ command to generate the output files.
<comment xml:lang="es">complemento de Excel</comment>
<comment xml:lang="en_GB">Excel add-in</comment>
<comment xml:lang="el">Πρόσθετο Excel</comment>
- <comment xml:lang="de">Excel Add-in</comment>
+ <comment xml:lang="de">Excel-Add-in</comment>
<comment xml:lang="da">Excel-tilføjelse</comment>
<comment xml:lang="cs">doplněk aplikace Excel</comment>
<comment xml:lang="ca">complement d'Excel</comment>
<comment xml:lang="bg">Приставка — Excel</comment>
+ <comment xml:lang="be">надбудова Excel</comment>
<comment xml:lang="ar">إضافة اكسل</comment>
<comment xml:lang="af">Excel-byvoeging</comment>
<generic-icon name="x-office-spreadsheet"/>
@@ -3325,20 +3583,23 @@ command to generate the output files.
<comment xml:lang="tr">Excel 2007 ikilik hesap çizelgesi</comment>
<comment xml:lang="sv">Binärt Excel 2007-kalkylblad</comment>
<comment xml:lang="sr">Ексел 2007 бинарна табела</comment>
+ <comment xml:lang="sq">fletëllogaritje dyore Excel 2007</comment>
<comment xml:lang="sl">Binarna preglednica Excel 2007</comment>
+ <comment xml:lang="si">Excel 2007 ද්විමය පැතුරුම්පත</comment>
<comment xml:lang="sk">Binárny zošit Excel 2007</comment>
<comment xml:lang="ru">Двоичная электронная таблица Excel 2007</comment>
<comment xml:lang="pt_BR">Planilha binária do Excel 2007</comment>
<comment xml:lang="pt">folha de cálculo binária Excel 2007</comment>
<comment xml:lang="pl">Binarny arkusz Excel 2007</comment>
<comment xml:lang="oc">fuèlh de calcul binaire Excel 2007</comment>
- <comment xml:lang="nl">Excel 2007 binary spreadsheet</comment>
+ <comment xml:lang="nl">Excel 2007 binair rekenblad</comment>
<comment xml:lang="lv">Excel 2007 binārā izklājlapa</comment>
<comment xml:lang="ko">Excel 2007 바이너리 스프레드시트</comment>
<comment xml:lang="kk">Excel 2007 бинарды кестесі</comment>
<comment xml:lang="ka">Excel 2007-ის ბინარული ცხრილი</comment>
<comment xml:lang="ja">Excel 2007 バイナリスプレッドシート</comment>
<comment xml:lang="it">Foglio di calcolo binario Excel 2007</comment>
+ <comment xml:lang="is">Excel tvíunddarkerfis töflureikniskjal</comment>
<comment xml:lang="id">Lembar kerja biner Excel 2007</comment>
<comment xml:lang="ia">Folio de calculo binari Excel 2007</comment>
<comment xml:lang="hu">Excel 2007 bináris táblázat</comment>
@@ -3358,6 +3619,7 @@ command to generate the output files.
<comment xml:lang="cs">binární formát sešitu Excel 2007</comment>
<comment xml:lang="ca">full de càlcul binari d'Excel 2007</comment>
<comment xml:lang="bg">Таблица — Excel 2007, двоична</comment>
+ <comment xml:lang="be">двайковая электронная табліца Excel 2007</comment>
<comment xml:lang="ar">مستند اكسل 2007 ثنائي</comment>
<comment xml:lang="af">Excel 2007 binêre sigblad</comment>
<generic-icon name="x-office-spreadsheet"/>
@@ -3369,12 +3631,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">Excel 試算表</comment>
<comment xml:lang="zh_CN">Excel 电子表格</comment>
<comment xml:lang="vi">Bảng tính Excel</comment>
- <comment xml:lang="uk">ел. таблиця Excel</comment>
+ <comment xml:lang="uk">електронна таблиця Excel</comment>
<comment xml:lang="tr">Excel hesap çizelgesi</comment>
<comment xml:lang="sv">Excel-kalkylblad</comment>
<comment xml:lang="sr">Екселова табела</comment>
- <comment xml:lang="sq">Fletë llogaritje Excel</comment>
+ <comment xml:lang="sq">fletëllogaritje Excel</comment>
<comment xml:lang="sl">Razpredelnica Microsoft Excel</comment>
+ <comment xml:lang="si">එක්සෙල් පැතුරුම්පත</comment>
<comment xml:lang="sk">Zošit Excel</comment>
<comment xml:lang="ru">Электронная таблица Excel</comment>
<comment xml:lang="ro">Foaie de calcul Excel</comment>
@@ -3392,6 +3655,7 @@ command to generate the output files.
<comment xml:lang="ka">Excel-ის ცხრილი</comment>
<comment xml:lang="ja">Excel スプレッドシート</comment>
<comment xml:lang="it">Foglio di calcolo Excel</comment>
+ <comment xml:lang="is">Excel töflureikniskjal</comment>
<comment xml:lang="id">Lembar sebar Excel</comment>
<comment xml:lang="ia">Folio de calculo Excel</comment>
<comment xml:lang="hu">Excel táblázat</comment>
@@ -3414,6 +3678,7 @@ command to generate the output files.
<comment xml:lang="ca">full de càlcul d'Excel</comment>
<comment xml:lang="bg">Таблица — Excel</comment>
<comment xml:lang="be@latin">Raźlikovy akruš Excel</comment>
+ <comment xml:lang="be">электронная табліца Excel</comment>
<comment xml:lang="ar">جدول اكسل</comment>
<comment xml:lang="af">Excel-sigblad</comment>
<generic-icon name="x-office-spreadsheet"/>
@@ -3428,22 +3693,27 @@ command to generate the output files.
<comment xml:lang="tr">Excel hesap çizelgesi şablonu</comment>
<comment xml:lang="sv">Excel-kalkylarksmall</comment>
<comment xml:lang="sr">Екселов шаблон табеле</comment>
+ <comment xml:lang="sq">gjedhe fletëllogaritjesh Excel</comment>
<comment xml:lang="sl">Predloga preglednice Excel</comment>
+ <comment xml:lang="si">එක්සෙල් පැතුරුම්පත් අච්චුව</comment>
<comment xml:lang="sk">Šablóna tabuľky aplikácie Excel</comment>
<comment xml:lang="ru">Шаблон таблицы Excel</comment>
<comment xml:lang="pt_BR">Modelo de planilha do Excel</comment>
<comment xml:lang="pt">predefinição da folha de cálculo Excel</comment>
<comment xml:lang="pl">Szablon arkusza Excel</comment>
<comment xml:lang="oc">Modèl de fuèlh de calcul Excel</comment>
+ <comment xml:lang="nl">Excel-rekenbladsjabloon</comment>
<comment xml:lang="ko">Excel 스프레드시트 서식</comment>
<comment xml:lang="kk">Excel кестесінің үлгісі</comment>
<comment xml:lang="ja">Excel スプレッドシートテンプレート</comment>
<comment xml:lang="it">Modello foglio di calcolo Excel</comment>
+ <comment xml:lang="is">Excel töflureiknisniðmát</comment>
<comment xml:lang="id">Templat lembar kerja Excel</comment>
<comment xml:lang="ia">Patrono de folio de calculo Excel</comment>
<comment xml:lang="hu">Excel munkafüzetsablon</comment>
<comment xml:lang="hr">Predložak Excel proračunske tablice</comment>
<comment xml:lang="he">תבנית גיליון נתונים של Excel</comment>
+ <comment xml:lang="gl">Modelo de folla de cálculo de Excel</comment>
<comment xml:lang="ga">teimpléad scarbhileoige Excel</comment>
<comment xml:lang="fur">model sfuei di calcul Excel</comment>
<comment xml:lang="fr">modèle de feuille de calcul Excel</comment>
@@ -3457,6 +3727,7 @@ command to generate the output files.
<comment xml:lang="cs">šablona tabulky Excel</comment>
<comment xml:lang="ca">plantilla de full de càlcul d'Excel</comment>
<comment xml:lang="bg">Шаблон за таблица — Excel</comment>
+ <comment xml:lang="be">шаблон электроннай табліцы Excel</comment>
<comment xml:lang="ar">قالب جدول اكسل</comment>
<comment xml:lang="af">Excel-sigbladsjabloon</comment>
<generic-icon name="x-office-spreadsheet"/>
@@ -3472,8 +3743,9 @@ command to generate the output files.
<comment xml:lang="tr">PowerPoint sunumu</comment>
<comment xml:lang="sv">PowerPoint-presentation</comment>
<comment xml:lang="sr">Пауер поинт презентација</comment>
- <comment xml:lang="sq">Prezantim PowerPoint</comment>
+ <comment xml:lang="sq">paraqitje PowerPoint</comment>
<comment xml:lang="sl">Predstavitev Microsoft PowerPoint</comment>
+ <comment xml:lang="si">PowerPoint ඉදිරිපත් කිරීම</comment>
<comment xml:lang="sk">Prezentácia PowerPoint</comment>
<comment xml:lang="ru">Презентация PowerPoint</comment>
<comment xml:lang="ro">Prezentare PowerPoint</comment>
@@ -3490,6 +3762,7 @@ command to generate the output files.
<comment xml:lang="kk">PowerPoint презентациясы</comment>
<comment xml:lang="ja">PowerPoint プレゼンテーション</comment>
<comment xml:lang="it">Presentazione PowerPoint</comment>
+ <comment xml:lang="is">PowerPoint kynning</comment>
<comment xml:lang="id">Presentasi PowerPoint</comment>
<comment xml:lang="ia">Presentation PowerPoint</comment>
<comment xml:lang="hu">PowerPoint prezentáció</comment>
@@ -3512,8 +3785,10 @@ command to generate the output files.
<comment xml:lang="ca">presentació de PowerPoint</comment>
<comment xml:lang="bg">Презентация — PowerPoint</comment>
<comment xml:lang="be@latin">Prezentacyja PowerPoint</comment>
+ <comment xml:lang="be">прэзентацыя PowerPoint</comment>
<comment xml:lang="ar">عرض تقديمي بوربوينت</comment>
<comment xml:lang="af">PowerPoint-voorlegging</comment>
+ <sub-class-of type="application/x-ole-storage"/>
<generic-icon name="x-office-presentation"/>
<glob pattern="*.ppz"/>
<glob pattern="*.ppt"/>
@@ -3531,20 +3806,23 @@ command to generate the output files.
<comment xml:lang="tr">PowerPoint eklentisi</comment>
<comment xml:lang="sv">PowerPoint-tillägg</comment>
<comment xml:lang="sr">Пауер поинт додатак</comment>
+ <comment xml:lang="sq">shtojcë PowerPoint</comment>
<comment xml:lang="sl">Vstavek PowerPoint</comment>
+ <comment xml:lang="si">PowerPoint ඇඩෝනය</comment>
<comment xml:lang="sk">Doplnok aplikácie PowerPoint </comment>
<comment xml:lang="ru">Дополнение PowerPoint</comment>
<comment xml:lang="pt_BR">Suplemento do PowerPoint</comment>
<comment xml:lang="pt">extensão PowerPoint</comment>
<comment xml:lang="pl">Dodatek PowerPoint</comment>
<comment xml:lang="oc">complement PowerPoint</comment>
- <comment xml:lang="nl">PowerPoint add-in</comment>
+ <comment xml:lang="nl">PowerPoint-add-in</comment>
<comment xml:lang="lv">PowerPoint pievienojumprogramma</comment>
<comment xml:lang="ko">PowerPoint 추가 기능</comment>
<comment xml:lang="kk">PowerPoint қосымшасы</comment>
<comment xml:lang="ka">PowerPoint-ის დამატება</comment>
<comment xml:lang="ja">PowerPoint アドイン</comment>
<comment xml:lang="it">Add-in PowerPoint</comment>
+ <comment xml:lang="is">PowerPoint viðbót</comment>
<comment xml:lang="id">Add-in PowerPoint</comment>
<comment xml:lang="ia">Add-in PowerPoint</comment>
<comment xml:lang="hu">PowerPoint bővítmény</comment>
@@ -3559,11 +3837,12 @@ command to generate the output files.
<comment xml:lang="es">complemento de PowerPoint</comment>
<comment xml:lang="en_GB">PowerPoint add-in</comment>
<comment xml:lang="el">Πρόσθετο PowerPoint</comment>
- <comment xml:lang="de">PowerPoint Add-in</comment>
+ <comment xml:lang="de">PowerPoint-Add-in</comment>
<comment xml:lang="da">PowerPoint-tilføjelse</comment>
<comment xml:lang="cs">doplněk PowerPoint</comment>
<comment xml:lang="ca">complement de PowerPoint</comment>
<comment xml:lang="bg">Приставка — PowerPoint</comment>
+ <comment xml:lang="be">надбудова PowerPoint</comment>
<comment xml:lang="ar">إضافة بوربوينت</comment>
<comment xml:lang="af">PowerPoint-byvoeging</comment>
<generic-icon name="x-office-presentation"/>
@@ -3578,8 +3857,9 @@ command to generate the output files.
<comment xml:lang="tr">PowerPoint sunumu</comment>
<comment xml:lang="sv">PowerPoint-presentation</comment>
<comment xml:lang="sr">Пауер поинт презентација</comment>
- <comment xml:lang="sq">Prezantim PowerPoint</comment>
+ <comment xml:lang="sq">paraqitje PowerPoint</comment>
<comment xml:lang="sl">Predstavitev Microsoft PowerPoint</comment>
+ <comment xml:lang="si">PowerPoint ඉදිරිපත් කිරීම</comment>
<comment xml:lang="sk">Prezentácia PowerPoint</comment>
<comment xml:lang="ru">Презентация PowerPoint</comment>
<comment xml:lang="ro">Prezentare PowerPoint</comment>
@@ -3596,6 +3876,7 @@ command to generate the output files.
<comment xml:lang="kk">PowerPoint презентациясы</comment>
<comment xml:lang="ja">PowerPoint プレゼンテーション</comment>
<comment xml:lang="it">Presentazione PowerPoint</comment>
+ <comment xml:lang="is">PowerPoint kynning</comment>
<comment xml:lang="id">Presentasi PowerPoint</comment>
<comment xml:lang="ia">Presentation PowerPoint</comment>
<comment xml:lang="hu">PowerPoint prezentáció</comment>
@@ -3618,6 +3899,7 @@ command to generate the output files.
<comment xml:lang="ca">presentació de PowerPoint</comment>
<comment xml:lang="bg">Презентация — PowerPoint</comment>
<comment xml:lang="be@latin">Prezentacyja PowerPoint</comment>
+ <comment xml:lang="be">прэзентацыя PowerPoint</comment>
<comment xml:lang="ar">عرض تقديمي بوربوينت</comment>
<comment xml:lang="af">PowerPoint-voorlegging</comment>
<generic-icon name="x-office-presentation"/>
@@ -3632,22 +3914,27 @@ command to generate the output files.
<comment xml:lang="tr">PowerPoint sunusu</comment>
<comment xml:lang="sv">PowerPoint-bildspel</comment>
<comment xml:lang="sr">Пауер поинт слајд</comment>
+ <comment xml:lang="sq">diapozitiv PowerPoint</comment>
<comment xml:lang="sl">Prosojnica PowerPoint</comment>
+ <comment xml:lang="si">PowerPoint ස්ලයිඩය</comment>
<comment xml:lang="sk">Snímka aplikácie PowerPoint</comment>
<comment xml:lang="ru">Слайд PowerPoint</comment>
<comment xml:lang="pt_BR">Slide do PowerPoint</comment>
<comment xml:lang="pt">diapositivo PowerPoint</comment>
<comment xml:lang="pl">Slajd PowerPoint</comment>
<comment xml:lang="oc">Diapositiva PowerPoint</comment>
+ <comment xml:lang="nl">PowerPoint-dia</comment>
<comment xml:lang="ko">PowerPoint 슬라이드</comment>
<comment xml:lang="kk">PowerPoint слайды</comment>
<comment xml:lang="ja">PowerPoint スライド</comment>
<comment xml:lang="it">Diapositiva PowerPoint</comment>
+ <comment xml:lang="is">PowerPoint skyggna</comment>
<comment xml:lang="id">Salindia PowerPoint</comment>
<comment xml:lang="ia">Diapositiva PowerPoint</comment>
<comment xml:lang="hu">PowerPoint dia</comment>
<comment xml:lang="hr">PowerPoint prezentacija</comment>
<comment xml:lang="he">שקופית של PowerPoint</comment>
+ <comment xml:lang="gl">Diapositiva de PowerPoint</comment>
<comment xml:lang="ga">sleamhnán PowerPoint</comment>
<comment xml:lang="fur">diapositive PowerPoint</comment>
<comment xml:lang="fr">diapositive PowerPoint</comment>
@@ -3661,6 +3948,7 @@ command to generate the output files.
<comment xml:lang="cs">promítání PowerPoint</comment>
<comment xml:lang="ca">dispositiva de PowerPoint</comment>
<comment xml:lang="bg">Кадър — PowerPoint</comment>
+ <comment xml:lang="be">слайд PowerPoint</comment>
<comment xml:lang="ast">Diapositiva de PowerPoint</comment>
<comment xml:lang="ar">شريحة بوربوينت</comment>
<comment xml:lang="af">PowerPoint-skyfie</comment>
@@ -3677,8 +3965,9 @@ command to generate the output files.
<comment xml:lang="tr">PowerPoint sunumu</comment>
<comment xml:lang="sv">PowerPoint-presentation</comment>
<comment xml:lang="sr">Пауер поинт презентација</comment>
- <comment xml:lang="sq">Prezantim PowerPoint</comment>
+ <comment xml:lang="sq">paraqitje PowerPoint</comment>
<comment xml:lang="sl">Predstavitev Microsoft PowerPoint</comment>
+ <comment xml:lang="si">PowerPoint ඉදිරිපත් කිරීම</comment>
<comment xml:lang="sk">Prezentácia PowerPoint</comment>
<comment xml:lang="ru">Презентация PowerPoint</comment>
<comment xml:lang="ro">Prezentare PowerPoint</comment>
@@ -3695,6 +3984,7 @@ command to generate the output files.
<comment xml:lang="kk">PowerPoint презентациясы</comment>
<comment xml:lang="ja">PowerPoint プレゼンテーション</comment>
<comment xml:lang="it">Presentazione PowerPoint</comment>
+ <comment xml:lang="is">PowerPoint kynning</comment>
<comment xml:lang="id">Presentasi PowerPoint</comment>
<comment xml:lang="ia">Presentation PowerPoint</comment>
<comment xml:lang="hu">PowerPoint prezentáció</comment>
@@ -3717,6 +4007,7 @@ command to generate the output files.
<comment xml:lang="ca">presentació de PowerPoint</comment>
<comment xml:lang="bg">Презентация — PowerPoint</comment>
<comment xml:lang="be@latin">Prezentacyja PowerPoint</comment>
+ <comment xml:lang="be">прэзентацыя PowerPoint</comment>
<comment xml:lang="ar">عرض تقديمي بوربوينت</comment>
<comment xml:lang="af">PowerPoint-voorlegging</comment>
<generic-icon name="x-office-presentation"/>
@@ -3731,22 +4022,27 @@ command to generate the output files.
<comment xml:lang="tr">PowerPoint sunum şablonu</comment>
<comment xml:lang="sv">PowerPoint-presentationsmall</comment>
<comment xml:lang="sr">Шаблон презентације Пауер поинта</comment>
+ <comment xml:lang="sq">gjedhe paraqitjeje PowerPoint</comment>
<comment xml:lang="sl">Predloga predstavitve PowerPoint</comment>
+ <comment xml:lang="si">PowerPoint ඉදිරිපත් කිරීමේ අච්චුව</comment>
<comment xml:lang="sk">Šablóna prezentácie aplikácie PowerPoint</comment>
<comment xml:lang="ru">Шаблон презентации PowerPoint</comment>
<comment xml:lang="pt_BR">Modelo de apresentação do PowerPoint</comment>
<comment xml:lang="pt">predefinição de apresentação PowerPoint</comment>
<comment xml:lang="pl">Szablon prezentacji PowerPoint</comment>
<comment xml:lang="oc">Modèl de presentacion PowerPoint</comment>
+ <comment xml:lang="nl">PowerPoint-presentatiesjabloon</comment>
<comment xml:lang="ko">PowerPoint 프레젠테이션 서식</comment>
<comment xml:lang="kk">PowerPoint презентация үлгісі</comment>
<comment xml:lang="ja">PowerPoint プレゼンテーションテンプレート</comment>
<comment xml:lang="it">Modello presentazione PowerPoint</comment>
+ <comment xml:lang="is">PowerPoint sniðmát fyrir glærukynningu</comment>
<comment xml:lang="id">Templat presentasi PowerPoint</comment>
<comment xml:lang="ia">Patrono de presentation PowerPoint</comment>
<comment xml:lang="hu">PowerPoint bemutatósablon</comment>
<comment xml:lang="hr">Predložak PowerPoint prezentacije</comment>
<comment xml:lang="he">תבנית מצגת PowerPoint</comment>
+ <comment xml:lang="gl">Modelo de presentación de PowerPoint</comment>
<comment xml:lang="ga">teimpléad láithreoireachta PowerPoint</comment>
<comment xml:lang="fur">model di presentazion PowerPoint</comment>
<comment xml:lang="fr">modèle de présentation PowerPoint</comment>
@@ -3760,6 +4056,7 @@ command to generate the output files.
<comment xml:lang="cs">šablona prezentace PowerPoint</comment>
<comment xml:lang="ca">plantilla de presentació de PowerPoint</comment>
<comment xml:lang="bg">Шаблон за презентация — PowerPoint</comment>
+ <comment xml:lang="be">шаблон прэзентацыі PowerPoint</comment>
<comment xml:lang="ast">Plantía de presentaciones de PowerPoint</comment>
<comment xml:lang="ar">قالب عرض بوربوينت</comment>
<comment xml:lang="af">PowerPoint-voorleggingsjabloon</comment>
@@ -3774,20 +4071,25 @@ command to generate the output files.
<comment xml:lang="uk">малюнок Visio Office Open у XML</comment>
<comment xml:lang="tr">Office Open XML Visio çizimi</comment>
<comment xml:lang="sv">Office Open XML Visio-ritning</comment>
+ <comment xml:lang="sq">vizatim Office Open XML Visio</comment>
<comment xml:lang="sl">Risba Office Open XML Visio</comment>
+ <comment xml:lang="si">කාර්යාල විවෘත XML Visio ඇඳීම</comment>
<comment xml:lang="sk">Kresba aplikácie Office Open XML Visio</comment>
<comment xml:lang="ru">Рисунок Visio формата Office Open XML</comment>
<comment xml:lang="pt_BR">Desenho do Office Open XML Visio</comment>
<comment xml:lang="pt">desenho Visio do Open Office XML</comment>
<comment xml:lang="pl">Rysunek Office Open XML Visio</comment>
+ <comment xml:lang="nl">Office Open XML Visio-tekening</comment>
<comment xml:lang="ko">오피스 오픈 XML Visio 드로잉</comment>
<comment xml:lang="kk">Office Open XML Visio суреті</comment>
<comment xml:lang="ja">Office Open XML Visio ドロー</comment>
<comment xml:lang="it">Disegno Visio Office Open XML</comment>
+ <comment xml:lang="is">Office Open XML Visio teikning</comment>
<comment xml:lang="id">Gambar Office Open XML Visio</comment>
<comment xml:lang="hu">Office Open XML Visio rajz</comment>
<comment xml:lang="hr">Office Open XML Visio crtež</comment>
<comment xml:lang="he">ציור Office Open XML Visio</comment>
+ <comment xml:lang="gl">Debuxo de Office Open XML Visio</comment>
<comment xml:lang="fr">dessin Visio Office Open XML</comment>
<comment xml:lang="fi">Office Open XML Visio -piirros</comment>
<comment xml:lang="eu">Office Open XML Visio marrazkia</comment>
@@ -3797,6 +4099,7 @@ command to generate the output files.
<comment xml:lang="da">Office Open XML Visio-tegning</comment>
<comment xml:lang="ca">dibuix en Office Open XML de Visio</comment>
<comment xml:lang="bg">Чертеж — Office Open XML Visio</comment>
+ <comment xml:lang="be">рысунак Office Open XML Visio</comment>
<comment xml:lang="ar">رسم فيزيو Open XML</comment>
<generic-icon name="image-x-generic"/>
<glob pattern="*.vsdx"/>
@@ -3809,20 +4112,25 @@ command to generate the output files.
<comment xml:lang="uk">шаблон Visio Office Open у XML</comment>
<comment xml:lang="tr">Office Open XML Visio şablonu</comment>
<comment xml:lang="sv">Office Open XML Visio-mall</comment>
+ <comment xml:lang="sq">gjedhe Office Open XML Visio</comment>
<comment xml:lang="sl">Predloga Office Open XML Visio</comment>
+ <comment xml:lang="si">Office Open XML Visio අච්චුව</comment>
<comment xml:lang="sk">Šablóna aplikácie Office Open XML Visio</comment>
<comment xml:lang="ru">Шаблон Visio формата Office Open XML</comment>
<comment xml:lang="pt_BR">Modelo Office Open XML Visio</comment>
<comment xml:lang="pt">predefinição Visio do Open Office XML</comment>
<comment xml:lang="pl">Szablon Office Open XML Visio</comment>
+ <comment xml:lang="nl">Office Open XML Visio-sjabloon</comment>
<comment xml:lang="ko">오피스 오픈 XML Visio 양식</comment>
<comment xml:lang="kk">Office Open XML Visio үлгісі</comment>
<comment xml:lang="ja">Office Open XML Visio テンプレート</comment>
<comment xml:lang="it">Modello Visio Office Open XML</comment>
+ <comment xml:lang="is">Office Open XML Visio sniðmát</comment>
<comment xml:lang="id">Templat Office Open XML Visio</comment>
<comment xml:lang="hu">Office Open XML Visio sablon</comment>
<comment xml:lang="hr">Office Open XML Visio predložak</comment>
<comment xml:lang="he">תבנית Office Open XML Visio</comment>
+ <comment xml:lang="gl">Modelo de Office Open XML Visio</comment>
<comment xml:lang="fr">modèle Visio Office Open XML</comment>
<comment xml:lang="fi">Office Open XML Visio -malli</comment>
<comment xml:lang="eu">Office Open XML Visio txantiloia</comment>
@@ -3832,6 +4140,7 @@ command to generate the output files.
<comment xml:lang="da">Office Open XML Visio-skabelon</comment>
<comment xml:lang="ca">plantilla en Office Open XML de Visio</comment>
<comment xml:lang="bg">Шаблон за чертеж — Office Open XML Visio</comment>
+ <comment xml:lang="be">шаблон Office Open XML Visio</comment>
<comment xml:lang="ar">قالب فيزيو Open XML</comment>
<generic-icon name="image-x-generic"/>
<glob pattern="*.vstx"/>
@@ -3843,18 +4152,23 @@ command to generate the output files.
<comment xml:lang="uk">трафарет Visio Office Open у XML</comment>
<comment xml:lang="tr">Office Open XML Visio kalıbı</comment>
<comment xml:lang="sv">Office Open XML Visio-stencil</comment>
+ <comment xml:lang="sq">model Office Open XML Visio</comment>
+ <comment xml:lang="si">කාර්යාල විවෘත XML Visio ස්ටෙන්සිල්</comment>
<comment xml:lang="ru">Трафарет Visio формата Office Open XML</comment>
<comment xml:lang="pt_BR">Estêncil do Office Open XML Visio</comment>
<comment xml:lang="pt">estêncil Visio do Open Office XML</comment>
<comment xml:lang="pl">Wzór Office Open XML Visio</comment>
+ <comment xml:lang="nl">Office Open XML Visio-stencil</comment>
<comment xml:lang="ko">오피스 오픈 XML Visio 스텐실</comment>
<comment xml:lang="kk">Office Open XML Visio трафареті</comment>
<comment xml:lang="ja">Office Open XML Visio ステンシル</comment>
<comment xml:lang="it">Stencil Visio Office Open XML</comment>
+ <comment xml:lang="is">Office Open XML Visio stensill</comment>
<comment xml:lang="id">Stensil Office Open XML Visio</comment>
<comment xml:lang="hu">Office Open XML Visio stencil</comment>
<comment xml:lang="hr">Office Open XML Visio šablona</comment>
<comment xml:lang="he">סטנסיל ל־Visio ב־Open XML מבית Office</comment>
+ <comment xml:lang="gl">Pincel de de Office Open XML Visio</comment>
<comment xml:lang="fr">stencil Visio Office Open XML</comment>
<comment xml:lang="fi">Office Open XML Visio -malli</comment>
<comment xml:lang="eu">Office Open XML Visio txantiloia</comment>
@@ -3864,6 +4178,7 @@ command to generate the output files.
<comment xml:lang="da">Office Open XML Visio-stencil</comment>
<comment xml:lang="ca">patró en Office Open XML de Visio</comment>
<comment xml:lang="bg">Образци — Office Open XML Visio</comment>
+ <comment xml:lang="be">трафарэт Office Open XML Visio</comment>
<comment xml:lang="ar">شكل فيزيو Open XML</comment>
<generic-icon name="image-x-generic"/>
<glob pattern="*.vssx"/>
@@ -3876,20 +4191,25 @@ command to generate the output files.
<comment xml:lang="uk">малюнок Visio Office Open у XML</comment>
<comment xml:lang="tr">Office Open XML Visio çizimi</comment>
<comment xml:lang="sv">Office Open XML Visio-ritning</comment>
+ <comment xml:lang="sq">vizatim Office Open XML Visio</comment>
<comment xml:lang="sl">Risba Office Open XML Visio</comment>
+ <comment xml:lang="si">කාර්යාල විවෘත XML Visio ඇඳීම</comment>
<comment xml:lang="sk">Kresba aplikácie Office Open XML Visio</comment>
<comment xml:lang="ru">Рисунок Visio формата Office Open XML</comment>
<comment xml:lang="pt_BR">Desenho do Office Open XML Visio</comment>
<comment xml:lang="pt">desenho Visio do Open Office XML</comment>
<comment xml:lang="pl">Rysunek Office Open XML Visio</comment>
+ <comment xml:lang="nl">Office Open XML Visio-tekening</comment>
<comment xml:lang="ko">오피스 오픈 XML Visio 드로잉</comment>
<comment xml:lang="kk">Office Open XML Visio суреті</comment>
<comment xml:lang="ja">Office Open XML Visio ドロー</comment>
<comment xml:lang="it">Disegno Visio Office Open XML</comment>
+ <comment xml:lang="is">Office Open XML Visio teikning</comment>
<comment xml:lang="id">Gambar Office Open XML Visio</comment>
<comment xml:lang="hu">Office Open XML Visio rajz</comment>
<comment xml:lang="hr">Office Open XML Visio crtež</comment>
<comment xml:lang="he">ציור Office Open XML Visio</comment>
+ <comment xml:lang="gl">Debuxo de Office Open XML Visio</comment>
<comment xml:lang="fr">dessin Visio Office Open XML</comment>
<comment xml:lang="fi">Office Open XML Visio -piirros</comment>
<comment xml:lang="eu">Office Open XML Visio marrazkia</comment>
@@ -3899,6 +4219,7 @@ command to generate the output files.
<comment xml:lang="da">Office Open XML Visio-tegning</comment>
<comment xml:lang="ca">dibuix en Office Open XML de Visio</comment>
<comment xml:lang="bg">Чертеж — Office Open XML Visio</comment>
+ <comment xml:lang="be">рысунак Office Open XML Visio</comment>
<comment xml:lang="ar">رسم فيزيو Open XML</comment>
<generic-icon name="image-x-generic"/>
<glob pattern="*.vsdm"/>
@@ -3911,20 +4232,25 @@ command to generate the output files.
<comment xml:lang="uk">шаблон Visio Office Open у XML</comment>
<comment xml:lang="tr">Office Open XML Visio şablonu</comment>
<comment xml:lang="sv">Office Open XML Visio-mall</comment>
+ <comment xml:lang="sq">gjedhe Office Open XML Visio</comment>
<comment xml:lang="sl">Predloga Office Open XML Visio</comment>
+ <comment xml:lang="si">Office Open XML Visio අච්චුව</comment>
<comment xml:lang="sk">Šablóna aplikácie Office Open XML Visio</comment>
<comment xml:lang="ru">Шаблон Visio формата Office Open XML</comment>
<comment xml:lang="pt_BR">Modelo Office Open XML Visio</comment>
<comment xml:lang="pt">predefinição Visio do Open Office XML</comment>
<comment xml:lang="pl">Szablon Office Open XML Visio</comment>
+ <comment xml:lang="nl">Office Open XML Visio-sjabloon</comment>
<comment xml:lang="ko">오피스 오픈 XML Visio 양식</comment>
<comment xml:lang="kk">Office Open XML Visio үлгісі</comment>
<comment xml:lang="ja">Office Open XML Visio テンプレート</comment>
<comment xml:lang="it">Modello Visio Office Open XML</comment>
+ <comment xml:lang="is">Office Open XML Visio sniðmát</comment>
<comment xml:lang="id">Templat Office Open XML Visio</comment>
<comment xml:lang="hu">Office Open XML Visio sablon</comment>
<comment xml:lang="hr">Office Open XML Visio predložak</comment>
<comment xml:lang="he">תבנית Office Open XML Visio</comment>
+ <comment xml:lang="gl">Modelo de Office Open XML Visio</comment>
<comment xml:lang="fr">modèle Visio Office Open XML</comment>
<comment xml:lang="fi">Office Open XML Visio -malli</comment>
<comment xml:lang="eu">Office Open XML Visio txantiloia</comment>
@@ -3934,6 +4260,7 @@ command to generate the output files.
<comment xml:lang="da">Office Open XML Visio-skabelon</comment>
<comment xml:lang="ca">plantilla en Office Open XML de Visio</comment>
<comment xml:lang="bg">Шаблон за чертеж — Office Open XML Visio</comment>
+ <comment xml:lang="be">шаблон Office Open XML Visio</comment>
<comment xml:lang="ar">قالب فيزيو Open XML</comment>
<generic-icon name="image-x-generic"/>
<glob pattern="*.vstm"/>
@@ -3945,18 +4272,23 @@ command to generate the output files.
<comment xml:lang="uk">трафарет Visio Office Open у XML</comment>
<comment xml:lang="tr">Office Open XML Visio kalıbı</comment>
<comment xml:lang="sv">Office Open XML Visio-stencil</comment>
+ <comment xml:lang="sq">model Office Open XML Visio</comment>
+ <comment xml:lang="si">කාර්යාල විවෘත XML Visio ස්ටෙන්සිල්</comment>
<comment xml:lang="ru">Трафарет Visio формата Office Open XML</comment>
<comment xml:lang="pt_BR">Estêncil do Office Open XML Visio</comment>
<comment xml:lang="pt">estêncil Visio do Open Office XML</comment>
<comment xml:lang="pl">Wzór Office Open XML Visio</comment>
+ <comment xml:lang="nl">Office Open XML Visio-stencil</comment>
<comment xml:lang="ko">오피스 오픈 XML Visio 스텐실</comment>
<comment xml:lang="kk">Office Open XML Visio трафареті</comment>
<comment xml:lang="ja">Office Open XML Visio ステンシル</comment>
<comment xml:lang="it">Stencil Visio Office Open XML</comment>
+ <comment xml:lang="is">Office Open XML Visio stensill</comment>
<comment xml:lang="id">Stensil Office Open XML Visio</comment>
<comment xml:lang="hu">Office Open XML Visio stencil</comment>
<comment xml:lang="hr">Office Open XML Visio šablona</comment>
<comment xml:lang="he">סטנסיל ל־Visio ב־Open XML מבית Office</comment>
+ <comment xml:lang="gl">Pincel de de Office Open XML Visio</comment>
<comment xml:lang="fr">stencil Visio Office Open XML</comment>
<comment xml:lang="fi">Office Open XML Visio -malli</comment>
<comment xml:lang="eu">Office Open XML Visio txantiloia</comment>
@@ -3966,6 +4298,7 @@ command to generate the output files.
<comment xml:lang="da">Office Open XML Visio-stencil</comment>
<comment xml:lang="ca">patró en Office Open XML de Visio</comment>
<comment xml:lang="bg">Образци — Office Open XML Visio</comment>
+ <comment xml:lang="be">трафарэт Office Open XML Visio</comment>
<comment xml:lang="ar">شكل فيزيو Open XML</comment>
<generic-icon name="image-x-generic"/>
<glob pattern="*.vssm"/>
@@ -3980,8 +4313,9 @@ command to generate the output files.
<comment xml:lang="tr">Word belgesi</comment>
<comment xml:lang="sv">Word-dokument</comment>
<comment xml:lang="sr">Ворд документ</comment>
- <comment xml:lang="sq">Dokument Word</comment>
+ <comment xml:lang="sq">dokument Word</comment>
<comment xml:lang="sl">Dokument Word</comment>
+ <comment xml:lang="si">වචන ලේඛනය</comment>
<comment xml:lang="sk">Dokument Word</comment>
<comment xml:lang="ru">Документ Word</comment>
<comment xml:lang="ro">Document Word</comment>
@@ -3996,8 +4330,10 @@ command to generate the output files.
<comment xml:lang="lt">Word dokumentas</comment>
<comment xml:lang="ko">Word 문서</comment>
<comment xml:lang="kk">Word құжаты</comment>
+ <comment xml:lang="ka">Word -ის დოკუმენტი</comment>
<comment xml:lang="ja">Word ドキュメント</comment>
<comment xml:lang="it">Documento Word</comment>
+ <comment xml:lang="is">Word skjal</comment>
<comment xml:lang="id">Dokumen Word</comment>
<comment xml:lang="ia">Documento Word</comment>
<comment xml:lang="hu">Word dokumentum</comment>
@@ -4020,6 +4356,7 @@ command to generate the output files.
<comment xml:lang="ca">document Word</comment>
<comment xml:lang="bg">Документ — Word</comment>
<comment xml:lang="be@latin">Dakument Word</comment>
+ <comment xml:lang="be">дакумент Word</comment>
<comment xml:lang="ast">Documentu de Word</comment>
<comment xml:lang="ar">مستند ورد</comment>
<comment xml:lang="af">Word-dokument</comment>
@@ -4035,22 +4372,27 @@ command to generate the output files.
<comment xml:lang="tr">Word belgesi şablonu</comment>
<comment xml:lang="sv">Word-dokumentmall</comment>
<comment xml:lang="sr">Шаблон Ворд документа</comment>
+ <comment xml:lang="sq">gjedhe dokumenti Word</comment>
<comment xml:lang="sl">Predloga dokumenta Word</comment>
+ <comment xml:lang="si">වචන ලේඛන ආකෘතිය</comment>
<comment xml:lang="sk">Šablóna dokumentu aplikácie Word</comment>
<comment xml:lang="ru">Шаблон документа Word</comment>
<comment xml:lang="pt_BR">Modelo de documento do Word</comment>
<comment xml:lang="pt">modelo de documento Word</comment>
<comment xml:lang="pl">Szablon dokumentu Word</comment>
<comment xml:lang="oc">modèl de document Word</comment>
+ <comment xml:lang="nl">Word-documentsjabloon</comment>
<comment xml:lang="ko">Word 문서 서식</comment>
<comment xml:lang="kk">Word құжатының үлгісі</comment>
<comment xml:lang="ja">Word ドキュメントテンプレート</comment>
<comment xml:lang="it">Modello documento Word</comment>
+ <comment xml:lang="is">Word sniðmát fyrir textaskjal</comment>
<comment xml:lang="id">Templat dokumen Word</comment>
<comment xml:lang="ia">Patrono de documento Word</comment>
<comment xml:lang="hu">Word dokumentumsablon</comment>
<comment xml:lang="hr">Predložak Word dokumenta</comment>
<comment xml:lang="he">תבנית מסמך Word</comment>
+ <comment xml:lang="gl">Modelo de documento Word</comment>
<comment xml:lang="ga">teimpléad Word</comment>
<comment xml:lang="fur">model di document Word</comment>
<comment xml:lang="fr">modèle de document Word</comment>
@@ -4064,6 +4406,7 @@ command to generate the output files.
<comment xml:lang="cs">šablona dokumentu Word</comment>
<comment xml:lang="ca">plantilla de document Word</comment>
<comment xml:lang="bg">Шаблон за документ — Word</comment>
+ <comment xml:lang="be">шаблон дакумента Word</comment>
<comment xml:lang="ast">Plantía de documentu de Word</comment>
<comment xml:lang="ar">قالب مستند ورد</comment>
<comment xml:lang="af">Word-dokumentsjabloon</comment>
@@ -4073,28 +4416,40 @@ command to generate the output files.
</mime-type>
<mime-type type="application/oxps">
<comment>OpenXPS document</comment>
+ <comment xml:lang="zh_TW">OpenXPS 文件</comment>
<comment xml:lang="zh_CN">OpenXPS 文档</comment>
<comment xml:lang="uk">документ OpenXPS</comment>
<comment xml:lang="tr">OpenXPS belgesi</comment>
<comment xml:lang="sv">OpenXPS-dokument</comment>
+ <comment xml:lang="sl">Dokument OpenXPS</comment>
+ <comment xml:lang="si">OpenXPS ලේඛනය</comment>
+ <comment xml:lang="sk">Dokument OpenXPS</comment>
+ <comment xml:lang="ru">Документ OpenXPS</comment>
<comment xml:lang="pt_BR">Documento OpenXPS</comment>
<comment xml:lang="pt">documento OpenXPS</comment>
<comment xml:lang="pl">Dokument OpenXPS</comment>
<comment xml:lang="oc">document OpenXPS</comment>
+ <comment xml:lang="nl">OpenXPS-document</comment>
<comment xml:lang="ko">OpenXPS 문서</comment>
+ <comment xml:lang="kk">OpenXPS құжаты</comment>
+ <comment xml:lang="ka">OpenXPS -ის დოკუმენტი</comment>
<comment xml:lang="ja">OpenXPS ドキュメント</comment>
<comment xml:lang="it">Documento OpenXPS</comment>
+ <comment xml:lang="is">OpenXPS skjal</comment>
<comment xml:lang="id">Dokumen OpenXPS</comment>
<comment xml:lang="hu">OpenXPS-dokumentum</comment>
<comment xml:lang="hr">OpenXPS dokument</comment>
<comment xml:lang="he">מסמך OpenXPS</comment>
+ <comment xml:lang="gl">Documento de OpenXPS</comment>
<comment xml:lang="fr">Document OpenXPS</comment>
<comment xml:lang="fi">OpenXPS-asiakirja</comment>
+ <comment xml:lang="eu">OpenXPS dokumentua</comment>
<comment xml:lang="es">documento OpenXPS</comment>
<comment xml:lang="en_GB">OpenXPS document</comment>
<comment xml:lang="de">OpenXPS-Dokument</comment>
<comment xml:lang="da">OpenXPS-dokument</comment>
<comment xml:lang="ca">document OpenXPS</comment>
+ <comment xml:lang="be">дакумент OpenXPS</comment>
<comment xml:lang="ar">مستند OpenXPS</comment>
<acronym>OpenXPS</acronym>
<expanded-acronym>Open XML Paper Specification</expanded-acronym>
@@ -4111,8 +4466,9 @@ command to generate the output files.
<comment xml:lang="tr">XPS belgesi</comment>
<comment xml:lang="sv">XPS-dokument</comment>
<comment xml:lang="sr">ИксПС документ</comment>
- <comment xml:lang="sq">Dokument XPS</comment>
+ <comment xml:lang="sq">dokument XPS</comment>
<comment xml:lang="sl">Dokument XPS</comment>
+ <comment xml:lang="si">XPS ලේඛනය</comment>
<comment xml:lang="sk">Dokument XPS</comment>
<comment xml:lang="ru">Документ XPS</comment>
<comment xml:lang="ro">Document XPS</comment>
@@ -4127,8 +4483,10 @@ command to generate the output files.
<comment xml:lang="lt">XPS dokumentas</comment>
<comment xml:lang="ko">XPS 문서</comment>
<comment xml:lang="kk">XPS құжаты</comment>
+ <comment xml:lang="ka">XPS -ის დოკუმენტი</comment>
<comment xml:lang="ja">XPS ドキュメント</comment>
<comment xml:lang="it">Documento XPS</comment>
+ <comment xml:lang="is">XPS skjal</comment>
<comment xml:lang="id">Dokumen XPS</comment>
<comment xml:lang="ia">Documento XPS</comment>
<comment xml:lang="hu">XPS dokumentum</comment>
@@ -4151,6 +4509,7 @@ command to generate the output files.
<comment xml:lang="ca">document XPS</comment>
<comment xml:lang="bg">Документ — XPS</comment>
<comment xml:lang="be@latin">Dakument XPS</comment>
+ <comment xml:lang="be">дакумент XPS</comment>
<comment xml:lang="ast">Documentu XPS</comment>
<comment xml:lang="ar">مستند XPS</comment>
<comment xml:lang="af">XPS-dokument</comment>
@@ -4170,8 +4529,9 @@ command to generate the output files.
<comment xml:lang="tr">Microsoft Works belgesi</comment>
<comment xml:lang="sv">Microsoft Works-dokument</comment>
<comment xml:lang="sr">документ Мајкрософт Воркса</comment>
- <comment xml:lang="sq">Dokument Microsoft Works</comment>
+ <comment xml:lang="sq">dokument Microsoft Works</comment>
<comment xml:lang="sl">Dokument Microsoft Works</comment>
+ <comment xml:lang="si">Microsoft Works ලේඛනය</comment>
<comment xml:lang="sk">Dokument Microsoft Works</comment>
<comment xml:lang="ru">Документ Microsoft Works</comment>
<comment xml:lang="ro">Document Microsoft Works</comment>
@@ -4189,6 +4549,7 @@ command to generate the output files.
<comment xml:lang="ka">Microsoft Works-ის დოკუმენტი</comment>
<comment xml:lang="ja">Microsoft Works ドキュメント</comment>
<comment xml:lang="it">Documento Microsoft Works</comment>
+ <comment xml:lang="is">Microsoft Works skjal</comment>
<comment xml:lang="id">Dokumen Microsoft Works</comment>
<comment xml:lang="ia">Documento Microsoft Works</comment>
<comment xml:lang="hu">Microsoft Works dokumentum</comment>
@@ -4210,6 +4571,7 @@ command to generate the output files.
<comment xml:lang="ca">document de Microsoft Works</comment>
<comment xml:lang="bg">Документ — Microsoft Works</comment>
<comment xml:lang="be@latin">Dakument Microsoft Works</comment>
+ <comment xml:lang="be">дакумент Microsoft Works</comment>
<comment xml:lang="ast">Documentu de Microsoft Works</comment>
<comment xml:lang="ar">مستند Microsoft Works</comment>
<comment xml:lang="af">Microsoft Works-dokument</comment>
@@ -4229,7 +4591,9 @@ command to generate the output files.
<comment xml:lang="tr">Microsoft Visio belgesi</comment>
<comment xml:lang="sv">Microsoft Visio-dokument</comment>
<comment xml:lang="sr">документ Мајкрософт Визиа</comment>
+ <comment xml:lang="sq">dokument Microsoft Visio</comment>
<comment xml:lang="sl">Dokument Microsoft Visio</comment>
+ <comment xml:lang="si">Microsoft Visio ලේඛනය</comment>
<comment xml:lang="sk">Dokument Microsoft Visio</comment>
<comment xml:lang="ru">Документ Microsoft Visio</comment>
<comment xml:lang="pt_BR">Documento do Microsoft Visio</comment>
@@ -4243,6 +4607,7 @@ command to generate the output files.
<comment xml:lang="ka">Microsoft Visio-ის დოკუმენტი</comment>
<comment xml:lang="ja">Microsoft Visio ドキュメント</comment>
<comment xml:lang="it">Documento Microsoft Visio</comment>
+ <comment xml:lang="is">Microsoft Visio skjal</comment>
<comment xml:lang="id">Dokumen Microsoft Visio</comment>
<comment xml:lang="ia">Documento Microsoft Visio</comment>
<comment xml:lang="hu">Microsoft Visio dokumentum</comment>
@@ -4262,6 +4627,7 @@ command to generate the output files.
<comment xml:lang="cs">dokument Microsoft Visio</comment>
<comment xml:lang="ca">document de Microsoft Visio</comment>
<comment xml:lang="bg">Документ — Microsoft Visio</comment>
+ <comment xml:lang="be">дакумент Microsoft Visio</comment>
<comment xml:lang="ast">Documentu de Microsoft Visio</comment>
<comment xml:lang="ar">مستند مايكروسوفت فيزو</comment>
<comment xml:lang="af">Microsoft Visio-dokument</comment>
@@ -4281,8 +4647,9 @@ command to generate the output files.
<comment xml:lang="tr">Word belgesi</comment>
<comment xml:lang="sv">Word-dokument</comment>
<comment xml:lang="sr">Ворд документ</comment>
- <comment xml:lang="sq">Dokument Word</comment>
+ <comment xml:lang="sq">dokument Word</comment>
<comment xml:lang="sl">Dokument Word</comment>
+ <comment xml:lang="si">වචන ලේඛනය</comment>
<comment xml:lang="sk">Dokument Word</comment>
<comment xml:lang="ru">Документ Word</comment>
<comment xml:lang="ro">Document Word</comment>
@@ -4297,8 +4664,10 @@ command to generate the output files.
<comment xml:lang="lt">Word dokumentas</comment>
<comment xml:lang="ko">Word 문서</comment>
<comment xml:lang="kk">Word құжаты</comment>
+ <comment xml:lang="ka">Word -ის დოკუმენტი</comment>
<comment xml:lang="ja">Word ドキュメント</comment>
<comment xml:lang="it">Documento Word</comment>
+ <comment xml:lang="is">Word skjal</comment>
<comment xml:lang="id">Dokumen Word</comment>
<comment xml:lang="ia">Documento Word</comment>
<comment xml:lang="hu">Word dokumentum</comment>
@@ -4321,6 +4690,7 @@ command to generate the output files.
<comment xml:lang="ca">document Word</comment>
<comment xml:lang="bg">Документ — Word</comment>
<comment xml:lang="be@latin">Dakument Word</comment>
+ <comment xml:lang="be">дакумент Word</comment>
<comment xml:lang="ast">Documentu de Word</comment>
<comment xml:lang="ar">مستند ورد</comment>
<comment xml:lang="af">Word-dokument</comment>
@@ -4351,8 +4721,9 @@ command to generate the output files.
<comment xml:lang="tr">Word şablonu</comment>
<comment xml:lang="sv">Word-mall</comment>
<comment xml:lang="sr">Ворд шаблон</comment>
- <comment xml:lang="sq">Model Word</comment>
+ <comment xml:lang="sq">gjedhe Word</comment>
<comment xml:lang="sl">Predloga dokumenta Microsoft Word</comment>
+ <comment xml:lang="si">වචන සැකිල්ල</comment>
<comment xml:lang="sk">Šablóna Word</comment>
<comment xml:lang="ru">Шаблон Word</comment>
<comment xml:lang="ro">Șablon Word</comment>
@@ -4369,6 +4740,7 @@ command to generate the output files.
<comment xml:lang="kk">Word үлгісі</comment>
<comment xml:lang="ja">Word テンプレート</comment>
<comment xml:lang="it">Modello Word</comment>
+ <comment xml:lang="is">Word sniðmát</comment>
<comment xml:lang="id">Templat Word</comment>
<comment xml:lang="ia">Patrono Word</comment>
<comment xml:lang="hu">Word sablon</comment>
@@ -4391,6 +4763,7 @@ command to generate the output files.
<comment xml:lang="ca">plantilla de Word</comment>
<comment xml:lang="bg">Шаблон за документи — Word</comment>
<comment xml:lang="be@latin">Šablon Word</comment>
+ <comment xml:lang="be">шаблон Word</comment>
<comment xml:lang="ast">Plantía de Word</comment>
<comment xml:lang="ar">قالب ورد</comment>
<comment xml:lang="af">Word-sjabloon</comment>
@@ -4406,19 +4779,24 @@ command to generate the output files.
<comment xml:lang="tr">GML belgesi</comment>
<comment xml:lang="sv">GML-dokument</comment>
<comment xml:lang="sr">ГМЛ документ</comment>
+ <comment xml:lang="sq">dokument GML</comment>
<comment xml:lang="sl">Dokument GML</comment>
+ <comment xml:lang="si">GML ලේඛනය</comment>
<comment xml:lang="sk">Dokument GML</comment>
<comment xml:lang="ru">Документ GML</comment>
<comment xml:lang="pt_BR">Documento GML</comment>
<comment xml:lang="pt">documento GML</comment>
<comment xml:lang="pl">Dokument GML</comment>
<comment xml:lang="oc">document GML</comment>
+ <comment xml:lang="nl">GML-document</comment>
<comment xml:lang="lv">GML dokuments</comment>
<comment xml:lang="lt">GML dokumentas</comment>
<comment xml:lang="ko">GML 문서</comment>
<comment xml:lang="kk">GML құжаты</comment>
+ <comment xml:lang="ka">GML -ის დოკუმენტი</comment>
<comment xml:lang="ja">GML ドキュメント</comment>
<comment xml:lang="it">Documento GML</comment>
+ <comment xml:lang="is">GML skjal</comment>
<comment xml:lang="id">Dokumen GML</comment>
<comment xml:lang="ia">Documento GML</comment>
<comment xml:lang="hu">GML dokumentum</comment>
@@ -4438,6 +4816,7 @@ command to generate the output files.
<comment xml:lang="cs">dokument GML</comment>
<comment xml:lang="ca">document GML</comment>
<comment xml:lang="bg">Документ — GML</comment>
+ <comment xml:lang="be">дакумент GML</comment>
<comment xml:lang="ast">Documentu GML</comment>
<comment xml:lang="ar">مستند GML</comment>
<comment xml:lang="af">GML-dokument</comment>
@@ -4456,8 +4835,9 @@ command to generate the output files.
<comment xml:lang="tr">GNUnet arama dosyası</comment>
<comment xml:lang="sv">GNUnet-sökfil</comment>
<comment xml:lang="sr">ГНУнет датотека претраге</comment>
- <comment xml:lang="sq">File kërkimi GNUnet</comment>
+ <comment xml:lang="sq">kartelë kërkimi GNUnet</comment>
<comment xml:lang="sl">Iskalna datoteka GNUnet</comment>
+ <comment xml:lang="si">GNUnet සෙවුම් ගොනුව</comment>
<comment xml:lang="sk">Vyhľadávací súbor GNUnet</comment>
<comment xml:lang="ru">Файл поиска GNUnet</comment>
<comment xml:lang="ro">Fișier căutare GNUnet</comment>
@@ -4475,6 +4855,7 @@ command to generate the output files.
<comment xml:lang="ka">GNUnet ძებნის ფაილი</comment>
<comment xml:lang="ja">GNUnet 検索ファイル</comment>
<comment xml:lang="it">File ricerca GNUnet</comment>
+ <comment xml:lang="is">GNUnet leitarskrá</comment>
<comment xml:lang="id">Berkas telusur GNUnet</comment>
<comment xml:lang="ia">File de recerca GNUnet</comment>
<comment xml:lang="hu">GNUnet keresési fájl</comment>
@@ -4496,6 +4877,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer de cerca GNUnet</comment>
<comment xml:lang="bg">Указател за търсене — GNUnet</comment>
<comment xml:lang="be@latin">fajł pošuku GNUnet</comment>
+ <comment xml:lang="be">файл пошуку GNUnet</comment>
<comment xml:lang="ar">ملف بحث GNUnet</comment>
<comment xml:lang="af">GNUnet-soeklêer</comment>
<magic>
@@ -4512,8 +4894,9 @@ command to generate the output files.
<comment xml:lang="tr">TNEF iletisi</comment>
<comment xml:lang="sv">TNEF-meddelande</comment>
<comment xml:lang="sr">ТНЕФ порука</comment>
- <comment xml:lang="sq">Mesazh TNEF</comment>
+ <comment xml:lang="sq">mesazh TNEF</comment>
<comment xml:lang="sl">Datoteka sporočila TNEF</comment>
+ <comment xml:lang="si">TNEF පණිවිඩය</comment>
<comment xml:lang="sk">Správa TNEF</comment>
<comment xml:lang="ru">Сообщение TNEF</comment>
<comment xml:lang="ro">Mesaj TNEF</comment>
@@ -4530,6 +4913,7 @@ command to generate the output files.
<comment xml:lang="kk">TNEF мәлімдемесі</comment>
<comment xml:lang="ja">TNEF メッセージ</comment>
<comment xml:lang="it">Messaggio TNEF</comment>
+ <comment xml:lang="is">TNEF skilaboð</comment>
<comment xml:lang="id">Pesan TNEF</comment>
<comment xml:lang="ia">Message TNEF</comment>
<comment xml:lang="hu">TNEF üzenet</comment>
@@ -4551,6 +4935,7 @@ command to generate the output files.
<comment xml:lang="ca">missatge TNEF</comment>
<comment xml:lang="bg">Съобщение — TNEF</comment>
<comment xml:lang="be@latin">List TNEF</comment>
+ <comment xml:lang="be">паведамленне TNEF</comment>
<comment xml:lang="ast">Mensaxe TNEF</comment>
<comment xml:lang="ar">رسالة TNEF</comment>
<comment xml:lang="af">TNEF-boodskap</comment>
@@ -4569,12 +4954,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">StarCalc 試算表</comment>
<comment xml:lang="zh_CN">StarCalc 电子表格</comment>
<comment xml:lang="vi">Bảng tính StarCalc</comment>
- <comment xml:lang="uk">ел. таблиця StarCalc</comment>
+ <comment xml:lang="uk">електронна таблиця StarCalc</comment>
<comment xml:lang="tr">StarCalc hesap çizelgesi</comment>
<comment xml:lang="sv">StarCalc-kalkylblad</comment>
<comment xml:lang="sr">Стар калк табела</comment>
- <comment xml:lang="sq">Fletë llogaritjesh StarCalc</comment>
+ <comment xml:lang="sq">fletëllogaritje StarCalc</comment>
<comment xml:lang="sl">Preglednica StarCalc</comment>
+ <comment xml:lang="si">StarCalc පැතුරුම්පත</comment>
<comment xml:lang="sk">Zošit StarCalc</comment>
<comment xml:lang="ru">Электронная таблица StarCalc</comment>
<comment xml:lang="ro">Foaie de calcul StarCalc</comment>
@@ -4592,6 +4978,7 @@ command to generate the output files.
<comment xml:lang="kk">StarCalc электрондық кестесі</comment>
<comment xml:lang="ja">StarCalc スプレッドシート</comment>
<comment xml:lang="it">Foglio di calcolo StarCalc</comment>
+ <comment xml:lang="is">StarCalc töflureikniskjal</comment>
<comment xml:lang="id">Lembar sebar StarCalc</comment>
<comment xml:lang="ia">Folio de calculo StarCalc</comment>
<comment xml:lang="hu">StarCalc-munkafüzet</comment>
@@ -4615,6 +5002,7 @@ command to generate the output files.
<comment xml:lang="ca">full de càlcul de StarCalc</comment>
<comment xml:lang="bg">Таблица — StarCalc</comment>
<comment xml:lang="be@latin">Raźlikovy arkuš StarCalc</comment>
+ <comment xml:lang="be">электронная табліца StarCalc</comment>
<comment xml:lang="az">StarCalc hesab cədvəli</comment>
<comment xml:lang="ar">جدول StarCalc</comment>
<comment xml:lang="af">StarCalc-sigblad</comment>
@@ -4630,8 +5018,9 @@ command to generate the output files.
<comment xml:lang="tr">StarChart çizgesi</comment>
<comment xml:lang="sv">StarChart-diagram</comment>
<comment xml:lang="sr">График Стар Графика</comment>
- <comment xml:lang="sq">Grafik StarChart</comment>
+ <comment xml:lang="sq">grafik StarChart</comment>
<comment xml:lang="sl">Datoteka grafikona StarChart</comment>
+ <comment xml:lang="si">StarChart සටහන</comment>
<comment xml:lang="sk">Graf StarChart</comment>
<comment xml:lang="ru">Диаграмма StarChart</comment>
<comment xml:lang="ro">Diagramă StarChart</comment>
@@ -4649,6 +5038,7 @@ command to generate the output files.
<comment xml:lang="kk">StarChart диаграммасы</comment>
<comment xml:lang="ja">StarChart チャート</comment>
<comment xml:lang="it">Grafico StarChart</comment>
+ <comment xml:lang="is">StarChart kort</comment>
<comment xml:lang="id">Bagan StarChart</comment>
<comment xml:lang="ia">Graphico StarChart</comment>
<comment xml:lang="hu">StarChart-grafikon</comment>
@@ -4672,6 +5062,7 @@ command to generate the output files.
<comment xml:lang="ca">diagrama de StarChart</comment>
<comment xml:lang="bg">Диаграма — StarChart</comment>
<comment xml:lang="be@latin">Dyjahrama StarChart</comment>
+ <comment xml:lang="be">дыяграма StarChart</comment>
<comment xml:lang="az">StarChart cədvəli</comment>
<comment xml:lang="ar">مخطط StarChart</comment>
<comment xml:lang="af">StarChart-grafiek</comment>
@@ -4687,8 +5078,9 @@ command to generate the output files.
<comment xml:lang="tr">StarDraw çizimi</comment>
<comment xml:lang="sv">StarDraw-teckning</comment>
<comment xml:lang="sr">Цртеж Стар Цртежа</comment>
- <comment xml:lang="sq">Vizatim StarDraw</comment>
+ <comment xml:lang="sq">vizatim StarDraw</comment>
<comment xml:lang="sl">Datoteka risbe StarDraw</comment>
+ <comment xml:lang="si">StarDraw ඇඳීම</comment>
<comment xml:lang="sk">Kresba StarDraw</comment>
<comment xml:lang="ru">Рисунок StarDraw</comment>
<comment xml:lang="ro">Desen StarDraw</comment>
@@ -4706,6 +5098,7 @@ command to generate the output files.
<comment xml:lang="kk">StarDraw суреті</comment>
<comment xml:lang="ja">StarDraw ドロー</comment>
<comment xml:lang="it">Disegno StarDraw</comment>
+ <comment xml:lang="is">StarDraw teikning</comment>
<comment xml:lang="id">Gambar StarDraw</comment>
<comment xml:lang="ia">Designo StarDraw</comment>
<comment xml:lang="hu">StarDraw-rajz</comment>
@@ -4729,6 +5122,7 @@ command to generate the output files.
<comment xml:lang="ca">dibuix de StarDraw</comment>
<comment xml:lang="bg">Чертеж — StarDraw</comment>
<comment xml:lang="be@latin">Rysunak StarDraw</comment>
+ <comment xml:lang="be">рысунак StarDraw</comment>
<comment xml:lang="az">StarDraw çəkimi</comment>
<comment xml:lang="ar">تصميم StarDraw</comment>
<comment xml:lang="af">StarDraw-tekening</comment>
@@ -4744,8 +5138,9 @@ command to generate the output files.
<comment xml:lang="tr">StarImpress sunumu</comment>
<comment xml:lang="sv">StarImpress-presentation</comment>
<comment xml:lang="sr">Презентација Стар Импреса</comment>
- <comment xml:lang="sq">Prezantim StarImpress</comment>
+ <comment xml:lang="sq">paraqitje StarImpress</comment>
<comment xml:lang="sl">Predstavitev StarImpress</comment>
+ <comment xml:lang="si">StarImpress ඉදිරිපත් කිරීම</comment>
<comment xml:lang="sk">Prezentácia StarImpress</comment>
<comment xml:lang="ru">Презентация StarImpress</comment>
<comment xml:lang="ro">Prezentare StarImpress</comment>
@@ -4763,6 +5158,7 @@ command to generate the output files.
<comment xml:lang="kk">StarImpress презентациясы</comment>
<comment xml:lang="ja">StarImpress プレゼンテーション</comment>
<comment xml:lang="it">Presentazione StarImpress</comment>
+ <comment xml:lang="is">StarImpress framsetning</comment>
<comment xml:lang="id">Presentasi StarImpress</comment>
<comment xml:lang="ia">Presentation StarImpress</comment>
<comment xml:lang="hu">StarImpress-bemutató</comment>
@@ -4786,6 +5182,7 @@ command to generate the output files.
<comment xml:lang="ca">presentació de StarImpress</comment>
<comment xml:lang="bg">Презентация — StarImpress</comment>
<comment xml:lang="be@latin">Prezentacyja StarImpress</comment>
+ <comment xml:lang="be">прэзентацыя StarImpress</comment>
<comment xml:lang="az">StarImpress təqdimatı</comment>
<comment xml:lang="ar">عرض تقديمي StarImpress</comment>
<comment xml:lang="af">StarImpress-voorlegging</comment>
@@ -4802,8 +5199,9 @@ command to generate the output files.
<comment xml:lang="tr">StarMail epostası</comment>
<comment xml:lang="sv">StarMail-e-post</comment>
<comment xml:lang="sr">Ел. пошта Стар Поште</comment>
- <comment xml:lang="sq">Mesazh StarMail</comment>
+ <comment xml:lang="sq">email StarMail</comment>
<comment xml:lang="sl">Datoteka pošte StarMail</comment>
+ <comment xml:lang="si">StarMail ඊමේල්</comment>
<comment xml:lang="sk">E-mail StarMail</comment>
<comment xml:lang="ru">Электронное письмо StarMail</comment>
<comment xml:lang="ro">Email StarEmail</comment>
@@ -4821,6 +5219,7 @@ command to generate the output files.
<comment xml:lang="kk">StarMail электрондық хаты</comment>
<comment xml:lang="ja">StarMail メール</comment>
<comment xml:lang="it">Email StarMail</comment>
+ <comment xml:lang="is">StarMail tölvupóstur</comment>
<comment xml:lang="id">Email StarMail</comment>
<comment xml:lang="ia">Message electronic StarMail</comment>
<comment xml:lang="hu">StarMail e-mail</comment>
@@ -4843,6 +5242,7 @@ command to generate the output files.
<comment xml:lang="ca">correu electrònic de StarMail</comment>
<comment xml:lang="bg">Електронно писмо — StarMail</comment>
<comment xml:lang="be@latin">Email StarMail</comment>
+ <comment xml:lang="be">Email StarMail</comment>
<comment xml:lang="ar">بريد إلكتروني StarMail</comment>
<comment xml:lang="af">StarMail-e-pos</comment>
<glob pattern="*.smd"/>
@@ -4856,8 +5256,9 @@ command to generate the output files.
<comment xml:lang="tr">StarMath formülü</comment>
<comment xml:lang="sv">StarMath-formel</comment>
<comment xml:lang="sr">Формула Стар Математике</comment>
- <comment xml:lang="sq">Formulë StarMath</comment>
+ <comment xml:lang="sq">formulë StarMath</comment>
<comment xml:lang="sl">Datoteka formule StarMath</comment>
+ <comment xml:lang="si">StarMath සූත්‍රය</comment>
<comment xml:lang="sk">Vzorec StarMath</comment>
<comment xml:lang="ru">Формула StarMath</comment>
<comment xml:lang="ro">Formulă StarMath</comment>
@@ -4875,6 +5276,7 @@ command to generate the output files.
<comment xml:lang="kk">StarMath формуласы</comment>
<comment xml:lang="ja">StarMath 計算式</comment>
<comment xml:lang="it">Formula StarMath</comment>
+ <comment xml:lang="is">StarMath formúla</comment>
<comment xml:lang="id">Formula StarMath</comment>
<comment xml:lang="ia">Formula StarMath</comment>
<comment xml:lang="hu">StarMath-képlet</comment>
@@ -4897,6 +5299,7 @@ command to generate the output files.
<comment xml:lang="ca">fórmula de StarMath</comment>
<comment xml:lang="bg">Формула — StarMath</comment>
<comment xml:lang="be@latin">Formuła StarMath</comment>
+ <comment xml:lang="be">формула StarMath</comment>
<comment xml:lang="ar">صيغة StarMath</comment>
<comment xml:lang="af">StarMath-formule</comment>
<generic-icon name="x-office-document"/>
@@ -4911,8 +5314,9 @@ command to generate the output files.
<comment xml:lang="tr">StarWriter belgesi</comment>
<comment xml:lang="sv">StarWriter-dokument</comment>
<comment xml:lang="sr">Документ Стар Писца</comment>
- <comment xml:lang="sq">Dokument StarWriter</comment>
+ <comment xml:lang="sq">dokument StarWriter</comment>
<comment xml:lang="sl">Dokument StarWriter</comment>
+ <comment xml:lang="si">StarWriter ලේඛනය</comment>
<comment xml:lang="sk">Dokument StarWriter</comment>
<comment xml:lang="ru">Документ StarWriter</comment>
<comment xml:lang="ro">Document StarWriter</comment>
@@ -4930,6 +5334,7 @@ command to generate the output files.
<comment xml:lang="kk">StarWriter құжаты</comment>
<comment xml:lang="ja">StarWriter ドキュメント</comment>
<comment xml:lang="it">Documento StrarWriter</comment>
+ <comment xml:lang="is">StarWriter skjal</comment>
<comment xml:lang="id">Dokumen StarWriter</comment>
<comment xml:lang="ia">Documento StarWriter</comment>
<comment xml:lang="hu">StarWriter-dokumentum</comment>
@@ -4953,6 +5358,7 @@ command to generate the output files.
<comment xml:lang="ca">document StarWriter</comment>
<comment xml:lang="bg">Документ — StarWriter</comment>
<comment xml:lang="be@latin">Dakument StarWriter</comment>
+ <comment xml:lang="be">дакумент StarWriter</comment>
<comment xml:lang="az">StarWriter sənədi</comment>
<comment xml:lang="ast">Documentu de StarWriter</comment>
<comment xml:lang="ar">مستند StarWriter</comment>
@@ -4967,56 +5373,18 @@ command to generate the output files.
<alias type="application/vnd.stardivision.writer-global"/>
</mime-type>
<mime-type type="application/vnd.sun.xml.calc">
- <comment>OpenOffice Calc spreadsheet</comment>
- <comment xml:lang="zh_TW">OpenOffice Calc 試算表</comment>
- <comment xml:lang="zh_CN">OpenOffice Calc 电子表格</comment>
- <comment xml:lang="vi">Bảng tính Calc của OpenOffice.org</comment>
- <comment xml:lang="uk">ел. таблиця OpenOffice Calc</comment>
- <comment xml:lang="tr">OpenOffice Calc hesap çizelgesi</comment>
- <comment xml:lang="sv">OpenOffice Calc-kalkylblad</comment>
- <comment xml:lang="sr">Табела Опен Офис Рачуна</comment>
- <comment xml:lang="sq">Fletë llogaritjesh OpenOffice Calc</comment>
- <comment xml:lang="sl">Razpredelnica OpenOffice.org Calc</comment>
- <comment xml:lang="sk">Zošit OpenOffice Calc</comment>
- <comment xml:lang="ru">Электронная таблица OpenOffice Calc</comment>
- <comment xml:lang="ro">Foaie de calcul OpenOffice Calc</comment>
- <comment xml:lang="pt_BR">Planilha do OpenOffice Calc</comment>
- <comment xml:lang="pt">folha de cálculo OpenOffice Calc</comment>
- <comment xml:lang="pl">Arkusz OpenOffice.org Calc</comment>
- <comment xml:lang="oc">fuèlh de calcul OpenOffice Calc</comment>
- <comment xml:lang="nn">OpenOffice Calc-rekneark</comment>
- <comment xml:lang="nl">OpenOffice.org Calc-rekenblad</comment>
- <comment xml:lang="nb">OpenOffice Calc-regneark</comment>
- <comment xml:lang="lv">OpenOffice Calc izklājlapa</comment>
- <comment xml:lang="lt">OpenOffice Calc skaičialentė</comment>
- <comment xml:lang="ko">OpenOffice Calc 스프레드시트</comment>
- <comment xml:lang="kk">OpenOffice Calc электрондық кестесі</comment>
- <comment xml:lang="ka">OpenOffice Calc-ის ცხრილი</comment>
- <comment xml:lang="ja">OpenOffice Calc スプレッドシート</comment>
- <comment xml:lang="it">Foglio di calcolo OpenOffice Calc</comment>
- <comment xml:lang="id">Lembar sebar OpenOffice Calc</comment>
- <comment xml:lang="ia">Folio de calculo OpenOffice Calc</comment>
- <comment xml:lang="hu">OpenOffice Calc táblázat</comment>
- <comment xml:lang="hr">OpenOffice Calc proračunska tablica</comment>
- <comment xml:lang="he">גיליון נתונים של OpenOffice Calc</comment>
- <comment xml:lang="gl">folla de cálculo de OpenOffice Calc</comment>
- <comment xml:lang="ga">scarbhileog OpenOffice Calc</comment>
- <comment xml:lang="fur">sfuei di calcul OpenOffice Calc</comment>
- <comment xml:lang="fr">feuille de calcul OpenOffice Calc</comment>
- <comment xml:lang="fo">OpenOffice Calc rokniark</comment>
- <comment xml:lang="fi">OpenOffice Calc -taulukko</comment>
- <comment xml:lang="eu">OpenOffice.org Calc kalkulu-orria</comment>
+ <comment>LibreOffice Calc spreadsheet</comment>
+ <comment xml:lang="uk">електронна таблиця LibreOffice Calc</comment>
+ <comment xml:lang="sv">LibreOffice Calc-kalkylblad</comment>
+ <comment xml:lang="ru">Электронная таблица LibreOffice Calc</comment>
+ <comment xml:lang="pt_BR">Planilha do LibreOffice Calc</comment>
+ <comment xml:lang="pl">Arkusz LibreOffice Calc</comment>
+ <comment xml:lang="it">Foglio di calcolo LibreOffice Calc</comment>
+ <comment xml:lang="gl">Folla de cálculo de LibreOffice Calc</comment>
+ <comment xml:lang="eu">LibreOffice Calc kalkulu-orria</comment>
<comment xml:lang="es">hoja de cálculo de LibreOffice Calc</comment>
- <comment xml:lang="en_GB">OpenOffice Calc spreadsheet</comment>
- <comment xml:lang="el">Λογιστικό φύλλο OpenOffice Calc</comment>
- <comment xml:lang="de">OpenOffice-Calc-Tabelle</comment>
- <comment xml:lang="da">OpenOffice Calc-regneark</comment>
- <comment xml:lang="cs">sešit OpenOffice Calc</comment>
- <comment xml:lang="ca">full de càlcul d'OpenOffice Calc</comment>
- <comment xml:lang="bg">Таблица — OpenOffice Calc</comment>
- <comment xml:lang="be@latin">Raźlikovy arkuš OpenOffice Calc</comment>
- <comment xml:lang="ar">جدول Calc المكتب المفتوح</comment>
- <comment xml:lang="af">OpenOffice Calc-sigblad</comment>
+ <comment xml:lang="de">LibreOffice Calc-Tabelle</comment>
+ <comment xml:lang="be">электронная табліца LibreOffice Calc</comment>
<sub-class-of type="application/zip"/>
<generic-icon name="x-office-spreadsheet"/>
<magic priority="70">
@@ -5029,56 +5397,18 @@ command to generate the output files.
<glob pattern="*.sxc"/>
</mime-type>
<mime-type type="application/vnd.sun.xml.calc.template">
- <comment>OpenOffice Calc template</comment>
- <comment xml:lang="zh_TW">OpenOffice Calc 範本</comment>
- <comment xml:lang="zh_CN">OpenOffice Calc 模板</comment>
- <comment xml:lang="vi">Mẫu bảng tính Calc của OpenOffice.org</comment>
- <comment xml:lang="uk">шаблон ел.таблиці OpenOffice Calc</comment>
- <comment xml:lang="tr">OpenOffice Calc şablonu</comment>
- <comment xml:lang="sv">OpenOffice Calc-mall</comment>
- <comment xml:lang="sr">Шаблон Опен Офис Рачуна</comment>
- <comment xml:lang="sq">Model OpenOffice Calc</comment>
- <comment xml:lang="sl">Predloga OpenOffice.org Calc</comment>
- <comment xml:lang="sk">Šablóna OpenOffice Calc</comment>
- <comment xml:lang="ru">Шаблон OpenOffice Calc</comment>
- <comment xml:lang="ro">Șablon OpenOffice Calc</comment>
- <comment xml:lang="pt_BR">Modelo do OpenOffice Calc</comment>
- <comment xml:lang="pt">modelo OpenOffice Calc</comment>
- <comment xml:lang="pl">Szablon arkusza OpenOffice.org Calc</comment>
- <comment xml:lang="oc">modèl OpenOffice Calc</comment>
- <comment xml:lang="nn">OpenOffice Calc-mal</comment>
- <comment xml:lang="nl">OpenOffice.org Calc-sjabloon</comment>
- <comment xml:lang="nb">OpenOffice Calc-mal</comment>
- <comment xml:lang="lv">OpenOffice Calc veidne</comment>
- <comment xml:lang="lt">OpenOffice Calc šablonas</comment>
- <comment xml:lang="ko">OpenOffice Calc 스프레드시트 문서 서식</comment>
- <comment xml:lang="kk">OpenOffice Calc үлгісі</comment>
- <comment xml:lang="ka">OpenOffice Calc-ის შაბლონი</comment>
- <comment xml:lang="ja">OpenOffice Calc テンプレート</comment>
- <comment xml:lang="it">Modello OpenOffice Calc</comment>
- <comment xml:lang="id">Templat OpenOffice Calc</comment>
- <comment xml:lang="ia">Patrono OpenOffice Calc</comment>
- <comment xml:lang="hu">OpenOffice Calc sablon</comment>
- <comment xml:lang="hr">OpenOffice Calc predložak</comment>
- <comment xml:lang="he">תבנית של OpenOffice Calc</comment>
- <comment xml:lang="gl">modelo de OpenOffice Calc</comment>
- <comment xml:lang="ga">teimpléad OpenOffice Calc</comment>
- <comment xml:lang="fur">model OpenOffice Calc</comment>
- <comment xml:lang="fr">modèle OpenOffice Calc</comment>
- <comment xml:lang="fo">OpenOffice Calc formur</comment>
- <comment xml:lang="fi">OpenOffice Calc -malli</comment>
- <comment xml:lang="eu">OpenOffice Calc txantiloia</comment>
+ <comment>LibreOffice Calc template</comment>
+ <comment xml:lang="uk">шаблон LibreOffice Calc</comment>
+ <comment xml:lang="sv">LibreOffice Calc-mall</comment>
+ <comment xml:lang="ru">Шаблон LibreOffice Calc</comment>
+ <comment xml:lang="pt_BR">Modelo do LibreOffice Calc</comment>
+ <comment xml:lang="pl">Szablon arkusza LibreOffice Calc</comment>
+ <comment xml:lang="it">Modello LibreOffice Calc</comment>
+ <comment xml:lang="gl">Modelo de LibreOffice Calc</comment>
+ <comment xml:lang="eu">LibreOffice Calc txantiloia</comment>
<comment xml:lang="es">plantilla de LibreOffice Calc</comment>
- <comment xml:lang="en_GB">OpenOffice Calc template</comment>
- <comment xml:lang="el">Πρότυπο OpenOffice Calc</comment>
- <comment xml:lang="de">OpenOffice-Calc-Vorlage</comment>
- <comment xml:lang="da">OpenOffice Calc-skabelon</comment>
- <comment xml:lang="cs">šablona OpenOffice Calc</comment>
- <comment xml:lang="ca">plantilla d'OpenOffice Calc</comment>
- <comment xml:lang="bg">Шаблон за таблици — OpenOffice Calc</comment>
- <comment xml:lang="be@latin">Šablon OpenOffice Calc</comment>
- <comment xml:lang="ar">قالب Calc المكتب المفتوح</comment>
- <comment xml:lang="af">OpenOffice Calc-sjabloon</comment>
+ <comment xml:lang="de">LibreOffice Calc-Vorlage</comment>
+ <comment xml:lang="be">шаблон LibreOffice Calc</comment>
<sub-class-of type="application/zip"/>
<generic-icon name="x-office-spreadsheet"/>
<magic priority="70">
@@ -5091,56 +5421,18 @@ command to generate the output files.
<glob pattern="*.stc"/>
</mime-type>
<mime-type type="application/vnd.sun.xml.draw">
- <comment>OpenOffice Draw drawing</comment>
- <comment xml:lang="zh_TW">OpenOffice Draw 繪圖</comment>
- <comment xml:lang="zh_CN">OpenOffice Draw 绘图</comment>
- <comment xml:lang="vi">Bản vẽ Draw của OpenOffice.org</comment>
- <comment xml:lang="uk">малюнок OpenOffice Draw</comment>
- <comment xml:lang="tr">OpenOffice Draw çizimi</comment>
- <comment xml:lang="sv">OpenOffice Draw-teckning</comment>
- <comment xml:lang="sr">Цртеж Опен Офис Цртежа</comment>
- <comment xml:lang="sq">Vizatim OpenOffice Draw</comment>
- <comment xml:lang="sl">Datoteka risbe OpenOffice.org Draw</comment>
- <comment xml:lang="sk">Kresba OpenOffice Draw</comment>
- <comment xml:lang="ru">Рисунок OpenOffice Draw</comment>
- <comment xml:lang="ro">Desen OpenOffice Draw</comment>
- <comment xml:lang="pt_BR">Desenho do OpenOffice Draw</comment>
- <comment xml:lang="pt">desenho OpenOffice Draw</comment>
- <comment xml:lang="pl">Rysunek OpenOffice.org Draw</comment>
- <comment xml:lang="oc">dessenh OpenOffice Draw</comment>
- <comment xml:lang="nn">OpenOffice Draw-teikning</comment>
- <comment xml:lang="nl">OpenOffice.org Draw-tekening</comment>
- <comment xml:lang="nb">OpenOffice Draw-tegning</comment>
- <comment xml:lang="lv">OpenOffice Draw zīmējums</comment>
- <comment xml:lang="lt">OpenOffice Draw piešinys</comment>
- <comment xml:lang="ko">OpenOffice Draw 그림</comment>
- <comment xml:lang="kk">OpenOffice Draw суреті</comment>
- <comment xml:lang="ka">OpenOffice Draw-ის ნახაზი</comment>
- <comment xml:lang="ja">OpenOffice Draw ドロー</comment>
- <comment xml:lang="it">Disegno OpenOffice Draw</comment>
- <comment xml:lang="id">Gambar OpenOffice Draw</comment>
- <comment xml:lang="ia">Designo OpenOffice Draw</comment>
- <comment xml:lang="hu">OpenOffice Draw rajz</comment>
- <comment xml:lang="hr">OpenOffice Draw crtež</comment>
- <comment xml:lang="he">ציור של OpenOffice Draw</comment>
- <comment xml:lang="gl">debuxo de OpenOffice Draw</comment>
- <comment xml:lang="ga">líníocht OpenOffice Draw</comment>
- <comment xml:lang="fur">dissen OpenOffice Draw</comment>
- <comment xml:lang="fr">dessin OpenOffice Draw</comment>
- <comment xml:lang="fo">OpenOffice Draw tekning</comment>
- <comment xml:lang="fi">OpenOffice Draw -piirros</comment>
- <comment xml:lang="eu">OpenOffice.org Draw marrazkia</comment>
+ <comment>LibreOffice Draw drawing</comment>
+ <comment xml:lang="uk">рисунок LibreOffice Draw</comment>
+ <comment xml:lang="sv">LibreOffice Draw-teckning</comment>
+ <comment xml:lang="ru">Рисунок LibreOffice Draw</comment>
+ <comment xml:lang="pt_BR">Desenho do LibreOffice Draw</comment>
+ <comment xml:lang="pl">Rysunek LibreOffice Draw</comment>
+ <comment xml:lang="it">Disegno LibreOffice Draw</comment>
+ <comment xml:lang="gl">Debuxo de LibreOffice Draw</comment>
+ <comment xml:lang="eu">LibreOffice Draw marrazkia</comment>
<comment xml:lang="es">dibujo de LibreOffice Draw</comment>
- <comment xml:lang="en_GB">OpenOffice Draw drawing</comment>
- <comment xml:lang="el">Σχέδιο OpenOffice Draw</comment>
- <comment xml:lang="de">OpenOffice-Draw-Zeichnung</comment>
- <comment xml:lang="da">OpenOffice Draw-tegning</comment>
- <comment xml:lang="cs">kresba OpenOffice Draw</comment>
- <comment xml:lang="ca">dibuix d'OpenOffice Draw</comment>
- <comment xml:lang="bg">Чертеж — OpenOffice Draw</comment>
- <comment xml:lang="be@latin">Rysunak OpenOffice Draw</comment>
- <comment xml:lang="ar">تصميم Draw المكتب المفتوح</comment>
- <comment xml:lang="af">OpenOffice Draw-tekening</comment>
+ <comment xml:lang="de">LibreOffice Draw-Zeichnung</comment>
+ <comment xml:lang="be">рысунак LibreOffice Draw</comment>
<sub-class-of type="application/zip"/>
<generic-icon name="image-x-generic"/>
<magic priority="70">
@@ -5153,56 +5445,18 @@ command to generate the output files.
<glob pattern="*.sxd"/>
</mime-type>
<mime-type type="application/vnd.sun.xml.draw.template">
- <comment>OpenOffice Draw template</comment>
- <comment xml:lang="zh_TW">OpenOffice Draw 範本</comment>
- <comment xml:lang="zh_CN">OpenOffice Draw 模板</comment>
- <comment xml:lang="vi">Mẫu bản vẽ Draw của OpenOffice.org</comment>
- <comment xml:lang="uk">шаблон малюнку OpenOffice Draw</comment>
- <comment xml:lang="tr">OpenOffice Draw şablonu</comment>
- <comment xml:lang="sv">OpenOffice Draw-mall</comment>
- <comment xml:lang="sr">Шаблон Опен Офис Цртежа</comment>
- <comment xml:lang="sq">Model OpenOffice Draw</comment>
- <comment xml:lang="sl">Predloga OpenOffice.org Draw</comment>
- <comment xml:lang="sk">Šablóna OpenOffice Draw</comment>
- <comment xml:lang="ru">Шаблон OpenOffice Draw</comment>
- <comment xml:lang="ro">Șablon OpenOffice Draw</comment>
- <comment xml:lang="pt_BR">Modelo do OpenOffice Draw</comment>
- <comment xml:lang="pt">modelo OpenOffice Draw</comment>
- <comment xml:lang="pl">Szablon rysunku OpenOffice.org Draw</comment>
- <comment xml:lang="oc">modèl OpenOffice Draw</comment>
- <comment xml:lang="nn">OpenOffice Draw-mal</comment>
- <comment xml:lang="nl">OpenOffice.org Draw-sjabloon</comment>
- <comment xml:lang="nb">OpenOffice Draw-mal</comment>
- <comment xml:lang="lv">OpenOffice Draw veidne</comment>
- <comment xml:lang="lt">OpenOffice Draw šablonas</comment>
- <comment xml:lang="ko">OpenOffice Draw 그림 문서 서식</comment>
- <comment xml:lang="kk">OpenOffice Draw үлгісі</comment>
- <comment xml:lang="ka">OpenOffice Draw-ის შაბლონი</comment>
- <comment xml:lang="ja">OpenOffice Draw テンプレート</comment>
- <comment xml:lang="it">Modello OpenOffice Draw</comment>
- <comment xml:lang="id">Templat OpenOffice Draw</comment>
- <comment xml:lang="ia">Patrono OpenOffice Draw</comment>
- <comment xml:lang="hu">OpenOffice Draw sablon</comment>
- <comment xml:lang="hr">Predložak OpenOffice Drawa</comment>
- <comment xml:lang="he">תבנית של OpenOffice Draw</comment>
- <comment xml:lang="gl">modelo de OpenOffice Draw</comment>
- <comment xml:lang="ga">teimpléad OpenOffice Draw</comment>
- <comment xml:lang="fur">model OpenOffice Draw </comment>
- <comment xml:lang="fr">modèle OpenOffice Draw</comment>
- <comment xml:lang="fo">OpenOffice Draw formur</comment>
- <comment xml:lang="fi">OpenOffice Draw -malli</comment>
- <comment xml:lang="eu">OpenOffice Draw txantiloia</comment>
+ <comment>LibreOffice Draw template</comment>
+ <comment xml:lang="uk">шаблон LibreOffice Draw</comment>
+ <comment xml:lang="sv">LibreOffice Draw-mall</comment>
+ <comment xml:lang="ru">Шаблон LibreOffice Draw</comment>
+ <comment xml:lang="pt_BR">Modelo do LibreOffice Draw</comment>
+ <comment xml:lang="pl">Szablon rysunku LibreOffice Draw</comment>
+ <comment xml:lang="it">Modello LibreOffice Draw</comment>
+ <comment xml:lang="gl">Modelo de LibreOffice Draw</comment>
+ <comment xml:lang="eu">LibreOffice Draw txantiloia</comment>
<comment xml:lang="es">plantilla de LibreOffice Draw</comment>
- <comment xml:lang="en_GB">OpenOffice Draw template</comment>
- <comment xml:lang="el">Πρότυπο OpenOffice Draw</comment>
- <comment xml:lang="de">OpenOffice-Draw-Vorlage</comment>
- <comment xml:lang="da">OpenOffice Draw-skabelon</comment>
- <comment xml:lang="cs">šablona OpenOffice Draw</comment>
- <comment xml:lang="ca">plantilla d'OpenOffice Draw</comment>
- <comment xml:lang="bg">Шаблон за чертежи — OpenOffice Draw</comment>
- <comment xml:lang="be@latin">Šablon OpenOffice Draw</comment>
- <comment xml:lang="ar">قالب Draw المكتب المفتوح</comment>
- <comment xml:lang="af">OpenOffice Draw-sjabloon</comment>
+ <comment xml:lang="de">LibreOffice Draw-Vorlage</comment>
+ <comment xml:lang="be">шаблон LibreOffice Draw</comment>
<sub-class-of type="application/zip"/>
<generic-icon name="image-x-generic"/>
<magic priority="70">
@@ -5215,58 +5469,18 @@ command to generate the output files.
<glob pattern="*.std"/>
</mime-type>
<mime-type type="application/vnd.sun.xml.impress">
- <comment>OpenOffice Impress presentation</comment>
- <comment xml:lang="zh_TW">OpenOffice Impress 簡報</comment>
- <comment xml:lang="zh_CN">OpenOffice Impress 演示文稿</comment>
- <comment xml:lang="vi">Trình diễn Impress của OpenOffice.org</comment>
- <comment xml:lang="uk">презентація OpenOffice Impress</comment>
- <comment xml:lang="tr">OpenOffice Impress sunumu</comment>
- <comment xml:lang="sv">OpenOffice Impress-presentation</comment>
- <comment xml:lang="sr">Презентација Опен Офис Импреса</comment>
- <comment xml:lang="sq">Prezantim OpenOffice Impress</comment>
- <comment xml:lang="sl">Predstavitev OpenOffice.org Impress</comment>
- <comment xml:lang="sk">Prezentácia OpenOffice Impress</comment>
- <comment xml:lang="ru">Презентация OpenOffice Impress</comment>
- <comment xml:lang="ro">Prezentare OpenOffice Impress</comment>
- <comment xml:lang="pt_BR">Apresentação do OpenOffice Impress</comment>
- <comment xml:lang="pt">apresentação OpenOffice Impress</comment>
- <comment xml:lang="pl">Prezentacja OpenOffice.org Impress</comment>
- <comment xml:lang="oc">presentacion OpenOffice Impress</comment>
- <comment xml:lang="nn">OpenOffice Impress-presentasjon</comment>
- <comment xml:lang="nl">OpenOffice.org Impress-presentatie</comment>
- <comment xml:lang="nb">OpenOffice Impress-presentasjon</comment>
- <comment xml:lang="lv">OpenOffice Impress prezentācija</comment>
- <comment xml:lang="lt">OpenOffice Impress pateiktis</comment>
- <comment xml:lang="ko">OpenOffice Impress 프레젠테이션</comment>
- <comment xml:lang="kk">OpenOffice Impress презентациясы</comment>
- <comment xml:lang="ka">OpenOffice Impress-ის პრეზენტაცია</comment>
- <comment xml:lang="ja">OpenOffice Impress プレゼンテーション</comment>
- <comment xml:lang="it">Presentazione OpenOffice Impress</comment>
- <comment xml:lang="id">Presentasi OpenOffice Impress</comment>
- <comment xml:lang="ia">Presentation OpenOffice Impress</comment>
- <comment xml:lang="hu">OpenOffice Impress bemutató</comment>
- <comment xml:lang="hr">OpenOffice Impress prezentacija</comment>
- <comment xml:lang="he">מצגת של OpenOffice Impress</comment>
- <comment xml:lang="gl">presentación de de OpenOffice Impress</comment>
- <comment xml:lang="ga">láithreoireacht OpenOffice Impress</comment>
- <comment xml:lang="fur">presentazion OpenOffice Impress</comment>
- <comment xml:lang="fr">présentation OpenOffice Impress</comment>
- <comment xml:lang="fo">OpenOffice Impress framløga</comment>
- <comment xml:lang="fi">OpenOffice Impress -esitys</comment>
- <comment xml:lang="eu">OpenOffice.org Impress aurkezpena</comment>
+ <comment>LibreOffice Impress presentation</comment>
+ <comment xml:lang="uk">презентація LibreOffice Impress</comment>
+ <comment xml:lang="sv">LibreOffice Impress-presentation</comment>
+ <comment xml:lang="ru">Презентация LibreOffice Impress</comment>
+ <comment xml:lang="pt_BR">Apresentação do LibreOffice Impress</comment>
+ <comment xml:lang="pl">Prezentacja LibreOffice Impress</comment>
+ <comment xml:lang="it">Presentazione LibreOffice Impress</comment>
+ <comment xml:lang="gl">Presentación de LibreOffice Impress</comment>
+ <comment xml:lang="eu">LibreOffice Impress aurkezpena</comment>
<comment xml:lang="es">presentación de LibreOffice Impress</comment>
- <comment xml:lang="en_GB">OpenOffice Impress presentation</comment>
- <comment xml:lang="el">Παρουσίαση OpenOffice Impress</comment>
- <comment xml:lang="de">OpenOffice-Impress-Vorlage</comment>
- <comment xml:lang="da">OpenOffice Impress-præsentation</comment>
- <comment xml:lang="cy">Cyflwyniad OpenOffice (Impress)</comment>
- <comment xml:lang="cs">prezentace OpenOffice Impress</comment>
- <comment xml:lang="ca">presentació d'OpenOffice Impress</comment>
- <comment xml:lang="bg">Презентация — OpenOffice Impress</comment>
- <comment xml:lang="be@latin">Prezentacyja OpenOffice Impress</comment>
- <comment xml:lang="az">OpenOffice Impress sənədi</comment>
- <comment xml:lang="ar">عرض تقديمي Impress المكتب المفتوح</comment>
- <comment xml:lang="af">OpenOffice Impress-voorlegging</comment>
+ <comment xml:lang="de">LibreOffice Impress-Präsentation</comment>
+ <comment xml:lang="be">прэзентацыя LibreOffice Impress</comment>
<sub-class-of type="application/zip"/>
<generic-icon name="x-office-presentation"/>
<magic priority="70">
@@ -5279,56 +5493,18 @@ command to generate the output files.
<glob pattern="*.sxi"/>
</mime-type>
<mime-type type="application/vnd.sun.xml.impress.template">
- <comment>OpenOffice Impress template</comment>
- <comment xml:lang="zh_TW">OpenOffice Impress 範本</comment>
- <comment xml:lang="zh_CN">OpenOffice Impress 模板</comment>
- <comment xml:lang="vi">Mẫu trình diễn Impress của OpenOffice.org</comment>
- <comment xml:lang="uk">шаблон презентації OpenOffice Impress</comment>
- <comment xml:lang="tr">OpenOffice Impress şablonu</comment>
- <comment xml:lang="sv">OpenOffice Impress-mall</comment>
- <comment xml:lang="sr">Шаблон Опен Офис Импреса</comment>
- <comment xml:lang="sq">Model OpenOffice Impress</comment>
- <comment xml:lang="sl">Predloga OpenOffice.org Impress</comment>
- <comment xml:lang="sk">Šablóna OpenOffice Impress</comment>
- <comment xml:lang="ru">Шаблон OpenOffice Impress</comment>
- <comment xml:lang="ro">Șablon OpenOffice Impress</comment>
- <comment xml:lang="pt_BR">Modelo do OpenOffice Impress</comment>
- <comment xml:lang="pt">modelo OpenOffice Impress</comment>
- <comment xml:lang="pl">Szablon prezentacji OpenOffice.org Impress</comment>
- <comment xml:lang="oc">modèl OpenOffice Impress</comment>
- <comment xml:lang="nn">OpenOffice Impress-mal</comment>
- <comment xml:lang="nl">OpenOffice.org Impress-sjabloon</comment>
- <comment xml:lang="nb">OpenOffice Impress-mal</comment>
- <comment xml:lang="lv">OpenOffice Impress veidne</comment>
- <comment xml:lang="lt">OpenOffice Impress šablonas</comment>
- <comment xml:lang="ko">OpenOffice Impress 프레젠테이션 문서 서식</comment>
- <comment xml:lang="kk">OpenOffice Impress үлгісі</comment>
- <comment xml:lang="ka">OpenOffice Impress-ის შაბლონი</comment>
- <comment xml:lang="ja">OpenOffice Impress テンプレート</comment>
- <comment xml:lang="it">Modello OpenOffice Impress</comment>
- <comment xml:lang="id">Templat OpenOffice Impress</comment>
- <comment xml:lang="ia">Patrono OpenOffice Impress</comment>
- <comment xml:lang="hu">OpenOffice Impress sablon</comment>
- <comment xml:lang="hr">Predložak OpenOffice Impressa</comment>
- <comment xml:lang="he">תבנית של OpenOffice Impress</comment>
- <comment xml:lang="gl">modelo de OpenOffice Impress</comment>
- <comment xml:lang="ga">teimpléad OpenOffice Impress</comment>
- <comment xml:lang="fur">model OpenOffice Impress</comment>
- <comment xml:lang="fr">modèle OpenOffice Impress</comment>
- <comment xml:lang="fo">OpenOffice Impress formur</comment>
- <comment xml:lang="fi">OpenOffice Impress -malli</comment>
- <comment xml:lang="eu">OpenOffice Impress txantiloia</comment>
+ <comment>LibreOffice Impress template</comment>
+ <comment xml:lang="uk">шаблон LibreOffice Impress</comment>
+ <comment xml:lang="sv">LibreOffice Impress-mall</comment>
+ <comment xml:lang="ru">Шаблон LibreOffice Impress</comment>
+ <comment xml:lang="pt_BR">Documento do LibreOffice Impress</comment>
+ <comment xml:lang="pl">Szablon prezentacji LibreOffice Impress</comment>
+ <comment xml:lang="it">Modello LibreOffice Impress</comment>
+ <comment xml:lang="gl">Modelo de LibreOffice Impress</comment>
+ <comment xml:lang="eu">LibreOffice Impress txantiloia</comment>
<comment xml:lang="es">plantilla de LibreOffice Impress</comment>
- <comment xml:lang="en_GB">OpenOffice Impress template</comment>
- <comment xml:lang="el">Πρότυπο OpenOffice Impress</comment>
- <comment xml:lang="de">OpenOffice-Impress-Vorlage</comment>
- <comment xml:lang="da">OpenOffice Impress-skabelon</comment>
- <comment xml:lang="cs">šablona OpenOffice Impress</comment>
- <comment xml:lang="ca">plantilla d'OpenOffice Impress</comment>
- <comment xml:lang="bg">Шаблон за презентации — OpenOffice Impress</comment>
- <comment xml:lang="be@latin">Šablon OpenOffice Impress</comment>
- <comment xml:lang="ar">قالب Impress المكتب المفتوح</comment>
- <comment xml:lang="af">OpenOffice Impress-sjabloon</comment>
+ <comment xml:lang="de">LibreOffice Impress-Vorlage</comment>
+ <comment xml:lang="be">шаблон LibreOffice Impress</comment>
<sub-class-of type="application/zip"/>
<generic-icon name="x-office-presentation"/>
<magic priority="70">
@@ -5341,56 +5517,18 @@ command to generate the output files.
<glob pattern="*.sti"/>
</mime-type>
<mime-type type="application/vnd.sun.xml.math">
- <comment>OpenOffice Math formula</comment>
- <comment xml:lang="zh_TW">OpenOffice Math 公式</comment>
- <comment xml:lang="zh_CN">OpenOffice Math 公式</comment>
- <comment xml:lang="vi">Công thức Math của OpenOffice.org</comment>
- <comment xml:lang="uk">формула OpenOffice Math</comment>
- <comment xml:lang="tr">OpenOffice Math formülü</comment>
- <comment xml:lang="sv">OpenOffice Math-formel</comment>
- <comment xml:lang="sr">Формула Опен Офис Математике</comment>
- <comment xml:lang="sq">Formulë OpenOffice Math</comment>
- <comment xml:lang="sl">Dokument formule OpenOffice.org Math</comment>
- <comment xml:lang="sk">Vzorec OpenOffice Math</comment>
- <comment xml:lang="ru">Формула OpenOffice Math</comment>
- <comment xml:lang="ro">Formulă OpenOffice Math</comment>
- <comment xml:lang="pt_BR">Fórmula do OpenOffice Math</comment>
- <comment xml:lang="pt">fórmula OpenOffice Math</comment>
- <comment xml:lang="pl">Formuła OpenOffice.org Math</comment>
- <comment xml:lang="oc">formula OpenOffice Math</comment>
- <comment xml:lang="nn">OpenOffice Math-formel</comment>
- <comment xml:lang="nl">OpenOffice.org Math-formule</comment>
- <comment xml:lang="nb">OpenOffice Math-formel</comment>
- <comment xml:lang="lv">OpenOffice Math formula</comment>
- <comment xml:lang="lt">OpenOffice Math formulė</comment>
- <comment xml:lang="ko">OpenOffice Math 수식</comment>
- <comment xml:lang="kk">OpenOffice Math формуласы</comment>
- <comment xml:lang="ka">OpenOffice Math-ის ფორმულა</comment>
- <comment xml:lang="ja">OpenOffice Math 計算式</comment>
- <comment xml:lang="it">Formula OpenOffice Math</comment>
- <comment xml:lang="id">Formula OpenOffice Math</comment>
- <comment xml:lang="ia">Formula OpenOffice Math</comment>
- <comment xml:lang="hu">OpenOffice Math képlet</comment>
- <comment xml:lang="hr">OpenOffice Math formula</comment>
- <comment xml:lang="he">נוסחה של OpenOffice Math</comment>
- <comment xml:lang="gl">fórmula de OpenOffice Math</comment>
- <comment xml:lang="ga">foirmle OpenOffice Math</comment>
- <comment xml:lang="fur">formule OpenOffice Math</comment>
- <comment xml:lang="fr">formule OpenOffice Math</comment>
- <comment xml:lang="fo">OpenOffice Math frymil</comment>
- <comment xml:lang="fi">OpenOffice Math -kaava</comment>
- <comment xml:lang="eu">OpenOffice.org Math formula</comment>
+ <comment>LibreOffice Math formula</comment>
+ <comment xml:lang="uk">формула LibreOffice Math</comment>
+ <comment xml:lang="sv">LibreOffice Math-formel</comment>
+ <comment xml:lang="ru">Формула LibreOffice Math</comment>
+ <comment xml:lang="pt_BR">Fórmula do LibreOffice Math</comment>
+ <comment xml:lang="pl">Formuła LibreOffice Math</comment>
+ <comment xml:lang="it">Formula LibreOffice Math</comment>
+ <comment xml:lang="gl">Fórmula de LibreOffice Math</comment>
+ <comment xml:lang="eu">LibreOffice Math formula</comment>
<comment xml:lang="es">fórmula de LibreOffice Math</comment>
- <comment xml:lang="en_GB">OpenOffice Math formula</comment>
- <comment xml:lang="el">Μαθηματικός τύπος OpenOffice Math</comment>
- <comment xml:lang="de">OpenOffice-Math-Formel</comment>
- <comment xml:lang="da">OpenOffice Math-formel</comment>
- <comment xml:lang="cs">vzorec OpenOffice Math</comment>
- <comment xml:lang="ca">fórmula d'OpenOffice Math</comment>
- <comment xml:lang="bg">Формула — OpenOffice Math</comment>
- <comment xml:lang="be@latin">Formuła OpenOffice Math</comment>
- <comment xml:lang="ar">صيغة Math المكتب المفتوح</comment>
- <comment xml:lang="af">OpenOffice Math-formule</comment>
+ <comment xml:lang="de">LibreOffice Math-Formel</comment>
+ <comment xml:lang="be">формула LibreOffice Math</comment>
<sub-class-of type="application/zip"/>
<generic-icon name="x-office-document"/>
<magic priority="70">
@@ -5403,59 +5541,18 @@ command to generate the output files.
<glob pattern="*.sxm"/>
</mime-type>
<mime-type type="application/vnd.sun.xml.writer">
- <comment>OpenOffice Writer document</comment>
- <comment xml:lang="zh_TW">OpenOffice Writer 文件</comment>
- <comment xml:lang="zh_CN">OpenOffice Writer 文档</comment>
- <comment xml:lang="vi">Tài liệu Writer của OpenOffice.org</comment>
- <comment xml:lang="uk">документ OpenOffice Writer</comment>
- <comment xml:lang="tr">OpenOffice Writer belgesi</comment>
- <comment xml:lang="sv">OpenOffice Writer-dokument</comment>
- <comment xml:lang="sr">Документ Опен Офис Писца</comment>
- <comment xml:lang="sq">Dokument OpenOffice Writer</comment>
- <comment xml:lang="sl">Dokument OpenOffice.org Writer</comment>
- <comment xml:lang="sk">Dokument OpenOffice Writer</comment>
- <comment xml:lang="ru">Документ OpenOffice Writer</comment>
- <comment xml:lang="ro">Document OpenOffice Writer</comment>
- <comment xml:lang="pt_BR">Documento do OpenOffice Writer</comment>
- <comment xml:lang="pt">documento OpenOffice Writer</comment>
- <comment xml:lang="pl">Dokument OpenOffice.org Writer</comment>
- <comment xml:lang="oc">document OpenOffice Writer</comment>
- <comment xml:lang="nn">OpenOffice Writer-dokument</comment>
- <comment xml:lang="nl">OpenOffice.org Writer-document</comment>
- <comment xml:lang="nb">OpenOffice Writer-dokument</comment>
- <comment xml:lang="lv">OpenOffice Writer dokuments</comment>
- <comment xml:lang="lt">OpenOffice Writer dokumentas</comment>
- <comment xml:lang="ko">OpenOffice Writer 문서</comment>
- <comment xml:lang="kk">OpenOffice Writer құжаты</comment>
- <comment xml:lang="ka">OpenOffice Writer-ის დოკუმენტი</comment>
- <comment xml:lang="ja">OpenOffice Writer ドキュメント</comment>
- <comment xml:lang="it">Documento OpenOffice Writer</comment>
- <comment xml:lang="id">Dokumen OpenOffice Writer</comment>
- <comment xml:lang="ia">Documento OpenOffice Writer</comment>
- <comment xml:lang="hu">OpenOffice Writer dokumentum</comment>
- <comment xml:lang="hr">OpenOffice Writer dokument</comment>
- <comment xml:lang="he">מסמך של OpenOffice Writer</comment>
- <comment xml:lang="gl">documento de OpenOffice Writer</comment>
- <comment xml:lang="ga">cáipéis OpenOffice Writer</comment>
- <comment xml:lang="fur">document OpenOffice Writer</comment>
- <comment xml:lang="fr">document OpenOffice Writer</comment>
- <comment xml:lang="fo">OpenOffice Writer skjal</comment>
- <comment xml:lang="fi">OpenOffice Writer -asiakirja</comment>
- <comment xml:lang="eu">OpenOffice.org Writer dokumentua</comment>
+ <comment>LibreOffice Writer document</comment>
+ <comment xml:lang="uk">документ LibreOffice Writer</comment>
+ <comment xml:lang="sv">LibreOffice Writer-dokument</comment>
+ <comment xml:lang="ru">Документ LibreOffice Writer</comment>
+ <comment xml:lang="pt_BR">Documento do LibreOffice Writer</comment>
+ <comment xml:lang="pl">Dokument LibreOffice Writer</comment>
+ <comment xml:lang="it">Documento LibreOffice Writer</comment>
+ <comment xml:lang="gl">Documento de LibreOffice Writer</comment>
+ <comment xml:lang="eu">LibreOffice Writer dokumentua</comment>
<comment xml:lang="es">documento de LibreOffice Writer</comment>
- <comment xml:lang="en_GB">OpenOffice Writer document</comment>
- <comment xml:lang="el">Έγγραφο OpenOffice Writer</comment>
- <comment xml:lang="de">OpenOffice-Writer-Dokument</comment>
- <comment xml:lang="da">OpenOffice Writer-dokument</comment>
- <comment xml:lang="cy">Dogfen OpenOffice (Writer)</comment>
- <comment xml:lang="cs">dokument OpenOffice Writer</comment>
- <comment xml:lang="ca">document d'OpenOffice Writer</comment>
- <comment xml:lang="bg">Документ — OpenOffice Writer</comment>
- <comment xml:lang="be@latin">Dakument OpenOffice Writer</comment>
- <comment xml:lang="az">OpenOffice Writer sənədi</comment>
- <comment xml:lang="ast">Documentu d'OpenOffice Writer</comment>
- <comment xml:lang="ar">مستند Writer المكتب المفتوح</comment>
- <comment xml:lang="af">OpenOffice Writer-dokument</comment>
+ <comment xml:lang="de">LibreOffice Writer-Dokument</comment>
+ <comment xml:lang="be">дакумент LibreOffice Writer</comment>
<sub-class-of type="application/zip"/>
<generic-icon name="x-office-document"/>
<magic priority="70">
@@ -5468,59 +5565,18 @@ command to generate the output files.
<glob pattern="*.sxw"/>
</mime-type>
<mime-type type="application/vnd.sun.xml.writer.global">
- <comment>OpenOffice Writer global document</comment>
- <comment xml:lang="zh_TW">OpenOffice Writer 主控文件</comment>
- <comment xml:lang="zh_CN">OpenOffice Writer 全局文档</comment>
- <comment xml:lang="vi">Tài liệu toàn cục Writer của OpenOffice.org</comment>
- <comment xml:lang="uk">загальний документ OpenOffice Writer</comment>
- <comment xml:lang="tr">OpenOffice Writer global belgesi</comment>
- <comment xml:lang="sv">OpenOffice Writer-globaldokument</comment>
- <comment xml:lang="sr">Општи документ Опен Офис Писца</comment>
- <comment xml:lang="sq">Dokument i përgjithshëm OpenOffice Writer</comment>
- <comment xml:lang="sl">Splošni dokument OpenOffice.org Writer</comment>
- <comment xml:lang="sk">Globálny dokument OpenOffice Writer</comment>
- <comment xml:lang="ru">Основной документ OpenOffice Writer</comment>
- <comment xml:lang="ro">Document global OpenOffice Writer</comment>
- <comment xml:lang="pt_BR">Documento global do OpenOffice Writer</comment>
- <comment xml:lang="pt">documento global OpenOffice Writer</comment>
- <comment xml:lang="pl">Globalny dokument OpenOffice.org Writer</comment>
- <comment xml:lang="oc">document global OpenOffice Writer</comment>
- <comment xml:lang="nn">OpenOffice Writer globalt dokument</comment>
- <comment xml:lang="nl">OpenOffice.org Writer-globaal-document</comment>
- <comment xml:lang="nb">Global OpenOffice Writer globalt dokument</comment>
- <comment xml:lang="lv">OpenOffice Writer globālais dokuments</comment>
- <comment xml:lang="lt">OpenOffice Writer bendrinis dokumentas</comment>
- <comment xml:lang="ko">OpenOffice Writer 글로벌 문서</comment>
- <comment xml:lang="kk">OpenOffice Writer негізгі құжаты</comment>
- <comment xml:lang="ka">OpenOffice Writer-ის გლობალური დოკუმენტი</comment>
- <comment xml:lang="ja">OpenOffice Writer グローバルドキュメント</comment>
- <comment xml:lang="it">Documento globale OpenOffice Writer</comment>
- <comment xml:lang="id">Dokumen global OpenOffice Writer</comment>
- <comment xml:lang="ia">Documento global OpenOffice Writer</comment>
- <comment xml:lang="hu">OpenOffice Writer globális dokumentum</comment>
- <comment xml:lang="hr">OpenOffice Writer globalni dokument</comment>
- <comment xml:lang="he">מסמך גלובלי של OpenOffice Writer</comment>
- <comment xml:lang="gl">documento global de OpenOffice Writer</comment>
- <comment xml:lang="ga">cáipéis chomhchoiteann OpenOffice Writer</comment>
- <comment xml:lang="fur">document globâl OpenOffice Writer</comment>
- <comment xml:lang="fr">document global OpenOffice Writer</comment>
- <comment xml:lang="fo">OpenOffice Writer heiltøkt skjal</comment>
- <comment xml:lang="fi">OpenOffice Writer - yleinen asiakirja</comment>
- <comment xml:lang="eu">OpenOffice.org Writer dokumentu globala</comment>
+ <comment>LibreOffice Writer global document</comment>
+ <comment xml:lang="uk">загальний документ LibreOffice Writer</comment>
+ <comment xml:lang="sv">LibreOffice Writer-globaldokument</comment>
+ <comment xml:lang="ru">Основной документ LibreOffice Writer</comment>
+ <comment xml:lang="pt_BR">Documento global do LibreOffice Writer</comment>
+ <comment xml:lang="pl">Globalny dokument LibreOffice Writer</comment>
+ <comment xml:lang="it">Documento globale LibreOffice Writer</comment>
+ <comment xml:lang="gl">Documento global de LibreOffice Writer</comment>
+ <comment xml:lang="eu">LibreOffice Writer dokumentu globala</comment>
<comment xml:lang="es">documento global de LibreOffice Writer</comment>
- <comment xml:lang="en_GB">OpenOffice Writer global document</comment>
- <comment xml:lang="el">Καθολικό έγγραφο OpenOffice Writer</comment>
- <comment xml:lang="de">OpenOffice-Writer-Globaldokument</comment>
- <comment xml:lang="da">OpenOffice Writer-globalt dokument</comment>
- <comment xml:lang="cy">Dogfen eang OpenOffice (Writer)</comment>
- <comment xml:lang="cs">globální dokument OpenOffice Writer</comment>
- <comment xml:lang="ca">document global d'OpenOffice Writer</comment>
- <comment xml:lang="bg">Глобален документ — OpenOffice Writer</comment>
- <comment xml:lang="be@latin">Hlabalny dakument OpenOffice Writer</comment>
- <comment xml:lang="az">OpenOffice Writer qlobal sənədi</comment>
- <comment xml:lang="ast">Documentu global d'OpenOffice Writer</comment>
- <comment xml:lang="ar">مستند المكتب المفتوح Writer العالمي</comment>
- <comment xml:lang="af">OpenOffice Writer globale dokument</comment>
+ <comment xml:lang="de">LibreOffice Writer-Globaldokument</comment>
+ <comment xml:lang="be">глабальны дакумент LibreOffice Writer</comment>
<sub-class-of type="application/zip"/>
<generic-icon name="x-office-document"/>
<magic priority="70">
@@ -5533,59 +5589,18 @@ command to generate the output files.
<glob pattern="*.sxg"/>
</mime-type>
<mime-type type="application/vnd.sun.xml.writer.template">
- <comment>OpenOffice Writer template</comment>
- <comment xml:lang="zh_TW">OpenOffice Writer 範本</comment>
- <comment xml:lang="zh_CN">OpenOffice Writer 模板</comment>
- <comment xml:lang="vi">Mẫu tài liệu Writer của OpenOffice.org</comment>
- <comment xml:lang="uk">шаблон документа OpenOffice Writer</comment>
- <comment xml:lang="tr">OpenOffice Writer şablonu</comment>
- <comment xml:lang="sv">OpenOffice Writer-mall</comment>
- <comment xml:lang="sr">Шаблон Опен Офис Писца</comment>
- <comment xml:lang="sq">Model OpenOffice Writer</comment>
- <comment xml:lang="sl">Predloga OpenOffice.org Writer</comment>
- <comment xml:lang="sk">Šablóna OpenOffice Writer</comment>
- <comment xml:lang="ru">Шаблон OpenOffice Writer</comment>
- <comment xml:lang="ro">Șablon OpenOffice Writer</comment>
- <comment xml:lang="pt_BR">Modelo do OpenOffice Writer</comment>
- <comment xml:lang="pt">modelo OpenOffice Writer</comment>
- <comment xml:lang="pl">Szablon dokumentu OpenOffice.org Writer</comment>
- <comment xml:lang="oc">modèl OpenOffice Writer</comment>
- <comment xml:lang="nn">OpenOffice Writer-mal</comment>
- <comment xml:lang="nl">OpenOffice.org Writer-sjabloon</comment>
- <comment xml:lang="nb">OpenOffice Writer-mal</comment>
- <comment xml:lang="ms">Templat OpenOffice Writer</comment>
- <comment xml:lang="lv">OpenOffice Writer veidne</comment>
- <comment xml:lang="lt">OpenOffice Writer šablonas</comment>
- <comment xml:lang="ko">OpenOffice Writer 문서 서식</comment>
- <comment xml:lang="kk">OpenOffice Writer үлгісі</comment>
- <comment xml:lang="ka">OpenOffice Writer-ის შაბლონი</comment>
- <comment xml:lang="ja">OpenOffice Writer ドキュメントテンプレート</comment>
- <comment xml:lang="it">Modello OpenOffice Writer</comment>
- <comment xml:lang="id">Templat OpenOffice Writer</comment>
- <comment xml:lang="ia">Patrono OpenOffice Writer</comment>
- <comment xml:lang="hu">OpenOffice Writer sablon</comment>
- <comment xml:lang="hr">OpenOffice Writer predložak</comment>
- <comment xml:lang="he">תסנית של OpenOffice Writer</comment>
- <comment xml:lang="gl">modelo de OpenOffice Writer</comment>
- <comment xml:lang="ga">teimpléad OpenOffice Writer</comment>
- <comment xml:lang="fur">model OpenOffice Writer</comment>
- <comment xml:lang="fr">modèle OpenOffice Writer</comment>
- <comment xml:lang="fo">OpenOffice Writer formur</comment>
- <comment xml:lang="fi">OpenOffice Writer -malli</comment>
- <comment xml:lang="eu">OpenOffice Writer txantiloia</comment>
+ <comment>LibreOffice Writer template</comment>
+ <comment xml:lang="uk">шаблон LibreOffice Writer</comment>
+ <comment xml:lang="sv">LibreOffice Writer-mall</comment>
+ <comment xml:lang="ru">Шаблон LibreOffice Writer</comment>
+ <comment xml:lang="pt_BR">Modelo do LibreOffice Writer</comment>
+ <comment xml:lang="pl">Szablon dokumentu LibreOffice Writer</comment>
+ <comment xml:lang="it">Modello LibreOffice Writer</comment>
+ <comment xml:lang="gl">Modelo de LibreOffice Writer</comment>
+ <comment xml:lang="eu">LibreOffice Writer txantiloia</comment>
<comment xml:lang="es">plantilla de LibreOffice Writer</comment>
- <comment xml:lang="en_GB">OpenOffice Writer template</comment>
- <comment xml:lang="el">Πρότυπο OpenOffice Writer</comment>
- <comment xml:lang="de">OpenOffice-Writer-Vorlage</comment>
- <comment xml:lang="da">OpenOffice Writer-skabelon</comment>
- <comment xml:lang="cy">Templed OpenOffice (Writer)</comment>
- <comment xml:lang="cs">šablona OpenOffice Writer</comment>
- <comment xml:lang="ca">plantilla d'OpenOffice Writer</comment>
- <comment xml:lang="bg">Шаблон за документи — OpenOffice Writer</comment>
- <comment xml:lang="be@latin">Šablon OpenOffice Writer</comment>
- <comment xml:lang="az">OpenOffice Writer şablonu</comment>
- <comment xml:lang="ar">قالب Writer المكتب المفتوح</comment>
- <comment xml:lang="af">OpenOffice Writer-sjabloon</comment>
+ <comment xml:lang="de">LibreOffice Writer-Vorlage</comment>
+ <comment xml:lang="be">шаблон LibreOffice Writer</comment>
<sub-class-of type="application/zip"/>
<generic-icon name="x-office-document"/>
<magic priority="70">
@@ -5606,8 +5621,9 @@ command to generate the output files.
<comment xml:lang="tr">ODT belgesi</comment>
<comment xml:lang="sv">ODT-dokument</comment>
<comment xml:lang="sr">ОДТ документ</comment>
- <comment xml:lang="sq">Dokument ODT</comment>
+ <comment xml:lang="sq">dokument ODT</comment>
<comment xml:lang="sl">Dokument ODT</comment>
+ <comment xml:lang="si">ODT ලේඛනය</comment>
<comment xml:lang="sk">Dokument ODT</comment>
<comment xml:lang="ru">Документ ODT</comment>
<comment xml:lang="ro">Document ODT</comment>
@@ -5625,6 +5641,7 @@ command to generate the output files.
<comment xml:lang="ka">ODT დოკუმენტი</comment>
<comment xml:lang="ja">ODT ドキュメント</comment>
<comment xml:lang="it">Documento ODT</comment>
+ <comment xml:lang="is">ODT skjal</comment>
<comment xml:lang="id">Dokumen ODT</comment>
<comment xml:lang="ia">Documento ODT</comment>
<comment xml:lang="hu">ODT-dokumentum</comment>
@@ -5647,6 +5664,7 @@ command to generate the output files.
<comment xml:lang="ca">document ODT</comment>
<comment xml:lang="bg">Документ — ODT</comment>
<comment xml:lang="be@latin">Dakument ODT</comment>
+ <comment xml:lang="be">дакумент ODT</comment>
<comment xml:lang="ast">Documentu ODT</comment>
<comment xml:lang="ar">مستند ODT</comment>
<comment xml:lang="af">ODT-dokument</comment>
@@ -5671,7 +5689,9 @@ command to generate the output files.
<comment xml:lang="tr">ODT belgesi (Düz XML)</comment>
<comment xml:lang="sv">ODT-dokument (platt XML)</comment>
<comment xml:lang="sr">ОДТ документ (Обични ИксМЛ)</comment>
+ <comment xml:lang="sq">dokument ODT (Flat XML)</comment>
<comment xml:lang="sl">Datoteka dokumenta ODT (nepovezan XML)</comment>
+ <comment xml:lang="si">ODT ලේඛනය (පැතලි XML)</comment>
<comment xml:lang="sk">Dokument ODT (čisté XML)</comment>
<comment xml:lang="ru">Документ ODT (простой XML)</comment>
<comment xml:lang="ro">Document ODT (XML simplu)</comment>
@@ -5687,6 +5707,7 @@ command to generate the output files.
<comment xml:lang="ka">ODT დოკუმენტი (Flat XML)</comment>
<comment xml:lang="ja">ODT ドキュメント (Flat XML)</comment>
<comment xml:lang="it">Documento ODT (XML semplice)</comment>
+ <comment xml:lang="is">ODT skjal (flatt XML)</comment>
<comment xml:lang="id">Dokumen ODT (Flat XML)</comment>
<comment xml:lang="ia">Documento ODT (XML platte)</comment>
<comment xml:lang="hu">ODT-dokumentum (egyszerű XML)</comment>
@@ -5702,11 +5723,12 @@ command to generate the output files.
<comment xml:lang="es">documento ODT (XML plano)</comment>
<comment xml:lang="en_GB">ODT document (Flat XML)</comment>
<comment xml:lang="el">Έγγραφο ODT (Flat XML)</comment>
- <comment xml:lang="de">ODT-Dokument (Unkomprimiertes XML)</comment>
+ <comment xml:lang="de">ODT-Dokument (einfaches XML)</comment>
<comment xml:lang="da">ODT-dokument (flad XML)</comment>
<comment xml:lang="cs">dokument ODT (Flat XML)</comment>
<comment xml:lang="ca">document ODT (XML pla)</comment>
<comment xml:lang="bg">Документ — ODT (само XML)</comment>
+ <comment xml:lang="be">дакумент ODT (плоскі XML)</comment>
<comment xml:lang="ast">Documentu ODT (XML planu)</comment>
<comment xml:lang="ar">مستند ODT (Flat XML)</comment>
<comment xml:lang="af">ODT-dokument (plat XML)</comment>
@@ -5725,8 +5747,9 @@ command to generate the output files.
<comment xml:lang="tr">ODT şablonu</comment>
<comment xml:lang="sv">ODT-mall</comment>
<comment xml:lang="sr">ОДТ шаблон</comment>
- <comment xml:lang="sq">Model ODT</comment>
+ <comment xml:lang="sq">gjedhe ODT</comment>
<comment xml:lang="sl">Predloga dokumenta ODT</comment>
+ <comment xml:lang="si">ODT අච්චුව</comment>
<comment xml:lang="sk">Šablóna ODT</comment>
<comment xml:lang="ru">Шаблон ODT</comment>
<comment xml:lang="ro">Șablon ODT</comment>
@@ -5744,6 +5767,7 @@ command to generate the output files.
<comment xml:lang="ka">ODT დოკუმენტი</comment>
<comment xml:lang="ja">ODT テンプレート</comment>
<comment xml:lang="it">Modello ODT</comment>
+ <comment xml:lang="is">ODT sniðmát</comment>
<comment xml:lang="id">Templat ODT</comment>
<comment xml:lang="ia">Patrono ODT</comment>
<comment xml:lang="hu">ODT-sablon</comment>
@@ -5766,6 +5790,7 @@ command to generate the output files.
<comment xml:lang="ca">plantilla ODT</comment>
<comment xml:lang="bg">Шаблон за документи — ODT</comment>
<comment xml:lang="be@latin">Šablon ODT</comment>
+ <comment xml:lang="be">шаблон ODT</comment>
<comment xml:lang="ar">قالب ODT</comment>
<comment xml:lang="af">ODT-sjabloon</comment>
<acronym>ODT</acronym>
@@ -5790,8 +5815,9 @@ command to generate the output files.
<comment xml:lang="tr">OTH şablonu</comment>
<comment xml:lang="sv">OTH-mall</comment>
<comment xml:lang="sr">ОТХ шаблон</comment>
- <comment xml:lang="sq">Model OTH</comment>
+ <comment xml:lang="sq">gjedhe OTH</comment>
<comment xml:lang="sl">Predloga OTH</comment>
+ <comment xml:lang="si">OTH අච්චුව</comment>
<comment xml:lang="sk">Šablóna OTH</comment>
<comment xml:lang="ru">Шаблон OTH</comment>
<comment xml:lang="ro">Șablon OTH</comment>
@@ -5809,6 +5835,7 @@ command to generate the output files.
<comment xml:lang="ka">OTH შაბლონი</comment>
<comment xml:lang="ja">OTH テンプレート</comment>
<comment xml:lang="it">Modello OTH</comment>
+ <comment xml:lang="is">OTH sniðmát</comment>
<comment xml:lang="id">Templat OTH</comment>
<comment xml:lang="ia">Patrono OTH</comment>
<comment xml:lang="hu">OTH-sablon</comment>
@@ -5831,6 +5858,7 @@ command to generate the output files.
<comment xml:lang="ca">plantilla OTH</comment>
<comment xml:lang="bg">Шаблон за страници — OTH</comment>
<comment xml:lang="be@latin">Šablon OTH</comment>
+ <comment xml:lang="be">шаблон OTH</comment>
<comment xml:lang="ar">قالب OTH</comment>
<comment xml:lang="af">OTH-sjabloon</comment>
<acronym>OTH</acronym>
@@ -5855,8 +5883,9 @@ command to generate the output files.
<comment xml:lang="tr">ODM belgesi</comment>
<comment xml:lang="sv">ODM-dokument</comment>
<comment xml:lang="sr">ОДМ документ</comment>
- <comment xml:lang="sq">Dokument ODM</comment>
+ <comment xml:lang="sq">dokument ODM</comment>
<comment xml:lang="sl">Dokument ODM</comment>
+ <comment xml:lang="si">ODM ලේඛනය</comment>
<comment xml:lang="sk">Dokument ODM</comment>
<comment xml:lang="ru">Документ ODM</comment>
<comment xml:lang="ro">Document ODM</comment>
@@ -5874,6 +5903,7 @@ command to generate the output files.
<comment xml:lang="ka">ODM დოკუმენტი</comment>
<comment xml:lang="ja">ODM ドキュメント</comment>
<comment xml:lang="it">Documento ODM</comment>
+ <comment xml:lang="is">ODM skjal</comment>
<comment xml:lang="id">Dokumen ODM</comment>
<comment xml:lang="ia">Documento ODM</comment>
<comment xml:lang="hu">ODM-dokumentum</comment>
@@ -5896,6 +5926,7 @@ command to generate the output files.
<comment xml:lang="ca">document ODM</comment>
<comment xml:lang="bg">Документ — ODM</comment>
<comment xml:lang="be@latin">Dakument ODM</comment>
+ <comment xml:lang="be">дакумент ODM</comment>
<comment xml:lang="ast">Documentu ODM</comment>
<comment xml:lang="ar">مستند ODM</comment>
<comment xml:lang="af">ODM-dokument</comment>
@@ -5921,8 +5952,9 @@ command to generate the output files.
<comment xml:lang="tr">ODG çizimi</comment>
<comment xml:lang="sv">ODG-teckning</comment>
<comment xml:lang="sr">ОДГ цртеж</comment>
- <comment xml:lang="sq">Vizatim ODG</comment>
+ <comment xml:lang="sq">vizatim ODG</comment>
<comment xml:lang="sl">Datoteka risbe ODG</comment>
+ <comment xml:lang="si">ODG ඇඳීම</comment>
<comment xml:lang="sk">Kresba ODG</comment>
<comment xml:lang="ru">Рисунок ODG</comment>
<comment xml:lang="ro">Desen ODG</comment>
@@ -5940,6 +5972,7 @@ command to generate the output files.
<comment xml:lang="ka">ODG-ის ნახაზი</comment>
<comment xml:lang="ja">ODG ドロー</comment>
<comment xml:lang="it">Disegno ODG</comment>
+ <comment xml:lang="is">ODG teikning</comment>
<comment xml:lang="id">Gambar ODG</comment>
<comment xml:lang="ia">Designo ODG</comment>
<comment xml:lang="hu">ODG-rajz</comment>
@@ -5962,6 +5995,7 @@ command to generate the output files.
<comment xml:lang="ca">dibuix ODG</comment>
<comment xml:lang="bg">Чертеж — ODG</comment>
<comment xml:lang="be@latin">Rysunak ODG</comment>
+ <comment xml:lang="be">рысунак ODG</comment>
<comment xml:lang="ar">تصميم ODG</comment>
<comment xml:lang="af">ODG-tekening</comment>
<acronym>ODG</acronym>
@@ -5985,7 +6019,9 @@ command to generate the output files.
<comment xml:lang="tr">ODG çizimi (Düz XML)</comment>
<comment xml:lang="sv">ODG-teckning (platt XML)</comment>
<comment xml:lang="sr">ОДГ цртеж (Обичан ИксМЛ)</comment>
+ <comment xml:lang="sq">vizatim ODF (Flat XML)</comment>
<comment xml:lang="sl">Datoteka risbe ODG (nepovezan XML)</comment>
+ <comment xml:lang="si">ODG ඇඳීම (පැතලි XML)</comment>
<comment xml:lang="sk">Kresba ODG (čisté XML)</comment>
<comment xml:lang="ru">Рисунок ODG (простой XML)</comment>
<comment xml:lang="ro">Desen ODG (XML simplu)</comment>
@@ -6001,6 +6037,7 @@ command to generate the output files.
<comment xml:lang="ka">ODG-ის ნახაზი (Flat XML)</comment>
<comment xml:lang="ja">ODG ドロー (Flat XML)</comment>
<comment xml:lang="it">Disegno ODG (XML semplice)</comment>
+ <comment xml:lang="is">ODG teikning (flatt XML)</comment>
<comment xml:lang="id">Gambar ODG (FLAT XML)</comment>
<comment xml:lang="ia">Designo ODG (XML platte)</comment>
<comment xml:lang="hu">ODG-rajz (egyszerű XML)</comment>
@@ -6016,11 +6053,12 @@ command to generate the output files.
<comment xml:lang="es">dibujo ODG (XML plano)</comment>
<comment xml:lang="en_GB">ODG drawing (Flat XML)</comment>
<comment xml:lang="el">Σχέδιο ODG (Flat XML)</comment>
- <comment xml:lang="de">ODG-Zeichnung (Unkomprimiertes XML)</comment>
+ <comment xml:lang="de">ODG-Zeichnung (einfaches XML)</comment>
<comment xml:lang="da">ODG-tegning (flad XML)</comment>
<comment xml:lang="cs">kresba ODG (Flat XML)</comment>
<comment xml:lang="ca">dibuix ODG (XML pla) </comment>
<comment xml:lang="bg">Чертеж — ODG (само XML)</comment>
+ <comment xml:lang="be">рысунак ODG (плоскі XML)</comment>
<comment xml:lang="ar">رسمة ODG (Flat XML)</comment>
<comment xml:lang="af">ODG-tekening (plat XML)</comment>
<acronym>FODG</acronym>
@@ -6038,8 +6076,9 @@ command to generate the output files.
<comment xml:lang="tr">ODG şablonu</comment>
<comment xml:lang="sv">ODG-mall</comment>
<comment xml:lang="sr">ОДГ шаблон</comment>
- <comment xml:lang="sq">Model ODG</comment>
+ <comment xml:lang="sq">gjedhe ODG</comment>
<comment xml:lang="sl">Predloga dokumenta ODG</comment>
+ <comment xml:lang="si">ODG අච්චුව</comment>
<comment xml:lang="sk">Šablóna ODG</comment>
<comment xml:lang="ru">Шаблон ODG</comment>
<comment xml:lang="ro">Șablon ODG</comment>
@@ -6057,6 +6096,7 @@ command to generate the output files.
<comment xml:lang="ka">ODG-ის შაბლონი</comment>
<comment xml:lang="ja">ODG テンプレート</comment>
<comment xml:lang="it">Modello ODG</comment>
+ <comment xml:lang="is">ODG sniðmát</comment>
<comment xml:lang="id">Templat ODG</comment>
<comment xml:lang="ia">Patrono ODG</comment>
<comment xml:lang="hu">ODG-sablon</comment>
@@ -6079,6 +6119,7 @@ command to generate the output files.
<comment xml:lang="ca">plantilla ODG</comment>
<comment xml:lang="bg">Шаблон за чертежи — ODG</comment>
<comment xml:lang="be@latin">Šablon ODG</comment>
+ <comment xml:lang="be">шаблон ODG</comment>
<comment xml:lang="ar">قالب ODG</comment>
<comment xml:lang="af">ODG-sjabloon</comment>
<acronym>ODG</acronym>
@@ -6103,8 +6144,9 @@ command to generate the output files.
<comment xml:lang="tr">ODP sunumu</comment>
<comment xml:lang="sv">ODP-presentation</comment>
<comment xml:lang="sr">ОДП презентација</comment>
- <comment xml:lang="sq">Prezantim ODP</comment>
+ <comment xml:lang="sq">paraqitje ODP</comment>
<comment xml:lang="sl">Predstavitev ODP</comment>
+ <comment xml:lang="si">ODP ඉදිරිපත් කිරීම</comment>
<comment xml:lang="sk">Prezentácia ODP</comment>
<comment xml:lang="ru">Презентация ODP</comment>
<comment xml:lang="ro">Prezentare ODP</comment>
@@ -6122,6 +6164,7 @@ command to generate the output files.
<comment xml:lang="ka">ODP პრეზენტაცია</comment>
<comment xml:lang="ja">ODP プレゼンテーション</comment>
<comment xml:lang="it">Presentazione ODP</comment>
+ <comment xml:lang="is">ODP kynning</comment>
<comment xml:lang="id">Presentasi ODP</comment>
<comment xml:lang="ia">Presentation ODP</comment>
<comment xml:lang="hu">ODP-prezentáció</comment>
@@ -6144,6 +6187,7 @@ command to generate the output files.
<comment xml:lang="ca">presentació ODP</comment>
<comment xml:lang="bg">Презентация — ODP</comment>
<comment xml:lang="be@latin">Prezentacyja ODP</comment>
+ <comment xml:lang="be">прэзентацыя ODP</comment>
<comment xml:lang="ar">عرض تقديمي ODP</comment>
<comment xml:lang="af">ODP-voorlegging</comment>
<acronym>ODP</acronym>
@@ -6167,7 +6211,9 @@ command to generate the output files.
<comment xml:lang="tr">ODP sunumu (Düz XML)</comment>
<comment xml:lang="sv">ODP-presentation (platt XML)</comment>
<comment xml:lang="sr">ОДП презентација (Обични ИксМЛ)</comment>
+ <comment xml:lang="sq">paraqitje ODF (Flat XML)</comment>
<comment xml:lang="sl">Predstavitev ODP (nepovezan XML)</comment>
+ <comment xml:lang="si">ODP ඉදිරිපත් කිරීම (පැතලි XML)</comment>
<comment xml:lang="sk">Prezentácia ODP (čisté XML)</comment>
<comment xml:lang="ru">Презентация ODP (простой XML)</comment>
<comment xml:lang="ro">Prezentare ODP (XML simplu)</comment>
@@ -6183,6 +6229,7 @@ command to generate the output files.
<comment xml:lang="ka">ODP პრეზენტაცია (Flat XML)</comment>
<comment xml:lang="ja">ODP プレゼンテーション (Flat XML)</comment>
<comment xml:lang="it">Presentazione ODP (XML semplice)</comment>
+ <comment xml:lang="is">ODP glærukynning (flatt XML)</comment>
<comment xml:lang="id">Presentasi ODP (Flat XML)</comment>
<comment xml:lang="ia">Presentation ODP (XML platte)</comment>
<comment xml:lang="hu">ODP-prezentáció (egyszerű XML)</comment>
@@ -6198,11 +6245,12 @@ command to generate the output files.
<comment xml:lang="es">presentación ODP (XML plano)</comment>
<comment xml:lang="en_GB">ODP presentation (Flat XML)</comment>
<comment xml:lang="el">Παρουσίαση ODP (Flat XML)</comment>
- <comment xml:lang="de">ODP-Präsentation (Unkomprimiertes XML)</comment>
+ <comment xml:lang="de">ODP-Präsentation (einfaches XML)</comment>
<comment xml:lang="da">ODP-præsentation (flad XML)</comment>
<comment xml:lang="cs">prezentace ODP (Flat XML)</comment>
<comment xml:lang="ca">presentació ODP (XML pla)</comment>
<comment xml:lang="bg">Презентация — ODP (само XML)</comment>
+ <comment xml:lang="be">прэзентацыя ODP (плоскі XML)</comment>
<comment xml:lang="ar">عرض ODP (Flat XML)</comment>
<comment xml:lang="af">ODP-voorlegging (plat XML)</comment>
<acronym>FODP</acronym>
@@ -6220,8 +6268,9 @@ command to generate the output files.
<comment xml:lang="tr">ODP şablonu</comment>
<comment xml:lang="sv">ODP-mall</comment>
<comment xml:lang="sr">ОДП шаблон</comment>
- <comment xml:lang="sq">Model ODP</comment>
+ <comment xml:lang="sq">gjedhe ODP</comment>
<comment xml:lang="sl">Predloga dokumenta ODP</comment>
+ <comment xml:lang="si">ODP අච්චුව</comment>
<comment xml:lang="sk">Šablóna ODP</comment>
<comment xml:lang="ru">Шаблон ODP</comment>
<comment xml:lang="ro">Șablon ODP</comment>
@@ -6239,6 +6288,7 @@ command to generate the output files.
<comment xml:lang="ka">ODP შაბლონი</comment>
<comment xml:lang="ja">ODP テンプレート</comment>
<comment xml:lang="it">Modello ODP</comment>
+ <comment xml:lang="is">ODP sniðmát</comment>
<comment xml:lang="id">Templat ODP</comment>
<comment xml:lang="ia">Patrono ODP</comment>
<comment xml:lang="hu">ODP-sablon</comment>
@@ -6261,6 +6311,7 @@ command to generate the output files.
<comment xml:lang="ca">plantilla ODP</comment>
<comment xml:lang="bg">Шаблон за презентации — ODP</comment>
<comment xml:lang="be@latin">Šablon ODP</comment>
+ <comment xml:lang="be">шаблон ODP</comment>
<comment xml:lang="ar">قالب ODP</comment>
<comment xml:lang="af">ODP-sjabloon</comment>
<acronym>ODP</acronym>
@@ -6281,12 +6332,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">ODS 試算表</comment>
<comment xml:lang="zh_CN">ODS 电子表格</comment>
<comment xml:lang="vi">Bảng tính ODS</comment>
- <comment xml:lang="uk">ел. таблиця ODS</comment>
+ <comment xml:lang="uk">електронна таблиця ODS</comment>
<comment xml:lang="tr">ODS hesap çizelgesi</comment>
<comment xml:lang="sv">ODS-kalkylblad</comment>
<comment xml:lang="sr">ОДС табела</comment>
- <comment xml:lang="sq">Fletë llogaritjesh ODS</comment>
+ <comment xml:lang="sq">fletëllogaritje ODS</comment>
<comment xml:lang="sl">Preglednica ODS</comment>
+ <comment xml:lang="si">ODS පැතුරුම්පත</comment>
<comment xml:lang="sk">Zošit ODS</comment>
<comment xml:lang="ru">Электронная таблица ODS</comment>
<comment xml:lang="ro">Foaie de calcul ODS</comment>
@@ -6304,6 +6356,7 @@ command to generate the output files.
<comment xml:lang="ka">ODS ცხრილი</comment>
<comment xml:lang="ja">ODS スプレッドシート</comment>
<comment xml:lang="it">Foglio di calcolo ODS</comment>
+ <comment xml:lang="is">ODS töflureikniskjal</comment>
<comment xml:lang="id">Lembar sebar ODS</comment>
<comment xml:lang="ia">Folio de calculo ODS</comment>
<comment xml:lang="hu">ODS-táblázat</comment>
@@ -6326,6 +6379,7 @@ command to generate the output files.
<comment xml:lang="ca">full de càlcul ODS</comment>
<comment xml:lang="bg">Таблица — ODS</comment>
<comment xml:lang="be@latin">Raźlikovy arkuš ODS</comment>
+ <comment xml:lang="be">электронная табліца ODS</comment>
<comment xml:lang="ar">جدول ODS</comment>
<comment xml:lang="af">ODS-sigblad</comment>
<acronym>ODS</acronym>
@@ -6345,11 +6399,13 @@ command to generate the output files.
<comment>ODS spreadsheet (Flat XML)</comment>
<comment xml:lang="zh_TW">ODS 試算表 (Flat XML)</comment>
<comment xml:lang="zh_CN">ODS 电子表格 (Flat XML)</comment>
- <comment xml:lang="uk">ел. таблиця ODS (Flat XML)</comment>
+ <comment xml:lang="uk">електронна таблиця ODS (Flat XML)</comment>
<comment xml:lang="tr">ODS hesap çizelgesi (Düz XML)</comment>
<comment xml:lang="sv">ODS-kalkylblad (platt XML)</comment>
<comment xml:lang="sr">ОДС табела (обични ИксМЛ)</comment>
+ <comment xml:lang="sq">fletëllogaritje ODF (Flat XML)</comment>
<comment xml:lang="sl">Preglednica ODS (nepovezan XML)</comment>
+ <comment xml:lang="si">ODS පැතුරුම්පත (පැතලි XML)</comment>
<comment xml:lang="sk">Zošit ODS (čisté XML)</comment>
<comment xml:lang="ru">Электронная таблица ODS (простой XML)</comment>
<comment xml:lang="ro">Foaie de calcul ODS (XML simplu)</comment>
@@ -6365,6 +6421,7 @@ command to generate the output files.
<comment xml:lang="ka">ODS ცხრილი (Flat XML)</comment>
<comment xml:lang="ja">ODS スプレッドシート (Flat XML)</comment>
<comment xml:lang="it">Foglio di calcolo ODS (XML semplice)</comment>
+ <comment xml:lang="is">ODS töflureikniskjal (flatt XML)</comment>
<comment xml:lang="id">Lembar sebar ODS (Flat XML)</comment>
<comment xml:lang="ia">Folio de calculo ODS (XML platte)</comment>
<comment xml:lang="hu">ODS-táblázat (egyszerű XML)</comment>
@@ -6380,11 +6437,12 @@ command to generate the output files.
<comment xml:lang="es">hoja de cálculo ODS (XML plano)</comment>
<comment xml:lang="en_GB">ODS spreadsheet (Flat XML)</comment>
<comment xml:lang="el">Λογιστικό φύλλο ODS (Flat XML)</comment>
- <comment xml:lang="de">ODS-Tabelle (Unkomprimiertes XML)</comment>
+ <comment xml:lang="de">ODS-Tabelle (einfaches XML)</comment>
<comment xml:lang="da">ODS-regneark (flad XML)</comment>
<comment xml:lang="cs">sešit ODS (Flat XML)</comment>
<comment xml:lang="ca">full de càlcul ODS (XML pla)</comment>
<comment xml:lang="bg">Таблица — ODS (само XML)</comment>
+ <comment xml:lang="be">электронная табліца ODS (плоскі XML)</comment>
<comment xml:lang="ar">جدول ODS (Flat XML)</comment>
<comment xml:lang="af">ODS-sigblad (plat XML)</comment>
<acronym>FODS</acronym>
@@ -6402,8 +6460,9 @@ command to generate the output files.
<comment xml:lang="tr">ODS şablonu</comment>
<comment xml:lang="sv">ODS-mall</comment>
<comment xml:lang="sr">ОДС шаблон</comment>
- <comment xml:lang="sq">Model ODS</comment>
+ <comment xml:lang="sq">gjedhe ODS</comment>
<comment xml:lang="sl">Predloga dokumenta ODS</comment>
+ <comment xml:lang="si">ODS ආකෘතිය</comment>
<comment xml:lang="sk">Šablóna ODS</comment>
<comment xml:lang="ru">Шаблон ODS</comment>
<comment xml:lang="ro">Șablon ODS</comment>
@@ -6421,6 +6480,7 @@ command to generate the output files.
<comment xml:lang="ka">ODS-ის შაბლონი</comment>
<comment xml:lang="ja">ODS テンプレート</comment>
<comment xml:lang="it">Modello ODS</comment>
+ <comment xml:lang="is">ODS sniðmát</comment>
<comment xml:lang="id">Templat ODS</comment>
<comment xml:lang="ia">Patrono ODS</comment>
<comment xml:lang="hu">ODS-sablon</comment>
@@ -6443,6 +6503,7 @@ command to generate the output files.
<comment xml:lang="ca">plantilla ODS</comment>
<comment xml:lang="bg">Шаблон за таблици — ODS</comment>
<comment xml:lang="be@latin">Šablon ODS</comment>
+ <comment xml:lang="be">шаблон ODS</comment>
<comment xml:lang="ar">قالب ODS</comment>
<comment xml:lang="af">ODS-sjabloon</comment>
<acronym>ODS</acronym>
@@ -6467,8 +6528,9 @@ command to generate the output files.
<comment xml:lang="tr">ODC çizgesi</comment>
<comment xml:lang="sv">ODC-diagram</comment>
<comment xml:lang="sr">ОДЦ график</comment>
- <comment xml:lang="sq">Grafik ODC</comment>
+ <comment xml:lang="sq">grafik ODC</comment>
<comment xml:lang="sl">Datoteka grafikona ODC</comment>
+ <comment xml:lang="si">ODC ප්‍රස්ථාරය</comment>
<comment xml:lang="sk">Graf ODC</comment>
<comment xml:lang="ru">Диаграмма ODC</comment>
<comment xml:lang="ro">Diagramă ODC</comment>
@@ -6485,6 +6547,7 @@ command to generate the output files.
<comment xml:lang="kk">ODC диаграммасы</comment>
<comment xml:lang="ja">ODC チャート</comment>
<comment xml:lang="it">Grafico ODC</comment>
+ <comment xml:lang="is">ODC graf</comment>
<comment xml:lang="id">Bagan ODC</comment>
<comment xml:lang="ia">Graphico ODC</comment>
<comment xml:lang="hu">ODC-táblázat</comment>
@@ -6507,6 +6570,7 @@ command to generate the output files.
<comment xml:lang="ca">diagrama ODC</comment>
<comment xml:lang="bg">Диаграма — ODC</comment>
<comment xml:lang="be@latin">Dyjahrama ODC</comment>
+ <comment xml:lang="be">дыяграма ODC</comment>
<comment xml:lang="ar">مخطط ODC</comment>
<comment xml:lang="af">ODC-grafiek</comment>
<acronym>ODC</acronym>
@@ -6531,7 +6595,9 @@ command to generate the output files.
<comment xml:lang="tr">ODC şablonu</comment>
<comment xml:lang="sv">ODC-mall</comment>
<comment xml:lang="sr">ОДЦ шаблон</comment>
+ <comment xml:lang="sq">gjedhe ODC</comment>
<comment xml:lang="sl">Predloga ODC</comment>
+ <comment xml:lang="si">ODC අච්චුව</comment>
<comment xml:lang="sk">Šablóna ODC</comment>
<comment xml:lang="ru">Шаблон ODC</comment>
<comment xml:lang="ro">Șablon ODC</comment>
@@ -6547,6 +6613,7 @@ command to generate the output files.
<comment xml:lang="ka">ODC შაბლონი</comment>
<comment xml:lang="ja">ODC テンプレート</comment>
<comment xml:lang="it">Modello ODC</comment>
+ <comment xml:lang="is">ODC sniðmát</comment>
<comment xml:lang="id">Templat ODC</comment>
<comment xml:lang="ia">Patrono ODC</comment>
<comment xml:lang="hu">ODC-sablon</comment>
@@ -6568,6 +6635,7 @@ command to generate the output files.
<comment xml:lang="cs">šablona ODC</comment>
<comment xml:lang="ca">plantilla ODC</comment>
<comment xml:lang="bg">Шаблон за диаграми — ODC</comment>
+ <comment xml:lang="be">шаблон ODC</comment>
<comment xml:lang="ar">قالب ODC</comment>
<comment xml:lang="af">ODC-sjabloon</comment>
<acronym>ODC</acronym>
@@ -6592,8 +6660,9 @@ command to generate the output files.
<comment xml:lang="tr">ODF formülü</comment>
<comment xml:lang="sv">ODF-formel</comment>
<comment xml:lang="sr">ОДФ формула</comment>
- <comment xml:lang="sq">Formulë ODF</comment>
+ <comment xml:lang="sq">formulë ODF</comment>
<comment xml:lang="sl">Dokument formule ODF</comment>
+ <comment xml:lang="si">ODF සූත්‍රය</comment>
<comment xml:lang="sk">Vzorec ODF</comment>
<comment xml:lang="ru">Формула ODF</comment>
<comment xml:lang="ro">Formulă ODF</comment>
@@ -6611,6 +6680,7 @@ command to generate the output files.
<comment xml:lang="ka">ODF-ის ფორმულა</comment>
<comment xml:lang="ja">ODF 計算式</comment>
<comment xml:lang="it">Formula ODF</comment>
+ <comment xml:lang="is">ODF formúla</comment>
<comment xml:lang="id">Formula ODF</comment>
<comment xml:lang="ia">Formula ODF</comment>
<comment xml:lang="hu">ODF-képlet</comment>
@@ -6633,6 +6703,7 @@ command to generate the output files.
<comment xml:lang="ca">fórmula ODF</comment>
<comment xml:lang="bg">Формула — ODF</comment>
<comment xml:lang="be@latin">Formuła ODF</comment>
+ <comment xml:lang="be">формула ODF</comment>
<comment xml:lang="ar">صيغة ODF</comment>
<comment xml:lang="af">ODF-formule</comment>
<acronym>ODF</acronym>
@@ -6657,7 +6728,9 @@ command to generate the output files.
<comment xml:lang="tr">ODF şablonu</comment>
<comment xml:lang="sv">ODF-mall</comment>
<comment xml:lang="sr">ОДФ шаблон</comment>
+ <comment xml:lang="sq">gjedhe ODF</comment>
<comment xml:lang="sl">Predloga dokumenta ODF</comment>
+ <comment xml:lang="si">ODF ආකෘතිය</comment>
<comment xml:lang="sk">Šablóna ODF</comment>
<comment xml:lang="ru">Шаблон ODF</comment>
<comment xml:lang="ro">Șablon ODF</comment>
@@ -6673,6 +6746,7 @@ command to generate the output files.
<comment xml:lang="ka">ODF-ის შაბლონი</comment>
<comment xml:lang="ja">ODF テンプレート</comment>
<comment xml:lang="it">Modello ODF</comment>
+ <comment xml:lang="is">ODF sniðmát</comment>
<comment xml:lang="id">Templat ODF</comment>
<comment xml:lang="ia">Patrono ODF</comment>
<comment xml:lang="hu">ODG-sablon</comment>
@@ -6694,6 +6768,7 @@ command to generate the output files.
<comment xml:lang="cs">šablona ODF</comment>
<comment xml:lang="ca">plantilla ODF</comment>
<comment xml:lang="bg">Шаблон за формули — ODF</comment>
+ <comment xml:lang="be">шаблон ODF</comment>
<comment xml:lang="ar">قالب ODF</comment>
<comment xml:lang="af">ODF-sjabloon</comment>
<acronym>ODF</acronym>
@@ -6718,8 +6793,9 @@ command to generate the output files.
<comment xml:lang="tr">ODB veri tabanı</comment>
<comment xml:lang="sv">ODB-databas</comment>
<comment xml:lang="sr">ОДБ база података</comment>
- <comment xml:lang="sq">Bazë me të dhëna ODB</comment>
+ <comment xml:lang="sq">bazë të dhënash ODB</comment>
<comment xml:lang="sl">Podatkovna zbirka ODB</comment>
+ <comment xml:lang="si">ODB දත්ත සමුදාය</comment>
<comment xml:lang="sk">Databáza ODB</comment>
<comment xml:lang="ru">База данных ODB</comment>
<comment xml:lang="ro">Bază de date ODB</comment>
@@ -6737,6 +6813,7 @@ command to generate the output files.
<comment xml:lang="ka">ODB-ის მონაცემთა ბაზა</comment>
<comment xml:lang="ja">ODB データベース</comment>
<comment xml:lang="it">Database ODB</comment>
+ <comment xml:lang="is">ODB gagnagrunnur</comment>
<comment xml:lang="id">Basis data ODB</comment>
<comment xml:lang="ia">Base de datos ODB</comment>
<comment xml:lang="hu">ODB-adatbázis</comment>
@@ -6759,6 +6836,7 @@ command to generate the output files.
<comment xml:lang="ca">base de dades ODB</comment>
<comment xml:lang="bg">База от данни — ODB</comment>
<comment xml:lang="be@latin">Baza źviestak ODB</comment>
+ <comment xml:lang="be">база даных ODB</comment>
<comment xml:lang="ar">قاعدة بيانات ODB</comment>
<comment xml:lang="af">ODB-databasis</comment>
<acronym>ODB</acronym>
@@ -6784,8 +6862,9 @@ command to generate the output files.
<comment xml:lang="tr">ODI görüntüsü</comment>
<comment xml:lang="sv">ODI-bild</comment>
<comment xml:lang="sr">ОДИ слика</comment>
- <comment xml:lang="sq">Figurë ODI</comment>
+ <comment xml:lang="sq">figurë ODI</comment>
<comment xml:lang="sl">Slikovna datoteka ODI</comment>
+ <comment xml:lang="si">ODI රූපය</comment>
<comment xml:lang="sk">Obrázok ODI</comment>
<comment xml:lang="ru">Изображение ODI</comment>
<comment xml:lang="ro">Imagine ODI</comment>
@@ -6803,6 +6882,7 @@ command to generate the output files.
<comment xml:lang="ka">ODI გამოსახულება</comment>
<comment xml:lang="ja">ODI 画像</comment>
<comment xml:lang="it">Immagine ODI</comment>
+ <comment xml:lang="is">ODI mynd</comment>
<comment xml:lang="id">Citra ODI</comment>
<comment xml:lang="ia">Imagine ODI</comment>
<comment xml:lang="hu">ODI-kép</comment>
@@ -6825,6 +6905,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge ODI</comment>
<comment xml:lang="bg">Изображение — ODI</comment>
<comment xml:lang="be@latin">Vyjava ODI</comment>
+ <comment xml:lang="be">выява ODI</comment>
<comment xml:lang="ast">Imaxe ODI</comment>
<comment xml:lang="ar">صورة ODI</comment>
<comment xml:lang="af">ODI-beeld</comment>
@@ -6850,8 +6931,9 @@ command to generate the output files.
<comment xml:lang="tr">OpenOffice.org eklentisi</comment>
<comment xml:lang="sv">OpenOffice.org-tillägg</comment>
<comment xml:lang="sr">проширење ОпенОфис.орг-а</comment>
- <comment xml:lang="sq">Shtojcë për OpenOffice.org</comment>
+ <comment xml:lang="sq">zgjerim OpenOffice.org</comment>
<comment xml:lang="sl">Razširitev OpenOffice.org</comment>
+ <comment xml:lang="si">OpenOffice.org දිගුව</comment>
<comment xml:lang="sk">Rozšírenie OpenOffice.org</comment>
<comment xml:lang="ru">Расширение OpenOffice.org</comment>
<comment xml:lang="ro">Extensie OpenOffice.org</comment>
@@ -6868,6 +6950,7 @@ command to generate the output files.
<comment xml:lang="ka">OpenOffice.org-ის გაფართოება</comment>
<comment xml:lang="ja">OpenOffice.org 拡張機能</comment>
<comment xml:lang="it">Estensione OpenOffice.org</comment>
+ <comment xml:lang="is">OpenOffice.org viðauki</comment>
<comment xml:lang="id">Ekstensi OpenOffice.org</comment>
<comment xml:lang="ia">Extension OpenOffice.org</comment>
<comment xml:lang="hu">OpenOffice.org kiterjesztés</comment>
@@ -6889,6 +6972,7 @@ command to generate the output files.
<comment xml:lang="ca">extensió d'OpenOffice.org</comment>
<comment xml:lang="bg">Приставка — OpenOffice</comment>
<comment xml:lang="be@latin">Pašyreńnie OpenOffice.org</comment>
+ <comment xml:lang="be">пашырэнне OpenOffice.org</comment>
<comment xml:lang="ast">Estensión d'OpenOffice.org</comment>
<comment xml:lang="ar">امتداد OpenOffice.org</comment>
<comment xml:lang="af">OpenOffice.org-uitbreiding</comment>
@@ -6904,14 +6988,16 @@ command to generate the output files.
<comment xml:lang="tr">Android paketi</comment>
<comment xml:lang="sv">Android-paket</comment>
<comment xml:lang="sr">Андроидов пакет</comment>
+ <comment xml:lang="sq">pakete Android</comment>
<comment xml:lang="sl">Paket Android</comment>
+ <comment xml:lang="si">Android පැකේජය</comment>
<comment xml:lang="sk">Balík Android</comment>
<comment xml:lang="ru">Пакет Android</comment>
<comment xml:lang="pt_BR">Pacote do Android</comment>
<comment xml:lang="pt">pacote Android</comment>
<comment xml:lang="pl">Pakiet Androida</comment>
<comment xml:lang="oc">paquet Android</comment>
- <comment xml:lang="nl">Android pakket</comment>
+ <comment xml:lang="nl">Android-pakket</comment>
<comment xml:lang="lv">Android pakotne</comment>
<comment xml:lang="lt">Android paketas</comment>
<comment xml:lang="ko">Android 패키지</comment>
@@ -6919,6 +7005,7 @@ command to generate the output files.
<comment xml:lang="ka">Android-ის პაკეტი</comment>
<comment xml:lang="ja">Android パッケージ</comment>
<comment xml:lang="it">Pacchetto Android</comment>
+ <comment xml:lang="is">Android pakki</comment>
<comment xml:lang="id">Paket Android</comment>
<comment xml:lang="ia">Pacchetto Android</comment>
<comment xml:lang="hu">Android csomag</comment>
@@ -6939,10 +7026,11 @@ command to generate the output files.
<comment xml:lang="cs">balíčky systému Android</comment>
<comment xml:lang="ca">paquet d'Android</comment>
<comment xml:lang="bg">Пакет — Android</comment>
+ <comment xml:lang="be">пакет Android</comment>
<comment xml:lang="ast">Paquete d'Android</comment>
<comment xml:lang="ar">حزمة أندرويد</comment>
<comment xml:lang="af">Android-pakket</comment>
- <sub-class-of type="application/x-java-archive"/>
+ <sub-class-of type="application/java-archive"/>
<glob pattern="*.apk"/>
</mime-type>
<mime-type type="application/vnd.symbian.install">
@@ -6954,8 +7042,9 @@ command to generate the output files.
<comment xml:lang="tr">SIS paketi</comment>
<comment xml:lang="sv">SIS-paket</comment>
<comment xml:lang="sr">СИС пакет</comment>
- <comment xml:lang="sq">Paketë SIS</comment>
+ <comment xml:lang="sq">paketë SIS</comment>
<comment xml:lang="sl">Datoteka paketa SIS</comment>
+ <comment xml:lang="si">SIS පැකේජය</comment>
<comment xml:lang="sk">Balíček SIS</comment>
<comment xml:lang="ru">Пакет SIS</comment>
<comment xml:lang="ro">Pachet SIS</comment>
@@ -6972,6 +7061,7 @@ command to generate the output files.
<comment xml:lang="kk">SIS дестесі</comment>
<comment xml:lang="ja">SIS パッケージ</comment>
<comment xml:lang="it">Pacchetto SIS</comment>
+ <comment xml:lang="is">SIS pakki</comment>
<comment xml:lang="id">Paket SIS</comment>
<comment xml:lang="ia">Pacchetto SIS</comment>
<comment xml:lang="hu">SIS csomag</comment>
@@ -6994,6 +7084,7 @@ command to generate the output files.
<comment xml:lang="ca">paquet SIS</comment>
<comment xml:lang="bg">Пакет — SIS</comment>
<comment xml:lang="be@latin">Pakunak SIS</comment>
+ <comment xml:lang="be">пакет SIS</comment>
<comment xml:lang="ast">Paquete SIS</comment>
<comment xml:lang="ar">حزمة SIS</comment>
<comment xml:lang="af">SIS-pakket</comment>
@@ -7014,8 +7105,9 @@ command to generate the output files.
<comment xml:lang="tr">SISX paketi</comment>
<comment xml:lang="sv">SISX-paket</comment>
<comment xml:lang="sr">СИСИкс пакет</comment>
- <comment xml:lang="sq">Paketë SISX</comment>
+ <comment xml:lang="sq">paketë SISX</comment>
<comment xml:lang="sl">Datoteka paketa SISX</comment>
+ <comment xml:lang="si">SISX පැකේජය</comment>
<comment xml:lang="sk">Balíček SISX</comment>
<comment xml:lang="ru">Пакет SISX</comment>
<comment xml:lang="ro">Pachet SISX</comment>
@@ -7032,6 +7124,7 @@ command to generate the output files.
<comment xml:lang="kk">SISX дестесі</comment>
<comment xml:lang="ja">SISX パッケージ</comment>
<comment xml:lang="it">Pacchetto SISX</comment>
+ <comment xml:lang="is">SISX pakki</comment>
<comment xml:lang="id">Paket SISX</comment>
<comment xml:lang="ia">Pacchetto SISX</comment>
<comment xml:lang="hu">SISX csomag</comment>
@@ -7054,6 +7147,7 @@ command to generate the output files.
<comment xml:lang="ca">paquet SISX</comment>
<comment xml:lang="bg">Пакет — SISX</comment>
<comment xml:lang="be@latin">Pakunak SISX</comment>
+ <comment xml:lang="be">пакет SISX</comment>
<comment xml:lang="ast">Paquete SISX</comment>
<comment xml:lang="ar">حزمة SISX</comment>
<comment xml:lang="af">SISX-pakket</comment>
@@ -7066,33 +7160,17 @@ command to generate the output files.
<glob pattern="*.sisx"/>
</mime-type>
<mime-type type="application/vnd.tcpdump.pcap">
- <comment>network packet capture</comment>
- <comment xml:lang="zh_CN">网络数据包抓取</comment>
- <comment xml:lang="uk">перехоплення мережевого пакета</comment>
- <comment xml:lang="tr">ağ paket yakalaması</comment>
- <comment xml:lang="sv">nätverkspaketsspårning</comment>
- <comment xml:lang="ru">захваченные сетевые пакеты</comment>
+ <comment>Network packet capture</comment>
+ <comment xml:lang="uk">перехоплення пакетів мережі</comment>
+ <comment xml:lang="sv">Nätverkspaketsspårning</comment>
+ <comment xml:lang="ru">Захваченные сетевые пакеты</comment>
<comment xml:lang="pt_BR">Captura de pacotes de rede</comment>
- <comment xml:lang="pt">captura dos pacotes de rede</comment>
<comment xml:lang="pl">Przechwycenie pakietu sieciowego</comment>
- <comment xml:lang="ko">네트워크 패킷 캡처</comment>
- <comment xml:lang="kk">ұсталған желілік пакеттер</comment>
- <comment xml:lang="ja">ネットワークパケットキャプチャー</comment>
- <comment xml:lang="it">Cattura pacchetti rete</comment>
- <comment xml:lang="id">tangkapan paket jaringan</comment>
- <comment xml:lang="hu">hálózaticsomag-rögzítés</comment>
- <comment xml:lang="hr">Mrežno hvatanje paketa</comment>
- <comment xml:lang="he">לכידת מנות מהרשת</comment>
- <comment xml:lang="fr">capture de paquet réseau</comment>
- <comment xml:lang="fi">verkkopakettien kaappaus</comment>
- <comment xml:lang="eu">sareko pakete kaptura</comment>
+ <comment xml:lang="it">Cattura pacchetti di rete</comment>
+ <comment xml:lang="gl">Captura de paquetes de red</comment>
<comment xml:lang="es">captura de paquetes de red</comment>
- <comment xml:lang="en_GB">network packet capture</comment>
- <comment xml:lang="de">Netzwerkpaketmitschnitt</comment>
- <comment xml:lang="da">Netværkspakkeoptagelse</comment>
- <comment xml:lang="ca">captura de paquets de xarxa</comment>
- <comment xml:lang="bg">Прихванати мрежови пакети</comment>
- <comment xml:lang="ar">التقاطة حزمة شبكة</comment>
+ <comment xml:lang="de">Netzwerkpaket-Aufzeichnung</comment>
+ <comment xml:lang="be">захопленыя сеткавыя пакеты</comment>
<magic>
<match type="host32" value="0xa1b2c3d4" offset="0"/>
<match type="host32" value="0xd4c3b2a1" offset="0"/>
@@ -7112,8 +7190,9 @@ command to generate the output files.
<comment xml:lang="tr">WordPerfect belgesi</comment>
<comment xml:lang="sv">WordPerfect-dokument</comment>
<comment xml:lang="sr">документ Ворд перфекта</comment>
- <comment xml:lang="sq">Dokument WordPerfect</comment>
+ <comment xml:lang="sq">dokument WordPerfect</comment>
<comment xml:lang="sl">Dokument WordPerfect</comment>
+ <comment xml:lang="si">WordPerfect ලේඛනය</comment>
<comment xml:lang="sk">Dokument WordPerfect</comment>
<comment xml:lang="ru">Документ WordPerfect</comment>
<comment xml:lang="ro">Document WordPerfect</comment>
@@ -7129,8 +7208,10 @@ command to generate the output files.
<comment xml:lang="lt">WordPerfect dokumentas</comment>
<comment xml:lang="ko">WordPerfect 문서</comment>
<comment xml:lang="kk">WordPerfect құжаты</comment>
+ <comment xml:lang="ka">WordPerfect -ის დოკუმენტი</comment>
<comment xml:lang="ja">WordPerfect ドキュメント</comment>
<comment xml:lang="it">Documento WordPerfect</comment>
+ <comment xml:lang="is">WordPerfect skjal</comment>
<comment xml:lang="id">Dokumen WordPerfect</comment>
<comment xml:lang="ia">Documento WordPerfect</comment>
<comment xml:lang="hu">WordPerfect-dokumentum</comment>
@@ -7154,6 +7235,7 @@ command to generate the output files.
<comment xml:lang="ca">document WordPerfect</comment>
<comment xml:lang="bg">Документ — WordPerfect</comment>
<comment xml:lang="be@latin">Dakument WordPerfect</comment>
+ <comment xml:lang="be">дакумент WordPerfect</comment>
<comment xml:lang="az">WordPerfect sənədi</comment>
<comment xml:lang="ast">Documentu de WordPerfect</comment>
<comment xml:lang="ar">مستند WordPerfect</comment>
@@ -7172,25 +7254,32 @@ command to generate the output files.
<glob pattern="*.wpd"/>
<glob pattern="*.wpp"/>
</mime-type>
- <mime-type type="application/vnd.youtube.yt">
+ <mime-type type="video/vnd.youtube.yt">
<comment>YouTube media archive</comment>
<comment xml:lang="zh_CN">YouTube 媒体存档</comment>
<comment xml:lang="uk">мультимедійний архів YouTube</comment>
<comment xml:lang="tr">YouTube ortam arşivi</comment>
<comment xml:lang="sv">YouTube-mediaarkiv</comment>
+ <comment xml:lang="sq">arkiv media YouTube</comment>
+ <comment xml:lang="sl">Medijski arhiv YouTube</comment>
+ <comment xml:lang="si">YouTube මාධ්‍ය සංරක්ෂිතය</comment>
<comment xml:lang="sk">Archív médií YouTube</comment>
<comment xml:lang="ru">Медиа-архив YouTube</comment>
<comment xml:lang="pt_BR">Arquivo de mídia do Youtube</comment>
<comment xml:lang="pt">arquivo multimédia do YouTube</comment>
<comment xml:lang="pl">Archiwum multimediów YouTube</comment>
+ <comment xml:lang="oc">archiu mèdia YouTube</comment>
+ <comment xml:lang="nl">YouTube-media-archief</comment>
<comment xml:lang="ko">유튜브 미디어 저장 파일</comment>
<comment xml:lang="kk">YouTube медиа архиві</comment>
<comment xml:lang="ja">YouTube メディアアーカイブ</comment>
<comment xml:lang="it">Archivio multimediale YouTube</comment>
+ <comment xml:lang="is">YouTube margmiðlunarsafnskrá</comment>
<comment xml:lang="id">Arsip media YouTube</comment>
<comment xml:lang="hu">YouTube médiaarchívum</comment>
<comment xml:lang="hr">YouTube medijska arhiva</comment>
<comment xml:lang="he">ארכיון מדיה של YouTube</comment>
+ <comment xml:lang="gl">Arquivo multimedia de Youtube</comment>
<comment xml:lang="fr">archive média YouTube</comment>
<comment xml:lang="fi">YouTube-media-arkisto</comment>
<comment xml:lang="eu">YouTube media fitxategia</comment>
@@ -7200,8 +7289,13 @@ command to generate the output files.
<comment xml:lang="da">YouTube-mediearkiv</comment>
<comment xml:lang="ca">arxiu de mitjans de YouTube</comment>
<comment xml:lang="bg">Медиен архив — YouTube</comment>
+ <comment xml:lang="be">архіў мультымедыя YouTube</comment>
<comment xml:lang="ar">أرشيف وسائط يوتيوب</comment>
+ <alias type="application/vnd.youtube.yt"/>
<generic-icon name="video-x-generic"/>
+ <magic>
+ <match type="string" value="ftypyt4 " offset="4"/>
+ </magic>
<glob pattern="*.yt"/>
<sub-class-of type="application/zip"/>
</mime-type>
@@ -7212,28 +7306,36 @@ command to generate the output files.
<comment xml:lang="uk">портативний файл даних SPSS</comment>
<comment xml:lang="tr">SPSS taşınabilir veri dosyası</comment>
<comment xml:lang="sv">SPSS portabel datafil</comment>
+ <comment xml:lang="sq">kartelë të dhënash të bartshme SPSS</comment>
+ <comment xml:lang="sl">Prenosna podatkovna datoteka SPSS</comment>
+ <comment xml:lang="si">SPSS අතේ ගෙන යා හැකි දත්ත ගොනුව</comment>
<comment xml:lang="sk">Súbor prenosných údajov SPSS</comment>
<comment xml:lang="ru">Файл переносимых данных SPSS</comment>
<comment xml:lang="pt_BR">Arquivo de dados portáteis SPSS</comment>
<comment xml:lang="pt">ficheiro de dados portátil SPSS</comment>
<comment xml:lang="pl">Plik przenośnych danych SPSS</comment>
+ <comment xml:lang="nl">SPSS-portable-gegevensbestand</comment>
<comment xml:lang="ko">SPSS 휴대 데이터 파일</comment>
<comment xml:lang="kk">SPSS тасымалы деректер файлы</comment>
+ <comment xml:lang="ka">SPSS გადატანადი მონაცემების ფაილი</comment>
<comment xml:lang="ja">SPSS ポータブルデータファイル</comment>
<comment xml:lang="it">File dati SPSS Portable</comment>
+ <comment xml:lang="is">yfirfæranleg SPSS gagnaskrá</comment>
<comment xml:lang="id">Berkas data portabel SPSS</comment>
<comment xml:lang="hu">SPSS hordozható adatfájl</comment>
<comment xml:lang="hr">SPSS prenosiva podatkovna datoteka</comment>
<comment xml:lang="he">קובץ נתונים נייד של SPSS</comment>
+ <comment xml:lang="gl">Ficheiro de datos portábel de SPSS</comment>
<comment xml:lang="fr">fichier portable de données SPSS</comment>
<comment xml:lang="fi">Siirrettävä SPSS-tiedosto</comment>
<comment xml:lang="eu">SPSS datu fitxategi eramangarria</comment>
<comment xml:lang="es">archivo de datos portátiles de SPSS</comment>
<comment xml:lang="en_GB">SPSS portable data file</comment>
- <comment xml:lang="de">SPSS portable Datendatei</comment>
+ <comment xml:lang="de">Portierbare SPSS-Datendatei</comment>
<comment xml:lang="da">SPSS portable data-fil</comment>
<comment xml:lang="ca">fitxer de dades portables SPSS</comment>
<comment xml:lang="bg">Данни — SPSS, преносими</comment>
+ <comment xml:lang="be">файл пераносу даных SPSS</comment>
<comment xml:lang="ar">ملف بيانات SPSS متنقل</comment>
<acronym>SPSS</acronym>
<expanded-acronym>Statistical Package for the Social Sciences</expanded-acronym>
@@ -7249,19 +7351,25 @@ command to generate the output files.
<comment xml:lang="uk">файл даних SPSS</comment>
<comment xml:lang="tr">SPSS veri dosyası</comment>
<comment xml:lang="sv">SPSS-datafil</comment>
+ <comment xml:lang="sq">kartelë të dhënash SPSS</comment>
+ <comment xml:lang="sl">Podatkovna datoteka SPSS</comment>
+ <comment xml:lang="si">SPSS දත්ත ගොනුව</comment>
<comment xml:lang="sk">Súbor údajov SPSS</comment>
<comment xml:lang="ru">Файл данных SPSS</comment>
<comment xml:lang="pt_BR">Arquivo de dados SPSS</comment>
<comment xml:lang="pt">ficheiro de dados SPSS</comment>
<comment xml:lang="pl">Plik danych SPSS</comment>
+ <comment xml:lang="nl">SPSS-gegevensbestand</comment>
<comment xml:lang="ko">SPSS 데이터 파일</comment>
<comment xml:lang="kk">SPSS деректер файлы</comment>
<comment xml:lang="ja">SPSS データファイル</comment>
<comment xml:lang="it">File dati SPSS</comment>
+ <comment xml:lang="is">SPSS gagnaskrá</comment>
<comment xml:lang="id">Berkas data SPSS</comment>
<comment xml:lang="hu">SPSS adatfájl</comment>
<comment xml:lang="hr">SPSS podatkovna datoteka</comment>
<comment xml:lang="he">קובץ נתונים של SPSS</comment>
+ <comment xml:lang="gl">Ficheiro de datos SPSS</comment>
<comment xml:lang="fr">fichier de données SPSS</comment>
<comment xml:lang="fi">SPSS-datatiedosto</comment>
<comment xml:lang="eu">SPSS datu fitxategia</comment>
@@ -7271,6 +7379,7 @@ command to generate the output files.
<comment xml:lang="da">SPSS data-fil</comment>
<comment xml:lang="ca">fitxer de dades SPSS</comment>
<comment xml:lang="bg">Данни — SPSS</comment>
+ <comment xml:lang="be">файл даных SPSS</comment>
<comment xml:lang="ar">ملف بيانات SPSS</comment>
<acronym>SPSS</acronym>
<expanded-acronym>Statistical Package for the Social Sciences</expanded-acronym>
@@ -7291,8 +7400,9 @@ command to generate the output files.
<comment xml:lang="tr">XBEL yer imleri</comment>
<comment xml:lang="sv">XBEL-bokmärken</comment>
<comment xml:lang="sr">ИксБЕЛ обележивачи</comment>
- <comment xml:lang="sq">Libërshënues XBEL</comment>
+ <comment xml:lang="sq">faqerojtës XBEL</comment>
<comment xml:lang="sl">Datoteka zaznamkov XBEL</comment>
+ <comment xml:lang="si">XBEL පිටුසන්</comment>
<comment xml:lang="sk">Záložky XBEL</comment>
<comment xml:lang="ru">Закладки XBEL</comment>
<comment xml:lang="ro">Semne de carte XBEL</comment>
@@ -7310,6 +7420,7 @@ command to generate the output files.
<comment xml:lang="kk">XBEL бетбелгілері</comment>
<comment xml:lang="ja">XBEL ブックマーク</comment>
<comment xml:lang="it">Segnalibri XBEL</comment>
+ <comment xml:lang="is">XBEL bókamerki</comment>
<comment xml:lang="id">Bookmark XBEL</comment>
<comment xml:lang="ia">Marcapaginas XBEL</comment>
<comment xml:lang="hu">XBEL-könyvjelzők</comment>
@@ -7332,6 +7443,7 @@ command to generate the output files.
<comment xml:lang="ca">llista d'adreces d'interès XBEL</comment>
<comment xml:lang="bg">Отметки — XBEL</comment>
<comment xml:lang="be@latin">Zakładki XBEL</comment>
+ <comment xml:lang="be">закладкі XBEL</comment>
<comment xml:lang="ar">علامات XBEL</comment>
<comment xml:lang="af">XBEL-boekmerke</comment>
<acronym>XBEL</acronym>
@@ -7352,8 +7464,9 @@ command to generate the output files.
<comment xml:lang="tr">7-Zip arşivi</comment>
<comment xml:lang="sv">7-zip-arkiv</comment>
<comment xml:lang="sr">7-зип архива</comment>
- <comment xml:lang="sq">Arkiv 7-zip</comment>
+ <comment xml:lang="sq">arkiv 7-zip</comment>
<comment xml:lang="sl">Datoteka arhiva 7-zip</comment>
+ <comment xml:lang="si">7-zip සංරක්ෂිතය</comment>
<comment xml:lang="sk">Archív 7-zip</comment>
<comment xml:lang="ru">Архив 7-zip</comment>
<comment xml:lang="ro">Arhivă 7-zip</comment>
@@ -7371,6 +7484,7 @@ command to generate the output files.
<comment xml:lang="ka">7-zip არქივი</comment>
<comment xml:lang="ja">7-zip アーカイブ</comment>
<comment xml:lang="it">Archivio 7-zip</comment>
+ <comment xml:lang="is">7-zip safnskrá</comment>
<comment xml:lang="id">Arsip 7-zip</comment>
<comment xml:lang="ia">Archivo 7-zip</comment>
<comment xml:lang="hu">7-zip archívum</comment>
@@ -7387,12 +7501,13 @@ command to generate the output files.
<comment xml:lang="eo">7z-arkivo</comment>
<comment xml:lang="en_GB">7-zip archive</comment>
<comment xml:lang="el">Συμπιεσμένο αρχείο 7-zip</comment>
- <comment xml:lang="de">7zip-Archiv</comment>
+ <comment xml:lang="de">7-Zip-Archiv</comment>
<comment xml:lang="da">7-zip-arkiv</comment>
<comment xml:lang="cs">archiv 7-zip</comment>
<comment xml:lang="ca">arxiu 7-zip</comment>
<comment xml:lang="bg">Архив — 7-zip</comment>
<comment xml:lang="be@latin">Archiŭ 7-zip</comment>
+ <comment xml:lang="be">архіў 7-zip</comment>
<comment xml:lang="ast">Archivu 7-zip</comment>
<comment xml:lang="ar">أرشيف 7-zip</comment>
<comment xml:lang="af">7-zip-argief</comment>
@@ -7412,8 +7527,9 @@ command to generate the output files.
<comment xml:lang="tr">AbiWord belgesi</comment>
<comment xml:lang="sv">AbiWord-dokument</comment>
<comment xml:lang="sr">Абиворд документ</comment>
- <comment xml:lang="sq">Dokument AbiWord</comment>
+ <comment xml:lang="sq">dokument AbiWord</comment>
<comment xml:lang="sl">Dokument AbiWord</comment>
+ <comment xml:lang="si">AbiWord ලේඛනය</comment>
<comment xml:lang="sk">Dokument AbiWord</comment>
<comment xml:lang="ru">Документ AbiWord</comment>
<comment xml:lang="ro">Document AbiWord</comment>
@@ -7432,6 +7548,7 @@ command to generate the output files.
<comment xml:lang="ka">AbiWord-ის დოკუმენტი</comment>
<comment xml:lang="ja">AbiWord ドキュメント</comment>
<comment xml:lang="it">Documento AbiWord</comment>
+ <comment xml:lang="is">AbiWord skjal</comment>
<comment xml:lang="id">Dokumen AbiWord</comment>
<comment xml:lang="ia">Documento AbiWord</comment>
<comment xml:lang="hu">AbiWord-dokumentum</comment>
@@ -7444,7 +7561,7 @@ command to generate the output files.
<comment xml:lang="fo">AbiWord skjal</comment>
<comment xml:lang="fi">AbiWord-asiakirja</comment>
<comment xml:lang="eu">AbiWord dokumentua</comment>
- <comment xml:lang="es">documento de Abiword</comment>
+ <comment xml:lang="es">documento de AbiWord</comment>
<comment xml:lang="eo">AbiWord-dokumento</comment>
<comment xml:lang="en_GB">AbiWord document</comment>
<comment xml:lang="el">Έγγραφο AbiWord</comment>
@@ -7454,6 +7571,7 @@ command to generate the output files.
<comment xml:lang="ca">document AbiWord</comment>
<comment xml:lang="bg">Документ — AbiWord</comment>
<comment xml:lang="be@latin">Dakument AbiWord</comment>
+ <comment xml:lang="be">дакумент AbiWord</comment>
<comment xml:lang="ast">Documentu d'AbiWord</comment>
<comment xml:lang="ar">مستند آبي وورد</comment>
<comment xml:lang="af">AbiWord-dokument</comment>
@@ -7478,8 +7596,8 @@ command to generate the output files.
<comment xml:lang="tr">CD görüntüsü çizelgesi</comment>
<comment xml:lang="sv">Indexblad för cd-avbild</comment>
<comment xml:lang="sr">Кју лист ЦД одраза</comment>
- <comment xml:lang="sq">Cuesheet imazhi CD</comment>
<comment xml:lang="sl">Datoteka razpredelnice odtisa CD cue</comment>
+ <comment xml:lang="si">සීඩී රූප කුට්ටිය</comment>
<comment xml:lang="sk">Rozvrhnutie stôp obrazu CD</comment>
<comment xml:lang="ru">Таблица содержания образа CD</comment>
<comment xml:lang="ro">Imagine CD cuesheet</comment>
@@ -7496,6 +7614,7 @@ command to generate the output files.
<comment xml:lang="kk">CD бейнесінің құрама кестесі</comment>
<comment xml:lang="ja">CD イメージキューシート</comment>
<comment xml:lang="it">Cuesheet immagine CD</comment>
+ <comment xml:lang="is">cuesheet CD diskmyndar</comment>
<comment xml:lang="id">Citra cuesheet CD</comment>
<comment xml:lang="ia">Indice de pistas de CD</comment>
<comment xml:lang="hu">CD lemezkép-jelölőlap</comment>
@@ -7516,6 +7635,7 @@ command to generate the output files.
<comment xml:lang="ca">«cuesheet» d'imatge de CD</comment>
<comment xml:lang="bg">Съдържание на CD</comment>
<comment xml:lang="be@latin">Infarmacyjny arkuš vyjavy CD</comment>
+ <comment xml:lang="be">табліца разметкі вобраза CD</comment>
<comment xml:lang="ar">صفيحة صورة CD جديلة</comment>
<sub-class-of type="text/plain"/>
<generic-icon name="text-x-generic"/>
@@ -7530,8 +7650,9 @@ command to generate the output files.
<comment xml:lang="tr">Lotus AmiPro belgesi</comment>
<comment xml:lang="sv">Lotus AmiPro-dokument</comment>
<comment xml:lang="sr">Лотусов Ами Про документ</comment>
- <comment xml:lang="sq">Dokument Lotus AmiPro</comment>
+ <comment xml:lang="sq">dokument Lotus AmiPro</comment>
<comment xml:lang="sl">Dokument Lotus AmiPro</comment>
+ <comment xml:lang="si">Lotus AmiPro ලේඛනය</comment>
<comment xml:lang="sk">Dokument Lotus AmiPro</comment>
<comment xml:lang="ru">Документ Lotus AmiPro</comment>
<comment xml:lang="ro">Document Lotus AmiPro</comment>
@@ -7549,6 +7670,7 @@ command to generate the output files.
<comment xml:lang="kk">Lotus AmiPro құжаты</comment>
<comment xml:lang="ja">Lotus AmiPro ドキュメント</comment>
<comment xml:lang="it">Documento Lotus AmiPro</comment>
+ <comment xml:lang="is">Lotus AmiPro skjal</comment>
<comment xml:lang="id">Dokumen Lotus AmiPro</comment>
<comment xml:lang="ia">Documento Lotus AmiPro</comment>
<comment xml:lang="hu">Lotus AmiPro-dokumentum</comment>
@@ -7572,6 +7694,7 @@ command to generate the output files.
<comment xml:lang="ca">document de Lotus AmiPro</comment>
<comment xml:lang="bg">Документ — Lotus AmiPro</comment>
<comment xml:lang="be@latin">Dakument Lotus AmiPro</comment>
+ <comment xml:lang="be">дакумент Lotus AmiPro</comment>
<comment xml:lang="az">Lotus AmiPro sənədi</comment>
<comment xml:lang="ast">Documentu de Lotus AmiPro</comment>
<comment xml:lang="ar">مستند Lotus AmiPro</comment>
@@ -7588,7 +7711,9 @@ command to generate the output files.
<comment xml:lang="tr">AportisDoc belgesi</comment>
<comment xml:lang="sv">AportisDoc-dokument</comment>
<comment xml:lang="sr">Апортис Док документ</comment>
+ <comment xml:lang="sq">dokument AportisDoc</comment>
<comment xml:lang="sl">Dokument AportisDoc</comment>
+ <comment xml:lang="si">AportisDoc ලේඛනය</comment>
<comment xml:lang="sk">Dokument AportisDoc</comment>
<comment xml:lang="ru">Документ AportisDoc</comment>
<comment xml:lang="ro">Document AportisDoc</comment>
@@ -7604,6 +7729,7 @@ command to generate the output files.
<comment xml:lang="ka">AportisDoc-ის დოკუმენტი</comment>
<comment xml:lang="ja">AportisDoc ドキュメント</comment>
<comment xml:lang="it">Documento AportisDoc</comment>
+ <comment xml:lang="is">AportisDoc skjal</comment>
<comment xml:lang="id">Dokumen AportisDoc</comment>
<comment xml:lang="ia">Documento AportisDoc</comment>
<comment xml:lang="hu">AportisDoc-dokumentum</comment>
@@ -7625,6 +7751,7 @@ command to generate the output files.
<comment xml:lang="cs">dokument AportisDoc</comment>
<comment xml:lang="ca">document AportisDoc</comment>
<comment xml:lang="bg">Документ — AportisDoc</comment>
+ <comment xml:lang="be">дакумент AportisDoc</comment>
<comment xml:lang="ast">Documentu d'AportisDoc</comment>
<comment xml:lang="ar">مستند AportisDoc</comment>
<comment xml:lang="af">AportisDoc-dokument</comment>
@@ -7634,20 +7761,36 @@ command to generate the output files.
<match type="string" value="TEXtREAd" offset="60"/>
<match type="string" value="TEXtTlDc" offset="60"/>
</magic>
- <glob pattern="*.pdb"/>
+ <glob pattern="*.pdb" weight="30"/>
<glob pattern="*.pdc"/>
</mime-type>
+ <mime-type type="chemical/x-pdb">
+ <comment>Protein Data Bank file</comment>
+ <comment xml:lang="uk">файл банку даних протеїнів</comment>
+ <comment xml:lang="sv">Protein Data Bank-fil</comment>
+ <comment xml:lang="ru">Файл Protein Data Bank</comment>
+ <comment xml:lang="pl">Plik Protein Data Bank</comment>
+ <comment xml:lang="de">Protein-Datenbank-Datei</comment>
+ <sub-class-of type="text/plain"/>
+ <generic-icon name="text-x-generic"/>
+ <magic priority="40">
+ <match type="string" value="HEADER " offset="0"/>
+ </magic>
+ <glob pattern="*.pdb"/>
+ <glob pattern="*.brk"/>
+ </mime-type>
<mime-type type="application/x-applix-spreadsheet">
<comment>Applix Spreadsheets spreadsheet</comment>
<comment xml:lang="zh_TW">Applix Spreadsheets 試算表</comment>
<comment xml:lang="zh_CN">Applix Spreadsheets 电子表格</comment>
<comment xml:lang="vi">Bảng tính Applix Spreadsheets</comment>
- <comment xml:lang="uk">ел. таблиця Applix Spreadsheets</comment>
+ <comment xml:lang="uk">електронна таблиця Applix Spreadsheets</comment>
<comment xml:lang="tr">Applix Spreadsheets hesap çizelgesi</comment>
<comment xml:lang="sv">Applix Spreadsheets-kalkylblad</comment>
<comment xml:lang="sr">документ Апликсове Табеле</comment>
- <comment xml:lang="sq">Fletë llogaritjesh Applix Spreadsheets</comment>
+ <comment xml:lang="sq">fletëllogaritje Applix Spreadsheets</comment>
<comment xml:lang="sl">Razpredelnica Applix Spreadsheets</comment>
+ <comment xml:lang="si">Applix පැතුරුම්පත් පැතුරුම්පත</comment>
<comment xml:lang="sk">Zošit Applix Spreadsheets</comment>
<comment xml:lang="ru">Электронная таблица Applix Spreadsheets</comment>
<comment xml:lang="ro">Foaie de calcul Applix</comment>
@@ -7666,6 +7809,7 @@ command to generate the output files.
<comment xml:lang="ka">Applix Spreadsheets-ის ცხრილი</comment>
<comment xml:lang="ja">Applix Spreadsheets スプレッドシート</comment>
<comment xml:lang="it">Foglio di calcolo Applix Spreadsheets</comment>
+ <comment xml:lang="is">Applix Spreadsheets töflureikniskjal</comment>
<comment xml:lang="id">Lembar sebar Applix Spreadsheets</comment>
<comment xml:lang="ia">Folio de calculo Applix Spreadsheets</comment>
<comment xml:lang="hu">Applix Spreadsheets-munkafüzet</comment>
@@ -7688,6 +7832,7 @@ command to generate the output files.
<comment xml:lang="ca">full de càlcul d'Applix Spreadsheets</comment>
<comment xml:lang="bg">Таблица — Applix Spreadsheets</comment>
<comment xml:lang="be@latin">Raźlikovy arkuš Applix Spreadsheets</comment>
+ <comment xml:lang="be">электронная табліца Applix Spreadsheets</comment>
<comment xml:lang="ar">جداول بيانات Applix</comment>
<comment xml:lang="af">Applix Spreadsheets-sigblad</comment>
<generic-icon name="x-office-spreadsheet"/>
@@ -7708,8 +7853,9 @@ command to generate the output files.
<comment xml:lang="tr">Applix Words belgesi</comment>
<comment xml:lang="sv">Applix Words-dokument</comment>
<comment xml:lang="sr">документ Апликсових Речи</comment>
- <comment xml:lang="sq">Dokument Applix Words</comment>
+ <comment xml:lang="sq">dokument Applix Words</comment>
<comment xml:lang="sl">Dokument Applix Words</comment>
+ <comment xml:lang="si">Applix Words ලේඛනය</comment>
<comment xml:lang="sk">Dokument Applix Words</comment>
<comment xml:lang="ru">Документ Applix Words</comment>
<comment xml:lang="ro">Document Applix Words</comment>
@@ -7728,6 +7874,7 @@ command to generate the output files.
<comment xml:lang="ka">Applix Words-ის დოკუმენტი</comment>
<comment xml:lang="ja">Applix Words ドキュメント</comment>
<comment xml:lang="it">Documento Applix Words</comment>
+ <comment xml:lang="is">Applix Words skjal</comment>
<comment xml:lang="id">Dokumen Applix Words</comment>
<comment xml:lang="ia">Documento Applix Words</comment>
<comment xml:lang="hu">Applix Words-dokumentum</comment>
@@ -7751,6 +7898,7 @@ command to generate the output files.
<comment xml:lang="ca">document d'Applix Words</comment>
<comment xml:lang="bg">Документ — Applix Words</comment>
<comment xml:lang="be@latin">Dakument Applix Words</comment>
+ <comment xml:lang="be">дакумент Applix Words</comment>
<comment xml:lang="az">Applix Words sənədi</comment>
<comment xml:lang="ast">Documentu d'Applix Words</comment>
<comment xml:lang="ar">مستند كلمات Applix</comment>
@@ -7772,8 +7920,9 @@ command to generate the output files.
<comment xml:lang="tr">ARC arşivi</comment>
<comment xml:lang="sv">ARC-arkiv</comment>
<comment xml:lang="sr">АРЦ архива</comment>
- <comment xml:lang="sq">Arkiv ARC</comment>
+ <comment xml:lang="sq">arkiv ARC</comment>
<comment xml:lang="sl">Datoteka arhiva ARC</comment>
+ <comment xml:lang="si">ARC ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív ARC</comment>
<comment xml:lang="ru">Архив ARC</comment>
<comment xml:lang="ro">Arhivă ARC</comment>
@@ -7791,6 +7940,7 @@ command to generate the output files.
<comment xml:lang="ka">ARC არქივი</comment>
<comment xml:lang="ja">ARC アーカイブ</comment>
<comment xml:lang="it">Archivio ARC</comment>
+ <comment xml:lang="is">ARC safnskrá</comment>
<comment xml:lang="id">Arsip ARC</comment>
<comment xml:lang="ia">Archivo ARC</comment>
<comment xml:lang="hu">ARC-archívum</comment>
@@ -7813,6 +7963,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu ARC</comment>
<comment xml:lang="bg">Архив — ARC</comment>
<comment xml:lang="be@latin">Archiŭ ARC</comment>
+ <comment xml:lang="be">архіў ARC</comment>
<comment xml:lang="ar">أرشيف ARC</comment>
<comment xml:lang="af">ARC-argief</comment>
<generic-icon name="package-x-generic"/>
@@ -7834,8 +7985,9 @@ command to generate the output files.
<comment xml:lang="tr">AR arşivi</comment>
<comment xml:lang="sv">AR-arkiv</comment>
<comment xml:lang="sr">АР архива</comment>
- <comment xml:lang="sq">Arkiv AR</comment>
+ <comment xml:lang="sq">arkiv AR</comment>
<comment xml:lang="sl">Datoteka arhiva AR</comment>
+ <comment xml:lang="si">AR ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív AR</comment>
<comment xml:lang="ru">Архив AR</comment>
<comment xml:lang="ro">Arhivă AR</comment>
@@ -7854,6 +8006,7 @@ command to generate the output files.
<comment xml:lang="ka">AR არქივი</comment>
<comment xml:lang="ja">AR アーカイブ</comment>
<comment xml:lang="it">Archivio AR</comment>
+ <comment xml:lang="is">AR safnskrá</comment>
<comment xml:lang="id">Arsip AR</comment>
<comment xml:lang="ia">Archivo AR</comment>
<comment xml:lang="hu">AR-archívum</comment>
@@ -7876,6 +8029,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu AR</comment>
<comment xml:lang="bg">Архив — AR</comment>
<comment xml:lang="be@latin">Archiŭ AR</comment>
+ <comment xml:lang="be">архіў AR</comment>
<comment xml:lang="ar">أرشيف AR</comment>
<comment xml:lang="af">AR-argief</comment>
<generic-icon name="package-x-generic"/>
@@ -7895,8 +8049,9 @@ command to generate the output files.
<comment xml:lang="tr">ARJ arşivi</comment>
<comment xml:lang="sv">ARJ-arkiv</comment>
<comment xml:lang="sr">АРЈ архива</comment>
- <comment xml:lang="sq">Arkiv ARJ</comment>
+ <comment xml:lang="sq">arkiv ARJ</comment>
<comment xml:lang="sl">Datoteka arhiva ARJ</comment>
+ <comment xml:lang="si">ARJ ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív ARJ</comment>
<comment xml:lang="ru">Архив ARJ</comment>
<comment xml:lang="ro">Arhivă ARJ</comment>
@@ -7915,6 +8070,7 @@ command to generate the output files.
<comment xml:lang="ka">ARJ არქივი</comment>
<comment xml:lang="ja">ARJ アーカイブ</comment>
<comment xml:lang="it">Archivio ARJ</comment>
+ <comment xml:lang="is">ARJ safnskrá</comment>
<comment xml:lang="id">Arsip ARJ</comment>
<comment xml:lang="ia">Archivo ARJ</comment>
<comment xml:lang="hu">ARJ-archívum</comment>
@@ -7938,6 +8094,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu ARJ</comment>
<comment xml:lang="bg">Архив — ARJ</comment>
<comment xml:lang="be@latin">Archiŭ ARJ</comment>
+ <comment xml:lang="be">архіў ARJ</comment>
<comment xml:lang="az">ARJ arxivi</comment>
<comment xml:lang="ar">أرشيف ARJ</comment>
<comment xml:lang="af">ARJ-argief</comment>
@@ -7951,6 +8108,30 @@ command to generate the output files.
</mime-type>
<mime-type type="application/x-asar">
<comment>Electron Archive (ASAR)</comment>
+ <comment xml:lang="zh_CN">Electron 归档 (ASAR)</comment>
+ <comment xml:lang="uk">архів Electron (ASAR)</comment>
+ <comment xml:lang="tr">Electron Arşivi (ASAR)</comment>
+ <comment xml:lang="sv">Electron-arkiv (ASAR)</comment>
+ <comment xml:lang="sl">Arhiv Electron (ASAR)</comment>
+ <comment xml:lang="si">ඉලෙක්ට්‍රෝන ලේඛනාගාරය (ASAR)</comment>
+ <comment xml:lang="ru">Electron Archive (ASAR)</comment>
+ <comment xml:lang="pt_BR">Arquivo do Electron (ASAR)</comment>
+ <comment xml:lang="pl">Archiwum Electron (ASAR)</comment>
+ <comment xml:lang="nl">Electron Archive (ASAR)</comment>
+ <comment xml:lang="ko">일렉트론 묶음 파일 (ASAR)</comment>
+ <comment xml:lang="kk">Electron архиві (ASAR)</comment>
+ <comment xml:lang="ja">Electron アーカイブ (ASAR)</comment>
+ <comment xml:lang="it">Archivio Electron (ASAR)</comment>
+ <comment xml:lang="hr">Electron arhiva (ASAR)</comment>
+ <comment xml:lang="he">ארכיון Electron‏ (ASAR)</comment>
+ <comment xml:lang="gl">Arquivo Electron (ASAR)</comment>
+ <comment xml:lang="fi">Electron Archive (ASAR)</comment>
+ <comment xml:lang="eu">Electron artxiboa (ASAR)</comment>
+ <comment xml:lang="es">archivador Electron (ASARP)</comment>
+ <comment xml:lang="en_GB">Electron Archive (ASAR)</comment>
+ <comment xml:lang="de">Electron-Archiv (ASAR)</comment>
+ <comment xml:lang="be">архіў Electron (ASAR)</comment>
+ <comment xml:lang="ar">أرشيف إليكترون (ASAR)</comment>
<acronym>ASAR</acronym>
<expanded-acronym>Atom Shell Archive Format</expanded-acronym>
<magic>
@@ -7969,8 +8150,9 @@ command to generate the output files.
<comment xml:lang="tr">ASP sayfası</comment>
<comment xml:lang="sv">ASP-sida</comment>
<comment xml:lang="sr">АСП страница</comment>
- <comment xml:lang="sq">Faqe ASP</comment>
+ <comment xml:lang="sq">faqe ASP</comment>
<comment xml:lang="sl">Datoteka spletne strani ASP</comment>
+ <comment xml:lang="si">ASP පිටුව</comment>
<comment xml:lang="sk">Stránka ASP</comment>
<comment xml:lang="ru">Страница ASP</comment>
<comment xml:lang="ro">Pagină ASP</comment>
@@ -7988,6 +8170,7 @@ command to generate the output files.
<comment xml:lang="ka">ASP გვერდი</comment>
<comment xml:lang="ja">ASP ページ</comment>
<comment xml:lang="it">Pagina ASP</comment>
+ <comment xml:lang="is">ASP síða</comment>
<comment xml:lang="id">Halaman ASP</comment>
<comment xml:lang="ia">Pagina ASP</comment>
<comment xml:lang="hu">ASP oldal</comment>
@@ -8010,6 +8193,7 @@ command to generate the output files.
<comment xml:lang="ca">pàgina ASP</comment>
<comment xml:lang="bg">Страница — ASP</comment>
<comment xml:lang="be@latin">Staronka ASP</comment>
+ <comment xml:lang="be">старонка ASP</comment>
<comment xml:lang="ast">Páxina ASP</comment>
<comment xml:lang="ar">صفحة ASP</comment>
<comment xml:lang="af">ASP-bladsy</comment>
@@ -8028,8 +8212,9 @@ command to generate the output files.
<comment xml:lang="tr">AWK betiği</comment>
<comment xml:lang="sv">AWK-skript</comment>
<comment xml:lang="sr">АВК скрипта</comment>
- <comment xml:lang="sq">Script AWK</comment>
+ <comment xml:lang="sq">programth AWK</comment>
<comment xml:lang="sl">Skriptna datoteka AWK</comment>
+ <comment xml:lang="si">AWK පිටපත</comment>
<comment xml:lang="sk">Skript AWK</comment>
<comment xml:lang="ru">Сценарий AWK</comment>
<comment xml:lang="ro">Script AWK</comment>
@@ -8048,6 +8233,7 @@ command to generate the output files.
<comment xml:lang="ka">AWK სცენარი</comment>
<comment xml:lang="ja">AWK スクリプト</comment>
<comment xml:lang="it">Script AWK</comment>
+ <comment xml:lang="is">AWK skrifta</comment>
<comment xml:lang="id">Skrip AWK</comment>
<comment xml:lang="ia">Script AWK</comment>
<comment xml:lang="hu">AWK-parancsfájl</comment>
@@ -8071,6 +8257,7 @@ command to generate the output files.
<comment xml:lang="ca">script AWK</comment>
<comment xml:lang="bg">Скрипт — AWK</comment>
<comment xml:lang="be@latin">Skrypt AWK</comment>
+ <comment xml:lang="be">скрыпт AWK</comment>
<comment xml:lang="az">AWK skripti</comment>
<comment xml:lang="ast">Script AWK</comment>
<comment xml:lang="ar">سكربت AWK</comment>
@@ -8094,6 +8281,32 @@ command to generate the output files.
</mime-type>
<mime-type type="application/x-bcpio">
<comment>BCPIO archive</comment>
+ <comment xml:lang="zh_CN">BCPIO 归档</comment>
+ <comment xml:lang="uk">архів BCPIO</comment>
+ <comment xml:lang="tr">BCPIO arşivi</comment>
+ <comment xml:lang="sv">BCPIO-arkiv</comment>
+ <comment xml:lang="sl">Arhiv BCPIO</comment>
+ <comment xml:lang="si">BCPIO ලේඛනාගාරය</comment>
+ <comment xml:lang="sk">Archív BCPIO</comment>
+ <comment xml:lang="ru">Архив BCPIO</comment>
+ <comment xml:lang="pt_BR">Arquivo BCPIO</comment>
+ <comment xml:lang="pl">Archiwum BCPIO</comment>
+ <comment xml:lang="oc">archiu BCPIO</comment>
+ <comment xml:lang="nl">BCPIO-archief</comment>
+ <comment xml:lang="ko">BCPIO 묶음 파일</comment>
+ <comment xml:lang="kk">BCPIO архиві</comment>
+ <comment xml:lang="ja">BCPIO アーカイブ</comment>
+ <comment xml:lang="it">Archivio BCPIO</comment>
+ <comment xml:lang="hr">BCPIO arhiva</comment>
+ <comment xml:lang="he">ארכיון BCPIO</comment>
+ <comment xml:lang="gl">Arquivo BCPIO</comment>
+ <comment xml:lang="fi">BCPIO-arkisto</comment>
+ <comment xml:lang="eu">BCPIO artxiboa</comment>
+ <comment xml:lang="es">archivador BCPIO</comment>
+ <comment xml:lang="en_GB">BCPIO archive</comment>
+ <comment xml:lang="de">BCPIO-Archiv</comment>
+ <comment xml:lang="be">архіў BCPIO</comment>
+ <comment xml:lang="ar">أرشيف BCPIO</comment>
<acronym>BCPIO</acronym>
<expanded-acronym>Binary CPIO</expanded-acronym>
<generic-icon name="package-x-generic"/>
@@ -8108,8 +8321,9 @@ command to generate the output files.
<comment xml:lang="tr">BitTorrent tohum dosyası</comment>
<comment xml:lang="sv">BitTorrent-distributionsfil</comment>
<comment xml:lang="sr">датотека сејача Бит Торента</comment>
- <comment xml:lang="sq">File bazë BitTorrent</comment>
+ <comment xml:lang="sq">kartelë seed BitTorrent</comment>
<comment xml:lang="sl">Datoteka sejanja BitTorrent</comment>
+ <comment xml:lang="si">BitTorrent බීජ ගොනුව</comment>
<comment xml:lang="sk">Súbor BitTorrent</comment>
<comment xml:lang="ru">Файл источника BitTorrent</comment>
<comment xml:lang="ro">Fișier sursă-completă BitTorrent</comment>
@@ -8127,6 +8341,7 @@ command to generate the output files.
<comment xml:lang="kk">BitTorrent көз файлы</comment>
<comment xml:lang="ja">BitTorrent シードファイル</comment>
<comment xml:lang="it">File seed BitTorrent</comment>
+ <comment xml:lang="is">BitTorrent sáningarskrá</comment>
<comment xml:lang="id">Berkas benih BitTorrent</comment>
<comment xml:lang="ia">File seminal de BitTorrent</comment>
<comment xml:lang="hu">BitTorrent-magfájl</comment>
@@ -8143,13 +8358,14 @@ command to generate the output files.
<comment xml:lang="eo">BitTorrent-semdosiero</comment>
<comment xml:lang="en_GB">BitTorrent seed file</comment>
<comment xml:lang="el">Αρχείο BitTorrent seed</comment>
- <comment xml:lang="de">BitTorrent-Seed-Datei</comment>
+ <comment xml:lang="de">BitTorrent-Startdatei</comment>
<comment xml:lang="da">BitTorrent-frøfil</comment>
<comment xml:lang="cy">Ffeil hadu BitTorrent</comment>
<comment xml:lang="cs">soubor BitTorrent</comment>
<comment xml:lang="ca">fitxer de llavor BitTorrent</comment>
<comment xml:lang="bg">Файл-източник — BitTorrent</comment>
<comment xml:lang="be@latin">Fajł krynicy BitTorrent</comment>
+ <comment xml:lang="be">файл раздачы BitTorrent</comment>
<comment xml:lang="az">BitTorrent seed faylı</comment>
<comment xml:lang="ar">ملف باذر بت تورنت</comment>
<comment xml:lang="af">BitTorrent-saadlêer</comment>
@@ -8167,8 +8383,9 @@ command to generate the output files.
<comment xml:lang="tr">Blender sahnesi</comment>
<comment xml:lang="sv">Blender-scen</comment>
<comment xml:lang="sr">Блендерова сцена</comment>
- <comment xml:lang="sq">Skenë Blender</comment>
+ <comment xml:lang="sq">skenë Blender</comment>
<comment xml:lang="sl">Datoteka scene Blender</comment>
+ <comment xml:lang="si">බ්ලෙන්ඩර් දර්ශනය</comment>
<comment xml:lang="sk">Scéna Blender</comment>
<comment xml:lang="ru">Сцена Blender</comment>
<comment xml:lang="ro">Scenă Blender</comment>
@@ -8187,6 +8404,7 @@ command to generate the output files.
<comment xml:lang="ka">Blender-ის სცენა</comment>
<comment xml:lang="ja">Blender シーン</comment>
<comment xml:lang="it">Scena Blender</comment>
+ <comment xml:lang="is">Blender sviðsmynd</comment>
<comment xml:lang="id">Scene Blender</comment>
<comment xml:lang="ia">Scena Blender</comment>
<comment xml:lang="hu">Blender-jelenet</comment>
@@ -8209,6 +8427,7 @@ command to generate the output files.
<comment xml:lang="ca">escena de Blender</comment>
<comment xml:lang="bg">Сцена — Blender</comment>
<comment xml:lang="be@latin">Scena Blender</comment>
+ <comment xml:lang="be">сцэна Blender</comment>
<comment xml:lang="ast">Escena de Blender</comment>
<comment xml:lang="ar">مشهد بلندر</comment>
<comment xml:lang="af">Blender-toneel</comment>
@@ -8221,312 +8440,197 @@ command to generate the output files.
</magic>
</mime-type>
<mime-type type="application/x-bzdvi">
- <comment>TeX DVI document (bzip-compressed)</comment>
- <comment xml:lang="zh_TW">TeX DVI 文件 (bzip 壓縮)</comment>
- <comment xml:lang="zh_CN">TeX DVI 文档(gzip 压缩)</comment>
- <comment xml:lang="vi">Tài liệu DVI TeX (đã nén bzip)</comment>
- <comment xml:lang="uk">документ TeX DVI (стиснений bzip)</comment>
- <comment xml:lang="tr">TeX DVI belgesi (bzip ile sıkıştırılmış)</comment>
- <comment xml:lang="sv">TeX DVI-dokument (bzip-komprimerat)</comment>
- <comment xml:lang="sr">ТеКс ДВИ документ (запакована бзипом)</comment>
- <comment xml:lang="sq">Dokument Tex DVI (i kompresuar me bzip)</comment>
- <comment xml:lang="sl">Dokument TeX DVI (stisnjen z bzip)</comment>
- <comment xml:lang="sk">Dokument TeX DVI (komprimovaný pomocou bzip)</comment>
- <comment xml:lang="ru">Документ TeX DVI (сжатый bzip)</comment>
- <comment xml:lang="ro">Document TeX DVI (comprimat bzip)</comment>
- <comment xml:lang="pt_BR">Documento DVI TeX (compactado com bzip)</comment>
- <comment xml:lang="pt">documento TeX DVI (compressão bzip)</comment>
- <comment xml:lang="pl">Dokument TeX DVI (kompresja bzip)</comment>
- <comment xml:lang="oc">document DVI TeX (compressat bzip)</comment>
- <comment xml:lang="nn">TeX DVI-dokument (pakka med bzip)</comment>
- <comment xml:lang="nl">TeX DVI-document (ingepakt met bzip)</comment>
- <comment xml:lang="nb">TeX DVI-dokument (bzip-komprimert)</comment>
- <comment xml:lang="lv">TeX DVI dokuments (saspiests ar bzip)</comment>
- <comment xml:lang="lt">TeX DVI dokumentas (suglaudintas su bzip)</comment>
- <comment xml:lang="ko">TeX DVI 문서(BZIP 압축)</comment>
- <comment xml:lang="kk">TeX DVI құжаты (bzip-пен сығылған)</comment>
- <comment xml:lang="ja">Tex DVI ドキュメント (bzip 圧縮)</comment>
- <comment xml:lang="it">Documento TeX DVI (compresso con bzip)</comment>
- <comment xml:lang="id">Dokumen TeX DVI (terkompresi bzip)</comment>
- <comment xml:lang="ia">Documento TeX DVI (comprimite con bzip)</comment>
- <comment xml:lang="hu">TeX DVI dokumentum (bzip tömörítésű)</comment>
- <comment xml:lang="hr">TeX DVI dokument (bzip sažeto)</comment>
- <comment xml:lang="he">מסמך מסוג TeX DVI (מכווץ ע״י bzip)</comment>
- <comment xml:lang="gl">documento DVI de TeX (comprimido con bzip)</comment>
- <comment xml:lang="ga">cáipéis DVI TeX (comhbhrúite le bzip)</comment>
- <comment xml:lang="fur">document DVI TeX (comprimût cun bzip)</comment>
- <comment xml:lang="fr">document DVI TeX (compressé bzip)</comment>
- <comment xml:lang="fo">TeX DVI skjal (bzip-stappað)</comment>
- <comment xml:lang="fi">TeX DVI -asiakirja (bzip-pakattu)</comment>
- <comment xml:lang="eu">TeX DVI dokumentua (bzip-ekin konprimitua)</comment>
- <comment xml:lang="es">documento DVI de TeX (comprimido con bzip)</comment>
- <comment xml:lang="en_GB">TeX DVI document (bzip-compressed)</comment>
- <comment xml:lang="el">Αρχείο TeX DVI (συμπιεσμένο με bzip)</comment>
- <comment xml:lang="de">TeX-DVI-Dokument (bzip-komprimiert)</comment>
- <comment xml:lang="da">TeX DVI-dokument (bzip-komprimeret)</comment>
- <comment xml:lang="cs">dokument TeX DVI (komprimovaný pomocí bzip)</comment>
- <comment xml:lang="ca">document de TeX DVI (amb compressió bzip)</comment>
- <comment xml:lang="bg">Документ — TeX DVI, компресиран с bzip</comment>
- <comment xml:lang="be@latin">Dakument TeX DVI (bzip-skampresavany)</comment>
- <comment xml:lang="ast">Documentu Tex DVI (comprimíu en bzip)</comment>
- <comment xml:lang="ar">مستند TeX DVI (مضغوط-bzip)</comment>
- <comment xml:lang="af">TeX DVI-dokument (bzip-saamgepers)</comment>
- <sub-class-of type="application/x-bzip"/>
+ <comment>TeX DVI document (bzip2-compressed)</comment>
+ <comment xml:lang="uk">документ DVI TeX (стиснений bzip2)</comment>
+ <comment xml:lang="sv">TeX DVI-dokument (bzip2-komprimerat)</comment>
+ <comment xml:lang="ru">Документ DVI издательской системы TeX (сжатый bzip2)</comment>
+ <comment xml:lang="pt_BR">Documento DVI TeX (compactado com bzip2)</comment>
+ <comment xml:lang="pl">Dokument TeX DVI (kompresja bzip2)</comment>
+ <comment xml:lang="es">documento DVI de TeX (comprimido con BZIP2)</comment>
+ <comment xml:lang="de">TeX-DVI-Dokument (bzip2-komprimiert)</comment>
+ <sub-class-of type="application/x-bzip2"/>
<generic-icon name="x-office-document"/>
<glob pattern="*.dvi.bz2"/>
</mime-type>
- <mime-type type="application/x-bzip">
- <comment>Bzip archive</comment>
- <comment xml:lang="zh_TW">Bzip 封存檔</comment>
- <comment xml:lang="zh_CN">Bzip 归档文件</comment>
- <comment xml:lang="vi">Kho nén bzip</comment>
- <comment xml:lang="uk">архів bzip</comment>
- <comment xml:lang="tr">Bzip arşivi</comment>
- <comment xml:lang="sv">Bzip-arkiv</comment>
- <comment xml:lang="sr">Бзип архива</comment>
- <comment xml:lang="sq">Arkiv bzip</comment>
- <comment xml:lang="sl">Datoteka arhiva Bzip</comment>
- <comment xml:lang="sk">Archív Bzip</comment>
- <comment xml:lang="ru">Архив BZIP</comment>
- <comment xml:lang="ro">Arhivă Bzip</comment>
- <comment xml:lang="pt_BR">Pacote Bzip</comment>
- <comment xml:lang="pt">arquivo Bzip</comment>
- <comment xml:lang="pl">Archiwum bzip</comment>
- <comment xml:lang="oc">archiu bzip</comment>
- <comment xml:lang="nn">Bzip-arkiv</comment>
- <comment xml:lang="nl">Bzip-archief</comment>
- <comment xml:lang="nb">Bzip-arkiv</comment>
- <comment xml:lang="lv">Bzip arhīvs</comment>
- <comment xml:lang="lt">Bzip archyvas</comment>
- <comment xml:lang="ko">BZIP 압축 파일</comment>
- <comment xml:lang="kk">Bzip архиві</comment>
- <comment xml:lang="ka">Bzip არქივი</comment>
- <comment xml:lang="ja">Bzip アーカイブ</comment>
- <comment xml:lang="it">Archivio bzip</comment>
- <comment xml:lang="id">Arsip Bzip</comment>
- <comment xml:lang="ia">Archivo Bzip</comment>
- <comment xml:lang="hu">Bzip archívum</comment>
- <comment xml:lang="hr">Bzip arhiva</comment>
- <comment xml:lang="he">ארכיון Bzip</comment>
- <comment xml:lang="gl">arquivo Bzip</comment>
- <comment xml:lang="ga">cartlann Bzip</comment>
- <comment xml:lang="fur">archivi Bzip</comment>
- <comment xml:lang="fr">archive bzip</comment>
- <comment xml:lang="fo">Bzip skjalasavn</comment>
- <comment xml:lang="fi">Bzip-arkisto</comment>
- <comment xml:lang="eu">Bzip artxiboa</comment>
- <comment xml:lang="es">archivador Bzip</comment>
- <comment xml:lang="eo">Bzip-arkivo</comment>
- <comment xml:lang="en_GB">Bzip archive</comment>
- <comment xml:lang="el">Συμπιεσμένο αρχείο Bzip</comment>
- <comment xml:lang="de">Bzip-Archiv</comment>
- <comment xml:lang="da">Bzip-arkiv</comment>
- <comment xml:lang="cs">archiv bzip</comment>
- <comment xml:lang="ca">arxiu bzip</comment>
- <comment xml:lang="bg">Архив — bzip</comment>
- <comment xml:lang="be@latin">Archiŭ bzip</comment>
- <comment xml:lang="ast">Archivu Bzip</comment>
- <comment xml:lang="ar">أرشيف Bzip</comment>
- <comment xml:lang="af">Bzip-argief</comment>
+ <mime-type type="application/x-bzip1">
+ <comment>Bzip1 archive</comment>
+ <comment xml:lang="uk">архів bzip1</comment>
+ <comment xml:lang="sv">Bzip1-arkiv</comment>
+ <comment xml:lang="ru">Архив Bzip1</comment>
+ <comment xml:lang="pl">Archiwum bzip1</comment>
+ <comment xml:lang="es">archivador BZIP1</comment>
+ <comment xml:lang="de">Bzip1-Archiv</comment>
+ <generic-icon name="package-x-generic"/>
+ <magic>
+ <match type="string" value="BZ0" offset="0"/>
+ </magic>
+ <glob pattern="*.bz"/>
+ </mime-type>
+ <mime-type type="application/x-bzip1-compressed-tar">
+ <comment>Tar archive (bzip1-compressed)</comment>
+ <comment xml:lang="uk">архів tar (стиснений bzip1)</comment>
+ <comment xml:lang="sv">Tar-arkiv (bzip1-komprimerat)</comment>
+ <comment xml:lang="ru">Архив Tar (сжатый bzip1)</comment>
+ <comment xml:lang="pl">Archiwum tar (kompresja bzip1)</comment>
+ <comment xml:lang="es">archivador TAR (comprimido con BZIP1)</comment>
+ <comment xml:lang="de">Tar-Archiv (bzip1-komprimiert)</comment>
+ <generic-icon name="package-x-generic"/>
+ <sub-class-of type="application/x-bzip1"/>
+ <glob pattern="*.tar.bz"/>
+ <glob pattern="*.tbz"/>
+ </mime-type>
+ <mime-type type="application/x-bzip2">
+ <comment>Bzip2 archive</comment>
+ <comment xml:lang="uk">архів bzip2</comment>
+ <comment xml:lang="sv">Bzip2-arkiv</comment>
+ <comment xml:lang="ru">Архив Bzip2</comment>
+ <comment xml:lang="pt_BR">Pacote Bzip2</comment>
+ <comment xml:lang="pl">Archiwum bzip2</comment>
+ <comment xml:lang="it">Archivio bzip2</comment>
+ <comment xml:lang="gl">Arquivo Bzip2</comment>
+ <comment xml:lang="eu">Bzip2 artxiboa</comment>
+ <comment xml:lang="es">archivador BZIP2</comment>
+ <comment xml:lang="de">Bzip2-Archiv</comment>
+ <comment xml:lang="be">архіў bzip2</comment>
<generic-icon name="package-x-generic"/>
<magic>
<match type="string" value="BZh" offset="0"/>
</magic>
<glob pattern="*.bz2"/>
- <glob pattern="*.bz"/>
- <alias type="application/x-bzip2"/>
<alias type="application/bzip2"/>
- </mime-type>
- <mime-type type="application/x-bzip-compressed-tar">
- <comment>Tar archive (bzip-compressed)</comment>
- <comment xml:lang="zh_TW">Tar 封存檔 (bzip 壓縮)</comment>
- <comment xml:lang="zh_CN">Tar 归档文件(bzip 压缩)</comment>
- <comment xml:lang="vi">Kho nén tar (đã nén bzip)</comment>
- <comment xml:lang="uk">архів tar (стиснений bzip)</comment>
- <comment xml:lang="tr">Tar arşivi (bzip ile sıkıştırılmış)</comment>
- <comment xml:lang="sv">Tar-arkiv (bzip-komprimerat)</comment>
- <comment xml:lang="sr">Тар архива (запакована бзипом)</comment>
- <comment xml:lang="sq">Arkiv tar (i kompresuar me bzip)</comment>
- <comment xml:lang="sl">Datoteka arhiva Tar (stisnjen z bzip)</comment>
- <comment xml:lang="sk">Archív Tar (komprimovaný pomocou bzip)</comment>
- <comment xml:lang="ru">Архив TAR (сжатый bzip)</comment>
- <comment xml:lang="ro">Arhivă Tar (comprimată bzip)</comment>
- <comment xml:lang="pt_BR">Pacote Tar (compactado com bzip)</comment>
- <comment xml:lang="pt">arquivo Tar (compressão bzip)</comment>
- <comment xml:lang="pl">Archiwum tar (kompresja bzip)</comment>
- <comment xml:lang="oc">archiu tar (compressat bzip)</comment>
- <comment xml:lang="nn">Tar-arkiv (pakka med bzip)</comment>
- <comment xml:lang="nl">Tar-archief (ingepakt met bzip)</comment>
- <comment xml:lang="nb">Tar-arkiv (bzip-komprimert)</comment>
- <comment xml:lang="lv">Tar arhīvs (saspiests ar bzip)</comment>
- <comment xml:lang="lt">Tar archyvas (suglaudintas su bzip)</comment>
- <comment xml:lang="ko">TAR 묶음 파일(BZIP 압축)</comment>
- <comment xml:lang="kk">Tar архиві (bzip-пен сығылған)</comment>
- <comment xml:lang="ja">Tar アーカイブ (bzip 圧縮)</comment>
- <comment xml:lang="it">Archivio tar (compresso con bzip)</comment>
- <comment xml:lang="id">Arsip Tar (terkompresi bzip)</comment>
- <comment xml:lang="ia">Archivo Tar (comprimite con bzip)</comment>
- <comment xml:lang="hu">Tar archívum (bzip tömörítésű)</comment>
- <comment xml:lang="hr">Tar arhiva (bzip sažeto)</comment>
- <comment xml:lang="he">ארכיון Tar (מכווץ ע״י bzip)</comment>
- <comment xml:lang="gl">arquivo Tar (comprimido con bzip)</comment>
- <comment xml:lang="ga">cartlann Tar (comhbhrúite le bzip)</comment>
- <comment xml:lang="fur">archivi Tar (comprimût cun bzip)</comment>
- <comment xml:lang="fr">archive tar (compressée bzip)</comment>
- <comment xml:lang="fo">Tar skjalasavn (bzip-stappað)</comment>
- <comment xml:lang="fi">Tar-arkisto (bzip-pakattu)</comment>
- <comment xml:lang="eu">Tar artxiboa (bzip-ekin konprimitua)</comment>
- <comment xml:lang="es">archivador Tar (comprimido con bzip)</comment>
- <comment xml:lang="en_GB">Tar archive (bzip-compressed)</comment>
- <comment xml:lang="el">Αρχείο Tar (συμπιεσμένο με bzip)</comment>
- <comment xml:lang="de">Tar-Archiv (bzip-komprimiert)</comment>
- <comment xml:lang="da">Tar-arkiv (bzip-komprimeret)</comment>
- <comment xml:lang="cs">archiv Tar (komprimovaný pomocí bzip)</comment>
- <comment xml:lang="ca">arxiu tar (amb compressió bzip)</comment>
- <comment xml:lang="bg">Архив — tar, компресиран с bzip</comment>
- <comment xml:lang="be@latin">Archiŭ tar (bzip-skampresavany)</comment>
- <comment xml:lang="ast">Archivu Tar (comprimíu en bzip)</comment>
- <comment xml:lang="ar">أرشيف Tar (مضغوط-bzip)</comment>
- <comment xml:lang="af">Tar-argief (bzip-saamgepers)</comment>
+ <alias type="application/x-bzip"/>
+ </mime-type>
+ <mime-type type="application/x-bzip2-compressed-tar">
+ <comment>Tar archive (bzip2-compressed)</comment>
+ <comment xml:lang="uk">архів tar (стиснений bzip2)</comment>
+ <comment xml:lang="sv">Tar-arkiv (bzip2-komprimerat)</comment>
+ <comment xml:lang="ru">Архив Tar (сжатый bzip2)</comment>
+ <comment xml:lang="pl">Archiwum tar (kompresja bzip2)</comment>
+ <comment xml:lang="es">archivador TAR (comprimido con BZIP2)</comment>
+ <comment xml:lang="de">Tar-Archiv (bzip2-komprimiert)</comment>
<generic-icon name="package-x-generic"/>
- <sub-class-of type="application/x-bzip"/>
+ <sub-class-of type="application/x-bzip2"/>
<glob pattern="*.tar.bz2"/>
- <glob pattern="*.tar.bz"/>
<glob pattern="*.tbz2"/>
- <glob pattern="*.tbz"/>
<glob pattern="*.tb2"/>
+ <alias type="application/x-bzip-compressed-tar"/>
+ </mime-type>
+ <mime-type type="application/x-bzip3">
+ <comment>Bzip3 archive</comment>
+ <comment xml:lang="uk">архів bzip3</comment>
+ <comment xml:lang="sv">Bzip3-arkiv</comment>
+ <comment xml:lang="ru">Архив Bzip3</comment>
+ <comment xml:lang="pl">Archiwum bzip3</comment>
+ <comment xml:lang="it">Archivio bzip3</comment>
+ <comment xml:lang="gl">Arquivo Bzip3</comment>
+ <comment xml:lang="eu">Bzip3 artxiboa</comment>
+ <comment xml:lang="es">archivador BZIP3</comment>
+ <comment xml:lang="de">Bzip3-Archiv</comment>
+ <comment xml:lang="be">архіў bzip3</comment>
+ <generic-icon name="package-x-generic"/>
+ <magic>
+ <match type="string" value="BZ3v1" offset="0"/>
+ </magic>
+ <glob pattern="*.bz3"/>
+ </mime-type>
+ <mime-type type="application/x-bzip3-compressed-tar">
+ <comment>Tar archive (bzip3-compressed)</comment>
+ <comment xml:lang="uk">архів tar (стиснений bzip3)</comment>
+ <comment xml:lang="sv">Tar-arkiv (bzip3-komprimerat)</comment>
+ <comment xml:lang="ru">TAR Архив (сжатый bzip3)</comment>
+ <comment xml:lang="pl">Archiwum tar (kompresja bzip3)</comment>
+ <comment xml:lang="it">Archivio tar (compresso con bzip3)</comment>
+ <comment xml:lang="gl">Arquivo Tar (comprimido con bzip3)</comment>
+ <comment xml:lang="eu">Tar artxiboa (bzip3-compressed)</comment>
+ <comment xml:lang="es">archivador TAR (comprimido con BZIP3)</comment>
+ <comment xml:lang="de">Tar-Archiv (bzip3-komprimiert)</comment>
+ <comment xml:lang="be">архіў tar (сцісканне bzip3)</comment>
+ <generic-icon name="package-x-generic"/>
+ <sub-class-of type="application/x-bzip3"/>
+ <glob pattern="*.tar.bz3"/>
+ <glob pattern="*.tbz3"/>
</mime-type>
<mime-type type="application/x-bzpdf">
- <comment>PDF document (bzip-compressed)</comment>
- <comment xml:lang="zh_TW">PDF 文件 (bzip 壓縮)</comment>
- <comment xml:lang="zh_CN">PDF 文档(bzip 压缩)</comment>
- <comment xml:lang="vi">Tài liệu PDF (đã nén bzip)</comment>
- <comment xml:lang="uk">документ PDF (стиснений bzip)</comment>
- <comment xml:lang="tr">PDF belgesi (bzip ile sıkıştırılmış)</comment>
- <comment xml:lang="sv">PDF-dokument (bzip-komprimerat)</comment>
- <comment xml:lang="sr">ПДФ документ (запакован бзипом)</comment>
- <comment xml:lang="sq">Dokument PDF (i kompresuar me bzip)</comment>
- <comment xml:lang="sl">Dokument PDF (stisnjen z bzip)</comment>
- <comment xml:lang="sk">Dokument PDF (komprimovaný pomocou bzip)</comment>
- <comment xml:lang="ru">Документ PDF (сжатый bzip)</comment>
- <comment xml:lang="ro">Document PDF (comprimat bzip)</comment>
- <comment xml:lang="pt_BR">Documento PDF (compactado com bzip)</comment>
- <comment xml:lang="pt">documento PDF (compressão bzip)</comment>
- <comment xml:lang="pl">Dokument PDF (kompresja bzip)</comment>
- <comment xml:lang="oc">document PDF (compressat bzip)</comment>
- <comment xml:lang="nn">PDF-dokument (pakka med bzip)</comment>
- <comment xml:lang="nl">PDF-document (ingepakt met bzip)</comment>
- <comment xml:lang="nb">PDF-dokument (bzip-komprimert)</comment>
- <comment xml:lang="lv">PDF dokuments (saspiests ar bzip)</comment>
- <comment xml:lang="lt">PDF dokumentas (suglaudintas su bzip)</comment>
- <comment xml:lang="ko">PDF 문서(BZIP 압축)</comment>
- <comment xml:lang="kk">PDF құжаты (bzip-пен сығылған)</comment>
- <comment xml:lang="ja">PDF ドキュメント (bzip 圧縮)</comment>
- <comment xml:lang="it">Documento PDF (compresso con bzip)</comment>
- <comment xml:lang="id">Dokumen PDF (terkompresi bzip)</comment>
- <comment xml:lang="ia">Documento PDF (comprimite con bzip)</comment>
- <comment xml:lang="hu">PDF dokumentum (bzip tömörítésű)</comment>
- <comment xml:lang="hr">PDF dokument (bzip sažet)</comment>
- <comment xml:lang="he">מסמך PDF (מכווץ ע״י bzip)</comment>
- <comment xml:lang="gl">documento PDF (comprimido en bzip)</comment>
- <comment xml:lang="ga">cáipéis PDF (comhbhrúite le bzip)</comment>
- <comment xml:lang="fur">document PDF (comprimût cun bzip)</comment>
- <comment xml:lang="fr">document PDF (compressé bzip)</comment>
- <comment xml:lang="fo">PDF skjal (bzip-stappað)</comment>
- <comment xml:lang="fi">PDF-asiakirja (bzip-pakattu)</comment>
- <comment xml:lang="eu">PostScript dokumentua (bzip-ekin konprimitua)</comment>
- <comment xml:lang="es">documento PDF (comprimido con bzip)</comment>
- <comment xml:lang="en_GB">PDF document (bzip-compressed)</comment>
- <comment xml:lang="el">Έγγραφο PDF (συμπιεσμένο με bzip)</comment>
- <comment xml:lang="de">PDF-Dokument (bzip-komprimiert)</comment>
- <comment xml:lang="da">PDF-dokument (bzip-komprimeret)</comment>
- <comment xml:lang="cs">dokument PDF (komprimovaný pomocí bzip)</comment>
- <comment xml:lang="ca">document PDF (amb compressió bzip)</comment>
- <comment xml:lang="bg">Документ — PDF, компресиран с bzip</comment>
- <comment xml:lang="be@latin">Dakument PDF (bzip-skampresavany)</comment>
- <comment xml:lang="ast">Documentu PDF (comprimíu en bzip)</comment>
- <comment xml:lang="ar">مستند PDF (مضغوط-bzip)</comment>
- <comment xml:lang="af">PDF-dokument (bzip-saamgepers)</comment>
- <sub-class-of type="application/x-bzip"/>
+ <comment>PDF document (bzip2-compressed)</comment>
+ <comment xml:lang="uk">документ PDF (стиснений bzip2)</comment>
+ <comment xml:lang="sv">PDF-dokument (bzip2-komprimerat)</comment>
+ <comment xml:lang="ru">Документ PDF (сжатый bzip2)</comment>
+ <comment xml:lang="pl">Dokument PDF (kompresja bzip2)</comment>
+ <comment xml:lang="es">documento PDF (comprimido con BZIP2)</comment>
+ <comment xml:lang="de">PDF-Dokument (bzip2-komprimiert)</comment>
+ <sub-class-of type="application/x-bzip2"/>
<generic-icon name="x-office-document"/>
<glob pattern="*.pdf.bz2"/>
</mime-type>
<mime-type type="application/x-bzpostscript">
- <comment>PostScript document (bzip-compressed)</comment>
- <comment xml:lang="zh_TW">PostScript 文件 (bzip 壓縮)</comment>
- <comment xml:lang="zh_CN">PostScript 文档(bzip 压缩)</comment>
- <comment xml:lang="vi">Tài liệu PostScript (đã nén bzip)</comment>
- <comment xml:lang="uk">документ PostScript (стиснене bzip)</comment>
- <comment xml:lang="tr">PostScript belgesi (bzip ile sıkıştırılmış)</comment>
- <comment xml:lang="sv">Postscript-dokument (bzip-komprimerat)</comment>
- <comment xml:lang="sr">Постскрипт документ (запакован бзипом)</comment>
- <comment xml:lang="sq">Dokument PostScript (i kompresuar me bzip)</comment>
- <comment xml:lang="sl">Dokument PostScript (stisnjen z bzip)</comment>
- <comment xml:lang="sk">Dokument PostScript (komprimovaný pomocou bzip)</comment>
- <comment xml:lang="ru">Документ PostScript (сжатый bzip)</comment>
- <comment xml:lang="ro">Document PostScript (comprimat bzip)</comment>
- <comment xml:lang="pt_BR">Documento PostScript (compactado com bzip)</comment>
- <comment xml:lang="pt">documento PostScript (compressão bzip)</comment>
- <comment xml:lang="pl">Dokument PostScript (kompresja bzip)</comment>
- <comment xml:lang="oc">document PostEscript (compressat bzip)</comment>
- <comment xml:lang="nn">PostScript-dokument (pakka med bzip)</comment>
- <comment xml:lang="nl">PostScript-document (ingepakt met bzip)</comment>
- <comment xml:lang="nb">PostScript-dokument (bzip-komprimert)</comment>
- <comment xml:lang="lv">PostScript dokuments (saspiests ar bzip)</comment>
- <comment xml:lang="lt">PostScript dokumentas (suglaudintas su bzip)</comment>
- <comment xml:lang="ko">PostScript 문서(BZIP 압축)</comment>
- <comment xml:lang="kk">PostScript құжаты (bzip-пен сығылған)</comment>
- <comment xml:lang="ja">PostScript ドキュメント (bzip 圧縮)</comment>
- <comment xml:lang="it">Documento PostScript (compresso con bzip)</comment>
- <comment xml:lang="id">Dokumen PostScript (terkompresi bzip)</comment>
- <comment xml:lang="ia">Documento PostScript (comprimite con bzip)</comment>
- <comment xml:lang="hu">PostScript dokumentum (bzip tömörítésű)</comment>
- <comment xml:lang="hr">PostScript dokument (bzip sažet)</comment>
- <comment xml:lang="he">מסמך PostDcript (מכווץ ע״י bzip)</comment>
- <comment xml:lang="gl">documento PostScript (comprimido con bzip)</comment>
- <comment xml:lang="ga">cáipéis PostScript (comhbhrúite le bzip)</comment>
- <comment xml:lang="fur">document PostScript (comprimût cun bzip)</comment>
- <comment xml:lang="fr">document PostScript (compressé bzip)</comment>
- <comment xml:lang="fo">PostScript skjal (bzip-stappað)</comment>
- <comment xml:lang="fi">PostScript-asiakirja (bzip-pakattu)</comment>
- <comment xml:lang="eu">PostScript dokumentua (bzip-ekin konprimitua)</comment>
- <comment xml:lang="es">documento PostScript (comprimido con bzip)</comment>
- <comment xml:lang="en_GB">PostScript document (bzip-compressed)</comment>
- <comment xml:lang="el">Έγγραφο PostScript (συμπιεσμένο με bzip)</comment>
- <comment xml:lang="de">PostScript-Dokument (bzip-komprimiert)</comment>
- <comment xml:lang="da">PostScript-dokument (bzip-komprimeret)</comment>
- <comment xml:lang="cs">dokument PostScript (komprimovaný pomocí bzip)</comment>
- <comment xml:lang="ca">document PostScript (amb compressió bzip)</comment>
- <comment xml:lang="bg">Документ — PostScript, компресиран с bzip</comment>
- <comment xml:lang="be@latin">Dakument PostScript (bzip-skampresavany)</comment>
- <comment xml:lang="ast">Documentu PostScript (comprimíu en bzip)</comment>
- <comment xml:lang="ar">مستند PostScript (مضغوط-bzip)</comment>
- <comment xml:lang="af">PostScript-dokument (bzip-saamgepers)</comment>
- <sub-class-of type="application/x-bzip"/>
+ <comment>PostScript document (bzip2-compressed)</comment>
+ <comment xml:lang="uk">документ PostScript (стиснений bzip2)</comment>
+ <comment xml:lang="sv">Postscript-dokument (bzip2-komprimerat)</comment>
+ <comment xml:lang="ru">Документ PostScript (сжатый bzip2)</comment>
+ <comment xml:lang="pl">Dokument PostScript (kompresja bzip2)</comment>
+ <comment xml:lang="es">documento PostScript (comprimido con BZIP2)</comment>
+ <comment xml:lang="de">PostScript-Dokument (bzip2-komprimiert)</comment>
+ <sub-class-of type="application/x-bzip2"/>
<generic-icon name="x-office-document"/>
<glob pattern="*.ps.bz2"/>
</mime-type>
<mime-type type="application/vnd.comicbook-rar">
- <comment>comic book archive (rar container)</comment>
+ <comment>Comic book archive (rar container)</comment>
+ <comment xml:lang="uk">архів коміксів (контейнер rar)</comment>
+ <comment xml:lang="sv">Serietidningsarkiv (rar-behållare)</comment>
+ <comment xml:lang="ru">Архив комиксов (rar-контейнер)</comment>
+ <comment xml:lang="pl">Archiwum komiksu (kontener RAR)</comment>
+ <comment xml:lang="it">Archivio comic book (contenitore rar)</comment>
+ <comment xml:lang="gl">Arquivo de libro de banda deseñada (contedor rar)</comment>
+ <comment xml:lang="es">archivador de libro de historietas (contenedor RAR)</comment>
+ <comment xml:lang="de">Comic-Book-Archiv (rar-Container)</comment>
+ <comment xml:lang="be">архіў comic book (кантэйнер rar)</comment>
<sub-class-of type="application/vnd.rar"/>
<generic-icon name="x-office-document"/>
<glob pattern="*.cbr"/>
<alias type="application/x-cbr"/>
</mime-type>
<mime-type type="application/x-cb7">
- <comment>comic book archive (7z container)</comment>
+ <comment>Comic book archive (7z container)</comment>
+ <comment xml:lang="uk">архів коміксів (контейнер 7z)</comment>
+ <comment xml:lang="sv">Serietidningsarkiv (7z-behållare)</comment>
+ <comment xml:lang="ru">Архив комиксов (7z-контейнер)</comment>
+ <comment xml:lang="pl">Archiwum komiksu (kontener 7z)</comment>
+ <comment xml:lang="it">Archivio comic book (contenitore 7z)</comment>
+ <comment xml:lang="gl">Arquivo de libro de banda deseñada (contedor 7z)</comment>
+ <comment xml:lang="es">archivador de libro de historietas (contenedor 7Z)</comment>
+ <comment xml:lang="de">Comic-Book-Archiv (7z-Container)</comment>
+ <comment xml:lang="be">архіў comic book (кантэйнер 7z)</comment>
<sub-class-of type="application/x-7z-compressed"/>
<generic-icon name="x-office-document"/>
<glob pattern="*.cb7"/>
</mime-type>
<mime-type type="application/x-cbt">
- <comment>comic book archive (tar container)</comment>
+ <comment>Comic book archive (tar container)</comment>
+ <comment xml:lang="uk">архів коміксів (контейнер tar)</comment>
+ <comment xml:lang="sv">Serietidningsarkiv (tar-behållare)</comment>
+ <comment xml:lang="ru">Архив комиксов (tar-контейнер)</comment>
+ <comment xml:lang="pl">Archiwum komiksu (kontener tar)</comment>
+ <comment xml:lang="it">Archivio comic book (contenitore tar)</comment>
+ <comment xml:lang="gl">Arquivo de libro de banda deseñada (contedor tar)</comment>
+ <comment xml:lang="es">archivador de libro de historietas (contenedor TAR)</comment>
+ <comment xml:lang="de">Comic-Book-Archiv (tar-Container)</comment>
+ <comment xml:lang="be">архіў comic book (кантэйнер tar)</comment>
<sub-class-of type="application/x-tar"/>
<generic-icon name="x-office-document"/>
<glob pattern="*.cbt"/>
</mime-type>
<mime-type type="application/vnd.comicbook+zip">
- <comment>comic book archive (zip container)</comment>
+ <comment>Comic book archive (zip container)</comment>
+ <comment xml:lang="uk">архів коміксів (контейнер zip)</comment>
+ <comment xml:lang="sv">Serietidningsarkiv (zip-behållare)</comment>
+ <comment xml:lang="ru">Архив комиксов (zip-контейнер)</comment>
+ <comment xml:lang="pl">Archiwum komiksu (kontener ZIP)</comment>
+ <comment xml:lang="it">Archivio comic book (contenitore zip)</comment>
+ <comment xml:lang="gl">Arquivo de libro de banda deseñada (contedor zip)</comment>
+ <comment xml:lang="es">archivador de libro de historietas (contenedor ZIP)</comment>
+ <comment xml:lang="de">Comic-Book-Archiv (zip-Container)</comment>
+ <comment xml:lang="be">архіў comic book (кантэйнер zip)</comment>
<sub-class-of type="application/zip"/>
<generic-icon name="x-office-document"/>
<glob pattern="*.cbz"/>
@@ -8540,7 +8644,9 @@ command to generate the output files.
<comment xml:lang="tr">Lrzip arşivi</comment>
<comment xml:lang="sv">Lrzip-arkiv</comment>
<comment xml:lang="sr">Лрзип архива</comment>
+ <comment xml:lang="sq">arkiv Lrzip</comment>
<comment xml:lang="sl">Datoteka arhiva Lrzip</comment>
+ <comment xml:lang="si">Lrzip සංරක්ෂිතය</comment>
<comment xml:lang="sk">Archív Lrzip</comment>
<comment xml:lang="ru">Архив LRZIP</comment>
<comment xml:lang="ro">Arhivă Lrzip</comment>
@@ -8548,13 +8654,14 @@ command to generate the output files.
<comment xml:lang="pt">arquivo Lrzip</comment>
<comment xml:lang="pl">Archiwum lrzip</comment>
<comment xml:lang="oc">archiu lrzip</comment>
- <comment xml:lang="nl">Lrzip archief</comment>
+ <comment xml:lang="nl">Lrzip-archief</comment>
<comment xml:lang="lv">Lrzip arhīvs</comment>
<comment xml:lang="lt">Lrzip archyvas</comment>
<comment xml:lang="ko">LRZIP 압축 파일</comment>
<comment xml:lang="kk">Lrzip архиві</comment>
<comment xml:lang="ja">Lrzip アーカイブ</comment>
<comment xml:lang="it">Archivio Lrzip</comment>
+ <comment xml:lang="is">Lrzip safnskrá</comment>
<comment xml:lang="id">Arsip Lrzip</comment>
<comment xml:lang="ia">Archivo Lrzip</comment>
<comment xml:lang="hu">Lrzip archívum</comment>
@@ -8567,7 +8674,7 @@ command to generate the output files.
<comment xml:lang="fo">Lrzip skjalasavn</comment>
<comment xml:lang="fi">Lrzip-arkisto</comment>
<comment xml:lang="eu">Lrzip artxiboa</comment>
- <comment xml:lang="es">archivador Lrzip</comment>
+ <comment xml:lang="es">archivador LRZIP</comment>
<comment xml:lang="eo">Lrzip-arkivo</comment>
<comment xml:lang="en_GB">Lrzip archive</comment>
<comment xml:lang="el">Συμπιεσμένο αρχείο Lrzip</comment>
@@ -8576,6 +8683,7 @@ command to generate the output files.
<comment xml:lang="cs">archiv Lrzip</comment>
<comment xml:lang="ca">arxiu lrzip</comment>
<comment xml:lang="bg">Архив — lrzip</comment>
+ <comment xml:lang="be">архіў Lrzip</comment>
<comment xml:lang="ar">أرشيف Lrzip</comment>
<comment xml:lang="af">Lrzip-argief</comment>
<acronym>Lrzip</acronym>
@@ -8594,7 +8702,9 @@ command to generate the output files.
<comment xml:lang="tr">Tar arşivi (lrzip ile sıkıştırılmış)</comment>
<comment xml:lang="sv">Tar-arkiv (lrzip-komprimerat)</comment>
<comment xml:lang="sr">Тар архива (запакована лрзипом)</comment>
+ <comment xml:lang="sq">arkiv tar (ngjeshur me lrzip)</comment>
<comment xml:lang="sl">Datoteka arhiva Tar (stisnjen z lrzip)</comment>
+ <comment xml:lang="si">තාර සංරක්ෂිතය (lrzip-සම්පීඩිත)</comment>
<comment xml:lang="sk">Archív Tar (komprimovaný pomocou lrzip)</comment>
<comment xml:lang="ru">Архив TAR (сжатый lrzip)</comment>
<comment xml:lang="ro">Arhivă Tar (comprimată lrzip)</comment>
@@ -8602,13 +8712,14 @@ command to generate the output files.
<comment xml:lang="pt">arquivo Tar (compressão Lrzip)</comment>
<comment xml:lang="pl">Archiwum tar (kompresja lrzip)</comment>
<comment xml:lang="oc">archiu tar (compressat lrzip)</comment>
- <comment xml:lang="nl">Tar archief (lrzip-compressed)</comment>
+ <comment xml:lang="nl">Tar-archief (gecomprimeerd met lrzip)</comment>
<comment xml:lang="lv">Tar arhīvs (saspiests ar lrzip)</comment>
<comment xml:lang="lt">Tar archyvas (suglaudintas su lrzip)</comment>
<comment xml:lang="ko">TAR 묶음 파일(LRZIP 압축)</comment>
<comment xml:lang="kk">Tar архиві (lrzip-пен сығылған)</comment>
<comment xml:lang="ja">Tar アーカイブ (lrzip 圧縮)</comment>
<comment xml:lang="it">Archivio tar (compresso con lrzip)</comment>
+ <comment xml:lang="is">Tar safnskrá (lrzip-þjappað)</comment>
<comment xml:lang="id">Arsip Tar (terkompresi lrzip)</comment>
<comment xml:lang="ia">Archivo Tar (comprimite con lrzip)</comment>
<comment xml:lang="hu">Tar archívum (lrzip tömörítésű)</comment>
@@ -8621,7 +8732,7 @@ command to generate the output files.
<comment xml:lang="fo">Tar skjalasavn (lrzip-stappað)</comment>
<comment xml:lang="fi">Tar-arkisto (lrzip-pakattu)</comment>
<comment xml:lang="eu">Tar artxiboa (lrzip-ekin konprimitua)</comment>
- <comment xml:lang="es">archivador Tar (comprimido con lrzip)</comment>
+ <comment xml:lang="es">archivador TAR (comprimido con LRZIP)</comment>
<comment xml:lang="en_GB">Tar archive (lrzip-compressed)</comment>
<comment xml:lang="el">Αρχείο Tar (συμπιεσμένο με lrzip)</comment>
<comment xml:lang="de">Tar-Archiv (lrzip-komprimiert)</comment>
@@ -8629,6 +8740,7 @@ command to generate the output files.
<comment xml:lang="cs">archiv Tar (komprimovaný pomocí lrzip)</comment>
<comment xml:lang="ca">arxiu tar (amb compressió lrzip)</comment>
<comment xml:lang="bg">Архив — tar, компресиран с lrzip</comment>
+ <comment xml:lang="be">архіў tar (сцісканне lrzip)</comment>
<comment xml:lang="ar">أرشيف Tar (مضغوط-lrzip)</comment>
<comment xml:lang="af">Tar-argief (lrzip-saamgepers)</comment>
<generic-icon name="package-x-generic"/>
@@ -8644,20 +8756,23 @@ command to generate the output files.
<comment xml:lang="tr">Apple disk görüntüsü</comment>
<comment xml:lang="sv">Apple-diskavbild</comment>
<comment xml:lang="sr">Еплов одраз диска</comment>
+ <comment xml:lang="sq">pamje disku Apple</comment>
<comment xml:lang="sl">Odtis diska Apple</comment>
+ <comment xml:lang="si">ඇපල් තැටි රූපය</comment>
<comment xml:lang="sk">Obraz disku Apple</comment>
<comment xml:lang="ru">Образ диска Apple Mac OS X</comment>
<comment xml:lang="pt_BR">Imagem de disco Apple</comment>
<comment xml:lang="pt">imagem de disco Apple</comment>
<comment xml:lang="pl">Obraz dysku Apple</comment>
<comment xml:lang="oc">imatge disc Apple</comment>
- <comment xml:lang="nl">Apple disk image</comment>
+ <comment xml:lang="nl">Apple-schijfkopiebestand</comment>
<comment xml:lang="lv">Apple diska attēls</comment>
<comment xml:lang="ko">Apple 디스크 이미지</comment>
<comment xml:lang="kk">Apple диск бейнесі</comment>
<comment xml:lang="ka">Apple-ის სადისკო გამოსახულება</comment>
<comment xml:lang="ja">Apple ディスクイメージ</comment>
<comment xml:lang="it">Immagine disco Apple</comment>
+ <comment xml:lang="is">Apple diskmynd</comment>
<comment xml:lang="id">Image disk Apple</comment>
<comment xml:lang="ia">Imagine de disco Apple</comment>
<comment xml:lang="hu">Apple lemezkép</comment>
@@ -8677,12 +8792,13 @@ command to generate the output files.
<comment xml:lang="cs">obraz disku Apple</comment>
<comment xml:lang="ca">imatge de disc d'Apple</comment>
<comment xml:lang="bg">Диск — Apple</comment>
+ <comment xml:lang="be">вобраз дыска Apple</comment>
<comment xml:lang="ast">Imaxe de discu d'Apple</comment>
<comment xml:lang="ar">صورة قرص أبل</comment>
<comment xml:lang="af">Apple-skyfbeeldlêer</comment>
<glob pattern="*.dmg"/>
</mime-type>
- <mime-type type="application/x-raw-disk-image">
+ <mime-type type="application/vnd.efi.img">
<comment>Raw disk image</comment>
<comment xml:lang="zh_TW">原始磁碟映像檔</comment>
<comment xml:lang="zh_CN">原始磁盘映像</comment>
@@ -8690,17 +8806,21 @@ command to generate the output files.
<comment xml:lang="tr">Ham disk görüntüsü</comment>
<comment xml:lang="sv">Rå diskavbild</comment>
<comment xml:lang="sr">сиров одраз диска</comment>
+ <comment xml:lang="sq">pamje disku e papërpunuar</comment>
<comment xml:lang="sl">Surovi odtis diska</comment>
+ <comment xml:lang="si">අමු තැටි රූපය</comment>
<comment xml:lang="sk">Obraz disku</comment>
<comment xml:lang="ru">Необработанный образ диска</comment>
<comment xml:lang="pt_BR">Imagem bruta de disco</comment>
<comment xml:lang="pt">imagem de disco Raw</comment>
<comment xml:lang="pl">Surowy obraz dysku</comment>
<comment xml:lang="oc">imatge disc Raw</comment>
+ <comment xml:lang="nl">Onbewerkt schijfkopiebestand</comment>
<comment xml:lang="ko">RAW 디스크 이미지</comment>
<comment xml:lang="kk">Шикі диск бейнесі</comment>
<comment xml:lang="ja">Raw ディスクイメージ</comment>
<comment xml:lang="it">Immagine disco raw</comment>
+ <comment xml:lang="is">Hrá diskmynd</comment>
<comment xml:lang="id">Image disk mentah</comment>
<comment xml:lang="ia">Imagine de disco crude</comment>
<comment xml:lang="hu">Nyers lemezkép</comment>
@@ -8720,9 +8840,11 @@ command to generate the output files.
<comment xml:lang="cs">surový obraz disku</comment>
<comment xml:lang="ca">imatge de disc RAW</comment>
<comment xml:lang="bg">Диск — raw</comment>
+ <comment xml:lang="be">неапрацаваны вобраз дыска</comment>
<comment xml:lang="ast">Imaxe de discu en bruto</comment>
<comment xml:lang="ar">صورة قرص خام</comment>
<comment xml:lang="af">Rou skyfbeeldlêer</comment>
+ <alias type="application/x-raw-disk-image"/>
<glob pattern="*.raw-disk-image"/>
<glob pattern="*.img"/>
</mime-type>
@@ -8734,19 +8856,26 @@ command to generate the output files.
<comment xml:lang="tr">Disket görüntüsü</comment>
<comment xml:lang="sv">Diskettavbild</comment>
<comment xml:lang="sr">одраз флопи диска</comment>
+ <comment xml:lang="sq">pamje diskete</comment>
+ <comment xml:lang="sl">Slika diskete</comment>
+ <comment xml:lang="si">නම්ය තැටි රූපය</comment>
<comment xml:lang="sk">Obraz pružného disku</comment>
- <comment xml:lang="ru">Образ гибкого диска</comment>
+ <comment xml:lang="ru">Образ дискеты</comment>
<comment xml:lang="pt_BR">Imagem de disco flexível</comment>
<comment xml:lang="pt">imagem da disquete</comment>
<comment xml:lang="pl">Obraz dyskietki</comment>
+ <comment xml:lang="oc">imatge disc disqueta</comment>
+ <comment xml:lang="nl">Diskette-schijfkopiebestand</comment>
<comment xml:lang="ko">플로피 디스크 이미지</comment>
<comment xml:lang="kk">Иілгіш диск бейнесі</comment>
<comment xml:lang="ja">Floppy ディスクイメージ</comment>
<comment xml:lang="it">Immagine disco floppy</comment>
+ <comment xml:lang="is">Disklingsmynd</comment>
<comment xml:lang="id">Image disk floppy</comment>
<comment xml:lang="hu">Flopi lemezkép</comment>
<comment xml:lang="hr">Slika diskete</comment>
<comment xml:lang="he">דמות תקליטון</comment>
+ <comment xml:lang="gl">Imaxe de disco de Disquete</comment>
<comment xml:lang="ga">íomhá diosca fhlapaigh</comment>
<comment xml:lang="fur">imagjin disc floppy</comment>
<comment xml:lang="fr">image disquette</comment>
@@ -8759,9 +8888,11 @@ command to generate the output files.
<comment xml:lang="cs">obraz diskety</comment>
<comment xml:lang="ca">imatge de disquet</comment>
<comment xml:lang="bg">Диск — флопи</comment>
+ <comment xml:lang="be">вобраз гнуткага дыска</comment>
<comment xml:lang="ar">صورة قرص مرن</comment>
<comment xml:lang="af">Disket-skyfbeeldlêer</comment>
- <sub-class-of type="application/x-raw-disk-image"/>
+ <sub-class-of type="application/vnd.efi.img"/>
+ <generic-icon name="media-floppy"/>
<alias type="application/x-fd-file"/>
<glob pattern="*.fd"/>
<glob pattern="*.qd"/>
@@ -8774,17 +8905,21 @@ command to generate the output files.
<comment xml:lang="tr">Ham disk görüntüsü (XZ ile sıkıştırılmış)</comment>
<comment xml:lang="sv">Rå diskavbild (XZ-komprimerad)</comment>
<comment xml:lang="sr">сиров одраз диска (запакована ИксЗ-ом)</comment>
+ <comment xml:lang="sq">pamje disku e papërpunuar (ngjeshur me XZ)</comment>
<comment xml:lang="sl">Surovi odtis diska (stisnjeno z XZ)</comment>
+ <comment xml:lang="si">අමු තැටි රූපය (XZ-සම්පීඩිත)</comment>
<comment xml:lang="sk">Obraz disku (komprimovaný pomocou XZ)</comment>
- <comment xml:lang="ru">Необработанный образ диска (сжатый xz)</comment>
+ <comment xml:lang="ru">Необработанный образ диска (сжатый XZ)</comment>
<comment xml:lang="pt_BR">Imagem bruta de disco (compactada com XZ)</comment>
<comment xml:lang="pt">imagem de disco Raw (compressão XZ)</comment>
<comment xml:lang="pl">Surowy obraz dysku (kompresja XZ)</comment>
<comment xml:lang="oc">imatge disc Raw (compression XZ)</comment>
+ <comment xml:lang="nl">Onbewerkt schijfkopiebestand (gecomprimeerd met XZ)</comment>
<comment xml:lang="ko">RAW 디스크 이미지(XZ 압축)</comment>
<comment xml:lang="kk">Шикі диск бейнесі (XZ-мен сығылған)</comment>
<comment xml:lang="ja">Raw ディスクイメージ (XZ 圧縮)</comment>
<comment xml:lang="it">Immagine disco raw (compressa XZ)</comment>
+ <comment xml:lang="is">Hrá diskmynd (XZ-þjöppuð)</comment>
<comment xml:lang="id">Image disk mentah (terkompresi XZ)</comment>
<comment xml:lang="ia">Imagine de disco crude (comprimite con XZ)</comment>
<comment xml:lang="hu">Nyers lemezkép (XZ tömörítésű)</comment>
@@ -8804,6 +8939,7 @@ command to generate the output files.
<comment xml:lang="cs">surový obraz disku (komprimovaný pomocí XZ)</comment>
<comment xml:lang="ca">imatge de disc RAW (amb compressió XZ)</comment>
<comment xml:lang="bg">Диск — raw, компресиран с xz</comment>
+ <comment xml:lang="be">неапрацаваны вобраз дыска (сцісканне XZ)</comment>
<comment xml:lang="ast">Imaxe de discu en bruto (comprimida en XZ)</comment>
<comment xml:lang="ar">صورة قرص خام (مضغوطة-ZX)</comment>
<comment xml:lang="af">Rou skyfbeeldlêer (XZ-saamgepers)</comment>
@@ -8811,60 +8947,21 @@ command to generate the output files.
<glob pattern="*.raw-disk-image.xz"/>
<glob pattern="*.img.xz"/>
</mime-type>
- <mime-type type="application/x-cd-image">
- <comment>raw CD image</comment>
- <comment xml:lang="zh_TW">原生 CD 映像檔</comment>
- <comment xml:lang="zh_CN">原始 CD 映像</comment>
- <comment xml:lang="vi">ảnh đĩa CD thô</comment>
- <comment xml:lang="uk">образ raw CD</comment>
- <comment xml:lang="tr">ham CD görüntüsü</comment>
- <comment xml:lang="sv">rå cd-avbild</comment>
- <comment xml:lang="sr">сиров одраз ЦД-а</comment>
- <comment xml:lang="sq">Imazh raw CD</comment>
- <comment xml:lang="sl">surovi CD odtis</comment>
- <comment xml:lang="sk">Surový obraz CD</comment>
+ <mime-type type="application/vnd.efi.iso">
+ <comment>Raw CD image</comment>
+ <comment xml:lang="uk">простий образ CD</comment>
+ <comment xml:lang="sv">Rå cd-avbild</comment>
<comment xml:lang="ru">Необработанный образ компакт-диска</comment>
- <comment xml:lang="ro">imagine de CD brută</comment>
- <comment xml:lang="pt_BR">Imagem bruta de CD</comment>
- <comment xml:lang="pt">imagem em bruto de CD</comment>
<comment xml:lang="pl">Surowy obraz CD</comment>
- <comment xml:lang="oc">imatge CD brut</comment>
- <comment xml:lang="nn">rått CD-bilete</comment>
- <comment xml:lang="nl">ruw CD-beeldbestand</comment>
- <comment xml:lang="nb">rått CD-bilde</comment>
- <comment xml:lang="ms">Imej CD mentah</comment>
- <comment xml:lang="lv">CD jēlattēls</comment>
- <comment xml:lang="lt">raw CD atvaizdis</comment>
- <comment xml:lang="ko">CD 이미지</comment>
- <comment xml:lang="kk">өңделмеген CD бейнесі</comment>
- <comment xml:lang="ja">生 CD イメージ</comment>
<comment xml:lang="it">Immagine raw CD</comment>
- <comment xml:lang="id">citra CD mentah</comment>
- <comment xml:lang="ia">Imagine CD brute</comment>
- <comment xml:lang="hu">nyers CD-lemezkép</comment>
- <comment xml:lang="hr">Osnovna CD slika</comment>
- <comment xml:lang="he">תמונת דיסק גולמית</comment>
- <comment xml:lang="gl">imaxe de CD en bruto</comment>
- <comment xml:lang="ga">amhíomhá dhlúthdhiosca</comment>
- <comment xml:lang="fur">imagjin CD grese</comment>
- <comment xml:lang="fr">image CD brute</comment>
- <comment xml:lang="fo">rá CD mynd</comment>
- <comment xml:lang="fi">raaka CD-levykuva</comment>
- <comment xml:lang="eu">CD gordinaren irudia </comment>
+ <comment xml:lang="gl">Imaxe de CD en bruto</comment>
+ <comment xml:lang="eu">CD irudi gordina</comment>
<comment xml:lang="es">imagen de CD en bruto</comment>
- <comment xml:lang="eo">kruda lumdiskbildo</comment>
- <comment xml:lang="en_GB">raw CD image</comment>
- <comment xml:lang="el">Εικόνα περιεχομένου ψηφιακού δίσκου</comment>
<comment xml:lang="de">CD-Roh-Abbild</comment>
- <comment xml:lang="da">raw cd-aftryk</comment>
- <comment xml:lang="cs">surový obraz CD</comment>
- <comment xml:lang="ca">imatge de CD en cru</comment>
- <comment xml:lang="bg">Диск — raw CD</comment>
- <comment xml:lang="be@latin">suvoraja vyjava CD</comment>
- <comment xml:lang="ast">imaxe de CD en bruto</comment>
- <comment xml:lang="ar">صورة CD خامة</comment>
- <comment xml:lang="af">rou CD-beeldlêer</comment>
- <sub-class-of type="application/x-raw-disk-image"/>
+ <comment xml:lang="be">Неапрацаваны вобраз CD</comment>
+ <sub-class-of type="application/vnd.efi.img"/>
+ <generic-icon name="media-optical"/>
+ <alias type="application/x-cd-image"/>
<alias type="application/x-iso9660-image"/>
<!-- No magic, see https://bugs.freedesktop.org/show_bug.cgi?id=10049 -->
<glob pattern="*.iso" weight="80"/>
@@ -8872,29 +8969,40 @@ command to generate the output files.
</mime-type>
<mime-type type="application/x-compressed-iso">
<comment>Compressed CD image</comment>
+ <comment xml:lang="zh_CN">压缩的 CD 映像</comment>
<comment xml:lang="uk">стиснений образ CD</comment>
<comment xml:lang="tr">Sıkıştırılmış CD görüntüsü</comment>
<comment xml:lang="sv">Komprimerad cd-avbild</comment>
<comment xml:lang="sr">компресовани ЦД одраз</comment>
+ <comment xml:lang="sl">Stisnjena slika CD</comment>
+ <comment xml:lang="si">සම්පීඩිත CD රූපය</comment>
+ <comment xml:lang="ru">Сжатый образ компакт-диска</comment>
<comment xml:lang="pt_BR">Imagem de CD compactada</comment>
<comment xml:lang="pt">Imagem de CD comprimida</comment>
<comment xml:lang="pl">Skompresowany obraz płyty CD</comment>
<comment xml:lang="oc">imatge CD compressat</comment>
+ <comment xml:lang="nl">Gecomprimeerd CD-schijfkopiebestand</comment>
<comment xml:lang="ko">압축된 CD 이미지</comment>
+ <comment xml:lang="kk">Сығылған CD бейнесі</comment>
<comment xml:lang="ja">圧縮 CD イメージ</comment>
<comment xml:lang="it">Immagine CD compressa</comment>
+ <comment xml:lang="is">Þjöppuð CD diskmynd</comment>
<comment xml:lang="id">Image CD terkompresi</comment>
<comment xml:lang="hu">Tömörített CD lemezkép</comment>
<comment xml:lang="hr">Sažeta CD slika</comment>
<comment xml:lang="he">דמות תקליטור דחוסה</comment>
+ <comment xml:lang="gl">Imaxe de CD comprimido</comment>
<comment xml:lang="fr">Image CD compressée</comment>
<comment xml:lang="fi">Pakattu CD-levykuva</comment>
+ <comment xml:lang="eu">Konprimatutako CD irudia</comment>
<comment xml:lang="es">imagen comprimida de CD</comment>
<comment xml:lang="en_GB">Compressed CD image</comment>
<comment xml:lang="de">Komprimiertes CD-Abbild</comment>
<comment xml:lang="da">Komprimeret CD-aftryk</comment>
<comment xml:lang="ca">imatge de CD amb compressió</comment>
+ <comment xml:lang="be">сціснуты вобраз CD</comment>
<comment xml:lang="ar">صورة سي دي مضغوطة</comment>
+ <generic-icon name="media-optical"/>
<magic>
<match value="CISO" type="string" offset="0"/>
</magic>
@@ -8908,19 +9016,24 @@ command to generate the output files.
<comment xml:lang="tr">AppImage uygulama paketi</comment>
<comment xml:lang="sv">AppImage-programbunt</comment>
<comment xml:lang="sr">скуп програма Ап-слике</comment>
+ <comment xml:lang="sq">paketë aplikacioni AppImage</comment>
+ <comment xml:lang="si">AppImage යෙදුම් මිටියක්</comment>
<comment xml:lang="sk">Balík aplikácií AppImage</comment>
<comment xml:lang="ru">Пакет приложения AppImage</comment>
<comment xml:lang="pt_BR">Pacote de aplicativo AppImage</comment>
<comment xml:lang="pt">pacote de aplicação AppImage</comment>
<comment xml:lang="pl">Pakiet programu AppImage</comment>
+ <comment xml:lang="nl">AppImage-toepassingsbundel</comment>
<comment xml:lang="ko">AppImage 프로그램 번들</comment>
<comment xml:lang="kk">AppImage қолданбалар дестесі</comment>
<comment xml:lang="ja">AppImage アプリケーションバンドル</comment>
<comment xml:lang="it">Bundle applicazione AppImage</comment>
+ <comment xml:lang="is">AppImage forritavöndull</comment>
<comment xml:lang="id">Bundel aplikasi AppImage</comment>
<comment xml:lang="hu">AppImage alkalmazáscsomag</comment>
<comment xml:lang="hr">AppImage paket aplikacije</comment>
<comment xml:lang="he">חבילת יישומי AppImage</comment>
+ <comment xml:lang="gl">Paquete de aplicación de AppImage</comment>
<comment xml:lang="ga">burla feidhmchláir AppImage</comment>
<comment xml:lang="fur">côl di aplicazions AppImage</comment>
<comment xml:lang="fr">lot applicatif AppImage</comment>
@@ -8933,10 +9046,11 @@ command to generate the output files.
<comment xml:lang="cs">balíček AppImage s aplikací</comment>
<comment xml:lang="ca">paquet d'aplicació AppImage</comment>
<comment xml:lang="bg">Програмен пакет — AppImage</comment>
+ <comment xml:lang="be">пакет праграмы AppImage</comment>
<comment xml:lang="ar">حزمة تطبيق AppImage</comment>
<comment xml:lang="af">AppImage-toepassingsbundel</comment>
<sub-class-of type="application/x-executable"/>
- <sub-class-of type="application/x-cd-image"/>
+ <sub-class-of type="application/vnd.efi.iso"/>
<generic-icon name="application-x-executable"/>
<magic>
<match value="ELF" type="string" offset="1">
@@ -8958,10 +9072,11 @@ command to generate the output files.
<comment xml:lang="tr">CD İçindekiler Tablosu</comment>
<comment xml:lang="sv">Cd-innehållsförteckning</comment>
<comment xml:lang="sr">табела садржаја ЦД-а</comment>
- <comment xml:lang="sq">Tregues CD</comment>
+ <comment xml:lang="sq">Tryezë Lënde CD</comment>
<comment xml:lang="sl">Kazalo vsebine CD nosilca</comment>
+ <comment xml:lang="si">CD පටුන</comment>
<comment xml:lang="sk">Obsah CD</comment>
- <comment xml:lang="ru">Таблица содержания CD</comment>
+ <comment xml:lang="ru">Содержание компакт-диска</comment>
<comment xml:lang="ro">Tabel conținut CD</comment>
<comment xml:lang="pt_BR">Sumário de CD</comment>
<comment xml:lang="pt">Tabela de conteúdos de CD</comment>
@@ -8976,6 +9091,7 @@ command to generate the output files.
<comment xml:lang="kk">CD құрама кестесі</comment>
<comment xml:lang="ja">CD Table Of Contents</comment>
<comment xml:lang="it">Indice CD</comment>
+ <comment xml:lang="is">Efnisyfirlit CD-disks</comment>
<comment xml:lang="id">Tabel Isi CD</comment>
<comment xml:lang="ia">Tabula de contento de CD</comment>
<comment xml:lang="hu">CD tartalomjegyzék</comment>
@@ -8997,6 +9113,7 @@ command to generate the output files.
<comment xml:lang="ca">taula de continguts de CD</comment>
<comment xml:lang="bg">Съдържание на CD</comment>
<comment xml:lang="be@latin">Źmieściva CD</comment>
+ <comment xml:lang="be">табліца змесціва CD</comment>
<comment xml:lang="ar">جدول محتويات CD</comment>
<comment xml:lang="af">CD-inhoudsopgawe</comment>
<sub-class-of type="text/plain"/>
@@ -9017,11 +9134,16 @@ command to generate the output files.
<comment xml:lang="uk">таблиця CUE образу GD-ROM</comment>
<comment xml:lang="tr">GD-ROM görüntüsü çizelgesi</comment>
<comment xml:lang="sv">GD-ROM Indexblad för cd-avbild</comment>
+ <comment xml:lang="si">GD-ROM රූප කුට්ටිය</comment>
+ <comment xml:lang="ru">Файл разметки образа GD-ROM</comment>
<comment xml:lang="pt_BR">Índice de Imagem de GD-ROM</comment>
<comment xml:lang="pl">Obraz cuesheet płyty GD-ROM</comment>
+ <comment xml:lang="nl">GD-ROM-schijfkopiebestand-cue-sheet</comment>
<comment xml:lang="ko">GD-ROM 이미지 큐시트</comment>
+ <comment xml:lang="kk">GD-ROM бейнесінің құрама кестесі</comment>
<comment xml:lang="ja">GD-ROM イメージキューシート</comment>
<comment xml:lang="it">Cuesheet immagine GD-ROM</comment>
+ <comment xml:lang="is">cuesheet CD-ROM diskmyndar</comment>
<comment xml:lang="id">cuesheet image GD-ROM</comment>
<comment xml:lang="hu">GD-ROM lemezkép-jelölőlap</comment>
<comment xml:lang="hr">GD-ROM popis slika</comment>
@@ -9033,6 +9155,7 @@ command to generate the output files.
<comment xml:lang="de">GD-ROM-Abbild-Cuesheet</comment>
<comment xml:lang="da">GD-ROM-aftrykscuesheet</comment>
<comment xml:lang="ca">«cuesheet» d'imatge de GD-ROM</comment>
+ <comment xml:lang="be">табліца разметкі вобраза GD-ROM</comment>
<comment xml:lang="ar">صفيحة صورة الـGD-ROM جديلة</comment>
<!-- It is a non-standard cuesheet used only for Dreamcast GD-ROM images, it
is typically surrounded by the .bin and .raw files it lists, each one
@@ -9044,18 +9167,25 @@ command to generate the output files.
</mime-type>
<mime-type type="application/x-discjuggler-cd-image">
<comment>Padus DiscJuggler CD image</comment>
+ <comment xml:lang="zh_CN">Padus DiscJuggler CD 映像</comment>
<comment xml:lang="uk">образ CD Padus DiscJuggler</comment>
<comment xml:lang="tr">Padus DiscJuggler CD görüntüsü</comment>
<comment xml:lang="sv">Padus DiscJuggler cd-avbild</comment>
+ <comment xml:lang="si">Padus DiscJuggler CD රූපය</comment>
+ <comment xml:lang="ru">Образ диска Padus DiscJuggler CD</comment>
<comment xml:lang="pt_BR">Imagem de CD do Padus DiscJuggler</comment>
<comment xml:lang="pl">Obraz płyty CD programu Padus DiscJuggler</comment>
+ <comment xml:lang="nl">Padus DiscJuggler CD-schijfkopiebestand</comment>
<comment xml:lang="ko">Padus DiscJuggler CD 이미지</comment>
+ <comment xml:lang="kk">Padus DiscJuggler CD бейнесі</comment>
<comment xml:lang="ja">Padus DiscJuggler CD イメージ</comment>
<comment xml:lang="it">Immagine CD DiscJuggler Padus</comment>
+ <comment xml:lang="is">Padus DiscJuggler CD diskmynd</comment>
<comment xml:lang="id">image CD Padus DiscJuggler</comment>
<comment xml:lang="hu">Padus DiscJuggler CD lemezkép</comment>
<comment xml:lang="hr">Padus DiscJuggler CD slika</comment>
<comment xml:lang="he">תמונת תקליטור Padus DiscJuggler</comment>
+ <comment xml:lang="gl">Imaxe de CD Padus DiscJuggler</comment>
<comment xml:lang="fr">Image CD Padus DiscJuggler</comment>
<comment xml:lang="fi">Padus DiscJuggler CD-levykuva</comment>
<comment xml:lang="es">imagen de CD de Padus DiscJuggler</comment>
@@ -9063,7 +9193,9 @@ command to generate the output files.
<comment xml:lang="de">Padus-DiscJuggler-CD-Abbild</comment>
<comment xml:lang="da">Padus DiscJuggler CD-aftryk</comment>
<comment xml:lang="ca">imatge de CD de Padus DiscJuggler</comment>
+ <comment xml:lang="be">вобраз CD Padus DiscJuggler</comment>
<comment xml:lang="ar">صورة سي دي Padus DiscJuggler</comment>
+ <generic-icon name="media-optical"/>
<glob pattern="*.cdi"/>
</mime-type>
<mime-type type="application/vnd.chess-pgn">
@@ -9075,8 +9207,9 @@ command to generate the output files.
<comment xml:lang="tr">PGN satranç oyun gösterimi</comment>
<comment xml:lang="sv">PGN-schackpartinotation</comment>
<comment xml:lang="sr">ПГН забелешка шаховске игре</comment>
- <comment xml:lang="sq">Njoftim loje shahu PGN</comment>
+ <comment xml:lang="sq">sistem zbardhjeje loje shahu PGN</comment>
<comment xml:lang="sl">Datoteka opomb šahovske igre PGN</comment>
+ <comment xml:lang="si">PGN චෙස් ක්‍රීඩා අංකනය</comment>
<comment xml:lang="sk">Šachová notácia PGN</comment>
<comment xml:lang="ru">Шахматная партия PGN</comment>
<comment xml:lang="ro">Notație joc șah PGN</comment>
@@ -9093,6 +9226,7 @@ command to generate the output files.
<comment xml:lang="kk">PGN шахмат ойыны</comment>
<comment xml:lang="ja">PGN チェスゲーム記録</comment>
<comment xml:lang="it">Notazione partita a scacchi PGN</comment>
+ <comment xml:lang="is">færsla PGN skákleiks</comment>
<comment xml:lang="id">Notasi permainan catur PGN</comment>
<comment xml:lang="ia">Notation de joco de chacos PGN</comment>
<comment xml:lang="hu">PGN sakkfeljegyzés</comment>
@@ -9114,6 +9248,7 @@ command to generate the output files.
<comment xml:lang="ca">notació de joc d'escacs PGN</comment>
<comment xml:lang="bg">Игра шах — PGN</comment>
<comment xml:lang="be@latin">Zaciem ab šachmatnaj partyi PGN</comment>
+ <comment xml:lang="be">запіс шахматнай партыі PGN</comment>
<comment xml:lang="ar">تدوينة لعبة شطرنج PGN</comment>
<comment xml:lang="af">PGN-skaakspelnotasie</comment>
<acronym>PGN</acronym>
@@ -9135,8 +9270,9 @@ command to generate the output files.
<comment xml:lang="tr">CHM belgesi</comment>
<comment xml:lang="sv">CHM-dokument</comment>
<comment xml:lang="sr">ЦХМ документ</comment>
- <comment xml:lang="sq">Dokument CHM</comment>
+ <comment xml:lang="sq">dokument CHM</comment>
<comment xml:lang="sl">Dokument CHM</comment>
+ <comment xml:lang="si">CHM ලේඛනය</comment>
<comment xml:lang="sk">Dokument CHM</comment>
<comment xml:lang="ru">Документ CHM</comment>
<comment xml:lang="ro">Document CHM</comment>
@@ -9154,6 +9290,7 @@ command to generate the output files.
<comment xml:lang="ka">CHM დოკუმენტი</comment>
<comment xml:lang="ja">CHM ドキュメント</comment>
<comment xml:lang="it">Documento CHM</comment>
+ <comment xml:lang="is">CHM skjal</comment>
<comment xml:lang="id">Dokumen CHM</comment>
<comment xml:lang="ia">Documento CHM</comment>
<comment xml:lang="hu">CHM dokumentum</comment>
@@ -9176,6 +9313,7 @@ command to generate the output files.
<comment xml:lang="ca">document CHM</comment>
<comment xml:lang="bg">Документ — CHM</comment>
<comment xml:lang="be@latin">Dakument CHM</comment>
+ <comment xml:lang="be">дакумент CHM</comment>
<comment xml:lang="ast">Documentu CHM</comment>
<comment xml:lang="ar">مستند CHM</comment>
<comment xml:lang="af">CHM-dokument</comment>
@@ -9194,8 +9332,8 @@ command to generate the output files.
<comment xml:lang="tr">Java derlenmiş kodu</comment>
<comment xml:lang="sv">Java-bytekod</comment>
<comment xml:lang="sr">бајтни ко̂д Јаве</comment>
- <comment xml:lang="sq">Byte code Java</comment>
<comment xml:lang="sl">Datoteka bitne kode Java</comment>
+ <comment xml:lang="si">ජාවා බයිට් කේතය</comment>
<comment xml:lang="sk">Bajtový kód Java</comment>
<comment xml:lang="ru">Байт-код Java</comment>
<comment xml:lang="ro">Bytecode Java</comment>
@@ -9213,6 +9351,7 @@ command to generate the output files.
<comment xml:lang="kk">Java байт коды</comment>
<comment xml:lang="ja">Java バイトコード</comment>
<comment xml:lang="it">Bytecode Java</comment>
+ <comment xml:lang="is">Java bætkóði</comment>
<comment xml:lang="id">Kode bita Java</comment>
<comment xml:lang="ia">Codice intermediari de Java</comment>
<comment xml:lang="hu">Java-bájtkód</comment>
@@ -9236,6 +9375,7 @@ command to generate the output files.
<comment xml:lang="ca">bytecode de Java</comment>
<comment xml:lang="bg">Байт код за Java</comment>
<comment xml:lang="be@latin">Bajtavy kod Java</comment>
+ <comment xml:lang="be">байт-код Java</comment>
<comment xml:lang="az">Java bayt kodu</comment>
<comment xml:lang="ar">رمز بايت Java</comment>
<comment xml:lang="af">Java binêre kode</comment>
@@ -9249,10 +9389,11 @@ command to generate the output files.
<comment xml:lang="tr">UNIX-sıkıştırılmış dosyası</comment>
<comment xml:lang="sv">UNIX-komprimerad fil</comment>
<comment xml:lang="sr">датотека запакована ЈУНИКС-ом</comment>
- <comment xml:lang="sq">File i kompresuar UNIX</comment>
+ <comment xml:lang="sq">kartelë e ngjeshur me Unix</comment>
<comment xml:lang="sl">Skrčena Unix datoteka</comment>
+ <comment xml:lang="si">UNIX සම්පීඩිත ගොනුව</comment>
<comment xml:lang="sk">Súbor komprimovaný v Unixe</comment>
- <comment xml:lang="ru">Файл (UNIX-сжатый)</comment>
+ <comment xml:lang="ru">Сжатый файл UNIX</comment>
<comment xml:lang="ro">Fișier comprimat UNIX</comment>
<comment xml:lang="pt_BR">Arquivo compactado do UNIX</comment>
<comment xml:lang="pt">ficheiro comprimido UNIX</comment>
@@ -9268,6 +9409,7 @@ command to generate the output files.
<comment xml:lang="kk">файл (UNIX-сығылған)</comment>
<comment xml:lang="ja">UNIX-compress ファイル</comment>
<comment xml:lang="it">File compresso-UNIX</comment>
+ <comment xml:lang="is">UNIX-þjöppuð skrá</comment>
<comment xml:lang="id">Berkas terkompresi UNIX</comment>
<comment xml:lang="ia">File comprimite de UNIX</comment>
<comment xml:lang="hu">UNIX tömörítésű fájl</comment>
@@ -9290,6 +9432,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer amb compressió UNIX</comment>
<comment xml:lang="bg">Файл — компресиран за UNIX</comment>
<comment xml:lang="be@latin">Skampresavany UNIX-fajł</comment>
+ <comment xml:lang="be">файл сціснуты UNIX</comment>
<comment xml:lang="ar">ملف يونكس-مضغوط</comment>
<comment xml:lang="af">UNIX-saamgepersde lêer</comment>
<generic-icon name="package-x-generic"/>
@@ -9307,8 +9450,9 @@ command to generate the output files.
<comment xml:lang="tr">Tar arşivi (gzip ile sıkıştırılmış)</comment>
<comment xml:lang="sv">Tar-arkiv (gzip-komprimerat)</comment>
<comment xml:lang="sr">Тар архива (запакована гзипом)</comment>
- <comment xml:lang="sq">Arkiv tar (i kompresuar me gzip)</comment>
+ <comment xml:lang="sq">arkiv tar (ngjeshur me gzip)</comment>
<comment xml:lang="sl">Datoteka arhiva Tar (stisnjen z gzip)</comment>
+ <comment xml:lang="si">තාර සංරක්ෂිතය (gzip-සම්පීඩිත)</comment>
<comment xml:lang="sk">Archív Tar (komprimovaný pomocou gzip)</comment>
<comment xml:lang="ru">Архив TAR (сжатый gzip)</comment>
<comment xml:lang="ro">Arhivă Tar (comprimată gzip)</comment>
@@ -9325,6 +9469,7 @@ command to generate the output files.
<comment xml:lang="kk">Tar архиві (gzip-пен сығылған)</comment>
<comment xml:lang="ja">Tar アーカイブ (gzip 圧縮)</comment>
<comment xml:lang="it">Archivio tar (compresso con gzip)</comment>
+ <comment xml:lang="is">Tar safnskrá (Gzip þjappað)</comment>
<comment xml:lang="id">Arsip Tar (terkompresi gzip)</comment>
<comment xml:lang="ia">Archivo Tar (comprimite con gzip)</comment>
<comment xml:lang="hu">Tar archívum (gzip tömörítésű)</comment>
@@ -9337,7 +9482,7 @@ command to generate the output files.
<comment xml:lang="fo">Tar skjalasavn (gzip-stappað)</comment>
<comment xml:lang="fi">Tar-arkisto (gzip-pakattu)</comment>
<comment xml:lang="eu">Tar artxiboa (gzip-ekin konprimitua)</comment>
- <comment xml:lang="es">archivador Tar (comprimido con gzip)</comment>
+ <comment xml:lang="es">archivador TAR (comprimido con GZIP)</comment>
<comment xml:lang="en_GB">Tar archive (gzip-compressed)</comment>
<comment xml:lang="el">Αρχείο Tar (συμπιεσμένο με gzip)</comment>
<comment xml:lang="de">Tar-Archiv (gzip-komprimiert)</comment>
@@ -9346,6 +9491,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu tar (amb compressió gzip)</comment>
<comment xml:lang="bg">Архив — tar, компресиран с gzip</comment>
<comment xml:lang="be@latin">Archiŭ tar (gzip-skampresavany)</comment>
+ <comment xml:lang="be">архіў tar (сцісканне gzip)</comment>
<comment xml:lang="ar">أرشيف Tar (مضغوط-gzip)</comment>
<comment xml:lang="af">Tar-argief (gzip-saamgepers)</comment>
<sub-class-of type="application/gzip"/>
@@ -9354,57 +9500,15 @@ command to generate the output files.
<glob pattern="*.tgz"/>
</mime-type>
<mime-type type="application/x-core">
- <comment>program crash data</comment>
- <comment xml:lang="zh_TW">程式當掉資料</comment>
- <comment xml:lang="zh_CN">程序崩溃数据</comment>
- <comment xml:lang="vi">dữ liệu sụp đổ chương trình</comment>
- <comment xml:lang="uk">аварійні дані про програму</comment>
- <comment xml:lang="tr">program çökme verisi</comment>
- <comment xml:lang="sv">programkraschdata</comment>
- <comment xml:lang="sr">подаци о падовима програма</comment>
- <comment xml:lang="sq">Të dhëna nga programi i bllokuar</comment>
- <comment xml:lang="sl">podatki sesutja programa</comment>
- <comment xml:lang="sk">Údaje o páde programu</comment>
+ <comment>Program crash data</comment>
+ <comment xml:lang="uk">дані щодо аварії програми</comment>
+ <comment xml:lang="sv">Programkraschdata</comment>
<comment xml:lang="ru">Данные аварийного завершения программы</comment>
- <comment xml:lang="ro">date eroare program</comment>
- <comment xml:lang="pt_BR">Dados de travamento de programa</comment>
- <comment xml:lang="pt">dados de rebentamento de aplicação</comment>
<comment xml:lang="pl">Dane awarii programu</comment>
- <comment xml:lang="oc">donadas de plantage de programa</comment>
- <comment xml:lang="nn">data om programkrasj</comment>
- <comment xml:lang="nl">programma-crashgegevens</comment>
- <comment xml:lang="nb">krasjdata fra program</comment>
- <comment xml:lang="ms">Data program musnah</comment>
- <comment xml:lang="lv">programmas avārijas dati</comment>
- <comment xml:lang="lt">programos nulūžimo duomenys</comment>
- <comment xml:lang="ko">프로그램 비정상 종료 데이터</comment>
- <comment xml:lang="kk">апатты аяқтаудың мәліметтері</comment>
- <comment xml:lang="ja">プログラムクラッシュデータ</comment>
<comment xml:lang="it">Dati crash di applicazione</comment>
- <comment xml:lang="id">data program macet</comment>
- <comment xml:lang="ia">Datos de fallimento de programma</comment>
- <comment xml:lang="hu">összeomlott program adatai</comment>
- <comment xml:lang="hr">podaci o rušenju programa</comment>
- <comment xml:lang="he">מידע מקריסת תכנית</comment>
- <comment xml:lang="gl">datos de colgue do programa</comment>
- <comment xml:lang="ga">sonraí tuairte ríomhchláir</comment>
- <comment xml:lang="fur">dâts di colàs di program</comment>
- <comment xml:lang="fr">données de plantage de programme</comment>
- <comment xml:lang="fo">forrits sordáta</comment>
- <comment xml:lang="fi">ohjelman kaatumistiedot</comment>
- <comment xml:lang="eu">programaren kraskaduraren datuak</comment>
- <comment xml:lang="es">datos de cuelgue de programa</comment>
- <comment xml:lang="eo">datumo pri kraŝo de programo</comment>
- <comment xml:lang="en_GB">program crash data</comment>
- <comment xml:lang="el">δεδομένα από την κατάρρευση προγράμματος</comment>
- <comment xml:lang="de">Daten zu Programmabsturz</comment>
- <comment xml:lang="da">programnedbrudsdata</comment>
- <comment xml:lang="cs">data o pádu programu</comment>
- <comment xml:lang="ca">dades de fallada de programa</comment>
- <comment xml:lang="bg">Данни от забиване на програма</comment>
- <comment xml:lang="be@latin">źviestki złamanaj prahramy</comment>
- <comment xml:lang="ar">معلومات انهيار برنامج</comment>
- <comment xml:lang="af">programomvaldata</comment>
+ <comment xml:lang="es">datos de cierre inesperado de programa</comment>
+ <comment xml:lang="de">Programmabsturz-Daten</comment>
+ <comment xml:lang="be">даныя пра збой праграмы</comment>
<magic>
<match type="string" mask="0xffffffff000000000000000000000000ff" value="\177ELF \004" offset="0"/>
<match type="string" value="\177ELF" offset="0">
@@ -9431,8 +9535,9 @@ command to generate the output files.
<comment xml:lang="tr">CPIO arşivi</comment>
<comment xml:lang="sv">CPIO-arkiv</comment>
<comment xml:lang="sr">ЦПИО архива</comment>
- <comment xml:lang="sq">Arkiv CPIO</comment>
+ <comment xml:lang="sq">arkiv CPIO</comment>
<comment xml:lang="sl">Datoteka arhiva CPIO</comment>
+ <comment xml:lang="si">CPIO ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív CPIO</comment>
<comment xml:lang="ru">Архив CPIO</comment>
<comment xml:lang="ro">Arhivă CPIO</comment>
@@ -9451,6 +9556,7 @@ command to generate the output files.
<comment xml:lang="ka">CPIO არქივი</comment>
<comment xml:lang="ja">CPIO アーカイブ</comment>
<comment xml:lang="it">Archivio CPIO</comment>
+ <comment xml:lang="is">CPIO safnskrá</comment>
<comment xml:lang="id">Arsip CPIO</comment>
<comment xml:lang="ia">Archivo CPIO</comment>
<comment xml:lang="hu">CPIO-archívum</comment>
@@ -9474,6 +9580,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu CPIO</comment>
<comment xml:lang="bg">Архив — CPIO</comment>
<comment xml:lang="be@latin">Archiŭ CPIO</comment>
+ <comment xml:lang="be">архіў CPIO</comment>
<comment xml:lang="az">CPIO arxivi</comment>
<comment xml:lang="ast">Archivu CPIO</comment>
<comment xml:lang="ar">أرشيف CPIO</comment>
@@ -9496,8 +9603,9 @@ command to generate the output files.
<comment xml:lang="tr">CPIO arşivi (gzip ile sıkıştırılmış)</comment>
<comment xml:lang="sv">CPIO-arkiv (gzip-komprimerat)</comment>
<comment xml:lang="sr">ЦПИО архива (компресована гзип-ом)</comment>
- <comment xml:lang="sq">Arkiv CPIO (kompresuar me gzip)</comment>
+ <comment xml:lang="sq">arkiv CPIO (ngjeshur me gzip)</comment>
<comment xml:lang="sl">Datoteka arhiva CPIO (skrčena z gzip)</comment>
+ <comment xml:lang="si">CPIO සංරක්ෂිතය (gzip-සම්පීඩිත)</comment>
<comment xml:lang="sk">Archív CPIO (komprimovaný pomocou gzip)</comment>
<comment xml:lang="ru">Архив CPIO (сжатый gzip)</comment>
<comment xml:lang="ro">Arhivă CPIO (compresie gzip)</comment>
@@ -9516,6 +9624,7 @@ command to generate the output files.
<comment xml:lang="ka">CPIO არქივი (gzip-ით შეკუმშული)</comment>
<comment xml:lang="ja">CPIO (gzip 圧縮) アーカイブ</comment>
<comment xml:lang="it">Archivio CPIO (compresso con gzip)</comment>
+ <comment xml:lang="is">CPIO safnskrá (Gzip þjappað)</comment>
<comment xml:lang="id">Arsip CPIO (terkompresi gzip)</comment>
<comment xml:lang="ia">Archivo CPIO (comprimite con gzip)</comment>
<comment xml:lang="hu">CPIO archívum (gzip tömörítésű)</comment>
@@ -9528,7 +9637,7 @@ command to generate the output files.
<comment xml:lang="fo">CPIO skjalasavn (gzip-stappað)</comment>
<comment xml:lang="fi">CPIO-arkisto (gzip-pakattu)</comment>
<comment xml:lang="eu">CPIO artxiboa (gzip-ekin konprimitua)</comment>
- <comment xml:lang="es">archivador CPIO (comprimido con gzip)</comment>
+ <comment xml:lang="es">archivador CPIO (comprimido con GZIP)</comment>
<comment xml:lang="eo">CPIO-arkivo (kunpremita per gzip)</comment>
<comment xml:lang="en_GB">CPIO archive (gzip-compressed)</comment>
<comment xml:lang="el">Αρχείο CPIO (συμπιεσμένο με gzip)</comment>
@@ -9539,6 +9648,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu CPIO (amb compressió gzip)</comment>
<comment xml:lang="bg">Архив — CPIO, компресиран с gzip</comment>
<comment xml:lang="be@latin">Archiŭ CPIO (gzip-skampresavany)</comment>
+ <comment xml:lang="be">архіў CPIO (сцісканне gzip)</comment>
<comment xml:lang="az">CPIO arxivi (gzip ilə sıxışdırılmış)</comment>
<comment xml:lang="ar">أرشيف CPIO (مضغوط-gzip)</comment>
<comment xml:lang="af">CPIO-argief (gzip-saamgepers)</comment>
@@ -9546,6 +9656,21 @@ command to generate the output files.
<generic-icon name="package-x-generic"/>
<glob pattern="*.cpio.gz"/>
</mime-type>
+ <mime-type type="application/x-perf-data">
+ <comment>Perf data</comment>
+ <comment xml:lang="uk">дані Perf</comment>
+ <comment xml:lang="sv">Perf-data</comment>
+ <comment xml:lang="ru">Данные Perf</comment>
+ <comment xml:lang="pl">Dane wydajności</comment>
+ <comment xml:lang="it">Dati perf</comment>
+ <comment xml:lang="gl">Datos de Perf</comment>
+ <comment xml:lang="es">datos de rendimiento</comment>
+ <comment xml:lang="de">Leistungsdaten</comment>
+ <glob pattern="perf.data" case-sensitive="true"/>
+ <magic priority="50">
+ <match type="string" value="PERFILE2" offset="0"/>
+ </magic>
+ </mime-type>
<mime-type type="application/x-csh">
<comment>C shell script</comment>
<comment xml:lang="zh_TW">C shell 指令稿</comment>
@@ -9555,8 +9680,9 @@ command to generate the output files.
<comment xml:lang="tr">C kabuk betiği</comment>
<comment xml:lang="sv">Skalskript (csh)</comment>
<comment xml:lang="sr">скрипта Ц шкољке</comment>
- <comment xml:lang="sq">Script shell C</comment>
+ <comment xml:lang="sq">programth C shell</comment>
<comment xml:lang="sl">Skriptna datoteka lupine C</comment>
+ <comment xml:lang="si">C shell පිටපත</comment>
<comment xml:lang="sk">Skript shellu C</comment>
<comment xml:lang="ru">Сценарий C shell</comment>
<comment xml:lang="ro">Script C shell</comment>
@@ -9574,6 +9700,7 @@ command to generate the output files.
<comment xml:lang="kk">C shell сценарийі</comment>
<comment xml:lang="ja">C シェルスクリプト</comment>
<comment xml:lang="it">Script C shell</comment>
+ <comment xml:lang="is">C skjeljarskrifta</comment>
<comment xml:lang="id">Skrip shell C</comment>
<comment xml:lang="ia">Script C-shell</comment>
<comment xml:lang="hu">C héj-parancsfájl</comment>
@@ -9597,6 +9724,7 @@ command to generate the output files.
<comment xml:lang="ca">script C shell</comment>
<comment xml:lang="bg">Скрипт — обвивка C</comment>
<comment xml:lang="be@latin">Skrypt abałonki C</comment>
+ <comment xml:lang="be">скрыпт C shell</comment>
<comment xml:lang="az">C qabıq skripti</comment>
<comment xml:lang="ar">سكربت شِل سي</comment>
<comment xml:lang="af">C shell-skrip</comment>
@@ -9611,7 +9739,7 @@ command to generate the output files.
</magic>
<glob pattern="*.csh"/>
</mime-type>
- <mime-type type="application/x-dbf">
+ <mime-type type="application/vnd.dbf">
<comment>Xbase document</comment>
<comment xml:lang="zh_TW">Xbase 文件</comment>
<comment xml:lang="zh_CN">Xbase 文档</comment>
@@ -9620,8 +9748,9 @@ command to generate the output files.
<comment xml:lang="tr">Xbase belgesi</comment>
<comment xml:lang="sv">Xbase-dokument</comment>
<comment xml:lang="sr">документ Иксбазе</comment>
- <comment xml:lang="sq">Dokument Xbase</comment>
+ <comment xml:lang="sq">dokument Xbase</comment>
<comment xml:lang="sl">Dokument Xbase</comment>
+ <comment xml:lang="si">Xbase ලේඛනය</comment>
<comment xml:lang="sk">Dokument Xbase</comment>
<comment xml:lang="ru">Документ Xbase</comment>
<comment xml:lang="ro">Document Xbase</comment>
@@ -9638,6 +9767,7 @@ command to generate the output files.
<comment xml:lang="kk">Xbase құжаты</comment>
<comment xml:lang="ja">Xbase ドキュメント</comment>
<comment xml:lang="it">Documento Xbase</comment>
+ <comment xml:lang="is">Xbase skjal</comment>
<comment xml:lang="id">Dokumen Xbase</comment>
<comment xml:lang="ia">Documento Xbase</comment>
<comment xml:lang="hu">Xbase dokumentum</comment>
@@ -9660,14 +9790,16 @@ command to generate the output files.
<comment xml:lang="ca">document Xbase</comment>
<comment xml:lang="bg">Документ — Xbase</comment>
<comment xml:lang="be@latin">Dakument Xbase</comment>
+ <comment xml:lang="be">дакумент Xbase</comment>
<comment xml:lang="ast">Documentu Xbase</comment>
<comment xml:lang="ar">مستند Xbase</comment>
<comment xml:lang="af">Xbase-dokument</comment>
<generic-icon name="x-office-document"/>
<glob pattern="*.dbf"/>
- <alias type="application/x-dbase"/>
- <alias type="application/dbf"/>
<alias type="application/dbase"/>
+ <alias type="application/dbf"/>
+ <alias type="application/x-dbase"/>
+ <alias type="application/x-dbf"/>
</mime-type>
<mime-type type="application/ecmascript">
<comment>ECMAScript program</comment>
@@ -9678,8 +9810,9 @@ command to generate the output files.
<comment xml:lang="tr">ECMAScript programı</comment>
<comment xml:lang="sv">ECMAScript-program</comment>
<comment xml:lang="sr">програм ЕЦМАСкрипте</comment>
- <comment xml:lang="sq">Program ECMAScript</comment>
+ <comment xml:lang="sq">program ECMAScript</comment>
<comment xml:lang="sl">Programska datoteka ECMAScript</comment>
+ <comment xml:lang="si">ECMAScript වැඩසටහන</comment>
<comment xml:lang="sk">Program ECMAScript</comment>
<comment xml:lang="ru">Программа ECMAScript</comment>
<comment xml:lang="ro">Program ECMAScript</comment>
@@ -9697,6 +9830,7 @@ command to generate the output files.
<comment xml:lang="ka">ECMAScript პროგრამა</comment>
<comment xml:lang="ja">ECMAScript プログラム</comment>
<comment xml:lang="it">Programma ECMAScript</comment>
+ <comment xml:lang="is">ECMAScript forrit</comment>
<comment xml:lang="id">Program ECMAScript</comment>
<comment xml:lang="ia">Programma ECMAScript</comment>
<comment xml:lang="hu">ECMAScript program</comment>
@@ -9718,11 +9852,11 @@ command to generate the output files.
<comment xml:lang="ca">programa ECMAScript</comment>
<comment xml:lang="bg">Програма — ECMAScript</comment>
<comment xml:lang="be@latin">Prahrama ECMAScript</comment>
+ <comment xml:lang="be">праграма ECMAScript</comment>
<comment xml:lang="ar">برنامج ECMAScript</comment>
<comment xml:lang="af">ECMAScript-program</comment>
<alias type="text/ecmascript"/>
- <sub-class-of type="application/x-executable"/>
- <sub-class-of type="text/plain"/>
+ <sub-class-of type="text/javascript"/>
<generic-icon name="text-x-script"/>
<glob pattern="*.es"/>
</mime-type>
@@ -9732,15 +9866,21 @@ command to generate the output files.
<comment xml:lang="tr">MAME sıkıştırılmış sabit disk görüntüsü</comment>
<comment xml:lang="sv">MAME komprimerad hårddiskavbild</comment>
<comment xml:lang="sr">МАМЕ компресовани одраз диска</comment>
+ <comment xml:lang="si">MAME සම්පීඩිත දෘඪ තැටි රූපය</comment>
+ <comment xml:lang="ru">Сжатый образ жесткого диска MAME</comment>
<comment xml:lang="pt_BR">Imagem de disco rígido compactado do MAME</comment>
<comment xml:lang="pl">Skompresowany obraz dysku twardego MAME</comment>
+ <comment xml:lang="nl">met MAME gecomprimeerd harde-schijfkopiebestand</comment>
<comment xml:lang="ko">MAME 압축된 하드 디스크 이미지</comment>
+ <comment xml:lang="kk">MAME сығылған қатты диск бейнесі</comment>
<comment xml:lang="ja">MAME 圧縮ハーディディスクイメージ</comment>
<comment xml:lang="it">Immagine disco MAME compressa</comment>
+ <comment xml:lang="is">Þjöppuð MAME diskmynd</comment>
<comment xml:lang="id">image hard disk MAME terkompresi</comment>
<comment xml:lang="hu">MAME tömörített merevlemezkép</comment>
<comment xml:lang="hr">MAME komprimirane slike tvrdog diska</comment>
<comment xml:lang="he">דמות כונן קשיח בדחיסת MAME</comment>
+ <comment xml:lang="gl">Imaxe de disco duro comprimido MAME</comment>
<comment xml:lang="fr">Image de disque dur compressé MAME</comment>
<comment xml:lang="fi">MAME pakatun kiintolevyn levykuva</comment>
<comment xml:lang="es">imagen comprimida de disco duro de MAME</comment>
@@ -9748,6 +9888,7 @@ command to generate the output files.
<comment xml:lang="de">MAME-komprimiertes Festplattenabbild</comment>
<comment xml:lang="da">MAME-komprimeret harddiskaftryk</comment>
<comment xml:lang="ca">imatge de disc dur MAME amb compressió</comment>
+ <comment xml:lang="be">сціснуты вобраз цвёрдага дыска MAME</comment>
<comment xml:lang="ar">صورة قرص صلب MAME مضغوطة</comment>
<generic-icon name="application-x-executable"/>
<magic>
@@ -9765,19 +9906,26 @@ command to generate the output files.
<comment xml:lang="tr">Sega CD disk görüntüsü</comment>
<comment xml:lang="sv">Mega-CD-skivavbild</comment>
<comment xml:lang="sr">одраз диска Сега ЦД-а</comment>
+ <comment xml:lang="sq">pamje disku CD Sega</comment>
+ <comment xml:lang="sl">Slika diska CD Sega</comment>
+ <comment xml:lang="si">Sega CD තැටි රූපය</comment>
<comment xml:lang="sk">Obraz disku CD Sega</comment>
<comment xml:lang="ru">Образ диска CD Sega</comment>
<comment xml:lang="pt_BR">Imagem de disco Sega CD</comment>
<comment xml:lang="pt">imagem de disco Mega-CD</comment>
<comment xml:lang="pl">Obraz płyty konsoli Mega-CD</comment>
+ <comment xml:lang="oc">imatge disc Sega CD</comment>
+ <comment xml:lang="nl">Sega CD-schijfkopiebestand</comment>
<comment xml:lang="ko">세가 CD 디스크 이미지</comment>
<comment xml:lang="kk">Sega CD диск бейнесі</comment>
<comment xml:lang="ja">Sega CD ディスクイメージ</comment>
<comment xml:lang="it">Immagine disco Sega Mega CD</comment>
+ <comment xml:lang="is">Sega CD diskmynd</comment>
<comment xml:lang="id">Image cakram CD Sega</comment>
<comment xml:lang="hu">Sega CD-lemezkép</comment>
<comment xml:lang="hr">Sega CD slika diska</comment>
<comment xml:lang="he">דמות כונן Sega CD</comment>
+ <comment xml:lang="gl">Imaxe de disco de Sega CD</comment>
<comment xml:lang="ga">íomhá dlúthdhiosca Sega</comment>
<comment xml:lang="fur">imagjin disc CD Sega</comment>
<comment xml:lang="fr">image disque Sega CD</comment>
@@ -9790,6 +9938,7 @@ command to generate the output files.
<comment xml:lang="cs">obraz disku CD pro Sega</comment>
<comment xml:lang="ca">imatge de disc de Sega CD</comment>
<comment xml:lang="bg">Диск — Mega-CD (Sega)</comment>
+ <comment xml:lang="be">вобраз CD-дыска Sega</comment>
<comment xml:lang="ast">Imaxe de discu de Sega CD</comment>
<comment xml:lang="ar">صورة قرص ميجا سي دي</comment>
<comment xml:lang="af">Mega CD-skyfbeeldlêer</comment>
@@ -9815,19 +9964,26 @@ command to generate the output files.
<comment xml:lang="tr">Sega Pico ROM</comment>
<comment xml:lang="sv">Sega Pico-rom</comment>
<comment xml:lang="sr">Сега Пико РОМ</comment>
+ <comment xml:lang="sq">ROM Sega Pico</comment>
+ <comment xml:lang="sl">Sega Pico ROM</comment>
+ <comment xml:lang="si">Sega Pico ROM</comment>
<comment xml:lang="sk">ROM pre Sega Pico</comment>
<comment xml:lang="ru">Sega Pico ROM</comment>
<comment xml:lang="pt_BR">ROM de Sega Pico</comment>
<comment xml:lang="pt">ROM Sega Pico</comment>
<comment xml:lang="pl">Plik ROM konsoli Sega Pico</comment>
+ <comment xml:lang="oc">ROM Sega Pico</comment>
+ <comment xml:lang="nl">Sega Pico-ROM</comment>
<comment xml:lang="ko">세가 피코 롬</comment>
<comment xml:lang="kk">Sega Pico ROM</comment>
<comment xml:lang="ja">キッズコンピュータ・ピコ ROM</comment>
<comment xml:lang="it">ROM Sega Pico</comment>
+ <comment xml:lang="is">Sega Pico ROM</comment>
<comment xml:lang="id">ROM Sega Pico</comment>
<comment xml:lang="hu">Sega Pico ROM</comment>
<comment xml:lang="hr">Sega Pico ROM</comment>
<comment xml:lang="he">ROM של Sega Pico</comment>
+ <comment xml:lang="gl">ROM de Sega Pico</comment>
<comment xml:lang="ga">ROM Sega Pico</comment>
<comment xml:lang="fur">ROM Sega Pico</comment>
<comment xml:lang="fr">ROM Sega Pico</comment>
@@ -9835,11 +9991,12 @@ command to generate the output files.
<comment xml:lang="eu">Sega Pico ROM</comment>
<comment xml:lang="es">ROM de Sega Pico</comment>
<comment xml:lang="en_GB">Sega Pico ROM</comment>
- <comment xml:lang="de">Sega Pico ROM</comment>
+ <comment xml:lang="de">Sega-Pico-ROM</comment>
<comment xml:lang="da">Sega Pico-ROM</comment>
<comment xml:lang="cs">ROM pro Sega Pico</comment>
<comment xml:lang="ca">ROM de Sega Pico</comment>
<comment xml:lang="bg">ROM — Sega Pico</comment>
+ <comment xml:lang="be">Sega Pico ROM</comment>
<comment xml:lang="ast">ROM de Sega Pico</comment>
<comment xml:lang="ar">روم سيجا بيك</comment>
<generic-icon name="application-x-executable"/>
@@ -9856,21 +10013,27 @@ command to generate the output files.
<comment xml:lang="tr">Sega Saturn disk görüntüsü</comment>
<comment xml:lang="sv">Sega Saturn-skivavbild</comment>
<comment xml:lang="sr">одраз диска Сега Сатурна</comment>
+ <comment xml:lang="sq">pamje disku Sega Saturn</comment>
+ <comment xml:lang="sl">Slika diska Sega Saturn</comment>
+ <comment xml:lang="si">සේගා සෙනසුරු තැටි රූපය</comment>
<comment xml:lang="sk">Obraz disku Sega Saturn</comment>
<comment xml:lang="ru">Образ диска Sega Saturn</comment>
<comment xml:lang="pt_BR">Imagem de disco do Sega Saturn</comment>
<comment xml:lang="pt">imagem de disco Sega Saturn</comment>
<comment xml:lang="pl">Obraz płyty konsoli Sega Saturn</comment>
<comment xml:lang="oc">imatge disc Sega Saturn</comment>
+ <comment xml:lang="nl">Sega Saturn-schijfkopiebestand</comment>
<comment xml:lang="ko">세가 새턴 디스크 이미지</comment>
<comment xml:lang="kk">Sega Saturn диск бейнесі</comment>
<comment xml:lang="ja">Sega Saturn ディスクイメージ</comment>
<comment xml:lang="it">Immagine disco Sega Saturn</comment>
+ <comment xml:lang="is">Sega Saturn diskmynd</comment>
<comment xml:lang="id">Image cakram Sega Saturn</comment>
<comment xml:lang="ia">Imagine de disco Sega Saturn</comment>
<comment xml:lang="hu">Sega Saturn lemezkép</comment>
<comment xml:lang="hr">Sega Saturn slika diska</comment>
<comment xml:lang="he">דמות כונן Sega Saturn</comment>
+ <comment xml:lang="gl">Imaxe de disco de Sega Saturn</comment>
<comment xml:lang="ga">íomhá diosca Sega Saturn</comment>
<comment xml:lang="fur">imagjin disc Sega Saturn</comment>
<comment xml:lang="fr">image disque Sega Saturn</comment>
@@ -9884,6 +10047,7 @@ command to generate the output files.
<comment xml:lang="cs">obraz disku pro Sega Saturn</comment>
<comment xml:lang="ca">imatge de disc de Sega Saturn</comment>
<comment xml:lang="bg">Диск — Sega Saturn</comment>
+ <comment xml:lang="be">вобраз дыска Sega Saturn</comment>
<comment xml:lang="ast">Imaxe de discu de Sega Saturn</comment>
<comment xml:lang="ar">صورة قرص ميجا ساتورن</comment>
<comment xml:lang="af">Sega Saturn-skyfbeeldlêer</comment>
@@ -9901,20 +10065,26 @@ command to generate the output files.
<comment xml:lang="uk">образ диска Dreamcast</comment>
<comment xml:lang="tr">Dreamcast disk görüntüsü</comment>
<comment xml:lang="sv">Dreamcast-skivavbild</comment>
+ <comment xml:lang="sq">pamje disku Dreamcast</comment>
+ <comment xml:lang="sl">Slika diska Dreamcast</comment>
+ <comment xml:lang="si">Dreamcast තැටි රූපය</comment>
<comment xml:lang="sk">Obraz disku Dreamcast</comment>
<comment xml:lang="ru">Образ диска Dreamcast</comment>
<comment xml:lang="pt_BR">Imagem de disco do Dreamcast</comment>
<comment xml:lang="pt">imagem de disco Dreamcast</comment>
<comment xml:lang="pl">Obraz płyty konsoli Dreamcast</comment>
<comment xml:lang="oc">imatge disc Dreamcast</comment>
+ <comment xml:lang="nl">Dreamcast-schijfkopiebestand</comment>
<comment xml:lang="ko">드림캐스트 디스크 이미지</comment>
<comment xml:lang="kk">Dreamcast диск бейнесі</comment>
<comment xml:lang="ja">Dreamcast ディスクイメージ</comment>
<comment xml:lang="it">Immagine disco Dreamcast</comment>
+ <comment xml:lang="is">Dreamcast diskmynd</comment>
<comment xml:lang="id">Image cakram Dreamcast</comment>
<comment xml:lang="hu">Dreamcast lemezkép</comment>
<comment xml:lang="hr">Dreamcast slika disa</comment>
<comment xml:lang="he">דמות כונן Dreamcast</comment>
+ <comment xml:lang="gl">Imaxe de disco de Dreamcast</comment>
<comment xml:lang="fr">image disque Dreamcast</comment>
<comment xml:lang="fi">Dreamcast-levykuva</comment>
<comment xml:lang="eu">Dreamcast disko irudia</comment>
@@ -9924,6 +10094,7 @@ command to generate the output files.
<comment xml:lang="da">Dreamcast-diskaftryk</comment>
<comment xml:lang="ca">imatge de disc de Dreamcast</comment>
<comment xml:lang="bg">Диск — Dreamcast</comment>
+ <comment xml:lang="be">вобраз дыска Dreamcast</comment>
<comment xml:lang="ar">صورة قرص Dreamcast</comment>
<generic-icon name="application-x-executable"/>
<magic>
@@ -9942,6 +10113,7 @@ command to generate the output files.
<comment xml:lang="sr">Нинтендо ДС РОМ</comment>
<comment xml:lang="sq">ROM Nintendo DS</comment>
<comment xml:lang="sl">Bralni pomnilnik Nintendo DS</comment>
+ <comment xml:lang="si">Nintendo DS ROM</comment>
<comment xml:lang="sk">ROM pre Nintendo DS</comment>
<comment xml:lang="ru">Nintendo DS ROM</comment>
<comment xml:lang="ro">ROM Nintendo DS</comment>
@@ -9950,7 +10122,7 @@ command to generate the output files.
<comment xml:lang="pl">Plik ROM konsoli Nintendo DS</comment>
<comment xml:lang="oc">ROM Nintendo DS</comment>
<comment xml:lang="nn">Nintendo DS-ROM</comment>
- <comment xml:lang="nl">Nintendo-DS-ROM</comment>
+ <comment xml:lang="nl">Nintendo DS-ROM</comment>
<comment xml:lang="nb">Nintendo DS-ROM</comment>
<comment xml:lang="lv">Nintendo DS ROM</comment>
<comment xml:lang="lt">Nintendo DS ROM</comment>
@@ -9958,6 +10130,7 @@ command to generate the output files.
<comment xml:lang="kk">Nintendo DS ROM</comment>
<comment xml:lang="ja">ニンテンドーDS ROM</comment>
<comment xml:lang="it">ROM Nintendo DS</comment>
+ <comment xml:lang="is">Nintendo DS ROM</comment>
<comment xml:lang="id">Memori baca-saja Nintendo DS</comment>
<comment xml:lang="ia">ROM pro Nintendo DS</comment>
<comment xml:lang="hu">Nintendo DS ROM</comment>
@@ -9973,12 +10146,13 @@ command to generate the output files.
<comment xml:lang="es">ROM de Nintendo DS</comment>
<comment xml:lang="en_GB">Nintendo DS ROM</comment>
<comment xml:lang="el">Nintendo DS ROM</comment>
- <comment xml:lang="de">Nintendo DS ROM</comment>
+ <comment xml:lang="de">Nintendo-DS-ROM</comment>
<comment xml:lang="da">Nintendo DS-ROM</comment>
<comment xml:lang="cs">ROM pro Nintendo DS</comment>
<comment xml:lang="ca">ROM de Nintendo DS</comment>
<comment xml:lang="bg">ROM — Nintendo DS</comment>
<comment xml:lang="be@latin">Nintendo DS ROM</comment>
+ <comment xml:lang="be">Nintendo DS ROM</comment>
<comment xml:lang="ast">ROM de Nintendo DS</comment>
<comment xml:lang="ar">روم نينتندو دي</comment>
<generic-icon name="application-x-executable"/>
@@ -9989,24 +10163,33 @@ command to generate the output files.
<comment xml:lang="uk">ППП Nintendo 3DS</comment>
<comment xml:lang="tr">Nintendo 3DS ROM</comment>
<comment xml:lang="sv">Nintendo 3DS-rom</comment>
+ <comment xml:lang="sl">Nintendo 3DS ROM</comment>
+ <comment xml:lang="si">Nintendo 3DS ROM</comment>
+ <comment xml:lang="ru">Nintendo 3DS ROM</comment>
<comment xml:lang="pt_BR">ROM do Nintendo 3DS</comment>
<comment xml:lang="pt">ROM Nintendo 3DS</comment>
<comment xml:lang="pl">Plik ROM konsoli Nintendo 3DS</comment>
<comment xml:lang="oc">ROM Nintendo 3DS</comment>
+ <comment xml:lang="nl">Nintendo 3DS-ROM</comment>
<comment xml:lang="ko">닌텐도 3DS 롬</comment>
+ <comment xml:lang="kk">Nintendo 3DS ROM</comment>
<comment xml:lang="ja">ニンテンドー3DS ROM</comment>
<comment xml:lang="it">ROM Nintendo 3DS</comment>
+ <comment xml:lang="is">Nintendo 3DS ROM</comment>
<comment xml:lang="id">ROM Nintendo 3DS</comment>
<comment xml:lang="hu">Nintendo 3DS ROM</comment>
<comment xml:lang="hr">Nintendo 3DS ROM</comment>
<comment xml:lang="he">ROM של Nintendo 3DS</comment>
+ <comment xml:lang="gl">ROM de Nintendo 3DS</comment>
<comment xml:lang="fr">ROM Nintendo 3DS</comment>
<comment xml:lang="fi">Nintendo 3DS ROM</comment>
+ <comment xml:lang="eu">Nintendo 3DS ROMa</comment>
<comment xml:lang="es">ROM de Nintendo 3DS</comment>
<comment xml:lang="en_GB">Nintendo 3DS ROM</comment>
- <comment xml:lang="de">Nintendo 3DS ROM</comment>
+ <comment xml:lang="de">Nintendo-3DS-ROM</comment>
<comment xml:lang="da">Nintendo 3DS-ROM</comment>
<comment xml:lang="ca">ROM de Nintendo 3DS</comment>
+ <comment xml:lang="be">Nintendo 3DS ROM</comment>
<comment xml:lang="ar">روم نينتندو 3دي</comment>
<generic-icon name="application-x-executable"/>
<glob pattern="*.3ds"/>
@@ -10020,23 +10203,32 @@ command to generate the output files.
<comment xml:lang="uk">виконуваний файл Nintendo 3DS</comment>
<comment xml:lang="tr">Nintendo 3DS Executable</comment>
<comment xml:lang="sv">Körbar Nintendo 3DS-fil</comment>
+ <comment xml:lang="si">Nintendo 3DS Executable</comment>
+ <comment xml:lang="ru">Nintendo 3DS Executable</comment>
<comment xml:lang="pt_BR">Executável do Nintendo 3DS</comment>
<comment xml:lang="pt">Executável da Nintendo 3DS</comment>
<comment xml:lang="pl">Plik wykonywalny konsoli Nintendo 3DS</comment>
+ <comment xml:lang="oc">Executable Nintendo 3DS</comment>
+ <comment xml:lang="nl">Nintendo 3DS-programmabestand</comment>
<comment xml:lang="ko">닌텐도 3DS 실행 파일</comment>
+ <comment xml:lang="kk">Nintendo 3DS орындалатын файлы</comment>
<comment xml:lang="ja">Nintendo 3DS 実行ファイル</comment>
<comment xml:lang="it">Eseguibile Nintendo 3DS</comment>
+ <comment xml:lang="is">Nintendo 3DS keyrsluskrá</comment>
<comment xml:lang="id">Executable Nintendo 3DS</comment>
<comment xml:lang="hu">Nintendo 3DS végrehajtható fájl</comment>
<comment xml:lang="hr">Nintendo 3DS izvršna datoteka</comment>
<comment xml:lang="he">קובץ הפעלה של Nintendo 3DS</comment>
+ <comment xml:lang="gl">Executábel de Nintendo 3DS</comment>
<comment xml:lang="fr">Exécutable Nintendo 3DS</comment>
<comment xml:lang="fi">Nintendo 3DS -ohjelma</comment>
+ <comment xml:lang="eu">Nintendo 3DS exekutagarria</comment>
<comment xml:lang="es">ejecutable de Nintendo 3DS</comment>
<comment xml:lang="en_GB">Nintendo 3DS Executable</comment>
<comment xml:lang="de">Nintendo-3DS-Programmdatei</comment>
<comment xml:lang="da">Nintendo 3DS-kørbar</comment>
<comment xml:lang="ca">executable de Nintendo 3DS</comment>
+ <comment xml:lang="be">выконвальны файл Nintendo 3DS</comment>
<comment xml:lang="ar">تنفيذي نينتندو 3دي إس</comment>
<generic-icon name="application-x-executable"/>
<glob pattern="*.3dsx"/>
@@ -10053,16 +10245,19 @@ command to generate the output files.
<comment xml:lang="sv">PC Engine-rom</comment>
<comment xml:lang="sr">ПЦ Енџин РОМ</comment>
<comment xml:lang="sl">Pomnilnik PC Engine ROM</comment>
+ <comment xml:lang="si">PC Engine ROM</comment>
<comment xml:lang="sk">PC Engine ROM</comment>
<comment xml:lang="ru">PC Engine ROM</comment>
<comment xml:lang="pt_BR">ROM de PC Engine</comment>
<comment xml:lang="pt">ROM PC Engine</comment>
<comment xml:lang="pl">Plik ROM konsoli PC Engine</comment>
<comment xml:lang="oc">ROM PC Engine</comment>
+ <comment xml:lang="nl">PC Engine-ROM</comment>
<comment xml:lang="ko">PC 엔진 롬</comment>
<comment xml:lang="kk">PC Engine ROM</comment>
<comment xml:lang="ja">PCエンジン ROM</comment>
<comment xml:lang="it">ROM PC Engine</comment>
+ <comment xml:lang="is">PC Engine ROM</comment>
<comment xml:lang="id">ROM PC Engine</comment>
<comment xml:lang="ia">ROM PC Engine</comment>
<comment xml:lang="hu">PC Engine ROM</comment>
@@ -10077,11 +10272,12 @@ command to generate the output files.
<comment xml:lang="es">ROM de PC Engine</comment>
<comment xml:lang="en_GB">PC Engine ROM</comment>
<comment xml:lang="el">PC Engine ROM</comment>
- <comment xml:lang="de">PC Engine ROM</comment>
+ <comment xml:lang="de">PC-Engine ROM</comment>
<comment xml:lang="da">PC Engine-ROM</comment>
<comment xml:lang="cs">ROM pro PC Engine</comment>
<comment xml:lang="ca">ROM de PC Engine</comment>
<comment xml:lang="bg">ROM — PC Engine</comment>
+ <comment xml:lang="be">PC Engine ROM</comment>
<comment xml:lang="ast">ROM de PC Engine</comment>
<comment xml:lang="ar">روم محرك PC</comment>
<generic-icon name="application-x-executable"/>
@@ -10095,17 +10291,21 @@ command to generate the output files.
<comment xml:lang="tr">Wii disk görüntüsü</comment>
<comment xml:lang="sv">Wii-skivavbild</comment>
<comment xml:lang="sr">одраз диска Вии-ја</comment>
+ <comment xml:lang="sq">pamje disku Wii</comment>
<comment xml:lang="sl">Odtis diska Wii</comment>
+ <comment xml:lang="si">Wii තැටි රූපය</comment>
<comment xml:lang="sk">Obraz disku Wii</comment>
<comment xml:lang="ru">Образ диска Wii</comment>
<comment xml:lang="pt_BR">Imagem de disco Wii</comment>
<comment xml:lang="pt">imagem de disco Wii</comment>
<comment xml:lang="pl">Obraz płyty konsoli Wii</comment>
<comment xml:lang="oc">imatge disc Wii</comment>
+ <comment xml:lang="nl">Wii-schijfkopiebestand</comment>
<comment xml:lang="ko">Wii 디스크 이미지</comment>
<comment xml:lang="kk">Wii диск бейнесі</comment>
<comment xml:lang="ja">Wii ディスクイメージ</comment>
<comment xml:lang="it">Immagine disco Wii</comment>
+ <comment xml:lang="is">Wii diskmynd</comment>
<comment xml:lang="id">Image disk Wii</comment>
<comment xml:lang="ia">Imagine de disco Wii</comment>
<comment xml:lang="hu">Wii lemezkép</comment>
@@ -10125,6 +10325,7 @@ command to generate the output files.
<comment xml:lang="cs">obraz disku pro Wii</comment>
<comment xml:lang="ca">imatge de disc de Wii</comment>
<comment xml:lang="bg">Диск — Wii</comment>
+ <comment xml:lang="be">вобраз дыска Wii</comment>
<comment xml:lang="ast">Imaxe de discu de Wii</comment>
<comment xml:lang="ar">صورة قرص وي</comment>
<comment xml:lang="af">Wii-skyfbeeldlêer</comment>
@@ -10147,21 +10348,26 @@ command to generate the output files.
<comment xml:lang="tr">WiiWare paketi</comment>
<comment xml:lang="sv">WiiWare-paket</comment>
<comment xml:lang="sr">ВииВер комплет</comment>
+ <comment xml:lang="sq">paketë WiiWare</comment>
+ <comment xml:lang="si">WiiWare බණ්ඩලය</comment>
<comment xml:lang="sk">Balík WiiWare</comment>
<comment xml:lang="ru">Пакет WiiWare</comment>
<comment xml:lang="pt_BR">Pacote WiiWare</comment>
<comment xml:lang="pt">pacote WiiWare</comment>
<comment xml:lang="pl">Pakiet WiiWare</comment>
<comment xml:lang="oc">lòt WiiWare</comment>
+ <comment xml:lang="nl">WiiWare-bundel</comment>
<comment xml:lang="ko">WiiWare 번들</comment>
<comment xml:lang="kk">WiiWare дестесі</comment>
<comment xml:lang="ja">WiiWare バンドル</comment>
<comment xml:lang="it">Bundle WiiWare</comment>
+ <comment xml:lang="is">WiiWare vöndull</comment>
<comment xml:lang="id">Bundel WiiWare</comment>
<comment xml:lang="ia">Pacchetto WiiWare</comment>
<comment xml:lang="hu">WiiWare csomag</comment>
<comment xml:lang="hr">WiiWare paket</comment>
<comment xml:lang="he">מאגד WiiWare</comment>
+ <comment xml:lang="gl">Empaquetado WiiWare</comment>
<comment xml:lang="ga">burla WiiWare</comment>
<comment xml:lang="fur">côl WiiWare</comment>
<comment xml:lang="fr">lot WiiWare</comment>
@@ -10174,6 +10380,7 @@ command to generate the output files.
<comment xml:lang="cs">balíček pro WiiWare</comment>
<comment xml:lang="ca">paquet de WiiWare</comment>
<comment xml:lang="bg">Програмен пакет — WiiWare</comment>
+ <comment xml:lang="be">пакет WiiWare</comment>
<comment xml:lang="ar">حزمة وي واير</comment>
<comment xml:lang="af">WiiWare-bundel</comment>
<generic-icon name="application-x-executable"/>
@@ -10192,17 +10399,21 @@ command to generate the output files.
<comment xml:lang="tr">GameCube disk görüntüsü</comment>
<comment xml:lang="sv">GameCube-skivavbild</comment>
<comment xml:lang="sr">одраз диска Гејм Коцке</comment>
+ <comment xml:lang="sq">pamje disku GameCube</comment>
<comment xml:lang="sl">Odtis diska GameCube</comment>
+ <comment xml:lang="si">GameCube තැටි රූපය</comment>
<comment xml:lang="sk">Obraz disku GameCube</comment>
<comment xml:lang="ru">Образ диска GameCube</comment>
<comment xml:lang="pt_BR">Imagem de disco GameCube</comment>
<comment xml:lang="pt">imagem de disco GameCube</comment>
<comment xml:lang="pl">Obraz płyty konsoli GameCube</comment>
<comment xml:lang="oc">imatge disc GameCube</comment>
+ <comment xml:lang="nl">GameCube-schijfkopiebestand</comment>
<comment xml:lang="ko">게임큐브 디스크 이미지</comment>
<comment xml:lang="kk">GameCube диск бейнесі</comment>
<comment xml:lang="ja">GameCube ディスクイメージ</comment>
<comment xml:lang="it">Immagine disco GameCube</comment>
+ <comment xml:lang="is">GameCube diskmynd</comment>
<comment xml:lang="id">Image disk GameCube</comment>
<comment xml:lang="ia">Imagine de disco GameCube</comment>
<comment xml:lang="hu">GameCube lemezkép</comment>
@@ -10222,6 +10433,7 @@ command to generate the output files.
<comment xml:lang="cs">obraz disku pro GameCube</comment>
<comment xml:lang="ca">imatge de disc de GameCube</comment>
<comment xml:lang="bg">Диск — GameCube</comment>
+ <comment xml:lang="be">вобраз дыска GameCube</comment>
<comment xml:lang="ar">صورة قرص GameCube</comment>
<comment xml:lang="af">GameCube-skyfbeeldlêer</comment>
<generic-icon name="application-x-executable"/>
@@ -10239,19 +10451,24 @@ command to generate the output files.
<comment xml:lang="tr">Thomson Mémo7 kartuşu</comment>
<comment xml:lang="sv">Thomson Mémo7-spelkassett</comment>
<comment xml:lang="sr">Томсон Мемо7 кертриџ</comment>
+ <comment xml:lang="sq">bobinë Thomson Mémo7</comment>
+ <comment xml:lang="si">Thomson Mémo7 කාට්රිජ්</comment>
<comment xml:lang="sk">Kazeta Thomson Mémo7</comment>
<comment xml:lang="ru">Картридж Thomson Mémo7</comment>
<comment xml:lang="pt_BR">Cartucho Thomson Mémo7</comment>
<comment xml:lang="pt">cartucho Thomson Mémo7</comment>
<comment xml:lang="pl">Kartridż Thomson Mémo7</comment>
+ <comment xml:lang="nl">Thomson Mémo7-casette</comment>
<comment xml:lang="ko">톰슨 Mémo7 카트리지</comment>
<comment xml:lang="kk">Thomson Mémo7 картриджі</comment>
<comment xml:lang="ja">Thomson Mémo7 カートリッジ</comment>
<comment xml:lang="it">Cartuccia Thomson Mémo7</comment>
+ <comment xml:lang="is">Thomson Mémo7 hylki</comment>
<comment xml:lang="id">Cartridge Thomson Mémo7</comment>
<comment xml:lang="hu">Thomson Mémo7 kazetta</comment>
<comment xml:lang="hr">Thomson Mémo7 uložak</comment>
<comment xml:lang="he">קלטת Thomson Mémo7</comment>
+ <comment xml:lang="gl">Cartucho de Thomson Mémo7</comment>
<comment xml:lang="ga">cartús Thomson Mémo7</comment>
<comment xml:lang="fur">cartucje Mémo7 Thomson</comment>
<comment xml:lang="fr">cartouche Thomson Mémo7</comment>
@@ -10264,6 +10481,7 @@ command to generate the output files.
<comment xml:lang="cs">Kazeta Thomson Mémo7</comment>
<comment xml:lang="ca">cartutx Thomson Mémo7</comment>
<comment xml:lang="bg">Касета — Thomson Mémo7</comment>
+ <comment xml:lang="be">картрыдж Thomson Mémo7</comment>
<comment xml:lang="ar">خرطوشة Thomson Mémo7</comment>
<generic-icon name="application-x-executable"/>
<glob pattern="*.m7"/>
@@ -10276,15 +10494,20 @@ command to generate the output files.
<comment xml:lang="tr">Thomson kaset</comment>
<comment xml:lang="sv">Thomson-kassett</comment>
<comment xml:lang="sr">Томсон касете</comment>
+ <comment xml:lang="sq">kasetë Thomson</comment>
+ <comment xml:lang="sl">Kaseta Thomson</comment>
+ <comment xml:lang="si">තොම්සන් කැසට් පටය</comment>
<comment xml:lang="sk">Kazeta Thomson</comment>
<comment xml:lang="ru">Кассета Thomson</comment>
<comment xml:lang="pt_BR">Cassete Thomson</comment>
<comment xml:lang="pt">cassete Thomson</comment>
<comment xml:lang="pl">Kaseta Thomson</comment>
+ <comment xml:lang="nl">Thomson-cassette</comment>
<comment xml:lang="ko">톰슨 카세트</comment>
<comment xml:lang="kk">Thomson кассетасы</comment>
<comment xml:lang="ja">Thomson カセット</comment>
<comment xml:lang="it">Cassetta Thomson</comment>
+ <comment xml:lang="is">Thomson snælda</comment>
<comment xml:lang="id">Kaset Thomson</comment>
<comment xml:lang="hu">Thomson kazetta</comment>
<comment xml:lang="hr">Thomson kaseta</comment>
@@ -10301,6 +10524,7 @@ command to generate the output files.
<comment xml:lang="cs">Kazeta Thomson</comment>
<comment xml:lang="ca">cinta de casset Thomson</comment>
<comment xml:lang="bg">Касета — Thomson</comment>
+ <comment xml:lang="be">касета Thomson</comment>
<comment xml:lang="ar">شريط Thomson</comment>
<generic-icon name="application-x-executable"/>
<glob pattern="*.k7"/>
@@ -10313,19 +10537,25 @@ command to generate the output files.
<comment xml:lang="tr">HFE disket görüntüsü</comment>
<comment xml:lang="sv">HFE-diskavbild</comment>
<comment xml:lang="sr">ХФЕ слика флопи диска</comment>
+ <comment xml:lang="sq">pamje diskete HFE</comment>
+ <comment xml:lang="sl">Slika diskete HFE</comment>
+ <comment xml:lang="si">HFE නම්ය තැටි රූපය</comment>
<comment xml:lang="sk">Obraz pružného disku HFE</comment>
<comment xml:lang="ru">Образ гибкого диска HFE</comment>
<comment xml:lang="pt_BR">Imagem de disco flexível HFE</comment>
<comment xml:lang="pt">imagem de disquete HFE</comment>
<comment xml:lang="pl">Obraz dyskietki HFE</comment>
+ <comment xml:lang="nl">HFE-diskette-schijfkopiebestand</comment>
<comment xml:lang="ko">HFE 플로피 디스크 이미지</comment>
<comment xml:lang="kk">HFE иілгіш диск бейнесі</comment>
<comment xml:lang="ja">HFE フロッピーディスクイメージ</comment>
<comment xml:lang="it">Immagine disco floppy HFE</comment>
+ <comment xml:lang="is">HFE disklingsmynd</comment>
<comment xml:lang="id">Image disk floppy HFE</comment>
<comment xml:lang="hu">HFE flopi lemezkép</comment>
<comment xml:lang="hr">HFE slika diskete</comment>
<comment xml:lang="he">דמות כונן תקליטון מסוג HPE</comment>
+ <comment xml:lang="gl">Imaxe de disquete HHFE</comment>
<comment xml:lang="ga">íomhá diosca fhlapaigh HFE</comment>
<comment xml:lang="fur">imagjin disc floppy HFE</comment>
<comment xml:lang="fr">image disquette HFE</comment>
@@ -10338,6 +10568,7 @@ command to generate the output files.
<comment xml:lang="cs">Obraz diskety HFE</comment>
<comment xml:lang="ca">imatge de disquet HFE</comment>
<comment xml:lang="bg">Диск — флопи, HFE</comment>
+ <comment xml:lang="be">вобраз гнуткага дыска HFE</comment>
<comment xml:lang="ar">صورة قرص مرن HFE</comment>
<acronym>HFE</acronym>
<expanded-acronym>HxC Floppy Emulator</expanded-acronym>
@@ -10356,19 +10587,25 @@ command to generate the output files.
<comment xml:lang="tr">SAP Thomson disket görüntüsü</comment>
<comment xml:lang="sv">SAP Thomson-diskavbild</comment>
<comment xml:lang="sr">САП Томсон слика флопи диска</comment>
+ <comment xml:lang="sq">pamje diskete SAP Thomson</comment>
+ <comment xml:lang="sl">Slika diskete SAP Thomson</comment>
+ <comment xml:lang="si">SAP තොම්සන් නම්ය තැටි රූපය</comment>
<comment xml:lang="sk">Obraz pružného disku SAP Thomson</comment>
<comment xml:lang="ru">Образ гибкого диска SAP Thomson</comment>
<comment xml:lang="pt_BR">Imagem de disco flexível SAP Thomson</comment>
<comment xml:lang="pt">imagem de disquete SAP Thomson</comment>
<comment xml:lang="pl">Obraz dyskietki SAP Thomson</comment>
+ <comment xml:lang="nl">SAP Thomson diskette-schijfkopiebestand</comment>
<comment xml:lang="ko">SAP 톰슨 플로피 디스크 이미지</comment>
<comment xml:lang="kk">SAP Thomson иілгіш диск бейнесі</comment>
<comment xml:lang="ja">SAP Thomson フロッピーディスクイメージ</comment>
<comment xml:lang="it">Immagine disco floppy Thomson SAP</comment>
+ <comment xml:lang="is">SAP Thomson disklingsmynd</comment>
<comment xml:lang="id">Image disk floppy SAP Thomson</comment>
<comment xml:lang="hu">SAP Thomson flopi lemezkép</comment>
<comment xml:lang="hr">SAP Thomson slika diskete</comment>
<comment xml:lang="he">דמות כונן תקליטון מסוג SAP Thomson</comment>
+ <comment xml:lang="gl">Imaxe de disquete SAP Thomson</comment>
<comment xml:lang="ga">íomhá diosca fhlapaigh SAP Thomson</comment>
<comment xml:lang="fur">imagjin disc floppy SAP Thomson</comment>
<comment xml:lang="fr">image disquette SAP Thomson</comment>
@@ -10381,6 +10618,7 @@ command to generate the output files.
<comment xml:lang="cs">Obraz diskety SAP Thomson</comment>
<comment xml:lang="ca">imatge de disquet SAP Thomson</comment>
<comment xml:lang="bg">Диск — флопи, SAP Thomson</comment>
+ <comment xml:lang="be">вобраз гнуткага дыска SAP Thomson</comment>
<comment xml:lang="ar">صورة قرص مرن SAP Thomson</comment>
<acronym>SAP</acronym>
<expanded-acronym>Système d'Archivage Pukall</expanded-acronym>
@@ -10402,6 +10640,7 @@ command to generate the output files.
<comment xml:lang="sr">Дебијанов пакет</comment>
<comment xml:lang="sq">Paketë Debian</comment>
<comment xml:lang="sl">Datoteka paketa Debian</comment>
+ <comment xml:lang="si">ඩේබියන් පැකේජය</comment>
<comment xml:lang="sk">Balíček Debianu</comment>
<comment xml:lang="ru">Пакет Debian</comment>
<comment xml:lang="ro">Pachet Debian</comment>
@@ -10420,6 +10659,7 @@ command to generate the output files.
<comment xml:lang="ka">Debian-ის პაკეტი</comment>
<comment xml:lang="ja">Debian パッケージ</comment>
<comment xml:lang="it">Pacchetto Debian</comment>
+ <comment xml:lang="is">Debian pakki</comment>
<comment xml:lang="id">Paket Debian</comment>
<comment xml:lang="ia">Pacchetto Debian</comment>
<comment xml:lang="hu">Debian-csomag</comment>
@@ -10443,6 +10683,7 @@ command to generate the output files.
<comment xml:lang="ca">paquet Debian</comment>
<comment xml:lang="bg">Пакет — Debian</comment>
<comment xml:lang="be@latin">Pakunak Debian</comment>
+ <comment xml:lang="be">пакет Debian</comment>
<comment xml:lang="az">Debian paketi</comment>
<comment xml:lang="ar">حزمة ديبيان</comment>
<comment xml:lang="af">Debian-pakket</comment>
@@ -10464,14 +10705,19 @@ command to generate the output files.
<comment xml:lang="uk">документ інтерфейсу Qt Designer</comment>
<comment xml:lang="tr">Qt Designer arayüz belgesi</comment>
<comment xml:lang="sv">Qt Designer-gränssnittsdokument</comment>
+ <comment xml:lang="sq">dokument ndërfaqesh Qt Designer</comment>
+ <comment xml:lang="sl">Dokument vmesnika Qt Designer</comment>
+ <comment xml:lang="si">Qt Designer අතුරුමුහුණත් ලේඛනය</comment>
<comment xml:lang="ru">Документ интерфейса Qt Designer</comment>
<comment xml:lang="pt_BR">Documento de interface do Qt Designer</comment>
<comment xml:lang="pt">documento de interface Qt Designer</comment>
<comment xml:lang="pl">Dokument interfejsu Qt Designer</comment>
+ <comment xml:lang="nl">Qt Designer-interfacedocument</comment>
<comment xml:lang="ko">Qt 디자이너 인터페이스 문서</comment>
<comment xml:lang="kk">Qt Designer интерфейс құжаты</comment>
<comment xml:lang="ja">Qt Designer インターフェイスドキュメント</comment>
<comment xml:lang="it">Documento interfaccia Qt Designer</comment>
+ <comment xml:lang="is">Qt Designer viðmótsskjal</comment>
<comment xml:lang="id">Dokumen antarmuka Qt Designer</comment>
<comment xml:lang="hu">Qt Designer felületleíró dokumentum</comment>
<comment xml:lang="hr">Qt Designer dokument sučelja</comment>
@@ -10485,6 +10731,7 @@ command to generate the output files.
<comment xml:lang="da">Qt Designer-brugerflade-dokument</comment>
<comment xml:lang="ca">document d'interfície Qt Designer</comment>
<comment xml:lang="bg">Документ — интерфейс, Qt Designer</comment>
+ <comment xml:lang="be">дакумент інтэрфейсу Qt Designer</comment>
<comment xml:lang="ar">مستند واجهة مصمم كيوت</comment>
<generic-icon name="x-office-document"/>
<sub-class-of type="application/xml"/>
@@ -10499,11 +10746,16 @@ command to generate the output files.
<comment xml:lang="uk">файл визначень Kaitai Struct</comment>
<comment xml:lang="tr">Kaitai Struct tanım dosyası</comment>
<comment xml:lang="sv">Kaitai Struct-definitionsfil</comment>
+ <comment xml:lang="si">Kaitai Struct නිර්වචන ගොනුව</comment>
+ <comment xml:lang="ru">Файл Kaitai Struct definition</comment>
<comment xml:lang="pt_BR">Arquivo de definição da Kaitai Struct</comment>
<comment xml:lang="pl">Plik definicji Kaitai Struct</comment>
+ <comment xml:lang="nl">Kaitai Struct-definitiebestand</comment>
<comment xml:lang="ko">Kaitai 구조체 정의 파일</comment>
+ <comment xml:lang="kk">Kaitai Struct сипаттама файлы</comment>
<comment xml:lang="ja">Kaitai Struct 定義ファイル</comment>
<comment xml:lang="it">File definizione Kaitai Struct</comment>
+ <comment xml:lang="is">Kaitai Struct skilgreiningarskrá</comment>
<comment xml:lang="id">berkas definisi Kaitai Struct</comment>
<comment xml:lang="hu">Kaitai szerkezetdefiníciós fájl</comment>
<comment xml:lang="hr">Kaitai Struct datoteka definicije</comment>
@@ -10515,8 +10767,9 @@ command to generate the output files.
<comment xml:lang="de">Kaitai Struct-Definitionsdatei</comment>
<comment xml:lang="da">Kaitai Struct-definitionsfil</comment>
<comment xml:lang="ca">fitxer de definicions Kaitai Struct</comment>
+ <comment xml:lang="be">файл азначэння Kaitai Struct</comment>
<comment xml:lang="ar">ملف تعريف Kaitai Struct</comment>
- <sub-class-of type="application/x-yaml"/>
+ <sub-class-of type="application/yaml"/>
<glob pattern="*.ksy"/>
</mime-type>
<mime-type type="text/x-qml">
@@ -10527,7 +10780,9 @@ command to generate the output files.
<comment xml:lang="tr">Qt İşaretleme Dili dosyası</comment>
<comment xml:lang="sv">Qt-märkspråksfil</comment>
<comment xml:lang="sr">датотека КуТ-овог језика означавања</comment>
+ <comment xml:lang="sq">kartelë Qt Markup Language</comment>
<comment xml:lang="sl">Datoteka označevalnega jezika Qt</comment>
+ <comment xml:lang="si">Qt Markup භාෂා ගොනුව</comment>
<comment xml:lang="sk">Súbor značkovacieho jazyka Qt</comment>
<comment xml:lang="ru">Файл Qt Markup Language</comment>
<comment xml:lang="pt_BR">Arquivo de Qt Markup Language</comment>
@@ -10540,6 +10795,7 @@ command to generate the output files.
<comment xml:lang="kk">Qt Markup Language файлы</comment>
<comment xml:lang="ja">Qt マークアップ言語ファイル</comment>
<comment xml:lang="it">File Qt Markup Language</comment>
+ <comment xml:lang="is">Qt Markup Language skrá</comment>
<comment xml:lang="id">Berkas Bahasa Markup Qt</comment>
<comment xml:lang="ia">File de linguage de marcation Qt</comment>
<comment xml:lang="hu">Qt jelölőnyelvű fájl</comment>
@@ -10559,6 +10815,7 @@ command to generate the output files.
<comment xml:lang="cs">soubor Qt Markup Language</comment>
<comment xml:lang="ca">fitxer de llenguatge de marcadors Qt</comment>
<comment xml:lang="bg">Интерфейс — Qt Markup</comment>
+ <comment xml:lang="be">файл Qt Markup Language</comment>
<comment xml:lang="ar">ملف لغة وصف Qt</comment>
<comment xml:lang="af">Qt Markup Language-lêer</comment>
<sub-class-of type="text/plain"/>
@@ -10576,7 +10833,17 @@ command to generate the output files.
<glob pattern="*.qmlproject"/>
</mime-type>
<mime-type type="application/x-desktop">
- <comment>desktop entry</comment>
+ <comment>Desktop entry</comment>
+ <comment xml:lang="uk">стільничний запис</comment>
+ <comment xml:lang="sv">Skrivbordspost</comment>
+ <comment xml:lang="ru">Запись рабочего стола</comment>
+ <comment xml:lang="pl">Wpis środowiska</comment>
+ <comment xml:lang="it">Elemento desktop</comment>
+ <comment xml:lang="gl">Entrada de escritorio</comment>
+ <comment xml:lang="eu">Mahaigaineko sarrera</comment>
+ <comment xml:lang="es">entrada de escritorio</comment>
+ <comment xml:lang="de">Desktop-Eintrag</comment>
+ <comment xml:lang="be">запіс desktop</comment>
<sub-class-of type="text/plain"/>
<generic-icon name="text-x-generic"/>
<magic>
@@ -10599,7 +10866,9 @@ command to generate the output files.
<comment xml:lang="tr">FictionBook belgesi</comment>
<comment xml:lang="sv">FictionBook-dokument</comment>
<comment xml:lang="sr">документ Фикшон Књиге</comment>
+ <comment xml:lang="sq">dokument FictionBook</comment>
<comment xml:lang="sl">Dokument FictionBook</comment>
+ <comment xml:lang="si">ප්‍රබන්ධ පොත් ලේඛනය</comment>
<comment xml:lang="sk">Dokument FictionBook</comment>
<comment xml:lang="ru">Документ FictionBook</comment>
<comment xml:lang="ro">Document FictionBook</comment>
@@ -10615,6 +10884,7 @@ command to generate the output files.
<comment xml:lang="ka">FictionBook-ის დოკუმენტი</comment>
<comment xml:lang="ja">FictionBook ドキュメント</comment>
<comment xml:lang="it">Documento FictionBook</comment>
+ <comment xml:lang="is">FictionBook skjal</comment>
<comment xml:lang="id">Dokumen FictionBook</comment>
<comment xml:lang="ia">Documento FictionBook</comment>
<comment xml:lang="hu">FictionBook-dokumentum</comment>
@@ -10636,6 +10906,7 @@ command to generate the output files.
<comment xml:lang="cs">dokument FictionBook</comment>
<comment xml:lang="ca">document FictionBook</comment>
<comment xml:lang="bg">Документ — FictionBook</comment>
+ <comment xml:lang="be">дакумент FictionBook</comment>
<comment xml:lang="ast">Documentu de FictionBook</comment>
<comment xml:lang="ar">مستند FictionBook</comment>
<comment xml:lang="af">FictionBook-dokument</comment>
@@ -10655,17 +10926,21 @@ command to generate the output files.
<comment xml:lang="tr">Sıkıştırılmış FictionBook belgesi</comment>
<comment xml:lang="sv">Komprimerat FictionBook-dokument</comment>
<comment xml:lang="sr">запаковани документ Фикшон Књиге</comment>
+ <comment xml:lang="sq">dokument FictionBook i ngjeshur</comment>
<comment xml:lang="sl">Stisnjeni dokument FictionBook</comment>
+ <comment xml:lang="si">සම්පීඩිත FictionBook ලේඛනය</comment>
<comment xml:lang="sk">Komprimovaný dokument FictionBook</comment>
<comment xml:lang="ru">Сжатый документ FictionBook</comment>
<comment xml:lang="pt_BR">Documento FictionBook comprimido</comment>
<comment xml:lang="pt">documento comprimido FictionBook</comment>
<comment xml:lang="pl">Skompresowany dokument FictionBook</comment>
<comment xml:lang="oc">document FictionBook compressat</comment>
+ <comment xml:lang="nl">Gecomprimeerd FictionBook-document</comment>
<comment xml:lang="ko">압축한 FictionBook 문서</comment>
<comment xml:lang="kk">Сығылған FictionBook құжаты</comment>
<comment xml:lang="ja">圧縮 FictionBook ドキュメント</comment>
<comment xml:lang="it">Documento FictionBook compresso</comment>
+ <comment xml:lang="is">Þjappað FictionBook skjal</comment>
<comment xml:lang="id">Dokumen FictionBook terkompresi</comment>
<comment xml:lang="ia">Documento FictionBook comprimite</comment>
<comment xml:lang="hu">Tömörített FictionBook dokumentum</comment>
@@ -10685,6 +10960,7 @@ command to generate the output files.
<comment xml:lang="cs">komprimovaný dokument FictionBook</comment>
<comment xml:lang="ca">document FictionBook amb compressió</comment>
<comment xml:lang="bg">Документ — FictionBook, компресиран</comment>
+ <comment xml:lang="be">сціснуты дакумент FictionBook</comment>
<comment xml:lang="ast">Documentu comprimíu de FictionBook</comment>
<comment xml:lang="ar">مستند FictionBook مضغوط</comment>
<comment xml:lang="af">Saamgepersde FictionBook-dokument</comment>
@@ -10706,8 +10982,9 @@ command to generate the output files.
<comment xml:lang="tr">Dia çizimi</comment>
<comment xml:lang="sv">Dia-diagram</comment>
<comment xml:lang="sr">дијаграм Дие</comment>
- <comment xml:lang="sq">Diagramë Dia</comment>
+ <comment xml:lang="sq">diagram Dia</comment>
<comment xml:lang="sl">Datoteka diagrama Dia</comment>
+ <comment xml:lang="si">Dia රූප සටහන</comment>
<comment xml:lang="sk">Diagram Dia</comment>
<comment xml:lang="ru">Диаграмма Dia</comment>
<comment xml:lang="ro">Diagramă Dia</comment>
@@ -10726,6 +11003,7 @@ command to generate the output files.
<comment xml:lang="ka">Dia-ის დიაგრამა</comment>
<comment xml:lang="ja">Dia ダイアグラム</comment>
<comment xml:lang="it">Diagramma Dia</comment>
+ <comment xml:lang="is">Dia teikning</comment>
<comment xml:lang="id">Diagram Dia</comment>
<comment xml:lang="ia">Diagramma Dia</comment>
<comment xml:lang="hu">Dia-diagram</comment>
@@ -10749,6 +11027,7 @@ command to generate the output files.
<comment xml:lang="ca">diagrama de Dia</comment>
<comment xml:lang="bg">Диаграма — Dia</comment>
<comment xml:lang="be@latin">Dyjahrama Dia</comment>
+ <comment xml:lang="be">дыяграма Dia</comment>
<comment xml:lang="az">Dia diaqramı</comment>
<comment xml:lang="ar">خطاطة Dia</comment>
<comment xml:lang="af">Dia-diagram</comment>
@@ -10768,7 +11047,9 @@ command to generate the output files.
<comment xml:lang="tr">Dia şekli</comment>
<comment xml:lang="sv">Dia-figur</comment>
<comment xml:lang="sr">облик Дие</comment>
+ <comment xml:lang="sq">formë Dia</comment>
<comment xml:lang="sl">Datoteka oblik Dia</comment>
+ <comment xml:lang="si">Dia හැඩය</comment>
<comment xml:lang="sk">Tvar Dia</comment>
<comment xml:lang="ru">Фигура Dia</comment>
<comment xml:lang="ro">Figură Dia</comment>
@@ -10783,6 +11064,7 @@ command to generate the output files.
<comment xml:lang="kk">Dia сызбасы</comment>
<comment xml:lang="ja">Dia 図形</comment>
<comment xml:lang="it">Sagoma Dia</comment>
+ <comment xml:lang="is">Dia lögun</comment>
<comment xml:lang="id">Shape Dia</comment>
<comment xml:lang="ia">Forma Dia</comment>
<comment xml:lang="hu">Dia alakzat</comment>
@@ -10803,6 +11085,7 @@ command to generate the output files.
<comment xml:lang="cs">symboly Dia</comment>
<comment xml:lang="ca">forma de Dia</comment>
<comment xml:lang="bg">Фигура — Dia</comment>
+ <comment xml:lang="be">фігура Dia</comment>
<comment xml:lang="ar">شكل Dia</comment>
<comment xml:lang="af">Dia-vorm</comment>
<generic-icon name="image-x-generic"/>
@@ -10822,10 +11105,11 @@ command to generate the output files.
<comment xml:lang="tr">TeX DVI belgesi</comment>
<comment xml:lang="sv">TeX DVI-dokument</comment>
<comment xml:lang="sr">ТеКс ДВИ документ</comment>
- <comment xml:lang="sq">Dokument TeX DVI</comment>
+ <comment xml:lang="sq">dokument TeX DVI</comment>
<comment xml:lang="sl">Dokument TeX DVI</comment>
+ <comment xml:lang="si">TeX DVI ලේඛනය</comment>
<comment xml:lang="sk">Dokument TeX DVI</comment>
- <comment xml:lang="ru">Документ TeX DVI</comment>
+ <comment xml:lang="ru">Документ DVI издательской системы TeX</comment>
<comment xml:lang="ro">Document Tex DVI</comment>
<comment xml:lang="pt_BR">Documento DVI TeX</comment>
<comment xml:lang="pt">documento TeX DVI</comment>
@@ -10841,6 +11125,7 @@ command to generate the output files.
<comment xml:lang="kk">TeX DVI құжаты</comment>
<comment xml:lang="ja">TeX DVI ドキュメント</comment>
<comment xml:lang="it">Documento TeX DVI</comment>
+ <comment xml:lang="is">TeX DVI skjal</comment>
<comment xml:lang="id">Dokumen TeX DVI</comment>
<comment xml:lang="ia">Documento TeX DVI</comment>
<comment xml:lang="hu">TeX DVI-dokumentum</comment>
@@ -10863,6 +11148,7 @@ command to generate the output files.
<comment xml:lang="ca">document DVI de TeX</comment>
<comment xml:lang="bg">Документ — TeX DVI</comment>
<comment xml:lang="be@latin">Dakument TeX DVI</comment>
+ <comment xml:lang="be">дакумент TeX DVI</comment>
<comment xml:lang="ast">Documentu Tex DVI</comment>
<comment xml:lang="ar">مستند TeX DVI</comment>
<comment xml:lang="af">TeX DVI-dokument</comment>
@@ -10883,8 +11169,9 @@ command to generate the output files.
<comment xml:lang="tr">Enlightenment teması</comment>
<comment xml:lang="sv">Enlightenment-tema</comment>
<comment xml:lang="sr">тема за Енлајтмент</comment>
- <comment xml:lang="sq">Tema Enlightenment</comment>
+ <comment xml:lang="sq">temë Enlightenment</comment>
<comment xml:lang="sl">Datoteka teme Enlightenment</comment>
+ <comment xml:lang="si">බුද්ධත්වයේ තේමාව</comment>
<comment xml:lang="sk">Motív Enlightenment</comment>
<comment xml:lang="ru">Тема Enlightenment</comment>
<comment xml:lang="ro">Temă Enlightenment</comment>
@@ -10903,6 +11190,7 @@ command to generate the output files.
<comment xml:lang="ka">Enlightenment-ის თემა</comment>
<comment xml:lang="ja">Enlightenment テーマ</comment>
<comment xml:lang="it">Tema Enlightenment</comment>
+ <comment xml:lang="is">Enlightenment þema</comment>
<comment xml:lang="id">Tema Enlightenment</comment>
<comment xml:lang="ia">Thema de Enlightenment</comment>
<comment xml:lang="hu">Enlightenment-téma</comment>
@@ -10926,6 +11214,7 @@ command to generate the output files.
<comment xml:lang="ca">tema d'Enlightenment</comment>
<comment xml:lang="bg">Тема — Enlightenment</comment>
<comment xml:lang="be@latin">Matyŭ Enlightenment</comment>
+ <comment xml:lang="be">тэма Enlightenment</comment>
<comment xml:lang="az">Enlightenment örtüyü</comment>
<comment xml:lang="ar">سمة Enlightenment</comment>
<comment xml:lang="af">Enlightenment-tema</comment>
@@ -10940,8 +11229,9 @@ command to generate the output files.
<comment xml:lang="tr">Egon Animator canlandırması</comment>
<comment xml:lang="sv">Egon Animator-animering</comment>
<comment xml:lang="sr">анимација Егон аниматора</comment>
- <comment xml:lang="sq">Animim Egon Animator</comment>
+ <comment xml:lang="sq">animacion Egon Animator</comment>
<comment xml:lang="sl">Datoteka animacije Egon Animator</comment>
+ <comment xml:lang="si">Egon Animator සජීවිකරණය</comment>
<comment xml:lang="sk">Animácia Egon Animator</comment>
<comment xml:lang="ru">Анимация Egon Animator</comment>
<comment xml:lang="ro">Animație Egon Animator</comment>
@@ -10960,6 +11250,7 @@ command to generate the output files.
<comment xml:lang="ka">Egon Animator-ის ანიმაცია</comment>
<comment xml:lang="ja">Egon Animator アニメーション</comment>
<comment xml:lang="it">Animazione Egon Animator</comment>
+ <comment xml:lang="is">Egon Animator hreyfimynd</comment>
<comment xml:lang="id">Animasi Egon Animator</comment>
<comment xml:lang="ia">Imagine Egon Animator</comment>
<comment xml:lang="hu">Egon Animator-animáció</comment>
@@ -10982,62 +11273,24 @@ command to generate the output files.
<comment xml:lang="ca">animació d'Egon Animator</comment>
<comment xml:lang="bg">Анимация — Egon Animator</comment>
<comment xml:lang="be@latin">Animacyja Egon Animator</comment>
+ <comment xml:lang="be">анімацыя Egon Animator</comment>
<comment xml:lang="ar">تحريكة محرك Egon</comment>
<generic-icon name="image-x-generic"/>
<glob pattern="*.egon"/>
</mime-type>
<mime-type type="application/x-executable">
- <comment>executable</comment>
- <comment xml:lang="zh_TW">可執行檔</comment>
- <comment xml:lang="zh_CN">可执行文件</comment>
- <comment xml:lang="vi">thực hiện được</comment>
+ <comment>Executable</comment>
<comment xml:lang="uk">виконуваний файл</comment>
- <comment xml:lang="tr">çalıştırılabilir</comment>
- <comment xml:lang="sv">körbar fil</comment>
- <comment xml:lang="sr">извршна</comment>
- <comment xml:lang="sq">I ekzekutueshëm</comment>
- <comment xml:lang="sl">izvedljiva datoteka</comment>
- <comment xml:lang="sk">Spustiteľný súbor</comment>
+ <comment xml:lang="sv">Körbar fil</comment>
<comment xml:lang="ru">Исполняемый</comment>
- <comment xml:lang="ro">executabil</comment>
<comment xml:lang="pt_BR">Executável</comment>
- <comment xml:lang="pt">executável</comment>
<comment xml:lang="pl">Program</comment>
- <comment xml:lang="oc">executable</comment>
- <comment xml:lang="nn">køyrbar</comment>
- <comment xml:lang="nl">uitvoerbaar bestand</comment>
- <comment xml:lang="nb">kjørbar</comment>
- <comment xml:lang="ms">Bolehlaksana</comment>
- <comment xml:lang="lv">izpildāmais</comment>
- <comment xml:lang="lt">vykdomasis failas</comment>
- <comment xml:lang="ko">실행 파일</comment>
- <comment xml:lang="kk">орындалатын</comment>
- <comment xml:lang="ja">実行ファイル</comment>
<comment xml:lang="it">Eseguibile</comment>
- <comment xml:lang="id">dapat dieksekusi</comment>
- <comment xml:lang="ia">Executabile</comment>
- <comment xml:lang="hu">futtatható</comment>
- <comment xml:lang="hr">Izvršna datoteka</comment>
- <comment xml:lang="he">קובץ הרצה</comment>
- <comment xml:lang="gl">executábel</comment>
- <comment xml:lang="ga">comhad inrite</comment>
- <comment xml:lang="fur">eseguibil</comment>
- <comment xml:lang="fr">exécutable</comment>
- <comment xml:lang="fo">inningarfør</comment>
- <comment xml:lang="fi">suoritettava ohjelma</comment>
- <comment xml:lang="eu">exekutagarria</comment>
+ <comment xml:lang="gl">Executábel</comment>
+ <comment xml:lang="eu">Exekutagarria</comment>
<comment xml:lang="es">ejecutable</comment>
- <comment xml:lang="eo">plenumebla</comment>
- <comment xml:lang="en_GB">executable</comment>
- <comment xml:lang="el">Εκτελέσιμο</comment>
- <comment xml:lang="de">Programm</comment>
- <comment xml:lang="da">kørbar</comment>
- <comment xml:lang="cs">spustitelný soubor</comment>
- <comment xml:lang="ca">executable</comment>
- <comment xml:lang="bg">Изпълним файл</comment>
- <comment xml:lang="be@latin">vykonvalny fajł</comment>
- <comment xml:lang="ar">تنفيذي</comment>
- <comment xml:lang="af">uitvoerbaar</comment>
+ <comment xml:lang="de">Ausführbare Datei</comment>
+ <comment xml:lang="be">выконвальны файл</comment>
<generic-icon name="application-x-executable"/>
<magic priority="40">
<match type="string" value="\177ELF" offset="0">
@@ -11062,8 +11315,9 @@ command to generate the output files.
<comment xml:lang="tr">FLTK Fluid dosyası</comment>
<comment xml:lang="sv">FLTK Fluid-fil</comment>
<comment xml:lang="sr">датотека ФЛТК Флуида</comment>
- <comment xml:lang="sq">File FLTK Fluid</comment>
+ <comment xml:lang="sq">kartelë FLTK Fluid</comment>
<comment xml:lang="sl">Datoteka FLTK Fluid</comment>
+ <comment xml:lang="si">FLTK තරල ගොනුව</comment>
<comment xml:lang="sk">Súbor FLTK Fluid</comment>
<comment xml:lang="ru">Файл FLTK Fluid</comment>
<comment xml:lang="ro">Fișier FLTK Fluid</comment>
@@ -11081,6 +11335,7 @@ command to generate the output files.
<comment xml:lang="ka">FLTK Fluid-ის ფაილი</comment>
<comment xml:lang="ja">FLTK Fluid ファイル</comment>
<comment xml:lang="it">File FLTK Fluid</comment>
+ <comment xml:lang="is">FLTK Fluid skrá</comment>
<comment xml:lang="id">Berkas FLTK Fluid</comment>
<comment xml:lang="ia">File Fluid de FLTK</comment>
<comment xml:lang="hu">FLTK Fluid fájl</comment>
@@ -11102,6 +11357,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer FLTK Fluid</comment>
<comment xml:lang="bg">Интерфейс — FLTK Fluid</comment>
<comment xml:lang="be@latin">Fajł FLTK Fluid</comment>
+ <comment xml:lang="be">файл FLTK Fluid</comment>
<comment xml:lang="ar">ملف FLTK Fluid</comment>
<comment xml:lang="af">FLTK Fluit-lêer</comment>
<acronym>FLTK</acronym>
@@ -11121,19 +11377,23 @@ command to generate the output files.
<comment xml:lang="tr">WOFF yazı tipi</comment>
<comment xml:lang="sv">WOFF-typsnitt</comment>
<comment xml:lang="sr">ВОФФ слова</comment>
+ <comment xml:lang="sq">shkronja WOFF</comment>
<comment xml:lang="sl">Pisava WOFF</comment>
+ <comment xml:lang="si">WOFF අකුරු</comment>
<comment xml:lang="sk">Písmo WOFF</comment>
<comment xml:lang="ru">Шрифт WOFF</comment>
<comment xml:lang="pt_BR">Fonte WOFF</comment>
<comment xml:lang="pt">letra WOFF</comment>
<comment xml:lang="pl">Czcionka WOFF</comment>
<comment xml:lang="oc">poliça WOFF</comment>
+ <comment xml:lang="nl">WOFF-lettertype</comment>
<comment xml:lang="lv">WOFF fonts</comment>
<comment xml:lang="lt">WOFF šriftas</comment>
<comment xml:lang="ko">WOFF 글꼴</comment>
<comment xml:lang="kk">WOFF қарібі</comment>
<comment xml:lang="ja">WOFF フォント</comment>
<comment xml:lang="it">Carattere WOFF</comment>
+ <comment xml:lang="is">WOFF letur</comment>
<comment xml:lang="id">Fonta WOFF</comment>
<comment xml:lang="ia">Typo de litteras WOFF</comment>
<comment xml:lang="hu">WOFF-betűkészlet</comment>
@@ -11153,6 +11413,7 @@ command to generate the output files.
<comment xml:lang="cs">font WOFF</comment>
<comment xml:lang="ca">lletra WOFF</comment>
<comment xml:lang="bg">Шрифт — WOFF</comment>
+ <comment xml:lang="be">шрыфт WOFF</comment>
<comment xml:lang="ast">Fonte WOFF</comment>
<comment xml:lang="ar">خط WOFF</comment>
<comment xml:lang="af">WOFF-skriftipe</comment>
@@ -11172,22 +11433,27 @@ command to generate the output files.
<comment xml:lang="uk">шрифт WOFF2</comment>
<comment xml:lang="tr">WOFF2 yazı tipi</comment>
<comment xml:lang="sv">WOFF2-typsnitt</comment>
+ <comment xml:lang="sq">shkronja WOFF2</comment>
<comment xml:lang="sl">Pisava WOFF2</comment>
+ <comment xml:lang="si">WOFF2 අකුරු</comment>
<comment xml:lang="sk">Písmo WOFF2</comment>
<comment xml:lang="ru">Шрифт WOFF2</comment>
<comment xml:lang="pt_BR">Fonte WOFF2</comment>
<comment xml:lang="pt">letra WOFF2</comment>
<comment xml:lang="pl">Czcionka WOFF2</comment>
<comment xml:lang="oc">poliça WOFF2</comment>
+ <comment xml:lang="nl">WOFF2-lettertype</comment>
<comment xml:lang="lt">WOFF2 šriftas</comment>
<comment xml:lang="ko">WOFF2 글꼴</comment>
<comment xml:lang="kk">WOFF2 қарібі</comment>
<comment xml:lang="ja">WOFF2 フォント</comment>
<comment xml:lang="it">Carattere WOFF2</comment>
+ <comment xml:lang="is">WOFF2 letur</comment>
<comment xml:lang="id">Fonta WOFF2</comment>
<comment xml:lang="hu">WOFF2 betűkészlet</comment>
<comment xml:lang="hr">WOFF2 font</comment>
<comment xml:lang="he">גופן WOFF2</comment>
+ <comment xml:lang="gl">Tipo de letra WOFF2</comment>
<comment xml:lang="ga">cló WOFF2</comment>
<comment xml:lang="fur">caratar WOFF2</comment>
<comment xml:lang="fr">police WOFF2</comment>
@@ -11200,6 +11466,7 @@ command to generate the output files.
<comment xml:lang="cs">font WOFF2</comment>
<comment xml:lang="ca">lletra WOFF2</comment>
<comment xml:lang="bg">Шрифт — WOFF2</comment>
+ <comment xml:lang="be">шрыфт WOFF 2</comment>
<comment xml:lang="ast">Fonte WOFF2</comment>
<comment xml:lang="ar">خط WOFF2</comment>
<comment xml:lang="af">WOFF2-skriftipe</comment>
@@ -11219,19 +11486,25 @@ command to generate the output files.
<comment xml:lang="tr">PostScript tip-1 yazı tipi</comment>
<comment xml:lang="sv">PostScript type-1-typsnitt</comment>
<comment xml:lang="sr">слова Постскрипта врсте-1</comment>
+ <comment xml:lang="sq">shkronja PostScript type-1</comment>
+ <comment xml:lang="sl">Datoteka pisave PostScript vrsta-1</comment>
+ <comment xml:lang="si">PostScript වර්ගය-1 අකුරු</comment>
<comment xml:lang="sk">Písmo PostScript typu 1</comment>
<comment xml:lang="ru">Шрифт PostScript Type-1</comment>
<comment xml:lang="pt_BR">Fonte PostScript tipo-1</comment>
<comment xml:lang="pt">letra PostScript Tipo 1</comment>
<comment xml:lang="pl">Czcionka PostScript Type-1</comment>
+ <comment xml:lang="nl">PostScript type-1-lettertype</comment>
<comment xml:lang="ko">PostScript Type-1 글꼴</comment>
<comment xml:lang="kk">PostScript type-1 қарібі</comment>
<comment xml:lang="ja">PostScript type-1 フォント</comment>
<comment xml:lang="it">Carattere PostScript type-1</comment>
+ <comment xml:lang="is">PostScript type-1 letur</comment>
<comment xml:lang="id">Fonta PostScript type-1</comment>
<comment xml:lang="hu">PostScript type-1 betűkészlet</comment>
<comment xml:lang="hr">PostScript type-1 font</comment>
<comment xml:lang="he">גופן PostScript type-1</comment>
+ <comment xml:lang="gl">Tipo de letra PostScript tipo 1</comment>
<comment xml:lang="ga">cló PostScript type-1</comment>
<comment xml:lang="fur">caratar PostScript type-1</comment>
<comment xml:lang="fr">police PostScript Type 1</comment>
@@ -11244,6 +11517,7 @@ command to generate the output files.
<comment xml:lang="cs">font PostScript type-1</comment>
<comment xml:lang="ca">lletra type-1 de PostScript</comment>
<comment xml:lang="bg">Шрифт — PostScript type-1</comment>
+ <comment xml:lang="be">шрыфт PostScript type-1</comment>
<comment xml:lang="ar">خط بوستسكربت النوع ١</comment>
<comment xml:lang="af">PostScript tipe 1-skriftipe</comment>
<sub-class-of type="application/postscript"/>
@@ -11269,8 +11543,9 @@ command to generate the output files.
<comment xml:lang="tr">Adobe yazı tipi ölçüleri</comment>
<comment xml:lang="sv">Adobe-typsnittsmetrik</comment>
<comment xml:lang="sr">метрика Адобе слова</comment>
- <comment xml:lang="sq">Metrik lloj gërmash Adobe</comment>
+ <comment xml:lang="sq">vlera shkronjash Adobe</comment>
<comment xml:lang="sl">Matrika pisave Adobe</comment>
+ <comment xml:lang="si">Adobe අකුරු මිතික</comment>
<comment xml:lang="sk">Metrika písma Adobe</comment>
<comment xml:lang="ru">Метрика шрифта Adobe</comment>
<comment xml:lang="ro">Dimensiuni font Adobe</comment>
@@ -11279,7 +11554,7 @@ command to generate the output files.
<comment xml:lang="pl">Metryka czcionki Adobe</comment>
<comment xml:lang="oc">metricas de poliça Adobe</comment>
<comment xml:lang="nn">Adobe skrifttypemetrikk</comment>
- <comment xml:lang="nl">Adobe-lettertype-metrieken</comment>
+ <comment xml:lang="nl">Adobe lettertype-metrieken</comment>
<comment xml:lang="nb">Adobe skrifttypefil</comment>
<comment xml:lang="ms">Metrik font Adobe</comment>
<comment xml:lang="lv">Adobe fonta metrika</comment>
@@ -11288,6 +11563,7 @@ command to generate the output files.
<comment xml:lang="kk">Adobe қаріп метрикалары</comment>
<comment xml:lang="ja">Adobe フォントメトリック</comment>
<comment xml:lang="it">Metriche tipo carattere Adobe</comment>
+ <comment xml:lang="is">Adobe leturupplýsingar</comment>
<comment xml:lang="id">Metrik fonta Adobe</comment>
<comment xml:lang="ia">Metricas de typo de litteras Adobe</comment>
<comment xml:lang="hu">Adobe-betűmetrika</comment>
@@ -11310,6 +11586,7 @@ command to generate the output files.
<comment xml:lang="ca">mètrica de lletra d'Adobe</comment>
<comment xml:lang="bg">Шрифтова метрика — Adobe</comment>
<comment xml:lang="be@latin">Metryka šryftu Adobe</comment>
+ <comment xml:lang="be">метрыкі шрыфту Adobe</comment>
<comment xml:lang="az">Adobe yazı növü metrikləri</comment>
<comment xml:lang="ar">مقاييس خط أدوبي</comment>
<comment xml:lang="af">Adobe skriftipe-afmetings</comment>
@@ -11325,8 +11602,9 @@ command to generate the output files.
<comment xml:lang="tr">BDF yazı tipi</comment>
<comment xml:lang="sv">BDF-typsnitt</comment>
<comment xml:lang="sr">БДФ слова</comment>
- <comment xml:lang="sq">Lloj gërme BDF</comment>
+ <comment xml:lang="sq">shkronja BDF</comment>
<comment xml:lang="sl">Datoteka pisave BDF</comment>
+ <comment xml:lang="si">BDF අකුරු</comment>
<comment xml:lang="sk">Písmo BDF</comment>
<comment xml:lang="ru">Шрифт BDF</comment>
<comment xml:lang="ro">Font BDF</comment>
@@ -11344,6 +11622,7 @@ command to generate the output files.
<comment xml:lang="kk">BDF қарібі</comment>
<comment xml:lang="ja">BDF フォント</comment>
<comment xml:lang="it">Carattere BDF</comment>
+ <comment xml:lang="is">BDF letur</comment>
<comment xml:lang="id">Fonta BDF</comment>
<comment xml:lang="ia">Typo de litteras BDF</comment>
<comment xml:lang="hu">BDF-betűkészlet</comment>
@@ -11367,6 +11646,7 @@ command to generate the output files.
<comment xml:lang="ca">lletra BDF</comment>
<comment xml:lang="bg">Шрифт — BDF</comment>
<comment xml:lang="be@latin">Šryft BDF</comment>
+ <comment xml:lang="be">шрыфт BDF</comment>
<comment xml:lang="az">BDF yazı növü</comment>
<comment xml:lang="ar">خط BDF</comment>
<comment xml:lang="af">BDF-skriftipe</comment>
@@ -11385,8 +11665,9 @@ command to generate the output files.
<comment xml:lang="tr">DOS yazı tipi</comment>
<comment xml:lang="sv">DOS-typsnitt</comment>
<comment xml:lang="sr">ДОС слова</comment>
- <comment xml:lang="sq">Gërmë DOS</comment>
+ <comment xml:lang="sq">shkronja DOS</comment>
<comment xml:lang="sl">Datoteka pisave DOS</comment>
+ <comment xml:lang="si">DOS අකුරු</comment>
<comment xml:lang="sk">Písmo pre DOS</comment>
<comment xml:lang="ru">Шрифт DOS</comment>
<comment xml:lang="ro">Font DOS</comment>
@@ -11404,6 +11685,7 @@ command to generate the output files.
<comment xml:lang="kk">DOS қарібі</comment>
<comment xml:lang="ja">DOS フォント</comment>
<comment xml:lang="it">Carattere DOS</comment>
+ <comment xml:lang="is">DOS letur</comment>
<comment xml:lang="id">Fonta DOS</comment>
<comment xml:lang="ia">Typo de litteras DOS</comment>
<comment xml:lang="hu">DOS-betűkészlet</comment>
@@ -11427,6 +11709,7 @@ command to generate the output files.
<comment xml:lang="ca">lletra DOS</comment>
<comment xml:lang="bg">Шрифт — DOS</comment>
<comment xml:lang="be@latin">Šryft DOS</comment>
+ <comment xml:lang="be">шрыфт DOS</comment>
<comment xml:lang="az">DOS yazı növü</comment>
<comment xml:lang="ar">خط DOS</comment>
<comment xml:lang="af">DOS-skriftipe</comment>
@@ -11446,8 +11729,9 @@ command to generate the output files.
<comment xml:lang="tr">Adobe FrameMaker yazı tipi</comment>
<comment xml:lang="sv">Adobe FrameMaker-typsnitt</comment>
<comment xml:lang="sr">слова Адобе Фрејм Мејкера</comment>
- <comment xml:lang="sq">Gërma Adobe FrameMaker</comment>
+ <comment xml:lang="sq">shkronja Adobe FrameMaker</comment>
<comment xml:lang="sl">Datoteka pisave Adobe FrameMaker</comment>
+ <comment xml:lang="si">Adobe FrameMaker අකුරු</comment>
<comment xml:lang="sk">Písmo Adobe FrameMaker</comment>
<comment xml:lang="ru">Шрифт Adobe FrameMaker</comment>
<comment xml:lang="ro">Font Adobe FrameMaker</comment>
@@ -11465,6 +11749,7 @@ command to generate the output files.
<comment xml:lang="kk">Adobe FrameMaker қарібі</comment>
<comment xml:lang="ja">Adobe FrameMaker フォント</comment>
<comment xml:lang="it">Carattere Adobe FrameMaker</comment>
+ <comment xml:lang="is">Adobe FrameMaker letur</comment>
<comment xml:lang="id">Fonta Adobe FrameMaker</comment>
<comment xml:lang="ia">Typo de litteras pro Adobe FrameMaker</comment>
<comment xml:lang="hu">Adobe FrameMaker-betűkészlet</comment>
@@ -11488,6 +11773,7 @@ command to generate the output files.
<comment xml:lang="ca">lletra d'Adobe FrameMaker</comment>
<comment xml:lang="bg">Шрифт — Adobe FrameMaker</comment>
<comment xml:lang="be@latin">Šryft Adobe FrameMaker</comment>
+ <comment xml:lang="be">шрыфт Adobe FrameMaker</comment>
<comment xml:lang="az">Adobe FrameMaker yazı növü</comment>
<comment xml:lang="ar">خط أدوبي FrameMaker</comment>
<comment xml:lang="af">Adobe FrameMaker-skriftipe</comment>
@@ -11505,8 +11791,9 @@ command to generate the output files.
<comment xml:lang="tr">LIBGRX yazı tipi</comment>
<comment xml:lang="sv">LIBGRX-typsnitt</comment>
<comment xml:lang="sr">ЛИБГРИкс слова</comment>
- <comment xml:lang="sq">Lloj gërme LIBGRX</comment>
+ <comment xml:lang="sq">shkronja LIBGRX</comment>
<comment xml:lang="sl">Datoteka pisave LIBGRX</comment>
+ <comment xml:lang="si">LIBGRX අකුරු</comment>
<comment xml:lang="sk">Písmo LIBGRX</comment>
<comment xml:lang="ru">Шрифт LIBGRX</comment>
<comment xml:lang="ro">Font LIBGRX</comment>
@@ -11524,6 +11811,7 @@ command to generate the output files.
<comment xml:lang="kk">LIBGRX қарібі</comment>
<comment xml:lang="ja">LIBGRX フォーマット</comment>
<comment xml:lang="it">Carattere LIBGRX</comment>
+ <comment xml:lang="is">LIBGRX letur</comment>
<comment xml:lang="id">Fonta LIBGRX</comment>
<comment xml:lang="ia">Typo de litteras LIBGRX</comment>
<comment xml:lang="hu">LIBGRX-betűkészlet</comment>
@@ -11547,6 +11835,7 @@ command to generate the output files.
<comment xml:lang="ca">lletra LIBGRX</comment>
<comment xml:lang="bg">Шрифт — LIBGRX</comment>
<comment xml:lang="be@latin">Šryft LIBGRX</comment>
+ <comment xml:lang="be">шрыфт LIBGRX</comment>
<comment xml:lang="az">LIBGRX yazı növü</comment>
<comment xml:lang="ar">خط LIBGRX</comment>
<comment xml:lang="af">LIBGRX-skriftipe</comment>
@@ -11564,8 +11853,9 @@ command to generate the output files.
<comment xml:lang="tr">Linux PSF konsol yazı tipi</comment>
<comment xml:lang="sv">Linux PSF-konsoltypsnitt</comment>
<comment xml:lang="sr">слова Линуксове ПСФ конзоле</comment>
- <comment xml:lang="sq">Lloj gërme për konsolë Linux PSF</comment>
+ <comment xml:lang="sq">shkronja konsole Linux PSF</comment>
<comment xml:lang="sl">Datoteka pisave konzole Linux PSF</comment>
+ <comment xml:lang="si">Linux PSF කොන්සෝල අකුරු</comment>
<comment xml:lang="sk">Písmo PSF pre konzolu Linuxu</comment>
<comment xml:lang="ru">Консольный шрифт Linux PSF</comment>
<comment xml:lang="ro">Font consolă Linux PSF</comment>
@@ -11583,6 +11873,7 @@ command to generate the output files.
<comment xml:lang="kk">Linux PSF консольдік қарібі</comment>
<comment xml:lang="ja">Linux PSF コンソールフォント</comment>
<comment xml:lang="it">Carattere console Linux PSF</comment>
+ <comment xml:lang="is">Linux PSF stjórnskjáaletur</comment>
<comment xml:lang="id">Fonta konsol Linux PSF</comment>
<comment xml:lang="ia">Typo de litteras console Linux PSF</comment>
<comment xml:lang="hu">Linux PSF konzolos betűkészlet</comment>
@@ -11606,6 +11897,7 @@ command to generate the output files.
<comment xml:lang="ca">lletra de consola PSF de Linux</comment>
<comment xml:lang="bg">Шрифт — PSF, за конзолата на Линукс</comment>
<comment xml:lang="be@latin">Kansolny šryft PSF dla Linuksa</comment>
+ <comment xml:lang="be">шрыфт кансолі PSF для Linux</comment>
<comment xml:lang="az">Linux PSF konsol yazı növü</comment>
<comment xml:lang="ar">خط كونسول PSF لينكس</comment>
<comment xml:lang="af">Linux PSF-konsoleskriftipe</comment>
@@ -11626,8 +11918,9 @@ command to generate the output files.
<comment xml:lang="tr">Linux PSF konsol yazı tipi (gzip ile sıkıştırılmış)</comment>
<comment xml:lang="sv">Linux PSF-konsoltypsnitt (gzip-komprimerat)</comment>
<comment xml:lang="sr">слова Линуксове ПСФ конзоле (запакована гзип-ом)</comment>
- <comment xml:lang="sq">Lloj gërme për konsolë Linux PSF (komresuar me gzip)</comment>
+ <comment xml:lang="sq">shkronja konsole Linux PSF (ngjeshur me gzip)</comment>
<comment xml:lang="sl">Datoteka pisave konzole Linux PSF (skrčena z gzip)</comment>
+ <comment xml:lang="si">Linux PSF කොන්සෝල අකුරු (gzip-compressed)</comment>
<comment xml:lang="sk">Písmo PSF pre konzolu Linuxu (komprimované pomocou gzip)</comment>
<comment xml:lang="ru">Консольный шрифт Linux PSF (сжатый gzip)</comment>
<comment xml:lang="ro">Font consolă Linux PSF (compresie gzip)</comment>
@@ -11644,6 +11937,7 @@ command to generate the output files.
<comment xml:lang="kk">Linux PSF консольдік қарібі (gzip-пен сығылған)</comment>
<comment xml:lang="ja">Linux PSF コンソールフォント (gzip 圧縮)</comment>
<comment xml:lang="it">Carattere console Linux PSF (compresso con gzip)</comment>
+ <comment xml:lang="is">Linux PSF stjórnskjáaletur (gzip-þjöppað)</comment>
<comment xml:lang="id">Fonta konsol Linux PSF (terkompresi gzip)</comment>
<comment xml:lang="ia">Typo de litteras console Linux PSF (comprimite con gzip)</comment>
<comment xml:lang="hu">Linux PSF konzolos betűkészlet (gzip tömörítésű)</comment>
@@ -11656,7 +11950,7 @@ command to generate the output files.
<comment xml:lang="fo">Linux PSF stýristøðs stavasnið (gzip-stappað)</comment>
<comment xml:lang="fi">Linux PSF -konsolifontti (gzip-pakattu)</comment>
<comment xml:lang="eu">Linux PSF kontsolako letra-tipoa (gzip-ekin konprimitua)</comment>
- <comment xml:lang="es">tipo de letra de consola Linux PSF (comprimido con gzip)</comment>
+ <comment xml:lang="es">tipo de letra de consola Linux PSF (comprimido con GZIP)</comment>
<comment xml:lang="en_GB">Linux PSF console font (gzip-compressed)</comment>
<comment xml:lang="el">Γραμματοσειρά κονσόλας PSF Linux (συμπιεσμένη με gzip)</comment>
<comment xml:lang="de">Linux-PSF-Konsolenschrift (gzip-komprimiert)</comment>
@@ -11665,6 +11959,7 @@ command to generate the output files.
<comment xml:lang="ca">lletra de consola PSF de Linux (amb compressió gzip)</comment>
<comment xml:lang="bg">Шрифт — Linux PSF, компресиран с gzip</comment>
<comment xml:lang="be@latin">Kansolny šryft PSF dla Linuksa (gzip-skampresavany)</comment>
+ <comment xml:lang="be">шрыфт кансолі PSF для Linux (сцісканне gzip)</comment>
<comment xml:lang="ar">خط كونسول PSF لينكس (مضغوط-gzip)</comment>
<comment xml:lang="af">Linux PSF-konsoleskriftipe (gzip-saamgepers)</comment>
<acronym>PSF</acronym>
@@ -11682,8 +11977,9 @@ command to generate the output files.
<comment xml:lang="tr">PCF yazı tipi</comment>
<comment xml:lang="sv">PCF-typsnitt</comment>
<comment xml:lang="sr">ПЦФ слова</comment>
- <comment xml:lang="sq">Gërma PCF</comment>
+ <comment xml:lang="sq">shkronja PCF</comment>
<comment xml:lang="sl">Datoteka pisave PCF</comment>
+ <comment xml:lang="si">PCF අකුරු</comment>
<comment xml:lang="sk">Písmo PCF</comment>
<comment xml:lang="ru">Шрифт PCF</comment>
<comment xml:lang="ro">Font PCF</comment>
@@ -11701,6 +11997,7 @@ command to generate the output files.
<comment xml:lang="kk">PCF қарібі</comment>
<comment xml:lang="ja">PCF フォント</comment>
<comment xml:lang="it">Carattere PCF</comment>
+ <comment xml:lang="is">PCF letur</comment>
<comment xml:lang="id">Fonta PCF</comment>
<comment xml:lang="ia">Typo de litteras PCF</comment>
<comment xml:lang="hu">PCF-betűkészlet</comment>
@@ -11724,6 +12021,7 @@ command to generate the output files.
<comment xml:lang="ca">lletra PCF</comment>
<comment xml:lang="bg">Шрифт — PCF</comment>
<comment xml:lang="be@latin">Šryft PCF</comment>
+ <comment xml:lang="be">шрыфт PCF</comment>
<comment xml:lang="az">PCF yazı növü</comment>
<comment xml:lang="ar">خط PCF</comment>
<comment xml:lang="af">PCF-skriftipe</comment>
@@ -11746,8 +12044,9 @@ command to generate the output files.
<comment xml:lang="tr">OpenType yazı tipi</comment>
<comment xml:lang="sv">OpenType-typsnitt</comment>
<comment xml:lang="sr">слова Отворене Врсте</comment>
- <comment xml:lang="sq">Gërma OpenType</comment>
+ <comment xml:lang="sq">shkronja OpenType</comment>
<comment xml:lang="sl">Datoteka pisave OpenType</comment>
+ <comment xml:lang="si">OpenType අකුරු</comment>
<comment xml:lang="sk">Písmo OpenType</comment>
<comment xml:lang="ru">Шрифт OpenType</comment>
<comment xml:lang="ro">Font OpenType</comment>
@@ -11765,6 +12064,7 @@ command to generate the output files.
<comment xml:lang="kk">OpenType қарібі</comment>
<comment xml:lang="ja">OpenType フォント</comment>
<comment xml:lang="it">Carattere OpenType</comment>
+ <comment xml:lang="is">Open Type letur</comment>
<comment xml:lang="id">Fonta OpenType</comment>
<comment xml:lang="ia">Typo de litteras OpenType</comment>
<comment xml:lang="hu">OpenType-betűkészlet</comment>
@@ -11788,6 +12088,7 @@ command to generate the output files.
<comment xml:lang="ca">lletra OpenType</comment>
<comment xml:lang="bg">Шрифт — OpenType</comment>
<comment xml:lang="be@latin">Šryft OpenType</comment>
+ <comment xml:lang="be">шрыфт OpenType</comment>
<comment xml:lang="az">OpenType yazı növü</comment>
<comment xml:lang="ar">خط OpenType</comment>
<comment xml:lang="af">OpenType-skriftipe</comment>
@@ -11808,8 +12109,9 @@ command to generate the output files.
<comment xml:lang="tr">Speedo yazı tipi</comment>
<comment xml:lang="sv">Speedo-typsnitt</comment>
<comment xml:lang="sr">Спидо слова</comment>
- <comment xml:lang="sq">Gërma Speedo</comment>
+ <comment xml:lang="sq">shkronja Speedo</comment>
<comment xml:lang="sl">Datoteka pisave Speedo</comment>
+ <comment xml:lang="si">ස්පීඩෝ අකුරු</comment>
<comment xml:lang="sk">Písmo Speedo</comment>
<comment xml:lang="ru">Шрифт Speedo</comment>
<comment xml:lang="ro">Font Speedo</comment>
@@ -11827,6 +12129,7 @@ command to generate the output files.
<comment xml:lang="kk">Speedo қарібі</comment>
<comment xml:lang="ja">Speedo フォント</comment>
<comment xml:lang="it">Carattere Speedo</comment>
+ <comment xml:lang="is">Speedo letur</comment>
<comment xml:lang="id">Fonta Speedo</comment>
<comment xml:lang="ia">Typo de litteras Speedo</comment>
<comment xml:lang="hu">Speedo-betűkészlet</comment>
@@ -11850,6 +12153,7 @@ command to generate the output files.
<comment xml:lang="ca">lletra Speedo</comment>
<comment xml:lang="bg">Шрифт — Speedo</comment>
<comment xml:lang="be@latin">Šryft Speedo</comment>
+ <comment xml:lang="be">шрыфт Speedo</comment>
<comment xml:lang="az">Speedo yazı növü</comment>
<comment xml:lang="ar">خط Speedo</comment>
<comment xml:lang="af">Speedo-skriftipe</comment>
@@ -11868,8 +12172,9 @@ command to generate the output files.
<comment xml:lang="tr">SunOS News yazı tipi</comment>
<comment xml:lang="sv">SunOS News-typsnitt</comment>
<comment xml:lang="sr">слова СанОС Њуза</comment>
- <comment xml:lang="sq">Gërma SunOS News</comment>
+ <comment xml:lang="sq">shkronja SunOS News</comment>
<comment xml:lang="sl">Datoteka pisave SunOS News</comment>
+ <comment xml:lang="si">SunOS News අකුරු</comment>
<comment xml:lang="sk">Písmo SunOS News</comment>
<comment xml:lang="ru">Шрифт SunOS News</comment>
<comment xml:lang="ro">Font SunOS News</comment>
@@ -11887,6 +12192,7 @@ command to generate the output files.
<comment xml:lang="kk">SunOS News қарібі</comment>
<comment xml:lang="ja">SunOS News フォント</comment>
<comment xml:lang="it">Carattere SunOS News</comment>
+ <comment xml:lang="is">SunOS News letur</comment>
<comment xml:lang="id">Fonta SunOS News</comment>
<comment xml:lang="ia">Typo de litteras SunOS News</comment>
<comment xml:lang="hu">SunOS News-betűkészlet</comment>
@@ -11903,13 +12209,14 @@ command to generate the output files.
<comment xml:lang="eo">tiparo de SunOS News</comment>
<comment xml:lang="en_GB">SunOS News font</comment>
<comment xml:lang="el">Γραμματοσειρά SunOS News</comment>
- <comment xml:lang="de">SunOS-News-Schrift</comment>
+ <comment xml:lang="de">SunOS-NeWS-Schrift</comment>
<comment xml:lang="da">SunOS News-skrifttype</comment>
<comment xml:lang="cy">Ffont SunOS News</comment>
<comment xml:lang="cs">font SunOS News</comment>
<comment xml:lang="ca">lletra News de SunOS</comment>
<comment xml:lang="bg">Шрифт — SunOS News</comment>
<comment xml:lang="be@latin">Šryft SunOS News</comment>
+ <comment xml:lang="be">шрыфт SunOS News</comment>
<comment xml:lang="az">SunOS News yazı növü</comment>
<comment xml:lang="ar">خط SunOS News</comment>
<comment xml:lang="af">SunOS News-skriftipe</comment>
@@ -11920,6 +12227,29 @@ command to generate the output files.
<match type="string" value="\x13\x7A\x2B" offset="8"/>
</magic>
</mime-type>
+ <mime-type type="application/font-tdpfr">
+ <comment>TDPFR font</comment>
+ <comment xml:lang="uk">шрифт TDPFR</comment>
+ <comment xml:lang="sv">TDPFR-typsnitt</comment>
+ <comment xml:lang="ru">Шрифт TDPFR</comment>
+ <comment xml:lang="pt_BR">Fonte TDPFR</comment>
+ <comment xml:lang="pl">Czcionka TDPFR</comment>
+ <comment xml:lang="it">Carattere TDPFR</comment>
+ <comment xml:lang="gl">Tipo de letra TDPFR</comment>
+ <comment xml:lang="eu">TDPFR letra-tipoa</comment>
+ <comment xml:lang="es">tipo de letra TDPFR</comment>
+ <comment xml:lang="de">TDPFR-Schrift</comment>
+ <comment xml:lang="be">шрыфт TDPFR</comment>
+ <acronym>TDPFR</acronym>
+ <expanded-acronym>TrueDoc Portable Font Resource</expanded-acronym>
+ <generic-icon name="font-x-generic"/>
+ <magic>
+ <match type="big32" value="0x50465230" offset="0"/>
+ <match type="big32" value="0x50465231" offset="0"/>
+ </magic>
+ <glob pattern="*.pfr"/>
+ <alias type="application/vnd.truedoc"/>
+ </mime-type>
<mime-type type="application/x-font-tex">
<comment>TeX font</comment>
<comment xml:lang="zh_TW">TeX 字型</comment>
@@ -11929,8 +12259,9 @@ command to generate the output files.
<comment xml:lang="tr">TeX yazı tipi</comment>
<comment xml:lang="sv">TeX-typsnitt</comment>
<comment xml:lang="sr">ТеКс слова</comment>
- <comment xml:lang="sq">Gërma TeX</comment>
+ <comment xml:lang="sq">shkronja TeX</comment>
<comment xml:lang="sl">Datoteka pisave TeX</comment>
+ <comment xml:lang="si">TeX අකුරු</comment>
<comment xml:lang="sk">Písmo TeX</comment>
<comment xml:lang="ru">Шрифт TeX</comment>
<comment xml:lang="ro">Font TeX</comment>
@@ -11948,6 +12279,7 @@ command to generate the output files.
<comment xml:lang="kk">TeX қарібі</comment>
<comment xml:lang="ja">TeX フォント</comment>
<comment xml:lang="it">Carattere TeX</comment>
+ <comment xml:lang="is">TeX letur</comment>
<comment xml:lang="id">Fonta TeX</comment>
<comment xml:lang="ia">Typo de litteras TeX</comment>
<comment xml:lang="hu">TeX-betűkészlet</comment>
@@ -11971,6 +12303,7 @@ command to generate the output files.
<comment xml:lang="ca">lletra TeX</comment>
<comment xml:lang="bg">Шрифт — TeX</comment>
<comment xml:lang="be@latin">Šryft TeX</comment>
+ <comment xml:lang="be">шрыфт TeX</comment>
<comment xml:lang="az">TeX yazı növü</comment>
<comment xml:lang="ar">خط TeX</comment>
<comment xml:lang="af">TeX-skriftipe</comment>
@@ -11990,8 +12323,9 @@ command to generate the output files.
<comment xml:lang="tr">TeX yazı tipi ölçüleri</comment>
<comment xml:lang="sv">TeX-typsnittsmetrik</comment>
<comment xml:lang="sr">метрика слова ТеКс-а</comment>
- <comment xml:lang="sq">Gërma TeX metrics</comment>
+ <comment xml:lang="sq">vlera shkronjash TeX</comment>
<comment xml:lang="sl">Matrika pisave Tex</comment>
+ <comment xml:lang="si">TeX අකුරු ප්‍රමිතික</comment>
<comment xml:lang="sk">Metrika písma TeX</comment>
<comment xml:lang="ru">Метрика шрифта TeX</comment>
<comment xml:lang="ro">Dimensiuni font TeX</comment>
@@ -12009,6 +12343,7 @@ command to generate the output files.
<comment xml:lang="kk">TeX қаріп метрикалары</comment>
<comment xml:lang="ja">TeX フォントメトリック</comment>
<comment xml:lang="it">Metriche tipo carattere TeX</comment>
+ <comment xml:lang="is">TeX leturupplýsingar</comment>
<comment xml:lang="id">Fonta metrik TeX</comment>
<comment xml:lang="ia">Metricas de typo de litteras TeX</comment>
<comment xml:lang="hu">TeX-betűmetrika</comment>
@@ -12031,6 +12366,7 @@ command to generate the output files.
<comment xml:lang="ca">mètrica de lletra de TeX</comment>
<comment xml:lang="bg">Шрифтова метрика — TeX</comment>
<comment xml:lang="be@latin">Metryka šryftu TeX</comment>
+ <comment xml:lang="be">метрыкі шрыфту TeX</comment>
<comment xml:lang="az">TeX yazı növü metrikləri</comment>
<comment xml:lang="ar">مقاييس خط TeX</comment>
<comment xml:lang="af">TeX-skriftipeafmetings</comment>
@@ -12049,8 +12385,9 @@ command to generate the output files.
<comment xml:lang="tr">TrueType yazı tipi</comment>
<comment xml:lang="sv">Truetype-typsnitt</comment>
<comment xml:lang="sr">Трутајп слова</comment>
- <comment xml:lang="sq">Lloj gërme TrueType</comment>
+ <comment xml:lang="sq">shkronja TrueType</comment>
<comment xml:lang="sl">Datoteka pisave TrueType</comment>
+ <comment xml:lang="si">TrueType අකුරු</comment>
<comment xml:lang="sk">Písmo TrueType</comment>
<comment xml:lang="ru">Шрифт TrueType</comment>
<comment xml:lang="ro">Font TrueType</comment>
@@ -12068,6 +12405,7 @@ command to generate the output files.
<comment xml:lang="kk">TrueType қарібі</comment>
<comment xml:lang="ja">TrueType フォント</comment>
<comment xml:lang="it">Carattere TrueType</comment>
+ <comment xml:lang="is">TrueType letur</comment>
<comment xml:lang="id">Fonta TrueType</comment>
<comment xml:lang="ia">Typo de litteras TrueType</comment>
<comment xml:lang="hu">TrueType-betűkészlet</comment>
@@ -12090,6 +12428,7 @@ command to generate the output files.
<comment xml:lang="ca">lletra TrueType</comment>
<comment xml:lang="bg">Шрифт — TrueType</comment>
<comment xml:lang="be@latin">Šryft TrueType</comment>
+ <comment xml:lang="be">шрыфт TrueType</comment>
<comment xml:lang="ar">خط TrueType</comment>
<comment xml:lang="af">TrueType-skriftipe</comment>
<generic-icon name="font-x-generic"/>
@@ -12108,20 +12447,25 @@ command to generate the output files.
<comment xml:lang="uk">збірка шрифтів</comment>
<comment xml:lang="tr">Yazı tipi derlemi</comment>
<comment xml:lang="sv">Typsnittssamling</comment>
+ <comment xml:lang="sq">koleksion shkronjash</comment>
<comment xml:lang="sl">Zbirka pisav</comment>
+ <comment xml:lang="si">අකුරු එකතුව</comment>
<comment xml:lang="sk">Zbierka písiem</comment>
<comment xml:lang="ru">Коллекция шрифтов</comment>
<comment xml:lang="pt_BR">Coleção de fontes</comment>
<comment xml:lang="pt">coleção de letras</comment>
<comment xml:lang="pl">Kolekcja czcionek</comment>
+ <comment xml:lang="nl">Lettertypeverzameling</comment>
<comment xml:lang="ko">글꼴 모음</comment>
<comment xml:lang="kk">Қаріптер жинағы</comment>
<comment xml:lang="ja">フォントコレクション</comment>
<comment xml:lang="it">Raccolta di caratteri</comment>
+ <comment xml:lang="is">Letursafn</comment>
<comment xml:lang="id">Koleksi fonta</comment>
<comment xml:lang="hu">Betűkészlet-gyűjtemény</comment>
<comment xml:lang="hr">Zbirka fontova</comment>
<comment xml:lang="he">אוסף גופנים</comment>
+ <comment xml:lang="gl">Colección de tipo de letra</comment>
<comment xml:lang="ga">bailiúchán clónna</comment>
<comment xml:lang="fur">colezion di caratars</comment>
<comment xml:lang="fr">Collection de polices</comment>
@@ -12134,6 +12478,7 @@ command to generate the output files.
<comment xml:lang="cs">kolekce fontů</comment>
<comment xml:lang="ca">ccol·lecció de lletres</comment>
<comment xml:lang="bg">Шрифтова колекция</comment>
+ <comment xml:lang="be">калекцыя шрыфтоў</comment>
<comment xml:lang="ar">تجميعة خط</comment>
<comment xml:lang="af">Skriftipeversameling</comment>
<generic-icon name="font-x-generic"/>
@@ -12148,8 +12493,9 @@ command to generate the output files.
<comment xml:lang="tr">TrueType XML yazı tipi</comment>
<comment xml:lang="sv">Truetype XML-typsnitt</comment>
<comment xml:lang="sr">Трутајп ИксМЛ слова</comment>
- <comment xml:lang="sq">Lloj gërme TrueType XML</comment>
+ <comment xml:lang="sq">shkronja TrueType XML</comment>
<comment xml:lang="sl">Datoteka pisave TrueType XML</comment>
+ <comment xml:lang="si">TrueType XML අකුරු</comment>
<comment xml:lang="sk">Písmo TrueType XML</comment>
<comment xml:lang="ru">Шрифт TrueType XML</comment>
<comment xml:lang="ro">Font XML TrueType</comment>
@@ -12166,6 +12512,7 @@ command to generate the output files.
<comment xml:lang="kk">TrueType XML қарібі</comment>
<comment xml:lang="ja">TrueType XML フォント</comment>
<comment xml:lang="it">Carattere TrueType XML</comment>
+ <comment xml:lang="is">TrueType XML letur</comment>
<comment xml:lang="id">Fonta TrueType XML</comment>
<comment xml:lang="ia">Typo de litteras TrueType XML</comment>
<comment xml:lang="hu">TrueType XML betűkészlet</comment>
@@ -12187,6 +12534,7 @@ command to generate the output files.
<comment xml:lang="ca">lletra XML de TrueType</comment>
<comment xml:lang="bg">Шрифт — TrueType XML</comment>
<comment xml:lang="be@latin">Šryft TrueType XML</comment>
+ <comment xml:lang="be">шрыфт TrueType XML</comment>
<comment xml:lang="ar">خط TrueType XML</comment>
<comment xml:lang="af">TrueType XML-skriftipe</comment>
<sub-class-of type="application/xml"/>
@@ -12205,10 +12553,11 @@ command to generate the output files.
<comment xml:lang="tr">V yazı tipi</comment>
<comment xml:lang="sv">V-typsnitt</comment>
<comment xml:lang="sr">В слова</comment>
- <comment xml:lang="sq">Gërmë V</comment>
+ <comment xml:lang="sq">shkronja V</comment>
<comment xml:lang="sl">Datoteka pisave V</comment>
+ <comment xml:lang="si">V අකුරු</comment>
<comment xml:lang="sk">Písmo V</comment>
- <comment xml:lang="ru">Шрифт V font</comment>
+ <comment xml:lang="ru">V-шрифт</comment>
<comment xml:lang="ro">Font V</comment>
<comment xml:lang="pt_BR">Fonte V</comment>
<comment xml:lang="pt">letra V</comment>
@@ -12224,6 +12573,7 @@ command to generate the output files.
<comment xml:lang="kk">V font қарібі</comment>
<comment xml:lang="ja">V フォント</comment>
<comment xml:lang="it">Carattere V</comment>
+ <comment xml:lang="is">V letur</comment>
<comment xml:lang="id">Fonta V</comment>
<comment xml:lang="ia">Typo de litteras V</comment>
<comment xml:lang="hu">V-betűkészlet</comment>
@@ -12247,6 +12597,7 @@ command to generate the output files.
<comment xml:lang="ca">lletra V</comment>
<comment xml:lang="bg">Шрифт — V</comment>
<comment xml:lang="be@latin">Šryft V</comment>
+ <comment xml:lang="be">шрыфт V</comment>
<comment xml:lang="az">V yazı növü</comment>
<comment xml:lang="ar">خط V</comment>
<comment xml:lang="af">V-skriftipe</comment>
@@ -12264,8 +12615,9 @@ command to generate the output files.
<comment xml:lang="tr">Adobe FrameMaker belgesi</comment>
<comment xml:lang="sv">Adobe FrameMaker-dokument</comment>
<comment xml:lang="sr">документ Адобе Фреј Мејкера</comment>
- <comment xml:lang="sq">Dokument Adobe FrameMaker</comment>
+ <comment xml:lang="sq">dokument Adobe FrameMaker</comment>
<comment xml:lang="sl">Dokument Adobe FrameMaker</comment>
+ <comment xml:lang="si">Adobe FrameMaker ලේඛනය</comment>
<comment xml:lang="sk">Dokument Adobe FrameMaker</comment>
<comment xml:lang="ru">Документ Adobe FrameMaker</comment>
<comment xml:lang="ro">Document Adobe FrameMaker</comment>
@@ -12283,6 +12635,7 @@ command to generate the output files.
<comment xml:lang="ka">Adobe FrameMaker-ის დოკუმენტი</comment>
<comment xml:lang="ja">Adobe FrameMaker ドキュメント</comment>
<comment xml:lang="it">Documento Adobe FrameMaker</comment>
+ <comment xml:lang="is">Adobe FrameMaker skjal</comment>
<comment xml:lang="id">Dokumen Adobe FrameMaker</comment>
<comment xml:lang="ia">Documento Adobe FrameMaker</comment>
<comment xml:lang="hu">Adobe FrameMaker-dokumentum</comment>
@@ -12305,6 +12658,7 @@ command to generate the output files.
<comment xml:lang="ca">document d'Adobe FrameMaker</comment>
<comment xml:lang="bg">Документ — Adobe FrameMaker</comment>
<comment xml:lang="be@latin">Dakument Adobe FrameMaker</comment>
+ <comment xml:lang="be">дакумент Adobe FrameMaker</comment>
<comment xml:lang="ast">Documentu d'Adobe FrameMaker</comment>
<comment xml:lang="ar">مستند أدوبي FrameMaker</comment>
<comment xml:lang="af">Adobe FrameMaker-dokument</comment>
@@ -12332,6 +12686,7 @@ command to generate the output files.
<comment xml:lang="sr">Гејм Бој РОМ</comment>
<comment xml:lang="sq">ROM Game Boy</comment>
<comment xml:lang="sl">Bralni pomnilnik Game Boy</comment>
+ <comment xml:lang="si">Game Boy ROM</comment>
<comment xml:lang="sk">ROM pre Game Boy</comment>
<comment xml:lang="ru">Game Boy ROM</comment>
<comment xml:lang="ro">ROM Game Boy</comment>
@@ -12350,6 +12705,7 @@ command to generate the output files.
<comment xml:lang="ka">Game Boy-ის ROM</comment>
<comment xml:lang="ja">ゲームボーイ ROM</comment>
<comment xml:lang="it">ROM Game Boy</comment>
+ <comment xml:lang="is">Game Boy ROM</comment>
<comment xml:lang="id">Memori baca-saja Game Boy</comment>
<comment xml:lang="ia">ROM de Game Boy</comment>
<comment xml:lang="hu">Game Boy ROM</comment>
@@ -12366,12 +12722,13 @@ command to generate the output files.
<comment xml:lang="eo">NLM de Game Boy</comment>
<comment xml:lang="en_GB">Game Boy ROM</comment>
<comment xml:lang="el">Game Boy ROM</comment>
- <comment xml:lang="de">Game Boy ROM</comment>
+ <comment xml:lang="de">Game-Boy-ROM</comment>
<comment xml:lang="da">Game Boy-ROM</comment>
<comment xml:lang="cs">ROM pro Game Boy</comment>
<comment xml:lang="ca">ROM de Game Boy</comment>
<comment xml:lang="bg">ROM — Game Boy</comment>
<comment xml:lang="be@latin">Game Boy ROM</comment>
+ <comment xml:lang="be">Game Boy ROM</comment>
<comment xml:lang="ar">Game Boy ROM</comment>
<generic-icon name="application-x-executable"/>
<magic>
@@ -12390,19 +12747,25 @@ command to generate the output files.
<comment xml:lang="tr">Game Boy Color ROM</comment>
<comment xml:lang="sv">Game Boy Color-rom</comment>
<comment xml:lang="sr">Гејм Бој РОМ боје</comment>
+ <comment xml:lang="sq">ROM Game Boy Color</comment>
+ <comment xml:lang="sl">Game Boy Color ROM</comment>
+ <comment xml:lang="si">Game Boy Color ROM</comment>
<comment xml:lang="sk">ROM pre Game Boy Color</comment>
<comment xml:lang="ru">Game Boy Color ROM</comment>
<comment xml:lang="pt_BR">ROM de Game Boy Color</comment>
<comment xml:lang="pl">Plik ROM konsoli Game Boy Color</comment>
<comment xml:lang="oc">ROM Game Boy Color</comment>
+ <comment xml:lang="nl">Game Boy Color-ROM</comment>
<comment xml:lang="ko">게임보이 컬러 롬</comment>
<comment xml:lang="kk">Game Boy Color ROM</comment>
<comment xml:lang="ja">ゲームボーイカラー ROM</comment>
<comment xml:lang="it">ROM Game Boy Color</comment>
+ <comment xml:lang="is">Game Boy Color ROM</comment>
<comment xml:lang="id">ROM Game Boy Color</comment>
<comment xml:lang="hu">Game Boy Color ROM</comment>
<comment xml:lang="hr">Game Boy Color ROM</comment>
<comment xml:lang="he">ROM של Game Boy Color</comment>
+ <comment xml:lang="gl">ROM de Game Boy Color</comment>
<comment xml:lang="ga">ROM Game Boy Color</comment>
<comment xml:lang="fur">ROM Game Boy Color</comment>
<comment xml:lang="fr">ROM Game Boy Color</comment>
@@ -12410,11 +12773,12 @@ command to generate the output files.
<comment xml:lang="eu">Game Boy Color ROM</comment>
<comment xml:lang="es">ROM de Game Boy Color</comment>
<comment xml:lang="en_GB">Game Boy Colour ROM</comment>
- <comment xml:lang="de">Game Boy Color ROM</comment>
+ <comment xml:lang="de">Game-Boy-Color-ROM</comment>
<comment xml:lang="da">Game Boy Color-ROM</comment>
<comment xml:lang="cs">ROM pro Game Boy Color</comment>
<comment xml:lang="ca">ROM de Game Boy Color</comment>
<comment xml:lang="bg">ROM — Game Boy Color</comment>
+ <comment xml:lang="be">Game Boy Color ROM</comment>
<comment xml:lang="ar">روم جيم بوي كولر</comment>
<generic-icon name="application-x-executable"/>
<magic>
@@ -12436,6 +12800,7 @@ command to generate the output files.
<comment xml:lang="sr">Гејм Бој Адванс РОМ</comment>
<comment xml:lang="sq">ROM Game Boy Advance</comment>
<comment xml:lang="sl">Bralni pomnilnik Game Boy Advance</comment>
+ <comment xml:lang="si">Game Boy Advance ROM</comment>
<comment xml:lang="sk">ROM pre Game Boy Advance</comment>
<comment xml:lang="ru">Game Boy Advance ROM</comment>
<comment xml:lang="ro">ROM Game Boy Advance</comment>
@@ -12453,6 +12818,7 @@ command to generate the output files.
<comment xml:lang="ka">Game Boy Advance-ის ROM</comment>
<comment xml:lang="ja">ゲームボーイアドバンス ROM</comment>
<comment xml:lang="it">ROM Game Boy Advance</comment>
+ <comment xml:lang="is">Game Boy Advance ROM</comment>
<comment xml:lang="id">Memori baca-saja Game Boy Advance</comment>
<comment xml:lang="ia">ROM de Game Boy Advance</comment>
<comment xml:lang="hu">Game Boy Advance ROM</comment>
@@ -12468,12 +12834,13 @@ command to generate the output files.
<comment xml:lang="es">ROM de Game Boy Advance</comment>
<comment xml:lang="en_GB">Game Boy Advance ROM</comment>
<comment xml:lang="el">Game Boy Advance ROM</comment>
- <comment xml:lang="de">Game Boy Advance ROM</comment>
+ <comment xml:lang="de">Game-Boy-Advance-ROM</comment>
<comment xml:lang="da">Game Boy Advance-ROM</comment>
<comment xml:lang="cs">ROM pro Game Boy Advance</comment>
<comment xml:lang="ca">ROM de Game Boy Advance</comment>
<comment xml:lang="bg">ROM — Game Boy Advance</comment>
<comment xml:lang="be@latin">Game Boy Advance ROM</comment>
+ <comment xml:lang="be">Game Boy Advance ROM</comment>
<comment xml:lang="ar">Game Boy Advance ROM</comment>
<generic-icon name="application-x-executable"/>
<glob pattern="*.gba"/>
@@ -12486,19 +12853,25 @@ command to generate the output files.
<comment xml:lang="uk">ROM Virtual Boy</comment>
<comment xml:lang="tr">Virtual Boy ROM</comment>
<comment xml:lang="sv">Virtual Boy-rom</comment>
+ <comment xml:lang="sq">ROM Virtual Boy</comment>
+ <comment xml:lang="sl">Virtual Boy ROM</comment>
+ <comment xml:lang="si">Virtual Boy ROM</comment>
<comment xml:lang="sk">ROM pre Virtual Boy</comment>
<comment xml:lang="ru">Virtual Boy ROM</comment>
<comment xml:lang="pt_BR">ROM de Virtual Boy</comment>
<comment xml:lang="pt">ROM Virtua Boy</comment>
<comment xml:lang="pl">Plik ROM konsoli Virtual Boy</comment>
+ <comment xml:lang="nl">Virtual Boy-ROM</comment>
<comment xml:lang="ko">버추얼 보이 롬</comment>
<comment xml:lang="kk">Virtual Boy ROM</comment>
<comment xml:lang="ja">バーチャルボーイ ROM</comment>
<comment xml:lang="it">ROM Virtual Boy</comment>
+ <comment xml:lang="is">Virtual Boy ROM</comment>
<comment xml:lang="id">ROM Virtual Boy</comment>
<comment xml:lang="hu">Virtual Boy ROM</comment>
<comment xml:lang="hr">Virtual Boy ROM</comment>
<comment xml:lang="he">ROM של Virtual Boy</comment>
+ <comment xml:lang="gl">ROM de Virtual Boy</comment>
<comment xml:lang="ga">ROM Virtual Boy</comment>
<comment xml:lang="fur">ROM Virtual Boy</comment>
<comment xml:lang="fr">ROM Virtual Boy</comment>
@@ -12506,11 +12879,12 @@ command to generate the output files.
<comment xml:lang="eu">Virtual Boy ROM</comment>
<comment xml:lang="es">ROM de Virtual Boy</comment>
<comment xml:lang="en_GB">Virtual Boy ROM</comment>
- <comment xml:lang="de">Virtual Boy ROM</comment>
+ <comment xml:lang="de">Virtual-Boy-ROM</comment>
<comment xml:lang="da">Virtual Boy-ROM</comment>
<comment xml:lang="cs">ROM pro Virtual Boy</comment>
<comment xml:lang="ca">ROM de Virtual Boy</comment>
<comment xml:lang="bg">ROM — Virtual Boy</comment>
+ <comment xml:lang="be">Virtual Boy ROM</comment>
<comment xml:lang="ar">روم بوي الافتراضي</comment>
<generic-icon name="application-x-executable"/>
<glob pattern="*.vb"/>
@@ -12524,8 +12898,9 @@ command to generate the output files.
<comment xml:lang="tr">GDBM veri tabanı</comment>
<comment xml:lang="sv">GDBM-databas</comment>
<comment xml:lang="sr">ГДБМ база података</comment>
- <comment xml:lang="sq">Bazë me të dhëna GDBM</comment>
+ <comment xml:lang="sq">bazë të dhënash GDBM</comment>
<comment xml:lang="sl">Podatkovna zbirka GDBM</comment>
+ <comment xml:lang="si">GDBM දත්ත සමුදාය</comment>
<comment xml:lang="sk">Databáza GDBM</comment>
<comment xml:lang="ru">База данных GDBM</comment>
<comment xml:lang="ro">Bază de date GDBM</comment>
@@ -12534,7 +12909,7 @@ command to generate the output files.
<comment xml:lang="pl">Baza danych GDBM</comment>
<comment xml:lang="oc">banca de donadas GDBM</comment>
<comment xml:lang="nn">GDBM-database</comment>
- <comment xml:lang="nl">GDBM-gegevensbank</comment>
+ <comment xml:lang="nl">GDBM-database</comment>
<comment xml:lang="nb">GDBM-database</comment>
<comment xml:lang="lv">GDBM datubāze</comment>
<comment xml:lang="lt">GDBM duomenų bazė</comment>
@@ -12543,6 +12918,7 @@ command to generate the output files.
<comment xml:lang="ka">GDBM მონაცემთა ბაზა</comment>
<comment xml:lang="ja">GDBM データベース</comment>
<comment xml:lang="it">Database GDBM</comment>
+ <comment xml:lang="is">GDBM gagnagrunnur</comment>
<comment xml:lang="id">Basis data GDBM</comment>
<comment xml:lang="ia">Base de datos GDBM</comment>
<comment xml:lang="hu">GDBM adatbázis</comment>
@@ -12565,6 +12941,7 @@ command to generate the output files.
<comment xml:lang="ca">base de dades GDBM</comment>
<comment xml:lang="bg">База от данни — GDBM</comment>
<comment xml:lang="be@latin">Baza źviestak GDBM</comment>
+ <comment xml:lang="be">база даных GDBM</comment>
<comment xml:lang="ar">قاعدة بيانات GDBM</comment>
<comment xml:lang="af">GDBM-databasis</comment>
<acronym>GDBM</acronym>
@@ -12588,6 +12965,7 @@ command to generate the output files.
<comment xml:lang="sr">Мегадрајв РОМ</comment>
<comment xml:lang="sq">ROM Genesis</comment>
<comment xml:lang="sl">Bralni pomnilnik Genesis</comment>
+ <comment xml:lang="si">උත්පත්ති ROM</comment>
<comment xml:lang="sk">ROM pre Megadrive</comment>
<comment xml:lang="ru">Genesis ROM</comment>
<comment xml:lang="ro">ROM Genesis</comment>
@@ -12596,7 +12974,7 @@ command to generate the output files.
<comment xml:lang="pl">Plik ROM konsoli Mega Drive</comment>
<comment xml:lang="oc">ROM Mega Drive/Genesis</comment>
<comment xml:lang="nn">Genesis-ROM</comment>
- <comment xml:lang="nl">Mega Drive</comment>
+ <comment xml:lang="nl">Mega Drive-ROM</comment>
<comment xml:lang="nb">Genesis-ROM</comment>
<comment xml:lang="ms">ROM Genesis</comment>
<comment xml:lang="lv">Genesis ROM</comment>
@@ -12605,6 +12983,7 @@ command to generate the output files.
<comment xml:lang="kk">Genesis ROM</comment>
<comment xml:lang="ja">メガドライブ ROM</comment>
<comment xml:lang="it">ROM Megadrive</comment>
+ <comment xml:lang="is">Genesis ROM</comment>
<comment xml:lang="id">Memori baca-saja Genesis</comment>
<comment xml:lang="ia">ROM de Mega Drive/Genesis</comment>
<comment xml:lang="hu">Genesis ROM</comment>
@@ -12621,12 +13000,13 @@ command to generate the output files.
<comment xml:lang="eo">Genesis-NLM</comment>
<comment xml:lang="en_GB">Genesis ROM</comment>
<comment xml:lang="el">Genesis ROM</comment>
- <comment xml:lang="de">Genesis ROM</comment>
+ <comment xml:lang="de">Mega-Drive-ROM</comment>
<comment xml:lang="da">Genesis-ROM</comment>
<comment xml:lang="cs">ROM pro Genesis</comment>
<comment xml:lang="ca">ROM de Genesis</comment>
<comment xml:lang="bg">ROM — Genesis</comment>
<comment xml:lang="be@latin">Genesis ROM</comment>
+ <comment xml:lang="be">Genesis ROM</comment>
<comment xml:lang="ar">روم Genesis</comment>
<generic-icon name="application-x-executable"/>
<magic>
@@ -12650,19 +13030,25 @@ command to generate the output files.
<comment xml:lang="tr">Genesis 32X ROM</comment>
<comment xml:lang="sv">Mega Drive 32X-rom</comment>
<comment xml:lang="sr">Џенезис 32X РОМ</comment>
+ <comment xml:lang="sq">ROM Genesis 32X</comment>
+ <comment xml:lang="sl">Genesis 32X ROM</comment>
+ <comment xml:lang="si">උත්පත්ති 32X ROM</comment>
<comment xml:lang="sk">ROM pre Genesis 32X</comment>
<comment xml:lang="ru">Genesis 32X ROM</comment>
<comment xml:lang="pt_BR">ROM de Genesis 32X</comment>
<comment xml:lang="pt">ROM Genesis 32X</comment>
<comment xml:lang="pl">Plik ROM konsoli Mega Drive 32X</comment>
+ <comment xml:lang="nl">Mega Drive 32X-ROM</comment>
<comment xml:lang="ko">제네시스 32X 롬</comment>
<comment xml:lang="kk">Genesis 32X ROM</comment>
<comment xml:lang="ja">メガドライブ 32X ROM</comment>
<comment xml:lang="it">ROM Sega Mega Drive 32X</comment>
+ <comment xml:lang="is">Genesis 32X ROM</comment>
<comment xml:lang="id">ROM Genesis 32X</comment>
<comment xml:lang="hu">Genesis 32X ROM</comment>
<comment xml:lang="hr">Genesis 32X ROM</comment>
<comment xml:lang="he">ROM מסוג Genesis 32X</comment>
+ <comment xml:lang="gl">ROM Genesis 32X</comment>
<comment xml:lang="ga">ROM Genesis 32X</comment>
<comment xml:lang="fur">ROM Sega Mega Drive 32X</comment>
<comment xml:lang="fr">ROM Genesis 32X</comment>
@@ -12670,11 +13056,12 @@ command to generate the output files.
<comment xml:lang="eu">Genesis 32X ROM</comment>
<comment xml:lang="es">ROM de Genesis 32X</comment>
<comment xml:lang="en_GB">Genesis 32X ROM</comment>
- <comment xml:lang="de">Genesis 32X ROM</comment>
+ <comment xml:lang="de">Mega-32X-ROM</comment>
<comment xml:lang="da">Genesis 32X-ROM</comment>
<comment xml:lang="cs">ROM pro Genesis 32X</comment>
<comment xml:lang="ca">ROM de Genesis 32X</comment>
<comment xml:lang="bg">ROM — Genesis 32X</comment>
+ <comment xml:lang="be">Genesis 32X ROM</comment>
<comment xml:lang="ar">روم Genesis 32X</comment>
<generic-icon name="application-x-executable"/>
<magic>
@@ -12684,58 +13071,17 @@ command to generate the output files.
<glob pattern="*.mdx"/>
</mime-type>
<mime-type type="application/x-gettext-translation">
- <comment>translated messages (machine-readable)</comment>
- <comment xml:lang="zh_TW">翻譯訊息 (程式讀取格式)</comment>
- <comment xml:lang="zh_CN">已翻译消息(机读)</comment>
- <comment xml:lang="vi">thông điệp đã dịch (máy đọc được)</comment>
+ <comment>Translated messages (machine-readable)</comment>
<comment xml:lang="uk">перекладені повідомлення (у машинній формі)</comment>
- <comment xml:lang="tr">çevrilmiş iletiler (makine tarafından okunabilir)</comment>
- <comment xml:lang="sv">översatta meddelanden (maskinläsbara)</comment>
- <comment xml:lang="sr">преведене поруке (машинама читљиве)</comment>
- <comment xml:lang="sq">Mesazhe të përkthyer (të lexueshëm nga makina)</comment>
- <comment xml:lang="sl">prevedena sporočila (strojni zapis)</comment>
- <comment xml:lang="sk">Preložené správy (strojovo čitateľné)</comment>
+ <comment xml:lang="sv">Översatta meddelanden (maskinläsbara)</comment>
<comment xml:lang="ru">Переводы сообщений (откомпилированые)</comment>
- <comment xml:lang="ro">mesaje traduse (citite de calculator)</comment>
- <comment xml:lang="pt_BR">Mensagens traduzidas (legível pelo computador)</comment>
- <comment xml:lang="pt">mensagens traduzidas (leitura pelo computador)</comment>
<comment xml:lang="pl">Przetłumaczone komunikaty (czytelne dla komputera)</comment>
- <comment xml:lang="oc">messatges tradusits (legibles per maquina)</comment>
- <comment xml:lang="nn">oversette meldingar (maskinlesbare)</comment>
- <comment xml:lang="nl">vertaalde berichten (machine-leesbaar)</comment>
- <comment xml:lang="nb">oversatte meldinger (maskinlesbar)</comment>
- <comment xml:lang="ms">Mesej diterjemah (bolehdibaca-mesin)</comment>
- <comment xml:lang="lv">pārtulkotie ziņojumi (mašīnlasāms)</comment>
- <comment xml:lang="lt">išversti užrašai (kompiuteriniu formatu)</comment>
- <comment xml:lang="ko">번역 메시지(컴퓨터 사용 형식)</comment>
- <comment xml:lang="kk">аударылған хабарламалар (машиналық түрде)</comment>
- <comment xml:lang="ka">ნათარგმნი შეტყობინებები (მანქანისთვის განკუთვნილი)</comment>
- <comment xml:lang="ja">翻訳メッセージ (マシン用)</comment>
<comment xml:lang="it">Messaggi tradotti (leggibili da macchina)</comment>
- <comment xml:lang="id">pesan diterjemahkan (dapat dibaca mesin)</comment>
- <comment xml:lang="ia">messages traducite (legibile pro machinas)</comment>
- <comment xml:lang="hu">lefordított üzenetek (gépi kód)</comment>
- <comment xml:lang="hr">Prevedene poruke (strojno čitljive)</comment>
- <comment xml:lang="he">הודעות מתורגמות (מובן ע״י מכונה)</comment>
- <comment xml:lang="gl">mensaxes traducidos (lexíbeis por máquinas)</comment>
- <comment xml:lang="ga">teachtaireachtaí aistrithe (inléite ag meaisín)</comment>
- <comment xml:lang="fur">messaçs tradots (leibii de machine)</comment>
- <comment xml:lang="fr">messages traduits (lisibles par machine)</comment>
- <comment xml:lang="fo">týdd boð (maskin-lesifør)</comment>
- <comment xml:lang="fi">käännetyt viestit (koneluettava)</comment>
- <comment xml:lang="eu">itzulitako mezuak (ordenagailuek irakurtzeko)</comment>
+ <comment xml:lang="gl">Mensaxes traducidos (lexíbel pola máquina)</comment>
+ <comment xml:lang="eu">Itzulitako mezuak (makinak irakurtzeko modukoak)</comment>
<comment xml:lang="es">mensajes traducidos (legibles por máquinas)</comment>
- <comment xml:lang="eo">tradukitaj mesaĝoj (maŝinlegebla)</comment>
- <comment xml:lang="en_GB">translated messages (machine-readable)</comment>
- <comment xml:lang="el">Μεταφρασμένα μηνύματα (για μηχανική ανάγνωση)</comment>
<comment xml:lang="de">Übersetzte Meldungen (maschinenlesbar)</comment>
- <comment xml:lang="da">oversatte meddelelser (maskinlæsbare)</comment>
- <comment xml:lang="cs">přeložené zprávy (strojově čitelné)</comment>
- <comment xml:lang="ca">missatges traduïts (llegible per màquina)</comment>
- <comment xml:lang="bg">Преведени съобщения — машинен формат</comment>
- <comment xml:lang="be@latin">pierakładzienyja paviedamleńni (dla čytańnia kamputaram)</comment>
- <comment xml:lang="ar">رسائل مترجمة (مقروءة آليا)</comment>
- <comment xml:lang="af">vertaalde boodskappe (masjienleesbaar)</comment>
+ <comment xml:lang="be">перакладзеныя паведамленні (для чытання камп'ютарам)</comment>
<magic>
<match type="string" value="\336\22\4\225" offset="0"/>
<match type="string" value="\225\4\22\336" offset="0"/>
@@ -12750,17 +13096,23 @@ command to generate the output files.
<comment xml:lang="uk">документ інтерфейсу GTK+ Builder</comment>
<comment xml:lang="tr">GTK+ Builder arayüz belgesi</comment>
<comment xml:lang="sv">GTK+-Builder-gränssnittsdokument</comment>
+ <comment xml:lang="sq">dokument ndërfaqesh GTK+ Builder</comment>
+ <comment xml:lang="sl">Dokument vmesnika GTK+ Builder</comment>
+ <comment xml:lang="si">GTK+ Builder අතුරුමුහුණත් ලේඛනය</comment>
<comment xml:lang="ru">Документ интерфейса GTK+ Builder</comment>
<comment xml:lang="pt_BR">Documento de interface do GTK+ Builder</comment>
<comment xml:lang="pl">Dokument interfejsu GTK Builder</comment>
+ <comment xml:lang="nl">GTK-Builder-interfacedocument</comment>
<comment xml:lang="ko">GTK+ 빌더 인터페이스 문서</comment>
<comment xml:lang="kk">GTK+ Builder интерфейс құжаты</comment>
<comment xml:lang="ja">GTK+ Builder インターフェイスドキュメント</comment>
<comment xml:lang="it">Documento interfaccia GTK+ Builder</comment>
+ <comment xml:lang="is">GTK+ Builder viðmótsskjal</comment>
<comment xml:lang="id">Dokumen antarmuka GTK+ Builder</comment>
<comment xml:lang="hu">GTK+ Builder felületleíró dokumentum</comment>
<comment xml:lang="hr">GTK+ Graditelj dokument sučelja</comment>
<comment xml:lang="he">מסמך מנשק של GTK+ Builder</comment>
+ <comment xml:lang="gl">Documento de interface do Construtor de GTK+ </comment>
<comment xml:lang="fr">document d'interface GTK+ Builder</comment>
<comment xml:lang="fi">GTK+ Builder -käyttöliittymän asiakirja</comment>
<comment xml:lang="eu">GTK+ Builder interfaze dokumentua</comment>
@@ -12770,6 +13122,7 @@ command to generate the output files.
<comment xml:lang="da">GTK+ Builder-brugerflade-dokument</comment>
<comment xml:lang="ca">document d'interfície GTK+ Builder</comment>
<comment xml:lang="bg">Интерфейс — GTK+ Builder</comment>
+ <comment xml:lang="be">дакумент інтэрфейсу GTK+ Builder</comment>
<comment xml:lang="ar">مستند واجهة باني جي تي كي بلس</comment>
<sub-class-of type="application/xml"/>
<generic-icon name="x-office-document"/>
@@ -12787,8 +13140,9 @@ command to generate the output files.
<comment xml:lang="tr">Glade projesi</comment>
<comment xml:lang="sv">Glade-projekt</comment>
<comment xml:lang="sr">Глејдов пројекат</comment>
- <comment xml:lang="sq">Projekt Glade</comment>
+ <comment xml:lang="sq">projekt Glade</comment>
<comment xml:lang="sl">Datoteka projekta Glade</comment>
+ <comment xml:lang="si">ග්ලේඩ් ව්යාපෘතිය</comment>
<comment xml:lang="sk">Projekt Glade</comment>
<comment xml:lang="ru">Проект Glade</comment>
<comment xml:lang="ro">Proiect Glade</comment>
@@ -12806,6 +13160,7 @@ command to generate the output files.
<comment xml:lang="kk">Glade жобасы</comment>
<comment xml:lang="ja">Glade プロジェクト</comment>
<comment xml:lang="it">Progetto Glade</comment>
+ <comment xml:lang="is">Glade verkefni</comment>
<comment xml:lang="id">Proyek Glade</comment>
<comment xml:lang="ia">Projecto Glade</comment>
<comment xml:lang="hu">Glade-projekt</comment>
@@ -12829,6 +13184,7 @@ command to generate the output files.
<comment xml:lang="ca">projecte de Glade</comment>
<comment xml:lang="bg">Проект — Glade</comment>
<comment xml:lang="be@latin">Prajekt Glade</comment>
+ <comment xml:lang="be">праект Glade</comment>
<comment xml:lang="az">Glade layihəsi</comment>
<comment xml:lang="ar">مشروع Glade</comment>
<comment xml:lang="af">Glade-projek</comment>
@@ -12848,7 +13204,9 @@ command to generate the output files.
<comment xml:lang="tr">GnuCash mali verisi</comment>
<comment xml:lang="sv">GnuCash-finansdata</comment>
<comment xml:lang="sr">финансијски подаци Гнуовог новца</comment>
+ <comment xml:lang="sq">të dhëna financiare GnuCash</comment>
<comment xml:lang="sl">Datoteka finančnih podatkov GnuCash</comment>
+ <comment xml:lang="si">GnuCash මූල්ය දත්ත</comment>
<comment xml:lang="sk">Finančné údaje GnuCash</comment>
<comment xml:lang="ru">Финансовые данные GnuCash</comment>
<comment xml:lang="ro">Date financiare GnuCash</comment>
@@ -12863,6 +13221,7 @@ command to generate the output files.
<comment xml:lang="kk">GnuCash қаржы ақпараты</comment>
<comment xml:lang="ja">GnuCash 会計データ</comment>
<comment xml:lang="it">Dati finanziari GnuCash</comment>
+ <comment xml:lang="is">GnuCash fjárhagsgögn</comment>
<comment xml:lang="id">Data keuangan GnuCash</comment>
<comment xml:lang="ia">Datos financiari GnuCash</comment>
<comment xml:lang="hu">GnuCash pénzügyi adatok</comment>
@@ -12883,6 +13242,7 @@ command to generate the output files.
<comment xml:lang="cs">finanční data GnuCash</comment>
<comment xml:lang="ca">dades financeres de GnuCash</comment>
<comment xml:lang="bg">Финансови данни — GnuCash</comment>
+ <comment xml:lang="be">фінансавыя даныя GnuCash</comment>
<comment xml:lang="ar">بيانات مالية GnuCash</comment>
<comment xml:lang="af">GnuCash finansiële data</comment>
<generic-icon name="x-office-spreadsheet"/>
@@ -12895,12 +13255,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">Gnumeric 試算表</comment>
<comment xml:lang="zh_CN">Gnumeric 电子表格</comment>
<comment xml:lang="vi">Bảng tính Gnumeric.</comment>
- <comment xml:lang="uk">ел. таблиця Gnumeric</comment>
+ <comment xml:lang="uk">електронна таблиця Gnumeric</comment>
<comment xml:lang="tr">Gnumeric hesap çizelgesi</comment>
<comment xml:lang="sv">Gnumeric-kalkylblad</comment>
<comment xml:lang="sr">табела Гномовог бројевника</comment>
- <comment xml:lang="sq">Fletë llogaritjesh Gnumeric</comment>
+ <comment xml:lang="sq">fletëllogaritjesh Gnumeric</comment>
<comment xml:lang="sl">Razpredelnica Gnumeric</comment>
+ <comment xml:lang="si">Gnumeric පැතුරුම්පත</comment>
<comment xml:lang="sk">Zošit Gnumeric</comment>
<comment xml:lang="ru">Электронная таблица Gnumeric</comment>
<comment xml:lang="ro">Foaie de calcul Gnumeric</comment>
@@ -12918,6 +13279,7 @@ command to generate the output files.
<comment xml:lang="kk">Gnumeric электрондық кестесі</comment>
<comment xml:lang="ja">Gnumeric スプレッドシート</comment>
<comment xml:lang="it">Foglio di calcolo Gnumeric</comment>
+ <comment xml:lang="is">Gnumeric töflureikniskjal</comment>
<comment xml:lang="id">Lembar sebar Gnumeric</comment>
<comment xml:lang="ia">Folio de calculo Gnumeric</comment>
<comment xml:lang="hu">Gnumeric-munkafüzet</comment>
@@ -12940,6 +13302,7 @@ command to generate the output files.
<comment xml:lang="ca">full de càlcul de Gnumeric</comment>
<comment xml:lang="bg">Таблица — Gnumeric</comment>
<comment xml:lang="be@latin">Raźlikovy arkuš Gnumeric</comment>
+ <comment xml:lang="be">электронная табліца Gnumeric</comment>
<comment xml:lang="ar">جدول Gnumeric</comment>
<comment xml:lang="af">Gnumeric-sigblad</comment>
<generic-icon name="x-office-spreadsheet"/>
@@ -12958,8 +13321,9 @@ command to generate the output files.
<comment xml:lang="tr">Gnuplot belgesi</comment>
<comment xml:lang="sv">Gnuplot-dokument</comment>
<comment xml:lang="sr">документ Гнуплота</comment>
- <comment xml:lang="sq">Dokument Gnuplot</comment>
+ <comment xml:lang="sq">dokument Gnuplot</comment>
<comment xml:lang="sl">Dokument Gnuplot</comment>
+ <comment xml:lang="si">Gnuplot ලේඛනය</comment>
<comment xml:lang="sk">Dokument Gnuplot</comment>
<comment xml:lang="ru">Документ Gnuplot</comment>
<comment xml:lang="ro">Document Gnuplot</comment>
@@ -12976,6 +13340,7 @@ command to generate the output files.
<comment xml:lang="kk">Gnuplot құжаты</comment>
<comment xml:lang="ja">Gnuplot ドキュメント</comment>
<comment xml:lang="it">Documento Gnuplot</comment>
+ <comment xml:lang="is">Gnuplot skjal</comment>
<comment xml:lang="id">Dokumen Gnuplot</comment>
<comment xml:lang="ia">Documento Gnuplot</comment>
<comment xml:lang="hu">Gnuplot dokumentum</comment>
@@ -12998,6 +13363,7 @@ command to generate the output files.
<comment xml:lang="ca">document gnuplot</comment>
<comment xml:lang="bg">Документ — Gnuplot</comment>
<comment xml:lang="be@latin">Dakument Gnuplot</comment>
+ <comment xml:lang="be">дакумент Gnuplot</comment>
<comment xml:lang="ast">Documentu de Gnuplot</comment>
<comment xml:lang="ar">مستند Gnuplot</comment>
<comment xml:lang="af">Gnuplot-dokument</comment>
@@ -13016,8 +13382,9 @@ command to generate the output files.
<comment xml:lang="tr">Graphite bilimsel grafiği</comment>
<comment xml:lang="sv">Vetenskaplig Graphite-grafer</comment>
<comment xml:lang="sr">Графитов научни графикони</comment>
- <comment xml:lang="sq">Grafik shkencor Graphite </comment>
+ <comment xml:lang="sq">grafik shkencor Graphite</comment>
<comment xml:lang="sl">Datoteka znanstvenega grafa Graphite</comment>
+ <comment xml:lang="si">ග්රැෆයිට් විද්යාත්මක ප්රස්ථාරය</comment>
<comment xml:lang="sk">Vedecký graf Graphite</comment>
<comment xml:lang="ru">Научная диаграмма Graphite</comment>
<comment xml:lang="ro">Grafic științific Graphite</comment>
@@ -13035,6 +13402,7 @@ command to generate the output files.
<comment xml:lang="kk">Graphite ғылыми кескіні</comment>
<comment xml:lang="ja">Graphite scientific グラフ</comment>
<comment xml:lang="it">Grafico scientifico Graphite</comment>
+ <comment xml:lang="is">Graphite vísindalegt graf</comment>
<comment xml:lang="id">Grafik sains Graphite</comment>
<comment xml:lang="ia">Graphico scientific Graphite</comment>
<comment xml:lang="hu">Graphite tudományos grafikon</comment>
@@ -13057,6 +13425,7 @@ command to generate the output files.
<comment xml:lang="ca">gràfic científic Graphite</comment>
<comment xml:lang="bg">Графика — Graphite</comment>
<comment xml:lang="be@latin">Navukovy hrafik Graphite</comment>
+ <comment xml:lang="be">навуковы граф Graphite</comment>
<comment xml:lang="ar">مبيان جرافيت علمي</comment>
<generic-icon name="x-office-document"/>
<glob pattern="*.gra"/>
@@ -13070,8 +13439,9 @@ command to generate the output files.
<comment xml:lang="tr">GTKtalog kataloğu</comment>
<comment xml:lang="sv">GTKtalog-katalog</comment>
<comment xml:lang="sr">каталог ГТКталога</comment>
- <comment xml:lang="sq">Katallog GTKtalog</comment>
+ <comment xml:lang="sq">katalog GTKtalog</comment>
<comment xml:lang="sl">Datoteka kataloga GTKtalog</comment>
+ <comment xml:lang="si">GTKtalog නාමාවලිය</comment>
<comment xml:lang="sk">Katalóg GTKtalog</comment>
<comment xml:lang="ru">Каталог GTKtalog</comment>
<comment xml:lang="ro">Catalog GTKalog</comment>
@@ -13090,6 +13460,7 @@ command to generate the output files.
<comment xml:lang="ka">GTKtalog-ის კატალოგი</comment>
<comment xml:lang="ja">GTKtalog カタログ</comment>
<comment xml:lang="it">Catalogo GTKtalog</comment>
+ <comment xml:lang="is">GTKtalog efnisskrá</comment>
<comment xml:lang="id">Katalog GTKtalog</comment>
<comment xml:lang="ia">Catalogo GTKtalog</comment>
<comment xml:lang="hu">GTKtalog-katalógus</comment>
@@ -13112,6 +13483,7 @@ command to generate the output files.
<comment xml:lang="ca">catàleg de GTKtalog</comment>
<comment xml:lang="bg">Каталог — Gtktalog</comment>
<comment xml:lang="be@latin">Kataloh GTKtalog</comment>
+ <comment xml:lang="be">каталог GTKtalog</comment>
<comment xml:lang="ar">كتالوج GTKtalog</comment>
<generic-icon name="x-office-document"/>
<magic>
@@ -13127,10 +13499,11 @@ command to generate the output files.
<comment xml:lang="tr">TeX DVI belgesi (gzip ile sıkıştırılmış)</comment>
<comment xml:lang="sv">TeX DVI-dokument (gzip-komprimerat)</comment>
<comment xml:lang="sr">ТеКс ДВИ документ (запакован гзип-ом)</comment>
- <comment xml:lang="sq">Dokument TeX DVI (i kompresuar me gzip)</comment>
+ <comment xml:lang="sq">dokument TeX DVI (ngjeshur me gzip)</comment>
<comment xml:lang="sl">Dokument TeX DVI (stisnjen z gzip)</comment>
+ <comment xml:lang="si">TeX DVI ලේඛනය (gzip-සම්පීඩිත)</comment>
<comment xml:lang="sk">Dokument TeX DVI (komprimovaný pomocou gzip)</comment>
- <comment xml:lang="ru">Документ TeX DVI (сжатый gzip)</comment>
+ <comment xml:lang="ru">Документ DVI издательской системы TeX (сжатый gzip)</comment>
<comment xml:lang="ro">Document TeX DVI (comprimat gzip)</comment>
<comment xml:lang="pt_BR">Documento DVI TeX (compactado com gzip)</comment>
<comment xml:lang="pt">documento TeX DVI (compressão gzip)</comment>
@@ -13145,6 +13518,7 @@ command to generate the output files.
<comment xml:lang="kk">TeX DVI құжаты (gzip-пен сығылған)</comment>
<comment xml:lang="ja">Tex DVI ドキュメント (gzip 圧縮)</comment>
<comment xml:lang="it">Documento Tex DVI (compresso con gzip)</comment>
+ <comment xml:lang="is">TeX DVI skjal (gzip-þjappað)</comment>
<comment xml:lang="id">Dokumen TeX DVI (terkompresi gzip)</comment>
<comment xml:lang="ia">Documento TeX DVI (comprimite con gzip)</comment>
<comment xml:lang="hu">TeX DVI dokumentum (gzip tömörítésű)</comment>
@@ -13157,7 +13531,7 @@ command to generate the output files.
<comment xml:lang="fo">TeX DVI skjal (gzip-stappað)</comment>
<comment xml:lang="fi">TeX DVI -asiakirja (gzip-pakattu)</comment>
<comment xml:lang="eu">TeX DVI dokumentua (gzip-ekin konprimitua)</comment>
- <comment xml:lang="es">documento DVI de TeX (comprimido con gzip)</comment>
+ <comment xml:lang="es">documento DVI de TeX (comprimido con GZIP)</comment>
<comment xml:lang="en_GB">TeX DVI document (gzip-compressed)</comment>
<comment xml:lang="el">Έγγραφο TeX DVI (συμπιεσμένο με gzip)</comment>
<comment xml:lang="de">TeX-DVI-Dokument (gzip-komprimiert)</comment>
@@ -13166,6 +13540,7 @@ command to generate the output files.
<comment xml:lang="ca">document DVI de TeX (amb compressió gzip)</comment>
<comment xml:lang="bg">Документ — TeX DVI, компресиран с gzip</comment>
<comment xml:lang="be@latin">Dakument TeX DVI (gzip-skampresavany)</comment>
+ <comment xml:lang="be">дакумент TeX DVI (сцісканне gzip)</comment>
<comment xml:lang="ast">Documentu Tex DVI (comprimíu en gzip)</comment>
<comment xml:lang="ar">مستند TeX DVI (مضغوط-gzip)</comment>
<comment xml:lang="af">TeX DVI-dokument (gzip-saamgepers)</comment>
@@ -13182,8 +13557,9 @@ command to generate the output files.
<comment xml:lang="tr">Gzip arşivi</comment>
<comment xml:lang="sv">Gzip-arkiv</comment>
<comment xml:lang="sr">Гзип архива</comment>
- <comment xml:lang="sq">Arkiv gzip</comment>
+ <comment xml:lang="sq">arkiv gzip</comment>
<comment xml:lang="sl">Datoteka arhiva Gzip</comment>
+ <comment xml:lang="si">Gzip සංරක්ෂිතය</comment>
<comment xml:lang="sk">Archív Gzip</comment>
<comment xml:lang="ru">Архив GZIP</comment>
<comment xml:lang="ro">Arhivă Gzip</comment>
@@ -13200,6 +13576,7 @@ command to generate the output files.
<comment xml:lang="kk">Gzip архиві</comment>
<comment xml:lang="ja">Gzip アーカイブ</comment>
<comment xml:lang="it">Archivio gzip</comment>
+ <comment xml:lang="is">gzip safnskrá</comment>
<comment xml:lang="id">Arsip Gzip</comment>
<comment xml:lang="ia">Archivo Gzip</comment>
<comment xml:lang="hu">Gzip archívum</comment>
@@ -13212,7 +13589,7 @@ command to generate the output files.
<comment xml:lang="fo">Gzip skjalasavn</comment>
<comment xml:lang="fi">Gzip-arkisto</comment>
<comment xml:lang="eu">Gzip artxiboa</comment>
- <comment xml:lang="es">archivador Gzip</comment>
+ <comment xml:lang="es">archivador GZIP</comment>
<comment xml:lang="eo">Gzip-arkivo</comment>
<comment xml:lang="en_GB">Gzip archive</comment>
<comment xml:lang="el">Συμπιεσμένο αρχείο Gzip</comment>
@@ -13222,6 +13599,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu gzip</comment>
<comment xml:lang="bg">Архив — gzip</comment>
<comment xml:lang="be@latin">Archiŭ gzip</comment>
+ <comment xml:lang="be">архіў gzip</comment>
<comment xml:lang="ar">أرشيف Gzip</comment>
<comment xml:lang="af">Gzip-argief</comment>
<generic-icon name="package-x-generic"/>
@@ -13240,8 +13618,9 @@ command to generate the output files.
<comment xml:lang="tr">PDF belgesi (gzip ile sıkıştırılmış)</comment>
<comment xml:lang="sv">PDF-dokument (gzip-komprimerat)</comment>
<comment xml:lang="sr">ПДФ документ (запакован гзип-ом)</comment>
- <comment xml:lang="sq">Dokument PDF (i kompresuar me gzip)</comment>
+ <comment xml:lang="sq">dokument PDF (ngjeshur me gzip)</comment>
<comment xml:lang="sl">Dokument PDF (stisnjen z gzip)</comment>
+ <comment xml:lang="si">PDF ලේඛනය (gzip-compressed)</comment>
<comment xml:lang="sk">Dokument PDF (komprimovaný pomocou gzip)</comment>
<comment xml:lang="ru">Документ PDF (сжатый gzip)</comment>
<comment xml:lang="ro">Document PDF (comprimat gzip)</comment>
@@ -13258,6 +13637,7 @@ command to generate the output files.
<comment xml:lang="kk">PDF құжаты (gzip-пен сығылған)</comment>
<comment xml:lang="ja">PDF ドキュメント (gzip 圧縮)</comment>
<comment xml:lang="it">Documento PDF (compresso con gzip)</comment>
+ <comment xml:lang="is">PDF skjal (gzip-þjappað)</comment>
<comment xml:lang="id">Dokumen PDF (terkompresi gzip)</comment>
<comment xml:lang="ia">Documento PDF (comprimite con gzip)</comment>
<comment xml:lang="hu">PDF dokumentum (gzip tömörítésű)</comment>
@@ -13270,7 +13650,7 @@ command to generate the output files.
<comment xml:lang="fo">PDF skjal (gzip-stappað)</comment>
<comment xml:lang="fi">PDF-asiakirja (gzip-pakattu)</comment>
<comment xml:lang="eu">PDF dokumentua (gzip-ekin konprimitua)</comment>
- <comment xml:lang="es">documento PDF (comprimido con gzip)</comment>
+ <comment xml:lang="es">documento PDF (comprimido con GZIP)</comment>
<comment xml:lang="en_GB">PDF document (gzip-compressed)</comment>
<comment xml:lang="el">Έγγραφο PDF (συμπιεσμένο με gzip)</comment>
<comment xml:lang="de">PDF-Dokument (gzip-komprimiert)</comment>
@@ -13279,6 +13659,7 @@ command to generate the output files.
<comment xml:lang="ca">document PDF (amb compressió gzip)</comment>
<comment xml:lang="bg">Документ — PDF, компресиран с gzip</comment>
<comment xml:lang="be@latin">Dakument PDF (gzip-skampresavany)</comment>
+ <comment xml:lang="be">дакумент PDF (сцісканне gzip)</comment>
<comment xml:lang="ast">Documentu PDF (comprimíu en gzip)</comment>
<comment xml:lang="ar">مستند PDF (مضغوط-gzip)</comment>
<comment xml:lang="af">PDF-dokument (gzip-saamgepers)</comment>
@@ -13295,8 +13676,9 @@ command to generate the output files.
<comment xml:lang="tr">PostScript belgesi (gzip ile sıkıştırılmış)</comment>
<comment xml:lang="sv">Postscript-dokument (gzip-komprimerat)</comment>
<comment xml:lang="sr">Постскрипт документ (запакован гзип-ом)</comment>
- <comment xml:lang="sq">Dokument PostScript (i kompresuar me gzip)</comment>
+ <comment xml:lang="sq">dokument PostScript (ngjeshur me gzip)</comment>
<comment xml:lang="sl">Dokument PostScript (stisnjen z gzip)</comment>
+ <comment xml:lang="si">PostScript ලේඛනය (gzip-compressed)</comment>
<comment xml:lang="sk">Dokument PostScript (komprimovaný pomocou gzip)</comment>
<comment xml:lang="ru">Документ PostScript (сжатый gzip)</comment>
<comment xml:lang="ro">Document PostScript (comprimat gzip)</comment>
@@ -13314,6 +13696,7 @@ command to generate the output files.
<comment xml:lang="kk">PostScript құжаты (gzip-пен сығылған)</comment>
<comment xml:lang="ja">PostScript ドキュメント (gzip 圧縮)</comment>
<comment xml:lang="it">Documento PostScript (compresso con gzip)</comment>
+ <comment xml:lang="is">PostScript skjal (gzip-þjappað)</comment>
<comment xml:lang="id">Dokumen PostScript (terkompresi gzip)</comment>
<comment xml:lang="ia">Documento PostScript (comprimite con gzip)</comment>
<comment xml:lang="hu">PostScript-dokumentum (gzip tömörítésű)</comment>
@@ -13326,7 +13709,7 @@ command to generate the output files.
<comment xml:lang="fo">PostScript skjal (gzip-stappað)</comment>
<comment xml:lang="fi">PostScript-asiakirja (gzip-pakattu)</comment>
<comment xml:lang="eu">PostScript dokumentua (gzip-konprimitua)</comment>
- <comment xml:lang="es">documento PostScript (comprimido con gzip)</comment>
+ <comment xml:lang="es">documento PostScript (comprimido con GZIP)</comment>
<comment xml:lang="eo">PostScript-dokumento (kunpremita per gzip)</comment>
<comment xml:lang="en_GB">PostScript document (gzip-compressed)</comment>
<comment xml:lang="el">Έγγραφο PostScript (συμπιεσμένο με gzip)</comment>
@@ -13336,6 +13719,7 @@ command to generate the output files.
<comment xml:lang="ca">document PostScript (amb compressió gzip)</comment>
<comment xml:lang="bg">Документ — PostScript, компресиран с gzip</comment>
<comment xml:lang="be@latin">Dakument PostScript (gzip-skampresavany)</comment>
+ <comment xml:lang="be">дакумент PostScript (сцісканне gzip)</comment>
<comment xml:lang="ast">Documentu PostScript (comprimíu en gzip)</comment>
<comment xml:lang="ar">مستند PostScript (مضغوط-gzip)</comment>
<comment xml:lang="af">PostScript-dokument (gzip-saamgepers)</comment>
@@ -13352,8 +13736,9 @@ command to generate the output files.
<comment xml:lang="tr">HDF belgesi</comment>
<comment xml:lang="sv">HDF-dokument</comment>
<comment xml:lang="sr">ХДФ документ</comment>
- <comment xml:lang="sq">Dokument HDF</comment>
+ <comment xml:lang="sq">dokument HDF</comment>
<comment xml:lang="sl">Dokument HDF</comment>
+ <comment xml:lang="si">HDF ලේඛනය</comment>
<comment xml:lang="sk">Dokument HDF</comment>
<comment xml:lang="ru">Документ HDF</comment>
<comment xml:lang="ro">Document HDF</comment>
@@ -13371,6 +13756,7 @@ command to generate the output files.
<comment xml:lang="kk">HDF құжаты</comment>
<comment xml:lang="ja">HDF ドキュメント</comment>
<comment xml:lang="it">Documento HDF</comment>
+ <comment xml:lang="is">HDF skjal</comment>
<comment xml:lang="id">Dokumen HDF</comment>
<comment xml:lang="ia">Documento HDF</comment>
<comment xml:lang="hu">HDF-dokumentum</comment>
@@ -13394,6 +13780,7 @@ command to generate the output files.
<comment xml:lang="ca">document HDF</comment>
<comment xml:lang="bg">Документ — HDF</comment>
<comment xml:lang="be@latin">Dakument HDF</comment>
+ <comment xml:lang="be">дакумент HDF</comment>
<comment xml:lang="az">HDF sənədi</comment>
<comment xml:lang="ast">Documentu HDF</comment>
<comment xml:lang="ar">مستند HDF</comment>
@@ -13419,18 +13806,22 @@ command to generate the output files.
<comment xml:lang="tr">IFF dosyası</comment>
<comment xml:lang="sv">IFF-fil</comment>
<comment xml:lang="sr">ИФФ датотека</comment>
+ <comment xml:lang="sq">kartelë IFF</comment>
<comment xml:lang="sl">Datoteka IFF</comment>
+ <comment xml:lang="si">IFF ගොනුව</comment>
<comment xml:lang="sk">Súbor IFF</comment>
<comment xml:lang="ru">Файл IFF</comment>
<comment xml:lang="pt_BR">Arquivo IFF</comment>
<comment xml:lang="pt">ficheiro IFF</comment>
<comment xml:lang="pl">Plik IFF</comment>
<comment xml:lang="oc">fichièr IFF</comment>
+ <comment xml:lang="nl">IFF-bestand</comment>
<comment xml:lang="lv">IFF datne</comment>
<comment xml:lang="ko">IFF 파일</comment>
<comment xml:lang="kk">IFF файлы</comment>
<comment xml:lang="ja">IFF ファイル</comment>
<comment xml:lang="it">File IFF</comment>
+ <comment xml:lang="is">IFF skrá</comment>
<comment xml:lang="id">Berkas IFF</comment>
<comment xml:lang="ia">File IFF</comment>
<comment xml:lang="hu">IFF fájl</comment>
@@ -13450,6 +13841,7 @@ command to generate the output files.
<comment xml:lang="cs">soubor IFF</comment>
<comment xml:lang="ca">fitxer IFF</comment>
<comment xml:lang="bg">Пакет — IFF</comment>
+ <comment xml:lang="be">файл IFF</comment>
<comment xml:lang="ar">ملف IFF</comment>
<comment xml:lang="af">IFF-lêer</comment>
<acronym>IFF</acronym>
@@ -13467,8 +13859,9 @@ command to generate the output files.
<comment xml:lang="tr">iPod donanım yazılımı</comment>
<comment xml:lang="sv">fast iPod-program</comment>
<comment xml:lang="sr">ајПод-ов уграђени</comment>
- <comment xml:lang="sq">Firmware iPod</comment>
+ <comment xml:lang="sq">firmware iPod</comment>
<comment xml:lang="sl">Programska strojna oprema iPod</comment>
+ <comment xml:lang="si">iPod ස්ථිරාංග</comment>
<comment xml:lang="sk">Firmware iPod</comment>
<comment xml:lang="ru">Микропрограмма iPod</comment>
<comment xml:lang="ro">Firmware iPod</comment>
@@ -13486,6 +13879,7 @@ command to generate the output files.
<comment xml:lang="kk">iPod микробағдарламасы</comment>
<comment xml:lang="ja">iPod ファームウェア</comment>
<comment xml:lang="it">Firmware iPod</comment>
+ <comment xml:lang="is">iPod grunnhugbúnaður</comment>
<comment xml:lang="id">peranti tegar iPod</comment>
<comment xml:lang="ia">Firmware iPod</comment>
<comment xml:lang="hu">iPod-firmware</comment>
@@ -13508,12 +13902,13 @@ command to generate the output files.
<comment xml:lang="ca">microprogramari d'iPod</comment>
<comment xml:lang="bg">Фърмуер — iPod</comment>
<comment xml:lang="be@latin">Firmware iPod</comment>
+ <comment xml:lang="be">убудаванае ПЗ iPod</comment>
<comment xml:lang="ar">برنامج عتاد الـiPod</comment>
<magic>
<match type="string" value="S T O P" offset="0"/>
</magic>
</mime-type>
- <mime-type type="application/x-java-archive">
+ <mime-type type="application/java-archive">
<comment>Java archive</comment>
<comment xml:lang="zh_TW">Java 封存檔</comment>
<comment xml:lang="zh_CN">Java 归档文件</comment>
@@ -13522,8 +13917,9 @@ command to generate the output files.
<comment xml:lang="tr">Java arşivi</comment>
<comment xml:lang="sv">Java-arkiv</comment>
<comment xml:lang="sr">архива Јаве</comment>
- <comment xml:lang="sq">Arkiv Java</comment>
+ <comment xml:lang="sq">arkiv Java</comment>
<comment xml:lang="sl">Datoteka arhiva Java</comment>
+ <comment xml:lang="si">ජාවා ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív Java</comment>
<comment xml:lang="ru">Архив Java</comment>
<comment xml:lang="ro">Arhivă Java</comment>
@@ -13541,6 +13937,7 @@ command to generate the output files.
<comment xml:lang="kk">Java архиві</comment>
<comment xml:lang="ja">Java アーカイブ</comment>
<comment xml:lang="it">Archivio Java</comment>
+ <comment xml:lang="is">Java safnskrá</comment>
<comment xml:lang="id">Arsip Java</comment>
<comment xml:lang="ia">Archivo Java</comment>
<comment xml:lang="hu">Java-archívum</comment>
@@ -13553,7 +13950,7 @@ command to generate the output files.
<comment xml:lang="fo">Java skjalasavn</comment>
<comment xml:lang="fi">Java-arkisto</comment>
<comment xml:lang="eu">Java artxiboa</comment>
- <comment xml:lang="es">archivador Java</comment>
+ <comment xml:lang="es">archivador de Java</comment>
<comment xml:lang="eo">Java-arkivo</comment>
<comment xml:lang="en_GB">Java archive</comment>
<comment xml:lang="el">Συμπιεσμένο αρχείο Java</comment>
@@ -13563,12 +13960,13 @@ command to generate the output files.
<comment xml:lang="ca">arxiu de Java</comment>
<comment xml:lang="bg">Архив — Java</comment>
<comment xml:lang="be@latin">Archiŭ Java</comment>
+ <comment xml:lang="be">архіў Java</comment>
<comment xml:lang="ar">أرشيف Java</comment>
<comment xml:lang="af">Java-argief</comment>
<sub-class-of type="application/zip"/>
<generic-icon name="package-x-generic"/>
<alias type="application/x-jar"/>
- <alias type="application/java-archive"/>
+ <alias type="application/x-java-archive"/>
<glob pattern="*.jar"/>
</mime-type>
<mime-type type="application/x-java">
@@ -13580,8 +13978,9 @@ command to generate the output files.
<comment xml:lang="tr">Java sınıfı</comment>
<comment xml:lang="sv">Java-klass</comment>
<comment xml:lang="sr">разред Јаве</comment>
- <comment xml:lang="sq">Klasë Java</comment>
+ <comment xml:lang="sq">klasë Java</comment>
<comment xml:lang="sl">Datoteka razreda Java</comment>
+ <comment xml:lang="si">ජාවා පන්තිය</comment>
<comment xml:lang="sk">Trieda Java</comment>
<comment xml:lang="ru">Класс Java</comment>
<comment xml:lang="ro">Clasă Java</comment>
@@ -13599,6 +13998,7 @@ command to generate the output files.
<comment xml:lang="kk">Java класы</comment>
<comment xml:lang="ja">Java クラス</comment>
<comment xml:lang="it">Classe Java</comment>
+ <comment xml:lang="is">Java klassi</comment>
<comment xml:lang="id">Kelas Java</comment>
<comment xml:lang="ia">Classe Java</comment>
<comment xml:lang="hu">Java-osztály</comment>
@@ -13621,6 +14021,7 @@ command to generate the output files.
<comment xml:lang="ca">classe de Java</comment>
<comment xml:lang="bg">Клас — Java</comment>
<comment xml:lang="be@latin">Klasa Java</comment>
+ <comment xml:lang="be">клас Java</comment>
<comment xml:lang="ar">صنف java</comment>
<comment xml:lang="af">Java-klas</comment>
<magic>
@@ -13637,21 +14038,27 @@ command to generate the output files.
<comment>Groovy source code</comment>
<comment xml:lang="zh_TW">Groovy 原始碼</comment>
<comment xml:lang="zh_CN">Groovy 源代码</comment>
- <comment xml:lang="uk">вихідний код мовою Groovy</comment>
+ <comment xml:lang="uk">початковий код мовою Groovy</comment>
<comment xml:lang="tr">Groovy kaynak kodu</comment>
<comment xml:lang="sv">Groovy-källkod</comment>
+ <comment xml:lang="sq">kod burim Groovy</comment>
+ <comment xml:lang="sl">Izvorna koda Groovy</comment>
+ <comment xml:lang="si">Groovy මූල කේතය</comment>
<comment xml:lang="ru">Исходный код Groovy</comment>
<comment xml:lang="pt_BR">Código-fonte Groovy</comment>
<comment xml:lang="pl">Kod źródłowy Groovy</comment>
<comment xml:lang="oc">còdi font Groovy</comment>
+ <comment xml:lang="nl">Groovy-broncode</comment>
<comment xml:lang="ko">그루비 소스 코드</comment>
<comment xml:lang="kk">Groovy бастапқы коды</comment>
<comment xml:lang="ja">Groovy ソースコード</comment>
<comment xml:lang="it">Codice sorgente Groovy</comment>
+ <comment xml:lang="is">Groovy frumkóði</comment>
<comment xml:lang="id">Kode sumber Groovy</comment>
<comment xml:lang="hu">Groovy forráskód</comment>
<comment xml:lang="hr">Groovy izvorni kôd</comment>
<comment xml:lang="he">קוד מקור ב־Groovy</comment>
+ <comment xml:lang="gl">Código fonte en Groovy</comment>
<comment xml:lang="fr">code source Groovy</comment>
<comment xml:lang="fi">Groovy-lähdekoodi</comment>
<comment xml:lang="eu">Groovy iturburu-kodea</comment>
@@ -13661,6 +14068,7 @@ command to generate the output files.
<comment xml:lang="da">Groovy-kildekode</comment>
<comment xml:lang="ca">codi font en Groovy</comment>
<comment xml:lang="bg">Изходен код — Groovy</comment>
+ <comment xml:lang="be">зыходны код Groovy</comment>
<comment xml:lang="ar">شفرة مصدر Groovy</comment>
<sub-class-of type="text/x-csrc"/>
<generic-icon name="text-x-script"/>
@@ -13671,6 +14079,30 @@ command to generate the output files.
</mime-type>
<mime-type type="text/x-gradle">
<comment>Gradle script</comment>
+ <comment xml:lang="zh_TW">Gradle 指令稿</comment>
+ <comment xml:lang="zh_CN">Gradle 脚本</comment>
+ <comment xml:lang="uk">скрипт Gradle</comment>
+ <comment xml:lang="tr">Gradle betiği</comment>
+ <comment xml:lang="sv">Gradle-skript</comment>
+ <comment xml:lang="sl">Skript Gradle</comment>
+ <comment xml:lang="si">Gradle පිටපත</comment>
+ <comment xml:lang="ru">Сценарий Gradle</comment>
+ <comment xml:lang="pt_BR">Script Gradle</comment>
+ <comment xml:lang="pl">Skrypt Gradle</comment>
+ <comment xml:lang="nl">Gradle-script</comment>
+ <comment xml:lang="ko">Gradle 스크립트</comment>
+ <comment xml:lang="kk">Gradle сценарийі</comment>
+ <comment xml:lang="ja">Gradle スクリプト</comment>
+ <comment xml:lang="it">Script Gradle</comment>
+ <comment xml:lang="hr">Gradle skripta</comment>
+ <comment xml:lang="gl">Script de Gradle</comment>
+ <comment xml:lang="fi">Gradle-skripti</comment>
+ <comment xml:lang="eu">Gradle script-a</comment>
+ <comment xml:lang="es">secuencia de órdenes de Gradle</comment>
+ <comment xml:lang="en_GB">Gradle script</comment>
+ <comment xml:lang="de">Gradle-Skript</comment>
+ <comment xml:lang="be">скрыпт Gradle</comment>
+ <comment xml:lang="ar">سكربت Gradle</comment>
<sub-class-of type="text/x-groovy"/>
<glob pattern="*.gradle"/>
</mime-type>
@@ -13683,8 +14115,9 @@ command to generate the output files.
<comment xml:lang="tr">JNLP dosyası</comment>
<comment xml:lang="sv">JNLP-fil</comment>
<comment xml:lang="sr">ЈНЛП датотека</comment>
- <comment xml:lang="sq">File JNLP</comment>
+ <comment xml:lang="sq">kartelë JNLP</comment>
<comment xml:lang="sl">Datoteka JNLP</comment>
+ <comment xml:lang="si">JNLP ගොනුව</comment>
<comment xml:lang="sk">Súbor JNLP</comment>
<comment xml:lang="ru">Файл JNLP</comment>
<comment xml:lang="ro">Fișier JNLP</comment>
@@ -13701,6 +14134,7 @@ command to generate the output files.
<comment xml:lang="kk">JNLP файлы</comment>
<comment xml:lang="ja">JNLP ファイル</comment>
<comment xml:lang="it">File JNPL</comment>
+ <comment xml:lang="is">JNLP skrá</comment>
<comment xml:lang="id">Berkas JNLP</comment>
<comment xml:lang="ia">File JNLP</comment>
<comment xml:lang="hu">JNLP fájl</comment>
@@ -13723,6 +14157,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer JNLP</comment>
<comment xml:lang="bg">Стартер — JNLP</comment>
<comment xml:lang="be@latin">Fajł JNLP</comment>
+ <comment xml:lang="be">файл JNLP</comment>
<comment xml:lang="ar">ملف JNLP</comment>
<comment xml:lang="af">JNLP-lêer</comment>
<acronym>JNLP</acronym>
@@ -13743,6 +14178,7 @@ command to generate the output files.
<comment xml:lang="sv">Java-nyckellager</comment>
<comment xml:lang="sr">смештај кључа Јаве</comment>
<comment xml:lang="sl">Datoteka tipkovne razporeditve Java</comment>
+ <comment xml:lang="si">ජාවා යතුරු ගබඩාව</comment>
<comment xml:lang="sk">Úložisko kľúčov Java</comment>
<comment xml:lang="ru">Хранилище ключей Java</comment>
<comment xml:lang="ro">Stocare chei Java</comment>
@@ -13750,13 +14186,14 @@ command to generate the output files.
<comment xml:lang="pt">armazém de chaves Java</comment>
<comment xml:lang="pl">Baza kluczy Java</comment>
<comment xml:lang="oc">emmagazinatge de claus Java</comment>
- <comment xml:lang="nl">Java keystore</comment>
+ <comment xml:lang="nl">Java-keystore</comment>
<comment xml:lang="lv">Java keystore</comment>
<comment xml:lang="lt">Java raktų saugykla</comment>
<comment xml:lang="ko">Java 키 저장소</comment>
<comment xml:lang="kk">Java сақталымы</comment>
<comment xml:lang="ja">Java キーストア</comment>
<comment xml:lang="it">Keystore Java</comment>
+ <comment xml:lang="is">Java lyklageymsla</comment>
<comment xml:lang="id">Penyimpanan kunci Java</comment>
<comment xml:lang="ia">Magazin de claves Java</comment>
<comment xml:lang="hu">Java kulcstároló</comment>
@@ -13777,6 +14214,7 @@ command to generate the output files.
<comment xml:lang="cs">úložiště klíčů Java</comment>
<comment xml:lang="ca">magatzem de claus de Java</comment>
<comment xml:lang="bg">Ключодържател — Java</comment>
+ <comment xml:lang="be">сховішча ключоў Java</comment>
<comment xml:lang="ar">مخزن مفاتيح جافا</comment>
<magic>
<match type="big32" value="0xfeedfeed" offset="0"/>
@@ -13794,6 +14232,7 @@ command to generate the output files.
<comment xml:lang="sv">Java JCE-nyckellager</comment>
<comment xml:lang="sr">смештај ЈЦЕ кључа Јаве</comment>
<comment xml:lang="sl">Datoteka tipkovne razporeditve Java JCE</comment>
+ <comment xml:lang="si">ජාවා JCE යතුරු ගබඩාව</comment>
<comment xml:lang="sk">Úložisko kľúčov Java JCE</comment>
<comment xml:lang="ru">Хранилище ключей Java JCE</comment>
<comment xml:lang="ro">Stocare chei Java JCE</comment>
@@ -13801,13 +14240,14 @@ command to generate the output files.
<comment xml:lang="pt">armazém de chaves JavaJCE</comment>
<comment xml:lang="pl">Baza kluczy Java JCE</comment>
<comment xml:lang="oc">emmagazinatge de claus Java JCE</comment>
- <comment xml:lang="nl">Java JCE keystore</comment>
+ <comment xml:lang="nl">Java JCE-keystore</comment>
<comment xml:lang="lv">Java JCE keystore</comment>
<comment xml:lang="lt">Java JCE raktų saugykla</comment>
<comment xml:lang="ko">Java JCE 키 저장소</comment>
<comment xml:lang="kk">Java JCE сақталымы</comment>
<comment xml:lang="ja">Java JCE キーストア</comment>
<comment xml:lang="it">Keystore Java JCE</comment>
+ <comment xml:lang="is">Java JCE lyklageymsla</comment>
<comment xml:lang="id">Penyimpanan kunci Java JCE</comment>
<comment xml:lang="ia">Magazin de claves Java JCE</comment>
<comment xml:lang="hu">Java JCE kulcstároló</comment>
@@ -13828,6 +14268,7 @@ command to generate the output files.
<comment xml:lang="cs">úložiště klíčů Java JCE</comment>
<comment xml:lang="ca">magatzem de claus JCE de Java</comment>
<comment xml:lang="bg">Ключодържател — Java JCE</comment>
+ <comment xml:lang="be">сховішча ключоў Java JCE</comment>
<comment xml:lang="ar">مخزن مفاتيح Java JCE</comment>
<acronym>JCE</acronym>
<expanded-acronym>Java Cryptography Extension</expanded-acronym>
@@ -13845,8 +14286,9 @@ command to generate the output files.
<comment xml:lang="tr">Pack200 Java arşivi</comment>
<comment xml:lang="sv">Pack200 Java-arkiv</comment>
<comment xml:lang="sr">архива Јаве Пак200</comment>
- <comment xml:lang="sq">Arkiv Java Pack200</comment>
+ <comment xml:lang="sq">arkiv Java Pack200</comment>
<comment xml:lang="sl">Datoteka arhiva Pack200 Java</comment>
+ <comment xml:lang="si">Pack200 Java සංරක්ෂිතය</comment>
<comment xml:lang="sk">Archív Java Pack200</comment>
<comment xml:lang="ru">Архив Java Pack200</comment>
<comment xml:lang="ro">Arhivă Java Pack2000</comment>
@@ -13863,6 +14305,7 @@ command to generate the output files.
<comment xml:lang="kk">Pack200 Java архиві</comment>
<comment xml:lang="ja">Pack200 Java アーカイブ</comment>
<comment xml:lang="it">Archivio Pack200 Java</comment>
+ <comment xml:lang="is">Pack200 Java safnskrá</comment>
<comment xml:lang="id">Arsip Pack200 Java</comment>
<comment xml:lang="ia">Archivo Java Pack200</comment>
<comment xml:lang="hu">Pack200 Java-archívum</comment>
@@ -13884,6 +14327,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu de Java en Pack200</comment>
<comment xml:lang="bg">Архив — Java Pack200</comment>
<comment xml:lang="be@latin">Archiŭ Pack200 Java</comment>
+ <comment xml:lang="be">архіў Pack200 Java</comment>
<comment xml:lang="ar">أرشيف Pack200 Java</comment>
<generic-icon name="package-x-generic"/>
<magic priority="60">
@@ -13891,7 +14335,7 @@ command to generate the output files.
</magic>
<glob pattern="*.pack"/>
</mime-type>
- <mime-type type="application/javascript">
+ <mime-type type="text/javascript">
<comment>JavaScript program</comment>
<comment xml:lang="zh_TW">JavaScript 程式</comment>
<comment xml:lang="zh_CN">JavaScript 程序</comment>
@@ -13900,8 +14344,9 @@ command to generate the output files.
<comment xml:lang="tr">JavaScript programı</comment>
<comment xml:lang="sv">JavaScript-program</comment>
<comment xml:lang="sr">програм Јава скрипте</comment>
- <comment xml:lang="sq">Program JavaScript</comment>
+ <comment xml:lang="sq">program JavaScript</comment>
<comment xml:lang="sl">Programska datoteka JavaScript</comment>
+ <comment xml:lang="si">JavaScript වැඩසටහන</comment>
<comment xml:lang="sk">Program jazyka JavaScript</comment>
<comment xml:lang="ru">Программа JavaScript</comment>
<comment xml:lang="ro">Program JavaScript</comment>
@@ -13919,6 +14364,7 @@ command to generate the output files.
<comment xml:lang="kk">JavaScript бағдарламасы</comment>
<comment xml:lang="ja">JavaScript プログラム</comment>
<comment xml:lang="it">Programma JavaScript</comment>
+ <comment xml:lang="is">JavaScript forrit</comment>
<comment xml:lang="id">Program JavaScript</comment>
<comment xml:lang="ia">Programma JavaScript</comment>
<comment xml:lang="hu">JavaScript-program</comment>
@@ -13941,11 +14387,14 @@ command to generate the output files.
<comment xml:lang="ca">programa JavaScript</comment>
<comment xml:lang="bg">Програма на JavaScript</comment>
<comment xml:lang="be@latin">Prahrama JavaScript</comment>
+ <comment xml:lang="be">праграма JavaScript</comment>
<comment xml:lang="ar">برنامج جافاسكربت</comment>
<comment xml:lang="af">JavaScript-program</comment>
<alias type="application/x-javascript"/>
- <alias type="text/javascript"/>
- <sub-class-of type="application/ecmascript"/>
+ <alias type="application/javascript"/>
+ <alias type="text/jscript"/>
+ <sub-class-of type="application/x-executable"/>
+ <sub-class-of type="text/plain"/>
<generic-icon name="text-x-script"/>
<magic>
<match type="string" value="#!/bin/gjs" offset="0"/>
@@ -13963,6 +14412,21 @@ command to generate the output files.
<glob pattern="*.jsm"/>
<glob pattern="*.mjs"/>
</mime-type>
+ <mime-type type="text/jscript.encode">
+ <comment>Encoded JScript program</comment>
+ <comment xml:lang="uk">кодована програма JScript</comment>
+ <comment xml:lang="sv">Kodat JScript-program</comment>
+ <comment xml:lang="ru">Зашифрованная программа на JScript</comment>
+ <comment xml:lang="pl">Zakodowany program JScript</comment>
+ <comment xml:lang="es">programa en JScript codificado</comment>
+ <comment xml:lang="de">Verschlüsseltes JScript-Programm</comment>
+ <sub-class-of type="application/x-executable"/>
+ <generic-icon name="text-x-script"/>
+ <magic>
+ <match type="string" value="#@~^" offset="0"/>
+ </magic>
+ <glob pattern="*.jse"/>
+ </mime-type>
<mime-type type="application/json">
<comment>JSON document</comment>
<comment xml:lang="zh_TW">JSON 文件</comment>
@@ -13971,17 +14435,21 @@ command to generate the output files.
<comment xml:lang="tr">JSON belgesi</comment>
<comment xml:lang="sv">JSON-dokument</comment>
<comment xml:lang="sr">ЈСОН документ</comment>
+ <comment xml:lang="sq">dokument JSON</comment>
<comment xml:lang="sl">Dokument JSON</comment>
+ <comment xml:lang="si">JSON ලේඛනය</comment>
<comment xml:lang="sk">Dokument JSON</comment>
<comment xml:lang="ru">Документ JSON</comment>
<comment xml:lang="pt_BR">Documento JSON</comment>
<comment xml:lang="pt">documento JSON</comment>
<comment xml:lang="pl">Dokument JSON</comment>
<comment xml:lang="oc">document JSON</comment>
+ <comment xml:lang="nl">JSON-document</comment>
<comment xml:lang="ko">JSON 문서</comment>
<comment xml:lang="kk">JSON құжаты</comment>
<comment xml:lang="ja">JSON ドキュメント</comment>
<comment xml:lang="it">Documento JSON</comment>
+ <comment xml:lang="is">JSON skjal</comment>
<comment xml:lang="id">Dokumen JSON</comment>
<comment xml:lang="ia">Documento JSON</comment>
<comment xml:lang="hu">JSON dokumentum</comment>
@@ -14001,15 +14469,30 @@ command to generate the output files.
<comment xml:lang="cs">dokument JSON</comment>
<comment xml:lang="ca">document JSON</comment>
<comment xml:lang="bg">Документ — JSON</comment>
+ <comment xml:lang="be">дакумент JSON</comment>
<comment xml:lang="ast">Documentu JSON</comment>
<comment xml:lang="ar">مستند JSON</comment>
<comment xml:lang="af">JSON-dokument</comment>
<acronym>JSON</acronym>
<expanded-acronym>JavaScript Object Notation</expanded-acronym>
- <sub-class-of type="application/javascript"/>
+ <sub-class-of type="application/json5"/>
<generic-icon name="text-x-script"/>
<glob pattern="*.json"/>
</mime-type>
+ <mime-type type="application/json5">
+ <comment>JSON5 document</comment>
+ <comment xml:lang="uk">документ JSON5</comment>
+ <comment xml:lang="sv">JSON5-dokument</comment>
+ <comment xml:lang="ru">Документ JSON5</comment>
+ <comment xml:lang="pl">Dokument JSON5</comment>
+ <comment xml:lang="es">documento JSON5</comment>
+ <comment xml:lang="de">JSON5-Dokument</comment>
+ <acronym>JSON5</acronym>
+ <expanded-acronym>JavaScript Object Notation 5</expanded-acronym>
+ <sub-class-of type="text/javascript"/>
+ <generic-icon name="text-x-script"/>
+ <glob pattern="*.json5"/>
+ </mime-type>
<mime-type type="application/jrd+json">
<comment>JRD document</comment>
<comment xml:lang="zh_TW">JRD 文件</comment>
@@ -14018,22 +14501,27 @@ command to generate the output files.
<comment xml:lang="tr">JRD belgesi</comment>
<comment xml:lang="sv">JRD-dokument</comment>
<comment xml:lang="sr">ЈРД документ</comment>
+ <comment xml:lang="sq">dokument JRD</comment>
<comment xml:lang="sl">Dokument JRD</comment>
+ <comment xml:lang="si">JRD ලේඛනය</comment>
<comment xml:lang="sk">Dokument JRD</comment>
<comment xml:lang="ru">Документ JRD</comment>
<comment xml:lang="pt_BR">Documento JRD</comment>
<comment xml:lang="pt">doxumento JRD</comment>
<comment xml:lang="pl">Dokument JRD</comment>
<comment xml:lang="oc">document JRD</comment>
+ <comment xml:lang="nl">JRD-document</comment>
<comment xml:lang="ko">JRD 문서</comment>
<comment xml:lang="kk">JRD құжаты</comment>
<comment xml:lang="ja">JRD ドキュメント</comment>
<comment xml:lang="it">Documento JRD</comment>
+ <comment xml:lang="is">JRD skjal</comment>
<comment xml:lang="id">Dokumen JRD</comment>
<comment xml:lang="ia">Documento JRD</comment>
<comment xml:lang="hu">JRD dokumentum</comment>
<comment xml:lang="hr">JRD dokument</comment>
<comment xml:lang="he">מסמך JRD</comment>
+ <comment xml:lang="gl">Documento JRD</comment>
<comment xml:lang="ga">cáipéis JRD</comment>
<comment xml:lang="fur">document JRD</comment>
<comment xml:lang="fr">document JRD</comment>
@@ -14047,6 +14535,7 @@ command to generate the output files.
<comment xml:lang="cs">dokument JRD</comment>
<comment xml:lang="ca">document JRD</comment>
<comment xml:lang="bg">Документ — JRD</comment>
+ <comment xml:lang="be">дакумент JRD</comment>
<comment xml:lang="ast">Documentu JRD</comment>
<comment xml:lang="ar">مستند JRD</comment>
<comment xml:lang="af">JRD-dokument</comment>
@@ -14064,21 +14553,27 @@ command to generate the output files.
<comment xml:lang="tr">JSON yaması</comment>
<comment xml:lang="sv">JSON patch</comment>
<comment xml:lang="sr">ЈСОН закрпа</comment>
+ <comment xml:lang="sq">arnë JSON</comment>
+ <comment xml:lang="sl">Popravek JSON</comment>
+ <comment xml:lang="si">JSON පැච්</comment>
<comment xml:lang="sk">Záplata JSON</comment>
<comment xml:lang="ru">Патч JSON</comment>
<comment xml:lang="pt_BR">Patch JSON</comment>
<comment xml:lang="pt">patch JSON</comment>
<comment xml:lang="pl">Łata JSON</comment>
<comment xml:lang="oc">correctiu JSON</comment>
+ <comment xml:lang="nl">JSON-patch</comment>
<comment xml:lang="ko">JSON 패치</comment>
<comment xml:lang="kk">JSON өзгерісі</comment>
<comment xml:lang="ja">JSON パッチ</comment>
<comment xml:lang="it">Patch JSON</comment>
+ <comment xml:lang="is">JSON kóðabót</comment>
<comment xml:lang="id">Patch JSON</comment>
<comment xml:lang="ia">Patch JSON</comment>
<comment xml:lang="hu">JSON javítócsomag</comment>
<comment xml:lang="hr">JSON zakrpa</comment>
<comment xml:lang="he">טלאי JSON</comment>
+ <comment xml:lang="gl">Parche JSON</comment>
<comment xml:lang="ga">paiste JSON</comment>
<comment xml:lang="fur">blec JSON</comment>
<comment xml:lang="fr">correctif JSON</comment>
@@ -14091,6 +14586,7 @@ command to generate the output files.
<comment xml:lang="cs">cesta JSON</comment>
<comment xml:lang="ca">pedaç de JSON</comment>
<comment xml:lang="bg">Кръпка — JSON</comment>
+ <comment xml:lang="be">патч JSON</comment>
<comment xml:lang="ar">رقعة JSON</comment>
<acronym>JSON</acronym>
<expanded-acronym>JavaScript Object Notation</expanded-acronym>
@@ -14106,22 +14602,27 @@ command to generate the output files.
<comment xml:lang="tr">JSON-LD belgesi</comment>
<comment xml:lang="sv">JSON-LD-dokument</comment>
<comment xml:lang="sr">ЈСОН-ЛД документ</comment>
+ <comment xml:lang="sq">dokument JSON-LD</comment>
<comment xml:lang="sl">Dokument JSON-LD</comment>
+ <comment xml:lang="si">JSON-LD ලේඛනය</comment>
<comment xml:lang="sk">Dokument JSON-LD</comment>
<comment xml:lang="ru">Документ JSON-LD</comment>
<comment xml:lang="pt_BR">Documento JSON-LD</comment>
<comment xml:lang="pt">documento JSON-LD</comment>
<comment xml:lang="pl">Dokument JSON-LD</comment>
<comment xml:lang="oc">Document JSON-LD</comment>
+ <comment xml:lang="nl">JSON-LD-document</comment>
<comment xml:lang="ko">JSON-LD 문서</comment>
<comment xml:lang="kk">JSON-LD құжаты</comment>
<comment xml:lang="ja">JSON-LD ドキュメント</comment>
<comment xml:lang="it">Documento JSON-LD</comment>
+ <comment xml:lang="is">JSON-LD skjal</comment>
<comment xml:lang="id">Dokumen JSON-LD</comment>
<comment xml:lang="ia">Documento JSON-LD</comment>
<comment xml:lang="hu">JSON-LD dokumentum</comment>
<comment xml:lang="hr">JSON-LD dokument</comment>
<comment xml:lang="he">מסמך JSON-LD</comment>
+ <comment xml:lang="gl">Documento de JSON-LD</comment>
<comment xml:lang="ga">cáipéis JSON-LD</comment>
<comment xml:lang="fur">document JSON-LD</comment>
<comment xml:lang="fr">document JSON-LD</comment>
@@ -14135,6 +14636,7 @@ command to generate the output files.
<comment xml:lang="cs">dokument JSON-LD</comment>
<comment xml:lang="ca">document JSON-LD</comment>
<comment xml:lang="bg">Документ — JSON-LD</comment>
+ <comment xml:lang="be">дакумент JSON-LD</comment>
<comment xml:lang="ast">Documentu JSON-LD</comment>
<comment xml:lang="ar">مستند JSON-LD</comment>
<acronym>JSON-LD</acronym>
@@ -14145,6 +14647,29 @@ command to generate the output files.
</mime-type>
<mime-type type="application/schema+json">
<comment>JSON schema</comment>
+ <comment xml:lang="uk">схема JSON</comment>
+ <comment xml:lang="tr">JSON şeması</comment>
+ <comment xml:lang="sv">JSON-schema</comment>
+ <comment xml:lang="sl">Shema JSON</comment>
+ <comment xml:lang="si">JSON යෝජනා ක්රමය</comment>
+ <comment xml:lang="ru">Схема JSON</comment>
+ <comment xml:lang="pl">Schemat JSON</comment>
+ <comment xml:lang="oc">esquèma JSON</comment>
+ <comment xml:lang="nl">JSON-schema</comment>
+ <comment xml:lang="ko">JSON 스키마</comment>
+ <comment xml:lang="kk">JSON сұлбасы</comment>
+ <comment xml:lang="ja">JSON スキーマ</comment>
+ <comment xml:lang="it">Schema JSON</comment>
+ <comment xml:lang="hr">JSON shema</comment>
+ <comment xml:lang="he">סכמת JSON</comment>
+ <comment xml:lang="gl">Esquema de JSON</comment>
+ <comment xml:lang="fi">JSON-skeema</comment>
+ <comment xml:lang="eu">JSON eskema</comment>
+ <comment xml:lang="es">esquema JSON</comment>
+ <comment xml:lang="en_GB">JSON schema</comment>
+ <comment xml:lang="de">JSON-Schema</comment>
+ <comment xml:lang="be">схема JSON</comment>
+ <comment xml:lang="ar">مخطط JSON</comment>
<sub-class-of type="application/json"/>
<generic-icon name="text-x-script"/>
<magic priority="80">
@@ -14161,17 +14686,22 @@ command to generate the output files.
<comment xml:lang="uk">документ нотатника Jupyter</comment>
<comment xml:lang="tr">Jupyter notebook belgesi</comment>
<comment xml:lang="sv">Jupyter-anteckningsboksdokument</comment>
+ <comment xml:lang="sq">dokument ditari Jupyter</comment>
+ <comment xml:lang="si">Jupyter සටහන් පොත් ලේඛනය</comment>
<comment xml:lang="ru">Документ Jupyter notebook</comment>
<comment xml:lang="pt_BR">Documento Jupyter Notebook</comment>
<comment xml:lang="pl">Dokument notatnika Jupyter</comment>
+ <comment xml:lang="nl">Jupyter notebook-document</comment>
<comment xml:lang="ko">주피터 노트북 문서</comment>
<comment xml:lang="kk">Jupyter блокнот құжаты</comment>
<comment xml:lang="ja">Jupyter notebook ドキュメント</comment>
<comment xml:lang="it">Documento notebook Jupyter</comment>
+ <comment xml:lang="is">Jupyter skrifblokkarskjal</comment>
<comment xml:lang="id">Dokumen Jupyter notebook</comment>
<comment xml:lang="hu">Jupyter munkafüzet dokumentum</comment>
<comment xml:lang="hr">Jupyter notebook dokument</comment>
<comment xml:lang="he">מסמך מחברת של Jupyter</comment>
+ <comment xml:lang="gl">Documento de caderno de Jupyter</comment>
<comment xml:lang="fr">carnet de notes Jupyter</comment>
<comment xml:lang="fi">Jupyter notebook -asiakirja</comment>
<comment xml:lang="eu">Jupyter notebook dokumentua</comment>
@@ -14181,6 +14711,7 @@ command to generate the output files.
<comment xml:lang="da">Jupyter notebook-dokument</comment>
<comment xml:lang="ca">document de llibreta de notes de Jupyter</comment>
<comment xml:lang="bg">Скицник — Jupyter</comment>
+ <comment xml:lang="be">дакумент Jupyter notebook</comment>
<comment xml:lang="ar">مستند دفتر Jupyter</comment>
<sub-class-of type="application/json"/>
<generic-icon name="x-office-document"/>
@@ -14199,22 +14730,27 @@ command to generate the output files.
<comment xml:lang="tr">CoffeeScript belgesi</comment>
<comment xml:lang="sv">CoffeeScript-dokument</comment>
<comment xml:lang="sr">Кофи скрипт документ</comment>
+ <comment xml:lang="sq">dokument CoffeeScript</comment>
<comment xml:lang="sl">Dokument CoffeeScript</comment>
+ <comment xml:lang="si">CoffeeScript ලේඛනය</comment>
<comment xml:lang="sk">Dokument CoffeeScript</comment>
<comment xml:lang="ru">Документ CoffeeScript</comment>
<comment xml:lang="pt_BR">Documento CoffeeScript</comment>
<comment xml:lang="pt">documento CoffeeScript</comment>
<comment xml:lang="pl">Dokument CoffeeScript</comment>
<comment xml:lang="oc">Document CoffeScript</comment>
+ <comment xml:lang="nl">CoffeeScript-document</comment>
<comment xml:lang="ko">CoffeeScript 문서</comment>
<comment xml:lang="kk">CoffeeScript құжаты</comment>
<comment xml:lang="ja">CoffeeScript ドキュメント</comment>
<comment xml:lang="it">Documento CoffeeScript</comment>
+ <comment xml:lang="is">CoffeeScript skjal</comment>
<comment xml:lang="id">Dokumen CoffeeScript</comment>
<comment xml:lang="ia">Documento CoffeeScript</comment>
<comment xml:lang="hu">CoffeeScript dokumentum</comment>
<comment xml:lang="hr">CoffeeScript dokument</comment>
<comment xml:lang="he">מסמך CoffeeScript</comment>
+ <comment xml:lang="gl">Documento CoffeeScript</comment>
<comment xml:lang="ga">cáipéis CoffeeScript</comment>
<comment xml:lang="fur">document CoffeeScript</comment>
<comment xml:lang="fr">document CoffeeScript</comment>
@@ -14228,6 +14764,7 @@ command to generate the output files.
<comment xml:lang="cs">dokument CoffeeScript</comment>
<comment xml:lang="ca">document CoffeeScript</comment>
<comment xml:lang="bg">Документ — CoffeeScript</comment>
+ <comment xml:lang="be">дакумент CoffeeScript</comment>
<comment xml:lang="ast">Documentu de CoffeScript</comment>
<comment xml:lang="ar">مستند CoffeeScript</comment>
<comment xml:lang="af">CoffeeScript-dokument</comment>
@@ -14244,8 +14781,9 @@ command to generate the output files.
<comment xml:lang="tr">JBuilder projesi</comment>
<comment xml:lang="sv">JBuilder-projekt</comment>
<comment xml:lang="sr">пројекат ЈГрадитеља</comment>
- <comment xml:lang="sq">Projekt JBuilder</comment>
+ <comment xml:lang="sq">projekt JBuilder</comment>
<comment xml:lang="sl">Datoteka projekta JBuilder</comment>
+ <comment xml:lang="si">JBuilder ව්යාපෘතිය</comment>
<comment xml:lang="sk">Projekt JBuilder</comment>
<comment xml:lang="ru">Проект JBuilder</comment>
<comment xml:lang="ro">Proiect JBuilder</comment>
@@ -14263,6 +14801,7 @@ command to generate the output files.
<comment xml:lang="kk">JBuilder жобасы</comment>
<comment xml:lang="ja">JBuilder プロジェクト</comment>
<comment xml:lang="it">Progetto JBuilder</comment>
+ <comment xml:lang="is">JBuilder verkefni</comment>
<comment xml:lang="id">Proyek JBuilder</comment>
<comment xml:lang="ia">Projecto JBuilder</comment>
<comment xml:lang="hu">JBuilder-projekt</comment>
@@ -14285,6 +14824,7 @@ command to generate the output files.
<comment xml:lang="ca">projecte de JBuilder</comment>
<comment xml:lang="bg">Проект — JBuilder</comment>
<comment xml:lang="be@latin">Prajekt JBuilder</comment>
+ <comment xml:lang="be">праект JBuilder</comment>
<comment xml:lang="ar">مشروع JBuilder</comment>
<comment xml:lang="af">JBuilder-projek</comment>
<generic-icon name="x-office-document"/>
@@ -14300,8 +14840,9 @@ command to generate the output files.
<comment xml:lang="tr">Karbon14 çizimi</comment>
<comment xml:lang="sv">Karbon14-teckning</comment>
<comment xml:lang="sr">цртеж Карбона14</comment>
- <comment xml:lang="sq">Vizatim Karbon14</comment>
+ <comment xml:lang="sq">vizatim Karbon14</comment>
<comment xml:lang="sl">Datoteka risbe Karbon14</comment>
+ <comment xml:lang="si">Karbon14 ඇඳීම</comment>
<comment xml:lang="sk">Kresba Karbon14</comment>
<comment xml:lang="ru">Рисунок Karbon14</comment>
<comment xml:lang="ro">Desen Karbon14</comment>
@@ -14319,6 +14860,7 @@ command to generate the output files.
<comment xml:lang="kk">Karbon14 суреті</comment>
<comment xml:lang="ja">Karbon14 ドロー</comment>
<comment xml:lang="it">Disegno Karbon14</comment>
+ <comment xml:lang="is">Karbon14 Tteikning</comment>
<comment xml:lang="id">Gambar Karbon14</comment>
<comment xml:lang="ia">Designo Karbon14</comment>
<comment xml:lang="hu">Karbon14-rajz</comment>
@@ -14341,6 +14883,7 @@ command to generate the output files.
<comment xml:lang="ca">dibuix de Karbon14</comment>
<comment xml:lang="bg">Чертеж — Karbon14</comment>
<comment xml:lang="be@latin">Rysunak Karbon14</comment>
+ <comment xml:lang="be">рысунак Karbon14</comment>
<comment xml:lang="ar">تصميم Karbon14</comment>
<comment xml:lang="af">Karbon14-tekening</comment>
<generic-icon name="image-x-generic"/>
@@ -14367,8 +14910,9 @@ command to generate the output files.
<comment xml:lang="tr">KChart çizgesi</comment>
<comment xml:lang="sv">KChart-diagram</comment>
<comment xml:lang="sr">графикон К-графика</comment>
- <comment xml:lang="sq">Grafik KChart</comment>
+ <comment xml:lang="sq">grafik KChart</comment>
<comment xml:lang="sl">Datoteka grafikona KChart</comment>
+ <comment xml:lang="si">KChart ප්‍රස්ථාරය</comment>
<comment xml:lang="sk">Graf KChart</comment>
<comment xml:lang="ru">Диаграмма KChart</comment>
<comment xml:lang="ro">Diagramă KChart</comment>
@@ -14386,6 +14930,7 @@ command to generate the output files.
<comment xml:lang="kk">KChart диаграммасы</comment>
<comment xml:lang="ja">KChart チャート</comment>
<comment xml:lang="it">Grafico KChart</comment>
+ <comment xml:lang="is">KChart línurit</comment>
<comment xml:lang="id">Bagan KChart</comment>
<comment xml:lang="ia">Graphico KChart</comment>
<comment xml:lang="hu">KChart-grafikon</comment>
@@ -14408,6 +14953,7 @@ command to generate the output files.
<comment xml:lang="ca">diagrama de KChart</comment>
<comment xml:lang="bg">Диаграма — KChart</comment>
<comment xml:lang="be@latin">Hrafik KChart</comment>
+ <comment xml:lang="be">графік KChart</comment>
<comment xml:lang="ar">رسم بياني KChart</comment>
<comment xml:lang="af">KChart-grafiek</comment>
<generic-icon name="x-office-spreadsheet"/>
@@ -14432,19 +14978,25 @@ command to generate the output files.
<comment xml:lang="uk">параметри Kexi</comment>
<comment xml:lang="tr">Kexi ayarları</comment>
<comment xml:lang="sv">Kexi-inställningar</comment>
+ <comment xml:lang="sq">rregullime Kexi</comment>
<comment xml:lang="sl">Nastavitve Kexi</comment>
+ <comment xml:lang="si">Kexi සැකසුම්</comment>
<comment xml:lang="sk">Nastavenia Kexi</comment>
<comment xml:lang="ru">Файл настроек Kexi</comment>
<comment xml:lang="pt_BR">Configurações do Kexi</comment>
<comment xml:lang="pl">Ustawienia Kexi</comment>
+ <comment xml:lang="oc">paramètres Kexi</comment>
+ <comment xml:lang="nl">Kexi-instellingen</comment>
<comment xml:lang="ko">Kexi 설정</comment>
<comment xml:lang="kk">Kexi баптаулары</comment>
<comment xml:lang="ja">Kexi 設定</comment>
<comment xml:lang="it">Impostazioni Kexi</comment>
+ <comment xml:lang="is">Kexi stillingar</comment>
<comment xml:lang="id">Pengaturan Kexi</comment>
<comment xml:lang="hu">Kexi beállítások</comment>
<comment xml:lang="hr">Kexi postavke</comment>
<comment xml:lang="he">הגדרות Kexi</comment>
+ <comment xml:lang="gl">Preferencias de Kexi</comment>
<comment xml:lang="fr">réglages Kexi</comment>
<comment xml:lang="fi">Kexi-asetukset</comment>
<comment xml:lang="eu">Kexi ezarpenak</comment>
@@ -14454,6 +15006,7 @@ command to generate the output files.
<comment xml:lang="da">Kexi-indstillinger</comment>
<comment xml:lang="ca">ajusts de Kexi</comment>
<comment xml:lang="bg">Настройки — Kexi</comment>
+ <comment xml:lang="be">налады Kexi</comment>
<comment xml:lang="ar">إعدادات Kexi</comment>
<glob pattern="*.kexic"/>
</mime-type>
@@ -14464,18 +15017,24 @@ command to generate the output files.
<comment xml:lang="uk">скорочення Kexi</comment>
<comment xml:lang="tr">Kexi kısayolu</comment>
<comment xml:lang="sv">Kexi-genväg</comment>
+ <comment xml:lang="sq">shkurtore Kexi</comment>
+ <comment xml:lang="sl">Bližnjica Kexi</comment>
+ <comment xml:lang="si">Kexi කෙටිමඟ</comment>
<comment xml:lang="sk">Odkaz Kexi</comment>
<comment xml:lang="ru">Ссылка Kexi</comment>
<comment xml:lang="pt_BR">Atalho do Kexi</comment>
<comment xml:lang="pl">Skrót Kexi</comment>
+ <comment xml:lang="nl">Kexi-snelkoppeling</comment>
<comment xml:lang="ko">Kexi 바로 가기</comment>
<comment xml:lang="kk">Kexi жарлығы</comment>
<comment xml:lang="ja">Kexi ショートカット</comment>
<comment xml:lang="it">Scorciatoia Kexi</comment>
+ <comment xml:lang="is">Kexi fýtileið</comment>
<comment xml:lang="id">Pintasan Kexi</comment>
<comment xml:lang="hu">Kexi parancsiko</comment>
<comment xml:lang="hr">Kexi prečac</comment>
<comment xml:lang="he">קיצור דרך של Kexi</comment>
+ <comment xml:lang="gl">Atallo de Kexi</comment>
<comment xml:lang="fr">raccourci Kexi</comment>
<comment xml:lang="fi">Kexi-pikakuvake</comment>
<comment xml:lang="eu">Kexi lasterbidea</comment>
@@ -14485,6 +15044,7 @@ command to generate the output files.
<comment xml:lang="da">Kexi-genvej</comment>
<comment xml:lang="ca">drecera de Kexi</comment>
<comment xml:lang="bg">Ускорител — Kexi</comment>
+ <comment xml:lang="be">ярлык Kexi</comment>
<comment xml:lang="ar">اختصار Kexi</comment>
<glob pattern="*.kexis"/>
</mime-type>
@@ -14495,18 +15055,24 @@ command to generate the output files.
<comment xml:lang="uk">файл бази даних Kexi</comment>
<comment xml:lang="tr">Kexi veri tabanı dosyası</comment>
<comment xml:lang="sv">Kexi-databasfil</comment>
+ <comment xml:lang="sq">kartelë baze të dhënash Kexi</comment>
+ <comment xml:lang="sl">Datoteka zbirke podatkov Kexi</comment>
+ <comment xml:lang="si">Kexi දත්ත සමුදා ගොනුව</comment>
<comment xml:lang="sk">Súbor databázy Kexi</comment>
<comment xml:lang="ru">Файл базы данных Kexi</comment>
<comment xml:lang="pt_BR">Arquivo de banco de dados do Kexi</comment>
<comment xml:lang="pl">Plik bazy danych Kexi</comment>
+ <comment xml:lang="nl">Kexi-databasebestand</comment>
<comment xml:lang="ko">Kexi 데이터베이스 파일</comment>
<comment xml:lang="kk">Kexi дерекқор файлы</comment>
<comment xml:lang="ja">Kexi データベースファイル</comment>
<comment xml:lang="it">File database Kexi</comment>
+ <comment xml:lang="is">Kexi gagnagrunnsskrá</comment>
<comment xml:lang="id">Berkas basis data Kexi</comment>
<comment xml:lang="hu">Kexi adatbázisfájl</comment>
<comment xml:lang="hr">Kexi datoteka baze podataka</comment>
<comment xml:lang="he">קובץ מסד נתונים של Kexi</comment>
+ <comment xml:lang="gl">Ficheiro de base de datos Kexi</comment>
<comment xml:lang="fr">fichier de base de données Kexi</comment>
<comment xml:lang="fi">Kexi-tietokanta</comment>
<comment xml:lang="eu">Kexi datu-base fitxategia</comment>
@@ -14516,6 +15082,7 @@ command to generate the output files.
<comment xml:lang="da">Kexi database-fil</comment>
<comment xml:lang="ca">fitxer de base de dades de Kexi</comment>
<comment xml:lang="bg">База от данни — Kexi</comment>
+ <comment xml:lang="be">база даных Kexi</comment>
<comment xml:lang="ar">ملف قاعدة Kexi</comment>
<sub-class-of type="application/x-sqlite2"/>
<glob pattern="*.kexi"/>
@@ -14527,18 +15094,24 @@ command to generate the output files.
<comment xml:lang="uk">файл бази даних Kexi</comment>
<comment xml:lang="tr">Kexi veri tabanı dosyası</comment>
<comment xml:lang="sv">Kexi-databasfil</comment>
+ <comment xml:lang="sq">kartelë baze të dhënash Kexi</comment>
+ <comment xml:lang="sl">Datoteka zbirke podatkov Kexi</comment>
+ <comment xml:lang="si">Kexi දත්ත සමුදා ගොනුව</comment>
<comment xml:lang="sk">Súbor databázy Kexi</comment>
<comment xml:lang="ru">Файл базы данных Kexi</comment>
<comment xml:lang="pt_BR">Arquivo de banco de dados do Kexi</comment>
<comment xml:lang="pl">Plik bazy danych Kexi</comment>
+ <comment xml:lang="nl">Kexi-databasebestand</comment>
<comment xml:lang="ko">Kexi 데이터베이스 파일</comment>
<comment xml:lang="kk">Kexi дерекқор файлы</comment>
<comment xml:lang="ja">Kexi データベースファイル</comment>
<comment xml:lang="it">File database Kexi</comment>
+ <comment xml:lang="is">Kexi gagnagrunnsskrá</comment>
<comment xml:lang="id">Berkas basis data Kexi</comment>
<comment xml:lang="hu">Kexi adatbázisfájl</comment>
<comment xml:lang="hr">Kexi datoteka baze podataka</comment>
<comment xml:lang="he">קובץ מסד נתונים של Kexi</comment>
+ <comment xml:lang="gl">Ficheiro de base de datos Kexi</comment>
<comment xml:lang="fr">fichier de base de données Kexi</comment>
<comment xml:lang="fi">Kexi-tietokanta</comment>
<comment xml:lang="eu">Kexi datu-base fitxategia</comment>
@@ -14548,6 +15121,7 @@ command to generate the output files.
<comment xml:lang="da">Kexi database-fil</comment>
<comment xml:lang="ca">fitxer de base de dades de Kexi</comment>
<comment xml:lang="bg">База от данни — Kexi</comment>
+ <comment xml:lang="be">база даных Kexi</comment>
<comment xml:lang="ar">ملف قاعدة Kexi</comment>
<sub-class-of type="application/vnd.sqlite3"/>
<glob pattern="*.kexi"/>
@@ -14563,8 +15137,9 @@ command to generate the output files.
<comment xml:lang="tr">KFormula formülü</comment>
<comment xml:lang="sv">KFormula-formel</comment>
<comment xml:lang="sr">формула К-формуле</comment>
- <comment xml:lang="sq">Formulë KFormula</comment>
+ <comment xml:lang="sq">formulë KFormula</comment>
<comment xml:lang="sl">Datoteka formule KFormula</comment>
+ <comment xml:lang="si">KFormula සූත්‍රය</comment>
<comment xml:lang="sk">Vzorec KFormula</comment>
<comment xml:lang="ru">Формула KFormula</comment>
<comment xml:lang="ro">Formulă KFormula</comment>
@@ -14582,6 +15157,7 @@ command to generate the output files.
<comment xml:lang="kk">KFormula формуласы</comment>
<comment xml:lang="ja">KFormula 計算式</comment>
<comment xml:lang="it">Formula KFormula</comment>
+ <comment xml:lang="is">KFormula formúla</comment>
<comment xml:lang="id">Formula KFormula</comment>
<comment xml:lang="ia">Formula KFormula</comment>
<comment xml:lang="hu">KFormula-képlet</comment>
@@ -14604,6 +15180,7 @@ command to generate the output files.
<comment xml:lang="ca">fórmula de KFormula</comment>
<comment xml:lang="bg">Формула — KFormula</comment>
<comment xml:lang="be@latin">Formuła KFormula</comment>
+ <comment xml:lang="be">формула KFormula</comment>
<comment xml:lang="ar">صيغة KFormula</comment>
<comment xml:lang="af">KFormula-formule</comment>
<generic-icon name="x-office-document"/>
@@ -14630,8 +15207,9 @@ command to generate the output files.
<comment xml:lang="tr">KIllustrator çizimi</comment>
<comment xml:lang="sv">KIllustrator-teckning</comment>
<comment xml:lang="sr">цртеж К-илустратора</comment>
- <comment xml:lang="sq">Vizatim KIllustrator</comment>
+ <comment xml:lang="sq">vizatim KIllustrator</comment>
<comment xml:lang="sl">Datoteka risbe KIllustrator</comment>
+ <comment xml:lang="si">කිලිස්ට්රේටර් ඇඳීම</comment>
<comment xml:lang="sk">Kresba KIllustrator</comment>
<comment xml:lang="ru">Рисунок KIllustrator</comment>
<comment xml:lang="ro">Desen KIllustrator</comment>
@@ -14649,6 +15227,7 @@ command to generate the output files.
<comment xml:lang="kk">KIllustrator суреті</comment>
<comment xml:lang="ja">KIllustrator ドロー</comment>
<comment xml:lang="it">Disegno KIllustrator</comment>
+ <comment xml:lang="is">KIllustrator teikning</comment>
<comment xml:lang="id">Gambar KIllustrator</comment>
<comment xml:lang="ia">Designo KIllustrator</comment>
<comment xml:lang="hu">KIllustrator-rajz</comment>
@@ -14671,6 +15250,7 @@ command to generate the output files.
<comment xml:lang="ca">dibuix de KIllustrator</comment>
<comment xml:lang="bg">Чертеж — KIllustrator</comment>
<comment xml:lang="be@latin">Rysunak KIllustrator</comment>
+ <comment xml:lang="be">рысунак KIllustrator</comment>
<comment xml:lang="ar">تصميم KIllustrator</comment>
<comment xml:lang="af">KIllustrator-tekening</comment>
<generic-icon name="image-x-generic"/>
@@ -14692,8 +15272,9 @@ command to generate the output files.
<comment xml:lang="tr">Kivio akış çizgesi</comment>
<comment xml:lang="sv">Kivio-flödesschema</comment>
<comment xml:lang="sr">Кивиов дијаграм тока</comment>
- <comment xml:lang="sq">Diagramë fluksi Kivio</comment>
+ <comment xml:lang="sq">diagram hapash Kivio</comment>
<comment xml:lang="sl">Datoteka grafikona Kivio</comment>
+ <comment xml:lang="si">කිවියෝ ගැලීම් සටහන</comment>
<comment xml:lang="sk">Vývojový diagram Kivio</comment>
<comment xml:lang="ru">Диаграмма Kivio</comment>
<comment xml:lang="ro">Diagramă Kivio</comment>
@@ -14711,6 +15292,7 @@ command to generate the output files.
<comment xml:lang="kk">Kivio диаграммасы</comment>
<comment xml:lang="ja">Kivio フローチャート</comment>
<comment xml:lang="it">Diagramma di flusso Kivio</comment>
+ <comment xml:lang="is">Kivio flæðirit</comment>
<comment xml:lang="id">Bagan Kivio</comment>
<comment xml:lang="ia">Diagramma de fluxo Kivio</comment>
<comment xml:lang="hu">Kivio-folyamatábra</comment>
@@ -14733,6 +15315,7 @@ command to generate the output files.
<comment xml:lang="ca">diagrama de flux de Kivio</comment>
<comment xml:lang="bg">Диаграма — Kivio</comment>
<comment xml:lang="be@latin">Blok-schiema Kivio</comment>
+ <comment xml:lang="be">блок-схема Kivio</comment>
<comment xml:lang="ar">قائمة تدفق Kivio</comment>
<comment xml:lang="af">Kivio-vloeidiagram</comment>
<generic-icon name="x-office-document"/>
@@ -14759,8 +15342,9 @@ command to generate the output files.
<comment xml:lang="tr">Kontour çizimi</comment>
<comment xml:lang="sv">Kontour-teckning</comment>
<comment xml:lang="sr">Контуров цртеж</comment>
- <comment xml:lang="sq">Vizatim Kontour</comment>
+ <comment xml:lang="sq">vizatim Kontour</comment>
<comment xml:lang="sl">Datoteka risbe Kontour</comment>
+ <comment xml:lang="si">කොන්ටූර් ඇඳීම</comment>
<comment xml:lang="sk">Kresba Kontour</comment>
<comment xml:lang="ru">Рисунок Kontour</comment>
<comment xml:lang="ro">Desen Kontour</comment>
@@ -14778,6 +15362,7 @@ command to generate the output files.
<comment xml:lang="kk">Kontour суреті</comment>
<comment xml:lang="ja">Kontour ドロー</comment>
<comment xml:lang="it">Disegno Kontour</comment>
+ <comment xml:lang="is">Kontour teikning</comment>
<comment xml:lang="id">Gambar Kontour</comment>
<comment xml:lang="ia">Designo Kontour</comment>
<comment xml:lang="hu">Kontour-rajz</comment>
@@ -14800,6 +15385,7 @@ command to generate the output files.
<comment xml:lang="ca">dibuix de Kontour</comment>
<comment xml:lang="bg">Чертеж — Kontour</comment>
<comment xml:lang="be@latin">Rysunak Kontour</comment>
+ <comment xml:lang="be">рысунак Kontour</comment>
<comment xml:lang="ar">تصميم Kontour</comment>
<comment xml:lang="af">Kontour-tekening</comment>
<generic-icon name="image-x-generic"/>
@@ -14826,8 +15412,9 @@ command to generate the output files.
<comment xml:lang="tr">KPovModeler sahnesi</comment>
<comment xml:lang="sv">KPovModeler-scen</comment>
<comment xml:lang="sr">сцена КПов Моделера</comment>
- <comment xml:lang="sq">Skenë KPovModeler</comment>
+ <comment xml:lang="sq">skenë KPovModeler</comment>
<comment xml:lang="sl">Datoteka scene KPovModeler</comment>
+ <comment xml:lang="si">KPovModeler දර්ශනය</comment>
<comment xml:lang="sk">Scéna KPovModeler</comment>
<comment xml:lang="ru">Сцена KPovModeler</comment>
<comment xml:lang="ro">Scenă KPovModeler</comment>
@@ -14845,6 +15432,7 @@ command to generate the output files.
<comment xml:lang="kk">KPovModeler сахнасы</comment>
<comment xml:lang="ja">KPovModeler シーン</comment>
<comment xml:lang="it">Scena KPovModeler</comment>
+ <comment xml:lang="is">KPovModeler sviðsmynd</comment>
<comment xml:lang="id">Scene KPovModeler</comment>
<comment xml:lang="ia">Scena KPovModeler</comment>
<comment xml:lang="hu">KPovModeler-jelenet</comment>
@@ -14867,6 +15455,7 @@ command to generate the output files.
<comment xml:lang="ca">escena de KPovModeler</comment>
<comment xml:lang="bg">Сцена — KPovModeler</comment>
<comment xml:lang="be@latin">Scena KPovModeler</comment>
+ <comment xml:lang="be">сцэна KPovModeler</comment>
<comment xml:lang="ar">مشهد KPovModeler</comment>
<comment xml:lang="af">KPovModeler-toneel</comment>
<generic-icon name="image-x-generic"/>
@@ -14881,8 +15470,9 @@ command to generate the output files.
<comment xml:lang="tr">KPresenter sunum dosyası</comment>
<comment xml:lang="sv">KPresenter-presentation</comment>
<comment xml:lang="sr">презентација К-представљача</comment>
- <comment xml:lang="sq">Prezantim i KPresenter</comment>
+ <comment xml:lang="sq">paraqitje KPresenter</comment>
<comment xml:lang="sl">Predstavitev KPresenter</comment>
+ <comment xml:lang="si">KPresenter ඉදිරිපත් කිරීම</comment>
<comment xml:lang="sk">Prezentácia KPresenter</comment>
<comment xml:lang="ru">Презентация KPresenter</comment>
<comment xml:lang="ro">Prezentare KPresenter</comment>
@@ -14900,6 +15490,7 @@ command to generate the output files.
<comment xml:lang="kk">KPresenter презентациясы</comment>
<comment xml:lang="ja">KPresenter プレゼンテーション</comment>
<comment xml:lang="it">Presentazione KPresenter</comment>
+ <comment xml:lang="is">KPresenter framsetning</comment>
<comment xml:lang="id">Presentasi KPresenter</comment>
<comment xml:lang="ia">Presentation KPresenter</comment>
<comment xml:lang="hu">KPresenter-bemutató</comment>
@@ -14922,6 +15513,7 @@ command to generate the output files.
<comment xml:lang="ca">presentació de KPresenter</comment>
<comment xml:lang="bg">Презентация — KPresenter</comment>
<comment xml:lang="be@latin">Prezentacyja KPresenter</comment>
+ <comment xml:lang="be">прэзентацыя KPresenter</comment>
<comment xml:lang="ar">عرض تقديمي KPresenter</comment>
<comment xml:lang="af">KPresenter-voorlegging</comment>
<generic-icon name="x-office-presentation"/>
@@ -14949,8 +15541,9 @@ command to generate the output files.
<comment xml:lang="tr">Krita belgesi</comment>
<comment xml:lang="sv">Krita-dokument</comment>
<comment xml:lang="sr">документ Крите</comment>
- <comment xml:lang="sq">Dokument Krita</comment>
+ <comment xml:lang="sq">dokument Krita</comment>
<comment xml:lang="sl">Dokument Krita</comment>
+ <comment xml:lang="si">ක්‍රිටා ලේඛනය</comment>
<comment xml:lang="sk">Dokument Krita</comment>
<comment xml:lang="ru">Документ Krita</comment>
<comment xml:lang="ro">Document Krita</comment>
@@ -14968,6 +15561,7 @@ command to generate the output files.
<comment xml:lang="kk">Krita құжаты</comment>
<comment xml:lang="ja">Krita ドキュメント</comment>
<comment xml:lang="it">Documento Krita</comment>
+ <comment xml:lang="is">Krita skjal</comment>
<comment xml:lang="id">Dokumen Krita</comment>
<comment xml:lang="ia">Documento Krita</comment>
<comment xml:lang="hu">Krita-dokumentum</comment>
@@ -14990,6 +15584,7 @@ command to generate the output files.
<comment xml:lang="ca">document de Krita</comment>
<comment xml:lang="bg">Документ — Krita</comment>
<comment xml:lang="be@latin">Dakument Krita</comment>
+ <comment xml:lang="be">дакумент Krita</comment>
<comment xml:lang="ast">Documentu de Krita</comment>
<comment xml:lang="ar">مستند Krita</comment>
<comment xml:lang="af">Krita-dokument</comment>
@@ -15017,12 +15612,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">KSpread 試算表</comment>
<comment xml:lang="zh_CN">KSpread 电子表格</comment>
<comment xml:lang="vi">Bảng tính KSpread</comment>
- <comment xml:lang="uk">ел. таблиця KSpread</comment>
+ <comment xml:lang="uk">електронна таблиця KSpread</comment>
<comment xml:lang="tr">KSpread hesap çizelgesi</comment>
<comment xml:lang="sv">KSpread-kalkylblad</comment>
<comment xml:lang="sr">табела К-табеле</comment>
- <comment xml:lang="sq">Fletë llogaritjesh KSpread</comment>
+ <comment xml:lang="sq">fletëllogaritje KSpread</comment>
<comment xml:lang="sl">Preglednica KSpread</comment>
+ <comment xml:lang="si">KSpread පැතුරුම්පත</comment>
<comment xml:lang="sk">Zošit KSpread</comment>
<comment xml:lang="ru">Электронная таблица KSpread</comment>
<comment xml:lang="ro">Foaie de calcul KSpread</comment>
@@ -15040,6 +15636,7 @@ command to generate the output files.
<comment xml:lang="kk">KSpread электрондық кестесі</comment>
<comment xml:lang="ja">KSpread スプレッドシート</comment>
<comment xml:lang="it">Foglio di calcolo KSpread</comment>
+ <comment xml:lang="is">KSpread töflureikniskjal</comment>
<comment xml:lang="id">Lembar sebar KSpread</comment>
<comment xml:lang="ia">Folio de calculo KSpread</comment>
<comment xml:lang="hu">KSpread-munkafüzet</comment>
@@ -15062,6 +15659,7 @@ command to generate the output files.
<comment xml:lang="ca">full de càlcul de KSpread</comment>
<comment xml:lang="bg">Таблица — KSpread</comment>
<comment xml:lang="be@latin">Raźlikovy arkuš KSpread</comment>
+ <comment xml:lang="be">электронная табліца KSpread</comment>
<comment xml:lang="ar">جدول KSpread</comment>
<comment xml:lang="af">KSpread-sigblad</comment>
<generic-icon name="x-office-spreadsheet"/>
@@ -15084,12 +15682,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">KSpread 試算表 (加密)</comment>
<comment xml:lang="zh_CN">KSpread 电子表格(加密)</comment>
<comment xml:lang="vi">Bảng tính KSpread (đã mật mã)</comment>
- <comment xml:lang="uk">ел. таблиця KSpread (зашифрована)</comment>
+ <comment xml:lang="uk">електронна таблиця KSpread (зашифрована)</comment>
<comment xml:lang="tr">KSpread hesap çizelgesi (şifreli)</comment>
<comment xml:lang="sv">KSpread-kalkylblad (krypterat)</comment>
<comment xml:lang="sr">табела К-табеле (шифрована)</comment>
- <comment xml:lang="sq">Fletë llogaritjesh KSpread (e kriptuar)</comment>
+ <comment xml:lang="sq">fletëllogaritje KSpread (e fshehtëzuar)</comment>
<comment xml:lang="sl">Preglednica KSpread (šifrirana)</comment>
+ <comment xml:lang="si">KSpread පැතුරුම්පත (සංකේතනය කළ)</comment>
<comment xml:lang="sk">Zošit KSpread (šifrovaný)</comment>
<comment xml:lang="ru">Электронная таблица KSpread (зашифрованная)</comment>
<comment xml:lang="ro">Foaie de calcul KSpread (criptat)</comment>
@@ -15107,6 +15706,7 @@ command to generate the output files.
<comment xml:lang="kk">KSpread электрондық кестесі (шифрленген)</comment>
<comment xml:lang="ja">KSpread (暗号化) スプレッドシート</comment>
<comment xml:lang="it">Foglio di calcolo KSpread (cifrato)</comment>
+ <comment xml:lang="is">KSpread töflureikniskjal (dulritað)</comment>
<comment xml:lang="id">Lembar sebar KSpread (terenkripsi)</comment>
<comment xml:lang="ia">Folio de calculo KSpread (cryptate)</comment>
<comment xml:lang="hu">KSpread-munkafüzet (titkosított)</comment>
@@ -15129,6 +15729,7 @@ command to generate the output files.
<comment xml:lang="ca">full de càlcul de KSpread (xifrat)</comment>
<comment xml:lang="bg">Таблица — KSpread, шифрирана</comment>
<comment xml:lang="be@latin">Raźlikovy arkuš KSpread (zašyfravany)</comment>
+ <comment xml:lang="be">электронная табліца KSpread (зашыфравана)</comment>
<comment xml:lang="ar">جدول KSpread (مشفر)</comment>
<comment xml:lang="af">KSpread-sigblad (geënkripteer)</comment>
<generic-icon name="x-office-spreadsheet"/>
@@ -15145,8 +15746,9 @@ command to generate the output files.
<comment xml:lang="tr">KSysV init paketi</comment>
<comment xml:lang="sv">KSysV init-paket</comment>
<comment xml:lang="sr">КСисВ побудни пакет</comment>
- <comment xml:lang="sq">Paketë init KSysV</comment>
+ <comment xml:lang="sq">paketë init KSysV</comment>
<comment xml:lang="sl">Datoteka paketa KSysV init</comment>
+ <comment xml:lang="si">KSysV init පැකේජය</comment>
<comment xml:lang="sk">Balíček KSysV init</comment>
<comment xml:lang="ru">Пакет инициализации KSysV</comment>
<comment xml:lang="ro">Pachet KSysV init</comment>
@@ -15163,6 +15765,7 @@ command to generate the output files.
<comment xml:lang="kk">KSysV инициализация дестесі</comment>
<comment xml:lang="ja">KSysV init パッケージ</comment>
<comment xml:lang="it">Pacchetto init KSysV</comment>
+ <comment xml:lang="is">KSysV init-pakki</comment>
<comment xml:lang="id">Paket init KSysV</comment>
<comment xml:lang="ia">Pacchetto de initialisation KSysV</comment>
<comment xml:lang="hu">KSysV init csomag</comment>
@@ -15184,6 +15787,7 @@ command to generate the output files.
<comment xml:lang="ca">paquet de KSysV init</comment>
<comment xml:lang="bg">Пакет — KSysV init</comment>
<comment xml:lang="be@latin">Inicyjalny pakunak KSysV</comment>
+ <comment xml:lang="be">пакет ініцыялізацыі KSysV</comment>
<comment xml:lang="ar">حزمة KSysV init</comment>
<generic-icon name="package-x-generic"/>
<magic>
@@ -15201,8 +15805,9 @@ command to generate the output files.
<comment xml:lang="tr">Kugar belgesi</comment>
<comment xml:lang="sv">Kugar-dokument</comment>
<comment xml:lang="sr">документ Кугара</comment>
- <comment xml:lang="sq">Dokument Kugar</comment>
+ <comment xml:lang="sq">dokument Kugar</comment>
<comment xml:lang="sl">Dokument Kugar</comment>
+ <comment xml:lang="si">කුගර් ලේඛනය</comment>
<comment xml:lang="sk">Dokument Kugar</comment>
<comment xml:lang="ru">Документ Kugar</comment>
<comment xml:lang="ro">Document Kugar</comment>
@@ -15220,6 +15825,7 @@ command to generate the output files.
<comment xml:lang="kk">Kugar құжаты</comment>
<comment xml:lang="ja">Kugar ドキュメント</comment>
<comment xml:lang="it">Documento Kugar</comment>
+ <comment xml:lang="is">Kugar skjal</comment>
<comment xml:lang="id">Dokumen Kugar</comment>
<comment xml:lang="ia">Documento Kugar</comment>
<comment xml:lang="hu">Kugar-dokumentum</comment>
@@ -15242,6 +15848,7 @@ command to generate the output files.
<comment xml:lang="ca">document Kugar</comment>
<comment xml:lang="bg">Документ — Kugar</comment>
<comment xml:lang="be@latin">Dakument Kugar</comment>
+ <comment xml:lang="be">дакумент Kugar</comment>
<comment xml:lang="ast">Documentu de Kugar</comment>
<comment xml:lang="ar">مستند Kugar</comment>
<comment xml:lang="af">Kugar-dokument</comment>
@@ -15257,8 +15864,9 @@ command to generate the output files.
<comment xml:lang="tr">KWord belgesi</comment>
<comment xml:lang="sv">KWord-dokument</comment>
<comment xml:lang="sr">документ К-речи</comment>
- <comment xml:lang="sq">Dokument KWord</comment>
+ <comment xml:lang="sq">dokument KWord</comment>
<comment xml:lang="sl">Dokument KWord</comment>
+ <comment xml:lang="si">KWord ලේඛනය</comment>
<comment xml:lang="sk">Dokument KWord</comment>
<comment xml:lang="ru">Документ KWord</comment>
<comment xml:lang="ro">Document KWord</comment>
@@ -15276,6 +15884,7 @@ command to generate the output files.
<comment xml:lang="kk">KWord құжаты</comment>
<comment xml:lang="ja">KWord ドキュメント</comment>
<comment xml:lang="it">Documento KWord</comment>
+ <comment xml:lang="is">KWord skjal</comment>
<comment xml:lang="id">Dokumen KWord</comment>
<comment xml:lang="ia">Documento KWord</comment>
<comment xml:lang="hu">KWord-dokumentum</comment>
@@ -15299,6 +15908,7 @@ command to generate the output files.
<comment xml:lang="ca">document KWord</comment>
<comment xml:lang="bg">Документ — KWord</comment>
<comment xml:lang="be@latin">Dakument KWord</comment>
+ <comment xml:lang="be">дакумент KWord</comment>
<comment xml:lang="ast">Documentu de Kword</comment>
<comment xml:lang="ar">مستند KWord</comment>
<comment xml:lang="af">KWord-dokument</comment>
@@ -15327,8 +15937,9 @@ command to generate the output files.
<comment xml:lang="tr">KWord belgesi (şifreli)</comment>
<comment xml:lang="sv">KWord-dokument (krypterat)</comment>
<comment xml:lang="sr">документ К-речи (шифровани)</comment>
- <comment xml:lang="sq">Dokument KWord (i kriptuar)</comment>
+ <comment xml:lang="sq">dokument KWord (i fshehtëzuar)</comment>
<comment xml:lang="sl">Dokument KWord (šifriran)</comment>
+ <comment xml:lang="si">KWord ලේඛනය (සංකේතනය කළ)</comment>
<comment xml:lang="sk">Dokument KWord (šifrovaný)</comment>
<comment xml:lang="ru">Документ KWord (зашифрованный)</comment>
<comment xml:lang="ro">Document KWord (criptat)</comment>
@@ -15346,6 +15957,7 @@ command to generate the output files.
<comment xml:lang="kk">KWord құжаты (шифрленген)</comment>
<comment xml:lang="ja">KWord (暗号化) ドキュメント</comment>
<comment xml:lang="it">Documento KWord (cifrato)</comment>
+ <comment xml:lang="is">KWord skjal (dulritað)</comment>
<comment xml:lang="id">Dokumen KWord (terenkripsi)</comment>
<comment xml:lang="ia">Documento KWord (cryptate)</comment>
<comment xml:lang="hu">KWord-dokumentum (titkosított)</comment>
@@ -15368,6 +15980,7 @@ command to generate the output files.
<comment xml:lang="ca">document KWord (xifrat)</comment>
<comment xml:lang="bg">Документ — KWord, шифриран</comment>
<comment xml:lang="be@latin">Dakument KWord (zašyfravany)</comment>
+ <comment xml:lang="be">дакумент KWord (зашыфраваны)</comment>
<comment xml:lang="ast">Documentu de Kword (cifráu)</comment>
<comment xml:lang="ar">مستند KWord (مشفر)</comment>
<comment xml:lang="af">KWord-dokument (geënkripteer)</comment>
@@ -15385,8 +15998,9 @@ command to generate the output files.
<comment xml:lang="tr">LHA arşivi</comment>
<comment xml:lang="sv">LHA-arkiv</comment>
<comment xml:lang="sr">ЛХА архива</comment>
- <comment xml:lang="sq">Arkiv LHA</comment>
+ <comment xml:lang="sq">arkiv LHA</comment>
<comment xml:lang="sl">Datoteka arhiva LHA</comment>
+ <comment xml:lang="si">LHA ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív LHA</comment>
<comment xml:lang="ru">Архив LHA</comment>
<comment xml:lang="ro">Arhivă LHA</comment>
@@ -15404,6 +16018,7 @@ command to generate the output files.
<comment xml:lang="kk">LHA архиві</comment>
<comment xml:lang="ja">LHA アーカイブ</comment>
<comment xml:lang="it">Archivio LHA</comment>
+ <comment xml:lang="is">LHA safnskrá</comment>
<comment xml:lang="id">Arsip LHA</comment>
<comment xml:lang="ia">Archivo LHA</comment>
<comment xml:lang="hu">LHA-archívum</comment>
@@ -15427,6 +16042,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu LHA</comment>
<comment xml:lang="bg">Архив — LHA</comment>
<comment xml:lang="be@latin">Archiŭ LHA</comment>
+ <comment xml:lang="be">архіў LHA</comment>
<comment xml:lang="az">LHA arxivi</comment>
<comment xml:lang="ar">أرشيف LHA</comment>
<comment xml:lang="af">LHA-argief</comment>
@@ -15458,8 +16074,9 @@ command to generate the output files.
<comment xml:lang="tr">LHZ arşivi</comment>
<comment xml:lang="sv">LHZ-arkiv</comment>
<comment xml:lang="sr">ЛХЗ архива</comment>
- <comment xml:lang="sq">Arkiv LHZ</comment>
+ <comment xml:lang="sq">arkiv LHZ</comment>
<comment xml:lang="sl">Datoteka arhiva LHZ</comment>
+ <comment xml:lang="si">LHZ ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív LHZ</comment>
<comment xml:lang="ru">Архив LHZ</comment>
<comment xml:lang="ro">Arhivă LHZ</comment>
@@ -15477,6 +16094,7 @@ command to generate the output files.
<comment xml:lang="kk">LHZ архиві</comment>
<comment xml:lang="ja">LHZ アーカイブ</comment>
<comment xml:lang="it">Archivio LHZ</comment>
+ <comment xml:lang="is">LHZ safnskrá</comment>
<comment xml:lang="id">Arsip LHZ</comment>
<comment xml:lang="ia">Archivo LHZ</comment>
<comment xml:lang="hu">LHZ-archívum</comment>
@@ -15499,63 +16117,24 @@ command to generate the output files.
<comment xml:lang="ca">arxiu LHZ</comment>
<comment xml:lang="bg">Архив — LHZ</comment>
<comment xml:lang="be@latin">Archiŭ LHZ</comment>
+ <comment xml:lang="be">архіў LHZ</comment>
<comment xml:lang="ar">أرشيف LHZ</comment>
<comment xml:lang="af">LHZ-argief</comment>
<generic-icon name="package-x-generic"/>
<glob pattern="*.lhz"/>
</mime-type>
<mime-type type="text/vnd.trolltech.linguist">
- <comment>message catalog</comment>
- <comment xml:lang="zh_TW">訊息目錄</comment>
- <comment xml:lang="zh_CN">消息库</comment>
- <comment xml:lang="vi">phân loại thông điệp</comment>
+ <comment>Message catalog</comment>
<comment xml:lang="uk">каталог повідомлень</comment>
- <comment xml:lang="tr">ileti kataloğu</comment>
- <comment xml:lang="sv">meddelandekatalog</comment>
- <comment xml:lang="sr">каталог порука</comment>
- <comment xml:lang="sq">Katallog mesazhesh</comment>
- <comment xml:lang="sl">katalogov sporočil</comment>
- <comment xml:lang="sk">Katalóg správ</comment>
+ <comment xml:lang="sv">Meddelandekatalog</comment>
<comment xml:lang="ru">Каталог сообщений</comment>
- <comment xml:lang="ro">catalog de mesaje</comment>
- <comment xml:lang="pt_BR">Catálogo de mensagens</comment>
- <comment xml:lang="pt">catálogo de mensagens</comment>
<comment xml:lang="pl">Katalog wiadomości</comment>
- <comment xml:lang="oc">catalòg de messatges</comment>
- <comment xml:lang="nn">meldingskatalog</comment>
- <comment xml:lang="nl">berichtencatalogus</comment>
- <comment xml:lang="nb">meldingskatalog</comment>
- <comment xml:lang="ms">Katalog mesej</comment>
- <comment xml:lang="lv">ziņojumu katalogs</comment>
- <comment xml:lang="lt">laiškų katalogas</comment>
- <comment xml:lang="ko">메시지 카탈로그</comment>
- <comment xml:lang="kk">мәлімдемелер каталогы</comment>
- <comment xml:lang="ja">メッセージカタログ</comment>
<comment xml:lang="it">Catalogo di messaggi</comment>
- <comment xml:lang="id">katalog pesan</comment>
- <comment xml:lang="ia">Catalogo de messages</comment>
- <comment xml:lang="hu">üzenetkatalógus</comment>
- <comment xml:lang="hr">Katalog poruka</comment>
- <comment xml:lang="he">קטלוג הודעות</comment>
- <comment xml:lang="gl">catálogo de mensaxes</comment>
- <comment xml:lang="ga">catalóg theachtaireachtaí</comment>
- <comment xml:lang="fur">catalic di messaçs</comment>
- <comment xml:lang="fr">catalogue de messages</comment>
- <comment xml:lang="fo">boðskrá</comment>
- <comment xml:lang="fi">viestiluettelo</comment>
- <comment xml:lang="eu">mezuen katalogoa</comment>
+ <comment xml:lang="gl">Catálogo de mensaxes</comment>
+ <comment xml:lang="eu">Mezu-katalogoa</comment>
<comment xml:lang="es">catálogo de mensajes</comment>
- <comment xml:lang="eo">katalogo de mesaĝoj</comment>
- <comment xml:lang="en_GB">message catalogue</comment>
- <comment xml:lang="el">Κατάλογος μηνυμάτων</comment>
<comment xml:lang="de">Nachrichtenkatalog</comment>
- <comment xml:lang="da">meddelelseskatalog</comment>
- <comment xml:lang="cs">katalog zpráv</comment>
- <comment xml:lang="ca">catàleg de missatges</comment>
- <comment xml:lang="bg">Каталог със съобщения</comment>
- <comment xml:lang="be@latin">kataloh paviedamleńniaŭ</comment>
- <comment xml:lang="ar">دليل رسالة</comment>
- <comment xml:lang="af">boodskaplêer</comment>
+ <comment xml:lang="be">каталог паведамленняў</comment>
<sub-class-of type="application/xml"/>
<magic>
<match type="string" value="&lt;TS " offset="0:256"/>
@@ -15574,8 +16153,9 @@ command to generate the output files.
<comment xml:lang="tr">LyX belgesi</comment>
<comment xml:lang="sv">LyX-dokument</comment>
<comment xml:lang="sr">ЛиКс документ</comment>
- <comment xml:lang="sq">Dokument LyX</comment>
+ <comment xml:lang="sq">dokument LyX</comment>
<comment xml:lang="sl">Dokument LyX</comment>
+ <comment xml:lang="si">LyX ලේඛනය</comment>
<comment xml:lang="sk">Dokument LyX</comment>
<comment xml:lang="ru">Документ LyX</comment>
<comment xml:lang="ro">Document LyX</comment>
@@ -15593,6 +16173,7 @@ command to generate the output files.
<comment xml:lang="kk">LyX құжаты</comment>
<comment xml:lang="ja">LyX ドキュメント</comment>
<comment xml:lang="it">Documento LyX</comment>
+ <comment xml:lang="is">LyX skjal</comment>
<comment xml:lang="id">Dokumen LyX</comment>
<comment xml:lang="ia">Documento LyX</comment>
<comment xml:lang="hu">LyX-dokumentum</comment>
@@ -15615,6 +16196,7 @@ command to generate the output files.
<comment xml:lang="ca">document LyX</comment>
<comment xml:lang="bg">Документ — LyX</comment>
<comment xml:lang="be@latin">Dakument LyX</comment>
+ <comment xml:lang="be">дакумент LyX</comment>
<comment xml:lang="ast">Documentu de Lyx</comment>
<comment xml:lang="ar">مستند LyX</comment>
<comment xml:lang="af">LyX-dokument</comment>
@@ -15634,17 +16216,21 @@ command to generate the output files.
<comment xml:lang="tr">LZ4 arşivi</comment>
<comment xml:lang="sv">LZ4-arkiv</comment>
<comment xml:lang="sr">ЛЗ4 архива</comment>
+ <comment xml:lang="sq">arkiv LZ4</comment>
<comment xml:lang="sl">Datoteka arhiva LZ4</comment>
+ <comment xml:lang="si">LZ4 ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív LZ4</comment>
<comment xml:lang="ru">Архив LZ4</comment>
<comment xml:lang="pt_BR">Pacote LZ4</comment>
<comment xml:lang="pt">arquivo LZ4</comment>
<comment xml:lang="pl">Archiwum LZ4</comment>
<comment xml:lang="oc">archiu LZ4</comment>
+ <comment xml:lang="nl">LZ4-archief</comment>
<comment xml:lang="ko">LZ4 압축 파일</comment>
<comment xml:lang="kk">LZ4 архиві</comment>
<comment xml:lang="ja">LZ4 アーカイヴ</comment>
<comment xml:lang="it">Archivio LZ4</comment>
+ <comment xml:lang="is">LZ4 safnskrá</comment>
<comment xml:lang="id">Arsip LZ4</comment>
<comment xml:lang="ia">Archivo LZ4</comment>
<comment xml:lang="hu">LZ4 archívum</comment>
@@ -15664,6 +16250,7 @@ command to generate the output files.
<comment xml:lang="cs">archiv LZ4</comment>
<comment xml:lang="ca">arxiu LZ4</comment>
<comment xml:lang="bg">Архив — LZ4</comment>
+ <comment xml:lang="be">архіў LZ4</comment>
<comment xml:lang="ar">أرشيف LZ4</comment>
<comment xml:lang="af">LZ4-argief</comment>
<generic-icon name="package-x-generic"/>
@@ -15681,14 +16268,20 @@ command to generate the output files.
<comment xml:lang="tr">Tar arşivi (LZ4 ile sıkıştırılmış)</comment>
<comment xml:lang="sv">Tar-arkiv (LZ4-komprimerat)</comment>
<comment xml:lang="sr">Тар архива (запакована ЛЗ4-ом)</comment>
+ <comment xml:lang="sq">arkiv tar (ngjeshur me LZ4)</comment>
+ <comment xml:lang="sl">Arhiv tar (stisnjen, LZ4)</comment>
+ <comment xml:lang="si">තාර සංරක්ෂිතය (LZ4-සම්පීඩිත)</comment>
<comment xml:lang="sk">Archív Tar (komprimovaný pomocou LZ4)</comment>
<comment xml:lang="ru">Архив TAR (сжатый lz4)</comment>
<comment xml:lang="pt_BR">Arquivo Tar (compactado com LZ4)</comment>
<comment xml:lang="pl">Archiwum tar (kompresja LZ4)</comment>
+ <comment xml:lang="oc">archiu Tar (compression LZ4)</comment>
+ <comment xml:lang="nl">Tar-archief (gecomprimeerd met LZ4)</comment>
<comment xml:lang="ko">Tar 묶음 파일(LZ4 압축)</comment>
<comment xml:lang="kk">Tar архиві (LZ4-пен сығылған)</comment>
<comment xml:lang="ja">Tar アーカイブ (LZ4 圧縮)</comment>
<comment xml:lang="it">Archivio tar (compresso con LZ4)</comment>
+ <comment xml:lang="is">Tar safnskrá (LZ4-þjappað)</comment>
<comment xml:lang="id">Arsip tar (terkompresi LZ4)</comment>
<comment xml:lang="hu">Tar archívum (LZ4 tömörítésű)</comment>
<comment xml:lang="hr">Tar arhiva (LZ4 sažeto)</comment>
@@ -15698,13 +16291,14 @@ command to generate the output files.
<comment xml:lang="fr">archive tar (compression LZ4)</comment>
<comment xml:lang="fi">Tar-arkisto (LZ4-pakattu)</comment>
<comment xml:lang="eu">Tar artxiboa (LZ4-rekin konprimatua)</comment>
- <comment xml:lang="es">archivador Tar (comprimido con LZ4)</comment>
+ <comment xml:lang="es">archivador TAR (comprimido con LZ4)</comment>
<comment xml:lang="en_GB">Tar archive (LZ4-compressed)</comment>
<comment xml:lang="de">Tar-Archiv (LZ4-komprimiert)</comment>
<comment xml:lang="da">Tar-arkiv (LZ4-komprimeret)</comment>
<comment xml:lang="cs">archiv Tar (komprimace LZ4)</comment>
<comment xml:lang="ca">arxiu tar (amb compressió LZ4)</comment>
<comment xml:lang="bg">Архив — tar, компресиран с LZ4</comment>
+ <comment xml:lang="be">архіў tar (сцісканне LZ4)</comment>
<comment xml:lang="ar">أرشيف Tar (مضغوط-LZ4)</comment>
<comment xml:lang="af">Tar-argief (LZ4-saamgepers)</comment>
<generic-icon name="package-x-generic"/>
@@ -15719,7 +16313,9 @@ command to generate the output files.
<comment xml:lang="tr">Lzip arşivi</comment>
<comment xml:lang="sv">Lzip-arkiv</comment>
<comment xml:lang="sr">Лзип архива</comment>
+ <comment xml:lang="sq">arkiv Lzip</comment>
<comment xml:lang="sl">Datoteka arhiva Lzip</comment>
+ <comment xml:lang="si">Lzip සංරක්ෂිතය</comment>
<comment xml:lang="sk">Archív Lzip</comment>
<comment xml:lang="ru">Архив LZIP</comment>
<comment xml:lang="ro">Arhivă Lzip</comment>
@@ -15727,13 +16323,14 @@ command to generate the output files.
<comment xml:lang="pt">arquivo LZip</comment>
<comment xml:lang="pl">Archiwum lzip</comment>
<comment xml:lang="oc">archiu lzip</comment>
- <comment xml:lang="nl">Lzip archief</comment>
+ <comment xml:lang="nl">Lzip-archief</comment>
<comment xml:lang="lv">Lzip arhīvs</comment>
<comment xml:lang="lt">Lzip archyvas</comment>
<comment xml:lang="ko">LZIP 압축 파일</comment>
<comment xml:lang="kk">Lzip архиві</comment>
<comment xml:lang="ja">Lzip アーカイブ</comment>
<comment xml:lang="it">Archivio Lzip</comment>
+ <comment xml:lang="is">Lzip safnskrá</comment>
<comment xml:lang="id">Arsip Lzip</comment>
<comment xml:lang="ia">Archivo Lzip</comment>
<comment xml:lang="hu">Lzip archívum</comment>
@@ -15755,6 +16352,7 @@ command to generate the output files.
<comment xml:lang="cs">archiv Lzip</comment>
<comment xml:lang="ca">arxiu lzip</comment>
<comment xml:lang="bg">Архив — Lzip</comment>
+ <comment xml:lang="be">архіў Lzip</comment>
<comment xml:lang="ar">أرشيف Lzip</comment>
<comment xml:lang="af">Lzip-argief</comment>
<generic-icon name="package-x-generic"/>
@@ -15771,14 +16369,20 @@ command to generate the output files.
<comment xml:lang="tr">Tar arşivi (lzip ile sıkıştırılmış)</comment>
<comment xml:lang="sv">Tar-arkiv (lzip-komprimerat)</comment>
<comment xml:lang="sr">Тар архива (запакована лзипом)</comment>
+ <comment xml:lang="sq">arkiv tar (ngjeshur me lzip)</comment>
+ <comment xml:lang="sl">Arhiv tar (stisnjen, lzip)</comment>
+ <comment xml:lang="si">තාර සංරක්ෂිතය (lzip-සම්පීඩිත)</comment>
<comment xml:lang="sk">Archív Tar (komprimovaný pomocou lzip)</comment>
<comment xml:lang="ru">Архив TAR (сжатый lzip)</comment>
<comment xml:lang="pt_BR">Arquivo Tar (compactado com lzip)</comment>
<comment xml:lang="pl">Archiwum tar (kompresja lzip)</comment>
+ <comment xml:lang="oc">archiu Tar (compression lzip)</comment>
+ <comment xml:lang="nl">Tar-archief (gecomprimeerd met lzip)</comment>
<comment xml:lang="ko">TAR 묶음 파일(LZIP 압축)</comment>
<comment xml:lang="kk">Tar архиві (lzip-пен сығылған)</comment>
<comment xml:lang="ja">Tar アーカイブ (lzip 圧縮)</comment>
<comment xml:lang="it">Archivio tar (compresso con lzip)</comment>
+ <comment xml:lang="is">Tar safnskrá (lzip-þjappað)</comment>
<comment xml:lang="id">Arsip tar (terkompresi lzip)</comment>
<comment xml:lang="hu">Tar archívum (lzip tömörítésű)</comment>
<comment xml:lang="hr">Tar arhiva (lzip sažeto)</comment>
@@ -15788,13 +16392,14 @@ command to generate the output files.
<comment xml:lang="fr">archive tar (compressée lzip)</comment>
<comment xml:lang="fi">Tar-arkisto (lzip-pakattu)</comment>
<comment xml:lang="eu">Tar artxiboa (lzip-rekin konprimatua)</comment>
- <comment xml:lang="es">archivador Tar (comprimido con lzip)</comment>
+ <comment xml:lang="es">archivador TAR (comprimido con LZIP)</comment>
<comment xml:lang="en_GB">Tar archive (lzip-compressed)</comment>
<comment xml:lang="de">Tar-Archiv (lzip-komprimiert)</comment>
<comment xml:lang="da">Tar-arkiv (lzip-komprimeret)</comment>
<comment xml:lang="cs">archiv Tar (komprimace lzip)</comment>
<comment xml:lang="ca">arxiu tar (amb compressió lzip)</comment>
<comment xml:lang="bg">Архив — tar, компресиран с Lzip</comment>
+ <comment xml:lang="be">архіў tar (сцісканне lzip)</comment>
<comment xml:lang="ar">أرشيف Tar (مضغوط-lzip)</comment>
<comment xml:lang="af">Tar-argief (lzip-saamgepers)</comment>
<generic-icon name="package-x-generic"/>
@@ -15809,15 +16414,20 @@ command to generate the output files.
<comment xml:lang="tr">PDF belgesi (lzip ile sıkıştırılmış)</comment>
<comment xml:lang="sv">PDF-dokument (lzip-komprimerat)</comment>
<comment xml:lang="sr">ПДФ документ (запакован лзип-ом)</comment>
+ <comment xml:lang="sq">dokument PDF (ngjeshur me lzip)</comment>
+ <comment xml:lang="sl">Dokument PDF (stisnjen, lzip)</comment>
+ <comment xml:lang="si">PDF ලේඛනය (lzip-compressed)</comment>
<comment xml:lang="sk">Dokument PDF (komprimovaný pomocou lzip)</comment>
<comment xml:lang="ru">Документ PDF (сжатый lzip)</comment>
<comment xml:lang="pt_BR">Documento PDF (compactado com lzip)</comment>
<comment xml:lang="pl">Dokument PDF (kompresja lzip)</comment>
<comment xml:lang="oc">document PDF (compressat amb lzip)</comment>
+ <comment xml:lang="nl">PDF-document (gecomprimeerd met lzip)</comment>
<comment xml:lang="ko">PDF 문서(LZIP 압축)</comment>
<comment xml:lang="kk">PDF құжаты (lzip-пен сығылған)</comment>
<comment xml:lang="ja">PDF ドキュメント (lzip 圧縮)</comment>
<comment xml:lang="it">Documento PDF (compresso con lzip)</comment>
+ <comment xml:lang="is">PDF skjal (lzip-þjappað)</comment>
<comment xml:lang="id">Dokumen PDF (termkompresi lzip)</comment>
<comment xml:lang="hu">PDF dokumentum (lzip tömörítésű)</comment>
<comment xml:lang="hr">PDF dokument (lzip sažeto)</comment>
@@ -15827,13 +16437,14 @@ command to generate the output files.
<comment xml:lang="fr">document PDF (compressé lzip)</comment>
<comment xml:lang="fi">PDF-asiakirja (lzip-pakattu)</comment>
<comment xml:lang="eu">PDF dokumentua (lzip-rekin konprimitua)</comment>
- <comment xml:lang="es">documento PDF (comprimido con lzip)</comment>
+ <comment xml:lang="es">documento PDF (comprimido con LZIP)</comment>
<comment xml:lang="en_GB">PDF document (lzip-compressed)</comment>
<comment xml:lang="de">PDF-Dokument (lzip-komprimiert)</comment>
<comment xml:lang="da">PDF-dokument (lzip-komprimeret)</comment>
<comment xml:lang="cs">dokument PDF (komprimace lzip)</comment>
<comment xml:lang="ca">document PDF (amb compressió lzip)</comment>
<comment xml:lang="bg">Документ — PDF, компресиран с Lzip</comment>
+ <comment xml:lang="be">дакумент PDF (сцісканне lzip)</comment>
<comment xml:lang="ast">Documentu PDF (comprimíu en lzip)</comment>
<comment xml:lang="ar">مستند PDF (مضغوط-lzip)</comment>
<comment xml:lang="af">PDF-dokument (lzip-saamgepers)</comment>
@@ -15850,8 +16461,9 @@ command to generate the output files.
<comment xml:lang="tr">LZMA arşivi</comment>
<comment xml:lang="sv">LZMA-arkiv</comment>
<comment xml:lang="sr">ЛЗМА архива</comment>
- <comment xml:lang="sq">Arkiv LZMA</comment>
+ <comment xml:lang="sq">arkiv LZMA</comment>
<comment xml:lang="sl">Datoteka arhiva LZMA</comment>
+ <comment xml:lang="si">LZMA ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív LZMA</comment>
<comment xml:lang="ru">Архив LZMA</comment>
<comment xml:lang="ro">Arhivă LZMA</comment>
@@ -15868,6 +16480,7 @@ command to generate the output files.
<comment xml:lang="kk">LZMA архиві</comment>
<comment xml:lang="ja">LZMA アーカイブ</comment>
<comment xml:lang="it">Archivio LZMA</comment>
+ <comment xml:lang="is">LZMA safnskrá</comment>
<comment xml:lang="id">Arsip LZMA</comment>
<comment xml:lang="ia">Archivo LZMA</comment>
<comment xml:lang="hu">LZMA-archívum</comment>
@@ -15890,6 +16503,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu LZMA</comment>
<comment xml:lang="bg">Архив — LZMA</comment>
<comment xml:lang="be@latin">Archiŭ LZMA</comment>
+ <comment xml:lang="be">архіў LZMA</comment>
<comment xml:lang="ar">أرشيف LZMA</comment>
<comment xml:lang="af">LZMA-argief</comment>
<acronym>LZMA</acronym>
@@ -15906,8 +16520,9 @@ command to generate the output files.
<comment xml:lang="tr">Tar arşivi (LZMA ile sıkıştırılmış)</comment>
<comment xml:lang="sv">Tar-arkiv (LZMA-komprimerat)</comment>
<comment xml:lang="sr">Тар архива (запакована ЛЗМА-ом)</comment>
- <comment xml:lang="sq">Arkiv tar (i kompresuar me LZMA)</comment>
+ <comment xml:lang="sq">arkiv Tar (ngjeshur me LZMA)</comment>
<comment xml:lang="sl">Datoteka arhiva Tar (stisnjen z LZMA)</comment>
+ <comment xml:lang="si">තාර සංරක්ෂිතය (LZMA-සම්පීඩිත)</comment>
<comment xml:lang="sk">Archív Tar (komprimovaný pomocou LZMA)</comment>
<comment xml:lang="ru">Архив TAR (сжатый lzma)</comment>
<comment xml:lang="ro">Arhivă Tar (comprimată LZMA)</comment>
@@ -15916,7 +16531,7 @@ command to generate the output files.
<comment xml:lang="pl">Archiwum tar (kompresja LZMA)</comment>
<comment xml:lang="oc">archiu tar (compression LZMA)</comment>
<comment xml:lang="nn">Tar-arkiv (pakka med LZMA)</comment>
- <comment xml:lang="nl">Tar-archief (ingepakt met LZMA)</comment>
+ <comment xml:lang="nl">Tar-archief (gecomprimeerd met LZMA)</comment>
<comment xml:lang="nb">Tar-arkiv (LZMA-komprimert)</comment>
<comment xml:lang="lv">Tar arhīvs (saspiests ar LZMA)</comment>
<comment xml:lang="lt">Tar archyvas (suglaudintas su LZMA)</comment>
@@ -15924,6 +16539,7 @@ command to generate the output files.
<comment xml:lang="kk">Tar архиві (LZMA-мен сығылған)</comment>
<comment xml:lang="ja">Tar アーカイブ (LZMA 圧縮)</comment>
<comment xml:lang="it">Archivio tar (compresso con LZMA)</comment>
+ <comment xml:lang="is">Tar safnskrá (LZMA-þjappað)</comment>
<comment xml:lang="id">Arsip Tar (terkompresi LZMA)</comment>
<comment xml:lang="ia">Archivo Tar (comprimite con LZMA)</comment>
<comment xml:lang="hu">Tar archívum (LZMA tömörítésű)</comment>
@@ -15936,7 +16552,7 @@ command to generate the output files.
<comment xml:lang="fo">Tar skjalasavn (LZMA-stappað)</comment>
<comment xml:lang="fi">Tar-arkisto (LZMA-pakattu)</comment>
<comment xml:lang="eu">Tar artxiboa (LZMA-rekin konprimitua)</comment>
- <comment xml:lang="es">archivador Tar (comprimido con LZMA)</comment>
+ <comment xml:lang="es">archivador TAR (comprimido con LZMA)</comment>
<comment xml:lang="en_GB">Tar archive (LZMA-compressed)</comment>
<comment xml:lang="el">Αρχείο Tar (συμπιεσμένο με LZMA)</comment>
<comment xml:lang="de">Tar-Archiv (LZMA-komprimiert)</comment>
@@ -15945,6 +16561,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu tar (amb compressió LZMA)</comment>
<comment xml:lang="bg">Архив — tar, компресиран с LZMA</comment>
<comment xml:lang="be@latin">Archiŭ tar (LZMA-skampresavany)</comment>
+ <comment xml:lang="be">архіў tar (сцісканне LZMA)</comment>
<comment xml:lang="ar">أرشيف Tar (مضغوط-LZMA)</comment>
<comment xml:lang="af">Tar-argief (LZMA-saamgepers)</comment>
<sub-class-of type="application/x-lzma"/>
@@ -15961,8 +16578,9 @@ command to generate the output files.
<comment xml:lang="tr">LZO arşivi</comment>
<comment xml:lang="sv">LZO-arkiv</comment>
<comment xml:lang="sr">ЛЗО архива</comment>
- <comment xml:lang="sq">Arkiv LZO</comment>
+ <comment xml:lang="sq">arkiv LZO</comment>
<comment xml:lang="sl">Datoteka arhiva LZO</comment>
+ <comment xml:lang="si">LZO ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív LZO</comment>
<comment xml:lang="ru">Архив LZO</comment>
<comment xml:lang="ro">Arhivă LZO</comment>
@@ -15980,6 +16598,7 @@ command to generate the output files.
<comment xml:lang="kk">LZO архиві</comment>
<comment xml:lang="ja">LZO アーカイブ</comment>
<comment xml:lang="it">Archivio LZO</comment>
+ <comment xml:lang="is">LZO safnskrá</comment>
<comment xml:lang="id">Arsip LZO</comment>
<comment xml:lang="ia">Archivo LZO</comment>
<comment xml:lang="hu">LZO-archívum</comment>
@@ -16002,6 +16621,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu LZO</comment>
<comment xml:lang="bg">Архив — LZO</comment>
<comment xml:lang="be@latin">Archiŭ LZO</comment>
+ <comment xml:lang="be">архіў LZO</comment>
<comment xml:lang="ar">أرشيف LZO</comment>
<comment xml:lang="af">LZO-argief</comment>
<acronym>LZO</acronym>
@@ -16020,17 +16640,21 @@ command to generate the output files.
<comment xml:lang="tr">Qpress arşivi</comment>
<comment xml:lang="sv">Qpress-arkiv</comment>
<comment xml:lang="sr">Купрес архива</comment>
+ <comment xml:lang="sq">arkiv Qpress</comment>
<comment xml:lang="sl">Datoteka arhiva Qpress</comment>
+ <comment xml:lang="si">Qpress සංරක්ෂිතය</comment>
<comment xml:lang="sk">Archív Qpress</comment>
<comment xml:lang="ru">Архив Qpress</comment>
<comment xml:lang="pt_BR">Pacote Qpress</comment>
<comment xml:lang="pt">arquivo Qpress</comment>
<comment xml:lang="pl">Archiwum Qpress</comment>
<comment xml:lang="oc">Archiu Qpress</comment>
+ <comment xml:lang="nl">Qpress-archief</comment>
<comment xml:lang="ko">Qpress 압축 파일</comment>
<comment xml:lang="kk">Qpress архиві</comment>
<comment xml:lang="ja">Qpress アーカイブ</comment>
<comment xml:lang="it">Archivio Qpress</comment>
+ <comment xml:lang="is">Qpress safnskrá</comment>
<comment xml:lang="id">Arsip Qpress</comment>
<comment xml:lang="ia">Archivo Qpress</comment>
<comment xml:lang="hu">Qpress archívum</comment>
@@ -16050,6 +16674,7 @@ command to generate the output files.
<comment xml:lang="cs">archiv Qpress</comment>
<comment xml:lang="ca">arxiu Qpress</comment>
<comment xml:lang="bg">Архив — Qpress</comment>
+ <comment xml:lang="be">архіў Qpress</comment>
<comment xml:lang="ar">أرشيف Qpress</comment>
<comment xml:lang="af">Qpress-argief</comment>
<generic-icon name="package-x-generic"/>
@@ -16066,19 +16691,25 @@ command to generate the output files.
<comment xml:lang="tr">XAR arşivi</comment>
<comment xml:lang="sv">XAR-arkiv</comment>
<comment xml:lang="sr">ИксАР архива</comment>
+ <comment xml:lang="sq">arkvi XAR</comment>
+ <comment xml:lang="sl">Arhiv XAR</comment>
+ <comment xml:lang="si">XAR ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív XAR</comment>
<comment xml:lang="ru">Архив XAR</comment>
<comment xml:lang="pt_BR">Arquivo XAR</comment>
<comment xml:lang="pl">Archiwum XAR</comment>
<comment xml:lang="oc">Archiu XAR</comment>
+ <comment xml:lang="nl">XAR-archief</comment>
<comment xml:lang="ko">XAR 압축 파일</comment>
<comment xml:lang="kk">XAR архиві</comment>
<comment xml:lang="ja">XAR アーカイブ</comment>
<comment xml:lang="it">Archivio XAR</comment>
+ <comment xml:lang="is">XAR safnskrá</comment>
<comment xml:lang="id">Arsip XAR</comment>
<comment xml:lang="hu">XAR archívum</comment>
<comment xml:lang="hr">XAR arhiva</comment>
<comment xml:lang="he">ארכיון XAR</comment>
+ <comment xml:lang="gl">Arquivo XAR</comment>
<comment xml:lang="ga">cartlann XAR</comment>
<comment xml:lang="fur">archivi XAR</comment>
<comment xml:lang="fr">archive XAR</comment>
@@ -16091,6 +16722,7 @@ command to generate the output files.
<comment xml:lang="cs">archiv XAR</comment>
<comment xml:lang="ca">arxiu XAR</comment>
<comment xml:lang="bg">Архив — XAR</comment>
+ <comment xml:lang="be">архіў XAR</comment>
<comment xml:lang="ar">أرشيف XAR</comment>
<comment xml:lang="af">XAR-argief</comment>
<acronym>XAR</acronym>
@@ -16111,17 +16743,21 @@ command to generate the output files.
<comment xml:lang="tr">Zlib arşivi</comment>
<comment xml:lang="sv">Zlib-arkiv</comment>
<comment xml:lang="sr">Злиб архива</comment>
+ <comment xml:lang="sq">arkiv Zlib</comment>
<comment xml:lang="sl">Datoteka arhiva Zlib</comment>
+ <comment xml:lang="si">Zlib ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív Zlib</comment>
<comment xml:lang="ru">Архив Zlib</comment>
<comment xml:lang="pt_BR">Pacote Zlib</comment>
<comment xml:lang="pt">arquivo Zlib</comment>
<comment xml:lang="pl">Archiwum Zlib</comment>
<comment xml:lang="oc">Archiu Zlib</comment>
+ <comment xml:lang="nl">Zlib-archief</comment>
<comment xml:lang="ko">Zlib 압축 파일</comment>
<comment xml:lang="kk">Zlib архиві</comment>
<comment xml:lang="ja">Zlib アーカイブ</comment>
<comment xml:lang="it">Archivio zlib</comment>
+ <comment xml:lang="is">Zlib safnskrá</comment>
<comment xml:lang="id">Arsip Zlib</comment>
<comment xml:lang="ia">Archivo Zlib</comment>
<comment xml:lang="hu">Zlib archívum</comment>
@@ -16141,6 +16777,7 @@ command to generate the output files.
<comment xml:lang="cs">archiv Zlib</comment>
<comment xml:lang="ca">arxiu Zlib</comment>
<comment xml:lang="bg">Архив — Zlib</comment>
+ <comment xml:lang="be">архіў Zlib</comment>
<comment xml:lang="ar">أرشيف Zlib</comment>
<comment xml:lang="af">Zlib-argief</comment>
<generic-icon name="package-x-generic"/>
@@ -16155,8 +16792,9 @@ command to generate the output files.
<comment xml:lang="tr">MagicPoint sunumu</comment>
<comment xml:lang="sv">MagicPoint-presentation</comment>
<comment xml:lang="sr">презентација Меџик Поинта</comment>
- <comment xml:lang="sq">Prezantim MagicPoint</comment>
+ <comment xml:lang="sq">paraqitje MagicPoint</comment>
<comment xml:lang="sl">Predstavitev MagicPoint</comment>
+ <comment xml:lang="si">MagicPoint ඉදිරිපත් කිරීම</comment>
<comment xml:lang="sk">Prezentácia MagicPoint</comment>
<comment xml:lang="ru">Презентация MagicPoint</comment>
<comment xml:lang="ro">Prezentare MagicPoint</comment>
@@ -16175,6 +16813,7 @@ command to generate the output files.
<comment xml:lang="ka">MagicPoint-ის პრეზენტაცია</comment>
<comment xml:lang="ja">MagicPoint プレゼンテーション</comment>
<comment xml:lang="it">Presentazione MagicPoint</comment>
+ <comment xml:lang="is">MagicPoint framsetning</comment>
<comment xml:lang="id">Presentasi MagicPoint</comment>
<comment xml:lang="ia">Presentation MagicPoint</comment>
<comment xml:lang="hu">MagicPoint-bemutató</comment>
@@ -16198,6 +16837,7 @@ command to generate the output files.
<comment xml:lang="ca">presentació de MagicPoint</comment>
<comment xml:lang="bg">Презентация — MagicPoint</comment>
<comment xml:lang="be@latin">Prezentacyja MagicPoint</comment>
+ <comment xml:lang="be">прэзентацыя MagicPoint</comment>
<comment xml:lang="ar">عرض تقديمي MagicPoint</comment>
<comment xml:lang="af">MagicPoint-voorlegging</comment>
<sub-class-of type="text/plain"/>
@@ -16213,8 +16853,9 @@ command to generate the output files.
<comment xml:lang="tr">Macintosh MacBinary dosyası</comment>
<comment xml:lang="sv">Macintosh MacBinary-fil</comment>
<comment xml:lang="sr">Мекинтош Мек Бинари датотека</comment>
- <comment xml:lang="sq">File MacBinary Macintosh</comment>
+ <comment xml:lang="sq">kartelë MacBinary Macintosh</comment>
<comment xml:lang="sl">Izvedljiva dvojiška datoteka Macintosh MacBinary</comment>
+ <comment xml:lang="si">Macintosh MacBinary ගොනුව</comment>
<comment xml:lang="sk">Súbor pre Macintosh MacBinary</comment>
<comment xml:lang="ru">Файл Macintosh MacBinary</comment>
<comment xml:lang="ro">Fișier Macintosh MacBinary</comment>
@@ -16232,6 +16873,7 @@ command to generate the output files.
<comment xml:lang="kk">Macintosh MacBinary файлы</comment>
<comment xml:lang="ja">Macintosh MacBinary ファイル</comment>
<comment xml:lang="it">File Macintosh MacBinary</comment>
+ <comment xml:lang="is">Macintosh MacBinary skrá</comment>
<comment xml:lang="id">Berkas Macintosh MacBinary</comment>
<comment xml:lang="ia">File MacBinary de Macintosh</comment>
<comment xml:lang="hu">Macintosh MacBinary-fájl</comment>
@@ -16254,6 +16896,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer MacBinary de Macintosh</comment>
<comment xml:lang="bg">Файл — MacBinary</comment>
<comment xml:lang="be@latin">Fajł Macintosh MacBinary</comment>
+ <comment xml:lang="be">файл Macintosh MacBinary</comment>
<comment xml:lang="ar">ملف Macintosh MacBinary</comment>
<comment xml:lang="af">Macintosh MacBinary-lêer</comment>
<generic-icon name="package-x-generic"/>
@@ -16270,8 +16913,9 @@ command to generate the output files.
<comment xml:lang="tr">Matroska akışı</comment>
<comment xml:lang="sv">Matroska-ström</comment>
<comment xml:lang="sr">Матрошкин ток</comment>
- <comment xml:lang="sq">Stream Matroska</comment>
+ <comment xml:lang="sq">rrjedhë Matroska</comment>
<comment xml:lang="sl">Pretočni vir Matroska</comment>
+ <comment xml:lang="si">Matroska ධාරාව</comment>
<comment xml:lang="sk">Stream Matroska</comment>
<comment xml:lang="ru">Поток Matroska</comment>
<comment xml:lang="ro">Flux Matroska</comment>
@@ -16288,6 +16932,7 @@ command to generate the output files.
<comment xml:lang="ka">Matroska-ის ნაკადი</comment>
<comment xml:lang="ja">Matroska ストリーム</comment>
<comment xml:lang="it">Stream Matroska</comment>
+ <comment xml:lang="is">Matroska streymi</comment>
<comment xml:lang="id">Stream Matroska</comment>
<comment xml:lang="ia">Fluxo Matroska</comment>
<comment xml:lang="hu">Matroska adatfolyam</comment>
@@ -16309,6 +16954,7 @@ command to generate the output files.
<comment xml:lang="ca">flux Matroska</comment>
<comment xml:lang="bg">Поток — Matroska</comment>
<comment xml:lang="be@latin">Płyń Matroska</comment>
+ <comment xml:lang="be">плынь Matroska</comment>
<comment xml:lang="ar">دفق Matroska</comment>
<comment xml:lang="af">Matroska-stroom</comment>
<generic-icon name="video-x-generic"/>
@@ -16332,8 +16978,9 @@ command to generate the output files.
<comment xml:lang="tr">Matroska video</comment>
<comment xml:lang="sv">Matroska-video</comment>
<comment xml:lang="sr">Матрошкин видео</comment>
- <comment xml:lang="sq">Video Matroska</comment>
+ <comment xml:lang="sq">video Matroska</comment>
<comment xml:lang="sl">Video datoteka Matroska</comment>
+ <comment xml:lang="si">Matroska වීඩියෝව</comment>
<comment xml:lang="sk">Video Matroska</comment>
<comment xml:lang="ru">Видео Matroska</comment>
<comment xml:lang="ro">Video Matroska</comment>
@@ -16352,6 +16999,7 @@ command to generate the output files.
<comment xml:lang="ka">Matroska-ის ვიდეო</comment>
<comment xml:lang="ja">Matroska 動画</comment>
<comment xml:lang="it">Video Matroska</comment>
+ <comment xml:lang="is">Matroska myndskeið</comment>
<comment xml:lang="id">Video Matroska</comment>
<comment xml:lang="ia">Video Matroska</comment>
<comment xml:lang="hu">Matroska-videó</comment>
@@ -16374,6 +17022,7 @@ command to generate the output files.
<comment xml:lang="ca">vídeo Matroska</comment>
<comment xml:lang="bg">Видео — Matroska</comment>
<comment xml:lang="be@latin">Videa Matroska</comment>
+ <comment xml:lang="be">відэа Matroska</comment>
<comment xml:lang="ast">Videu en Matroska</comment>
<comment xml:lang="ar">فيديو Matroska</comment>
<comment xml:lang="af">Matroska-video</comment>
@@ -16388,17 +17037,21 @@ command to generate the output files.
<comment xml:lang="tr">Matroska 3B video</comment>
<comment xml:lang="sv">Matroska 3D-video</comment>
<comment xml:lang="sr">Матрошкин 3Д видео</comment>
+ <comment xml:lang="sq">video Matroska 3D</comment>
<comment xml:lang="sl">Video datoteka Matroska 3D</comment>
+ <comment xml:lang="si">Matroska 3D වීඩියෝ</comment>
<comment xml:lang="sk">3D video Matroska</comment>
<comment xml:lang="ru">Видео Matroska 3D</comment>
<comment xml:lang="pt_BR">Vídeo 3D Matroska</comment>
<comment xml:lang="pt">vídeo 3D Matroska</comment>
<comment xml:lang="pl">Plik wideo Matroska 3D</comment>
<comment xml:lang="oc">vidèo Matroska 3D</comment>
+ <comment xml:lang="nl">Matroska-3D-video</comment>
<comment xml:lang="ko">Matroska 3D 동영상</comment>
<comment xml:lang="kk">Matroska 3D видеосы</comment>
<comment xml:lang="ja">Matroska 3D ビデオ</comment>
<comment xml:lang="it">Video Matroska 3D</comment>
+ <comment xml:lang="is">Matroska 3D myndskeið</comment>
<comment xml:lang="id">Video 3D Matroska</comment>
<comment xml:lang="ia">Video 3D Matroska</comment>
<comment xml:lang="hu">Matroska 3D videó</comment>
@@ -16413,11 +17066,12 @@ command to generate the output files.
<comment xml:lang="es">vídeo Matroska en 3D</comment>
<comment xml:lang="en_GB">Matroska 3D video</comment>
<comment xml:lang="el">Βίντεο 3Δ Matroska</comment>
- <comment xml:lang="de">Matroska 3D-Video</comment>
+ <comment xml:lang="de">Matroska-3D-Video</comment>
<comment xml:lang="da">Matroska 3D-video</comment>
<comment xml:lang="cs">3D video Matroska</comment>
<comment xml:lang="ca">vídeo Matroska 3D</comment>
<comment xml:lang="bg">Видео — Matroska 3D</comment>
+ <comment xml:lang="be">відэа Matroska 3D</comment>
<comment xml:lang="ast">Videu en Matroska 3D</comment>
<comment xml:lang="ar">فيديو Matroska 3D</comment>
<comment xml:lang="af">Matroska 3D video</comment>
@@ -16433,8 +17087,9 @@ command to generate the output files.
<comment xml:lang="tr">Matroska ses</comment>
<comment xml:lang="sv">Matroska-ljud</comment>
<comment xml:lang="sr">Матрошкин звук</comment>
- <comment xml:lang="sq">Audio Matroska</comment>
+ <comment xml:lang="sq">audio Matroska</comment>
<comment xml:lang="sl">Zvočna datoteka Matroska</comment>
+ <comment xml:lang="si">Matroska ශ්රව්ය</comment>
<comment xml:lang="sk">Zvuk Matroska</comment>
<comment xml:lang="ru">Аудио Matroska</comment>
<comment xml:lang="ro">Audio Matroska</comment>
@@ -16452,6 +17107,7 @@ command to generate the output files.
<comment xml:lang="ka">Matroska-ის აუდიო</comment>
<comment xml:lang="ja">Matroska オーディオ</comment>
<comment xml:lang="it">Audio Matroska</comment>
+ <comment xml:lang="is">Matroska hljóðskrá</comment>
<comment xml:lang="id">Audio Matroska</comment>
<comment xml:lang="ia">Audio Matroska</comment>
<comment xml:lang="hu">Matroska hang</comment>
@@ -16464,7 +17120,7 @@ command to generate the output files.
<comment xml:lang="fo">Matroska ljóður</comment>
<comment xml:lang="fi">Matroska-ääni</comment>
<comment xml:lang="eu">Matroska audioa</comment>
- <comment xml:lang="es">audio Matroska</comment>
+ <comment xml:lang="es">sonido Matroska</comment>
<comment xml:lang="eo">Matroska-sondosiero</comment>
<comment xml:lang="en_GB">Matroska audio</comment>
<comment xml:lang="el">Ήχος Matroska</comment>
@@ -16474,6 +17130,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio Matroska</comment>
<comment xml:lang="bg">Аудио — Matroska</comment>
<comment xml:lang="be@latin">Aŭdyjo Matroska</comment>
+ <comment xml:lang="be">аўдыя Matroska</comment>
<comment xml:lang="ar">صوت Matroska</comment>
<comment xml:lang="af">Matroska-oudio</comment>
<glob pattern="*.mka"/>
@@ -16487,7 +17144,9 @@ command to generate the output files.
<comment xml:lang="tr">WebM video</comment>
<comment xml:lang="sv">WebM-video</comment>
<comment xml:lang="sr">ВебМ видео</comment>
+ <comment xml:lang="sq">audio WebM</comment>
<comment xml:lang="sl">Video datoteka WebM</comment>
+ <comment xml:lang="si">WebM වීඩියෝව</comment>
<comment xml:lang="sk">Video WebM</comment>
<comment xml:lang="ru">Видео WebM</comment>
<comment xml:lang="ro">Video WebM</comment>
@@ -16495,13 +17154,14 @@ command to generate the output files.
<comment xml:lang="pt">vídeo WebM</comment>
<comment xml:lang="pl">Plik wideo WebM</comment>
<comment xml:lang="oc">vidèo WebM</comment>
- <comment xml:lang="nl">WebM video</comment>
+ <comment xml:lang="nl">WebM-video</comment>
<comment xml:lang="lv">WebM video</comment>
<comment xml:lang="lt">WebM vaizdo įrašas</comment>
<comment xml:lang="ko">WebM 동영상</comment>
<comment xml:lang="kk">WebM видеосы</comment>
<comment xml:lang="ja">WebM 動画</comment>
<comment xml:lang="it">Video WebM</comment>
+ <comment xml:lang="is">WebM myndskeið</comment>
<comment xml:lang="id">Video WebM</comment>
<comment xml:lang="ia">Video WebM</comment>
<comment xml:lang="hu">WebM videó</comment>
@@ -16523,6 +17183,7 @@ command to generate the output files.
<comment xml:lang="cs">video WebM</comment>
<comment xml:lang="ca">vídeo WebM</comment>
<comment xml:lang="bg">Видео — WebM</comment>
+ <comment xml:lang="be">відэа WebM</comment>
<comment xml:lang="ast">Videu en WebM</comment>
<comment xml:lang="ar">فيديو WebM</comment>
<comment xml:lang="af">WebM-video</comment>
@@ -16546,7 +17207,9 @@ command to generate the output files.
<comment xml:lang="tr">WebM sesi</comment>
<comment xml:lang="sv">WebM-ljud</comment>
<comment xml:lang="sr">ВебМ звук</comment>
+ <comment xml:lang="sq">audio WebM</comment>
<comment xml:lang="sl">Zvočna datoteka WebM</comment>
+ <comment xml:lang="si">WebM ශ්‍රව්‍ය</comment>
<comment xml:lang="sk">Zvuk WebM</comment>
<comment xml:lang="ru">Аудио WebM</comment>
<comment xml:lang="ro">Audio WebM</comment>
@@ -16554,13 +17217,14 @@ command to generate the output files.
<comment xml:lang="pt">áudio WebM</comment>
<comment xml:lang="pl">Plik dźwiękowy WebM</comment>
<comment xml:lang="oc">àudio WebM</comment>
- <comment xml:lang="nl">WebM audio</comment>
+ <comment xml:lang="nl">WebM-audio</comment>
<comment xml:lang="lv">WebM audio</comment>
<comment xml:lang="lt">WebM garso įrašas</comment>
<comment xml:lang="ko">WebM 오디오</comment>
<comment xml:lang="kk">WebM аудиосы</comment>
<comment xml:lang="ja">WebM オーディオ</comment>
<comment xml:lang="it">Audio WebM</comment>
+ <comment xml:lang="is">WebM hljóðskrá</comment>
<comment xml:lang="id">Audio WebM</comment>
<comment xml:lang="ia">Audio WebM</comment>
<comment xml:lang="hu">WebM hang</comment>
@@ -16573,7 +17237,7 @@ command to generate the output files.
<comment xml:lang="fo">WebM ljóður</comment>
<comment xml:lang="fi">WebM-ääni</comment>
<comment xml:lang="eu">WebM audioa</comment>
- <comment xml:lang="es">audio WebM</comment>
+ <comment xml:lang="es">sonido WebM</comment>
<comment xml:lang="eo">WebM-sondosiero</comment>
<comment xml:lang="en_GB">WebM audio</comment>
<comment xml:lang="el">Ήχος WebM</comment>
@@ -16582,6 +17246,7 @@ command to generate the output files.
<comment xml:lang="cs">zvuk WebM</comment>
<comment xml:lang="ca">àudio WebM</comment>
<comment xml:lang="bg">Аудио — WebM</comment>
+ <comment xml:lang="be">аўдыя WebM</comment>
<comment xml:lang="ar">صوت WebM</comment>
<comment xml:lang="af">WebM-oudio</comment>
<sub-class-of type="video/webm"/>
@@ -16594,18 +17259,22 @@ command to generate the output files.
<comment xml:lang="tr">MHTML web arşivi</comment>
<comment xml:lang="sv">MHTML-webbarkiv</comment>
<comment xml:lang="sr">МХТМЛ веб архива</comment>
+ <comment xml:lang="sq">arkiv web MHTML</comment>
<comment xml:lang="sl">Spletni arhiv MHTML</comment>
+ <comment xml:lang="si">MHTML වෙබ් සංරක්ෂිතය</comment>
<comment xml:lang="sk">Webový archív MHTML</comment>
<comment xml:lang="ru">Веб-архив MHTML</comment>
<comment xml:lang="pt_BR">Pacote web MHTML</comment>
<comment xml:lang="pt">arquivo web MHTML</comment>
<comment xml:lang="pl">Archiwum witryny MHTML</comment>
<comment xml:lang="oc">archiu web MHTML</comment>
+ <comment xml:lang="nl">MHTML-webarchief</comment>
<comment xml:lang="lv">MHTML tīmekļa arhīvs</comment>
<comment xml:lang="ko">MHTML 웹 보관 파일</comment>
<comment xml:lang="kk">MHTML веб архиві</comment>
<comment xml:lang="ja">MHTML Web アーカイブ</comment>
<comment xml:lang="it">Archivio web MHTML</comment>
+ <comment xml:lang="is">MHTML vefsafnskrá</comment>
<comment xml:lang="id">Arsip web MHTML</comment>
<comment xml:lang="ia">Archivo web MHTML</comment>
<comment xml:lang="hu">MHTML webarchívum</comment>
@@ -16625,6 +17294,7 @@ command to generate the output files.
<comment xml:lang="cs">webový archiv MHTML</comment>
<comment xml:lang="ca">arxiu web MHTML</comment>
<comment xml:lang="bg">Архив — MHTML</comment>
+ <comment xml:lang="be">вэб-архіў MHTML</comment>
<comment xml:lang="ar">أرشيف ويب MHTML</comment>
<comment xml:lang="af">MHTML-webargief</comment>
<acronym>MHTML</acronym>
@@ -16641,7 +17311,9 @@ command to generate the output files.
<comment xml:lang="tr">MXF video</comment>
<comment xml:lang="sv">MXF-video</comment>
<comment xml:lang="sr">МИксФ видео</comment>
+ <comment xml:lang="sq">video MXF</comment>
<comment xml:lang="sl">Video datoteka MXF</comment>
+ <comment xml:lang="si">MXF වීඩියෝව</comment>
<comment xml:lang="sk">Video MXF</comment>
<comment xml:lang="ru">Видео MXF</comment>
<comment xml:lang="ro">Video MXF</comment>
@@ -16649,7 +17321,7 @@ command to generate the output files.
<comment xml:lang="pt">vídeo MXF</comment>
<comment xml:lang="pl">Plik wideo MXF</comment>
<comment xml:lang="oc">vidèo MXF</comment>
- <comment xml:lang="nl">MXF video</comment>
+ <comment xml:lang="nl">MXF-video</comment>
<comment xml:lang="lv">MXF video</comment>
<comment xml:lang="lt">MXF vaizdo įrašas</comment>
<comment xml:lang="ko">MXF 동영상</comment>
@@ -16657,6 +17329,7 @@ command to generate the output files.
<comment xml:lang="ka">MXF ვიდეო</comment>
<comment xml:lang="ja">MXF 動画</comment>
<comment xml:lang="it">Video MXF</comment>
+ <comment xml:lang="is">MXF myndskeið</comment>
<comment xml:lang="id">Video MXF</comment>
<comment xml:lang="ia">Video MXF</comment>
<comment xml:lang="hu">MXF videó</comment>
@@ -16678,6 +17351,7 @@ command to generate the output files.
<comment xml:lang="cs">video MXF</comment>
<comment xml:lang="ca">vídeo MXF</comment>
<comment xml:lang="bg">Видео — MXF</comment>
+ <comment xml:lang="be">відэа MXF</comment>
<comment xml:lang="ast">Videu en MXF</comment>
<comment xml:lang="ar">فيديو MXF</comment>
<comment xml:lang="af">MXF-video</comment>
@@ -16698,8 +17372,9 @@ command to generate the output files.
<comment xml:lang="tr">OCL dosyası</comment>
<comment xml:lang="sv">OCL-fil</comment>
<comment xml:lang="sr">ОЦЛ датотека</comment>
- <comment xml:lang="sq">File OCL</comment>
+ <comment xml:lang="sq">kartelë OCL</comment>
<comment xml:lang="sl">Datoteka OCL</comment>
+ <comment xml:lang="si">OCL ගොනුව</comment>
<comment xml:lang="sk">Súbor OCL</comment>
<comment xml:lang="ru">Файл OCL</comment>
<comment xml:lang="ro">Fișier OCL</comment>
@@ -16716,6 +17391,7 @@ command to generate the output files.
<comment xml:lang="kk">OCL файлы</comment>
<comment xml:lang="ja">OCL ファイル</comment>
<comment xml:lang="it">File OCL</comment>
+ <comment xml:lang="is">OCL skrá</comment>
<comment xml:lang="id">Berkas OCL</comment>
<comment xml:lang="ia">File OCL</comment>
<comment xml:lang="hu">OCL fájl</comment>
@@ -16738,6 +17414,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer OCL</comment>
<comment xml:lang="bg">Файл — OCL</comment>
<comment xml:lang="be@latin">Fajł OCL</comment>
+ <comment xml:lang="be">файл OCL</comment>
<comment xml:lang="ar">ملف OCL</comment>
<comment xml:lang="af">OCL-lêer</comment>
<acronym>OCL</acronym>
@@ -16749,22 +17426,28 @@ command to generate the output files.
<comment>COBOL source code</comment>
<comment xml:lang="zh_TW">COBOL 原始碼</comment>
<comment xml:lang="zh_CN">COBOL 源代码</comment>
- <comment xml:lang="uk">вихідний код мовою COBOL</comment>
+ <comment xml:lang="uk">початковий код мовою COBOL</comment>
<comment xml:lang="tr">COBOL kaynak kodu</comment>
<comment xml:lang="sv">COBOL-källkod</comment>
+ <comment xml:lang="sq">kod burim COBOL</comment>
+ <comment xml:lang="sl">Izvorna koda COBOL</comment>
+ <comment xml:lang="si">COBOL මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód COBOL</comment>
<comment xml:lang="ru">Исходный код COBOL</comment>
<comment xml:lang="pt_BR">Código-fonte COBOL</comment>
<comment xml:lang="pl">Kod źródłowy COBOL</comment>
<comment xml:lang="oc">còdi font COBOL</comment>
+ <comment xml:lang="nl">COBOL-broncode</comment>
<comment xml:lang="ko">코볼 소스 코드</comment>
<comment xml:lang="kk">COBOL бастапқы коды</comment>
<comment xml:lang="ja">COBOL ソースコード</comment>
<comment xml:lang="it">Codice sorgente COBOL</comment>
+ <comment xml:lang="is">COBOL frumkóði</comment>
<comment xml:lang="id">Kode sumber COBOL</comment>
<comment xml:lang="hu">COBOL forráskód</comment>
<comment xml:lang="hr">COBOL izvorni kôd</comment>
<comment xml:lang="he">קוד מקור COBOL</comment>
+ <comment xml:lang="gl">Código fonte en COBOL</comment>
<comment xml:lang="fr">code source COBOL</comment>
<comment xml:lang="fi">COBOL-lähdekoodi</comment>
<comment xml:lang="eu">COBOL iturburu-kodea</comment>
@@ -16774,6 +17457,7 @@ command to generate the output files.
<comment xml:lang="da">COBOL-kildekode</comment>
<comment xml:lang="ca">codi font en COBOL</comment>
<comment xml:lang="bg">Изходен код — COBOL</comment>
+ <comment xml:lang="be">зыходны код COBOL</comment>
<comment xml:lang="ar">شيفرة مصدر كوبول</comment>
<acronym>COBOL</acronym>
<expanded-acronym>COmmon Business Oriented Language</expanded-acronym>
@@ -16789,7 +17473,9 @@ command to generate the output files.
<comment xml:lang="tr">Mobipocket e-kitap</comment>
<comment xml:lang="sv">Mobipocket-e-bok</comment>
<comment xml:lang="sr">Мобипокет ел. књига</comment>
+ <comment xml:lang="sq">e-libër Mobipocket</comment>
<comment xml:lang="sl">e-knjiga Mobipocket</comment>
+ <comment xml:lang="si">මොබිපොකට් ඊ-පොත</comment>
<comment xml:lang="sk">E-kniha Mobipocket</comment>
<comment xml:lang="ru">Электронная книга Mobipocket</comment>
<comment xml:lang="pt_BR">E-book Mobipocket</comment>
@@ -16803,6 +17489,7 @@ command to generate the output files.
<comment xml:lang="ka">Mobipocket-ის ელწიგნი</comment>
<comment xml:lang="ja">Mobipocket 電子書籍</comment>
<comment xml:lang="it">E-book Mobipocket</comment>
+ <comment xml:lang="is">Mobipocket rafbók</comment>
<comment xml:lang="id">E-book Mobipocket</comment>
<comment xml:lang="ia">E-libro Mobipocket</comment>
<comment xml:lang="hu">Mobipocket e-könyv</comment>
@@ -16822,6 +17509,7 @@ command to generate the output files.
<comment xml:lang="cs">elektronická kniha Mobipocket</comment>
<comment xml:lang="ca">llibre electrònic Mobipocket </comment>
<comment xml:lang="bg">Е-книга — Mobipocket</comment>
+ <comment xml:lang="be">электронная кніга Mobipocket</comment>
<comment xml:lang="ar">كتاب إلكتروني Mobipocket</comment>
<comment xml:lang="af">Mobipocket e-boek</comment>
<sub-class-of type="application/vnd.palm"/>
@@ -16845,8 +17533,9 @@ command to generate the output files.
<comment xml:lang="tr">Adobe FrameMaker MIF belgesi</comment>
<comment xml:lang="sv">Adobe FrameMaker MIF-dokument</comment>
<comment xml:lang="sr">Адобе Фрејм Мејкер МИФ документ</comment>
- <comment xml:lang="sq">Dokument MIF Adobe FrameMaker</comment>
+ <comment xml:lang="sq">dokument MIF Adobe FrameMaker</comment>
<comment xml:lang="sl">Dokument Adobe FrameMaker MIF</comment>
+ <comment xml:lang="si">Adobe FrameMaker MIF ලේඛනය</comment>
<comment xml:lang="sk">Dokument Adobe FrameMaker MIF</comment>
<comment xml:lang="ru">Документ Adobe FrameMaker MIF</comment>
<comment xml:lang="ro">Document Adobe FrameMaker MIF</comment>
@@ -16864,6 +17553,7 @@ command to generate the output files.
<comment xml:lang="ka">Adobe FrameMaker-ის MIF დოკუმენტი</comment>
<comment xml:lang="ja">Adobe FrameMaker MIF ドキュメント</comment>
<comment xml:lang="it">Documento MIF Adobe FrameMaker</comment>
+ <comment xml:lang="is">Adobe FrameMaker MIF skjal</comment>
<comment xml:lang="id">Dokumen Adobe FrameMaker MIF</comment>
<comment xml:lang="ia">Documento MIF de Adobe FrameMaker</comment>
<comment xml:lang="hu">Adobe FrameMaker MIF-dokumentum</comment>
@@ -16886,6 +17576,7 @@ command to generate the output files.
<comment xml:lang="ca">document MIF d'Adobe FrameMaker</comment>
<comment xml:lang="bg">Документ — Adobe FrameMaker MIF</comment>
<comment xml:lang="be@latin">Dakument Adobe FrameMaker MIF</comment>
+ <comment xml:lang="be">дакумент Adobe FrameMaker MIF</comment>
<comment xml:lang="ast">Documentu MIF d'Adobe FrameMaker</comment>
<comment xml:lang="ar">مستند أدوبي FrameMaker MIF</comment>
<comment xml:lang="af">Adobe FrameMaker MIF-dokument</comment>
@@ -16900,8 +17591,9 @@ command to generate the output files.
<comment xml:lang="tr">Mozilla yer imleri</comment>
<comment xml:lang="sv">Mozilla-bokmärken</comment>
<comment xml:lang="sr">Мозилини обележивачи</comment>
- <comment xml:lang="sq">Libërshënues Mozilla</comment>
+ <comment xml:lang="sq">faqerojtës Mozilla</comment>
<comment xml:lang="sl">Datoteka zaznamkov Mozilla</comment>
+ <comment xml:lang="si">මොසිල්ලා පිටු සලකුණු</comment>
<comment xml:lang="sk">Záložky Mozilla</comment>
<comment xml:lang="ru">Закладки Mozilla</comment>
<comment xml:lang="ro">Semne de carte Mozilla</comment>
@@ -16919,6 +17611,7 @@ command to generate the output files.
<comment xml:lang="kk">Mozilla бетбелгілері</comment>
<comment xml:lang="ja">Mozilla ブックマーク</comment>
<comment xml:lang="it">Segnalibri Mozilla</comment>
+ <comment xml:lang="is">Mozilla bókamerki</comment>
<comment xml:lang="id">Bookmark Mozilla</comment>
<comment xml:lang="ia">Marcapaginas Mozilla</comment>
<comment xml:lang="hu">Mozilla-könyvjelzők</comment>
@@ -16941,6 +17634,7 @@ command to generate the output files.
<comment xml:lang="ca">llista d'adreces d'interès de Mozilla</comment>
<comment xml:lang="bg">Отметки — Mozilla</comment>
<comment xml:lang="be@latin">Zakładki Mozilla</comment>
+ <comment xml:lang="be">закладкі Mozilla</comment>
<comment xml:lang="ar">علامات موزيلا</comment>
<comment xml:lang="af">Mozilla-boekmerke</comment>
<sub-class-of type="text/html"/>
@@ -16950,64 +17644,134 @@ command to generate the output files.
</magic>
<alias type="application/x-netscape-bookmarks"/>
</mime-type>
- <mime-type type="application/x-ms-dos-executable">
- <comment>DOS/Windows executable</comment>
- <comment xml:lang="zh_TW">DOS/Windows 可執行檔</comment>
- <comment xml:lang="zh_CN">DOS/Windows 可执行文件</comment>
- <comment xml:lang="vi">Tập tin có thực hiện được DOS/Windows</comment>
- <comment xml:lang="uk">виконуваний файл DOS/Windows</comment>
- <comment xml:lang="tr">DOS/Windows çalıştırılabiliri</comment>
- <comment xml:lang="sv">Körbar DOS/Windows-fil</comment>
- <comment xml:lang="sr">ДОС/Виндоуз извршна</comment>
- <comment xml:lang="sq">I ekzekutueshëm DOS/Windows</comment>
- <comment xml:lang="sl">Izvedljiva datoteka DOS/Windows</comment>
- <comment xml:lang="sk">Spustiteľný súbor pre DOS/Windows</comment>
- <comment xml:lang="ru">Исполняемый файл DOS/Windows</comment>
- <comment xml:lang="ro">Executabil DOS/Windows</comment>
- <comment xml:lang="pt_BR">Executável do DOS/Windows</comment>
- <comment xml:lang="pt">executável DOS/Windows</comment>
- <comment xml:lang="pl">Program DOS/Windows</comment>
- <comment xml:lang="oc">executable DOS/Windows</comment>
- <comment xml:lang="nn">DOS/Windows køyrbar fil</comment>
- <comment xml:lang="nl">DOS/Windows-uitvoerbaar bestand</comment>
- <comment xml:lang="nb">Kjørbar fil for DOS/Windows</comment>
- <comment xml:lang="ms">Bolehlaksana DOS/Windows</comment>
- <comment xml:lang="lv">DOS/Windows izpildāmais</comment>
- <comment xml:lang="lt">DOS/Windows vykdomasis failas</comment>
- <comment xml:lang="ko">DOS/Windows 실행 파일</comment>
- <comment xml:lang="kk">DOS/Windows орындалатын файлы</comment>
- <comment xml:lang="ka">DOS/Windows გაშვებადი ფაილი</comment>
- <comment xml:lang="ja">DOS/Windows 実行ファイル</comment>
- <comment xml:lang="it">Eseguibile DOS/Windows</comment>
- <comment xml:lang="id">DOS/Windows dapat dieksekusi</comment>
- <comment xml:lang="ia">Executabile DOS/Windows</comment>
- <comment xml:lang="hu">DOS/Windows futtatható</comment>
- <comment xml:lang="hr">DOS/Windows izvršna datoteka</comment>
- <comment xml:lang="he">קובץ בר־הרצה של DOS/חלונות</comment>
- <comment xml:lang="gl">executábel de DOS/Windows</comment>
- <comment xml:lang="ga">comhad inrite DOS/Windows</comment>
- <comment xml:lang="fur">eseguibil DOS/Windows</comment>
- <comment xml:lang="fr">exécutable DOS/Windows</comment>
- <comment xml:lang="fo">DOS/Windows inningarfør</comment>
- <comment xml:lang="fi">DOS/Windows-ohjelma</comment>
- <comment xml:lang="eu">DOS/Windows-eko exekutagarria</comment>
- <comment xml:lang="es">ejecutable de DOS/Windows</comment>
- <comment xml:lang="eo">DOS/Windows-plenumebla</comment>
- <comment xml:lang="en_GB">DOS/Windows executable</comment>
- <comment xml:lang="el">Εκτελέσιμο DOS/Windows</comment>
- <comment xml:lang="de">DOS/Windows-Programmdatei</comment>
- <comment xml:lang="da">DOS-/Windowskørbar</comment>
- <comment xml:lang="cs">spustitelný soubor pro DOS/Windows</comment>
- <comment xml:lang="ca">executable de DOS o de Windows</comment>
- <comment xml:lang="bg">Изпълним файл — DOS/Windows</comment>
- <comment xml:lang="be@latin">Vykonvalny fajł DOS/Windows</comment>
- <comment xml:lang="ar">تنفيذي DOS/Windows</comment>
- <comment xml:lang="af">DOS/Windows-uitvoerbaar</comment>
+ <mime-type type="application/x-msdownload">
+ <comment>Windows or DOS program</comment>
+ <acronym>DOS</acronym>
+ <expanded-acronym>Disk Operating System</expanded-acronym>
+ <sub-class-of type="application/x-executable"/>
<generic-icon name="application-x-executable"/>
<magic>
<match type="string" value="MZ" offset="0"/>
</magic>
<glob pattern="*.exe"/>
+ <glob pattern="*.dll"/>
+ <glob pattern="*.cpl"/>
+ <glob pattern="*.drv"/>
+ <glob pattern="*.scr"/>
+ <alias type="application/x-ms-dos-executable"/>
+ </mime-type>
+ <mime-type type="application/x-dosexec">
+ <comment>DOS executable</comment>
+ <acronym>DOS</acronym>
+ <expanded-acronym>Disk Operating System</expanded-acronym>
+ <sub-class-of type="application/x-msdownload"/>
+ <generic-icon name="application-x-executable"/>
+ <magic priority="60">
+ <match type="string" value="MZ" offset="0">
+ <match type="little16" mask="0xffc0" value="0" offset="24"/>
+ </match>
+ </magic>
+ <glob pattern="*.exe" weight="30"/>
+ </mime-type>
+ <mime-type type="application/x-ms-ne-executable">
+ <comment>16-bit Windows program</comment>
+ <sub-class-of type="application/x-msdownload"/>
+ <generic-icon name="application-x-executable"/>
+ <magic priority="70">
+ <match type="string" value="MZ" offset="0">
+ <match type="string" value="NE" offset="64:256"/>
+ </match>
+ </magic>
+ <glob pattern="*.exe" weight="20"/>
+ <glob pattern="*.dll" weight="20"/>
+ <glob pattern="*.cpl" weight="20"/>
+ <glob pattern="*.drv" weight="20"/>
+ <glob pattern="*.scr" weight="20"/>
+ </mime-type>
+ <mime-type type="application/vnd.microsoft.portable-executable">
+ <comment>Windows or EFI program</comment>
+ <acronym>EFI</acronym>
+ <expanded-acronym>Extensible Firmware Interface</expanded-acronym>
+ <sub-class-of type="application/x-msdownload"/>
+ <generic-icon name="application-x-executable"/>
+ <magic priority="80">
+ <match type="string" value="MZ" offset="0">
+ <match type="string" value="PE\0\0" offset="64:256"/>
+ </match>
+ </magic>
+ <glob pattern="*.exe" weight="40"/>
+ <glob pattern="*.dll" weight="40"/>
+ <glob pattern="*.cpl" weight="40"/>
+ <glob pattern="*.drv" weight="40"/>
+ <glob pattern="*.scr" weight="40"/>
+ <glob pattern="*.efi"/>
+ <glob pattern="*.ocx"/>
+ <glob pattern="*.sys"/>
+ <glob pattern="*.lib"/>
+ </mime-type>
+ <mime-type type="application/x-ms-pdb">
+ <comment>Windows program database</comment>
+ <comment xml:lang="uk">база даних програм Windows</comment>
+ <comment xml:lang="sv">Windows-programdatabas</comment>
+ <comment xml:lang="ru">База данных программ Windows</comment>
+ <comment xml:lang="pl">Baza danych programów Windows</comment>
+ <comment xml:lang="eu">Windows programen datu-basea</comment>
+ <comment xml:lang="es">base de datos de programa de Windows</comment>
+ <comment xml:lang="de">Windows-Programmdatenbank</comment>
+ <magic>
+ <match type="string" value="Microsoft C/C++ MSF 7.00\r\n\x1aDS" offset="0"/>
+ <match type="string" value="Microsoft C/C++ program database 2.00\r\n\x1aJG" offset="0"/>
+ </magic>
+ <glob pattern="*.pdb"/>
+ </mime-type>
+ <mime-type type="application/x-bat">
+ <comment>DOS/Windows batch file</comment>
+ <comment xml:lang="uk">пакетний файл DOS/Windows</comment>
+ <comment xml:lang="sv">DOS/Windows-batchfil</comment>
+ <comment xml:lang="ru">Пакетный файл DOS/Windows</comment>
+ <comment xml:lang="pl">Plik wsadowy DOS/Windows</comment>
+ <comment xml:lang="ja">DOS/Windowsバッチファイル</comment>
+ <comment xml:lang="it">File batch DOS/Windows</comment>
+ <comment xml:lang="gl">Ficheiro en lote DOS/Windows</comment>
+ <comment xml:lang="eu">DOS/Windows sortakako fitxategia</comment>
+ <comment xml:lang="es">archivo por lotes de DOS/Windows</comment>
+ <comment xml:lang="de">DOS/Windows Stapelverarbeitungsdatei</comment>
+ <comment xml:lang="be">выконвальны файл DOS/Windows</comment>
+ <sub-class-of type="text/plain"/>
+ <alias type="application/bat"/>
+ <generic-icon name="text-x-script"/>
+ <glob pattern="*.bat"/>
+ </mime-type>
+ <mime-type type="application/x-powershell">
+ <comment>PowerShell script</comment>
+ <comment xml:lang="uk">скрипт PowerShell</comment>
+ <comment xml:lang="sv">PowerShell-skript</comment>
+ <comment xml:lang="ru">Сценарий PowerShell</comment>
+ <comment xml:lang="pl">Skrypt PowerShell</comment>
+ <comment xml:lang="es">secuencia de órdenes de PowerShell</comment>
+ <comment xml:lang="de">PowerShell-Skript</comment>
+ <sub-class-of type="text/plain"/>
+ <generic-icon name="text-x-script"/>
+ <magic>
+ <match type="string" value="#Requires -PSEdition Core" offset="0"/>
+ <match type="string" value="#Requires -PSEdition Desktop" offset="0"/>
+ </magic>
+ <glob pattern="*.ps1"/>
+ </mime-type>
+ <mime-type type="application/x-ms-shortcut">
+ <comment>Windows shortcut</comment>
+ <comment xml:lang="uk">ярлик Windows</comment>
+ <comment xml:lang="sv">Windows-genväg</comment>
+ <comment xml:lang="ru">Ярлык Windows</comment>
+ <comment xml:lang="pl">Skrót Windows</comment>
+ <comment xml:lang="es">acceso directo de Windows</comment>
+ <comment xml:lang="de">Windows-Verweis</comment>
+ <generic-icon name="emblem-symbolic-link"/>
+ <magic>
+ <match type="string" value="\x4c\x00\x00\x00\x01\x14\x02\x00\x00\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x46" offset="0"/>
+ </magic>
+ <glob pattern="*.lnk"/>
+ <alias type="application/x-win-lnk"/>
</mime-type>
<mime-type type="application/x-mswinurl">
<comment>Internet shortcut</comment>
@@ -17018,8 +17782,9 @@ command to generate the output files.
<comment xml:lang="tr">İnternet kısayolu</comment>
<comment xml:lang="sv">Internetgenväg</comment>
<comment xml:lang="sr">интернет пречица</comment>
- <comment xml:lang="sq">Shkurtim internet</comment>
+ <comment xml:lang="sq">shkurtore Internet</comment>
<comment xml:lang="sl">Internetna bližnjica</comment>
+ <comment xml:lang="si">අන්තර්ජාල කෙටි මග</comment>
<comment xml:lang="sk">Internetový odkaz</comment>
<comment xml:lang="ru">Интернет-ссылка</comment>
<comment xml:lang="ro">Scurtătură Internet</comment>
@@ -17036,6 +17801,7 @@ command to generate the output files.
<comment xml:lang="kk">Интернет сілтемесі</comment>
<comment xml:lang="ja">インターネットショートカット</comment>
<comment xml:lang="it">Scorciatoia Internet</comment>
+ <comment xml:lang="is">Internet-flýtileið</comment>
<comment xml:lang="id">Jalan pintas Internet</comment>
<comment xml:lang="ia">Ligamine Internet</comment>
<comment xml:lang="hu">Internetes indítóikon</comment>
@@ -17057,9 +17823,11 @@ command to generate the output files.
<comment xml:lang="ca">drecera d'Internet</comment>
<comment xml:lang="bg">Адрес в Интернет</comment>
<comment xml:lang="be@latin">Sieciŭnaja spasyłka</comment>
+ <comment xml:lang="be">ярлык інтэрнэту</comment>
<comment xml:lang="ar">اختصار إنترنت</comment>
<comment xml:lang="af">Internet-kortpad</comment>
<sub-class-of type="text/plain"/>
+ <generic-icon name="emblem-symbolic-link"/>
<magic>
<match type="string" value="InternetShortcut" offset="1"/>
<match type="string" value="DEFAULT" offset="1">
@@ -17077,8 +17845,9 @@ command to generate the output files.
<comment xml:lang="tr">WRI belgesi</comment>
<comment xml:lang="sv">WRI-dokument</comment>
<comment xml:lang="sr">ВРИ документ</comment>
- <comment xml:lang="sq">Dokument WRI</comment>
+ <comment xml:lang="sq">dokument WRI</comment>
<comment xml:lang="sl">Dokument WRI</comment>
+ <comment xml:lang="si">WRI ලේඛනය</comment>
<comment xml:lang="sk">Dokument WRI</comment>
<comment xml:lang="ru">Документ WRI</comment>
<comment xml:lang="ro">Document WRI</comment>
@@ -17095,6 +17864,7 @@ command to generate the output files.
<comment xml:lang="kk">WRI құжаты</comment>
<comment xml:lang="ja">WRI ドキュメント</comment>
<comment xml:lang="it">Documento WRI</comment>
+ <comment xml:lang="is">WRI skjal</comment>
<comment xml:lang="id">Dokumen WRI</comment>
<comment xml:lang="ia">Documento WRI</comment>
<comment xml:lang="hu">WRI dokumentum</comment>
@@ -17117,6 +17887,7 @@ command to generate the output files.
<comment xml:lang="ca">document WRI</comment>
<comment xml:lang="bg">Документ — WRI</comment>
<comment xml:lang="be@latin">Dakument WRI</comment>
+ <comment xml:lang="be">дакумент WRI</comment>
<comment xml:lang="ast">Documentu WRI</comment>
<comment xml:lang="ar">مستند WRI</comment>
<comment xml:lang="af">WRI-dokument</comment>
@@ -17134,6 +17905,7 @@ command to generate the output files.
<comment xml:lang="sr">МСИкс РОМ</comment>
<comment xml:lang="sq">ROM MSX</comment>
<comment xml:lang="sl">Bralni pomnilnik MSX</comment>
+ <comment xml:lang="si">MSX ROM</comment>
<comment xml:lang="sk">ROM pre MSX</comment>
<comment xml:lang="ru">MSX ROM</comment>
<comment xml:lang="ro">ROM MSX</comment>
@@ -17152,6 +17924,7 @@ command to generate the output files.
<comment xml:lang="ka">MSX-ის ROM</comment>
<comment xml:lang="ja">MSX ROM</comment>
<comment xml:lang="it">ROM MSX</comment>
+ <comment xml:lang="is">MSX ROM</comment>
<comment xml:lang="id">Memori baca-saja MSX</comment>
<comment xml:lang="ia">ROM pro MSX</comment>
<comment xml:lang="hu">MSX ROM</comment>
@@ -17168,13 +17941,14 @@ command to generate the output files.
<comment xml:lang="eo">MSX-NLM</comment>
<comment xml:lang="en_GB">MSX ROM</comment>
<comment xml:lang="el">MSX ROM</comment>
- <comment xml:lang="de">MSX ROM</comment>
+ <comment xml:lang="de">MSX-ROM</comment>
<comment xml:lang="da">MSX-ROM</comment>
<comment xml:lang="cy">ROM MSX</comment>
<comment xml:lang="cs">ROM pro MSX</comment>
<comment xml:lang="ca">ROM de MSX</comment>
<comment xml:lang="bg">ROM — MSX</comment>
<comment xml:lang="be@latin">MSX ROM</comment>
+ <comment xml:lang="be">MSX ROM</comment>
<comment xml:lang="ar">روم MSX</comment>
<generic-icon name="application-x-executable"/>
<glob pattern="*.msx"/>
@@ -17190,6 +17964,7 @@ command to generate the output files.
<comment xml:lang="sr">М4 макро</comment>
<comment xml:lang="sq">Macro M4</comment>
<comment xml:lang="sl">Makro datoteka M4</comment>
+ <comment xml:lang="si">M4 මැක්රෝ</comment>
<comment xml:lang="sk">Makro M4</comment>
<comment xml:lang="ru">Макрос M4</comment>
<comment xml:lang="ro">Macro M4</comment>
@@ -17206,6 +17981,7 @@ command to generate the output files.
<comment xml:lang="kk">M4 макросы</comment>
<comment xml:lang="ja">M4 マクロ</comment>
<comment xml:lang="it">Macro M4</comment>
+ <comment xml:lang="is">M4 fjölvi</comment>
<comment xml:lang="id">Makro M4</comment>
<comment xml:lang="ia">Macro M4</comment>
<comment xml:lang="hu">M4 makró</comment>
@@ -17227,6 +18003,7 @@ command to generate the output files.
<comment xml:lang="ca">macro M4</comment>
<comment xml:lang="bg">Макроси — M4</comment>
<comment xml:lang="be@latin">Makras M4</comment>
+ <comment xml:lang="be">макрас M4</comment>
<comment xml:lang="ar">ماكرو M4</comment>
<comment xml:lang="af">M4-makro</comment>
<sub-class-of type="text/plain"/>
@@ -17244,6 +18021,7 @@ command to generate the output files.
<comment xml:lang="sr">Нинтендо64 РОМ</comment>
<comment xml:lang="sq">ROM Nintendo64</comment>
<comment xml:lang="sl">Bralni pomnilnik Nintendo64</comment>
+ <comment xml:lang="si">Nintendo64 ROM</comment>
<comment xml:lang="sk">ROM pre Nintendo64</comment>
<comment xml:lang="ru">Nintendo64 ROM</comment>
<comment xml:lang="ro">ROM Nintendo64</comment>
@@ -17261,6 +18039,7 @@ command to generate the output files.
<comment xml:lang="kk">Nintendo64 ROM</comment>
<comment xml:lang="ja">Nintendo64 ROM</comment>
<comment xml:lang="it">ROM Nintendo64</comment>
+ <comment xml:lang="is">Nintendo64 ROM</comment>
<comment xml:lang="id">Memori baca-saja Nintendo64</comment>
<comment xml:lang="ia">ROM pro Nintendo64</comment>
<comment xml:lang="hu">Nintendo64 ROM</comment>
@@ -17277,12 +18056,13 @@ command to generate the output files.
<comment xml:lang="eo">Nintendo64-NLM</comment>
<comment xml:lang="en_GB">Nintendo64 ROM</comment>
<comment xml:lang="el">Nintendo64 ROM</comment>
- <comment xml:lang="de">Nintendo64 ROM</comment>
+ <comment xml:lang="de">Nintendo64-ROM</comment>
<comment xml:lang="da">Nintendo64-ROM</comment>
<comment xml:lang="cs">ROM pro Nintendo64</comment>
<comment xml:lang="ca">ROM de Nintendo64</comment>
<comment xml:lang="bg">ROM — Nintendo64</comment>
<comment xml:lang="be@latin">Nintendo64 ROM</comment>
+ <comment xml:lang="be">Nintendo64 ROM</comment>
<comment xml:lang="ar">روم Nintendo64</comment>
<generic-icon name="application-x-executable"/>
<glob pattern="*.n64"/>
@@ -17306,8 +18086,9 @@ command to generate the output files.
<comment xml:lang="tr">Nautilus bağlantısı</comment>
<comment xml:lang="sv">Nautiluslänk</comment>
<comment xml:lang="sr">Наутилусова веза</comment>
- <comment xml:lang="sq">Lidhje Nautilus</comment>
+ <comment xml:lang="sq">lidhje Nautilus</comment>
<comment xml:lang="sl">Datoteka povezave Nautilus</comment>
+ <comment xml:lang="si">Nautilus සබැඳිය</comment>
<comment xml:lang="sk">Odkaz Nautilus</comment>
<comment xml:lang="ru">Ссылка Nautilus</comment>
<comment xml:lang="ro">Legătură Nautilus</comment>
@@ -17325,6 +18106,7 @@ command to generate the output files.
<comment xml:lang="kk">Nautilus сілтемесі</comment>
<comment xml:lang="ja">Nautilus リンク</comment>
<comment xml:lang="it">Collegamento Nautilus</comment>
+ <comment xml:lang="is">Nautilus tengill</comment>
<comment xml:lang="id">Taut Nautilus</comment>
<comment xml:lang="ia">Ligamine Nautilus</comment>
<comment xml:lang="hu">Nautilus-link</comment>
@@ -17348,6 +18130,7 @@ command to generate the output files.
<comment xml:lang="ca">enllaç de Nautilus</comment>
<comment xml:lang="bg">Връзка — Nautilus</comment>
<comment xml:lang="be@latin">Spasyłka Nautilus</comment>
+ <comment xml:lang="be">спасылка Nautilus</comment>
<comment xml:lang="az">Nautilus körpüsü</comment>
<comment xml:lang="ar">وصلة Nautilus</comment>
<comment xml:lang="af">Nautilus-skakel</comment>
@@ -17365,18 +18148,24 @@ command to generate the output files.
<comment xml:lang="tr">Neo-Geo Pocket ROM</comment>
<comment xml:lang="sv">Neo-Geo Pocket-rom</comment>
<comment xml:lang="sr">Нео-Гео Покет РОМ</comment>
+ <comment xml:lang="sq">ROM Neo-Geo Pocket</comment>
+ <comment xml:lang="sl">Neo-Geo Pocket ROM</comment>
+ <comment xml:lang="si">Neo-Geo Pocket ROM</comment>
<comment xml:lang="sk">ROM pre Neo-Geo Pocket</comment>
<comment xml:lang="ru">Neo-Geo Pocket ROM</comment>
<comment xml:lang="pt_BR">ROM de Neo-Geo Pocket</comment>
<comment xml:lang="pl">Plik ROM konsoli Neo-Geo Pocket</comment>
+ <comment xml:lang="nl">Neo-Geo Pocket-ROM</comment>
<comment xml:lang="ko">네오지오 포켓 롬</comment>
<comment xml:lang="kk">Neo-Geo Pocket ROM</comment>
<comment xml:lang="ja">ネオジオポケット ROM</comment>
<comment xml:lang="it">ROM Neo-Geo Pocket</comment>
+ <comment xml:lang="is">Neo-Geo Pocket ROM</comment>
<comment xml:lang="id">ROM Neo-Geo Pocket</comment>
<comment xml:lang="hu">Neo-Geo Pocket ROM</comment>
<comment xml:lang="hr">Neo-Geo Pocket ROM</comment>
<comment xml:lang="he">ROM מסוג Neo-Geo Pocket</comment>
+ <comment xml:lang="gl">ROM de Neo-Geo Pocket</comment>
<comment xml:lang="ga">ROM Neo-Geo Pocket</comment>
<comment xml:lang="fur">ROM Neo-Geo Pocket</comment>
<comment xml:lang="fr">ROM Neo-Geo Pocket</comment>
@@ -17384,11 +18173,12 @@ command to generate the output files.
<comment xml:lang="eu">Neo-Geo Pocket ROM</comment>
<comment xml:lang="es">ROM de Neo-Geo Pocket</comment>
<comment xml:lang="en_GB">Neo-Geo Pocket ROM</comment>
- <comment xml:lang="de">Neo-Geo Pocket ROM</comment>
+ <comment xml:lang="de">Neo-Geo-Pocket-ROM</comment>
<comment xml:lang="da">Neo-Geo Pocket-ROM</comment>
<comment xml:lang="cs">ROM pro Neo-Geo Pocket</comment>
<comment xml:lang="ca">ROM de Neo-Geo Pocket</comment>
<comment xml:lang="bg">ROM — Neo-Geo Pocket</comment>
+ <comment xml:lang="be">Neo-Geo Pocket ROM</comment>
<comment xml:lang="ar">روم Neo-Geo Pocket</comment>
<generic-icon name="application-x-executable"/>
<glob pattern="*.ngp"/>
@@ -17406,18 +18196,24 @@ command to generate the output files.
<comment xml:lang="uk">ППП Neo-Geo Pocket Color</comment>
<comment xml:lang="tr">Neo-Geo Pocket Color ROM</comment>
<comment xml:lang="sv">Neo-Geo Pocket Color ROM</comment>
+ <comment xml:lang="sq">ROM Neo-Geo Pocket Color</comment>
+ <comment xml:lang="sl">Neo-Geo Pocket Color ROM</comment>
+ <comment xml:lang="si">Neo-Geo Pocket Color ROM</comment>
<comment xml:lang="sk">ROM pre Neo-Geo Pocket Color</comment>
<comment xml:lang="ru">Neo-Geo Pocket Color ROM</comment>
<comment xml:lang="pt_BR">ROM de Neo-Geo Pocket Color</comment>
<comment xml:lang="pl">Plik ROM konsoli Neo-Geo Pocket Color</comment>
+ <comment xml:lang="nl">Neo-Geo Pocket Color-ROM</comment>
<comment xml:lang="ko">네오지오 포켓 컬러 롬</comment>
<comment xml:lang="kk">Neo-Geo Pocket Color ROM</comment>
<comment xml:lang="ja">ネオジオポケットカラー ROM</comment>
<comment xml:lang="it">ROM Neo-Geo Pocket Color</comment>
+ <comment xml:lang="is">Neo-Geo Pocket Color ROM</comment>
<comment xml:lang="id">ROM Neo-Geo Pocket Color</comment>
<comment xml:lang="hu">Neo-Geo Pocket Color ROM</comment>
<comment xml:lang="hr">Neo-Geo Pocket Color ROM</comment>
<comment xml:lang="he">ROM של Neo-Geo Pocket</comment>
+ <comment xml:lang="gl">ROM de Neo-Geo Pocket Color</comment>
<comment xml:lang="ga">ROM datha Neo-Geo Pocket</comment>
<comment xml:lang="fur">ROM Neo-Geo Pocket Color</comment>
<comment xml:lang="fr">ROM Neo-Geo Pocket Color</comment>
@@ -17425,11 +18221,12 @@ command to generate the output files.
<comment xml:lang="eu">Neo-Geo Pocket Color ROM</comment>
<comment xml:lang="es">ROM de Neo-Geo Pocket Color</comment>
<comment xml:lang="en_GB">Neo-Geo Pocket Colour ROM</comment>
- <comment xml:lang="de">Neo-Geo Pocket Color ROM</comment>
+ <comment xml:lang="de">Neo-Geo-Pocket-Color-ROM</comment>
<comment xml:lang="da">Neo-Geo Pocket Color-ROM</comment>
<comment xml:lang="cs">ROM pro Neo-Geo Pocket Color</comment>
<comment xml:lang="ca">ROM de Neo-Geo Pocket Color</comment>
<comment xml:lang="bg">ROM — Neo-Geo Pocket Color</comment>
+ <comment xml:lang="be">Neo-Geo Pocket Color ROM</comment>
<comment xml:lang="ar">روم Neo-Geo Pocket Color</comment>
<generic-icon name="application-x-executable"/>
<glob pattern="*.ngc"/>
@@ -17452,6 +18249,7 @@ command to generate the output files.
<comment xml:lang="sr">НЕС РОМ</comment>
<comment xml:lang="sq">ROM NES</comment>
<comment xml:lang="sl">Bralni pomnilnik NES</comment>
+ <comment xml:lang="si">NES ROM</comment>
<comment xml:lang="sk">ROM pre NES</comment>
<comment xml:lang="ru">NES ROM</comment>
<comment xml:lang="ro">ROM NES</comment>
@@ -17460,7 +18258,7 @@ command to generate the output files.
<comment xml:lang="pl">Plik ROM konsoli NES</comment>
<comment xml:lang="oc">ROM NES</comment>
<comment xml:lang="nn">NES-ROM</comment>
- <comment xml:lang="nl">Nintendo</comment>
+ <comment xml:lang="nl">Super Nintendo-ROM</comment>
<comment xml:lang="nb">NES ROM</comment>
<comment xml:lang="ms">ROM NES</comment>
<comment xml:lang="lv">NES ROM</comment>
@@ -17469,6 +18267,7 @@ command to generate the output files.
<comment xml:lang="kk">NES ROM</comment>
<comment xml:lang="ja">ファミコン ROM</comment>
<comment xml:lang="it">ROM NES</comment>
+ <comment xml:lang="is">NES ROM</comment>
<comment xml:lang="id">Memori baca-saja NES</comment>
<comment xml:lang="ia">ROM pro NES</comment>
<comment xml:lang="hu">NES ROM</comment>
@@ -17485,13 +18284,14 @@ command to generate the output files.
<comment xml:lang="eo">NES-NLM</comment>
<comment xml:lang="en_GB">NES ROM</comment>
<comment xml:lang="el">NES ROM</comment>
- <comment xml:lang="de">NES ROM</comment>
+ <comment xml:lang="de">NES-ROM</comment>
<comment xml:lang="da">NES-ROM</comment>
<comment xml:lang="cy">ROM NES</comment>
<comment xml:lang="cs">ROM pro NES</comment>
<comment xml:lang="ca">ROM de NES</comment>
<comment xml:lang="bg">ROM — NES</comment>
<comment xml:lang="be@latin">NES ROM</comment>
+ <comment xml:lang="be">NES ROM</comment>
<comment xml:lang="ar">روم NES</comment>
<generic-icon name="application-x-executable"/>
<glob pattern="*.nes"/>
@@ -17508,8 +18308,9 @@ command to generate the output files.
<comment xml:lang="tr">Unidata NetCDF belgesi</comment>
<comment xml:lang="sv">Unidata NetCDF-dokument</comment>
<comment xml:lang="sr">документ Унидата НетЦДФ-а</comment>
- <comment xml:lang="sq">Dokument Unidata NetCDF</comment>
+ <comment xml:lang="sq">dokument Unidata NetCDF</comment>
<comment xml:lang="sl">Dokument Unidata NetCDF</comment>
+ <comment xml:lang="si">Unidata NetCDF ලේඛනය</comment>
<comment xml:lang="sk">Dokument Unidata NetCDF</comment>
<comment xml:lang="ru">Документ Unidata NetCDF</comment>
<comment xml:lang="ro">Document Unidata NetCDF</comment>
@@ -17527,6 +18328,7 @@ command to generate the output files.
<comment xml:lang="kk">Unidata NetCDF құжаты</comment>
<comment xml:lang="ja">Unidata NetCDF ドキュメント</comment>
<comment xml:lang="it">Documento Unidata NetCDF</comment>
+ <comment xml:lang="is">Unidata NetCDF skjal</comment>
<comment xml:lang="id">Dokumen Unidata NetCDF</comment>
<comment xml:lang="ia">Documento Unidata NetCDF</comment>
<comment xml:lang="hu">Unidata NetCDF-dokumentum</comment>
@@ -17549,6 +18351,7 @@ command to generate the output files.
<comment xml:lang="ca">document d'Unidata NetCDF</comment>
<comment xml:lang="bg">Документ — Unidata NetCDF</comment>
<comment xml:lang="be@latin">Dakument Unidata NetCDF</comment>
+ <comment xml:lang="be">дакумент Unidata NetCDF</comment>
<comment xml:lang="ast">Documentu NetCDF d'Unidata</comment>
<comment xml:lang="ar">مستند Unidata NetCDF</comment>
<acronym>NetCDF</acronym>
@@ -17565,19 +18368,22 @@ command to generate the output files.
<comment xml:lang="tr">NewzBin usenet dizini</comment>
<comment xml:lang="sv">NewzBin-usenetindex</comment>
<comment xml:lang="sr">Њузбин попис јузнета</comment>
+ <comment xml:lang="sq">tregues usenet NewzBin</comment>
<comment xml:lang="sl">Kazalo usenet NewzBin</comment>
+ <comment xml:lang="si">NewzBin Usenet index</comment>
<comment xml:lang="sk">Index Usenetu NewzBin</comment>
<comment xml:lang="ru">Индекс usenet NewzBin</comment>
<comment xml:lang="pt_BR">Índice de usenet NewzBin</comment>
<comment xml:lang="pt">índice usenet NewzBin</comment>
<comment xml:lang="pl">Indeks grup dyskusyjnych NewzBin</comment>
<comment xml:lang="oc">indèx usenet NewzBin</comment>
- <comment xml:lang="nl">NewzBin usenet index</comment>
+ <comment xml:lang="nl">NewzBin usenet-index</comment>
<comment xml:lang="lv">NewzBin usenet rādītājs</comment>
<comment xml:lang="ko">NewzBin 유즈넷 인덱스</comment>
<comment xml:lang="kk">NewzBin usenet индексі</comment>
<comment xml:lang="ja">NewzBin Usenet インデックス</comment>
<comment xml:lang="it">Indice Usenet NewzBiz</comment>
+ <comment xml:lang="is">NewzBin usenet yfirlit</comment>
<comment xml:lang="id">Indeks usenet NewzBin</comment>
<comment xml:lang="ia">Indice de usenet NewzBin</comment>
<comment xml:lang="hu">NewzBin usenet index</comment>
@@ -17592,11 +18398,12 @@ command to generate the output files.
<comment xml:lang="es">índice NewzBin de usenet</comment>
<comment xml:lang="en_GB">NewzBin usenet index</comment>
<comment xml:lang="el">Ευρετήριο usenet NewzBin</comment>
- <comment xml:lang="de">NewzBin-Usenet-Index</comment>
+ <comment xml:lang="de">NewzBin Usenet-Index</comment>
<comment xml:lang="da">NewzBin usenet-indeks</comment>
<comment xml:lang="cs">index NewzBin diskuzních skupin Usenet</comment>
<comment xml:lang="ca">índex d'Usenet NewzBin</comment>
<comment xml:lang="bg">Индекс — Usenet, NewzBin</comment>
+ <comment xml:lang="be">індэкс usenet NewzBin</comment>
<comment xml:lang="ar">فهرس يوزنت NewzBin</comment>
<sub-class-of type="application/xml"/>
<magic priority="80">
@@ -17605,56 +18412,18 @@ command to generate the output files.
<glob pattern="*.nzb"/>
</mime-type>
<mime-type type="application/x-object">
- <comment>object code</comment>
- <comment xml:lang="zh_TW">目的碼</comment>
- <comment xml:lang="zh_CN">目标代码</comment>
- <comment xml:lang="vi">mã đối tượng</comment>
+ <comment>Object code</comment>
<comment xml:lang="uk">об'єктний код</comment>
- <comment xml:lang="tr">nesne kodu</comment>
- <comment xml:lang="sv">objektkod</comment>
- <comment xml:lang="sr">објектни ко̂д</comment>
- <comment xml:lang="sq">Kod objekti</comment>
- <comment xml:lang="sl">predmetna koda</comment>
- <comment xml:lang="sk">Objektový kód</comment>
+ <comment xml:lang="sv">Objektkod</comment>
<comment xml:lang="ru">Объектный код</comment>
- <comment xml:lang="ro">cod sursă obiect</comment>
- <comment xml:lang="pt_BR">Código-objeto</comment>
- <comment xml:lang="pt">código de objeto</comment>
<comment xml:lang="pl">Kod obiektowy</comment>
- <comment xml:lang="oc">còde objet</comment>
- <comment xml:lang="nn">objektkode</comment>
- <comment xml:lang="nl">objectcode</comment>
- <comment xml:lang="nb">objektkode</comment>
- <comment xml:lang="ms">Kod objek</comment>
- <comment xml:lang="lv">objekta kods</comment>
- <comment xml:lang="lt">objektinis kodas</comment>
- <comment xml:lang="ko">개체 코드</comment>
- <comment xml:lang="kk">объектті коды</comment>
- <comment xml:lang="ja">オブジェクトコード</comment>
+ <comment xml:lang="ja">目的符号文書</comment>
<comment xml:lang="it">Codice oggetto</comment>
- <comment xml:lang="id">kode objek</comment>
- <comment xml:lang="ia">Codice objecto</comment>
- <comment xml:lang="hu">tárgykód</comment>
- <comment xml:lang="hr">Object kôd</comment>
- <comment xml:lang="he">קוד אובייקט</comment>
- <comment xml:lang="gl">código obxecto</comment>
- <comment xml:lang="ga">cód réada</comment>
- <comment xml:lang="fur">codiç ogjet</comment>
- <comment xml:lang="fr">code objet</comment>
- <comment xml:lang="fi">objektikoodi</comment>
- <comment xml:lang="eu">objektu kodea</comment>
- <comment xml:lang="es">código objeto</comment>
- <comment xml:lang="eo">celkodo</comment>
- <comment xml:lang="en_GB">object code</comment>
- <comment xml:lang="el">Μεταφρασμένος κώδικας</comment>
+ <comment xml:lang="gl">Código obxecto</comment>
+ <comment xml:lang="eu">Objektu-kodea</comment>
+ <comment xml:lang="es">código de objeto</comment>
<comment xml:lang="de">Objektcode</comment>
- <comment xml:lang="da">objektkode</comment>
- <comment xml:lang="cs">objektový kód</comment>
- <comment xml:lang="ca">codi objecte</comment>
- <comment xml:lang="bg">Обектен код</comment>
- <comment xml:lang="be@latin">abjektny kod</comment>
- <comment xml:lang="ar">شفرة كائن</comment>
- <comment xml:lang="af">objekkode</comment>
+ <comment xml:lang="be">аб'ектны код</comment>
<generic-icon name="x-office-document"/>
<magic>
<match type="string" value="\177ELF" offset="0">
@@ -17681,6 +18450,7 @@ command to generate the output files.
<comment xml:lang="sv">Annodex-utväxlingsformat</comment>
<comment xml:lang="sr">Анодексов запис размене</comment>
<comment xml:lang="sl">Izmenjalna datoteka Annodex</comment>
+ <comment xml:lang="si">Annodex හුවමාරු ආකෘතිය</comment>
<comment xml:lang="sk">Formát pre výmenu Annodex</comment>
<comment xml:lang="ru">Формат обмена Annodex</comment>
<comment xml:lang="ro">Format schimb Annodex</comment>
@@ -17696,6 +18466,7 @@ command to generate the output files.
<comment xml:lang="ka">Annodex-ის გაცვლითი ფორმატი</comment>
<comment xml:lang="ja">Annodex 交換フォーマット</comment>
<comment xml:lang="it">Formato di scambio Annodex</comment>
+ <comment xml:lang="is">Annodex skiptiskráasnið</comment>
<comment xml:lang="id">Format pertukaran Annodex</comment>
<comment xml:lang="ia">Formato de excambio Annodex</comment>
<comment xml:lang="hu">Annodex csereformátum</comment>
@@ -17711,11 +18482,12 @@ command to generate the output files.
<comment xml:lang="es">formato de intercambio de Annodex</comment>
<comment xml:lang="en_GB">Annodex exchange format</comment>
<comment xml:lang="el">Μορφή ανταλλαγής Annodex</comment>
- <comment xml:lang="de">Annodex-Wechselformat</comment>
+ <comment xml:lang="de">Annodex-Austauschformat</comment>
<comment xml:lang="da">Udvekslingsformat for Annodex</comment>
<comment xml:lang="cs">výměnný formát Annodex</comment>
<comment xml:lang="ca">format d'intercanvi Annodex</comment>
<comment xml:lang="bg">Формат за обмяна — Annodex</comment>
+ <comment xml:lang="be">фармат абмену Annodex</comment>
<comment xml:lang="ar">صيغة تبادل Annodex</comment>
<generic-icon name="video-x-generic"/>
<magic>
@@ -17735,17 +18507,24 @@ command to generate the output files.
<comment xml:lang="uk">відео Annodex</comment>
<comment xml:lang="tr">Annodex video</comment>
<comment xml:lang="sv">Annodex-video</comment>
+ <comment xml:lang="sq">video Annodex</comment>
+ <comment xml:lang="sl">Video Annodex</comment>
+ <comment xml:lang="si">Annodex වීඩියෝව</comment>
<comment xml:lang="ru">Видео Annodex</comment>
<comment xml:lang="pt_BR">Vídeo Annodex</comment>
<comment xml:lang="pl">Plik wideo Annodex</comment>
+ <comment xml:lang="oc">vidèo Annodex</comment>
+ <comment xml:lang="nl">Annodex-video</comment>
<comment xml:lang="ko">Annodex 동영상</comment>
<comment xml:lang="kk">Annodex видеосы</comment>
<comment xml:lang="ja">Annodex 動画</comment>
<comment xml:lang="it">Video Annodex</comment>
+ <comment xml:lang="is">Annodex myndskeið</comment>
<comment xml:lang="id">Video Annodex</comment>
<comment xml:lang="hu">Annodex videó</comment>
<comment xml:lang="hr">Annodex video snimka</comment>
<comment xml:lang="he">סרטון Annodex</comment>
+ <comment xml:lang="gl">Vídeo de Annodex</comment>
<comment xml:lang="fr">vidéo Annodex</comment>
<comment xml:lang="fi">Annodex-video</comment>
<comment xml:lang="eu">Annodex bideoa</comment>
@@ -17755,6 +18534,7 @@ command to generate the output files.
<comment xml:lang="da">Annodex-video</comment>
<comment xml:lang="ca">vídeo Annodex</comment>
<comment xml:lang="bg">Видео — Annodex</comment>
+ <comment xml:lang="be">відэа Annodex</comment>
<comment xml:lang="ar">فيديو Annodex</comment>
<sub-class-of type="application/annodex"/>
<magic>
@@ -17774,26 +18554,34 @@ command to generate the output files.
<comment xml:lang="uk">звук Annodex</comment>
<comment xml:lang="tr">Annodex sesi</comment>
<comment xml:lang="sv">Annodex-ljud</comment>
+ <comment xml:lang="sq">audio Annodex</comment>
+ <comment xml:lang="sl">Zvok Annodex</comment>
+ <comment xml:lang="si">ඇනෝඩෙක්ස් ඕඩියෝ</comment>
<comment xml:lang="ru">Аудио Annodex</comment>
<comment xml:lang="pt_BR">Áudio Annodex</comment>
<comment xml:lang="pl">Plik dźwiękowy Annodex</comment>
+ <comment xml:lang="oc">àudio Annodex</comment>
+ <comment xml:lang="nl">Annodex-audio</comment>
<comment xml:lang="ko">Annodex 오디오</comment>
<comment xml:lang="kk">Annodex аудиосы</comment>
<comment xml:lang="ja">Annodex オーディオ</comment>
<comment xml:lang="it">Audio Annodex</comment>
+ <comment xml:lang="is">Annodex hljóðskrá</comment>
<comment xml:lang="id">Audio Annodex</comment>
<comment xml:lang="hu">Annodex hang</comment>
<comment xml:lang="hr">Annodex zvučni zapis</comment>
<comment xml:lang="he">שמע Annodex</comment>
+ <comment xml:lang="gl">Son de Annodex</comment>
<comment xml:lang="fr">audio Annodex</comment>
<comment xml:lang="fi">Annodex-ääni</comment>
<comment xml:lang="eu">Annodex audioa</comment>
- <comment xml:lang="es">audio Annodex</comment>
+ <comment xml:lang="es">sonido Annodex</comment>
<comment xml:lang="en_GB">Annodex audio</comment>
<comment xml:lang="de">Annodex-Audio</comment>
<comment xml:lang="da">Annodex-lyd</comment>
<comment xml:lang="ca">àudio Annodex</comment>
<comment xml:lang="bg">Аудио — Annodex</comment>
+ <comment xml:lang="be">аўдыя Annodex</comment>
<comment xml:lang="ar">صوت Annodex</comment>
<sub-class-of type="application/annodex"/>
<magic>
@@ -17815,8 +18603,9 @@ command to generate the output files.
<comment xml:lang="tr">Ogg çoklu ortam dosyası</comment>
<comment xml:lang="sv">Ogg-multimediafil</comment>
<comment xml:lang="sr">Огг мултимедијална датотека</comment>
- <comment xml:lang="sq">File multimedial Ogg</comment>
+ <comment xml:lang="sq">kartelë multimediale Ogg</comment>
<comment xml:lang="sl">Večpredstavnostna datoteka Ogg</comment>
+ <comment xml:lang="si">Ogg බහුමාධ්‍ය ගොනුව</comment>
<comment xml:lang="sk">Súbor multimédií Ogg</comment>
<comment xml:lang="ru">Мультимедийный файл Ogg</comment>
<comment xml:lang="ro">Fișier multimedia Ogg</comment>
@@ -17834,6 +18623,7 @@ command to generate the output files.
<comment xml:lang="ka">Ogg-ის მულტიმედია ფაილი</comment>
<comment xml:lang="ja">Ogg マルチメディアファイル</comment>
<comment xml:lang="it">File multimediale Ogg</comment>
+ <comment xml:lang="is">OGG margmiðlunarskrá</comment>
<comment xml:lang="id">Berkas multimedia Ogg</comment>
<comment xml:lang="ia">File multimedial Ogg</comment>
<comment xml:lang="hu">Ogg multimédiafájl</comment>
@@ -17855,6 +18645,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer multimèdia Ogg</comment>
<comment xml:lang="bg">Мултимедия — Ogg</comment>
<comment xml:lang="be@latin">Multymedyjny fajł Ogg</comment>
+ <comment xml:lang="be">мультымедыйны файл Ogg</comment>
<comment xml:lang="ar">ملف وسائط متعددة Ogg</comment>
<comment xml:lang="af">Ogg-multimedialêer</comment>
<generic-icon name="video-x-generic"/>
@@ -17872,28 +18663,35 @@ command to generate the output files.
<comment xml:lang="tr">Ogg sesi</comment>
<comment xml:lang="sv">Ogg-ljud</comment>
<comment xml:lang="sr">ОГГ аудио</comment>
+ <comment xml:lang="sq">audio Ogg</comment>
+ <comment xml:lang="sl">Zvok Ogg</comment>
+ <comment xml:lang="si">ඕග් ඕඩියෝ</comment>
<comment xml:lang="sk">Zvuk Ogg</comment>
<comment xml:lang="ru">Аудио Ogg</comment>
<comment xml:lang="pt_BR">Áudio Ogg</comment>
<comment xml:lang="pl">Plik dźwiękowy Ogg</comment>
<comment xml:lang="oc">àudio Ogg</comment>
+ <comment xml:lang="nl">Ogg-audio</comment>
<comment xml:lang="ko">Ogg 오디오</comment>
<comment xml:lang="kk">Ogg аулиосы</comment>
<comment xml:lang="ja">Ogg オーディオ</comment>
<comment xml:lang="it">Audio Ogg</comment>
+ <comment xml:lang="is">Ogg hljóðskrá</comment>
<comment xml:lang="id">Audio Ogg</comment>
<comment xml:lang="hu">Ogg hang</comment>
<comment xml:lang="hr">Ogg zvučni zapis</comment>
<comment xml:lang="he">שמע Ogg</comment>
+ <comment xml:lang="gl">Son Ogg</comment>
<comment xml:lang="fr">audio Ogg</comment>
<comment xml:lang="fi">Ogg-ääni</comment>
<comment xml:lang="eu">Ogg audioa</comment>
- <comment xml:lang="es">audio Ogg</comment>
+ <comment xml:lang="es">sonido Ogg</comment>
<comment xml:lang="en_GB">Ogg audio</comment>
<comment xml:lang="de">Ogg-Audio</comment>
<comment xml:lang="da">Ogg-lyd</comment>
<comment xml:lang="ca">àudio Ogg</comment>
<comment xml:lang="bg">Аудио — Ogg</comment>
+ <comment xml:lang="be">аўдыя Ogg</comment>
<comment xml:lang="ar">صوت Ogg</comment>
<sub-class-of type="application/ogg"/>
<magic>
@@ -17912,19 +18710,25 @@ command to generate the output files.
<comment xml:lang="tr">Ogg video</comment>
<comment xml:lang="sv">Ogg-video</comment>
<comment xml:lang="sr">ОГГ видео</comment>
+ <comment xml:lang="sq">video Ogg</comment>
+ <comment xml:lang="sl">Video Ogg</comment>
+ <comment xml:lang="si">ඔග් වීඩියෝව</comment>
<comment xml:lang="sk">Video Ogg</comment>
<comment xml:lang="ru">Видео Ogg</comment>
<comment xml:lang="pt_BR">Vídeo Ogg</comment>
<comment xml:lang="pl">Plik wideo Ogg</comment>
<comment xml:lang="oc">vidèo Ogg</comment>
+ <comment xml:lang="nl">Ogg-video</comment>
<comment xml:lang="ko">Ogg 동영상</comment>
<comment xml:lang="kk">Ogg видеосы</comment>
<comment xml:lang="ja">Ogg 動画</comment>
<comment xml:lang="it">Video Ogg</comment>
+ <comment xml:lang="is">Ogg myndskeið</comment>
<comment xml:lang="id">Video Ogg</comment>
<comment xml:lang="hu">Ogg videó</comment>
<comment xml:lang="hr">Ogg video snimka</comment>
<comment xml:lang="he">וידאו Ogg</comment>
+ <comment xml:lang="gl">Vídeo Ogg</comment>
<comment xml:lang="fr">vidéo Ogg</comment>
<comment xml:lang="fi">Ogg-video</comment>
<comment xml:lang="eu">Ogg bideoa</comment>
@@ -17934,6 +18738,7 @@ command to generate the output files.
<comment xml:lang="da">Ogg-video</comment>
<comment xml:lang="ca">vídeo Ogg</comment>
<comment xml:lang="bg">Видео — Ogg</comment>
+ <comment xml:lang="be">відэа Ogg</comment>
<comment xml:lang="ar">فيديو Ogg</comment>
<sub-class-of type="application/ogg"/>
<magic>
@@ -17952,8 +18757,9 @@ command to generate the output files.
<comment xml:lang="tr">Ogg Vorbis sesi</comment>
<comment xml:lang="sv">Ogg Vorbis-ljud</comment>
<comment xml:lang="sr">Огг Ворбис звук</comment>
- <comment xml:lang="sq">Audio Ogg Vorbis</comment>
+ <comment xml:lang="sq">audio Ogg Vorbis</comment>
<comment xml:lang="sl">Zvočna datoteka Ogg Vorbis</comment>
+ <comment xml:lang="si">Ogg Vorbis ශ්රව්ය</comment>
<comment xml:lang="sk">Zvuk Ogg Vorbis</comment>
<comment xml:lang="ru">Аудио Ogg Vorbis</comment>
<comment xml:lang="ro">Audio Ogg Vorbis</comment>
@@ -17972,6 +18778,7 @@ command to generate the output files.
<comment xml:lang="ka">Ogg Vorbis აუდიო</comment>
<comment xml:lang="ja">Ogg Vorbis オーディオ</comment>
<comment xml:lang="it">Audio Ogg Vorbis</comment>
+ <comment xml:lang="is">Ogg Vorbis hljóðskrá</comment>
<comment xml:lang="id">Audio Ogg Vorbis</comment>
<comment xml:lang="ia">Audio Ogg Vorbis</comment>
<comment xml:lang="hu">Ogg Vorbis hang</comment>
@@ -17984,7 +18791,7 @@ command to generate the output files.
<comment xml:lang="fo">Ogg Vorbis ljóður</comment>
<comment xml:lang="fi">Ogg Vorbis -ääni</comment>
<comment xml:lang="eu">Ogg Vorbis audioa</comment>
- <comment xml:lang="es">audio Ogg Vorbis</comment>
+ <comment xml:lang="es">sonido Ogg Vorbis</comment>
<comment xml:lang="eo">Ogg-Vorbis-sondosiero</comment>
<comment xml:lang="en_GB">Ogg Vorbis audio</comment>
<comment xml:lang="el">Ήχος Ogg Vobris</comment>
@@ -17995,6 +18802,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio Ogg Vorbis</comment>
<comment xml:lang="bg">Аудио — Ogg Vorbis</comment>
<comment xml:lang="be@latin">Aŭdyjo Ogg Vorbis</comment>
+ <comment xml:lang="be">аўдыя Ogg Vorbis</comment>
<comment xml:lang="az">Ogg Vorbis audio faylı</comment>
<comment xml:lang="ar">صوت Ogg Vorbis</comment>
<comment xml:lang="af">Ogg Vorbis-oudio</comment>
@@ -18018,8 +18826,9 @@ command to generate the output files.
<comment xml:lang="tr">Ogg FLAC sesi</comment>
<comment xml:lang="sv">Ogg FLAC-ljud</comment>
<comment xml:lang="sr">Огг ФЛАЦ звук</comment>
- <comment xml:lang="sq">Audio Ogg FLAC</comment>
+ <comment xml:lang="sq">audio Ogg FLAC</comment>
<comment xml:lang="sl">Zvočna datoteka Ogg FLAC</comment>
+ <comment xml:lang="si">Ogg FLAC ශ්රව්ය</comment>
<comment xml:lang="sk">Zvuk Ogg FLAC</comment>
<comment xml:lang="ru">Аудио Ogg FLAC</comment>
<comment xml:lang="ro">Audio Ogg FLAC</comment>
@@ -18037,6 +18846,7 @@ command to generate the output files.
<comment xml:lang="ka">Ogg FLAC აუდიო</comment>
<comment xml:lang="ja">Ogg FLAC オーディオ</comment>
<comment xml:lang="it">Audio Ogg FLAC</comment>
+ <comment xml:lang="is">Ogg FLAC hljóðskrá</comment>
<comment xml:lang="id">Audio Ogg FLAC</comment>
<comment xml:lang="ia">Audio Ogg FLAC</comment>
<comment xml:lang="hu">Ogg FLAC hang</comment>
@@ -18049,7 +18859,7 @@ command to generate the output files.
<comment xml:lang="fo">Ogg FLAC ljóður</comment>
<comment xml:lang="fi">Ogg FLAC -ääni</comment>
<comment xml:lang="eu">Ogg FLAC audioa</comment>
- <comment xml:lang="es">audio Ogg FLAC</comment>
+ <comment xml:lang="es">sonido Ogg FLAC</comment>
<comment xml:lang="en_GB">Ogg FLAC audio</comment>
<comment xml:lang="el">Ήχος Ogg FLAC</comment>
<comment xml:lang="de">Ogg-FLAC-Audio</comment>
@@ -18058,6 +18868,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio Ogg FLAC</comment>
<comment xml:lang="bg">Аудио — Ogg FLAC</comment>
<comment xml:lang="be@latin">Aŭdyjo Ogg FLAC</comment>
+ <comment xml:lang="be">аўдыя Ogg FLAC</comment>
<comment xml:lang="ar">صوت Ogg FLAC</comment>
<comment xml:lang="af">Ogg FLAC-oudio</comment>
<sub-class-of type="audio/ogg"/>
@@ -18081,17 +18892,21 @@ command to generate the output files.
<comment xml:lang="tr">Opus sesi</comment>
<comment xml:lang="sv">Opus-ljud</comment>
<comment xml:lang="sr">Опус звук</comment>
+ <comment xml:lang="sq">audio Opus</comment>
<comment xml:lang="sl">Zvočna datoteka Opus</comment>
+ <comment xml:lang="si">ඕපස් ඕඩියෝ</comment>
<comment xml:lang="sk">Zvuk Opu</comment>
<comment xml:lang="ru">Аудио Opus</comment>
<comment xml:lang="pt_BR">Áudio Opus</comment>
<comment xml:lang="pt">áudio Opus</comment>
<comment xml:lang="pl">Plik dźwiękowy Opus</comment>
<comment xml:lang="oc">àudio Opus</comment>
+ <comment xml:lang="nl">Opus-audio</comment>
<comment xml:lang="ko">Opus 오디오</comment>
<comment xml:lang="kk">Opus аудиосы</comment>
<comment xml:lang="ja">Opus オーディオ</comment>
<comment xml:lang="it">Audio Opus</comment>
+ <comment xml:lang="is">Opus hljóðskrá</comment>
<comment xml:lang="id">Audio Opus</comment>
<comment xml:lang="ia">Audio Opus</comment>
<comment xml:lang="hu">Opus hang</comment>
@@ -18103,7 +18918,7 @@ command to generate the output files.
<comment xml:lang="fr">audio Opus</comment>
<comment xml:lang="fi">Opus-ääni</comment>
<comment xml:lang="eu">Opus audioa</comment>
- <comment xml:lang="es">audio Opus</comment>
+ <comment xml:lang="es">sonido Opus</comment>
<comment xml:lang="en_GB">Opus audio</comment>
<comment xml:lang="el">Ήχος Opus </comment>
<comment xml:lang="de">Opus-Audio</comment>
@@ -18111,6 +18926,7 @@ command to generate the output files.
<comment xml:lang="cs">zvuk Opus</comment>
<comment xml:lang="ca">àudio Opus</comment>
<comment xml:lang="bg">Аудио — Opus</comment>
+ <comment xml:lang="be">аўдыя Opus</comment>
<comment xml:lang="ar">صوت Opus</comment>
<comment xml:lang="af">Opus-oudio</comment>
<sub-class-of type="audio/ogg"/>
@@ -18130,8 +18946,9 @@ command to generate the output files.
<comment xml:lang="tr">Ogg Speex sesi</comment>
<comment xml:lang="sv">Ogg Speex-ljud</comment>
<comment xml:lang="sr">Огг Спикс звук</comment>
- <comment xml:lang="sq">Audio Ogg Speex</comment>
+ <comment xml:lang="sq">audio Ogg Speex</comment>
<comment xml:lang="sl">Zvočna datoteka Ogg Speex</comment>
+ <comment xml:lang="si">Ogg Speex ශ්‍රව්‍ය</comment>
<comment xml:lang="sk">Zvuk Ogg Speex</comment>
<comment xml:lang="ru">Аудио Ogg Speex</comment>
<comment xml:lang="ro">Audio Ogg Speex</comment>
@@ -18149,6 +18966,7 @@ command to generate the output files.
<comment xml:lang="ka">Ogg Speex აუდიო</comment>
<comment xml:lang="ja">Ogg Speex オーディオ</comment>
<comment xml:lang="it">Audio Ogg Speex</comment>
+ <comment xml:lang="is">Ogg Speex hljóðskrá</comment>
<comment xml:lang="id">Audio Ogg Speex</comment>
<comment xml:lang="ia">Audio Ogg Speex</comment>
<comment xml:lang="hu">Ogg Speex hang</comment>
@@ -18161,7 +18979,7 @@ command to generate the output files.
<comment xml:lang="fo">Ogg Speex ljóður</comment>
<comment xml:lang="fi">Ogg Speex -ääni</comment>
<comment xml:lang="eu">Ogg Speex audioa</comment>
- <comment xml:lang="es">audio Ogg Speex</comment>
+ <comment xml:lang="es">sonido Ogg Speex</comment>
<comment xml:lang="en_GB">Ogg Speex audio</comment>
<comment xml:lang="el">Ήχος Ogg Speex</comment>
<comment xml:lang="de">Ogg-Speex-Audio</comment>
@@ -18170,6 +18988,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio Ogg Speex</comment>
<comment xml:lang="bg">Аудио — Ogg Speex</comment>
<comment xml:lang="be@latin">Aŭdyjo Ogg Speex</comment>
+ <comment xml:lang="be">аўдыя Ogg Speex</comment>
<comment xml:lang="ar">صوت Ogg Speex</comment>
<comment xml:lang="af">Ogg Speex-oudio</comment>
<sub-class-of type="audio/ogg"/>
@@ -18191,8 +19010,9 @@ command to generate the output files.
<comment xml:lang="tr">Speex sesi</comment>
<comment xml:lang="sv">Speex-ljud</comment>
<comment xml:lang="sr">Спикс звук</comment>
- <comment xml:lang="sq">Audio Speex</comment>
+ <comment xml:lang="sq">audio Speex</comment>
<comment xml:lang="sl">Zvočna datoteka Speex</comment>
+ <comment xml:lang="si">ස්පීක්ස් ඕඩියෝ</comment>
<comment xml:lang="sk">Zvuk Speex</comment>
<comment xml:lang="ru">Аудио Speex</comment>
<comment xml:lang="ro">Audio Speex</comment>
@@ -18209,6 +19029,7 @@ command to generate the output files.
<comment xml:lang="kk">Speex аудиосы</comment>
<comment xml:lang="ja">Speex オーディオ</comment>
<comment xml:lang="it">Audio Speex</comment>
+ <comment xml:lang="is">Speex hljóðskrá</comment>
<comment xml:lang="id">Audio Speex</comment>
<comment xml:lang="ia">Audio Speex</comment>
<comment xml:lang="hu">Speex hang</comment>
@@ -18221,7 +19042,7 @@ command to generate the output files.
<comment xml:lang="fo">Speex ljóður</comment>
<comment xml:lang="fi">Speex-ääni</comment>
<comment xml:lang="eu">Speex audioa</comment>
- <comment xml:lang="es">audio Speex</comment>
+ <comment xml:lang="es">sonido Speex</comment>
<comment xml:lang="en_GB">Speex audio</comment>
<comment xml:lang="el">Ήχος Speex</comment>
<comment xml:lang="de">Speex-Audio</comment>
@@ -18230,6 +19051,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio Speex</comment>
<comment xml:lang="bg">Аудио — Speex</comment>
<comment xml:lang="be@latin">Aŭdyjo Speex</comment>
+ <comment xml:lang="be">аўдыя Speex</comment>
<comment xml:lang="ar">صوت Speex</comment>
<comment xml:lang="af">Speex-oudio</comment>
<magic>
@@ -18246,8 +19068,9 @@ command to generate the output files.
<comment xml:lang="tr">Ogg Theora video</comment>
<comment xml:lang="sv">Ogg Theora-video</comment>
<comment xml:lang="sr">Огг Теора видео</comment>
- <comment xml:lang="sq">Video Ogg Theora</comment>
+ <comment xml:lang="sq">video Ogg Theora</comment>
<comment xml:lang="sl">Video datoteka Ogg Theora</comment>
+ <comment xml:lang="si">Ogg Theora වීඩියෝව</comment>
<comment xml:lang="sk">Video Ogg Theora</comment>
<comment xml:lang="ru">Видео Ogg Theora</comment>
<comment xml:lang="ro">Video Ogg Theora</comment>
@@ -18265,6 +19088,7 @@ command to generate the output files.
<comment xml:lang="ka">Ogg Theora ვიდეო</comment>
<comment xml:lang="ja">Ogg Theora 動画</comment>
<comment xml:lang="it">Video Ogg Theora</comment>
+ <comment xml:lang="is">Ogg Theora myndskeið</comment>
<comment xml:lang="id">Video Ogg Theora</comment>
<comment xml:lang="ia">Video Ogg Theora</comment>
<comment xml:lang="hu">Ogg Theora videó</comment>
@@ -18286,6 +19110,7 @@ command to generate the output files.
<comment xml:lang="ca">vídeo Ogg Theora</comment>
<comment xml:lang="bg">Видео — Ogg Theora</comment>
<comment xml:lang="be@latin">Videa Ogg Theora</comment>
+ <comment xml:lang="be">відэа Ogg Theora</comment>
<comment xml:lang="ast">Videu n'Ogg Theora</comment>
<comment xml:lang="ar">فيديو Ogg Theora</comment>
<comment xml:lang="af">Ogg Theora-video</comment>
@@ -18307,8 +19132,9 @@ command to generate the output files.
<comment xml:lang="tr">OGM video</comment>
<comment xml:lang="sv">OGM-video</comment>
<comment xml:lang="sr">ОГМ видео</comment>
- <comment xml:lang="sq">Video OGM</comment>
+ <comment xml:lang="sq">video OGM</comment>
<comment xml:lang="sl">Video datoteka OGM</comment>
+ <comment xml:lang="si">OGM වීඩියෝව</comment>
<comment xml:lang="sk">Video OGM</comment>
<comment xml:lang="ru">Видео OGM</comment>
<comment xml:lang="ro">Video OGM</comment>
@@ -18326,6 +19152,7 @@ command to generate the output files.
<comment xml:lang="ka">OGM ვიდეო</comment>
<comment xml:lang="ja">OGM 動画</comment>
<comment xml:lang="it">Video OGM</comment>
+ <comment xml:lang="is">OGM myndskeið</comment>
<comment xml:lang="id">Video OGM</comment>
<comment xml:lang="ia">Video OGM</comment>
<comment xml:lang="hu">OGM-videó</comment>
@@ -18348,6 +19175,7 @@ command to generate the output files.
<comment xml:lang="ca">vídeo OGM</comment>
<comment xml:lang="bg">Видео — OGM</comment>
<comment xml:lang="be@latin">Videa OGM</comment>
+ <comment xml:lang="be">відэа OGM</comment>
<comment xml:lang="ast">Videu n'OGM</comment>
<comment xml:lang="ar">فيديو OGM</comment>
<comment xml:lang="af">OGM-video</comment>
@@ -18371,8 +19199,9 @@ command to generate the output files.
<comment xml:lang="tr">OLE2 bileşik belge depolama</comment>
<comment xml:lang="sv">Sammansatt OLE2-dokumentlager</comment>
<comment xml:lang="sr">смештај ОЛЕ2 сједињеног документа</comment>
- <comment xml:lang="sq">Arkiv dokumenti i përbërë OLE2</comment>
+ <comment xml:lang="sq">depozitë dokumenti të përbërë OLE2</comment>
<comment xml:lang="sl">Združeni dokument OLE2</comment>
+ <comment xml:lang="si">OLE2 සංයුක්ත ලේඛන ගබඩා කිරීම</comment>
<comment xml:lang="sk">Úložisko zloženého dokumentu OLE2</comment>
<comment xml:lang="ru">Хранилище составных документов OLE2</comment>
<comment xml:lang="ro">Document de stocare compus OLE2</comment>
@@ -18390,6 +19219,7 @@ command to generate the output files.
<comment xml:lang="kk">OLE2 құрама құжаттар қоймасы</comment>
<comment xml:lang="ja">OLE2 複合ドキュメントストレージ</comment>
<comment xml:lang="it">Memorizzazione documento composto OLE2</comment>
+ <comment xml:lang="is">OLE2 samsett skjalageymsla</comment>
<comment xml:lang="id">Penyimpan dokumen kompon OLE2</comment>
<comment xml:lang="ia">Magazin de documentos composite OLE2</comment>
<comment xml:lang="hu">OLE2 összetett dokumentumtároló</comment>
@@ -18406,12 +19236,13 @@ command to generate the output files.
<comment xml:lang="eo">OLE2-deponejo de parentezaj dokumentoj</comment>
<comment xml:lang="en_GB">OLE2 compound document storage</comment>
<comment xml:lang="el">Αρχείο συμπαγούς αποθήκευσης εγγράφων OLE2</comment>
- <comment xml:lang="de">OLE2-Verbunddokumentenspeicher</comment>
+ <comment xml:lang="de">OLE2-Verbunddokumentspeicher</comment>
<comment xml:lang="da">OLE2-sammensat dokumentlager</comment>
<comment xml:lang="cs">úložiště složeného dokumentu OLE2</comment>
<comment xml:lang="ca">emmagatzematge de documents compostos OLE2</comment>
<comment xml:lang="bg">Съставен документ-хранилище — OLE2</comment>
<comment xml:lang="be@latin">Schovišča dla kampanentaŭ dakumentu OLE2</comment>
+ <comment xml:lang="be">сховішча складаных дакументаў OLE2</comment>
<comment xml:lang="ast">Almacenamientu de documentos compuestu por OLE2</comment>
<comment xml:lang="ar">تخزين مجمع مستند OLE2</comment>
<generic-icon name="x-office-document"/>
@@ -18420,6 +19251,27 @@ command to generate the output files.
<match type="little32" value="0xe011cfd0" offset="0"/>
</magic>
</mime-type>
+ <mime-type type="application/vnd.microsoft.windows.thumbnail-cache">
+ <comment>Microsoft Windows Thumbnail Cache</comment>
+ <comment xml:lang="uk">кеш мініатюр Microsoft Windows</comment>
+ <comment xml:lang="sv">Microsoft Windows-miniatyrbildscache</comment>
+ <comment xml:lang="ru">Кэш миниатюр Microsoft Windows</comment>
+ <comment xml:lang="pl">Pamięć podręczna miniatur Microsoft Windows</comment>
+ <comment xml:lang="it">Cache miniuature Microsoft Windows</comment>
+ <comment xml:lang="eu">Microsoft Windows miniatura-cachea</comment>
+ <comment xml:lang="es">antememoria de miniaturas de Microsoft Windows</comment>
+ <comment xml:lang="de">Microsoft Windows-Vorschaubilderzwischenspeicher</comment>
+ <comment xml:lang="be">пакет тэмы Microsoft Windows</comment>
+ <sub-class-of type="application/x-ole-storage"/>
+ <generic-icon name="image-x-generic"/>
+ <glob pattern="ehthumbs.db"/>
+ <glob pattern="ehthumbs_vista.db"/>
+ <glob pattern="image.db"/>
+ <glob pattern="musicthumbs.db"/>
+ <glob pattern="thumbs.db"/>
+ <glob pattern="tvthumb.db"/>
+ <glob pattern="video.db"/>
+ </mime-type>
<mime-type type="application/vnd.ms-publisher">
<comment>Microsoft Publisher document</comment>
<comment xml:lang="zh_TW">微軟 Publisher 文件</comment>
@@ -18428,17 +19280,21 @@ command to generate the output files.
<comment xml:lang="tr">Microsoft Publisher belgesi</comment>
<comment xml:lang="sv">Microsoft Publisher-dokument</comment>
<comment xml:lang="sr">документ Мајкрософтовог Издавача</comment>
+ <comment xml:lang="sq">dokument Microsoft Publisher</comment>
<comment xml:lang="sl">Dokument Microsoft Publisher</comment>
+ <comment xml:lang="si">Microsoft Publisher ලේඛනය</comment>
<comment xml:lang="sk">Dokument Microsoft Publisher</comment>
<comment xml:lang="ru">Документ Microsoft Publisher</comment>
<comment xml:lang="pt_BR">Documento do Microsoft Publisher</comment>
<comment xml:lang="pt">documento Microsoft Publisher</comment>
<comment xml:lang="pl">Dokument Microsoft Publisher</comment>
<comment xml:lang="oc">document Microsoft Publisher</comment>
+ <comment xml:lang="nl">Microsoft Publisher-document</comment>
<comment xml:lang="ko">Microsoft Publisher 문서</comment>
<comment xml:lang="kk">Microsoft Publisher құжаты</comment>
<comment xml:lang="ja">Microsoft Publisher ドキュメント</comment>
<comment xml:lang="it">Documento Microsoft Publisher</comment>
+ <comment xml:lang="is">Microsoft Publisher skjal</comment>
<comment xml:lang="id">Dokumen Microsoft Publisher</comment>
<comment xml:lang="ia">Documento Microsoft Publisher</comment>
<comment xml:lang="hu">Microsoft Publisher dokumentum</comment>
@@ -18458,6 +19314,7 @@ command to generate the output files.
<comment xml:lang="cs">dokument Microsoft Publisher</comment>
<comment xml:lang="ca">document de Microsoft Publisher</comment>
<comment xml:lang="bg">Документ — Microsoft Publisher</comment>
+ <comment xml:lang="be">дакумент Microsoft Publisher</comment>
<comment xml:lang="ast">Documentu de Microsoft Publisher</comment>
<comment xml:lang="ar">مستند ناشر مايكروسوفت</comment>
<comment xml:lang="af">Microsoft Publisher-dokument</comment>
@@ -18473,8 +19330,9 @@ command to generate the output files.
<comment xml:lang="tr">Windows Installer paketi</comment>
<comment xml:lang="sv">Windows Installer-paket</comment>
<comment xml:lang="sr">пакет Виндоузовог инсталатера</comment>
- <comment xml:lang="sq">Paketë Windows Installer</comment>
+ <comment xml:lang="sq">paketë Windows Installer</comment>
<comment xml:lang="sl">Datoteka paketa Windows namestilnika</comment>
+ <comment xml:lang="si">වින්ඩෝස් ස්ථාපක පැකේජය</comment>
<comment xml:lang="sk">Balík Windows Installer</comment>
<comment xml:lang="ru">Пакет Windows Installer</comment>
<comment xml:lang="ro">Pachet instalator Windows</comment>
@@ -18490,6 +19348,7 @@ command to generate the output files.
<comment xml:lang="kk">Windows Installer дестесі</comment>
<comment xml:lang="ja">Windows インストーラパッケージ</comment>
<comment xml:lang="it">Pacchetto Windows Installer</comment>
+ <comment xml:lang="is">Windows uppsetningarpakki</comment>
<comment xml:lang="id">Paket Windows Installer</comment>
<comment xml:lang="ia">Pacchetto Windows Installer</comment>
<comment xml:lang="hu">Windows Installer csomag</comment>
@@ -18511,22 +19370,86 @@ command to generate the output files.
<comment xml:lang="ca">paquet de Windows Installer</comment>
<comment xml:lang="bg">Пакет — инсталация за Windows</comment>
<comment xml:lang="be@latin">Pakunak Windows Installer</comment>
+ <comment xml:lang="be">пакет Windows Installer</comment>
<comment xml:lang="ar">حزمة مثبّت ويندوز</comment>
<comment xml:lang="af">Windows-installeerpakket</comment>
<sub-class-of type="application/x-ole-storage"/>
+ <generic-icon name="package-x-generic"/>
<glob pattern="*.msi"/>
</mime-type>
+ <mime-type type="application/appx">
+ <comment>Windows app store package</comment>
+ <comment xml:lang="uk">пакунок крамниці програм Windows</comment>
+ <comment xml:lang="sv">Windows app store-paket</comment>
+ <comment xml:lang="ru">Пакет магазина приложений Windows</comment>
+ <comment xml:lang="pl">Pakiet sklepu z aplikacjami Windows</comment>
+ <comment xml:lang="es">paquete de la tienda de aplicaciones de Windows</comment>
+ <comment xml:lang="de">Windows-Appstore-Paket</comment>
+ <sub-class-of type="application/zip"/>
+ <generic-icon name="package-x-generic"/>
+ <glob pattern="*.appx"/>
+ </mime-type>
+ <mime-type type="application/msix">
+ <comment>Windows app store package</comment>
+ <comment xml:lang="uk">пакунок крамниці програм Windows</comment>
+ <comment xml:lang="sv">Windows app store-paket</comment>
+ <comment xml:lang="ru">Пакет магазина приложений Windows</comment>
+ <comment xml:lang="pl">Pakiet sklepu z aplikacjami Windows</comment>
+ <comment xml:lang="es">paquete de la tienda de aplicaciones de Windows</comment>
+ <comment xml:lang="de">Windows-Appstore-Paket</comment>
+ <sub-class-of type="application/zip"/>
+ <generic-icon name="package-x-generic"/>
+ <glob pattern="*.msix"/>
+ </mime-type>
+ <mime-type type="application/appxbundle">
+ <comment>Windows app store bundle</comment>
+ <comment xml:lang="uk">комплект крамниці програм Windows</comment>
+ <comment xml:lang="sv">Windows app store-bunt</comment>
+ <comment xml:lang="ru">Объединённый пакет магазина приложений Windows</comment>
+ <comment xml:lang="pl">Paczka sklepu z aplikacjami Windows</comment>
+ <comment xml:lang="de">Zusammengefasste Windows-Appstore-Pakete</comment>
+ <sub-class-of type="application/zip"/>
+ <generic-icon name="package-x-generic"/>
+ <glob pattern="*.appxbundle"/>
+ </mime-type>
+ <mime-type type="application/msixbundle">
+ <comment>Windows app store bundle</comment>
+ <comment xml:lang="uk">комплект крамниці програм Windows</comment>
+ <comment xml:lang="sv">Windows app store-bunt</comment>
+ <comment xml:lang="ru">Объединённый пакет магазина приложений Windows</comment>
+ <comment xml:lang="pl">Paczka sklepu z aplikacjami Windows</comment>
+ <comment xml:lang="de">Zusammengefasste Windows-Appstore-Pakete</comment>
+ <sub-class-of type="application/zip"/>
+ <generic-icon name="package-x-generic"/>
+ <glob pattern="*.msixbundle"/>
+ </mime-type>
+ <mime-type type="application/appinstaller">
+ <comment>Windows app store installer</comment>
+ <comment xml:lang="uk">встановлювач крамниці програм Windows</comment>
+ <comment xml:lang="sv">Windows app store-installerare</comment>
+ <comment xml:lang="ru">Программа установки магазина приложений Windows</comment>
+ <comment xml:lang="pl">Instalator sklepu z aplikacjami Windows</comment>
+ <comment xml:lang="es">instalador de la tienda de aplicaciones de Windows</comment>
+ <comment xml:lang="de">Windows-Appstore-Installationsprogramm</comment>
+ <sub-class-of type="application/xml"/>
+ <generic-icon name="package-x-generic"/>
+ <magic>
+ <match type="string" value="&lt;AppInstaller" offset="0:256"/>
+ </magic>
+ <glob pattern="*.appinstaller"/>
+ </mime-type>
<mime-type type="application/x-oleo">
<comment>GNU Oleo spreadsheet</comment>
<comment xml:lang="zh_TW">GNU Oleo 試算表</comment>
<comment xml:lang="zh_CN">GNU Oleo 电子表格</comment>
<comment xml:lang="vi">Bảng tính Oleo của GNU</comment>
- <comment xml:lang="uk">ел. таблиця GNU Oleo</comment>
+ <comment xml:lang="uk">електронна таблиця GNU Oleo</comment>
<comment xml:lang="tr">GNU Oleo hesap çizelgesi</comment>
<comment xml:lang="sv">GNU Oleo-kalkylblad</comment>
<comment xml:lang="sr">ГНУ Олео табела</comment>
- <comment xml:lang="sq">Fletë llogaritje GNU Oleo</comment>
+ <comment xml:lang="sq">fletëllogaritje GNU Oleo</comment>
<comment xml:lang="sl">Preglednica GNU Oleo</comment>
+ <comment xml:lang="si">GNU Oleo පැතුරුම්පත</comment>
<comment xml:lang="sk">Zošit GNU Oleo</comment>
<comment xml:lang="ru">Электронная таблица GNU Oleo</comment>
<comment xml:lang="ro">Foaie de calcul GNU Oleo</comment>
@@ -18545,6 +19468,7 @@ command to generate the output files.
<comment xml:lang="ka">GNU Oleo ცხრილი</comment>
<comment xml:lang="ja">GNU Oleo スプレッドシート</comment>
<comment xml:lang="it">Foglio di calcolo GNU Oleo</comment>
+ <comment xml:lang="is">GNU Oleo töflureikniskjal</comment>
<comment xml:lang="id">Lembar sebar GNU Oleo</comment>
<comment xml:lang="ia">Folio de calculo GNU Oleo</comment>
<comment xml:lang="hu">GNU Oleo-munkafüzet</comment>
@@ -18567,6 +19491,7 @@ command to generate the output files.
<comment xml:lang="ca">full de càlcul de GNU Oleo</comment>
<comment xml:lang="bg">Таблица — GNU Oleo</comment>
<comment xml:lang="be@latin">Raźlikovy arkuš GNU Oleo</comment>
+ <comment xml:lang="be">электронная табліца GNU Oleo</comment>
<comment xml:lang="ar">جدول جنو Oleo</comment>
<comment xml:lang="af">GNU Oleo-sigblad</comment>
<generic-icon name="x-office-spreadsheet"/>
@@ -18584,8 +19509,9 @@ command to generate the output files.
<comment xml:lang="tr">PAK arşivi</comment>
<comment xml:lang="sv">PAK-arkiv</comment>
<comment xml:lang="sr">ПАК архива</comment>
- <comment xml:lang="sq">Arkiv PAK</comment>
+ <comment xml:lang="sq">arkiv PAK</comment>
<comment xml:lang="sl">Datoteka arhiva PAK</comment>
+ <comment xml:lang="si">PAK ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív PAK</comment>
<comment xml:lang="ru">Архив PAK</comment>
<comment xml:lang="ro">Arhivă PAK</comment>
@@ -18603,6 +19529,7 @@ command to generate the output files.
<comment xml:lang="ka">PAK არქივი</comment>
<comment xml:lang="ja">PAK アーカイブ</comment>
<comment xml:lang="it">Archivio PAK</comment>
+ <comment xml:lang="is">PAK safnskrá</comment>
<comment xml:lang="id">Arsip PAK</comment>
<comment xml:lang="ia">Archivo PAK</comment>
<comment xml:lang="hu">PAK-archívum</comment>
@@ -18625,12 +19552,10 @@ command to generate the output files.
<comment xml:lang="ca">arxiu PAK</comment>
<comment xml:lang="bg">Архив — PAK</comment>
<comment xml:lang="be@latin">Archiŭ PAK</comment>
+ <comment xml:lang="be">архіў PAK</comment>
<comment xml:lang="ar">أرشيف PAK</comment>
<comment xml:lang="af">PAK-argief</comment>
<generic-icon name="package-x-generic"/>
- <magic priority="80">
- <match offset="0" type="string" value="PACK"/>
- </magic>
<glob pattern="*.pak"/>
</mime-type>
<mime-type type="application/vnd.palm">
@@ -18642,8 +19567,9 @@ command to generate the output files.
<comment xml:lang="tr">Palm OS veri tabanı</comment>
<comment xml:lang="sv">Palm OS-databas</comment>
<comment xml:lang="sr">база података Палм ОС-а</comment>
- <comment xml:lang="sq">Bankë me të dhëna Palm OS</comment>
+ <comment xml:lang="sq">bazë të dhënash Palm OS</comment>
<comment xml:lang="sl">Podatkovna zbirka Palm OS</comment>
+ <comment xml:lang="si">Palm OS දත්ත ගබඩාව</comment>
<comment xml:lang="sk">Databáza Palm OS</comment>
<comment xml:lang="ru">База данных Palm OS</comment>
<comment xml:lang="ro">Bază de date Palm OS</comment>
@@ -18652,7 +19578,7 @@ command to generate the output files.
<comment xml:lang="pl">Baza danych Palm OS</comment>
<comment xml:lang="oc">banca de donadas Palm OS</comment>
<comment xml:lang="nn">Palm OS-database</comment>
- <comment xml:lang="nl">Palm OS-gegevensbank</comment>
+ <comment xml:lang="nl">Palm OS-database</comment>
<comment xml:lang="nb">Palm OS-database</comment>
<comment xml:lang="ms">Pangkalandata PalmOS</comment>
<comment xml:lang="lv">Palm OS datubāze</comment>
@@ -18661,6 +19587,7 @@ command to generate the output files.
<comment xml:lang="kk">Palm OS дерекқоры</comment>
<comment xml:lang="ja">Palm OS データベース</comment>
<comment xml:lang="it">Database Palm OS</comment>
+ <comment xml:lang="is">Palm OS gagnagrunnur</comment>
<comment xml:lang="id">Basis data Palm OS</comment>
<comment xml:lang="ia">Base de datos Palm OS</comment>
<comment xml:lang="hu">Palm OS-adatbázis</comment>
@@ -18684,11 +19611,12 @@ command to generate the output files.
<comment xml:lang="ca">base de dades Palm OS</comment>
<comment xml:lang="bg">База от данни — Palm OS</comment>
<comment xml:lang="be@latin">Baza źviestak Palm OS</comment>
+ <comment xml:lang="be">база даных Palm OS</comment>
<comment xml:lang="az">Palm OS mə'lumat bazası</comment>
<comment xml:lang="ar">قاعدة بيانات Palm OS</comment>
<comment xml:lang="af">Palm OS-databasis</comment>
<glob pattern="*.prc"/>
- <glob pattern="*.pdb"/>
+ <glob pattern="*.pdb" weight="40"/>
<glob pattern="*.pqa"/>
<glob pattern="*.oprc"/>
<alias type="application/x-palm-database"/>
@@ -18702,8 +19630,9 @@ command to generate the output files.
<comment xml:lang="tr">Parchive arşivi</comment>
<comment xml:lang="sv">Parchive-arkiv</comment>
<comment xml:lang="sr">архива Пархива</comment>
- <comment xml:lang="sq">Arkiv Parchive</comment>
+ <comment xml:lang="sq">arkiv Parchive</comment>
<comment xml:lang="sl">Datoteka arhiva Parchive</comment>
+ <comment xml:lang="si">Parchive ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív Parchive</comment>
<comment xml:lang="ru">Архив Parchive</comment>
<comment xml:lang="ro">Arhivă Parchive</comment>
@@ -18720,6 +19649,7 @@ command to generate the output files.
<comment xml:lang="kk">Parchive архиві</comment>
<comment xml:lang="ja">Parchive アーカイブ</comment>
<comment xml:lang="it">Archivio Parchive</comment>
+ <comment xml:lang="is">Parchive safnskrá</comment>
<comment xml:lang="id">Arsip Parchive</comment>
<comment xml:lang="ia">Archivo Parchive</comment>
<comment xml:lang="hu">Parchive archívum</comment>
@@ -18741,6 +19671,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu Parchive</comment>
<comment xml:lang="bg">Архив — parchive</comment>
<comment xml:lang="be@latin">Archiŭ Parchive</comment>
+ <comment xml:lang="be">архіў Parchive</comment>
<comment xml:lang="ar">أرشيف Parchive</comment>
<comment xml:lang="af">Parchive-argief</comment>
<acronym>Parchive</acronym>
@@ -18761,8 +19692,9 @@ command to generate the output files.
<comment xml:lang="tr">PEF çalıştırılabilir</comment>
<comment xml:lang="sv">Körbar PEF-fil</comment>
<comment xml:lang="sr">ПЕФ извршна</comment>
- <comment xml:lang="sq">E ekzekutueshme PEF</comment>
+ <comment xml:lang="sq">e ekzekutueshme PEF</comment>
<comment xml:lang="sl">Izvedljiva datoteka PEF</comment>
+ <comment xml:lang="si">PEF ක්‍රියාත්මක කළ හැකිය</comment>
<comment xml:lang="sk">Spustiteľný súbor PEF</comment>
<comment xml:lang="ru">Исполняемый файл PEF</comment>
<comment xml:lang="ro">Executabil PEF</comment>
@@ -18771,7 +19703,7 @@ command to generate the output files.
<comment xml:lang="pl">Program PEF</comment>
<comment xml:lang="oc">executable PEF</comment>
<comment xml:lang="nn">Køyrbar PEF-fil</comment>
- <comment xml:lang="nl">PEF-uitvoerbaar bestand</comment>
+ <comment xml:lang="nl">PEF-programmabestand</comment>
<comment xml:lang="nb">PEF-kjørbar</comment>
<comment xml:lang="ms">Bolehlaksana PEF</comment>
<comment xml:lang="lv">PEF izpildāmais</comment>
@@ -18780,6 +19712,7 @@ command to generate the output files.
<comment xml:lang="kk">PEF орындалатын файлы</comment>
<comment xml:lang="ja">PEF 実行ファイル</comment>
<comment xml:lang="it">Eseguibile PEF</comment>
+ <comment xml:lang="is">PEF keyrsluskrá</comment>
<comment xml:lang="id">PEF dapat dieksekusi</comment>
<comment xml:lang="ia">Executabile PEF</comment>
<comment xml:lang="hu">PEF futtatható</comment>
@@ -18802,6 +19735,7 @@ command to generate the output files.
<comment xml:lang="ca">executable PEF</comment>
<comment xml:lang="bg">Изпълним файл — PEF</comment>
<comment xml:lang="be@latin">Vykonvalny fajł PEF</comment>
+ <comment xml:lang="be">выконвальны файл PEF</comment>
<comment xml:lang="ar">PEF تنفيذي</comment>
<comment xml:lang="af">PEF-uitvoerbaar</comment>
<acronym>PEF</acronym>
@@ -18820,8 +19754,9 @@ command to generate the output files.
<comment xml:lang="tr">Perl betiği</comment>
<comment xml:lang="sv">Perlskript</comment>
<comment xml:lang="sr">Перл скрипта</comment>
- <comment xml:lang="sq">Script Perl</comment>
+ <comment xml:lang="sq">programth Perl</comment>
<comment xml:lang="sl">Skriptna datoteka Perl</comment>
+ <comment xml:lang="si">පර්ල් පිටපත</comment>
<comment xml:lang="sk">Skript jazyka Perl</comment>
<comment xml:lang="ru">Сценарий Perl</comment>
<comment xml:lang="ro">Script Perl</comment>
@@ -18839,6 +19774,7 @@ command to generate the output files.
<comment xml:lang="kk">Perl сценарийі</comment>
<comment xml:lang="ja">Perl スクリプト</comment>
<comment xml:lang="it">Script Perl</comment>
+ <comment xml:lang="is">Perl skrifta</comment>
<comment xml:lang="id">Skrip Perl</comment>
<comment xml:lang="ia">Script Perl</comment>
<comment xml:lang="hu">Perl-parancsfájl</comment>
@@ -18862,6 +19798,7 @@ command to generate the output files.
<comment xml:lang="ca">script Perl</comment>
<comment xml:lang="bg">Скрипт — Perl</comment>
<comment xml:lang="be@latin">Skrypt Perl</comment>
+ <comment xml:lang="be">скрыпт Perl</comment>
<comment xml:lang="ar">سكربت بيرل</comment>
<comment xml:lang="af">Perl-skrip</comment>
<sub-class-of type="application/x-executable"/>
@@ -18905,8 +19842,9 @@ command to generate the output files.
<comment xml:lang="tr">PHP betiği</comment>
<comment xml:lang="sv">PHP-skript</comment>
<comment xml:lang="sr">ПХП скрипта</comment>
- <comment xml:lang="sq">Script PHP</comment>
+ <comment xml:lang="sq">programth PHP</comment>
<comment xml:lang="sl">Skriptna datoteka PHP</comment>
+ <comment xml:lang="si">PHP ස්ක්‍රිප්ට්</comment>
<comment xml:lang="sk">Skript PHP</comment>
<comment xml:lang="ru">Сценарий PHP</comment>
<comment xml:lang="ro">Script PHP</comment>
@@ -18924,6 +19862,7 @@ command to generate the output files.
<comment xml:lang="kk">PHP сценарийі</comment>
<comment xml:lang="ja">PHP スクリプト</comment>
<comment xml:lang="it">Script PHP</comment>
+ <comment xml:lang="is">PHP skrifta</comment>
<comment xml:lang="id">Skrip PHP</comment>
<comment xml:lang="ia">Script PHP</comment>
<comment xml:lang="hu">PHP-parancsfájl</comment>
@@ -18947,6 +19886,7 @@ command to generate the output files.
<comment xml:lang="ca">script PHP</comment>
<comment xml:lang="bg">Скрипт — PHP</comment>
<comment xml:lang="be@latin">Skrypt PHP</comment>
+ <comment xml:lang="be">скрыпт PHP</comment>
<comment xml:lang="az">PHP skripti</comment>
<comment xml:lang="ar">سكربت PHP</comment>
<comment xml:lang="af">PHP-skrip</comment>
@@ -18970,7 +19910,9 @@ command to generate the output files.
<comment xml:lang="tr">PKCS#7 sertifika paketi</comment>
<comment xml:lang="sv">PKCS#7-certifikatsamling</comment>
<comment xml:lang="sr">ПКЦС#7 пакет уверења</comment>
+ <comment xml:lang="sq">paketë dëshmish PKCS#7</comment>
<comment xml:lang="sl">Datoteka potrdila PKCS#7</comment>
+ <comment xml:lang="si">PKCS#7 සහතික මිටියක්</comment>
<comment xml:lang="sk">Zväzok certifikátov PKCS#7</comment>
<comment xml:lang="ru">Пакет сертификата PKCS#7</comment>
<comment xml:lang="ro">Pachet certificat PKCS#7</comment>
@@ -18985,6 +19927,7 @@ command to generate the output files.
<comment xml:lang="kk">PKCS#7 сертификаттар дестесі</comment>
<comment xml:lang="ja">PKCS#7 証明書バンドル</comment>
<comment xml:lang="it">Bundle certificato PKCS#7</comment>
+ <comment xml:lang="is">PKCS#7 skilríkjavöndull</comment>
<comment xml:lang="id">Bundel sertifikat PKCS#7</comment>
<comment xml:lang="ia">Pacchetto de certificatos PKCS#7</comment>
<comment xml:lang="hu">PKCS#7-tanúsítványcsomag</comment>
@@ -19000,11 +19943,12 @@ command to generate the output files.
<comment xml:lang="es">lote de certificados PCKS#7</comment>
<comment xml:lang="en_GB">PKCS#7 certificate bundle</comment>
<comment xml:lang="el">Πακέτο ψηφιακών πιστοποιητικών PKCS#7</comment>
- <comment xml:lang="de">PKCS#7-Zertifikatspaket</comment>
+ <comment xml:lang="de">PKCS#7-Zertifikatpaket</comment>
<comment xml:lang="da">PKCS#7-certifikatbundt</comment>
<comment xml:lang="cs">svazek certifikátů PKCS#7</comment>
<comment xml:lang="ca">conjunt de certificats PKCS#7</comment>
<comment xml:lang="bg">Пакет със сертификати — PKCS#7</comment>
+ <comment xml:lang="be">пакет сертыфікатаў PKCS#7</comment>
<comment xml:lang="ar">رزمة شهادة PKCS#7</comment>
<comment xml:lang="af">PKCS#7-sertifikaatbundel</comment>
<acronym>PKCS</acronym>
@@ -19021,8 +19965,9 @@ command to generate the output files.
<comment xml:lang="tr">PKCS#12 sertifika paketi</comment>
<comment xml:lang="sv">PKCS#12-certifikatsamling</comment>
<comment xml:lang="sr">ПКЦС#12 пакет уверења</comment>
- <comment xml:lang="sq">Bundle çertifikate PKCS#12</comment>
+ <comment xml:lang="sq">paketë dëshmish PKCS#12</comment>
<comment xml:lang="sl">Datoteka potrdila PKCS#12</comment>
+ <comment xml:lang="si">PKCS#12 සහතික මිටියක්</comment>
<comment xml:lang="sk">Zväzok certifikátov PKCS#12</comment>
<comment xml:lang="ru">Пакет сертификата PKCS#12</comment>
<comment xml:lang="ro">Certificat împachetat PKCS#12</comment>
@@ -19040,6 +19985,7 @@ command to generate the output files.
<comment xml:lang="kk">PKCS#12 сертификаттар дестесі</comment>
<comment xml:lang="ja">PKCS#12 証明書バンドル</comment>
<comment xml:lang="it">Bundle certificato PKCS#12</comment>
+ <comment xml:lang="is">PKCS#12 skilríkjavöndull</comment>
<comment xml:lang="id">Bundel sertifikat PKCS#12</comment>
<comment xml:lang="ia">Pacchetto de certificatos PKCS#12</comment>
<comment xml:lang="hu">PKCS#12-tanúsítványcsomag</comment>
@@ -19056,12 +20002,13 @@ command to generate the output files.
<comment xml:lang="eo">ligaĵo de PKCS#12-atestiloj</comment>
<comment xml:lang="en_GB">PKCS#12 certificate bundle</comment>
<comment xml:lang="el">Πακέτο ψηφιακών πιστοποιητικών PKCS#12</comment>
- <comment xml:lang="de">PKCS#12-Zertifikatspaket</comment>
+ <comment xml:lang="de">PKCS#12-Zertifikatpaket</comment>
<comment xml:lang="da">PKCS#12-certifikatbundt</comment>
<comment xml:lang="cs">svazek certifikátů PKCS#12</comment>
<comment xml:lang="ca">conjunt de certificats PKCS#12</comment>
<comment xml:lang="bg">Пакет със сертификати — PKCS#12</comment>
<comment xml:lang="be@latin">Viazka sertyfikataŭ PKCS#12</comment>
+ <comment xml:lang="be">пакет сертыфікатаў PKCS#12</comment>
<comment xml:lang="ar">رزمة شهادة PKCS#12</comment>
<comment xml:lang="af">PKCS#12-sertifikaatbundel</comment>
<acronym>PKCS</acronym>
@@ -19075,12 +20022,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">PlanPerfect 試算表</comment>
<comment xml:lang="zh_CN">PlanPerfect 电子表格</comment>
<comment xml:lang="vi">Bảng tính PlanPerfect</comment>
- <comment xml:lang="uk">ел. таблиця PlanPerfect</comment>
+ <comment xml:lang="uk">електронна таблиця PlanPerfect</comment>
<comment xml:lang="tr">PlanPerfect hesap çizelgesi</comment>
<comment xml:lang="sv">PlanPerfect-kalkylblad</comment>
<comment xml:lang="sr">табела План Перфекта</comment>
- <comment xml:lang="sq">Fletë llogaritjesh PlanPerfect</comment>
+ <comment xml:lang="sq">fletëllogaritje PlanPerfect</comment>
<comment xml:lang="sl">Preglednica PlanPerfect</comment>
+ <comment xml:lang="si">PlanPerfect පැතුරුම්පත</comment>
<comment xml:lang="sk">Zošit PlanPerfect</comment>
<comment xml:lang="ru">Электронная таблица PlanPerfect</comment>
<comment xml:lang="ro">Foaie de calcul PlanPerfect</comment>
@@ -19097,6 +20045,7 @@ command to generate the output files.
<comment xml:lang="kk">PlanPerfect электрондық кестесі</comment>
<comment xml:lang="ja">PlanPerfect スプレッドシート</comment>
<comment xml:lang="it">Foglio di calcolo PlanPerfect</comment>
+ <comment xml:lang="is">PlanPerfect töflureikniskjal</comment>
<comment xml:lang="id">Lembar sebar PlanPerfect</comment>
<comment xml:lang="ia">Folio de calculo PlanPerfect</comment>
<comment xml:lang="hu">PlanPerfect táblázat</comment>
@@ -19118,6 +20067,7 @@ command to generate the output files.
<comment xml:lang="ca">full de càlcul de PlanPerfect</comment>
<comment xml:lang="bg">Таблица — PlanPerfect</comment>
<comment xml:lang="be@latin">Raźlikovy arkuš PlanPerfect</comment>
+ <comment xml:lang="be">электронная табліца PlanPerfect</comment>
<comment xml:lang="ar">جدول PlanPerfect</comment>
<comment xml:lang="af">PlanPerfect-sigblad</comment>
<generic-icon name="x-office-spreadsheet"/>
@@ -19132,7 +20082,9 @@ command to generate the output files.
<comment xml:lang="tr">Pocket Word belgesi</comment>
<comment xml:lang="sv">Pocket Word-dokument</comment>
<comment xml:lang="sr">документ Покет Ворда</comment>
+ <comment xml:lang="sq">dokument Pocket Word</comment>
<comment xml:lang="sl">Dokument Pocket Word</comment>
+ <comment xml:lang="si">Pocket Word ලේඛනය</comment>
<comment xml:lang="sk">Dokument Pocket Word</comment>
<comment xml:lang="ru">Документ Pocket Word</comment>
<comment xml:lang="ro">Document Pocket Word</comment>
@@ -19147,6 +20099,7 @@ command to generate the output files.
<comment xml:lang="kk">Pocket Word құжаты</comment>
<comment xml:lang="ja">Pocket Word ドキュメント</comment>
<comment xml:lang="it">Documento Pocket Word</comment>
+ <comment xml:lang="is">Pocket Word skjal</comment>
<comment xml:lang="id">Dokumen Pocket Word</comment>
<comment xml:lang="ia">Documento Pocket Word</comment>
<comment xml:lang="hu">Pocket Word dokumentum</comment>
@@ -19167,6 +20120,7 @@ command to generate the output files.
<comment xml:lang="cs">dokument Pocket Word</comment>
<comment xml:lang="ca">document de Pocket Word</comment>
<comment xml:lang="bg">Документ — Pocket Word</comment>
+ <comment xml:lang="be">дакумент Pocket Word</comment>
<comment xml:lang="ast">Documentu de PocketWord</comment>
<comment xml:lang="ar">مستند Pocket Word</comment>
<comment xml:lang="af">Pocket Word-dokument</comment>
@@ -19177,58 +20131,17 @@ command to generate the output files.
<glob pattern="*.psw"/>
</mime-type>
<mime-type type="application/x-profile">
- <comment>profiler results</comment>
- <comment xml:lang="zh_TW">硬體資訊產生器成果</comment>
- <comment xml:lang="zh_CN">探查器结果</comment>
- <comment xml:lang="vi">kết quả nét hiện trạng</comment>
+ <comment>Profiler results</comment>
<comment xml:lang="uk">результати профілювання</comment>
- <comment xml:lang="tr">profiler sonuçları</comment>
- <comment xml:lang="sv">profilerarresultat</comment>
- <comment xml:lang="sr">резултати профилатора</comment>
- <comment xml:lang="sq">Rezultate të profiluesit</comment>
- <comment xml:lang="sl">rezultati profilirnika</comment>
- <comment xml:lang="sk">Výsledky profilera</comment>
+ <comment xml:lang="sv">Profilerarresultat</comment>
<comment xml:lang="ru">Результаты профилирования</comment>
- <comment xml:lang="ro">rezultate profiler</comment>
- <comment xml:lang="pt_BR">Resultados do profiler</comment>
- <comment xml:lang="pt">resultados de análise de perfil</comment>
<comment xml:lang="pl">Wyniki profilowania</comment>
- <comment xml:lang="oc">resultats de perfilador</comment>
- <comment xml:lang="nn">profileringsresultat</comment>
- <comment xml:lang="nl">profiler-resultaten</comment>
- <comment xml:lang="nb">profileingsresultat</comment>
- <comment xml:lang="ms">Hasil pemprofil</comment>
- <comment xml:lang="lv">profilētāja rezultāti</comment>
- <comment xml:lang="lt">profiliklio rezultatai</comment>
- <comment xml:lang="ko">프로파일러 결과</comment>
- <comment xml:lang="kk">прифильдеу нәтижелері</comment>
- <comment xml:lang="ja">プロファイラー結果</comment>
<comment xml:lang="it">Risultati profiler</comment>
- <comment xml:lang="id">hasil profiler</comment>
- <comment xml:lang="ia">Resultatos de profilator</comment>
- <comment xml:lang="hu">profilírozó-eredmények</comment>
- <comment xml:lang="hr">Rezultati profila</comment>
- <comment xml:lang="he">תוצאות מאבחן</comment>
- <comment xml:lang="gl">resultados do perfilador</comment>
- <comment xml:lang="ga">torthaí próifíleora</comment>
- <comment xml:lang="fur">risultâts profiladôr</comment>
- <comment xml:lang="fr">résultats de profileur</comment>
- <comment xml:lang="fi">profilointitulokset</comment>
- <comment xml:lang="eu">profiler-aren emaitzak</comment>
- <comment xml:lang="es">resultados del perfilador</comment>
- <comment xml:lang="eo">resultoj de profililo</comment>
- <comment xml:lang="en_GB">profiler results</comment>
- <comment xml:lang="el">Αποτελέσματα μετρήσεων για την εκτέλεση προγράμματος</comment>
+ <comment xml:lang="gl">Resultados dos perfiladores</comment>
+ <comment xml:lang="eu">Profilatzaile-emaitzak</comment>
+ <comment xml:lang="es">resultados de generador de perfiles</comment>
<comment xml:lang="de">Profiler-Ergebnisse</comment>
- <comment xml:lang="da">profileringsresultater</comment>
- <comment xml:lang="cy">canlyniadau proffeilio</comment>
- <comment xml:lang="cs">výsledky profileru</comment>
- <comment xml:lang="ca">resultats del perfilador</comment>
- <comment xml:lang="bg">Резултати от анализатора</comment>
- <comment xml:lang="be@latin">vyniki profilera</comment>
- <comment xml:lang="az">profiler nəticələri</comment>
- <comment xml:lang="ar">نتائج محلل</comment>
- <comment xml:lang="af">profieldata</comment>
+ <comment xml:lang="be">вынікі прафіліроўшчыка</comment>
<sub-class-of type="text/plain"/>
<generic-icon name="text-x-generic"/>
<glob pattern="gmon.out"/>
@@ -19242,8 +20155,9 @@ command to generate the output files.
<comment xml:lang="tr">Pathetic Writer belgesi</comment>
<comment xml:lang="sv">Pathetic Writer-dokument</comment>
<comment xml:lang="sr">документ Патетичног Писца</comment>
- <comment xml:lang="sq">Dokument Pathetic Writer</comment>
+ <comment xml:lang="sq">dokument Pathetic Writer</comment>
<comment xml:lang="sl">Dokument Pathetic Writer</comment>
+ <comment xml:lang="si">දුක්ඛිත ලේඛක ලේඛනය</comment>
<comment xml:lang="sk">Dokument Pathetic Writer</comment>
<comment xml:lang="ru">Документ Pathetic Writer</comment>
<comment xml:lang="ro">Document Pathetic Writer</comment>
@@ -19261,6 +20175,7 @@ command to generate the output files.
<comment xml:lang="kk">Pathetic Writer құжаты</comment>
<comment xml:lang="ja">Pathetic Writer ドキュメント</comment>
<comment xml:lang="it">Documento Pathetic Writer</comment>
+ <comment xml:lang="is">Pathetic Writer skjal</comment>
<comment xml:lang="id">Dokumen Pathetic Writer</comment>
<comment xml:lang="ia">Documento Pathetic Writer</comment>
<comment xml:lang="hu">Pathetic Writer-dokumentum</comment>
@@ -19283,6 +20198,7 @@ command to generate the output files.
<comment xml:lang="ca">document de Pathetic Writer</comment>
<comment xml:lang="bg">Документ — Pathetic Writer</comment>
<comment xml:lang="be@latin">Dakument Pathetic Writer</comment>
+ <comment xml:lang="be">дакумент Pathetic Writer</comment>
<comment xml:lang="ast">Documentu de Pathetic Writer</comment>
<comment xml:lang="ar">مستند Pathetic Writer</comment>
<comment xml:lang="af">Pathetic Writer-dokument</comment>
@@ -19298,8 +20214,8 @@ command to generate the output files.
<comment xml:lang="tr">Python bayt kodu</comment>
<comment xml:lang="sv">Python-bytekod</comment>
<comment xml:lang="sr">Питонов бајтни ко̂д</comment>
- <comment xml:lang="sq">Bytecode Python</comment>
<comment xml:lang="sl">Datoteka bitne kode Python</comment>
+ <comment xml:lang="si">පයිතන් බයිට්කෝඩ්</comment>
<comment xml:lang="sk">Bajtový kód Python</comment>
<comment xml:lang="ru">Байт-код Python</comment>
<comment xml:lang="ro">Bytecode Python</comment>
@@ -19317,6 +20233,7 @@ command to generate the output files.
<comment xml:lang="kk">Python байткоды</comment>
<comment xml:lang="ja">Python バイトコード</comment>
<comment xml:lang="it">Bytecode Python</comment>
+ <comment xml:lang="is">Python bætakóði</comment>
<comment xml:lang="id">Kode bita Python</comment>
<comment xml:lang="ia">Codice intermediari Python</comment>
<comment xml:lang="hu">Python-bájtkód</comment>
@@ -19329,7 +20246,7 @@ command to generate the output files.
<comment xml:lang="fo">Python býtkota</comment>
<comment xml:lang="fi">Python-tavukoodi</comment>
<comment xml:lang="eu">Python byte-kodea</comment>
- <comment xml:lang="es">bytecode de Python</comment>
+ <comment xml:lang="es">código intermedio de Python</comment>
<comment xml:lang="eo">Python-bajtkodo</comment>
<comment xml:lang="en_GB">Python bytecode</comment>
<comment xml:lang="el">Συμβολοκώδικας Python</comment>
@@ -19340,6 +20257,7 @@ command to generate the output files.
<comment xml:lang="ca">bytecode de Python</comment>
<comment xml:lang="bg">Байт код — Python</comment>
<comment xml:lang="be@latin">Bajtavy kod Python</comment>
+ <comment xml:lang="be">байт-код Python</comment>
<comment xml:lang="az">Python bayt kodu</comment>
<comment xml:lang="ar">Python bytecode</comment>
<comment xml:lang="af">Python binêre kode</comment>
@@ -19357,18 +20275,22 @@ command to generate the output files.
<comment xml:lang="tr">QtiPlot belgesi</comment>
<comment xml:lang="sv">QtiPlot-dokument</comment>
<comment xml:lang="sr">КутиПлот документ</comment>
+ <comment xml:lang="sq">dokument QtiPlot</comment>
<comment xml:lang="sl">Dokument QtiPlot</comment>
+ <comment xml:lang="si">QtiPlot ලේඛනය</comment>
<comment xml:lang="sk">Dokument QtiPlot</comment>
<comment xml:lang="ru">Документ QtiPlot</comment>
<comment xml:lang="pt_BR">Documento do QtiPlot</comment>
<comment xml:lang="pt">documento QtiPlot</comment>
<comment xml:lang="pl">Dokument QtiPlot</comment>
<comment xml:lang="oc">document QtiPlot</comment>
+ <comment xml:lang="nl">QtiPlot-document</comment>
<comment xml:lang="lv">QtiPlot dokuments</comment>
<comment xml:lang="ko">QtiPlot 문서</comment>
<comment xml:lang="kk">QtiPlot құжаты</comment>
<comment xml:lang="ja">QtiPlot ドキュメント</comment>
<comment xml:lang="it">Documento QtiPlot</comment>
+ <comment xml:lang="is">QtiPlot skjal</comment>
<comment xml:lang="id">Dokumen QtiPlot</comment>
<comment xml:lang="ia">Documento QtiPlot</comment>
<comment xml:lang="hu">QtiPlot dokumentum</comment>
@@ -19388,6 +20310,7 @@ command to generate the output files.
<comment xml:lang="cs">dokument GtiPlot</comment>
<comment xml:lang="ca">document QtiPlot</comment>
<comment xml:lang="bg">Документ — QtiPlot</comment>
+ <comment xml:lang="be">дакумент QtiPlot</comment>
<comment xml:lang="ast">Documentu de QtiPlot</comment>
<comment xml:lang="ar">مستند QtiPlot</comment>
<comment xml:lang="af">QtiPlot-dokument</comment>
@@ -19404,12 +20327,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">Quattro Pro 試算表</comment>
<comment xml:lang="zh_CN">Quattro Pro 电子表格</comment>
<comment xml:lang="vi">Bảng tính Quattro Pro</comment>
- <comment xml:lang="uk">ел. таблиця Quattro Pro</comment>
+ <comment xml:lang="uk">електронна таблиця Quattro Pro</comment>
<comment xml:lang="tr">Quattro Pro hesap çizelgesi</comment>
<comment xml:lang="sv">Quattro Pro-kalkylblad</comment>
<comment xml:lang="sr">Кватро Про табела</comment>
- <comment xml:lang="sq">Fletë llogaritjesh Quattro Pro</comment>
+ <comment xml:lang="sq">fletëllogaritje Quattro Pro</comment>
<comment xml:lang="sl">Preglednica Quattro Pro</comment>
+ <comment xml:lang="si">Quattro Pro පැතුරුම්පත</comment>
<comment xml:lang="sk">Zošit Quattro Pro</comment>
<comment xml:lang="ru">Электронная таблица Quattro Pro</comment>
<comment xml:lang="ro">Foaie de calcul Quattro Pro</comment>
@@ -19427,6 +20351,7 @@ command to generate the output files.
<comment xml:lang="kk">Quattro Pro электрондық кестесі</comment>
<comment xml:lang="ja">Quattro Pro スプレッドシート</comment>
<comment xml:lang="it">Foglio di calcolo Quattro Pro</comment>
+ <comment xml:lang="is">Quattro Pro töflureikniskjal</comment>
<comment xml:lang="id">Lembar sebar Quattro Pro</comment>
<comment xml:lang="ia">Folio de calculo Quattro Pro</comment>
<comment xml:lang="hu">Quattro Pro-munkafüzet</comment>
@@ -19449,6 +20374,7 @@ command to generate the output files.
<comment xml:lang="ca">full de càlcul de Quattro Pro</comment>
<comment xml:lang="bg">Таблица — Quattro Pro</comment>
<comment xml:lang="be@latin">Raźlikovy arkuš Quattro Pro</comment>
+ <comment xml:lang="be">электронная табліца Quattro Pro</comment>
<comment xml:lang="ar">جدول Quattro Pro</comment>
<comment xml:lang="af">Quattro Pro-sigblad</comment>
<generic-icon name="x-office-spreadsheet"/>
@@ -19463,15 +20389,21 @@ command to generate the output files.
<comment xml:lang="uk">список відтворення QuickTime</comment>
<comment xml:lang="tr">QuickTime çalma listesi</comment>
<comment xml:lang="sv">QuickTime-spellista</comment>
+ <comment xml:lang="sq">luajlistë QuickTime</comment>
+ <comment xml:lang="sl">Seznam predvajanja QuickTime</comment>
+ <comment xml:lang="si">QuickTime ධාවන ලැයිස්තුව</comment>
<comment xml:lang="sk">Zoznam skladieb QuickTime</comment>
<comment xml:lang="ru">Список воспроизведения QuickTime</comment>
<comment xml:lang="pt_BR">Lista de reprodução do QuickTime</comment>
<comment xml:lang="pl">Lista odtwarzania QuickTime</comment>
<comment xml:lang="oc">lista de lectura QuickTime</comment>
+ <comment xml:lang="nl">QuickTime-afspeellijst</comment>
<comment xml:lang="ko">퀵타임 재생 목록</comment>
<comment xml:lang="kk">QuickTime ойнау тізімі</comment>
+ <comment xml:lang="ka">QuickTime დასაკრავი სია</comment>
<comment xml:lang="ja">QuickTime プレイリスト</comment>
<comment xml:lang="it">Playlist QuickTime</comment>
+ <comment xml:lang="is">QuickTime spilunarlisti</comment>
<comment xml:lang="id">Daftar putar QuickTime</comment>
<comment xml:lang="hu">QuickTime lejátszólista</comment>
<comment xml:lang="hr">QuickTime popis izvođenja</comment>
@@ -19485,6 +20417,7 @@ command to generate the output files.
<comment xml:lang="da">QuickTime-afspilningsliste</comment>
<comment xml:lang="ca">llista de reproducció QuickTime</comment>
<comment xml:lang="bg">Списък за изпълнение — QuickTime</comment>
+ <comment xml:lang="be">плэй-ліст QuickTime</comment>
<comment xml:lang="ar">قائمة تشغيل كويك تايم</comment>
<generic-icon name="video-x-generic"/>
<sub-class-of type="video/quicktime"/>
@@ -19508,8 +20441,9 @@ command to generate the output files.
<comment xml:lang="tr">Quicken belgesi</comment>
<comment xml:lang="sv">Quicken-dokument</comment>
<comment xml:lang="sr">Квикен документ</comment>
- <comment xml:lang="sq">Dokument Quicken</comment>
+ <comment xml:lang="sq">dokument Quicken</comment>
<comment xml:lang="sl">Dokument Quicken</comment>
+ <comment xml:lang="si">ඉක්මන් ලේඛනය</comment>
<comment xml:lang="sk">Dokument Quicken</comment>
<comment xml:lang="ru">Документ Quicken</comment>
<comment xml:lang="ro">Document Quicken</comment>
@@ -19527,6 +20461,7 @@ command to generate the output files.
<comment xml:lang="kk">Quicken құжаты</comment>
<comment xml:lang="ja">Quicken ドキュメント</comment>
<comment xml:lang="it">Documento Quicken</comment>
+ <comment xml:lang="is">Quicken skjal</comment>
<comment xml:lang="id">Dokumen Quicken</comment>
<comment xml:lang="ia">Documento Quicken</comment>
<comment xml:lang="hu">Quicken-dokumentum</comment>
@@ -19550,6 +20485,7 @@ command to generate the output files.
<comment xml:lang="ca">document Quicken</comment>
<comment xml:lang="bg">Документ — Quicken</comment>
<comment xml:lang="be@latin">Dakument Quicken</comment>
+ <comment xml:lang="be">дакумент Quicken</comment>
<comment xml:lang="az">Quicken sənədi</comment>
<comment xml:lang="ast">Documentu de Quicken</comment>
<comment xml:lang="ar">مستند Quicken</comment>
@@ -19566,8 +20502,9 @@ command to generate the output files.
<comment xml:lang="tr">RAR arşivi</comment>
<comment xml:lang="sv">RAR-arkiv</comment>
<comment xml:lang="sr">РАР архива</comment>
- <comment xml:lang="sq">Arkiv RAR</comment>
+ <comment xml:lang="sq">arkiv RAR</comment>
<comment xml:lang="sl">Datoteka arhiva RAR</comment>
+ <comment xml:lang="si">RAR ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív RAR</comment>
<comment xml:lang="ru">Архив RAR</comment>
<comment xml:lang="ro">Arhivă RAR</comment>
@@ -19585,6 +20522,7 @@ command to generate the output files.
<comment xml:lang="kk">RAR архиві</comment>
<comment xml:lang="ja">RAR アーカイブ</comment>
<comment xml:lang="it">Archivio RAR</comment>
+ <comment xml:lang="is">RAR safnskrá</comment>
<comment xml:lang="id">Arsip RAR</comment>
<comment xml:lang="ia">Archivo RAR</comment>
<comment xml:lang="hu">RAR-archívum</comment>
@@ -19608,6 +20546,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu RAR</comment>
<comment xml:lang="bg">Архив — RAR</comment>
<comment xml:lang="be@latin">Archiŭ RAR</comment>
+ <comment xml:lang="be">архіў RAR</comment>
<comment xml:lang="ar">أرشيف RAR</comment>
<comment xml:lang="af">RAR-argief</comment>
<acronym>RAR</acronym>
@@ -19629,8 +20568,9 @@ command to generate the output files.
<comment xml:lang="tr">DAR arşivi</comment>
<comment xml:lang="sv">DAR-arkiv</comment>
<comment xml:lang="sr">ДАР архива</comment>
- <comment xml:lang="sq">Arkiv DAR</comment>
+ <comment xml:lang="sq">arkiv DAR</comment>
<comment xml:lang="sl">Datoteka arhiva DAR</comment>
+ <comment xml:lang="si">DAR ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív DAR</comment>
<comment xml:lang="ru">Архив DAR</comment>
<comment xml:lang="ro">Arhivă DAR</comment>
@@ -19648,6 +20588,7 @@ command to generate the output files.
<comment xml:lang="ka">DAR არქივი</comment>
<comment xml:lang="ja">DAR アーカイブ</comment>
<comment xml:lang="it">Archivio DAR</comment>
+ <comment xml:lang="is">DAR safnskrá</comment>
<comment xml:lang="id">Arsip DAR</comment>
<comment xml:lang="ia">Archivo DAR</comment>
<comment xml:lang="hu">DAR archívum</comment>
@@ -19670,6 +20611,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu DAR</comment>
<comment xml:lang="bg">Архив — DAR</comment>
<comment xml:lang="be@latin">Archiŭ DAR</comment>
+ <comment xml:lang="be">архіў DAR</comment>
<comment xml:lang="ar">أرشيف DAR</comment>
<comment xml:lang="af">DAR-argief</comment>
<acronym>DAR</acronym>
@@ -19689,8 +20631,9 @@ command to generate the output files.
<comment xml:lang="tr">Alzip arşivi</comment>
<comment xml:lang="sv">Alzip-arkiv</comment>
<comment xml:lang="sr">Алзип архива</comment>
- <comment xml:lang="sq">Arkiv Alzip</comment>
+ <comment xml:lang="sq">arkiv Alzip</comment>
<comment xml:lang="sl">Datoteka arhiva Alzip</comment>
+ <comment xml:lang="si">Alzip සංරක්ෂිතය</comment>
<comment xml:lang="sk">Archív Alzip</comment>
<comment xml:lang="ru">Архив ALZIP</comment>
<comment xml:lang="ro">Arhivă Alzip</comment>
@@ -19708,6 +20651,7 @@ command to generate the output files.
<comment xml:lang="ka">Alzip არქივი</comment>
<comment xml:lang="ja">Alzip アーカイブ</comment>
<comment xml:lang="it">Archivio Alzip</comment>
+ <comment xml:lang="is">Alzip safnskrá</comment>
<comment xml:lang="id">Arsip Alzip</comment>
<comment xml:lang="ia">Archivo Alzip</comment>
<comment xml:lang="hu">Alzip archívum</comment>
@@ -19724,12 +20668,13 @@ command to generate the output files.
<comment xml:lang="eo">Alzip-arkivo</comment>
<comment xml:lang="en_GB">Alzip archive</comment>
<comment xml:lang="el">Συμπιεσμένο αρχείο Alzip</comment>
- <comment xml:lang="de">Alzip-Archiv</comment>
+ <comment xml:lang="de">ALZip-Archiv</comment>
<comment xml:lang="da">Alzip-arkiv</comment>
<comment xml:lang="cs">archiv Alzip</comment>
<comment xml:lang="ca">arxiu Alzip</comment>
<comment xml:lang="bg">Архив — alzip</comment>
<comment xml:lang="be@latin">Archiŭ Alzip</comment>
+ <comment xml:lang="be">архіў Alzip</comment>
<comment xml:lang="ar">أرشيف Alzip</comment>
<comment xml:lang="af">Alzip-argief</comment>
<generic-icon name="package-x-generic"/>
@@ -19739,56 +20684,17 @@ command to generate the output files.
<glob pattern="*.alz"/>
</mime-type>
<mime-type type="text/x-reject">
- <comment>rejected patch</comment>
- <comment xml:lang="zh_TW">回絕的修補</comment>
- <comment xml:lang="zh_CN">拒绝的补丁</comment>
- <comment xml:lang="vi">đắp vá bị từ chối</comment>
- <comment xml:lang="uk">відхилена латка</comment>
- <comment xml:lang="tr">reddedilmiş yama</comment>
- <comment xml:lang="sv">avvisad programfix</comment>
- <comment xml:lang="sr">одбијена закрпа</comment>
- <comment xml:lang="sq">Patch i kthyer mbrapsht</comment>
- <comment xml:lang="sl">zavrnjen popravek</comment>
- <comment xml:lang="sk">Odmietnutá záplata</comment>
+ <comment>Rejected patch</comment>
+ <comment xml:lang="uk">відкинута латка</comment>
+ <comment xml:lang="sv">Avvisad programfix</comment>
<comment xml:lang="ru">Отклонённый патч</comment>
- <comment xml:lang="ro">petec respsins</comment>
- <comment xml:lang="pt_BR">Arquivo de patch rejeitado</comment>
- <comment xml:lang="pt">patch rejeitado</comment>
<comment xml:lang="pl">Odrzucona łata</comment>
- <comment xml:lang="oc">correctiu regetat</comment>
- <comment xml:lang="nn">avvist programfiks</comment>
- <comment xml:lang="nl">verworpen patch</comment>
- <comment xml:lang="nb">avvist patchfil</comment>
- <comment xml:lang="ms">Tampungan ditolak</comment>
- <comment xml:lang="lv">noraidītais ceļš</comment>
- <comment xml:lang="lt">atmestas lopas</comment>
- <comment xml:lang="ko">거부된 패치 파일</comment>
- <comment xml:lang="kk">алынбаған патч</comment>
- <comment xml:lang="ja">拒否されたパッチ</comment>
<comment xml:lang="it">Patch rifiutata</comment>
- <comment xml:lang="id">patch ditolak</comment>
- <comment xml:lang="ia">Patch rejectate</comment>
- <comment xml:lang="hu">visszautasított folt</comment>
- <comment xml:lang="hr">Odbijena zakrpa</comment>
- <comment xml:lang="he">טלאי שנדחה</comment>
- <comment xml:lang="gl">parche rexeitado</comment>
- <comment xml:lang="ga">paiste diúltaithe</comment>
- <comment xml:lang="fur">blec refudât</comment>
- <comment xml:lang="fr">correctif rejeté</comment>
- <comment xml:lang="fo">vrakað rætting</comment>
- <comment xml:lang="fi">hylättyjen muutosten tiedosto</comment>
- <comment xml:lang="eu">baztertutako adabakia</comment>
+ <comment xml:lang="gl">Parche rexeitado</comment>
+ <comment xml:lang="eu">Baztertutako adabakia</comment>
<comment xml:lang="es">parche rechazado</comment>
- <comment xml:lang="eo">reĵeta flikaĵo</comment>
- <comment xml:lang="en_GB">rejected patch</comment>
- <comment xml:lang="el">Διόρθωση που απορρίφθηκε</comment>
<comment xml:lang="de">Abgelehnter Patch</comment>
- <comment xml:lang="da">afvist rettelse</comment>
- <comment xml:lang="cs">odmítnutá záplata</comment>
- <comment xml:lang="ca">pedaç rebutjat</comment>
- <comment xml:lang="bg">Отхвърлен файл с кръпка</comment>
- <comment xml:lang="be@latin">niepryniaty patch</comment>
- <comment xml:lang="ar">رقعة مرفوضة</comment>
+ <comment xml:lang="be">адхілены патч</comment>
<sub-class-of type="text/plain"/>
<generic-icon name="text-x-generic"/>
<alias type="application/x-reject"/>
@@ -19803,8 +20709,9 @@ command to generate the output files.
<comment xml:lang="tr">RPM paketi</comment>
<comment xml:lang="sv">RPM-paket</comment>
<comment xml:lang="sr">РПМ пакет</comment>
- <comment xml:lang="sq">Paketë RPM</comment>
+ <comment xml:lang="sq">paketë RPM</comment>
<comment xml:lang="sl">Datoteka paketa RPM</comment>
+ <comment xml:lang="si">RPM පැකේජය</comment>
<comment xml:lang="sk">Balík RPM</comment>
<comment xml:lang="ru">Пакет RPM</comment>
<comment xml:lang="ro">Pachet RPM</comment>
@@ -19822,6 +20729,7 @@ command to generate the output files.
<comment xml:lang="kk">RPM дестесі</comment>
<comment xml:lang="ja">RPM パッケージ</comment>
<comment xml:lang="it">Pacchetto RPM</comment>
+ <comment xml:lang="is">RPM pakki</comment>
<comment xml:lang="id">Paket RPM</comment>
<comment xml:lang="ia">Pacchetto RPM</comment>
<comment xml:lang="hu">RPM-csomag</comment>
@@ -19844,6 +20752,7 @@ command to generate the output files.
<comment xml:lang="ca">paquet RPM</comment>
<comment xml:lang="bg">Пакет — RPM</comment>
<comment xml:lang="be@latin">Pakunak RPM</comment>
+ <comment xml:lang="be">пакет RPM</comment>
<comment xml:lang="ar">حزمة RPM</comment>
<comment xml:lang="af">RPM-pakket</comment>
<generic-icon name="package-x-generic"/>
@@ -19861,18 +20770,22 @@ command to generate the output files.
<comment xml:lang="tr">Kaynak RPM paketi</comment>
<comment xml:lang="sv">Käll-RPM-paket</comment>
<comment xml:lang="sr">изворни РПМ пакет</comment>
+ <comment xml:lang="sq">paketë RPM burimi</comment>
<comment xml:lang="sl">Paket izvorne kode RPM</comment>
+ <comment xml:lang="si">මූලාශ්‍ර RPM පැකේජය</comment>
<comment xml:lang="sk">Zdrojový balík RPM</comment>
<comment xml:lang="ru">Пакет RPM с исходным кодом</comment>
<comment xml:lang="pt_BR">Pacote fonte RPM</comment>
<comment xml:lang="pt">pacote origem RPM</comment>
<comment xml:lang="pl">Źródłowy pakiet RPM</comment>
<comment xml:lang="oc">paquet font RPM</comment>
+ <comment xml:lang="nl">Source RPM-pakket</comment>
<comment xml:lang="lv">Avota RPM pakotne</comment>
<comment xml:lang="ko">소스 RPM 패키지</comment>
<comment xml:lang="kk">RPM бастапқы код дестесі</comment>
<comment xml:lang="ja">ソース RPM パッケージ</comment>
<comment xml:lang="it">Pacchetto sorgente RPM</comment>
+ <comment xml:lang="is">RPM grunnkóðapakki</comment>
<comment xml:lang="id">Paket RPM sumber</comment>
<comment xml:lang="ia">Pacchetto de fonte RPM</comment>
<comment xml:lang="hu">Forrás RPM-csomag</comment>
@@ -19887,11 +20800,12 @@ command to generate the output files.
<comment xml:lang="es">paquete de fuente RPM</comment>
<comment xml:lang="en_GB">Source RPM package</comment>
<comment xml:lang="el">Πακέτο πηγής RPM</comment>
- <comment xml:lang="de">Quell-RPM-Paket</comment>
+ <comment xml:lang="de">RPM-Quellpaket</comment>
<comment xml:lang="da">Kilde RPM-pakke</comment>
<comment xml:lang="cs">zdrojový balíček RPM</comment>
<comment xml:lang="ca">paquet RPM de codi font</comment>
<comment xml:lang="bg">Пакет — RPM с изходен код</comment>
+ <comment xml:lang="be">пакет RPM з зыходным кодам</comment>
<comment xml:lang="ar">حزمة RPM مصدرية</comment>
<comment xml:lang="af">Bron-RPM-pakket</comment>
<generic-icon name="package-x-generic"/>
@@ -19908,8 +20822,9 @@ command to generate the output files.
<comment xml:lang="tr">Ruby betiği</comment>
<comment xml:lang="sv">Ruby-skript</comment>
<comment xml:lang="sr">Руби скрипта</comment>
- <comment xml:lang="sq">Script Ruby</comment>
+ <comment xml:lang="sq">programth Ruby</comment>
<comment xml:lang="sl">Skriptna datoteka Ruby</comment>
+ <comment xml:lang="si">Ruby පිටපත</comment>
<comment xml:lang="sk">Skript Ruby</comment>
<comment xml:lang="ru">Сценарий Ruby</comment>
<comment xml:lang="ro">Script Ruby</comment>
@@ -19927,6 +20842,7 @@ command to generate the output files.
<comment xml:lang="kk">Ruby сценарийі</comment>
<comment xml:lang="ja">Ruby スクリプト</comment>
<comment xml:lang="it">Script Ruby</comment>
+ <comment xml:lang="is">Ruby skrifta</comment>
<comment xml:lang="id">Skrip Ruby</comment>
<comment xml:lang="ia">Script Ruby</comment>
<comment xml:lang="hu">Ruby-parancsfájl</comment>
@@ -19949,6 +20865,7 @@ command to generate the output files.
<comment xml:lang="ca">script Ruby</comment>
<comment xml:lang="bg">Скрипт — Ruby</comment>
<comment xml:lang="be@latin">Skrypt Ruby</comment>
+ <comment xml:lang="be">скрыпт Ruby</comment>
<comment xml:lang="ar">سكربت روبي</comment>
<comment xml:lang="af">Ruby-skrip</comment>
<sub-class-of type="application/x-executable"/>
@@ -19969,8 +20886,9 @@ command to generate the output files.
<comment xml:lang="tr">Markaby betiği</comment>
<comment xml:lang="sv">Markaby-skript</comment>
<comment xml:lang="sr">Маркаби скрипта</comment>
- <comment xml:lang="sq">Script Markaby</comment>
+ <comment xml:lang="sq">programth Markaby</comment>
<comment xml:lang="sl">Skriptna datoteka Markaby</comment>
+ <comment xml:lang="si">Markaby පිටපත</comment>
<comment xml:lang="sk">Skript Markaby</comment>
<comment xml:lang="ru">Сценарий Markaby</comment>
<comment xml:lang="ro">Script Markaby</comment>
@@ -19988,6 +20906,7 @@ command to generate the output files.
<comment xml:lang="ka">Markaby-ის სცენარი</comment>
<comment xml:lang="ja">Markaby スクリプト</comment>
<comment xml:lang="it">Script Markaby</comment>
+ <comment xml:lang="is">Markaby skrifta</comment>
<comment xml:lang="id">Skrip Markaby</comment>
<comment xml:lang="ia">Script Markaby</comment>
<comment xml:lang="hu">Markaby parancsfájl</comment>
@@ -20010,6 +20929,7 @@ command to generate the output files.
<comment xml:lang="ca">script Markaby</comment>
<comment xml:lang="bg">Скрипт — Markaby</comment>
<comment xml:lang="be@latin">Skrypt Markaby</comment>
+ <comment xml:lang="be">скрыпт Markaby</comment>
<comment xml:lang="ar">سكربت Markaby</comment>
<comment xml:lang="af">Markaby-skrip</comment>
<sub-class-of type="application/x-ruby"/>
@@ -20018,34 +20938,79 @@ command to generate the output files.
</mime-type>
<mime-type type="text/x-crystal">
<comment>Crystal source code</comment>
+ <comment xml:lang="zh_TW">Crystal 原始碼</comment>
+ <comment xml:lang="zh_CN">Crystal 源代码</comment>
+ <comment xml:lang="uk">початковий код мовою Crystal</comment>
+ <comment xml:lang="tr">Crystal kaynak kodu</comment>
+ <comment xml:lang="sv">Crystal-källkod</comment>
+ <comment xml:lang="sl">Izvorna koda Crystal</comment>
+ <comment xml:lang="si">Crystal source code</comment>
+ <comment xml:lang="ru">Исходный код Crystal</comment>
+ <comment xml:lang="pl">Kod źródłowy Crystal</comment>
+ <comment xml:lang="oc">còdi font Crystal</comment>
+ <comment xml:lang="nl">Crystal-broncode</comment>
+ <comment xml:lang="ko">Crystal 소스 코드</comment>
+ <comment xml:lang="kk">Crystal бастапқы коды</comment>
+ <comment xml:lang="ja">Crystal ソースコード</comment>
+ <comment xml:lang="it">Codice sorgente Crystal</comment>
+ <comment xml:lang="hr">Crystal izvorni kôd</comment>
+ <comment xml:lang="gl">Código fonte en Crystal</comment>
+ <comment xml:lang="fi">Crystal-lähdekoodi</comment>
+ <comment xml:lang="eu">Crystal iturburu-kodea</comment>
+ <comment xml:lang="es">código fuente en Crystal</comment>
+ <comment xml:lang="en_GB">Crystal source code</comment>
+ <comment xml:lang="de">Crystal-Quelltext</comment>
+ <comment xml:lang="be">зыходны код Crystal</comment>
+ <comment xml:lang="ar">شفرة مصدر Crystal</comment>
<sub-class-of type="text/plain"/>
<glob pattern="*.cr"/>
<alias type="text/crystal"/>
</mime-type>
+ <mime-type type="text/julia">
+ <comment>Julia source code</comment>
+ <comment xml:lang="uk">початковий код Julia</comment>
+ <comment xml:lang="sv">Julia-källkod</comment>
+ <comment xml:lang="ru">Исходный код Julia</comment>
+ <comment xml:lang="pl">Kod źródłowy Julia</comment>
+ <comment xml:lang="ja">Julia算譜</comment>
+ <comment xml:lang="it">Codice sorgente Julia</comment>
+ <comment xml:lang="gl">Código fonte en Julia</comment>
+ <comment xml:lang="eu">Julia iturburu-kodea</comment>
+ <comment xml:lang="es">código fuente en Julia</comment>
+ <comment xml:lang="de">Julia-Quelltext</comment>
+ <comment xml:lang="be">зыходны код Julia</comment>
+ <sub-class-of type="text/plain"/>
+ <glob pattern="*.jl"/>
+ </mime-type>
<mime-type type="text/rust">
<comment>Rust source code</comment>
<comment xml:lang="zh_TW">Rust 源碼</comment>
<comment xml:lang="zh_CN">Rust 源代码</comment>
- <comment xml:lang="uk">вихідний код мовою Rust</comment>
+ <comment xml:lang="uk">початковий код мовою Rust</comment>
<comment xml:lang="tr">Rust kaynak kodu</comment>
<comment xml:lang="sv">Rust-källkod</comment>
<comment xml:lang="sr">Раст изворни ко̂д</comment>
+ <comment xml:lang="sq">kod burim Rust</comment>
<comment xml:lang="sl">Izvorna koda Rust</comment>
+ <comment xml:lang="si">මලකඩ මූලාශ්ර කේතය</comment>
<comment xml:lang="sk">Zdrojový kód Rust</comment>
<comment xml:lang="ru">Исходный код Rust</comment>
<comment xml:lang="pt_BR">Código-fonte Rust</comment>
<comment xml:lang="pt">código origem Rust</comment>
<comment xml:lang="pl">Kod źródłowy Rust</comment>
<comment xml:lang="oc">còde font Rust</comment>
+ <comment xml:lang="nl">Rust-broncode</comment>
<comment xml:lang="ko">Rust 소스 코드</comment>
<comment xml:lang="kk">Rust бастапқы коды</comment>
<comment xml:lang="ja">Rust ソースコード</comment>
<comment xml:lang="it">Codice sorgente Rust</comment>
+ <comment xml:lang="is">Rust frumkóði</comment>
<comment xml:lang="id">Kode program Rust</comment>
<comment xml:lang="ia">Codice-fonte Rust</comment>
<comment xml:lang="hu">Rust forrásfájl</comment>
<comment xml:lang="hr">Rust izvorni kôd</comment>
<comment xml:lang="he">קוד מקור של Rust</comment>
+ <comment xml:lang="gl">Código fonte en Rust</comment>
<comment xml:lang="ga">cód foinseach Rust</comment>
<comment xml:lang="fur">codiç sorzint Rust</comment>
<comment xml:lang="fr">code source Rust</comment>
@@ -20059,6 +21024,7 @@ command to generate the output files.
<comment xml:lang="cs">zdrojový kód v jazyce Rust</comment>
<comment xml:lang="ca">codi font en Rust</comment>
<comment xml:lang="bg">Изходен код — Rust</comment>
+ <comment xml:lang="be">зыходны код Rust</comment>
<comment xml:lang="ar">شفرة مصدر رست</comment>
<comment xml:lang="af">Rust-bronkode</comment>
<sub-class-of type="text/plain"/>
@@ -20069,12 +21035,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">SC/Xspread 試算表</comment>
<comment xml:lang="zh_CN">SC/Xspread 电子表格</comment>
<comment xml:lang="vi">Bảng tính SC/Xspread</comment>
- <comment xml:lang="uk">ел. таблиця SC/Xspread</comment>
+ <comment xml:lang="uk">електронна таблиця SC/Xspread</comment>
<comment xml:lang="tr">SC/Xspread hesap çizelgesi</comment>
<comment xml:lang="sv">SC/Xspread-kalkylblad</comment>
<comment xml:lang="sr">табела СЦ/Икс-табеле</comment>
- <comment xml:lang="sq">Fletë llogaritjesh SC/Xspread</comment>
+ <comment xml:lang="sq">fletëllogaritje SC/Xspread</comment>
<comment xml:lang="sl">Preglednica SC/Xspread</comment>
+ <comment xml:lang="si">SC/Xspread පැතුරුම්පත</comment>
<comment xml:lang="sk">Zošit SC/Xspread</comment>
<comment xml:lang="ru">Электронная таблица SC/Xspread</comment>
<comment xml:lang="ro">Foaie de calcul SC/Xspread</comment>
@@ -20091,6 +21058,7 @@ command to generate the output files.
<comment xml:lang="kk">SC/Xspread электрондық кестесі</comment>
<comment xml:lang="ja">SC/Xspread スプレッドシート</comment>
<comment xml:lang="it">Foglio di calcolo SC/Xspread</comment>
+ <comment xml:lang="is">SC/Xspread töflureikniskjal</comment>
<comment xml:lang="id">Lembar sebar SC/Xspread</comment>
<comment xml:lang="ia">Folio de calculo SC/Xspread</comment>
<comment xml:lang="hu">SC/Xspread táblázat</comment>
@@ -20107,12 +21075,13 @@ command to generate the output files.
<comment xml:lang="eo">SC/Xspread-kalkultabelo</comment>
<comment xml:lang="en_GB">SC/Xspread spreadsheet</comment>
<comment xml:lang="el">Λογιστικό φύλλο SC/Xspread</comment>
- <comment xml:lang="de">SX/Xspread-Tabelle</comment>
+ <comment xml:lang="de">SC/Xspread-Tabelle</comment>
<comment xml:lang="da">SC/Xspread-regneark</comment>
<comment xml:lang="cs">sešit SC/Xspread</comment>
<comment xml:lang="ca">full de càlcul de SC/Xspread</comment>
<comment xml:lang="bg">Таблица — SC/Xspread</comment>
<comment xml:lang="be@latin">Raźlikovy arkuš SC/Xspread</comment>
+ <comment xml:lang="be">электронная табліца SC/Xspread</comment>
<comment xml:lang="ar">جدول SC/Xspread</comment>
<comment xml:lang="af">SC/Xspread-sigblad</comment>
<generic-icon name="x-office-spreadsheet"/>
@@ -20121,170 +21090,49 @@ command to generate the output files.
</magic>
</mime-type>
<mime-type type="application/x-shar">
- <comment>shell archive</comment>
- <comment xml:lang="zh_TW">shell 封存檔</comment>
- <comment xml:lang="zh_CN">shell 归档文件</comment>
- <comment xml:lang="vi">kho trình bao</comment>
+ <comment>Shell archive</comment>
<comment xml:lang="uk">архів оболонки</comment>
- <comment xml:lang="tr">kabuk arşivi</comment>
- <comment xml:lang="sv">skalarkiv</comment>
- <comment xml:lang="sr">архива љуске</comment>
- <comment xml:lang="sq">Arkiv shell</comment>
- <comment xml:lang="sl">lupinski arhiv</comment>
- <comment xml:lang="sk">Archív shellu</comment>
+ <comment xml:lang="sv">Skalarkiv</comment>
<comment xml:lang="ru">Архив shell</comment>
- <comment xml:lang="ro">arhivă shell</comment>
- <comment xml:lang="pt_BR">Pacote shell</comment>
- <comment xml:lang="pt">arquivo de terminal</comment>
<comment xml:lang="pl">Archiwum powłoki</comment>
- <comment xml:lang="oc">archiu shell</comment>
- <comment xml:lang="nn">skal-arkiv</comment>
- <comment xml:lang="nl">shell-archief</comment>
- <comment xml:lang="nb">skallarkiv</comment>
- <comment xml:lang="ms">Arkib shell</comment>
- <comment xml:lang="lv">čaulas arhīvs</comment>
- <comment xml:lang="lt">shell archyvas</comment>
- <comment xml:lang="ko">셸 압축 파일</comment>
- <comment xml:lang="kk">қоршам архиві</comment>
- <comment xml:lang="ja">シェルアーカイブ</comment>
+ <comment xml:lang="ja">シェル自己解凍ファイル</comment>
<comment xml:lang="it">Archivio shell</comment>
- <comment xml:lang="id">arsip shell</comment>
- <comment xml:lang="ia">Archivo de shell</comment>
- <comment xml:lang="hu">héjarchívum</comment>
- <comment xml:lang="hr">Arhiva ljuske</comment>
- <comment xml:lang="he">ארכיון מעטפת</comment>
- <comment xml:lang="gl">ficheiro shell</comment>
- <comment xml:lang="ga">cartlann bhlaoisce</comment>
- <comment xml:lang="fur">archivi shell</comment>
- <comment xml:lang="fr">archive shell</comment>
- <comment xml:lang="fo">skel savn</comment>
- <comment xml:lang="fi">komentotulkkiarkisto</comment>
- <comment xml:lang="eu">shell artxiboa</comment>
- <comment xml:lang="es">archivador shell</comment>
- <comment xml:lang="eo">ŝel-arkivo</comment>
- <comment xml:lang="en_GB">shell archive</comment>
- <comment xml:lang="el">Αρχείο κέλυφους</comment>
+ <comment xml:lang="gl">Arquivo de Shell</comment>
+ <comment xml:lang="eu">Shell artxiboa</comment>
+ <comment xml:lang="es">archivador Shell</comment>
<comment xml:lang="de">Shell-Archiv</comment>
- <comment xml:lang="da">skal-arkiv</comment>
- <comment xml:lang="cy">archif plisgyn</comment>
- <comment xml:lang="cs">archiv shellu</comment>
- <comment xml:lang="ca">arxiu de shell</comment>
- <comment xml:lang="bg">Архив на обвивката</comment>
- <comment xml:lang="be@latin">archiŭ abałonki</comment>
- <comment xml:lang="az">qabıq arxivi</comment>
- <comment xml:lang="ar">أرشيف شِل</comment>
- <comment xml:lang="af">shell-argief</comment>
+ <comment xml:lang="be">архіў абалонкі</comment>
<generic-icon name="package-x-generic"/>
<glob pattern="*.shar"/>
</mime-type>
<mime-type type="application/x-shared-library-la">
- <comment>libtool shared library</comment>
- <comment xml:lang="zh_TW">libtool 共享函式庫</comment>
- <comment xml:lang="zh_CN">libtool 共享库</comment>
- <comment xml:lang="vi">thư viện dùng chung libtool</comment>
+ <comment>Libtool shared library</comment>
<comment xml:lang="uk">спільна бібліотека libtool</comment>
- <comment xml:lang="tr">libtool paylaşımlı kitaplığı</comment>
- <comment xml:lang="sv">delat libtool-bibliotek</comment>
- <comment xml:lang="sr">дељена библиотека библ-алата</comment>
- <comment xml:lang="sq">Librari e përbashkët libtool</comment>
- <comment xml:lang="sl">Souporabna knjižnica libtool</comment>
- <comment xml:lang="sk">Zdieľaná knižnica libtool</comment>
+ <comment xml:lang="sv">Delat libtool-bibliotek</comment>
<comment xml:lang="ru">Разделяемая библиотека libtool</comment>
- <comment xml:lang="ro">bibliotecă partajată libtool</comment>
- <comment xml:lang="pt_BR">Biblioteca compartilhada libtool</comment>
- <comment xml:lang="pt">biblioteca partilhada libtool</comment>
<comment xml:lang="pl">Biblioteka współdzielona libtool</comment>
- <comment xml:lang="oc">bibliotèca partejada libtool</comment>
- <comment xml:lang="nn">libtool delt bibliotek</comment>
- <comment xml:lang="nl">gedeelde libtool-bibliotheek</comment>
- <comment xml:lang="nb">libtool delt bibliotek</comment>
- <comment xml:lang="lv">libtool koplietotā bibliotēka</comment>
- <comment xml:lang="lt">libtool bendroji biblioteka</comment>
- <comment xml:lang="ko">libtool 공유 라이브러리</comment>
- <comment xml:lang="kk">libtool ортақ жинағы</comment>
- <comment xml:lang="ja">libtool 共有ライブラリ</comment>
<comment xml:lang="it">Libreria condivisa libtool</comment>
- <comment xml:lang="id">pustaka bersama libtool</comment>
- <comment xml:lang="ia">Bibliotheca commun Libtool</comment>
- <comment xml:lang="hu">libtool osztott programkönyvtár</comment>
- <comment xml:lang="hr">libtool dijeljena biblioteka</comment>
- <comment xml:lang="he">ספרייה משותפת של libtool</comment>
- <comment xml:lang="gl">biblioteca compartida de libtool</comment>
- <comment xml:lang="ga">comhleabharlann libtool</comment>
- <comment xml:lang="fur">librarie condividude libtool</comment>
- <comment xml:lang="fr">bibliothèque partagée libtool</comment>
- <comment xml:lang="fo">libtool felagssavn</comment>
- <comment xml:lang="fi">jaettu libtool-kirjasto</comment>
- <comment xml:lang="eu">libtool partekatutako liburutegia</comment>
- <comment xml:lang="es">biblioteca compartida de libtool</comment>
- <comment xml:lang="en_GB">libtool shared library</comment>
- <comment xml:lang="el">Κοινόχρηστη βιβλιοθήκη libtool</comment>
+ <comment xml:lang="eu">Libtool liburutegi partekatua</comment>
+ <comment xml:lang="es">biblioteca compartida de Libtool</comment>
<comment xml:lang="de">Gemeinsame libtool-Bibliothek</comment>
- <comment xml:lang="da">libtool delt bibliotek</comment>
- <comment xml:lang="cs">sdílená knihovna libtool</comment>
- <comment xml:lang="ca">biblioteca compartida libtool</comment>
- <comment xml:lang="bg">Споделена библиотека — libtool</comment>
- <comment xml:lang="be@latin">supolnaja biblijateka libtool</comment>
- <comment xml:lang="ar">مكتبة libtool مشتركة</comment>
- <comment xml:lang="af">libtool- gedeelde biblioteek</comment>
+ <comment xml:lang="be">агульная бібліятэка libtool</comment>
<sub-class-of type="text/plain"/>
<generic-icon name="text-x-script"/>
<glob pattern="*.la"/>
</mime-type>
<mime-type type="application/x-sharedlib">
- <comment>shared library</comment>
- <comment xml:lang="zh_TW">共享函式庫</comment>
- <comment xml:lang="zh_CN">共享库</comment>
- <comment xml:lang="vi">thư viện dùng chung</comment>
+ <comment>Shared library</comment>
<comment xml:lang="uk">спільна бібліотека</comment>
- <comment xml:lang="tr">paylaşımlı kitaplık</comment>
- <comment xml:lang="sv">delat bibliotek</comment>
- <comment xml:lang="sr">дељена библиотека</comment>
- <comment xml:lang="sq">Librari e përbashkët</comment>
- <comment xml:lang="sl">souporabljena knjižnica</comment>
- <comment xml:lang="sk">Zdieľaná knižnica</comment>
+ <comment xml:lang="sv">Delat bibliotek</comment>
<comment xml:lang="ru">Разделяемая библиотека</comment>
- <comment xml:lang="ro">bibliotecă partajată</comment>
- <comment xml:lang="pt_BR">Biblioteca compartilhada</comment>
- <comment xml:lang="pt">biblioteca partilhada</comment>
<comment xml:lang="pl">Biblioteka współdzielona</comment>
- <comment xml:lang="oc">bibliotèca partejada</comment>
- <comment xml:lang="nn">delt bibliotek</comment>
- <comment xml:lang="nl">gedeelde bibliotheek</comment>
- <comment xml:lang="nb">delt bibliotek</comment>
- <comment xml:lang="ms">Pustaka terkongsi</comment>
- <comment xml:lang="lv">koplietotā bibliotēka</comment>
- <comment xml:lang="lt">bendroji biblioteka</comment>
- <comment xml:lang="ko">공유 라이브러리</comment>
- <comment xml:lang="kk">бөлісетін библиотека</comment>
<comment xml:lang="ja">共有ライブラリ</comment>
<comment xml:lang="it">Libreria condivisa</comment>
- <comment xml:lang="id">pustaka bersama</comment>
- <comment xml:lang="ia">Bibliotheca commun</comment>
- <comment xml:lang="hu">osztott programkönyvtár</comment>
- <comment xml:lang="hr">dijeljena biblioteka</comment>
- <comment xml:lang="he">ספרייה משותפת</comment>
- <comment xml:lang="gl">biblioteca compartida</comment>
- <comment xml:lang="ga">comhleabharlann</comment>
- <comment xml:lang="fur">librarie condividude</comment>
- <comment xml:lang="fr">bibliothèque partagée</comment>
- <comment xml:lang="fo">felagssavn</comment>
- <comment xml:lang="fi">jaettu kirjasto</comment>
- <comment xml:lang="eu">partekatutako liburutegia</comment>
+ <comment xml:lang="gl">Biblioteca compartida</comment>
+ <comment xml:lang="eu">Liburutegi partekatua</comment>
<comment xml:lang="es">biblioteca compartida</comment>
- <comment xml:lang="eo">dinamike bindebla biblioteko</comment>
- <comment xml:lang="en_GB">shared library</comment>
- <comment xml:lang="el">Αρχείο κοινόχρηστης βιβλιοθήκης</comment>
- <comment xml:lang="de">Gemeinsame Bibliothek</comment>
- <comment xml:lang="da">delt bibliotek</comment>
- <comment xml:lang="cy">llyfrgell wedi ei rhannu</comment>
- <comment xml:lang="cs">sdílená knihovna</comment>
- <comment xml:lang="ca">biblioteca compartida</comment>
- <comment xml:lang="bg">Споделена библиотека</comment>
- <comment xml:lang="be@latin">supolnaja biblijateka</comment>
- <comment xml:lang="az">bölüşülmüş kitabxana</comment>
- <comment xml:lang="ar">مكتبة مشتركة</comment>
- <comment xml:lang="af">gedeelde biblioteek</comment>
+ <comment xml:lang="de">Gemeinsam genutzte Bibliothek</comment>
+ <comment xml:lang="be">агульная бібліятэка</comment>
<magic>
<match type="little16" value="0603" offset="0">
<match type="little16" mask="030000" value="020000" offset="22"/>
@@ -20294,59 +21142,16 @@ command to generate the output files.
<glob weight="60" pattern="*.so.[0-9]*"/>
</mime-type>
<mime-type type="application/x-shellscript">
- <comment>shell script</comment>
- <comment xml:lang="zh_TW">shell 指令稿</comment>
- <comment xml:lang="zh_CN">shell 脚本</comment>
- <comment xml:lang="vi">văn lệnh trình bao</comment>
+ <comment>Shell script</comment>
<comment xml:lang="uk">скрипт оболонки</comment>
- <comment xml:lang="tr">kabuk betiği</comment>
- <comment xml:lang="sv">skalskript</comment>
- <comment xml:lang="sr">скрипта љуске</comment>
- <comment xml:lang="sq">Script shell</comment>
- <comment xml:lang="sl">lupinski skript</comment>
- <comment xml:lang="sk">Skript shellu</comment>
+ <comment xml:lang="sv">Skalskript</comment>
<comment xml:lang="ru">Сценарий shell</comment>
- <comment xml:lang="ro">script shell</comment>
- <comment xml:lang="pt_BR">Script shell</comment>
- <comment xml:lang="pt">script de terminal</comment>
<comment xml:lang="pl">Skrypt powłoki</comment>
- <comment xml:lang="oc">escript shell</comment>
- <comment xml:lang="nn">skalskript</comment>
- <comment xml:lang="nl">shellscript</comment>
- <comment xml:lang="nb">skallskript</comment>
- <comment xml:lang="ms">Skrip shell</comment>
- <comment xml:lang="lv">čaulas skripts</comment>
- <comment xml:lang="lt">shell scenarijus</comment>
- <comment xml:lang="ko">셸 스크립트</comment>
- <comment xml:lang="kk">қоршам сценарийі</comment>
- <comment xml:lang="ja">シェルスクリプト</comment>
<comment xml:lang="it">Script shell</comment>
- <comment xml:lang="id">skrip shell</comment>
- <comment xml:lang="ia">Script de shell</comment>
- <comment xml:lang="hu">héj-parancsfájl</comment>
- <comment xml:lang="hr">Skripta ljuske</comment>
- <comment xml:lang="he">תסריט מעטפת</comment>
- <comment xml:lang="gl">script de shell</comment>
- <comment xml:lang="ga">script bhlaoisce</comment>
- <comment xml:lang="fur">script shell</comment>
- <comment xml:lang="fr">script shell</comment>
- <comment xml:lang="fo">skel boðrøð</comment>
- <comment xml:lang="fi">komentotulkin komentotiedosto</comment>
- <comment xml:lang="eu">shell script-a</comment>
- <comment xml:lang="es">secuencia de órdenes en shell</comment>
- <comment xml:lang="eo">ŝelskripto</comment>
- <comment xml:lang="en_GB">shell script</comment>
- <comment xml:lang="el">Δέσμη ενεργειών κελύφους</comment>
+ <comment xml:lang="eu">Shell scripta</comment>
+ <comment xml:lang="es">secuencia de órdenes de consola</comment>
<comment xml:lang="de">Shell-Skript</comment>
- <comment xml:lang="da">skal-program</comment>
- <comment xml:lang="cy">sgript plisgyn</comment>
- <comment xml:lang="cs">skript shellu</comment>
- <comment xml:lang="ca">script shell</comment>
- <comment xml:lang="bg">Скрипт на обвивката</comment>
- <comment xml:lang="be@latin">skrypt abałonki</comment>
- <comment xml:lang="az">qabıq skripti</comment>
- <comment xml:lang="ar">سكربت شِل</comment>
- <comment xml:lang="af">shell-skrip</comment>
+ <comment xml:lang="be">скрыпт абалонкі</comment>
<sub-class-of type="application/x-executable"/>
<sub-class-of type="text/plain"/>
<alias type="text/x-sh"/>
@@ -20366,6 +21171,46 @@ command to generate the output files.
</magic>
<glob pattern="*.sh"/>
</mime-type>
+ <mime-type type="application/x-fishscript">
+ <comment>Fish shell script</comment>
+ <comment xml:lang="uk">скрипт оболонки fish</comment>
+ <comment xml:lang="sv">Fish-skalskript</comment>
+ <comment xml:lang="ru">Сценарий fish shell</comment>
+ <comment xml:lang="pl">Skrypt powłoki Fish</comment>
+ <comment xml:lang="it">Script shell Fish</comment>
+ <comment xml:lang="eu">Fish shell scripta</comment>
+ <comment xml:lang="es">secuencia de órdenes de consola Fish</comment>
+ <comment xml:lang="de">Fish-Shell-Skript</comment>
+ <comment xml:lang="be">скрыпт Fish shell</comment>
+ <sub-class-of type="application/x-executable"/>
+ <sub-class-of type="text/plain"/>
+ <alias type="text/x-fish"/>
+ <generic-icon name="text-x-script"/>
+ <magic>
+ <match type="string" value="/bin/env fish" offset="2:16"/>
+ </magic>
+ <glob pattern="*.fish"/>
+ </mime-type>
+ <mime-type type="application/x-nuscript">
+ <comment>Nu shell script</comment>
+ <comment xml:lang="uk">скрипт оболонки nu</comment>
+ <comment xml:lang="sv">Nu-skalskript</comment>
+ <comment xml:lang="ru">Сценарий nu shell</comment>
+ <comment xml:lang="pl">Skrypt powłoki Nu</comment>
+ <comment xml:lang="it">Script shell Nu</comment>
+ <comment xml:lang="eu">Nu shell scripta</comment>
+ <comment xml:lang="es">secuencia de órdenes de consola Nu</comment>
+ <comment xml:lang="de">Nu-Shell-Skript</comment>
+ <comment xml:lang="be">скрыпт Nu shell</comment>
+ <sub-class-of type="application/x-executable"/>
+ <sub-class-of type="text/plain"/>
+ <alias type="text/x-nu"/>
+ <generic-icon name="text-x-script"/>
+ <magic>
+ <match type="string" value="/bin/env nu" offset="2:16"/>
+ </magic>
+ <glob pattern="*.nu"/>
+ </mime-type>
<mime-type type="application/vnd.adobe.flash.movie">
<comment>Shockwave Flash file</comment>
<comment xml:lang="zh_TW">Shockwave Flash 檔案</comment>
@@ -20375,8 +21220,9 @@ command to generate the output files.
<comment xml:lang="tr">Shockwave Flash dosyası</comment>
<comment xml:lang="sv">Shockwave Flash-fil</comment>
<comment xml:lang="sr">Шоквејв Флеш датотека</comment>
- <comment xml:lang="sq">File Flash Shockwave</comment>
+ <comment xml:lang="sq">kartelë Shockwave Flash</comment>
<comment xml:lang="sl">Datoteka Shockwave Flash</comment>
+ <comment xml:lang="si">කම්පන තරංග ෆ්ලෑෂ් ගොනුව</comment>
<comment xml:lang="sk">Súbor Shockwave Flash</comment>
<comment xml:lang="ru">Файл Shockwave Flash</comment>
<comment xml:lang="ro">Fișier Shockwave Flash</comment>
@@ -20394,6 +21240,7 @@ command to generate the output files.
<comment xml:lang="kk">Shockwave Flash файлы</comment>
<comment xml:lang="ja">Shockwave Flash ファイル</comment>
<comment xml:lang="it">File Shockwave Flash</comment>
+ <comment xml:lang="is">Shockwave Flash skrá</comment>
<comment xml:lang="id">Berkas Shockwave Flash</comment>
<comment xml:lang="ia">File Shockwave Flash</comment>
<comment xml:lang="hu">Shockwave Flash-fájl</comment>
@@ -20416,6 +21263,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer Shockwave Flash</comment>
<comment xml:lang="bg">Файл — Shockwave Flash</comment>
<comment xml:lang="be@latin">Fajł Shockwave Flash</comment>
+ <comment xml:lang="be">файл Shockwave Flash</comment>
<comment xml:lang="ar">ملف Shockwave Flash</comment>
<comment xml:lang="af">Shockwave Flash-lêer</comment>
<alias type="application/x-shockwave-flash"/>
@@ -20438,8 +21286,9 @@ command to generate the output files.
<comment xml:lang="tr">Shorten sesi</comment>
<comment xml:lang="sv">Shorten-ljud</comment>
<comment xml:lang="sr">Шортен звук</comment>
- <comment xml:lang="sq">Audio Shorten</comment>
+ <comment xml:lang="sq">audio Shorten</comment>
<comment xml:lang="sl">Zvočna datoteka Shorten</comment>
+ <comment xml:lang="si">ශ්රව්ය උපකරණ කෙටි කරන්න</comment>
<comment xml:lang="sk">Zvuk Shorten</comment>
<comment xml:lang="ru">Аудио Shorten</comment>
<comment xml:lang="ro">Audio Shorten</comment>
@@ -20456,6 +21305,7 @@ command to generate the output files.
<comment xml:lang="kk">Shorten аудиосы</comment>
<comment xml:lang="ja">Shorten オーディオ</comment>
<comment xml:lang="it">Audio Shorten</comment>
+ <comment xml:lang="is">Shorten hljóðskrá</comment>
<comment xml:lang="id">Audio Shorten</comment>
<comment xml:lang="ia">Audio Shorten</comment>
<comment xml:lang="hu">Shorten hang</comment>
@@ -20478,6 +21328,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio de Shorten</comment>
<comment xml:lang="bg">Аудио — Shorten</comment>
<comment xml:lang="be@latin">Aŭdyjo Shorten</comment>
+ <comment xml:lang="be">аўдыя Shorten</comment>
<comment xml:lang="ar">صوت Shorten</comment>
<comment xml:lang="af">Shorten-oudio</comment>
<generic-icon name="audio-x-generic"/>
@@ -20492,12 +21343,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">Siag 試算表</comment>
<comment xml:lang="zh_CN">Siag 电子表格</comment>
<comment xml:lang="vi">Bảng tính Slag</comment>
- <comment xml:lang="uk">ел. таблиця Siag</comment>
+ <comment xml:lang="uk">електронна таблиця Siag</comment>
<comment xml:lang="tr">Siag hesap çizelgesi</comment>
<comment xml:lang="sv">Siag-kalkylblad</comment>
<comment xml:lang="sr">Сјаг табела</comment>
- <comment xml:lang="sq">Fletë llogaritjesh Siag</comment>
+ <comment xml:lang="sq">fletëllogaritje Siag</comment>
<comment xml:lang="sl">Preglednica Siag</comment>
+ <comment xml:lang="si">Siag පැතුරුම්පත</comment>
<comment xml:lang="sk">Zošit Siag</comment>
<comment xml:lang="ru">Электронная таблица Siag</comment>
<comment xml:lang="ro">Foaie de calcul Siag</comment>
@@ -20515,6 +21367,7 @@ command to generate the output files.
<comment xml:lang="kk">Siag электрондық кестесі</comment>
<comment xml:lang="ja">Siag スプレッドシート</comment>
<comment xml:lang="it">Foglio di calcolo Siag</comment>
+ <comment xml:lang="is">Siag töflureikniskjal</comment>
<comment xml:lang="id">Lembar sebar Siag</comment>
<comment xml:lang="ia">Folio de calculo Siag</comment>
<comment xml:lang="hu">Siag-munkafüzet</comment>
@@ -20537,6 +21390,7 @@ command to generate the output files.
<comment xml:lang="ca">full de càlcul Siag</comment>
<comment xml:lang="bg">Таблица — Siag</comment>
<comment xml:lang="be@latin">Raźlikovy arkuš Siag</comment>
+ <comment xml:lang="be">электронная табліца Siag</comment>
<comment xml:lang="ar">جدول Siag</comment>
<comment xml:lang="af">Siag-sigblad</comment>
<generic-icon name="x-office-spreadsheet"/>
@@ -20551,8 +21405,9 @@ command to generate the output files.
<comment xml:lang="tr">Skencil belgesi</comment>
<comment xml:lang="sv">Skencil-dokument</comment>
<comment xml:lang="sr">Скенцил документ</comment>
- <comment xml:lang="sq">Dokument Skencil</comment>
+ <comment xml:lang="sq">dokument Skencil</comment>
<comment xml:lang="sl">Dokument Skencil</comment>
+ <comment xml:lang="si">ස්කෙන්සිල් ලේඛනය</comment>
<comment xml:lang="sk">Dokument Skencil</comment>
<comment xml:lang="ru">Документ Skencil</comment>
<comment xml:lang="ro">Document Skencil</comment>
@@ -20568,6 +21423,7 @@ command to generate the output files.
<comment xml:lang="kk">Skencil құжаты</comment>
<comment xml:lang="ja">Skencil ドキュメント</comment>
<comment xml:lang="it">Documento Skencil</comment>
+ <comment xml:lang="is">Skencil skjal</comment>
<comment xml:lang="id">Dokumen Skencil</comment>
<comment xml:lang="ia">Documento Skencil</comment>
<comment xml:lang="hu">Skencil-dokumentum</comment>
@@ -20590,6 +21446,7 @@ command to generate the output files.
<comment xml:lang="ca">document Skencil</comment>
<comment xml:lang="bg">Документ — Skencil</comment>
<comment xml:lang="be@latin">Dakument Skencil</comment>
+ <comment xml:lang="be">дакумент Skencil</comment>
<comment xml:lang="ast">Documentu de Skencil</comment>
<comment xml:lang="ar">مستند Skencil</comment>
<comment xml:lang="af">Skencil-dokument</comment>
@@ -20608,8 +21465,9 @@ command to generate the output files.
<comment xml:lang="tr">Stampede paketi</comment>
<comment xml:lang="sv">Stampede-paket</comment>
<comment xml:lang="sr">Стампеде пакет</comment>
- <comment xml:lang="sq">Paketë Stampede</comment>
+ <comment xml:lang="sq">paketë Stampede</comment>
<comment xml:lang="sl">Datoteka paketa Stampede</comment>
+ <comment xml:lang="si">මුද්දර පැකේජය</comment>
<comment xml:lang="sk">Balíček Stampede</comment>
<comment xml:lang="ru">Пакет Stampede</comment>
<comment xml:lang="ro">Pachet Stampede</comment>
@@ -20627,6 +21485,7 @@ command to generate the output files.
<comment xml:lang="kk">Stampede дестесі</comment>
<comment xml:lang="ja">Stampede パッケージ</comment>
<comment xml:lang="it">Pacchetto Stampede</comment>
+ <comment xml:lang="is">Stampede pakki</comment>
<comment xml:lang="id">Paket Stampede</comment>
<comment xml:lang="ia">Pacchetto Stampede</comment>
<comment xml:lang="hu">Stampede-csomag</comment>
@@ -20650,6 +21509,7 @@ command to generate the output files.
<comment xml:lang="ca">paquet Stampede</comment>
<comment xml:lang="bg">Пакет — Stampede</comment>
<comment xml:lang="be@latin">Pakunak Stampede</comment>
+ <comment xml:lang="be">пакет Stampede</comment>
<comment xml:lang="az">Stampede paketi</comment>
<comment xml:lang="ar">حزمة Stampede</comment>
<comment xml:lang="af">Stampede-pakket</comment>
@@ -20663,15 +21523,19 @@ command to generate the output files.
<comment xml:lang="tr">SG-1000 ROM</comment>
<comment xml:lang="sv">SG-1000-rom</comment>
<comment xml:lang="sr">СГ-1000 РОМ</comment>
+ <comment xml:lang="sq">ROM SG-1000</comment>
<comment xml:lang="sl">SG-1000 ROM</comment>
+ <comment xml:lang="si">SG-1000 ROM</comment>
<comment xml:lang="sk">ROM pre SG-1000</comment>
<comment xml:lang="ru">SG-1000 ROM</comment>
<comment xml:lang="pt_BR">ROM de SG-1000</comment>
<comment xml:lang="pl">Plik ROM konsoli SG-1000</comment>
+ <comment xml:lang="nl">SG-1000-ROM</comment>
<comment xml:lang="ko">SG-1000 롬</comment>
<comment xml:lang="kk">SG-1000 ROM</comment>
<comment xml:lang="ja">SG-1000 ROM</comment>
<comment xml:lang="it">ROM SG-1000</comment>
+ <comment xml:lang="is">SG-1000 ROM</comment>
<comment xml:lang="id">ROM SG-1000</comment>
<comment xml:lang="hu">SG-1000 ROM</comment>
<comment xml:lang="hr">SG-1000 ROM</comment>
@@ -20683,11 +21547,12 @@ command to generate the output files.
<comment xml:lang="eu">SG-1000 ROM</comment>
<comment xml:lang="es">ROM de SG-1000</comment>
<comment xml:lang="en_GB">SG-1000 ROM</comment>
- <comment xml:lang="de">SG-1000 ROM</comment>
+ <comment xml:lang="de">SG-1000-ROM</comment>
<comment xml:lang="da">SG-1000-ROM</comment>
<comment xml:lang="cs">ROM pro SG-1000</comment>
<comment xml:lang="ca">ROM de SG-1000</comment>
<comment xml:lang="bg">ROM — SG-1000</comment>
+ <comment xml:lang="be">SG-1000 ROM</comment>
<comment xml:lang="ar">روم SG-1000</comment>
<generic-icon name="application-x-executable"/>
<glob pattern="*.sg"/>
@@ -20701,14 +21566,18 @@ command to generate the output files.
<comment xml:lang="tr">Master System ROM</comment>
<comment xml:lang="sv">Master System-rom</comment>
<comment xml:lang="sr">Мастер Систем РОМ</comment>
+ <comment xml:lang="sq">ROM Master System</comment>
+ <comment xml:lang="si">Master System ROM</comment>
<comment xml:lang="sk">ROM pre Master System</comment>
<comment xml:lang="ru">Master System ROM</comment>
<comment xml:lang="pt_BR">ROM de Master System</comment>
<comment xml:lang="pl">Plik ROM konsoli SMS</comment>
+ <comment xml:lang="nl">Master System-ROM</comment>
<comment xml:lang="ko">마스터 시스템 롬</comment>
<comment xml:lang="kk">Master System ROM</comment>
<comment xml:lang="ja">マスターシステム ROM</comment>
<comment xml:lang="it">ROM Master System</comment>
+ <comment xml:lang="is">Master System ROM</comment>
<comment xml:lang="id">ROM Master System</comment>
<comment xml:lang="hu">Master System ROM</comment>
<comment xml:lang="hr">Master System ROM</comment>
@@ -20720,11 +21589,12 @@ command to generate the output files.
<comment xml:lang="eu">Master System ROM</comment>
<comment xml:lang="es">ROM de Master System</comment>
<comment xml:lang="en_GB">Master System ROM</comment>
- <comment xml:lang="de">Master System ROM</comment>
+ <comment xml:lang="de">Master-System-ROM</comment>
<comment xml:lang="da">Master System-ROM</comment>
<comment xml:lang="cs">ROM pro Master System</comment>
<comment xml:lang="ca">ROM de Master System</comment>
<comment xml:lang="bg">ROM — Master System</comment>
+ <comment xml:lang="be">Master System ROM</comment>
<comment xml:lang="ar">روم Master System</comment>
<generic-icon name="application-x-executable"/>
<!-- Disabled, the magic would be too far into the file
@@ -20744,14 +21614,19 @@ command to generate the output files.
<comment xml:lang="tr">Game Gear ROM</comment>
<comment xml:lang="sv">Game Gear-rom</comment>
<comment xml:lang="sr">Гејм Гир РОМ</comment>
+ <comment xml:lang="sq">ROM Game Gear</comment>
+ <comment xml:lang="sl">Game Gear ROM</comment>
+ <comment xml:lang="si">Game Gear ROM</comment>
<comment xml:lang="sk">ROM pre Game Gear</comment>
<comment xml:lang="ru">Game Gear ROM</comment>
<comment xml:lang="pt_BR">ROM de Game Gear</comment>
<comment xml:lang="pl">Plik ROM konsoli Game Gear</comment>
+ <comment xml:lang="nl">Game Gear-ROM</comment>
<comment xml:lang="ko">게임 기어 롬</comment>
<comment xml:lang="kk">Game Gear ROM</comment>
<comment xml:lang="ja">ゲームギア ROM</comment>
<comment xml:lang="it">ROM Game Gear</comment>
+ <comment xml:lang="is">Game Gear ROM</comment>
<comment xml:lang="id">ROM Game Gear</comment>
<comment xml:lang="hu">Game Gear ROM</comment>
<comment xml:lang="hr">Game Gear ROM</comment>
@@ -20763,11 +21638,12 @@ command to generate the output files.
<comment xml:lang="eu">Game Gear ROM</comment>
<comment xml:lang="es">ROM de Game Gear</comment>
<comment xml:lang="en_GB">Game Gear ROM</comment>
- <comment xml:lang="de">Game Gear ROM</comment>
+ <comment xml:lang="de">Game-Gear-ROM</comment>
<comment xml:lang="da">Game Gear-ROM</comment>
<comment xml:lang="cs">ROM pro Game Gear</comment>
<comment xml:lang="ca">ROM de Game Gear</comment>
<comment xml:lang="bg">ROM — Game Gear</comment>
+ <comment xml:lang="be">Game Gear ROM</comment>
<comment xml:lang="ar">روم جيم جير</comment>
<generic-icon name="application-x-executable"/>
<!-- Disabled, the magic would be too far into the file
@@ -20792,6 +21668,7 @@ command to generate the output files.
<comment xml:lang="sr">Супер НЕС РОМ</comment>
<comment xml:lang="sq">ROM Super NES</comment>
<comment xml:lang="sl">Bralni pomnilnik Super NES</comment>
+ <comment xml:lang="si">සුපිරි NES ROM</comment>
<comment xml:lang="sk">ROM pre Super Nintendo</comment>
<comment xml:lang="ru">Super NES ROM</comment>
<comment xml:lang="ro">ROM Super Nintendo</comment>
@@ -20800,7 +21677,7 @@ command to generate the output files.
<comment xml:lang="pl">Plik ROM konsoli SNES</comment>
<comment xml:lang="oc">ROM Super Nintendo</comment>
<comment xml:lang="nn">Super NES-ROM</comment>
- <comment xml:lang="nl">Super Nintendo</comment>
+ <comment xml:lang="nl">Super Nintendo-ROM</comment>
<comment xml:lang="nb">Super Nintendo ROM</comment>
<comment xml:lang="lv">Super NES ROM</comment>
<comment xml:lang="lt">Super NES ROM</comment>
@@ -20808,6 +21685,7 @@ command to generate the output files.
<comment xml:lang="kk">Super NES ROM</comment>
<comment xml:lang="ja">スーパーファミコン ROM</comment>
<comment xml:lang="it">ROM Super Nintendo</comment>
+ <comment xml:lang="is">Super NES ROM</comment>
<comment xml:lang="id">Memori baca-saja Super Nintendo</comment>
<comment xml:lang="ia">ROM pro Super Nintendo</comment>
<comment xml:lang="hu">Super NES ROM</comment>
@@ -20823,12 +21701,13 @@ command to generate the output files.
<comment xml:lang="es">ROM de Super NES</comment>
<comment xml:lang="en_GB">Super NES ROM</comment>
<comment xml:lang="el">Super NES ROM</comment>
- <comment xml:lang="de">Super NES ROM</comment>
+ <comment xml:lang="de">Super-Nintendo-ROM</comment>
<comment xml:lang="da">Super NES-ROM</comment>
<comment xml:lang="cs">ROM pro Super Nintendo</comment>
<comment xml:lang="ca">ROM de Super NES</comment>
<comment xml:lang="bg">ROM — Super NES</comment>
<comment xml:lang="be@latin">Super Nintendo ROM</comment>
+ <comment xml:lang="be">Super Nintendo ROM</comment>
<comment xml:lang="ar">روم Super NES</comment>
<generic-icon name="application-x-executable"/>
<alias type="application/x-snes-rom"/>
@@ -20844,8 +21723,9 @@ command to generate the output files.
<comment xml:lang="tr">StuffIt arşivi</comment>
<comment xml:lang="sv">StuffIt-arkiv </comment>
<comment xml:lang="sr">Стаф Ит архива</comment>
- <comment xml:lang="sq">Arkiv StuffIt</comment>
+ <comment xml:lang="sq">arkiv StuffIt</comment>
<comment xml:lang="sl">Datoteka arhiva StuffIt</comment>
+ <comment xml:lang="si">StuffIt ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív StuffIt</comment>
<comment xml:lang="ru">Архив StuffIt</comment>
<comment xml:lang="ro">Arhivă StuffIt</comment>
@@ -20862,6 +21742,7 @@ command to generate the output files.
<comment xml:lang="kk">StuffIt архиві</comment>
<comment xml:lang="ja">StuffIt アーカイブ</comment>
<comment xml:lang="it">Archivio StuffIt</comment>
+ <comment xml:lang="is">StuffIt safnskrá</comment>
<comment xml:lang="id">Arsip StuffIt</comment>
<comment xml:lang="ia">Archivo StuffIt</comment>
<comment xml:lang="hu">StuffIt-archívum</comment>
@@ -20884,6 +21765,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu StuffIt</comment>
<comment xml:lang="bg">Архив — StuffIt</comment>
<comment xml:lang="be@latin">Archiŭ StuffIt</comment>
+ <comment xml:lang="be">архіў StuffIt</comment>
<comment xml:lang="ar">أرشيف StuffIt</comment>
<comment xml:lang="af">StuffIt-argief</comment>
<generic-icon name="package-x-generic"/>
@@ -20895,6 +21777,24 @@ command to generate the output files.
</magic>
<glob pattern="*.sit"/>
</mime-type>
+ <mime-type type="application/x-stuffitx">
+ <comment>StuffIt X archive</comment>
+ <comment xml:lang="uk">архів StuffIt X</comment>
+ <comment xml:lang="sv">StuffIt X-arkiv </comment>
+ <comment xml:lang="ru">Архив StuffIt X</comment>
+ <comment xml:lang="pl">Archiwum StuffIt X</comment>
+ <comment xml:lang="it">Archivio StuffIt X</comment>
+ <comment xml:lang="eu">StuffIt X artxiboa</comment>
+ <comment xml:lang="es">archivador de StuffIt X</comment>
+ <comment xml:lang="de">StuffIt-X-Archiv</comment>
+ <comment xml:lang="be">архіў StuffIt X</comment>
+ <generic-icon name="package-x-generic"/>
+ <alias type="application/x-sitx"/>
+ <magic priority="60">
+ <match type="string" value="StuffIt!" offset="0"/>
+ </magic>
+ <glob pattern="*.sitx"/>
+ </mime-type>
<mime-type type="application/x-subrip">
<comment>SubRip subtitles</comment>
<comment xml:lang="zh_TW">SubRip 字幕</comment>
@@ -20904,8 +21804,9 @@ command to generate the output files.
<comment xml:lang="tr">SubRip alt yazıları</comment>
<comment xml:lang="sv">SubRip-undertexter</comment>
<comment xml:lang="sr">Суб Рип преводи</comment>
- <comment xml:lang="sq">Nëntituj SubRip</comment>
+ <comment xml:lang="sq">titra SubRip</comment>
<comment xml:lang="sl">Datoteka podnapisov SubRip</comment>
+ <comment xml:lang="si">SubRip උපසිරැසි</comment>
<comment xml:lang="sk">Titulky SubRip</comment>
<comment xml:lang="ru">Субтитры SubRip</comment>
<comment xml:lang="ro">Subtitrare SubRip</comment>
@@ -20922,6 +21823,7 @@ command to generate the output files.
<comment xml:lang="kk">SubRip субтитрлары</comment>
<comment xml:lang="ja">SubRip 字幕</comment>
<comment xml:lang="it">Sottotitoli SubRip</comment>
+ <comment xml:lang="is">SubRip skjátextar</comment>
<comment xml:lang="id">Subjudul SubRip</comment>
<comment xml:lang="ia">Subtitulos SubRip</comment>
<comment xml:lang="hu">SubRip feliratok</comment>
@@ -20944,6 +21846,7 @@ command to generate the output files.
<comment xml:lang="ca">subtítols SubRip</comment>
<comment xml:lang="bg">Субтитри — SubRip</comment>
<comment xml:lang="be@latin">Subtytry SubRip</comment>
+ <comment xml:lang="be">субцітры SubRip</comment>
<comment xml:lang="ar">ترجمات SubRip</comment>
<comment xml:lang="af">SubRip-onderskrifte</comment>
<alias type="application/x-srt"/>
@@ -20964,7 +21867,9 @@ command to generate the output files.
<comment xml:lang="tr">WebVTT alt yazıları</comment>
<comment xml:lang="sv">WebVTT-undertexter</comment>
<comment xml:lang="sr">Веб ВТТ преводи</comment>
+ <comment xml:lang="sq">titra WebVTT</comment>
<comment xml:lang="sl">Podnapisi WebVTT</comment>
+ <comment xml:lang="si">WebVTT උපසිරැසි</comment>
<comment xml:lang="sk">Titulky WebVTT</comment>
<comment xml:lang="ru">Субтитры WebVTT</comment>
<comment xml:lang="pt_BR">Legendas WebVTT</comment>
@@ -20976,8 +21881,9 @@ command to generate the output files.
<comment xml:lang="ko">WebVTT 자막 파일</comment>
<comment xml:lang="kk">WebVTT субтитрлары</comment>
<comment xml:lang="ka">WebVTT ქვეტიტრები</comment>
- <comment xml:lang="ja">WebVTT サブタイトル</comment>
+ <comment xml:lang="ja">WebVTT 字幕</comment>
<comment xml:lang="it">Sottotitoli WebVTT</comment>
+ <comment xml:lang="is">WebVTT skjátextar</comment>
<comment xml:lang="id">Subjudul WebVTT</comment>
<comment xml:lang="ia">Subtitulos WebVTT</comment>
<comment xml:lang="hu">WebVTT feliratok</comment>
@@ -20997,6 +21903,7 @@ command to generate the output files.
<comment xml:lang="cs">titulky WebVTT</comment>
<comment xml:lang="ca">subtítols WebVTT</comment>
<comment xml:lang="bg">Субтитри — WebVTT</comment>
+ <comment xml:lang="be">субцітры WebVTT</comment>
<comment xml:lang="ar">ترجمات WebVTT</comment>
<comment xml:lang="af">WebVTT-onderskrifte</comment>
<acronym>VTT</acronym>
@@ -21017,8 +21924,9 @@ command to generate the output files.
<comment xml:lang="tr">SAMI alt yazıları</comment>
<comment xml:lang="sv">SAMI-undertexter</comment>
<comment xml:lang="sr">САМИ преводи</comment>
- <comment xml:lang="sq">Nëntituj SAMI</comment>
+ <comment xml:lang="sq">titra SAMI</comment>
<comment xml:lang="sl">Datoteka podnapisov SAMI</comment>
+ <comment xml:lang="si">SAMI උපසිරැසි</comment>
<comment xml:lang="sk">Titulky SAMI</comment>
<comment xml:lang="ru">Субтитры SAMI</comment>
<comment xml:lang="ro">Subtitrări SAMI</comment>
@@ -21035,6 +21943,7 @@ command to generate the output files.
<comment xml:lang="kk">SAMI субтитрлары</comment>
<comment xml:lang="ja">SAMI 字幕</comment>
<comment xml:lang="it">Sottotitoli SAMI</comment>
+ <comment xml:lang="is">SAMI skjátextar</comment>
<comment xml:lang="id">Subjudul SAMI</comment>
<comment xml:lang="ia">Subtitulos SAMI</comment>
<comment xml:lang="hu">SAMI feliratok</comment>
@@ -21057,6 +21966,7 @@ command to generate the output files.
<comment xml:lang="ca">subtítols SAMI</comment>
<comment xml:lang="bg">Субтитри — SAMI</comment>
<comment xml:lang="be@latin">Subtytry SAMI</comment>
+ <comment xml:lang="be">субцітры SAMI</comment>
<comment xml:lang="ar">ترجمات SAMI</comment>
<comment xml:lang="af">SAMI-onderskrifte</comment>
<acronym>SAMI</acronym>
@@ -21078,8 +21988,9 @@ command to generate the output files.
<comment xml:lang="tr">MicroDVD alt yazısı</comment>
<comment xml:lang="sv">MicroDVD-undertexter</comment>
<comment xml:lang="sr">Микро ДВД преводи</comment>
- <comment xml:lang="sq">Nëntituj MicroDVD</comment>
+ <comment xml:lang="sq">titra MicroDVD</comment>
<comment xml:lang="sl">Datoteka podnapisov MicroDVD</comment>
+ <comment xml:lang="si">MicroDVD උපසිරැසි</comment>
<comment xml:lang="sk">Titulky MicroDVD</comment>
<comment xml:lang="ru">Субтитры MicroDVD</comment>
<comment xml:lang="ro">Subtitrări MicroDVD</comment>
@@ -21097,6 +22008,7 @@ command to generate the output files.
<comment xml:lang="ka">MicroDVD-ის ქვეტიტრები</comment>
<comment xml:lang="ja">MicroDVD 字幕</comment>
<comment xml:lang="it">Sottotitoli MicroDVD</comment>
+ <comment xml:lang="is">MicroDVD skjátextar</comment>
<comment xml:lang="id">Subjudul MicroDVD</comment>
<comment xml:lang="ia">Subtitulos MicroDVD</comment>
<comment xml:lang="hu">MicroDVD feliratok</comment>
@@ -21119,6 +22031,7 @@ command to generate the output files.
<comment xml:lang="ca">subtítols MicroDVD</comment>
<comment xml:lang="bg">Субтитри — MicroDVD</comment>
<comment xml:lang="be@latin">Subtytry MicroDVD</comment>
+ <comment xml:lang="be">субцітры MicroDVD</comment>
<comment xml:lang="ar">ترجمات MicroDVD</comment>
<comment xml:lang="af">MicroDVD-onderskrifte</comment>
<sub-class-of type="text/plain"/>
@@ -21130,7 +22043,13 @@ command to generate the output files.
<glob pattern="*.sub"/>
</mime-type>
<mime-type type="text/x-mpl2">
- <comment>MPlayer2 subtitles</comment>
+ <comment>MPL2 subtitles</comment>
+ <comment xml:lang="uk">субтитри MPL2</comment>
+ <comment xml:lang="sv">MPL2-undertexter</comment>
+ <comment xml:lang="ru">Субтитры MPL2</comment>
+ <comment xml:lang="pl">Napisy MPL2</comment>
+ <comment xml:lang="es">subtítulos MPL2</comment>
+ <comment xml:lang="de">MPL2-Untertitel</comment>
<sub-class-of type="text/plain"/>
<magic>
<match type="string" value="[1]" offset="0"/>
@@ -21140,61 +22059,15 @@ command to generate the output files.
<glob pattern="*.mpl"/>
</mime-type>
<mime-type type="text/x-mpsub">
- <comment>MPSub subtitles</comment>
- <comment xml:lang="zh_TW">MPSub 字幕</comment>
- <comment xml:lang="zh_CN">MPSub 字幕</comment>
- <comment xml:lang="vi">Phụ đề MPSub</comment>
- <comment xml:lang="uk">субтитри MPSub</comment>
- <comment xml:lang="tr">MPSub alt yazıları</comment>
- <comment xml:lang="sv">MPSub-undertexter</comment>
- <comment xml:lang="sr">МПСуб преводи</comment>
- <comment xml:lang="sq">Nëntituj MPSub</comment>
- <comment xml:lang="sl">Datoteka podnapisov MPSub</comment>
- <comment xml:lang="sk">Titulky MPSub</comment>
- <comment xml:lang="ru">Субтитры MPSub</comment>
- <comment xml:lang="ro">Subtitrări MPSub</comment>
- <comment xml:lang="pt_BR">Legendas MPSub</comment>
- <comment xml:lang="pt">legendas MPSub</comment>
- <comment xml:lang="pl">Napisy MPSub</comment>
- <comment xml:lang="oc">sostítols MPSub</comment>
- <comment xml:lang="nn">MPSub-undertekstar</comment>
- <comment xml:lang="nl">MPSub-ondertitels</comment>
- <comment xml:lang="nb">MPSub undertekst</comment>
- <comment xml:lang="lv">MPSub subtitri</comment>
- <comment xml:lang="lt">MPSub subtitrai</comment>
- <comment xml:lang="ko">MPSub 자막 파일</comment>
- <comment xml:lang="kk">MPSub субтитрлары</comment>
- <comment xml:lang="ka">MPSub ქვეტიტრები</comment>
- <comment xml:lang="ja">MPSub サブタイトル</comment>
- <comment xml:lang="it">Sottotitoli MPSub</comment>
- <comment xml:lang="id">Subjudul MPSub</comment>
- <comment xml:lang="ia">Subtitulos MPSub</comment>
- <comment xml:lang="hu">MPSub feliratok</comment>
- <comment xml:lang="hr">MPSub podnaslovi</comment>
- <comment xml:lang="he">כתוביות MPSub</comment>
- <comment xml:lang="gl">subtítulos MPSub</comment>
- <comment xml:lang="ga">fotheidil MPSub</comment>
- <comment xml:lang="fur">sottitui MPSub</comment>
- <comment xml:lang="fr">sous-titres MPSub</comment>
- <comment xml:lang="fo">MPSub undirtekstir</comment>
- <comment xml:lang="fi">MPSub-tekstitykset</comment>
- <comment xml:lang="eu">MPSub azpitituluak</comment>
- <comment xml:lang="es">subtítulos MPSub</comment>
- <comment xml:lang="eo">MPSub-subtekstoj</comment>
- <comment xml:lang="en_GB">MPSub subtitles</comment>
- <comment xml:lang="el">Υπότιτλοι MPSub</comment>
- <comment xml:lang="de">MPSub-Untertitel</comment>
- <comment xml:lang="da">MPSub-undertekster</comment>
- <comment xml:lang="cs">titulky MPSub</comment>
- <comment xml:lang="ca">subtítols MPSub</comment>
- <comment xml:lang="bg">Субтитри — MPSub</comment>
- <comment xml:lang="be@latin">Subtytry MPSub</comment>
- <comment xml:lang="ar">ترجمات MPSub</comment>
- <comment xml:lang="af">MPSub-onderskrifte</comment>
- <acronym>MPSub</acronym>
- <expanded-acronym>MPlayer Subtitle</expanded-acronym>
+ <comment>MPlayer subtitles</comment>
+ <comment xml:lang="uk">субтитри MPlayer</comment>
+ <comment xml:lang="sv">MPlayer-undertexter</comment>
+ <comment xml:lang="ru">Субтитры MPlayer</comment>
+ <comment xml:lang="pl">Napisy MPlayer</comment>
+ <comment xml:lang="es">subtítulos de MPlayer</comment>
+ <comment xml:lang="de">MPlayer-Untertitel</comment>
<sub-class-of type="text/plain"/>
- <magic>
+ <magic priority="40">
<match type="string" value="FORMAT=" offset="0:256"/>
</magic>
<glob pattern="*.sub"/>
@@ -21208,8 +22081,9 @@ command to generate the output files.
<comment xml:lang="tr">SSA alt yazıları</comment>
<comment xml:lang="sv">SSA-undertexter</comment>
<comment xml:lang="sr">ССА преводи</comment>
- <comment xml:lang="sq">Nëntituj SSA</comment>
+ <comment xml:lang="sq">titra SSA</comment>
<comment xml:lang="sl">Datoteka podnapisov SSA</comment>
+ <comment xml:lang="si">SSA උපසිරැසි</comment>
<comment xml:lang="sk">Titulky SSA</comment>
<comment xml:lang="ru">Субтитры SSA</comment>
<comment xml:lang="ro">Subtitrări SSA</comment>
@@ -21226,6 +22100,7 @@ command to generate the output files.
<comment xml:lang="kk">SSA субтитрлары</comment>
<comment xml:lang="ja">SSA 字幕</comment>
<comment xml:lang="it">Sottotitoli SSA</comment>
+ <comment xml:lang="is">SSA skjátextar</comment>
<comment xml:lang="id">Subjudul SSA</comment>
<comment xml:lang="ia">Subtitulos SSA</comment>
<comment xml:lang="hu">SSA feliratok</comment>
@@ -21248,6 +22123,7 @@ command to generate the output files.
<comment xml:lang="ca">subtítols SSA</comment>
<comment xml:lang="bg">Субтитри — SSA</comment>
<comment xml:lang="be@latin">Subtytry SSA</comment>
+ <comment xml:lang="be">субцітры SSA</comment>
<comment xml:lang="ar">ترجمات SSA</comment>
<comment xml:lang="af">SSA-onderskrifte</comment>
<acronym>SSA</acronym>
@@ -21269,8 +22145,9 @@ command to generate the output files.
<comment xml:lang="tr">SubViewer alt yazıları</comment>
<comment xml:lang="sv">SubViewer-undertexter</comment>
<comment xml:lang="sr">Суб Вјивер преводи</comment>
- <comment xml:lang="sq">Nëntituj SubViewer</comment>
+ <comment xml:lang="sq">titra SubViewer</comment>
<comment xml:lang="sl">Datoteka podnapisov SubViewer</comment>
+ <comment xml:lang="si">SubViewer උපසිරැසි</comment>
<comment xml:lang="sk">Titulky SubViewer</comment>
<comment xml:lang="ru">Субтитры SubViewer</comment>
<comment xml:lang="ro">Subtitrare SubViewer</comment>
@@ -21287,6 +22164,7 @@ command to generate the output files.
<comment xml:lang="kk">SubViewer субтитрлары</comment>
<comment xml:lang="ja">SubViewer 字幕</comment>
<comment xml:lang="it">Sottotitoli SubViewer</comment>
+ <comment xml:lang="is">SubViewer skjátextar</comment>
<comment xml:lang="id">Subjudul SubViewer</comment>
<comment xml:lang="ia">Subtitulos SubViewer</comment>
<comment xml:lang="hu">SubViewer feliratok</comment>
@@ -21309,6 +22187,7 @@ command to generate the output files.
<comment xml:lang="ca">subtítols SubViewer</comment>
<comment xml:lang="bg">Субтитри — SubViewer</comment>
<comment xml:lang="be@latin">Subtytry SubViewer</comment>
+ <comment xml:lang="be">субцітры SubViewer</comment>
<comment xml:lang="ar">ترجمات SubViewer</comment>
<comment xml:lang="af">SubViewer-onderskrifte</comment>
<sub-class-of type="text/plain"/>
@@ -21326,8 +22205,9 @@ command to generate the output files.
<comment xml:lang="tr">iMelody melodisi</comment>
<comment xml:lang="sv">iMelody-ringsignal</comment>
<comment xml:lang="sr">звоно ајМелодије</comment>
- <comment xml:lang="sq">Zile iMelody</comment>
+ <comment xml:lang="sq">zile iMelody</comment>
<comment xml:lang="sl">Zvonjenje iMelody</comment>
+ <comment xml:lang="si">iMelody නාද රටා</comment>
<comment xml:lang="sk">Vyzváňacie melódie iMelody</comment>
<comment xml:lang="ru">Мелодия iMelody</comment>
<comment xml:lang="ro">Sonerie iMelody</comment>
@@ -21344,6 +22224,7 @@ command to generate the output files.
<comment xml:lang="kk">iMelody әуені</comment>
<comment xml:lang="ja">iMelody リングトーン</comment>
<comment xml:lang="it">Suoneria iMelody</comment>
+ <comment xml:lang="is">iMelody hringitónn</comment>
<comment xml:lang="id">nada dering iMelody</comment>
<comment xml:lang="ia">Tono de appello iMelody</comment>
<comment xml:lang="hu">iMelody csengőhang</comment>
@@ -21365,6 +22246,7 @@ command to generate the output files.
<comment xml:lang="ca">to de trucada iMelody</comment>
<comment xml:lang="bg">Аудио — iMelody</comment>
<comment xml:lang="be@latin">Rington iMelody</comment>
+ <comment xml:lang="be">мелодыя выкліку iMelody</comment>
<comment xml:lang="ar">نغمة iMelody</comment>
<comment xml:lang="af">iMelody-luitoon</comment>
<sub-class-of type="text/plain"/>
@@ -21385,8 +22267,9 @@ command to generate the output files.
<comment xml:lang="tr">SMAF sesi</comment>
<comment xml:lang="sv">SMAF-ljud</comment>
<comment xml:lang="sr">СМАФ звук</comment>
- <comment xml:lang="sq">Audio SMAF</comment>
+ <comment xml:lang="sq">audio SMAF</comment>
<comment xml:lang="sl">Zvočna datoteka SMAF</comment>
+ <comment xml:lang="si">SMAF ශ්රව්ය</comment>
<comment xml:lang="sk">Zvuk SMAF</comment>
<comment xml:lang="ru">Аудио SMAF</comment>
<comment xml:lang="ro">Audio SMAF</comment>
@@ -21403,6 +22286,7 @@ command to generate the output files.
<comment xml:lang="kk">SMAF аудиосы</comment>
<comment xml:lang="ja">SMAF オーディオ</comment>
<comment xml:lang="it">Audio SMAF</comment>
+ <comment xml:lang="is">SMAF hljóðskrá</comment>
<comment xml:lang="id">Audio SMAF</comment>
<comment xml:lang="ia">Audio SMAF</comment>
<comment xml:lang="hu">SMAF hang</comment>
@@ -21425,6 +22309,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio SMAF</comment>
<comment xml:lang="bg">Аудио — SMAF</comment>
<comment xml:lang="be@latin">Aŭdyjo SMAF</comment>
+ <comment xml:lang="be">аўдыя SMAF</comment>
<comment xml:lang="ar">صوت SMAF</comment>
<comment xml:lang="af">SMAF-oudio</comment>
<acronym>SMAF</acronym>
@@ -21446,8 +22331,9 @@ command to generate the output files.
<comment xml:lang="tr">MRML çalma listesi</comment>
<comment xml:lang="sv">MRML-spellista</comment>
<comment xml:lang="sr">МРМЛ списак нумера</comment>
- <comment xml:lang="sq">Listë titujsh MRML</comment>
+ <comment xml:lang="sq">luajlistë MRML</comment>
<comment xml:lang="sl">Seznam predvajanja MRML</comment>
+ <comment xml:lang="si">MRML ධාවන ලැයිස්තුව</comment>
<comment xml:lang="sk">Zoznam skladieb MRML</comment>
<comment xml:lang="ru">Список воспроизведения MRML</comment>
<comment xml:lang="ro">Listă redare MRML</comment>
@@ -21465,6 +22351,7 @@ command to generate the output files.
<comment xml:lang="ka">MRML რეპერტუარი</comment>
<comment xml:lang="ja">MRML プレイリスト</comment>
<comment xml:lang="it">Playlist MRML</comment>
+ <comment xml:lang="is">MRML spilunarlisti</comment>
<comment xml:lang="id">Senarai putar MRML</comment>
<comment xml:lang="ia">Lista de selection MRML</comment>
<comment xml:lang="hu">MRML-lejátszólista</comment>
@@ -21487,6 +22374,7 @@ command to generate the output files.
<comment xml:lang="ca">llista de reproducció MRML</comment>
<comment xml:lang="bg">Списък за изпълнение — MRML</comment>
<comment xml:lang="be@latin">Śpis piesień MRML</comment>
+ <comment xml:lang="be">плэй-ліст MRML</comment>
<comment xml:lang="ar">قائمة تشغيل MRML</comment>
<comment xml:lang="af">MRML-speellys</comment>
<acronym>MRML</acronym>
@@ -21507,8 +22395,9 @@ command to generate the output files.
<comment xml:lang="tr">XMF sesi</comment>
<comment xml:lang="sv">XMF-ljud</comment>
<comment xml:lang="sr">ИксМФ звук</comment>
- <comment xml:lang="sq">Audio XMF</comment>
+ <comment xml:lang="sq">audio XMF</comment>
<comment xml:lang="sl">Zvočna datoteka XMF</comment>
+ <comment xml:lang="si">XMF ශ්රව්ය</comment>
<comment xml:lang="sk">Zvuk XMF</comment>
<comment xml:lang="ru">Аудио XMF</comment>
<comment xml:lang="ro">Audio XMF</comment>
@@ -21525,6 +22414,7 @@ command to generate the output files.
<comment xml:lang="kk">XMF аудиосы</comment>
<comment xml:lang="ja">XMF オーディオ</comment>
<comment xml:lang="it">Audio XMF</comment>
+ <comment xml:lang="is">XMF hljóðskrá</comment>
<comment xml:lang="id">Audio XMF</comment>
<comment xml:lang="ia">Audio XMF</comment>
<comment xml:lang="hu">XMF hang</comment>
@@ -21537,7 +22427,7 @@ command to generate the output files.
<comment xml:lang="fo">XMF ljóður</comment>
<comment xml:lang="fi">XMF-ääni</comment>
<comment xml:lang="eu">XMF audioa</comment>
- <comment xml:lang="es">audio XMF</comment>
+ <comment xml:lang="es">sonido XMF</comment>
<comment xml:lang="eo">XMF-sondosiero</comment>
<comment xml:lang="en_GB">XMF audio</comment>
<comment xml:lang="el">Ήχος XMF</comment>
@@ -21547,6 +22437,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio XMF</comment>
<comment xml:lang="bg">Аудио — XMF</comment>
<comment xml:lang="be@latin">Aŭdyjo XMF</comment>
+ <comment xml:lang="be">аўдыя XMF</comment>
<comment xml:lang="ar">صوت XMF</comment>
<comment xml:lang="af">XMF-oudio</comment>
<acronym>XMF</acronym>
@@ -21559,6 +22450,26 @@ command to generate the output files.
</mime-type>
<mime-type type="audio/mobile-xmf">
<comment>Mobile XMF audio</comment>
+ <comment xml:lang="uk">звукові дані Mobile XMF</comment>
+ <comment xml:lang="tr">Mobile XMF sesi</comment>
+ <comment xml:lang="sv">Mobile XMF-ljud</comment>
+ <comment xml:lang="sl">Zvok Mobile XMF</comment>
+ <comment xml:lang="si">ජංගම XMF ශ්රව්ය</comment>
+ <comment xml:lang="ru">Аудио Mobile XMF</comment>
+ <comment xml:lang="pl">Plik dźwiękowy Mobile XMF</comment>
+ <comment xml:lang="nl">Mobile XMF-audio</comment>
+ <comment xml:lang="ko">모바일 XMF 오디오</comment>
+ <comment xml:lang="kk">Mobile XMF аудиосы</comment>
+ <comment xml:lang="ja">Mobile XMF オーディオ</comment>
+ <comment xml:lang="it">Audio XMF mobile</comment>
+ <comment xml:lang="hr">Mobilni XMF zvuk</comment>
+ <comment xml:lang="fi">Mobiili XMF-ääni</comment>
+ <comment xml:lang="eu">Mobile XMF audioa</comment>
+ <comment xml:lang="es">audio Mobile XMF</comment>
+ <comment xml:lang="en_GB">Mobile XMF audio</comment>
+ <comment xml:lang="de">Mobile-XMF-Audio</comment>
+ <comment xml:lang="be">аўдыя MXMF</comment>
+ <comment xml:lang="ar">صوت Mobile XMF</comment>
<acronym>XMF</acronym>
<expanded-acronym>eXtensible Music Format</expanded-acronym>
<magic>
@@ -21576,8 +22487,9 @@ command to generate the output files.
<comment xml:lang="tr">SV4 CPIO arşivi</comment>
<comment xml:lang="sv">SV4 CPIO-arkiv</comment>
<comment xml:lang="sr">СВ4 ЦПИО архива</comment>
- <comment xml:lang="sq">Arkiv SV4 CPIO</comment>
+ <comment xml:lang="sq">arkiv SV4 CPIO</comment>
<comment xml:lang="sl">Datoteka arhiva SV4 CPIO</comment>
+ <comment xml:lang="si">SV4 CPIO සංරක්ෂිතය</comment>
<comment xml:lang="sk">Archív SV4 CPIO</comment>
<comment xml:lang="ru">Архив SV4 CPIO</comment>
<comment xml:lang="ro">Arhivă SV4 CPIO</comment>
@@ -21595,6 +22507,7 @@ command to generate the output files.
<comment xml:lang="kk">SV4 CPIO архиві</comment>
<comment xml:lang="ja">SV4 CPIO アーカイブ</comment>
<comment xml:lang="it">Archivio SV4 CPIO</comment>
+ <comment xml:lang="is">SV4 CPIO safnskrá</comment>
<comment xml:lang="id">Arsip SV4 CPIO</comment>
<comment xml:lang="ia">Archivo CPIO SV4</comment>
<comment xml:lang="hu">SV4 CPIO-archívum</comment>
@@ -21618,6 +22531,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu SV4 CPIO</comment>
<comment xml:lang="bg">Архив — SV4 CPIO</comment>
<comment xml:lang="be@latin">Archiŭ SV4 CPIO</comment>
+ <comment xml:lang="be">архіў SV4 CPIO</comment>
<comment xml:lang="az">SV4 CPIO arxivi</comment>
<comment xml:lang="ar">أرشيف SV4 CPIO</comment>
<comment xml:lang="af">SV4 CPIO-argief</comment>
@@ -21633,8 +22547,9 @@ command to generate the output files.
<comment xml:lang="tr">SV4 CPIO arşivi (CRC ile)</comment>
<comment xml:lang="sv">SV4 CPIO-arkiv (med CRC)</comment>
<comment xml:lang="sr">СВ4 ЦПИО архива (са ЦРЦ-ом)</comment>
- <comment xml:lang="sq">Arkiv SV4 CPIO (me CRC)</comment>
+ <comment xml:lang="sq">arkiv SV4 CPIO (me CRC)</comment>
<comment xml:lang="sl">Datoteka arhiva SV4 CPIO (z razpršilom CRC)</comment>
+ <comment xml:lang="si">SV4 CPIO සංරක්ෂිතය (CRC සමඟ)</comment>
<comment xml:lang="sk">Archív SV4 CPIO (s CRC)</comment>
<comment xml:lang="ru">Архив SV4 CPIO (с CRC)</comment>
<comment xml:lang="ro">Arhivă SV4 CPIO (cu CRC)</comment>
@@ -21652,6 +22567,7 @@ command to generate the output files.
<comment xml:lang="kk">SV4 CPIO архиві (CRC бар)</comment>
<comment xml:lang="ja">SV4 CPIO アーカイブ (CRC 有り)</comment>
<comment xml:lang="it">Archivio SV4 CPIO (con CRC)</comment>
+ <comment xml:lang="is">SV4 CPIO safnskrá (með CRC)</comment>
<comment xml:lang="id">Arsip SV4 CPIO (dengan CRC)</comment>
<comment xml:lang="ia">Archivo CPIO SV4 (con CRC)</comment>
<comment xml:lang="hu">SV4 CPIO-archívum (CRC-vel)</comment>
@@ -21674,6 +22590,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu SV4 CPIO (amb CRC)</comment>
<comment xml:lang="bg">Архив — SV4 CPIO, проверка за грешки CRC</comment>
<comment xml:lang="be@latin">Archiŭ SV4 CPIO (z CRC)</comment>
+ <comment xml:lang="be">архіў SV4 CPIO (z CRC)</comment>
<comment xml:lang="ar">أرشيف SV4 CPIO (مع CRC)</comment>
<comment xml:lang="af">SV4 CPIO-argief (met CRC)</comment>
<generic-icon name="package-x-generic"/>
@@ -21688,8 +22605,9 @@ command to generate the output files.
<comment xml:lang="tr">Tar arşivi</comment>
<comment xml:lang="sv">Tar-arkiv</comment>
<comment xml:lang="sr">Тар архива</comment>
- <comment xml:lang="sq">Arkiv tar</comment>
+ <comment xml:lang="sq">arkiv tar</comment>
<comment xml:lang="sl">Datoteka arhiva Tar</comment>
+ <comment xml:lang="si">තාර ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív Tar</comment>
<comment xml:lang="ru">Архив TAR</comment>
<comment xml:lang="ro">Arhivă Tar</comment>
@@ -21707,6 +22625,7 @@ command to generate the output files.
<comment xml:lang="kk">Tar архиві</comment>
<comment xml:lang="ja">Tar アーカイブ</comment>
<comment xml:lang="it">Archivio tar</comment>
+ <comment xml:lang="is">Tar safnskrá</comment>
<comment xml:lang="id">Arsip Tar</comment>
<comment xml:lang="ia">Archivo Tar</comment>
<comment xml:lang="hu">Tar archívum</comment>
@@ -21729,6 +22648,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu tar</comment>
<comment xml:lang="bg">Архив — tar</comment>
<comment xml:lang="be@latin">Archiŭ tar</comment>
+ <comment xml:lang="be">архіў tar</comment>
<comment xml:lang="az">Tar arxivi</comment>
<comment xml:lang="ar">أرشيف Tar</comment>
<comment xml:lang="af">Tar-argief</comment>
@@ -21751,8 +22671,9 @@ command to generate the output files.
<comment xml:lang="tr">Tar arşivi (sıkıştırılmış)</comment>
<comment xml:lang="sv">Tar-arkiv (komprimerat)</comment>
<comment xml:lang="sr">Тар архива (запакована)</comment>
- <comment xml:lang="sq">Arkiv tar (i kompresuar)</comment>
+ <comment xml:lang="sq">arkiv tar (i kompresuar)</comment>
<comment xml:lang="sl">Datoteka arhiva Tar (stisnjen)</comment>
+ <comment xml:lang="si">තාර සංරක්ෂිතය (සම්පීඩිත)</comment>
<comment xml:lang="sk">Archív Tar (komprimovaný)</comment>
<comment xml:lang="ru">Архив TAR (сжатый)</comment>
<comment xml:lang="ro">Arhivă Tar (comprimată)</comment>
@@ -21769,6 +22690,7 @@ command to generate the output files.
<comment xml:lang="kk">Tar архиві (сығылған)</comment>
<comment xml:lang="ja">Tar アーカイブ (圧縮)</comment>
<comment xml:lang="it">Archivio tar (compresso)</comment>
+ <comment xml:lang="is">Tar safnskrá (þjappað)</comment>
<comment xml:lang="id">Arsip Tar (terkompresi)</comment>
<comment xml:lang="ia">Archivo Tar (comprimite)</comment>
<comment xml:lang="hu">Tar archívum (tömörített)</comment>
@@ -21790,6 +22712,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu tar (amb compressió)</comment>
<comment xml:lang="bg">Архив — tar, компресиран</comment>
<comment xml:lang="be@latin">Archiŭ tar (skampresavany)</comment>
+ <comment xml:lang="be">архіў tar (сціснуты)</comment>
<comment xml:lang="ar">أرشيف Tar (مضغوط)</comment>
<comment xml:lang="af">Tar-argief (saamgepers)</comment>
<sub-class-of type="application/x-compress"/>
@@ -21798,112 +22721,31 @@ command to generate the output files.
<glob pattern="*.taz"/>
</mime-type>
<mime-type type="application/x-tex-gf">
- <comment>generic font file</comment>
- <comment xml:lang="zh_TW">通用字型檔</comment>
- <comment xml:lang="zh_CN">通用字体文件</comment>
- <comment xml:lang="vi">tập tin phông giống loài</comment>
- <comment xml:lang="uk">загальний файл шрифту</comment>
- <comment xml:lang="tr">genel yazı tipi dosyası</comment>
- <comment xml:lang="sv">allmän typsnittsfil</comment>
- <comment xml:lang="sr">општа датотека слова</comment>
- <comment xml:lang="sq">File lloj gërme i përgjithshëm</comment>
- <comment xml:lang="sl">izvorna datoteka pisave</comment>
- <comment xml:lang="sk">Obyčajný súbor písma</comment>
+ <comment>Generic font file</comment>
+ <comment xml:lang="uk">типовий файл шрифту</comment>
+ <comment xml:lang="sv">Allmän typsnittsfil</comment>
<comment xml:lang="ru">Обычный файл шрифта</comment>
- <comment xml:lang="ro">fișier de font generic</comment>
- <comment xml:lang="pt_BR">Arquivo de fonte genérico</comment>
- <comment xml:lang="pt">ficheiro genérico de letra</comment>
<comment xml:lang="pl">Zwykły plik czcionki</comment>
- <comment xml:lang="oc">fichièr de poliças generic</comment>
- <comment xml:lang="nn">vanleg skrifttypefil</comment>
- <comment xml:lang="nl">algemeen lettertypebestand</comment>
- <comment xml:lang="nb">vanlig skriftfil</comment>
- <comment xml:lang="ms">Fail font generik</comment>
- <comment xml:lang="lv">vispārēja fonta datne</comment>
- <comment xml:lang="lt">bendras šrifto failas</comment>
- <comment xml:lang="ko">일반 글꼴 파일</comment>
- <comment xml:lang="kk">қаріп файлы</comment>
- <comment xml:lang="ja">一般フォントファイル</comment>
- <comment xml:lang="it">File tipo carattere generico</comment>
- <comment xml:lang="id">berkas fonta generik</comment>
- <comment xml:lang="ia">File de typo de litteras generic</comment>
- <comment xml:lang="hu">általános betűkészletfájl</comment>
- <comment xml:lang="hr">generička datoteka fonta</comment>
- <comment xml:lang="he">קובץ גופן גנרי</comment>
- <comment xml:lang="gl">ficheiro de tipo de fonte xenérica</comment>
- <comment xml:lang="ga">comhad cló ginearálta</comment>
- <comment xml:lang="fur">file di caratar gjeneric</comment>
- <comment xml:lang="fr">fichier de polices générique</comment>
- <comment xml:lang="fo">felagsstavasniðsfíla</comment>
- <comment xml:lang="fi">yleinen fonttitiedosto</comment>
- <comment xml:lang="eu">letra-tipo orokorra</comment>
- <comment xml:lang="es">tipo de letra genérico</comment>
- <comment xml:lang="eo">genera tipara dosiero</comment>
- <comment xml:lang="en_GB">generic font file</comment>
- <comment xml:lang="el">Γενικό αρχείο γραμματοσειράς</comment>
+ <comment xml:lang="ja">汎用フォント</comment>
+ <comment xml:lang="it">File tipo di carattere generico</comment>
+ <comment xml:lang="eu">Letra-tipoen fitxategi orokorra</comment>
+ <comment xml:lang="es">archivo de tipo de letra genérico</comment>
<comment xml:lang="de">Allgemeine Schriftdatei</comment>
- <comment xml:lang="da">general skrifttypefil</comment>
- <comment xml:lang="cs">obecný soubor s fontem</comment>
- <comment xml:lang="ca">fitxer de lletra genèrica</comment>
- <comment xml:lang="bg">Шрифт</comment>
- <comment xml:lang="be@latin">zvyčajny fajł šryftu</comment>
- <comment xml:lang="ar">ملف خط عام</comment>
- <comment xml:lang="af">generiese skriftipelêer</comment>
+ <comment xml:lang="be">файл тыповага шрыфту</comment>
<generic-icon name="font-x-generic"/>
<glob pattern="*.gf"/>
</mime-type>
<mime-type type="application/x-tex-pk">
- <comment>packed font file</comment>
- <comment xml:lang="zh_TW">包裝字型檔</comment>
- <comment xml:lang="zh_CN">打包的字体文件</comment>
- <comment xml:lang="vi">tập tin phông chữ đã đóng gói</comment>
+ <comment>Packed font file</comment>
<comment xml:lang="uk">запакований файл шрифту</comment>
- <comment xml:lang="tr">paketlenmiş yazı tipi dosyası</comment>
- <comment xml:lang="sv">packad typsnittsfil</comment>
- <comment xml:lang="sr">пакована датотека слова</comment>
- <comment xml:lang="sq">File lloj gërmash i kondensuar</comment>
- <comment xml:lang="sl">pakirana datoteka pisave</comment>
- <comment xml:lang="sk">Komprimovaný súbor písma</comment>
+ <comment xml:lang="sv">Packad typsnittsfil</comment>
<comment xml:lang="ru">Сжатый файл шрифта</comment>
- <comment xml:lang="ro">fișier font împachetat</comment>
- <comment xml:lang="pt_BR">Arquivo de fonte empacotado</comment>
- <comment xml:lang="pt">ficheiro de letras empacotadas</comment>
<comment xml:lang="pl">Plik ze spakowaną czcionką</comment>
- <comment xml:lang="oc">fichièr de poliças empaquetadas</comment>
- <comment xml:lang="nn">pakka skrifttypefil</comment>
- <comment xml:lang="nl">ingepakt lettertypebestand</comment>
- <comment xml:lang="nb">pakket skriftfil</comment>
- <comment xml:lang="ms">Fail font dipek</comment>
- <comment xml:lang="lv">sapakota fonta datne</comment>
- <comment xml:lang="lt">supakuotas šrifto failas</comment>
- <comment xml:lang="ko">글꼴 묶음 파일</comment>
- <comment xml:lang="kk">қаріп файлы (дестеленген)</comment>
- <comment xml:lang="ja">パックされたフォントファイル</comment>
- <comment xml:lang="it">File tipo carattere condensato</comment>
- <comment xml:lang="id">berkas fonta terkemas</comment>
- <comment xml:lang="ia">File de typos de litteras impacchettate</comment>
- <comment xml:lang="hu">packed font-fájl</comment>
- <comment xml:lang="hr">zapakirana datoteka fonta</comment>
- <comment xml:lang="he">קובץ גופן ארוז</comment>
- <comment xml:lang="gl">ficheiro de fonte empaquetada</comment>
- <comment xml:lang="ga">comhad cló pacáilte</comment>
- <comment xml:lang="fur">file di caratar impachetât</comment>
- <comment xml:lang="fr">fichier de polices empaquetées</comment>
- <comment xml:lang="fo">pakkað stavasniðsfíla</comment>
- <comment xml:lang="fi">pakattu fonttitiedosto</comment>
- <comment xml:lang="eu">Letra-tipo fitxategi paketatua</comment>
- <comment xml:lang="es">tipo de letra empaquetado</comment>
- <comment xml:lang="eo">pakigita tipara dosiero</comment>
- <comment xml:lang="en_GB">packed font file</comment>
- <comment xml:lang="el">Αρχείο συμπιεσμένης γραμματοσειράς</comment>
+ <comment xml:lang="it">File tipo di carattere condensato</comment>
+ <comment xml:lang="eu">Letra-tipoen fitxategi paketatua</comment>
+ <comment xml:lang="es">archivo de tipo de letra empaquetado</comment>
<comment xml:lang="de">Gepackte Schriftdatei</comment>
- <comment xml:lang="da">pakket skrifttypefil</comment>
- <comment xml:lang="cs">komprimovaný soubor s fontem</comment>
- <comment xml:lang="ca">fitxer de lletra empaquetada</comment>
- <comment xml:lang="bg">Шрифт — компресиран</comment>
- <comment xml:lang="be@latin">zapakavany fajł šryftu</comment>
- <comment xml:lang="ar">ملف خط مرزم</comment>
- <comment xml:lang="af">verpakte skriftipelêer</comment>
+ <comment xml:lang="be">запакаваны файл шрыфту</comment>
<generic-icon name="font-x-generic"/>
<glob pattern="*.pk"/>
</mime-type>
@@ -21916,8 +22758,9 @@ command to generate the output files.
<comment xml:lang="tr">TGIF belgesi</comment>
<comment xml:lang="sv">TGIF-dokument</comment>
<comment xml:lang="sr">ТГИФ документ</comment>
- <comment xml:lang="sq">Dokument TGIF</comment>
+ <comment xml:lang="sq">dokument TGIF</comment>
<comment xml:lang="sl">Dokument TGIF</comment>
+ <comment xml:lang="si">TGIF ලේඛනය</comment>
<comment xml:lang="sk">Dokument TGIF</comment>
<comment xml:lang="ru">Документ TGIF</comment>
<comment xml:lang="ro">Document TGIF</comment>
@@ -21935,6 +22778,7 @@ command to generate the output files.
<comment xml:lang="kk">TGIF құжаты</comment>
<comment xml:lang="ja">TGIF ドキュメント</comment>
<comment xml:lang="it">Documento TGIF</comment>
+ <comment xml:lang="is">TGIF skjal</comment>
<comment xml:lang="id">Dokumen TGIF</comment>
<comment xml:lang="ia">Documento TGIF</comment>
<comment xml:lang="hu">TGIF-dokumentum</comment>
@@ -21957,6 +22801,7 @@ command to generate the output files.
<comment xml:lang="ca">document TGIF</comment>
<comment xml:lang="bg">Документ — TGIF</comment>
<comment xml:lang="be@latin">Dakument TGIF</comment>
+ <comment xml:lang="be">дакумент TGIF</comment>
<comment xml:lang="ast">Documentu de TGIF</comment>
<comment xml:lang="ar">مستند TGIF</comment>
<comment xml:lang="af">TGIF-dokument</comment>
@@ -21967,60 +22812,17 @@ command to generate the output files.
<glob pattern="*.obj"/>
</mime-type>
<mime-type type="application/x-theme">
- <comment>theme</comment>
- <comment xml:lang="zh_TW">佈景主題</comment>
- <comment xml:lang="zh_CN">主题</comment>
- <comment xml:lang="vi">sắc thái</comment>
+ <comment>Theme</comment>
<comment xml:lang="uk">тема</comment>
- <comment xml:lang="tr">tema</comment>
- <comment xml:lang="sv">tema</comment>
- <comment xml:lang="sr">тема</comment>
- <comment xml:lang="sq">Temë</comment>
- <comment xml:lang="sl">tema</comment>
- <comment xml:lang="sk">Motív</comment>
+ <comment xml:lang="sv">Tema</comment>
<comment xml:lang="ru">Тема</comment>
- <comment xml:lang="ro">temă</comment>
- <comment xml:lang="pt_BR">Tema</comment>
- <comment xml:lang="pt">tema</comment>
<comment xml:lang="pl">Motyw</comment>
- <comment xml:lang="oc">tèma</comment>
- <comment xml:lang="nn">drakt</comment>
- <comment xml:lang="nl">thema</comment>
- <comment xml:lang="nb">tema</comment>
- <comment xml:lang="ms">Tema</comment>
- <comment xml:lang="lv">motīvs</comment>
- <comment xml:lang="lt">tema</comment>
- <comment xml:lang="ko">테마</comment>
- <comment xml:lang="kk">тема</comment>
- <comment xml:lang="ka">თემა</comment>
- <comment xml:lang="ja">テーマ</comment>
<comment xml:lang="it">Tema</comment>
- <comment xml:lang="id">tema</comment>
- <comment xml:lang="ia">Thema</comment>
- <comment xml:lang="hu">téma</comment>
- <comment xml:lang="hr">Tema</comment>
- <comment xml:lang="he">ערכת נושא</comment>
- <comment xml:lang="gl">tema</comment>
- <comment xml:lang="ga">téama</comment>
- <comment xml:lang="fur">teme</comment>
- <comment xml:lang="fr">thème</comment>
- <comment xml:lang="fo">tema</comment>
- <comment xml:lang="fi">teema</comment>
- <comment xml:lang="eu">gaia</comment>
+ <comment xml:lang="gl">Tema</comment>
+ <comment xml:lang="eu">Gaia</comment>
<comment xml:lang="es">tema</comment>
- <comment xml:lang="eo">etoso</comment>
- <comment xml:lang="en_GB">theme</comment>
- <comment xml:lang="el">Θέμα</comment>
<comment xml:lang="de">Thema</comment>
- <comment xml:lang="da">tema</comment>
- <comment xml:lang="cy">thema</comment>
- <comment xml:lang="cs">motiv</comment>
- <comment xml:lang="ca">tema</comment>
- <comment xml:lang="bg">Тема</comment>
- <comment xml:lang="be@latin">matyŭ</comment>
- <comment xml:lang="az">örtük</comment>
- <comment xml:lang="ar">سمة</comment>
- <comment xml:lang="af">tema</comment>
+ <comment xml:lang="be">тэма</comment>
<sub-class-of type="application/x-desktop"/>
<generic-icon name="package-x-generic"/>
<glob pattern="*.theme"/>
@@ -22034,8 +22836,9 @@ command to generate the output files.
<comment xml:lang="tr">ToutDoux belgesi</comment>
<comment xml:lang="sv">ToutDoux-dokument</comment>
<comment xml:lang="sr">Туду документ</comment>
- <comment xml:lang="sq">Dokument ToutDoux</comment>
+ <comment xml:lang="sq">dokument ToutDoux</comment>
<comment xml:lang="sl">Dokument ToutDoux</comment>
+ <comment xml:lang="si">ToutDoux ලේඛනය</comment>
<comment xml:lang="sk">Dokument ToutDoux</comment>
<comment xml:lang="ru">Документ ToutDoux</comment>
<comment xml:lang="ro">Document ToutDoux</comment>
@@ -22053,6 +22856,7 @@ command to generate the output files.
<comment xml:lang="kk">ToutDoux құжаты</comment>
<comment xml:lang="ja">ToutDoux ドキュメント</comment>
<comment xml:lang="it">Documento ToutDoux</comment>
+ <comment xml:lang="is">ToutDoux skjal</comment>
<comment xml:lang="id">Dokumen ToutDoux</comment>
<comment xml:lang="ia">Documento ToutDoux</comment>
<comment xml:lang="hu">ToutDoux-dokumentum</comment>
@@ -22076,6 +22880,7 @@ command to generate the output files.
<comment xml:lang="ca">document ToutDoux</comment>
<comment xml:lang="bg">Документ — ToutDoux</comment>
<comment xml:lang="be@latin">Dakument ToutDoux</comment>
+ <comment xml:lang="be">дакумент ToutDoux</comment>
<comment xml:lang="az">ToutDoux sənədi</comment>
<comment xml:lang="ast">Documentu de ToutDoux</comment>
<comment xml:lang="ar">مستند ToutDoux</comment>
@@ -22083,57 +22888,19 @@ command to generate the output files.
<generic-icon name="x-office-document"/>
</mime-type>
<mime-type type="application/x-trash">
- <comment>backup file</comment>
- <comment xml:lang="zh_TW">備份檔</comment>
- <comment xml:lang="zh_CN">备份文件</comment>
- <comment xml:lang="vi">tập tin sao lưu</comment>
- <comment xml:lang="uk">резервна копія</comment>
- <comment xml:lang="tr">yedek dosyası</comment>
- <comment xml:lang="sv">säkerhetskopia</comment>
- <comment xml:lang="sr">датотека резерве</comment>
- <comment xml:lang="sq">File backup</comment>
- <comment xml:lang="sl">varnostna kopija datoteke</comment>
- <comment xml:lang="sk">Záložný súbor</comment>
+ <comment>Backup file</comment>
+ <comment xml:lang="uk">Файл резервної копії</comment>
+ <comment xml:lang="sv">Säkerhetskopia</comment>
<comment xml:lang="ru">Резервная копия</comment>
- <comment xml:lang="ro">fișier de backup</comment>
<comment xml:lang="pt_BR">Arquivo de backup</comment>
- <comment xml:lang="pt">cópia de segurança</comment>
<comment xml:lang="pl">Plik zapasowy</comment>
- <comment xml:lang="oc">fichièr de salvament</comment>
- <comment xml:lang="nn">tryggleikskopi</comment>
- <comment xml:lang="nl">reservekopiebestand</comment>
- <comment xml:lang="nb">sikkerhetskopi</comment>
- <comment xml:lang="ms">Fail backup</comment>
- <comment xml:lang="lv">dublējuma datne</comment>
- <comment xml:lang="lt">atsarginis failas</comment>
- <comment xml:lang="ko">백업 파일</comment>
- <comment xml:lang="kk">резервті көшірмесі</comment>
- <comment xml:lang="ja">バックアップファイル</comment>
+ <comment xml:lang="ja">控え</comment>
<comment xml:lang="it">File di backup</comment>
- <comment xml:lang="id">berkas cadangan</comment>
- <comment xml:lang="ia">Copia de reserva</comment>
- <comment xml:lang="hu">biztonsági mentés</comment>
- <comment xml:lang="hr">Datoteka sigurnosne kopije</comment>
- <comment xml:lang="he">קובץ גיבוי</comment>
- <comment xml:lang="gl">ficheiro de copia de seguridade</comment>
- <comment xml:lang="ga">comhad cúltaca</comment>
- <comment xml:lang="fur">file di backup</comment>
- <comment xml:lang="fr">fichier de sauvegarde</comment>
- <comment xml:lang="fo">trygdarritsfíla</comment>
- <comment xml:lang="fi">varmuuskopio</comment>
- <comment xml:lang="eu">babes-kopiako fitxategia</comment>
- <comment xml:lang="es">archivo de respaldo</comment>
- <comment xml:lang="eo">restaŭrkopio</comment>
- <comment xml:lang="en_GB">backup file</comment>
- <comment xml:lang="el">Αντίγραφο ασφαλείας</comment>
+ <comment xml:lang="gl">Ficheiro de respaldo</comment>
+ <comment xml:lang="eu">Babeskopia-fitxategia</comment>
+ <comment xml:lang="es">archivo de copia de respaldo</comment>
<comment xml:lang="de">Sicherungsdatei</comment>
- <comment xml:lang="da">sikkerhedskopi</comment>
- <comment xml:lang="cs">záložní soubor</comment>
- <comment xml:lang="ca">fitxer de còpia de seguretat</comment>
- <comment xml:lang="bg">Резервно копие</comment>
- <comment xml:lang="be@latin">zapasny fajł</comment>
- <comment xml:lang="ar">ملف نسخ احتياطي</comment>
- <comment xml:lang="af">rugsteunlêer</comment>
+ <comment xml:lang="be">рэзервовая копія файла</comment>
<glob pattern="*~"/>
<glob pattern="*%"/>
<glob pattern="*.bak"/>
@@ -22149,8 +22916,9 @@ command to generate the output files.
<comment xml:lang="tr">Troff belgesi</comment>
<comment xml:lang="sv">Troff-dokument</comment>
<comment xml:lang="sr">Трофф документ</comment>
- <comment xml:lang="sq">Dokument Troff</comment>
+ <comment xml:lang="sq">dokument Troff</comment>
<comment xml:lang="sl">Dokument Troff</comment>
+ <comment xml:lang="si">ට්රොෆ් ලේඛනය</comment>
<comment xml:lang="sk">Dokument troff</comment>
<comment xml:lang="ru">Документ Troff</comment>
<comment xml:lang="ro">Document Troff</comment>
@@ -22168,6 +22936,7 @@ command to generate the output files.
<comment xml:lang="kk">Troff құжаты</comment>
<comment xml:lang="ja">Troff 入力ドキュメント</comment>
<comment xml:lang="it">Documento Troff</comment>
+ <comment xml:lang="is">Troff skjal</comment>
<comment xml:lang="id">Dokumen Troff</comment>
<comment xml:lang="ia">Documento Troff</comment>
<comment xml:lang="hu">Troff-dokumentum</comment>
@@ -22191,6 +22960,7 @@ command to generate the output files.
<comment xml:lang="ca">document Troff</comment>
<comment xml:lang="bg">Документ — Troff</comment>
<comment xml:lang="be@latin">Dakument Troff</comment>
+ <comment xml:lang="be">дакумент Troff</comment>
<comment xml:lang="az">Troff sənədi</comment>
<comment xml:lang="ast">Documentu de Troff</comment>
<comment xml:lang="ar">مستند Troff</comment>
@@ -22210,6 +22980,28 @@ command to generate the output files.
</mime-type>
<mime-type type="application/x-troff-man">
<comment>Manual page</comment>
+ <comment xml:lang="zh_CN">手册页</comment>
+ <comment xml:lang="uk">сторінка підручника</comment>
+ <comment xml:lang="tr">Kılavuz sayfası</comment>
+ <comment xml:lang="sv">Manualsida</comment>
+ <comment xml:lang="si">අත්පොත පිටුව</comment>
+ <comment xml:lang="ru">Страница руководства</comment>
+ <comment xml:lang="pt_BR">Página de manual</comment>
+ <comment xml:lang="pl">Strona podręcznika</comment>
+ <comment xml:lang="nl">Handleidingpagina</comment>
+ <comment xml:lang="ko">man 페이지</comment>
+ <comment xml:lang="kk">Нұсқаулық парағы</comment>
+ <comment xml:lang="ja">マニュアルページ</comment>
+ <comment xml:lang="it">Pagina di manuale</comment>
+ <comment xml:lang="hr">Stranica priručnika</comment>
+ <comment xml:lang="gl">Páxina de manual</comment>
+ <comment xml:lang="fi">Manuaalisivu</comment>
+ <comment xml:lang="eu">Eskuliburu-orria</comment>
+ <comment xml:lang="es">página de manual</comment>
+ <comment xml:lang="en_GB">Manual page</comment>
+ <comment xml:lang="de">Handbuchseite</comment>
+ <comment xml:lang="be">старонка даведкі</comment>
+ <comment xml:lang="ar">صفحة دليل</comment>
<sub-class-of type="text/plain"/>
<generic-icon name="text-x-generic"/>
<glob pattern="*.man"/>
@@ -22217,6 +23009,28 @@ command to generate the output files.
</mime-type>
<mime-type type="application/x-troff-man-compressed">
<comment>Manual page (compressed)</comment>
+ <comment xml:lang="zh_CN">手册页(压缩)</comment>
+ <comment xml:lang="uk">сторінка підручника (стиснена)</comment>
+ <comment xml:lang="tr">Kılavuz sayfası (sıkıştırılmış)</comment>
+ <comment xml:lang="sv">Manualsida (komprimerad)</comment>
+ <comment xml:lang="si">අතින් පිටුව (සම්පීඩිත)</comment>
+ <comment xml:lang="ru">Страница руководства (сжатая)</comment>
+ <comment xml:lang="pt_BR">Página de manual (compactada)</comment>
+ <comment xml:lang="pl">Strona podręcznika (skompresowana)</comment>
+ <comment xml:lang="nl">Handleidingpagina (gecomprimeerd)</comment>
+ <comment xml:lang="ko">man 페이지 (압축)</comment>
+ <comment xml:lang="kk">Нұсқаулық парағы (сығылған)</comment>
+ <comment xml:lang="ja">マニュアルページ (圧縮)</comment>
+ <comment xml:lang="it">Pagina di manuale (compressa)</comment>
+ <comment xml:lang="hr">Stranica priručnika (sažeta)</comment>
+ <comment xml:lang="gl">Páxina de manual (comprimida)</comment>
+ <comment xml:lang="fi">Manuaalisivu (pakattu)</comment>
+ <comment xml:lang="eu">Eskuliburu-orria (konprimatua)</comment>
+ <comment xml:lang="es">página de manual (comprimida)</comment>
+ <comment xml:lang="en_GB">Manual page (compressed)</comment>
+ <comment xml:lang="de">Handbuchseite (komprimiert)</comment>
+ <comment xml:lang="be">старонка даведкі (сціснутая)</comment>
+ <comment xml:lang="ar">صفحة دليل (مضغوطة)</comment>
<generic-icon name="text-x-generic"/>
</mime-type>
<mime-type type="application/x-tzo">
@@ -22228,8 +23042,9 @@ command to generate the output files.
<comment xml:lang="tr">Tar arşivi (LZO ile sıkıştırılmış)</comment>
<comment xml:lang="sv">Tar-arkiv (LZO-komprimerat)</comment>
<comment xml:lang="sr">Тар архива (запакована ЛЗО-ом)</comment>
- <comment xml:lang="sq">Arkiv tar (i kompresuar me LZO)</comment>
+ <comment xml:lang="sq">arkiv tar (ngjeshur me LZO)</comment>
<comment xml:lang="sl">Datoteka arhiva Tar (stisnjen z LZO)</comment>
+ <comment xml:lang="si">තාර සංරක්ෂිතය (LZO-සම්පීඩිත)</comment>
<comment xml:lang="sk">Archív Tar (komprimovaný pomocou LZO)</comment>
<comment xml:lang="ru">Архив TAR (сжатый lzo)</comment>
<comment xml:lang="ro">Arhivă Tar (comprimată LZO)</comment>
@@ -22246,6 +23061,7 @@ command to generate the output files.
<comment xml:lang="kk">Tar архиві (LZO-мен сығылған)</comment>
<comment xml:lang="ja">Tar アーカイブ (LZO 圧縮)</comment>
<comment xml:lang="it">Archivio tar (compresso con LZO)</comment>
+ <comment xml:lang="is">Tar safnskrá (LZO-þjappað)</comment>
<comment xml:lang="id">Arsip Tar (terkompresi LZO)</comment>
<comment xml:lang="ia">Archivo Tar (comprimite con LZO)</comment>
<comment xml:lang="hu">Tar archívum (LZO tömörítésű)</comment>
@@ -22258,7 +23074,7 @@ command to generate the output files.
<comment xml:lang="fo">Tar skjalasavn (LZO-stappað)</comment>
<comment xml:lang="fi">Tar-arkisto (LZO-pakattu)</comment>
<comment xml:lang="eu">Tar artxiboa (LZO-rekin konprimitua)</comment>
- <comment xml:lang="es">archivador Tar (comprimido con LZO)</comment>
+ <comment xml:lang="es">archivador TAR (comprimido con LZO)</comment>
<comment xml:lang="en_GB">Tar archive (LZO-compressed)</comment>
<comment xml:lang="el">Αρχείο Tar (συμπιεσμένο με LZO)</comment>
<comment xml:lang="de">Tar-Archiv (LZO-komprimiert)</comment>
@@ -22267,6 +23083,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu tar (amb compressió LZO)</comment>
<comment xml:lang="bg">Архив — tar, компресиран с LZO</comment>
<comment xml:lang="be@latin">Archiŭ tar (LZO-skampresavany)</comment>
+ <comment xml:lang="be">архіў tar (сцісканне LZO)</comment>
<comment xml:lang="ar">أرشيف Tar (مضغوط-LZO)</comment>
<comment xml:lang="af">Tar-argief (LZO-saamgepers)</comment>
<sub-class-of type="application/x-lzop"/>
@@ -22282,7 +23099,9 @@ command to generate the output files.
<comment xml:lang="tr">XZ arşivi</comment>
<comment xml:lang="sv">XZ-arkiv</comment>
<comment xml:lang="sr">ИксЗ архива</comment>
+ <comment xml:lang="sq">arkiv XZ</comment>
<comment xml:lang="sl">Datoteka arhiva XZ</comment>
+ <comment xml:lang="si">XZ ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív XZ</comment>
<comment xml:lang="ru">Архив XZ</comment>
<comment xml:lang="ro">Arhivă XZ</comment>
@@ -22297,6 +23116,7 @@ command to generate the output files.
<comment xml:lang="kk">XZ архиві</comment>
<comment xml:lang="ja">XZ アーカイブ</comment>
<comment xml:lang="it">Archivio xz</comment>
+ <comment xml:lang="is">XZ safnskrá</comment>
<comment xml:lang="id">Arsip XZ</comment>
<comment xml:lang="ia">Archivo XZ</comment>
<comment xml:lang="hu">XZ-archívum</comment>
@@ -22318,6 +23138,7 @@ command to generate the output files.
<comment xml:lang="cs">archiv XZ</comment>
<comment xml:lang="ca">arxiu XZ</comment>
<comment xml:lang="bg">Архив — XZ</comment>
+ <comment xml:lang="be">архіў XZ</comment>
<comment xml:lang="ar">أرشيف XZ</comment>
<comment xml:lang="af">XZ-argief</comment>
<generic-icon name="package-x-generic"/>
@@ -22334,7 +23155,9 @@ command to generate the output files.
<comment xml:lang="tr">Tar arşivi (XZ ile sıkıştırılmış)</comment>
<comment xml:lang="sv">Tar-arkiv (XZ-komprimerat)</comment>
<comment xml:lang="sr">Тар архива (запакована ИксЗ-ом)</comment>
+ <comment xml:lang="sq">arkiv tar (ngjeshur me XZ)</comment>
<comment xml:lang="sl">Datoteka arhiva Tar (stisnjen z XZ)</comment>
+ <comment xml:lang="si">තාර සංරක්ෂිතය (XZ-සම්පීඩිත)</comment>
<comment xml:lang="sk">Archív Tar (komprimovaný pomocou XZ)</comment>
<comment xml:lang="ru">Архив TAR (сжатый xz)</comment>
<comment xml:lang="ro">Arhivă Tar (comprimată XZ)</comment>
@@ -22349,6 +23172,7 @@ command to generate the output files.
<comment xml:lang="kk">Tar архиві (XZ-мен сығылған)</comment>
<comment xml:lang="ja">Tar アーカイブ (XZ 圧縮)</comment>
<comment xml:lang="it">Archivio tar (compresso con XZ)</comment>
+ <comment xml:lang="is">Tar safnskrá (XZ-þjappað)</comment>
<comment xml:lang="id">Arsip Tar (terkompresi XZ)</comment>
<comment xml:lang="ia">Archivo Tar (comprimite con XZ)</comment>
<comment xml:lang="hu">Tar archívum (XZ tömörítésű)</comment>
@@ -22361,7 +23185,7 @@ command to generate the output files.
<comment xml:lang="fo">Tar skjalasavn(XZ-stappað)</comment>
<comment xml:lang="fi">Tar-arkisto (XZ-pakattu)</comment>
<comment xml:lang="eu">Tar artxiboa (XZ-rekin konprimitua)</comment>
- <comment xml:lang="es">archivador Tar (comprimido con XZ)</comment>
+ <comment xml:lang="es">archivador TAR (comprimido con XZ)</comment>
<comment xml:lang="en_GB">Tar archive (XZ-compressed)</comment>
<comment xml:lang="el">Αρχείο Tar (συμπιεσμένο με XZ)</comment>
<comment xml:lang="de">Tar-Archiv (XZ-komprimiert)</comment>
@@ -22369,6 +23193,7 @@ command to generate the output files.
<comment xml:lang="cs">archiv Tar (komprimovaný pomocí XZ)</comment>
<comment xml:lang="ca">arxiu tar (amb compressió XZ)</comment>
<comment xml:lang="bg">Архив — tar, компресиран с XZ</comment>
+ <comment xml:lang="be">архіў tar (сцісканне XZ)</comment>
<comment xml:lang="ar">أرشيف Tar (مضغوط-XZ)</comment>
<comment xml:lang="af">Tar-argief (XZ-saamgepers)</comment>
<sub-class-of type="application/x-xz"/>
@@ -22376,6 +23201,24 @@ command to generate the output files.
<glob pattern="*.tar.xz"/>
<glob pattern="*.txz"/>
</mime-type>
+ <mime-type type="application/x-zpaq">
+ <comment>Zpaq Archive</comment>
+ <comment xml:lang="uk">архів zpaq</comment>
+ <comment xml:lang="sv">Zpaq-arkiv</comment>
+ <comment xml:lang="ru">Архив zpaq</comment>
+ <comment xml:lang="pl">Archiwum ZPAQ</comment>
+ <comment xml:lang="it">Archivio zpaq</comment>
+ <comment xml:lang="gl">Arquivo Zpaq</comment>
+ <comment xml:lang="eu">Zpaq artxiboa</comment>
+ <comment xml:lang="es">archivador Zpaq</comment>
+ <comment xml:lang="de">Zpaq-Archiv</comment>
+ <comment xml:lang="be">архіў Zpaq</comment>
+ <generic-icon name="package-x-generic"/>
+ <magic>
+ <match type="string" value="7kSt" offset="0"/>
+ </magic>
+ <glob pattern="*.zpaq"/>
+ </mime-type>
<mime-type type="application/zstd">
<comment>Zstandard archive</comment>
<comment xml:lang="zh_TW">Zstandard 封存檔</comment>
@@ -22383,19 +23226,25 @@ command to generate the output files.
<comment xml:lang="uk">архів Zstandard</comment>
<comment xml:lang="tr">Zstandard arşivi</comment>
<comment xml:lang="sv">Zstandard-arkiv</comment>
+ <comment xml:lang="sq">arkiv Zstandard</comment>
+ <comment xml:lang="sl">Arhiv Zstandard</comment>
+ <comment xml:lang="si">Zstandard ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív Zstandard</comment>
<comment xml:lang="ru">Архив Zstandard</comment>
<comment xml:lang="pt_BR">Pacote Zstandard</comment>
<comment xml:lang="pl">Archiwum Zstandard</comment>
<comment xml:lang="oc">archiu Zstandard</comment>
+ <comment xml:lang="nl">Zstandard-archief</comment>
<comment xml:lang="ko">Zstandard 압축 파일</comment>
<comment xml:lang="kk">Zstandard архиві</comment>
<comment xml:lang="ja">Zstandard アーカイブ</comment>
<comment xml:lang="it">Archivio Zstandard</comment>
+ <comment xml:lang="is">Zstandard safnskrá</comment>
<comment xml:lang="id">Arsip Zstandard</comment>
<comment xml:lang="hu">Zstandard archívum</comment>
<comment xml:lang="hr">Zstandard arhiva</comment>
<comment xml:lang="he">ארכיון Zstandard</comment>
+ <comment xml:lang="gl">Arquivo de Zstandard</comment>
<comment xml:lang="fur">archivi Zstandard</comment>
<comment xml:lang="fr">archive Zstandard</comment>
<comment xml:lang="fi">Zstandard-arkisto</comment>
@@ -22407,6 +23256,7 @@ command to generate the output files.
<comment xml:lang="cs">archiv Zstandard</comment>
<comment xml:lang="ca">arxiu Zstandard</comment>
<comment xml:lang="bg">Архив — Zstandard</comment>
+ <comment xml:lang="be">архіў Zstandard</comment>
<comment xml:lang="ar">أرشيف Zstandard</comment>
<generic-icon name="package-x-generic"/>
<magic priority="60">
@@ -22421,29 +23271,36 @@ command to generate the output files.
<comment xml:lang="uk">архів tar archive (стиснений Zstandard)</comment>
<comment xml:lang="tr">Tar arşivi (Zstandard ile sıkıştırılmış)</comment>
<comment xml:lang="sv">Tar-arkiv (Zstandard-komprimerat)</comment>
+ <comment xml:lang="sq">arkiv tar (ngjeshur me Zstandard)</comment>
+ <comment xml:lang="sl">Arhiv tar (stisnjen, Zstandard)</comment>
+ <comment xml:lang="si">තාර සංරක්ෂිතය (Zstandard-compressed)</comment>
<comment xml:lang="ru">Архив TAR (сжатый zstandard)</comment>
<comment xml:lang="pt_BR">Pacote Tar (compactado com Zstandard)</comment>
<comment xml:lang="pl">Archiwum tar (kompresja Zstandard)</comment>
<comment xml:lang="oc">archiu Tar (compressat amb Zstandard)</comment>
+ <comment xml:lang="nl">Tar-archief (gecomprimeerd met Zstandard)</comment>
<comment xml:lang="ko">TAR 묶음 파일(Zstandard 압축)</comment>
<comment xml:lang="kk">Tar архиві (Zstandard-пен сығылған)</comment>
<comment xml:lang="ja">Tar アーカイブ (ZStandard 圧縮)</comment>
<comment xml:lang="it">Archivio tar (compresso con Zstandard)</comment>
+ <comment xml:lang="is">Tar safnskrá (Zstandard þjappað)</comment>
<comment xml:lang="id">Arsip Tar (terkompresi Zstandard)</comment>
<comment xml:lang="hu">Tar archívum (Zstandard tömörítésű)</comment>
<comment xml:lang="hr">Tar arhiva (Zstandard-sažeta)</comment>
<comment xml:lang="he">ארכיון Tar (מכווץ ע״י Zstandard)</comment>
+ <comment xml:lang="gl">Arquivo Tar (comprimido Zstandard)</comment>
<comment xml:lang="fur">archivi Tar (comprimût cun Zstandard)</comment>
<comment xml:lang="fr">archive tar (compression Zstandard)</comment>
<comment xml:lang="fi">Tar-arkisto (Zstandard-pakattu)</comment>
<comment xml:lang="eu">Tar artxiboa (Zstandard-rekin konprimitua)</comment>
- <comment xml:lang="es">archivador Tar (comprimido con Zstandard)</comment>
+ <comment xml:lang="es">archivador TAR (comprimido con Zstandard)</comment>
<comment xml:lang="en_GB">Tar archive (Zstandard-compressed)</comment>
<comment xml:lang="de">Tar-Archiv (Zstandard-komprimiert)</comment>
<comment xml:lang="da">Tar-arkiv (Zstandard-komprimeret)</comment>
<comment xml:lang="cs">archiv Tar (komprimovaný pomocí Zstandard)</comment>
<comment xml:lang="ca">arxiu tar (amb compressió Zstandard)</comment>
<comment xml:lang="bg">Архив — tar, компресиран със Zstandard</comment>
+ <comment xml:lang="be">архіў tar (сцісканне Zstandard)</comment>
<comment xml:lang="ar">أرشيف Tar (مضغوط-Zstandard)</comment>
<generic-icon name="package-x-generic"/>
<sub-class-of type="application/zstd"/>
@@ -22458,7 +23315,9 @@ command to generate the output files.
<comment xml:lang="tr">PDF belgesi (XZ ile sıkıştırılmış)</comment>
<comment xml:lang="sv">PDF-dokument (XZ-komprimerat)</comment>
<comment xml:lang="sr">ПДФ документ (запакован ИксЗ-ом)</comment>
+ <comment xml:lang="sq">dokument PDF (ngjeshur me XZ)</comment>
<comment xml:lang="sl">Dokument PDF (XZ-stisnjen)</comment>
+ <comment xml:lang="si">PDF ලේඛනය (XZ-සම්පීඩිත)</comment>
<comment xml:lang="sk">Dokument PDF (komprimovaný pomocou XZ)</comment>
<comment xml:lang="ru">Документ PDF (сжатый xz)</comment>
<comment xml:lang="pt_BR">Documento PDF (compactado com XZ)</comment>
@@ -22472,6 +23331,7 @@ command to generate the output files.
<comment xml:lang="ka">PDF დოკუმენტი (XZ-ით შეკუმშული)</comment>
<comment xml:lang="ja">PDF 文書(XZ 圧縮)</comment>
<comment xml:lang="it">Documento PDF (compresso con XZ)</comment>
+ <comment xml:lang="is">PDF skjal (XZ-þjappað)</comment>
<comment xml:lang="id">Dokumen PDF (terkompresi XZ)</comment>
<comment xml:lang="ia">Documento PDF (comprimite con XZ)</comment>
<comment xml:lang="hu">PDF dokumentum (XZ tömörítésű)</comment>
@@ -22491,6 +23351,7 @@ command to generate the output files.
<comment xml:lang="cs">dokument PDF (komprimovaný pomocí XZ)</comment>
<comment xml:lang="ca">document PDF (amb compressió XZ)</comment>
<comment xml:lang="bg">Документ — PDF, компресиран с XZ</comment>
+ <comment xml:lang="be">дакумент PDF (сцісканне XZ)</comment>
<comment xml:lang="ast">Documentu PDF (comprimíu en XZ)</comment>
<comment xml:lang="ar">مستند PDF (مضغوط-XZ)</comment>
<comment xml:lang="af">PDF-dokument (XZ-saamgepers)</comment>
@@ -22507,8 +23368,9 @@ command to generate the output files.
<comment xml:lang="tr">Ustar arşivi</comment>
<comment xml:lang="sv">Ustar-arkiv</comment>
<comment xml:lang="sr">Устар архива</comment>
- <comment xml:lang="sq">Arkiv Ustar</comment>
+ <comment xml:lang="sq">arkiv Ustar</comment>
<comment xml:lang="sl">Datoteka arhiva Ustar</comment>
+ <comment xml:lang="si">Ustar ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív Ustar</comment>
<comment xml:lang="ru">Архив Ustar</comment>
<comment xml:lang="ro">Arhivă Ustar</comment>
@@ -22525,6 +23387,7 @@ command to generate the output files.
<comment xml:lang="kk">Ustar архиві</comment>
<comment xml:lang="ja">Ustar アーカイブ</comment>
<comment xml:lang="it">Archivio ustar</comment>
+ <comment xml:lang="is">Ustar safnskrá</comment>
<comment xml:lang="id">Arsip Ustar</comment>
<comment xml:lang="ia">Archivo Ustar</comment>
<comment xml:lang="hu">Ustar archívum</comment>
@@ -22547,6 +23410,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu ustar</comment>
<comment xml:lang="bg">Архив — ustar</comment>
<comment xml:lang="be@latin">Archiŭ ustar</comment>
+ <comment xml:lang="be">архіў ustar</comment>
<comment xml:lang="ar">أرشيف Ustar</comment>
<comment xml:lang="af">Ustar-argief</comment>
<generic-icon name="package-x-generic"/>
@@ -22557,12 +23421,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">WAIS 源碼</comment>
<comment xml:lang="zh_CN">WAIS 源代码</comment>
<comment xml:lang="vi">Mã nguồn WAIS</comment>
- <comment xml:lang="uk">вихідний код мовою WAIS</comment>
+ <comment xml:lang="uk">початковий код мовою WAIS</comment>
<comment xml:lang="tr">WAIS kaynak kodu</comment>
<comment xml:lang="sv">WAIS-källkod</comment>
<comment xml:lang="sr">ВАИС изворни ко̂д</comment>
- <comment xml:lang="sq">Kod burues WAIS</comment>
+ <comment xml:lang="sq">kod burim WAIS</comment>
<comment xml:lang="sl">Datoteka izvorne kode WAIS</comment>
+ <comment xml:lang="si">WAIS මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód WAIS</comment>
<comment xml:lang="ru">Исходный код WAIS</comment>
<comment xml:lang="ro">Cod sursă WAIS</comment>
@@ -22580,6 +23445,7 @@ command to generate the output files.
<comment xml:lang="kk">WAIS бастапқы коды</comment>
<comment xml:lang="ja">WAIS ソースコード</comment>
<comment xml:lang="it">Codice sorgente WAIS</comment>
+ <comment xml:lang="is">WAIS frumkóði</comment>
<comment xml:lang="id">Kode program WAIS</comment>
<comment xml:lang="ia">Codice-fonte WAIS</comment>
<comment xml:lang="hu">WAIS-forráskód</comment>
@@ -22603,6 +23469,7 @@ command to generate the output files.
<comment xml:lang="ca">codi font en WAIS</comment>
<comment xml:lang="bg">Изходен код — WAIS</comment>
<comment xml:lang="be@latin">Kryničny kod WAIS</comment>
+ <comment xml:lang="be">зыходны код WAIS</comment>
<comment xml:lang="az">WAIS mənbə faylı</comment>
<comment xml:lang="ar">شفرة مصدر WAIS</comment>
<comment xml:lang="af">WAIS-bronkode</comment>
@@ -22619,8 +23486,9 @@ command to generate the output files.
<comment xml:lang="tr">WordPerfect/DrawPerfect görüntüsü</comment>
<comment xml:lang="sv">WordPerfect/Drawperfect-bild</comment>
<comment xml:lang="sr">Ворд Перфект/Дров Перфект слика</comment>
- <comment xml:lang="sq">Figurë WordPerfect/Drawperfect</comment>
+ <comment xml:lang="sq">figurë WordPerfect/Drawperfect</comment>
<comment xml:lang="sl">Slikovna datoteka Drawperfect</comment>
+ <comment xml:lang="si">WordPerfect/Drawperfect රූපය</comment>
<comment xml:lang="sk">Obrázok WordPerfect/Drawperfect</comment>
<comment xml:lang="ru">Изображение WordPerfect/Drawperfect</comment>
<comment xml:lang="ro">Imagine WordPerfect/Drawperfect</comment>
@@ -22638,6 +23506,7 @@ command to generate the output files.
<comment xml:lang="kk">WordPerfect/Drawperfect суреті</comment>
<comment xml:lang="ja">WordPerfect/Drawperfect 画像</comment>
<comment xml:lang="it">Immagine WordPerfect/Drawperfect</comment>
+ <comment xml:lang="is">WordPerfect/Drawperfect mynd</comment>
<comment xml:lang="id">Gambar WordPerfect/Drawperfect</comment>
<comment xml:lang="ia">Imagine WordPerfect/DrawPerfect</comment>
<comment xml:lang="hu">WordPerfect/Drawperfect-kép</comment>
@@ -22660,6 +23529,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge de WordPerfect/Drawperfect</comment>
<comment xml:lang="bg">Изображение — WordPerfect/Drawperfect</comment>
<comment xml:lang="be@latin">Vyjava WordPerfect/Drawperfect</comment>
+ <comment xml:lang="be">выява WordPerfect/Drawperfect</comment>
<comment xml:lang="ar">صورة WordPerfect/Drawperfect</comment>
<comment xml:lang="af">WordPerfect/Drawperfect-beeld</comment>
<generic-icon name="image-x-generic"/>
@@ -22672,14 +23542,18 @@ command to generate the output files.
<comment xml:lang="uk">ROM Bandai WonderSwan</comment>
<comment xml:lang="tr">Bandai WonderSwan ROM</comment>
<comment xml:lang="sv">Bandai WonderSwan-rom</comment>
+ <comment xml:lang="sq">ROM Bandai WonderSwan</comment>
+ <comment xml:lang="si">බන්ඩායි WonderSwan ROM</comment>
<comment xml:lang="sk">ROM pre Bandai WonderSwan</comment>
<comment xml:lang="ru">Bandai WonderSwan ROM</comment>
<comment xml:lang="pt_BR">ROM de WonderSwan da Bandai</comment>
<comment xml:lang="pl">Plik ROM konsoli Bandai WonderSwan</comment>
+ <comment xml:lang="nl">Bandai WonderSwan-ROM</comment>
<comment xml:lang="ko">반다이 원더스완 롬</comment>
<comment xml:lang="kk">Bandai WonderSwan ROM</comment>
<comment xml:lang="ja">バンダイワンダースワン ROM</comment>
<comment xml:lang="it">ROM Bandai WonderSwan</comment>
+ <comment xml:lang="is">Bandai WonderSwan ROM</comment>
<comment xml:lang="id">ROM Bandai WonderSwan</comment>
<comment xml:lang="hu">Bandai WonderSwan ROM</comment>
<comment xml:lang="hr">Bandai WonderSwan ROM</comment>
@@ -22691,11 +23565,12 @@ command to generate the output files.
<comment xml:lang="eu">Bandai WonderSwan ROM</comment>
<comment xml:lang="es">ROM de Bandai WonderSwan</comment>
<comment xml:lang="en_GB">Bandai WonderSwan ROM</comment>
- <comment xml:lang="de">Bandai WonderSwan ROM</comment>
+ <comment xml:lang="de">Bandai-WonderSwan-ROM</comment>
<comment xml:lang="da">Bandai WonderSwan-ROM</comment>
<comment xml:lang="cs">ROM pro Bandai WonderSwan</comment>
<comment xml:lang="ca">ROM de Bandai WonderSwan</comment>
<comment xml:lang="bg">ROM — Bandai WonderSwan</comment>
+ <comment xml:lang="be">Bandai WonderSwan ROM</comment>
<comment xml:lang="ar">روم Bandai WonderSwan</comment>
<generic-icon name="application-x-executable"/>
<glob pattern="*.ws"/>
@@ -22707,14 +23582,18 @@ command to generate the output files.
<comment xml:lang="uk">ROM Bandai WonderSwan Color</comment>
<comment xml:lang="tr">Bandai WonderSwan Color ROM</comment>
<comment xml:lang="sv">Bandai WonderSwan Color-rom</comment>
+ <comment xml:lang="sq">ROM Bandai WonderSwan Color</comment>
+ <comment xml:lang="si">Bandai WonderSwan වර්ණ ROM</comment>
<comment xml:lang="sk">ROM pre Bandai WonderSwan Color</comment>
<comment xml:lang="ru">Bandai WonderSwan Color ROM</comment>
<comment xml:lang="pt_BR">ROM de WonderSwan Color da Bandai</comment>
<comment xml:lang="pl">Plik ROM konsoli Bandai WonderSwan Color</comment>
+ <comment xml:lang="nl">Bandai WonderSwan Color-ROM</comment>
<comment xml:lang="ko">반다이 원더스완 컬러 롬</comment>
<comment xml:lang="kk">Bandai WonderSwan Color ROM</comment>
<comment xml:lang="ja">バンダイワンダースワンカラー ROM</comment>
<comment xml:lang="it">ROM Bandai WonderSwan Color</comment>
+ <comment xml:lang="is">Bandai WonderSwan Color ROM</comment>
<comment xml:lang="id">ROM Bandai WonderSwan Color</comment>
<comment xml:lang="hu">Bandai WonderSwan Color ROM</comment>
<comment xml:lang="hr">Bandai WonderSwan Color ROM</comment>
@@ -22726,11 +23605,12 @@ command to generate the output files.
<comment xml:lang="eu">Bandai WonderSwan Color ROM</comment>
<comment xml:lang="es">ROM de Bandai WonderSwan Color</comment>
<comment xml:lang="en_GB">Bandai WonderSwan Color ROM</comment>
- <comment xml:lang="de">Bandai WonderSwan Color ROM</comment>
+ <comment xml:lang="de">Bandai-WonderSwan-Color-ROM</comment>
<comment xml:lang="da">Bandai WonderSwan Color-ROM</comment>
<comment xml:lang="cs">ROM pro Bandai WonderSwan Color</comment>
<comment xml:lang="ca">ROM de Bandai WonderSwan Color</comment>
<comment xml:lang="bg">ROM — Bandai WonderSwan Color</comment>
+ <comment xml:lang="be">Bandai WonderSwan Color ROM</comment>
<comment xml:lang="ar">روم لون Bandai WonderSwan</comment>
<generic-icon name="application-x-executable"/>
<glob pattern="*.wsc"/>
@@ -22744,10 +23624,11 @@ command to generate the output files.
<comment xml:lang="tr">DER/PEM/Netscape-kodlanmış X.509 sertfikası</comment>
<comment xml:lang="sv">DER/PEM/Netscape-kodat X.509-certifikat</comment>
<comment xml:lang="sr">ДЕР/ПЕМ/Нетскејп кодирано уверење Икс.509</comment>
- <comment xml:lang="sq">Çertifikatë DER/PEM/Netscape-encoded X.509</comment>
+ <comment xml:lang="sq">dëshmi X.509 koduar për DER/PEM/Netscape</comment>
<comment xml:lang="sl">Datoteka potrdila DER/PEM/Netscape X.509</comment>
+ <comment xml:lang="si">DER/PEM/Netscape-කේතනය කළ X.509 සහතිකය</comment>
<comment xml:lang="sk">Certifikát X.509 kódovaný ako DER/PEM/Netscape</comment>
- <comment xml:lang="ru">Сертификат X.509 (DER/PEM/Netscape-закодированный)</comment>
+ <comment xml:lang="ru">Сертификат X.509 в формате DER/PEM/Netscape</comment>
<comment xml:lang="ro">Certificat DER/PEM/Netscape-codat X.509</comment>
<comment xml:lang="pt_BR">Certificado X.509 codificado com DER/PEM/Netscape</comment>
<comment xml:lang="pt">certificado X.509 codificado com DER/PEM/Netscape</comment>
@@ -22764,6 +23645,7 @@ command to generate the output files.
<comment xml:lang="ka">DER/PEM/Netscape კოდირებული X.509 სერტიფიკატი</comment>
<comment xml:lang="ja">DER/PEM/Netscape エンコード X.509 証明書</comment>
<comment xml:lang="it">Certificato X.509 DER/PEM/Netscape</comment>
+ <comment xml:lang="is">DER/PEM/Netscape-kóðað X.509 skilríki</comment>
<comment xml:lang="id">Sertifikat DER/PEM/Netscape-tersandi X.509</comment>
<comment xml:lang="ia">Certificato X.509 codificate in DER/PEM/Netscape</comment>
<comment xml:lang="hu">DER/PEM/Netscape formátumú X.509-tanúsítvány</comment>
@@ -22780,12 +23662,13 @@ command to generate the output files.
<comment xml:lang="eo">DER/PEM/Netscape-kodigita X.509-atestilo</comment>
<comment xml:lang="en_GB">DER/PEM/Netscape-encoded X.509 certificate</comment>
<comment xml:lang="el">Ψηφιακό πιστοποιητικό X.509 κωδικοποιημένο κατά DER/PEM/Netscape</comment>
- <comment xml:lang="de">DER/PEM/Netscape-kodiertes X.509-Zertifikat</comment>
+ <comment xml:lang="de">DER/PEM/Netscape-verschlüsseltes X.509-Zertifikat</comment>
<comment xml:lang="da">DER-/PEM-/Netscape-kodet X.509-certifikat</comment>
<comment xml:lang="cs">certifikát X.509 kódovaný jako DER/PEM/Netscape</comment>
<comment xml:lang="ca">certificat X.509 codificat com DER/PEM/Netscape</comment>
<comment xml:lang="bg">Сертификат — DER/PEM/Netscape X.509</comment>
<comment xml:lang="be@latin">Sertyfikat X.509, zakadavany ŭ DER/PEM/Netscape</comment>
+ <comment xml:lang="be">сертыфікат X.509, закадаваны праз DER/PEM/Netscape</comment>
<comment xml:lang="ar">شهادة DER/PEM/Netscape-encoded X.509</comment>
<comment xml:lang="af">DER/PEM/Netscape-geënkodeerde X.509-sertifikaat</comment>
<generic-icon name="text-x-generic"/>
@@ -22799,58 +23682,18 @@ command to generate the output files.
<glob pattern="*.pem"/>
</mime-type>
<mime-type type="application/x-zerosize">
- <comment>empty document</comment>
- <comment xml:lang="zh_TW">空白文件</comment>
- <comment xml:lang="zh_CN">空文档</comment>
- <comment xml:lang="vi">tài liệu rỗng</comment>
+ <comment>Empty document</comment>
<comment xml:lang="uk">порожній документ</comment>
- <comment xml:lang="tr">boş belge</comment>
- <comment xml:lang="sv">tomt dokument</comment>
- <comment xml:lang="sr">празан документ</comment>
- <comment xml:lang="sq">Dokument bosh</comment>
- <comment xml:lang="sl">prazen dokument</comment>
- <comment xml:lang="sk">Prázdny dokument</comment>
+ <comment xml:lang="sv">Tomt dokument</comment>
<comment xml:lang="ru">Пустой документ</comment>
- <comment xml:lang="ro">document gol</comment>
- <comment xml:lang="pt_BR">Documento vazio</comment>
- <comment xml:lang="pt">documento vazio</comment>
+ <comment xml:lang="pt_BR">Documento em branco</comment>
<comment xml:lang="pl">Pusty dokument</comment>
- <comment xml:lang="oc">document void</comment>
- <comment xml:lang="nn">tomt dokument</comment>
- <comment xml:lang="nl">leeg document</comment>
- <comment xml:lang="nb">tomt dokument</comment>
- <comment xml:lang="ms">Dokumen kosong</comment>
- <comment xml:lang="lv">tukšs dokuments</comment>
- <comment xml:lang="lt">tuščias dokumentas</comment>
- <comment xml:lang="ko">빈 문서</comment>
- <comment xml:lang="kk">бос құжат</comment>
- <comment xml:lang="ja">空のドキュメント</comment>
+ <comment xml:lang="ja">空の文書</comment>
<comment xml:lang="it">Documento vuoto</comment>
- <comment xml:lang="id">dokumen kosong</comment>
- <comment xml:lang="ia">Documento vacue</comment>
- <comment xml:lang="hu">üres dokumentum</comment>
- <comment xml:lang="hr">Prazan dokument</comment>
- <comment xml:lang="he">מסמך ריק</comment>
- <comment xml:lang="gl">documeto baleiro</comment>
- <comment xml:lang="ga">cáipéis fholamh</comment>
- <comment xml:lang="fur">document vueit</comment>
- <comment xml:lang="fr">document vide</comment>
- <comment xml:lang="fo">tómt skjal</comment>
- <comment xml:lang="fi">tyhjä asiakirja</comment>
- <comment xml:lang="eu">dokumentu hutsa</comment>
+ <comment xml:lang="eu">Dokumentu hutsa</comment>
<comment xml:lang="es">documento vacío</comment>
- <comment xml:lang="eo">malplena dokumento</comment>
- <comment xml:lang="en_GB">empty document</comment>
- <comment xml:lang="el">Κενό έγγραφο</comment>
<comment xml:lang="de">Leeres Dokument</comment>
- <comment xml:lang="da">tomt dokument</comment>
- <comment xml:lang="cs">prázdný dokument</comment>
- <comment xml:lang="ca">document buit</comment>
- <comment xml:lang="bg">Празен документ</comment>
- <comment xml:lang="be@latin">pusty dakument</comment>
- <comment xml:lang="ast">documentu baleru</comment>
- <comment xml:lang="ar">مستند فارغ</comment>
- <comment xml:lang="af">leë dokument</comment>
+ <comment xml:lang="be">пусты дакумент</comment>
</mime-type>
<mime-type type="application/x-zoo">
<comment>Zoo archive</comment>
@@ -22861,8 +23704,9 @@ command to generate the output files.
<comment xml:lang="tr">Zoo arşivi</comment>
<comment xml:lang="sv">Zoo-arkiv</comment>
<comment xml:lang="sr">Зoo архива</comment>
- <comment xml:lang="sq">Arkiv zoo</comment>
+ <comment xml:lang="sq">arkiv zoo</comment>
<comment xml:lang="sl">Datoteka arhiva ZOO</comment>
+ <comment xml:lang="si">සත්වෝද්යාන ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív Zoo</comment>
<comment xml:lang="ru">Архив ZOO</comment>
<comment xml:lang="ro">Arhivă Zoo</comment>
@@ -22879,6 +23723,7 @@ command to generate the output files.
<comment xml:lang="kk">Zoo архиві</comment>
<comment xml:lang="ja">Zoo アーカイブ</comment>
<comment xml:lang="it">Archivio zoo</comment>
+ <comment xml:lang="is">Zoo safnskrá</comment>
<comment xml:lang="id">Arsip Zoo</comment>
<comment xml:lang="ia">Archivo Zoo</comment>
<comment xml:lang="hu">Zoo archívum</comment>
@@ -22902,6 +23747,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu zoo</comment>
<comment xml:lang="bg">Архив — zoo</comment>
<comment xml:lang="be@latin">Archiŭ zoo</comment>
+ <comment xml:lang="be">архіў zoo</comment>
<comment xml:lang="az">Zoo arxivi</comment>
<comment xml:lang="ar">أرشيف Zoo</comment>
<comment xml:lang="af">Zoo-argief</comment>
@@ -22920,8 +23766,9 @@ command to generate the output files.
<comment xml:lang="tr">XHTML sayfası</comment>
<comment xml:lang="sv">XHTML-sida</comment>
<comment xml:lang="sr">ИксХТМЛ страница</comment>
- <comment xml:lang="sq">Faqe XHTML</comment>
+ <comment xml:lang="sq">faqe XHTML</comment>
<comment xml:lang="sl">Datoteka spletne strani XHTML</comment>
+ <comment xml:lang="si">XHTML පිටුව</comment>
<comment xml:lang="sk">Stránka XHTML</comment>
<comment xml:lang="ru">Страница XHTML</comment>
<comment xml:lang="ro">Pagină XHTML</comment>
@@ -22939,6 +23786,7 @@ command to generate the output files.
<comment xml:lang="kk">XHTML парағы</comment>
<comment xml:lang="ja">XHTML ページ</comment>
<comment xml:lang="it">Pagina XHTML</comment>
+ <comment xml:lang="is">XHTML síða</comment>
<comment xml:lang="id">Halaman XHTML</comment>
<comment xml:lang="ia">Pagina XHTML</comment>
<comment xml:lang="hu">XHTML-oldal</comment>
@@ -22961,6 +23809,7 @@ command to generate the output files.
<comment xml:lang="ca">pàgina XHTML</comment>
<comment xml:lang="bg">Страница — XHTML</comment>
<comment xml:lang="be@latin">Staronka XHTML</comment>
+ <comment xml:lang="be">старонка XHTML</comment>
<comment xml:lang="ar">صفحة XHTML</comment>
<comment xml:lang="af">XHTML-bladsy</comment>
<acronym>XHTML</acronym>
@@ -22988,8 +23837,9 @@ command to generate the output files.
<comment xml:lang="tr">Zip arşivi</comment>
<comment xml:lang="sv">Zip-arkiv</comment>
<comment xml:lang="sr">Зип архива</comment>
- <comment xml:lang="sq">Arkiv zip</comment>
+ <comment xml:lang="sq">arkiv zip</comment>
<comment xml:lang="sl">Datoteka arhiva ZIP</comment>
+ <comment xml:lang="si">Zip සංරක්ෂිතය</comment>
<comment xml:lang="sk">Archív ZIP</comment>
<comment xml:lang="ru">Архив ZIP</comment>
<comment xml:lang="ro">Arhivă zip</comment>
@@ -23006,6 +23856,7 @@ command to generate the output files.
<comment xml:lang="kk">Zip архиві</comment>
<comment xml:lang="ja">Zip アーカイブ</comment>
<comment xml:lang="it">Archivio zip</comment>
+ <comment xml:lang="is">Zip safnskrá</comment>
<comment xml:lang="id">Arsip Zip</comment>
<comment xml:lang="ia">Archivo Zip</comment>
<comment xml:lang="hu">Zip archívum</comment>
@@ -23029,6 +23880,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu zip</comment>
<comment xml:lang="bg">Архив — zip</comment>
<comment xml:lang="be@latin">Archiŭ zip</comment>
+ <comment xml:lang="be">архіў zip</comment>
<comment xml:lang="az">Zip arxivi</comment>
<comment xml:lang="ar">أرشيف Zip</comment>
<comment xml:lang="af">Zip-argief</comment>
@@ -23048,14 +23900,19 @@ command to generate the output files.
<comment xml:lang="uk">образ диска WIM</comment>
<comment xml:lang="tr">WIM disk görüntüsü</comment>
<comment xml:lang="sv">WIM-diskavbildning</comment>
+ <comment xml:lang="sq">pamje disku WIM</comment>
+ <comment xml:lang="sl">Slika diska WIM</comment>
+ <comment xml:lang="si">WIM තැටි රූපය</comment>
<comment xml:lang="sk">Obraz disku WIM</comment>
<comment xml:lang="ru">Образ диска WIM</comment>
<comment xml:lang="pt_BR">Imagem de disco WIM</comment>
<comment xml:lang="pl">Obraz dysku WIM</comment>
+ <comment xml:lang="nl">WIM-schijfkopiebestand</comment>
<comment xml:lang="ko">WIM 디스크 이미지</comment>
<comment xml:lang="kk">WIM диск бейнесі</comment>
<comment xml:lang="ja">WIM ディスクイメージ</comment>
<comment xml:lang="it">Immagine disco WIM</comment>
+ <comment xml:lang="is">WIM diskmynd</comment>
<comment xml:lang="id">Image disk WIM</comment>
<comment xml:lang="hu">WIM lemezkép</comment>
<comment xml:lang="hr">WIM slika diska</comment>
@@ -23069,6 +23926,7 @@ command to generate the output files.
<comment xml:lang="da">WIM-diskaftryk</comment>
<comment xml:lang="ca">imatge de disc WIM</comment>
<comment xml:lang="bg">Диск — WIM</comment>
+ <comment xml:lang="be">вобраз дыска WIM</comment>
<comment xml:lang="ar">صورة قرص WIM</comment>
<acronym>WIM</acronym>
<expanded-acronym>Windows Imaging Format</expanded-acronym>
@@ -23087,8 +23945,9 @@ command to generate the output files.
<comment xml:lang="tr">Dolby Digital sesi</comment>
<comment xml:lang="sv">Dolby Digital-ljud</comment>
<comment xml:lang="sr">Дигитални Долби звук</comment>
- <comment xml:lang="sq">Audio Dolby Digital</comment>
+ <comment xml:lang="sq">audio Dolby Digital</comment>
<comment xml:lang="sl">Zvočna datoteka Dolby Digital</comment>
+ <comment xml:lang="si">ඩොල්බි ඩිජිටල් ඕඩියෝ</comment>
<comment xml:lang="sk">Zvuk Dolby Digital</comment>
<comment xml:lang="ru">Аудио Dolby Digital</comment>
<comment xml:lang="ro">Audio Dolby Digital</comment>
@@ -23107,6 +23966,7 @@ command to generate the output files.
<comment xml:lang="ka">Dolby Digital-ის აუდიო</comment>
<comment xml:lang="ja">ドルビーデジタルオーディオ</comment>
<comment xml:lang="it">Audio Dolby Digital</comment>
+ <comment xml:lang="is">Dolby Digital hljóðskrá</comment>
<comment xml:lang="id">Audio Dolby Digital</comment>
<comment xml:lang="ia">Audio Dolby Digital</comment>
<comment xml:lang="hu">Dolby Digital hang</comment>
@@ -23119,7 +23979,7 @@ command to generate the output files.
<comment xml:lang="fo">Dolby Digital ljóður</comment>
<comment xml:lang="fi">Dolby Digital -ääni</comment>
<comment xml:lang="eu">Dolby audio digitala</comment>
- <comment xml:lang="es">audio Dolby Digital</comment>
+ <comment xml:lang="es">sonido Dolby Digital</comment>
<comment xml:lang="eo">Sondosiero en Dolby Digital</comment>
<comment xml:lang="en_GB">Dolby Digital audio</comment>
<comment xml:lang="el">Ψηφιακός Ήχος Dolby</comment>
@@ -23130,6 +23990,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio Dolby Digital</comment>
<comment xml:lang="bg">Аудио — Dolby Digital</comment>
<comment xml:lang="be@latin">Aŭdyjo Dolby Digital</comment>
+ <comment xml:lang="be">аўдыя Dolby Digital</comment>
<comment xml:lang="az">Dolby Digital audio</comment>
<comment xml:lang="ar">صوت Dolby Digital</comment>
<comment xml:lang="af">Dolby Digital-oudio</comment>
@@ -23146,18 +24007,22 @@ command to generate the output files.
<comment xml:lang="tr">DTS sesi</comment>
<comment xml:lang="sv">DTS-ljud</comment>
<comment xml:lang="sr">ДТС звук</comment>
+ <comment xml:lang="sq">audio DTS</comment>
<comment xml:lang="sl">Zvok DTS</comment>
+ <comment xml:lang="si">DTS ශ්රව්ය</comment>
<comment xml:lang="sk">Zvuk DTS</comment>
<comment xml:lang="ru">Аудио DTS</comment>
<comment xml:lang="pt_BR">Áudio DTS</comment>
<comment xml:lang="pt">aúdio DTS</comment>
<comment xml:lang="pl">Plik dźwiękowy DTS</comment>
<comment xml:lang="oc">àudio DTS</comment>
+ <comment xml:lang="nl">DTS-audio</comment>
<comment xml:lang="lv">DTS audio</comment>
<comment xml:lang="ko">DTS 오디오</comment>
<comment xml:lang="kk">DTS аудиосы</comment>
<comment xml:lang="ja">DTS オーディオ</comment>
<comment xml:lang="it">Audio DTS</comment>
+ <comment xml:lang="is">DTS hljóðskrá</comment>
<comment xml:lang="id">Audio DTS</comment>
<comment xml:lang="ia">Audio DTS</comment>
<comment xml:lang="hu">DTS hang</comment>
@@ -23169,7 +24034,7 @@ command to generate the output files.
<comment xml:lang="fr">audio DTS</comment>
<comment xml:lang="fi">DTS-ääni</comment>
<comment xml:lang="eu">DTS audioa</comment>
- <comment xml:lang="es">audio DTS</comment>
+ <comment xml:lang="es">sonido DTS</comment>
<comment xml:lang="en_GB">DTS audio</comment>
<comment xml:lang="el">Ήχος DTS</comment>
<comment xml:lang="de">DTS-Audio</comment>
@@ -23177,6 +24042,7 @@ command to generate the output files.
<comment xml:lang="cs">zvuk DTS</comment>
<comment xml:lang="ca">àudio DTS</comment>
<comment xml:lang="bg">Аудио — DTS</comment>
+ <comment xml:lang="be">аўдыя DTS</comment>
<comment xml:lang="ar">صوت DTS</comment>
<comment xml:lang="af">DTS-oudio</comment>
<acronym>DTS</acronym>
@@ -23196,6 +24062,29 @@ command to generate the output files.
</mime-type>
<mime-type type="audio/vnd.dts.hd">
<comment>DTS-HD audio</comment>
+ <comment xml:lang="zh_TW">DTS-HD 音訊</comment>
+ <comment xml:lang="zh_CN">DTS-HD 音频</comment>
+ <comment xml:lang="uk">звукові дані DTS-HD</comment>
+ <comment xml:lang="tr">DTS-HD sesi</comment>
+ <comment xml:lang="sv">DTS-HD-ljud</comment>
+ <comment xml:lang="sl">Zvok DTS-HD</comment>
+ <comment xml:lang="si">DTS-HD ශ්රව්ය</comment>
+ <comment xml:lang="ru">Аудио DTS-HD</comment>
+ <comment xml:lang="pt_BR">Áudio DTS-HD</comment>
+ <comment xml:lang="pl">Plik dźwiękowy DTS-HD</comment>
+ <comment xml:lang="nl">DTS-HD-audio</comment>
+ <comment xml:lang="ko">DTS-HD 오디오</comment>
+ <comment xml:lang="kk">DTS-HD аудиосы</comment>
+ <comment xml:lang="ja">DTS-HD オーディオ</comment>
+ <comment xml:lang="it">Audio DTS-HD</comment>
+ <comment xml:lang="hr">DTS-HD zvučni zapis</comment>
+ <comment xml:lang="fi">DTS-HD-ääni</comment>
+ <comment xml:lang="eu">DTS-HD audioa</comment>
+ <comment xml:lang="es">sonido DTS-HD</comment>
+ <comment xml:lang="en_GB">DTS-HD audio</comment>
+ <comment xml:lang="de">DTS-HD-Audio</comment>
+ <comment xml:lang="be">аўдыя DTS-HD</comment>
+ <comment xml:lang="ar">صوت DTS-HD</comment>
<acronym>DTS-HD</acronym>
<expanded-acronym>Digital Theater Systems High Definition</expanded-acronym>
<sub-class-of type="audio/vnd.dts"/>
@@ -23218,8 +24107,9 @@ command to generate the output files.
<comment xml:lang="tr">AMR sesi</comment>
<comment xml:lang="sv">AMR-ljud</comment>
<comment xml:lang="sr">АМР звук</comment>
- <comment xml:lang="sq">Audio AMR</comment>
+ <comment xml:lang="sq">audio AMR</comment>
<comment xml:lang="sl">Zvočna datoteka AMR</comment>
+ <comment xml:lang="si">AMR ශ්‍රව්‍ය</comment>
<comment xml:lang="sk">Zvuk AMR</comment>
<comment xml:lang="ru">Аудио AMR</comment>
<comment xml:lang="ro">Audio AMR</comment>
@@ -23237,6 +24127,7 @@ command to generate the output files.
<comment xml:lang="ka">AMR აუდიო</comment>
<comment xml:lang="ja">AMR オーディオ</comment>
<comment xml:lang="it">Audio AMR</comment>
+ <comment xml:lang="is">AMR hljóðskrá</comment>
<comment xml:lang="id">Audio AMR</comment>
<comment xml:lang="ia">Audio AMR</comment>
<comment xml:lang="hu">AMR hang</comment>
@@ -23249,7 +24140,7 @@ command to generate the output files.
<comment xml:lang="fo">AMR ljóður</comment>
<comment xml:lang="fi">AMR-ääni</comment>
<comment xml:lang="eu">AMR audioa</comment>
- <comment xml:lang="es">audio AMR</comment>
+ <comment xml:lang="es">sonido AMR</comment>
<comment xml:lang="eo">AMR-sondosiero</comment>
<comment xml:lang="en_GB">AMR audio</comment>
<comment xml:lang="el">Ήχος AMR</comment>
@@ -23259,6 +24150,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio AMR</comment>
<comment xml:lang="bg">Аудио — AMR</comment>
<comment xml:lang="be@latin">Aŭdyjo AMR</comment>
+ <comment xml:lang="be">аўдыя AMR</comment>
<comment xml:lang="ar">صوت AMR</comment>
<comment xml:lang="af">AMR-oudio</comment>
<acronym>AMR</acronym>
@@ -23279,8 +24171,9 @@ command to generate the output files.
<comment xml:lang="tr">AMR-WB sesi</comment>
<comment xml:lang="sv">AMR-WB-ljud</comment>
<comment xml:lang="sr">АМР-ВБ звук</comment>
- <comment xml:lang="sq">Audio AMR-WB</comment>
+ <comment xml:lang="sq">audio AMR-WB</comment>
<comment xml:lang="sl">Zvočna datoteka AMR-WB</comment>
+ <comment xml:lang="si">AMR-WB ශ්‍රව්‍ය</comment>
<comment xml:lang="sk">Zvuk AMR-WB</comment>
<comment xml:lang="ru">Аудио AMR-WB</comment>
<comment xml:lang="ro">Audio AMR-WB</comment>
@@ -23298,6 +24191,7 @@ command to generate the output files.
<comment xml:lang="ka">AMR-WB აუდიო</comment>
<comment xml:lang="ja">AMR-WB オーディオ</comment>
<comment xml:lang="it">Audio AMR-WB</comment>
+ <comment xml:lang="is">AMR-WB hljóðskrá</comment>
<comment xml:lang="id">Audio AMR-WB</comment>
<comment xml:lang="ia">Audio AMR-WB</comment>
<comment xml:lang="hu">AMR-WB hang</comment>
@@ -23310,7 +24204,7 @@ command to generate the output files.
<comment xml:lang="fo">AMR-WB ljóður</comment>
<comment xml:lang="fi">AMR-WB-ääni</comment>
<comment xml:lang="eu">AMR-WB audioa</comment>
- <comment xml:lang="es">audio AMR-WB</comment>
+ <comment xml:lang="es">sonido AMR-WB</comment>
<comment xml:lang="eo">AMR-WB-sondosiero</comment>
<comment xml:lang="en_GB">AMR-WB audio</comment>
<comment xml:lang="el">Ήχος AMR-WB</comment>
@@ -23320,6 +24214,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio AMR-WB</comment>
<comment xml:lang="bg">Аудио — AMR-WB</comment>
<comment xml:lang="be@latin">Aŭdyjo AMR-WB</comment>
+ <comment xml:lang="be">аўдыя AMR-WB</comment>
<comment xml:lang="ar">صوت AMR-WB</comment>
<comment xml:lang="af">AMR-WB-oudio</comment>
<acronym>AMR-WB</acronym>
@@ -23340,8 +24235,9 @@ command to generate the output files.
<comment xml:lang="tr">ULAW (Sun) sesi</comment>
<comment xml:lang="sv">ULAW-ljud (Sun)</comment>
<comment xml:lang="sr">УЛАВ (Сан) звук</comment>
- <comment xml:lang="sq">Audio ULAW (Sun)</comment>
+ <comment xml:lang="sq">audio ULAW (Sun)</comment>
<comment xml:lang="sl">Zvočna datoteka ULAW (Sun)</comment>
+ <comment xml:lang="si">ULAW (හිරු) ශ්‍රව්‍ය</comment>
<comment xml:lang="sk">Zvuk ULAW (Sun)</comment>
<comment xml:lang="ru">Аудио ULAW (Sun)</comment>
<comment xml:lang="ro">Fișier audio ULAW (Sun)</comment>
@@ -23359,6 +24255,7 @@ command to generate the output files.
<comment xml:lang="kk">ULAW (Sun) аудиосы</comment>
<comment xml:lang="ja">ULAW (Sun) オーディオ</comment>
<comment xml:lang="it">Audio ULAW (Sun)</comment>
+ <comment xml:lang="is">ULAW (Sun) hljóðskrá</comment>
<comment xml:lang="id">Audio ULAW (Sun)</comment>
<comment xml:lang="ia">Audio ULAW (sun)</comment>
<comment xml:lang="hu">ULAW (Sun) hang</comment>
@@ -23371,7 +24268,7 @@ command to generate the output files.
<comment xml:lang="fo">ULAW (Sun) ljóður</comment>
<comment xml:lang="fi">ULAW (Sun) -ääni</comment>
<comment xml:lang="eu">ULAW (sun) audioa</comment>
- <comment xml:lang="es">audio ULAW (Sun)</comment>
+ <comment xml:lang="es">sonido ULAW (Sun)</comment>
<comment xml:lang="eo">ULAW-sondosiero (Sun)</comment>
<comment xml:lang="en_GB">ULAW (Sun) audio</comment>
<comment xml:lang="el">Ήχος ULAW (Sun)</comment>
@@ -23382,6 +24279,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio ULAW (Sun)</comment>
<comment xml:lang="bg">Аудио — ULAW, Sun</comment>
<comment xml:lang="be@latin">Aŭdyjo ULAW (Sun)</comment>
+ <comment xml:lang="be">аўдыя ULAW (Sun)</comment>
<comment xml:lang="az">ULAW (Sun) audio faylı</comment>
<comment xml:lang="ar">صوت ULAW (صن)</comment>
<comment xml:lang="af">ULAW- (Sun) oudio</comment>
@@ -23400,8 +24298,9 @@ command to generate the output files.
<comment xml:lang="tr">Commodore 64 sesi</comment>
<comment xml:lang="sv">Commodore 64-ljud</comment>
<comment xml:lang="sr">звук Комодора 64</comment>
- <comment xml:lang="sq">Audio Commodore 64</comment>
+ <comment xml:lang="sq">audio Commodore 64</comment>
<comment xml:lang="sl">Zvočna datoteka Commodore 64</comment>
+ <comment xml:lang="si">කොමදෝරු 64 ශ්‍රව්‍ය</comment>
<comment xml:lang="sk">Zvuk Commodore 64</comment>
<comment xml:lang="ru">Аудио Commodore 64</comment>
<comment xml:lang="ro">Audio Commodore 64</comment>
@@ -23420,6 +24319,7 @@ command to generate the output files.
<comment xml:lang="ka">Commodore 64-ის აუდიო</comment>
<comment xml:lang="ja">Commodore 64 オーディオ</comment>
<comment xml:lang="it">Audio Commodore 64</comment>
+ <comment xml:lang="is">Commodore 64 hljóðskrá</comment>
<comment xml:lang="id">Audio Commodore 64</comment>
<comment xml:lang="ia">Audio Commodore 64</comment>
<comment xml:lang="hu">Commodore 64 hang</comment>
@@ -23432,7 +24332,7 @@ command to generate the output files.
<comment xml:lang="fo">Commodore 64 ljóð</comment>
<comment xml:lang="fi">Commodore 64 -ääni</comment>
<comment xml:lang="eu">Commodore 64 Audioa</comment>
- <comment xml:lang="es">audio de Commodore 64</comment>
+ <comment xml:lang="es">sonido de Commodore 64</comment>
<comment xml:lang="eo">Sondosiero de Commodore 64</comment>
<comment xml:lang="en_GB">Commodore 64 audio</comment>
<comment xml:lang="el">Ήχος Commodore 64</comment>
@@ -23442,6 +24342,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio de Commodore 64</comment>
<comment xml:lang="bg">Аудио — Commodore 64</comment>
<comment xml:lang="be@latin">Aŭdyjo Commodore 64</comment>
+ <comment xml:lang="be">аўдыя Commodore 64</comment>
<comment xml:lang="ar">صوت Commodore 64</comment>
<comment xml:lang="af">Commodore 64-oudio</comment>
<magic>
@@ -23459,8 +24360,9 @@ command to generate the output files.
<comment xml:lang="tr">PCM sesi</comment>
<comment xml:lang="sv">PCM-ljud</comment>
<comment xml:lang="sr">ПЦМ звук</comment>
- <comment xml:lang="sq">Audio PCM</comment>
+ <comment xml:lang="sq">audio PCM</comment>
<comment xml:lang="sl">Zvočna datoteka PCM</comment>
+ <comment xml:lang="si">PCM ශ්රව්ය</comment>
<comment xml:lang="sk">Zvuk PCM</comment>
<comment xml:lang="ru">Аудио PCM</comment>
<comment xml:lang="ro">Audio PCM</comment>
@@ -23478,6 +24380,7 @@ command to generate the output files.
<comment xml:lang="kk">PCM аудиосы</comment>
<comment xml:lang="ja">PCM オーディオ</comment>
<comment xml:lang="it">Audio PCM</comment>
+ <comment xml:lang="is">PCM hljóðskrá</comment>
<comment xml:lang="id">Audio PCM</comment>
<comment xml:lang="ia">Audio PCM</comment>
<comment xml:lang="hu">PCM hang</comment>
@@ -23490,7 +24393,7 @@ command to generate the output files.
<comment xml:lang="fo">PCM ljóður</comment>
<comment xml:lang="fi">PCM-ääni</comment>
<comment xml:lang="eu">PCM audioa</comment>
- <comment xml:lang="es">audio PCM</comment>
+ <comment xml:lang="es">sonido PCM</comment>
<comment xml:lang="eo">PCM-sondosiero</comment>
<comment xml:lang="en_GB">PCM audio</comment>
<comment xml:lang="el">Ήχος PCM</comment>
@@ -23501,6 +24404,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio PCM</comment>
<comment xml:lang="bg">Аудио — PCM</comment>
<comment xml:lang="be@latin">Aŭdyjo PCM</comment>
+ <comment xml:lang="be">аўдыя PCM</comment>
<comment xml:lang="az">PCM audio faylı</comment>
<comment xml:lang="ar">صوت PCM</comment>
<comment xml:lang="af">PCM-oudio</comment>
@@ -23531,8 +24435,9 @@ command to generate the output files.
<comment xml:lang="tr">AIFC sesi</comment>
<comment xml:lang="sv">AIFC-ljud</comment>
<comment xml:lang="sr">АИФЦ звук</comment>
- <comment xml:lang="sq">Audio AIFC</comment>
+ <comment xml:lang="sq">audio AIFC</comment>
<comment xml:lang="sl">Zvočna datoteka AIFC</comment>
+ <comment xml:lang="si">AIFC ශ්‍රව්‍ය</comment>
<comment xml:lang="sk">Zvuk AIFC</comment>
<comment xml:lang="ru">Аудио AIFC</comment>
<comment xml:lang="ro">Fișier audio AIFC</comment>
@@ -23551,6 +24456,7 @@ command to generate the output files.
<comment xml:lang="ka">AIFC აუდიო</comment>
<comment xml:lang="ja">AIFC オーディオ</comment>
<comment xml:lang="it">Audio AIFC</comment>
+ <comment xml:lang="is">AIFC hljóðskrá</comment>
<comment xml:lang="id">Audio AIFC</comment>
<comment xml:lang="ia">Audio AIFC</comment>
<comment xml:lang="hu">AIFC hang</comment>
@@ -23563,7 +24469,7 @@ command to generate the output files.
<comment xml:lang="fo">AIFC ljóður</comment>
<comment xml:lang="fi">AIFC-ääni</comment>
<comment xml:lang="eu">AIFC audioa</comment>
- <comment xml:lang="es">audio AIFC</comment>
+ <comment xml:lang="es">sonido AIFC</comment>
<comment xml:lang="eo">AIFC-sondosiero</comment>
<comment xml:lang="en_GB">AIFC audio</comment>
<comment xml:lang="el">Ήχος AIFC</comment>
@@ -23574,6 +24480,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio AIFC</comment>
<comment xml:lang="bg">Аудио — AIFC</comment>
<comment xml:lang="be@latin">Aŭdyjo AIFC</comment>
+ <comment xml:lang="be">аўдыя AIFC</comment>
<comment xml:lang="az">AIFC audio faylı</comment>
<comment xml:lang="ar">صوت AIFC</comment>
<comment xml:lang="af">AIFC-oudio</comment>
@@ -23596,8 +24503,9 @@ command to generate the output files.
<comment xml:lang="tr">AIFF/Amiga/Mac sesi</comment>
<comment xml:lang="sv">AIFF/Amiga/Mac-ljud</comment>
<comment xml:lang="sr">АИФФ/Амига/Мекинтош звук</comment>
- <comment xml:lang="sq">Audio AIFF/Amiga/Mac</comment>
+ <comment xml:lang="sq">audio AIFF/Amiga/Mac</comment>
<comment xml:lang="sl">Zvočna datoteka AIFF/Amiga/Mac</comment>
+ <comment xml:lang="si">AIFF/Amiga/Mac ශ්‍රව්‍ය</comment>
<comment xml:lang="sk">Zvuk AIFF/Amiga/Mac</comment>
<comment xml:lang="ru">Аудио AIFF/Amiga/Mac</comment>
<comment xml:lang="ro">Audio AIFF/Amiga/Mac</comment>
@@ -23616,6 +24524,7 @@ command to generate the output files.
<comment xml:lang="ka">AIFF/Amiga/Mac აუდიო</comment>
<comment xml:lang="ja">AIFF/Amiga/Mac オーディオ</comment>
<comment xml:lang="it">Audio AIFF/Amiga/Mac</comment>
+ <comment xml:lang="is">AIFF/Amiga/Mac hljóðskrá</comment>
<comment xml:lang="id">Audio AIFF/Amiga/Mac</comment>
<comment xml:lang="ia">Audio AIFF/Amiga/Mac</comment>
<comment xml:lang="hu">AIFF/Amiga/Mac hang</comment>
@@ -23628,7 +24537,7 @@ command to generate the output files.
<comment xml:lang="fo">AIFF/Amiga/Mac ljóður</comment>
<comment xml:lang="fi">AIFF/Amiga/Mac-ääni</comment>
<comment xml:lang="eu">AIFF/Amiga/Mac audioa</comment>
- <comment xml:lang="es">audio AIFF/Amiga/Mac</comment>
+ <comment xml:lang="es">sonido AIFF/Amiga/Mac</comment>
<comment xml:lang="eo">AIFF/Amiga/Mac-sondosiero</comment>
<comment xml:lang="en_GB">AIFF/Amiga/Mac audio</comment>
<comment xml:lang="el">Ήχος AIFF/Amiga/Mac</comment>
@@ -23639,6 +24548,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio AIFF/Amiga/Mac</comment>
<comment xml:lang="bg">Аудио — AIFF/Amiga/Mac</comment>
<comment xml:lang="be@latin">Aŭdyjo AIFF/Amiga/Mac</comment>
+ <comment xml:lang="be">аўдыя AIFF/Amiga/Mac</comment>
<comment xml:lang="az">AIFF/Amiga/Mac audio faylı</comment>
<comment xml:lang="ar">صوت AIFF/Amiga/Mac</comment>
<comment xml:lang="af">AIFF/Amiga/Mac-oudio</comment>
@@ -23661,8 +24571,9 @@ command to generate the output files.
<comment xml:lang="tr">Monkey's sesi</comment>
<comment xml:lang="sv">Monkey's audio</comment>
<comment xml:lang="sr">Монкијев звук</comment>
- <comment xml:lang="sq">Audio Monkey's</comment>
+ <comment xml:lang="sq">audio Monkey's</comment>
<comment xml:lang="sl">Zvočna datoteka Monkey</comment>
+ <comment xml:lang="si">වඳුරාගේ හඬ පටය</comment>
<comment xml:lang="sk">Zvuk Monkey's</comment>
<comment xml:lang="ru">Аудио Monkey's</comment>
<comment xml:lang="ro">Audio Monkey's</comment>
@@ -23679,6 +24590,7 @@ command to generate the output files.
<comment xml:lang="kk">Monkey аудиосы</comment>
<comment xml:lang="ja">Monkey's オーディオ</comment>
<comment xml:lang="it">Audio Monkey's</comment>
+ <comment xml:lang="is">Monkey's hljóðskrá</comment>
<comment xml:lang="id">Audio Monkey</comment>
<comment xml:lang="ia">Audio Monkey's</comment>
<comment xml:lang="hu">Monkey hang</comment>
@@ -23691,7 +24603,7 @@ command to generate the output files.
<comment xml:lang="fo">Monkey's ljóður</comment>
<comment xml:lang="fi">Monkey's Audio -ääni</comment>
<comment xml:lang="eu">Monkey audioa</comment>
- <comment xml:lang="es">audio de Monkey</comment>
+ <comment xml:lang="es">sonido de Monkey</comment>
<comment xml:lang="en_GB">Monkey's audio</comment>
<comment xml:lang="el">Ήχος Monkey's</comment>
<comment xml:lang="de">Monkey's-Audio</comment>
@@ -23700,6 +24612,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio de Monkey</comment>
<comment xml:lang="bg">Аудио — Monkey</comment>
<comment xml:lang="be@latin">Aŭdyjo Monkey's</comment>
+ <comment xml:lang="be">аўдыя Monkey's</comment>
<comment xml:lang="ar">صوت Monkey</comment>
<magic>
<match type="string" value="MAC " offset="0"/>
@@ -23713,14 +24626,19 @@ command to generate the output files.
<comment xml:lang="uk">звук Audible.Com</comment>
<comment xml:lang="tr">Audible.Com sesi</comment>
<comment xml:lang="sv">Audible.Com-ljud</comment>
+ <comment xml:lang="sq">audio Audible.Com</comment>
+ <comment xml:lang="sl">Zvok Audible.Com</comment>
+ <comment xml:lang="si">Audible.Com ශ්‍රව්‍ය</comment>
<comment xml:lang="sk">Audio Audible.Com</comment>
<comment xml:lang="ru">Аудио Audible.Com</comment>
<comment xml:lang="pt_BR">Áudio de audible.com</comment>
<comment xml:lang="pl">Plik dźwiękowy Audible.com</comment>
+ <comment xml:lang="nl">Audible.com-audio</comment>
<comment xml:lang="ko">Audible.Com 오디오</comment>
<comment xml:lang="kk">Audible.Com аудиосы</comment>
<comment xml:lang="ja">Audible.Com オーディオ</comment>
<comment xml:lang="it">Audio Audible.Com</comment>
+ <comment xml:lang="is">Audible.Com hljóðskrá</comment>
<comment xml:lang="id">Audio Audible.Com</comment>
<comment xml:lang="hu">Audible.Com hang</comment>
<comment xml:lang="hr">Audible.Com zvučni zapis</comment>
@@ -23730,13 +24648,14 @@ command to generate the output files.
<comment xml:lang="fr">audio Audible.Com</comment>
<comment xml:lang="fi">Audible.Com-ääni</comment>
<comment xml:lang="eu">Audible.Com audioa</comment>
- <comment xml:lang="es">audio de Audible.com</comment>
+ <comment xml:lang="es">sonido de Audible.com</comment>
<comment xml:lang="en_GB">Audible.Com audio</comment>
- <comment xml:lang="de">Audible.Com-Audio</comment>
+ <comment xml:lang="de">Audible.com-Audio</comment>
<comment xml:lang="da">Audible.Com-lyd</comment>
<comment xml:lang="cs">zvuk Audible.Com</comment>
<comment xml:lang="ca">àudio d'Audible.Com</comment>
<comment xml:lang="bg">Аудио — Audible.Com</comment>
+ <comment xml:lang="be">аўдыя Audible.Com</comment>
<comment xml:lang="ar">صوت Audible.Com</comment>
<magic>
<!-- https://github.com/FFmpeg/FFmpeg/blob/master/libavformat/aadec.c#L33 -->
@@ -23751,30 +24670,93 @@ command to generate the output files.
<comment xml:lang="uk">звук Audible Enhanced</comment>
<comment xml:lang="tr">Audible Enhanced sesi</comment>
<comment xml:lang="sv">Audible förbättrat ljud</comment>
+ <comment xml:lang="si">ශ්‍රවණය කළ හැකි වැඩිදියුණු කළ ශ්‍රව්‍ය</comment>
+ <comment xml:lang="ru">Аудио Audible Enhanced</comment>
<comment xml:lang="pt_BR">Áudio Audible Enhanced</comment>
<comment xml:lang="pl">Plik dźwiękowy Audible Enhanced</comment>
+ <comment xml:lang="nl">Audible verbeterde-audio</comment>
<comment xml:lang="ko">Audible 확장된 오디오</comment>
+ <comment xml:lang="kk">Audible Enhanced аудиосы</comment>
<comment xml:lang="ja">Audible エンハンスオーディオ</comment>
<comment xml:lang="it">Audio Audible Enhanced</comment>
+ <comment xml:lang="is">Audible Enhanced hljóðskrá</comment>
<comment xml:lang="id">audio Audible Enhanced</comment>
<comment xml:lang="hu">Audible Enhanced hang</comment>
<comment xml:lang="hr">Audible poboljšani zvučni zapis</comment>
<comment xml:lang="he">שמע Audible Enhanced</comment>
<comment xml:lang="fr">Audio amélioré Audible</comment>
<comment xml:lang="fi">Audible Enhanced -ääni</comment>
- <comment xml:lang="es">audio mejorado de Audible</comment>
+ <comment xml:lang="es">sonido mejorado de Audible</comment>
<comment xml:lang="en_GB">Audible Enhanced audio</comment>
- <comment xml:lang="de">Audible Erweitertes Audio</comment>
+ <comment xml:lang="de">Audible verbessertes Audio</comment>
<comment xml:lang="da">Audible Enhanced-lyd</comment>
<comment xml:lang="ca">àudio d'Audible Enhanced</comment>
+ <comment xml:lang="be">аўдыя Audible Enhanced</comment>
<comment xml:lang="ar">صوت محسن مسموع</comment>
<magic>
<match type="string" value="ftypaax " offset="4"/>
</magic>
<glob pattern="*.aax"/>
</mime-type>
+ <mime-type type="audio/vnd.audible.aaxc">
+ <comment>Audible Enhanced audio</comment>
+ <comment xml:lang="zh_CN">Audible 增强音频</comment>
+ <comment xml:lang="uk">звук Audible Enhanced</comment>
+ <comment xml:lang="tr">Audible Enhanced sesi</comment>
+ <comment xml:lang="sv">Audible förbättrat ljud</comment>
+ <comment xml:lang="si">ශ්‍රවණය කළ හැකි වැඩිදියුණු කළ ශ්‍රව්‍ය</comment>
+ <comment xml:lang="ru">Аудио Audible Enhanced</comment>
+ <comment xml:lang="pt_BR">Áudio Audible Enhanced</comment>
+ <comment xml:lang="pl">Plik dźwiękowy Audible Enhanced</comment>
+ <comment xml:lang="nl">Audible verbeterde-audio</comment>
+ <comment xml:lang="ko">Audible 확장된 오디오</comment>
+ <comment xml:lang="kk">Audible Enhanced аудиосы</comment>
+ <comment xml:lang="ja">Audible エンハンスオーディオ</comment>
+ <comment xml:lang="it">Audio Audible Enhanced</comment>
+ <comment xml:lang="is">Audible Enhanced hljóðskrá</comment>
+ <comment xml:lang="id">audio Audible Enhanced</comment>
+ <comment xml:lang="hu">Audible Enhanced hang</comment>
+ <comment xml:lang="hr">Audible poboljšani zvučni zapis</comment>
+ <comment xml:lang="he">שמע Audible Enhanced</comment>
+ <comment xml:lang="fr">Audio amélioré Audible</comment>
+ <comment xml:lang="fi">Audible Enhanced -ääni</comment>
+ <comment xml:lang="es">sonido mejorado de Audible</comment>
+ <comment xml:lang="en_GB">Audible Enhanced audio</comment>
+ <comment xml:lang="de">Audible verbessertes Audio</comment>
+ <comment xml:lang="da">Audible Enhanced-lyd</comment>
+ <comment xml:lang="ca">àudio d'Audible Enhanced</comment>
+ <comment xml:lang="be">аўдыя Audible Enhanced</comment>
+ <comment xml:lang="ar">صوت محسن مسموع</comment>
+ <magic priority="50">
+ <match type="string" value="ftypaaxc" offset="4"/>
+ </magic>
+ <glob pattern="*.aaxc"/>
+ </mime-type>
<mime-type type="audio/x-dff">
<comment>DSDIFF audio</comment>
+ <comment xml:lang="zh_TW">DSDIFF 音訊</comment>
+ <comment xml:lang="zh_CN">DSDIFF 音频</comment>
+ <comment xml:lang="uk">звукові дані DSDIFF</comment>
+ <comment xml:lang="tr">DSDIFF sesi</comment>
+ <comment xml:lang="sv">DSDIFF-ljud</comment>
+ <comment xml:lang="sl">Zvok DSDIFF</comment>
+ <comment xml:lang="si">DSDIFF ශ්රව්ය</comment>
+ <comment xml:lang="ru">Аудио DSDIFF</comment>
+ <comment xml:lang="pt_BR">Áudio DSDIFF</comment>
+ <comment xml:lang="pl">Plik dźwiękowy DSDIFF</comment>
+ <comment xml:lang="nl">DSDIFF-audio</comment>
+ <comment xml:lang="ko">DSDIFF 오디오</comment>
+ <comment xml:lang="kk">DSDIFF аудиосы</comment>
+ <comment xml:lang="ja">DSDIFF オーディオ</comment>
+ <comment xml:lang="it">Audio DSDIFF</comment>
+ <comment xml:lang="hr">DSDIFF zvučni zapis</comment>
+ <comment xml:lang="fi">DSDIFF-ääni</comment>
+ <comment xml:lang="eu">DSDIFF audioa</comment>
+ <comment xml:lang="es">sonido DSDIFF</comment>
+ <comment xml:lang="en_GB">DSDIFF audio</comment>
+ <comment xml:lang="de">DSDIFF-Audio</comment>
+ <comment xml:lang="be">аўдыя DSDIFF</comment>
+ <comment xml:lang="ar">صوت DSDIFF</comment>
<acronym>DSDIFF</acronym>
<expanded-acronym>Direct Stream Digital Interchange File Format</expanded-acronym>
<magic>
@@ -23788,6 +24770,30 @@ command to generate the output files.
</mime-type>
<mime-type type="audio/x-dsf">
<comment>DSF audio</comment>
+ <comment xml:lang="zh_TW">DSF 音訊</comment>
+ <comment xml:lang="zh_CN">DSF 音频</comment>
+ <comment xml:lang="uk">звукові дані DSF</comment>
+ <comment xml:lang="tr">DSF sesi</comment>
+ <comment xml:lang="sv">DSF-ljud</comment>
+ <comment xml:lang="sl">Zvok DSF</comment>
+ <comment xml:lang="si">DSF ශ්‍රව්‍ය</comment>
+ <comment xml:lang="ru">Аудио DSF</comment>
+ <comment xml:lang="pt_BR">Áudio DSF</comment>
+ <comment xml:lang="pl">Plik dźwiękowy DSF</comment>
+ <comment xml:lang="nl">DSF-audio</comment>
+ <comment xml:lang="ko">DSF 오디오</comment>
+ <comment xml:lang="kk">DSF аудиосы</comment>
+ <comment xml:lang="ja">DSF オーディオ</comment>
+ <comment xml:lang="it">Audio DSF</comment>
+ <comment xml:lang="hr">DSF zvučni zapis</comment>
+ <comment xml:lang="gl">Son DSF</comment>
+ <comment xml:lang="fi">DSF-ääni</comment>
+ <comment xml:lang="eu">DSF audioa</comment>
+ <comment xml:lang="es">sonido DSF</comment>
+ <comment xml:lang="en_GB">DSF audio</comment>
+ <comment xml:lang="de">DSF-Audio</comment>
+ <comment xml:lang="be">аўдыя DSF</comment>
+ <comment xml:lang="ar">صوت DSF</comment>
<acronym>DSF</acronym>
<expanded-acronym>Direct stream digital Stream File</expanded-acronym>
<magic>
@@ -23813,8 +24819,9 @@ command to generate the output files.
<comment xml:lang="tr">Impulse Tracker sesi</comment>
<comment xml:lang="sv">Impulse Tracker-ljud</comment>
<comment xml:lang="sr">звук Пратиоца Импулса</comment>
- <comment xml:lang="sq">Audio Impulse Tracker</comment>
+ <comment xml:lang="sq">audio Impulse Tracker</comment>
<comment xml:lang="sl">Zvočna datoteka Impulse Tracker</comment>
+ <comment xml:lang="si">Impulse Tracker ශ්‍රව්‍ය</comment>
<comment xml:lang="sk">Zvuk Impulse Tracker</comment>
<comment xml:lang="ru">Аудио Impulse Tracker</comment>
<comment xml:lang="ro">Audio Impulse Tracker</comment>
@@ -23832,6 +24839,7 @@ command to generate the output files.
<comment xml:lang="kk">Impulse Tracker аудиосы</comment>
<comment xml:lang="ja">Impulse Tracker オーディオ</comment>
<comment xml:lang="it">Audio Impulse Tracker</comment>
+ <comment xml:lang="is">Impulse Tracker hljóðskrá</comment>
<comment xml:lang="id">Audio Impulse Tracker</comment>
<comment xml:lang="ia">Audio Impulse Tracker</comment>
<comment xml:lang="hu">Impulse Tracker hang</comment>
@@ -23844,7 +24852,7 @@ command to generate the output files.
<comment xml:lang="fo">Impulse Tracker ljóður</comment>
<comment xml:lang="fi">Impulse Tracker -ääni</comment>
<comment xml:lang="eu">Impulse Tracker audioa</comment>
- <comment xml:lang="es">audio de Impulse Tracker</comment>
+ <comment xml:lang="es">sonido de Impulse Tracker</comment>
<comment xml:lang="eo">Sondosiero de Impulse Tracker</comment>
<comment xml:lang="en_GB">Impulse Tracker audio</comment>
<comment xml:lang="el">Ήχος Impulse Tracker</comment>
@@ -23855,6 +24863,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio d'Impulse Tracker</comment>
<comment xml:lang="bg">Аудио — Impulse Tracker</comment>
<comment xml:lang="be@latin">Aŭdyjo Impulse Tracker</comment>
+ <comment xml:lang="be">аўдыя Impulse Tracker</comment>
<comment xml:lang="az">Impulse Tracker audio faylı</comment>
<comment xml:lang="ar">صوت Impulse Tracker</comment>
<magic>
@@ -23871,8 +24880,9 @@ command to generate the output files.
<comment xml:lang="tr">FLAC sesi</comment>
<comment xml:lang="sv">FLAC-ljud</comment>
<comment xml:lang="sr">ФЛАЦ звук</comment>
- <comment xml:lang="sq">Audio FLAC</comment>
+ <comment xml:lang="sq">audio FLAC</comment>
<comment xml:lang="sl">Zvočna datoteka Flac</comment>
+ <comment xml:lang="si">FLAC ශ්රව්ය</comment>
<comment xml:lang="sk">Zvuk FLAC</comment>
<comment xml:lang="ru">Аудио FLAC</comment>
<comment xml:lang="ro">Audio FLAC</comment>
@@ -23891,6 +24901,7 @@ command to generate the output files.
<comment xml:lang="ka">FLAC აუდიო</comment>
<comment xml:lang="ja">FLAC オーディオ</comment>
<comment xml:lang="it">Audio FLAC</comment>
+ <comment xml:lang="is">FLAC hljóðskrá</comment>
<comment xml:lang="id">Audio FLAC</comment>
<comment xml:lang="ia">Audio FLAC</comment>
<comment xml:lang="hu">FLAC hang</comment>
@@ -23903,7 +24914,7 @@ command to generate the output files.
<comment xml:lang="fo">FLAC ljóður</comment>
<comment xml:lang="fi">FLAC-ääni</comment>
<comment xml:lang="eu">FLAC audioa</comment>
- <comment xml:lang="es">audio FLAC</comment>
+ <comment xml:lang="es">sonido FLAC</comment>
<comment xml:lang="eo">FLAC-sondosiero</comment>
<comment xml:lang="en_GB">FLAC audio</comment>
<comment xml:lang="el">Ήχος FLAC</comment>
@@ -23913,6 +24924,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio FLAC</comment>
<comment xml:lang="bg">Аудио — FLAC</comment>
<comment xml:lang="be@latin">Aŭdyjo FLAC</comment>
+ <comment xml:lang="be">аўдыя FLAC</comment>
<comment xml:lang="ar">صوت FLAC</comment>
<comment xml:lang="af">FLAC-oudio</comment>
<acronym>FLAC</acronym>
@@ -23923,6 +24935,26 @@ command to generate the output files.
<glob pattern="*.flac"/>
<alias type="audio/x-flac"/>
</mime-type>
+ <mime-type type="audio/x-tak">
+ <comment>TAK audio</comment>
+ <comment xml:lang="uk">звук TAK</comment>
+ <comment xml:lang="sv">TAK-ljud</comment>
+ <comment xml:lang="ru">Аудио TAK</comment>
+ <comment xml:lang="pt_BR">Áudio TAK</comment>
+ <comment xml:lang="pl">Plik dźwiękowy TAK</comment>
+ <comment xml:lang="it">Audio Tak</comment>
+ <comment xml:lang="gl">Son TAK</comment>
+ <comment xml:lang="eu">TAK audioa</comment>
+ <comment xml:lang="es">audio TAK</comment>
+ <comment xml:lang="de">TAK-Audio</comment>
+ <comment xml:lang="be">аўдыя TAK</comment>
+ <acronym>TAK</acronym>
+ <expanded-acronym>Tom's lossless Audio Kompressor</expanded-acronym>
+ <magic>
+ <match type="string" value="tBaK" offset="0"/>
+ </magic>
+ <glob pattern="*.tak"/>
+ </mime-type>
<mime-type type="audio/x-wavpack">
<comment>WavPack audio</comment>
<comment xml:lang="zh_TW">WavPack 音訊</comment>
@@ -23932,8 +24964,9 @@ command to generate the output files.
<comment xml:lang="tr">WavPack sesi</comment>
<comment xml:lang="sv">WavPack-ljud</comment>
<comment xml:lang="sr">Вејвпак звук</comment>
- <comment xml:lang="sq">Audio WavPack</comment>
+ <comment xml:lang="sq">audio WavPack</comment>
<comment xml:lang="sl">Zvočna datoteka WavPack</comment>
+ <comment xml:lang="si">WavPack ශ්රව්ය</comment>
<comment xml:lang="sk">Zvuk WavPack</comment>
<comment xml:lang="ru">Аудио WavPack</comment>
<comment xml:lang="ro">Audio WavPack</comment>
@@ -23950,6 +24983,7 @@ command to generate the output files.
<comment xml:lang="kk">WavPack аудиосы</comment>
<comment xml:lang="ja">WavPack オーディオ</comment>
<comment xml:lang="it">Audio WavPack</comment>
+ <comment xml:lang="is">WavPack hljóðskrá</comment>
<comment xml:lang="id">Audio WavPack</comment>
<comment xml:lang="ia">Audio WavPack</comment>
<comment xml:lang="hu">WavPack hang</comment>
@@ -23962,7 +24996,7 @@ command to generate the output files.
<comment xml:lang="fo">WavPack ljóður</comment>
<comment xml:lang="fi">WavPack-ääni</comment>
<comment xml:lang="eu">WavPack audioa</comment>
- <comment xml:lang="es">audio WavPack</comment>
+ <comment xml:lang="es">sonido WavPack</comment>
<comment xml:lang="eo">WavPack-sondosiero</comment>
<comment xml:lang="en_GB">WavPack audio</comment>
<comment xml:lang="el">Ήχος WavePack</comment>
@@ -23972,6 +25006,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio de WavPack</comment>
<comment xml:lang="bg">Аудио — WavPack</comment>
<comment xml:lang="be@latin">Aŭdyjo WavPack</comment>
+ <comment xml:lang="be">аўдыя WavPack</comment>
<comment xml:lang="ar">صوت WavPack</comment>
<comment xml:lang="af">WavPack-oudio</comment>
<magic>
@@ -23989,8 +25024,9 @@ command to generate the output files.
<comment xml:lang="tr">WavPack ses düzeltme dosyası</comment>
<comment xml:lang="sv">WavPack-ljudkorrigeringsfil</comment>
<comment xml:lang="sr">датотека поправке Вејвпак звука</comment>
- <comment xml:lang="sq">File korrigjgimi audio WavPack</comment>
+ <comment xml:lang="sq">kartelë saktësimi audio WavPack</comment>
<comment xml:lang="sl">popravljalna zvočna datoteka WavPack</comment>
+ <comment xml:lang="si">WavPack ශ්‍රව්‍ය නිවැරදි කිරීමේ ගොනුව</comment>
<comment xml:lang="sk">Opravný zvukový súbor WavPack</comment>
<comment xml:lang="ru">Файл коррекции аудио WavPack</comment>
<comment xml:lang="ro">Fișier audio de corecție WavPack</comment>
@@ -24007,6 +25043,7 @@ command to generate the output files.
<comment xml:lang="kk">WavPack аудио түзету файлы</comment>
<comment xml:lang="ja">WavPack オーディオコレクションファイル</comment>
<comment xml:lang="it">File correzione audio WavPack</comment>
+ <comment xml:lang="is">WavPack hljóðleiðréttingaskrá</comment>
<comment xml:lang="id">Berkas koreksi audio WavPack</comment>
<comment xml:lang="ia">File de correction audio WavPack</comment>
<comment xml:lang="hu">WavPack hangjavítási fájl</comment>
@@ -24019,7 +25056,7 @@ command to generate the output files.
<comment xml:lang="fo">WavPack ljóðrættingarfíla</comment>
<comment xml:lang="fi">WavPack-äänikorjaustiedosto</comment>
<comment xml:lang="eu">WavPack audio-zuzenketaren fitxategia</comment>
- <comment xml:lang="es">archivo de corrección de audio WavPack</comment>
+ <comment xml:lang="es">archivo de corrección de sonido WavPack</comment>
<comment xml:lang="en_GB">WavPack audio correction file</comment>
<comment xml:lang="el">Αρχείο διόρθωσης ήχου WavePack</comment>
<comment xml:lang="de">WavPack-Audiokorrekturdatei</comment>
@@ -24028,6 +25065,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer de correcció d'àudio de WavPack</comment>
<comment xml:lang="bg">Файл за корекции на аудио — WavPack</comment>
<comment xml:lang="be@latin">Fajł aŭdyjokarekcyi WavPack</comment>
+ <comment xml:lang="be">файл аўдыякарэкцыі WavPack</comment>
<comment xml:lang="ar">ملف تصحيح صوت WavPack</comment>
<magic>
<match type="string" value="wvpk" offset="0"/>
@@ -24043,8 +25081,9 @@ command to generate the output files.
<comment xml:lang="tr">MIDI sesi</comment>
<comment xml:lang="sv">MIDI-ljud</comment>
<comment xml:lang="sr">МИДИ звук</comment>
- <comment xml:lang="sq">Audio MIDI</comment>
+ <comment xml:lang="sq">audio MIDI</comment>
<comment xml:lang="sl">Zvočna datoteka MIDI</comment>
+ <comment xml:lang="si">MIDI ශ්‍රව්‍ය</comment>
<comment xml:lang="sk">Zvuk MIDI</comment>
<comment xml:lang="ru">Аудио MIDI</comment>
<comment xml:lang="ro">Audio MIDI</comment>
@@ -24062,6 +25101,7 @@ command to generate the output files.
<comment xml:lang="kk">MIDI аудиосы</comment>
<comment xml:lang="ja">MIDI オーディオ</comment>
<comment xml:lang="it">Audio MIDI</comment>
+ <comment xml:lang="is">MIDI hljóðskrá</comment>
<comment xml:lang="id">Audio MIDI</comment>
<comment xml:lang="ia">Audio MIDI</comment>
<comment xml:lang="hu">MIDI hang</comment>
@@ -24074,7 +25114,7 @@ command to generate the output files.
<comment xml:lang="fo">MIDI ljóður</comment>
<comment xml:lang="fi">MIDI-ääni</comment>
<comment xml:lang="eu">MIDI audioa</comment>
- <comment xml:lang="es">audio MIDI</comment>
+ <comment xml:lang="es">sonido MIDI</comment>
<comment xml:lang="eo">MIDI-sondosiero</comment>
<comment xml:lang="en_GB">MIDI audio</comment>
<comment xml:lang="el">Ήχος MIDI</comment>
@@ -24085,6 +25125,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio MIDI</comment>
<comment xml:lang="bg">Аудио — MIDI</comment>
<comment xml:lang="be@latin">Aŭdyjo MIDI</comment>
+ <comment xml:lang="be">аўдыя MIDI</comment>
<comment xml:lang="az">MIDI audio faylı</comment>
<comment xml:lang="ar">صوت MIDI</comment>
<comment xml:lang="af">MIDI-oudio</comment>
@@ -24099,53 +25140,16 @@ command to generate the output files.
<glob pattern="*.kar"/>
</mime-type>
<mime-type type="audio/x-mo3">
- <comment>compressed Tracker audio</comment>
- <comment xml:lang="zh_TW">壓縮版 Tracker 音訊</comment>
- <comment xml:lang="zh_CN">压缩的 Tracker 音频</comment>
- <comment xml:lang="vi">âm thanh Tracker đã nén</comment>
- <comment xml:lang="uk">стиснутий звук Tracker</comment>
- <comment xml:lang="tr">sıkıştırılmış Tracker sesi</comment>
- <comment xml:lang="sv">komprimerat Tracker-ljud</comment>
- <comment xml:lang="sr">запаковани звук Пратиоца</comment>
- <comment xml:lang="sq">Audio Tracker e kompresuar</comment>
- <comment xml:lang="sl">Skrčena zvočna datoteka Tracker</comment>
- <comment xml:lang="sk">Komprimovaný zvuk Tracker</comment>
+ <comment>Compressed Tracker audio</comment>
+ <comment xml:lang="uk">стиснутий звук tracker</comment>
+ <comment xml:lang="sv">Komprimerat Tracker-ljud</comment>
<comment xml:lang="ru">Сжатое аудио Tracker</comment>
- <comment xml:lang="ro">Tracker audio comprimat</comment>
- <comment xml:lang="pt_BR">Áudio Tracker compactado</comment>
- <comment xml:lang="pt">áudio comprimido Tracker</comment>
<comment xml:lang="pl">Skompresowany plik dźwiękowy Tracker</comment>
- <comment xml:lang="oc">àudio Tracker compressat</comment>
- <comment xml:lang="nn">komprimert Tracker-lyd</comment>
- <comment xml:lang="nl">ingepakte Tracker-audio</comment>
- <comment xml:lang="lv">saspiests Tracker audio</comment>
- <comment xml:lang="lt">suglaudintas Tracker garso įrašas</comment>
- <comment xml:lang="ko">압축된 Tracker 오디오</comment>
- <comment xml:lang="kk">сығылған Tracker аудиосы</comment>
- <comment xml:lang="ja">圧縮 Tracker オーディオ</comment>
<comment xml:lang="it">Audio compresso Tracker</comment>
- <comment xml:lang="id">audio Tracker terkompresi</comment>
- <comment xml:lang="ia">Audio Tracker comprimite</comment>
- <comment xml:lang="hu">tömörített Tracker hang</comment>
- <comment xml:lang="hr">Sažeti Tracker zvučni zapis</comment>
- <comment xml:lang="he">שמע גשש מכווץ</comment>
- <comment xml:lang="gl">son comprimido de Tracker</comment>
- <comment xml:lang="ga">fuaim chomhbhrúite Tracker</comment>
- <comment xml:lang="fur">audio Tracker comprimût</comment>
- <comment xml:lang="fr">audio Tracker compressé</comment>
- <comment xml:lang="fo">stappað Tracker ljóður</comment>
- <comment xml:lang="fi">pakattu Tracker-ääni</comment>
- <comment xml:lang="eu">konprimitutako Tracker audioa</comment>
+ <comment xml:lang="gl">Son de Tracker comprimido</comment>
<comment xml:lang="es">audio de Tracker comprimido</comment>
- <comment xml:lang="en_GB">compressed Tracker audio</comment>
- <comment xml:lang="el">Συμπιεσμένος ήχος Tracker</comment>
<comment xml:lang="de">Komprimiertes Tracker-Audio</comment>
- <comment xml:lang="da">komprimeret trackerlyd</comment>
- <comment xml:lang="cs">komprimovaný zvuk Tracker</comment>
- <comment xml:lang="ca">àudio Tracker amb compressió</comment>
- <comment xml:lang="bg">Аудио — Tracker, компресирано</comment>
- <comment xml:lang="be@latin">aŭdyjo skampresavanaha Trackera</comment>
- <comment xml:lang="ar">صوت Tracker مضغوط</comment>
+ <comment xml:lang="be">сціснутае аўдыя Tracker</comment>
<magic>
<match type="string" value="MO3" offset="0"/>
</magic>
@@ -24159,18 +25163,22 @@ command to generate the output files.
<comment xml:lang="tr">AAC sesi</comment>
<comment xml:lang="sv">AAC-ljud</comment>
<comment xml:lang="sr">ААЦ звук</comment>
+ <comment xml:lang="sq">audio AAC</comment>
<comment xml:lang="sl">Zvok AAC</comment>
+ <comment xml:lang="si">AAC ශ්රව්ය</comment>
<comment xml:lang="sk">Zvuk AAC</comment>
<comment xml:lang="ru">Аудио AAC</comment>
<comment xml:lang="pt_BR">Áudio AAC</comment>
<comment xml:lang="pt">áudio AAC</comment>
<comment xml:lang="pl">Plik dźwiękowy AAC</comment>
<comment xml:lang="oc">àudio AAC</comment>
+ <comment xml:lang="nl">AAC-audio</comment>
<comment xml:lang="lv">AAC audio</comment>
<comment xml:lang="ko">AAC 오디오</comment>
<comment xml:lang="kk">AAC аудиосы</comment>
<comment xml:lang="ja">AAC オーディオ</comment>
<comment xml:lang="it">Audio AAC</comment>
+ <comment xml:lang="is">AAC hljóðskrá</comment>
<comment xml:lang="id">Audio AAC</comment>
<comment xml:lang="ia">Audio ACC</comment>
<comment xml:lang="hu">AAC hang</comment>
@@ -24182,7 +25190,7 @@ command to generate the output files.
<comment xml:lang="fr">audio AAC</comment>
<comment xml:lang="fi">AAC-ääni</comment>
<comment xml:lang="eu">AAC audioa</comment>
- <comment xml:lang="es">audio AAC</comment>
+ <comment xml:lang="es">sonido AAC</comment>
<comment xml:lang="en_GB">AAC audio</comment>
<comment xml:lang="el">Ήχος AAC</comment>
<comment xml:lang="de">AAC-Audio</comment>
@@ -24190,6 +25198,7 @@ command to generate the output files.
<comment xml:lang="cs">zvuk AAC</comment>
<comment xml:lang="ca">àudio AAC</comment>
<comment xml:lang="bg">Аудио — AAC</comment>
+ <comment xml:lang="be">аўдыя AAC</comment>
<comment xml:lang="ar">صوت AAC</comment>
<comment xml:lang="af">AAC-oudio</comment>
<acronym>AAC</acronym>
@@ -24210,30 +25219,37 @@ command to generate the output files.
<comment xml:lang="uk">звукові дані USAC</comment>
<comment xml:lang="tr">USAC sesi</comment>
<comment xml:lang="sv">USAC-ljud</comment>
+ <comment xml:lang="sq">audio USAC</comment>
+ <comment xml:lang="sl">Zvok USAC</comment>
+ <comment xml:lang="si">USAC ශ්රව්ය</comment>
<comment xml:lang="sk">Zvuk USAC</comment>
<comment xml:lang="ru">Аудио USAC</comment>
<comment xml:lang="pt_BR">Áudio USAC</comment>
<comment xml:lang="pl">Plik dźwiękowy USAC</comment>
+ <comment xml:lang="nl">USAC-audio</comment>
<comment xml:lang="ko">USAC 오디오</comment>
<comment xml:lang="kk">USAC аудиосы</comment>
<comment xml:lang="ja">USAC オーディオ</comment>
<comment xml:lang="it">Audio USAC</comment>
+ <comment xml:lang="is">USAC hljóðskrá</comment>
<comment xml:lang="id">Audio USAC</comment>
<comment xml:lang="hu">USAC hang</comment>
<comment xml:lang="hr">USAC zvučni zapis</comment>
<comment xml:lang="he">שמע USAC</comment>
+ <comment xml:lang="gl">Son USAC</comment>
<comment xml:lang="ga">fuaim USAC</comment>
<comment xml:lang="fur">audio USAC</comment>
<comment xml:lang="fr">audio USAC</comment>
<comment xml:lang="fi">USAC-ääni</comment>
<comment xml:lang="eu">USAC audioa</comment>
- <comment xml:lang="es">audio USAC</comment>
+ <comment xml:lang="es">sonido USAC</comment>
<comment xml:lang="en_GB">USAC audio</comment>
<comment xml:lang="de">USAC-Audio</comment>
<comment xml:lang="da">USAC-lyd</comment>
<comment xml:lang="cs">zvuk USAC</comment>
<comment xml:lang="ca">àudio USAC</comment>
<comment xml:lang="bg">Аудио — USAC</comment>
+ <comment xml:lang="be">аўдыя USAC</comment>
<comment xml:lang="ar">صوت USAC</comment>
<comment xml:lang="af">USAC-oudio</comment>
<acronym>USAC</acronym>
@@ -24250,8 +25266,9 @@ command to generate the output files.
<comment xml:lang="tr">MPEG-4 sesi</comment>
<comment xml:lang="sv">MPEG-4-ljud</comment>
<comment xml:lang="sr">МПЕГ-4 звук</comment>
- <comment xml:lang="sq">Audio MPEG-4</comment>
+ <comment xml:lang="sq">audio MPEG-4</comment>
<comment xml:lang="sl">Zvočna datoteka MPEG-4</comment>
+ <comment xml:lang="si">MPEG-4 ශ්රව්ය</comment>
<comment xml:lang="sk">Zvuk MPEG-4</comment>
<comment xml:lang="ru">Аудио MPEG-4</comment>
<comment xml:lang="ro">Audio MPEG-4</comment>
@@ -24269,6 +25286,7 @@ command to generate the output files.
<comment xml:lang="ka">MPEG-4 აუდიო</comment>
<comment xml:lang="ja">MPEG-4 オーディオ</comment>
<comment xml:lang="it">Audio MPEG-4</comment>
+ <comment xml:lang="is">MPEG-4 hljóð</comment>
<comment xml:lang="id">Audio MPEG-4</comment>
<comment xml:lang="ia">Audio MPEG-4</comment>
<comment xml:lang="hu">MPEG-4 hang</comment>
@@ -24281,7 +25299,7 @@ command to generate the output files.
<comment xml:lang="fo">MPEG-4 ljóður</comment>
<comment xml:lang="fi">MPEG-4-ääni</comment>
<comment xml:lang="eu">MPEG-4 audioa</comment>
- <comment xml:lang="es">audio MPEG-4</comment>
+ <comment xml:lang="es">sonido MPEG-4</comment>
<comment xml:lang="eo">MPEG4-sondosiero</comment>
<comment xml:lang="en_GB">MPEG-4 audio</comment>
<comment xml:lang="el">Ήχος MPEG-4</comment>
@@ -24291,6 +25309,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio MPEG-4</comment>
<comment xml:lang="bg">Аудио — MPEG-4</comment>
<comment xml:lang="be@latin">Aŭdyjo MPEG-4</comment>
+ <comment xml:lang="be">аўдыя MPEG-4</comment>
<comment xml:lang="ar">صوت MPEG-4</comment>
<comment xml:lang="af">MPEG-4-oudio</comment>
<alias type="audio/x-m4a"/>
@@ -24308,18 +25327,24 @@ command to generate the output files.
<comment xml:lang="uk">рингтон MPEG-4</comment>
<comment xml:lang="tr">MPEG-4 zil sesi</comment>
<comment xml:lang="sv">MPEG-4-ringsignal</comment>
+ <comment xml:lang="sq">zile MPEG-4</comment>
+ <comment xml:lang="sl">Zvonjenje MPEG-4</comment>
+ <comment xml:lang="si">MPEG-4 නාද රටාව</comment>
<comment xml:lang="sk">Zvonenie MPEG-4</comment>
<comment xml:lang="ru">Мелодия MPEG-4</comment>
<comment xml:lang="pt_BR">Toque MPEG-4</comment>
<comment xml:lang="pl">Dzwonek MPEG-4</comment>
+ <comment xml:lang="nl">MPEG-4-ringtone</comment>
<comment xml:lang="ko">MPEG-4 벨소리</comment>
<comment xml:lang="kk">MPEG-4 рингтоны</comment>
<comment xml:lang="ja">MPEG-4 着信音</comment>
<comment xml:lang="it">Suoneria MPEG-4</comment>
+ <comment xml:lang="is">MPEG-4 hringitónn</comment>
<comment xml:lang="id">Nada panggil MPEG-4</comment>
<comment xml:lang="hu">MPEG-4 csengőhang</comment>
<comment xml:lang="hr">MPEG-4 melodija zvona</comment>
<comment xml:lang="he">נעימון MPEG-4</comment>
+ <comment xml:lang="gl">Ton de chamada MPEG-4</comment>
<comment xml:lang="fr">sonnerie MPEG-4</comment>
<comment xml:lang="fi">MPEG-4-soittoääni</comment>
<comment xml:lang="eu">MPEG-4 dei-tonua</comment>
@@ -24329,6 +25354,7 @@ command to generate the output files.
<comment xml:lang="da">MPEG-4-ringetone</comment>
<comment xml:lang="ca">to de trucada MPEG-4</comment>
<comment xml:lang="bg">Аудио — MPEG-4, звънене</comment>
+ <comment xml:lang="be">мелодыя выкліку MPEG-4</comment>
<comment xml:lang="ar">نغمة MPEG-4</comment>
<glob pattern="*.m4r"/>
<sub-class-of type="video/mp4"/>
@@ -24342,8 +25368,9 @@ command to generate the output files.
<comment xml:lang="tr">MPEG-4 video</comment>
<comment xml:lang="sv">MPEG-4-video</comment>
<comment xml:lang="sr">МПЕГ-4 видео</comment>
- <comment xml:lang="sq">Video MPEG-4</comment>
+ <comment xml:lang="sq">video MPEG-4</comment>
<comment xml:lang="sl">Video datoteka MPEG-4</comment>
+ <comment xml:lang="si">MPEG-4 වීඩියෝව</comment>
<comment xml:lang="sk">Video MPEG-4</comment>
<comment xml:lang="ru">Видео MPEG-4</comment>
<comment xml:lang="ro">Video MPEG-4</comment>
@@ -24361,6 +25388,7 @@ command to generate the output files.
<comment xml:lang="ka">MPEG-4 ვიდეო</comment>
<comment xml:lang="ja">MPEG-4 動画</comment>
<comment xml:lang="it">Video MPEG-4</comment>
+ <comment xml:lang="is">MPEG-4 myndskeið</comment>
<comment xml:lang="id">Video MPEG-4</comment>
<comment xml:lang="ia">Video MPEG-4</comment>
<comment xml:lang="hu">MPEG-4 videó</comment>
@@ -24383,6 +25411,7 @@ command to generate the output files.
<comment xml:lang="ca">vídeo MPEG-4</comment>
<comment xml:lang="bg">Видео — MPEG-4</comment>
<comment xml:lang="be@latin">Videa MPEG-4</comment>
+ <comment xml:lang="be">відэа MPEG-4</comment>
<comment xml:lang="ast">Videu en MPEG-4</comment>
<comment xml:lang="ar">فيديو MPEG-4</comment>
<comment xml:lang="af">MPEG-4-video</comment>
@@ -24410,8 +25439,9 @@ command to generate the output files.
<comment xml:lang="tr">MPEG-4 sesli kitabı</comment>
<comment xml:lang="sv">MPEG-4-ljudbok</comment>
<comment xml:lang="sr">МПЕГ-4 звукотека</comment>
- <comment xml:lang="sq">Audiolibër MPEG-4</comment>
+ <comment xml:lang="sq">audiolibër MPEG-4</comment>
<comment xml:lang="sl">Zvočna knjiga MPEG-4</comment>
+ <comment xml:lang="si">MPEG-4 ශ්රව්ය පොත</comment>
<comment xml:lang="sk">Zvuková kniha MPEG-4</comment>
<comment xml:lang="ru">Аудиокнига MPEG-4</comment>
<comment xml:lang="ro">Carte audio MPEG-4</comment>
@@ -24429,6 +25459,7 @@ command to generate the output files.
<comment xml:lang="ka">MPEG-4 აუდიოწიგნი</comment>
<comment xml:lang="ja">MPEG-4 オーディオブック</comment>
<comment xml:lang="it">Audiolibro MPEG-4</comment>
+ <comment xml:lang="is">MPEG-4 hljóðbók</comment>
<comment xml:lang="id">Buku audio MPEG-4</comment>
<comment xml:lang="ia">Libro audio MPEG-4</comment>
<comment xml:lang="hu">MPEG-4 hangoskönyv</comment>
@@ -24451,6 +25482,7 @@ command to generate the output files.
<comment xml:lang="ca">llibre d'àudio MPEG-4</comment>
<comment xml:lang="bg">Аудио книга — MPEG-4</comment>
<comment xml:lang="be@latin">Aŭdyjokniha MPEG-4</comment>
+ <comment xml:lang="be">аўдыякніга MPEG-4</comment>
<comment xml:lang="ar">كتاب MPEG-4 صوتي</comment>
<comment xml:lang="af">MPEG-4-oudioboek</comment>
<sub-class-of type="audio/mp4"/>
@@ -24469,8 +25501,9 @@ command to generate the output files.
<comment xml:lang="tr">3GPP çoklu ortam dosyası</comment>
<comment xml:lang="sv">3GPP-multimediafil</comment>
<comment xml:lang="sr">3ГПП мултимедијална датотека</comment>
- <comment xml:lang="sq">File multimedial 3GPP</comment>
+ <comment xml:lang="sq">kartelë multimedia 3GPP</comment>
<comment xml:lang="sl">Večpredstavnostna datoteka 3GPP</comment>
+ <comment xml:lang="si">3GPP බහුමාධ්‍ය ගොනුව</comment>
<comment xml:lang="sk">Súbor multimédií 3GPP</comment>
<comment xml:lang="ru">Мультимедийный файл 3GPP</comment>
<comment xml:lang="ro">Fișier multimedia 3GPP</comment>
@@ -24488,6 +25521,7 @@ command to generate the output files.
<comment xml:lang="ka">3GPP მულტიმედიური ფაილი</comment>
<comment xml:lang="ja">3GPP マルチメディアファイル</comment>
<comment xml:lang="it">File multimediale 3GPP</comment>
+ <comment xml:lang="is">3GPP margmiðlunarskrá</comment>
<comment xml:lang="id">Berkas multimedia 3GPP</comment>
<comment xml:lang="ia">File multimedial 3GPP</comment>
<comment xml:lang="hu">3GPP multimédiafájl</comment>
@@ -24509,6 +25543,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer multimèdia 3GPP</comment>
<comment xml:lang="bg">Мултимедия — 3GPP</comment>
<comment xml:lang="be@latin">Multymedyjny fajł 3GPP</comment>
+ <comment xml:lang="be">мультымедыйны файл 3GPP</comment>
<comment xml:lang="ar">ملف وسائط متعددة 3GPP</comment>
<comment xml:lang="af">3GPP-multimedialêer</comment>
<acronym>3GPP</acronym>
@@ -24540,7 +25575,9 @@ command to generate the output files.
<comment xml:lang="tr">3GPP2 çoklu ortam dosyası</comment>
<comment xml:lang="sv">3GPP2-multimediafil</comment>
<comment xml:lang="sr">3ГПП2 мултимедијална датотека</comment>
+ <comment xml:lang="sq">kartelë multimedia 3GPP2</comment>
<comment xml:lang="sl">Večpredstavnostna datoteka 3GPP2</comment>
+ <comment xml:lang="si">3GPP2 බහුමාධ්‍ය ගොනුව</comment>
<comment xml:lang="sk">Súbor multimédií 3GPP2</comment>
<comment xml:lang="ru">Мультимедийный файл 3GPP2</comment>
<comment xml:lang="ro">Fișier multimedia 3GPP2</comment>
@@ -24548,7 +25585,7 @@ command to generate the output files.
<comment xml:lang="pt">ficheiro multimédia 3GPP2</comment>
<comment xml:lang="pl">Plik multimedialny 3GPP2</comment>
<comment xml:lang="oc">fichièr multimèdia 3GPP2</comment>
- <comment xml:lang="nl">3GPP2 multimedia bestand</comment>
+ <comment xml:lang="nl">3GPP2-multimediabestand</comment>
<comment xml:lang="lv">3GPP2 multimediju datne</comment>
<comment xml:lang="lt">3GPP2 multimedijos failas</comment>
<comment xml:lang="ko">3GPP2 멀티미디어 파일</comment>
@@ -24556,6 +25593,7 @@ command to generate the output files.
<comment xml:lang="ka">3GPP2 მულტიმედიური ფაილი</comment>
<comment xml:lang="ja">3GPP2 マルチメディアファイル</comment>
<comment xml:lang="it">File multimediale 3GPP2</comment>
+ <comment xml:lang="is">3GPP2 margmiðlunarskrá</comment>
<comment xml:lang="id">Berkas multimedia 3GPP2</comment>
<comment xml:lang="ia">File multimedial 3GPP2</comment>
<comment xml:lang="hu">3GPP2 multimédiafájl</comment>
@@ -24576,6 +25614,7 @@ command to generate the output files.
<comment xml:lang="cs">multimediální soubor 3GPP2</comment>
<comment xml:lang="ca">fitxer multimèdia 3GPP2</comment>
<comment xml:lang="bg">Мултимедия — 3GPP2</comment>
+ <comment xml:lang="be">мультымедыйны файл 3GPP2</comment>
<comment xml:lang="ar">ملف وسائط متعددة 3GPP2</comment>
<comment xml:lang="af">3GPP2-multimedialêer</comment>
<acronym>3GPP2</acronym>
@@ -24597,8 +25636,9 @@ command to generate the output files.
<comment xml:lang="tr">Amiga SoundTracker sesi</comment>
<comment xml:lang="sv">Amiga SoundTracker-ljud</comment>
<comment xml:lang="sr">звук Амигиног Пратиоца Звука</comment>
- <comment xml:lang="sq">Audio Amiga SoundTracker</comment>
+ <comment xml:lang="sq">audio Amiga SoundTracker</comment>
<comment xml:lang="sl">Zvočna datoteka Amiga SoundTracker</comment>
+ <comment xml:lang="si">Amiga SoundTracker ශ්‍රව්‍ය</comment>
<comment xml:lang="sk">Zvuk Amiga SoundTracker</comment>
<comment xml:lang="ru">Аудио Amiga SoundTracker</comment>
<comment xml:lang="ro">Audio Amiga SoundTracker</comment>
@@ -24617,6 +25657,7 @@ command to generate the output files.
<comment xml:lang="ka">Amiga SoundTracker-ის აუდიო</comment>
<comment xml:lang="ja">Amiga SoundTracker オーディオ</comment>
<comment xml:lang="it">Audio Amiga SoundTracker</comment>
+ <comment xml:lang="is">Amiga SoundTracker hljóðskrá</comment>
<comment xml:lang="id">Audio Amida SoundTracker</comment>
<comment xml:lang="ia">Audio Amiga SoundTracker</comment>
<comment xml:lang="hu">Amiga SoundTracker hang</comment>
@@ -24629,7 +25670,7 @@ command to generate the output files.
<comment xml:lang="fo">Amiga SoundTracker ljóður</comment>
<comment xml:lang="fi">Amiga SoundTracker -ääni</comment>
<comment xml:lang="eu">Amiga soundtracker audioa</comment>
- <comment xml:lang="es">audio de Amiga SoundTracker</comment>
+ <comment xml:lang="es">sonido de Amiga SoundTracker</comment>
<comment xml:lang="eo">Sondosiero de Amiga SoundTracker</comment>
<comment xml:lang="en_GB">Amiga SoundTracker audio</comment>
<comment xml:lang="el">Ήχος Amiga SoundTracker</comment>
@@ -24639,6 +25680,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio SoundTracker d'Amiga</comment>
<comment xml:lang="bg">Аудио — Amiga SoundTracker</comment>
<comment xml:lang="be@latin">Aŭdyjo Amiga SoundTracker</comment>
+ <comment xml:lang="be">аўдыя Amiga SoundTracker</comment>
<comment xml:lang="ar">مقتفي صوت Amiga السمعي</comment>
<magic priority="40">
<match type="string" value="MTM" offset="0"/>
@@ -24712,8 +25754,9 @@ command to generate the output files.
<comment xml:lang="tr">MP2 sesi</comment>
<comment xml:lang="sv">MP2-ljud</comment>
<comment xml:lang="sr">МП2 звук</comment>
- <comment xml:lang="sq">Audio MP2</comment>
+ <comment xml:lang="sq">audio MP2</comment>
<comment xml:lang="sl">Zvočna datoteka MP2</comment>
+ <comment xml:lang="si">MP2 ශ්රව්ය</comment>
<comment xml:lang="sk">Zvuk MP2</comment>
<comment xml:lang="ru">Аудио MP2</comment>
<comment xml:lang="ro">Audio MP2</comment>
@@ -24730,6 +25773,7 @@ command to generate the output files.
<comment xml:lang="kk">MP2 аудиосы</comment>
<comment xml:lang="ja">MP2 オーディオ</comment>
<comment xml:lang="it">Audio MP2</comment>
+ <comment xml:lang="is">MP2 hljóðskrá</comment>
<comment xml:lang="id">Audio MP2</comment>
<comment xml:lang="ia">Audio MP2</comment>
<comment xml:lang="hu">MP2 hang</comment>
@@ -24742,7 +25786,7 @@ command to generate the output files.
<comment xml:lang="fo">MP2 ljóður</comment>
<comment xml:lang="fi">MP2-ääni</comment>
<comment xml:lang="eu">MP2 audioa</comment>
- <comment xml:lang="es">audio MP2</comment>
+ <comment xml:lang="es">sonido MP2</comment>
<comment xml:lang="eo">MP2-sondosiero</comment>
<comment xml:lang="en_GB">MP2 audio</comment>
<comment xml:lang="el">Ήχος MP2</comment>
@@ -24752,6 +25796,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio MP2</comment>
<comment xml:lang="bg">Аудио — MP2</comment>
<comment xml:lang="be@latin">Aŭdyjo MP2</comment>
+ <comment xml:lang="be">аўдыя MP2</comment>
<comment xml:lang="ar">صوت MP2</comment>
<comment xml:lang="af">MP2-oudio</comment>
<alias type="audio/x-mp2"/>
@@ -24766,8 +25811,9 @@ command to generate the output files.
<comment xml:lang="tr">MP3 sesi</comment>
<comment xml:lang="sv">MP3-ljud</comment>
<comment xml:lang="sr">МП3 звук</comment>
- <comment xml:lang="sq">Audio MP3</comment>
+ <comment xml:lang="sq">audio MP3</comment>
<comment xml:lang="sl">Zvočna datoteka MP3</comment>
+ <comment xml:lang="si">MP3 ශ්රව්ය</comment>
<comment xml:lang="sk">Zvuk MP3</comment>
<comment xml:lang="ru">Аудио MP3</comment>
<comment xml:lang="ro">Audio MP3</comment>
@@ -24786,6 +25832,7 @@ command to generate the output files.
<comment xml:lang="ka">MP3 აუდიო</comment>
<comment xml:lang="ja">MP3 オーディオ</comment>
<comment xml:lang="it">Audio MP3</comment>
+ <comment xml:lang="is">MP3 hljóðskrá</comment>
<comment xml:lang="id">Audio MP3</comment>
<comment xml:lang="ia">Audio MP3</comment>
<comment xml:lang="hu">MP3 hang</comment>
@@ -24798,7 +25845,7 @@ command to generate the output files.
<comment xml:lang="fo">MP3 ljóður</comment>
<comment xml:lang="fi">MP3-ääni</comment>
<comment xml:lang="eu">MP3 audioa</comment>
- <comment xml:lang="es">audio MP3</comment>
+ <comment xml:lang="es">sonido MP3</comment>
<comment xml:lang="eo">MP3-sondosiero</comment>
<comment xml:lang="en_GB">MP3 audio</comment>
<comment xml:lang="el">Ήχος MP3</comment>
@@ -24809,6 +25856,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio MP3</comment>
<comment xml:lang="bg">Аудио — MP3</comment>
<comment xml:lang="be@latin">Aŭdyjo MP3</comment>
+ <comment xml:lang="be">аўдыя MP3</comment>
<comment xml:lang="az">MP3 audio faylı</comment>
<comment xml:lang="ar">صوت MP3</comment>
<comment xml:lang="af">MP3-oudio</comment>
@@ -24830,6 +25878,28 @@ command to generate the output files.
</mime-type>
<mime-type type="audio/x-mpegurl">
<comment>Media playlist</comment>
+ <comment xml:lang="zh_CN">媒体播放列表</comment>
+ <comment xml:lang="uk">мультимедійний список відтворення</comment>
+ <comment xml:lang="tr">Ortam çalma listesi</comment>
+ <comment xml:lang="sv">Mediaspellista</comment>
+ <comment xml:lang="si">මාධ්‍ය ධාවන ලැයිස්තුව</comment>
+ <comment xml:lang="ru">Список воспроизведения медиа-данных</comment>
+ <comment xml:lang="pl">Lista odtwarzania multimediów</comment>
+ <comment xml:lang="nl">Media-afspeellijst</comment>
+ <comment xml:lang="ko">Media 재생 목록</comment>
+ <comment xml:lang="kk">Медиа ойнату тізімі</comment>
+ <comment xml:lang="ka">მედიის დასაკრავი სია</comment>
+ <comment xml:lang="ja">メディアプレイリスト</comment>
+ <comment xml:lang="it">Playlist multimediale</comment>
+ <comment xml:lang="hr">Media popis izvođenja</comment>
+ <comment xml:lang="gl">Lista de reprodución multimedia</comment>
+ <comment xml:lang="fi">Media-soittolista</comment>
+ <comment xml:lang="eu">Multimediako erreprodukzio-zerrenda</comment>
+ <comment xml:lang="es">lista de reproducción de medios</comment>
+ <comment xml:lang="en_GB">Media playlist</comment>
+ <comment xml:lang="de">Medien-Wiedergabeliste</comment>
+ <comment xml:lang="be">плэй-ліст мультымедыя</comment>
+ <comment xml:lang="ar">قائمة تشغيل وسائط</comment>
<sub-class-of type="text/plain"/>
<alias type="audio/mpegurl"/>
<alias type="application/m3u"/>
@@ -24845,6 +25915,28 @@ command to generate the output files.
</mime-type>
<mime-type type="application/vnd.apple.mpegurl">
<comment>Media playlist</comment>
+ <comment xml:lang="zh_CN">媒体播放列表</comment>
+ <comment xml:lang="uk">мультимедійний список відтворення</comment>
+ <comment xml:lang="tr">Ortam çalma listesi</comment>
+ <comment xml:lang="sv">Mediaspellista</comment>
+ <comment xml:lang="si">මාධ්‍ය ධාවන ලැයිස්තුව</comment>
+ <comment xml:lang="ru">Список воспроизведения медиа-данных</comment>
+ <comment xml:lang="pl">Lista odtwarzania multimediów</comment>
+ <comment xml:lang="nl">Media-afspeellijst</comment>
+ <comment xml:lang="ko">Media 재생 목록</comment>
+ <comment xml:lang="kk">Медиа ойнату тізімі</comment>
+ <comment xml:lang="ka">მედიის დასაკრავი სია</comment>
+ <comment xml:lang="ja">メディアプレイリスト</comment>
+ <comment xml:lang="it">Playlist multimediale</comment>
+ <comment xml:lang="hr">Media popis izvođenja</comment>
+ <comment xml:lang="gl">Lista de reprodución multimedia</comment>
+ <comment xml:lang="fi">Media-soittolista</comment>
+ <comment xml:lang="eu">Multimediako erreprodukzio-zerrenda</comment>
+ <comment xml:lang="es">lista de reproducción de medios</comment>
+ <comment xml:lang="en_GB">Media playlist</comment>
+ <comment xml:lang="de">Medien-Wiedergabeliste</comment>
+ <comment xml:lang="be">плэй-ліст мультымедыя</comment>
+ <comment xml:lang="ar">قائمة تشغيل وسائط</comment>
<sub-class-of type="text/plain"/>
<glob pattern="*.m3u"/>
<glob pattern="*.m3u8"/>
@@ -24864,8 +25956,9 @@ command to generate the output files.
<comment xml:lang="tr">Microsoft ASX çalma listesi</comment>
<comment xml:lang="sv">Microsoft ASX-spellista</comment>
<comment xml:lang="sr">Мајкрософтов АСИкс списак нумера</comment>
- <comment xml:lang="sq">Listë titujsh Microsoft ASF</comment>
+ <comment xml:lang="sq">luajlistë Microsoft ASF</comment>
<comment xml:lang="sl">Seznam predvajanja Microsoft ASX</comment>
+ <comment xml:lang="si">Microsoft ASX ධාවන ලැයිස්තුව</comment>
<comment xml:lang="sk">Zoznam skladieb Microsoft ASX</comment>
<comment xml:lang="ru">Список воспроизведения Microsoft ASX</comment>
<comment xml:lang="ro">Listă redare Microsoft ASX</comment>
@@ -24883,6 +25976,7 @@ command to generate the output files.
<comment xml:lang="ka">Microsoft-ის ASX რეპერტუარი</comment>
<comment xml:lang="ja">Microsoft ASX プレイリスト</comment>
<comment xml:lang="it">Playlist Microsoft ASX</comment>
+ <comment xml:lang="is">Microsoft ASX spilunarlisti</comment>
<comment xml:lang="id">Senarai putar Microsoft ASX</comment>
<comment xml:lang="ia">Lista de selection Microsoft ASX</comment>
<comment xml:lang="hu">Microsoft ASX lejátszólista</comment>
@@ -24904,6 +25998,7 @@ command to generate the output files.
<comment xml:lang="ca">llista de reproducció de Microsoft ASX</comment>
<comment xml:lang="bg">Списък за изпълнение — Microsoft ASX</comment>
<comment xml:lang="be@latin">Śpis Microsoft ASX</comment>
+ <comment xml:lang="be">плэй-ліст Microsoft ASX</comment>
<comment xml:lang="ar">قائمة تشغيل مايكروسوفت ASX</comment>
<alias type="video/x-ms-wvx"/>
<alias type="video/x-ms-wax"/>
@@ -24929,8 +26024,9 @@ command to generate the output files.
<comment xml:lang="tr">PSF sesi</comment>
<comment xml:lang="sv">PSF-ljud</comment>
<comment xml:lang="sr">ПСФ звук</comment>
- <comment xml:lang="sq">Audio PSF</comment>
+ <comment xml:lang="sq">audio PSF</comment>
<comment xml:lang="sl">Zvočna datoteka PSF</comment>
+ <comment xml:lang="si">PSF ශ්රව්ය උපකරණ</comment>
<comment xml:lang="sk">Zvuk PSF</comment>
<comment xml:lang="ru">Аудио PSF</comment>
<comment xml:lang="ro">Audio PSF</comment>
@@ -24947,6 +26043,7 @@ command to generate the output files.
<comment xml:lang="kk">PSF аудиосы</comment>
<comment xml:lang="ja">PSF オーディオ</comment>
<comment xml:lang="it">Audio PSF</comment>
+ <comment xml:lang="is">PSF hljóðskrá</comment>
<comment xml:lang="id">Audio PSF</comment>
<comment xml:lang="ia">Audio PSF</comment>
<comment xml:lang="hu">PSF hang</comment>
@@ -24959,7 +26056,7 @@ command to generate the output files.
<comment xml:lang="fo">PSF ljóður</comment>
<comment xml:lang="fi">PSF-ääni</comment>
<comment xml:lang="eu">PSF audioa</comment>
- <comment xml:lang="es">audio PSF</comment>
+ <comment xml:lang="es">sonido PSF</comment>
<comment xml:lang="eo">PSF-sondosiero</comment>
<comment xml:lang="en_GB">PSF audio</comment>
<comment xml:lang="el">Ήχος PSF</comment>
@@ -24969,6 +26066,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio PSF</comment>
<comment xml:lang="bg">Аудио — PSF</comment>
<comment xml:lang="be@latin">Aŭdyjo PSF</comment>
+ <comment xml:lang="be">аўдыя PSF</comment>
<comment xml:lang="ar">صوت PSF</comment>
<comment xml:lang="af">PSF-oudio</comment>
<acronym>PSF</acronym>
@@ -24987,8 +26085,9 @@ command to generate the output files.
<comment xml:lang="tr">MiniPSF sesi</comment>
<comment xml:lang="sv">MiniPSF-ljud</comment>
<comment xml:lang="sr">Мини ПСФ звук</comment>
- <comment xml:lang="sq">Audio MiniPSF</comment>
+ <comment xml:lang="sq">audio MiniPSF</comment>
<comment xml:lang="sl">Zvočna datoteka MiniPSF</comment>
+ <comment xml:lang="si">MiniPSF ශ්රව්ය</comment>
<comment xml:lang="sk">Zvuk MiniPSF</comment>
<comment xml:lang="ru">Аудио MiniPSF</comment>
<comment xml:lang="ro">Audio MiniPSF</comment>
@@ -25006,6 +26105,7 @@ command to generate the output files.
<comment xml:lang="ka">MiniPSF-ის აუდიო</comment>
<comment xml:lang="ja">MiniPSF オーディオ</comment>
<comment xml:lang="it">Audio MiniPSF</comment>
+ <comment xml:lang="is">MiniPSF hljóðskrá</comment>
<comment xml:lang="id">Audio MiniPSF</comment>
<comment xml:lang="ia">Audio MiniPSF</comment>
<comment xml:lang="hu">MiniPSF hang</comment>
@@ -25018,7 +26118,7 @@ command to generate the output files.
<comment xml:lang="fo">MiniPSF ljóður</comment>
<comment xml:lang="fi">MiniPSF-ääni</comment>
<comment xml:lang="eu">MiniPSF audioa</comment>
- <comment xml:lang="es">audio MiniPSF</comment>
+ <comment xml:lang="es">sonido MiniPSF</comment>
<comment xml:lang="eo">MiniPSF-sondosiero</comment>
<comment xml:lang="en_GB">MiniPSF audio</comment>
<comment xml:lang="el">Ήχος MiniPSF</comment>
@@ -25028,6 +26128,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio MiniPSF</comment>
<comment xml:lang="bg">Аудио — MiniPSF</comment>
<comment xml:lang="be@latin">Aŭdyjo MiniPSF</comment>
+ <comment xml:lang="be">аўдыя MiniPSF</comment>
<comment xml:lang="ar">صوت MiniPSF</comment>
<comment xml:lang="af">MiniPSF-oudio</comment>
<acronym>MiniPSF</acronym>
@@ -25044,8 +26145,9 @@ command to generate the output files.
<comment xml:lang="tr">PSFlib ses kitaplığı</comment>
<comment xml:lang="sv">PSFlib-ljudbibliotek</comment>
<comment xml:lang="sr">библиотека звука ПСФ библиотеке</comment>
- <comment xml:lang="sq">Librari audio PSFlib</comment>
+ <comment xml:lang="sq">bibliotekë audio PSFlib</comment>
<comment xml:lang="sl">Zvočna knjižnica PSFlib</comment>
+ <comment xml:lang="si">PSFlib ශ්‍රව්‍ය පුස්තකාලය</comment>
<comment xml:lang="sk">Zvuková knižnica PSFlib</comment>
<comment xml:lang="ru">Фонотека PSFlib</comment>
<comment xml:lang="ro">Bibliotecă audio PSFlib</comment>
@@ -25062,6 +26164,7 @@ command to generate the output files.
<comment xml:lang="kk">PSFlib аудио жинағы</comment>
<comment xml:lang="ja">PSFlib オーディオライブラリ</comment>
<comment xml:lang="it">Libreria audio PSFlib</comment>
+ <comment xml:lang="is">PSFlib hljóðaðgerðasafn</comment>
<comment xml:lang="id">Pustaka audio PSFlib</comment>
<comment xml:lang="ia">Bibliotheca audio PSFlib</comment>
<comment xml:lang="hu">PSFlib hanggyűjtemény</comment>
@@ -25074,7 +26177,7 @@ command to generate the output files.
<comment xml:lang="fo">PSFlib ljóðsavn</comment>
<comment xml:lang="fi">PSFlib-äänikirjasto</comment>
<comment xml:lang="eu">PSFlib audioaren liburutegia</comment>
- <comment xml:lang="es">biblioteca de audio PSFlib</comment>
+ <comment xml:lang="es">biblioteca de sonido PSFlib</comment>
<comment xml:lang="en_GB">PSFlib audio library</comment>
<comment xml:lang="el">Βιβλιοθήκη ήχου PSFlib</comment>
<comment xml:lang="de">PSFlib-Audiobibliothek</comment>
@@ -25083,6 +26186,7 @@ command to generate the output files.
<comment xml:lang="ca">biblioteca d'àudio PSFlib</comment>
<comment xml:lang="bg">Аудио библиотека — PSFlib</comment>
<comment xml:lang="be@latin">Aŭdyjobiblijateka PSFlib</comment>
+ <comment xml:lang="be">аўдыябібліятэка PSFlib</comment>
<comment xml:lang="ar">مكتبة صوت PSFlib</comment>
<comment xml:lang="af">PSFlib-oudiobiblioteek</comment>
<acronym>PSFlib</acronym>
@@ -25099,8 +26203,9 @@ command to generate the output files.
<comment xml:lang="tr">Windows Media sesi</comment>
<comment xml:lang="sv">Windows Media-ljud</comment>
<comment xml:lang="sr">Виндоуз Медија звук</comment>
- <comment xml:lang="sq">Audio Windows Media</comment>
+ <comment xml:lang="sq">audio Windows Media</comment>
<comment xml:lang="sl">Zvočna datoteka Windows Media</comment>
+ <comment xml:lang="si">වින්ඩෝස් මීඩියා ඕඩියෝ</comment>
<comment xml:lang="sk">Zvuk Windows Media</comment>
<comment xml:lang="ru">Аудио Windows Media</comment>
<comment xml:lang="ro">Audio Windows Media</comment>
@@ -25117,6 +26222,7 @@ command to generate the output files.
<comment xml:lang="kk">Windows Media аудиосы</comment>
<comment xml:lang="ja">Windows Media オーディオ</comment>
<comment xml:lang="it">Audio Windows Media</comment>
+ <comment xml:lang="is">Windows Media hljóðskrá</comment>
<comment xml:lang="id">Audio Windows Media</comment>
<comment xml:lang="ia">Audio Windows Media</comment>
<comment xml:lang="hu">Windows Media hang</comment>
@@ -25129,7 +26235,7 @@ command to generate the output files.
<comment xml:lang="fo">Windows Media ljóður</comment>
<comment xml:lang="fi">Windows Media -ääni</comment>
<comment xml:lang="eu">Windows Media audioa</comment>
- <comment xml:lang="es">audio de Windows Media</comment>
+ <comment xml:lang="es">sonido de Windows Media</comment>
<comment xml:lang="en_GB">Windows Media audio</comment>
<comment xml:lang="el">Ήχος Windows Media</comment>
<comment xml:lang="de">Windows-Media-Audio</comment>
@@ -25138,6 +26244,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio de Windows Media</comment>
<comment xml:lang="bg">Аудио — Windows Media</comment>
<comment xml:lang="be@latin">Aŭdyjo Windows Media</comment>
+ <comment xml:lang="be">аўдыя Windows Media</comment>
<comment xml:lang="ar">فيديو ويندوز ميديا</comment>
<comment xml:lang="af">Windows Media-oudio</comment>
<sub-class-of type="application/vnd.ms-asf"/>
@@ -25153,8 +26260,9 @@ command to generate the output files.
<comment xml:lang="tr">Musepack sesi</comment>
<comment xml:lang="sv">Musepack-ljud</comment>
<comment xml:lang="sr">звук Мјузпака</comment>
- <comment xml:lang="sq">Audio Musepack</comment>
+ <comment xml:lang="sq">audio Musepack</comment>
<comment xml:lang="sl">Zvočna datoteka Musepack</comment>
+ <comment xml:lang="si">Musepack ශ්‍රව්‍ය</comment>
<comment xml:lang="sk">Zvuk Musepack</comment>
<comment xml:lang="ru">Аудио Musepack</comment>
<comment xml:lang="ro">Audio Musepack</comment>
@@ -25171,6 +26279,7 @@ command to generate the output files.
<comment xml:lang="kk">Musepack аудиосы</comment>
<comment xml:lang="ja">Musepack オーディオ</comment>
<comment xml:lang="it">Audio Musepack</comment>
+ <comment xml:lang="is">Musepack hljóðskrá</comment>
<comment xml:lang="id">Audio Musepack</comment>
<comment xml:lang="ia">Audio Musepack</comment>
<comment xml:lang="hu">Musepack hang</comment>
@@ -25183,7 +26292,7 @@ command to generate the output files.
<comment xml:lang="fo">Musepack ljóður</comment>
<comment xml:lang="fi">Musepack-ääni</comment>
<comment xml:lang="eu">Musepack audioa</comment>
- <comment xml:lang="es">audio Musepack</comment>
+ <comment xml:lang="es">sonido Musepack</comment>
<comment xml:lang="en_GB">Musepack audio</comment>
<comment xml:lang="el">Ήχος Musepack</comment>
<comment xml:lang="de">Musepack-Audio</comment>
@@ -25192,6 +26301,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio de Musepack</comment>
<comment xml:lang="bg">Аудио — Musepack</comment>
<comment xml:lang="be@latin">Aŭdyjo Musepack</comment>
+ <comment xml:lang="be">аўдыя Musepack</comment>
<comment xml:lang="ar">صوت Musepack</comment>
<comment xml:lang="af">Musepack-oudio</comment>
<magic>
@@ -25211,8 +26321,9 @@ command to generate the output files.
<comment xml:lang="tr">RealAudio belgesi</comment>
<comment xml:lang="sv">RealAudio-dokument</comment>
<comment xml:lang="sr">документ Рил Аудиа</comment>
- <comment xml:lang="sq">Dokument RealAudio</comment>
+ <comment xml:lang="sq">dokument RealAudio</comment>
<comment xml:lang="sl">Dokument RealAudio</comment>
+ <comment xml:lang="si">රියල් ඕඩියෝ ලේඛනය</comment>
<comment xml:lang="sk">Dokument RealAudio</comment>
<comment xml:lang="ru">Документ RealAudio</comment>
<comment xml:lang="ro">Document RealAudio</comment>
@@ -25229,6 +26340,7 @@ command to generate the output files.
<comment xml:lang="kk">RealAudio құжаты</comment>
<comment xml:lang="ja">RealAudio ドキュメント</comment>
<comment xml:lang="it">Documento RealAudio</comment>
+ <comment xml:lang="is">RealAudio skjal</comment>
<comment xml:lang="id">Dokumen RealAudio</comment>
<comment xml:lang="ia">Documento RealAudio</comment>
<comment xml:lang="hu">RealAudio dokumentum</comment>
@@ -25251,6 +26363,7 @@ command to generate the output files.
<comment xml:lang="ca">document RealAudio</comment>
<comment xml:lang="bg">Документ — RealAudio</comment>
<comment xml:lang="be@latin">Dakument RealAudio</comment>
+ <comment xml:lang="be">дакумент RealAudio</comment>
<comment xml:lang="ast">Documentu RealAudio</comment>
<comment xml:lang="ar">مستند RealAudio</comment>
<comment xml:lang="af">RealAudio-dokument</comment>
@@ -25266,20 +26379,27 @@ command to generate the output files.
<comment xml:lang="uk">список відтворення RealMedia</comment>
<comment xml:lang="tr">RealMedia çalma listesi</comment>
<comment xml:lang="sv">RealMedia-spellista</comment>
+ <comment xml:lang="sq">luajlistë RealMedia</comment>
+ <comment xml:lang="sl">Seznam predvajanja RealMedia</comment>
+ <comment xml:lang="si">RealMedia ධාවන ලැයිස්තුව</comment>
<comment xml:lang="sk">Zoznam skladieb RealMedia</comment>
<comment xml:lang="ru">Список воспроизведения RealMedia</comment>
<comment xml:lang="pt_BR">Lista de reprodução do RealMedia</comment>
<comment xml:lang="pl">Lista odtwarzania RealMedia</comment>
<comment xml:lang="oc">lista de lectura RealMedia</comment>
+ <comment xml:lang="nl">RealMedia-afspeellijst</comment>
<comment xml:lang="lt">RealMedia grojaraštis</comment>
<comment xml:lang="ko">RealMedia 재생 목록</comment>
<comment xml:lang="kk">RealMedia ойнау тізімі</comment>
+ <comment xml:lang="ka">RealMedia დასაკრავი სია</comment>
<comment xml:lang="ja">RealMedia プレイリスト</comment>
<comment xml:lang="it">Playlist RealMedia</comment>
+ <comment xml:lang="is">RealMedia spilunarlisti</comment>
<comment xml:lang="id">Daftar putar RealMedia</comment>
<comment xml:lang="hu">RealMedia lejátszólista</comment>
<comment xml:lang="hr">RealMedia popis izvođenja</comment>
<comment xml:lang="he">רשימת השמעה של RealMedia</comment>
+ <comment xml:lang="gl">Lista de reprodución RealMedia</comment>
<comment xml:lang="fr">liste de lecture RealMedia</comment>
<comment xml:lang="fi">RealMedia-soittolista</comment>
<comment xml:lang="eu">RealMedia erreprodukzio-zerrenda</comment>
@@ -25289,6 +26409,7 @@ command to generate the output files.
<comment xml:lang="da">RealMedia-afspilningsliste</comment>
<comment xml:lang="ca">llista de reproducció RealMedia</comment>
<comment xml:lang="bg">Списък за изпълнение — RealMedia</comment>
+ <comment xml:lang="be">плэй-ліст RealMedia</comment>
<comment xml:lang="ar">قائمة تشغيل RealMedia</comment>
<glob pattern="*.ram"/>
</mime-type>
@@ -25301,8 +26422,9 @@ command to generate the output files.
<comment xml:lang="tr">RealVideo belgesi</comment>
<comment xml:lang="sv">RealVideo-dokument</comment>
<comment xml:lang="sr">документ Рил Видеа</comment>
- <comment xml:lang="sq">Dokument RealVideo</comment>
+ <comment xml:lang="sq">dokument RealVideo</comment>
<comment xml:lang="sl">Video datoteka RealVideo</comment>
+ <comment xml:lang="si">RealVideo ලේඛනය</comment>
<comment xml:lang="sk">Dokument RealVideo</comment>
<comment xml:lang="ru">Документ RealVideo</comment>
<comment xml:lang="ro">Document RealVideo</comment>
@@ -25319,6 +26441,7 @@ command to generate the output files.
<comment xml:lang="kk">RealVideo құжаты</comment>
<comment xml:lang="ja">RealVideo ドキュメント</comment>
<comment xml:lang="it">Documento RealVideo</comment>
+ <comment xml:lang="is">RealVideo skjal</comment>
<comment xml:lang="id">Dokumen RealVideo</comment>
<comment xml:lang="ia">Documento RealVideo</comment>
<comment xml:lang="hu">RealVideo dokumentum</comment>
@@ -25341,6 +26464,7 @@ command to generate the output files.
<comment xml:lang="ca">document RealVideo</comment>
<comment xml:lang="bg">Документ — RealVideo</comment>
<comment xml:lang="be@latin">Dakument RealVideo</comment>
+ <comment xml:lang="be">дакумент RealVideo</comment>
<comment xml:lang="ast">Documentu RealVideo</comment>
<comment xml:lang="ar">مستند RealVideo</comment>
<comment xml:lang="af">RealVideo-dokument</comment>
@@ -25357,8 +26481,9 @@ command to generate the output files.
<comment xml:lang="tr">RealMedia belgesi</comment>
<comment xml:lang="sv">RealMedia-dokument</comment>
<comment xml:lang="sr">документ Рил Медија</comment>
- <comment xml:lang="sq">Dokument RealMedia</comment>
+ <comment xml:lang="sq">dokument RealMedia</comment>
<comment xml:lang="sl">Dokument RealMedia</comment>
+ <comment xml:lang="si">රියල් මීඩියා ලේඛනය</comment>
<comment xml:lang="sk">Dokument RealMedia</comment>
<comment xml:lang="ru">Документ RealMedia</comment>
<comment xml:lang="ro">Document RealMedia</comment>
@@ -25375,6 +26500,7 @@ command to generate the output files.
<comment xml:lang="kk">RealMedia құжаты</comment>
<comment xml:lang="ja">RealMedia ドキュメント</comment>
<comment xml:lang="it">Documento RealMedia</comment>
+ <comment xml:lang="is">RealMedia skjal</comment>
<comment xml:lang="id">Dokumen RealMedia</comment>
<comment xml:lang="ia">Documento RealMedia</comment>
<comment xml:lang="hu">RealMedia dokumentum</comment>
@@ -25397,6 +26523,7 @@ command to generate the output files.
<comment xml:lang="ca">document RealMedia</comment>
<comment xml:lang="bg">Документ — RealMedia</comment>
<comment xml:lang="be@latin">Dakument RealMedia</comment>
+ <comment xml:lang="be">дакумент RealMedia</comment>
<comment xml:lang="ast">Documentu RealMedia</comment>
<comment xml:lang="ar">مستند RealMedia</comment>
<comment xml:lang="af">RealMedia-dokument</comment>
@@ -25421,8 +26548,9 @@ command to generate the output files.
<comment xml:lang="tr">RealPix belgesi</comment>
<comment xml:lang="sv">RealPix-dokument</comment>
<comment xml:lang="sr">документ Рил Пикса</comment>
- <comment xml:lang="sq">Dokument RealPix</comment>
+ <comment xml:lang="sq">dokument RealPix</comment>
<comment xml:lang="sl">Dokument RealPix</comment>
+ <comment xml:lang="si">RealPix ලේඛනය</comment>
<comment xml:lang="sk">Dokument RealPix</comment>
<comment xml:lang="ru">Документ RealPix</comment>
<comment xml:lang="ro">Document RealPix</comment>
@@ -25439,6 +26567,7 @@ command to generate the output files.
<comment xml:lang="kk">RealPix құжаты</comment>
<comment xml:lang="ja">RealPix ドキュメント</comment>
<comment xml:lang="it">Documento RealPix</comment>
+ <comment xml:lang="is">RealPix skjal</comment>
<comment xml:lang="id">Dokumen RealPix</comment>
<comment xml:lang="ia">Documento RealPix</comment>
<comment xml:lang="hu">RealPix dokumentum</comment>
@@ -25461,6 +26590,7 @@ command to generate the output files.
<comment xml:lang="ca">document RealPix</comment>
<comment xml:lang="bg">Документ — RealPix</comment>
<comment xml:lang="be@latin">Dakument RealPix</comment>
+ <comment xml:lang="be">дакумент RealPix</comment>
<comment xml:lang="ast">Documentu RealPix</comment>
<comment xml:lang="ar">مستند RealPix</comment>
<comment xml:lang="af">RealPix-dokument</comment>
@@ -25475,8 +26605,9 @@ command to generate the output files.
<comment xml:lang="tr">RealText belgesi</comment>
<comment xml:lang="sv">RealText-dokument</comment>
<comment xml:lang="sr">документ Рил Текста</comment>
- <comment xml:lang="sq">Dokument RealText</comment>
+ <comment xml:lang="sq">dokument RealText</comment>
<comment xml:lang="sl">Dokument RealText</comment>
+ <comment xml:lang="si">RealText ලේඛනය</comment>
<comment xml:lang="sk">Dokument RealText</comment>
<comment xml:lang="ru">Документ RealText</comment>
<comment xml:lang="ro">Document RealText</comment>
@@ -25493,6 +26624,7 @@ command to generate the output files.
<comment xml:lang="kk">RealText құжаты</comment>
<comment xml:lang="ja">RealText ドキュメント</comment>
<comment xml:lang="it">Documento RealText</comment>
+ <comment xml:lang="is">RealText skjal</comment>
<comment xml:lang="id">Dokumen RealText</comment>
<comment xml:lang="ia">Documento RealText</comment>
<comment xml:lang="hu">RealText dokumentum</comment>
@@ -25515,6 +26647,7 @@ command to generate the output files.
<comment xml:lang="ca">document RealText</comment>
<comment xml:lang="bg">Документ — RealText</comment>
<comment xml:lang="be@latin">Dakument RealText</comment>
+ <comment xml:lang="be">дакумент RealText</comment>
<comment xml:lang="ast">Documentu RealText</comment>
<comment xml:lang="ar">مستند RealText</comment>
<comment xml:lang="af">RealText-dokument</comment>
@@ -25530,8 +26663,9 @@ command to generate the output files.
<comment xml:lang="tr">RIFF sesi</comment>
<comment xml:lang="sv">RIFF-ljud</comment>
<comment xml:lang="sr">РИФФ звук</comment>
- <comment xml:lang="sq">Audio RIFF</comment>
+ <comment xml:lang="sq">audio RIFF</comment>
<comment xml:lang="sl">Zvočna datoteka RIFF</comment>
+ <comment xml:lang="si">RIFF ශ්‍රව්‍ය</comment>
<comment xml:lang="sk">Zvuk RIFF</comment>
<comment xml:lang="ru">Аудио RIFF</comment>
<comment xml:lang="ro">Audio RIFF</comment>
@@ -25549,6 +26683,7 @@ command to generate the output files.
<comment xml:lang="kk">RIFF аудиосы</comment>
<comment xml:lang="ja">RIFF オーディオ</comment>
<comment xml:lang="it">Audio RIFF</comment>
+ <comment xml:lang="is">RIFF hljóðskrá</comment>
<comment xml:lang="id">Audio RIFF</comment>
<comment xml:lang="ia">Audio RIFF</comment>
<comment xml:lang="hu">RIFF-kép</comment>
@@ -25561,7 +26696,7 @@ command to generate the output files.
<comment xml:lang="fo">RIFF ljóð</comment>
<comment xml:lang="fi">RIFF-ääni</comment>
<comment xml:lang="eu">RIFF audioa</comment>
- <comment xml:lang="es">audio RIFF</comment>
+ <comment xml:lang="es">sonido RIFF</comment>
<comment xml:lang="eo">RIFF-sondosiero</comment>
<comment xml:lang="en_GB">RIFF audio</comment>
<comment xml:lang="el">Ήχος RIFF</comment>
@@ -25572,6 +26707,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio RIFF</comment>
<comment xml:lang="bg">Аудио — RIFF</comment>
<comment xml:lang="be@latin">Aŭdyjo RIFF</comment>
+ <comment xml:lang="be">аўдыя RIFF</comment>
<comment xml:lang="az">RIFF audio faylı</comment>
<comment xml:lang="ar">صوت RIFF</comment>
<comment xml:lang="af">RIFF-oudio</comment>
@@ -25584,18 +26720,22 @@ command to generate the output files.
<comment xml:lang="tr">RIFF deposu</comment>
<comment xml:lang="sv">RIFF-behållare</comment>
<comment xml:lang="sr">РИФФ садржалац</comment>
+ <comment xml:lang="sq">kontejner RIFF</comment>
<comment xml:lang="sl">Vsebnik RIFF</comment>
+ <comment xml:lang="si">RIFF කන්ටේනරය</comment>
<comment xml:lang="sk">Kontajner RIFF</comment>
<comment xml:lang="ru">Контейнер RIFF</comment>
<comment xml:lang="pt_BR">Contêiner RIFF</comment>
<comment xml:lang="pt">contentor RIFF</comment>
<comment xml:lang="pl">Kontener RIFF</comment>
<comment xml:lang="oc">contenidor RIFF</comment>
+ <comment xml:lang="nl">RIFF-container</comment>
<comment xml:lang="lt">RIFF konteineris</comment>
<comment xml:lang="ko">RIFF 컨테이너</comment>
<comment xml:lang="kk">RIFF контейнері</comment>
<comment xml:lang="ja">RIFF コンテナ</comment>
<comment xml:lang="it">Container RIFF</comment>
+ <comment xml:lang="is">RIFF gagnagámur</comment>
<comment xml:lang="id">Wadah RIFF</comment>
<comment xml:lang="ia">Receptaculo RIFF</comment>
<comment xml:lang="hu">RIFF konténer</comment>
@@ -25615,6 +26755,7 @@ command to generate the output files.
<comment xml:lang="cs">kontejner RIFF</comment>
<comment xml:lang="ca">contenidor RIFF</comment>
<comment xml:lang="bg">Контейнер — RIFF</comment>
+ <comment xml:lang="be">кантэйнер RIFF</comment>
<comment xml:lang="ar">حاوية RIFF</comment>
<comment xml:lang="af">RIFF-houer</comment>
<!-- need to be lower prio than avi -->
@@ -25631,8 +26772,9 @@ command to generate the output files.
<comment xml:lang="tr">Scream Tracker 3 sesi</comment>
<comment xml:lang="sv">Scream Tracker 3-ljud</comment>
<comment xml:lang="sr">звук Скрим Тракера 3</comment>
- <comment xml:lang="sq">Audio Scream Tracker 3</comment>
+ <comment xml:lang="sq">audio Scream Tracker 3</comment>
<comment xml:lang="sl">Zvočna datoteka Scream Tracker 3</comment>
+ <comment xml:lang="si">Scream Tracker 3 ශ්‍රව්‍ය</comment>
<comment xml:lang="sk">Skladba Scream Tracker 3</comment>
<comment xml:lang="ru">Аудио Scream Tracker 3</comment>
<comment xml:lang="ro">Audio Scream Tracker 3</comment>
@@ -25650,6 +26792,7 @@ command to generate the output files.
<comment xml:lang="kk">Scream Tracker 3 аудиосы</comment>
<comment xml:lang="ja">Scream Tracker 3 オーディオ</comment>
<comment xml:lang="it">Audio Scream Tracker 3</comment>
+ <comment xml:lang="is">Scream Tracker 3 hljóðskrá</comment>
<comment xml:lang="id">Audio Scream Tracker 3</comment>
<comment xml:lang="ia">Audio Scream Tracker 3</comment>
<comment xml:lang="hu">Scream Tracker 3 hang</comment>
@@ -25662,7 +26805,7 @@ command to generate the output files.
<comment xml:lang="fo">Scream Tracker 3 ljóður</comment>
<comment xml:lang="fi">Scream Tracker 3 -ääni</comment>
<comment xml:lang="eu">Scream Tracker 3 audioa</comment>
- <comment xml:lang="es">audio Scream Tracker 3</comment>
+ <comment xml:lang="es">sonido Scream Tracker 3</comment>
<comment xml:lang="eo">Sondosiero de Scream Tracker 3</comment>
<comment xml:lang="en_GB">Scream Tracker 3 audio</comment>
<comment xml:lang="el">Ήχος Scream Tracker 3</comment>
@@ -25673,6 +26816,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio de Scream Tracker 3</comment>
<comment xml:lang="bg">Аудио — Scream Tracker 3</comment>
<comment xml:lang="be@latin">Aŭdyjo Scream Tracker 3</comment>
+ <comment xml:lang="be">аўдыя Scream Tracker 3</comment>
<comment xml:lang="az">Scream Tracker 3 audio faylı</comment>
<comment xml:lang="ar">صوت Scream Tracker 3</comment>
<magic>
@@ -25689,8 +26833,9 @@ command to generate the output files.
<comment xml:lang="tr">MP3 ShoutCast çalma listesi</comment>
<comment xml:lang="sv">MP3 ShoutCast-spellista</comment>
<comment xml:lang="sr">списак МП3 песама Шаут Каста</comment>
- <comment xml:lang="sq">Listë titujsh MP3 ShoutCast</comment>
+ <comment xml:lang="sq">luajlistë MP3 ShoutCast</comment>
<comment xml:lang="sl">Seznam predvajanja MP3 ShoutCast</comment>
+ <comment xml:lang="si">MP3 ShoutCast ධාවන ලැයිස්තුව</comment>
<comment xml:lang="sk">Zoznam skladieb MP3 ShoutCast</comment>
<comment xml:lang="ru">Список воспроизведения MP3 ShoutCast</comment>
<comment xml:lang="ro">Listă MP3 ShoutCast</comment>
@@ -25706,8 +26851,10 @@ command to generate the output files.
<comment xml:lang="lt">MP3 ShoutCast grojaraštis</comment>
<comment xml:lang="ko">MP3 ShoutCast 재생 목록</comment>
<comment xml:lang="kk">MP3 ShoutCast ойнау тізімі</comment>
+ <comment xml:lang="ka">MP3 ShoutCast დასაკრავი სია</comment>
<comment xml:lang="ja">MP3 ShoutCast プレイリスト</comment>
<comment xml:lang="it">Playlist MP3 ShoutCast</comment>
+ <comment xml:lang="is">MP3 ShoutCast spilunarlisti</comment>
<comment xml:lang="id">Senarai putar MP3 ShoutCast</comment>
<comment xml:lang="ia">Lista de selection MP3 ShoutCast</comment>
<comment xml:lang="hu">MP3 ShoutCast-lejátszólista</comment>
@@ -25730,6 +26877,7 @@ command to generate the output files.
<comment xml:lang="ca">llista de reproducció MP3 ShoutCast</comment>
<comment xml:lang="bg">Списък за изпълнение — MP3 ShoutCast</comment>
<comment xml:lang="be@latin">Śpis piesień dla tranślacyi MP3</comment>
+ <comment xml:lang="be">плэй-ліст MP3 ShoutCast</comment>
<comment xml:lang="ar">قائمة تشغيل MP3 ShoutCast</comment>
<alias type="application/pls"/>
<alias type="audio/scpls"/>
@@ -25749,8 +26897,9 @@ command to generate the output files.
<comment xml:lang="tr">Scream Tracker sesi</comment>
<comment xml:lang="sv">Scream Tracker-ljud</comment>
<comment xml:lang="sr">звук Скрим Тракера</comment>
- <comment xml:lang="sq">Audio Scream Tracker</comment>
+ <comment xml:lang="sq">audio Scream Tracker</comment>
<comment xml:lang="sl">Zvočna datoteka Scream Tracker</comment>
+ <comment xml:lang="si">Scream Tracker ශ්‍රව්‍ය</comment>
<comment xml:lang="sk">Skladba Scream Tracker</comment>
<comment xml:lang="ru">Аудио Scream Tracker</comment>
<comment xml:lang="ro">Audio Scream Tracker</comment>
@@ -25768,6 +26917,7 @@ command to generate the output files.
<comment xml:lang="kk">Scream Tracker аудиосы</comment>
<comment xml:lang="ja">Scream Tracker オーディオ</comment>
<comment xml:lang="it">Audio Scream Tracker</comment>
+ <comment xml:lang="is">Scream Tracker hljóðskrá</comment>
<comment xml:lang="id">Audio Scream Tracker</comment>
<comment xml:lang="ia">Audio Scream Tracker</comment>
<comment xml:lang="hu">Scream Tracker hang</comment>
@@ -25780,7 +26930,7 @@ command to generate the output files.
<comment xml:lang="fo">Scream Tracker ljóður</comment>
<comment xml:lang="fi">Scream Tracker -ääni</comment>
<comment xml:lang="eu">Scream Tracker audioa</comment>
- <comment xml:lang="es">audio Scream Tracker</comment>
+ <comment xml:lang="es">sonido Scream Tracker</comment>
<comment xml:lang="eo">Sondosiero de Scream Tracker</comment>
<comment xml:lang="en_GB">Scream Tracker audio</comment>
<comment xml:lang="el">Ήχος Scream Tracker</comment>
@@ -25791,6 +26941,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio de Scream Tracker</comment>
<comment xml:lang="bg">Аудио — Scream Tracker</comment>
<comment xml:lang="be@latin">Aŭdyjo Scream Tracker</comment>
+ <comment xml:lang="be">аўдыя Scream Tracker</comment>
<comment xml:lang="az">Scream Tracker audio faylı</comment>
<comment xml:lang="ar">صوت Scream Tracker</comment>
<magic>
@@ -25809,8 +26960,9 @@ command to generate the output files.
<comment xml:lang="tr">VOC sesi</comment>
<comment xml:lang="sv">VOC-ljud</comment>
<comment xml:lang="sr">ВОЦ звук</comment>
- <comment xml:lang="sq">Audio VOC</comment>
+ <comment xml:lang="sq">audio VOC</comment>
<comment xml:lang="sl">Zvočna datoteka VOC</comment>
+ <comment xml:lang="si">VOC ශ්‍රව්‍ය</comment>
<comment xml:lang="sk">Zvuk VOC</comment>
<comment xml:lang="ru">Аудио VOC</comment>
<comment xml:lang="ro">Audio VOC</comment>
@@ -25828,6 +26980,7 @@ command to generate the output files.
<comment xml:lang="kk">VOC аудиосы</comment>
<comment xml:lang="ja">VOC オーディオ</comment>
<comment xml:lang="it">Audio VOC</comment>
+ <comment xml:lang="is">VOC hljóðskrá</comment>
<comment xml:lang="id">Audio VOC</comment>
<comment xml:lang="ia">Audio VOC</comment>
<comment xml:lang="hu">VOC hang</comment>
@@ -25840,7 +26993,7 @@ command to generate the output files.
<comment xml:lang="fo">VOC ljóður</comment>
<comment xml:lang="fi">VOC-ääni</comment>
<comment xml:lang="eu">VOC audioa</comment>
- <comment xml:lang="es">audio VOC</comment>
+ <comment xml:lang="es">sonido VOC</comment>
<comment xml:lang="eo">VOC-sondosiero</comment>
<comment xml:lang="en_GB">VOC audio</comment>
<comment xml:lang="el">Ήχος VOC</comment>
@@ -25851,12 +27004,13 @@ command to generate the output files.
<comment xml:lang="ca">àudio VOC</comment>
<comment xml:lang="bg">Аудио — VOC</comment>
<comment xml:lang="be@latin">Aŭdyjo VOC</comment>
+ <comment xml:lang="be">аўдыя VOC</comment>
<comment xml:lang="az">VOC audio faylı</comment>
<comment xml:lang="ar">صوت VOC</comment>
<comment xml:lang="af">VOC-oudio</comment>
<glob pattern="*.voc"/>
</mime-type>
- <mime-type type="audio/x-wav">
+ <mime-type type="audio/vnd.wave">
<comment>WAV audio</comment>
<comment xml:lang="zh_TW">WAV 音訊</comment>
<comment xml:lang="zh_CN">WAV 音频</comment>
@@ -25865,8 +27019,9 @@ command to generate the output files.
<comment xml:lang="tr">WAV sesi</comment>
<comment xml:lang="sv">WAV-ljud</comment>
<comment xml:lang="sr">ВАВ звук</comment>
- <comment xml:lang="sq">Audio WAV</comment>
+ <comment xml:lang="sq">audio WAV</comment>
<comment xml:lang="sl">Zvočna datoteka WAV</comment>
+ <comment xml:lang="si">WAV ශ්රව්ය</comment>
<comment xml:lang="sk">Zvuk WAV</comment>
<comment xml:lang="ru">Аудио WAV</comment>
<comment xml:lang="ro">Audio WAV</comment>
@@ -25884,6 +27039,7 @@ command to generate the output files.
<comment xml:lang="kk">WAV аудиосы</comment>
<comment xml:lang="ja">WAV オーディオ</comment>
<comment xml:lang="it">Audio WAV</comment>
+ <comment xml:lang="is">WAV hljóðskrá</comment>
<comment xml:lang="id">Audio WAV</comment>
<comment xml:lang="ia">Audio WAV</comment>
<comment xml:lang="hu">WAV hang</comment>
@@ -25896,7 +27052,7 @@ command to generate the output files.
<comment xml:lang="fo">WAV ljóður</comment>
<comment xml:lang="fi">WAV-ääni</comment>
<comment xml:lang="eu">WAV audioa</comment>
- <comment xml:lang="es">audio WAV</comment>
+ <comment xml:lang="es">sonido WAV</comment>
<comment xml:lang="eo">WAV-sonkodo</comment>
<comment xml:lang="en_GB">WAV audio</comment>
<comment xml:lang="el">Ήχος WAV</comment>
@@ -25907,11 +27063,13 @@ command to generate the output files.
<comment xml:lang="ca">àudio WAV</comment>
<comment xml:lang="bg">Аудио — WAV</comment>
<comment xml:lang="be@latin">Aŭdyjo WAV</comment>
+ <comment xml:lang="be">аўдыя WAV</comment>
<comment xml:lang="az">WAV audio faylı</comment>
<comment xml:lang="ar">صوت WAV</comment>
<comment xml:lang="af">WAV-oudio</comment>
<alias type="audio/wav"/>
- <alias type="audio/vnd.wave"/>
+ <alias type="audio/x-wav"/>
+ <sub-class-of type="application/x-riff"/>
<magic>
<match type="string" value="WAVE" offset="8"/>
<match type="string" value="WAV " offset="8"/>
@@ -25919,58 +27077,16 @@ command to generate the output files.
<glob pattern="*.wav"/>
</mime-type>
<mime-type type="audio/x-xi">
- <comment>Scream Tracker instrument</comment>
- <comment xml:lang="zh_TW">Scream Tracker 樂器檔</comment>
- <comment xml:lang="zh_CN">Scream Tracker 乐器</comment>
- <comment xml:lang="vi">Nhạc khí Scream Tracker</comment>
- <comment xml:lang="uk">інструмент Scream Tracker</comment>
- <comment xml:lang="tr">Scream Tracker çalgısı</comment>
- <comment xml:lang="sv">Scream Tracker-instrument</comment>
- <comment xml:lang="sr">инструмент Скрим Тракера</comment>
- <comment xml:lang="sq">Instrument Scream Tracker</comment>
- <comment xml:lang="sl">Datoteka zvoka glasbila Scream Tracker</comment>
- <comment xml:lang="sk">Nástroj pre Scream Tracker</comment>
- <comment xml:lang="ru">Инструмент Scream Tracker</comment>
- <comment xml:lang="ro">Instrument Scream Tracker</comment>
- <comment xml:lang="pt_BR">Instrumento Scream Tracker</comment>
- <comment xml:lang="pt">instrumento Scream Tracker</comment>
- <comment xml:lang="pl">Instrument Scream Tracker</comment>
- <comment xml:lang="oc">instrument Scream Tracker</comment>
- <comment xml:lang="nn">Scream Tracker instrument</comment>
- <comment xml:lang="nl">Scream Tracker-instrument</comment>
- <comment xml:lang="nb">Scream Tracker-instrument</comment>
- <comment xml:lang="ms">Instrumen Scream Tracker</comment>
- <comment xml:lang="lv">Scream Tracker instrumenti</comment>
- <comment xml:lang="lt">Scream Tracker instrumentas</comment>
- <comment xml:lang="ko">Scream Tracker 악기</comment>
- <comment xml:lang="kk">Scream Tracker сайманы</comment>
- <comment xml:lang="ja">Scream Tracker インストゥルメント</comment>
- <comment xml:lang="it">Strumento Scream Tracker</comment>
- <comment xml:lang="id">Instrumen Scream Tracker</comment>
- <comment xml:lang="ia">Instrumento Scream Tracker</comment>
- <comment xml:lang="hu">Scream Tracker hangszer</comment>
- <comment xml:lang="hr">Scream Tracker instrument</comment>
- <comment xml:lang="he">כלי של Scream Tracker</comment>
- <comment xml:lang="gl">Instrumento Scream Tracker</comment>
- <comment xml:lang="ga">ionstraim Scream Tracker</comment>
- <comment xml:lang="fur">strument Scream Tracker</comment>
- <comment xml:lang="fr">instrument Scream Tracker</comment>
- <comment xml:lang="fo">Scream Tracker ljóðføri</comment>
- <comment xml:lang="fi">Scream Tracker -soitin</comment>
- <comment xml:lang="eu">Scream Tracker instrumentua</comment>
- <comment xml:lang="es">instrumento Scream Tracker</comment>
- <comment xml:lang="eo">instrumento de Scream Tracker</comment>
- <comment xml:lang="en_GB">Scream Tracker instrument</comment>
- <comment xml:lang="el">Μουσικό όργανο Scream Tracker</comment>
- <comment xml:lang="de">Scream-Tracker-Instrument</comment>
- <comment xml:lang="da">Scream Tracker-instrument</comment>
- <comment xml:lang="cy">Offeryn Scream Tracker</comment>
- <comment xml:lang="cs">nástroj pro Scream Tracker</comment>
- <comment xml:lang="ca">instrument de Scream Tracker</comment>
- <comment xml:lang="bg">Инструмент — Scream Tracker</comment>
- <comment xml:lang="be@latin">Instrument Scream Tracker</comment>
- <comment xml:lang="az">Scream Tracker instrumenti</comment>
- <comment xml:lang="ar">آلة Scream Tracker</comment>
+ <comment>FastTracker II instrument</comment>
+ <comment xml:lang="uk">інструмент FastTracker II</comment>
+ <comment xml:lang="sv">FastTracker II-instrument</comment>
+ <comment xml:lang="ru">Инструмент FastTracker II</comment>
+ <comment xml:lang="pl">Instrument FastTracker II</comment>
+ <comment xml:lang="it">Strumento FastTracker II</comment>
+ <comment xml:lang="eu">FastTracker II tresna</comment>
+ <comment xml:lang="es">instrumento de FastTracker II</comment>
+ <comment xml:lang="de">FastTracker-II-Instrument</comment>
+ <comment xml:lang="be">інструмент FastTracker II</comment>
<magic>
<match value="Extended Instrument:" type="string" offset="0"/>
</magic>
@@ -25985,8 +27101,9 @@ command to generate the output files.
<comment xml:lang="tr">FastTracker II sesi</comment>
<comment xml:lang="sv">FastTracker II-ljud</comment>
<comment xml:lang="sr">звук Фаст Тракера ИИ</comment>
- <comment xml:lang="sq">Audio FastTracker II</comment>
+ <comment xml:lang="sq">audio FastTracker II</comment>
<comment xml:lang="sl">Zvočna datoteka FastTracker II</comment>
+ <comment xml:lang="si">FastTracker II ශ්‍රව්‍ය</comment>
<comment xml:lang="sk">Zvuk FastTracker II</comment>
<comment xml:lang="ru">Аудио FastTracker II</comment>
<comment xml:lang="ro">Audio FastTracker II</comment>
@@ -26005,6 +27122,7 @@ command to generate the output files.
<comment xml:lang="ka">FastTracker II-ის აუდიო</comment>
<comment xml:lang="ja">FastTracker II オーディオ</comment>
<comment xml:lang="it">Audio FastTracker II</comment>
+ <comment xml:lang="is">FastTracker II hljóðskrá</comment>
<comment xml:lang="id">Audio FastTracker II</comment>
<comment xml:lang="ia">Audio FastTracker II</comment>
<comment xml:lang="hu">FastTracker II hang</comment>
@@ -26017,7 +27135,7 @@ command to generate the output files.
<comment xml:lang="fo">FastTracker II ljóður</comment>
<comment xml:lang="fi">FastTracker II -ääni</comment>
<comment xml:lang="eu">FastTracker II.ren audioa</comment>
- <comment xml:lang="es">audio FastTracker II</comment>
+ <comment xml:lang="es">sonido FastTracker II</comment>
<comment xml:lang="eo">Sondosiero de FastTracker II</comment>
<comment xml:lang="en_GB">FastTracker II audio</comment>
<comment xml:lang="el">Ήχος FastTracker II</comment>
@@ -26028,6 +27146,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio de FastTracker II</comment>
<comment xml:lang="bg">Аудио — FastTracker II</comment>
<comment xml:lang="be@latin">Aŭdyjo FastTracker II</comment>
+ <comment xml:lang="be">аўдыя FastTracker II</comment>
<comment xml:lang="az">FastTracker II audio faylı</comment>
<comment xml:lang="ar">صوت FastTracker II</comment>
<magic>
@@ -26044,8 +27163,9 @@ command to generate the output files.
<comment xml:lang="tr">TrueAudio sesi</comment>
<comment xml:lang="sv">TrueAudio-ljud</comment>
<comment xml:lang="sr">Тру Аудио звук</comment>
- <comment xml:lang="sq">Audio TrueAudio</comment>
+ <comment xml:lang="sq">audio TrueAudio</comment>
<comment xml:lang="sl">Zvočna datoteka TrueAudio</comment>
+ <comment xml:lang="si">TrueAudio ශ්රව්ය</comment>
<comment xml:lang="sk">Zvuk TrueAudio</comment>
<comment xml:lang="ru">Аудио TrueAudio</comment>
<comment xml:lang="ro">Audio TrueAudio</comment>
@@ -26062,6 +27182,7 @@ command to generate the output files.
<comment xml:lang="kk">TrueAudio аудиосы</comment>
<comment xml:lang="ja">TrueAudio オーディオ</comment>
<comment xml:lang="it">Audio TrueAudio</comment>
+ <comment xml:lang="is">TrueAudio hljóðskrá</comment>
<comment xml:lang="id">Audio TrueAudio</comment>
<comment xml:lang="ia">Audio TrueAudio</comment>
<comment xml:lang="hu">TrueAudio hang</comment>
@@ -26074,7 +27195,7 @@ command to generate the output files.
<comment xml:lang="fo">TrueAudio ljóður</comment>
<comment xml:lang="fi">TrueAudio-ääni</comment>
<comment xml:lang="eu">TrueAudio audioa</comment>
- <comment xml:lang="es">audio TrueAudio</comment>
+ <comment xml:lang="es">sonido TrueAudio</comment>
<comment xml:lang="eo">TrueAudio-sondosiero</comment>
<comment xml:lang="en_GB">TrueAudio audio</comment>
<comment xml:lang="el">Ήχος TrueAudio</comment>
@@ -26084,6 +27205,7 @@ command to generate the output files.
<comment xml:lang="ca">àudio TrueAudio</comment>
<comment xml:lang="bg">Аудио — TrueAudio</comment>
<comment xml:lang="be@latin">Aŭdyjo TrueAudio</comment>
+ <comment xml:lang="be">аўдыя TrueAudio</comment>
<comment xml:lang="ar">صوت TrueAudio</comment>
<comment xml:lang="af">TrueAudio-oudio</comment>
<alias type="audio/tta"/>
@@ -26101,8 +27223,9 @@ command to generate the output files.
<comment xml:lang="tr">Windows BMP görüntüsü</comment>
<comment xml:lang="sv">Windows BMP-bild</comment>
<comment xml:lang="sr">Виндоузова БМП слика</comment>
- <comment xml:lang="sq">Figurë Windows BMP</comment>
+ <comment xml:lang="sq">figurë Windows BMP</comment>
<comment xml:lang="sl">Slikovna datoteka Windows BMP</comment>
+ <comment xml:lang="si">වින්ඩෝස් BMP රූපය</comment>
<comment xml:lang="sk">Obrázok Windows BMP</comment>
<comment xml:lang="ru">Изображение Windows BMP</comment>
<comment xml:lang="ro">Imagine Windows BMP</comment>
@@ -26120,6 +27243,7 @@ command to generate the output files.
<comment xml:lang="kk">Windows BMP суреті</comment>
<comment xml:lang="ja">Windows BMP 画像</comment>
<comment xml:lang="it">Immagine Windows BMP</comment>
+ <comment xml:lang="is">Windows BMP mynd</comment>
<comment xml:lang="id">Citra Windows BMP</comment>
<comment xml:lang="ia">Imagine BMP de Windows</comment>
<comment xml:lang="hu">Windows BMP-kép</comment>
@@ -26136,13 +27260,14 @@ command to generate the output files.
<comment xml:lang="eo">BMP-bildo de Vindozo</comment>
<comment xml:lang="en_GB">Windows BMP image</comment>
<comment xml:lang="el">Εικόνα Windows BMP</comment>
- <comment xml:lang="de">Windows-BMP-Bild</comment>
+ <comment xml:lang="de">Windows BMP-Bild</comment>
<comment xml:lang="da">Windows BMP-billede</comment>
<comment xml:lang="cy">Delwedd BMP Windows</comment>
<comment xml:lang="cs">obrázek Windows BMP</comment>
<comment xml:lang="ca">imatge BMP de Windows</comment>
<comment xml:lang="bg">Изображение — Windows BMP</comment>
<comment xml:lang="be@latin">Vyjava Windows BMP</comment>
+ <comment xml:lang="be">выява Windows BMP</comment>
<comment xml:lang="az">Windows BMP rəsmi</comment>
<comment xml:lang="ar">صورة Windows BMP</comment>
<comment xml:lang="af">Windows BMP-beeld</comment>
@@ -26168,8 +27293,9 @@ command to generate the output files.
<comment xml:lang="tr">WBMP görüntüsü</comment>
<comment xml:lang="sv">WBMP-bild</comment>
<comment xml:lang="sr">ВБМП слика</comment>
- <comment xml:lang="sq">Figurë WBMP</comment>
+ <comment xml:lang="sq">figurë WBMP</comment>
<comment xml:lang="sl">Slikovna datoteka WBMP</comment>
+ <comment xml:lang="si">WBMP රූපය</comment>
<comment xml:lang="sk">Obrázok WBMP</comment>
<comment xml:lang="ru">Изображение WBMP</comment>
<comment xml:lang="ro">Imagine WBMP</comment>
@@ -26186,6 +27312,7 @@ command to generate the output files.
<comment xml:lang="kk">WBMP суреті</comment>
<comment xml:lang="ja">WBMP 画像</comment>
<comment xml:lang="it">Immagine WBMP</comment>
+ <comment xml:lang="is">WBMP mynd</comment>
<comment xml:lang="id">Citra WBMP</comment>
<comment xml:lang="ia">Imagine WBMP</comment>
<comment xml:lang="hu">WBMP kép</comment>
@@ -26208,6 +27335,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge WBMP</comment>
<comment xml:lang="bg">Изображение — WBMP</comment>
<comment xml:lang="be@latin">Vyjava WBMP</comment>
+ <comment xml:lang="be">выява WBMP</comment>
<comment xml:lang="ar">صورة WBMP</comment>
<comment xml:lang="af">WBMP-beeld</comment>
<acronym>WBMP</acronym>
@@ -26221,16 +27349,20 @@ command to generate the output files.
<comment xml:lang="uk">зображення CGM</comment>
<comment xml:lang="tr">CGM görüntüsü</comment>
<comment xml:lang="sv">CGM-bild</comment>
+ <comment xml:lang="sq">figurë CGM</comment>
<comment xml:lang="sl">Slika CGM</comment>
+ <comment xml:lang="si">CGM රූපය</comment>
<comment xml:lang="sk">Obrázok CGM</comment>
<comment xml:lang="ru">Изображение CGM</comment>
<comment xml:lang="pt_BR">Imagem CGM</comment>
<comment xml:lang="pl">Obraz CGM</comment>
<comment xml:lang="oc">imatge CGM</comment>
+ <comment xml:lang="nl">CGM-afbeelding</comment>
<comment xml:lang="ko">CGM 이미지</comment>
<comment xml:lang="kk">CGM суреті</comment>
<comment xml:lang="ja">CGM 画像</comment>
<comment xml:lang="it">Immagine CGM</comment>
+ <comment xml:lang="is">CGM mynd</comment>
<comment xml:lang="id">Citra CGM</comment>
<comment xml:lang="hu">CGM-kép</comment>
<comment xml:lang="hr">CGM slika</comment>
@@ -26244,6 +27376,7 @@ command to generate the output files.
<comment xml:lang="da">CGM-billede</comment>
<comment xml:lang="ca">imatge CGM</comment>
<comment xml:lang="bg">Изображение — CGM</comment>
+ <comment xml:lang="be">выява CGM</comment>
<comment xml:lang="ar">صورة CGM</comment>
<acronym>CGM</acronym>
<expanded-acronym>Computer Graphics Metafile</expanded-acronym>
@@ -26256,13 +27389,18 @@ command to generate the output files.
<comment xml:lang="uk">зображення факсу G3 CCITT</comment>
<comment xml:lang="tr">CCITT G3 faks görüntüsü</comment>
<comment xml:lang="sv">CCITT G3 faxbild</comment>
+ <comment xml:lang="sq">figurë faks CCITT G3</comment>
+ <comment xml:lang="sl">Slikovna datoteka faksimila CCITT G3</comment>
+ <comment xml:lang="si">CCITT G3 ෆැක්ස් රූපය</comment>
<comment xml:lang="ru">Факсовое изображение CCITT G3</comment>
<comment xml:lang="pt_BR">Imagem de fax CCITT G3</comment>
<comment xml:lang="pl">Obraz faksowy G3 CCITT</comment>
+ <comment xml:lang="nl">CCITT G3-faxafbeelding</comment>
<comment xml:lang="ko">CCITT G3 팩스 이미지</comment>
<comment xml:lang="kk">CCITT G3 факс суреті</comment>
<comment xml:lang="ja">CCITT G3 ファックス画像</comment>
<comment xml:lang="it">Immagine fax CCIT G3</comment>
+ <comment xml:lang="is">CCITT G3 faxmynd</comment>
<comment xml:lang="id">Citra faks CCITT G3</comment>
<comment xml:lang="hu">CCITT G3-faxkép</comment>
<comment xml:lang="hr">CCITT G3 slika faksa</comment>
@@ -26272,10 +27410,11 @@ command to generate the output files.
<comment xml:lang="eu">CCITT G3 fax irudia</comment>
<comment xml:lang="es">imagen de fax CCITT G3</comment>
<comment xml:lang="en_GB">CCITT G3 fax image</comment>
- <comment xml:lang="de">CCITT-G3-Faxbild</comment>
+ <comment xml:lang="de">CCITT-G3-Fax</comment>
<comment xml:lang="da">CCITT G3-faxbillede</comment>
<comment xml:lang="ca">imatge de fax CCITT G3</comment>
<comment xml:lang="bg">Изображение — CCITT G3, факс</comment>
+ <comment xml:lang="be">выява факса CCITT G3</comment>
<comment xml:lang="ar">صورة فاكس CCITT G3</comment>
<acronym>CCITT</acronym>
<expanded-acronym>Comité Consultatif International Téléphonique et Télégraphique</expanded-acronym>
@@ -26291,8 +27430,9 @@ command to generate the output files.
<comment xml:lang="tr">GIF görüntüsü</comment>
<comment xml:lang="sv">GIF-bild</comment>
<comment xml:lang="sr">ГИФ слика</comment>
- <comment xml:lang="sq">Figurë GIF</comment>
+ <comment xml:lang="sq">figurë GIF</comment>
<comment xml:lang="sl">Slikovna datoteka GIF</comment>
+ <comment xml:lang="si">GIF රූපය</comment>
<comment xml:lang="sk">Obrázok GIF</comment>
<comment xml:lang="ru">Изображение GIF</comment>
<comment xml:lang="ro">Imagine GIF</comment>
@@ -26311,6 +27451,7 @@ command to generate the output files.
<comment xml:lang="ka">GIF გამოსახულება</comment>
<comment xml:lang="ja">GIF 画像</comment>
<comment xml:lang="it">Immagine GIF</comment>
+ <comment xml:lang="is">GIF mynd</comment>
<comment xml:lang="id">Citra GIF</comment>
<comment xml:lang="ia">Imagine GIF</comment>
<comment xml:lang="hu">GIF-kép</comment>
@@ -26334,6 +27475,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge GIF</comment>
<comment xml:lang="bg">Изображение — GIF</comment>
<comment xml:lang="be@latin">Vyjava GIF</comment>
+ <comment xml:lang="be">выява GIF</comment>
<comment xml:lang="az">GIF rəsmi</comment>
<comment xml:lang="ar">صورة GIF</comment>
<comment xml:lang="af">GIF-beeld</comment>
@@ -26351,15 +27493,19 @@ command to generate the output files.
<comment xml:lang="uk">зображення HEIF</comment>
<comment xml:lang="tr">HEIF görüntüsü</comment>
<comment xml:lang="sv">HEIF-bild</comment>
+ <comment xml:lang="sq">figurë HEIF</comment>
<comment xml:lang="sl">Slika HEIF</comment>
+ <comment xml:lang="si">HEIF රූපය</comment>
<comment xml:lang="sk">Obrázok HEIF</comment>
<comment xml:lang="ru">Изображение HEIF</comment>
<comment xml:lang="pt_BR">Imagem HEIF</comment>
<comment xml:lang="pl">Obraz HEIF</comment>
+ <comment xml:lang="nl">HEIF-afbeelding</comment>
<comment xml:lang="ko">HEIF 그림</comment>
<comment xml:lang="kk">HEIF суреті</comment>
<comment xml:lang="ja">HEIF 画像</comment>
<comment xml:lang="it">Immagine HEIF</comment>
+ <comment xml:lang="is">HEIF mynd</comment>
<comment xml:lang="id">Citra HEIF</comment>
<comment xml:lang="hu">HEIF kép</comment>
<comment xml:lang="hr">HEIF slika</comment>
@@ -26376,6 +27522,7 @@ command to generate the output files.
<comment xml:lang="cs">obrázek HEIF</comment>
<comment xml:lang="ca">imatge HEIF</comment>
<comment xml:lang="bg">Изображение — HEIF</comment>
+ <comment xml:lang="be">выява HEIF</comment>
<comment xml:lang="ar">صورة HEIF</comment>
<comment xml:lang="af">HEIF-beeld</comment>
<acronym>HEIF</acronym>
@@ -26405,8 +27552,9 @@ command to generate the output files.
<comment xml:lang="tr">IEF görüntüsü</comment>
<comment xml:lang="sv">IEF-bild</comment>
<comment xml:lang="sr">ИЕФ слика</comment>
- <comment xml:lang="sq">Figurë IEF</comment>
+ <comment xml:lang="sq">figurë IEF</comment>
<comment xml:lang="sl">Slikovna datoteka IEF</comment>
+ <comment xml:lang="si">IEF රූපය</comment>
<comment xml:lang="sk">Obrázok IEF</comment>
<comment xml:lang="ru">Изображение IEF</comment>
<comment xml:lang="ro">Imagine IEF</comment>
@@ -26424,6 +27572,7 @@ command to generate the output files.
<comment xml:lang="kk">IEF суреті</comment>
<comment xml:lang="ja">IEF 画像</comment>
<comment xml:lang="it">Immagine IEF</comment>
+ <comment xml:lang="is">IEF mynd</comment>
<comment xml:lang="id">Citra IEF</comment>
<comment xml:lang="ia">Imagine IEF</comment>
<comment xml:lang="hu">IEF-kép</comment>
@@ -26447,6 +27596,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge IEF</comment>
<comment xml:lang="bg">Изображение — IEF</comment>
<comment xml:lang="be@latin">Vyjava IEF</comment>
+ <comment xml:lang="be">выява IEF</comment>
<comment xml:lang="az">IEF rəsmi</comment>
<comment xml:lang="ar">صورة IEF</comment>
<comment xml:lang="af">IEF-beeld</comment>
@@ -26461,8 +27611,9 @@ command to generate the output files.
<comment xml:lang="tr">JPEG görüntüsü</comment>
<comment xml:lang="sv">JPEG-bild</comment>
<comment xml:lang="sr">ЈПЕГ слика</comment>
- <comment xml:lang="sq">Figurë JPEG</comment>
+ <comment xml:lang="sq">figurë JPEG</comment>
<comment xml:lang="sl">Slikovna datoteka JPEG</comment>
+ <comment xml:lang="si">JPEG රූපය</comment>
<comment xml:lang="sk">Obrázok JPEG</comment>
<comment xml:lang="ru">Изображение JPEG</comment>
<comment xml:lang="ro">Imagine JPEG</comment>
@@ -26478,8 +27629,10 @@ command to generate the output files.
<comment xml:lang="lt">JPEG paveikslėlis</comment>
<comment xml:lang="ko">JPEG 그림</comment>
<comment xml:lang="kk">JPEG суреті</comment>
+ <comment xml:lang="ka">JPEG გამოსახულება</comment>
<comment xml:lang="ja">JPEG 画像 </comment>
<comment xml:lang="it">Immagine JPEG</comment>
+ <comment xml:lang="is">JPEG mynd</comment>
<comment xml:lang="id">Citra JPEG</comment>
<comment xml:lang="ia">Imagine JPEG</comment>
<comment xml:lang="hu">JPEG-kép</comment>
@@ -26503,6 +27656,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge JPEG</comment>
<comment xml:lang="bg">Изображение — JPEG</comment>
<comment xml:lang="be@latin">Vyjava JPEG</comment>
+ <comment xml:lang="be">выява JPEG</comment>
<comment xml:lang="az">JPEG rəsmi</comment>
<comment xml:lang="ar">صورة JPEG</comment>
<comment xml:lang="af">JPEG-beeld</comment>
@@ -26515,6 +27669,7 @@ command to generate the output files.
<glob pattern="*.jpg"/>
<glob pattern="*.jpeg"/>
<glob pattern="*.jpe"/>
+ <glob pattern="*.jfif"/>
<alias type="image/pjpeg"/>
</mime-type>
<mime-type type="video/x-mjpeg">
@@ -26524,15 +27679,19 @@ command to generate the output files.
<comment xml:lang="uk">відеопотік MJPEG</comment>
<comment xml:lang="tr">MJPEG video akışı</comment>
<comment xml:lang="sv">MJPEG-videoström</comment>
+ <comment xml:lang="sq">transmetim video MJEPG</comment>
+ <comment xml:lang="si">MJPEG වීඩියෝ ප්‍රවාහය</comment>
<comment xml:lang="sk">Stream videa MJPEG</comment>
<comment xml:lang="ru">Видеопоток MJPEG</comment>
<comment xml:lang="pt_BR">Fluxo de vídeo MPEG</comment>
<comment xml:lang="pl">Strumień wideo MJPEG</comment>
+ <comment xml:lang="nl">MJPEG-video-stream</comment>
<comment xml:lang="lt">MJPEG vaizdo srautas</comment>
- <comment xml:lang="ko">MJPEG 비디오 스트림</comment>
+ <comment xml:lang="ko">MJPEG 동영상 스트림</comment>
<comment xml:lang="kk">MJPEG видео ағыны</comment>
<comment xml:lang="ja">MJPEG 動画ストリーム</comment>
<comment xml:lang="it">Stream video MJPEG</comment>
+ <comment xml:lang="is">MJPEG myndmerkisstreymi</comment>
<comment xml:lang="id">Stream video MJPEG</comment>
<comment xml:lang="hu">MJPEG videofolyam</comment>
<comment xml:lang="hr">Prijenos MJPEG videa</comment>
@@ -26549,6 +27708,7 @@ command to generate the output files.
<comment xml:lang="cs">datový tok videa MJPEG</comment>
<comment xml:lang="ca">flux de vídeo MJPEG</comment>
<comment xml:lang="bg">Поток — MJPEG, видео</comment>
+ <comment xml:lang="be">плынь відэа MJPEG</comment>
<comment xml:lang="ar">دفق فيديو MJPEG</comment>
<comment xml:lang="af">MJPEG-videostroom</comment>
<acronym>MJPEG</acronym>
@@ -26564,14 +27724,17 @@ command to generate the output files.
<comment xml:lang="uk">потік коду JPEG-2000</comment>
<comment xml:lang="tr">JPEG-2000 codestream</comment>
<comment xml:lang="sv">JPEG-2000-kodström</comment>
+ <comment xml:lang="si">JPEG-2000 කේත ප්‍රවාහය</comment>
<comment xml:lang="sk">JPEG-2000 codestream</comment>
<comment xml:lang="ru">Кодовый поток JPEG-2000</comment>
<comment xml:lang="pt_BR">Imagem JPEG-2000</comment>
<comment xml:lang="pl">Strumień kodu JPEG-2000</comment>
+ <comment xml:lang="nl">JPEG-2000-codestream</comment>
<comment xml:lang="ko">JPEG-2000 코드스트림</comment>
<comment xml:lang="kk">JPEG-2000 код ағыны</comment>
<comment xml:lang="ja">JPEG-2000 コードストリーム</comment>
<comment xml:lang="it">Codestream JPEG-2000</comment>
+ <comment xml:lang="is">JPEG-2000 kóðastreymi</comment>
<comment xml:lang="id">Codestream JPEG-2000</comment>
<comment xml:lang="hu">JPEG-2000 kódfolyam</comment>
<comment xml:lang="hr">JPEG-2000 kôd strujanja</comment>
@@ -26588,6 +27751,7 @@ command to generate the output files.
<comment xml:lang="cs">datový tok JPEG-2000</comment>
<comment xml:lang="ca">flux de codis JPEG-2000</comment>
<comment xml:lang="bg">Поток — JPEG-2000, кодирано</comment>
+ <comment xml:lang="be">плынь кода JPEG-2000</comment>
<comment xml:lang="ar">تيار شفرة JPEG-2000</comment>
<magic>
<match type="big32" value="0xff4fff51" offset="0"/>
@@ -26603,15 +27767,20 @@ command to generate the output files.
<comment xml:lang="uk">зображення JP2 JPEG-2000</comment>
<comment xml:lang="tr">JPEG-2000 JP2 görüntüsü</comment>
<comment xml:lang="sv">JPEG-2000 JP2-bild</comment>
+ <comment xml:lang="sq">figurë JPEG-2000 JP2</comment>
<comment xml:lang="sl">Slika JPEG-2000 JP2</comment>
+ <comment xml:lang="si">JPEG-2000 JP2 රූපය</comment>
<comment xml:lang="sk">Obrázok JPEG-2000 JP2</comment>
- <comment xml:lang="ru">Изоражение JPEG-2000 JP2</comment>
+ <comment xml:lang="ru">Изображение JPEG-2000 JP2</comment>
<comment xml:lang="pt_BR">Imagem JP2 de JPEG-2000</comment>
<comment xml:lang="pl">Obraz JP2 JPEG-2000</comment>
+ <comment xml:lang="oc">imatge JPEG-2000 JP2</comment>
+ <comment xml:lang="nl">JPEG-2000 JP2-afbeelding</comment>
<comment xml:lang="ko">JPEG-2000 JP2 그림</comment>
<comment xml:lang="kk">JPEG-2000 JP2 суреті</comment>
<comment xml:lang="ja">JPEG-2000 JP2 画像</comment>
<comment xml:lang="it">Immagine JPEG-2000 JP2</comment>
+ <comment xml:lang="is">JPEG-2000 JP2 mynd</comment>
<comment xml:lang="id">Citra JPEG-2000 JP2</comment>
<comment xml:lang="hu">JPEG-2000 JP2 kép</comment>
<comment xml:lang="hr">JPEG-2000 JP2 slika</comment>
@@ -26628,6 +27797,7 @@ command to generate the output files.
<comment xml:lang="cs">obrázek JPEG-2000 JP2</comment>
<comment xml:lang="ca">imatge JPEG-2000 JP2</comment>
<comment xml:lang="bg">Изображение — JPEG-2000 JP2</comment>
+ <comment xml:lang="be">выява JPEG-2000 JP2</comment>
<comment xml:lang="ar">صورة JPEG-2000 JP2</comment>
<comment xml:lang="af">JPEG-2000 JP2-beeld</comment>
<acronym>JP2</acronym>
@@ -26648,15 +27818,20 @@ command to generate the output files.
<comment xml:lang="uk">зображення JPX JPEG-2000</comment>
<comment xml:lang="tr">JPEG-2000 JPX görüntüsü</comment>
<comment xml:lang="sv">JPEG-2000 JPX-bild</comment>
+ <comment xml:lang="sq"> image JPEG-2000 JPX</comment>
<comment xml:lang="sl">Slika JPEG-2000 JPX</comment>
+ <comment xml:lang="si">JPEG-2000 JPX රූපය</comment>
<comment xml:lang="sk">Obrázok JPEG-2000 JPX</comment>
<comment xml:lang="ru">Изображение JPEG-2000 JPX</comment>
<comment xml:lang="pt_BR">Imagem JPX de JPEG-2000</comment>
<comment xml:lang="pl">Obraz JPX JPEG-2000</comment>
+ <comment xml:lang="oc">imatge JPEG-2000 JPX</comment>
+ <comment xml:lang="nl">JPEG-2000 JPX-afbeelding</comment>
<comment xml:lang="ko">JPEG-2000 JPX 그림</comment>
<comment xml:lang="kk">JPEG-2000 JPX суреті</comment>
<comment xml:lang="ja">JPEG-2000 JPX 画像</comment>
<comment xml:lang="it">Immagine JPEG-2000 JPX</comment>
+ <comment xml:lang="is">JPEG-2000 JPX mynd</comment>
<comment xml:lang="id">Citra JPEG-2000 JPX</comment>
<comment xml:lang="hu">JPEG-2000 JPX kép</comment>
<comment xml:lang="hr">JPEG-2000 JPX slika</comment>
@@ -26673,6 +27848,7 @@ command to generate the output files.
<comment xml:lang="cs">obrázek JPEG-2000 JPX</comment>
<comment xml:lang="ca">imatge JPEG-2000 JPX</comment>
<comment xml:lang="bg">Изображение — JPEG-2000 JPX</comment>
+ <comment xml:lang="be">выява JPEG-2000 JPX</comment>
<comment xml:lang="ar">صورة JPEG-2000 JPX</comment>
<comment xml:lang="af">JPEG-2000 JPX-beeld</comment>
<acronym>JPX</acronym>
@@ -26690,15 +27866,20 @@ command to generate the output files.
<comment xml:lang="uk">зображення JPM JPEG-2000</comment>
<comment xml:lang="tr">JPEG-2000 JPM görüntüsü</comment>
<comment xml:lang="sv">JPEG-2000 JPM-bild</comment>
+ <comment xml:lang="sq">figurë JPEG-2000 JPM</comment>
<comment xml:lang="sl">Slika JPEG-2000 JPM</comment>
+ <comment xml:lang="si">JPEG-2000 JPM රූපය</comment>
<comment xml:lang="sk">Obrázok JPEG-2000 JPM</comment>
<comment xml:lang="ru">Изображение JPEG-2000 JPM</comment>
<comment xml:lang="pt_BR">Imagem JPM de JPEG-2000</comment>
<comment xml:lang="pl">Obraz JPM JPEG-2000</comment>
+ <comment xml:lang="oc">imatge JPEG-2000 JPM</comment>
+ <comment xml:lang="nl">JPEG-2000 JPM-afbeelding</comment>
<comment xml:lang="ko">JPEG-2000 JPM 그림</comment>
<comment xml:lang="kk">JPEG-2000 JPM суреті</comment>
<comment xml:lang="ja">JPEG-2000 JPM 画像</comment>
<comment xml:lang="it">Immagine JPEG-2000 JPM</comment>
+ <comment xml:lang="is">JPEG-2000 JPM mynd</comment>
<comment xml:lang="id">Citra JPEG-2000 JPM</comment>
<comment xml:lang="hu">JPEG-2000 JPM kép</comment>
<comment xml:lang="hr">JPEG-2000 JPM slika</comment>
@@ -26715,6 +27896,7 @@ command to generate the output files.
<comment xml:lang="cs">obrázek JPEG-2000 JPM</comment>
<comment xml:lang="ca">imatge JPEG-2000 JPM</comment>
<comment xml:lang="bg">Изображение — JPEG-2000 JPM</comment>
+ <comment xml:lang="be">выява JPEG-2000 JPM</comment>
<comment xml:lang="ar">صورة JPEG-2000 JPM</comment>
<comment xml:lang="af">JPEG-2000 JPM-beeld</comment>
<acronym>JPM</acronym>
@@ -26732,15 +27914,20 @@ command to generate the output files.
<comment xml:lang="uk">зображення MJ2 JPEG-2000</comment>
<comment xml:lang="tr">JPEG-2000 MJ2 videosu</comment>
<comment xml:lang="sv">JPEG-2000 MJ2-bild</comment>
+ <comment xml:lang="sq">video JPEG-2000 MJ2</comment>
<comment xml:lang="sl">Video JPEG-2000 MJ2</comment>
+ <comment xml:lang="si">JPEG-2000 MJ2 වීඩියෝව</comment>
<comment xml:lang="sk">Video JPEG-2000 MJ2</comment>
<comment xml:lang="ru">Видео JPEG-2000 MJ2</comment>
<comment xml:lang="pt_BR">Imagem MJ2 de JPEG-2000</comment>
<comment xml:lang="pl">Plik wideo MJ2 JPEG-2000</comment>
+ <comment xml:lang="oc">vidèo JPEG-2000 MJ2</comment>
+ <comment xml:lang="nl">JPEG-2000 MJ2-video</comment>
<comment xml:lang="ko">JPEG-2000 MJ2 동영상</comment>
<comment xml:lang="kk">JPEG-2000 MJ2 видеосы</comment>
<comment xml:lang="ja">JPEG-2000 MJ2 動画</comment>
<comment xml:lang="it">Video JPEG-2000 MJ2</comment>
+ <comment xml:lang="is">JPEG-2000 MJ2 myndskeið</comment>
<comment xml:lang="id">Video JPEG-2000 MJ2</comment>
<comment xml:lang="hu">JPEG-2000 MJ2 videó</comment>
<comment xml:lang="hr">JPEG-2000 MJ2 video snimka</comment>
@@ -26757,6 +27944,7 @@ command to generate the output files.
<comment xml:lang="cs">video JPEG-2000 MJ2</comment>
<comment xml:lang="ca">vídeo JPEG-2000 MJ2</comment>
<comment xml:lang="bg">Видео — JPEG-2000 MJ2</comment>
+ <comment xml:lang="be">відэа JPEG-2000 MJ2</comment>
<comment xml:lang="ar">فيديو JPEG-2000 MJ2</comment>
<comment xml:lang="af">JPEG-2000 MJ2-video</comment>
<acronym>MJ2</acronym>
@@ -26769,6 +27957,31 @@ command to generate the output files.
</mime-type>
<mime-type type="image/jxl">
<comment>JPEG XL image</comment>
+ <comment xml:lang="zh_TW">JPEG XL 影像</comment>
+ <comment xml:lang="zh_CN">JPEG XL 图像</comment>
+ <comment xml:lang="uk">зображення JPEG XL</comment>
+ <comment xml:lang="tr">JPEG XL görüntüsü</comment>
+ <comment xml:lang="sv">JPEG XL-bild</comment>
+ <comment xml:lang="sl">Slika JPEG XL</comment>
+ <comment xml:lang="si">JPEG XL රූපය</comment>
+ <comment xml:lang="ru">Изображение JPEG XL</comment>
+ <comment xml:lang="pt_BR">Imagem JPEG XL</comment>
+ <comment xml:lang="pl">Obraz JPEG XL</comment>
+ <comment xml:lang="oc">imatge JPEG XL</comment>
+ <comment xml:lang="nl">JPEG XL-afbeelding</comment>
+ <comment xml:lang="ko">JPEG XL 그림</comment>
+ <comment xml:lang="kk">JPEG XL суреті</comment>
+ <comment xml:lang="ja">JPEG XL 画像 </comment>
+ <comment xml:lang="it">Immagine JPEG XL</comment>
+ <comment xml:lang="hr">JPEG XL slika</comment>
+ <comment xml:lang="gl">Imaxe JPEG XL</comment>
+ <comment xml:lang="fi">JPEG XL-kuva</comment>
+ <comment xml:lang="eu">JPEG XL irudia</comment>
+ <comment xml:lang="es">imagen JPEG XL</comment>
+ <comment xml:lang="en_GB">JPEG XL image</comment>
+ <comment xml:lang="de">JPEG-XL-Bild</comment>
+ <comment xml:lang="be">выява JPEG XL</comment>
+ <comment xml:lang="ar">صورة JPEG XL</comment>
<magic>
<match type="string" offset="0" value="\xFF\x0A"/>
<match type="string" offset="0" value="\0\0\0\x0CJXL \x0D\x0A\x87\x0A"/>
@@ -26782,19 +27995,25 @@ command to generate the output files.
<comment xml:lang="uk">зображення OpenRaster</comment>
<comment xml:lang="tr">OpenRaster görüntüsü</comment>
<comment xml:lang="sv">OpenRaster-bild</comment>
+ <comment xml:lang="sq">figurë OpenRaster</comment>
<comment xml:lang="sl">Slika OpenRaster</comment>
+ <comment xml:lang="si">OpenRaster රූපය</comment>
<comment xml:lang="sk">Obrázok OpenRaster</comment>
<comment xml:lang="ru">Изображение OpenRaster</comment>
<comment xml:lang="pt_BR">Imagem OpenRaster</comment>
<comment xml:lang="pl">Obraz OpenRaster</comment>
+ <comment xml:lang="oc">imatge OpenRaster</comment>
+ <comment xml:lang="nl">OpenRaster-afbeelding</comment>
<comment xml:lang="ko">OpenRaster 그림</comment>
<comment xml:lang="kk">OpenRaster суреті</comment>
<comment xml:lang="ja">OpenRaster 画像</comment>
<comment xml:lang="it">Immagine OpenRaster</comment>
+ <comment xml:lang="is">OpenRaster-mynd</comment>
<comment xml:lang="id">Citra OpenRaster</comment>
<comment xml:lang="hu">OpenRaster kép</comment>
<comment xml:lang="hr">OpenRaster slika</comment>
<comment xml:lang="he">תמונת OpenRaster</comment>
+ <comment xml:lang="gl">Imaxe OpenRaster</comment>
<comment xml:lang="fr">image OpenRaster</comment>
<comment xml:lang="fi">OpenRaster-kuva</comment>
<comment xml:lang="eu">OpenRaster irudia</comment>
@@ -26804,6 +28023,7 @@ command to generate the output files.
<comment xml:lang="da">OpenRaster-billede</comment>
<comment xml:lang="ca">imatge OpenRaster</comment>
<comment xml:lang="bg">Изображение — OpenRaster</comment>
+ <comment xml:lang="be">выява OpenRaster</comment>
<comment xml:lang="ar">صورة OpenRaster</comment>
<sub-class-of type="application/zip"/>
<magic priority="70">
@@ -26824,8 +28044,9 @@ command to generate the output files.
<comment xml:lang="tr">DirectDraw yüzeyi</comment>
<comment xml:lang="sv">DirectDraw-yta</comment>
<comment xml:lang="sr">Директ Дров површина</comment>
- <comment xml:lang="sq">Superfaqe DirectDraw</comment>
+ <comment xml:lang="sq">sipërfaqe DirectDraw</comment>
<comment xml:lang="sl">Datoteka predmeta DirectDraw</comment>
+ <comment xml:lang="si">DirectDraw මතුපිට</comment>
<comment xml:lang="sk">Plocha DirectDraw</comment>
<comment xml:lang="ru">Плоскость DirectDraw</comment>
<comment xml:lang="ro">Suprafață DirectDraw</comment>
@@ -26843,6 +28064,7 @@ command to generate the output files.
<comment xml:lang="ka">DirectDraw-ის ზედაპირი</comment>
<comment xml:lang="ja">DirectDraw サーフェイス</comment>
<comment xml:lang="it">Superficie DirectDraw</comment>
+ <comment xml:lang="is">DirectDraw yfirborðsupplýsingar</comment>
<comment xml:lang="id">Permukaan DirectDraw</comment>
<comment xml:lang="ia">Superficie DirectDraw</comment>
<comment xml:lang="hu">DirectDraw felület</comment>
@@ -26864,6 +28086,7 @@ command to generate the output files.
<comment xml:lang="ca">superfície DirectDraw</comment>
<comment xml:lang="bg">Изображение — повърхност на DirectDraw</comment>
<comment xml:lang="be@latin">Pavierchnia DirectDraw</comment>
+ <comment xml:lang="be">паверхня DirectDraw</comment>
<comment xml:lang="ar">سطح DirectDraw</comment>
<magic>
<match value="DDS" type="string" offset="0"/>
@@ -26879,8 +28102,9 @@ command to generate the output files.
<comment xml:lang="tr">X11 imleci</comment>
<comment xml:lang="sv">X11-muspekare</comment>
<comment xml:lang="sr">Икс11 курсор</comment>
- <comment xml:lang="sq">Kursor X11</comment>
+ <comment xml:lang="sq">kursor X11</comment>
<comment xml:lang="sl">Datoteka kazalke X11</comment>
+ <comment xml:lang="si">X11 කර්සරය</comment>
<comment xml:lang="sk">Kurzor X11</comment>
<comment xml:lang="ru">Курсор X11</comment>
<comment xml:lang="ro">Cursor X11</comment>
@@ -26897,6 +28121,7 @@ command to generate the output files.
<comment xml:lang="kk">X11 курсоры</comment>
<comment xml:lang="ja">X11 カーソル</comment>
<comment xml:lang="it">Cursore X11</comment>
+ <comment xml:lang="is">X11 bendill</comment>
<comment xml:lang="id">Kursor X11</comment>
<comment xml:lang="ia">Cursor X11</comment>
<comment xml:lang="hu">X11 kurzor</comment>
@@ -26912,12 +28137,13 @@ command to generate the output files.
<comment xml:lang="es">cursor de X11</comment>
<comment xml:lang="en_GB">X11 cursor</comment>
<comment xml:lang="el">Δρομέας X11</comment>
- <comment xml:lang="de">X11-Zeiger</comment>
+ <comment xml:lang="de">X11-Mauszeiger</comment>
<comment xml:lang="da">X11-markør</comment>
<comment xml:lang="cs">kurzor X11</comment>
<comment xml:lang="ca">cursor de X11</comment>
<comment xml:lang="bg">Курсор — X11</comment>
<comment xml:lang="be@latin">Kursor X11</comment>
+ <comment xml:lang="be">курсор X11</comment>
<comment xml:lang="ar">مؤشر X11</comment>
<comment xml:lang="af">X11-wyser</comment>
<magic>
@@ -26933,8 +28159,9 @@ command to generate the output files.
<comment xml:lang="tr">EXR görüntüsü</comment>
<comment xml:lang="sv">EXR-bild</comment>
<comment xml:lang="sr">ЕИксР слика</comment>
- <comment xml:lang="sq">Figurë EXR</comment>
+ <comment xml:lang="sq">figurë EXR</comment>
<comment xml:lang="sl">Slikovna datoteka EXR</comment>
+ <comment xml:lang="si">EXR රූපය</comment>
<comment xml:lang="sk">Obrázok EXR</comment>
<comment xml:lang="ru">Изображение EXR</comment>
<comment xml:lang="ro">Imagine EXR</comment>
@@ -26952,6 +28179,7 @@ command to generate the output files.
<comment xml:lang="ka">EXR გამოსახულება</comment>
<comment xml:lang="ja">EXR 画像</comment>
<comment xml:lang="it">Immagine EXR</comment>
+ <comment xml:lang="is">EXR mynd</comment>
<comment xml:lang="id">Citra EXR</comment>
<comment xml:lang="ia">Imagine EXR</comment>
<comment xml:lang="hu">EXR kép</comment>
@@ -26974,6 +28202,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge EXR</comment>
<comment xml:lang="bg">Изображение — EXR</comment>
<comment xml:lang="be@latin">Vyjava EXR</comment>
+ <comment xml:lang="be">выява EXR</comment>
<comment xml:lang="ar">صورة EXR</comment>
<comment xml:lang="af">EXR-beeld</comment>
<magic>
@@ -26990,8 +28219,9 @@ command to generate the output files.
<comment xml:lang="tr">Macintosh Quickdraw/PICT çizimi</comment>
<comment xml:lang="sv">Macintosh Quickdraw/PICT-teckning</comment>
<comment xml:lang="sr">Мекинтошов Квикдров/ПИЦТ цртеж</comment>
- <comment xml:lang="sq">Vizatim Macintosh Quickdraw/PICT</comment>
+ <comment xml:lang="sq">vizatim Macintosh Quickdraw/PICT</comment>
<comment xml:lang="sl">Datoteka risbe Macintosh Quickdraw/PICT</comment>
+ <comment xml:lang="si">Macintosh Quickdraw/PICT ඇඳීම</comment>
<comment xml:lang="sk">Kresba Macintosh QuickDraw/PICT</comment>
<comment xml:lang="ru">Рисунок Macintosh Quickdraw/PICT</comment>
<comment xml:lang="ro">Desen Macintosh Quickdraw/PICT</comment>
@@ -27009,6 +28239,7 @@ command to generate the output files.
<comment xml:lang="kk">Macintosh Quickdraw/PICT суреті</comment>
<comment xml:lang="ja">Macintosh Quickdraw/PICT ドロー</comment>
<comment xml:lang="it">Disegno Macintosh Quickdraw/PICT</comment>
+ <comment xml:lang="is">Macintosh Quickdraw/PICT teikning</comment>
<comment xml:lang="id">Gambar Macintosh Quickdraw/PICT</comment>
<comment xml:lang="ia">Designo QuickDraw/PICT de Macintosh</comment>
<comment xml:lang="hu">Macintosh Quickdraw/PICT-rajz</comment>
@@ -27031,6 +28262,7 @@ command to generate the output files.
<comment xml:lang="ca">dibuix Quickdraw/PICT de Macintosh</comment>
<comment xml:lang="bg">Чертеж — Macintosh Quickdraw/PICT</comment>
<comment xml:lang="be@latin">Rysunak Macintosh Quickdraw/PICT</comment>
+ <comment xml:lang="be">рысунак Macintosh Quickdraw/PICT</comment>
<comment xml:lang="ar">رسمة ماكنتوش Quickdraw/PICT</comment>
<comment xml:lang="af">Macintosh Quickdraw/PICT-tekening</comment>
<magic>
@@ -27065,8 +28297,9 @@ command to generate the output files.
<comment xml:lang="tr">UFRaw ID görüntüsü</comment>
<comment xml:lang="sv">UFRaw ID-bild</comment>
<comment xml:lang="sr">УФ сирова ИД слика</comment>
- <comment xml:lang="sq">Figurë UFRaw ID</comment>
+ <comment xml:lang="sq">figurë UFRaw ID</comment>
<comment xml:lang="sl">Slikovna datoteka UFRaw ID</comment>
+ <comment xml:lang="si">UFRaw ID රූපය</comment>
<comment xml:lang="sk">Obrázok ID UFRaw</comment>
<comment xml:lang="ru">Изображение UFRaw ID</comment>
<comment xml:lang="ro">ID imagine UFRaw</comment>
@@ -27083,6 +28316,7 @@ command to generate the output files.
<comment xml:lang="kk">UFRaw ID суреті</comment>
<comment xml:lang="ja">UFRaw ID イメージ</comment>
<comment xml:lang="it">Immagine UFRaw ID</comment>
+ <comment xml:lang="is">UFRaw ID mynd</comment>
<comment xml:lang="id">Citra UFRaw ID</comment>
<comment xml:lang="ia">Imagine UFRaw ID</comment>
<comment xml:lang="hu">UFRaw azonosítófájl</comment>
@@ -27104,6 +28338,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge ID UFRaw</comment>
<comment xml:lang="bg">Изображение — UFRaw ID</comment>
<comment xml:lang="be@latin">Vyjava UFRaw ID</comment>
+ <comment xml:lang="be">выява UFRaw ID</comment>
<comment xml:lang="ar">صورة UFRaw ID</comment>
<comment xml:lang="af">UFRaw ID-beeld</comment>
<acronym>UFRaw</acronym>
@@ -27113,55 +28348,18 @@ command to generate the output files.
<glob pattern="*.ufraw"/>
</mime-type>
<mime-type type="image/x-dcraw">
- <comment>digital raw image</comment>
- <comment xml:lang="zh_TW">數位原始影像</comment>
- <comment xml:lang="zh_CN">数字化原始图像</comment>
- <comment xml:lang="vi">ảnh thô số</comment>
- <comment xml:lang="uk">зображення цифрового негатива</comment>
- <comment xml:lang="tr">sayısal ham görüntü</comment>
- <comment xml:lang="sv">digital råbild</comment>
- <comment xml:lang="sr">дигитална сирова слика</comment>
- <comment xml:lang="sq">Figurë raw dixhitale</comment>
- <comment xml:lang="sl">surova digitalna slika</comment>
- <comment xml:lang="sk">Digitálny surový obrázok</comment>
+ <comment>Digital raw image</comment>
+ <comment xml:lang="uk">простий цифровий негатив</comment>
+ <comment xml:lang="sv">Digital råbild</comment>
<comment xml:lang="ru">Необработанное цифровое изображение</comment>
- <comment xml:lang="ro">imagine digitală brută</comment>
- <comment xml:lang="pt_BR">Imagem digital bruta</comment>
- <comment xml:lang="pt">imagem digital em bruto</comment>
<comment xml:lang="pl">Surowy obraz cyfrowy</comment>
- <comment xml:lang="oc">imatge brut numeric</comment>
- <comment xml:lang="nn">digitalt råbilete</comment>
- <comment xml:lang="nl">onbewerkt digitaal beeld</comment>
- <comment xml:lang="nb">digitalt raw-bilde</comment>
- <comment xml:lang="lv">digitāls jēlattēls</comment>
- <comment xml:lang="lt">skaitmeninis neapdorotas paveikslėlis</comment>
- <comment xml:lang="ko">디지털 원본 사진</comment>
- <comment xml:lang="kk">өңделмеген сандық суреттер</comment>
- <comment xml:lang="ja">デジタル raw 画像</comment>
+ <comment xml:lang="ja">生写真</comment>
<comment xml:lang="it">Immagine raw digitale</comment>
- <comment xml:lang="id">citra mentah digital</comment>
- <comment xml:lang="ia">Imagine brute digital</comment>
- <comment xml:lang="hu">digitális nyers kép</comment>
- <comment xml:lang="hr">Digitalna osnovna slika</comment>
- <comment xml:lang="he">תמונה דיגטלית גולמית</comment>
- <comment xml:lang="gl">imaxe en bruto dixital</comment>
- <comment xml:lang="ga">amhíomhá dhigiteach</comment>
- <comment xml:lang="fur">imagjin grese digjitâl</comment>
- <comment xml:lang="fr">image brute numérique</comment>
- <comment xml:lang="fo">talgild rámynd</comment>
- <comment xml:lang="fi">digitaalinen raakakuva</comment>
- <comment xml:lang="eu">irudi gordin digitala</comment>
+ <comment xml:lang="gl">Imaxe RAW dixital</comment>
+ <comment xml:lang="eu">Irudi digital gordina</comment>
<comment xml:lang="es">imagen digital en bruto</comment>
- <comment xml:lang="en_GB">digital raw image</comment>
- <comment xml:lang="el">Ανεπεξέργαστη ψηφιακή εικόνα</comment>
<comment xml:lang="de">Digitales Rohbild</comment>
- <comment xml:lang="da">digitalt raw-billede</comment>
- <comment xml:lang="cs">digitální surový obrázek</comment>
- <comment xml:lang="ca">imatge digital en cru</comment>
- <comment xml:lang="bg">Изображение — digital raw</comment>
- <comment xml:lang="be@latin">suvoraja ličbavaja vyjava</comment>
- <comment xml:lang="ar">صورة رقمية خامة</comment>
- <comment xml:lang="af">digitale rou beeld</comment>
+ <comment xml:lang="be">неапрацаваная лічбавая выява</comment>
</mime-type>
<mime-type type="image/x-adobe-dng">
<comment>Adobe DNG negative</comment>
@@ -27172,8 +28370,9 @@ command to generate the output files.
<comment xml:lang="tr">Adobe DNG negatifi</comment>
<comment xml:lang="sv">Adobe DNG-negativ</comment>
<comment xml:lang="sr">Адобов ДНГ негатив</comment>
- <comment xml:lang="sq">Negativ Adobe DNG</comment>
+ <comment xml:lang="sq">negativ Adobe DNG</comment>
<comment xml:lang="sl">Datoteka negativa Adobe DNG</comment>
+ <comment xml:lang="si">Adobe DNG සෘණ</comment>
<comment xml:lang="sk">Adobe Digital Negative (DNG)</comment>
<comment xml:lang="ru">Негатив Adobe DNG</comment>
<comment xml:lang="ro">Negativ Adobe DNG</comment>
@@ -27191,6 +28390,7 @@ command to generate the output files.
<comment xml:lang="ka">Adobe DNG-ის ნეგატივი</comment>
<comment xml:lang="ja">Adobe DNG ネガ</comment>
<comment xml:lang="it">Negativo Adobe DNG</comment>
+ <comment xml:lang="is">Adobe DNG negatíva</comment>
<comment xml:lang="id">Negatif Adobe DNG</comment>
<comment xml:lang="ia">Negativo Adobe DNG</comment>
<comment xml:lang="hu">Adobe DNG negatív</comment>
@@ -27212,6 +28412,7 @@ command to generate the output files.
<comment xml:lang="ca">negatiu DNG d'Adobe</comment>
<comment xml:lang="bg">Изображение — Adobe DNG negative</comment>
<comment xml:lang="be@latin">Adobe DNG Negative</comment>
+ <comment xml:lang="be">Adobe DNG Negative</comment>
<comment xml:lang="ar">سالبة Adobe DNG</comment>
<comment xml:lang="af">Adobe DNG-negatief</comment>
<acronym>DNG</acronym>
@@ -27231,8 +28432,9 @@ command to generate the output files.
<comment xml:lang="tr">Canon CRW ham görüntüsü</comment>
<comment xml:lang="sv">Canon CRW-råbild</comment>
<comment xml:lang="sr">Кенон ЦРВ сирова слика</comment>
- <comment xml:lang="sq">Figurë raw Canon CRW</comment>
+ <comment xml:lang="sq">figurë Canon CRW e papërpunuar</comment>
<comment xml:lang="sl">Surova slikovna datoteka Canon CRW</comment>
+ <comment xml:lang="si">Canon CRW අමු රූපය</comment>
<comment xml:lang="sk">Surový obrázok Canon CRW</comment>
<comment xml:lang="ru">Необработанное изображение Canon CRW</comment>
<comment xml:lang="ro">Imagine brută Canon CRW</comment>
@@ -27250,6 +28452,7 @@ command to generate the output files.
<comment xml:lang="ka">Canon CRW raw გამოსახულება</comment>
<comment xml:lang="ja">Canon CRW raw 画像</comment>
<comment xml:lang="it">Immagine raw Canon CRW</comment>
+ <comment xml:lang="is">Canon CRW hrámynd</comment>
<comment xml:lang="id">Citra mentah Canon CRW</comment>
<comment xml:lang="ia">Imagine brute CRW Canon</comment>
<comment xml:lang="hu">Canon CRW nyers kép</comment>
@@ -27271,6 +28474,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge en cru de Canon CRW</comment>
<comment xml:lang="bg">Изображение — Canon CRW raw</comment>
<comment xml:lang="be@latin">Suvoraja vyjava Canon CRW</comment>
+ <comment xml:lang="be">неапрацаваная выява Canon CRW</comment>
<comment xml:lang="ar">صورة Canon CRW خامة</comment>
<comment xml:lang="af">Canon CRW rou beeld</comment>
<acronym>CRW</acronym>
@@ -27291,8 +28495,9 @@ command to generate the output files.
<comment xml:lang="tr">Canon CR2 ham görüntüsü</comment>
<comment xml:lang="sv">Canon CR2-råbild</comment>
<comment xml:lang="sr">Кенон ЦР2 сирова слика</comment>
- <comment xml:lang="sq">Figurë raw Canon CR2</comment>
+ <comment xml:lang="sq">figurë Canon CR2 e papërpunuar</comment>
<comment xml:lang="sl">Surova slikovna datoteka Canon CR2</comment>
+ <comment xml:lang="si">Canon CR2 අමු රූපය</comment>
<comment xml:lang="sk">Surový obrázok Canon CR2</comment>
<comment xml:lang="ru">Необработанное изображение Canon CR2</comment>
<comment xml:lang="ro">Imagine brută Canon CR2</comment>
@@ -27310,6 +28515,7 @@ command to generate the output files.
<comment xml:lang="ka">Canon CR2 raw გამოსახულება</comment>
<comment xml:lang="ja">Canon CR2 raw 画像</comment>
<comment xml:lang="it">Immagine raw Canon CR2</comment>
+ <comment xml:lang="is">Canon CR2 hrámynd</comment>
<comment xml:lang="id">Citra mentah Canon CR2</comment>
<comment xml:lang="ia">Imagine brute CR2 Canon</comment>
<comment xml:lang="hu">Canon CR2 nyers kép</comment>
@@ -27331,6 +28537,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge en cru de Canon CR2</comment>
<comment xml:lang="bg">Изображение — Canon CR2 raw</comment>
<comment xml:lang="be@latin">Suvoraja vyjava Canon CR2</comment>
+ <comment xml:lang="be">неапрацаваная выява Canon CR2</comment>
<comment xml:lang="ar">صورة Canon CR2 خامة</comment>
<comment xml:lang="af">Canon CR2 rou beeld</comment>
<acronym>CR2</acronym>
@@ -27341,6 +28548,31 @@ command to generate the output files.
</mime-type>
<mime-type type="image/x-canon-cr3">
<comment>Canon CR3 raw image</comment>
+ <comment xml:lang="zh_TW">Canon CR3 原始影像</comment>
+ <comment xml:lang="zh_CN">佳能 CR3 原始图像</comment>
+ <comment xml:lang="uk">цифровий негатив CR3 Canon</comment>
+ <comment xml:lang="tr">Canon CR3 ham görüntüsü</comment>
+ <comment xml:lang="sv">Canon CR3-råbild</comment>
+ <comment xml:lang="sl">Neobdelana slika Canon CR3</comment>
+ <comment xml:lang="si">Canon CR3 අමු රූපය</comment>
+ <comment xml:lang="ru">Необработанное изображение Canon CR3</comment>
+ <comment xml:lang="pt_BR">Imagem bruta CR3 da Canon</comment>
+ <comment xml:lang="pl">Surowy obraz CR3 Canon</comment>
+ <comment xml:lang="oc">imatge brut Canon CR3</comment>
+ <comment xml:lang="nl">onbewerkt Canon CR3 beeld</comment>
+ <comment xml:lang="ko">캐논 CR3 RAW 사진</comment>
+ <comment xml:lang="kk">Canon CR3 өңделмеген суреті</comment>
+ <comment xml:lang="ja">Canon CR3 raw 画像ファイル</comment>
+ <comment xml:lang="it">Immagine raw Canon CR3</comment>
+ <comment xml:lang="hr">Canon CR3 osnovna slika</comment>
+ <comment xml:lang="gl">Imaxe RAW de Canon CR3</comment>
+ <comment xml:lang="fi">Canon CR3-raakakuva</comment>
+ <comment xml:lang="eu">Canon CR3 irudi gordina</comment>
+ <comment xml:lang="es">imagen en bruto CR3 de Canon</comment>
+ <comment xml:lang="en_GB">Canon CR3 raw image</comment>
+ <comment xml:lang="de">Canon-CR3-Rohbild</comment>
+ <comment xml:lang="be">неапрацаваная выява Canon CR3</comment>
+ <comment xml:lang="ar">صورة Canon CR3 خامة</comment>
<acronym>CR3</acronym>
<expanded-acronym>Canon Raw 3</expanded-acronym>
<sub-class-of type="image/x-dcraw"/>
@@ -27355,8 +28587,9 @@ command to generate the output files.
<comment xml:lang="tr">Fuji RAF ham görüntüsü</comment>
<comment xml:lang="sv">Fuji RAF-råbild</comment>
<comment xml:lang="sr">Фуџи РАФ сирова слика</comment>
- <comment xml:lang="sq">Figurë raw Fuji RAF</comment>
+ <comment xml:lang="sq">figurë Fuji RAF e papërpunuar</comment>
<comment xml:lang="sl">Surova slikovna datoteka Fuji RAF</comment>
+ <comment xml:lang="si">Fuji RAF අමු රූපය</comment>
<comment xml:lang="sk">Surový obrázok Fuji RAF</comment>
<comment xml:lang="ru">Необработанное изображение Fuji RAF</comment>
<comment xml:lang="ro">Imagine brută Fuji RAF</comment>
@@ -27374,6 +28607,7 @@ command to generate the output files.
<comment xml:lang="ka">Fuji RAF-ის raw გამოსახულება</comment>
<comment xml:lang="ja">Fuji RAF raw 画像</comment>
<comment xml:lang="it">Immagine raw Fuji RAF</comment>
+ <comment xml:lang="is">Fuji RAF hrámynd</comment>
<comment xml:lang="id">Citra mentah Fuji RAF</comment>
<comment xml:lang="ia">Imagine brute RAF de Fuji</comment>
<comment xml:lang="hu">Fuji RAF nyers kép</comment>
@@ -27395,6 +28629,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge en cru de Fuji RAF</comment>
<comment xml:lang="bg">Изображение — Fuji RAF raw</comment>
<comment xml:lang="be@latin">Suvoraja vyjava Fuji RAF</comment>
+ <comment xml:lang="be">неапрацаваная выява Fuji RAF</comment>
<comment xml:lang="ar">صورة Fuji RAF خامة</comment>
<comment xml:lang="af">Fuji RAF rou beeld</comment>
<acronym>RAF</acronym>
@@ -27414,8 +28649,9 @@ command to generate the output files.
<comment xml:lang="tr">Kodak DCR ham görüntüsü</comment>
<comment xml:lang="sv">Kodak DCR-råbild</comment>
<comment xml:lang="sr">Кодак ДЦР сирова слика</comment>
- <comment xml:lang="sq">Figurë raw Kodak DCR</comment>
+ <comment xml:lang="sq">figurë Kodak DCR e papërpunuar</comment>
<comment xml:lang="sl">Surova slikovna datoteka Kodak DCR</comment>
+ <comment xml:lang="si">Kodak DCR අමු රූපය</comment>
<comment xml:lang="sk">Surový obrázok Kodak DCR</comment>
<comment xml:lang="ru">Необработанное изображение Kodak DCR</comment>
<comment xml:lang="ro">Imagine brută Kodak DCR</comment>
@@ -27432,6 +28668,7 @@ command to generate the output files.
<comment xml:lang="kk">Kodak DCR өңделмеген суреті</comment>
<comment xml:lang="ja">Kodak DCR raw 画像</comment>
<comment xml:lang="it">Immagine raw Kodak DCR</comment>
+ <comment xml:lang="is">Kodak DCR hrámynd</comment>
<comment xml:lang="id">Citra mentah Kodak DCR</comment>
<comment xml:lang="ia">Imagine brute DCR de Kodak</comment>
<comment xml:lang="hu">Kodak DCR nyers kép</comment>
@@ -27453,6 +28690,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge en cru de Kodak DCR</comment>
<comment xml:lang="bg">Изображение — Kodak DCR raw</comment>
<comment xml:lang="be@latin">Suvoraja vyjava Kodak DCR</comment>
+ <comment xml:lang="be">неапрацаваная выява Kodak DCR</comment>
<comment xml:lang="ar">صورة Kodak DCR خامة</comment>
<comment xml:lang="af">Kodak DCR rou beeld</comment>
<acronym>DCR</acronym>
@@ -27470,8 +28708,9 @@ command to generate the output files.
<comment xml:lang="tr">Kodak K25 ham görüntüsü</comment>
<comment xml:lang="sv">Kodak K25-råbild</comment>
<comment xml:lang="sr">Кодак К25 сирова слика</comment>
- <comment xml:lang="sq">Figurë raw Kodak K25</comment>
+ <comment xml:lang="sq">figurë Kodak K25 e papërpunuar</comment>
<comment xml:lang="sl">Surova slikovna datoteka Kodak K25</comment>
+ <comment xml:lang="si">Kodak K25 අමු රූපය</comment>
<comment xml:lang="sk">Surový obrázok Kodak K25</comment>
<comment xml:lang="ru">Необработанное изображение Kodak K25</comment>
<comment xml:lang="ro">Imagine brută Kodak K25</comment>
@@ -27488,6 +28727,7 @@ command to generate the output files.
<comment xml:lang="kk">Kodak K25 өңделмеген суреті</comment>
<comment xml:lang="ja">Kodak K25 raw 画像</comment>
<comment xml:lang="it">Immagine raw Kodak K25</comment>
+ <comment xml:lang="is">Kodak K25 hrámynd</comment>
<comment xml:lang="id">Citra mentah Kodak K25</comment>
<comment xml:lang="ia">Imagine brute K25 de Kodak</comment>
<comment xml:lang="hu">Kodak K25 nyers kép</comment>
@@ -27509,6 +28749,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge en cru de Kodak K25</comment>
<comment xml:lang="bg">Изображение — Kodak K25 raw</comment>
<comment xml:lang="be@latin">Suvoraja vyjava Kodak K25</comment>
+ <comment xml:lang="be">неапрацаваная выява Kodak K25</comment>
<comment xml:lang="ar">صورة Kodak K25 خامة</comment>
<comment xml:lang="af">Kodak K25 rou beeld</comment>
<acronym>K25</acronym>
@@ -27526,8 +28767,9 @@ command to generate the output files.
<comment xml:lang="tr">Kodak KDC ham görüntüsü</comment>
<comment xml:lang="sv">Kodak KDC-råbild</comment>
<comment xml:lang="sr">Кодак КДЦ сирова слика</comment>
- <comment xml:lang="sq">Figurë raw Kodak KDC</comment>
+ <comment xml:lang="sq">figurë Kodak KDC e papërpunuar</comment>
<comment xml:lang="sl">Surova slikovna datoteka Kodak KDC</comment>
+ <comment xml:lang="si">Kodak KDC අමු රූපය</comment>
<comment xml:lang="sk">Surový obrázok Kodak KDC</comment>
<comment xml:lang="ru">Необработанное изображение Kodak KDC</comment>
<comment xml:lang="ro">Imagine brută Kodak KDC</comment>
@@ -27544,6 +28786,7 @@ command to generate the output files.
<comment xml:lang="kk">Kodak KDC өңделмеген суреті</comment>
<comment xml:lang="ja">Kodak KDC raw 画像</comment>
<comment xml:lang="it">Immagine raw Kodak KDC</comment>
+ <comment xml:lang="is">Kodak KDC hrámynd</comment>
<comment xml:lang="id">Citra mentah Kodak KDC</comment>
<comment xml:lang="ia">Imagine brute KDC de Kodak</comment>
<comment xml:lang="hu">Kodak KDC nyers kép</comment>
@@ -27565,6 +28808,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge en cru de Kodak KDC</comment>
<comment xml:lang="bg">Изображение — Kodak KDC raw</comment>
<comment xml:lang="be@latin">Suvoraja vyjava Kodak KDC</comment>
+ <comment xml:lang="be">неапрацаваная выява Kodak KDC</comment>
<comment xml:lang="ar">صورة Kodak KDC خامة</comment>
<comment xml:lang="af">Kodak KDC rou beeld</comment>
<acronym>KDC</acronym>
@@ -27585,8 +28829,9 @@ command to generate the output files.
<comment xml:lang="tr">Minolta MRW ham görüntüsü</comment>
<comment xml:lang="sv">Minolta MRW-råbild</comment>
<comment xml:lang="sr">Минолта МРВ сирова слика</comment>
- <comment xml:lang="sq">Figurë raw Minolta MRW</comment>
+ <comment xml:lang="sq">figurë Minolta MRW e papërpunuar</comment>
<comment xml:lang="sl">Surova slikovna datoteka Minolta MRW</comment>
+ <comment xml:lang="si">Minolta MRW අමු රූපය</comment>
<comment xml:lang="sk">Surový obrázok Minolta MRW</comment>
<comment xml:lang="ru">Необработанное изображение Minolta MRW</comment>
<comment xml:lang="ro">Imagine brută Minolta MRW</comment>
@@ -27603,6 +28848,7 @@ command to generate the output files.
<comment xml:lang="kk">Minolta MRW өңделмеген суреті</comment>
<comment xml:lang="ja">Minolta MRW raw 画像</comment>
<comment xml:lang="it">Immagine raw Minolta MRW</comment>
+ <comment xml:lang="is">Minolta MRW hrámynd</comment>
<comment xml:lang="id">Citra mentah Minolta MRW</comment>
<comment xml:lang="ia">Imagine brute Minolta MRW</comment>
<comment xml:lang="hu">Minolta MRW nyers kép</comment>
@@ -27624,6 +28870,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge en cru de Minolta MRW</comment>
<comment xml:lang="bg">Изображение — Minolta MRW raw</comment>
<comment xml:lang="be@latin">Suvoraja vyjava Minolta MRW</comment>
+ <comment xml:lang="be">неапрацаваная выява Minolta MRW</comment>
<comment xml:lang="ar">صورة Minolta MRW خامة</comment>
<comment xml:lang="af">Minolta MRW rou beeld</comment>
<acronym>MRW</acronym>
@@ -27643,8 +28890,9 @@ command to generate the output files.
<comment xml:lang="tr">Nikon NEF ham görüntüsü</comment>
<comment xml:lang="sv">Nikon NEF-råbild</comment>
<comment xml:lang="sr">Никон НЕФ сирова слика</comment>
- <comment xml:lang="sq">Figurë raw Nikon NEF</comment>
+ <comment xml:lang="sq">figurë Nikon NEF e papërpunuar</comment>
<comment xml:lang="sl">Surova slikovna datoteka Nikon NEF</comment>
+ <comment xml:lang="si">Nikon NEF අමු රූපය</comment>
<comment xml:lang="sk">Surový obrázok Nikon NEF</comment>
<comment xml:lang="ru">Необработанное изображение Nikon NEF</comment>
<comment xml:lang="ro">Imagine brută Nikon NEF</comment>
@@ -27661,6 +28909,7 @@ command to generate the output files.
<comment xml:lang="kk">Nikon NEF өңделмеген суреті</comment>
<comment xml:lang="ja">Nikon NEF raw イメージ</comment>
<comment xml:lang="it">Immagine raw Nikon NEF</comment>
+ <comment xml:lang="is">Nikon NEF hrámynd</comment>
<comment xml:lang="id">Citra mentah Nikon NEF</comment>
<comment xml:lang="ia">Imagine brute Nikon NEF</comment>
<comment xml:lang="hu">Nikon NEF nyers kép</comment>
@@ -27682,6 +28931,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge en cru de Nikon NEF</comment>
<comment xml:lang="bg">Изображение — Nikon NEF raw</comment>
<comment xml:lang="be@latin">Suvoraja vyjava Nikon NEF</comment>
+ <comment xml:lang="be">неапрацаваная выява Nikon NEF</comment>
<comment xml:lang="ar">صورة Nikon NEF خامة</comment>
<comment xml:lang="af">Nikon NEF rou beeld</comment>
<acronym>NEF</acronym>
@@ -27692,6 +28942,31 @@ command to generate the output files.
</mime-type>
<mime-type type="image/x-nikon-nrw">
<comment>Nikon NRW raw image</comment>
+ <comment xml:lang="zh_TW">Nikon NRW 原始影像</comment>
+ <comment xml:lang="zh_CN">尼康 NRW 原始图像</comment>
+ <comment xml:lang="uk">цифровий негатив NRW Nikon</comment>
+ <comment xml:lang="tr">Nikon NRW ham görüntüsü</comment>
+ <comment xml:lang="sv">Nikon NRW-råbild</comment>
+ <comment xml:lang="sl">Neobdelana slika NRW</comment>
+ <comment xml:lang="si">Nikon NRW අමු රූපය</comment>
+ <comment xml:lang="ru">Необработанное изображение Nikon NRW</comment>
+ <comment xml:lang="pt_BR">Imagem bruta NRW da Nikon</comment>
+ <comment xml:lang="pl">Surowy obraz NRW Nikon</comment>
+ <comment xml:lang="oc">imatge brut Nikon NRW</comment>
+ <comment xml:lang="nl">onbewerkt Nikon NRW beeld</comment>
+ <comment xml:lang="ko">니콘 NRW RAW 사진</comment>
+ <comment xml:lang="kk">Nikon NRW өңделмеген суреті</comment>
+ <comment xml:lang="ja">Nikon NRW raw 画像ファイル</comment>
+ <comment xml:lang="it">Immagine raw Nikon NRW</comment>
+ <comment xml:lang="hr">Nikon NRW osnovna slika</comment>
+ <comment xml:lang="gl">Imaxe RAW de Nikon NRW</comment>
+ <comment xml:lang="fi">Nikon-NRW-raakakuva</comment>
+ <comment xml:lang="eu">Nikon NRW irudi gordina</comment>
+ <comment xml:lang="es">imagen en bruto NRW de Nikon</comment>
+ <comment xml:lang="en_GB">Nikon NRW raw image</comment>
+ <comment xml:lang="de">Nikon-NRW-Rohbild</comment>
+ <comment xml:lang="be">неапрацаваная выява Nikon NRW</comment>
+ <comment xml:lang="ar">صورة Nikon NRW خامة</comment>
<sub-class-of type="image/x-dcraw"/>
<sub-class-of type="image/tiff"/>
<glob pattern="*.nrw"/>
@@ -27705,8 +28980,9 @@ command to generate the output files.
<comment xml:lang="tr">Olympus ORF ham görüntüsü</comment>
<comment xml:lang="sv">Olympus ORF-råbild</comment>
<comment xml:lang="sr">Олимпус ОРФ сирова слика</comment>
- <comment xml:lang="sq">Figurë raw Olympus ORF</comment>
+ <comment xml:lang="sq">figurë Olympus ORF e papërpunuar</comment>
<comment xml:lang="sl">Surova slikovna datoteka Olympus ORF</comment>
+ <comment xml:lang="si">Olympus ORF අමු රූපය</comment>
<comment xml:lang="sk">Surový obrázok Olympus ORF</comment>
<comment xml:lang="ru">Необработанное изображение Olympus ORF</comment>
<comment xml:lang="ro">Imagine brută Olympus ORF</comment>
@@ -27724,6 +29000,7 @@ command to generate the output files.
<comment xml:lang="ka">Olympus ORF-ის raw გამოსახულება</comment>
<comment xml:lang="ja">Olympus ORF raw 画像</comment>
<comment xml:lang="it">Immagine raw Olympus ORF</comment>
+ <comment xml:lang="is">Olympus ORF hrámynd</comment>
<comment xml:lang="id">Citra mentah Olympus ORF</comment>
<comment xml:lang="ia">Imagine brute Olympus ORF</comment>
<comment xml:lang="hu">Olympus ORF nyers kép</comment>
@@ -27745,6 +29022,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge en cru d'Olympus ORF</comment>
<comment xml:lang="bg">Изображение — Olympus ORF raw</comment>
<comment xml:lang="be@latin">Suvoraja vyjava Olympus ORF</comment>
+ <comment xml:lang="be">неапрацаваная выява Olympus ORF</comment>
<comment xml:lang="ar">صورة Olympus ORF خامة</comment>
<comment xml:lang="af">Olympus ORF rou beeld</comment>
<acronym>ORF</acronym>
@@ -27769,8 +29047,9 @@ command to generate the output files.
<comment xml:lang="tr">Panasonic ham görüntüsü</comment>
<comment xml:lang="sv">Panasonic-råbild</comment>
<comment xml:lang="sr">Панасоник сирова слика</comment>
- <comment xml:lang="sq">Figurë raw Panasonic</comment>
+ <comment xml:lang="sq">figurë Panasonic e papërpunuar</comment>
<comment xml:lang="sl">Surova slikovna datoteka Panasonic</comment>
+ <comment xml:lang="si">පැනසොනික් අමු රූපය</comment>
<comment xml:lang="sk">Surový obrázok Panasonic</comment>
<comment xml:lang="ru">Необработанное изображение Panasonic</comment>
<comment xml:lang="ro">Imagine brută Panasonic</comment>
@@ -27787,6 +29066,7 @@ command to generate the output files.
<comment xml:lang="kk">Panasonic өңделмеген суреті</comment>
<comment xml:lang="ja">Panasonic raw 画像</comment>
<comment xml:lang="it">Immagine raw Panasonic</comment>
+ <comment xml:lang="is">Panasonic hrámynd</comment>
<comment xml:lang="id">Citra mentah Panasonic</comment>
<comment xml:lang="ia">Imagine brute Panasonic</comment>
<comment xml:lang="hu">Panasonic nyers kép</comment>
@@ -27808,6 +29088,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge en cru de Panasonic</comment>
<comment xml:lang="bg">Изображение — Panasonic raw</comment>
<comment xml:lang="be@latin">Suvoraja vyjava Panasonic</comment>
+ <comment xml:lang="be">неапрацаваная выява Panasonic</comment>
<comment xml:lang="ar">صورة Panasonic خامة</comment>
<comment xml:lang="af">Panasonic rou beeld</comment>
<sub-class-of type="image/x-dcraw"/>
@@ -27827,8 +29108,9 @@ command to generate the output files.
<comment xml:lang="tr">Panasonic ham görüntüsü</comment>
<comment xml:lang="sv">Panasonic-råbild</comment>
<comment xml:lang="sr">Панасоник сирова слика</comment>
- <comment xml:lang="sq">Figurë raw Panasonic</comment>
+ <comment xml:lang="sq">figurë Panasonic e papërpunuar</comment>
<comment xml:lang="sl">Surova slikovna datoteka Panasonic</comment>
+ <comment xml:lang="si">පැනසොනික් අමු රූපය</comment>
<comment xml:lang="sk">Surový obrázok Panasonic</comment>
<comment xml:lang="ru">Необработанное изображение Panasonic</comment>
<comment xml:lang="ro">Imagine brută Panasonic</comment>
@@ -27845,6 +29127,7 @@ command to generate the output files.
<comment xml:lang="kk">Panasonic өңделмеген суреті</comment>
<comment xml:lang="ja">Panasonic raw 画像</comment>
<comment xml:lang="it">Immagine raw Panasonic</comment>
+ <comment xml:lang="is">Panasonic hrámynd</comment>
<comment xml:lang="id">Citra mentah Panasonic</comment>
<comment xml:lang="ia">Imagine brute Panasonic</comment>
<comment xml:lang="hu">Panasonic nyers kép</comment>
@@ -27866,6 +29149,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge en cru de Panasonic</comment>
<comment xml:lang="bg">Изображение — Panasonic raw</comment>
<comment xml:lang="be@latin">Suvoraja vyjava Panasonic</comment>
+ <comment xml:lang="be">неапрацаваная выява Panasonic</comment>
<comment xml:lang="ar">صورة Panasonic خامة</comment>
<comment xml:lang="af">Panasonic rou beeld</comment>
<sub-class-of type="image/x-dcraw"/>
@@ -27885,8 +29169,9 @@ command to generate the output files.
<comment xml:lang="tr">Pentax PEF ham görüntüsü</comment>
<comment xml:lang="sv">Pentax PEF-råbild</comment>
<comment xml:lang="sr">Пентакс ПЕФ сирова слика</comment>
- <comment xml:lang="sq">Figurë raw Pentax PEF</comment>
+ <comment xml:lang="sq">figurë Pentax PEF e papërpunuar</comment>
<comment xml:lang="sl">Surova slikovna datoteka Pentax PEF</comment>
+ <comment xml:lang="si">Pentax PEF අමු රූපය</comment>
<comment xml:lang="sk">Surový obrázok Pentax PEF</comment>
<comment xml:lang="ru">Необработанное изображение Pentax PEF</comment>
<comment xml:lang="ro">Imagine brută Pentax PEF</comment>
@@ -27903,6 +29188,7 @@ command to generate the output files.
<comment xml:lang="kk">Pentax PEF өңделмеген суреті</comment>
<comment xml:lang="ja">Pentax PEF raw 画像</comment>
<comment xml:lang="it">Immagine raw Pentax PEF</comment>
+ <comment xml:lang="is">Pentax PEF hrámynd</comment>
<comment xml:lang="id">Citra mentah Pentax PEF</comment>
<comment xml:lang="ia">Imagine brute Pentax PEF</comment>
<comment xml:lang="hu">Pentax PEF nyers kép</comment>
@@ -27924,6 +29210,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge en cru de Pentax PEF</comment>
<comment xml:lang="bg">Изображение — Pentax PEF raw</comment>
<comment xml:lang="be@latin">Suvoraja vyjava Pentax PEF</comment>
+ <comment xml:lang="be">неапрацаваная выява Pentax PEF</comment>
<comment xml:lang="ar">صورة Pentax PEF خامة</comment>
<comment xml:lang="af">Pentax PEF rou beeld</comment>
<acronym>PEF</acronym>
@@ -27941,8 +29228,9 @@ command to generate the output files.
<comment xml:lang="tr">Sigma X3F ham görüntüsü</comment>
<comment xml:lang="sv">Sigma X3F-råbild</comment>
<comment xml:lang="sr">Сигма Икс3Ф сирова слика</comment>
- <comment xml:lang="sq">Fifurë raw Sigma X3F</comment>
+ <comment xml:lang="sq">figurë Sigma X3F e papërpunuar</comment>
<comment xml:lang="sl">Surova slikovna datoteka Sigma X3F</comment>
+ <comment xml:lang="si">Sigma X3F අමු රූපය</comment>
<comment xml:lang="sk">Surový obrázok Sigma X3F</comment>
<comment xml:lang="ru">Необработанное изображение Sigma X3F</comment>
<comment xml:lang="ro">Imagine brută Sigma X3F</comment>
@@ -27959,6 +29247,7 @@ command to generate the output files.
<comment xml:lang="kk">Sigma X3F өңделмеген суреті</comment>
<comment xml:lang="ja">Sigma X3F raw 画像</comment>
<comment xml:lang="it">Immagine raw Sigma X3F</comment>
+ <comment xml:lang="is">Sigma X3F hrámynd</comment>
<comment xml:lang="id">Citra mentah Sigma X3F</comment>
<comment xml:lang="ia">Imagine brute Sigma X3F</comment>
<comment xml:lang="hu">Sigma XF3 nyers kép</comment>
@@ -27980,6 +29269,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge en cru de Sigma X3F</comment>
<comment xml:lang="bg">Изображение — Sigma X3F raw</comment>
<comment xml:lang="be@latin">Suvoraja vyjava Sigma X3F</comment>
+ <comment xml:lang="be">неапрацаваная выява Sigma X3F</comment>
<comment xml:lang="ar">صورة Sigma X3F خامة</comment>
<comment xml:lang="af">Sigma X3F rou beeld</comment>
<acronym>X3F</acronym>
@@ -28003,8 +29293,9 @@ command to generate the output files.
<comment xml:lang="tr">Sony SRF ham görüntüsü</comment>
<comment xml:lang="sv">Sony SRF-råbild</comment>
<comment xml:lang="sr">Сони СРФ сирова слика</comment>
- <comment xml:lang="sq">Figurë raw Sony SRF</comment>
+ <comment xml:lang="sq">figurë Sony SRF e papërpunuar</comment>
<comment xml:lang="sl">Surova slikovna datoteka Sony SRF</comment>
+ <comment xml:lang="si">Sony SRF අමු රූපය</comment>
<comment xml:lang="sk">Surový obrázok Sony SRF</comment>
<comment xml:lang="ru">Необработанное изображение Sony SRF</comment>
<comment xml:lang="ro">Imagine brută Sony SRF</comment>
@@ -28021,6 +29312,7 @@ command to generate the output files.
<comment xml:lang="kk">Sony SRF өңделмеген суреті</comment>
<comment xml:lang="ja">Sony SRF raw 画像</comment>
<comment xml:lang="it">Immagine raw Sony SRF</comment>
+ <comment xml:lang="is">Sony SRF hrámynd</comment>
<comment xml:lang="id">Citra mentah Sony SRF</comment>
<comment xml:lang="ia">Imagine brute Sony SRF</comment>
<comment xml:lang="hu">Sony SRF nyers kép</comment>
@@ -28042,6 +29334,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge en cru de Sony SRF</comment>
<comment xml:lang="bg">Изображение — Sony SRF raw</comment>
<comment xml:lang="be@latin">Suvoraja vyjava Sony SRF</comment>
+ <comment xml:lang="be">неапрацаваная выява Sony SRF</comment>
<comment xml:lang="ar">صورة Sony SRF خامة</comment>
<comment xml:lang="af">Sony SRF rou beeld</comment>
<acronym>SRF</acronym>
@@ -28059,8 +29352,9 @@ command to generate the output files.
<comment xml:lang="tr">Sony SR2 ham görüntüsü</comment>
<comment xml:lang="sv">Sony SR2-råbild</comment>
<comment xml:lang="sr">Сони СР2 сирова слика</comment>
- <comment xml:lang="sq">Figurë raw Sony SR2</comment>
+ <comment xml:lang="sq">figurë Sony SR2 e papërpunuar</comment>
<comment xml:lang="sl">Surova slikovna datoteka Sony SR2</comment>
+ <comment xml:lang="si">Sony SR2 අමු රූපය</comment>
<comment xml:lang="sk">Surový obrázok Sony SR2</comment>
<comment xml:lang="ru">Необработанное изображение Sony SR2</comment>
<comment xml:lang="ro">Imagine brută Sony SR2</comment>
@@ -28077,6 +29371,7 @@ command to generate the output files.
<comment xml:lang="kk">Sony SR2 өңделмеген суреті</comment>
<comment xml:lang="ja">Sony SR2 raw 画像</comment>
<comment xml:lang="it">Immagine raw Sony SR2</comment>
+ <comment xml:lang="is">Sony SR2 hrámynd</comment>
<comment xml:lang="id">Citra mentah Sony SR2</comment>
<comment xml:lang="ia">Imagine brute Sony SR2</comment>
<comment xml:lang="hu">Sony SR2 nyers kép</comment>
@@ -28098,6 +29393,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge en cru de Sony SR2</comment>
<comment xml:lang="bg">Изображение — Sony SR2 raw</comment>
<comment xml:lang="be@latin">Suvoraja vyjava Sony SR2</comment>
+ <comment xml:lang="be">неапрацаваная выява Sony SR2</comment>
<comment xml:lang="ar">صورة Sony SR2 خامة</comment>
<comment xml:lang="af">Sony SR2 rou beeld</comment>
<acronym>SR2</acronym>
@@ -28115,8 +29411,9 @@ command to generate the output files.
<comment xml:lang="tr">Sony ARW ham görüntüsü</comment>
<comment xml:lang="sv">Sony ARW-råbild</comment>
<comment xml:lang="sr">Сони АРВ сирова слика</comment>
- <comment xml:lang="sq">Figurë raw Sony ARW</comment>
+ <comment xml:lang="sq">figurë Sony ARW e papërpunuar</comment>
<comment xml:lang="sl">Surova slikovna datoteka Sony ARW</comment>
+ <comment xml:lang="si">Sony ARW අමු රූපය</comment>
<comment xml:lang="sk">Surový obrázok Sony ARW</comment>
<comment xml:lang="ru">Необработанное изображение Sony ARW</comment>
<comment xml:lang="ro">Imagine brută Sony ARW</comment>
@@ -28133,6 +29430,7 @@ command to generate the output files.
<comment xml:lang="kk">Sony ARW өңделмеген суреті</comment>
<comment xml:lang="ja">Sony ARW raw 画像</comment>
<comment xml:lang="it">Immagine raw Sony ARW</comment>
+ <comment xml:lang="is">Sony ARW hrámynd</comment>
<comment xml:lang="id">Citra mentah Sony ARW</comment>
<comment xml:lang="ia">Imagine brute Sony ARW</comment>
<comment xml:lang="hu">Sony ARW nyers kép</comment>
@@ -28154,6 +29452,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge en cru de Sony ARW</comment>
<comment xml:lang="bg">Изображение — Sony ARW raw</comment>
<comment xml:lang="be@latin">Suvoraja vyjava Sony ARW</comment>
+ <comment xml:lang="be">неапрацаваная выява Sony ARW</comment>
<comment xml:lang="ar">صورة Sony ARW خامة</comment>
<comment xml:lang="af">Sony ARW rou beeld</comment>
<acronym>ARW</acronym>
@@ -28171,8 +29470,9 @@ command to generate the output files.
<comment xml:lang="tr">PNG görüntüsü</comment>
<comment xml:lang="sv">PNG-bild</comment>
<comment xml:lang="sr">ПНГ слика</comment>
- <comment xml:lang="sq">Figurë PNG</comment>
+ <comment xml:lang="sq">figurë PNG</comment>
<comment xml:lang="sl">Slikovna datoteka PNG</comment>
+ <comment xml:lang="si">PNG රූපය</comment>
<comment xml:lang="sk">Obrázok PNG</comment>
<comment xml:lang="ru">Изображение PNG</comment>
<comment xml:lang="ro">Imagine PNG</comment>
@@ -28188,8 +29488,10 @@ command to generate the output files.
<comment xml:lang="lt">PNG paveikslėlis</comment>
<comment xml:lang="ko">PNG 그림</comment>
<comment xml:lang="kk">PNG суреті</comment>
+ <comment xml:lang="ka">PNG გამოსახულება</comment>
<comment xml:lang="ja">PNG 画像</comment>
<comment xml:lang="it">Immagine PNG</comment>
+ <comment xml:lang="is">PNG mynd</comment>
<comment xml:lang="id">Citra PNG</comment>
<comment xml:lang="ia">Imagine PNG</comment>
<comment xml:lang="hu">PNG-kép</comment>
@@ -28213,16 +29515,42 @@ command to generate the output files.
<comment xml:lang="ca">imatge PNG</comment>
<comment xml:lang="bg">Изображение — PNG</comment>
<comment xml:lang="be@latin">Vyjava PNG</comment>
+ <comment xml:lang="be">выява PNG</comment>
<comment xml:lang="az">PNG rəsmi</comment>
<comment xml:lang="ar">صورة PNG</comment>
<comment xml:lang="af">PNG-beeld</comment>
<acronym>PNG</acronym>
<expanded-acronym>Portable Network Graphics</expanded-acronym>
<magic>
- <match type="string" value="\x89PNG" offset="0"/>
+ <match type="string" value="\x89PNG\r\n\x1A\n" offset="0"/>
</magic>
<glob pattern="*.png"/>
</mime-type>
+ <mime-type type="image/apng">
+ <comment>Animated PNG image</comment>
+ <comment xml:lang="uk">анімоване зображення PNG</comment>
+ <comment xml:lang="sv">Animerad PNG-bild</comment>
+ <comment xml:lang="ru">Анимированное изображение PNG</comment>
+ <comment xml:lang="pl">Animowany obraz PNG</comment>
+ <comment xml:lang="ja">PNG動画</comment>
+ <comment xml:lang="it">Immagine PNG animata</comment>
+ <comment xml:lang="gl">Imaxe de PNG animado</comment>
+ <comment xml:lang="eu">PNG irudi animatua</comment>
+ <comment xml:lang="es">imagen PNG animada</comment>
+ <comment xml:lang="de">Animiertes PNG-Bild</comment>
+ <comment xml:lang="be">анімаваная выява PNG</comment>
+ <acronym>PNG</acronym>
+ <expanded-acronym>Portable Network Graphics</expanded-acronym>
+ <sub-class-of type="image/png"/>
+ <magic priority="60">
+ <match type="string" value="\x89PNG\r\n\x1A\n" offset="0">
+ <match type="string" value="acTL" offset="37"/>
+ </match>
+ </magic>
+ <glob pattern="*.apng"/>
+ <glob pattern="*.png" weight="40"/>
+ <alias type="image/vnd.mozilla.apng"/>
+ </mime-type>
<mime-type type="image/rle">
<comment>RLE bitmap image</comment>
<comment xml:lang="zh_TW">RLE 點陣影像</comment>
@@ -28230,27 +29558,33 @@ command to generate the output files.
<comment xml:lang="uk">растрове зображення RLE</comment>
<comment xml:lang="tr">RLE bit eşlem görüntüsü</comment>
<comment xml:lang="sv">RLE bitmappsbild</comment>
+ <comment xml:lang="sq">figurë bitmap RLE</comment>
<comment xml:lang="sl">Bitna slika RLE</comment>
+ <comment xml:lang="si">RLE බිට්මැප් රූපය</comment>
<comment xml:lang="ru">Растровое изображение RLE</comment>
<comment xml:lang="pt_BR">Imagem bitmap RLE</comment>
<comment xml:lang="pl">Obraz bitmapy RLE</comment>
+ <comment xml:lang="nl">RLE-bitmapafbeelding</comment>
<comment xml:lang="ko">RLE 비트맵 그림</comment>
<comment xml:lang="kk">RLE растрлық суреті</comment>
<comment xml:lang="ja">RLE ビットマップ画像</comment>
<comment xml:lang="it">Immagine bitmap RLE</comment>
+ <comment xml:lang="is">RLE bitamynd</comment>
<comment xml:lang="id">Citra bitmap RLE</comment>
<comment xml:lang="hu">RLE bitkép</comment>
<comment xml:lang="hr">RLE bitmap slika</comment>
<comment xml:lang="he">תמונת מפת סיביות RLE</comment>
+ <comment xml:lang="gl">Imaxe de mapa de bits RLE</comment>
<comment xml:lang="fr">image matricielle RLE</comment>
<comment xml:lang="fi">RLE-bittikarttakuva</comment>
<comment xml:lang="eu">RLE bitmap irudia</comment>
- <comment xml:lang="es">imagen de mapa de bits RLE</comment>
+ <comment xml:lang="es">imagen de mapa de los bit RLE</comment>
<comment xml:lang="en_GB">RLE bitmap image</comment>
<comment xml:lang="de">Lauflängenkodiertes Bitmap-Bild</comment>
<comment xml:lang="da">RLE bitmap-billede</comment>
<comment xml:lang="ca">imatge de mapa de bits RLE</comment>
<comment xml:lang="bg">Изображение — RLE bitmap</comment>
+ <comment xml:lang="be">растравая выява RLE</comment>
<comment xml:lang="ar">صورة نقطية RLE</comment>
<acronym>RLE</acronym>
<expanded-acronym>Run Length Encoded</expanded-acronym>
@@ -28265,8 +29599,9 @@ command to generate the output files.
<comment xml:lang="tr">SVG görüntüsü</comment>
<comment xml:lang="sv">SVG-bild</comment>
<comment xml:lang="sr">СВГ слика</comment>
- <comment xml:lang="sq">Figurë SVG</comment>
+ <comment xml:lang="sq">figurë SVG</comment>
<comment xml:lang="sl">Slikovna vektorska datoteka SVG</comment>
+ <comment xml:lang="si">SVG රූපය</comment>
<comment xml:lang="sk">Obrázok SVG</comment>
<comment xml:lang="ru">Изображение SVG</comment>
<comment xml:lang="ro">Imagine SVG</comment>
@@ -28281,8 +29616,10 @@ command to generate the output files.
<comment xml:lang="lt">SVG paveikslėlis</comment>
<comment xml:lang="ko">SVG 그림</comment>
<comment xml:lang="kk">SVG суреті</comment>
+ <comment xml:lang="ka">SVG გამოსახულება</comment>
<comment xml:lang="ja">SVG 画像</comment>
<comment xml:lang="it">Immagine SVG</comment>
+ <comment xml:lang="is">SVG mynd</comment>
<comment xml:lang="id">Citra SVG</comment>
<comment xml:lang="ia">Imagine SVG</comment>
<comment xml:lang="hu">SVG kép</comment>
@@ -28305,6 +29642,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge SVG</comment>
<comment xml:lang="bg">Изображение — SVG</comment>
<comment xml:lang="be@latin">Vyjava SVG</comment>
+ <comment xml:lang="be">выява SVG</comment>
<comment xml:lang="ar">صورة SVG</comment>
<comment xml:lang="af">SVG-beeld</comment>
<acronym>SVG</acronym>
@@ -28324,55 +29662,18 @@ command to generate the output files.
<root-XML namespaceURI="http://www.w3.org/2000/svg" localName="svg"/>
</mime-type>
<mime-type type="image/svg+xml-compressed">
- <comment>compressed SVG image</comment>
- <comment xml:lang="zh_TW">壓縮版 SVG 影像</comment>
- <comment xml:lang="zh_CN">压缩的 SVG 图像</comment>
- <comment xml:lang="vi">ảnh SVG đã nén</comment>
+ <comment>Compressed SVG image</comment>
<comment xml:lang="uk">стиснене зображення SVG</comment>
- <comment xml:lang="tr">sıkıştırılmış SVG görüntüsü</comment>
- <comment xml:lang="sv">komprimerad SVG-bild</comment>
- <comment xml:lang="sr">запакована СВГ слика</comment>
- <comment xml:lang="sq">Figurë SVG e kompresuar</comment>
- <comment xml:lang="sl">Slikovna datoteka SVG (stisnjena)</comment>
- <comment xml:lang="sk">Komprimovaný obrázok SVG</comment>
+ <comment xml:lang="sv">Komprimerad SVG-bild</comment>
<comment xml:lang="ru">Сжатое изображение SVG</comment>
- <comment xml:lang="ro">imagine comprimată SVG</comment>
- <comment xml:lang="pt_BR">Imagem SVG compactada</comment>
- <comment xml:lang="pt">imagem SVG comprimida</comment>
<comment xml:lang="pl">Skompresowany obraz SVG</comment>
- <comment xml:lang="oc">imatge SVG compressat</comment>
- <comment xml:lang="nn">komprimert SVG-bilete</comment>
- <comment xml:lang="nl">ingepakte SVG-afbeelding</comment>
- <comment xml:lang="nb">komprimert SVG-bilde</comment>
- <comment xml:lang="lv">saspiests SVG attēls</comment>
- <comment xml:lang="lt">suglaudintas SVG paveikslėlis</comment>
- <comment xml:lang="ko">압축된 SVG 그림</comment>
- <comment xml:lang="kk">сығылған SVG суреті</comment>
- <comment xml:lang="ja">圧縮 SVG 画像</comment>
+ <comment xml:lang="ja">SVG画像(圧縮)</comment>
<comment xml:lang="it">Immagine SVG compressa</comment>
- <comment xml:lang="id">citra SVG terkompresi</comment>
- <comment xml:lang="ia">Imagine SVG comprimite</comment>
- <comment xml:lang="hu">tömörített SVG kép</comment>
- <comment xml:lang="hr">Sažeta SVG slika</comment>
- <comment xml:lang="he">תמונת SVG מכווצת</comment>
- <comment xml:lang="gl">imaxe SVG comprimida</comment>
- <comment xml:lang="ga">íomhá SVG comhbhrúite</comment>
- <comment xml:lang="fur">imagjin SVG comprimude</comment>
- <comment xml:lang="fr">image SVG compressée</comment>
- <comment xml:lang="fo">stappað SVG mynd</comment>
- <comment xml:lang="fi">pakattu SVG-kuva</comment>
- <comment xml:lang="eu">konprimitutako SVG irudia</comment>
+ <comment xml:lang="gl">Imaxe SVG comprimido</comment>
+ <comment xml:lang="eu">SVG irudi konprimatua</comment>
<comment xml:lang="es">imagen SVG comprimida</comment>
- <comment xml:lang="en_GB">compressed SVG image</comment>
- <comment xml:lang="el">Συμπιεσμένη εικόνα SVG</comment>
<comment xml:lang="de">Komprimiertes SVG-Bild</comment>
- <comment xml:lang="da">SVG-komprimeret billede</comment>
- <comment xml:lang="cs">komprimovaný obrázek SVG</comment>
- <comment xml:lang="ca">imatge SVG amb compressió</comment>
- <comment xml:lang="bg">Изображение — SVG, компресирано</comment>
- <comment xml:lang="be@latin">skampresavanaja vyjava SVG</comment>
- <comment xml:lang="ar">صورة SVG مضغوطة</comment>
- <comment xml:lang="af">saamgepersde SVG-beeld</comment>
+ <comment xml:lang="be">сціснутая выява SVG</comment>
<acronym>SVG</acronym>
<expanded-acronym>Scalable Vector Graphics</expanded-acronym>
<sub-class-of type="application/gzip"/>
@@ -28388,8 +29689,9 @@ command to generate the output files.
<comment xml:lang="tr">TIFF görüntüsü</comment>
<comment xml:lang="sv">TIFF-bild</comment>
<comment xml:lang="sr">ТИФФ слика</comment>
- <comment xml:lang="sq">Figurë TIFF</comment>
+ <comment xml:lang="sq">figurë TIFF</comment>
<comment xml:lang="sl">Slikovna datoteka TIFF</comment>
+ <comment xml:lang="si">TIFF රූපය</comment>
<comment xml:lang="sk">Obrázok TIFF</comment>
<comment xml:lang="ru">Изображение TIFF</comment>
<comment xml:lang="ro">Imagine TIFF</comment>
@@ -28407,6 +29709,7 @@ command to generate the output files.
<comment xml:lang="kk">TIFF суреті</comment>
<comment xml:lang="ja">TIFF 画像</comment>
<comment xml:lang="it">Immagine TIFF</comment>
+ <comment xml:lang="is">TIFF mynd</comment>
<comment xml:lang="id">Citra TIFF</comment>
<comment xml:lang="ia">Imagine TIFF</comment>
<comment xml:lang="hu">TIFF-kép</comment>
@@ -28429,6 +29732,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge TIFF</comment>
<comment xml:lang="bg">Изображение — TIFF</comment>
<comment xml:lang="be@latin">Vyjava TIFF</comment>
+ <comment xml:lang="be">выява TIFF</comment>
<comment xml:lang="ar">صورة TIFF</comment>
<comment xml:lang="af">TIFF-beeld</comment>
<acronym>TIFF</acronym>
@@ -28448,17 +29752,21 @@ command to generate the output files.
<comment xml:lang="tr">Çok sayfalı TIFF görüntüsü</comment>
<comment xml:lang="sv">Flersidig TIFF-bild</comment>
<comment xml:lang="sr">Вишестранична ТИФФ слика</comment>
+ <comment xml:lang="sq">figurë TIFF me shumë faqe</comment>
<comment xml:lang="sl">Večstranska slika TIFF</comment>
+ <comment xml:lang="si">බහු-පිටු TIFF රූපය</comment>
<comment xml:lang="sk">Viacstránkový obrázok TIFF</comment>
<comment xml:lang="ru">Многостраничное изображение TIFF</comment>
<comment xml:lang="pt_BR">Imagem TIFF multipágina</comment>
<comment xml:lang="pt">imagem TIFF multipágina</comment>
<comment xml:lang="pl">Wielostronnicowy obraz TIFF</comment>
<comment xml:lang="oc">Imatge TIFF multipagina</comment>
+ <comment xml:lang="nl">Multi-pagina TIFF-afbeelding</comment>
<comment xml:lang="ko">다중 페이지 TIFF 그림</comment>
<comment xml:lang="kk">Көпбеттік TIFF суреті</comment>
<comment xml:lang="ja">マルチページ TIFF 画像</comment>
<comment xml:lang="it">Immagine TIFF multi-pagina</comment>
+ <comment xml:lang="is">Margsíðna TIFF mynd</comment>
<comment xml:lang="id">Citra TIFF multi halaman</comment>
<comment xml:lang="ia">Imagine TIFF multi-pagina</comment>
<comment xml:lang="hu">Többoldalas TIFF kép</comment>
@@ -28470,7 +29778,7 @@ command to generate the output files.
<comment xml:lang="fr">Image TIFF multi-page</comment>
<comment xml:lang="fi">Monisivuinen TIFF-kuva</comment>
<comment xml:lang="eu">Multi-page TIFF irudia</comment>
- <comment xml:lang="es">imagen TIFF de varias páginas</comment>
+ <comment xml:lang="es">imagen TIFF multipágina</comment>
<comment xml:lang="en_GB">Multi-page TIFF image</comment>
<comment xml:lang="el">Πολυσέλιδη εικόνα TIFF</comment>
<comment xml:lang="de">Mehrseitiges TIFF-Bild</comment>
@@ -28478,6 +29786,7 @@ command to generate the output files.
<comment xml:lang="cs">vícestránkový obrázek TIFF</comment>
<comment xml:lang="ca">imatge TIFF multipàgina</comment>
<comment xml:lang="bg">Изображение — TIFF, много страници</comment>
+ <comment xml:lang="be">шматстаронкавая выява TIFF</comment>
<comment xml:lang="ar">صورة TIFF متعددة الصفحات</comment>
<comment xml:lang="af">Multibladsy TIFF-beeld</comment>
<acronym>TIFF</acronym>
@@ -28493,8 +29802,9 @@ command to generate the output files.
<comment xml:lang="tr">AutoCAD görüntüsü</comment>
<comment xml:lang="sv">AutoCAD-bild</comment>
<comment xml:lang="sr">АутоКАД слика</comment>
- <comment xml:lang="sq">Figurë AutoCAD</comment>
+ <comment xml:lang="sq">figurë AutoCAD</comment>
<comment xml:lang="sl">Slikovna datoteka AutoCAD</comment>
+ <comment xml:lang="si">AutoCAD රූපය</comment>
<comment xml:lang="sk">Obrázok AutoCAD</comment>
<comment xml:lang="ru">Изображение AutoCAD</comment>
<comment xml:lang="ro">Imagine AutoCAD</comment>
@@ -28513,6 +29823,7 @@ command to generate the output files.
<comment xml:lang="ka">AutoCAD-ის გამოსახულება</comment>
<comment xml:lang="ja">AutoCAD 画像</comment>
<comment xml:lang="it">Immagine AutoCAD</comment>
+ <comment xml:lang="is">AutoCAD mynd</comment>
<comment xml:lang="id">Citra AutoCAD</comment>
<comment xml:lang="ia">Imagine AutoCAD</comment>
<comment xml:lang="hu">AutoCAD-kép</comment>
@@ -28536,6 +29847,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge d'AutoCAD</comment>
<comment xml:lang="bg">Изображение — AutoCAD</comment>
<comment xml:lang="be@latin">Vyjava AutoCAD</comment>
+ <comment xml:lang="be">выява AutoCAD</comment>
<comment xml:lang="az">AutoCAD rəsmi</comment>
<comment xml:lang="ar">صورة AutoCAD</comment>
<comment xml:lang="af">AutoCAD-beeld</comment>
@@ -28550,8 +29862,9 @@ command to generate the output files.
<comment xml:lang="tr">DXF vektör görüntüsü</comment>
<comment xml:lang="sv">DXF-vektorbild</comment>
<comment xml:lang="sr">ДИксФ векторска графика</comment>
- <comment xml:lang="sq">Figurë vektoriale DFX</comment>
+ <comment xml:lang="sq">figurë vektoriale DFX</comment>
<comment xml:lang="sl">Slikovna vektorska datoteka DXF</comment>
+ <comment xml:lang="si">DXF දෛශික රූපය</comment>
<comment xml:lang="sk">Vektorový obrázok DXF</comment>
<comment xml:lang="ru">Векторное изображение DXF</comment>
<comment xml:lang="ro">Imagine vectorială DXF</comment>
@@ -28570,6 +29883,7 @@ command to generate the output files.
<comment xml:lang="ka">DXF ვექტორული გამოსახულება</comment>
<comment xml:lang="ja">DXF ベクター画像</comment>
<comment xml:lang="it">Immagine vettoriale DXF</comment>
+ <comment xml:lang="is">DXF vigurteikning</comment>
<comment xml:lang="id">Citra vektor DXF</comment>
<comment xml:lang="ia">Imagine vectorial DXF</comment>
<comment xml:lang="hu">DXF-vektorkép</comment>
@@ -28592,6 +29906,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge vectorial DXF</comment>
<comment xml:lang="bg">Изображение — DXF</comment>
<comment xml:lang="be@latin">Vektarnaja vyjava DXF</comment>
+ <comment xml:lang="be">вектарная выява DXF</comment>
<comment xml:lang="ar">صورة DXF نقطية</comment>
<comment xml:lang="af">DXF-vektorbeeld</comment>
<glob pattern="*.dxf"/>
@@ -28607,20 +29922,25 @@ command to generate the output files.
<comment xml:lang="uk">зображення MDI</comment>
<comment xml:lang="tr">MDI görüntüsü</comment>
<comment xml:lang="sv">MDI-bild</comment>
+ <comment xml:lang="sq">figurë MDI</comment>
<comment xml:lang="sl">Slika MDI</comment>
+ <comment xml:lang="si">MDI රූපය</comment>
<comment xml:lang="sk">Obrázok MDI</comment>
<comment xml:lang="ru">Изображение MDI</comment>
<comment xml:lang="pt_BR">Imagem MDI</comment>
<comment xml:lang="pl">Obraz MDI</comment>
<comment xml:lang="oc">imatge MDI</comment>
+ <comment xml:lang="nl">MDI-afbeelding</comment>
<comment xml:lang="ko">MDI 그림</comment>
<comment xml:lang="kk">MDI суреті</comment>
<comment xml:lang="ja">MDI 画像</comment>
<comment xml:lang="it">Immagine MDI</comment>
+ <comment xml:lang="is">MDI mynd</comment>
<comment xml:lang="id">Citra MDI</comment>
<comment xml:lang="hu">MDI-kép</comment>
<comment xml:lang="hr">MDI slika</comment>
<comment xml:lang="he">תמונת MDI</comment>
+ <comment xml:lang="gl">Imaxe MDI</comment>
<comment xml:lang="fr">image MDI</comment>
<comment xml:lang="fi">MDI-kuva</comment>
<comment xml:lang="eu">MDI irudia</comment>
@@ -28630,6 +29950,7 @@ command to generate the output files.
<comment xml:lang="da">MDI-billede</comment>
<comment xml:lang="ca">imatge MDI</comment>
<comment xml:lang="bg">Изображение — MDI</comment>
+ <comment xml:lang="be">выява MDI</comment>
<comment xml:lang="ar">صورة MDI</comment>
<acronym>MDI</acronym>
<expanded-acronym>Microsoft Document Imaging</expanded-acronym>
@@ -28638,6 +29959,29 @@ command to generate the output files.
<match type="string" value="\x45\x50\x2A\x00" offset="0"/>
</magic>
</mime-type>
+ <mime-type type="image/jxr">
+ <comment>JPEG XR image</comment>
+ <comment xml:lang="uk">зображення JPEG XR</comment>
+ <comment xml:lang="sv">JPEG XR-bild</comment>
+ <comment xml:lang="ru">Изображение JPEG XR</comment>
+ <comment xml:lang="pt_BR">Imagem JPEG XR</comment>
+ <comment xml:lang="pl">Obraz JPEG XR</comment>
+ <comment xml:lang="it">Immagine JPEG XR</comment>
+ <comment xml:lang="gl">Imaxe JPEG XR</comment>
+ <comment xml:lang="eu">JPEG XR irudia</comment>
+ <comment xml:lang="es">imagen JPEG XR</comment>
+ <comment xml:lang="de">JPEG-XR-Bild</comment>
+ <comment xml:lang="be">выява JPEG XR</comment>
+ <acronym>XR</acronym>
+ <expanded-acronym>Extended Range</expanded-acronym>
+ <glob pattern="*.jxr"/>
+ <glob pattern="*.hdp"/>
+ <glob pattern="*.wdp"/>
+ <magic>
+ <match type="string" value="II\xBC\x01" offset="0"/>
+ </magic>
+ <alias type="image/vnd.ms-photo"/>
+ </mime-type>
<mime-type type="image/webp">
<comment>WebP image</comment>
<comment xml:lang="zh_TW">WebP 影像</comment>
@@ -28646,17 +29990,21 @@ command to generate the output files.
<comment xml:lang="tr">WebP görüntüsü</comment>
<comment xml:lang="sv">WebP-bild</comment>
<comment xml:lang="sr">ВебП слика</comment>
+ <comment xml:lang="sq">figurë WebP</comment>
<comment xml:lang="sl">Slika WebP</comment>
+ <comment xml:lang="si">WebP රූපය</comment>
<comment xml:lang="sk">Obrázok WebP</comment>
<comment xml:lang="ru">Изображение WebP</comment>
<comment xml:lang="pt_BR">Imagem WebP</comment>
<comment xml:lang="pt">imagem WebP</comment>
<comment xml:lang="pl">Obraz WebP</comment>
<comment xml:lang="oc">imatge WebP</comment>
+ <comment xml:lang="nl">WebP-afbeelding</comment>
<comment xml:lang="ko">WebP 그림</comment>
<comment xml:lang="kk">WebP суреті</comment>
<comment xml:lang="ja">WebP 画像</comment>
<comment xml:lang="it">Immagine WebP</comment>
+ <comment xml:lang="is">WebP-mynd</comment>
<comment xml:lang="id">Citra WebP</comment>
<comment xml:lang="ia">Imagine WebP</comment>
<comment xml:lang="hu">WebP kép</comment>
@@ -28676,6 +30024,7 @@ command to generate the output files.
<comment xml:lang="cs">obrázek WebP</comment>
<comment xml:lang="ca">imatge WebP</comment>
<comment xml:lang="bg">Изображение — WebP</comment>
+ <comment xml:lang="be">выява WebP</comment>
<comment xml:lang="ar">صورة WebP</comment>
<comment xml:lang="af">WebP-beeld</comment>
<magic>
@@ -28694,8 +30043,9 @@ command to generate the output files.
<comment xml:lang="tr">3D Studio görüntüsü</comment>
<comment xml:lang="sv">3D Studio-bild</comment>
<comment xml:lang="sr">слика 3Д Студија</comment>
- <comment xml:lang="sq">Figurë 3D Studio</comment>
+ <comment xml:lang="sq">figurë 3D Studio</comment>
<comment xml:lang="sl">Slikovna datoteka 3D Studio</comment>
+ <comment xml:lang="si">3D ස්ටුඩියෝ රූපය</comment>
<comment xml:lang="sk">Obrázok 3D Studio</comment>
<comment xml:lang="ru">Сцена 3D Studio</comment>
<comment xml:lang="ro">Imagine 3D Studio</comment>
@@ -28714,6 +30064,7 @@ command to generate the output files.
<comment xml:lang="ka">3D Studio-ის გამოსახულება</comment>
<comment xml:lang="ja">3D Studio 画像</comment>
<comment xml:lang="it">Immagine 3D Studio</comment>
+ <comment xml:lang="is">3D Studio mynd</comment>
<comment xml:lang="id">Citra 3D Studio</comment>
<comment xml:lang="ia">Imagine 3D Studio</comment>
<comment xml:lang="hu">3D Studio-kép</comment>
@@ -28737,6 +30088,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge de 3D Studio</comment>
<comment xml:lang="bg">Изображение — 3D Studio</comment>
<comment xml:lang="be@latin">Vyjava 3D Studio</comment>
+ <comment xml:lang="be">выява 3D Studio</comment>
<comment xml:lang="az">3D Studio rəsmi</comment>
<comment xml:lang="ar">صورة 3دي استديو</comment>
<comment xml:lang="af">3D Studio-beeld</comment>
@@ -28754,8 +30106,9 @@ command to generate the output files.
<comment xml:lang="tr">Applix Graphics görüntüsü</comment>
<comment xml:lang="sv">Applix Graphics-bild</comment>
<comment xml:lang="sr">Апликсов графички документ</comment>
- <comment xml:lang="sq">Figurë Applix Graphics</comment>
+ <comment xml:lang="sq">figurë Applix Graphics</comment>
<comment xml:lang="sl">Slikovna datoteka Applix Graphics</comment>
+ <comment xml:lang="si">Applix Graphics රූපය</comment>
<comment xml:lang="sk">Obrázok Applix Graphics</comment>
<comment xml:lang="ru">Изображение Applix Graphics</comment>
<comment xml:lang="ro">Imagine Applix Graphics</comment>
@@ -28774,6 +30127,7 @@ command to generate the output files.
<comment xml:lang="ka">Applix Graphics-ის გამოსახულება</comment>
<comment xml:lang="ja">Applix Graphics 画像</comment>
<comment xml:lang="it">Immagine Applix Graphics</comment>
+ <comment xml:lang="is">Applix Graphics mynd</comment>
<comment xml:lang="id">Citra Applix Graphics</comment>
<comment xml:lang="ia">Imagine Applix Graphics</comment>
<comment xml:lang="hu">Applix Graphics-kép</comment>
@@ -28796,6 +30150,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge d'Applix Graphics</comment>
<comment xml:lang="bg">Изображение — Applix Graphics</comment>
<comment xml:lang="be@latin">Vyjava Applix Graphics</comment>
+ <comment xml:lang="be">выява Applix Graphics</comment>
<comment xml:lang="ar">صورة رسوميات Applix</comment>
<comment xml:lang="af">Applix Graphics-beeld</comment>
<magic>
@@ -28806,57 +30161,14 @@ command to generate the output files.
<glob pattern="*.ag"/>
</mime-type>
<mime-type type="image/x-bzeps">
- <comment>EPS image (bzip-compressed)</comment>
- <comment xml:lang="zh_TW">EPS 影像 (bzip 壓縮)</comment>
- <comment xml:lang="zh_CN">EPS 图像(bzip 压缩)</comment>
- <comment xml:lang="vi">Ảnh EPS (đã nén bzip)</comment>
- <comment xml:lang="uk">зображення EPS (стиснене bzip)</comment>
- <comment xml:lang="tr">EPS görüntüsü (bzip ile sıkıştırılmış)</comment>
- <comment xml:lang="sv">EPS-bild (bzip-komprimerad)</comment>
- <comment xml:lang="sr">ЕПС слика (запакована бзип-ом)</comment>
- <comment xml:lang="sq">Figurë EPS (e kompresuar me bzip)</comment>
- <comment xml:lang="sl">Slikovna datoteka EPS (stisnjena z bzip)</comment>
- <comment xml:lang="sk">Obrázok EPS (komprimovaný pomocou bzip)</comment>
- <comment xml:lang="ru">Изображение EPS (сжатое bzip)</comment>
- <comment xml:lang="ro">Imagine EPS (compresie bzip)</comment>
- <comment xml:lang="pt_BR">Imagem EPS (compactada com bzip)</comment>
- <comment xml:lang="pt">imagem EPS (compressão bzip)</comment>
- <comment xml:lang="pl">Obraz EPS (kompresja bzip)</comment>
- <comment xml:lang="oc">imatge EPS (compressat bzip)</comment>
- <comment xml:lang="nn">EPS-bilete (pakka med bzip)</comment>
- <comment xml:lang="nl">EPS-afbeelding (ingepakt met bzip)</comment>
- <comment xml:lang="nb">EPS-bilde (bzip-komprimert)</comment>
- <comment xml:lang="lv">EPS attēls (saspiests ar bzip)</comment>
- <comment xml:lang="lt">EPS paveikslėlis (suglaudintas su bzip)</comment>
- <comment xml:lang="ko">EPS 그림(BZIP 압축)</comment>
- <comment xml:lang="kk">EPS суреті (bzip-пен сығылған)</comment>
- <comment xml:lang="ka">EPS გამოსახულება (bzip-ით შეკუმშული)</comment>
- <comment xml:lang="ja">EPS 画像 (bzip 圧縮)</comment>
- <comment xml:lang="it">Immagine EPS (compressa con bzip)</comment>
- <comment xml:lang="id">Citra EPS (terkompresi bzip)</comment>
- <comment xml:lang="ia">Imagine EPS (comprimite con bzip)</comment>
- <comment xml:lang="hu">EPS kép (bzip tömörítésű)</comment>
- <comment xml:lang="hr">EPS slika (bzip sažeta)</comment>
- <comment xml:lang="he">תמונת EPS (מכווץ בbzip)</comment>
- <comment xml:lang="gl">imaxe EPS (comprimida con bzip)</comment>
- <comment xml:lang="ga">íomhá EPS (comhbhrúite le bzip)</comment>
- <comment xml:lang="fur">imagjin EPS (comprimude cun bzip)</comment>
- <comment xml:lang="fr">image EPS (compressée bzip)</comment>
- <comment xml:lang="fo">EPS mynd (bzip-stappað)</comment>
- <comment xml:lang="fi">EPS-kuva (bzip-pakattu)</comment>
- <comment xml:lang="eu">EPS irudia (bzip-ekin konprimitua)</comment>
- <comment xml:lang="es">imagen EPS (comprimida con bzip)</comment>
- <comment xml:lang="en_GB">EPS image (bzip-compressed)</comment>
- <comment xml:lang="el">Εικόνα EPS (συμπιεσμένη bzip)</comment>
- <comment xml:lang="de">EPS-Bild (bzip-komprimiert)</comment>
- <comment xml:lang="da">EPS-billede (bzip-komprimeret)</comment>
- <comment xml:lang="cs">obrázek EPS (komprimovaný pomocí bzip)</comment>
- <comment xml:lang="ca">imatge EPS (amb compressió bzip)</comment>
- <comment xml:lang="bg">Изображение — EPS, компресирано с bzip</comment>
- <comment xml:lang="be@latin">Vyjava EPS (bzip-skampresavanaja)</comment>
- <comment xml:lang="ar">صورة EPS (مضغوط-bzip)</comment>
- <comment xml:lang="af">EPS-beeld (bzip-saamgepers)</comment>
- <sub-class-of type="application/x-bzip"/>
+ <comment>EPS image (bzip2-compressed)</comment>
+ <comment xml:lang="uk">зображення EPS (стиснений bzip2)</comment>
+ <comment xml:lang="sv">EPS-bild (bzip2-komprimerad)</comment>
+ <comment xml:lang="ru">Изображение EPS (сжатое bzip2)</comment>
+ <comment xml:lang="pl">Obraz EPS (kompresja bzip2)</comment>
+ <comment xml:lang="es">imagen EPS (comprimida con BZIP2)</comment>
+ <comment xml:lang="de">EPS-Bild (bzip2-komprimiert)</comment>
+ <sub-class-of type="application/x-bzip2"/>
<glob pattern="*.eps.bz2"/>
<glob pattern="*.epsi.bz2"/>
<glob pattern="*.epsf.bz2"/>
@@ -28870,8 +30182,9 @@ command to generate the output files.
<comment xml:lang="tr">CMU tarama görüntüsü</comment>
<comment xml:lang="sv">CMU-rasterbild</comment>
<comment xml:lang="sr">ЦМУ растерска слика</comment>
- <comment xml:lang="sq">Figurë raster CMU</comment>
+ <comment xml:lang="sq">figurë raster CMU</comment>
<comment xml:lang="sl">Slikovna rastrska datoteka CMU</comment>
+ <comment xml:lang="si">CMU රාස්ටර් රූපය</comment>
<comment xml:lang="sk">Rastrový obrázok CMU</comment>
<comment xml:lang="ru">Растровое изображение CMU</comment>
<comment xml:lang="ro">Imagine raster CMU</comment>
@@ -28890,6 +30203,7 @@ command to generate the output files.
<comment xml:lang="ka">CMU-ის რასტრული გამოსახულება</comment>
<comment xml:lang="ja">CMU ラスター画像</comment>
<comment xml:lang="it">Immagine raster CMU</comment>
+ <comment xml:lang="is">CMU rastamynd</comment>
<comment xml:lang="id">Citra raster CMU</comment>
<comment xml:lang="ia">Imagine raster CMU</comment>
<comment xml:lang="hu">CMU-raszterkép</comment>
@@ -28913,61 +30227,25 @@ command to generate the output files.
<comment xml:lang="ca">imatge ràster CMU</comment>
<comment xml:lang="bg">Изображение — CMU raster</comment>
<comment xml:lang="be@latin">Rastravaja vyjava CMU</comment>
+ <comment xml:lang="be">растравая выява CMU</comment>
<comment xml:lang="az">CMU raster rəsmi</comment>
<comment xml:lang="ar">صورة CMU نقطية</comment>
<comment xml:lang="af">CMU-roosterbeeld</comment>
<glob pattern="*.ras"/>
</mime-type>
<mime-type type="image/x-compressed-xcf">
- <comment>compressed GIMP image</comment>
- <comment xml:lang="zh_TW">壓縮版 GIMP 影像</comment>
- <comment xml:lang="zh_CN">压缩的 GIMP 图像</comment>
- <comment xml:lang="vi">ảnh GIMP đã nén</comment>
+ <comment>Compressed GIMP image</comment>
<comment xml:lang="uk">стиснене зображення GIMP</comment>
- <comment xml:lang="tr">sıkıştırılmış GIMP görüntüsü</comment>
- <comment xml:lang="sv">komprimerad GIMP-bild</comment>
- <comment xml:lang="sr">запакована ГИМП слика</comment>
- <comment xml:lang="sq">Figurë GIMP e kompresuar</comment>
- <comment xml:lang="sl">Slikovna datoteka GIMP (stisnjena)</comment>
- <comment xml:lang="sk">Komprimovaný obrázok GIMP</comment>
+ <comment xml:lang="sv">Komprimerad GIMP-bild</comment>
<comment xml:lang="ru">Сжатое изображение GIMP</comment>
- <comment xml:lang="ro">imagine comprimată GIMP</comment>
- <comment xml:lang="pt_BR">Imagem do GIMP compactada</comment>
- <comment xml:lang="pt">imagem GIMP comprimida</comment>
<comment xml:lang="pl">Skompresowany obraz GIMP</comment>
- <comment xml:lang="oc">imatge GIMP compressat</comment>
- <comment xml:lang="nn">komprimert GIMP-bilete</comment>
- <comment xml:lang="nl">ingepakte GIMP-afbeelding</comment>
- <comment xml:lang="nb">komprimert GIMP-bilde</comment>
- <comment xml:lang="lv">saspiests GIMP attēls</comment>
- <comment xml:lang="lt">suglaudintas GIMP paveikslėlis</comment>
- <comment xml:lang="ko">압축된 GIMP 그림</comment>
- <comment xml:lang="kk">сығылған GIMP суреті</comment>
- <comment xml:lang="ja">圧縮 GIMP 画像</comment>
+ <comment xml:lang="ja">GIMP画像(圧縮)</comment>
<comment xml:lang="it">Immagine GIMP compressa</comment>
- <comment xml:lang="id">citra GIMP terkompresi</comment>
- <comment xml:lang="ia">Imagine GIMP comprimite</comment>
- <comment xml:lang="hu">tömörített GIMP kép</comment>
- <comment xml:lang="hr">Sažeta GIMP slika</comment>
- <comment xml:lang="he">תמונת GIMP מכווצת</comment>
- <comment xml:lang="gl">imaxe de GIMP comprimida</comment>
- <comment xml:lang="ga">íomhá GIMP comhbhrúite</comment>
- <comment xml:lang="fur">imagjin GIMP comprimude</comment>
- <comment xml:lang="fr">image GIMP compressée</comment>
- <comment xml:lang="fo">stappað GIMP mynd</comment>
- <comment xml:lang="fi">pakattu GIMP-kuva</comment>
- <comment xml:lang="eu">konprimitutako GIMP irudia</comment>
- <comment xml:lang="es">imagen GIMP comprimida</comment>
- <comment xml:lang="en_GB">compressed GIMP image</comment>
- <comment xml:lang="el">Συμπιεσμένη εικόνα GIMP</comment>
+ <comment xml:lang="gl">Imaxe GIMP comprimida</comment>
+ <comment xml:lang="eu">GIMP irudi konprimatua</comment>
+ <comment xml:lang="es">imagen de GIMP comprimida</comment>
<comment xml:lang="de">Komprimiertes GIMP-Bild</comment>
- <comment xml:lang="da">komprimeret GIMP-billede</comment>
- <comment xml:lang="cs">komprimovaný obrázek GIMP</comment>
- <comment xml:lang="ca">imatge GIMP amb compressió</comment>
- <comment xml:lang="bg">Изображение — GIMP, компресирано</comment>
- <comment xml:lang="be@latin">skampresavanaja vyjava GIMP</comment>
- <comment xml:lang="ar">صورة GIMP مضغوطة</comment>
- <comment xml:lang="af">saamgepersde GIMP-beeld</comment>
+ <comment xml:lang="be">сціснутая выява GIMP</comment>
<glob pattern="*.xcf.gz"/>
<glob pattern="*.xcf.bz2"/>
</mime-type>
@@ -28980,8 +30258,9 @@ command to generate the output files.
<comment xml:lang="tr">DICOM görüntüsü</comment>
<comment xml:lang="sv">DICOM-bild</comment>
<comment xml:lang="sr">ДИКОМ слика</comment>
- <comment xml:lang="sq">Figurë DICOM</comment>
+ <comment xml:lang="sq">figurë DICOM</comment>
<comment xml:lang="sl">Slikovna datoteka DICOM</comment>
+ <comment xml:lang="si">DICOM රූපය</comment>
<comment xml:lang="sk">Obrázok DICOM</comment>
<comment xml:lang="ru">Изображение DICOM</comment>
<comment xml:lang="ro">Imagine DICOM</comment>
@@ -28999,6 +30278,7 @@ command to generate the output files.
<comment xml:lang="ka">DICOM გამოსახულება</comment>
<comment xml:lang="ja">DICOM 画像</comment>
<comment xml:lang="it">Immagine DICOM</comment>
+ <comment xml:lang="is">DICOM mynd</comment>
<comment xml:lang="id">Citra DICOM</comment>
<comment xml:lang="ia">Imagine DICOM</comment>
<comment xml:lang="hu">DICOM kép</comment>
@@ -29021,6 +30301,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge DICOM</comment>
<comment xml:lang="bg">Изображение — DICOM</comment>
<comment xml:lang="be@latin">Vyjava DICOM</comment>
+ <comment xml:lang="be">выява DICOM</comment>
<comment xml:lang="ar">صورة DICOM</comment>
<comment xml:lang="af">DICOM-beeld</comment>
<acronym>DICOM</acronym>
@@ -29041,8 +30322,9 @@ command to generate the output files.
<comment xml:lang="tr">DocBook belgesi</comment>
<comment xml:lang="sv">DocBook-dokument</comment>
<comment xml:lang="sr">Док Бук документ</comment>
- <comment xml:lang="sq">Dokument DocBook</comment>
+ <comment xml:lang="sq">dokument DocBook</comment>
<comment xml:lang="sl">Dokument DocBook</comment>
+ <comment xml:lang="si">DocBook ලේඛනය</comment>
<comment xml:lang="sk">Dokument DocBook</comment>
<comment xml:lang="ru">Документ DocBook</comment>
<comment xml:lang="ro">Document DocBook</comment>
@@ -29060,6 +30342,7 @@ command to generate the output files.
<comment xml:lang="ka">DocBook-ის დოკუმენტი</comment>
<comment xml:lang="ja">DocBook ドキュメント</comment>
<comment xml:lang="it">Documento DocBook</comment>
+ <comment xml:lang="is">DocBook skjal</comment>
<comment xml:lang="id">Dokumen DocBook</comment>
<comment xml:lang="ia">Documento DocBook</comment>
<comment xml:lang="hu">DocBook dokumentum</comment>
@@ -29082,6 +30365,7 @@ command to generate the output files.
<comment xml:lang="ca">document DocBook</comment>
<comment xml:lang="bg">Документ — DocBook</comment>
<comment xml:lang="be@latin">Dakument DocBook</comment>
+ <comment xml:lang="be">дакумент DocBook</comment>
<comment xml:lang="ast">Documentu DocBook</comment>
<comment xml:lang="ar">مستند DocBook</comment>
<comment xml:lang="af">DocBook-dokument</comment>
@@ -29107,8 +30391,9 @@ command to generate the output files.
<comment xml:lang="tr">DIB görüntüsü</comment>
<comment xml:lang="sv">DIB-bild</comment>
<comment xml:lang="sr">ДИБ слика</comment>
- <comment xml:lang="sq">Figurë DIB</comment>
+ <comment xml:lang="sq">figurë DIB</comment>
<comment xml:lang="sl">Slikovna datoteka DIB</comment>
+ <comment xml:lang="si">DIB රූපය</comment>
<comment xml:lang="sk">Obrázok DIB</comment>
<comment xml:lang="ru">Изображение DIB</comment>
<comment xml:lang="ro">Imagine DIB</comment>
@@ -29126,6 +30411,7 @@ command to generate the output files.
<comment xml:lang="ka">DIB გამოსახულება</comment>
<comment xml:lang="ja">DIB 画像</comment>
<comment xml:lang="it">Immagine DIB</comment>
+ <comment xml:lang="is">DIB mynd</comment>
<comment xml:lang="id">Citra DIB</comment>
<comment xml:lang="ia">Imagine DIB</comment>
<comment xml:lang="hu">DIB kép</comment>
@@ -29148,6 +30434,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge DIB</comment>
<comment xml:lang="bg">Изображение — DIB</comment>
<comment xml:lang="be@latin">Vyjava DIB</comment>
+ <comment xml:lang="be">выява DIB</comment>
<comment xml:lang="ar">صورة DIB</comment>
<comment xml:lang="af">DIB-beeld</comment>
<acronym>DIB</acronym>
@@ -29165,8 +30452,9 @@ command to generate the output files.
<comment xml:lang="tr">DjVu görüntüsü</comment>
<comment xml:lang="sv">DjVu-bild</comment>
<comment xml:lang="sr">ДјВу слика</comment>
- <comment xml:lang="sq">Figurë DjVu</comment>
+ <comment xml:lang="sq">figurë DjVu</comment>
<comment xml:lang="sl">Slikovna datoteka DjVu</comment>
+ <comment xml:lang="si">DjVu රූපය</comment>
<comment xml:lang="sk">Obrázok DjVu</comment>
<comment xml:lang="ru">Изображение DjVu</comment>
<comment xml:lang="ro">Imagine DjVu</comment>
@@ -29185,6 +30473,7 @@ command to generate the output files.
<comment xml:lang="ka">DjVu გამოსახულება</comment>
<comment xml:lang="ja">DjVu 画像</comment>
<comment xml:lang="it">Immagine DjVu</comment>
+ <comment xml:lang="is">DjVu mynd</comment>
<comment xml:lang="id">Citra DjVu</comment>
<comment xml:lang="ia">Imagine DjVu</comment>
<comment xml:lang="hu">DjVu-kép</comment>
@@ -29207,6 +30496,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge DjVu</comment>
<comment xml:lang="bg">Изображение — DjVu</comment>
<comment xml:lang="be@latin">Vyjava DjVu</comment>
+ <comment xml:lang="be">выява DjVu</comment>
<comment xml:lang="ar">صورة DjVu</comment>
<comment xml:lang="af">DjVu-beeld</comment>
<alias type="image/x-djvu"/>
@@ -29230,23 +30520,28 @@ command to generate the output files.
<comment xml:lang="tr">DjVu belgesi</comment>
<comment xml:lang="sv">DjVu-dokument</comment>
<comment xml:lang="sr">ДјВу документ</comment>
+ <comment xml:lang="sq">dokument DjVu</comment>
<comment xml:lang="sl">Dokument DjVu</comment>
+ <comment xml:lang="si">DjVu ලේඛනය</comment>
<comment xml:lang="sk">Dokument DjVu</comment>
<comment xml:lang="ru">Документ DjVu</comment>
<comment xml:lang="pt_BR">Documento DjVu</comment>
<comment xml:lang="pt">documento DjVu</comment>
<comment xml:lang="pl">Dokument DjVu</comment>
<comment xml:lang="oc">document DjVu</comment>
+ <comment xml:lang="nl">DjVu-document</comment>
<comment xml:lang="lt">DjVu dokumentas</comment>
<comment xml:lang="ko">DjVu 문서</comment>
<comment xml:lang="kk">DjVu құжаты</comment>
<comment xml:lang="ja">DjVu ドキュメント</comment>
<comment xml:lang="it">Documento DjVu</comment>
+ <comment xml:lang="is">DjVu skjal</comment>
<comment xml:lang="id">Dokumen DjVu</comment>
<comment xml:lang="ia">Documento DjVu</comment>
<comment xml:lang="hu">DjVu dokumentum</comment>
<comment xml:lang="hr">DjVu dokument</comment>
<comment xml:lang="he">מסמך DjVu</comment>
+ <comment xml:lang="gl">Documento DjVu</comment>
<comment xml:lang="ga">cáipéis DjVu</comment>
<comment xml:lang="fur">document DjVu</comment>
<comment xml:lang="fr">document DjVu</comment>
@@ -29260,6 +30555,7 @@ command to generate the output files.
<comment xml:lang="cs">dokument DjVu</comment>
<comment xml:lang="ca">document DjVu</comment>
<comment xml:lang="bg">Документ — DjVu</comment>
+ <comment xml:lang="be">дакумент DjVu</comment>
<comment xml:lang="ast">Documentu DjVu</comment>
<comment xml:lang="ar">مستند DjVu</comment>
<comment xml:lang="af">DjVu-dokument</comment>
@@ -29285,8 +30581,9 @@ command to generate the output files.
<comment xml:lang="tr">DPX görüntüsü</comment>
<comment xml:lang="sv">DPX-bild</comment>
<comment xml:lang="sr">ДПИкс слика</comment>
- <comment xml:lang="sq">Figurë DPX</comment>
+ <comment xml:lang="sq">figurë DPX</comment>
<comment xml:lang="sl">Slikovna datoteka DPX</comment>
+ <comment xml:lang="si">DPX රූපය</comment>
<comment xml:lang="sk">Obrázok DPX</comment>
<comment xml:lang="ru">Изображение DPX</comment>
<comment xml:lang="ro">Imagine DPX</comment>
@@ -29304,6 +30601,7 @@ command to generate the output files.
<comment xml:lang="ka">DPX გამოსახულება</comment>
<comment xml:lang="ja">DPX 画像</comment>
<comment xml:lang="it">Immagine DPX</comment>
+ <comment xml:lang="is">DPX mynd</comment>
<comment xml:lang="id">Citra DPX</comment>
<comment xml:lang="ia">Imagine DPX</comment>
<comment xml:lang="hu">DPX kép</comment>
@@ -29326,6 +30624,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge DPX</comment>
<comment xml:lang="bg">Изображение — DPX</comment>
<comment xml:lang="be@latin">Vyjava DPX</comment>
+ <comment xml:lang="be">выява DPX</comment>
<comment xml:lang="ar">صورة DPX</comment>
<comment xml:lang="af">DPX-beeld</comment>
<acronym>DPX</acronym>
@@ -29343,8 +30642,9 @@ command to generate the output files.
<comment xml:lang="tr">EPS görüntüsü</comment>
<comment xml:lang="sv">EPS-bild</comment>
<comment xml:lang="sr">ЕПС слика</comment>
- <comment xml:lang="sq">Figurë EPS</comment>
+ <comment xml:lang="sq">figurë EPS</comment>
<comment xml:lang="sl">Slikovna datoteka EPS</comment>
+ <comment xml:lang="si">EPS රූපය</comment>
<comment xml:lang="sk">Obrázok EPS</comment>
<comment xml:lang="ru">Изображение EPS</comment>
<comment xml:lang="ro">Imagine EPS</comment>
@@ -29362,6 +30662,7 @@ command to generate the output files.
<comment xml:lang="ka">EPS გამოსახულება</comment>
<comment xml:lang="ja">EPS 画像</comment>
<comment xml:lang="it">Immagine EPS</comment>
+ <comment xml:lang="is">EPS mynd</comment>
<comment xml:lang="id">Citra EPS</comment>
<comment xml:lang="ia">Imagine EPS</comment>
<comment xml:lang="hu">EPS kép</comment>
@@ -29384,6 +30685,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge EPS</comment>
<comment xml:lang="bg">Изображение — EPS</comment>
<comment xml:lang="be@latin">Vyjava EPS</comment>
+ <comment xml:lang="be">выява EPS</comment>
<comment xml:lang="ar">صورة EPS</comment>
<comment xml:lang="af">EPS-beeld</comment>
<acronym>EPS</acronym>
@@ -29411,8 +30713,9 @@ command to generate the output files.
<comment xml:lang="tr">FITS belgesi</comment>
<comment xml:lang="sv">FITS-dokument</comment>
<comment xml:lang="sr">ФИТС документ</comment>
- <comment xml:lang="sq">Dokument FITS</comment>
+ <comment xml:lang="sq">dokument FITS</comment>
<comment xml:lang="sl">Dokument FITS</comment>
+ <comment xml:lang="si">FITS ලේඛනය</comment>
<comment xml:lang="sk">Dokument FITS</comment>
<comment xml:lang="ru">Документ FITS</comment>
<comment xml:lang="ro">Document FITS</comment>
@@ -29430,6 +30733,7 @@ command to generate the output files.
<comment xml:lang="ka">FITS დოკუმენტი</comment>
<comment xml:lang="ja">FITS ドキュメント</comment>
<comment xml:lang="it">Documento FITS</comment>
+ <comment xml:lang="is">FITS skjalskjal</comment>
<comment xml:lang="id">Dokumen FITS</comment>
<comment xml:lang="ia">Documento FITS</comment>
<comment xml:lang="hu">FITS dokumentum</comment>
@@ -29452,6 +30756,7 @@ command to generate the output files.
<comment xml:lang="ca">document FITS</comment>
<comment xml:lang="bg">Документ — FITS</comment>
<comment xml:lang="be@latin">Dakument FITS</comment>
+ <comment xml:lang="be">дакумент FITS</comment>
<comment xml:lang="ast">Documentu FITS</comment>
<comment xml:lang="ar">مستند FITS</comment>
<comment xml:lang="af">FITS-dokument</comment>
@@ -29475,8 +30780,9 @@ command to generate the output files.
<comment xml:lang="tr">FPX görüntüsü</comment>
<comment xml:lang="sv">FPX-bild</comment>
<comment xml:lang="sr">ФПИкс слика</comment>
- <comment xml:lang="sq">Figurë FPX</comment>
+ <comment xml:lang="sq">figurë FPX</comment>
<comment xml:lang="sl">Slikovna datoteka FPX</comment>
+ <comment xml:lang="si">FPX රූපය</comment>
<comment xml:lang="sk">Obrázok FPX</comment>
<comment xml:lang="ru">Изображение FPX</comment>
<comment xml:lang="ro">Imagine FPX</comment>
@@ -29494,6 +30800,7 @@ command to generate the output files.
<comment xml:lang="ka">FPX გამოსახულება</comment>
<comment xml:lang="ja">FPX 画像</comment>
<comment xml:lang="it">Immagine FPX</comment>
+ <comment xml:lang="is">FPX mynd</comment>
<comment xml:lang="id">Citra FPX</comment>
<comment xml:lang="ia">Imagine FPX</comment>
<comment xml:lang="hu">FPX kép</comment>
@@ -29516,6 +30823,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge FPX</comment>
<comment xml:lang="bg">Изображение — FPX</comment>
<comment xml:lang="be@latin">Vyjava FPX</comment>
+ <comment xml:lang="be">выява FPX</comment>
<comment xml:lang="ar">صورة FPX</comment>
<comment xml:lang="af">FPX-beeld</comment>
<acronym>FPX</acronym>
@@ -29533,8 +30841,9 @@ command to generate the output files.
<comment xml:lang="tr">EPS görüntüsü (gzip ile sıkıştırılmış)</comment>
<comment xml:lang="sv">EPS-bild (gzip-komprimerad)</comment>
<comment xml:lang="sr">ЕПС слика (запакована гзип-ом)</comment>
- <comment xml:lang="sq">Figurë EPS (e kompresuar me gzip)</comment>
+ <comment xml:lang="sq">figurë EPS (ngjeshur me gzip)</comment>
<comment xml:lang="sl">Slikovna datoteka EPS (stisnjena z gzip)</comment>
+ <comment xml:lang="si">EPS රූපය (gzip සම්පීඩිත)</comment>
<comment xml:lang="sk">Obrázok EPS (komprimovaný pomocou gzip)</comment>
<comment xml:lang="ru">Изображение EPS (сжатое gzip)</comment>
<comment xml:lang="ro">Imagine EPS (compresie gzip)</comment>
@@ -29552,6 +30861,7 @@ command to generate the output files.
<comment xml:lang="ka">EPS გამოსახულება (gzip-ით შეკუმშული)</comment>
<comment xml:lang="ja">EPS 画像 (gzip 圧縮)</comment>
<comment xml:lang="it">Immagine EPS (compressa con gzip)</comment>
+ <comment xml:lang="is">EPS mynd (gzip-þjöppuð)</comment>
<comment xml:lang="id">Citra EPS (terkompresi gzip)</comment>
<comment xml:lang="ia">Imagine EPS (comprimite con gzip)</comment>
<comment xml:lang="hu">EPS kép (gzip tömörítésű)</comment>
@@ -29564,7 +30874,7 @@ command to generate the output files.
<comment xml:lang="fo">EPS mynd (gzip-stappað)</comment>
<comment xml:lang="fi">EPS-kuva (gzip-pakattu)</comment>
<comment xml:lang="eu">EPS irudia (gzip-ekin konprimitua)</comment>
- <comment xml:lang="es">imagen EPS (comprimida con gzip)</comment>
+ <comment xml:lang="es">imagen EPS (comprimida con GZIP)</comment>
<comment xml:lang="en_GB">EPS image (gzip-compressed)</comment>
<comment xml:lang="el">Εικόνα EPS (συμπιεσμένη gzip)</comment>
<comment xml:lang="de">EPS-Bild (gzip-komprimiert)</comment>
@@ -29573,6 +30883,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge EPS (amb compressió gzip)</comment>
<comment xml:lang="bg">Изображение — EPS, компресирано с gzip</comment>
<comment xml:lang="be@latin">Vyjava EPS (gzip-skampresavanaja)</comment>
+ <comment xml:lang="be">выява EPS (сцісканне gzip)</comment>
<comment xml:lang="ar">صورة EPS (مضغوط-gzip)</comment>
<comment xml:lang="af">EPS-beeld (gzip-saamgepers)</comment>
<sub-class-of type="application/gzip"/>
@@ -29588,23 +30899,29 @@ command to generate the output files.
<comment xml:lang="tr">Windows simgesi</comment>
<comment xml:lang="sv">Windows-ikon</comment>
<comment xml:lang="sr">Иконица Виндоуза</comment>
+ <comment xml:lang="sq">ikonë Windows</comment>
<comment xml:lang="sl">Ikona Windows</comment>
+ <comment xml:lang="si">වින්ඩෝස් නිරූපකය</comment>
<comment xml:lang="sk">Ikona Windows</comment>
<comment xml:lang="ru">Значок Windows</comment>
<comment xml:lang="pt_BR">Ícone do Windows</comment>
<comment xml:lang="pt">ícone Windows</comment>
<comment xml:lang="pl">Ikona Windows</comment>
<comment xml:lang="oc">icòna Windows</comment>
+ <comment xml:lang="nl">Windows-pictogram</comment>
<comment xml:lang="lt">Windows piktograma</comment>
<comment xml:lang="ko">Windows 아이콘</comment>
<comment xml:lang="kk">Windows таңбашасы</comment>
+ <comment xml:lang="ka">Windows icon</comment>
<comment xml:lang="ja">Windows アイコン</comment>
<comment xml:lang="it">Icona Windows</comment>
+ <comment xml:lang="is">Windows táknmynd</comment>
<comment xml:lang="id">Ikon Windows</comment>
<comment xml:lang="ia">Icone pro Windows</comment>
<comment xml:lang="hu">Windows ikon</comment>
<comment xml:lang="hr">Windows ikona</comment>
<comment xml:lang="he">סמל של Windows</comment>
+ <comment xml:lang="gl">Icona de Windows</comment>
<comment xml:lang="ga">deilbhín Windows</comment>
<comment xml:lang="fur">icone Windows</comment>
<comment xml:lang="fr">icône Windows</comment>
@@ -29618,6 +30935,7 @@ command to generate the output files.
<comment xml:lang="cs">ikona Windows</comment>
<comment xml:lang="ca">icona de Windows</comment>
<comment xml:lang="bg">Икона — Windows</comment>
+ <comment xml:lang="be">значок Windows</comment>
<comment xml:lang="ar">أيقونة ويندوز</comment>
<comment xml:lang="af">Windows-ikoon</comment>
<magic>
@@ -29642,8 +30960,9 @@ command to generate the output files.
<comment xml:lang="tr">MacOS X simgesi</comment>
<comment xml:lang="sv">MacOS X-ikon</comment>
<comment xml:lang="sr">МекОС Икс иконица</comment>
- <comment xml:lang="sq">Ikonë MacOS X</comment>
+ <comment xml:lang="sq">ikonë MacOS X</comment>
<comment xml:lang="sl">Datoteka ikone MacOS X</comment>
+ <comment xml:lang="si">MacOS X නිරූපකය</comment>
<comment xml:lang="sk">Ikona MacOS X</comment>
<comment xml:lang="ru">Значок MacOS X</comment>
<comment xml:lang="ro">Iconiță MacOS X</comment>
@@ -29661,6 +30980,7 @@ command to generate the output files.
<comment xml:lang="ka">MacOS X-ის ხატულა</comment>
<comment xml:lang="ja">MacOS X アイコン</comment>
<comment xml:lang="it">Icona MacOS X</comment>
+ <comment xml:lang="is">MacOS X táknmynd</comment>
<comment xml:lang="id">Ikon MacOS X</comment>
<comment xml:lang="ia">Icone de Mac OS X</comment>
<comment xml:lang="hu">MacOS X ikon</comment>
@@ -29683,6 +31003,7 @@ command to generate the output files.
<comment xml:lang="ca">icona MacOS X</comment>
<comment xml:lang="bg">Икона — MacOS X</comment>
<comment xml:lang="be@latin">Ikona MacOS X</comment>
+ <comment xml:lang="be">значок MacOS X</comment>
<comment xml:lang="ar">أيقونة MacOS X</comment>
<comment xml:lang="af">MacOS X-ikoon</comment>
<glob pattern="*.icns"/>
@@ -29699,8 +31020,9 @@ command to generate the output files.
<comment xml:lang="tr">ILBM görüntüsü</comment>
<comment xml:lang="sv">ILBM-bild</comment>
<comment xml:lang="sr">ИЛБМ слика</comment>
- <comment xml:lang="sq">Figurë ILBM</comment>
+ <comment xml:lang="sq">figurë ILBM</comment>
<comment xml:lang="sl">Slikovna datoteka ILBM</comment>
+ <comment xml:lang="si">ILBM රූපය</comment>
<comment xml:lang="sk">Obrázok ILMB</comment>
<comment xml:lang="ru">Изображение ILBM</comment>
<comment xml:lang="ro">Imagine ILBM</comment>
@@ -29718,6 +31040,7 @@ command to generate the output files.
<comment xml:lang="kk">ILBM суреті</comment>
<comment xml:lang="ja">ILBM 画像</comment>
<comment xml:lang="it">Immagine ILBM</comment>
+ <comment xml:lang="is">ILBM mynd</comment>
<comment xml:lang="id">Citra ILBM</comment>
<comment xml:lang="ia">Imagine ILBM</comment>
<comment xml:lang="hu">ILBM-kép</comment>
@@ -29741,6 +31064,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge ILBM</comment>
<comment xml:lang="bg">Изображение — ILBM</comment>
<comment xml:lang="be@latin">Vyjava ILBM</comment>
+ <comment xml:lang="be">выява ILBM</comment>
<comment xml:lang="az">ILBM rəsmi</comment>
<comment xml:lang="ar">صورة ILBM</comment>
<comment xml:lang="af">ILBM-beeld</comment>
@@ -29765,8 +31089,9 @@ command to generate the output files.
<comment xml:lang="tr">JNG görüntüsü</comment>
<comment xml:lang="sv">JNG-bild</comment>
<comment xml:lang="sr">ЈНГ слика</comment>
- <comment xml:lang="sq">Figurë JNG</comment>
+ <comment xml:lang="sq">figurë JNG</comment>
<comment xml:lang="sl">Slikovna datoteka JNG</comment>
+ <comment xml:lang="si">JNG රූපය</comment>
<comment xml:lang="sk">Obrázok JNG</comment>
<comment xml:lang="ru">Изображение JNG</comment>
<comment xml:lang="ro">Imagine JNG</comment>
@@ -29784,6 +31109,7 @@ command to generate the output files.
<comment xml:lang="kk">JNG суреті</comment>
<comment xml:lang="ja">JNG 画像</comment>
<comment xml:lang="it">Immagine JNG</comment>
+ <comment xml:lang="is">JNG mynd</comment>
<comment xml:lang="id">Citra JNG</comment>
<comment xml:lang="ia">Imagine JNG</comment>
<comment xml:lang="hu">JNG-kép</comment>
@@ -29807,6 +31133,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge JNG</comment>
<comment xml:lang="bg">Изображение — JNG</comment>
<comment xml:lang="be@latin">Vyjava JNG</comment>
+ <comment xml:lang="be">выява JNG</comment>
<comment xml:lang="az">JNG rəsmi</comment>
<comment xml:lang="ar">صورة JNG</comment>
<comment xml:lang="af">JNG-beeld</comment>
@@ -29823,8 +31150,9 @@ command to generate the output files.
<comment xml:lang="tr">LightWave nesnesi</comment>
<comment xml:lang="sv">LightWave-objekt</comment>
<comment xml:lang="sr">Лајт Вејв објекат</comment>
- <comment xml:lang="sq">Objekt LightWave</comment>
+ <comment xml:lang="sq">objekt LightWave</comment>
<comment xml:lang="sl">Datoteka predmeta LightWave</comment>
+ <comment xml:lang="si">LightWave වස්තුව</comment>
<comment xml:lang="sk">Objekt LightWave</comment>
<comment xml:lang="ru">Объект LightWave</comment>
<comment xml:lang="ro">Obiect LightWave</comment>
@@ -29842,6 +31170,7 @@ command to generate the output files.
<comment xml:lang="kk">LightWave объекті</comment>
<comment xml:lang="ja">LightWave オブジェクト</comment>
<comment xml:lang="it">Oggetto LightWave</comment>
+ <comment xml:lang="is">LightWave hlutur</comment>
<comment xml:lang="id">Proyek LightWave</comment>
<comment xml:lang="ia">Objecto LightWave</comment>
<comment xml:lang="hu">LightWave-objektum</comment>
@@ -29865,6 +31194,7 @@ command to generate the output files.
<comment xml:lang="ca">objecte de LightWave</comment>
<comment xml:lang="bg">Обект — LightWave</comment>
<comment xml:lang="be@latin">Abjekt LightWave</comment>
+ <comment xml:lang="be">аб'ект LightWave</comment>
<comment xml:lang="az">LightWave cismi</comment>
<comment xml:lang="ar">كائن LightWave</comment>
<comment xml:lang="af">LightWave-objek</comment>
@@ -29880,8 +31210,9 @@ command to generate the output files.
<comment xml:lang="tr">LightWave sahnesi</comment>
<comment xml:lang="sv">LightWave-scen</comment>
<comment xml:lang="sr">Лајт Вејв сцена</comment>
- <comment xml:lang="sq">Skenë LightWave</comment>
+ <comment xml:lang="sq">skenë LightWave</comment>
<comment xml:lang="sl">Datoteka scene LightWave</comment>
+ <comment xml:lang="si">LightWave දර්ශනය</comment>
<comment xml:lang="sk">Scéna LightWave</comment>
<comment xml:lang="ru">Сцена LightWave</comment>
<comment xml:lang="ro">Scenă LightWave</comment>
@@ -29899,6 +31230,7 @@ command to generate the output files.
<comment xml:lang="kk">LightWave сахнасы</comment>
<comment xml:lang="ja">LightWave シーン</comment>
<comment xml:lang="it">Scena LightWave</comment>
+ <comment xml:lang="is">LightWave sviðsmynd</comment>
<comment xml:lang="id">Scene LightWave</comment>
<comment xml:lang="ia">Scena LightWave</comment>
<comment xml:lang="hu">LightWave-jelenet</comment>
@@ -29922,6 +31254,7 @@ command to generate the output files.
<comment xml:lang="ca">escena de LightWave</comment>
<comment xml:lang="bg">Сцена — LightWave</comment>
<comment xml:lang="be@latin">Scena LightWave</comment>
+ <comment xml:lang="be">сцэна LightWave</comment>
<comment xml:lang="az">LightWave səhnəsi</comment>
<comment xml:lang="ar">مشهد LightWave</comment>
<comment xml:lang="af">LightWave-toneel</comment>
@@ -29936,8 +31269,9 @@ command to generate the output files.
<comment xml:lang="tr">MacPaint bit eşlem görüntüsü</comment>
<comment xml:lang="sv">MacPaint Bitmap-bild</comment>
<comment xml:lang="sr">Мек Пеинт битмап слика</comment>
- <comment xml:lang="sq">Figurë BitMap MacPaint</comment>
+ <comment xml:lang="sq">figurë BitMap MacPaint</comment>
<comment xml:lang="sl">Slikovna bitna datoteka MacPaint</comment>
+ <comment xml:lang="si">MacPaint Bitmap රූපය</comment>
<comment xml:lang="sk">Obrázok MacPaint Bitmap</comment>
<comment xml:lang="ru">Растровое изображение MacPaint</comment>
<comment xml:lang="ro">Imagine MacPaint Bitmap</comment>
@@ -29954,6 +31288,7 @@ command to generate the output files.
<comment xml:lang="kk">MacPaint растрлық суреті</comment>
<comment xml:lang="ja">MacPaint ビットマップ画像</comment>
<comment xml:lang="it">Immagine Bitmap MacPaint</comment>
+ <comment xml:lang="is">MacPaint bitamynd</comment>
<comment xml:lang="id">Citra MacPaint Bitmap</comment>
<comment xml:lang="ia">Imagine bitmap de MacPaint</comment>
<comment xml:lang="hu">MacPaint bitkép</comment>
@@ -29975,6 +31310,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge de mapa de bits MacPaint</comment>
<comment xml:lang="bg">Изображение — MacPaint Bitmap</comment>
<comment xml:lang="be@latin">Bitmapnaja vyjava MacPaint</comment>
+ <comment xml:lang="be">растравая выява MacPaint</comment>
<comment xml:lang="ar">صورة MacPaint Bitmap</comment>
<comment xml:lang="af">MacPaint-roosterbeeld</comment>
<glob pattern="*.pntg"/>
@@ -29988,8 +31324,9 @@ command to generate the output files.
<comment xml:lang="tr">Ofis çizimi</comment>
<comment xml:lang="sv">Office-teckning</comment>
<comment xml:lang="sr">Канцеларијски цртеж</comment>
- <comment xml:lang="sq">Vizatim Office</comment>
+ <comment xml:lang="sq">vizatim Office</comment>
<comment xml:lang="sl">Datoteka risbe Office</comment>
+ <comment xml:lang="si">කාර්යාල ඇඳීම</comment>
<comment xml:lang="sk">Kresba Office</comment>
<comment xml:lang="ru">Рисунок Office</comment>
<comment xml:lang="ro">Desen Office</comment>
@@ -30006,6 +31343,7 @@ command to generate the output files.
<comment xml:lang="kk">Office суреті</comment>
<comment xml:lang="ja">Office ドロー</comment>
<comment xml:lang="it">Disegno Office</comment>
+ <comment xml:lang="is">Office teikning</comment>
<comment xml:lang="id">Gambar Office</comment>
<comment xml:lang="ia">Designo Office</comment>
<comment xml:lang="hu">Office rajz</comment>
@@ -30027,6 +31365,7 @@ command to generate the output files.
<comment xml:lang="ca">dibuix d'Office</comment>
<comment xml:lang="bg">Чертеж — Office</comment>
<comment xml:lang="be@latin">Ofisny rysunak</comment>
+ <comment xml:lang="be">рысунак Office</comment>
<comment xml:lang="ar">تصميم أوفيس</comment>
<comment xml:lang="af">Office-tekening</comment>
<glob pattern="*.msod"/>
@@ -30040,8 +31379,9 @@ command to generate the output files.
<comment xml:lang="tr">NIFF görüntüsü</comment>
<comment xml:lang="sv">NIFF-bild</comment>
<comment xml:lang="sr">НИФФ слика</comment>
- <comment xml:lang="sq">Figurë NIFF</comment>
+ <comment xml:lang="sq">figurë NIFF</comment>
<comment xml:lang="sl">Slikovna datoteka NIFF</comment>
+ <comment xml:lang="si">NIFF රූපය</comment>
<comment xml:lang="sk">Obrázok NIFF</comment>
<comment xml:lang="ru">Изображение NIFF</comment>
<comment xml:lang="ro">Imagine NIF</comment>
@@ -30058,6 +31398,7 @@ command to generate the output files.
<comment xml:lang="kk">NIFF суреті</comment>
<comment xml:lang="ja">NIFF 画像</comment>
<comment xml:lang="it">Immagine NIFF</comment>
+ <comment xml:lang="is">NIFF mynd</comment>
<comment xml:lang="id">Citra NIFF</comment>
<comment xml:lang="ia">Imagine NIFF</comment>
<comment xml:lang="hu">NIFF kép</comment>
@@ -30080,6 +31421,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge NIFF</comment>
<comment xml:lang="bg">Изображение — NIFF</comment>
<comment xml:lang="be@latin">Vyjava NIFF</comment>
+ <comment xml:lang="be">выява NIFF</comment>
<comment xml:lang="ar">صورة NIFF</comment>
<comment xml:lang="af">NIFF-beeld</comment>
<acronym>NIFF</acronym>
@@ -30097,8 +31439,9 @@ command to generate the output files.
<comment xml:lang="tr">PCX görüntüsü</comment>
<comment xml:lang="sv">PCX-bild</comment>
<comment xml:lang="sr">ПЦИкс слика</comment>
- <comment xml:lang="sq">Figurë PCX</comment>
+ <comment xml:lang="sq">figurë PCX</comment>
<comment xml:lang="sl">Slikovna datoteka PCX</comment>
+ <comment xml:lang="si">PCX රූපය</comment>
<comment xml:lang="sk">Obrázok PCX</comment>
<comment xml:lang="ru">Изображение PCX</comment>
<comment xml:lang="ro">Imagine PCX</comment>
@@ -30115,6 +31458,7 @@ command to generate the output files.
<comment xml:lang="kk">PCX суреті</comment>
<comment xml:lang="ja">PCX 画像</comment>
<comment xml:lang="it">Immagine PCX</comment>
+ <comment xml:lang="is">PCX mynd</comment>
<comment xml:lang="id">Citra PCX</comment>
<comment xml:lang="ia">Imagine PCX</comment>
<comment xml:lang="hu">PCX kép</comment>
@@ -30137,6 +31481,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge PCX</comment>
<comment xml:lang="bg">Изображение — PCX</comment>
<comment xml:lang="be@latin">Vyjava PCX</comment>
+ <comment xml:lang="be">выява PCX</comment>
<comment xml:lang="ar">صورة PCX</comment>
<comment xml:lang="af">PCX-beeld</comment>
<acronym>PCX</acronym>
@@ -30161,8 +31506,9 @@ command to generate the output files.
<comment xml:lang="tr">PCD görüntüsü</comment>
<comment xml:lang="sv">PCD-bild</comment>
<comment xml:lang="sr">ПЦД слика</comment>
- <comment xml:lang="sq">Figurë PCD</comment>
+ <comment xml:lang="sq">figurë PCD</comment>
<comment xml:lang="sl">Slikovna datoteka PCD</comment>
+ <comment xml:lang="si">PCD රූපය</comment>
<comment xml:lang="sk">Obrázok PCD</comment>
<comment xml:lang="ru">Изображение PCD</comment>
<comment xml:lang="ro">Imagine PCD</comment>
@@ -30180,6 +31526,7 @@ command to generate the output files.
<comment xml:lang="ka">PCD გამოსახულება</comment>
<comment xml:lang="ja">PCD 画像</comment>
<comment xml:lang="it">Immagine PCD</comment>
+ <comment xml:lang="is">PCD mynd</comment>
<comment xml:lang="id">Citra PCD</comment>
<comment xml:lang="ia">Imagine PCD</comment>
<comment xml:lang="hu">PCD kép</comment>
@@ -30202,10 +31549,12 @@ command to generate the output files.
<comment xml:lang="ca">imatge PCD</comment>
<comment xml:lang="bg">Изображение — PCD</comment>
<comment xml:lang="be@latin">Vyjava PCD</comment>
+ <comment xml:lang="be">выява PCD</comment>
<comment xml:lang="ar">صورة PCD</comment>
<comment xml:lang="af">PCD-beeld</comment>
<acronym>PCD</acronym>
<expanded-acronym>PhotoCD</expanded-acronym>
+ <generic-icon name="media-optical"/>
<glob pattern="*.pcd"/>
</mime-type>
<mime-type type="image/x-portable-anymap">
@@ -30217,8 +31566,9 @@ command to generate the output files.
<comment xml:lang="tr">PNM görüntüsü</comment>
<comment xml:lang="sv">PNM-bild</comment>
<comment xml:lang="sr">ПНМ слика</comment>
- <comment xml:lang="sq">Figurë PNM</comment>
+ <comment xml:lang="sq">figurë PNM</comment>
<comment xml:lang="sl">Slikovna datoteka PNM</comment>
+ <comment xml:lang="si">PNM රූපය</comment>
<comment xml:lang="sk">Obrázok PNM</comment>
<comment xml:lang="ru">Изображение PNM</comment>
<comment xml:lang="ro">Imagine PNM</comment>
@@ -30234,8 +31584,10 @@ command to generate the output files.
<comment xml:lang="lt">PNM paveikslėlis</comment>
<comment xml:lang="ko">PNM 그림</comment>
<comment xml:lang="kk">PNM суреті</comment>
+ <comment xml:lang="ka">PNM გამოსახულება</comment>
<comment xml:lang="ja">PNM 画像</comment>
<comment xml:lang="it">Immagine PNM</comment>
+ <comment xml:lang="is">PNM mynd</comment>
<comment xml:lang="id">Citra PNM</comment>
<comment xml:lang="ia">Imagine PNM</comment>
<comment xml:lang="hu">PNM-kép</comment>
@@ -30259,6 +31611,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge PNM</comment>
<comment xml:lang="bg">Изображение — PNM</comment>
<comment xml:lang="be@latin">Vyjava PNM</comment>
+ <comment xml:lang="be">выява PNM</comment>
<comment xml:lang="az">PNM rəsmi</comment>
<comment xml:lang="ar">صورة PNM</comment>
<comment xml:lang="af">PNM-beeld</comment>
@@ -30275,8 +31628,9 @@ command to generate the output files.
<comment xml:lang="tr">PBM görüntüsü</comment>
<comment xml:lang="sv">PBM-bild</comment>
<comment xml:lang="sr">ПБМ слика</comment>
- <comment xml:lang="sq">Figurë PBM</comment>
+ <comment xml:lang="sq">figurë PBM</comment>
<comment xml:lang="sl">Slikovna datoteka PBM</comment>
+ <comment xml:lang="si">PBM රූපය</comment>
<comment xml:lang="sk">Obrázok PBM</comment>
<comment xml:lang="ru">Изображение PBM</comment>
<comment xml:lang="ro">Imagine PBM</comment>
@@ -30294,6 +31648,7 @@ command to generate the output files.
<comment xml:lang="ka">PBM გამოსახულება</comment>
<comment xml:lang="ja">PBM 画像</comment>
<comment xml:lang="it">Immagine PBM</comment>
+ <comment xml:lang="is">PBM mynd</comment>
<comment xml:lang="id">Citra PBM</comment>
<comment xml:lang="ia">Imagine PBM</comment>
<comment xml:lang="hu">PBM kép</comment>
@@ -30317,6 +31672,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge PBM</comment>
<comment xml:lang="bg">Изображение — PBM</comment>
<comment xml:lang="be@latin">Vyjava PBM</comment>
+ <comment xml:lang="be">выява PBM</comment>
<comment xml:lang="ar">صورة PBM</comment>
<comment xml:lang="af">PBM-beeld</comment>
<acronym>PBM</acronym>
@@ -30347,8 +31703,9 @@ command to generate the output files.
<comment xml:lang="tr">PGM görüntüsü</comment>
<comment xml:lang="sv">PGM-bild</comment>
<comment xml:lang="sr">ПГМ слика</comment>
- <comment xml:lang="sq">Figurë PGM</comment>
+ <comment xml:lang="sq">figurë PGM</comment>
<comment xml:lang="sl">Slikovna datoteka PGM</comment>
+ <comment xml:lang="si">PGM රූපය</comment>
<comment xml:lang="sk">Obrázok PGM</comment>
<comment xml:lang="ru">Изображение PGM</comment>
<comment xml:lang="ro">Imagine PGM</comment>
@@ -30363,8 +31720,10 @@ command to generate the output files.
<comment xml:lang="lt">PGM paveikslėlis</comment>
<comment xml:lang="ko">PGM 그림</comment>
<comment xml:lang="kk">PGM суреті</comment>
+ <comment xml:lang="ka">PGM გამოსახულება</comment>
<comment xml:lang="ja">PGM 画像</comment>
<comment xml:lang="it">Immagine PGM</comment>
+ <comment xml:lang="is">PGM mynd</comment>
<comment xml:lang="id">Citra PGM</comment>
<comment xml:lang="ia">Imagine PGM</comment>
<comment xml:lang="hu">PGM kép</comment>
@@ -30388,6 +31747,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge PGM</comment>
<comment xml:lang="bg">Изображение — PGM</comment>
<comment xml:lang="be@latin">Vyjava PGM</comment>
+ <comment xml:lang="be">выява PGM</comment>
<comment xml:lang="ar">صورة PGM</comment>
<comment xml:lang="af">PGM-beeld</comment>
<acronym>PGM</acronym>
@@ -30418,8 +31778,9 @@ command to generate the output files.
<comment xml:lang="tr">PPM görüntüsü</comment>
<comment xml:lang="sv">PPM-bild</comment>
<comment xml:lang="sr">ППМ слика</comment>
- <comment xml:lang="sq">Figurë PPM</comment>
+ <comment xml:lang="sq">figurë PPM</comment>
<comment xml:lang="sl">Slikovna datoteka PPM</comment>
+ <comment xml:lang="si">PPM රූපය</comment>
<comment xml:lang="sk">Obrázok PPM</comment>
<comment xml:lang="ru">Изображение PPM</comment>
<comment xml:lang="ro">Imagine PPM</comment>
@@ -30434,8 +31795,10 @@ command to generate the output files.
<comment xml:lang="lt">PPM paveikslėlis</comment>
<comment xml:lang="ko">PPM 그림</comment>
<comment xml:lang="kk">PPM суреті</comment>
+ <comment xml:lang="ka">PPM გამოსახულება</comment>
<comment xml:lang="ja">PPM 画像</comment>
<comment xml:lang="it">Immagine PPM</comment>
+ <comment xml:lang="is">PPM mynd</comment>
<comment xml:lang="id">Citra PPM</comment>
<comment xml:lang="ia">Imagine PPM</comment>
<comment xml:lang="hu">PPM kép</comment>
@@ -30459,6 +31822,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge PPM</comment>
<comment xml:lang="bg">Изображение — PPM</comment>
<comment xml:lang="be@latin">Vyjava PPM</comment>
+ <comment xml:lang="be">выява PPM</comment>
<comment xml:lang="ar">صورة PPM</comment>
<comment xml:lang="af">PPM-beeld</comment>
<acronym>PPM</acronym>
@@ -30489,7 +31853,9 @@ command to generate the output files.
<comment xml:lang="tr">Photoshop görüntüsü</comment>
<comment xml:lang="sv">Photoshop-bild</comment>
<comment xml:lang="sr">Фотошоп слика</comment>
+ <comment xml:lang="sq">figurë Photoshop</comment>
<comment xml:lang="sl">Slikovna datoteka Photoshop</comment>
+ <comment xml:lang="si">Photoshop රූපය</comment>
<comment xml:lang="sk">Obrázok Photoshop</comment>
<comment xml:lang="ru">Изображение Photoshop</comment>
<comment xml:lang="ro">Imagine Photoshop</comment>
@@ -30505,6 +31871,7 @@ command to generate the output files.
<comment xml:lang="kk">изображение Photoshop</comment>
<comment xml:lang="ja">Photoshop 画像</comment>
<comment xml:lang="it">Immagine Photoshop</comment>
+ <comment xml:lang="is">Photoshop mynd</comment>
<comment xml:lang="id">Citra Photoshop</comment>
<comment xml:lang="ia">Imagine Photoshop</comment>
<comment xml:lang="hu">Photoshop-kép</comment>
@@ -30526,6 +31893,7 @@ command to generate the output files.
<comment xml:lang="cs">obrázek Photoshop</comment>
<comment xml:lang="ca">imatge de Photoshop</comment>
<comment xml:lang="bg">Изображение — Photoshop</comment>
+ <comment xml:lang="be">выява Photoshop</comment>
<comment xml:lang="ar">صورة فوتوشوب</comment>
<comment xml:lang="af">Photoshop-beeld</comment>
<magic>
@@ -30548,8 +31916,9 @@ command to generate the output files.
<comment xml:lang="tr">RGB görüntüsü</comment>
<comment xml:lang="sv">RGB-bild</comment>
<comment xml:lang="sr">РГБ слика</comment>
- <comment xml:lang="sq">Figurë RGB</comment>
+ <comment xml:lang="sq">figurë RGB</comment>
<comment xml:lang="sl">Slikovna datoteka RGB</comment>
+ <comment xml:lang="si">RGB රූපය</comment>
<comment xml:lang="sk">Obrázok RGB</comment>
<comment xml:lang="ru">Изображение RGB</comment>
<comment xml:lang="ro">Imagine RGB</comment>
@@ -30567,6 +31936,7 @@ command to generate the output files.
<comment xml:lang="kk">RGB суреті</comment>
<comment xml:lang="ja">RGB 画像</comment>
<comment xml:lang="it">Immagine RGB</comment>
+ <comment xml:lang="is">RGB mynd</comment>
<comment xml:lang="id">Citra RGB</comment>
<comment xml:lang="ia">Imagine RGB</comment>
<comment xml:lang="hu">RGB-kép</comment>
@@ -30590,6 +31960,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge RGB</comment>
<comment xml:lang="bg">Изображение — RGB</comment>
<comment xml:lang="be@latin">Vyjava RGB</comment>
+ <comment xml:lang="be">выява RGB</comment>
<comment xml:lang="az">RGB rəsmi</comment>
<comment xml:lang="ar">صورة RGB</comment>
<comment xml:lang="af">RGB-beeld</comment>
@@ -30604,8 +31975,9 @@ command to generate the output files.
<comment xml:lang="tr">SGI görüntüsü</comment>
<comment xml:lang="sv">SGI-bild</comment>
<comment xml:lang="sr">СГИ слика</comment>
- <comment xml:lang="sq">Figurë SGI</comment>
+ <comment xml:lang="sq">figurë SGI</comment>
<comment xml:lang="sl">Slikovna datoteka SGI</comment>
+ <comment xml:lang="si">SGI රූපය</comment>
<comment xml:lang="sk">Obrázok SGI</comment>
<comment xml:lang="ru">Изображение SGI</comment>
<comment xml:lang="ro">Imagine SGI</comment>
@@ -30622,6 +31994,7 @@ command to generate the output files.
<comment xml:lang="kk">SGI суреті</comment>
<comment xml:lang="ja">SGI 画像</comment>
<comment xml:lang="it">Immagine SGI</comment>
+ <comment xml:lang="is">SGI mynd</comment>
<comment xml:lang="id">Citra SGI</comment>
<comment xml:lang="ia">Imagine SGI</comment>
<comment xml:lang="hu">SGI kép</comment>
@@ -30644,6 +32017,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge SGI</comment>
<comment xml:lang="bg">Изображение — SGI</comment>
<comment xml:lang="be@latin">Vyjava SGI</comment>
+ <comment xml:lang="be">выява SGI</comment>
<comment xml:lang="ar">صورة SGI</comment>
<comment xml:lang="af">SGI-beeld</comment>
<glob pattern="*.sgi"/>
@@ -30657,8 +32031,9 @@ command to generate the output files.
<comment xml:lang="tr">Sun raster görüntüsü</comment>
<comment xml:lang="sv">Sun-rasterbild</comment>
<comment xml:lang="sr">слика Сановог растера</comment>
- <comment xml:lang="sq">Figurë raster Sun</comment>
+ <comment xml:lang="sq">figurë raster Sun</comment>
<comment xml:lang="sl">Slikovna rastrska datoteka Sun</comment>
+ <comment xml:lang="si">හිරු රස්ටර් රූපය</comment>
<comment xml:lang="sk">Rastrový obrázok Sun</comment>
<comment xml:lang="ru">Растровое изображение Sun</comment>
<comment xml:lang="ro">Imagine rasterizată Sun</comment>
@@ -30675,6 +32050,7 @@ command to generate the output files.
<comment xml:lang="kk">Sun растрлық суреті</comment>
<comment xml:lang="ja">Sun ラスタ画像</comment>
<comment xml:lang="it">Immagine raster Sun</comment>
+ <comment xml:lang="is">Sun rastamynd</comment>
<comment xml:lang="id">Citra raster Sun</comment>
<comment xml:lang="ia">Imagine raster Sun</comment>
<comment xml:lang="hu">SUN raszterkép</comment>
@@ -30696,6 +32072,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge ràster Sun</comment>
<comment xml:lang="bg">Изображение — Sun raster</comment>
<comment xml:lang="be@latin">Rastravaja vyjava Sun</comment>
+ <comment xml:lang="be">выява Sun raster</comment>
<comment xml:lang="ar">صورة Sun raster</comment>
<comment xml:lang="af">Sun-roosterbeeld</comment>
<magic>
@@ -30712,8 +32089,9 @@ command to generate the output files.
<comment xml:lang="tr">TGA görüntüsü</comment>
<comment xml:lang="sv">TGA-bild</comment>
<comment xml:lang="sr">ТГА слика</comment>
- <comment xml:lang="sq">Figurë TGA</comment>
+ <comment xml:lang="sq">figurë TGA</comment>
<comment xml:lang="sl">Slikovna datoteka TGA</comment>
+ <comment xml:lang="si">TGA රූපය</comment>
<comment xml:lang="sk">Obrázok TGA</comment>
<comment xml:lang="ru">Изображение TGA</comment>
<comment xml:lang="ro">Imagine TGA</comment>
@@ -30730,6 +32108,7 @@ command to generate the output files.
<comment xml:lang="kk">TGA суреті</comment>
<comment xml:lang="ja">TGA 画像</comment>
<comment xml:lang="it">Immagine TGA</comment>
+ <comment xml:lang="is">TGA mynd</comment>
<comment xml:lang="id">Citra TGA</comment>
<comment xml:lang="ia">Imagine TGA</comment>
<comment xml:lang="hu">TGA kép</comment>
@@ -30752,6 +32131,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge TGA</comment>
<comment xml:lang="bg">Изображение — TGA</comment>
<comment xml:lang="be@latin">Vyjava TGA</comment>
+ <comment xml:lang="be">выява TGA</comment>
<comment xml:lang="ar">صورة TGA</comment>
<comment xml:lang="af">TGA-beeld</comment>
<acronym>TGA</acronym>
@@ -30793,8 +32173,9 @@ command to generate the output files.
<comment xml:lang="tr">Windows imleci</comment>
<comment xml:lang="sv">Windows-muspekare</comment>
<comment xml:lang="sr">Виндоузов курсор</comment>
- <comment xml:lang="sq">Kursor Windows</comment>
+ <comment xml:lang="sq">kursor Windows</comment>
<comment xml:lang="sl">Datoteka kazalke Windows</comment>
+ <comment xml:lang="si">වින්ඩෝස් කර්සරය</comment>
<comment xml:lang="sk">Kurzor Windows</comment>
<comment xml:lang="ru">Курсор Windows</comment>
<comment xml:lang="ro">Cursor Windows</comment>
@@ -30812,6 +32193,7 @@ command to generate the output files.
<comment xml:lang="kk">Windows курсоры</comment>
<comment xml:lang="ja">Windows カーソル</comment>
<comment xml:lang="it">Cursore Windows</comment>
+ <comment xml:lang="is">Windows bendill</comment>
<comment xml:lang="id">Kursor Windows</comment>
<comment xml:lang="ia">Cursor pro Windows</comment>
<comment xml:lang="hu">Windows-kurzor</comment>
@@ -30828,12 +32210,13 @@ command to generate the output files.
<comment xml:lang="eo">Windows-kursoro</comment>
<comment xml:lang="en_GB">Windows cursor</comment>
<comment xml:lang="el">Δρομέας Windows</comment>
- <comment xml:lang="de">Windows-Cursor</comment>
+ <comment xml:lang="de">Windows-Mauszeiger</comment>
<comment xml:lang="da">Windowsmarkør</comment>
<comment xml:lang="cs">kurzor Windows</comment>
<comment xml:lang="ca">cursor de Windows</comment>
<comment xml:lang="bg">Курсор — Windows</comment>
<comment xml:lang="be@latin">Kursor Windows</comment>
+ <comment xml:lang="be">курсор Windows</comment>
<comment xml:lang="ar">مؤشر ويندوز</comment>
<comment xml:lang="af">Windows-wyser</comment>
<magic>
@@ -30852,8 +32235,9 @@ command to generate the output files.
<comment xml:lang="tr">Windows canlandırmalı imleci</comment>
<comment xml:lang="sv">Animerad Windows-muspekare</comment>
<comment xml:lang="sr">Виндоузов анимирани курсор</comment>
- <comment xml:lang="sq">Kursor i animuar Windows</comment>
+ <comment xml:lang="sq">kursor i animuar Windows</comment>
<comment xml:lang="sl">Datoteka animirane kazalke Windows</comment>
+ <comment xml:lang="si">වින්ඩෝස් සජීවිකරණ කර්සරය</comment>
<comment xml:lang="sk">Animovaný kurzor Windows</comment>
<comment xml:lang="ru">Анимированный курсор Windows</comment>
<comment xml:lang="ro">Cursor animat Windows</comment>
@@ -30867,8 +32251,10 @@ command to generate the output files.
<comment xml:lang="lt">Animuotas Windows žymeklis</comment>
<comment xml:lang="ko">Windows 움직이는 커서</comment>
<comment xml:lang="kk">Windows анимациясы бар курсор</comment>
+ <comment xml:lang="ka">Windows -ის ანიმირებული კურსორი</comment>
<comment xml:lang="ja">Windows アニメーションカーソル</comment>
<comment xml:lang="it">Cursore animato Windows</comment>
+ <comment xml:lang="is">Windows hreyfibendill</comment>
<comment xml:lang="id">Kursor animasi Windows</comment>
<comment xml:lang="ia">Cursor animate pro Windows</comment>
<comment xml:lang="hu">Windows animált kurzor</comment>
@@ -30884,12 +32270,13 @@ command to generate the output files.
<comment xml:lang="es">cursor animado de Windows</comment>
<comment xml:lang="en_GB">Windows animated cursor</comment>
<comment xml:lang="el">Κινούμενος δρομέας Windows</comment>
- <comment xml:lang="de">Animierter Windows-Cursor</comment>
+ <comment xml:lang="de">Animierter Windows-Mauszeiger</comment>
<comment xml:lang="da">Windowsanimeret markør</comment>
<comment xml:lang="cs">animovaný kurzor Windows</comment>
<comment xml:lang="ca">cursor animat de Windows</comment>
<comment xml:lang="bg">Курсор — Windows, анимиран</comment>
<comment xml:lang="be@latin">Animavany kursor Windows</comment>
+ <comment xml:lang="be">анімаваны курсор Windows</comment>
<comment xml:lang="ar">مؤشر ويندوز متحرك</comment>
<comment xml:lang="af">Windows geanimeerde wyser</comment>
<magic>
@@ -30908,8 +32295,9 @@ command to generate the output files.
<comment xml:lang="tr">EMF görüntüsü</comment>
<comment xml:lang="sv">EMF-bild</comment>
<comment xml:lang="sr">ЕМФ слика</comment>
- <comment xml:lang="sq">Figurë EMF</comment>
+ <comment xml:lang="sq">figurë EMF</comment>
<comment xml:lang="sl">Slikovna datoteka EMF</comment>
+ <comment xml:lang="si">EMF රූපය</comment>
<comment xml:lang="sk">Obrázok EMF</comment>
<comment xml:lang="ru">Изображение EMF</comment>
<comment xml:lang="ro">Imagine EMF</comment>
@@ -30927,6 +32315,7 @@ command to generate the output files.
<comment xml:lang="ka">EMF გამოსახულება</comment>
<comment xml:lang="ja">EMF 画像</comment>
<comment xml:lang="it">Immagine EMF</comment>
+ <comment xml:lang="is">EMF mynd</comment>
<comment xml:lang="id">Citra EMF</comment>
<comment xml:lang="ia">Imagine EMF</comment>
<comment xml:lang="hu">EMF kép</comment>
@@ -30949,6 +32338,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge EMF</comment>
<comment xml:lang="bg">Изображение — EMF</comment>
<comment xml:lang="be@latin">Vyjava EMF</comment>
+ <comment xml:lang="be">выява EMF</comment>
<comment xml:lang="ar">صورة EMF</comment>
<comment xml:lang="af">EMF-beeld</comment>
<acronym>EMF</acronym>
@@ -30976,8 +32366,9 @@ command to generate the output files.
<comment xml:lang="tr">WMF görüntüsü</comment>
<comment xml:lang="sv">WMF-bild</comment>
<comment xml:lang="sr">ВМФ слика</comment>
- <comment xml:lang="sq">Figurë WMF</comment>
+ <comment xml:lang="sq">figurë WMF</comment>
<comment xml:lang="sl">Slikovna datoteka WMF</comment>
+ <comment xml:lang="si">WMF රූපය</comment>
<comment xml:lang="sk">Obrázok WMF</comment>
<comment xml:lang="ru">Изображение WMF</comment>
<comment xml:lang="ro">Imagine WMF</comment>
@@ -30994,6 +32385,7 @@ command to generate the output files.
<comment xml:lang="kk">WMF суреті</comment>
<comment xml:lang="ja">WMF 画像</comment>
<comment xml:lang="it">Immagine WMF</comment>
+ <comment xml:lang="is">WMF mynd</comment>
<comment xml:lang="id">Citra WMF</comment>
<comment xml:lang="ia">Imagine WMF</comment>
<comment xml:lang="hu">WMF kép</comment>
@@ -31016,6 +32408,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge WMF</comment>
<comment xml:lang="bg">Изображение — WMF</comment>
<comment xml:lang="be@latin">Vyjava WMF</comment>
+ <comment xml:lang="be">выява WMF</comment>
<comment xml:lang="ar">صورة WMF</comment>
<comment xml:lang="af">WMF-beeld</comment>
<acronym>WMF</acronym>
@@ -31049,8 +32442,9 @@ command to generate the output files.
<comment xml:lang="tr">XBM görüntüsü</comment>
<comment xml:lang="sv">XBM-bild</comment>
<comment xml:lang="sr">ИксБМ слика</comment>
- <comment xml:lang="sq">Figurë XBM</comment>
+ <comment xml:lang="sq">figurë XBM</comment>
<comment xml:lang="sl">Slikovna datoteka XBM</comment>
+ <comment xml:lang="si">XBM රූපය</comment>
<comment xml:lang="sk">Obrázok XBM</comment>
<comment xml:lang="ru">Изображение XBM</comment>
<comment xml:lang="ro">Imagine XBM</comment>
@@ -31067,6 +32461,7 @@ command to generate the output files.
<comment xml:lang="kk">XBM суреті</comment>
<comment xml:lang="ja">XBM 画像</comment>
<comment xml:lang="it">Immagine XBM</comment>
+ <comment xml:lang="is">XBM mynd</comment>
<comment xml:lang="id">Citra XBM</comment>
<comment xml:lang="ia">Imagine XBM</comment>
<comment xml:lang="hu">XBM-kép</comment>
@@ -31089,6 +32484,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge XBM</comment>
<comment xml:lang="bg">Изображение — XBM</comment>
<comment xml:lang="be@latin">Vyjava XBM</comment>
+ <comment xml:lang="be">выява XBM</comment>
<comment xml:lang="ar">صورة XBM</comment>
<comment xml:lang="af">XBM-beeld</comment>
<acronym>XBM</acronym>
@@ -31104,8 +32500,9 @@ command to generate the output files.
<comment xml:lang="tr">GIMP görüntüsü</comment>
<comment xml:lang="sv">GIMP-bild</comment>
<comment xml:lang="sr">Гимпова слика</comment>
- <comment xml:lang="sq">Figurë GIMP</comment>
+ <comment xml:lang="sq">figurë GIMP</comment>
<comment xml:lang="sl">Slikovna datoteka GIMP</comment>
+ <comment xml:lang="si">GIMP රූපය</comment>
<comment xml:lang="sk">Obrázok GIMP</comment>
<comment xml:lang="ru">Изображение GIMP</comment>
<comment xml:lang="ro">Imagine GIMP</comment>
@@ -31124,6 +32521,7 @@ command to generate the output files.
<comment xml:lang="ka">GIMP გამოსახულება</comment>
<comment xml:lang="ja">GIMP 画像</comment>
<comment xml:lang="it">Immagine GIMP</comment>
+ <comment xml:lang="is">GIMP mynd</comment>
<comment xml:lang="id">Citra GIMP</comment>
<comment xml:lang="ia">Imagine GIMP</comment>
<comment xml:lang="hu">GIMP-kép</comment>
@@ -31146,6 +32544,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge de GIMP</comment>
<comment xml:lang="bg">Изображение — GIMP</comment>
<comment xml:lang="be@latin">Vyjava GIMP</comment>
+ <comment xml:lang="be">выява GIMP</comment>
<comment xml:lang="ar">صورة GIMP</comment>
<comment xml:lang="af">GIMP-beeld</comment>
<glob pattern="*.xcf"/>
@@ -31161,19 +32560,25 @@ command to generate the output files.
<comment xml:lang="uk">пензель GIMP</comment>
<comment xml:lang="tr">GIMP fırçası</comment>
<comment xml:lang="sv">GIMP-pensel</comment>
+ <comment xml:lang="sq">penel GIMP</comment>
<comment xml:lang="sl">Čopič GIMP</comment>
+ <comment xml:lang="si">GIMP බුරුසුව</comment>
<comment xml:lang="sk">Štetec aplikácie GIMP</comment>
<comment xml:lang="ru">Кисть GIMP</comment>
<comment xml:lang="pt_BR">Pincel do GIMP</comment>
<comment xml:lang="pl">Pędzel programu GIMP</comment>
+ <comment xml:lang="nl">GIMP-kwast</comment>
<comment xml:lang="ko">GIMP 붓</comment>
<comment xml:lang="kk">GIMP бояу жаққышы</comment>
+ <comment xml:lang="ka">GIMP-ის ფუნჯი</comment>
<comment xml:lang="ja">GIMP ブラシ</comment>
<comment xml:lang="it">Pennello GIMP</comment>
+ <comment xml:lang="is">GIMP-pensill</comment>
<comment xml:lang="id">Kuas GIMP</comment>
<comment xml:lang="hu">GIMP ecset</comment>
<comment xml:lang="hr">GIMP kist</comment>
<comment xml:lang="he">מברשת GIMP</comment>
+ <comment xml:lang="gl">Pincel de GIMP</comment>
<comment xml:lang="ga">scuab GIMP</comment>
<comment xml:lang="fur">pinel GIMP</comment>
<comment xml:lang="fr">brosse GIMP</comment>
@@ -31186,6 +32591,7 @@ command to generate the output files.
<comment xml:lang="cs">štětec GIMP</comment>
<comment xml:lang="ca">pinzell de GIMP</comment>
<comment xml:lang="bg">Четка — GIMP</comment>
+ <comment xml:lang="be">пэндзаль GIMP</comment>
<comment xml:lang="ar">فرشاة جمب</comment>
<comment xml:lang="af">GIMP-kwas</comment>
<glob pattern="*.gbr"/>
@@ -31200,13 +32606,16 @@ command to generate the output files.
<comment xml:lang="uk">канал пензлів GIMP</comment>
<comment xml:lang="tr">GIMP fırça borusu</comment>
<comment xml:lang="sv">GIMP-penselrör</comment>
+ <comment xml:lang="si">GIMP බුරුසු පයිප්ප</comment>
<comment xml:lang="ru">Анимированная кисть GIMP</comment>
<comment xml:lang="pt_BR">Tubo de pincel do GIMP</comment>
<comment xml:lang="pl">Potok pędzla programu GIMP</comment>
+ <comment xml:lang="nl">GIMP-kwast-pijp</comment>
<comment xml:lang="ko">GIMP 붓 파이프</comment>
<comment xml:lang="kk">GIMP бояу жаққыш түтігі</comment>
<comment xml:lang="ja">GIMP パイプブラシ</comment>
<comment xml:lang="it">Pipe pennello GIMP</comment>
+ <comment xml:lang="is">GIMP-pensilpípa</comment>
<comment xml:lang="id">Pipa kuas GIMP</comment>
<comment xml:lang="hu">GIMP ecsetcsatorna</comment>
<comment xml:lang="hr">Proces GIMP kista</comment>
@@ -31218,11 +32627,12 @@ command to generate the output files.
<comment xml:lang="eu">GIMP pintzel hodia pipe</comment>
<comment xml:lang="es">pincel animado del GIMP</comment>
<comment xml:lang="en_GB">GIMP brush pipe</comment>
- <comment xml:lang="de">GIMP-Pinselanimation</comment>
+ <comment xml:lang="de">Animierter GIMP-Pinsel</comment>
<comment xml:lang="da">GIMP-penselrør</comment>
<comment xml:lang="cs">zřetězení štětců GIMP</comment>
<comment xml:lang="ca">conducte del pinzell de GIMP</comment>
<comment xml:lang="bg">Конвейер с четки — GIMP</comment>
+ <comment xml:lang="be">самаробны пэндзаль GIMP</comment>
<comment xml:lang="ar">أنبوب فرشاة GIMP</comment>
<glob pattern="*.gih"/>
</mime-type>
@@ -31234,18 +32644,23 @@ command to generate the output files.
<comment xml:lang="tr">GIMP deseni</comment>
<comment xml:lang="sv">GIMP-mönster</comment>
<comment xml:lang="sl">Vzorec GIMP</comment>
+ <comment xml:lang="si">GIMP රටාව</comment>
<comment xml:lang="sk">Vzor aplikácie GIMP</comment>
<comment xml:lang="ru">Шаблон GIMP</comment>
<comment xml:lang="pt_BR">Textura do GIMP</comment>
<comment xml:lang="pl">Deseń programu GIMP</comment>
+ <comment xml:lang="nl">GIMP-patroon</comment>
<comment xml:lang="ko">GIMP 패턴</comment>
<comment xml:lang="kk">GIMP оюы</comment>
+ <comment xml:lang="ka">GIMP შაბლონი</comment>
<comment xml:lang="ja">GIMP パターン</comment>
<comment xml:lang="it">Motivo GIMP</comment>
+ <comment xml:lang="is">GIMP-mynstur</comment>
<comment xml:lang="id">Pola GIMP</comment>
<comment xml:lang="hu">GIMP minta</comment>
<comment xml:lang="hr">GIMP uzorak</comment>
<comment xml:lang="he">מרקם של GIMP</comment>
+ <comment xml:lang="gl">Patrón de GIMP</comment>
<comment xml:lang="ga">patrún GIMP</comment>
<comment xml:lang="fur">motîf GIMP</comment>
<comment xml:lang="fr">motif GIMP</comment>
@@ -31258,6 +32673,7 @@ command to generate the output files.
<comment xml:lang="cs">vzorek GIMP</comment>
<comment xml:lang="ca">patró de GIMP</comment>
<comment xml:lang="bg">Шарка — GIMP</comment>
+ <comment xml:lang="be">узор GIMP</comment>
<comment xml:lang="ar">نقش GIMP</comment>
<comment xml:lang="af">GIMP-patroon</comment>
<glob pattern="*.pat"/>
@@ -31274,8 +32690,9 @@ command to generate the output files.
<comment xml:lang="tr">XFig görüntüsü</comment>
<comment xml:lang="sv">XFig-bild</comment>
<comment xml:lang="sr">ИксФиг слика</comment>
- <comment xml:lang="sq">Figurë XFig</comment>
+ <comment xml:lang="sq">figurë XFig</comment>
<comment xml:lang="sl">Slikovna datoteka XFig</comment>
+ <comment xml:lang="si">XFig රූපය</comment>
<comment xml:lang="sk">Obrázok XFig</comment>
<comment xml:lang="ru">Изображение XFig</comment>
<comment xml:lang="ro">Imagine XFig</comment>
@@ -31293,6 +32710,7 @@ command to generate the output files.
<comment xml:lang="kk">XFig суреті</comment>
<comment xml:lang="ja">XFig 画像</comment>
<comment xml:lang="it">Immagine XFig</comment>
+ <comment xml:lang="is">XFig mynd</comment>
<comment xml:lang="id">Citra XFig</comment>
<comment xml:lang="ia">Imagine XFig</comment>
<comment xml:lang="hu">XFig-kép</comment>
@@ -31315,6 +32733,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge de XFig</comment>
<comment xml:lang="bg">Изображение — XFig</comment>
<comment xml:lang="be@latin">Vyjava XFig</comment>
+ <comment xml:lang="be">выява XFig</comment>
<comment xml:lang="ar">صورة XFig</comment>
<comment xml:lang="af">XFig-beeld</comment>
<glob pattern="*.fig"/>
@@ -31331,8 +32750,9 @@ command to generate the output files.
<comment xml:lang="tr">XPM görüntüsü</comment>
<comment xml:lang="sv">XPM-bild</comment>
<comment xml:lang="sr">ИксПМ слика</comment>
- <comment xml:lang="sq">Figurë XPM</comment>
+ <comment xml:lang="sq">figurë XPM</comment>
<comment xml:lang="sl">Slikovna datoteka XPM</comment>
+ <comment xml:lang="si">XPM රූපය</comment>
<comment xml:lang="sk">Obrázok XPM</comment>
<comment xml:lang="ru">Изображение XPM</comment>
<comment xml:lang="ro">Imagine XPM</comment>
@@ -31349,6 +32769,7 @@ command to generate the output files.
<comment xml:lang="kk">XPM суреті</comment>
<comment xml:lang="ja">XPM 画像</comment>
<comment xml:lang="it">Immagine XPM</comment>
+ <comment xml:lang="is">XPM mynd</comment>
<comment xml:lang="id">Citra XPM</comment>
<comment xml:lang="ia">Imagine XPM</comment>
<comment xml:lang="hu">XPM kép</comment>
@@ -31372,6 +32793,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge XPM</comment>
<comment xml:lang="bg">Изображение — XPM</comment>
<comment xml:lang="be@latin">Vyjava XPM</comment>
+ <comment xml:lang="be">выява XPM</comment>
<comment xml:lang="ar">صورة XPM</comment>
<comment xml:lang="af">XPM-beeld</comment>
<acronym>XPM</acronym>
@@ -31392,8 +32814,9 @@ command to generate the output files.
<comment xml:lang="tr">X pencere görüntüsü</comment>
<comment xml:lang="sv">X-fönsterbild</comment>
<comment xml:lang="sr">слика Икс прозора</comment>
- <comment xml:lang="sq">Figurë X window</comment>
+ <comment xml:lang="sq">figurë X window</comment>
<comment xml:lang="sl">slika X oken</comment>
+ <comment xml:lang="si">X කවුළු රූපය</comment>
<comment xml:lang="sk">Obrázok X window</comment>
<comment xml:lang="ru">Изображение X window</comment>
<comment xml:lang="ro">Imagine X window</comment>
@@ -31411,6 +32834,7 @@ command to generate the output files.
<comment xml:lang="kk">X window суреті</comment>
<comment xml:lang="ja">X window 画像</comment>
<comment xml:lang="it">Immagine X window</comment>
+ <comment xml:lang="is">X window mynd</comment>
<comment xml:lang="id">Citra X window</comment>
<comment xml:lang="ia">Imagine X Window</comment>
<comment xml:lang="hu">X window-kép</comment>
@@ -31434,560 +32858,153 @@ command to generate the output files.
<comment xml:lang="ca">imatge de X window</comment>
<comment xml:lang="bg">Изображение — X Window</comment>
<comment xml:lang="be@latin">Vyjava vakna X</comment>
+ <comment xml:lang="be">выява X window</comment>
<comment xml:lang="az">X window rəsmi</comment>
<comment xml:lang="ar">صورة X window</comment>
<comment xml:lang="af">X window-beeld</comment>
<glob pattern="*.xwd"/>
</mime-type>
<mime-type type="inode/blockdevice">
- <comment>block device</comment>
- <comment xml:lang="zh_TW">區塊裝置</comment>
- <comment xml:lang="zh_CN">块设备</comment>
- <comment xml:lang="vi">thiết bị khối</comment>
+ <comment>Block device</comment>
<comment xml:lang="uk">блоковий пристрій</comment>
- <comment xml:lang="tr">blok aygıtı</comment>
- <comment xml:lang="sv">blockenhet</comment>
- <comment xml:lang="sr">блок уређај</comment>
- <comment xml:lang="sq">device me blloqe</comment>
- <comment xml:lang="sl">bločna naprava</comment>
- <comment xml:lang="sk">Blokové zariadenie</comment>
+ <comment xml:lang="sv">Blockenhet</comment>
<comment xml:lang="ru">Блочное устройство</comment>
- <comment xml:lang="ro">dispozitiv bloc</comment>
- <comment xml:lang="pt_BR">Dispositivo de bloco</comment>
- <comment xml:lang="pt">dispositivo de bloco</comment>
<comment xml:lang="pl">Urządzenie blokowe</comment>
- <comment xml:lang="oc">periferic de blòts</comment>
- <comment xml:lang="nn">blokk-eining</comment>
- <comment xml:lang="nl">blok-apparaat</comment>
- <comment xml:lang="nb">blokkenhet</comment>
- <comment xml:lang="ms">Peranti blok</comment>
- <comment xml:lang="lv">bloka ierīce</comment>
- <comment xml:lang="lt">blokinis įrenginys</comment>
- <comment xml:lang="ko">블록 장치</comment>
- <comment xml:lang="kk">блоктық құрылғысы</comment>
- <comment xml:lang="ja">ブロックデバイス</comment>
+ <comment xml:lang="ja">区画様機器</comment>
<comment xml:lang="it">Device a blocchi</comment>
- <comment xml:lang="id">peranti blok</comment>
- <comment xml:lang="ia">Dispositivo de blocos</comment>
- <comment xml:lang="hu">blokkos eszköz</comment>
- <comment xml:lang="hr">Blokovski uređaj</comment>
- <comment xml:lang="he">התקן בלוק</comment>
- <comment xml:lang="gl">dispositivo de bloque</comment>
- <comment xml:lang="ga">gléas bloc</comment>
- <comment xml:lang="fur">dispositîf a blocs</comment>
- <comment xml:lang="fr">périphérique de blocs</comment>
- <comment xml:lang="fo">blokka tóleind</comment>
- <comment xml:lang="fi">lohkolaite</comment>
- <comment xml:lang="eu">bloke-gailua</comment>
+ <comment xml:lang="gl">Dispositivo de bloque</comment>
+ <comment xml:lang="eu">Bloke-gailua</comment>
<comment xml:lang="es">dispositivo de bloques</comment>
- <comment xml:lang="eo">bloka disponaĵo</comment>
- <comment xml:lang="en_GB">block device</comment>
- <comment xml:lang="el">Συσκευή block</comment>
<comment xml:lang="de">Blockorientiertes Gerät</comment>
- <comment xml:lang="da">blokenhed</comment>
- <comment xml:lang="cs">blokové zařízení</comment>
- <comment xml:lang="ca">dispositiu de blocs</comment>
- <comment xml:lang="bg">Блоково устройство</comment>
- <comment xml:lang="be@latin">blokavaja pryłada</comment>
- <comment xml:lang="ast">preséu de bloques</comment>
- <comment xml:lang="ar">جهاز كتلي</comment>
- <comment xml:lang="af">bloktoestel</comment>
+ <comment xml:lang="be">блокавая прылада</comment>
</mime-type>
<mime-type type="inode/chardevice">
- <comment>character device</comment>
- <comment xml:lang="zh_TW">字元裝置</comment>
- <comment xml:lang="zh_CN">字符设备</comment>
- <comment xml:lang="vi">thiết bị ký tự</comment>
- <comment xml:lang="uk">символьний пристрій</comment>
- <comment xml:lang="tr">karakter aygıtı</comment>
- <comment xml:lang="sv">teckenenhet</comment>
- <comment xml:lang="sr">знаковни уређај</comment>
- <comment xml:lang="sq">device me karaktere</comment>
- <comment xml:lang="sl">znakovna naprava</comment>
- <comment xml:lang="sk">Znakové zariadenie</comment>
+ <comment>Character device</comment>
+ <comment xml:lang="uk">Символьний пристрій</comment>
+ <comment xml:lang="sv">Teckenenhet</comment>
<comment xml:lang="ru">Символьное устройство</comment>
- <comment xml:lang="ro">dispozitiv caracter</comment>
- <comment xml:lang="pt_BR">Dispositivo de caractere</comment>
- <comment xml:lang="pt">dispositivo de caracteres</comment>
<comment xml:lang="pl">Urządzenie znakowe</comment>
- <comment xml:lang="oc">periferic de caractèrs</comment>
- <comment xml:lang="nn">teikneining</comment>
- <comment xml:lang="nl">byte-apparaat</comment>
- <comment xml:lang="nb">tegnenhet</comment>
- <comment xml:lang="ms">Peranti aksara</comment>
- <comment xml:lang="lv">rakstzīmju ierīce</comment>
- <comment xml:lang="lt">simbolinis įrenginys</comment>
- <comment xml:lang="ko">문자 장치</comment>
- <comment xml:lang="kk">символдық құрылғысы</comment>
- <comment xml:lang="ja">キャラクタデバイス</comment>
+ <comment xml:lang="ja">文字様機器</comment>
<comment xml:lang="it">Device a caratteri</comment>
- <comment xml:lang="id">peranti karakter</comment>
- <comment xml:lang="ia">Dispositivo de characteres</comment>
- <comment xml:lang="hu">karakteres eszköz</comment>
- <comment xml:lang="hr">Znakovni uređaj</comment>
- <comment xml:lang="he">התקן תכונה</comment>
- <comment xml:lang="gl">dispositivo de caracter</comment>
- <comment xml:lang="ga">gléas carachtar</comment>
- <comment xml:lang="fur">dispositîf a caratars</comment>
- <comment xml:lang="fr">périphérique de caractères</comment>
- <comment xml:lang="fo">stavatóleind</comment>
- <comment xml:lang="fi">merkkilaite</comment>
- <comment xml:lang="eu">karaktereen gailua</comment>
+ <comment xml:lang="gl">Dispositivo de caracter</comment>
+ <comment xml:lang="eu">Karaktere-gailua</comment>
<comment xml:lang="es">dispositivo de caracteres</comment>
- <comment xml:lang="eo">signa disponaĵo</comment>
- <comment xml:lang="en_GB">character device</comment>
- <comment xml:lang="el">Συσκευή χαρακτήρων</comment>
<comment xml:lang="de">Zeichenorientiertes Gerät</comment>
- <comment xml:lang="da">tegnenhed</comment>
- <comment xml:lang="cs">znakové zařízení</comment>
- <comment xml:lang="ca">dispositiu de caràcters</comment>
- <comment xml:lang="bg">Символно устройство</comment>
- <comment xml:lang="be@latin">znakavaja pryłada</comment>
- <comment xml:lang="ast">preséu de caráuteres</comment>
- <comment xml:lang="ar">جهاز حرفي</comment>
- <comment xml:lang="af">karaktertoestel</comment>
+ <comment xml:lang="be">сімвальная прылада</comment>
</mime-type>
<mime-type type="inode/directory">
- <comment>folder</comment>
- <comment xml:lang="zh_TW">資料夾</comment>
- <comment xml:lang="zh_CN">文件夹</comment>
- <comment xml:lang="vi">thư mục</comment>
- <comment xml:lang="uk">тека</comment>
- <comment xml:lang="tr">dizin</comment>
- <comment xml:lang="sv">mapp</comment>
- <comment xml:lang="sr">фасцикла</comment>
- <comment xml:lang="sq">Kartelë</comment>
- <comment xml:lang="sl">mapa</comment>
- <comment xml:lang="sk">Priečinok</comment>
+ <comment>Folder</comment>
+ <comment xml:lang="uk">Тека</comment>
+ <comment xml:lang="sv">Mapp</comment>
<comment xml:lang="ru">Папка</comment>
- <comment xml:lang="ro">dosar</comment>
<comment xml:lang="pt_BR">Pasta</comment>
- <comment xml:lang="pt">pasta</comment>
<comment xml:lang="pl">Katalog</comment>
- <comment xml:lang="oc">dorsièr</comment>
- <comment xml:lang="nn">mappe</comment>
- <comment xml:lang="nl">map</comment>
- <comment xml:lang="nb">mappe</comment>
- <comment xml:lang="ms">Folder</comment>
- <comment xml:lang="lv">mape</comment>
- <comment xml:lang="lt">aplankas</comment>
- <comment xml:lang="ko">폴더</comment>
- <comment xml:lang="kk">бума</comment>
- <comment xml:lang="ja">フォルダー</comment>
+ <comment xml:lang="ja">フォルダ</comment>
<comment xml:lang="it">Cartella</comment>
- <comment xml:lang="id">folder</comment>
- <comment xml:lang="ia">Dossier</comment>
- <comment xml:lang="hu">mappa</comment>
- <comment xml:lang="hr">Mapa</comment>
- <comment xml:lang="he">תיקייה</comment>
- <comment xml:lang="gl">cartafol</comment>
- <comment xml:lang="ga">fillteán</comment>
- <comment xml:lang="fur">cartele</comment>
- <comment xml:lang="fr">dossier</comment>
- <comment xml:lang="fo">mappa</comment>
- <comment xml:lang="fi">kansio</comment>
- <comment xml:lang="eu">karpeta</comment>
+ <comment xml:lang="gl">Cartafol</comment>
+ <comment xml:lang="eu">Karpeta</comment>
<comment xml:lang="es">carpeta</comment>
- <comment xml:lang="eo">dosierujo</comment>
- <comment xml:lang="en_GB">folder</comment>
- <comment xml:lang="el">Φάκελος</comment>
<comment xml:lang="de">Ordner</comment>
- <comment xml:lang="da">mappe</comment>
- <comment xml:lang="cs">složka</comment>
- <comment xml:lang="ca">carpeta</comment>
- <comment xml:lang="bg">Папка</comment>
- <comment xml:lang="be@latin">kataloh</comment>
- <comment xml:lang="ast">carpeta</comment>
- <comment xml:lang="ar">مجلّد</comment>
- <comment xml:lang="af">gids</comment>
+ <comment xml:lang="be">папка</comment>
<generic-icon name="folder"/>
<alias type="x-directory/normal"/>
</mime-type>
<mime-type type="inode/fifo">
- <comment>pipe</comment>
- <comment xml:lang="zh_TW">管線</comment>
- <comment xml:lang="zh_CN">管道</comment>
- <comment xml:lang="vi">ống dẫn</comment>
- <comment xml:lang="uk">канал</comment>
- <comment xml:lang="tr">boru</comment>
- <comment xml:lang="sv">rör</comment>
- <comment xml:lang="sr">спојка</comment>
- <comment xml:lang="sq">Pipe</comment>
- <comment xml:lang="sl">cev</comment>
- <comment xml:lang="sk">Rúra</comment>
+ <comment>Pipe</comment>
+ <comment xml:lang="uk">Канал</comment>
+ <comment xml:lang="sv">Rör</comment>
<comment xml:lang="ru">Канал</comment>
- <comment xml:lang="ro">canal pipe</comment>
- <comment xml:lang="pt_BR">Pipe</comment>
- <comment xml:lang="pt">canal</comment>
<comment xml:lang="pl">Potok</comment>
- <comment xml:lang="oc">tub</comment>
- <comment xml:lang="nn">røyr</comment>
- <comment xml:lang="nl">pijp</comment>
- <comment xml:lang="nb">rør</comment>
- <comment xml:lang="ms">Paip</comment>
- <comment xml:lang="lv">programmkanāls</comment>
- <comment xml:lang="lt">konvejeris</comment>
- <comment xml:lang="ko">파이프</comment>
- <comment xml:lang="kk">арна</comment>
<comment xml:lang="ja">パイプ</comment>
<comment xml:lang="it">Pipe</comment>
- <comment xml:lang="id">pipa</comment>
- <comment xml:lang="ia">Tubo</comment>
- <comment xml:lang="hu">adatcsatorna</comment>
- <comment xml:lang="hr">Slivnik</comment>
- <comment xml:lang="he">צינור</comment>
- <comment xml:lang="gl">tubería</comment>
- <comment xml:lang="ga">píopa</comment>
- <comment xml:lang="fur">condot</comment>
- <comment xml:lang="fr">tube</comment>
- <comment xml:lang="fo">rør</comment>
- <comment xml:lang="fi">putki</comment>
- <comment xml:lang="eu">kanalizazioa</comment>
+ <comment xml:lang="gl">Tubería</comment>
+ <comment xml:lang="eu">Kanalizazioa</comment>
<comment xml:lang="es">canalización</comment>
- <comment xml:lang="eo">dukto</comment>
- <comment xml:lang="en_GB">pipe</comment>
- <comment xml:lang="el">Διοχέτευση</comment>
- <comment xml:lang="de">Pipe</comment>
- <comment xml:lang="da">datakanal</comment>
- <comment xml:lang="cs">roura</comment>
- <comment xml:lang="ca">conducte</comment>
- <comment xml:lang="bg">Конвейер</comment>
- <comment xml:lang="be@latin">kanvejer</comment>
- <comment xml:lang="ar">أنبوب</comment>
- <comment xml:lang="af">pyp</comment>
+ <comment xml:lang="de">Weiterleitung</comment>
+ <comment xml:lang="be">канал</comment>
</mime-type>
<mime-type type="inode/mount-point">
- <comment>mount point</comment>
- <comment xml:lang="zh_TW">掛載點</comment>
- <comment xml:lang="zh_CN">挂载点</comment>
- <comment xml:lang="vi">điểm lắp</comment>
- <comment xml:lang="uk">точка монтування</comment>
- <comment xml:lang="tr">bağlama noktası</comment>
- <comment xml:lang="sv">monteringspunkt</comment>
- <comment xml:lang="sr">тачка прикључења</comment>
- <comment xml:lang="sq">Pikë montimi</comment>
- <comment xml:lang="sl">priklopna točka</comment>
- <comment xml:lang="sk">Miesto pripojenia</comment>
+ <comment>Mount point</comment>
+ <comment xml:lang="uk">Точка монтування</comment>
+ <comment xml:lang="sv">Monteringspunkt</comment>
<comment xml:lang="ru">Точка монтирования</comment>
- <comment xml:lang="ro">loc montare</comment>
<comment xml:lang="pt_BR">Ponto de montagem</comment>
- <comment xml:lang="pt">ponto de montagem</comment>
<comment xml:lang="pl">Punkt montowania</comment>
- <comment xml:lang="oc">punt d'accès</comment>
- <comment xml:lang="nn">monteringspunkt</comment>
- <comment xml:lang="nl">aankoppelingspunt</comment>
- <comment xml:lang="nb">monteringspunkt</comment>
- <comment xml:lang="ms">Titik lekapan</comment>
- <comment xml:lang="lv">montēšanas punkts</comment>
- <comment xml:lang="lt">prijungimo taškas</comment>
- <comment xml:lang="ko">마운트 위치</comment>
- <comment xml:lang="kk">тіркеу нүктесі</comment>
- <comment xml:lang="ja">マウントポイント</comment>
+ <comment xml:lang="ja">マウント箇所</comment>
<comment xml:lang="it">Punto di mount</comment>
- <comment xml:lang="id">titik mount</comment>
- <comment xml:lang="ia">Puncto de montage</comment>
- <comment xml:lang="hu">csatolási pont</comment>
- <comment xml:lang="hr">Točka montiranja</comment>
- <comment xml:lang="he">נקודת עיגון</comment>
- <comment xml:lang="gl">punto de montaxe</comment>
- <comment xml:lang="ga">pointe feistithe</comment>
- <comment xml:lang="fur">pont di montaç</comment>
- <comment xml:lang="fr">point d'accès</comment>
- <comment xml:lang="fo">ísetingarpunkt</comment>
- <comment xml:lang="fi">liitospiste</comment>
- <comment xml:lang="eu">muntatze-puntua</comment>
+ <comment xml:lang="gl">Punto de montaxe</comment>
+ <comment xml:lang="eu">Muntatze-puntua</comment>
<comment xml:lang="es">punto de montaje</comment>
- <comment xml:lang="eo">surmetingo</comment>
- <comment xml:lang="en_GB">mount point</comment>
- <comment xml:lang="el">Σημείο προσάρτησης</comment>
<comment xml:lang="de">Einhängepunkt</comment>
- <comment xml:lang="da">monteringspunkt</comment>
- <comment xml:lang="cs">přípojné místo</comment>
- <comment xml:lang="ca">punt de muntatge</comment>
- <comment xml:lang="bg">Точка на монтиране</comment>
- <comment xml:lang="be@latin">punkt mantavańnia</comment>
- <comment xml:lang="ast">puntu de montaxe</comment>
- <comment xml:lang="ar">نقطة وصْل</comment>
- <comment xml:lang="af">hegpunt</comment>
+ <comment xml:lang="be">пункт мантавання</comment>
<sub-class-of type="inode/directory"/>
</mime-type>
<mime-type type="inode/socket">
- <comment>socket</comment>
- <comment xml:lang="zh_TW">socket</comment>
- <comment xml:lang="zh_CN">套接字</comment>
- <comment xml:lang="vi">ổ cắm</comment>
+ <comment>Socket</comment>
<comment xml:lang="uk">сокет</comment>
- <comment xml:lang="tr">soket</comment>
- <comment xml:lang="sv">uttag</comment>
- <comment xml:lang="sr">прикључница</comment>
- <comment xml:lang="sq">Socket</comment>
- <comment xml:lang="sl">vtič</comment>
- <comment xml:lang="sk">Soket</comment>
+ <comment xml:lang="sv">Uttag</comment>
<comment xml:lang="ru">Сокет</comment>
- <comment xml:lang="ro">socket</comment>
- <comment xml:lang="pt_BR">Socket</comment>
- <comment xml:lang="pt">tomada</comment>
<comment xml:lang="pl">Gniazdo</comment>
- <comment xml:lang="oc">connector ret</comment>
- <comment xml:lang="nn">sokkel</comment>
- <comment xml:lang="nl">socket</comment>
- <comment xml:lang="nb">plugg</comment>
- <comment xml:lang="ms">Soket</comment>
- <comment xml:lang="lv">sokets</comment>
- <comment xml:lang="lt">lizdas</comment>
- <comment xml:lang="ko">소켓</comment>
- <comment xml:lang="kk">сокет</comment>
<comment xml:lang="ja">ソケット</comment>
<comment xml:lang="it">Socket</comment>
- <comment xml:lang="id">soket</comment>
- <comment xml:lang="ia">Socket</comment>
- <comment xml:lang="hu">illesztőpont</comment>
- <comment xml:lang="hr">Priključnica</comment>
- <comment xml:lang="he">נקודת חיבור</comment>
- <comment xml:lang="gl">socket</comment>
- <comment xml:lang="ga">soicéad</comment>
- <comment xml:lang="fur">socket</comment>
- <comment xml:lang="fr">connecteur réseau</comment>
- <comment xml:lang="fo">sokkul</comment>
- <comment xml:lang="fi">pistoke</comment>
- <comment xml:lang="eu">socketa</comment>
- <comment xml:lang="es">socket</comment>
- <comment xml:lang="eo">kontaktoskatolo</comment>
- <comment xml:lang="en_GB">socket</comment>
- <comment xml:lang="el">Υποδοχή</comment>
+ <comment xml:lang="gl">Socket</comment>
+ <comment xml:lang="eu">Socket-a</comment>
+ <comment xml:lang="es">zócalo</comment>
<comment xml:lang="de">Socket</comment>
- <comment xml:lang="da">sokkel</comment>
- <comment xml:lang="cs">socket</comment>
- <comment xml:lang="ca">sòcol</comment>
- <comment xml:lang="bg">Гнездо</comment>
- <comment xml:lang="be@latin">sokiet</comment>
- <comment xml:lang="ar">مقبس</comment>
- <comment xml:lang="af">sok</comment>
+ <comment xml:lang="be">сокет</comment>
</mime-type>
<mime-type type="inode/symlink">
- <comment>symbolic link</comment>
- <comment xml:lang="zh_TW">符號連結</comment>
- <comment xml:lang="zh_CN">符号链接</comment>
- <comment xml:lang="vi">liên kết tượng trưng</comment>
- <comment xml:lang="uk">символічне посилання</comment>
- <comment xml:lang="tr">simgesel bağlantı</comment>
- <comment xml:lang="sv">symbolisk länk</comment>
- <comment xml:lang="sr">симболичка веза</comment>
- <comment xml:lang="sq">Lidhje simbolike</comment>
- <comment xml:lang="sl">simbolna povezava</comment>
- <comment xml:lang="sk">Symbolický odkaz</comment>
+ <comment>Symbolic link</comment>
+ <comment xml:lang="uk">Символічне посилання</comment>
+ <comment xml:lang="sv">Symbolisk länk</comment>
<comment xml:lang="ru">Символьная ссылка</comment>
- <comment xml:lang="ro">legătură simbolică</comment>
- <comment xml:lang="pt_BR">Ligação simbólica</comment>
- <comment xml:lang="pt">ligação simbólica</comment>
+ <comment xml:lang="pt_BR">Link simbólico</comment>
<comment xml:lang="pl">Dowiązanie symboliczne</comment>
- <comment xml:lang="oc">ligam simbolic</comment>
- <comment xml:lang="nn">symbolsk lenkje</comment>
- <comment xml:lang="nl">symbolische koppeling</comment>
- <comment xml:lang="nb">symbolsk lenke</comment>
- <comment xml:lang="ms">Pautan simbolik</comment>
- <comment xml:lang="lv">simboliskā saite</comment>
- <comment xml:lang="lt">simbolinė nuoroda</comment>
- <comment xml:lang="ko">심볼릭 링크</comment>
- <comment xml:lang="kk">символдық сілтеме</comment>
- <comment xml:lang="ka">სიმბოლური ბმული</comment>
<comment xml:lang="ja">シンボリックリンク</comment>
<comment xml:lang="it">Collegamento simbolico</comment>
- <comment xml:lang="id">taut simbolik</comment>
- <comment xml:lang="ia">Ligamine symbolic</comment>
- <comment xml:lang="hu">szimbolikus link</comment>
- <comment xml:lang="hr">Simbolička poveznica</comment>
- <comment xml:lang="he">קישור סימבולי</comment>
- <comment xml:lang="gl">ligazón simbólica</comment>
- <comment xml:lang="ga">nasc siombalach</comment>
- <comment xml:lang="fur">colegament simbolic</comment>
- <comment xml:lang="fr">lien symbolique</comment>
- <comment xml:lang="fo">tykislig leinkja</comment>
- <comment xml:lang="fi">symbolinen linkki</comment>
- <comment xml:lang="eu">esteka sinbolikoa</comment>
+ <comment xml:lang="gl">Ligazón simbólica</comment>
+ <comment xml:lang="eu">Esteka sinbolikoa</comment>
<comment xml:lang="es">enlace simbólico</comment>
- <comment xml:lang="eo">simbola ligilo</comment>
- <comment xml:lang="en_GB">symbolic link</comment>
- <comment xml:lang="el">Συμβολικός σύνδεσμος</comment>
<comment xml:lang="de">Symbolische Verknüpfung</comment>
- <comment xml:lang="da">symbolsk henvisning</comment>
- <comment xml:lang="cy">cyswllt symbolaidd</comment>
- <comment xml:lang="cs">symbolický odkaz</comment>
- <comment xml:lang="ca">enllaç simbòlic</comment>
- <comment xml:lang="bg">Символна връзка</comment>
- <comment xml:lang="be@latin">symbalnaja spasyłka</comment>
- <comment xml:lang="az">simvolik körpü</comment>
- <comment xml:lang="ast">enllaz simbólicu</comment>
- <comment xml:lang="ar">وصلة رمزية</comment>
- <comment xml:lang="af">simboliese skakel</comment>
+ <comment xml:lang="be">сімвалічная спасылка</comment>
</mime-type>
<mime-type type="message/delivery-status">
- <comment>mail delivery report</comment>
- <comment xml:lang="zh_TW">郵件寄送回報</comment>
- <comment xml:lang="zh_CN">邮件投递报告</comment>
- <comment xml:lang="vi">thông báo phát thư</comment>
- <comment xml:lang="uk">звіт про доставку пошти</comment>
- <comment xml:lang="tr">posta iletim raporu</comment>
- <comment xml:lang="sv">e-postleveransrapport</comment>
- <comment xml:lang="sr">извештај доставе поруке</comment>
- <comment xml:lang="sq">Raport mbi dorëzimin e mesazhit</comment>
- <comment xml:lang="sl">poročilo dostave pošte</comment>
- <comment xml:lang="sk">Správa o doručení pošty</comment>
+ <comment>Mail delivery report</comment>
+ <comment xml:lang="uk">звіт щодо доставлення пошти</comment>
+ <comment xml:lang="sv">E-postleveransrapport</comment>
<comment xml:lang="ru">Отчёт о доставке сообщения</comment>
- <comment xml:lang="ro">raport de trimitere email</comment>
- <comment xml:lang="pt_BR">Relatório de entrega de correspondência</comment>
- <comment xml:lang="pt">relatório de entrega de email</comment>
<comment xml:lang="pl">Raport z dostarczenia poczty</comment>
- <comment xml:lang="oc">rapòrt de liurason de corrièrs electronics</comment>
- <comment xml:lang="nn">e-post-leveringsrapport</comment>
- <comment xml:lang="nl">e-mail-bezorgingsbericht</comment>
- <comment xml:lang="nb">e-postleveranserapport</comment>
- <comment xml:lang="ms">Laporan penghantaran mel</comment>
- <comment xml:lang="lv">pasta piegādes atskaite</comment>
- <comment xml:lang="lt">pašto pristatymo ataskaita</comment>
- <comment xml:lang="ko">메일 배달 보고서</comment>
- <comment xml:lang="kk">пошта жеткізілгені туралы отчет</comment>
- <comment xml:lang="ja">メール配送ポート</comment>
<comment xml:lang="it">Rapporto di consegna posta</comment>
- <comment xml:lang="id">laporan pengantaran surat</comment>
- <comment xml:lang="ia">Reporto de livration de e-mail</comment>
- <comment xml:lang="hu">jelentés levélkézbesítésről</comment>
- <comment xml:lang="hr">Izvještaj dostave pošte</comment>
- <comment xml:lang="he">דוח העברת דואר</comment>
- <comment xml:lang="gl">informe de entrega de correo</comment>
- <comment xml:lang="ga">tuairisc sheachadta r-phoist</comment>
- <comment xml:lang="fur">rapuart di consegne pueste</comment>
- <comment xml:lang="fr">rapport de livraison de courriels</comment>
- <comment xml:lang="fo">post útberingarfrásøgn</comment>
- <comment xml:lang="fi">viestin jakeluilmoitus</comment>
- <comment xml:lang="eu">posta banaketako txostena</comment>
+ <comment xml:lang="gl">Informe de envío de coreo electrónico</comment>
<comment xml:lang="es">informe de entrega de correo</comment>
- <comment xml:lang="eo">raporto pri transdono de retpoŝto</comment>
- <comment xml:lang="en_GB">mail delivery report</comment>
- <comment xml:lang="el">Αναφορά παράδοσης μηνύματος</comment>
<comment xml:lang="de">E-Mail-Zustellungsbericht</comment>
- <comment xml:lang="da">postleveringsrapport</comment>
- <comment xml:lang="cy">Adroddiad trosgludo post</comment>
- <comment xml:lang="cs">zpráva o doručení pošty</comment>
- <comment xml:lang="ca">informe de lliurament de correu</comment>
- <comment xml:lang="bg">Отчет за пристигналата поща</comment>
- <comment xml:lang="be@latin">rapart ab dastaŭcy pošty</comment>
- <comment xml:lang="az">poçt yollama raportu</comment>
- <comment xml:lang="ar">تقرير تسليم بريد</comment>
- <comment xml:lang="af">posafleweringverslag</comment>
+ <comment xml:lang="be">справаздача пра дастаўку пошты</comment>
<generic-icon name="text-x-generic"/>
<sub-class-of type="text/plain"/>
</mime-type>
<mime-type type="message/disposition-notification">
- <comment>mail disposition report</comment>
- <comment xml:lang="zh_TW">郵件處置回報</comment>
- <comment xml:lang="zh_CN">邮件接收报告</comment>
- <comment xml:lang="vi">thông báo chuyển nhượng thư</comment>
- <comment xml:lang="uk">звіт про розташування пошти</comment>
- <comment xml:lang="tr">posta silinme raporu</comment>
- <comment xml:lang="sv">e-postdispositionsrapport</comment>
- <comment xml:lang="sr">извештај слања поруке</comment>
- <comment xml:lang="sq">Raport mbi njoftimin e mesazhit</comment>
- <comment xml:lang="sl">poročilo razporeditve pošte</comment>
- <comment xml:lang="sk">Správa o odovzdaní pošty</comment>
+ <comment>Mail disposition report</comment>
+ <comment xml:lang="uk">звіт щодо розташування пошти</comment>
+ <comment xml:lang="sv">E-postdispositionsrapport</comment>
<comment xml:lang="ru">Отчёт о перемещении почты</comment>
- <comment xml:lang="ro">confirmare primire email</comment>
- <comment xml:lang="pt_BR">Relatório de disposição de correspondência</comment>
- <comment xml:lang="pt">relatório de disposição de email</comment>
<comment xml:lang="pl">Raport z wysyłania poczty</comment>
- <comment xml:lang="oc">rapòrt de disposicion de corrièrs electronics</comment>
- <comment xml:lang="nn">e-post-disposisjonsrapport</comment>
- <comment xml:lang="nl">e-mail-plaatsingsbericht</comment>
- <comment xml:lang="nb">e-postdispositionsrapport</comment>
- <comment xml:lang="ms">Laporan pelupusan mel</comment>
- <comment xml:lang="lv">pasta izvietojuma atskaite</comment>
- <comment xml:lang="lt">pašto charakteristikos ataskaita</comment>
- <comment xml:lang="ko">메일 처리 보고서</comment>
- <comment xml:lang="kk">пошта жылжытылғаны туралы отчет</comment>
- <comment xml:lang="ja">メール停止レポート</comment>
<comment xml:lang="it">Rapporto di disposizione posta</comment>
- <comment xml:lang="id">laporan disposisi surat</comment>
- <comment xml:lang="ia">Reporto de disposition de e-mail</comment>
- <comment xml:lang="hu">jelentés levélkidobásról</comment>
- <comment xml:lang="hr">Izvještaj smještaja e-pošte</comment>
- <comment xml:lang="he">דוח אספקת דואר</comment>
- <comment xml:lang="gl">informe de disposición de correo</comment>
- <comment xml:lang="ga">tuairisc chóirithe r-phoist</comment>
- <comment xml:lang="fur">rapuart di disposizion pueste</comment>
- <comment xml:lang="fr">rapport de disposition de courriels</comment>
- <comment xml:lang="fo">post avhendingarfrásøgn</comment>
- <comment xml:lang="fi">viestin kuittausilmoitus</comment>
- <comment xml:lang="eu">posta joerako txostena</comment>
<comment xml:lang="es">informe de disposición de correo</comment>
- <comment xml:lang="eo">raporto pri dispono de retpoŝto</comment>
- <comment xml:lang="en_GB">mail disposition report</comment>
- <comment xml:lang="el">Αναφορά διάθεσης μηνύματος</comment>
<comment xml:lang="de">E-Mail-Übertragungsbericht</comment>
- <comment xml:lang="da">postdisponeringsrapport</comment>
- <comment xml:lang="cy">adroddiad ffurf post</comment>
- <comment xml:lang="cs">zpráva o předání pošty</comment>
- <comment xml:lang="ca">informe de disposició de correu</comment>
- <comment xml:lang="bg">Отчет за състоянието на пощата</comment>
- <comment xml:lang="be@latin">rapart ab raźmiaščeńni pošty</comment>
- <comment xml:lang="az">poçt qayıtma raportu</comment>
- <comment xml:lang="ar">تقرير ترتيب بريد</comment>
+ <comment xml:lang="be">справаздача пра дзеянні з поштай</comment>
<generic-icon name="text-x-generic"/>
<sub-class-of type="text/plain"/>
</mime-type>
<mime-type type="message/external-body">
- <comment>reference to remote file</comment>
- <comment xml:lang="zh_TW">遠端檔案的參照</comment>
- <comment xml:lang="zh_CN">到远程文件的引用</comment>
- <comment xml:lang="vi">tham chiếu đến tập tin ở xa</comment>
+ <comment>Reference to remote file</comment>
<comment xml:lang="uk">посилання на віддалений файл</comment>
- <comment xml:lang="tr">uzaktaki dosyaya atıf</comment>
- <comment xml:lang="sv">referens till fjärrfil</comment>
- <comment xml:lang="sr">упута на удаљену датотеку</comment>
- <comment xml:lang="sq">Referim për tek file në distancë</comment>
- <comment xml:lang="sl">sklic do oddaljene datoteke</comment>
- <comment xml:lang="sk">Odkaz na vzdialený súbor</comment>
+ <comment xml:lang="sv">Referens till fjärrfil</comment>
<comment xml:lang="ru">Ссылка на удалённый файл</comment>
- <comment xml:lang="ro">referință fișier la distanță</comment>
- <comment xml:lang="pt_BR">Referência para arquivo remoto</comment>
- <comment xml:lang="pt">referência a um ficheiro remoto</comment>
<comment xml:lang="pl">Odwołanie do pliku zdalnego</comment>
- <comment xml:lang="oc">referéncia al fichièr distant</comment>
- <comment xml:lang="nn">referanse til fil over nettverk</comment>
- <comment xml:lang="nl">verwijzing naar bestand op afstand</comment>
- <comment xml:lang="nb">referanse til ekstern fil</comment>
- <comment xml:lang="ms">Rujukan ke fail jauh</comment>
- <comment xml:lang="lv">norāde uz attālinātu datni</comment>
- <comment xml:lang="lt">nuoroda į nutolusį failą</comment>
- <comment xml:lang="ko">원격 파일 참조</comment>
- <comment xml:lang="kk">қашықтағы файлға сілтеме</comment>
- <comment xml:lang="ja">リモートファイルへの参照</comment>
<comment xml:lang="it">Riferimento a file remoto</comment>
- <comment xml:lang="id">referensi ke berkas jarak jauh</comment>
- <comment xml:lang="ia">Referentia a un file remote</comment>
- <comment xml:lang="hu">hivatkozás távoli fájlra</comment>
- <comment xml:lang="hr">Preporuka na udaljenu datoteku</comment>
- <comment xml:lang="he">התיחסות לקובץ מרוחק</comment>
- <comment xml:lang="gl">referencia a un ficheiro remoto</comment>
- <comment xml:lang="ga">tagairt do chomhad cianda</comment>
- <comment xml:lang="fur">riferiment a file rimot</comment>
- <comment xml:lang="fr">référence au fichier distant</comment>
- <comment xml:lang="fo">tilvísing til fjarfílu</comment>
- <comment xml:lang="fi">viittaus etätiedostoon</comment>
- <comment xml:lang="eu">erreferentzia urruneko fitxategiari</comment>
- <comment xml:lang="es">referencia a un archivo remoto</comment>
- <comment xml:lang="eo">referenco al fora dosiero</comment>
- <comment xml:lang="en_GB">reference to remote file</comment>
- <comment xml:lang="el">Αναφορά σε απομακρυσμένο αρχείο</comment>
+ <comment xml:lang="es">referencia a archivo remoto</comment>
<comment xml:lang="de">Verweis auf entfernte Datei</comment>
- <comment xml:lang="da">reference til fjern fil</comment>
- <comment xml:lang="cy">cyfeiriad at ffeil bell</comment>
- <comment xml:lang="cs">odkaz na vzdálený soubor</comment>
- <comment xml:lang="ca">referència a fitxer remot</comment>
- <comment xml:lang="bg">Препратка към отдалечен файл</comment>
- <comment xml:lang="be@latin">spasyłka da addalenaha fajłu</comment>
- <comment xml:lang="az">uzaq fayla göstəriş</comment>
- <comment xml:lang="ar">مرجع إلى ملف بعيد</comment>
- <comment xml:lang="af">verwysing na afgeleë lêer</comment>
+ <comment xml:lang="be">спасылка на выдалены файл</comment>
<generic-icon name="text-x-generic"/>
</mime-type>
<mime-type type="message/news">
@@ -31999,8 +33016,9 @@ command to generate the output files.
<comment xml:lang="tr">Usenet haber iletisi</comment>
<comment xml:lang="sv">Usenet-diskussionsgruppsmeddelande</comment>
<comment xml:lang="sr">Порука новости Јузнета</comment>
- <comment xml:lang="sq">Mesazh lajmesh Usenet</comment>
+ <comment xml:lang="sq">mesazh lajmesh Usenet</comment>
<comment xml:lang="sl">novičarsko sporočilo Usenet</comment>
+ <comment xml:lang="si">යූස්නෙට් පුවත් පණිවිඩය</comment>
<comment xml:lang="sk">Príspevok do diskusných skupín Usenet</comment>
<comment xml:lang="ru">Новостное сообщение Usenet</comment>
<comment xml:lang="ro">Mesaj Usenet de știri </comment>
@@ -32018,6 +33036,7 @@ command to generate the output files.
<comment xml:lang="kk">Usenet жаңалық мәлімдемесі</comment>
<comment xml:lang="ja">Usenet news メッセージ</comment>
<comment xml:lang="it">Messaggio news Usenet</comment>
+ <comment xml:lang="is">USENET fréttaskilaboð</comment>
<comment xml:lang="id">Pesan berita Usenet</comment>
<comment xml:lang="ia">Message de gruppo Usenet</comment>
<comment xml:lang="hu">USENET-hírcsoportüzenet</comment>
@@ -32041,6 +33060,7 @@ command to generate the output files.
<comment xml:lang="ca">missatge de notícies Usenet</comment>
<comment xml:lang="bg">Съобщение — Usenet</comment>
<comment xml:lang="be@latin">Navina Usenet</comment>
+ <comment xml:lang="be">навіна Usenet</comment>
<comment xml:lang="az">Usenet xəbərlər ismarışı</comment>
<comment xml:lang="ar">رسالة أخبار Usenet</comment>
<comment xml:lang="af">Usenet-nuusboodskap</comment>
@@ -32053,117 +33073,35 @@ command to generate the output files.
</magic>
</mime-type>
<mime-type type="message/partial">
- <comment>partial email message</comment>
- <comment xml:lang="zh_TW">部份電子郵件訊息</comment>
- <comment xml:lang="zh_CN">部分电子邮件</comment>
- <comment xml:lang="vi">thư điện tử riêng phần</comment>
+ <comment>Partial email message</comment>
<comment xml:lang="uk">часткове поштове повідомлення</comment>
- <comment xml:lang="tr">kısmi eposta iletisi</comment>
- <comment xml:lang="sv">del av e-postmeddelande</comment>
- <comment xml:lang="sr">делимична порука ел. поште</comment>
- <comment xml:lang="sq">Mesazh poste i pjesëshëm</comment>
- <comment xml:lang="sl">delno elektronsko sporočilo</comment>
- <comment xml:lang="sk">Čiastočná e-mailová správa</comment>
+ <comment xml:lang="sv">Del av e-postmeddelande</comment>
<comment xml:lang="ru">Фрагмент сообщения электронной почты</comment>
- <comment xml:lang="ro">mesaj de email parțial</comment>
- <comment xml:lang="pt_BR">Mensagem de e-mail parcial</comment>
- <comment xml:lang="pt">mensagem parcial de email</comment>
<comment xml:lang="pl">Częściowa wiadomość e-mail</comment>
- <comment xml:lang="oc">messatge parcial de corrièr electronic</comment>
- <comment xml:lang="nn">del av e-post-melding</comment>
- <comment xml:lang="nl">gedeeltelijk e-mailbericht</comment>
- <comment xml:lang="nb">del av e-postmelding</comment>
- <comment xml:lang="ms">Bahagian mesej emel</comment>
- <comment xml:lang="lv">daļēja e-pasta vēstule</comment>
- <comment xml:lang="lt">nepilnas el. laiškas</comment>
- <comment xml:lang="ko">전자 우편 메시지 일부</comment>
- <comment xml:lang="kk">электронды поштаның үзінді мәлімдемесі</comment>
- <comment xml:lang="ja">部分メールメッセージ</comment>
<comment xml:lang="it">Messaggio email parziale</comment>
- <comment xml:lang="id">pesan email sebagian</comment>
- <comment xml:lang="ia">Message de e-mail partial</comment>
- <comment xml:lang="hu">részleges elektronikus levél</comment>
- <comment xml:lang="hr">Nepotpuna poruka e-pošte</comment>
- <comment xml:lang="he">מסר דוא״ל חלקי</comment>
- <comment xml:lang="gl">mensaxe de correo electrónico parcial</comment>
- <comment xml:lang="ga">teachtaireacht ríomhphoist neamhiomlán</comment>
- <comment xml:lang="fur">messaç e-mail parziâl</comment>
- <comment xml:lang="fr">message partiel de courriel</comment>
- <comment xml:lang="fi">osittainen sähköpostiviesti</comment>
- <comment xml:lang="eu">posta mezu partziala</comment>
<comment xml:lang="es">mensaje de correo electrónico parcial</comment>
- <comment xml:lang="eo">parta retpoŝta mesaĝo</comment>
- <comment xml:lang="en_GB">partial email message</comment>
- <comment xml:lang="el">Τμηματικό ηλ. μήνυμα</comment>
<comment xml:lang="de">E-Mail-Nachrichtenfragment</comment>
- <comment xml:lang="da">delvis postmeddelelse</comment>
- <comment xml:lang="cy">darn o neges e-bost</comment>
- <comment xml:lang="cs">částečná e-mailová zpráva</comment>
- <comment xml:lang="ca">missatge de correu electrònic parcial</comment>
- <comment xml:lang="bg">Част от електронно писмо</comment>
- <comment xml:lang="be@latin">niapoŭny list email</comment>
- <comment xml:lang="az">qismi poçt ismarışı</comment>
- <comment xml:lang="ar">رسالة بريد إلكتروني جزئية</comment>
- <comment xml:lang="af">gedeeltelike e-posboodskap</comment>
+ <comment xml:lang="be">частка электроннага ліста</comment>
<generic-icon name="text-x-generic"/>
<sub-class-of type="text/plain"/>
</mime-type>
<mime-type type="message/rfc822">
- <comment>email message</comment>
- <comment xml:lang="zh_TW">電子郵件內容</comment>
- <comment xml:lang="zh_CN">电子邮件</comment>
- <comment xml:lang="vi">thư điện tử</comment>
- <comment xml:lang="uk">повідомлення email</comment>
- <comment xml:lang="tr">eposta iletisi</comment>
- <comment xml:lang="sv">e-postmeddelande</comment>
- <comment xml:lang="sr">порука ел. поште</comment>
- <comment xml:lang="sq">Mesazh poste</comment>
- <comment xml:lang="sl">sporočilo elektronske pošte</comment>
- <comment xml:lang="sk">E-mailová správa</comment>
+ <comment>Email message</comment>
+ <comment xml:lang="uk">поштове повідомлення</comment>
+ <comment xml:lang="sv">E-postmeddelande</comment>
<comment xml:lang="ru">Почтовое сообщение</comment>
- <comment xml:lang="ro">mesaj email</comment>
<comment xml:lang="pt_BR">Mensagem de e-mail</comment>
- <comment xml:lang="pt">mensagem de email</comment>
<comment xml:lang="pl">Wiadomość e-mail</comment>
- <comment xml:lang="oc">messatge de corrièr electronic</comment>
- <comment xml:lang="nn">e-postmelding</comment>
- <comment xml:lang="nl">e-mailbericht</comment>
- <comment xml:lang="nb">e-postmelding</comment>
- <comment xml:lang="ms">Mesej emel</comment>
- <comment xml:lang="lv">e-pasta vēstule</comment>
- <comment xml:lang="lt">el. laiškas</comment>
- <comment xml:lang="ko">전자 우편 본문</comment>
- <comment xml:lang="kk">пошталық мәлімдеме</comment>
- <comment xml:lang="ja">メール本文</comment>
<comment xml:lang="it">Messaggio email</comment>
- <comment xml:lang="id">pesan email</comment>
- <comment xml:lang="ia">Message de e-mail</comment>
- <comment xml:lang="hu">elektronikus levél</comment>
- <comment xml:lang="hr">Poruka e-pošte</comment>
- <comment xml:lang="he">הודעת דואר אלקטרוני</comment>
- <comment xml:lang="gl">mensaxe de correo electrónico</comment>
- <comment xml:lang="ga">teachtaireacht ríomhphoist</comment>
- <comment xml:lang="fur">messaç e-mail</comment>
- <comment xml:lang="fr">message de courriel</comment>
- <comment xml:lang="fo">t-post boð</comment>
- <comment xml:lang="fi">sähköpostiviesti</comment>
- <comment xml:lang="eu">helbide elektronikoen mezua</comment>
+ <comment xml:lang="gl">Mensaxe de correo electrónico</comment>
<comment xml:lang="es">mensaje de correo electrónico</comment>
- <comment xml:lang="eo">retpoŝta mesaĝo</comment>
- <comment xml:lang="en_GB">email message</comment>
- <comment xml:lang="el">Ηλ. μήνυμα</comment>
<comment xml:lang="de">E-Mail-Nachricht</comment>
- <comment xml:lang="da">postmeddelelse</comment>
- <comment xml:lang="cs">e-mailová zpráva</comment>
- <comment xml:lang="ca">missatge de correu electrònic</comment>
- <comment xml:lang="bg">Съобщение по електронната поща</comment>
- <comment xml:lang="be@latin">list email</comment>
- <comment xml:lang="ar">رسالة بريد إلكتروني</comment>
- <comment xml:lang="af">e-posboodskap</comment>
+ <comment xml:lang="be">электронны ліст</comment>
<generic-icon name="text-x-generic"/>
<sub-class-of type="text/plain"/>
<magic>
<match type="string" value="#! rnews" offset="0"/>
+ <match type="string" value="Content-Type:" offset="0"/>
<match type="string" value="Forward to" offset="0"/>
<match type="string" value="From:" offset="0"/>
<match type="string" value="N#! rnews" offset="0"/>
@@ -32173,6 +33111,7 @@ command to generate the output files.
<match type="string" value="Return-Path:" offset="0"/>
<match type="string" value="Return-path:" offset="0"/>
<match type="string" value="Subject: " offset="0"/>
+ <match type="string" value="To:" offset="0"/>
</magic>
<glob pattern="*.eml"/>
</mime-type>
@@ -32185,8 +33124,9 @@ command to generate the output files.
<comment xml:lang="tr">GNU posta iletisi</comment>
<comment xml:lang="sv">GNU-epostmeddelande</comment>
<comment xml:lang="sr">порука Гнуове поште</comment>
- <comment xml:lang="sq">Mesazh GNU mail</comment>
+ <comment xml:lang="sq">mesazh GNU mail</comment>
<comment xml:lang="sl">Sporočilo pošte GNU</comment>
+ <comment xml:lang="si">GNU තැපැල් පණිවිඩය</comment>
<comment xml:lang="sk">Správa GNU mail</comment>
<comment xml:lang="ru">Почтовое сообщение GNU</comment>
<comment xml:lang="ro">Mesaj GNU mail</comment>
@@ -32205,6 +33145,7 @@ command to generate the output files.
<comment xml:lang="ka">GNU mail შეტყობინება</comment>
<comment xml:lang="ja">GNU メールメッセージ</comment>
<comment xml:lang="it">Messaggio GNU mail</comment>
+ <comment xml:lang="is">GNU póst skilaboð</comment>
<comment xml:lang="id">Pesan surat GNU</comment>
<comment xml:lang="ia">Message electronic de GNU</comment>
<comment xml:lang="hu">GNU elektronikus levél</comment>
@@ -32228,6 +33169,7 @@ command to generate the output files.
<comment xml:lang="ca">missatge de GNU mail</comment>
<comment xml:lang="bg">Съобщение — GNU mail</comment>
<comment xml:lang="be@latin">List GNU</comment>
+ <comment xml:lang="be">электронны ліст GNU</comment>
<comment xml:lang="az">GNU poçt ismarışı</comment>
<comment xml:lang="ar">رسالة بريد جنو</comment>
<comment xml:lang="af">GNU-posboodskap</comment>
@@ -32242,19 +33184,25 @@ command to generate the output files.
<comment xml:lang="tr">IGES belgesi</comment>
<comment xml:lang="sv">IGES-dokument</comment>
<comment xml:lang="sr">ИГЕС документ</comment>
+ <comment xml:lang="sq">dokument IGES</comment>
<comment xml:lang="sl">Dokument IGES</comment>
+ <comment xml:lang="si">IGES ලේඛනය</comment>
<comment xml:lang="sk">Dokument IGES</comment>
<comment xml:lang="ru">Документ IGES</comment>
<comment xml:lang="pt_BR">Documento IGES</comment>
<comment xml:lang="pl">Dokument IGES</comment>
+ <comment xml:lang="oc">document IGES</comment>
+ <comment xml:lang="nl">IGES-document</comment>
<comment xml:lang="ko">IGES 문서</comment>
<comment xml:lang="kk">IGES құжаты</comment>
<comment xml:lang="ja">IGES ドキュメント</comment>
<comment xml:lang="it">Documento IGES</comment>
+ <comment xml:lang="is">IGES skjalskjal</comment>
<comment xml:lang="id">Dokumen IGES</comment>
<comment xml:lang="hu">IGES dokumentum</comment>
<comment xml:lang="hr">IGES dokument</comment>
<comment xml:lang="he">מסמך IGES</comment>
+ <comment xml:lang="gl">Documento IGES</comment>
<comment xml:lang="ga">cáipéis IGES</comment>
<comment xml:lang="fur">document IGES</comment>
<comment xml:lang="fr">document IGES</comment>
@@ -32267,6 +33215,7 @@ command to generate the output files.
<comment xml:lang="cs">dokument IGES</comment>
<comment xml:lang="ca">document IGES</comment>
<comment xml:lang="bg">Документ — IGES</comment>
+ <comment xml:lang="be">дакумент IGES</comment>
<comment xml:lang="ast">Documentu IGES</comment>
<comment xml:lang="ar">مستند IGES</comment>
<comment xml:lang="af">IGES-dokument</comment>
@@ -32283,8 +33232,34 @@ command to generate the output files.
</mime-type>
<mime-type type="model/gltf-binary">
<comment>glTF model</comment>
+ <comment xml:lang="zh_CN">glTF 模型</comment>
+ <comment xml:lang="uk">модель glTF</comment>
+ <comment xml:lang="tr">glTF modeli</comment>
+ <comment xml:lang="sv">glTF-modell</comment>
+ <comment xml:lang="sl">Model gITF</comment>
+ <comment xml:lang="si">glTF ආකෘතිය</comment>
+ <comment xml:lang="ru">glTF-модель</comment>
+ <comment xml:lang="pt_BR">Modelo gITF</comment>
+ <comment xml:lang="pl">Model glTF</comment>
+ <comment xml:lang="oc">modèl glTF</comment>
+ <comment xml:lang="nl">glTF-model</comment>
+ <comment xml:lang="ko">glTF 모델</comment>
+ <comment xml:lang="kk">glTF моделі</comment>
+ <comment xml:lang="ja">glTF モデル</comment>
+ <comment xml:lang="it">Modello glTF</comment>
+ <comment xml:lang="hr">glTF model</comment>
+ <comment xml:lang="he">דגם gITF</comment>
+ <comment xml:lang="gl">Modelo glTF</comment>
+ <comment xml:lang="fi">glTF malli</comment>
+ <comment xml:lang="eu">glTF eredua</comment>
+ <comment xml:lang="es">modelo gITF</comment>
+ <comment xml:lang="en_GB">glTF model</comment>
+ <comment xml:lang="de">glTF-Modell</comment>
+ <comment xml:lang="be">мадэль glTF</comment>
+ <comment xml:lang="ar">نموذج glTF</comment>
<acronym>glTF</acronym>
<expanded-acronym>GL Transmission Format</expanded-acronym>
+ <generic-icon name="image-x-generic"/>
<magic>
<match type="string" value="glTF" offset="0"/>
</magic>
@@ -32292,8 +33267,34 @@ command to generate the output files.
</mime-type>
<mime-type type="model/gltf+json">
<comment>glTF model</comment>
+ <comment xml:lang="zh_CN">glTF 模型</comment>
+ <comment xml:lang="uk">модель glTF</comment>
+ <comment xml:lang="tr">glTF modeli</comment>
+ <comment xml:lang="sv">glTF-modell</comment>
+ <comment xml:lang="sl">Model gITF</comment>
+ <comment xml:lang="si">glTF ආකෘතිය</comment>
+ <comment xml:lang="ru">glTF-модель</comment>
+ <comment xml:lang="pt_BR">Modelo gITF</comment>
+ <comment xml:lang="pl">Model glTF</comment>
+ <comment xml:lang="oc">modèl glTF</comment>
+ <comment xml:lang="nl">glTF-model</comment>
+ <comment xml:lang="ko">glTF 모델</comment>
+ <comment xml:lang="kk">glTF моделі</comment>
+ <comment xml:lang="ja">glTF モデル</comment>
+ <comment xml:lang="it">Modello glTF</comment>
+ <comment xml:lang="hr">glTF model</comment>
+ <comment xml:lang="he">דגם gITF</comment>
+ <comment xml:lang="gl">Modelo glTF</comment>
+ <comment xml:lang="fi">glTF malli</comment>
+ <comment xml:lang="eu">glTF eredua</comment>
+ <comment xml:lang="es">modelo gITF</comment>
+ <comment xml:lang="en_GB">glTF model</comment>
+ <comment xml:lang="de">glTF-Modell</comment>
+ <comment xml:lang="be">мадэль glTF</comment>
+ <comment xml:lang="ar">نموذج glTF</comment>
<acronym>glTF</acronym>
<expanded-acronym>GL Transmission Format</expanded-acronym>
+ <generic-icon name="image-x-generic"/>
<sub-class-of type="application/json"/>
<glob pattern="*.gltf"/>
</mime-type>
@@ -32306,8 +33307,9 @@ command to generate the output files.
<comment xml:lang="tr">VRML belgesi</comment>
<comment xml:lang="sv">VRML-dokument</comment>
<comment xml:lang="sr">ВРМЛ документ</comment>
- <comment xml:lang="sq">Dokument VRML</comment>
+ <comment xml:lang="sq">dokument VRML</comment>
<comment xml:lang="sl">Dokument VRML</comment>
+ <comment xml:lang="si">VRML ලේඛනය</comment>
<comment xml:lang="sk">Dokument VRML</comment>
<comment xml:lang="ru">Документ VRML</comment>
<comment xml:lang="ro">Document VRML</comment>
@@ -32325,6 +33327,7 @@ command to generate the output files.
<comment xml:lang="kk">VRML құжаты</comment>
<comment xml:lang="ja">VRML ドキュメント</comment>
<comment xml:lang="it">Documento VRML</comment>
+ <comment xml:lang="is">VRML skjal</comment>
<comment xml:lang="id">Dokumen VRML</comment>
<comment xml:lang="ia">Documento VRML</comment>
<comment xml:lang="hu">VRML-dokumentum</comment>
@@ -32348,6 +33351,7 @@ command to generate the output files.
<comment xml:lang="ca">document VRML</comment>
<comment xml:lang="bg">Документ — VRML</comment>
<comment xml:lang="be@latin">Dakument VRML</comment>
+ <comment xml:lang="be">дакумент VRML</comment>
<comment xml:lang="az">VRML sənədi</comment>
<comment xml:lang="ast">Documentu VRML</comment>
<comment xml:lang="ar">مستند VRML</comment>
@@ -32365,7 +33369,32 @@ command to generate the output files.
</mime-type>
<mime-type type="model/obj">
<comment>OBJ 3D model</comment>
+ <comment xml:lang="zh_CN">OBJ 3D 模型</comment>
+ <comment xml:lang="uk">просторова модель OBJ</comment>
+ <comment xml:lang="tr">OBJ 3B modeli</comment>
+ <comment xml:lang="sv">OBJ-3D-modell</comment>
+ <comment xml:lang="sl">3D-model OBJ</comment>
+ <comment xml:lang="si">OBJ 3D ආකෘතිය</comment>
+ <comment xml:lang="ru">OBJ 3D-модель</comment>
+ <comment xml:lang="pt_BR">Modelo OBJ 3D</comment>
+ <comment xml:lang="pl">Model 3D OBJ</comment>
+ <comment xml:lang="oc">modèl OBJ 3D</comment>
+ <comment xml:lang="nl">OBJ 3D-model</comment>
+ <comment xml:lang="ko">OBJ 3D 모델</comment>
+ <comment xml:lang="kk">OBJ 3D моделі</comment>
+ <comment xml:lang="ja">OBJ 3D モデル</comment>
+ <comment xml:lang="it">Modello OBJ 3D</comment>
+ <comment xml:lang="hr">OBJ 3D model</comment>
+ <comment xml:lang="gl">Modelo OBJ 3D</comment>
+ <comment xml:lang="fi">OBJ 3D-malli</comment>
+ <comment xml:lang="eu">OBJ 3D eredua</comment>
+ <comment xml:lang="es">modelo OBJ 3D</comment>
+ <comment xml:lang="en_GB">OBJ 3D model</comment>
+ <comment xml:lang="de">OBJ-3D-Modell</comment>
+ <comment xml:lang="be">мадэль OBJ 3D</comment>
+ <comment xml:lang="ar">نموذج OBJ 3D</comment>
<sub-class-of type="text/plain"/>
+ <generic-icon name="image-x-generic"/>
<magic>
<match type="string" value=" OBJ File: '" offset="0:64"/>
<match type="string" value="mtllib " offset="0:256"/>
@@ -32374,6 +33403,26 @@ command to generate the output files.
</mime-type>
<mime-type type="model/mtl">
<comment>OBJ 3D model material library</comment>
+ <comment xml:lang="uk">бібліотека матеріалів просторової моделі OBJ</comment>
+ <comment xml:lang="tr">OBJ 3B modeli malzeme kitaplığı</comment>
+ <comment xml:lang="sv">Materialbibliotek för OBJ 3D-modell</comment>
+ <comment xml:lang="sl">Knjižnica materialov 3D-modelov OBJ</comment>
+ <comment xml:lang="si">OBJ 3D ආදර්ශ ද්රව්ය පුස්තකාලය</comment>
+ <comment xml:lang="ru">Библиотека материалов OBJ 3D-модели</comment>
+ <comment xml:lang="pl">Biblioteka materiałów modeli 3D OBJ</comment>
+ <comment xml:lang="nl">OBJ-3D-model-materiaal­bibliotheek</comment>
+ <comment xml:lang="ko">OBJ 3D 모델 실체 라이브러리</comment>
+ <comment xml:lang="kk">OBJ 3D-моделінің материалдар кітапханасы</comment>
+ <comment xml:lang="ja">OBJ 3D モデルマテリアルライブラリー</comment>
+ <comment xml:lang="it">Modello libreria materiale OBJ 3D</comment>
+ <comment xml:lang="hr">OBJ 3D model biblioteka materijala</comment>
+ <comment xml:lang="fi">OBJ 3D-mallin materiaalikirjasto</comment>
+ <comment xml:lang="es">biblioteca de modelo material OBJ 3D</comment>
+ <comment xml:lang="en_GB">OBJ 3D model material library</comment>
+ <comment xml:lang="de">OBJ-3D-Modell-Materialbibliothek</comment>
+ <comment xml:lang="be">бібліятэка матэрыялаў мадэлі OBJ 3D</comment>
+ <comment xml:lang="ar">مكتبة المواد النموذجية OBJ 3D</comment>
+ <generic-icon name="image-x-generic"/>
<sub-class-of type="text/plain"/>
<magic>
<match type="string" value="# Blender MTL File: '" offset="0"/>
@@ -32382,59 +33431,15 @@ command to generate the output files.
<glob pattern="*.mtl"/>
</mime-type>
<mime-type type="multipart/alternative">
- <comment>message in several formats</comment>
- <comment xml:lang="zh_TW">多種格式的訊息</comment>
- <comment xml:lang="zh_CN">各种格式的信件</comment>
- <comment xml:lang="vi">thông điệp có vài định dạng</comment>
+ <comment>Message in several formats</comment>
<comment xml:lang="uk">повідомлення у кількох форматах</comment>
- <comment xml:lang="tr">farklı biçimlerde ileti</comment>
- <comment xml:lang="sv">meddelande i flera format</comment>
- <comment xml:lang="sr">порука у неколико записа</comment>
- <comment xml:lang="sq">Mesazh në formate të ndryshëm</comment>
- <comment xml:lang="sl">sporočilo v več zapisih</comment>
- <comment xml:lang="sk">Správa v niekoľkých formátoch</comment>
+ <comment xml:lang="sv">Meddelande i flera format</comment>
<comment xml:lang="ru">Сообщение в нескольких форматах</comment>
- <comment xml:lang="ro">mesaj în diferite formate</comment>
- <comment xml:lang="pt_BR">Mensagem em vários formatos</comment>
- <comment xml:lang="pt">mensagem em vários formatos</comment>
<comment xml:lang="pl">Wiadomość w wielu formatach</comment>
- <comment xml:lang="oc">messatge en formats divèrses</comment>
- <comment xml:lang="nn">melding i fleire format</comment>
- <comment xml:lang="nl">bericht in meerdere opmaken</comment>
- <comment xml:lang="nb">melding i flere formater</comment>
- <comment xml:lang="ms">Mesej dalam beberapa format</comment>
- <comment xml:lang="lv">ziņojums dažādos formātos</comment>
- <comment xml:lang="lt">laiškas keletu formatų</comment>
- <comment xml:lang="ko">여러 가지 형식의 메시지</comment>
- <comment xml:lang="kk">бірнеше пішімдегі мәлімдеме</comment>
- <comment xml:lang="ja">いくつかの形式でのメッセージ</comment>
<comment xml:lang="it">Messaggio in diversi formati</comment>
- <comment xml:lang="id">pesan dalam beberapa format</comment>
- <comment xml:lang="ia">Message in plure formatos</comment>
- <comment xml:lang="hu">többféle formátumú üzenet</comment>
- <comment xml:lang="hr">Poruka u nekoliko oblika</comment>
- <comment xml:lang="he">הודעה במספר תבניות</comment>
- <comment xml:lang="gl">mensaxe en varios formatos</comment>
- <comment xml:lang="ga">teachtaireacht i bhformáidí éagsúla</comment>
- <comment xml:lang="fur">messaç in diviers formâts</comment>
- <comment xml:lang="fr">message en formats divers</comment>
- <comment xml:lang="fo">boð í fleiri sniðum</comment>
- <comment xml:lang="fi">viesti useissa muodoissa</comment>
- <comment xml:lang="eu">hainbat formatuko mezua</comment>
<comment xml:lang="es">mensaje en varios formatos</comment>
- <comment xml:lang="eo">mesaĝo en pluraj formatoj</comment>
- <comment xml:lang="en_GB">message in several formats</comment>
- <comment xml:lang="el">Μήνυμα σε διάφορες μορφές</comment>
- <comment xml:lang="de">Nachricht in mehreren Formaten</comment>
- <comment xml:lang="da">meddelelse i flere formater</comment>
- <comment xml:lang="cy">neges mewn sawl fformat</comment>
- <comment xml:lang="cs">zpráva v několika formátech</comment>
- <comment xml:lang="ca">missatge en diversos formats</comment>
- <comment xml:lang="bg">Съобщение в няколко формата</comment>
- <comment xml:lang="be@latin">paviedamleńnie ŭ niekalkich farmatach</comment>
- <comment xml:lang="az">verici formatlarında ismarış</comment>
- <comment xml:lang="ar">رسالة في عدة صيغ</comment>
- <comment xml:lang="af">boodskap in verskeie formate</comment>
+ <comment xml:lang="de">Nachricht in verschiedenen Formaten</comment>
+ <comment xml:lang="be">паведамленне ў некалькіх фарматах</comment>
</mime-type>
<mime-type type="multipart/appledouble">
<comment>Macintosh AppleDouble-encoded file</comment>
@@ -32445,8 +33450,9 @@ command to generate the output files.
<comment xml:lang="tr">Macintosh AppleDouble-şifreli dosyası</comment>
<comment xml:lang="sv">Macintosh AppleDouble-kodad fil</comment>
<comment xml:lang="sr">Мекинтошова датотека кодирана Епл Дуплим</comment>
- <comment xml:lang="sq">File Macintosh i kodifikuar AppleDouble</comment>
+ <comment xml:lang="sq">kartelë Macintosh koduar me AppleDouble</comment>
<comment xml:lang="sl">Kodirana datoteka Macintosh (AppleDouble)</comment>
+ <comment xml:lang="si">Macintosh AppleDouble-කේතනය කළ ගොනුව</comment>
<comment xml:lang="sk">Súbor kódovaný pomocou Macintosh AppleDouble</comment>
<comment xml:lang="ru">Файл, закодированный Macintosh AppleDouble</comment>
<comment xml:lang="ro">Fișier codat Macintosh AppleDouble</comment>
@@ -32464,6 +33470,7 @@ command to generate the output files.
<comment xml:lang="kk">Macintosh AppleDouble кодталған файлы</comment>
<comment xml:lang="ja">Macintosh AppleDouble エンコードファイル</comment>
<comment xml:lang="it">File Macintosh codificato AppleDouble</comment>
+ <comment xml:lang="is">Macintosh AppleDouble-kóðuð skrá</comment>
<comment xml:lang="id">Berkas tersandi Macintosh AppleDouble</comment>
<comment xml:lang="ia">File codificate in AppleDouble de Macintosh</comment>
<comment xml:lang="hu">Macintosh AppleDouble kódolású fájl</comment>
@@ -32480,396 +33487,90 @@ command to generate the output files.
<comment xml:lang="eo">dosiero kodigita laŭ Macintosh AppleDouble</comment>
<comment xml:lang="en_GB">Macintosh AppleDouble-encoded file</comment>
<comment xml:lang="el">Αρχείο Macintosh κωδικοποίησης AppleDouble</comment>
- <comment xml:lang="de">Macintosh-Datei (AppleDouble-kodiert)</comment>
+ <comment xml:lang="de">Macintosh-Datei (AppleDouble-Format)</comment>
<comment xml:lang="da">Macintosh AppleDouble-kodet fil</comment>
<comment xml:lang="cy">Ffeil AppleDouble-amgodedig Macintosh</comment>
<comment xml:lang="cs">soubor kódovaný pomocí Macintosh AppleDouble</comment>
<comment xml:lang="ca">fitxer codificat AppleDouble de Macintosh</comment>
<comment xml:lang="bg">Файл — кодиран с Macintosh AppleDouble</comment>
<comment xml:lang="be@latin">Fajł Macintosh, AppleDouble-zakadavany</comment>
+ <comment xml:lang="be">файл з кадаваннем Macintosh AppleDouble</comment>
<comment xml:lang="az">Macintosh AppleDouble-kodlanmış fayl</comment>
<comment xml:lang="ar">ملف Macintosh AppleDouble مشفر</comment>
<comment xml:lang="af">Macintosh AppleDouble-geënkodeerde lêer</comment>
</mime-type>
<mime-type type="multipart/digest">
- <comment>message digest</comment>
- <comment xml:lang="zh_TW">訊息摘要</comment>
- <comment xml:lang="zh_CN">信件摘要</comment>
- <comment xml:lang="vi">bản tóm tắt thông điệp</comment>
- <comment xml:lang="uk">збірка повідомлень</comment>
- <comment xml:lang="tr">ileti özeti</comment>
- <comment xml:lang="sv">meddelandesamling</comment>
- <comment xml:lang="sr">гомила порука</comment>
- <comment xml:lang="sq">Shpërndarje mesazhesh</comment>
- <comment xml:lang="sl">povzetek sporočila</comment>
- <comment xml:lang="sk">Prehľad správ</comment>
+ <comment>Message digest</comment>
+ <comment xml:lang="uk">контрольна сума повідомлення</comment>
+ <comment xml:lang="sv">Meddelandesamling</comment>
<comment xml:lang="ru">Дайджест сообщения</comment>
- <comment xml:lang="ro">colecție mesaje email</comment>
- <comment xml:lang="pt_BR">Resumo de mensagem</comment>
- <comment xml:lang="pt">grupo de mensagens</comment>
<comment xml:lang="pl">Wiadomość przetwarzania</comment>
- <comment xml:lang="oc">condensé de messatge</comment>
- <comment xml:lang="nn">meldingsamandrag</comment>
- <comment xml:lang="nl">berichtenbundel</comment>
- <comment xml:lang="nb">medldingssamling</comment>
- <comment xml:lang="ms">Jilid mesej</comment>
- <comment xml:lang="lv">ziņojumu apkopojums</comment>
- <comment xml:lang="lt">laiškų santrauka</comment>
- <comment xml:lang="ko">메시지 묶음</comment>
- <comment xml:lang="kk">мәлімдеме профилі</comment>
- <comment xml:lang="ja">メッセージダイジェスト</comment>
<comment xml:lang="it">Digest di messaggi</comment>
- <comment xml:lang="id">digest pesan</comment>
- <comment xml:lang="ia">Digesto de messages</comment>
- <comment xml:lang="hu">ömlesztett üzenet</comment>
- <comment xml:lang="hr">Poruka kratkg sadržaja</comment>
- <comment xml:lang="he">תקציר ההודעה</comment>
- <comment xml:lang="gl">recompilación de mensaxe</comment>
- <comment xml:lang="ga">achoimre theachtaireachtaí</comment>
- <comment xml:lang="fur">sunt di messaç</comment>
- <comment xml:lang="fr">condensé de message</comment>
- <comment xml:lang="fo">boð samandráttur</comment>
- <comment xml:lang="fi">viestikokoelma</comment>
- <comment xml:lang="eu">mezu laburra</comment>
- <comment xml:lang="es">recopilación de mensajes</comment>
- <comment xml:lang="eo">mesaĝaro</comment>
- <comment xml:lang="en_GB">message digest</comment>
- <comment xml:lang="el">Περίληψη μηνύματος</comment>
+ <comment xml:lang="es">resumen de mensajes</comment>
<comment xml:lang="de">Nachrichtensammlung</comment>
- <comment xml:lang="da">meddelelsessammendrag</comment>
- <comment xml:lang="cy">crynodeb negeseuon</comment>
- <comment xml:lang="cs">přehled zpráv</comment>
- <comment xml:lang="ca">recopilació de missatges</comment>
- <comment xml:lang="bg">Извадка от съобщение</comment>
- <comment xml:lang="be@latin">digest paviedamleńniaŭ</comment>
- <comment xml:lang="az">ismarış daycesti</comment>
- <comment xml:lang="ar">خلاصة رسالة</comment>
+ <comment xml:lang="be">дайджэст паведамлення</comment>
</mime-type>
<mime-type type="multipart/encrypted">
- <comment>encrypted message</comment>
- <comment xml:lang="zh_TW">加密訊息</comment>
- <comment xml:lang="zh_CN">加密信件</comment>
- <comment xml:lang="vi">thông điệp đã mật mã</comment>
- <comment xml:lang="uk">шифроване повідомлення</comment>
- <comment xml:lang="tr">şifrelenmiş ileti</comment>
- <comment xml:lang="sv">krypterat meddelande</comment>
- <comment xml:lang="sr">шифрована порука</comment>
- <comment xml:lang="sq">Mesazh i kriptuar</comment>
- <comment xml:lang="sl">šifrirano sporočilo</comment>
- <comment xml:lang="sk">Zašifrovaná správa</comment>
+ <comment>Encrypted message</comment>
+ <comment xml:lang="uk">зашифроване повідомлення</comment>
+ <comment xml:lang="sv">Krypterat meddelande</comment>
<comment xml:lang="ru">Зашифрованное сообщение</comment>
- <comment xml:lang="ro">mesaj criptat</comment>
- <comment xml:lang="pt_BR">Mensagem criptografada</comment>
- <comment xml:lang="pt">mensagem encriptada</comment>
<comment xml:lang="pl">Wiadomość zaszyfrowana</comment>
- <comment xml:lang="oc">messatge chifrat</comment>
- <comment xml:lang="nn">kryptert melding</comment>
- <comment xml:lang="nl">versleuteld bericht</comment>
- <comment xml:lang="nb">kryptert melding</comment>
- <comment xml:lang="ms">Mesej terenkripsi</comment>
- <comment xml:lang="lv">šifrēta vēstule</comment>
- <comment xml:lang="lt">užšifruotas laiškas</comment>
- <comment xml:lang="ko">암호화된 메시지</comment>
- <comment xml:lang="kk">шифрленген мәлімдеме</comment>
- <comment xml:lang="ja">暗号化メッセージ</comment>
<comment xml:lang="it">Messaggio cifrato</comment>
- <comment xml:lang="id">pesan terenkripsi</comment>
- <comment xml:lang="ia">Message cryptate</comment>
- <comment xml:lang="hu">titkosított üzenet</comment>
- <comment xml:lang="hr">Šifrirana poruka</comment>
- <comment xml:lang="he">הודעה מוצפנת</comment>
- <comment xml:lang="gl">mensaxe cifrado</comment>
- <comment xml:lang="ga">teachtaireacht chriptithe</comment>
- <comment xml:lang="fur">messaç cifrât</comment>
- <comment xml:lang="fr">message chiffré</comment>
- <comment xml:lang="fo">bronglað boð</comment>
- <comment xml:lang="fi">salattu viesti</comment>
- <comment xml:lang="eu">zifratutako mezua</comment>
<comment xml:lang="es">mensaje cifrado</comment>
- <comment xml:lang="eo">ĉifrita mesaĝo</comment>
- <comment xml:lang="en_GB">encrypted message</comment>
- <comment xml:lang="el">Κρυπτογραφημένο μήνυμα</comment>
<comment xml:lang="de">Verschlüsselte Nachricht</comment>
- <comment xml:lang="da">krypteret meddelelse</comment>
- <comment xml:lang="cy">Neges wedi ei hamgryptio</comment>
- <comment xml:lang="cs">zašifrovaná zpráva</comment>
- <comment xml:lang="ca">missatge xifrat</comment>
- <comment xml:lang="bg">Шифрирано съобщение</comment>
- <comment xml:lang="be@latin">zašyfravanaje paviedamleńnie</comment>
- <comment xml:lang="az">şifrələnmiş ismarış</comment>
- <comment xml:lang="ar">رسالة مشفرة</comment>
- <comment xml:lang="af">geënkripteerde boodskap</comment>
+ <comment xml:lang="be">зашыфраванае паведамленне</comment>
</mime-type>
<mime-type type="multipart/mixed">
- <comment>compound documents</comment>
- <comment xml:lang="zh_TW">複合文件</comment>
- <comment xml:lang="zh_CN">组合文档</comment>
- <comment xml:lang="vi">tài liệu ghép</comment>
+ <comment>Compound documents</comment>
<comment xml:lang="uk">складні документи</comment>
- <comment xml:lang="tr">bileşik belgeler</comment>
- <comment xml:lang="sv">sammansatta dokument</comment>
- <comment xml:lang="sr">сједињени документи</comment>
- <comment xml:lang="sq">dokumente të përbërë</comment>
- <comment xml:lang="sl">združeni dokumenti</comment>
- <comment xml:lang="sk">Zložené dokumenty</comment>
+ <comment xml:lang="sv">Sammansatta dokument</comment>
<comment xml:lang="ru">Составные документы</comment>
- <comment xml:lang="ro">documente compuse</comment>
- <comment xml:lang="pt_BR">Documentos compostos</comment>
- <comment xml:lang="pt">documentos compostos</comment>
<comment xml:lang="pl">Dokumenty złożone</comment>
- <comment xml:lang="oc">documents compausats</comment>
- <comment xml:lang="nn">samansette dokument</comment>
- <comment xml:lang="nl">samengestelde documenten</comment>
- <comment xml:lang="nb">sammensatte dokumenter</comment>
- <comment xml:lang="ms">Dokumen halaman</comment>
- <comment xml:lang="lv">salikti dokumenti</comment>
- <comment xml:lang="lt">sudurtiniai dokumentai</comment>
- <comment xml:lang="ko">복합 문서</comment>
- <comment xml:lang="kk">құрама құжаттары</comment>
- <comment xml:lang="ja">複合ドキュメント</comment>
<comment xml:lang="it">Documenti composti</comment>
- <comment xml:lang="id">dokumen kompon</comment>
- <comment xml:lang="ia">Documentos composite</comment>
- <comment xml:lang="hu">összetett dokumentumok</comment>
- <comment xml:lang="hr">Složeni dokumenti</comment>
- <comment xml:lang="he">מסמכים מורכבים</comment>
- <comment xml:lang="gl">documentos compostos</comment>
- <comment xml:lang="ga">cáipéisí comhshuite</comment>
- <comment xml:lang="fur">documents composcj</comment>
- <comment xml:lang="fr">documents composés</comment>
- <comment xml:lang="fo">samansett skjøl</comment>
- <comment xml:lang="fi">yhdisteasiakirjat</comment>
- <comment xml:lang="eu">konposatutako dokumentuak</comment>
- <comment xml:lang="es">documentos compuestos</comment>
- <comment xml:lang="eo">parentezaj dokumentoj</comment>
- <comment xml:lang="en_GB">compound documents</comment>
- <comment xml:lang="el">Σύνθετα έγγραφα</comment>
<comment xml:lang="de">Verbunddokumente</comment>
- <comment xml:lang="da">sammensatte dokumenter</comment>
- <comment xml:lang="cs">složené dokumenty</comment>
- <comment xml:lang="ca">documents compostos</comment>
- <comment xml:lang="bg">Съставни документи</comment>
- <comment xml:lang="be@latin">składanyja dakumenty</comment>
- <comment xml:lang="ast">documentos compuestos</comment>
- <comment xml:lang="ar">مستندات مركبة</comment>
- <comment xml:lang="af">saamgestelde dokumente</comment>
+ <comment xml:lang="be">складаныя дакументы</comment>
</mime-type>
<mime-type type="multipart/related">
- <comment>compound document</comment>
- <comment xml:lang="zh_TW">複合文件</comment>
- <comment xml:lang="zh_CN">组合文档</comment>
- <comment xml:lang="vi">tài liệu ghép</comment>
+ <comment>Compound document</comment>
<comment xml:lang="uk">складний документ</comment>
- <comment xml:lang="tr">bileşik belge</comment>
- <comment xml:lang="sv">sammansatt dokument</comment>
- <comment xml:lang="sr">сједињени документ</comment>
- <comment xml:lang="sq">dokumet i përbërë</comment>
- <comment xml:lang="sl">združeni dokument</comment>
- <comment xml:lang="sk">Zložený dokument</comment>
+ <comment xml:lang="sv">Sammansatt dokument</comment>
<comment xml:lang="ru">Составной документ</comment>
- <comment xml:lang="ro">document compus</comment>
- <comment xml:lang="pt_BR">Documento composto</comment>
- <comment xml:lang="pt">documento composto</comment>
<comment xml:lang="pl">Dokument złożony</comment>
- <comment xml:lang="oc">document compausat</comment>
- <comment xml:lang="nn">samansett dokument</comment>
- <comment xml:lang="nl">samengesteld document</comment>
- <comment xml:lang="nb">sammensatt dokument</comment>
- <comment xml:lang="ms">Dokumen halaman</comment>
- <comment xml:lang="lv">salikts dokuments</comment>
- <comment xml:lang="lt">sudurtinis dokumentas</comment>
- <comment xml:lang="ko">복합 문서</comment>
- <comment xml:lang="kk">құрама құжаты</comment>
- <comment xml:lang="ja">複合ドキュメント</comment>
<comment xml:lang="it">Documento composto</comment>
- <comment xml:lang="id">dokumen kompon</comment>
- <comment xml:lang="ia">Documento composite</comment>
- <comment xml:lang="hu">összetett dokumentum</comment>
- <comment xml:lang="hr">Složeni dokument</comment>
- <comment xml:lang="he">מסמך מורכב</comment>
- <comment xml:lang="gl">documento composto</comment>
- <comment xml:lang="ga">cáipéis comhshuite</comment>
- <comment xml:lang="fur">document compost</comment>
- <comment xml:lang="fr">document composé</comment>
- <comment xml:lang="fo">samansett skjal</comment>
- <comment xml:lang="fi">yhdisteasiakirja</comment>
- <comment xml:lang="eu">konposatutako dokumentua</comment>
- <comment xml:lang="es">documento compuesto</comment>
- <comment xml:lang="eo">parenteza dokumento</comment>
- <comment xml:lang="en_GB">compound document</comment>
- <comment xml:lang="el">Σύνθετο έγγραφο</comment>
<comment xml:lang="de">Verbunddokument</comment>
- <comment xml:lang="da">sammensat dokument</comment>
- <comment xml:lang="cy">dogfen gyfansawdd</comment>
- <comment xml:lang="cs">složený dokument</comment>
- <comment xml:lang="ca">document compost</comment>
- <comment xml:lang="bg">Съставен документ</comment>
- <comment xml:lang="be@latin">składany dakument</comment>
- <comment xml:lang="az">birləşik sənəd</comment>
- <comment xml:lang="ast">documentu compuestu</comment>
- <comment xml:lang="ar">مستند مركب</comment>
- <comment xml:lang="af">saamgestelde dokument</comment>
+ <comment xml:lang="be">складаны дакумент</comment>
</mime-type>
<mime-type type="multipart/report">
- <comment>mail system report</comment>
- <comment xml:lang="zh_TW">郵件系統回報</comment>
- <comment xml:lang="zh_CN">邮件系统报告</comment>
- <comment xml:lang="vi">thông báo hệ thống thư</comment>
+ <comment>Mail system report</comment>
<comment xml:lang="uk">звіт поштової системи</comment>
- <comment xml:lang="tr">posta sistem raporu</comment>
- <comment xml:lang="sv">e-postsystemrapport</comment>
- <comment xml:lang="sr">извештај поштанског система</comment>
- <comment xml:lang="sq">Raport i sistemit të postës</comment>
- <comment xml:lang="sl">poročilo poštnega sistema</comment>
- <comment xml:lang="sk">Správa poštového systému</comment>
+ <comment xml:lang="sv">E-postsystemrapport</comment>
<comment xml:lang="ru">Отчёт почтовой системы</comment>
- <comment xml:lang="ro">raport sistem email</comment>
- <comment xml:lang="pt_BR">Relatório do sistema de correspondência</comment>
- <comment xml:lang="pt">relatório de sistema de email</comment>
<comment xml:lang="pl">Raport systemu pocztowego</comment>
- <comment xml:lang="oc">rapòrt sistèma de corrièrs electronics</comment>
- <comment xml:lang="nn">e-post-systemrapport</comment>
- <comment xml:lang="nl">e-mail-systeembericht</comment>
- <comment xml:lang="nb">e-postsystemrapport</comment>
- <comment xml:lang="ms">Laporan sistem mel</comment>
- <comment xml:lang="lv">pasta sistēmas atskaite</comment>
- <comment xml:lang="lt">pašto sistemos ataskaita</comment>
- <comment xml:lang="ko">메일 시스템 보고서</comment>
- <comment xml:lang="kk">пошта жүйесінің мәлімдемесі</comment>
- <comment xml:lang="ja">メールシステムレポート</comment>
<comment xml:lang="it">Rapporto di sistema posta</comment>
- <comment xml:lang="id">laporan sistem surat</comment>
- <comment xml:lang="ia">Reporto de systema de e-mail</comment>
- <comment xml:lang="hu">levelezőrendszer jelentése</comment>
- <comment xml:lang="hr">Izvještaj sustava pošte</comment>
- <comment xml:lang="he">דו״ח של מערכת הדואר</comment>
- <comment xml:lang="gl">informe do sistema de correo</comment>
- <comment xml:lang="ga">tuairisc chórais r-phoist</comment>
- <comment xml:lang="fur">rapuart di sisteme de pueste</comment>
- <comment xml:lang="fr">rapport système de courriels</comment>
- <comment xml:lang="fo">postkervisfrásøgn</comment>
- <comment xml:lang="fi">viestijärjestelmän ilmoitus</comment>
- <comment xml:lang="eu">posta sistemako txostena</comment>
- <comment xml:lang="es">informe del sistema de correo</comment>
- <comment xml:lang="eo">raporto de retpoŝta sistemo</comment>
- <comment xml:lang="en_GB">mail system report</comment>
- <comment xml:lang="el">Αναφορά συστήματος ηλ. ταχυδρομείου</comment>
<comment xml:lang="de">E-Mail-Systembericht</comment>
- <comment xml:lang="da">postsystemrapport</comment>
- <comment xml:lang="cy">adroddiad system bost</comment>
- <comment xml:lang="cs">zpráva poštovního systému</comment>
- <comment xml:lang="ca">informe de sistema de correu</comment>
- <comment xml:lang="bg">Отчет за пощенската система</comment>
- <comment xml:lang="be@latin">rapart paštovaj systemy</comment>
- <comment xml:lang="az">poçt sistemi raportu</comment>
- <comment xml:lang="ar">تقرير نظام بريد</comment>
+ <comment xml:lang="be">справаздача паштовай сістэмы</comment>
</mime-type>
<mime-type type="multipart/signed">
- <comment>signed message</comment>
- <comment xml:lang="zh_TW">已簽署的訊息</comment>
- <comment xml:lang="zh_CN">签名信件</comment>
- <comment xml:lang="vi">thông điệp đã ký</comment>
+ <comment>Signed message</comment>
<comment xml:lang="uk">підписане повідомлення</comment>
- <comment xml:lang="tr">imzalı ileti</comment>
- <comment xml:lang="sv">signerat meddelande</comment>
- <comment xml:lang="sr">потписана порука</comment>
- <comment xml:lang="sq">Mesazh i firmosur</comment>
- <comment xml:lang="sl">podpisano sporočilo</comment>
- <comment xml:lang="sk">Podpísaná správa</comment>
+ <comment xml:lang="sv">Signerat meddelande</comment>
<comment xml:lang="ru">Подписанное сообщение</comment>
- <comment xml:lang="ro">mesaj semnat</comment>
- <comment xml:lang="pt_BR">Mensagem assinada</comment>
- <comment xml:lang="pt">mensagem assinada</comment>
<comment xml:lang="pl">Podpisana wiadomość</comment>
- <comment xml:lang="oc">messatge signat</comment>
- <comment xml:lang="nn">signert melding</comment>
- <comment xml:lang="nl">ondertekend bericht</comment>
- <comment xml:lang="nb">signert melding</comment>
- <comment xml:lang="ms">Mesej ditandatangani</comment>
- <comment xml:lang="lv">parakstīta ziņa</comment>
- <comment xml:lang="lt">pasirašytas laiškas</comment>
- <comment xml:lang="ko">서명된 메시지</comment>
- <comment xml:lang="kk">қолтаңбасы бар мәлімдеме</comment>
- <comment xml:lang="ja">署名付きメッセージ</comment>
<comment xml:lang="it">Messaggio firmato</comment>
- <comment xml:lang="id">pesan ditandatangani</comment>
- <comment xml:lang="ia">Message signate</comment>
- <comment xml:lang="hu">aláírt üzenet</comment>
- <comment xml:lang="hr">Potpisana poruka</comment>
- <comment xml:lang="he">הודעה חתומה</comment>
- <comment xml:lang="gl">mensaxe firmado</comment>
- <comment xml:lang="ga">teachtaireacht sínithe</comment>
- <comment xml:lang="fur">messaç firmât</comment>
- <comment xml:lang="fr">message signé</comment>
- <comment xml:lang="fo">undirskrivað boð</comment>
- <comment xml:lang="fi">allekirjoitettu viesti</comment>
- <comment xml:lang="eu">sinatutako mezua</comment>
<comment xml:lang="es">mensaje firmado</comment>
- <comment xml:lang="eo">pruvita mesaĝo</comment>
- <comment xml:lang="en_GB">signed message</comment>
- <comment xml:lang="el">Υπογεγραμμένο μήνυμα</comment>
<comment xml:lang="de">Signierte Nachricht</comment>
- <comment xml:lang="da">signeret meddelelse</comment>
- <comment xml:lang="cy">neges lofnodwyd</comment>
- <comment xml:lang="cs">podepsaná zpráva</comment>
- <comment xml:lang="ca">missatge signat</comment>
- <comment xml:lang="bg">Подписано съобщение</comment>
- <comment xml:lang="be@latin">padpisanaje paviedamleńnie</comment>
- <comment xml:lang="az">imzalanmış ismarış</comment>
- <comment xml:lang="ar">رسالة موقّعة</comment>
- <comment xml:lang="af">getekende boodskap</comment>
+ <comment xml:lang="be">падпісанае паведамленне</comment>
</mime-type>
<mime-type type="multipart/x-mixed-replace">
- <comment>stream of data (server push)</comment>
- <comment xml:lang="zh_TW">資料串流 (server push)</comment>
- <comment xml:lang="zh_CN">数据流(服务器推送)</comment>
- <comment xml:lang="vi">luồng dữ liệu (trình phục vụ đẩy)</comment>
+ <comment>Stream of data (server push)</comment>
<comment xml:lang="uk">потік даних (від сервера)</comment>
- <comment xml:lang="tr">veri akışı (sunucudan gönderilen)</comment>
- <comment xml:lang="sv">dataflöde (serverutsändning)</comment>
- <comment xml:lang="sr">ток података (гурање са сервера)</comment>
- <comment xml:lang="sq">Fluks me të dhëna (server push)</comment>
- <comment xml:lang="sl">pretok podatkov (strežniški)</comment>
- <comment xml:lang="sk">Prúd dát (posielaný serverom)</comment>
+ <comment xml:lang="sv">Dataflöde (serverutsändning)</comment>
<comment xml:lang="ru">Поток данных (server push)</comment>
- <comment xml:lang="ro">flux de date (de la server)</comment>
- <comment xml:lang="pt_BR">Fluxo de dados (por iniciativa do servidor)</comment>
- <comment xml:lang="pt">fluxo de dados (empurrados pelo servidor)</comment>
<comment xml:lang="pl">Strumień danych (wymuszenie serwera)</comment>
- <comment xml:lang="oc">flux de donadas (emés pel servidor)</comment>
- <comment xml:lang="nn">datastraum (dytta av tenaren)</comment>
- <comment xml:lang="nl">gegevensstroom (server duwt)</comment>
- <comment xml:lang="nb">datastrøm (server push)</comment>
- <comment xml:lang="ms">Aliran dara (paksaan pelayan)</comment>
- <comment xml:lang="lv">datu straume (servera grūsta)</comment>
- <comment xml:lang="lt">duomenų srautas (iš serverio)</comment>
- <comment xml:lang="ko">데이터 스트림(서버 푸시)</comment>
- <comment xml:lang="kk">мәліметтер ағымы (server push)</comment>
- <comment xml:lang="ja">データストリーム (サーバープッシュ型)</comment>
<comment xml:lang="it">Flusso di dati (server push)</comment>
- <comment xml:lang="id">arus data (dorongan server)</comment>
- <comment xml:lang="ia">Fluxo de datos (pulsate per servitor)</comment>
- <comment xml:lang="hu">sugárzott adatfolyam (kiszolgálóról)</comment>
- <comment xml:lang="hr">Strujanje podataka (poslužiteljem pogurano)</comment>
- <comment xml:lang="he">מידע בזרימה (דחיפה ע״י השרת)</comment>
- <comment xml:lang="gl">fluxo de datos (por iniciativa do servidor)</comment>
- <comment xml:lang="ga">sruth sonraí (brú freastalaí)</comment>
- <comment xml:lang="fur">flus di dâts (pe iniziative dal servidôr)</comment>
- <comment xml:lang="fr">flux de données (émis par le serveur)</comment>
- <comment xml:lang="fo">streymur av dáta (ambætara skump)</comment>
- <comment xml:lang="fi">tietovirta (palvelin työntää)</comment>
- <comment xml:lang="eu">datu-korrontea (zerbitzari igortzailea)</comment>
- <comment xml:lang="es">flujo de datos (por iniciativa del servidor)</comment>
- <comment xml:lang="eo">datumstrio (puŝata per servilo)</comment>
- <comment xml:lang="en_GB">stream of data (server push)</comment>
- <comment xml:lang="el">Ροή δεδομένων (στελλόμενα από διακομιστή)</comment>
<comment xml:lang="de">Datenstrom (Server-Push)</comment>
- <comment xml:lang="da">datastrøm (serverskubbet)</comment>
- <comment xml:lang="cs">proud dat (posílaný serverem)</comment>
- <comment xml:lang="ca">flux de dades (enviat pel servidor)</comment>
- <comment xml:lang="bg">Поток от данни — пратени от сървър</comment>
- <comment xml:lang="be@latin">płyń źviestak (ad servera)</comment>
- <comment xml:lang="ar">دفق بيانات (دفع خادم)</comment>
+ <comment xml:lang="be">плынь даных (ад сервера)</comment>
</mime-type>
<mime-type type="text/calendar">
<comment>VCS/ICS calendar</comment>
@@ -32880,8 +33581,9 @@ command to generate the output files.
<comment xml:lang="tr">VCS/ICS takvimi</comment>
<comment xml:lang="sv">VCS/ICS-kalender</comment>
<comment xml:lang="sr">ВЦС/ИЦС календар</comment>
- <comment xml:lang="sq">Kalendar VCS/ICS</comment>
+ <comment xml:lang="sq">kalendar VCS/ICS</comment>
<comment xml:lang="sl">Datoteka koledarja VCS/ICS</comment>
+ <comment xml:lang="si">VCS/ICS දින දර්ශනය</comment>
<comment xml:lang="sk">Kalendár VCS/ICS</comment>
<comment xml:lang="ru">Календарь VCS/ICS</comment>
<comment xml:lang="ro">Calendar VCS/ICS</comment>
@@ -32898,6 +33600,7 @@ command to generate the output files.
<comment xml:lang="kk">VCS/ICS күнтізбесі</comment>
<comment xml:lang="ja">VCS/ICS カレンダー</comment>
<comment xml:lang="it">Calendario VCS/ICS</comment>
+ <comment xml:lang="is">VCS/ICS-dagatal</comment>
<comment xml:lang="id">Kalender VCS/ICS</comment>
<comment xml:lang="ia">Calendario VCS/ICS</comment>
<comment xml:lang="hu">VCS/ICS naptár</comment>
@@ -32920,6 +33623,7 @@ command to generate the output files.
<comment xml:lang="ca">calendari VCS/ICS</comment>
<comment xml:lang="bg">Календар — VCS/ICS</comment>
<comment xml:lang="be@latin">Kalandar VCS/ICS</comment>
+ <comment xml:lang="be">каляндар VCS/ICS</comment>
<comment xml:lang="ar">سجل VCS/ICS</comment>
<comment xml:lang="af">VCS/ICS-kalender</comment>
<acronym>VCS/ICS</acronym>
@@ -32943,8 +33647,9 @@ command to generate the output files.
<comment xml:lang="tr">CSS stil kağıdı</comment>
<comment xml:lang="sv">CSS-stilmall</comment>
<comment xml:lang="sr">ЦСС стилски лист</comment>
- <comment xml:lang="sq">Fletë stili CSS</comment>
+ <comment xml:lang="sq">fletëstil CSS</comment>
<comment xml:lang="sl">Slogovna predloga CSS</comment>
+ <comment xml:lang="si">CSS මෝස්තර පත්‍රිකාව</comment>
<comment xml:lang="sk">Štýly CSS</comment>
<comment xml:lang="ru">Таблица стилей CSS</comment>
<comment xml:lang="ro">Pagină de stil CSS</comment>
@@ -32962,6 +33667,7 @@ command to generate the output files.
<comment xml:lang="ka">CSS სტილი</comment>
<comment xml:lang="ja">CSS スタイルシート</comment>
<comment xml:lang="it">Foglio di stile CSS</comment>
+ <comment xml:lang="is">CSS-stílsnið</comment>
<comment xml:lang="id">Lembar gaya CSS</comment>
<comment xml:lang="ia">Folio de stilo CSS</comment>
<comment xml:lang="hu">CSS stíluslap</comment>
@@ -32984,6 +33690,7 @@ command to generate the output files.
<comment xml:lang="ca">llista d'estil CSS</comment>
<comment xml:lang="bg">Стилове — CSS</comment>
<comment xml:lang="be@latin">Arkuš stylaŭ CSS</comment>
+ <comment xml:lang="be">табліца стыляў CSS</comment>
<comment xml:lang="ar">نمط CSS</comment>
<comment xml:lang="af">CSS-stylblad</comment>
<acronym>CSS</acronym>
@@ -32992,55 +33699,16 @@ command to generate the output files.
<glob pattern="*.css"/>
</mime-type>
<mime-type type="text/vcard">
- <comment>electronic business card</comment>
- <comment xml:lang="zh_TW">電子商務名片</comment>
- <comment xml:lang="zh_CN">电子商务卡</comment>
- <comment xml:lang="vi">danh thiếp điện tử</comment>
+ <comment>Electronic business card</comment>
<comment xml:lang="uk">електронна бізнес-картка</comment>
- <comment xml:lang="tr">elektronik iş kartı</comment>
- <comment xml:lang="sv">elektroniskt visitkort</comment>
- <comment xml:lang="sr">електронска пословна картица</comment>
- <comment xml:lang="sq">Skedë elektronike biznesi</comment>
- <comment xml:lang="sl">elektronska poslovna vizitka</comment>
- <comment xml:lang="sk">Elektronická vizitka</comment>
+ <comment xml:lang="sv">Elektroniskt visitkort</comment>
<comment xml:lang="ru">Электронная визитная карточка</comment>
- <comment xml:lang="ro">carte de vizită electronică</comment>
- <comment xml:lang="pt_BR">Cartão de visitas eletrônico</comment>
- <comment xml:lang="pt">cartão de visita eletrónico</comment>
<comment xml:lang="pl">Wizytówka elektroniczna</comment>
- <comment xml:lang="oc">carta de visita electronica</comment>
- <comment xml:lang="nn">elektronisk visittkort</comment>
- <comment xml:lang="nl">elektronisch visitekaartje</comment>
- <comment xml:lang="lv">elektroniskā biznesa kartiņa</comment>
- <comment xml:lang="lt">elektroninė vizitinė kortelė</comment>
- <comment xml:lang="ko">전자 명함</comment>
- <comment xml:lang="kk">электронды визит карточкасы</comment>
<comment xml:lang="ja">電子名刺</comment>
<comment xml:lang="it">Biglietto da visita elettronico</comment>
- <comment xml:lang="id">kartu bisnis elektronik</comment>
- <comment xml:lang="ia">Carta de visita electronic</comment>
- <comment xml:lang="hu">elektronikus névjegykártya</comment>
- <comment xml:lang="hr">Elektronička posjetnica</comment>
- <comment xml:lang="he">כרטיס ביקור אלקטרוני</comment>
- <comment xml:lang="gl">tarxeta de negocio electrónica</comment>
- <comment xml:lang="ga">cárta gnó leictreonach</comment>
- <comment xml:lang="fur">biliet di visite eletronic</comment>
- <comment xml:lang="fr">carte de visite électronique</comment>
- <comment xml:lang="fo">elektroniskt handilskort</comment>
- <comment xml:lang="fi">sähköinen käyntikortti</comment>
- <comment xml:lang="eu">enpresako txartel elektronikoa</comment>
<comment xml:lang="es">tarjeta de visita electrónica</comment>
- <comment xml:lang="eo">elektronika vizitkarto</comment>
- <comment xml:lang="en_GB">electronic business card</comment>
- <comment xml:lang="el">Ηλεκτρονική επαγγελματική κάρτα</comment>
<comment xml:lang="de">Elektronische Visitenkarte</comment>
- <comment xml:lang="da">elektronisk visitkort</comment>
- <comment xml:lang="cs">elektronická navštívenka</comment>
- <comment xml:lang="ca">targeta de visita electrònica</comment>
- <comment xml:lang="bg">Електронна визитна картичка</comment>
- <comment xml:lang="be@latin">elektronnaja biznes-kartka</comment>
- <comment xml:lang="ar">بطاقة أعمال إلكترونية</comment>
- <comment xml:lang="af">elektroniese beskigheidskaartjie</comment>
+ <comment xml:lang="be">электронная візітная картка</comment>
<alias type="text/directory"/>
<alias type="text/x-vcard"/>
<sub-class-of type="text/plain"/>
@@ -33061,17 +33729,21 @@ command to generate the output files.
<comment xml:lang="tr">Turtle belgesi</comment>
<comment xml:lang="sv">Turtle-dokument</comment>
<comment xml:lang="sr">Тартл документ</comment>
+ <comment xml:lang="sq">dokument Turtle</comment>
<comment xml:lang="sl">Dokument Turtle</comment>
+ <comment xml:lang="si">කැස්බෑ ලියවිල්ල</comment>
<comment xml:lang="sk">Dokument Turtle</comment>
<comment xml:lang="ru">Документ Turtle</comment>
<comment xml:lang="pt_BR">Documento Turtle</comment>
<comment xml:lang="pt">documento Turtle</comment>
<comment xml:lang="pl">Dokument Turtle</comment>
<comment xml:lang="oc">document Turtle</comment>
+ <comment xml:lang="nl">Turtle-document</comment>
<comment xml:lang="ko">Turtle 문서</comment>
<comment xml:lang="kk">Turtle құжаты</comment>
<comment xml:lang="ja">Turtle ドキュメント</comment>
<comment xml:lang="it">Documento Turtle</comment>
+ <comment xml:lang="is">Turtle skjal</comment>
<comment xml:lang="id">Dokumen Turtle</comment>
<comment xml:lang="ia">Documento Turtle</comment>
<comment xml:lang="hu">Turtle dokumentum</comment>
@@ -33090,6 +33762,7 @@ command to generate the output files.
<comment xml:lang="cs">dokument Turtle</comment>
<comment xml:lang="ca">document Turtle</comment>
<comment xml:lang="bg">Документ — Turtle</comment>
+ <comment xml:lang="be">дакумент Turtle</comment>
<comment xml:lang="ast">Documentu Turtle</comment>
<comment xml:lang="ar">وثيقة Turtle</comment>
<comment xml:lang="af">Turtle-dokument</comment>
@@ -33105,8 +33778,9 @@ command to generate the output files.
<comment xml:lang="tr">txt2tags belgesi</comment>
<comment xml:lang="sv">txt2tags-dokument</comment>
<comment xml:lang="sr">документ текста-у-ознаке</comment>
- <comment xml:lang="sq">Dokument txt2tags</comment>
+ <comment xml:lang="sq">dokument txt2tags</comment>
<comment xml:lang="sl">Dokument txt2tags</comment>
+ <comment xml:lang="si">txt2tags ලේඛනය</comment>
<comment xml:lang="sk">Dokument txt2tags</comment>
<comment xml:lang="ru">Документ txt2tags</comment>
<comment xml:lang="ro">document txt2tags</comment>
@@ -33124,6 +33798,7 @@ command to generate the output files.
<comment xml:lang="ka">txt2tags დოკუმენტი</comment>
<comment xml:lang="ja">txt2tags ドキュメント</comment>
<comment xml:lang="it">Documento txt2tags</comment>
+ <comment xml:lang="is">txt2tags skjalskjal</comment>
<comment xml:lang="id">dokumen txt2tags</comment>
<comment xml:lang="ia">Documento txt2tags</comment>
<comment xml:lang="hu">txt2tags dokumentum</comment>
@@ -33146,6 +33821,7 @@ command to generate the output files.
<comment xml:lang="ca">document txt2tags</comment>
<comment xml:lang="bg">Документ — txt2tags</comment>
<comment xml:lang="be@latin">dakument txt2tags</comment>
+ <comment xml:lang="be">дакумент txt2tags</comment>
<comment xml:lang="ast">Documentu txt2tags</comment>
<comment xml:lang="ar">مستند txt2tags</comment>
<comment xml:lang="af">txt2tags-dokument</comment>
@@ -33160,23 +33836,26 @@ command to generate the output files.
<comment>Verilog source code</comment>
<comment xml:lang="zh_TW">Verilog 源碼</comment>
<comment xml:lang="zh_CN">Verilog 源代码</comment>
- <comment xml:lang="uk">вихідний код мовою Verilog</comment>
+ <comment xml:lang="uk">початковий код мовою Verilog</comment>
<comment xml:lang="tr">Verilog kaynak kodu</comment>
<comment xml:lang="sv">Verilog-källkod</comment>
<comment xml:lang="sr">изворни код Верилога</comment>
+ <comment xml:lang="sq">kod burim Verilog</comment>
<comment xml:lang="sl">Datoteka izvorne kode Verilog</comment>
+ <comment xml:lang="si">Verilog මූලාශ්ර කේතය</comment>
<comment xml:lang="sk">Zdrojový kód Verilog</comment>
<comment xml:lang="ru">Исходный код Verilog</comment>
<comment xml:lang="pt_BR">Código-fonte Verilog</comment>
<comment xml:lang="pt">código origem Verilog</comment>
<comment xml:lang="pl">Kod źródłowy Verilog</comment>
<comment xml:lang="oc">còde font Verilog</comment>
- <comment xml:lang="nl">Verilog broncode</comment>
+ <comment xml:lang="nl">Verilog-broncode</comment>
<comment xml:lang="lv">Verilog pirmkods</comment>
<comment xml:lang="ko">Verilog 소스 코드</comment>
<comment xml:lang="kk">Verilog бастапқы коды</comment>
<comment xml:lang="ja">Verilog ソースコード</comment>
<comment xml:lang="it">Codice sorgente Verilog</comment>
+ <comment xml:lang="is">Verilog frumkóði</comment>
<comment xml:lang="id">Kode sumber Verilog</comment>
<comment xml:lang="ia">Codice-fonte Verilog</comment>
<comment xml:lang="hu">Verilog-forráskód</comment>
@@ -33197,6 +33876,7 @@ command to generate the output files.
<comment xml:lang="cs">zdrojový kód v jazyce Verilog</comment>
<comment xml:lang="ca">codi font en Verilog</comment>
<comment xml:lang="bg">Изходен код — Verilog</comment>
+ <comment xml:lang="be">зыходны код Verilog</comment>
<comment xml:lang="ar">شفرة مصدر Verilog</comment>
<comment xml:lang="af">Verilog-bronkode</comment>
<sub-class-of type="text/plain"/>
@@ -33210,19 +33890,22 @@ command to generate the output files.
<comment xml:lang="tr">SystemVerilog başlığı</comment>
<comment xml:lang="sv">SystemVerilog-headerfil</comment>
<comment xml:lang="sr">заглавље Система Верилога</comment>
+ <comment xml:lang="sq">krye SystemVerilog</comment>
<comment xml:lang="sl">Datoteka glave SystemVerilog</comment>
+ <comment xml:lang="si">SystemVerilog ශීර්ෂකය</comment>
<comment xml:lang="sk">Hlavičky SystemVerilog</comment>
<comment xml:lang="ru">Заголовочный файл SystemVerilog</comment>
<comment xml:lang="pt_BR">Cabeçalho de SystemVerilog</comment>
<comment xml:lang="pt">cabeçalho SystemVerilog</comment>
<comment xml:lang="pl">Nagłówek SystemVerilog</comment>
<comment xml:lang="oc">entèsta SystemVerilog</comment>
- <comment xml:lang="nl">SystemVerilog header</comment>
+ <comment xml:lang="nl">SystemVerilog-header</comment>
<comment xml:lang="lv">SystemVerilog galvene</comment>
<comment xml:lang="ko">SystemVerilog 헤더</comment>
<comment xml:lang="kk">SystemVerilog тақырыптамасы</comment>
<comment xml:lang="ja">SystemVerilog ヘッダー</comment>
<comment xml:lang="it">Header SystemVerilog</comment>
+ <comment xml:lang="is">SystemVerilog haus</comment>
<comment xml:lang="id">Header SystemVerilog</comment>
<comment xml:lang="ia">Capite SystemVerilog</comment>
<comment xml:lang="hu">SystemVerilog fejléc</comment>
@@ -33242,6 +33925,7 @@ command to generate the output files.
<comment xml:lang="cs">záhlaví SystemVerilog</comment>
<comment xml:lang="ca">capçalera en SystemVerilog</comment>
<comment xml:lang="bg">Заглавен файл — SystemVerilog</comment>
+ <comment xml:lang="be">загаловак SystemVerilog</comment>
<comment xml:lang="ar">ترويسة SystemVerilog</comment>
<sub-class-of type="text/x-verilog"/>
<glob pattern="*.svh"/>
@@ -33250,23 +33934,26 @@ command to generate the output files.
<comment>SystemVerilog source code</comment>
<comment xml:lang="zh_TW">SystemVerilog 源碼</comment>
<comment xml:lang="zh_CN">SystemVerilog 源代码</comment>
- <comment xml:lang="uk">вихідний файл мовою SystemVerilog</comment>
+ <comment xml:lang="uk">початковий код мовою SystemVerilog</comment>
<comment xml:lang="tr">SystemVerilog kaynak kodu</comment>
<comment xml:lang="sv">SystemVerilog-källkod</comment>
<comment xml:lang="sr">изворни код Система Верилога</comment>
+ <comment xml:lang="sq">kod burim SystemVerilog</comment>
<comment xml:lang="sl">Datoteka izvorne kode SystemVerilog</comment>
+ <comment xml:lang="si">SystemVerilog මූලාශ්‍ර කේතය</comment>
<comment xml:lang="sk">Zdrojový kód SystemVerilog</comment>
<comment xml:lang="ru">Исходный код SystemVerilog</comment>
<comment xml:lang="pt_BR">Código-fonte de SystemVerilog</comment>
<comment xml:lang="pt">código origem SystemVerilog</comment>
<comment xml:lang="pl">Kod źródłowy SystemVerilog</comment>
<comment xml:lang="oc">còde font SystemVerilog</comment>
- <comment xml:lang="nl">SystemVerilog broncode</comment>
+ <comment xml:lang="nl">SystemVerilog-broncode</comment>
<comment xml:lang="lv">SystemVerilog pirmkods</comment>
<comment xml:lang="ko">SystemVerilog 소스 코드</comment>
<comment xml:lang="kk">SystemVerilog бастапқы коды</comment>
<comment xml:lang="ja">SystemVerilog ソースコード</comment>
<comment xml:lang="it">Codice sorgente </comment>
+ <comment xml:lang="is">SystemVerilog frumkóði</comment>
<comment xml:lang="id">Kode sumber SystemVerilog</comment>
<comment xml:lang="ia">Codice-fonte SystemVerilog</comment>
<comment xml:lang="hu">SystemVerilog-forráskód</comment>
@@ -33286,6 +33973,7 @@ command to generate the output files.
<comment xml:lang="cs">zdrojový kód SystemVerilog</comment>
<comment xml:lang="ca">codi font en SystemVerilog</comment>
<comment xml:lang="bg">Изходен код — SystemVerilog</comment>
+ <comment xml:lang="be">зыходны код SystemVerilog</comment>
<comment xml:lang="ar">شفرة مصدر SystemVerilog</comment>
<comment xml:lang="af">SystemVerilog-bronkode</comment>
<sub-class-of type="text/x-verilog"/>
@@ -33295,23 +33983,26 @@ command to generate the output files.
<comment>VHDL source code</comment>
<comment xml:lang="zh_TW">VHDL 源碼</comment>
<comment xml:lang="zh_CN">VHDL 源代码</comment>
- <comment xml:lang="uk">вихідний код мовою VHDL</comment>
+ <comment xml:lang="uk">початковий код мовою VHDL</comment>
<comment xml:lang="tr">VHDL kaynak kodu</comment>
<comment xml:lang="sv">VHDL-källkod</comment>
<comment xml:lang="sr">ВХДЛ изворни код</comment>
+ <comment xml:lang="sq">kod burim VHDL</comment>
<comment xml:lang="sl">Datoteka izvorne kode VHDL</comment>
+ <comment xml:lang="si">VHDL මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód VHDL</comment>
<comment xml:lang="ru">Исходный код VHDL</comment>
<comment xml:lang="pt_BR">Código-fonte VHDL</comment>
<comment xml:lang="pt">código origem VHDL</comment>
<comment xml:lang="pl">Kod źródłowy VHDL</comment>
<comment xml:lang="oc">còde font VHDL</comment>
- <comment xml:lang="nl">VHDL broncode</comment>
+ <comment xml:lang="nl">VHDL-broncode</comment>
<comment xml:lang="lv">VHDL pirmkods</comment>
<comment xml:lang="ko">VHDL 소스 코드</comment>
<comment xml:lang="kk">VHDL бастапқы коды</comment>
<comment xml:lang="ja">VHDL ソースコード</comment>
<comment xml:lang="it">Codice sorgente VHDL</comment>
+ <comment xml:lang="is">VHDL frumkóði</comment>
<comment xml:lang="id">Kode sumber VHDL</comment>
<comment xml:lang="ia">Codice-fonte VHDL</comment>
<comment xml:lang="hu">VHDL-forráskód</comment>
@@ -33332,6 +34023,7 @@ command to generate the output files.
<comment xml:lang="cs">zdrojový kód v jazyce VHDL</comment>
<comment xml:lang="ca">codi font en VHDL</comment>
<comment xml:lang="bg">Изходен код — VHDL</comment>
+ <comment xml:lang="be">зыходны код VHDL</comment>
<comment xml:lang="ar">شفرة مصدر VHDL</comment>
<comment xml:lang="af">VHDL-bronkode</comment>
<acronym>VHDL</acronym>
@@ -33341,170 +34033,46 @@ command to generate the output files.
<glob pattern="*.vhdl"/>
</mime-type>
<mime-type type="text/enriched">
- <comment>enriched text document</comment>
- <comment xml:lang="zh_TW">豐富化文字文件</comment>
- <comment xml:lang="zh_CN">浓缩文本文档 (ETF)</comment>
- <comment xml:lang="vi">tài liệu văn bản có kiểu dáng</comment>
+ <comment>Enriched text document</comment>
<comment xml:lang="uk">форматований текстовий документ</comment>
- <comment xml:lang="tr">zenginleştirilmiş metin belgesi</comment>
- <comment xml:lang="sv">berikat textdokument</comment>
- <comment xml:lang="sr">обогаћени текстуални документ</comment>
- <comment xml:lang="sq">Dokument teksti i pasuruar</comment>
- <comment xml:lang="sl">dokument z obogatenim besedilom</comment>
- <comment xml:lang="sk">Rozšírený textový dokument</comment>
+ <comment xml:lang="sv">Enriched text-dokument</comment>
<comment xml:lang="ru">Форматированный текстовый документ</comment>
- <comment xml:lang="ro">document text îmbogățit</comment>
- <comment xml:lang="pt_BR">Documento de texto enriquecido</comment>
- <comment xml:lang="pt">documento de texto rico</comment>
<comment xml:lang="pl">Wzbogacony dokument tekstowy</comment>
- <comment xml:lang="oc">document tèxte enriquit</comment>
- <comment xml:lang="nn">rik tekst tekstdokument</comment>
- <comment xml:lang="nl">verrijkt tekstdocument</comment>
- <comment xml:lang="nb">riktekst-dokument</comment>
- <comment xml:lang="ms">Dokumen teks diperkaya</comment>
- <comment xml:lang="lv">bagātināta teksta formāts</comment>
- <comment xml:lang="lt">praturtinto teksto dokumentas</comment>
- <comment xml:lang="ko">확장된 텍스트 문서</comment>
- <comment xml:lang="kk">пішімделген мәтіндік құжаты</comment>
- <comment xml:lang="ja">リッチテキストドキュメント</comment>
+ <comment xml:lang="ja">装飾された文書</comment>
<comment xml:lang="it">Documento testo arricchito</comment>
- <comment xml:lang="id">dokumen teks diperkaya</comment>
- <comment xml:lang="ia">Documento de texto inricchite</comment>
- <comment xml:lang="hu">enriched text dokumentum</comment>
- <comment xml:lang="hr">Obogaćeni tekstovni dokument</comment>
- <comment xml:lang="he">מסמך טקסט מועשר</comment>
- <comment xml:lang="gl">documento de texto enriquecido</comment>
- <comment xml:lang="ga">cáipéis téacs saibhrithe</comment>
- <comment xml:lang="fur">document di test inricjît</comment>
- <comment xml:lang="fr">document texte enrichi</comment>
- <comment xml:lang="fo">ríkað tekstskjal</comment>
- <comment xml:lang="fi">rikastettu tekstiasiakirja</comment>
- <comment xml:lang="eu">aberastutako testu dokumentua</comment>
<comment xml:lang="es">documento de texto enriquecido</comment>
- <comment xml:lang="eo">riĉigita teksta dokumento</comment>
- <comment xml:lang="en_GB">enriched text document</comment>
- <comment xml:lang="el">Έγγραφο εμπλουτισμένου κειμένου</comment>
<comment xml:lang="de">Angereichertes Textdokument</comment>
- <comment xml:lang="da">beriget tekstdokument</comment>
- <comment xml:lang="cy">Dogfen testun wedi ei gyfoethogi</comment>
- <comment xml:lang="cs">rozšířený textový dokument</comment>
- <comment xml:lang="ca">document de text enriquit</comment>
- <comment xml:lang="bg">Документ с обогатен текст</comment>
- <comment xml:lang="be@latin">azdobleny tekstavy dakument</comment>
- <comment xml:lang="az">zəngin mətn sənədi</comment>
- <comment xml:lang="ast">documentu de testu arriquecíu</comment>
- <comment xml:lang="ar">مستند نصي مغنى</comment>
- <comment xml:lang="af">verrykte teksdokument</comment>
+ <comment xml:lang="be">дакумент з фарматаваннем enriched text</comment>
<sub-class-of type="text/plain"/>
</mime-type>
<mime-type type="text/htmlh">
- <comment>help page</comment>
- <comment xml:lang="zh_TW">求助頁面</comment>
- <comment xml:lang="zh_CN">帮助页面</comment>
- <comment xml:lang="vi">trang trợ giúp</comment>
- <comment xml:lang="uk">сторінка довідки</comment>
- <comment xml:lang="tr">yardım sayfası</comment>
- <comment xml:lang="sv">hjälpsida</comment>
- <comment xml:lang="sr">страница помоћи</comment>
- <comment xml:lang="sq">Faqe ndihme</comment>
- <comment xml:lang="sl">stran pomoči</comment>
- <comment xml:lang="sk">Stránka Pomocníka</comment>
+ <comment>Help page</comment>
+ <comment xml:lang="uk">Довідкова сторінка</comment>
+ <comment xml:lang="sv">Hjälpsida</comment>
<comment xml:lang="ru">Страница справки</comment>
- <comment xml:lang="ro">pagină de ajutor</comment>
<comment xml:lang="pt_BR">Página de ajuda</comment>
- <comment xml:lang="pt">página de ajuda</comment>
<comment xml:lang="pl">Strona pomocy</comment>
- <comment xml:lang="oc">pagina d'ajuda</comment>
- <comment xml:lang="nn">hjelpeside</comment>
- <comment xml:lang="nl">hulppagina</comment>
- <comment xml:lang="nb">hjelpside</comment>
- <comment xml:lang="ms">Halaman bantuan</comment>
- <comment xml:lang="lv">palīdzības lapa</comment>
- <comment xml:lang="lt">žinyno puslapis</comment>
- <comment xml:lang="ko">도움말 페이지</comment>
- <comment xml:lang="kk">анықтама парағы</comment>
- <comment xml:lang="ja">ヘルプページ</comment>
+ <comment xml:lang="ja">取説文書</comment>
<comment xml:lang="it">Pagina di aiuto</comment>
- <comment xml:lang="id">halaman bantuan</comment>
- <comment xml:lang="ia">Pagina de adjuta</comment>
- <comment xml:lang="hu">súgóoldal</comment>
- <comment xml:lang="hr">Stranica pomoći</comment>
- <comment xml:lang="he">דף עזרה</comment>
- <comment xml:lang="gl">páxina de axuda</comment>
- <comment xml:lang="ga">leathanach cabhrach</comment>
- <comment xml:lang="fur">pagjine di jutori</comment>
- <comment xml:lang="fr">page d'aide</comment>
- <comment xml:lang="fo">hjálparsíða</comment>
- <comment xml:lang="fi">ohjesivu</comment>
- <comment xml:lang="eu">laguntzako orria</comment>
+ <comment xml:lang="eu">Laguntza-orria</comment>
<comment xml:lang="es">página de ayuda</comment>
- <comment xml:lang="eo">help-paĝo</comment>
- <comment xml:lang="en_GB">help page</comment>
- <comment xml:lang="el">Σελίδα βοήθειας</comment>
<comment xml:lang="de">Hilfeseite</comment>
- <comment xml:lang="da">hjælpeside</comment>
- <comment xml:lang="cy">tudalen gymorth</comment>
- <comment xml:lang="cs">stránka nápovědy</comment>
- <comment xml:lang="ca">pàgina d'ajuda</comment>
- <comment xml:lang="bg">Страница от помощта</comment>
- <comment xml:lang="be@latin">staronka dapamohi</comment>
- <comment xml:lang="az">yardım səhifəsi</comment>
- <comment xml:lang="ar">صفحة مساعدة</comment>
- <comment xml:lang="af">hulpbladsy</comment>
+ <comment xml:lang="be">старонка даведкі</comment>
<sub-class-of type="text/plain"/>
</mime-type>
<mime-type type="text/plain">
- <comment>plain text document</comment>
- <comment xml:lang="zh_TW">純文字文件</comment>
- <comment xml:lang="zh_CN">纯文本文档</comment>
- <comment xml:lang="vi">tài liệu nhập thô</comment>
- <comment xml:lang="uk">звичайний текстовий документ</comment>
- <comment xml:lang="tr">düz metin belgesi</comment>
- <comment xml:lang="sv">vanligt textdokument</comment>
- <comment xml:lang="sr">обичан текстуални документ</comment>
- <comment xml:lang="sq">Dokument në tekst të thjeshtë</comment>
- <comment xml:lang="sl">običajna besedilna datoteka</comment>
- <comment xml:lang="sk">Obyčajný textový dokument</comment>
+ <comment>Plain text document</comment>
+ <comment xml:lang="uk">простий текстовий документ</comment>
+ <comment xml:lang="sv">Vanligt textdokument</comment>
<comment xml:lang="ru">Текстовый документ</comment>
- <comment xml:lang="ro">document text simplu</comment>
- <comment xml:lang="pt_BR">Documento de Texto</comment>
- <comment xml:lang="pt">documento em texto simples</comment>
+ <comment xml:lang="pt_BR">Documento de texto simples</comment>
<comment xml:lang="pl">Zwykły dokument tekstowy</comment>
- <comment xml:lang="oc">document tèxte brut</comment>
- <comment xml:lang="nn">vanleg tekstdokument</comment>
- <comment xml:lang="nl">plattetekst-document</comment>
- <comment xml:lang="nb">vanlig tekstdokument</comment>
- <comment xml:lang="ms">Dokumen teks jernih</comment>
- <comment xml:lang="lv">vienkāršs teksta dokuments</comment>
- <comment xml:lang="lt">paprastas tekstinis dokumentas</comment>
- <comment xml:lang="ko">일반 텍스트 문서</comment>
- <comment xml:lang="kk">мәтіндік құжаты</comment>
- <comment xml:lang="ja">平文テキストドキュメント</comment>
+ <comment xml:lang="ja">平文文書</comment>
<comment xml:lang="it">Documento in testo semplice</comment>
- <comment xml:lang="id">dokumen teks polos</comment>
- <comment xml:lang="ia">Documento de texto simple</comment>
- <comment xml:lang="hu">egyszerű szöveg</comment>
- <comment xml:lang="hr">Običan tekstovni dokument</comment>
- <comment xml:lang="he">מסמך טקסט פשוט</comment>
- <comment xml:lang="gl">documento de texto sinxelo</comment>
- <comment xml:lang="ga">cáipéis ghnáth-théacs</comment>
- <comment xml:lang="fur">document di test sempliç</comment>
- <comment xml:lang="fr">document texte brut</comment>
- <comment xml:lang="fi">perustekstiasiakirja</comment>
- <comment xml:lang="eu">testu soileko dokumentua</comment>
- <comment xml:lang="es">documento de texto sencillo</comment>
- <comment xml:lang="eo">plata teksta dokumento</comment>
- <comment xml:lang="en_GB">plain text document</comment>
- <comment xml:lang="el">Έγγραφο απλού κειμένου</comment>
+ <comment xml:lang="eu">Testu soileko dokumentua</comment>
+ <comment xml:lang="es">documento de texto sin formato</comment>
<comment xml:lang="de">Einfaches Textdokument</comment>
- <comment xml:lang="da">rent tekstdokument</comment>
- <comment xml:lang="cs">prostý textový dokument</comment>
- <comment xml:lang="ca">document de text pla</comment>
- <comment xml:lang="bg">Документ с неформатиран текст</comment>
- <comment xml:lang="be@latin">prosty tekstavy dakument</comment>
- <comment xml:lang="ast">documentu de testu planu</comment>
- <comment xml:lang="ar">مستند نصي مجرد</comment>
- <comment xml:lang="af">skoonteksdokument</comment>
+ <comment xml:lang="be">звычайны тэкст</comment>
<magic>
<match type="string" value="This is TeX," offset="0"/>
<match type="string" value="This is METAFONT," offset="0"/>
@@ -33522,8 +34090,9 @@ command to generate the output files.
<comment xml:lang="tr">RDF dosyası</comment>
<comment xml:lang="sv">RDF-fil</comment>
<comment xml:lang="sr">РДФ датотека</comment>
- <comment xml:lang="sq">File RDF</comment>
+ <comment xml:lang="sq">kartelë RDF</comment>
<comment xml:lang="sl">Datoteka RDF</comment>
+ <comment xml:lang="si">RDF ගොනුව</comment>
<comment xml:lang="sk">Súbor RDF</comment>
<comment xml:lang="ru">Файл RDF</comment>
<comment xml:lang="ro">Fișier RDF</comment>
@@ -33540,6 +34109,7 @@ command to generate the output files.
<comment xml:lang="kk">RDF файлы</comment>
<comment xml:lang="ja">RDF ファイル</comment>
<comment xml:lang="it">File RDF</comment>
+ <comment xml:lang="is">RDF skrá</comment>
<comment xml:lang="id">Arsip RDF</comment>
<comment xml:lang="ia">File RDF</comment>
<comment xml:lang="hu">RDF fájl</comment>
@@ -33562,6 +34132,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer RDF</comment>
<comment xml:lang="bg">Файл — RDF</comment>
<comment xml:lang="be@latin">Fajł RDF</comment>
+ <comment xml:lang="be">файл RDF</comment>
<comment xml:lang="ar">ملف RDF</comment>
<comment xml:lang="af">RDF-lêer</comment>
<acronym>RDF</acronym>
@@ -33574,39 +34145,16 @@ command to generate the output files.
<root-XML namespaceURI="http://www.w3.org/1999/02/22-rdf-syntax-ns#" localName="RDF"/>
</mime-type>
<mime-type type="text/x-rst">
- <comment>reStructuredText document</comment>
- <comment xml:lang="zh_TW">reStructuredText 文件</comment>
- <comment xml:lang="zh_CN">reStructuredText 文档</comment>
- <comment xml:lang="uk">документ reStructuredText</comment>
- <comment xml:lang="tr">reStructuredText belgesi</comment>
- <comment xml:lang="sv">reStructuredText-dokument</comment>
- <comment xml:lang="sl">Dokument reStructuredText</comment>
- <comment xml:lang="sk">Dokument reStructuredText</comment>
- <comment xml:lang="ru">Документ reStructuredText</comment>
- <comment xml:lang="pt_BR">Documento reStructuredText</comment>
+ <comment>ReStructuredText document</comment>
+ <comment xml:lang="uk">документ ReStructuredText</comment>
+ <comment xml:lang="sv">ReStructuredText-dokument</comment>
+ <comment xml:lang="ru">Документ ReStructuredText</comment>
<comment xml:lang="pl">Dokument reStructuredText</comment>
- <comment xml:lang="ko">reStructuredText 문서</comment>
- <comment xml:lang="kk">reStructuredText құжаты</comment>
- <comment xml:lang="ja">reStructuredText ドキュメント</comment>
<comment xml:lang="it">Documento reStructuredText</comment>
- <comment xml:lang="id">dokumen reStructuredText</comment>
- <comment xml:lang="hu">reStructuredText dokumentum</comment>
- <comment xml:lang="hr">reStructuredText dokument</comment>
- <comment xml:lang="he">מסמך reStructuredText</comment>
- <comment xml:lang="ga">cáipéis reStructuredText</comment>
- <comment xml:lang="fur">document reStructuredText</comment>
- <comment xml:lang="fr">document reStructuredText</comment>
- <comment xml:lang="fi">reStructuredText-asiakirja</comment>
- <comment xml:lang="eu">reStructuredText document</comment>
- <comment xml:lang="es">documento en reStructuredText</comment>
- <comment xml:lang="en_GB">reStructuredText document</comment>
+ <comment xml:lang="eu">ReStructuredText dokumentua</comment>
+ <comment xml:lang="es">documento ReStructuredText</comment>
<comment xml:lang="de">reStructuredText-Dokument</comment>
- <comment xml:lang="da">reStructuredText-dokument</comment>
- <comment xml:lang="cs">dokument reStructuredText</comment>
- <comment xml:lang="ca">document reStructuredText</comment>
- <comment xml:lang="bg">Документ — reStructuredText</comment>
- <comment xml:lang="ar">مستند reStructuredText</comment>
- <comment xml:lang="af">reStructuredText-dokument</comment>
+ <comment xml:lang="be">дакумент reStructuredText</comment>
<sub-class-of type="text/plain"/>
<glob pattern="*.rst"/>
</mime-type>
@@ -33618,17 +34166,21 @@ command to generate the output files.
<comment xml:lang="tr">OWL XML dosyası</comment>
<comment xml:lang="sv">OWL XML-fil</comment>
<comment xml:lang="sr">ОВЛ ИксМЛ датотека</comment>
+ <comment xml:lang="sq">kartelë OWL XML</comment>
<comment xml:lang="sl">Datoteka OWL XML</comment>
+ <comment xml:lang="si">OWL XML ගොනුව</comment>
<comment xml:lang="sk">Súbor XML OWL</comment>
<comment xml:lang="ru">Файл XML OWL</comment>
<comment xml:lang="pt_BR">Arquivo OWL XML</comment>
<comment xml:lang="pt">ficheiro OWL XML</comment>
<comment xml:lang="pl">Plik XML OWL</comment>
<comment xml:lang="oc">fichièr OWL XML</comment>
+ <comment xml:lang="nl">OWL XML-bestand</comment>
<comment xml:lang="ko">OWL XML 파일</comment>
<comment xml:lang="kk">OWL XML файлы</comment>
<comment xml:lang="ja">OWL XML ファイル</comment>
<comment xml:lang="it">File XML OWL</comment>
+ <comment xml:lang="is">OWL XML skrá</comment>
<comment xml:lang="id">Berkas XML OWL</comment>
<comment xml:lang="ia">File XML OWL</comment>
<comment xml:lang="hu">OWL XML-fájl</comment>
@@ -33647,6 +34199,7 @@ command to generate the output files.
<comment xml:lang="cs">soubor OWL XML</comment>
<comment xml:lang="ca">fitxer XML OWL</comment>
<comment xml:lang="bg">Файл — OWL XML</comment>
+ <comment xml:lang="be">файл OWL XML</comment>
<comment xml:lang="ar">ملف OWL XML</comment>
<comment xml:lang="af">OWL XML-lêer</comment>
<acronym>OWL</acronym>
@@ -33659,114 +34212,29 @@ command to generate the output files.
<root-XML namespaceURI="http://www.w3.org/2002/07/owl#" localName="Ontology"/>
</mime-type>
<mime-type type="text/rfc822-headers">
- <comment>email headers</comment>
- <comment xml:lang="zh_TW">電子郵件標頭</comment>
- <comment xml:lang="zh_CN">电子邮件头</comment>
- <comment xml:lang="vi">dòng đầu thư điện tử</comment>
- <comment xml:lang="uk">заголовки email</comment>
- <comment xml:lang="tr">eposta başlığı</comment>
- <comment xml:lang="sv">e-posthuvuden</comment>
- <comment xml:lang="sr">заглавља ел. поште</comment>
- <comment xml:lang="sq">Header email</comment>
- <comment xml:lang="sl">glava elektronske pošte</comment>
- <comment xml:lang="sk">Hlavičky e-mailu</comment>
+ <comment>Email headers</comment>
+ <comment xml:lang="uk">заголовки повідомлення ел. пошти</comment>
+ <comment xml:lang="sv">E-posthuvuden</comment>
<comment xml:lang="ru">Почтовые заголовки</comment>
- <comment xml:lang="ro">antete email</comment>
- <comment xml:lang="pt_BR">Cabeçalhos de e-mail</comment>
- <comment xml:lang="pt">cabeçalhos de email</comment>
<comment xml:lang="pl">Nagłówki wiadomości e-mail</comment>
- <comment xml:lang="oc">entèstas de corrièr electronic</comment>
- <comment xml:lang="nn">e-post-hovud</comment>
- <comment xml:lang="nl">e-mail-kopregels</comment>
- <comment xml:lang="nb">e-posthode</comment>
- <comment xml:lang="ms">Pengepala emel</comment>
- <comment xml:lang="lv">e-pasta galvene</comment>
- <comment xml:lang="lt">el. laiško antraštės</comment>
- <comment xml:lang="ko">전자메일 헤더</comment>
- <comment xml:lang="kk">пошталық тақырыптамалары</comment>
- <comment xml:lang="ja">メールヘッダー</comment>
<comment xml:lang="it">Intestazioni email</comment>
- <comment xml:lang="id">header email</comment>
- <comment xml:lang="ia">Capites de e-mail</comment>
- <comment xml:lang="hu">levélfejléc</comment>
- <comment xml:lang="hr">Zaglavlja e-pošte</comment>
- <comment xml:lang="he">כותרת דוא״ל</comment>
- <comment xml:lang="gl">cabeceiras de correo electrónico</comment>
- <comment xml:lang="ga">ceanntásca ríomhphoist</comment>
- <comment xml:lang="fur">intestazions e-mail</comment>
- <comment xml:lang="fr">en-têtes de courriel</comment>
- <comment xml:lang="fo">t-post tekshøvd</comment>
- <comment xml:lang="fi">sähköpostiotsakkeet</comment>
- <comment xml:lang="eu">helbide elektronikoen goiburuak</comment>
+ <comment xml:lang="eu">Posta-goiburuak</comment>
<comment xml:lang="es">cabeceras de correo electrónico</comment>
- <comment xml:lang="eo">retpoŝtaj ĉapoj</comment>
- <comment xml:lang="en_GB">email headers</comment>
- <comment xml:lang="el">Κεφαλίδες ηλ. μηνυμάτων</comment>
<comment xml:lang="de">E-Mail-Kopfzeilen</comment>
- <comment xml:lang="da">posthoveder</comment>
- <comment xml:lang="cy">penawdau e-bost</comment>
- <comment xml:lang="cs">záhlaví e-mailu</comment>
- <comment xml:lang="ca">capçaleres de correu electrònic</comment>
- <comment xml:lang="bg">Заглавни части на електронни писма</comment>
- <comment xml:lang="be@latin">paštovyja zahałoŭki</comment>
- <comment xml:lang="az">epoçt başlıqları</comment>
- <comment xml:lang="ar">ترويسة بريد إلكتروني</comment>
+ <comment xml:lang="be">паштовыя загалоўкі</comment>
<sub-class-of type="text/plain"/>
</mime-type>
<mime-type type="text/richtext">
- <comment>rich text document</comment>
- <comment xml:lang="zh_TW">豐富文字文件 (RTF)</comment>
- <comment xml:lang="zh_CN">富文本文档 (RTF)</comment>
- <comment xml:lang="vi">tài liệu văn bản có kiểu dáng (RTF)</comment>
+ <comment>Rich text document</comment>
<comment xml:lang="uk">форматований текстовий документ</comment>
- <comment xml:lang="tr">zengin metin belgesi</comment>
- <comment xml:lang="sv">RTF-textdokument</comment>
- <comment xml:lang="sr">богат текстуални документ</comment>
- <comment xml:lang="sq">Dokument rich text</comment>
- <comment xml:lang="sl">dokument z oblikovanim besedilom</comment>
- <comment xml:lang="sk">Textový dokument RTF</comment>
- <comment xml:lang="ru">Документ с форматированным текстом</comment>
- <comment xml:lang="ro">document text îmbogățit</comment>
- <comment xml:lang="pt_BR">Documento rich text</comment>
- <comment xml:lang="pt">documento em texto rico</comment>
+ <comment xml:lang="sv">Rich text-dokument</comment>
+ <comment xml:lang="ru">Форматированный текстовый документ</comment>
<comment xml:lang="pl">Dokument Rich Text</comment>
- <comment xml:lang="oc">document « rich text »</comment>
- <comment xml:lang="nn">rik tekst-dokument</comment>
- <comment xml:lang="nl">opgemaakt tekstdocument</comment>
- <comment xml:lang="nb">rik tekst-dokument</comment>
- <comment xml:lang="ms">Dokumen teks diperkaya</comment>
- <comment xml:lang="lv">bagātā teksta dokuments</comment>
- <comment xml:lang="lt">praturtinto teksto dokumentas</comment>
- <comment xml:lang="ko">서식 있는 텍스트 문서</comment>
- <comment xml:lang="kk">пішімделген мәтіні бар құжаты</comment>
- <comment xml:lang="ja">リッチテキストドキュメント</comment>
- <comment xml:lang="it">Documento rich text</comment>
- <comment xml:lang="id">dokumen teks kaya</comment>
- <comment xml:lang="ia">Documento de texto inricchite</comment>
- <comment xml:lang="hu">rich text-dokumentum</comment>
- <comment xml:lang="hr">Obogaćeni tekstovni dokument</comment>
- <comment xml:lang="he">מסמך טקסט עשיר</comment>
- <comment xml:lang="gl">documento do texto enriquecido</comment>
- <comment xml:lang="ga">cáipéis mhéith-théacs</comment>
- <comment xml:lang="fur">document rich text</comment>
- <comment xml:lang="fr">document « rich text »</comment>
- <comment xml:lang="fi">RTF-asiakirja</comment>
- <comment xml:lang="eu">aberastutako testu formatua</comment>
+ <comment xml:lang="it">Documento testo arricchito</comment>
+ <comment xml:lang="eu">Testu aberatseko dokumentua</comment>
<comment xml:lang="es">documento de texto enriquecido</comment>
- <comment xml:lang="eo">riĉteksta dokumento</comment>
- <comment xml:lang="en_GB">rich text document</comment>
- <comment xml:lang="el">Έγγραφο εμπλουτισμένου κειμένου (RTF)</comment>
<comment xml:lang="de">RTF-Textdokument</comment>
- <comment xml:lang="da">richtekstdokument</comment>
- <comment xml:lang="cy">dogfen testun gyfoethog (rtf)</comment>
- <comment xml:lang="cs">textový dokument RTF</comment>
- <comment xml:lang="ca">document de text enriquit</comment>
- <comment xml:lang="bg">Документ — rich text</comment>
- <comment xml:lang="be@latin">azdobleny tekstavy dakument</comment>
- <comment xml:lang="az">zəngin mətn sənədi</comment>
- <comment xml:lang="ast">documentu de testu ricu</comment>
- <comment xml:lang="ar">مستند نصي غني</comment>
- <comment xml:lang="af">rykteksdokument</comment>
+ <comment xml:lang="be">дакумент у фармаце RTF</comment>
<sub-class-of type="text/plain"/>
<glob pattern="*.rtx"/>
</mime-type>
@@ -33779,8 +34247,9 @@ command to generate the output files.
<comment xml:lang="tr">RSS özeti</comment>
<comment xml:lang="sv">RSS-sammanfattning</comment>
<comment xml:lang="sr">РСС сажетак</comment>
- <comment xml:lang="sq">Përmbledhje RSS</comment>
+ <comment xml:lang="sq">përmbledhje RSS</comment>
<comment xml:lang="sl">Datoteka povzetek RSS</comment>
+ <comment xml:lang="si">RSS සාරාංශය</comment>
<comment xml:lang="sk">Súhrn RSS</comment>
<comment xml:lang="ru">Сводка RSS</comment>
<comment xml:lang="ro">Rezumat RSS</comment>
@@ -33797,6 +34266,7 @@ command to generate the output files.
<comment xml:lang="kk">RSS жинақталғаны</comment>
<comment xml:lang="ja">RSS サマリ</comment>
<comment xml:lang="it">Sommario RSS</comment>
+ <comment xml:lang="is">RSS samantekt</comment>
<comment xml:lang="id">Ringkasan RSS</comment>
<comment xml:lang="ia">Summario RSS</comment>
<comment xml:lang="hu">RSS összefoglaló</comment>
@@ -33818,6 +34288,7 @@ command to generate the output files.
<comment xml:lang="ca">resum RSS</comment>
<comment xml:lang="bg">Обобщение за сайтове — RSS</comment>
<comment xml:lang="be@latin">Karotki ahlad RSS</comment>
+ <comment xml:lang="be">зводка RSS</comment>
<comment xml:lang="ar">ملخص RSS</comment>
<comment xml:lang="af">RSS-opsomming</comment>
<acronym>RSS</acronym>
@@ -33840,8 +34311,9 @@ command to generate the output files.
<comment xml:lang="tr">Atom besleme kaynağı</comment>
<comment xml:lang="sv">Atom-syndikeringskanal</comment>
<comment xml:lang="sr">Атомов довод синдикализације</comment>
- <comment xml:lang="sq">Feed për përhapje Atom</comment>
+ <comment xml:lang="sq">prurje RSS Atom</comment>
<comment xml:lang="sl">Sindikalni vir Atom</comment>
+ <comment xml:lang="si">පරමාණු සින්ඩිකේෂන් පෝෂණය</comment>
<comment xml:lang="sk">Kanál Atom</comment>
<comment xml:lang="ru">Лента новостей Atom</comment>
<comment xml:lang="ro">Flux agregare Atom</comment>
@@ -33858,6 +34330,7 @@ command to generate the output files.
<comment xml:lang="kk">Atom жаңалықтар таспасы</comment>
<comment xml:lang="ja">Atom 配信フィード</comment>
<comment xml:lang="it">Feed di distribuzione Atom</comment>
+ <comment xml:lang="is">Atom fréttastreymi</comment>
<comment xml:lang="id">Umpan sindikasi Atom</comment>
<comment xml:lang="ia">Fluxo de syndication Atom</comment>
<comment xml:lang="hu">Atom egyesítőfolyam</comment>
@@ -33878,6 +34351,7 @@ command to generate the output files.
<comment xml:lang="ca">canal de sindicació Atom</comment>
<comment xml:lang="bg">Емисия — Atom</comment>
<comment xml:lang="be@latin">Syndykacyjny kanał navinaŭ Atom</comment>
+ <comment xml:lang="be">канал сіндыкацыі Atom</comment>
<comment xml:lang="ar">مروج تغذية Atom</comment>
<sub-class-of type="application/xml"/>
<generic-icon name="text-html"/>
@@ -33896,8 +34370,9 @@ command to generate the output files.
<comment xml:lang="tr">OPML besleme kaynağı</comment>
<comment xml:lang="sv">OPML-syndikeringskanal</comment>
<comment xml:lang="sr">ОМПЛ довод синдикализације</comment>
- <comment xml:lang="sq">Feed për përhapje OPML</comment>
+ <comment xml:lang="sq">Prurje RSS OPML</comment>
<comment xml:lang="sl">Sindikalni vir OPML</comment>
+ <comment xml:lang="si">OPML සින්ඩිකේෂන් සංග්‍රහය</comment>
<comment xml:lang="sk">Kanál OPML</comment>
<comment xml:lang="ru">Лента новостей OPML</comment>
<comment xml:lang="ro">Flux OPML syndication</comment>
@@ -33914,6 +34389,7 @@ command to generate the output files.
<comment xml:lang="kk">OPML жаңалықтар таспасы</comment>
<comment xml:lang="ja">OPML 配信フィード</comment>
<comment xml:lang="it">Feed di distribuzione OPML</comment>
+ <comment xml:lang="is">OPML fréttastreymi</comment>
<comment xml:lang="id">Umpan sindikasi OPML</comment>
<comment xml:lang="ia">Fluxo de syndication OPML</comment>
<comment xml:lang="hu">OPML egyesítőfolyam</comment>
@@ -33934,6 +34410,7 @@ command to generate the output files.
<comment xml:lang="ca">canal de sindicació OPML</comment>
<comment xml:lang="bg">Емисия — OPML</comment>
<comment xml:lang="be@latin">Syndykacyjny kanał OPML</comment>
+ <comment xml:lang="be">канал сіндыкацыі OPML</comment>
<comment xml:lang="ar">مروج تغذية OPML</comment>
<acronym>OPML</acronym>
<expanded-acronym>Outline Processor Markup Language</expanded-acronym>
@@ -33954,8 +34431,9 @@ command to generate the output files.
<comment xml:lang="tr">SGML belgesi</comment>
<comment xml:lang="sv">SGML-dokument</comment>
<comment xml:lang="sr">СГМЛ документ</comment>
- <comment xml:lang="sq">Dokument SGML</comment>
+ <comment xml:lang="sq">dokument SGML</comment>
<comment xml:lang="sl">Dokument SGML</comment>
+ <comment xml:lang="si">SGML ලේඛනය</comment>
<comment xml:lang="sk">Dokument SGML</comment>
<comment xml:lang="ru">Документ SGML</comment>
<comment xml:lang="ro">Document SGML</comment>
@@ -33973,6 +34451,7 @@ command to generate the output files.
<comment xml:lang="kk">SGML құжаты</comment>
<comment xml:lang="ja">SGML ドキュメント</comment>
<comment xml:lang="it">Documento SGML</comment>
+ <comment xml:lang="is">SGML skjal</comment>
<comment xml:lang="id">Dokumen SGML</comment>
<comment xml:lang="ia">Documento SGML</comment>
<comment xml:lang="hu">SGML-dokumentum</comment>
@@ -33996,6 +34475,7 @@ command to generate the output files.
<comment xml:lang="ca">document SGML</comment>
<comment xml:lang="bg">Документ — SGML</comment>
<comment xml:lang="be@latin">Dakument SGML</comment>
+ <comment xml:lang="be">дакумент SGML</comment>
<comment xml:lang="ast">Documentu SGML</comment>
<comment xml:lang="ar">مستند SGML</comment>
<comment xml:lang="af">SGML-dokument</comment>
@@ -34006,55 +34486,15 @@ command to generate the output files.
<glob pattern="*.sgm"/>
</mime-type>
<mime-type type="text/spreadsheet">
- <comment>spreadsheet interchange document</comment>
- <comment xml:lang="zh_TW">試算表交換文件</comment>
- <comment xml:lang="zh_CN">电子表格交换文档</comment>
- <comment xml:lang="vi">tài liệu hoán đổi bảng tính</comment>
+ <comment>Spreadsheet interchange document</comment>
<comment xml:lang="uk">документ обміну ел. таблицями</comment>
- <comment xml:lang="tr">hesap çizelgesi değişim belgesi</comment>
- <comment xml:lang="sv">spreadsheet interchange-dokument</comment>
- <comment xml:lang="sr">документ размене табеле</comment>
- <comment xml:lang="sq">Dokument shkëmbimi për fletë llogaritje</comment>
- <comment xml:lang="sl">dokument izmenjeve preglednic</comment>
- <comment xml:lang="sk">Zošitový prenosový dokument</comment>
+ <comment xml:lang="sv">Spreadsheet interchange-dokument</comment>
<comment xml:lang="ru">Документ Spreadsheet Interchange</comment>
- <comment xml:lang="ro">document schimb filă de calcul</comment>
- <comment xml:lang="pt_BR">Documento de intercâmbio de planilhas</comment>
- <comment xml:lang="pt">documento de troca interna de folhas de cálculo</comment>
<comment xml:lang="pl">Dokument wymiany arkuszy kalkulacyjnych</comment>
- <comment xml:lang="oc">document d'escambi de fuèlhs de calcul</comment>
- <comment xml:lang="nn">Utvekslingsdokument for rekneark</comment>
- <comment xml:lang="nl">rekenblad-uitwisselingsdocument</comment>
- <comment xml:lang="nb">dokument for regnearkutveksling</comment>
- <comment xml:lang="lv">izklājlapu apmaiņas dokuments</comment>
- <comment xml:lang="lt">skaičialenčių apsikeitimo dokumentas</comment>
- <comment xml:lang="ko">스프레드시트 교환 문서</comment>
- <comment xml:lang="kk">spreadsheet interchange құжаты</comment>
- <comment xml:lang="ja">スプレッドシート交換ドキュメント</comment>
<comment xml:lang="it">Documento di scambio per foglio di calcolo</comment>
- <comment xml:lang="id">dokumen lembar sebar saling tukar</comment>
- <comment xml:lang="ia">Documento de intercambio de folio de calculo</comment>
- <comment xml:lang="hu">spreadsheet-cserélhetődokumentum</comment>
- <comment xml:lang="hr">Dokument razmjene proračunske tablice</comment>
- <comment xml:lang="he">מסמך גיליון נתונים מתחלף</comment>
- <comment xml:lang="gl">documento de intercambio de follas de cálculo</comment>
- <comment xml:lang="ga">cáipéis idirmhalartaithe scarbhileog</comment>
- <comment xml:lang="fur">document di interscambi par sfuei di calcul</comment>
- <comment xml:lang="fr">document d'échange de feuilles de calcul</comment>
- <comment xml:lang="fo">rokniarks umbýtisskjal</comment>
- <comment xml:lang="fi">taulukkovälitysasiakirja</comment>
- <comment xml:lang="eu">kalkulu-orriak trukatzeko dokumentua</comment>
- <comment xml:lang="es">documento de intercambio de hoja de cálculo</comment>
- <comment xml:lang="en_GB">spreadsheet interchange document</comment>
- <comment xml:lang="el">Έγγραφο ανταλλαγής λογιστικού φύλλου</comment>
+ <comment xml:lang="es">documento de intercambio de hojas de cálculo</comment>
<comment xml:lang="de">Tabellenkalkulations-Austauschdokument</comment>
- <comment xml:lang="da">regnearksudvekslingsdokument</comment>
- <comment xml:lang="cs">sešitový výměnný dokument</comment>
- <comment xml:lang="ca">document d'intercanvi de full de càlcul</comment>
- <comment xml:lang="bg">Документ — обмяна между електронни таблици</comment>
- <comment xml:lang="be@latin">dakument dla abmienu raźlikovymi arkušami</comment>
- <comment xml:lang="ast">documentu d'intercambéu de fueyes de cálculu</comment>
- <comment xml:lang="ar">مستند تبادل جدول</comment>
+ <comment xml:lang="be">дакумент для абмену электроннымі табліцамі</comment>
<sub-class-of type="text/plain"/>
<magic>
<match type="string" value="ID;" offset="0"/>
@@ -34071,8 +34511,9 @@ command to generate the output files.
<comment xml:lang="tr">TSV belgesi</comment>
<comment xml:lang="sv">TSV-dokument</comment>
<comment xml:lang="sr">ТСВ документ</comment>
- <comment xml:lang="sq">Dokument TSV</comment>
+ <comment xml:lang="sq">dokument TSV</comment>
<comment xml:lang="sl">Dokument TSV</comment>
+ <comment xml:lang="si">TSV ලේඛනය</comment>
<comment xml:lang="sk">Dokument TSV</comment>
<comment xml:lang="ru">Документ TSV</comment>
<comment xml:lang="ro">Document TSV</comment>
@@ -34089,6 +34530,7 @@ command to generate the output files.
<comment xml:lang="kk">TSV құжаты</comment>
<comment xml:lang="ja">TSV ドキュメント</comment>
<comment xml:lang="it">Documento TSV</comment>
+ <comment xml:lang="is">TSV skjal</comment>
<comment xml:lang="id">Dokumen TSV</comment>
<comment xml:lang="ia">Documento TSV</comment>
<comment xml:lang="hu">TSV dokumentum</comment>
@@ -34110,6 +34552,7 @@ command to generate the output files.
<comment xml:lang="ca">document TSV</comment>
<comment xml:lang="bg">Документ — TSV</comment>
<comment xml:lang="be@latin">Dakument TSV</comment>
+ <comment xml:lang="be">дакумент TSV</comment>
<comment xml:lang="ast">Documentu TSV</comment>
<comment xml:lang="ar">مستند TSV</comment>
<comment xml:lang="af">TSV-dokument</comment>
@@ -34127,7 +34570,9 @@ command to generate the output files.
<comment xml:lang="tr">Graphviz DOT grafiği</comment>
<comment xml:lang="sv">Graphviz DOT-graf</comment>
<comment xml:lang="sr">график Графвиз ДОТ-а</comment>
+ <comment xml:lang="sq">grafik Graphviz DOT</comment>
<comment xml:lang="sl">Datoteka grafikona Graphviz DOT</comment>
+ <comment xml:lang="si">Graphviz DOT ප්‍රස්ථාරය</comment>
<comment xml:lang="sk">Graf Graphviz DOT</comment>
<comment xml:lang="ru">Диаграмма Graphviz DOT</comment>
<comment xml:lang="ro">Grafic Graphviz DOT</comment>
@@ -34135,13 +34580,14 @@ command to generate the output files.
<comment xml:lang="pt">gráfico Graphviz DOT</comment>
<comment xml:lang="pl">Wykres DOT Graphviz</comment>
<comment xml:lang="oc">graf Graphviz DOT</comment>
- <comment xml:lang="nl">Graphviz wetenschappelijke grafiek</comment>
+ <comment xml:lang="nl">Graphviz DOT-grafiek</comment>
<comment xml:lang="lv">Graphviz DOT grafiks</comment>
<comment xml:lang="lt">Graphviz DOT diagrama</comment>
<comment xml:lang="ko">Graphviz DOT 그래프</comment>
<comment xml:lang="kk">Graphviz DOT сызбасы</comment>
<comment xml:lang="ja">Graphviz DOT グラフ</comment>
<comment xml:lang="it">Grafico Graphviz DOT</comment>
+ <comment xml:lang="is">Graphviz DOT punktgraf</comment>
<comment xml:lang="id">Grafik Graphviz DOT</comment>
<comment xml:lang="ia">Graphico DOT de Graphviz</comment>
<comment xml:lang="hu">Graphviz DOT-grafikon</comment>
@@ -34162,6 +34608,7 @@ command to generate the output files.
<comment xml:lang="cs">graf Graphviz DOT</comment>
<comment xml:lang="ca">gràfic Graphviz DOT</comment>
<comment xml:lang="bg">Граф — Graphviz DOT</comment>
+ <comment xml:lang="be">граф Graphviz DOT</comment>
<comment xml:lang="ar">مبيان Graphviz DOT</comment>
<comment xml:lang="af">Graphviz DOT-grafiek</comment>
<sub-class-of type="text/plain"/>
@@ -34184,8 +34631,9 @@ command to generate the output files.
<comment xml:lang="tr">JAD belgesi</comment>
<comment xml:lang="sv">JAD-dokument</comment>
<comment xml:lang="sr">ЈАД документ</comment>
- <comment xml:lang="sq">Dokument JAD</comment>
+ <comment xml:lang="sq">dokument JAD</comment>
<comment xml:lang="sl">Dokument JAD</comment>
+ <comment xml:lang="si">JAD ලේඛනය</comment>
<comment xml:lang="sk">Dokument JAD</comment>
<comment xml:lang="ru">Документ JAD</comment>
<comment xml:lang="ro">Document JAD</comment>
@@ -34202,6 +34650,7 @@ command to generate the output files.
<comment xml:lang="kk">JAD құжаты</comment>
<comment xml:lang="ja">JAD ドキュメント</comment>
<comment xml:lang="it">Documento JAD</comment>
+ <comment xml:lang="is">JAD skjal</comment>
<comment xml:lang="id">Dokumen JAD</comment>
<comment xml:lang="ia">Documento JAD</comment>
<comment xml:lang="hu">JAD dokumentum</comment>
@@ -34224,6 +34673,7 @@ command to generate the output files.
<comment xml:lang="ca">document JAD</comment>
<comment xml:lang="bg">Документ — JAD</comment>
<comment xml:lang="be@latin">Dakument JAD</comment>
+ <comment xml:lang="be">дакумент JAD</comment>
<comment xml:lang="ast">Documentu JAD</comment>
<comment xml:lang="ar">مستند JAD</comment>
<comment xml:lang="af">JAD-dokument</comment>
@@ -34244,8 +34694,9 @@ command to generate the output files.
<comment xml:lang="tr">WML belgesi</comment>
<comment xml:lang="sv">WML-dokument</comment>
<comment xml:lang="sr">ВМЛ документ</comment>
- <comment xml:lang="sq">Dokument WML</comment>
+ <comment xml:lang="sq">dokument WML</comment>
<comment xml:lang="sl">Dokument WML</comment>
+ <comment xml:lang="si">WML ලේඛනය</comment>
<comment xml:lang="sk">Dokument WML</comment>
<comment xml:lang="ru">Документ WML</comment>
<comment xml:lang="ro">Document WML</comment>
@@ -34263,6 +34714,7 @@ command to generate the output files.
<comment xml:lang="kk">WML құжаты</comment>
<comment xml:lang="ja">WML ドキュメント</comment>
<comment xml:lang="it">Documento WML</comment>
+ <comment xml:lang="is">WML skjal</comment>
<comment xml:lang="id">Dokumen WML</comment>
<comment xml:lang="ia">Documento WML</comment>
<comment xml:lang="hu">WML-dokumentum</comment>
@@ -34286,6 +34738,7 @@ command to generate the output files.
<comment xml:lang="ca">document WML</comment>
<comment xml:lang="bg">Документ — WML</comment>
<comment xml:lang="be@latin">Dakument WML</comment>
+ <comment xml:lang="be">дакумент WML</comment>
<comment xml:lang="az">WML sənədi</comment>
<comment xml:lang="ast">Documentu WML</comment>
<comment xml:lang="ar">مستند WML</comment>
@@ -34304,8 +34757,9 @@ command to generate the output files.
<comment xml:lang="tr">WMLScript programı</comment>
<comment xml:lang="sv">WMLScript-program</comment>
<comment xml:lang="sr">програм ВМЛ скрипте</comment>
- <comment xml:lang="sq">Program WMLScript</comment>
+ <comment xml:lang="sq">program WMLScript</comment>
<comment xml:lang="sl">Programska datoteka WMLScript</comment>
+ <comment xml:lang="si">WMLScript වැඩසටහන</comment>
<comment xml:lang="sk">Program WMLScript</comment>
<comment xml:lang="ru">Программа WMLScript</comment>
<comment xml:lang="ro">Program WMLScript</comment>
@@ -34314,7 +34768,7 @@ command to generate the output files.
<comment xml:lang="pl">Pogram WMLScript</comment>
<comment xml:lang="oc">programa WMLEscript</comment>
<comment xml:lang="nn">WMLScript-program</comment>
- <comment xml:lang="nl">WMLScript-programma</comment>
+ <comment xml:lang="nl">WMLScript-toepassing</comment>
<comment xml:lang="nb">WMLScript-program</comment>
<comment xml:lang="lv">WMLScript programma</comment>
<comment xml:lang="lt">WMLScript programa</comment>
@@ -34322,6 +34776,7 @@ command to generate the output files.
<comment xml:lang="kk">WMLScript бағдарламасы</comment>
<comment xml:lang="ja">WMLScript プログラム</comment>
<comment xml:lang="it">Programma WMLScript</comment>
+ <comment xml:lang="is">WMLScript forrit</comment>
<comment xml:lang="id">Program WMLScript</comment>
<comment xml:lang="ia">Programma WMLScript</comment>
<comment xml:lang="hu">WMLScript program</comment>
@@ -34343,6 +34798,7 @@ command to generate the output files.
<comment xml:lang="ca">programa WMLScript</comment>
<comment xml:lang="bg">Програма — WMLScript</comment>
<comment xml:lang="be@latin">Prahrama WMLScript</comment>
+ <comment xml:lang="be">праграма WMLScript</comment>
<comment xml:lang="ar">برنامج WMLScript</comment>
<comment xml:lang="af">WMLScript-program</comment>
<sub-class-of type="text/plain"/>
@@ -34352,21 +34808,26 @@ command to generate the output files.
<comment>WarpScript source code</comment>
<comment xml:lang="zh_TW">WarpScript 原始碼</comment>
<comment xml:lang="zh_CN">WarpScript 源代码</comment>
- <comment xml:lang="uk">вихідний код мовою WarpScript</comment>
+ <comment xml:lang="uk">початковий код мовою WarpScript</comment>
<comment xml:lang="tr">WarpScript kaynak kodu</comment>
<comment xml:lang="sv">WarpScript-källkod</comment>
+ <comment xml:lang="sq">kod burim WarpScript</comment>
<comment xml:lang="sl">Izvorna koda WarpScript</comment>
+ <comment xml:lang="si">WarpScript මූලාශ්‍ර කේතය</comment>
<comment xml:lang="ru">Исходный код WarpScript</comment>
<comment xml:lang="pt_BR">Código-fonte WarpScript</comment>
<comment xml:lang="pl">Kod źródłowy WarpScript</comment>
+ <comment xml:lang="nl">WarpScript-broncode</comment>
<comment xml:lang="ko">WarpScript 소스 코드</comment>
<comment xml:lang="kk">WarpScript бастапқы коды</comment>
<comment xml:lang="ja">WarpScript ソースコード</comment>
<comment xml:lang="it">Codice sorgente WarpScript</comment>
+ <comment xml:lang="is">WarpScript frumkóði</comment>
<comment xml:lang="id">Kode sumber WarpScript</comment>
<comment xml:lang="hu">WarpScript forráskód</comment>
<comment xml:lang="hr">WarpScript izvorni kôd</comment>
<comment xml:lang="he">קוד מקור ב־WarpScript</comment>
+ <comment xml:lang="gl">Código fonte en WarpScript</comment>
<comment xml:lang="fur">codiç sorzint WarpScript</comment>
<comment xml:lang="fr">code source WarpScript</comment>
<comment xml:lang="fi">WarpScript-lähdekoodi</comment>
@@ -34378,6 +34839,7 @@ command to generate the output files.
<comment xml:lang="cs">zdrojový kód v jazyce WarpScript</comment>
<comment xml:lang="ca">codi font en WarpScript</comment>
<comment xml:lang="bg">Изходен код — WarpScript</comment>
+ <comment xml:lang="be">зыходны код WarpScript</comment>
<comment xml:lang="ar">شفرة مصدر WarpScript</comment>
<sub-class-of type="text/plain"/>
<glob pattern="*.mc2"/>
@@ -34391,8 +34853,9 @@ command to generate the output files.
<comment xml:lang="tr">ACE arşivi</comment>
<comment xml:lang="sv">ACE-arkiv</comment>
<comment xml:lang="sr">АЦЕ архива</comment>
- <comment xml:lang="sq">Arkiv ACE</comment>
+ <comment xml:lang="sq">arkiv ACE</comment>
<comment xml:lang="sl">Datoteka arhiva ACE</comment>
+ <comment xml:lang="si">ACE ලේඛනාගාරය</comment>
<comment xml:lang="sk">Archív ACE</comment>
<comment xml:lang="ru">Архив ACE</comment>
<comment xml:lang="ro">Arhivă ACE</comment>
@@ -34410,6 +34873,7 @@ command to generate the output files.
<comment xml:lang="ka">ACE არქივი</comment>
<comment xml:lang="ja">ACE アーカイブ</comment>
<comment xml:lang="it">Archivio ACE</comment>
+ <comment xml:lang="is">ACE safnskrá</comment>
<comment xml:lang="id">Arsip ACE</comment>
<comment xml:lang="ia">Archivo ACE</comment>
<comment xml:lang="hu">ACE archívum</comment>
@@ -34432,6 +34896,7 @@ command to generate the output files.
<comment xml:lang="ca">arxiu ACE</comment>
<comment xml:lang="bg">Архив — ACE</comment>
<comment xml:lang="be@latin">Archiŭ ACE</comment>
+ <comment xml:lang="be">архіў ACE</comment>
<comment xml:lang="ar">أرشيف ACE</comment>
<comment xml:lang="af">ACE-argief</comment>
<generic-icon name="package-x-generic"/>
@@ -34445,12 +34910,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">Ada 源碼</comment>
<comment xml:lang="zh_CN">Ada 源代码</comment>
<comment xml:lang="vi">Mã nguồn Ada</comment>
- <comment xml:lang="uk">вихідний код мовою Ada</comment>
+ <comment xml:lang="uk">початковий код мовою Ada</comment>
<comment xml:lang="tr">Ada kaynak kodu</comment>
<comment xml:lang="sv">Ada-källkod</comment>
<comment xml:lang="sr">Ада изворни ко̂д</comment>
- <comment xml:lang="sq">Kod burues Ada</comment>
+ <comment xml:lang="sq">kod burim Ada</comment>
<comment xml:lang="sl">Datoteka izvorne kode Ada</comment>
+ <comment xml:lang="si">Ada මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód jazyka Ada</comment>
<comment xml:lang="ru">Исходный код Ada</comment>
<comment xml:lang="ro">Cod sursă Ada</comment>
@@ -34469,6 +34935,7 @@ command to generate the output files.
<comment xml:lang="ka">Ada-ის საწყისი კოდი</comment>
<comment xml:lang="ja">Ada ソースコード</comment>
<comment xml:lang="it">Codice sorgente Ada</comment>
+ <comment xml:lang="is">Ada frumkóði</comment>
<comment xml:lang="id">Kode sumber Ada</comment>
<comment xml:lang="ia">Codice-fonte Ada</comment>
<comment xml:lang="hu">Ada-forráskód</comment>
@@ -34491,6 +34958,7 @@ command to generate the output files.
<comment xml:lang="ca">codi font en Ada</comment>
<comment xml:lang="bg">Изходен код — Ada</comment>
<comment xml:lang="be@latin">Kryničny kod Ada</comment>
+ <comment xml:lang="be">зыходны код Ada</comment>
<comment xml:lang="ar">شفرة مصدر Ada</comment>
<comment xml:lang="af">Ada-bronkode</comment>
<sub-class-of type="text/plain"/>
@@ -34498,57 +34966,16 @@ command to generate the output files.
<glob pattern="*.ads"/>
</mime-type>
<mime-type type="text/x-authors">
- <comment>author list</comment>
- <comment xml:lang="zh_TW">作者清單</comment>
- <comment xml:lang="zh_CN">作者列表</comment>
- <comment xml:lang="vi">danh sách tác giả</comment>
- <comment xml:lang="uk">перелік авторів</comment>
- <comment xml:lang="tr">yazar listesi</comment>
- <comment xml:lang="sv">författarlista</comment>
- <comment xml:lang="sr">списак аутора</comment>
- <comment xml:lang="sq">Lista e autorëve</comment>
- <comment xml:lang="sl">seznam avtorjev</comment>
- <comment xml:lang="sk">Zoznam autorov</comment>
+ <comment>Author list</comment>
+ <comment xml:lang="uk">список авторів</comment>
+ <comment xml:lang="sv">Författarlista</comment>
<comment xml:lang="ru">Список авторов</comment>
- <comment xml:lang="ro">listă autori</comment>
- <comment xml:lang="pt_BR">Lista de autores</comment>
- <comment xml:lang="pt">lista de autores</comment>
<comment xml:lang="pl">Lista autorów</comment>
- <comment xml:lang="oc">lista d'autors</comment>
- <comment xml:lang="nn">forfattarliste</comment>
- <comment xml:lang="nl">auteurslijst</comment>
- <comment xml:lang="nb">forfatterliste</comment>
- <comment xml:lang="ms">Senarai penulis</comment>
- <comment xml:lang="lv">autoru saraksts</comment>
- <comment xml:lang="lt">autorių sąrašas</comment>
- <comment xml:lang="ko">저자 목록</comment>
- <comment xml:lang="kk">авторлар тізімі</comment>
- <comment xml:lang="ja">著者リスト</comment>
<comment xml:lang="it">Elenco autori</comment>
- <comment xml:lang="id">senarai penulis</comment>
- <comment xml:lang="ia">Lista de autores</comment>
- <comment xml:lang="hu">szerzőlista</comment>
- <comment xml:lang="hr">Popis autora</comment>
- <comment xml:lang="he">רשימת יוצרים</comment>
- <comment xml:lang="gl">lista de autores</comment>
- <comment xml:lang="ga">liosta údar</comment>
- <comment xml:lang="fur">liste di autôrs</comment>
- <comment xml:lang="fr">liste d'auteurs</comment>
- <comment xml:lang="fo">høvundalisti</comment>
- <comment xml:lang="fi">tekijäluettelo</comment>
- <comment xml:lang="eu">egile-zerrenda</comment>
+ <comment xml:lang="eu">Egile-zerrenda</comment>
<comment xml:lang="es">lista de autores</comment>
- <comment xml:lang="eo">listo de aŭtoroj</comment>
- <comment xml:lang="en_GB">author list</comment>
- <comment xml:lang="el">Κατάλογος συγγραφέων</comment>
<comment xml:lang="de">Autorenliste</comment>
- <comment xml:lang="da">forfatterliste</comment>
- <comment xml:lang="cs">seznam autorů</comment>
- <comment xml:lang="ca">llista d'autors</comment>
- <comment xml:lang="bg">Списък на авторите</comment>
- <comment xml:lang="be@latin">śpis aŭtaraŭ</comment>
- <comment xml:lang="ar">لائحة المؤلف</comment>
- <comment xml:lang="af">outeurlys</comment>
+ <comment xml:lang="be">спіс аўтараў</comment>
<sub-class-of type="text/plain"/>
<glob pattern="AUTHORS"/>
</mime-type>
@@ -34561,8 +34988,9 @@ command to generate the output files.
<comment xml:lang="tr">BibTeX belgesi</comment>
<comment xml:lang="sv">BibTeX-dokument</comment>
<comment xml:lang="sr">Биб ТеКс документ</comment>
- <comment xml:lang="sq">Dokument BibTeX</comment>
+ <comment xml:lang="sq">dokument BibTeX</comment>
<comment xml:lang="sl">Dokument BibTeX</comment>
+ <comment xml:lang="si">BibTeX ලේඛනය</comment>
<comment xml:lang="sk">Dokument BibTeX</comment>
<comment xml:lang="ru">Документ BibTeX</comment>
<comment xml:lang="ro">Document BibTeX</comment>
@@ -34580,6 +35008,7 @@ command to generate the output files.
<comment xml:lang="ka">BibTeX-ის დოკუმენტი</comment>
<comment xml:lang="ja">BibTeX ドキュメント</comment>
<comment xml:lang="it">Documento BibTeX</comment>
+ <comment xml:lang="is">BibTeX skjal</comment>
<comment xml:lang="id">Dokumen BibTeX</comment>
<comment xml:lang="ia">Documento BibTeX</comment>
<comment xml:lang="hu">BibTeX dokumentum</comment>
@@ -34602,6 +35031,7 @@ command to generate the output files.
<comment xml:lang="ca">document BibTeX</comment>
<comment xml:lang="bg">Документ — BibTeX</comment>
<comment xml:lang="be@latin">Dakument BibTeX</comment>
+ <comment xml:lang="be">дакумент BibTeX</comment>
<comment xml:lang="ast">Documentu de BibTeX</comment>
<comment xml:lang="ar">مستند BibTeX</comment>
<comment xml:lang="af">BibTeX-dokument</comment>
@@ -34611,6 +35041,20 @@ command to generate the output files.
</magic>
<glob pattern="*.bib"/>
</mime-type>
+ <mime-type type="text/x-blueprint">
+ <comment>Blueprint source code</comment>
+ <comment xml:lang="uk">початковий код синьки</comment>
+ <comment xml:lang="sv">Blueprint-källkod</comment>
+ <comment xml:lang="ru">Исходный код Blueprint</comment>
+ <comment xml:lang="pl">Kod źródłowy Blueprint</comment>
+ <comment xml:lang="it">Codice sorgente Blueprint</comment>
+ <comment xml:lang="gl">Código fonte en Blueprint</comment>
+ <comment xml:lang="es">código fuente en Blueprint</comment>
+ <comment xml:lang="de">Blueprint-Quelltext</comment>
+ <comment xml:lang="be">зыходны код Blueprint</comment>
+ <sub-class-of type="text/plain"/>
+ <glob pattern="*.blp"/>
+ </mime-type>
<mime-type type="text/x-c++hdr">
<comment>C++ header</comment>
<comment xml:lang="zh_TW">C++ 標頭檔</comment>
@@ -34620,8 +35064,9 @@ command to generate the output files.
<comment xml:lang="tr">C++ başlığı</comment>
<comment xml:lang="sv">C++-huvud</comment>
<comment xml:lang="sr">Ц++ заглавље</comment>
- <comment xml:lang="sq">Header C++</comment>
+ <comment xml:lang="sq">krye C++</comment>
<comment xml:lang="sl">Datoteka glave C++</comment>
+ <comment xml:lang="si">C++ ශීර්ෂකය</comment>
<comment xml:lang="sk">Hlavičky jazyka C++</comment>
<comment xml:lang="ru">Заголовочный файл C++</comment>
<comment xml:lang="ro">Antet C++</comment>
@@ -34639,6 +35084,7 @@ command to generate the output files.
<comment xml:lang="ka">C++-ის თავსართი</comment>
<comment xml:lang="ja">C++ ヘッダー</comment>
<comment xml:lang="it">Header C++</comment>
+ <comment xml:lang="is">C++ haus</comment>
<comment xml:lang="id">Header C++</comment>
<comment xml:lang="ia">Capite C++</comment>
<comment xml:lang="hu">C++ fejléc</comment>
@@ -34660,6 +35106,7 @@ command to generate the output files.
<comment xml:lang="ca">capçalera en C++</comment>
<comment xml:lang="bg">Заглавен файл — C++</comment>
<comment xml:lang="be@latin">Zahałoŭny fajł C++</comment>
+ <comment xml:lang="be">загаловачны файл C++</comment>
<comment xml:lang="ar">ترويسة سي++</comment>
<sub-class-of type="text/x-chdr"/>
<glob pattern="*.hh"/>
@@ -34673,12 +35120,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">C++ 源碼</comment>
<comment xml:lang="zh_CN">C++ 源代码</comment>
<comment xml:lang="vi">Mã nguồn C++</comment>
- <comment xml:lang="uk">вихідний код мовою C++</comment>
+ <comment xml:lang="uk">початковий код мовою C++</comment>
<comment xml:lang="tr">C++ kaynak kodu</comment>
<comment xml:lang="sv">C++-källkod</comment>
<comment xml:lang="sr">Ц++ изворни ко̂д</comment>
- <comment xml:lang="sq">Kod burues C++</comment>
+ <comment xml:lang="sq">kod burim C++</comment>
<comment xml:lang="sl">Datoteka izvorne kode C++</comment>
+ <comment xml:lang="si">C++ මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód jazyka C++</comment>
<comment xml:lang="ru">Исходный код C++</comment>
<comment xml:lang="ro">Cod sursă C++</comment>
@@ -34697,6 +35145,7 @@ command to generate the output files.
<comment xml:lang="ka">C++-ის საწყისი კოდი</comment>
<comment xml:lang="ja">C++ ソースコード</comment>
<comment xml:lang="it">Codice sorgente C++</comment>
+ <comment xml:lang="is">C++ frumkóði</comment>
<comment xml:lang="id">Kode sumber C++</comment>
<comment xml:lang="ia">Codice-fonte C++</comment>
<comment xml:lang="hu">C++-forráskód</comment>
@@ -34719,6 +35168,7 @@ command to generate the output files.
<comment xml:lang="ca">codi font en C++</comment>
<comment xml:lang="bg">Изходен код — C++</comment>
<comment xml:lang="be@latin">Kryničny kod C++</comment>
+ <comment xml:lang="be">зыходны код C++</comment>
<comment xml:lang="ar">شفرة مصدر سي++</comment>
<comment xml:lang="af">C++-bronkode</comment>
<sub-class-of type="text/x-csrc"/>
@@ -34737,8 +35187,9 @@ command to generate the output files.
<comment xml:lang="tr">ChangeLog belgesi</comment>
<comment xml:lang="sv">Ändringsloggsdokument</comment>
<comment xml:lang="sr">документ дневника измена</comment>
- <comment xml:lang="sq">Dokument ChangeLog</comment>
+ <comment xml:lang="sq">dokument regjistri ndryshimesh</comment>
<comment xml:lang="sl">Dokument ChangeLog</comment>
+ <comment xml:lang="si">ChangeLog ලේඛනය</comment>
<comment xml:lang="sk">Dokument ChangeLog</comment>
<comment xml:lang="ru">Протокол изменений</comment>
<comment xml:lang="ro">Document ChangeLog</comment>
@@ -34756,6 +35207,7 @@ command to generate the output files.
<comment xml:lang="ka">ChangeLog დოკუმენტი</comment>
<comment xml:lang="ja">ChangeLog ドキュメント</comment>
<comment xml:lang="it">Documento ChangeLog</comment>
+ <comment xml:lang="is">ChangeLog skjal</comment>
<comment xml:lang="id">Dokumen ChangeLog</comment>
<comment xml:lang="ia">Lista de cambiamentos</comment>
<comment xml:lang="hu">ChangeLog dokumentum</comment>
@@ -34777,6 +35229,7 @@ command to generate the output files.
<comment xml:lang="ca">document de registre de canvis</comment>
<comment xml:lang="bg">Дневник за промени — ChangeLog</comment>
<comment xml:lang="be@latin">Dakument zafiksavanych źmienaŭ ChangeLog</comment>
+ <comment xml:lang="be">дакумент zafiksavanych źmienaŭ ChangeLog</comment>
<comment xml:lang="ast">Documentu de rexistru de cambeos</comment>
<comment xml:lang="ar">مستند ChangeLog</comment>
<comment xml:lang="af">ChangeLog-dokument</comment>
@@ -34792,8 +35245,9 @@ command to generate the output files.
<comment xml:lang="tr">C başlığı</comment>
<comment xml:lang="sv">C-huvud</comment>
<comment xml:lang="sr">Ц заглавље</comment>
- <comment xml:lang="sq">Header C</comment>
+ <comment xml:lang="sq">krye C</comment>
<comment xml:lang="sl">Datoteka glave C</comment>
+ <comment xml:lang="si">C ශීර්ෂකය</comment>
<comment xml:lang="sk">Hlavičky jazyka C</comment>
<comment xml:lang="ru">Заголовочный файл C</comment>
<comment xml:lang="ro">Antet C</comment>
@@ -34811,6 +35265,7 @@ command to generate the output files.
<comment xml:lang="ka">C-ის თავსართი</comment>
<comment xml:lang="ja">C ヘッダー</comment>
<comment xml:lang="it">Header C</comment>
+ <comment xml:lang="is">C haus</comment>
<comment xml:lang="id">Header C</comment>
<comment xml:lang="ia">Capite C</comment>
<comment xml:lang="hu">C fejléc</comment>
@@ -34832,6 +35287,7 @@ command to generate the output files.
<comment xml:lang="ca">capçalera en C</comment>
<comment xml:lang="bg">Заглавен файл — C</comment>
<comment xml:lang="be@latin">Zahałoŭny fajł C</comment>
+ <comment xml:lang="be">загаловачны файл C</comment>
<comment xml:lang="ar">ترويسة C</comment>
<sub-class-of type="text/x-csrc"/>
<glob pattern="*.h"/>
@@ -34841,12 +35297,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">CMake 源碼</comment>
<comment xml:lang="zh_CN">CMake 源代码</comment>
<comment xml:lang="vi">Mã nguồn CMake</comment>
- <comment xml:lang="uk">вихідний код CMake</comment>
+ <comment xml:lang="uk">початковий код мовою CMake</comment>
<comment xml:lang="tr">CMake kaynak kodu</comment>
<comment xml:lang="sv">CMake-källkod</comment>
<comment xml:lang="sr">Ц Мејк изворни ко̂д</comment>
- <comment xml:lang="sq">Kod burues CMake</comment>
+ <comment xml:lang="sq">kod burim CMake</comment>
<comment xml:lang="sl">Datoteka izvorne kode CMake</comment>
+ <comment xml:lang="si">CMake මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód CMake</comment>
<comment xml:lang="ru">Исходный код CMake</comment>
<comment xml:lang="ro">Cod sursă CMake</comment>
@@ -34864,6 +35321,7 @@ command to generate the output files.
<comment xml:lang="ka">CMake-ის საწყისი კოდი</comment>
<comment xml:lang="ja">CMake ソースコード</comment>
<comment xml:lang="it">Codice sorgente CMake</comment>
+ <comment xml:lang="is">CMake frumkóði</comment>
<comment xml:lang="id">Kode sumber CMake</comment>
<comment xml:lang="ia">Codice-fonte CMake</comment>
<comment xml:lang="hu">CMake-forráskód</comment>
@@ -34886,6 +35344,7 @@ command to generate the output files.
<comment xml:lang="ca">codi font en CMake</comment>
<comment xml:lang="bg">Изходен код — CMake</comment>
<comment xml:lang="be@latin">Kryničny kod CMake</comment>
+ <comment xml:lang="be">зыходны код CMake</comment>
<comment xml:lang="ar">شفرة مصدر CMake</comment>
<comment xml:lang="af">CMake-bronkode</comment>
<glob pattern="*.cmake"/>
@@ -34894,20 +35353,26 @@ command to generate the output files.
</mime-type>
<mime-type type="text/x-common-lisp">
<comment>Common Lisp source code</comment>
- <comment xml:lang="zh_TW">Common Lisp 源碼</comment>
+ <comment xml:lang="zh_TW">Common Lisp 原始碼</comment>
<comment xml:lang="zh_CN">Common Lisp 源代码</comment>
- <comment xml:lang="uk">вихідний код мовою Common Lisp</comment>
+ <comment xml:lang="uk">початковий код мовою Common Lisp</comment>
<comment xml:lang="tr">Common Lisp kaynak kodu</comment>
<comment xml:lang="sv">Common Lisp-källkod</comment>
+ <comment xml:lang="si">පොදු Lisp මූලාශ්‍ර කේතය</comment>
+ <comment xml:lang="ru">Исходный код Common Lisp</comment>
<comment xml:lang="pt_BR">Código-fonte Common Lisp</comment>
<comment xml:lang="pl">Kod źródłowy Common Lisp</comment>
+ <comment xml:lang="nl">Common Lisp-broncode</comment>
<comment xml:lang="ko">Common Lisp 소스 코드</comment>
+ <comment xml:lang="kk">Common Lisp бастапқы коды</comment>
<comment xml:lang="ja">Common Lisp ソースコード</comment>
<comment xml:lang="it">Codice sorgente Common Lisp</comment>
+ <comment xml:lang="is">Sameiginlegur Lisp frumkóði</comment>
<comment xml:lang="id">kode sumber Common Lisp</comment>
<comment xml:lang="hu">Common Lisp forráskód</comment>
<comment xml:lang="hr">Common Lisp izvorni kôd</comment>
<comment xml:lang="he">קוד מקור של Common Lisp</comment>
+ <comment xml:lang="gl">Código fonte en Common Lisp</comment>
<comment xml:lang="fr">code source Common Lisp</comment>
<comment xml:lang="fi">Common Lisp -lähdekoodi</comment>
<comment xml:lang="es">código fuente en Common Lisp</comment>
@@ -34915,6 +35380,7 @@ command to generate the output files.
<comment xml:lang="de">Common-Lisp-Quelltext</comment>
<comment xml:lang="da">Common Lisp-kildekode</comment>
<comment xml:lang="ca">codi font en Common Lisp</comment>
+ <comment xml:lang="be">зыходны код Common Lisp</comment>
<comment xml:lang="ar">شفرة مصدر Common Lisp</comment>
<sub-class-of type="text/plain"/>
<glob pattern="*.asd"/>
@@ -34931,8 +35397,9 @@ command to generate the output files.
<comment xml:lang="tr">CSV belgesi</comment>
<comment xml:lang="sv">CSV-dokument</comment>
<comment xml:lang="sr">ЦСВ документ</comment>
- <comment xml:lang="sq">Dokument CSV</comment>
+ <comment xml:lang="sq">dokument CSV</comment>
<comment xml:lang="sl">Dokument CSV</comment>
+ <comment xml:lang="si">CSV ලේඛනය</comment>
<comment xml:lang="sk">Dokument CSV</comment>
<comment xml:lang="ru">Документ CSV</comment>
<comment xml:lang="ro">Document CSV</comment>
@@ -34950,6 +35417,7 @@ command to generate the output files.
<comment xml:lang="ka">CSV დოკუმენტი</comment>
<comment xml:lang="ja">CSV ドキュメント</comment>
<comment xml:lang="it">Documento CSV</comment>
+ <comment xml:lang="is">CSV skjal</comment>
<comment xml:lang="id">Dokumen CSV</comment>
<comment xml:lang="ia">Documento CSV</comment>
<comment xml:lang="hu">CSV dokumentum</comment>
@@ -34972,6 +35440,7 @@ command to generate the output files.
<comment xml:lang="ca">document CSV</comment>
<comment xml:lang="bg">Документ — CSV</comment>
<comment xml:lang="be@latin">Dakument CSV</comment>
+ <comment xml:lang="be">дакумент CSV</comment>
<comment xml:lang="ast">Documentu CVS</comment>
<comment xml:lang="ar">مستند CSV</comment>
<comment xml:lang="af">CSV-dokument</comment>
@@ -34990,16 +35459,20 @@ command to generate the output files.
<comment xml:lang="tr">CSV Şeması belgesi</comment>
<comment xml:lang="sv">CSV Schema-dokument</comment>
<comment xml:lang="sr">документ ЦСВ шеме</comment>
+ <comment xml:lang="sq">dokument CSV Schema</comment>
<comment xml:lang="sl">Dokument CSV Schema</comment>
+ <comment xml:lang="si">CSV ක්‍රම ලේඛනය</comment>
<comment xml:lang="sk">Dokument schémy CSV</comment>
<comment xml:lang="ru">Документ CSV Schema</comment>
<comment xml:lang="pt_BR">Documento CSV Schema</comment>
<comment xml:lang="pt">documento CSV Schema</comment>
<comment xml:lang="pl">Dokument schematu CSV</comment>
+ <comment xml:lang="nl">CSV-schemadocument</comment>
<comment xml:lang="ko">CSV 스키마 문서</comment>
<comment xml:lang="kk">CSV сұлба құжаты</comment>
<comment xml:lang="ja">CSV Schema ドキュメント</comment>
<comment xml:lang="it">Documento schema CSV</comment>
+ <comment xml:lang="is">CSV skemaskjal</comment>
<comment xml:lang="id">Dokumen Skema CSV</comment>
<comment xml:lang="ia">Documento CSV Schema</comment>
<comment xml:lang="hu">CSV sémadokumentum</comment>
@@ -35017,6 +35490,7 @@ command to generate the output files.
<comment xml:lang="cs">dokument schématu CSV</comment>
<comment xml:lang="ca">document Schema de CSV</comment>
<comment xml:lang="bg">Документ — схема на CSV</comment>
+ <comment xml:lang="be">дакумент CSV Schema</comment>
<comment xml:lang="ast">Documentu d'esquema CSV</comment>
<comment xml:lang="ar">مستند مخطط CSV</comment>
<comment xml:lang="af">CSV Schema-dokument</comment>
@@ -35026,110 +35500,33 @@ command to generate the output files.
<glob pattern="*.csvs"/>
</mime-type>
<mime-type type="text/x-copying">
- <comment>license terms</comment>
- <comment xml:lang="zh_TW">授權條款</comment>
- <comment xml:lang="zh_CN">软件许可条款</comment>
- <comment xml:lang="vi">điều kiện giấy phép</comment>
- <comment xml:lang="uk">ліцензійні умови</comment>
- <comment xml:lang="tr">lisans koşulları</comment>
- <comment xml:lang="sv">licensvillkor</comment>
- <comment xml:lang="sr">услови коришћења</comment>
- <comment xml:lang="sq">Kushte liçence</comment>
- <comment xml:lang="sl">pogoji in dovoljenja uporabe</comment>
- <comment xml:lang="sk">Licenčné podmienky</comment>
+ <comment>License terms</comment>
+ <comment xml:lang="uk">умови ліцензування</comment>
+ <comment xml:lang="sv">Licensvillkor</comment>
<comment xml:lang="ru">Лицензионное соглашение</comment>
- <comment xml:lang="ro">termeni de licență</comment>
- <comment xml:lang="pt_BR">Termos de licença</comment>
- <comment xml:lang="pt">termos de licença</comment>
<comment xml:lang="pl">Warunki licencji</comment>
- <comment xml:lang="oc">tèrmes de licéncia</comment>
- <comment xml:lang="nn">lisensvilkår</comment>
- <comment xml:lang="nl">licentievoorwaarden</comment>
- <comment xml:lang="nb">lisensbestemmelser</comment>
- <comment xml:lang="lv">licences nosacījumi</comment>
- <comment xml:lang="lt">licencijos sąlygos</comment>
- <comment xml:lang="ko">라이선스 조항</comment>
- <comment xml:lang="kk">лицензиялық келісімі</comment>
- <comment xml:lang="ja">ソフトウェアライセンス条項</comment>
+ <comment xml:lang="ja">利用許諾</comment>
<comment xml:lang="it">Termini di licenza</comment>
- <comment xml:lang="id">persyaratan lisensi</comment>
- <comment xml:lang="ia">Conditiones de licentia</comment>
- <comment xml:lang="hu">licencfeltételek</comment>
- <comment xml:lang="hr">Uvjeti licence</comment>
- <comment xml:lang="he">תנאי רישיון</comment>
- <comment xml:lang="gl">termos de licenza</comment>
- <comment xml:lang="ga">téarmaí ceadúnais</comment>
- <comment xml:lang="fur">tiermins di licence</comment>
- <comment xml:lang="fr">termes de licence</comment>
- <comment xml:lang="fo">loyvistreytir</comment>
- <comment xml:lang="fi">lisenssiehdot</comment>
- <comment xml:lang="eu">lizentzia baldintzak</comment>
+ <comment xml:lang="gl">Termos de licenza</comment>
+ <comment xml:lang="eu">Lizentziaren terminoak</comment>
<comment xml:lang="es">términos de licencia</comment>
- <comment xml:lang="en_GB">licence terms</comment>
- <comment xml:lang="el">Όροι άδειας</comment>
<comment xml:lang="de">Lizenzbedingungen</comment>
- <comment xml:lang="da">licensbetingelser</comment>
- <comment xml:lang="cs">licenční podmínky</comment>
- <comment xml:lang="ca">condicions de llicència</comment>
- <comment xml:lang="bg">Лицензни условия</comment>
- <comment xml:lang="be@latin">licenzijnyja ŭmovy</comment>
- <comment xml:lang="ast">términos de llicencia</comment>
- <comment xml:lang="ar">شروط الترخيص</comment>
- <comment xml:lang="af">lisensievoorwaardes</comment>
+ <comment xml:lang="be">умовы карыстання</comment>
<sub-class-of type="text/plain"/>
<glob pattern="COPYING"/>
</mime-type>
<mime-type type="text/x-credits">
- <comment>author credits</comment>
- <comment xml:lang="zh_TW">作者致謝名單</comment>
- <comment xml:lang="zh_CN">软件作者致谢</comment>
- <comment xml:lang="vi">công trạng tác giả</comment>
- <comment xml:lang="uk">подяки авторам програми</comment>
- <comment xml:lang="tr">yazar bilgileri</comment>
- <comment xml:lang="sv">författarlista</comment>
- <comment xml:lang="sr">заслуге аутора</comment>
- <comment xml:lang="sq">Kreditë e autorëve</comment>
- <comment xml:lang="sl">avtorske zasluge</comment>
- <comment xml:lang="sk">Autorské zásluhy</comment>
+ <comment>Author credits</comment>
+ <comment xml:lang="uk">подяки авторам</comment>
+ <comment xml:lang="sv">Författarlista</comment>
<comment xml:lang="ru">Авторы программы</comment>
- <comment xml:lang="ro">mulțumiri autori</comment>
- <comment xml:lang="pt_BR">Créditos do autor</comment>
- <comment xml:lang="pt">créditos de autor</comment>
<comment xml:lang="pl">Podziękowania autorów programu</comment>
- <comment xml:lang="oc">mercejaments</comment>
- <comment xml:lang="nn">forfattarliste</comment>
- <comment xml:lang="nl">auteursinformatie</comment>
- <comment xml:lang="nb">liste med bidragsytere</comment>
- <comment xml:lang="lv">veidotāji</comment>
- <comment xml:lang="lt">padėkos autoriams</comment>
- <comment xml:lang="ko">작성자 정보</comment>
- <comment xml:lang="kk">бағдарлама авторлары</comment>
- <comment xml:lang="ja">ソフトウェア作者クレジット</comment>
<comment xml:lang="it">Riconoscimenti autori</comment>
- <comment xml:lang="id">kredit penulis</comment>
- <comment xml:lang="ia">Recognoscentia de autores</comment>
- <comment xml:lang="hu">szerzők listája</comment>
- <comment xml:lang="hr">Zasluge autora</comment>
- <comment xml:lang="he">קרדיטים של היוצר</comment>
- <comment xml:lang="gl">créditos de autor</comment>
- <comment xml:lang="ga">admhálacha údar</comment>
- <comment xml:lang="fur">ricognossiments autôrs</comment>
- <comment xml:lang="fr">remerciements</comment>
- <comment xml:lang="fo">høvundaheiður</comment>
- <comment xml:lang="fi">tekijöiden kiitokset</comment>
- <comment xml:lang="eu">egile-kredituak</comment>
- <comment xml:lang="es">reconocimiento de autoría</comment>
- <comment xml:lang="en_GB">author credits</comment>
- <comment xml:lang="el">Μνεία συγγραφέων</comment>
+ <comment xml:lang="gl">Créditos de autor</comment>
+ <comment xml:lang="eu">Egile-kredituak</comment>
+ <comment xml:lang="es">créditos de autoría</comment>
<comment xml:lang="de">Autorendanksagung</comment>
- <comment xml:lang="da">bidragydere</comment>
- <comment xml:lang="cs">autorské zásluhy</comment>
- <comment xml:lang="ca">atribucions d'autor</comment>
- <comment xml:lang="bg">Благодарности към авторите</comment>
- <comment xml:lang="be@latin">zasłuhi aŭtara</comment>
- <comment xml:lang="ast">creitos del autor</comment>
- <comment xml:lang="ar">إشادات مؤلف</comment>
- <comment xml:lang="af">outeurerkenning</comment>
+ <comment xml:lang="be">звесткі пра аўтараў</comment>
<sub-class-of type="text/plain"/>
<glob pattern="CREDITS"/>
</mime-type>
@@ -35138,12 +35535,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">C 源碼</comment>
<comment xml:lang="zh_CN">C 源代码</comment>
<comment xml:lang="vi">Mã nguồn C</comment>
- <comment xml:lang="uk">вихідний код мовою C</comment>
+ <comment xml:lang="uk">початковий код мовою C</comment>
<comment xml:lang="tr">C kaynak kodu</comment>
<comment xml:lang="sv">C-källkod</comment>
<comment xml:lang="sr">Ц изворни ко̂д</comment>
- <comment xml:lang="sq">Kod burues C</comment>
+ <comment xml:lang="sq">kod burim C</comment>
<comment xml:lang="sl">Datoteka izvorne kode C</comment>
+ <comment xml:lang="si">C මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód jazyka C</comment>
<comment xml:lang="ru">Исходный код C</comment>
<comment xml:lang="ro">Cod sursă C</comment>
@@ -35162,6 +35560,7 @@ command to generate the output files.
<comment xml:lang="ka">C-ის საწყისი კოდი</comment>
<comment xml:lang="ja">C ソースコード</comment>
<comment xml:lang="it">Codice sorgente C</comment>
+ <comment xml:lang="is">C frumkóði</comment>
<comment xml:lang="id">Kode sumber C</comment>
<comment xml:lang="ia">Codice-fonte C</comment>
<comment xml:lang="hu">C-forráskód</comment>
@@ -35184,6 +35583,7 @@ command to generate the output files.
<comment xml:lang="ca">codi font en C</comment>
<comment xml:lang="bg">Изходен код — C</comment>
<comment xml:lang="be@latin">Kryničny kod C</comment>
+ <comment xml:lang="be">зыходны код C</comment>
<comment xml:lang="ar">شفرة مصدر سي</comment>
<comment xml:lang="af">C-bronkode</comment>
<sub-class-of type="text/plain"/>
@@ -35200,12 +35600,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">C# 源碼</comment>
<comment xml:lang="zh_CN">C# 源代码</comment>
<comment xml:lang="vi">Mã nguồn C#</comment>
- <comment xml:lang="uk">вихідний код мовою C#</comment>
+ <comment xml:lang="uk">початковий код мовою C#</comment>
<comment xml:lang="tr">C# kaynak kodu</comment>
<comment xml:lang="sv">C#-källkod</comment>
<comment xml:lang="sr">Ц# изворни ко̂д</comment>
- <comment xml:lang="sq">Kod burues C#</comment>
+ <comment xml:lang="sq">kod burim C#</comment>
<comment xml:lang="sl">Datoteka izvorne kode C#</comment>
+ <comment xml:lang="si">C# මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód jazyka C#</comment>
<comment xml:lang="ru">Исходный код C#</comment>
<comment xml:lang="ro">Cod sursă C#</comment>
@@ -35224,6 +35625,7 @@ command to generate the output files.
<comment xml:lang="ka">C#-ის საწყისი კოდი</comment>
<comment xml:lang="ja">C# ソースコード</comment>
<comment xml:lang="it">Codice sorgente C#</comment>
+ <comment xml:lang="is">C# frumkóði</comment>
<comment xml:lang="id">Kode sumber C#</comment>
<comment xml:lang="ia">Codice-fonte C#</comment>
<comment xml:lang="hu">C#-forráskód</comment>
@@ -35246,6 +35648,7 @@ command to generate the output files.
<comment xml:lang="ca">codi font en C#</comment>
<comment xml:lang="bg">Изходен код — C#</comment>
<comment xml:lang="be@latin">Kryničny kod C#</comment>
+ <comment xml:lang="be">зыходны код C#</comment>
<comment xml:lang="ar">شفرة مصدر سي#</comment>
<comment xml:lang="af">C#-bronkode</comment>
<sub-class-of type="text/x-csrc"/>
@@ -35256,12 +35659,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">Vala 源碼</comment>
<comment xml:lang="zh_CN">Vala 源代码</comment>
<comment xml:lang="vi">Mã nguồn Vala</comment>
- <comment xml:lang="uk">вихідний код мовою Vala</comment>
+ <comment xml:lang="uk">початковий код мовою Vala</comment>
<comment xml:lang="tr">Vala kaynak kodu</comment>
<comment xml:lang="sv">Vala-källkod</comment>
<comment xml:lang="sr">Вала изворни ко̂д</comment>
- <comment xml:lang="sq">Kod burues Vala</comment>
+ <comment xml:lang="sq">kod burim Vala</comment>
<comment xml:lang="sl">Datoteka izvorne kode Vala</comment>
+ <comment xml:lang="si">වාල මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód Vala</comment>
<comment xml:lang="ru">Исходный код Vala</comment>
<comment xml:lang="ro">Cod sursă Vala</comment>
@@ -35278,6 +35682,7 @@ command to generate the output files.
<comment xml:lang="kk">Vala бастапқы коды</comment>
<comment xml:lang="ja">Vala ソースコード</comment>
<comment xml:lang="it">Codice sorgente Vala</comment>
+ <comment xml:lang="is">Vala frumkóði</comment>
<comment xml:lang="id">Kode sumber Vala</comment>
<comment xml:lang="ia">Codice-fonte Vala</comment>
<comment xml:lang="hu">Vala forráskód</comment>
@@ -35300,6 +35705,7 @@ command to generate the output files.
<comment xml:lang="ca">codi font en Vala</comment>
<comment xml:lang="bg">Изходен код — Vala</comment>
<comment xml:lang="be@latin">Kryničny kod Vala</comment>
+ <comment xml:lang="be">зыходны код Vala</comment>
<comment xml:lang="ar">شفرة مصدر Vala</comment>
<comment xml:lang="af">Vala-bronkode</comment>
<sub-class-of type="text/x-csrc"/>
@@ -35310,24 +35716,27 @@ command to generate the output files.
<comment>OOC source code</comment>
<comment xml:lang="zh_TW">OOC 源碼</comment>
<comment xml:lang="zh_CN">OOC 源代码</comment>
- <comment xml:lang="uk">вихідний код мовою OOC</comment>
+ <comment xml:lang="uk">початковий код мовою OOC</comment>
<comment xml:lang="tr">OOC kaynak kodu</comment>
<comment xml:lang="sv">OOC-källkod</comment>
<comment xml:lang="sr">ООЦ изворни ко̂д</comment>
+ <comment xml:lang="sq">kod burim OOC</comment>
<comment xml:lang="sl">Izvorna koda OOC</comment>
+ <comment xml:lang="si">OOC මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód OOC</comment>
<comment xml:lang="ru">Исходный код OOC</comment>
<comment xml:lang="pt_BR">Código-fonte OOC</comment>
<comment xml:lang="pt">código origem OOC</comment>
<comment xml:lang="pl">Kod źródłowy OOC</comment>
<comment xml:lang="oc">font còde OOC</comment>
- <comment xml:lang="nl">OOC broncode</comment>
+ <comment xml:lang="nl">OOC-broncode</comment>
<comment xml:lang="lv">OOC pirmkods</comment>
<comment xml:lang="ko">OOC 소스 코드</comment>
<comment xml:lang="kk">OOC бастапқы коды</comment>
<comment xml:lang="ka">OOC-ის საწყისი კოდი</comment>
<comment xml:lang="ja">OOC ソースコード</comment>
<comment xml:lang="it">Codice sorgente OOC</comment>
+ <comment xml:lang="is">OOC frumkóði</comment>
<comment xml:lang="id">Kode sumber OOC</comment>
<comment xml:lang="ia">Codice-fonte OCC</comment>
<comment xml:lang="hu">OOC forráskód</comment>
@@ -35348,6 +35757,7 @@ command to generate the output files.
<comment xml:lang="cs">zdrojový kód OOC</comment>
<comment xml:lang="ca">codi font en OOC</comment>
<comment xml:lang="bg">Изходен код — OOC</comment>
+ <comment xml:lang="be">зыходны код OOC</comment>
<comment xml:lang="ar">شفرة مصدر OOC</comment>
<comment xml:lang="af">OOC-bronkode</comment>
<acronym>OOC</acronym>
@@ -35364,8 +35774,9 @@ command to generate the output files.
<comment xml:lang="tr">DCL betiği</comment>
<comment xml:lang="sv">DCL-skript</comment>
<comment xml:lang="sr">ДЦЛ скрипта</comment>
- <comment xml:lang="sq">Script DCL</comment>
+ <comment xml:lang="sq">programth DCL</comment>
<comment xml:lang="sl">Skriptna datoteka DCL</comment>
+ <comment xml:lang="si">DCL පිටපත</comment>
<comment xml:lang="sk">Skript DCL</comment>
<comment xml:lang="ru">Сценарий DCL</comment>
<comment xml:lang="ro">Script DCL</comment>
@@ -35384,6 +35795,7 @@ command to generate the output files.
<comment xml:lang="ka">DCL სცენარი</comment>
<comment xml:lang="ja">DCL スクリプト</comment>
<comment xml:lang="it">Script DCL</comment>
+ <comment xml:lang="is">DCL skrifta</comment>
<comment xml:lang="id">Skrip DCL</comment>
<comment xml:lang="ia">Script DCL</comment>
<comment xml:lang="hu">DCL-parancsfájl</comment>
@@ -35407,6 +35819,7 @@ command to generate the output files.
<comment xml:lang="ca">script DCL</comment>
<comment xml:lang="bg">Скрипт — DCL</comment>
<comment xml:lang="be@latin">Skrypt DCL</comment>
+ <comment xml:lang="be">скрыпт DCL</comment>
<comment xml:lang="az">DCL skripti</comment>
<comment xml:lang="ar">سكربت DCL</comment>
<comment xml:lang="af">DCL-skrip</comment>
@@ -35424,8 +35837,9 @@ command to generate the output files.
<comment xml:lang="tr">DSSSL belgesi</comment>
<comment xml:lang="sv">DSSSL-dokument</comment>
<comment xml:lang="sr">ДСССЛ документ</comment>
- <comment xml:lang="sq">Dokument DSSSL</comment>
+ <comment xml:lang="sq">dokument DSSSL</comment>
<comment xml:lang="sl">Dokument DSSSL</comment>
+ <comment xml:lang="si">DSSSL ලේඛනය</comment>
<comment xml:lang="sk">Dokument DSSSL</comment>
<comment xml:lang="ru">Документ DSSSL</comment>
<comment xml:lang="ro">Document DSSSL</comment>
@@ -35444,6 +35858,7 @@ command to generate the output files.
<comment xml:lang="ka">DSSSL დოკუმენტი</comment>
<comment xml:lang="ja">DSSSL ドキュメント</comment>
<comment xml:lang="it">Documento DSSSL</comment>
+ <comment xml:lang="is">DSSSL skjal</comment>
<comment xml:lang="id">Dokumen DSSSL</comment>
<comment xml:lang="ia">Documento DSSSL</comment>
<comment xml:lang="hu">DSSSL-dokumentum</comment>
@@ -35467,6 +35882,7 @@ command to generate the output files.
<comment xml:lang="ca">document DSSSL</comment>
<comment xml:lang="bg">Документ — DSSSL</comment>
<comment xml:lang="be@latin">Dakument DSSSL</comment>
+ <comment xml:lang="be">дакумент DSSSL</comment>
<comment xml:lang="az">DSSSL sənədi</comment>
<comment xml:lang="ast">Documentu DSSSL</comment>
<comment xml:lang="ar">مستند DSSSL</comment>
@@ -35481,12 +35897,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">D 源碼</comment>
<comment xml:lang="zh_CN">D 源代码</comment>
<comment xml:lang="vi">Mã nguồn D</comment>
- <comment xml:lang="uk">вихідний код мовою D</comment>
+ <comment xml:lang="uk">початковий код мовою D</comment>
<comment xml:lang="tr">D kaynak kodu</comment>
<comment xml:lang="sv">D-källkod</comment>
<comment xml:lang="sr">Д изворни ко̂д</comment>
- <comment xml:lang="sq">Kod burues D</comment>
+ <comment xml:lang="sq">kod burim D</comment>
<comment xml:lang="sl">Datoteka izvorne kode D</comment>
+ <comment xml:lang="si">D මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód jazyka D</comment>
<comment xml:lang="ru">Исходный код D</comment>
<comment xml:lang="ro">Cod sursă D</comment>
@@ -35504,6 +35921,7 @@ command to generate the output files.
<comment xml:lang="ka">D-ის საწყისი კოდი</comment>
<comment xml:lang="ja">D ソースコード</comment>
<comment xml:lang="it">Codice sorgente D</comment>
+ <comment xml:lang="is">D frumkóði</comment>
<comment xml:lang="id">Kode sumber D</comment>
<comment xml:lang="ia">Codice-fonte D</comment>
<comment xml:lang="hu">D-forráskód</comment>
@@ -35526,6 +35944,7 @@ command to generate the output files.
<comment xml:lang="ca">codi font en D</comment>
<comment xml:lang="bg">Изходен код — D</comment>
<comment xml:lang="be@latin">Kryničny kod D</comment>
+ <comment xml:lang="be">зыходны код D</comment>
<comment xml:lang="ar">شفرة مصدر D</comment>
<comment xml:lang="af">D-bronkode</comment>
<sub-class-of type="text/x-csrc"/>
@@ -35541,8 +35960,9 @@ command to generate the output files.
<comment xml:lang="tr">DTD dosyası</comment>
<comment xml:lang="sv">DTD-fil</comment>
<comment xml:lang="sr">ДТД датотека</comment>
- <comment xml:lang="sq">File DTD</comment>
+ <comment xml:lang="sq">kartelë DTD</comment>
<comment xml:lang="sl">Datoteka DTD</comment>
+ <comment xml:lang="si">DTD ගොනුව</comment>
<comment xml:lang="sk">Súbor DTD</comment>
<comment xml:lang="ru">Файл DTD</comment>
<comment xml:lang="ro">Fișier DTD</comment>
@@ -35560,6 +35980,7 @@ command to generate the output files.
<comment xml:lang="ka">DTD ფაილი</comment>
<comment xml:lang="ja">DTD ファイル</comment>
<comment xml:lang="it">File DTD</comment>
+ <comment xml:lang="is">DTD-skrá</comment>
<comment xml:lang="id">Berkas DTD</comment>
<comment xml:lang="ia">File DTD</comment>
<comment xml:lang="hu">DTD fájl</comment>
@@ -35582,6 +36003,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer DTD</comment>
<comment xml:lang="bg">Документ — DTD</comment>
<comment xml:lang="be@latin">Fajł DTD</comment>
+ <comment xml:lang="be">файл DTD</comment>
<comment xml:lang="ar">ملف DTD</comment>
<comment xml:lang="af">DTD-lêer</comment>
<acronym>DTD</acronym>
@@ -35596,12 +36018,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">Eiffel 源碼</comment>
<comment xml:lang="zh_CN">Eiffel 源代码</comment>
<comment xml:lang="vi">Mã nguồn Eiffel</comment>
- <comment xml:lang="uk">вихідний код мовою Eiffel</comment>
+ <comment xml:lang="uk">початковий код мовою Eiffel</comment>
<comment xml:lang="tr">Eiffel kaynak kodu</comment>
<comment xml:lang="sv">Eiffel-källkod</comment>
<comment xml:lang="sr">Ајфел изворни ко̂д</comment>
- <comment xml:lang="sq">Kod burues Eiffel</comment>
+ <comment xml:lang="sq">kod burim Eiffel</comment>
<comment xml:lang="sl">Datoteka izvorne kode Eiffel</comment>
+ <comment xml:lang="si">අයිෆල් මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód Eiffel</comment>
<comment xml:lang="ru">Исходный код Eiffel</comment>
<comment xml:lang="ro">Cod sursă Eiffel</comment>
@@ -35619,6 +36042,7 @@ command to generate the output files.
<comment xml:lang="ka">Eiffel-ის საწყისი კოდი</comment>
<comment xml:lang="ja">Eiffel ソースコード</comment>
<comment xml:lang="it">Codice sorgente Eiffel</comment>
+ <comment xml:lang="is">Eiffel frumkóði</comment>
<comment xml:lang="id">Kode sumber Eiffel</comment>
<comment xml:lang="ia">Codice-fonte Eiffel</comment>
<comment xml:lang="hu">Eiffel forráskód</comment>
@@ -35641,6 +36065,7 @@ command to generate the output files.
<comment xml:lang="ca">codi font en Eiffel</comment>
<comment xml:lang="bg">Изходен код — Eiffel</comment>
<comment xml:lang="be@latin">Kryničny kod Eiffel</comment>
+ <comment xml:lang="be">зыходны код Eiffel</comment>
<comment xml:lang="ar">شفرة مصدر Eiffel</comment>
<comment xml:lang="af">Eiffel-bronkode</comment>
<sub-class-of type="text/plain"/>
@@ -35652,12 +36077,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">Emacs Lisp 源碼</comment>
<comment xml:lang="zh_CN">Emacs Lisp 源代码</comment>
<comment xml:lang="vi">Mã nguồn Lisp Emacs</comment>
- <comment xml:lang="uk">вихідний код мовою Emacs Lisp</comment>
+ <comment xml:lang="uk">початковий код мовою Emacs Lisp</comment>
<comment xml:lang="tr">Emacs Lisp kaynak kodu</comment>
<comment xml:lang="sv">Emacs Lisp-källkod</comment>
<comment xml:lang="sr">Емакс Лисп изворни ко̂д</comment>
- <comment xml:lang="sq">Kod burues Emacs Lisp</comment>
+ <comment xml:lang="sq">kod burim Emacs Lisp</comment>
<comment xml:lang="sl">Datoteka izvorne kode Emacs Lisp</comment>
+ <comment xml:lang="si">Emacs Lisp මූලාශ්‍ර කේතය</comment>
<comment xml:lang="sk">Zdrojový kód Emacs Lisp</comment>
<comment xml:lang="ru">Исходный код Emacs Lisp</comment>
<comment xml:lang="ro">Cod sursă Emacs Lisp</comment>
@@ -35676,6 +36102,7 @@ command to generate the output files.
<comment xml:lang="ka">Emacs-ის Lisp საწყისი კოდი</comment>
<comment xml:lang="ja">Emacs Lisp ソースコード</comment>
<comment xml:lang="it">Codice sorgente Emacs Lisp</comment>
+ <comment xml:lang="is">Emacs Lisp frumkóði</comment>
<comment xml:lang="id">Kode sumber Emacs Lisp</comment>
<comment xml:lang="ia">Codice-fonte Lisp de Emacs</comment>
<comment xml:lang="hu">Emacs Lisp-forráskód</comment>
@@ -35699,6 +36126,7 @@ command to generate the output files.
<comment xml:lang="ca">codi font en Emacs Lisp</comment>
<comment xml:lang="bg">Изходен код — Emacs Lisp</comment>
<comment xml:lang="be@latin">Kryničny kod Emacs Lisp</comment>
+ <comment xml:lang="be">зыходны код Emacs Lisp</comment>
<comment xml:lang="az">Emacs Lisp mənbə kodu</comment>
<comment xml:lang="ar">شفرة مصدر Emacs Lisp</comment>
<comment xml:lang="af">Emacs Lisp-bronkode</comment>
@@ -35711,6 +36139,31 @@ command to generate the output files.
</mime-type>
<mime-type type="text/x-elixir">
<comment>Elixir source code</comment>
+ <comment xml:lang="zh_TW">Elixir 原始碼</comment>
+ <comment xml:lang="zh_CN">Elixir 源代码</comment>
+ <comment xml:lang="uk">початковий код мовою Elixir</comment>
+ <comment xml:lang="tr">Elixir kaynak kodu</comment>
+ <comment xml:lang="sv">Elixir-källkod</comment>
+ <comment xml:lang="sl">Izvorna koda Elixir</comment>
+ <comment xml:lang="si">Elixir මූල කේතය</comment>
+ <comment xml:lang="ru">Исходный код Elixir</comment>
+ <comment xml:lang="pt_BR">Código-fonte Elixir</comment>
+ <comment xml:lang="pl">Kod źródłowy Elixir</comment>
+ <comment xml:lang="nl">Elixir-broncode</comment>
+ <comment xml:lang="ko">Elixir 소스 코드</comment>
+ <comment xml:lang="kk">Elixir бастапқы коды</comment>
+ <comment xml:lang="ja">Elixir ソースコード</comment>
+ <comment xml:lang="it">Codice sorgente Elixir</comment>
+ <comment xml:lang="hr">Elixir izvorni kôd</comment>
+ <comment xml:lang="he">קוד מקור ב־Elixir</comment>
+ <comment xml:lang="gl">Código de fonte Elixir</comment>
+ <comment xml:lang="fi">Elixir-lähdekoodi</comment>
+ <comment xml:lang="eu">Elixir iturburu-kodea</comment>
+ <comment xml:lang="es">código fuente Elixir</comment>
+ <comment xml:lang="en_GB">Elixir source code</comment>
+ <comment xml:lang="de">Elixir-Quelltext</comment>
+ <comment xml:lang="be">зыходны код Elixir</comment>
+ <comment xml:lang="ar">شفرة مصدر Elixir</comment>
<sub-class-of type="text/plain"/>
<glob pattern="*.ex"/>
<glob pattern="*.exs"/>
@@ -35720,12 +36173,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">Erlang 源碼</comment>
<comment xml:lang="zh_CN">Erlang 源代码</comment>
<comment xml:lang="vi">Mã nguồn Erlang</comment>
- <comment xml:lang="uk">вихідний код мовою Erlang</comment>
+ <comment xml:lang="uk">початковий код мовою Erlang</comment>
<comment xml:lang="tr">Erlang kaynak kodu</comment>
<comment xml:lang="sv">Erlang-källkod</comment>
<comment xml:lang="sr">Ерланг изворни ко̂д</comment>
- <comment xml:lang="sq">Kod burues Erlang</comment>
+ <comment xml:lang="sq">kod burim Erlang</comment>
<comment xml:lang="sl">Datoteka izvorne kode Erlang</comment>
+ <comment xml:lang="si">Erlang මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód Erlang</comment>
<comment xml:lang="ru">Исходный код Erlang</comment>
<comment xml:lang="ro">Cod sursă Erlang</comment>
@@ -35743,6 +36197,7 @@ command to generate the output files.
<comment xml:lang="ka">Erlang-ის საწყისი კოდი</comment>
<comment xml:lang="ja">Erlang ソースコード</comment>
<comment xml:lang="it">Codice sorgente Erlang</comment>
+ <comment xml:lang="is">Erlang frumkóði</comment>
<comment xml:lang="id">Kode sumber Erlang</comment>
<comment xml:lang="ia">Codice-fonte Erlang</comment>
<comment xml:lang="hu">Erlang forráskód</comment>
@@ -35765,6 +36220,7 @@ command to generate the output files.
<comment xml:lang="ca">codi font en Erlang</comment>
<comment xml:lang="bg">Изходен код — Erlang</comment>
<comment xml:lang="be@latin">Kryničny kod Erlang</comment>
+ <comment xml:lang="be">зыходны код Erlang</comment>
<comment xml:lang="ar">شفرة مصدر Erlang</comment>
<comment xml:lang="af">Erlang-bronkode</comment>
<sub-class-of type="text/plain"/>
@@ -35775,12 +36231,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">Fortran 源碼</comment>
<comment xml:lang="zh_CN">Fortran 源代码</comment>
<comment xml:lang="vi">Mã nguồn Fortran</comment>
- <comment xml:lang="uk">вихідний код мовою Fortran</comment>
+ <comment xml:lang="uk">початковий код мовою Fortran</comment>
<comment xml:lang="tr">Fortran kaynak kodu</comment>
<comment xml:lang="sv">Fortran-källkod</comment>
<comment xml:lang="sr">Фортран изворни ко̂д</comment>
- <comment xml:lang="sq">Kod burues Fortran</comment>
+ <comment xml:lang="sq">kod burim Fortran</comment>
<comment xml:lang="sl">Datoteka izvorne kode Fortran</comment>
+ <comment xml:lang="si">Fortran මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód Fortran</comment>
<comment xml:lang="ru">Исходный код Fortran</comment>
<comment xml:lang="ro">Cod sursă Fortran</comment>
@@ -35799,6 +36256,7 @@ command to generate the output files.
<comment xml:lang="ka">Fortran-ის საწყისი კოდი</comment>
<comment xml:lang="ja">Fortran ソースコード</comment>
<comment xml:lang="it">Codice sorgente Fortran</comment>
+ <comment xml:lang="is">Fortran frumkóði</comment>
<comment xml:lang="id">Kode sumber Fortran</comment>
<comment xml:lang="ia">Codice-fonte Fortran</comment>
<comment xml:lang="hu">Fortran-forráskód</comment>
@@ -35822,6 +36280,7 @@ command to generate the output files.
<comment xml:lang="ca">codi font en Fortran</comment>
<comment xml:lang="bg">Изходен код — Fortran</comment>
<comment xml:lang="be@latin">Kryničny kod Fortran</comment>
+ <comment xml:lang="be">зыходны код Fortran</comment>
<comment xml:lang="az">Fortran mənbə kodu</comment>
<comment xml:lang="ar">شفرة مصدر Fortran</comment>
<comment xml:lang="af">Fortran-bronkode</comment>
@@ -35835,26 +36294,31 @@ command to generate the output files.
<comment>Genie source code</comment>
<comment xml:lang="zh_TW">Genie 源碼</comment>
<comment xml:lang="zh_CN">Genie 源代码</comment>
- <comment xml:lang="uk">вихідний код мовою Genie</comment>
+ <comment xml:lang="uk">початковий код мовою Genie</comment>
<comment xml:lang="tr">Genie kaynak kodu</comment>
<comment xml:lang="sv">Genie-källkod</comment>
<comment xml:lang="sr">Гение изворни ко̂д</comment>
+ <comment xml:lang="sq">kod burim Genie</comment>
<comment xml:lang="sl">Izvorna koda Genie</comment>
+ <comment xml:lang="si">Genie මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód Genie</comment>
<comment xml:lang="ru">Исходный код Genie</comment>
<comment xml:lang="pt_BR">Código-fonte Genie</comment>
<comment xml:lang="pt">código origem Genie</comment>
<comment xml:lang="pl">Kod źródłowy Genie</comment>
<comment xml:lang="oc">còde font Genie</comment>
+ <comment xml:lang="nl">Genie-broncode</comment>
<comment xml:lang="ko">Genie 소스 코드</comment>
<comment xml:lang="kk">Genie бастапқы коды</comment>
<comment xml:lang="ja">Genie ソースコード</comment>
<comment xml:lang="it">Codice sorgente Genie</comment>
+ <comment xml:lang="is">Genie frumkóði</comment>
<comment xml:lang="id">Kode sumber Genie</comment>
<comment xml:lang="ia">Codice-fonte Genie</comment>
<comment xml:lang="hu">Genie forráskód</comment>
<comment xml:lang="hr">Genie izvorni kôd</comment>
<comment xml:lang="he">קוד מקור של Genie</comment>
+ <comment xml:lang="gl">Código de fonte Genie</comment>
<comment xml:lang="ga">cód foinseach Genie</comment>
<comment xml:lang="fur">codiç sorzint Genie</comment>
<comment xml:lang="fr">code source Genie</comment>
@@ -35868,6 +36332,7 @@ command to generate the output files.
<comment xml:lang="cs">zdrojový kód v jazyce Genie</comment>
<comment xml:lang="ca">codi font en Genie</comment>
<comment xml:lang="bg">Изходен код — Genie</comment>
+ <comment xml:lang="be">зыходны код Genie</comment>
<comment xml:lang="ar">شفرة مصدر Genie</comment>
<comment xml:lang="af">Genie-bronkode</comment>
<sub-class-of type="text/plain"/>
@@ -35875,116 +36340,38 @@ command to generate the output files.
<generic-icon name="text-x-generic"/>
</mime-type>
<mime-type type="text/x-gettext-translation">
- <comment>translation file</comment>
- <comment xml:lang="zh_TW">翻譯檔</comment>
- <comment xml:lang="zh_CN">翻译文件</comment>
- <comment xml:lang="vi">tập tin dịch</comment>
- <comment xml:lang="uk">файл перекладу</comment>
- <comment xml:lang="tr">çeviri dosyası</comment>
- <comment xml:lang="sv">översättningsfil</comment>
- <comment xml:lang="sr">датотека превода</comment>
- <comment xml:lang="sq">File përkthimesh</comment>
- <comment xml:lang="sl">datoteka prevoda programa</comment>
- <comment xml:lang="sk">Súbor prekladu</comment>
- <comment xml:lang="ru">Файл переводов</comment>
- <comment xml:lang="ro">fișier traducere</comment>
+ <comment>Translation file</comment>
+ <comment xml:lang="uk">Файл перекладу</comment>
+ <comment xml:lang="sv">Översättningsfil</comment>
+ <comment xml:lang="ru">Файл перевода</comment>
<comment xml:lang="pt_BR">Arquivo de tradução</comment>
- <comment xml:lang="pt">ficheiro de tradução</comment>
<comment xml:lang="pl">Plik tłumaczenia</comment>
- <comment xml:lang="oc">fichièr de traduccion</comment>
- <comment xml:lang="nn">omsetjingsfil</comment>
- <comment xml:lang="nl">vertalingsbestand</comment>
- <comment xml:lang="nb">oversettelsesfil</comment>
- <comment xml:lang="lv">tulkošanas datne</comment>
- <comment xml:lang="lt">vertimo failas</comment>
- <comment xml:lang="ko">번역 파일</comment>
- <comment xml:lang="kk">аудармалар файлы</comment>
- <comment xml:lang="ka">თარგმნის ფაილი</comment>
- <comment xml:lang="ja">翻訳ファイル</comment>
+ <comment xml:lang="ja">翻訳文書</comment>
<comment xml:lang="it">File traduzione</comment>
- <comment xml:lang="id">berkas terjemahan</comment>
- <comment xml:lang="ia">File de traduction</comment>
- <comment xml:lang="hu">fordítási fájl</comment>
- <comment xml:lang="hr">Datoteka prijevoda</comment>
- <comment xml:lang="he">קובץ תרגום</comment>
- <comment xml:lang="gl">ficheiro de tradución</comment>
- <comment xml:lang="ga">comhad aistriúcháin</comment>
- <comment xml:lang="fur">file di traduzion</comment>
- <comment xml:lang="fr">fichier de traduction</comment>
- <comment xml:lang="fo">týðingarfíla</comment>
- <comment xml:lang="fi">käännöstiedosto</comment>
- <comment xml:lang="eu">itzulpen-fitxategia</comment>
+ <comment xml:lang="gl">Ficheiro de traducións</comment>
+ <comment xml:lang="eu">Itzulpen-fitxategia</comment>
<comment xml:lang="es">archivo de traducción</comment>
- <comment xml:lang="eo">tradukad-dosiero</comment>
- <comment xml:lang="en_GB">translation file</comment>
- <comment xml:lang="el">Αρχείο μετάφρασης</comment>
<comment xml:lang="de">Übersetzungsdatei</comment>
- <comment xml:lang="da">oversættelsesfil</comment>
- <comment xml:lang="cs">soubor překladu</comment>
- <comment xml:lang="ca">fitxer de traducció</comment>
- <comment xml:lang="bg">Превод</comment>
- <comment xml:lang="be@latin">fajł pierakładu</comment>
- <comment xml:lang="ast">ficheru de traducción</comment>
- <comment xml:lang="ar">ملف ترجمة</comment>
- <comment xml:lang="af">vertaallêer</comment>
+ <comment xml:lang="be">файл перакладу</comment>
<sub-class-of type="text/plain"/>
<glob pattern="*.po"/>
<alias type="text/x-po"/>
<alias type="application/x-gettext"/>
</mime-type>
<mime-type type="text/x-gettext-translation-template">
- <comment>translation template</comment>
- <comment xml:lang="zh_TW">翻譯模版</comment>
- <comment xml:lang="zh_CN">翻译模板</comment>
- <comment xml:lang="vi">mẫu dịch</comment>
+ <comment>Translation template</comment>
<comment xml:lang="uk">шаблон перекладу</comment>
- <comment xml:lang="tr">çeviri şablonu</comment>
- <comment xml:lang="sv">översättningsmall</comment>
- <comment xml:lang="sr">шаблон превода</comment>
- <comment xml:lang="sq">Model përkthimesh</comment>
- <comment xml:lang="sl">predloga datoteke prevoda programa</comment>
- <comment xml:lang="sk">Šablóna prekladu</comment>
- <comment xml:lang="ru">Шаблон переводов</comment>
- <comment xml:lang="ro">șablon de traducere</comment>
+ <comment xml:lang="sv">Översättningsmall</comment>
+ <comment xml:lang="ru">Шаблон перевода</comment>
<comment xml:lang="pt_BR">Modelo de tradução</comment>
- <comment xml:lang="pt">modelo de tradução</comment>
<comment xml:lang="pl">Szablon tłumaczenia</comment>
- <comment xml:lang="oc">modèl de traduccion</comment>
- <comment xml:lang="nn">omsetjingsmal</comment>
- <comment xml:lang="nl">vertalingssjabloon</comment>
- <comment xml:lang="nb">mal for oversetting</comment>
- <comment xml:lang="lv">tulkošanas veidne</comment>
- <comment xml:lang="lt">vertimo šablonas</comment>
- <comment xml:lang="ko">메시지 번역 서식</comment>
- <comment xml:lang="kk">аудармалар үлгісі</comment>
- <comment xml:lang="ka">თარგმნის შაბლონი</comment>
- <comment xml:lang="ja">翻訳テンプレート</comment>
- <comment xml:lang="it">Modello di traduzione</comment>
- <comment xml:lang="id">templat terjemahan</comment>
- <comment xml:lang="ia">Patrono de traduction</comment>
- <comment xml:lang="hu">fordítási sablon</comment>
- <comment xml:lang="hr">Predložak prijevoda</comment>
- <comment xml:lang="he">תבנית תרגום</comment>
- <comment xml:lang="gl">plantilla de tradución</comment>
- <comment xml:lang="ga">teimpléad aistriúcháin</comment>
- <comment xml:lang="fur">model di traduzion</comment>
- <comment xml:lang="fr">modèle de traduction</comment>
- <comment xml:lang="fo">týðingarformur</comment>
- <comment xml:lang="fi">käännösmalli</comment>
- <comment xml:lang="eu">itzulpenen txantiloia</comment>
- <comment xml:lang="es">plantilla de traducción</comment>
- <comment xml:lang="eo">tradukad-ŝablono</comment>
- <comment xml:lang="en_GB">translation template</comment>
- <comment xml:lang="el">Πρότυπο μετάφρασης</comment>
+ <comment xml:lang="ja">翻訳雛形</comment>
+ <comment xml:lang="it">Modello traduzione</comment>
+ <comment xml:lang="gl">Modelo de tradución</comment>
+ <comment xml:lang="eu">Itzulpen-txantiloia</comment>
+ <comment xml:lang="es">plantilla de traducciones</comment>
<comment xml:lang="de">Übersetzungsvorlage</comment>
- <comment xml:lang="da">oversættelsesskabelon</comment>
- <comment xml:lang="cs">šablona překladu</comment>
- <comment xml:lang="ca">plantilla de traducció</comment>
- <comment xml:lang="bg">Шаблон за преводи</comment>
- <comment xml:lang="be@latin">šablon dla pierakładu</comment>
- <comment xml:lang="ast">plantía de traducción</comment>
- <comment xml:lang="ar">قالب ترجمة</comment>
- <comment xml:lang="af">vertaalsjabloon</comment>
+ <comment xml:lang="be">шаблон перакладу</comment>
<sub-class-of type="text/plain"/>
<glob pattern="*.pot"/>
<alias type="text/x-pot"/>
@@ -35999,20 +36386,25 @@ command to generate the output files.
<comment xml:lang="uk">документ Gherkin</comment>
<comment xml:lang="tr">Gherkin belgesi</comment>
<comment xml:lang="sv">Gherkin-dokument</comment>
+ <comment xml:lang="sq">dokument Gherkin</comment>
<comment xml:lang="sl">Dokument Gherkin</comment>
+ <comment xml:lang="si">ගර්කින් ලේඛනය</comment>
<comment xml:lang="sk">Dokument Gherkin</comment>
<comment xml:lang="ru">Документ Gherkin</comment>
<comment xml:lang="pt_BR">Documento Gherkin</comment>
<comment xml:lang="pl">Dokument Gherkin</comment>
<comment xml:lang="oc">document Gherkin</comment>
+ <comment xml:lang="nl">Gherkin-document</comment>
<comment xml:lang="ko">게르킨 문서</comment>
<comment xml:lang="kk">Gherkin құжаты</comment>
<comment xml:lang="ja">Gherkin ドキュメント</comment>
<comment xml:lang="it">Documento Gherkin</comment>
+ <comment xml:lang="is">Gherkin skjal</comment>
<comment xml:lang="id">Dokumen Gherkin</comment>
<comment xml:lang="hu">Gherkin dokumentum</comment>
<comment xml:lang="hr">Gherkin dokument</comment>
<comment xml:lang="he">מסמך Gherkin</comment>
+ <comment xml:lang="gl">Documento Gherkin</comment>
<comment xml:lang="fr">document Gherkin</comment>
<comment xml:lang="fi">Gherkin-asiakirja</comment>
<comment xml:lang="eu">Gherkin dokumentua</comment>
@@ -36022,6 +36414,7 @@ command to generate the output files.
<comment xml:lang="da">Gherkin-dokument</comment>
<comment xml:lang="ca">document Gherkin</comment>
<comment xml:lang="bg">Документ — Gherkin</comment>
+ <comment xml:lang="be">дакумент Gherkin</comment>
<comment xml:lang="ar">مستند Gherkin</comment>
<sub-class-of type="text/plain"/>
<glob pattern="*.feature"/>
@@ -36035,8 +36428,9 @@ command to generate the output files.
<comment xml:lang="tr">HTML belgesi</comment>
<comment xml:lang="sv">HTML-dokument</comment>
<comment xml:lang="sr">ХТМЛ документ</comment>
- <comment xml:lang="sq">Dokument HTML</comment>
+ <comment xml:lang="sq">dokument HTML</comment>
<comment xml:lang="sl">Dokument HTML</comment>
+ <comment xml:lang="si">HTML ලේඛනය</comment>
<comment xml:lang="sk">Dokument HTML</comment>
<comment xml:lang="ru">Документ HTML</comment>
<comment xml:lang="ro">Document HTML</comment>
@@ -36053,6 +36447,7 @@ command to generate the output files.
<comment xml:lang="kk">HTML құжаты</comment>
<comment xml:lang="ja">HTML ドキュメント</comment>
<comment xml:lang="it">Documento HTML</comment>
+ <comment xml:lang="is">HTML skjal</comment>
<comment xml:lang="id">Dokumen HTML</comment>
<comment xml:lang="ia">Documento HTML</comment>
<comment xml:lang="hu">HTML dokumentum</comment>
@@ -36075,6 +36470,7 @@ command to generate the output files.
<comment xml:lang="ca">document HTML</comment>
<comment xml:lang="bg">Документ — HTML</comment>
<comment xml:lang="be@latin">Dakument HTML</comment>
+ <comment xml:lang="be">дакумент HTML</comment>
<comment xml:lang="ast">Documentu HTML</comment>
<comment xml:lang="ar">مستند HTML</comment>
<comment xml:lang="af">HTML-dokument</comment>
@@ -36105,33 +36501,54 @@ command to generate the output files.
<glob pattern="*.html" weight="80"/>
<glob pattern="*.htm" weight="80"/>
</mime-type>
+ <mime-type type="text/x-component">
+ <comment>HTML component</comment>
+ <comment xml:lang="uk">компонент HTML</comment>
+ <comment xml:lang="sv">HTML-komponent</comment>
+ <comment xml:lang="ru">Компонент HTML</comment>
+ <comment xml:lang="pl">Składnik HTML</comment>
+ <comment xml:lang="es">componente de HTML</comment>
+ <comment xml:lang="de">HTML-Komponente</comment>
+ <acronym>HTML</acronym>
+ <expanded-acronym>HyperText Markup Language</expanded-acronym>
+ <sub-class-of type="application/xml"/>
+ <generic-icon name="text-html"/>
+ <glob pattern="*.htc"/>
+ <root-XML namespaceURI="urn:HTMLComponent" localName="PUBLIC"/>
+ </mime-type>
<mime-type type="text/cache-manifest">
<comment>Web application cache file</comment>
<comment xml:lang="zh_CN">Web 应用缓存文件</comment>
<comment xml:lang="uk">файл кешу вебпрограми</comment>
<comment xml:lang="tr">Web uygulama önbellek dosyası</comment>
<comment xml:lang="sv">Webbapplikationscachefil</comment>
+ <comment xml:lang="sq">kartelë fshehtine aplikacioni Web</comment>
+ <comment xml:lang="si">වෙබ් යෙදුම් හැඹිලි ගොනුව</comment>
<comment xml:lang="ru">Файл кэша веб-приложения</comment>
<comment xml:lang="pt_BR">Arquivo de cache de aplicativo Web</comment>
<comment xml:lang="pl">Plik pamięci podręcznej aplikacji WWW</comment>
<comment xml:lang="oc">fichièr d'escondedor aplicacion Web</comment>
+ <comment xml:lang="nl">Cachebestand van webtoepassing</comment>
<comment xml:lang="ko">웹 애플리케이션 캐시 파일</comment>
<comment xml:lang="kk">Веб қолданбасының кэш файлы</comment>
<comment xml:lang="ja">Web アプリケーションキャッシュファイル</comment>
<comment xml:lang="it">File cache applicazione Web</comment>
+ <comment xml:lang="is">skyndiminnisskrá vefforrits</comment>
<comment xml:lang="id">Berkas singgahan aplikasi web</comment>
<comment xml:lang="hu">Webalkalmazás gyorsítótárfájl</comment>
<comment xml:lang="hr"> Web aplikacija datoteka predmemorije </comment>
<comment xml:lang="he">קובץ מטמון של תוכנית ברשת</comment>
+ <comment xml:lang="gl">Ficheiro de caché de aplicación web</comment>
<comment xml:lang="fr">fichier de cache d'application Web</comment>
<comment xml:lang="fi">Web-sovelluksen välimuistitiedosto</comment>
<comment xml:lang="eu">Web-aplikazio katxe fitxategia</comment>
<comment xml:lang="es">archivo de antememoria de aplicación web</comment>
<comment xml:lang="en_GB">Web application cache file</comment>
- <comment xml:lang="de">Webanwendungscache-Datei</comment>
+ <comment xml:lang="de">Webanwendungs-Zwischenspeicherdatei</comment>
<comment xml:lang="da">Webprogrammellemlagerfil</comment>
<comment xml:lang="ca">fitxer de memòria cau d'aplicació Web</comment>
<comment xml:lang="bg">Кеш — уеб приложение</comment>
+ <comment xml:lang="be">файл кэша вэб-праграмы</comment>
<comment xml:lang="ar">ملف خبيئة تطبيق ويب</comment>
<sub-class-of type="text/plain"/>
<magic>
@@ -36150,13 +36567,17 @@ command to generate the output files.
<comment xml:lang="uk">скорочення вказівника відео Google</comment>
<comment xml:lang="tr">Google Video Pointer kısayolu</comment>
<comment xml:lang="sv">Google Video Pointer-genväg</comment>
+ <comment xml:lang="sq">shkurtore Google Video Pointer</comment>
+ <comment xml:lang="si">Google Video Pointer කෙටිමඟ</comment>
<comment xml:lang="ru">Ссылка Google Video Pointer</comment>
<comment xml:lang="pt_BR">Atalho do Google Video Pointer</comment>
<comment xml:lang="pl">Skrót listy odtwarzania Google Video</comment>
+ <comment xml:lang="nl">Google Video Pointer-snelkoppeling</comment>
<comment xml:lang="ko">구글 동영상 포인터 바로 가기</comment>
<comment xml:lang="kk">Google Video Pointer жарлығы</comment>
<comment xml:lang="ja">Google Video Pointer ショートカット</comment>
<comment xml:lang="it">Scorciatoia Google Video Pointer</comment>
+ <comment xml:lang="is">Google Video Pointer flýtivísun</comment>
<comment xml:lang="id">Pintasan Google Video Pointer</comment>
<comment xml:lang="hu">Google Video Pointer parancsikon</comment>
<comment xml:lang="hr">Google Video pretraživač prečac</comment>
@@ -36166,10 +36587,11 @@ command to generate the output files.
<comment xml:lang="eu">Google Video Pointer lasterbidea</comment>
<comment xml:lang="es">atajo de Google Video Pointer</comment>
<comment xml:lang="en_GB">Google Video Pointer shortcut</comment>
- <comment xml:lang="de">Google-Video-Zeigerverweis</comment>
+ <comment xml:lang="de">Google-Videozeiger-Verweis</comment>
<comment xml:lang="da">Google Video Pointer-genvej</comment>
<comment xml:lang="ca">drecera d'apuntador a vídeo de Google</comment>
<comment xml:lang="bg">Отметка — Google Video</comment>
+ <comment xml:lang="be">ярлык Google Video Pointer</comment>
<comment xml:lang="ar">اختصار مؤشر فيديو غوغل</comment>
<sub-class-of type="text/plain"/>
<magic>
@@ -36184,12 +36606,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">Haskell 源碼</comment>
<comment xml:lang="zh_CN">Haskell 源代码</comment>
<comment xml:lang="vi">Mã nguồn Haskell</comment>
- <comment xml:lang="uk">вихідний код мовою Haskell</comment>
+ <comment xml:lang="uk">початковий код мовою Haskell</comment>
<comment xml:lang="tr">Haskell kaynak kodu</comment>
<comment xml:lang="sv">Haskell-källkod</comment>
<comment xml:lang="sr">Хаскел изворни ко̂д</comment>
- <comment xml:lang="sq">Kod burues Haskell</comment>
+ <comment xml:lang="sq">kod burim Haskell</comment>
<comment xml:lang="sl">Datoteka izvorne kode Haskell</comment>
+ <comment xml:lang="si">Haskell මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód Haskell</comment>
<comment xml:lang="ru">Исходный код Haskell</comment>
<comment xml:lang="ro">Cod sursă Haskell</comment>
@@ -36207,6 +36630,7 @@ command to generate the output files.
<comment xml:lang="kk">Haskell бастапқы коды</comment>
<comment xml:lang="ja">Haskell ソースコード</comment>
<comment xml:lang="it">Codice sorgente Haskell</comment>
+ <comment xml:lang="is">Haskell frumkóði</comment>
<comment xml:lang="id">Kode sumber Haskell</comment>
<comment xml:lang="ia">Codice-fonte Haskell</comment>
<comment xml:lang="hu">Haskell-forráskód</comment>
@@ -36230,6 +36654,7 @@ command to generate the output files.
<comment xml:lang="ca">codi font en Haskell</comment>
<comment xml:lang="bg">Изходен код — Haskell</comment>
<comment xml:lang="be@latin">Kryničny kod Haskell</comment>
+ <comment xml:lang="be">зыходны код Haskell</comment>
<comment xml:lang="az">Haskell mənbə kodu</comment>
<comment xml:lang="ar">شفرة مصدر Haskell</comment>
<comment xml:lang="af">Haskell-bronkode</comment>
@@ -36245,8 +36670,9 @@ command to generate the output files.
<comment xml:lang="tr">IDL belgesi</comment>
<comment xml:lang="sv">IDL-dokument</comment>
<comment xml:lang="sr">ИДЛ документ</comment>
- <comment xml:lang="sq">Dokument IDL</comment>
+ <comment xml:lang="sq">dokument IDL</comment>
<comment xml:lang="sl">Dokument IDL</comment>
+ <comment xml:lang="si">IDL ලේඛනය</comment>
<comment xml:lang="sk">Dokument IDL</comment>
<comment xml:lang="ru">Документ IDL</comment>
<comment xml:lang="ro">Document IDL</comment>
@@ -36264,6 +36690,7 @@ command to generate the output files.
<comment xml:lang="kk">IDL құжаты</comment>
<comment xml:lang="ja">IDL ドキュメント</comment>
<comment xml:lang="it">Documento IDL</comment>
+ <comment xml:lang="is">IDL skjal</comment>
<comment xml:lang="id">Dokumen IDL</comment>
<comment xml:lang="ia">Documento IDL</comment>
<comment xml:lang="hu">IDL-dokumentum</comment>
@@ -36287,6 +36714,7 @@ command to generate the output files.
<comment xml:lang="ca">document IDL</comment>
<comment xml:lang="bg">Документ — IDL</comment>
<comment xml:lang="be@latin">Dakument IDL</comment>
+ <comment xml:lang="be">дакумент IDL</comment>
<comment xml:lang="az">IDL sənədi</comment>
<comment xml:lang="ast">Documentu IDL</comment>
<comment xml:lang="ar">مستند IDL</comment>
@@ -36297,56 +36725,18 @@ command to generate the output files.
<glob pattern="*.idl"/>
</mime-type>
<mime-type type="text/x-install">
- <comment>installation instructions</comment>
- <comment xml:lang="zh_TW">安裝指引</comment>
- <comment xml:lang="zh_CN">软件安装指南</comment>
- <comment xml:lang="vi">hướng dẫn cài đặt</comment>
- <comment xml:lang="uk">інструкції з встановлення</comment>
- <comment xml:lang="tr">kurulum yönergeleri</comment>
- <comment xml:lang="sv">installationsinstruktioner</comment>
- <comment xml:lang="sr">упутства инсталације</comment>
- <comment xml:lang="sq">Udhëzime instalimi</comment>
- <comment xml:lang="sl">navodila namestitve</comment>
- <comment xml:lang="sk">Návod na inštaláciu</comment>
+ <comment>Installation instructions</comment>
+ <comment xml:lang="uk">настанови щодо встановлення</comment>
+ <comment xml:lang="sv">Installationsinstruktioner</comment>
<comment xml:lang="ru">Инструкции по установке</comment>
- <comment xml:lang="ro">instrucțiuni de instalare</comment>
<comment xml:lang="pt_BR">Instruções de instalação</comment>
- <comment xml:lang="pt">instruções de instalação</comment>
<comment xml:lang="pl">Instrukcje instalacji</comment>
- <comment xml:lang="oc">instructions d'installacion</comment>
- <comment xml:lang="nn">installasjonsinstruksjonar</comment>
- <comment xml:lang="nl">installatie-instructies</comment>
- <comment xml:lang="nb">installationsinstruksjoner</comment>
- <comment xml:lang="lv">instalācijas instrukcijas</comment>
- <comment xml:lang="lt">diegimo instrukcijos</comment>
- <comment xml:lang="ko">설치 방법</comment>
- <comment xml:lang="kk">бағдарламаны орнату нұсқаулары</comment>
- <comment xml:lang="ja">ソフトウェアインストール説明</comment>
+ <comment xml:lang="ja">導入指南</comment>
<comment xml:lang="it">Istruzioni di installazione</comment>
- <comment xml:lang="id">instruksi instalasi</comment>
- <comment xml:lang="ia">Instructiones de installation</comment>
- <comment xml:lang="hu">telepítési utasítások</comment>
- <comment xml:lang="hr">Upute za instalaciju</comment>
- <comment xml:lang="he">הוראות התקנה</comment>
- <comment xml:lang="gl">instrucións de instalación</comment>
- <comment xml:lang="ga">treoracha suiteála</comment>
- <comment xml:lang="fur">istruzions di instalazion</comment>
- <comment xml:lang="fr">instructions d'installation</comment>
- <comment xml:lang="fo">innleggingar vegleiðing</comment>
- <comment xml:lang="fi">asennusohjeet</comment>
- <comment xml:lang="eu">instalazioaren instrukzioak</comment>
+ <comment xml:lang="eu">Instalazio-argibideak</comment>
<comment xml:lang="es">instrucciones de instalación</comment>
- <comment xml:lang="en_GB">installation instructions</comment>
- <comment xml:lang="el">Οδηγίες εγκατάστασης</comment>
<comment xml:lang="de">Installationsanleitung</comment>
- <comment xml:lang="da">installationsinstruktioner</comment>
- <comment xml:lang="cs">návod k instalaci</comment>
- <comment xml:lang="ca">instruccions d'instal·lació</comment>
- <comment xml:lang="bg">Инструкции за инсталация</comment>
- <comment xml:lang="be@latin">instrukcyja dla instalavańnia</comment>
- <comment xml:lang="ast">instrucciones d'instalación</comment>
- <comment xml:lang="ar">تعليمات تثبيت</comment>
- <comment xml:lang="af">installasie-instruksies</comment>
+ <comment xml:lang="be">інструкцыі для ўсталявання</comment>
<sub-class-of type="text/plain"/>
<glob pattern="INSTALL"/>
</mime-type>
@@ -36355,12 +36745,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">Java 源碼</comment>
<comment xml:lang="zh_CN">Java 源代码</comment>
<comment xml:lang="vi">Mã nguồn Java</comment>
- <comment xml:lang="uk">вихідний код мовою Java</comment>
+ <comment xml:lang="uk">початковий код мовою Java</comment>
<comment xml:lang="tr">Java kaynak kodu</comment>
<comment xml:lang="sv">Java-källkod</comment>
<comment xml:lang="sr">Јава изворни ко̂д</comment>
- <comment xml:lang="sq">Kod burues Java</comment>
+ <comment xml:lang="sq">kod burim Java</comment>
<comment xml:lang="sl">Datoteka izvorne kode Java</comment>
+ <comment xml:lang="si">ජාවා මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód Java</comment>
<comment xml:lang="ru">Исходный код Java</comment>
<comment xml:lang="ro">Cod sursă Java</comment>
@@ -36378,6 +36769,7 @@ command to generate the output files.
<comment xml:lang="kk">Java бастапқы коды</comment>
<comment xml:lang="ja">Java ソースコード</comment>
<comment xml:lang="it">Codice sorgente Java</comment>
+ <comment xml:lang="is">Java frumkóði</comment>
<comment xml:lang="id">Kode sumber Java</comment>
<comment xml:lang="ia">Codice-fonte Java</comment>
<comment xml:lang="hu">Java-forráskód</comment>
@@ -36400,6 +36792,7 @@ command to generate the output files.
<comment xml:lang="ca">codi font en Java</comment>
<comment xml:lang="bg">Изходен код — Java</comment>
<comment xml:lang="be@latin">Kryničny kod Java</comment>
+ <comment xml:lang="be">зыходны код Java</comment>
<comment xml:lang="ar">شفرة مصدر Java</comment>
<comment xml:lang="af">Java-bronkode</comment>
<sub-class-of type="text/x-csrc"/>
@@ -36414,8 +36807,9 @@ command to generate the output files.
<comment xml:lang="tr">LDIF adres defteri</comment>
<comment xml:lang="sv">LDIF-adressbok</comment>
<comment xml:lang="sr">ЛДИФ адресар</comment>
- <comment xml:lang="sq">Rubrikë LDIF</comment>
+ <comment xml:lang="sq">libër adresash LDIF</comment>
<comment xml:lang="sl">Datoteka imenika naslovov LDIF</comment>
+ <comment xml:lang="si">LDIF ලිපින පොත</comment>
<comment xml:lang="sk">Adresár LDIF</comment>
<comment xml:lang="ru">Адресная книга LDIF</comment>
<comment xml:lang="ro">Agendă LDIF</comment>
@@ -36432,6 +36826,7 @@ command to generate the output files.
<comment xml:lang="kk">LDIF адрестер кітабы</comment>
<comment xml:lang="ja">LDIF アドレス帳</comment>
<comment xml:lang="it">Rubrica LDIF</comment>
+ <comment xml:lang="is">LDIF-nafnaskrá</comment>
<comment xml:lang="id">Buku alamat LDIF</comment>
<comment xml:lang="ia">Adressario LDIF</comment>
<comment xml:lang="hu">LDIF címjegyzék</comment>
@@ -36454,6 +36849,7 @@ command to generate the output files.
<comment xml:lang="ca">llibreta d'adreces LDIF</comment>
<comment xml:lang="bg">Адресна книга — LDIF</comment>
<comment xml:lang="be@latin">Adrasnaja kniha LDIF</comment>
+ <comment xml:lang="be">адрасная кніга LDIF</comment>
<comment xml:lang="ar">دفتر عناوين LDIF</comment>
<comment xml:lang="af">LDIF-adresboek</comment>
<acronym>LDIF</acronym>
@@ -36474,8 +36870,9 @@ command to generate the output files.
<comment xml:lang="tr">Lilypond müzik sayfası</comment>
<comment xml:lang="sv">Lilypond-notblad</comment>
<comment xml:lang="sr">Лилипонд музички лист</comment>
- <comment xml:lang="sq">Partiturë Lilypond</comment>
+ <comment xml:lang="sq">partiturë Lilypond</comment>
<comment xml:lang="sl">Glasbena predloga Lilypond</comment>
+ <comment xml:lang="si">ලිලිපොන්ඩ් සංගීත පත්රය</comment>
<comment xml:lang="sk">Notový papier Lilypond</comment>
<comment xml:lang="ru">Список музыки Lilypond</comment>
<comment xml:lang="ro">Fișă muzică Lilypond</comment>
@@ -36491,6 +36888,7 @@ command to generate the output files.
<comment xml:lang="kk">Lilypond музыка тізімі</comment>
<comment xml:lang="ja">Lilypond 楽譜データ</comment>
<comment xml:lang="it">Partitura Lilypond</comment>
+ <comment xml:lang="is">LilyPond nótnablað</comment>
<comment xml:lang="id">Lembar musik Lilypond</comment>
<comment xml:lang="ia">Partition musical Lilypond</comment>
<comment xml:lang="hu">Lilypond kotta</comment>
@@ -36512,6 +36910,7 @@ command to generate the output files.
<comment xml:lang="ca">full de música Lilypond</comment>
<comment xml:lang="bg">Нотация на Lilypond</comment>
<comment xml:lang="be@latin">Muzyčny arkuš Lilypond</comment>
+ <comment xml:lang="be">нотны запіс Lilypond</comment>
<comment xml:lang="ar">صفحة موسيقى Lilypond</comment>
<comment xml:lang="af">Lilypond-musiekblad</comment>
<glob pattern="*.ly"/>
@@ -36522,12 +36921,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">LHS 源碼</comment>
<comment xml:lang="zh_CN">LHS 源代码</comment>
<comment xml:lang="vi">Mã nguồn LHS</comment>
- <comment xml:lang="uk">вихідний код LHS</comment>
+ <comment xml:lang="uk">початковий код LHS</comment>
<comment xml:lang="tr">LHS kaynak kodu</comment>
<comment xml:lang="sv">LHS-källkod</comment>
<comment xml:lang="sr">ЛХС изворни ко̂д</comment>
- <comment xml:lang="sq">Kod burues LHS</comment>
+ <comment xml:lang="sq">kod burim LHS</comment>
<comment xml:lang="sl">Datoteka izvorne kode LHS</comment>
+ <comment xml:lang="si">LHS මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód LHS</comment>
<comment xml:lang="ru">Исходный код LHS</comment>
<comment xml:lang="ro">Cod sursă LHS</comment>
@@ -36544,6 +36944,7 @@ command to generate the output files.
<comment xml:lang="kk">LHS бастапқы коды</comment>
<comment xml:lang="ja">LHS ソースコード</comment>
<comment xml:lang="it">Codice sorgente LHS</comment>
+ <comment xml:lang="is">LHS frumkóði</comment>
<comment xml:lang="id">Kode sumber LHS</comment>
<comment xml:lang="ia">Codice-fonte LHS</comment>
<comment xml:lang="hu">LHS forráskód</comment>
@@ -36566,6 +36967,7 @@ command to generate the output files.
<comment xml:lang="ca">codi font en LHS</comment>
<comment xml:lang="bg">Изходен код — LHS</comment>
<comment xml:lang="be@latin">Kryničny kod LHS</comment>
+ <comment xml:lang="be">зыходны код LHS</comment>
<comment xml:lang="ar">شفرة مصدر LHS</comment>
<comment xml:lang="af">LHS-bronkode</comment>
<acronym>LHS</acronym>
@@ -36574,57 +36976,18 @@ command to generate the output files.
<glob pattern="*.lhs"/>
</mime-type>
<mime-type type="text/x-log">
- <comment>application log</comment>
- <comment xml:lang="zh_TW">程式紀錄檔</comment>
- <comment xml:lang="zh_CN">应用程序日志</comment>
- <comment xml:lang="vi">bản ghi ứng dụng</comment>
+ <comment>Application log</comment>
<comment xml:lang="uk">журнал програми</comment>
- <comment xml:lang="tr">uygulama günlüğü</comment>
- <comment xml:lang="sv">programlogg</comment>
- <comment xml:lang="sr">дневник програма</comment>
- <comment xml:lang="sq">log i mesazheve të programit</comment>
- <comment xml:lang="sl">dnevnik programa</comment>
- <comment xml:lang="sk">Záznam aplikácie</comment>
+ <comment xml:lang="sv">Programlogg</comment>
<comment xml:lang="ru">Журнал сообщений</comment>
- <comment xml:lang="ro">înregistrare aplicație</comment>
- <comment xml:lang="pt_BR">Registro de aplicativo</comment>
- <comment xml:lang="pt">diário de aplicação</comment>
<comment xml:lang="pl">Dziennik programu</comment>
- <comment xml:lang="oc">jornal d'aplicacion</comment>
- <comment xml:lang="nn">programlogg</comment>
- <comment xml:lang="nl">programma-logbestand</comment>
- <comment xml:lang="nb">applikasjonslogg</comment>
- <comment xml:lang="ms">Log aplikasi</comment>
- <comment xml:lang="lv">lietotnes žurnāls</comment>
- <comment xml:lang="lt">programos žurnalas</comment>
- <comment xml:lang="ko">프로그램 기록</comment>
- <comment xml:lang="kk">мәлімдемелер журналы</comment>
- <comment xml:lang="ja">アプリケーションログ</comment>
+ <comment xml:lang="ja">アプリケーション記録</comment>
<comment xml:lang="it">Registro applicazione</comment>
- <comment xml:lang="id">log aplikasi</comment>
- <comment xml:lang="ia">Registro de application</comment>
- <comment xml:lang="hu">alkalmazás naplója</comment>
- <comment xml:lang="hr">Zapis aplikacije</comment>
- <comment xml:lang="he">יומן יישום</comment>
- <comment xml:lang="gl">rexistro de aplicativo</comment>
- <comment xml:lang="ga">logchomhad feidhmchláir</comment>
- <comment xml:lang="fur">regjistri aplicazion</comment>
- <comment xml:lang="fr">journal d'application</comment>
- <comment xml:lang="fo">nýtsluskipan logg</comment>
- <comment xml:lang="fi">sovelluksen lokitiedosto</comment>
- <comment xml:lang="eu">aplikazio egunkaria</comment>
- <comment xml:lang="es">registro de aplicación</comment>
- <comment xml:lang="eo">protokolo de aplikaĵo</comment>
- <comment xml:lang="en_GB">application log</comment>
- <comment xml:lang="el">Καταγραφή εφαρμογή</comment>
+ <comment xml:lang="gl">Rexistro de aplicación</comment>
+ <comment xml:lang="eu">Aplikazio-egunkaria</comment>
+ <comment xml:lang="es">registro de aplicaciones</comment>
<comment xml:lang="de">Anwendungsprotokoll</comment>
- <comment xml:lang="da">programlog</comment>
- <comment xml:lang="cs">záznam aplikace</comment>
- <comment xml:lang="ca">registre d'aplicació</comment>
- <comment xml:lang="bg">Журнал със съобщения</comment>
- <comment xml:lang="be@latin">časopis aplikacyi</comment>
- <comment xml:lang="ast">rexistru d'aplicación</comment>
- <comment xml:lang="ar">سجل تطبيق</comment>
+ <comment xml:lang="be">журнал праграмы</comment>
<sub-class-of type="text/plain"/>
<glob pattern="*.log"/>
</mime-type>
@@ -36634,18 +36997,23 @@ command to generate the output files.
<comment xml:lang="uk">файл збирання Makefile</comment>
<comment xml:lang="tr">Makefile derleme dosyası</comment>
<comment xml:lang="sv">Makefile-byggfil</comment>
+ <comment xml:lang="sq">kartelë montimi Makefile</comment>
+ <comment xml:lang="si">Makefile ගොඩනැගීමේ ගොනුව</comment>
<comment xml:lang="sk">Súbor zostavenia Makefile</comment>
<comment xml:lang="ru">Сборочный файл Makefile</comment>
<comment xml:lang="pt_BR">Arquivo de compilação Makefile</comment>
<comment xml:lang="pl">Plik budowania Makefile</comment>
+ <comment xml:lang="nl">Makefile-compilatiebestand</comment>
<comment xml:lang="ko">Makefile 빌드 파일</comment>
<comment xml:lang="kk">Makefile құрастыру файлы</comment>
<comment xml:lang="ja">Makefile ビルドファイル</comment>
<comment xml:lang="it">File compilazione Makefile</comment>
+ <comment xml:lang="is">Makefile byggingaskrá</comment>
<comment xml:lang="id">Berkas build Makefile</comment>
<comment xml:lang="hu">Makefile összeállítási fájl</comment>
<comment xml:lang="hr">Makefile datoteka izgradnje</comment>
<comment xml:lang="he">קובץ בניית Makefile</comment>
+ <comment xml:lang="gl">Ficheiro de construción Makefile</comment>
<comment xml:lang="fr">fichier de construction Makefile</comment>
<comment xml:lang="fi">Makefile-rakennustiedosto</comment>
<comment xml:lang="eu">Makefile build fitxategia</comment>
@@ -36655,6 +37023,7 @@ command to generate the output files.
<comment xml:lang="da">Makefile build-fil</comment>
<comment xml:lang="ca">fitxer de construcció Makefile</comment>
<comment xml:lang="bg">Проект — Makefile</comment>
+ <comment xml:lang="be">файл зборкі Makefile</comment>
<comment xml:lang="ar">ملف بناء Makefile</comment>
<sub-class-of type="text/plain"/>
<glob pattern="makefile"/>
@@ -36675,19 +37044,22 @@ command to generate the output files.
<comment xml:lang="tr">Markdown belgesi</comment>
<comment xml:lang="sv">Markdown-dokument</comment>
<comment xml:lang="sr">Маркдаун документ</comment>
+ <comment xml:lang="sq">dokument Markdown</comment>
<comment xml:lang="sl">Dokument Markdown</comment>
+ <comment xml:lang="si">සලකුණු ලේඛනය</comment>
<comment xml:lang="sk">Dokument Markdown</comment>
<comment xml:lang="ru">Документ Markdown</comment>
<comment xml:lang="pt_BR">Documento Markdown</comment>
<comment xml:lang="pt">documento Markdown</comment>
<comment xml:lang="pl">Dokument Markdown</comment>
<comment xml:lang="oc">document Markdown</comment>
- <comment xml:lang="nl">Markdown document</comment>
+ <comment xml:lang="nl">Markdown-document</comment>
<comment xml:lang="lv">Markdown dokuments</comment>
<comment xml:lang="ko">마크다운 문서</comment>
<comment xml:lang="kk">Markdown құжаты</comment>
<comment xml:lang="ja">Markdown </comment>
<comment xml:lang="it">Documento Markdown</comment>
+ <comment xml:lang="is">Markdown skjal</comment>
<comment xml:lang="id">Dokumen markdown</comment>
<comment xml:lang="ia">Documento Markdown</comment>
<comment xml:lang="hu">Markdown dokumentum</comment>
@@ -36707,10 +37079,12 @@ command to generate the output files.
<comment xml:lang="cs">dokument Markdown</comment>
<comment xml:lang="ca">document Markdown</comment>
<comment xml:lang="bg">Документ — Markdown</comment>
+ <comment xml:lang="be">дакумент Markdown</comment>
<comment xml:lang="ast">Documentu Markdown</comment>
<comment xml:lang="ar">مستند مارك داون</comment>
<comment xml:lang="af">Markdown-dokument</comment>
<sub-class-of type="text/plain"/>
+ <generic-icon name="x-office-document"/>
<glob pattern="*.md"/>
<glob pattern="*.mkd"/>
<glob pattern="*.markdown"/>
@@ -36725,8 +37099,9 @@ command to generate the output files.
<comment xml:lang="tr">Qt MOC dosyası</comment>
<comment xml:lang="sv">Qt MOC-fil</comment>
<comment xml:lang="sr">Кут МОЦ датотека</comment>
- <comment xml:lang="sq">File Qt MOC</comment>
+ <comment xml:lang="sq">kartelë Qt MOC</comment>
<comment xml:lang="sl">Datoteka Qt MOC</comment>
+ <comment xml:lang="si">Qt MOC ගොනුව</comment>
<comment xml:lang="sk">Súbor Qt MOC</comment>
<comment xml:lang="ru">Файл Qt MOC</comment>
<comment xml:lang="ro">Fișier Qt MOC</comment>
@@ -36743,6 +37118,7 @@ command to generate the output files.
<comment xml:lang="kk">Qt MOC файлы</comment>
<comment xml:lang="ja">Qt MOC ファイル</comment>
<comment xml:lang="it">File MOC Qt</comment>
+ <comment xml:lang="is">Qt MOC-skrá</comment>
<comment xml:lang="id">Berkas Qt MOC</comment>
<comment xml:lang="ia">File Qt MOC</comment>
<comment xml:lang="hu">Qt MOC fájl</comment>
@@ -36764,6 +37140,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer MOC de Qt</comment>
<comment xml:lang="bg">Файл — Qt MOC</comment>
<comment xml:lang="be@latin">Fajł Qt MOC</comment>
+ <comment xml:lang="be">файл Qt MOC</comment>
<comment xml:lang="ar">ملف Qt MOC</comment>
<acronym>Qt MOC</acronym>
<expanded-acronym>Qt Meta Object Compiler</expanded-acronym>
@@ -36779,8 +37156,9 @@ command to generate the output files.
<comment xml:lang="tr">Windows Kayıt Defteri özü</comment>
<comment xml:lang="sv">Windows Registry-utdrag</comment>
<comment xml:lang="sr">исцедак Виндоузовог регистра</comment>
- <comment xml:lang="sq">Pjesë Windows Registry</comment>
+ <comment xml:lang="sq">copëz Windows Registry</comment>
<comment xml:lang="sl">izvleček vpisnika Windows</comment>
+ <comment xml:lang="si">වින්ඩෝස් රෙජිස්ට්රි උපුටා ගැනීම</comment>
<comment xml:lang="sk">Časť registrov Windows</comment>
<comment xml:lang="ru">Фрагмент Windows Registry</comment>
<comment xml:lang="ro">Extras al registrului Windows</comment>
@@ -36797,6 +37175,7 @@ command to generate the output files.
<comment xml:lang="kk">Windows Registry бөлігі</comment>
<comment xml:lang="ja">WIndows レジストリ抽出ファイル</comment>
<comment xml:lang="it">Estratto Windows Registry</comment>
+ <comment xml:lang="is">Windows Registry útdráttur</comment>
<comment xml:lang="id">Ekstrak Windows Registry</comment>
<comment xml:lang="ia">Extracto de registro de systema Windows</comment>
<comment xml:lang="hu">Windows Registry kivonat</comment>
@@ -36818,6 +37197,7 @@ command to generate the output files.
<comment xml:lang="ca">extracte de Windows Registry</comment>
<comment xml:lang="bg">Извадка от регистъра на Windows</comment>
<comment xml:lang="be@latin">Element rehistru Windows</comment>
+ <comment xml:lang="be">элемент рэгістру Windows</comment>
<comment xml:lang="ar">استخراج مسجل ويندوز</comment>
<comment xml:lang="af">Windows-registerlêeruittreksel</comment>
<sub-class-of type="text/plain"/>
@@ -36835,20 +37215,25 @@ command to generate the output files.
<comment xml:lang="uk">файл MOF</comment>
<comment xml:lang="tr">MOF dosyası</comment>
<comment xml:lang="sv">MOF-fil</comment>
+ <comment xml:lang="sq">kartelë MOF</comment>
<comment xml:lang="sl">Datoteka MOF</comment>
+ <comment xml:lang="si">MOF ගොනුව</comment>
<comment xml:lang="sk">Súbor MOF</comment>
<comment xml:lang="ru">Файл MOF</comment>
<comment xml:lang="pt_BR">Arquivo MOF</comment>
<comment xml:lang="pl">Plik MOF</comment>
<comment xml:lang="oc">fichièr MOF</comment>
+ <comment xml:lang="nl">MOF-bestand</comment>
<comment xml:lang="ko">MOF 파일</comment>
<comment xml:lang="kk">MOF файлы</comment>
<comment xml:lang="ja">MOF ファイル</comment>
<comment xml:lang="it">File MOF</comment>
+ <comment xml:lang="is">MOF-skrá</comment>
<comment xml:lang="id">Berkas MOF</comment>
<comment xml:lang="hu">MOF fájl</comment>
<comment xml:lang="hr">MOF datoteka</comment>
<comment xml:lang="he">קובץ MOF</comment>
+ <comment xml:lang="gl">Ficheiro MOF</comment>
<comment xml:lang="fr">fichier MOF</comment>
<comment xml:lang="fi">MOF-tiedosto</comment>
<comment xml:lang="eu">MOF fitxategia</comment>
@@ -36858,6 +37243,7 @@ command to generate the output files.
<comment xml:lang="da">MOF-fil</comment>
<comment xml:lang="ca">fitxer MOF</comment>
<comment xml:lang="bg">Модел — MOF</comment>
+ <comment xml:lang="be">файл MOF</comment>
<comment xml:lang="ar">ملف MOF</comment>
<acronym>MOF</acronym>
<expanded-acronym>Windows Managed Object File</expanded-acronym>
@@ -36871,17 +37257,23 @@ command to generate the output files.
<comment xml:lang="uk">документ музичного запису твору Mup</comment>
<comment xml:lang="tr">Mup musical composition belgesi</comment>
<comment xml:lang="sv">Mup musikkompositionsdokument</comment>
+ <comment xml:lang="sq">dokument kompozimi muzikor Mup</comment>
+ <comment xml:lang="si">Mup සංගීත සංයුතිය ලේඛනය</comment>
<comment xml:lang="sk">Dokument hudobnej kompozície Mup</comment>
+ <comment xml:lang="ru">Документ Mup musical composition</comment>
<comment xml:lang="pt_BR">Documento de composição musical Mup</comment>
<comment xml:lang="pl">Dokument kompozycji muzycznej Mup</comment>
+ <comment xml:lang="nl">Mup-muzikaal-compositie­document</comment>
<comment xml:lang="ko">mup 작곡 문서</comment>
<comment xml:lang="kk">Mup музыкалық композиция құжаты</comment>
<comment xml:lang="ja">Mup 作曲ドキュメント</comment>
<comment xml:lang="it">Documento composizione musicale Mup</comment>
+ <comment xml:lang="is">MUP-nótnaskjal</comment>
<comment xml:lang="id">Dokumen komposisi musik Mup</comment>
<comment xml:lang="hu">Mup zenei kompozíciós dokumentum</comment>
<comment xml:lang="hr">Mup dokument glazbene kompozicije</comment>
<comment xml:lang="he">מסמך קומפוזיציה מוזיקלית מסוג Mup</comment>
+ <comment xml:lang="gl">Documento de composición musical MUP</comment>
<comment xml:lang="fr">document de composition musicale Mup</comment>
<comment xml:lang="fi">Mup-sävellysdokumentti</comment>
<comment xml:lang="eu">Mup konposizio musikal dokumentua</comment>
@@ -36891,6 +37283,7 @@ command to generate the output files.
<comment xml:lang="da">Mup-musiksamling-dokument</comment>
<comment xml:lang="ca">document de composició musical Mup</comment>
<comment xml:lang="bg">Музикална композиция — Mup</comment>
+ <comment xml:lang="be">дакумент музычнай кампазіцыі Mup</comment>
<comment xml:lang="ar">وثيقة تأليف موسيقي Mup </comment>
<sub-class-of type="text/plain"/>
<magic>
@@ -36904,12 +37297,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">Objective-C 源碼</comment>
<comment xml:lang="zh_CN">Objective-C 源代码</comment>
<comment xml:lang="vi">Mã nguồn Objective-C</comment>
- <comment xml:lang="uk">вихідний код мовою Objective-C</comment>
+ <comment xml:lang="uk">початковий код мовою Objective-C</comment>
<comment xml:lang="tr">Objective-C kaynak kodu</comment>
<comment xml:lang="sv">Objective-C-källkod</comment>
<comment xml:lang="sr">Објектни-Ц изворни ко̂д</comment>
- <comment xml:lang="sq">Kod burues C objekt</comment>
+ <comment xml:lang="sq">kod burim Objective-C</comment>
<comment xml:lang="sl">Datoteka izvorne kode Objective-C</comment>
+ <comment xml:lang="si">Objective-C මූලාශ්‍ර කේතය</comment>
<comment xml:lang="sk">Zdrojový kód Objective-C</comment>
<comment xml:lang="ru">Исходный код Objective-C</comment>
<comment xml:lang="ro">Cod sursă Objective-C</comment>
@@ -36928,6 +37322,7 @@ command to generate the output files.
<comment xml:lang="ka">Objective-C-ის საწყისი კოდი</comment>
<comment xml:lang="ja">Objective-C ソースコード</comment>
<comment xml:lang="it">Codice sorgente Objective-C</comment>
+ <comment xml:lang="is">Objective-C frumkóði</comment>
<comment xml:lang="id">Kode sumber Objective-C</comment>
<comment xml:lang="ia">Codice-fonte Objective-C</comment>
<comment xml:lang="hu">Objective-C forráskód</comment>
@@ -36950,6 +37345,7 @@ command to generate the output files.
<comment xml:lang="ca">codi font en Objective-C</comment>
<comment xml:lang="bg">Изходен код — Objective C</comment>
<comment xml:lang="be@latin">Kryničny kod Objective-C</comment>
+ <comment xml:lang="be">зыходны код Objective-C</comment>
<comment xml:lang="ar">شفرة مصدر Objective-C</comment>
<comment xml:lang="af">Objective-C-bronkode</comment>
<sub-class-of type="text/x-csrc"/>
@@ -36960,6 +37356,30 @@ command to generate the output files.
</mime-type>
<mime-type type="text/x-objc++src">
<comment>Objective-C++ source code</comment>
+ <comment xml:lang="zh_TW">Objective-C++ 原始碼</comment>
+ <comment xml:lang="zh_CN">Objective-C++ 源代码</comment>
+ <comment xml:lang="uk">початковий код мовою Objective-C++</comment>
+ <comment xml:lang="tr">Objective-C++ kaynak kodu</comment>
+ <comment xml:lang="sv">Objective-C++-källkod</comment>
+ <comment xml:lang="sl">Datoteka izvorne kode Objective-C++</comment>
+ <comment xml:lang="si">අරමුණ-C++ මූල කේතය</comment>
+ <comment xml:lang="ru">Исходный код Objective-C++</comment>
+ <comment xml:lang="pt_BR">Código-fonte Objective-C++</comment>
+ <comment xml:lang="pl">Kod źródłowy Objective-C++</comment>
+ <comment xml:lang="nl">Objective-C++-broncode</comment>
+ <comment xml:lang="ko">Objective-C++ 소스 코드</comment>
+ <comment xml:lang="kk">Objective-C++ бастапқы коды</comment>
+ <comment xml:lang="ja">Objective-C++ ソースコード</comment>
+ <comment xml:lang="it">Codice sorgente Objective-C++</comment>
+ <comment xml:lang="hr">Objective-C++ izvorni kôd</comment>
+ <comment xml:lang="gl">Código fonte de Objective-C++</comment>
+ <comment xml:lang="fi">Objective-C++ lähdekoodi</comment>
+ <comment xml:lang="eu">Objective-C++ iturburu-kodea</comment>
+ <comment xml:lang="es">código fuente en Objective-C++</comment>
+ <comment xml:lang="en_GB">Objective-C++ source code</comment>
+ <comment xml:lang="de">Objective-C++-Quelltext</comment>
+ <comment xml:lang="be">зыходны код Objective-C++</comment>
+ <comment xml:lang="ar">شفرة مصدر Objective-سي++</comment>
<sub-class-of type="text/x-c++src"/>
<sub-class-of type="text/x-objcsrc"/>
<glob pattern="*.mm"/>
@@ -36969,12 +37389,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">OCaml 源碼</comment>
<comment xml:lang="zh_CN">OCaml 源代码</comment>
<comment xml:lang="vi">Mã nguồn OCaml</comment>
- <comment xml:lang="uk">первинний код мовою OCaml</comment>
+ <comment xml:lang="uk">початковий код мовою OCaml</comment>
<comment xml:lang="tr">OCaml kaynak kodu</comment>
<comment xml:lang="sv">OCaml-källkod</comment>
<comment xml:lang="sr">Окемл изворни ко̂д</comment>
- <comment xml:lang="sq">Kod burues OCaml</comment>
+ <comment xml:lang="sq">kod burim OCaml</comment>
<comment xml:lang="sl">Datoteka izvorne kode OCaml</comment>
+ <comment xml:lang="si">OCaml මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód OCaml</comment>
<comment xml:lang="ru">Исходный код OCaml</comment>
<comment xml:lang="ro">Cod sursă OCaml</comment>
@@ -36991,6 +37412,7 @@ command to generate the output files.
<comment xml:lang="kk">OCaml бастапқы коды</comment>
<comment xml:lang="ja">OCaml ソースコード</comment>
<comment xml:lang="it">Codice sorgente OCaml</comment>
+ <comment xml:lang="is">OCaml frumkóði</comment>
<comment xml:lang="id">Kode sumber OCaml</comment>
<comment xml:lang="ia">Codice-fonte OCaml</comment>
<comment xml:lang="hu">OCaml forráskód</comment>
@@ -37013,6 +37435,7 @@ command to generate the output files.
<comment xml:lang="ca">codi font en OCaml</comment>
<comment xml:lang="bg">Изходен код — OCaml</comment>
<comment xml:lang="be@latin">Kryničny kod OCaml</comment>
+ <comment xml:lang="be">зыходны код OCaml</comment>
<comment xml:lang="ar">شفرة مصدر OCaml</comment>
<comment xml:lang="af">OCaml-bronkode</comment>
<sub-class-of type="text/plain"/>
@@ -37021,25 +37444,30 @@ command to generate the output files.
</mime-type>
<mime-type type="text/x-opencl-src">
<comment>OpenCL source code</comment>
- <comment xml:lang="zh_TW">OpenCL 源碼</comment>
+ <comment xml:lang="zh_TW">OpenCL 原始碼</comment>
<comment xml:lang="zh_CN">OpenCL 源代码</comment>
- <comment xml:lang="uk">вихідний код мовою OpenCL</comment>
+ <comment xml:lang="uk">початковий код мовою OpenCL</comment>
<comment xml:lang="tr">OpenCL kaynak kodu</comment>
<comment xml:lang="sv">OpenCL-källkod</comment>
+ <comment xml:lang="sq">kod burim OpenCL</comment>
<comment xml:lang="sl">Izvorna koda OpenCL</comment>
+ <comment xml:lang="si">OpenCL මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód OpenCL</comment>
<comment xml:lang="ru">Исходный код OpenGL</comment>
<comment xml:lang="pt_BR">Código-fonte OpenCL</comment>
<comment xml:lang="pl">Kod źródłowy OpenCL</comment>
<comment xml:lang="oc">còdi font OpenCL</comment>
+ <comment xml:lang="nl">OpenCL-broncode</comment>
<comment xml:lang="ko">OpenCL 소스 코드</comment>
<comment xml:lang="kk">OpenCL бастапқы коды</comment>
<comment xml:lang="ja">OpenCL ソースコード</comment>
<comment xml:lang="it">Codice sorgente OpenCL</comment>
+ <comment xml:lang="is">OpenCL frumkóði</comment>
<comment xml:lang="id">Kode sumber OpenCL</comment>
<comment xml:lang="hu">OpenCL forráskód</comment>
<comment xml:lang="hr">OpenCL izvorni kôd</comment>
<comment xml:lang="he">קוד מקור OpenCL</comment>
+ <comment xml:lang="gl">Código fonte en OpenCL</comment>
<comment xml:lang="ga">cód foinseach OpenCL</comment>
<comment xml:lang="fur">codiç sorzint OpenCL</comment>
<comment xml:lang="fr">code source OpenCL</comment>
@@ -37052,6 +37480,7 @@ command to generate the output files.
<comment xml:lang="cs">zdrojový kód v jazyce OpenCL</comment>
<comment xml:lang="ca">codi font en OpenCL</comment>
<comment xml:lang="bg">Изходен код — OpenCL</comment>
+ <comment xml:lang="be">зыходны код OpenCL</comment>
<comment xml:lang="ar">شفرة مصدر OpenCL</comment>
<comment xml:lang="af">OpenCL-bronkode</comment>
<acronym>OpenCL</acronym>
@@ -37066,19 +37495,24 @@ command to generate the output files.
<comment xml:lang="uk">файл MATLAB</comment>
<comment xml:lang="tr">MATLAB dosyası</comment>
<comment xml:lang="sv">MATLAB-fil</comment>
+ <comment xml:lang="sq">kartelë MATLAB</comment>
<comment xml:lang="sl">Datoteka MATLAB</comment>
+ <comment xml:lang="si">MATLAB ගොනුව</comment>
<comment xml:lang="sk">Súbor MATLAB</comment>
<comment xml:lang="ru">Файл MATLAB</comment>
<comment xml:lang="pt_BR">Arquivo do MATLAB</comment>
<comment xml:lang="pl">Plik MATLAB</comment>
+ <comment xml:lang="nl">MATLAB-bestand</comment>
<comment xml:lang="ko">MATLAB 파일</comment>
<comment xml:lang="kk">MATLAB файлы</comment>
<comment xml:lang="ja">MATLAB ファイル</comment>
<comment xml:lang="it">File MATLAB</comment>
+ <comment xml:lang="is">MATLAB-skrá</comment>
<comment xml:lang="id">Berkas MATLAB</comment>
<comment xml:lang="hu">MATLAB fájl</comment>
<comment xml:lang="hr">MATLAB datoteka</comment>
<comment xml:lang="he">קובץ MATLAB</comment>
+ <comment xml:lang="gl">Ficheiro de MATLAB</comment>
<comment xml:lang="fr">fichier MATLAB</comment>
<comment xml:lang="fi">MATLAB-tiedosto</comment>
<comment xml:lang="eu">MATLAB fitxategia</comment>
@@ -37088,14 +37522,12 @@ command to generate the output files.
<comment xml:lang="da">MATLAB-fil</comment>
<comment xml:lang="ca">fitxer MATLAB</comment>
<comment xml:lang="bg">Файл — MATLAB</comment>
+ <comment xml:lang="be">файл MATLAB</comment>
<comment xml:lang="ar">ملف ماتلاب</comment>
<sub-class-of type="text/plain"/>
<magic priority="10">
<match type="string" value="%" offset="0"/>
</magic>
- <magic priority="10">
- <match type="string" value="##" offset="0"/>
- </magic>
<magic>
<match type="string" value="function" offset="0"/>
</magic>
@@ -37106,26 +37538,31 @@ command to generate the output files.
<comment>Meson source code</comment>
<comment xml:lang="zh_TW">Meson 源碼</comment>
<comment xml:lang="zh_CN">Meson 源代码</comment>
- <comment xml:lang="uk">вихідний код мовою Meson</comment>
+ <comment xml:lang="uk">початковий код мовою Meson</comment>
<comment xml:lang="tr">Meson kaynak kodu</comment>
<comment xml:lang="sv">Meson-källkod</comment>
<comment xml:lang="sr">Месон изворни ко̂д</comment>
+ <comment xml:lang="sq">kod burim Meson</comment>
<comment xml:lang="sl">Izvorna koda Meson</comment>
+ <comment xml:lang="si">Meson මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód Meson</comment>
<comment xml:lang="ru">Исходный код Meson</comment>
<comment xml:lang="pt_BR">Código-fonte Meson</comment>
<comment xml:lang="pt">código origem Meson</comment>
<comment xml:lang="pl">Kod źródłowy Meson</comment>
<comment xml:lang="oc">còde font Meson</comment>
+ <comment xml:lang="nl">Meson-broncode</comment>
<comment xml:lang="ko">Meson 소스 코드</comment>
<comment xml:lang="kk">Meson бастапқы коды</comment>
<comment xml:lang="ja">Meson ソースコード</comment>
<comment xml:lang="it">Codice sorgente Meson</comment>
+ <comment xml:lang="is">Meson frumkóði</comment>
<comment xml:lang="id">Kode sumber Meson</comment>
<comment xml:lang="ia">Codice-fonte Meson</comment>
<comment xml:lang="hu">Meson forráskód</comment>
<comment xml:lang="hr">Meson izvorni kôd</comment>
<comment xml:lang="he">קוד מקור Meson</comment>
+ <comment xml:lang="gl">Código fonte Meson</comment>
<comment xml:lang="ga">cód foinseach Meson</comment>
<comment xml:lang="fur">codiç sorzint Meson</comment>
<comment xml:lang="fr">code source Meson</comment>
@@ -37139,6 +37576,7 @@ command to generate the output files.
<comment xml:lang="cs">zdrojový kód Meson</comment>
<comment xml:lang="ca">codi font en Meson</comment>
<comment xml:lang="bg">Изходен код — Meson</comment>
+ <comment xml:lang="be">зыходны код Meson</comment>
<comment xml:lang="ar">شفرة مصدر Meson</comment>
<comment xml:lang="af">Meson-bronkode</comment>
<glob pattern="meson.build"/>
@@ -37153,18 +37591,22 @@ command to generate the output files.
<comment xml:lang="tr">Modelica modeli</comment>
<comment xml:lang="sv">Modelica-modell</comment>
<comment xml:lang="sr">модел Моделике</comment>
+ <comment xml:lang="sq">model Modelica</comment>
<comment xml:lang="sl">Model Modelica</comment>
+ <comment xml:lang="si">Modelica ආකෘතිය</comment>
<comment xml:lang="sk">Model Modelica</comment>
<comment xml:lang="ru">Модель Modelica</comment>
<comment xml:lang="pt_BR">Modelo da Modelica</comment>
<comment xml:lang="pt">modelo Modelica</comment>
<comment xml:lang="pl">Model Modelica</comment>
<comment xml:lang="oc">modèl Modelica</comment>
+ <comment xml:lang="nl">Modelica-model</comment>
<comment xml:lang="lv">Modelica modelis</comment>
<comment xml:lang="ko">Modelica 모델</comment>
<comment xml:lang="kk">Modelica моделі</comment>
<comment xml:lang="ja">Modelica モデル</comment>
<comment xml:lang="it">Modello Modelica</comment>
+ <comment xml:lang="is">Modelica líkan</comment>
<comment xml:lang="id">Model Modelica</comment>
<comment xml:lang="ia">Modello Modelica</comment>
<comment xml:lang="hu">Modelica modell</comment>
@@ -37184,6 +37626,7 @@ command to generate the output files.
<comment xml:lang="cs">model Modelica</comment>
<comment xml:lang="ca">model de Modelica</comment>
<comment xml:lang="bg">Модел — Modelica</comment>
+ <comment xml:lang="be">мадэль Modelica</comment>
<comment xml:lang="ar">نموذج Modelica</comment>
<comment xml:lang="af">Modelica-model</comment>
<sub-class-of type="text/plain"/>
@@ -37209,12 +37652,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">Pascal 源碼</comment>
<comment xml:lang="zh_CN">Pascal 源代码</comment>
<comment xml:lang="vi">Mã nguồn Pascal</comment>
- <comment xml:lang="uk">вихідний код мовою Pascal</comment>
+ <comment xml:lang="uk">початковий код мовою Pascal</comment>
<comment xml:lang="tr">Pascal kaynak kodu</comment>
<comment xml:lang="sv">Pascal-källkod</comment>
<comment xml:lang="sr">Паскалов изворни ко̂д</comment>
- <comment xml:lang="sq">Kod burues Pascal</comment>
+ <comment xml:lang="sq">kod burim Pascal</comment>
<comment xml:lang="sl">Datoteka izvorne kode Pascal</comment>
+ <comment xml:lang="si">පැස්කල් මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód Pascal</comment>
<comment xml:lang="ru">Исходный код Pascal</comment>
<comment xml:lang="ro">Cod sursă Pascal</comment>
@@ -37232,6 +37676,7 @@ command to generate the output files.
<comment xml:lang="kk">Pascal бастапқы коды</comment>
<comment xml:lang="ja">Pascal ソースコード</comment>
<comment xml:lang="it">Codice sorgente Pascal</comment>
+ <comment xml:lang="is">Pascal frumkóði</comment>
<comment xml:lang="id">Kode sumber Pascal</comment>
<comment xml:lang="ia">Codice-fonte Pascal</comment>
<comment xml:lang="hu">Pascal-forráskód</comment>
@@ -37254,6 +37699,7 @@ command to generate the output files.
<comment xml:lang="ca">codi font en Pascal</comment>
<comment xml:lang="bg">Изходен код — Pascal</comment>
<comment xml:lang="be@latin">Kryničny kod Pascal</comment>
+ <comment xml:lang="be">зыходны код Pascal</comment>
<comment xml:lang="ar">شفرة مصدر باسكال</comment>
<comment xml:lang="af">Pascal-bronkode</comment>
<sub-class-of type="text/plain"/>
@@ -37261,57 +37707,18 @@ command to generate the output files.
<glob pattern="*.pas"/>
</mime-type>
<mime-type type="text/x-patch">
- <comment>differences between files</comment>
- <comment xml:lang="zh_TW">檔案內容差異</comment>
- <comment xml:lang="zh_CN">文件的区别</comment>
- <comment xml:lang="vi">khác biệt giữa các tập tin</comment>
+ <comment>Differences between files</comment>
<comment xml:lang="uk">різниця між файлами</comment>
- <comment xml:lang="tr">dosyalar arasındaki fark</comment>
- <comment xml:lang="sv">skillnader mellan filer</comment>
- <comment xml:lang="sr">разлике између датотека</comment>
- <comment xml:lang="sq">Diferencë midis file</comment>
- <comment xml:lang="sl">razlike med datotekami</comment>
- <comment xml:lang="sk">Rozdiely medzi súbormi</comment>
+ <comment xml:lang="sv">Skillnader mellan filer</comment>
<comment xml:lang="ru">Различия между файлами</comment>
- <comment xml:lang="ro">diferențe între fișiere</comment>
- <comment xml:lang="pt_BR">Diferenças entre arquivos</comment>
- <comment xml:lang="pt">diferenças entre ficheiros</comment>
<comment xml:lang="pl">Różnica pomiędzy plikami</comment>
- <comment xml:lang="oc">différences entre fichièrs</comment>
- <comment xml:lang="nn">skilnader mellom filer</comment>
- <comment xml:lang="nl">verschillen tussen bestanden</comment>
- <comment xml:lang="nb">forskjeller mellom filer</comment>
- <comment xml:lang="ms">Perbezaan antara fail</comment>
- <comment xml:lang="lv">divu datņu atšķirība</comment>
- <comment xml:lang="lt">skirtumai tarp failų</comment>
- <comment xml:lang="ko">파일 사이의 차이점</comment>
- <comment xml:lang="kk">файлдар арасындағы айырмашылықтары</comment>
- <comment xml:lang="ja">ファイル間差分</comment>
+ <comment xml:lang="ja">差分文書</comment>
<comment xml:lang="it">Differenze tra file</comment>
- <comment xml:lang="id">perbedaan diantara berkas</comment>
- <comment xml:lang="ia">Differentias inter files</comment>
- <comment xml:lang="hu">diff-különbségfájl</comment>
- <comment xml:lang="hr">Razlike između datoteka</comment>
- <comment xml:lang="he">הבדל בין קבצים</comment>
- <comment xml:lang="gl">diferenzas entre ficheiros</comment>
- <comment xml:lang="ga">difríochtaí idir chomhaid</comment>
- <comment xml:lang="fur">diferencis tra file</comment>
- <comment xml:lang="fr">différences entre fichiers</comment>
- <comment xml:lang="fo">munur millum fílur</comment>
- <comment xml:lang="fi">tiedostojen väliset erot</comment>
- <comment xml:lang="eu">fitxategien arteko ezberdintasunak</comment>
+ <comment xml:lang="gl">Diferenzas entre ficheiros</comment>
+ <comment xml:lang="eu">Fitxategien arteko diferentziak</comment>
<comment xml:lang="es">diferencias entre archivos</comment>
- <comment xml:lang="eo">diferencoj inter dosieroj</comment>
- <comment xml:lang="en_GB">differences between files</comment>
- <comment xml:lang="el">Διαφορές μεταξύ αρχείων</comment>
<comment xml:lang="de">Unterschiede zwischen Dateien</comment>
- <comment xml:lang="da">forskel mellem filer</comment>
- <comment xml:lang="cs">rozdíly mezi soubory</comment>
- <comment xml:lang="ca">diferències entre fitxers</comment>
- <comment xml:lang="bg">Разлики между файлове</comment>
- <comment xml:lang="be@latin">adroźnieńni pamiž fajłami</comment>
- <comment xml:lang="ar">فرق بين ملفات</comment>
- <comment xml:lang="af">verskille tussen lêers</comment>
+ <comment xml:lang="be">адрозненні паміж файламі</comment>
<alias type="text/x-diff"/>
<sub-class-of type="text/plain"/>
<magic>
@@ -37329,33 +37736,93 @@ command to generate the output files.
<glob pattern="*.diff"/>
<glob pattern="*.patch"/>
</mime-type>
- <mime-type type="text/x-dart">
+ <mime-type type="application/vnd.dart">
<comment>Dart source code</comment>
+ <comment xml:lang="zh_TW">Dart 原始碼</comment>
+ <comment xml:lang="zh_CN">Dart 源代码</comment>
+ <comment xml:lang="uk">початковий код мовою Dart</comment>
+ <comment xml:lang="tr">Dart kaynak kodu</comment>
+ <comment xml:lang="sv">Dart-källkod</comment>
+ <comment xml:lang="sl">Izvorna koda Dart</comment>
+ <comment xml:lang="si">ඩාර්ට් මූලාශ්‍ර කේතය</comment>
+ <comment xml:lang="ru">Исходный код Dart</comment>
+ <comment xml:lang="pt_BR">Código-fonte Dart</comment>
+ <comment xml:lang="pl">Kod źródłowy Dart</comment>
+ <comment xml:lang="nl">Dart-broncode</comment>
+ <comment xml:lang="ko">Dart 소스 코드</comment>
+ <comment xml:lang="kk">Dart бастапқы коды</comment>
+ <comment xml:lang="ja">Dart ソースコード</comment>
+ <comment xml:lang="it">Codice sorgente Dart</comment>
+ <comment xml:lang="hr">Dart izvorni kôd</comment>
+ <comment xml:lang="he">קוד מקור ב־Dart</comment>
+ <comment xml:lang="gl">Código fonte Dart</comment>
+ <comment xml:lang="fi">Dart-lähdekoodi</comment>
+ <comment xml:lang="eu">Dart iturburu-kodea</comment>
+ <comment xml:lang="es">código fuente Dart</comment>
+ <comment xml:lang="en_GB">Dart source code</comment>
+ <comment xml:lang="de">Dart-Quelltext</comment>
+ <comment xml:lang="be">зыходны код Dart</comment>
+ <comment xml:lang="ar">شفرة مصدر Dart</comment>
<sub-class-of type="text/plain"/>
<glob pattern="*.dart"/>
+ <alias type="text/x-dart"/>
+ </mime-type>
+ <mime-type type="text/x-nim">
+ <comment>Nim source code</comment>
+ <comment xml:lang="uk">початковий код мовою Nim</comment>
+ <comment xml:lang="sv">Nim-källkod</comment>
+ <comment xml:lang="ru">Исходный код Nim</comment>
+ <comment xml:lang="pl">Kod źródłowy Nim</comment>
+ <comment xml:lang="it">Codice sorgente Nim</comment>
+ <comment xml:lang="gl">Código fonte Nim</comment>
+ <comment xml:lang="eu">Nim iturburu-kodea</comment>
+ <comment xml:lang="es">código fuente en Nim</comment>
+ <comment xml:lang="de">Nim-Quelltext</comment>
+ <comment xml:lang="be">зыходны код Nim</comment>
+ <sub-class-of type="text/plain"/>
+ <glob pattern="*.nim"/>
+ </mime-type>
+ <mime-type type="text/x-nimscript">
+ <comment>Nimscript source code</comment>
+ <comment xml:lang="uk">початковий код мовою Nimscript</comment>
+ <comment xml:lang="sv">Nimscript-källkod</comment>
+ <comment xml:lang="ru">Исходный код Nimscript</comment>
+ <comment xml:lang="pl">Kod źródłowy NimScript</comment>
+ <comment xml:lang="it">Codice sorgente Nimscript</comment>
+ <comment xml:lang="gl">Código fonte Nimscript</comment>
+ <comment xml:lang="eu">Nimscript iturburu-kodea</comment>
+ <comment xml:lang="es">código fuente en Nimscript</comment>
+ <comment xml:lang="de">Nimscript-Quelltext</comment>
+ <comment xml:lang="be">зыходны код Nimscript</comment>
+ <sub-class-of type="text/x-nim"/>
+ <glob pattern="*.nims"/>
+ <glob pattern="*.nimble"/>
</mime-type>
<mime-type type="text/x-go">
<comment>Go source code</comment>
<comment xml:lang="zh_TW">Go 源碼</comment>
<comment xml:lang="zh_CN">Go 源代码</comment>
- <comment xml:lang="uk">вихідний код мовою Go</comment>
+ <comment xml:lang="uk">початковий код мовою Go</comment>
<comment xml:lang="tr">Go kaynak kodu</comment>
<comment xml:lang="sv">Go-källkod</comment>
<comment xml:lang="sr">Гоу изворни ко̂д</comment>
+ <comment xml:lang="sq">kod burim Go</comment>
<comment xml:lang="sl">Izvorna koda Go</comment>
+ <comment xml:lang="si">මූල කේතය වෙත යන්න</comment>
<comment xml:lang="sk">Zdrojový kód Go</comment>
<comment xml:lang="ru">Исходный код Go</comment>
<comment xml:lang="pt_BR">Código-fonte Go</comment>
<comment xml:lang="pt">cigo origem Go</comment>
<comment xml:lang="pl">Kod źródłowy Go</comment>
<comment xml:lang="oc">còde font Go</comment>
- <comment xml:lang="nl">Go broncode</comment>
+ <comment xml:lang="nl">Go-broncode</comment>
<comment xml:lang="lv">Go pirmkods</comment>
<comment xml:lang="ko">Go 소스 코드</comment>
<comment xml:lang="kk">Go бастапқы коды</comment>
<comment xml:lang="ka">Go-ის საწყისი კოდი</comment>
<comment xml:lang="ja">Go ソースコード</comment>
<comment xml:lang="it">Codice sorgente Go</comment>
+ <comment xml:lang="is">Go frumkóði</comment>
<comment xml:lang="id">Kode sumber Go</comment>
<comment xml:lang="ia">Codice-fonte Go</comment>
<comment xml:lang="hu">Go forráskód</comment>
@@ -37376,6 +37843,7 @@ command to generate the output files.
<comment xml:lang="cs">zdrojový kód v jazyce Go</comment>
<comment xml:lang="ca">codi font en Go</comment>
<comment xml:lang="bg">Изходен код — Go</comment>
+ <comment xml:lang="be">зыходны код Go</comment>
<comment xml:lang="ar">شفرة مصدر غو</comment>
<comment xml:lang="af">Go-bronkode</comment>
<sub-class-of type="text/plain"/>
@@ -37389,22 +37857,27 @@ command to generate the output files.
<comment xml:lang="tr">SCons yapılandırma dosyası</comment>
<comment xml:lang="sv">SCons-konfigurationsfil</comment>
<comment xml:lang="sr">СКонс датотека подешавања</comment>
+ <comment xml:lang="sq">kartelë formësimi SCons</comment>
<comment xml:lang="sl">Prilagoditvena datoteka SCons</comment>
+ <comment xml:lang="si">SCons වින්‍යාස ගොනුව</comment>
<comment xml:lang="sk">Konfiguračný súbor SCons</comment>
<comment xml:lang="ru">Файл настроек SCons</comment>
<comment xml:lang="pt_BR">Arquivo de configuração do SCons</comment>
<comment xml:lang="pt">ficheiro de configuração SCons</comment>
<comment xml:lang="pl">Plik konfiguracji SCons</comment>
<comment xml:lang="oc">fichièr de configuracion SCons</comment>
+ <comment xml:lang="nl">SCons-configuratiebestand</comment>
<comment xml:lang="ko">SCons 설정 파일</comment>
<comment xml:lang="kk">SCons баптаулар файлы</comment>
<comment xml:lang="ja">SCons 設定ファイル</comment>
<comment xml:lang="it">File configurazione SCons</comment>
+ <comment xml:lang="is">SCons stillingaskrá</comment>
<comment xml:lang="id">Berkas konfigurasi SCons</comment>
<comment xml:lang="ia">File de cofniguration SCons</comment>
<comment xml:lang="hu">SCons beállítófájl</comment>
<comment xml:lang="hr">SCons datoteka podešavanja</comment>
<comment xml:lang="he">קובץ תצורה של SCons</comment>
+ <comment xml:lang="gl">Ficheiro de configuración SCons</comment>
<comment xml:lang="ga">comhad cumraíochta SCons</comment>
<comment xml:lang="fur">file di configurazion SCons</comment>
<comment xml:lang="fr">fichier de configuration SCons</comment>
@@ -37418,6 +37891,7 @@ command to generate the output files.
<comment xml:lang="cs">konfigurační soubor SCons</comment>
<comment xml:lang="ca">fitxer de configuració de SCons</comment>
<comment xml:lang="bg">Настройки — SCons</comment>
+ <comment xml:lang="be">файл канфігурацыі SCons</comment>
<comment xml:lang="ar">ملف إعداد SCons</comment>
<comment xml:lang="af">SCons-opstellingslêer</comment>
<sub-class-of type="text/x-python"/>
@@ -37432,16 +37906,20 @@ command to generate the output files.
<comment xml:lang="uk">скрипт мовою Python 3</comment>
<comment xml:lang="tr">Python 3 betiği</comment>
<comment xml:lang="sv">Python 3-skript</comment>
+ <comment xml:lang="sq">programth Python 3</comment>
<comment xml:lang="sl">Skript Python 3</comment>
+ <comment xml:lang="si">Python 3 පිටපත</comment>
<comment xml:lang="sk">Skript Python 3</comment>
<comment xml:lang="ru">Сценарий Python 3</comment>
<comment xml:lang="pt_BR">Script Python 3</comment>
<comment xml:lang="pl">Skrypt Python 3</comment>
<comment xml:lang="oc">script Python 3</comment>
+ <comment xml:lang="nl">Python 3-script</comment>
<comment xml:lang="ko">파이썬 3 스크립트</comment>
<comment xml:lang="kk">Python 3 скрипті</comment>
<comment xml:lang="ja">Python 3 スクリプト</comment>
<comment xml:lang="it">Script Python 3</comment>
+ <comment xml:lang="is">Python 3 skrifta</comment>
<comment xml:lang="id">Skrip Python 3</comment>
<comment xml:lang="hu">Python 3 parancsfájl</comment>
<comment xml:lang="hr">Python3 skripta</comment>
@@ -37458,6 +37936,7 @@ command to generate the output files.
<comment xml:lang="cs">skript v jazyce Python 3</comment>
<comment xml:lang="ca">script Python 3</comment>
<comment xml:lang="bg">Скрипт — Python 3</comment>
+ <comment xml:lang="be">скрыпт Python 3</comment>
<comment xml:lang="ar">سكربت بايثون٣</comment>
<comment xml:lang="af">Python 3-skrip</comment>
<sub-class-of type="text/x-python"/>
@@ -37489,8 +37968,9 @@ command to generate the output files.
<comment xml:lang="tr">Python betiği</comment>
<comment xml:lang="sv">Pythonskript</comment>
<comment xml:lang="sr">Питонова скрипта</comment>
- <comment xml:lang="sq">Script Python</comment>
+ <comment xml:lang="sq">programth Python</comment>
<comment xml:lang="sl">Skriptna datoteka Python</comment>
+ <comment xml:lang="si">පයිතන් පිටපත</comment>
<comment xml:lang="sk">Skript Python</comment>
<comment xml:lang="ru">Сценарий Python</comment>
<comment xml:lang="ro">Script Python</comment>
@@ -37508,6 +37988,7 @@ command to generate the output files.
<comment xml:lang="kk">Python сценарийі</comment>
<comment xml:lang="ja">Python スクリプト</comment>
<comment xml:lang="it">Script Python</comment>
+ <comment xml:lang="is">Python skrifta</comment>
<comment xml:lang="id">Skrip Python</comment>
<comment xml:lang="ia">Script Python</comment>
<comment xml:lang="hu">Python-parancsfájl</comment>
@@ -37530,6 +38011,7 @@ command to generate the output files.
<comment xml:lang="ca">script Python</comment>
<comment xml:lang="bg">Скрипт — Python</comment>
<comment xml:lang="be@latin">Skrypt Python</comment>
+ <comment xml:lang="be">скрыпт Python</comment>
<comment xml:lang="ar">سكربت بايثون</comment>
<comment xml:lang="af">Python-skrip</comment>
<sub-class-of type="application/x-executable"/>
@@ -37552,26 +38034,35 @@ command to generate the output files.
</mime-type>
<mime-type type="text/x-sagemath">
<comment>SageMath script</comment>
+ <comment xml:lang="zh_TW">SageMath 指令稿</comment>
<comment xml:lang="zh_CN">SageMath 脚本</comment>
<comment xml:lang="uk">скрипт SageMath</comment>
<comment xml:lang="tr">SageMath betiği</comment>
<comment xml:lang="sv">SageMath-skript</comment>
+ <comment xml:lang="sl">Skript SageMath</comment>
+ <comment xml:lang="si">SageMath පිටපත</comment>
+ <comment xml:lang="ru">Сценарий SageMath</comment>
<comment xml:lang="pt_BR">Script SageMath</comment>
<comment xml:lang="pl">Skrypt SageMath</comment>
+ <comment xml:lang="nl">SageMath-script</comment>
<comment xml:lang="ko">SageMath 스크립트</comment>
+ <comment xml:lang="kk">SageMath сценарийі</comment>
<comment xml:lang="ja">SageMath スクリプト</comment>
<comment xml:lang="it">Script SageMath</comment>
+ <comment xml:lang="is">SageMath skrifta</comment>
<comment xml:lang="id">skrip SageMath</comment>
<comment xml:lang="hu">SageMath parancsfájl</comment>
<comment xml:lang="hr">SageMath skripta</comment>
<comment xml:lang="he">סקריפט SageMath</comment>
<comment xml:lang="fr">Script SageMath</comment>
<comment xml:lang="fi">SageMath-komentotiedosto</comment>
+ <comment xml:lang="eu">SageMath script-a</comment>
<comment xml:lang="es">secuencia de órdenes de SageMath</comment>
<comment xml:lang="en_GB">SageMath script</comment>
<comment xml:lang="de">SageMath-Skript</comment>
<comment xml:lang="da">SageMath-program</comment>
<comment xml:lang="ca">script SageMath</comment>
+ <comment xml:lang="be">скрыпт SageMath</comment>
<comment xml:lang="ar">سكربت SageMath</comment>
<sub-class-of type="text/x-python"/>
<glob pattern="*.sage" weight="60"/>
@@ -37585,8 +38076,9 @@ command to generate the output files.
<comment xml:lang="tr">Lua betiği</comment>
<comment xml:lang="sv">Lua-skript</comment>
<comment xml:lang="sr">Луа скрипта</comment>
- <comment xml:lang="sq">Script Lua</comment>
+ <comment xml:lang="sq">programth Lua</comment>
<comment xml:lang="sl">Skriptna datoteka Lua</comment>
+ <comment xml:lang="si">Lua පිටපත</comment>
<comment xml:lang="sk">Skript Lua</comment>
<comment xml:lang="ru">Сценарий Lua</comment>
<comment xml:lang="ro">Script Lua</comment>
@@ -37603,6 +38095,7 @@ command to generate the output files.
<comment xml:lang="kk">Lua сценарийі</comment>
<comment xml:lang="ja">Lua スクリプト</comment>
<comment xml:lang="it">Script Lua</comment>
+ <comment xml:lang="is">Lua skrifta</comment>
<comment xml:lang="id">Skrip Lua</comment>
<comment xml:lang="ia">Script Lua</comment>
<comment xml:lang="hu">Lua parancsfájl</comment>
@@ -37625,6 +38118,7 @@ command to generate the output files.
<comment xml:lang="ca">script Lua</comment>
<comment xml:lang="bg">Скрипт на Lua</comment>
<comment xml:lang="be@latin">Skrypt Lua</comment>
+ <comment xml:lang="be">скрыпт Lua</comment>
<comment xml:lang="ar">سكربت Lua</comment>
<comment xml:lang="af">Lua-skrip</comment>
<sub-class-of type="application/x-executable"/>
@@ -37646,8 +38140,9 @@ command to generate the output files.
<comment xml:lang="tr">README belgesi</comment>
<comment xml:lang="sv">README-dokument</comment>
<comment xml:lang="sr">документ ПРОЧИТАЈМЕ</comment>
- <comment xml:lang="sq">Dokument README</comment>
+ <comment xml:lang="sq">dokument README</comment>
<comment xml:lang="sl">Dokument README</comment>
+ <comment xml:lang="si">README ලේඛනය</comment>
<comment xml:lang="sk">Dokument README</comment>
<comment xml:lang="ru">Документ README</comment>
<comment xml:lang="ro">Document README</comment>
@@ -37665,6 +38160,7 @@ command to generate the output files.
<comment xml:lang="kk">README құжаты</comment>
<comment xml:lang="ja">README ドキュメント</comment>
<comment xml:lang="it">Documento README</comment>
+ <comment xml:lang="is">README skjal</comment>
<comment xml:lang="id">Dokumen README</comment>
<comment xml:lang="ia">Documento LEGE-ME</comment>
<comment xml:lang="hu">README-dokumentum</comment>
@@ -37688,6 +38184,7 @@ command to generate the output files.
<comment xml:lang="ca">document README</comment>
<comment xml:lang="bg">Документ — „Да се прочете“</comment>
<comment xml:lang="be@latin">Dakument README</comment>
+ <comment xml:lang="be">дакумент README</comment>
<comment xml:lang="az">README sənədi</comment>
<comment xml:lang="ast">Documentu LLEIME</comment>
<comment xml:lang="ar">مستند README</comment>
@@ -37704,8 +38201,9 @@ command to generate the output files.
<comment xml:lang="tr">NFO belgesi</comment>
<comment xml:lang="sv">NFO-dokument</comment>
<comment xml:lang="sr">документ НФО</comment>
- <comment xml:lang="sq">Dokument NFO</comment>
+ <comment xml:lang="sq">dokument NFO</comment>
<comment xml:lang="sl">Dokument NFO</comment>
+ <comment xml:lang="si">NFO ලේඛනය</comment>
<comment xml:lang="sk">Dokument NFO</comment>
<comment xml:lang="ru">Документ NFO</comment>
<comment xml:lang="ro">Document NFO</comment>
@@ -37722,6 +38220,7 @@ command to generate the output files.
<comment xml:lang="kk">NFO құжаты</comment>
<comment xml:lang="ja">NFO ドキュメント</comment>
<comment xml:lang="it">Documento NFO</comment>
+ <comment xml:lang="is">NFO skjal</comment>
<comment xml:lang="id">Dokumen NFO</comment>
<comment xml:lang="ia">Documento NFO</comment>
<comment xml:lang="hu">NFO-dokumentum</comment>
@@ -37744,12 +38243,30 @@ command to generate the output files.
<comment xml:lang="ca">document NFO</comment>
<comment xml:lang="bg">Документ — NFO</comment>
<comment xml:lang="be@latin">Dakument NFO</comment>
+ <comment xml:lang="be">дакумент NFO</comment>
<comment xml:lang="ast">Documentu NFO</comment>
<comment xml:lang="ar">مستند NFO</comment>
<comment xml:lang="af">NFO-dokument</comment>
<sub-class-of type="text/x-readme"/>
<glob pattern="*.nfo"/>
</mime-type>
+ <mime-type type="text/x-todo-txt">
+ <comment>Todo.txt file</comment>
+ <comment xml:lang="uk">файл Todo.txt</comment>
+ <comment xml:lang="sv">Todo.txt-fil</comment>
+ <comment xml:lang="ru">Файл Todo.txt</comment>
+ <comment xml:lang="pl">Plik Todo.txt</comment>
+ <comment xml:lang="ja">TODO文書</comment>
+ <comment xml:lang="it">File todo.txt</comment>
+ <comment xml:lang="es">archivo Todo.txt</comment>
+ <comment xml:lang="de">Todo.txt-Datei</comment>
+ <sub-class-of type="text/plain"/>
+ <magic priority="10">
+ <match type="string" value="(A) " offset="0"/>
+ <match type="string" value="x " offset="0"/>
+ </magic>
+ <glob weight="10" pattern="todo.txt"/>
+ </mime-type>
<mime-type type="text/x-rpm-spec">
<comment>RPM spec file</comment>
<comment xml:lang="zh_TW">RPM spec 規格檔</comment>
@@ -37759,8 +38276,9 @@ command to generate the output files.
<comment xml:lang="tr">RPM spec dosyası</comment>
<comment xml:lang="sv">RPM spec-fil</comment>
<comment xml:lang="sr">РПМ посебна датотека</comment>
- <comment xml:lang="sq">File specifikimi RPM</comment>
+ <comment xml:lang="sq">kartelë specifikimesh RPM</comment>
<comment xml:lang="sl">Določilna datoteka RPM</comment>
+ <comment xml:lang="si">RPM පිරිවිතර ගොනුව</comment>
<comment xml:lang="sk">Súbor RPM spec</comment>
<comment xml:lang="ru">Файл описания RPM</comment>
<comment xml:lang="ro">Fișier RPM spec</comment>
@@ -37777,6 +38295,7 @@ command to generate the output files.
<comment xml:lang="kk">RPM анықтама файлы</comment>
<comment xml:lang="ja">RPM spec ファイル</comment>
<comment xml:lang="it">File specifica RPM</comment>
+ <comment xml:lang="is">RPM spec-skrá</comment>
<comment xml:lang="id">Berkas spesifikasi RPM</comment>
<comment xml:lang="ia">File de specification RPM</comment>
<comment xml:lang="hu">RPM spec fájl</comment>
@@ -37798,6 +38317,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer spec RPM</comment>
<comment xml:lang="bg">Файл — спецификация за RPM</comment>
<comment xml:lang="be@latin">Specyfikacyjny fajł RPM</comment>
+ <comment xml:lang="be">файл спецыфікацыі RPM</comment>
<comment xml:lang="ar">ملف مواصفات RPM</comment>
<comment xml:lang="af">RPM-spesifikasielêer</comment>
<acronym>RPM</acronym>
@@ -37817,14 +38337,18 @@ command to generate the output files.
<comment xml:lang="tr">Sass CSS önişlemci dosyası</comment>
<comment xml:lang="sv">Sass CSS-preprocessorfil</comment>
<comment xml:lang="sr">датотека Сас ЦСС пре-процесора</comment>
+ <comment xml:lang="sq">kartelë pre-procesori CSS Sass</comment>
+ <comment xml:lang="si">Sass CSS පෙර-ප්‍රොසෙසර ගොනුව</comment>
<comment xml:lang="sk">Súbor Sass CSS pre-procesora</comment>
<comment xml:lang="ru">Файл препроцессора Sass CSS</comment>
<comment xml:lang="pt_BR">Arquivo de pré-processamento Sass CSS</comment>
<comment xml:lang="pl">Plik preprocesora CSS Sass</comment>
+ <comment xml:lang="nl">SaSS CSS-voorverwerkersbestand</comment>
<comment xml:lang="ko">Sass CSS 전처리기 파일</comment>
<comment xml:lang="kk">Sass CSS препроцессор файлы</comment>
<comment xml:lang="ja">Sass CSS プリプロセッサファイル</comment>
<comment xml:lang="it">File CSS Sass</comment>
+ <comment xml:lang="is">Sass CSS pre-processor skrá</comment>
<comment xml:lang="id">Berkas pre-processor Sass CSS</comment>
<comment xml:lang="hu">Sass CSS előfeldolgozó fájl</comment>
<comment xml:lang="hr">Sass CSS datoteka predobrade</comment>
@@ -37841,6 +38365,7 @@ command to generate the output files.
<comment xml:lang="cs">soubor preprocesoru Sass CSS</comment>
<comment xml:lang="ca">fitxer preprocessador CSS Sass</comment>
<comment xml:lang="bg">Директиви за препроцесора — Sass CSS</comment>
+ <comment xml:lang="be">файл прэпрацэсара Sass CSS</comment>
<comment xml:lang="ar">ملف Sass CSS قبل المعالج</comment>
<comment xml:lang="af">Sass CSS-voorverwerkerlêer</comment>
<acronym>Sass</acronym>
@@ -37853,11 +38378,13 @@ command to generate the output files.
<comment>Scala source code</comment>
<comment xml:lang="zh_TW">Scala 源碼</comment>
<comment xml:lang="zh_CN">Scala 源代码</comment>
- <comment xml:lang="uk">вихідний код мовою Scala</comment>
+ <comment xml:lang="uk">початковий код мовою Scala</comment>
<comment xml:lang="tr">Scala kaynak kodu</comment>
<comment xml:lang="sv">Scala-källkod</comment>
<comment xml:lang="sr">Скала изворни ко̂д</comment>
+ <comment xml:lang="sq">kod burim Scala</comment>
<comment xml:lang="sl">Izvorna koda Scala</comment>
+ <comment xml:lang="si">Scala මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód Scala</comment>
<comment xml:lang="ru">Исходный код Scala</comment>
<comment xml:lang="pt_BR">Código-fonte Scala</comment>
@@ -37871,6 +38398,7 @@ command to generate the output files.
<comment xml:lang="ka">Scala-ის საწყისი კოდი</comment>
<comment xml:lang="ja">Scala ソースコード</comment>
<comment xml:lang="it">Codice sorgente Scala</comment>
+ <comment xml:lang="is">Scala frumkóði</comment>
<comment xml:lang="id">Kode sumber Scala</comment>
<comment xml:lang="ia">Codice-fonte Scala</comment>
<comment xml:lang="hu">Scala forráskód</comment>
@@ -37890,6 +38418,7 @@ command to generate the output files.
<comment xml:lang="cs">zdrojový kód Scala</comment>
<comment xml:lang="ca">codi font en Scala</comment>
<comment xml:lang="bg">Изходен код — Scala</comment>
+ <comment xml:lang="be">зыходны код Scala</comment>
<comment xml:lang="ar">شفرة مصدر Scala</comment>
<comment xml:lang="af">Scala-bronkode</comment>
<sub-class-of type="text/plain"/>
@@ -37901,12 +38430,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">Scheme 源碼</comment>
<comment xml:lang="zh_CN">Scheme 源代码</comment>
<comment xml:lang="vi">Mã nguồn Scheme</comment>
- <comment xml:lang="uk">вихідний файл мовою Scheme</comment>
+ <comment xml:lang="uk">початковий код мовою Scheme</comment>
<comment xml:lang="tr">Scheme kaynak kodu</comment>
<comment xml:lang="sv">Scheme-källkod</comment>
<comment xml:lang="sr">Шемски изворни ко̂д</comment>
- <comment xml:lang="sq">Kod burues Scheme</comment>
+ <comment xml:lang="sq">kod burim Scheme</comment>
<comment xml:lang="sl">Datoteka izvorne kode Scheme</comment>
+ <comment xml:lang="si">යෝජනා ක්‍රම මූල කේතය</comment>
<comment xml:lang="sk">Zdrojový kód Scheme</comment>
<comment xml:lang="ru">Исходный код Scheme</comment>
<comment xml:lang="ro">Cod sursă Scheme</comment>
@@ -37924,6 +38454,7 @@ command to generate the output files.
<comment xml:lang="kk">Scheme бастапқы коды</comment>
<comment xml:lang="ja">Scheme ソースコード</comment>
<comment xml:lang="it">Codice sorgente Scheme</comment>
+ <comment xml:lang="is">Scheme frumkóði</comment>
<comment xml:lang="id">Kode program Scheme</comment>
<comment xml:lang="ia">Codice-fonte Scheme</comment>
<comment xml:lang="hu">Scheme-forráskód</comment>
@@ -37947,6 +38478,7 @@ command to generate the output files.
<comment xml:lang="ca">codi font en Scheme</comment>
<comment xml:lang="bg">Изходен код — Scheme</comment>
<comment xml:lang="be@latin">Kryničny kod Scheme</comment>
+ <comment xml:lang="be">зыходны код Scheme</comment>
<comment xml:lang="az">Sxem mənbə kodu</comment>
<comment xml:lang="ar">شفرة مصدر Scheme</comment>
<comment xml:lang="af">Scheme-bronkode</comment>
@@ -37961,13 +38493,17 @@ command to generate the output files.
<comment xml:lang="uk">файл засобу попередньої обробки SCSS</comment>
<comment xml:lang="tr">SCSS ön işleyici dosyası</comment>
<comment xml:lang="sv">SCSS förprocessorfil</comment>
+ <comment xml:lang="sq">kartelë pre-procesori SCSS</comment>
+ <comment xml:lang="si">SCSS පෙර සැකසුම් ගොනුව</comment>
<comment xml:lang="ru">Файл препроцессора SCSS</comment>
<comment xml:lang="pt_BR">Arquivo de pré-processamento SCSS</comment>
<comment xml:lang="pl">Plik preprocesora SCSS</comment>
+ <comment xml:lang="nl">SCSS-voorverwerkersbestand</comment>
<comment xml:lang="ko">SCSS 전처리 파일</comment>
<comment xml:lang="kk">SCSS препроцессор файлы</comment>
<comment xml:lang="ja">SCSS プリプロセッサファイル</comment>
<comment xml:lang="it">File SCSS</comment>
+ <comment xml:lang="is">SCSS pre-processor skrá</comment>
<comment xml:lang="id">Berkas preprosesor SCSS</comment>
<comment xml:lang="hu">SCSS előfeldolgozófájl</comment>
<comment xml:lang="hr">SCSS datoteka predobrade</comment>
@@ -37981,6 +38517,7 @@ command to generate the output files.
<comment xml:lang="da">SCSS pre-processor-fil</comment>
<comment xml:lang="ca">fitxer preprocessador SCSS</comment>
<comment xml:lang="bg">Директиви за препроцесора — SCSS</comment>
+ <comment xml:lang="be">файл прэпрацэсара SCSS</comment>
<comment xml:lang="ar">ملف SCSS قبل المعالج</comment>
<acronym>SCSS</acronym>
<expanded-acronym>Sassy CSS</expanded-acronym>
@@ -37997,8 +38534,9 @@ command to generate the output files.
<comment xml:lang="tr">Setext belgesi</comment>
<comment xml:lang="sv">Setext-dokument</comment>
<comment xml:lang="sr">Сетекст документ</comment>
- <comment xml:lang="sq">Dokument Setext</comment>
+ <comment xml:lang="sq">dokument Setext</comment>
<comment xml:lang="sl">Dokument Setext</comment>
+ <comment xml:lang="si">පෙළ ලේඛනය</comment>
<comment xml:lang="sk">Dokument Setext</comment>
<comment xml:lang="ru">Документ Setext</comment>
<comment xml:lang="ro">Document Setext</comment>
@@ -38016,6 +38554,7 @@ command to generate the output files.
<comment xml:lang="kk">Setext құжаты</comment>
<comment xml:lang="ja">Setext ドキュメント</comment>
<comment xml:lang="it">Documento Setext</comment>
+ <comment xml:lang="is">Setext skjal</comment>
<comment xml:lang="id">Dokumen Setext</comment>
<comment xml:lang="ia">Documento Setext</comment>
<comment xml:lang="hu">Setext-dokumentum</comment>
@@ -38039,6 +38578,7 @@ command to generate the output files.
<comment xml:lang="ca">document Setext</comment>
<comment xml:lang="bg">Документ — Setext</comment>
<comment xml:lang="be@latin">Dakument Setext</comment>
+ <comment xml:lang="be">дакумент Setext</comment>
<comment xml:lang="az">Setext sənədi</comment>
<comment xml:lang="ast">Documentu Setext</comment>
<comment xml:lang="ar">مستند Setext</comment>
@@ -38055,8 +38595,9 @@ command to generate the output files.
<comment xml:lang="tr">SQL kodu</comment>
<comment xml:lang="sv">SQL-kod</comment>
<comment xml:lang="sr">СКуЛ ко̂д</comment>
- <comment xml:lang="sq">Kod SQL</comment>
+ <comment xml:lang="sq">kod SQL</comment>
<comment xml:lang="sl">Datoteka kode SQL</comment>
+ <comment xml:lang="si">SQL කේතය</comment>
<comment xml:lang="sk">Kód SQL</comment>
<comment xml:lang="ru">Код SQL</comment>
<comment xml:lang="ro">Cod SQL</comment>
@@ -38074,6 +38615,7 @@ command to generate the output files.
<comment xml:lang="kk">SQL коды</comment>
<comment xml:lang="ja">SQL コード</comment>
<comment xml:lang="it">Codice SQL</comment>
+ <comment xml:lang="is">SQL kóði</comment>
<comment xml:lang="id">Kode SQL</comment>
<comment xml:lang="ia">Codice SQL</comment>
<comment xml:lang="hu">SQL-kód</comment>
@@ -38097,6 +38639,7 @@ command to generate the output files.
<comment xml:lang="ca">codi en SQL</comment>
<comment xml:lang="bg">Код — SQL</comment>
<comment xml:lang="be@latin">Kod SQL</comment>
+ <comment xml:lang="be">код SQL</comment>
<comment xml:lang="az">SQL kodu</comment>
<comment xml:lang="ar">شفرة SQL</comment>
<comment xml:lang="af">SQL-kode</comment>
@@ -38113,8 +38656,9 @@ command to generate the output files.
<comment xml:lang="tr">Tcl betiği</comment>
<comment xml:lang="sv">Tcl-skript</comment>
<comment xml:lang="sr">Тцл скрипта</comment>
- <comment xml:lang="sq">Script Tcl</comment>
+ <comment xml:lang="sq">programth Tcl</comment>
<comment xml:lang="sl">Skriptna datoteka Tcl</comment>
+ <comment xml:lang="si">Tcl පිටපත</comment>
<comment xml:lang="sk">Skript Tcl</comment>
<comment xml:lang="ru">Сценарий Tcl</comment>
<comment xml:lang="ro">Script Tcl</comment>
@@ -38132,6 +38676,7 @@ command to generate the output files.
<comment xml:lang="kk">Tcl сценарийі</comment>
<comment xml:lang="ja">Tcl スクリプト</comment>
<comment xml:lang="it">Script Tcl</comment>
+ <comment xml:lang="is">Tcl skrifta</comment>
<comment xml:lang="id">Skrip Tcl</comment>
<comment xml:lang="ia">Script Tcl</comment>
<comment xml:lang="hu">Tcl-parancsfájl</comment>
@@ -38154,6 +38699,7 @@ command to generate the output files.
<comment xml:lang="ca">script Tcl</comment>
<comment xml:lang="bg">Скрипт — Tcl</comment>
<comment xml:lang="be@latin">Skrypt Tcl</comment>
+ <comment xml:lang="be">скрыпт Tcl</comment>
<comment xml:lang="ar">سكربت Tcl</comment>
<comment xml:lang="af">Tcl-skrip</comment>
<alias type="text/x-tcl"/>
@@ -38170,8 +38716,9 @@ command to generate the output files.
<comment xml:lang="tr">TeX belgesi</comment>
<comment xml:lang="sv">TeX-dokument</comment>
<comment xml:lang="sr">ТеКс документ</comment>
- <comment xml:lang="sq">Dokument TeX</comment>
+ <comment xml:lang="sq">dokument TeX</comment>
<comment xml:lang="sl">Dokument TeX</comment>
+ <comment xml:lang="si">TeX ලේඛනය</comment>
<comment xml:lang="sk">Dokument TeX</comment>
<comment xml:lang="ru">Документ TeX</comment>
<comment xml:lang="ro">Document TeX</comment>
@@ -38189,6 +38736,7 @@ command to generate the output files.
<comment xml:lang="kk">TeX құжаты</comment>
<comment xml:lang="ja">TeX ドキュメント</comment>
<comment xml:lang="it">Documento TeX</comment>
+ <comment xml:lang="is">TeX skjal</comment>
<comment xml:lang="id">Dokumen TeX</comment>
<comment xml:lang="ia">Documento TeX</comment>
<comment xml:lang="hu">TeX-dokumentum</comment>
@@ -38212,6 +38760,7 @@ command to generate the output files.
<comment xml:lang="ca">document TeX</comment>
<comment xml:lang="bg">Документ — TeX</comment>
<comment xml:lang="be@latin">Dakument TeX</comment>
+ <comment xml:lang="be">дакумент TeX</comment>
<comment xml:lang="ast">Documentu TeX</comment>
<comment xml:lang="ar">مستند TeX</comment>
<comment xml:lang="af">TeX-dokument</comment>
@@ -38240,8 +38789,9 @@ command to generate the output files.
<comment xml:lang="tr">TeXInfo belgesi</comment>
<comment xml:lang="sv">TeXInfo-dokument</comment>
<comment xml:lang="sr">ТеКсинфо документ</comment>
- <comment xml:lang="sq">Dokument TeXInfo</comment>
+ <comment xml:lang="sq">dokument TeXInfo</comment>
<comment xml:lang="sl">Dokument TeXInfo</comment>
+ <comment xml:lang="si">TeXInfo ලේඛනය</comment>
<comment xml:lang="sk">Dokument TeXInfo</comment>
<comment xml:lang="ru">Документ TeXInfo</comment>
<comment xml:lang="ro">Document TexInfo</comment>
@@ -38259,6 +38809,7 @@ command to generate the output files.
<comment xml:lang="kk">TeXInfo құжаты</comment>
<comment xml:lang="ja">TeXInfo ドキュメント</comment>
<comment xml:lang="it">Documento TeXInfo</comment>
+ <comment xml:lang="is">TeXInfo skjal</comment>
<comment xml:lang="id">Dokumen TeXInfo</comment>
<comment xml:lang="ia">Documento TeXInfo</comment>
<comment xml:lang="hu">TeXInfo-dokumentum</comment>
@@ -38282,6 +38833,7 @@ command to generate the output files.
<comment xml:lang="ca">document TeXInfo</comment>
<comment xml:lang="bg">Документ — TeXInfo</comment>
<comment xml:lang="be@latin">Dakument TeXInfo</comment>
+ <comment xml:lang="be">дакумент TeXInfo</comment>
<comment xml:lang="az">TeXInfo sənədi</comment>
<comment xml:lang="ast">Documentu TeXInfo</comment>
<comment xml:lang="ar">مستند TeXInfo</comment>
@@ -38290,6 +38842,21 @@ command to generate the output files.
<glob pattern="*.texi"/>
<glob pattern="*.texinfo"/>
</mime-type>
+ <mime-type type="text/x-typst">
+ <comment>Typst document</comment>
+ <comment xml:lang="uk">документ Typst</comment>
+ <comment xml:lang="sv">Typst-dokument</comment>
+ <comment xml:lang="ru">Документ Typst</comment>
+ <comment xml:lang="pl">Dokument Typst</comment>
+ <comment xml:lang="it">Documento Typst</comment>
+ <comment xml:lang="gl">Documento de Typst</comment>
+ <comment xml:lang="eu">Typst dokumentua</comment>
+ <comment xml:lang="es">documento de Typst</comment>
+ <comment xml:lang="de">Typst-Dokument</comment>
+ <comment xml:lang="be">дакумент Typst</comment>
+ <sub-class-of type="text/plain"/>
+ <glob pattern="*.typ"/>
+ </mime-type>
<mime-type type="text/x-troff-me">
<comment>Troff ME input document</comment>
<comment xml:lang="zh_TW">Troff ME 輸入文件</comment>
@@ -38299,8 +38866,9 @@ command to generate the output files.
<comment xml:lang="tr">Troff ME girdi belgesi</comment>
<comment xml:lang="sv">Troff ME-indatadokument</comment>
<comment xml:lang="sr">Трофф МЕ улазни документ</comment>
- <comment xml:lang="sq">Dokument i input Troff ME</comment>
+ <comment xml:lang="sq">dokument ME input-i për Troff</comment>
<comment xml:lang="sl">Vnosni dokument Troff ME</comment>
+ <comment xml:lang="si">ට්‍රොෆ් ME ආදාන ලේඛනය</comment>
<comment xml:lang="sk">Vstupný dokument Troff ME</comment>
<comment xml:lang="ru">Входной документ Troff ME</comment>
<comment xml:lang="ro">Document intrare Troff ME</comment>
@@ -38318,6 +38886,7 @@ command to generate the output files.
<comment xml:lang="kk">Troff ME кіріс құжаты</comment>
<comment xml:lang="ja">Troff ME 入力ドキュメント</comment>
<comment xml:lang="it">Documento di input Troff ME</comment>
+ <comment xml:lang="is">Troff ME inngangsskjal</comment>
<comment xml:lang="id">Dokumen masukan Troff ME</comment>
<comment xml:lang="ia">Documento de entrata Troff ME</comment>
<comment xml:lang="hu">Troff ME bemeneti dokumentum</comment>
@@ -38340,6 +38909,7 @@ command to generate the output files.
<comment xml:lang="ca">document d'entrada Troff ME</comment>
<comment xml:lang="bg">Изходен документ — Troff ME</comment>
<comment xml:lang="be@latin">Uvodny dakument Troff ME</comment>
+ <comment xml:lang="be">уваходны дакумент Troff ME</comment>
<comment xml:lang="ast">Documentu d'entrada de Troff ME</comment>
<comment xml:lang="ar">مستند Troff ME input</comment>
<comment xml:lang="af">Troff ME-toevoerdokument</comment>
@@ -38355,8 +38925,9 @@ command to generate the output files.
<comment xml:lang="tr">Troff MM girdi belgesi</comment>
<comment xml:lang="sv">Troff MM-indatadokument</comment>
<comment xml:lang="sr">Трофф ММ улазни документ</comment>
- <comment xml:lang="sq">Dokument i input Troff MM</comment>
+ <comment xml:lang="sq">dokument MM input-i për Troff</comment>
<comment xml:lang="sl">Vnosni dokument Troff MM</comment>
+ <comment xml:lang="si">Troff MM ආදාන ලේඛනය</comment>
<comment xml:lang="sk">Vstupný dokument Troff MM</comment>
<comment xml:lang="ru">Входной документ Troff MM</comment>
<comment xml:lang="ro">Document intrare Troff MM</comment>
@@ -38374,6 +38945,7 @@ command to generate the output files.
<comment xml:lang="kk">Troff MM кіріс құжаты</comment>
<comment xml:lang="ja">Troff MM 入力ドキュメント</comment>
<comment xml:lang="it">Documento di input Troff MM</comment>
+ <comment xml:lang="is">Troff MM inngangsskjal</comment>
<comment xml:lang="id">Dokumen masukan Troff MM</comment>
<comment xml:lang="ia">Documento de entrata Troff MM</comment>
<comment xml:lang="hu">Troff MM bemeneti dokumentum</comment>
@@ -38396,6 +38968,7 @@ command to generate the output files.
<comment xml:lang="ca">document d'entrada Troff MM</comment>
<comment xml:lang="bg">Изходен документ — Troff MM</comment>
<comment xml:lang="be@latin">Uvodny dakument Troff MM</comment>
+ <comment xml:lang="be">уваходны дакумент Troff MM</comment>
<comment xml:lang="ast">Documentu d'entrada de Troff MM</comment>
<comment xml:lang="ar">مستند Troff MM input</comment>
<comment xml:lang="af">Troff MM-toevoerdokument</comment>
@@ -38411,8 +38984,9 @@ command to generate the output files.
<comment xml:lang="tr">Troff MS girdi belgesi</comment>
<comment xml:lang="sv">Troff MS-indatadokument</comment>
<comment xml:lang="sr">Трофф МС улазни документ</comment>
- <comment xml:lang="sq">Dokument i input Troff MS</comment>
+ <comment xml:lang="sq">dokument MS input-i për Troff</comment>
<comment xml:lang="sl">Vnosni dokument Troff MS</comment>
+ <comment xml:lang="si">Troff MS ආදාන ලේඛනය</comment>
<comment xml:lang="sk">Vstupný dokument Troff MS</comment>
<comment xml:lang="ru">Входной документ Troff MS</comment>
<comment xml:lang="ro">Document intrare Troff MS</comment>
@@ -38430,6 +39004,7 @@ command to generate the output files.
<comment xml:lang="kk">Troff MS кіріс құжаты</comment>
<comment xml:lang="ja">Troff MS 入力ドキュメント</comment>
<comment xml:lang="it">Documento di input Troff MS</comment>
+ <comment xml:lang="is">Troff MS inngangsskjal</comment>
<comment xml:lang="id">Dokumen masukan Troff MS</comment>
<comment xml:lang="ia">Documento de entrata Troff MS</comment>
<comment xml:lang="hu">Troff MS bemeneti dokumentum</comment>
@@ -38452,6 +39027,7 @@ command to generate the output files.
<comment xml:lang="ca">document d'entrada Troff MS</comment>
<comment xml:lang="bg">Изходен документ — Troff MS</comment>
<comment xml:lang="be@latin">Uvodny dakument Troff MS</comment>
+ <comment xml:lang="be">уваходны дакумент Troff MS</comment>
<comment xml:lang="ast">Documentu d'entrada de Troff MS</comment>
<comment xml:lang="ar">مستند Troff MS input</comment>
<comment xml:lang="af">Troff MS-toevoerdokument</comment>
@@ -38466,19 +39042,25 @@ command to generate the output files.
<comment xml:lang="tr">Twig şablonu</comment>
<comment xml:lang="sv">Twig-mall</comment>
<comment xml:lang="sr">Твиг шаблон</comment>
+ <comment xml:lang="sq">gjedhe Twig</comment>
+ <comment xml:lang="sl">Predloga Twig</comment>
+ <comment xml:lang="si">අතු අච්චුව</comment>
<comment xml:lang="sk">Šablóna Twig</comment>
<comment xml:lang="ru">Шаблон Twig</comment>
<comment xml:lang="pt_BR">Modelo Twig</comment>
<comment xml:lang="pl">Szablon Twig</comment>
<comment xml:lang="oc">modèl Twig</comment>
+ <comment xml:lang="nl">Twig-sjabloon</comment>
<comment xml:lang="ko">Twig 문서 서식</comment>
<comment xml:lang="kk">Twig үлгісі</comment>
<comment xml:lang="ja">Twig テンプレート</comment>
<comment xml:lang="it">Modello twig</comment>
+ <comment xml:lang="is">Twig-sniðmát</comment>
<comment xml:lang="id">Templat Twig</comment>
<comment xml:lang="hu">Twig-sablon</comment>
<comment xml:lang="hr">Twig predložak</comment>
<comment xml:lang="he">תבנית Twig</comment>
+ <comment xml:lang="gl">Plantilla de Twig</comment>
<comment xml:lang="ga">teimpléad Twig</comment>
<comment xml:lang="fur">model Twig</comment>
<comment xml:lang="fr">modèle Twig</comment>
@@ -38491,6 +39073,7 @@ command to generate the output files.
<comment xml:lang="cs">šablona Twig</comment>
<comment xml:lang="ca">plantilla Twig</comment>
<comment xml:lang="bg">Шаблон — Twig</comment>
+ <comment xml:lang="be">шаблон Twig</comment>
<comment xml:lang="ar">قالب Twig</comment>
<comment xml:lang="af">Twig-sjabloon</comment>
<sub-class-of type="text/plain"/>
@@ -38506,8 +39089,9 @@ command to generate the output files.
<comment xml:lang="tr">X-Motif UIL tablosu</comment>
<comment xml:lang="sv">X-Motif UIL-tabell</comment>
<comment xml:lang="sr">Икс-Мотиф УИЛ табела</comment>
- <comment xml:lang="sq">Tabelë X-Motif UIL</comment>
+ <comment xml:lang="sq">tabelë X-Motif UIL</comment>
<comment xml:lang="sl">Preglednica X-Motif UIL</comment>
+ <comment xml:lang="si">X-Motif UIL වගුව</comment>
<comment xml:lang="sk">Tabuľka X-Motif UIL</comment>
<comment xml:lang="ru">Таблица UIL X-Motif</comment>
<comment xml:lang="ro">Tabel X-Motif UIL</comment>
@@ -38525,6 +39109,7 @@ command to generate the output files.
<comment xml:lang="kk">X-Motif UIL кестесі</comment>
<comment xml:lang="ja">X-Motif UIL 表</comment>
<comment xml:lang="it">Tabella UIL X-Motif</comment>
+ <comment xml:lang="is">X-Motif UIL tafla</comment>
<comment xml:lang="id">Tabel X-Motif UIL</comment>
<comment xml:lang="ia">Tabella X-Motif UIL</comment>
<comment xml:lang="hu">X-Motif UIL-táblázat</comment>
@@ -38546,62 +39131,24 @@ command to generate the output files.
<comment xml:lang="ca">taula UIL de X-Motif</comment>
<comment xml:lang="bg">Таблица — X-Motif UIL</comment>
<comment xml:lang="be@latin">Tablica X-Motif UIL</comment>
+ <comment xml:lang="be">табліца X-Motif UIL</comment>
<comment xml:lang="ar">جدول X-Motif UIL</comment>
<comment xml:lang="af">X-Motif UIL-tabel</comment>
<sub-class-of type="text/plain"/>
<glob pattern="*.uil"/>
</mime-type>
<mime-type type="text/x-uri">
- <comment>resource location</comment>
- <comment xml:lang="zh_TW">資源位置</comment>
- <comment xml:lang="zh_CN">资源位置</comment>
- <comment xml:lang="vi">địa điểm tài nguyên</comment>
+ <comment>Resource location</comment>
<comment xml:lang="uk">розташування ресурсу</comment>
- <comment xml:lang="tr">kaynak ayırma</comment>
- <comment xml:lang="sv">resursplats</comment>
- <comment xml:lang="sr">путања изворишта</comment>
- <comment xml:lang="sq">Pozicion rezerve</comment>
- <comment xml:lang="sl">mesto vira</comment>
- <comment xml:lang="sk">Umiestnenie zdroja</comment>
+ <comment xml:lang="sv">Resursplats</comment>
<comment xml:lang="ru">Расположение ресурса</comment>
- <comment xml:lang="ro">locație de resursă</comment>
- <comment xml:lang="pt_BR">Localização de recurso</comment>
- <comment xml:lang="pt">localização de recurso</comment>
<comment xml:lang="pl">Położenie zasobu</comment>
- <comment xml:lang="oc">localizacion de ressorsa</comment>
- <comment xml:lang="nn">ressursplassering</comment>
- <comment xml:lang="nl">bronlocatie</comment>
- <comment xml:lang="nb">ressurslokasjon</comment>
- <comment xml:lang="ms">Lokasi sumber</comment>
- <comment xml:lang="lv">resursa atrašanās vieta</comment>
- <comment xml:lang="lt">resurso vieta</comment>
- <comment xml:lang="ko">자원 위치</comment>
- <comment xml:lang="kk">ресурс орналасуы</comment>
- <comment xml:lang="ja">リソースの場所</comment>
<comment xml:lang="it">Posizione risorsa</comment>
- <comment xml:lang="id">lokasi sumber daya</comment>
- <comment xml:lang="ia">Loco de ressources</comment>
- <comment xml:lang="hu">erőforrás-hely</comment>
- <comment xml:lang="hr">Lokacija resursa</comment>
- <comment xml:lang="he">מיקום של משאב</comment>
- <comment xml:lang="gl">localización do recurso</comment>
- <comment xml:lang="ga">suíomh acmhainne</comment>
- <comment xml:lang="fur">posizion risorse</comment>
- <comment xml:lang="fr">localisation de ressource</comment>
- <comment xml:lang="fo">tilfeingisstaður</comment>
- <comment xml:lang="fi">resurssisijainti</comment>
- <comment xml:lang="eu">baliabidearen kokalekua</comment>
- <comment xml:lang="es">ubicación del recurso</comment>
- <comment xml:lang="eo">loko de risurco</comment>
- <comment xml:lang="en_GB">resource location</comment>
- <comment xml:lang="el">Τοποθεσία πόρου</comment>
+ <comment xml:lang="gl">Localización de recurso</comment>
+ <comment xml:lang="eu">Baliabideen kokalekua</comment>
+ <comment xml:lang="es">ubicación de recurso</comment>
<comment xml:lang="de">Ressourcenort</comment>
- <comment xml:lang="da">resurseplacering</comment>
- <comment xml:lang="cs">umístění prostředku</comment>
- <comment xml:lang="ca">localització de recurs</comment>
- <comment xml:lang="bg">Местоположение на ресурс</comment>
- <comment xml:lang="be@latin">pałažeńnie resursu</comment>
- <comment xml:lang="ar">موقع مورد</comment>
+ <comment xml:lang="be">размяшчэнне рэсурсу</comment>
<sub-class-of type="text/plain"/>
<!-- Note: text/uri-list is reserved by the XDND protocol! -->
</mime-type>
@@ -38614,17 +39161,20 @@ command to generate the output files.
<comment xml:lang="sv">uuencode-fil</comment>
<comment xml:lang="sr">уукодирана датотека</comment>
<comment xml:lang="sl">Datoteka uuencode</comment>
+ <comment xml:lang="si">uuencoded ගොනුව</comment>
<comment xml:lang="sk">Súbor v kódovaní uuencode</comment>
<comment xml:lang="ru">Файл, кодированный uuencode</comment>
<comment xml:lang="pt_BR">Arquivo codificado UUE</comment>
<comment xml:lang="pt">ficheiro uuencoded</comment>
<comment xml:lang="pl">Plik zakodowany za pomocą uuencode</comment>
<comment xml:lang="oc">fichièr uuencodat</comment>
+ <comment xml:lang="nl">uuencoded bestand</comment>
<comment xml:lang="lv">uu kodējuma datne</comment>
<comment xml:lang="ko">uuencoded 파일</comment>
<comment xml:lang="kk">uuencode кодталған файлы</comment>
<comment xml:lang="ja">未エンコードファイル</comment>
<comment xml:lang="it">File uuencoded</comment>
+ <comment xml:lang="is">uuencoded skrá</comment>
<comment xml:lang="id">berkas ter-uuencode</comment>
<comment xml:lang="ia">File in uuencode</comment>
<comment xml:lang="hu">uuencode-olt fájl</comment>
@@ -38644,6 +39194,7 @@ command to generate the output files.
<comment xml:lang="cs">soubor kódovaný pomocí uuencoding</comment>
<comment xml:lang="ca">fitxer uuencoded</comment>
<comment xml:lang="bg">Файл — кодиран с uuencode</comment>
+ <comment xml:lang="be">файл, закадаваны uuencode</comment>
<comment xml:lang="ar">ملف uuencoded</comment>
<comment xml:lang="af">uu-geënkodeerde lêer</comment>
<sub-class-of type="text/plain"/>
@@ -38653,6 +39204,34 @@ command to generate the output files.
</magic>
<alias type="zz-application/zz-winassoc-uu"/>
</mime-type>
+ <mime-type type="text/x-basic">
+ <comment>BASIC program</comment>
+ <comment xml:lang="uk">програма BASIC</comment>
+ <comment xml:lang="sv">BASIC-program</comment>
+ <comment xml:lang="ru">Программа BASIC</comment>
+ <comment xml:lang="pl">Program BASIC</comment>
+ <comment xml:lang="es">programa en BASIC</comment>
+ <comment xml:lang="de">BASIC-Programm</comment>
+ <sub-class-of type="text/plain"/>
+ <generic-icon name="text-x-script"/>
+ <glob pattern="*.bas"/>
+ </mime-type>
+ <mime-type type="text/x-vb">
+ <comment>Visual Basic .NET source code</comment>
+ <comment xml:lang="uk">початковий код Visual Basic .NET</comment>
+ <comment xml:lang="sv">Visual Basic .NET-källkod</comment>
+ <comment xml:lang="ru">Исходный код Visual Basic .NET</comment>
+ <comment xml:lang="pl">Kod źródłowy Visual Basic .NET</comment>
+ <comment xml:lang="es">código fuente en Visual Basic .NET</comment>
+ <comment xml:lang="de">Visual-Basic-.NET-Quelltext</comment>
+ <sub-class-of type="text/plain"/>
+ <magic>
+ <match type="string" value="Imports" offset="0"/>
+ <match type="string" value="Module" offset="0"/>
+ <match type="string" value="REM" offset="0"/>
+ </magic>
+ <glob pattern="*.vb"/>
+ </mime-type>
<mime-type type="text/vbscript">
<comment>VBScript program</comment>
<comment xml:lang="zh_TW">VBScript 程式</comment>
@@ -38660,28 +39239,54 @@ command to generate the output files.
<comment xml:lang="uk">програма мовою VBScript</comment>
<comment xml:lang="tr">VBScript programı</comment>
<comment xml:lang="sv">VBScript-program</comment>
+ <comment xml:lang="sl">Programska datoteka VBScript</comment>
+ <comment xml:lang="si">VBScript වැඩසටහන</comment>
+ <comment xml:lang="ru">Программа VBScript</comment>
<comment xml:lang="pt_BR">Programa VBScript</comment>
<comment xml:lang="pl">Pogram VBScript</comment>
+ <comment xml:lang="oc">programa VBScript</comment>
+ <comment xml:lang="nl">VBScript-programma</comment>
<comment xml:lang="ko">VBScript 프로그램</comment>
+ <comment xml:lang="kk">VBScript бағдарламасы</comment>
<comment xml:lang="ja">VBScript プログラム</comment>
<comment xml:lang="it">Programma VBScript</comment>
+ <comment xml:lang="is">VBScript forrit</comment>
<comment xml:lang="id">program VBScript</comment>
<comment xml:lang="hu">VBScript program</comment>
<comment xml:lang="hr">VBScript program</comment>
<comment xml:lang="he">תכנית VBScript</comment>
+ <comment xml:lang="gl">Programa VBScript</comment>
<comment xml:lang="fr">programme VBScript</comment>
<comment xml:lang="fi">VBScript-ohjelma</comment>
+ <comment xml:lang="eu">VBScript programa</comment>
<comment xml:lang="es">programa en VBScript</comment>
<comment xml:lang="en_GB">VBScript program</comment>
<comment xml:lang="de">VBScript-Programm</comment>
<comment xml:lang="da">VBScript-program</comment>
<comment xml:lang="ca">programa VBScript</comment>
+ <comment xml:lang="be">праграма VBScript</comment>
<comment xml:lang="ar">برنامج في بي سكريبت</comment>
<alias type="text/vbs"/>
<sub-class-of type="text/plain"/>
<generic-icon name="text-x-script"/>
<glob pattern="*.vbs"/>
</mime-type>
+ <mime-type type="text/vbscript.encode">
+ <comment>Encoded VBScript program</comment>
+ <comment xml:lang="uk">кодована програма VBScript</comment>
+ <comment xml:lang="sv">Kodat VBScript-program</comment>
+ <comment xml:lang="ru">Зашифрованная программа на VBScript</comment>
+ <comment xml:lang="pl">Zakodowany program VBScript</comment>
+ <comment xml:lang="es">Programa en VBScript codificado</comment>
+ <comment xml:lang="de">Verschlüsseltes VBScript-Programm</comment>
+ <sub-class-of type="application/x-executable"/>
+ <sub-class-of type="text/plain"/>
+ <generic-icon name="text-x-script"/>
+ <magic>
+ <match type="string" value="#@~^" offset="0"/>
+ </magic>
+ <glob pattern="*.vbe"/>
+ </mime-type>
<mime-type type="text/x-xmi">
<comment>XMI file</comment>
<comment xml:lang="zh_TW">XMI 檔</comment>
@@ -38691,8 +39296,9 @@ command to generate the output files.
<comment xml:lang="tr">XMI dosyası</comment>
<comment xml:lang="sv">XMI-fil</comment>
<comment xml:lang="sr">ИксМИ датотека</comment>
- <comment xml:lang="sq">File XMI</comment>
+ <comment xml:lang="sq">kartelë XMI</comment>
<comment xml:lang="sl">Datoteka XMI</comment>
+ <comment xml:lang="si">XMI ගොනුව</comment>
<comment xml:lang="sk">Súbor XMI</comment>
<comment xml:lang="ru">Файл XMI</comment>
<comment xml:lang="ro">Fișier XMI</comment>
@@ -38709,6 +39315,7 @@ command to generate the output files.
<comment xml:lang="kk">XMI файлы</comment>
<comment xml:lang="ja">XMI ファイル</comment>
<comment xml:lang="it">File XMI</comment>
+ <comment xml:lang="is">XMI-skrá</comment>
<comment xml:lang="id">Berkas XMI</comment>
<comment xml:lang="ia">File XMI</comment>
<comment xml:lang="hu">XMI fájl</comment>
@@ -38731,6 +39338,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer XMI</comment>
<comment xml:lang="bg">Файл — XMI</comment>
<comment xml:lang="be@latin">Fajł XMI</comment>
+ <comment xml:lang="be">файл XMI</comment>
<comment xml:lang="ar">ملف XMI</comment>
<comment xml:lang="af">XMI-lêer</comment>
<acronym>XMI</acronym>
@@ -38749,8 +39357,9 @@ command to generate the output files.
<comment xml:lang="tr">XSL FO dosyası</comment>
<comment xml:lang="sv">XSL FO-fil</comment>
<comment xml:lang="sr">ИксСЛ ФО датотека</comment>
- <comment xml:lang="sq">File XSL FO</comment>
+ <comment xml:lang="sq">kartelë XSL FO</comment>
<comment xml:lang="sl">Datoteka XSL FO</comment>
+ <comment xml:lang="si">XSL FO ගොනුව</comment>
<comment xml:lang="sk">Súbor XSL FO</comment>
<comment xml:lang="ru">Файл XSL FO</comment>
<comment xml:lang="ro">Fișier XSL FO</comment>
@@ -38767,6 +39376,7 @@ command to generate the output files.
<comment xml:lang="kk">XSL FO файлы</comment>
<comment xml:lang="ja">XSL FO ファイル</comment>
<comment xml:lang="it">File XSL FO</comment>
+ <comment xml:lang="is">XSL FO skrá</comment>
<comment xml:lang="id">Berkas XSL FO</comment>
<comment xml:lang="ia">File XSL FO</comment>
<comment xml:lang="hu">XSL FO fájl</comment>
@@ -38789,6 +39399,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer FO XSL</comment>
<comment xml:lang="bg">Форматиращ файл — XSL FO</comment>
<comment xml:lang="be@latin">Fajł XSL FO</comment>
+ <comment xml:lang="be">файл XSL FO</comment>
<comment xml:lang="ar">ملف XSL FO</comment>
<comment xml:lang="af">XSL FO-lêer</comment>
<acronym>XSL FO</acronym>
@@ -38807,8 +39418,9 @@ command to generate the output files.
<comment xml:lang="tr">iptables yapılandırma dosyası</comment>
<comment xml:lang="sv">iptables-konfigurationsfil</comment>
<comment xml:lang="sr">датотека подешавања иптабела</comment>
- <comment xml:lang="sq">File konfigurimi iptables</comment>
+ <comment xml:lang="sq">kartelë formësimi iptables</comment>
<comment xml:lang="sl">nastavitvena datoteka iptables</comment>
+ <comment xml:lang="si">iptables වින්‍යාස ගොනුව</comment>
<comment xml:lang="sk">Súbor nastavení iptables</comment>
<comment xml:lang="ru">Файл настроек iptables</comment>
<comment xml:lang="ro">fișier configurare iptables</comment>
@@ -38825,6 +39437,7 @@ command to generate the output files.
<comment xml:lang="kk">iptables баптаулар файлы</comment>
<comment xml:lang="ja">iptables 設定ファイル</comment>
<comment xml:lang="it">File configurazione iptables</comment>
+ <comment xml:lang="is">iptables stillingaskrá</comment>
<comment xml:lang="id">berkas konfigurasi iptables</comment>
<comment xml:lang="ia">File de configuration IPTables</comment>
<comment xml:lang="hu">iptables beállítófájl</comment>
@@ -38846,6 +39459,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer de configuració d'iptables</comment>
<comment xml:lang="bg">Настройки за iptables</comment>
<comment xml:lang="be@latin">kanfihuracyjny fajł iptables</comment>
+ <comment xml:lang="be">файл канфігурацыі iptables</comment>
<comment xml:lang="ast">ficheru de configuración d'iptables</comment>
<comment xml:lang="ar">ملف إعداد iptables</comment>
<comment xml:lang="af">iptables-opstellingslêer</comment>
@@ -38880,18 +39494,23 @@ command to generate the output files.
<comment xml:lang="tr">D-Bus hizmeti dosyası</comment>
<comment xml:lang="sv">D-BUS-tjänstfil</comment>
<comment xml:lang="sr">датотека услуге Д-сабирнице</comment>
+ <comment xml:lang="sq">kartelë shërbimi D-Bus</comment>
+ <comment xml:lang="si">D-බස් සේවා ගොනුව</comment>
<comment xml:lang="sk">Súbor služby D-Bus</comment>
<comment xml:lang="ru">Файл службы D-Bus</comment>
<comment xml:lang="pt_BR">Arquivo de serviço do D-Bus</comment>
<comment xml:lang="pl">Plik usługi D-Bus</comment>
+ <comment xml:lang="nl">D-Bus-servicebestand</comment>
<comment xml:lang="ko">D-Bus 서비스 파일</comment>
<comment xml:lang="kk">D-Bus қызметтік файлы</comment>
<comment xml:lang="ja">D-Bus サービスファイル</comment>
<comment xml:lang="it">File servizio D-Bus</comment>
+ <comment xml:lang="is">D-Bus þjónustuskrá</comment>
<comment xml:lang="id">Berkas layanan D-Bus</comment>
<comment xml:lang="hu">D-Bus szolgáltatás fájl</comment>
<comment xml:lang="hr">Datoteka D-Bus usluge</comment>
<comment xml:lang="he">קובץ שירות D-Bus</comment>
+ <comment xml:lang="gl">Ficheiro de servizo D-Bus</comment>
<comment xml:lang="ga">comhad seirbhíse D-Bus</comment>
<comment xml:lang="fur">file di servizi D-Bus</comment>
<comment xml:lang="fr">fichier de service D-Bus</comment>
@@ -38904,6 +39523,7 @@ command to generate the output files.
<comment xml:lang="cs">soubor služby D-Bus</comment>
<comment xml:lang="ca">fitxer de servei de D-Bus</comment>
<comment xml:lang="bg">Услуга — D-Bus</comment>
+ <comment xml:lang="be">файл сэрвісу D-Bus</comment>
<comment xml:lang="ar">ملف خدمة دي-باص</comment>
<comment xml:lang="af">D-Bus-dienslêer</comment>
<sub-class-of type="text/plain"/>
@@ -38914,40 +39534,18 @@ command to generate the output files.
<glob pattern="*.service"/>
</mime-type>
<mime-type type="text/x-systemd-unit">
- <comment>systemd unit file</comment>
- <comment xml:lang="zh_TW">systemd 單位檔</comment>
- <comment xml:lang="zh_CN">systemd 单元文件</comment>
+ <comment>Systemd unit file</comment>
<comment xml:lang="uk">файл модуля systemd</comment>
- <comment xml:lang="tr">systemd birim dosyası</comment>
- <comment xml:lang="sv">systemd-enhetsfil</comment>
- <comment xml:lang="sr">датотека јединице системд-а</comment>
- <comment xml:lang="sk">Súbor jednotky systemd</comment>
+ <comment xml:lang="sv">Systemd-enhetsfil</comment>
<comment xml:lang="ru">Модульный файл Systemd</comment>
- <comment xml:lang="pt_BR">Arquivo de unit do systemd</comment>
<comment xml:lang="pl">Plik jednostki systemd</comment>
- <comment xml:lang="ko">systemd 유닛 파일</comment>
- <comment xml:lang="kk">systemd юнит файлы</comment>
- <comment xml:lang="ja">systemd ユニットファイル</comment>
+ <comment xml:lang="ja">systemdのunitファイル</comment>
<comment xml:lang="it">File unità systemd</comment>
- <comment xml:lang="id">berkas unit systemd</comment>
- <comment xml:lang="hu">systemd egység fájl</comment>
- <comment xml:lang="hr">Datoteka systemd jedinice</comment>
- <comment xml:lang="he">קובץ יחידת systemd</comment>
- <comment xml:lang="ga">comhad aonaid systemd</comment>
- <comment xml:lang="fur">file unitât di systemd</comment>
- <comment xml:lang="fr">fichier d'unité systemd</comment>
- <comment xml:lang="fi">systemd-yksikkötiedosto</comment>
- <comment xml:lang="eu">systemd unitate fitxategia</comment>
- <comment xml:lang="es">archivo de unidad de systemd</comment>
- <comment xml:lang="en_GB">systemd unit file</comment>
- <comment xml:lang="de">systemd-Einheitsdatei</comment>
- <comment xml:lang="da">systemd unit-fil</comment>
- <comment xml:lang="cs">jednotkový soubor systemd</comment>
- <comment xml:lang="ca">fitxer d'unitat de systemd</comment>
- <comment xml:lang="bg">Елемент — systemd</comment>
- <comment xml:lang="ast">ficheru d'unidaes de systemd</comment>
- <comment xml:lang="ar">ملف وحدة systemd</comment>
- <comment xml:lang="af">systemd-eenheidlêer</comment>
+ <comment xml:lang="gl">Ficheiro de unidade de Systemd</comment>
+ <comment xml:lang="eu">Systemd unitate-fitxategia</comment>
+ <comment xml:lang="es">archivo de unidad de Systemd</comment>
+ <comment xml:lang="de">Systemd-Einheitendatei</comment>
+ <comment xml:lang="be">файл адзінкі systemd</comment>
<sub-class-of type="text/plain"/>
<magic>
<!-- Matches part-way through the file. -->
@@ -38998,8 +39596,9 @@ command to generate the output files.
<comment xml:lang="tr">XSLT çalışma sayfası</comment>
<comment xml:lang="sv">XSLT-stilmall</comment>
<comment xml:lang="sr">ИксСЛТ стилски лист</comment>
- <comment xml:lang="sq">Fletë stili XSLT</comment>
+ <comment xml:lang="sq">fletëstil XSLT</comment>
<comment xml:lang="sl">Slogovna predloga XSLT</comment>
+ <comment xml:lang="si">XSLT මෝස්තර පත්‍රිකාව</comment>
<comment xml:lang="sk">Štýl XSLT</comment>
<comment xml:lang="ru">Таблица стилей XSLT</comment>
<comment xml:lang="ro">Fișă de stil XSLT</comment>
@@ -39017,6 +39616,7 @@ command to generate the output files.
<comment xml:lang="kk">XSLT стильдер кестесі</comment>
<comment xml:lang="ja">XSLT スタイルシート</comment>
<comment xml:lang="it">Foglio di stile XSLT</comment>
+ <comment xml:lang="is">XSLT stílblað</comment>
<comment xml:lang="id">Lembar gaya XSLT</comment>
<comment xml:lang="ia">Folio de stilo XSLT</comment>
<comment xml:lang="hu">XSLT-stíluslap</comment>
@@ -39033,12 +39633,13 @@ command to generate the output files.
<comment xml:lang="eo">XSLT-stilfolio</comment>
<comment xml:lang="en_GB">XSLT stylesheet</comment>
<comment xml:lang="el">Φύλλο στυλ XSLT</comment>
- <comment xml:lang="de">XSLT-Stylesheet</comment>
+ <comment xml:lang="de">XSLT-Stilvorlage</comment>
<comment xml:lang="da">XSLT-stilark</comment>
<comment xml:lang="cs">stylopis XSLT</comment>
<comment xml:lang="ca">full d'estil XSLT</comment>
<comment xml:lang="bg">Стилове — XSLT</comment>
<comment xml:lang="be@latin">Arkuš stylaŭ XSLT</comment>
+ <comment xml:lang="be">табліца стыляў XSLT</comment>
<comment xml:lang="ar">نمط XSLT</comment>
<comment xml:lang="af">XSLT-stylblad</comment>
<acronym>XSLT</acronym>
@@ -39059,18 +39660,24 @@ command to generate the output files.
<comment xml:lang="uk">файл опису Maven</comment>
<comment xml:lang="tr">Maven açıklama dosyası</comment>
<comment xml:lang="sv">Maven-beskrivningsfil</comment>
+ <comment xml:lang="sq">kartelë përshkrimi Maven</comment>
+ <comment xml:lang="sl">Opisna datoteka Maven</comment>
+ <comment xml:lang="si">Maven විස්තර ගොනුව</comment>
<comment xml:lang="sk">Súbor popisu Maven</comment>
<comment xml:lang="ru">Файл описания Maven</comment>
<comment xml:lang="pt_BR">Arquivo de descrição Maven</comment>
<comment xml:lang="pl">Plik opisu Maven</comment>
+ <comment xml:lang="nl">Maven-omschrijvingsbestand</comment>
<comment xml:lang="ko">Maven 설명 파일</comment>
<comment xml:lang="kk">Maven сипаттама файлы</comment>
<comment xml:lang="ja">Maven 説明ファイル</comment>
<comment xml:lang="it">File descrizione Mave</comment>
+ <comment xml:lang="is">Maven lýsingarskrá</comment>
<comment xml:lang="id">Berkas deskripsi Maven</comment>
<comment xml:lang="hu">Maven leírófájl</comment>
<comment xml:lang="hr">Maven datoteka opisa</comment>
<comment xml:lang="he">קובץ תיאור Maven</comment>
+ <comment xml:lang="gl">Ficheiro de descrición de Maven</comment>
<comment xml:lang="ga">cur síos Maven</comment>
<comment xml:lang="fur">file di descrizion Maven</comment>
<comment xml:lang="fr">fichier de description Maven</comment>
@@ -39083,6 +39690,7 @@ command to generate the output files.
<comment xml:lang="cs">popisný soubor Maven</comment>
<comment xml:lang="ca">fitxer de descripció Maven</comment>
<comment xml:lang="bg">Модел — Maven</comment>
+ <comment xml:lang="be">файл апісання Maven</comment>
<comment xml:lang="ar">ملف وصف Maven</comment>
<comment xml:lang="af">Maven-beskrywingslêer</comment>
<generic-icon name="text-x-generic"/>
@@ -39099,8 +39707,9 @@ command to generate the output files.
<comment xml:lang="tr">XMCD CD veri tabanı</comment>
<comment xml:lang="sv">XMCD cd-databas</comment>
<comment xml:lang="sr">ИксМЦД ЦД база података</comment>
- <comment xml:lang="sq">Bazë me të dhëna XMCD CD</comment>
+ <comment xml:lang="sq">bazë të dhënash XMCD CD</comment>
<comment xml:lang="sl">Podatkovna zbirka XMCD CD</comment>
+ <comment xml:lang="si">XMCD CD දත්ත ගබඩාව</comment>
<comment xml:lang="sk">Databáza XMCD CD</comment>
<comment xml:lang="ru">База данных компакт-дисков XMCD</comment>
<comment xml:lang="ro">Bază de date XMCD CD</comment>
@@ -39117,6 +39726,7 @@ command to generate the output files.
<comment xml:lang="kk">XMCD CD дерекқоры</comment>
<comment xml:lang="ja">XMCD CD データベース</comment>
<comment xml:lang="it">Database XMCD CD</comment>
+ <comment xml:lang="is">XMCD CD gagnagrunnur</comment>
<comment xml:lang="id">Basis data XMCD CD</comment>
<comment xml:lang="ia">Base de datos de CD XMCD</comment>
<comment xml:lang="hu">XMCD CD-adatbázis</comment>
@@ -39138,6 +39748,7 @@ command to generate the output files.
<comment xml:lang="ca">base de dades de CD XMCD</comment>
<comment xml:lang="bg">База от данни за CD-та — XMCD</comment>
<comment xml:lang="be@latin">Baza źviestak ab dyskach XMCD</comment>
+ <comment xml:lang="be">база даных кампакт-дыскаў XMCD</comment>
<comment xml:lang="ar">قاعدة بيانات XMCD CD</comment>
<comment xml:lang="af">XMCD CD-databasis</comment>
<sub-class-of type="text/plain"/>
@@ -39154,8 +39765,9 @@ command to generate the output files.
<comment xml:lang="tr">XML belgesi</comment>
<comment xml:lang="sv">XML-dokument</comment>
<comment xml:lang="sr">ИксМЛ документ</comment>
- <comment xml:lang="sq">Dokument XML</comment>
+ <comment xml:lang="sq">dokument XML</comment>
<comment xml:lang="sl">Dokument XML</comment>
+ <comment xml:lang="si">XML ලේඛනය</comment>
<comment xml:lang="sk">Dokument XML</comment>
<comment xml:lang="ru">Документ XML</comment>
<comment xml:lang="ro">Document XML</comment>
@@ -39172,6 +39784,7 @@ command to generate the output files.
<comment xml:lang="kk">XML құжаты</comment>
<comment xml:lang="ja">XML ドキュメント</comment>
<comment xml:lang="it">Documento XML</comment>
+ <comment xml:lang="is">XML skjal</comment>
<comment xml:lang="id">Dokumen XML</comment>
<comment xml:lang="ia">Documento XML</comment>
<comment xml:lang="hu">XML dokumentum</comment>
@@ -39194,6 +39807,7 @@ command to generate the output files.
<comment xml:lang="ca">document XML</comment>
<comment xml:lang="bg">Документ — XML</comment>
<comment xml:lang="be@latin">Dakument XML</comment>
+ <comment xml:lang="be">дакумент XML</comment>
<comment xml:lang="ast">Documentu XML</comment>
<comment xml:lang="ar">مستند XML</comment>
<comment xml:lang="af">XML-dokument</comment>
@@ -39219,8 +39833,9 @@ command to generate the output files.
<comment xml:lang="tr">XML varlıklar belgesi</comment>
<comment xml:lang="sv">XML-entitetsdokument</comment>
<comment xml:lang="sr">документ ИксМЛ ставки</comment>
- <comment xml:lang="sq">Dokument njësish XML</comment>
+ <comment xml:lang="sq">dokument njësish XML</comment>
<comment xml:lang="sl">Dokument XML določil</comment>
+ <comment xml:lang="si">XML ආයතන ලේඛනය</comment>
<comment xml:lang="sk">Dokument entít XML</comment>
<comment xml:lang="ru">Файл сущностей XML</comment>
<comment xml:lang="ro">Document entități XML</comment>
@@ -39237,6 +39852,7 @@ command to generate the output files.
<comment xml:lang="kk">XML мәндер құжаты</comment>
<comment xml:lang="ja">XML エントリドキュメント</comment>
<comment xml:lang="it">Documento entità XML</comment>
+ <comment xml:lang="is">XML-eininda skjal</comment>
<comment xml:lang="id">Dokumen entitas XML</comment>
<comment xml:lang="ia">Documento de entitates XML</comment>
<comment xml:lang="hu">XML egyeddokumentum</comment>
@@ -39252,12 +39868,13 @@ command to generate the output files.
<comment xml:lang="es">documento de entidades XML</comment>
<comment xml:lang="en_GB">XML entities document</comment>
<comment xml:lang="el">Έγγραφο οντοτήτων XML</comment>
- <comment xml:lang="de">XML-Dokument-Entitäten</comment>
+ <comment xml:lang="de">XML-Entitätendokument</comment>
<comment xml:lang="da">XML-enhedsdokument</comment>
<comment xml:lang="cs">dokument entit XML</comment>
<comment xml:lang="ca">document d'entitats XML</comment>
<comment xml:lang="bg">Документ — заместващи последователности в XML</comment>
<comment xml:lang="be@latin">Dakument elementaŭ XML</comment>
+ <comment xml:lang="be">дакумент сутнасцей XML</comment>
<comment xml:lang="ast">Documentu d'entidaes XML</comment>
<comment xml:lang="ar">مستند كيانات XML</comment>
<comment xml:lang="af">XML-entiteitedokument</comment>
@@ -39277,8 +39894,9 @@ command to generate the output files.
<comment xml:lang="tr">DV video</comment>
<comment xml:lang="sv">DV-video</comment>
<comment xml:lang="sr">ДВ видео</comment>
- <comment xml:lang="sq">Video DV</comment>
+ <comment xml:lang="sq">video DV</comment>
<comment xml:lang="sl">Video datoteka DV</comment>
+ <comment xml:lang="si">DV වීඩියෝ</comment>
<comment xml:lang="sk">Video DV</comment>
<comment xml:lang="ru">Видео DV</comment>
<comment xml:lang="ro">Video DV</comment>
@@ -39296,6 +39914,7 @@ command to generate the output files.
<comment xml:lang="ka">DV ვიდეო</comment>
<comment xml:lang="ja">DV 動画</comment>
<comment xml:lang="it">Video DV</comment>
+ <comment xml:lang="is">DV myndskeið</comment>
<comment xml:lang="id">Video DV</comment>
<comment xml:lang="ia">Video DV</comment>
<comment xml:lang="hu">DV videó</comment>
@@ -39318,6 +39937,7 @@ command to generate the output files.
<comment xml:lang="ca">vídeo DV</comment>
<comment xml:lang="bg">Видео — DV</comment>
<comment xml:lang="be@latin">Videa DV</comment>
+ <comment xml:lang="be">відэа DV</comment>
<comment xml:lang="ast">Videu en DV</comment>
<comment xml:lang="ar">فيديو DV</comment>
<comment xml:lang="af">DV-video</comment>
@@ -39337,8 +39957,9 @@ command to generate the output files.
<comment xml:lang="tr">ISI videosu</comment>
<comment xml:lang="sv">ISI-video</comment>
<comment xml:lang="sr">ИСИ видео</comment>
- <comment xml:lang="sq">Video ISI</comment>
+ <comment xml:lang="sq">video ISI</comment>
<comment xml:lang="sl">Video datoteka ISI</comment>
+ <comment xml:lang="si">ISI වීඩියෝව</comment>
<comment xml:lang="sk">Video ISI</comment>
<comment xml:lang="ru">Видео ISI</comment>
<comment xml:lang="ro">Video ISI</comment>
@@ -39356,6 +39977,7 @@ command to generate the output files.
<comment xml:lang="kk">ISI видеосы</comment>
<comment xml:lang="ja">ISI 動画</comment>
<comment xml:lang="it">Video ISI</comment>
+ <comment xml:lang="is">ISI myndskeið</comment>
<comment xml:lang="id">Video ISI</comment>
<comment xml:lang="ia">Video ISI</comment>
<comment xml:lang="hu">ISI-videó</comment>
@@ -39379,6 +40001,7 @@ command to generate the output files.
<comment xml:lang="ca">vídeo ISI</comment>
<comment xml:lang="bg">Видео — ISI</comment>
<comment xml:lang="be@latin">Videa ISI</comment>
+ <comment xml:lang="be">відэа ISI</comment>
<comment xml:lang="az">ISI video faylı</comment>
<comment xml:lang="ast">Videu n'ISI</comment>
<comment xml:lang="ar">فيديو ISI</comment>
@@ -39393,6 +40016,7 @@ command to generate the output files.
<comment xml:lang="sv">MPEG-2 transportström</comment>
<comment xml:lang="sr">МПЕГ-2 ток преноса</comment>
<comment xml:lang="sl">Pretočni vir prenosega MPEG</comment>
+ <comment xml:lang="si">MPEG-2 ප්රවාහන ප්රවාහය</comment>
<comment xml:lang="sk">MPEG-2 Transport Stream</comment>
<comment xml:lang="ru">Транспортный поток MPEG-2</comment>
<comment xml:lang="ro">Flux transport MPEG-2</comment>
@@ -39408,6 +40032,7 @@ command to generate the output files.
<comment xml:lang="ka">MPEG-2-ის ტრანსპორტული ნაკადი</comment>
<comment xml:lang="ja">MPEG-2 トランスポートストリーム</comment>
<comment xml:lang="it">Stream di trasporto MPEG-2</comment>
+ <comment xml:lang="is">MPEG-2 Transport streymi</comment>
<comment xml:lang="id">Stream transport MPEG-2</comment>
<comment xml:lang="ia">Fluxo de transporto MPEG-2</comment>
<comment xml:lang="hu">MPEG-2 átviteli adatfolyam</comment>
@@ -39428,6 +40053,7 @@ command to generate the output files.
<comment xml:lang="cs">přenosový proud MPEG-2</comment>
<comment xml:lang="ca">flux de transport MPEG-2</comment>
<comment xml:lang="bg">Поток — транспорт по MPEG-2</comment>
+ <comment xml:lang="be">транспартная плынь MPEG-2</comment>
<comment xml:lang="ar">بث نقل MPEG-2</comment>
<comment xml:lang="af">MPEG-2-vervoerstroom</comment>
<acronym>MPEG-2 TS</acronym>
@@ -39472,8 +40098,9 @@ command to generate the output files.
<comment xml:lang="tr">MPEG videosu</comment>
<comment xml:lang="sv">MPEG-video</comment>
<comment xml:lang="sr">МПЕГ видео</comment>
- <comment xml:lang="sq">Video MPEG</comment>
+ <comment xml:lang="sq">video MPEG</comment>
<comment xml:lang="sl">Video datoteka MPEG</comment>
+ <comment xml:lang="si">MPEG වීඩියෝව</comment>
<comment xml:lang="sk">Video MPEG</comment>
<comment xml:lang="ru">Видео MPEG</comment>
<comment xml:lang="ro">Video MPEG</comment>
@@ -39492,6 +40119,7 @@ command to generate the output files.
<comment xml:lang="ka">MPEG ვიდეო</comment>
<comment xml:lang="ja">MPEG 動画</comment>
<comment xml:lang="it">Video MPEG</comment>
+ <comment xml:lang="is">MPEG myndskeið</comment>
<comment xml:lang="id">Video MPEG</comment>
<comment xml:lang="ia">Video MPEG</comment>
<comment xml:lang="hu">MPEG-videó</comment>
@@ -39514,6 +40142,7 @@ command to generate the output files.
<comment xml:lang="ca">vídeo MPEG</comment>
<comment xml:lang="bg">Видео — MPEG</comment>
<comment xml:lang="be@latin">Videa MPEG</comment>
+ <comment xml:lang="be">відэа MPEG</comment>
<comment xml:lang="ast">Videu en MPEG</comment>
<comment xml:lang="ar">فيديو MPEG</comment>
<comment xml:lang="af">MPEG-video</comment>
@@ -39537,6 +40166,30 @@ command to generate the output files.
</mime-type>
<mime-type type="video/vnd.mpegurl">
<comment>Video playlist</comment>
+ <comment xml:lang="zh_CN">视频播放列表</comment>
+ <comment xml:lang="uk">список відтворення відео</comment>
+ <comment xml:lang="tr">Video çalma listesi</comment>
+ <comment xml:lang="sv">Videospellista</comment>
+ <comment xml:lang="sl">Seznam predvajanja videoposnetkov</comment>
+ <comment xml:lang="si">වීඩියෝ ධාවන ලැයිස්තුව</comment>
+ <comment xml:lang="ru">Список воспроизведения видео-данных</comment>
+ <comment xml:lang="pl">Lista odtwarzania wideo</comment>
+ <comment xml:lang="oc">lista de lectura vidèo</comment>
+ <comment xml:lang="nl">Video-afspeellijst</comment>
+ <comment xml:lang="ko">동영상 재생 목록</comment>
+ <comment xml:lang="kk">Видео ойнату тізімі</comment>
+ <comment xml:lang="ka">ვიდეო დასაკრავი სია</comment>
+ <comment xml:lang="ja">ビデオ再生リスト</comment>
+ <comment xml:lang="it">Playlist video</comment>
+ <comment xml:lang="hr">Video popis izvođenja</comment>
+ <comment xml:lang="gl">Lista de reprodución de vídeos</comment>
+ <comment xml:lang="fi">Video-soittolista</comment>
+ <comment xml:lang="eu">Bideoen erreprodukzio-zerrenda</comment>
+ <comment xml:lang="es">lista de reproducción de vídeo</comment>
+ <comment xml:lang="en_GB">Video playlist</comment>
+ <comment xml:lang="de">Video-Wiedergabeliste</comment>
+ <comment xml:lang="be">плэй-ліст відэа</comment>
+ <comment xml:lang="ar">قائمة تشغيل فيديو</comment>
<sub-class-of type="text/plain"/>
<alias type="video/x-mpegurl"/>
<magic>
@@ -39555,8 +40208,9 @@ command to generate the output files.
<comment xml:lang="tr">QuickTime videosu</comment>
<comment xml:lang="sv">QuickTime-video</comment>
<comment xml:lang="sr">Квик Тајм видео</comment>
- <comment xml:lang="sq">Video QuickTime</comment>
+ <comment xml:lang="sq">video QuickTime</comment>
<comment xml:lang="sl">Video datoteka QuickTime</comment>
+ <comment xml:lang="si">QuickTime වීඩියෝව</comment>
<comment xml:lang="sk">Video QuickTime</comment>
<comment xml:lang="ru">Видео QuickTime</comment>
<comment xml:lang="ro">Video QuickTime</comment>
@@ -39574,6 +40228,7 @@ command to generate the output files.
<comment xml:lang="kk">QuickTime видеосы</comment>
<comment xml:lang="ja">QuickTime 動画</comment>
<comment xml:lang="it">Video QuickTime</comment>
+ <comment xml:lang="is">QuickTime myndskeið</comment>
<comment xml:lang="id">Video QuickTime</comment>
<comment xml:lang="ia">Video QuickTime</comment>
<comment xml:lang="hu">QuickTime videó</comment>
@@ -39596,6 +40251,7 @@ command to generate the output files.
<comment xml:lang="ca">vídeo QuickTime</comment>
<comment xml:lang="bg">Видео — QuickTime</comment>
<comment xml:lang="be@latin">Videa QuickTime</comment>
+ <comment xml:lang="be">відэа QuickTime</comment>
<comment xml:lang="ast">Videu en QuickTime</comment>
<comment xml:lang="ar">فيديو QuickTime</comment>
<comment xml:lang="af">QuickTime-video</comment>
@@ -39619,8 +40275,9 @@ command to generate the output files.
<comment xml:lang="tr">QuickTime görüntüsü</comment>
<comment xml:lang="sv">QuickTime-bild</comment>
<comment xml:lang="sr">Квик Тајм слика</comment>
- <comment xml:lang="sq">Figurë QuickTime</comment>
+ <comment xml:lang="sq">figurë QuickTime</comment>
<comment xml:lang="sl">Slikovna datoteka QuickTime</comment>
+ <comment xml:lang="si">QuickTime රූපය</comment>
<comment xml:lang="sk">Obrázok QuickTime</comment>
<comment xml:lang="ru">Изображение QuickTime</comment>
<comment xml:lang="ro">Imagine QuickTime</comment>
@@ -39637,6 +40294,7 @@ command to generate the output files.
<comment xml:lang="kk">QuickTime суреті</comment>
<comment xml:lang="ja">QuickTime 画像</comment>
<comment xml:lang="it">Immagine QuickTime</comment>
+ <comment xml:lang="is">QuickTime mynd</comment>
<comment xml:lang="id">Citra QuickTime</comment>
<comment xml:lang="ia">Imagine QuickTime</comment>
<comment xml:lang="hu">QuickTime kép</comment>
@@ -39659,6 +40317,7 @@ command to generate the output files.
<comment xml:lang="ca">imatge QuickTime</comment>
<comment xml:lang="bg">Изображение — QuickTime</comment>
<comment xml:lang="be@latin">Vyjava QuickTime</comment>
+ <comment xml:lang="be">выява QuickTime</comment>
<comment xml:lang="ar">صورة QuickTime</comment>
<comment xml:lang="af">QuickTime-beeld</comment>
<magic>
@@ -39675,18 +40334,23 @@ command to generate the output files.
<comment xml:lang="tr">Khronos kaplama görüntüsü</comment>
<comment xml:lang="sv">Khronos-texturbild</comment>
<comment xml:lang="sr">слика Кронос текстуре</comment>
+ <comment xml:lang="sl">Slika teksture Khronos</comment>
+ <comment xml:lang="si">ක්‍රොනොස් වයනය රූපය</comment>
<comment xml:lang="sk">Obrázok textúry Khronos</comment>
<comment xml:lang="ru">Изображение текстуры Khronos</comment>
<comment xml:lang="pt_BR">Imagem de textura do Khronos</comment>
<comment xml:lang="pl">Obraz tekstury Khronos</comment>
+ <comment xml:lang="nl">Khronos-textuurafbeelding</comment>
<comment xml:lang="ko">크로노스 텍스처 파일</comment>
<comment xml:lang="kk">Khronos текстура суреті</comment>
<comment xml:lang="ja">Khronos テクスチャ画像</comment>
<comment xml:lang="it">Immagine texture Khronos</comment>
+ <comment xml:lang="is">Khronos efnisáferðarmynd</comment>
<comment xml:lang="id">Citra tekstur Khronos</comment>
<comment xml:lang="hu">Khronos textúra kép</comment>
<comment xml:lang="hr">Khronos tekstura slika</comment>
<comment xml:lang="he">תמונת מרקם של Khronos</comment>
+ <comment xml:lang="gl">Imaxe de textura Khronos</comment>
<comment xml:lang="ga">íomhá uigeachta Khronos</comment>
<comment xml:lang="fur">imagjin di struture/texture Khronos</comment>
<comment xml:lang="fr">image de texture Khronos</comment>
@@ -39699,6 +40363,7 @@ command to generate the output files.
<comment xml:lang="cs">obrázek s texturou Khronos</comment>
<comment xml:lang="ca">imatge de textura de Khronos</comment>
<comment xml:lang="bg">Изображение — текстура за Khronos</comment>
+ <comment xml:lang="be">выява тэкстуры Khronos</comment>
<comment xml:lang="ar">صور نسيج Khronos</comment>
<comment xml:lang="af">Khronos-tekstuurbeeld</comment>
<magic priority="80">
@@ -39718,18 +40383,23 @@ command to generate the output files.
<comment xml:lang="tr">Khronos kaplama görüntüsü</comment>
<comment xml:lang="sv">Khronos-texturbild</comment>
<comment xml:lang="sr">слика Кронос текстуре</comment>
+ <comment xml:lang="sl">Slika teksture Khronos</comment>
+ <comment xml:lang="si">ක්‍රොනොස් වයනය රූපය</comment>
<comment xml:lang="sk">Obrázok textúry Khronos</comment>
<comment xml:lang="ru">Изображение текстуры Khronos</comment>
<comment xml:lang="pt_BR">Imagem de textura do Khronos</comment>
<comment xml:lang="pl">Obraz tekstury Khronos</comment>
+ <comment xml:lang="nl">Khronos-textuurafbeelding</comment>
<comment xml:lang="ko">크로노스 텍스처 파일</comment>
<comment xml:lang="kk">Khronos текстура суреті</comment>
<comment xml:lang="ja">Khronos テクスチャ画像</comment>
<comment xml:lang="it">Immagine texture Khronos</comment>
+ <comment xml:lang="is">Khronos efnisáferðarmynd</comment>
<comment xml:lang="id">Citra tekstur Khronos</comment>
<comment xml:lang="hu">Khronos textúra kép</comment>
<comment xml:lang="hr">Khronos tekstura slika</comment>
<comment xml:lang="he">תמונת מרקם של Khronos</comment>
+ <comment xml:lang="gl">Imaxe de textura Khronos</comment>
<comment xml:lang="ga">íomhá uigeachta Khronos</comment>
<comment xml:lang="fur">imagjin di struture/texture Khronos</comment>
<comment xml:lang="fr">image de texture Khronos</comment>
@@ -39742,6 +40412,7 @@ command to generate the output files.
<comment xml:lang="cs">obrázek s texturou Khronos</comment>
<comment xml:lang="ca">imatge de textura de Khronos</comment>
<comment xml:lang="bg">Изображение — текстура за Khronos</comment>
+ <comment xml:lang="be">выява тэкстуры Khronos</comment>
<comment xml:lang="ar">صور نسيج Khronos</comment>
<comment xml:lang="af">Khronos-tekstuurbeeld</comment>
<magic priority="80">
@@ -39758,15 +40429,22 @@ command to generate the output files.
<comment xml:lang="uk">текстура ASTC</comment>
<comment xml:lang="tr">ASTC dokusu</comment>
<comment xml:lang="sv">ASTC-textur</comment>
+ <comment xml:lang="sl">Tekstura ASTC</comment>
+ <comment xml:lang="si">ASTC වයනය</comment>
+ <comment xml:lang="ru">Текстура ASTC</comment>
<comment xml:lang="pt_BR">Textura ASTC</comment>
<comment xml:lang="pl">Tekstura ASTC</comment>
+ <comment xml:lang="nl">ASTC-textuur</comment>
<comment xml:lang="ko">ASTC 텍스처</comment>
+ <comment xml:lang="kk">ASTC текстурасы</comment>
<comment xml:lang="ja">ASTC テクスチャ</comment>
<comment xml:lang="it">Texture ASTC</comment>
+ <comment xml:lang="is">ASTC efnisáferð</comment>
<comment xml:lang="id">tekstur ASTC</comment>
<comment xml:lang="hu">ASTC textúra</comment>
<comment xml:lang="hr">ASTC tekstura</comment>
<comment xml:lang="he">מרקם של ASTC</comment>
+ <comment xml:lang="gl">Textura ASTC</comment>
<comment xml:lang="fr">Texture ASTC</comment>
<comment xml:lang="fi">ASTC-tekstuuri</comment>
<comment xml:lang="es">textura ASTC</comment>
@@ -39774,6 +40452,7 @@ command to generate the output files.
<comment xml:lang="de">ASTC-Textur</comment>
<comment xml:lang="da">ASTC-struktur</comment>
<comment xml:lang="ca">textura ASTC</comment>
+ <comment xml:lang="be">тэкстура ASTC</comment>
<comment xml:lang="ar">نسيج ASTC</comment>
<acronym>ASTC</acronym>
<expanded-acronym>Advanced Scalable Texture Compression</expanded-acronym>
@@ -39791,8 +40470,9 @@ command to generate the output files.
<comment xml:lang="tr">Vivo videosu</comment>
<comment xml:lang="sv">Vivo-video</comment>
<comment xml:lang="sr">Виво видео</comment>
- <comment xml:lang="sq">Video Vivo</comment>
+ <comment xml:lang="sq">video Vivo</comment>
<comment xml:lang="sl">Video datoteka Vivo</comment>
+ <comment xml:lang="si">Vivo වීඩියෝව</comment>
<comment xml:lang="sk">Video Vivo</comment>
<comment xml:lang="ru">Видео Vivo</comment>
<comment xml:lang="ro">Video Vivo</comment>
@@ -39810,6 +40490,7 @@ command to generate the output files.
<comment xml:lang="kk">Vivo видеосы</comment>
<comment xml:lang="ja">Vivo 動画</comment>
<comment xml:lang="it">Video Vivo</comment>
+ <comment xml:lang="is">Vivo myndskeið</comment>
<comment xml:lang="id">Video Vivo</comment>
<comment xml:lang="ia">Video Vivo</comment>
<comment xml:lang="hu">Vivo-videó</comment>
@@ -39833,6 +40514,7 @@ command to generate the output files.
<comment xml:lang="ca">vídeo Vivo</comment>
<comment xml:lang="bg">Видео — Vivo</comment>
<comment xml:lang="be@latin">Videa Vivo</comment>
+ <comment xml:lang="be">відэа Vivo</comment>
<comment xml:lang="az">Vivo video faylı</comment>
<comment xml:lang="ast">Videu en Vivo</comment>
<comment xml:lang="ar">فيديو Vivo</comment>
@@ -39850,8 +40532,9 @@ command to generate the output files.
<comment xml:lang="tr">Wavelet videosu</comment>
<comment xml:lang="sv">Wavelet-video</comment>
<comment xml:lang="sr">Вејвелет видео</comment>
- <comment xml:lang="sq">Video Wavelet</comment>
+ <comment xml:lang="sq">video Wavelet</comment>
<comment xml:lang="sl">Video datoteka Wavelet</comment>
+ <comment xml:lang="si">Wavelet වීඩියෝව</comment>
<comment xml:lang="sk">Video Wavelet</comment>
<comment xml:lang="ru">Видео Wavelet</comment>
<comment xml:lang="ro">Video Wavelet</comment>
@@ -39869,6 +40552,7 @@ command to generate the output files.
<comment xml:lang="kk">Wavelet видеосы</comment>
<comment xml:lang="ja">Wavelet 動画</comment>
<comment xml:lang="it">Video Wavelet</comment>
+ <comment xml:lang="is">Wavelet myndskeið</comment>
<comment xml:lang="id">Video Wavelet</comment>
<comment xml:lang="ia">Video Wavelet</comment>
<comment xml:lang="hu">Wavelet-videó</comment>
@@ -39892,6 +40576,7 @@ command to generate the output files.
<comment xml:lang="ca">vídeo Wavelet</comment>
<comment xml:lang="bg">Видео — Wavelet</comment>
<comment xml:lang="be@latin">Videa Wavelet</comment>
+ <comment xml:lang="be">відэа Wavelet</comment>
<comment xml:lang="az">Wavelet video faylı</comment>
<comment xml:lang="ast">Videu en Wavelet</comment>
<comment xml:lang="ar">فيديو Wavelet</comment>
@@ -39906,8 +40591,9 @@ command to generate the output files.
<comment xml:lang="tr">ANIM canlandırması</comment>
<comment xml:lang="sv">ANIM-animering</comment>
<comment xml:lang="sr">АНИМ анимација</comment>
- <comment xml:lang="sq">Animim ANIM</comment>
+ <comment xml:lang="sq">animacion ANIM</comment>
<comment xml:lang="sl">Datoteka animacije ANIM</comment>
+ <comment xml:lang="si">ANIM සජීවිකරණය</comment>
<comment xml:lang="sk">Animácia ANIM</comment>
<comment xml:lang="ru">Анимация ANIM</comment>
<comment xml:lang="ro">Animație ANIM</comment>
@@ -39926,6 +40612,7 @@ command to generate the output files.
<comment xml:lang="ka">ANIM ანიმაცია</comment>
<comment xml:lang="ja">ANIM アニメーション</comment>
<comment xml:lang="it">Animazione ANIM</comment>
+ <comment xml:lang="is">ANIM hreyfimynd</comment>
<comment xml:lang="id">Animasi ANIM</comment>
<comment xml:lang="ia">Animation ANIM</comment>
<comment xml:lang="hu">ANIM-animáció</comment>
@@ -39949,6 +40636,7 @@ command to generate the output files.
<comment xml:lang="ca">animació ANIM</comment>
<comment xml:lang="bg">Анимация — ANIM</comment>
<comment xml:lang="be@latin">Animacyja ANIM</comment>
+ <comment xml:lang="be">анімацыя ANIM</comment>
<comment xml:lang="az">ANIM animasiyası</comment>
<comment xml:lang="ar">تحريكة ANIM</comment>
<comment xml:lang="af">ANIM-animasie</comment>
@@ -39963,8 +40651,9 @@ command to generate the output files.
<comment xml:lang="tr">FLIC animasyonu</comment>
<comment xml:lang="sv">FLIC-animering</comment>
<comment xml:lang="sr">ФЛИЦ анимација</comment>
- <comment xml:lang="sq">Animim FLIC</comment>
+ <comment xml:lang="sq">animacion FLIC</comment>
<comment xml:lang="sl">Datoteka animacije FLIC</comment>
+ <comment xml:lang="si">FLIC සජීවිකරණය</comment>
<comment xml:lang="sk">Animácia FLIC</comment>
<comment xml:lang="ru">Анимация FLIC</comment>
<comment xml:lang="ro">Animație FLIC</comment>
@@ -39982,6 +40671,7 @@ command to generate the output files.
<comment xml:lang="ka">FLIC ანიმაცია</comment>
<comment xml:lang="ja">FLIC アニメーション</comment>
<comment xml:lang="it">Animazione FLIC</comment>
+ <comment xml:lang="is">FLIC-hreyfimynd</comment>
<comment xml:lang="id">Animasi FLIC</comment>
<comment xml:lang="ia">Animation FLIC</comment>
<comment xml:lang="hu">FLIC animáció</comment>
@@ -40003,6 +40693,7 @@ command to generate the output files.
<comment xml:lang="ca">animació FLIC</comment>
<comment xml:lang="bg">Анимация — FLIC</comment>
<comment xml:lang="be@latin">Animacyja FLIC</comment>
+ <comment xml:lang="be">анімацыя FLIC</comment>
<comment xml:lang="ar">تحريكة FLIC</comment>
<comment xml:lang="af">FLIC-animasie</comment>
<alias type="video/fli"/>
@@ -40023,8 +40714,9 @@ command to generate the output files.
<comment xml:lang="tr">Haansoft Hangul belgesi</comment>
<comment xml:lang="sv">Haansoft Hangul-dokument</comment>
<comment xml:lang="sr">Хансофт Хангул документ</comment>
- <comment xml:lang="sq">Dokument Haansoft Hangul</comment>
+ <comment xml:lang="sq">dokument Haansoft Hangul</comment>
<comment xml:lang="sl">Dokument Haansoft Hangul</comment>
+ <comment xml:lang="si">Haansoft Hangul ලේඛනය</comment>
<comment xml:lang="sk">Dokument Haansoft Hangul</comment>
<comment xml:lang="ru">Документ Haansoft Hangul</comment>
<comment xml:lang="ro">Document Haansoft Hangul</comment>
@@ -40041,6 +40733,7 @@ command to generate the output files.
<comment xml:lang="kk">Haansoft Hangul құжаты</comment>
<comment xml:lang="ja">Haansoft Hangul ドキュメント</comment>
<comment xml:lang="it">Documento Haansoft Hangul</comment>
+ <comment xml:lang="is">Haansoft Hangul skjal</comment>
<comment xml:lang="id">Dokumen Haansoft Hangul</comment>
<comment xml:lang="ia">Documento Haansoft Hangul</comment>
<comment xml:lang="hu">Haansoft hangul dokumentum</comment>
@@ -40062,6 +40755,7 @@ command to generate the output files.
<comment xml:lang="ca">document d'Haansoft Hangul</comment>
<comment xml:lang="bg">Документ — Haansoft Hangul</comment>
<comment xml:lang="be@latin">Dakument Haansoft Hangul</comment>
+ <comment xml:lang="be">дакумент Haansoft Hangul</comment>
<comment xml:lang="ast">Documentu de Haansoft Hangul</comment>
<comment xml:lang="ar">مستند Haansoft Hangul</comment>
<comment xml:lang="af">Haansoft Hangul-dokument</comment>
@@ -40081,8 +40775,9 @@ command to generate the output files.
<comment xml:lang="tr">Haansoft Hangul belge şablonu</comment>
<comment xml:lang="sv">Haansoft Hangul-dokumentmall</comment>
<comment xml:lang="sr">шаблон Хансофт Хангул документа</comment>
- <comment xml:lang="sq">Model dokumenti Haansoft Hangul</comment>
+ <comment xml:lang="sq">gjedhe dokumentesh Haansoft Hangul</comment>
<comment xml:lang="sl">Predloga dokumenta Haansoft Hangul</comment>
+ <comment xml:lang="si">Haansoft Hangul ලේඛන අච්චුව</comment>
<comment xml:lang="sk">Šablóna dokumentu Haansoft Hangul</comment>
<comment xml:lang="ru">Шаблон документа Haansoft Hangul</comment>
<comment xml:lang="ro">Document șablon Haansoft Hangul</comment>
@@ -40099,6 +40794,7 @@ command to generate the output files.
<comment xml:lang="kk">Haansoft Hangul құжат үлгісі</comment>
<comment xml:lang="ja">Haansoft Hangul ドキュメントテンプレート</comment>
<comment xml:lang="it">Modello documento Haansoft Hangul</comment>
+ <comment xml:lang="is">Haansoft Hangul sniðskjal</comment>
<comment xml:lang="id">Templat dokumen Haansoft Hangul</comment>
<comment xml:lang="ia">Patrono de documento Haansoft Hangul</comment>
<comment xml:lang="hu">Haansoft hangul dokumentumsablon</comment>
@@ -40120,6 +40816,7 @@ command to generate the output files.
<comment xml:lang="ca">plantilla de document d'Haansoft Hangul</comment>
<comment xml:lang="bg">Шаблон за документи — Haansoft Hangul</comment>
<comment xml:lang="be@latin">Šablon dakumentu Haansoft Hangul</comment>
+ <comment xml:lang="be">шаблон дакумента Haansoft Hangul</comment>
<comment xml:lang="ast">Plantía de documentu de Haansoft Hangul</comment>
<comment xml:lang="ar">قالب مستند Haansoft Hangul</comment>
<comment xml:lang="af">Haansoft Hangul-dokumentsjabloon</comment>
@@ -40136,8 +40833,9 @@ command to generate the output files.
<comment xml:lang="tr">MNG canlandırması</comment>
<comment xml:lang="sv">MNG-animering</comment>
<comment xml:lang="sr">МНГ анимација</comment>
- <comment xml:lang="sq">Animim MNG</comment>
+ <comment xml:lang="sq">animacion MNG</comment>
<comment xml:lang="sl">Datoteka animacije MNG</comment>
+ <comment xml:lang="si">MNG සජීවිකරණය</comment>
<comment xml:lang="sk">Animácia MNG</comment>
<comment xml:lang="ru">Анимация MNG</comment>
<comment xml:lang="ro">Animație MNG</comment>
@@ -40155,6 +40853,7 @@ command to generate the output files.
<comment xml:lang="kk">MNG анимациясы</comment>
<comment xml:lang="ja">MNG アニメーション</comment>
<comment xml:lang="it">Animazione MNG</comment>
+ <comment xml:lang="is">MNG hreyfimynd</comment>
<comment xml:lang="id">Animasi MNG</comment>
<comment xml:lang="ia">Animation MNG</comment>
<comment xml:lang="hu">MNG-animáció</comment>
@@ -40177,6 +40876,7 @@ command to generate the output files.
<comment xml:lang="ca">animació MNG</comment>
<comment xml:lang="bg">Анимация — MNG</comment>
<comment xml:lang="be@latin">Animacyja MNG</comment>
+ <comment xml:lang="be">анімацыя MNG</comment>
<comment xml:lang="ar">تحريكة MNG</comment>
<comment xml:lang="af">MNG-animasie</comment>
<acronym>MNG</acronym>
@@ -40195,8 +40895,9 @@ command to generate the output files.
<comment xml:lang="tr">ASF videosu</comment>
<comment xml:lang="sv">ASF-video</comment>
<comment xml:lang="sr">АСФ видео</comment>
- <comment xml:lang="sq">Video ASF</comment>
+ <comment xml:lang="sq">video ASF</comment>
<comment xml:lang="sl">Video datoteka ASF</comment>
+ <comment xml:lang="si">ASF වීඩියෝව</comment>
<comment xml:lang="sk">Video ASF</comment>
<comment xml:lang="ru">Видео ASF</comment>
<comment xml:lang="ro">Video ASF</comment>
@@ -40214,6 +40915,7 @@ command to generate the output files.
<comment xml:lang="ka">ASF ვიდეო</comment>
<comment xml:lang="ja">ASF 動画</comment>
<comment xml:lang="it">Video ASF</comment>
+ <comment xml:lang="is">ASF myndskeið</comment>
<comment xml:lang="id">Video ASF</comment>
<comment xml:lang="ia">Video ASF</comment>
<comment xml:lang="hu">ASF videó</comment>
@@ -40236,6 +40938,7 @@ command to generate the output files.
<comment xml:lang="ca">vídeo ASF</comment>
<comment xml:lang="bg">Видео — ASF</comment>
<comment xml:lang="be@latin">Videa ASF</comment>
+ <comment xml:lang="be">відэа ASF</comment>
<comment xml:lang="ast">Videu n'ASF</comment>
<comment xml:lang="ar">فيديو ASF</comment>
<comment xml:lang="af">ASF-video</comment>
@@ -40259,8 +40962,9 @@ command to generate the output files.
<comment xml:lang="tr">Windows Media Station dosyası</comment>
<comment xml:lang="sv">Windows Media Station-fil</comment>
<comment xml:lang="sr">датотека станице Виндоузовог Медија</comment>
- <comment xml:lang="sq">File Windows Media Station</comment>
+ <comment xml:lang="sq">kartelë Windows Media Station</comment>
<comment xml:lang="sl">Datoteka Windows Media Station</comment>
+ <comment xml:lang="si">Windows Media Station ගොනුව</comment>
<comment xml:lang="sk">Súbor Windows Media Station</comment>
<comment xml:lang="ru">Файл Windows Media Station</comment>
<comment xml:lang="ro">Fișier Windows Media Station</comment>
@@ -40277,6 +40981,7 @@ command to generate the output files.
<comment xml:lang="kk">Windows Media Station файлы</comment>
<comment xml:lang="ja">Windows Media Station ファイル</comment>
<comment xml:lang="it">File Windows Media Station</comment>
+ <comment xml:lang="is">Windows Media Station skrá</comment>
<comment xml:lang="id">Berkas Windows Media Station</comment>
<comment xml:lang="ia">File de station Windows Media</comment>
<comment xml:lang="hu">Windows Media Station fájl</comment>
@@ -40292,12 +40997,13 @@ command to generate the output files.
<comment xml:lang="es">archivo de emisora de Windows Media</comment>
<comment xml:lang="en_GB">Windows Media Station file</comment>
<comment xml:lang="el">Αρχείο Windows Media Station</comment>
- <comment xml:lang="de">Windows-Media-Streamingbeschreibung</comment>
+ <comment xml:lang="de">Windows-Media-Station-Datei</comment>
<comment xml:lang="da">Windows Media Station-fil</comment>
<comment xml:lang="cs">soubor Windows Media Station</comment>
<comment xml:lang="ca">fitxer de Windows Media Station</comment>
<comment xml:lang="bg">Файл — Windows Media Station</comment>
<comment xml:lang="be@latin">Fajł Windows Media Station</comment>
+ <comment xml:lang="be">файл Windows Media Station</comment>
<comment xml:lang="ar">ملف محطة ويندوز ميديا</comment>
<comment xml:lang="af">Windows Media Station-lêer</comment>
<sub-class-of type="application/vnd.ms-asf"/>
@@ -40316,8 +41022,9 @@ command to generate the output files.
<comment xml:lang="tr">Windows Media videosu</comment>
<comment xml:lang="sv">Windows Media-video</comment>
<comment xml:lang="sr">Виндоуз Медија видео</comment>
- <comment xml:lang="sq">Video Windows Media</comment>
+ <comment xml:lang="sq">video Windows Media</comment>
<comment xml:lang="sl">Video datoteka Windows Media</comment>
+ <comment xml:lang="si">වින්ඩෝස් මීඩියා වීඩියෝව</comment>
<comment xml:lang="sk">Video Windows Media</comment>
<comment xml:lang="ru">Видео Windows Media</comment>
<comment xml:lang="ro">Video Windows Media</comment>
@@ -40334,6 +41041,7 @@ command to generate the output files.
<comment xml:lang="kk">Windows Media видеосы</comment>
<comment xml:lang="ja">Windows Media 動画</comment>
<comment xml:lang="it">Video Windows Media</comment>
+ <comment xml:lang="is">Windows Media myndskeið</comment>
<comment xml:lang="id">Video Windows Media</comment>
<comment xml:lang="ia">Video Windows Media</comment>
<comment xml:lang="hu">Windows Media videó</comment>
@@ -40355,13 +41063,14 @@ command to generate the output files.
<comment xml:lang="ca">vídeo de Windows Media</comment>
<comment xml:lang="bg">Видео — Windows Media</comment>
<comment xml:lang="be@latin">Videa Windows Media</comment>
+ <comment xml:lang="be">відэа Windows Media</comment>
<comment xml:lang="ast">Videu de Windows Media</comment>
<comment xml:lang="ar">فيديو ويندوز ميديا</comment>
<comment xml:lang="af">Windows Media-video</comment>
<sub-class-of type="application/vnd.ms-asf"/>
<glob pattern="*.wmv"/>
</mime-type>
- <mime-type type="video/x-msvideo">
+ <mime-type type="video/vnd.avi">
<comment>AVI video</comment>
<comment xml:lang="zh_TW">AVI 視訊</comment>
<comment xml:lang="zh_CN">AVI 视频</comment>
@@ -40370,8 +41079,9 @@ command to generate the output files.
<comment xml:lang="tr">AVI videosu</comment>
<comment xml:lang="sv">AVI-video</comment>
<comment xml:lang="sr">АВИ видео</comment>
- <comment xml:lang="sq">Video AVI</comment>
+ <comment xml:lang="sq">video AVI</comment>
<comment xml:lang="sl">Video datoteka AVI</comment>
+ <comment xml:lang="si">AVI වීඩියෝ</comment>
<comment xml:lang="sk">Video AVI</comment>
<comment xml:lang="ru">Видео AVI</comment>
<comment xml:lang="ro">Video AVI</comment>
@@ -40390,6 +41100,7 @@ command to generate the output files.
<comment xml:lang="ka">AVI ვიდეო</comment>
<comment xml:lang="ja">AVI 動画</comment>
<comment xml:lang="it">Video AVI</comment>
+ <comment xml:lang="is">AVI myndskeið</comment>
<comment xml:lang="id">Video AVI</comment>
<comment xml:lang="ia">Video AVI</comment>
<comment xml:lang="hu">AVI-videó</comment>
@@ -40413,6 +41124,7 @@ command to generate the output files.
<comment xml:lang="ca">vídeo AVI</comment>
<comment xml:lang="bg">Видео — AVI</comment>
<comment xml:lang="be@latin">Videa AVI</comment>
+ <comment xml:lang="be">відэа AVI</comment>
<comment xml:lang="az">AVI video faylı</comment>
<comment xml:lang="ast">Videu n'AVI</comment>
<comment xml:lang="ar">فيديو AVI</comment>
@@ -40424,6 +41136,7 @@ command to generate the output files.
<alias type="video/divx"/>
<alias type="video/msvideo"/>
<alias type="video/vnd.divx"/>
+ <alias type="video/x-msvideo"/>
<magic>
<match type="string" value="RIFF" offset="0">
<match type="string" value="AVI " offset="8"/>
@@ -40445,8 +41158,9 @@ command to generate the output files.
<comment xml:lang="tr">Nullsoft videosu</comment>
<comment xml:lang="sv">NullSoft-video</comment>
<comment xml:lang="sr">Нул Софт видео</comment>
- <comment xml:lang="sq">Video NullSoft</comment>
+ <comment xml:lang="sq">video NullSoft</comment>
<comment xml:lang="sl">Video datoteka NullSoft</comment>
+ <comment xml:lang="si">NullSoft වීඩියෝව</comment>
<comment xml:lang="sk">Video NullSoft</comment>
<comment xml:lang="ru">Видео Nullsoft</comment>
<comment xml:lang="ro">Video NullSoft</comment>
@@ -40463,6 +41177,7 @@ command to generate the output files.
<comment xml:lang="kk">NullSoft видеосы</comment>
<comment xml:lang="ja">NullSoft 動画</comment>
<comment xml:lang="it">Video NullSoft</comment>
+ <comment xml:lang="is">Nullsoft myndskeið</comment>
<comment xml:lang="id">Video NullSoft</comment>
<comment xml:lang="ia">Video NullSoft</comment>
<comment xml:lang="hu">NullSoft videó</comment>
@@ -40485,6 +41200,7 @@ command to generate the output files.
<comment xml:lang="ca">vídeo NullSoft</comment>
<comment xml:lang="bg">Видео — NullSoft</comment>
<comment xml:lang="be@latin">Videa NullSoft</comment>
+ <comment xml:lang="be">відэа NullSoft</comment>
<comment xml:lang="ast">Videu de NullSoft</comment>
<comment xml:lang="ar">فيديو NullSoft</comment>
<comment xml:lang="af">NullSoft-video</comment>
@@ -40502,8 +41218,9 @@ command to generate the output files.
<comment xml:lang="tr">SDP çoklu yayın akışı dosyası</comment>
<comment xml:lang="sv">SDP multicast stream-fil</comment>
<comment xml:lang="sr">СДП датотека тока вишеструког емитовања</comment>
- <comment xml:lang="sq">File stream multicast SDP</comment>
+ <comment xml:lang="sq">kartelë transmetimi multicast SDP</comment>
<comment xml:lang="sl">Pretočni vir večsmernega oddajanja</comment>
+ <comment xml:lang="si">SDP බහු විකාශන ප්‍රවාහ ගොනුව</comment>
<comment xml:lang="sk">Súbor viacsmerového vysielania prúdu SDP</comment>
<comment xml:lang="ru">Файл мультикаст-потока SDP</comment>
<comment xml:lang="ro">Fișier flux multicast SDP</comment>
@@ -40520,6 +41237,7 @@ command to generate the output files.
<comment xml:lang="kk">SDP мультикаст ағым файлы</comment>
<comment xml:lang="ja">SDP マルチキャストストリームファイル</comment>
<comment xml:lang="it">File stream multicast SDP</comment>
+ <comment xml:lang="is">SDP multicast streymisskrá</comment>
<comment xml:lang="id">Berkas SDP multicast stream</comment>
<comment xml:lang="ia">File de fluxo multidiffusion SDP</comment>
<comment xml:lang="hu">SDP multicast műsorfájl</comment>
@@ -40541,6 +41259,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer de flux de multidifusió SDP</comment>
<comment xml:lang="bg">Поток — SDP multicast</comment>
<comment xml:lang="be@latin">Šmatadrasny płynievy fajł SDP</comment>
+ <comment xml:lang="be">файл шматадраснай плыні SDP</comment>
<comment xml:lang="ar">ملف دفق متعدد البث SDP</comment>
<acronym>SDP</acronym>
<expanded-acronym>Session Description Protocol</expanded-acronym>
@@ -40564,8 +41283,9 @@ command to generate the output files.
<comment xml:lang="tr">SGI videosu</comment>
<comment xml:lang="sv">SGI-video</comment>
<comment xml:lang="sr">СГИ видео</comment>
- <comment xml:lang="sq">Video SGI</comment>
+ <comment xml:lang="sq">video SGI</comment>
<comment xml:lang="sl">Video datoteka SGI</comment>
+ <comment xml:lang="si">SGI වීඩියෝව</comment>
<comment xml:lang="sk">Video SGI</comment>
<comment xml:lang="ru">Видео SGI</comment>
<comment xml:lang="ro">Video SGI</comment>
@@ -40583,6 +41303,7 @@ command to generate the output files.
<comment xml:lang="kk">SGI видеосы</comment>
<comment xml:lang="ja">SGI 動画</comment>
<comment xml:lang="it">Video SGI</comment>
+ <comment xml:lang="is">SGI myndskeið</comment>
<comment xml:lang="id">Video SGI</comment>
<comment xml:lang="ia">Video SGI</comment>
<comment xml:lang="hu">SGI-videó</comment>
@@ -40606,6 +41327,7 @@ command to generate the output files.
<comment xml:lang="ca">vídeo SGI</comment>
<comment xml:lang="bg">Видео — SGI</comment>
<comment xml:lang="be@latin">Videa SGI</comment>
+ <comment xml:lang="be">відэа SGI</comment>
<comment xml:lang="az">SGI video faylı</comment>
<comment xml:lang="ast">Videu en SGI</comment>
<comment xml:lang="ar">فيديو SGI</comment>
@@ -40624,8 +41346,9 @@ command to generate the output files.
<comment xml:lang="tr">eMusic indirme paketi</comment>
<comment xml:lang="sv">eMusic-hämtningspaket</comment>
<comment xml:lang="sr">пакет преузимања еМузике</comment>
- <comment xml:lang="sq">Paketë shkarkimi eMusic</comment>
+ <comment xml:lang="sq">paketë shkarkimi eMusic</comment>
<comment xml:lang="sl">Datoteka paketa eMusic</comment>
+ <comment xml:lang="si">eMusic බාගත කිරීමේ පැකේජය</comment>
<comment xml:lang="sk">Balíček sťahovania eMusic</comment>
<comment xml:lang="ru">Пакет загрузок eMusic</comment>
<comment xml:lang="ro">pachet descărcare eMusic</comment>
@@ -40642,6 +41365,7 @@ command to generate the output files.
<comment xml:lang="kk">eMusic жүктемелер дестесі</comment>
<comment xml:lang="ja">eMusic ダウンロードパッケージ</comment>
<comment xml:lang="it">Pacchetto scaricamento eMusic</comment>
+ <comment xml:lang="is">eMusic niðurhalspakki</comment>
<comment xml:lang="id">paket unduh eMusic</comment>
<comment xml:lang="ia">Pacchetto de discargamento eMusic</comment>
<comment xml:lang="hu">eMusic letöltési csomag</comment>
@@ -40663,6 +41387,7 @@ command to generate the output files.
<comment xml:lang="ca">paquet de baixades d'eMusic</comment>
<comment xml:lang="bg">Пакет за сваляне — eMusic</comment>
<comment xml:lang="be@latin">pakunak zahruzki eMusic</comment>
+ <comment xml:lang="be">пакет спампоўвання eMusic</comment>
<comment xml:lang="ar">حزمة تنزيل eMusic</comment>
<comment xml:lang="af">eMusic-aflaaipakket</comment>
<generic-icon name="package-x-generic"/>
@@ -40679,7 +41404,9 @@ command to generate the output files.
<comment xml:lang="tr">KML coğrafi verisi</comment>
<comment xml:lang="sv">KML geografisk data</comment>
<comment xml:lang="sr">КМЛ географски подаци</comment>
+ <comment xml:lang="sq">të dhëna gjeografike KML</comment>
<comment xml:lang="sl">Datoteka geografskih podatkov KML</comment>
+ <comment xml:lang="si">KML භූගෝලීය දත්ත</comment>
<comment xml:lang="sk">Zemepisné údaje KML</comment>
<comment xml:lang="ru">Географические данные KML</comment>
<comment xml:lang="ro">Date geografice KML</comment>
@@ -40687,13 +41414,14 @@ command to generate the output files.
<comment xml:lang="pt">dados geográficos KML</comment>
<comment xml:lang="pl">Dane geograficzne KML</comment>
<comment xml:lang="oc">donadas geograficas KML</comment>
- <comment xml:lang="nl">KML geographic data</comment>
+ <comment xml:lang="nl">KML geografische gegevens</comment>
<comment xml:lang="lv">KML ģeogrāfiskie dati</comment>
<comment xml:lang="lt">KML geografiniai duomenys</comment>
<comment xml:lang="ko">KML 지리 정보 데이터</comment>
<comment xml:lang="kk">KML географилық ақпараты</comment>
<comment xml:lang="ja">KML 地理データ</comment>
<comment xml:lang="it">Dati geografici KML</comment>
+ <comment xml:lang="is">KML hnattstaðsetningargögn</comment>
<comment xml:lang="id">Data geografis KML</comment>
<comment xml:lang="ia">Datos geographic KML</comment>
<comment xml:lang="hu">KML földrajzi adatok</comment>
@@ -40709,11 +41437,12 @@ command to generate the output files.
<comment xml:lang="es">datos geográficos KML</comment>
<comment xml:lang="en_GB">KML geographic data</comment>
<comment xml:lang="el">Γεωγραφικά δεδομένα KML</comment>
- <comment xml:lang="de">KML geographische Daten</comment>
+ <comment xml:lang="de">KML-Geodaten</comment>
<comment xml:lang="da">Geografiske data i KML-format</comment>
<comment xml:lang="cs">geografická data KML</comment>
<comment xml:lang="ca">dades geogràfiques KML</comment>
<comment xml:lang="bg">Географски данни — KML</comment>
+ <comment xml:lang="be">геаграфічныя даныя KML</comment>
<comment xml:lang="ar">بيانات جغرافية KML</comment>
<comment xml:lang="af">KML geografiese data</comment>
<acronym>KML</acronym>
@@ -40730,7 +41459,9 @@ command to generate the output files.
<comment xml:lang="tr">KML sıkıştırılmış coğrafi verisi</comment>
<comment xml:lang="sv">KML geografiskt komprimerat data</comment>
<comment xml:lang="sr">КМЛ географски запаковани подаци</comment>
+ <comment xml:lang="sq">të dhëna gjeografike KML të ngjeshura</comment>
<comment xml:lang="sl">Skrčeni geografski podatki KML</comment>
+ <comment xml:lang="si">KML භූගෝලීය සම්පීඩිත දත්ත</comment>
<comment xml:lang="sk">Komprimované zemepisné údaje KML</comment>
<comment xml:lang="ru">Сжатые географические данные KML</comment>
<comment xml:lang="ro">Date geografice comprimate KML</comment>
@@ -40738,13 +41469,14 @@ command to generate the output files.
<comment xml:lang="pt">dados geográficos comprimidos KML</comment>
<comment xml:lang="pl">Skompresowane dane geograficzne KML</comment>
<comment xml:lang="oc">donadas geograficas KML compressats</comment>
- <comment xml:lang="nl">KML geographic compressed data</comment>
+ <comment xml:lang="nl">KML geografische gecomprimeerde gegevens</comment>
<comment xml:lang="lv">KML saspiesti ģeogrāfiskie dati</comment>
<comment xml:lang="lt">KML geografiniai suglaudinti duomenys</comment>
<comment xml:lang="ko">KML 지리 정보 압축 데이터</comment>
<comment xml:lang="kk">KML географиялық сығылған ақпарат</comment>
<comment xml:lang="ja">KML 地理圧縮データ</comment>
<comment xml:lang="it">Dati geografici KML compressi</comment>
+ <comment xml:lang="is">KML þjöppuð hnattstaðsetningargögn</comment>
<comment xml:lang="id">Data geografis KML terkompresi</comment>
<comment xml:lang="ia">Datos geographic KML comprimite</comment>
<comment xml:lang="hu">KML tömörített földrajzi adatok</comment>
@@ -40760,11 +41492,12 @@ command to generate the output files.
<comment xml:lang="es">datos geográficos comprimidos KML</comment>
<comment xml:lang="en_GB">KML geographic compressed data</comment>
<comment xml:lang="el">Γεωγραφικά συμπιεσμένα δεδομένα KML</comment>
- <comment xml:lang="de">KML geographische komprimierte Daten</comment>
+ <comment xml:lang="de">Komprimierte KML-Geodaten</comment>
<comment xml:lang="da">KML-geografiske komprimerede data</comment>
<comment xml:lang="cs">komprimovaná geografická data KML</comment>
<comment xml:lang="ca">dades geogràfiques KML amb compressió</comment>
<comment xml:lang="bg">Географски данни — KML, компресирани</comment>
+ <comment xml:lang="be">сціснутыя геаграфічныя даныя KML</comment>
<comment xml:lang="ar">بيانات جغرافية مضغوطة KML</comment>
<comment xml:lang="af">KML saamgepersde geografiese data</comment>
<acronym>KML</acronym>
@@ -40780,18 +41513,23 @@ command to generate the output files.
<comment xml:lang="tr">GeoJSON coğrafi verileri</comment>
<comment xml:lang="sv">Geospatialt GeoJSON-data</comment>
<comment xml:lang="sr">ГеоЈСОН геопросторни подаци</comment>
+ <comment xml:lang="sq">të dhëna gjeohapësinore GeoJSON</comment>
+ <comment xml:lang="si">GeoJSON භූගෝලීය දත්ත</comment>
<comment xml:lang="sk">Geopriestorové údaje GeoJSON</comment>
<comment xml:lang="ru">Геопространственные данные GeoJSON</comment>
<comment xml:lang="pt_BR">Dados geoespaciais GeoJSON</comment>
<comment xml:lang="pl">Dane geoprzestrzenne GeoJSON</comment>
+ <comment xml:lang="nl">GeoJSON geospatiële gegevens</comment>
<comment xml:lang="ko">GeoJSON 지리 정보 데이터</comment>
<comment xml:lang="kk">GeoJSON геокеңістіктік деректері</comment>
<comment xml:lang="ja">GeoJSON 地理空間データ</comment>
<comment xml:lang="it">Dati geo-spaziali GeoJSON</comment>
+ <comment xml:lang="is">GeoJSON landupplýsingagögn</comment>
<comment xml:lang="id">Data geospasial GeoJSON</comment>
<comment xml:lang="hu">GeoJSON téradatok</comment>
<comment xml:lang="hr">GeoJSON geoprostorni podaci</comment>
<comment xml:lang="he">נתונים מרחביים ב־GeoJSON</comment>
+ <comment xml:lang="gl">Datos xeoespaciais GeoJSON</comment>
<comment xml:lang="ga">sonraí geospásúla GeoJSON</comment>
<comment xml:lang="fur">dâts gjeo-spaziâls GeoJSON</comment>
<comment xml:lang="fr">données géospatiales GeoJSON</comment>
@@ -40804,6 +41542,7 @@ command to generate the output files.
<comment xml:lang="cs">geoprostorová data GeoJSON</comment>
<comment xml:lang="ca">dades geomàtiques GeoJSON</comment>
<comment xml:lang="bg">Географски данни — GeoJSON</comment>
+ <comment xml:lang="be">геапрасторавыя даныя GeoJSON</comment>
<comment xml:lang="ar">بيانات جغرافية مكانية GeoJSON</comment>
<comment xml:lang="af">GeoJSON georuimtelike data</comment>
<sub-class-of type="application/json"/>
@@ -40819,19 +41558,25 @@ command to generate the output files.
<comment xml:lang="tr">GPX coğrafi verileri</comment>
<comment xml:lang="sv">GPX geografisk data</comment>
<comment xml:lang="sr">ГПИкс географски подаци</comment>
+ <comment xml:lang="sq">të dhëna gjeografike GPX</comment>
+ <comment xml:lang="sl">Zemljepisni podatki GPX</comment>
+ <comment xml:lang="si">GPX භූගෝලීය දත්ත</comment>
<comment xml:lang="sk">Zemepisné údaje GPX</comment>
<comment xml:lang="ru">Географические данные GPX</comment>
<comment xml:lang="pt_BR">Dados geográficos GPX</comment>
<comment xml:lang="pl">Dane geograficzne GPX</comment>
<comment xml:lang="oc">Donadas geograficas GPX</comment>
+ <comment xml:lang="nl">GPX geografische gegevens</comment>
<comment xml:lang="ko">GPX 지리 공간정보 데이터</comment>
<comment xml:lang="kk">GPX географикалық деректері</comment>
<comment xml:lang="ja">GPX 地理データ</comment>
<comment xml:lang="it">Dati geografici GPX</comment>
+ <comment xml:lang="is">GPX hnattstaðsetningargögn</comment>
<comment xml:lang="id">Data geografis GPX</comment>
<comment xml:lang="hu">GPX földrajzi adatok</comment>
<comment xml:lang="hr">GPX geografski podaci</comment>
<comment xml:lang="he">נתונים גאוגרפיים GPX</comment>
+ <comment xml:lang="gl">Datos xeográficos GPX</comment>
<comment xml:lang="ga">sonraí geografacha GPX</comment>
<comment xml:lang="fur">dâts gjeografics GPX</comment>
<comment xml:lang="fr">données géographiques GPX</comment>
@@ -40844,6 +41589,7 @@ command to generate the output files.
<comment xml:lang="cs">geografická data GPX</comment>
<comment xml:lang="ca">dades geogràfiques GPX</comment>
<comment xml:lang="bg">Географски данни — GPX</comment>
+ <comment xml:lang="be">геаграфічныя даныя GPX</comment>
<comment xml:lang="ar">بيانات جغرافية GPX</comment>
<comment xml:lang="af">GPX geografiese data</comment>
<acronym>GPX</acronym>
@@ -40865,8 +41611,9 @@ command to generate the output files.
<comment xml:lang="tr">Citrix ICA ayar dosyası</comment>
<comment xml:lang="sv">Citrix ICA-inställningsfil</comment>
<comment xml:lang="sr">датотека подешавања Цитрикс ИЦА-а</comment>
- <comment xml:lang="sq">File rregullimesh Citrix ICA</comment>
+ <comment xml:lang="sq">kartelë rregullimesh Citrix ICA</comment>
<comment xml:lang="sl">Nastavitvena datoteka Citrix ICA</comment>
+ <comment xml:lang="si">Citrix ICA සැකසුම් ගොනුව</comment>
<comment xml:lang="sk">Súbor nastavení Citrix ICA</comment>
<comment xml:lang="ru">Файл настроек Citrix ICA</comment>
<comment xml:lang="ro">Fișier de configurări Citrix ICA</comment>
@@ -40884,6 +41631,7 @@ command to generate the output files.
<comment xml:lang="ka">Citrix ICA-ის პარამეტრების ფაილი</comment>
<comment xml:lang="ja">Citrix ICA 設定ファイル</comment>
<comment xml:lang="it">File impostazioni Citrix ICA</comment>
+ <comment xml:lang="is">Citrix ICA stillingaskrá</comment>
<comment xml:lang="id">Berkas penataan Citrix ICA</comment>
<comment xml:lang="ia">File de configuration ICA Citrix</comment>
<comment xml:lang="hu">Citrix ICA beállításfájl</comment>
@@ -40905,6 +41653,7 @@ command to generate the output files.
<comment xml:lang="ca">fitxer d'ajusts de Citrix ICA</comment>
<comment xml:lang="bg">Настройки — Citrix ICA</comment>
<comment xml:lang="be@latin">Fajł naładaŭ Citrix ICA</comment>
+ <comment xml:lang="be">файл налад Citrix ICA</comment>
<comment xml:lang="ar">ملف إعدادات Citrix ICA</comment>
<comment xml:lang="af">Citrix ICA-instellingslêer</comment>
<acronym>ICA</acronym>
@@ -40922,8 +41671,9 @@ command to generate the output files.
<comment xml:lang="tr">XUL arayüz belgesi</comment>
<comment xml:lang="sv">XUL-gränssnittsdokument</comment>
<comment xml:lang="sr">документ ИксУЛ сучеља</comment>
- <comment xml:lang="sq">Dokument interfaqe XUL</comment>
+ <comment xml:lang="sq">dokument ndërfaqeje XUL</comment>
<comment xml:lang="sl">Dokument vmesnika XUL</comment>
+ <comment xml:lang="si">XUL අතුරුමුහුණත් ලේඛනය</comment>
<comment xml:lang="sk">Dokument rozhrania XUL</comment>
<comment xml:lang="ru">Документ интерфейса XUL</comment>
<comment xml:lang="ro">Document interfață XUL</comment>
@@ -40940,6 +41690,7 @@ command to generate the output files.
<comment xml:lang="kk">XUL интерфейс құжаты</comment>
<comment xml:lang="ja">XUL インターフェイスドキュメント</comment>
<comment xml:lang="it">Documento interfaccia XUL</comment>
+ <comment xml:lang="is">XUL viðmótsskjal</comment>
<comment xml:lang="id">Dokumen antarmuka XUL</comment>
<comment xml:lang="ia">Documento de interfacie XUL</comment>
<comment xml:lang="hu">XUL-felületdokumentum</comment>
@@ -40955,12 +41706,13 @@ command to generate the output files.
<comment xml:lang="es">documento de interfaz XUL</comment>
<comment xml:lang="en_GB">XUL interface document</comment>
<comment xml:lang="el">Έγγραφο διεπαφής XUL</comment>
- <comment xml:lang="de">XUL-Oberflächendokument</comment>
+ <comment xml:lang="de">XUL-Benutzeroberflächendokument</comment>
<comment xml:lang="da">XUL-grænsefladedokument</comment>
<comment xml:lang="cs">dokument rozhraní XUL</comment>
<comment xml:lang="ca">document d'interfície XUL</comment>
<comment xml:lang="bg">Документ — интерфейс, XUL</comment>
<comment xml:lang="be@latin">Interfejsny dakument XUL</comment>
+ <comment xml:lang="be">дакумент інтэрфейсу XUL</comment>
<comment xml:lang="ast">Documentu d'interfaz XUL</comment>
<comment xml:lang="ar">مستند واجهة XUL</comment>
<comment xml:lang="af">XUL-koppelvlakdokument</comment>
@@ -40979,7 +41731,9 @@ command to generate the output files.
<comment xml:lang="tr">XPInstall kurulum modülü</comment>
<comment xml:lang="sv">XPInstall-installeringsmodul</comment>
<comment xml:lang="sr">модул инсталатера Инсталирања ИксПе-а</comment>
+ <comment xml:lang="sq">modul instaluesi XPInstall</comment>
<comment xml:lang="sl">modul namestilnika XPInstall</comment>
+ <comment xml:lang="si">XPI ස්ථාපක මොඩියුලය ස්ථාපනය කරන්න</comment>
<comment xml:lang="sk">Modul inštalátora XPInstall</comment>
<comment xml:lang="ru">Модуль установщика XPInstall</comment>
<comment xml:lang="ro">Modul de instalare XPInstall</comment>
@@ -40994,6 +41748,7 @@ command to generate the output files.
<comment xml:lang="kk">XPInstall орнату модулі</comment>
<comment xml:lang="ja">XPInstall インストーラモジュール</comment>
<comment xml:lang="it">Modulo installatore XPInstall</comment>
+ <comment xml:lang="is">XPInstall uppsetningareining</comment>
<comment xml:lang="id">Modul installer XPInstall</comment>
<comment xml:lang="ia">Modulo de installation XPInstall</comment>
<comment xml:lang="hu">XPInstall telepítőmodul</comment>
@@ -41014,6 +41769,7 @@ command to generate the output files.
<comment xml:lang="cs">modul instalátoru XPInstall</comment>
<comment xml:lang="ca">mòdul de l'instal·lador XPinstall</comment>
<comment xml:lang="bg">Пакет — инсталация XPInstall</comment>
+ <comment xml:lang="be">модуль усталёўшчыка XPInstall</comment>
<comment xml:lang="ar">وحدة مثبت XPInstall</comment>
<comment xml:lang="af">XPInstall-installasiemodule</comment>
<sub-class-of type="application/zip"/>
@@ -41028,7 +41784,9 @@ command to generate the output files.
<comment xml:lang="tr">Word 2007 belgesi</comment>
<comment xml:lang="sv">Word 2007-dokument</comment>
<comment xml:lang="sr">документ Ворда 2007</comment>
+ <comment xml:lang="sq">dokument Word 2007</comment>
<comment xml:lang="sl">Dokument Word 2007</comment>
+ <comment xml:lang="si">Word 2007 ලේඛනය</comment>
<comment xml:lang="sk">Dokument Word 2007</comment>
<comment xml:lang="ru">Документ Word 2007</comment>
<comment xml:lang="ro">Document Word 2007</comment>
@@ -41043,6 +41801,7 @@ command to generate the output files.
<comment xml:lang="kk">Word 2007 құжаты</comment>
<comment xml:lang="ja">Word 2007 ドキュメント</comment>
<comment xml:lang="it">Documento Word 2007</comment>
+ <comment xml:lang="is">Word 2007 skjal</comment>
<comment xml:lang="id">Dokumen Word 2007</comment>
<comment xml:lang="ia">Documento Word 2007</comment>
<comment xml:lang="hu">Word 2007 dokumentum</comment>
@@ -41063,6 +41822,7 @@ command to generate the output files.
<comment xml:lang="cs">dokument Word 2007</comment>
<comment xml:lang="ca">document de Word 2007</comment>
<comment xml:lang="bg">Документ — Word 2007</comment>
+ <comment xml:lang="be">дакумент Word 2007</comment>
<comment xml:lang="ast">Documentu de Word 2007</comment>
<comment xml:lang="ar">مستند ورد 2007</comment>
<comment xml:lang="af">Word 2007-dokument</comment>
@@ -41078,20 +41838,23 @@ command to generate the output files.
<comment xml:lang="tr">Word 2007 belge şablonu</comment>
<comment xml:lang="sv">Word 2007-dokumentmall</comment>
<comment xml:lang="sr">шаблон документа Ворда 2007</comment>
+ <comment xml:lang="sq">gjedhe dokumentesh Word 2007</comment>
<comment xml:lang="sl">Predloga dokumenta Word 2007</comment>
+ <comment xml:lang="si">Word 2007 ලේඛන සැකිල්ල</comment>
<comment xml:lang="sk">Šablóna dokumentu Word 2007</comment>
<comment xml:lang="ru">Шаблон документа Word 2007</comment>
<comment xml:lang="pt_BR">Modelo de documento do Word 2007</comment>
<comment xml:lang="pt">modelo de documento Word 2007</comment>
<comment xml:lang="pl">Szablon dokumentu Word 2007</comment>
<comment xml:lang="oc">modèl de document Word 2007</comment>
- <comment xml:lang="nl">Word 2007 document sjabloon</comment>
+ <comment xml:lang="nl">Word 2007-documentsjabloon</comment>
<comment xml:lang="lv">Word 2007 dokumenta veidne</comment>
<comment xml:lang="ko">Word 2007 문서 서식</comment>
<comment xml:lang="kk">Word 2007 құжатының үлгісі</comment>
<comment xml:lang="ka">Word 2007-ის დოკუმენტის შაბლონი</comment>
<comment xml:lang="ja">Word 2007 ドキュメントテンプレート</comment>
<comment xml:lang="it">Modello documento Word 2007</comment>
+ <comment xml:lang="is">Word sniðmát fyrir textaskjal</comment>
<comment xml:lang="id">Templat dokumen Word 2007</comment>
<comment xml:lang="ia">Patrono de documento Word 2007</comment>
<comment xml:lang="hu">Word 2007 dokumentumsablon</comment>
@@ -41111,6 +41874,7 @@ command to generate the output files.
<comment xml:lang="cs">šablona dokumentu Word 2007</comment>
<comment xml:lang="ca">plantilla de document de Word 2007</comment>
<comment xml:lang="bg">Шаблон за документи — Word 2007</comment>
+ <comment xml:lang="be">шаблон дакумента Word 2007</comment>
<comment xml:lang="ast">Plantía de documentu de Word 2007</comment>
<comment xml:lang="ar">قالب مستند ورد 2007</comment>
<comment xml:lang="af">Word 2007-dokumentsjabloon</comment>
@@ -41127,7 +41891,9 @@ command to generate the output files.
<comment xml:lang="tr">PowerPoint 2007 sunumu</comment>
<comment xml:lang="sv">PowerPoint 2007-presentation</comment>
<comment xml:lang="sr">презентација Пауер Поинта 2007</comment>
+ <comment xml:lang="sq">paraqitje PowerPoint 2007</comment>
<comment xml:lang="sl">Predstavitev Microsoft PowerPoint 2007</comment>
+ <comment xml:lang="si">PowerPoint 2007 ඉදිරිපත් කිරීම</comment>
<comment xml:lang="sk">Prezentácia PowerPoint 2007</comment>
<comment xml:lang="ru">Презентация PowerPoint 2007</comment>
<comment xml:lang="ro">Prezentare PowerPoint 2007</comment>
@@ -41142,6 +41908,7 @@ command to generate the output files.
<comment xml:lang="kk">PowerPoint 2007 презентациясы</comment>
<comment xml:lang="ja">PowerPoint 2007 プレゼンテーション</comment>
<comment xml:lang="it">Presentazione standard PowerPoint 2007</comment>
+ <comment xml:lang="is">PowerPoint 2007 kynning</comment>
<comment xml:lang="id">Presentasi PowerPoint 2007</comment>
<comment xml:lang="ia">Presentation PowerPoint 2007</comment>
<comment xml:lang="hu">PowerPoint 2007 prezentáció</comment>
@@ -41162,6 +41929,7 @@ command to generate the output files.
<comment xml:lang="cs">prezentace PowerPoint 2007</comment>
<comment xml:lang="ca">presentació de PowerPoint 2007</comment>
<comment xml:lang="bg">Презентация — PowerPoint 2007</comment>
+ <comment xml:lang="be">прэзентацыя PowerPoint 2007</comment>
<comment xml:lang="ar">عرض تقديمي بوربوينت 2007</comment>
<comment xml:lang="af">PowerPoint 2007-voorlegging</comment>
<glob pattern="*.pptx"/>
@@ -41176,20 +41944,23 @@ command to generate the output files.
<comment xml:lang="tr">PowerPoint 2007 slaytı</comment>
<comment xml:lang="sv">PowerPoint 2007-bildspel</comment>
<comment xml:lang="sr">слајд Пауер Поинта 2007</comment>
+ <comment xml:lang="sq">diapozitiv PowerPoint 2007</comment>
<comment xml:lang="sl">Prosojnica PowerPoint 2007</comment>
+ <comment xml:lang="si">PowerPoint 2007 ස්ලයිඩය</comment>
<comment xml:lang="sk">Snímka PowerPoint 2007</comment>
<comment xml:lang="ru">Слайд PowerPoint 2007</comment>
<comment xml:lang="pt_BR">Slide do PowerPoint 2007</comment>
<comment xml:lang="pt">diapositivo PowerPoint 2007</comment>
<comment xml:lang="pl">Slajd PowerPoint 2007</comment>
<comment xml:lang="oc">diapositive PowerPoint 2007</comment>
- <comment xml:lang="nl">PowerPoint 2007 dia</comment>
+ <comment xml:lang="nl">PowerPoint 2007-dia</comment>
<comment xml:lang="lv">PowerPoint 2007 slaids</comment>
<comment xml:lang="ko">PowerPoint 2007 슬라이드</comment>
<comment xml:lang="kk">PowerPoint 2007 слайды</comment>
<comment xml:lang="ka">PowerPoint 2007-ის სლაიდი</comment>
<comment xml:lang="ja">PowerPoint 2007 スライド</comment>
<comment xml:lang="it">Diapositiva PowerPoint 2007</comment>
+ <comment xml:lang="is">PowerPoint 2007 skyggna</comment>
<comment xml:lang="id">Slide PowerPoint 2007</comment>
<comment xml:lang="ia">Diapositiva PowerPoint 2007</comment>
<comment xml:lang="hu">PowerPoint 2007 dia</comment>
@@ -41204,11 +41975,12 @@ command to generate the output files.
<comment xml:lang="es">diapositiva de PowerPoint 2007</comment>
<comment xml:lang="en_GB">PowerPoint 2007 slide</comment>
<comment xml:lang="el">Διαφάνεια PowerPoint 2007</comment>
- <comment xml:lang="de">PowerPoint 2007-Folie</comment>
+ <comment xml:lang="de">PowerPoint-2007-Folie</comment>
<comment xml:lang="da">PowerPoint 2007-slide</comment>
<comment xml:lang="cs">snímek PowerPoint 2007</comment>
<comment xml:lang="ca">dispositiva de PowerPoint 2007</comment>
<comment xml:lang="bg">Кадър — PoerPoint 2007</comment>
+ <comment xml:lang="be">слайд PowerPoint 2007</comment>
<comment xml:lang="ar">شريحة بوربوينت 2007</comment>
<comment xml:lang="af">PowerPoint 2007-skyfie</comment>
<glob pattern="*.sldx"/>
@@ -41224,6 +41996,7 @@ command to generate the output files.
<comment xml:lang="sv">PowerPoint 2007-visning</comment>
<comment xml:lang="sr">приказ Пауер Поинта 2007</comment>
<comment xml:lang="sl">Zagonska predstavitev PowerPoint 2007</comment>
+ <comment xml:lang="si">PowerPoint 2007 ප්රදර්ශනය</comment>
<comment xml:lang="sk">Ukážka PowerPoint 2007</comment>
<comment xml:lang="ru">Презентация PowerPoint 2007</comment>
<comment xml:lang="ro">Prezentare PowerPoint 2007</comment>
@@ -41231,13 +42004,14 @@ command to generate the output files.
<comment xml:lang="pt">espetáculo PowerPoint 2007</comment>
<comment xml:lang="pl">Pokaz PowerPoint 2007</comment>
<comment xml:lang="oc">diaporama PowerPoint 2007</comment>
- <comment xml:lang="nl">PowerPoint 2007 show</comment>
+ <comment xml:lang="nl">PowerPoint 2007-show</comment>
<comment xml:lang="lv">PowerPoint 2007 slīdrāde</comment>
<comment xml:lang="lt">PowerPoint 2007 pateiktis</comment>
<comment xml:lang="ko">PowerPoint 2007 쇼</comment>
<comment xml:lang="kk">PowerPoint 2007 көрсетілімі</comment>
<comment xml:lang="ja">PowerPoint 2007 プレゼンテーション</comment>
<comment xml:lang="it">Solo presentazione PowerPoint 2007</comment>
+ <comment xml:lang="is">PowerPoint 2007 glærukynning</comment>
<comment xml:lang="id">Presentasi PowerPoint 2007</comment>
<comment xml:lang="ia">Projection de diapositivas PowerPoint 2007</comment>
<comment xml:lang="hu">PowerPoint 2007 bemutató</comment>
@@ -41258,6 +42032,7 @@ command to generate the output files.
<comment xml:lang="cs">prezentace PowerPoint 2007</comment>
<comment xml:lang="ca">exposició de PowerPoint 2007</comment>
<comment xml:lang="bg">Презентация-шоу — PowerPoint 2007</comment>
+ <comment xml:lang="be">паказ слайдаў PowerPoint 2007</comment>
<comment xml:lang="ar">عرض بوربوينت 2007</comment>
<comment xml:lang="af">PowerPoint 2007-vertoning</comment>
<glob pattern="*.ppsx"/>
@@ -41272,20 +42047,23 @@ command to generate the output files.
<comment xml:lang="tr">PowerPoint 2007 sunum şablonu</comment>
<comment xml:lang="sv">PowerPoint 2007-presentationsmall</comment>
<comment xml:lang="sr">шаблон презентације Пауер Поинта 2007</comment>
+ <comment xml:lang="sq">gjedhe paraqitjesh PowerPoint 2007</comment>
<comment xml:lang="sl">Predloga predstavitve PowerPoint 2007</comment>
+ <comment xml:lang="si">PowerPoint 2007 ඉදිරිපත් කිරීමේ අච්චුව</comment>
<comment xml:lang="sk">Šablóna prezentácie PowerPoint 2007</comment>
<comment xml:lang="ru">Шаблон презентации PowerPoint 2007</comment>
<comment xml:lang="pt_BR">Modelo de apresentação do PowerPoint 2007</comment>
<comment xml:lang="pt">modelo de apresentação PowerPoint 2007</comment>
<comment xml:lang="pl">Szablon prezentacji PowerPoint 2007</comment>
<comment xml:lang="oc">modèl de presentacion PowerPoint 2007</comment>
- <comment xml:lang="nl">PowerPoint 2007 presentation sjabloon</comment>
+ <comment xml:lang="nl">PowerPoint 2007-presentatiesjabloon</comment>
<comment xml:lang="lv">PowerPoint 2007 prezentācijas veidne</comment>
<comment xml:lang="ko">PowerPoint 2007 프레젠테이션 서식</comment>
<comment xml:lang="kk">PowerPoint 2007 презентация шаблоны</comment>
<comment xml:lang="ka">PowerPoint 2007-ის პრეზენტაციის შაბლონი</comment>
<comment xml:lang="ja">PowerPoint 2007 プレゼンテーションテンプレート</comment>
<comment xml:lang="it">Modello presentazione PowerPoint 2007</comment>
+ <comment xml:lang="is">PowerPoint 2007 sniðmát fyrir glærukynningu</comment>
<comment xml:lang="id">Templat presentasi PowerPoint 2007</comment>
<comment xml:lang="ia">Patrono de presentation PowerPoint 2007</comment>
<comment xml:lang="hu">PowerPoint 2007 bemutatósablon</comment>
@@ -41300,11 +42078,12 @@ command to generate the output files.
<comment xml:lang="es">plantilla de presentación de PowerPoint 2007</comment>
<comment xml:lang="en_GB">PowerPoint 2007 presentation template</comment>
<comment xml:lang="el">Πρότυπο παρουσίασης PowerPoint 2007</comment>
- <comment xml:lang="de">PowerPoint 2007-Präsentationsvorlage</comment>
+ <comment xml:lang="de">PowerPoint-2007-Präsentationsvorlage</comment>
<comment xml:lang="da">PowerPoint 2007-præsentationsskabelon</comment>
<comment xml:lang="cs">šablona prezentace PowerPoint 2007</comment>
<comment xml:lang="ca">plantilla de presentació de PowerPoint 2007</comment>
<comment xml:lang="bg">Шаблон за презентации — PowerPoint 2007</comment>
+ <comment xml:lang="be">шаблон прэзентацыі PowerPoint 2007</comment>
<comment xml:lang="ar">قالب عرض بوربوينت 2007</comment>
<comment xml:lang="af">PowerPoint 2007-voorleggingsjabloon</comment>
<glob pattern="*.potx"/>
@@ -41316,11 +42095,13 @@ command to generate the output files.
<comment xml:lang="zh_TW">Excel 2007 試算表</comment>
<comment xml:lang="zh_CN">Excel 2007 电子表格</comment>
<comment xml:lang="vi">Bảng tính Excel 2007</comment>
- <comment xml:lang="uk">ел. таблиця Excel 2007</comment>
+ <comment xml:lang="uk">електронна таблиця Excel 2007</comment>
<comment xml:lang="tr">Excel 2007 hesap çizelgesi sayfası</comment>
<comment xml:lang="sv">Excel 2007-kalkylblad</comment>
<comment xml:lang="sr">табела Ексела 2007</comment>
+ <comment xml:lang="sq">fletëllogaritje Excel 2007</comment>
<comment xml:lang="sl">Razpredelnica Microsoft Excel 2007</comment>
+ <comment xml:lang="si">Excel 2007 පැතුරුම්පත</comment>
<comment xml:lang="sk">Zošit Excel 2007</comment>
<comment xml:lang="ru">Электронная таблица Excel 2007</comment>
<comment xml:lang="ro">Foaie de calcul Excel 2007</comment>
@@ -41336,6 +42117,7 @@ command to generate the output files.
<comment xml:lang="ka">Excel 2007-ის ცხრილი</comment>
<comment xml:lang="ja">Excel 2007 スプレッドシート</comment>
<comment xml:lang="it">Foglio di calcolo Excel 2007</comment>
+ <comment xml:lang="is">Excel 2007 töflureikniskjal</comment>
<comment xml:lang="id">Lembar sebar Excel 2007</comment>
<comment xml:lang="ia">Folio de calculo Excel 2007</comment>
<comment xml:lang="hu">Excel 2007 táblázat</comment>
@@ -41356,6 +42138,7 @@ command to generate the output files.
<comment xml:lang="cs">sešit Excel 2007</comment>
<comment xml:lang="ca">full de càlcul d'Excel 2007</comment>
<comment xml:lang="bg">Таблица — Excel 2007</comment>
+ <comment xml:lang="be">электронная табліца Excel 2007</comment>
<comment xml:lang="ar">جدول اكسل 2007</comment>
<comment xml:lang="af">Excel 2007-sigblad</comment>
<glob pattern="*.xlsx"/>
@@ -41370,7 +42153,9 @@ command to generate the output files.
<comment xml:lang="tr">Excel 2007 hesap çizelgesi şablonu</comment>
<comment xml:lang="sv">Excel 2007-kalkylarksmall</comment>
<comment xml:lang="sr">шаблон табеле Ексела 2007</comment>
+ <comment xml:lang="sq">gjedhe fletëllogaritjesh Excel 2007</comment>
<comment xml:lang="sl">Predloga razpredelnice Excel 2007</comment>
+ <comment xml:lang="si">Excel 2007 පැතුරුම්පත් අච්චුව</comment>
<comment xml:lang="sk">Šablóna zošitu Excel 2007</comment>
<comment xml:lang="ru">Шаблон электронной таблицы Excel 2007</comment>
<comment xml:lang="pt_BR">Modelo de planilha do Excel 2007</comment>
@@ -41384,6 +42169,7 @@ command to generate the output files.
<comment xml:lang="ka">Excel 2007-ის ცხრილის შაბლონი</comment>
<comment xml:lang="ja">Excel 2007 スプレッドシートテンプレート</comment>
<comment xml:lang="it">Modello foglio di calcolo Excel 2007</comment>
+ <comment xml:lang="is">Excel 2007 töflureiknisniðmát</comment>
<comment xml:lang="id">Templat lembar kerja Excel 2007</comment>
<comment xml:lang="ia">Patrono de folio de calculo Excel 2007</comment>
<comment xml:lang="hu">Excel 2007 táblázatsablon</comment>
@@ -41398,17 +42184,33 @@ command to generate the output files.
<comment xml:lang="es">plantilla de hoja de cálculo de Excel 2007</comment>
<comment xml:lang="en_GB">Excel 2007 spreadsheet template</comment>
<comment xml:lang="el">Πρότυπο λογιστικού φύλλου Excel 2007</comment>
- <comment xml:lang="de">Excel 2007-Tabellenvorlage</comment>
+ <comment xml:lang="de">Excel-2007-Tabellenvorlage</comment>
<comment xml:lang="da">Excel 2007-regnearksskabelon</comment>
<comment xml:lang="cs">šablona sešitu Excel 2007</comment>
<comment xml:lang="ca">plantilla de full de càlcul d'Excel 2007</comment>
<comment xml:lang="bg">Шаблон за таблици — Excel 2007</comment>
+ <comment xml:lang="be">шаблон электроннай табліцы Excel 2007</comment>
<comment xml:lang="ar">قالب جدول اكسل 2007</comment>
<comment xml:lang="af">Excel 2007-sigbladsjabloon</comment>
<glob pattern="*.xltx"/>
<sub-class-of type="application/zip"/>
<generic-icon name="x-office-spreadsheet"/>
</mime-type>
+ <mime-type type="application/vnd.ms-officetheme">
+ <comment>Microsoft Office 2007 theme</comment>
+ <comment xml:lang="uk">тема Microsoft Office 2007</comment>
+ <comment xml:lang="sv">Microsoft Office 2007-tema</comment>
+ <comment xml:lang="ru">Тема Microsoft Office 2007</comment>
+ <comment xml:lang="pl">Motyw Microsoft Office 2007</comment>
+ <comment xml:lang="it">Tema Microsoft Office 2007</comment>
+ <comment xml:lang="eu">Microsoft Office 2007 gaia</comment>
+ <comment xml:lang="es">tema de Microsoft Office 2007</comment>
+ <comment xml:lang="de">Microsoft-Office-2007-Thema</comment>
+ <comment xml:lang="be">тэма Microsoft Office 2007</comment>
+ <glob pattern="*.thmx"/>
+ <sub-class-of type="application/zip"/>
+ <generic-icon name="text-x-generic-template"/>
+ </mime-type>
<mime-type type="application/x-t602">
<comment>T602 document</comment>
<comment xml:lang="zh_TW">T602 文件</comment>
@@ -41418,8 +42220,9 @@ command to generate the output files.
<comment xml:lang="tr">T602 belgesi</comment>
<comment xml:lang="sv">T602-dokument</comment>
<comment xml:lang="sr">Т602 документ</comment>
- <comment xml:lang="sq">Dokument T602</comment>
+ <comment xml:lang="sq">dokument T602</comment>
<comment xml:lang="sl">Dokument T602</comment>
+ <comment xml:lang="si">T602 ලේඛනය</comment>
<comment xml:lang="sk">Dokument T602</comment>
<comment xml:lang="ru">Документ T602</comment>
<comment xml:lang="ro">Document T602</comment>
@@ -41436,6 +42239,7 @@ command to generate the output files.
<comment xml:lang="kk">T602 құжаты</comment>
<comment xml:lang="ja">T602 ドキュメント</comment>
<comment xml:lang="it">Documento T602</comment>
+ <comment xml:lang="is">T602 skjal</comment>
<comment xml:lang="id">Dokumen T602</comment>
<comment xml:lang="ia">Documento T602</comment>
<comment xml:lang="hu">T602 dokumentum</comment>
@@ -41458,6 +42262,7 @@ command to generate the output files.
<comment xml:lang="ca">document T602</comment>
<comment xml:lang="bg">Документ — T602</comment>
<comment xml:lang="be@latin">Dakument T602</comment>
+ <comment xml:lang="be">дакумент T602</comment>
<comment xml:lang="ast">Documentu T602</comment>
<comment xml:lang="ar">مستند T602</comment>
<comment xml:lang="af">T602-dokument</comment>
@@ -41476,20 +42281,25 @@ command to generate the output files.
<comment xml:lang="uk">параметри VPN Cisco</comment>
<comment xml:lang="tr">Cisco VPN ayarları</comment>
<comment xml:lang="sv">Cisco VPN-inställningar</comment>
+ <comment xml:lang="sq">rregullime VPN-je Cisco</comment>
<comment xml:lang="sl">Nastavitve Cisco VPN</comment>
+ <comment xml:lang="si">Cisco VPN සැකසුම්</comment>
<comment xml:lang="sk">Nastavenia Cisco VPN</comment>
<comment xml:lang="ru">Файл настроек Cisco VPN</comment>
<comment xml:lang="pt_BR">Configurações de VPN da Cisco</comment>
<comment xml:lang="pl">Ustawienia VPN Cisco</comment>
<comment xml:lang="oc">paramètres VPN Cisco</comment>
+ <comment xml:lang="nl">Cisco VPN-instellingen</comment>
<comment xml:lang="ko">시스코 VPN 설정</comment>
<comment xml:lang="kk">Cisco VPN баптаулары</comment>
<comment xml:lang="ja">Cisco VPN 設定</comment>
<comment xml:lang="it">Impostazioni VPN Cisco</comment>
+ <comment xml:lang="is">Cisco VPN-stillingar</comment>
<comment xml:lang="id">Pengaturan VPN Cisco</comment>
<comment xml:lang="hu">Cisco VPN beállítások</comment>
<comment xml:lang="hr">Cisco VPN postavke</comment>
<comment xml:lang="he">הגדרות VPN של Cisco</comment>
+ <comment xml:lang="gl">Configuracións de Cisco VPN</comment>
<comment xml:lang="fr">paramètres VPN Cisco</comment>
<comment xml:lang="fi">Ciscon VPN-asetukset</comment>
<comment xml:lang="eu">Cisco VPN ezarpenak</comment>
@@ -41499,6 +42309,7 @@ command to generate the output files.
<comment xml:lang="da">Cisco VPN-indstillinger</comment>
<comment xml:lang="ca">ajusts VPN de Cisco</comment>
<comment xml:lang="bg">Настройки — ВЧМ на Cisco</comment>
+ <comment xml:lang="be">налады Cisco VPN</comment>
<comment xml:lang="ar">إعدادات Cisco VPN</comment>
<sub-class-of type="text/plain"/>
<generic-icon name="text-x-generic"/>
@@ -41517,7 +42328,9 @@ command to generate the output files.
<comment xml:lang="tr">ICC profili</comment>
<comment xml:lang="sv">ICC-profil</comment>
<comment xml:lang="sr">ИЦЦ профил</comment>
+ <comment xml:lang="sq">profil ICC</comment>
<comment xml:lang="sl">Datoteka profila ICC</comment>
+ <comment xml:lang="si">ICC පැතිකඩ</comment>
<comment xml:lang="sk">Profil farieb ICC</comment>
<comment xml:lang="ru">Профиль ICC</comment>
<comment xml:lang="ro">Profil ICC</comment>
@@ -41525,13 +42338,15 @@ command to generate the output files.
<comment xml:lang="pt">perfil ICC</comment>
<comment xml:lang="pl">Profil ICC</comment>
<comment xml:lang="oc">perfil ICC</comment>
- <comment xml:lang="nl">ICC profiel</comment>
+ <comment xml:lang="nl">ICC-profiel</comment>
<comment xml:lang="lv">ICC profils</comment>
<comment xml:lang="lt">ICC profilis</comment>
<comment xml:lang="ko">ICC 프로필</comment>
<comment xml:lang="kk">ICC профайлы</comment>
+ <comment xml:lang="ka">ICC პროფილი</comment>
<comment xml:lang="ja">ICC プロファイル</comment>
<comment xml:lang="it">Profilo ICC</comment>
+ <comment xml:lang="is">ICC snið</comment>
<comment xml:lang="id">Profil ICC</comment>
<comment xml:lang="ia">Profilo ICC</comment>
<comment xml:lang="hu">ICC profil</comment>
@@ -41553,6 +42368,7 @@ command to generate the output files.
<comment xml:lang="cs">profil ICC</comment>
<comment xml:lang="ca">perfil ICC</comment>
<comment xml:lang="bg">Цветови профил — OCL</comment>
+ <comment xml:lang="be">профіль ICC</comment>
<comment xml:lang="ast">Perfil ICC</comment>
<comment xml:lang="ar">تشكيلة ICC</comment>
<comment xml:lang="af">ICC-profiel</comment>
@@ -41572,7 +42388,9 @@ command to generate the output files.
<comment xml:lang="tr">IT 8.7 renk kalibrasyon dosyası</comment>
<comment xml:lang="sv">IT 8.7-färgkalibreringsfil</comment>
<comment xml:lang="sr">ИТ 8.7 датотека калибрације боје</comment>
+ <comment xml:lang="sq">kartelë kalibrimi ngjyrash IT 8.7</comment>
<comment xml:lang="sl">Umeritvena datoteka barve IT 8.7</comment>
+ <comment xml:lang="si">IT 8.7 වර්ණ ක්‍රමාංකන ගොනුව</comment>
<comment xml:lang="sk">Súbor kalibrácie farieb IT 8.7</comment>
<comment xml:lang="ru">Файл калибровки цвета IT 8.7</comment>
<comment xml:lang="ro">Fișier de calibrare a culorii IT 8.7</comment>
@@ -41580,13 +42398,14 @@ command to generate the output files.
<comment xml:lang="pt">ficheiro de calibração de cor IT 8.7</comment>
<comment xml:lang="pl">Plik kalibracji kolorów IT 8.7</comment>
<comment xml:lang="oc">fichièr de calibracion color IT 8.7</comment>
- <comment xml:lang="nl">IT 8.7 kleurcalibratie bestand</comment>
+ <comment xml:lang="nl">IT 8.7-kleurcalibratiebestand</comment>
<comment xml:lang="lv">IT 8.7 krāsu kalibrācijas datne</comment>
<comment xml:lang="lt">IT 8.7 spalvų kalibravimo failas</comment>
<comment xml:lang="ko">IT 8.7 색 조율 파일</comment>
<comment xml:lang="kk">IT 8.7 түс баптау файлы</comment>
<comment xml:lang="ja">IT 8.7 カラーキャリブレーションファイル</comment>
<comment xml:lang="it">File calibrazione colore IT 8.7</comment>
+ <comment xml:lang="is">IT 8.7 litkvörðunarskrá</comment>
<comment xml:lang="id">Berkas kalibrasi warna IT 8.7</comment>
<comment xml:lang="ia">File de calibration de colores IT 8.7</comment>
<comment xml:lang="hu">IT 8.7 színkalibrációs fájl</comment>
@@ -41602,11 +42421,12 @@ command to generate the output files.
<comment xml:lang="es">archivo de calibración de color IT 8.7</comment>
<comment xml:lang="en_GB">IT 8.7 color calibration file</comment>
<comment xml:lang="el">Αρχείο βαθμονόμησης χρώματος ΙΤ 8.7</comment>
- <comment xml:lang="de">IT 8.7-Farbkalibrierungsdatei</comment>
+ <comment xml:lang="de">IT-8.7-Farbkalibrierungsdatei</comment>
<comment xml:lang="da">IT 8.7 farvekalibreringsfil</comment>
<comment xml:lang="cs">soubor kalibrace barev IT 8.7</comment>
<comment xml:lang="ca">fitxer de calibratge de color IT 8.7</comment>
<comment xml:lang="bg">Цветово калибриране — IT 8.7</comment>
+ <comment xml:lang="be">файл каліброўкі колеру IT 8.7</comment>
<comment xml:lang="ar">ملف ضبط ألوان IT 8.7</comment>
<magic>
<match type="string" value="IT8.7" offset="0"/>
@@ -41623,18 +42443,22 @@ command to generate the output files.
<comment xml:lang="tr">CCMX renk düzeltme dosyası</comment>
<comment xml:lang="sv">CCMX-färgkorrigeringsfil</comment>
<comment xml:lang="sr">ЦЦМИкс датотека поправке боје</comment>
+ <comment xml:lang="sq">kartelë saktësimi ngjyrash CCMX</comment>
<comment xml:lang="sl">Datoteka barvne poprave CCMX</comment>
+ <comment xml:lang="si">CCMX වර්ණ නිවැරදි කිරීමේ ගොනුව</comment>
<comment xml:lang="sk">Súbor korekcie farieb CCMX</comment>
<comment xml:lang="ru">Файл цветовой коррекции CCMX</comment>
<comment xml:lang="pt_BR">Arquivo de correção de cor CCMX</comment>
<comment xml:lang="pt">ficheiro de correção de cor CCMX</comment>
<comment xml:lang="pl">Plik korekcji kolorów CCMX</comment>
<comment xml:lang="oc">fichièr de correccion colorimetrica CCMX</comment>
+ <comment xml:lang="nl">CCMX-kleurcorrectiebestand</comment>
<comment xml:lang="lv">CCMX krāsu korekciju datne</comment>
<comment xml:lang="ko">CCMX 색상 보정 파일</comment>
<comment xml:lang="kk">CCMX түсті келтіру файлы</comment>
<comment xml:lang="ja">CCMX カラー訂正ファイル</comment>
<comment xml:lang="it">File correzione colore CCMX</comment>
+ <comment xml:lang="is">CCMX litleiðréttingarskrá</comment>
<comment xml:lang="id">Berkas koreksi warna CCMX</comment>
<comment xml:lang="ia">File de correction de colores CCMX</comment>
<comment xml:lang="hu">CCMX színjavítási fájl</comment>
@@ -41654,6 +42478,7 @@ command to generate the output files.
<comment xml:lang="cs">soubor korekce barev CCMX</comment>
<comment xml:lang="ca">fitxer de correcció de color CCMX</comment>
<comment xml:lang="bg">Цветови поправки — CCMX</comment>
+ <comment xml:lang="be">файл карэкцыі колеру CCMX</comment>
<comment xml:lang="ar">ملف تصحيح لون CCMX</comment>
<magic>
<match type="string" value="CCMX" offset="0"/>
@@ -41670,18 +42495,22 @@ command to generate the output files.
<comment xml:lang="tr">WinHelp yardım dosyası</comment>
<comment xml:lang="sv">WinHelp-hjälpfil</comment>
<comment xml:lang="sr">датотека помоћи Вин хелпа</comment>
+ <comment xml:lang="sq">kartelë ndihme WinHelp</comment>
<comment xml:lang="sl">Datoteka pomoči WinHelp</comment>
+ <comment xml:lang="si">WinHelp උදව් ගොනුව</comment>
<comment xml:lang="sk">Súbor Pomocníka WinHelp</comment>
<comment xml:lang="ru">Файл справки WinHelp</comment>
<comment xml:lang="pt_BR">Arquivo de ajuda WinHelp</comment>
<comment xml:lang="pt">ficheiro de ajuda WinHelp</comment>
<comment xml:lang="pl">Plik pomocy WinHelp</comment>
<comment xml:lang="oc">fichièr d'ajuda WinHelp</comment>
+ <comment xml:lang="nl">WinHelp-hulpbestand</comment>
<comment xml:lang="lv">WinHelp palīdzības datne</comment>
<comment xml:lang="ko">WinHelp 도움말 파일</comment>
<comment xml:lang="kk">WinHelp көмек файлы</comment>
<comment xml:lang="ja">WinHelp ヘルプファイル</comment>
<comment xml:lang="it">File aiuto WInHelp</comment>
+ <comment xml:lang="is">WinHelp-hjálparskrá</comment>
<comment xml:lang="id">Berkas bantuan WinHelp</comment>
<comment xml:lang="ia">File de adjuta WinHelp</comment>
<comment xml:lang="hu">WinHelp súgófájl</comment>
@@ -41701,6 +42530,7 @@ command to generate the output files.
<comment xml:lang="cs">soubor nápovědy WinHelp</comment>
<comment xml:lang="ca">fitxer d'ajuda WinHelp</comment>
<comment xml:lang="bg">Помощен файл — WinHelp</comment>
+ <comment xml:lang="be">файл даведкі WinHelp</comment>
<comment xml:lang="ar">ملف مساعدة ويندوز</comment>
<comment xml:lang="af">WinHelp-hulplêer</comment>
<magic>
@@ -41710,38 +42540,16 @@ command to generate the output files.
<alias type="zz-application/zz-winassoc-hlp"/>
</mime-type>
<mime-type type="application/x-bsdiff">
- <comment>binary differences between files</comment>
- <comment xml:lang="zh_TW">檔案間的二進位差異</comment>
- <comment xml:lang="zh_CN">文件的二进制区别</comment>
+ <comment>Binary differences between files</comment>
<comment xml:lang="uk">двійкова різниця між файлами</comment>
- <comment xml:lang="tr">dosyalar arasındaki ikilik farklar</comment>
- <comment xml:lang="sv">binära skillnader mellan filer</comment>
- <comment xml:lang="sr">бинарне разлике датотека</comment>
- <comment xml:lang="sk">Binárne rozdiely medzi súbormi</comment>
+ <comment xml:lang="sv">Binära skillnader mellan filer</comment>
<comment xml:lang="ru">Двоичные различия между файлами</comment>
- <comment xml:lang="pt_BR">Diferenças binárias entre arquivos</comment>
<comment xml:lang="pl">Binarna różnica pomiędzy plikami</comment>
- <comment xml:lang="ko">바이너리 차이 비교 파일</comment>
- <comment xml:lang="kk">файлдар арасындағы бинарлық айырмашылықтар</comment>
- <comment xml:lang="ja">ファイル間バイナリ差分</comment>
<comment xml:lang="it">Differenze binarie tra file</comment>
- <comment xml:lang="id">perbedaan biner antar berkas</comment>
- <comment xml:lang="hu">bináris különbségfájl</comment>
- <comment xml:lang="hr">Binarne razlike između datoteka</comment>
- <comment xml:lang="he">הבדלים בינריים בין קבצים</comment>
- <comment xml:lang="ga">difríochtaí dénártha idir comhaid</comment>
- <comment xml:lang="fur">diferencis binariis tra file</comment>
- <comment xml:lang="fr">différences binaires entre fichiers</comment>
- <comment xml:lang="fi">binääriset erot tiedostojen välillä</comment>
- <comment xml:lang="eu">fitxategi binarioen arteko ezberdinstasunak</comment>
- <comment xml:lang="es">diferencias entre archivos binarios</comment>
- <comment xml:lang="en_GB">binary differences between files</comment>
- <comment xml:lang="de">binäre Unterschiede zwischen Dateien</comment>
- <comment xml:lang="da">binære forskelle mellem filer</comment>
- <comment xml:lang="cs">binární rozdíl mezi soubory</comment>
- <comment xml:lang="ca">diferencies binàries entre fitxers</comment>
- <comment xml:lang="bg">двоична разлика между файлове</comment>
- <comment xml:lang="ar">فرق ثنائي بين ملفات</comment>
+ <comment xml:lang="eu">Fitxategien arteko diferentzia bitarra</comment>
+ <comment xml:lang="es">diferencias binarias entre archivos</comment>
+ <comment xml:lang="de">Binäre Unterschiede zwischen Dateien</comment>
+ <comment xml:lang="be">бінарныя адрозненні паміж файламі</comment>
<magic>
<match type="string" value="BSDIFF40" offset="0"/>
<match type="string" value="BSDIFN40" offset="0"/>
@@ -41751,54 +42559,18 @@ command to generate the output files.
<!-- Tree content-types -->
<mime-type type="x-content/image-dcf">
<!-- http://en.wikipedia.org/wiki/Design_rule_for_Camera_File_system -->
- <comment>digital photos</comment>
- <comment xml:lang="zh_TW">數位相片</comment>
- <comment xml:lang="zh_CN">数字化图像</comment>
- <comment xml:lang="vi">ảnh chụp số</comment>
+ <comment>Digital photos</comment>
<comment xml:lang="uk">цифрові фотографії</comment>
- <comment xml:lang="tr">sayısal fotoğraflar</comment>
- <comment xml:lang="sv">digitalbilder</comment>
- <comment xml:lang="sr">дигиталне фотографије</comment>
- <comment xml:lang="sq">Fotografi dixhitale</comment>
- <comment xml:lang="sl">digitalne fotografije</comment>
- <comment xml:lang="sk">Digitálne fotografie</comment>
+ <comment xml:lang="sv">Digitalbilder</comment>
<comment xml:lang="ru">Цифровые фотографии</comment>
- <comment xml:lang="ro">fotografii digitale</comment>
<comment xml:lang="pt_BR">Fotos digitais</comment>
- <comment xml:lang="pt">fotografias digitais</comment>
<comment xml:lang="pl">Zdjęcia cyfrowe</comment>
- <comment xml:lang="oc">fòtos numericas</comment>
- <comment xml:lang="nn">digitale fotografi</comment>
- <comment xml:lang="nl">digitale foto's</comment>
- <comment xml:lang="lv">digitāla fotogrāfija</comment>
- <comment xml:lang="lt">skaitmeninės nuotraukos</comment>
- <comment xml:lang="ko">디지털 사진</comment>
- <comment xml:lang="kk">сандық фотосуреттер</comment>
- <comment xml:lang="ja">デジタルフォト</comment>
<comment xml:lang="it">Foto digitali</comment>
- <comment xml:lang="id">foto digital</comment>
- <comment xml:lang="ia">Photos digital</comment>
- <comment xml:lang="hu">digitális fényképek</comment>
- <comment xml:lang="hr">Digitalne fotografije</comment>
- <comment xml:lang="he">תמונות דיגיטליות</comment>
- <comment xml:lang="gl">fotos dixitais</comment>
- <comment xml:lang="ga">grianghraif dhigiteacha</comment>
- <comment xml:lang="fur">fotos digjitâls</comment>
- <comment xml:lang="fr">photos numériques</comment>
- <comment xml:lang="fo">talgildar myndir</comment>
- <comment xml:lang="fi">digivalokuvia</comment>
- <comment xml:lang="eu">argazki digitalak</comment>
- <comment xml:lang="es">fotos digitales</comment>
- <comment xml:lang="en_GB">digital photos</comment>
- <comment xml:lang="el">Ψηφιακές φωτογραφίες</comment>
+ <comment xml:lang="gl">Fotos dixitais</comment>
+ <comment xml:lang="eu">Argazki digitalak</comment>
+ <comment xml:lang="es">fotografías digitales</comment>
<comment xml:lang="de">Digitale Fotos</comment>
- <comment xml:lang="da">digitale billeder</comment>
- <comment xml:lang="cs">digitální fotografie</comment>
- <comment xml:lang="ca">fotos digitals</comment>
- <comment xml:lang="bg">Цифрови фотографии</comment>
- <comment xml:lang="be@latin">ličbavyja zdymki</comment>
- <comment xml:lang="ar">صور رقمية</comment>
- <comment xml:lang="af">digitale foto’s</comment>
+ <comment xml:lang="be">лічбавыя фатаграфіі</comment>
<treemagic>
<treematch path="dcim" type="directory" non-empty="true"/>
</treemagic>
@@ -41817,6 +42589,7 @@ command to generate the output files.
<comment xml:lang="sr">Видео ЦД</comment>
<comment xml:lang="sq">CD Video</comment>
<comment xml:lang="sl">Video CD</comment>
+ <comment xml:lang="si">වීඩියෝ සීඩී</comment>
<comment xml:lang="sk">Video CD</comment>
<comment xml:lang="ru">Видео CD</comment>
<comment xml:lang="ro">CD video</comment>
@@ -41830,8 +42603,10 @@ command to generate the output files.
<comment xml:lang="lt">Vaizdo CD</comment>
<comment xml:lang="ko">비디오 CD</comment>
<comment xml:lang="kk">видео CD</comment>
+ <comment xml:lang="ka">ვიდეო CD</comment>
<comment xml:lang="ja">ビデオ CD</comment>
<comment xml:lang="it">Video CD</comment>
+ <comment xml:lang="is">Video CD-mynddiskur</comment>
<comment xml:lang="id">Video CD</comment>
<comment xml:lang="ia">Video CD</comment>
<comment xml:lang="hu">Video CD</comment>
@@ -41854,6 +42629,7 @@ command to generate the output files.
<comment xml:lang="ca">Video CD</comment>
<comment xml:lang="bg">CD — видео</comment>
<comment xml:lang="be@latin">Videa CD</comment>
+ <comment xml:lang="be">відэа CD</comment>
<comment xml:lang="ast">CD de videu</comment>
<comment xml:lang="ar">سي دي فيديو</comment>
<comment xml:lang="af">Video-CD</comment>
@@ -41875,6 +42651,7 @@ command to generate the output files.
<comment xml:lang="sr">Супер видео ЦД</comment>
<comment xml:lang="sq">CD Super Video</comment>
<comment xml:lang="sl">Super Video CD</comment>
+ <comment xml:lang="si">සුපිරි වීඩියෝ CD</comment>
<comment xml:lang="sk">Super Video CD</comment>
<comment xml:lang="ru">Super Video CD</comment>
<comment xml:lang="ro">Super Video CD</comment>
@@ -41888,8 +42665,10 @@ command to generate the output files.
<comment xml:lang="lt">Super vaizdo CD</comment>
<comment xml:lang="ko">수퍼 비디오 CD</comment>
<comment xml:lang="kk">Super Video CD</comment>
+ <comment xml:lang="ka">Super Video CD</comment>
<comment xml:lang="ja">スーパービデオ CD</comment>
<comment xml:lang="it">Super Video CD</comment>
+ <comment xml:lang="is">Super Video CD-mynddiskur</comment>
<comment xml:lang="id">Super Video CD</comment>
<comment xml:lang="ia">Super Video CD</comment>
<comment xml:lang="hu">Super Video CD</comment>
@@ -41912,6 +42691,7 @@ command to generate the output files.
<comment xml:lang="ca">Super Video CD</comment>
<comment xml:lang="bg">CD — супер видео</comment>
<comment xml:lang="be@latin">Super Video CD</comment>
+ <comment xml:lang="be">Super Video CD</comment>
<comment xml:lang="ast">CD de Super Video</comment>
<comment xml:lang="ar">سي دي فيديو فائق</comment>
<comment xml:lang="af">Super Video-CD</comment>
@@ -41921,57 +42701,19 @@ command to generate the output files.
</mime-type>
<mime-type type="x-content/video-dvd">
<!-- http://en.wikipedia.org/wiki/DVD-Video -->
- <comment>video DVD</comment>
- <comment xml:lang="zh_TW">視訊 DVD</comment>
- <comment xml:lang="zh_CN">视频 DVD</comment>
- <comment xml:lang="vi">đĩa DVD ảnh động</comment>
- <comment xml:lang="uk">відео-DVD</comment>
- <comment xml:lang="tr">video DVD</comment>
- <comment xml:lang="sv">video-dvd</comment>
- <comment xml:lang="sr">видео ДВД</comment>
- <comment xml:lang="sq">DVD video</comment>
- <comment xml:lang="sl">video DVD</comment>
- <comment xml:lang="sk">DVD-Video</comment>
+ <comment>Video DVD</comment>
+ <comment xml:lang="uk">DVD з відеозаписами</comment>
+ <comment xml:lang="sv">Video-dvd</comment>
<comment xml:lang="ru">Видео DVD</comment>
- <comment xml:lang="ro">DVD video</comment>
<comment xml:lang="pt_BR">DVD de vídeo</comment>
- <comment xml:lang="pt">DVD vídeo</comment>
<comment xml:lang="pl">DVD-Video</comment>
- <comment xml:lang="oc">DVD vidèo</comment>
- <comment xml:lang="nn">Video-DVD</comment>
- <comment xml:lang="nl">video-DVD</comment>
- <comment xml:lang="lv">video DVD</comment>
- <comment xml:lang="lt">vaizdo DVD</comment>
- <comment xml:lang="ko">동영상 DVD</comment>
- <comment xml:lang="kk">видео DVD</comment>
- <comment xml:lang="ka">ვიდეო DVD</comment>
- <comment xml:lang="ja">ビデオ DVD</comment>
+ <comment xml:lang="ja">動画DVD</comment>
<comment xml:lang="it">DVD video</comment>
- <comment xml:lang="id">DVD video</comment>
- <comment xml:lang="ia">DVD video</comment>
- <comment xml:lang="hu">video DVD</comment>
- <comment xml:lang="hr">Video DVD</comment>
- <comment xml:lang="he">DVD וידאו</comment>
<comment xml:lang="gl">DVD de vídeo</comment>
- <comment xml:lang="ga">DVD físe</comment>
- <comment xml:lang="fur">DVD video</comment>
- <comment xml:lang="fr">DVD vidéo</comment>
- <comment xml:lang="fo">video DVD</comment>
- <comment xml:lang="fi">video-DVD</comment>
- <comment xml:lang="eu">bideo DVDa</comment>
+ <comment xml:lang="eu">Bideoko DVDa</comment>
<comment xml:lang="es">DVD de vídeo</comment>
- <comment xml:lang="eo">video-DVD</comment>
- <comment xml:lang="en_GB">video DVD</comment>
- <comment xml:lang="el">Βίντεο DVD</comment>
<comment xml:lang="de">Video-DVD</comment>
- <comment xml:lang="da">video-dvd</comment>
- <comment xml:lang="cs">videodisk DVD</comment>
- <comment xml:lang="ca">DVD de video</comment>
- <comment xml:lang="bg">DVD — видео</comment>
- <comment xml:lang="be@latin">videa DVD</comment>
- <comment xml:lang="ast">DVD de videu</comment>
- <comment xml:lang="ar">فيديو DVD</comment>
- <comment xml:lang="af">video-DVD</comment>
+ <comment xml:lang="be">відэа DVD</comment>
<treemagic>
<treematch path="VIDEO_TS/VIDEO_TS.IFO" type="file"/>
<treematch path="VIDEO_TS/VIDEO_TS.IFO;1" type="file"/>
@@ -41981,311 +42723,96 @@ command to generate the output files.
</mime-type>
<mime-type type="x-content/audio-cdda">
<!-- http://en.wikipedia.org/wiki/Red_Book_(audio_CD_standard) -->
- <comment>audio CD</comment>
- <comment xml:lang="zh_TW">音訊 CD</comment>
- <comment xml:lang="zh_CN">音频 CD</comment>
- <comment xml:lang="vi">đĩa CD âm thanh</comment>
- <comment xml:lang="uk">звуковий CD</comment>
- <comment xml:lang="tr">ses CD'si</comment>
- <comment xml:lang="sv">ljud-cd</comment>
- <comment xml:lang="sr">звучни ЦД</comment>
- <comment xml:lang="sq">CD audio</comment>
- <comment xml:lang="sl">zvočni CD</comment>
- <comment xml:lang="sk">Zvukové CD</comment>
+ <comment>Audio CD</comment>
+ <comment xml:lang="uk">звуковий компакт-диск</comment>
+ <comment xml:lang="sv">Ljud-cd</comment>
<comment xml:lang="ru">Аудио CD</comment>
- <comment xml:lang="ro">CD audio</comment>
<comment xml:lang="pt_BR">CD de áudio</comment>
- <comment xml:lang="pt">CD áudio</comment>
<comment xml:lang="pl">CD-Audio</comment>
- <comment xml:lang="oc">CD àudio</comment>
- <comment xml:lang="nn">lyd-CD</comment>
- <comment xml:lang="nl">audio-CD</comment>
- <comment xml:lang="lv">audio CD</comment>
- <comment xml:lang="lt">garso CD</comment>
- <comment xml:lang="ko">오디오 CD</comment>
- <comment xml:lang="kk">аудио CD</comment>
- <comment xml:lang="ja">オーディオ CD</comment>
+ <comment xml:lang="ja">音声CD</comment>
<comment xml:lang="it">CD audio</comment>
- <comment xml:lang="id">CD audio</comment>
- <comment xml:lang="ia">CD audio</comment>
- <comment xml:lang="hu">hang CD</comment>
- <comment xml:lang="hr">Glazbeni CD</comment>
- <comment xml:lang="he">תקליטור שמע</comment>
<comment xml:lang="gl">CD de son</comment>
- <comment xml:lang="ga">dlúthdhiosca fuaime</comment>
- <comment xml:lang="fur">CD audio</comment>
- <comment xml:lang="fr">CD audio</comment>
- <comment xml:lang="fo">audio CD</comment>
- <comment xml:lang="fi">ääni-CD</comment>
- <comment xml:lang="eu">Audio CDa</comment>
+ <comment xml:lang="eu">Audioko CDa</comment>
<comment xml:lang="es">CD de audio</comment>
- <comment xml:lang="eo">Son-KD</comment>
- <comment xml:lang="en_GB">audio CD</comment>
- <comment xml:lang="el">CD ήχου</comment>
<comment xml:lang="de">Audio-CD</comment>
- <comment xml:lang="da">lyd-cd</comment>
- <comment xml:lang="cs">zvukové CD</comment>
- <comment xml:lang="ca">CD d'àudio</comment>
- <comment xml:lang="bg">CD — аудио</comment>
- <comment xml:lang="be@latin">aŭdyjo CD</comment>
- <comment xml:lang="ar">صوت CD</comment>
- <comment xml:lang="af">oudio-CD</comment>
+ <comment xml:lang="be">аўдыя CD</comment>
</mime-type>
<mime-type type="x-content/blank-cd">
<!-- http://en.wikipedia.org/wiki/Compact_Disc -->
- <comment>blank CD disc</comment>
- <comment xml:lang="zh_TW">空白 CD 光碟</comment>
- <comment xml:lang="zh_CN">空 CD 光盘</comment>
- <comment xml:lang="vi">đĩa CD trống</comment>
+ <comment>Blank CD disc</comment>
<comment xml:lang="uk">порожній компакт-диск</comment>
- <comment xml:lang="tr">boş CD diski</comment>
- <comment xml:lang="sv">tom cd-skiva</comment>
- <comment xml:lang="sr">празан ЦД диск</comment>
- <comment xml:lang="sq">Disk bosh CD</comment>
- <comment xml:lang="sl">prazen CD disk</comment>
- <comment xml:lang="sk">Prázdny disk CD</comment>
+ <comment xml:lang="sv">Tom cd-skiva</comment>
<comment xml:lang="ru">Чистый диск CD</comment>
- <comment xml:lang="ro">disc gol CD</comment>
<comment xml:lang="pt_BR">Disco CD vazio</comment>
- <comment xml:lang="pt">CD vazio</comment>
<comment xml:lang="pl">Pusta płyta CD</comment>
- <comment xml:lang="oc">CD verge</comment>
- <comment xml:lang="nn">tom CD-plate</comment>
- <comment xml:lang="nl">blanco CD</comment>
- <comment xml:lang="lv">tukšs CD disks</comment>
- <comment xml:lang="lt">tuščias CD diskas</comment>
- <comment xml:lang="ko">빈 CD 디스크</comment>
- <comment xml:lang="kk">таза CD дискі</comment>
- <comment xml:lang="ja">ブランク CD ディスク</comment>
+ <comment xml:lang="ja">空CD</comment>
<comment xml:lang="it">Disco vuoto CD</comment>
- <comment xml:lang="id">cakram CD kosong</comment>
- <comment xml:lang="ia">Disco CD vacue</comment>
- <comment xml:lang="hu">üres CD-lemez</comment>
- <comment xml:lang="hr">Prazni CD disk</comment>
- <comment xml:lang="he">תקליטור ריק</comment>
- <comment xml:lang="gl">disco de CD en brancho</comment>
- <comment xml:lang="ga">dlúthdhiosca folamh</comment>
- <comment xml:lang="fur">disc CD vueit</comment>
- <comment xml:lang="fr">CD vierge</comment>
- <comment xml:lang="fo">blonk fløga</comment>
- <comment xml:lang="fi">tyhjä CD-levy</comment>
+ <comment xml:lang="gl">Disco de CD en branco</comment>
<comment xml:lang="eu">CD disko hutsa</comment>
- <comment xml:lang="es">disco CD en blanco</comment>
- <comment xml:lang="en_GB">blank CD disc</comment>
- <comment xml:lang="el">Κενό CD</comment>
+ <comment xml:lang="es">disco CD vacío</comment>
<comment xml:lang="de">Leere CD</comment>
- <comment xml:lang="da">tom cd-disk</comment>
- <comment xml:lang="cs">prázdný disk CD</comment>
- <comment xml:lang="ca">disc CD en blanc</comment>
- <comment xml:lang="bg">CD — празно</comment>
- <comment xml:lang="be@latin">čysty dysk CD</comment>
- <comment xml:lang="ar">قرص CD فارغ</comment>
- <comment xml:lang="af">skoon CD-skyf</comment>
+ <comment xml:lang="be">чысты дыск CD</comment>
</mime-type>
<mime-type type="x-content/blank-dvd">
<!-- http://en.wikipedia.org/wiki/DVD -->
- <comment>blank DVD disc</comment>
- <comment xml:lang="zh_TW">空白 DVD 光碟</comment>
- <comment xml:lang="zh_CN">空 DVD 光盘</comment>
- <comment xml:lang="vi">đĩa DVD trống</comment>
+ <comment>Blank DVD disc</comment>
<comment xml:lang="uk">порожній диск DVD</comment>
- <comment xml:lang="tr">boş DVD diski</comment>
- <comment xml:lang="sv">tom dvd-skiva</comment>
- <comment xml:lang="sr">празан ДВД диск</comment>
- <comment xml:lang="sq">Disk bosh DVD</comment>
- <comment xml:lang="sl">prazen DVD disk</comment>
- <comment xml:lang="sk">Prázdny disk DVD</comment>
+ <comment xml:lang="sv">Tom dvd-skiva</comment>
<comment xml:lang="ru">Чистый диск DVD</comment>
- <comment xml:lang="ro">disc gol DVD</comment>
<comment xml:lang="pt_BR">Disco DVD vazio</comment>
- <comment xml:lang="pt">DVD vazio</comment>
<comment xml:lang="pl">Pusta płyta DVD</comment>
- <comment xml:lang="oc">DVD verge</comment>
- <comment xml:lang="nn">tom DVD-plate</comment>
- <comment xml:lang="nl">blanco DVD</comment>
- <comment xml:lang="lv">tukšs DVD disks</comment>
- <comment xml:lang="lt">tuščias DVD diskas</comment>
- <comment xml:lang="ko">빈 DVD 디스크</comment>
- <comment xml:lang="kk">таза DVD дискі</comment>
- <comment xml:lang="ja">ブランク DVD ディスク</comment>
+ <comment xml:lang="ja">空DVD</comment>
<comment xml:lang="it">Disco vuoto DVD</comment>
- <comment xml:lang="id">cakram DVD kosong</comment>
- <comment xml:lang="ia">Disco DVD vacue</comment>
- <comment xml:lang="hu">üres DVD-lemez</comment>
- <comment xml:lang="hr">Prazni DVD disk</comment>
- <comment xml:lang="he">תקליטור DVD ריק</comment>
- <comment xml:lang="gl">disco de DVD en branco</comment>
- <comment xml:lang="ga">DVD folamh</comment>
- <comment xml:lang="fur">disc DVD vueit</comment>
- <comment xml:lang="fr">DVD vierge</comment>
- <comment xml:lang="fo">blonk margfløga</comment>
- <comment xml:lang="fi">tyhjä DVD-levy</comment>
+ <comment xml:lang="gl">Disco de DVD en branco</comment>
<comment xml:lang="eu">DVD disko hutsa</comment>
- <comment xml:lang="es">disco DVD en blanco</comment>
- <comment xml:lang="en_GB">blank DVD disc</comment>
- <comment xml:lang="el">Κενό DVD</comment>
+ <comment xml:lang="es">disco DVD vacío</comment>
<comment xml:lang="de">Leere DVD</comment>
- <comment xml:lang="da">tom dvd-disk</comment>
- <comment xml:lang="cs">prázdný disk DVD</comment>
- <comment xml:lang="ca">disc DVD en blanc</comment>
- <comment xml:lang="bg">DVD — празно</comment>
- <comment xml:lang="be@latin">čysty dysk DVD</comment>
- <comment xml:lang="ar">قرص DVD فارغ</comment>
- <comment xml:lang="af">skoon DVD-skyf</comment>
+ <comment xml:lang="be">чысты дыск DVD</comment>
</mime-type>
<mime-type type="x-content/blank-bd">
<!-- http://en.wikipedia.org/wiki/Blu-ray_Disc -->
- <comment>blank Blu-ray disc</comment>
- <comment xml:lang="zh_TW">空白 Blu-ray 光碟</comment>
- <comment xml:lang="zh_CN">空蓝光 DVD</comment>
- <comment xml:lang="vi">đĩa Blu-ray trống</comment>
+ <comment>Blank Blu-ray disc</comment>
<comment xml:lang="uk">порожній диск Blu-ray</comment>
- <comment xml:lang="tr">boş Blu-ray diski</comment>
- <comment xml:lang="sv">tom Blu-ray-skiva</comment>
- <comment xml:lang="sr">празан Блу-реј диск</comment>
- <comment xml:lang="sq">Disk bosh Blu-ray</comment>
- <comment xml:lang="sl">prazen Blu-Ray disk</comment>
- <comment xml:lang="sk">Prázdny disk Blu-ray</comment>
+ <comment xml:lang="sv">Tom Blu-ray-skiva</comment>
<comment xml:lang="ru">Чистый диск Blu-ray</comment>
- <comment xml:lang="ro">disc gol Blu-ray</comment>
<comment xml:lang="pt_BR">Disco Blu-ray vazio</comment>
- <comment xml:lang="pt">Blu-Ray vazio</comment>
<comment xml:lang="pl">Pusta płyta Blu-ray</comment>
- <comment xml:lang="oc">disc Blu-Ray verge</comment>
- <comment xml:lang="nn">tom Blu-Ray-plate</comment>
- <comment xml:lang="nl">blanco Blu-ray-disk</comment>
- <comment xml:lang="lv">tukšs Blu-ray disks</comment>
- <comment xml:lang="lt">tuščias Blu-ray diskas</comment>
- <comment xml:lang="ko">빈 블루레이 디스크</comment>
- <comment xml:lang="kk">таза Blu-ray дискі</comment>
- <comment xml:lang="ja">ブランク Blu-ray ディスク</comment>
<comment xml:lang="it">Disco vuoto Blu-ray</comment>
- <comment xml:lang="id">cakram Blu-ray kosong</comment>
- <comment xml:lang="ia">Disco Bly-ray vacue</comment>
- <comment xml:lang="hu">üres Blu-Ray lemez</comment>
- <comment xml:lang="hr">Prazni Blu-ray disk</comment>
- <comment xml:lang="he">תקליטור בלו־ריי ריק</comment>
- <comment xml:lang="gl">disco Blu-ray en branco</comment>
- <comment xml:lang="ga">diosca folamh Blu-Ray</comment>
- <comment xml:lang="fur">disc Blu-ray vueit</comment>
- <comment xml:lang="fr">disque Blu-Ray vierge</comment>
- <comment xml:lang="fo">blankur Blu-ray diskur</comment>
- <comment xml:lang="fi">tyhjä Blu-ray-levy</comment>
+ <comment xml:lang="gl">Disco Blu-ray en branco</comment>
<comment xml:lang="eu">Blu-ray disko hutsa</comment>
- <comment xml:lang="es">disco Blu-ray en blanco</comment>
- <comment xml:lang="en_GB">blank Blu-ray disc</comment>
- <comment xml:lang="el">Κενό Blu-ray</comment>
- <comment xml:lang="de">Leere Blu-ray-Scheibe</comment>
- <comment xml:lang="da">tom Blu-ray-disk</comment>
- <comment xml:lang="cs">prázdný disk Blu-ray</comment>
- <comment xml:lang="ca">disc Blu-Ray en blanc</comment>
- <comment xml:lang="bg">Blu-ray — празно</comment>
- <comment xml:lang="be@latin">čysty dysk Blu-ray</comment>
- <comment xml:lang="ar">قرص بلو-راي فارغ</comment>
- <comment xml:lang="af">skoon Blu-ray-skyf</comment>
+ <comment xml:lang="es">disco Blu-ray vacío</comment>
+ <comment xml:lang="de">Leere Blu-ray</comment>
+ <comment xml:lang="be">чысты дыск Blu-ray</comment>
</mime-type>
<mime-type type="x-content/blank-hddvd">
<!-- http://en.wikipedia.org/wiki/HD_DVD -->
- <comment>blank HD DVD disc</comment>
- <comment xml:lang="zh_TW">空白 HD DVD 光碟</comment>
- <comment xml:lang="zh_CN">空 HD DVD 光盘</comment>
- <comment xml:lang="vi">đĩa DVD HD trống</comment>
+ <comment>Blank HD DVD disc</comment>
<comment xml:lang="uk">порожній диск HD DVD</comment>
- <comment xml:lang="tr">boş HD DVD diski</comment>
- <comment xml:lang="sv">tom HD DVD-skiva</comment>
- <comment xml:lang="sr">празан ХД ДВД диск</comment>
- <comment xml:lang="sq">Disk bosh DVD HD</comment>
- <comment xml:lang="sl">prazen HD DVD disk</comment>
- <comment xml:lang="sk">Prázdny disk HD DVD</comment>
+ <comment xml:lang="sv">Tom HD DVD-skiva</comment>
<comment xml:lang="ru">Чистый диск HD DVD</comment>
- <comment xml:lang="ro">disc gol HD DVD</comment>
<comment xml:lang="pt_BR">Disco HD DVD vazio</comment>
- <comment xml:lang="pt">HD DVD vazio</comment>
<comment xml:lang="pl">Pusta płyta HD DVD</comment>
- <comment xml:lang="oc">disc HD-DVD verge</comment>
- <comment xml:lang="nn">tom HD-DVD-plate</comment>
- <comment xml:lang="nl">blanco HD-DVD</comment>
- <comment xml:lang="lv">tukšs HD DVD disks</comment>
- <comment xml:lang="lt">tuščias HD DVD diskas</comment>
- <comment xml:lang="ko">빈 HD DVD 디스크</comment>
- <comment xml:lang="kk">таза HD DVD дискі</comment>
- <comment xml:lang="ja">ブランク HD DVD ディスク</comment>
<comment xml:lang="it">Disco vuoto DVD HD</comment>
- <comment xml:lang="id">cakram HD DVD kosong</comment>
- <comment xml:lang="ia">Disco HD DVD vacue</comment>
- <comment xml:lang="hu">üres HD DVD-lemez</comment>
- <comment xml:lang="hr">Prazni HD DVD disk</comment>
- <comment xml:lang="he">דיסק HD DVD ריק</comment>
- <comment xml:lang="gl">disco de HD DVD en branco</comment>
- <comment xml:lang="ga">HD DVD folamh</comment>
- <comment xml:lang="fur">disc HD DVD vueit</comment>
- <comment xml:lang="fr">disque HD-DVD vierge</comment>
- <comment xml:lang="fo">blankur HD DVD diskur</comment>
- <comment xml:lang="fi">tyhjä HD DVD -levy</comment>
+ <comment xml:lang="gl">Disco de HD DVD en branco</comment>
<comment xml:lang="eu">HD DVD disko hutsa</comment>
- <comment xml:lang="es">disco HD DVD en blanco</comment>
- <comment xml:lang="en_GB">blank HD DVD disc</comment>
- <comment xml:lang="el">Κενό HD DVD</comment>
+ <comment xml:lang="es">disco HD DVD vacío</comment>
<comment xml:lang="de">Leere HD-DVD</comment>
- <comment xml:lang="da">tom HD dvd-disk</comment>
- <comment xml:lang="cs">prázdný disk HD DVD</comment>
- <comment xml:lang="ca">disc HD-DVD en blanc</comment>
- <comment xml:lang="bg">HD DVD — празно</comment>
- <comment xml:lang="be@latin">čysty dysk HD DVD</comment>
- <comment xml:lang="ar">قرص HD DVD فارغ</comment>
- <comment xml:lang="af">skoon HD-DVD-skyf</comment>
+ <comment xml:lang="be">чысты дыск HD DVD</comment>
</mime-type>
<mime-type type="x-content/audio-dvd">
<!-- http://en.wikipedia.org/wiki/DVD-Audio -->
- <comment>audio DVD</comment>
- <comment xml:lang="zh_TW">音訊 DVD</comment>
- <comment xml:lang="zh_CN">音频 DVD</comment>
- <comment xml:lang="vi">đĩa DVD âm thanh</comment>
- <comment xml:lang="uk">звуковий DVD</comment>
- <comment xml:lang="tr">ses DVD'si</comment>
- <comment xml:lang="sv">ljud-dvd</comment>
- <comment xml:lang="sr">звучни ДВД</comment>
- <comment xml:lang="sq">DVD audio</comment>
- <comment xml:lang="sl">zvočni DVD</comment>
- <comment xml:lang="sk">Zvukové DVD</comment>
+ <comment>Audio DVD</comment>
+ <comment xml:lang="uk">Звуковий DVD</comment>
+ <comment xml:lang="sv">Ljud-dvd</comment>
<comment xml:lang="ru">Аудио DVD</comment>
- <comment xml:lang="ro">DVD audio</comment>
<comment xml:lang="pt_BR">DVD de áudio</comment>
- <comment xml:lang="pt">DVD áudio</comment>
<comment xml:lang="pl">DVD-Audio</comment>
- <comment xml:lang="oc">DVD àudio</comment>
- <comment xml:lang="nn">lyd-DVD</comment>
- <comment xml:lang="nl">audio-DVD</comment>
- <comment xml:lang="lv">audio DVD</comment>
- <comment xml:lang="lt">garso DVD</comment>
- <comment xml:lang="ko">오디오 DVD</comment>
- <comment xml:lang="kk">аудио DVD</comment>
- <comment xml:lang="ja">オーディオ DVD</comment>
<comment xml:lang="it">DVD audio</comment>
- <comment xml:lang="id">DVD audio</comment>
- <comment xml:lang="ia">DVD audio</comment>
- <comment xml:lang="hu">hang DVD</comment>
- <comment xml:lang="hr">Glazbeni DVD</comment>
- <comment xml:lang="he">DVD שמע</comment>
<comment xml:lang="gl">DVD de son</comment>
- <comment xml:lang="ga">DVD fuaime</comment>
- <comment xml:lang="fur">DVD audio</comment>
- <comment xml:lang="fr">DVD audio</comment>
- <comment xml:lang="fo">Ljóð DVD</comment>
- <comment xml:lang="fi">ääni-DVD</comment>
- <comment xml:lang="eu">audio DVDa</comment>
+ <comment xml:lang="eu">Audioko DVDa</comment>
<comment xml:lang="es">DVD de audio</comment>
- <comment xml:lang="eo">Son-DVD</comment>
- <comment xml:lang="en_GB">audio DVD</comment>
- <comment xml:lang="el">DVD ήχου</comment>
<comment xml:lang="de">Audio-DVD</comment>
- <comment xml:lang="da">lyd-dvd</comment>
- <comment xml:lang="cs">zvukové DVD</comment>
- <comment xml:lang="ca">DVD d'àudio</comment>
- <comment xml:lang="bg">DVD — аудио</comment>
- <comment xml:lang="be@latin">aŭdyjo DVD</comment>
- <comment xml:lang="ar">صوت DVD</comment>
- <comment xml:lang="af">oudio-DVD</comment>
+ <comment xml:lang="be">аўдыя DVD</comment>
<treemagic>
<treematch path="AUDIO_TS/AUDIO_TS.IFO" type="file"/>
<treematch path="AUDIO_TS/AUDIO_TS.IFO;1" type="file"/>
@@ -42302,8 +42829,9 @@ command to generate the output files.
<comment xml:lang="tr">Blu-ray video diski</comment>
<comment xml:lang="sv">Blu-ray-videoskiva</comment>
<comment xml:lang="sr">Блу-реј видео диск</comment>
- <comment xml:lang="sq">Disk video Blu-ray</comment>
+ <comment xml:lang="sq">disk video Blu-ray</comment>
<comment xml:lang="sl">Blu-ray video disk</comment>
+ <comment xml:lang="si">Blu-ray වීඩියෝ තැටිය</comment>
<comment xml:lang="sk">Videodisk Blu-ray</comment>
<comment xml:lang="ru">Видеодиск Blu-ray</comment>
<comment xml:lang="ro">Disc video Blu-ray</comment>
@@ -42320,6 +42848,7 @@ command to generate the output files.
<comment xml:lang="ka">Blu-ray ვიდეო დისკი</comment>
<comment xml:lang="ja">Blu-ray ビデオディスク</comment>
<comment xml:lang="it">Disco video Blu-ray</comment>
+ <comment xml:lang="is">Blu-Ray mynddiskur</comment>
<comment xml:lang="id">Cakram video Blu-ray</comment>
<comment xml:lang="ia">Disco video Blu-ray</comment>
<comment xml:lang="hu">Blu-ray videolemez</comment>
@@ -42335,12 +42864,13 @@ command to generate the output files.
<comment xml:lang="es">disco de vídeo Blu-ray</comment>
<comment xml:lang="en_GB">Blu-ray video disc</comment>
<comment xml:lang="el">Δίσκος βίντεο Blu-ray</comment>
- <comment xml:lang="de">Blu-ray-Videoscheibe</comment>
+ <comment xml:lang="de">Blu-ray-Video</comment>
<comment xml:lang="da">Blu-ray-videodisk</comment>
<comment xml:lang="cs">videodisk Blu-ray</comment>
<comment xml:lang="ca">disc de vídeo Blu-Ray</comment>
<comment xml:lang="bg">Blu-ray — видео</comment>
<comment xml:lang="be@latin">Videadysk Blu-ray</comment>
+ <comment xml:lang="be">відэадыск Blu-ray</comment>
<comment xml:lang="ast">Discu Blu-ray de videu</comment>
<comment xml:lang="ar">قرص فيديو بلو-راي</comment>
<comment xml:lang="af">Blu-ray-videoskyf</comment>
@@ -42360,8 +42890,9 @@ command to generate the output files.
<comment xml:lang="tr">HD DVD vidyo diski</comment>
<comment xml:lang="sv">HD DVD-videoskiva</comment>
<comment xml:lang="sr">ХД ДВД видео диск</comment>
- <comment xml:lang="sq">Disk video DVD HD</comment>
+ <comment xml:lang="sq">disk video DVD HD</comment>
<comment xml:lang="sl">HD DVD video disk</comment>
+ <comment xml:lang="si">HD DVD වීඩියෝ තැටිය</comment>
<comment xml:lang="sk">Videodisk HD DVD</comment>
<comment xml:lang="ru">Видеодиск HD DVD</comment>
<comment xml:lang="ro">Disc video HD DVD</comment>
@@ -42375,8 +42906,10 @@ command to generate the output files.
<comment xml:lang="lt">HD DVD vaizdo diskas</comment>
<comment xml:lang="ko">HD DVD 동영상 디스크</comment>
<comment xml:lang="kk">HD DVD видео дискі</comment>
+ <comment xml:lang="ka">HD DVD ვიდეო დისკი</comment>
<comment xml:lang="ja">HD DVD ビデオディスク</comment>
<comment xml:lang="it">Disco video DVD HD</comment>
+ <comment xml:lang="is">HD DVD mynddiskur</comment>
<comment xml:lang="id">Cakram video HD DVD</comment>
<comment xml:lang="ia">Disco video HD DVD</comment>
<comment xml:lang="hu">HD DVD videolemez</comment>
@@ -42392,12 +42925,13 @@ command to generate the output files.
<comment xml:lang="es">disco de vídeo HD DVD</comment>
<comment xml:lang="en_GB">HD DVD video disc</comment>
<comment xml:lang="el">Δίσκος βίντεο HD DVD</comment>
- <comment xml:lang="de">HD-DVD-Videoscheibe</comment>
+ <comment xml:lang="de">HD-DVD-Video</comment>
<comment xml:lang="da">HD DVD-videodisk</comment>
<comment xml:lang="cs">Videodisk HD DVD</comment>
<comment xml:lang="ca">disc de vídeo HD-DVD</comment>
<comment xml:lang="bg">HD DVD — видео</comment>
<comment xml:lang="be@latin">Videadysk HD DVD</comment>
+ <comment xml:lang="be">відэадыск HD DVD</comment>
<comment xml:lang="ast">Discu HD DVD de videu</comment>
<comment xml:lang="ar">قرص فيديو HD DVD</comment>
<comment xml:lang="af">HD-DVD-videoskyf</comment>
@@ -42409,47 +42943,18 @@ command to generate the output files.
</mime-type>
<mime-type type="x-content/ebook-reader">
<!-- see fd.o hal spec -->
- <comment>e-book reader</comment>
- <comment xml:lang="zh_TW">e-book 閱讀器</comment>
- <comment xml:lang="zh_CN">电子书阅读器</comment>
- <comment xml:lang="uk">пристрій для читання електронних книг</comment>
- <comment xml:lang="tr">e-kitap okuyucu</comment>
- <comment xml:lang="sv">e-bokläsare</comment>
- <comment xml:lang="sr">читач ел. књига</comment>
- <comment xml:lang="sl">Bralnik elektronskih knjig</comment>
- <comment xml:lang="sk">Čítačka e-kníh</comment>
+ <comment>E-book reader</comment>
+ <comment xml:lang="uk">пристрій для читання ел. книг</comment>
+ <comment xml:lang="sv">E-bokläsare</comment>
<comment xml:lang="ru">Устройство для чтения электронных книг</comment>
<comment xml:lang="pt_BR">Leitor de e-book</comment>
- <comment xml:lang="pt">leitor de ebooks</comment>
<comment xml:lang="pl">Czytnik e-booków</comment>
- <comment xml:lang="oc">lector de libre numeric</comment>
- <comment xml:lang="nl">e-book reader</comment>
- <comment xml:lang="lv">e-grāmatu lasītājs</comment>
- <comment xml:lang="ko">전자책 리더</comment>
- <comment xml:lang="kk">электронды кітаптарды оқу құрылғысы</comment>
- <comment xml:lang="ja">電子書籍リーダー</comment>
+ <comment xml:lang="ja">電子書籍閲覧機</comment>
<comment xml:lang="it">Lettore e-book</comment>
- <comment xml:lang="id">pembaca e-book</comment>
- <comment xml:lang="ia">Lector de libro electronic</comment>
- <comment xml:lang="hu">e-könyvolvasó</comment>
- <comment xml:lang="hr">Čitač e-knjiga</comment>
- <comment xml:lang="he">קורא ספרים אלקטרוניים</comment>
- <comment xml:lang="gl">lector de libros electrónicos</comment>
- <comment xml:lang="ga">léitheoir r-leabhair</comment>
- <comment xml:lang="fur">letôr e-book</comment>
- <comment xml:lang="fr">lecteur de livre numérique</comment>
- <comment xml:lang="fi">e-kirjan lukulaite</comment>
- <comment xml:lang="eu">e-book irakurlea</comment>
+ <comment xml:lang="gl">Lector de libros electrónicos</comment>
<comment xml:lang="es">lector de libros electrónicos</comment>
- <comment xml:lang="en_GB">e-book reader</comment>
- <comment xml:lang="el">Αναγνώστης ηλεκτρονικών βιβλίων</comment>
- <comment xml:lang="de">E-Book-Leser</comment>
- <comment xml:lang="da">e-bogslæser</comment>
- <comment xml:lang="cs">čtečka elektronických knih</comment>
- <comment xml:lang="ca">lector de llibres electrònics</comment>
- <comment xml:lang="bg">Четец на е-книги</comment>
- <comment xml:lang="ar">قارئ كتاب إلكترونية</comment>
- <comment xml:lang="af">e-boekleser</comment>
+ <comment xml:lang="de">E-Book-Reader</comment>
+ <comment xml:lang="be">электронная кніга</comment>
<treemagic>
<treematch path=".kobo" type="directory" non-empty="true"/>
<treematch path="system/com.amazon.ebook.booklet.reader" non-empty="false"/>
@@ -42469,6 +42974,7 @@ command to generate the output files.
<comment xml:lang="sr">ЦД са сликама</comment>
<comment xml:lang="sq">Picture CD</comment>
<comment xml:lang="sl">Slikovni CD</comment>
+ <comment xml:lang="si">පින්තූර සීඩී</comment>
<comment xml:lang="sk">Picture CD</comment>
<comment xml:lang="ru">Picture CD</comment>
<comment xml:lang="ro">CD cu fotografii</comment>
@@ -42477,13 +42983,15 @@ command to generate the output files.
<comment xml:lang="pl">Picture CD</comment>
<comment xml:lang="oc">CD Picture</comment>
<comment xml:lang="nn">Bilete-CD</comment>
- <comment xml:lang="nl">foto-CD</comment>
+ <comment xml:lang="nl">Picture CD</comment>
<comment xml:lang="lv">Attēlu CD</comment>
<comment xml:lang="lt">Paveikslėlių CD</comment>
<comment xml:lang="ko">Picture CD</comment>
<comment xml:lang="kk">Picture CD</comment>
+ <comment xml:lang="ka">ფოტო სურათებიანი CD</comment>
<comment xml:lang="ja">ピクチャー CD</comment>
<comment xml:lang="it">Picture CD</comment>
+ <comment xml:lang="is">Picture CD-mynddiskur</comment>
<comment xml:lang="id">CD Gambar</comment>
<comment xml:lang="ia">Disco Picture CD</comment>
<comment xml:lang="hu">Picture CD</comment>
@@ -42499,12 +43007,13 @@ command to generate the output files.
<comment xml:lang="es">Picture CD</comment>
<comment xml:lang="en_GB">Picture CD</comment>
<comment xml:lang="el">CD εικόνων</comment>
- <comment xml:lang="de">Picture CD</comment>
+ <comment xml:lang="de">Kodak Picture-CD</comment>
<comment xml:lang="da">Billedcd</comment>
<comment xml:lang="cs">Picture CD</comment>
<comment xml:lang="ca">CD d'imatges</comment>
<comment xml:lang="bg">Picture CD — изображения</comment>
<comment xml:lang="be@latin">Picture CD</comment>
+ <comment xml:lang="be">Picture CD</comment>
<comment xml:lang="ar">سي دي صورة</comment>
<comment xml:lang="af">Picture CD</comment>
<treemagic>
@@ -42513,54 +43022,15 @@ command to generate the output files.
</mime-type>
<mime-type type="x-content/audio-player">
<!-- see fd.o hal spec -->
- <comment>portable audio player</comment>
- <comment xml:lang="zh_TW">可攜式音訊播放程式</comment>
- <comment xml:lang="zh_CN">便携式音频播放器</comment>
- <comment xml:lang="vi">bộ phát nhạc di động</comment>
- <comment xml:lang="uk">портативний аудіопрогравач</comment>
- <comment xml:lang="tr">taşınabilir ses oynatıcısı</comment>
- <comment xml:lang="sv">bärbar ljudspelare</comment>
- <comment xml:lang="sr">преносна музичка справица</comment>
- <comment xml:lang="sq">Lexues audio portativ</comment>
- <comment xml:lang="sl">prenosni predvajalnik zvoka</comment>
- <comment xml:lang="sk">Prenosný hudobný prehrávač</comment>
+ <comment>Portable audio player</comment>
+ <comment xml:lang="uk">портативний звуковий програвач</comment>
+ <comment xml:lang="sv">Bärbar ljudspelare</comment>
<comment xml:lang="ru">Портативный аудиопроигрыватель</comment>
- <comment xml:lang="ro">player audio portabil</comment>
- <comment xml:lang="pt_BR">Reprodutor de áudio portátil</comment>
- <comment xml:lang="pt">reprodutor áudio portátil</comment>
<comment xml:lang="pl">Przenośny odtwarzacz dźwięku</comment>
- <comment xml:lang="oc">lector àudio portable</comment>
- <comment xml:lang="nn">portable audio layer</comment>
- <comment xml:lang="nl">draagbare audiospeler</comment>
- <comment xml:lang="lv">portatīvais audio atskaņotājs</comment>
- <comment xml:lang="lt">nešiojamasis garso leistuvas</comment>
- <comment xml:lang="ko">휴대용 오디오 재생기</comment>
- <comment xml:lang="kk">тасымалы аудио плеер</comment>
- <comment xml:lang="ja">ポータブルオーディオプレイヤー</comment>
<comment xml:lang="it">Lettore audio portabile</comment>
- <comment xml:lang="id">pemutar audio portable</comment>
- <comment xml:lang="ia">Lector audio portabile</comment>
- <comment xml:lang="hu">hordozható zenelejátszó</comment>
- <comment xml:lang="hr">Prenosivi glazbeni svirač</comment>
- <comment xml:lang="he">נגן מוזיקה נייד</comment>
- <comment xml:lang="gl">dispositivo de son portábel</comment>
- <comment xml:lang="ga">seinnteoir iniompartha fuaime</comment>
- <comment xml:lang="fur">riprodutôr audio portatil</comment>
- <comment xml:lang="fr">lecteur audio portable</comment>
- <comment xml:lang="fo">leysur ljóðavspælari</comment>
- <comment xml:lang="fi">siirrettävä äänisoitin</comment>
- <comment xml:lang="eu">audio erreproduzigailu eramangarria</comment>
<comment xml:lang="es">reproductor de audio portátil</comment>
- <comment xml:lang="en_GB">portable audio player</comment>
- <comment xml:lang="el">Φορητός αναπαραγωγέας μουσικής</comment>
<comment xml:lang="de">Portables Audio-Wiedergabegerät</comment>
- <comment xml:lang="da">bærbar lydafspiller</comment>
- <comment xml:lang="cs">přenosný zvukový přehrávač</comment>
- <comment xml:lang="ca">reproductor d'àudio portàtil</comment>
- <comment xml:lang="bg">Преносим аудио плеър</comment>
- <comment xml:lang="be@latin">pieranosny aŭdyjoplayer</comment>
- <comment xml:lang="ar">مشغل ملفات مسموعة محمولة</comment>
- <comment xml:lang="af">draagbare oudiospeler</comment>
+ <comment xml:lang="be">партатыўны аўдыяплэер</comment>
</mime-type>
<mime-type type="x-content/ostree-repository">
<!-- https://github.com/ostreedev/ostree/blob/master/man/ostree-create-usb.xml -->
@@ -42570,12 +43040,18 @@ command to generate the output files.
<comment xml:lang="uk">оновлення програмного забезпечення OSTree</comment>
<comment xml:lang="tr">OSTree yazılım güncellemeleri</comment>
<comment xml:lang="sv">OSTree programvaruuppdateringar</comment>
+ <comment xml:lang="sq">përditësime software-i OSTree</comment>
+ <comment xml:lang="sl">Posodobitve programja OSTree</comment>
+ <comment xml:lang="si">OSTree මෘදුකාංග යාවත්කාලීන</comment>
+ <comment xml:lang="ru">Обновления программного обеспечения OSTree</comment>
<comment xml:lang="pt_BR">Atualizações de software OSTree</comment>
<comment xml:lang="pl">Aktualizacje oprogramowania OSTree</comment>
+ <comment xml:lang="nl">OSTree-software-updates</comment>
<comment xml:lang="ko">OSTree 소프트웨어 업데이트</comment>
<comment xml:lang="kk">OSTree бағдарламалық қамтама жаңартулары</comment>
<comment xml:lang="ja">OSTree ソフトウェアアップデート</comment>
<comment xml:lang="it">Aggiornamenti software OSTree</comment>
+ <comment xml:lang="is">OSTree hugbúnaðaruppfærslur</comment>
<comment xml:lang="id">Pemutakhiran perangkat lunak OSTree</comment>
<comment xml:lang="hu">OSTree szoftverfrissítések</comment>
<comment xml:lang="hr">OSTree nadopune softvera</comment>
@@ -42589,6 +43065,7 @@ command to generate the output files.
<comment xml:lang="da">OSTree-softwareopdateringer</comment>
<comment xml:lang="ca">actualitzacions de programari OSTree</comment>
<comment xml:lang="bg">Обновление — OSTree</comment>
+ <comment xml:lang="be">абнаўленні ПЗ OSTree</comment>
<comment xml:lang="ar">تحديثات برامج OSTree</comment>
<treemagic>
<treematch path=".ostree" type="directory" non-empty="true" match-case="true"/>
@@ -42599,55 +43076,19 @@ command to generate the output files.
<mime-type type="x-content/software">
<!-- http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
http://bugzilla.gnome.org/show_bug.cgi?id=509823#c3 -->
- <comment>software</comment>
- <comment xml:lang="zh_TW">軟體</comment>
- <comment xml:lang="zh_CN">软件</comment>
- <comment xml:lang="vi">phần mềm</comment>
+ <comment>Software</comment>
<comment xml:lang="uk">програмне забезпечення</comment>
- <comment xml:lang="tr">yazılım</comment>
- <comment xml:lang="sv">programvara</comment>
- <comment xml:lang="sr">софтвер</comment>
- <comment xml:lang="sq">Software</comment>
- <comment xml:lang="sl">programska oprema</comment>
- <comment xml:lang="sk">Softvér</comment>
+ <comment xml:lang="sv">Programvara</comment>
<comment xml:lang="ru">Программное обеспечение</comment>
- <comment xml:lang="ro">software</comment>
- <comment xml:lang="pt_BR">Aplicativo</comment>
- <comment xml:lang="pt">programa</comment>
+ <comment xml:lang="pt_BR">Software</comment>
<comment xml:lang="pl">Oprogramowanie</comment>
- <comment xml:lang="oc">logicial</comment>
- <comment xml:lang="nn">programvare</comment>
- <comment xml:lang="nl">software</comment>
- <comment xml:lang="lv">programmatūra</comment>
- <comment xml:lang="lt">programinė įranga</comment>
- <comment xml:lang="ko">소프트웨어</comment>
- <comment xml:lang="kk">бағдарламалық қамтама</comment>
- <comment xml:lang="ka">პროგრამული უზრუნველყოფა</comment>
<comment xml:lang="ja">ソフトウェア</comment>
<comment xml:lang="it">Software</comment>
- <comment xml:lang="id">peranti lunak</comment>
- <comment xml:lang="ia">Software</comment>
- <comment xml:lang="hu">szoftver</comment>
- <comment xml:lang="hr">Softver</comment>
- <comment xml:lang="he">תכנה</comment>
- <comment xml:lang="gl">software</comment>
- <comment xml:lang="ga">bogearraí</comment>
- <comment xml:lang="fur">software</comment>
- <comment xml:lang="fr">logiciel</comment>
- <comment xml:lang="fo">ritbúnaður</comment>
- <comment xml:lang="fi">ohjelmisto</comment>
- <comment xml:lang="eu">softwarea</comment>
- <comment xml:lang="es">software</comment>
- <comment xml:lang="en_GB">software</comment>
- <comment xml:lang="el">Λογισμικό</comment>
+ <comment xml:lang="gl">Software</comment>
+ <comment xml:lang="eu">Softwarea</comment>
+ <comment xml:lang="es">sóftwer</comment>
<comment xml:lang="de">Software</comment>
- <comment xml:lang="da">software</comment>
- <comment xml:lang="cs">software</comment>
- <comment xml:lang="ca">programari</comment>
- <comment xml:lang="bg">Софтуер</comment>
- <comment xml:lang="be@latin">prahrama</comment>
- <comment xml:lang="ar">برنامج</comment>
- <comment xml:lang="af">sagteware</comment>
+ <comment xml:lang="be">праграмнае забеспячэнне</comment>
</mime-type>
<mime-type type="x-content/unix-software">
<!-- http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
@@ -42659,7 +43100,9 @@ command to generate the output files.
<comment xml:lang="tr">UNIX yazılımı</comment>
<comment xml:lang="sv">UNIX-programvara</comment>
<comment xml:lang="sr">ЈУНИКС-ов софтвер</comment>
+ <comment xml:lang="sq">software UNIX</comment>
<comment xml:lang="sl">Programska datoteka UNIX</comment>
+ <comment xml:lang="si">UNIX මෘදුකාංගය</comment>
<comment xml:lang="sk">Softvér UNIX</comment>
<comment xml:lang="ru">Программа UNIX</comment>
<comment xml:lang="ro">Software UNIX</comment>
@@ -42667,13 +43110,14 @@ command to generate the output files.
<comment xml:lang="pt">programa UNIX</comment>
<comment xml:lang="pl">Oprogramowanie systemu UNIX</comment>
<comment xml:lang="oc">logicial UNIX</comment>
- <comment xml:lang="nl">UNIX software</comment>
+ <comment xml:lang="nl">UNIX-software</comment>
<comment xml:lang="lv">UNIX programmatūra</comment>
<comment xml:lang="lt">UNIX programinė įranga</comment>
<comment xml:lang="ko">UNIX 소프트웨어</comment>
<comment xml:lang="kk">UNIX бағдарламасы</comment>
<comment xml:lang="ja">UNIX ソフトウェア</comment>
<comment xml:lang="it">Software UNIX</comment>
+ <comment xml:lang="is">UNIX hugbúnaður</comment>
<comment xml:lang="id">Peranti lunak UNIX</comment>
<comment xml:lang="ia">Software pro UNIX</comment>
<comment xml:lang="hu">UNIX-szoftver</comment>
@@ -42694,6 +43138,7 @@ command to generate the output files.
<comment xml:lang="cs">software systému UNIX</comment>
<comment xml:lang="ca">programari d'UNIX</comment>
<comment xml:lang="bg">Софтуер — UNIX</comment>
+ <comment xml:lang="be">ПЗ UNIX</comment>
<comment xml:lang="ar">برنامج يونكس</comment>
<comment xml:lang="af">UNIX-sagteware</comment>
<sub-class-of type="x-content/software"/>
@@ -42713,7 +43158,9 @@ command to generate the output files.
<comment xml:lang="tr">Windows yazılımı</comment>
<comment xml:lang="sv">Windows-program</comment>
<comment xml:lang="sr">Виндоузов софтвер</comment>
+ <comment xml:lang="sq">software Windows</comment>
<comment xml:lang="sl">Programska oprema za okolje Windows</comment>
+ <comment xml:lang="si">වින්ඩෝස් මෘදුකාංග</comment>
<comment xml:lang="sk">Softvér Windows</comment>
<comment xml:lang="ru">Программа Windows</comment>
<comment xml:lang="ro">Software Windows</comment>
@@ -42721,13 +43168,15 @@ command to generate the output files.
<comment xml:lang="pt">programa Windows</comment>
<comment xml:lang="pl">Oprogramowanie systemu Windows</comment>
<comment xml:lang="oc">logicial Windows</comment>
- <comment xml:lang="nl">Windows software</comment>
+ <comment xml:lang="nl">Windows-software</comment>
<comment xml:lang="lv">Windows programmatūra</comment>
<comment xml:lang="lt">Windows programinė įranga</comment>
<comment xml:lang="ko">Windows 소프트웨어</comment>
<comment xml:lang="kk">Windows бағдарламасы</comment>
+ <comment xml:lang="ka">Windows-ის პროგრამა</comment>
<comment xml:lang="ja">Windows ソフトウェア</comment>
<comment xml:lang="it">Software Windows</comment>
+ <comment xml:lang="is">Windows hugbúnaður</comment>
<comment xml:lang="id">Piranti lunak Windows</comment>
<comment xml:lang="ia">Software Windows</comment>
<comment xml:lang="hu">Windows-szoftver</comment>
@@ -42748,6 +43197,7 @@ command to generate the output files.
<comment xml:lang="cs">software systému Windows</comment>
<comment xml:lang="ca">programari de Windows</comment>
<comment xml:lang="bg">Софтуер — Windows</comment>
+ <comment xml:lang="be">ПЗ Windows</comment>
<comment xml:lang="ar">برنامج ويندوز</comment>
<comment xml:lang="af">Windows-sagteware</comment>
<sub-class-of type="x-content/software"/>
@@ -42764,17 +43214,21 @@ command to generate the output files.
<comment xml:lang="tr">TriG RDF belgesi</comment>
<comment xml:lang="sv">TriG RDF-dokument</comment>
<comment xml:lang="sr">ТриГ РДФ документ</comment>
+ <comment xml:lang="sq">dokument TriG RDF</comment>
<comment xml:lang="sl">Dokument TriG RDF</comment>
+ <comment xml:lang="si">TriG RDF ලේඛනය</comment>
<comment xml:lang="sk">RDF dokument TriG</comment>
<comment xml:lang="ru">Документ TriG RDF</comment>
<comment xml:lang="pt_BR">Documento RDF do TriG</comment>
<comment xml:lang="pt">documento TriG RDF</comment>
<comment xml:lang="pl">Dokument RDF TriG</comment>
<comment xml:lang="oc">document RDF TriG</comment>
+ <comment xml:lang="nl">TriG RDF-document</comment>
<comment xml:lang="ko">TriG RDF 문서</comment>
<comment xml:lang="kk">TriG RDF құжаты</comment>
<comment xml:lang="ja">TriG RDF ドキュメント</comment>
<comment xml:lang="it">Documento TriG RDF</comment>
+ <comment xml:lang="is">TriG RDF skjal</comment>
<comment xml:lang="id">Dokumen TriG RDF</comment>
<comment xml:lang="ia">Documento TriG RDF</comment>
<comment xml:lang="hu">TriG RDF dokumentum</comment>
@@ -42794,6 +43248,7 @@ command to generate the output files.
<comment xml:lang="cs">dokument Trig RDF</comment>
<comment xml:lang="ca">document TriG RDF</comment>
<comment xml:lang="bg">Документ — TriG RDF</comment>
+ <comment xml:lang="be">дакумент TriG RDF</comment>
<comment xml:lang="ast">Documentu RDF TriG</comment>
<comment xml:lang="ar">وثيقة TriG RDF</comment>
<comment xml:lang="af">TriG RDF-dokument</comment>
@@ -42811,17 +43266,21 @@ command to generate the output files.
<comment xml:lang="tr">Apple Keynote 5 sunumu</comment>
<comment xml:lang="sv">Apple Keynote 5-presentation</comment>
<comment xml:lang="sr">презентација Епл Кинота 5</comment>
+ <comment xml:lang="sq">paraqitje Apple Keynote 5</comment>
<comment xml:lang="sl">Predstavitev Apple Keynote 5</comment>
+ <comment xml:lang="si">Apple Keynote 5 ඉදිරිපත් කිරීම</comment>
<comment xml:lang="sk">Prezentácia Apple Keynote 5</comment>
<comment xml:lang="ru">Презентация Apple Keynote 5</comment>
<comment xml:lang="pt_BR">Apresentação do Apple Keynote 5</comment>
<comment xml:lang="pt">apresentação Apple Keynote 5</comment>
<comment xml:lang="pl">Prezentacja Apple Keynote 5</comment>
<comment xml:lang="oc">presentacion Apple Keynote 5</comment>
+ <comment xml:lang="nl">Apple Keynote 5-presentatie</comment>
<comment xml:lang="ko">Apple 키노트 5 프레젠테이션</comment>
<comment xml:lang="kk">Apple Keynote 5 презентациясы</comment>
<comment xml:lang="ja">Apple Keynote 5 プレゼンテーション</comment>
<comment xml:lang="it">Presentazione Apple Keynote 5</comment>
+ <comment xml:lang="is">Apple Keynote 5 glærukynning</comment>
<comment xml:lang="id">Presentasi Apple Keynote 5</comment>
<comment xml:lang="ia">Presentation Apple Keynote 5</comment>
<comment xml:lang="hu">Apple Keynote 5 prezentáció</comment>
@@ -42841,6 +43300,7 @@ command to generate the output files.
<comment xml:lang="cs">prezentace Apple Keynote 5</comment>
<comment xml:lang="ca">presentació d'Apple Keynote 5</comment>
<comment xml:lang="bg">Презентация — Apple Keynote 5</comment>
+ <comment xml:lang="be">прэзентацыя Apple Keynote 5</comment>
<comment xml:lang="ar">عرض أبل كي نوت ٥</comment>
<comment xml:lang="af">Apple Keynote 5-voorlegging</comment>
<sub-class-of type="application/zip"/>
@@ -42855,6 +43315,26 @@ command to generate the output files.
</mime-type>
<mime-type type="application/vnd.apple.numbers">
<comment>Apple Numbers spreadsheet</comment>
+ <comment xml:lang="zh_TW">Apple Numbers 試算表</comment>
+ <comment xml:lang="uk">електронні таблиці Apple Numbers</comment>
+ <comment xml:lang="tr">Apple Numbers hesap çizelgesi</comment>
+ <comment xml:lang="sv">Apple Numbers-kalkylblad</comment>
+ <comment xml:lang="sl">Razpredelnica Apple Numbers</comment>
+ <comment xml:lang="si">ඇපල් අංක පැතුරුම්පත</comment>
+ <comment xml:lang="ru">Электронная таблица Apple Numbers</comment>
+ <comment xml:lang="pl">Arkusz Apple Numbers</comment>
+ <comment xml:lang="nl">Apple Numbers-werkblad</comment>
+ <comment xml:lang="ko">애플 넘버스 스프레드시트</comment>
+ <comment xml:lang="kk">Apple Numbers электрондық кестесі</comment>
+ <comment xml:lang="ja">Apple Numbers スプレッドシート</comment>
+ <comment xml:lang="it">Foglio di calcolo Apple Numbers</comment>
+ <comment xml:lang="hr">Apple Numbers proračunska tablica</comment>
+ <comment xml:lang="fi">Apple Numbers-taulukko</comment>
+ <comment xml:lang="es">hoja de cálculo Apple Numbers</comment>
+ <comment xml:lang="en_GB">Apple Numbers spreadsheet</comment>
+ <comment xml:lang="de">Apple-Numbers-Tabelle</comment>
+ <comment xml:lang="be">электронная табліца Apple Numbers</comment>
+ <comment xml:lang="ar">جدول أرقام أبل</comment>
<sub-class-of type="application/zip"/>
<generic-icon name="x-office-spreadsheet"/>
<magic priority="65">
@@ -42868,6 +43348,27 @@ command to generate the output files.
</mime-type>
<mime-type type="application/vnd.apple.pages">
<comment>Apple Pages document</comment>
+ <comment xml:lang="zh_TW">Apple Pages 文件</comment>
+ <comment xml:lang="uk">документ Apple Pages</comment>
+ <comment xml:lang="tr">Apple Pages belgesi</comment>
+ <comment xml:lang="sv">Apple Pages-dokument</comment>
+ <comment xml:lang="sl">Dokument Apple Pages</comment>
+ <comment xml:lang="si">Apple පිටු ලේඛනය</comment>
+ <comment xml:lang="ru">Документ Apple Pages</comment>
+ <comment xml:lang="pl">Dokument Apple Pages</comment>
+ <comment xml:lang="nl">Apple Pages-document</comment>
+ <comment xml:lang="ko">애플 페이지 문서</comment>
+ <comment xml:lang="kk">Apple Pages құжаты</comment>
+ <comment xml:lang="ja">Apple Pages ドキュメント</comment>
+ <comment xml:lang="it">Documento Apple Pages</comment>
+ <comment xml:lang="hr">Apple Pages dokument</comment>
+ <comment xml:lang="fi">Apple Pages-asiakirja</comment>
+ <comment xml:lang="eu">Apple Pages dokumentua</comment>
+ <comment xml:lang="es">documento de Apple Pages</comment>
+ <comment xml:lang="en_GB">Apple Pages document</comment>
+ <comment xml:lang="de">Apple-Pages-Dokument</comment>
+ <comment xml:lang="be">дакумент Apple Pages</comment>
+ <comment xml:lang="ar">مستند صفحات أبل</comment>
<sub-class-of type="application/zip"/>
<generic-icon name="x-office-document"/>
<magic priority="70">
@@ -42881,6 +43382,25 @@ command to generate the output files.
</mime-type>
<mime-type type="application/vnd.apple.pkpass">
<comment>Apple Wallet pass</comment>
+ <comment xml:lang="uk">пропуск Apple Wallet</comment>
+ <comment xml:lang="tr">Apple Cüzdan geçişi</comment>
+ <comment xml:lang="sv">Apple Wallet-pass</comment>
+ <comment xml:lang="si">Apple Wallet පාස්</comment>
+ <comment xml:lang="ru">Пропуск Apple Wallet</comment>
+ <comment xml:lang="pl">Hasło Apple Wallet</comment>
+ <comment xml:lang="nl">Apple Wallet-pas</comment>
+ <comment xml:lang="ko">애플 지갑 인증</comment>
+ <comment xml:lang="kk">Apple Wallet рұқсатнамасы</comment>
+ <comment xml:lang="ja">Apple ウォレットパス</comment>
+ <comment xml:lang="it">Pass Apple Wallet</comment>
+ <comment xml:lang="hr">Apple Novčanik propusnica</comment>
+ <comment xml:lang="gl">Pase de Apple Wallet</comment>
+ <comment xml:lang="fi">Apple Wallet-kulkulupa</comment>
+ <comment xml:lang="es">monedero Apple Wallet</comment>
+ <comment xml:lang="en_GB">Apple Wallet pass</comment>
+ <comment xml:lang="de">Apple-Wallet-Pass</comment>
+ <comment xml:lang="be">пропуск Apple Wallet</comment>
+ <comment xml:lang="ar">بطاقة محفظة أبل</comment>
<sub-class-of type="application/zip"/>
<magic priority="65">
<match type="string" value="PK\003\004" offset="0">
@@ -42896,18 +43416,24 @@ command to generate the output files.
<comment xml:lang="uk">документ Adobe PageMaker</comment>
<comment xml:lang="tr">Adobe PageMaker belgesi</comment>
<comment xml:lang="sv">Adobe PageMaker-dokument</comment>
+ <comment xml:lang="sq">dokument Adobe PageMaker</comment>
+ <comment xml:lang="sl">Dokument Adobe PageMaker</comment>
+ <comment xml:lang="si">Adobe PageMaker ලේඛනය</comment>
<comment xml:lang="sk">Dokument Adobe PageMaker</comment>
<comment xml:lang="ru">Документ Adobe PageMaker</comment>
<comment xml:lang="pt_BR">Documento do Adobe PageMaker</comment>
<comment xml:lang="pl">Dokument Adobe PageMaker</comment>
+ <comment xml:lang="nl">Adobe PageMaker-document</comment>
<comment xml:lang="ko">어도비 페이지메이커 문서</comment>
<comment xml:lang="kk">Adobe PageMaker құжаты</comment>
<comment xml:lang="ja">Adobe PageMaker ドキュメント</comment>
<comment xml:lang="it">Documento Adobe PageMaker</comment>
+ <comment xml:lang="is">Adobe PageMaker skjal</comment>
<comment xml:lang="id">Dokume Adobe PageMaker</comment>
<comment xml:lang="hu">Adobe PageMaker dokumentum</comment>
<comment xml:lang="hr">Adobe PageMaker dokument</comment>
<comment xml:lang="he">מסמך Adobe PageMaker</comment>
+ <comment xml:lang="gl">Documento de Adobe Pagemaker</comment>
<comment xml:lang="fr">document Adobe PageMaker</comment>
<comment xml:lang="fi">Adobe PageMaker -asiakirja</comment>
<comment xml:lang="eu">Adobe PageMaker dokumentua</comment>
@@ -42917,6 +43443,7 @@ command to generate the output files.
<comment xml:lang="da">Adobe PageMaker-dokument</comment>
<comment xml:lang="ca">document d'Adobe PageMaker</comment>
<comment xml:lang="bg">Документ — Adobe PageMaker</comment>
+ <comment xml:lang="be">дакумент Adobe PageMaker</comment>
<comment xml:lang="ar">مستند أدوبي بيج ميكر</comment>
<sub-class-of type="application/x-ole-storage"/>
<generic-icon name="x-office-document"/>
@@ -42932,17 +43459,23 @@ command to generate the output files.
<comment xml:lang="uk">файл WAD Doom</comment>
<comment xml:lang="tr">Doom WAD dosyası</comment>
<comment xml:lang="sv">Doom WAD-fil</comment>
+ <comment xml:lang="sq">kartelë Doom WAD</comment>
+ <comment xml:lang="sl">Datoteka Doom WAD</comment>
+ <comment xml:lang="si">Doom WAD ගොනුව</comment>
<comment xml:lang="ru">Файл Doom WAD</comment>
<comment xml:lang="pt_BR">Arquivo Doom WAD</comment>
<comment xml:lang="pl">Plik WAD gry Doom</comment>
+ <comment xml:lang="nl">Doom WAD-bestand</comment>
<comment xml:lang="ko">둠 WAD 파일</comment>
<comment xml:lang="kk">Doom WAD файлы</comment>
<comment xml:lang="ja">Doom WAD ファイル</comment>
<comment xml:lang="it">File WAD Doom</comment>
+ <comment xml:lang="is">Doom WAD skrá</comment>
<comment xml:lang="id">Berkas WAD Doom</comment>
<comment xml:lang="hu">Doom WAD fájl</comment>
<comment xml:lang="hr">Doom WAD datoteka</comment>
<comment xml:lang="he">קובץ WAD של Doom</comment>
+ <comment xml:lang="gl">Ficheiro de Doom WAD</comment>
<comment xml:lang="fr">fichier Doom WAD</comment>
<comment xml:lang="fi">Doom WAD -tiedosto</comment>
<comment xml:lang="eu">Doom WAD fitxategia</comment>
@@ -42952,6 +43485,7 @@ command to generate the output files.
<comment xml:lang="da">Doom WAD-fil</comment>
<comment xml:lang="ca">fitxer WAD de Doom</comment>
<comment xml:lang="bg">Ниво — Doom</comment>
+ <comment xml:lang="be">файл Doom WAD</comment>
<comment xml:lang="ar">ملف Doom WAD</comment>
<acronym>WAD</acronym>
<expanded-acronym>Where's All the Data</expanded-acronym>
@@ -42970,21 +43504,27 @@ command to generate the output files.
<comment xml:lang="tr">Amiga disk görüntüsü</comment>
<comment xml:lang="sv">Amiga-diskavbild</comment>
<comment xml:lang="sr">слика диска Амиге</comment>
+ <comment xml:lang="sq">pamje disku Amiga</comment>
+ <comment xml:lang="sl">Slika diska Amiga</comment>
+ <comment xml:lang="si">Amiga තැටි රූපය</comment>
<comment xml:lang="sk">Obraz disku Amiga</comment>
<comment xml:lang="ru">Образ диска Amiga</comment>
<comment xml:lang="pt_BR">Imagem de disco Amiga</comment>
<comment xml:lang="pt">imagem de disco Amiga</comment>
<comment xml:lang="pl">Obraz dysku Amiga</comment>
<comment xml:lang="oc">imatge disc Amiga</comment>
+ <comment xml:lang="nl">Amiga-schijfkopiebestand</comment>
<comment xml:lang="ko">Amiga 디스크 이미지</comment>
<comment xml:lang="kk">Amiga диск бейнесі</comment>
<comment xml:lang="ja">Amiga ディスクイメージ</comment>
<comment xml:lang="it">Disco immagine Amiga</comment>
+ <comment xml:lang="is">Amiga diskmynd</comment>
<comment xml:lang="id">Image disk Amiga</comment>
<comment xml:lang="ia">Imagine de disco Amiga</comment>
<comment xml:lang="hu">Amiga lemezkép</comment>
<comment xml:lang="hr">Amiga slika diska</comment>
<comment xml:lang="he">דמות כונן Amiga</comment>
+ <comment xml:lang="gl">Imaxe de disco de Amiga</comment>
<comment xml:lang="ga">íomhá diosca Amiga</comment>
<comment xml:lang="fur">imagjin disc Amiga</comment>
<comment xml:lang="fr">image disque Amiga</comment>
@@ -42998,6 +43538,7 @@ command to generate the output files.
<comment xml:lang="cs">obraz disku pro Amigu</comment>
<comment xml:lang="ca">imatge de disc d'Amiga</comment>
<comment xml:lang="bg">Диск — Amiga</comment>
+ <comment xml:lang="be">вобраз дыска Amiga</comment>
<comment xml:lang="ar">صورة قرص Amiga</comment>
<comment xml:lang="af">Amiga-skyfbeeldlêer</comment>
<magic>
@@ -43013,14 +43554,18 @@ command to generate the output files.
<comment xml:lang="tr">Flatpak uygulama paketi</comment>
<comment xml:lang="sv">Flatpak-programbunt</comment>
<comment xml:lang="sr">скуп програма Флатпака</comment>
+ <comment xml:lang="sq">paketë aplikacionesh Flatpak</comment>
+ <comment xml:lang="si">Flatpak යෙදුම් මිටියක්</comment>
<comment xml:lang="sk">Balík aplikácií Flatpak</comment>
<comment xml:lang="ru">Пакет приложения Flatpak</comment>
<comment xml:lang="pt_BR">Pacote de aplicativo Flatpak</comment>
<comment xml:lang="pl">Pakiet programu Flatpak</comment>
+ <comment xml:lang="nl">Flatpak-toepassingsbundel</comment>
<comment xml:lang="ko">Flatpak 프로그램 번들</comment>
<comment xml:lang="kk">Flatpak қолданбалар дестесі</comment>
<comment xml:lang="ja">Flatpak アプリケーションバンドル</comment>
<comment xml:lang="it">Bundle applicazione Flatpak</comment>
+ <comment xml:lang="is">Flatpak forritavöndull</comment>
<comment xml:lang="id">Bundel aplikasi Flatpak</comment>
<comment xml:lang="hu">Flatpak alkalmazáscsomag</comment>
<comment xml:lang="hr">Flatpak paket aplikacije</comment>
@@ -43037,6 +43582,7 @@ command to generate the output files.
<comment xml:lang="cs">balíček Flatpak s aplikací</comment>
<comment xml:lang="ca">paquet d'aplicació Flatpak</comment>
<comment xml:lang="bg">Програмен пакет — Flatpak</comment>
+ <comment xml:lang="be">пакет праграмы Flatpak</comment>
<comment xml:lang="ar">حزمة تطبيق Flatpak</comment>
<comment xml:lang="af">Flatpak-toepassingsbundel</comment>
<generic-icon name="package-x-generic"/>
@@ -43056,14 +43602,18 @@ command to generate the output files.
<comment xml:lang="tr">Flatpak depo açıklaması</comment>
<comment xml:lang="sv">Flatpak-förrådsbeskrivning</comment>
<comment xml:lang="sr">опис ризнице Флатпака</comment>
+ <comment xml:lang="sq">përshkrim depoje Flatpak</comment>
+ <comment xml:lang="si">Flatpak ගබඩා විස්තරය</comment>
<comment xml:lang="sk">Popis repozitára Flatpak</comment>
<comment xml:lang="ru">Описание репозитория Flatpak</comment>
<comment xml:lang="pt_BR">Descrição de repositório Flatpak</comment>
<comment xml:lang="pl">Opis repozytorium Flatpak</comment>
+ <comment xml:lang="nl">Flatpak-pakketbronomschrijving</comment>
<comment xml:lang="ko">Flatpak 저장소 디스크립션</comment>
<comment xml:lang="kk">Flatpak репозиторийі сипаттамасы</comment>
<comment xml:lang="ja">Flatpak リポジトリ説明</comment>
<comment xml:lang="it">Descrizione repository Flatpack</comment>
+ <comment xml:lang="is">Flatpak lýsing gagnasafns</comment>
<comment xml:lang="id">Deskripsi repositori Flatpak</comment>
<comment xml:lang="hu">Flatpak tárolóleírás</comment>
<comment xml:lang="hr">Flatpak opis repozitorija</comment>
@@ -43075,11 +43625,12 @@ command to generate the output files.
<comment xml:lang="eu">Flatpak biltegi deskribapena</comment>
<comment xml:lang="es">descripción de repositorio de Flatpak</comment>
<comment xml:lang="en_GB">Flatpak repository description</comment>
- <comment xml:lang="de">Flatpak-Repositoriumsbeschreibung</comment>
+ <comment xml:lang="de">Flatpak-Repositorybeschreibung</comment>
<comment xml:lang="da">Flatpak-arkivbeskrivelse</comment>
<comment xml:lang="cs">popis repozitáře Flatpak</comment>
<comment xml:lang="ca">descripció de dipòsit de Flatpak</comment>
<comment xml:lang="bg">Описание на хранилище — Flatpak</comment>
+ <comment xml:lang="be">апісанне рэпазіторыя Flatpak</comment>
<comment xml:lang="ar">وصف مستودع Flatpak</comment>
<generic-icon name="package-x-generic"/>
<sub-class-of type="text/plain"/>
@@ -43096,14 +43647,18 @@ command to generate the output files.
<comment xml:lang="tr">Flatpak depo atfı</comment>
<comment xml:lang="sv">Flatpak-förrådsreferens</comment>
<comment xml:lang="sr">упута ризнице Флатпака</comment>
+ <comment xml:lang="sq">referencë depoje Flatpak</comment>
+ <comment xml:lang="si">Flatpak නිධිය යොමුව</comment>
<comment xml:lang="sk">Referencia repozitára Flatpak</comment>
<comment xml:lang="ru">Ссылка на репозиторий Flatpak</comment>
<comment xml:lang="pt_BR">Referência de repositório Flatpak</comment>
<comment xml:lang="pl">Odwołanie do repozytorium Flatpak</comment>
+ <comment xml:lang="nl">Flatpak-pakketbronverwijzing</comment>
<comment xml:lang="ko">Flatpak 저장소 참조</comment>
<comment xml:lang="kk">Flatpak репозиторийіне сілтеме</comment>
<comment xml:lang="ja">Flatpak リポジトリリファレンス</comment>
<comment xml:lang="it">Riferimento repository Flatpack</comment>
+ <comment xml:lang="is">Flatpak tilvísun gagnasafns</comment>
<comment xml:lang="id">Acuan repositori Flatpak</comment>
<comment xml:lang="hu">Flatpak tárolóhivatkozás</comment>
<comment xml:lang="hr">Flatpak preporučeni repozitorij</comment>
@@ -43115,11 +43670,12 @@ command to generate the output files.
<comment xml:lang="eu">Flatpak biltegi erreferentzia</comment>
<comment xml:lang="es">referencia a repositorio de Flatpak</comment>
<comment xml:lang="en_GB">Flatpak repository reference</comment>
- <comment xml:lang="de">Flatpak-Repositoriumsreferenz</comment>
+ <comment xml:lang="de">Flatpak-Repositoryreferenz</comment>
<comment xml:lang="da">Flatpak-arkivreference</comment>
<comment xml:lang="cs">odkaz na repozitář Flatpak</comment>
<comment xml:lang="ca">referència de dipòsit Flatpak</comment>
<comment xml:lang="bg">Указател към хранилище — Flatpak</comment>
+ <comment xml:lang="be">спасылкая рэпазіторыя Flatpak</comment>
<comment xml:lang="ar">مرجع مستودع Flatpak</comment>
<generic-icon name="package-x-generic"/>
<sub-class-of type="text/plain"/>
@@ -43135,14 +43691,18 @@ command to generate the output files.
<comment xml:lang="uk">образ файлової системи squashfs</comment>
<comment xml:lang="tr">Squashfs dosya sistemi görüntüsü</comment>
<comment xml:lang="sv">Squashfs filsystemsavbildning</comment>
+ <comment xml:lang="sq">pamje sistemi kartelash Squashfs</comment>
+ <comment xml:lang="si">Squashfs ගොනු පද්ධති රූපය</comment>
<comment xml:lang="sk">Obraz systému súborov Squashfs</comment>
<comment xml:lang="ru">Образ файловой системы Squashfs</comment>
<comment xml:lang="pt_BR">Imagem de sistema de arquivos Squashfs</comment>
<comment xml:lang="pl">Obraz systemu plików SquashFS</comment>
+ <comment xml:lang="nl">Squashfs-schijfkopiebestand</comment>
<comment xml:lang="ko">Squashfs 파일 시스템 이미지</comment>
<comment xml:lang="kk">Squashfs файлдық жүйе бейнесі</comment>
<comment xml:lang="ja">Squashfs ファイルシステムイメージ</comment>
<comment xml:lang="it">Immagine file system squashfs</comment>
+ <comment xml:lang="is">Squashfs skráakerfismynd</comment>
<comment xml:lang="id">Image sistem berkas Squashfs</comment>
<comment xml:lang="hu">Squashfs fájlrenszerkép</comment>
<comment xml:lang="hr">Squashfs slika datotečnog sustava</comment>
@@ -43156,7 +43716,9 @@ command to generate the output files.
<comment xml:lang="da">Squashfs-filsystemaftryk</comment>
<comment xml:lang="ca">imatge de sistema de fitxers Squashfs</comment>
<comment xml:lang="bg">Диск — Squashfs</comment>
+ <comment xml:lang="be">вобраз файлавай сістэмы Squashfs</comment>
<comment xml:lang="ar">صورة نظام ملفات Squashfs</comment>
+ <sub-class-of type="application/vnd.efi.img"/>
<magic>
<match type="string" value="sqsh" offset="0"/>
<match type="string" value="hsqs" offset="0"/>
@@ -43172,19 +43734,24 @@ command to generate the output files.
<comment xml:lang="tr">AppImage uygulama paketi</comment>
<comment xml:lang="sv">AppImage-programbunt</comment>
<comment xml:lang="sr">скуп програма Ап-слике</comment>
+ <comment xml:lang="sq">paketë aplikacioni AppImage</comment>
+ <comment xml:lang="si">AppImage යෙදුම් මිටියක්</comment>
<comment xml:lang="sk">Balík aplikácií AppImage</comment>
<comment xml:lang="ru">Пакет приложения AppImage</comment>
<comment xml:lang="pt_BR">Pacote de aplicativo AppImage</comment>
<comment xml:lang="pt">pacote de aplicação AppImage</comment>
<comment xml:lang="pl">Pakiet programu AppImage</comment>
+ <comment xml:lang="nl">AppImage-toepassingsbundel</comment>
<comment xml:lang="ko">AppImage 프로그램 번들</comment>
<comment xml:lang="kk">AppImage қолданбалар дестесі</comment>
<comment xml:lang="ja">AppImage アプリケーションバンドル</comment>
<comment xml:lang="it">Bundle applicazione AppImage</comment>
+ <comment xml:lang="is">AppImage forritavöndull</comment>
<comment xml:lang="id">Bundel aplikasi AppImage</comment>
<comment xml:lang="hu">AppImage alkalmazáscsomag</comment>
<comment xml:lang="hr">AppImage paket aplikacije</comment>
<comment xml:lang="he">חבילת יישומי AppImage</comment>
+ <comment xml:lang="gl">Paquete de aplicación de AppImage</comment>
<comment xml:lang="ga">burla feidhmchláir AppImage</comment>
<comment xml:lang="fur">côl di aplicazions AppImage</comment>
<comment xml:lang="fr">lot applicatif AppImage</comment>
@@ -43197,6 +43764,7 @@ command to generate the output files.
<comment xml:lang="cs">balíček AppImage s aplikací</comment>
<comment xml:lang="ca">paquet d'aplicació AppImage</comment>
<comment xml:lang="bg">Програмен пакет — AppImage</comment>
+ <comment xml:lang="be">пакет праграмы AppImage</comment>
<comment xml:lang="ar">حزمة تطبيق AppImage</comment>
<comment xml:lang="af">AppImage-toepassingsbundel</comment>
<sub-class-of type="application/x-executable"/>
@@ -43221,15 +43789,20 @@ command to generate the output files.
<comment xml:lang="tr">Snap paketi</comment>
<comment xml:lang="sv">Snap-paket</comment>
<comment xml:lang="sr">Снап пакет</comment>
+ <comment xml:lang="sq">paketë Snap</comment>
<comment xml:lang="sl">Paket Snap</comment>
+ <comment xml:lang="si">Snap පැකේජය</comment>
<comment xml:lang="sk">Balík Snap</comment>
<comment xml:lang="ru">Пакет Snap</comment>
<comment xml:lang="pt_BR">Pacote Snap</comment>
<comment xml:lang="pl">Pakiet Snap</comment>
+ <comment xml:lang="oc">paquet Snap</comment>
+ <comment xml:lang="nl">Snap-pakket</comment>
<comment xml:lang="ko">Snap 패키지</comment>
<comment xml:lang="kk">Snap дестесі</comment>
<comment xml:lang="ja">Snap パッケージ</comment>
<comment xml:lang="it">Pacchetto snap</comment>
+ <comment xml:lang="is">Snap-pakki</comment>
<comment xml:lang="id">Paket Snap</comment>
<comment xml:lang="hu">Snap-csomag</comment>
<comment xml:lang="hr">Snap paket</comment>
@@ -43246,6 +43819,7 @@ command to generate the output files.
<comment xml:lang="cs">balíček Snap</comment>
<comment xml:lang="ca">paquet snap</comment>
<comment xml:lang="bg">Пакет — Snap</comment>
+ <comment xml:lang="be">пакет Snap</comment>
<comment xml:lang="ar">حزمة سناب</comment>
<comment xml:lang="af">Snap-pakket</comment>
<glob pattern="*.snap"/>
@@ -43254,11 +43828,34 @@ command to generate the output files.
<!-- 3D models and GCODEs -->
<mime-type type="model/3mf">
<comment>3MF document</comment>
+ <comment xml:lang="zh_CN">3MF 文档</comment>
+ <comment xml:lang="uk">документ 3MF</comment>
+ <comment xml:lang="tr">3MF belgesi</comment>
+ <comment xml:lang="sv">3MF-dokument</comment>
+ <comment xml:lang="sl">Dokument 3MF</comment>
+ <comment xml:lang="si">3MF ලේඛනය</comment>
+ <comment xml:lang="ru">Документ 3MF</comment>
+ <comment xml:lang="pt_BR">Documento 3MF</comment>
+ <comment xml:lang="pl">Dokument 3MF</comment>
+ <comment xml:lang="nl">3MF-document</comment>
+ <comment xml:lang="ko">3MF 문서</comment>
+ <comment xml:lang="kk">3MF құжаты</comment>
+ <comment xml:lang="ja">3MF ドキュメント</comment>
+ <comment xml:lang="it">Documento 3MF</comment>
+ <comment xml:lang="hr">3MF dokument</comment>
+ <comment xml:lang="fi">3MF-asiakirja</comment>
+ <comment xml:lang="eu">3MF dokumentua</comment>
+ <comment xml:lang="es">documento 3MF</comment>
+ <comment xml:lang="en_GB">3MF document</comment>
+ <comment xml:lang="de">3MF-Dokument</comment>
+ <comment xml:lang="be">дакумент 3MF</comment>
+ <comment xml:lang="ar">مستند 3MF</comment>
<acronym>3MF</acronym>
<expanded-acronym>3D Manufacturing Format</expanded-acronym>
<glob pattern="*.3mf"/>
<alias type="application/vnd.ms-3mfdocument"/>
<sub-class-of type="application/zip"/>
+ <generic-icon name="image-x-generic"/>
</mime-type>
<mime-type type="model/stl">
<comment>STL 3D model</comment>
@@ -43267,15 +43864,19 @@ command to generate the output files.
<comment xml:lang="uk">просторова модель STL</comment>
<comment xml:lang="tr">STL 3D modeli</comment>
<comment xml:lang="sv">STL-3D-modell</comment>
+ <comment xml:lang="sq">model STL 3D</comment>
<comment xml:lang="sl">Model STL 3D</comment>
+ <comment xml:lang="si">STL 3D ආකෘතිය</comment>
<comment xml:lang="sk">STL 3D model</comment>
<comment xml:lang="ru">3D-модель STL</comment>
<comment xml:lang="pt_BR">Modelo 3D STL</comment>
<comment xml:lang="pl">Model 3D STL</comment>
+ <comment xml:lang="nl">STL 3D-model</comment>
<comment xml:lang="ko">STL 3D 모델</comment>
<comment xml:lang="kk">STL 3D моделі</comment>
<comment xml:lang="ja">STL 3D モデル</comment>
<comment xml:lang="it">Modello 3D STL</comment>
+ <comment xml:lang="is">STL 3D-líkan</comment>
<comment xml:lang="id">Model 3D STL</comment>
<comment xml:lang="hu">STL 3D modell</comment>
<comment xml:lang="hr">STL 3D model</comment>
@@ -43292,10 +43893,12 @@ command to generate the output files.
<comment xml:lang="cs">3D model STL</comment>
<comment xml:lang="ca">model 3D STL</comment>
<comment xml:lang="bg">Модел — STL 3D</comment>
+ <comment xml:lang="be">мадэль STL 3D</comment>
<comment xml:lang="ar">نموذج STL 3D</comment>
<comment xml:lang="af">STL 3D-model</comment>
<acronym>STL</acronym>
<expanded-acronym>StereoLithography</expanded-acronym>
+ <generic-icon name="image-x-generic"/>
<magic>
<match type="string" value="solid" offset="0"/>
<match type="string" value="SOLID" offset="0"/>
@@ -43312,16 +43915,20 @@ command to generate the output files.
<comment xml:lang="tr">G-code dosyası</comment>
<comment xml:lang="sv">G-code-fil</comment>
<comment xml:lang="sr">датотека Г-ко̂да</comment>
+ <comment xml:lang="sq">kartelë G-code</comment>
<comment xml:lang="sl">Datoteka G-code</comment>
+ <comment xml:lang="si">G-කේත ගොනුව</comment>
<comment xml:lang="sk">Súbor G-code</comment>
<comment xml:lang="ru">Файл G-code</comment>
<comment xml:lang="pt_BR">Arquivo G-code</comment>
<comment xml:lang="pl">Plik G-code</comment>
<comment xml:lang="oc">fichièr G-code</comment>
+ <comment xml:lang="nl">G-code-bestand</comment>
<comment xml:lang="ko">G-code 파일</comment>
<comment xml:lang="kk">G-code файлы</comment>
<comment xml:lang="ja">G-code ファイル</comment>
<comment xml:lang="it">File G-code</comment>
+ <comment xml:lang="is">G-code skrá</comment>
<comment xml:lang="id">Berkas G-code</comment>
<comment xml:lang="hu">G-code fájl</comment>
<comment xml:lang="hr">G-kôd datoteka</comment>
@@ -43338,6 +43945,7 @@ command to generate the output files.
<comment xml:lang="cs">soubor G-code</comment>
<comment xml:lang="ca">fitxer G-code</comment>
<comment xml:lang="bg">Модел — G-code</comment>
+ <comment xml:lang="be">файл G-code</comment>
<comment xml:lang="ar">ملف G-code</comment>
<sub-class-of type="text/plain"/>
<generic-icon name="text-x-generic"/>
@@ -43345,6 +43953,24 @@ command to generate the output files.
</mime-type>
<mime-type type="text/x-gcode-gx">
<comment>G-code Extended file</comment>
+ <comment xml:lang="uk">файл G-code Extended</comment>
+ <comment xml:lang="tr">G-code Uzatılmış dosyası</comment>
+ <comment xml:lang="sv">Utökad G-code-fil</comment>
+ <comment xml:lang="si">G-කේත විස්තීරණ ගොනුව</comment>
+ <comment xml:lang="ru">Файл G-code Extended</comment>
+ <comment xml:lang="pl">Plik rozszerzonego G-code</comment>
+ <comment xml:lang="nl">G-code Extended-bestand</comment>
+ <comment xml:lang="ko">G-code 확장 파일</comment>
+ <comment xml:lang="kk">G-code Extended файлы</comment>
+ <comment xml:lang="ja">G-code 拡張ファイル</comment>
+ <comment xml:lang="it">File G-code Extended</comment>
+ <comment xml:lang="hr">G-kôd proširena datoteka</comment>
+ <comment xml:lang="fi">G-code Extended-tiedosto</comment>
+ <comment xml:lang="es">archivo G-code extendido</comment>
+ <comment xml:lang="en_GB">G-code Extended file</comment>
+ <comment xml:lang="de">Erweiterte G-Code-Datei</comment>
+ <comment xml:lang="be">файл G-code Extended</comment>
+ <comment xml:lang="ar">ملف غي-كود الموسع</comment>
<magic>
<match type="string" value="xgcode 1.0" offset="0"/>
</magic>
@@ -43358,14 +43984,19 @@ command to generate the output files.
<comment xml:lang="tr">Nintendo FDS disk görüntüsü</comment>
<comment xml:lang="sv">Nintendo FDS-diskavbild</comment>
<comment xml:lang="sr">Нинтендо ФДС слика диска</comment>
+ <comment xml:lang="sq">pamje disku Nintendo FDS</comment>
+ <comment xml:lang="sl">Slika diska Nintendo FDS</comment>
+ <comment xml:lang="si">Nintendo FDS තැටි රූපය</comment>
<comment xml:lang="sk">Obraz disku Nintendo FDS</comment>
<comment xml:lang="ru">Образ диска Nintendo FDS</comment>
<comment xml:lang="pt_BR">Imagem de disco Nintendo FDS</comment>
<comment xml:lang="pl">Obraz dysku Nintendo FDS</comment>
+ <comment xml:lang="nl">Nintendo FDS-schijfkopiebestand</comment>
<comment xml:lang="ko">닌텐도 FDS 디스크 이미지</comment>
<comment xml:lang="kk">Nintendo FDS диск бейнесі</comment>
<comment xml:lang="ja">Nintendo FDS ディスクイメージ</comment>
<comment xml:lang="it">Immagine disco Nintendo FDS</comment>
+ <comment xml:lang="is">Nintendo FDS diskmynd</comment>
<comment xml:lang="id">Image disk Nintendo FDS</comment>
<comment xml:lang="hu">Nintendo FDS lemezkép</comment>
<comment xml:lang="hr">Nintendo FDS slika diska</comment>
@@ -43382,6 +44013,7 @@ command to generate the output files.
<comment xml:lang="cs">obraz disku pro Nintendo FDS</comment>
<comment xml:lang="ca">imatge de disc Nintendo FDS</comment>
<comment xml:lang="bg">Диск — Nintendo FDS</comment>
+ <comment xml:lang="be">вобраз дыска Nintendo FDS</comment>
<comment xml:lang="ar">صورة قرص نينتندو اف دي اس</comment>
<comment xml:lang="af">Nintendo FDS-skyfbeeldlêer</comment>
<acronym>FDS</acronym>
@@ -43393,10 +44025,32 @@ command to generate the output files.
</mime-type>
<mime-type type="application/ovf">
<comment>OVF disk image</comment>
+ <comment xml:lang="zh_CN">OVF 磁盘映像</comment>
+ <comment xml:lang="uk">образ диска OVF</comment>
+ <comment xml:lang="tr">OVF disk görüntüsü</comment>
+ <comment xml:lang="sv">OVF-diskavbildning</comment>
+ <comment xml:lang="sl">Slika diska OVF</comment>
+ <comment xml:lang="si">OVF තැටි රූපය</comment>
+ <comment xml:lang="ru">Образ диска OVF</comment>
+ <comment xml:lang="pt_BR">Imagem de disco OVF</comment>
+ <comment xml:lang="pl">Obraz dysku OVF</comment>
+ <comment xml:lang="nl">OVF-schijfkopiebestand</comment>
+ <comment xml:lang="ko">OVF 디스크 이미지</comment>
+ <comment xml:lang="kk">OVF диск бейнесі</comment>
+ <comment xml:lang="ja">OVF ディスクイメージ</comment>
+ <comment xml:lang="it">Immagine disco OVF</comment>
+ <comment xml:lang="hr">OVF slika diska</comment>
+ <comment xml:lang="fi">OVF-levykuva</comment>
+ <comment xml:lang="eu">OVF disko-irudia</comment>
+ <comment xml:lang="es">imagen de disco OVF</comment>
+ <comment xml:lang="en_GB">OVF disk image</comment>
+ <comment xml:lang="de">OVF-Datenträgerabbild</comment>
+ <comment xml:lang="be">вобраз дыска OVF</comment>
+ <comment xml:lang="ar">صورة قرص OVF</comment>
<acronym>OVF</acronym>
<expanded-acronym>Open Virtualization Format</expanded-acronym>
<glob pattern="*.ova"/>
- <magic priority="60">
+ <magic priority="62">
<match type="string" value=".ovf" offset="1:256">
<match type="string" value="ustar\0" offset="257"/>
<match type="string" value="ustar\040\040\0" offset="257"/>
@@ -43407,6 +44061,29 @@ command to generate the output files.
</mime-type>
<mime-type type="application/x-qed-disk">
<comment>QEMU QED disk image</comment>
+ <comment xml:lang="zh_TW">QEMU QED 磁碟映像檔</comment>
+ <comment xml:lang="zh_CN">QEMU QED 磁盘映像</comment>
+ <comment xml:lang="uk">образ диска QED QEMU</comment>
+ <comment xml:lang="tr">QEMU QED disk görüntüsü</comment>
+ <comment xml:lang="sv">QEMU QED-diskavbildning</comment>
+ <comment xml:lang="sl">Slika diska QEMU QED</comment>
+ <comment xml:lang="si">QEMU QED තැටි රූපය</comment>
+ <comment xml:lang="ru">Образ диска QEMU QED</comment>
+ <comment xml:lang="pt_BR">Imagem de disco QEMU QED</comment>
+ <comment xml:lang="pl">Obraz dysku QED QEMU</comment>
+ <comment xml:lang="nl">QEMU QED-schijfkopiebestand</comment>
+ <comment xml:lang="ko">QEMU QED 디스크 이미지</comment>
+ <comment xml:lang="kk">QEMU QED диск бейнесі</comment>
+ <comment xml:lang="ja">QEMU QED ディスクイメージ</comment>
+ <comment xml:lang="it">Immagine disco QEMU QED</comment>
+ <comment xml:lang="hr">QEMU QED slika diska</comment>
+ <comment xml:lang="fi">QEMU QED-levykuva</comment>
+ <comment xml:lang="eu">QEMU QED disko-irudia</comment>
+ <comment xml:lang="es">imagen de disco QED de QEMU</comment>
+ <comment xml:lang="en_GB">QEMU QED disk image</comment>
+ <comment xml:lang="de">QEMU-QED-Datenträgerabbild</comment>
+ <comment xml:lang="be">вобраз дыска QEMU QED</comment>
+ <comment xml:lang="ar">صورة قرص QEMU QED</comment>
<acronym>QED</acronym>
<expanded-acronym>QEMU Enhanced Disk</expanded-acronym>
<glob pattern="*.qed"/>
@@ -43421,24 +44098,30 @@ command to generate the output files.
<comment xml:lang="uk">образ диска QCOW QEMU</comment>
<comment xml:lang="tr">QEMU QCOW disk görüntüsü</comment>
<comment xml:lang="sv">QEMU QCOW-diskavbildning</comment>
+ <comment xml:lang="sl">Slika diska QEMU QCOW</comment>
+ <comment xml:lang="si">QEMU QCOW තැටි රූපය</comment>
<comment xml:lang="ru">Образ диска QEMU QCOW</comment>
<comment xml:lang="pt_BR">Imagem de disco QEMU QCOW</comment>
<comment xml:lang="pl">Obraz dysku QCOW QEMU</comment>
+ <comment xml:lang="nl">QEMU QCOW-schijfkopiebestand</comment>
<comment xml:lang="ko">QEMU QCOW 디스크 이미지</comment>
<comment xml:lang="kk">QEMU QCOW диск бейнесі</comment>
<comment xml:lang="ja">QEMU QCOW ディスクイメージ</comment>
<comment xml:lang="it">Immagine disco QEMU QCOW</comment>
+ <comment xml:lang="is">QEMU QCOW diskmynd</comment>
<comment xml:lang="id">Image disk QCOW QEMU</comment>
<comment xml:lang="hu">QEMU QCOW lemezkép</comment>
<comment xml:lang="hr">QEMU QCOW slika diska</comment>
<comment xml:lang="he">תמונת כונן QEMU QCOW</comment>
<comment xml:lang="fr">image disque QEMU QCOW</comment>
<comment xml:lang="fi">QEMU QCOW -levykuva</comment>
+ <comment xml:lang="eu">QEMU QCOW disko-irudia</comment>
<comment xml:lang="es">imagen de disco QCOW de QEMU</comment>
<comment xml:lang="en_GB">QEMU QCOW disk image</comment>
- <comment xml:lang="de">QEMU QCOW-Datenträgerabbild</comment>
+ <comment xml:lang="de">QEMU-QCOW-Datenträgerabbild</comment>
<comment xml:lang="da">QEMU QCOW-diskaftryk</comment>
<comment xml:lang="ca">imatge de disc QEMU QCOW</comment>
+ <comment xml:lang="be">вобраз дыска QEMU QCOW</comment>
<comment xml:lang="ar">صورة قرص QEMU QCOW</comment>
<acronym>QCOW</acronym>
<expanded-acronym>QEMU Copy On Write</expanded-acronym>
@@ -43452,6 +44135,29 @@ command to generate the output files.
</mime-type>
<mime-type type="application/x-vhd-disk">
<comment>VHD disk image</comment>
+ <comment xml:lang="zh_TW">VHD 磁碟映像檔</comment>
+ <comment xml:lang="zh_CN">VHD 磁盘映像</comment>
+ <comment xml:lang="uk">образ диска VHD</comment>
+ <comment xml:lang="tr">VHD disk görüntüsü</comment>
+ <comment xml:lang="sv">VHD-diskavbildning</comment>
+ <comment xml:lang="sl">Slika diska VHD</comment>
+ <comment xml:lang="si">VHD තැටි රූපය</comment>
+ <comment xml:lang="ru">Образ диска VHD</comment>
+ <comment xml:lang="pt_BR">Imagem de disco VHD</comment>
+ <comment xml:lang="pl">Obraz dysku VHD</comment>
+ <comment xml:lang="nl">VHD-schijfkopiebestand</comment>
+ <comment xml:lang="ko">VHD 디스크 이미지</comment>
+ <comment xml:lang="kk">VHD диск бейнесі</comment>
+ <comment xml:lang="ja">VHD ディスクイメージ</comment>
+ <comment xml:lang="it">Immagine disco VHD</comment>
+ <comment xml:lang="hr">VHD slika diska</comment>
+ <comment xml:lang="fi">VHD-levykuva</comment>
+ <comment xml:lang="eu">VHD disko-irudia</comment>
+ <comment xml:lang="es">imagen de disco VHD</comment>
+ <comment xml:lang="en_GB">VHD disk image</comment>
+ <comment xml:lang="de">VHD-Datenträgerabbild</comment>
+ <comment xml:lang="be">вобраз дыска VHD</comment>
+ <comment xml:lang="ar">صورة قرص VHD</comment>
<acronym>VHD</acronym>
<expanded-acronym>Virtual Hard Disk</expanded-acronym>
<glob pattern="*.vhd"/>
@@ -43463,6 +44169,29 @@ command to generate the output files.
</mime-type>
<mime-type type="application/x-vhdx-disk">
<comment>VHDX disk image</comment>
+ <comment xml:lang="zh_TW">VHDX 磁碟映像檔</comment>
+ <comment xml:lang="zh_CN">VHDX 磁盘映像</comment>
+ <comment xml:lang="uk">образ диска VHDX</comment>
+ <comment xml:lang="tr">VHDX disk görüntüsü</comment>
+ <comment xml:lang="sv">VHDX-diskavbildning</comment>
+ <comment xml:lang="sl">Slika diska VHDX</comment>
+ <comment xml:lang="si">VHDX තැටි රූපය</comment>
+ <comment xml:lang="ru">Образ диска VHDX</comment>
+ <comment xml:lang="pt_BR">Imagem de disco VHDX</comment>
+ <comment xml:lang="pl">Obraz dysku VHDX</comment>
+ <comment xml:lang="nl">VHDX-schijfkopiebestand</comment>
+ <comment xml:lang="ko">VHDX 디스크 이미지</comment>
+ <comment xml:lang="kk">VHDX диск бейнесі</comment>
+ <comment xml:lang="ja">VHDX ディスクイメージ</comment>
+ <comment xml:lang="it">Immagine disco VHDX</comment>
+ <comment xml:lang="hr">VHDX slika diska</comment>
+ <comment xml:lang="fi">VHDX-levykuva</comment>
+ <comment xml:lang="eu">VHDX disko-irudia</comment>
+ <comment xml:lang="es">imagen de disco VHDX</comment>
+ <comment xml:lang="en_GB">VHDX disk image</comment>
+ <comment xml:lang="de">VHDX-Datenträgerabbild</comment>
+ <comment xml:lang="be">вобраз дыска VHDX</comment>
+ <comment xml:lang="ar">صورة قرص VHDX</comment>
<acronym>VHDX</acronym>
<expanded-acronym>Virtual Hard Disk v2</expanded-acronym>
<glob pattern="*.vhdx"/>
@@ -43473,6 +44202,29 @@ command to generate the output files.
</mime-type>
<mime-type type="application/x-vmdk-disk">
<comment>VMDK disk image</comment>
+ <comment xml:lang="zh_TW">VMDK 磁碟映像檔</comment>
+ <comment xml:lang="zh_CN">VMDK 磁盘映像</comment>
+ <comment xml:lang="uk">образ диска VMDK</comment>
+ <comment xml:lang="tr">VMDK disk görüntüsü</comment>
+ <comment xml:lang="sv">VMDK-diskavbildning</comment>
+ <comment xml:lang="sl">Slika diska VMDK</comment>
+ <comment xml:lang="si">VMDK තැටි රූපය</comment>
+ <comment xml:lang="ru">Образ диска VMDK</comment>
+ <comment xml:lang="pt_BR">Imagem de disco VMDK</comment>
+ <comment xml:lang="pl">Obraz dysku VMDK</comment>
+ <comment xml:lang="nl">VMDK-schijfkopiebestand</comment>
+ <comment xml:lang="ko">VMDK 디스크 이미지</comment>
+ <comment xml:lang="kk">VMDK диск бейнесі</comment>
+ <comment xml:lang="ja">VMDK ディスクイメージ</comment>
+ <comment xml:lang="it">Immagine disco VMDK</comment>
+ <comment xml:lang="hr">VMDK slika diska</comment>
+ <comment xml:lang="fi">VMDK-levykuva</comment>
+ <comment xml:lang="eu">VMDK disko-irudia</comment>
+ <comment xml:lang="es">imagen de disco VMDK</comment>
+ <comment xml:lang="en_GB">VMDK disk image</comment>
+ <comment xml:lang="de">VMDK-Datenträgerabbild</comment>
+ <comment xml:lang="be">вобраз дыска VMDK</comment>
+ <comment xml:lang="ar">صورة قرص VMDK</comment>
<acronym>VMDK</acronym>
<expanded-acronym>Virtual Machine Disk</expanded-acronym>
<glob pattern="*.vmdk"/>
@@ -43484,6 +44236,29 @@ command to generate the output files.
</mime-type>
<mime-type type="application/x-vdi-disk">
<comment>VDI disk image</comment>
+ <comment xml:lang="zh_TW">VDI 磁碟映像檔</comment>
+ <comment xml:lang="zh_CN">VDI 磁盘映像</comment>
+ <comment xml:lang="uk">образ диска VDI</comment>
+ <comment xml:lang="tr">VDI disk görüntüsü</comment>
+ <comment xml:lang="sv">VDI-diskavbildning</comment>
+ <comment xml:lang="sl">Slika diska VDI</comment>
+ <comment xml:lang="si">VDI තැටි රූපය</comment>
+ <comment xml:lang="ru">Образ диска VDI</comment>
+ <comment xml:lang="pt_BR">Imagem de disco VDI</comment>
+ <comment xml:lang="pl">Obraz dysku VDI</comment>
+ <comment xml:lang="nl">VDI-schijfkopiebestand</comment>
+ <comment xml:lang="ko">VDI 디스크 이미지</comment>
+ <comment xml:lang="kk">VDI диск бейнесі</comment>
+ <comment xml:lang="ja">VDI ディスクイメージ</comment>
+ <comment xml:lang="it">Immagine disco VDI</comment>
+ <comment xml:lang="hr">VDI slika diska</comment>
+ <comment xml:lang="fi">VDI-levykuva</comment>
+ <comment xml:lang="eu">VDI disko-irudia</comment>
+ <comment xml:lang="es">imagen de disco VDI</comment>
+ <comment xml:lang="en_GB">VDI disk image</comment>
+ <comment xml:lang="de">VDI-Datenträgerabbild</comment>
+ <comment xml:lang="be">вобраз дыска VDI</comment>
+ <comment xml:lang="ar">صورة قرص VDI</comment>
<acronym>VDI</acronym>
<expanded-acronym>Virtual Disk Image</expanded-acronym>
<glob pattern="*.vdi"/>
@@ -43505,25 +44280,30 @@ command to generate the output files.
<comment xml:lang="tr">AppleWorks belgesi</comment>
<comment xml:lang="sv">AppleWorks-dokument</comment>
<comment xml:lang="sl">Dokument AppleWorks</comment>
+ <comment xml:lang="si">AppleWorks ලේඛනය</comment>
<comment xml:lang="ru">Документ AppleWorks</comment>
<comment xml:lang="pt_BR">Documento AppleWorks</comment>
<comment xml:lang="pl">Dokument AppleWorks</comment>
<comment xml:lang="oc">document AppleWorks</comment>
+ <comment xml:lang="nl">AppleWorks-document</comment>
<comment xml:lang="ko">AppleWorks 문서</comment>
<comment xml:lang="kk">AppleWorks құжаты</comment>
<comment xml:lang="ja">AppleWorks ドキュメント</comment>
<comment xml:lang="it">Documento AppleWorks</comment>
+ <comment xml:lang="is">AppleWorks skjal</comment>
<comment xml:lang="id">Dokumen AppleWorks</comment>
<comment xml:lang="hu">AppleWorks-dokumentum</comment>
<comment xml:lang="hr">AppleWorks dokument</comment>
<comment xml:lang="he">מסמך AppleWorks</comment>
<comment xml:lang="fr">document AppleWorks</comment>
<comment xml:lang="fi">AppleWorks-asiakirja</comment>
+ <comment xml:lang="eu">AppleWorks dokumentua</comment>
<comment xml:lang="es">documento de AppleWorks</comment>
<comment xml:lang="en_GB">AppleWorks document</comment>
<comment xml:lang="de">AppleWorks-Dokument</comment>
<comment xml:lang="da">AppleWorks-dokument</comment>
<comment xml:lang="ca">document AppleWorks</comment>
+ <comment xml:lang="be">дакумент AppleWorks</comment>
<comment xml:lang="ar">مستند AppleWorks</comment>
<generic-icon name="x-office-document"/>
<glob pattern="*.cwk"/>
@@ -43535,13 +44315,18 @@ command to generate the output files.
<comment xml:lang="uk">латка BPS</comment>
<comment xml:lang="tr">BPS yaması</comment>
<comment xml:lang="sv">BPS-patch</comment>
+ <comment xml:lang="sl">Popravek BPS</comment>
+ <comment xml:lang="si">BPS පැච්</comment>
+ <comment xml:lang="sk">Záplata BPS</comment>
<comment xml:lang="ru">Патч BPS</comment>
<comment xml:lang="pt_BR">Patch BPS</comment>
<comment xml:lang="pl">Łata BPS</comment>
+ <comment xml:lang="nl">BPS-patch</comment>
<comment xml:lang="ko">BPS 패치</comment>
<comment xml:lang="kk">BPS өзгерісі</comment>
<comment xml:lang="ja">BPS パッチ</comment>
<comment xml:lang="it">Patch BPS</comment>
+ <comment xml:lang="is">BPS kóðabót</comment>
<comment xml:lang="id">Patch BPS</comment>
<comment xml:lang="hu">BPS javítócsomag</comment>
<comment xml:lang="hr">BPS zakrpa</comment>
@@ -43553,6 +44338,7 @@ command to generate the output files.
<comment xml:lang="de">BPS-Patch</comment>
<comment xml:lang="da">BPS-rettelse</comment>
<comment xml:lang="ca">pedaç de BPS</comment>
+ <comment xml:lang="be">патч BPS</comment>
<comment xml:lang="ar">رقعة BPS</comment>
<acronym>BPS</acronym>
<expanded-acronym>Binary Patching System</expanded-acronym>
@@ -43568,13 +44354,17 @@ command to generate the output files.
<comment xml:lang="uk">латка IPS</comment>
<comment xml:lang="tr">IPS yaması</comment>
<comment xml:lang="sv">IPS-patch</comment>
+ <comment xml:lang="sl">Popravek IPS</comment>
+ <comment xml:lang="si">IPS පැච්</comment>
<comment xml:lang="ru">Патч IPS</comment>
<comment xml:lang="pt_BR">Patch IPS</comment>
<comment xml:lang="pl">Łata IPS</comment>
+ <comment xml:lang="nl">IPS-patch</comment>
<comment xml:lang="ko">IPS 패치</comment>
<comment xml:lang="kk">IPS өзгерісі</comment>
<comment xml:lang="ja">IPS パッチ</comment>
<comment xml:lang="it">Patch IPS</comment>
+ <comment xml:lang="is">IPS kóðabót</comment>
<comment xml:lang="id">Patch IPS</comment>
<comment xml:lang="hu">IPS javítócsomag</comment>
<comment xml:lang="hr">IPS zakrpa</comment>
@@ -43586,6 +44376,7 @@ command to generate the output files.
<comment xml:lang="de">IPS-Patch</comment>
<comment xml:lang="da">IPS-rettelse</comment>
<comment xml:lang="ca">pedaç d'IPS</comment>
+ <comment xml:lang="be">патч IPS</comment>
<comment xml:lang="ar">رقعة IPS</comment>
<acronym>IPS</acronym>
<expanded-acronym>International Patching System</expanded-acronym>
@@ -43598,14 +44389,20 @@ command to generate the output files.
<comment>Pyspread spreadsheet</comment>
<comment xml:lang="zh_TW">Pyspread 試算表</comment>
<comment xml:lang="zh_CN">Pyspread 电子表格</comment>
- <comment xml:lang="uk">ел. таблиця Pyspread</comment>
+ <comment xml:lang="uk">електронна таблиця Pyspread</comment>
<comment xml:lang="tr">Pyspread hesap çizelgesi</comment>
<comment xml:lang="sv">Pyspread-kalkylblad</comment>
+ <comment xml:lang="sl">Preglednica Pyspread</comment>
+ <comment xml:lang="si">Pyspread පැතුරුම්පත</comment>
+ <comment xml:lang="ru">Электронная таблица Pyspread</comment>
<comment xml:lang="pt_BR">Planilha do Pyspread</comment>
<comment xml:lang="pl">Arkusz pyspread</comment>
+ <comment xml:lang="nl">Pyspread werkblad</comment>
<comment xml:lang="ko">Pyspread 스프레드시트</comment>
+ <comment xml:lang="kk">Pyspread электрондық кестесі</comment>
<comment xml:lang="ja">Pyspread スプレッドシート</comment>
<comment xml:lang="it">Foglio di calcolo Pyspread</comment>
+ <comment xml:lang="is">Pyspread töflureikniskjal</comment>
<comment xml:lang="id">lembar kerja Pyspread</comment>
<comment xml:lang="hu">Pyspread-munkafüzet</comment>
<comment xml:lang="hr">Pyspread proračunska tablica</comment>
@@ -43617,6 +44414,7 @@ command to generate the output files.
<comment xml:lang="de">Pyspread-Tabelle</comment>
<comment xml:lang="da">Pyspread-regneark</comment>
<comment xml:lang="ca">full de càlcul de Pyspread</comment>
+ <comment xml:lang="be">электронная табліца Pyspread</comment>
<comment xml:lang="ar">ورقة عمل Pyspread</comment>
<glob pattern="*.pysu"/>
<magic>
@@ -43625,50 +44423,41 @@ command to generate the output files.
<generic-icon name="x-office-spreadsheet"/>
</mime-type>
<mime-type type="application/x-pyspread-bz-spreadsheet">
- <comment>Pyspread spreadsheet (bzip-compressed)</comment>
- <comment xml:lang="zh_TW">Pyspread 試算表 (bzip 壓縮)</comment>
- <comment xml:lang="zh_CN">Pyspread 电子表格(bzip 压缩)</comment>
- <comment xml:lang="uk">ел. таблиця Pyspread (стиснена bzip)</comment>
- <comment xml:lang="tr">Pyspread hesap çizelgesi (bzip ile sıkıştırılmış)</comment>
- <comment xml:lang="sv">Pyspread-kalkylblad (bzip-komprimerat)</comment>
- <comment xml:lang="pt_BR">Planilha do Pyspread (compactada com bzip)</comment>
- <comment xml:lang="pl">Arkusz pyspread (kompresja bzip)</comment>
- <comment xml:lang="ko">Pyspread 스프레드시트(bzip 압축됨)</comment>
- <comment xml:lang="ja">Pyspread アーカイブ (bzip 圧縮)</comment>
- <comment xml:lang="it">Foglio di calcolo Pyspread (compresso con bzip)</comment>
- <comment xml:lang="id">lembar kerja Pyspread (terkompresi bzip)</comment>
- <comment xml:lang="hu">Pyspread-munkafüzet (bzip-pel tömörített)</comment>
- <comment xml:lang="hr">Pyspread proračunska tablica (bzip sažeta)</comment>
- <comment xml:lang="he">גיליון Pyspread (בדחיסת bzip)</comment>
- <comment xml:lang="fr">feuille de calcul Pyspread (compressée bzip)</comment>
- <comment xml:lang="fi">Pyspread-taulukko (bzip-pakattu)</comment>
- <comment xml:lang="es">hoja de cálculo de Pyspread (comprimida con bzip)</comment>
- <comment xml:lang="en_GB">Pyspread spreadsheet (bzip-compressed)</comment>
- <comment xml:lang="de">Pyspread-Tabelle (bzip-komprimiert)</comment>
- <comment xml:lang="da">Pyspread-regneark (bzip-komprimeret)</comment>
- <comment xml:lang="ca">full de càlcul de Pyspread (amb compressió bzip)</comment>
- <comment xml:lang="ar">ورقة عمل Pyspread (مضغوطه-bzip)</comment>
- <sub-class-of type="application/x-bzip"/>
+ <comment>Pyspread spreadsheet (bzip2-compressed)</comment>
+ <comment xml:lang="uk">електронна таблиця Pyspread (стиснена bzip2)</comment>
+ <comment xml:lang="sv">Pyspread-kalkylblad (bzip2-komprimerat)</comment>
+ <comment xml:lang="ru">Электронная таблица Pyspread (сжатая bzip2)</comment>
+ <comment xml:lang="pl">Arkusz pyspread (kompresja bzip2)</comment>
+ <comment xml:lang="es">hoja de cálculo de Pyspread (comprimida con BZIP2)</comment>
+ <comment xml:lang="de">Pyspread-Tabelle (bzip2-komprimiert)</comment>
+ <sub-class-of type="application/x-bzip2"/>
<glob pattern="*.pys"/>
<generic-icon name="x-office-spreadsheet"/>
</mime-type>
<mime-type type="text/x-kotlin">
<comment>Kotlin source code</comment>
- <comment xml:lang="zh_TW">Kotlin 源碼</comment>
+ <comment xml:lang="zh_TW">Kotlin 原始碼</comment>
<comment xml:lang="zh_CN">Kotlin 源代码</comment>
- <comment xml:lang="uk">вихідний код мовою Kotlin</comment>
+ <comment xml:lang="uk">початковий код мовою Kotlin</comment>
<comment xml:lang="tr">Kotlin kaynak kodu</comment>
<comment xml:lang="sv">Kotlin-källkod</comment>
+ <comment xml:lang="sl">Izvorna koda Kotlin</comment>
+ <comment xml:lang="si">Kotlin මූල කේතය</comment>
+ <comment xml:lang="ru">Исходный код Kotlin</comment>
<comment xml:lang="pt_BR">Código-fonte Kotlin</comment>
<comment xml:lang="pl">Kod źródłowy Kotlin</comment>
<comment xml:lang="oc">còdi font Kotlin</comment>
+ <comment xml:lang="nl">Kotlin-broncode</comment>
<comment xml:lang="ko">Kotlin 소스 코드</comment>
+ <comment xml:lang="kk">Kotlin бастапқы коды</comment>
<comment xml:lang="ja">Kotlin ソースコード</comment>
<comment xml:lang="it">Codice sorgente Kotlin</comment>
+ <comment xml:lang="is">Kotlin frumkóði</comment>
<comment xml:lang="id">kode sumber Kotlin</comment>
<comment xml:lang="hu">Kotlin forráskód</comment>
<comment xml:lang="hr">Kotlin izvorni kôd</comment>
<comment xml:lang="he">קוד מקור של Kotlin</comment>
+ <comment xml:lang="gl">Código fonte en Kotlin</comment>
<comment xml:lang="fr">code source Kotlin</comment>
<comment xml:lang="fi">Kotlin-lähdekoodi</comment>
<comment xml:lang="es">código fuente en Kotlin</comment>
@@ -43676,12 +44465,83 @@ command to generate the output files.
<comment xml:lang="de">Kotlin-Quelltext</comment>
<comment xml:lang="da">Kotlin-kildekode</comment>
<comment xml:lang="ca">codi font en Kotlin</comment>
+ <comment xml:lang="be">зыходны код Kotlin</comment>
<comment xml:lang="ar">شفرة مصدر Kotlin</comment>
<sub-class-of type="text/plain"/>
<glob pattern="*.kt"/>
</mime-type>
+ <mime-type type="text/x-devicetree-source">
+ <comment>Devicetree source code</comment>
+ <comment xml:lang="uk">початковий код devicetree</comment>
+ <comment xml:lang="sv">Enhetsträdskällkod</comment>
+ <comment xml:lang="ru">Исходный код Devicetree</comment>
+ <comment xml:lang="pl">Kod źródłowy DeviceTree</comment>
+ <comment xml:lang="it">Codice sorgente Devicetree</comment>
+ <comment xml:lang="gl">Código fonte en Devicetree</comment>
+ <comment xml:lang="es">código fuente de árbol de dispositivos</comment>
+ <comment xml:lang="de">Gerätebaum-Quelltext</comment>
+ <comment xml:lang="be">зыходны код Devicetree</comment>
+ <acronym>DTS</acronym>
+ <expanded-acronym>Device Tree Source</expanded-acronym>
+ <sub-class-of type="text/plain"/>
+ <glob pattern="*.dts"/>
+ <glob pattern="*.dtsi"/>
+ <magic>
+ <match type="string" mask="0x8080" value="\000\000" offset="0">
+ <match type="string" value="/dts-v1/" offset="0:4080"/>
+ </match>
+ </magic>
+ <magic priority="40">
+ <match type="string" mask="0x8080" value="\000\000" offset="0">
+ <match type="string" value="/ {" offset="0:4090"/>
+ <match type="string" value="include " offset="0:4080">
+ <match type="string" value=".dts" offset="10:4090"/>
+ </match>
+ </match>
+ </magic>
+ </mime-type>
+ <mime-type type="text/x-devicetree-binary">
+ <comment>Flattened Devicetree</comment>
+ <comment xml:lang="uk">зведене Devicetree</comment>
+ <comment xml:lang="sv">Utplattat enhetsträd</comment>
+ <comment xml:lang="ru">Плоское дерево устройств</comment>
+ <comment xml:lang="pl">Spłaszczone DeviceTree</comment>
+ <comment xml:lang="it">Devicetree compatto</comment>
+ <comment xml:lang="es">árbol de dispositivos aplanado</comment>
+ <comment xml:lang="de">Verflachter Gerätebaum</comment>
+ <acronym>DTB</acronym>
+ <expanded-acronym>Device Tree Binary</expanded-acronym>
+ <glob pattern="*.dtb"/>
+ <magic>
+ <match type="big32" value="0xd00dfeed" offset="0"/>
+ </magic>
+ </mime-type>
<mime-type type="image/avif">
<comment>AVIF image</comment>
+ <comment xml:lang="zh_TW">AVIF 影像</comment>
+ <comment xml:lang="zh_CN">AVIF 图像</comment>
+ <comment xml:lang="uk">зображення AVIF</comment>
+ <comment xml:lang="tr">AVIF görüntüsü</comment>
+ <comment xml:lang="sv">AVIF-bild</comment>
+ <comment xml:lang="sl">Slika AVIF</comment>
+ <comment xml:lang="si">AVIF රූපය</comment>
+ <comment xml:lang="ru">Изображение AVIF</comment>
+ <comment xml:lang="pt_BR">Imagem AVIF</comment>
+ <comment xml:lang="pl">Obraz AVIF</comment>
+ <comment xml:lang="oc">imatge AVIF</comment>
+ <comment xml:lang="nl">AVIF-afbeelding</comment>
+ <comment xml:lang="ko">AVIF 그림</comment>
+ <comment xml:lang="kk">AVIF суреті</comment>
+ <comment xml:lang="ja">AVIF 画像</comment>
+ <comment xml:lang="it">Immagine AVIF</comment>
+ <comment xml:lang="hr">AVIF slika</comment>
+ <comment xml:lang="fi">AVIF-kuva</comment>
+ <comment xml:lang="eu">AVIF irudia</comment>
+ <comment xml:lang="es">imagen AVIF</comment>
+ <comment xml:lang="en_GB">AVIF image</comment>
+ <comment xml:lang="de">AVIF-Bild</comment>
+ <comment xml:lang="be">выява AVIF</comment>
+ <comment xml:lang="ar">صورة AVIF</comment>
<acronym>AVIF</acronym>
<expanded-acronym>AV1 Image File Format</expanded-acronym>
<magic>
@@ -43697,8 +44557,44 @@ command to generate the output files.
<glob pattern="*.avifs"/>
<alias type="image/avif-sequence"/>
</mime-type>
+ <mime-type type="image/qoi">
+ <comment>Quite OK Image Format</comment>
+ <comment xml:lang="uk">формат зображень Quite OK</comment>
+ <comment xml:lang="sv">Quite OK Image-format</comment>
+ <comment xml:lang="ru">Формат изображений Quite OK</comment>
+ <comment xml:lang="pl">Obraz QOI</comment>
+ <comment xml:lang="it">Formato immagine Quite OK</comment>
+ <comment xml:lang="es">formato de imagen Quite OK</comment>
+ <comment xml:lang="de">Quite-OK-Bildformat</comment>
+ <magic>
+ <match type="string" value="qoif" offset="0"/>
+ </magic>
+ <glob pattern="*.qoi"/>
+ </mime-type>
<mime-type type="video/vnd.radgamettools.bink">
<comment>Bink Video</comment>
+ <comment xml:lang="zh_CN">Bink 视频</comment>
+ <comment xml:lang="uk">відео Bink</comment>
+ <comment xml:lang="tr">Bink Videosu</comment>
+ <comment xml:lang="sv">Bink-video</comment>
+ <comment xml:lang="sl">Video Bink</comment>
+ <comment xml:lang="si">බින්ක් වීඩියෝව</comment>
+ <comment xml:lang="ru">Видео Bink</comment>
+ <comment xml:lang="pt_BR">Vídeo Bink</comment>
+ <comment xml:lang="pl">Plik wideo Bink</comment>
+ <comment xml:lang="nl">Bink-video</comment>
+ <comment xml:lang="ko">Bink 동영상</comment>
+ <comment xml:lang="kk">Bink видеосы</comment>
+ <comment xml:lang="ja">Bink 動画</comment>
+ <comment xml:lang="it">Video Bink</comment>
+ <comment xml:lang="hr">Bink video snimka</comment>
+ <comment xml:lang="fi">Bink Video</comment>
+ <comment xml:lang="eu">Bink bideoa</comment>
+ <comment xml:lang="es">vídeo BINK</comment>
+ <comment xml:lang="en_GB">Bink Video</comment>
+ <comment xml:lang="de">Bink-Video</comment>
+ <comment xml:lang="be">відэа Bink</comment>
+ <comment xml:lang="ar">فيديو Bink</comment>
<magic>
<match type="string" value="BIK" offset="0">
<match type="string" value="b" offset="3"/>
@@ -43723,6 +44619,28 @@ command to generate the output files.
</mime-type>
<mime-type type="video/vnd.radgamettools.smacker">
<comment>Smacker Video</comment>
+ <comment xml:lang="zh_CN">Smacker 视频</comment>
+ <comment xml:lang="uk">відео Smacker</comment>
+ <comment xml:lang="tr">Smacker Videosu</comment>
+ <comment xml:lang="sv">Smacker-video</comment>
+ <comment xml:lang="sl">Video Smacker</comment>
+ <comment xml:lang="si">ස්මකර් වීඩියෝව</comment>
+ <comment xml:lang="ru">Видео Smacker</comment>
+ <comment xml:lang="pt_BR">Vídeo Smacker</comment>
+ <comment xml:lang="pl">Plik wideo Smacker</comment>
+ <comment xml:lang="nl">Smacker-video</comment>
+ <comment xml:lang="ko">Smacker 동영상</comment>
+ <comment xml:lang="kk">Smacker видеосы</comment>
+ <comment xml:lang="ja">Smacker 動画</comment>
+ <comment xml:lang="it">Video Smacker</comment>
+ <comment xml:lang="hr">Smacker video snimka</comment>
+ <comment xml:lang="fi">Smacker Video</comment>
+ <comment xml:lang="eu">Smacker bideoa</comment>
+ <comment xml:lang="es">vídeo Smacker</comment>
+ <comment xml:lang="en_GB">Smacker Video</comment>
+ <comment xml:lang="de">Smacker-Video</comment>
+ <comment xml:lang="be">відэа Smacker</comment>
+ <comment xml:lang="ar">فيديو Smacker</comment>
<magic>
<match type="string" value="SMK" offset="0">
<match type="string" value="2" offset="3"/>
@@ -43733,11 +44651,54 @@ command to generate the output files.
</mime-type>
<mime-type type="text/org">
<comment>Org-mode file</comment>
+ <comment xml:lang="zh_CN">Org-mode 文件</comment>
+ <comment xml:lang="uk">файл Org-mode</comment>
+ <comment xml:lang="tr">Org-mode dosyası</comment>
+ <comment xml:lang="sv">Org-mode-fil</comment>
+ <comment xml:lang="sl">Datoteka org-mode</comment>
+ <comment xml:lang="si">Org-mode ගොනුව</comment>
+ <comment xml:lang="ru">Файл Org-mode</comment>
+ <comment xml:lang="pl">Plik Org-mode</comment>
+ <comment xml:lang="nl">Org-mode-bestand</comment>
+ <comment xml:lang="ko">Org-mode 파일</comment>
+ <comment xml:lang="kk">Org-mode файлы</comment>
+ <comment xml:lang="ja">Org-mode ファイル</comment>
+ <comment xml:lang="it">File Org-mode</comment>
+ <comment xml:lang="hr">Org-mode datoteka</comment>
+ <comment xml:lang="fi">Org-mode-tiedosto</comment>
+ <comment xml:lang="es">archivo modo Org</comment>
+ <comment xml:lang="en_GB">Org-mode file</comment>
+ <comment xml:lang="de">Org-mode-Datei</comment>
+ <comment xml:lang="be">файл Org-mode</comment>
+ <comment xml:lang="ar">ملف Org-mode</comment>
<sub-class-of type="text/plain"/>
<glob pattern="*.org"/>
</mime-type>
<mime-type type="application/x-openzim">
<comment>OpenZIM file</comment>
+ <comment xml:lang="zh_CN">OpenZIM 文件</comment>
+ <comment xml:lang="uk">файл OpenZIM</comment>
+ <comment xml:lang="tr">OpenZIM dosyası</comment>
+ <comment xml:lang="sv">OpenZIM-fil</comment>
+ <comment xml:lang="sl">Datoteka OpenZIM</comment>
+ <comment xml:lang="si">OpenZIM ගොනුව</comment>
+ <comment xml:lang="ru">Файл OpenZIM</comment>
+ <comment xml:lang="pt_BR">Arquivo OpenZIM</comment>
+ <comment xml:lang="pl">Plik OpenZIM</comment>
+ <comment xml:lang="oc">fichièr OpenZIM</comment>
+ <comment xml:lang="nl">OpenZIM-bestand</comment>
+ <comment xml:lang="ko">OpenZIM 파일</comment>
+ <comment xml:lang="kk">OpenZIM файлы</comment>
+ <comment xml:lang="ja">OpenZIM ファイル</comment>
+ <comment xml:lang="it">File OpenZIM</comment>
+ <comment xml:lang="hr">OpenZIM datoteka</comment>
+ <comment xml:lang="fi">OpenZIM-tiedosto</comment>
+ <comment xml:lang="eu">OpenZIM fitxategia</comment>
+ <comment xml:lang="es">archivo OpenZIM</comment>
+ <comment xml:lang="en_GB">OpenZIM file</comment>
+ <comment xml:lang="de">OpenZIM-Datei</comment>
+ <comment xml:lang="be">файл OpenZIM</comment>
+ <comment xml:lang="ar">ملف OpenZIM </comment>
<acronym>ZIM</acronym>
<expanded-acronym>Zeno IMproved</expanded-acronym>
<glob pattern="*.zim"/>
@@ -43747,6 +44708,29 @@ command to generate the output files.
</mime-type>
<mime-type type="application/sparql-query">
<comment>SPARQL query</comment>
+ <comment xml:lang="zh_CN">SPARQL 查询</comment>
+ <comment xml:lang="uk">запит SPARQL</comment>
+ <comment xml:lang="tr">SPARQL sorgusu</comment>
+ <comment xml:lang="sv">SPARQL-fråga</comment>
+ <comment xml:lang="sl">Poizvedba SPARQL</comment>
+ <comment xml:lang="si">SPARQL විමසුම</comment>
+ <comment xml:lang="ru">Запрос SPARQL</comment>
+ <comment xml:lang="pl">Zapytanie SPARQL</comment>
+ <comment xml:lang="nl">SPARQL-zoekopdracht</comment>
+ <comment xml:lang="ko">SPARQL 질의문</comment>
+ <comment xml:lang="kk">SPARQL сұранымы</comment>
+ <comment xml:lang="ka">SPARQL მოთხოვნა</comment>
+ <comment xml:lang="ja">SPARQL クエリー</comment>
+ <comment xml:lang="it">Ricerca SPARQL</comment>
+ <comment xml:lang="hr">SPARQL zahtjev</comment>
+ <comment xml:lang="he">שאילתת SPARQL</comment>
+ <comment xml:lang="fi">SPARQL-kysely</comment>
+ <comment xml:lang="eu">SPARQL kontsulta</comment>
+ <comment xml:lang="es">consulta SPARQL</comment>
+ <comment xml:lang="en_GB">SPARQL query</comment>
+ <comment xml:lang="de">SPARQL-Abfrage</comment>
+ <comment xml:lang="be">запыт SPARQL</comment>
+ <comment xml:lang="ar">استعلام SPARQL</comment>
<acronym>SPARQL</acronym>
<expanded-acronym>SPARQL Protocol and RDF Query Language</expanded-acronym>
<glob pattern="*.qs"/>
@@ -43756,10 +44740,186 @@ command to generate the output files.
</mime-type>
<mime-type type="application/sparql-results+xml">
<comment>SPARQL query results</comment>
+ <comment xml:lang="zh_CN">SPARQL 查询结果</comment>
+ <comment xml:lang="uk">результати запиту SPARQL</comment>
+ <comment xml:lang="tr">SPARQL sorgu sonuçları</comment>
+ <comment xml:lang="sv">SPARQL-frågeresultat</comment>
+ <comment xml:lang="sl">Rezultati poizvedbe SPARQL</comment>
+ <comment xml:lang="si">SPARQL විමසුම් ප්රතිඵල</comment>
+ <comment xml:lang="ru">Результаты запроса SPARQL</comment>
+ <comment xml:lang="pl">Wyniki zapytania SPARQL</comment>
+ <comment xml:lang="nl">SPARQL-zoekopdrachtresultaten</comment>
+ <comment xml:lang="ko">SPARQL 질의문 결과</comment>
+ <comment xml:lang="kk">SPARQL сұраным нәтижелері</comment>
+ <comment xml:lang="ja">SPARQL クエリーの結果</comment>
+ <comment xml:lang="it">Risultati ricerca SPARQL</comment>
+ <comment xml:lang="hr">Rezultati SPARQL zahtjeva</comment>
+ <comment xml:lang="he">תוצאות שאילתת SPARQL</comment>
+ <comment xml:lang="fi">SPARQL-kyselyn tulokset</comment>
+ <comment xml:lang="eu">SPARQL kontsultaren emaitzak</comment>
+ <comment xml:lang="es">resultados de consulta SPARQL</comment>
+ <comment xml:lang="en_GB">SPARQL query results</comment>
+ <comment xml:lang="de">SPARQL-Abfrageergebnisse</comment>
+ <comment xml:lang="be">вынікі запыту SPARQL</comment>
+ <comment xml:lang="ar">نتائج استعلام SPARQL</comment>
<acronym>SPARQL</acronym>
<expanded-acronym>SPARQL Protocol and RDF Query Language</expanded-acronym>
<sub-class-of type="application/xml"/>
<root-XML namespaceURI="http://www.w3.org/2005/sparql-results#" localName="sparql"/>
<glob pattern="*.srx"/>
</mime-type>
+ <mime-type type="application/wasm">
+ <comment>WASM binary module</comment>
+ <comment xml:lang="uk">двійковий модуль WASM</comment>
+ <comment xml:lang="sv">WASM-binärmodul</comment>
+ <comment xml:lang="ru">Двоичный модуль WASM</comment>
+ <comment xml:lang="pl">Moduł binarny WASM</comment>
+ <comment xml:lang="es">módulo binario de WASM</comment>
+ <comment xml:lang="de">WASM-Binärmodul</comment>
+ <acronym>WASM</acronym>
+ <expanded-acronym>Web Assembly</expanded-acronym>
+ <glob pattern="*.wasm"/>
+ <magic>
+ <match type="string" value="\000asm" offset="0"/>
+ </magic>
+ </mime-type>
+ <mime-type type="application/x-openvpn-profile">
+ <comment>OpenVPN profile</comment>
+ <comment xml:lang="uk">профіль OpenVPN</comment>
+ <comment xml:lang="sv">OpenVPN-profil</comment>
+ <comment xml:lang="ru">Профиль OpenVPN</comment>
+ <comment xml:lang="pl">Profil OpenVPN</comment>
+ <comment xml:lang="it">Profilo OpenVPN</comment>
+ <comment xml:lang="es">perfil OpenVPN</comment>
+ <comment xml:lang="de">OpenVPN-Profil</comment>
+ <comment xml:lang="be">профіль OpenVPN</comment>
+ <sub-class-of type="text/plain"/>
+ <generic-icon name="text-x-generic"/>
+ <glob pattern="*.openvpn"/>
+ <glob pattern="*.ovpn"/>
+ </mime-type>
+ <mime-type type="application/x-modrinth-modpack+zip">
+ <comment>Modrinth Modpack</comment>
+ <comment xml:lang="uk">модпак Modrinth</comment>
+ <comment xml:lang="sv">Modrinth-moddpack</comment>
+ <comment xml:lang="ru">Модификационный пакет Modrinth</comment>
+ <comment xml:lang="pl">Pakiet modów Modrinth</comment>
+ <comment xml:lang="it">Modpack Modrinth</comment>
+ <comment xml:lang="es">paquete de modificaciones de Modrinth</comment>
+ <comment xml:lang="de">Modrinth-Modpack</comment>
+ <sub-class-of type="application/zip"/>
+ <generic-icon name="package-x-generic"/>
+ <glob pattern="*.mrpack"/>
+ </mime-type>
+ <mime-type type="application/cbor">
+ <comment>CBOR Data</comment>
+ <comment xml:lang="zh_TW">CBOR 資料</comment>
+ <comment xml:lang="uk">дані CBOR</comment>
+ <comment xml:lang="sv">CBOR-data</comment>
+ <comment xml:lang="ru">Данные CBOR</comment>
+ <comment xml:lang="pl">Dane CBOR</comment>
+ <comment xml:lang="it">Dati CBOR</comment>
+ <comment xml:lang="es">datos CBOR</comment>
+ <comment xml:lang="de">CBOR-Daten</comment>
+ <comment xml:lang="be">даныя CBOR</comment>
+ <acronym>CBOR</acronym>
+ <expanded-acronym>Concise Binary Object Representation</expanded-acronym>
+ <glob pattern="*.cbor"/>
+ </mime-type>
+ <mime-type type="application/x-eris-link+cbor">
+ <comment>ERIS Link</comment>
+ <comment xml:lang="uk">посилання ERIS</comment>
+ <comment xml:lang="sv">ERIS-länk</comment>
+ <comment xml:lang="ru">Ссылка ERIS</comment>
+ <comment xml:lang="pl">Dowiązanie ERIS</comment>
+ <comment xml:lang="it">Collegamento ERIS</comment>
+ <comment xml:lang="es">enlace ERIS</comment>
+ <comment xml:lang="de">ERIS-Verweis</comment>
+ <comment xml:lang="be">спасылка ERIS</comment>
+ <acronym>ERIS</acronym>
+ <expanded-acronym>Encoding for Robust Immutable Storage</expanded-acronym>
+ <sub-class-of type="application/cbor"/>
+ <glob pattern="*.eris"/>
+ <magic priority="90">
+ <match type="string" value="\xD9\xD9\xF7\x84\xD9\x01\x14\x58\x42" offset="0"/>
+ </magic>
+ </mime-type>
+ <mime-type type="application/vnd.gerber">
+ <comment>Gerber file</comment>
+ <comment xml:lang="uk">файл Gerber</comment>
+ <comment xml:lang="sv">Gerber-fil</comment>
+ <comment xml:lang="ru">Файл Gerber</comment>
+ <comment xml:lang="pl">Plik Gerber</comment>
+ <comment xml:lang="it">File Gerber</comment>
+ <comment xml:lang="es">archivo de Gerber</comment>
+ <comment xml:lang="de">Gerber-Datei</comment>
+ <comment xml:lang="be">файл Gerber</comment>
+ <sub-class-of type="text/plain"/>
+ <glob pattern="*.gbr"/>
+ <!--Try to match with some common opening commands-->
+ <magic>
+ <!--A comment line-->
+ <match type="string" value="G04 " offset="0"/>
+ <!--Some setup macros-->
+ <match type="string" value="%FSLA" offset="0"/>
+ <match type="string" value="%MO" offset="0"/>
+ <match type="string" value="%TF." offset="0"/>
+ <!--Seems to be common with files exported from some programs-->
+ <match type="string" value="G75*" offset="0"/>
+ </magic>
+ <generic-icon name="text-x-generic"/>
+ <!--Already being used as the MIME identifier by some programs-->
+ <alias type="application/x-gerber"/>
+ </mime-type>
+ <mime-type type="application/x-gerber-job">
+ <comment>Gerber job file</comment>
+ <comment xml:lang="uk">файл завдання Gerber</comment>
+ <comment xml:lang="sv">Gerber-jobbfil</comment>
+ <comment xml:lang="ru">Файл работ Gerber</comment>
+ <comment xml:lang="pl">Plik zadania Gerber</comment>
+ <comment xml:lang="it">File lavoro Gerber</comment>
+ <comment xml:lang="es">archivo de tarea de Gerber</comment>
+ <comment xml:lang="de">Gerber-Aufgabendatei</comment>
+ <comment xml:lang="be">працоўны файл Gerber</comment>
+ <sub-class-of type="application/json"/>
+ <glob pattern="*.gbrjob"/>
+ <generic-icon name="text-x-generic"/>
+ </mime-type>
+ <mime-type type="application/x-excellon">
+ <comment>Excellon drill file</comment>
+ <comment xml:lang="uk">файл drill Excellon</comment>
+ <comment xml:lang="sv">Excellon-borrfil</comment>
+ <comment xml:lang="ru">Файл Excellon drill</comment>
+ <comment xml:lang="pl">Plik wiercenia Excellon</comment>
+ <comment xml:lang="es">archivo de perforación de Excellon</comment>
+ <comment xml:lang="de">Excellon-Bohrdatei</comment>
+ <sub-class-of type="text/plain"/>
+ <glob pattern="*.drl"/>
+ <magic>
+ <!--This is always the header for an excellon drill file-->
+ <match type="string" value="M48\n" offset="0"/>
+ </magic>
+ <generic-icon name="text-x-generic"/>
+ </mime-type>
+ <mime-type type="application/x-tiled-tmx">
+ <comment>Tiled map files</comment>
+ <comment xml:lang="uk">файли мозаїчної карти</comment>
+ <comment xml:lang="sv">Tiled-kartfiler</comment>
+ <comment xml:lang="ru">Файлы карты Tiled</comment>
+ <comment xml:lang="pl">Pliki map Tiled</comment>
+ <comment xml:lang="es">archivos de mapa en mosaico</comment>
+ <comment xml:lang="de">Tiled-Kartendatei</comment>
+ <sub-class-of type="application/xml"/>
+ <glob pattern="*.tmx"/>
+ </mime-type>
+ <mime-type type="application/x-tiled-tsx">
+ <comment>Tiled tileset files</comment>
+ <comment xml:lang="uk">файл набору плиток мозаїки</comment>
+ <comment xml:lang="sv">Tiled-kartrutuppsättningsfiler</comment>
+ <comment xml:lang="ru">Файлы наборов плиток Tiled</comment>
+ <comment xml:lang="pl">Pliki zestawów kafli Tiled</comment>
+ <comment xml:lang="de">Tiled-Kartensetdatei</comment>
+ <sub-class-of type="application/xml"/>
+ <glob pattern="*.tsx"/>
+ </mime-type>
</mime-info>
diff --git a/src/corelib/mimetypes/qmimedatabase.cpp b/src/corelib/mimetypes/qmimedatabase.cpp
index c55904c1d0..d52ccacbe7 100644
--- a/src/corelib/mimetypes/qmimedatabase.cpp
+++ b/src/corelib/mimetypes/qmimedatabase.cpp
@@ -10,9 +10,9 @@
#include "qmimeprovider_p.h"
#include "qmimetype_p.h"
+#include <private/qduplicatetracker_p.h>
#include <private/qfilesystementry_p.h>
-#include <QtCore/QMap>
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
#include <QtCore/QStandardPaths>
@@ -74,7 +74,7 @@ static QStringList locateMimeDirectories()
return QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("mime"), QStandardPaths::LocateDirectory);
}
-#if defined(Q_OS_UNIX) && !defined(Q_OS_NACL) && !defined(Q_OS_INTEGRITY)
+#if defined(Q_OS_UNIX) && !defined(Q_OS_INTEGRITY)
# define QT_USE_MMAP
#endif
@@ -142,6 +142,13 @@ void QMimeDatabasePrivate::loadProviders()
m_providers.push_back(std::move(*it));
}
}
+
+ auto it = m_providers.begin();
+ (*it)->setOverrideProvider(nullptr);
+ ++it;
+ const auto end = m_providers.end();
+ for (; it != end; ++it)
+ (*it)->setOverrideProvider((it - 1)->get());
}
const QMimeDatabasePrivate::Providers &QMimeDatabasePrivate::providers()
@@ -177,9 +184,8 @@ QMimeType QMimeDatabasePrivate::mimeTypeForName(const QString &nameOrAlias)
{
const QString mimeName = resolveAlias(nameOrAlias);
for (const auto &provider : providers()) {
- const QMimeType mime = provider->mimeTypeForName(mimeName);
- if (mime.isValid())
- return mime;
+ if (provider->knowsMimeType(mimeName))
+ return QMimeType(QMimeTypePrivate(mimeName));
}
return {};
}
@@ -204,54 +210,54 @@ QMimeGlobMatchResult QMimeDatabasePrivate::findByFileName(const QString &fileNam
return result;
}
-void QMimeDatabasePrivate::loadMimeTypePrivate(QMimeTypePrivate &mimePrivate)
+QMimeTypePrivate::LocaleHash QMimeDatabasePrivate::localeComments(const QString &name)
{
QMutexLocker locker(&mutex);
- if (mimePrivate.name.isEmpty())
- return; // invalid mimetype
- if (!mimePrivate.loaded) { // XML provider sets loaded=true, binary provider does this on demand
- Q_ASSERT(mimePrivate.fromCache);
- bool found = false;
- for (const auto &provider : providers()) {
- if (provider->loadMimeTypePrivate(mimePrivate)) {
- found = true;
- break;
- }
- }
- if (!found) {
- const QString file = mimePrivate.name + ".xml"_L1;
- qWarning() << "No file found for" << file << ", even though update-mime-info said it would exist.\n"
- "Either it was just removed, or the directory doesn't have executable permission..."
- << locateMimeDirectories();
- }
- mimePrivate.loaded = true;
+ for (const auto &provider : providers()) {
+ auto comments = provider->localeComments(name);
+ if (!comments.isEmpty())
+ return comments; // maybe we want to merge in comments from more global providers, in
+ // case of more translations?
}
+ return {};
}
-void QMimeDatabasePrivate::loadGenericIcon(QMimeTypePrivate &mimePrivate)
+QStringList QMimeDatabasePrivate::globPatterns(const QString &name)
{
QMutexLocker locker(&mutex);
- if (mimePrivate.fromCache) {
- mimePrivate.genericIconName.clear();
- for (const auto &provider : providers()) {
- provider->loadGenericIcon(mimePrivate);
- if (!mimePrivate.genericIconName.isEmpty())
- break;
- }
+ QStringList patterns;
+ const auto &providerList = providers();
+ // reverse iteration because we start from most global, add up, clear if delete-all, and add up
+ // again.
+ for (auto rit = providerList.rbegin(); rit != providerList.rend(); ++rit) {
+ auto *provider = rit->get();
+ if (provider->hasGlobDeleteAll(name))
+ patterns.clear();
+ patterns += provider->globPatterns(name);
}
+ return patterns;
}
-void QMimeDatabasePrivate::loadIcon(QMimeTypePrivate &mimePrivate)
+QString QMimeDatabasePrivate::genericIcon(const QString &name)
{
QMutexLocker locker(&mutex);
- if (mimePrivate.fromCache) {
- mimePrivate.iconName.clear();
- for (const auto &provider : providers()) {
- provider->loadIcon(mimePrivate);
- if (!mimePrivate.iconName.isEmpty())
- break;
- }
+ for (const auto &provider : providers()) {
+ QString genericIconName = provider->genericIcon(name);
+ if (!genericIconName.isEmpty())
+ return genericIconName;
}
+ return {};
+}
+
+QString QMimeDatabasePrivate::icon(const QString &name)
+{
+ QMutexLocker locker(&mutex);
+ for (const auto &provider : providers()) {
+ QString iconName = provider->icon(name);
+ if (!iconName.isEmpty())
+ return iconName;
+ }
+ return {};
}
QString QMimeDatabasePrivate::fallbackParent(const QString &mimeTypeName) const
@@ -331,13 +337,14 @@ QMimeType QMimeDatabasePrivate::findByData(const QByteArray &data, int *accuracy
return mimeTypeForName(QStringLiteral("application/x-zerosize"));
}
- *accuracyPtr = 0;
- QMimeType candidate;
+ QMimeMagicResult result;
for (const auto &provider : providers())
- provider->findByMagic(data, accuracyPtr, candidate);
+ provider->findByMagic(data, result);
- if (candidate.isValid())
- return candidate;
+ if (result.isValid()) {
+ *accuracyPtr = result.accuracy;
+ return QMimeType(QMimeTypePrivate(result.candidate));
+ }
if (isTextFile(data)) {
*accuracyPtr = 5;
@@ -496,6 +503,7 @@ QList<QMimeType> QMimeDatabasePrivate::allMimeTypes()
bool QMimeDatabasePrivate::inherits(const QString &mime, const QString &parent)
{
const QString resolvedParent = resolveAlias(parent);
+ QDuplicateTracker<QString> seen;
std::stack<QString, QStringList> toCheck;
toCheck.push(mime);
while (!toCheck.empty()) {
@@ -504,8 +512,11 @@ bool QMimeDatabasePrivate::inherits(const QString &mime, const QString &parent)
const QString mimeName = toCheck.top();
toCheck.pop();
const auto parentList = parents(mimeName);
- for (const QString &par : parentList)
- toCheck.push(resolveAlias(par));
+ for (const QString &par : parentList) {
+ const QString resolvedPar = resolveAlias(par);
+ if (!seen.hasSeen(resolvedPar))
+ toCheck.push(resolvedPar);
+ }
}
return false;
}
@@ -547,7 +558,7 @@ bool QMimeDatabasePrivate::inherits(const QString &mime, const QString &parent)
\snippet code/src_corelib_mimetype_qmimedatabase.cpp 0
- \sa QMimeType, {MIME Type Browser Example}
+ \sa QMimeType, {MIME Type Browser}
*/
/*!
@@ -668,7 +679,7 @@ QList<QMimeType> QMimeDatabase::mimeTypesForFileName(const QString &fileName) co
QString QMimeDatabase::suffixForFileName(const QString &fileName) const
{
QMutexLocker locker(&d->mutex);
- const int suffixLength = d->findByFileName(fileName).m_knownSuffixLength;
+ const qsizetype suffixLength = d->findByFileName(fileName).m_knownSuffixLength;
return fileName.right(suffixLength);
}
diff --git a/src/corelib/mimetypes/qmimedatabase_p.h b/src/corelib/mimetypes/qmimedatabase_p.h
index 96981ba3fe..cb28f0b791 100644
--- a/src/corelib/mimetypes/qmimedatabase_p.h
+++ b/src/corelib/mimetypes/qmimedatabase_p.h
@@ -66,9 +66,10 @@ public:
QMimeGlobMatchResult findByFileName(const QString &fileName);
// API for QMimeType. Takes care of locking the mutex.
- void loadMimeTypePrivate(QMimeTypePrivate &mimePrivate);
- void loadGenericIcon(QMimeTypePrivate &mimePrivate);
- void loadIcon(QMimeTypePrivate &mimePrivate);
+ QMimeTypePrivate::LocaleHash localeComments(const QString &name);
+ QStringList globPatterns(const QString &name);
+ QString genericIcon(const QString &name);
+ QString icon(const QString &name);
QStringList mimeParents(const QString &mimeName);
QStringList listAliases(const QString &mimeName);
bool mimeInherits(const QString &mime, const QString &parent);
@@ -81,7 +82,7 @@ private:
QString fallbackParent(const QString &mimeTypeName) const;
const QString m_defaultMimeType;
- mutable Providers m_providers;
+ mutable Providers m_providers; // most local first, most global last
QElapsedTimer m_lastCheck;
public:
diff --git a/src/corelib/mimetypes/qmimeglobpattern.cpp b/src/corelib/mimetypes/qmimeglobpattern.cpp
index 381b635b90..d50787a0be 100644
--- a/src/corelib/mimetypes/qmimeglobpattern.cpp
+++ b/src/corelib/mimetypes/qmimeglobpattern.cpp
@@ -22,7 +22,8 @@ using namespace Qt::StringLiterals;
Handles glob weights, and preferring longer matches over shorter matches.
*/
-void QMimeGlobMatchResult::addMatch(const QString &mimeType, int weight, const QString &pattern, int knownSuffixLength)
+void QMimeGlobMatchResult::addMatch(const QString &mimeType, int weight, const QString &pattern,
+ qsizetype knownSuffixLength)
{
if (m_allMatchingMimeTypes.contains(mimeType))
return;
@@ -57,13 +58,13 @@ void QMimeGlobMatchResult::addMatch(const QString &mimeType, int weight, const Q
}
}
-QMimeGlobPattern::PatternType QMimeGlobPattern::detectPatternType(const QString &pattern) const
+QMimeGlobPattern::PatternType QMimeGlobPattern::detectPatternType(QStringView pattern) const
{
- const int patternLength = pattern.size();
+ const qsizetype patternLength = pattern.size();
if (!patternLength)
return OtherPattern;
- const int starCount = pattern.count(u'*');
+ const qsizetype starCount = pattern.count(u'*');
const bool hasSquareBracket = pattern.indexOf(u'[') != -1;
const bool hasQuestionMark = pattern.indexOf(u'?') != -1;
@@ -108,10 +109,10 @@ bool QMimeGlobPattern::matchFileName(const QString &inputFileName) const
const QString fileName = m_caseSensitivity == Qt::CaseInsensitive
? inputFileName.toLower() : inputFileName;
- const int patternLength = m_pattern.size();
+ const qsizetype patternLength = m_pattern.size();
if (!patternLength)
return false;
- const int fileNameLength = fileName.size();
+ const qsizetype fileNameLength = fileName.size();
switch (m_patternType) {
case SuffixPattern: {
@@ -162,7 +163,7 @@ bool QMimeGlobPattern::matchFileName(const QString &inputFileName) const
return false;
}
-static bool isSimplePattern(const QString &pattern)
+static bool isSimplePattern(QStringView pattern)
{
// starts with "*.", has no other '*'
return pattern.lastIndexOf(u'*') == 0
@@ -174,7 +175,7 @@ static bool isSimplePattern(const QString &pattern)
;
}
-static bool isFastPattern(const QString &pattern)
+static bool isFastPattern(QStringView pattern)
{
// starts with "*.", has no other '*' and no other '.'
return pattern.lastIndexOf(u'*') == 0
@@ -219,45 +220,45 @@ void QMimeAllGlobPatterns::removeMimeType(const QString &mimeType)
m_lowWeightGlobs.removeMimeType(mimeType);
}
-void QMimeGlobPatternList::match(QMimeGlobMatchResult &result,
- const QString &fileName) const
+void QMimeGlobPatternList::match(QMimeGlobMatchResult &result, const QString &fileName,
+ const AddMatchFilterFunc &filterFunc) const
{
-
- QMimeGlobPatternList::const_iterator it = this->constBegin();
- const QMimeGlobPatternList::const_iterator endIt = this->constEnd();
- for (; it != endIt; ++it) {
- const QMimeGlobPattern &glob = *it;
- if (glob.matchFileName(fileName)) {
+ for (const QMimeGlobPattern &glob : *this) {
+ if (glob.matchFileName(fileName) && filterFunc(glob.mimeType())) {
const QString pattern = glob.pattern();
- const int suffixLen = isSimplePattern(pattern) ? pattern.size() - 2 : 0;
+ const qsizetype suffixLen = isSimplePattern(pattern) ? pattern.size() - strlen("*.") : 0;
result.addMatch(glob.mimeType(), glob.weight(), pattern, suffixLen);
}
}
}
-void QMimeAllGlobPatterns::matchingGlobs(const QString &fileName, QMimeGlobMatchResult &result) const
+void QMimeAllGlobPatterns::matchingGlobs(const QString &fileName, QMimeGlobMatchResult &result,
+ const AddMatchFilterFunc &filterFunc) const
{
// First try the high weight matches (>50), if any.
- m_highWeightGlobs.match(result, fileName);
+ m_highWeightGlobs.match(result, fileName, filterFunc);
// Now use the "fast patterns" dict, for simple *.foo patterns with weight 50
// (which is most of them, so this optimization is definitely worth it)
- const int lastDot = fileName.lastIndexOf(u'.');
+ const qsizetype lastDot = fileName.lastIndexOf(u'.');
if (lastDot != -1) { // if no '.', skip the extension lookup
- const int ext_len = fileName.size() - lastDot - 1;
+ const qsizetype ext_len = fileName.size() - lastDot - 1;
const QString simpleExtension = fileName.right(ext_len).toLower();
// (toLower because fast patterns are always case-insensitive and saved as lowercase)
const QStringList matchingMimeTypes = m_fastPatterns.value(simpleExtension);
const QString simplePattern = "*."_L1 + simpleExtension;
- for (const QString &mime : matchingMimeTypes)
- result.addMatch(mime, 50, simplePattern, simpleExtension.size());
+ for (const QString &mime : matchingMimeTypes) {
+ if (filterFunc(mime)) {
+ result.addMatch(mime, 50, simplePattern, simpleExtension.size());
+ }
+ }
// Can't return yet; *.tar.bz2 has to win over *.bz2, so we need the low-weight mimetypes anyway,
// at least those with weight 50.
}
// Finally, try the low weight matches (<=50)
- m_lowWeightGlobs.match(result, fileName);
+ m_lowWeightGlobs.match(result, fileName, filterFunc);
}
void QMimeAllGlobPatterns::clear()
diff --git a/src/corelib/mimetypes/qmimeglobpattern_p.h b/src/corelib/mimetypes/qmimeglobpattern_p.h
index bb54a086d4..b4316355ba 100644
--- a/src/corelib/mimetypes/qmimeglobpattern_p.h
+++ b/src/corelib/mimetypes/qmimeglobpattern_p.h
@@ -22,17 +22,20 @@ QT_REQUIRE_CONFIG(mimetype);
#include <QtCore/qstringlist.h>
#include <QtCore/qhash.h>
+#include <algorithm>
+
QT_BEGIN_NAMESPACE
struct QMimeGlobMatchResult
{
- void addMatch(const QString &mimeType, int weight, const QString &pattern, int knownSuffixLength = 0);
+ void addMatch(const QString &mimeType, int weight, const QString &pattern,
+ qsizetype knownSuffixLength = 0);
QStringList m_matchingMimeTypes; // only those with highest weight
QStringList m_allMatchingMimeTypes;
int m_weight = 0;
- int m_matchingPatternLength = 0;
- int m_knownSuffixLength = 0;
+ qsizetype m_matchingPatternLength = 0;
+ qsizetype m_knownSuffixLength = 0;
};
class QMimeGlobPattern
@@ -76,7 +79,7 @@ private:
AnimPattern, // special handling for "*.anim[1-9j]" pattern
OtherPattern
};
- PatternType detectPatternType(const QString &pattern) const;
+ PatternType detectPatternType(QStringView pattern) const;
QString m_pattern;
QString m_mimeType;
@@ -86,31 +89,32 @@ private:
};
Q_DECLARE_SHARED(QMimeGlobPattern)
+using AddMatchFilterFunc = std::function<bool(const QString &)>;
+
class QMimeGlobPatternList : public QList<QMimeGlobPattern>
{
public:
- bool hasPattern(const QString &mimeType, const QString &pattern) const
+ bool hasPattern(QStringView mimeType, QStringView pattern) const
{
- const_iterator it = begin();
- const const_iterator myend = end();
- for (; it != myend; ++it)
- if ((*it).pattern() == pattern && (*it).mimeType() == mimeType)
- return true;
- return false;
+ auto matchesMimeAndPattern = [mimeType, pattern](const QMimeGlobPattern &e) {
+ return e.pattern() == pattern && e.mimeType() == mimeType;
+ };
+ return std::any_of(begin(), end(), matchesMimeAndPattern);
}
/*!
"noglobs" is very rare occurrence, so it's ok if it's slow
*/
- void removeMimeType(const QString &mimeType)
+ void removeMimeType(QStringView mimeType)
{
- auto isMimeTypeEqual = [&mimeType](const QMimeGlobPattern &pattern) {
+ auto isMimeTypeEqual = [mimeType](const QMimeGlobPattern &pattern) {
return pattern.mimeType() == mimeType;
};
removeIf(isMimeTypeEqual);
}
- void match(QMimeGlobMatchResult &result, const QString &fileName) const;
+ void match(QMimeGlobMatchResult &result, const QString &fileName,
+ const AddMatchFilterFunc &filterFunc) const;
};
/*!
@@ -127,7 +131,8 @@ public:
void addGlob(const QMimeGlobPattern &glob);
void removeMimeType(const QString &mimeType);
- void matchingGlobs(const QString &fileName, QMimeGlobMatchResult &result) const;
+ void matchingGlobs(const QString &fileName, QMimeGlobMatchResult &result,
+ const AddMatchFilterFunc &filterFunc) const;
void clear();
PatternsMap m_fastPatterns; // example: "doc" -> "application/msword", "text/plain"
diff --git a/src/corelib/mimetypes/qmimemagicrule.cpp b/src/corelib/mimetypes/qmimemagicrule.cpp
index b0846e375b..3c33d53aac 100644
--- a/src/corelib/mimetypes/qmimemagicrule.cpp
+++ b/src/corelib/mimetypes/qmimemagicrule.cpp
@@ -8,7 +8,6 @@
#include "qmimetypeparser_p.h"
#include <QtCore/QList>
-#include <QtCore/QMap>
#include <QtCore/QDebug>
#include <qendian.h>
@@ -61,12 +60,12 @@ bool QMimeMagicRule::operator==(const QMimeMagicRule &other) const
}
// Used by both providers
-bool QMimeMagicRule::matchSubstring(const char *dataPtr, int dataSize, int rangeStart, int rangeLength,
- int valueLength, const char *valueData, const char *mask)
+bool QMimeMagicRule::matchSubstring(const char *dataPtr, qsizetype dataSize, int rangeStart, int rangeLength,
+ qsizetype valueLength, const char *valueData, const char *mask)
{
// Size of searched data.
// Example: value="ABC", rangeLength=3 -> we need 3+3-1=5 bytes (ABCxx,xABCx,xxABC would match)
- const int dataNeeded = qMin(rangeLength + valueLength - 1, dataSize - rangeStart);
+ const qsizetype dataNeeded = qMin(rangeLength + valueLength - 1, dataSize - rangeStart);
if (!mask) {
// callgrind says QByteArray::indexOf is much slower, since our strings are typically too
@@ -90,7 +89,7 @@ bool QMimeMagicRule::matchSubstring(const char *dataPtr, int dataSize, int range
// deviceSize is 4, so dataNeeded was max'ed to 4.
// maxStartPos = 4 - 3 + 1 = 2, and indeed
// we need to check for a match a positions 0 and 1 (ABCx and xABC).
- const int maxStartPos = dataNeeded - valueLength + 1;
+ const qsizetype maxStartPos = dataNeeded - valueLength + 1;
for (int i = 0; i < maxStartPos; ++i) {
const char *d = readDataBase + i;
bool valid = true;
@@ -201,7 +200,7 @@ QMimeMagicRule::QMimeMagicRule(const QString &type,
}
// Parse for offset as "1" or "1:10"
- const int colonIndex = offsets.indexOf(u':');
+ const qsizetype colonIndex = offsets.indexOf(u':');
const QStringView startPosStr = QStringView{offsets}.mid(0, colonIndex); // \ These decay to returning 'offsets'
const QStringView endPosStr = QStringView{offsets}.mid(colonIndex + 1);// / unchanged when colonIndex == -1
if (Q_UNLIKELY(!QMimeTypeParserBase::parseNumber(startPosStr, &m_startPos, errorString)) ||
diff --git a/src/corelib/mimetypes/qmimemagicrule_p.h b/src/corelib/mimetypes/qmimemagicrule_p.h
index e1d4719026..bd1b72d113 100644
--- a/src/corelib/mimetypes/qmimemagicrule_p.h
+++ b/src/corelib/mimetypes/qmimemagicrule_p.h
@@ -63,7 +63,9 @@ public:
static Type type(const QByteArray &type);
static QByteArray typeName(Type type);
- static bool matchSubstring(const char *dataPtr, int dataSize, int rangeStart, int rangeLength, int valueLength, const char *valueData, const char *mask);
+ static bool matchSubstring(const char *dataPtr, qsizetype dataSize, int rangeStart,
+ int rangeLength, qsizetype valueLength, const char *valueData,
+ const char *mask);
private:
Type m_type;
diff --git a/src/corelib/mimetypes/qmimeprovider.cpp b/src/corelib/mimetypes/qmimeprovider.cpp
index 8732d4c915..458cd46385 100644
--- a/src/corelib/mimetypes/qmimeprovider.cpp
+++ b/src/corelib/mimetypes/qmimeprovider.cpp
@@ -9,7 +9,6 @@
#include <qstandardpaths.h>
#include "qmimemagicrulematcher_p.h"
-#include <QMap>
#include <QXmlStreamReader>
#include <QBuffer>
#include <QDir>
@@ -51,18 +50,6 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-QMimeProviderBase::QMimeProviderBase(QMimeDatabasePrivate *db, const QString &directory)
- : m_db(db), m_directory(directory)
-{
-}
-
-
-QMimeBinaryProvider::QMimeBinaryProvider(QMimeDatabasePrivate *db, const QString &directory)
- : QMimeProviderBase(db, directory), m_mimetypeListLoaded(false)
-{
- ensureLoaded();
-}
-
struct QMimeBinaryProvider::CacheFile
{
CacheFile(const QString &fileName);
@@ -90,6 +77,43 @@ struct QMimeBinaryProvider::CacheFile
bool m_valid;
};
+static inline void appendIfNew(QStringList &list, const QString &str)
+{
+ if (!list.contains(str))
+ list.push_back(str);
+}
+
+QMimeProviderBase::QMimeProviderBase(QMimeDatabasePrivate *db, const QString &directory)
+ : m_db(db), m_directory(directory)
+{
+}
+
+QMimeProviderBase *QMimeProviderBase::overrideProvider() const
+{
+ return m_overrideProvider;
+}
+
+void QMimeProviderBase::setOverrideProvider(QMimeProviderBase *provider)
+{
+ m_overrideProvider = provider;
+}
+
+bool QMimeProviderBase::isMimeTypeGlobsExcluded(const QString &name) const
+{
+ if (m_overrideProvider) {
+ if (m_overrideProvider->hasGlobDeleteAll(name))
+ return true;
+ return m_overrideProvider->isMimeTypeGlobsExcluded(name);
+ }
+ return false;
+}
+
+QMimeBinaryProvider::QMimeBinaryProvider(QMimeDatabasePrivate *db, const QString &directory)
+ : QMimeProviderBase(db, directory), m_mimetypeListLoaded(false)
+{
+ ensureLoaded();
+}
+
QMimeBinaryProvider::CacheFile::CacheFile(const QString &fileName)
: file(fileName), m_valid(false)
{
@@ -124,10 +148,7 @@ bool QMimeBinaryProvider::CacheFile::reload()
return load();
}
-QMimeBinaryProvider::~QMimeBinaryProvider()
-{
- delete m_cacheFile;
-}
+QMimeBinaryProvider::~QMimeBinaryProvider() = default;
bool QMimeBinaryProvider::isValid()
{
@@ -168,7 +189,7 @@ void QMimeBinaryProvider::ensureLoaded()
{
if (!m_cacheFile) {
const QString cacheFileName = m_directory + "/mime.cache"_L1;
- m_cacheFile = new CacheFile(cacheFileName);
+ m_cacheFile = std::make_unique<CacheFile>(cacheFileName);
m_mimetypeListLoaded = false;
m_mimetypeExtra.clear();
} else {
@@ -179,31 +200,15 @@ void QMimeBinaryProvider::ensureLoaded()
return; // nothing to do
}
}
- if (!m_cacheFile->isValid()) { // verify existence and version
- delete m_cacheFile;
- m_cacheFile = nullptr;
- }
+ if (!m_cacheFile->isValid()) // verify existence and version
+ m_cacheFile.reset();
}
-static QMimeType mimeTypeForNameUnchecked(const QString &name)
-{
- QMimeTypePrivate data;
- data.name = name;
- data.fromCache = true;
- // The rest is retrieved on demand.
- // comment and globPatterns: in loadMimeTypePrivate
- // iconName: in loadIcon
- // genericIconName: in loadGenericIcon
- return QMimeType(data);
-}
-
-QMimeType QMimeBinaryProvider::mimeTypeForName(const QString &name)
+bool QMimeBinaryProvider::knowsMimeType(const QString &name)
{
if (!m_mimetypeListLoaded)
loadMimeTypeList();
- if (!m_mimetypeNames.contains(name))
- return QMimeType(); // unknown mimetype
- return mimeTypeForNameUnchecked(name);
+ return m_mimetypeNames.contains(name);
}
void QMimeBinaryProvider::addFileNameMatches(const QString &fileName, QMimeGlobMatchResult &result)
@@ -211,25 +216,34 @@ void QMimeBinaryProvider::addFileNameMatches(const QString &fileName, QMimeGlobM
if (fileName.isEmpty())
return;
Q_ASSERT(m_cacheFile);
- const QString lowerFileName = fileName.toLower();
+ int numMatches = 0;
// Check literals (e.g. "Makefile")
- matchGlobList(result, m_cacheFile, m_cacheFile->getUint32(PosLiteralListOffset), fileName);
+ numMatches = matchGlobList(result, m_cacheFile.get(),
+ m_cacheFile->getUint32(PosLiteralListOffset), fileName);
// Check the very common *.txt cases with the suffix tree
- if (result.m_matchingMimeTypes.isEmpty()) {
+ if (numMatches == 0) {
+ const QString lowerFileName = fileName.toLower();
const int reverseSuffixTreeOffset = m_cacheFile->getUint32(PosReverseSuffixTreeOffset);
const int numRoots = m_cacheFile->getUint32(reverseSuffixTreeOffset);
const int firstRootOffset = m_cacheFile->getUint32(reverseSuffixTreeOffset + 4);
- matchSuffixTree(result, m_cacheFile, numRoots, firstRootOffset, lowerFileName, lowerFileName.size() - 1, false);
- if (result.m_matchingMimeTypes.isEmpty())
- matchSuffixTree(result, m_cacheFile, numRoots, firstRootOffset, fileName, fileName.size() - 1, true);
+ if (matchSuffixTree(result, m_cacheFile.get(), numRoots, firstRootOffset, lowerFileName,
+ lowerFileName.size() - 1, false)) {
+ ++numMatches;
+ } else if (matchSuffixTree(result, m_cacheFile.get(), numRoots, firstRootOffset, fileName,
+ fileName.size() - 1, true)) {
+ ++numMatches;
+ }
}
// Check complex globs (e.g. "callgrind.out[0-9]*" or "README*")
- if (result.m_matchingMimeTypes.isEmpty())
- matchGlobList(result, m_cacheFile, m_cacheFile->getUint32(PosGlobListOffset), fileName);
+ if (numMatches == 0)
+ matchGlobList(result, m_cacheFile.get(), m_cacheFile->getUint32(PosGlobListOffset),
+ fileName);
}
-void QMimeBinaryProvider::matchGlobList(QMimeGlobMatchResult &result, CacheFile *cacheFile, int off, const QString &fileName)
+int QMimeBinaryProvider::matchGlobList(QMimeGlobMatchResult &result, CacheFile *cacheFile, int off,
+ const QString &fileName)
{
+ int numMatches = 0;
const int numGlobs = cacheFile->getUint32(off);
//qDebug() << "Loading" << numGlobs << "globs from" << cacheFile->file.fileName() << "at offset" << cacheFile->globListOffset;
for (int i = 0; i < numGlobs; ++i) {
@@ -241,16 +255,24 @@ void QMimeBinaryProvider::matchGlobList(QMimeGlobMatchResult &result, CacheFile
const Qt::CaseSensitivity qtCaseSensitive = caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
const QString pattern = QLatin1StringView(cacheFile->getCharStar(globOffset));
- const char *mimeType = cacheFile->getCharStar(mimeTypeOffset);
+ const QLatin1StringView mimeType(cacheFile->getCharStar(mimeTypeOffset));
//qDebug() << pattern << mimeType << weight << caseSensitive;
- QMimeGlobPattern glob(pattern, QString() /*unused*/, weight, qtCaseSensitive);
+ if (isMimeTypeGlobsExcluded(mimeType))
+ continue;
- if (glob.matchFileName(fileName))
- result.addMatch(QLatin1StringView(mimeType), weight, pattern);
+ QMimeGlobPattern glob(pattern, QString() /*unused*/, weight, qtCaseSensitive);
+ if (glob.matchFileName(fileName)) {
+ result.addMatch(mimeType, weight, pattern);
+ ++numMatches;
+ }
}
+ return numMatches;
}
-bool QMimeBinaryProvider::matchSuffixTree(QMimeGlobMatchResult &result, QMimeBinaryProvider::CacheFile *cacheFile, int numEntries, int firstOffset, const QString &fileName, int charPos, bool caseSensitiveCheck)
+bool QMimeBinaryProvider::matchSuffixTree(QMimeGlobMatchResult &result,
+ QMimeBinaryProvider::CacheFile *cacheFile, int numEntries,
+ int firstOffset, const QString &fileName,
+ qsizetype charPos, bool caseSensitiveCheck)
{
QChar fileChar = fileName[charPos];
int min = 0;
@@ -277,13 +299,15 @@ bool QMimeBinaryProvider::matchSuffixTree(QMimeGlobMatchResult &result, QMimeBin
if (mch != 0)
break;
const int mimeTypeOffset = cacheFile->getUint32(childOff + 4);
- const char *mimeType = cacheFile->getCharStar(mimeTypeOffset);
+ const QLatin1StringView mimeType(cacheFile->getCharStar(mimeTypeOffset));
+ if (isMimeTypeGlobsExcluded(mimeType))
+ continue;
const int flagsAndWeight = cacheFile->getUint32(childOff + 8);
const int weight = flagsAndWeight & 0xff;
const bool caseSensitive = flagsAndWeight & 0x100;
if (caseSensitiveCheck || !caseSensitive) {
- result.addMatch(QLatin1StringView(mimeType), weight,
- u'*' + QStringView{fileName}.mid(charPos + 1),
+ result.addMatch(mimeType, weight,
+ u'*' + QStringView{ fileName }.mid(charPos + 1),
fileName.size() - charPos - 2);
success = true;
}
@@ -298,7 +322,7 @@ bool QMimeBinaryProvider::matchSuffixTree(QMimeGlobMatchResult &result, QMimeBin
bool QMimeBinaryProvider::matchMagicRule(QMimeBinaryProvider::CacheFile *cacheFile, int numMatchlets, int firstOffset, const QByteArray &data)
{
const char *dataPtr = data.constData();
- const int dataSize = data.size();
+ const qsizetype dataSize = data.size();
for (int matchlet = 0; matchlet < numMatchlets; ++matchlet) {
const int off = firstOffset + matchlet * 32;
const int rangeStart = cacheFile->getUint32(off);
@@ -323,7 +347,7 @@ bool QMimeBinaryProvider::matchMagicRule(QMimeBinaryProvider::CacheFile *cacheFi
return false;
}
-void QMimeBinaryProvider::findByMagic(const QByteArray &data, int *accuracyPtr, QMimeType &candidate)
+void QMimeBinaryProvider::findByMagic(const QByteArray &data, QMimeMagicResult &result)
{
const int magicListOffset = m_cacheFile->getUint32(PosMagicListOffset);
const int numMatches = m_cacheFile->getUint32(magicListOffset);
@@ -334,14 +358,16 @@ void QMimeBinaryProvider::findByMagic(const QByteArray &data, int *accuracyPtr,
const int off = firstMatchOffset + i * 16;
const int numMatchlets = m_cacheFile->getUint32(off + 8);
const int firstMatchletOffset = m_cacheFile->getUint32(off + 12);
- if (matchMagicRule(m_cacheFile, numMatchlets, firstMatchletOffset, data)) {
+ if (matchMagicRule(m_cacheFile.get(), numMatchlets, firstMatchletOffset, data)) {
const int mimeTypeOffset = m_cacheFile->getUint32(off + 4);
const char *mimeType = m_cacheFile->getCharStar(mimeTypeOffset);
- *accuracyPtr = m_cacheFile->getUint32(off);
- // Return the first match. We have no rules for conflicting magic data...
- // (mime.cache itself is sorted, but what about local overrides with a lower prio?)
- candidate = mimeTypeForNameUnchecked(QLatin1StringView(mimeType));
- return;
+ const int accuracy = static_cast<int>(m_cacheFile->getUint32(off));
+ if (accuracy > result.accuracy) {
+ result.accuracy = accuracy;
+ result.candidate = QString::fromLatin1(mimeType);
+ // Return the first match, mime.cache is sorted
+ return;
+ }
}
}
}
@@ -371,8 +397,7 @@ void QMimeBinaryProvider::addParents(const QString &mime, QStringList &result)
const int parentOffset = m_cacheFile->getUint32(parentsOffset + 4 + 4 * i);
const char *aParent = m_cacheFile->getCharStar(parentOffset);
const QString strParent = QString::fromLatin1(aParent);
- if (!result.contains(strParent))
- result.append(strParent);
+ appendIfNew(result, strParent);
}
break;
}
@@ -419,8 +444,7 @@ void QMimeBinaryProvider::addAliases(const QString &name, QStringList &result)
const int aliasOffset = m_cacheFile->getUint32(off);
const char *alias = m_cacheFile->getCharStar(aliasOffset);
const QString strAlias = QString::fromLatin1(alias);
- if (!result.contains(strAlias))
- result.append(strAlias);
+ appendIfNew(result, strAlias);
}
}
}
@@ -432,13 +456,14 @@ void QMimeBinaryProvider::loadMimeTypeList()
m_mimetypeNames.clear();
// Unfortunately mime.cache doesn't have a full list of all mimetypes.
// So we have to parse the plain-text files called "types".
- QFile file(m_directory + QStringLiteral("/types"));
+ QFile file(m_directory + QStringView(u"/types"));
if (file.open(QIODevice::ReadOnly)) {
while (!file.atEnd()) {
- QByteArray line = file.readLine();
- if (line.endsWith('\n'))
- line.chop(1);
- m_mimetypeNames.insert(QString::fromLatin1(line));
+ const QByteArray line = file.readLine();
+ auto lineView = QByteArrayView(line);
+ if (lineView.endsWith('\n'))
+ lineView.chop(1);
+ m_mimetypeNames.insert(QString::fromLatin1(lineView));
}
}
}
@@ -450,53 +475,70 @@ void QMimeBinaryProvider::addAllMimeTypes(QList<QMimeType> &result)
if (result.isEmpty()) {
result.reserve(m_mimetypeNames.size());
for (const QString &name : std::as_const(m_mimetypeNames))
- result.append(mimeTypeForNameUnchecked(name));
+ result.append(QMimeType(QMimeTypePrivate(name)));
} else {
for (const QString &name : std::as_const(m_mimetypeNames))
if (std::find_if(result.constBegin(), result.constEnd(), [name](const QMimeType &mime) -> bool { return mime.name() == name; })
== result.constEnd())
- result.append(mimeTypeForNameUnchecked(name));
+ result.append(QMimeType(QMimeTypePrivate(name)));
}
}
-bool QMimeBinaryProvider::loadMimeTypePrivate(QMimeTypePrivate &data)
+QMimeTypePrivate::LocaleHash QMimeBinaryProvider::localeComments(const QString &name)
{
-#ifdef QT_NO_XMLSTREAMREADER
- Q_UNUSED(data);
- qWarning("Cannot load mime type since QXmlStreamReader is not available.");
- return false;
-#else
- if (data.loaded)
- return true;
+ MimeTypeExtraMap::const_iterator it = loadMimeTypeExtra(name);
+ if (it != m_mimetypeExtra.cend())
+ return it->second.localeComments;
+ return {};
+}
+
+bool QMimeBinaryProvider::hasGlobDeleteAll(const QString &name)
+{
+ MimeTypeExtraMap::const_iterator it = loadMimeTypeExtra(name);
+ if (it != m_mimetypeExtra.cend())
+ return it->second.hasGlobDeleteAll;
+ return {};
+}
+
+QStringList QMimeBinaryProvider::globPatterns(const QString &name)
+{
+ MimeTypeExtraMap::const_iterator it = loadMimeTypeExtra(name);
+ if (it != m_mimetypeExtra.cend())
+ return it->second.globPatterns;
+ return {};
+}
- auto it = m_mimetypeExtra.constFind(data.name);
- if (it == m_mimetypeExtra.constEnd()) {
+QMimeBinaryProvider::MimeTypeExtraMap::const_iterator
+QMimeBinaryProvider::loadMimeTypeExtra(const QString &mimeName)
+{
+#if QT_CONFIG(xmlstreamreader)
+ auto it = m_mimetypeExtra.find(mimeName);
+ if (it == m_mimetypeExtra.cend()) {
// load comment and globPatterns
// shared-mime-info since 1.3 lowercases the xml files
- QString mimeFile = m_directory + u'/' + data.name.toLower() + ".xml"_L1;
+ QString mimeFile = m_directory + u'/' + mimeName.toLower() + ".xml"_L1;
if (!QFile::exists(mimeFile))
- mimeFile = m_directory + u'/' + data.name + ".xml"_L1; // pre-1.3
+ mimeFile = m_directory + u'/' + mimeName + ".xml"_L1; // pre-1.3
QFile qfile(mimeFile);
if (!qfile.open(QFile::ReadOnly))
- return false;
+ return m_mimetypeExtra.cend();
- auto insertIt = m_mimetypeExtra.insert(data.name, MimeTypeExtra{});
- it = insertIt;
- MimeTypeExtra &extra = insertIt.value();
+ it = m_mimetypeExtra.try_emplace(mimeName).first;
+ MimeTypeExtra &extra = it->second;
QString mainPattern;
QXmlStreamReader xml(&qfile);
if (xml.readNextStartElement()) {
if (xml.name() != "mime-type"_L1) {
- return false;
+ return m_mimetypeExtra.cend();
}
const auto name = xml.attributes().value("type"_L1);
if (name.isEmpty())
- return false;
- if (name.compare(data.name, Qt::CaseInsensitive))
- qWarning() << "Got name" << name << "in file" << mimeFile << "expected" << data.name;
+ return m_mimetypeExtra.cend();
+ if (name.compare(mimeName, Qt::CaseInsensitive))
+ qWarning() << "Got name" << name << "in file" << mimeFile << "expected" << mimeName;
while (xml.readNextStartElement()) {
const auto tag = xml.name();
@@ -509,15 +551,13 @@ bool QMimeBinaryProvider::loadMimeTypePrivate(QMimeTypePrivate &data)
extra.localeComments.insert(lang, text);
continue; // we called readElementText, so we're at the EndElement already.
} else if (tag == "glob-deleteall"_L1) { // as written out by shared-mime-info >= 0.70
- extra.globPatterns.clear();
- mainPattern.clear();
+ extra.hasGlobDeleteAll = true;
} else if (tag == "glob"_L1) { // as written out by shared-mime-info >= 0.70
const QString pattern = xml.attributes().value("pattern"_L1).toString();
if (mainPattern.isEmpty() && pattern.startsWith(u'*')) {
mainPattern = pattern;
}
- if (!extra.globPatterns.contains(pattern))
- extra.globPatterns.append(pattern);
+ appendIfNew(extra.globPatterns, pattern);
}
xml.skipCurrentElement();
}
@@ -533,11 +573,12 @@ bool QMimeBinaryProvider::loadMimeTypePrivate(QMimeTypePrivate &data)
extra.globPatterns.prepend(mainPattern);
}
}
- const MimeTypeExtra &e = it.value();
- data.localeComments = e.localeComments;
- data.globPatterns = e.globPatterns;
- return true;
-#endif //QT_NO_XMLSTREAMREADER
+ return it;
+#else
+ Q_UNUSED(mimeName);
+ qWarning("Cannot load mime type since QXmlStreamReader is not available.");
+ return m_mimetypeExtra.cend();
+#endif // feature xmlstreamreader
}
// Binary search in the icons or generic-icons list
@@ -566,22 +607,16 @@ QLatin1StringView QMimeBinaryProvider::iconForMime(CacheFile *cacheFile, int pos
return QLatin1StringView();
}
-void QMimeBinaryProvider::loadIcon(QMimeTypePrivate &data)
+QString QMimeBinaryProvider::icon(const QString &name)
{
- const QByteArray inputMime = data.name.toLatin1();
- const QLatin1StringView icon = iconForMime(m_cacheFile, PosIconsListOffset, inputMime);
- if (!icon.isEmpty()) {
- data.iconName = icon;
- }
+ const QByteArray inputMime = name.toLatin1();
+ return iconForMime(m_cacheFile.get(), PosIconsListOffset, inputMime);
}
-void QMimeBinaryProvider::loadGenericIcon(QMimeTypePrivate &data)
+QString QMimeBinaryProvider::genericIcon(const QString &name)
{
- const QByteArray inputMime = data.name.toLatin1();
- const QLatin1StringView icon = iconForMime(m_cacheFile, PosGenericIconsListOffset, inputMime);
- if (!icon.isEmpty()) {
- data.genericIconName = icon;
- }
+ const QByteArray inputMime = name.toLatin1();
+ return iconForMime(m_cacheFile.get(), PosGenericIconsListOffset, inputMime);
}
////
@@ -666,38 +701,34 @@ bool QMimeXMLProvider::isInternalDatabase() const
#endif
}
-QMimeType QMimeXMLProvider::mimeTypeForName(const QString &name)
+bool QMimeXMLProvider::knowsMimeType(const QString &name)
{
- return m_nameMimeTypeMap.value(name);
+ return m_nameMimeTypeMap.contains(name);
}
void QMimeXMLProvider::addFileNameMatches(const QString &fileName, QMimeGlobMatchResult &result)
{
- m_mimeTypeGlobs.matchingGlobs(fileName, result);
+ auto filterFunc = [this](const QString &name) { return !isMimeTypeGlobsExcluded(name); };
+ m_mimeTypeGlobs.matchingGlobs(fileName, result, filterFunc);
}
-void QMimeXMLProvider::findByMagic(const QByteArray &data, int *accuracyPtr, QMimeType &candidate)
+void QMimeXMLProvider::findByMagic(const QByteArray &data, QMimeMagicResult &result)
{
- QString candidateName;
- bool foundOne = false;
for (const QMimeMagicRuleMatcher &matcher : std::as_const(m_magicMatchers)) {
if (matcher.matches(data)) {
const int priority = matcher.priority();
- if (priority > *accuracyPtr) {
- *accuracyPtr = priority;
- candidateName = matcher.mimetype();
- foundOne = true;
+ if (priority > result.accuracy) {
+ result.accuracy = priority;
+ result.candidate = matcher.mimetype();
}
}
}
- if (foundOne)
- candidate = mimeTypeForName(candidateName);
}
void QMimeXMLProvider::ensureLoaded()
{
QStringList allFiles;
- const QString packageDir = m_directory + QStringLiteral("/packages");
+ const QString packageDir = m_directory + QStringView(u"/packages");
QDir dir(packageDir);
const QStringList files = dir.entryList(QDir::Files | QDir::NoDotAndDotDot);
allFiles.reserve(files.size());
@@ -720,6 +751,31 @@ void QMimeXMLProvider::ensureLoaded()
load(file);
}
+QMimeTypePrivate::LocaleHash QMimeXMLProvider::localeComments(const QString &name)
+{
+ return m_nameMimeTypeMap.value(name).localeComments;
+}
+
+bool QMimeXMLProvider::hasGlobDeleteAll(const QString &name)
+{
+ return m_nameMimeTypeMap.value(name).hasGlobDeleteAll;
+}
+
+QStringList QMimeXMLProvider::globPatterns(const QString &name)
+{
+ return m_nameMimeTypeMap.value(name).globPatterns;
+}
+
+QString QMimeXMLProvider::icon(const QString &name)
+{
+ return m_nameMimeTypeMap.value(name).iconName;
+}
+
+QString QMimeXMLProvider::genericIcon(const QString &name)
+{
+ return m_nameMimeTypeMap.value(name).genericIconName;
+}
+
void QMimeXMLProvider::load(const QString &fileName)
{
QString errorMessage;
@@ -761,10 +817,9 @@ void QMimeXMLProvider::addGlobPattern(const QMimeGlobPattern &glob)
m_mimeTypeGlobs.addGlob(glob);
}
-void QMimeXMLProvider::addMimeType(const QMimeType &mt)
+void QMimeXMLProvider::addMimeType(const QMimeTypeXMLData &mt)
{
- Q_ASSERT(!mt.d.data()->fromCache);
- m_nameMimeTypeMap.insert(mt.name(), mt);
+ m_nameMimeTypeMap.insert(mt.name, mt);
}
void QMimeXMLProvider::addParents(const QString &mime, QStringList &result)
@@ -783,13 +838,10 @@ void QMimeXMLProvider::addParent(const QString &child, const QString &parent)
void QMimeXMLProvider::addAliases(const QString &name, QStringList &result)
{
// Iterate through the whole hash. This method is rarely used.
- for (auto it = m_aliases.constBegin(), end = m_aliases.constEnd() ; it != end ; ++it) {
- if (it.value() == name) {
- if (!result.contains(it.key()))
- result.append(it.key());
- }
+ for (const auto &[alias, mimeName] : std::as_const(m_aliases).asKeyValueRange()) {
+ if (mimeName == name)
+ appendIfNew(result, alias);
}
-
}
QString QMimeXMLProvider::resolveAlias(const QString &name)
@@ -805,13 +857,16 @@ void QMimeXMLProvider::addAlias(const QString &alias, const QString &name)
void QMimeXMLProvider::addAllMimeTypes(QList<QMimeType> &result)
{
if (result.isEmpty()) { // fast path
- result = m_nameMimeTypeMap.values();
+ for (auto it = m_nameMimeTypeMap.constBegin(), end = m_nameMimeTypeMap.constEnd();
+ it != end; ++it) {
+ result.append(QMimeType(QMimeTypePrivate(it.value().name)));
+ }
} else {
for (auto it = m_nameMimeTypeMap.constBegin(), end = m_nameMimeTypeMap.constEnd() ; it != end ; ++it) {
const QString newMime = it.key();
if (std::find_if(result.constBegin(), result.constEnd(), [newMime](const QMimeType &mime) -> bool { return mime.name() == newMime; })
== result.constEnd())
- result.append(it.value());
+ result.append(QMimeType(QMimeTypePrivate(it.value().name)));
}
}
}
diff --git a/src/corelib/mimetypes/qmimeprovider_p.h b/src/corelib/mimetypes/qmimeprovider_p.h
index f5cc7bc3c0..3ded01cd46 100644
--- a/src/corelib/mimetypes/qmimeprovider_p.h
+++ b/src/corelib/mimetypes/qmimeprovider_p.h
@@ -23,36 +23,56 @@ QT_REQUIRE_CONFIG(mimetype);
#include "qmimeglobpattern_p.h"
#include <QtCore/qdatetime.h>
#include <QtCore/qset.h>
-#include <QtCore/qmap.h>
+
+#include <map>
QT_BEGIN_NAMESPACE
class QMimeMagicRuleMatcher;
+class QMimeTypeXMLData;
+class QMimeProviderBase;
+
+struct QMimeMagicResult
+{
+ bool isValid() const { return !candidate.isEmpty(); }
+
+ QString candidate;
+ int accuracy = 0;
+};
class QMimeProviderBase
{
+ Q_DISABLE_COPY(QMimeProviderBase)
+
public:
QMimeProviderBase(QMimeDatabasePrivate *db, const QString &directory);
virtual ~QMimeProviderBase() {}
virtual bool isValid() = 0;
virtual bool isInternalDatabase() const = 0;
- virtual QMimeType mimeTypeForName(const QString &name) = 0;
+ virtual bool knowsMimeType(const QString &name) = 0;
virtual void addFileNameMatches(const QString &fileName, QMimeGlobMatchResult &result) = 0;
virtual void addParents(const QString &mime, QStringList &result) = 0;
virtual QString resolveAlias(const QString &name) = 0;
virtual void addAliases(const QString &name, QStringList &result) = 0;
- virtual void findByMagic(const QByteArray &data, int *accuracyPtr, QMimeType &candidate) = 0;
+ virtual void findByMagic(const QByteArray &data, QMimeMagicResult &result) = 0;
virtual void addAllMimeTypes(QList<QMimeType> &result) = 0;
- virtual bool loadMimeTypePrivate(QMimeTypePrivate &) { return false; }
- virtual void loadIcon(QMimeTypePrivate &) {}
- virtual void loadGenericIcon(QMimeTypePrivate &) {}
- virtual void ensureLoaded() {}
+ virtual QMimeTypePrivate::LocaleHash localeComments(const QString &name) = 0;
+ virtual bool hasGlobDeleteAll(const QString &name) = 0;
+ virtual QStringList globPatterns(const QString &name) = 0;
+ virtual QString icon(const QString &name) = 0;
+ virtual QString genericIcon(const QString &name) = 0;
+ virtual void ensureLoaded() { }
QString directory() const { return m_directory; }
+ QMimeProviderBase *overrideProvider() const;
+ void setOverrideProvider(QMimeProviderBase *provider);
+ bool isMimeTypeGlobsExcluded(const QString &name) const;
+
QMimeDatabasePrivate *m_db;
QString m_directory;
+ QMimeProviderBase *m_overrideProvider = nullptr; // more "local" than this one
};
/*
@@ -66,29 +86,35 @@ public:
bool isValid() override;
bool isInternalDatabase() const override;
- QMimeType mimeTypeForName(const QString &name) override;
+ bool knowsMimeType(const QString &name) override;
void addFileNameMatches(const QString &fileName, QMimeGlobMatchResult &result) override;
void addParents(const QString &mime, QStringList &result) override;
QString resolveAlias(const QString &name) override;
void addAliases(const QString &name, QStringList &result) override;
- void findByMagic(const QByteArray &data, int *accuracyPtr, QMimeType &candidate) override;
+ void findByMagic(const QByteArray &data, QMimeMagicResult &result) override;
void addAllMimeTypes(QList<QMimeType> &result) override;
- bool loadMimeTypePrivate(QMimeTypePrivate &) override;
- void loadIcon(QMimeTypePrivate &) override;
- void loadGenericIcon(QMimeTypePrivate &) override;
+ QMimeTypePrivate::LocaleHash localeComments(const QString &name) override;
+ bool hasGlobDeleteAll(const QString &name) override;
+ QStringList globPatterns(const QString &name) override;
+ QString icon(const QString &name) override;
+ QString genericIcon(const QString &name) override;
void ensureLoaded() override;
private:
struct CacheFile;
- void matchGlobList(QMimeGlobMatchResult &result, CacheFile *cacheFile, int offset, const QString &fileName);
- bool matchSuffixTree(QMimeGlobMatchResult &result, CacheFile *cacheFile, int numEntries, int firstOffset, const QString &fileName, int charPos, bool caseSensitiveCheck);
- bool matchMagicRule(CacheFile *cacheFile, int numMatchlets, int firstOffset, const QByteArray &data);
+ int matchGlobList(QMimeGlobMatchResult &result, CacheFile *cacheFile, int offset,
+ const QString &fileName);
+ bool matchSuffixTree(QMimeGlobMatchResult &result, CacheFile *cacheFile, int numEntries,
+ int firstOffset, const QString &fileName, qsizetype charPos,
+ bool caseSensitiveCheck);
+ bool matchMagicRule(CacheFile *cacheFile, int numMatchlets, int firstOffset,
+ const QByteArray &data);
QLatin1StringView iconForMime(CacheFile *cacheFile, int posListOffset, const QByteArray &inputMime);
void loadMimeTypeList();
bool checkCacheChanged();
- CacheFile *m_cacheFile = nullptr;
+ std::unique_ptr<CacheFile> m_cacheFile;
QStringList m_cacheFileNames;
QSet<QString> m_mimetypeNames;
bool m_mimetypeListLoaded;
@@ -96,8 +122,12 @@ private:
{
QHash<QString, QString> localeComments;
QStringList globPatterns;
+ bool hasGlobDeleteAll = false;
};
- QMap<QString, MimeTypeExtra> m_mimetypeExtra;
+ using MimeTypeExtraMap = std::map<QString, MimeTypeExtra>;
+ MimeTypeExtraMap m_mimetypeExtra;
+
+ MimeTypeExtraMap::const_iterator loadMimeTypeExtra(const QString &mimeName);
};
/*
@@ -118,19 +148,24 @@ public:
bool isValid() override;
bool isInternalDatabase() const override;
- QMimeType mimeTypeForName(const QString &name) override;
+ bool knowsMimeType(const QString &name) override;
void addFileNameMatches(const QString &fileName, QMimeGlobMatchResult &result) override;
void addParents(const QString &mime, QStringList &result) override;
QString resolveAlias(const QString &name) override;
void addAliases(const QString &name, QStringList &result) override;
- void findByMagic(const QByteArray &data, int *accuracyPtr, QMimeType &candidate) override;
+ void findByMagic(const QByteArray &data, QMimeMagicResult &result) override;
void addAllMimeTypes(QList<QMimeType> &result) override;
void ensureLoaded() override;
+ QMimeTypePrivate::LocaleHash localeComments(const QString &name) override;
+ bool hasGlobDeleteAll(const QString &name) override;
+ QStringList globPatterns(const QString &name) override;
+ QString icon(const QString &name) override;
+ QString genericIcon(const QString &name) override;
bool load(const QString &fileName, QString *errorMessage);
// Called by the mimetype xml parser
- void addMimeType(const QMimeType &mt);
+ void addMimeType(const QMimeTypeXMLData &mt);
void addGlobPattern(const QMimeGlobPattern &glob);
void addParent(const QString &child, const QString &parent);
void addAlias(const QString &alias, const QString &name);
@@ -140,7 +175,7 @@ private:
void load(const QString &fileName);
void load(const char *data, qsizetype len);
- typedef QHash<QString, QMimeType> NameMimeTypeMap;
+ typedef QHash<QString, QMimeTypeXMLData> NameMimeTypeMap;
NameMimeTypeMap m_nameMimeTypeMap;
typedef QHash<QString, QString> AliasHash;
diff --git a/src/corelib/mimetypes/qmimetype.cpp b/src/corelib/mimetypes/qmimetype.cpp
index cf153fd8d5..e26c8b898d 100644
--- a/src/corelib/mimetypes/qmimetype.cpp
+++ b/src/corelib/mimetypes/qmimetype.cpp
@@ -6,9 +6,6 @@
#include "qmimetype_p.h"
#include "qmimedatabase_p.h"
-#include "qmimeprovider_p.h"
-
-#include "qmimeglobpattern_p.h"
#include <QtCore/QDebug>
#include <QtCore/QLocale>
@@ -20,33 +17,6 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-QMimeTypePrivate::QMimeTypePrivate()
- : loaded(false), fromCache(false)
-{}
-
-QMimeTypePrivate::QMimeTypePrivate(const QMimeType &other)
- : loaded(other.d->loaded),
- name(other.d->name),
- localeComments(other.d->localeComments),
- genericIconName(other.d->genericIconName),
- iconName(other.d->iconName),
- globPatterns(other.d->globPatterns)
-{}
-
-void QMimeTypePrivate::clear()
-{
- name.clear();
- localeComments.clear();
- genericIconName.clear();
- iconName.clear();
- globPatterns.clear();
-}
-
-void QMimeTypePrivate::addGlobPattern(const QString &pattern)
-{
- globPatterns.append(pattern);
-}
-
/*!
\class QMimeType
\inmodule QtCore
@@ -54,6 +24,7 @@ void QMimeTypePrivate::addGlobPattern(const QString &pattern)
\brief The QMimeType class describes types of file or data, represented by a MIME type string.
\since 5.0
+ \compares equality
For instance a file named "readme.txt" has the MIME type "text/plain".
The MIME type can be determined from the file name, or from the file
@@ -70,7 +41,7 @@ void QMimeTypePrivate::addGlobPattern(const QString &pattern)
MIME types can inherit from each other: for instance a C source file is
a specific type of plain text file, so text/x-csrc inherits text/plain.
- \sa QMimeDatabase, {MIME Type Browser Example}
+ \sa QMimeDatabase, {MIME Type Browser}
*/
/*!
@@ -141,14 +112,15 @@ QMimeType::~QMimeType()
}
/*!
- \fn bool QMimeType::operator==(const QMimeType &other) const;
- Returns \c true if \a other equals this QMimeType object, otherwise returns \c false.
+ \fn bool QMimeType::operator==(const QMimeType &lhs, const QMimeType &rhs);
+ Returns \c true if \a lhs equals to the \a rhs QMimeType object, otherwise
+ returns \c false.
The name is the unique identifier for a mimetype, so two mimetypes with
the same name, are equal.
*/
-bool QMimeType::operator==(const QMimeType &other) const
+bool comparesEqual(const QMimeType &lhs, const QMimeType &rhs) noexcept
{
- return d == other.d || d->name == other.d->name;
+ return lhs.d == rhs.d || lhs.d->name == rhs.d->name;
}
/*!
@@ -164,8 +136,9 @@ size_t qHash(const QMimeType &key, size_t seed) noexcept
}
/*!
- \fn bool QMimeType::operator!=(const QMimeType &other) const;
- Returns \c true if \a other does not equal this QMimeType object, otherwise returns \c false.
+ \fn bool QMimeType::operator!=(const QMimeType &lhs, const QMimeType &rhs);
+ Returns \c true if QMimeType \a lhs is not equal to QMimeType \a rhs,
+ otherwise returns \c false.
*/
/*!
@@ -219,24 +192,38 @@ QString QMimeType::name() const
*/
QString QMimeType::comment() const
{
- QMimeDatabasePrivate::instance()->loadMimeTypePrivate(const_cast<QMimeTypePrivate&>(*d));
+ const auto localeComments = QMimeDatabasePrivate::instance()->localeComments(d->name);
+
+ QStringList languageList = QLocale().uiLanguages(QLocale::TagSeparator::Underscore);
+ qsizetype defaultIndex = languageList.indexOf(u"en_US"_s);
+
+ // Include the default locale as fall-back.
+ if (defaultIndex >= 0) {
+ // en_US is generally the default, and may be omitted from the
+ // overtly-named locales in the MIME type's data (QTBUG-105007).
+ ++defaultIndex; // Skip over en_US.
+ // That's typically followed by en_Latn_US and en (in that order):
+ if (defaultIndex < languageList.size() && languageList.at(defaultIndex) == u"en_Latn_US")
+ ++defaultIndex;
+ if (defaultIndex < languageList.size() && languageList.at(defaultIndex) == u"en")
+ ++defaultIndex;
+ } else {
+ // Absent en-US, just append it:
+ defaultIndex = languageList.size();
+ }
+ languageList.insert(defaultIndex, u"default"_s);
- QStringList languageList;
- languageList << QLocale().name();
- languageList << QLocale().uiLanguages();
- languageList << u"default"_s; // use the default locale if possible.
for (const QString &language : std::as_const(languageList)) {
const QString lang = language == "C"_L1 ? u"en_US"_s : language;
- const QString comm = d->localeComments.value(lang);
+ QString comm = localeComments.value(lang);
if (!comm.isEmpty())
return comm;
- const qsizetype pos = lang.indexOf(u'_');
- if (pos != -1) {
- // "pt_BR" not found? try just "pt"
- const QString shortLang = lang.left(pos);
- const QString commShort = d->localeComments.value(shortLang);
- if (!commShort.isEmpty())
- return commShort;
+ const qsizetype cut = lang.indexOf(u'_');
+ // If "de_CH" is missing, check for "de" (and similar):
+ if (cut != -1) {
+ comm = localeComments.value(lang.left(cut));
+ if (!comm.isEmpty())
+ return comm;
}
}
@@ -260,8 +247,8 @@ QString QMimeType::comment() const
*/
QString QMimeType::genericIconName() const
{
- QMimeDatabasePrivate::instance()->loadGenericIcon(const_cast<QMimeTypePrivate&>(*d));
- if (d->genericIconName.isEmpty()) {
+ QString genericIconName = QMimeDatabasePrivate::instance()->genericIcon(d->name);
+ if (genericIconName.isEmpty()) {
// From the spec:
// If the generic icon name is empty (not specified by the mimetype definition)
// then the mimetype is used to generate the generic icon by using the top-level
@@ -274,7 +261,7 @@ QString QMimeType::genericIconName() const
groupRef = groupRef.left(slashindex);
return groupRef + "-x-generic"_L1;
}
- return d->genericIconName;
+ return genericIconName;
}
static QString make_default_icon_name_from_mimetype_name(QString iconName)
@@ -296,11 +283,11 @@ static QString make_default_icon_name_from_mimetype_name(QString iconName)
*/
QString QMimeType::iconName() const
{
- QMimeDatabasePrivate::instance()->loadIcon(const_cast<QMimeTypePrivate&>(*d));
- if (d->iconName.isEmpty()) {
+ QString iconName = QMimeDatabasePrivate::instance()->icon(d->name);
+ if (iconName.isEmpty()) {
return make_default_icon_name_from_mimetype_name(name());
}
- return d->iconName;
+ return iconName;
}
/*!
@@ -312,8 +299,7 @@ QString QMimeType::iconName() const
*/
QStringList QMimeType::globPatterns() const
{
- QMimeDatabasePrivate::instance()->loadMimeTypePrivate(const_cast<QMimeTypePrivate&>(*d));
- return d->globPatterns;
+ return QMimeDatabasePrivate::instance()->globPatterns(d->name);
}
/*!
@@ -342,14 +328,17 @@ QStringList QMimeType::parentMimeTypes() const
static void collectParentMimeTypes(const QString &mime, QStringList &allParents)
{
const QStringList parents = QMimeDatabasePrivate::instance()->mimeParents(mime);
+ QStringList newParents;
for (const QString &parent : parents) {
// I would use QSet, but since order matters I better not
- if (!allParents.contains(parent))
+ if (!allParents.contains(parent)) {
allParents.append(parent);
+ newParents.append(parent);
+ }
}
// We want a breadth-first search, so that the least-specific parent (octet-stream) is last
// This means iterating twice, unfortunately.
- for (const QString &parent : parents)
+ for (const QString &parent : newParents)
collectParentMimeTypes(parent, allParents);
}
@@ -407,10 +396,11 @@ QStringList QMimeType::aliases() const
*/
QStringList QMimeType::suffixes() const
{
- QMimeDatabasePrivate::instance()->loadMimeTypePrivate(const_cast<QMimeTypePrivate&>(*d));
+ const QStringList patterns = globPatterns();
QStringList result;
- for (const QString &pattern : std::as_const(d->globPatterns)) {
+ result.reserve(patterns.size());
+ for (const QString &pattern : patterns) {
// Not a simple suffix if it looks like: README or *. or *.* or *.JP*G or *.JP?
if (pattern.startsWith("*."_L1) &&
pattern.size() > 2 &&
@@ -450,17 +440,11 @@ QString QMimeType::preferredSuffix() const
*/
QString QMimeType::filterString() const
{
- QMimeDatabasePrivate::instance()->loadMimeTypePrivate(const_cast<QMimeTypePrivate&>(*d));
+ const QStringList patterns = globPatterns();
QString filter;
- if (!d->globPatterns.empty()) {
- filter += comment() + " ("_L1;
- for (int i = 0; i < d->globPatterns.size(); ++i) {
- if (i != 0)
- filter += u' ';
- filter += d->globPatterns.at(i);
- }
- filter += u')';
+ if (!patterns.isEmpty()) {
+ filter = comment() + " ("_L1 + patterns.join(u' ') + u')';
}
return filter;
diff --git a/src/corelib/mimetypes/qmimetype.h b/src/corelib/mimetypes/qmimetype.h
index 3421638f5b..508a5cfb53 100644
--- a/src/corelib/mimetypes/qmimetype.h
+++ b/src/corelib/mimetypes/qmimetype.h
@@ -49,14 +49,14 @@ public:
}
explicit QMimeType(const QMimeTypePrivate &dd);
~QMimeType();
-
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QMimeType &other) const;
inline bool operator!=(const QMimeType &other) const
{
return !operator==(other);
}
-
+#endif
bool isValid() const;
bool isDefault() const;
@@ -86,6 +86,10 @@ protected:
friend Q_CORE_EXPORT size_t qHash(const QMimeType &key, size_t seed) noexcept;
QExplicitlySharedDataPointer<QMimeTypePrivate> d;
+
+private:
+ friend Q_CORE_EXPORT bool comparesEqual(const QMimeType &lhs, const QMimeType &rhs) noexcept;
+ Q_DECLARE_EQUALITY_COMPARABLE(QMimeType)
};
Q_DECLARE_SHARED(QMimeType)
diff --git a/src/corelib/mimetypes/qmimetype_p.h b/src/corelib/mimetypes/qmimetype_p.h
index 232c36c38e..b6040098a9 100644
--- a/src/corelib/mimetypes/qmimetype_p.h
+++ b/src/corelib/mimetypes/qmimetype_p.h
@@ -16,13 +16,14 @@
//
#include <QtCore/private/qglobal_p.h>
-#include "qmimetype.h"
+#include <QtCore/qshareddata.h>
QT_REQUIRE_CONFIG(mimetype);
#include <QtCore/qhash.h>
#include <QtCore/qstringlist.h>
+class QMimeBinaryProvider;
QT_BEGIN_NAMESPACE
class Q_AUTOTEST_EXPORT QMimeTypePrivate : public QSharedData
@@ -30,41 +31,12 @@ class Q_AUTOTEST_EXPORT QMimeTypePrivate : public QSharedData
public:
typedef QHash<QString, QString> LocaleHash;
- QMimeTypePrivate();
- explicit QMimeTypePrivate(const QMimeType &other);
+ QMimeTypePrivate() { }
+ explicit QMimeTypePrivate(const QString &name) : name(name) { }
- void clear();
-
- void addGlobPattern(const QString &pattern);
-
- bool loaded; // QSharedData leaves a 4 byte gap, so don't put 8 byte members first
- bool fromCache; // true if this comes from the binary provider
QString name;
- LocaleHash localeComments;
- QString genericIconName;
- QString iconName;
- QStringList globPatterns;
};
QT_END_NAMESPACE
-#define QMIMETYPE_BUILDER_FROM_RVALUE_REFS \
- QT_BEGIN_NAMESPACE \
- static QMimeType buildQMimeType ( \
- QString &&name, \
- QString &&genericIconName, \
- QString &&iconName, \
- QStringList &&globPatterns \
- ) \
- { \
- QMimeTypePrivate qMimeTypeData; \
- qMimeTypeData.loaded = true; \
- qMimeTypeData.name = std::move(name); \
- qMimeTypeData.genericIconName = std::move(genericIconName); \
- qMimeTypeData.iconName = std::move(iconName); \
- qMimeTypeData.globPatterns = std::move(globPatterns); \
- return QMimeType(qMimeTypeData); \
- } \
- QT_END_NAMESPACE
-
-#endif // QMIMETYPE_P_H
+#endif // QMIMETYPE_P_H
diff --git a/src/corelib/mimetypes/qmimetypeparser.cpp b/src/corelib/mimetypes/qmimetypeparser.cpp
index 349313a01d..3f1e53b25d 100644
--- a/src/corelib/mimetypes/qmimetypeparser.cpp
+++ b/src/corelib/mimetypes/qmimetypeparser.cpp
@@ -139,7 +139,7 @@ bool QMimeTypeParserBase::parseNumber(QStringView n, int *target, QString *error
return true;
}
-#ifndef QT_NO_XMLSTREAMREADER
+#if QT_CONFIG(xmlstreamreader)
struct CreateMagicMatchRuleResult
{
QString errorMessage; // must be first
@@ -160,18 +160,12 @@ static CreateMagicMatchRuleResult createMagicMatchRule(const QXmlStreamAttribute
const auto mask = atts.value(QLatin1StringView(matchMaskAttributeC));
return CreateMagicMatchRuleResult(type, value, offsets, mask);
}
-#endif
+#endif // feature xmlstreamreader
bool QMimeTypeParserBase::parse(QIODevice *dev, const QString &fileName, QString *errorMessage)
{
-#ifdef QT_NO_XMLSTREAMREADER
- Q_UNUSED(dev);
- if (errorMessage)
- *errorMessage = QString::fromLatin1("QXmlStreamReader is not available, cannot parse '%1'.").arg(fileName);
- return false;
-#else
- QMimeTypePrivate data;
- data.loaded = true;
+#if QT_CONFIG(xmlstreamreader)
+ QMimeTypeXMLData data;
int priority = 50;
QStack<QMimeMagicRule *> currentRules; // stack for the nesting of rules
QList<QMimeMagicRule> rules; // toplevel rules
@@ -215,6 +209,7 @@ bool QMimeTypeParserBase::parse(QIODevice *dev, const QString &fileName, QString
break;
case ParseGlobDeleteAll:
data.globPatterns.clear();
+ data.hasGlobDeleteAll = true;
break;
case ParseSubClass: {
const QString inheritsFrom = atts.value(QLatin1StringView(mimeTypeAttributeC)).toString();
@@ -277,7 +272,7 @@ bool QMimeTypeParserBase::parse(QIODevice *dev, const QString &fileName, QString
{
const auto elementName = reader.name();
if (elementName == QLatin1StringView(mimeTypeTagC)) {
- if (!process(QMimeType(data), errorMessage))
+ if (!process(data, errorMessage))
return false;
data.clear();
} else if (elementName == QLatin1StringView(matchTagC)) {
@@ -310,7 +305,27 @@ bool QMimeTypeParserBase::parse(QIODevice *dev, const QString &fileName, QString
}
return true;
-#endif //QT_NO_XMLSTREAMREADER
+#else
+ Q_UNUSED(dev);
+ if (errorMessage)
+ *errorMessage = "QXmlStreamReader is not available, cannot parse '%1'."_L1.arg(fileName);
+ return false;
+#endif // feature xmlstreamreader
+}
+
+void QMimeTypeXMLData::clear()
+{
+ hasGlobDeleteAll = false;
+ name.clear();
+ localeComments.clear();
+ genericIconName.clear();
+ iconName.clear();
+ globPatterns.clear();
+}
+
+void QMimeTypeXMLData::addGlobPattern(const QString &pattern)
+{
+ globPatterns.append(pattern);
}
QT_END_NAMESPACE
diff --git a/src/corelib/mimetypes/qmimetypeparser_p.h b/src/corelib/mimetypes/qmimetypeparser_p.h
index c9698e149f..d4266ffcc0 100644
--- a/src/corelib/mimetypes/qmimetypeparser_p.h
+++ b/src/corelib/mimetypes/qmimetypeparser_p.h
@@ -16,7 +16,7 @@
// We mean it.
//
-#include "qmimedatabase_p.h"
+#include <QtCore/qtconfigmacros.h>
QT_REQUIRE_CONFIG(mimetype);
@@ -24,6 +24,21 @@ QT_REQUIRE_CONFIG(mimetype);
QT_BEGIN_NAMESPACE
+class QMimeTypeXMLData
+{
+public:
+ void clear();
+
+ void addGlobPattern(const QString &pattern);
+
+ bool hasGlobDeleteAll = false; // true if the mimetype has a glob-deleteall tag
+ QString name;
+ QMimeTypePrivate::LocaleHash localeComments;
+ QString genericIconName; // TODO move to a struct that's specific to the XML provider
+ QString iconName; // TODO move to a struct that's specific to the XML provider
+ QStringList globPatterns;
+};
+
class QIODevice;
class QMimeTypeParserBase
@@ -39,7 +54,7 @@ public:
static bool parseNumber(QStringView n, int *target, QString *errorMessage);
protected:
- virtual bool process(const QMimeType &t, QString *errorMessage) = 0;
+ virtual bool process(const QMimeTypeXMLData &t, QString *errorMessage) = 0;
virtual bool process(const QMimeGlobPattern &t, QString *errorMessage) = 0;
virtual void processParent(const QString &child, const QString &parent) = 0;
virtual void processAlias(const QString &alias, const QString &name) = 0;
@@ -73,7 +88,7 @@ public:
explicit QMimeTypeParser(QMimeXMLProvider &provider) : m_provider(provider) {}
protected:
- inline bool process(const QMimeType &t, QString *) override
+ inline bool process(const QMimeTypeXMLData &t, QString *) override
{ m_provider.addMimeType(t); return true; }
inline bool process(const QMimeGlobPattern &glob, QString *) override
diff --git a/src/corelib/platform/android/qandroidextras.cpp b/src/corelib/platform/android/qandroidextras.cpp
index 89b4bed283..aa0c3fd093 100644
--- a/src/corelib/platform/android/qandroidextras.cpp
+++ b/src/corelib/platform/android/qandroidextras.cpp
@@ -672,6 +672,45 @@ QAndroidBinder* QAndroidService::onBind(const QAndroidIntent &/*intent*/)
return nullptr;
}
+static jboolean onTransact(JNIEnv */*env*/, jclass /*cls*/, jlong id, jint code, jobject data,
+ jobject reply, jint flags)
+{
+ if (!id)
+ return false;
+
+ return reinterpret_cast<QAndroidBinder*>(id)->onTransact(
+ code, QAndroidParcel(data), QAndroidParcel(reply), QAndroidBinder::CallType(flags));
+}
+
+static void onServiceConnected(JNIEnv */*env*/, jclass /*cls*/, jlong id, jstring name,
+ jobject service)
+{
+ if (!id)
+ return;
+
+ return reinterpret_cast<QAndroidServiceConnection *>(id)->onServiceConnected(
+ QJniObject(name).toString(), QAndroidBinder(service));
+}
+
+static void onServiceDisconnected(JNIEnv */*env*/, jclass /*cls*/, jlong id, jstring name)
+{
+ if (!id)
+ return;
+
+ return reinterpret_cast<QAndroidServiceConnection *>(id)->onServiceDisconnected(
+ QJniObject(name).toString());
+}
+
+bool QtAndroidPrivate::registerExtrasNatives(QJniEnvironment &env)
+{
+ static const JNINativeMethod methods[] = {
+ {"onTransact", "(JILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void *)onTransact},
+ {"onServiceConnected", "(JLjava/lang/String;Landroid/os/IBinder;)V", (void *)onServiceConnected},
+ {"onServiceDisconnected", "(JLjava/lang/String;)V", (void *)onServiceDisconnected}
+ };
+
+ return env.registerNativeMethods("org/qtproject/qt/android/extras/QtNative", methods, 3);
+}
/*!
\class QAndroidIntent
@@ -1091,11 +1130,11 @@ requestPermissionsInternal(const QStringList &permissions)
// ### can we kick off all checkPermission()s, and whenAll() collect results?
for (const QString &permission : permissions)
result.push_back(QtAndroidPrivate::checkPermission(permission).result());
- return QtFuture::makeReadyFuture(std::as_const(result)); // as_const d/t QTBUG-109677
+ return QtFuture::makeReadyRangeFuture(result);
}
if (!QtAndroidPrivate::acquireAndroidDeadlockProtector())
- return QtFuture::makeReadyFuture(QtAndroidPrivate::Denied);
+ return QtFuture::makeReadyValueFuture(QtAndroidPrivate::Denied);
QSharedPointer<QPromise<QtAndroidPrivate::PermissionResult>> promise;
promise.reset(new QPromise<QtAndroidPrivate::PermissionResult>());
@@ -1145,7 +1184,7 @@ QtAndroidPrivate::requestPermissions(const QStringList &permissions)
{
// avoid the uneccessary call and response to an empty permission string
if (permissions.isEmpty())
- return QtFuture::makeReadyFuture(QtAndroidPrivate::Denied);
+ return QtFuture::makeReadyValueFuture(QtAndroidPrivate::Denied);
return requestPermissionsInternal(permissions);
}
@@ -1168,10 +1207,10 @@ QtAndroidPrivate::checkPermission(const QString &permission)
QJniObject::fromString(permission).object());
result = resultFromAndroid(res);
}
- return QtFuture::makeReadyFuture(result);
+ return QtFuture::makeReadyValueFuture(result);
}
-bool QtAndroidPrivate::registerPermissionNatives()
+bool QtAndroidPrivate::registerPermissionNatives(QJniEnvironment &env)
{
if (QtAndroidPrivate::androidSdkVersion() < 23)
return true;
@@ -1181,8 +1220,9 @@ bool QtAndroidPrivate::registerPermissionNatives()
reinterpret_cast<void *>(sendRequestPermissionsResult)
}};
- QJniEnvironment env;
return env.registerNativeMethods(qtNativeClassName, methods, 1);
}
QT_END_NAMESPACE
+
+#include "moc_qandroidextras_p.cpp"
diff --git a/src/corelib/platform/android/qandroidnativeinterface.cpp b/src/corelib/platform/android/qandroidnativeinterface.cpp
index 5b967f22bf..fc3a09c78b 100644
--- a/src/corelib/platform/android/qandroidnativeinterface.cpp
+++ b/src/corelib/platform/android/qandroidnativeinterface.cpp
@@ -46,9 +46,9 @@ Q_CONSTINIT static QBasicMutex g_pendingRunnablesMutex;
QT_DEFINE_NATIVE_INTERFACE(QAndroidApplication);
/*!
- \fn jobject QNativeInterface::QAndroidApplication::context()
+ \fn QJniObject QNativeInterface::QAndroidApplication::context()
- Returns the Android context as a \c jobject. The context is an \c Activity
+ Returns the Android context as a \c QJniObject. The context is an \c Activity
if the main activity object is valid. Otherwise, the context is a \c Service.
\since 6.2
@@ -68,7 +68,7 @@ QtJniTypes::Context QNativeInterface::QAndroidApplication::context()
*/
bool QNativeInterface::QAndroidApplication::isActivityContext()
{
- return QtAndroidPrivate::activity();
+ return QtAndroidPrivate::activity().isValid();
}
/*!
@@ -94,8 +94,7 @@ int QNativeInterface::QAndroidApplication::sdkVersion()
*/
void QNativeInterface::QAndroidApplication::hideSplashScreen(int duration)
{
- QJniObject::callStaticMethod<void>("org/qtproject/qt/android/QtNative",
- "hideSplashScreen", "(I)V", duration);
+ QtAndroidPrivate::activity().callMethod<void>("hideSplashScreen", duration);
}
/*!
@@ -231,11 +230,11 @@ static void runPendingCppRunnables(JNIEnv */*env*/, jobject /*obj*/)
}
#endif
-bool QtAndroidPrivate::registerNativeInterfaceNatives()
+bool QtAndroidPrivate::registerNativeInterfaceNatives(QJniEnvironment &env)
{
#if QT_CONFIG(future) && !defined(QT_NO_QOBJECT)
const JNINativeMethod methods = {"runPendingCppRunnables", "()V", (void *)runPendingCppRunnables};
- return QJniEnvironment().registerNativeMethods(qtNativeClassName, &methods, 1);
+ return env.registerNativeMethods(qtNativeClassName, &methods, 1);
#else
return true;
#endif
diff --git a/src/corelib/platform/darwin/qdarwinpermissionplugin_bluetooth.mm b/src/corelib/platform/darwin/qdarwinpermissionplugin_bluetooth.mm
index 01fb638283..0cd375561f 100644
--- a/src/corelib/platform/darwin/qdarwinpermissionplugin_bluetooth.mm
+++ b/src/corelib/platform/darwin/qdarwinpermissionplugin_bluetooth.mm
@@ -31,7 +31,8 @@
- (Qt::PermissionStatus)currentStatus
{
- switch (CBCentralManager.authorization) {
+ auto status = CBCentralManager.authorization;
+ switch (status) {
case CBManagerAuthorizationNotDetermined:
return Qt::PermissionStatus::Undetermined;
case CBManagerAuthorizationRestricted:
@@ -41,7 +42,8 @@
return Qt::PermissionStatus::Granted;
}
- Q_UNREACHABLE();
+ qCWarning(lcPermissions) << "Unknown permission status" << status << "detected in" << self;
+ return Qt::PermissionStatus::Denied;
}
- (void)requestPermission:(QPermission)permission withCallback:(PermissionCallback)callback
diff --git a/src/corelib/platform/darwin/qdarwinpermissionplugin_calendar.mm b/src/corelib/platform/darwin/qdarwinpermissionplugin_calendar.mm
index 79a85ef3d2..a3eddd6d8f 100644
--- a/src/corelib/platform/darwin/qdarwinpermissionplugin_calendar.mm
+++ b/src/corelib/platform/darwin/qdarwinpermissionplugin_calendar.mm
@@ -5,8 +5,6 @@
#include <EventKit/EventKit.h>
-QT_DEFINE_PERMISSION_STATUS_CONVERTER(EKAuthorizationStatus);
-
@interface QDarwinCalendarPermissionHandler ()
@property (nonatomic, retain) EKEventStore *eventStore;
@end
@@ -20,8 +18,24 @@ QT_DEFINE_PERMISSION_STATUS_CONVERTER(EKAuthorizationStatus);
- (Qt::PermissionStatus)currentStatus
{
- const auto status = [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent];
- return nativeStatusToQtStatus(status);
+ auto status = [EKEventStore authorizationStatusForEntityType:EKEntityTypeEvent];
+ switch (status) {
+ case EKAuthorizationStatusNotDetermined:
+ return Qt::PermissionStatus::Undetermined;
+ case EKAuthorizationStatusRestricted:
+ case EKAuthorizationStatusDenied:
+ return Qt::PermissionStatus::Denied;
+ case EKAuthorizationStatusAuthorized:
+ return Qt::PermissionStatus::Granted;
+#if QT_MACOS_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(140000, 170000)
+ case EKAuthorizationStatusWriteOnly:
+ // FIXME: Add WriteOnly AccessMode
+ return Qt::PermissionStatus::Denied;
+#endif
+ }
+
+ qCWarning(lcPermissions) << "Unknown permission status" << status << "detected in" << self;
+ return Qt::PermissionStatus::Denied;
}
- (QStringList)usageDescriptionsFor:(QPermission)permission
diff --git a/src/corelib/platform/darwin/qdarwinpermissionplugin_location.mm b/src/corelib/platform/darwin/qdarwinpermissionplugin_location.mm
index ed6acd3c9f..1d32c0fcac 100644
--- a/src/corelib/platform/darwin/qdarwinpermissionplugin_location.mm
+++ b/src/corelib/platform/darwin/qdarwinpermissionplugin_location.mm
@@ -73,15 +73,23 @@ struct PermissionRequest
return Qt::PermissionStatus::Denied;
}
- switch ([self authorizationStatus]) {
+#if defined(Q_OS_VISIONOS)
+ if (permission.availability() == QLocationPermission::Always)
+ return Qt::PermissionStatus::Denied;
+#endif
+
+ auto status = [self authorizationStatus];
+ switch (status) {
case kCLAuthorizationStatusRestricted:
case kCLAuthorizationStatusDenied:
return Qt::PermissionStatus::Denied;
case kCLAuthorizationStatusNotDetermined:
return Qt::PermissionStatus::Undetermined;
+#if !defined(Q_OS_VISIONOS)
case kCLAuthorizationStatusAuthorizedAlways:
return Qt::PermissionStatus::Granted;
-#ifdef Q_OS_IOS
+#endif
+#if defined(Q_OS_IOS) || defined(Q_OS_VISIONOS)
case kCLAuthorizationStatusAuthorizedWhenInUse:
if (permission.availability() == QLocationPermission::Always)
return Qt::PermissionStatus::Denied;
@@ -89,7 +97,8 @@ struct PermissionRequest
#endif
}
- Q_UNREACHABLE();
+ qCWarning(lcPermissions) << "Unknown permission status" << status << "detected in" << self;
+ return Qt::PermissionStatus::Denied;
}
- (CLAuthorizationStatus)authorizationStatus
@@ -118,7 +127,8 @@ struct PermissionRequest
return Qt::PermissionStatus::Denied;
}
- Q_UNREACHABLE();
+ qCWarning(lcPermissions) << "Unknown accuracy status" << status << "detected in" << self;
+ return Qt::PermissionStatus::Denied;
}
- (QStringList)usageDescriptionsFor:(QPermission)permission
@@ -174,6 +184,9 @@ struct PermissionRequest
}
break;
case QLocationPermission::Always:
+#if defined(Q_OS_VISIONOS)
+ [self deliverResult]; // Not supported
+#else
// The documentation specifies that requestAlwaysAuthorization can only
// be called when the current authorization status is either undetermined,
// or authorized when in use.
@@ -196,6 +209,7 @@ struct PermissionRequest
default:
[self deliverResult];
}
+#endif
break;
}
}
diff --git a/src/corelib/platform/darwin/qdarwinpermissionplugin_p_p.h b/src/corelib/platform/darwin/qdarwinpermissionplugin_p_p.h
index 9e4bbe92de..649af06507 100644
--- a/src/corelib/platform/darwin/qdarwinpermissionplugin_p_p.h
+++ b/src/corelib/platform/darwin/qdarwinpermissionplugin_p_p.h
@@ -83,7 +83,9 @@ Qt::PermissionStatus nativeStatusToQtStatus(NativeStatus status)
case Converter::Undetermined:
return Qt::PermissionStatus::Undetermined;
}
- Q_UNREACHABLE();
+ qCWarning(lcPermissions) << "Unknown permission status" << status << "detected in"
+ << QT_STRINGIFY(QT_DARWIN_PERMISSION_PLUGIN);
+ return Qt::PermissionStatus::Denied;
}
} // namespace
diff --git a/src/corelib/platform/ios/PrivacyInfo.xcprivacy b/src/corelib/platform/ios/PrivacyInfo.xcprivacy
new file mode 100644
index 0000000000..5f84a229a5
--- /dev/null
+++ b/src/corelib/platform/ios/PrivacyInfo.xcprivacy
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>NSPrivacyTracking</key>
+ <false/>
+ <key>NSPrivacyCollectedDataTypes</key>
+ <array/>
+ <key>NSPrivacyTrackingDomains</key>
+ <array/>
+ <key>NSPrivacyAccessedAPITypes</key>
+ <array>
+ <dict>
+ <key>NSPrivacyAccessedAPIType</key>
+ <string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
+ <key>NSPrivacyAccessedAPITypeReasons</key>
+ <array>
+ <string>0A2A.1</string> <!-- QFileInfo -->
+ </array>
+ </dict>
+ <dict>
+ <key>NSPrivacyAccessedAPIType</key>
+ <string>NSPrivacyAccessedAPICategoryDiskSpace</string>
+ <key>NSPrivacyAccessedAPITypeReasons</key>
+ <array>
+ <string>85F4.1</string> <!-- QStorageInfo -->
+ </array>
+ </dict>
+ </array>
+</dict>
+</plist>
diff --git a/src/corelib/platform/wasm/qstdweb.cpp b/src/corelib/platform/wasm/qstdweb.cpp
index 78e0bb83ab..75e76a6806 100644
--- a/src/corelib/platform/wasm/qstdweb.cpp
+++ b/src/corelib/platform/wasm/qstdweb.cpp
@@ -10,6 +10,8 @@
#include <emscripten/bind.h>
#include <emscripten/emscripten.h>
#include <emscripten/html5.h>
+#include <emscripten/threading.h>
+
#include <cstdint>
#include <iostream>
@@ -17,6 +19,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::Literals::StringLiterals;
+
namespace qstdweb {
static void usePotentialyUnusedSymbols()
@@ -30,7 +34,7 @@ static void usePotentialyUnusedSymbols()
// called at runtime.
volatile bool doIt = false;
if (doIt)
- emscripten_set_wheel_callback(NULL, 0, 0, NULL);
+ emscripten_set_wheel_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, 0, NULL);
}
Q_CONSTRUCTOR_FUNCTION(usePotentialyUnusedSymbols)
@@ -134,11 +138,12 @@ public:
"catch",
emscripten::val::module_property(thunkName(CallbackType::Catch, id()).data()));
}
- if (callbacks.finallyFunc) {
- target = target.call<val>(
- "finally",
- emscripten::val::module_property(thunkName(CallbackType::Finally, id()).data()));
- }
+ // Guarantee the invocation of at least one callback by always
+ // registering 'finally'. This is required by WebPromiseManager
+ // design
+ target = target.call<val>(
+ "finally", emscripten::val::module_property(
+ thunkName(CallbackType::Finally, id()).data()));
}
private:
@@ -319,25 +324,21 @@ void WebPromiseManager::promiseThunkCallback(int context, CallbackType type, ems
auto* promiseState = &m_promiseRegistry[context];
auto* callbacks = &promiseState->callbacks;
- bool expectingOtherCallbacks;
switch (type) {
case CallbackType::Then:
callbacks->thenFunc(result);
- // At this point, if there is no finally function, we are sure that the Catch callback won't be issued.
- expectingOtherCallbacks = !!callbacks->finallyFunc;
break;
case CallbackType::Catch:
callbacks->catchFunc(result);
- expectingOtherCallbacks = !!callbacks->finallyFunc;
break;
case CallbackType::Finally:
- callbacks->finallyFunc();
- expectingOtherCallbacks = false;
+ // Final callback may be empty, used solely for promise unregistration
+ if (callbacks->finallyFunc) {
+ callbacks->finallyFunc();
+ }
+ unregisterPromise(context);
break;
- }
-
- if (!expectingOtherCallbacks)
- unregisterPromise(context);
+ }
}
void WebPromiseManager::registerPromise(
@@ -363,118 +364,15 @@ void WebPromiseManager::adoptPromise(emscripten::val target, PromiseCallbacks ca
#if defined(QT_STATIC)
EM_JS(bool, jsHaveAsyncify, (), { return typeof Asyncify !== "undefined"; });
+EM_JS(bool, jsHaveJspi, (),
+ { return typeof Asyncify !== "undefined" && !!Asyncify.makeAsyncFunction && !!WebAssembly.Function; });
#else
bool jsHaveAsyncify() { return false; }
+bool jsHaveJspi() { return false; }
#endif
-
-struct DataTransferReader
-{
-public:
- using DoneCallback = std::function<void(std::unique_ptr<QMimeData>)>;
-
- static std::shared_ptr<CancellationFlag> read(emscripten::val webDataTransfer,
- std::function<QVariant(QByteArray)> imageReader,
- DoneCallback onCompleted)
- {
- auto cancellationFlag = std::make_shared<CancellationFlag>();
- (new DataTransferReader(std::move(onCompleted), std::move(imageReader), cancellationFlag))
- ->read(webDataTransfer);
- return cancellationFlag;
- }
-
- ~DataTransferReader() = default;
-
-private:
- DataTransferReader(DoneCallback onCompleted, std::function<QVariant(QByteArray)> imageReader,
- std::shared_ptr<CancellationFlag> cancellationFlag)
- : mimeData(std::make_unique<QMimeData>()),
- imageReader(std::move(imageReader)),
- onCompleted(std::move(onCompleted)),
- cancellationFlag(cancellationFlag)
- {
- }
-
- void read(emscripten::val webDataTransfer)
- {
- enum class ItemKind {
- File,
- String,
- };
-
- const auto items = webDataTransfer["items"];
- for (int i = 0; i < items["length"].as<int>(); ++i) {
- const auto item = items[i];
- const auto itemKind =
- item["kind"].as<std::string>() == "string" ? ItemKind::String : ItemKind::File;
- const auto itemMimeType = QString::fromStdString(item["type"].as<std::string>());
-
- switch (itemKind) {
- case ItemKind::File: {
- ++fileCount;
-
- qstdweb::File file(item.call<emscripten::val>("getAsFile"));
-
- QByteArray fileContent(file.size(), Qt::Uninitialized);
- file.stream(fileContent.data(), [this, itemMimeType, fileContent]() {
- if (!fileContent.isEmpty()) {
- if (itemMimeType.startsWith("image/")) {
- mimeData->setImageData(imageReader(fileContent));
- } else {
- mimeData->setData(itemMimeType, fileContent.data());
- }
- }
- ++doneCount;
- onFileRead();
- });
- break;
- }
- case ItemKind::String:
- if (itemMimeType.contains("STRING", Qt::CaseSensitive)
- || itemMimeType.contains("TEXT", Qt::CaseSensitive)) {
- break;
- }
- QString a;
- const QString data = QString::fromJsString(webDataTransfer.call<emscripten::val>(
- "getData", emscripten::val(itemMimeType.toStdString())));
-
- if (!data.isEmpty()) {
- if (itemMimeType == "text/html")
- mimeData->setHtml(data);
- else if (itemMimeType.isEmpty() || itemMimeType == "text/plain")
- mimeData->setText(data); // the type can be empty
- else
- mimeData->setData(itemMimeType, data.toLocal8Bit());
- }
- break;
- }
- }
-
- onFileRead();
- }
-
- void onFileRead()
- {
- Q_ASSERT(doneCount <= fileCount);
- if (doneCount < fileCount)
- return;
-
- std::unique_ptr<DataTransferReader> deleteThisLater(this);
- if (!cancellationFlag.expired())
- onCompleted(std::move(mimeData));
- }
-
- int fileCount = 0;
- int doneCount = 0;
- std::unique_ptr<QMimeData> mimeData;
- std::function<QVariant(QByteArray)> imageReader;
- DoneCallback onCompleted;
-
- std::weak_ptr<CancellationFlag> cancellationFlag;
-};
-
} // namespace
ArrayBuffer::ArrayBuffer(uint32_t size)
@@ -496,7 +394,12 @@ uint32_t ArrayBuffer::byteLength() const
return m_arrayBuffer["byteLength"].as<uint32_t>();
}
-emscripten::val ArrayBuffer::val()
+ArrayBuffer ArrayBuffer::slice(uint32_t begin, uint32_t end) const
+{
+ return ArrayBuffer(m_arrayBuffer.call<emscripten::val>("slice", begin, end));
+}
+
+emscripten::val ArrayBuffer::val() const
{
return m_arrayBuffer;
}
@@ -507,24 +410,55 @@ Blob::Blob(const emscripten::val &blob)
}
+Blob Blob::fromArrayBuffer(const ArrayBuffer &arrayBuffer)
+{
+ auto array = emscripten::val::array();
+ array.call<void>("push", arrayBuffer.val());
+ return Blob(emscripten::val::global("Blob").new_(array));
+}
+
uint32_t Blob::size() const
{
return m_blob["size"].as<uint32_t>();
}
-// Copies content from the given buffer into a Blob object
-Blob Blob::copyFrom(const char *buffer, uint32_t size)
+Blob Blob::copyFrom(const char *buffer, uint32_t size, std::string mimeType)
{
Uint8Array contentCopy = Uint8Array::copyFrom(buffer, size);
emscripten::val contentArray = emscripten::val::array();
contentArray.call<void>("push", contentCopy.val());
emscripten::val type = emscripten::val::object();
- type.set("type","application/octet-stream");
+ type.set("type", std::move(mimeType));
return Blob(emscripten::val::global("Blob").new_(contentArray, type));
}
-emscripten::val Blob::val()
+// Copies content from the given buffer into a Blob object
+Blob Blob::copyFrom(const char *buffer, uint32_t size)
+{
+ return copyFrom(buffer, size, "application/octet-stream");
+}
+
+Blob Blob::slice(uint32_t begin, uint32_t end) const
+{
+ return Blob(m_blob.call<emscripten::val>("slice", begin, end));
+}
+
+ArrayBuffer Blob::arrayBuffer_sync() const
+{
+ QEventLoop loop;
+ emscripten::val buffer;
+ qstdweb::Promise::make(m_blob, QStringLiteral("arrayBuffer"), {
+ .thenFunc = [&loop, &buffer](emscripten::val arrayBuffer) {
+ buffer = arrayBuffer;
+ loop.quit();
+ }
+ });
+ loop.exec();
+ return ArrayBuffer(buffer);
+}
+
+emscripten::val Blob::val() const
{
return m_blob;
}
@@ -535,6 +469,17 @@ File::File(const emscripten::val &file)
}
+File::~File() = default;
+
+File::File(const File &other) = default;
+
+File::File(File &&other) = default;
+
+File &File::operator=(const File &other) = default;
+
+File &File::operator=(File &&other) = default;
+
+
Blob File::slice(uint64_t begin, uint64_t end) const
{
return Blob(m_file.call<emscripten::val>("slice", uint53_t(begin), uint53_t(end)));
@@ -575,11 +520,27 @@ std::string File::type() const
return m_file["type"].as<std::string>();
}
-emscripten::val File::val()
+emscripten::val File::val() const
{
return m_file;
}
+FileUrlRegistration::FileUrlRegistration(File file)
+{
+ m_path = QString::fromStdString(emscripten::val::global("window")["URL"].call<std::string>(
+ "createObjectURL", file.file()));
+}
+
+FileUrlRegistration::~FileUrlRegistration()
+{
+ emscripten::val::global("window")["URL"].call<void>("revokeObjectURL",
+ emscripten::val(m_path.toStdString()));
+}
+
+FileUrlRegistration::FileUrlRegistration(FileUrlRegistration &&other) = default;
+
+FileUrlRegistration &FileUrlRegistration::operator=(FileUrlRegistration &&other) = default;
+
FileList::FileList(const emscripten::val &fileList)
:m_fileList(fileList)
{
@@ -618,20 +579,23 @@ void FileReader::readAsArrayBuffer(const Blob &blob) const
void FileReader::onLoad(const std::function<void(emscripten::val)> &onLoad)
{
- m_onLoad.reset(new EventCallback(m_fileReader, "load", onLoad));
+ m_onLoad.reset();
+ m_onLoad = std::make_unique<EventCallback>(m_fileReader, "load", onLoad);
}
void FileReader::onError(const std::function<void(emscripten::val)> &onError)
{
- m_onError.reset(new EventCallback(m_fileReader, "error", onError));
+ m_onError.reset();
+ m_onError = std::make_unique<EventCallback>(m_fileReader, "error", onError);
}
void FileReader::onAbort(const std::function<void(emscripten::val)> &onAbort)
{
- m_onAbort.reset(new EventCallback(m_fileReader, "abort", onAbort));
+ m_onAbort.reset();
+ m_onAbort = std::make_unique<EventCallback>(m_fileReader, "abort", onAbort);
}
-emscripten::val FileReader::val()
+emscripten::val FileReader::val() const
{
return m_fileReader;
}
@@ -691,6 +655,13 @@ void Uint8Array::set(const Uint8Array &source)
m_uint8Array.call<void>("set", source.m_uint8Array); // copies source content
}
+Uint8Array Uint8Array::subarray(uint32_t begin, uint32_t end)
+{
+ // Note: using uint64_t here errors with "Cannot convert a BigInt value to a number"
+ // (see JS BigInt and Number types). Use uint32_t for now.
+ return Uint8Array(m_uint8Array.call<emscripten::val>("subarray", begin, end));
+}
+
// Copies the Uint8Array content to a destination on the heap
void Uint8Array::copyTo(char *destination) const
{
@@ -729,7 +700,7 @@ Uint8Array Uint8Array::copyFrom(const QByteArray &buffer)
return copyFrom(buffer.constData(), buffer.size());
}
-emscripten::val Uint8Array::val()
+emscripten::val Uint8Array::val() const
{
return m_uint8Array;
}
@@ -744,47 +715,45 @@ emscripten::val Uint8Array::constructor_()
return emscripten::val::global("Uint8Array");
}
+class EventListener {
+public:
+ EventListener(uintptr_t handler)
+ :m_handler(handler)
+ {
+
+ }
+
+ // Special function - addEventListender() allows adding an object with a
+ // handleEvent() function which eceives the event.
+ void handleEvent(emscripten::val event) {
+ auto handlerPtr = reinterpret_cast<std::function<void(emscripten::val)> *>(m_handler);
+ (*handlerPtr)(event);
+ }
+
+ uintptr_t m_handler;
+};
+
// Registers a callback function for a named event on the given element. The event
// name must be the name as returned by the Event.type property: e.g. "load", "error".
EventCallback::~EventCallback()
{
- // Clean up if this instance's callback is still installed on the element
- if (m_element[contextPropertyName(m_eventName).c_str()].as<intptr_t>() == intptr_t(this)) {
- m_element.set(contextPropertyName(m_eventName).c_str(), emscripten::val::undefined());
- m_element.set((std::string("on") + m_eventName).c_str(), emscripten::val::undefined());
- }
+ m_element.call<void>("removeEventListener", m_eventName, m_eventListener);
}
-EventCallback::EventCallback(emscripten::val element, const std::string &name, const std::function<void(emscripten::val)> &fn)
+EventCallback::EventCallback(emscripten::val element, const std::string &name, const std::function<void(emscripten::val)> &handler)
:m_element(element)
,m_eventName(name)
- ,m_fn(fn)
-{
- Q_ASSERT_X(m_element[contextPropertyName(m_eventName)].isUndefined(), Q_FUNC_INFO,
- "Only one event callback of type currently supported with EventCallback");
- m_element.set(contextPropertyName(m_eventName).c_str(), emscripten::val(intptr_t(this)));
- m_element.set((std::string("on") + m_eventName).c_str(), emscripten::val::module_property("qtStdWebEventCallbackActivate"));
-}
-
-void EventCallback::activate(emscripten::val event)
-{
- emscripten::val target = event["currentTarget"];
- std::string eventName = event["type"].as<std::string>();
- emscripten::val property = target[contextPropertyName(eventName)];
- // This might happen when the event bubbles
- if (property.isUndefined())
- return;
- EventCallback *that = reinterpret_cast<EventCallback *>(property.as<intptr_t>());
- that->m_fn(event);
-}
-
-std::string EventCallback::contextPropertyName(const std::string &eventName)
+ ,m_handler(std::make_unique<std::function<void(emscripten::val)>>(handler))
{
- return std::string("data-qtEventCallbackContext") + eventName;
+ uintptr_t handlerUint = reinterpret_cast<uintptr_t>(m_handler.get()); // FIXME: pass pointer directly instead
+ m_eventListener = emscripten::val::module_property("QtEventListener").new_(handlerUint);
+ m_element.call<void>("addEventListener", m_eventName, m_eventListener);
}
EMSCRIPTEN_BINDINGS(qtStdwebCalback) {
- emscripten::function("qtStdWebEventCallbackActivate", &EventCallback::activate);
+ emscripten::class_<EventListener>("QtEventListener")
+ .constructor<uintptr_t>()
+ .function("handleEvent", &EventListener::handleEvent);
}
namespace Promise {
@@ -841,17 +810,126 @@ namespace Promise {
}
}
+// Asyncify and thread blocking: Normally, it's not possible to block the main
+// thread, except if asyncify is enabled. Secondary threads can always block.
+//
+// haveAsyncify(): returns true if the main thread can block on QEventLoop::exec(),
+// if either asyncify 1 or 2 (JSPI) is available.
+//
+// haveJspi(): returns true if asyncify 2 (JSPI) is available.
+//
+// canBlockCallingThread(): returns true if the calling thread can block on
+// QEventLoop::exec(), using either asyncify or as a seconarday thread.
+bool haveJspi()
+{
+ static bool HaveJspi = jsHaveJspi();
+ return HaveJspi;
+}
+
bool haveAsyncify()
{
- static bool HaveAsyncify = jsHaveAsyncify();
+ static bool HaveAsyncify = jsHaveAsyncify() || haveJspi();
return HaveAsyncify;
}
-std::shared_ptr<CancellationFlag>
-readDataTransfer(emscripten::val webDataTransfer, std::function<QVariant(QByteArray)> imageReader,
- std::function<void(std::unique_ptr<QMimeData>)> onDone)
+bool canBlockCallingThread()
+{
+ return haveAsyncify() || !emscripten_is_main_runtime_thread();
+}
+
+BlobIODevice::BlobIODevice(Blob blob)
+ : m_blob(blob)
+{
+
+}
+
+bool BlobIODevice::open(QIODevice::OpenMode mode)
+{
+ if (mode.testFlag(QIODevice::WriteOnly))
+ return false;
+ return QIODevice::open(mode);
+}
+
+bool BlobIODevice::isSequential() const
+{
+ return false;
+}
+
+qint64 BlobIODevice::size() const
+{
+ return m_blob.size();
+}
+
+bool BlobIODevice::seek(qint64 pos)
+{
+ if (pos >= size())
+ return false;
+ return QIODevice::seek(pos);
+}
+
+qint64 BlobIODevice::readData(char *data, qint64 maxSize)
+{
+ uint64_t begin = QIODevice::pos();
+ uint64_t end = std::min<uint64_t>(begin + maxSize, size());
+ uint64_t size = end - begin;
+ if (size > 0) {
+ qstdweb::ArrayBuffer buffer = m_blob.slice(begin, end).arrayBuffer_sync();
+ qstdweb::Uint8Array(buffer).copyTo(data);
+ }
+ return size;
+}
+
+qint64 BlobIODevice::writeData(const char *, qint64)
+{
+ Q_UNREACHABLE();
+}
+
+Uint8ArrayIODevice::Uint8ArrayIODevice(Uint8Array array)
+ : m_array(array)
+{
+
+}
+
+bool Uint8ArrayIODevice::open(QIODevice::OpenMode mode)
+{
+ return QIODevice::open(mode);
+}
+
+bool Uint8ArrayIODevice::isSequential() const
+{
+ return false;
+}
+
+qint64 Uint8ArrayIODevice::size() const
+{
+ return m_array.length();
+}
+
+bool Uint8ArrayIODevice::seek(qint64 pos)
+{
+ if (pos >= size())
+ return false;
+ return QIODevice::seek(pos);
+}
+
+qint64 Uint8ArrayIODevice::readData(char *data, qint64 maxSize)
+{
+ uint64_t begin = QIODevice::pos();
+ uint64_t end = std::min<uint64_t>(begin + maxSize, size());
+ uint64_t size = end - begin;
+ if (size > 0)
+ m_array.subarray(begin, end).copyTo(data);
+ return size;
+}
+
+qint64 Uint8ArrayIODevice::writeData(const char *data, qint64 maxSize)
{
- return DataTransferReader::read(webDataTransfer, std::move(imageReader), std::move(onDone));
+ uint64_t begin = QIODevice::pos();
+ uint64_t end = std::min<uint64_t>(begin + maxSize, size());
+ uint64_t size = end - begin;
+ if (size > 0)
+ m_array.subarray(begin, end).set(Uint8Array(data, size));
+ return size;
}
} // namespace qstdweb
diff --git a/src/corelib/platform/wasm/qstdweb_p.h b/src/corelib/platform/wasm/qstdweb_p.h
index e01a5bd855..a3b5bd5b6b 100644
--- a/src/corelib/platform/wasm/qstdweb_p.h
+++ b/src/corelib/platform/wasm/qstdweb_p.h
@@ -18,6 +18,7 @@
#include <private/qglobal_p.h>
#include <QtCore/qglobal.h>
#include "QtCore/qhash.h"
+#include "QtCore/qiodevice.h"
#include <emscripten/val.h>
@@ -28,6 +29,11 @@
#include <string>
#include <utility>
+#if QT_CONFIG(thread)
+#include <emscripten/proxying.h>
+#include <emscripten/threading.h>
+#endif // #if QT_CONFIG(thread)
+
QT_BEGIN_NAMESPACE
class QMimeData;
@@ -53,7 +59,8 @@ namespace qstdweb {
explicit ArrayBuffer(uint32_t size);
explicit ArrayBuffer(const emscripten::val &arrayBuffer);
uint32_t byteLength() const;
- emscripten::val val();
+ ArrayBuffer slice(uint32_t begin, uint32_t end) const;
+ emscripten::val val() const;
private:
friend class Uint8Array;
@@ -63,9 +70,13 @@ namespace qstdweb {
class Q_CORE_EXPORT Blob {
public:
explicit Blob(const emscripten::val &blob);
+ static Blob fromArrayBuffer(const ArrayBuffer &arrayBuffer);
uint32_t size() const;
+ static Blob copyFrom(const char *buffer, uint32_t size, std::string mimeType);
static Blob copyFrom(const char *buffer, uint32_t size);
- emscripten::val val();
+ Blob slice(uint32_t begin, uint32_t end) const;
+ ArrayBuffer arrayBuffer_sync() const;
+ emscripten::val val() const;
std::string type() const;
private:
@@ -77,6 +88,12 @@ namespace qstdweb {
public:
File() = default;
explicit File(const emscripten::val &file);
+ ~File();
+
+ File(const File &other);
+ File(File &&other);
+ File &operator=(const File &other);
+ File &operator=(File &&other);
Blob slice(uint64_t begin, uint64_t end) const;
std::string name() const;
@@ -85,12 +102,35 @@ namespace qstdweb {
void stream(uint32_t offset, uint32_t length, char *buffer,
std::function<void()> completed) const;
void stream(char *buffer, std::function<void()> completed) const;
- emscripten::val val();
+ emscripten::val val() const;
+ void fileUrlRegistration() const;
+ const QString &fileUrlPath() const { return m_urlPath; }
+ emscripten::val file() const { return m_file; }
private:
emscripten::val m_file = emscripten::val::undefined();
+ QString m_urlPath;
+ };
+
+ class Q_CORE_EXPORT FileUrlRegistration
+ {
+ public:
+ explicit FileUrlRegistration(File file);
+ ~FileUrlRegistration();
+
+ FileUrlRegistration(const FileUrlRegistration &other) = delete;
+ FileUrlRegistration(FileUrlRegistration &&other);
+ FileUrlRegistration &operator=(const FileUrlRegistration &other) = delete;
+ FileUrlRegistration &operator=(FileUrlRegistration &&other);
+
+ const QString &path() const { return m_path; }
+
+ private:
+ QString m_path;
};
+ using FileUrlRegistrations = std::vector<std::unique_ptr<FileUrlRegistration>>;
+
class Q_CORE_EXPORT FileList {
public:
FileList() = default;
@@ -113,7 +153,7 @@ namespace qstdweb {
void onLoad(const std::function<void(emscripten::val)> &onLoad);
void onError(const std::function<void(emscripten::val)> &onError);
void onAbort(const std::function<void(emscripten::val)> &onAbort);
- emscripten::val val();
+ emscripten::val val() const;
private:
emscripten::val m_fileReader = emscripten::val::global("FileReader").new_();
@@ -134,6 +174,7 @@ namespace qstdweb {
ArrayBuffer buffer() const;
uint32_t length() const;
void set(const Uint8Array &source);
+ Uint8Array subarray(uint32_t begin, uint32_t end);
void copyTo(char *destination) const;
QByteArray copyToQByteArray() const;
@@ -141,7 +182,7 @@ namespace qstdweb {
static void copy(char *destination, const Uint8Array &source);
static Uint8Array copyFrom(const char *buffer, uint32_t size);
static Uint8Array copyFrom(const QByteArray &buffer);
- emscripten::val val();
+ emscripten::val val() const;
private:
static emscripten::val heap_();
@@ -158,13 +199,12 @@ namespace qstdweb {
EventCallback& operator=(EventCallback const&) = delete;
EventCallback(emscripten::val element, const std::string &name,
const std::function<void(emscripten::val)> &fn);
- static void activate(emscripten::val event);
private:
- static std::string contextPropertyName(const std::string &eventName);
emscripten::val m_element = emscripten::val::undefined();
std::string m_eventName;
- std::function<void(emscripten::val)> m_fn;
+ std::unique_ptr<std::function<void(emscripten::val)>> m_handler;
+ emscripten::val m_eventListener = emscripten::val::undefined();
};
struct PromiseCallbacks
@@ -195,6 +235,46 @@ namespace qstdweb {
void Q_CORE_EXPORT all(std::vector<emscripten::val> promises, PromiseCallbacks callbacks);
};
+ template<class F>
+ decltype(auto) bindForever(F wrappedCallback)
+ {
+ return wrappedCallback;
+ }
+
+ class Q_CORE_EXPORT BlobIODevice: public QIODevice
+ {
+ public:
+ BlobIODevice(Blob blob);
+ bool open(QIODeviceBase::OpenMode mode) override;
+ bool isSequential() const override;
+ qint64 size() const override;
+ bool seek(qint64 pos) override;
+
+ protected:
+ qint64 readData(char *data, qint64 maxSize) override;
+ qint64 writeData(const char *, qint64) override;
+
+ private:
+ Blob m_blob;
+ };
+
+ class Uint8ArrayIODevice: public QIODevice
+ {
+ public:
+ Uint8ArrayIODevice(Uint8Array array);
+ bool open(QIODevice::OpenMode mode) override;
+ bool isSequential() const override;
+ qint64 size() const override;
+ bool seek(qint64 pos) override;
+
+ protected:
+ qint64 readData(char *data, qint64 maxSize) override;
+ qint64 writeData(const char *data, qint64 size) override;
+
+ private:
+ Uint8Array m_array;
+ };
+
inline emscripten::val window()
{
static emscripten::val savedWindow = emscripten::val::global("window");
@@ -202,14 +282,50 @@ namespace qstdweb {
}
bool haveAsyncify();
+ bool Q_CORE_EXPORT haveJspi();
+ bool canBlockCallingThread();
struct CancellationFlag
{
};
- Q_CORE_EXPORT std::shared_ptr<CancellationFlag>
- readDataTransfer(emscripten::val webObject, std::function<QVariant(QByteArray)> imageReader,
- std::function<void(std::unique_ptr<QMimeData>)> onDone);
+#if QT_CONFIG(thread)
+ template<class T>
+ T proxyCall(std::function<T()> task, emscripten::ProxyingQueue *queue)
+ {
+ T result;
+ queue->proxySync(emscripten_main_runtime_thread_id(),
+ [task, result = &result]() { *result = task(); });
+ return result;
+ }
+
+ template<>
+ inline void proxyCall<void>(std::function<void()> task, emscripten::ProxyingQueue *queue)
+ {
+ queue->proxySync(emscripten_main_runtime_thread_id(), task);
+ }
+
+ template<class T>
+ T runTaskOnMainThread(std::function<T()> task, emscripten::ProxyingQueue *queue)
+ {
+ return emscripten_is_main_runtime_thread() ? task() : proxyCall<T>(std::move(task), queue);
+ }
+
+ template<class T>
+ T runTaskOnMainThread(std::function<T()> task)
+ {
+ emscripten::ProxyingQueue singleUseQueue;
+ return runTaskOnMainThread<T>(task, &singleUseQueue);
+ }
+
+#else
+ template<class T>
+ T runTaskOnMainThread(std::function<T()> task)
+ {
+ return task();
+ }
+#endif // QT_CONFIG(thread)
+
}
QT_END_NAMESPACE
diff --git a/src/corelib/platform/windows/qcomobject_p.h b/src/corelib/platform/windows/qcomobject_p.h
new file mode 100644
index 0000000000..8f27a18ff6
--- /dev/null
+++ b/src/corelib/platform/windows/qcomobject_p.h
@@ -0,0 +1,127 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QCOMOBJECT_P_H
+#define QCOMOBJECT_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/private/qglobal_p.h>
+
+#if defined(Q_OS_WIN) || defined(Q_QDOC)
+
+# include <QtCore/qt_windows.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtPrivate {
+
+template <typename... TInterfaces>
+struct QComObjectTraits
+{
+ static constexpr bool isGuidOf(REFIID riid) noexcept
+ {
+ return ((riid == __uuidof(TInterfaces)) || ...);
+ }
+};
+
+} // namespace QtPrivate
+
+// NOTE: In order to be able to query the intermediate interface, i.e. the one you do not specify in
+// QComObject interface list (TFirstInterface, TInterfaces) but that is a base for any of them
+// (except IUnknown) you need to provide an explicit specialization of function
+// QComObjectTraits<...>::isGuidOf for that type. For example, if you want to inherit interface
+// IMFSampleGrabberSinkCallback which inherits IMFClockStateSink and you want to be able to query
+// the latter one you need to provide this explicit specialization:
+//
+// class SinkCallback : public QComObject<IMFSampleGrabberSinkCallback>
+// {
+// ...
+// };
+//
+// namespace QtPrivate {
+//
+// template <>
+// struct QComObjectTraits<IMFSampleGrabberSinkCallback>
+// {
+// static constexpr bool isGuidOf(REFIID riid) noexcept
+// {
+// return QComObjectTraits<IMFSampleGrabberSinkCallback, IMFClockStateSink>::isGuidOf(riid);
+// }
+// };
+//
+// }
+
+template <typename TFirstInterface, typename... TAdditionalInterfaces>
+class QComObject : public TFirstInterface, public TAdditionalInterfaces...
+{
+public:
+ STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) override
+ {
+ if (!ppvObject)
+ return E_POINTER;
+
+ if (riid == __uuidof(IUnknown)) {
+ *ppvObject = static_cast<IUnknown *>(static_cast<TFirstInterface *>(this));
+ AddRef();
+
+ return S_OK;
+ }
+
+ return tryQueryInterface<TFirstInterface, TAdditionalInterfaces...>(riid, ppvObject);
+ }
+
+ STDMETHODIMP_(ULONG) AddRef() override { return ++m_referenceCount; }
+
+ STDMETHODIMP_(ULONG) Release() override
+ {
+ const LONG referenceCount = --m_referenceCount;
+ if (referenceCount == 0)
+ delete this;
+
+ return referenceCount;
+ }
+
+protected:
+ QComObject() = default;
+
+ // Destructor is not public. Caller should call Release.
+ // Derived class should make its destructor private to force this behavior.
+ virtual ~QComObject() = default;
+
+private:
+ template <typename TInterface, typename... TRest>
+ HRESULT tryQueryInterface(REFIID riid, void **ppvObject)
+ {
+ if (QtPrivate::QComObjectTraits<TInterface>::isGuidOf(riid)) {
+ *ppvObject = static_cast<TInterface *>(this);
+ AddRef();
+
+ return S_OK;
+ }
+
+ if constexpr (sizeof...(TRest) > 0)
+ return tryQueryInterface<TRest...>(riid, ppvObject);
+
+ *ppvObject = nullptr;
+
+ return E_NOINTERFACE;
+ }
+
+ std::atomic<LONG> m_referenceCount = 1;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q_OS_WIN
+
+#endif // QCOMOBJECT_P_H
diff --git a/src/corelib/plugin/qcoffpeparser.cpp b/src/corelib/plugin/qcoffpeparser.cpp
index 054a433603..639e402a07 100644
--- a/src/corelib/plugin/qcoffpeparser.cpp
+++ b/src/corelib/plugin/qcoffpeparser.cpp
@@ -117,7 +117,7 @@ Q_DECL_UNUSED static QDebug &operator<<(QDebug &d, HeaderDebug h)
switch (h.h->FileHeader.Machine) {
case IMAGE_FILE_MACHINE_I386: d << "i386"; break;
case IMAGE_FILE_MACHINE_ARM: d << "ARM"; break;
- case IMAGE_FILE_MACHINE_ARMNT: d << "ARM Thumb-2"; break;;
+ case IMAGE_FILE_MACHINE_ARMNT: d << "ARM Thumb-2"; break;
case IMAGE_FILE_MACHINE_THUMB: d << "Thumb"; break;
case IMAGE_FILE_MACHINE_IA64: d << "IA-64"; break;
case IMAGE_FILE_MACHINE_MIPS16: d << "MIPS16"; break;
diff --git a/src/corelib/plugin/qelfparser_p.cpp b/src/corelib/plugin/qelfparser_p.cpp
index 54e5a19e2e..7f6271cde4 100644
--- a/src/corelib/plugin/qelfparser_p.cpp
+++ b/src/corelib/plugin/qelfparser_p.cpp
@@ -20,11 +20,6 @@
# error "Need ELF header to parse plugins."
#endif
-// Support older ELFOSABI define for GNU/Linux
-#if !defined(ELFOSABI_GNU) && defined(ELFOSABI_LINUX)
-# define ELFOSABI_GNU ELFOSABI_LINUX
-#endif
-
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
@@ -59,6 +54,10 @@ static Q_LOGGING_CATEGORY(lcElfParser, "qt.core.plugin.elfparser")
# define PT_GNU_PROPERTY 0x6474e553
#endif
+#ifndef PN_XNUM
+# define PN_XNUM 0xffff
+#endif
+
QT_WARNING_PUSH
QT_WARNING_DISABLE_CLANG("-Wunused-const-variable")
@@ -340,7 +339,7 @@ Q_DECL_UNUSED Q_DECL_COLD_FUNCTION static QDebug &operator<<(QDebug &d, ElfHeade
case ELFOSABI_SYSV: d << " (SYSV"; break;
case ELFOSABI_HPUX: d << " (HP-UX"; break;
case ELFOSABI_NETBSD: d << " (NetBSD"; break;
- case ELFOSABI_GNU: d << " (GNU/Linux"; break;
+ case ELFOSABI_LINUX: d << " (GNU/Linux"; break;
case ELFOSABI_SOLARIS: d << " (Solaris"; break;
case ELFOSABI_AIX: d << " (AIX"; break;
case ELFOSABI_IRIX: d << " (IRIX"; break;
@@ -402,7 +401,9 @@ Q_DECL_UNUSED Q_DECL_COLD_FUNCTION static QDebug &operator<<(QDebug &d, ElfHeade
#ifdef EM_RISCV
case EM_RISCV: d << ", RISC-V"; break;
#endif
+#ifdef EM_S390
case EM_S390: d << ", S/390"; break;
+#endif
case EM_SH: d << ", SuperH"; break;
case EM_SPARC: d << ", SPARC"; break;
case EM_SPARCV9: d << ", SPARCv9"; break;
@@ -542,6 +543,8 @@ static bool preScanProgramHeaders(QByteArrayView data, const ErrorMaker &error)
// first, validate the extent of the full program header table
T::Word e_phnum = header->e_phnum;
+ if (e_phnum == PN_XNUM)
+ return error(QLibrary::tr("unimplemented: PN_XNUM program headers")), false;
T::Off offset = e_phnum * sizeof(T::Phdr); // can't overflow due to size of T::Half
if (qAddOverflow(offset, header->e_phoff, &offset) || offset > size_t(data.size()))
return error(QLibrary::tr("program header table extends past the end of the file")), false;
@@ -696,7 +699,7 @@ static QLibraryScanResult scanSections(QByteArrayView data, const ErrorMaker &er
// sections aren't allowed to extend past the end of the file, unless
// they are NOBITS sections
if (shdr->sh_type == SHT_NOBITS)
- continue;;
+ continue;
if (T::Off end; qAddOverflow(shdr->sh_offset, shdr->sh_size, &end)
|| end > size_t(data.size())) {
return error(QLibrary::tr("section contents extend past the end of the file"));
diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp
index 669949b975..e2d9a40cb4 100644
--- a/src/corelib/plugin/qfactoryloader.cpp
+++ b/src/corelib/plugin/qfactoryloader.cpp
@@ -5,22 +5,19 @@
#include "qfactoryloader_p.h"
#ifndef QT_NO_QOBJECT
-#include "qfactoryinterface.h"
-
#include "private/qcoreapplication_p.h"
#include "private/qduplicatetracker_p.h"
#include "private/qloggingregistry_p.h"
#include "private/qobject_p.h"
#include "qcborarray.h"
#include "qcbormap.h"
+#include "qcborstreamreader.h"
#include "qcborvalue.h"
-#include "qcborvalue.h"
-#include "qdiriterator.h"
+#include "qdirlisting.h"
#include "qfileinfo.h"
#include "qjsonarray.h"
#include "qjsondocument.h"
#include "qjsonobject.h"
-#include "qmap.h"
#include "qmutex.h"
#include "qplugin.h"
#include "qplugin_p.h"
@@ -32,32 +29,189 @@
#include <qtcore_tracepoints_p.h>
+#include <map>
+#include <vector>
+
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
Q_TRACE_POINT(qtcore, QFactoryLoader_update, const QString &fileName);
-bool QPluginParsedMetaData::parse(QByteArrayView raw)
+namespace {
+struct IterationResult
+{
+ enum Result {
+ FinishedSearch = 0,
+ ContinueSearch,
+
+ // parse errors
+ ParsingError = -1,
+ InvalidMetaDataVersion = -2,
+ InvalidTopLevelItem = -3,
+ InvalidHeaderItem = -4,
+ };
+ Result result;
+ QCborError error = { QCborError::NoError };
+
+ Q_IMPLICIT IterationResult(Result r) : result(r) {}
+ Q_IMPLICIT IterationResult(QCborError e) : result(ParsingError), error(e) {}
+};
+
+struct QFactoryLoaderIidSearch
+{
+ QLatin1StringView iid;
+ bool matchesIid = false;
+ QFactoryLoaderIidSearch(QLatin1StringView iid) : iid(iid)
+ { Q_ASSERT(!iid.isEmpty()); }
+
+ static IterationResult::Result skip(QCborStreamReader &reader)
+ {
+ // skip this, whatever it is
+ reader.next();
+ return IterationResult::ContinueSearch;
+ }
+
+ IterationResult::Result operator()(QtPluginMetaDataKeys key, QCborStreamReader &reader)
+ {
+ if (key != QtPluginMetaDataKeys::IID)
+ return skip(reader);
+ matchesIid = (reader.readAllString() == iid);
+ return IterationResult::FinishedSearch;
+ }
+ IterationResult::Result operator()(QUtf8StringView, QCborStreamReader &reader)
+ {
+ return skip(reader);
+ }
+};
+
+struct QFactoryLoaderMetaDataKeysExtractor : QFactoryLoaderIidSearch
+{
+ QCborArray keys;
+ QFactoryLoaderMetaDataKeysExtractor(QLatin1StringView iid)
+ : QFactoryLoaderIidSearch(iid)
+ {}
+
+ IterationResult::Result operator()(QtPluginMetaDataKeys key, QCborStreamReader &reader)
+ {
+ if (key == QtPluginMetaDataKeys::IID) {
+ QFactoryLoaderIidSearch::operator()(key, reader);
+ return IterationResult::ContinueSearch;
+ }
+ if (key != QtPluginMetaDataKeys::MetaData)
+ return skip(reader);
+
+ if (!matchesIid)
+ return IterationResult::FinishedSearch;
+ if (!reader.isMap() || !reader.isLengthKnown())
+ return IterationResult::InvalidHeaderItem;
+ if (!reader.enterContainer())
+ return IterationResult::ParsingError;
+ while (reader.isValid()) {
+ // the metadata is JSON, so keys are all strings
+ QByteArray key = reader.readAllUtf8String();
+ if (key == "Keys") {
+ if (!reader.isArray() || !reader.isLengthKnown())
+ return IterationResult::InvalidHeaderItem;
+ keys = QCborValue::fromCbor(reader).toArray();
+ break;
+ }
+ skip(reader);
+ }
+ // warning: we may not have finished iterating over the header
+ return IterationResult::FinishedSearch;
+ }
+ using QFactoryLoaderIidSearch::operator();
+};
+} // unnamed namespace
+
+template <typename F> static IterationResult iterateInPluginMetaData(QByteArrayView raw, F &&f)
{
QPluginMetaData::Header header;
Q_ASSERT(raw.size() >= qsizetype(sizeof(header)));
memcpy(&header, raw.data(), sizeof(header));
if (Q_UNLIKELY(header.version > QPluginMetaData::CurrentMetaDataVersion))
- return setError(QFactoryLoader::tr("Invalid metadata version"));
+ return IterationResult::InvalidMetaDataVersion;
// use fromRawData to keep QCborStreamReader from copying
raw = raw.sliced(sizeof(header));
QByteArray ba = QByteArray::fromRawData(raw.data(), raw.size());
- QCborParserError err;
- QCborValue metadata = QCborValue::fromCbor(ba, &err);
+ QCborStreamReader reader(ba);
+ if (reader.isInvalid())
+ return reader.lastError();
+ if (!reader.isMap())
+ return IterationResult::InvalidTopLevelItem;
+ if (!reader.enterContainer())
+ return reader.lastError();
+ while (reader.isValid()) {
+ IterationResult::Result r;
+ if (reader.isInteger()) {
+ // integer key, one of ours
+ qint64 value = reader.toInteger();
+ auto key = QtPluginMetaDataKeys(value);
+ if (qint64(key) != value)
+ return IterationResult::InvalidHeaderItem;
+ if (!reader.next())
+ return reader.lastError();
+ r = f(key, reader);
+ } else if (reader.isString()) {
+ QByteArray key = reader.readAllUtf8String();
+ if (key.isNull())
+ return reader.lastError();
+ r = f(QUtf8StringView(key), reader);
+ } else {
+ return IterationResult::InvalidTopLevelItem;
+ }
+
+ if (QCborError e = reader.lastError())
+ return e;
+ if (r != IterationResult::ContinueSearch)
+ return r;
+ }
+
+ if (!reader.leaveContainer())
+ return reader.lastError();
+ return IterationResult::FinishedSearch;
+}
+
+static bool isIidMatch(QByteArrayView raw, QLatin1StringView iid)
+{
+ QFactoryLoaderIidSearch search(iid);
+ iterateInPluginMetaData(raw, search);
+ return search.matchesIid;
+}
- if (err.error != QCborError::NoError)
- return setError(QFactoryLoader::tr("Metadata parsing error: %1").arg(err.error.toString()));
- if (!metadata.isMap())
+bool QPluginParsedMetaData::parse(QByteArrayView raw)
+{
+ QCborMap map;
+ auto r = iterateInPluginMetaData(raw, [&](const auto &key, QCborStreamReader &reader) {
+ QCborValue item = QCborValue::fromCbor(reader);
+ if (item.isInvalid())
+ return IterationResult::ParsingError;
+ if constexpr (std::is_enum_v<std::decay_t<decltype(key)>>)
+ map[int(key)] = item;
+ else
+ map[QString::fromUtf8(key)] = item;
+ return IterationResult::ContinueSearch;
+ });
+
+ switch (r.result) {
+ case IterationResult::FinishedSearch:
+ case IterationResult::ContinueSearch:
+ break;
+
+ // parse errors
+ case IterationResult::ParsingError:
+ return setError(QFactoryLoader::tr("Metadata parsing error: %1").arg(r.error.toString()));
+ case IterationResult::InvalidMetaDataVersion:
+ return setError(QFactoryLoader::tr("Invalid metadata version"));
+ case IterationResult::InvalidTopLevelItem:
+ case IterationResult::InvalidHeaderItem:
return setError(QFactoryLoader::tr("Unexpected metadata contents"));
- QCborMap map = metadata.toMap();
- metadata = {};
+ }
+
+ // header was validated
+ auto header = qFromUnaligned<QPluginMetaData::Header>(raw.data());
DecodedArchRequirements archReq =
header.version == 0 ? decodeVersion0ArchRequirements(header.plugin_arch_requirements)
@@ -98,6 +252,7 @@ QJsonObject QPluginParsedMetaData::toJson() const
class QFactoryLoaderPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QFactoryLoader)
+ Q_DISABLE_COPY_MOVE(QFactoryLoaderPrivate)
public:
QFactoryLoaderPrivate() { }
QByteArray iid;
@@ -105,8 +260,8 @@ public:
~QFactoryLoaderPrivate();
mutable QMutex mutex;
QDuplicateTracker<QString> loadedPaths;
- QList<QLibraryPrivate*> libraryList;
- QMap<QString,QLibraryPrivate*> keyMap;
+ std::vector<QLibraryPrivate::UniquePtr> libraries;
+ std::map<QString, QLibraryPrivate*> keyMap;
QString suffix;
QString extraSearchPath;
Qt::CaseSensitivity cs;
@@ -133,10 +288,7 @@ struct QFactoryLoaderGlobals
Q_GLOBAL_STATIC(QFactoryLoaderGlobals, qt_factoryloader_global)
QFactoryLoaderPrivate::~QFactoryLoaderPrivate()
-{
- for (QLibraryPrivate *library : std::as_const(libraryList))
- library->release();
-}
+ = default;
inline void QFactoryLoaderPrivate::updateSinglePath(const QString &path)
{
@@ -151,7 +303,7 @@ inline void QFactoryLoaderPrivate::updateSinglePath(const QString &path)
qCDebug(lcFactoryLoader) << "checking directory path" << path << "...";
- QDirIterator plugins(path,
+ QDirListing plugins(path,
#if defined(Q_OS_WIN)
QStringList(QStringLiteral("*.dll")),
#elif defined(Q_OS_ANDROID)
@@ -159,8 +311,8 @@ inline void QFactoryLoaderPrivate::updateSinglePath(const QString &path)
#endif
QDir::Files);
- while (plugins.hasNext()) {
- QString fileName = plugins.next();
+ for (const auto &dirEntry : plugins) {
+ const QString &fileName = dirEntry.fileName();
#ifdef Q_OS_DARWIN
const bool isDebugPlugin = fileName.endsWith("_debug.dylib"_L1);
const bool isDebugLibrary =
@@ -184,8 +336,8 @@ inline void QFactoryLoaderPrivate::updateSinglePath(const QString &path)
Q_TRACE(QFactoryLoader_update, fileName);
- std::unique_ptr<QLibraryPrivate, LibraryReleaser> library;
- library.reset(QLibraryPrivate::findOrCreate(QFileInfo(fileName).canonicalFilePath()));
+ QLibraryPrivate::UniquePtr library;
+ library.reset(QLibraryPrivate::findOrCreate(dirEntry.canonicalFilePath()));
if (!library->isPlugin()) {
qCDebug(lcFactoryLoader) << library->errorString << Qt::endl
<< " not a plugin";
@@ -216,20 +368,20 @@ inline void QFactoryLoaderPrivate::updateSinglePath(const QString &path)
// whereas the new one has a Qt version that fits
// better
constexpr int QtVersionNoPatch = QT_VERSION_CHECK(QT_VERSION_MAJOR, QT_VERSION_MINOR, 0);
- QLibraryPrivate *previous = keyMap.value(key);
+ QLibraryPrivate *&previous = keyMap[key];
int prev_qt_version = 0;
if (previous)
prev_qt_version = int(previous->metaData.value(QtPluginMetaDataKeys::QtVersion).toInteger());
int qt_version = int(library->metaData.value(QtPluginMetaDataKeys::QtVersion).toInteger());
if (!previous || (prev_qt_version > QtVersionNoPatch && qt_version <= QtVersionNoPatch)) {
- keyMap[key] = library.get(); // we WILL .release()
+ previous = library.get(); // we WILL .release()
++keyUsageCount;
}
}
if (keyUsageCount || keys.isEmpty()) {
library->setLoadHints(QLibrary::PreventUnloadHint); // once loaded, don't unload
QMutexLocker locker(&mutex);
- libraryList += library.release();
+ libraries.push_back(std::move(library));
}
};
}
@@ -270,7 +422,10 @@ QFactoryLoader::~QFactoryLoader()
QLibraryPrivate *QFactoryLoader::library(const QString &key) const
{
Q_D(const QFactoryLoader);
- return d->keyMap.value(d->cs ? key : key.toLower());
+ const auto it = d->keyMap.find(d->cs ? key : key.toLower());
+ if (it == d->keyMap.cend())
+ return nullptr;
+ return it->second;
}
#endif
@@ -328,7 +483,7 @@ void QFactoryLoader::setExtraSearchPath(const QString &path)
} else {
// must re-scan everything
d->loadedPaths.clear();
- d->libraryList.clear();
+ d->libraries.clear();
d->keyMap.clear();
update();
}
@@ -343,7 +498,7 @@ QFactoryLoader::MetaDataList QFactoryLoader::metaData() const
QList<QPluginParsedMetaData> metaData;
#if QT_CONFIG(library)
QMutexLocker locker(&d->mutex);
- for (QLibraryPrivate *library : std::as_const(d->libraryList))
+ for (const auto &library : d->libraries)
metaData.append(library->metaData);
#endif
@@ -356,6 +511,37 @@ QFactoryLoader::MetaDataList QFactoryLoader::metaData() const
continue;
metaData.append(std::move(parsed));
}
+
+ // other portions of the code will cast to int (e.g., keyMap())
+ Q_ASSERT(metaData.size() <= std::numeric_limits<int>::max());
+ return metaData;
+}
+
+QList<QCborArray> QFactoryLoader::metaDataKeys() const
+{
+ Q_D(const QFactoryLoader);
+ QList<QCborArray> metaData;
+#if QT_CONFIG(library)
+ QMutexLocker locker(&d->mutex);
+ for (const auto &library : d->libraries) {
+ const QCborValue md = library->metaData.value(QtPluginMetaDataKeys::MetaData);
+ metaData.append(md["Keys"_L1].toArray());
+ }
+#endif
+
+ QLatin1StringView iid(d->iid.constData(), d->iid.size());
+ const auto staticPlugins = QPluginLoader::staticPlugins();
+ for (const QStaticPlugin &plugin : staticPlugins) {
+ QByteArrayView pluginData(static_cast<const char *>(plugin.rawMetaData),
+ plugin.rawMetaDataSize);
+ QFactoryLoaderMetaDataKeysExtractor extractor{ iid };
+ iterateInPluginMetaData(pluginData, extractor);
+ if (extractor.matchesIid)
+ metaData += std::move(extractor.keys);
+ }
+
+ // other portions of the code will cast to int (e.g., keyMap())
+ Q_ASSERT(metaData.size() <= std::numeric_limits<int>::max());
return metaData;
}
@@ -367,8 +553,8 @@ QObject *QFactoryLoader::instance(int index) const
#if QT_CONFIG(library)
QMutexLocker lock(&d->mutex);
- if (index < d->libraryList.size()) {
- QLibraryPrivate *library = d->libraryList.at(index);
+ if (size_t(index) < d->libraries.size()) {
+ QLibraryPrivate *library = d->libraries[index].get();
if (QObject *obj = library->pluginInstance()) {
if (!obj->parent())
obj->moveToThread(QCoreApplicationPrivate::mainThread());
@@ -376,7 +562,8 @@ QObject *QFactoryLoader::instance(int index) const
}
return nullptr;
}
- index -= d->libraryList.size();
+ // we know d->libraries.size() <= index <= numeric_limits<decltype(index)>::max() → no overflow
+ index -= static_cast<int>(d->libraries.size());
lock.unlock();
#endif
@@ -384,8 +571,7 @@ QObject *QFactoryLoader::instance(int index) const
const QList<QStaticPlugin> staticPlugins = QPluginLoader::staticPlugins();
for (QStaticPlugin plugin : staticPlugins) {
QByteArrayView pluginData(static_cast<const char *>(plugin.rawMetaData), plugin.rawMetaDataSize);
- QPluginParsedMetaData parsed(pluginData);
- if (parsed.isError() || parsed.value(QtPluginMetaDataKeys::IID) != iid)
+ if (!isIidMatch(pluginData, iid))
continue;
if (index == 0)
@@ -399,10 +585,9 @@ QObject *QFactoryLoader::instance(int index) const
QMultiMap<int, QString> QFactoryLoader::keyMap() const
{
QMultiMap<int, QString> result;
- const QList<QPluginParsedMetaData> metaDataList = metaData();
- for (int i = 0; i < metaDataList.size(); ++i) {
- const QCborMap metaData = metaDataList.at(i).value(QtPluginMetaDataKeys::MetaData).toMap();
- const QCborArray keys = metaData.value("Keys"_L1).toArray();
+ const QList<QCborArray> metaDataList = metaDataKeys();
+ for (int i = 0; i < int(metaDataList.size()); ++i) {
+ const QCborArray &keys = metaDataList[i];
for (QCborValueConstRef key : keys)
result.insert(i, key.toString());
}
@@ -411,10 +596,9 @@ QMultiMap<int, QString> QFactoryLoader::keyMap() const
int QFactoryLoader::indexOf(const QString &needle) const
{
- const QList<QPluginParsedMetaData> metaDataList = metaData();
- for (int i = 0; i < metaDataList.size(); ++i) {
- const QCborMap metaData = metaDataList.at(i).value(QtPluginMetaDataKeys::MetaData).toMap();
- const QCborArray keys = metaData.value("Keys"_L1).toArray();
+ const QList<QCborArray> metaDataList = metaDataKeys();
+ for (int i = 0; i < int(metaDataList.size()); ++i) {
+ const QCborArray &keys = metaDataList[i];
for (QCborValueConstRef key : keys) {
if (key.toString().compare(needle, Qt::CaseInsensitive) == 0)
return i;
diff --git a/src/corelib/plugin/qfactoryloader_p.h b/src/corelib/plugin/qfactoryloader_p.h
index fcfb4cf597..56dc7e6ad1 100644
--- a/src/corelib/plugin/qfactoryloader_p.h
+++ b/src/corelib/plugin/qfactoryloader_p.h
@@ -86,6 +86,7 @@ public:
using MetaDataList = QList<QPluginParsedMetaData>;
MetaDataList metaData() const;
+ QList<QCborArray> metaDataKeys() const;
QObject *instance(int index) const;
};
diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp
index 5459ae15b0..a3ef8e3c52 100644
--- a/src/corelib/plugin/qlibrary.cpp
+++ b/src/corelib/plugin/qlibrary.cpp
@@ -11,7 +11,6 @@
#include <qfile.h>
#include <qfileinfo.h>
#include <qjsondocument.h>
-#include <qmap.h>
#include <qmutex.h>
#include <qoperatingsystemversion.h>
#include <qstringlist.h>
@@ -30,6 +29,8 @@
#include <qtcore_tracepoints_p.h>
+#include <QtCore/q20map.h>
+
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
@@ -258,7 +259,7 @@ static QLibraryScanResult findPatternUnloaded(const QString &library, QLibraryPr
#endif
if (!lib->metaData.parse(QByteArrayView(filedata + r.pos, r.length))) {
errMsg = lib->metaData.errorString();
- qCWarning(qt_lcDebugPlugins, "Found invalid metadata in lib %ls: %ls",
+ qCDebug(qt_lcDebugPlugins, "Found invalid metadata in lib %ls: %ls",
qUtf16Printable(library), qUtf16Printable(errMsg));
} else {
qCDebug(qt_lcDebugPlugins, "Found metadata in lib %ls, metadata=\n%s\n",
@@ -321,7 +322,7 @@ private:
static inline QLibraryStore *instance();
// all members and instance() are protected by qt_library_mutex
- typedef QMap<QString, QLibraryPrivate *> LibraryMap;
+ typedef std::map<QString, QLibraryPrivate *> LibraryMap;
LibraryMap libraryMap;
};
@@ -341,9 +342,7 @@ inline void QLibraryStore::cleanup()
return;
// find any libraries that are still loaded but have a no one attached to them
- LibraryMap::Iterator it = data->libraryMap.begin();
- for (; it != data->libraryMap.end(); ++it) {
- QLibraryPrivate *lib = it.value();
+ for (auto &[_, lib] : data->libraryMap) {
if (lib->libraryRefCount.loadRelaxed() == 1) {
if (lib->libraryUnloadCount.loadRelaxed() > 0) {
Q_ASSERT(lib->pHnd.loadRelaxed());
@@ -357,14 +356,13 @@ inline void QLibraryStore::cleanup()
lib->unload();
#endif
}
- delete lib;
- it.value() = nullptr;
+ delete std::exchange(lib, nullptr);
}
}
// dump all objects that remain
if (lcDebugLibrary().isDebugEnabled()) {
- for (QLibraryPrivate *lib : std::as_const(data->libraryMap)) {
+ for (auto &[_, lib] : data->libraryMap) {
if (lib)
qDebug(lcDebugLibrary)
<< "On QtCore unload," << lib->fileName << "was leaked, with"
@@ -395,26 +393,34 @@ QLibraryStore *QLibraryStore::instance()
inline QLibraryPrivate *QLibraryStore::findOrCreate(const QString &fileName, const QString &version,
QLibrary::LoadHints loadHints)
{
+ auto lazyNewLib = [&] {
+ auto result = new QLibraryPrivate(fileName, version, loadHints);
+ result->libraryRefCount.ref();
+ return result;
+ };
+
+ if (fileName.isEmpty()) // request for empty d-pointer in QLibrary::setLoadHints();
+ return lazyNewLib(); // must return an independent (new) object
+
QMutexLocker locker(&qt_library_mutex);
QLibraryStore *data = instance();
+ if (Q_UNLIKELY(!data)) {
+ locker.unlock();
+ return lazyNewLib();
+ }
+
QString mapName = version.isEmpty() ? fileName : fileName + u'\0' + version;
- // check if this library is already loaded
- QLibraryPrivate *lib = nullptr;
- if (Q_LIKELY(data)) {
- lib = data->libraryMap.value(mapName);
- if (lib)
- lib->mergeLoadHints(loadHints);
+ QLibraryPrivate *&lib = data->libraryMap[std::move(mapName)];
+ if (lib) {
+ // already loaded
+ lib->libraryRefCount.ref();
+ lib->mergeLoadHints(loadHints);
+ } else {
+ lib = lazyNewLib();
}
- if (!lib)
- lib = new QLibraryPrivate(fileName, version, loadHints);
-
- // track this library
- if (Q_LIKELY(data) && !fileName.isEmpty())
- data->libraryMap.insert(mapName, lib);
- lib->libraryRefCount.ref();
return lib;
}
@@ -432,8 +438,9 @@ inline void QLibraryStore::releaseLibrary(QLibraryPrivate *lib)
Q_ASSERT(lib->libraryUnloadCount.loadRelaxed() == 0);
if (Q_LIKELY(data) && !lib->fileName.isEmpty()) {
- qsizetype n = erase_if(data->libraryMap, [lib](LibraryMap::iterator it) {
- return it.value() == lib;
+ using q20::erase_if;
+ const auto n = erase_if(data->libraryMap, [lib](const auto &e) {
+ return e.second == lib;
});
Q_ASSERT_X(n, "~QLibrary", "Did not find this library in the library map");
Q_UNUSED(n);
@@ -465,7 +472,7 @@ void QLibraryPrivate::mergeLoadHints(QLibrary::LoadHints lh)
if (pHnd.loadRelaxed())
return;
- loadHintsInt.storeRelaxed(lh.toInt());
+ loadHintsInt.fetchAndOrRelaxed(lh.toInt());
}
QFunctionPointer QLibraryPrivate::resolve(const char *symbol)
@@ -477,6 +484,13 @@ QFunctionPointer QLibraryPrivate::resolve(const char *symbol)
void QLibraryPrivate::setLoadHints(QLibrary::LoadHints lh)
{
+ // Set the load hints directly for a dummy if this object is not associated
+ // with a file. Such object is not shared between multiple instances.
+ if (fileName.isEmpty()) {
+ loadHintsInt.storeRelaxed(lh.toInt());
+ return;
+ }
+
// this locks a global mutex
QMutexLocker lock(&qt_library_mutex);
mergeLoadHints(lh);
@@ -766,7 +780,7 @@ void QLibraryPrivate::updatePluginState()
uint qt_version = uint(metaData.value(QtPluginMetaDataKeys::QtVersion).toInteger());
bool debug = metaData.value(QtPluginMetaDataKeys::IsDebug).toBool();
if ((qt_version & 0x00ff00) > (QT_VERSION & 0x00ff00) || (qt_version & 0xff0000) != (QT_VERSION & 0xff0000)) {
- qCWarning(qt_lcDebugPlugins, "In %s:\n"
+ qCDebug(qt_lcDebugPlugins, "In %s:\n"
" Plugin uses incompatible Qt library (%d.%d.%d) [%s]",
QFile::encodeName(fileName).constData(),
(qt_version&0xff0000) >> 16, (qt_version&0xff00) >> 8, qt_version&0xff,
@@ -820,7 +834,9 @@ bool QLibrary::load()
call will fail, and unloading will only happen when every instance
has called unload().
- Note that on Mac OS X 10.3 (Panther), dynamic libraries cannot be unloaded.
+ Note that on \macos, dynamic libraries cannot be unloaded.
+ QLibrary::unload() will return \c true, but the library will remain
+ loaded into the process.
\sa resolve(), load()
*/
@@ -834,13 +850,17 @@ bool QLibrary::unload()
}
/*!
- Returns \c true if the library is loaded; otherwise returns \c false.
+ Returns \c true if load() succeeded; otherwise returns \c false.
+
+ \note Prior to Qt 6.6, this function would return \c true even without a
+ call to load() if another QLibrary object on the same library had caused it
+ to be loaded.
\sa load()
*/
bool QLibrary::isLoaded() const
{
- return d && d->pHnd.loadRelaxed();
+ return d.tag() == Loaded;
}
@@ -977,8 +997,7 @@ void QLibrary::setFileNameAndVersion(const QString &fileName, const QString &ver
d->release();
}
QLibraryPrivate *dd = QLibraryPrivate::findOrCreate(fileName, version, lh);
- d = dd;
- d.setTag(isLoaded() ? Loaded : NotLoaded);
+ d = QTaggedPointer(dd, NotLoaded); // we haven't load()ed
}
/*!
@@ -1113,6 +1132,10 @@ QString QLibrary::errorString() const
lazy symbol resolution, and will not export external symbols for resolution
in other dynamically-loaded libraries.
+ \note Hints can only be cleared when this object is not associated with a
+ file. Hints can only be added once the file name is set (\a hints will
+ be or'ed with the old hints).
+
\note Setting this property after the library has been loaded has no effect
and loadHints() will not reflect those changes.
diff --git a/src/corelib/plugin/qlibrary_p.h b/src/corelib/plugin/qlibrary_p.h
index e3bbbe104b..87d36ee5c8 100644
--- a/src/corelib/plugin/qlibrary_p.h
+++ b/src/corelib/plugin/qlibrary_p.h
@@ -28,6 +28,8 @@
# include "QtCore/qt_windows.h"
#endif
+#include <memory>
+
QT_REQUIRE_CONFIG(library);
QT_BEGIN_NAMESPACE
@@ -54,6 +56,12 @@ public:
#endif
enum UnloadFlag { UnloadSys, NoUnloadSys };
+ struct Deleter {
+ // QLibraryPrivate::release() is not, yet, and cannot easily be made, noexcept:
+ void operator()(QLibraryPrivate *p) const { p->release(); }
+ };
+ using UniquePtr = std::unique_ptr<QLibraryPrivate, Deleter>;
+
const QString fileName;
const QString fullVersion;
diff --git a/src/corelib/plugin/qlibrary_unix.cpp b/src/corelib/plugin/qlibrary_unix.cpp
index 4ca205bb7d..a6fb5403cd 100644
--- a/src/corelib/plugin/qlibrary_unix.cpp
+++ b/src/corelib/plugin/qlibrary_unix.cpp
@@ -25,12 +25,6 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-static QString qdlerror()
-{
- const char *err = dlerror();
- return err ? u'(' + QString::fromLocal8Bit(err) + u')' : QString();
-}
-
QStringList QLibraryPrivate::suffixes_sys(const QString &fullVersion)
{
QStringList suffixes;
@@ -199,7 +193,7 @@ bool QLibraryPrivate::load_sys()
continue;
if (loadHints & QLibrary::LoadArchiveMemberHint) {
attempt = name;
- int lparen = attempt.indexOf(u'(');
+ qsizetype lparen = attempt.indexOf(u'(');
if (lparen == -1)
lparen = attempt.size();
attempt = path + prefixes.at(prefix) + attempt.insert(lparen, suffixes.at(suffix));
@@ -213,14 +207,6 @@ bool QLibraryPrivate::load_sys()
auto attemptFromBundle = attempt;
hnd = dlopen(QFile::encodeName(attemptFromBundle.replace(u'/', u'_')), dlFlags);
}
- if (hnd) {
- using JniOnLoadPtr = jint (*)(JavaVM *vm, void *reserved);
- JniOnLoadPtr jniOnLoad = reinterpret_cast<JniOnLoadPtr>(dlsym(hnd, "JNI_OnLoad"));
- if (jniOnLoad && jniOnLoad(QJniEnvironment::javaVM(), nullptr) == JNI_ERR) {
- dlclose(hnd);
- hnd = nullptr;
- }
- }
#endif
if (!hnd && fileName.startsWith(u'/') && QFile::exists(attempt)) {
@@ -250,7 +236,8 @@ bool QLibraryPrivate::load_sys()
locker.relock();
if (!hnd) {
- errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName, qdlerror());
+ errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName,
+ QLatin1StringView(dlerror()));
}
if (hnd) {
qualifiedFileName = attempt;
@@ -262,36 +249,27 @@ bool QLibraryPrivate::load_sys()
bool QLibraryPrivate::unload_sys()
{
- if (dlclose(pHnd.loadAcquire())) {
-#if defined (Q_OS_QNX) // Workaround until fixed in QNX; fixes crash in
- char *error = dlerror(); // QtDeclarative auto test "qqmlenginecleanup" for instance
+ bool doTryUnload = true;
+#ifndef RTLD_NODELETE
+ if (loadHints() & QLibrary::PreventUnloadHint)
+ doTryUnload = false;
+#endif
+ if (doTryUnload && dlclose(pHnd.loadAcquire())) {
+ const char *error = dlerror();
+#if defined (Q_OS_QNX)
+ // Workaround until fixed in QNX; fixes crash in
+ // QtDeclarative auto test "qqmlenginecleanup" for instance
if (!qstrcmp(error, "Shared objects still referenced")) // On QNX that's only "informative"
return true;
+#endif
errorString = QLibrary::tr("Cannot unload library %1: %2").arg(fileName,
QLatin1StringView(error));
-#else
- errorString = QLibrary::tr("Cannot unload library %1: %2").arg(fileName, qdlerror());
-#endif
return false;
}
errorString.clear();
return true;
}
-#if defined(Q_OS_LINUX)
-Q_CORE_EXPORT QFunctionPointer qt_linux_find_symbol_sys(const char *symbol)
-{
- return QFunctionPointer(dlsym(RTLD_DEFAULT, symbol));
-}
-#endif
-
-#ifdef Q_OS_DARWIN
-Q_CORE_EXPORT QFunctionPointer qt_mac_resolve_sys(void *handle, const char *symbol)
-{
- return QFunctionPointer(dlsym(handle, symbol));
-}
-#endif
-
QFunctionPointer QLibraryPrivate::resolve_sys(const char *symbol)
{
QFunctionPointer address = QFunctionPointer(dlsym(pHnd.loadAcquire(), symbol));
diff --git a/src/corelib/plugin/qplugin.qdoc b/src/corelib/plugin/qplugin.qdoc
index dd4aa5f4b0..0ca248a548 100644
--- a/src/corelib/plugin/qplugin.qdoc
+++ b/src/corelib/plugin/qplugin.qdoc
@@ -19,13 +19,10 @@
This macro associates the given \a Identifier (a string literal)
to the interface class called \a ClassName. The \a Identifier must
- be unique. For example:
-
- \snippet plugandpaint/app/interfaces.h 3
+ be unique.
This macro is normally used right after the class definition for
- \a ClassName, in a header file. See the
- \l{tools/plugandpaint/app}{Plug & Paint} example for details.
+ \a ClassName, in a header file.
If you want to use Q_DECLARE_INTERFACE with interface classes
declared in a namespace then you have to make sure the Q_DECLARE_INTERFACE
@@ -53,8 +50,6 @@
\snippet code/doc_src_qplugin.cpp 1
- See the \l{tools/plugandpaint/app}{Plug & Paint} example for details.
-
Note that the class this macro appears on must be default-constructible.
FILE is optional and points to a json file.
diff --git a/src/corelib/plugin/qpluginloader.cpp b/src/corelib/plugin/qpluginloader.cpp
index 599256783e..03b8cfbb84 100644
--- a/src/corelib/plugin/qpluginloader.cpp
+++ b/src/corelib/plugin/qpluginloader.cpp
@@ -71,7 +71,7 @@ using namespace Qt::StringLiterals;
link to plugins statically. You can use QLibrary if you need to
load dynamic libraries in a statically linked application.
- \sa QLibrary, {Plug & Paint Example}
+ \sa QLibrary
*/
static constexpr QLibrary::LoadHints defaultLoadHints = QLibrary::PreventUnloadHint;
@@ -235,7 +235,7 @@ static QString locatePlugin(const QString& fileName)
suffixes.prepend(QString());
// Split up "subdir/filename"
- const int slash = fileName.lastIndexOf(u'/');
+ const qsizetype slash = fileName.lastIndexOf(u'/');
const auto baseName = QStringView{fileName}.mid(slash + 1);
const auto basePath = isAbsolute ? QStringView() : QStringView{fileName}.left(slash + 1); // keep the '/'
@@ -349,10 +349,11 @@ QString QPluginLoader::errorString() const
void QPluginLoader::setLoadHints(QLibrary::LoadHints loadHints)
{
if (!d) {
- d = QLibraryPrivate::findOrCreate(QString()); // ugly, but we need a d-ptr
+ d = QLibraryPrivate::findOrCreate({}, {}, loadHints); // ugly, but we need a d-ptr
d->errorString.clear();
+ } else {
+ d->setLoadHints(loadHints);
}
- d->setLoadHints(loadHints);
}
QLibrary::LoadHints QPluginLoader::loadHints() const
@@ -379,7 +380,19 @@ Q_GLOBAL_STATIC(StaticPluginList, staticPluginList)
*/
void Q_CORE_EXPORT qRegisterStaticPluginFunction(QStaticPlugin plugin)
{
- staticPluginList()->append(plugin);
+ // using operator* because we shouldn't be registering plugins while
+ // unloading the application!
+ StaticPluginList &plugins = *staticPluginList;
+
+ // insert the plugin in the list, sorted by address, so we can detect
+ // duplicate registrations
+ auto comparator = [=](const QStaticPlugin &p1, const QStaticPlugin &p2) {
+ using Less = std::less<decltype(plugin.instance)>;
+ return Less{}(p1.instance, p2.instance);
+ };
+ auto pos = std::lower_bound(plugins.constBegin(), plugins.constEnd(), plugin, comparator);
+ if (pos == plugins.constEnd() || pos->instance != plugin.instance)
+ plugins.insert(pos, plugin);
}
/*!
@@ -390,12 +403,11 @@ void Q_CORE_EXPORT qRegisterStaticPluginFunction(QStaticPlugin plugin)
QObjectList QPluginLoader::staticInstances()
{
QObjectList instances;
- const StaticPluginList *plugins = staticPluginList();
- if (plugins) {
- const int numPlugins = plugins->size();
- instances.reserve(numPlugins);
- for (int i = 0; i < numPlugins; ++i)
- instances += plugins->at(i).instance();
+ if (staticPluginList.exists()) {
+ const StaticPluginList &plugins = *staticPluginList;
+ instances.reserve(plugins.size());
+ for (QStaticPlugin plugin : plugins)
+ instances += plugin.instance();
}
return instances;
}
diff --git a/src/corelib/plugin/quuid.cpp b/src/corelib/plugin/quuid.cpp
index baf9a8bd3e..9c7216c3c5 100644
--- a/src/corelib/plugin/quuid.cpp
+++ b/src/corelib/plugin/quuid.cpp
@@ -301,20 +301,96 @@ static QUuid createFromName(const QUuid &ns, const QByteArray &baseData, QCrypto
*/
/*!
+ \fn QUuid::Id128Bytes qFromBigEndian(QUuid::Id128Bytes src)
+ \since 6.6
+ \relates QUuid::Id128Bytes
+ \overload
+
+ Converts \a src from big-endian byte order and returns the struct holding
+ the binary representation of UUID in host byte order.
+
+ \sa <QtEndian>
+*/
+
+/*!
+ \fn QUuid::Id128Bytes qFromLittleEndian(QUuid::Id128Bytes src)
+ \since 6.6
+ \relates QUuid::Id128Bytes
+ \overload
+
+ Converts \a src from little-endian byte order and returns the struct holding
+ the binary representation of UUID in host byte order.
+
+ \sa <QtEndian>
+*/
+
+/*!
+ \fn QUuid::Id128Bytes qToBigEndian(QUuid::Id128Bytes src)
+ \since 6.6
+ \relates QUuid::Id128Bytes
+ \overload
+
+ Converts \a src from host byte order and returns the struct holding the
+ binary representation of UUID in big-endian byte order.
+
+ \sa <QtEndian>
+*/
+
+/*!
+ \fn QUuid::Id128Bytes qToLittleEndian(QUuid::Id128Bytes src)
+ \since 6.6
+ \relates QUuid::Id128Bytes
+ \overload
+
+ Converts \a src from host byte order and returns the struct holding the
+ binary representation of UUID in little-endian byte order.
+
+ \sa <QtEndian>
+*/
+
+/*!
\fn QUuid::QUuid(Id128Bytes id128, QSysInfo::Endian order) noexcept
\since 6.6
- Creates a QUuid based on the integral \a id128 parameter and respecting the
- byte order \a order.
+ Creates a QUuid based on the integral \a id128 parameter. The input
+ \a id128 parameter is considered to have byte order \a order.
+
+ \sa fromBytes(), toBytes(), toRfc4122(), toUInt128()
+*/
+
+/*!
+ \fn QUuid::fromUInt128(quint128 uuid, QSysInfo::Endian order) noexcept
+ \since 6.6
+
+ Creates a QUuid based on the integral \a uuid parameter. The input \a uuid
+ parameter is considered to have byte order \a order.
- \sa fromBytes(), toBytes(), toRfc4122()
+ \note This function is only present on platforms that offer a 128-bit
+ integer type.
+
+ \sa toUInt128(), fromBytes(), toBytes(), toRfc4122()
+*/
+
+/*!
+ \fn quint128 QUuid::toUInt128(QSysInfo::Endian order) const noexcept
+ \since 6.6
+
+ Returns a 128-bit integer created from this QUuid on the byte order
+ specified by \a order. The binary content of this function is the same as
+ toRfc4122() if the order is QSysInfo::BigEndian. See that function for more
+ details.
+
+ \note This function is only present on platforms that offer a 128-bit
+ integer type.
+
+ \sa toRfc4122(), fromUInt128(), toBytes(), fromBytes(), QUuid()
*/
/*!
\fn QUuid::Id128Bytes QUuid::toBytes(QSysInfo::Endian order) const noexcept
\since 6.6
- Returns an 128-bit ID created from this QUuid on the byte order specified
+ Returns a 128-bit ID created from this QUuid on the byte order specified
by \a order. The binary content of this function is the same as toRfc4122()
if the order is QSysInfo::BigEndian. See that function for more details.
@@ -669,13 +745,15 @@ QByteArray QUuid::toRfc4122() const
*/
QDataStream &operator<<(QDataStream &s, const QUuid &id)
{
- QByteArray bytes;
+ constexpr int NumBytes = sizeof(QUuid);
+ static_assert(NumBytes == 16, "Change the serialization format when this ever hits");
+ char bytes[NumBytes];
if (s.byteOrder() == QDataStream::BigEndian) {
- bytes = id.toRfc4122();
+ const auto id128 = id.toBytes();
+ static_assert(sizeof(id128) == NumBytes);
+ memcpy(bytes, &id128, NumBytes);
} else {
- // we know how many bytes a UUID has, I hope :)
- bytes = QByteArray(16, Qt::Uninitialized);
- uchar *data = reinterpret_cast<uchar *>(bytes.data());
+ auto *data = bytes;
// for historical reasons, our little-endian serialization format
// stores each of the UUID fields in little endian, instead of storing
@@ -693,9 +771,9 @@ QDataStream &operator<<(QDataStream &s, const QUuid &id)
}
}
- if (s.writeRawData(bytes.data(), 16) != 16) {
+ if (s.writeRawData(bytes, NumBytes) != NumBytes)
s.setStatus(QDataStream::WriteFailed);
- }
+
return s;
}
@@ -914,7 +992,7 @@ QUuid QUuid::createUuid()
return result;
}
-#else // Q_OS_WIN
+#elif !defined(QT_BOOTSTRAPPED)
QUuid QUuid::createUuid()
{
@@ -928,7 +1006,7 @@ QUuid QUuid::createUuid()
return result;
}
-#endif // !Q_OS_WIN
+#endif // !Q_OS_WIN && !QT_BOOTSTRAPPED
/*!
\fn bool QUuid::operator==(const GUID &guid) const
diff --git a/src/corelib/plugin/quuid.h b/src/corelib/plugin/quuid.h
index 9ba6564ef0..7125e8e2cc 100644
--- a/src/corelib/plugin/quuid.h
+++ b/src/corelib/plugin/quuid.h
@@ -55,24 +55,44 @@ public:
Id128 = 3
};
- union Id128Bytes {
+ union alignas(16) Id128Bytes {
quint8 data[16];
quint16 data16[8];
quint32 data32[4];
quint64 data64[2];
+#if defined(__SIZEOF_INT128__)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Wpedantic") // ISO C++ does not support ‘__int128’ for ‘data128’
+ unsigned __int128 data128[1];
+QT_WARNING_POP
+#elif defined(QT_SUPPORTS_INT128)
+# error "struct QUuid::Id128Bytes should not depend on QT_SUPPORTS_INT128 for ABI reasons."
+# error "Adjust the declaration of the `data128` member above so it is always defined if it's " \
+ "supported by the current compiler/architecture in any configuration."
+#endif
constexpr explicit operator QByteArrayView() const noexcept
{
return QByteArrayView(data, sizeof(data));
}
+
+ friend constexpr Id128Bytes qbswap(Id128Bytes b) noexcept
+ {
+ // 128-bit byte swap
+ auto b0 = qbswap(b.data64[0]);
+ auto b1 = qbswap(b.data64[1]);
+ b.data64[0] = b1;
+ b.data64[1] = b0;
+ return b;
+ }
};
- constexpr QUuid() noexcept {}
+ constexpr QUuid() noexcept : data1(0), data2(0), data3(0), data4{0,0,0,0,0,0,0,0} {}
constexpr QUuid(uint l, ushort w1, ushort w2, uchar b1, uchar b2, uchar b3,
uchar b4, uchar b5, uchar b6, uchar b7, uchar b8) noexcept
: data1(l), data2(w1), data3(w2), data4{b1, b2, b3, b4, b5, b6, b7, b8} {}
- QUuid(Id128Bytes id128, QSysInfo::Endian order = QSysInfo::BigEndian) noexcept;
+ explicit inline QUuid(Id128Bytes id128, QSysInfo::Endian order = QSysInfo::BigEndian) noexcept;
explicit QUuid(QAnyStringView string) noexcept
: QUuid{fromString(string)} {}
@@ -86,10 +106,10 @@ public:
#endif
QString toString(StringFormat mode = WithBraces) const;
QByteArray toByteArray(StringFormat mode = WithBraces) const;
- Id128Bytes toBytes(QSysInfo::Endian order = QSysInfo::BigEndian) const noexcept;
+ inline Id128Bytes toBytes(QSysInfo::Endian order = QSysInfo::BigEndian) const noexcept;
QByteArray toRfc4122() const;
- static QUuid fromBytes(const void *bytes, QSysInfo::Endian order = QSysInfo::BigEndian) noexcept;
+ static inline QUuid fromBytes(const void *bytes, QSysInfo::Endian order = QSysInfo::BigEndian);
#if QT_CORE_REMOVED_SINCE(6, 3)
static QUuid fromRfc4122(const QByteArray &);
#endif
@@ -97,6 +117,11 @@ public:
bool isNull() const noexcept;
+#ifdef QT_SUPPORTS_INT128
+ static constexpr QUuid fromUInt128(quint128 uuid, QSysInfo::Endian order = QSysInfo::BigEndian) noexcept;
+ constexpr quint128 toUInt128(QSysInfo::Endian order = QSysInfo::BigEndian) const noexcept;
+#endif
+
constexpr bool operator==(const QUuid &orig) const noexcept
{
if (data1 != orig.data1 || data2 != orig.data2 ||
@@ -175,20 +200,10 @@ public:
NSUUID *toNSUUID() const Q_DECL_NS_RETURNS_AUTORELEASED;
#endif
- uint data1 = 0;
- ushort data2 = 0;
- ushort data3 = 0;
- uchar data4[8] = {};
-
-private:
- static constexpr Id128Bytes bswap(Id128Bytes b)
- {
- // 128-bit byte swap
- b.data64[0] = qbswap(b.data64[0]);
- b.data64[1] = qbswap(b.data64[1]);
- qSwap(b.data64[0], b.data64[1]);
- return b;
- }
+ uint data1;
+ ushort data2;
+ ushort data3;
+ uchar data4[8];
};
Q_DECLARE_TYPEINFO(QUuid, Q_PRIMITIVE_TYPE);
@@ -204,17 +219,17 @@ Q_CORE_EXPORT QDebug operator<<(QDebug, const QUuid &);
Q_CORE_EXPORT size_t qHash(const QUuid &uuid, size_t seed = 0) noexcept;
-inline QUuid::QUuid(Id128Bytes uuid, QSysInfo::Endian order) noexcept
+QUuid::QUuid(Id128Bytes uuid, QSysInfo::Endian order) noexcept
{
if (order == QSysInfo::LittleEndian)
- uuid = bswap(uuid);
+ uuid = qbswap(uuid);
data1 = qFromBigEndian<quint32>(&uuid.data[0]);
data2 = qFromBigEndian<quint16>(&uuid.data[4]);
data3 = qFromBigEndian<quint16>(&uuid.data[6]);
memcpy(data4, &uuid.data[8], sizeof(data4));
}
-inline QUuid::Id128Bytes QUuid::toBytes(QSysInfo::Endian order) const noexcept
+QUuid::Id128Bytes QUuid::toBytes(QSysInfo::Endian order) const noexcept
{
Id128Bytes result = {};
qToBigEndian(data1, &result.data[0]);
@@ -222,22 +237,74 @@ inline QUuid::Id128Bytes QUuid::toBytes(QSysInfo::Endian order) const noexcept
qToBigEndian(data3, &result.data[6]);
memcpy(&result.data[8], data4, sizeof(data4));
if (order == QSysInfo::LittleEndian)
- return bswap(result);
+ return qbswap(result);
return result;
}
-inline QUuid QUuid::fromBytes(const void *bytes, QSysInfo::Endian order) noexcept
+QUuid QUuid::fromBytes(const void *bytes, QSysInfo::Endian order)
{
Id128Bytes result = {};
memcpy(result.data, bytes, sizeof(result));
return QUuid(result, order);
}
+#ifdef QT_SUPPORTS_INT128
+constexpr QUuid QUuid::fromUInt128(quint128 uuid, QSysInfo::Endian order) noexcept
+{
+ QUuid result = {};
+ if (order == QSysInfo::BigEndian) {
+ result.data1 = qFromBigEndian<quint32>(int(uuid));
+ result.data2 = qFromBigEndian<quint16>(ushort(uuid >> 32));
+ result.data3 = qFromBigEndian<quint16>(ushort(uuid >> 48));
+ for (int i = 0; i < 8; ++i)
+ result.data4[i] = uchar(uuid >> (64 + i * 8));
+ } else {
+ result.data1 = qFromLittleEndian<quint32>(uint(uuid >> 96));
+ result.data2 = qFromLittleEndian<quint16>(ushort(uuid >> 80));
+ result.data3 = qFromLittleEndian<quint16>(ushort(uuid >> 64));
+ for (int i = 0; i < 8; ++i)
+ result.data4[i] = uchar(uuid >> (56 - i * 8));
+ }
+ return result;
+}
+
+constexpr quint128 QUuid::toUInt128(QSysInfo::Endian order) const noexcept
+{
+ quint128 result = {};
+ if (order == QSysInfo::BigEndian) {
+ for (int i = 0; i < 8; ++i)
+ result |= quint64(data4[i]) << (i * 8);
+ result = result << 64;
+ result |= quint64(qToBigEndian<quint16>(data3)) << 48;
+ result |= quint64(qToBigEndian<quint16>(data2)) << 32;
+ result |= qToBigEndian<quint32>(data1);
+ } else {
+ result = qToLittleEndian<quint32>(data1);
+ result = result << 32;
+ result |= quint64(qToLittleEndian<quint16>(data2)) << 16;
+ result |= quint64(qToLittleEndian<quint16>(data3));
+ result = result << 64;
+ for (int i = 0; i < 8; ++i)
+ result |= quint64(data4[i]) << (56 - i * 8);
+ }
+ return result;
+}
+#endif
+
inline bool operator<=(const QUuid &lhs, const QUuid &rhs) noexcept
{ return !(rhs < lhs); }
inline bool operator>=(const QUuid &lhs, const QUuid &rhs) noexcept
{ return !(lhs < rhs); }
+#if defined(Q_QDOC)
+// provide fake declarations of qXXXEndian() functions, so that qDoc could
+// distinguish them from the general template
+QUuid::Id128Bytes qFromBigEndian(QUuid::Id128Bytes src);
+QUuid::Id128Bytes qFromLittleEndian(QUuid::Id128Bytes src);
+QUuid::Id128Bytes qToBigEndian(QUuid::Id128Bytes src);
+QUuid::Id128Bytes qToLittleEndian(QUuid::Id128Bytes src);
+#endif
+
QT_END_NAMESPACE
#endif // QUUID_H
diff --git a/src/corelib/qt_cmdline.cmake b/src/corelib/qt_cmdline.cmake
index fecc43cce6..dddb74cbaf 100644
--- a/src/corelib/qt_cmdline.cmake
+++ b/src/corelib/qt_cmdline.cmake
@@ -2,7 +2,6 @@
# SPDX-License-Identifier: BSD-3-Clause
qt_commandline_option(doubleconversion TYPE enum VALUES no qt system)
-qt_commandline_option(eventfd TYPE boolean)
qt_commandline_option(glib TYPE boolean)
qt_commandline_option(icu TYPE boolean)
qt_commandline_option(inotify TYPE boolean)
diff --git a/src/corelib/serialization/make-xml-parser.sh b/src/corelib/serialization/make-xml-parser.sh
index c34a8795b1..1889833700 100755
--- a/src/corelib/serialization/make-xml-parser.sh
+++ b/src/corelib/serialization/make-xml-parser.sh
@@ -1,6 +1,6 @@
#!/bin/sh
# Copyright (C) 2016 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
me=$(dirname $0)
mkdir -p $me/out
diff --git a/src/corelib/serialization/qcborarray.cpp b/src/corelib/serialization/qcborarray.cpp
index dc373533c5..626fb49a70 100644
--- a/src/corelib/serialization/qcborarray.cpp
+++ b/src/corelib/serialization/qcborarray.cpp
@@ -19,6 +19,10 @@ using namespace QtCbor;
\brief The QCborArray class is used to hold an array of CBOR elements.
+ \compares strong
+ \compareswith strong QCborValueConstRef
+ \endcompareswith
+
This class can be used to hold one sequential container in CBOR (an array).
CBOR is the Concise Binary Object Representation, a very compact form of
binary data encoding that is a superset of JSON. It was created by the IETF
@@ -31,8 +35,8 @@ using namespace QtCbor;
from those two, though there may be loss of information in some
conversions.
- \sa QCborValue, QCborMap, QJsonArray, QList, {Cbordump Example},
- {Convert Example}, {JSON Save Game Example}
+ \sa QCborValue, QCborMap, QJsonArray, QList, {Parsing and displaying CBOR data},
+ {Serialization Converter}, {Saving and Loading a Game}
*/
/*!
@@ -420,7 +424,7 @@ void QCborArray::removeAt(qsizetype i)
bool QCborArray::contains(const QCborValue &value) const
{
for (qsizetype i = 0; i < size(); ++i) {
- int cmp = d->compareElement(i, value);
+ int cmp = d->compareElement(i, value, Comparison::ForEquality);
if (cmp == 0)
return true;
}
@@ -442,9 +446,9 @@ bool QCborArray::contains(const QCborValue &value) const
*/
/*!
- \fn bool QCborArray::operator==(const QCborArray &other) const
+ \fn bool QCborArray::operator==(const QCborArray &lhs, const QCborArray &rhs)
- Compares this array and \a other, comparing each element in sequence, and
+ Compares \a lhs and \a rhs arrays, comparing each element in sequence, and
returns true if both arrays contains the same elements, false otherwise.
For more information on CBOR equality in Qt, see, QCborValue::compare().
@@ -454,9 +458,9 @@ bool QCborArray::contains(const QCborValue &value) const
*/
/*!
- \fn bool QCborArray::operator!=(const QCborArray &other) const
+ \fn bool QCborArray::operator!=(const QCborArray &lhs, const QCborArray &rhs)
- Compares this array and \a other, comparing each element in sequence, and
+ Compares \a lhs and \a rhs arrays, comparing each element in sequence, and
returns true if the two arrays' contents are different, false otherwise.
For more information on CBOR equality in Qt, see, QCborValue::compare().
@@ -466,19 +470,58 @@ bool QCborArray::contains(const QCborValue &value) const
*/
/*!
- \fn bool QCborArray::operator<(const QCborArray &other) const
+ \fn bool QCborArray::operator<(const QCborArray &lhs, const QCborArray &rhs)
- Compares this array and \a other, comparing each element in sequence, and
- returns true if this array should be sorted before \a other, false
+ Compares \a lhs and \a rhs arrays, comparing each element in sequence, and
+ returns true if \a lhs array should be sorted before \a rhs, false
otherwise.
For more information on CBOR sorting order, see QCborValue::compare().
\sa compare(), QCborValue::operator==(), QCborMap::operator==(),
- operator==(), operator!=()
+ operator==(), operator!=(), operator<=()
*/
/*!
+ \fn bool QCborArray::operator<=(const QCborArray &lhs, const QCborArray &rhs)
+
+ Compares \a lhs and \a rhs arrays, comparing each element in sequence, and
+ returns true if \a lhs array should be sorted before \a rhs, or if both
+ arrays contains the same elements, false otherwise.
+
+ For more information on CBOR sorting order, see QCborValue::compare().
+
+ \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
+ operator==(), operator!=(), operator<()
+*/
+
+/*!
+ \fn bool QCborArray::operator>(const QCborArray &lhs, const QCborArray &rhs)
+
+ Compares \a lhs and \a rhs arrays, comparing each element in sequence, and
+ returns true if \a lhs array should be sorted after \a rhs, false
+ otherwise.
+
+ For more information on CBOR sorting order, see QCborValue::compare().
+
+ \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
+ operator==(), operator!=(), operator>=()
+*/
+
+/*!
+ \fn bool QCborArray::operator>=(const QCborArray &lhs, const QCborArray &rhs)
+
+ Compares \a lhs and \a rhs arrays, comparing each element in sequence, and
+ returns true if \a lhs array should be sorted after \a rhs, or if both
+ arrays contains the same elements, false otherwise.
+
+ For more information on CBOR sorting order, see QCborValue::compare().
+
+ \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
+ operator==(), operator!=(), operator>()
+*/
+
+/*!
\typedef QCborArray::iterator
A synonym to QCborArray::Iterator.
@@ -679,6 +722,10 @@ void QCborArray::detach(qsizetype reserved)
\brief The QCborArray::Iterator class provides an STL-style non-const iterator for QCborArray.
+ \compares strong
+ \compareswith strong QCborArray::ConstIterator
+ \endcompareswith
+
QCborArray::Iterator allows you to iterate over a QCborArray and to modify
the array item associated with the iterator. If you want to iterate over a
const QCborArray, use QCborArray::ConstIterator instead. It is generally a
@@ -793,56 +840,56 @@ void QCborArray::detach(qsizetype reserved)
*/
/*!
- \fn bool QCborArray::Iterator::operator==(const Iterator &other) const
- \fn bool QCborArray::Iterator::operator==(const ConstIterator &other) const
+ \fn bool QCborArray::Iterator::operator==(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborArray::Iterator::operator==(const Iterator &lhs, const ConstIterator &rhs)
- Returns \c true if \a other points to the same entry in the array as this
+ Returns \c true if \a lhs points to the same entry in the array as \a rhs
iterator; otherwise returns \c false.
\sa operator!=()
*/
/*!
- \fn bool QCborArray::Iterator::operator!=(const Iterator &other) const
- \fn bool QCborArray::Iterator::operator!=(const ConstIterator &other) const
+ \fn bool QCborArray::Iterator::operator!=(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborArray::Iterator::operator!=(const Iterator &lhs, const ConstIterator &rhs)
- Returns \c true if \a other points to a different entry in the array than
- this iterator; otherwise returns \c false.
+ Returns \c true if \a lhs points to a different entry in the array than
+ \a rhs iterator; otherwise returns \c false.
\sa operator==()
*/
/*!
- \fn bool QCborArray::Iterator::operator<(const Iterator& other) const
- \fn bool QCborArray::Iterator::operator<(const ConstIterator& other) const
+ \fn bool QCborArray::Iterator::operator<(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborArray::Iterator::operator<(const Iterator &lhs, const ConstIterator &rhs)
- Returns \c true if the entry in the array pointed to by this iterator
- occurs before the entry pointed to by the \a other iterator.
+ Returns \c true if the entry in the array pointed to by \a lhs iterator
+ occurs before the entry pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QCborArray::Iterator::operator<=(const Iterator& other) const
- \fn bool QCborArray::Iterator::operator<=(const ConstIterator& other) const
+ \fn bool QCborArray::Iterator::operator<=(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborArray::Iterator::operator<=(const Iterator &lhs, const ConstIterator &rhs)
- Returns \c true if the entry in the array pointed to by this iterator
- occurs before or is the same entry as is pointed to by the \a other
+ Returns \c true if the entry in the array pointed to by \a lhs iterator
+ occurs before or is the same entry as is pointed to by the \a rhs
iterator.
*/
/*!
- \fn bool QCborArray::Iterator::operator>(const Iterator& other) const
- \fn bool QCborArray::Iterator::operator>(const ConstIterator& other) const
+ \fn bool QCborArray::Iterator::operator>(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborArray::Iterator::operator>(const Iterator &lhs, const ConstIterator &rhs)
- Returns \c true if the entry in the array pointed to by this iterator
- occurs after the entry pointed to by the \a other iterator.
+ Returns \c true if the entry in the array pointed to by \a lhs iterator
+ occurs after the entry pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QCborArray::Iterator::operator>=(const Iterator& other) const
- \fn bool QCborArray::Iterator::operator>=(const ConstIterator& other) const
+ \fn bool QCborArray::Iterator::operator>=(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborArray::Iterator::operator>=(const Iterator &lhs, const ConstIterator &rhs)
- Returns \c true if the entry in the array pointed to by this iterator
- occurs after or is the same entry as is pointed to by the \a other
+ Returns \c true if the entry in the array pointed to by \a lhs iterator
+ occurs after or is the same entry as is pointed to by the \a rhs
iterator.
*/
@@ -934,6 +981,10 @@ void QCborArray::detach(qsizetype reserved)
\brief The QCborArray::ConstIterator class provides an STL-style const iterator for QCborArray.
+ \compares strong
+ \compareswith strong QCborArray::Iterator
+ \endcompareswith
+
QCborArray::ConstIterator allows you to iterate over a QCborArray. If you
want to modify the QCborArray as you iterate over it, use
QCborArray::Iterator instead. It is generally good practice to use
@@ -1033,56 +1084,50 @@ void QCborArray::detach(qsizetype reserved)
*/
/*!
- \fn bool QCborArray::ConstIterator::operator==(const Iterator &other) const
- \fn bool QCborArray::ConstIterator::operator==(const ConstIterator &other) const
+ \fn bool QCborArray::ConstIterator::operator==(const ConstIterator &lhs, const ConstIterator &rhs)
- Returns \c true if \a other points to the same entry in the array as this
+ Returns \c true if \a lhs points to the same entry in the array as \a rhs
iterator; otherwise returns \c false.
\sa operator!=()
*/
/*!
- \fn bool QCborArray::ConstIterator::operator!=(const Iterator &o) const
- \fn bool QCborArray::ConstIterator::operator!=(const ConstIterator &o) const
+ \fn bool QCborArray::ConstIterator::operator!=(const ConstIterator &lhs, const ConstIterator &rhs)
- Returns \c true if \a o points to a different entry in the array than
- this iterator; otherwise returns \c false.
+ Returns \c true if \a lhs points to a different entry in the array than
+ \a rhs iterator; otherwise returns \c false.
\sa operator==()
*/
/*!
- \fn bool QCborArray::ConstIterator::operator<(const Iterator &other) const
- \fn bool QCborArray::ConstIterator::operator<(const ConstIterator &other) const
+ \fn bool QCborArray::ConstIterator::operator<(const ConstIterator &lhs, const ConstIterator &rhs)
- Returns \c true if the entry in the array pointed to by this iterator
- occurs before the entry pointed to by the \a other iterator.
+ Returns \c true if the entry in the array pointed to by \a lhs iterator
+ occurs before the entry pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QCborArray::ConstIterator::operator<=(const Iterator &other) const
- \fn bool QCborArray::ConstIterator::operator<=(const ConstIterator &other) const
+ \fn bool QCborArray::ConstIterator::operator<=(const ConstIterator &lhs, const ConstIterator &rhs)
- Returns \c true if the entry in the array pointed to by this iterator
- occurs before or is the same entry as is pointed to by the \a other
+ Returns \c true if the entry in the array pointed to by \a lhs iterator
+ occurs before or is the same entry as is pointed to by the \a rhs
iterator.
*/
/*!
- \fn bool QCborArray::ConstIterator::operator>(const Iterator &other) const
- \fn bool QCborArray::ConstIterator::operator>(const ConstIterator &other) const
+ \fn bool QCborArray::ConstIterator::operator>(const ConstIterator &lhs, const ConstIterator &rhs)
- Returns \c true if the entry in the array pointed to by this iterator
- occurs after the entry pointed to by the \a other iterator.
+ Returns \c true if the entry in the array pointed to by \a lhs iterator
+ occurs after the entry pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QCborArray::ConstIterator::operator>=(const Iterator &other) const
- \fn bool QCborArray::ConstIterator::operator>=(const ConstIterator &other) const
+ \fn bool QCborArray::ConstIterator::operator>=(const ConstIterator &lhs, const ConstIterator &rhs)
- Returns \c true if the entry in the array pointed to by this iterator
- occurs after or is the same entry as is pointed to by the \a other
+ Returns \c true if the entry in the array pointed to by \a lhs iterator
+ occurs after or is the same entry as is pointed to by the \a rhs
iterator.
*/
diff --git a/src/corelib/serialization/qcborarray.h b/src/corelib/serialization/qcborarray.h
index 2ac778ce47..481f316f33 100644
--- a/src/corelib/serialization/qcborarray.h
+++ b/src/corelib/serialization/qcborarray.h
@@ -46,19 +46,20 @@ public:
QCborValueRef *operator->() { return &item; }
const QCborValueConstRef *operator->() const { return &item; }
QCborValueRef operator[](qsizetype j) const { return { item.d, item.i + j }; }
-
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const Iterator &o) const { return item.d == o.item.d && item.i == o.item.i; }
- bool operator!=(const Iterator &o) const { return !(*this == o); }
+ bool operator!=(const Iterator &o) const { return !operator==(o); }
bool operator<(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i < other.item.i; }
bool operator<=(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i <= other.item.i; }
bool operator>(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i > other.item.i; }
bool operator>=(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i >= other.item.i; }
bool operator==(const ConstIterator &o) const { return item.d == o.item.d && item.i == o.item.i; }
- bool operator!=(const ConstIterator &o) const { return !(*this == o); }
+ bool operator!=(const ConstIterator &o) const { return !operator==(o); }
bool operator<(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i < other.item.i; }
bool operator<=(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i <= other.item.i; }
bool operator>(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i > other.item.i; }
bool operator>=(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i >= other.item.i; }
+#endif
Iterator &operator++() { ++item.i; return *this; }
Iterator operator++(int) { Iterator n = *this; ++item.i; return n; }
Iterator &operator--() { item.i--; return *this; }
@@ -68,6 +69,53 @@ public:
Iterator operator+(qsizetype j) const { return Iterator({ item.d, item.i + j }); }
Iterator operator-(qsizetype j) const { return Iterator({ item.d, item.i - j }); }
qsizetype operator-(Iterator j) const { return item.i - j.item.i; }
+ private:
+ // Helper functions
+ static bool comparesEqual_helper(const Iterator &lhs, const Iterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.i == rhs.item.i;
+ }
+
+ static bool comparesEqual_helper(const Iterator &lhs, const ConstIterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.i == rhs.item.i;
+ }
+
+ static Qt::strong_ordering compareThreeWay_helper(const Iterator &lhs,
+ const Iterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.i, rhs.item.i);
+ }
+
+ static Qt::strong_ordering compareThreeWay_helper(const Iterator &lhs,
+ const ConstIterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.i, rhs.item.i);
+ }
+
+ // Compare friends
+ friend bool comparesEqual(const Iterator &lhs, const Iterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const Iterator &lhs,
+ const Iterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(Iterator)
+ friend bool comparesEqual(const Iterator &lhs, const ConstIterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const Iterator &lhs,
+ const ConstIterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(Iterator, ConstIterator)
};
class ConstIterator {
@@ -95,19 +143,20 @@ public:
QCborValueConstRef operator*() const { return item; }
const QCborValueConstRef *operator->() const { return &item; }
QCborValueConstRef operator[](qsizetype j) const { return QCborValueRef{ item.d, item.i + j }; }
-
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const Iterator &o) const { return item.d == o.item.d && item.i == o.item.i; }
- bool operator!=(const Iterator &o) const { return !(*this == o); }
+ bool operator!=(const Iterator &o) const { return !operator==(o); }
bool operator<(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i < other.item.i; }
bool operator<=(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i <= other.item.i; }
bool operator>(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i > other.item.i; }
bool operator>=(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i >= other.item.i; }
bool operator==(const ConstIterator &o) const { return item.d == o.item.d && item.i == o.item.i; }
- bool operator!=(const ConstIterator &o) const { return !(*this == o); }
+ bool operator!=(const ConstIterator &o) const { return !operator==(o); }
bool operator<(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i < other.item.i; }
bool operator<=(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i <= other.item.i; }
bool operator>(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i > other.item.i; }
bool operator>=(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i >= other.item.i; }
+#endif
ConstIterator &operator++() { ++item.i; return *this; }
ConstIterator operator++(int) { ConstIterator n = *this; ++item.i; return n; }
ConstIterator &operator--() { item.i--; return *this; }
@@ -117,6 +166,31 @@ public:
ConstIterator operator+(qsizetype j) const { return ConstIterator({ item.d, item.i + j }); }
ConstIterator operator-(qsizetype j) const { return ConstIterator({ item.d, item.i - j }); }
qsizetype operator-(ConstIterator j) const { return item.i - j.item.i; }
+ private:
+ // Helper functions
+ static bool comparesEqual_helper(const ConstIterator &lhs,
+ const ConstIterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.i == rhs.item.i;
+ }
+ static Qt::strong_ordering compareThreeWay_helper(const ConstIterator &lhs,
+ const ConstIterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.i, rhs.item.i);
+ }
+
+ // Compare friends
+ friend bool comparesEqual(const ConstIterator &lhs, const ConstIterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const ConstIterator &lhs,
+ const ConstIterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(ConstIterator)
};
typedef qsizetype size_type;
@@ -181,19 +255,11 @@ public:
bool contains(const QCborValue &value) const;
int compare(const QCborArray &other) const noexcept Q_DECL_PURE_FUNCTION;
-#if 0 && __has_include(<compare>)
- std::strong_ordering operator<=>(const QCborArray &other) const
- {
- int c = compare(other);
- if (c > 0) return std::strong_ordering::greater;
- if (c == 0) return std::strong_ordering::equivalent;
- return std::strong_ordering::less;
- }
-#else
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QCborArray &other) const noexcept
{ return compare(other) == 0; }
bool operator!=(const QCborArray &other) const noexcept
- { return !(*this == other); }
+ { return !operator==(other); }
bool operator<(const QCborArray &other) const
{ return compare(other) < 0; }
#endif
@@ -237,6 +303,48 @@ public:
QJsonArray toJsonArray() const;
private:
+ friend Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool
+ comparesEqual(const QCborArray &lhs, const QCborArray &rhs) noexcept;
+ friend Qt::strong_ordering compareThreeWay(const QCborArray &lhs,
+ const QCborArray &rhs) noexcept
+ {
+ int c = lhs.compare(rhs);
+ return Qt::compareThreeWay(c, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QCborArray)
+
+ static Q_DECL_PURE_FUNCTION bool
+ comparesEqual_helper(const QCborArray &lhs, const QCborValue &rhs) noexcept;
+ static Q_DECL_PURE_FUNCTION Qt::strong_ordering
+ compareThreeWay_helper(const QCborArray &lhs, const QCborValue &rhs) noexcept;
+ friend bool comparesEqual(const QCborArray &lhs,
+ const QCborValue &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const QCborArray &lhs,
+ const QCborValue &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QCborArray, QCborValue)
+
+ static Q_DECL_PURE_FUNCTION bool
+ comparesEqual_helper(const QCborArray &lhs, QCborValueConstRef rhs) noexcept;
+ static Q_DECL_PURE_FUNCTION Qt::strong_ordering
+ compareThreeWay_helper(const QCborArray &lhs, QCborValueConstRef rhs) noexcept;
+ friend bool comparesEqual(const QCborArray &lhs,
+ const QCborValueConstRef &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const QCborArray &lhs,
+ const QCborValueConstRef &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QCborArray, QCborValueConstRef)
+
void detach(qsizetype reserve = 0);
friend QCborValue;
diff --git a/src/corelib/serialization/qcborcommon.cpp b/src/corelib/serialization/qcborcommon.cpp
index 66d6dcd685..b3d4f70aa2 100644
--- a/src/corelib/serialization/qcborcommon.cpp
+++ b/src/corelib/serialization/qcborcommon.cpp
@@ -179,8 +179,9 @@ QDataStream &operator>>(QDataStream &ds, QCborSimpleType &st)
\brief The QCborError class holds the error condition found while parsing or
validating a CBOR stream.
- \sa QCborStreamReader, QCborValue, QCborParserError
- \sa {Cbordump Example}, {Convert Example}, {JSON Save Game Example}
+ \sa QCborStreamReader, QCborValue, QCborParserError,
+ {Parsing and displaying CBOR data}, {Serialization Converter},
+ {Saving and Loading a Game}
*/
/*!
diff --git a/src/corelib/serialization/qcbormap.cpp b/src/corelib/serialization/qcbormap.cpp
index 3b16c309b0..038e0d61ce 100644
--- a/src/corelib/serialization/qcbormap.cpp
+++ b/src/corelib/serialization/qcbormap.cpp
@@ -18,6 +18,10 @@ using namespace QtCbor;
\brief The QCborMap class is used to hold an associative container representable in CBOR.
+ \compares strong
+ \compareswith strong QCborValue QCborValueConstRef
+ \endcompareswith
+
This class can be used to hold an associative container in CBOR, a map
between a key and a value type. CBOR is the Concise Binary Object
Representation, a very compact form of binary data encoding that is a
@@ -47,8 +51,9 @@ using namespace QtCbor;
stringified using a one-way method that the conversion back to QCborMap
will not undo.
- \sa QCborArray, QCborValue, QJsonDocument, QVariantMap, {Cbordump Example}
- \sa {Convert Example}, {JSON Save Game Example}
+ \sa QCborArray, QCborValue, QJsonDocument, QVariantMap,
+ {Parsing and displaying CBOR data}, {Serialization Converter},
+ {Saving and Loading a Game}
*/
/*!
@@ -1104,10 +1109,10 @@ QCborValue QCborMap::extract(iterator it)
*/
/*!
- \fn bool QCborMap::operator==(const QCborMap &other) const
+ \fn bool QCborMap::operator==(const QCborMap &lhs, const QCborMap &rhs)
- Compares this map and \a other, comparing each element in sequence, and
- returns true if the two maps contains the same elements in the same order,
+ Compares \a lhs and \a rhs maps, comparing each element in sequence, and
+ returns true if the two maps contain the same elements in the same order,
false otherwise.
Note that CBOR maps are unordered, which means that two maps containing the
@@ -1123,10 +1128,10 @@ QCborValue QCborMap::extract(iterator it)
*/
/*!
- \fn bool QCborMap::operator!=(const QCborMap &other) const
+ \fn bool QCborMap::operator!=(const QCborMap &lhs, const QCborMap &rhs)
- Compares this map and \a other, comparing each element in sequence, and
- returns true if the two maps contains any different elements or elements in
+ Compares \a lhs and \a rhs maps, comparing each element in sequence, and
+ returns true if the two maps contain any different elements or elements in
different orders, false otherwise.
Note that CBOR maps are unordered, which means that two maps containing the
@@ -1142,10 +1147,10 @@ QCborValue QCborMap::extract(iterator it)
*/
/*!
- \fn bool QCborMap::operator<(const QCborMap &other) const
+ \fn bool QCborMap::operator<(const QCborMap &lhs, const QCborMap &rhs)
- Compares this map and \a other, comparing each element in sequence, and
- returns true if this map should be sorted before \a other, false
+ Compares \a lhs and \a rhs maps, comparing each element in sequence, and
+ returns true if \a lhs map should be sorted before \a rhs, false
otherwise.
Note that CBOR maps are unordered, which means that two maps containing the
@@ -1160,6 +1165,65 @@ QCborValue QCborMap::extract(iterator it)
operator==(), operator!=()
*/
+/*!
+ \fn bool QCborMap::operator<=(const QCborMap &lhs, const QCborMap &rhs)
+
+ Compares \a lhs and \a rhs maps, comparing each element in sequence, and
+ returns true if \a lhs map should be sorted before \a rhs or
+ if the two maps contain the same elements in the same order, false
+ otherwise.
+
+ Note that CBOR maps are unordered, which means that two maps containing the
+ very same pairs but in different order will still compare differently. To
+ avoid this, it is recommended to insert elements into the map in a
+ predictable order, such as by ascending key value. In fact, maps with keys
+ in sorted order are required for Canonical CBOR representation.
+
+ For more information on CBOR sorting order, see QCborValue::compare().
+
+ \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
+ operator==(), operator!=()
+*/
+
+/*!
+ \fn bool QCborMap::operator>=(const QCborMap &lhs, const QCborMap &rhs)
+
+ Compares \a lhs and \a rhs maps, comparing each element in sequence, and
+ returns true if \a lhs map should be sorted after \a rhs or
+ if the two maps contain the same elements in the same order, false
+ otherwise.
+
+ Note that CBOR maps are unordered, which means that two maps containing the
+ very same pairs but in different order will still compare differently. To
+ avoid this, it is recommended to insert elements into the map in a
+ predictable order, such as by ascending key value. In fact, maps with keys
+ in sorted order are required for Canonical CBOR representation.
+
+ For more information on CBOR sorting order, see QCborValue::compare().
+
+ \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
+ operator==(), operator!=()
+*/
+
+/*!
+ \fn bool QCborMap::operator>(const QCborMap &lhs, const QCborMap &rhs)
+
+ Compares \a lhs and \a rhs maps, comparing each element in sequence, and
+ returns true if \a lhs map should be sorted after \a rhs, false
+ otherwise.
+
+ Note that CBOR maps are unordered, which means that two maps containing the
+ very same pairs but in different order will still compare differently. To
+ avoid this, it is recommended to insert elements into the map in a
+ predictable order, such as by ascending key value. In fact, maps with keys
+ in sorted order are required for Canonical CBOR representation.
+
+ For more information on CBOR sorting order, see QCborValue::compare().
+
+ \sa compare(), QCborValue::operator==(), QCborMap::operator==(),
+ operator==(), operator!=()
+*/
+
void QCborMap::detach(qsizetype reserved)
{
d = QCborContainerPrivate::detach(d.data(), reserved ? reserved : size() * 2);
@@ -1174,6 +1238,10 @@ void QCborMap::detach(qsizetype reserved)
\brief The QCborMap::Iterator class provides an STL-style non-const iterator for QCborMap.
+ \compares strong
+ \compareswith strong ConstIterator
+ \endcompareswith
+
QCborMap::Iterator allows you to iterate over a QCborMap and to modify the
value (but not the key) stored under a particular key. If you want to
iterate over a const QCborMap, you should use QCborMap::ConstIterator. It
@@ -1295,56 +1363,56 @@ void QCborMap::detach(qsizetype reserved)
*/
/*!
- \fn bool QCborMap::Iterator::operator==(const Iterator &other) const
- \fn bool QCborMap::Iterator::operator==(const ConstIterator &other) const
+ \fn bool QCborMap::Iterator::operator==(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborMap::Iterator::operator==(const Iterator &lhs, const ConstIterator &rhs)
- Returns \c true if \a other points to the same entry in the map as this
+ Returns \c true if \a lhs points to the same entry in the map as \a rhs
iterator; otherwise returns \c false.
\sa operator!=()
*/
/*!
- \fn bool QCborMap::Iterator::operator!=(const Iterator &other) const
- \fn bool QCborMap::Iterator::operator!=(const ConstIterator &other) const
+ \fn bool QCborMap::Iterator::operator!=(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborMap::Iterator::operator!=(const Iterator &lhs, const ConstIterator &rhs)
- Returns \c true if \a other points to a different entry in the map than
- this iterator; otherwise returns \c false.
+ Returns \c true if \a lhs points to a different entry in the map than
+ \a rhs iterator; otherwise returns \c false.
\sa operator==()
*/
/*!
- \fn bool QCborMap::Iterator::operator<(const Iterator& other) const
- \fn bool QCborMap::Iterator::operator<(const ConstIterator& other) const
+ \fn bool QCborMap::Iterator::operator<(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborMap::Iterator::operator<(const Iterator &lhs, const ConstIterator &rhs)
- Returns \c true if the entry in the map pointed to by this iterator
- occurs before the entry pointed to by the \a other iterator.
+ Returns \c true if the entry in the map pointed to by \a lhs iterator
+ occurs before the entry pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QCborMap::Iterator::operator<=(const Iterator& other) const
- \fn bool QCborMap::Iterator::operator<=(const ConstIterator& other) const
+ \fn bool QCborMap::Iterator::operator<=(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborMap::Iterator::operator<=(const Iterator &lhs, const ConstIterator &rhs)
- Returns \c true if the entry in the map pointed to by this iterator
- occurs before or is the same entry as is pointed to by the \a other
+ Returns \c true if the entry in the map pointed to by \a lhs iterator
+ occurs before or is the same entry as is pointed to by the \a rhs
iterator.
*/
/*!
- \fn bool QCborMap::Iterator::operator>(const Iterator& other) const
- \fn bool QCborMap::Iterator::operator>(const ConstIterator& other) const
+ \fn bool QCborMap::Iterator::operator>(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborMap::Iterator::operator>(const Iterator &lhs, const ConstIterator &rhs)
- Returns \c true if the entry in the map pointed to by this iterator
- occurs after the entry pointed to by the \a other iterator.
+ Returns \c true if the entry in the map pointed to by \a lhs iterator
+ occurs after the entry pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QCborMap::Iterator::operator>=(const Iterator& other) const
- \fn bool QCborMap::Iterator::operator>=(const ConstIterator& other) const
+ \fn bool QCborMap::Iterator::operator>=(const Iterator &lhs, const Iterator &rhs)
+ \fn bool QCborMap::Iterator::operator>=(const Iterator &lhs, const ConstIterator &rhs)
- Returns \c true if the entry in the map pointed to by this iterator
- occurs after or is the same entry as is pointed to by the \a other
+ Returns \c true if the entry in the map pointed to by \a lhs iterator
+ occurs after or is the same entry as is pointed to by the \a rhs
iterator.
*/
@@ -1440,6 +1508,10 @@ void QCborMap::detach(qsizetype reserved)
\brief The QCborMap::ConstIterator class provides an STL-style const iterator for QCborMap.
+ \compares strong
+ \compareswith strong Iterator
+ \endcompareswith
+
QCborMap::ConstIterator allows you to iterate over a QCborMap. If you want
to modify the QCborMap as you iterate over it, you must use
QCborMap::Iterator instead. It is generally good practice to use
@@ -1540,56 +1612,50 @@ void QCborMap::detach(qsizetype reserved)
*/
/*!
- \fn bool QCborMap::ConstIterator::operator==(const ConstIterator &other) const
- \fn bool QCborMap::ConstIterator::operator==(const Iterator &other) const
+ \fn bool QCborMap::ConstIterator::operator==(const ConstIterator &lhs, const ConstIterator &rhs)
- Returns \c true if \a other points to the same entry in the map as this
+ Returns \c true if \a lhs points to the same entry in the map as \a rhs
iterator; otherwise returns \c false.
\sa operator!=()
*/
/*!
- \fn bool QCborMap::ConstIterator::operator!=(const ConstIterator &other) const
- \fn bool QCborMap::ConstIterator::operator!=(const Iterator &other) const
+ \fn bool QCborMap::ConstIterator::operator!=(const ConstIterator &lhs, const ConstIterator &rhs)
- Returns \c true if \a other points to a different entry in the map than
- this iterator; otherwise returns \c false.
+ Returns \c true if \a lhs points to a different entry in the map than
+ \a rhs iterator; otherwise returns \c false.
\sa operator==()
*/
/*!
- \fn bool QCborMap::ConstIterator::operator<(const Iterator &other) const
- \fn bool QCborMap::ConstIterator::operator<(const ConstIterator &other) const
+ \fn bool QCborMap::ConstIterator::operator<(const ConstIterator &lhs, const ConstIterator &rhs)
- Returns \c true if the entry in the map pointed to by this iterator
- occurs before the entry pointed to by the \a other iterator.
+ Returns \c true if the entry in the map pointed to by \a lhs iterator
+ occurs before the entry pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QCborMap::ConstIterator::operator<=(const Iterator &other) const
- \fn bool QCborMap::ConstIterator::operator<=(const ConstIterator &other) const
+ \fn bool QCborMap::ConstIterator::operator<=(const ConstIterator &lhs, const ConstIterator &rhs)
- Returns \c true if the entry in the map pointed to by this iterator
- occurs before or is the same entry as is pointed to by the \a other
+ Returns \c true if the entry in the map pointed to by \a lhs iterator
+ occurs before or is the same entry as is pointed to by the \a rhs
iterator.
*/
/*!
- \fn bool QCborMap::ConstIterator::operator>(const Iterator &other) const
- \fn bool QCborMap::ConstIterator::operator>(const ConstIterator &other) const
+ \fn bool QCborMap::ConstIterator::operator>(const ConstIterator &lhs, const ConstIterator &rhs)
- Returns \c true if the entry in the map pointed to by this iterator
- occurs after the entry pointed to by the \a other iterator.
+ Returns \c true if the entry in the map pointed to by \a lhs iterator
+ occurs after the entry pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QCborMap::ConstIterator::operator>=(const Iterator &other) const
- \fn bool QCborMap::ConstIterator::operator>=(const ConstIterator &other) const
+ \fn bool QCborMap::ConstIterator::operator>=(const ConstIterator &lhs, const ConstIterator &rhs)
- Returns \c true if the entry in the map pointed to by this iterator
- occurs after or is the same entry as is pointed to by the \a other
+ Returns \c true if the entry in the map pointed to by \a lhs iterator
+ occurs after or is the same entry as is pointed to by the \a rhs
iterator.
*/
diff --git a/src/corelib/serialization/qcbormap.h b/src/corelib/serialization/qcbormap.h
index 523ef9ea34..d2fd769240 100644
--- a/src/corelib/serialization/qcbormap.h
+++ b/src/corelib/serialization/qcbormap.h
@@ -20,7 +20,7 @@ class QCborContainerPrivate;
class Q_CORE_EXPORT QCborMap
{
public:
- typedef QPair<QCborValue, QCborValue> value_type;
+ typedef std::pair<QCborValue, QCborValue> value_type;
typedef QCborValue key_type;
typedef QCborValue mapped_type;
typedef qsizetype size_type;
@@ -34,12 +34,13 @@ public:
public:
typedef std::random_access_iterator_tag iterator_category;
typedef qsizetype difference_type;
- typedef QPair<QCborValueConstRef, QCborValueRef> value_type;
- typedef QPair<QCborValueConstRef, QCborValueRef> reference;
- typedef QPair<QCborValueConstRef, QCborValueRef> pointer;
+ typedef std::pair<QCborValueConstRef, QCborValueRef> value_type;
+ typedef std::pair<QCborValueConstRef, QCborValueRef> reference;
+ typedef std::pair<QCborValueConstRef, QCborValueRef> pointer;
constexpr Iterator() = default;
constexpr Iterator(const Iterator &) = default;
+ ~Iterator() = default;
Iterator &operator=(const Iterator &other)
{
// rebind the reference
@@ -60,18 +61,20 @@ public:
key() const { return QCborValueRef(item.d, item.i - 1); }
QCborValueRef value() const { return item; }
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const Iterator &o) const { return item.d == o.item.d && item.i == o.item.i; }
- bool operator!=(const Iterator &o) const { return !(*this == o); }
+ bool operator!=(const Iterator &o) const { return !operator==(o); }
bool operator<(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i < other.item.i; }
bool operator<=(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i <= other.item.i; }
bool operator>(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i > other.item.i; }
bool operator>=(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i >= other.item.i; }
bool operator==(const ConstIterator &o) const { return item.d == o.item.d && item.i == o.item.i; }
- bool operator!=(const ConstIterator &o) const { return !(*this == o); }
+ bool operator!=(const ConstIterator &o) const { return !operator==(o); }
bool operator<(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i < other.item.i; }
bool operator<=(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i <= other.item.i; }
bool operator>(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i > other.item.i; }
bool operator>=(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i >= other.item.i; }
+#endif
Iterator &operator++() { item.i += 2; return *this; }
Iterator operator++(int) { Iterator n = *this; item.i += 2; return n; }
Iterator &operator--() { item.i -= 2; return *this; }
@@ -81,6 +84,54 @@ public:
Iterator operator+(qsizetype j) const { return Iterator({ item.d, item.i + 2 * j }); }
Iterator operator-(qsizetype j) const { return Iterator({ item.d, item.i - 2 * j }); }
qsizetype operator-(Iterator j) const { return (item.i - j.item.i) / 2; }
+
+ private:
+ // Helper functions
+ static bool comparesEqual_helper(const Iterator &lhs, const Iterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.i == rhs.item.i;
+ }
+
+ static bool comparesEqual_helper(const Iterator &lhs, const ConstIterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.i == rhs.item.i;
+ }
+
+ static Qt::strong_ordering compareThreeWay_helper(const Iterator &lhs,
+ const Iterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.i, rhs.item.i);
+ }
+
+ static Qt::strong_ordering compareThreeWay_helper(const Iterator &lhs,
+ const ConstIterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.i, rhs.item.i);
+ }
+
+ // Compare friends
+ friend bool comparesEqual(const Iterator &lhs, const Iterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const Iterator &lhs,
+ const Iterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(Iterator)
+ friend bool comparesEqual(const Iterator &lhs, const ConstIterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const Iterator &lhs,
+ const ConstIterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(Iterator, ConstIterator)
};
class ConstIterator {
@@ -94,12 +145,13 @@ public:
public:
typedef std::random_access_iterator_tag iterator_category;
typedef qsizetype difference_type;
- typedef QPair<QCborValueConstRef, QCborValueConstRef> value_type;
- typedef QPair<QCborValueConstRef, QCborValueConstRef> reference;
- typedef QPair<QCborValueConstRef, QCborValueConstRef> pointer;
+ typedef std::pair<QCborValueConstRef, QCborValueConstRef> value_type;
+ typedef std::pair<QCborValueConstRef, QCborValueConstRef> reference;
+ typedef std::pair<QCborValueConstRef, QCborValueConstRef> pointer;
constexpr ConstIterator() = default;
constexpr ConstIterator(const ConstIterator &) = default;
+ ~ConstIterator() = default;
ConstIterator &operator=(const ConstIterator &other)
{
// rebind the reference
@@ -119,18 +171,20 @@ public:
key() const { return QCborValueRef(item.d, item.i - 1); }
QCborValueConstRef value() const { return item; }
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const Iterator &o) const { return item.d == o.item.d && item.i == o.item.i; }
- bool operator!=(const Iterator &o) const { return !(*this == o); }
+ bool operator!=(const Iterator &o) const { return !operator==(o); }
bool operator<(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i < other.item.i; }
bool operator<=(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i <= other.item.i; }
bool operator>(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i > other.item.i; }
bool operator>=(const Iterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i >= other.item.i; }
bool operator==(const ConstIterator &o) const { return item.d == o.item.d && item.i == o.item.i; }
- bool operator!=(const ConstIterator &o) const { return !(*this == o); }
+ bool operator!=(const ConstIterator &o) const { return !operator==(o); }
bool operator<(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i < other.item.i; }
bool operator<=(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i <= other.item.i; }
bool operator>(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i > other.item.i; }
bool operator>=(const ConstIterator& other) const { Q_ASSERT(item.d == other.item.d); return item.i >= other.item.i; }
+#endif
ConstIterator &operator++() { item.i += 2; return *this; }
ConstIterator operator++(int) { ConstIterator n = *this; item.i += 2; return n; }
ConstIterator &operator--() { item.i -= 2; return *this; }
@@ -140,6 +194,31 @@ public:
ConstIterator operator+(qsizetype j) const { return ConstIterator{ item.d, item.i + 2 * j }; }
ConstIterator operator-(qsizetype j) const { return ConstIterator{ item.d, item.i - 2 * j }; }
qsizetype operator-(ConstIterator j) const { return (item.i - j.item.i) / 2; }
+ private:
+ // Helper functions
+ static bool comparesEqual_helper(const ConstIterator &lhs,
+ const ConstIterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.i == rhs.item.i;
+ }
+ static Qt::strong_ordering compareThreeWay_helper(const ConstIterator &lhs,
+ const ConstIterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.i, rhs.item.i);
+ }
+
+ // Compare friends
+ friend bool comparesEqual(const ConstIterator &lhs, const ConstIterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const ConstIterator &lhs,
+ const ConstIterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(ConstIterator)
};
QCborMap() noexcept;
@@ -167,25 +246,25 @@ public:
QList<QCborValue> keys() const;
QCborValue value(qint64 key) const
- { const_iterator it = find(key); return it == end() ? QCborValue() : it.value(); }
+ { const_iterator it = find(key); return comparesEqual(it, end()) ? QCborValue() : it.value(); }
QCborValue value(QLatin1StringView key) const
- { const_iterator it = find(key); return it == end() ? QCborValue() : it.value(); }
+ { const_iterator it = find(key); return comparesEqual(it, end()) ? QCborValue() : it.value(); }
QCborValue value(const QString & key) const
- { const_iterator it = find(key); return it == end() ? QCborValue() : it.value(); }
+ { const_iterator it = find(key); return comparesEqual(it, end()) ? QCborValue() : it.value(); }
QCborValue value(const QCborValue &key) const
- { const_iterator it = find(key); return it == end() ? QCborValue() : it.value(); }
+ { const_iterator it = find(key); return comparesEqual(it, end()) ? QCborValue() : it.value(); }
#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
template<size_t N> QT_ASCII_CAST_WARN const QCborValue value(const char (&key)[N]) const
{ return value(QString::fromUtf8(key, N - 1)); }
#endif
const QCborValue operator[](qint64 key) const
- { const_iterator it = find(key); return it == end() ? QCborValue() : it.value(); }
+ { const_iterator it = find(key); return comparesEqual(it, end()) ? QCborValue() : it.value(); }
const QCborValue operator[](QLatin1StringView key) const
- { const_iterator it = find(key); return it == end() ? QCborValue() : it.value(); }
+ { const_iterator it = find(key); return comparesEqual(it, end()) ? QCborValue() : it.value(); }
const QCborValue operator[](const QString & key) const
- { const_iterator it = find(key); return it == end() ? QCborValue() : it.value(); }
+ { const_iterator it = find(key); return comparesEqual(it, end()) ? QCborValue() : it.value(); }
const QCborValue operator[](const QCborValue &key) const
- { const_iterator it = find(key); return it == end() ? QCborValue() : it.value(); }
+ { const_iterator it = find(key); return comparesEqual(it, end()) ? QCborValue() : it.value(); }
#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
template<size_t N> QT_ASCII_CAST_WARN const QCborValue operator[](const char (&key)[N]) const
{ return operator[](QString::fromUtf8(key, N - 1)); }
@@ -196,44 +275,36 @@ public:
QCborValueRef operator[](const QCborValue &key);
QCborValue take(qint64 key)
- { const_iterator it = constFind(key); if (it != constEnd()) return extract(it); return QCborValue(); }
+ { const_iterator it = constFind(key); if (!comparesEqual(it, constEnd())) return extract(it); return QCborValue(); }
QCborValue take(QLatin1StringView key)
- { const_iterator it = constFind(key); if (it != constEnd()) return extract(it); return QCborValue(); }
+ { const_iterator it = constFind(key); if (!comparesEqual(it, constEnd())) return extract(it); return QCborValue(); }
QCborValue take(const QString &key)
- { const_iterator it = constFind(key); if (it != constEnd()) return extract(it); return QCborValue(); }
+ { const_iterator it = constFind(key); if (!comparesEqual(it, constEnd())) return extract(it); return QCborValue(); }
QCborValue take(const QCborValue &key)
- { const_iterator it = constFind(key); if (it != constEnd()) return extract(it); return QCborValue(); }
+ { const_iterator it = constFind(key); if (!comparesEqual(it, constEnd())) return extract(it); return QCborValue(); }
void remove(qint64 key)
- { const_iterator it = constFind(key); if (it != constEnd()) erase(it); }
+ { const_iterator it = constFind(key); if (!comparesEqual(it, constEnd())) erase(it); }
void remove(QLatin1StringView key)
- { const_iterator it = constFind(key); if (it != constEnd()) erase(it); }
+ { const_iterator it = constFind(key); if (!comparesEqual(it, constEnd())) erase(it); }
void remove(const QString & key)
- { const_iterator it = constFind(key); if (it != constEnd()) erase(it); }
+ { const_iterator it = constFind(key); if (!comparesEqual(it, constEnd())) erase(it); }
void remove(const QCborValue &key)
- { const_iterator it = constFind(key); if (it != constEnd()) erase(it); }
+ { const_iterator it = constFind(key); if (!comparesEqual(it, constEnd())) erase(it); }
bool contains(qint64 key) const
- { const_iterator it = find(key); return it != end(); }
+ { const_iterator it = find(key); return !comparesEqual(it, end()); }
bool contains(QLatin1StringView key) const
- { const_iterator it = find(key); return it != end(); }
+ { const_iterator it = find(key); return !comparesEqual(it, end()); }
bool contains(const QString & key) const
- { const_iterator it = find(key); return it != end(); }
+ { const_iterator it = find(key); return !comparesEqual(it, end()); }
bool contains(const QCborValue &key) const
- { const_iterator it = find(key); return it != end(); }
+ { const_iterator it = find(key); return !comparesEqual(it, end()); }
int compare(const QCborMap &other) const noexcept Q_DECL_PURE_FUNCTION;
-#if 0 && __has_include(<compare>)
- std::strong_ordering operator<=>(const QCborMap &other) const
- {
- int c = compare(other);
- if (c > 0) return std::strong_ordering::greater;
- if (c == 0) return std::strong_ordering::equivalent;
- return std::strong_ordering::less;
- }
-#else
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QCborMap &other) const noexcept
{ return compare(other) == 0; }
bool operator!=(const QCborMap &other) const noexcept
- { return !(*this == other); }
+ { return !operator==(other); }
bool operator<(const QCborMap &other) const
{ return compare(other) < 0; }
#endif
@@ -308,6 +379,48 @@ private:
friend class QJsonPrivate::Variant;
void detach(qsizetype reserve = 0);
+ friend Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool
+ comparesEqual(const QCborMap &lhs, const QCborMap &rhs) noexcept;
+ friend Qt::strong_ordering compareThreeWay(const QCborMap &lhs,
+ const QCborMap &rhs) noexcept
+ {
+ int c = lhs.compare(rhs);
+ return Qt::compareThreeWay(c, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QCborMap)
+
+ static Q_DECL_PURE_FUNCTION bool
+ comparesEqual_helper(const QCborMap &lhs, const QCborValue &rhs) noexcept;
+ static Q_DECL_PURE_FUNCTION Qt::strong_ordering
+ compareThreeWay_helper(const QCborMap &lhs, const QCborValue &rhs) noexcept;
+ friend bool comparesEqual(const QCborMap &lhs,
+ const QCborValue &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const QCborMap &lhs,
+ const QCborValue &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QCborMap, QCborValue)
+
+ static Q_DECL_PURE_FUNCTION bool
+ comparesEqual_helper(const QCborMap &lhs, QCborValueConstRef rhs) noexcept;
+ static Q_DECL_PURE_FUNCTION Qt::strong_ordering
+ compareThreeWay_helper(const QCborMap &lhs, QCborValueConstRef rhs) noexcept;
+ friend bool comparesEqual(const QCborMap &lhs,
+ const QCborValueConstRef &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const QCborMap &lhs,
+ const QCborValueConstRef &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QCborMap, QCborValueConstRef)
+
explicit QCborMap(QCborContainerPrivate &dd) noexcept;
QExplicitlySharedDataPointer<QCborContainerPrivate> d;
};
diff --git a/src/corelib/serialization/qcborstreamreader.cpp b/src/corelib/serialization/qcborstreamreader.cpp
index 887bcdd6b0..863c24534a 100644
--- a/src/corelib/serialization/qcborstreamreader.cpp
+++ b/src/corelib/serialization/qcborstreamreader.cpp
@@ -6,7 +6,6 @@
#define CBOR_NO_ENCODER_API
#include <private/qcborcommon_p.h>
-#include <private/qbytearray_p.h>
#include <private/qnumeric_p.h>
#include <private/qstringconverter_p.h>
#include <qiodevice.h>
@@ -29,6 +28,7 @@ static CborError qt_cbor_decoder_transfer_string(void *token, const void **userp
QT_WARNING_PUSH
QT_WARNING_DISABLE_MSVC(4334) // '<<': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
+QT_WARNING_DISABLE_GCC("-Wimplicit-fallthrough")
#include <cborparser.c>
@@ -150,8 +150,9 @@ static_assert(int(QCborStreamReader::Invalid) == CborInvalidType);
parsing from a QByteArray, or reparse(), if it is instead reading directly
a the QIDOevice that now has more data available (see setDevice()).
- \sa QCborStreamWriter, QCborValue, QXmlStreamReader, {Cbordump Example}
- \sa {Convert Example}, {JSON Save Game Example}
+ \sa QCborStreamWriter, QCborValue, QXmlStreamReader,
+ {Parsing and displaying CBOR data}, {Serialization Converter},
+ {Saving and Loading a Game}
*/
/*!
@@ -617,21 +618,24 @@ public:
QByteArray *array;
QString *string;
};
- enum { ByteArray = -1, String = -3 };
+ enum Type { ByteArray = -1, String = -3, Utf8String = -5 };
qsizetype maxlen_or_type;
ReadStringChunk(char *ptr, qsizetype maxlen) : ptr(ptr), maxlen_or_type(maxlen) {}
- ReadStringChunk(QByteArray *array) : array(array), maxlen_or_type(ByteArray) {}
+ ReadStringChunk(QByteArray *array, Type type = ByteArray) : array(array), maxlen_or_type(type) {}
ReadStringChunk(QString *str) : string(str), maxlen_or_type(String) {}
bool isString() const { return maxlen_or_type == String; }
+ bool isUtf8String() const { return maxlen_or_type == Utf8String; }
bool isByteArray() const { return maxlen_or_type == ByteArray; }
bool isPlainPointer() const { return maxlen_or_type >= 0; }
};
static QCborStreamReader::StringResultCode appendStringChunk(QCborStreamReader &reader, QByteArray *data);
+ bool readFullString(ReadStringChunk params);
QCborStreamReader::StringResult<qsizetype> readStringChunk(ReadStringChunk params);
qsizetype readStringChunk_byte(ReadStringChunk params, qsizetype len);
qsizetype readStringChunk_unicode(ReadStringChunk params, qsizetype utf8len);
+ qsizetype readStringChunk_utf8(ReadStringChunk params, qsizetype utf8len);
bool ensureStringIteration();
};
@@ -681,7 +685,7 @@ static CborError qt_cbor_decoder_transfer_string(void *token, const void **userp
// (otherwise, we'd lose the length information)
qsizetype total;
if (len > size_t(std::numeric_limits<QByteArray::size_type>::max())
- || add_overflow<qsizetype>(offset, len, &total))
+ || qAddOverflow<qsizetype>(offset, len, &total))
return CborErrorDataTooLarge;
// our string transfer is just saving the offset to the userptr
@@ -928,7 +932,7 @@ void QCborStreamReader::reset()
\sa isValid()
*/
-QCborError QCborStreamReader::lastError()
+QCborError QCborStreamReader::lastError() const
{
return d->lastError;
}
@@ -1289,16 +1293,20 @@ bool QCborStreamReader::leaveContainer()
Decodes one string chunk from the CBOR string and returns it. This function
is used for both regular and chunked string contents, so the caller must
- always loop around calling this function, even if isLengthKnown() has
+ always loop around calling this function, even if isLengthKnown()
is true. The typical use of this function is as follows:
\snippet code/src_corelib_serialization_qcborstream.cpp 27
+ The readAllString() function implements the above loop and some extra checks.
+
+//! [string-no-type-conversions]
This function does not perform any type conversions, including from integers
or from byte arrays. Therefore, it may only be called if isString() returned
true; calling it in any other condition is an error.
+//! [string-no-type-conversions]
- \sa readByteArray(), isString(), readStringChunk()
+ \sa readAllString(), readByteArray(), isString(), readStringChunk()
*/
QCborStreamReader::StringResult<QString> QCborStreamReader::_readString_helper()
{
@@ -1317,20 +1325,58 @@ QCborStreamReader::StringResult<QString> QCborStreamReader::_readString_helper()
}
/*!
+ \fn QCborStreamReader::StringResult<QByteArray> QCborStreamReader::readUtf8String()
+ \since 6.7
+
+ Decodes one string chunk from the CBOR string and returns it. This function
+ is used for both regular and chunked string contents, so the caller must
+ always loop around calling this function, even if isLengthKnown() is true.
+ The typical use of this function is as for readString() in the following:
+
+ \snippet code/src_corelib_serialization_qcborstream.cpp 27
+
+ The readAllUtf8String() function implements the above loop and some extra checks.
+
+ \include qcborstreamreader.cpp string-no-type-conversions
+
+ \sa readAllString(), readByteArray(), isString(), readStringChunk()
+ */
+QCborStreamReader::StringResult<QByteArray> QCborStreamReader::_readUtf8String_helper()
+{
+ using P = QCborStreamReaderPrivate::ReadStringChunk;
+ QCborStreamReader::StringResult<QByteArray> result;
+ auto r = d->readStringChunk(P{ &result.data, P::Utf8String });
+ result.status = r.status;
+ if (r.status == Error) {
+ result.data.clear();
+ } else {
+ Q_ASSERT(r.data == result.data.size());
+ if (r.status == EndOfString && lastError() == QCborError::NoError)
+ preparse();
+ }
+
+ return result;
+}
+
+/*!
\fn QCborStreamReader::StringResult<QByteArray> QCborStreamReader::readByteArray()
Decodes one byte array chunk from the CBOR string and returns it. This
function is used for both regular and chunked contents, so the caller must
- always loop around calling this function, even if isLengthKnown() has
+ always loop around calling this function, even if isLengthKnown()
is true. The typical use of this function is as follows:
\snippet code/src_corelib_serialization_qcborstream.cpp 28
+ The readAllByteArray() function implements the above loop and some extra checks.
+
+//! [bytearray-no-type-conversions]
This function does not perform any type conversions, including from integers
or from strings. Therefore, it may only be called if isByteArray() is true;
calling it in any other condition is an error.
+//! [bytearray-no-type-conversions]
- \sa readString(), isByteArray(), readStringChunk()
+ \sa readAllByteArray(), readString(), isByteArray(), readStringChunk()
*/
QCborStreamReader::StringResult<QByteArray> QCborStreamReader::_readByteArray_helper()
{
@@ -1379,6 +1425,147 @@ qsizetype QCborStreamReader::_currentStringChunkSize() const
return -1;
}
+bool QCborStreamReaderPrivate::readFullString(ReadStringChunk params)
+{
+ auto r = readStringChunk(params);
+ while (r.status == QCborStreamReader::Ok) {
+ // keep appending
+ r = readStringChunk(params);
+ }
+
+ bool ok = r.status == QCborStreamReader::EndOfString;
+ Q_ASSERT(ok == !lastError);
+ return ok;
+}
+
+/*!
+ \fn QCborStreamReader::readAllString()
+ \since 6.7
+
+ Decodes the current text string and returns it. If the string is chunked,
+ this function will iterate over all chunks and concatenate them. If an
+ error happens, this function returns a default-constructed QString(), but
+ that may not be distinguishable from certain empty text strings. Instead,
+ check lastError() to determine if an error has happened.
+
+ \include qcborstreamreader.cpp string-no-type-conversions
+
+//! [note-not-restartable]
+ \note This function cannot be resumed. That is, this function should not
+ be used in contexts where the CBOR data may still be received, for example
+ from a socket or pipe. It should only be used when the full data has
+ already been received and is available in the input QByteArray or
+ QIODevice.
+//! [note-not-restartable]
+
+ \sa readString(), readStringChunk(), isString(), readAllByteArray()
+ */
+/*!
+ \fn QCborStreamReader::readAndAppendToString(QString &dst)
+ \since 6.7
+
+ Decodes the current text string and appends to \a dst. If the string is
+ chunked, this function will iterate over all chunks and concatenate them.
+ If an error happens during decoding, other chunks that could be decoded
+ successfully may have been written to \a dst nonetheless. Returns \c true
+ if the decoding happened without errors, \c false otherwise.
+
+ \include qcborstreamreader.cpp string-no-type-conversions
+
+ \include qcborstreamreader.cpp note-not-restartable
+
+ \sa readString(), readStringChunk(), isString(), readAndAppendToByteArray()
+ */
+bool QCborStreamReader::_readAndAppendToString_helper(QString &dst)
+{
+ bool ok = d->readFullString(&dst);
+ if (ok)
+ preparse();
+ return ok;
+}
+
+/*!
+ \fn QCborStreamReader::readAllUtf8String()
+ \since 6.7
+
+ Decodes the current text string and returns it. If the string is chunked,
+ this function will iterate over all chunks and concatenate them. If an
+ error happens, this function returns a default-constructed QString(), but
+ that may not be distinguishable from certain empty text strings. Instead,
+ check lastError() to determine if an error has happened.
+
+ \include qcborstreamreader.cpp string-no-type-conversions
+
+ \include qcborstreamreader.cpp note-not-restartable
+
+ \sa readString(), readStringChunk(), isString(), readAllByteArray()
+ */
+/*!
+ \fn QCborStreamReader::readAndAppendToUtf8String(QByteArray &dst)
+ \since 6.7
+
+ Decodes the current text string and appends to \a dst. If the string is
+ chunked, this function will iterate over all chunks and concatenate them.
+ If an error happens during decoding, other chunks that could be decoded
+ successfully may have been written to \a dst nonetheless. Returns \c true
+ if the decoding happened without errors, \c false otherwise.
+
+ \include qcborstreamreader.cpp string-no-type-conversions
+
+ \include qcborstreamreader.cpp note-not-restartable
+
+ \sa readString(), readStringChunk(), isString(), readAndAppendToByteArray()
+ */
+bool QCborStreamReader::_readAndAppendToUtf8String_helper(QByteArray &dst)
+{
+ using P = QCborStreamReaderPrivate::ReadStringChunk;
+ bool ok = d->readFullString({ &dst, P::Utf8String });
+ if (ok)
+ preparse();
+ return ok;
+}
+
+/*!
+ \fn QCborStreamReader::readAllByteArray()
+ \since 6.7
+
+ Decodes the current byte string and returns it. If the string is chunked,
+ this function will iterate over all chunks and concatenate them. If an
+ error happens, this function returns a default-constructed QByteArray(),
+ but that may not be distinguishable from certain empty byte strings.
+ Instead, check lastError() to determine if an error has happened.
+
+ \include qcborstreamreader.cpp bytearray-no-type-conversions
+
+ \include qcborstreamreader.cpp note-not-restartable
+
+ \sa readByteArray(), readStringChunk(), isByteArray(), readAllString()
+ */
+
+/*!
+ \fn QCborStreamReader::readAndAppendToByteArray(QByteArray &dst)
+ \since 6.7
+
+ Decodes the current byte string and appends to \a dst. If the string is
+ chunked, this function will iterate over all chunks and concatenate them.
+ If an error happens during decoding, other chunks that could be decoded
+ successfully may have been written to \a dst nonetheless. Returns \c true
+ if the decoding happened without errors, \c false otherwise.
+
+ \include qcborstreamreader.cpp bytearray-no-type-conversions
+
+ \include qcborstreamreader.cpp note-not-restartable
+
+ \sa readByteArray(), readStringChunk(), isByteArray(), readAndAppendToString()
+ */
+bool QCborStreamReader::_readAndAppendToByteArray_helper(QByteArray &dst)
+{
+ bool ok = d->readFullString(&dst);
+ if (ok)
+ preparse();
+ return ok;
+}
+
/*!
Reads the current string chunk into the buffer pointed to by \a ptr, whose
size is \a maxlen. This function returns a \l StringResult object, with the
@@ -1451,6 +1638,12 @@ QCborStreamReaderPrivate::readStringChunk(ReadStringChunk params)
// qt_cbor_decoder_transfer_string() enforces that
// QIODevice::bytesAvailable() be bigger than the amount we're about to
// read.
+ //
+ // This is an important security gate: if the CBOR stream is corrupt or
+ // malicious, and has an impossibly large string size, we only go past it
+ // if the transfer to the destination buffer will succeed (modulo QIODevice
+ // I/O failures).
+
#if 1
// Using internal TinyCBOR API!
err = _cbor_value_get_string_chunk(&currentElement, &content, &len, &currentElement);
@@ -1493,6 +1686,8 @@ QCborStreamReaderPrivate::readStringChunk(ReadStringChunk params)
if (params.isString()) {
// readString()
result.data = readStringChunk_unicode(params, qsizetype(len));
+ } else if (params.isUtf8String()) {
+ result.data = readStringChunk_utf8(params, qsizetype(len));
} else {
// readByteArray() or readStringChunk()
result.data = readStringChunk_byte(params, qsizetype(len));
@@ -1539,11 +1734,11 @@ QCborStreamReaderPrivate::readStringChunk_byte(ReadStringChunk params, qsizetype
else
toRead = params.maxlen_or_type; // buffer smaller than string
ptr = params.ptr;
- } else if (params.isByteArray()) {
+ } else if (!params.isString()) {
// See note above on having ensured there is enough incoming data.
auto oldSize = params.array->size();
auto newSize = oldSize;
- if (add_overflow<decltype(newSize)>(oldSize, toRead, &newSize)) {
+ if (qAddOverflow<decltype(newSize)>(oldSize, toRead, &newSize)) {
handleError(CborErrorDataTooLarge);
return -1;
}
@@ -1553,7 +1748,7 @@ QCborStreamReaderPrivate::readStringChunk_byte(ReadStringChunk params, qsizetype
// the distinction between DataTooLarge and OOM is mostly for
// compatibility with Qt 5; in Qt 6, we could consider everything
// to be OOM.
- handleError(newSize > MaxByteArraySize ? CborErrorDataTooLarge: CborErrorOutOfMemory);
+ handleError(newSize > QByteArray::max_size() ? CborErrorDataTooLarge: CborErrorOutOfMemory);
return -1;
}
@@ -1586,24 +1781,25 @@ QCborStreamReaderPrivate::readStringChunk_byte(ReadStringChunk params, qsizetype
inline qsizetype
QCborStreamReaderPrivate::readStringChunk_unicode(ReadStringChunk params, qsizetype utf8len)
{
+ Q_ASSERT(params.isString());
+
// See QUtf8::convertToUnicode() a detailed explanation of why this
// conversion uses the same number of words or less.
- QChar *begin = nullptr;
- if (params.isString()) {
- QT_TRY {
- params.string->resize(utf8len);
- } QT_CATCH (const std::bad_alloc &) {
- if (utf8len > MaxStringSize)
- handleError(CborErrorDataTooLarge);
- else
- handleError(CborErrorOutOfMemory);
- return -1;
- }
-
- begin = const_cast<QChar *>(params.string->constData());
+ qsizetype currentSize = params.string->size();
+ size_t newSize = size_t(utf8len) + size_t(currentSize); // can't overflow
+ if (utf8len > QString::max_size() || qsizetype(newSize) < 0) {
+ handleError(CborErrorDataTooLarge);
+ return -1;
+ }
+ QT_TRY {
+ params.string->resize(qsizetype(newSize));
+ } QT_CATCH (const std::bad_alloc &) {
+ handleError(CborErrorOutOfMemory);
+ return -1;
}
- QChar *ptr = begin;
+ QChar *begin = const_cast<QChar *>(params.string->constData());
+ QChar *ptr = begin + currentSize;
QStringConverter::State cs(QStringConverter::Flag::Stateless);
if (device == nullptr) {
// Easy case: we can decode straight from the buffer we already have
@@ -1635,9 +1831,25 @@ QCborStreamReaderPrivate::readStringChunk_unicode(ReadStringChunk params, qsizet
}
qsizetype size = ptr - begin;
- if (params.isString())
- params.string->truncate(size);
- return size;
+ params.string->truncate(ptr - begin);
+ return size - currentSize; // how many bytes we added
+}
+
+inline qsizetype
+QCborStreamReaderPrivate::readStringChunk_utf8(ReadStringChunk params, qsizetype utf8len)
+{
+ qsizetype result = readStringChunk_byte(params, utf8len);
+ if (result < 0)
+ return result;
+
+ // validate the UTF-8 content we've just read
+ QByteArrayView chunk = *params.array;
+ chunk = chunk.last(result);
+ if (QtPrivate::isValidUtf8(chunk))
+ return result;
+
+ handleError(CborErrorInvalidUtf8TextString);
+ return -1;
}
QT_END_NAMESPACE
diff --git a/src/corelib/serialization/qcborstreamreader.h b/src/corelib/serialization/qcborstreamreader.h
index cc4b9cdf42..2666b7c7b2 100644
--- a/src/corelib/serialization/qcborstreamreader.h
+++ b/src/corelib/serialization/qcborstreamreader.h
@@ -77,7 +77,10 @@ public:
void clear();
void reset();
+#if QT_CORE_REMOVED_SINCE(6, 7)
QCborError lastError();
+#endif
+ QCborError lastError() const;
qint64 currentOffset() const;
@@ -117,7 +120,14 @@ public:
bool enterContainer() { Q_ASSERT(isContainer()); return _enterContainer_helper(); }
bool leaveContainer();
+ bool readAndAppendToString(QString &dst)
+ { Q_ASSERT(isString()); return _readAndAppendToString_helper(dst); }
+ bool readAndAppendToUtf8String(QByteArray &dst)
+ { Q_ASSERT(isString()); return _readAndAppendToUtf8String_helper(dst); }
+ bool readAndAppendToByteArray(QByteArray &dst)
+ { Q_ASSERT(isByteArray()); return _readAndAppendToByteArray_helper(dst); }
StringResult<QString> readString() { Q_ASSERT(isString()); return _readString_helper(); }
+ StringResult<QByteArray> readUtf8String() { Q_ASSERT(isString()); return _readUtf8String_helper(); }
StringResult<QByteArray> readByteArray(){ Q_ASSERT(isByteArray()); return _readByteArray_helper(); }
qsizetype currentStringChunkSize() const{ Q_ASSERT(isString() || isByteArray()); return _currentStringChunkSize(); }
StringResult<qsizetype> readStringChunk(char *ptr, qsizetype maxlen);
@@ -139,13 +149,38 @@ public:
return -v - 1;
return v;
}
+ QString readAllString()
+ {
+ QString dst;
+ if (!readAndAppendToString(dst))
+ dst = QString{};
+ return dst;
+ }
+ QByteArray readAllUtf8String()
+ {
+ QByteArray dst;
+ if (!readAndAppendToUtf8String(dst))
+ dst = QByteArray{};
+ return dst;
+ }
+ QByteArray readAllByteArray()
+ {
+ QByteArray dst;
+ if (!readAndAppendToByteArray(dst))
+ dst = QByteArray{};
+ return dst;
+ }
private:
void preparse();
bool _enterContainer_helper();
StringResult<QString> _readString_helper();
+ StringResult<QByteArray> _readUtf8String_helper();
StringResult<QByteArray> _readByteArray_helper();
qsizetype _currentStringChunkSize() const;
+ bool _readAndAppendToString_helper(QString &);
+ bool _readAndAppendToUtf8String_helper(QByteArray &);
+ bool _readAndAppendToByteArray_helper(QByteArray &);
template <typename FP> FP _toFloatingPoint() const noexcept
{
diff --git a/src/corelib/serialization/qcborstreamwriter.cpp b/src/corelib/serialization/qcborstreamwriter.cpp
index 0e00fe9bd6..7b5099567e 100644
--- a/src/corelib/serialization/qcborstreamwriter.cpp
+++ b/src/corelib/serialization/qcborstreamwriter.cpp
@@ -7,9 +7,11 @@
#include <private/qcborcommon_p.h>
#include <private/qnumeric_p.h>
+#include <private/qstringconverter_p.h>
#include <qbuffer.h>
#include <qdebug.h>
#include <qstack.h>
+#include <qvarlengtharray.h>
QT_BEGIN_NAMESPACE
@@ -174,7 +176,8 @@ Q_DECLARE_TYPEINFO(CborEncoder, Q_PRIMITIVE_TYPE);
\endlist
\sa QCborStreamReader, QCborValue, QXmlStreamWriter
- \sa {Cbordump Example}, {Convert Example}, {JSON Save Game Example}
+ {Parsing and displaying CBOR data}, {Serialization Converter},
+ {Saving and Loading a Game}
*/
class QCborStreamWriterPrivate
@@ -438,8 +441,10 @@ void QCborStreamWriter::append(QLatin1StringView str)
// it is plain US-ASCII
appendTextString(str.latin1(), str.size());
} else {
- // non-ASCII, so we need a pass-through UTF-16
- append(QString(str));
+ // non-ASCII, convert:
+ QVarLengthArray<char> utf8(str.size() * 2); // each L1 char gives at most two U8 units
+ const qsizetype written = QUtf8::convertFromLatin1(utf8.data(), str) - utf8.data();
+ appendTextString(utf8.data(), written);
}
}
@@ -726,7 +731,8 @@ void QCborStreamWriter::startArray()
seem to allow up to 2\sup{64}-1 elements in the array. However, both
QCborStreamWriter and QCborStreamReader are currently limited to 2\sup{32}-2
items on 32-bit systems and 2\sup{64}-2 items on 64-bit ones. Also note that
- QCborArray is currently limited to 2\sup{27} elements in any platform.
+ QCborArray is currently limited to 2\sup{27} elements on 32-bit platforms and
+ 2\sup{59} elements on 64-bit ones.
\sa startArray(), endArray(), startMap(), QCborStreamReader::isArray(),
QCborStreamReader::isLengthKnown()
@@ -799,7 +805,8 @@ void QCborStreamWriter::startMap()
seem to allow up to 2\sup{64}-1 pairs in the map. However, both
QCborStreamWriter and QCborStreamReader are currently limited to 2\sup{31}-1
items on 32-bit systems and 2\sup{63}-1 items on 64-bit ones. Also note that
- QCborMap is currently limited to 2\sup{26} elements in any platform.
+ QCborMap is currently limited to 2\sup{26} elements on 32-bit platforms and
+ 2\sup{58} on 64-bit ones.
\sa startMap(), endMap(), startArray(), QCborStreamReader::isMap(),
QCborStreamReader::isLengthKnown()
diff --git a/src/corelib/serialization/qcborvalue.cpp b/src/corelib/serialization/qcborvalue.cpp
index ae1902f1dd..cd0b842111 100644
--- a/src/corelib/serialization/qcborvalue.cpp
+++ b/src/corelib/serialization/qcborvalue.cpp
@@ -19,7 +19,6 @@
#include <qlocale.h>
#include <qdatetime.h>
#include <qtimezone.h>
-#include <private/qbytearray_p.h>
#include <private/qnumeric_p.h>
#include <private/qsimd_p.h>
@@ -52,6 +51,8 @@ Q_DECL_UNUSED static constexpr quint64 MaximumPreallocatedElementCount =
\brief The QCborValue class encapsulates a value in CBOR.
+ \compares strong
+
This class can be used to hold one of the many types available in CBOR.
CBOR is the Concise Binary Object Representation, a very compact form of
binary data encoding that is a superset of JSON. It was created by the IETF
@@ -191,9 +192,9 @@ Q_DECL_UNUSED static constexpr quint64 MaximumPreallocatedElementCount =
array or map it refers to will be modified with the new value. In all other
aspects, its API is identical to QCborValue.
- \sa QCborArray, QCborMap, QCborStreamReader, QCborStreamWriter
- \sa QJsonValue, QJsonDocument, {Cbordump Example}, {Convert Example}
- \sa {JSON Save Game Example}
+ \sa QCborArray, QCborMap, QCborStreamReader, QCborStreamWriter,
+ QJsonValue, QJsonDocument, {Serialization Converter}, {Saving and Loading a Game}
+ {Parsing and displaying CBOR data}
*/
/*!
@@ -787,9 +788,9 @@ static QCborValue::Type convertToExtendedType(QCborContainerPrivate *d)
bool ok = false;
if (e.type == QCborValue::Integer) {
#if QT_POINTER_SIZE == 8
- // we don't have a fast 64-bit mul_overflow implementation on
+ // we don't have a fast 64-bit qMulOverflow implementation on
// 32-bit architectures.
- ok = !mul_overflow(e.value, qint64(1000), &msecs);
+ ok = !qMulOverflow(e.value, qint64(1000), &msecs);
#else
static const qint64 Limit = std::numeric_limits<qint64>::max() / 1000;
ok = (e.value > -Limit && e.value < Limit);
@@ -903,12 +904,12 @@ static void writeDoubleToCbor(QCborStreamWriter &writer, double d, QCborValue::E
}
#endif // QT_CONFIG(cborstreamwriter)
-static inline int typeOrder(Element e1, Element e2)
+static inline int typeOrder(QCborValue::Type e1, QCborValue::Type e2)
{
- auto comparable = [](Element e) {
- if (e.type >= 0x10000) // see QCborValue::isTag_helper()
+ auto comparable = [](QCborValue::Type type) {
+ if (type >= 0x10000) // see QCborValue::isTag_helper()
return QCborValue::Tag;
- return e.type;
+ return type;
};
return comparable(e1) - comparable(e2);
}
@@ -922,14 +923,24 @@ QCborContainerPrivate::~QCborContainerPrivate()
}
}
-void QCborContainerPrivate::compact(qsizetype reserved)
+void QCborContainerPrivate::compact()
{
if (usedData > data.size() / 2)
return;
// 50% savings if we recreate the byte data
- // ### TBD
- Q_UNUSED(reserved);
+ QByteArray newData;
+ QByteArray::size_type newUsedData = 0;
+ // Compact only elements that have byte data.
+ // Nested containers will be compacted when their data changes.
+ for (auto &e : elements) {
+ if (e.flags & Element::HasByteData) {
+ if (const ByteData *b = byteData(e))
+ e.value = addByteDataImpl(newData, newUsedData, b->byte(), b->len);
+ }
+ }
+ data = newData;
+ usedData = newUsedData;
}
QCborContainerPrivate *QCborContainerPrivate::clone(QCborContainerPrivate *d, qsizetype reserved)
@@ -941,7 +952,7 @@ QCborContainerPrivate *QCborContainerPrivate::clone(QCborContainerPrivate *d, qs
QExplicitlySharedDataPointer u(new QCborContainerPrivate(*d));
if (reserved >= 0) {
u->elements.reserve(reserved);
- u->compact(reserved);
+ u->compact();
}
d = u.take();
@@ -973,7 +984,7 @@ QCborContainerPrivate *QCborContainerPrivate::grow(QCborContainerPrivate *d, qsi
Q_ASSERT(index >= 0);
d = detach(d, index + 1);
Q_ASSERT(d);
- int j = d->elements.size();
+ qsizetype j = d->elements.size();
while (j++ < index)
d->append(Undefined());
return d;
@@ -1013,10 +1024,23 @@ void QCborContainerPrivate::replaceAt_complex(Element &e, const QCborValue &valu
// Copy string data, if any
if (const ByteData *b = value.container->byteData(value.n)) {
- if (this == value.container)
- e.value = addByteData(b->toByteArray(), b->len);
- else
+ const auto flags = e.flags;
+ // The element e has an invalid e.value, because it is copied from
+ // value. It means that calling compact() will trigger an assertion
+ // or just silently corrupt the data.
+ // Temporarily unset the Element::HasByteData flag in order to skip
+ // the element e in the call to compact().
+ e.flags = e.flags & ~Element::HasByteData;
+ if (this == value.container) {
+ const QByteArray valueData = b->toByteArray();
+ compact();
+ e.value = addByteData(valueData, valueData.size());
+ } else {
+ compact();
e.value = addByteData(b->byte(), b->len);
+ }
+ // restore the flags
+ e.flags = flags;
}
if (disp == MoveContainer)
@@ -1041,6 +1065,12 @@ Q_NEVER_INLINE void QCborContainerPrivate::appendAsciiString(QStringView s)
qt_to_latin1_unchecked(l, s.utf16(), len);
}
+void QCborContainerPrivate::appendNonAsciiString(QStringView s)
+{
+ appendByteData(reinterpret_cast<const char *>(s.utf16()), s.size() * 2,
+ QCborValue::String, QtCbor::Element::StringIsUtf16);
+}
+
QCborValue QCborContainerPrivate::extractAt_complex(Element e)
{
// create a new container for the returned value, containing the byte data
@@ -1053,7 +1083,7 @@ QCborValue QCborContainerPrivate::extractAt_complex(Element e)
// make a shallow copy of the byte data
container->appendByteData(b->byte(), b->len, e.type, e.flags);
usedData -= b->len + qsizetype(sizeof(*b));
- compact(elements.size());
+ compact();
} else {
// just share with the original byte data
container->data = data;
@@ -1064,9 +1094,127 @@ QCborValue QCborContainerPrivate::extractAt_complex(Element e)
return makeValue(e.type, 0, container);
}
+// Similar to QStringIterator::next() but returns malformed surrogate pair
+// itself when one is detected, and returns the length in UTF-8.
+static auto nextUtf32Character(const char16_t *&ptr, const char16_t *end) noexcept
+{
+ Q_ASSERT(ptr != end);
+ struct R {
+ char32_t c;
+ qsizetype len = 1; // in UTF-8 code units (bytes)
+ } r = { *ptr++ };
+
+ if (r.c < 0x0800) {
+ if (r.c >= 0x0080)
+ ++r.len;
+ } else if (!QChar::isHighSurrogate(r.c) || ptr == end) {
+ r.len += 2;
+ } else {
+ r.len += 3;
+ r.c = QChar::surrogateToUcs4(r.c, *ptr++);
+ }
+
+ return r;
+}
+
+static qsizetype stringLengthInUtf8(const char16_t *ptr, const char16_t *end) noexcept
+{
+ qsizetype len = 0;
+ while (ptr < end)
+ len += nextUtf32Character(ptr, end).len;
+ return len;
+}
+
+static int compareStringsInUtf8(QStringView lhs, QStringView rhs, Comparison mode) noexcept
+{
+ if (mode == Comparison::ForEquality)
+ return lhs == rhs ? 0 : 1;
+
+ // The UTF-16 length is *usually* comparable, but not always. There are
+ // pathological cases where they can be wrong, so we need to compare as if
+ // we were doing it in UTF-8. That includes the case of UTF-16 surrogate
+ // pairs, because qstring.cpp sorts them before U+E000-U+FFFF.
+ int diff = 0;
+ qsizetype len1 = 0;
+ qsizetype len2 = 0;
+ const char16_t *src1 = lhs.utf16();
+ const char16_t *src2 = rhs.utf16();
+ const char16_t *end1 = src1 + lhs.size();
+ const char16_t *end2 = src2 + rhs.size();
+
+ // first, scan until we find a difference (if any)
+ do {
+ auto r1 = nextUtf32Character(src1, end1);
+ auto r2 = nextUtf32Character(src2, end2);
+ len1 += r1.len;
+ len2 += r2.len;
+ diff = int(r1.c) - int(r2.c); // no underflow due to limited range
+ } while (src1 < end1 && src2 < end2 && diff == 0);
+
+ // compute the full length past this first difference
+ len1 += stringLengthInUtf8(src1, end1);
+ len2 += stringLengthInUtf8(src2, end2);
+ if (len1 == len2)
+ return diff;
+ return len1 < len2 ? -1 : 1;
+}
+
+static int compareStringsInUtf8(QUtf8StringView lhs, QStringView rhs, Comparison mode) noexcept
+{
+ // CBOR requires that the shortest of the two strings be sorted first, so
+ // we have to calculate the UTF-8 length of the UTF-16 string while
+ // comparing. Unlike the UTF-32 comparison above, we convert the UTF-16
+ // string to UTF-8 so we only need to decode one string.
+
+ const qsizetype len1 = lhs.size();
+ const auto src1 = reinterpret_cast<const uchar *>(lhs.data());
+ const char16_t *src2 = rhs.utf16();
+ const char16_t *const end2 = src2 + rhs.size();
+
+ // Compare the two strings until we find a difference.
+ int diff = 0;
+ qptrdiff idx1 = 0;
+ qsizetype len2 = 0;
+ do {
+ uchar utf8[4]; // longest possible Unicode character in UTF-8
+ uchar *ptr = utf8;
+ char16_t uc = *src2++;
+ int r = QUtf8Functions::toUtf8<QUtf8BaseTraits>(uc, ptr, src2, end2);
+ Q_UNUSED(r); // ignore failure to encode proper UTF-16 surrogates
+
+ qptrdiff n = ptr - utf8;
+ len2 += n;
+ if (len1 - idx1 < n)
+ return -1; // lhs is definitely shorter
+ diff = memcmp(src1 + idx1, utf8, n);
+ idx1 += n;
+ } while (diff == 0 && idx1 < len1 && src2 < end2);
+
+ if (mode == Comparison::ForEquality && diff)
+ return diff;
+ if ((idx1 == len1) != (src2 == end2)) {
+ // One of the strings ended earlier than the other
+ return idx1 == len1 ? -1 : 1;
+ }
+
+ // We found a difference and neither string ended, so continue calculating
+ // the UTF-8 length of rhs.
+ len2 += stringLengthInUtf8(src2, end2);
+
+ if (len1 != len2)
+ return len1 < len2 ? -1 : 1;
+ return diff;
+}
+
+static int compareStringsInUtf8(QStringView lhs, QUtf8StringView rhs, Comparison mode) noexcept
+{
+ return -compareStringsInUtf8(rhs, lhs, mode);
+}
+
QT_WARNING_DISABLE_MSVC(4146) // unary minus operator applied to unsigned type, result still unsigned
-static int compareContainer(const QCborContainerPrivate *c1, const QCborContainerPrivate *c2);
-static int compareElementNoData(const Element &e1, const Element &e2)
+static int compareContainer(const QCborContainerPrivate *c1, const QCborContainerPrivate *c2,
+ Comparison mode) noexcept;
+static int compareElementNoData(const Element &e1, const Element &e2) noexcept
{
Q_ASSERT(e1.type == e2.type);
@@ -1110,15 +1258,16 @@ static int compareElementNoData(const Element &e1, const Element &e2)
}
static int compareElementRecursive(const QCborContainerPrivate *c1, const Element &e1,
- const QCborContainerPrivate *c2, const Element &e2)
+ const QCborContainerPrivate *c2, const Element &e2,
+ Comparison mode) noexcept
{
- int cmp = typeOrder(e1, e2);
+ int cmp = typeOrder(e1.type, e2.type);
if (cmp != 0)
return cmp;
if ((e1.flags & Element::IsContainer) || (e2.flags & Element::IsContainer))
return compareContainer(e1.flags & Element::IsContainer ? e1.container : nullptr,
- e2.flags & Element::IsContainer ? e2.container : nullptr);
+ e2.flags & Element::IsContainer ? e2.container : nullptr, mode);
// string data?
const ByteData *b1 = c1 ? c1->byteData(e1) : nullptr;
@@ -1126,11 +1275,6 @@ static int compareElementRecursive(const QCborContainerPrivate *c1, const Elemen
if (b1 || b2) {
auto len1 = b1 ? b1->len : 0;
auto len2 = b2 ? b2->len : 0;
-
- if (e1.flags & Element::StringIsUtf16)
- len1 /= 2;
- if (e2.flags & Element::StringIsUtf16)
- len2 /= 2;
if (len1 == 0 || len2 == 0)
return len1 < len2 ? -1 : len1 == len2 ? 0 : 1;
@@ -1139,58 +1283,37 @@ static int compareElementRecursive(const QCborContainerPrivate *c1, const Elemen
Q_ASSERT(b2);
// Officially with CBOR, we sort first the string with the shortest
- // UTF-8 length. The length of an ASCII string is the same as its UTF-8
- // and UTF-16 ones, but the UTF-8 length of a string is bigger than the
- // UTF-16 equivalent. Combinations are:
- // 1) UTF-16 and UTF-16
- // 2) UTF-16 and UTF-8 <=== this is the problem case
- // 3) UTF-16 and US-ASCII
- // 4) UTF-8 and UTF-8
- // 5) UTF-8 and US-ASCII
- // 6) US-ASCII and US-ASCII
- if ((e1.flags & Element::StringIsUtf16) && (e2.flags & Element::StringIsUtf16)) {
- // Case 1: both UTF-16, so lengths are comparable.
- // (we can't use memcmp in little-endian machines)
- if (len1 == len2)
- return QtPrivate::compareStrings(b1->asStringView(), b2->asStringView());
- return len1 < len2 ? -1 : 1;
- }
+ // UTF-8 length. Since US-ASCII is just a subset of UTF-8, its length
+ // is the UTF-8 length. But the UTF-16 length may not be directly
+ // comparable.
+ if ((e1.flags & Element::StringIsUtf16) && (e2.flags & Element::StringIsUtf16))
+ return compareStringsInUtf8(b1->asStringView(), b2->asStringView(), mode);
if (!(e1.flags & Element::StringIsUtf16) && !(e2.flags & Element::StringIsUtf16)) {
- // Cases 4, 5 and 6: neither is UTF-16, so lengths are comparable too
+ // Neither is UTF-16, so lengths are comparable too
// (this case includes byte arrays too)
- if (len1 == len2)
+ if (len1 == len2) {
+ if (mode == Comparison::ForEquality) {
+ // GCC optimizes this to __memcmpeq(); Clang to bcmp()
+ return memcmp(b1->byte(), b2->byte(), size_t(len1)) == 0 ? 0 : 1;
+ }
return memcmp(b1->byte(), b2->byte(), size_t(len1));
+ }
return len1 < len2 ? -1 : 1;
}
- if (!(e1.flags & Element::StringIsAscii) || !(e2.flags & Element::StringIsAscii)) {
- // Case 2: one of them is UTF-8 and the other is UTF-16, so lengths
- // are NOT comparable. We need to convert to UTF-16 first...
- // (we can't use QUtf8::compareUtf8 because we need to compare lengths)
- auto string = [](const Element &e, const ByteData *b) {
- return e.flags & Element::StringIsUtf16 ? b->asQStringRaw() : b->toUtf8String();
- };
-
- QString s1 = string(e1, b1);
- QString s2 = string(e2, b2);
- if (s1.size() == s2.size())
- return s1.compare(s2);
- return s1.size() < s2.size() ? -1 : 1;
- }
-
- // Case 3 (UTF-16 and US-ASCII) remains, so lengths are comparable again
- if (len1 != len2)
- return len1 < len2 ? -1 : 1;
+ // Only one is UTF-16
if (e1.flags & Element::StringIsUtf16)
- return QtPrivate::compareStrings(b1->asStringView(), b2->asLatin1());
- return QtPrivate::compareStrings(b1->asLatin1(), b2->asStringView());
+ return compareStringsInUtf8(b1->asStringView(), b2->asUtf8StringView(), mode);
+ else
+ return compareStringsInUtf8(b1->asUtf8StringView(), b2->asStringView(), mode);
}
return compareElementNoData(e1, e2);
}
-static int compareContainer(const QCborContainerPrivate *c1, const QCborContainerPrivate *c2)
+static int compareContainer(const QCborContainerPrivate *c1, const QCborContainerPrivate *c2,
+ Comparison mode) noexcept
{
auto len1 = c1 ? c1->elements.size() : 0;
auto len2 = c2 ? c2->elements.size() : 0;
@@ -1202,7 +1325,7 @@ static int compareContainer(const QCborContainerPrivate *c1, const QCborContaine
for (qsizetype i = 0; i < len1; ++i) {
const Element &e1 = c1->elements.at(i);
const Element &e2 = c2->elements.at(i);
- int cmp = QCborContainerPrivate::compareElement_helper(c1, e1, c2, e2);
+ int cmp = compareElementRecursive(c1, e1, c2, e2, mode);
if (cmp)
return cmp;
}
@@ -1211,15 +1334,16 @@ static int compareContainer(const QCborContainerPrivate *c1, const QCborContaine
}
inline int QCborContainerPrivate::compareElement_helper(const QCborContainerPrivate *c1, Element e1,
- const QCborContainerPrivate *c2, Element e2)
+ const QCborContainerPrivate *c2, Element e2,
+ Comparison mode) noexcept
{
- return compareElementRecursive(c1, e1, c2, e2);
+ return compareElementRecursive(c1, e1, c2, e2, mode);
}
/*!
- \fn bool QCborValue::operator==(const QCborValue &other) const
+ \fn bool QCborValue::operator==(const QCborValue &lhs, const QCborValue &rhs)
- Compares this value and \a other, and returns true if they hold the same
+ Compares \a lhs and \a rhs, and returns true if they hold the same
contents, false otherwise. If each QCborValue contains an array or map, the
comparison is recursive to elements contained in them.
@@ -1230,9 +1354,9 @@ inline int QCborContainerPrivate::compareElement_helper(const QCborContainerPriv
*/
/*!
- \fn bool QCborValue::operator!=(const QCborValue &other) const
+ \fn bool QCborValue::operator!=(const QCborValue &lhs, const QCborValue &rhs)
- Compares this value and \a other, and returns true if contents differ,
+ Compares \a lhs and \a rhs, and returns true if contents differ,
false otherwise. If each QCborValue contains an array or map, the comparison
is recursive to elements contained in them.
@@ -1241,12 +1365,20 @@ inline int QCborContainerPrivate::compareElement_helper(const QCborContainerPriv
\sa compare(), QCborValue::operator==(), QCborMap::operator==(),
operator==(), operator<()
*/
+bool comparesEqual(const QCborValue &lhs,
+ const QCborValue &rhs) noexcept
+{
+ Element e1 = QCborContainerPrivate::elementFromValue(lhs);
+ Element e2 = QCborContainerPrivate::elementFromValue(rhs);
+ return compareElementRecursive(lhs.container, e1, rhs.container, e2,
+ Comparison::ForEquality) == 0;
+}
/*!
- \fn bool QCborValue::operator<(const QCborValue &other) const
+ \fn bool QCborValue::operator<(const QCborValue &lhs, const QCborValue &rhs)
- Compares this value and \a other, and returns true if this value should be
- sorted before \a other, false otherwise. If each QCborValue contains an
+ Compares \a lhs and \a rhs, and returns true if \a lhs should be
+ sorted before \a rhs, false otherwise. If each QCborValue contains an
array or map, the comparison is recursive to elements contained in them.
For more information on CBOR sorting order, see QCborValue::compare().
@@ -1256,6 +1388,47 @@ inline int QCborContainerPrivate::compareElement_helper(const QCborContainerPriv
*/
/*!
+ \fn bool QCborValue::operator<=(const QCborValue &lhs, const QCborValue &rhs)
+
+ Compares \a lhs and \a rhs, and returns true if \a lhs should be
+ sorted before \a rhs or is being equal to \a rhs, false otherwise.
+ If each QCborValue contains an array or map, the comparison is recursive
+ to elements contained in them.
+
+ For more information on CBOR sorting order, see QCborValue::compare().
+
+ \sa compare(), QCborValue::operator<(), QCborMap::operator==(),
+ operator==(), operator!=()
+*/
+
+/*!
+ \fn bool QCborValue::operator>(const QCborValue &lhs, const QCborValue &rhs)
+
+ Compares \a lhs and \a rhs, and returns true if \a lhs should be
+ sorted after \a rhs, false otherwise. If each QCborValue contains an
+ array or map, the comparison is recursive to elements contained in them.
+
+ For more information on CBOR sorting order, see QCborValue::compare().
+
+ \sa compare(), QCborValue::operator>=(), QCborMap::operator==(),
+ operator==(), operator!=()
+*/
+
+/*!
+ \fn bool QCborValue::operator>=(const QCborValue &lhs, const QCborValue &rhs)
+
+ Compares \a lhs and \a rhs, and returns true if \a lhs should be
+ sorted after \a rhs or is being equal to \a rhs, false otherwise.
+ If each QCborValue contains an array or map, the comparison is recursive
+ to elements contained in them.
+
+ For more information on CBOR sorting order, see QCborValue::compare().
+
+ \sa compare(), QCborValue::operator>(), QCborMap::operator==(),
+ operator==(), operator!=()
+*/
+
+/*!
Compares this value and \a other, and returns an integer that indicates
whether this value should be sorted prior to (if the result is negative) or
after \a other (if the result is positive). If this function returns 0, the
@@ -1320,17 +1493,59 @@ int QCborValue::compare(const QCborValue &other) const
{
Element e1 = QCborContainerPrivate::elementFromValue(*this);
Element e2 = QCborContainerPrivate::elementFromValue(other);
- return compareElementRecursive(container, e1, other.container, e2);
+ return compareElementRecursive(container, e1, other.container, e2, Comparison::ForOrdering);
+}
+
+bool comparesEqual(const QCborArray &lhs, const QCborArray &rhs) noexcept
+{
+ return compareContainer(lhs.d.constData(), rhs.d.constData(), Comparison::ForEquality) == 0;
}
int QCborArray::compare(const QCborArray &other) const noexcept
{
- return compareContainer(d.data(), other.d.data());
+ return compareContainer(d.data(), other.d.data(), Comparison::ForOrdering);
+}
+
+bool QCborArray::comparesEqual_helper(const QCborArray &lhs, const QCborValue &rhs) noexcept
+{
+ if (typeOrder(QCborValue::Array, rhs.type()))
+ return false;
+ return compareContainer(lhs.d.constData(), rhs.container, Comparison::ForEquality) == 0;
+}
+
+Qt::strong_ordering
+QCborArray::compareThreeWay_helper(const QCborArray &lhs, const QCborValue &rhs) noexcept
+{
+ int c = typeOrder(QCborValue::Array, rhs.type());
+ if (c == 0)
+ c = compareContainer(lhs.d.constData(), rhs.container, Comparison::ForOrdering);
+ return Qt::compareThreeWay(c, 0);
+}
+
+bool comparesEqual(const QCborMap &lhs, const QCborMap &rhs) noexcept
+{
+ return compareContainer(lhs.d.constData(), rhs.d.constData(), Comparison::ForEquality) == 0;
}
int QCborMap::compare(const QCborMap &other) const noexcept
{
- return compareContainer(d.data(), other.d.data());
+ return compareContainer(d.data(), other.d.data(), Comparison::ForOrdering);
+}
+
+bool QCborMap::comparesEqual_helper(const QCborMap &lhs, const QCborValue &rhs) noexcept
+{
+ if (typeOrder(QCborValue::Map, rhs.type()))
+ return false;
+ return compareContainer(lhs.d.constData(), rhs.container, Comparison::ForEquality) == 0;
+}
+
+Qt::strong_ordering
+QCborMap::compareThreeWay_helper(const QCborMap &lhs, const QCborValue &rhs) noexcept
+{
+ int c = typeOrder(QCborValue::Map, rhs.type());
+ if (c == 0)
+ c = compareContainer(lhs.d.constData(), rhs.container, Comparison::ForOrdering);
+ return Qt::compareThreeWay(c, 0);
}
#if QT_CONFIG(cborstreamwriter)
@@ -1593,7 +1808,7 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
// add space for aligned ByteData (this can't overflow)
offset += sizeof(QtCbor::ByteData) + alignof(QtCbor::ByteData);
offset &= ~(alignof(QtCbor::ByteData) - 1);
- if (offset > size_t(MaxByteArraySize)) {
+ if (offset > size_t(QByteArray::max_size())) {
// overflow
setErrorInReader(reader, { QCborError::DataTooLarge });
return;
@@ -1606,9 +1821,9 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
// so capa how much we allocate
newCapacity = offset + MaxMemoryIncrement - EstimatedOverhead;
}
- if (newCapacity > size_t(MaxByteArraySize)) {
+ if (newCapacity > size_t(QByteArray::max_size())) {
// this may cause an allocation failure
- newCapacity = MaxByteArraySize;
+ newCapacity = QByteArray::max_size();
}
if (newCapacity > size_t(data.capacity()))
data.reserve(newCapacity);
@@ -1659,7 +1874,7 @@ void QCborContainerPrivate::decodeStringFromCbor(QCborStreamReader &reader)
// check that this UTF-8 text string can be loaded onto a QString
if (e.type == QCborValue::String) {
- if (Q_UNLIKELY(b->len > MaxStringSize)) {
+ if (Q_UNLIKELY(b->len > QString::max_size())) {
setErrorInReader(reader, { QCborError::DataTooLarge });
status = QCborStreamReader::Error;
}
@@ -2248,12 +2463,6 @@ static void convertArrayToMap(QCborContainerPrivate *&array)
for (qsizetype i = 0; i < size; ++i)
dst[i * 2] = { i, QCborValue::Integer };
- // only do this last portion if we're not modifying in-place
- for (qsizetype i = 0; src != dst && i < size; ++i) {
- if (dst[i * 2 + 1].flags & QtCbor::Element::IsContainer)
- dst[i * 2 + 1].container->ref.ref();
- }
-
// update reference counts
assignContainer(array, map);
}
@@ -2678,6 +2887,76 @@ QString QCborValueConstRef::concreteString(QCborValueConstRef self, const QStrin
return self.d->stringAt(self.i);
}
+bool
+QCborValueConstRef::comparesEqual_helper(QCborValueConstRef lhs, QCborValueConstRef rhs) noexcept
+{
+ QtCbor::Element e1 = lhs.d->elements.at(lhs.i);
+ QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
+ return compareElementRecursive(lhs.d, e1, rhs.d, e2, Comparison::ForEquality) == 0;
+}
+
+Qt::strong_ordering
+QCborValueConstRef::compareThreeWay_helper(QCborValueConstRef lhs, QCborValueConstRef rhs) noexcept
+{
+ QtCbor::Element e1 = lhs.d->elements.at(lhs.i);
+ QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
+ int c = compareElementRecursive(lhs.d, e1, rhs.d, e2, Comparison::ForOrdering);
+ return Qt::compareThreeWay(c, 0);
+}
+
+bool
+QCborValueConstRef::comparesEqual_helper(QCborValueConstRef lhs, const QCborValue &rhs) noexcept
+{
+ QtCbor::Element e1 = lhs.d->elements.at(lhs.i);
+ QtCbor::Element e2 = QCborContainerPrivate::elementFromValue(rhs);
+ return compareElementRecursive(lhs.d, e1, rhs.container, e2, Comparison::ForEquality) == 0;
+}
+
+Qt::strong_ordering
+QCborValueConstRef::compareThreeWay_helper(QCborValueConstRef lhs, const QCborValue &rhs) noexcept
+{
+ QtCbor::Element e1 = lhs.d->elements.at(lhs.i);
+ QtCbor::Element e2 = QCborContainerPrivate::elementFromValue(rhs);
+ int c = compareElementRecursive(lhs.d, e1, rhs.container, e2, Comparison::ForOrdering);
+ return Qt::compareThreeWay(c, 0);
+}
+
+bool QCborArray::comparesEqual_helper(const QCborArray &lhs, QCborValueConstRef rhs) noexcept
+{
+ QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
+ if (typeOrder(QCborValue::Array, e2.type))
+ return false;
+ return compareContainer(lhs.d.constData(), e2.container, Comparison::ForEquality) == 0;
+}
+
+Qt::strong_ordering
+QCborArray::compareThreeWay_helper(const QCborArray &lhs, QCborValueConstRef rhs) noexcept
+{
+ QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
+ int c = typeOrder(QCborValue::Array, e2.type);
+ if (c == 0)
+ c = compareContainer(lhs.d.constData(), e2.container, Comparison::ForOrdering);
+ return Qt::compareThreeWay(c, 0);
+}
+
+bool QCborMap::comparesEqual_helper(const QCborMap &lhs, QCborValueConstRef rhs) noexcept
+{
+ QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
+ if (typeOrder(QCborValue::Array, e2.type))
+ return false;
+ return compareContainer(lhs.d.constData(), e2.container, Comparison::ForEquality) == 0;
+}
+
+Qt::strong_ordering
+QCborMap::compareThreeWay_helper(const QCborMap &lhs, QCborValueConstRef rhs) noexcept
+{
+ QtCbor::Element e2 = rhs.d->elements.at(rhs.i);
+ int c = typeOrder(QCborValue::Map, e2.type);
+ if (c == 0)
+ c = compareContainer(lhs.d.constData(), e2.container, Comparison::ForOrdering);
+ return Qt::compareThreeWay(c, 0);
+}
+
QCborValue QCborValueConstRef::concrete(QCborValueConstRef self) noexcept
{
return self.d->valueAt(self.i);
diff --git a/src/corelib/serialization/qcborvalue.h b/src/corelib/serialization/qcborvalue.h
index b90d397bcc..93adbec344 100644
--- a/src/corelib/serialization/qcborvalue.h
+++ b/src/corelib/serialization/qcborvalue.h
@@ -5,8 +5,9 @@
#define QCBORVALUE_H
#include <QtCore/qbytearray.h>
-#include <QtCore/qdatetime.h>
#include <QtCore/qcborcommon.h>
+#include <QtCore/qcompare.h>
+#include <QtCore/qdatetime.h>
#if QT_CONFIG(regularexpression)
# include <QtCore/qregularexpression.h>
#endif
@@ -22,10 +23,6 @@
# undef False
#endif
-#if 0 && __has_include(<compare>)
-# include <compare>
-#endif
-
QT_BEGIN_NAMESPACE
class QCborArray;
@@ -222,19 +219,11 @@ public:
QCborValueRef operator[](const QString & key);
int compare(const QCborValue &other) const;
-#if 0 && __has_include(<compare>)
- std::strong_ordering operator<=>(const QCborValue &other) const
- {
- int c = compare(other);
- if (c > 0) return std::partial_ordering::greater;
- if (c == 0) return std::partial_ordering::equivalent;
- return std::partial_ordering::less;
- }
-#else
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QCborValue &other) const noexcept
{ return compare(other) == 0; }
bool operator!=(const QCborValue &other) const noexcept
- { return !(*this == other); }
+ { return !operator==(other); }
bool operator<(const QCborValue &other) const
{ return compare(other) < 0; }
#endif
@@ -260,6 +249,19 @@ public:
QString toDiagnosticNotation(DiagnosticNotationOptions opts = Compact) const;
private:
+ friend Q_CORE_EXPORT Q_DECL_PURE_FUNCTION
+ bool comparesEqual(const QCborValue &lhs, const QCborValue &rhs) noexcept;
+ friend Qt::strong_ordering compareThreeWay(const QCborValue &lhs,
+ const QCborValue &rhs) noexcept
+ {
+ int c = lhs.compare(rhs);
+ return Qt::compareThreeWay(c, 0);
+ }
+
+ Q_DECLARE_STRONGLY_ORDERED(QCborValue)
+ friend class QCborArray;
+ friend class QCborMap;
+ friend class QCborValueConstRef;
friend class QCborValueRef;
friend class QCborContainerPrivate;
friend class QJsonPrivate::Value;
@@ -369,22 +371,6 @@ public:
int compare(const QCborValue &other) const
{ return concrete().compare(other); }
-#if 0 && __has_include(<compare>)
- std::strong_ordering operator<=>(const QCborValue &other) const
- {
- int c = compare(other);
- if (c > 0) return std::strong_ordering::greater;
- if (c == 0) return std::strong_ordering::equivalent;
- return std::strong_ordering::less;
- }
-#else
- bool operator==(const QCborValue &other) const
- { return compare(other) == 0; }
- bool operator!=(const QCborValue &other) const
- { return !(*this == other); }
- bool operator<(const QCborValue &other) const
- { return compare(other) < 0; }
-#endif
QVariant toVariant() const { return concrete().toVariant(); }
inline QJsonValue toJsonValue() const; // in qjsonvalue.h
@@ -406,6 +392,37 @@ protected:
friend class QCborContainerPrivate;
QCborValue concrete() const noexcept { return concrete(*this); }
+ static Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool
+ comparesEqual_helper(QCborValueConstRef lhs, QCborValueConstRef rhs) noexcept;
+ static Q_CORE_EXPORT Q_DECL_PURE_FUNCTION Qt::strong_ordering
+ compareThreeWay_helper(QCborValueConstRef lhs, QCborValueConstRef rhs) noexcept;
+ friend bool comparesEqual(const QCborValueConstRef &lhs,
+ const QCborValueConstRef &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const QCborValueConstRef &lhs,
+ const QCborValueConstRef &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QCborValueConstRef)
+
+ static Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool
+ comparesEqual_helper(QCborValueConstRef lhs, const QCborValue &rhs) noexcept;
+ static Q_CORE_EXPORT Q_DECL_PURE_FUNCTION Qt::strong_ordering
+ compareThreeWay_helper(QCborValueConstRef lhs, const QCborValue &rhs) noexcept;
+ friend bool comparesEqual(const QCborValueConstRef &lhs,
+ const QCborValue &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const QCborValueConstRef &lhs,
+ const QCborValue &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QCborValueConstRef, QCborValue)
static Q_CORE_EXPORT QCborValue concrete(QCborValueConstRef that) noexcept;
static Q_CORE_EXPORT QCborValue::Type concreteType(QCborValueConstRef that) noexcept Q_DECL_PURE_FUNCTION;
@@ -428,6 +445,8 @@ protected:
qsizetype i;
};
+QT_WARNING_PUSH
+QT6_ONLY(QT_WARNING_DISABLE_MSVC(4275)) // non dll-interface class 'QJsonValueConstRef' used as base for dll-interface class 'QJsonValueRef'
class QT6_ONLY(Q_CORE_EXPORT) QCborValueRef : public QCborValueConstRef
{
public:
@@ -522,19 +541,11 @@ public:
int compare(const QCborValue &other) const
{ return concrete().compare(other); }
-#if 0 && __has_include(<compare>)
- std::strong_ordering operator<=>(const QCborValue &other) const
- {
- int c = compare(other);
- if (c > 0) return std::strong_ordering::greater;
- if (c == 0) return std::strong_ordering::equivalent;
- return std::strong_ordering::less;
- }
-#else
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QCborValue &other) const
{ return compare(other) == 0; }
bool operator!=(const QCborValue &other) const
- { return !(*this == other); }
+ { return !operator==(other); }
bool operator<(const QCborValue &other) const
{ return compare(other) < 0; }
#endif
@@ -582,6 +593,7 @@ private:
QT7_ONLY(Q_CORE_EXPORT) static void assign(QCborValueRef that, QCborValue &&other);
QT7_ONLY(Q_CORE_EXPORT) static void assign(QCborValueRef that, const QCborValueRef other);
};
+QT_WARNING_POP
Q_DECLARE_OPERATORS_FOR_FLAGS(QCborValue::EncodingOptions)
Q_DECLARE_OPERATORS_FOR_FLAGS(QCborValue::DiagnosticNotationOptions)
diff --git a/src/corelib/serialization/qcborvalue_p.h b/src/corelib/serialization/qcborvalue_p.h
index c5cc6c6f0b..33eb912a6d 100644
--- a/src/corelib/serialization/qcborvalue_p.h
+++ b/src/corelib/serialization/qcborvalue_p.h
@@ -29,6 +29,11 @@
QT_BEGIN_NAMESPACE
namespace QtCbor {
+enum class Comparison {
+ ForEquality,
+ ForOrdering,
+};
+
struct Undefined {};
struct Element
{
@@ -103,18 +108,19 @@ public:
QList<QtCbor::Element> elements;
void deref() { if (!ref.deref()) delete this; }
- void compact(qsizetype reserved);
+ void compact();
static QCborContainerPrivate *clone(QCborContainerPrivate *d, qsizetype reserved = -1);
static QCborContainerPrivate *detach(QCborContainerPrivate *d, qsizetype reserved);
static QCborContainerPrivate *grow(QCborContainerPrivate *d, qsizetype index);
- qptrdiff addByteData(const char *block, qsizetype len)
+ static qptrdiff addByteDataImpl(QByteArray &target, QByteArray::size_type &targetUsed,
+ const char *block, qsizetype len)
{
// This function does not do overflow checking, since the len parameter
// is expected to be trusted. There's another version of this function
// in decodeStringFromCbor(), which checks.
- qptrdiff offset = data.size();
+ qptrdiff offset = target.size();
// align offset
offset += alignof(QtCbor::ByteData) - 1;
@@ -122,10 +128,10 @@ public:
qptrdiff increment = qptrdiff(sizeof(QtCbor::ByteData)) + len;
- usedData += increment;
- data.resize(offset + increment);
+ targetUsed += increment;
+ target.resize(offset + increment);
- char *ptr = data.begin() + offset;
+ char *ptr = target.begin() + offset;
auto b = new (ptr) QtCbor::ByteData;
b->len = len;
if (block)
@@ -134,6 +140,11 @@ public:
return offset;
}
+ qptrdiff addByteData(const char *block, qsizetype len)
+ {
+ return addByteDataImpl(data, usedData, block, len);
+ }
+
const QtCbor::ByteData *byteData(QtCbor::Element e) const
{
if ((e.flags & QtCbor::Element::HasByteData) == 0)
@@ -184,7 +195,7 @@ public:
}
void insertAt(qsizetype idx, const QCborValue &value, ContainerDisposition disp = CopyContainer)
{
- replaceAt_internal(*elements.insert(elements.begin() + int(idx), {}), value, disp);
+ replaceAt_internal(*elements.insert(idx, {}), value, disp);
}
void append(QtCbor::Undefined)
@@ -217,13 +228,14 @@ public:
void append(QLatin1StringView s)
{
if (!QtPrivate::isAscii(s))
- return append(QString(s));
+ return appendNonAsciiString(QString(s));
// US-ASCII is a subset of UTF-8, so we can keep in 8-bit
appendByteData(s.latin1(), s.size(), QCborValue::String,
QtCbor::Element::StringIsAscii);
}
void appendAsciiString(QStringView s);
+ void appendNonAsciiString(QStringView s);
void append(const QString &s)
{
@@ -235,8 +247,7 @@ public:
if (QtPrivate::isAscii(s))
appendAsciiString(s);
else
- appendByteData(reinterpret_cast<const char *>(s.utf16()), s.size() * 2,
- QCborValue::String, QtCbor::Element::StringIsUtf16);
+ appendNonAsciiString(s);
}
void append(const QCborValue &v)
{
@@ -340,7 +351,7 @@ public:
}
template<typename String>
- int stringCompareElement(const QtCbor::Element &e, String s) const
+ int stringCompareElement(const QtCbor::Element &e, String s, QtCbor::Comparison mode) const
{
if (e.type != QCborValue::String)
return int(e.type) - int(QCborValue::String);
@@ -349,15 +360,18 @@ public:
if (!b)
return s.isEmpty() ? 0 : -1;
- if (e.flags & QtCbor::Element::StringIsUtf16)
+ if (e.flags & QtCbor::Element::StringIsUtf16) {
+ if (mode == QtCbor::Comparison::ForEquality)
+ return QtPrivate::equalStrings(b->asStringView(), s) ? 0 : 1;
return QtPrivate::compareStrings(b->asStringView(), s);
+ }
return compareUtf8(b, s);
}
template<typename String>
bool stringEqualsElement(const QtCbor::Element &e, String s) const
{
- return stringCompareElement(e, s) == 0;
+ return stringCompareElement(e, s, QtCbor::Comparison::ForEquality) == 0;
}
template<typename String>
@@ -367,12 +381,13 @@ public:
}
static int compareElement_helper(const QCborContainerPrivate *c1, QtCbor::Element e1,
- const QCborContainerPrivate *c2, QtCbor::Element e2);
- int compareElement(qsizetype idx, const QCborValue &value) const
+ const QCborContainerPrivate *c2, QtCbor::Element e2,
+ QtCbor::Comparison mode) noexcept;
+ int compareElement(qsizetype idx, const QCborValue &value, QtCbor::Comparison mode) const
{
auto &e1 = elements.at(idx);
auto e2 = elementFromValue(value);
- return compareElement_helper(this, e1, value.container, e2);
+ return compareElement_helper(this, e1, value.container, e2, mode);
}
void removeAt(qsizetype idx)
@@ -389,7 +404,7 @@ public:
const auto &e = elements.at(i);
bool equals;
if constexpr (std::is_same_v<std::decay_t<KeyType>, QCborValue>) {
- equals = (compareElement(i, key) == 0);
+ equals = (compareElement(i, key, QtCbor::Comparison::ForEquality) == 0);
} else if constexpr (std::is_integral_v<KeyType>) {
equals = (e.type == QCborValue::Integer && e.value == key);
} else {
diff --git a/src/corelib/serialization/qdatastream.cpp b/src/corelib/serialization/qdatastream.cpp
index 9372cb421f..329be4a294 100644
--- a/src/corelib/serialization/qdatastream.cpp
+++ b/src/corelib/serialization/qdatastream.cpp
@@ -15,6 +15,9 @@
QT_BEGIN_NAMESPACE
+constexpr quint32 QDataStream::NullCode;
+constexpr quint32 QDataStream::ExtendedSize;
+
/*!
\class QDataStream
\inmodule QtCore
@@ -67,17 +70,30 @@ QT_BEGIN_NAMESPACE
need of manually defining streaming operators. Enum classes are
serialized using the declared size.
- To take one example, a \c{char *} string is written as a 32-bit
- integer equal to the length of the string including the '\\0' byte,
- followed by all the characters of the string including the
- '\\0' byte. When reading a \c{char *} string, 4 bytes are read to
- create the 32-bit length value, then that many characters for the
- \c {char *} string including the '\\0' terminator are read.
-
The initial I/O device is usually set in the constructor, but can be
changed with setDevice(). If you've reached the end of the data
(or if there is no I/O device set) atEnd() will return true.
+ \section1 Serializing containers and strings
+
+ The serialization format is a length specifier first, then \a l bytes of data.
+ The length specifier is one quint32 if the version is less than 6.7 or if the
+ number of elements is less than 0xfffffffe (2^32 -2). Otherwise there is
+ an extend value 0xfffffffe followed by one quint64 with the actual value.
+ In addition for containers that support isNull(), it is encoded as a single
+ quint32 with all bits set and no data.
+
+ To take one example, if the string size fits into 32 bits, a \c{char *} string
+ is written as a 32-bit integer equal to the length of the string, including
+ the '\\0' byte, followed by all the characters of the string, including the
+ '\\0' byte. If the string size is greater, the value 0xffffffffe is written
+ as a marker of an extended size, followed by 64 bits of the actual size.
+ When reading a \c {char *} string, 4 bytes are read first. If the value is
+ not equal to 0xffffffffe (the marker of extended size), then these 4 bytes
+ are treated as the 32 bit size of the string. Otherwise, the next 8 bytes are
+ read and treated as a 64 bit size of the string. Then, all the characters for
+ the \c {char *} string, including the '\\0' terminator, are read.
+
\section1 Versioning
QDataStream's binary format has evolved since Qt 1.0, and is
@@ -164,6 +180,27 @@ QT_BEGIN_NAMESPACE
If no full packet is received, this code restores the stream to the
initial position, after which you need to wait for more data to arrive.
+ \section1 Corruption and Security
+
+ QDataStream is not resilient against corrupted data inputs and should
+ therefore not be used for security-sensitive situations, even when using
+ transactions. Transactions will help determine if a valid input can
+ currently be decoded with the data currently available on an asynchronous
+ device, but will assume that the data that is available is correctly
+ formed.
+
+ Additionally, many QDataStream demarshalling operators will allocate memory
+ based on information found in the stream. Those operators perform no
+ verification on whether the requested amount of memory is reasonable or if
+ it is compatible with the amount of data available in the stream (example:
+ demarshalling a QByteArray or QString may see the request for allocation of
+ several gigabytes of data).
+
+ QDataStream should not be used on content whose provenance cannot be
+ trusted. Applications should be designed to attempt to decode only streams
+ whose provenance is at least as trustworthy as that of the application
+ itself or its plugins.
+
\sa QTextStream, QVariant
*/
@@ -201,6 +238,11 @@ QT_BEGIN_NAMESPACE
data in the underlying device.
\value ReadCorruptData The data stream has read corrupt data.
\value WriteFailed The data stream cannot write to the underlying device.
+ \value [since 6.7] SizeLimitExceeded The data stream cannot read or write
+ the data because its size is larger than supported
+ by the current platform. This can happen, for
+ example, when trying to read more that 2 GiB of
+ data on a 32-bit platform.
*/
/*****************************************************************************
@@ -229,7 +271,7 @@ QT_BEGIN_NAMESPACE
return retVal;
#define CHECK_STREAM_TRANSACTION_PRECOND(retVal) \
- if (!d || d->transactionDepth == 0) { \
+ if (transactionDepth == 0) { \
qWarning("QDataStream: No transaction in progress"); \
return retVal; \
}
@@ -242,12 +284,6 @@ QT_BEGIN_NAMESPACE
QDataStream::QDataStream()
{
- dev = nullptr;
- owndev = false;
- byteorder = BigEndian;
- ver = Qt_DefaultCompiledVersion;
- noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
- q_status = Ok;
}
/*!
@@ -259,11 +295,6 @@ QDataStream::QDataStream()
QDataStream::QDataStream(QIODevice *d)
{
dev = d; // set device
- owndev = false;
- byteorder = BigEndian; // default byte order
- ver = Qt_DefaultCompiledVersion;
- noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
- q_status = Ok;
}
/*!
@@ -288,10 +319,6 @@ QDataStream::QDataStream(QByteArray *a, OpenMode flags)
buf->open(flags);
dev = buf;
owndev = true;
- byteorder = BigEndian;
- ver = Qt_DefaultCompiledVersion;
- noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
- q_status = Ok;
}
/*!
@@ -312,10 +339,6 @@ QDataStream::QDataStream(const QByteArray &a)
buf->open(QIODevice::ReadOnly);
dev = buf;
owndev = true;
- byteorder = BigEndian;
- ver = Qt_DefaultCompiledVersion;
- noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
- q_status = Ok;
}
/*!
@@ -377,16 +400,14 @@ bool QDataStream::atEnd() const
}
/*!
+ \fn QDataStream::FloatingPointPrecision QDataStream::floatingPointPrecision() const
+
Returns the floating point precision of the data stream.
\since 4.6
\sa FloatingPointPrecision, setFloatingPointPrecision()
*/
-QDataStream::FloatingPointPrecision QDataStream::floatingPointPrecision() const
-{
- return d ? d->floatingPointPrecision : QDataStream::DoublePrecision;
-}
/*!
Sets the floating point precision of the data stream to \a precision. If the floating point precision is
@@ -410,22 +431,17 @@ QDataStream::FloatingPointPrecision QDataStream::floatingPointPrecision() const
*/
void QDataStream::setFloatingPointPrecision(QDataStream::FloatingPointPrecision precision)
{
- if (!d)
- d.reset(new QDataStreamPrivate());
- d->floatingPointPrecision = precision;
+ fpPrecision = precision;
}
/*!
+ \fn QDataStream::status() const
+
Returns the status of the data stream.
\sa Status, setStatus(), resetStatus()
*/
-QDataStream::Status QDataStream::status() const
-{
- return q_status;
-}
-
/*!
Resets the status of the data stream.
@@ -473,11 +489,14 @@ void QDataStream::setStatus(Status status)
void QDataStream::setByteOrder(ByteOrder bo)
{
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
+ // accessed by inline byteOrder() prior to Qt 6.8
byteorder = bo;
+#endif
if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
- noswap = (byteorder == BigEndian);
+ noswap = (bo == BigEndian);
else
- noswap = (byteorder == LittleEndian);
+ noswap = (bo == LittleEndian);
}
@@ -525,7 +544,9 @@ void QDataStream::setByteOrder(ByteOrder bo)
\value Qt_6_3 Same as Qt_6_0
\value Qt_6_4 Same as Qt_6_0
\value Qt_6_5 Same as Qt_6_0
- \value Qt_6_6 Same as Qt_6_0
+ \value Qt_6_6 Version 21 (Qt 6.6)
+ \value Qt_6_7 Version 22 (Qt 6.7)
+ \value Qt_6_8 Same as Qt_6_7
\omitvalue Qt_DefaultCompiledVersion
\sa setVersion(), version()
@@ -599,10 +620,7 @@ void QDataStream::startTransaction()
{
CHECK_STREAM_PRECOND(Q_VOID)
- if (!d)
- d.reset(new QDataStreamPrivate());
-
- if (++d->transactionDepth == 1) {
+ if (++transactionDepth == 1) {
dev->startTransaction();
resetStatus();
}
@@ -631,7 +649,7 @@ void QDataStream::startTransaction()
bool QDataStream::commitTransaction()
{
CHECK_STREAM_TRANSACTION_PRECOND(false)
- if (--d->transactionDepth == 0) {
+ if (--transactionDepth == 0) {
CHECK_STREAM_PRECOND(false)
if (q_status == ReadPastEnd) {
@@ -671,7 +689,7 @@ void QDataStream::rollbackTransaction()
setStatus(ReadPastEnd);
CHECK_STREAM_TRANSACTION_PRECOND(Q_VOID)
- if (--d->transactionDepth != 0)
+ if (--transactionDepth != 0)
return;
CHECK_STREAM_PRECOND(Q_VOID)
@@ -707,7 +725,7 @@ void QDataStream::abortTransaction()
q_status = ReadCorruptData;
CHECK_STREAM_TRANSACTION_PRECOND(Q_VOID)
- if (--d->transactionDepth != 0)
+ if (--transactionDepth != 0)
return;
CHECK_STREAM_PRECOND(Q_VOID)
@@ -730,13 +748,13 @@ bool QDataStream::isDeviceTransactionStarted() const
\internal
*/
-int QDataStream::readBlock(char *data, int len)
+qint64 QDataStream::readBlock(char *data, qint64 len)
{
// Disable reads on failure in transacted stream
if (q_status != Ok && dev->isTransactionStarted())
return -1;
- const int readResult = dev->read(data, len);
+ const qint64 readResult = dev->read(data, len);
if (readResult != len)
setStatus(ReadPastEnd);
return readResult;
@@ -961,10 +979,11 @@ QDataStream &QDataStream::operator>>(double &f)
/*!
\overload
- Reads the '\\0'-terminated string \a s from the stream and returns
- a reference to the stream.
+ Reads string \a s from the stream and returns a reference to the stream.
- The string is deserialized using \c{readBytes()}.
+ The string is deserialized using \c{readBytes()} where the serialization
+ format is a \c quint32 length specifier first, followed by that many bytes
+ of data. The resulting string is always '\\0'-terminated.
Space for the string is allocated using \c{new []} -- the caller must
destroy it with \c{delete []}.
@@ -974,7 +993,7 @@ QDataStream &QDataStream::operator>>(double &f)
QDataStream &QDataStream::operator>>(char *&s)
{
- uint len = 0;
+ qint64 len = 0;
return readBytes(s, len);
}
@@ -1008,7 +1027,29 @@ QDataStream &QDataStream::operator>>(char32_t &c)
return *this;
}
+#if QT_DEPRECATED_SINCE(6, 11)
+
+/*
+ \deprecated [6.11] Use an overload that takes qint64 length instead.
+*/
+QDataStream &QDataStream::readBytes(char *&s, uint &l)
+{
+ qint64 length = 0;
+ (void)readBytes(s, length);
+ if (length != qint64(uint(length))) {
+ setStatus(SizeLimitExceeded); // Cannot store length in l
+ delete[] s;
+ l = 0;
+ return *this;
+ }
+ l = uint(length);
+ return *this;
+}
+
+#endif // QT_DEPRECATED_SINCE(6, 11)
+
/*!
+ \since 6.7
Reads the buffer \a s from the stream and returns a reference to
the stream.
@@ -1018,46 +1059,53 @@ QDataStream &QDataStream::operator>>(char32_t &c)
The \a l parameter is set to the length of the buffer. If the
string read is empty, \a l is set to 0 and \a s is set to \nullptr.
- The serialization format is a quint32 length specifier first,
- then \a l bytes of data.
+ The serialization format is a length specifier first, then \a l
+ bytes of data. The length specifier is one quint32 if the version
+ is less than 6.7 or if the number of elements is less than 0xfffffffe
+ (2^32 -2), otherwise there is an extend value 0xfffffffe followed by
+ one quint64 with the actual value. In addition for containers that
+ support isNull(), it is encoded as a single quint32 with all bits
+ set and no data.
\sa readRawData(), writeBytes()
*/
-QDataStream &QDataStream::readBytes(char *&s, uint &l)
+QDataStream &QDataStream::readBytes(char *&s, qint64 &l)
{
s = nullptr;
l = 0;
CHECK_STREAM_PRECOND(*this)
- quint32 len;
- *this >> len;
- if (len == 0)
+ qint64 length = readQSizeType(*this);
+ if (length == 0)
return *this;
- const quint32 Step = 1024 * 1024;
- quint32 allocated = 0;
- char *prevBuf = nullptr;
- char *curBuf = nullptr;
+ qsizetype len = qsizetype(length);
+ if (length != len || length < 0) {
+ setStatus(SizeLimitExceeded); // Cannot store len
+ return *this;
+ }
+
+ qsizetype step = (dev->bytesAvailable() >= len) ? len : 1024 * 1024;
+ qsizetype allocated = 0;
+ std::unique_ptr<char[]> curBuf = nullptr;
+ constexpr qsizetype StepIncreaseThreshold = std::numeric_limits<qsizetype>::max() / 2;
do {
- int blockSize = qMin(Step, len - allocated);
- prevBuf = curBuf;
- curBuf = new char[allocated + blockSize + 1];
- if (prevBuf) {
- memcpy(curBuf, prevBuf, allocated);
- delete [] prevBuf;
- }
- if (readBlock(curBuf + allocated, blockSize) != blockSize) {
- delete [] curBuf;
+ qsizetype blockSize = qMin(step, len - allocated);
+ const qsizetype n = allocated + blockSize + 1;
+ if (const auto prevBuf = std::exchange(curBuf, std::make_unique<char[]>(n)))
+ memcpy(curBuf.get(), prevBuf.get(), allocated);
+ if (readBlock(curBuf.get() + allocated, blockSize) != blockSize)
return *this;
- }
allocated += blockSize;
+ if (step <= StepIncreaseThreshold)
+ step *= 2;
} while (allocated < len);
- s = curBuf;
+ s = curBuf.release();
s[len] = '\0';
- l = (uint)len;
+ l = len;
return *this;
}
@@ -1070,7 +1118,7 @@ QDataStream &QDataStream::readBytes(char *&s, uint &l)
\sa readBytes(), QIODevice::read(), writeRawData()
*/
-int QDataStream::readRawData(char *s, int len)
+qint64 QDataStream::readRawData(char *s, qint64 len)
{
CHECK_STREAM_PRECOND(-1)
return readBlock(s, len);
@@ -1208,18 +1256,13 @@ QDataStream &QDataStream::operator<<(qint64 i)
*/
/*!
+ \fn QDataStream &QDataStream::operator<<(bool i)
+ \overload
+
Writes a boolean value, \a i, to the stream. Returns a reference
to the stream.
*/
-QDataStream &QDataStream::operator<<(bool i)
-{
- CHECK_STREAM_WRITE_PRECOND(*this)
- if (!dev->putChar(qint8(i)))
- q_status = WriteFailed;
- return *this;
-}
-
/*!
\overload
@@ -1306,13 +1349,9 @@ QDataStream &QDataStream::operator<<(double f)
QDataStream &QDataStream::operator<<(const char *s)
{
- if (!s) {
- *this << (quint32)0;
- return *this;
- }
- int len = int(qstrlen(s)) + 1; // also write null terminator
- *this << (quint32)len; // write length specifier
- writeRawData(s, len);
+ // Include null terminator, unless s itself is null
+ const qint64 len = s ? qint64(qstrlen(s)) + 1 : 0;
+ writeBytes(s, len);
return *this;
}
@@ -1344,22 +1383,26 @@ QDataStream &QDataStream::operator<<(char32_t c)
Writes the length specifier \a len and the buffer \a s to the
stream and returns a reference to the stream.
- The \a len is serialized as a quint32, followed by \a len bytes
- from \a s. Note that the data is \e not encoded.
+ The \a len is serialized as a quint32 and an optional quint64,
+ followed by \a len bytes from \a s. Note that the data is
+ \e not encoded.
\sa writeRawData(), readBytes()
*/
-QDataStream &QDataStream::writeBytes(const char *s, uint len)
+QDataStream &QDataStream::writeBytes(const char *s, qint64 len)
{
+ if (len < 0) {
+ q_status = WriteFailed;
+ return *this;
+ }
CHECK_STREAM_WRITE_PRECOND(*this)
- *this << (quint32)len; // write length specifier
- if (len)
+ // Write length then, if any, content
+ if (writeQSizeType(*this, len) && len > 0)
writeRawData(s, len);
return *this;
}
-
/*!
Writes \a len bytes from \a s to the stream. Returns the
number of bytes actually written, or -1 on error.
@@ -1368,10 +1411,10 @@ QDataStream &QDataStream::writeBytes(const char *s, uint len)
\sa writeBytes(), QIODevice::write(), readRawData()
*/
-int QDataStream::writeRawData(const char *s, int len)
+qint64 QDataStream::writeRawData(const char *s, qint64 len)
{
CHECK_STREAM_WRITE_PRECOND(-1)
- int ret = dev->write(s, len);
+ qint64 ret = dev->write(s, len);
if (ret != len)
q_status = WriteFailed;
return ret;
@@ -1388,13 +1431,13 @@ int QDataStream::writeRawData(const char *s, int len)
\sa QIODevice::seek()
*/
-int QDataStream::skipRawData(int len)
+qint64 QDataStream::skipRawData(qint64 len)
{
CHECK_STREAM_PRECOND(-1)
if (q_status != Ok && dev->isTransactionStarted())
return -1;
- const int skipResult = dev->skip(len);
+ const qint64 skipResult = dev->skip(len);
if (skipResult != len)
setStatus(ReadPastEnd);
return skipResult;
diff --git a/src/corelib/serialization/qdatastream.h b/src/corelib/serialization/qdatastream.h
index 0942c3ed1d..cf37df71d7 100644
--- a/src/corelib/serialization/qdatastream.h
+++ b/src/corelib/serialization/qdatastream.h
@@ -9,6 +9,8 @@
#include <QtCore/qcontainerfwd.h>
#include <QtCore/qnamespace.h>
+#include <iterator> // std::distance(), std::next()
+
#ifdef Status
#error qdatastream.h must be included before any header file that defines Status
#endif
@@ -19,17 +21,31 @@ QT_BEGIN_NAMESPACE
class qfloat16;
#endif
class QByteArray;
+class QDataStream;
class QIODevice;
+class QString;
-#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
+#if !defined(QT_NO_DATASTREAM)
class QDataStreamPrivate;
namespace QtPrivate {
class StreamStateSaver;
+template <typename Container>
+QDataStream &readArrayBasedContainer(QDataStream &s, Container &c);
+template <typename Container>
+QDataStream &readListBasedContainer(QDataStream &s, Container &c);
+template <typename Container>
+QDataStream &readAssociativeContainer(QDataStream &s, Container &c);
+template <typename Container>
+QDataStream &writeSequentialContainer(QDataStream &s, const Container &c);
+template <typename Container>
+QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c);
+template <typename Container>
+QDataStream &writeAssociativeMultiContainer(QDataStream &s, const Container &c);
}
class Q_CORE_EXPORT QDataStream : public QIODeviceBase
{
public:
- enum Version {
+ enum Version QT7_ONLY(: quint8) {
Qt_1_0 = 1,
Qt_2_0 = 2,
Qt_2_1 = 3,
@@ -68,9 +84,11 @@ public:
Qt_6_3 = Qt_6_0,
Qt_6_4 = Qt_6_0,
Qt_6_5 = Qt_6_0,
- Qt_6_6 = Qt_6_0,
- Qt_DefaultCompiledVersion = Qt_6_6
-#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
+ Qt_6_6 = 21,
+ Qt_6_7 = 22,
+ Qt_6_8 = Qt_6_7,
+ Qt_DefaultCompiledVersion = Qt_6_8
+#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
#error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion
#endif
};
@@ -80,14 +98,15 @@ public:
LittleEndian = QSysInfo::LittleEndian
};
- enum Status {
+ enum Status QT7_ONLY(: quint8) {
Ok,
ReadPastEnd,
ReadCorruptData,
- WriteFailed
+ WriteFailed,
+ SizeLimitExceeded,
};
- enum FloatingPointPrecision {
+ enum FloatingPointPrecision QT7_ONLY(: quint8) {
SinglePrecision,
DoublePrecision
};
@@ -103,10 +122,12 @@ public:
bool atEnd() const;
+ QT_CORE_INLINE_SINCE(6, 8)
Status status() const;
void setStatus(Status status);
void resetStatus();
+ QT_CORE_INLINE_SINCE(6, 8)
FloatingPointPrecision floatingPointPrecision() const;
void setFloatingPointPrecision(FloatingPointPrecision precision);
@@ -147,7 +168,18 @@ public:
QDataStream &operator<<(qint64 i);
QDataStream &operator<<(quint64 i);
QDataStream &operator<<(std::nullptr_t) { return *this; }
+#if QT_CORE_REMOVED_SINCE(6, 8) || defined(Q_QDOC)
QDataStream &operator<<(bool i);
+#endif
+#if !defined(Q_QDOC)
+ // Disable implicit conversions to bool (e.g. for pointers)
+ template <typename T,
+ std::enable_if_t<std::is_same_v<T, bool>, bool> = true>
+ QDataStream &operator<<(T i)
+ {
+ return (*this << qint8(i));
+ }
+#endif
#if QT_CORE_REMOVED_SINCE(6, 3)
QDataStream &operator<<(qfloat16 f);
#endif
@@ -157,14 +189,21 @@ public:
QDataStream &operator<<(char16_t c);
QDataStream &operator<<(char32_t c);
-
+#if QT_DEPRECATED_SINCE(6, 11)
+ QT_DEPRECATED_VERSION_X_6_11("Use an overload that takes qint64 length.")
QDataStream &readBytes(char *&, uint &len);
- int readRawData(char *, int len);
-
+#endif
+#if QT_CORE_REMOVED_SINCE(6, 7)
QDataStream &writeBytes(const char *, uint len);
- int writeRawData(const char *, int len);
-
int skipRawData(int len);
+ int readRawData(char *, int len);
+ int writeRawData(const char *, int len);
+#endif
+ QDataStream &readBytes(char *&, qint64 &len);
+ qint64 readRawData(char *, qint64 len);
+ QDataStream &writeBytes(const char *, qint64 len);
+ qint64 writeRawData(const char *, qint64 len);
+ qint64 skipRawData(qint64 len);
void startTransaction();
bool commitTransaction();
@@ -177,21 +216,53 @@ private:
QScopedPointer<QDataStreamPrivate> d;
- QIODevice *dev;
- bool owndev;
- bool noswap;
- ByteOrder byteorder;
- int ver;
- Status q_status;
+ QIODevice *dev = nullptr;
+ bool owndev = false;
+ bool noswap = QSysInfo::ByteOrder == QSysInfo::BigEndian;
+ quint8 fpPrecision = QDataStream::DoublePrecision;
+ quint8 q_status = Ok;
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
+ ByteOrder byteorder = BigEndian;
+ int ver = Qt_DefaultCompiledVersion;
+#else
+ Version ver = Qt_DefaultCompiledVersion;
+#endif
+ quint16 transactionDepth = 0;
+#if QT_CORE_REMOVED_SINCE(6, 7)
int readBlock(char *data, int len);
+#endif
+ qint64 readBlock(char *data, qint64 len);
+ static inline qint64 readQSizeType(QDataStream &s);
+ static inline bool writeQSizeType(QDataStream &s, qint64 value);
+ static constexpr quint32 NullCode = 0xffffffffu;
+ static constexpr quint32 ExtendedSize = 0xfffffffeu;
+
friend class QtPrivate::StreamStateSaver;
+ Q_CORE_EXPORT friend QDataStream &operator<<(QDataStream &out, const QString &str);
+ Q_CORE_EXPORT friend QDataStream &operator>>(QDataStream &in, QString &str);
+ Q_CORE_EXPORT friend QDataStream &operator<<(QDataStream &out, const QByteArray &ba);
+ Q_CORE_EXPORT friend QDataStream &operator>>(QDataStream &in, QByteArray &ba);
+ template <typename Container>
+ friend QDataStream &QtPrivate::readArrayBasedContainer(QDataStream &s, Container &c);
+ template <typename Container>
+ friend QDataStream &QtPrivate::readListBasedContainer(QDataStream &s, Container &c);
+ template <typename Container>
+ friend QDataStream &QtPrivate::readAssociativeContainer(QDataStream &s, Container &c);
+ template <typename Container>
+ friend QDataStream &QtPrivate::writeSequentialContainer(QDataStream &s, const Container &c);
+ template <typename Container>
+ friend QDataStream &QtPrivate::writeAssociativeContainer(QDataStream &s, const Container &c);
+ template <typename Container>
+ friend QDataStream &QtPrivate::writeAssociativeMultiContainer(QDataStream &s,
+ const Container &c);
};
namespace QtPrivate {
class StreamStateSaver
{
+ Q_DISABLE_COPY_MOVE(StreamStateSaver)
public:
inline StreamStateSaver(QDataStream *s) : stream(s), oldStatus(s->status())
{
@@ -217,10 +288,14 @@ QDataStream &readArrayBasedContainer(QDataStream &s, Container &c)
StreamStateSaver stateSaver(&s);
c.clear();
- quint32 n;
- s >> n;
+ qint64 size = QDataStream::readQSizeType(s);
+ qsizetype n = size;
+ if (size != n || size < 0) {
+ s.setStatus(QDataStream::SizeLimitExceeded);
+ return s;
+ }
c.reserve(n);
- for (quint32 i = 0; i < n; ++i) {
+ for (qsizetype i = 0; i < n; ++i) {
typename Container::value_type t;
s >> t;
if (s.status() != QDataStream::Ok) {
@@ -239,9 +314,13 @@ QDataStream &readListBasedContainer(QDataStream &s, Container &c)
StreamStateSaver stateSaver(&s);
c.clear();
- quint32 n;
- s >> n;
- for (quint32 i = 0; i < n; ++i) {
+ qint64 size = QDataStream::readQSizeType(s);
+ qsizetype n = size;
+ if (size != n || size < 0) {
+ s.setStatus(QDataStream::SizeLimitExceeded);
+ return s;
+ }
+ for (qsizetype i = 0; i < n; ++i) {
typename Container::value_type t;
s >> t;
if (s.status() != QDataStream::Ok) {
@@ -260,9 +339,13 @@ QDataStream &readAssociativeContainer(QDataStream &s, Container &c)
StreamStateSaver stateSaver(&s);
c.clear();
- quint32 n;
- s >> n;
- for (quint32 i = 0; i < n; ++i) {
+ qint64 size = QDataStream::readQSizeType(s);
+ qsizetype n = size;
+ if (size != n || size < 0) {
+ s.setStatus(QDataStream::SizeLimitExceeded);
+ return s;
+ }
+ for (qsizetype i = 0; i < n; ++i) {
typename Container::key_type k;
typename Container::mapped_type t;
s >> k >> t;
@@ -279,7 +362,8 @@ QDataStream &readAssociativeContainer(QDataStream &s, Container &c)
template <typename Container>
QDataStream &writeSequentialContainer(QDataStream &s, const Container &c)
{
- s << quint32(c.size());
+ if (!QDataStream::writeQSizeType(s, c.size()))
+ return s;
for (const typename Container::value_type &t : c)
s << t;
@@ -289,7 +373,8 @@ QDataStream &writeSequentialContainer(QDataStream &s, const Container &c)
template <typename Container>
QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c)
{
- s << quint32(c.size());
+ if (!QDataStream::writeQSizeType(s, c.size()))
+ return s;
auto it = c.constBegin();
auto end = c.constEnd();
while (it != end) {
@@ -303,7 +388,8 @@ QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c)
template <typename Container>
QDataStream &writeAssociativeMultiContainer(QDataStream &s, const Container &c)
{
- s << quint32(c.size());
+ if (!QDataStream::writeQSizeType(s, c.size()))
+ return s;
auto it = c.constBegin();
auto end = c.constEnd();
while (it != end) {
@@ -343,14 +429,58 @@ using QDataStreamIfHasIStreamOperatorsContainer =
inline QIODevice *QDataStream::device() const
{ return dev; }
+#if QT_CORE_INLINE_IMPL_SINCE(6, 8)
+QDataStream::Status QDataStream::status() const
+{
+ return Status(q_status);
+}
+
+QDataStream::FloatingPointPrecision QDataStream::floatingPointPrecision() const
+{
+ return FloatingPointPrecision(fpPrecision);
+}
+#endif // INLINE_SINCE 6.8
+
inline QDataStream::ByteOrder QDataStream::byteOrder() const
-{ return byteorder; }
+{
+ if constexpr (QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ return noswap ? BigEndian : LittleEndian;
+ return noswap ? LittleEndian : BigEndian;
+}
inline int QDataStream::version() const
{ return ver; }
inline void QDataStream::setVersion(int v)
-{ ver = v; }
+{ ver = Version(v); }
+
+qint64 QDataStream::readQSizeType(QDataStream &s)
+{
+ quint32 first;
+ s >> first;
+ if (first == NullCode)
+ return -1;
+ if (first < ExtendedSize || s.version() < QDataStream::Qt_6_7)
+ return qint64(first);
+ qint64 extendedLen;
+ s >> extendedLen;
+ return extendedLen;
+}
+
+bool QDataStream::writeQSizeType(QDataStream &s, qint64 value)
+{
+ if (value < qint64(ExtendedSize)) {
+ s << quint32(value);
+ } else if (s.version() >= QDataStream::Qt_6_7) {
+ s << ExtendedSize << value;
+ } else if (value == qint64(ExtendedSize)) {
+ s << ExtendedSize;
+ } else {
+ s.setStatus(QDataStream::SizeLimitExceeded); // value is too big for old format
+ return false;
+ }
+ return true;
+}
inline QDataStream &QDataStream::operator>>(char &i)
{ return *this >> reinterpret_cast<qint8&>(i); }
diff --git a/src/corelib/serialization/qdatastream_p.h b/src/corelib/serialization/qdatastream_p.h
index 0e7ebb5750..c4fe7c784c 100644
--- a/src/corelib/serialization/qdatastream_p.h
+++ b/src/corelib/serialization/qdatastream_p.h
@@ -24,11 +24,6 @@ QT_BEGIN_NAMESPACE
class QDataStreamPrivate
{
public:
- QDataStreamPrivate() : floatingPointPrecision(QDataStream::DoublePrecision),
- transactionDepth(0) { }
-
- QDataStream::FloatingPointPrecision floatingPointPrecision;
- int transactionDepth;
};
#endif
diff --git a/src/corelib/serialization/qjsonarray.cpp b/src/corelib/serialization/qjsonarray.cpp
index 96947cf2d0..0c1b0ac7c8 100644
--- a/src/corelib/serialization/qjsonarray.cpp
+++ b/src/corelib/serialization/qjsonarray.cpp
@@ -28,6 +28,10 @@ QT_BEGIN_NAMESPACE
\brief The QJsonArray class encapsulates a JSON array.
+ \compares equality
+ \compareswith equality QJsonValue
+ \endcompareswith
+
A JSON array is a list of values. The list can be manipulated by inserting and
removing QJsonValue's from the array.
@@ -40,7 +44,7 @@ QT_BEGIN_NAMESPACE
You can convert the array to and from text based JSON through QJsonDocument.
- \sa {JSON Support in Qt}, {JSON Save Game Example}
+ \sa {JSON Support in Qt}, {Saving and Loading a Game}
*/
/*!
@@ -211,6 +215,7 @@ QJsonArray QJsonArray::fromStringList(const QStringList &list)
return array;
}
+#ifndef QT_NO_VARIANT
/*!
Converts the variant list \a list to a QJsonArray.
@@ -235,6 +240,7 @@ QVariantList QJsonArray::toVariantList() const
{
return QCborArray::fromJsonArray(*this).toVariantList();
}
+#endif // !QT_NO_VARIANT
/*!
@@ -469,36 +475,40 @@ QJsonValue QJsonArray::operator[](qsizetype i) const
return at(i);
}
-/*!
- Returns \c true if this array is equal to \a other.
- */
-bool QJsonArray::operator==(const QJsonArray &other) const
+bool comparesEqual(const QJsonArray &lhs, const QJsonArray &rhs) noexcept
{
- if (a == other.a)
+ if (lhs.a == rhs.a)
return true;
- if (!a)
- return !other.a->elements.size();
- if (!other.a)
- return !a->elements.size();
- if (a->elements.size() != other.a->elements.size())
+ if (!lhs.a)
+ return !rhs.a->elements.size();
+ if (!rhs.a)
+ return !lhs.a->elements.size();
+ if (lhs.a->elements.size() != rhs.a->elements.size())
return false;
- for (qsizetype i = 0; i < a->elements.size(); ++i) {
- if (a->valueAt(i) != other.a->valueAt(i))
+ for (qsizetype i = 0; i < lhs.a->elements.size(); ++i) {
+ if (lhs.a->valueAt(i) != rhs.a->valueAt(i))
return false;
}
return true;
}
-/*!
- Returns \c true if this array is not equal to \a other.
- */
-bool QJsonArray::operator!=(const QJsonArray &other) const
+bool comparesEqual(const QJsonArray &lhs, const QJsonValue &rhs) noexcept
{
- return !(*this == other);
+ return lhs == rhs.toArray();
}
+/*! \fn bool QJsonArray::operator==(const QJsonArray &lhs, const QJsonArray &rhs)
+
+ Returns \c true if \a lhs array is equal to \a rhs, \c false otherwise.
+*/
+
+/*! \fn bool QJsonArray::operator!=(const QJsonArray &lhs, const QJsonArray &rhs)
+
+ Returns \c true if \a lhs array is not equal to \a rhs, \c false otherwise.
+*/
+
/*! \fn QJsonArray::iterator QJsonArray::begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in
@@ -593,6 +603,10 @@ bool QJsonArray::operator!=(const QJsonArray &other) const
\inmodule QtCore
\brief The QJsonArray::iterator class provides an STL-style non-const iterator for QJsonArray.
+ \compares strong
+ \compareswith strong QJsonArray::const_iterator
+ \endcompareswith
+
QJsonArray::iterator allows you to iterate over a QJsonArray
and to modify the array item associated with the
iterator. If you want to iterate over a const QJsonArray, use
@@ -697,55 +711,55 @@ bool QJsonArray::operator!=(const QJsonArray &other) const
*/
/*!
- \fn bool QJsonArray::iterator::operator==(const iterator &other) const
- \fn bool QJsonArray::iterator::operator==(const const_iterator &other) const
+ \fn bool QJsonArray::iterator::operator==(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonArray::iterator::operator==(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to the same item as this
+ Returns \c true if \a lhs points to the same item as \a rhs
iterator; otherwise returns \c false.
\sa operator!=()
*/
/*!
- \fn bool QJsonArray::iterator::operator!=(const iterator &other) const
- \fn bool QJsonArray::iterator::operator!=(const const_iterator &other) const
+ \fn bool QJsonArray::iterator::operator!=(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonArray::iterator::operator!=(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to a different item than this
+ Returns \c true if \a lhs points to a different item than \a rhs
iterator; otherwise returns \c false.
\sa operator==()
*/
/*!
- \fn bool QJsonArray::iterator::operator<(const iterator& other) const
- \fn bool QJsonArray::iterator::operator<(const const_iterator& other) const
+ \fn bool QJsonArray::iterator::operator<(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonArray::iterator::operator<(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is less than
- the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is less than
+ the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonArray::iterator::operator<=(const iterator& other) const
- \fn bool QJsonArray::iterator::operator<=(const const_iterator& other) const
+ \fn bool QJsonArray::iterator::operator<=(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonArray::iterator::operator<=(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is less than
- or equal to the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is less than
+ or equal to the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonArray::iterator::operator>(const iterator& other) const
- \fn bool QJsonArray::iterator::operator>(const const_iterator& other) const
+ \fn bool QJsonArray::iterator::operator>(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonArray::iterator::operator>(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is greater
- than the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is greater
+ than the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonArray::iterator::operator>=(const iterator& other) const
- \fn bool QJsonArray::iterator::operator>=(const const_iterator& other) const
+ \fn bool QJsonArray::iterator::operator>=(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonArray::iterator::operator>=(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is greater
- than or equal to the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is greater
+ than or equal to the item pointed to by the \a rhs iterator.
*/
/*! \fn QJsonArray::iterator &QJsonArray::iterator::operator++()
@@ -828,6 +842,10 @@ bool QJsonArray::operator!=(const QJsonArray &other) const
\inmodule QtCore
\brief The QJsonArray::const_iterator class provides an STL-style const iterator for QJsonArray.
+ \compares strong
+ \compareswith strong QJsonArray::iterator
+ \endcompareswith
+
QJsonArray::const_iterator allows you to iterate over a
QJsonArray. If you want to modify the QJsonArray as
you iterate over it, use QJsonArray::iterator instead. It is generally a
@@ -920,48 +938,48 @@ bool QJsonArray::operator!=(const QJsonArray &other) const
\sa operator+()
*/
-/*! \fn bool QJsonArray::const_iterator::operator==(const const_iterator &other) const
+/*! \fn bool QJsonArray::const_iterator::operator==(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to the same item as this
+ Returns \c true if \a lhs points to the same item as \a rhs
iterator; otherwise returns \c false.
\sa operator!=()
*/
-/*! \fn bool QJsonArray::const_iterator::operator!=(const const_iterator &other) const
+/*! \fn bool QJsonArray::const_iterator::operator!=(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to a different item than this
+ Returns \c true if \a lhs points to a different item than \a rhs
iterator; otherwise returns \c false.
\sa operator==()
*/
/*!
- \fn bool QJsonArray::const_iterator::operator<(const const_iterator& other) const
+ \fn bool QJsonArray::const_iterator::operator<(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is less than
- the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is less than
+ the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonArray::const_iterator::operator<=(const const_iterator& other) const
+ \fn bool QJsonArray::const_iterator::operator<=(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is less than
- or equal to the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is less than
+ or equal to the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonArray::const_iterator::operator>(const const_iterator& other) const
+ \fn bool QJsonArray::const_iterator::operator>(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is greater
- than the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is greater
+ than the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonArray::const_iterator::operator>=(const const_iterator& other) const
+ \fn bool QJsonArray::const_iterator::operator>=(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is greater
- than or equal to the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is greater
+ than or equal to the item pointed to by the \a rhs iterator.
*/
/*! \fn QJsonArray::const_iterator &QJsonArray::const_iterator::operator++()
@@ -1076,9 +1094,7 @@ QDebug operator<<(QDebug dbg, const QJsonArray &a)
#ifndef QT_NO_DATASTREAM
QDataStream &operator<<(QDataStream &stream, const QJsonArray &array)
{
- QJsonDocument doc{array};
- stream << doc.toJson(QJsonDocument::Compact);
- return stream;
+ return stream << QJsonDocument{array};
}
QDataStream &operator>>(QDataStream &stream, QJsonArray &array)
diff --git a/src/corelib/serialization/qjsonarray.h b/src/corelib/serialization/qjsonarray.h
index af4ac9fd37..26a04e9196 100644
--- a/src/corelib/serialization/qjsonarray.h
+++ b/src/corelib/serialization/qjsonarray.h
@@ -60,9 +60,10 @@ public:
QJsonValueRef operator[](qsizetype i);
QJsonValue operator[](qsizetype i) const;
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QJsonArray &other) const;
bool operator!=(const QJsonArray &other) const;
-
+#endif
void swap(QJsonArray &other) noexcept
{
a.swap(other.a);
@@ -93,24 +94,26 @@ public:
inline QJsonValueRef *operator->() { return &item; }
inline QJsonValueRef operator[](qsizetype j) const { return *(*this + j); }
+#if QT_CORE_REMOVED_SINCE(6, 8)
inline bool operator==(const iterator &o) const
{ return item.d == o.item.d && item.index == o.item.index; }
- inline bool operator!=(const iterator &o) const { return !(*this == o); }
+ inline bool operator!=(const iterator &o) const { return !operator==(o); }
inline bool operator<(const iterator &other) const
{ Q_ASSERT(item.d == other.item.d); return item.index < other.item.index; }
inline bool operator<=(const iterator &other) const
{ Q_ASSERT(item.d == other.item.d); return item.index <= other.item.index; }
- inline bool operator>(const iterator &other) const { return !(*this <= other); }
- inline bool operator>=(const iterator &other) const { return !(*this < other); }
+ inline bool operator>(const iterator &other) const { return !operator<=(other); }
+ inline bool operator>=(const iterator &other) const { return !operator<(other); }
inline bool operator==(const const_iterator &o) const
{ return item.d == o.item.d && item.index == o.item.index; }
- inline bool operator!=(const const_iterator &o) const { return !(*this == o); }
+ inline bool operator!=(const const_iterator &o) const { return !operator==(o); }
inline bool operator<(const const_iterator &other) const
{ Q_ASSERT(item.d == other.item.d); return item.index < other.item.index; }
inline bool operator<=(const const_iterator &other) const
{ Q_ASSERT(item.d == other.item.d); return item.index <= other.item.index; }
- inline bool operator>(const const_iterator &other) const { return !(*this <= other); }
- inline bool operator>=(const const_iterator &other) const { return !(*this < other); }
+ inline bool operator>(const const_iterator &other) const { return !operator<=(other); }
+ inline bool operator>=(const const_iterator &other) const { return !operator<(other); }
+#endif
inline iterator &operator++() { ++item.index; return *this; }
inline iterator operator++(int) { iterator n = *this; ++item.index; return n; }
inline iterator &operator--() { item.index--; return *this; }
@@ -122,6 +125,53 @@ public:
inline qsizetype operator-(iterator j) const { return item.index - j.item.index; }
private:
+ // Helper functions
+ static bool comparesEqual_helper(const iterator &lhs, const iterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.index == rhs.item.index;
+ }
+
+ static bool comparesEqual_helper(const iterator &lhs, const const_iterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.index == rhs.item.index;
+ }
+
+ static Qt::strong_ordering compareThreeWay_helper(const iterator &lhs,
+ const iterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.index, rhs.item.index);
+ }
+
+ static Qt::strong_ordering compareThreeWay_helper(const iterator &lhs,
+ const const_iterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.index, rhs.item.index);
+ }
+
+ // Compare friends
+ friend bool comparesEqual(const iterator &lhs, const iterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const iterator &lhs,
+ const iterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(iterator)
+ friend bool comparesEqual(const iterator &lhs, const const_iterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const iterator &lhs,
+ const const_iterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(iterator, const_iterator)
+
QJsonValueRef item;
friend class QJsonArray;
};
@@ -151,15 +201,17 @@ public:
inline const QJsonValueConstRef *operator->() const { return &item; }
inline QJsonValueConstRef operator[](qsizetype j) const { return *(*this + j); }
+#if QT_CORE_REMOVED_SINCE(6, 8)
inline bool operator==(const const_iterator &o) const
{ return item.d == o.item.d && item.index == o.item.index; }
- inline bool operator!=(const const_iterator &o) const { return !(*this == o); }
+ inline bool operator!=(const const_iterator &o) const { return !operator==(o); }
inline bool operator<(const const_iterator &other) const
{ Q_ASSERT(item.d == other.item.d); return item.index < other.item.index; }
inline bool operator<=(const const_iterator &other) const
{ Q_ASSERT(item.d == other.item.d); return item.index <= other.item.index; }
- inline bool operator>(const const_iterator &other) const { return !(*this <= other); }
- inline bool operator>=(const const_iterator &other) const { return !(*this < other); }
+ inline bool operator>(const const_iterator &other) const { return !operator<=(other); }
+ inline bool operator>=(const const_iterator &other) const { return !operator<(other); }
+#endif
inline const_iterator &operator++() { ++item.index; return *this; }
inline const_iterator operator++(int) { const_iterator n = *this; ++item.index; return n; }
inline const_iterator &operator--() { item.index--; return *this; }
@@ -171,6 +223,30 @@ public:
inline qsizetype operator-(const_iterator j) const { return item.index - j.item.index; }
private:
+ // Helper functions
+ static bool comparesEqual_helper(const const_iterator &lhs,
+ const const_iterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.index == rhs.item.index;
+ }
+ static Qt::strong_ordering compareThreeWay_helper(const const_iterator &lhs,
+ const const_iterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.index, rhs.item.index);
+ }
+
+ // Compare friends
+ friend bool comparesEqual(const const_iterator &lhs, const const_iterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const const_iterator &lhs,
+ const const_iterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(const_iterator)
QJsonValueConstRef item;
friend class QJsonArray;
};
@@ -225,6 +301,14 @@ private:
friend class QCborArray;
friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonArray &);
+ friend Q_CORE_EXPORT bool comparesEqual(const QJsonArray &lhs,
+ const QJsonArray &rhs) noexcept;
+
+ friend Q_CORE_EXPORT bool comparesEqual(const QJsonArray &lhs,
+ const QJsonValue &rhs) noexcept;
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonArray)
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonArray, QJsonValue)
+
QJsonArray(QCborContainerPrivate *array);
bool detach(qsizetype reserve = 0);
diff --git a/src/corelib/serialization/qjsoncbor.cpp b/src/corelib/serialization/qjsoncbor.cpp
index ad0e95061c..da07eca8a7 100644
--- a/src/corelib/serialization/qjsoncbor.cpp
+++ b/src/corelib/serialization/qjsoncbor.cpp
@@ -421,11 +421,13 @@ QJsonArray QCborArray::toJsonArray() const
return convertToJsonArray(d.data());
}
+#ifndef QT_NO_VARIANT
QJsonArray QJsonPrivate::Variant::toJsonArray(const QVariantList &list)
{
const auto cborArray = QCborArray::fromVariantList(list);
return convertToJsonArray(cborArray.d.data(), ConversionMode::FromVariantToJson);
}
+#endif // !QT_NO_VARIANT
/*!
Recursively converts every \l QCborValue value in this map to JSON using
@@ -469,6 +471,7 @@ QJsonObject QCborMap::toJsonObject() const
return convertToJsonObject(d.data());
}
+#ifndef QT_NO_VARIANT
QJsonObject QJsonPrivate::Variant::toJsonObject(const QVariantMap &map)
{
const auto cborMap = QCborMap::fromVariantMap(map);
@@ -578,6 +581,7 @@ QVariant QCborValue::toVariant() const
Q_UNREACHABLE_RETURN(QVariant());
}
+#endif // !QT_NO_VARIANT
/*!
Converts the JSON value contained in \a v into its corresponding CBOR value
@@ -631,6 +635,7 @@ QCborValue QCborValue::fromJsonValue(const QJsonValue &v)
return QCborValue();
}
+#ifndef QT_NO_VARIANT
static void appendVariant(QCborContainerPrivate *d, const QVariant &variant)
{
// Handle strings and byte arrays directly, to avoid creating a temporary
@@ -831,6 +836,7 @@ QCborArray QCborArray::fromVariantList(const QVariantList &list)
appendVariant(a.d.data(), v);
return a;
}
+#endif // !QT_NO_VARIANT
/*!
Converts all JSON items found in the \a array array to CBOR using
@@ -862,6 +868,7 @@ QCborArray QCborArray::fromJsonArray(QJsonArray &&array) noexcept
}
+#ifndef QT_NO_VARIANT
/*!
Converts the CBOR values to QVariant using QCborValue::toVariant() and
"stringifies" all the CBOR keys in this map, returning the QVariantMap that
@@ -958,6 +965,7 @@ QCborMap QCborMap::fromVariantHash(const QVariantHash &hash)
}
return m;
}
+#endif // !QT_NO_VARIANT
/*!
Converts all JSON items found in the \a obj object to CBOR using
diff --git a/src/corelib/serialization/qjsondocument.cpp b/src/corelib/serialization/qjsondocument.cpp
index 1ba4b5952c..e2528f18dc 100644
--- a/src/corelib/serialization/qjsondocument.cpp
+++ b/src/corelib/serialization/qjsondocument.cpp
@@ -30,6 +30,8 @@ QT_BEGIN_NAMESPACE
\brief The QJsonDocument class provides a way to read and write JSON documents.
+ \compares equality
+
QJsonDocument is a class that wraps a complete JSON document and can read
this document from, and write it to, a UTF-8 encoded text-based
representation.
@@ -44,7 +46,7 @@ QT_BEGIN_NAMESPACE
and isObject(). The array or object contained in the document can be retrieved using
array() or object() and then read or manipulated.
- \sa {JSON Support in Qt}, {JSON Save Game Example}
+ \sa {JSON Support in Qt}, {Saving and Loading a Game}
*/
@@ -181,6 +183,7 @@ QJsonDocument &QJsonDocument::operator =(const QJsonDocument &other)
Swaps the document \a other with this. This operation is very fast and never fails.
*/
+#ifndef QT_NO_VARIANT
/*!
Creates a QJsonDocument from the QVariant \a variant.
@@ -231,6 +234,7 @@ QVariant QJsonDocument::toVariant() const
return QJsonArray(container).toVariantList();
return QJsonObject(container).toVariantMap();
}
+#endif // !QT_NO_VARIANT
/*!
\enum QJsonDocument::JsonFormat
@@ -454,20 +458,22 @@ const QJsonValue QJsonDocument::operator[](qsizetype i) const
}
/*!
- Returns \c true if the \a other document is equal to this document.
- */
-bool QJsonDocument::operator==(const QJsonDocument &other) const
+ \fn bool QJsonDocument::operator==(const QJsonDocument &lhs, const QJsonDocument &rhs)
+
+ Returns \c true if the \a lhs document is equal to \a rhs document, \c false otherwise.
+*/
+bool comparesEqual(const QJsonDocument &lhs, const QJsonDocument &rhs) noexcept
{
- if (d && other.d)
- return d->value == other.d->value;
- return !d == !other.d;
+ if (lhs.d && rhs.d)
+ return lhs.d->value == rhs.d->value;
+ return !lhs.d == !rhs.d;
}
/*!
- \fn bool QJsonDocument::operator!=(const QJsonDocument &other) const
+ \fn bool QJsonDocument::operator!=(const QJsonDocument &lhs, const QJsonDocument &rhs)
- returns \c true if \a other is not equal to this document
- */
+ Returns \c true if the \a lhs document is not equal to \a rhs document, \c false otherwise.
+*/
/*!
returns \c true if this document is null.
diff --git a/src/corelib/serialization/qjsondocument.h b/src/corelib/serialization/qjsondocument.h
index 350c6bb76d..3659f7b5cb 100644
--- a/src/corelib/serialization/qjsondocument.h
+++ b/src/corelib/serialization/qjsondocument.h
@@ -4,6 +4,7 @@
#ifndef QJSONDOCUMENT_H
#define QJSONDOCUMENT_H
+#include <QtCore/qcompare.h>
#include <QtCore/qjsonvalue.h>
#include <QtCore/qscopedpointer.h>
@@ -98,16 +99,19 @@ public:
const QJsonValue operator[](QStringView key) const;
const QJsonValue operator[](QLatin1StringView key) const;
const QJsonValue operator[](qsizetype i) const;
-
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QJsonDocument &other) const;
- bool operator!=(const QJsonDocument &other) const { return !(*this == other); }
-
+ bool operator!=(const QJsonDocument &other) const { return !operator==(other); }
+#endif
bool isNull() const;
private:
friend class QJsonValue;
friend class QJsonPrivate::Parser;
friend Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonDocument &);
+ friend Q_CORE_EXPORT bool comparesEqual(const QJsonDocument &lhs,
+ const QJsonDocument &rhs) noexcept;
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonDocument)
QJsonDocument(const QCborValue &data);
diff --git a/src/corelib/serialization/qjsonobject.cpp b/src/corelib/serialization/qjsonobject.cpp
index d4f702e46e..2f61de0824 100644
--- a/src/corelib/serialization/qjsonobject.cpp
+++ b/src/corelib/serialization/qjsonobject.cpp
@@ -31,6 +31,10 @@ QT_BEGIN_NAMESPACE
\brief The QJsonObject class encapsulates a JSON object.
+ \compares equality
+ \compareswith equality QJsonValue QJsonValueConstRef
+ \endcompareswith
+
A JSON object is a list of key value pairs, where the keys are unique strings
and the values are represented by a QJsonValue.
@@ -43,7 +47,7 @@ QT_BEGIN_NAMESPACE
You can convert the object to and from text based JSON through QJsonDocument.
- \sa {JSON Support in Qt}, {JSON Save Game Example}
+ \sa {JSON Support in Qt}, {Saving and Loading a Game}
*/
/*!
@@ -85,7 +89,7 @@ QT_BEGIN_NAMESPACE
QJsonObject::QJsonObject() = default;
/*!
- \fn QJsonObject::QJsonObject(std::initializer_list<QPair<QString, QJsonValue> > args)
+ \fn QJsonObject::QJsonObject(std::initializer_list<std::pair<QString, QJsonValue> > args)
\since 5.4
Constructs a QJsonObject instance initialized from \a args initialization list.
For example:
@@ -111,7 +115,7 @@ QJsonObject::QJsonObject(QCborContainerPrivate *object)
*/
QJsonObject::~QJsonObject() = default;
-QJsonObject::QJsonObject(std::initializer_list<QPair<QString, QJsonValue> > args)
+QJsonObject::QJsonObject(std::initializer_list<std::pair<QString, QJsonValue> > args)
{
for (const auto &arg : args)
insert(arg.first, arg.second);
@@ -156,7 +160,7 @@ QJsonObject &QJsonObject::operator =(const QJsonObject &other) noexcept = defaul
Swaps the object \a other with this. This operation is very fast and never fails.
*/
-
+#ifndef QT_NO_VARIANT
/*!
Converts the variant map \a map to a QJsonObject.
@@ -219,11 +223,12 @@ QVariantHash QJsonObject::toVariantHash() const
{
return QCborMap::fromJsonObject(*this).toVariantHash();
}
+#endif // !QT_NO_VARIANT
/*!
Returns a list of all keys in this object.
- The list is sorted lexographically.
+ The list is sorted alphabetically.
*/
QStringList QJsonObject::keys() const
{
@@ -264,7 +269,7 @@ static qsizetype indexOf(const QExplicitlySharedDataPointer<QCborContainerPrivat
const auto it = std::lower_bound(
begin, end, key,
[&](const QJsonPrivate::ConstKeyIterator::value_type &e, const String &key) {
- return o->stringCompareElement(e.key(), key) < 0;
+ return o->stringCompareElement(e.key(), key, QtCbor::Comparison::ForOrdering) < 0;
});
*keyExists = (it != end) && o->stringEqualsElement((*it).key(), key);
@@ -612,22 +617,24 @@ bool QJsonObject::containsImpl(T key) const
}
/*!
- Returns \c true if \a other is equal to this object.
- */
-bool QJsonObject::operator==(const QJsonObject &other) const
+ \fn bool QJsonObject::operator==(const QJsonObject &lhs, const QJsonObject &rhs)
+
+ Returns \c true if \a lhs object is equal to \a rhs, \c false otherwise.
+*/
+bool comparesEqual(const QJsonObject &lhs, const QJsonObject &rhs) noexcept
{
- if (o == other.o)
+ if (lhs.o == rhs.o)
return true;
- if (!o)
- return !other.o->elements.size();
- if (!other.o)
- return !o->elements.size();
- if (o->elements.size() != other.o->elements.size())
+ if (!lhs.o)
+ return !rhs.o->elements.size();
+ if (!rhs.o)
+ return !lhs.o->elements.size();
+ if (lhs.o->elements.size() != rhs.o->elements.size())
return false;
- for (qsizetype i = 0, end = o->elements.size(); i < end; ++i) {
- if (o->valueAt(i) != other.o->valueAt(i))
+ for (qsizetype i = 0, end = lhs.o->elements.size(); i < end; ++i) {
+ if (lhs.o->valueAt(i) != rhs.o->valueAt(i))
return false;
}
@@ -635,12 +642,10 @@ bool QJsonObject::operator==(const QJsonObject &other) const
}
/*!
- Returns \c true if \a other is not equal to this object.
- */
-bool QJsonObject::operator!=(const QJsonObject &other) const
-{
- return !(*this == other);
-}
+ \fn bool QJsonObject::operator!=(const QJsonObject &lhs, const QJsonObject &rhs)
+
+ Returns \c true if \a lhs object is not equal to \a rhs, \c false otherwise.
+*/
/*!
Removes the (key, value) pair pointed to by the iterator \a it
@@ -835,6 +840,10 @@ QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const
\brief The QJsonObject::iterator class provides an STL-style non-const iterator for QJsonObject.
+ \compares strong
+ \compareswith strong QJsonObject::const_iterator
+ \endcompareswith
+
QJsonObject::iterator allows you to iterate over a QJsonObject
and to modify the value (but not the key) stored under
a particular key. If you want to iterate over a const QJsonObject, you
@@ -851,7 +860,7 @@ QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const
Multiple iterators can be used on the same object. Existing iterators will however
become dangling once the object gets modified.
- \sa QJsonObject::const_iterator, {JSON Support in Qt}, {JSON Save Game Example}
+ \sa QJsonObject::const_iterator, {JSON Support in Qt}, {Saving and Loading a Game}
*/
/*! \typedef QJsonObject::iterator::difference_type
@@ -968,55 +977,55 @@ QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const
*/
/*!
- \fn bool QJsonObject::iterator::operator==(const iterator &other) const
- \fn bool QJsonObject::iterator::operator==(const const_iterator &other) const
+ \fn bool QJsonObject::iterator::operator==(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonObject::iterator::operator==(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to the same item as this
+ Returns \c true if \a lhs points to the same item as \a rhs
iterator; otherwise returns \c false.
\sa operator!=()
*/
/*!
- \fn bool QJsonObject::iterator::operator!=(const iterator &other) const
- \fn bool QJsonObject::iterator::operator!=(const const_iterator &other) const
+ \fn bool QJsonObject::iterator::operator!=(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonObject::iterator::operator!=(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to a different item than this
+ Returns \c true if \a lhs points to a different item than \a rhs
iterator; otherwise returns \c false.
\sa operator==()
*/
/*!
- \fn bool QJsonObject::iterator::operator<(const iterator& other) const
- \fn bool QJsonObject::iterator::operator<(const const_iterator& other) const
+ \fn bool QJsonObject::iterator::operator<(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonObject::iterator::operator<(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is less than
- the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is less than
+ the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonObject::iterator::operator<=(const iterator& other) const
- \fn bool QJsonObject::iterator::operator<=(const const_iterator& other) const
+ \fn bool QJsonObject::iterator::operator<=(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonObject::iterator::operator<=(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is less than
- or equal to the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is less than
+ or equal to the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonObject::iterator::operator>(const iterator& other) const
- \fn bool QJsonObject::iterator::operator>(const const_iterator& other) const
+ \fn bool QJsonObject::iterator::operator>(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonObject::iterator::operator>(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is greater
- than the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is greater
+ than the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonObject::iterator::operator>=(const iterator& other) const
- \fn bool QJsonObject::iterator::operator>=(const const_iterator& other) const
+ \fn bool QJsonObject::iterator::operator>=(const iterator &lhs, const iterator &rhs)
+ \fn bool QJsonObject::iterator::operator>=(const iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is greater
- than or equal to the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is greater
+ than or equal to the item pointed to by the \a rhs iterator.
*/
/*! \fn QJsonObject::iterator QJsonObject::iterator::operator++()
@@ -1105,6 +1114,10 @@ QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const
\since 5.0
\brief The QJsonObject::const_iterator class provides an STL-style const iterator for QJsonObject.
+ \compares strong
+ \compareswith strong QJsonObject::iterator
+ \endcompareswith
+
QJsonObject::const_iterator allows you to iterate over a QJsonObject.
If you want to modify the QJsonObject as you iterate
over it, you must use QJsonObject::iterator instead. It is generally
@@ -1121,7 +1134,7 @@ QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const
Multiple iterators can be used on the same object. Existing iterators
will however become dangling if the object gets modified.
- \sa QJsonObject::iterator, {JSON Support in Qt}, {JSON Save Game Example}
+ \sa QJsonObject::iterator, {JSON Support in Qt}, {Saving and Loading a Game}
*/
/*! \typedef QJsonObject::const_iterator::difference_type
@@ -1213,50 +1226,48 @@ QJsonObject::const_iterator QJsonObject::constFindImpl(T key) const
*/
-/*! \fn bool QJsonObject::const_iterator::operator==(const const_iterator &other) const
- \fn bool QJsonObject::const_iterator::operator==(const iterator &other) const
+/*! \fn bool QJsonObject::const_iterator::operator==(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to the same item as this
+ Returns \c true if \a lhs points to the same item as \a rhs
iterator; otherwise returns \c false.
\sa operator!=()
*/
-/*! \fn bool QJsonObject::const_iterator::operator!=(const const_iterator &other) const
- \fn bool QJsonObject::const_iterator::operator!=(const iterator &other) const
+/*! \fn bool QJsonObject::const_iterator::operator!=(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if \a other points to a different item than this
+ Returns \c true if \a lhs points to a different item than \a rhs
iterator; otherwise returns \c false.
\sa operator==()
*/
/*!
- \fn bool QJsonObject::const_iterator::operator<(const const_iterator& other) const
+ \fn bool QJsonObject::const_iterator::operator<(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is less than
- the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is less than
+ the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonObject::const_iterator::operator<=(const const_iterator& other) const
+ \fn bool QJsonObject::const_iterator::operator<=(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is less than
- or equal to the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is less than
+ or equal to the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonObject::const_iterator::operator>(const const_iterator& other) const
+ \fn bool QJsonObject::const_iterator::operator>(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is greater
- than the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is greater
+ than the item pointed to by the \a rhs iterator.
*/
/*!
- \fn bool QJsonObject::const_iterator::operator>=(const const_iterator& other) const
+ \fn bool QJsonObject::const_iterator::operator>=(const const_iterator &lhs, const const_iterator &rhs)
- Returns \c true if the item pointed to by this iterator is greater
- than or equal to the item pointed to by the \a other iterator.
+ Returns \c true if the item pointed to by \a lhs iterator is greater
+ than or equal to the item pointed to by the \a rhs iterator.
*/
/*! \fn QJsonObject::const_iterator QJsonObject::const_iterator::operator++()
diff --git a/src/corelib/serialization/qjsonobject.h b/src/corelib/serialization/qjsonobject.h
index d7d3fe549b..4cdbf4511d 100644
--- a/src/corelib/serialization/qjsonobject.h
+++ b/src/corelib/serialization/qjsonobject.h
@@ -21,7 +21,7 @@ class Q_CORE_EXPORT QJsonObject
public:
QJsonObject();
- QJsonObject(std::initializer_list<QPair<QString, QJsonValue> > args);
+ QJsonObject(std::initializer_list<std::pair<QString, QJsonValue> > args);
~QJsonObject();
@@ -72,9 +72,10 @@ public:
bool contains(QStringView key) const;
bool contains(QLatin1StringView key) const;
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QJsonObject &other) const;
bool operator!=(const QJsonObject &other) const;
-
+#endif
class const_iterator;
class iterator
@@ -106,17 +107,17 @@ public:
inline const QJsonValueConstRef *operator->() const { return &item; }
inline QJsonValueRef *operator->() { return &item; }
inline QJsonValueRef operator[](qsizetype j) const { return *(*this + j); }
-
+#if QT_CORE_REMOVED_SINCE(6, 8)
inline bool operator==(const iterator &other) const
{ return item.d == other.item.d && item.index == other.item.index; }
- inline bool operator!=(const iterator &other) const { return !(*this == other); }
+ inline bool operator!=(const iterator &other) const { return !operator==(other); }
bool operator<(const iterator& other) const
{ Q_ASSERT(item.d == other.item.d); return item.index < other.item.index; }
bool operator<=(const iterator& other) const
{ Q_ASSERT(item.d == other.item.d); return item.index <= other.item.index; }
- bool operator>(const iterator& other) const { return !(*this <= other); }
- bool operator>=(const iterator& other) const { return !(*this < other); }
-
+ bool operator>(const iterator& other) const { return !operator<=(other); }
+ bool operator>=(const iterator& other) const { return !operator<(other); }
+#endif
inline iterator &operator++() { ++item.index; return *this; }
inline iterator operator++(int) { iterator r = *this; ++item.index; return r; }
inline iterator &operator--() { --item.index; return *this; }
@@ -128,15 +129,63 @@ public:
qsizetype operator-(iterator j) const { return item.index - j.item.index; }
public:
+#if QT_CORE_REMOVED_SINCE(6, 8)
inline bool operator==(const const_iterator &other) const
{ return item.d == other.item.d && item.index == other.item.index; }
- inline bool operator!=(const const_iterator &other) const { return !(*this == other); }
+ inline bool operator!=(const const_iterator &other) const { return !operator==(other); }
bool operator<(const const_iterator& other) const
{ Q_ASSERT(item.d == other.item.d); return item.index < other.item.index; }
bool operator<=(const const_iterator& other) const
{ Q_ASSERT(item.d == other.item.d); return item.index <= other.item.index; }
- bool operator>(const const_iterator& other) const { return !(*this <= other); }
- bool operator>=(const const_iterator& other) const { return !(*this < other); }
+ bool operator>(const const_iterator& other) const { return operator<=(other); }
+ bool operator>=(const const_iterator& other) const { return operator<(other); }
+#endif
+ private:
+ // Helper functions
+ static bool comparesEqual_helper(const iterator &lhs, const iterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.index == rhs.item.index;
+ }
+ static bool comparesEqual_helper(const iterator &lhs, const const_iterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.index == rhs.item.index;
+ }
+
+ static Qt::strong_ordering compareThreeWay_helper(const iterator &lhs,
+ const iterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.index, rhs.item.index);
+ }
+ static Qt::strong_ordering compareThreeWay_helper(const iterator &lhs,
+ const const_iterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.index, rhs.item.index);
+ }
+
+ // Compare friends
+ friend bool comparesEqual(const iterator &lhs, const iterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const iterator &lhs,
+ const iterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(iterator)
+
+ friend bool comparesEqual(const iterator &lhs, const const_iterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const iterator &lhs,
+ const const_iterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(iterator, const_iterator)
};
friend class iterator;
@@ -170,17 +219,17 @@ public:
inline const QJsonValueConstRef operator*() const { return item; }
inline const QJsonValueConstRef *operator->() const { return &item; }
inline QJsonValueConstRef operator[](qsizetype j) const { return *(*this + j); }
-
+#if QT_CORE_REMOVED_SINCE(6, 8)
inline bool operator==(const const_iterator &other) const
{ return item.d == other.item.d && item.index == other.item.index; }
- inline bool operator!=(const const_iterator &other) const { return !(*this == other); }
+ inline bool operator!=(const const_iterator &other) const { return !operator==(other); }
bool operator<(const const_iterator& other) const
{ Q_ASSERT(item.d == other.item.d); return item.index < other.item.index; }
bool operator<=(const const_iterator& other) const
{ Q_ASSERT(item.d == other.item.d); return item.index <= other.item.index; }
- bool operator>(const const_iterator& other) const { return !(*this <= other); }
- bool operator>=(const const_iterator& other) const { return !(*this < other); }
-
+ bool operator>(const const_iterator& other) const { return !operator<=(other); }
+ bool operator>=(const const_iterator& other) const { return !operator<(other); }
+#endif
inline const_iterator &operator++() { ++item.index; return *this; }
inline const_iterator operator++(int) { const_iterator r = *this; ++item.index; return r; }
inline const_iterator &operator--() { --item.index; return *this; }
@@ -190,16 +239,43 @@ public:
inline const_iterator &operator+=(qsizetype j) { item.index += quint64(j); return *this; }
inline const_iterator &operator-=(qsizetype j) { item.index -= quint64(j); return *this; }
qsizetype operator-(const_iterator j) const { return item.index - j.item.index; }
-
+#if QT_CORE_REMOVED_SINCE(6, 8)
inline bool operator==(const iterator &other) const
{ return item.d == other.item.d && item.index == other.item.index; }
- inline bool operator!=(const iterator &other) const { return !(*this == other); }
+ inline bool operator!=(const iterator &other) const { return !operator==(other); }
bool operator<(const iterator& other) const
{ Q_ASSERT(item.d == other.item.d); return item.index < other.item.index; }
bool operator<=(const iterator& other) const
{ Q_ASSERT(item.d == other.item.d); return item.index <= other.item.index; }
- bool operator>(const iterator& other) const { return !(*this <= other); }
- bool operator>=(const iterator& other) const { return !(*this < other); }
+ bool operator>(const iterator& other) const { return !operator<=(other); }
+ bool operator>=(const iterator& other) const { return !operator<(other); }
+#endif
+
+ private:
+ // Helper functions
+ static bool comparesEqual_helper(const const_iterator &lhs,
+ const const_iterator &rhs) noexcept
+ {
+ return lhs.item.d == rhs.item.d && lhs.item.index == rhs.item.index;
+ }
+ static Qt::strong_ordering compareThreeWay_helper(const const_iterator &lhs,
+ const const_iterator &rhs) noexcept
+ {
+ Q_ASSERT(lhs.item.d == rhs.item.d);
+ return Qt::compareThreeWay(lhs.item.index, rhs.item.index);
+ }
+
+ // Compare friends
+ friend bool comparesEqual(const const_iterator &lhs, const const_iterator &rhs) noexcept
+ {
+ return comparesEqual_helper(lhs, rhs);
+ }
+ friend Qt::strong_ordering compareThreeWay(const const_iterator &lhs,
+ const const_iterator &rhs) noexcept
+ {
+ return compareThreeWay_helper(lhs, rhs);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(const_iterator)
};
friend class const_iterator;
@@ -236,6 +312,21 @@ public:
inline bool empty() const { return isEmpty(); }
private:
+ friend Q_CORE_EXPORT bool comparesEqual(const QJsonObject &lhs,
+ const QJsonObject &rhs) noexcept;
+ friend bool comparesEqual(const QJsonObject &lhs,
+ const QJsonValue &rhs) noexcept
+ {
+ return comparesEqual(lhs, rhs.toObject());
+ }
+ friend bool comparesEqual(const QJsonObject &lhs,
+ const QJsonValueConstRef &rhs) noexcept
+ {
+ return comparesEqual(lhs, rhs.toObject());
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonObject)
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonObject, QJsonValue)
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonObject, QJsonValueConstRef)
friend class QJsonValue;
friend class QJsonDocument;
friend class QJsonPrivate::Value;
diff --git a/src/corelib/serialization/qjsonparser.cpp b/src/corelib/serialization/qjsonparser.cpp
index dba603815f..ba4887225d 100644
--- a/src/corelib/serialization/qjsonparser.cpp
+++ b/src/corelib/serialization/qjsonparser.cpp
@@ -15,14 +15,18 @@
//#define PARSER_DEBUG
#ifdef PARSER_DEBUG
+# error currently broken after `current` was moved to StashedContainer
Q_CONSTINIT static int indent = 0;
-#define BEGIN qDebug() << QByteArray(4*indent++, ' ').constData() << "pos=" << current
-#define END --indent
-#define DEBUG qDebug() << QByteArray(4*indent, ' ').constData()
+# define QT_PARSER_TRACING_BEGIN \
+ qDebug() << QByteArray(4 * indent++, ' ').constData() << "pos=" << current
+# define QT_PARSER_TRACING_END --indent
+# define QT_PARSER_TRACING_DEBUG qDebug() << QByteArray(4 * indent, ' ').constData()
#else
-#define BEGIN if (1) ; else qDebug()
-#define END do {} while (0)
-#define DEBUG if (1) ; else qDebug()
+# define QT_PARSER_TRACING_BEGIN QT_NO_QDEBUG_MACRO()
+# define QT_PARSER_TRACING_END \
+ do { \
+ } while (0)
+# define QT_PARSER_TRACING_DEBUG QT_NO_QDEBUG_MACRO()
#endif
static const int nestingLimit = 1024;
@@ -59,7 +63,7 @@ using namespace QtMiscUtils;
\brief The QJsonParseError class is used to report errors during JSON parsing.
- \sa {JSON Support in Qt}, {JSON Save Game Example}
+ \sa {JSON Support in Qt}, {Saving and Loading a Game}
*/
/*!
@@ -301,7 +305,7 @@ QCborValue Parser::parse(QJsonParseError *error)
QCborValue data;
- DEBUG << Qt::hex << (uint)token;
+ QT_PARSER_TRACING_DEBUG << Qt::hex << (uint)token;
if (token == BeginArray) {
container = new QCborContainerPrivate;
if (!parseArray())
@@ -325,7 +329,7 @@ QCborValue Parser::parse(QJsonParseError *error)
goto error;
}
- END;
+ QT_PARSER_TRACING_END;
{
if (error) {
error->offset = 0;
@@ -457,7 +461,7 @@ bool Parser::parseObject()
return false;
}
- BEGIN << "parseObject" << json;
+ QT_PARSER_TRACING_BEGIN << "parseObject" << json;
char token = nextToken();
while (token == Quote) {
@@ -475,13 +479,13 @@ bool Parser::parseObject()
}
}
- DEBUG << "end token=" << token;
+ QT_PARSER_TRACING_DEBUG << "end token=" << token;
if (token != EndObject) {
lastError = QJsonParseError::UnterminatedObject;
return false;
}
- END;
+ QT_PARSER_TRACING_END;
--nestingLevel;
@@ -495,7 +499,7 @@ bool Parser::parseObject()
*/
bool Parser::parseMember()
{
- BEGIN << "parseMember";
+ QT_PARSER_TRACING_BEGIN << "parseMember";
if (!parseString())
return false;
@@ -511,7 +515,7 @@ bool Parser::parseMember()
if (!parseValue())
return false;
- END;
+ QT_PARSER_TRACING_END;
return true;
}
@@ -520,7 +524,7 @@ bool Parser::parseMember()
*/
bool Parser::parseArray()
{
- BEGIN << "parseArray";
+ QT_PARSER_TRACING_BEGIN << "parseArray";
if (++nestingLevel > nestingLimit) {
lastError = QJsonParseError::DeepNesting;
@@ -556,8 +560,8 @@ bool Parser::parseArray()
}
}
- DEBUG << "size =" << (container ? container->elements.size() : 0);
- END;
+ QT_PARSER_TRACING_DEBUG << "size =" << (container ? container->elements.size() : 0);
+ QT_PARSER_TRACING_END;
--nestingLevel;
@@ -571,7 +575,7 @@ value = false / null / true / object / array / number / string
bool Parser::parseValue()
{
- BEGIN << "parse Value" << json;
+ QT_PARSER_TRACING_BEGIN << "parse Value" << json;
switch (*json++) {
case 'n':
@@ -583,8 +587,8 @@ bool Parser::parseValue()
*json++ == 'l' &&
*json++ == 'l') {
container->append(QCborValue(QCborValue::Null));
- DEBUG << "value: null";
- END;
+ QT_PARSER_TRACING_DEBUG << "value: null";
+ QT_PARSER_TRACING_END;
return true;
}
lastError = QJsonParseError::IllegalValue;
@@ -598,8 +602,8 @@ bool Parser::parseValue()
*json++ == 'u' &&
*json++ == 'e') {
container->append(QCborValue(true));
- DEBUG << "value: true";
- END;
+ QT_PARSER_TRACING_DEBUG << "value: true";
+ QT_PARSER_TRACING_END;
return true;
}
lastError = QJsonParseError::IllegalValue;
@@ -614,8 +618,8 @@ bool Parser::parseValue()
*json++ == 's' &&
*json++ == 'e') {
container->append(QCborValue(false));
- DEBUG << "value: false";
- END;
+ QT_PARSER_TRACING_DEBUG << "value: false";
+ QT_PARSER_TRACING_END;
return true;
}
lastError = QJsonParseError::IllegalValue;
@@ -623,24 +627,24 @@ bool Parser::parseValue()
case Quote: {
if (!parseString())
return false;
- DEBUG << "value: string";
- END;
+ QT_PARSER_TRACING_DEBUG << "value: string";
+ QT_PARSER_TRACING_END;
return true;
}
case BeginArray: {
StashedContainer stashedContainer(&container, QCborValue::Array);
if (!parseArray())
return false;
- DEBUG << "value: array";
- END;
+ QT_PARSER_TRACING_DEBUG << "value: array";
+ QT_PARSER_TRACING_END;
return true;
}
case BeginObject: {
StashedContainer stashedContainer(&container, QCborValue::Map);
if (!parseObject())
return false;
- DEBUG << "value: object";
- END;
+ QT_PARSER_TRACING_DEBUG << "value: object";
+ QT_PARSER_TRACING_END;
return true;
}
case ValueSeparator:
@@ -656,8 +660,8 @@ bool Parser::parseValue()
--json;
if (!parseNumber())
return false;
- DEBUG << "value: number";
- END;
+ QT_PARSER_TRACING_DEBUG << "value: number";
+ QT_PARSER_TRACING_END;
}
return true;
@@ -683,7 +687,7 @@ bool Parser::parseValue()
bool Parser::parseNumber()
{
- BEGIN << "parseNumber" << json;
+ QT_PARSER_TRACING_BEGIN << "parseNumber" << json;
const char *start = json;
bool isInt = true;
@@ -725,14 +729,14 @@ bool Parser::parseNumber()
}
const QByteArray number = QByteArray::fromRawData(start, json - start);
- DEBUG << "numberstring" << number;
+ QT_PARSER_TRACING_DEBUG << "numberstring" << number;
if (isInt) {
bool ok;
qlonglong n = number.toLongLong(&ok);
if (ok) {
container->append(QCborValue(n));
- END;
+ QT_PARSER_TRACING_END;
return true;
}
}
@@ -751,7 +755,7 @@ bool Parser::parseNumber()
else
container->append(QCborValue(d));
- END;
+ QT_PARSER_TRACING_END;
return true;
}
@@ -795,7 +799,7 @@ static inline bool scanEscapeSequence(const char *&json, const char *end, char32
if (json >= end)
return false;
- DEBUG << "scan escape" << (char)*json;
+ QT_PARSER_TRACING_DEBUG << "scan escape" << (char)*json;
uchar escaped = *json++;
switch (escaped) {
case '"':
@@ -839,7 +843,7 @@ static inline bool scanUtf8Char(const char *&json, const char *end, char32_t *re
const auto *usrc = reinterpret_cast<const uchar *>(json);
const auto *uend = reinterpret_cast<const uchar *>(end);
const uchar b = *usrc++;
- int res = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(b, result, usrc, uend);
+ qsizetype res = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(b, result, usrc, uend);
if (res < 0)
return false;
@@ -853,7 +857,7 @@ bool Parser::parseString()
// try to parse a utf-8 string without escape sequences, and note whether it's 7bit ASCII.
- BEGIN << "parse string" << json;
+ QT_PARSER_TRACING_BEGIN << "parse string" << json;
bool isUtf8 = true;
bool isAscii = true;
while (json < end) {
@@ -874,10 +878,10 @@ bool Parser::parseString()
}
if (ch > 0x7f)
isAscii = false;
- DEBUG << " " << ch << char(ch);
+ QT_PARSER_TRACING_DEBUG << " " << ch << char(ch);
}
++json;
- DEBUG << "end of string";
+ QT_PARSER_TRACING_DEBUG << "end of string";
if (json >= end) {
lastError = QJsonParseError::UnterminatedString;
return false;
@@ -889,11 +893,11 @@ bool Parser::parseString()
container->appendAsciiString(start, json - start - 1);
else
container->appendUtf8String(start, json - start - 1);
- END;
+ QT_PARSER_TRACING_END;
return true;
}
- DEBUG << "has escape sequences";
+ QT_PARSER_TRACING_DEBUG << "has escape sequences";
json = start;
@@ -924,8 +928,12 @@ bool Parser::parseString()
container->appendByteData(reinterpret_cast<const char *>(ucs4.constData()), ucs4.size() * 2,
QCborValue::String, QtCbor::Element::StringIsUtf16);
- END;
+ QT_PARSER_TRACING_END;
return true;
}
QT_END_NAMESPACE
+
+#undef QT_PARSER_TRACING_BEGIN
+#undef QT_PARSER_TRACING_END
+#undef QT_PARSER_TRACING_DEBUG
diff --git a/src/corelib/serialization/qjsonvalue.cpp b/src/corelib/serialization/qjsonvalue.cpp
index 1cc8e71d9b..6c2656d89f 100644
--- a/src/corelib/serialization/qjsonvalue.cpp
+++ b/src/corelib/serialization/qjsonvalue.cpp
@@ -59,6 +59,10 @@ static QJsonValue::Type convertFromCborType(QCborValue::Type type) noexcept
\brief The QJsonValue class encapsulates a value in JSON.
+ \compares equality
+ \compareswith equality QJsonValueConstRef QJsonValueRef
+ \endcompareswith
+
A value in JSON can be one of 6 basic types:
JSON is a format to store structured data. It has 6 basic data types:
@@ -96,7 +100,7 @@ static QJsonValue::Type convertFromCborType(QCborValue::Type type) noexcept
\li \l {QJsonObject}::operator[](const QString & key) const
\endlist
- \sa {JSON Support in Qt}, {JSON Save Game Example}
+ \sa {JSON Support in Qt}, {Saving and Loading a Game}
*/
/*!
@@ -345,6 +349,7 @@ void QJsonValue::swap(QJsonValue &other) noexcept
error cases as e.g. accessing a non existing key in a QJsonObject.
*/
+#ifndef QT_NO_VARIANT
/*!
Converts \a variant to a QJsonValue and returns it.
@@ -587,6 +592,7 @@ QVariant QJsonValue::toVariant() const
error condition, when trying to read an out of bounds value
in an array or a non existent key in an object.
*/
+#endif // !QT_NO_VARIANT
/*!
Returns the type of the value.
@@ -821,35 +827,37 @@ const QJsonValue QJsonValue::operator[](qsizetype i) const
}
/*!
- Returns \c true if the value is equal to \a other.
- */
-bool QJsonValue::operator==(const QJsonValue &other) const
+ \fn bool QJsonValue::operator==(const QJsonValue &lhs, const QJsonValue &rhs)
+
+ Returns \c true if the \a lhs value is equal to \a rhs value, \c false otherwise.
+*/
+bool comparesEqual(const QJsonValue &lhs, const QJsonValue &rhs) noexcept
{
- if (value.type() != other.value.type()) {
- if (isDouble() && other.isDouble()) {
+ if (lhs.value.type() != rhs.value.type()) {
+ if (lhs.isDouble() && rhs.isDouble()) {
// One value Cbor integer, one Cbor double, should interact as doubles.
- return toDouble() == other.toDouble();
+ return lhs.toDouble() == rhs.toDouble();
}
return false;
}
- switch (value.type()) {
+ switch (lhs.value.type()) {
case QCborValue::Undefined:
case QCborValue::Null:
case QCborValue::True:
case QCborValue::False:
break;
case QCborValue::Double:
- return toDouble() == other.toDouble();
+ return lhs.toDouble() == rhs.toDouble();
case QCborValue::Integer:
- return QJsonPrivate::Value::valueHelper(value)
- == QJsonPrivate::Value::valueHelper(other.value);
+ return QJsonPrivate::Value::valueHelper(lhs.value)
+ == QJsonPrivate::Value::valueHelper(rhs.value);
case QCborValue::String:
- return toString() == other.toString();
+ return lhs.toString() == rhs.toString();
case QCborValue::Array:
- return toArray() == other.toArray();
+ return lhs.toArray() == rhs.toArray();
case QCborValue::Map:
- return toObject() == other.toObject();
+ return lhs.toObject() == rhs.toObject();
default:
return false;
}
@@ -857,12 +865,10 @@ bool QJsonValue::operator==(const QJsonValue &other) const
}
/*!
- Returns \c true if the value is not equal to \a other.
- */
-bool QJsonValue::operator!=(const QJsonValue &other) const
-{
- return !(*this == other);
-}
+ \fn bool QJsonValue::operator!=(const QJsonValue &lhs, const QJsonValue &rhs)
+
+ Returns \c true if the \a lhs value is not equal to \a rhs value, \c false otherwise.
+*/
/*!
\class QJsonValueRef
@@ -936,10 +942,12 @@ QJsonValueRef &QJsonValueRef::operator =(const QJsonValueRef &ref)
return assignToRef(*this, d->valueAt(index), is_object);
}
+#ifndef QT_NO_VARIANT
QVariant QJsonValueConstRef::toVariant() const
{
return concrete(*this).toVariant();
}
+#endif // !QT_NO_VARIANT
QJsonArray QJsonValueConstRef::toArray() const
{
@@ -1011,7 +1019,7 @@ QJsonValue QJsonValueConstRef::concrete(QJsonValueConstRef self) noexcept
QString QJsonValueConstRef::objectKey(QJsonValueConstRef self)
{
Q_ASSERT(self.is_object);
- Q_ASSUME(self.is_object);
+ Q_ASSERT(self.is_object);
const QCborContainerPrivate *d = QJsonPrivate::Value::container(self);
qsizetype index = QJsonPrivate::Value::indexHelper(self);
diff --git a/src/corelib/serialization/qjsonvalue.h b/src/corelib/serialization/qjsonvalue.h
index dddc8a0c30..d71dadf837 100644
--- a/src/corelib/serialization/qjsonvalue.h
+++ b/src/corelib/serialization/qjsonvalue.h
@@ -4,10 +4,11 @@
#ifndef QJSONVALUE_H
#define QJSONVALUE_H
+#include <QtCore/qcborvalue.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qglobal.h>
#include <QtCore/qstring.h>
#include <QtCore/qshareddata.h>
-#include <QtCore/qcborvalue.h>
QT_BEGIN_NAMESPACE
@@ -92,10 +93,16 @@ public:
const QJsonValue operator[](QLatin1StringView key) const;
const QJsonValue operator[](qsizetype i) const;
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool operator==(const QJsonValue &other) const;
bool operator!=(const QJsonValue &other) const;
+#endif
private:
+ friend Q_CORE_EXPORT bool comparesEqual(const QJsonValue &lhs,
+ const QJsonValue &rhs) noexcept;
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonValue)
+
// avoid implicit conversions from char * to bool
QJsonValue(const void *) = delete;
friend class QJsonPrivate::Value;
@@ -148,10 +155,20 @@ public:
const QJsonValue operator[](QLatin1StringView key) const { return concrete(*this)[key]; }
const QJsonValue operator[](qsizetype i) const { return concrete(*this)[i]; }
- inline bool operator==(const QJsonValue &other) const { return concrete(*this) == other; }
- inline bool operator!=(const QJsonValue &other) const { return concrete(*this) != other; }
-
protected:
+ friend bool comparesEqual(const QJsonValueConstRef &lhs,
+ const QJsonValueConstRef &rhs) noexcept
+ {
+ return comparesEqual(concrete(lhs), concrete(rhs));
+ }
+ friend bool comparesEqual(const QJsonValueConstRef &lhs,
+ const QJsonValue &rhs) noexcept
+ {
+ return comparesEqual(concrete(lhs), rhs);
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonValueConstRef)
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonValueConstRef, QJsonValue)
+
Q_CORE_EXPORT static QJsonValue::Type
concreteType(QJsonValueConstRef self) noexcept Q_DECL_PURE_FUNCTION;
Q_CORE_EXPORT static bool
@@ -215,6 +232,8 @@ protected:
friend class QJsonPrivate::Value;
};
+QT_WARNING_PUSH
+QT6_ONLY(QT_WARNING_DISABLE_MSVC(4275)) // non dll-interface class 'QJsonValueConstRef' used as base for dll-interface class 'QJsonValueRef'
class QT6_ONLY(Q_CORE_EXPORT) QJsonValueRef : public QJsonValueConstRef
{
public:
@@ -255,10 +274,25 @@ public:
const QJsonValue operator[](QLatin1StringView key) const { return QJsonValueConstRef::operator[](key); }
const QJsonValue operator[](qsizetype i) const { return QJsonValueConstRef::operator[](i); }
- inline bool operator==(const QJsonValue &other) const { return QJsonValueConstRef::operator==(other); }
- inline bool operator!=(const QJsonValue &other) const { return QJsonValueConstRef::operator!=(other); }
+#if QT_CORE_REMOVED_SINCE(6, 8)
+ inline bool operator==(const QJsonValue &other) const { return comparesEqual(*this, other); }
+ inline bool operator!=(const QJsonValue &other) const { return !comparesEqual(*this, other); }
+#endif
private:
+ friend bool comparesEqual(const QJsonValueRef &lhs,
+ const QJsonValueRef &rhs) noexcept
+ {
+ return comparesEqual(QJsonValue(lhs), QJsonValue(rhs));
+ }
+ friend bool comparesEqual(const QJsonValueRef &lhs,
+ const QJsonValueConstRef &rhs) noexcept
+ {
+ return comparesEqual(QJsonValue(lhs), QJsonValue(rhs));
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonValueRef)
+ Q_DECLARE_EQUALITY_COMPARABLE(QJsonValueRef, QJsonValueConstRef)
+
QJsonValue toValue() const;
#else
using QJsonValueConstRef::operator[];
@@ -273,27 +307,13 @@ private:
friend class QJsonArray;
friend class QJsonObject;
};
+QT_WARNING_POP
inline QJsonValue QCborValueConstRef::toJsonValue() const
{
return concrete().toJsonValue();
}
-inline bool operator==(const QJsonValueConstRef &lhs, const QJsonValueRef &rhs)
-{ return QJsonValue(lhs) == QJsonValue(rhs); }
-inline bool operator!=(const QJsonValueConstRef &lhs, const QJsonValueRef &rhs)
-{ return !(lhs == rhs); }
-
-inline bool operator==(const QJsonValueRef &lhs, const QJsonValueConstRef &rhs)
-{ return QJsonValue(lhs) == QJsonValue(rhs); }
-inline bool operator!=(const QJsonValueRef &lhs, const QJsonValueConstRef &rhs)
-{ return !(lhs == rhs); }
-
-inline bool operator==(const QJsonValueRef &lhs, const QJsonValueRef &rhs)
-{ return QJsonValue(lhs) == QJsonValue(rhs); }
-inline bool operator!=(const QJsonValueRef &lhs, const QJsonValueRef &rhs)
-{ return !(lhs == rhs); }
-
Q_CORE_EXPORT size_t qHash(const QJsonValue &value, size_t seed = 0);
#if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY)
diff --git a/src/corelib/serialization/qjsonwriter.cpp b/src/corelib/serialization/qjsonwriter.cpp
index b0e6ef1d0c..ab34e9228d 100644
--- a/src/corelib/serialization/qjsonwriter.cpp
+++ b/src/corelib/serialization/qjsonwriter.cpp
@@ -22,23 +22,24 @@ static inline uchar hexdig(uint u)
return (u < 0xa ? '0' + u : 'a' + u - 0xa);
}
-static QByteArray escapedString(const QString &s)
+static QByteArray escapedString(QStringView s)
{
// give it a minimum size to ensure the resize() below always adds enough space
QByteArray ba(qMax(s.size(), 16), Qt::Uninitialized);
+ auto ba_const_start = [&]() { return reinterpret_cast<const uchar *>(ba.constData()); };
uchar *cursor = reinterpret_cast<uchar *>(const_cast<char *>(ba.constData()));
const uchar *ba_end = cursor + ba.size();
- const char16_t *src = reinterpret_cast<const char16_t *>(s.constBegin());
- const char16_t *const end = reinterpret_cast<const char16_t *>(s.constEnd());
+ const char16_t *src = s.utf16();
+ const char16_t *const end = s.utf16() + s.size();
while (src != end) {
if (cursor >= ba_end - 6) {
// ensure we have enough space
- int pos = cursor - (const uchar *)ba.constData();
+ qptrdiff pos = cursor - ba_const_start();
ba.resize(ba.size()*2);
- cursor = (uchar *)ba.data() + pos;
- ba_end = (const uchar *)ba.constData() + ba.size();
+ cursor = reinterpret_cast<uchar *>(ba.data()) + pos;
+ ba_end = ba_const_start() + ba.size();
}
char16_t u = *src++;
@@ -88,7 +89,7 @@ static QByteArray escapedString(const QString &s)
}
}
- ba.resize(cursor - (const uchar *)ba.constData());
+ ba.resize(cursor - ba_const_start());
return ba;
}
@@ -107,7 +108,7 @@ static void valueToJson(const QCborValue &v, QByteArray &json, int indent, bool
break;
case QCborValue::Double: {
const double d = v.toDouble();
- if (qIsFinite(d))
+ if (qt_is_finite(d))
json += QByteArray::number(d, 'g', QLocale::FloatingPointShortest);
else
json += "null"; // +INF || -INF || NaN (see RFC4627#section2.4)
diff --git a/src/corelib/serialization/qtextstream.cpp b/src/corelib/serialization/qtextstream.cpp
index c02effb165..e9d650b3e2 100644
--- a/src/corelib/serialization/qtextstream.cpp
+++ b/src/corelib/serialization/qtextstream.cpp
@@ -196,6 +196,7 @@ static const int QTEXTSTREAM_BUFFERSIZE = 16384;
#include "qnumeric.h"
#include "qvarlengtharray.h"
#include <private/qdebug_p.h>
+#include <private/qnumeric_p.h>
#include <private/qtools_p.h>
#include <locale.h>
@@ -359,6 +360,7 @@ bool QTextStreamPrivate::fillReadBuffer(qint64 maxBytes)
if (bytesRead <= 0)
return false;
+#ifndef QT_BOOTSTRAPPED
if (autoDetectUnicode) {
autoDetectUnicode = false;
@@ -373,6 +375,7 @@ bool QTextStreamPrivate::fillReadBuffer(qint64 maxBytes)
#if defined (QTEXTSTREAM_DEBUG)
qDebug("QTextStreamPrivate::fillReadBuffer(), using %s encoding", QStringConverter::nameForEncoding(encoding));
#endif
+#endif
#if defined (QTEXTSTREAM_DEBUG)
qDebug("QTextStreamPrivate::fillReadBuffer(), device->read(\"%s\", %d) == %d",
@@ -999,7 +1002,10 @@ QTextStream::QTextStream(FILE *fileHandle, OpenMode openMode)
fileHandle, int(openMode));
#endif
QFile *file = new QFile;
- file->open(fileHandle, openMode);
+ // Discarding the return value of open; even if it failed
+ // (and the file is not open), QTextStream still reports `Ok`
+ // for closed QIODevices, so there's nothing really to do here.
+ (void)file->open(fileHandle, openMode);
Q_D(QTextStream);
d->device = file;
@@ -1911,13 +1917,13 @@ bool QTextStreamPrivate::getReal(double *f)
// nan/+inf/-inf, so here we also check for uppercase and mixed
// case versions.
if (!qstricmp(buf, "nan") || !qstricmp(buf, "+nan") || !qstricmp(buf, "-nan")) {
- *f = qQNaN();
+ *f = qt_qnan();
return true;
} else if (!qstricmp(buf, "+inf") || !qstricmp(buf, "inf")) {
- *f = qInf();
+ *f = qt_inf();
return true;
} else if (!qstricmp(buf, "-inf")) {
- *f = -qInf();
+ *f = -qt_inf();
return true;
}
bool ok;
@@ -1949,7 +1955,7 @@ QTextStream &QTextStream::operator>>(QChar &c)
\overload
Reads a character from the stream and stores it in \a c. The
- character from the stream is converted to ISO-5589-1 before it is
+ character from the stream is converted to ISO-8859-1 before it is
stored.
\sa QChar::toLatin1()
diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp
index c6d085714f..0fe8c87779 100644
--- a/src/corelib/serialization/qxmlstream.cpp
+++ b/src/corelib/serialization/qxmlstream.cpp
@@ -3,7 +3,7 @@
#include "QtCore/qxmlstream.h"
-#ifndef QT_NO_XMLSTREAM
+#if QT_CONFIG(xmlstream)
#include "qxmlutils_p.h"
#include <qdebug.h>
@@ -22,6 +22,7 @@
#include "qxmlstream_p.h"
#include "qxmlstreamparser_p.h"
#include <private/qstringconverter_p.h>
+#include <private/qstringiterator_p.h>
QT_BEGIN_NAMESPACE
@@ -185,7 +186,7 @@ WRAP(indexOf, QLatin1StringView)
addData() or by waiting for it to arrive on the device().
\value UnexpectedElementError The parser encountered an element
- that was different to those it expected.
+ or token that was different to those it expected.
*/
@@ -232,7 +233,7 @@ QString QXmlStreamEntityResolver::resolveUndeclaredEntity(const QString &/*name*
return QString();
}
-#ifndef QT_NO_XMLSTREAMREADER
+#if QT_CONFIG(xmlstreamreader)
QString QXmlStreamReaderPrivate::resolveUndeclaredEntity(const QString &name)
{
@@ -322,13 +323,34 @@ QXmlStreamEntityResolver *QXmlStreamReader::entityResolver() const
QXmlStreamReader is a well-formed XML 1.0 parser that does \e not
include external parsed entities. As long as no error occurs, the
- application code can thus be assured that the data provided by the
- stream reader satisfies the W3C's criteria for well-formed XML. For
- example, you can be certain that all tags are indeed nested and
- closed properly, that references to internal entities have been
- replaced with the correct replacement text, and that attributes have
- been normalized or added according to the internal subset of the
- DTD.
+ application code can thus be assured, that
+ \list
+ \li the data provided by the stream reader satisfies the W3C's
+ criteria for well-formed XML,
+ \li tokens are provided in a valid order.
+ \endlist
+
+ Unless QXmlStreamReader raises an error, it guarantees the following:
+ \list
+ \li All tags are nested and closed properly.
+ \li References to internal entities have been replaced with the
+ correct replacement text.
+ \li Attributes have been normalized or added according to the
+ internal subset of the \l DTD.
+ \li Tokens of type \l StartDocument happen before all others,
+ aside from comments and processing instructions.
+ \li At most one DOCTYPE element (a token of type \l DTD) is present.
+ \li If present, the DOCTYPE appears before all other elements,
+ aside from StartDocument, comments and processing instructions.
+ \endlist
+
+ In particular, once any token of type \l StartElement, \l EndElement,
+ \l Characters, \l EntityReference or \l EndDocument is seen, no
+ tokens of type StartDocument or DTD will be seen. If one is present in
+ the input stream, out of order, an error is raised.
+
+ \note The token types \l Comment and \l ProcessingInstruction may appear
+ anywhere in the stream.
If an error occurs while parsing, atEnd() and hasError() return
true, and error() returns the error that occurred. The functions
@@ -659,6 +681,7 @@ QXmlStreamReader::TokenType QXmlStreamReader::readNext()
d->token = -1;
return readNext();
}
+ d->checkToken();
return d->type;
}
@@ -699,7 +722,7 @@ QXmlStreamReader::TokenType QXmlStreamReader::tokenType() const
bool QXmlStreamReader::readNextStartElement()
{
while (readNext() != Invalid) {
- if (isEndElement())
+ if (isEndElement() || isEndDocument())
return false;
else if (isStartElement())
return true;
@@ -743,6 +766,11 @@ static constexpr auto QXmlStreamReader_tokenTypeString = qOffsetStringArray(
"ProcessingInstruction"
);
+static constexpr auto QXmlStreamReader_XmlContextString = qOffsetStringArray(
+ "Prolog",
+ "Body"
+);
+
/*!
\property QXmlStreamReader::namespaceProcessing
\brief the namespace-processing flag of the stream reader.
@@ -777,7 +805,16 @@ QString QXmlStreamReader::tokenString() const
return QLatin1StringView(QXmlStreamReader_tokenTypeString.at(d->type));
}
-#endif // QT_NO_XMLSTREAMREADER
+/*!
+ \internal
+ \return \param ctxt (Prolog/Body) as a string.
+ */
+static constexpr QLatin1StringView contextString(QXmlStreamReaderPrivate::XmlContext ctxt)
+{
+ return QLatin1StringView(QXmlStreamReader_XmlContextString.at(static_cast<int>(ctxt)));
+}
+
+#endif // feature xmlstreamreader
QXmlStreamPrivateTagStack::QXmlStreamPrivateTagStack()
{
@@ -791,7 +828,7 @@ QXmlStreamPrivateTagStack::QXmlStreamPrivateTagStack()
tagsDone = false;
}
-#ifndef QT_NO_XMLSTREAMREADER
+#if QT_CONFIG(xmlstreamreader)
QXmlStreamReaderPrivate::QXmlStreamReaderPrivate(QXmlStreamReader *q)
:q_ptr(q)
@@ -827,6 +864,7 @@ void QXmlStreamReaderPrivate::init()
isWhitespace = true;
isCDATA = false;
standalone = false;
+ hasStandalone = false;
tos = 0;
resumeReduction = 0;
state_stack[tos++] = 0;
@@ -863,6 +901,8 @@ void QXmlStreamReaderPrivate::init()
type = QXmlStreamReader::NoToken;
error = QXmlStreamReader::NoError;
+ currentContext = XmlContext::Prolog;
+ foundDTD = false;
}
/*
@@ -1295,7 +1335,8 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanContentCharList()
return n;
}
-inline qsizetype QXmlStreamReaderPrivate::fastScanName(qint16 *prefix)
+// Fast scan an XML attribute name (e.g. "xml:lang").
+inline std::optional<qsizetype> QXmlStreamReaderPrivate::fastScanName(Value *val)
{
qsizetype n = 0;
uint c;
@@ -1303,7 +1344,8 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(qint16 *prefix)
if (n >= 4096) {
// This is too long to be a sensible name, and
// can exhaust memory, or the range of decltype(*prefix)
- return 0;
+ raiseNamePrefixTooLongError();
+ return std::nullopt;
}
switch (c) {
case '\n':
@@ -1332,16 +1374,16 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(qint16 *prefix)
case '+':
case '*':
putChar(c);
- if (prefix && *prefix == n+1) {
- *prefix = 0;
+ if (val && val->prefix == n + 1) {
+ val->prefix = 0;
putChar(':');
--n;
}
return n;
case ':':
- if (prefix) {
- if (*prefix == 0) {
- *prefix = qint16(n + 2);
+ if (val) {
+ if (val->prefix == 0) {
+ val->prefix = qint16(n + 2);
} else { // only one colon allowed according to the namespace spec.
putChar(c);
return n;
@@ -1357,8 +1399,8 @@ inline qsizetype QXmlStreamReaderPrivate::fastScanName(qint16 *prefix)
}
}
- if (prefix)
- *prefix = 0;
+ if (val)
+ val->prefix = 0;
qsizetype pos = textBuffer.size() - n;
putString(textBuffer, pos);
textBuffer.resize(pos);
@@ -1777,7 +1819,6 @@ void QXmlStreamReaderPrivate::startDocument()
* proper order:
*
* [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' */
- bool hasStandalone = false;
for (qsizetype i = 0; err.isNull() && i < n; ++i) {
Attribute &attrib = attributeStack[i];
@@ -1812,7 +1853,7 @@ void QXmlStreamReaderPrivate::startDocument()
else
err = QXmlStream::tr("Standalone accepts only yes or no.");
} else {
- err = QXmlStream::tr("Invalid attribute in XML declaration.");
+ err = QXmlStream::tr("Invalid attribute in XML declaration: %1 = %2").arg(key).arg(value);
}
}
@@ -1841,6 +1882,14 @@ void QXmlStreamReaderPrivate::raiseWellFormedError(const QString &message)
raiseError(QXmlStreamReader::NotWellFormedError, message);
}
+void QXmlStreamReaderPrivate::raiseNamePrefixTooLongError()
+{
+ // TODO: add a ImplementationLimitsExceededError and use it instead
+ raiseError(QXmlStreamReader::NotWellFormedError,
+ QXmlStream::tr("Length of XML attribute name exceeds implementation limits (4KiB "
+ "characters)."));
+}
+
void QXmlStreamReaderPrivate::parseError()
{
@@ -2272,7 +2321,7 @@ QXmlStreamAttributes QXmlStreamReader::attributes() const
return d->attributes;
}
-#endif // QT_NO_XMLSTREAMREADER
+#endif // feature xmlstreamreader
/*!
\class QXmlStreamAttribute
@@ -2283,6 +2332,8 @@ QXmlStreamAttributes QXmlStreamReader::attributes() const
\ingroup xml-tools
+ \compares equality
+
An attribute consists of an optionally empty namespaceUri(), a
name(), a value(), and an isDefault() attribute.
@@ -2357,14 +2408,14 @@ QXmlStreamAttribute::QXmlStreamAttribute(const QString &qualifiedName, const QSt
value following an ATTLIST declaration in the DTD; otherwise
returns \c false.
*/
-/*! \fn bool QXmlStreamAttribute::operator==(const QXmlStreamAttribute &other) const
+/*! \fn bool QXmlStreamAttribute::operator==(const QXmlStreamAttribute &lhs, const QXmlStreamAttribute &rhs)
- Compares this attribute with \a other and returns \c true if they are
+ Compares \a lhs attribute with \a rhs and returns \c true if they are
equal; otherwise returns \c false.
*/
-/*! \fn bool QXmlStreamAttribute::operator!=(const QXmlStreamAttribute &other) const
+/*! \fn bool QXmlStreamAttribute::operator!=(const QXmlStreamAttribute &lhs, const QXmlStreamAttribute &rhs)
- Compares this attribute with \a other and returns \c true if they are
+ Compares \a lhs attribute with \a rhs and returns \c true if they are
not equal; otherwise returns \c false.
*/
@@ -2413,6 +2464,8 @@ QXmlStreamAttribute::QXmlStreamAttribute(const QString &qualifiedName, const QSt
\ingroup xml-tools
+ \compares equality
+
An notation declaration consists of a name(), a systemId(), and a publicId().
*/
@@ -2436,14 +2489,14 @@ Returns the system identifier.
Returns the public identifier.
*/
-/*! \fn inline bool QXmlStreamNotationDeclaration::operator==(const QXmlStreamNotationDeclaration &other) const
+/*! \fn inline bool QXmlStreamNotationDeclaration::operator==(const QXmlStreamNotationDeclaration &lhs, const QXmlStreamNotationDeclaration &rhs)
- Compares this notation declaration with \a other and returns \c true
+ Compares \a lhs notation declaration with \a rhs and returns \c true
if they are equal; otherwise returns \c false.
*/
-/*! \fn inline bool QXmlStreamNotationDeclaration::operator!=(const QXmlStreamNotationDeclaration &other) const
+/*! \fn inline bool QXmlStreamNotationDeclaration::operator!=(const QXmlStreamNotationDeclaration &lhs, const QXmlStreamNotationDeclaration &rhs)
- Compares this notation declaration with \a other and returns \c true
+ Compares \a lhs notation declaration with \a rhs and returns \c true
if they are not equal; otherwise returns \c false.
*/
@@ -2463,16 +2516,18 @@ Returns the public identifier.
\ingroup xml-tools
+ \compares equality
+
An namespace declaration consists of a prefix() and a namespaceUri().
*/
-/*! \fn inline bool QXmlStreamNamespaceDeclaration::operator==(const QXmlStreamNamespaceDeclaration &other) const
+/*! \fn inline bool QXmlStreamNamespaceDeclaration::operator==(const QXmlStreamNamespaceDeclaration &lhs, const QXmlStreamNamespaceDeclaration &rhs)
- Compares this namespace declaration with \a other and returns \c true
+ Compares \a lhs namespace declaration with \a rhs and returns \c true
if they are equal; otherwise returns \c false.
*/
-/*! \fn inline bool QXmlStreamNamespaceDeclaration::operator!=(const QXmlStreamNamespaceDeclaration &other) const
+/*! \fn inline bool QXmlStreamNamespaceDeclaration::operator!=(const QXmlStreamNamespaceDeclaration &lhs, const QXmlStreamNamespaceDeclaration &rhs)
- Compares this namespace declaration with \a other and returns \c true
+ Compares \a lhs namespace declaration with \a rhs and returns \c true
if they are not equal; otherwise returns \c false.
*/
@@ -2529,6 +2584,7 @@ Returns the namespaceUri.
\ingroup xml-tools
+ \compares equality
An entity declaration consists of a name(), a notationName(), a
systemId(), a publicId(), and a value().
*/
@@ -2561,51 +2617,25 @@ Returns the public identifier.
Returns the entity's value.
*/
-/*! \fn bool QXmlStreamEntityDeclaration::operator==(const QXmlStreamEntityDeclaration &other) const
+/*! \fn bool QXmlStreamEntityDeclaration::operator==(const QXmlStreamEntityDeclaration &lhs, const QXmlStreamEntityDeclaration &rhs)
- Compares this entity declaration with \a other and returns \c true if
+ Compares \a lhs entity declaration with \a rhs and returns \c true if
they are equal; otherwise returns \c false.
*/
-/*! \fn bool QXmlStreamEntityDeclaration::operator!=(const QXmlStreamEntityDeclaration &other) const
+/*! \fn bool QXmlStreamEntityDeclaration::operator!=(const QXmlStreamEntityDeclaration &lhs, const QXmlStreamEntityDeclaration &rhs)
- Compares this entity declaration with \a other and returns \c true if
+ Compares \a lhs entity declaration with \a rhs and returns \c true if
they are not equal; otherwise returns \c false.
*/
/*! Returns the value of the attribute \a name in the namespace
described with \a namespaceUri, or an empty string reference if the
attribute is not defined. The \a namespaceUri can be empty.
- */
-QStringView QXmlStreamAttributes::value(const QString &namespaceUri, const QString &name) const
-{
- for (const QXmlStreamAttribute &attribute : *this) {
- if (attribute.name() == name && attribute.namespaceUri() == namespaceUri)
- return attribute.value();
- }
- return QStringView();
-}
-/*!\overload
- Returns the value of the attribute \a name in the namespace
- described with \a namespaceUri, or an empty string reference if the
- attribute is not defined. The \a namespaceUri can be empty.
+ \note In Qt versions prior to 6.6, this function was implemented as an
+ overload set accepting combinations of QString and QLatin1StringView only.
*/
-QStringView QXmlStreamAttributes::value(const QString &namespaceUri, QLatin1StringView name) const
-{
- for (const QXmlStreamAttribute &attribute : *this) {
- if (attribute.name() == name && attribute.namespaceUri() == namespaceUri)
- return attribute.value();
- }
- return QStringView();
-}
-
-/*!\overload
- Returns the value of the attribute \a name in the namespace
- described with \a namespaceUri, or an empty string reference if the
- attribute is not defined. The \a namespaceUri can be empty.
- */
-QStringView QXmlStreamAttributes::value(QLatin1StringView namespaceUri,
- QLatin1StringView name) const
+QStringView QXmlStreamAttributes::value(QAnyStringView namespaceUri, QAnyStringView name) const noexcept
{
for (const QXmlStreamAttribute &attribute : *this) {
if (attribute.name() == name && attribute.namespaceUri() == namespaceUri)
@@ -2625,29 +2655,12 @@ QStringView QXmlStreamAttributes::value(QLatin1StringView namespaceUri,
different prefixes can point to the same namespace), you shouldn't
use qualified names, but a resolved namespaceUri and the attribute's
local name.
- */
-QStringView QXmlStreamAttributes::value(const QString &qualifiedName) const
-{
- for (const QXmlStreamAttribute &attribute : *this) {
- if (attribute.qualifiedName() == qualifiedName)
- return attribute.value();
- }
- return QStringView();
-}
-/*!\overload
+ \note In Qt versions prior to 6.6, this function was implemented as an
+ overload set accepting QString and QLatin1StringView only.
- Returns the value of the attribute with qualified name \a
- qualifiedName , or an empty string reference if the attribute is not
- defined. A qualified name is the raw name of an attribute in the XML
- data. It consists of the namespace prefix, followed by colon,
- followed by the attribute's local name. Since the namespace prefix
- is not unique (the same prefix can point to different namespaces and
- different prefixes can point to the same namespace), you shouldn't
- use qualified names, but a resolved namespaceUri and the attribute's
- local name.
*/
-QStringView QXmlStreamAttributes::value(QLatin1StringView qualifiedName) const
+QStringView QXmlStreamAttributes::value(QAnyStringView qualifiedName) const noexcept
{
for (const QXmlStreamAttribute &attribute : *this) {
if (attribute.qualifiedName() == qualifiedName)
@@ -2674,7 +2687,7 @@ void QXmlStreamAttributes::append(const QString &qualifiedName, const QString &v
append(QXmlStreamAttribute(qualifiedName, value));
}
-#ifndef QT_NO_XMLSTREAMREADER
+#if QT_CONFIG(xmlstreamreader)
/*! \fn bool QXmlStreamReader::isStartDocument() const
Returns \c true if tokenType() equals \l StartDocument; otherwise returns \c false.
@@ -2735,6 +2748,8 @@ bool QXmlStreamReader::isCDATA() const
XML declaration; otherwise returns \c false.
If no XML declaration has been parsed, this function returns \c false.
+
+ \sa hasStandaloneDeclaration()
*/
bool QXmlStreamReader::isStandaloneDocument() const
{
@@ -2742,6 +2757,21 @@ bool QXmlStreamReader::isStandaloneDocument() const
return d->standalone;
}
+/*!
+ \since 6.6
+
+ Returns \c true if this document has an explicit standalone
+ declaration (can be 'yes' or 'no'); otherwise returns \c false;
+
+ If no XML declaration has been parsed, this function returns \c false.
+
+ \sa isStandaloneDocument()
+ */
+bool QXmlStreamReader::hasStandaloneDeclaration() const
+{
+ Q_D(const QXmlStreamReader);
+ return d->hasStandalone;
+}
/*!
\since 4.4
@@ -2773,7 +2803,7 @@ QStringView QXmlStreamReader::documentEncoding() const
return QStringView();
}
-#endif // QT_NO_XMLSTREAMREADER
+#endif // feature xmlstreamreader
/*!
\class QXmlStreamWriter
@@ -2850,12 +2880,18 @@ QStringView QXmlStreamReader::documentEncoding() const
*/
-#ifndef QT_NO_XMLSTREAMWRITER
+#if QT_CONFIG(xmlstreamwriter)
-class QXmlStreamWriterPrivate : public QXmlStreamPrivateTagStack {
+class QXmlStreamWriterPrivate : public QXmlStreamPrivateTagStack
+{
QXmlStreamWriter *q_ptr;
Q_DECLARE_PUBLIC(QXmlStreamWriter)
public:
+ enum class StartElementOption {
+ KeepEverything = 0, // write out every attribute, namespace, &c.
+ OmitNamespaceDeclarations = 1,
+ };
+
QXmlStreamWriterPrivate(QXmlStreamWriter *q);
~QXmlStreamWriterPrivate() {
if (deleteDevice)
@@ -2865,7 +2901,8 @@ public:
void write(QAnyStringView s);
void writeEscaped(QAnyStringView, bool escapeWhitespace = false);
bool finishStartElement(bool contents = true);
- void writeStartElement(QAnyStringView namespaceUri, QAnyStringView name);
+ void writeStartElement(QAnyStringView namespaceUri, QAnyStringView name,
+ StartElementOption option = StartElementOption::KeepEverything);
QIODevice *device;
QString *stringDevice;
uint deleteDevice :1;
@@ -2880,6 +2917,7 @@ public:
NamespaceDeclaration emptyNamespace;
qsizetype lastNamespaceDeclaration;
+ NamespaceDeclaration &addExtraNamespace(QAnyStringView namespaceUri, QAnyStringView prefix);
NamespaceDeclaration &findNamespace(QAnyStringView namespaceUri, bool writeDeclaration = false, bool noDefault = false);
void writeNamespaceDeclaration(const NamespaceDeclaration &namespaceDeclaration);
@@ -2926,54 +2964,83 @@ void QXmlStreamWriterPrivate::write(QAnyStringView s)
void QXmlStreamWriterPrivate::writeEscaped(QAnyStringView s, bool escapeWhitespace)
{
+ struct NextLatin1 {
+ char32_t operator()(const char *&it, const char *) const
+ { return uchar(*it++); }
+ };
+ struct NextUtf8 {
+ char32_t operator()(const char *&it, const char *end) const
+ {
+ uchar uc = *it++;
+ char32_t utf32 = 0;
+ char32_t *output = &utf32;
+ qsizetype n = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(uc, output, it, end);
+ return n < 0 ? 0 : utf32;
+ }
+ };
+ struct NextUtf16 {
+ char32_t operator()(const QChar *&it, const QChar *end) const
+ {
+ QStringIterator decoder(it, end);
+ char32_t result = decoder.next(u'\0');
+ it = decoder.position();
+ return result;
+ }
+ };
+
QString escaped;
escaped.reserve(s.size());
s.visit([&] (auto s) {
using View = decltype(s);
+ using Decoder = std::conditional_t<std::is_same_v<View, QLatin1StringView>, NextLatin1,
+ std::conditional_t<std::is_same_v<View, QUtf8StringView>, NextUtf8, NextUtf16>>;
auto it = s.begin();
const auto end = s.end();
+ Decoder decoder;
while (it != end) {
QLatin1StringView replacement;
auto mark = it;
while (it != end) {
- if (*it == u'<') {
+ auto next_it = it;
+ char32_t uc = decoder(next_it, end);
+ if (uc == u'<') {
replacement = "&lt;"_L1;
break;
- } else if (*it == u'>') {
+ } else if (uc == u'>') {
replacement = "&gt;"_L1;
break;
- } else if (*it == u'&') {
+ } else if (uc == u'&') {
replacement = "&amp;"_L1;
break;
- } else if (*it == u'\"') {
+ } else if (uc == u'\"') {
replacement = "&quot;"_L1;
break;
- } else if (*it == u'\t') {
+ } else if (uc == u'\t') {
if (escapeWhitespace) {
replacement = "&#9;"_L1;
break;
}
- } else if (*it == u'\n') {
+ } else if (uc == u'\n') {
if (escapeWhitespace) {
replacement = "&#10;"_L1;
break;
}
- } else if (*it == u'\v' || *it == u'\f') {
+ } else if (uc == u'\v' || uc == u'\f') {
hasEncodingError = true;
break;
- } else if (*it == u'\r') {
+ } else if (uc == u'\r') {
if (escapeWhitespace) {
replacement = "&#13;"_L1;
break;
}
- } else if (*it <= u'\x1F' || *it >= u'\uFFFE') {
+ } else if (uc <= u'\x1F' || uc == u'\uFFFE' || uc == u'\uFFFF') {
hasEncodingError = true;
break;
}
- ++it;
+ it = next_it;
}
escaped.append(View{mark, it});
@@ -3020,6 +3087,32 @@ bool QXmlStreamWriterPrivate::finishStartElement(bool contents)
return hadSomethingWritten;
}
+QXmlStreamPrivateTagStack::NamespaceDeclaration &
+QXmlStreamWriterPrivate::addExtraNamespace(QAnyStringView namespaceUri, QAnyStringView prefix)
+{
+ const bool prefixIsXml = prefix == "xml"_L1;
+ const bool namespaceUriIsXml = namespaceUri == "http://www.w3.org/XML/1998/namespace"_L1;
+ if (prefixIsXml && !namespaceUriIsXml) {
+ qWarning("Reserved prefix 'xml' must not be bound to a different namespace name "
+ "than 'http://www.w3.org/XML/1998/namespace'");
+ } else if (!prefixIsXml && namespaceUriIsXml) {
+ const QString prefixString = prefix.toString();
+ qWarning("The prefix '%ls' must not be bound to namespace name "
+ "'http://www.w3.org/XML/1998/namespace' which 'xml' is already bound to",
+ qUtf16Printable(prefixString));
+ }
+ if (namespaceUri == "http://www.w3.org/2000/xmlns/"_L1) {
+ const QString prefixString = prefix.toString();
+ qWarning("The prefix '%ls' must not be bound to namespace name "
+ "'http://www.w3.org/2000/xmlns/'",
+ qUtf16Printable(prefixString));
+ }
+ auto &namespaceDeclaration = namespaceDeclarations.push();
+ namespaceDeclaration.prefix = addToStringStorage(prefix);
+ namespaceDeclaration.namespaceUri = addToStringStorage(namespaceUri);
+ return namespaceDeclaration;
+}
+
QXmlStreamPrivateTagStack::NamespaceDeclaration &QXmlStreamWriterPrivate::findNamespace(QAnyStringView namespaceUri, bool writeDeclaration, bool noDefault)
{
for (NamespaceDeclaration &namespaceDeclaration : reversed(namespaceDeclarations)) {
@@ -3598,11 +3691,7 @@ void QXmlStreamWriter::writeNamespace(QAnyStringView namespaceUri, QAnyStringVie
if (prefix.isEmpty()) {
d->findNamespace(namespaceUri, d->inStartElement);
} else {
- Q_ASSERT(!((prefix == "xml"_L1) ^ (namespaceUri == "http://www.w3.org/XML/1998/namespace"_L1)));
- Q_ASSERT(namespaceUri != "http://www.w3.org/2000/xmlns/"_L1);
- QXmlStreamWriterPrivate::NamespaceDeclaration &namespaceDeclaration = d->namespaceDeclarations.push();
- namespaceDeclaration.prefix = d->addToStringStorage(prefix);
- namespaceDeclaration.namespaceUri = d->addToStringStorage(namespaceUri);
+ auto &namespaceDeclaration = d->addExtraNamespace(namespaceUri, prefix);
if (d->inStartElement)
d->writeNamespaceDeclaration(namespaceDeclaration);
}
@@ -3751,7 +3840,8 @@ void QXmlStreamWriter::writeStartElement(QAnyStringView namespaceUri, QAnyString
d->writeStartElement(namespaceUri, name);
}
-void QXmlStreamWriterPrivate::writeStartElement(QAnyStringView namespaceUri, QAnyStringView name)
+void QXmlStreamWriterPrivate::writeStartElement(QAnyStringView namespaceUri, QAnyStringView name,
+ StartElementOption option)
{
if (!finishStartElement(false) && autoFormatting)
indent(tagStack.size());
@@ -3767,12 +3857,14 @@ void QXmlStreamWriterPrivate::writeStartElement(QAnyStringView namespaceUri, QAn
write(tag.name);
inStartElement = lastWasStartElement = true;
- for (qsizetype i = lastNamespaceDeclaration; i < namespaceDeclarations.size(); ++i)
- writeNamespaceDeclaration(namespaceDeclarations[i]);
+ if (option != StartElementOption::OmitNamespaceDeclarations) {
+ for (qsizetype i = lastNamespaceDeclaration; i < namespaceDeclarations.size(); ++i)
+ writeNamespaceDeclaration(namespaceDeclarations[i]);
+ }
tag.namespaceDeclarationsSize = lastNamespaceDeclaration;
}
-#ifndef QT_NO_XMLSTREAMREADER
+#if QT_CONFIG(xmlstreamreader)
/*! Writes the current state of the \a reader. All possible valid
states are supported.
@@ -3782,6 +3874,7 @@ void QXmlStreamWriterPrivate::writeStartElement(QAnyStringView namespaceUri, QAn
*/
void QXmlStreamWriter::writeCurrentToken(const QXmlStreamReader &reader)
{
+ Q_D(QXmlStreamWriter);
switch (reader.tokenType()) {
case QXmlStreamReader::NoToken:
break;
@@ -3792,12 +3885,19 @@ void QXmlStreamWriter::writeCurrentToken(const QXmlStreamReader &reader)
writeEndDocument();
break;
case QXmlStreamReader::StartElement: {
- writeStartElement(reader.namespaceUri(), reader.name());
- const QXmlStreamNamespaceDeclarations decls = reader.namespaceDeclarations();
- for (const auto &namespaceDeclaration : decls) {
- writeNamespace(namespaceDeclaration.namespaceUri(),
- namespaceDeclaration.prefix());
+ // Namespaces must be added before writeStartElement is called so new prefixes are found
+ QList<QXmlStreamPrivateTagStack::NamespaceDeclaration> extraNamespaces;
+ for (const auto &namespaceDeclaration : reader.namespaceDeclarations()) {
+ auto &extraNamespace = d->addExtraNamespace(namespaceDeclaration.namespaceUri(),
+ namespaceDeclaration.prefix());
+ extraNamespaces.append(extraNamespace);
}
+ d->writeStartElement(
+ reader.namespaceUri(), reader.name(),
+ QXmlStreamWriterPrivate::StartElementOption::OmitNamespaceDeclarations);
+ // Namespace declarations are written afterwards
+ for (const auto &extraNamespace : std::as_const(extraNamespaces))
+ d->writeNamespaceDeclaration(extraNamespace);
writeAttributes(reader.attributes());
} break;
case QXmlStreamReader::EndElement:
@@ -3829,9 +3929,99 @@ void QXmlStreamWriter::writeCurrentToken(const QXmlStreamReader &reader)
}
}
+static constexpr bool isTokenAllowedInContext(QXmlStreamReader::TokenType type,
+ QXmlStreamReaderPrivate::XmlContext ctxt)
+{
+ switch (type) {
+ case QXmlStreamReader::StartDocument:
+ case QXmlStreamReader::DTD:
+ return ctxt == QXmlStreamReaderPrivate::XmlContext::Prolog;
+
+ case QXmlStreamReader::StartElement:
+ case QXmlStreamReader::EndElement:
+ case QXmlStreamReader::Characters:
+ case QXmlStreamReader::EntityReference:
+ case QXmlStreamReader::EndDocument:
+ return ctxt == QXmlStreamReaderPrivate::XmlContext::Body;
+
+ case QXmlStreamReader::Comment:
+ case QXmlStreamReader::ProcessingInstruction:
+ return true;
+
+ case QXmlStreamReader::NoToken:
+ case QXmlStreamReader::Invalid:
+ return false;
+ }
+
+ // GCC 8.x does not treat __builtin_unreachable() as constexpr
+#if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
+ Q_UNREACHABLE_RETURN(false);
+#else
+ return false;
+#endif
+}
+
+/*!
+ \internal
+ \brief QXmlStreamReader::isValidToken
+ \return \c true if \param type is a valid token type.
+ \return \c false if \param type is an unexpected token,
+ which indicates a non-well-formed or invalid XML stream.
+ */
+bool QXmlStreamReaderPrivate::isValidToken(QXmlStreamReader::TokenType type)
+{
+ // Don't change currentContext, if Invalid or NoToken occur in the prolog
+ if (type == QXmlStreamReader::Invalid || type == QXmlStreamReader::NoToken)
+ return false;
+
+ // If a token type gets rejected in the body, there is no recovery
+ const bool result = isTokenAllowedInContext(type, currentContext);
+ if (result || currentContext == XmlContext::Body)
+ return result;
+
+ // First non-Prolog token observed => switch context to body and check again.
+ currentContext = XmlContext::Body;
+ return isTokenAllowedInContext(type, currentContext);
+}
+
+/*!
+ \internal
+ Checks token type and raises an error, if it is invalid
+ in the current context (prolog/body).
+ */
+void QXmlStreamReaderPrivate::checkToken()
+{
+ Q_Q(QXmlStreamReader);
+
+ // The token type must be consumed, to keep track if the body has been reached.
+ const XmlContext context = currentContext;
+ const bool ok = isValidToken(type);
+
+ // Do nothing if an error has been raised already (going along with an unexpected token)
+ if (error != QXmlStreamReader::Error::NoError)
+ return;
+
+ if (!ok) {
+ raiseError(QXmlStreamReader::UnexpectedElementError,
+ QXmlStream::tr("Unexpected token type %1 in %2.")
+ .arg(q->tokenString(), contextString(context)));
+ return;
+ }
+
+ if (type != QXmlStreamReader::DTD)
+ return;
+
+ // Raise error on multiple DTD tokens
+ if (foundDTD) {
+ raiseError(QXmlStreamReader::UnexpectedElementError,
+ QXmlStream::tr("Found second DTD token in %1.").arg(contextString(context)));
+ } else {
+ foundDTD = true;
+ }
+}
+
/*!
- \fn bool QXmlStreamAttributes::hasAttribute(const QString &qualifiedName) const
- \since 4.5
+ \fn bool QXmlStreamAttributes::hasAttribute(QAnyStringView qualifiedName) const
Returns \c true if this QXmlStreamAttributes has an attribute whose
qualified name is \a qualifiedName; otherwise returns \c false.
@@ -3845,25 +4035,18 @@ void QXmlStreamWriter::writeCurrentToken(const QXmlStreamReader &reader)
*/
/*!
- \fn bool QXmlStreamAttributes::hasAttribute(QLatin1StringView qualifiedName) const
- \overload
- \since 4.5
-*/
-
-/*!
- \fn bool QXmlStreamAttributes::hasAttribute(const QString &namespaceUri,
- const QString &name) const
+ \fn bool QXmlStreamAttributes::hasAttribute(QAnyStringView namespaceUri,
+ QAnyStringView name) const
\overload
- \since 4.5
Returns \c true if this QXmlStreamAttributes has an attribute whose
namespace URI and name correspond to \a namespaceUri and \a name;
otherwise returns \c false.
*/
-#endif // QT_NO_XMLSTREAMREADER
-#endif // QT_NO_XMLSTREAMWRITER
+#endif // feature xmlstreamreader
+#endif // feature xmlstreamwriter
QT_END_NAMESPACE
-#endif // QT_NO_XMLSTREAM
+#endif // feature xmlstream
diff --git a/src/corelib/serialization/qxmlstream.g b/src/corelib/serialization/qxmlstream.g
index d06c371eb8..860b7fd727 100644
--- a/src/corelib/serialization/qxmlstream.g
+++ b/src/corelib/serialization/qxmlstream.g
@@ -58,7 +58,7 @@
%token PCDATA "PCDATA"
-- error
-%token ERROR
+%token XML_ERROR
-- entities
%token PARSE_ENTITY
@@ -110,7 +110,7 @@
%start document
/.// Copyright (C) 2020 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only$
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
@@ -149,7 +149,7 @@
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_XMLSTREAMREADER
+#if QT_CONFIG(xmlstreamreader)
bool QXmlStreamReaderPrivate::parse()
{
@@ -251,7 +251,7 @@ bool QXmlStreamReaderPrivate::parse()
} else switch (token_char) {
case 0xfffe:
case 0xffff:
- token = ERROR;
+ token = XML_ERROR;
break;
case '\r':
token = SPACE;
@@ -1419,7 +1419,12 @@ space_opt ::= space;
qname ::= LETTER;
/.
case $rule_number: {
- sym(1).len += fastScanName(&sym(1).prefix);
+ Value &val = sym(1);
+ if (auto res = fastScanName(&val))
+ val.len += *res;
+ else
+ return false;
+
if (atEnd) {
resume($rule_number);
return false;
@@ -1430,7 +1435,11 @@ qname ::= LETTER;
name ::= LETTER;
/.
case $rule_number:
- sym(1).len += fastScanName();
+ if (auto res = fastScanName())
+ sym(1).len += *res;
+ else
+ return false;
+
if (atEnd) {
resume($rule_number);
return false;
@@ -1478,7 +1487,7 @@ nmtoken ::= COLON;
return false;
}
-#endif
+#endif // feature xmlstreamreader
QT_END_NAMESPACE
diff --git a/src/corelib/serialization/qxmlstream.h b/src/corelib/serialization/qxmlstream.h
index fffb9b689c..8a12c6d611 100644
--- a/src/corelib/serialization/qxmlstream.h
+++ b/src/corelib/serialization/qxmlstream.h
@@ -6,8 +6,9 @@
#include <QtCore/qiodevice.h>
-#ifndef QT_NO_XMLSTREAM
+#if QT_CONFIG(xmlstream)
+#include <QtCore/qcompare.h>
#include <QtCore/qlist.h>
#include <QtCore/qscopedpointer.h>
#include <QtCore/qstring.h>
@@ -58,13 +59,23 @@ public:
}
inline QStringView value() const { return m_value; }
inline bool isDefault() const { return m_isDefault; }
- inline bool operator==(const QXmlStreamAttribute &other) const {
- return (value() == other.value()
- && (namespaceUri().isNull() ? (qualifiedName() == other.qualifiedName())
- : (namespaceUri() == other.namespaceUri() && name() == other.name())));
- }
+#if QT_CORE_REMOVED_SINCE(6, 8)
+ inline bool operator==(const QXmlStreamAttribute &other) const
+ { return comparesEqual(*this, other); }
inline bool operator!=(const QXmlStreamAttribute &other) const
- { return !operator==(other); }
+ { return !operator==(other); }
+#endif
+
+private:
+ friend bool comparesEqual(const QXmlStreamAttribute &lhs,
+ const QXmlStreamAttribute &rhs) noexcept
+ {
+ return (lhs.value() == rhs.value()
+ && (lhs.namespaceUri().isNull() ? (lhs.qualifiedName() == rhs.qualifiedName())
+ : (lhs.namespaceUri() == rhs.namespaceUri()
+ && lhs.name() == rhs.name())));
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QXmlStreamAttribute)
};
Q_DECLARE_TYPEINFO(QXmlStreamAttribute, Q_RELOCATABLE_TYPE);
@@ -75,25 +86,25 @@ class QXmlStreamAttributes : public QList<QXmlStreamAttribute>
{
public:
inline QXmlStreamAttributes() {}
+#if QT_CORE_REMOVED_SINCE(6, 6)
Q_CORE_EXPORT QStringView value(const QString &namespaceUri, const QString &name) const;
Q_CORE_EXPORT QStringView value(const QString &namespaceUri, QLatin1StringView name) const;
Q_CORE_EXPORT QStringView value(QLatin1StringView namespaceUri, QLatin1StringView name) const;
Q_CORE_EXPORT QStringView value(const QString &qualifiedName) const;
Q_CORE_EXPORT QStringView value(QLatin1StringView qualifiedName) const;
+#endif
+ Q_CORE_EXPORT QStringView value(QAnyStringView namespaceUri, QAnyStringView name) const noexcept;
+ Q_CORE_EXPORT QStringView value(QAnyStringView qualifiedName) const noexcept;
+
Q_CORE_EXPORT void append(const QString &namespaceUri, const QString &name, const QString &value);
Q_CORE_EXPORT void append(const QString &qualifiedName, const QString &value);
- inline bool hasAttribute(const QString &qualifiedName) const
+ bool hasAttribute(QAnyStringView qualifiedName) const
{
return !value(qualifiedName).isNull();
}
- inline bool hasAttribute(QLatin1StringView qualifiedName) const
- {
- return !value(qualifiedName).isNull();
- }
-
- inline bool hasAttribute(const QString &namespaceUri, const QString &name) const
+ bool hasAttribute(QAnyStringView namespaceUri, QAnyStringView name) const
{
return !value(namespaceUri, name).isNull();
}
@@ -111,11 +122,19 @@ public:
inline QStringView prefix() const { return m_prefix; }
inline QStringView namespaceUri() const { return m_namespaceUri; }
- inline bool operator==(const QXmlStreamNamespaceDeclaration &other) const {
- return (prefix() == other.prefix() && namespaceUri() == other.namespaceUri());
- }
+#if QT_CORE_REMOVED_SINCE(6, 8)
+ inline bool operator==(const QXmlStreamNamespaceDeclaration &other) const
+ { return comparesEqual(*this, other); }
inline bool operator!=(const QXmlStreamNamespaceDeclaration &other) const
- { return !operator==(other); }
+ { return !operator==(other); }
+#endif
+private:
+ friend bool comparesEqual(const QXmlStreamNamespaceDeclaration &lhs,
+ const QXmlStreamNamespaceDeclaration &rhs) noexcept
+ {
+ return (lhs.prefix() == rhs.prefix() && lhs.namespaceUri() == rhs.namespaceUri());
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QXmlStreamNamespaceDeclaration)
};
Q_DECLARE_TYPEINFO(QXmlStreamNamespaceDeclaration, Q_RELOCATABLE_TYPE);
@@ -131,12 +150,20 @@ public:
inline QStringView name() const { return m_name; }
inline QStringView systemId() const { return m_systemId; }
inline QStringView publicId() const { return m_publicId; }
- inline bool operator==(const QXmlStreamNotationDeclaration &other) const {
- return (name() == other.name() && systemId() == other.systemId()
- && publicId() == other.publicId());
- }
+#if QT_CORE_REMOVED_SINCE(6, 8)
+ inline bool operator==(const QXmlStreamNotationDeclaration &other) const
+ { return comparesEqual(*this, other); }
inline bool operator!=(const QXmlStreamNotationDeclaration &other) const
- { return !operator==(other); }
+ { return !operator==(other); }
+#endif
+private:
+ friend bool comparesEqual(const QXmlStreamNotationDeclaration &lhs,
+ const QXmlStreamNotationDeclaration &rhs) noexcept
+ {
+ return (lhs.name() == rhs.name() && lhs.systemId() == rhs.systemId()
+ && lhs.publicId() == rhs.publicId());
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QXmlStreamNotationDeclaration)
};
Q_DECLARE_TYPEINFO(QXmlStreamNotationDeclaration, Q_RELOCATABLE_TYPE);
@@ -154,15 +181,24 @@ public:
inline QStringView systemId() const { return m_systemId; }
inline QStringView publicId() const { return m_publicId; }
inline QStringView value() const { return m_value; }
- inline bool operator==(const QXmlStreamEntityDeclaration &other) const {
- return (name() == other.name()
- && notationName() == other.notationName()
- && systemId() == other.systemId()
- && publicId() == other.publicId()
- && value() == other.value());
- }
+#if QT_CORE_REMOVED_SINCE(6, 8)
+ inline bool operator==(const QXmlStreamEntityDeclaration &other) const
+ { return comparesEqual(*this, other); }
inline bool operator!=(const QXmlStreamEntityDeclaration &other) const
- { return !operator==(other); }
+ { return !operator==(other); }
+#endif
+
+private:
+ friend bool comparesEqual(const QXmlStreamEntityDeclaration &lhs,
+ const QXmlStreamEntityDeclaration &rhs) noexcept
+ {
+ return (lhs.name() == rhs.name()
+ && lhs.notationName() == rhs.notationName()
+ && lhs.systemId() == rhs.systemId()
+ && lhs.publicId() == rhs.publicId()
+ && lhs.value() == rhs.value());
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QXmlStreamEntityDeclaration)
};
Q_DECLARE_TYPEINFO(QXmlStreamEntityDeclaration, Q_RELOCATABLE_TYPE);
@@ -170,14 +206,17 @@ typedef QList<QXmlStreamEntityDeclaration> QXmlStreamEntityDeclarations;
class Q_CORE_EXPORT QXmlStreamEntityResolver
{
+ Q_DISABLE_COPY_MOVE(QXmlStreamEntityResolver)
public:
+ QXmlStreamEntityResolver() = default;
virtual ~QXmlStreamEntityResolver();
virtual QString resolveEntity(const QString& publicId, const QString& systemId);
virtual QString resolveUndeclaredEntity(const QString &name);
};
-#ifndef QT_NO_XMLSTREAMREADER
-class Q_CORE_EXPORT QXmlStreamReader {
+#if QT_CONFIG(xmlstreamreader)
+class Q_CORE_EXPORT QXmlStreamReader
+{
QDOC_PROPERTY(bool namespaceProcessing READ namespaceProcessing WRITE setNamespaceProcessing)
public:
enum TokenType {
@@ -246,6 +285,7 @@ public:
inline bool isProcessingInstruction() const { return tokenType() == ProcessingInstruction; }
bool isStandaloneDocument() const;
+ bool hasStandaloneDeclaration() const;
QStringView documentVersion() const;
QStringView documentEncoding() const;
@@ -313,9 +353,9 @@ private:
QScopedPointer<QXmlStreamReaderPrivate> d_ptr;
};
-#endif // QT_NO_XMLSTREAMREADER
+#endif // feature xmlstreamreader
-#ifndef QT_NO_XMLSTREAMWRITER
+#if QT_CONFIG(xmlstreamwriter)
class QXmlStreamWriterPrivate;
@@ -401,7 +441,7 @@ public:
void writeStartElement(QAnyStringView qualifiedName);
void writeStartElement(QAnyStringView namespaceUri, QAnyStringView name);
-#ifndef QT_NO_XMLSTREAMREADER
+#if QT_CONFIG(xmlstreamreader)
void writeCurrentToken(const QXmlStreamReader &reader);
#endif
@@ -412,9 +452,10 @@ private:
Q_DECLARE_PRIVATE(QXmlStreamWriter)
QScopedPointer<QXmlStreamWriterPrivate> d_ptr;
};
-#endif // QT_NO_XMLSTREAMWRITER
+#endif // feature xmlstreamwriter
QT_END_NAMESPACE
-#endif // QT_NO_XMLSTREAM
+#endif // feature xmlstream
+
#endif // QXMLSTREAM_H
diff --git a/src/corelib/serialization/qxmlstream_p.h b/src/corelib/serialization/qxmlstream_p.h
index b1fee62e04..a29ee656e9 100644
--- a/src/corelib/serialization/qxmlstream_p.h
+++ b/src/corelib/serialization/qxmlstream_p.h
@@ -21,6 +21,7 @@
#include <memory>
+#include <optional>
#ifndef QXMLSTREAM_P_H
#define QXMLSTREAM_P_H
@@ -38,7 +39,7 @@ public:
constexpr XmlStringRef() = default;
constexpr inline XmlStringRef(const QString *string, qsizetype pos, qsizetype length)
- : m_string(string), m_pos(pos), m_size(length)
+ : m_string(string), m_pos(pos), m_size((Q_ASSERT(length >= 0), length))
{
}
XmlStringRef(const QString *string)
@@ -296,6 +297,17 @@ public:
QStringDecoder decoder;
bool atEnd;
+ enum class XmlContext
+ {
+ Prolog,
+ Body,
+ };
+
+ XmlContext currentContext = XmlContext::Prolog;
+ bool foundDTD = false;
+ bool isValidToken(QXmlStreamReader::TokenType type);
+ void checkToken();
+
/*!
\sa setType()
*/
@@ -383,6 +395,7 @@ public:
uint hasExternalDtdSubset : 1;
uint lockEncoding : 1;
uint namespaceProcessing : 1;
+ uint hasStandalone : 1; // TODO: expose in public API
int resumeReduction;
void resume(int rule);
@@ -497,7 +510,7 @@ public:
qsizetype fastScanLiteralContent();
qsizetype fastScanSpace();
qsizetype fastScanContentCharList();
- qsizetype fastScanName(qint16 *prefix = nullptr);
+ std::optional<qsizetype> fastScanName(Value *val = nullptr);
inline qsizetype fastScanNMTOKEN();
@@ -506,6 +519,7 @@ public:
void raiseError(QXmlStreamReader::Error error, const QString& message = QString());
void raiseWellFormedError(const QString &message);
+ void raiseNamePrefixTooLongError();
QXmlStreamEntityResolver *entityResolver;
diff --git a/src/corelib/serialization/qxmlstreamgrammar_p.h b/src/corelib/serialization/qxmlstreamgrammar_p.h
index 0ad3232779..80ee8e929f 100644
--- a/src/corelib/serialization/qxmlstreamgrammar_p.h
+++ b/src/corelib/serialization/qxmlstreamgrammar_p.h
@@ -44,7 +44,6 @@ public:
ENTITY = 32,
ENTITY_DONE = 45,
EQ = 14,
- XML_ERROR = 43,
FIXED = 39,
HASH = 6,
ID = 48,
@@ -81,6 +80,7 @@ public:
UNRESOLVED_ENTITY = 46,
VERSION = 55,
XML = 54,
+ XML_ERROR = 43,
ACCEPT_STATE = 416,
RULE_COUNT = 270,
diff --git a/src/corelib/serialization/qxmlstreamparser_p.h b/src/corelib/serialization/qxmlstreamparser_p.h
index 71d5d06081..1363bf4d41 100644
--- a/src/corelib/serialization/qxmlstreamparser_p.h
+++ b/src/corelib/serialization/qxmlstreamparser_p.h
@@ -38,7 +38,7 @@
QT_BEGIN_NAMESPACE
-#ifndef QT_NO_XMLSTREAMREADER
+#if QT_CONFIG(xmlstreamreader)
bool QXmlStreamReaderPrivate::parse()
{
@@ -947,7 +947,12 @@ bool QXmlStreamReaderPrivate::parse()
break;
case 262: {
- sym(1).len += fastScanName(&sym(1).prefix);
+ Value &val = sym(1);
+ if (auto res = fastScanName(&val))
+ val.len += *res;
+ else
+ return false;
+
if (atEnd) {
resume(262);
return false;
@@ -955,7 +960,11 @@ bool QXmlStreamReaderPrivate::parse()
} break;
case 263:
- sym(1).len += fastScanName();
+ if (auto res = fastScanName())
+ sym(1).len += *res;
+ else
+ return false;
+
if (atEnd) {
resume(263);
return false;
@@ -989,7 +998,7 @@ bool QXmlStreamReaderPrivate::parse()
return false;
}
-#endif
+#endif // feature xmlstreamreader
QT_END_NAMESPACE
diff --git a/src/corelib/serialization/qxmlutils.cpp b/src/corelib/serialization/qxmlutils.cpp
index 00a1121280..e6fae7c173 100644
--- a/src/corelib/serialization/qxmlutils.cpp
+++ b/src/corelib/serialization/qxmlutils.cpp
@@ -48,7 +48,7 @@ bool QXmlUtils::rangeContains(RangeIter begin, RangeIter end, const QChar c)
return cp >= begin->min;
while (begin != end) {
- int delta = (end - begin) / 2;
+ qptrdiff delta = (end - begin) / 2;
RangeIter mid = begin + delta;
if (mid->min > cp)
diff --git a/src/corelib/text/UNICODE_LICENSE.txt b/src/corelib/text/UNICODE_LICENSE.txt
deleted file mode 100644
index 8bf2769587..0000000000
--- a/src/corelib/text/UNICODE_LICENSE.txt
+++ /dev/null
@@ -1,46 +0,0 @@
-UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
-
-See Terms of Use for definitions of Unicode Inc.'s
-Data Files and Software.
-
-NOTICE TO USER: Carefully read the following legal agreement.
-BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S
-DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"),
-YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
-TERMS AND CONDITIONS OF THIS AGREEMENT.
-IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE
-THE DATA FILES OR SOFTWARE.
-
-COPYRIGHT AND PERMISSION NOTICE
-
-Copyright © 1991-2022 Unicode, Inc. All rights reserved.
-Distributed under the Terms of Use in https://www.unicode.org/copyright.html.
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of the Unicode data files and any associated documentation
-(the "Data Files") or Unicode software and any associated documentation
-(the "Software") to deal in the Data Files or Software
-without restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, and/or sell copies of
-the Data Files or Software, and to permit persons to whom the Data Files
-or Software are furnished to do so, provided that either
-(a) this copyright and permission notice appear with all copies
-of the Data Files or Software, or
-(b) this copyright and permission notice appear in associated
-Documentation.
-
-THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
-ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT OF THIRD PARTY RIGHTS.
-IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
-NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
-DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
-DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
-TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THE DATA FILES OR SOFTWARE.
-
-Except as contained in this notice, the name of a copyright holder
-shall not be used in advertising or otherwise to promote the sale,
-use or other dealings in these Data Files or Software without prior
-written authorization of the copyright holder.
diff --git a/src/corelib/text/qanystringview.qdoc b/src/corelib/text/qanystringview.cpp
index 09cd002f39..4129257c02 100644
--- a/src/corelib/text/qanystringview.qdoc
+++ b/src/corelib/text/qanystringview.cpp
@@ -1,5 +1,11 @@
// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qanystringview.h"
+#include "qdebug.h"
+#include "qttypetraits.h"
+
+QT_BEGIN_NAMESPACE
/*!
\class QAnyStringView
@@ -11,6 +17,12 @@
\ingroup tools
\ingroup string-processing
+ \compares strong
+ \compareswith strong char16_t QChar {const char16_t *} {const char *} \
+ QByteArray QByteArrayView QString QStringView QUtf8StringView \
+ QLatin1StringView
+ \endcompareswith
+
A QAnyStringView references a contiguous portion of a string it does
not own. It acts as an interface type to all kinds of strings,
without the need to construct a QString first.
@@ -123,7 +135,7 @@
*/
/*!
- \fn template <typename Char> QAnyStringView::QAnyStringView(const Char *str, qsizetype len)
+ \fn template <typename Char, QAnyStringView::if_compatible_char<Char> = true> QAnyStringView::QAnyStringView(const Char *str, qsizetype len)
Constructs a string view on \a str with length \a len.
@@ -140,7 +152,7 @@
*/
/*!
- \fn template <typename Char> QAnyStringView::QAnyStringView(const Char *first, const Char *last)
+ \fn template <typename Char, QAnyStringView::if_compatible_char<Char> = true> QAnyStringView::QAnyStringView(const Char *first, const Char *last)
Constructs a string view on \a first with length (\a last - \a first).
@@ -215,6 +227,23 @@
*/
/*!
+ \fn template <typename Container, QAnyStringView::if_compatible_container<Container>> QAnyStringView::QAnyStringView(const Container &str)
+
+ Constructs a string view on \a str. The length is taken from \c{std::size(str)}.
+
+ \c{std::data(str)} must remain valid for the lifetime of this string view object.
+
+ This constructor only participates in overload resolution if \c Container is a
+ container with a compatible character type as \c{value_type}.
+
+ The string view will be empty if and only if \c{std::size(str) == 0}. It is unspecified
+ whether this constructor can result in a null string view (\c{std::data(str)} would
+ have to return \nullptr for this).
+
+ \sa isNull(), isEmpty()
+*/
+
+/*!
\fn template <typename Char, size_t Size> static QAnyStringView fromArray(const Char (&string)[Size]) noexcept
Constructs a string view on the full character string literal \a string,
@@ -417,8 +446,10 @@
Returns a string view containing \a n code points of this string view,
starting at position \a pos.
+//! [UB-sliced-index-length]
\note The behavior is undefined when \a pos < 0, \a n < 0,
or \a pos + \a n > size().
+//! [UB-sliced-index-length]
\sa first(), last(), chopped(), chop(), truncate(), {Sizes and Sub-Strings}
*/
@@ -430,7 +461,9 @@
Returns a string view starting at position \a pos in this object,
and extending to its end.
+//! [UB-sliced-index-only]
\note The behavior is undefined when \a pos < 0 or \a pos > size().
+//! [UB-sliced-index-only]
\sa first(), last(), chopped(), chop(), truncate(), {Sizes and Sub-Strings}
*/
@@ -544,7 +577,9 @@
/*!
\fn QAnyStringView::compare(QAnyStringView lhs, QAnyStringView rhs, Qt::CaseSensitivity cs)
- Returns an integer that compares to zero as \a lhs compares to \a rhs.
+ Compares the string view \a lhs with the string view \a rhs and returns a
+ negative integer if \a lhs is less than \a rhs, a positive integer if it is
+ greater than \a rhs, and zero if they are equal.
If \a cs is Qt::CaseSensitive (the default), the comparison is case sensitive;
otherwise the comparison is case-insensitive.
@@ -553,12 +588,12 @@
*/
/*!
- \fn bool QAnyStringView::operator==(QAnyStringView lhs, QAnyStringView rhs)
- \fn bool QAnyStringView::operator!=(QAnyStringView lhs, QAnyStringView rhs)
- \fn bool QAnyStringView::operator<=(QAnyStringView lhs, QAnyStringView rhs)
- \fn bool QAnyStringView::operator>=(QAnyStringView lhs, QAnyStringView rhs)
- \fn bool QAnyStringView::operator<(QAnyStringView lhs, QAnyStringView rhs)
- \fn bool QAnyStringView::operator>(QAnyStringView lhs, QAnyStringView rhs)
+ \fn bool QAnyStringView::operator==(const QAnyStringView &lhs, const QAnyStringView & rhs)
+ \fn bool QAnyStringView::operator!=(const QAnyStringView & lhs, const QAnyStringView & rhs)
+ \fn bool QAnyStringView::operator<=(const QAnyStringView & lhs, const QAnyStringView & rhs)
+ \fn bool QAnyStringView::operator>=(const QAnyStringView & lhs, const QAnyStringView & rhs)
+ \fn bool QAnyStringView::operator<(const QAnyStringView & lhs, const QAnyStringView & rhs)
+ \fn bool QAnyStringView::operator>(const QAnyStringView & lhs, const QAnyStringView & rhs)
Operators that compare \a lhs to \a rhs.
@@ -580,3 +615,46 @@
\sa QString::isNull(), QAnyStringView
*/
+/*!
+ \fn QAnyStringView::operator<<(QDebug d, QAnyStringView s)
+ \since 6.7
+ \relates QDebug
+
+ Outputs \a s to debug stream \a d.
+
+ If \c{d.quotedString()} is \c true, indicates which encoding the string is
+ in. If you just want the string data, use visit() like this:
+
+ \code
+ s.visit([&d) (auto s) { d << s; });
+ \endcode
+
+ \sa QAnyStringView::visit()
+*/
+QDebug operator<<(QDebug d, QAnyStringView s)
+{
+ struct S { const char *prefix, *suffix; };
+ const auto affixes = s.visit([](auto s) {
+ using View = decltype(s);
+ if constexpr (std::is_same_v<View, QLatin1StringView>) {
+ return S{"", "_L1"};
+ } else if constexpr (std::is_same_v<View, QUtf8StringView>) {
+ return S{"u8", ""};
+ } else if constexpr (std::is_same_v<View, QStringView>) {
+ return S{"u", ""};
+ } else {
+ static_assert(QtPrivate::type_dependent_false<View>());
+ }
+ });
+ const QDebugStateSaver saver(d);
+ d.nospace();
+ if (d.quoteStrings())
+ d << affixes.prefix;
+ s.visit([&d](auto s) { d << s; });
+ if (d.quoteStrings())
+ d << affixes.suffix;
+ return d;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/corelib/text/qanystringview.h b/src/corelib/text/qanystringview.h
index 4be8910cf6..01efd83743 100644
--- a/src/corelib/text/qanystringview.h
+++ b/src/corelib/text/qanystringview.h
@@ -4,6 +4,7 @@
#ifndef QANYSTRINGVIEW_H
#define QANYSTRINGVIEW_H
+#include <QtCore/qcompare.h>
#include <QtCore/qlatin1stringview.h>
#include <QtCore/qstringview.h>
#include <QtCore/qutf8stringview.h>
@@ -101,18 +102,8 @@ private:
static constexpr bool isAsciiOnlyCharsAtCompileTime(Char *str, qsizetype sz) noexcept
{
// do not perform check if not at compile time
-#if !(defined(__cpp_lib_is_constant_evaluated) || defined(Q_CC_GNU))
- Q_UNUSED(str);
- Q_UNUSED(sz);
- return false;
-#else
-# if defined(__cpp_lib_is_constant_evaluated)
- if (!std::is_constant_evaluated())
- return false;
-# elif defined(Q_CC_GNU) && !defined(Q_CC_CLANG)
- if (!str || !__builtin_constant_p(*str))
+ if (!q20::is_constant_evaluated())
return false;
-# endif
if constexpr (sizeof(Char) != sizeof(char)) {
Q_UNUSED(str);
Q_UNUSED(sz);
@@ -124,7 +115,6 @@ private:
}
return true;
}
-#endif
}
template<typename Char>
@@ -140,36 +130,16 @@ private:
}
template <typename Char>
- static qsizetype lengthHelperPointer(const Char *str) noexcept
+ static constexpr qsizetype lengthHelperPointer(const Char *str) noexcept
{
-#if defined(Q_CC_GNU) && !defined(Q_CC_CLANG)
- if (__builtin_constant_p(*str)) {
- qsizetype result = 0;
- while (*str++ != u'\0')
- ++result;
- return result;
- }
-#endif
+ if (q20::is_constant_evaluated())
+ return qsizetype(std::char_traits<Char>::length(str));
if constexpr (sizeof(Char) == sizeof(char16_t))
return QtPrivate::qustrlen(reinterpret_cast<const char16_t*>(str));
else
return qsizetype(strlen(reinterpret_cast<const char*>(str)));
}
- template <typename Container>
- static constexpr qsizetype lengthHelperContainer(const Container &c) noexcept
- {
- return qsizetype(std::size(c));
- }
-
- template <typename Char, size_t N>
- static constexpr qsizetype lengthHelperContainer(const Char (&str)[N]) noexcept
- {
- const auto it = std::char_traits<Char>::find(str, N, Char(0));
- const auto end = it ? it : std::next(str, N);
- return qsizetype(std::distance(str, end));
- }
-
static QChar toQChar(char ch) noexcept { return toQChar(QLatin1Char{ch}); } // we don't handle UTF-8 multibytes
static QChar toQChar(QChar ch) noexcept { return ch; }
static QChar toQChar(QLatin1Char ch) noexcept { return ch; }
@@ -211,8 +181,8 @@ public:
inline constexpr QAnyStringView(QLatin1StringView str) noexcept;
template <typename Container, if_compatible_container<Container> = true>
- constexpr QAnyStringView(const Container &c) noexcept
- : QAnyStringView(std::data(c), lengthHelperContainer(c)) {}
+ constexpr Q_ALWAYS_INLINE QAnyStringView(const Container &c) noexcept
+ : QAnyStringView(std::data(c), QtPrivate::lengthHelperContainer(c)) {}
template <typename Container, if_convertible_to<QString, Container> = true>
constexpr QAnyStringView(Container &&c, QtPrivate::wrapped_t<Container, QString> &&capacity = {})
@@ -236,11 +206,11 @@ public:
: QAnyStringView(capacity = QChar::fromUcs4(c)) {}
constexpr QAnyStringView(QStringView v) noexcept
- : QAnyStringView(std::data(v), lengthHelperContainer(v)) {}
+ : QAnyStringView(std::data(v), QtPrivate::lengthHelperContainer(v)) {}
template <bool UseChar8T>
constexpr QAnyStringView(QBasicUtf8StringView<UseChar8T> v) noexcept
- : QAnyStringView(std::data(v), lengthHelperContainer(v)) {}
+ : QAnyStringView(std::data(v), QtPrivate::lengthHelperContainer(v)) {}
template <typename Char, size_t Size, if_compatible_char<Char> = true>
[[nodiscard]] constexpr static QAnyStringView fromArray(const Char (&string)[Size]) noexcept
@@ -273,20 +243,20 @@ public:
}
[[nodiscard]] constexpr QAnyStringView sliced(qsizetype pos) const
- { verify(pos); auto r = *this; r.advanceData(pos); r.setSize(size() - pos); return r; }
+ { verify(pos, 0); auto r = *this; r.advanceData(pos); r.setSize(size() - pos); return r; }
[[nodiscard]] constexpr QAnyStringView sliced(qsizetype pos, qsizetype n) const
{ verify(pos, n); auto r = *this; r.advanceData(pos); r.setSize(n); return r; }
[[nodiscard]] constexpr QAnyStringView first(qsizetype n) const
- { verify(n); return sliced(0, n); }
+ { verify(0, n); return sliced(0, n); }
[[nodiscard]] constexpr QAnyStringView last(qsizetype n) const
- { verify(n); return sliced(size() - n, n); }
+ { verify(0, n); return sliced(size() - n, n); }
[[nodiscard]] constexpr QAnyStringView chopped(qsizetype n) const
- { verify(n); return sliced(0, size() - n); }
+ { verify(0, n); return sliced(0, size() - n); }
constexpr void truncate(qsizetype n)
- { verify(n); setSize(n); }
+ { verify(0, n); setSize(n); }
constexpr void chop(qsizetype n)
- { verify(n); setSize(size() - n); }
+ { verify(0, n); setSize(size() - n); }
[[nodiscard]] inline QString toString() const; // defined in qstring.h
@@ -299,12 +269,13 @@ public:
[[nodiscard]] Q_CORE_EXPORT static bool equal(QAnyStringView lhs, QAnyStringView rhs) noexcept;
static constexpr inline bool detects_US_ASCII_at_compile_time =
-#ifdef __cpp_lib_is_constant_evaluated
+#ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED
true
#else
false
#endif
;
+
//
// STL compatibility API:
//
@@ -323,23 +294,18 @@ public:
{ return size(); }
private:
- [[nodiscard]] friend inline bool operator==(QAnyStringView lhs, QAnyStringView rhs) noexcept
+ friend bool comparesEqual(const QAnyStringView &lhs, const QAnyStringView &rhs) noexcept
{ return QAnyStringView::equal(lhs, rhs); }
- [[nodiscard]] friend inline bool operator!=(QAnyStringView lhs, QAnyStringView rhs) noexcept
- { return !QAnyStringView::equal(lhs, rhs); }
+ friend Qt::strong_ordering
+ compareThreeWay(const QAnyStringView &lhs, const QAnyStringView &rhs) noexcept
+ {
+ const int res = QAnyStringView::compare(lhs, rhs);
+ return Qt::compareThreeWay(res, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QAnyStringView)
-#if defined(__cpp_impl_three_way_comparison) && !defined(Q_QDOC)
- [[nodiscard]] friend inline auto operator<=>(QAnyStringView lhs, QAnyStringView rhs) noexcept
- { return QAnyStringView::compare(lhs, rhs) <=> 0; }
-#else
- [[nodiscard]] friend inline bool operator<=(QAnyStringView lhs, QAnyStringView rhs) noexcept
- { return QAnyStringView::compare(lhs, rhs) <= 0; }
- [[nodiscard]] friend inline bool operator>=(QAnyStringView lhs, QAnyStringView rhs) noexcept
- { return QAnyStringView::compare(lhs, rhs) >= 0; }
- [[nodiscard]] friend inline bool operator<(QAnyStringView lhs, QAnyStringView rhs) noexcept
- { return QAnyStringView::compare(lhs, rhs) < 0; }
- [[nodiscard]] friend inline bool operator>(QAnyStringView lhs, QAnyStringView rhs) noexcept
- { return QAnyStringView::compare(lhs, rhs) > 0; }
+#ifndef QT_NO_DEBUG_STREAM
+ Q_CORE_EXPORT friend QDebug operator<<(QDebug d, QAnyStringView s);
#endif
[[nodiscard]] constexpr Tag tag() const noexcept { return Tag{m_size & TypeMask}; }
@@ -355,7 +321,8 @@ private:
constexpr void setSize(qsizetype sz) noexcept { m_size = size_t(sz) | tag(); }
constexpr void advanceData(qsizetype delta) noexcept
{ m_data_utf8 += delta * charSize(); }
- Q_ALWAYS_INLINE constexpr void verify(qsizetype pos, qsizetype n = 0) const
+ Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos = 0,
+ [[maybe_unused]] qsizetype n = 1) const
{
Q_ASSERT(pos >= 0);
Q_ASSERT(pos <= size());
@@ -377,7 +344,7 @@ template <typename QStringLike, std::enable_if_t<std::disjunction_v<
std::is_same<QStringLike, QByteArray>
>, bool> = true>
[[nodiscard]] inline QAnyStringView qToAnyStringViewIgnoringNull(const QStringLike &s) noexcept
-{ return QAnyStringView(s.data(), s.size()); }
+{ return QAnyStringView(s.begin(), s.size()); }
QT_END_NAMESPACE
diff --git a/src/corelib/text/qbytearray.cpp b/src/corelib/text/qbytearray.cpp
index 1b21c98a2f..e6387e4bed 100644
--- a/src/corelib/text/qbytearray.cpp
+++ b/src/corelib/text/qbytearray.cpp
@@ -14,7 +14,6 @@
#include "private/qsimd_p.h"
#include "qstringalgorithms_p.h"
#include "qscopedpointer.h"
-#include "qbytearray_p.h"
#include "qstringconverter_p.h"
#include <qdatastream.h>
#include <qmath.h>
@@ -34,7 +33,13 @@
#include <algorithm>
-#define IS_RAW_DATA(d) ((d)->flags() & QArrayData::RawDataType)
+#ifdef Q_OS_WIN
+# if !defined(QT_BOOTSTRAPPED) && (defined(QT_NO_CAST_FROM_ASCII) || defined(QT_NO_CAST_FROM_BYTEARRAY))
+// MSVC requires this, but let's apply it to MinGW compilers too, just in case
+# error "This file cannot be compiled with QT_NO_CAST_{TO,FROM}_ASCII, " \
+ "otherwise some QByteArray functions will not get exported."
+# endif
+#endif
QT_BEGIN_NAMESPACE
@@ -278,7 +283,7 @@ int qstricmp(const char *str1, const char *str2)
// yes, find out where
uint start = qCountTrailingZeroBits(mask);
uint end = sizeof(mask) * 8 - qCountLeadingZeroBits(mask);
- Q_ASSUME(end >= start);
+ Q_ASSERT(end >= start);
offset += start;
n = end - start;
break;
@@ -687,7 +692,7 @@ QByteArray qCompress(const uchar* data, qsizetype nbytes, int compressionLevel)
if (nbytes < SingleAllocLimit) {
// use maximum size
capacity += compressBound(uLong(nbytes)); // cannot overflow (both times)!
- return QArrayDataPointer{QTypedArrayData<char>::allocate(capacity)};
+ return QArrayDataPointer<char>(capacity);
}
// for larger buffers, assume it compresses optimally, and
@@ -697,7 +702,7 @@ QByteArray qCompress(const uchar* data, qsizetype nbytes, int compressionLevel)
// but use a nearby power-of-two (faster)
capacity += std::max(qsizetype(compressBound(uLong(SingleAllocLimit))),
nbytes / MaxCompressionFactor);
- return QArrayDataPointer{QTypedArrayData<char>::allocate(capacity, QArrayData::Grow)};
+ return QArrayDataPointer<char>(capacity, 0, QArrayData::Grow);
}();
if (out.data() == nullptr) // allocation failed
@@ -774,7 +779,7 @@ QByteArray qUncompress(const uchar* data, qsizetype nbytes)
return QByteArray();
}
- constexpr auto MaxDecompressedSize = size_t(MaxByteArraySize);
+ constexpr auto MaxDecompressedSize = size_t(QByteArray::max_size());
if constexpr (MaxDecompressedSize < std::numeric_limits<CompressSizeHint_t>::max()) {
if (expectedSize > MaxDecompressedSize)
return tooMuchData(ZLibOp::Decompression);
@@ -785,7 +790,7 @@ QByteArray qUncompress(const uchar* data, qsizetype nbytes)
qsizetype capacity = std::max(qsizetype(expectedSize), // cannot overflow!
nbytes);
- QArrayDataPointer d(QTypedArrayData<char>::allocate(capacity, QArrayData::KeepSize));
+ QArrayDataPointer<char> d(capacity);
return xxflate(ZLibOp::Decompression, std::move(d), {data + HeaderSize, nbytes - HeaderSize},
[] (z_stream *zs) { return inflateInit(zs); },
[] (z_stream *zs, size_t) { return inflate(zs, Z_NO_FLUSH); },
@@ -804,6 +809,14 @@ QByteArray qUncompress(const uchar* data, qsizetype nbytes)
\reentrant
+ \compares strong
+ \compareswith strong {const char *} QByteArrayView
+ \endcompareswith
+ \compareswith strong QChar char16_t QString QStringView QLatin1StringView \
+ QUtf8StringView
+ When comparing with string types, the content is interpreted as utf-8.
+ \endcompareswith
+
QByteArray can be used to store both raw bytes (including '\\0's)
and traditional 8-bit '\\0'-terminated strings. Using QByteArray
is much more convenient than using \c{const char *}. Behind the
@@ -1276,6 +1289,7 @@ QByteArray::iterator QByteArray::erase(QByteArray::const_iterator first, QByteAr
/*!
\fn QByteArray::iterator QByteArray::erase(QByteArray::const_iterator it)
+ \overload
\since 6.5
Removes the character denoted by \c it from the byte array.
@@ -1335,6 +1349,9 @@ QByteArray &QByteArray::operator=(const QByteArray & other) noexcept
\overload
Assigns \a str to this byte array.
+
+ \a str is assumed to point to a null-terminated string, and its length is
+ determined dynamically.
*/
QByteArray &QByteArray::operator=(const char *str)
@@ -1344,14 +1361,7 @@ QByteArray &QByteArray::operator=(const char *str)
} else if (!*str) {
d = DataPointer::fromRawData(&_empty, 0);
} else {
- const qsizetype len = qsizetype(strlen(str));
- const auto capacityAtEnd = d->allocatedCapacity() - d.freeSpaceAtBegin();
- if (d->needsDetach() || len > capacityAtEnd
- || (len < size() && len < (capacityAtEnd >> 1)))
- // ### inefficient! reallocData() does copy the old data and we then overwrite it in the next line
- reallocData(len, QArrayData::KeepSize);
- memcpy(d.data(), str, len + 1); // include null terminator
- d.size = len;
+ assign(str);
}
return *this;
}
@@ -1389,6 +1399,15 @@ QByteArray &QByteArray::operator=(const char *str)
\sa isEmpty(), resize()
*/
+/*! \fn qsizetype QByteArray::max_size()
+ \since 6.8
+
+ This function is provided for STL compatibility.
+ It returns the maximum number of elements that the byte array can
+ theoretically hold. In practice, the number can be much smaller,
+ limited by the amount of memory available to the system.
+*/
+
/*! \fn bool QByteArray::isEmpty() const
Returns \c true if the byte array has size 0; otherwise returns \c false.
@@ -1802,7 +1821,7 @@ QByteArray::QByteArray(const char *data, qsizetype size)
if (!size) {
d = DataPointer::fromRawData(&_empty, 0);
} else {
- d = DataPointer(Data::allocate(size), size);
+ d = DataPointer(size, size);
Q_CHECK_PTR(d.data());
memcpy(d.data(), data, size);
d.data()[size] = '\0';
@@ -1821,7 +1840,7 @@ QByteArray::QByteArray(qsizetype size, char ch)
if (size <= 0) {
d = DataPointer::fromRawData(&_empty, 0);
} else {
- d = DataPointer(Data::allocate(size), size);
+ d = DataPointer(size, size);
Q_CHECK_PTR(d.data());
memset(d.data(), ch, size);
d.data()[size] = '\0';
@@ -1829,8 +1848,6 @@ QByteArray::QByteArray(qsizetype size, char ch)
}
/*!
- \internal
-
Constructs a byte array of size \a size with uninitialized contents.
*/
@@ -1839,7 +1856,7 @@ QByteArray::QByteArray(qsizetype size, Qt::Initialization)
if (size <= 0) {
d = DataPointer::fromRawData(&_empty, 0);
} else {
- d = DataPointer(Data::allocate(size), size);
+ d = DataPointer(size, size);
Q_CHECK_PTR(d.data());
d.data()[size] = '\0';
}
@@ -1899,6 +1916,21 @@ void QByteArray::resize(qsizetype newSize, char c)
}
/*!
+ \since 6.8
+
+ Resizes the byte array to \a size bytes. If the size of the
+ byte array grows, the new bytes are uninitialized.
+
+ The behavior is identical to \c{resize(size)}.
+
+ \sa resize()
+*/
+void QByteArray::resizeForOverwrite(qsizetype size)
+{
+ resize(size);
+}
+
+/*!
Sets every byte in the byte array to \a ch. If \a size is different from -1
(the default), the byte array is resized to size \a size beforehand.
@@ -1928,7 +1960,7 @@ void QByteArray::reallocData(qsizetype alloc, QArrayData::AllocationOption optio
const bool cannotUseReallocate = d.freeSpaceAtBegin() > 0;
if (d->needsDetach() || cannotUseReallocate) {
- DataPointer dd(Data::allocate(alloc, option), qMin(alloc, d.size));
+ DataPointer dd(alloc, qMin(alloc, d.size), option);
Q_CHECK_PTR(dd.data());
if (dd.size > 0)
::memcpy(dd.data(), d.data(), dd.size);
@@ -2048,9 +2080,17 @@ QByteArray &QByteArray::prepend(const QByteArray &ba)
QByteArray &QByteArray::append(const QByteArray &ba)
{
- if (size() == 0 && ba.size() > d->freeSpaceAtEnd() && ba.d.isMutable())
- return (*this = ba);
- return append(QByteArrayView(ba));
+ if (!ba.isNull()) {
+ if (isNull()) {
+ if (Q_UNLIKELY(!ba.d.isMutable()))
+ assign(ba); // fromRawData, so we do a deep copy
+ else
+ operator=(ba);
+ } else if (ba.size()) {
+ append(QByteArrayView(ba));
+ }
+ }
+ return *this;
}
/*!
@@ -2109,6 +2149,73 @@ QByteArray& QByteArray::append(char ch)
}
/*!
+ \fn QByteArray &QByteArray::assign(QByteArrayView v)
+ \since 6.6
+
+ Replaces the contents of this byte array with a copy of \a v and returns a
+ reference to this byte array.
+
+ The size of this byte array will be equal to the size of \a v.
+
+ This function only allocates memory if the size of \a v exceeds the capacity
+ of this byte array or this byte array is shared.
+*/
+
+/*!
+ \fn QByteArray &QByteArray::assign(qsizetype n, char c)
+ \since 6.6
+
+ Replaces the contents of this byte array with \a n copies of \a c and
+ returns a reference to this byte array.
+
+ The size of this byte array will be equal to \a n, which has to be non-negative.
+
+ This function will only allocate memory if \a n exceeds the capacity of this
+ byte array or this byte array is shared.
+
+ \sa fill()
+*/
+
+/*!
+ \fn template <typename InputIterator, QByteArray::if_input_iterator<InputIterator>> QByteArray &QByteArray::assign(InputIterator first, InputIterator last)
+ \since 6.6
+
+ Replaces the contents of this byte array with a copy of the elements in the
+ iterator range [\a first, \a last) and returns a reference to this
+ byte array.
+
+ The size of this byte array will be equal to the number of elements in the
+ range [\a first, \a last).
+
+ This function will only allocate memory if the number of elements in the
+ range exceeds the capacity of this byte array or this byte array is shared.
+
+ \note This function overload only participates in overload resolution if
+ \c InputIterator meets the requirements of a
+ \l {https://en.cppreference.com/w/cpp/named_req/InputIterator} {LegacyInputIterator}.
+
+ \note The behavior is undefined if either argument is an iterator into *this or
+ [\a first, \a last) is not a valid range.
+*/
+
+QByteArray &QByteArray::assign(QByteArrayView v)
+{
+ const auto len = v.size();
+
+ if (len <= capacity() && isDetached()) {
+ const auto offset = d.freeSpaceAtBegin();
+ if (offset)
+ d.setBegin(d.begin() - offset);
+ std::memcpy(d.begin(), v.data(), len);
+ d.size = len;
+ d.data()[d.size] = '\0';
+ } else {
+ *this = v.toByteArray();
+ }
+ return *this;
+}
+
+/*!
Inserts \a data at index position \a i and returns a
reference to this byte array.
@@ -2498,12 +2605,11 @@ QByteArray &QByteArray::replace(QByteArrayView before, QByteArrayView after)
QByteArray &QByteArray::replace(char before, char after)
{
- if (!isEmpty()) {
- char *i = data();
- char *e = i + size();
- for (; i != e; ++i)
- if (*i == before)
- * i = after;
+ if (before != after) {
+ if (const auto pos = indexOf(before); pos >= 0) {
+ const auto detachedData = data();
+ std::replace(detachedData + pos, detachedData + size(), before, after);
+ }
}
return *this;
}
@@ -2579,20 +2685,6 @@ QByteArray QByteArray::repeated(qsizetype times) const
hashHaystack -= std::size_t(a) << ol_minus_1; \
hashHaystack <<= 1
-static inline qsizetype findCharHelper(QByteArrayView haystack, qsizetype from, char needle) noexcept
-{
- if (from < 0)
- from = qMax(from + haystack.size(), qsizetype(0));
- if (from < haystack.size()) {
- const char *const b = haystack.data();
- if (const auto n = static_cast<const char *>(
- memchr(b + from, needle, static_cast<size_t>(haystack.size() - from)))) {
- return n - b;
- }
- }
- return -1;
-}
-
qsizetype QtPrivate::findByteArray(QByteArrayView haystack, qsizetype from, QByteArrayView needle) noexcept
{
const auto ol = needle.size();
@@ -2605,7 +2697,7 @@ qsizetype QtPrivate::findByteArray(QByteArrayView haystack, qsizetype from, QByt
}
if (ol == 1)
- return findCharHelper(haystack, from, needle.front());
+ return findByteArray(haystack, from, needle.front());
if (from > l || ol + from > l)
return -1;
@@ -2627,6 +2719,7 @@ qsizetype QtPrivate::findByteArray(QByteArrayView haystack, qsizetype from, QByt
*/
/*!
+ \fn qsizetype QByteArray::indexOf(char ch, qsizetype from) const
\overload
Returns the index position of the start of the first occurrence of the
@@ -2639,11 +2732,6 @@ qsizetype QtPrivate::findByteArray(QByteArrayView haystack, qsizetype from, QByt
\sa lastIndexOf(), contains()
*/
-qsizetype QByteArray::indexOf(char ch, qsizetype from) const
-{
- return qToByteArrayViewIgnoringNull(*this).indexOf(ch, from);
-}
-
static qsizetype lastIndexOfHelper(const char *haystack, qsizetype l, const char *needle,
qsizetype ol, qsizetype from)
{
@@ -2697,6 +2785,11 @@ static inline qsizetype lastIndexOfCharHelper(QByteArrayView haystack, qsizetype
return -1;
}
+qsizetype QtPrivate::lastIndexOf(QByteArrayView haystack, qsizetype from, char needle) noexcept
+{
+ return lastIndexOfCharHelper(haystack, from, needle);
+}
+
qsizetype QtPrivate::lastIndexOf(QByteArrayView haystack, qsizetype from, QByteArrayView needle) noexcept
{
if (haystack.isEmpty()) {
@@ -2750,6 +2843,7 @@ qsizetype QtPrivate::lastIndexOf(QByteArrayView haystack, qsizetype from, QByteA
*/
/*!
+ \fn qsizetype QByteArray::lastIndexOf(char ch, qsizetype from) const
\overload
Returns the index position of the start of the last occurrence of byte \a ch
@@ -2763,11 +2857,6 @@ qsizetype QtPrivate::lastIndexOf(QByteArrayView haystack, qsizetype from, QByteA
\sa indexOf(), contains()
*/
-qsizetype QByteArray::lastIndexOf(char ch, qsizetype from) const
-{
- return qToByteArrayViewIgnoringNull(*this).lastIndexOf(ch, from);
-}
-
static inline qsizetype countCharHelper(QByteArrayView haystack, char needle) noexcept
{
qsizetype num = 0;
@@ -2959,6 +3048,9 @@ bool QByteArray::isLower() const
*/
/*!
+ \fn QByteArray QByteArray::left(qsizetype len) const &
+ \fn QByteArray QByteArray::left(qsizetype len) &&
+
Returns a byte array that contains the first \a len bytes of this byte
array.
@@ -2973,16 +3065,10 @@ bool QByteArray::isLower() const
\sa first(), last(), startsWith(), chopped(), chop(), truncate()
*/
-QByteArray QByteArray::left(qsizetype len) const
-{
- if (len >= size())
- return *this;
- if (len < 0)
- len = 0;
- return QByteArray(data(), len);
-}
-
/*!
+ \fn QByteArray QByteArray::right(qsizetype len) const &
+ \fn QByteArray QByteArray::right(qsizetype len) &&
+
Returns a byte array that contains the last \a len bytes of this byte array.
If you know that \a len cannot be out of bounds, use last() instead in new
@@ -2993,18 +3079,13 @@ QByteArray QByteArray::left(qsizetype len) const
Returns an empty QByteArray if \a len is smaller than 0.
- \sa endsWith(), last(), first(), sliced(), chopped(), chop(), truncate()
+ \sa endsWith(), last(), first(), sliced(), chopped(), chop(), truncate(), slice()
*/
-QByteArray QByteArray::right(qsizetype len) const
-{
- if (len >= size())
- return *this;
- if (len < 0)
- len = 0;
- return QByteArray(end() - len, len);
-}
/*!
+ \fn QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const &
+ \fn QByteArray QByteArray::mid(qsizetype pos, qsizetype len) &&
+
Returns a byte array containing \a len bytes from this byte array,
starting at position \a pos.
@@ -3015,10 +3096,10 @@ QByteArray QByteArray::right(qsizetype len) const
returns a byte array containing all bytes starting at position \a
pos until the end of the byte array.
- \sa first(), last(), sliced(), chopped(), chop(), truncate()
+ \sa first(), last(), sliced(), chopped(), chop(), truncate(), slice()
*/
-QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
+QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const &
{
qsizetype p = pos;
qsizetype l = len;
@@ -3033,13 +3114,33 @@ QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
case QContainerImplHelper::Full:
return *this;
case QContainerImplHelper::Subset:
- return QByteArray(d.data() + p, l);
+ return sliced(p, l);
+ }
+ Q_UNREACHABLE_RETURN(QByteArray());
+}
+
+QByteArray QByteArray::mid(qsizetype pos, qsizetype len) &&
+{
+ qsizetype p = pos;
+ qsizetype l = len;
+ using namespace QtPrivate;
+ switch (QContainerImplHelper::mid(size(), &p, &l)) {
+ case QContainerImplHelper::Null:
+ return QByteArray();
+ case QContainerImplHelper::Empty:
+ resize(0); // keep capacity if we've reserve()d
+ [[fallthrough]];
+ case QContainerImplHelper::Full:
+ return std::move(*this);
+ case QContainerImplHelper::Subset:
+ return std::move(*this).sliced(p, l);
}
Q_UNREACHABLE_RETURN(QByteArray());
}
/*!
- \fn QByteArray QByteArray::first(qsizetype n) const
+ \fn QByteArray QByteArray::first(qsizetype n) const &
+ \fn QByteArray QByteArray::first(qsizetype n) &&
\since 6.0
Returns the first \a n bytes of the byte array.
@@ -3049,11 +3150,12 @@ QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
Example:
\snippet code/src_corelib_text_qbytearray.cpp 27
- \sa last(), sliced(), startsWith(), chopped(), chop(), truncate()
+ \sa last(), sliced(), startsWith(), chopped(), chop(), truncate(), slice()
*/
/*!
- \fn QByteArray QByteArray::last(qsizetype n) const
+ \fn QByteArray QByteArray::last(qsizetype n) const &
+ \fn QByteArray QByteArray::last(qsizetype n) &&
\since 6.0
Returns the last \a n bytes of the byte array.
@@ -3063,11 +3165,12 @@ QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
Example:
\snippet code/src_corelib_text_qbytearray.cpp 28
- \sa first(), sliced(), endsWith(), chopped(), chop(), truncate()
+ \sa first(), sliced(), endsWith(), chopped(), chop(), truncate(), slice()
*/
/*!
- \fn QByteArray QByteArray::sliced(qsizetype pos, qsizetype n) const
+ \fn QByteArray QByteArray::sliced(qsizetype pos, qsizetype n) const &
+ \fn QByteArray QByteArray::sliced(qsizetype pos, qsizetype n) &&
\since 6.0
Returns a byte array containing the \a n bytes of this object starting
@@ -3079,11 +3182,20 @@ QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
Example:
\snippet code/src_corelib_text_qbytearray.cpp 29
- \sa first(), last(), chopped(), chop(), truncate()
+ \sa first(), last(), chopped(), chop(), truncate(), slice()
*/
+QByteArray QByteArray::sliced_helper(QByteArray &a, qsizetype pos, qsizetype n)
+{
+ if (n == 0)
+ return fromRawData(&_empty, 0);
+ DataPointer d = std::move(a.d).sliced(pos, n);
+ d.data()[n] = 0;
+ return QByteArray(std::move(d));
+}
/*!
- \fn QByteArray QByteArray::sliced(qsizetype pos) const
+ \fn QByteArray QByteArray::sliced(qsizetype pos) const &
+ \fn QByteArray QByteArray::sliced(qsizetype pos) &&
\since 6.0
\overload
@@ -3092,11 +3204,41 @@ QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
\note The behavior is undefined when \a pos < 0 or \a pos > size().
- \sa first(), last(), sliced(), chopped(), chop(), truncate()
+ \sa first(), last(), chopped(), chop(), truncate(), slice()
+*/
+
+/*!
+ \fn QByteArray &QByteArray::slice(qsizetype pos, qsizetype n)
+ \since 6.8
+
+ Modifies this byte array to start at position \a pos, extending for \a n
+ bytes, and returns a reference to this byte array.
+
+ \note The behavior is undefined if \a pos < 0, \a n < 0,
+ or \a pos + \a n > size().
+
+ Example:
+ \snippet code/src_corelib_text_qbytearray.cpp 57
+
+ \sa sliced(), first(), last(), chopped(), chop(), truncate()
*/
/*!
- \fn QByteArray QByteArray::chopped(qsizetype len) const
+ \fn QByteArray &QByteArray::slice(qsizetype pos)
+ \since 6.8
+ \overload
+
+ Modifies this byte array to start at position \a pos, extending to its
+ end, and returns a reference to this byte array.
+
+ \note The behavior is undefined if \a pos < 0 or \a pos > size().
+
+ \sa sliced(), first(), last(), chopped(), chop(), truncate()
+*/
+
+/*!
+ \fn QByteArray QByteArray::chopped(qsizetype len) const &
+ \fn QByteArray QByteArray::chopped(qsizetype len) &&
\since 5.10
Returns a byte array that contains the leftmost size() - \a len bytes of
@@ -3104,7 +3246,7 @@ QByteArray QByteArray::mid(qsizetype pos, qsizetype len) const
\note The behavior is undefined if \a len is negative or greater than size().
- \sa endsWith(), first(), last(), sliced(), chop(), truncate()
+ \sa endsWith(), first(), last(), sliced(), chop(), truncate(), slice()
*/
/*!
@@ -3190,7 +3332,7 @@ void QByteArray::clear()
d.clear();
}
-#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
+#if !defined(QT_NO_DATASTREAM)
/*! \relates QByteArray
@@ -3203,7 +3345,7 @@ void QByteArray::clear()
QDataStream &operator<<(QDataStream &out, const QByteArray &ba)
{
if (ba.isNull() && out.version() >= 6) {
- out << (quint32)0xffffffff;
+ QDataStream::writeQSizeType(out, -1);
return out;
}
return out.writeBytes(ba.constData(), ba.size());
@@ -3220,13 +3362,21 @@ QDataStream &operator<<(QDataStream &out, const QByteArray &ba)
QDataStream &operator>>(QDataStream &in, QByteArray &ba)
{
ba.clear();
- quint32 len;
- in >> len;
- if (len == 0xffffffff)
+
+ qint64 size = QDataStream::readQSizeType(in);
+ qsizetype len = size;
+ if (size != len || size < -1) {
+ ba.clear();
+ in.setStatus(QDataStream::SizeLimitExceeded);
+ return in;
+ }
+ if (len == -1) { // null byte-array
+ ba = QByteArray();
return in;
+ }
- const quint32 Step = 1024 * 1024;
- quint32 allocated = 0;
+ constexpr qsizetype Step = 1024 * 1024;
+ qsizetype allocated = 0;
do {
qsizetype blockSize = qMin(Step, len - allocated);
@@ -3243,248 +3393,164 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba)
}
#endif // QT_NO_DATASTREAM
-/*! \fn bool QByteArray::operator==(const QString &str) const
-
- Returns \c true if this byte array is equal to the UTF-8 encoding of \a str;
- otherwise returns \c false.
-
- The comparison is case sensitive.
-
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. You
- then need to call QString::fromUtf8(), QString::fromLatin1(),
- or QString::fromLocal8Bit() explicitly if you want to convert the byte
- array to a QString before doing the comparison.
-*/
-
-/*! \fn bool QByteArray::operator!=(const QString &str) const
-
- Returns \c true if this byte array is not equal to the UTF-8 encoding of \a
- str; otherwise returns \c false.
-
- The comparison is case sensitive.
-
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. You
- then need to call QString::fromUtf8(), QString::fromLatin1(),
- or QString::fromLocal8Bit() explicitly if you want to convert the byte
- array to a QString before doing the comparison.
-*/
-
-/*! \fn bool QByteArray::operator<(const QString &str) const
-
- Returns \c true if this byte array is lexically less than the UTF-8 encoding
- of \a str; otherwise returns \c false.
-
- The comparison is case sensitive.
-
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. You
- then need to call QString::fromUtf8(), QString::fromLatin1(),
- or QString::fromLocal8Bit() explicitly if you want to convert the byte
- array to a QString before doing the comparison.
-*/
-
-/*! \fn bool QByteArray::operator>(const QString &str) const
-
- Returns \c true if this byte array is lexically greater than the UTF-8
- encoding of \a str; otherwise returns \c false.
-
- The comparison is case sensitive.
-
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. You
- then need to call QString::fromUtf8(), QString::fromLatin1(),
- or QString::fromLocal8Bit() explicitly if you want to convert the byte
- array to a QString before doing the comparison.
-*/
-
-/*! \fn bool QByteArray::operator<=(const QString &str) const
-
- Returns \c true if this byte array is lexically less than or equal to the
- UTF-8 encoding of \a str; otherwise returns \c false.
-
- The comparison is case sensitive.
-
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. You
- then need to call QString::fromUtf8(), QString::fromLatin1(),
- or QString::fromLocal8Bit() explicitly if you want to convert the byte
- array to a QString before doing the comparison.
-*/
-
-/*! \fn bool QByteArray::operator>=(const QString &str) const
-
- Returns \c true if this byte array is greater than or equal to the UTF-8
- encoding of \a str; otherwise returns \c false.
-
- The comparison is case sensitive.
-
- You can disable this operator by defining \c
- QT_NO_CAST_FROM_ASCII when you compile your applications. You
- then need to call QString::fromUtf8(), QString::fromLatin1(),
- or QString::fromLocal8Bit() explicitly if you want to convert the byte
- array to a QString before doing the comparison.
-*/
-
-/*! \fn bool QByteArray::operator==(const QByteArray &a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator==(const QByteArray &lhs, const QByteArray &rhs)
\overload
- Returns \c true if byte array \a a1 is equal to byte array \a a2;
+ Returns \c true if byte array \a lhs is equal to byte array \a rhs;
otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator==(const QByteArray &a1, const char *a2)
+/*! \fn bool QByteArray::operator==(const QByteArray &lhs, const char * const &rhs)
\overload
- Returns \c true if byte array \a a1 is equal to the '\\0'-terminated string
- \a a2; otherwise returns \c false.
+ Returns \c true if byte array \a lhs is equal to the '\\0'-terminated string
+ \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator==(const char *a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator==(const char * const &lhs, const QByteArray &rhs)
\overload
- Returns \c true if '\\0'-terminated string \a a1 is equal to byte array \a
- a2; otherwise returns \c false.
+ Returns \c true if '\\0'-terminated string \a lhs is equal to byte array \a
+ rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator!=(const QByteArray &a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator!=(const QByteArray &lhs, const QByteArray &rhs)
\overload
- Returns \c true if byte array \a a1 is not equal to byte array \a a2;
+ Returns \c true if byte array \a lhs is not equal to byte array \a rhs;
otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator!=(const QByteArray &a1, const char *a2)
+/*! \fn bool QByteArray::operator!=(const QByteArray &lhs, const char * const &rhs)
\overload
- Returns \c true if byte array \a a1 is not equal to the '\\0'-terminated
- string \a a2; otherwise returns \c false.
+ Returns \c true if byte array \a lhs is not equal to the '\\0'-terminated
+ string \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator!=(const char *a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator!=(const char * const &lhs, const QByteArray &rhs)
\overload
- Returns \c true if '\\0'-terminated string \a a1 is not equal to byte array
- \a a2; otherwise returns \c false.
+ Returns \c true if '\\0'-terminated string \a lhs is not equal to byte array
+ \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator<(const QByteArray &a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator<(const QByteArray &lhs, const QByteArray &rhs)
\overload
- Returns \c true if byte array \a a1 is lexically less than byte array
- \a a2; otherwise returns \c false.
+ Returns \c true if byte array \a lhs is lexically less than byte array
+ \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator<(const QByteArray &a1, const char *a2)
+/*! \fn bool QByteArray::operator<(const QByteArray &lhs, const char * const &rhs)
\overload
- Returns \c true if byte array \a a1 is lexically less than the
- '\\0'-terminated string \a a2; otherwise returns \c false.
+ Returns \c true if byte array \a lhs is lexically less than the
+ '\\0'-terminated string \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator<(const char *a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator<(const char * const &lhs, const QByteArray &rhs)
\overload
- Returns \c true if '\\0'-terminated string \a a1 is lexically less than byte
- array \a a2; otherwise returns \c false.
+ Returns \c true if '\\0'-terminated string \a lhs is lexically less than byte
+ array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator<=(const QByteArray &a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator<=(const QByteArray &lhs, const QByteArray &rhs)
\overload
- Returns \c true if byte array \a a1 is lexically less than or equal
- to byte array \a a2; otherwise returns \c false.
+ Returns \c true if byte array \a lhs is lexically less than or equal
+ to byte array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator<=(const QByteArray &a1, const char *a2)
+/*! \fn bool QByteArray::operator<=(const QByteArray &lhs, const char * const &rhs)
\overload
- Returns \c true if byte array \a a1 is lexically less than or equal to the
- '\\0'-terminated string \a a2; otherwise returns \c false.
+ Returns \c true if byte array \a lhs is lexically less than or equal to the
+ '\\0'-terminated string \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator<=(const char *a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator<=(const char * const &lhs, const QByteArray &rhs)
\overload
- Returns \c true if '\\0'-terminated string \a a1 is lexically less than or
- equal to byte array \a a2; otherwise returns \c false.
+ Returns \c true if '\\0'-terminated string \a lhs is lexically less than or
+ equal to byte array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator>(const QByteArray &a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator>(const QByteArray &lhs, const QByteArray &rhs)
\overload
- Returns \c true if byte array \a a1 is lexically greater than byte
- array \a a2; otherwise returns \c false.
+ Returns \c true if byte array \a lhs is lexically greater than byte
+ array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator>(const QByteArray &a1, const char *a2)
+/*! \fn bool QByteArray::operator>(const QByteArray &lhs, const char * const &rhs)
\overload
- Returns \c true if byte array \a a1 is lexically greater than the
- '\\0'-terminated string \a a2; otherwise returns \c false.
+ Returns \c true if byte array \a lhs is lexically greater than the
+ '\\0'-terminated string \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator>(const char *a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator>(const char * const &lhs, const QByteArray &rhs)
\overload
- Returns \c true if '\\0'-terminated string \a a1 is lexically greater than
- byte array \a a2; otherwise returns \c false.
+ Returns \c true if '\\0'-terminated string \a lhs is lexically greater than
+ byte array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator>=(const QByteArray &a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator>=(const QByteArray &lhs, const QByteArray &rhs)
\overload
- Returns \c true if byte array \a a1 is lexically greater than or
- equal to byte array \a a2; otherwise returns \c false.
+ Returns \c true if byte array \a lhs is lexically greater than or
+ equal to byte array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator>=(const QByteArray &a1, const char *a2)
+/*! \fn bool QByteArray::operator>=(const QByteArray &lhs, const char * const &rhs)
\overload
- Returns \c true if byte array \a a1 is lexically greater than or equal to
- the '\\0'-terminated string \a a2; otherwise returns \c false.
+ Returns \c true if byte array \a lhs is lexically greater than or equal to
+ the '\\0'-terminated string \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
-/*! \fn bool QByteArray::operator>=(const char *a1, const QByteArray &a2)
+/*! \fn bool QByteArray::operator>=(const char * const &lhs, const QByteArray &rhs)
\overload
- Returns \c true if '\\0'-terminated string \a a1 is lexically greater than
- or equal to byte array \a a2; otherwise returns \c false.
+ Returns \c true if '\\0'-terminated string \a lhs is lexically greater than
+ or equal to byte array \a rhs; otherwise returns \c false.
\sa QByteArray::compare()
*/
@@ -3592,9 +3658,7 @@ QByteArray QByteArray::trimmed_helper(QByteArray &a)
QByteArrayView QtPrivate::trimmed(QByteArrayView view) noexcept
{
- auto start = view.begin();
- auto stop = view.end();
- QStringAlgorithms<QByteArrayView>::trimmed_helper_positions(start, stop);
+ const auto [start, stop] = QStringAlgorithms<QByteArrayView>::trimmed_helper_positions(view);
return QByteArrayView(start, stop);
}
@@ -3683,10 +3747,9 @@ auto QtPrivate::toSignedInteger(QByteArrayView data, int base) -> ParsedNumber<q
if (data.isEmpty())
return {};
- bool ok = false;
- const auto i = QLocaleData::bytearrayToLongLong(data, base, &ok);
- if (ok)
- return ParsedNumber(i);
+ const QSimpleParsedNumber r = QLocaleData::bytearrayToLongLong(data, base);
+ if (r.ok())
+ return ParsedNumber(r.result);
return {};
}
@@ -3701,10 +3764,9 @@ auto QtPrivate::toUnsignedInteger(QByteArrayView data, int base) -> ParsedNumber
if (data.isEmpty())
return {};
- bool ok = false;
- const auto u = QLocaleData::bytearrayToUnsLongLong(data, base, &ok);
- if (ok)
- return ParsedNumber(u);
+ const QSimpleParsedNumber r = QLocaleData::bytearrayToUnsLongLong(data, base);
+ if (r.ok())
+ return ParsedNumber(r.result);
return {};
}
@@ -4047,12 +4109,12 @@ auto QtPrivate::toFloat(QByteArrayView a) noexcept -> ParsedNumber<float>
*/
QByteArray QByteArray::toBase64(Base64Options options) const
{
- const char alphabet_base64[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef"
- "ghijklmn" "opqrstuv" "wxyz0123" "456789+/";
- const char alphabet_base64url[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef"
- "ghijklmn" "opqrstuv" "wxyz0123" "456789-_";
+ constexpr char alphabet_base64[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef"
+ "ghijklmn" "opqrstuv" "wxyz0123" "456789+/";
+ constexpr char alphabet_base64url[] = "ABCDEFGH" "IJKLMNOP" "QRSTUVWX" "YZabcdef"
+ "ghijklmn" "opqrstuv" "wxyz0123" "456789-_";
const char *const alphabet = options & Base64UrlEncoding ? alphabet_base64url : alphabet_base64;
- const char padchar = '=';
+ constexpr char padchar = '=';
qsizetype padlen = 0;
const qsizetype sz = size();
@@ -4164,7 +4226,7 @@ static char *qulltoa2(char *p, qulonglong n, int base)
base = 10;
}
#endif
- const char b = 'a' - 10;
+ constexpr char b = 'a' - 10;
do {
const int c = n % base;
n /= base;
@@ -4181,7 +4243,7 @@ static char *qulltoa2(char *p, qulonglong n, int base)
*/
QByteArray &QByteArray::setNum(qlonglong n, int base)
{
- const int buffsize = 66; // big enough for MAX_ULLONG in base 2
+ constexpr int buffsize = 66; // big enough for MAX_ULLONG in base 2
char buff[buffsize];
char *p;
@@ -4206,7 +4268,7 @@ QByteArray &QByteArray::setNum(qlonglong n, int base)
QByteArray &QByteArray::setNum(qulonglong n, int base)
{
- const int buffsize = 66; // big enough for MAX_ULLONG in base 2
+ constexpr int buffsize = 66; // big enough for MAX_ULLONG in base 2
char buff[buffsize];
char *p = qulltoa2(buff + buffsize, n, base);
@@ -5145,5 +5207,4 @@ size_t qHash(const QByteArray::FromBase64Result &key, size_t seed) noexcept
QT_END_NAMESPACE
-#undef IS_RAW_DATA
#undef REHASH
diff --git a/src/corelib/text/qbytearray.h b/src/corelib/text/qbytearray.h
index 2c15545ecd..3c8a3bba45 100644
--- a/src/corelib/text/qbytearray.h
+++ b/src/corelib/text/qbytearray.h
@@ -9,13 +9,13 @@
#include <QtCore/qnamespace.h>
#include <QtCore/qarraydata.h>
#include <QtCore/qarraydatapointer.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qcontainerfwd.h>
#include <QtCore/qbytearrayalgorithms.h>
#include <QtCore/qbytearrayview.h>
#include <stdlib.h>
#include <string.h>
-#include <stdarg.h>
#include <string>
#include <iterator>
@@ -40,6 +40,8 @@ namespace emscripten {
}
#endif
+class tst_QByteArray;
+
QT_BEGIN_NAMESPACE
class QString;
@@ -60,6 +62,11 @@ private:
DataPointer d;
static const char _empty;
+
+ friend class ::tst_QByteArray;
+
+ template <typename InputIterator>
+ using if_input_iterator = QtPrivate::IfIsInputIterator<InputIterator>;
public:
enum Base64Option {
@@ -85,6 +92,7 @@ public:
QByteArray(const char *, qsizetype size = -1);
QByteArray(qsizetype size, char c);
QByteArray(qsizetype size, Qt::Initialization);
+ explicit QByteArray(QByteArrayView v) : QByteArray(v.data(), v.size()) {}
inline QByteArray(const QByteArray &) noexcept;
inline ~QByteArray();
@@ -99,6 +107,7 @@ public:
bool isEmpty() const noexcept { return size() == 0; }
void resize(qsizetype size);
void resize(qsizetype size, char c);
+ void resizeForOverwrite(qsizetype size);
QByteArray &fill(char c, qsizetype size = -1);
@@ -127,10 +136,12 @@ public:
[[nodiscard]] char back() const { return at(size() - 1); }
[[nodiscard]] inline char &back();
+ QT_CORE_INLINE_SINCE(6, 7)
qsizetype indexOf(char c, qsizetype from = 0) const;
qsizetype indexOf(QByteArrayView bv, qsizetype from = 0) const
{ return QtPrivate::findByteArray(qToByteArrayViewIgnoringNull(*this), from, bv); }
+ QT_CORE_INLINE_SINCE(6, 7)
qsizetype lastIndexOf(char c, qsizetype from = -1) const;
qsizetype lastIndexOf(QByteArrayView bv) const
{ return lastIndexOf(bv, size()); }
@@ -145,20 +156,69 @@ public:
inline int compare(QByteArrayView a, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
- [[nodiscard]] QByteArray left(qsizetype len) const;
- [[nodiscard]] QByteArray right(qsizetype len) const;
- [[nodiscard]] QByteArray mid(qsizetype index, qsizetype len = -1) const;
-
- [[nodiscard]] QByteArray first(qsizetype n) const
- { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); return QByteArray(data(), n); }
- [[nodiscard]] QByteArray last(qsizetype n) const
- { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); return QByteArray(data() + size() - n, n); }
- [[nodiscard]] QByteArray sliced(qsizetype pos) const
- { Q_ASSERT(pos >= 0); Q_ASSERT(pos <= size()); return QByteArray(data() + pos, size() - pos); }
- [[nodiscard]] QByteArray sliced(qsizetype pos, qsizetype n) const
- { Q_ASSERT(pos >= 0); Q_ASSERT(n >= 0); Q_ASSERT(size_t(pos) + size_t(n) <= size_t(size())); return QByteArray(data() + pos, n); }
- [[nodiscard]] QByteArray chopped(qsizetype len) const
- { Q_ASSERT(len >= 0); Q_ASSERT(len <= size()); return first(size() - len); }
+#if QT_CORE_REMOVED_SINCE(6, 7)
+ QByteArray left(qsizetype len) const;
+ QByteArray right(qsizetype len) const;
+ QByteArray mid(qsizetype index, qsizetype len = -1) const;
+ QByteArray first(qsizetype n) const;
+ QByteArray last(qsizetype n) const;
+ QByteArray sliced(qsizetype pos) const;
+ QByteArray sliced(qsizetype pos, qsizetype n) const;
+ QByteArray chopped(qsizetype len) const;
+#else
+ [[nodiscard]] QByteArray left(qsizetype n) const &
+ {
+ if (n >= size())
+ return *this;
+ return first(qMax(n, 0));
+ }
+ [[nodiscard]] QByteArray left(qsizetype n) &&
+ {
+ if (n >= size())
+ return std::move(*this);
+ return std::move(*this).first(qMax(n, 0));
+ }
+ [[nodiscard]] QByteArray right(qsizetype n) const &
+ {
+ if (n >= size())
+ return *this;
+ return last(qMax(n, 0));
+ }
+ [[nodiscard]] QByteArray right(qsizetype n) &&
+ {
+ if (n >= size())
+ return std::move(*this);
+ return std::move(*this).last(qMax(n, 0));
+ }
+ [[nodiscard]] QByteArray mid(qsizetype index, qsizetype len = -1) const &;
+ [[nodiscard]] QByteArray mid(qsizetype index, qsizetype len = -1) &&;
+
+ [[nodiscard]] QByteArray first(qsizetype n) const &
+ { verify(0, n); return sliced(0, n); }
+ [[nodiscard]] QByteArray last(qsizetype n) const &
+ { verify(0, n); return sliced(size() - n, n); }
+ [[nodiscard]] QByteArray sliced(qsizetype pos) const &
+ { verify(pos, 0); return sliced(pos, size() - pos); }
+ [[nodiscard]] QByteArray sliced(qsizetype pos, qsizetype n) const &
+ { verify(pos, n); return QByteArray(d.data() + pos, n); }
+ [[nodiscard]] QByteArray chopped(qsizetype len) const &
+ { verify(0, len); return sliced(0, size() - len); }
+
+ [[nodiscard]] QByteArray first(qsizetype n) &&
+ {
+ verify(0, n);
+ resize(n); // may detach and allocate memory
+ return std::move(*this);
+ }
+ [[nodiscard]] QByteArray last(qsizetype n) &&
+ { verify(0, n); return sliced_helper(*this, size() - n, n); }
+ [[nodiscard]] QByteArray sliced(qsizetype pos) &&
+ { verify(pos, 0); return sliced_helper(*this, pos, size() - pos); }
+ [[nodiscard]] QByteArray sliced(qsizetype pos, qsizetype n) &&
+ { verify(pos, n); return sliced_helper(*this, pos, n); }
+ [[nodiscard]] QByteArray chopped(qsizetype len) &&
+ { verify(0, len); return std::move(*this).first(size() - len); }
+#endif
bool startsWith(QByteArrayView bv) const
{ return QtPrivate::startsWith(qToByteArrayViewIgnoringNull(*this), bv); }
@@ -179,6 +239,17 @@ public:
void truncate(qsizetype pos);
void chop(qsizetype n);
+ QByteArray &slice(qsizetype pos)
+ { verify(pos, 0); return remove(0, pos); }
+ QByteArray &slice(qsizetype pos, qsizetype n)
+ {
+ verify(pos, n);
+ if (isNull())
+ return *this;
+ resize(pos + n);
+ return remove(0, pos);
+ }
+
#if !defined(Q_QDOC)
[[nodiscard]] QByteArray toLower() const &
{ return toLower_helper(*this); }
@@ -227,6 +298,20 @@ public:
QByteArray &append(QByteArrayView a)
{ return insert(size(), a); }
+ QByteArray &assign(QByteArrayView v);
+ QByteArray &assign(qsizetype n, char c)
+ {
+ Q_ASSERT(n >= 0);
+ return fill(c, n);
+ }
+ template <typename InputIterator, if_input_iterator<InputIterator> = true>
+ QByteArray &assign(InputIterator first, InputIterator last)
+ {
+ d.assign(first, last);
+ d.data()[d.size] = '\0';
+ return *this;
+ }
+
QByteArray &insert(qsizetype i, QByteArrayView data);
inline QByteArray &insert(qsizetype i, const char *s)
{ return insert(i, QByteArrayView(s)); }
@@ -275,64 +360,15 @@ public:
[[nodiscard]] QByteArray repeated(qsizetype times) const;
#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
+#if QT_CORE_REMOVED_SINCE(6, 8)
QT_ASCII_CAST_WARN inline bool operator==(const QString &s2) const;
QT_ASCII_CAST_WARN inline bool operator!=(const QString &s2) const;
QT_ASCII_CAST_WARN inline bool operator<(const QString &s2) const;
QT_ASCII_CAST_WARN inline bool operator>(const QString &s2) const;
QT_ASCII_CAST_WARN inline bool operator<=(const QString &s2) const;
QT_ASCII_CAST_WARN inline bool operator>=(const QString &s2) const;
-#endif
- friend inline bool operator==(const QByteArray &a1, const QByteArray &a2) noexcept
- { return QByteArrayView(a1) == QByteArrayView(a2); }
- friend inline bool operator==(const QByteArray &a1, const char *a2) noexcept
- { return QByteArrayView(a1) == QByteArrayView(a2); }
- friend inline bool operator==(const char *a1, const QByteArray &a2) noexcept
- { return QByteArrayView(a1) == QByteArrayView(a2); }
- friend inline bool operator!=(const QByteArray &a1, const QByteArray &a2) noexcept
- { return !(a1==a2); }
- friend inline bool operator!=(const QByteArray &a1, const char *a2) noexcept
- { return QByteArrayView(a1) != QByteArrayView(a2); }
- friend inline bool operator!=(const char *a1, const QByteArray &a2) noexcept
- { return QByteArrayView(a1) != QByteArrayView(a2); }
- friend inline bool operator<(const QByteArray &a1, const QByteArray &a2) noexcept
- { return QtPrivate::compareMemory(QByteArrayView(a1), QByteArrayView(a2)) < 0; }
- friend inline bool operator<(const QByteArray &a1, const char *a2) noexcept
- { return QtPrivate::compareMemory(a1, a2) < 0; }
- friend inline bool operator<(const char *a1, const QByteArray &a2) noexcept
- { return QtPrivate::compareMemory(a1, a2) < 0; }
- friend inline bool operator<=(const QByteArray &a1, const QByteArray &a2) noexcept
- { return QtPrivate::compareMemory(QByteArrayView(a1), QByteArrayView(a2)) <= 0; }
- friend inline bool operator<=(const QByteArray &a1, const char *a2) noexcept
- { return QtPrivate::compareMemory(a1, a2) <= 0; }
- friend inline bool operator<=(const char *a1, const QByteArray &a2) noexcept
- { return QtPrivate::compareMemory(a1, a2) <= 0; }
- friend inline bool operator>(const QByteArray &a1, const QByteArray &a2) noexcept
- { return QtPrivate::compareMemory(QByteArrayView(a1), QByteArrayView(a2)) > 0; }
- friend inline bool operator>(const QByteArray &a1, const char *a2) noexcept
- { return QtPrivate::compareMemory(a1, a2) > 0; }
- friend inline bool operator>(const char *a1, const QByteArray &a2) noexcept
- { return QtPrivate::compareMemory(a1, a2) > 0; }
- friend inline bool operator>=(const QByteArray &a1, const QByteArray &a2) noexcept
- { return QtPrivate::compareMemory(QByteArrayView(a1), QByteArrayView(a2)) >= 0; }
- friend inline bool operator>=(const QByteArray &a1, const char *a2) noexcept
- { return QtPrivate::compareMemory(a1, a2) >= 0; }
- friend inline bool operator>=(const char *a1, const QByteArray &a2) noexcept
- { return QtPrivate::compareMemory(a1, a2) >= 0; }
-
- // Check isEmpty() instead of isNull() for backwards compatibility.
- friend inline bool operator==(const QByteArray &a1, std::nullptr_t) noexcept { return a1.isEmpty(); }
- friend inline bool operator!=(const QByteArray &a1, std::nullptr_t) noexcept { return !a1.isEmpty(); }
- friend inline bool operator< (const QByteArray & , std::nullptr_t) noexcept { return false; }
- friend inline bool operator> (const QByteArray &a1, std::nullptr_t) noexcept { return !a1.isEmpty(); }
- friend inline bool operator<=(const QByteArray &a1, std::nullptr_t) noexcept { return a1.isEmpty(); }
- friend inline bool operator>=(const QByteArray & , std::nullptr_t) noexcept { return true; }
-
- friend inline bool operator==(std::nullptr_t, const QByteArray &a2) noexcept { return a2 == nullptr; }
- friend inline bool operator!=(std::nullptr_t, const QByteArray &a2) noexcept { return a2 != nullptr; }
- friend inline bool operator< (std::nullptr_t, const QByteArray &a2) noexcept { return a2 > nullptr; }
- friend inline bool operator> (std::nullptr_t, const QByteArray &a2) noexcept { return a2 < nullptr; }
- friend inline bool operator<=(std::nullptr_t, const QByteArray &a2) noexcept { return a2 >= nullptr; }
- friend inline bool operator>=(std::nullptr_t, const QByteArray &a2) noexcept { return a2 <= nullptr; }
+#endif // QT_CORE_REMOVED_SINCE(6, 8)
+#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
short toShort(bool *ok = nullptr, int base = 10) const;
ushort toUShort(bool *ok = nullptr, int base = 10) const;
@@ -405,11 +441,11 @@ public:
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
iterator begin() { return data(); }
- const_iterator begin() const noexcept { return data(); }
+ const_iterator begin() const noexcept { return d.data(); }
const_iterator cbegin() const noexcept { return begin(); }
const_iterator constBegin() const noexcept { return begin(); }
- iterator end() { return data() + size(); }
- const_iterator end() const noexcept { return data() + size(); }
+ iterator end() { return begin() + size(); }
+ const_iterator end() const noexcept { return begin() + size(); }
const_iterator cend() const noexcept { return end(); }
const_iterator constEnd() const noexcept { return end(); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
@@ -446,6 +482,11 @@ public:
void shrink_to_fit() { squeeze(); }
iterator erase(const_iterator first, const_iterator last);
inline iterator erase(const_iterator it) { return erase(it, it + 1); }
+ static constexpr qsizetype max_size() noexcept
+ {
+ // -1 to deal with the NUL terminator
+ return Data::max_size() - 1;
+ }
static QByteArray fromStdString(const std::string &s);
std::string toStdString() const;
@@ -459,6 +500,7 @@ public:
QT_CORE_INLINE_SINCE(6, 4)
bool isNull() const noexcept;
+ inline const DataPointer &data_ptr() const { return d; }
inline DataPointer &data_ptr() { return d; }
#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
explicit inline QByteArray(const DataPointer &dd) : d(dd) {}
@@ -466,10 +508,66 @@ public:
explicit inline QByteArray(DataPointer &&dd) : d(std::move(dd)) {}
private:
+ friend bool comparesEqual(const QByteArray &lhs, const QByteArrayView &rhs) noexcept
+ { return QByteArrayView(lhs) == rhs; }
+ friend Qt::strong_ordering
+ compareThreeWay(const QByteArray &lhs, const QByteArrayView &rhs) noexcept
+ {
+ const int res = QtPrivate::compareMemory(QByteArrayView(lhs), rhs);
+ return Qt::compareThreeWay(res, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QByteArray)
+ Q_DECLARE_STRONGLY_ORDERED(QByteArray, QByteArrayView)
+ Q_DECLARE_STRONGLY_ORDERED(QByteArray, const char *)
+#if defined(__GLIBCXX__) && defined(__cpp_lib_three_way_comparison)
+ // libstdc++ has a bug [0] when `operator const void *()` is preferred over
+ // `operator<=>()` when calling std::less<> and other similar methods.
+ // Fix it by explicitly providing relational operators in such case.
+ // [0]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114153
+ friend bool operator<(const QByteArray &lhs, const QByteArray &rhs) noexcept
+ { return is_lt(compareThreeWay(lhs, rhs)); }
+ friend bool operator<=(const QByteArray &lhs, const QByteArray &rhs) noexcept
+ { return is_lteq(compareThreeWay(lhs, rhs)); }
+ friend bool operator>(const QByteArray &lhs, const QByteArray &rhs) noexcept
+ { return is_gt(compareThreeWay(lhs, rhs)); }
+ friend bool operator>=(const QByteArray &lhs, const QByteArray &rhs) noexcept
+ { return is_gteq(compareThreeWay(lhs, rhs)); }
+#endif // defined(__GLIBCXX__) && defined(__cpp_lib_three_way_comparison)
+
+ // Check isEmpty() instead of isNull() for backwards compatibility.
+ friend bool comparesEqual(const QByteArray &lhs, std::nullptr_t) noexcept
+ { return lhs.isEmpty(); }
+ friend Qt::strong_ordering compareThreeWay(const QByteArray &lhs, std::nullptr_t) noexcept
+ { return lhs.isEmpty() ? Qt::strong_ordering::equivalent : Qt::strong_ordering::greater; }
+ Q_DECLARE_STRONGLY_ORDERED(QByteArray, std::nullptr_t)
+
+ // defined in qstring.cpp
+ friend Q_CORE_EXPORT bool comparesEqual(const QByteArray &lhs, const QChar &rhs) noexcept;
+ friend Q_CORE_EXPORT Qt::strong_ordering
+ compareThreeWay(const QByteArray &lhs, const QChar &rhs) noexcept;
+ friend Q_CORE_EXPORT bool comparesEqual(const QByteArray &lhs, char16_t rhs) noexcept;
+ friend Q_CORE_EXPORT Qt::strong_ordering
+ compareThreeWay(const QByteArray &lhs, char16_t rhs) noexcept;
+#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
+ Q_DECLARE_STRONGLY_ORDERED(QByteArray, QChar, QT_ASCII_CAST_WARN)
+ Q_DECLARE_STRONGLY_ORDERED(QByteArray, char16_t, QT_ASCII_CAST_WARN)
+#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
+
+
void reallocData(qsizetype alloc, QArrayData::AllocationOption option);
void reallocGrowData(qsizetype n);
void expand(qsizetype i);
+ Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos = 0,
+ [[maybe_unused]] qsizetype n = 1) const
+ {
+ Q_ASSERT(pos >= 0);
+ Q_ASSERT(pos <= d.size);
+ Q_ASSERT(n >= 0);
+ Q_ASSERT(n <= d.size - pos);
+ }
+
+ static QByteArray sliced_helper(QByteArray &a, qsizetype pos, qsizetype n);
static QByteArray toLower_helper(const QByteArray &a);
static QByteArray toLower_helper(QByteArray &a);
static QByteArray toUpper_helper(const QByteArray &a);
@@ -500,9 +598,9 @@ inline constexpr QByteArray::QByteArray() noexcept {}
inline QByteArray::~QByteArray() {}
inline char QByteArray::at(qsizetype i) const
-{ Q_ASSERT(size_t(i) < size_t(size())); return d.data()[i]; }
+{ verify(i, 1); return d.data()[i]; }
inline char QByteArray::operator[](qsizetype i) const
-{ Q_ASSERT(size_t(i) < size_t(size())); return d.data()[i]; }
+{ verify(i, 1); return d.data()[i]; }
#ifndef QT_NO_CAST_FROM_BYTEARRAY
inline QByteArray::operator const char *() const
@@ -552,7 +650,7 @@ inline void QByteArray::squeeze()
}
inline char &QByteArray::operator[](qsizetype i)
-{ Q_ASSERT(i >= 0 && i < size()); return data()[i]; }
+{ verify(i, 1); return data()[i]; }
inline char &QByteArray::front() { return operator[](0); }
inline char &QByteArray::back() { return operator[](size() - 1); }
inline QByteArray &QByteArray::append(qsizetype n, char ch)
@@ -608,6 +706,16 @@ bool QByteArray::isNull() const noexcept
return d->isNull();
}
#endif
+#if QT_CORE_INLINE_IMPL_SINCE(6, 7)
+qsizetype QByteArray::indexOf(char ch, qsizetype from) const
+{
+ return qToByteArrayViewIgnoringNull(*this).indexOf(ch, from);
+}
+qsizetype QByteArray::lastIndexOf(char ch, qsizetype from) const
+{
+ return qToByteArrayViewIgnoringNull(*this).lastIndexOf(ch, from);
+}
+#endif
#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QByteArray &);
@@ -687,14 +795,14 @@ qsizetype erase_if(QByteArray &ba, Predicate pred)
//
QByteArray QByteArrayView::toByteArray() const
{
- return QByteArray(data(), size());
+ return QByteArray(*this);
}
namespace Qt {
inline namespace Literals {
inline namespace StringLiterals {
-inline QByteArray operator"" _ba(const char *str, size_t size) noexcept
+inline QByteArray operator""_ba(const char *str, size_t size) noexcept
{
return QByteArray(QByteArrayData(nullptr, const_cast<char *>(str), qsizetype(size)));
}
@@ -707,7 +815,7 @@ inline namespace QtLiterals {
#if QT_DEPRECATED_SINCE(6, 8)
QT_DEPRECATED_VERSION_X_6_8("Use _ba from Qt::StringLiterals namespace instead.")
-inline QByteArray operator"" _qba(const char *str, size_t size) noexcept
+inline QByteArray operator""_qba(const char *str, size_t size) noexcept
{
return Qt::StringLiterals::operator""_ba(str, size);
}
diff --git a/src/corelib/text/qbytearray_p.h b/src/corelib/text/qbytearray_p.h
deleted file mode 100644
index 8fc3d7e357..0000000000
--- a/src/corelib/text/qbytearray_p.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QBYTEARRAY_P_H
-#define QBYTEARRAY_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of other Qt classes. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qbytearray.h>
-#include "private/qtools_p.h"
-
-QT_BEGIN_NAMESPACE
-
-// -1 because of the terminating NUL
-constexpr qsizetype MaxByteArraySize = MaxAllocSize - sizeof(std::remove_pointer<QByteArray::DataPointer>::type) - 1;
-constexpr qsizetype MaxStringSize = (MaxAllocSize - sizeof(std::remove_pointer<QByteArray::DataPointer>::type)) / 2 - 1;
-
-QT_END_NAMESPACE
-
-#endif // QBYTEARRAY_P_H
diff --git a/src/corelib/text/qbytearrayalgorithms.h b/src/corelib/text/qbytearrayalgorithms.h
index 081fb66f81..7060161bb4 100644
--- a/src/corelib/text/qbytearrayalgorithms.h
+++ b/src/corelib/text/qbytearrayalgorithms.h
@@ -25,10 +25,16 @@ bool startsWith(QByteArrayView haystack, QByteArrayView needle) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION
bool endsWith(QByteArrayView haystack, QByteArrayView needle) noexcept;
+[[nodiscard]] inline
+qsizetype findByteArray(QByteArrayView haystack, qsizetype from, char needle) noexcept;
+
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION
qsizetype findByteArray(QByteArrayView haystack, qsizetype from, QByteArrayView needle) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION
+qsizetype lastIndexOf(QByteArrayView haystack, qsizetype from, char needle) noexcept;
+
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION
qsizetype lastIndexOf(QByteArrayView haystack, qsizetype from, QByteArrayView needle) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION
diff --git a/src/corelib/text/qbytearrayview.h b/src/corelib/text/qbytearrayview.h
index f822a2ca20..45ebc812cd 100644
--- a/src/corelib/text/qbytearrayview.h
+++ b/src/corelib/text/qbytearrayview.h
@@ -4,10 +4,12 @@
#define QBYTEARRAYVIEW_H
#include <QtCore/qbytearrayalgorithms.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qstringfwd.h>
#include <QtCore/qarraydata.h>
#include <string>
+#include <string_view>
#include <QtCore/q20type_traits.h>
QT_BEGIN_NAMESPACE
@@ -166,6 +168,9 @@ public:
constexpr QByteArrayView(const char (&data)[Size]) noexcept
: QByteArrayView(data, lengthHelperCharArray(data, Size)) {}
+ constexpr QByteArrayView(QLatin1StringView v) noexcept; // defined in qlatin1stringview.h
+ constexpr QByteArrayView(QUtf8StringView v) noexcept; // defined in qutf8stringview.h
+
#ifdef Q_QDOC
template <typename Byte, size_t Size>
#else
@@ -180,7 +185,7 @@ public:
[[nodiscard]] constexpr const_pointer constData() const noexcept { return data(); }
[[nodiscard]] constexpr char operator[](qsizetype n) const
- { Q_ASSERT(n >= 0); Q_ASSERT(n < size()); return m_data[n]; }
+ { verify(n, 1); return m_data[n]; }
//
// QByteArray API
@@ -188,15 +193,15 @@ public:
[[nodiscard]] constexpr char at(qsizetype n) const { return (*this)[n]; }
[[nodiscard]] constexpr QByteArrayView first(qsizetype n) const
- { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); return QByteArrayView(data(), n); }
+ { verify(0, n); return sliced(0, n); }
[[nodiscard]] constexpr QByteArrayView last(qsizetype n) const
- { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); return QByteArrayView(data() + size() - n, n); }
+ { verify(0, n); return sliced(size() - n, n); }
[[nodiscard]] constexpr QByteArrayView sliced(qsizetype pos) const
- { Q_ASSERT(pos >= 0); Q_ASSERT(pos <= size()); return QByteArrayView(data() + pos, size() - pos); }
+ { verify(pos, 0); return QByteArrayView(data() + pos, size() - pos); }
[[nodiscard]] constexpr QByteArrayView sliced(qsizetype pos, qsizetype n) const
- { Q_ASSERT(pos >= 0); Q_ASSERT(n >= 0); Q_ASSERT(size_t(pos) + size_t(n) <= size_t(size())); return QByteArrayView(data() + pos, n); }
+ { verify(pos, n); return QByteArrayView(data() + pos, n); }
[[nodiscard]] constexpr QByteArrayView chopped(qsizetype len) const
- { Q_ASSERT(len >= 0); Q_ASSERT(len <= size()); return first(size() - len); }
+ { verify(0, len); return sliced(0, size() - len); }
[[nodiscard]] constexpr QByteArrayView left(qsizetype n) const
{ if (n < 0 || n > size()) n = size(); return QByteArrayView(data(), n); }
@@ -211,9 +216,9 @@ public:
}
constexpr void truncate(qsizetype n)
- { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); m_size = n; }
+ { verify(0, n); m_size = n; }
constexpr void chop(qsizetype n)
- { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); m_size -= n; }
+ { verify(0, n); m_size -= n; }
// Defined in qbytearray.cpp:
[[nodiscard]] QByteArrayView trimmed() const noexcept
@@ -251,18 +256,18 @@ public:
[[nodiscard]] bool startsWith(QByteArrayView other) const noexcept
{ return QtPrivate::startsWith(*this, other); }
- [[nodiscard]] bool startsWith(char c) const noexcept
+ [[nodiscard]] constexpr bool startsWith(char c) const noexcept
{ return !empty() && front() == c; }
[[nodiscard]] bool endsWith(QByteArrayView other) const noexcept
{ return QtPrivate::endsWith(*this, other); }
- [[nodiscard]] bool endsWith(char c) const noexcept
+ [[nodiscard]] constexpr bool endsWith(char c) const noexcept
{ return !empty() && back() == c; }
[[nodiscard]] qsizetype indexOf(QByteArrayView a, qsizetype from = 0) const noexcept
{ return QtPrivate::findByteArray(*this, from, a); }
[[nodiscard]] qsizetype indexOf(char ch, qsizetype from = 0) const noexcept
- { return QtPrivate::findByteArray(*this, from, QByteArrayView(&ch, 1)); }
+ { return QtPrivate::findByteArray(*this, from, ch); }
[[nodiscard]] bool contains(QByteArrayView a) const noexcept
{ return indexOf(a) != qsizetype(-1); }
@@ -274,7 +279,7 @@ public:
[[nodiscard]] qsizetype lastIndexOf(QByteArrayView a, qsizetype from) const noexcept
{ return QtPrivate::lastIndexOf(*this, from, a); }
[[nodiscard]] qsizetype lastIndexOf(char ch, qsizetype from = -1) const noexcept
- { return QtPrivate::lastIndexOf(*this, from, QByteArrayView(&ch, 1)); }
+ { return QtPrivate::lastIndexOf(*this, from, ch); }
[[nodiscard]] qsizetype count(QByteArrayView a) const noexcept
{ return QtPrivate::count(*this, a); }
@@ -301,6 +306,9 @@ public:
[[nodiscard]] constexpr char front() const { Q_ASSERT(!empty()); return m_data[0]; }
[[nodiscard]] constexpr char back() const { Q_ASSERT(!empty()); return m_data[m_size - 1]; }
+ [[nodiscard]] constexpr Q_IMPLICIT operator std::string_view() const noexcept
+ { return std::string_view(m_data, size_t(m_size)); }
+
//
// Qt compatibility API:
//
@@ -311,20 +319,51 @@ public:
[[nodiscard]] constexpr char first() const { return front(); }
[[nodiscard]] constexpr char last() const { return back(); }
- friend inline bool operator==(QByteArrayView lhs, QByteArrayView rhs) noexcept
- { return lhs.size() == rhs.size() && (!lhs.size() || memcmp(lhs.data(), rhs.data(), lhs.size()) == 0); }
- friend inline bool operator!=(QByteArrayView lhs, QByteArrayView rhs) noexcept
- { return !(lhs == rhs); }
- friend inline bool operator< (QByteArrayView lhs, QByteArrayView rhs) noexcept
- { return QtPrivate::compareMemory(lhs, rhs) < 0; }
- friend inline bool operator<=(QByteArrayView lhs, QByteArrayView rhs) noexcept
- { return QtPrivate::compareMemory(lhs, rhs) <= 0; }
- friend inline bool operator> (QByteArrayView lhs, QByteArrayView rhs) noexcept
- { return !(lhs <= rhs); }
- friend inline bool operator>=(QByteArrayView lhs, QByteArrayView rhs) noexcept
- { return !(lhs < rhs); }
-
private:
+ Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos = 0,
+ [[maybe_unused]] qsizetype n = 1) const
+ {
+ Q_ASSERT(pos >= 0);
+ Q_ASSERT(pos <= size());
+ Q_ASSERT(n >= 0);
+ Q_ASSERT(n <= size() - pos);
+ }
+
+ friend bool
+ comparesEqual(const QByteArrayView &lhs, const QByteArrayView &rhs) noexcept
+ {
+ return lhs.size() == rhs.size()
+ && (!lhs.size() || memcmp(lhs.data(), rhs.data(), lhs.size()) == 0);
+ }
+ friend Qt::strong_ordering
+ compareThreeWay(const QByteArrayView &lhs, const QByteArrayView &rhs) noexcept
+ {
+ const int res = QtPrivate::compareMemory(lhs, rhs);
+ return Qt::compareThreeWay(res, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QByteArrayView)
+
+ friend bool comparesEqual(const QByteArrayView &lhs, const char *rhs) noexcept
+ { return comparesEqual(lhs, QByteArrayView(rhs)); }
+ friend Qt::strong_ordering
+ compareThreeWay(const QByteArrayView &lhs, const char *rhs) noexcept
+ { return compareThreeWay(lhs, QByteArrayView(rhs)); }
+ Q_DECLARE_STRONGLY_ORDERED(QByteArrayView, const char *)
+
+ // defined in qstring.cpp
+ friend Q_CORE_EXPORT bool
+ comparesEqual(const QByteArrayView &lhs, const QChar &rhs) noexcept;
+ friend Q_CORE_EXPORT Qt::strong_ordering
+ compareThreeWay(const QByteArrayView &lhs, const QChar &rhs) noexcept;
+ friend Q_CORE_EXPORT bool
+ comparesEqual(const QByteArrayView &lhs, char16_t rhs) noexcept;
+ friend Q_CORE_EXPORT Qt::strong_ordering
+ compareThreeWay(const QByteArrayView &lhs, char16_t rhs) noexcept;
+#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
+ Q_DECLARE_STRONGLY_ORDERED(QByteArrayView, QChar, QT_ASCII_CAST_WARN)
+ Q_DECLARE_STRONGLY_ORDERED(QByteArrayView, char16_t, QT_ASCII_CAST_WARN)
+#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
+
qsizetype m_size;
const storage_type *m_data;
};
@@ -333,7 +372,7 @@ Q_DECLARE_TYPEINFO(QByteArrayView, Q_PRIMITIVE_TYPE);
template<typename QByteArrayLike,
std::enable_if_t<std::is_same_v<QByteArrayLike, QByteArray>, bool> = true>
[[nodiscard]] inline QByteArrayView qToByteArrayViewIgnoringNull(const QByteArrayLike &b) noexcept
-{ return QByteArrayView(b.data(), b.size()); }
+{ return QByteArrayView(b.begin(), b.size()); }
inline int QByteArrayView::compare(QByteArrayView a, Qt::CaseSensitivity cs) const noexcept
{
@@ -348,6 +387,20 @@ inline quint16 qChecksum(const char *s, qsizetype len,
{ return qChecksum(QByteArrayView(s, len), standard); }
#endif
+qsizetype QtPrivate::findByteArray(QByteArrayView haystack, qsizetype from, char needle) noexcept
+{
+ if (from < 0)
+ from = qMax(from + haystack.size(), qsizetype(0));
+ if (from < haystack.size()) {
+ const char *const b = haystack.data();
+ if (const auto n = static_cast<const char *>(
+ memchr(b + from, needle, static_cast<size_t>(haystack.size() - from)))) {
+ return n - b;
+ }
+ }
+ return -1;
+}
+
QT_END_NAMESPACE
#endif // QBYTEARRAYVIEW_H
diff --git a/src/corelib/text/qbytearrayview.qdoc b/src/corelib/text/qbytearrayview.qdoc
index 48013f8661..eb890917eb 100644
--- a/src/corelib/text/qbytearrayview.qdoc
+++ b/src/corelib/text/qbytearrayview.qdoc
@@ -14,6 +14,15 @@
\reentrant
+ \compares strong
+ \compareswith strong QByteArray {const char *}
+ \endcompareswith
+ \compareswith strong QString QStringView QUtf8StringView QLatin1StringView \
+ QChar char16_t
+ When comparing with string and Unicode character types, the content is
+ interpreted as UTF-8.
+ \endcompareswith
+
A QByteArrayView references a contiguous portion of raw bytes it does
not own. It acts as an interface type to all kinds of byte-array-like data,
without the need to construct a QByteArray first.
@@ -184,7 +193,7 @@
*/
/*!
- \fn template <typename Byte> QByteArrayView::QByteArrayView(const Byte *data, qsizetype len)
+ \fn template <typename Byte, QByteArrayView::if_compatible_byte<Byte> = true> QByteArrayView::QByteArrayView(const Byte *data, qsizetype len)
Constructs a byte array view on \a data with length \a len.
@@ -202,7 +211,7 @@
*/
/*!
- \fn template <typename Byte> QByteArrayView::QByteArrayView(const Byte *first, const Byte *last)
+ \fn template <typename Byte, QByteArrayView::if_compatible_byte<Byte> = true> QByteArrayView::QByteArrayView(const Byte *first, const Byte *last)
Constructs a byte array view on \a first with length (\a last - \a first).
@@ -270,7 +279,7 @@
*/
/*!
- \fn template <typename Container> QByteArrayView::QByteArrayView(const Container &c)
+ \fn template <typename Container, QByteArrayView::if_compatible_container<Container> = true> QByteArrayView::QByteArrayView(const Container &c)
Constructs a byte array view on the array-like container \a c. The length and data
are set via \c{std::size(c)} and \c{std::data(c)} respectively.
@@ -332,12 +341,12 @@
*/
/*! //! friend
- \fn int QByteArrayView::operator==(QByteArrayView lhs, QByteArrayView rhs)
- \fn int QByteArrayView::operator!=(QByteArrayView lhs, QByteArrayView rhs)
- \fn int QByteArrayView::operator< (QByteArrayView lhs, QByteArrayView rhs)
- \fn int QByteArrayView::operator<=(QByteArrayView lhs, QByteArrayView rhs)
- \fn int QByteArrayView::operator> (QByteArrayView lhs, QByteArrayView rhs)
- \fn int QByteArrayView::operator>=(QByteArrayView lhs, QByteArrayView rhs)
+ \fn int QByteArrayView::operator==(const QByteArrayView &lhs, const QByteArrayView &rhs)
+ \fn int QByteArrayView::operator!=(const QByteArrayView &lhs, const QByteArrayView &rhs)
+ \fn int QByteArrayView::operator< (const QByteArrayView &lhs, const QByteArrayView &rhs)
+ \fn int QByteArrayView::operator<=(const QByteArrayView &lhs, const QByteArrayView &rhs)
+ \fn int QByteArrayView::operator> (const QByteArrayView &lhs, const QByteArrayView &rhs)
+ \fn int QByteArrayView::operator>=(const QByteArrayView &lhs, const QByteArrayView &rhs)
Comparison operators for QByteArrayView.
*/
@@ -562,8 +571,10 @@
Returns a byte array view that points to \a n bytes of this byte array
view, starting at position \a pos.
+//! [UB-sliced-index-length]
\note The behavior is undefined when \a pos < 0, \a n < 0,
or \a pos + \a n > size().
+//! [UB-sliced-index-length]
\sa first(), last(), chopped(), chop(), truncate()
*/
@@ -574,7 +585,9 @@
Returns a byte array view starting at position \a pos in this object,
and extending to its end.
+//! [UB-sliced-index-only]
\note The behavior is undefined when \a pos < 0 or \a pos > size().
+//! [UB-sliced-index-only]
\sa first(), last(), chopped(), chop(), truncate()
*/
@@ -1032,3 +1045,12 @@
\sa QByteArray::isNull(), QByteArrayView
*/
+
+/*!
+ \fn QByteArrayView::operator std::string_view() const
+ \since 6.7
+
+ Converts this QByteArrayView object to a \c{std::string_view} object.
+ The returned view will have the same data pointer and length of
+ this view.
+*/
diff --git a/src/corelib/text/qchar.cpp b/src/corelib/text/qchar.cpp
index 4175b6c849..63296a92de 100644
--- a/src/corelib/text/qchar.cpp
+++ b/src/corelib/text/qchar.cpp
@@ -1,14 +1,6 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-// Don't define it while compiling this module, or USERS of Qt will
-// not be able to link.
-#ifdef QT_NO_CAST_FROM_ASCII
-# undef QT_NO_CAST_FROM_ASCII
-#endif
-#ifdef QT_NO_CAST_TO_ASCII
-# undef QT_NO_CAST_TO_ASCII
-#endif
#include "qchar.h"
#include "qdatastream.h"
@@ -63,6 +55,13 @@ QT_BEGIN_NAMESPACE
\ingroup string-processing
\reentrant
+ \compares strong
+ \compareswith strong char16_t QString QStringView QLatin1StringView QUtf8StringView
+ \endcompareswith
+ \compareswith strong {const char *} QByteArray QByteArrayView
+ The contents of the byte array is interpreted as utf-8.
+ \endcompareswith
+
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
@@ -165,6 +164,7 @@ QT_BEGIN_NAMESPACE
\value [since 5.15] Unicode_13_0 Version 13.0
\value [since 6.3] Unicode_14_0 Version 14.0
\value [since 6.5] Unicode_15_0 Version 15.0
+ \value [since 6.8] Unicode_15_1 Version 15.1
\value Unicode_Unassigned The value is not assigned to any character
in version 8.0 of Unicode.
@@ -1747,42 +1747,42 @@ QDataStream &operator>>(QDataStream &in, QChar &chr)
*****************************************************************************/
/*!
- \fn bool QChar::operator==(QChar c1, QChar c2)
+ \fn bool QChar::operator==(const QChar &c1, const QChar &c2)
Returns \c true if \a c1 and \a c2 are the same Unicode character;
otherwise returns \c false.
*/
/*!
- \fn int QChar::operator!=(QChar c1, QChar c2)
+ \fn bool QChar::operator!=(const QChar &c1, const QChar &c2)
Returns \c true if \a c1 and \a c2 are not the same Unicode
character; otherwise returns \c false.
*/
/*!
- \fn int QChar::operator<=(QChar c1, QChar c2)
+ \fn bool QChar::operator<=(const QChar &c1, const QChar &c2)
Returns \c true if the numeric Unicode value of \a c1 is less than
or equal to that of \a c2; otherwise returns \c false.
*/
/*!
- \fn int QChar::operator>=(QChar c1, QChar c2)
+ \fn bool QChar::operator>=(const QChar &c1, const QChar &c2)
Returns \c true if the numeric Unicode value of \a c1 is greater than
or equal to that of \a c2; otherwise returns \c false.
*/
/*!
- \fn int QChar::operator<(QChar c1, QChar c2)
+ \fn bool QChar::operator<(const QChar &c1, const QChar &c2)
Returns \c true if the numeric Unicode value of \a c1 is less than
that of \a c2; otherwise returns \c false.
*/
/*!
- \fn int QChar::operator>(QChar c1, QChar c2)
+ \fn bool QChar::operator>(const QChar &c1, const QChar &c2)
Returns \c true if the numeric Unicode value of \a c1 is greater than
that of \a c2; otherwise returns \c false.
diff --git a/src/corelib/text/qchar.h b/src/corelib/text/qchar.h
index e9f0cf3346..c0c53664c2 100644
--- a/src/corelib/text/qchar.h
+++ b/src/corelib/text/qchar.h
@@ -5,6 +5,7 @@
#define QCHAR_H
#include <QtCore/qglobal.h>
+#include <QtCore/qcompare.h>
#include <functional> // for std::hash
@@ -20,32 +21,27 @@ public:
constexpr inline char toLatin1() const noexcept { return ch; }
constexpr inline char16_t unicode() const noexcept { return char16_t(uchar(ch)); }
- friend constexpr inline bool operator==(QLatin1Char lhs, QLatin1Char rhs) noexcept { return lhs.ch == rhs.ch; }
- friend constexpr inline bool operator!=(QLatin1Char lhs, QLatin1Char rhs) noexcept { return lhs.ch != rhs.ch; }
- friend constexpr inline bool operator<=(QLatin1Char lhs, QLatin1Char rhs) noexcept { return lhs.ch <= rhs.ch; }
- friend constexpr inline bool operator>=(QLatin1Char lhs, QLatin1Char rhs) noexcept { return lhs.ch >= rhs.ch; }
- friend constexpr inline bool operator< (QLatin1Char lhs, QLatin1Char rhs) noexcept { return lhs.ch < rhs.ch; }
- friend constexpr inline bool operator> (QLatin1Char lhs, QLatin1Char rhs) noexcept { return lhs.ch > rhs.ch; }
-
- friend constexpr inline bool operator==(char lhs, QLatin1Char rhs) noexcept { return lhs == rhs.toLatin1(); }
- friend constexpr inline bool operator!=(char lhs, QLatin1Char rhs) noexcept { return lhs != rhs.toLatin1(); }
- friend constexpr inline bool operator<=(char lhs, QLatin1Char rhs) noexcept { return lhs <= rhs.toLatin1(); }
- friend constexpr inline bool operator>=(char lhs, QLatin1Char rhs) noexcept { return lhs >= rhs.toLatin1(); }
- friend constexpr inline bool operator< (char lhs, QLatin1Char rhs) noexcept { return lhs < rhs.toLatin1(); }
- friend constexpr inline bool operator> (char lhs, QLatin1Char rhs) noexcept { return lhs > rhs.toLatin1(); }
-
- friend constexpr inline bool operator==(QLatin1Char lhs, char rhs) noexcept { return lhs.toLatin1() == rhs; }
- friend constexpr inline bool operator!=(QLatin1Char lhs, char rhs) noexcept { return lhs.toLatin1() != rhs; }
- friend constexpr inline bool operator<=(QLatin1Char lhs, char rhs) noexcept { return lhs.toLatin1() <= rhs; }
- friend constexpr inline bool operator>=(QLatin1Char lhs, char rhs) noexcept { return lhs.toLatin1() >= rhs; }
- friend constexpr inline bool operator< (QLatin1Char lhs, char rhs) noexcept { return lhs.toLatin1() < rhs; }
- friend constexpr inline bool operator> (QLatin1Char lhs, char rhs) noexcept { return lhs.toLatin1() > rhs; }
+ friend constexpr bool
+ comparesEqual(const QLatin1Char &lhs, const QLatin1Char &rhs) noexcept
+ { return lhs.ch == rhs.ch; }
+ friend constexpr Qt::strong_ordering
+ compareThreeWay(const QLatin1Char &lhs, const QLatin1Char &rhs) noexcept
+ { return Qt::compareThreeWay(uchar(lhs.ch), uchar(rhs.ch)); }
+ Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(QLatin1Char)
+
+ friend constexpr bool comparesEqual(const QLatin1Char &lhs, char rhs) noexcept
+ { return lhs.toLatin1() == rhs; }
+ friend constexpr Qt::strong_ordering
+ compareThreeWay(const QLatin1Char &lhs, char rhs) noexcept
+ { return Qt::compareThreeWay(uchar(lhs.toLatin1()), uchar(rhs)); }
+ Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(QLatin1Char, char)
private:
char ch;
};
-class Q_CORE_EXPORT QChar {
+#define QT_CHAR_FASTCALL QT7_ONLY(Q_CORE_EXPORT) QT_FASTCALL
+class QT6_ONLY(Q_CORE_EXPORT) QChar {
public:
enum SpecialCharacter {
Null = 0x0000,
@@ -431,6 +427,7 @@ public:
Unicode_13_0,
Unicode_14_0,
Unicode_15_0,
+ Unicode_15_1,
};
inline Category category() const noexcept { return QChar::category(ucs); }
@@ -524,39 +521,39 @@ public:
return char16_t(ucs4%0x400 + 0xdc00);
}
- static Category QT_FASTCALL category(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
- static Direction QT_FASTCALL direction(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
- static JoiningType QT_FASTCALL joiningType(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
- static unsigned char QT_FASTCALL combiningClass(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static Category QT_CHAR_FASTCALL category(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static Direction QT_CHAR_FASTCALL direction(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static JoiningType QT_CHAR_FASTCALL joiningType(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static unsigned char QT_CHAR_FASTCALL combiningClass(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
- static char32_t QT_FASTCALL mirroredChar(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
- static bool QT_FASTCALL hasMirrored(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static char32_t QT_CHAR_FASTCALL mirroredChar(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static bool QT_CHAR_FASTCALL hasMirrored(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
- static QString QT_FASTCALL decomposition(char32_t ucs4);
- static Decomposition QT_FASTCALL decompositionTag(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static QString QT_CHAR_FASTCALL decomposition(char32_t ucs4);
+ static Decomposition QT_CHAR_FASTCALL decompositionTag(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
- static int QT_FASTCALL digitValue(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
- static char32_t QT_FASTCALL toLower(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
- static char32_t QT_FASTCALL toUpper(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
- static char32_t QT_FASTCALL toTitleCase(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
- static char32_t QT_FASTCALL toCaseFolded(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static int QT_CHAR_FASTCALL digitValue(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static char32_t QT_CHAR_FASTCALL toLower(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static char32_t QT_CHAR_FASTCALL toUpper(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static char32_t QT_CHAR_FASTCALL toTitleCase(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static char32_t QT_CHAR_FASTCALL toCaseFolded(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
- static Script QT_FASTCALL script(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static Script QT_CHAR_FASTCALL script(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
- static UnicodeVersion QT_FASTCALL unicodeVersion(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static UnicodeVersion QT_CHAR_FASTCALL unicodeVersion(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
- static UnicodeVersion QT_FASTCALL currentUnicodeVersion() noexcept Q_DECL_CONST_FUNCTION;
+ static UnicodeVersion QT_CHAR_FASTCALL currentUnicodeVersion() noexcept Q_DECL_CONST_FUNCTION;
- static bool QT_FASTCALL isPrint(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static bool QT_CHAR_FASTCALL isPrint(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
static constexpr inline bool isSpace(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION
{
// note that [0x09..0x0d] + 0x85 are exceptional Cc-s and must be handled explicitly
return ucs4 == 0x20 || (ucs4 <= 0x0d && ucs4 >= 0x09)
|| (ucs4 > 127 && (ucs4 == 0x85 || ucs4 == 0xa0 || QChar::isSpace_helper(ucs4)));
}
- static bool QT_FASTCALL isMark(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
- static bool QT_FASTCALL isPunct(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
- static bool QT_FASTCALL isSymbol(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static bool QT_CHAR_FASTCALL isMark(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static bool QT_CHAR_FASTCALL isPunct(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static bool QT_CHAR_FASTCALL isSymbol(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
static constexpr inline bool isLetter(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION
{
return (ucs4 >= 'A' && ucs4 <= 'z' && (ucs4 >= 'a' || ucs4 <= 'Z'))
@@ -579,34 +576,44 @@ public:
static constexpr inline bool isTitleCase(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION
{ return ucs4 > 127 && QChar::category(ucs4) == Letter_Titlecase; }
- friend constexpr inline bool operator==(QChar c1, QChar c2) noexcept { return c1.ucs == c2.ucs; }
- friend constexpr inline bool operator< (QChar c1, QChar c2) noexcept { return c1.ucs < c2.ucs; }
+ friend constexpr bool comparesEqual(const QChar &lhs, const QChar &rhs) noexcept
+ { return lhs.ucs == rhs.ucs; }
+ friend constexpr Qt::strong_ordering
+ compareThreeWay(const QChar &lhs, const QChar &rhs) noexcept
+ { return Qt::compareThreeWay(lhs.ucs, rhs.ucs); }
+ Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(QChar)
- friend constexpr inline bool operator!=(QChar c1, QChar c2) noexcept { return !operator==(c1, c2); }
- friend constexpr inline bool operator>=(QChar c1, QChar c2) noexcept { return !operator< (c1, c2); }
- friend constexpr inline bool operator> (QChar c1, QChar c2) noexcept { return operator< (c2, c1); }
- friend constexpr inline bool operator<=(QChar c1, QChar c2) noexcept { return !operator< (c2, c1); }
-
- friend constexpr inline bool operator==(QChar lhs, std::nullptr_t) noexcept { return lhs.isNull(); }
- friend constexpr inline bool operator< (QChar, std::nullptr_t) noexcept { return false; }
- friend constexpr inline bool operator==(std::nullptr_t, QChar rhs) noexcept { return rhs.isNull(); }
- friend constexpr inline bool operator< (std::nullptr_t, QChar rhs) noexcept { return !rhs.isNull(); }
-
- friend constexpr inline bool operator!=(QChar lhs, std::nullptr_t) noexcept { return !operator==(lhs, nullptr); }
- friend constexpr inline bool operator>=(QChar lhs, std::nullptr_t) noexcept { return !operator< (lhs, nullptr); }
- friend constexpr inline bool operator> (QChar lhs, std::nullptr_t) noexcept { return operator< (nullptr, lhs); }
- friend constexpr inline bool operator<=(QChar lhs, std::nullptr_t) noexcept { return !operator< (nullptr, lhs); }
-
- friend constexpr inline bool operator!=(std::nullptr_t, QChar rhs) noexcept { return !operator==(nullptr, rhs); }
- friend constexpr inline bool operator>=(std::nullptr_t, QChar rhs) noexcept { return !operator< (nullptr, rhs); }
- friend constexpr inline bool operator> (std::nullptr_t, QChar rhs) noexcept { return operator< (rhs, nullptr); }
- friend constexpr inline bool operator<=(std::nullptr_t, QChar rhs) noexcept { return !operator< (rhs, nullptr); }
+ friend constexpr bool comparesEqual(const QChar &lhs, std::nullptr_t) noexcept
+ { return lhs.isNull(); }
+ friend constexpr Qt::strong_ordering
+ compareThreeWay(const QChar &lhs, std::nullptr_t) noexcept
+ { return lhs.isNull() ? Qt::strong_ordering::equivalent : Qt::strong_ordering::greater; }
+ Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(QChar, std::nullptr_t)
private:
- static bool QT_FASTCALL isSpace_helper(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
- static bool QT_FASTCALL isLetter_helper(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
- static bool QT_FASTCALL isNumber_helper(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
- static bool QT_FASTCALL isLetterOrNumber_helper(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static bool QT_CHAR_FASTCALL isSpace_helper(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static bool QT_CHAR_FASTCALL isLetter_helper(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static bool QT_CHAR_FASTCALL isNumber_helper(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+ static bool QT_CHAR_FASTCALL isLetterOrNumber_helper(char32_t ucs4) noexcept Q_DECL_CONST_FUNCTION;
+
+ // defined in qstring.cpp, because we need to go via QUtf8StringView
+ static bool QT_CHAR_FASTCALL
+ equal_helper(QChar lhs, const char *rhs) noexcept Q_DECL_CONST_FUNCTION;
+ static int QT_CHAR_FASTCALL
+ compare_helper(QChar lhs, const char *rhs) noexcept Q_DECL_CONST_FUNCTION;
+
+#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
+ Q_WEAK_OVERLOAD
+ friend bool comparesEqual(const QChar &lhs, const char *rhs) noexcept
+ { return equal_helper(lhs, rhs); }
+ Q_WEAK_OVERLOAD
+ friend Qt::strong_ordering compareThreeWay(const QChar &lhs, const char *rhs) noexcept
+ {
+ const int res = compare_helper(lhs, rhs);
+ return Qt::compareThreeWay(res, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QChar, const char *, Q_WEAK_OVERLOAD QT_ASCII_CAST_WARN)
+#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
#ifdef QT_NO_CAST_FROM_ASCII
QChar(char c) = delete;
@@ -615,6 +622,7 @@ private:
char16_t ucs;
};
+#undef QT_CHAR_FASTCALL
Q_DECLARE_TYPEINFO(QChar, Q_PRIMITIVE_TYPE);
@@ -627,7 +635,7 @@ namespace Qt {
inline namespace Literals {
inline namespace StringLiterals {
-constexpr inline QLatin1Char operator"" _L1(char ch) noexcept
+constexpr inline QLatin1Char operator""_L1(char ch) noexcept
{
return QLatin1Char(ch);
}
diff --git a/src/corelib/text/qcollator.cpp b/src/corelib/text/qcollator.cpp
index d753a05404..1f7e7459e7 100644
--- a/src/corelib/text/qcollator.cpp
+++ b/src/corelib/text/qcollator.cpp
@@ -11,6 +11,7 @@
#include "qthreadstorage.h"
QT_BEGIN_NAMESPACE
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QCollatorSortKeyPrivate)
namespace {
struct GenerationalCollator
@@ -57,9 +58,25 @@ Q_GLOBAL_STATIC(QThreadStorage<GenerationalCollator>, defaultCollator)
In addition to the locale, several optional flags can be set that influence
the result of the collation.
- \note On Linux, Qt is normally compiled to use ICU. When it isn't, all
- options are ignored and the only supported locales are the system default
- (that \c{setlocale(LC_COLLATE, nullptr)} would report) and the "C" locale.
+ \section1 POSIX fallback implementation
+
+ On Unix systems, Qt is normally compiled to use ICU (except for \macos,
+ where Qt defaults to using an equivalent Apple API). However, if ICU was
+ not available at compile time or explicitly disabled, Qt will use a
+ fallback backend that uses the POSIX API only. This backend has several
+ limitations:
+
+ \list
+ \li Only the QLocale::c() and QLocale::system() locales are supported.
+ Consult the POSIX and C Standard Library manuals for the
+ \c{<locale.h>} header for more information on the system locale.
+ \li caseSensitivity() is not supported: only case-sensitive collation
+ can be performed.
+ \li numericMode() and ignorePunctuation() are not supported.
+ \endlist
+
+ The use of any of the unsupported options will cause a warning to be
+ printed to the application's output.
*/
/*!
@@ -134,19 +151,19 @@ QCollator &QCollator::operator=(const QCollator &other)
Move constructor. Moves from \a other into this collator.
- Note that a moved-from QCollator can only be destroyed or assigned to.
- The effect of calling other functions than the destructor or one of the
- assignment operators is undefined.
+//! [partially-formed]
+ \note The moved-from object \a other is placed in a partially-formed state,
+ in which the only valid operations are destruction and assignment of a new
+ value.
+//! [partially-formed]
*/
/*!
\fn QCollator & QCollator::operator=(QCollator && other)
- Move-assigns from \a other to this collator.
+ Move-assigns \a other to this QCollator instance.
- Note that a moved-from QCollator can only be destroyed or assigned to.
- The effect of calling other functions than the destructor or one of the
- assignment operators is undefined.
+ \include qcollator.cpp partially-formed
*/
/*!
@@ -301,8 +318,8 @@ bool QCollator::ignorePunctuation() const
Compares \a s1 with \a s2.
- Returns an integer less than, equal to, or greater than zero depending on
- whether \a s1 sorts before, with or after \a s2.
+ Returns a negative integer if \a s1 is less than \a s2, a positive integer
+ if it is greater than \a s2, and zero if they are equal.
*/
/*!
@@ -325,8 +342,9 @@ bool QCollator::ignorePunctuation() const
Compares \a s1 with \a s2. \a len1 and \a len2 specify the lengths of the
QChar arrays pointed to by \a s1 and \a s2.
- Returns an integer less than, equal to, or greater than zero depending on
- whether \a s1 sorts before, with or after \a s2.
+ Returns a negative integer if \a s1 is less than \a s2, a positive integer
+ if it is greater than \a s2, and zero if they are equal.
+
\note In Qt versions prior to 6.4, the length arguments were of type
\c{int}, not \c{qsizetype}.
@@ -407,6 +425,14 @@ QCollatorSortKey::QCollatorSortKey(const QCollatorSortKey &other)
}
/*!
+ \since 6.8
+ \fn QCollatorSortKey::QCollatorSortKey(QCollatorSortKey &&other)
+ Move-constructs a new QCollatorSortKey from \a other.
+
+ \include qcollator.cpp partially-formed
+*/
+
+/*!
Destroys the collator key.
*/
QCollatorSortKey::~QCollatorSortKey()
@@ -427,7 +453,9 @@ QCollatorSortKey& QCollatorSortKey::operator=(const QCollatorSortKey &other)
/*!
\fn QCollatorSortKey &QCollatorSortKey::operator=(QCollatorSortKey && other)
- Move-assigns \a other to this collator key.
+ Move-assigns \a other to this QCollatorSortKey instance.
+
+ \include qcollator.cpp partially-formed
*/
/*!
diff --git a/src/corelib/text/qcollator.h b/src/corelib/text/qcollator.h
index 6f4882989b..9f61cfc22a 100644
--- a/src/corelib/text/qcollator.h
+++ b/src/corelib/text/qcollator.h
@@ -13,12 +13,14 @@ QT_BEGIN_NAMESPACE
class QCollatorPrivate;
class QCollatorSortKeyPrivate;
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QCollatorSortKeyPrivate, Q_CORE_EXPORT)
class Q_CORE_EXPORT QCollatorSortKey
{
friend class QCollator;
public:
QCollatorSortKey(const QCollatorSortKey &other);
+ QCollatorSortKey(QCollatorSortKey &&other) noexcept = default;
~QCollatorSortKey();
QCollatorSortKey &operator=(const QCollatorSortKey &other);
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QCollatorSortKey)
diff --git a/src/corelib/text/qlatin1stringmatcher.cpp b/src/corelib/text/qlatin1stringmatcher.cpp
index e23b4f20f3..68bf97db5c 100644
--- a/src/corelib/text/qlatin1stringmatcher.cpp
+++ b/src/corelib/text/qlatin1stringmatcher.cpp
@@ -162,8 +162,11 @@ qsizetype QLatin1StringMatcher::indexIn(QLatin1StringView haystack, qsizetype fr
{
if (m_pattern.isEmpty() && from == haystack.size())
return from;
+ if (from < 0) // Historical behavior (see QString::indexOf and co.)
+ from += haystack.size();
if (from >= haystack.size())
return -1;
+
auto begin = haystack.begin() + from;
auto end = haystack.end();
auto found = begin;
diff --git a/src/corelib/text/qlatin1stringview.h b/src/corelib/text/qlatin1stringview.h
index 6b6c306b69..91392d9540 100644
--- a/src/corelib/text/qlatin1stringview.h
+++ b/src/corelib/text/qlatin1stringview.h
@@ -8,6 +8,7 @@
#define QLATIN1STRINGVIEW_H
#include <QtCore/qchar.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qnamespace.h>
#include <QtCore/qtversionchecks.h>
#include <QtCore/qstringview.h>
@@ -182,6 +183,8 @@ public:
}
using value_type = const char;
+ using pointer = value_type*;
+ using const_pointer = pointer;
using reference = value_type&;
using const_reference = reference;
using iterator = value_type*;
@@ -223,20 +226,20 @@ public:
}
[[nodiscard]] constexpr QLatin1StringView sliced(qsizetype pos) const
- { verify(pos); return {m_data + pos, m_size - pos}; }
+ { verify(pos, 0); return {m_data + pos, m_size - pos}; }
[[nodiscard]] constexpr QLatin1StringView sliced(qsizetype pos, qsizetype n) const
{ verify(pos, n); return {m_data + pos, n}; }
[[nodiscard]] constexpr QLatin1StringView first(qsizetype n) const
- { verify(n); return {m_data, n}; }
+ { verify(0, n); return sliced(0, n); }
[[nodiscard]] constexpr QLatin1StringView last(qsizetype n) const
- { verify(n); return {m_data + size() - n, n}; }
+ { verify(0, n); return sliced(size() - n, n); }
[[nodiscard]] constexpr QLatin1StringView chopped(qsizetype n) const
- { verify(n); return {m_data, size() - n}; }
+ { verify(0, n); return sliced(0, size() - n); }
constexpr void chop(qsizetype n)
- { verify(n); m_size -= n; }
+ { verify(0, n); m_size -= n; }
constexpr void truncate(qsizetype n)
- { verify(n); m_size = n; }
+ { verify(0, n); m_size = n; }
[[nodiscard]] QLatin1StringView trimmed() const noexcept { return QtPrivate::trimmed(*this); }
@@ -247,90 +250,88 @@ public:
-> decltype(qTokenize(*this, std::forward<Needle>(needle), flags...))
{ return qTokenize(*this, std::forward<Needle>(needle), flags...); }
- friend bool operator==(QLatin1StringView s1, QLatin1StringView s2) noexcept
- { return QByteArrayView(s1) == QByteArrayView(s2); }
- friend bool operator!=(QLatin1StringView s1, QLatin1StringView s2) noexcept
- { return !(s1 == s2); }
- friend bool operator<(QLatin1StringView s1, QLatin1StringView s2) noexcept
+ friend bool comparesEqual(const QLatin1StringView &s1, const QLatin1StringView &s2) noexcept
+ { return s1.size() == s2.size() && QtPrivate::equalStrings(s1, s2); }
+ friend Qt::strong_ordering
+ compareThreeWay(const QLatin1StringView &s1, const QLatin1StringView &s2) noexcept
{
- const qsizetype len = qMin(s1.size(), s2.size());
- const int r = len ? memcmp(s1.latin1(), s2.latin1(), len) : 0;
- return r < 0 || (r == 0 && s1.size() < s2.size());
+ const int res = QtPrivate::compareStrings(s1, s2);
+ return Qt::compareThreeWay(res, 0);
}
- friend bool operator>(QLatin1StringView s1, QLatin1StringView s2) noexcept
- { return s2 < s1; }
- friend bool operator<=(QLatin1StringView s1, QLatin1StringView s2) noexcept
- { return !(s1 > s2); }
- friend bool operator>=(QLatin1StringView s1, QLatin1StringView s2) noexcept
- { return !(s1 < s2); }
+ Q_DECLARE_STRONGLY_ORDERED(QLatin1StringView)
// QChar <> QLatin1StringView
- friend bool operator==(QChar lhs, QLatin1StringView rhs) noexcept { return rhs.size() == 1 && lhs == rhs.front(); }
- friend bool operator< (QChar lhs, QLatin1StringView rhs) noexcept { return compare_helper(&lhs, 1, rhs) < 0; }
- friend bool operator> (QChar lhs, QLatin1StringView rhs) noexcept { return compare_helper(&lhs, 1, rhs) > 0; }
- friend bool operator!=(QChar lhs, QLatin1StringView rhs) noexcept { return !(lhs == rhs); }
- friend bool operator<=(QChar lhs, QLatin1StringView rhs) noexcept { return !(lhs > rhs); }
- friend bool operator>=(QChar lhs, QLatin1StringView rhs) noexcept { return !(lhs < rhs); }
-
- friend bool operator==(QLatin1StringView lhs, QChar rhs) noexcept { return rhs == lhs; }
- friend bool operator!=(QLatin1StringView lhs, QChar rhs) noexcept { return !(rhs == lhs); }
- friend bool operator< (QLatin1StringView lhs, QChar rhs) noexcept { return rhs > lhs; }
- friend bool operator> (QLatin1StringView lhs, QChar rhs) noexcept { return rhs < lhs; }
- friend bool operator<=(QLatin1StringView lhs, QChar rhs) noexcept { return !(rhs < lhs); }
- friend bool operator>=(QLatin1StringView lhs, QChar rhs) noexcept { return !(rhs > lhs); }
+ friend bool comparesEqual(const QLatin1StringView &lhs, QChar rhs) noexcept
+ { return lhs.size() == 1 && rhs == lhs.front(); }
+ friend Qt::strong_ordering
+ compareThreeWay(const QLatin1StringView &lhs, QChar rhs) noexcept
+ {
+ // negate, as the helper function expects QChar as lhs
+ const int res = -compare_helper(&rhs, 1, lhs);
+ return Qt::compareThreeWay(res, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QLatin1StringView, QChar)
// QStringView <> QLatin1StringView
- friend bool operator==(QStringView lhs, QLatin1StringView rhs) noexcept
+ friend bool comparesEqual(const QLatin1StringView &lhs, const QStringView &rhs) noexcept
{ return lhs.size() == rhs.size() && QtPrivate::equalStrings(lhs, rhs); }
- friend bool operator!=(QStringView lhs, QLatin1StringView rhs) noexcept { return !(lhs == rhs); }
- friend bool operator< (QStringView lhs, QLatin1StringView rhs) noexcept { return QtPrivate::compareStrings(lhs, rhs) < 0; }
- friend bool operator<=(QStringView lhs, QLatin1StringView rhs) noexcept { return QtPrivate::compareStrings(lhs, rhs) <= 0; }
- friend bool operator> (QStringView lhs, QLatin1StringView rhs) noexcept { return QtPrivate::compareStrings(lhs, rhs) > 0; }
- friend bool operator>=(QStringView lhs, QLatin1StringView rhs) noexcept { return QtPrivate::compareStrings(lhs, rhs) >= 0; }
+ friend Qt::strong_ordering
+ compareThreeWay(const QLatin1StringView &lhs, const QStringView &rhs) noexcept
+ {
+ const int res = QtPrivate::compareStrings(lhs, rhs);
+ return Qt::compareThreeWay(res, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QLatin1StringView, QStringView)
+
+ // Reversed helper methods for QStringView <> QLatin1StringView comparison.
+ // If we do not provide them explicitly, QStringView <> QByteArrayView
+ // overloads will be selected, which will provide wrong results, because
+ // they will convert from utf-8
+ friend bool comparesEqual(const QStringView &lhs, const QLatin1StringView &rhs) noexcept
+ { return comparesEqual(rhs, lhs); }
+ friend Qt::strong_ordering
+ compareThreeWay(const QStringView &lhs, const QLatin1StringView &rhs) noexcept
+ { return QtOrderingPrivate::reversed(compareThreeWay(rhs, lhs)); }
- friend bool operator==(QLatin1StringView lhs, QStringView rhs) noexcept
- { return lhs.size() == rhs.size() && QtPrivate::equalStrings(lhs, rhs); }
- friend bool operator!=(QLatin1StringView lhs, QStringView rhs) noexcept { return !(lhs == rhs); }
- friend bool operator< (QLatin1StringView lhs, QStringView rhs) noexcept { return QtPrivate::compareStrings(lhs, rhs) < 0; }
- friend bool operator<=(QLatin1StringView lhs, QStringView rhs) noexcept { return QtPrivate::compareStrings(lhs, rhs) <= 0; }
- friend bool operator> (QLatin1StringView lhs, QStringView rhs) noexcept { return QtPrivate::compareStrings(lhs, rhs) > 0; }
- friend bool operator>=(QLatin1StringView lhs, QStringView rhs) noexcept { return QtPrivate::compareStrings(lhs, rhs) >= 0; }
+private:
+ friend bool comparesEqual(const QLatin1StringView &lhs, const QByteArrayView &rhs) noexcept
+ { return equal_helper(lhs, rhs.data(), rhs.size()); }
+ friend Qt::strong_ordering
+ compareThreeWay(const QLatin1StringView &lhs, const QByteArrayView &rhs) noexcept
+ {
+ const int res = compare_helper(lhs, rhs.data(), rhs.size());
+ return Qt::compareThreeWay(res, 0);
+ }
+ // Reversed helper methods for QByteArrayView <> QLatin1StringView comparison.
+ // If we do not provide them explicitly, QByteArrayView <> QByteArrayView
+ // overloads will be selected, which will provide wrong results
+ friend bool comparesEqual(const QByteArrayView &lhs, const QLatin1StringView &rhs) noexcept
+ { return comparesEqual(rhs, lhs); }
+ friend Qt::strong_ordering
+ compareThreeWay(const QByteArrayView &lhs, const QLatin1StringView &rhs) noexcept
+ { return QtOrderingPrivate::reversed(compareThreeWay(rhs, lhs)); }
+public:
#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
- QT_ASCII_CAST_WARN inline bool operator==(const char *s) const;
- QT_ASCII_CAST_WARN inline bool operator!=(const char *s) const;
- QT_ASCII_CAST_WARN inline bool operator<(const char *s) const;
- QT_ASCII_CAST_WARN inline bool operator>(const char *s) const;
- QT_ASCII_CAST_WARN inline bool operator<=(const char *s) const;
- QT_ASCII_CAST_WARN inline bool operator>=(const char *s) const;
-
- QT_ASCII_CAST_WARN inline bool operator==(const QByteArray &s) const;
- QT_ASCII_CAST_WARN inline bool operator!=(const QByteArray &s) const;
- QT_ASCII_CAST_WARN inline bool operator<(const QByteArray &s) const;
- QT_ASCII_CAST_WARN inline bool operator>(const QByteArray &s) const;
- QT_ASCII_CAST_WARN inline bool operator<=(const QByteArray &s) const;
- QT_ASCII_CAST_WARN inline bool operator>=(const QByteArray &s) const;
-
- QT_ASCII_CAST_WARN friend bool operator==(const char *s1, QLatin1StringView s2) { return compare_helper(s2, s1) == 0; }
- QT_ASCII_CAST_WARN friend bool operator!=(const char *s1, QLatin1StringView s2) { return compare_helper(s2, s1) != 0; }
- QT_ASCII_CAST_WARN friend bool operator< (const char *s1, QLatin1StringView s2) { return compare_helper(s2, s1) > 0; }
- QT_ASCII_CAST_WARN friend bool operator> (const char *s1, QLatin1StringView s2) { return compare_helper(s2, s1) < 0; }
- QT_ASCII_CAST_WARN friend bool operator<=(const char *s1, QLatin1StringView s2) { return compare_helper(s2, s1) >= 0; }
- QT_ASCII_CAST_WARN friend bool operator>=(const char *s1, QLatin1StringView s2) { return compare_helper(s2, s1) <= 0; }
+ Q_DECLARE_STRONGLY_ORDERED(QLatin1StringView, QByteArrayView, QT_ASCII_CAST_WARN)
+ Q_DECLARE_STRONGLY_ORDERED(QLatin1StringView, QByteArray, QT_ASCII_CAST_WARN)
+ Q_DECLARE_STRONGLY_ORDERED(QLatin1StringView, const char *, QT_ASCII_CAST_WARN)
#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
private:
-#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
- static inline int compare_helper(const QLatin1StringView &s1, const char *s2);
-#endif
- Q_ALWAYS_INLINE constexpr void verify(qsizetype pos, qsizetype n = 0) const
+ Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos,
+ [[maybe_unused]] qsizetype n = 1) const
{
Q_ASSERT(pos >= 0);
Q_ASSERT(pos <= size());
Q_ASSERT(n >= 0);
Q_ASSERT(n <= size() - pos);
}
+ static int compare_helper(const QLatin1StringView &s1, const char *s2) noexcept
+ { return compare_helper(s1, s2, qstrlen(s2)); }
+ Q_CORE_EXPORT static bool equal_helper(QLatin1StringView s1, const char *s2, qsizetype len) noexcept;
+ Q_CORE_EXPORT static int compare_helper(const QLatin1StringView &s1, const char *s2, qsizetype len) noexcept;
Q_CORE_EXPORT static int compare_helper(const QChar *data1, qsizetype length1,
QLatin1StringView s2,
Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
@@ -348,11 +349,15 @@ Q_DECLARE_TYPEINFO(QLatin1StringView, Q_RELOCATABLE_TYPE);
Q_DECLARE_TYPEINFO(QLatin1String, Q_RELOCATABLE_TYPE);
#endif
+constexpr QByteArrayView::QByteArrayView(QLatin1StringView v) noexcept
+ : QByteArrayView(v.data(), v.size())
+{}
+
namespace Qt {
inline namespace Literals {
inline namespace StringLiterals {
-constexpr inline QLatin1StringView operator"" _L1(const char *str, size_t size) noexcept
+constexpr inline QLatin1StringView operator""_L1(const char *str, size_t size) noexcept
{
return {str, qsizetype(size)};
}
diff --git a/src/corelib/text/qlatin1stringview.qdoc b/src/corelib/text/qlatin1stringview.qdoc
index 3bd9312232..711057767b 100644
--- a/src/corelib/text/qlatin1stringview.qdoc
+++ b/src/corelib/text/qlatin1stringview.qdoc
@@ -1,7 +1,7 @@
// Copyright (C) 2021 The Qt Company Ltd.
// Copyright (C) 2022 Intel Corporation.
// Copyright (C) 2019 Mail.ru Group.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*! \class QLatin1StringView
\inmodule QtCore
@@ -11,6 +11,14 @@
\ingroup string-processing
\reentrant
+ \compares strong
+ \compareswith strong char16_t QChar QStringView QUtf8StringView QString \
+ {const char16_t *}
+ \endcompareswith
+ \compareswith strong {const char *} QByteArray QByteArrayView
+ The byte array data is interpreted as utf-8.
+ \endcompareswith
+
Many of QString's member functions are overloaded to accept
\c{const char *} instead of QString. This includes the copy
constructor, the assignment operator, the comparison operators,
@@ -103,6 +111,14 @@
*/
/*!
+ \typedef QLatin1StringView::pointer
+ \typedef QLatin1StringView::const_pointer
+ \since 6.7
+
+ Alias for \c{value_type *}. Provided for compatibility with the STL.
+*/
+
+/*!
\typedef QLatin1StringView::reference
\since 5.10
@@ -404,9 +420,10 @@
\fn int QLatin1StringView::compare(QChar ch, Qt::CaseSensitivity cs) const
\since 5.14
- Returns an integer that compares to zero as this string view compares
- to the UTF-16 string viewed by \a str, the Latin-1 string viewed by \a l1,
- or the character \a ch, respectively.
+ Compares this string view with UTF-16 string view \a str, Latin-1 string view \a l1,
+ or the character \a ch, respectively. Returns a negative integer if this
+ string is less than \a str, \a l1 or \a ch, returns a positive integer if it
+ is greater than \a str, \a l1 or \a ch, and zero if they are equal.
\include qstring.qdocinc {search-comparison-case-sensitivity} {search}
@@ -417,8 +434,9 @@
\fn int QLatin1StringView::compare(QUtf8StringView str, Qt::CaseSensitivity cs) const
\since 6.5
- Returns an integer that compares to zero as this string view compares to the
- string view \a str.
+ Compares this string view with \a str and returns a negative integer if
+ this string view is less than \a str, a positive integer if it is greater than
+ \a str, and zero if they are equal.
\include qstring.qdocinc {search-comparison-case-sensitivity} {comparison}
@@ -756,8 +774,10 @@
Returns a Latin-1 string view that points to \a n characters of this
string view, starting at position \a pos.
+//! [UB-sliced-index-length]
\note The behavior is undefined when \a pos < 0, \a n < 0,
or \c{pos + n > size()}.
+//! [UB-sliced-index-length]
\sa first(), last(), chopped(), chop(), truncate()
*/
@@ -769,7 +789,9 @@
Returns a Latin-1 string view starting at position \a pos in this
string view, and extending to its end.
+//! [UB-sliced-index-only]
\note The behavior is undefined when \a pos < 0 or \a pos > size().
+//! [UB-sliced-index-only]
\sa first(), last(), chopped(), chop(), truncate()
*/
@@ -826,14 +848,13 @@
*/
/*!
- \fn bool QLatin1StringView::operator==(const char *other) const
+ \fn bool QLatin1StringView::operator==(const QLatin1StringView &lhs, const char * const &rhs)
\since 4.3
- Returns \c true if the string is equal to const char pointer \a other;
+ Returns \c true if the string \a lhs is equal to const char pointer \a rhs;
otherwise returns \c false.
- The \a other const char pointer is converted to a QString using
- the QString::fromUtf8() function.
+ The \a rhs const char pointer is converted to a QUtf8StringView.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -844,12 +865,11 @@
*/
/*!
- \fn bool QLatin1StringView::operator==(const QByteArray &other) const
+ \fn bool QLatin1StringView::operator==(const QLatin1StringView &lhs, const QByteArray &rhs)
\since 5.0
\overload
- The \a other byte array is converted to a QString using
- the QString::fromUtf8() function.
+ The \a rhs byte array is converted to a QUtf8StringView.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -858,14 +878,13 @@
*/
/*!
- \fn bool QLatin1StringView::operator!=(const char *other) const
+ \fn bool QLatin1StringView::operator!=(const QLatin1StringView &lhs, const char * const &rhs)
\since 4.3
- Returns \c true if this string is not equal to const char pointer \a other;
+ Returns \c true if the string \a lhs is not equal to const char pointer \a rhs;
otherwise returns \c false.
- The \a other const char pointer is converted to a QString using
- the QString::fromUtf8() function.
+ The \a rhs const char pointer is converted to a QUtf8StringView.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -876,12 +895,11 @@
*/
/*!
- \fn bool QLatin1StringView::operator!=(const QByteArray &other) const
+ \fn bool QLatin1StringView::operator!=(const QLatin1StringView &lhs, const QByteArray &rhs)
\since 5.0
\overload operator!=()
- The \a other byte array is converted to a QString using
- the QString::fromUtf8() function.
+ The \a rhs byte array is converted to a QUtf8StringView.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -890,14 +908,13 @@
*/
/*!
- \fn bool QLatin1StringView::operator>(const char *other) const
+ \fn bool QLatin1StringView::operator>(const QLatin1StringView &lhs, const char * const &rhs)
\since 4.3
- Returns \c true if this string is lexically greater than const char pointer
- \a other; otherwise returns \c false.
+ Returns \c true if the string \a lhs is lexically greater than const char pointer
+ \a rhs; otherwise returns \c false.
- The \a other const char pointer is converted to a QString using
- the QString::fromUtf8() function.
+ The \a rhs const char pointer is converted to a QUtf8StringView.
You can disable this operator by defining \l QT_NO_CAST_FROM_ASCII
when you compile your applications. This can be useful if you want
@@ -908,12 +925,11 @@
*/
/*!
- \fn bool QLatin1StringView::operator>(const QByteArray &other) const
+ \fn bool QLatin1StringView::operator>(const QLatin1StringView &lhs, const QByteArray &rhs)
\since 5.0
\overload
- The \a other byte array is converted to a QString using
- the QString::fromUtf8() function.
+ The \a rhs byte array is converted to a QUtf8StringView.
You can disable this operator by defining \l QT_NO_CAST_FROM_ASCII
when you compile your applications. This can be useful if you want
@@ -922,14 +938,13 @@
*/
/*!
- \fn bool QLatin1StringView::operator<(const char *other) const
+ \fn bool QLatin1StringView::operator<(const QLatin1StringView &lhs, const char * const &rhs)
\since 4.3
- Returns \c true if this string is lexically less than const char pointer
- \a other; otherwise returns \c false.
+ Returns \c true if the string \a lhs is lexically less than const char pointer
+ \a rhs; otherwise returns \c false.
- The \a other const char pointer is converted to a QString using
- the QString::fromUtf8() function.
+ The \a rhs const char pointer is converted to a QUtf8StringView.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -940,12 +955,11 @@
*/
/*!
- \fn bool QLatin1StringView::operator<(const QByteArray &other) const
+ \fn bool QLatin1StringView::operator<(const QLatin1StringView &lhs, const QByteArray &rhs)
\since 5.0
\overload
- The \a other byte array is converted to a QString using
- the QString::fromUtf8() function.
+ The \a rhs byte array is converted to a QUtf8StringView.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -954,14 +968,13 @@
*/
/*!
- \fn bool QLatin1StringView::operator>=(const char *other) const
+ \fn bool QLatin1StringView::operator>=(const QLatin1StringView &lhs, const char * const &rhs)
\since 4.3
- Returns \c true if this string is lexically greater than or equal to
- const char pointer \a other; otherwise returns \c false.
+ Returns \c true if the string \a lhs is lexically greater than or equal to
+ const char pointer \a rhs; otherwise returns \c false.
- The \a other const char pointer is converted to a QString using
- the QString::fromUtf8() function.
+ The \a rhs const char pointer is converted to a QUtf8StringView.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -972,12 +985,11 @@
*/
/*!
- \fn bool QLatin1StringView::operator>=(const QByteArray &other) const
+ \fn bool QLatin1StringView::operator>=(const QLatin1StringView &lhs, const QByteArray &rhs)
\since 5.0
\overload
- The \a other byte array is converted to a QString using
- the QString::fromUtf8() function.
+ The \a rhs byte array is converted to a QUtf8StringView.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -986,14 +998,13 @@
*/
/*!
- \fn bool QLatin1StringView::operator<=(const char *other) const
+ \fn bool QLatin1StringView::operator<=(const QLatin1StringView &lhs, const char * const &rhs)
\since 4.3
- Returns \c true if this string is lexically less than or equal to
- const char pointer \a other; otherwise returns \c false.
+ Returns \c true if the string \a lhs is lexically less than or equal to
+ const char pointer \a rhs; otherwise returns \c false.
- The \a other const char pointer is converted to a QString using
- the QString::fromUtf8() function.
+ The \a rhs const char pointer is converted to a QUtf8StringView.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -1004,12 +1015,11 @@
*/
/*!
- \fn bool QLatin1StringView::operator<=(const QByteArray &other) const
+ \fn bool QLatin1StringView::operator<=(const QLatin1StringView &lhs, const QByteArray &rhs)
\since 5.0
\overload
- The \a other byte array is converted to a QString using
- the QString::fromUtf8() function.
+ The \a rhs byte array is converted to a QUtf8StringView.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -1017,189 +1027,189 @@
go through QObject::tr(), for example.
*/
-/*! \fn bool QLatin1StringView::operator==(QLatin1StringView s1, QLatin1StringView s2)
+/*! \fn bool QLatin1StringView::operator==(const QLatin1StringView &lhs, const QLatin1StringView &rhs)
- Returns \c true if string \a s1 is lexically equal to string \a s2;
+ Returns \c true if string \a lhs is lexically equal to string \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator!=(QLatin1StringView s1, QLatin1StringView s2)
+/*! \fn bool QLatin1StringView::operator!=(const QLatin1StringView &lhs, const QLatin1StringView &rhs)
- Returns \c true if string \a s1 is lexically not equal to string \a s2;
+ Returns \c true if string \a lhs is lexically not equal to string \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator<(QLatin1StringView s1, QLatin1StringView s2)
+/*! \fn bool QLatin1StringView::operator<(const QLatin1StringView &lhs, const QLatin1StringView &rhs)
- Returns \c true if string \a s1 is lexically less than string \a s2;
+ Returns \c true if string \a lhs is lexically less than string \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator<=(QLatin1StringView s1, QLatin1StringView s2)
+/*! \fn bool QLatin1StringView::operator<=(const QLatin1StringView &lhs, const QLatin1StringView &rhs)
- Returns \c true if string \a s1 is lexically less than or equal to
- string \a s2; otherwise returns \c false.
+ Returns \c true if string \a lhs is lexically less than or equal to
+ string \a rhs; otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator>(QLatin1StringView s1, QLatin1StringView s2)
+/*! \fn bool QLatin1StringView::operator>(const QLatin1StringView &lhs, const QLatin1StringView &rhs)
- Returns \c true if string \a s1 is lexically greater than string \a s2;
+ Returns \c true if string \a lhs is lexically greater than string \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator>=(QLatin1StringView s1, QLatin1StringView s2)
+/*! \fn bool QLatin1StringView::operator>=(const QLatin1StringView &lhs, const QLatin1StringView &rhs)
- Returns \c true if string \a s1 is lexically greater than or equal
- to string \a s2; otherwise returns \c false.
+ Returns \c true if string \a lhs is lexically greater than or equal
+ to string \a rhs; otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator==(QChar ch, QLatin1StringView s)
+/*! \fn bool QLatin1StringView::operator==(const QChar &lhs, const QLatin1StringView &rhs)
- Returns \c true if char \a ch is lexically equal to string \a s;
+ Returns \c true if char \a lhs is lexically equal to string \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator<(QChar ch, QLatin1StringView s)
+/*! \fn bool QLatin1StringView::operator<(const QChar &lhs, const QLatin1StringView &rhs)
- Returns \c true if char \a ch is lexically less than string \a s;
+ Returns \c true if char \a lhs is lexically less than string \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator>(QChar ch, QLatin1StringView s)
- Returns \c true if char \a ch is lexically greater than string \a s;
+/*! \fn bool QLatin1StringView::operator>(const QChar &lhs, const QLatin1StringView &rhs)
+ Returns \c true if char \a lhs is lexically greater than string \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator!=(QChar ch, QLatin1StringView s)
+/*! \fn bool QLatin1StringView::operator!=(const QChar &lhs, const QLatin1StringView &rhs)
- Returns \c true if char \a ch is lexically not equal to string \a s;
+ Returns \c true if char \a lhs is lexically not equal to string \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator<=(QChar ch, QLatin1StringView s)
+/*! \fn bool QLatin1StringView::operator<=(const QChar &lhs, const QLatin1StringView &rhs)
- Returns \c true if char \a ch is lexically less than or equal to
- string \a s; otherwise returns \c false.
+ Returns \c true if char \a lhs is lexically less than or equal to
+ string \a rhs; otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator>=(QChar ch, QLatin1StringView s)
+/*! \fn bool QLatin1StringView::operator>=(const QChar &lhs, const QLatin1StringView &rhs)
- Returns \c true if char \a ch is lexically greater than or equal to
- string \a s; otherwise returns \c false.
+ Returns \c true if char \a lhs is lexically greater than or equal to
+ string \a rhs; otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator==(QLatin1StringView s, QChar ch)
+/*! \fn bool QLatin1StringView::operator==(const QLatin1StringView &lhs, const QChar &rhs)
- Returns \c true if string \a s is lexically equal to char \a ch;
+ Returns \c true if string \a lhs is lexically equal to char \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator<(QLatin1StringView s, QChar ch)
+/*! \fn bool QLatin1StringView::operator<(const QLatin1StringView &lhs, const QChar &rhs)
- Returns \c true if string \a s is lexically less than char \a ch;
+ Returns \c true if string \a lhs is lexically less than char \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator>(QLatin1StringView s, QChar ch)
+/*! \fn bool QLatin1StringView::operator>(const QLatin1StringView &lhs, const QChar &rhs)
- Returns \c true if string \a s is lexically greater than char \a ch;
+ Returns \c true if string \a lhs is lexically greater than char \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator!=(QLatin1StringView s, QChar ch)
+/*! \fn bool QLatin1StringView::operator!=(const QLatin1StringView &lhs, const QChar &rhs)
- Returns \c true if string \a s is lexically not equal to char \a ch;
+ Returns \c true if string \a lhs is lexically not equal to char \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator<=(QLatin1StringView s, QChar ch)
+/*! \fn bool QLatin1StringView::operator<=(const QLatin1StringView &lhs, const QChar &rhs)
- Returns \c true if string \a s is lexically less than or equal to
- char \a ch; otherwise returns \c false.
+ Returns \c true if string \a lhs is lexically less than or equal to
+ char \a rhs; otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator>=(QLatin1StringView s, QChar ch)
+/*! \fn bool QLatin1StringView::operator>=(const QLatin1StringView &lhs, const QChar &rhs)
- Returns \c true if string \a s is lexically greater than or equal to
- char \a ch; otherwise returns \c false.
+ Returns \c true if string \a lhs is lexically greater than or equal to
+ char \a rhs; otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator==(QStringView s1, QLatin1StringView s2)
+/*! \fn bool QLatin1StringView::operator==(const QStringView &lhs, const QLatin1StringView &rhs)
- Returns \c true if string view \a s1 is lexically equal to string \a s2;
+ Returns \c true if string view \a lhs is lexically equal to string \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator<(QStringView s1, QLatin1StringView s2)
+/*! \fn bool QLatin1StringView::operator<(const QStringView &lhs, const QLatin1StringView &rhs)
- Returns \c true if string view \a s1 is lexically less than string \a s2;
+ Returns \c true if string view \a lhs is lexically less than string \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator>(QStringView s1, QLatin1StringView s2)
+/*! \fn bool QLatin1StringView::operator>(const QStringView &lhs, const QLatin1StringView &rhs)
- Returns \c true if string view \a s1 is lexically greater than string \a s2;
+ Returns \c true if string view \a lhs is lexically greater than string \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator!=(QStringView s1, QLatin1StringView s2)
+/*! \fn bool QLatin1StringView::operator!=(const QStringView &lhs, const QLatin1StringView &rhs)
- Returns \c true if string view \a s1 is lexically not equal to string \a s2;
+ Returns \c true if string view \a lhs is lexically not equal to string \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator<=(QStringView s1, QLatin1StringView s2)
+/*! \fn bool QLatin1StringView::operator<=(const QStringView &lhs, const QLatin1StringView &rhs)
- Returns \c true if string view \a s1 is lexically less than or equal to
- string \a s2; otherwise returns \c false.
+ Returns \c true if string view \a lhs is lexically less than or equal to
+ string \a rhs; otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator>=(QStringView s1, QLatin1StringView s2)
+/*! \fn bool QLatin1StringView::operator>=(const QStringView &lhs, const QLatin1StringView &rhs)
- Returns \c true if string view \a s1 is lexically greater than or equal to
- string \a s2; otherwise returns \c false.
+ Returns \c true if string view \a lhs is lexically greater than or equal to
+ string \a rhs; otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator==(QLatin1StringView s1, QStringView s2)
+/*! \fn bool QLatin1StringView::operator==(const QLatin1StringView &lhs, const QStringView &rhs)
- Returns \c true if string \a s1 is lexically equal to string view \a s2;
+ Returns \c true if string \a lhs is lexically equal to string view \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator<(QLatin1StringView s1, QStringView s2)
+/*! \fn bool QLatin1StringView::operator<(const QLatin1StringView &lhs, const QStringView &rhs)
- Returns \c true if string \a s1 is lexically less than string view \a s2;
+ Returns \c true if string \a lhs is lexically less than string view \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator>(QLatin1StringView s1, QStringView s2)
+/*! \fn bool QLatin1StringView::operator>(const QLatin1StringView &lhs, const QStringView &rhs)
- Returns \c true if string \a s1 is lexically greater than string view \a s2;
+ Returns \c true if string \a lhs is lexically greater than string view \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator!=(QLatin1StringView s1, QStringView s2)
+/*! \fn bool QLatin1StringView::operator!=(const QLatin1StringView &lhs, const QStringView &rhs)
- Returns \c true if string \a s1 is lexically not equal to string view \a s2;
+ Returns \c true if string \a lhs is lexically not equal to string view \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator<=(QLatin1StringView s1, QStringView s2)
+/*! \fn bool QLatin1StringView::operator<=(const QLatin1StringView &lhs, const QStringView &rhs)
- Returns \c true if string \a s1 is lexically less than or equal to
- string view \a s2; otherwise returns \c false.
+ Returns \c true if string \a lhs is lexically less than or equal to
+ string view \a rhs; otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator>=(QLatin1StringView s1, QStringView s2)
+/*! \fn bool QLatin1StringView::operator>=(const QLatin1StringView &lhs, const QStringView &rhs)
- Returns \c true if string \a s1 is lexically greater than or equal to
- string view \a s2; otherwise returns \c false.
+ Returns \c true if string \a lhs is lexically greater than or equal to
+ string view \a rhs; otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator==(const char *s1, QLatin1StringView s2)
+/*! \fn bool QLatin1StringView::operator==(const char * const &lhs, const QLatin1StringView &rhs)
- Returns \c true if const char pointer \a s1 is lexically equal to
- string \a s2; otherwise returns \c false.
+ Returns \c true if const char pointer \a lhs is lexically equal to
+ string \a rhs; otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator<(const char *s1, QLatin1StringView s2)
+/*! \fn bool QLatin1StringView::operator<(const char * const &lhs, const QLatin1StringView &rhs)
- Returns \c true if const char pointer \a s1 is lexically less than
- string \a s2; otherwise returns \c false.
+ Returns \c true if const char pointer \a lhs is lexically less than
+ string \a rhs; otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator>(const char *s1, QLatin1StringView s2)
+/*! \fn bool QLatin1StringView::operator>(const char * const &lhs, const QLatin1StringView &rhs)
- Returns \c true if const char pointer \a s1 is lexically greater than
- string \a s2; otherwise returns \c false.
+ Returns \c true if const char pointer \a lhs is lexically greater than
+ string \a rhs; otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator!=(const char *s1, QLatin1StringView s2)
+/*! \fn bool QLatin1StringView::operator!=(const char * const &lhs, const QLatin1StringView &rhs)
- Returns \c true if const char pointer \a s1 is lexically not equal to
- string \a s2; otherwise returns \c false.
+ Returns \c true if const char pointer \a lhs is lexically not equal to
+ string \a rhs; otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator<=(const char *s1, QLatin1StringView s2)
+/*! \fn bool QLatin1StringView::operator<=(const char * const &lhs, const QLatin1StringView &rhs)
- Returns \c true if const char pointer \a s1 is lexically less than or
- equal to string \a s2; otherwise returns \c false.
+ Returns \c true if const char pointer \a lhs is lexically less than or
+ equal to string \a rhs; otherwise returns \c false.
*/
-/*! \fn bool QLatin1StringView::operator>=(const char *s1, QLatin1StringView s2)
+/*! \fn bool QLatin1StringView::operator>=(const char * const &lhs, const QLatin1StringView &rhs)
- Returns \c true if const char pointer \a s1 is lexically greater than or
- equal to string \a s2; otherwise returns \c false.
+ Returns \c true if const char pointer \a lhs is lexically greater than or
+ equal to string \a rhs; otherwise returns \c false.
*/
/*!
diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp
index f8c98c4c16..ab95b300eb 100644
--- a/src/corelib/text/qlocale.cpp
+++ b/src/corelib/text/qlocale.cpp
@@ -54,6 +54,8 @@ QT_WARNING_DISABLE_GCC("-Wfree-nonheap-object") // false positive tracking
QT_BEGIN_NAMESPACE
+constexpr int QLocale::DefaultTwoDigitBaseYear;
+
QT_IMPL_METATYPE_EXTERN_TAGGED(QList<Qt::DayOfWeek>, QList_Qt__DayOfWeek)
#ifndef QT_NO_SYSTEMLOCALE
QT_IMPL_METATYPE_EXTERN_TAGGED(QSystemLocale::CurrencyToStringArgument,
@@ -109,18 +111,18 @@ QLocale::Language QLocalePrivate::codeToLanguage(QStringView code,
auto searchCode = [codeBuf](auto f) {
return std::find_if(languageCodeList.begin(), languageCodeList.end(),
- [=](const LanguageCodeEntry &i) { return f(i) == codeBuf; });
+ [=](LanguageCodeEntry i) { return f(i) == codeBuf; });
};
if (codeTypes.testFlag(QLocale::ISO639Part1) && uc3 == 0) {
- auto i = searchCode([](const LanguageCodeEntry &i) { return i.part1; });
+ auto i = searchCode([](LanguageCodeEntry i) { return i.part1; });
if (i != languageCodeList.end())
return QLocale::Language(std::distance(languageCodeList.begin(), i));
}
if (uc3 != 0) {
if (codeTypes.testFlag(QLocale::ISO639Part2B)) {
- auto i = searchCode([](const LanguageCodeEntry &i) { return i.part2B; });
+ auto i = searchCode([](LanguageCodeEntry i) { return i.part2B; });
if (i != languageCodeList.end())
return QLocale::Language(std::distance(languageCodeList.begin(), i));
}
@@ -129,13 +131,13 @@ QLocale::Language QLocalePrivate::codeToLanguage(QStringView code,
// This is asserted in iso639_3.LanguageCodeData.
if (codeTypes.testFlag(QLocale::ISO639Part2T)
&& !codeTypes.testFlag(QLocale::ISO639Part3)) {
- auto i = searchCode([](const LanguageCodeEntry &i) { return i.part2T; });
+ auto i = searchCode([](LanguageCodeEntry i) { return i.part2T; });
if (i != languageCodeList.end())
return QLocale::Language(std::distance(languageCodeList.begin(), i));
}
if (codeTypes.testFlag(QLocale::ISO639Part3)) {
- auto i = searchCode([](const LanguageCodeEntry &i) { return i.part3; });
+ auto i = searchCode([](LanguageCodeEntry i) { return i.part3; });
if (i != languageCodeList.end())
return QLocale::Language(std::distance(languageCodeList.begin(), i));
}
@@ -250,7 +252,7 @@ struct LikelyPair
QLocaleId value = QLocaleId { 0, 0, 0 };
};
-bool operator<(const LikelyPair &lhs, const LikelyPair &rhs)
+bool operator<(LikelyPair lhs, LikelyPair rhs)
{
// Must match the comparison LocaleDataWriter.likelySubtags() uses when
// sorting, see qtbase/util/locale_database.qlocalexml2cpp.py
@@ -463,7 +465,7 @@ QByteArray QLocalePrivate::bcp47Name(char separator) const
return m_data->id().withLikelySubtagsRemoved().name(separator);
}
-static qsizetype findLocaleIndexById(const QLocaleId &localeId)
+static qsizetype findLocaleIndexById(QLocaleId localeId)
{
qsizetype idx = locale_index[localeId.language_id];
// If there are no locales for specified language (so we we've got the
@@ -682,6 +684,7 @@ qsizetype qt_repeatCount(QStringView s)
}
Q_CONSTINIT static const QLocaleData *default_data = nullptr;
+Q_CONSTINIT QBasicAtomicInt QLocalePrivate::s_generation = Q_BASIC_ATOMIC_INITIALIZER(0);
static QLocalePrivate *c_private()
{
@@ -704,7 +707,7 @@ static QLocalePrivate *c_private()
system locale. This is only intended as a way to let a platform plugin
install its own system locale, overriding what might otherwise be provided
for its class of platform (as Android does, differing from Linux), and to
- let tests transiently over-ride the system or plugin-supplied one. As such,
+ let tests transiently override the system or plugin-supplied one. As such,
there should not be diverse threads creating and destroying QSystemLocale
instances concurrently, so no attempt is made at thread-safety in managing
the stack.
@@ -780,28 +783,49 @@ static void updateSystemPrivate()
systemLocaleData.m_script_id = res.toInt();
// Should we replace Any values based on likely sub-tags ?
+
+ // If system locale is default locale, update the default collator's generation:
+ if (default_data == &systemLocaleData)
+ QLocalePrivate::s_generation.fetchAndAddRelaxed(1);
}
#endif // !QT_NO_SYSTEMLOCALE
-static const QLocaleData *systemData()
+static const QLocaleData *systemData(qsizetype *sysIndex = nullptr)
{
#ifndef QT_NO_SYSTEMLOCALE
/*
Copy over the information from the fallback locale and modify.
- This modifies (cross-thread) global state, so take care to only call it in
- one thread.
+ If sysIndex is passed, it should be the m_index of the system locale's
+ QLocalePrivate, which we'll update if it needs it.
+
+ This modifies (cross-thread) global state, so is mutex-protected.
*/
{
+ Q_CONSTINIT static QLocaleId sysId;
+ bool updated = false;
+
Q_CONSTINIT static QBasicMutex systemDataMutex;
systemDataMutex.lock();
- if (systemLocaleData.m_language_id == 0)
+ if (systemLocaleData.m_language_id == 0) {
updateSystemPrivate();
+ updated = true;
+ }
+ // Initialization of system private has *sysIndex == -1 to hit this.
+ if (sysIndex && (updated || *sysIndex < 0)) {
+ const QLocaleId nowId = systemLocaleData.id();
+ if (sysId != nowId || *sysIndex < 0) {
+ // This look-up may be expensive:
+ *sysIndex = QLocaleData::findLocaleIndex(nowId);
+ sysId = nowId;
+ }
+ }
systemDataMutex.unlock();
}
return &systemLocaleData;
#else
+ Q_UNUSED(sysIndex);
return locale_data;
#endif
}
@@ -853,7 +877,6 @@ QDataStream &operator>>(QDataStream &ds, QLocale &l)
static constexpr qsizetype locale_data_size = q20::ssize(locale_data) - 1; // trailing guard
-Q_CONSTINIT QBasicAtomicInt QLocalePrivate::s_generation = Q_BASIC_ATOMIC_INITIALIZER(0);
Q_GLOBAL_STATIC(QSharedDataPointer<QLocalePrivate>, defaultLocalePrivate,
new QLocalePrivate(defaultData(), defaultIndex()))
@@ -980,6 +1003,21 @@ QLocale::QLocale(QLocalePrivate &dd)
: d(&dd)
{}
+/*!
+ \variable QLocale::DefaultTwoDigitBaseYear
+ \since 6.7
+
+ \brief The default start year of the century within which a format taking
+ a two-digit year will select. The value of the constant is \c {1900}.
+
+ Some locales use, particularly for ShortFormat, only the last two digits of
+ the year. Proir to 6.7 the year 1900 was always used as a base year for
+ such cases. Now various QLocale and QDate functions have the overloads that
+ allow callers to specify the base year, and this constant is used as its
+ default value.
+
+ \sa toDate(), toDateTime(), QDate::fromString(), QDateTime::fromString()
+*/
/*!
\since 6.3
@@ -1049,7 +1087,7 @@ QLocale::QLocale()
*/
QLocale::QLocale(Language language, Territory territory)
- : d(findLocalePrivate(language, QLocale::AnyScript, territory))
+ : d(findLocalePrivate(language, AnyScript, territory))
{
}
@@ -1176,10 +1214,10 @@ QString QLocale::quoteString(QStringView str, QuotationStyle style) const
#ifndef QT_NO_SYSTEMLOCALE
if (d->m_data == &systemLocaleData) {
QVariant res;
- if (style == QLocale::AlternateQuotation)
+ if (style == AlternateQuotation)
res = systemLocale()->query(QSystemLocale::StringToAlternateQuotation,
QVariant::fromValue(str));
- if (res.isNull() || style == QLocale::StandardQuotation)
+ if (res.isNull() || style == StandardQuotation)
res = systemLocale()->query(QSystemLocale::StringToStandardQuotation,
QVariant::fromValue(str));
if (!res.isNull())
@@ -1188,7 +1226,7 @@ QString QLocale::quoteString(QStringView str, QuotationStyle style) const
#endif
QLocaleData::DataRange start, end;
- if (style == QLocale::StandardQuotation) {
+ if (style == StandardQuotation) {
start = d->m_data->quoteStart();
end = d->m_data->quoteEnd();
} else {
@@ -1320,13 +1358,47 @@ QLocale::Country QLocale::country() const
#endif
/*!
+ \since 6.7
+ \enum QLocale::TagSeparator
+
+ Indicate how to combine the parts that make up a locale identifier.
+
+ A locale identifier may be made up of several tags, indicating language,
+ script and territory (plus, potentially, other details), joined together to
+ form the identifier. Various standards and conventional forms use either a
+ dash (the Unicode HYPHEN-MINUS, U+002D) or an underscore (LOW LINE, U+005F).
+ Different clients of QLocale may thus need one or the other.
+
+ \value Dash Use \c{'-'}, the dash or hyphen character.
+ \value Underscore Use \c{'_'}, the underscore character.
+
+ \note Although dash and underscore are the only separators used in public
+ standards (as at 2023), it is possible to cast any \l
+ {https://en.cppreference.com/w/cpp/language/ascii} {ASCII} character to this
+ type if a non-standard ASCII separator is needed. Casting a non-ASCII
+ character (with decimal value above 127) is not supported: such values are
+ reserved for future use as enum members if some public standard ever uses a
+ non-ASCII separator. It is, of course, possible to use QString::replace() to
+ replace the separator used by a function taking a parameter of this type
+ with an arbitrary Unicode character or string.
+*/
+
+Q_DECL_COLD_FUNCTION static void badSeparatorWarning(const char *method, char sep)
+{
+ qWarning("QLocale::%s(): Using non-ASCII separator '%c' (%02x) is unsupported",
+ method, sep, uint(uchar(sep)));
+}
+
+/*!
\brief The short name of this locale.
Returns the language and territory of this locale as a string of the form
"language_territory", where language is a lowercase, two-letter ISO 639
language code, and territory is an uppercase, two- or three-letter ISO 3166
territory code. If the locale has no specified territory, only the language
- name is returned.
+ name is returned. Since Qt 6.7 an optional \a separator parameter can be
+ supplied to override the default underscore character separating the two
+ tags.
Even if the QLocale object was constructed with an explicit script, name()
will not contain it for compatibility reasons. Use \l bcp47Name() instead if
@@ -1337,8 +1409,13 @@ QLocale::Country QLocale::country() const
\sa QLocale(), language(), script(), territory(), bcp47Name(), uiLanguages()
*/
-QString QLocale::name() const
+QString QLocale::name(TagSeparator separator) const
{
+ const char sep = char(separator);
+ if (uchar(sep) > 0x7f) {
+ badSeparatorWarning("name", sep);
+ return {};
+ }
const auto code = d->languageCode();
QLatin1StringView view{code.data()};
@@ -1350,7 +1427,7 @@ QString QLocale::name() const
if (c == AnyTerritory)
return view;
- return view + u'_' + d->territoryCode();
+ return view + QLatin1Char(sep) + d->territoryCode();
}
template <typename T> static inline
@@ -1359,12 +1436,16 @@ T toIntegral_helper(const QLocalePrivate *d, QStringView str, bool *ok)
constexpr bool isUnsigned = std::is_unsigned_v<T>;
using Int64 = typename std::conditional_t<isUnsigned, quint64, qint64>;
- Int64 val = 0;
+ QSimpleParsedNumber<Int64> r{};
if constexpr (isUnsigned)
- val = d->m_data->stringToUnsLongLong(str, 10, ok, d->m_numberOptions);
+ r = d->m_data->stringToUnsLongLong(str, 10, d->m_numberOptions);
else
- val = d->m_data->stringToLongLong(str, 10, ok, d->m_numberOptions);
+ r = d->m_data->stringToLongLong(str, 10, d->m_numberOptions);
+
+ if (ok)
+ *ok = r.ok();
+ Int64 val = r.result;
if (T(val) != val) {
if (ok != nullptr)
*ok = false;
@@ -1390,13 +1471,22 @@ T toIntegral_helper(const QLocalePrivate *d, QStringView str, bool *ok)
locale name of the QLocale data; this need not be the language the
user-interface should be in.
- This function tries to conform the locale name to BCP47.
+ This function tries to conform the locale name to the IETF Best Common
+ Practice 47, defined by RFC 5646. Since Qt 6.7, it supports an optional \a
+ separator parameter which can be used to override the BCP47-specified use of
+ a hyphen to separate the tags. For use in IETF-defined protocols, however,
+ the default, QLocale::TagSeparator::Dash, should be retained.
\sa name(), language(), territory(), script(), uiLanguages()
*/
-QString QLocale::bcp47Name() const
+QString QLocale::bcp47Name(TagSeparator separator) const
{
- return QString::fromLatin1(d->bcp47Name());
+ const char sep = char(separator);
+ if (uchar(sep) > 0x7f) {
+ badSeparatorWarning("bcp47Name", sep);
+ return {};
+ }
+ return QString::fromLatin1(d->bcp47Name(sep));
}
/*!
@@ -1541,9 +1631,9 @@ QLocale::Script QLocale::codeToScript(QStringView scriptCode) noexcept
QString QLocale::languageToString(Language language)
{
- if (language > QLocale::LastLanguage)
+ if (language > LastLanguage)
return "Unknown"_L1;
- return QLatin1StringView(language_name_list + language_name_index[language]);
+ return QString::fromUtf8(language_name_list + language_name_index[language]);
}
/*!
@@ -1553,11 +1643,11 @@ QString QLocale::languageToString(Language language)
\sa languageToString(), scriptToString(), territory(), bcp47Name()
*/
-QString QLocale::territoryToString(QLocale::Territory territory)
+QString QLocale::territoryToString(Territory territory)
{
- if (territory > QLocale::LastTerritory)
+ if (territory > LastTerritory)
return "Unknown"_L1;
- return QLatin1StringView(territory_name_list + territory_name_index[territory]);
+ return QString::fromUtf8(territory_name_list + territory_name_index[territory]);
}
#if QT_DEPRECATED_SINCE(6, 6)
@@ -1581,11 +1671,11 @@ QString QLocale::countryToString(Country country)
\sa languageToString(), territoryToString(), script(), bcp47Name()
*/
-QString QLocale::scriptToString(QLocale::Script script)
+QString QLocale::scriptToString(Script script)
{
- if (script > QLocale::LastScript)
+ if (script > LastScript)
return "Unknown"_L1;
- return QLatin1StringView(script_name_list + script_name_index[script]);
+ return QString::fromUtf8(script_name_list + script_name_index[script]);
}
/*!
@@ -2348,6 +2438,16 @@ QTime QLocale::toTime(const QString &string, FormatType format) const
Parses \a string and returns the date it represents. The format of the date
string is chosen according to the \a format parameter (see dateFormat()).
+//! [base-year-for-short]
+ Some locales use, particularly for ShortFormat, only the last two digits of
+ the year. In such a case, the 100 years starting at \a baseYear are the
+ candidates first considered. Prior to 6.7 there was no \a baseYear parameter
+ and 1900 was always used. This is the default for \a baseYear, selecting a
+ year from then to 1999. In some cases, other fields may lead to the next or
+ previous century being selected, to get a result consistent with all fields
+ given. See \l QDate::fromString() for details.
+//! [base-year-for-short]
+
\note Month and day names, where used, must be given in the locale's
language.
@@ -2355,18 +2455,18 @@ QTime QLocale::toTime(const QString &string, FormatType format) const
\sa dateFormat(), toTime(), toDateTime(), QDate::fromString()
*/
-QDate QLocale::toDate(const QString &string, FormatType format) const
+QDate QLocale::toDate(const QString &string, FormatType format, int baseYear) const
{
- return toDate(string, dateFormat(format));
+ return toDate(string, dateFormat(format), baseYear);
}
/*!
\since 5.14
\overload
*/
-QDate QLocale::toDate(const QString &string, FormatType format, QCalendar cal) const
+QDate QLocale::toDate(const QString &string, FormatType format, QCalendar cal, int baseYear) const
{
- return toDate(string, dateFormat(format), cal);
+ return toDate(string, dateFormat(format), cal, baseYear);
}
/*!
@@ -2378,6 +2478,8 @@ QDate QLocale::toDate(const QString &string, FormatType format, QCalendar cal) c
date string is chosen according to the \a format parameter (see
dateFormat()).
+ \include qlocale.cpp base-year-for-short
+
\note Month and day names, where used, must be given in the locale's
language. Any am/pm indicators used must match \l amText() or \l pmText(),
ignoring case.
@@ -2386,18 +2488,19 @@ QDate QLocale::toDate(const QString &string, FormatType format, QCalendar cal) c
\sa dateTimeFormat(), toTime(), toDate(), QDateTime::fromString()
*/
-QDateTime QLocale::toDateTime(const QString &string, FormatType format) const
+QDateTime QLocale::toDateTime(const QString &string, FormatType format, int baseYear) const
{
- return toDateTime(string, dateTimeFormat(format));
+ return toDateTime(string, dateTimeFormat(format), baseYear);
}
/*!
\since 5.14
\overload
*/
-QDateTime QLocale::toDateTime(const QString &string, FormatType format, QCalendar cal) const
+QDateTime QLocale::toDateTime(const QString &string, FormatType format, QCalendar cal,
+ int baseYear) const
{
- return toDateTime(string, dateTimeFormat(format), cal);
+ return toDateTime(string, dateTimeFormat(format), cal, baseYear);
}
/*!
@@ -2438,6 +2541,16 @@ QTime QLocale::toTime(const QString &string, const QString &format) const
Parses \a string and returns the date it represents. See QDate::fromString()
for the interpretation of \a format.
+//! [base-year-for-two-digit]
+ When \a format only specifies the last two digits of a year, the 100 years
+ starting at \a baseYear are the candidates first considered. Prior to 6.7
+ there was no \a baseYear parameter and 1900 was always used. This is the
+ default for \a baseYear, selecting a year from then to 1999. In some cases,
+ other fields may lead to the next or previous century being selected, to get
+ a result consistent with all fields given. See \l QDate::fromString() for
+ details.
+//! [base-year-for-two-digit]
+
\note Month and day names, where used, must be given in the locale's
language.
@@ -2445,26 +2558,27 @@ QTime QLocale::toTime(const QString &string, const QString &format) const
\sa dateFormat(), toTime(), toDateTime(), QDate::fromString()
*/
-QDate QLocale::toDate(const QString &string, const QString &format) const
+QDate QLocale::toDate(const QString &string, const QString &format, int baseYear) const
{
- return toDate(string, format, QCalendar());
+ return toDate(string, format, QCalendar(), baseYear);
}
/*!
\since 5.14
\overload
*/
-QDate QLocale::toDate(const QString &string, const QString &format, QCalendar cal) const
+QDate QLocale::toDate(const QString &string, const QString &format, QCalendar cal, int baseYear) const
{
QDate date;
#if QT_CONFIG(datetimeparser)
QDateTimeParser dt(QMetaType::QDate, QDateTimeParser::FromString, cal);
dt.setDefaultLocale(*this);
if (dt.parseFormat(format))
- dt.fromString(string, &date, nullptr);
+ dt.fromString(string, &date, nullptr, baseYear);
#else
Q_UNUSED(string);
Q_UNUSED(format);
+ Q_UNUSED(baseYear);
Q_UNUSED(cal);
#endif
return date;
@@ -2478,6 +2592,8 @@ QDate QLocale::toDate(const QString &string, const QString &format, QCalendar ca
Parses \a string and returns the date-time it represents. See
QDateTime::fromString() for the interpretation of \a format.
+ \include qlocale.cpp base-year-for-two-digit
+
\note Month and day names, where used, must be given in the locale's
language. Any am/pm indicators used must match \l amText() or \l pmText(),
ignoring case.
@@ -2491,27 +2607,31 @@ QDate QLocale::toDate(const QString &string, const QString &format, QCalendar ca
\sa dateTimeFormat(), toTime(), toDate(), QDateTime::fromString()
*/
-QDateTime QLocale::toDateTime(const QString &string, const QString &format) const
+QDateTime QLocale::toDateTime(const QString &string, const QString &format, int baseYear) const
{
- return toDateTime(string, format, QCalendar());
+ return toDateTime(string, format, QCalendar(), baseYear);
}
/*!
\since 5.14
\overload
*/
-QDateTime QLocale::toDateTime(const QString &string, const QString &format, QCalendar cal) const
+QDateTime QLocale::toDateTime(const QString &string, const QString &format, QCalendar cal,
+ int baseYear) const
{
#if QT_CONFIG(datetimeparser)
QDateTime datetime;
QDateTimeParser dt(QMetaType::QDateTime, QDateTimeParser::FromString, cal);
dt.setDefaultLocale(*this);
- if (dt.parseFormat(format) && (dt.fromString(string, &datetime) || !datetime.isValid()))
+ if (dt.parseFormat(format) && (dt.fromString(string, &datetime, baseYear)
+ || !datetime.isValid())) {
return datetime;
+ }
#else
Q_UNUSED(string);
Q_UNUSED(format);
+ Q_UNUSED(baseYear);
Q_UNUSED(cal);
#endif
return QDateTime();
@@ -2741,8 +2861,19 @@ QString QLocale::toString(double f, char format, int precision) const
QLocale QLocale::system()
{
- QT_PREPEND_NAMESPACE(systemData)(); // Ensure system data is up to date.
- static QLocalePrivate locale(systemData(), defaultIndex(), DefaultNumberOptions, 1);
+ constexpr auto sysData = []() {
+ // Same return as systemData(), but leave the setup to the actual call to it.
+#ifdef QT_NO_SYSTEMLOCALE
+ return locale_data;
+#else
+ return &systemLocaleData;
+#endif
+ };
+ Q_CONSTINIT static QLocalePrivate locale(sysData(), -1, DefaultNumberOptions, 1);
+ // Calling systemData() ensures system data is up to date; we also need it
+ // to ensure that locale's index stays up to date:
+ systemData(&locale.m_index);
+ Q_ASSERT(locale.m_index >= 0 && locale.m_index < locale_data_size);
return QLocale(locale);
}
@@ -2759,15 +2890,14 @@ QLocale QLocale::system()
QList<QLocale> locales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript,
QLocale::Russia);
*/
-QList<QLocale> QLocale::matchingLocales(QLocale::Language language, QLocale::Script script,
- QLocale::Territory territory)
+QList<QLocale> QLocale::matchingLocales(Language language, Script script, Territory territory)
{
const QLocaleId filter { language, script, territory };
if (!filter.isValid())
return QList<QLocale>();
- if (language == QLocale::C)
- return QList<QLocale>() << QLocale(QLocale::C);
+ if (language == C)
+ return QList<QLocale>{QLocale(C)};
QList<QLocale> result;
if (filter.matchesAll())
@@ -2790,7 +2920,7 @@ QList<QLocale> QLocale::matchingLocales(QLocale::Language language, QLocale::Scr
if (filter.acceptLanguage(syslocaledata->m_language_id)) {
const QLocaleId id = syslocaledata->id();
if (filter.acceptScriptTerritory(id))
- result.append(QLocale::system());
+ result.append(system());
}
return result;
@@ -2810,7 +2940,7 @@ QList<QLocale> QLocale::matchingLocales(QLocale::Language language, QLocale::Scr
QList<QLocale::Country> QLocale::countriesForLanguage(Language language)
{
const auto locales = matchingLocales(language, AnyScript, AnyCountry);
- QList<QLocale::Country> result;
+ QList<Country> result;
result.reserve(locales.size());
for (const auto &locale : locales)
result.append(locale.territory());
@@ -2888,6 +3018,14 @@ QString QLocale::standaloneDayName(int day, FormatType type) const
// Calendar look-up of month and day names:
+// Only used in assertions
+[[maybe_unused]] static bool sameLocale(const QLocaleData *locale, const QCalendarLocale &calendar)
+{
+ return locale->m_language_id == calendar.m_language_id
+ && locale->m_script_id == calendar.m_script_id
+ && locale->m_territory_id == calendar.m_territory_id;
+}
+
/*!
\internal
*/
@@ -2996,12 +3134,13 @@ QString QCalendarBackend::monthName(const QLocale &locale, int month, int,
QLocale::FormatType format) const
{
Q_ASSERT(month >= 1 && month <= maximumMonthsInYear());
- return rawMonthName(localeMonthIndexData()[locale.d->m_index],
- localeMonthData(), month, format);
+ const QCalendarLocale &monthly = localeMonthIndexData()[locale.d->m_index];
+ Q_ASSERT(sameLocale(locale.d->m_data, monthly));
+ return rawMonthName(monthly, localeMonthData(), month, format);
}
-QString QGregorianCalendar::monthName(const QLocale &locale, int month, int year,
- QLocale::FormatType format) const
+QString QRomanCalendar::monthName(const QLocale &locale, int month, int year,
+ QLocale::FormatType format) const
{
#ifndef QT_NO_SYSTEMLOCALE
if (locale.d->m_data == &systemLocaleData) {
@@ -3031,12 +3170,13 @@ QString QCalendarBackend::standaloneMonthName(const QLocale &locale, int month,
QLocale::FormatType format) const
{
Q_ASSERT(month >= 1 && month <= maximumMonthsInYear());
- return rawStandaloneMonthName(localeMonthIndexData()[locale.d->m_index],
- localeMonthData(), month, format);
+ const QCalendarLocale &monthly = localeMonthIndexData()[locale.d->m_index];
+ Q_ASSERT(sameLocale(locale.d->m_data, monthly));
+ return rawStandaloneMonthName(monthly, localeMonthData(), month, format);
}
-QString QGregorianCalendar::standaloneMonthName(const QLocale &locale, int month, int year,
- QLocale::FormatType format) const
+QString QRomanCalendar::standaloneMonthName(const QLocale &locale, int month, int year,
+ QLocale::FormatType format) const
{
#ifndef QT_NO_SYSTEMLOCALE
if (locale.d->m_data == &systemLocaleData) {
@@ -3204,34 +3344,34 @@ QLocale::MeasurementSystem QLocale::measurementSystem() const
Qt::LayoutDirection QLocale::textDirection() const
{
switch (script()) {
- case QLocale::AdlamScript:
- case QLocale::ArabicScript:
- case QLocale::AvestanScript:
- case QLocale::CypriotScript:
- case QLocale::HatranScript:
- case QLocale::HebrewScript:
- case QLocale::ImperialAramaicScript:
- case QLocale::InscriptionalPahlaviScript:
- case QLocale::InscriptionalParthianScript:
- case QLocale::KharoshthiScript:
- case QLocale::LydianScript:
- case QLocale::MandaeanScript:
- case QLocale::ManichaeanScript:
- case QLocale::MendeKikakuiScript:
- case QLocale::MeroiticCursiveScript:
- case QLocale::MeroiticScript:
- case QLocale::NabataeanScript:
- case QLocale::NkoScript:
- case QLocale::OldHungarianScript:
- case QLocale::OldNorthArabianScript:
- case QLocale::OldSouthArabianScript:
- case QLocale::OrkhonScript:
- case QLocale::PalmyreneScript:
- case QLocale::PhoenicianScript:
- case QLocale::PsalterPahlaviScript:
- case QLocale::SamaritanScript:
- case QLocale::SyriacScript:
- case QLocale::ThaanaScript:
+ case AdlamScript:
+ case ArabicScript:
+ case AvestanScript:
+ case CypriotScript:
+ case HatranScript:
+ case HebrewScript:
+ case ImperialAramaicScript:
+ case InscriptionalPahlaviScript:
+ case InscriptionalParthianScript:
+ case KharoshthiScript:
+ case LydianScript:
+ case MandaeanScript:
+ case ManichaeanScript:
+ case MendeKikakuiScript:
+ case MeroiticCursiveScript:
+ case MeroiticScript:
+ case NabataeanScript:
+ case NkoScript:
+ case OldHungarianScript:
+ case OldNorthArabianScript:
+ case OldSouthArabianScript:
+ case OrkhonScript:
+ case PalmyreneScript:
+ case PhoenicianScript:
+ case PsalterPahlaviScript:
+ case SamaritanScript:
+ case SyriacScript:
+ case ThaanaScript:
return Qt::RightToLeft;
default:
break;
@@ -3384,7 +3524,9 @@ QString QCalendarBackend::dateTimeToString(QStringView format, const QDateTime &
}
const QChar c = format.at(i);
- qsizetype repeat = qt_repeatCount(format.mid(i));
+ qsizetype rep = qt_repeatCount(format.mid(i));
+ Q_ASSERT(rep < std::numeric_limits<int>::max());
+ int repeat = int(rep);
bool used = false;
if (formatDate) {
switch (c.unicode()) {
@@ -3497,29 +3639,49 @@ QString QCalendarBackend::dateTimeToString(QStringView format, const QDateTime &
break;
case 't': {
+ enum AbbrType { Long, Offset, Short };
+ const auto tzAbbr = [locale](const QDateTime &when, AbbrType type) {
+#if QT_CONFIG(timezone)
+ if (type != Short || locale != QLocale::system()) {
+ QTimeZone::NameType mode =
+ type == Short ? QTimeZone::ShortName
+ : type == Long ? QTimeZone::LongName : QTimeZone::OffsetName;
+ return when.timeRepresentation().displayName(when, mode, locale);
+ } // else: prefer QDateTime's abbreviation, for backwards-compatibility.
+#endif // else, make do with non-localized abbreviation:
+ if (type != Offset)
+ return when.timeZoneAbbreviation();
+ // For Offset, we can coerce to a UTC-based zone's abbreviation:
+ return when.toOffsetFromUtc(when.offsetFromUtc()).timeZoneAbbreviation();
+ };
used = true;
repeat = qMin(repeat, 4);
// If we don't have a date-time, use the current system time:
const QDateTime when = formatDate ? datetime : QDateTime::currentDateTime();
QString text;
switch (repeat) {
-#if QT_CONFIG(timezone)
case 4:
- text = when.timeZone().displayName(when, QTimeZone::LongName);
+ text = tzAbbr(when, Long);
break;
-#endif // timezone
- case 3:
- case 2:
- text = when.toOffsetFromUtc(when.offsetFromUtc()).timeZoneAbbreviation();
- // If the offset is UTC that'll be a Qt::UTC, otherwise Qt::OffsetFromUTC.
- Q_ASSERT(text.startsWith("UTC"_L1));
- // The Qt::UTC case omits the zero offset, which we want:
- text = text.size() == 3 ? u"+00:00"_s : text.sliced(3);
- if (repeat == 2) // +hhmm format, rather than +hh:mm format
+ case 3: // ±hh:mm
+ case 2: // ±hhmm (we'll remove the ':' at the end)
+ text = tzAbbr(when, Offset);
+ Q_ASSERT(text.startsWith("UTC"_L1)); // Need to strip this.
+ // The Qt::UTC case omits the zero offset:
+ text = (text.size() == 3
+ ? u"+00:00"_s
+ : (text.size() <= 6
+ // Whole-hour offsets may lack the zero minutes:
+ ? QStringView{text}.sliced(3) + ":00"_L1
+ : std::move(text).sliced(3)));
+ if (repeat == 2)
text = text.remove(u':');
break;
default:
- text = when.timeZoneAbbreviation();
+ text = tzAbbr(when, Short);
+ // UTC-offset zones only include minutes if non-zero.
+ if (text.startsWith("UTC"_L1) && text.size() == 6)
+ text += ":00"_L1;
break;
}
if (!text.isEmpty())
@@ -3558,7 +3720,7 @@ QString QLocaleData::doubleToString(double d, int precision, DoubleForm form,
qsizetype bufSize = 1;
if (precision == QLocale::FloatingPointShortest)
bufSize += std::numeric_limits<double>::max_digits10;
- else if (form == DFDecimal && qIsFinite(d))
+ else if (form == DFDecimal && qt_is_finite(d))
bufSize += wholePartSpace(qAbs(d)) + precision;
else // Add extra digit due to different interpretations of precision.
bufSize += qMax(2, precision) + 1; // Must also be big enough for "nan" or "inf"
@@ -3637,7 +3799,7 @@ QString QLocaleData::doubleToString(double d, int precision, DoubleForm form,
int bias = 2 + minExponentDigits;
// Decimal form may get grouping separators inserted:
if (groupDigits && decpt >= m_grouping_top + m_grouping_least)
- bias -= (decpt - m_grouping_top - m_grouping_least) / m_grouping_higher + 1;
+ bias -= (decpt - m_grouping_least) / m_grouping_higher + 1;
// X = decpt - 1 needs two digits if decpt > 10:
if (decpt > 10 && minExponentDigits == 1)
++bias;
@@ -3726,7 +3888,7 @@ QString QLocaleData::decimalForm(QString &&digits, int decpt, int precision,
qsizetype i = decpt - m_grouping_least;
if (i >= m_grouping_top) {
digits.insert(i * digitWidth, group);
- while ((i -= m_grouping_higher) >= m_grouping_top)
+ while ((i -= m_grouping_higher) > 0)
digits.insert(i * digitWidth, group);
}
}
@@ -3834,7 +3996,7 @@ QString QLocaleData::applyIntegerFormatting(QString &&numStr, bool negative, int
if (i >= m_grouping_top) {
numStr.insert(i * digitWidth, group);
++usedWidth;
- while ((i -= m_grouping_higher) >= m_grouping_top) {
+ while ((i -= m_grouping_higher) > 0) {
numStr.insert(i * digitWidth, group);
++usedWidth;
}
@@ -4063,7 +4225,8 @@ char NumericTokenizer::nextToken()
// writing Cyrillic may well use that; and Ukrainians might well use E.
// All other Cyrillic locales (officially) use plain ASCII E.
if (m_guide.exponentCyrillic // Only true in scientific float mode.
- && (tail.startsWith(u"\u0415") || tail.startsWith(u"E"))) {
+ && (tail.startsWith(u"\u0415", Qt::CaseInsensitive)
+ || tail.startsWith(u"E", Qt::CaseInsensitive))) {
++m_index;
return 'e';
}
@@ -4152,7 +4315,7 @@ bool QLocaleData::numberToCLocale(QStringView s, QLocale::NumberOptions number_o
if (last_separator_idx == -1) {
// Check distance from the beginning of the digits:
if (start_of_digits_idx == -1 || m_grouping_top > digitsInGroup
- || digitsInGroup >= m_grouping_higher + m_grouping_top) {
+ || digitsInGroup >= m_grouping_least + m_grouping_top) {
return false;
}
} else {
@@ -4198,11 +4361,12 @@ bool QLocaleData::numberToCLocale(QStringView s, QLocale::NumberOptions number_o
return true;
}
-bool QLocaleData::validateChars(QStringView str, NumberMode numMode, QByteArray *buff,
- int decDigits, QLocale::NumberOptions number_options) const
+ParsingResult
+QLocaleData::validateChars(QStringView str, NumberMode numMode, int decDigits,
+ QLocale::NumberOptions number_options) const
{
- buff->clear();
- buff->reserve(str.size());
+ ParsingResult result;
+ result.buff.reserve(str.size());
enum { Whole, Fractional, Exponent } state = Whole;
const bool scientific = numMode == DoubleScientificMode;
@@ -4220,14 +4384,14 @@ bool QLocaleData::validateChars(QStringView str, NumberMode numMode, QByteArray
case Fractional:
// If a double has too many digits in its fractional part it is Invalid.
if (decDigits-- == 0)
- return false;
+ return {};
break;
case Exponent:
if (!isAsciiDigit(last)) {
// This is the first digit in the exponent (there may have beena '+'
// or '-' in before). If it's a zero, the exponent is zero-padded.
if (c == '0' && (number_options & QLocale::RejectLeadingZeroInExponent))
- return false;
+ return {};
}
break;
}
@@ -4238,7 +4402,7 @@ bool QLocaleData::validateChars(QStringView str, NumberMode numMode, QByteArray
// If an integer has a decimal point, it is Invalid.
// A double can only have one, at the end of its whole-number part.
if (numMode == IntegerMode || state != Whole)
- return false;
+ return {};
// Even when decDigits is 0, we do allow the decimal point to be
// present - just as long as no digits follow it.
@@ -4249,14 +4413,14 @@ bool QLocaleData::validateChars(QStringView str, NumberMode numMode, QByteArray
case '-':
// A sign can only appear at the start or after the e of scientific:
if (last != '\0' && !(scientific && last == 'e'))
- return false;
+ return {};
break;
case ',':
// Grouping is only allowed after a digit in the whole-number portion:
if ((number_options & QLocale::RejectGroupSeparator) || state != Whole
|| !isAsciiDigit(last)) {
- return false;
+ return {};
}
// We could check grouping sizes are correct, but fixup()s are
// probably better off correcting any misplacement instead.
@@ -4265,7 +4429,7 @@ bool QLocaleData::validateChars(QStringView str, NumberMode numMode, QByteArray
case 'e':
// Only one e is allowed and only in scientific:
if (!scientific || state == Exponent)
- return false;
+ return {};
state = Exponent;
break;
@@ -4275,16 +4439,23 @@ bool QLocaleData::validateChars(QStringView str, NumberMode numMode, QByteArray
// validators don't accept those values.
// For anything else, tokens.nextToken() must have returned 0.
Q_ASSERT(!c || c == 'a' || c == 'f' || c == 'i' || c == 'n');
- return false;
+ return {};
}
}
last = c;
if (c != ',') // Skip grouping
- buff->append(c);
+ result.buff.append(c);
}
- return true;
+ result.state = ParsingResult::Acceptable;
+
+ // Intermediate if it ends with any character that requires a digit after
+ // it to be valid e.g. group separator, sign, or exponent
+ if (last == ',' || last == '-' || last == '+' || last == 'e')
+ result.state = ParsingResult::Intermediate;
+
+ return result;
}
double QLocaleData::stringToDouble(QStringView str, bool *ok,
@@ -4302,83 +4473,60 @@ double QLocaleData::stringToDouble(QStringView str, bool *ok,
return r.result;
}
-qlonglong QLocaleData::stringToLongLong(QStringView str, int base, bool *ok,
- QLocale::NumberOptions number_options) const
+QSimpleParsedNumber<qint64>
+QLocaleData::stringToLongLong(QStringView str, int base,
+ QLocale::NumberOptions number_options) const
{
CharBuff buff;
- if (!numberToCLocale(str, number_options, IntegerMode, &buff)) {
- if (ok != nullptr)
- *ok = false;
- return 0;
- }
+ if (!numberToCLocale(str, number_options, IntegerMode, &buff))
+ return {};
- return bytearrayToLongLong(QByteArrayView(buff.constData(), buff.size()), base, ok);
+ return bytearrayToLongLong(QByteArrayView(buff), base);
}
-qulonglong QLocaleData::stringToUnsLongLong(QStringView str, int base, bool *ok,
- QLocale::NumberOptions number_options) const
+QSimpleParsedNumber<quint64>
+QLocaleData::stringToUnsLongLong(QStringView str, int base,
+ QLocale::NumberOptions number_options) const
{
CharBuff buff;
- if (!numberToCLocale(str, number_options, IntegerMode, &buff)) {
- if (ok != nullptr)
- *ok = false;
- return 0;
- }
+ if (!numberToCLocale(str, number_options, IntegerMode, &buff))
+ return {};
- return bytearrayToUnsLongLong(QByteArrayView(buff.constData(), buff.size()), base, ok);
+ return bytearrayToUnsLongLong(QByteArrayView(buff), base);
}
-qlonglong QLocaleData::bytearrayToLongLong(QByteArrayView num, int base, bool *ok)
+static bool checkParsed(QByteArrayView num, qsizetype used)
{
- const qsizetype len = num.size();
- auto [l, used] = qstrntoll(num.data(), len, base);
- if (used <= 0) {
- if (ok != nullptr)
- *ok = false;
- return 0;
- }
+ if (used <= 0)
+ return false;
+ const qsizetype len = num.size();
if (used < len && num[used] != '\0') {
while (used < len && ascii_isspace(num[used]))
++used;
}
- if (used < len && num[used] != '\0') {
+ if (used < len && num[used] != '\0')
// we stopped at a non-digit character after converting some digits
- if (ok != nullptr)
- *ok = false;
- return 0;
- }
+ return false;
- if (ok != nullptr)
- *ok = true;
- return l;
+ return true;
}
-qulonglong QLocaleData::bytearrayToUnsLongLong(QByteArrayView num, int base, bool *ok)
+QSimpleParsedNumber<qint64> QLocaleData::bytearrayToLongLong(QByteArrayView num, int base)
{
- const qsizetype len = num.size();
- auto [l, used] = qstrntoull(num.data(), len, base);
- if (used <= 0) {
- if (ok != nullptr)
- *ok = false;
- return 0;
- }
-
- if (used < len && num[used] != '\0') {
- while (used < len && ascii_isspace(num[used]))
- ++used;
- }
-
- if (used < len && num[used] != '\0') {
- if (ok != nullptr)
- *ok = false;
- return 0;
- }
+ auto r = qstrntoll(num.data(), num.size(), base);
+ if (!checkParsed(num, r.used))
+ return {};
+ return r;
+}
- if (ok != nullptr)
- *ok = true;
- return l;
+QSimpleParsedNumber<quint64> QLocaleData::bytearrayToUnsLongLong(QByteArrayView num, int base)
+{
+ auto r = qstrntoull(num.data(), num.size(), base);
+ if (!checkParsed(num, r.used))
+ return {};
+ return r;
}
/*!
@@ -4397,7 +4545,7 @@ qulonglong QLocaleData::bytearrayToUnsLongLong(QByteArrayView num, int base, boo
\since 4.8
Returns a currency symbol according to the \a format.
*/
-QString QLocale::currencySymbol(QLocale::CurrencySymbolFormat format) const
+QString QLocale::currencySymbol(CurrencySymbolFormat format) const
{
#ifndef QT_NO_SYSTEMLOCALE
if (d->m_data == &systemLocaleData) {
@@ -4448,7 +4596,7 @@ QString QLocale::toCurrencyString(qlonglong value, const QString &symbol) const
QString str = toString(value);
QString sym = symbol.isNull() ? currencySymbol() : symbol;
if (sym.isEmpty())
- sym = currencySymbol(QLocale::CurrencyIsoCode);
+ sym = currencySymbol(CurrencyIsoCode);
return range.viewData(currency_format_data).arg(str, sym);
}
@@ -4470,7 +4618,7 @@ QString QLocale::toCurrencyString(qulonglong value, const QString &symbol) const
QString str = toString(value);
QString sym = symbol.isNull() ? currencySymbol() : symbol;
if (sym.isEmpty())
- sym = currencySymbol(QLocale::CurrencyIsoCode);
+ sym = currencySymbol(CurrencyIsoCode);
return d->m_data->currencyFormat().getData(currency_format_data).arg(str, sym);
}
@@ -4503,7 +4651,7 @@ QString QLocale::toCurrencyString(double value, const QString &symbol, int preci
QString str = toString(value, 'f', precision == -1 ? d->m_data->m_currency_digits : precision);
QString sym = symbol.isNull() ? currencySymbol() : symbol;
if (sym.isEmpty())
- sym = currencySymbol(QLocale::CurrencyIsoCode);
+ sym = currencySymbol(CurrencyIsoCode);
return range.viewData(currency_format_data).arg(str, sym);
}
@@ -4579,21 +4727,32 @@ QString QLocale::formattedDataSize(qint64 bytes, int precision, DataSizeFormats
\since 4.8
\brief List of locale names for use in selecting translations
- Each entry in the returned list is the dash-joined name of a locale,
- suitable to the user's preferences for what to translate the UI into. For
- example, if the user has configured their system to use English as used in
- the USA, the list would be "en-Latn-US", "en-US", "en". The order of entries
- is the order in which to check for translations; earlier items in the list
- are to be preferred over later ones.
+ Each entry in the returned list is the name of a locale suitable to the
+ user's preferences for what to translate the UI into. Where a name in the
+ list is composed of several tags, they are joined as indicated by \a
+ separator. Prior to Qt 6.7 a dash was used as separator.
+
+ For example, using the default separator QLocale::TagSeparator::Dash, if the
+ user has configured their system to use English as used in the USA, the list
+ would be "en-Latn-US", "en-US", "en". The order of entries is the order in
+ which to check for translations; earlier items in the list are to be
+ preferred over later ones. If your translation files use underscores, rather
+ than dashes, to separate locale tags, pass QLocale::TagSeparator::Underscore
+ as \a separator.
Most likely you do not need to use this function directly, but just pass the
QLocale object to the QTranslator::load() function.
\sa QTranslator, bcp47Name()
*/
-QStringList QLocale::uiLanguages() const
+QStringList QLocale::uiLanguages(TagSeparator separator) const
{
+ const char sep = char(separator);
QStringList uiLanguages;
+ if (uchar(sep) > 0x7f) {
+ badSeparatorWarning("uiLanguages", sep);
+ return uiLanguages;
+ }
QList<QLocaleId> localeIds;
#ifdef QT_NO_SYSTEMLOCALE
constexpr bool isSystem = false;
@@ -4612,7 +4771,7 @@ QStringList QLocale::uiLanguages() const
// first. (Known issue, QTBUG-104930, on some macOS versions when in
// locale en_DE.) Our translation system might have a translation for a
// locale the platform doesn't believe in.
- const QString name = bcp47Name();
+ const QString name = bcp47Name(separator);
if (!name.isEmpty() && language() != C && !uiLanguages.contains(name)) {
// That uses contains(name) as a cheap pre-test, but there may be an
// entry that matches this on purging likely subtags.
@@ -4642,11 +4801,11 @@ QStringList QLocale::uiLanguages() const
j = i + 1;
} else if (id.language_id == C) {
// Attempt no likely sub-tag amendments to C:
- uiLanguages.append(QString::fromLatin1(id.name()));
+ uiLanguages.append(QString::fromLatin1(id.name(sep)));
continue;
} else {
// Plain locale or empty system uiLanguages; just append.
- prior = id.name();
+ prior = id.name(sep);
uiLanguages.append(QString::fromLatin1(prior));
j = uiLanguages.size();
}
@@ -4655,7 +4814,7 @@ QStringList QLocale::uiLanguages() const
const QLocaleId min = max.withLikelySubtagsRemoved();
// Include minimal version (last) unless it's what our locale is derived from:
- if (auto name = min.name(); name != prior)
+ if (auto name = min.name(sep); name != prior)
uiLanguages.insert(j, QString::fromLatin1(name));
else if (!isSystem)
--j; // bcp47Name() matches min(): put more specific forms *before* it.
@@ -4664,7 +4823,7 @@ QStringList QLocale::uiLanguages() const
// Include scriptless version if likely-equivalent and distinct:
id.script_id = 0;
if (id != min && id.withLikelySubtagsAdded() == max) {
- if (auto name = id.name(); name != prior)
+ if (auto name = id.name(sep); name != prior)
uiLanguages.insert(j, QString::fromLatin1(name));
}
}
@@ -4675,14 +4834,14 @@ QStringList QLocale::uiLanguages() const
// Include version with territory if it likely-equivalent and distinct:
id.territory_id = max.territory_id;
if (id != max && id.withLikelySubtagsAdded() == max) {
- if (auto name = id.name(); name != prior)
+ if (auto name = id.name(sep); name != prior)
uiLanguages.insert(j, QString::fromLatin1(name));
}
}
// Include version with all likely sub-tags (first) if distinct from the rest:
if (max != min && max != id) {
- if (auto name = max.name(); name != prior)
+ if (auto name = max.name(sep); name != prior)
uiLanguages.insert(j, QString::fromLatin1(name));
}
}
diff --git a/src/corelib/text/qlocale.h b/src/corelib/text/qlocale.h
index 7b93827282..abef24ea0e 100644
--- a/src/corelib/text/qlocale.h
+++ b/src/corelib/text/qlocale.h
@@ -36,6 +36,8 @@ class Q_CORE_EXPORT QLocale
friend class QTextStreamPrivate;
public:
+ static constexpr int DefaultTwoDigitBaseYear = 1900;
+
// see qlocale_data_p.h for more info on generated data
// GENERATED PART STARTS HERE
enum Language : ushort {
@@ -376,6 +378,13 @@ public:
TokiPona = 334,
Pijin = 335,
Obolo = 336,
+ Baluchi = 337,
+ Ligurian = 338,
+ Rohingya = 339,
+ Torwali = 340,
+ Anii = 341,
+ Kangri = 342,
+ Venetian = 343,
Afan = Oromo,
Bengali = Bangla,
@@ -397,7 +406,7 @@ public:
Uigur = Uyghur,
Walamo = Wolaytta,
- LastLanguage = Obolo
+ LastLanguage = Venetian
};
enum Script : ushort {
@@ -543,6 +552,7 @@ public:
VaiScript = 139,
VarangKshitiScript = 140,
YiScript = 141,
+ HanifiScript = 142,
BengaliScript = BanglaScript,
MendeKikakuiScript = MendeScript,
@@ -550,7 +560,7 @@ public:
SimplifiedChineseScript = SimplifiedHanScript,
TraditionalChineseScript = TraditionalHanScript,
- LastScript = YiScript
+ LastScript = HanifiScript
};
// ### Qt 7: Rename to Territory
@@ -880,11 +890,15 @@ public:
FloatingPointShortest = -128
};
+ enum class TagSeparator : char { Dash = '-', Underscore = '_' };
+ Q_ENUM(TagSeparator)
+
enum CurrencySymbolFormat {
CurrencyIsoCode,
CurrencySymbol,
CurrencyDisplayName
};
+ Q_ENUM(CurrencySymbolFormat)
enum DataSizeFormat {
// Single-bit values, for internal use.
@@ -919,9 +933,14 @@ public:
QT_DEPRECATED_VERSION_X_6_6("Use territory() instead")
Country country() const;
#endif
- QString name() const;
+#if QT_CORE_REMOVED_SINCE(6, 7)
+ QString name() const;
QString bcp47Name() const;
+#endif
+ QString name(TagSeparator separator = TagSeparator::Underscore) const;
+ QString bcp47Name(TagSeparator separator = TagSeparator::Dash) const;
+
QString nativeLanguageName() const;
QString nativeTerritoryName() const;
#if QT_DEPRECATED_SINCE(6, 6)
@@ -997,18 +1016,39 @@ public:
QString dateFormat(FormatType format = LongFormat) const;
QString timeFormat(FormatType format = LongFormat) const;
QString dateTimeFormat(FormatType format = LongFormat) const;
+ // QCalendar's header has to #include QLocale's, preventing the reverse, so
+ // QCalendar parameters can't have defaults here.
#if QT_CONFIG(datestring)
- QDate toDate(const QString &string, FormatType = LongFormat) const;
QTime toTime(const QString &string, FormatType = LongFormat) const;
- QDateTime toDateTime(const QString &string, FormatType format = LongFormat) const;
- QDate toDate(const QString &string, const QString &format) const;
QTime toTime(const QString &string, const QString &format) const;
+# if QT_CORE_REMOVED_SINCE(6, 7)
+ QDate toDate(const QString &string, FormatType = LongFormat) const;
+ QDate toDate(const QString &string, const QString &format) const;
+ QDateTime toDateTime(const QString &string, FormatType format = LongFormat) const;
QDateTime toDateTime(const QString &string, const QString &format) const;
// Calendar-aware API
QDate toDate(const QString &string, FormatType format, QCalendar cal) const;
- QDateTime toDateTime(const QString &string, FormatType format, QCalendar cal) const;
QDate toDate(const QString &string, const QString &format, QCalendar cal) const;
+ QDateTime toDateTime(const QString &string, FormatType format, QCalendar cal) const;
QDateTime toDateTime(const QString &string, const QString &format, QCalendar cal) const;
+# endif
+ QDate toDate(const QString &string, FormatType = LongFormat,
+ int baseYear = DefaultTwoDigitBaseYear) const;
+ QDate toDate(const QString &string, const QString &format,
+ int baseYear = DefaultTwoDigitBaseYear) const;
+ QDateTime toDateTime(const QString &string, FormatType format = LongFormat,
+ int baseYear = DefaultTwoDigitBaseYear) const;
+ QDateTime toDateTime(const QString &string, const QString &format,
+ int baseYear = DefaultTwoDigitBaseYear) const;
+ // Calendar-aware API
+ QDate toDate(const QString &string, FormatType format, QCalendar cal,
+ int baseYear = DefaultTwoDigitBaseYear) const;
+ QDate toDate(const QString &string, const QString &format, QCalendar cal,
+ int baseYear = DefaultTwoDigitBaseYear) const;
+ QDateTime toDateTime(const QString &string, FormatType format, QCalendar cal,
+ int baseYear = DefaultTwoDigitBaseYear) const;
+ QDateTime toDateTime(const QString &string, const QString &format, QCalendar cal,
+ int baseYear = DefaultTwoDigitBaseYear) const;
#endif
QString decimalPoint() const;
@@ -1054,7 +1094,10 @@ public:
QString formattedDataSize(qint64 bytes, int precision = 2, DataSizeFormats format = DataSizeIecFormat) const;
+#if QT_CORE_REMOVED_SINCE(6, 7)
QStringList uiLanguages() const;
+#endif
+ QStringList uiLanguages(TagSeparator separator = TagSeparator::Dash) const;
enum LanguageCodeType {
ISO639Part1 = 1 << 0,
@@ -1114,6 +1157,7 @@ public:
NumberOptions numberOptions() const;
enum QuotationStyle { StandardQuotation, AlternateQuotation };
+ Q_ENUM(QuotationStyle)
QString quoteString(const QString &str, QuotationStyle style = StandardQuotation) const
{ return quoteString(QStringView(str), style); }
QString quoteString(QStringView str, QuotationStyle style = StandardQuotation) const;
@@ -1126,11 +1170,14 @@ private:
friend class QLocalePrivate;
friend class QSystemLocale;
friend class QCalendarBackend;
- friend class QGregorianCalendar;
+ friend class QRomanCalendar;
friend Q_CORE_EXPORT size_t qHash(const QLocale &key, size_t seed) noexcept;
- friend bool operator==(const QLocale &lhs, const QLocale &rhs) { return lhs.equals(rhs); }
- friend bool operator!=(const QLocale &lhs, const QLocale &rhs) { return !lhs.equals(rhs); }
+ friend bool comparesEqual(const QLocale &lhs, const QLocale &rhs) noexcept
+ {
+ return lhs.equals(rhs);
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QLocale)
QSharedDataPointer<QLocalePrivate> d;
};
diff --git a/src/corelib/text/qlocale.qdoc b/src/corelib/text/qlocale.qdoc
index bb78bc4923..0cdacfd8e5 100644
--- a/src/corelib/text/qlocale.qdoc
+++ b/src/corelib/text/qlocale.qdoc
@@ -7,6 +7,7 @@
\brief The QLocale class converts between numbers and their
string representations in various languages.
+ \compares equality
\reentrant
\ingroup i18n
\ingroup string-processing
@@ -50,7 +51,7 @@
\note For the current keyboard input locale take a look at
QInputMethod::locale().
- QLocale's data is based on Common Locale Data Repository v42.
+ QLocale's data is based on Common Locale Data Repository v44.1.
\section1 Matching combinations of language, script and territory
@@ -102,6 +103,7 @@
\value Amharic
\value [since 5.1] AncientEgyptian
\value [since 5.1] AncientGreek
+ \value [since 6.7] Anii
\value Arabic
\value [since 5.1] Aragonese
\value [since 5.1] Aramaic
@@ -116,6 +118,7 @@
\value Azerbaijani
\value Bafia
\value [since 5.1] Balinese
+ \value [since 6.6] Baluchi
\value Bambara
\value [since 5.1] Bamun
\value [since 6.0] Bangla
@@ -229,6 +232,7 @@
\value [since 6.0] Kalaallisut
\value Kalenjin
\value Kamba
+ \value [since 6.7] Kangri
\value Kannada
\value Kanuri
\value Kashmiri
@@ -261,6 +265,7 @@
\value [since 5.5] Lezghian
\value Limburgish
\value Lingala
+ \value [since 6.6] Ligurian
\value [since 5.7] LiteraryChinese
\value Lithuanian
\value [since 5.12] Lojban
@@ -346,6 +351,7 @@
\value Quechua
\value [since 6.5] Rajasthani
\value RhaetoRomance Obsolete, please use Romansh
+ \value [since 6.6] Rohingya
\value Romanian
\value Romansh
\value Rombo
@@ -408,6 +414,7 @@
\value [since 6.5] TokiPona
\value [since 5.7] TokPisin
\value Tongan
+ \value [since 6.6] Torwali
\value Tsonga
\value Tswana
\value Turkish
@@ -424,6 +431,7 @@
\value Uzbek
\value Vai
\value Venda
+ \value [since 6.7] Venetian
\value Vietnamese
\value Volapuk
\value Vunjo
@@ -814,6 +822,7 @@
\value GujaratiScript
\value GurmukhiScript
\value [since 5.1] HangulScript
+ \value [since 6.6] HanifiScript
\value [since 5.1] HanScript
\value [since 5.1] HanunooScript
\value [since 5.7] HanWithBopomofoScript
@@ -1145,7 +1154,7 @@
*/
/*!
- \fn QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const
+ \fn QVariant QSystemLocale::query(QueryType type, QVariant &&in = QVariant()) const
Generic query method for locale data. Provides indirection.
Denotes the \a type of the query
diff --git a/src/corelib/text/qlocale_data_p.h b/src/corelib/text/qlocale_data_p.h
index 7780e4300f..6175398dd9 100644
--- a/src/corelib/text/qlocale_data_p.h
+++ b/src/corelib/text/qlocale_data_p.h
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: Unicode-3.0
#ifndef QLOCALE_DATA_P_H
#define QLOCALE_DATA_P_H
@@ -15,15 +15,19 @@
// We mean it.
//
-#include <array>
#include <QtCore/qendian.h>
-#include <QtCore/private/qglobal_p.h>
+#include <QtCore/private/qlocale_p.h>
+
+#include <array>
+#include <cstring> // std::memcmp
QT_BEGIN_NAMESPACE
-/* This part of the file isn't generated, but written by hand since
- * Unicode CLDR doesn't contain measurement system information.
- */
+/* This part of the file isn't generated, but written by hand. Unicode CLDR's
+ information about measurement systems doesn't say which to use by default in
+ each locale. Even if it did, adding another entry in every locale's row of
+ locale_data[] would take up much more memory than the small table below.
+*/
struct TerritoryLanguage
{
quint16 languageId;
@@ -74,8 +78,8 @@ struct LanguageCodeEntry {
// GENERATED PART STARTS HERE
/*
- This part of the file was generated on 2023-03-06 from the
- Common Locale Data Repository v42
+ This part of the file was generated on 2024-04-04 from the
+ Common Locale Data Repository v44.1
http://www.unicode.org/cldr/
@@ -220,7 +224,6 @@ static constexpr QLocaleId likely_subtags[] = {
{ 102, 0, 0 }, { 102, 66, 248 }, // haw -> haw_Latn_US
{ 103, 0, 0 }, { 103, 47, 116 }, // he -> he_Hebr_IL
{ 104, 0, 0 }, { 104, 66, 162 }, // hz -> hz_Latn_NA
- { 105, 66, 0 }, { 105, 66, 110 }, // hi_Latn -> hi_Latn_IN
{ 105, 0, 0 }, { 105, 29, 110 }, // hi -> hi_Deva_IN
{ 106, 0, 0 }, { 106, 66, 182 }, // ho -> ho_Latn_PG
{ 107, 0, 0 }, { 107, 66, 108 }, // hu -> hu_Latn_HU
@@ -231,6 +234,7 @@ static constexpr QLocaleId likely_subtags[] = {
{ 112, 0, 0 }, { 112, 66, 111 }, // id -> id_Latn_ID
{ 113, 0, 0 }, { 113, 27, 193 }, // inh -> inh_Cyrl_RU
{ 114, 0, 0 }, { 114, 66, 258 }, // ia -> ia_Latn_001
+ { 115, 0, 0 }, { 115, 66, 75 }, // ie -> ie_Latn_EE
{ 116, 0, 0 }, { 116, 18, 41 }, // iu -> iu_Cans_CA
{ 117, 0, 0 }, { 117, 66, 248 }, // ik -> ik_Latn_US
{ 118, 0, 0 }, { 118, 66, 114 }, // ga -> ga_Latn_IE
@@ -246,7 +250,8 @@ static constexpr QLocaleId likely_subtags[] = {
{ 128, 0, 0 }, { 128, 66, 124 }, // kln -> kln_Latn_KE
{ 129, 0, 0 }, { 129, 66, 124 }, // kam -> kam_Latn_KE
{ 130, 0, 0 }, { 130, 56, 110 }, // kn -> kn_Knda_IN
- { 131, 0, 0 }, { 131, 66, 0 }, // kr -> kr_Latn
+ { 131, 4, 0 }, { 131, 4, 169 }, // kr_Arab -> kr_Arab_NG
+ { 131, 0, 0 }, { 131, 66, 169 }, // kr -> kr_Latn_NG
{ 132, 0, 0 }, { 132, 4, 110 }, // ks -> ks_Arab_IN
{ 133, 0, 1 }, { 133, 4, 1 }, // kk_AF -> kk_Arab_AF
{ 133, 0, 50 }, { 133, 4, 50 }, // kk_CN -> kk_Arab_CN
@@ -345,7 +350,6 @@ static constexpr QLocaleId likely_subtags[] = {
{ 211, 0, 0 }, { 211, 66, 219 }, // nus -> nus_Latn_SS
{ 212, 0, 0 }, { 212, 66, 142 }, // ny -> ny_Latn_MW
{ 213, 0, 0 }, { 213, 66, 243 }, // nyn -> nyn_Latn_UG
- { 214, 0, 220 }, { 214, 66, 220 }, // oc_ES -> oc_Latn_ES
{ 214, 0, 0 }, { 214, 66, 84 }, // oc -> oc_Latn_FR
{ 215, 0, 0 }, { 215, 91, 110 }, // or -> or_Orya_IN
{ 216, 0, 0 }, { 216, 18, 41 }, // oj -> oj_Cans_CA
@@ -358,13 +362,20 @@ static constexpr QLocaleId likely_subtags[] = {
{ 223, 109, 0 }, { 223, 109, 50 }, // pal_Phlp -> pal_Phlp_CN
{ 223, 0, 0 }, { 223, 50, 112 }, // pal -> pal_Phli_IR
{ 224, 0, 0 }, { 224, 66, 179 }, // pau -> pau_Latn_PW
- { 226, 0, 0 }, { 226, 66, 13 }, // pap -> pap_Latn_AW
+ { 225, 14, 0 }, { 225, 14, 110 }, // pi_Brah -> pi_Brah_IN
+ { 225, 29, 0 }, { 225, 29, 110 }, // pi_Deva -> pi_Deva_IN
+ { 225, 59, 0 }, { 225, 59, 110 }, // pi_Khar -> pi_Khar_IN
+ { 225, 60, 0 }, { 225, 60, 110 }, // pi_Khmr -> pi_Khmr_IN
+ { 225, 86, 0 }, { 225, 86, 110 }, // pi_Mymr -> pi_Mymr_IN
+ { 225, 133, 0 }, { 225, 133, 110 }, // pi_Thai -> pi_Thai_IN
+ { 225, 0, 0 }, { 225, 119, 110 }, // pi -> pi_Sinh_IN
+ { 226, 0, 0 }, { 226, 66, 62 }, // pap -> pap_Latn_CW
{ 227, 0, 0 }, { 227, 4, 1 }, // ps -> ps_Arab_AF
{ 228, 0, 0 }, { 228, 4, 112 }, // fa -> fa_Arab_IR
{ 229, 0, 0 }, { 229, 107, 132 }, // phn -> phn_Phnx_LB
{ 230, 0, 0 }, { 230, 66, 187 }, // pl -> pl_Latn_PL
{ 231, 0, 0 }, { 231, 66, 32 }, // pt -> pt_Latn_BR
- { 232, 0, 0 }, { 232, 66, 258 }, // prg -> prg_Latn_001
+ { 232, 0, 0 }, { 232, 66, 187 }, // prg -> prg_Latn_PL
{ 233, 0, 178 }, { 233, 4, 178 }, // pa_PK -> pa_Arab_PK
{ 233, 4, 0 }, { 233, 4, 178 }, // pa_Arab -> pa_Arab_PK
{ 233, 0, 0 }, { 233, 41, 110 }, // pa -> pa_Guru_IN
@@ -473,7 +484,7 @@ static constexpr QLocaleId likely_subtags[] = {
{ 320, 0, 0 }, { 320, 66, 206 }, // wo -> wo_Latn_SN
{ 321, 0, 0 }, { 321, 66, 216 }, // xh -> xh_Latn_ZA
{ 322, 0, 0 }, { 322, 66, 40 }, // yav -> yav_Latn_CM
- { 323, 0, 0 }, { 323, 47, 258 }, // yi -> yi_Hebr_001
+ { 323, 0, 0 }, { 323, 47, 244 }, // yi -> yi_Hebr_UA
{ 324, 0, 0 }, { 324, 66, 169 }, // yo -> yo_Latn_NG
{ 325, 0, 0 }, { 325, 66, 170 }, // dje -> dje_Latn_NE
{ 326, 0, 0 }, { 326, 66, 50 }, // za -> za_Latn_CN
@@ -487,245 +498,457 @@ static constexpr QLocaleId likely_subtags[] = {
{ 334, 0, 0 }, { 334, 66, 258 }, // tok -> tok_Latn_001
{ 335, 0, 0 }, { 335, 66, 214 }, // pis -> pis_Latn_SB
{ 336, 0, 0 }, { 336, 66, 169 }, // ann -> ann_Latn_NG
+ { 337, 0, 0 }, { 337, 4, 178 }, // bal -> bal_Arab_PK
+ { 338, 0, 0 }, { 338, 66, 117 }, // lij -> lij_Latn_IT
+ { 339, 0, 0 }, { 339, 142, 161 }, // rhg -> rhg_Rohg_MM
+ { 340, 0, 0 }, { 340, 4, 178 }, // trw -> trw_Arab_PK
+ { 341, 0, 0 }, { 341, 66, 25 }, // blo -> blo_Latn_BJ
+ { 342, 0, 0 }, { 342, 29, 110 }, // xnr -> xnr_Deva_IN
+ { 343, 0, 0 }, { 343, 66, 117 }, // vec -> vec_Latn_IT
+ { 0, 4, 1 }, { 228, 4, 1 }, // und_Arab_AF -> fa_Arab_AF
{ 0, 66, 1 }, { 299, 66, 1 }, // und_Latn_AF -> tk_Latn_AF
{ 0, 0, 1 }, { 228, 4, 1 }, // und_AF -> fa_Arab_AF
+ { 0, 66, 2 }, { 275, 66, 2 }, // und_Latn_AX -> sv_Latn_AX
{ 0, 0, 2 }, { 275, 66, 2 }, // und_AX -> sv_Latn_AX
{ 0, 27, 3 }, { 169, 27, 3 }, // und_Cyrl_AL -> mk_Cyrl_AL
+ { 0, 66, 3 }, { 9, 66, 3 }, // und_Latn_AL -> sq_Latn_AL
{ 0, 0, 3 }, { 9, 66, 3 }, // und_AL -> sq_Latn_AL
{ 0, 66, 4 }, { 85, 66, 4 }, // und_Latn_DZ -> fr_Latn_DZ
{ 0, 0, 4 }, { 14, 4, 4 }, // und_DZ -> ar_Arab_DZ
+ { 0, 66, 5 }, { 244, 66, 5 }, // und_Latn_AS -> sm_Latn_AS
{ 0, 0, 5 }, { 244, 66, 5 }, // und_AS -> sm_Latn_AS
+ { 0, 66, 6 }, { 48, 66, 6 }, // und_Latn_AD -> ca_Latn_AD
{ 0, 0, 6 }, { 48, 66, 6 }, // und_AD -> ca_Latn_AD
+ { 0, 66, 7 }, { 231, 66, 7 }, // und_Latn_AO -> pt_Latn_AO
{ 0, 0, 7 }, { 231, 66, 7 }, // und_AO -> pt_Latn_AO
- { 0, 0, 9 }, { 0, 66, 9 }, // und_AQ -> und_Latn_AQ
+ { 0, 0, 8 }, { 75, 66, 8 }, // und_AI -> en_Latn_AI
+ { 0, 0, 9 }, { 75, 66, 9 }, // und_AQ -> en_Latn_AQ
+ { 0, 0, 10 }, { 75, 66, 10 }, // und_AG -> en_Latn_AG
+ { 0, 66, 11 }, { 270, 66, 11 }, // und_Latn_AR -> es_Latn_AR
{ 0, 0, 11 }, { 270, 66, 11 }, // und_AR -> es_Latn_AR
{ 0, 66, 12 }, { 148, 66, 12 }, // und_Latn_AM -> ku_Latn_AM
{ 0, 0, 12 }, { 17, 5, 12 }, // und_AM -> hy_Armn_AM
+ { 0, 66, 13 }, { 72, 66, 13 }, // und_Latn_AW -> nl_Latn_AW
{ 0, 0, 13 }, { 72, 66, 13 }, // und_AW -> nl_Latn_AW
+ { 0, 0, 14 }, { 75, 66, 14 }, // und_AC -> en_Latn_AC
+ { 0, 0, 15 }, { 75, 66, 15 }, // und_AU -> en_Latn_AU
+ { 0, 66, 16 }, { 94, 66, 16 }, // und_Latn_AT -> de_Latn_AT
{ 0, 0, 16 }, { 94, 66, 16 }, // und_AT -> de_Latn_AT
+ { 0, 66, 17 }, { 25, 66, 17 }, // und_Latn_AZ -> az_Latn_AZ
{ 0, 0, 17 }, { 25, 66, 17 }, // und_AZ -> az_Latn_AZ
+ { 0, 0, 18 }, { 75, 66, 18 }, // und_BS -> en_Latn_BS
{ 0, 0, 19 }, { 14, 4, 19 }, // und_BH -> ar_Arab_BH
{ 0, 0, 20 }, { 30, 9, 20 }, // und_BD -> bn_Beng_BD
+ { 0, 0, 21 }, { 75, 66, 21 }, // und_BB -> en_Latn_BB
+ { 0, 27, 22 }, { 35, 27, 22 }, // und_Cyrl_BY -> be_Cyrl_BY
{ 0, 0, 22 }, { 35, 27, 22 }, // und_BY -> be_Cyrl_BY
+ { 0, 66, 23 }, { 72, 66, 23 }, // und_Latn_BE -> nl_Latn_BE
{ 0, 0, 23 }, { 72, 66, 23 }, // und_BE -> nl_Latn_BE
+ { 0, 0, 24 }, { 75, 66, 24 }, // und_BZ -> en_Latn_BZ
+ { 0, 66, 25 }, { 85, 66, 25 }, // und_Latn_BJ -> fr_Latn_BJ
{ 0, 0, 25 }, { 85, 66, 25 }, // und_BJ -> fr_Latn_BJ
+ { 0, 0, 26 }, { 75, 66, 26 }, // und_BM -> en_Latn_BM
{ 0, 29, 27 }, { 199, 29, 27 }, // und_Deva_BT -> ne_Deva_BT
+ { 0, 134, 27 }, { 73, 134, 27 }, // und_Tibt_BT -> dz_Tibt_BT
{ 0, 0, 27 }, { 73, 134, 27 }, // und_BT -> dz_Tibt_BT
+ { 0, 66, 28 }, { 270, 66, 28 }, // und_Latn_BO -> es_Latn_BO
{ 0, 0, 28 }, { 270, 66, 28 }, // und_BO -> es_Latn_BO
{ 0, 27, 29 }, { 252, 27, 29 }, // und_Cyrl_BA -> sr_Cyrl_BA
+ { 0, 66, 29 }, { 42, 66, 29 }, // und_Latn_BA -> bs_Latn_BA
{ 0, 0, 29 }, { 42, 66, 29 }, // und_BA -> bs_Latn_BA
- { 0, 0, 31 }, { 0, 66, 31 }, // und_BV -> und_Latn_BV
+ { 0, 0, 30 }, { 75, 66, 30 }, // und_BW -> en_Latn_BW
+ { 0, 0, 31 }, { 75, 66, 31 }, // und_BV -> en_Latn_BV
+ { 0, 66, 32 }, { 231, 66, 32 }, // und_Latn_BR -> pt_Latn_BR
{ 0, 0, 32 }, { 231, 66, 32 }, // und_BR -> pt_Latn_BR
+ { 0, 0, 33 }, { 75, 66, 33 }, // und_IO -> en_Latn_IO
+ { 0, 0, 34 }, { 75, 66, 34 }, // und_VG -> en_Latn_VG
+ { 0, 66, 35 }, { 176, 66, 35 }, // und_Latn_BN -> ms_Latn_BN
{ 0, 0, 35 }, { 176, 66, 35 }, // und_BN -> ms_Latn_BN
+ { 0, 27, 36 }, { 45, 27, 36 }, // und_Cyrl_BG -> bg_Cyrl_BG
{ 0, 0, 36 }, { 45, 27, 36 }, // und_BG -> bg_Cyrl_BG
+ { 0, 66, 37 }, { 85, 66, 37 }, // und_Latn_BF -> fr_Latn_BF
{ 0, 0, 37 }, { 85, 66, 37 }, // und_BF -> fr_Latn_BF
+ { 0, 66, 38 }, { 238, 66, 38 }, // und_Latn_BI -> rn_Latn_BI
{ 0, 0, 38 }, { 238, 66, 38 }, // und_BI -> rn_Latn_BI
{ 0, 0, 39 }, { 135, 60, 39 }, // und_KH -> km_Khmr_KH
+ { 0, 66, 40 }, { 85, 66, 40 }, // und_Latn_CM -> fr_Latn_CM
{ 0, 0, 40 }, { 85, 66, 40 }, // und_CM -> fr_Latn_CM
{ 0, 137, 41 }, { 47, 137, 41 }, // und_Hant_CA -> yue_Hant_CA
+ { 0, 0, 41 }, { 75, 66, 41 }, // und_CA -> en_Latn_CA
+ { 0, 66, 42 }, { 270, 66, 42 }, // und_Latn_IC -> es_Latn_IC
{ 0, 0, 42 }, { 270, 66, 42 }, // und_IC -> es_Latn_IC
+ { 0, 66, 43 }, { 231, 66, 43 }, // und_Latn_CV -> pt_Latn_CV
{ 0, 0, 43 }, { 231, 66, 43 }, // und_CV -> pt_Latn_CV
+ { 0, 66, 44 }, { 226, 66, 44 }, // und_Latn_BQ -> pap_Latn_BQ
{ 0, 0, 44 }, { 226, 66, 44 }, // und_BQ -> pap_Latn_BQ
+ { 0, 0, 45 }, { 75, 66, 45 }, // und_KY -> en_Latn_KY
+ { 0, 66, 46 }, { 85, 66, 46 }, // und_Latn_CF -> fr_Latn_CF
{ 0, 0, 46 }, { 85, 66, 46 }, // und_CF -> fr_Latn_CF
+ { 0, 66, 47 }, { 270, 66, 47 }, // und_Latn_EA -> es_Latn_EA
{ 0, 0, 47 }, { 270, 66, 47 }, // und_EA -> es_Latn_EA
+ { 0, 66, 48 }, { 85, 66, 48 }, // und_Latn_TD -> fr_Latn_TD
{ 0, 0, 48 }, { 85, 66, 48 }, // und_TD -> fr_Latn_TD
+ { 0, 66, 49 }, { 270, 66, 49 }, // und_Latn_CL -> es_Latn_CL
{ 0, 0, 49 }, { 270, 66, 49 }, // und_CL -> es_Latn_CL
{ 0, 4, 50 }, { 306, 4, 50 }, // und_Arab_CN -> ug_Arab_CN
{ 0, 66, 50 }, { 326, 66, 50 }, // und_Latn_CN -> za_Latn_CN
{ 0, 0, 50 }, { 58, 118, 50 }, // und_CN -> zh_Hans_CN
- { 0, 0, 52 }, { 0, 66, 52 }, // und_CP -> und_Latn_CP
+ { 0, 0, 51 }, { 75, 66, 51 }, // und_CX -> en_Latn_CX
+ { 0, 0, 52 }, { 75, 66, 52 }, // und_CP -> en_Latn_CP
{ 0, 4, 53 }, { 176, 4, 53 }, // und_Arab_CC -> ms_Arab_CC
+ { 0, 0, 53 }, { 176, 4, 53 }, // und_CC -> ms_Arab_CC
+ { 0, 66, 54 }, { 270, 66, 54 }, // und_Latn_CO -> es_Latn_CO
{ 0, 0, 54 }, { 270, 66, 54 }, // und_CO -> es_Latn_CO
{ 0, 66, 55 }, { 85, 66, 55 }, // und_Latn_KM -> fr_Latn_KM
{ 0, 0, 55 }, { 14, 4, 55 }, // und_KM -> ar_Arab_KM
+ { 0, 66, 56 }, { 85, 66, 56 }, // und_Latn_CG -> fr_Latn_CG
{ 0, 0, 56 }, { 85, 66, 56 }, // und_CG -> fr_Latn_CG
+ { 0, 66, 57 }, { 273, 66, 57 }, // und_Latn_CD -> sw_Latn_CD
{ 0, 0, 57 }, { 273, 66, 57 }, // und_CD -> sw_Latn_CD
+ { 0, 0, 58 }, { 75, 66, 58 }, // und_CK -> en_Latn_CK
+ { 0, 66, 59 }, { 270, 66, 59 }, // und_Latn_CR -> es_Latn_CR
{ 0, 0, 59 }, { 270, 66, 59 }, // und_CR -> es_Latn_CR
+ { 0, 66, 60 }, { 66, 66, 60 }, // und_Latn_HR -> hr_Latn_HR
{ 0, 0, 60 }, { 66, 66, 60 }, // und_HR -> hr_Latn_HR
+ { 0, 66, 61 }, { 270, 66, 61 }, // und_Latn_CU -> es_Latn_CU
{ 0, 0, 61 }, { 270, 66, 61 }, // und_CU -> es_Latn_CU
+ { 0, 66, 62 }, { 226, 66, 62 }, // und_Latn_CW -> pap_Latn_CW
{ 0, 0, 62 }, { 226, 66, 62 }, // und_CW -> pap_Latn_CW
{ 0, 66, 63 }, { 298, 66, 63 }, // und_Latn_CY -> tr_Latn_CY
{ 0, 0, 63 }, { 96, 39, 63 }, // und_CY -> el_Grek_CY
+ { 0, 66, 64 }, { 67, 66, 64 }, // und_Latn_CZ -> cs_Latn_CZ
{ 0, 0, 64 }, { 67, 66, 64 }, // und_CZ -> cs_Latn_CZ
+ { 0, 66, 65 }, { 68, 66, 65 }, // und_Latn_DK -> da_Latn_DK
{ 0, 0, 65 }, { 68, 66, 65 }, // und_DK -> da_Latn_DK
+ { 0, 0, 66 }, { 75, 66, 66 }, // und_DG -> en_Latn_DG
+ { 0, 66, 67 }, { 3, 66, 67 }, // und_Latn_DJ -> aa_Latn_DJ
{ 0, 0, 67 }, { 3, 66, 67 }, // und_DJ -> aa_Latn_DJ
+ { 0, 0, 68 }, { 75, 66, 68 }, // und_DM -> en_Latn_DM
+ { 0, 66, 69 }, { 270, 66, 69 }, // und_Latn_DO -> es_Latn_DO
{ 0, 0, 69 }, { 270, 66, 69 }, // und_DO -> es_Latn_DO
+ { 0, 66, 70 }, { 270, 66, 70 }, // und_Latn_EC -> es_Latn_EC
{ 0, 0, 70 }, { 270, 66, 70 }, // und_EC -> es_Latn_EC
{ 0, 0, 71 }, { 14, 4, 71 }, // und_EG -> ar_Arab_EG
+ { 0, 66, 72 }, { 270, 66, 72 }, // und_Latn_SV -> es_Latn_SV
{ 0, 0, 72 }, { 270, 66, 72 }, // und_SV -> es_Latn_SV
+ { 0, 66, 73 }, { 270, 66, 73 }, // und_Latn_GQ -> es_Latn_GQ
{ 0, 0, 73 }, { 270, 66, 73 }, // und_GQ -> es_Latn_GQ
+ { 0, 33, 74 }, { 292, 33, 74 }, // und_Ethi_ER -> ti_Ethi_ER
{ 0, 0, 74 }, { 292, 33, 74 }, // und_ER -> ti_Ethi_ER
+ { 0, 66, 75 }, { 78, 66, 75 }, // und_Latn_EE -> et_Latn_EE
{ 0, 0, 75 }, { 78, 66, 75 }, // und_EE -> et_Latn_EE
+ { 0, 0, 76 }, { 75, 66, 76 }, // und_SZ -> en_Latn_SZ
{ 0, 66, 77 }, { 75, 66, 77 }, // und_Latn_ET -> en_Latn_ET
{ 0, 0, 77 }, { 11, 33, 77 }, // und_ET -> am_Ethi_ET
- { 0, 0, 78 }, { 239, 27, 193 }, // und_150 -> ru_Cyrl_RU
- { 0, 0, 79 }, { 75, 66, 114 }, // und_EU -> en_Latn_IE
+ { 0, 0, 80 }, { 75, 66, 80 }, // und_FK -> en_Latn_FK
+ { 0, 66, 81 }, { 81, 66, 81 }, // und_Latn_FO -> fo_Latn_FO
{ 0, 0, 81 }, { 81, 66, 81 }, // und_FO -> fo_Latn_FO
+ { 0, 0, 82 }, { 75, 66, 82 }, // und_FJ -> en_Latn_FJ
+ { 0, 66, 83 }, { 84, 66, 83 }, // und_Latn_FI -> fi_Latn_FI
{ 0, 0, 83 }, { 84, 66, 83 }, // und_FI -> fi_Latn_FI
+ { 0, 66, 84 }, { 85, 66, 84 }, // und_Latn_FR -> fr_Latn_FR
{ 0, 0, 84 }, { 85, 66, 84 }, // und_FR -> fr_Latn_FR
+ { 0, 66, 85 }, { 85, 66, 85 }, // und_Latn_GF -> fr_Latn_GF
{ 0, 0, 85 }, { 85, 66, 85 }, // und_GF -> fr_Latn_GF
+ { 0, 66, 86 }, { 85, 66, 86 }, // und_Latn_PF -> fr_Latn_PF
{ 0, 0, 86 }, { 85, 66, 86 }, // und_PF -> fr_Latn_PF
+ { 0, 66, 87 }, { 85, 66, 87 }, // und_Latn_TF -> fr_Latn_TF
{ 0, 0, 87 }, { 85, 66, 87 }, // und_TF -> fr_Latn_TF
+ { 0, 66, 88 }, { 85, 66, 88 }, // und_Latn_GA -> fr_Latn_GA
{ 0, 0, 88 }, { 85, 66, 88 }, // und_GA -> fr_Latn_GA
+ { 0, 0, 89 }, { 75, 66, 89 }, // und_GM -> en_Latn_GM
{ 0, 27, 90 }, { 2, 27, 90 }, // und_Cyrl_GE -> ab_Cyrl_GE
{ 0, 66, 90 }, { 148, 66, 90 }, // und_Latn_GE -> ku_Latn_GE
{ 0, 0, 90 }, { 93, 35, 90 }, // und_GE -> ka_Geor_GE
+ { 0, 66, 91 }, { 94, 66, 91 }, // und_Latn_DE -> de_Latn_DE
{ 0, 0, 91 }, { 94, 66, 91 }, // und_DE -> de_Latn_DE
+ { 0, 66, 92 }, { 6, 66, 92 }, // und_Latn_GH -> ak_Latn_GH
{ 0, 0, 92 }, { 6, 66, 92 }, // und_GH -> ak_Latn_GH
+ { 0, 0, 93 }, { 75, 66, 93 }, // und_GI -> en_Latn_GI
{ 0, 27, 94 }, { 169, 27, 94 }, // und_Cyrl_GR -> mk_Cyrl_GR
{ 0, 0, 94 }, { 96, 39, 94 }, // und_GR -> el_Grek_GR
+ { 0, 66, 95 }, { 127, 66, 95 }, // und_Latn_GL -> kl_Latn_GL
{ 0, 0, 95 }, { 127, 66, 95 }, // und_GL -> kl_Latn_GL
+ { 0, 0, 96 }, { 75, 66, 96 }, // und_GD -> en_Latn_GD
+ { 0, 66, 97 }, { 85, 66, 97 }, // und_Latn_GP -> fr_Latn_GP
{ 0, 0, 97 }, { 85, 66, 97 }, // und_GP -> fr_Latn_GP
+ { 0, 0, 98 }, { 75, 66, 98 }, // und_GU -> en_Latn_GU
+ { 0, 66, 99 }, { 270, 66, 99 }, // und_Latn_GT -> es_Latn_GT
{ 0, 0, 99 }, { 270, 66, 99 }, // und_GT -> es_Latn_GT
+ { 0, 0, 100 }, { 75, 66, 100 }, // und_GG -> en_Latn_GG
+ { 0, 66, 101 }, { 231, 66, 101 }, // und_Latn_GW -> pt_Latn_GW
{ 0, 0, 101 }, { 231, 66, 101 }, // und_GW -> pt_Latn_GW
+ { 0, 66, 102 }, { 85, 66, 102 }, // und_Latn_GN -> fr_Latn_GN
{ 0, 0, 102 }, { 85, 66, 102 }, // und_GN -> fr_Latn_GN
+ { 0, 0, 103 }, { 75, 66, 103 }, // und_GY -> en_Latn_GY
+ { 0, 66, 104 }, { 100, 66, 104 }, // und_Latn_HT -> ht_Latn_HT
{ 0, 0, 104 }, { 100, 66, 104 }, // und_HT -> ht_Latn_HT
- { 0, 0, 105 }, { 0, 66, 105 }, // und_HM -> und_Latn_HM
+ { 0, 0, 105 }, { 75, 66, 105 }, // und_HM -> en_Latn_HM
+ { 0, 66, 106 }, { 270, 66, 106 }, // und_Latn_HN -> es_Latn_HN
{ 0, 0, 106 }, { 270, 66, 106 }, // und_HN -> es_Latn_HN
{ 0, 0, 107 }, { 58, 137, 107 }, // und_HK -> zh_Hant_HK
+ { 0, 66, 108 }, { 107, 66, 108 }, // und_Latn_HU -> hu_Latn_HU
{ 0, 0, 108 }, { 107, 66, 108 }, // und_HU -> hu_Latn_HU
+ { 0, 66, 109 }, { 108, 66, 109 }, // und_Latn_IS -> is_Latn_IS
{ 0, 0, 109 }, { 108, 66, 109 }, // und_IS -> is_Latn_IS
{ 0, 4, 110 }, { 305, 4, 110 }, // und_Arab_IN -> ur_Arab_IN
{ 0, 0, 110 }, { 105, 29, 110 }, // und_IN -> hi_Deva_IN
{ 0, 4, 111 }, { 176, 4, 111 }, // und_Arab_ID -> ms_Arab_ID
+ { 0, 66, 111 }, { 112, 66, 111 }, // und_Latn_ID -> id_Latn_ID
{ 0, 0, 111 }, { 112, 66, 111 }, // und_ID -> id_Latn_ID
+ { 0, 4, 112 }, { 228, 4, 112 }, // und_Arab_IR -> fa_Arab_IR
{ 0, 66, 112 }, { 299, 66, 112 }, // und_Latn_IR -> tk_Latn_IR
{ 0, 0, 112 }, { 228, 4, 112 }, // und_IR -> fa_Arab_IR
{ 0, 0, 113 }, { 14, 4, 113 }, // und_IQ -> ar_Arab_IQ
+ { 0, 0, 114 }, { 75, 66, 114 }, // und_IE -> en_Latn_IE
+ { 0, 0, 115 }, { 75, 66, 115 }, // und_IM -> en_Latn_IM
{ 0, 0, 116 }, { 103, 47, 116 }, // und_IL -> he_Hebr_IL
+ { 0, 66, 117 }, { 119, 66, 117 }, // und_Latn_IT -> it_Latn_IT
{ 0, 0, 117 }, { 119, 66, 117 }, // und_IT -> it_Latn_IT
+ { 0, 66, 118 }, { 85, 66, 118 }, // und_Latn_CI -> fr_Latn_CI
{ 0, 0, 118 }, { 85, 66, 118 }, // und_CI -> fr_Latn_CI
+ { 0, 0, 119 }, { 75, 66, 119 }, // und_JM -> en_Latn_JM
{ 0, 0, 120 }, { 120, 53, 120 }, // und_JP -> ja_Jpan_JP
+ { 0, 0, 121 }, { 75, 66, 121 }, // und_JE -> en_Latn_JE
{ 0, 0, 122 }, { 14, 4, 122 }, // und_JO -> ar_Arab_JO
{ 0, 0, 123 }, { 239, 27, 123 }, // und_KZ -> ru_Cyrl_KZ
+ { 0, 66, 124 }, { 273, 66, 124 }, // und_Latn_KE -> sw_Latn_KE
{ 0, 0, 124 }, { 273, 66, 124 }, // und_KE -> sw_Latn_KE
+ { 0, 0, 125 }, { 75, 66, 125 }, // und_KI -> en_Latn_KI
{ 0, 27, 126 }, { 252, 27, 126 }, // und_Cyrl_XK -> sr_Cyrl_XK
+ { 0, 66, 126 }, { 9, 66, 126 }, // und_Latn_XK -> sq_Latn_XK
{ 0, 0, 126 }, { 9, 66, 126 }, // und_XK -> sq_Latn_XK
{ 0, 0, 127 }, { 14, 4, 127 }, // und_KW -> ar_Arab_KW
+ { 0, 27, 128 }, { 150, 27, 128 }, // und_Cyrl_KG -> ky_Cyrl_KG
{ 0, 0, 128 }, { 150, 27, 128 }, // und_KG -> ky_Cyrl_KG
{ 0, 0, 129 }, { 153, 65, 129 }, // und_LA -> lo_Laoo_LA
+ { 0, 66, 130 }, { 270, 66, 130 }, // und_Latn_419 -> es_Latn_419
{ 0, 0, 130 }, { 270, 66, 130 }, // und_419 -> es_Latn_419
+ { 0, 66, 131 }, { 155, 66, 131 }, // und_Latn_LV -> lv_Latn_LV
{ 0, 0, 131 }, { 155, 66, 131 }, // und_LV -> lv_Latn_LV
{ 0, 0, 132 }, { 14, 4, 132 }, // und_LB -> ar_Arab_LB
+ { 0, 66, 133 }, { 268, 66, 133 }, // und_Latn_LS -> st_Latn_LS
{ 0, 0, 133 }, { 268, 66, 133 }, // und_LS -> st_Latn_LS
+ { 0, 0, 134 }, { 75, 66, 134 }, // und_LR -> en_Latn_LR
{ 0, 0, 135 }, { 14, 4, 135 }, // und_LY -> ar_Arab_LY
+ { 0, 66, 136 }, { 94, 66, 136 }, // und_Latn_LI -> de_Latn_LI
{ 0, 0, 136 }, { 94, 66, 136 }, // und_LI -> de_Latn_LI
+ { 0, 66, 137 }, { 160, 66, 137 }, // und_Latn_LT -> lt_Latn_LT
{ 0, 0, 137 }, { 160, 66, 137 }, // und_LT -> lt_Latn_LT
+ { 0, 66, 138 }, { 85, 66, 138 }, // und_Latn_LU -> fr_Latn_LU
{ 0, 0, 138 }, { 85, 66, 138 }, // und_LU -> fr_Latn_LU
{ 0, 66, 139 }, { 231, 66, 139 }, // und_Latn_MO -> pt_Latn_MO
{ 0, 0, 139 }, { 58, 137, 139 }, // und_MO -> zh_Hant_MO
+ { 0, 27, 140 }, { 169, 27, 140 }, // und_Cyrl_MK -> mk_Cyrl_MK
{ 0, 66, 140 }, { 9, 66, 140 }, // und_Latn_MK -> sq_Latn_MK
{ 0, 0, 140 }, { 169, 27, 140 }, // und_MK -> mk_Cyrl_MK
+ { 0, 66, 141 }, { 174, 66, 141 }, // und_Latn_MG -> mg_Latn_MG
{ 0, 0, 141 }, { 174, 66, 141 }, // und_MG -> mg_Latn_MG
+ { 0, 0, 142 }, { 75, 66, 142 }, // und_MW -> en_Latn_MW
+ { 0, 66, 143 }, { 176, 66, 143 }, // und_Latn_MY -> ms_Latn_MY
{ 0, 0, 143 }, { 176, 66, 143 }, // und_MY -> ms_Latn_MY
{ 0, 0, 144 }, { 69, 132, 144 }, // und_MV -> dv_Thaa_MV
+ { 0, 66, 145 }, { 28, 66, 145 }, // und_Latn_ML -> bm_Latn_ML
{ 0, 0, 145 }, { 28, 66, 145 }, // und_ML -> bm_Latn_ML
+ { 0, 66, 146 }, { 177, 66, 146 }, // und_Latn_MT -> mt_Latn_MT
{ 0, 0, 146 }, { 177, 66, 146 }, // und_MT -> mt_Latn_MT
+ { 0, 0, 147 }, { 75, 66, 147 }, // und_MH -> en_Latn_MH
+ { 0, 66, 148 }, { 85, 66, 148 }, // und_Latn_MQ -> fr_Latn_MQ
{ 0, 0, 148 }, { 85, 66, 148 }, // und_MQ -> fr_Latn_MQ
{ 0, 66, 149 }, { 85, 66, 149 }, // und_Latn_MR -> fr_Latn_MR
{ 0, 0, 149 }, { 14, 4, 149 }, // und_MR -> ar_Arab_MR
{ 0, 4, 150 }, { 305, 4, 150 }, // und_Arab_MU -> ur_Arab_MU
{ 0, 29, 150 }, { 38, 29, 150 }, // und_Deva_MU -> bho_Deva_MU
+ { 0, 66, 150 }, { 192, 66, 150 }, // und_Latn_MU -> mfe_Latn_MU
{ 0, 0, 150 }, { 192, 66, 150 }, // und_MU -> mfe_Latn_MU
+ { 0, 66, 151 }, { 85, 66, 151 }, // und_Latn_YT -> fr_Latn_YT
{ 0, 0, 151 }, { 85, 66, 151 }, // und_YT -> fr_Latn_YT
+ { 0, 66, 152 }, { 270, 66, 152 }, // und_Latn_MX -> es_Latn_MX
{ 0, 0, 152 }, { 270, 66, 152 }, // und_MX -> es_Latn_MX
+ { 0, 0, 153 }, { 75, 66, 153 }, // und_FM -> en_Latn_FM
{ 0, 27, 154 }, { 303, 27, 154 }, // und_Cyrl_MD -> uk_Cyrl_MD
+ { 0, 66, 154 }, { 235, 66, 154 }, // und_Latn_MD -> ro_Latn_MD
{ 0, 0, 154 }, { 235, 66, 154 }, // und_MD -> ro_Latn_MD
+ { 0, 66, 155 }, { 85, 66, 155 }, // und_Latn_MC -> fr_Latn_MC
{ 0, 0, 155 }, { 85, 66, 155 }, // und_MC -> fr_Latn_MC
{ 0, 4, 156 }, { 133, 4, 156 }, // und_Arab_MN -> kk_Arab_MN
+ { 0, 27, 156 }, { 191, 27, 156 }, // und_Cyrl_MN -> mn_Cyrl_MN
{ 0, 0, 156 }, { 191, 27, 156 }, // und_MN -> mn_Cyrl_MN
+ { 0, 66, 157 }, { 252, 66, 157 }, // und_Latn_ME -> sr_Latn_ME
{ 0, 0, 157 }, { 252, 66, 157 }, // und_ME -> sr_Latn_ME
+ { 0, 0, 158 }, { 75, 66, 158 }, // und_MS -> en_Latn_MS
{ 0, 66, 159 }, { 85, 66, 159 }, // und_Latn_MA -> fr_Latn_MA
{ 0, 0, 159 }, { 14, 4, 159 }, // und_MA -> ar_Arab_MA
+ { 0, 66, 160 }, { 231, 66, 160 }, // und_Latn_MZ -> pt_Latn_MZ
{ 0, 0, 160 }, { 231, 66, 160 }, // und_MZ -> pt_Latn_MZ
+ { 0, 4, 161 }, { 339, 4, 161 }, // und_Arab_MM -> rhg_Arab_MM
{ 0, 0, 161 }, { 46, 86, 161 }, // und_MM -> my_Mymr_MM
+ { 0, 66, 162 }, { 4, 66, 162 }, // und_Latn_NA -> af_Latn_NA
{ 0, 0, 162 }, { 4, 66, 162 }, // und_NA -> af_Latn_NA
+ { 0, 0, 163 }, { 75, 66, 163 }, // und_NR -> en_Latn_NR
+ { 0, 29, 164 }, { 199, 29, 164 }, // und_Deva_NP -> ne_Deva_NP
{ 0, 0, 164 }, { 199, 29, 164 }, // und_NP -> ne_Deva_NP
+ { 0, 66, 165 }, { 72, 66, 165 }, // und_Latn_NL -> nl_Latn_NL
{ 0, 0, 165 }, { 72, 66, 165 }, // und_NL -> nl_Latn_NL
+ { 0, 66, 166 }, { 85, 66, 166 }, // und_Latn_NC -> fr_Latn_NC
{ 0, 0, 166 }, { 85, 66, 166 }, // und_NC -> fr_Latn_NC
+ { 0, 0, 167 }, { 75, 66, 167 }, // und_NZ -> en_Latn_NZ
+ { 0, 66, 168 }, { 270, 66, 168 }, // und_Latn_NI -> es_Latn_NI
{ 0, 0, 168 }, { 270, 66, 168 }, // und_NI -> es_Latn_NI
{ 0, 4, 169 }, { 101, 4, 169 }, // und_Arab_NG -> ha_Arab_NG
+ { 0, 0, 169 }, { 75, 66, 169 }, // und_NG -> en_Latn_NG
+ { 0, 66, 170 }, { 101, 66, 170 }, // und_Latn_NE -> ha_Latn_NE
{ 0, 0, 170 }, { 101, 66, 170 }, // und_NE -> ha_Latn_NE
+ { 0, 0, 171 }, { 75, 66, 171 }, // und_NU -> en_Latn_NU
+ { 0, 0, 172 }, { 75, 66, 172 }, // und_NF -> en_Latn_NF
+ { 0, 0, 173 }, { 75, 66, 173 }, // und_MP -> en_Latn_MP
{ 0, 0, 174 }, { 142, 63, 174 }, // und_KP -> ko_Kore_KP
+ { 0, 66, 175 }, { 209, 66, 175 }, // und_Latn_NO -> nb_Latn_NO
{ 0, 0, 175 }, { 209, 66, 175 }, // und_NO -> nb_Latn_NO
{ 0, 0, 176 }, { 14, 4, 176 }, // und_OM -> ar_Arab_OM
- { 0, 0, 177 }, { 75, 66, 66 }, // und_QO -> en_Latn_DG
{ 0, 4, 178 }, { 305, 4, 178 }, // und_Arab_PK -> ur_Arab_PK
{ 0, 0, 178 }, { 305, 4, 178 }, // und_PK -> ur_Arab_PK
+ { 0, 66, 179 }, { 224, 66, 179 }, // und_Latn_PW -> pau_Latn_PW
{ 0, 0, 179 }, { 224, 66, 179 }, // und_PW -> pau_Latn_PW
{ 0, 0, 180 }, { 14, 4, 180 }, // und_PS -> ar_Arab_PS
+ { 0, 66, 181 }, { 270, 66, 181 }, // und_Latn_PA -> es_Latn_PA
{ 0, 0, 181 }, { 270, 66, 181 }, // und_PA -> es_Latn_PA
+ { 0, 66, 182 }, { 294, 66, 182 }, // und_Latn_PG -> tpi_Latn_PG
{ 0, 0, 182 }, { 294, 66, 182 }, // und_PG -> tpi_Latn_PG
+ { 0, 66, 183 }, { 97, 66, 183 }, // und_Latn_PY -> gn_Latn_PY
{ 0, 0, 183 }, { 97, 66, 183 }, // und_PY -> gn_Latn_PY
+ { 0, 66, 184 }, { 270, 66, 184 }, // und_Latn_PE -> es_Latn_PE
{ 0, 0, 184 }, { 270, 66, 184 }, // und_PE -> es_Latn_PE
+ { 0, 66, 185 }, { 83, 66, 185 }, // und_Latn_PH -> fil_Latn_PH
{ 0, 0, 185 }, { 83, 66, 185 }, // und_PH -> fil_Latn_PH
+ { 0, 0, 186 }, { 75, 66, 186 }, // und_PN -> en_Latn_PN
+ { 0, 66, 187 }, { 230, 66, 187 }, // und_Latn_PL -> pl_Latn_PL
{ 0, 0, 187 }, { 230, 66, 187 }, // und_PL -> pl_Latn_PL
+ { 0, 66, 188 }, { 231, 66, 188 }, // und_Latn_PT -> pt_Latn_PT
{ 0, 0, 188 }, { 231, 66, 188 }, // und_PT -> pt_Latn_PT
+ { 0, 66, 189 }, { 270, 66, 189 }, // und_Latn_PR -> es_Latn_PR
{ 0, 0, 189 }, { 270, 66, 189 }, // und_PR -> es_Latn_PR
{ 0, 0, 190 }, { 14, 4, 190 }, // und_QA -> ar_Arab_QA
+ { 0, 66, 191 }, { 85, 66, 191 }, // und_Latn_RE -> fr_Latn_RE
{ 0, 0, 191 }, { 85, 66, 191 }, // und_RE -> fr_Latn_RE
{ 0, 27, 192 }, { 45, 27, 192 }, // und_Cyrl_RO -> bg_Cyrl_RO
+ { 0, 66, 192 }, { 235, 66, 192 }, // und_Latn_RO -> ro_Latn_RO
{ 0, 0, 192 }, { 235, 66, 192 }, // und_RO -> ro_Latn_RO
{ 0, 0, 193 }, { 239, 27, 193 }, // und_RU -> ru_Cyrl_RU
+ { 0, 66, 194 }, { 138, 66, 194 }, // und_Latn_RW -> rw_Latn_RW
{ 0, 0, 194 }, { 138, 66, 194 }, // und_RW -> rw_Latn_RW
+ { 0, 66, 195 }, { 85, 66, 195 }, // und_Latn_BL -> fr_Latn_BL
{ 0, 0, 195 }, { 85, 66, 195 }, // und_BL -> fr_Latn_BL
+ { 0, 0, 196 }, { 75, 66, 196 }, // und_SH -> en_Latn_SH
+ { 0, 0, 197 }, { 75, 66, 197 }, // und_KN -> en_Latn_KN
+ { 0, 0, 198 }, { 75, 66, 198 }, // und_LC -> en_Latn_LC
+ { 0, 66, 199 }, { 85, 66, 199 }, // und_Latn_MF -> fr_Latn_MF
{ 0, 0, 199 }, { 85, 66, 199 }, // und_MF -> fr_Latn_MF
+ { 0, 66, 200 }, { 85, 66, 200 }, // und_Latn_PM -> fr_Latn_PM
{ 0, 0, 200 }, { 85, 66, 200 }, // und_PM -> fr_Latn_PM
+ { 0, 0, 201 }, { 75, 66, 201 }, // und_VC -> en_Latn_VC
+ { 0, 66, 202 }, { 244, 66, 202 }, // und_Latn_WS -> sm_Latn_WS
{ 0, 0, 202 }, { 244, 66, 202 }, // und_WS -> sm_Latn_WS
+ { 0, 66, 203 }, { 119, 66, 203 }, // und_Latn_SM -> it_Latn_SM
{ 0, 0, 203 }, { 119, 66, 203 }, // und_SM -> it_Latn_SM
+ { 0, 66, 204 }, { 231, 66, 204 }, // und_Latn_ST -> pt_Latn_ST
{ 0, 0, 204 }, { 231, 66, 204 }, // und_ST -> pt_Latn_ST
{ 0, 0, 205 }, { 14, 4, 205 }, // und_SA -> ar_Arab_SA
+ { 0, 66, 206 }, { 85, 66, 206 }, // und_Latn_SN -> fr_Latn_SN
{ 0, 0, 206 }, { 85, 66, 206 }, // und_SN -> fr_Latn_SN
+ { 0, 27, 207 }, { 252, 27, 207 }, // und_Cyrl_RS -> sr_Cyrl_RS
+ { 0, 66, 207 }, { 252, 66, 207 }, // und_Latn_RS -> sr_Latn_RS
{ 0, 0, 207 }, { 252, 27, 207 }, // und_RS -> sr_Cyrl_RS
+ { 0, 66, 208 }, { 85, 66, 208 }, // und_Latn_SC -> fr_Latn_SC
{ 0, 0, 208 }, { 85, 66, 208 }, // und_SC -> fr_Latn_SC
+ { 0, 0, 210 }, { 75, 66, 210 }, // und_SG -> en_Latn_SG
+ { 0, 0, 211 }, { 75, 66, 211 }, // und_SX -> en_Latn_SX
{ 0, 27, 212 }, { 303, 27, 212 }, // und_Cyrl_SK -> uk_Cyrl_SK
+ { 0, 66, 212 }, { 262, 66, 212 }, // und_Latn_SK -> sk_Latn_SK
{ 0, 0, 212 }, { 262, 66, 212 }, // und_SK -> sk_Latn_SK
+ { 0, 66, 213 }, { 263, 66, 213 }, // und_Latn_SI -> sl_Latn_SI
{ 0, 0, 213 }, { 263, 66, 213 }, // und_SI -> sl_Latn_SI
+ { 0, 0, 214 }, { 75, 66, 214 }, // und_SB -> en_Latn_SB
+ { 0, 66, 215 }, { 265, 66, 215 }, // und_Latn_SO -> so_Latn_SO
{ 0, 0, 215 }, { 265, 66, 215 }, // und_SO -> so_Latn_SO
- { 0, 0, 217 }, { 0, 66, 217 }, // und_GS -> und_Latn_GS
+ { 0, 0, 216 }, { 75, 66, 216 }, // und_ZA -> en_Latn_ZA
+ { 0, 0, 217 }, { 75, 66, 217 }, // und_GS -> en_Latn_GS
{ 0, 0, 218 }, { 142, 63, 218 }, // und_KR -> ko_Kore_KR
+ { 0, 0, 219 }, { 14, 4, 219 }, // und_SS -> ar_Arab_SS
+ { 0, 66, 220 }, { 270, 66, 220 }, // und_Latn_ES -> es_Latn_ES
{ 0, 0, 220 }, { 270, 66, 220 }, // und_ES -> es_Latn_ES
{ 0, 0, 221 }, { 260, 119, 221 }, // und_LK -> si_Sinh_LK
{ 0, 0, 222 }, { 14, 4, 222 }, // und_SD -> ar_Arab_SD
+ { 0, 66, 223 }, { 72, 66, 223 }, // und_Latn_SR -> nl_Latn_SR
{ 0, 0, 223 }, { 72, 66, 223 }, // und_SR -> nl_Latn_SR
+ { 0, 66, 224 }, { 209, 66, 224 }, // und_Latn_SJ -> nb_Latn_SJ
{ 0, 0, 224 }, { 209, 66, 224 }, // und_SJ -> nb_Latn_SJ
{ 0, 47, 225 }, { 323, 47, 225 }, // und_Hebr_SE -> yi_Hebr_SE
+ { 0, 66, 225 }, { 275, 66, 225 }, // und_Latn_SE -> sv_Latn_SE
{ 0, 0, 225 }, { 275, 66, 225 }, // und_SE -> sv_Latn_SE
+ { 0, 66, 226 }, { 94, 66, 226 }, // und_Latn_CH -> de_Latn_CH
{ 0, 0, 226 }, { 94, 66, 226 }, // und_CH -> de_Latn_CH
{ 0, 66, 227 }, { 85, 66, 227 }, // und_Latn_SY -> fr_Latn_SY
{ 0, 0, 227 }, { 14, 4, 227 }, // und_SY -> ar_Arab_SY
{ 0, 66, 228 }, { 284, 66, 228 }, // und_Latn_TW -> trv_Latn_TW
{ 0, 0, 228 }, { 58, 137, 228 }, // und_TW -> zh_Hant_TW
{ 0, 4, 229 }, { 228, 4, 229 }, // und_Arab_TJ -> fa_Arab_TJ
+ { 0, 27, 229 }, { 282, 27, 229 }, // und_Cyrl_TJ -> tg_Cyrl_TJ
{ 0, 0, 229 }, { 282, 27, 229 }, // und_TJ -> tg_Cyrl_TJ
+ { 0, 66, 230 }, { 273, 66, 230 }, // und_Latn_TZ -> sw_Latn_TZ
{ 0, 0, 230 }, { 273, 66, 230 }, // und_TZ -> sw_Latn_TZ
{ 0, 0, 231 }, { 289, 133, 231 }, // und_TH -> th_Thai_TH
+ { 0, 66, 232 }, { 231, 66, 232 }, // und_Latn_TL -> pt_Latn_TL
{ 0, 0, 232 }, { 231, 66, 232 }, // und_TL -> pt_Latn_TL
+ { 0, 66, 233 }, { 85, 66, 233 }, // und_Latn_TG -> fr_Latn_TG
{ 0, 0, 233 }, { 85, 66, 233 }, // und_TG -> fr_Latn_TG
+ { 0, 66, 234 }, { 293, 66, 234 }, // und_Latn_TK -> tkl_Latn_TK
{ 0, 0, 234 }, { 293, 66, 234 }, // und_TK -> tkl_Latn_TK
+ { 0, 66, 235 }, { 295, 66, 235 }, // und_Latn_TO -> to_Latn_TO
{ 0, 0, 235 }, { 295, 66, 235 }, // und_TO -> to_Latn_TO
+ { 0, 0, 236 }, { 75, 66, 236 }, // und_TT -> en_Latn_TT
+ { 0, 0, 237 }, { 75, 66, 237 }, // und_TA -> en_Latn_TA
{ 0, 66, 238 }, { 85, 66, 238 }, // und_Latn_TN -> fr_Latn_TN
{ 0, 0, 238 }, { 14, 4, 238 }, // und_TN -> ar_Arab_TN
- { 0, 4, 239 }, { 25, 4, 239 }, // und_Arab_TR -> az_Arab_TR
+ { 0, 66, 239 }, { 298, 66, 239 }, // und_Latn_TR -> tr_Latn_TR
{ 0, 0, 239 }, { 298, 66, 239 }, // und_TR -> tr_Latn_TR
+ { 0, 66, 240 }, { 299, 66, 240 }, // und_Latn_TM -> tk_Latn_TM
{ 0, 0, 240 }, { 299, 66, 240 }, // und_TM -> tk_Latn_TM
+ { 0, 0, 241 }, { 75, 66, 241 }, // und_TC -> en_Latn_TC
+ { 0, 66, 242 }, { 300, 66, 242 }, // und_Latn_TV -> tvl_Latn_TV
{ 0, 0, 242 }, { 300, 66, 242 }, // und_TV -> tvl_Latn_TV
+ { 0, 66, 243 }, { 273, 66, 243 }, // und_Latn_UG -> sw_Latn_UG
{ 0, 0, 243 }, { 273, 66, 243 }, // und_UG -> sw_Latn_UG
+ { 0, 27, 244 }, { 303, 27, 244 }, // und_Cyrl_UA -> uk_Cyrl_UA
{ 0, 47, 244 }, { 323, 47, 244 }, // und_Hebr_UA -> yi_Hebr_UA
{ 0, 66, 244 }, { 230, 66, 244 }, // und_Latn_UA -> pl_Latn_UA
{ 0, 0, 244 }, { 303, 27, 244 }, // und_UA -> uk_Cyrl_UA
{ 0, 0, 245 }, { 14, 4, 245 }, // und_AE -> ar_Arab_AE
{ 0, 4, 246 }, { 305, 4, 246 }, // und_Arab_GB -> ur_Arab_GB
+ { 0, 0, 246 }, { 75, 66, 246 }, // und_GB -> en_Latn_GB
+ { 0, 0, 247 }, { 75, 66, 247 }, // und_UM -> en_Latn_UM
{ 0, 47, 248 }, { 323, 47, 248 }, // und_Hebr_US -> yi_Hebr_US
+ { 0, 0, 248 }, { 75, 66, 248 }, // und_US -> en_Latn_US
+ { 0, 0, 249 }, { 75, 66, 249 }, // und_VI -> en_Latn_VI
+ { 0, 66, 250 }, { 270, 66, 250 }, // und_Latn_UY -> es_Latn_UY
{ 0, 0, 250 }, { 270, 66, 250 }, // und_UY -> es_Latn_UY
+ { 0, 66, 251 }, { 307, 66, 251 }, // und_Latn_UZ -> uz_Latn_UZ
{ 0, 0, 251 }, { 307, 66, 251 }, // und_UZ -> uz_Latn_UZ
+ { 0, 66, 252 }, { 39, 66, 252 }, // und_Latn_VU -> bi_Latn_VU
{ 0, 0, 252 }, { 39, 66, 252 }, // und_VU -> bi_Latn_VU
+ { 0, 66, 253 }, { 119, 66, 253 }, // und_Latn_VA -> it_Latn_VA
{ 0, 0, 253 }, { 119, 66, 253 }, // und_VA -> it_Latn_VA
+ { 0, 66, 254 }, { 270, 66, 254 }, // und_Latn_VE -> es_Latn_VE
{ 0, 0, 254 }, { 270, 66, 254 }, // und_VE -> es_Latn_VE
+ { 0, 66, 255 }, { 310, 66, 255 }, // und_Latn_VN -> vi_Latn_VN
{ 0, 0, 255 }, { 310, 66, 255 }, // und_VN -> vi_Latn_VN
+ { 0, 66, 256 }, { 85, 66, 256 }, // und_Latn_WF -> fr_Latn_WF
{ 0, 0, 256 }, { 85, 66, 256 }, // und_WF -> fr_Latn_WF
{ 0, 0, 257 }, { 14, 4, 257 }, // und_EH -> ar_Arab_EH
{ 0, 0, 259 }, { 14, 4, 259 }, // und_YE -> ar_Arab_YE
+ { 0, 66, 260 }, { 36, 66, 260 }, // und_Latn_ZM -> bem_Latn_ZM
+ { 0, 0, 260 }, { 36, 66, 260 }, // und_ZM -> bem_Latn_ZM
+ { 0, 66, 261 }, { 254, 66, 261 }, // und_Latn_ZW -> sn_Latn_ZW
{ 0, 0, 261 }, { 254, 66, 261 }, // und_ZW -> sn_Latn_ZW
{ 0, 1, 0 }, { 87, 1, 102 }, // und_Adlm -> ff_Adlm_GN
{ 0, 4, 0 }, { 14, 4, 71 }, // und_Arab -> ar_Arab_EG
@@ -776,6 +999,7 @@ static constexpr QLocaleId likely_subtags[] = {
{ 0, 62, 0 }, { 259, 62, 110 }, // und_Sind -> sd_Sind_IN
{ 0, 63, 0 }, { 142, 63, 218 }, // und_Kore -> ko_Kore_KR
{ 0, 65, 0 }, { 153, 65, 129 }, // und_Laoo -> lo_Laoo_LA
+ { 0, 66, 0 }, { 75, 66, 248 }, // und_Latn -> en_Latn_US
{ 0, 70, 0 }, { 13, 70, 94 }, // und_Linb -> grc_Linb_GR
{ 0, 73, 0 }, { 105, 73, 110 }, // und_Mahj -> hi_Mahj_IN
{ 0, 74, 0 }, { 175, 74, 110 }, // und_Mlym -> ml_Mlym_IN
@@ -823,7 +1047,8 @@ static constexpr QLocaleId likely_subtags[] = {
{ 0, 137, 0 }, { 58, 137, 228 }, // und_Hant -> zh_Hant_TW
{ 0, 138, 0 }, { 302, 138, 227 }, // und_Ugar -> uga_Ugar_SY
{ 0, 139, 0 }, { 308, 139, 134 }, // und_Vaii -> vai_Vaii_LR
- { 0, 141, 0 }, { 255, 141, 50 } // und_Yiii -> ii_Yiii_CN
+ { 0, 141, 0 }, { 255, 141, 50 }, // und_Yiii -> ii_Yiii_CN
+ { 0, 142, 0 }, { 339, 142, 161 } // und_Rohg -> rhg_Rohg_MM
};
static constexpr quint16 locale_index[] = {
@@ -831,3108 +1056,5141 @@ static constexpr quint16 locale_index[] = {
0, // C
1, // Abkhazian
2, // Afar
- 3, // Afrikaans
- 5, // Aghem
- 6, // Akan
+ 5, // Afrikaans
+ 7, // Aghem
+ 8, // Akan
0, // Akkadian
- 7, // Akoose
- 8, // Albanian
+ 9, // Akoose
+ 10, // Albanian
0, // American Sign Language
- 11, // Amharic
+ 13, // Amharic
0, // Ancient Egyptian
0, // Ancient Greek
- 12, // Arabic
- 40, // Aragonese
+ 14, // Arabic
+ 42, // Aragonese
0, // Aramaic
- 41, // Armenian
- 42, // Assamese
- 43, // Asturian
- 44, // Asu
- 45, // Atsam
+ 43, // Armenian
+ 44, // Assamese
+ 45, // Asturian
+ 46, // Asu
+ 47, // Atsam
0, // Avaric
0, // Avestan
0, // Aymara
- 46, // Azerbaijani
- 49, // Bafia
+ 48, // Azerbaijani
+ 53, // Bafia
0, // Balinese
- 50, // Bambara
+ 54, // Bambara
0, // Bamun
- 52, // Bangla
- 54, // Basaa
- 55, // Bashkir
- 56, // Basque
+ 56, // Bangla
+ 58, // Basaa
+ 59, // Bashkir
+ 60, // Basque
0, // Batak Toba
- 57, // Belarusian
- 58, // Bemba
- 59, // Bena
- 60, // Bhojpuri
+ 61, // Belarusian
+ 62, // Bemba
+ 63, // Bena
+ 64, // Bhojpuri
0, // Bislama
- 61, // Blin
- 62, // Bodo
- 63, // Bosnian
- 65, // Breton
+ 65, // Blin
+ 66, // Bodo
+ 67, // Bosnian
+ 69, // Breton
0, // Buginese
- 66, // Bulgarian
- 67, // Burmese
- 68, // Cantonese
- 70, // Catalan
- 74, // Cebuano
- 75, // Central Atlas Tamazight
- 76, // Central Kurdish
- 78, // Chakma
+ 70, // Bulgarian
+ 71, // Burmese
+ 72, // Cantonese
+ 74, // Catalan
+ 78, // Cebuano
+ 79, // Central Atlas Tamazight
+ 80, // Central Kurdish
+ 82, // Chakma
0, // Chamorro
- 80, // Chechen
- 81, // Cherokee
- 82, // Chickasaw
- 83, // Chiga
- 84, // Chinese
- 91, // Church
- 92, // Chuvash
- 93, // Colognian
+ 84, // Chechen
+ 85, // Cherokee
+ 86, // Chickasaw
+ 87, // Chiga
+ 88, // Chinese
+ 95, // Church
+ 96, // Chuvash
+ 97, // Colognian
0, // Coptic
- 94, // Cornish
- 95, // Corsican
+ 98, // Cornish
+ 99, // Corsican
0, // Cree
- 96, // Croatian
- 98, // Czech
- 99, // Danish
- 101, // Divehi
- 102, // Dogri
- 103, // Duala
- 104, // Dutch
- 111, // Dzongkha
- 112, // Embu
- 113, // English
- 221, // Erzya
- 222, // Esperanto
- 223, // Estonian
- 224, // Ewe
- 226, // Ewondo
- 227, // Faroese
+ 100, // Croatian
+ 102, // Czech
+ 103, // Danish
+ 105, // Divehi
+ 106, // Dogri
+ 107, // Duala
+ 108, // Dutch
+ 115, // Dzongkha
+ 116, // Embu
+ 117, // English
+ 226, // Erzya
+ 227, // Esperanto
+ 228, // Estonian
+ 229, // Ewe
+ 231, // Ewondo
+ 232, // Faroese
0, // Fijian
- 229, // Filipino
- 230, // Finnish
- 231, // French
- 277, // Friulian
- 278, // Fulah
- 302, // Gaelic
- 303, // Ga
- 304, // Galician
- 305, // Ganda
- 306, // Geez
- 307, // Georgian
- 308, // German
+ 234, // Filipino
+ 235, // Finnish
+ 236, // French
+ 282, // Friulian
+ 283, // Fulah
+ 307, // Gaelic
+ 308, // Ga
+ 309, // Galician
+ 310, // Ganda
+ 311, // Geez
+ 313, // Georgian
+ 314, // German
0, // Gothic
- 315, // Greek
- 317, // Guarani
- 318, // Gujarati
- 319, // Gusii
+ 321, // Greek
+ 323, // Guarani
+ 324, // Gujarati
+ 325, // Gusii
0, // Haitian
- 320, // Hausa
- 324, // Hawaiian
- 325, // Hebrew
+ 326, // Hausa
+ 331, // Hawaiian
+ 332, // Hebrew
0, // Herero
- 326, // Hindi
+ 333, // Hindi
0, // Hiri Motu
- 328, // Hungarian
- 329, // Icelandic
- 330, // Ido
- 331, // Igbo
- 332, // Inari Sami
- 333, // Indonesian
+ 335, // Hungarian
+ 336, // Icelandic
+ 337, // Ido
+ 338, // Igbo
+ 339, // Inari Sami
+ 340, // Indonesian
0, // Ingush
- 334, // Interlingua
- 0, // Interlingue
- 335, // Inuktitut
+ 341, // Interlingua
+ 342, // Interlingue
+ 343, // Inuktitut
0, // Inupiaq
- 337, // Irish
- 339, // Italian
- 343, // Japanese
- 344, // Javanese
- 345, // Jju
- 346, // Jola Fonyi
- 347, // Kabuverdianu
- 348, // Kabyle
- 349, // Kako
- 350, // Kalaallisut
- 351, // Kalenjin
- 352, // Kamba
- 353, // Kannada
+ 345, // Irish
+ 347, // Italian
+ 351, // Japanese
+ 352, // Javanese
+ 353, // Jju
+ 354, // Jola-Fonyi
+ 355, // Kabuverdianu
+ 356, // Kabyle
+ 357, // Kako
+ 358, // Kalaallisut
+ 359, // Kalenjin
+ 360, // Kamba
+ 361, // Kannada
0, // Kanuri
- 354, // Kashmiri
- 356, // Kazakh
- 357, // Kenyang
- 358, // Khmer
- 359, // Kiche
- 360, // Kikuyu
- 361, // Kinyarwanda
+ 362, // Kashmiri
+ 364, // Kazakh
+ 365, // Kenyang
+ 366, // Khmer
+ 367, // Kiche
+ 368, // Kikuyu
+ 369, // Kinyarwanda
0, // Komi
0, // Kongo
- 362, // Konkani
- 363, // Korean
+ 370, // Konkani
+ 371, // Korean
0, // Koro
- 365, // Koyraboro Senni
- 366, // Koyra Chiini
- 367, // Kpelle
+ 374, // Koyraboro Senni
+ 375, // Koyra Chiini
+ 376, // Kpelle
0, // Kuanyama
- 368, // Kurdish
- 369, // Kwasio
- 370, // Kyrgyz
- 371, // Lakota
- 372, // Langi
- 373, // Lao
- 374, // Latin
- 375, // Latvian
+ 378, // Kurdish
+ 379, // Kwasio
+ 380, // Kyrgyz
+ 381, // Lakota
+ 382, // Langi
+ 383, // Lao
+ 384, // Latin
+ 385, // Latvian
0, // Lezghian
0, // Limburgish
- 376, // Lingala
+ 386, // Lingala
0, // Literary Chinese
- 380, // Lithuanian
- 381, // Lojban
- 382, // Lower Sorbian
- 383, // Low German
- 385, // Luba Katanga
- 386, // Lule Sami
- 387, // Luo
- 388, // Luxembourgish
- 389, // Luyia
- 390, // Macedonian
- 391, // Machame
- 392, // Maithili
- 393, // Makhuwa Meetto
- 394, // Makonde
- 395, // Malagasy
- 396, // Malayalam
- 397, // Malay
- 402, // Maltese
+ 390, // Lithuanian
+ 391, // Lojban
+ 392, // Lower Sorbian
+ 393, // Low German
+ 395, // Luba-Katanga
+ 396, // Lule Sami
+ 398, // Luo
+ 399, // Luxembourgish
+ 400, // Luyia
+ 401, // Macedonian
+ 402, // Machame
+ 403, // Maithili
+ 404, // Makhuwa-Meetto
+ 405, // Makonde
+ 406, // Malagasy
+ 407, // Malayalam
+ 408, // Malay
+ 414, // Maltese
0, // Mandingo
- 403, // Manipuri
- 405, // Manx
- 406, // Maori
- 407, // Mapuche
- 408, // Marathi
+ 415, // Manipuri
+ 417, // Manx
+ 418, // Maori
+ 419, // Mapuche
+ 420, // Marathi
0, // Marshallese
- 409, // Masai
- 411, // Mazanderani
+ 421, // Masai
+ 423, // Mazanderani
0, // Mende
- 412, // Meru
- 413, // Meta
- 414, // Mohawk
- 415, // Mongolian
- 417, // Morisyen
- 418, // Mundang
- 419, // Muscogee
- 420, // Nama
+ 424, // Meru
+ 425, // Meta
+ 426, // Mohawk
+ 427, // Mongolian
+ 430, // Morisyen
+ 431, // Mundang
+ 432, // Muscogee
+ 433, // Nama
0, // Nauru
- 421, // Navajo
+ 434, // Navajo
0, // Ndonga
- 422, // Nepali
+ 435, // Nepali
0, // Newari
- 424, // Ngiemboon
- 425, // Ngomba
- 426, // Nigerian Pidgin
- 427, // Nko
- 428, // Northern Luri
- 430, // Northern Sami
- 433, // Northern Sotho
- 434, // North Ndebele
- 435, // Norwegian Bokmal
- 437, // Norwegian Nynorsk
- 438, // Nuer
- 439, // Nyanja
- 440, // Nyankole
- 441, // Occitan
- 443, // Odia
+ 437, // Ngiemboon
+ 438, // Ngomba
+ 439, // Nigerian Pidgin
+ 440, // Nko
+ 441, // Northern Luri
+ 443, // Northern Sami
+ 446, // Northern Sotho
+ 447, // North Ndebele
+ 448, // Norwegian Bokmal
+ 450, // Norwegian Nynorsk
+ 451, // Nuer
+ 452, // Nyanja
+ 453, // Nyankole
+ 454, // Occitan
+ 456, // Odia
0, // Ojibwa
0, // Old Irish
0, // Old Norse
0, // Old Persian
- 444, // Oromo
- 446, // Osage
- 447, // Ossetic
+ 457, // Oromo
+ 459, // Osage
+ 460, // Ossetic
0, // Pahlavi
0, // Palauan
0, // Pali
- 0, // Papiamento
- 449, // Pashto
- 451, // Persian
+ 462, // Papiamento
+ 464, // Pashto
+ 466, // Persian
0, // Phoenician
- 453, // Polish
- 454, // Portuguese
- 466, // Prussian
- 467, // Punjabi
- 469, // Quechua
- 472, // Romanian
- 474, // Romansh
- 475, // Rombo
- 476, // Rundi
- 477, // Russian
- 483, // Rwa
- 484, // Saho
- 485, // Sakha
- 486, // Samburu
+ 468, // Polish
+ 469, // Portuguese
+ 481, // Prussian
+ 482, // Punjabi
+ 484, // Quechua
+ 487, // Romanian
+ 489, // Romansh
+ 490, // Rombo
+ 491, // Rundi
+ 492, // Russian
+ 498, // Rwa
+ 499, // Saho
+ 500, // Sakha
+ 501, // Samburu
0, // Samoan
- 487, // Sango
- 488, // Sangu
- 489, // Sanskrit
- 490, // Santali
- 492, // Sardinian
+ 502, // Sango
+ 503, // Sangu
+ 504, // Sanskrit
+ 505, // Santali
+ 507, // Sardinian
0, // Saurashtra
- 493, // Sena
- 494, // Serbian
- 502, // Shambala
- 503, // Shona
- 504, // Sichuan Yi
- 505, // Sicilian
- 506, // Sidamo
- 507, // Silesian
- 508, // Sindhi
- 510, // Sinhala
- 511, // Skolt Sami
- 512, // Slovak
- 513, // Slovenian
- 514, // Soga
- 515, // Somali
- 519, // Southern Kurdish
- 520, // Southern Sami
- 521, // Southern Sotho
- 522, // South Ndebele
- 523, // Spanish
- 551, // Standard Moroccan Tamazight
- 552, // Sundanese
- 553, // Swahili
- 557, // Swati
- 558, // Swedish
- 561, // Swiss German
- 564, // Syriac
- 565, // Tachelhit
+ 508, // Sena
+ 509, // Serbian
+ 517, // Shambala
+ 518, // Shona
+ 519, // Sichuan Yi
+ 520, // Sicilian
+ 521, // Sidamo
+ 522, // Silesian
+ 523, // Sindhi
+ 525, // Sinhala
+ 526, // Skolt Sami
+ 527, // Slovak
+ 528, // Slovenian
+ 529, // Soga
+ 530, // Somali
+ 534, // Southern Kurdish
+ 536, // Southern Sami
+ 538, // Southern Sotho
+ 540, // South Ndebele
+ 541, // Spanish
+ 569, // Standard Moroccan Tamazight
+ 570, // Sundanese
+ 571, // Swahili
+ 575, // Swati
+ 577, // Swedish
+ 580, // Swiss German
+ 583, // Syriac
+ 585, // Tachelhit
0, // Tahitian
- 567, // Tai Dam
- 568, // Taita
- 569, // Tajik
- 570, // Tamil
- 574, // Taroko
- 575, // Tasawaq
- 576, // Tatar
- 577, // Telugu
- 578, // Teso
- 580, // Thai
- 581, // Tibetan
- 583, // Tigre
- 584, // Tigrinya
+ 587, // Tai Dam
+ 588, // Taita
+ 589, // Tajik
+ 590, // Tamil
+ 594, // Taroko
+ 595, // Tasawaq
+ 596, // Tatar
+ 597, // Telugu
+ 598, // Teso
+ 600, // Thai
+ 601, // Tibetan
+ 603, // Tigre
+ 604, // Tigrinya
0, // Tokelau
- 586, // Tok Pisin
- 587, // Tongan
- 588, // Tsonga
- 589, // Tswana
- 590, // Turkish
- 592, // Turkmen
+ 606, // Tok Pisin
+ 607, // Tongan
+ 608, // Tsonga
+ 609, // Tswana
+ 611, // Turkish
+ 613, // Turkmen
0, // Tuvalu
- 593, // Tyap
+ 614, // Tyap
0, // Ugaritic
- 594, // Ukrainian
- 595, // Upper Sorbian
- 596, // Urdu
- 598, // Uyghur
- 599, // Uzbek
- 602, // Vai
- 604, // Venda
- 605, // Vietnamese
- 606, // Volapuk
- 607, // Vunjo
- 608, // Walloon
- 609, // Walser
- 610, // Warlpiri
- 611, // Welsh
- 612, // Western Balochi
- 613, // Western Frisian
- 614, // Wolaytta
- 615, // Wolof
- 616, // Xhosa
- 617, // Yangben
- 618, // Yiddish
- 619, // Yoruba
- 621, // Zarma
- 0, // Zhuang
- 622, // Zulu
- 623, // Kaingang
- 624, // Nheengatu
- 627, // Haryanvi
- 628, // Northern Frisian
- 629, // Rajasthani
- 630, // Moksha
- 631, // Toki Pona
- 632, // Pijin
- 633, // Obolo
+ 615, // Ukrainian
+ 616, // Upper Sorbian
+ 617, // Urdu
+ 619, // Uyghur
+ 620, // Uzbek
+ 623, // Vai
+ 625, // Venda
+ 626, // Vietnamese
+ 627, // Volapuk
+ 628, // Vunjo
+ 629, // Walloon
+ 630, // Walser
+ 631, // Warlpiri
+ 632, // Welsh
+ 633, // Western Balochi
+ 638, // Western Frisian
+ 639, // Wolaytta
+ 640, // Wolof
+ 641, // Xhosa
+ 642, // Yangben
+ 643, // Yiddish
+ 644, // Yoruba
+ 646, // Zarma
+ 647, // Zhuang
+ 648, // Zulu
+ 649, // Kaingang
+ 650, // Nheengatu
+ 653, // Haryanvi
+ 654, // Northern Frisian
+ 655, // Rajasthani
+ 656, // Moksha
+ 657, // Toki Pona
+ 658, // Pijin
+ 659, // Obolo
+ 660, // Baluchi
+ 662, // Ligurian
+ 663, // Rohingya
+ 665, // Torwali
+ 666, // Anii
+ 667, // Kangri
+ 668, // Venetian
0 // trailing 0
};
static constexpr QLocaleData locale_data[] = {
// lang script terr lStrt lpMid lpEnd lPair lDelm dec group prcnt zero minus plus exp qtOpn qtEnd altQO altQE lDFmt sDFmt lTFmt sTFmt slDay lDays ssDys sDays snDay nDays am pm byte siQnt iecQn crSym crDsp crFmt crFNg ntLng ntTer currISO curDgt curRnd dow1st wknd+ wknd- grpTop grpMid grpEnd
{ 1, 0, 0, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 8, 0, 17, 0, 0, 0, 0, 56, 56, 83, 96, 0, 0, 0, 5, 22, 0, 0, 0, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 8, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 0, 4, 0, 0, 0, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // C/AnyScript/AnyTerritory
- { 2, 27, 90, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {71,69,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Abkhazian/Cyrillic/Georgia
- { 3, 66, 77, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 0, 0, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Afar/Latin/Ethiopia
- { 4, 66, 216, 0, 0, 7, 7, 6, 1, 14, 2, 3, 4, 5, 9, 10, 11, 12, 13, 54, 44, 0, 0, 109, 109, 166, 166, 193, 193, 2, 2, 45, 5, 22, 1, 0, 9, 13, 0, 9, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 57, 57, 27, 27, 13, 13, 3, 3, 5, 17, 23, 1, 20, 4, 6, 9, 11, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Afrikaans/Latin/South Africa
- { 4, 66, 162, 0, 0, 7, 7, 6, 1, 14, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 44, 10, 22, 109, 109, 166, 166, 193, 193, 2, 2, 45, 5, 22, 2, 20, 9, 13, 0, 20, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 12, 7, 57, 57, 27, 27, 13, 13, 3, 3, 5, 17, 23, 1, 16, 4, 6, 9, 7, {78,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Afrikaans/Latin/Namibia
- { 5, 66, 40, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 15, 11, 16, 13, 71, 87, 0, 0, 206, 206, 277, 277, 304, 304, 5, 5, 0, 5, 22, 3, 36, 0, 0, 27, 32, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 71, 71, 27, 27, 13, 13, 3, 3, 4, 17, 23, 4, 14, 4, 0, 5, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Aghem/Latin/Cameroon
- { 6, 66, 92, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 95, 113, 10, 22, 317, 317, 365, 365, 392, 392, 8, 8, 0, 5, 22, 7, 50, 9, 0, 39, 43, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 12, 7, 48, 48, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 10, 4, 0, 4, 5, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Akan/Latin/Ghana
- { 8, 66, 40, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 3, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 4, 0, 5, 0, 0, 0, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Akoose/Latin/Cameroon
- { 9, 66, 3, 0, 0, 15, 15, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 10, 11, 0, 121, 29, 22, 405, 405, 462, 489, 516, 516, 10, 10, 50, 5, 22, 10, 60, 19, 24, 48, 53, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 13, 7, 57, 57, 27, 27, 14, 14, 11, 10, 4, 17, 23, 4, 13, 5, 7, 5, 8, {65,76,76}, 0, 0, 1, 6, 7, 2, 3, 3 }, // Albanian/Latin/Albania
- { 9, 66, 126, 0, 0, 15, 15, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 10, 11, 0, 121, 0, 0, 405, 405, 462, 489, 516, 516, 10, 10, 50, 5, 22, 14, 73, 19, 24, 48, 61, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 10, 5, 57, 57, 27, 27, 14, 14, 11, 10, 4, 17, 23, 1, 6, 5, 7, 5, 6, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Albanian/Latin/Kosovo
- { 9, 66, 140, 0, 0, 15, 15, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 10, 11, 0, 121, 0, 0, 405, 405, 462, 489, 516, 516, 10, 10, 50, 5, 22, 15, 79, 19, 24, 48, 67, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 10, 5, 57, 57, 27, 27, 14, 14, 11, 10, 4, 17, 23, 3, 16, 5, 7, 5, 18, {77,75,68}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Albanian/Latin/Macedonia
- { 11, 33, 77, 24, 24, 30, 39, 6, 0, 1, 2, 3, 4, 5, 9, 17, 18, 19, 20, 27, 127, 42, 54, 530, 530, 557, 557, 583, 583, 21, 20, 54, 57, 22, 18, 95, 9, 13, 85, 89, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 27, 27, 26, 26, 13, 13, 3, 4, 3, 23, 23, 2, 9, 4, 6, 4, 5, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Amharic/Ethiopic/Ethiopia
- { 14, 4, 71, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 20, 104, 31, 0, 94, 101, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 9, 6, 0, 7, 3, {69,71,80}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Egypt
- { 14, 4, 4, 47, 47, 47, 47, 6, 1, 0, 32, 3, 35, 37, 9, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 25, 113, 37, 42, 94, 104, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 12, 5, 7, 7, 7, {68,90,68}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Algeria
- { 14, 4, 19, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 30, 125, 31, 0, 94, 111, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 12, 6, 0, 7, 7, {66,72,68}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Bahrain
- { 14, 4, 48, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 3, 137, 31, 0, 94, 118, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 4, 15, 6, 0, 7, 4, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Chad
- { 14, 4, 55, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 0, 0, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 4, 152, 31, 0, 94, 122, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 10, 5, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 2, 14, 6, 0, 7, 9, {75,77,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Comoros
- { 14, 4, 67, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 35, 166, 31, 0, 94, 131, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 3, 11, 6, 0, 7, 6, {68,74,70}, 0, 0, 6, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Djibouti
- { 14, 4, 74, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 38, 177, 31, 0, 94, 137, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 3, 12, 6, 0, 7, 7, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Eritrea
- { 14, 4, 113, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 41, 189, 31, 0, 94, 144, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 11, 6, 0, 7, 6, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Iraq
- { 14, 4, 116, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 1, 1, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 46, 200, 31, 0, 94, 150, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 9, 4, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 1, 18, 6, 0, 7, 7, {73,76,83}, 2, 1, 7, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Israel
- { 14, 4, 122, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 47, 218, 31, 0, 94, 157, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 11, 6, 0, 7, 6, {74,79,68}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Jordan
- { 14, 4, 127, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 52, 229, 31, 0, 94, 163, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 11, 6, 0, 7, 6, {75,87,68}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Kuwait
- { 14, 4, 132, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 57, 240, 31, 0, 94, 169, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 11, 6, 0, 7, 5, {76,66,80}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Lebanon
- { 14, 4, 135, 47, 47, 47, 47, 6, 1, 0, 32, 3, 35, 37, 9, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 62, 251, 37, 42, 94, 174, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 5, 7, 7, 5, {76,89,68}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Libya
- { 14, 4, 149, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 67, 261, 31, 0, 94, 179, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 4, 15, 6, 0, 7, 9, {77,82,85}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Mauritania
- { 14, 4, 159, 47, 47, 47, 47, 6, 1, 0, 32, 3, 35, 37, 9, 11, 10, 13, 12, 137, 154, 0, 0, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 71, 276, 37, 42, 94, 188, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 10, 5, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 5, 7, 7, 6, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Morocco
- { 14, 4, 176, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 76, 286, 31, 0, 94, 194, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 6, 0, 7, 5, {79,77,82}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Oman
- { 14, 4, 180, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 46, 200, 31, 0, 94, 199, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 1, 18, 6, 0, 7, 18, {73,76,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Palestinian Territories
- { 14, 4, 190, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 81, 296, 31, 0, 94, 217, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 9, 6, 0, 7, 3, {81,65,82}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Qatar
- { 14, 4, 205, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 86, 305, 31, 0, 94, 220, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 6, 0, 7, 24, {83,65,82}, 2, 1, 7, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Saudi Arabia
- { 14, 4, 215, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 91, 315, 31, 0, 94, 244, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 1, 10, 6, 0, 7, 7, {83,79,83}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Somalia
- { 14, 4, 219, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 92, 325, 31, 0, 94, 251, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 1, 17, 6, 0, 7, 12, {83,83,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/South Sudan
- { 14, 4, 222, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 93, 342, 31, 0, 94, 263, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 4, 11, 6, 0, 7, 7, {83,68,71}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Sudan
- { 14, 4, 227, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 97, 353, 31, 0, 94, 270, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 6, 0, 7, 5, {83,89,80}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Syria
- { 14, 4, 238, 47, 47, 47, 47, 6, 1, 0, 32, 3, 35, 37, 9, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 102, 363, 37, 42, 94, 275, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 11, 5, 7, 7, 4, {84,78,68}, 3, 0, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Tunisia
- { 14, 4, 245, 47, 47, 47, 47, 6, 0, 1, 32, 3, 35, 37, 9, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 107, 374, 37, 42, 94, 279, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 12, 5, 7, 7, 24, {65,69,68}, 2, 1, 6, 6, 7, 1, 3, 3 }, // Arabic/Arabic/United Arab Emirates
- { 14, 4, 257, 47, 47, 47, 47, 6, 0, 1, 32, 3, 35, 37, 9, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 71, 276, 37, 42, 94, 303, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 5, 7, 7, 15, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Western Sahara
- { 14, 4, 258, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 0, 0, 31, 0, 318, 340, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 0, 0, 6, 0, 22, 6, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/World
- { 14, 4, 259, 47, 47, 47, 47, 53, 21, 22, 23, 25, 26, 28, 30, 11, 10, 13, 12, 137, 154, 42, 54, 596, 596, 596, 596, 647, 647, 24, 24, 80, 84, 22, 112, 386, 31, 0, 94, 346, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 9, 6, 0, 7, 5, {89,69,82}, 0, 0, 7, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Yemen
- { 15, 66, 220, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 14, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Aragonese/Latin/Spain
- { 17, 5, 12, 0, 0, 54, 54, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 17, 18, 164, 184, 0, 0, 660, 660, 721, 721, 748, 748, 0, 0, 121, 127, 22, 117, 395, 19, 0, 351, 358, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 20, 8, 10, 5, 61, 61, 27, 27, 13, 13, 2, 2, 6, 17, 23, 1, 13, 5, 0, 7, 8, {65,77,68}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Armenian/Armenian/Armenia
- { 18, 9, 110, 0, 0, 61, 61, 6, 0, 1, 2, 39, 4, 5, 9, 10, 11, 12, 13, 192, 210, 61, 61, 761, 761, 818, 818, 849, 849, 25, 25, 144, 148, 22, 118, 408, 9, 13, 366, 373, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 12, 7, 57, 57, 31, 31, 13, 13, 9, 7, 4, 37, 23, 1, 12, 4, 6, 7, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Assamese/Bangla/India
- { 19, 66, 220, 0, 0, 70, 70, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 10, 11, 218, 87, 0, 0, 862, 862, 915, 915, 942, 942, 34, 32, 0, 5, 22, 14, 420, 19, 0, 377, 386, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 6, 10, 5, 53, 53, 27, 27, 13, 13, 12, 11, 5, 17, 23, 1, 4, 5, 0, 9, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Asturian/Latin/Spain
- { 20, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 955, 955, 1014, 1014, 1041, 1041, 46, 43, 0, 5, 22, 119, 424, 19, 0, 392, 398, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 59, 59, 27, 27, 13, 13, 9, 8, 4, 17, 23, 3, 21, 5, 0, 6, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Asu/Latin/Tanzania
- { 21, 66, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 122, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Atsam/Latin/Nigeria
- { 25, 66, 17, 0, 0, 77, 77, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 240, 184, 0, 0, 1054, 1054, 1120, 1146, 96, 96, 0, 0, 185, 5, 22, 123, 445, 19, 0, 406, 416, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 10, 5, 66, 66, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 17, 5, 0, 10, 10, {65,90,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Azerbaijani/Latin/Azerbaijan
- { 25, 4, 112, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 0, 0, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Azerbaijani/Arabic/Iran
- { 25, 27, 17, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 19, 20, 240, 184, 0, 0, 1172, 1172, 1238, 1238, 96, 96, 55, 51, 0, 5, 22, 123, 462, 19, 0, 426, 436, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 10, 5, 66, 66, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 5, 5, 0, 10, 10, {65,90,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Azerbaijani/Cyrillic/Azerbaijan
- { 26, 66, 40, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 12, 13, 71, 87, 0, 0, 1264, 1264, 1308, 1308, 1336, 1336, 57, 53, 0, 5, 22, 3, 467, 19, 0, 446, 451, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 44, 44, 28, 28, 13, 13, 6, 7, 4, 17, 23, 4, 4, 5, 0, 5, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Bafia/Latin/Cameroon
- { 28, 66, 145, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 17, 18, 10, 11, 71, 87, 0, 0, 1349, 1349, 1392, 1392, 1419, 1419, 0, 0, 0, 5, 22, 124, 471, 9, 13, 458, 467, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 43, 43, 27, 27, 13, 13, 2, 2, 4, 17, 23, 5, 17, 4, 6, 9, 4, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Bambara/Latin/Mali
- { 28, 90, 145, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 124, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 5, 0, 5, 0, 0, 0, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Bambara/Nko/Mali
- { 30, 9, 20, 0, 0, 85, 85, 6, 0, 1, 2, 39, 4, 5, 9, 10, 11, 12, 13, 192, 87, 42, 54, 1432, 1432, 1489, 1489, 1525, 1525, 0, 0, 144, 5, 22, 129, 488, 0, 49, 471, 476, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 57, 57, 36, 36, 17, 17, 2, 2, 4, 17, 23, 1, 14, 4, 6, 5, 8, {66,68,84}, 2, 1, 7, 6, 7, 1, 2, 3 }, // Bangla/Bangla/Bangladesh
- { 30, 9, 110, 0, 0, 85, 85, 6, 0, 1, 2, 39, 4, 5, 9, 10, 11, 12, 13, 192, 87, 42, 54, 1432, 1432, 1489, 1489, 1525, 1525, 0, 0, 144, 5, 22, 118, 502, 9, 13, 471, 484, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 57, 57, 36, 36, 17, 17, 2, 2, 4, 17, 23, 1, 12, 4, 6, 5, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Bangla/Bangla/India
- { 31, 66, 40, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 15, 10, 71, 87, 0, 0, 1542, 1542, 1611, 1611, 1638, 1638, 63, 60, 0, 5, 22, 3, 514, 19, 0, 488, 493, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 69, 69, 27, 27, 13, 13, 10, 9, 4, 17, 23, 4, 15, 5, 0, 5, 8, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Basaa/Latin/Cameroon
- { 32, 27, 193, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 130, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Bashkir/Cyrillic/Russia
- { 33, 66, 220, 0, 0, 94, 94, 6, 1, 0, 2, 3, 40, 5, 9, 17, 18, 10, 11, 257, 293, 73, 0, 1651, 1651, 1718, 1718, 1745, 1745, 0, 0, 189, 5, 22, 14, 529, 19, 24, 501, 508, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 36, 6, 12, 5, 67, 67, 27, 27, 13, 13, 2, 2, 7, 17, 23, 1, 5, 5, 7, 7, 8, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Basque/Latin/Spain
- { 35, 27, 22, 0, 0, 103, 103, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 15, 10, 299, 185, 85, 0, 1758, 1758, 1813, 1813, 1833, 1833, 0, 0, 196, 201, 22, 131, 534, 19, 0, 516, 526, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 7, 11, 5, 55, 55, 20, 20, 13, 13, 2, 2, 5, 17, 23, 2, 16, 5, 0, 10, 8, {66,89,78}, 2, 0, 1, 6, 7, 2, 3, 3 }, // Belarusian/Cyrillic/Belarus
- { 36, 66, 260, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 1846, 1846, 1846, 1846, 83, 83, 73, 69, 0, 5, 22, 133, 0, 9, 13, 534, 543, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 79, 79, 79, 79, 13, 13, 8, 7, 4, 17, 23, 1, 0, 4, 6, 9, 6, {90,77,87}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Bemba/Latin/Zambia
- { 37, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 1925, 1925, 2006, 2006, 2033, 2033, 81, 76, 0, 5, 22, 119, 550, 0, 0, 549, 555, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 81, 81, 27, 27, 13, 13, 7, 7, 4, 17, 23, 3, 22, 4, 0, 6, 10, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Bena/Latin/Tanzania
- { 38, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 41, 4, 5, 9, 10, 11, 12, 13, 27, 44, 42, 54, 2046, 2046, 2046, 2046, 83, 83, 88, 83, 0, 5, 22, 118, 0, 9, 0, 565, 572, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 55, 55, 55, 55, 13, 13, 3, 4, 4, 17, 23, 1, 0, 4, 0, 7, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Bhojpuri/Devanagari/India
- { 40, 33, 74, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 0, 0, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Blin/Ethiopic/Eritrea
- { 41, 29, 110, 0, 0, 110, 120, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 240, 321, 96, 108, 2101, 2155, 2208, 2208, 2240, 2240, 91, 87, 0, 5, 22, 118, 572, 9, 13, 576, 572, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 10, 54, 53, 32, 32, 17, 17, 3, 6, 4, 17, 23, 1, 11, 4, 6, 3, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Bodo/Devanagari/India
- { 42, 66, 29, 0, 0, 129, 129, 6, 1, 0, 2, 3, 4, 5, 9, 15, 11, 12, 13, 331, 350, 0, 0, 2257, 2257, 2314, 2314, 2341, 2354, 94, 93, 218, 5, 22, 134, 583, 19, 0, 579, 587, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 11, 10, 5, 57, 57, 27, 27, 13, 13, 10, 7, 7, 17, 23, 2, 40, 5, 0, 8, 19, {66,65,77}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Bosnian/Latin/Bosnia And Herzegovina
- { 42, 27, 29, 0, 0, 136, 136, 6, 1, 0, 2, 3, 4, 5, 9, 15, 10, 16, 12, 361, 381, 0, 0, 2367, 2367, 2422, 2422, 2449, 2449, 104, 100, 0, 5, 22, 136, 623, 19, 0, 606, 614, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 20, 7, 10, 5, 55, 55, 27, 27, 13, 13, 11, 13, 4, 17, 23, 2, 19, 5, 0, 8, 19, {66,65,77}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Bosnian/Cyrillic/Bosnia And Herzegovina
- { 43, 66, 84, 0, 0, 143, 143, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 10, 11, 71, 127, 0, 0, 2462, 2462, 2504, 2504, 2536, 2536, 115, 113, 225, 232, 249, 14, 420, 19, 0, 633, 642, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 42, 42, 32, 32, 17, 17, 4, 4, 7, 17, 23, 1, 4, 5, 0, 9, 5, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Breton/Latin/France
- { 45, 27, 36, 0, 0, 136, 136, 6, 1, 14, 2, 3, 4, 5, 9, 15, 10, 15, 10, 299, 388, 118, 132, 2553, 2553, 2607, 2607, 2627, 2627, 119, 117, 272, 5, 22, 138, 642, 19, 24, 647, 656, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 12, 14, 9, 54, 54, 20, 20, 13, 13, 6, 6, 7, 17, 23, 3, 13, 5, 7, 9, 8, {66,71,78}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Bulgarian/Cyrillic/Bulgaria
- { 46, 86, 161, 151, 151, 158, 158, 168, 0, 1, 2, 42, 4, 5, 9, 10, 11, 12, 13, 400, 87, 141, 1, 2640, 2640, 2640, 2640, 2693, 2693, 125, 123, 279, 5, 22, 133, 655, 4, 0, 664, 664, 7, 7, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 10, 4, 53, 53, 53, 53, 13, 13, 5, 3, 5, 17, 23, 1, 11, 5, 0, 6, 6, {77,77,75}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Burmese/Myanmar/Myanmar
- { 47, 137, 107, 169, 169, 174, 174, 6, 0, 1, 2, 3, 4, 5, 9, 43, 44, 45, 46, 418, 432, 151, 27, 2706, 2706, 2706, 2706, 2733, 2733, 130, 126, 0, 5, 22, 141, 666, 9, 13, 670, 672, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 14, 8, 13, 6, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 2, 4, 6, 2, 14, {72,75,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Cantonese/Traditional Han/Hong Kong
- { 47, 118, 50, 169, 169, 174, 174, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 440, 432, 141, 0, 2706, 2706, 2746, 2746, 2733, 2733, 130, 126, 0, 5, 22, 144, 668, 9, 13, 686, 688, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 8, 10, 5, 27, 27, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 3, 4, 6, 2, 7, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Cantonese/Simplified Han/China
- { 48, 66, 220, 0, 0, 129, 129, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 10, 11, 218, 87, 74, 1, 2766, 2766, 2825, 2825, 2852, 2852, 132, 128, 0, 5, 22, 14, 420, 19, 24, 695, 701, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 6, 11, 4, 59, 59, 27, 27, 20, 20, 5, 5, 5, 17, 23, 1, 4, 5, 7, 6, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Catalan/Latin/Spain
- { 48, 66, 6, 0, 0, 129, 129, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 10, 11, 218, 87, 74, 1, 2766, 2766, 2825, 2825, 2852, 2852, 132, 128, 0, 5, 22, 14, 420, 19, 24, 695, 708, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 6, 11, 4, 59, 59, 27, 27, 20, 20, 5, 5, 5, 17, 23, 1, 4, 5, 7, 6, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Catalan/Latin/Andorra
- { 48, 66, 84, 0, 0, 129, 129, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 10, 11, 218, 87, 74, 1, 2766, 2766, 2825, 2825, 2852, 2852, 132, 128, 0, 5, 22, 14, 420, 19, 24, 695, 715, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 6, 11, 4, 59, 59, 27, 27, 20, 20, 5, 5, 5, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Catalan/Latin/France
- { 48, 66, 117, 0, 0, 129, 129, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 10, 11, 218, 87, 74, 1, 2766, 2766, 2825, 2825, 2852, 2852, 132, 128, 0, 5, 22, 14, 420, 19, 24, 695, 721, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 6, 11, 4, 59, 59, 27, 27, 20, 20, 5, 5, 5, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Catalan/Latin/Italy
- { 49, 66, 185, 0, 0, 179, 188, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 471, 10, 22, 2872, 2872, 2927, 2927, 2954, 2954, 0, 0, 284, 5, 22, 145, 671, 9, 13, 727, 734, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 55, 55, 27, 27, 13, 13, 2, 2, 8, 17, 23, 1, 15, 4, 6, 7, 9, {80,72,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Cebuano/Latin/Philippines
- { 50, 66, 159, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 2967, 2967, 3014, 3014, 3041, 3041, 137, 133, 0, 5, 22, 0, 686, 19, 0, 743, 760, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 47, 47, 27, 27, 13, 13, 9, 10, 4, 17, 23, 0, 15, 5, 0, 17, 6, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Central Atlas Tamazight/Latin/Morocco
- { 51, 4, 113, 0, 0, 0, 0, 53, 21, 22, 23, 25, 47, 49, 30, 10, 11, 12, 13, 27, 44, 42, 54, 3054, 3054, 3054, 3054, 3111, 3111, 146, 143, 0, 5, 22, 41, 701, 19, 0, 766, 780, 6, 6, 6, 6, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 7, 57, 57, 57, 57, 13, 13, 3, 3, 4, 17, 23, 5, 13, 5, 0, 14, 5, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Central Kurdish/Arabic/Iraq
- { 51, 4, 112, 0, 0, 0, 0, 53, 21, 22, 23, 25, 47, 49, 30, 10, 11, 12, 13, 27, 44, 0, 0, 3054, 3054, 3054, 3054, 3111, 3111, 146, 143, 0, 5, 22, 0, 714, 19, 0, 766, 785, 6, 6, 6, 6, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 10, 5, 57, 57, 57, 57, 13, 13, 3, 3, 4, 17, 23, 0, 12, 5, 0, 14, 5, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Central Kurdish/Arabic/Iran
- { 52, 21, 20, 0, 0, 196, 196, 6, 0, 1, 2, 51, 4, 5, 9, 10, 11, 12, 13, 192, 87, 42, 54, 3124, 3124, 3250, 3250, 3334, 3334, 0, 0, 292, 5, 22, 129, 726, 0, 49, 790, 802, 6, 6, 12, 12, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7,126,126, 84, 84, 38, 38, 2, 2, 8, 17, 23, 1, 21, 4, 6, 12, 14, {66,68,84}, 2, 1, 7, 6, 7, 1, 2, 3 }, // Chakma/Chakma/Bangladesh
- { 52, 21, 110, 0, 0, 196, 196, 6, 0, 1, 2, 51, 4, 5, 9, 10, 11, 12, 13, 192, 87, 42, 54, 3124, 3124, 3250, 3250, 3334, 3334, 0, 0, 292, 5, 22, 118, 747, 0, 49, 790, 816, 6, 6, 12, 12, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7,126,126, 84, 84, 38, 38, 2, 2, 8, 17, 23, 1, 27, 4, 6, 12, 10, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Chakma/Chakma/India
- { 54, 27, 193, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 3372, 3372, 3416, 3416, 3440, 3416, 0, 0, 0, 5, 22, 130, 774, 19, 0, 826, 833, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 44, 44, 24, 24, 16, 24, 2, 2, 4, 17, 23, 1, 11, 5, 0, 7, 5, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Chechen/Cyrillic/Russia
- { 55, 23, 248, 0, 0, 208, 217, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 471, 42, 54, 3456, 3456, 3504, 3504, 3531, 3531, 149, 146, 300, 5, 22, 2, 785, 9, 13, 838, 841, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 48, 48, 27, 27, 13, 13, 3, 6, 6, 17, 23, 1, 6, 4, 6, 3, 15, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Cherokee/Cherokee/United States
- { 56, 66, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 146, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 0, 0, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chickasaw/Latin/United States
- { 57, 66, 243, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 3544, 3544, 3617, 3617, 3644, 3644, 0, 0, 0, 5, 22, 149, 791, 9, 0, 856, 862, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 73, 73, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 19, 4, 0, 6, 6, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Chiga/Latin/Uganda
- { 58, 118, 50, 169, 169, 225, 225, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 440, 432, 141, 0, 2706, 2706, 2746, 2746, 2733, 2733, 130, 126, 306, 5, 22, 152, 668, 9, 13, 868, 872, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 8, 10, 5, 27, 27, 20, 20, 13, 13, 2, 2, 2, 17, 23, 1, 3, 4, 6, 4, 2, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Chinese/Simplified Han/China
- { 58, 118, 107, 169, 169, 225, 225, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 440, 87, 164, 27, 2706, 2706, 2746, 2746, 2733, 2733, 130, 126, 306, 5, 22, 141, 810, 9, 13, 868, 874, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 6, 11, 6, 27, 27, 20, 20, 13, 13, 2, 2, 2, 17, 23, 3, 2, 4, 6, 4, 9, {72,75,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chinese/Simplified Han/Hong Kong
- { 58, 118, 139, 169, 169, 225, 225, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 440, 87, 164, 27, 2706, 2706, 2746, 2746, 2733, 2733, 130, 126, 306, 5, 22, 153, 812, 9, 13, 868, 883, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 6, 11, 6, 27, 27, 20, 20, 13, 13, 2, 2, 2, 17, 23, 4, 3, 4, 6, 4, 9, {77,79,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chinese/Simplified Han/Macao
- { 58, 118, 210, 169, 169, 225, 225, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 440, 127, 164, 27, 2706, 2706, 2746, 2746, 2733, 2733, 130, 126, 306, 5, 22, 2, 815, 9, 13, 868, 892, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 8, 11, 6, 27, 27, 20, 20, 13, 13, 2, 2, 2, 17, 23, 1, 4, 4, 6, 4, 3, {83,71,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chinese/Simplified Han/Singapore
- { 58, 137, 107, 169, 169, 230, 230, 6, 0, 1, 2, 3, 4, 5, 9, 43, 44, 45, 46, 440, 87, 151, 27, 2706, 2706, 3657, 3657, 2733, 2733, 130, 126, 308, 5, 22, 141, 810, 9, 13, 895, 899, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 8, 13, 6, 27, 27, 20, 20, 13, 13, 2, 2, 3, 17, 23, 3, 2, 4, 6, 4, 9, {72,75,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chinese/Traditional Han/Hong Kong
- { 58, 137, 139, 169, 169, 230, 230, 6, 0, 1, 2, 3, 4, 5, 9, 43, 44, 45, 46, 440, 87, 151, 27, 2706, 2706, 3657, 3657, 2733, 2733, 130, 126, 308, 5, 22, 153, 819, 9, 13, 895, 908, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 8, 13, 6, 27, 27, 20, 20, 13, 13, 2, 2, 3, 17, 23, 4, 3, 4, 6, 4, 9, {77,79,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chinese/Traditional Han/Macao
- { 58, 137, 228, 169, 169, 225, 225, 6, 0, 1, 2, 3, 4, 5, 9, 43, 44, 45, 46, 418, 432, 175, 175, 2706, 2706, 3657, 3657, 2733, 2733, 130, 126, 0, 5, 22, 2, 822, 9, 13, 895, 917, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 14, 8, 12, 5, 27, 27, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 3, 4, 6, 4, 2, {84,87,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Chinese/Traditional Han/Taiwan
- { 59, 27, 193, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 130, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Church/Cyrillic/Russia
- { 60, 27, 193, 0, 0, 235, 235, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 15, 10, 477, 499, 0, 0, 3677, 3677, 3742, 3742, 3774, 3774, 0, 0, 0, 5, 22, 130, 825, 19, 0, 919, 924, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 10, 5, 65, 65, 32, 32, 13, 13, 2, 2, 4, 17, 23, 1, 12, 5, 0, 5, 6, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Chuvash/Cyrillic/Russia
- { 61, 66, 91, 0, 0, 245, 245, 6, 1, 14, 2, 3, 40, 5, 53, 15, 10, 16, 12, 509, 350, 0, 0, 3787, 3787, 3858, 3858, 3885, 3885, 152, 152, 0, 5, 22, 14, 73, 19, 0, 930, 936, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 23, 10, 10, 5, 71, 71, 27, 27, 13, 13, 16, 16, 4, 17, 23, 1, 4, 5, 0, 6, 11, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Colognian/Latin/Germany
- { 63, 66, 246, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 127, 0, 0, 3898, 3898, 3958, 3958, 83, 83, 168, 168, 0, 5, 22, 92, 0, 9, 0, 947, 955, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 60, 60, 27, 27, 13, 13, 4, 4, 4, 17, 23, 1, 0, 4, 0, 8, 14, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Cornish/Latin/United Kingdom
- { 64, 66, 84, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 14, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Corsican/Latin/France
- { 66, 66, 60, 0, 0, 129, 129, 6, 1, 0, 2, 3, 40, 5, 9, 15, 10, 16, 12, 331, 532, 73, 0, 2257, 2257, 2314, 2314, 2341, 2354, 0, 0, 218, 5, 22, 14, 420, 19, 0, 969, 977, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 13, 12, 5, 57, 57, 27, 27, 13, 13, 2, 2, 7, 17, 23, 1, 4, 5, 0, 8, 8, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Croatian/Latin/Croatia
- { 66, 66, 29, 0, 0, 129, 129, 6, 1, 0, 2, 3, 40, 5, 9, 15, 10, 16, 12, 331, 545, 73, 0, 2257, 2257, 2314, 2314, 2354, 2354, 0, 0, 218, 5, 22, 134, 604, 19, 0, 969, 587, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 9, 12, 5, 57, 57, 27, 27, 13, 13, 2, 2, 7, 17, 23, 2, 19, 5, 0, 8, 19, {66,65,77}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Croatian/Latin/Bosnia And Herzegovina
- { 67, 66, 64, 0, 0, 253, 253, 6, 1, 14, 2, 3, 4, 5, 9, 15, 10, 16, 12, 554, 184, 86, 1, 3985, 3985, 4033, 4033, 4053, 4053, 172, 172, 311, 5, 22, 157, 837, 19, 0, 985, 992, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 10, 4, 48, 48, 20, 20, 13, 13, 4, 4, 5, 17, 23, 2, 12, 5, 0, 7, 5, {67,90,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Czech/Latin/Czechia
- { 68, 66, 65, 0, 0, 260, 260, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 571, 499, 187, 187, 4066, 4066, 4116, 4116, 4152, 4152, 0, 0, 0, 5, 22, 159, 849, 19, 0, 997, 1002, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 10, 5, 50, 50, 36, 36, 13, 13, 2, 2, 5, 17, 23, 3, 11, 5, 0, 5, 7, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Danish/Latin/Denmark
- { 68, 66, 95, 0, 0, 260, 260, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 571, 499, 187, 187, 4066, 4066, 4116, 4116, 4152, 4152, 0, 0, 0, 5, 22, 159, 849, 19, 0, 997, 1009, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 10, 5, 50, 50, 36, 36, 13, 13, 2, 2, 5, 17, 23, 3, 11, 5, 0, 5, 8, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Danish/Latin/Greenland
- { 69, 132, 144, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 0, 0, {77,86,82}, 2, 1, 5, 6, 7, 1, 3, 3 }, // Divehi/Thaana/Maldives
- { 70, 29, 110, 0, 0, 268, 277, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 594, 87, 42, 54, 4165, 4165, 4215, 4215, 4244, 4266, 176, 176, 0, 5, 22, 118, 860, 9, 0, 1017, 572, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 50, 50, 29, 29, 22, 24, 4, 9, 4, 17, 23, 1, 10, 4, 0, 5, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Dogri/Devanagari/India
- { 71, 66, 40, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 12, 13, 71, 87, 0, 0, 4290, 4290, 4334, 4334, 4361, 4361, 180, 185, 0, 5, 22, 3, 0, 19, 0, 1022, 1027, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 44, 44, 27, 27, 13, 13, 5, 6, 4, 17, 23, 4, 0, 5, 0, 5, 8, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Duala/Latin/Cameroon
- { 72, 66, 165, 0, 0, 7, 7, 6, 1, 0, 2, 3, 4, 5, 9, 12, 13, 12, 13, 71, 321, 0, 0, 4374, 4374, 4432, 4432, 4452, 4452, 168, 168, 0, 5, 22, 14, 73, 4, 55, 1035, 1035, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 1, 4, 5, 7, 10, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Netherlands
- { 72, 66, 13, 0, 0, 7, 7, 6, 1, 0, 2, 3, 4, 5, 9, 12, 13, 12, 13, 71, 321, 0, 0, 4374, 4374, 4432, 4432, 4452, 4452, 168, 168, 0, 5, 22, 162, 870, 4, 55, 1035, 1045, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 4, 16, 5, 7, 10, 5, {65,87,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Aruba
- { 72, 66, 23, 0, 0, 7, 7, 6, 1, 0, 2, 3, 4, 5, 9, 12, 13, 12, 13, 71, 128, 0, 0, 4374, 4374, 4432, 4432, 4452, 4452, 168, 168, 0, 5, 22, 14, 73, 4, 55, 1050, 1056, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 9, 10, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Belgium
- { 72, 66, 44, 0, 0, 7, 7, 6, 1, 0, 2, 3, 4, 5, 9, 12, 13, 12, 13, 71, 321, 0, 0, 4374, 4374, 4432, 4432, 4452, 4452, 168, 168, 0, 5, 22, 2, 886, 4, 55, 1035, 1062, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 1, 18, 5, 7, 10, 19, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Caribbean Netherlands
- { 72, 66, 62, 0, 0, 7, 7, 6, 1, 0, 2, 3, 4, 5, 9, 12, 13, 12, 13, 71, 321, 0, 0, 4374, 4374, 4432, 4432, 4452, 4452, 168, 168, 0, 5, 22, 166, 904, 4, 55, 1035, 1081, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 4, 30, 5, 7, 10, 7, {65,78,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Curacao
- { 72, 66, 211, 0, 0, 7, 7, 6, 1, 0, 2, 3, 4, 5, 9, 12, 13, 12, 13, 71, 321, 0, 0, 4374, 4374, 4432, 4432, 4452, 4452, 168, 168, 0, 5, 22, 166, 904, 4, 55, 1035, 1088, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 4, 30, 5, 7, 10, 12, {65,78,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Sint Maarten
- { 72, 66, 223, 0, 0, 7, 7, 6, 1, 0, 2, 3, 4, 5, 9, 12, 13, 12, 13, 71, 321, 0, 0, 4374, 4374, 4432, 4432, 4452, 4452, 168, 168, 0, 5, 22, 2, 934, 4, 55, 1035, 1100, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 1, 17, 5, 7, 10, 8, {83,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Suriname
- { 73, 134, 27, 285, 285, 285, 285, 6, 0, 1, 2, 57, 4, 5, 9, 10, 11, 12, 13, 612, 44, 197, 224, 4465, 4465, 4543, 4543, 4576, 4576, 185, 191, 0, 5, 22, 170, 951, 9, 0, 1108, 1114, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 30, 10, 27, 22, 78, 78, 33, 33, 26, 26, 5, 6, 4, 17, 23, 3, 8, 4, 0, 6, 5, {66,84,78}, 2, 1, 7, 6, 7, 1, 2, 3 }, // Dzongkha/Tibetan/Bhutan
- { 74, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 4602, 4602, 4665, 4665, 4692, 4692, 190, 197, 0, 5, 22, 173, 959, 9, 13, 1119, 1125, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 63, 63, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 17, 4, 6, 6, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Embu/Latin/Kenya
- { 75, 66, 248, 0, 0, 294, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 471, 10, 22, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 2, 976, 9, 13, 1130, 1146, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 16, 13, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/United States
- { 75, 28, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 146, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 0, 0, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Deseret/United States
- { 75, 66, 5, 0, 0, 294, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 471, 10, 22, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 2, 976, 9, 13, 1139, 1159, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 14, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/American Samoa
- { 75, 66, 8, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 985, 9, 13, 1139, 1173, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 8, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Anguilla
- { 75, 66, 10, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 985, 9, 13, 1139, 1181, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 17, {88,67,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Antigua And Barbuda
- { 75, 66, 15, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 6, 10, 11, 12, 13, 0, 87, 10, 22, 0, 0, 56, 56, 4705, 4705, 82, 199, 0, 5, 22, 2, 1006, 9, 13, 1198, 1198, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 56, 56, 27, 27, 24, 24, 2, 2, 5, 17, 23, 1, 17, 4, 6, 18, 9, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Australia
- { 75, 66, 16, 0, 0, 304, 304, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 14, 73, 4, 0, 1139, 1216, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Austria
- { 75, 66, 18, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1023, 9, 13, 1139, 1223, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 7, {66,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Bahamas
- { 75, 66, 21, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1038, 9, 13, 1139, 1230, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 16, 4, 6, 7, 8, {66,66,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Barbados
- { 75, 66, 23, 0, 0, 304, 304, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 14, 73, 19, 0, 1139, 1238, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Belgium
- { 75, 66, 24, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 642, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1054, 9, 13, 1139, 1245, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 13, 4, 6, 7, 6, {66,90,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Belize
- { 75, 66, 26, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1067, 9, 13, 1139, 1251, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 16, 4, 6, 7, 7, {66,77,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Bermuda
- { 75, 66, 30, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 642, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 155, 1083, 9, 13, 1139, 1258, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 14, 4, 6, 7, 8, {66,87,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Botswana
- { 75, 66, 33, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 146, 976, 9, 13, 1139, 1266, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 30, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/British Indian Ocean Territory
- { 75, 66, 34, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 146, 976, 9, 13, 1139, 1296, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 22, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/British Virgin Islands
- { 75, 66, 38, 0, 0, 294, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 471, 0, 0, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 176, 1097, 9, 13, 1139, 1318, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 15, 4, 6, 7, 7, {66,73,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Burundi
- { 75, 66, 40, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 3, 1112, 9, 13, 1139, 1325, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 4, 25, 4, 6, 7, 8, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Cameroon
- { 75, 66, 41, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 471, 10, 22, 0, 0, 56, 56, 83, 83, 168, 168, 0, 5, 22, 2, 1137, 9, 13, 1333, 1349, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 56, 56, 27, 27, 13, 13, 4, 4, 5, 17, 23, 1, 15, 4, 6, 16, 6, {67,65,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // English/Latin/Canada
- { 75, 66, 45, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1152, 9, 13, 1139, 1355, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 14, {75,89,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Cayman Islands
- { 75, 66, 51, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1006, 9, 13, 1139, 1369, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 16, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Christmas Island
- { 75, 66, 53, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1006, 9, 13, 1139, 1385, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 23, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Cocos Islands
- { 75, 66, 58, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1173, 9, 13, 1139, 1408, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 12, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Cook Islands
- { 75, 66, 63, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 14, 73, 9, 13, 1139, 1420, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 4, 6, 7, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Cyprus
- { 75, 66, 65, 0, 0, 304, 304, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 187, 187, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 159, 1191, 19, 0, 1139, 1426, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 12, 5, 0, 7, 7, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Denmark
- { 75, 66, 66, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 146, 976, 9, 13, 1139, 1433, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 12, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Diego Garcia
- { 75, 66, 68, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 985, 9, 13, 1139, 1445, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 8, {88,67,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Dominica
- { 75, 66, 74, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 38, 1203, 9, 13, 1139, 1453, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 14, 4, 6, 7, 7, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Eritrea
- { 75, 66, 76, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 179, 1217, 9, 13, 1139, 1460, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 8, {83,90,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Eswatini
- { 75, 66, 78, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 0, 0, 19, 0, 1139, 1468, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 0, 5, 0, 7, 6, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Europe
- { 75, 66, 80, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 92, 1232, 9, 13, 1139, 1474, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 22, 4, 6, 7, 16, {70,75,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Falkland Islands
- { 75, 66, 82, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1254, 9, 13, 1139, 1490, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 13, 4, 6, 7, 4, {70,74,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Fiji
- { 75, 66, 83, 0, 0, 304, 304, 6, 1, 14, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 188, 188, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 14, 73, 19, 0, 1139, 1494, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 9, 4, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Finland
- { 75, 66, 89, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 180, 1267, 9, 13, 1139, 1501, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 14, 4, 6, 7, 6, {71,77,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Gambia
- { 75, 66, 91, 0, 0, 304, 304, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 14, 73, 19, 0, 1139, 1507, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Germany
- { 75, 66, 92, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 7, 1281, 9, 13, 1139, 1514, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 13, 4, 6, 7, 5, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Ghana
- { 75, 66, 93, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 92, 1294, 9, 13, 1139, 1519, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 9, {71,73,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Gibraltar
- { 75, 66, 96, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 985, 9, 13, 1139, 1528, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 7, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Grenada
- { 75, 66, 98, 0, 0, 294, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 471, 10, 22, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 2, 976, 9, 13, 1139, 1535, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 4, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Guam
- { 75, 66, 100, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 92, 1309, 9, 13, 1139, 1539, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 8, 4, 6, 7, 8, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Guernsey
- { 75, 66, 103, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1317, 9, 13, 1139, 1547, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 16, 4, 6, 7, 6, {71,89,68}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Guyana
- { 75, 66, 107, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 87, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 141, 1333, 9, 13, 1139, 1553, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 16, 4, 6, 7, 19, {72,75,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Hong Kong
- { 75, 66, 110, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 192, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 118, 1349, 9, 13, 1139, 1274, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 12, 4, 6, 7, 5, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // English/Latin/India
- { 75, 66, 114, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 127, 0, 0, 0, 0, 56, 56, 83, 83, 168, 168, 0, 5, 22, 14, 73, 9, 13, 1139, 1572, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 56, 56, 27, 27, 13, 13, 4, 4, 5, 17, 23, 1, 4, 4, 6, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Ireland
- { 75, 66, 115, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 92, 1309, 9, 13, 1139, 1579, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 8, 4, 6, 7, 11, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Isle Of Man
- { 75, 66, 116, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 1, 1, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 46, 1361, 9, 13, 1139, 1590, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 9, 4, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 6, {73,76,83}, 2, 1, 7, 5, 6, 1, 3, 3 }, // English/Latin/Israel
- { 75, 66, 119, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 87, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1379, 9, 13, 1139, 1596, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 7, {74,77,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Jamaica
- { 75, 66, 121, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 92, 1309, 9, 13, 1139, 1603, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 8, 4, 6, 7, 6, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Jersey
- { 75, 66, 124, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 173, 1394, 9, 13, 1139, 1125, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 15, 4, 6, 7, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Kenya
- { 75, 66, 125, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1006, 9, 13, 1139, 1609, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 8, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Kiribati
- { 75, 66, 133, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 1, 1409, 9, 13, 1139, 1617, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 7, {90,65,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Lesotho
- { 75, 66, 134, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1427, 9, 13, 1139, 1624, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 7, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Liberia
- { 75, 66, 139, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 153, 1442, 9, 13, 1139, 1631, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 4, 15, 4, 6, 7, 15, {77,79,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Macao
- { 75, 66, 141, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 181, 1457, 9, 13, 1139, 1646, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 15, 4, 6, 7, 10, {77,71,65}, 0, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Madagascar
- { 75, 66, 142, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 183, 1472, 9, 13, 1139, 1656, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 15, 4, 6, 7, 6, {77,87,75}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Malawi
- { 75, 66, 143, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 185, 1487, 9, 13, 1139, 1662, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 17, 4, 6, 7, 8, {77,89,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Malaysia
- { 75, 66, 144, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 210, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 187, 1504, 4, 0, 1139, 1670, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 17, 5, 0, 7, 8, {77,86,82}, 2, 1, 5, 6, 7, 1, 3, 3 }, // English/Latin/Maldives
- { 75, 66, 146, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 14, 73, 9, 13, 1139, 1678, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 4, 6, 7, 5, {69,85,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Malta
- { 75, 66, 147, 0, 0, 294, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 471, 10, 22, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 2, 976, 9, 13, 1139, 1683, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 16, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Marshall Islands
- { 75, 66, 150, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 189, 1521, 9, 13, 1139, 1699, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 15, 4, 6, 7, 9, {77,85,82}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Mauritius
- { 75, 66, 153, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 146, 976, 9, 13, 1139, 1708, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 10, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Micronesia
- { 75, 66, 158, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 985, 9, 13, 1139, 1718, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 10, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Montserrat
- { 75, 66, 162, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1536, 9, 13, 1139, 1728, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 7, {78,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Namibia
- { 75, 66, 163, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1006, 9, 13, 1139, 1735, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 5, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Nauru
- { 75, 66, 165, 0, 0, 304, 304, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 14, 73, 4, 55, 1139, 1740, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 7, 7, 11, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Netherlands
- { 75, 66, 167, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 128, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1173, 9, 13, 1139, 1751, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 7, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 11, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/New Zealand
- { 75, 66, 169, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 122, 1551, 9, 13, 1139, 1762, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 14, 4, 6, 7, 7, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Nigeria
- { 75, 66, 171, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1173, 9, 13, 1139, 1769, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 4, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Niue
- { 75, 66, 172, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1006, 9, 13, 1139, 1773, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 14, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Norfolk Island
- { 75, 66, 173, 0, 0, 294, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 471, 10, 22, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 2, 976, 9, 13, 1139, 1787, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 24, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Northern Mariana Islands
- { 75, 66, 178, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 189, 1565, 9, 13, 1139, 1811, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 15, 4, 6, 7, 8, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // English/Latin/Pakistan
- { 75, 66, 179, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 146, 976, 9, 13, 1139, 1819, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 5, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Palau
- { 75, 66, 182, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 133, 1580, 9, 13, 1139, 1824, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 22, 4, 6, 7, 16, {80,71,75}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Papua New Guinea
- { 75, 66, 185, 0, 0, 294, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 471, 10, 22, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 145, 671, 9, 13, 1139, 1840, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 11, {80,72,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Philippines
- { 75, 66, 186, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1173, 9, 13, 1139, 1851, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 16, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Pitcairn
- { 75, 66, 189, 0, 0, 294, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 471, 10, 22, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 2, 976, 9, 13, 1139, 1867, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 11, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Puerto Rico
- { 75, 66, 194, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 191, 1602, 9, 13, 1139, 1878, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 13, 4, 6, 7, 6, {82,87,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Rwanda
- { 75, 66, 196, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 92, 1615, 9, 13, 1139, 1884, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 9, {83,72,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Saint Helena
- { 75, 66, 197, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 985, 9, 13, 1139, 1893, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 16, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Saint Kitts And Nevis
- { 75, 66, 198, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 985, 9, 13, 1139, 1909, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 8, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Saint Lucia
- { 75, 66, 201, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 985, 9, 13, 1139, 1917, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 27, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Saint Vincent And Grenadines
- { 75, 66, 202, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 193, 1630, 9, 13, 1139, 1168, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 11, 4, 6, 7, 5, {87,83,84}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Samoa
- { 75, 66, 208, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 196, 1641, 9, 13, 1139, 1944, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 17, 4, 6, 7, 10, {83,67,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Seychelles
- { 75, 66, 209, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 10, 1658, 9, 13, 1139, 1954, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 20, 4, 6, 7, 12, {83,76,69}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Sierra Leone
- { 75, 66, 210, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 87, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1678, 9, 13, 1139, 1966, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 16, 4, 6, 7, 9, {83,71,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Singapore
- { 75, 66, 211, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 166, 1694, 9, 13, 1139, 1975, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 4, 29, 4, 6, 7, 12, {65,78,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Sint Maarten
- { 75, 66, 213, 0, 0, 304, 304, 6, 1, 0, 2, 3, 4, 5, 6, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 14, 73, 19, 24, 1139, 1987, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 7, 7, 8, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Slovenia
- { 75, 66, 214, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1723, 9, 13, 1139, 1995, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 22, 4, 6, 7, 15, {83,66,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Solomon Islands
- { 75, 66, 216, 0, 0, 304, 304, 6, 1, 14, 2, 3, 4, 5, 9, 10, 11, 12, 13, 642, 660, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 1, 1409, 9, 13, 1139, 2010, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 12, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/South Africa
- { 75, 66, 219, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 92, 1745, 9, 13, 1139, 2022, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 20, 4, 6, 7, 11, {83,83,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/South Sudan
- { 75, 66, 222, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 0, 1765, 9, 13, 1139, 2033, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 14, 4, 6, 7, 5, {83,68,71}, 2, 1, 6, 5, 6, 1, 3, 3 }, // English/Latin/Sudan
- { 75, 66, 225, 0, 0, 304, 304, 6, 1, 14, 2, 3, 4, 5, 53, 10, 11, 12, 13, 0, 44, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 159, 1779, 19, 0, 1139, 2038, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 13, 5, 0, 7, 6, {83,69,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Sweden
- { 75, 66, 226, 0, 0, 304, 304, 6, 0, 13, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 499, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 0, 1792, 4, 62, 1139, 2044, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 11, 5, 5, 7, 11, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Switzerland
- { 75, 66, 230, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 119, 1803, 9, 13, 1139, 2055, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 18, 4, 6, 7, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Tanzania
- { 75, 66, 234, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1173, 9, 13, 1139, 2063, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 7, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Tokelau
- { 75, 66, 235, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 198, 1821, 9, 13, 1139, 2070, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 14, 4, 6, 7, 5, {84,79,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Tonga
- { 75, 66, 236, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1835, 9, 13, 1139, 2075, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 24, 4, 6, 7, 17, {84,84,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Trinidad And Tobago
- { 75, 66, 241, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 146, 976, 9, 13, 1139, 2092, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 22, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Turks And Caicos Islands
- { 75, 66, 242, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 2, 1006, 9, 13, 1139, 2114, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 6, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Tuvalu
- { 75, 66, 243, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 149, 1859, 9, 13, 1139, 862, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 16, 4, 6, 7, 6, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // English/Latin/Uganda
- { 75, 66, 245, 0, 0, 294, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 200, 1875, 9, 13, 1139, 2120, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 27, 4, 6, 7, 20, {65,69,68}, 2, 1, 6, 6, 7, 1, 3, 3 }, // English/Latin/United Arab Emirates
- { 75, 66, 246, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 92, 1902, 9, 13, 2140, 2155, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 13, 4, 6, 15, 14, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/United Kingdom
- { 75, 66, 247, 0, 0, 294, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 471, 10, 22, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 2, 976, 9, 13, 1139, 2169, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 21, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/United States Outlying Islands
- { 75, 66, 249, 0, 0, 294, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 471, 10, 22, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 2, 976, 9, 13, 1139, 2190, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 19, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/United States Virgin Islands
- { 75, 66, 252, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 203, 1915, 9, 13, 1139, 2209, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 12, 4, 6, 7, 7, {86,85,86}, 0, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Vanuatu
- { 75, 66, 258, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 0, 0, 9, 13, 1139, 2216, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 0, 4, 6, 7, 5, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/World
- { 75, 66, 260, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 133, 1927, 9, 13, 1139, 543, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 14, 4, 6, 7, 6, {90,77,87}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Zambia
- { 75, 66, 261, 0, 0, 304, 304, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 642, 87, 0, 0, 0, 0, 56, 56, 83, 83, 82, 199, 0, 5, 22, 146, 976, 9, 13, 1139, 2221, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 8, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Zimbabwe
- { 75, 115, 246, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 92, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Shavian/United Kingdom
- { 76, 27, 193, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 130, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Erzya/Cyrillic/Russia
- { 77, 66, 258, 0, 0, 313, 313, 6, 1, 14, 2, 3, 40, 5, 9, 10, 11, 12, 13, 670, 46, 246, 0, 4729, 4729, 4779, 4779, 4799, 4799, 192, 201, 316, 5, 22, 0, 0, 4, 0, 2229, 2238, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 26, 8, 25, 5, 50, 50, 20, 20, 13, 13, 3, 3, 6, 17, 23, 0, 0, 5, 0, 9, 5, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Esperanto/Latin/World
- { 78, 66, 75, 0, 0, 322, 322, 6, 1, 14, 2, 3, 40, 5, 53, 15, 10, 16, 12, 331, 184, 0, 0, 4812, 4812, 4874, 4874, 4874, 4874, 0, 0, 322, 5, 22, 14, 420, 19, 24, 2243, 2248, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 18, 8, 10, 5, 62, 62, 13, 13, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 5, 5, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Estonian/Latin/Estonia
- { 79, 66, 92, 0, 0, 330, 341, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 696, 471, 271, 271, 4887, 4887, 4930, 4930, 4957, 4957, 195, 204, 0, 5, 22, 7, 1941, 9, 13, 2253, 2259, 6, 6, 11, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 17, 12, 43, 43, 27, 27, 13, 13, 3, 5, 4, 17, 23, 3, 10, 4, 6, 6, 12, {71,72,83}, 2, 1, 1, 6, 7, 3, 3, 3 }, // Ewe/Latin/Ghana
- { 79, 66, 233, 0, 0, 330, 341, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 696, 471, 0, 0, 4887, 4887, 4930, 4930, 4957, 4957, 195, 204, 0, 5, 22, 124, 1951, 9, 13, 2253, 2271, 6, 6, 11, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 10, 5, 43, 43, 27, 27, 13, 13, 3, 5, 4, 17, 23, 5, 33, 4, 6, 6, 11, {88,79,70}, 0, 0, 1, 6, 7, 3, 3, 3 }, // Ewe/Latin/Togo
- { 80, 66, 40, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 10, 11, 71, 87, 0, 0, 4970, 4970, 5054, 5054, 5083, 5083, 198, 209, 0, 5, 22, 3, 1984, 19, 0, 2282, 2288, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 84, 84, 29, 29, 13, 13, 7, 9, 4, 17, 23, 4, 16, 5, 0, 6, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Ewondo/Latin/Cameroon
- { 81, 66, 81, 0, 0, 260, 260, 6, 1, 0, 2, 3, 40, 5, 9, 10, 11, 12, 13, 331, 184, 0, 0, 5096, 5096, 5169, 5196, 5230, 5230, 0, 0, 328, 5, 22, 159, 2000, 19, 24, 2295, 2303, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 73, 73, 27, 34, 13, 13, 2, 2, 3, 17, 23, 2, 11, 5, 7, 8, 7, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Faroese/Latin/Faroe Islands
- { 81, 66, 65, 0, 0, 260, 260, 6, 1, 0, 2, 3, 40, 5, 9, 10, 11, 12, 13, 331, 184, 0, 0, 5096, 5096, 5169, 5196, 5230, 5230, 0, 0, 328, 5, 22, 159, 2000, 19, 24, 2295, 1002, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 73, 73, 27, 34, 13, 13, 2, 2, 3, 17, 23, 3, 11, 5, 7, 8, 7, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Faroese/Latin/Denmark
- { 83, 66, 185, 0, 0, 351, 360, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 471, 10, 22, 5243, 5243, 5297, 5297, 5297, 5297, 0, 0, 0, 5, 22, 145, 2011, 9, 13, 2310, 734, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 54, 54, 27, 27, 27, 27, 2, 2, 5, 17, 23, 1, 17, 4, 6, 8, 9, {80,72,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Filipino/Latin/Philippines
- { 84, 66, 83, 0, 0, 322, 322, 6, 1, 14, 2, 3, 40, 5, 9, 11, 11, 13, 13, 554, 719, 188, 188, 5324, 5390, 5470, 5470, 5490, 5490, 205, 218, 331, 336, 353, 14, 420, 19, 0, 2318, 2323, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 9, 4, 66, 80, 20, 20, 13, 13, 3, 3, 5, 17, 23, 1, 4, 5, 0, 5, 5, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Finnish/Latin/Finland
- { 85, 66, 84, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 14, 420, 19, 24, 2328, 2336, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/France
- { 85, 66, 4, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 10, 22, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 180, 2028, 19, 24, 2328, 2342, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 12, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 7, {68,90,68}, 2, 1, 6, 5, 6, 1, 3, 3 }, // French/Latin/Algeria
- { 85, 66, 23, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 128, 288, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 14, 420, 19, 24, 2328, 2349, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 7, 23, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 8, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Belgium
- { 85, 66, 25, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 124, 2042, 19, 24, 2328, 2357, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Benin
- { 85, 66, 37, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 124, 2042, 19, 24, 2328, 2362, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 12, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Burkina Faso
- { 85, 66, 38, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 176, 2059, 19, 24, 2328, 1318, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 3, 15, 5, 7, 8, 7, {66,73,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Burundi
- { 85, 66, 40, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 208, 221, 376, 232, 249, 3, 2074, 19, 24, 2328, 1027, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 5, 4, 6, 17, 23, 4, 16, 5, 7, 8, 8, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Cameroon
- { 85, 66, 41, 0, 0, 368, 368, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 11, 10, 71, 44, 311, 311, 5503, 5503, 5554, 5554, 5588, 5588, 168, 168, 376, 232, 249, 2, 2090, 19, 24, 2374, 1349, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 24, 9, 51, 51, 34, 34, 13, 13, 4, 4, 6, 17, 23, 1, 15, 5, 7, 17, 6, {67,65,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // French/Latin/Canada
- { 85, 66, 46, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 3, 2074, 19, 24, 2328, 2391, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 16, 5, 7, 8, 25, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Central African Republic
- { 85, 66, 48, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 10, 22, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 3, 2074, 19, 24, 2328, 2416, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 12, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 16, 5, 7, 8, 5, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Chad
- { 85, 66, 55, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 4, 2105, 19, 24, 2328, 2421, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 7, {75,77,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Comoros
- { 85, 66, 56, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 3, 2074, 19, 24, 2328, 2428, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 16, 5, 7, 8, 17, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Congo Brazzaville
- { 85, 66, 57, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 3, 2119, 19, 24, 2328, 2445, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 15, 5, 7, 8, 14, {67,68,70}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Congo Kinshasa
- { 85, 66, 67, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 10, 22, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 35, 2134, 19, 24, 2328, 2459, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 12, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 3, 16, 5, 7, 8, 8, {68,74,70}, 0, 0, 6, 6, 7, 1, 3, 3 }, // French/Latin/Djibouti
- { 85, 66, 73, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 3, 2074, 19, 24, 2328, 2467, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 16, 5, 7, 8, 18, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Equatorial Guinea
- { 85, 66, 85, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 14, 420, 19, 24, 2328, 2485, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 16, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/French Guiana
- { 85, 66, 86, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 205, 2150, 19, 24, 2328, 2501, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 9, 5, 7, 8, 19, {88,80,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/French Polynesia
- { 85, 66, 88, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 3, 2074, 19, 24, 2328, 2520, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 16, 5, 7, 8, 5, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Gabon
- { 85, 66, 97, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 14, 420, 19, 24, 2328, 2525, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Guadeloupe
- { 85, 66, 102, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 209, 2159, 19, 24, 2328, 2467, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 13, 5, 7, 8, 6, {71,78,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Guinea
- { 85, 66, 104, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 7, 2172, 19, 24, 2328, 2535, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 16, 5, 7, 8, 5, {72,84,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Haiti
- { 85, 66, 118, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 124, 2042, 19, 24, 2328, 2540, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 13, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Ivory Coast
- { 85, 66, 138, 0, 0, 368, 368, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 14, 420, 19, 24, 2328, 2553, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Luxembourg
- { 85, 66, 141, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 181, 2188, 19, 24, 2328, 1646, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 15, 5, 7, 8, 10, {77,71,65}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Madagascar
- { 85, 66, 145, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 124, 2042, 19, 24, 2328, 467, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 4, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Mali
- { 85, 66, 148, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 14, 420, 19, 24, 2328, 2563, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Martinique
- { 85, 66, 149, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 10, 22, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 211, 2203, 19, 24, 2328, 2573, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 12, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 19, 5, 7, 8, 10, {77,82,85}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Mauritania
- { 85, 66, 150, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 189, 2222, 19, 24, 2328, 2583, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 18, 5, 7, 8, 7, {77,85,82}, 2, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Mauritius
- { 85, 66, 151, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 14, 420, 19, 24, 2328, 2590, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Mayotte
- { 85, 66, 155, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 14, 420, 19, 24, 2328, 2597, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Monaco
- { 85, 66, 159, 0, 0, 368, 368, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 168, 168, 376, 232, 249, 213, 2240, 19, 24, 2328, 2603, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 4, 4, 6, 17, 23, 3, 15, 5, 7, 8, 5, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Morocco
- { 85, 66, 166, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 205, 2150, 19, 24, 2328, 2608, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 9, 5, 7, 8, 18, {88,80,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/New Caledonia
- { 85, 66, 170, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 124, 2042, 19, 24, 2328, 1762, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Niger
- { 85, 66, 191, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 14, 420, 19, 24, 2328, 2626, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Reunion
- { 85, 66, 194, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 191, 2255, 19, 24, 2328, 1878, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 6, {82,87,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Rwanda
- { 85, 66, 195, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 14, 420, 19, 24, 2328, 2636, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 16, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Saint Barthelemy
- { 85, 66, 199, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 14, 420, 19, 24, 2328, 2652, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 12, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Saint Martin
- { 85, 66, 200, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 14, 420, 19, 24, 2328, 2664, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 24, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Saint Pierre And Miquelon
- { 85, 66, 206, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 124, 2042, 19, 24, 2328, 2688, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 7, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Senegal
- { 85, 66, 208, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 196, 2269, 19, 24, 2328, 1944, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 21, 5, 7, 8, 10, {83,67,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Seychelles
- { 85, 66, 226, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 19, 20, 0, 184, 335, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 216, 2290, 19, 24, 2695, 2710, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 14, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 3, 12, 5, 7, 15, 6, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Switzerland
- { 85, 66, 227, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 10, 22, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 219, 2302, 19, 24, 2328, 2716, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 12, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 5, {83,89,80}, 0, 0, 6, 5, 6, 1, 3, 3 }, // French/Latin/Syria
- { 85, 66, 233, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 124, 2042, 19, 24, 2328, 2271, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 4, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Togo
- { 85, 66, 238, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 10, 22, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 221, 2316, 19, 24, 2328, 2721, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 12, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 7, {84,78,68}, 3, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Tunisia
- { 85, 66, 252, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 10, 22, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 203, 2330, 19, 24, 2328, 2209, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 12, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 7, {86,85,86}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Vanuatu
- { 85, 66, 256, 0, 0, 368, 368, 6, 1, 58, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 127, 0, 0, 5503, 5503, 5554, 5554, 5588, 5588, 0, 0, 376, 232, 249, 205, 2150, 19, 24, 2328, 2728, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 9, 5, 7, 8, 16, {88,80,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Wallis And Futuna
- { 86, 66, 117, 0, 0, 376, 376, 6, 1, 0, 2, 3, 4, 5, 9, 12, 13, 10, 11, 727, 127, 0, 0, 5601, 5601, 5650, 5650, 5588, 5588, 5, 128, 0, 5, 22, 14, 420, 4, 0, 2744, 2750, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 49, 49, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Friulian/Latin/Italy
- { 87, 66, 206, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 15, 11, 16, 13, 71, 87, 0, 0, 5677, 5677, 5735, 5735, 5762, 5762, 213, 225, 0, 5, 22, 124, 2344, 19, 0, 2756, 2762, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 5, 19, 5, 0, 6, 8, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Senegal
- { 87, 1, 37, 383, 383, 389, 398, 406, 0, 59, 2, 60, 4, 5, 62, 10, 11, 12, 13, 754, 210, 0, 0, 5775, 5775, 5893, 5893, 5945, 5945, 219, 232, 382, 394, 22, 223, 2363, 4, 0, 2770, 2780, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 10, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 6, 51, 5, 0, 10, 25, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Burkina Faso
- { 87, 1, 40, 383, 383, 389, 398, 406, 0, 59, 2, 60, 4, 5, 62, 10, 11, 12, 13, 754, 210, 0, 0, 5775, 5775, 5893, 5893, 5945, 5945, 219, 232, 382, 394, 22, 229, 2414, 4, 0, 2770, 2805, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 10, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 8, 44, 5, 0, 10, 16, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Cameroon
- { 87, 1, 89, 383, 383, 389, 398, 406, 0, 59, 2, 60, 4, 5, 62, 10, 11, 12, 13, 754, 210, 42, 54, 5775, 5775, 5893, 5893, 5945, 5945, 219, 232, 382, 394, 22, 180, 2458, 4, 0, 2770, 2821, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 12, 7,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 1, 29, 5, 0, 10, 14, {71,77,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Gambia
- { 87, 1, 92, 383, 383, 389, 398, 406, 0, 59, 2, 60, 4, 5, 62, 10, 11, 12, 13, 754, 210, 42, 54, 5775, 5775, 5893, 5893, 5945, 5945, 219, 232, 382, 394, 22, 7, 2487, 4, 0, 2770, 2835, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 12, 7,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 3, 23, 5, 0, 10, 8, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Ghana
- { 87, 1, 101, 383, 383, 389, 398, 406, 0, 59, 2, 60, 4, 5, 62, 10, 11, 12, 13, 754, 210, 0, 0, 5775, 5775, 5893, 5893, 5945, 5945, 219, 232, 382, 394, 22, 223, 2363, 4, 0, 2770, 2843, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 10, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 6, 51, 5, 0, 10, 23, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Guinea Bissau
- { 87, 1, 102, 383, 383, 389, 398, 406, 0, 59, 2, 60, 4, 5, 62, 10, 11, 12, 13, 754, 210, 0, 0, 5775, 5775, 5893, 5893, 5945, 5945, 219, 232, 382, 394, 22, 209, 2510, 4, 0, 2770, 2843, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 10, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 2, 25, 5, 0, 10, 8, {71,78,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Guinea
- { 87, 1, 134, 383, 383, 389, 398, 406, 0, 59, 2, 60, 4, 5, 62, 10, 11, 12, 13, 754, 210, 42, 54, 5775, 5775, 5893, 5893, 5945, 5945, 219, 232, 382, 394, 22, 2, 2535, 4, 0, 2770, 2866, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 12, 7,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 1, 31, 5, 0, 10, 18, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Liberia
- { 87, 1, 149, 383, 383, 389, 398, 406, 0, 59, 2, 60, 4, 5, 62, 10, 11, 12, 13, 754, 210, 42, 54, 5775, 5775, 5893, 5893, 5945, 5945, 219, 232, 382, 394, 22, 211, 2566, 4, 0, 2770, 2884, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 12, 7,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 2, 37, 5, 0, 10, 16, {77,82,85}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Mauritania
- { 87, 1, 169, 383, 383, 389, 398, 406, 0, 59, 2, 60, 4, 5, 62, 10, 11, 12, 13, 754, 210, 0, 0, 5775, 5775, 5893, 5893, 5945, 5945, 219, 232, 382, 394, 22, 122, 2603, 4, 0, 2770, 2900, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 10, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 1, 33, 5, 0, 10, 18, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Nigeria
- { 87, 1, 170, 383, 383, 389, 398, 406, 0, 59, 2, 60, 4, 5, 62, 10, 11, 12, 13, 754, 210, 0, 0, 5775, 5775, 5893, 5893, 5945, 5945, 219, 232, 382, 394, 22, 223, 2363, 4, 0, 2770, 2918, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 10, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 6, 51, 5, 0, 10, 12, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Niger
- { 87, 1, 206, 383, 383, 389, 398, 406, 0, 59, 2, 60, 4, 5, 62, 10, 11, 12, 13, 754, 210, 0, 0, 5775, 5775, 5893, 5893, 5945, 5945, 219, 232, 382, 394, 22, 223, 2363, 4, 0, 2770, 2930, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 10, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 6, 51, 5, 0, 10, 16, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Senegal
- { 87, 1, 209, 383, 383, 389, 398, 406, 0, 59, 2, 60, 4, 5, 62, 10, 11, 12, 13, 754, 210, 42, 54, 5775, 5775, 5893, 5893, 5945, 5945, 219, 232, 382, 394, 22, 10, 0, 4, 0, 2770, 2946, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 12, 7,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 2, 0, 5, 0, 10, 14, {83,76,69}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Sierra Leone
- { 87, 66, 37, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 15, 11, 16, 13, 71, 87, 0, 0, 5677, 5677, 5735, 5735, 5762, 5762, 213, 225, 0, 5, 22, 124, 2344, 19, 0, 2756, 2960, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 5, 19, 5, 0, 6, 14, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Burkina Faso
- { 87, 66, 40, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 15, 11, 16, 13, 71, 87, 0, 0, 5677, 5677, 5735, 5735, 5762, 5762, 213, 225, 0, 5, 22, 3, 2636, 19, 0, 2756, 2974, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 4, 18, 5, 0, 6, 8, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Cameroon
- { 87, 66, 89, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 15, 11, 16, 13, 71, 87, 10, 22, 5677, 5677, 5735, 5735, 5762, 5762, 213, 225, 0, 5, 22, 180, 2654, 19, 0, 2756, 2982, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 12, 7, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 1, 13, 5, 0, 6, 6, {71,77,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Gambia
- { 87, 66, 92, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 15, 11, 16, 13, 71, 87, 10, 22, 5677, 5677, 5735, 5735, 5762, 5762, 213, 225, 0, 5, 22, 7, 0, 19, 0, 2756, 2988, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 12, 7, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 3, 0, 5, 0, 6, 5, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Ghana
- { 87, 66, 101, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 15, 11, 16, 13, 71, 87, 0, 0, 5677, 5677, 5735, 5735, 5762, 5762, 213, 225, 0, 5, 22, 124, 2344, 19, 0, 2756, 2993, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 5, 19, 5, 0, 6, 12, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Guinea Bissau
- { 87, 66, 102, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 15, 11, 16, 13, 71, 87, 0, 0, 5677, 5677, 5735, 5735, 5762, 5762, 213, 225, 0, 5, 22, 209, 0, 19, 0, 2756, 2993, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 2, 0, 5, 0, 6, 4, {71,78,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Guinea
- { 87, 66, 134, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 15, 11, 16, 13, 71, 87, 10, 22, 5677, 5677, 5735, 5735, 5762, 5762, 213, 225, 0, 5, 22, 2, 2667, 19, 0, 2756, 3005, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 12, 7, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 1, 16, 5, 0, 6, 9, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Liberia
- { 87, 66, 149, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 15, 11, 16, 13, 71, 87, 10, 22, 5677, 5677, 5735, 5735, 5762, 5762, 213, 225, 0, 5, 22, 211, 2683, 19, 0, 2756, 3014, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 12, 7, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 2, 15, 5, 0, 6, 8, {77,82,85}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Mauritania
- { 87, 66, 169, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 15, 11, 16, 13, 71, 87, 0, 0, 5677, 5677, 5735, 5735, 5762, 5762, 213, 225, 0, 5, 22, 122, 2698, 19, 0, 2756, 3022, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 1, 16, 5, 0, 6, 9, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Nigeria
- { 87, 66, 170, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 15, 11, 16, 13, 71, 87, 0, 0, 5677, 5677, 5735, 5735, 5762, 5762, 213, 225, 0, 5, 22, 124, 2344, 19, 0, 2756, 3031, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 5, 19, 5, 0, 6, 6, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Niger
- { 87, 66, 209, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 15, 11, 16, 13, 71, 87, 10, 22, 5677, 5677, 5735, 5735, 5762, 5762, 213, 225, 0, 5, 22, 10, 0, 19, 0, 2756, 3037, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 12, 7, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 2, 0, 5, 0, 6, 11, {83,76,69}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Sierra Leone
- { 88, 66, 246, 0, 0, 407, 407, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 771, 127, 0, 0, 5967, 5967, 6035, 6035, 6062, 6062, 3, 135, 421, 5, 22, 92, 2714, 9, 13, 3048, 3056, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 10, 10, 5, 68, 68, 27, 27, 13, 13, 1, 1, 6, 17, 23, 1, 15, 4, 6, 8, 22, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Gaelic/Latin/United Kingdom
- { 89, 66, 92, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 7, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 0, 0, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ga/Latin/Ghana
- { 90, 66, 220, 0, 0, 376, 376, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 127, 0, 0, 6075, 6123, 6171, 6205, 942, 6239, 168, 168, 0, 5, 22, 14, 420, 19, 0, 3078, 386, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 48, 48, 34, 34, 13, 20, 4, 4, 5, 17, 23, 1, 4, 5, 0, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Galician/Latin/Spain
- { 91, 66, 243, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 6259, 6259, 6324, 6324, 6351, 6351, 0, 0, 0, 5, 22, 149, 2729, 0, 0, 3084, 3091, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 65, 65, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 19, 4, 0, 7, 7, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Ganda/Latin/Uganda
- { 92, 33, 77, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 0, 0, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Geez/Ethiopic/Ethiopia
- { 93, 35, 90, 0, 0, 417, 417, 6, 1, 14, 2, 3, 4, 5, 9, 15, 10, 17, 18, 819, 184, 0, 0, 6364, 6364, 6425, 6425, 6452, 6452, 0, 0, 427, 432, 22, 0, 2748, 19, 0, 3098, 3105, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 10, 5, 61, 61, 27, 27, 13, 13, 2, 2, 5, 29, 23, 1, 12, 5, 0, 7, 10, {71,69,76}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Georgian/Georgian/Georgia
- { 94, 66, 91, 0, 0, 425, 425, 6, 1, 0, 2, 3, 4, 5, 9, 15, 10, 16, 12, 331, 184, 0, 0, 6465, 6465, 6524, 6544, 3885, 3885, 0, 0, 461, 5, 22, 14, 73, 19, 0, 3115, 3122, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 11, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // German/Latin/Germany
- { 94, 66, 16, 0, 0, 425, 425, 6, 1, 14, 2, 3, 4, 5, 9, 15, 10, 16, 12, 331, 184, 0, 0, 6465, 6465, 6524, 6544, 3885, 3885, 0, 0, 461, 5, 22, 14, 73, 19, 0, 3133, 3133, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 24, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // German/Latin/Austria
- { 94, 66, 23, 0, 0, 425, 425, 6, 1, 0, 2, 3, 4, 5, 9, 15, 10, 16, 12, 331, 184, 0, 0, 6465, 6465, 6524, 6544, 3885, 3885, 0, 0, 461, 5, 22, 14, 73, 19, 0, 3115, 3157, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // German/Latin/Belgium
- { 94, 66, 117, 0, 0, 425, 425, 6, 1, 0, 2, 3, 4, 5, 9, 15, 10, 16, 12, 331, 184, 0, 0, 6465, 6465, 6524, 6544, 3885, 3885, 0, 0, 461, 5, 22, 14, 73, 19, 0, 3115, 3164, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // German/Latin/Italy
- { 94, 66, 136, 0, 0, 425, 425, 6, 0, 13, 2, 3, 4, 5, 9, 15, 10, 16, 12, 331, 184, 0, 0, 6465, 6465, 6524, 6544, 3885, 3885, 0, 0, 461, 5, 22, 216, 2760, 19, 0, 3115, 3171, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 3, 17, 5, 0, 7, 13, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // German/Latin/Liechtenstein
- { 94, 66, 138, 0, 0, 425, 425, 6, 1, 0, 2, 3, 4, 5, 9, 15, 10, 16, 12, 331, 184, 0, 0, 6465, 6465, 6524, 6544, 3885, 3885, 0, 0, 461, 5, 22, 14, 73, 19, 0, 3115, 3184, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // German/Latin/Luxembourg
- { 94, 66, 226, 0, 0, 425, 425, 6, 0, 13, 2, 3, 4, 5, 9, 15, 10, 16, 12, 331, 184, 0, 0, 6465, 6465, 6524, 6544, 3885, 3885, 0, 0, 461, 5, 22, 216, 2760, 19, 0, 3193, 3193, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 3, 17, 5, 0, 21, 7, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // German/Latin/Switzerland
- { 96, 39, 94, 0, 0, 434, 434, 6, 1, 0, 2, 3, 4, 5, 6, 17, 18, 10, 11, 71, 87, 10, 22, 6571, 6571, 6625, 6625, 6652, 6652, 223, 236, 0, 5, 22, 14, 2777, 19, 0, 3214, 3222, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 12, 7, 54, 54, 27, 27, 13, 13, 4, 4, 4, 17, 23, 1, 4, 5, 0, 8, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Greek/Greek/Greece
- { 96, 39, 63, 0, 0, 434, 434, 6, 1, 0, 2, 3, 4, 5, 6, 17, 18, 10, 11, 71, 87, 10, 22, 6571, 6571, 6625, 6625, 6652, 6652, 223, 236, 0, 5, 22, 14, 2777, 19, 0, 3214, 3228, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 12, 7, 54, 54, 27, 27, 13, 13, 4, 4, 4, 17, 23, 1, 4, 5, 0, 8, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Greek/Greek/Cyprus
- { 97, 66, 183, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 237, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {80,89,71}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Guarani/Latin/Paraguay
- { 98, 40, 110, 0, 0, 443, 443, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 192, 87, 349, 362, 6665, 6665, 6717, 6717, 6748, 6748, 0, 0, 466, 5, 22, 118, 2781, 9, 13, 3234, 3241, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 13, 8, 52, 52, 31, 31, 18, 18, 2, 2, 4, 17, 23, 1, 13, 4, 6, 7, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Gujarati/Gujarati/India
- { 99, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 6766, 6766, 6827, 6827, 6854, 6854, 227, 240, 0, 5, 22, 173, 959, 9, 13, 3245, 1125, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 61, 61, 27, 27, 13, 13, 6, 3, 4, 17, 23, 3, 17, 4, 6, 8, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Gusii/Latin/Kenya
- { 101, 66, 169, 0, 0, 452, 461, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 838, 87, 0, 0, 6867, 6867, 6918, 6918, 6945, 6945, 233, 243, 0, 470, 511, 122, 2794, 4, 0, 3253, 3022, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 10, 5, 51, 51, 27, 27, 13, 13, 6, 5, 5, 41, 47, 1, 15, 5, 0, 5, 8, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Hausa/Latin/Nigeria
- { 101, 4, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 122, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Hausa/Arabic/Nigeria
- { 101, 66, 92, 0, 0, 452, 461, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 838, 87, 10, 22, 6867, 6867, 6918, 6918, 6945, 6945, 233, 243, 0, 470, 511, 7, 2809, 4, 0, 3253, 2988, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 51, 51, 27, 27, 13, 13, 6, 5, 5, 41, 47, 3, 13, 5, 0, 5, 4, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Hausa/Latin/Ghana
- { 101, 66, 170, 0, 0, 452, 461, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 838, 87, 0, 0, 6867, 6867, 6918, 6918, 6945, 6945, 233, 243, 0, 470, 511, 124, 2822, 4, 0, 3253, 3258, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 10, 5, 51, 51, 27, 27, 13, 13, 6, 5, 5, 41, 47, 5, 29, 5, 0, 5, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Hausa/Latin/Niger
- { 102, 66, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 87, 10, 22, 6958, 6958, 7014, 7014, 83, 83, 0, 0, 0, 5, 22, 2, 0, 9, 13, 3263, 3277, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 56, 56, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 6, 14, 19, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Hawaiian/Latin/United States
- { 103, 47, 116, 0, 0, 469, 469, 6, 0, 1, 2, 3, 35, 37, 9, 11, 11, 13, 13, 855, 719, 1, 1, 7034, 7034, 7098, 7098, 7143, 7143, 239, 248, 558, 5, 22, 46, 2851, 67, 74, 3296, 3301, 6, 6, 6, 6, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 18, 8, 9, 4, 64, 64, 45, 45, 20, 20, 6, 5, 4, 17, 23, 1, 7, 7, 9, 5, 5, {73,76,83}, 2, 1, 7, 5, 6, 1, 3, 3 }, // Hebrew/Hebrew/Israel
- { 105, 29, 110, 0, 0, 475, 484, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 87, 42, 54, 7163, 7163, 7215, 7215, 7246, 7246, 82, 199, 562, 5, 22, 118, 2858, 9, 0, 3306, 572, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 52, 52, 31, 31, 18, 18, 2, 2, 4, 17, 23, 1, 12, 4, 0, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Hindi/Devanagari/India
- { 105, 66, 110, 0, 0, 492, 502, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 192, 127, 10, 22, 7264, 7264, 7330, 7330, 7368, 7368, 0, 0, 0, 5, 22, 118, 1349, 9, 0, 3312, 1274, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 12, 7, 66, 66, 38, 38, 21, 21, 2, 2, 5, 17, 23, 1, 12, 4, 0, 5, 5, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Hindi/Latin/India
- { 107, 66, 108, 0, 0, 511, 511, 6, 1, 14, 2, 3, 4, 5, 9, 15, 11, 18, 17, 873, 892, 1, 1, 7389, 7389, 7440, 7440, 7458, 7458, 245, 253, 566, 5, 22, 238, 2870, 19, 0, 3317, 3323, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 13, 9, 4, 51, 51, 18, 18, 16, 16, 3, 3, 4, 17, 23, 2, 13, 5, 0, 6, 12, {72,85,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Hungarian/Latin/Hungary
- { 108, 66, 109, 0, 0, 260, 260, 6, 1, 0, 2, 3, 4, 5, 9, 15, 10, 16, 12, 331, 719, 0, 0, 7474, 7474, 7554, 7554, 7588, 7588, 248, 256, 570, 5, 22, 159, 2883, 19, 0, 3335, 3343, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 80, 80, 34, 34, 13, 13, 4, 4, 4, 17, 23, 3, 13, 5, 0, 8, 6, {73,83,75}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Icelandic/Latin/Iceland
- { 109, 66, 258, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 0, 0, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ido/Latin/World
- { 110, 66, 169, 0, 0, 519, 528, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 87, 0, 0, 7601, 7601, 7654, 7654, 83, 83, 252, 260, 0, 5, 22, 122, 2896, 9, 13, 3349, 3353, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 10, 5, 53, 53, 28, 28, 13, 13, 7, 7, 4, 17, 23, 1, 5, 4, 6, 4, 8, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Igbo/Latin/Nigeria
- { 111, 66, 83, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 10, 11, 12, 13, 905, 719, 188, 188, 7682, 7751, 7823, 7823, 83, 7850, 259, 267, 0, 5, 22, 14, 420, 19, 0, 3361, 3372, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 9, 4, 69, 72, 27, 27, 13, 13, 3, 3, 4, 17, 23, 1, 4, 5, 0, 11, 5, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Inari Sami/Latin/Finland
- { 112, 66, 111, 0, 0, 536, 546, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 642, 127, 187, 187, 7863, 7863, 7905, 7905, 7932, 7932, 0, 0, 0, 5, 22, 240, 2901, 9, 0, 3377, 3377, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 42, 42, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 16, 4, 0, 9, 9, {73,68,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Indonesian/Latin/Indonesia
- { 114, 66, 258, 0, 0, 376, 376, 6, 1, 0, 2, 3, 4, 5, 9, 12, 13, 10, 11, 923, 321, 0, 0, 7945, 7945, 8001, 8001, 8028, 8028, 0, 0, 0, 5, 22, 0, 0, 4, 55, 3386, 3397, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 26, 10, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 0, 5, 7, 11, 5, {0,0,0}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Interlingua/Latin/World
- { 116, 18, 41, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 242, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 0, 0, {67,65,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Inuktitut/Canadian Aboriginal/Canada
- { 116, 66, 41, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 242, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 0, 0, {67,65,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Inuktitut/Latin/Canada
- { 118, 66, 114, 0, 0, 407, 407, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 127, 0, 0, 8041, 8041, 8115, 8115, 8151, 8151, 262, 270, 574, 5, 22, 14, 73, 9, 13, 3402, 3409, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 74, 74, 36, 36, 13, 13, 4, 4, 6, 17, 23, 1, 4, 4, 6, 7, 4, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Irish/Latin/Ireland
- { 118, 66, 246, 0, 0, 407, 407, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 127, 0, 0, 8041, 8041, 8115, 8115, 8151, 8151, 262, 270, 574, 5, 22, 92, 2917, 9, 13, 3402, 3413, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 74, 74, 36, 36, 13, 13, 4, 4, 6, 17, 23, 1, 14, 4, 6, 7, 19, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Irish/Latin/United Kingdom
- { 119, 66, 117, 0, 0, 376, 376, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 10, 11, 71, 127, 0, 0, 8164, 8164, 8220, 8220, 8247, 8247, 0, 0, 0, 5, 22, 14, 420, 19, 0, 3432, 3440, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 8, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Italian/Latin/Italy
- { 119, 66, 203, 0, 0, 376, 376, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 10, 11, 71, 127, 0, 0, 8164, 8164, 8220, 8220, 8247, 8247, 0, 0, 0, 5, 22, 14, 420, 19, 0, 3432, 3446, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 8, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Italian/Latin/San Marino
- { 119, 66, 226, 0, 0, 376, 376, 6, 0, 13, 2, 3, 4, 5, 9, 17, 18, 19, 20, 0, 184, 0, 0, 8164, 8164, 8220, 8220, 8247, 8247, 0, 0, 0, 5, 22, 0, 2931, 19, 0, 3432, 3456, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 15, 5, 0, 8, 8, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Italian/Latin/Switzerland
- { 119, 66, 253, 0, 0, 376, 376, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 10, 11, 71, 127, 0, 0, 8164, 8164, 8220, 8220, 8247, 8247, 0, 0, 0, 5, 22, 14, 420, 19, 0, 3432, 3464, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 8, 18, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Italian/Latin/Vatican City
- { 120, 53, 120, 169, 169, 169, 169, 6, 0, 1, 2, 3, 4, 5, 9, 43, 44, 45, 46, 440, 660, 370, 1, 8260, 8260, 8287, 8287, 8287, 8287, 266, 274, 580, 583, 22, 144, 2946, 9, 13, 3482, 3482, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 10, 10, 4, 27, 27, 13, 13, 13, 13, 2, 2, 3, 17, 23, 1, 3, 4, 6, 3, 2, {74,80,89}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Japanese/Japanese/Japan
- { 121, 66, 111, 0, 0, 555, 565, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 321, 0, 0, 8300, 8300, 8340, 8340, 8368, 8368, 268, 276, 600, 5, 22, 240, 2901, 4, 0, 3485, 3489, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 40, 40, 28, 28, 13, 13, 4, 5, 4, 17, 23, 2, 16, 5, 0, 4, 9, {73,68,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Javanese/Latin/Indonesia
- { 122, 66, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 122, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Jju/Latin/Nigeria
- { 123, 66, 206, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 10, 11, 71, 87, 0, 0, 8381, 8381, 8430, 8430, 8457, 8457, 0, 0, 0, 5, 22, 124, 2949, 19, 0, 3498, 3503, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 49, 49, 27, 27, 13, 13, 2, 2, 4, 17, 23, 5, 16, 5, 0, 5, 7, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Jola Fonyi/Latin/Senegal
- { 124, 66, 43, 0, 0, 129, 129, 6, 1, 14, 2, 3, 4, 5, 9, 10, 11, 12, 13, 949, 127, 0, 0, 8470, 8470, 8542, 8542, 8569, 8569, 82, 199, 0, 5, 22, 245, 2965, 19, 24, 3510, 3522, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 10, 10, 5, 72, 72, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 18, 5, 7, 12, 10, {67,86,69}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Kabuverdianu/Latin/Cape Verde
- { 125, 66, 4, 0, 0, 574, 582, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 10, 11, 71, 87, 10, 22, 8582, 8615, 8665, 8692, 8721, 8734, 272, 281, 604, 611, 22, 180, 2983, 0, 0, 3532, 3541, 6, 6, 8, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 12, 7, 33, 50, 27, 29, 13, 13, 7, 9, 7, 21, 23, 2, 14, 4, 0, 9, 8, {68,90,68}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Kabyle/Latin/Algeria
- { 126, 66, 40, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 19, 20, 54, 976, 0, 0, 8747, 8747, 8747, 8747, 8800, 8800, 0, 0, 0, 5, 22, 3, 2997, 4, 0, 3549, 3553, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 53, 53, 53, 53, 20, 20, 2, 2, 4, 17, 23, 4, 9, 5, 0, 4, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Kako/Latin/Cameroon
- { 127, 66, 95, 0, 0, 589, 589, 6, 1, 0, 2, 3, 40, 5, 53, 18, 17, 20, 19, 54, 44, 187, 187, 8820, 8820, 8917, 8917, 8944, 8944, 0, 0, 0, 5, 22, 159, 3006, 9, 83, 3560, 3571, 6, 6, 11, 11, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 17, 10, 10, 5, 97, 97, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 19, 4, 5, 11, 16, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Kalaallisut/Latin/Greenland
- { 128, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 8957, 8957, 9009, 9009, 9036, 9036, 279, 290, 0, 5, 22, 173, 3025, 9, 13, 3587, 3595, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 52, 52, 27, 27, 13, 13, 6, 10, 4, 17, 23, 3, 19, 4, 6, 8, 12, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Kalenjin/Latin/Kenya
- { 129, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 9049, 9049, 9122, 9122, 9149, 9149, 285, 300, 0, 5, 22, 173, 3044, 9, 13, 3607, 1125, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 73, 73, 27, 27, 13, 13, 9, 7, 4, 17, 23, 3, 16, 4, 6, 7, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Kamba/Latin/Kenya
- { 130, 56, 110, 0, 0, 600, 612, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 87, 349, 362, 9162, 9162, 9215, 9215, 9247, 9247, 294, 307, 632, 640, 22, 118, 3060, 9, 13, 3614, 3619, 6, 6, 12, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 13, 8, 53, 53, 32, 32, 19, 19, 9, 7, 8, 35, 23, 1, 13, 4, 6, 5, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Kannada/Kannada/India
- { 132, 4, 110, 623, 623, 629, 639, 53, 21, 22, 23, 64, 35, 65, 68, 10, 11, 12, 13, 453, 471, 42, 54, 9266, 9266, 9317, 9317, 9366, 9366, 303, 314, 0, 5, 22, 118, 3073, 9, 0, 3623, 3628, 6, 6, 10, 9, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 18, 6, 12, 7, 51, 51, 49, 49, 13, 13, 6, 6, 4, 17, 23, 1, 16, 4, 0, 5, 9, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Kashmiri/Arabic/India
- { 132, 29, 110, 0, 0, 648, 657, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 87, 96, 96, 9379, 9379, 9379, 9379, 9428, 9428, 309, 320, 0, 5, 22, 118, 3089, 9, 0, 3637, 3642, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 49, 49, 49, 49, 13, 13, 5, 5, 4, 17, 23, 1, 11, 4, 0, 5, 10, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Kashmiri/Devanagari/India
- { 133, 27, 123, 0, 0, 0, 665, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 10, 11, 986, 184, 0, 0, 9441, 9441, 9496, 9496, 9516, 9516, 0, 0, 196, 675, 692, 246, 3100, 19, 0, 3652, 3662, 6, 6, 6, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 8, 10, 5, 55, 55, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 17, 5, 0, 10, 9, {75,90,84}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Kazakh/Cyrillic/Kazakhstan
- { 134, 66, 40, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 3, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 4, 0, 5, 0, 0, 0, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Kenyang/Latin/Cameroon
- { 135, 60, 39, 0, 0, 675, 684, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 87, 42, 54, 9529, 9574, 9620, 9620, 9659, 9659, 0, 0, 715, 5, 22, 247, 3117, 0, 49, 3671, 3676, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 12, 7, 45, 46, 39, 39, 13, 13, 2, 2, 2, 17, 23, 1, 11, 4, 6, 5, 7, {75,72,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Khmer/Khmer/Cambodia
- { 136, 66, 99, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 248, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {71,84,81}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Kiche/Latin/Guatemala
- { 137, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 9672, 9672, 9734, 9734, 9761, 9761, 314, 325, 0, 5, 22, 173, 3128, 9, 13, 3683, 1125, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 62, 62, 27, 27, 13, 13, 6, 8, 4, 17, 23, 3, 16, 4, 6, 6, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Kikuyu/Latin/Kenya
- { 138, 66, 194, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 12, 13, 27, 44, 0, 0, 9774, 9774, 9857, 9857, 83, 83, 0, 0, 0, 5, 22, 191, 0, 4, 0, 3689, 3700, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 83, 83, 34, 34, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 11, 8, {82,87,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Kinyarwanda/Latin/Rwanda
- { 141, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 210, 42, 54, 9891, 9891, 9891, 9891, 9941, 9959, 320, 333, 717, 5, 22, 118, 2858, 9, 13, 3708, 572, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 12, 7, 50, 50, 50, 50, 18, 19, 4, 4, 4, 17, 23, 1, 12, 4, 6, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Konkani/Devanagari/India
- { 142, 63, 218, 0, 0, 693, 693, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 1008, 1024, 380, 96, 9978, 9978,10005,10005,10005,10005, 324, 337, 721, 5, 22, 249, 3144, 9, 13, 3714, 3717, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 9, 13, 7, 27, 27, 13, 13, 13, 13, 2, 2, 3, 17, 23, 1, 6, 4, 6, 3, 4, {75,82,87}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Korean/Korean/South Korea
- { 142, 63, 174, 0, 0, 693, 693, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 1008, 1024, 380, 96, 9978, 9978,10005,10005,10005,10005, 324, 337, 721, 5, 22, 250, 3150, 9, 13, 3714, 3721, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 9, 13, 7, 27, 27, 13, 13, 13, 13, 2, 2, 3, 17, 23, 3, 16, 4, 6, 3, 11, {75,80,87}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Korean/Korean/North Korea
- { 144, 66, 145, 0, 0, 0, 0, 6, 0, 14, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 87, 0, 0,10018,10018,10071,10071,10098,10098, 326, 339, 0, 5, 22, 124, 3166, 0, 0, 3732, 3747, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 53, 53, 27, 27, 13, 13, 6, 6, 4, 17, 23, 5, 16, 4, 0, 15, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Koyraboro Senni/Latin/Mali
- { 145, 66, 145, 0, 0, 0, 0, 6, 0, 14, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 87, 0, 0,10111,10111,10163,10163,10098,10098, 326, 339, 0, 5, 22, 124, 3166, 0, 0, 3752, 3747, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 52, 52, 27, 27, 13, 13, 6, 6, 4, 17, 23, 5, 16, 4, 0, 11, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Koyra Chiini/Latin/Mali
- { 146, 66, 134, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 2, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Kpelle/Latin/Liberia
- { 148, 66, 239, 0, 0, 700, 700, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0,10190,10190,10231,10231,10250,10250, 332, 345, 0, 5, 22, 253, 0, 19, 24, 3763, 3768, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 41, 41, 19, 19, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 7, 5, 7, {84,82,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Kurdish/Latin/Turkey
- { 149, 66, 40, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 15, 11, 17, 18, 71, 87, 0, 0,10263,10263,10351,10351,10380,10380, 334, 347, 0, 5, 22, 3, 3182, 19, 0, 3775, 3781, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 88, 88, 29, 29, 13, 13, 4, 4, 4, 17, 23, 4, 13, 5, 0, 6, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Kwasio/Latin/Cameroon
- { 150, 27, 128, 0, 0, 707, 707, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 15, 10, 1033, 87, 0, 0,10393,10393,10449,10449,10486,10486, 338, 351, 196, 724, 22, 254, 3195, 19, 0, 3788, 3796, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 10, 5, 56, 56, 37, 37, 13, 13, 5, 14, 4, 18, 23, 3, 15, 5, 0, 8, 10, {75,71,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Kyrgyz/Cyrillic/Kyrgyzstan
- { 151, 66, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 471, 10, 22,10499,10499,10499,10499, 83,10585, 0, 0, 0, 5, 22, 2, 0, 4, 0, 3806, 3818, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 86, 86, 86, 86, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 12, 22, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Lakota/Latin/United States
- { 152, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 11, 11, 13, 13, 0, 127, 0, 0,10598,10598,10660,10660,10695,10695, 343, 365, 0, 5, 22, 119, 3210, 4, 0, 3840, 3848, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 62, 62, 35, 35, 13, 13, 3, 3, 4, 17, 23, 3, 22, 5, 0, 8, 9, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Langi/Latin/Tanzania
- { 153, 65, 129, 0, 0, 0, 717, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 1056, 87, 393, 1,10708,10708,10764,10764,10799,10799, 346, 368, 0, 5, 22, 257, 3232, 9, 62, 3857, 3857, 6, 6, 6, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 24, 4, 56, 56, 35, 35, 16, 16, 8, 8, 4, 17, 23, 1, 7, 4, 5, 3, 3, {76,65,75}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Lao/Lao/Laos
- { 154, 66, 253, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 14, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Latin/Latin/Vatican City
- { 155, 66, 131, 0, 0, 245, 245, 6, 1, 14, 2, 3, 4, 5, 9, 10, 11, 12, 13, 1075, 184, 0, 0,10815,10886,10957,11007,11057,11057, 354, 376, 742, 5, 22, 14, 3239, 19, 0, 3860, 3868, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 26, 8, 10, 5, 71, 71, 50, 50, 13, 13, 14, 11, 5, 17, 23, 1, 4, 5, 0, 8, 7, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Latvian/Latin/Latvia
- { 158, 66, 57, 0, 0, 726, 726, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 87, 0, 0,11070,11070,11169,11169,11196,11196, 368, 387, 0, 5, 22, 3, 3243, 19, 0, 3875, 3882, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 99, 99, 27, 27, 13, 13, 8, 6, 4, 17, 23, 2, 16, 5, 0, 7, 30, {67,68,70}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Lingala/Latin/Congo Kinshasa
- { 158, 66, 7, 0, 0, 726, 726, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 87, 0, 0,11070,11070,11169,11169,11196,11196, 368, 387, 0, 5, 22, 258, 3259, 19, 0, 3875, 3912, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 99, 99, 27, 27, 13, 13, 8, 6, 4, 17, 23, 2, 16, 5, 0, 7, 6, {65,79,65}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Lingala/Latin/Angola
- { 158, 66, 46, 0, 0, 726, 726, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 87, 0, 0,11070,11070,11169,11169,11196,11196, 368, 387, 0, 5, 22, 3, 3275, 19, 0, 3875, 3918, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 99, 99, 27, 27, 13, 13, 8, 6, 4, 17, 23, 4, 16, 5, 0, 7, 26, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Lingala/Latin/Central African Republic
- { 158, 66, 56, 0, 0, 726, 726, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 87, 0, 0,11070,11070,11169,11169,11196,11196, 368, 387, 0, 5, 22, 3, 3275, 19, 0, 3875, 3944, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 99, 99, 27, 27, 13, 13, 8, 6, 4, 17, 23, 4, 16, 5, 0, 7, 5, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Lingala/Latin/Congo Brazzaville
- { 160, 66, 137, 0, 0, 735, 735, 6, 1, 14, 2, 3, 40, 5, 53, 15, 10, 15, 10, 1101, 44, 0, 0,11209,11209,11297,11297,11317,11317, 376, 393, 747, 5, 22, 14, 3291, 19, 0, 3949, 3957, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 27, 10, 10, 5, 88, 88, 20, 20, 13, 13, 9, 6, 6, 17, 23, 1, 5, 5, 0, 8, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Lithuanian/Latin/Lithuania
- { 161, 66, 258, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 0, 0, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Lojban/Latin/World
- { 162, 66, 91, 0, 0, 743, 743, 6, 1, 0, 2, 3, 4, 5, 9, 15, 10, 16, 12, 331, 121, 1, 1,11330,11330,11382,11382,11409,11409, 385, 399, 0, 5, 22, 14, 420, 19, 0, 3964, 3978, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 9, 4, 52, 52, 27, 27, 13, 13, 9, 10, 4, 17, 23, 1, 4, 5, 0, 14, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Lower Sorbian/Latin/Germany
- { 163, 66, 91, 0, 0, 245, 245, 6, 1, 0, 2, 3, 4, 5, 9, 15, 10, 16, 12, 1128, 185, 417, 436,11422,11422,11486,11486, 3885, 3885, 0, 0, 0, 5, 22, 14, 73, 19, 0, 3984, 3998, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 7, 19, 10, 64, 64, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 14, 11, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Low German/Latin/Germany
- { 163, 66, 165, 0, 0, 245, 245, 6, 1, 0, 2, 3, 4, 5, 9, 15, 10, 16, 12, 1128, 185, 417, 436,11422,11422,11486,11486, 3885, 3885, 0, 0, 0, 5, 22, 14, 73, 19, 0, 3984, 4009, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 7, 19, 10, 64, 64, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 14, 12, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Low German/Latin/Netherlands
- { 164, 66, 57, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 87, 0, 0,11513,11513,11562,11562,11589,11589, 394, 409, 0, 5, 22, 3, 3296, 0, 0, 4021, 4029, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 49, 49, 27, 27, 13, 13, 5, 6, 4, 17, 23, 2, 17, 4, 0, 8, 16, {67,68,70}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Luba Katanga/Latin/Congo Kinshasa
- { 165, 66, 225, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 159, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 0, 0, {83,69,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Lule Sami/Latin/Sweden
- { 166, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,11602,11602,11670,11670,11697,11697, 399, 415, 0, 5, 22, 173, 3313, 0, 0, 4045, 1125, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 68, 68, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 16, 4, 0, 6, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Luo/Latin/Kenya
- { 167, 66, 138, 0, 0, 750, 750, 6, 1, 0, 2, 3, 4, 5, 9, 15, 10, 16, 12, 331, 184, 0, 0,11710,11710,11774,11801, 3885, 3885, 401, 417, 461, 5, 22, 14, 73, 19, 0, 4051, 4051, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 64, 64, 27, 34, 13, 13, 5, 8, 5, 17, 23, 1, 4, 5, 0, 14, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Luxembourgish/Latin/Luxembourg
- { 168, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 15, 10, 16, 12, 0, 127, 0, 0,11835,11835,11909,11909, 83, 83, 168, 168, 0, 5, 22, 173, 3329, 9, 88, 4065, 1125, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 74, 74, 20, 20, 13, 13, 4, 4, 4, 17, 23, 3, 16, 4, 6, 7, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Luyia/Latin/Kenya
- { 169, 27, 140, 0, 0, 136, 136, 6, 1, 0, 2, 3, 4, 5, 9, 15, 10, 16, 12, 0, 121, 0, 0,11929,11929,11982,11982, 2627, 2627, 406, 425, 753, 5, 22, 260, 3345, 19, 0, 4072, 4082, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 10, 5, 53, 53, 34, 34, 13, 13, 7, 5, 5, 17, 23, 4, 16, 5, 0, 10, 18, {77,75,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Macedonian/Cyrillic/Macedonia
- { 170, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,12016,12016,12077,12077, 1041, 1041, 413, 430, 0, 5, 22, 119, 3361, 9, 0, 4100, 2055, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 61, 61, 27, 27, 13, 13, 5, 9, 4, 17, 23, 3, 20, 4, 0, 9, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Machame/Latin/Tanzania
- { 171, 29, 110, 0, 0, 475, 484, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 87, 42, 54,12104,12104, 7215, 7215, 7246, 7246, 88, 83, 0, 5, 22, 118, 2858, 4, 0, 4109, 572, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 63, 63, 31, 31, 18, 18, 3, 4, 4, 17, 23, 1, 12, 5, 0, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Maithili/Devanagari/India
- { 172, 66, 160, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,12167,12167,12225,12225,12252,12252, 418, 439, 0, 5, 22, 264, 0, 4, 0, 4115, 4120, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 58, 58, 27, 27, 13, 13, 8, 10, 4, 17, 23, 3, 0, 5, 0, 5, 10, {77,90,78}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Makhuwa Meetto/Latin/Mozambique
- { 173, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,12265,12265,12397,12397,12424,12424, 426, 449, 0, 5, 22, 119, 3361, 9, 13, 4130, 2055, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5,132,132, 27, 27, 13, 13, 4, 5, 4, 17, 23, 3, 20, 4, 6, 10, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Makonde/Latin/Tanzania
- { 174, 66, 141, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 17, 18, 10, 11, 71, 44, 0, 0,12437,12437,12496,12496,12529,12529, 0, 0, 0, 5, 22, 181, 1466, 9, 0, 4140, 4148, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 59, 59, 33, 33, 13, 13, 2, 2, 4, 17, 23, 2, 6, 4, 0, 8, 12, {77,71,65}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Malagasy/Latin/Madagascar
- { 175, 74, 110, 0, 0, 760, 773, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 1151, 87, 42, 54,12542,12618,12693,12693,12733,12754, 0, 0, 758, 764, 22, 118, 3381, 9, 13, 4160, 4166, 6, 6, 13, 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 76, 75, 40, 40, 21, 20, 2, 2, 6, 27, 23, 1, 11, 4, 6, 6, 6, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Malayalam/Malayalam/India
- { 176, 66, 143, 0, 0, 546, 546, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 128, 10, 22,12774,12774,12816,12816,12843,12843, 430, 454, 742, 5, 22, 185, 3392, 9, 13, 4172, 1662, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 7, 12, 7, 42, 42, 27, 27, 13, 13, 2, 3, 4, 17, 23, 2, 16, 4, 6, 6, 8, {77,89,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Malay/Latin/Malaysia
- { 176, 4, 143, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 185, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 0, 0, {77,89,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Malay/Arabic/Malaysia
- { 176, 66, 35, 0, 0, 546, 546, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 59, 128, 10, 22,12774,12774,12816,12816,12843,12843, 430, 454, 742, 5, 22, 2, 3408, 9, 13, 4172, 4178, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 12, 7, 12, 7, 42, 42, 27, 27, 13, 13, 2, 3, 4, 17, 23, 1, 12, 4, 6, 6, 6, {66,78,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Malay/Latin/Brunei
- { 176, 66, 111, 0, 0, 546, 546, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 642, 127, 187, 187,12774,12774,12816,12816,12843,12843, 430, 454, 742, 5, 22, 240, 2901, 9, 0, 4172, 3377, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 42, 42, 27, 27, 13, 13, 2, 3, 4, 17, 23, 2, 16, 4, 0, 6, 9, {73,68,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Malay/Latin/Indonesia
- { 176, 66, 210, 0, 0, 546, 546, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 128, 10, 22,12774,12774,12816,12816,12843,12843, 430, 454, 742, 5, 22, 2, 3420, 9, 13, 4172, 4184, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 7, 12, 7, 42, 42, 27, 27, 13, 13, 2, 3, 4, 17, 23, 1, 15, 4, 6, 6, 9, {83,71,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Malay/Latin/Singapore
- { 177, 66, 146, 0, 0, 785, 793, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 1169, 127, 0, 0,12856,12856,12918,12918,12945,12965, 0, 0, 0, 5, 22, 14, 3435, 9, 0, 4193, 1678, 6, 6, 8, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 10, 5, 62, 62, 27, 27, 20, 19, 2, 2, 4, 17, 23, 1, 4, 4, 0, 5, 5, {69,85,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Maltese/Latin/Malta
- { 179, 9, 110, 0, 0, 800, 800, 6, 0, 1, 2, 39, 4, 5, 9, 10, 11, 12, 13, 1192, 87, 42, 54,12984,12984,12984,12984,13042,13067, 432, 457, 0, 5, 22, 118, 3439, 4, 0, 4198, 4206, 6, 6, 11, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 58, 58, 58, 58, 25, 29, 4, 5, 4, 17, 23, 1, 14, 5, 0, 8, 8, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Manipuri/Bangla/India
- { 179, 78, 110, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 118, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Manipuri/Meitei Mayek/India
- { 180, 66, 115, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 54, 127, 0, 0,13096,13096,13152,13152, 83, 83, 168, 168, 0, 5, 22, 92, 0, 9, 0, 4214, 4219, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 10, 5, 56, 56, 29, 29, 13, 13, 4, 4, 4, 17, 23, 1, 0, 4, 0, 5, 12, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Manx/Latin/Isle Of Man
- { 181, 66, 167, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 321, 10, 22,13181,13181,13228,13228,13258,13273, 0, 0, 0, 5, 22, 2, 3453, 4, 0, 4231, 4236, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 47, 47, 30, 30, 15, 15, 2, 2, 4, 17, 23, 1, 15, 5, 0, 5, 8, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Maori/Latin/New Zealand
- { 182, 66, 49, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 2, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {67,76,80}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Mapuche/Latin/Chile
- { 183, 29, 110, 0, 0, 811, 811, 6, 0, 1, 2, 41, 4, 5, 9, 10, 11, 12, 13, 192, 87, 42, 54,13288,13288,13340,13340, 7246, 7246, 0, 0, 562, 5, 22, 118, 2858, 9, 13, 4244, 572, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 52, 52, 31, 31, 18, 18, 2, 2, 4, 17, 23, 1, 12, 4, 6, 5, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Marathi/Devanagari/India
- { 185, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,13371,13371,12077,12077,12424,12424, 436, 462, 0, 5, 22, 173, 3468, 9, 13, 1093, 1125, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 57, 57, 27, 27, 13, 13, 9, 6, 4, 17, 23, 3, 18, 4, 6, 3, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Masai/Latin/Kenya
- { 185, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,13371,13371,12077,12077,12424,12424, 436, 462, 0, 5, 22, 119, 3486, 9, 13, 1093, 4249, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 57, 57, 27, 27, 13, 13, 9, 6, 4, 17, 23, 3, 21, 4, 6, 3, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Masai/Latin/Tanzania
- { 186, 4, 112, 0, 0, 0, 0, 53, 21, 22, 23, 64, 35, 65, 68, 17, 18, 19, 20, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 791, 795, 22, 267, 3507, 4, 0, 4257, 4264, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 39, 23, 3, 10, 5, 0, 7, 5, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Mazanderani/Arabic/Iran
- { 188, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,13428,13428,13478,13478,13505,13505, 445, 468, 0, 5, 22, 173, 959, 9, 13, 4269, 1125, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 50, 50, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 17, 4, 6, 6, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Meru/Latin/Kenya
- { 189, 66, 40, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 95, 44, 0, 0,13518,13518,13518,13518,13566,13566, 0, 0, 0, 5, 22, 3, 3517, 4, 0, 4275, 4280, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 10, 5, 48, 48, 48, 48, 20, 20, 2, 2, 4, 17, 23, 4, 5, 5, 0, 5, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Meta/Latin/Cameroon
- { 190, 66, 41, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 242, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 0, 0, {67,65,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Mohawk/Latin/Canada
- { 191, 27, 156, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 1210, 1245, 73, 0,13586,13628,13670,13670,13670,13670, 447, 470, 196, 834, 22, 270, 3522, 4, 0, 4287, 4293, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 35, 10, 12, 5, 42, 42, 20, 20, 20, 20, 4, 4, 4, 17, 23, 1, 13, 5, 0, 6, 6, {77,78,84}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Mongolian/Cyrillic/Mongolia
- { 191, 83, 50, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 271, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 0, 0, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Mongolian/Mongolian/China
- { 192, 66, 150, 0, 0, 0, 0, 6, 0, 14, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 87, 0, 0,13690,13690,13737,13737,13763,13763, 0, 0, 0, 5, 22, 189, 3535, 4, 0, 4299, 4313, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 47, 47, 26, 26, 13, 13, 2, 2, 4, 17, 23, 2, 14, 5, 0, 14, 5, {77,85,82}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Morisyen/Latin/Mauritius
- { 193, 66, 40, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 10, 11, 71, 87, 0, 0,13776,13776,13849,13849,13876,13876, 451, 474, 0, 5, 22, 3, 3549, 9, 13, 4318, 4324, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 73, 73, 27, 27, 13, 13, 5, 5, 4, 17, 23, 4, 10, 4, 6, 6, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Mundang/Latin/Cameroon
- { 194, 66, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 146, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 0, 0, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Muscogee/Latin/United States
- { 195, 66, 162, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22,13889,13889,13980,13980,14002,14002, 456, 479, 0, 5, 22, 2, 3559, 9, 0, 4331, 4344, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 91, 91, 22, 22, 13, 13, 7, 5, 4, 17, 23, 1, 15, 4, 0, 13, 8, {78,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Nama/Latin/Namibia
- { 197, 66, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 146, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 0, 0, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Navajo/Latin/United States
- { 199, 29, 164, 820, 0, 825, 825, 6, 0, 1, 2, 41, 4, 5, 9, 10, 11, 12, 13, 27, 293, 0, 0,14015,14015,14068,14068,14100,14100, 463, 484, 562, 851, 22, 274, 3574, 4, 0, 4352, 4352, 5, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 10, 5, 53, 53, 32, 32, 17, 17, 9, 7, 4, 19, 23, 4, 14, 5, 0, 6, 5, {78,80,82}, 2, 1, 7, 6, 7, 1, 2, 3 }, // Nepali/Devanagari/Nepal
- { 199, 29, 110, 820, 0, 825, 825, 6, 0, 1, 2, 41, 4, 5, 9, 10, 11, 12, 13, 27, 293, 42, 54,14015,14015,14068,14068,14100,14100, 463, 484, 562, 851, 22, 118, 3588, 4, 0, 4352, 572, 5, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 53, 53, 32, 32, 17, 17, 9, 7, 4, 19, 23, 1, 14, 5, 0, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Nepali/Devanagari/India
- { 201, 66, 40, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 10, 11, 1255, 127, 0, 0,14117,14117,14117,14117, 83, 83, 472, 491, 0, 5, 22, 3, 3602, 4, 0, 4358, 4374, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 32, 8, 10, 5,110,110,110,110, 13, 13, 9, 8, 4, 17, 23, 4, 9, 5, 0, 16, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Ngiemboon/Latin/Cameroon
- { 202, 66, 40, 832, 832, 843, 859, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 19, 20, 95, 44, 0, 0,14227,14227,14227,14227,14286,14286, 481, 499, 0, 5, 22, 3, 3611, 4, 0, 4381, 4386, 11, 11, 16, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 10, 5, 59, 59, 59, 59, 24, 24, 8, 13, 4, 17, 23, 4, 5, 5, 0, 5, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Ngomba/Latin/Cameroon
- { 203, 66, 169, 0, 0, 868, 877, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,14310,14310,14361,14361, 83, 83, 489, 512, 870, 5, 22, 122, 3616, 9, 0, 4393, 4407, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 51, 51, 32, 32, 13, 13, 9, 8, 8, 17, 23, 1, 14, 4, 0, 14, 8, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Nigerian Pidgin/Latin/Nigeria
- { 204, 90, 102, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 209, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 0, 0, {71,78,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Nko/Nko/Guinea
- { 205, 4, 112, 0, 0, 0, 0, 53, 21, 22, 23, 64, 35, 65, 68, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 4415, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 11, 0, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Northern Luri/Arabic/Iran
- { 205, 4, 113, 0, 0, 0, 0, 53, 21, 22, 23, 64, 35, 65, 68, 10, 11, 12, 13, 27, 44, 42, 54, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 41, 0, 4, 0, 4415, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 12, 7, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 5, 0, 5, 0, 11, 0, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Northern Luri/Arabic/Iraq
- { 206, 66, 175, 0, 0, 322, 322, 6, 1, 14, 2, 3, 40, 5, 72, 11, 11, 13, 13, 27, 44, 0, 0,14393,14393,14467,14467,14499,14499, 498, 520, 0, 5, 22, 159, 3630, 19, 0, 4426, 4441, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 17, 10, 10, 5, 74, 74, 32, 32, 13, 13, 11, 13, 4, 17, 23, 2, 14, 5, 0, 15, 5, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Northern Sami/Latin/Norway
- { 206, 66, 83, 0, 0, 322, 322, 6, 1, 14, 2, 3, 40, 5, 72, 11, 11, 13, 13, 71, 499, 0, 0,14512,14512,14581,14581,14601,14601, 509, 185, 0, 5, 22, 14, 420, 19, 0, 4426, 4446, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 16, 10, 10, 5, 69, 69, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 15, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Northern Sami/Latin/Finland
- { 206, 66, 225, 0, 0, 322, 322, 6, 1, 14, 2, 3, 40, 5, 72, 11, 11, 13, 13, 27, 44, 0, 0,14393,14393,14467,14467,14499,14499, 498, 520, 0, 5, 22, 159, 3644, 19, 0, 4426, 4452, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 17, 10, 10, 5, 74, 74, 32, 32, 13, 13, 11, 13, 4, 17, 23, 2, 14, 5, 0, 15, 6, {83,69,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Northern Sami/Latin/Sweden
- { 207, 66, 216, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 1, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Northern Sotho/Latin/South Africa
- { 208, 66, 261, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,14614,14614,14663,14663,14690,14690, 0, 0, 0, 5, 22, 146, 3658, 9, 13, 4458, 2221, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 49, 49, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 17, 4, 6, 10, 8, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // North Ndebele/Latin/Zimbabwe
- { 209, 66, 175, 0, 0, 260, 260, 6, 1, 14, 2, 3, 40, 5, 9, 17, 18, 12, 13, 554, 499, 0, 0, 4066, 4066,14703,14703, 4152, 4152, 168, 168, 0, 5, 22, 159, 3675, 4, 55, 4468, 4480, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 50, 50, 34, 34, 13, 13, 4, 4, 4, 17, 23, 2, 13, 5, 7, 12, 5, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Norwegian Bokmal/Latin/Norway
- { 209, 66, 224, 0, 0, 260, 260, 6, 1, 14, 2, 3, 40, 5, 9, 17, 18, 12, 13, 554, 499, 0, 0, 4066, 4066,14703,14703, 4152, 4152, 168, 168, 0, 5, 22, 159, 3675, 4, 55, 4468, 4485, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 50, 50, 34, 34, 13, 13, 4, 4, 4, 17, 23, 2, 13, 5, 7, 12, 21, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Norwegian Bokmal/Latin/Svalbard And Jan Mayen
- { 210, 66, 175, 0, 0, 260, 260, 6, 1, 14, 2, 3, 40, 5, 9, 17, 18, 12, 13, 554, 499, 446, 0,14737,14737,14787,14814, 4152, 4152, 168, 168, 0, 5, 22, 159, 3675, 19, 0, 4506, 4519, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 16, 5, 50, 50, 27, 27, 13, 13, 4, 4, 4, 17, 23, 2, 13, 5, 0, 13, 5, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Norwegian Nynorsk/Latin/Norway
- { 211, 66, 219, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 128, 462, 22,14841,14841,14919,14919,14956,14956, 511, 533, 0, 5, 22, 92, 0, 9, 13, 4524, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 9, 12, 7, 78, 78, 37, 37, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 6, 9, 0, {83,83,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Nuer/Latin/South Sudan
- { 212, 66, 142, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 0, 0, {77,87,75}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Nyanja/Latin/Malawi
- { 213, 66, 243, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 3544, 3544, 3617, 3617, 3644, 3644, 0, 0, 0, 5, 22, 149, 791, 9, 0, 4533, 862, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 73, 73, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 19, 4, 0, 10, 6, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Nyankole/Latin/Uganda
- { 214, 66, 84, 0, 0, 885, 376, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 17, 18, 1287, 128, 0, 474,14969,14969,14969,14969,15025,15025, 0, 0, 376, 232, 249, 14, 420, 0, 49, 4543, 715, 6, 6, 8, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 7, 10, 6, 56, 56, 56, 56, 20, 20, 2, 2, 6, 17, 23, 1, 4, 4, 6, 7, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Occitan/Latin/France
- { 214, 66, 220, 0, 0, 376, 376, 6, 0, 1, 2, 3, 4, 5, 9, 17, 18, 10, 11, 792, 128, 74, 1,15045,15045,15102,15102,15129,15129, 0, 0, 376, 232, 249, 14, 420, 0, 0, 4543, 4550, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 7, 11, 4, 57, 57, 27, 27, 13, 13, 2, 2, 6, 17, 23, 1, 4, 4, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Occitan/Latin/Spain
- { 215, 91, 110, 0, 0, 893, 901, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 471, 42, 54,15142,15142,15195,15195,15227,15227, 0, 0, 878, 5, 22, 118, 3688, 9, 13, 4557, 4562, 6, 6, 8, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 53, 53, 32, 32, 17, 17, 2, 2, 5, 17, 23, 1, 12, 4, 6, 5, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Odia/Odia/India
- { 220, 66, 77, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 127, 10, 22,15244,15244,15298,15298, 83, 83, 513, 535, 0, 5, 22, 131, 3700, 9, 0, 4566, 4572, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 12, 7, 54, 54, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 17, 4, 0, 6, 10, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Oromo/Latin/Ethiopia
- { 220, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 127, 0, 0,15244,15244,15298,15298,15325,15325, 513, 535, 0, 5, 22, 173, 0, 9, 0, 4566, 4582, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 54, 54, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 4, 0, 6, 8, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Oromo/Latin/Kenya
- { 221, 101, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 146, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 0, 0, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Osage/Osage/United States
- { 222, 27, 90, 0, 0, 908, 908, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 15, 10, 1308, 184, 0, 0,15338,15398,15458,15485,15512,15512, 515, 537, 0, 5, 22, 0, 3717, 4, 0, 4590, 4594, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 10, 5, 60, 60, 27, 27, 13, 13, 15, 15, 4, 17, 23, 1, 3, 5, 0, 4, 11, {71,69,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ossetic/Cyrillic/Georgia
- { 222, 27, 193, 0, 0, 908, 908, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 15, 10, 1308, 184, 0, 0,15338,15398,15458,15485,15512,15512, 515, 537, 0, 5, 22, 130, 3720, 4, 0, 4590, 4605, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 10, 5, 60, 60, 27, 27, 13, 13, 15, 15, 4, 17, 23, 1, 3, 5, 0, 4, 6, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ossetic/Cyrillic/Russia
- { 227, 4, 1, 623, 623, 917, 926, 53, 21, 22, 23, 64, 35, 65, 68, 10, 11, 12, 13, 1331, 432, 74, 1,15525,15525,15525,15525, 83, 83, 530, 552, 883, 5, 22, 278, 3723, 9, 13, 4611, 4615, 6, 6, 9, 8, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 20, 8, 11, 4, 38, 38, 38, 38, 13, 13, 4, 4, 5, 17, 23, 1, 6, 4, 6, 4, 9, {65,70,78}, 0, 0, 6, 4, 5, 1, 3, 3 }, // Pashto/Arabic/Afghanistan
- { 227, 4, 178, 623, 623, 917, 926, 53, 21, 22, 23, 64, 35, 65, 68, 10, 11, 12, 13, 1331, 432, 42, 54,15525,15525,15525,15525, 83, 83, 530, 552, 883, 5, 22, 189, 3729, 9, 13, 4611, 4624, 6, 6, 9, 8, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 20, 8, 12, 7, 38, 38, 38, 38, 13, 13, 4, 4, 5, 17, 23, 2, 15, 4, 6, 4, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Pashto/Arabic/Pakistan
- { 228, 4, 112, 934, 934, 941, 949, 53, 21, 22, 23, 64, 76, 37, 68, 17, 18, 19, 20, 71, 432, 74, 1,15563,15563,15563,15563,15611,15611, 534, 556, 791, 5, 22, 279, 3744, 94, 100, 4631, 4264, 7, 7, 8, 7, 1, 1, 1, 1, 1, 2, 2, 4, 1, 1, 1, 1, 16, 8, 11, 4, 48, 48, 48, 48, 13, 13, 9, 8, 4, 17, 23, 4, 10, 6, 8, 5, 5, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Persian/Arabic/Iran
- { 228, 4, 1, 934, 934, 941, 949, 53, 21, 22, 23, 64, 76, 37, 68, 17, 18, 19, 20, 71, 432, 74, 1,15563,15563,15563,15563,15611,15611, 534, 556, 791, 5, 22, 278, 3754, 4, 100, 4636, 4615, 7, 7, 8, 7, 1, 1, 1, 1, 1, 2, 2, 4, 1, 1, 1, 1, 16, 8, 11, 4, 48, 48, 48, 48, 13, 13, 9, 8, 4, 17, 23, 1, 16, 5, 8, 3, 9, {65,70,78}, 0, 0, 6, 4, 5, 1, 3, 3 }, // Persian/Arabic/Afghanistan
- { 230, 66, 187, 0, 0, 129, 129, 6, 1, 14, 2, 3, 4, 5, 9, 15, 11, 17, 18, 0, 500, 0, 0,15624,15624,15682,15682,15715,15728, 0, 0, 311, 5, 22, 283, 3770, 19, 24, 4639, 4645, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 9, 10, 5, 58, 58, 33, 33, 13, 13, 2, 2, 5, 17, 23, 2, 12, 5, 7, 6, 6, {80,76,78}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Polish/Latin/Poland
- { 231, 66, 32, 0, 0, 376, 376, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 127, 0, 0,15741,15741,15819,15819,15853,15853, 0, 0, 0, 5, 22, 1, 3782, 4, 0, 4651, 4660, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 10, 10, 5, 78, 78, 34, 34, 13, 13, 2, 2, 5, 17, 23, 2, 15, 5, 0, 9, 6, {66,82,76}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Portuguese/Latin/Brazil
- { 231, 66, 7, 0, 0, 376, 376, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 10, 11, 792, 127, 0, 0,15741,15741,15866,15866,15853,15853, 543, 564, 0, 5, 22, 258, 3797, 19, 24, 4651, 4666, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 2, 15, 5, 7, 9, 6, {65,79,65}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Portuguese/Latin/Angola
- { 231, 66, 43, 0, 0, 376, 376, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 10, 11, 792, 127, 0, 0,15741,15741,15866,15866,15853,15853, 543, 564, 0, 5, 22, 245, 3812, 19, 24, 4651, 4672, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 1, 20, 5, 7, 9, 10, {67,86,69}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Cape Verde
- { 231, 66, 73, 0, 0, 376, 376, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 10, 11, 792, 127, 0, 0,15741,15741,15866,15866,15853,15853, 543, 564, 0, 5, 22, 3, 3832, 19, 24, 4651, 4682, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 4, 17, 5, 7, 9, 16, {88,65,70}, 0, 0, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Equatorial Guinea
- { 231, 66, 101, 0, 0, 376, 376, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 10, 11, 792, 127, 0, 0,15741,15741,15866,15866,15853,15853, 543, 564, 0, 5, 22, 124, 3849, 19, 24, 4651, 4698, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 5, 18, 5, 7, 9, 12, {88,79,70}, 0, 0, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Guinea Bissau
- { 231, 66, 138, 0, 0, 376, 376, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 10, 11, 792, 127, 0, 0,15741,15741,15866,15866,15853,15853, 543, 564, 0, 5, 22, 14, 420, 19, 24, 4651, 4710, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 1, 4, 5, 7, 9, 10, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Luxembourg
- { 231, 66, 139, 0, 0, 376, 376, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 10, 11, 792, 127, 10, 22,15741,15741,15866,15866,15853,15853, 543, 564, 0, 5, 22, 153, 3867, 19, 24, 4651, 4720, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 12, 7, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 4, 15, 5, 7, 9, 19, {77,79,80}, 2, 1, 7, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Macao
- { 231, 66, 160, 0, 0, 376, 376, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 10, 11, 792, 127, 0, 0,15741,15741,15866,15866,15853,15853, 543, 564, 0, 5, 22, 264, 3882, 19, 24, 4651, 4739, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 3, 19, 5, 7, 9, 10, {77,90,78}, 2, 1, 7, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Mozambique
- { 231, 66, 188, 0, 0, 376, 376, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 10, 11, 792, 127, 0, 0,15741,15741,15866,15866,15853,15853, 543, 564, 0, 5, 22, 14, 420, 19, 24, 4749, 4766, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 1, 4, 5, 7, 17, 8, {69,85,82}, 2, 1, 7, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Portugal
- { 231, 66, 204, 0, 0, 376, 376, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 10, 11, 792, 127, 0, 0,15741,15741,15866,15866,15853,15853, 543, 564, 0, 5, 22, 285, 3901, 19, 24, 4651, 4774, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 2, 28, 5, 7, 9, 19, {83,84,78}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Sao Tome And Principe
- { 231, 66, 226, 0, 0, 376, 376, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 10, 11, 792, 127, 0, 0,15741,15741,15866,15866,15853,15853, 543, 564, 0, 5, 22, 216, 3929, 19, 24, 4651, 4793, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 3, 12, 5, 7, 9, 5, {67,72,70}, 2, 0, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Switzerland
- { 231, 66, 232, 0, 0, 376, 376, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 10, 11, 792, 127, 0, 0,15741,15741,15866,15866,15853,15853, 543, 564, 0, 5, 22, 146, 3941, 19, 24, 4651, 4798, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 3, 24, 5, 7, 9, 11, {85,83,68}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Timor-Leste
- { 232, 66, 258, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 0, 0, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Prussian/Latin/World
- { 233, 41, 110, 0, 0, 956, 956, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 87, 42, 54,15914,15914,15970,15970,16005,16005, 551, 572, 888, 5, 22, 118, 3965, 4, 0, 4809, 4815, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 56, 56, 35, 35, 22, 22, 6, 6, 4, 17, 23, 1, 11, 5, 0, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Punjabi/Gurmukhi/India
- { 233, 4, 178, 0, 0, 0, 0, 53, 21, 22, 23, 64, 35, 65, 68, 10, 11, 12, 13, 642, 127, 42, 54,16027,16027,16027,16027, 83, 83, 0, 0, 0, 5, 22, 76, 3976, 4, 0, 4819, 4624, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 18, 10, 12, 7, 36, 36, 36, 36, 13, 13, 2, 2, 4, 17, 23, 1, 6, 5, 0, 6, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Punjabi/Arabic/Pakistan
- { 234, 66, 184, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 192, 127, 0, 0,16063,16063,16115,16115,16142,16142, 168, 168, 0, 5, 22, 287, 3982, 4, 0, 4825, 4833, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 10, 5, 52, 52, 27, 27, 13, 13, 4, 4, 4, 17, 23, 2, 11, 5, 0, 8, 4, {80,69,78}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Quechua/Latin/Peru
- { 234, 66, 28, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 192, 127, 0, 0,16063,16063,16115,16115,16142,16142, 168, 168, 0, 5, 22, 289, 3993, 4, 0, 4825, 4837, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 10, 5, 52, 52, 27, 27, 13, 13, 4, 4, 4, 17, 23, 2, 9, 5, 0, 8, 7, {66,79,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Quechua/Latin/Bolivia
- { 234, 66, 70, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 192, 127, 0, 0,16063,16063,16115,16115,16142,16142, 168, 168, 0, 5, 22, 2, 4002, 4, 0, 4825, 4844, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 10, 5, 52, 52, 27, 27, 13, 13, 4, 4, 4, 17, 23, 1, 15, 5, 0, 8, 7, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Quechua/Latin/Ecuador
- { 235, 66, 192, 0, 0, 965, 965, 6, 1, 0, 2, 3, 4, 5, 9, 15, 11, 17, 18, 0, 499, 0, 0,16155,16155,16202,16202, 5588, 5588, 168, 168, 892, 5, 22, 291, 4017, 19, 24, 4851, 4857, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 47, 47, 33, 33, 13, 13, 4, 4, 4, 17, 23, 3, 12, 5, 7, 6, 7, {82,79,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Romanian/Latin/Romania
- { 235, 66, 154, 0, 0, 965, 965, 6, 1, 0, 2, 3, 4, 5, 9, 15, 11, 17, 18, 0, 499, 0, 0,16155,16155,16235,16235,16262,16262, 168, 168, 892, 5, 22, 10, 4029, 19, 24, 4851, 4864, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 47, 47, 27, 27, 15, 15, 4, 4, 4, 17, 23, 1, 15, 5, 7, 6, 17, {77,68,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Romanian/Latin/Moldova
- { 236, 66, 226, 0, 0, 376, 376, 6, 0, 13, 2, 3, 40, 5, 9, 17, 18, 19, 20, 1351, 321, 0, 0,16277,16277,16332,16332,16354,16354, 0, 0, 0, 5, 22, 216, 4044, 19, 0, 4881, 4890, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 10, 5, 55, 55, 22, 22, 13, 13, 2, 2, 5, 17, 23, 3, 13, 5, 0, 9, 6, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Romansh/Latin/Switzerland
- { 237, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,16367,16367,16431,16431,12424,12424, 557, 578, 0, 5, 22, 119, 4057, 9, 0, 4896, 2055, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 64, 64, 28, 28, 13, 13, 8, 7, 4, 17, 23, 3, 18, 4, 0, 9, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Rombo/Latin/Tanzania
- { 238, 66, 38, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 9, 11, 11, 13, 13, 71, 87, 0, 0,16459,16459,16547,16547, 83, 83, 565, 585, 0, 5, 22, 176, 4075, 0, 0, 4905, 4913, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 88, 88, 33, 33, 13, 13, 5, 5, 4, 17, 23, 3, 20, 4, 0, 8, 8, {66,73,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Rundi/Latin/Burundi
- { 239, 27, 193, 0, 0, 136, 136, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 15, 10, 299, 499, 0, 0,16580,16580,16641,16641,16661,16661, 0, 0, 196, 834, 22, 130, 4095, 19, 0, 4921, 4928, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 10, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 16, 5, 0, 7, 6, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Russian/Cyrillic/Russia
- { 239, 27, 22, 0, 0, 136, 136, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 15, 10, 299, 499, 0, 0,16580,16580,16641,16641,16661,16661, 0, 0, 196, 834, 22, 131, 4111, 19, 0, 4921, 526, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 10, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 2, 17, 5, 0, 7, 8, {66,89,78}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Russian/Cyrillic/Belarus
- { 239, 27, 123, 0, 0, 136, 136, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 15, 10, 299, 499, 0, 0,16580,16580,16641,16641,16661,16661, 0, 0, 196, 834, 22, 246, 4128, 19, 0, 4921, 4934, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 10, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 15, 5, 0, 7, 9, {75,90,84}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Russian/Cyrillic/Kazakhstan
- { 239, 27, 128, 0, 0, 136, 136, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 15, 10, 299, 499, 0, 0,16580,16580,16641,16641,16661,16661, 0, 0, 196, 834, 22, 254, 4143, 19, 0, 4921, 4943, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 10, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 3, 14, 5, 0, 7, 8, {75,71,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Russian/Cyrillic/Kyrgyzstan
- { 239, 27, 154, 0, 0, 136, 136, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 15, 10, 299, 499, 0, 0,16580,16580,16641,16641,16661,16661, 0, 0, 196, 834, 22, 10, 4157, 19, 0, 4921, 4951, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 10, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 14, 5, 0, 7, 7, {77,68,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Russian/Cyrillic/Moldova
- { 239, 27, 244, 0, 0, 136, 136, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 15, 10, 299, 499, 0, 0,16580,16580,16641,16641,16661,16661, 0, 0, 196, 834, 22, 294, 4171, 19, 0, 4921, 4958, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 10, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 17, 5, 0, 7, 7, {85,65,72}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Russian/Cyrillic/Ukraine
- { 240, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,12016,12016,12077,12077, 1041, 1041, 413, 430, 0, 5, 22, 119, 3361, 0, 0, 4965, 2055, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 61, 61, 27, 27, 13, 13, 5, 9, 4, 17, 23, 3, 20, 4, 0, 6, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Rwa/Latin/Tanzania
- { 241, 66, 74, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 0, 0, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Saho/Latin/Eritrea
- { 242, 27, 193, 0, 0, 973, 973, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 15, 10, 1374, 293, 0, 0,16674,16674,16744,16744,16764,16764, 570, 590, 896, 901, 22, 130, 4188, 19, 0, 4971, 4980, 6, 6, 11, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 30, 6, 10, 5, 70, 70, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 20, 5, 0, 9, 9, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Sakha/Cyrillic/Russia
- { 243, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,16777,16777,16881,16881,16908,16908, 572, 592, 0, 5, 22, 173, 4208, 9, 13, 4989, 1125, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5,104,104, 27, 27, 13, 13, 7, 5, 4, 17, 23, 3, 18, 4, 6, 8, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Samburu/Latin/Kenya
- { 245, 66, 46, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 10, 11, 71, 87, 0, 0,16921,16921,16986,16986,17013,17013, 579, 597, 0, 5, 22, 3, 4226, 9, 62, 4997, 5002, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 65, 65, 27, 27, 13, 13, 2, 2, 4, 17, 23, 4, 18, 4, 5, 5, 22, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Sango/Latin/Central African Republic
- { 246, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,17026,17026,17085,17085,17112,17112, 581, 599, 0, 5, 22, 119, 4244, 0, 0, 5024, 5033, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 59, 59, 27, 27, 13, 13, 9, 9, 4, 17, 23, 3, 18, 4, 0, 9, 9, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Sangu/Latin/Tanzania
- { 247, 29, 110, 0, 0, 984, 994, 6, 0, 1, 2, 41, 4, 5, 9, 10, 11, 12, 13, 0, 87, 42, 54,17125,17125, 7215, 7215, 7246, 7246, 463, 484, 0, 5, 22, 118, 4262, 4, 0, 5042, 5054, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 66, 66, 31, 31, 18, 18, 9, 7, 4, 17, 23, 1, 15, 5, 0, 12, 5, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Sanskrit/Devanagari/India
- { 248, 93, 110, 0, 0, 0, 0, 6, 0, 1, 2, 78, 4, 5, 9, 10, 11, 12, 13, 0, 87, 42, 54,17191,17191,17232,17232,17257,17257, 590, 608, 0, 5, 22, 118, 4277, 4, 0, 5059, 5066, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 7, 41, 41, 25, 25, 13, 13, 5, 5, 4, 17, 23, 1, 16, 5, 0, 7, 6, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Santali/Ol Chiki/India
- { 248, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 118, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Santali/Devanagari/India
- { 249, 66, 117, 0, 0, 376, 376, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 10, 11, 1404, 127, 0, 0,17270,17270,17324,17324,17351,17351, 0, 0, 0, 5, 22, 14, 4293, 19, 0, 5072, 721, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 31, 10, 10, 5, 54, 54, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 5, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Sardinian/Latin/Italy
- { 251, 66, 160, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 87, 0, 0,17364,17364,17418,17418,17445,17445, 0, 0, 0, 5, 22, 264, 4297, 0, 0, 5077, 4739, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 54, 54, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 21, 4, 0, 4, 10, {77,90,78}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Sena/Latin/Mozambique
- { 252, 27, 207, 0, 0, 136, 136, 6, 1, 0, 2, 3, 4, 5, 9, 15, 10, 12, 12, 331, 381, 0, 0,17458,17458,17509,17509, 2449, 2449, 0, 0, 918, 5, 22, 295, 4318, 19, 24, 5081, 5087, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 10, 5, 51, 51, 27, 27, 13, 13, 2, 2, 7, 17, 23, 3, 12, 5, 7, 6, 6, {82,83,68}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Serbian/Cyrillic/Serbia
- { 252, 27, 29, 0, 0, 136, 136, 6, 1, 0, 2, 3, 4, 5, 9, 15, 10, 12, 12, 331, 381, 0, 0, 2367, 2367, 2422, 2422, 2449, 2449, 104, 613, 918, 5, 22, 136, 4330, 19, 24, 5081, 614, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 10, 5, 55, 55, 27, 27, 13, 13, 11, 8, 7, 17, 23, 2, 40, 5, 7, 6, 19, {66,65,77}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Cyrillic/Bosnia And Herzegovina
- { 252, 27, 126, 0, 0, 136, 136, 6, 1, 0, 2, 3, 4, 5, 9, 15, 10, 12, 12, 331, 381, 0, 0,17458,17458,17509,17509, 2449, 2449, 0, 0, 918, 5, 22, 14, 4370, 19, 24, 5081, 5093, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 10, 5, 51, 51, 27, 27, 13, 13, 2, 2, 7, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Cyrillic/Kosovo
- { 252, 27, 157, 0, 0, 136, 136, 6, 1, 0, 2, 3, 4, 5, 9, 15, 10, 12, 12, 331, 381, 0, 0,17536,17536,17509,17509, 2449, 2449, 104, 613, 918, 5, 22, 14, 4370, 19, 24, 5081, 5099, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 10, 5, 54, 54, 27, 27, 13, 13, 11, 8, 7, 17, 23, 1, 4, 5, 7, 6, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Cyrillic/Montenegro
- { 252, 66, 29, 0, 0, 129, 129, 6, 1, 0, 2, 3, 4, 5, 9, 15, 10, 12, 12, 331, 381, 0, 0, 2257, 2257, 2314, 2314, 2341, 2341, 595, 621, 218, 5, 22, 134, 583, 19, 24, 5108, 587, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 10, 5, 57, 57, 27, 27, 13, 13, 11, 8, 7, 17, 23, 2, 40, 5, 7, 6, 19, {66,65,77}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Latin/Bosnia And Herzegovina
- { 252, 66, 126, 0, 0, 129, 129, 6, 1, 0, 2, 3, 4, 5, 9, 15, 10, 12, 12, 331, 381, 0, 0,17590,17590,17643,17643, 2341, 2341, 0, 0, 218, 5, 22, 14, 4374, 19, 24, 5108, 5114, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 10, 5, 53, 53, 27, 27, 13, 13, 2, 2, 7, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Latin/Kosovo
- { 252, 66, 157, 0, 0, 129, 129, 6, 1, 0, 2, 3, 4, 5, 9, 15, 10, 12, 12, 331, 381, 0, 0,17670,17670,17643,17643, 2341, 2341, 595, 621, 218, 5, 22, 14, 4374, 19, 24, 5108, 5120, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 10, 5, 56, 56, 27, 27, 13, 13, 11, 8, 7, 17, 23, 1, 4, 5, 7, 6, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Latin/Montenegro
- { 252, 66, 207, 0, 0, 129, 129, 6, 1, 0, 2, 3, 4, 5, 9, 15, 10, 12, 12, 331, 381, 0, 0,17590,17590,17643,17643, 2341, 2341, 0, 0, 218, 5, 22, 295, 4378, 19, 24, 5108, 5129, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 10, 5, 53, 53, 27, 27, 13, 13, 2, 2, 7, 17, 23, 3, 12, 5, 7, 6, 6, {82,83,68}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Serbian/Latin/Serbia
- { 253, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,17726,17726,17788,17788,17815,17815, 606, 629, 0, 5, 22, 119, 4390, 0, 0, 5135, 2055, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 62, 62, 27, 27, 13, 13, 5, 8, 4, 17, 23, 3, 20, 4, 0, 9, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Shambala/Latin/Tanzania
- { 254, 66, 261, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 11, 11, 13, 13, 27, 44, 0, 0,17828,17828,17882,17882,17909,17909, 0, 0, 0, 5, 22, 146, 4410, 9, 13, 5144, 2221, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 54, 54, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 15, 4, 6, 8, 8, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Shona/Latin/Zimbabwe
- { 255, 141, 50, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0,17922,17922,17949,17949,17969,17969, 611, 637, 0, 5, 22, 152, 0, 4, 0, 5152, 5155, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 3, 2, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Sichuan Yi/Yi/China
- { 256, 66, 117, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 14, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Sicilian/Latin/Italy
- { 257, 66, 77, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 0, 0, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Sidamo/Latin/Ethiopia
- { 258, 66, 187, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 283, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 0, 0, {80,76,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Silesian/Latin/Poland
- { 259, 4, 178, 0, 0, 1003, 1011, 53, 21, 22, 23, 25, 26, 28, 30, 10, 11, 12, 13, 453, 44, 42, 54,17982,17982,17982,17982,18016,18016, 613, 639, 925, 931, 22, 189, 4425, 19, 0, 5157, 5161, 6, 6, 8, 7, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 18, 10, 12, 7, 34, 34, 34, 34, 30, 30, 11, 11, 6, 25, 23, 2, 12, 5, 0, 4, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Sindhi/Arabic/Pakistan
- { 259, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 471, 42, 54,18046,18073,18114,18136,18164,18164, 624, 650, 0, 5, 22, 118, 4437, 4, 0, 5168, 572, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 27, 41, 22, 28, 20, 20, 8, 6, 4, 17, 23, 1, 17, 5, 0, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Sindhi/Devanagari/India
- { 260, 119, 221, 0, 0, 1018, 1027, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 187, 187,18184,18184,18245,18245,18283,18283, 632, 656, 956, 961, 22, 298, 4454, 9, 13, 5174, 5179, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 61, 61, 38, 38, 18, 18, 5, 4, 5, 42, 23, 3, 17, 4, 6, 5, 11, {76,75,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Sinhala/Sinhala/Sri Lanka
- { 261, 66, 83, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 14, 0, 4, 0, 5190, 5200, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 10, 12, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Skolt Sami/Latin/Finland
- { 262, 66, 212, 0, 0, 743, 253, 6, 1, 14, 2, 3, 4, 5, 6, 15, 10, 16, 12, 554, 350, 1, 1,18301,18301,18352,18352,18372,18372, 0, 0, 311, 5, 22, 14, 420, 19, 24, 5212, 5222, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 9, 4, 51, 51, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 7, 10, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Slovak/Latin/Slovakia
- { 263, 66, 213, 0, 0, 1035, 1035, 6, 1, 0, 2, 3, 40, 5, 6, 15, 10, 16, 12, 331, 533, 0, 0,18385,18385,18436,18436,18470,18470, 172, 660, 50, 5, 22, 14, 4471, 19, 24, 5231, 5242, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 9, 10, 5, 51, 51, 34, 34, 13, 13, 4, 4, 4, 17, 23, 1, 4, 5, 7, 11, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Slovenian/Latin/Slovenia
- { 264, 66, 243, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,18483,18483,18547,18547,18581,18581, 637, 664, 0, 5, 22, 149, 2729, 19, 0, 5251, 3091, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 64, 64, 34, 34, 13, 13, 6, 6, 4, 17, 23, 3, 19, 5, 0, 7, 7, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Soga/Latin/Uganda
- { 265, 66, 215, 0, 0, 1043, 1043, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 127, 10, 22,18594,18594,18640,18640,18671,18671, 643, 670, 1003, 1009, 22, 91, 4475, 9, 13, 5258, 5266, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 12, 7, 46, 46, 31, 31, 14, 14, 2, 2, 6, 17, 23, 1, 20, 4, 6, 8, 10, {83,79,83}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Somali/Latin/Somalia
- { 265, 66, 67, 0, 0, 1043, 1043, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 127, 10, 22,18594,18594,18640,18640,18671,18671, 643, 670, 1003, 1009, 22, 35, 4495, 9, 13, 5258, 5276, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 12, 7, 46, 46, 31, 31, 14, 14, 2, 2, 6, 17, 23, 3, 13, 4, 6, 8, 7, {68,74,70}, 0, 0, 6, 6, 7, 1, 3, 3 }, // Somali/Latin/Djibouti
- { 265, 66, 77, 0, 0, 1043, 1043, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 127, 10, 22,18594,18594,18640,18640,18671,18671, 643, 670, 1003, 1009, 22, 131, 4508, 9, 13, 5258, 5283, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 12, 7, 46, 46, 31, 31, 14, 14, 2, 2, 6, 17, 23, 2, 15, 4, 6, 8, 8, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Somali/Latin/Ethiopia
- { 265, 66, 124, 0, 0, 1043, 1043, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 127, 0, 0,18594,18594,18640,18640,18671,18671, 643, 670, 1003, 1009, 22, 173, 4523, 9, 13, 5258, 1125, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 46, 46, 31, 31, 14, 14, 2, 2, 6, 17, 23, 3, 15, 4, 6, 8, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Somali/Latin/Kenya
- { 266, 4, 112, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 0, 0, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Southern Kurdish/Arabic/Iran
- { 267, 66, 225, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 159, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 0, 0, {83,69,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Southern Sami/Latin/Sweden
- { 268, 66, 216, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 1, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Southern Sotho/Latin/South Africa
- { 269, 66, 216, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 1, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // South Ndebele/Latin/South Africa
- { 270, 66, 220, 0, 0, 70, 70, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 10, 11, 792, 87, 74, 1,18685,18685,18737,18737,16142,16142, 132, 128, 0, 5, 22, 14, 420, 19, 0, 5291, 386, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 11, 4, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 4, 5, 0, 17, 6, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Spanish/Latin/Spain
- { 270, 66, 11, 0, 0, 70, 70, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 87, 0, 0,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 2, 4538, 4, 55, 5291, 5308, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 10, 5, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 14, 5, 7, 7, 9, {65,82,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Argentina
- { 270, 66, 24, 0, 0, 70, 70, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 87, 0, 0,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 2, 4552, 9, 0, 5291, 5317, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 10, 5, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 14, 4, 0, 7, 6, {66,90,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Belize
- { 270, 66, 28, 0, 0, 70, 70, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 87, 0, 0,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 289, 4566, 9, 0, 5291, 4837, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 10, 5, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 2, 9, 4, 0, 7, 7, {66,79,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Bolivia
- { 270, 66, 32, 0, 0, 70, 70, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 87, 0, 0,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 1, 4575, 9, 0, 5291, 4660, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 10, 5, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 2, 14, 4, 0, 7, 6, {66,82,76}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Brazil
- { 270, 66, 42, 0, 0, 70, 70, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 10, 11, 792, 87, 74, 1,18685,18685,18737,18737,16142,16142, 132, 128, 0, 5, 22, 14, 420, 19, 0, 5291, 5323, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 11, 4, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 4, 5, 0, 7, 8, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Spanish/Latin/Canary Islands
- { 270, 66, 47, 0, 0, 70, 70, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 10, 11, 792, 87, 74, 1,18685,18685,18737,18737,16142,16142, 132, 128, 0, 5, 22, 14, 420, 19, 0, 5291, 5331, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 11, 4, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 4, 5, 0, 7, 15, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Spanish/Latin/Ceuta And Melilla
- { 270, 66, 49, 0, 0, 70, 70, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 321, 0, 0,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 2, 4589, 9, 0, 5291, 5346, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 12, 4, 0, 7, 5, {67,76,80}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Chile
- { 270, 66, 54, 0, 0, 70, 70, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 128, 10, 22,18685,18685,18737,18737, 8028, 5588, 132, 128, 0, 5, 22, 2, 4601, 9, 0, 5291, 5351, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 7, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 15, 4, 0, 7, 8, {67,79,80}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Colombia
- { 270, 66, 59, 0, 0, 70, 70, 6, 1, 14, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 87, 0, 0,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 301, 4616, 9, 0, 5291, 5359, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 10, 5, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 19, 4, 0, 7, 10, {67,82,67}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Costa Rica
- { 270, 66, 61, 0, 0, 70, 70, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 87, 0, 0,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 2, 4635, 9, 0, 5291, 5369, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 10, 5, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 11, 4, 0, 7, 4, {67,85,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Cuba
- { 270, 66, 69, 0, 0, 70, 70, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 87, 10, 22,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 302, 4646, 9, 13, 5291, 5373, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 3, 15, 4, 6, 7, 20, {68,79,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Dominican Republic
- { 270, 66, 70, 0, 0, 70, 70, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 87, 0, 0,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 2, 4661, 9, 0, 5291, 4844, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 10, 5, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 20, 4, 0, 7, 7, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Ecuador
- { 270, 66, 72, 0, 0, 70, 70, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 87, 0, 0,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 2, 4661, 9, 0, 5291, 5393, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 10, 5, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 20, 4, 0, 7, 11, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/El Salvador
- { 270, 66, 73, 0, 0, 70, 70, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 10, 11, 792, 87, 74, 1,18685,18685,18737,18737,16142,16142, 132, 128, 0, 5, 22, 3, 4681, 19, 0, 5291, 5404, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 11, 4, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 4, 28, 5, 0, 7, 17, {88,65,70}, 0, 0, 1, 6, 7, 2, 3, 3 }, // Spanish/Latin/Equatorial Guinea
- { 270, 66, 99, 0, 0, 70, 70, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 128, 0, 0,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 248, 4709, 9, 0, 5291, 5421, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 7, 10, 5, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 7, 4, 0, 7, 9, {71,84,81}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Guatemala
- { 270, 66, 106, 0, 0, 70, 70, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 1435, 87, 0, 0,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 10, 4716, 9, 0, 5291, 5430, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 10, 5, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 17, 4, 0, 7, 8, {72,78,76}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Honduras
- { 270, 66, 130, 0, 0, 70, 70, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 87, 0, 0,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 0, 0, 9, 0, 5438, 5461, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 10, 5, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 0, 0, 4, 0, 23, 13, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Latin America
- { 270, 66, 152, 0, 0, 70, 70, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 127, 0, 0,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 2, 4733, 9, 0, 5474, 5491, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 10, 5, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 13, 4, 0, 17, 6, {77,88,78}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Mexico
- { 270, 66, 168, 0, 0, 70, 70, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 87, 0, 0,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 305, 4746, 9, 0, 5291, 5497, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 10, 5, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 2, 20, 4, 0, 7, 9, {78,73,79}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Nicaragua
- { 270, 66, 181, 0, 0, 70, 70, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 1462, 10, 22,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 307, 4766, 9, 0, 5291, 5506, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 3, 15, 4, 0, 7, 6, {80,65,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Panama
- { 270, 66, 183, 0, 0, 70, 70, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 87, 0, 0,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 310, 4781, 9, 0, 5291, 5512, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 10, 5, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 3, 17, 4, 0, 7, 8, {80,89,71}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Paraguay
- { 270, 66, 184, 0, 0, 70, 70, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 128, 0, 0,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 287, 4798, 9, 0, 5291, 4833, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 7, 10, 5, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 2, 11, 4, 0, 7, 4, {80,69,78}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Peru
- { 270, 66, 185, 0, 0, 70, 70, 6, 1, 0, 2, 3, 4, 5, 9, 17, 18, 10, 11, 792, 87, 10, 22,18685,18685,18737,18737,16142,16142, 132, 128, 0, 5, 22, 145, 4809, 19, 0, 5291, 5520, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 13, 5, 0, 7, 9, {80,72,80}, 2, 1, 7, 6, 7, 2, 3, 3 }, // Spanish/Latin/Philippines
- { 270, 66, 189, 0, 0, 70, 70, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 1462, 10, 22,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 2, 4661, 9, 0, 5291, 1867, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 20, 4, 0, 7, 11, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Puerto Rico
- { 270, 66, 248, 0, 0, 70, 70, 6, 0, 1, 2, 3, 4, 5, 9, 17, 18, 10, 11, 792, 87, 10, 22,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 2, 4661, 9, 0, 5291, 5529, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 20, 4, 0, 7, 14, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/United States
- { 270, 66, 250, 0, 0, 70, 70, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 87, 0, 0,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 2, 4822, 4, 55, 5291, 5543, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 10, 5, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 13, 5, 7, 7, 7, {85,89,85}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Uruguay
- { 270, 66, 254, 0, 0, 70, 70, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 792, 87, 10, 22,18685,18685,18737,18737, 5588, 5588, 132, 128, 0, 5, 22, 313, 4835, 9, 0, 5291, 5550, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 12, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 4, 16, 4, 0, 7, 9, {86,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Venezuela
- { 271, 135, 159, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 15, 11, 71, 87, 0, 0,18764,18764,18811,18811, 83, 83, 645, 672, 0, 5, 22, 0, 4851, 0, 0, 5559, 5567, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 47, 47, 29, 29, 13, 13, 6, 8, 4, 17, 23, 0, 14, 4, 0, 8, 6, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Standard Moroccan Tamazight/Tifinagh/Morocco
- { 272, 66, 111, 0, 0, 1052, 1065, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 87, 188, 188,18840,18840,18883,18883, 7932, 7932, 0, 0, 0, 5, 22, 240, 4865, 9, 0, 5573, 3377, 6, 6, 13, 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 9, 4, 43, 43, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 15, 4, 0, 10, 9, {73,68,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Sundanese/Latin/Indonesia
- { 273, 66, 230, 0, 0, 528, 528, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 955, 955, 955, 955, 83, 83, 0, 0, 742, 1026, 22, 119, 3361, 4, 0, 5583, 2055, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 59, 59, 59, 59, 13, 13, 2, 2, 5, 51, 23, 3, 20, 5, 0, 9, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Swahili/Latin/Tanzania
- { 273, 66, 57, 0, 0, 528, 528, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 955, 955, 955, 955, 83, 83, 0, 0, 742, 1026, 22, 3, 4880, 4, 0, 5583, 5592, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 59, 59, 59, 59, 13, 13, 2, 2, 5, 51, 23, 2, 16, 5, 0, 9, 32, {67,68,70}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Swahili/Latin/Congo Kinshasa
- { 273, 66, 124, 0, 0, 528, 528, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 955, 955, 955, 955, 83, 83, 0, 0, 742, 1026, 22, 173, 959, 4, 0, 5583, 1125, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 59, 59, 59, 59, 13, 13, 2, 2, 5, 51, 23, 3, 17, 5, 0, 9, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Swahili/Latin/Kenya
- { 273, 66, 243, 0, 0, 528, 528, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0, 955, 955, 955, 955, 83, 83, 0, 0, 742, 1026, 22, 149, 4896, 4, 0, 5583, 862, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 59, 59, 59, 59, 13, 13, 2, 2, 5, 51, 23, 3, 18, 5, 0, 9, 6, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Swahili/Latin/Uganda
- { 274, 66, 216, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 1, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Swati/Latin/South Africa
- { 275, 66, 225, 0, 0, 1077, 1077, 6, 1, 14, 2, 3, 40, 5, 53, 11, 11, 13, 13, 71, 44, 0, 0,18910,18910,18959,18959, 4152, 4152, 651, 680, 0, 5, 22, 159, 4914, 19, 0, 5624, 5631, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 16, 10, 10, 5, 49, 49, 28, 28, 13, 13, 2, 2, 4, 17, 23, 2, 12, 5, 0, 7, 7, {83,69,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Swedish/Latin/Sweden
- { 275, 66, 2, 0, 0, 1077, 1077, 6, 1, 14, 2, 3, 40, 5, 53, 11, 11, 13, 13, 71, 44, 0, 0,18910,18910,18959,18959, 4152, 4152, 651, 680, 0, 5, 22, 14, 420, 19, 0, 5624, 5638, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 16, 10, 10, 5, 49, 49, 28, 28, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 7, 5, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Swedish/Latin/Aland Islands
- { 275, 66, 83, 0, 0, 1077, 1077, 6, 1, 14, 2, 3, 40, 5, 53, 11, 11, 13, 13, 71, 44, 0, 0,18910,18910,18959,18959, 4152, 4152, 651, 680, 0, 5, 22, 14, 420, 19, 0, 5624, 1494, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 16, 10, 10, 5, 49, 49, 28, 28, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Swedish/Latin/Finland
- { 276, 66, 226, 0, 0, 425, 425, 6, 0, 13, 2, 3, 40, 5, 9, 17, 18, 19, 20, 331, 184, 0, 0,18987,18987,19049,19049, 3885, 3885, 653, 682, 0, 5, 22, 216, 4926, 19, 0, 5643, 5643, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 62, 62, 27, 27, 13, 13, 12, 11, 4, 17, 23, 3, 16, 5, 0, 16, 7, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Swiss German/Latin/Switzerland
- { 276, 66, 84, 0, 0, 425, 425, 6, 0, 13, 2, 3, 40, 5, 9, 17, 18, 19, 20, 331, 184, 0, 0,18987,18987,19049,19049, 3885, 3885, 653, 682, 0, 5, 22, 14, 73, 19, 0, 5643, 5659, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 62, 62, 27, 27, 13, 13, 12, 11, 4, 17, 23, 1, 4, 5, 0, 16, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Swiss German/Latin/France
- { 276, 66, 136, 0, 0, 425, 425, 6, 0, 13, 2, 3, 40, 5, 9, 17, 18, 19, 20, 331, 184, 0, 0,18987,18987,19049,19049, 3885, 3885, 653, 682, 0, 5, 22, 216, 4926, 19, 0, 5643, 5669, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 62, 62, 27, 27, 13, 13, 12, 11, 4, 17, 23, 3, 16, 5, 0, 16, 13, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Swiss German/Latin/Liechtenstein
- { 277, 123, 113, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 0, 0, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Syriac/Syriac/Iraq
- { 278, 135, 159, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 15, 11, 71, 87, 0, 0,19076,19076,18811,18811, 83, 83, 645, 672, 0, 5, 22, 0, 4851, 0, 0, 5682, 5567, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 46, 46, 29, 29, 13, 13, 6, 8, 4, 17, 23, 0, 14, 4, 0, 7, 6, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tachelhit/Tifinagh/Morocco
- { 278, 66, 159, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 15, 11, 71, 87, 0, 0,19122,19122,19169,19169, 83, 83, 665, 693, 0, 5, 22, 0, 4942, 0, 0, 5689, 5699, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 47, 47, 29, 29, 13, 13, 6, 8, 4, 17, 23, 0, 14, 4, 0, 10, 6, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tachelhit/Latin/Morocco
- { 280, 127, 255, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 317, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {86,78,68}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Tai Dam/Tai Viet/Vietnam
- { 281, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,19198,19198,19302,19302,19329,19329, 671, 701, 0, 5, 22, 173, 959, 9, 13, 5705, 1125, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5,104,104, 27, 27, 13, 13, 10, 10, 4, 17, 23, 3, 17, 4, 6, 7, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Taita/Latin/Kenya
- { 282, 27, 229, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 10, 11, 12, 13, 642, 127, 0, 0,19342,19342,19396,19396,19423,19423, 0, 0, 0, 5, 22, 318, 4956, 19, 0, 5712, 5718, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 54, 54, 27, 27, 13, 13, 2, 2, 4, 17, 23, 4, 6, 5, 0, 6, 10, {84,74,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tajik/Cyrillic/Tajikistan
- { 283, 129, 110, 0, 0, 1086, 1086, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 192, 87, 96, 96,19436,19436,19484,19484,19522,19522, 681, 711, 1077, 5, 22, 118, 4962, 9, 13, 5728, 5733, 6, 6, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 48, 48, 38, 38, 19, 19, 8, 8, 7, 17, 23, 1, 13, 4, 6, 5, 7, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Tamil/Tamil/India
- { 283, 129, 143, 0, 0, 1086, 1086, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 192, 87, 96, 96,19436,19436,19484,19484,19522,19522, 681, 711, 1077, 5, 22, 185, 4975, 9, 13, 5728, 5740, 6, 6, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 48, 48, 38, 38, 19, 19, 8, 8, 7, 17, 23, 2, 17, 4, 6, 5, 7, {77,89,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tamil/Tamil/Malaysia
- { 283, 129, 210, 0, 0, 1086, 1086, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 192, 87, 96, 96,19436,19436,19484,19484,19522,19522, 681, 711, 1077, 5, 22, 2, 4992, 9, 13, 5728, 5747, 6, 6, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 7, 48, 48, 38, 38, 19, 19, 8, 8, 7, 17, 23, 1, 17, 4, 6, 5, 11, {83,71,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Tamil/Tamil/Singapore
- { 283, 129, 221, 0, 0, 1086, 1086, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 192, 87, 0, 0,19436,19436,19484,19484,19522,19522, 681, 711, 1077, 5, 22, 322, 5009, 9, 13, 5728, 5758, 6, 6, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 10, 5, 48, 48, 38, 38, 19, 19, 8, 8, 7, 17, 23, 3, 13, 4, 6, 5, 6, {76,75,82}, 2, 1, 1, 6, 7, 1, 2, 3 }, // Tamil/Tamil/Sri Lanka
- { 284, 66, 228, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 325, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 0, 0, {84,87,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Taroko/Latin/Taiwan
- { 285, 66, 170, 0, 0, 0, 0, 6, 0, 14, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 87, 0, 0,10018,10018,10071,10071,10098,10098, 689, 719, 0, 5, 22, 124, 3166, 0, 0, 5764, 5777, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 53, 53, 27, 27, 13, 13, 8, 10, 4, 17, 23, 5, 16, 4, 0, 13, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Tasawaq/Latin/Niger
- { 286, 27, 193, 0, 0, 1099, 1099, 6, 1, 14, 2, 3, 4, 5, 9, 10, 11, 12, 13, 1470, 499, 1, 1,19541,19541,19596,19596,19631,19631, 0, 0, 0, 5, 22, 130, 5022, 19, 0, 5782, 4928, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 9, 4, 55, 55, 35, 35, 13, 13, 2, 2, 4, 17, 23, 1, 11, 5, 0, 5, 6, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tatar/Cyrillic/Russia
- { 287, 131, 110, 0, 0, 1108, 1108, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 1493, 321, 42, 54,19644,19644,19703,19703,19734,19734, 0, 0, 1084, 1091, 22, 118, 5033, 9, 13, 5787, 5793, 6, 6, 11, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 12, 7, 59, 59, 31, 31, 17, 17, 2, 2, 7, 29, 23, 1, 14, 4, 6, 6, 8, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Telugu/Telugu/India
- { 288, 66, 243, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,19751,19751,19819,19819,19846,19846, 697, 729, 0, 5, 22, 149, 5047, 9, 13, 5801, 862, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 68, 68, 27, 27, 13, 13, 9, 6, 4, 17, 23, 3, 21, 4, 6, 6, 6, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Teso/Latin/Uganda
- { 288, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,19751,19751,19819,19819,19846,19846, 697, 729, 0, 5, 22, 173, 5068, 9, 13, 5801, 5807, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 68, 68, 27, 27, 13, 13, 9, 6, 4, 17, 23, 3, 20, 4, 6, 6, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Teso/Latin/Kenya
- { 289, 133, 231, 1119, 1119, 1124, 1132, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 1511, 87, 480, 0,19859,19859,19926,19926,19948,19948, 706, 735, 1120, 5, 22, 328, 5088, 9, 13, 5812, 5812, 5, 5, 8, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 6, 28, 5, 67, 67, 22, 22, 15, 15, 10, 10, 4, 17, 23, 1, 3, 4, 6, 3, 3, {84,72,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Thai/Thai/Thailand
- { 290, 134, 50, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 1530, 44, 0, 0,19963,19963,20041,20041,20091,20091, 716, 745, 0, 5, 22, 152, 5091, 4, 0, 5815, 5823, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 10, 5, 78, 78, 50, 50, 26, 26, 7, 8, 4, 17, 23, 1, 6, 5, 0, 8, 6, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tibetan/Tibetan/China
- { 290, 134, 110, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 1530, 44, 42, 54,19963,19963,20041,20041,20091,20091, 716, 745, 0, 5, 22, 118, 5097, 4, 0, 5815, 5829, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 12, 7, 78, 78, 50, 50, 26, 26, 7, 8, 4, 17, 23, 1, 12, 5, 0, 8, 7, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Tibetan/Tibetan/India
- { 291, 33, 74, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 0, 0, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tigre/Ethiopic/Eritrea
- { 292, 33, 77, 24, 24, 1139, 1139, 6, 0, 1, 2, 3, 4, 5, 9, 17, 18, 10, 11, 1553, 127, 42, 54,20117,20117,20145,20145,20165,20165, 723, 753, 0, 5, 22, 131, 102, 9, 0, 5836, 89, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 12, 7, 28, 28, 20, 20, 13, 13, 4, 4, 4, 17, 23, 2, 2, 4, 0, 4, 5, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Tigrinya/Ethiopic/Ethiopia
- { 292, 33, 74, 24, 24, 1139, 1139, 6, 0, 1, 2, 3, 4, 5, 9, 12, 13, 10, 11, 1553, 127, 42, 54,20117,20117,20145,20145,20165,20165, 723, 753, 0, 5, 22, 38, 5109, 9, 0, 5836, 5840, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 12, 7, 28, 28, 20, 20, 13, 13, 4, 4, 4, 17, 23, 3, 3, 4, 0, 4, 4, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tigrinya/Ethiopic/Eritrea
- { 294, 66, 182, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 0, 0, {80,71,75}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tok Pisin/Latin/Papua New Guinea
- { 295, 66, 235, 1146, 1146, 1146, 1146, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 87, 10, 22,20178,20178,20237,20237,20265,20265, 727, 757, 1124, 1129, 1188, 198, 5112, 4, 0, 5844, 2070, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 12, 7, 59, 59, 28, 28, 13, 13, 10, 6, 5, 59, 65, 2, 17, 5, 0, 13, 5, {84,79,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tongan/Latin/Tonga
- { 296, 66, 216, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 1, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Tsonga/Latin/South Africa
- { 297, 66, 216, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 1, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Tswana/Latin/South Africa
- { 298, 66, 239, 0, 0, 1154, 1154, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 1570, 500, 0, 0,20278,20278,20331,20331,20358,20358, 737, 763, 185, 5, 22, 253, 5129, 9, 13, 5857, 5863, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 9, 10, 5, 53, 53, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 11, 4, 6, 6, 7, {84,82,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Turkish/Latin/Turkey
- { 298, 66, 63, 0, 0, 1154, 1154, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 1570, 500, 10, 22,20278,20278,20331,20331,20358,20358, 737, 763, 185, 5, 22, 14, 73, 9, 13, 5857, 5870, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 9, 12, 7, 53, 53, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 4, 6, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Turkish/Latin/Cyprus
- { 299, 66, 240, 0, 0, 1162, 1162, 6, 1, 14, 2, 3, 4, 5, 9, 10, 11, 10, 11, 1570, 499, 0, 0,20371,20424,20477,20504,20531,20531, 739, 765, 1253, 5, 22, 329, 5140, 19, 0, 5876, 5888, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 10, 5, 53, 53, 27, 27, 13, 13, 13, 14, 4, 17, 23, 3, 14, 5, 0, 12, 12, {84,77,84}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Turkmen/Latin/Turkmenistan
- { 301, 66, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 122, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tyap/Latin/Nigeria
- { 303, 27, 244, 0, 0, 103, 103, 6, 1, 14, 2, 3, 4, 5, 79, 17, 18, 15, 10, 1586, 184, 0, 0,20544,20544, 2607, 2607,20599,20599, 752, 779, 1257, 834, 22, 294, 5154, 19, 0, 5900, 5910, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 8, 10, 5, 55, 55, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 17, 5, 0, 10, 7, {85,65,72}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ukrainian/Cyrillic/Ukraine
- { 304, 66, 91, 0, 0, 743, 743, 6, 1, 0, 2, 3, 4, 5, 9, 15, 10, 16, 12, 331, 121, 1, 508,20612,20612,20664,20664,20691,20691, 385, 781, 1262, 5, 22, 14, 420, 19, 0, 5917, 5932, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 9, 12, 52, 52, 27, 27, 13, 13, 9, 9, 5, 17, 23, 1, 4, 5, 0, 15, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Upper Sorbian/Latin/Germany
- { 305, 4, 178, 623, 623, 1170, 1180, 6, 0, 1, 2, 3, 35, 37, 9, 11, 10, 13, 12, 1608, 87, 42, 54,20704,20704,20704,20704, 83, 83, 0, 0, 1267, 1271, 22, 189, 5171, 9, 13, 5938, 4624, 6, 6, 10, 9, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 18, 6, 12, 7, 35, 35, 35, 35, 13, 13, 2, 2, 4, 20, 23, 2, 14, 4, 6, 4, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Urdu/Arabic/Pakistan
- { 305, 4, 110, 623, 623, 1170, 1180, 6, 21, 22, 2, 64, 35, 65, 68, 11, 10, 13, 12, 1608, 87, 42, 54,20704,20704,20704,20704, 83, 83, 0, 0, 1267, 1271, 22, 118, 5185, 9, 13, 5938, 5942, 6, 6, 10, 9, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 18, 6, 12, 7, 35, 35, 35, 35, 13, 13, 2, 2, 4, 20, 23, 1, 12, 4, 6, 4, 5, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Urdu/Arabic/India
- { 306, 4, 50, 0, 0, 294, 304, 6, 0, 1, 2, 3, 4, 5, 9, 18, 17, 20, 19, 1626, 44, 0, 0,20739,20739,20793,20793,20813,20813, 754, 790, 0, 5, 22, 144, 5197, 9, 13, 5947, 5955, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 54, 54, 20, 20, 13, 13, 12, 12, 4, 17, 23, 1, 11, 4, 6, 8, 5, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Uyghur/Arabic/China
- { 307, 66, 251, 0, 0, 1189, 1189, 6, 1, 14, 2, 3, 4, 5, 9, 10, 11, 13, 12, 1643, 127, 74, 0,20826,20826,20886,20886,20917,20917, 343, 802, 185, 5, 22, 332, 5208, 9, 13, 5960, 5966, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 11, 5, 60, 60, 31, 31, 13, 13, 2, 2, 4, 17, 23, 4, 17, 4, 6, 6, 11, {85,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Uzbek/Latin/Uzbekistan
- { 307, 4, 1, 0, 0, 0, 0, 53, 21, 22, 23, 64, 35, 65, 68, 10, 11, 12, 13, 1661, 432, 74, 1,15563,15563,20930,20930, 83, 83, 0, 0, 0, 5, 22, 278, 3754, 19, 0, 5977, 4615, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 33, 8, 11, 4, 48, 48, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 6, 5, 0, 6, 9, {65,70,78}, 0, 0, 6, 4, 5, 1, 3, 3 }, // Uzbek/Arabic/Afghanistan
- { 307, 27, 251, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 10, 11, 12, 13, 819, 127, 73, 0,20950,20950,21002,21002,21029,21029, 766, 804, 0, 5, 22, 336, 5225, 19, 0, 5983, 5990, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 12, 5, 52, 52, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 14, 5, 0, 7, 10, {85,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Uzbek/Cyrillic/Uzbekistan
- { 308, 139, 134, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 42, 54,21042,21042,21042,21042, 83, 83, 0, 0, 0, 5, 22, 2, 5239, 9, 13, 6000, 6002, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 29, 29, 29, 29, 13, 13, 2, 2, 4, 17, 23, 1, 8, 4, 6, 2, 4, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Vai/Vai/Liberia
- { 308, 66, 134, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22,21071,21071,21071,21071, 83, 83, 0, 0, 0, 5, 22, 2, 5247, 9, 13, 6006, 6009, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 47, 47, 47, 47, 13, 13, 2, 2, 4, 17, 23, 1, 13, 4, 6, 3, 8, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Vai/Latin/Liberia
- { 309, 66, 216, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 1, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Venda/Latin/South Africa
- { 310, 66, 255, 0, 0, 1197, 1197, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 192, 127, 0, 0,21118,21118,21172,21172,21204,21204, 768, 806, 0, 5, 22, 317, 5260, 19, 0, 6017, 6027, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 10, 5, 54, 54, 32, 32, 20, 20, 2, 2, 4, 17, 23, 1, 13, 5, 0, 10, 8, {86,78,68}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Vietnamese/Latin/Vietnam
- { 311, 66, 258, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 0, 0, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Volapuk/Latin/World
- { 312, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,12016,12016,12077,12077, 1041, 1041, 413, 430, 0, 5, 22, 119, 3361, 9, 0, 6035, 2055, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 61, 61, 27, 27, 13, 13, 5, 9, 4, 17, 23, 3, 20, 4, 0, 8, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Vunjo/Latin/Tanzania
- { 313, 66, 23, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 14, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 0, 0, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Walloon/Latin/Belgium
- { 314, 66, 226, 0, 0, 425, 425, 6, 1, 13, 2, 3, 4, 5, 9, 17, 18, 19, 20, 331, 44, 0, 0,21224,21224,21276,21276,21303,21303, 0, 0, 0, 5, 22, 0, 0, 4, 0, 6043, 6049, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 10, 5, 52, 52, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 6, 6, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Walser/Latin/Switzerland
- { 315, 66, 15, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 243, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 0, 0, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Warlpiri/Latin/Australia
- { 316, 66, 246, 0, 0, 1205, 1216, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,21316,21316,21392,21420,21449,21449, 770, 808, 1291, 5, 22, 92, 5273, 9, 13, 6055, 6062, 6, 6, 11, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 10, 5, 76, 76, 28, 29, 14, 14, 2, 2, 7, 17, 23, 1, 12, 4, 6, 7, 16, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Welsh/Latin/United Kingdom
- { 317, 4, 178, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 189, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 0, 0, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Western Balochi/Arabic/Pakistan
- { 318, 66, 165, 0, 0, 7, 7, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 321, 0, 0,21463,21463,21516,21516, 83, 83, 0, 0, 0, 5, 22, 14, 73, 4, 55, 6078, 6083, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 53, 53, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 7, 5, 8, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Western Frisian/Latin/Netherlands
- { 319, 33, 77, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 0, 0, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Wolaytta/Ethiopic/Ethiopia
- { 320, 66, 206, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 1694, 321, 0, 0,21536,21536,21585,21585,21585,21585, 689, 810, 0, 5, 22, 124, 5285, 4, 0, 6091, 2762, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 49, 49, 27, 27, 27, 27, 3, 3, 4, 17, 23, 5, 29, 5, 0, 5, 8, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Wolof/Latin/Senegal
- { 321, 66, 216, 0, 0, 0, 0, 6, 0, 14, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 471, 0, 0,21612,21612,21672,21699,21728,21748, 0, 0, 0, 5, 22, 1, 5314, 9, 0, 6096, 6104, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 10, 5, 60, 60, 27, 29, 20, 21, 2, 2, 4, 17, 23, 1, 25, 4, 0, 8, 15, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Xhosa/Latin/South Africa
- { 322, 66, 40, 0, 0, 0, 0, 6, 1, 14, 2, 3, 4, 5, 9, 17, 18, 17, 18, 71, 87, 0, 0,21769,21769,21839,21839,21859,21859, 772, 813, 0, 5, 22, 3, 0, 19, 24, 6119, 6125, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 70, 70, 20, 20, 13, 13, 8, 8, 4, 17, 23, 4, 0, 5, 7, 6, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Yangben/Latin/Cameroon
- { 323, 47, 258, 0, 0, 1226, 1226, 6, 0, 1, 2, 3, 4, 5, 9, 11, 11, 13, 13, 1711, 127, 0, 0,21872,21872,21872,21872, 83, 83, 780, 821, 0, 5, 22, 0, 0, 4, 0, 6132, 6138, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 10, 5, 53, 53, 53, 53, 13, 13, 11, 10, 4, 17, 23, 0, 0, 5, 0, 6, 5, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Yiddish/Hebrew/World
- { 324, 66, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 1730, 87, 0, 1,21925,21968,22036,22036,22068,22068, 791, 831, 1298, 1309, 22, 122, 5339, 9, 13, 6143, 6153, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 3, 43, 68, 32, 32, 13, 13, 5, 5, 11, 37, 23, 1, 14, 4, 6, 10, 8, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Yoruba/Latin/Nigeria
- { 324, 66, 25, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 1730, 87, 0, 1,22081,22124,22192,22192,22224,22224, 796, 836, 1346, 1309, 22, 124, 5353, 9, 13, 6143, 6161, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 3, 43, 68, 32, 32, 13, 13, 5, 5, 11, 37, 23, 5, 26, 4, 6, 10, 6, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Yoruba/Latin/Benin
- { 325, 66, 170, 0, 0, 0, 0, 6, 0, 14, 2, 3, 4, 5, 9, 10, 11, 12, 13, 71, 87, 0, 0,22237,22237,10071,10071,22289,22289, 689, 719, 0, 5, 22, 124, 3166, 0, 0, 6167, 5777, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 10, 5, 52, 52, 27, 27, 13, 13, 8, 10, 4, 17, 23, 5, 16, 4, 0, 10, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Zarma/Latin/Niger
- { 327, 66, 216, 0, 0, 1235, 1244, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 453, 471, 0, 0,22302,22302,22375,22375,22402,22402, 0, 0, 0, 5, 22, 1, 5379, 9, 13, 6177, 6184, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 10, 5, 73, 73, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 20, 4, 6, 7, 17, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Zulu/Latin/South Africa
- { 328, 66, 32, 0, 0, 1252, 1252, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 1746, 127, 0, 0,22415,22415,22501,22501,22535,22535, 0, 0, 1357, 5, 22, 1, 5399, 4, 0, 6201, 6208, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 10, 5, 86, 86, 34, 34, 20, 20, 2, 2, 7, 17, 23, 2, 12, 5, 0, 7, 6, {66,82,76}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Kaingang/Latin/Brazil
- { 329, 66, 32, 0, 0, 1261, 1261, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 0, 0,22555,22555,22619,22619,22646,22646, 0, 0, 1364, 5, 22, 1, 5411, 4, 0, 6214, 6222, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 64, 64, 27, 27, 13, 13, 2, 2, 8, 17, 23, 2, 15, 5, 0, 8, 6, {66,82,76}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Nheengatu/Latin/Brazil
- { 329, 66, 54, 0, 0, 1261, 1261, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22,22555,22555,22619,22619,22646,22646, 132, 128, 1364, 5, 22, 2, 5426, 4, 0, 6228, 6235, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 64, 64, 27, 27, 13, 13, 5, 5, 8, 17, 23, 1, 17, 5, 0, 7, 8, {67,79,80}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Nheengatu/Latin/Colombia
- { 329, 66, 254, 0, 0, 1261, 1261, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 0, 127, 10, 22,22555,22555,22619,22619,22646,22646, 132, 128, 1364, 5, 22, 313, 5443, 4, 0, 6228, 6243, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 64, 64, 27, 27, 13, 13, 5, 5, 8, 17, 23, 4, 22, 5, 0, 7, 9, {86,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Nheengatu/Latin/Venezuela
- { 330, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 41, 4, 5, 9, 10, 11, 12, 13, 27, 44, 42, 54,22659,22659,22659,22659, 83, 83, 801, 83, 0, 5, 22, 118, 0, 4, 0, 6252, 572, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 54, 54, 54, 54, 13, 13, 4, 4, 4, 17, 23, 1, 0, 5, 0, 8, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Haryanvi/Devanagari/India
- { 331, 66, 91, 0, 0, 877, 877, 6, 1, 0, 2, 3, 4, 5, 9, 10, 11, 12, 13, 331, 127, 0, 0,22713,22713,22769,22769, 83, 83, 0, 0, 0, 5, 22, 14, 73, 4, 0, 6260, 6270, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 10, 5, 56, 56, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 10, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Northern Frisian/Latin/Germany
- { 332, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 41, 4, 5, 9, 10, 11, 12, 13, 27, 44, 42, 54, 7163, 7163, 7163, 7163, 83, 83, 805, 841, 0, 5, 22, 118, 0, 4, 0, 6279, 572, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 7, 52, 52, 52, 52, 13, 13, 5, 4, 4, 17, 23, 1, 0, 5, 0, 9, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Rajasthani/Devanagari/India
- { 333, 27, 193, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 130, 0, 4, 0, 6288, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 12, 0, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Moksha/Cyrillic/Russia
- { 334, 66, 258, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 6300, 6309, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 9, 6, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Toki Pona/Latin/World
- { 335, 66, 214, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0,22796,22796,22796,22796, 83, 83, 0, 0, 0, 5, 22, 2, 0, 4, 0, 6315, 6320, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 46, 46, 46, 46, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 5, 13, {83,66,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Pijin/Latin/Solomon Islands
- { 336, 66, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 27, 44, 0, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 122, 0, 4, 0, 6333, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 10, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 5, 0, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Obolo/Latin/Nigeria
+ { 2, 27, 90, 0, 0, 7, 7, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 27, 49, 10, 0, 109, 109, 157, 157, 179, 179, 0, 0, 0, 5, 22, 0, 0, 4, 0, 0, 6, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 13, 5, 48, 48, 22, 22, 15, 15, 2, 2, 4, 17, 23, 1, 0, 5, 0, 6, 9, {71,69,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Abkhazian/Cyrillic/Georgia
+ { 3, 66, 77, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 59, 78, 23, 38, 194, 194, 245, 245, 272, 272, 0, 0, 0, 5, 22, 1, 0, 2, 0, 15, 20, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 15, 7, 51, 51, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 4, 0, 5, 7, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Afar/Latin/Ethiopia
+ { 3, 66, 67, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 59, 78, 23, 38, 194, 194, 245, 245, 272, 272, 0, 0, 0, 5, 22, 3, 0, 2, 0, 15, 27, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 15, 7, 51, 51, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 4, 0, 5, 7, {68,74,70}, 0, 0, 6, 6, 7, 1, 3, 3 }, // Afar/Latin/Djibouti
+ { 3, 66, 74, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 59, 78, 23, 38, 194, 194, 245, 245, 272, 272, 0, 0, 0, 5, 22, 6, 0, 2, 0, 15, 34, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 15, 7, 51, 51, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 4, 0, 5, 7, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Afar/Latin/Eritrea
+ { 4, 66, 216, 0, 0, 16, 16, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 86, 103, 10, 0, 285, 285, 342, 342, 369, 369, 2, 2, 45, 5, 22, 9, 0, 2, 9, 41, 50, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 57, 57, 27, 27, 13, 13, 3, 3, 5, 17, 23, 1, 20, 4, 6, 9, 11, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Afrikaans/Latin/South Africa
+ { 4, 66, 162, 0, 0, 16, 16, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 103, 23, 38, 285, 285, 342, 342, 369, 369, 2, 2, 45, 5, 22, 10, 20, 2, 9, 41, 61, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 15, 7, 57, 57, 27, 27, 13, 13, 3, 3, 5, 17, 23, 1, 16, 4, 6, 9, 7, {78,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Afrikaans/Latin/Namibia
+ { 5, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 0, 382, 382, 453, 453, 480, 480, 5, 5, 0, 5, 22, 11, 36, 0, 0, 68, 73, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 71, 71, 27, 27, 13, 13, 3, 3, 4, 17, 23, 4, 14, 4, 0, 5, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Aghem/Latin/Cameroon
+ { 6, 66, 92, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 137, 155, 23, 38, 493, 493, 541, 541, 568, 568, 8, 8, 0, 5, 22, 15, 50, 2, 0, 80, 84, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 15, 7, 48, 48, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 10, 4, 0, 4, 5, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Akan/Latin/Ghana
+ { 8, 66, 40, 0, 0, 24, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 11, 60, 15, 0, 89, 95, 6, 6, 5, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 4, 10, 5, 0, 6, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Akoose/Latin/Cameroon
+ { 9, 66, 3, 0, 0, 29, 29, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 0, 180, 45, 38, 581, 581, 638, 638, 665, 665, 10, 10, 50, 5, 22, 18, 70, 4, 20, 102, 107, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 16, 7, 57, 57, 27, 27, 14, 14, 11, 10, 4, 17, 23, 4, 13, 5, 7, 5, 8, {65,76,76}, 0, 0, 1, 6, 7, 2, 3, 3 }, // Albanian/Latin/Albania
+ { 9, 66, 126, 0, 0, 29, 29, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 0, 180, 10, 0, 581, 581, 638, 638, 665, 665, 10, 10, 50, 5, 22, 22, 83, 4, 20, 102, 115, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 13, 5, 57, 57, 27, 27, 14, 14, 11, 10, 4, 17, 23, 1, 6, 5, 7, 5, 6, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Albanian/Latin/Kosovo
+ { 9, 66, 140, 0, 0, 29, 29, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 0, 180, 10, 0, 581, 581, 638, 638, 665, 665, 10, 10, 50, 5, 22, 23, 89, 4, 20, 102, 121, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 13, 5, 57, 57, 27, 27, 14, 14, 11, 10, 4, 17, 23, 3, 16, 5, 7, 5, 18, {77,75,68}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Albanian/Latin/Macedonia
+ { 11, 33, 77, 38, 38, 44, 53, 6, 0, 1, 2, 3, 4, 5, 10, 11, 12, 19, 20, 163, 186, 61, 76, 679, 679, 706, 706, 732, 732, 21, 20, 54, 57, 22, 26, 105, 2, 9, 139, 143, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 27, 27, 26, 26, 13, 13, 3, 4, 3, 23, 23, 2, 9, 4, 6, 4, 5, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Amharic/Ethiopic/Ethiopia
+ { 14, 4, 71, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 28, 114, 27, 0, 148, 155, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 9, 6, 0, 7, 3, {69,71,80}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Egypt
+ { 14, 4, 4, 61, 61, 61, 61, 6, 1, 0, 32, 3, 35, 37, 10, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 33, 123, 33, 38, 148, 158, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 12, 5, 7, 7, 7, {68,90,68}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Algeria
+ { 14, 4, 19, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 38, 135, 27, 0, 148, 165, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 12, 6, 0, 7, 7, {66,72,68}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Bahrain
+ { 14, 4, 48, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 11, 147, 27, 0, 148, 172, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 4, 15, 6, 0, 7, 4, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Chad
+ { 14, 4, 55, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 10, 0, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 12, 162, 27, 0, 148, 176, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 13, 5, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 2, 14, 6, 0, 7, 9, {75,77,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Comoros
+ { 14, 4, 67, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 3, 176, 27, 0, 148, 185, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 3, 11, 6, 0, 7, 6, {68,74,70}, 0, 0, 6, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Djibouti
+ { 14, 4, 74, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 6, 187, 27, 0, 148, 191, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 3, 12, 6, 0, 7, 7, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Eritrea
+ { 14, 4, 113, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 43, 199, 27, 0, 148, 198, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 11, 6, 0, 7, 6, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Iraq
+ { 14, 4, 116, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 11, 1, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 48, 210, 27, 0, 148, 204, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 12, 4, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 1, 18, 6, 0, 7, 7, {73,76,83}, 2, 1, 7, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Israel
+ { 14, 4, 122, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 49, 228, 27, 0, 148, 211, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 11, 6, 0, 7, 6, {74,79,68}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Jordan
+ { 14, 4, 127, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 54, 239, 27, 0, 148, 217, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 11, 6, 0, 7, 6, {75,87,68}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Kuwait
+ { 14, 4, 132, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 59, 250, 27, 0, 148, 223, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 11, 6, 0, 7, 5, {76,66,80}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Lebanon
+ { 14, 4, 135, 61, 61, 61, 61, 6, 1, 0, 32, 3, 35, 37, 10, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 64, 261, 33, 38, 148, 228, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 5, 7, 7, 5, {76,89,68}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Libya
+ { 14, 4, 149, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 69, 271, 27, 0, 148, 233, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 4, 15, 6, 0, 7, 9, {77,82,85}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Mauritania
+ { 14, 4, 159, 61, 61, 61, 61, 6, 1, 0, 32, 3, 35, 37, 10, 15, 14, 17, 16, 196, 213, 10, 0, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 73, 286, 33, 38, 148, 242, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 13, 5, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 5, 7, 7, 6, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Morocco
+ { 14, 4, 176, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 78, 296, 27, 0, 148, 248, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 6, 0, 7, 5, {79,77,82}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Oman
+ { 14, 4, 180, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 48, 210, 27, 0, 148, 253, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 1, 18, 6, 0, 7, 18, {73,76,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Palestinian Territories
+ { 14, 4, 190, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 83, 306, 27, 0, 148, 271, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 9, 6, 0, 7, 3, {81,65,82}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Qatar
+ { 14, 4, 205, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 88, 315, 27, 0, 148, 274, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 6, 0, 7, 24, {83,65,82}, 2, 1, 7, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Saudi Arabia
+ { 14, 4, 215, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 93, 325, 27, 0, 148, 298, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 1, 10, 6, 0, 7, 7, {83,79,83}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Somalia
+ { 14, 4, 219, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 94, 335, 27, 0, 148, 305, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 1, 17, 6, 0, 7, 12, {83,83,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/South Sudan
+ { 14, 4, 222, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 95, 352, 27, 0, 148, 317, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 4, 11, 6, 0, 7, 7, {83,68,71}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Sudan
+ { 14, 4, 227, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 99, 363, 27, 0, 148, 324, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 6, 0, 7, 5, {83,89,80}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Syria
+ { 14, 4, 238, 61, 61, 61, 61, 6, 1, 0, 32, 3, 35, 37, 10, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 104, 373, 33, 38, 148, 329, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 11, 5, 7, 7, 4, {84,78,68}, 3, 0, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Tunisia
+ { 14, 4, 245, 61, 61, 61, 61, 6, 0, 1, 32, 3, 35, 37, 10, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 109, 384, 33, 38, 148, 333, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 12, 5, 7, 7, 24, {65,69,68}, 2, 1, 6, 6, 7, 1, 3, 3 }, // Arabic/Arabic/United Arab Emirates
+ { 14, 4, 257, 61, 61, 61, 61, 6, 0, 1, 32, 3, 35, 37, 10, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 73, 286, 33, 38, 148, 357, 6, 6, 6, 6, 1, 1, 1, 3, 1, 2, 2, 1, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 10, 5, 7, 7, 15, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/Western Sahara
+ { 14, 4, 258, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 0, 0, 27, 0, 372, 394, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 0, 0, 6, 0, 22, 6, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Arabic/Arabic/world
+ { 14, 4, 259, 61, 61, 61, 61, 67, 21, 22, 23, 25, 26, 28, 30, 15, 14, 17, 16, 196, 213, 61, 76, 745, 745, 745, 745, 796, 796, 24, 24, 80, 84, 22, 114, 396, 27, 0, 148, 400, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 51, 51, 51, 51, 13, 13, 1, 1, 4, 37, 23, 5, 9, 6, 0, 7, 5, {89,69,82}, 0, 0, 7, 5, 6, 1, 3, 3 }, // Arabic/Arabic/Yemen
+ { 15, 66, 220, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 15, 15, 223, 129, 11, 1, 809, 809, 860, 860, 887, 887, 0, 0, 0, 5, 22, 22, 405, 2, 9, 405, 413, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 6, 12, 4, 51, 51, 27, 27, 16, 16, 2, 2, 4, 17, 23, 1, 4, 4, 6, 8, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Aragonese/Latin/Spain
+ { 17, 5, 12, 0, 0, 75, 75, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 11, 12, 245, 49, 10, 0, 903, 903, 964, 964, 991, 991, 0, 0, 121, 127, 22, 119, 409, 4, 0, 420, 427, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 20, 8, 13, 5, 61, 61, 27, 27, 13, 13, 2, 2, 6, 17, 23, 1, 13, 5, 0, 7, 8, {65,77,68}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Armenian/Armenian/Armenia
+ { 18, 9, 110, 0, 0, 82, 82, 6, 0, 1, 2, 39, 4, 5, 10, 14, 15, 16, 17, 265, 283, 83, 83, 1004, 1004, 1061, 1061, 1092, 1092, 25, 25, 144, 148, 22, 120, 422, 2, 9, 435, 442, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 15, 7, 57, 57, 31, 31, 13, 13, 9, 7, 4, 37, 23, 1, 12, 4, 6, 7, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Assamese/Bangla/India
+ { 19, 66, 220, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 223, 129, 10, 0, 1105, 1105, 1158, 1158, 1185, 1185, 34, 32, 0, 5, 22, 22, 405, 4, 0, 446, 455, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 6, 13, 5, 53, 53, 27, 27, 13, 13, 12, 11, 5, 17, 23, 1, 4, 5, 0, 9, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Asturian/Latin/Spain
+ { 20, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 1198, 1198, 1257, 1257, 1284, 1284, 46, 43, 0, 5, 22, 121, 434, 4, 0, 461, 467, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 59, 59, 27, 27, 13, 13, 9, 8, 4, 17, 23, 3, 21, 5, 0, 6, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Asu/Latin/Tanzania
+ { 21, 66, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 137, 155, 10, 0, 1297, 1297, 1383, 1383, 83, 83, 0, 0, 0, 5, 22, 124, 455, 15, 0, 475, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 86, 86, 33, 33, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 5, 0, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Atsam/Latin/Nigeria
+ { 25, 66, 17, 0, 0, 91, 91, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 291, 49, 10, 0, 1416, 1416, 1482, 1508, 96, 96, 0, 0, 185, 5, 22, 125, 459, 4, 0, 480, 490, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 13, 5, 66, 66, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 17, 5, 0, 10, 10, {65,90,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Azerbaijani/Latin/Azerbaijan
+ { 25, 4, 112, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 11, 12, 19, 20, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 500, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 6, 0, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Azerbaijani/Arabic/Iran
+ { 25, 4, 113, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 11, 12, 19, 20, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 500, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 6, 0, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Azerbaijani/Arabic/Iraq
+ { 25, 4, 239, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 11, 12, 19, 20, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 126, 0, 15, 0, 500, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 6, 0, {84,82,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Azerbaijani/Arabic/Turkey
+ { 25, 27, 17, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 19, 20, 291, 49, 10, 0, 1534, 1534, 1600, 1600, 96, 96, 55, 51, 0, 5, 22, 125, 476, 4, 0, 506, 516, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 13, 5, 66, 66, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 5, 5, 0, 10, 10, {65,90,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Azerbaijani/Cyrillic/Azerbaijan
+ { 26, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 16, 17, 113, 129, 10, 0, 1626, 1626, 1670, 1670, 1698, 1698, 57, 53, 0, 5, 22, 11, 481, 4, 0, 526, 531, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 44, 44, 28, 28, 13, 13, 6, 7, 4, 17, 23, 4, 4, 5, 0, 5, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Bafia/Latin/Cameroon
+ { 28, 66, 145, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 129, 10, 0, 1711, 1711, 1754, 1754, 1781, 1781, 0, 0, 0, 5, 22, 127, 485, 2, 9, 538, 547, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 43, 43, 27, 27, 13, 13, 2, 2, 4, 17, 23, 5, 17, 4, 6, 9, 4, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Bambara/Latin/Mali
+ { 28, 90, 145, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 127, 0, 2, 9, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 5, 0, 4, 6, 0, 0, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Bambara/Nko/Mali
+ { 30, 9, 20, 0, 0, 99, 99, 6, 0, 1, 2, 39, 4, 5, 10, 14, 15, 16, 17, 265, 129, 61, 76, 1794, 1794, 1851, 1851, 1887, 1887, 0, 0, 144, 5, 22, 132, 502, 0, 45, 551, 556, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 57, 57, 36, 36, 17, 17, 2, 2, 4, 17, 23, 1, 14, 4, 6, 5, 8, {66,68,84}, 2, 1, 7, 6, 7, 1, 2, 3 }, // Bangla/Bangla/Bangladesh
+ { 30, 9, 110, 0, 0, 99, 99, 6, 0, 1, 2, 39, 4, 5, 10, 14, 15, 16, 17, 265, 129, 61, 76, 1794, 1794, 1851, 1851, 1887, 1887, 0, 0, 144, 5, 22, 120, 516, 2, 9, 551, 564, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 57, 57, 36, 36, 17, 17, 2, 2, 4, 17, 23, 1, 12, 4, 6, 5, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Bangla/Bangla/India
+ { 31, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 113, 129, 10, 0, 1904, 1904, 1973, 1973, 2000, 2000, 63, 60, 0, 5, 22, 11, 528, 4, 0, 568, 573, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 69, 69, 27, 27, 13, 13, 10, 9, 4, 17, 23, 4, 15, 5, 0, 5, 8, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Basaa/Latin/Cameroon
+ { 32, 27, 193, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 133, 0, 15, 0, 581, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 12, 0, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Bashkir/Cyrillic/Russia
+ { 33, 66, 220, 0, 0, 108, 108, 6, 1, 0, 2, 3, 48, 5, 10, 11, 12, 14, 15, 308, 344, 98, 0, 2013, 2013, 2080, 2080, 2107, 2107, 0, 0, 189, 5, 22, 22, 543, 4, 20, 593, 600, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 36, 6, 15, 5, 67, 67, 27, 27, 13, 13, 2, 2, 7, 17, 23, 1, 5, 5, 7, 7, 8, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Basque/Latin/Spain
+ { 35, 27, 22, 0, 0, 117, 117, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 50, 113, 0, 2120, 2120, 2175, 2175, 2195, 2195, 0, 0, 196, 201, 22, 1, 548, 4, 0, 608, 618, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 7, 14, 5, 55, 55, 20, 20, 13, 13, 2, 2, 5, 17, 23, 2, 16, 5, 0, 10, 8, {66,89,78}, 2, 0, 1, 6, 7, 2, 3, 3 }, // Belarusian/Cyrillic/Belarus
+ { 36, 66, 260, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 2208, 2208, 2208, 2208, 83, 83, 73, 69, 0, 5, 22, 134, 0, 2, 9, 626, 635, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 79, 79, 79, 79, 13, 13, 8, 7, 4, 17, 23, 1, 0, 4, 6, 9, 6, {90,77,87}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Bemba/Latin/Zambia
+ { 37, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 2287, 2287, 2368, 2368, 2395, 2395, 81, 76, 0, 5, 22, 121, 564, 0, 0, 641, 647, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 81, 81, 27, 27, 13, 13, 7, 7, 4, 17, 23, 3, 22, 4, 0, 6, 10, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Bena/Latin/Tanzania
+ { 38, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 163, 103, 61, 76, 2408, 2408, 2408, 2408, 83, 83, 88, 83, 0, 5, 22, 120, 0, 2, 0, 657, 664, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 55, 55, 55, 55, 13, 13, 3, 4, 4, 17, 23, 1, 0, 4, 0, 7, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Bhojpuri/Devanagari/India
+ { 40, 33, 74, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 372, 78, 61, 76, 2463, 2463, 2505, 2505, 2530, 2530, 0, 0, 0, 5, 22, 6, 0, 2, 0, 668, 671, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 8, 15, 7, 42, 42, 25, 25, 13, 13, 2, 2, 4, 17, 23, 3, 0, 4, 0, 3, 4, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Blin/Ethiopic/Eritrea
+ { 41, 29, 110, 0, 0, 124, 134, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 291, 394, 127, 142, 2543, 2597, 2650, 2650, 2682, 2682, 91, 87, 0, 5, 22, 120, 586, 2, 9, 675, 664, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 10, 54, 53, 32, 32, 17, 17, 3, 6, 4, 17, 23, 1, 11, 4, 6, 3, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Bodo/Devanagari/India
+ { 42, 66, 29, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 13, 15, 16, 17, 404, 423, 10, 0, 2699, 2699, 2756, 2756, 2783, 2796, 94, 93, 218, 5, 22, 135, 597, 4, 0, 678, 686, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 11, 13, 5, 57, 57, 27, 27, 13, 13, 10, 7, 7, 17, 23, 2, 40, 5, 0, 8, 19, {66,65,77}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Bosnian/Latin/Bosnia and Herzegovina
+ { 42, 27, 29, 0, 0, 150, 150, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 434, 454, 10, 0, 2809, 2809, 2864, 2864, 2891, 2891, 104, 100, 0, 5, 22, 137, 637, 4, 0, 705, 713, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 20, 7, 13, 5, 55, 55, 27, 27, 13, 13, 11, 13, 4, 17, 23, 2, 19, 5, 0, 8, 19, {66,65,77}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Bosnian/Cyrillic/Bosnia and Herzegovina
+ { 43, 66, 84, 0, 0, 157, 157, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 186, 10, 0, 2904, 2904, 2946, 2946, 2978, 2978, 115, 113, 225, 232, 249, 22, 405, 4, 0, 732, 741, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 42, 42, 32, 32, 17, 17, 4, 4, 7, 17, 23, 1, 4, 5, 0, 9, 5, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Breton/Latin/France
+ { 45, 27, 36, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 13, 14, 13, 14, 350, 461, 152, 1, 2995, 2995, 3049, 3049, 3069, 3069, 119, 117, 272, 5, 22, 139, 656, 4, 20, 746, 755, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 12, 17, 4, 54, 54, 20, 20, 13, 13, 6, 6, 7, 17, 23, 3, 13, 5, 7, 9, 8, {66,71,78}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Bulgarian/Cyrillic/Bulgaria
+ { 46, 86, 161, 165, 165, 172, 172, 182, 0, 1, 2, 50, 4, 5, 10, 14, 15, 16, 17, 473, 129, 169, 1, 3082, 3082, 3082, 3082, 3135, 3135, 125, 123, 279, 5, 22, 134, 669, 15, 0, 763, 763, 7, 7, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 13, 4, 53, 53, 53, 53, 13, 13, 5, 3, 5, 17, 23, 1, 11, 5, 0, 6, 6, {77,77,75}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Burmese/Myanmar/Myanmar
+ { 47, 137, 107, 183, 183, 188, 188, 6, 0, 1, 2, 3, 4, 5, 10, 51, 52, 53, 54, 491, 505, 182, 43, 3148, 3148, 3148, 3148, 3175, 3175, 130, 126, 0, 5, 22, 142, 680, 2, 9, 769, 771, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 14, 8, 16, 6, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 2, 4, 6, 2, 14, {72,75,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Cantonese/Traditional Han/Hong Kong
+ { 47, 118, 50, 183, 183, 188, 188, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 513, 505, 169, 0, 3148, 3148, 3188, 3188, 3175, 3175, 130, 126, 0, 5, 22, 145, 682, 2, 9, 785, 787, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 8, 13, 5, 27, 27, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 3, 4, 6, 2, 7, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Cantonese/Simplified Han/China
+ { 48, 66, 220, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 526, 129, 99, 1, 3208, 3208, 3267, 3267, 3267, 3267, 132, 128, 0, 5, 22, 22, 405, 4, 20, 794, 413, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 14, 4, 59, 59, 27, 27, 27, 27, 5, 5, 5, 17, 23, 1, 4, 5, 7, 6, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Catalan/Latin/Spain
+ { 48, 66, 6, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 526, 129, 99, 1, 3208, 3208, 3267, 3267, 3267, 3267, 132, 128, 0, 5, 22, 22, 405, 4, 20, 794, 800, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 14, 4, 59, 59, 27, 27, 27, 27, 5, 5, 5, 17, 23, 1, 4, 5, 7, 6, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Catalan/Latin/Andorra
+ { 48, 66, 84, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 526, 129, 99, 1, 3208, 3208, 3267, 3267, 3267, 3267, 132, 128, 0, 5, 22, 22, 405, 4, 20, 794, 807, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 14, 4, 59, 59, 27, 27, 27, 27, 5, 5, 5, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Catalan/Latin/France
+ { 48, 66, 117, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 526, 129, 99, 1, 3208, 3208, 3267, 3267, 3267, 3267, 132, 128, 0, 5, 22, 22, 405, 4, 20, 794, 813, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 14, 4, 59, 59, 27, 27, 27, 27, 5, 5, 5, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Catalan/Latin/Italy
+ { 49, 66, 185, 0, 0, 193, 202, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 3294, 3294, 3349, 3349, 3376, 3376, 0, 0, 284, 5, 22, 146, 685, 2, 9, 819, 826, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 55, 55, 27, 27, 13, 13, 2, 2, 8, 17, 23, 1, 15, 4, 6, 7, 9, {80,72,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Cebuano/Latin/Philippines
+ { 50, 66, 159, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 3389, 3389, 3436, 3436, 3463, 3463, 137, 133, 0, 5, 22, 0, 700, 4, 0, 835, 852, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 47, 47, 27, 27, 13, 13, 9, 10, 4, 17, 23, 0, 15, 5, 0, 17, 6, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Central Atlas Tamazight/Latin/Morocco
+ { 51, 4, 113, 0, 0, 0, 0, 67, 21, 22, 23, 25, 55, 57, 59, 14, 15, 16, 17, 163, 103, 61, 76, 3476, 3476, 3476, 3476, 3533, 3533, 146, 143, 0, 5, 22, 43, 715, 4, 0, 858, 872, 6, 6, 6, 6, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 15, 7, 57, 57, 57, 57, 13, 13, 3, 3, 4, 17, 23, 5, 13, 5, 0, 14, 5, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Central Kurdish/Arabic/Iraq
+ { 51, 4, 112, 0, 0, 0, 0, 67, 21, 22, 23, 25, 55, 57, 59, 14, 15, 16, 17, 163, 103, 10, 0, 3476, 3476, 3476, 3476, 3533, 3533, 146, 143, 0, 5, 22, 0, 728, 4, 0, 858, 877, 6, 6, 6, 6, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 13, 5, 57, 57, 57, 57, 13, 13, 3, 3, 4, 17, 23, 0, 12, 5, 0, 14, 5, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Central Kurdish/Arabic/Iran
+ { 52, 21, 20, 0, 0, 210, 210, 6, 0, 1, 2, 61, 4, 5, 10, 14, 15, 16, 17, 265, 129, 61, 76, 3546, 3546, 3672, 3672, 3756, 3756, 0, 0, 292, 5, 22, 132, 740, 0, 45, 882, 894, 6, 6, 12, 12, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7,126,126, 84, 84, 38, 38, 2, 2, 8, 17, 23, 1, 21, 4, 6, 12, 14, {66,68,84}, 2, 1, 7, 6, 7, 1, 2, 3 }, // Chakma/Chakma/Bangladesh
+ { 52, 21, 110, 0, 0, 210, 210, 6, 0, 1, 2, 61, 4, 5, 10, 14, 15, 16, 17, 265, 129, 61, 76, 3546, 3546, 3672, 3672, 3756, 3756, 0, 0, 292, 5, 22, 120, 761, 0, 45, 882, 908, 6, 6, 12, 12, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7,126,126, 84, 84, 38, 38, 2, 2, 8, 17, 23, 1, 27, 4, 6, 12, 10, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Chakma/Chakma/India
+ { 54, 27, 193, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 3794, 3794, 3838, 3838, 3862, 3838, 0, 0, 0, 5, 22, 133, 788, 4, 0, 918, 925, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 44, 44, 24, 24, 16, 24, 2, 2, 4, 17, 23, 1, 11, 5, 0, 7, 5, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Chechen/Cyrillic/Russia
+ { 55, 23, 248, 0, 0, 222, 231, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 61, 76, 3878, 3878, 3926, 3926, 3953, 3953, 149, 146, 300, 5, 22, 10, 799, 2, 9, 930, 933, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 48, 48, 27, 27, 13, 13, 3, 6, 6, 17, 23, 1, 6, 4, 6, 3, 15, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Cherokee/Cherokee/United States
+ { 56, 66, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 3966, 3966, 3966, 3966, 83, 83, 0, 0, 0, 5, 22, 10, 0, 15, 0, 948, 964, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 87, 87, 87, 87, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 16, 13, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chickasaw/Latin/United States
+ { 57, 66, 243, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 4053, 4053, 4126, 4126, 4153, 4153, 0, 0, 0, 5, 22, 147, 805, 2, 0, 977, 983, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 73, 73, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 19, 4, 0, 6, 6, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Chiga/Latin/Uganda
+ { 58, 118, 50, 183, 183, 239, 239, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 513, 505, 169, 0, 3148, 3148, 3188, 3188, 3175, 3175, 130, 126, 306, 5, 22, 150, 682, 2, 9, 989, 993, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 8, 13, 5, 27, 27, 20, 20, 13, 13, 2, 2, 2, 17, 23, 1, 3, 4, 6, 4, 2, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Chinese/Simplified Han/China
+ { 58, 118, 107, 183, 183, 239, 239, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 513, 129, 198, 43, 3148, 3148, 3188, 3188, 3175, 3175, 130, 126, 306, 5, 22, 142, 824, 2, 9, 989, 995, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 6, 14, 6, 27, 27, 20, 20, 13, 13, 2, 2, 2, 17, 23, 3, 2, 4, 6, 4, 9, {72,75,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chinese/Simplified Han/Hong Kong
+ { 58, 118, 139, 183, 183, 239, 239, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 513, 129, 198, 43, 3148, 3148, 3188, 3188, 3175, 3175, 130, 126, 306, 5, 22, 151, 826, 2, 9, 989, 1004, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 6, 14, 6, 27, 27, 20, 20, 13, 13, 2, 2, 2, 17, 23, 4, 3, 4, 6, 4, 9, {77,79,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chinese/Simplified Han/Macao
+ { 58, 118, 210, 183, 183, 239, 239, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 513, 78, 198, 43, 3148, 3148, 3188, 3188, 3175, 3175, 130, 126, 306, 5, 22, 10, 829, 2, 9, 989, 1013, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 8, 14, 6, 27, 27, 20, 20, 13, 13, 2, 2, 2, 17, 23, 1, 4, 4, 6, 4, 3, {83,71,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chinese/Simplified Han/Singapore
+ { 58, 137, 107, 183, 183, 244, 244, 6, 0, 1, 2, 3, 4, 5, 10, 51, 52, 53, 54, 513, 129, 182, 43, 3148, 3148, 4166, 4166, 3175, 3175, 130, 126, 308, 5, 22, 142, 824, 2, 9, 1016, 1020, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 8, 16, 6, 27, 27, 20, 20, 13, 13, 2, 2, 3, 17, 23, 3, 2, 4, 6, 4, 9, {72,75,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chinese/Traditional Han/Hong Kong
+ { 58, 137, 139, 183, 183, 244, 244, 6, 0, 1, 2, 3, 4, 5, 10, 51, 52, 53, 54, 513, 129, 182, 43, 3148, 3148, 4166, 4166, 3175, 3175, 130, 126, 308, 5, 22, 151, 833, 2, 9, 1016, 1029, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 8, 16, 6, 27, 27, 20, 20, 13, 13, 2, 2, 3, 17, 23, 4, 3, 4, 6, 4, 9, {77,79,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Chinese/Traditional Han/Macao
+ { 58, 137, 228, 183, 183, 239, 239, 6, 0, 1, 2, 3, 4, 5, 10, 51, 52, 53, 54, 491, 505, 182, 43, 3148, 3148, 4166, 4166, 3175, 3175, 130, 126, 0, 5, 22, 10, 836, 2, 9, 1016, 1038, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 14, 8, 16, 6, 27, 27, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 3, 4, 6, 4, 2, {84,87,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Chinese/Traditional Han/Taiwan
+ { 59, 27, 193, 0, 0, 249, 249, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 573, 596, 10, 0, 4186, 4186, 4253, 4253, 4289, 4289, 0, 0, 0, 5, 22, 133, 839, 4, 0, 1040, 1059, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 13, 5, 67, 67, 36, 36, 13, 13, 2, 2, 4, 17, 23, 1, 18, 5, 0, 19, 7, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Church/Cyrillic/Russia
+ { 60, 27, 193, 0, 0, 257, 257, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 606, 49, 10, 0, 4302, 4302, 4367, 4367, 4399, 4399, 0, 0, 0, 5, 22, 133, 857, 4, 0, 1066, 1071, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 13, 5, 65, 65, 32, 32, 13, 13, 2, 2, 4, 17, 23, 1, 12, 5, 0, 5, 6, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Chuvash/Cyrillic/Russia
+ { 61, 66, 91, 0, 0, 267, 267, 6, 1, 9, 2, 3, 48, 5, 63, 13, 14, 18, 16, 628, 423, 10, 0, 4412, 4412, 4483, 4483, 4510, 4510, 152, 152, 0, 5, 22, 22, 83, 4, 0, 1077, 1083, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 23, 10, 13, 5, 71, 71, 27, 27, 13, 13, 16, 16, 4, 17, 23, 1, 4, 5, 0, 6, 11, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Colognian/Latin/Germany
+ { 63, 66, 246, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 186, 10, 0, 4523, 4523, 4583, 4583, 83, 83, 168, 168, 0, 5, 22, 94, 0, 2, 0, 1094, 1102, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 60, 60, 27, 27, 13, 13, 4, 4, 4, 17, 23, 1, 0, 4, 0, 8, 14, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Cornish/Latin/United Kingdom
+ { 64, 66, 84, 0, 0, 275, 275, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 11, 12, 651, 186, 10, 0, 4610, 4610, 4660, 4660, 4694, 4694, 0, 0, 0, 5, 22, 155, 405, 4, 51, 1116, 1121, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 25, 10, 13, 5, 50, 50, 34, 34, 13, 13, 2, 2, 4, 17, 23, 3, 4, 5, 7, 5, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Corsican/Latin/France
+ { 66, 66, 60, 0, 0, 143, 143, 6, 1, 0, 2, 3, 48, 5, 10, 13, 14, 18, 16, 404, 676, 98, 0, 2699, 2699, 2756, 2756, 2783, 2796, 0, 0, 218, 5, 22, 22, 405, 4, 0, 1128, 1136, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 13, 15, 5, 57, 57, 27, 27, 13, 13, 2, 2, 7, 17, 23, 1, 4, 5, 0, 8, 8, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Croatian/Latin/Croatia
+ { 66, 66, 29, 0, 0, 143, 143, 6, 1, 0, 2, 3, 48, 5, 10, 13, 14, 18, 16, 404, 689, 98, 0, 2699, 2699, 2756, 2756, 2796, 2796, 0, 0, 218, 5, 22, 135, 618, 4, 0, 1128, 686, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 9, 15, 5, 57, 57, 27, 27, 13, 13, 2, 2, 7, 17, 23, 2, 19, 5, 0, 8, 19, {66,65,77}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Croatian/Latin/Bosnia and Herzegovina
+ { 67, 66, 64, 0, 0, 282, 282, 6, 1, 9, 2, 3, 4, 5, 10, 13, 14, 18, 16, 698, 49, 114, 1, 4707, 4707, 4755, 4755, 4775, 4775, 172, 172, 311, 5, 22, 158, 869, 4, 0, 1144, 1151, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 13, 4, 48, 48, 20, 20, 13, 13, 4, 4, 5, 17, 23, 2, 12, 5, 0, 7, 5, {67,90,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Czech/Latin/Czechia
+ { 68, 66, 65, 0, 0, 289, 289, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 715, 49, 212, 212, 4788, 4788, 4838, 4838, 4874, 4874, 0, 0, 0, 5, 22, 160, 881, 4, 0, 1156, 1161, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 13, 5, 50, 50, 36, 36, 13, 13, 2, 2, 5, 17, 23, 3, 11, 5, 0, 5, 7, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Danish/Latin/Denmark
+ { 68, 66, 95, 0, 0, 289, 289, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 715, 49, 212, 212, 4788, 4788, 4838, 4838, 4874, 4874, 0, 0, 0, 5, 22, 160, 881, 4, 0, 1156, 1168, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 13, 5, 50, 50, 36, 36, 13, 13, 2, 2, 5, 17, 23, 3, 11, 5, 0, 5, 8, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Danish/Latin/Greenland
+ { 69, 132, 144, 0, 0, 0, 0, 2, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 283, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 163, 0, 15, 0, 1176, 1186, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 10, 13, {77,86,82}, 2, 1, 5, 6, 7, 1, 3, 3 }, // Divehi/Thaana/Maldives
+ { 70, 29, 110, 0, 0, 297, 306, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 738, 129, 61, 76, 4887, 4887, 4937, 4937, 4966, 4988, 176, 176, 0, 5, 22, 120, 892, 2, 0, 1199, 664, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 50, 50, 29, 29, 22, 24, 4, 9, 4, 17, 23, 1, 10, 4, 0, 5, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Dogri/Devanagari/India
+ { 71, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 16, 17, 113, 129, 10, 0, 5012, 5012, 5056, 5056, 5083, 5083, 180, 185, 0, 5, 22, 11, 0, 4, 0, 1204, 1209, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 44, 44, 27, 27, 13, 13, 5, 6, 4, 17, 23, 4, 0, 5, 0, 5, 8, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Duala/Latin/Cameroon
+ { 72, 66, 165, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 394, 10, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 22, 83, 15, 58, 1217, 1217, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 1, 4, 5, 7, 10, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Netherlands
+ { 72, 66, 13, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 394, 10, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 165, 902, 15, 58, 1217, 1227, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 4, 16, 5, 7, 10, 5, {65,87,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Aruba
+ { 72, 66, 23, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 187, 10, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 22, 83, 15, 58, 1232, 1238, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 9, 13, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Belgium
+ { 72, 66, 44, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 394, 10, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 10, 918, 15, 58, 1217, 1244, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 1, 18, 5, 7, 10, 19, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Caribbean Netherlands
+ { 72, 66, 62, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 394, 10, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 169, 936, 15, 58, 1217, 1263, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 4, 30, 5, 7, 10, 7, {65,78,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Curacao
+ { 72, 66, 211, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 394, 10, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 169, 936, 15, 58, 1217, 1270, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 4, 30, 5, 7, 10, 12, {65,78,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Sint Maarten
+ { 72, 66, 223, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 16, 17, 113, 394, 10, 0, 5096, 5096, 5154, 5154, 5174, 5174, 168, 168, 0, 5, 22, 10, 966, 15, 58, 1217, 1282, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 58, 58, 20, 20, 13, 13, 4, 4, 4, 17, 23, 1, 17, 5, 7, 10, 8, {83,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Dutch/Latin/Suriname
+ { 73, 134, 27, 314, 314, 314, 314, 6, 0, 1, 2, 67, 4, 5, 10, 14, 15, 16, 17, 756, 103, 225, 255, 5187, 5187, 5265, 5265, 5298, 5298, 185, 191, 0, 5, 22, 173, 983, 2, 0, 1290, 1296, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 30, 10, 30, 22, 78, 78, 33, 33, 26, 26, 5, 6, 4, 17, 23, 3, 8, 4, 0, 6, 5, {66,84,78}, 2, 1, 7, 6, 7, 1, 2, 3 }, // Dzongkha/Tibetan/Bhutan
+ { 74, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 5324, 5324, 5387, 5387, 5414, 5414, 190, 197, 0, 5, 22, 176, 991, 2, 9, 1301, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 63, 63, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 17, 4, 6, 6, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Embu/Latin/Kenya
+ { 75, 66, 248, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1312, 964, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 16, 13, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/United States
+ { 75, 28, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 5427, 5427, 5511, 5511, 5559, 5559, 192, 199, 0, 5, 22, 10, 0, 15, 0, 1328, 1338, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 84, 84, 48, 48, 20, 20, 4, 4, 4, 17, 23, 1, 0, 5, 0, 10, 25, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Deseret/United States
+ { 75, 66, 5, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 1363, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 14, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/American Samoa
+ { 75, 66, 8, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 1377, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 8, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Anguilla
+ { 75, 66, 10, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 1385, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 17, {88,67,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Antigua and Barbuda
+ { 75, 66, 15, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 6, 14, 15, 16, 17, 113, 129, 23, 38, 0, 0, 56, 56, 83, 5579, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1402, 1402, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 15, 7, 56, 56, 27, 27, 13, 24, 2, 2, 5, 17, 23, 1, 17, 4, 6, 18, 9, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Australia
+ { 75, 66, 16, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 15, 0, 1321, 1420, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Austria
+ { 75, 66, 18, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1055, 2, 9, 1321, 1427, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 7, {66,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Bahamas
+ { 75, 66, 21, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1070, 2, 9, 1321, 1434, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 16, 4, 6, 7, 8, {66,66,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Barbados
+ { 75, 66, 23, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 78, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 4, 0, 1321, 1442, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Belgium
+ { 75, 66, 24, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 786, 78, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1086, 2, 9, 1321, 1449, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 13, 4, 6, 7, 6, {66,90,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Belize
+ { 75, 66, 26, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1099, 2, 9, 1321, 1455, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 16, 4, 6, 7, 7, {66,77,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Bermuda
+ { 75, 66, 30, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 786, 78, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 153, 1115, 2, 9, 1321, 1462, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 14, 4, 6, 7, 8, {66,87,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Botswana
+ { 75, 66, 33, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 1470, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 30, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/British Indian Ocean Territory
+ { 75, 66, 34, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 1500, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 22, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/British Virgin Islands
+ { 75, 66, 38, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 0, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 182, 1129, 2, 9, 1321, 1522, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 15, 4, 6, 7, 7, {66,73,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Burundi
+ { 75, 66, 40, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 11, 1144, 2, 9, 1321, 1529, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 4, 25, 4, 6, 7, 8, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Cameroon
+ { 75, 66, 41, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 103, 23, 38, 0, 0, 56, 56, 83, 83, 168, 168, 0, 5, 22, 10, 1169, 2, 9, 1537, 1553, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 15, 7, 56, 56, 27, 27, 13, 13, 4, 4, 5, 17, 23, 1, 15, 4, 6, 16, 6, {67,65,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // English/Latin/Canada
+ { 75, 66, 45, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1184, 2, 9, 1321, 1559, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 14, {75,89,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Cayman Islands
+ { 75, 66, 51, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1321, 1573, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 16, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Christmas Island
+ { 75, 66, 53, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1321, 1589, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 23, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Cocos Islands
+ { 75, 66, 58, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1205, 2, 9, 1321, 1612, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 12, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Cook Islands
+ { 75, 66, 63, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 2, 9, 1321, 1624, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 4, 6, 7, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Cyprus
+ { 75, 66, 65, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 212, 212, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 160, 1223, 4, 0, 1321, 1630, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 12, 5, 0, 7, 7, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Denmark
+ { 75, 66, 66, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 1637, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 12, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Diego Garcia
+ { 75, 66, 68, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 1649, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 8, {88,67,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Dominica
+ { 75, 66, 74, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 6, 1235, 2, 9, 1321, 1657, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 14, 4, 6, 7, 7, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Eritrea
+ { 75, 66, 76, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 155, 1249, 2, 9, 1321, 1664, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 8, {83,90,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Eswatini
+ { 75, 66, 78, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 0, 0, 4, 0, 1321, 1672, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 0, 5, 0, 7, 6, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Europe
+ { 75, 66, 80, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1264, 2, 9, 1321, 1678, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 22, 4, 6, 7, 16, {70,75,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Falkland Islands
+ { 75, 66, 82, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1286, 2, 9, 1321, 1694, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 13, 4, 6, 7, 4, {70,74,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Fiji
+ { 75, 66, 83, 0, 0, 333, 333, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 213, 213, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 4, 0, 1321, 1698, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 4, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Finland
+ { 75, 66, 89, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 185, 1299, 2, 9, 1321, 1705, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 14, 4, 6, 7, 6, {71,77,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Gambia
+ { 75, 66, 91, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 4, 0, 1321, 1711, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Germany
+ { 75, 66, 92, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 15, 1313, 2, 9, 1321, 1718, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 13, 4, 6, 7, 5, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Ghana
+ { 75, 66, 93, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1326, 2, 9, 1321, 1723, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 9, {71,73,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Gibraltar
+ { 75, 66, 96, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 1732, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 7, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Grenada
+ { 75, 66, 98, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 1739, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 4, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Guam
+ { 75, 66, 100, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1341, 2, 9, 1321, 1743, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 8, 4, 6, 7, 8, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Guernsey
+ { 75, 66, 103, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1349, 2, 9, 1321, 1751, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 16, 4, 6, 7, 6, {71,89,68}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Guyana
+ { 75, 66, 107, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 142, 1365, 2, 9, 1321, 1757, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 16, 4, 6, 7, 19, {72,75,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Hong Kong
+ { 75, 66, 110, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 804, 78, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 120, 1381, 2, 9, 1321, 1478, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 12, 4, 6, 7, 5, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // English/Latin/India
+ { 75, 66, 111, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 212, 212, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 186, 1393, 2, 9, 1321, 1776, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 17, 4, 6, 7, 9, {73,68,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // English/Latin/Indonesia
+ { 75, 66, 114, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 186, 10, 0, 0, 0, 56, 56, 83, 83, 168, 168, 0, 5, 22, 22, 83, 2, 9, 1321, 1785, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 56, 56, 27, 27, 13, 13, 4, 4, 5, 17, 23, 1, 4, 4, 6, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Ireland
+ { 75, 66, 115, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1341, 2, 9, 1321, 1792, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 8, 4, 6, 7, 11, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Isle of Man
+ { 75, 66, 116, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 11, 1, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 48, 1410, 2, 9, 1321, 1803, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 4, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 6, {73,76,83}, 2, 1, 7, 5, 6, 1, 3, 3 }, // English/Latin/Israel
+ { 75, 66, 119, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1428, 2, 9, 1321, 1809, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 7, {74,77,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Jamaica
+ { 75, 66, 121, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1341, 2, 9, 1321, 1816, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 8, 4, 6, 7, 6, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Jersey
+ { 75, 66, 124, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 176, 1443, 2, 9, 1321, 1307, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 15, 4, 6, 7, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Kenya
+ { 75, 66, 125, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1321, 1822, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 8, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Kiribati
+ { 75, 66, 133, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 9, 1458, 2, 9, 1321, 1830, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 7, {90,65,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Lesotho
+ { 75, 66, 134, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1476, 2, 9, 1321, 1837, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 7, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Liberia
+ { 75, 66, 139, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 151, 1491, 2, 9, 1321, 1844, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 4, 15, 4, 6, 7, 15, {77,79,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Macao
+ { 75, 66, 141, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 188, 1506, 2, 9, 1321, 1859, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 15, 4, 6, 7, 10, {77,71,65}, 0, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Madagascar
+ { 75, 66, 142, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 190, 1521, 2, 9, 1321, 1869, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 15, 4, 6, 7, 6, {77,87,75}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Malawi
+ { 75, 66, 143, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 192, 1536, 2, 9, 1321, 1875, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 17, 4, 6, 7, 8, {77,89,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Malaysia
+ { 75, 66, 144, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 283, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 194, 1553, 15, 0, 1321, 1883, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 17, 5, 0, 7, 8, {77,86,82}, 2, 1, 5, 6, 7, 1, 3, 3 }, // English/Latin/Maldives
+ { 75, 66, 146, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 2, 9, 1321, 1891, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 4, 6, 7, 5, {69,85,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Malta
+ { 75, 66, 147, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 1896, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 16, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Marshall Islands
+ { 75, 66, 150, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 196, 1570, 2, 9, 1321, 1912, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 15, 4, 6, 7, 9, {77,85,82}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Mauritius
+ { 75, 66, 153, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 1921, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 10, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Micronesia
+ { 75, 66, 158, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 1931, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 10, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Montserrat
+ { 75, 66, 162, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1585, 2, 9, 1321, 1941, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 7, {78,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Namibia
+ { 75, 66, 163, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1321, 1948, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 5, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Nauru
+ { 75, 66, 165, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 15, 58, 1321, 1953, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 7, 7, 11, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Netherlands
+ { 75, 66, 167, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1205, 2, 9, 1321, 1964, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 11, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/New Zealand
+ { 75, 66, 169, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 124, 1600, 2, 9, 1321, 1975, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 14, 4, 6, 7, 7, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Nigeria
+ { 75, 66, 171, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1205, 2, 9, 1321, 1982, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 4, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Niue
+ { 75, 66, 172, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1321, 1986, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 14, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Norfolk Island
+ { 75, 66, 173, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 2000, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 24, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Northern Mariana Islands
+ { 75, 66, 178, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 196, 1614, 2, 9, 1321, 2024, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 15, 4, 6, 7, 8, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // English/Latin/Pakistan
+ { 75, 66, 179, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 2032, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 5, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Palau
+ { 75, 66, 182, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 134, 1629, 2, 9, 1321, 2037, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 22, 4, 6, 7, 16, {80,71,75}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Papua New Guinea
+ { 75, 66, 185, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 146, 685, 2, 9, 1321, 2053, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 11, {80,72,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Philippines
+ { 75, 66, 186, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1205, 2, 9, 1321, 2064, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 16, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Pitcairn
+ { 75, 66, 189, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 2080, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 11, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Puerto Rico
+ { 75, 66, 194, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 198, 1651, 2, 9, 1321, 2091, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 13, 4, 6, 7, 6, {82,87,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Rwanda
+ { 75, 66, 196, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1664, 2, 9, 1321, 2097, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 15, 4, 6, 7, 9, {83,72,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Saint Helena
+ { 75, 66, 197, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 2106, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 16, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Saint Kitts and Nevis
+ { 75, 66, 198, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 2122, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 8, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Saint Lucia
+ { 75, 66, 201, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1017, 2, 9, 1321, 2130, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 21, 4, 6, 7, 27, {88,67,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Saint Vincent and Grenadines
+ { 75, 66, 202, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 200, 1679, 2, 9, 1321, 1372, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 11, 4, 6, 7, 5, {87,83,84}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Samoa
+ { 75, 66, 208, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 203, 1690, 2, 9, 1321, 2157, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 17, 4, 6, 7, 10, {83,67,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Seychelles
+ { 75, 66, 209, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 18, 1707, 2, 9, 1321, 2167, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 20, 4, 6, 7, 12, {83,76,69}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Sierra Leone
+ { 75, 66, 210, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1727, 2, 9, 1321, 2179, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 16, 4, 6, 7, 9, {83,71,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Singapore
+ { 75, 66, 211, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 169, 1743, 2, 9, 1321, 2188, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 4, 29, 4, 6, 7, 12, {65,78,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Sint Maarten
+ { 75, 66, 213, 0, 0, 333, 333, 6, 1, 0, 2, 3, 4, 5, 6, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 22, 83, 4, 20, 1321, 2200, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 7, 7, 8, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Slovenia
+ { 75, 66, 214, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1772, 2, 9, 1321, 2208, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 22, 4, 6, 7, 15, {83,66,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Solomon Islands
+ { 75, 66, 216, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 786, 821, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 9, 1458, 2, 9, 1321, 2223, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 12, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/South Africa
+ { 75, 66, 219, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1794, 2, 9, 1321, 2235, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 20, 4, 6, 7, 11, {83,83,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/South Sudan
+ { 75, 66, 222, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 0, 1814, 2, 9, 1321, 2246, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 14, 4, 6, 7, 5, {83,68,71}, 2, 1, 6, 5, 6, 1, 3, 3 }, // English/Latin/Sudan
+ { 75, 66, 225, 0, 0, 333, 333, 6, 1, 9, 2, 3, 4, 5, 63, 14, 15, 16, 17, 0, 103, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 160, 1828, 4, 0, 1321, 2251, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 13, 5, 0, 7, 6, {83,69,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Sweden
+ { 75, 66, 226, 0, 0, 333, 333, 6, 0, 17, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 49, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 0, 1841, 15, 65, 1321, 2257, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 11, 5, 5, 7, 11, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Switzerland
+ { 75, 66, 230, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 121, 1852, 2, 9, 1321, 2268, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 18, 4, 6, 7, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Tanzania
+ { 75, 66, 234, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1205, 2, 9, 1321, 2276, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 18, 4, 6, 7, 7, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Tokelau
+ { 75, 66, 235, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 205, 1870, 2, 9, 1321, 2283, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 14, 4, 6, 7, 5, {84,79,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Tonga
+ { 75, 66, 236, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1884, 2, 9, 1321, 2288, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 24, 4, 6, 7, 17, {84,84,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Trinidad and Tobago
+ { 75, 66, 241, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 2305, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 22, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Turks and Caicos Islands
+ { 75, 66, 242, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 10, 1038, 2, 9, 1321, 2327, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 17, 4, 6, 7, 6, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Tuvalu
+ { 75, 66, 243, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 147, 1908, 2, 9, 1321, 983, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 16, 4, 6, 7, 6, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // English/Latin/Uganda
+ { 75, 66, 245, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 1924, 2, 9, 1321, 2333, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 27, 4, 6, 7, 20, {65,69,68}, 2, 1, 6, 6, 7, 1, 3, 3 }, // English/Latin/United Arab Emirates
+ { 75, 66, 246, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 186, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 94, 1951, 2, 9, 2353, 2368, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 13, 4, 6, 15, 14, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/United Kingdom
+ { 75, 66, 247, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 2382, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 21, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/United States Outlying Islands
+ { 75, 66, 249, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 0, 0, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 1008, 2, 9, 1321, 2403, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 9, 4, 6, 7, 19, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/United States Virgin Islands
+ { 75, 66, 252, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 207, 1964, 2, 9, 1321, 2422, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 2, 12, 4, 6, 7, 7, {86,85,86}, 0, 0, 1, 6, 7, 1, 3, 3 }, // English/Latin/Vanuatu
+ { 75, 66, 258, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 0, 0, 2, 9, 1321, 2429, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 0, 4, 6, 7, 5, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/world
+ { 75, 66, 260, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 134, 1976, 2, 9, 1321, 635, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 14, 4, 6, 7, 6, {90,77,87}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Latin/Zambia
+ { 75, 66, 261, 0, 0, 333, 333, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 786, 129, 10, 0, 0, 0, 56, 56, 83, 83, 82, 203, 0, 5, 22, 179, 1008, 2, 9, 1321, 2434, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 3, 9, 4, 6, 7, 8, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // English/Latin/Zimbabwe
+ { 75, 115, 246, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 5603, 5603, 5690, 5690, 5731, 5731, 196, 205, 0, 5, 22, 94, 0, 15, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 87, 87, 41, 41, 20, 20, 4, 4, 4, 17, 23, 1, 0, 5, 0, 0, 0, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // English/Shavian/United Kingdom
+ { 76, 27, 193, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 5751, 5811, 5892, 5892, 83, 83, 0, 0, 0, 5, 22, 133, 0, 15, 0, 2442, 2453, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 60, 81, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 11, 13, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Erzya/Cyrillic/Russia
+ { 77, 66, 258, 0, 0, 342, 342, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 831, 105, 10, 0, 5919, 5919, 5969, 5969, 5989, 5989, 200, 209, 316, 5, 22, 0, 0, 4, 0, 2466, 2475, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 31, 8, 13, 5, 50, 50, 20, 20, 13, 13, 3, 3, 6, 17, 23, 0, 0, 5, 0, 9, 5, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Esperanto/Latin/world
+ { 78, 66, 75, 0, 0, 351, 351, 6, 1, 9, 2, 3, 48, 5, 63, 13, 14, 18, 16, 404, 49, 10, 0, 6002, 6002, 6064, 6064, 6064, 6064, 0, 0, 322, 5, 22, 22, 405, 4, 20, 2480, 2485, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 18, 8, 13, 5, 62, 62, 13, 13, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 5, 5, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Estonian/Latin/Estonia
+ { 79, 66, 92, 0, 0, 359, 370, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 862, 567, 277, 277, 6077, 6077, 6120, 6120, 6147, 6147, 203, 212, 0, 5, 22, 15, 1990, 2, 9, 2490, 2496, 6, 6, 11, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 20, 12, 43, 43, 27, 27, 13, 13, 3, 5, 4, 17, 23, 3, 10, 4, 6, 6, 12, {71,72,83}, 2, 1, 1, 6, 7, 3, 3, 3 }, // Ewe/Latin/Ghana
+ { 79, 66, 233, 0, 0, 359, 370, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 862, 567, 10, 0, 6077, 6077, 6120, 6120, 6147, 6147, 203, 212, 0, 5, 22, 127, 2000, 2, 9, 2490, 2508, 6, 6, 11, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 13, 5, 43, 43, 27, 27, 13, 13, 3, 5, 4, 17, 23, 5, 33, 4, 6, 6, 11, {88,79,70}, 0, 0, 1, 6, 7, 3, 3, 3 }, // Ewe/Latin/Togo
+ { 80, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 129, 10, 0, 6160, 6160, 6244, 6244, 6273, 6273, 206, 217, 0, 5, 22, 11, 2033, 4, 0, 2519, 2525, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 84, 84, 29, 29, 13, 13, 7, 9, 4, 17, 23, 4, 16, 5, 0, 6, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Ewondo/Latin/Cameroon
+ { 81, 66, 81, 0, 0, 380, 289, 6, 1, 0, 2, 3, 48, 5, 10, 14, 15, 16, 17, 404, 49, 10, 0, 6286, 6286, 6359, 6386, 6420, 6420, 0, 0, 328, 5, 22, 160, 2049, 4, 20, 2532, 2540, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 73, 73, 27, 34, 13, 13, 2, 2, 3, 17, 23, 2, 11, 5, 7, 8, 7, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Faroese/Latin/Faroe Islands
+ { 81, 66, 65, 0, 0, 380, 289, 6, 1, 0, 2, 3, 48, 5, 10, 14, 15, 16, 17, 404, 49, 10, 0, 6286, 6286, 6359, 6386, 6420, 6420, 0, 0, 328, 5, 22, 160, 2049, 4, 20, 2532, 1161, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 73, 73, 27, 34, 13, 13, 2, 2, 3, 17, 23, 3, 11, 5, 7, 8, 7, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Faroese/Latin/Denmark
+ { 83, 66, 185, 0, 0, 389, 398, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 6433, 6433, 6487, 6487, 6487, 6487, 0, 0, 0, 5, 22, 146, 2060, 2, 9, 2547, 826, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 54, 54, 27, 27, 27, 27, 2, 2, 5, 17, 23, 1, 17, 4, 6, 8, 9, {80,72,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Filipino/Latin/Philippines
+ { 84, 66, 83, 0, 0, 351, 351, 6, 1, 9, 2, 3, 48, 5, 10, 15, 15, 17, 17, 698, 885, 213, 213, 6514, 6580, 6660, 6660, 6680, 6680, 213, 226, 331, 336, 353, 22, 405, 4, 0, 2555, 2560, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 12, 4, 66, 80, 20, 20, 13, 13, 3, 3, 5, 17, 23, 1, 4, 5, 0, 5, 5, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Finnish/Latin/Finland
+ { 85, 66, 84, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2573, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/France
+ { 85, 66, 4, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 23, 38, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 209, 2077, 4, 20, 2565, 2579, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 15, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 7, {68,90,68}, 2, 1, 6, 5, 6, 1, 3, 3 }, // French/Latin/Algeria
+ { 85, 66, 23, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 79, 297, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2586, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 7, 26, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 8, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Belgium
+ { 85, 66, 25, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 2594, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Benin
+ { 85, 66, 37, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 2599, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 12, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Burkina Faso
+ { 85, 66, 38, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 182, 2108, 4, 20, 2565, 1522, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 3, 15, 5, 7, 8, 7, {66,73,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Burundi
+ { 85, 66, 40, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 216, 229, 376, 232, 249, 11, 2123, 4, 20, 2565, 1209, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 5, 4, 6, 17, 23, 4, 16, 5, 7, 8, 8, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Cameroon
+ { 85, 66, 41, 0, 0, 406, 406, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 15, 14, 113, 103, 323, 323, 6693, 6693, 6744, 6744, 6778, 6778, 168, 168, 376, 232, 249, 10, 2139, 4, 20, 2611, 1553, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 27, 9, 51, 51, 34, 34, 13, 13, 4, 4, 6, 17, 23, 1, 15, 5, 7, 17, 6, {67,65,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // French/Latin/Canada
+ { 85, 66, 46, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 11, 2123, 4, 20, 2565, 2628, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 16, 5, 7, 8, 25, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Central African Republic
+ { 85, 66, 48, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 23, 38, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 11, 2123, 4, 20, 2565, 2653, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 15, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 16, 5, 7, 8, 5, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Chad
+ { 85, 66, 55, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 12, 2154, 4, 20, 2565, 2658, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 7, {75,77,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Comoros
+ { 85, 66, 56, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 11, 2123, 4, 20, 2565, 2665, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 16, 5, 7, 8, 17, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Congo - Brazzaville
+ { 85, 66, 57, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 11, 2168, 4, 20, 2565, 2682, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 15, 5, 7, 8, 14, {67,68,70}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Congo - Kinshasa
+ { 85, 66, 67, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 23, 38, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 3, 2183, 4, 20, 2565, 2696, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 15, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 3, 16, 5, 7, 8, 8, {68,74,70}, 0, 0, 6, 6, 7, 1, 3, 3 }, // French/Latin/Djibouti
+ { 85, 66, 73, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 11, 2123, 4, 20, 2565, 2704, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 16, 5, 7, 8, 18, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Equatorial Guinea
+ { 85, 66, 85, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2722, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 16, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/French Guiana
+ { 85, 66, 86, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 211, 2199, 4, 20, 2565, 2738, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 9, 5, 7, 8, 19, {88,80,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/French Polynesia
+ { 85, 66, 88, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 11, 2123, 4, 20, 2565, 2757, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 16, 5, 7, 8, 5, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Gabon
+ { 85, 66, 97, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2762, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Guadeloupe
+ { 85, 66, 102, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 215, 2208, 4, 20, 2565, 2704, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 13, 5, 7, 8, 6, {71,78,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Guinea
+ { 85, 66, 104, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 15, 2221, 4, 20, 2565, 2772, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 16, 5, 7, 8, 5, {72,84,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Haiti
+ { 85, 66, 118, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 2777, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 13, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Ivory Coast
+ { 85, 66, 138, 0, 0, 406, 406, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2790, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Luxembourg
+ { 85, 66, 141, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 188, 2237, 4, 20, 2565, 1859, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 15, 5, 7, 8, 10, {77,71,65}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Madagascar
+ { 85, 66, 145, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 547, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 4, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Mali
+ { 85, 66, 148, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2800, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Martinique
+ { 85, 66, 149, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 23, 38, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 217, 2252, 4, 20, 2565, 2810, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 15, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 19, 5, 7, 8, 10, {77,82,85}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Mauritania
+ { 85, 66, 150, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 196, 2271, 4, 20, 2565, 2820, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 18, 5, 7, 8, 7, {77,85,82}, 2, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Mauritius
+ { 85, 66, 151, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2827, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Mayotte
+ { 85, 66, 155, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2834, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Monaco
+ { 85, 66, 159, 0, 0, 406, 406, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 168, 168, 376, 232, 249, 0, 2289, 4, 20, 2565, 2840, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 4, 4, 6, 17, 23, 0, 15, 5, 7, 8, 5, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Morocco
+ { 85, 66, 166, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 211, 2199, 4, 20, 2565, 2845, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 9, 5, 7, 8, 18, {88,80,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/New Caledonia
+ { 85, 66, 170, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 1975, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Niger
+ { 85, 66, 191, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2863, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Reunion
+ { 85, 66, 194, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 198, 2304, 4, 20, 2565, 2091, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 6, {82,87,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Rwanda
+ { 85, 66, 195, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2873, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 16, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Saint Barthelemy
+ { 85, 66, 199, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2889, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 12, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Saint Martin
+ { 85, 66, 200, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 22, 405, 4, 20, 2565, 2901, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 1, 4, 5, 7, 8, 24, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Saint Pierre and Miquelon
+ { 85, 66, 206, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 2925, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 7, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Senegal
+ { 85, 66, 208, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 203, 2318, 4, 20, 2565, 2157, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 21, 5, 7, 8, 10, {83,67,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // French/Latin/Seychelles
+ { 85, 66, 226, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 19, 20, 0, 49, 350, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 0, 2339, 4, 20, 2932, 2947, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 17, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 0, 12, 5, 7, 15, 6, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Switzerland
+ { 85, 66, 227, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 23, 38, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 219, 2351, 4, 20, 2565, 2953, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 15, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 5, {83,89,80}, 0, 0, 6, 5, 6, 1, 3, 3 }, // French/Latin/Syria
+ { 85, 66, 233, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 127, 2091, 4, 20, 2565, 2508, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 5, 17, 5, 7, 8, 4, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Togo
+ { 85, 66, 238, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 23, 38, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 221, 2365, 4, 20, 2565, 2958, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 15, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 7, {84,78,68}, 3, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Tunisia
+ { 85, 66, 252, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 23, 38, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 207, 2379, 4, 20, 2565, 2422, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 15, 7, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 2, 14, 5, 7, 8, 7, {86,85,86}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Vanuatu
+ { 85, 66, 256, 0, 0, 406, 406, 6, 1, 68, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 186, 10, 0, 6693, 6693, 6744, 6744, 6778, 6778, 0, 0, 376, 232, 249, 211, 2199, 4, 20, 2565, 2965, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 51, 51, 34, 34, 13, 13, 2, 2, 6, 17, 23, 4, 9, 5, 7, 8, 16, {88,80,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // French/Latin/Wallis and Futuna
+ { 86, 66, 117, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 14, 15, 893, 78, 10, 0, 6791, 6791, 6840, 6840, 6778, 6778, 5, 128, 0, 5, 22, 22, 405, 15, 0, 2981, 2987, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 49, 49, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Friulian/Latin/Italy
+ { 87, 66, 206, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 127, 2393, 4, 0, 2993, 2999, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 5, 19, 5, 0, 6, 8, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Senegal
+ { 87, 1, 37, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 10, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 223, 2412, 15, 0, 3007, 3017, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 13, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 6, 51, 5, 0, 10, 25, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Burkina Faso
+ { 87, 1, 40, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 10, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 229, 2463, 15, 0, 3007, 3042, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 13, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 8, 44, 5, 0, 10, 16, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Cameroon
+ { 87, 1, 89, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 61, 76, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 185, 2507, 15, 0, 3007, 3058, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 15, 7,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 1, 29, 5, 0, 10, 14, {71,77,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Gambia
+ { 87, 1, 92, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 61, 76, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 15, 2536, 15, 0, 3007, 3072, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 15, 7,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 3, 23, 5, 0, 10, 8, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Ghana
+ { 87, 1, 101, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 10, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 223, 2412, 15, 0, 3007, 3080, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 13, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 6, 51, 5, 0, 10, 23, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Guinea-Bissau
+ { 87, 1, 102, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 10, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 215, 2559, 15, 0, 3007, 3080, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 13, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 2, 25, 5, 0, 10, 8, {71,78,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Guinea
+ { 87, 1, 134, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 61, 76, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 10, 2584, 15, 0, 3007, 3103, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 15, 7,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 1, 31, 5, 0, 10, 18, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Liberia
+ { 87, 1, 149, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 61, 76, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 217, 2615, 15, 0, 3007, 3121, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 15, 7,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 2, 37, 5, 0, 10, 16, {77,82,85}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Mauritania
+ { 87, 1, 169, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 10, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 124, 2652, 15, 0, 3007, 3137, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 13, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 1, 33, 5, 0, 10, 18, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Nigeria
+ { 87, 1, 170, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 10, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 223, 2412, 15, 0, 3007, 3155, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 13, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 6, 51, 5, 0, 10, 12, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Niger
+ { 87, 1, 206, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 10, 0, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 223, 2412, 15, 0, 3007, 3167, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 13, 5,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 6, 51, 5, 0, 10, 16, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Senegal
+ { 87, 1, 209, 421, 421, 427, 436, 444, 0, 69, 2, 70, 4, 5, 72, 14, 15, 16, 17, 920, 283, 61, 76, 6965, 6965, 7083, 7083, 7135, 7135, 227, 240, 382, 394, 22, 18, 2685, 15, 0, 3007, 3183, 6, 6, 9, 8, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 17, 8, 15, 7,118,118, 52, 52, 22, 22, 4, 4, 12, 27, 23, 2, 33, 5, 0, 10, 14, {83,76,69}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Adlam/Sierra Leone
+ { 87, 66, 37, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 127, 2393, 4, 0, 2993, 3197, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 5, 19, 5, 0, 6, 14, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Burkina Faso
+ { 87, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 11, 2718, 4, 0, 2993, 3211, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 4, 18, 5, 0, 6, 8, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Cameroon
+ { 87, 66, 89, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 23, 38, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 185, 2736, 4, 0, 2993, 3219, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 15, 7, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 1, 13, 5, 0, 6, 6, {71,77,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Gambia
+ { 87, 66, 92, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 23, 38, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 15, 0, 4, 0, 2993, 3225, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 15, 7, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 3, 0, 5, 0, 6, 5, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Ghana
+ { 87, 66, 101, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 127, 2393, 4, 0, 2993, 3230, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 5, 19, 5, 0, 6, 12, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Guinea-Bissau
+ { 87, 66, 102, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 215, 0, 4, 0, 2993, 3230, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 2, 0, 5, 0, 6, 4, {71,78,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Guinea
+ { 87, 66, 134, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 23, 38, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 10, 2749, 4, 0, 2993, 3242, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 15, 7, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 1, 16, 5, 0, 6, 9, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Liberia
+ { 87, 66, 149, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 23, 38, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 217, 2765, 4, 0, 2993, 3251, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 15, 7, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 2, 15, 5, 0, 6, 8, {77,82,85}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Mauritania
+ { 87, 66, 169, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 124, 2780, 4, 0, 2993, 3259, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 1, 16, 5, 0, 6, 9, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Nigeria
+ { 87, 66, 170, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 10, 0, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 127, 2393, 4, 0, 2993, 3268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 5, 19, 5, 0, 6, 6, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Niger
+ { 87, 66, 209, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 18, 17, 113, 129, 23, 38, 6867, 6867, 6925, 6925, 6952, 6952, 221, 233, 0, 5, 22, 18, 2796, 4, 0, 2993, 3274, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 15, 7, 58, 58, 27, 27, 13, 13, 6, 7, 4, 17, 23, 2, 18, 5, 0, 6, 11, {83,76,69}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Fulah/Latin/Sierra Leone
+ { 88, 66, 246, 0, 0, 445, 445, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 937, 186, 10, 0, 7157, 7157, 7225, 7225, 7252, 7252, 3, 135, 421, 5, 22, 94, 2814, 2, 9, 3285, 3293, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 10, 13, 5, 68, 68, 27, 27, 13, 13, 1, 1, 6, 17, 23, 1, 15, 4, 6, 8, 22, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Gaelic/Latin/United Kingdom
+ { 89, 66, 92, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38, 7265, 7265, 7297, 7297, 7323, 7323, 0, 0, 0, 5, 22, 15, 50, 2, 9, 3315, 1718, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 32, 32, 26, 26, 13, 13, 2, 2, 4, 17, 23, 3, 10, 4, 6, 2, 5, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ga/Latin/Ghana
+ { 90, 66, 220, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 78, 10, 0, 7336, 7336, 7384, 7384, 1185, 7418, 168, 168, 0, 5, 22, 22, 405, 4, 0, 3317, 455, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 48, 48, 34, 34, 13, 20, 4, 4, 5, 17, 23, 1, 4, 5, 0, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Galician/Latin/Spain
+ { 91, 66, 243, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 7438, 7438, 7503, 7503, 7530, 7530, 0, 0, 0, 5, 22, 147, 2829, 0, 0, 3323, 3330, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 65, 65, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 19, 4, 0, 7, 7, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Ganda/Latin/Uganda
+ { 92, 33, 77, 0, 0, 0, 0, 6, 0, 74, 2, 3, 4, 5, 10, 14, 15, 16, 17, 985, 78, 61, 76, 7543, 7543, 7543, 7543, 7571, 7571, 0, 0, 0, 5, 22, 0, 105, 15, 0, 3337, 143, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 15, 7, 28, 28, 28, 28, 13, 13, 2, 2, 4, 17, 23, 0, 9, 5, 0, 4, 5, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Geez/Ethiopic/Ethiopia
+ { 92, 33, 74, 0, 0, 0, 0, 6, 0, 74, 2, 3, 4, 5, 10, 14, 15, 16, 17, 985, 78, 61, 76, 7543, 7543, 7543, 7543, 7571, 7571, 0, 0, 0, 5, 22, 6, 0, 15, 0, 3337, 671, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 15, 7, 28, 28, 28, 28, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 4, 4, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Geez/Ethiopic/Eritrea
+ { 93, 35, 90, 0, 0, 455, 455, 6, 1, 9, 2, 3, 4, 5, 10, 13, 14, 11, 12, 1008, 49, 10, 0, 7584, 7584, 7645, 7645, 7672, 7672, 0, 0, 427, 432, 22, 0, 2848, 4, 0, 3341, 3348, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 13, 5, 61, 61, 27, 27, 13, 13, 2, 2, 5, 29, 23, 1, 12, 5, 0, 7, 10, {71,69,76}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Georgian/Georgian/Georgia
+ { 94, 66, 91, 0, 0, 463, 463, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 10, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 22, 83, 4, 0, 3358, 3365, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 11, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // German/Latin/Germany
+ { 94, 66, 16, 0, 0, 463, 463, 6, 1, 9, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 10, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 22, 83, 15, 0, 3376, 3376, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 24, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // German/Latin/Austria
+ { 94, 66, 23, 0, 0, 463, 463, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 10, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 22, 83, 4, 0, 3358, 3400, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // German/Latin/Belgium
+ { 94, 66, 117, 0, 0, 463, 463, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 10, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 22, 83, 4, 0, 3358, 3407, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // German/Latin/Italy
+ { 94, 66, 136, 0, 0, 463, 463, 6, 0, 17, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 10, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 0, 2860, 15, 0, 3358, 3414, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 0, 17, 5, 0, 7, 13, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // German/Latin/Liechtenstein
+ { 94, 66, 138, 0, 0, 463, 463, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 10, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 22, 83, 4, 0, 3358, 3427, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 7, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // German/Latin/Luxembourg
+ { 94, 66, 226, 0, 0, 463, 463, 6, 0, 17, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 10, 0, 7685, 7685, 7744, 7764, 4510, 4510, 0, 0, 461, 5, 22, 0, 2860, 15, 65, 3436, 3436, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 59, 59, 20, 27, 13, 13, 2, 2, 5, 17, 23, 0, 17, 5, 5, 21, 7, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // German/Latin/Switzerland
+ { 96, 39, 94, 0, 0, 472, 472, 6, 1, 0, 2, 3, 4, 5, 6, 11, 12, 14, 15, 113, 129, 23, 38, 7791, 7791, 7845, 7845, 7872, 7872, 231, 244, 0, 5, 22, 22, 2877, 4, 0, 3457, 3465, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 15, 7, 54, 54, 27, 27, 13, 13, 4, 4, 4, 17, 23, 1, 4, 5, 0, 8, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Greek/Greek/Greece
+ { 96, 39, 63, 0, 0, 472, 472, 6, 1, 0, 2, 3, 4, 5, 6, 11, 12, 14, 15, 113, 129, 23, 38, 7791, 7791, 7845, 7845, 7872, 7872, 231, 244, 0, 5, 22, 22, 2877, 4, 0, 3457, 3471, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 15, 7, 54, 54, 27, 27, 13, 13, 4, 4, 4, 17, 23, 1, 4, 5, 0, 8, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Greek/Greek/Cyprus
+ { 97, 66, 183, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 7885, 7885, 7885, 7885, 83, 83, 0, 0, 0, 5, 22, 237, 0, 15, 0, 3477, 3484, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 53, 53, 53, 53, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 7, 8, {80,89,71}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Guarani/Latin/Paraguay
+ { 98, 40, 110, 0, 0, 481, 481, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 367, 383, 7938, 7938, 7990, 7990, 8021, 8021, 0, 0, 466, 5, 22, 120, 2881, 2, 9, 3492, 3499, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 16, 8, 52, 52, 31, 31, 18, 18, 2, 2, 4, 17, 23, 1, 13, 4, 6, 7, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Gujarati/Gujarati/India
+ { 99, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 8039, 8039, 8100, 8100, 8127, 8127, 235, 248, 0, 5, 22, 176, 991, 2, 9, 3503, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 61, 61, 27, 27, 13, 13, 6, 3, 4, 17, 23, 3, 17, 4, 6, 8, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Gusii/Latin/Kenya
+ { 101, 66, 169, 0, 0, 490, 499, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 804, 129, 10, 0, 8140, 8140, 8191, 8191, 8218, 8218, 241, 251, 0, 470, 511, 124, 2894, 15, 0, 3511, 3259, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 13, 5, 51, 51, 27, 27, 13, 13, 6, 5, 5, 41, 47, 1, 15, 5, 0, 5, 8, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Hausa/Latin/Nigeria
+ { 101, 4, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 8231, 8231, 8287, 8287, 83, 83, 0, 0, 0, 5, 22, 124, 2909, 15, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 30, 30, 13, 13, 2, 2, 4, 17, 23, 1, 6, 5, 0, 0, 0, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Hausa/Arabic/Nigeria
+ { 101, 4, 222, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 8231, 8231, 8287, 8287, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 56, 56, 30, 30, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 0, 0, {83,68,71}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Hausa/Arabic/Sudan
+ { 101, 66, 92, 0, 0, 490, 499, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 804, 129, 23, 38, 8140, 8140, 8191, 8191, 8218, 8218, 241, 251, 0, 470, 511, 15, 2915, 15, 0, 3511, 3225, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 51, 51, 27, 27, 13, 13, 6, 5, 5, 41, 47, 3, 13, 5, 0, 5, 4, {71,72,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Hausa/Latin/Ghana
+ { 101, 66, 170, 0, 0, 490, 499, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 804, 129, 10, 0, 8140, 8140, 8191, 8191, 8218, 8218, 241, 251, 0, 470, 511, 127, 2928, 15, 0, 3511, 3516, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 13, 5, 51, 51, 27, 27, 13, 13, 6, 5, 5, 41, 47, 5, 29, 5, 0, 5, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Hausa/Latin/Niger
+ { 102, 66, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 23, 38, 8317, 8317, 8373, 8373, 83, 83, 0, 0, 0, 5, 22, 10, 0, 2, 9, 3521, 3535, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 56, 56, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 6, 14, 19, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Hawaiian/Latin/United States
+ { 103, 47, 116, 0, 0, 507, 507, 6, 0, 1, 2, 3, 35, 37, 10, 15, 15, 17, 17, 1027, 885, 11, 1, 8393, 8393, 8457, 8457, 8502, 8502, 247, 256, 558, 5, 22, 48, 2957, 70, 77, 3554, 3559, 6, 6, 6, 6, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 18, 8, 12, 4, 64, 64, 45, 45, 20, 20, 6, 5, 4, 17, 23, 1, 7, 7, 9, 5, 5, {73,76,83}, 2, 1, 7, 5, 6, 1, 3, 3 }, // Hebrew/Hebrew/Israel
+ { 105, 29, 110, 0, 0, 513, 522, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 61, 76, 8522, 8522, 8574, 8574, 8605, 8605, 82, 203, 562, 5, 22, 120, 2964, 2, 0, 3564, 664, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 52, 52, 31, 31, 18, 18, 2, 2, 4, 17, 23, 1, 12, 4, 0, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Hindi/Devanagari/India
+ { 105, 66, 110, 0, 0, 530, 540, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 804, 186, 23, 38, 8623, 8623, 8689, 8689, 8727, 8727, 0, 0, 0, 5, 22, 120, 1381, 2, 0, 3570, 1478, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 66, 66, 38, 38, 21, 21, 2, 2, 5, 17, 23, 1, 12, 4, 0, 13, 5, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Hindi/Latin/India
+ { 107, 66, 108, 0, 0, 549, 549, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 12, 11, 1045, 1064, 11, 1, 8748, 8748, 8799, 8799, 8817, 8817, 253, 261, 566, 5, 22, 238, 2976, 4, 0, 3583, 3589, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 13, 12, 4, 51, 51, 18, 18, 16, 16, 3, 3, 4, 17, 23, 2, 13, 5, 0, 6, 12, {72,85,70}, 2, 0, 1, 6, 7, 2, 3, 3 }, // Hungarian/Latin/Hungary
+ { 108, 66, 109, 0, 0, 289, 289, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 885, 10, 0, 8833, 8833, 8913, 8913, 8947, 8947, 256, 264, 570, 5, 22, 160, 2989, 4, 0, 3601, 3609, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 80, 80, 34, 34, 13, 13, 4, 4, 4, 17, 23, 3, 13, 5, 0, 8, 6, {73,83,75}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Icelandic/Latin/Iceland
+ { 109, 66, 258, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 3615, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 3, 0, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ido/Latin/world
+ { 110, 66, 169, 0, 0, 557, 566, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 10, 0, 8960, 8960, 9013, 9013, 83, 83, 260, 268, 0, 5, 22, 124, 3002, 2, 9, 3618, 3622, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 13, 5, 53, 53, 28, 28, 13, 13, 7, 7, 4, 17, 23, 1, 5, 4, 6, 4, 8, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Igbo/Latin/Nigeria
+ { 111, 66, 83, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1077, 885, 213, 213, 9041, 9110, 9182, 9182, 83, 9209, 267, 275, 0, 5, 22, 22, 405, 4, 0, 3630, 3641, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 12, 4, 69, 72, 27, 27, 13, 13, 3, 3, 4, 17, 23, 1, 4, 5, 0, 11, 5, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Inari Sami/Latin/Finland
+ { 112, 66, 111, 0, 0, 574, 584, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 786, 78, 212, 212, 9222, 9222, 9264, 9264, 9291, 9291, 0, 0, 0, 5, 22, 186, 3007, 2, 0, 1776, 1776, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 42, 42, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 16, 4, 0, 9, 9, {73,68,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Indonesian/Latin/Indonesia
+ { 114, 66, 258, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 16, 17, 14, 15, 1095, 394, 10, 0, 9304, 9304, 9360, 9360, 9387, 9387, 0, 0, 0, 5, 22, 0, 0, 15, 58, 3646, 3657, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 26, 10, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 5, 17, 23, 0, 0, 5, 7, 11, 5, {0,0,0}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Interlingua/Latin/world
+ { 115, 66, 75, 0, 0, 0, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 180, 10, 0, 9400, 9400, 9451, 9451, 9485, 9485, 270, 278, 574, 232, 249, 22, 405, 15, 86, 3662, 3673, 6, 6, 6, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 13, 5, 51, 51, 34, 34, 13, 13, 9, 8, 7, 17, 23, 1, 4, 5, 6, 11, 7, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Interlingue/Latin/Estonia
+ { 116, 18, 41, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 1121, 61, 76, 9498, 9498, 9498, 9498, 83, 83, 0, 0, 0, 5, 22, 240, 0, 15, 0, 3680, 3686, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 15, 7, 54, 54, 54, 54, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 6, 4, {67,65,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Inuktitut/Canadian Aboriginal/Canada
+ { 116, 66, 41, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 240, 0, 15, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 0, 0, {67,65,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Inuktitut/Latin/Canada
+ { 118, 66, 114, 0, 0, 445, 445, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 186, 10, 0, 9552, 9552, 9626, 9626, 9662, 9662, 279, 286, 581, 5, 22, 22, 83, 2, 9, 3690, 3697, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 74, 74, 36, 36, 13, 13, 4, 4, 6, 17, 23, 1, 4, 4, 6, 7, 4, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Irish/Latin/Ireland
+ { 118, 66, 246, 0, 0, 445, 445, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 186, 10, 0, 9552, 9552, 9626, 9626, 9662, 9662, 279, 286, 581, 5, 22, 94, 3023, 2, 9, 3690, 3701, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 74, 74, 36, 36, 13, 13, 4, 4, 6, 17, 23, 1, 14, 4, 6, 7, 19, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Irish/Latin/United Kingdom
+ { 119, 66, 117, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 78, 10, 0, 9675, 9675, 9731, 9731, 4694, 4694, 0, 0, 0, 5, 22, 22, 405, 4, 0, 3720, 3728, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 8, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Italian/Latin/Italy
+ { 119, 66, 203, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 78, 10, 0, 9675, 9675, 9731, 9731, 4694, 4694, 0, 0, 0, 5, 22, 22, 405, 4, 0, 3720, 3734, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 8, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Italian/Latin/San Marino
+ { 119, 66, 226, 0, 0, 414, 414, 6, 0, 17, 2, 3, 4, 5, 10, 11, 12, 19, 20, 0, 49, 10, 0, 9675, 9675, 9731, 9731, 4694, 4694, 0, 0, 0, 5, 22, 0, 3037, 15, 65, 3720, 3744, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 15, 5, 5, 8, 8, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Italian/Latin/Switzerland
+ { 119, 66, 253, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 78, 10, 0, 9675, 9675, 9731, 9731, 4694, 4694, 0, 0, 0, 5, 22, 22, 405, 4, 0, 3720, 3752, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 8, 18, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Italian/Latin/Vatican City
+ { 120, 53, 120, 183, 183, 183, 183, 6, 0, 1, 2, 3, 4, 5, 10, 51, 52, 53, 54, 513, 821, 391, 1, 9758, 9758, 9785, 9785, 9785, 9785, 283, 290, 587, 590, 22, 145, 3052, 2, 9, 3770, 3770, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 10, 13, 4, 27, 27, 13, 13, 13, 13, 2, 2, 3, 17, 23, 1, 3, 4, 6, 3, 2, {74,80,89}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Japanese/Japanese/Japan
+ { 121, 66, 111, 0, 0, 593, 603, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 394, 10, 0, 9798, 9798, 9838, 9838, 9866, 9866, 285, 292, 607, 5, 22, 186, 3007, 15, 0, 3773, 3777, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 40, 40, 28, 28, 13, 13, 4, 5, 4, 17, 23, 2, 16, 5, 0, 4, 9, {73,68,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Javanese/Latin/Indonesia
+ { 122, 66, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 137, 155, 10, 0, 9879, 9879, 9922, 9922, 83, 83, 0, 0, 0, 5, 22, 124, 3055, 15, 0, 3786, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 43, 43, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 7, 5, 0, 4, 0, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Jju/Latin/Nigeria
+ { 123, 66, 206, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 129, 10, 0, 9949, 9949, 9998, 9998,10025,10025, 0, 0, 0, 5, 22, 127, 3062, 4, 0, 3790, 3795, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 49, 49, 27, 27, 13, 13, 2, 2, 4, 17, 23, 5, 16, 5, 0, 5, 7, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Jola-Fonyi/Latin/Senegal
+ { 124, 66, 43, 0, 0, 143, 143, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1131, 186, 10, 0,10038,10038,10110,10110,10137,10137, 82, 203, 0, 5, 22, 243, 3078, 4, 20, 3802, 3814, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 10, 13, 5, 72, 72, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 18, 5, 7, 12, 10, {67,86,69}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Kabuverdianu/Latin/Cape Verde
+ { 125, 66, 4, 0, 0, 612, 620, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 129, 23, 38,10150,10183,10233,10260,10289,10302, 289, 297, 611, 618, 22, 209, 3096, 0, 0, 3824, 3833, 6, 6, 8, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 15, 7, 33, 50, 27, 29, 13, 13, 7, 9, 7, 21, 23, 2, 14, 4, 0, 9, 8, {68,90,68}, 2, 1, 6, 5, 6, 1, 3, 3 }, // Kabyle/Latin/Algeria
+ { 126, 66, 40, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 19, 20, 86, 1158, 10, 0,10315,10315,10315,10315,10368,10368, 0, 0, 0, 5, 22, 11, 3110, 15, 0, 3841, 3845, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 53, 53, 53, 53, 20, 20, 2, 2, 4, 17, 23, 4, 9, 5, 0, 4, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Kako/Latin/Cameroon
+ { 127, 66, 95, 0, 0, 627, 627, 6, 1, 0, 2, 3, 48, 5, 63, 12, 11, 20, 19, 86, 103, 212, 212,10388,10388,10485,10485,10512,10512, 0, 0, 0, 5, 22, 160, 3119, 2, 92, 3852, 3863, 6, 6, 11, 11, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 17, 10, 13, 5, 97, 97, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 19, 4, 5, 11, 16, {68,75,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Kalaallisut/Latin/Greenland
+ { 128, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,10525,10525,10577,10577,10604,10604, 296, 306, 0, 5, 22, 176, 3138, 2, 9, 3879, 3887, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 52, 52, 27, 27, 13, 13, 6, 10, 4, 17, 23, 3, 19, 4, 6, 8, 12, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Kalenjin/Latin/Kenya
+ { 129, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,10617,10617,10690,10690,10717,10717, 302, 316, 0, 5, 22, 176, 3157, 2, 9, 3899, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 73, 73, 27, 27, 13, 13, 9, 7, 4, 17, 23, 3, 16, 4, 6, 7, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Kamba/Latin/Kenya
+ { 130, 56, 110, 0, 0, 638, 650, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 129, 367, 383,10730,10730,10783,10783,10815,10815, 311, 323, 639, 647, 22, 120, 3173, 2, 9, 3906, 3911, 6, 6, 12, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 16, 8, 53, 53, 32, 32, 19, 19, 9, 7, 8, 35, 23, 1, 13, 4, 6, 5, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Kannada/Kannada/India
+ { 132, 4, 110, 661, 661, 667, 677, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 549, 567, 61, 76,10834,10834,10885,10885,10934,10934, 320, 330, 0, 5, 22, 120, 3186, 2, 0, 3915, 3920, 6, 6, 10, 9, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 18, 6, 15, 7, 51, 51, 49, 49, 13, 13, 6, 6, 4, 17, 23, 1, 16, 4, 0, 5, 9, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Kashmiri/Arabic/India
+ { 132, 29, 110, 0, 0, 686, 695, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 127, 127,10947,10996,10947,11045,11092,11092, 326, 336, 0, 5, 22, 120, 3202, 15, 0, 3929, 3934, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 49, 49, 49, 47, 13, 13, 5, 5, 4, 17, 23, 1, 11, 5, 0, 5, 10, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Kashmiri/Devanagari/India
+ { 133, 27, 123, 0, 0, 0, 703, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 1168, 49, 10, 0,11105,11105,11160,11160,11180,11180, 0, 0, 196, 682, 699, 244, 3213, 4, 0, 3944, 3954, 6, 6, 6, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 8, 13, 5, 55, 55, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 17, 5, 0, 10, 9, {75,90,84}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Kazakh/Cyrillic/Kazakhstan
+ { 134, 66, 40, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 11, 0, 15, 0, 3963, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 4, 0, 5, 0, 6, 0, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Kenyang/Latin/Cameroon
+ { 135, 60, 39, 0, 0, 713, 722, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 61, 76,11193,11238,11284,11284,11323,11323, 0, 0, 722, 5, 22, 245, 3230, 0, 45, 3969, 3974, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 15, 7, 45, 46, 39, 39, 13, 13, 2, 2, 2, 17, 23, 1, 11, 4, 6, 5, 7, {75,72,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Khmer/Khmer/Cambodia
+ { 136, 66, 99, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 246, 0, 15, 0, 3981, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 7, 0, {71,84,81}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Kiche/Latin/Guatemala
+ { 137, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,11336,11336,11398,11398,11425,11425, 331, 341, 0, 5, 22, 176, 3241, 2, 9, 3988, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 62, 62, 27, 27, 13, 13, 6, 8, 4, 17, 23, 3, 16, 4, 6, 6, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Kikuyu/Latin/Kenya
+ { 138, 66, 194, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 16, 17, 163, 103, 10, 0,11438,11438,11521,11521, 83, 83, 0, 0, 0, 5, 22, 198, 0, 15, 0, 3994, 4005, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 83, 83, 34, 34, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 11, 8, {82,87,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Kinyarwanda/Latin/Rwanda
+ { 141, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 283, 61, 76,11555,11555,11555,11555,11605,11623, 337, 349, 724, 5, 22, 120, 2964, 2, 9, 4013, 664, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 15, 7, 50, 50, 50, 50, 18, 19, 4, 4, 4, 17, 23, 1, 12, 4, 6, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Konkani/Devanagari/India
+ { 142, 63, 218, 0, 0, 731, 731, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1190, 1208, 404, 127,11642,11642,11669,11669,11669,11669, 341, 353, 728, 5, 22, 247, 3257, 2, 9, 4019, 4022, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 9, 16, 7, 27, 27, 13, 13, 13, 13, 2, 2, 3, 17, 23, 1, 6, 4, 6, 3, 4, {75,82,87}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Korean/Korean/South Korea
+ { 142, 63, 50, 0, 0, 731, 731, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1190, 1208, 169, 0,11642,11642,11669,11669,11669,11669, 341, 353, 728, 5, 22, 248, 3263, 2, 9, 4019, 4026, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 9, 13, 5, 27, 27, 13, 13, 13, 13, 2, 2, 3, 17, 23, 3, 6, 4, 6, 3, 2, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Korean/Korean/China
+ { 142, 63, 174, 0, 0, 731, 731, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1190, 1208, 404, 127,11642,11642,11669,11669,11669,11669, 341, 353, 728, 5, 22, 247, 3269, 2, 9, 4019, 4028, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 9, 16, 7, 27, 27, 13, 13, 13, 13, 2, 2, 3, 17, 23, 1, 16, 4, 6, 3, 11, {75,80,87}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Korean/Korean/North Korea
+ { 144, 66, 145, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0,11682,11682,11735,11735,11762,11762, 343, 355, 0, 5, 22, 127, 3285, 0, 0, 4039, 4054, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 53, 53, 27, 27, 13, 13, 6, 6, 4, 17, 23, 5, 16, 4, 0, 15, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Koyraboro Senni/Latin/Mali
+ { 145, 66, 145, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0,11775,11775,11827,11827,11762,11762, 343, 355, 0, 5, 22, 127, 3285, 0, 0, 4059, 4054, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 52, 52, 27, 27, 13, 13, 6, 6, 4, 17, 23, 5, 16, 4, 0, 11, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Koyra Chiini/Latin/Mali
+ { 146, 66, 134, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 23, 38, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 0, 15, 0, 4070, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 6, 0, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Kpelle/Latin/Liberia
+ { 146, 66, 102, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 215, 0, 15, 0, 4070, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 6, 0, {71,78,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Kpelle/Latin/Guinea
+ { 148, 66, 239, 0, 0, 738, 738, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1217, 49, 10, 0,11854,11854,11896,11896,11923,11923, 349, 361, 0, 5, 22, 126, 3301, 4, 20, 4076, 4092, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 10, 13, 5, 42, 42, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 12, 5, 7, 16, 7, {84,82,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Kurdish/Latin/Turkey
+ { 149, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 11, 12, 113, 129, 10, 0,11936,11936,12024,12024,12053,12053, 351, 363, 0, 5, 22, 11, 3313, 4, 0, 4099, 4105, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 88, 88, 29, 29, 13, 13, 4, 4, 4, 17, 23, 4, 13, 5, 0, 6, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Kwasio/Latin/Cameroon
+ { 150, 27, 128, 0, 0, 745, 745, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 1244, 129, 10, 0,12066,12066,12122,12122,12159,12159, 355, 367, 196, 731, 22, 251, 3326, 4, 0, 4112, 4120, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 6, 13, 5, 56, 56, 37, 37, 13, 13, 5, 14, 4, 18, 23, 3, 15, 5, 0, 8, 10, {75,71,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Kyrgyz/Cyrillic/Kyrgyzstan
+ { 151, 66, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38,12172,12172,12172,12172, 83,12258, 0, 0, 0, 5, 22, 10, 0, 15, 0, 4130, 4142, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 86, 86, 86, 86, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 12, 22, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Lakota/Latin/United States
+ { 152, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 15, 15, 17, 17, 0, 186, 10, 0,12271,12271,12333,12333,12368,12368, 360, 381, 0, 5, 22, 121, 3341, 15, 0, 4164, 4172, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 62, 62, 35, 35, 13, 13, 3, 3, 4, 17, 23, 3, 22, 5, 0, 8, 9, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Langi/Latin/Tanzania
+ { 153, 65, 129, 0, 0, 0, 755, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1267, 129, 420, 1,12381,12381,12437,12437,12472,12472, 363, 384, 0, 5, 22, 254, 3363, 2, 65, 4181, 4181, 6, 6, 6, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 27, 4, 56, 56, 35, 35, 16, 16, 8, 8, 4, 17, 23, 1, 7, 4, 5, 3, 3, {76,65,75}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Lao/Lao/Laos
+ { 154, 66, 253, 0, 0, 406, 406, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1286, 1309, 10, 0,12488,12488,12572,12572, 83, 83, 0, 0, 0, 5, 22, 22, 83, 15, 0, 4184, 4190, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 13, 5, 84, 84, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 6, 16, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Latin/Latin/Vatican City
+ { 155, 66, 131, 0, 0, 267, 267, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1317, 49, 10, 0,12599,12670,12741,12791,12841,12841, 371, 392, 749, 5, 22, 22, 3370, 4, 0, 4206, 4214, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 26, 8, 13, 5, 71, 71, 50, 50, 13, 13, 14, 11, 5, 17, 23, 1, 4, 5, 0, 8, 7, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Latvian/Latin/Latvia
+ { 158, 66, 57, 0, 0, 764, 764, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0,12854,12854,12953,12953,12980,12980, 385, 403, 0, 5, 22, 11, 3374, 4, 0, 4221, 4228, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 99, 99, 27, 27, 13, 13, 8, 6, 4, 17, 23, 2, 16, 5, 0, 7, 30, {67,68,70}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Lingala/Latin/Congo - Kinshasa
+ { 158, 66, 7, 0, 0, 764, 764, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0,12854,12854,12953,12953,12980,12980, 385, 403, 0, 5, 22, 255, 3390, 4, 0, 4221, 4258, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 99, 99, 27, 27, 13, 13, 8, 6, 4, 17, 23, 2, 16, 5, 0, 7, 6, {65,79,65}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Lingala/Latin/Angola
+ { 158, 66, 46, 0, 0, 764, 764, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0,12854,12854,12953,12953,12980,12980, 385, 403, 0, 5, 22, 11, 3406, 4, 0, 4221, 4264, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 99, 99, 27, 27, 13, 13, 8, 6, 4, 17, 23, 4, 16, 5, 0, 7, 26, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Lingala/Latin/Central African Republic
+ { 158, 66, 56, 0, 0, 764, 764, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0,12854,12854,12953,12953,12980,12980, 385, 403, 0, 5, 22, 11, 3406, 4, 0, 4221, 4290, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 99, 99, 27, 27, 13, 13, 8, 6, 4, 17, 23, 4, 16, 5, 0, 7, 5, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Lingala/Latin/Congo - Brazzaville
+ { 160, 66, 137, 0, 0, 773, 773, 6, 1, 9, 2, 3, 48, 5, 63, 13, 14, 13, 14, 1343, 103, 10, 0,12993,12993,13081,13081,13101,13101, 393, 409, 754, 5, 22, 22, 3422, 4, 0, 4295, 4303, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 27, 10, 13, 5, 88, 88, 20, 20, 13, 13, 9, 6, 6, 17, 23, 1, 5, 5, 0, 8, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Lithuanian/Latin/Lithuania
+ { 161, 66, 258, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 4310, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 11, 0, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Lojban/Latin/world
+ { 162, 66, 91, 0, 0, 781, 781, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 180, 11, 1,13114,13114,13166,13166,13193,13193, 402, 415, 0, 5, 22, 22, 405, 4, 0, 4321, 4335, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 4, 52, 52, 27, 27, 13, 13, 9, 10, 4, 17, 23, 1, 4, 5, 0, 14, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Lower Sorbian/Latin/Germany
+ { 163, 66, 91, 0, 0, 267, 267, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 1370, 50, 447, 469,13206,13206,13270,13270, 4510, 4510, 0, 0, 0, 5, 22, 22, 83, 4, 0, 4341, 4355, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 7, 22, 10, 64, 64, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 14, 11, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Low German/Latin/Germany
+ { 163, 66, 165, 0, 0, 267, 267, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 1370, 50, 447, 469,13206,13206,13270,13270, 4510, 4510, 0, 0, 0, 5, 22, 22, 83, 4, 0, 4341, 4366, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 7, 22, 10, 64, 64, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 14, 12, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Low German/Latin/Netherlands
+ { 164, 66, 57, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0,13297,13297,13346,13346,13373,13373, 411, 425, 0, 5, 22, 11, 3427, 0, 0, 4378, 4386, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 49, 49, 27, 27, 13, 13, 5, 6, 4, 17, 23, 2, 17, 4, 0, 8, 16, {67,68,70}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Luba-Katanga/Latin/Congo - Kinshasa
+ { 165, 66, 225, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 160, 0, 15, 0, 4402, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 15, 0, {83,69,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Lule Sami/Latin/Sweden
+ { 165, 66, 175, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 160, 0, 15, 0, 4402, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 15, 0, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Lule Sami/Latin/Norway
+ { 166, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,13386,13386,13454,13454,13481,13481, 416, 431, 0, 5, 22, 176, 3444, 0, 0, 4417, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 68, 68, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 16, 4, 0, 6, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Luo/Latin/Kenya
+ { 167, 66, 138, 0, 0, 788, 788, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 49, 10, 0,13494,13494,13558,13585, 4510, 4510, 418, 433, 461, 5, 22, 22, 83, 4, 0, 4423, 4423, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 64, 64, 27, 34, 13, 13, 5, 8, 5, 17, 23, 1, 4, 5, 0, 14, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Luxembourgish/Latin/Luxembourg
+ { 168, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 13, 14, 18, 16, 0, 186, 10, 0,13619,13619,13693,13693, 83, 83, 168, 168, 0, 5, 22, 176, 3460, 2, 97, 4437, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 74, 74, 20, 20, 13, 13, 4, 4, 4, 17, 23, 3, 16, 4, 6, 7, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Luyia/Latin/Kenya
+ { 169, 27, 140, 0, 0, 150, 150, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 0, 180, 10, 0,13713,13713,13766,13766, 3069, 3069, 423, 441, 760, 5, 22, 257, 3476, 4, 0, 4444, 4454, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 13, 5, 53, 53, 34, 34, 13, 13, 7, 5, 5, 17, 23, 4, 16, 5, 0, 10, 18, {77,75,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Macedonian/Cyrillic/Macedonia
+ { 170, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,13800,13800,13861,13861, 1284, 1284, 430, 446, 0, 5, 22, 121, 3492, 2, 0, 4472, 2268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 61, 61, 27, 27, 13, 13, 5, 9, 4, 17, 23, 3, 20, 4, 0, 9, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Machame/Latin/Tanzania
+ { 171, 29, 110, 0, 0, 513, 522, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 61, 76,13888,13888, 8574, 8574, 8605, 8605, 88, 83, 0, 5, 22, 120, 2964, 15, 0, 4481, 664, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 63, 63, 31, 31, 18, 18, 3, 4, 4, 17, 23, 1, 12, 5, 0, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Maithili/Devanagari/India
+ { 172, 66, 160, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,13951,13951,14009,14009,14036,14036, 435, 455, 0, 5, 22, 261, 0, 15, 0, 4487, 4492, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 58, 58, 27, 27, 13, 13, 8, 10, 4, 17, 23, 3, 0, 5, 0, 5, 10, {77,90,78}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Makhuwa-Meetto/Latin/Mozambique
+ { 173, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,14049,14049,14181,14181,14208,14208, 443, 465, 0, 5, 22, 121, 3492, 2, 9, 4502, 2268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5,132,132, 27, 27, 13, 13, 4, 5, 4, 17, 23, 3, 20, 4, 6, 10, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Makonde/Latin/Tanzania
+ { 174, 66, 141, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 103, 10, 0,14221,14221,14280,14280,14313,14313, 0, 0, 0, 5, 22, 188, 1515, 2, 0, 4512, 4520, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 59, 59, 33, 33, 13, 13, 2, 2, 4, 17, 23, 2, 6, 4, 0, 8, 12, {77,71,65}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Malagasy/Latin/Madagascar
+ { 175, 74, 110, 0, 0, 798, 811, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1393, 129, 61, 76,14326,14402,14477,14477,14517,14538, 0, 0, 765, 771, 22, 120, 3512, 2, 9, 4532, 4538, 6, 6, 13, 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 76, 75, 40, 40, 21, 20, 2, 2, 6, 27, 23, 1, 11, 4, 6, 6, 6, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Malayalam/Malayalam/India
+ { 176, 66, 143, 0, 0, 584, 584, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 79, 23, 38,14558,14558,14600,14600,14627,14627, 447, 470, 749, 5, 22, 192, 3523, 2, 9, 4544, 1875, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 7, 15, 7, 42, 42, 27, 27, 13, 13, 2, 3, 4, 17, 23, 2, 16, 4, 6, 6, 8, {77,89,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Malay/Latin/Malaysia
+ { 176, 4, 35, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 15, 14, 17, 16, 91, 79, 61, 76,14640,14640,14640,14640, 83, 83, 0, 0, 0, 5, 22, 10, 3539, 2, 9, 4550, 4560, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 12, 7, 15, 7, 34, 34, 34, 34, 13, 13, 2, 2, 4, 17, 23, 1, 10, 4, 6, 10, 5, {66,78,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Malay/Arabic/Brunei
+ { 176, 4, 143, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 15, 14, 17, 16, 196, 79, 61, 76,14640,14640,14640,14640, 83, 83, 0, 0, 0, 5, 22, 192, 3549, 2, 9, 4550, 4565, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 7, 15, 7, 34, 34, 34, 34, 13, 13, 2, 2, 4, 17, 23, 2, 13, 4, 6, 10, 6, {77,89,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Malay/Arabic/Malaysia
+ { 176, 66, 35, 0, 0, 584, 584, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 91, 79, 23, 38,14558,14558,14600,14600,14627,14627, 447, 470, 749, 5, 22, 10, 3562, 2, 9, 4544, 4571, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 12, 7, 15, 7, 42, 42, 27, 27, 13, 13, 2, 3, 4, 17, 23, 1, 12, 4, 6, 6, 6, {66,78,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Malay/Latin/Brunei
+ { 176, 66, 111, 0, 0, 584, 584, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 786, 78, 212, 212,14558,14558,14600,14600,14627,14627, 447, 470, 749, 5, 22, 186, 3007, 2, 0, 4544, 1776, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 42, 42, 27, 27, 13, 13, 2, 3, 4, 17, 23, 2, 16, 4, 0, 6, 9, {73,68,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Malay/Latin/Indonesia
+ { 176, 66, 210, 0, 0, 584, 584, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 79, 23, 38,14558,14558,14600,14600,14627,14627, 447, 470, 749, 5, 22, 10, 3574, 2, 9, 4544, 4577, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 7, 15, 7, 42, 42, 27, 27, 13, 13, 2, 3, 4, 17, 23, 1, 15, 4, 6, 6, 9, {83,71,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Malay/Latin/Singapore
+ { 177, 66, 146, 0, 0, 823, 831, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1411, 186, 10, 0,14674,14674,14736,14736,14763,14783, 0, 0, 0, 5, 22, 22, 3589, 2, 0, 4586, 1891, 6, 6, 8, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 13, 5, 62, 62, 27, 27, 20, 19, 2, 2, 4, 17, 23, 1, 4, 4, 0, 5, 5, {69,85,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Maltese/Latin/Malta
+ { 179, 9, 110, 0, 0, 838, 838, 6, 0, 1, 2, 39, 4, 5, 10, 14, 15, 16, 17, 1434, 129, 61, 76,14802,14802,14802,14802,14860,14885, 449, 473, 0, 5, 22, 120, 3593, 15, 0, 4591, 4599, 6, 6, 11, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 58, 58, 58, 58, 25, 29, 4, 5, 4, 17, 23, 1, 14, 5, 0, 8, 8, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Manipuri/Bangla/India
+ { 179, 78, 110, 0, 0, 0, 0, 6, 0, 1, 2, 75, 4, 5, 10, 14, 15, 16, 17, 265, 283, 479, 494, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 120, 0, 15, 0, 4607, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 15, 8, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 7, 0, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Manipuri/Meitei Mayek/India
+ { 180, 66, 115, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 86, 78, 10, 0,14914,14914,14970,14970, 83, 83, 168, 168, 0, 5, 22, 94, 0, 2, 0, 4614, 4619, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 13, 5, 56, 56, 29, 29, 13, 13, 4, 4, 4, 17, 23, 1, 0, 4, 0, 5, 12, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Manx/Latin/Isle of Man
+ { 181, 66, 167, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 394, 23, 38,14999,14999,15046,15046,15073,15073, 0, 0, 0, 5, 22, 10, 3607, 15, 0, 4631, 4636, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 47, 47, 27, 27, 15, 15, 2, 2, 4, 17, 23, 1, 15, 5, 0, 5, 8, {78,90,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Maori/Latin/New Zealand
+ { 182, 66, 49, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 10, 0, 15, 0, 4644, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 10, 0, {67,76,80}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Mapuche/Latin/Chile
+ { 183, 29, 110, 0, 0, 849, 849, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 265, 129, 61, 76,15088,15088,15140,15140, 8605, 8605, 0, 0, 562, 5, 22, 120, 2964, 2, 9, 4654, 664, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 52, 52, 31, 31, 18, 18, 2, 2, 4, 17, 23, 1, 12, 4, 6, 5, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Marathi/Devanagari/India
+ { 185, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,15171,15171,13861,13861,14208,14208, 453, 478, 0, 5, 22, 176, 3622, 2, 9, 1275, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 57, 57, 27, 27, 13, 13, 9, 6, 4, 17, 23, 3, 18, 4, 6, 3, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Masai/Latin/Kenya
+ { 185, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,15171,15171,13861,13861,14208,14208, 453, 478, 0, 5, 22, 121, 3640, 2, 9, 1275, 4659, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 57, 57, 27, 27, 13, 13, 9, 6, 4, 17, 23, 3, 21, 4, 6, 3, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Masai/Latin/Tanzania
+ { 186, 4, 112, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 11, 12, 19, 20, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 798, 802, 22, 0, 3661, 15, 0, 4667, 4674, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 39, 23, 0, 10, 5, 0, 7, 5, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Mazanderani/Arabic/Iran
+ { 188, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,15228,15228,15278,15278,15305,15305, 462, 484, 0, 5, 22, 176, 991, 2, 9, 4679, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 50, 50, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 17, 4, 6, 6, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Meru/Latin/Kenya
+ { 189, 66, 40, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 137, 103, 10, 0,15318,15318,15318,15318,15366,15366, 0, 0, 0, 5, 22, 11, 3671, 15, 0, 4685, 4690, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 13, 5, 48, 48, 48, 48, 20, 20, 2, 2, 4, 17, 23, 4, 5, 5, 0, 5, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Meta/Latin/Cameroon
+ { 190, 66, 41, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 23, 38, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 240, 0, 15, 0, 4697, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 11, 0, {67,65,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Mohawk/Latin/Canada
+ { 191, 27, 156, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1452, 596, 98, 0,15386,15428,15470,15470,15470,15470, 464, 486, 196, 841, 22, 264, 3676, 15, 0, 4708, 4714, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 35, 10, 15, 5, 42, 42, 20, 20, 20, 20, 4, 4, 4, 17, 23, 1, 13, 5, 0, 6, 6, {77,78,84}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Mongolian/Cyrillic/Mongolia
+ { 191, 83, 50, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 248, 3689, 15, 0, 0, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 4, 5, 0, 0, 0, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Mongolian/Mongolian/China
+ { 191, 83, 156, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1487, 596, 98, 0,15490,15490,15532,15555,15578,15578, 468, 490, 0, 5, 22, 264, 3693, 2, 0, 4720, 4720, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 36, 10, 15, 5, 42, 42, 23, 23, 23, 22, 4, 5, 4, 17, 23, 1, 8, 4, 0, 6, 6, {77,78,84}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Mongolian/Mongolian/Mongolia
+ { 192, 66, 150, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0,15601,15601,15648,15648,15674,15674, 0, 0, 0, 5, 22, 196, 3701, 15, 0, 4726, 4740, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 47, 47, 26, 26, 13, 13, 2, 2, 4, 17, 23, 2, 14, 5, 0, 14, 5, {77,85,82}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Morisyen/Latin/Mauritius
+ { 193, 66, 40, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 129, 10, 0,15687,15687,15760,15760,15787,15787, 472, 495, 0, 5, 22, 11, 3715, 2, 9, 4745, 4751, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 73, 73, 27, 27, 13, 13, 5, 5, 4, 17, 23, 4, 10, 4, 6, 6, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Mundang/Latin/Cameroon
+ { 194, 66, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 23, 38,15800,15800,15800,15800, 83, 83, 0, 0, 0, 5, 22, 10, 0, 15, 0, 4758, 964, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7,106,106,106,106, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 7, 13, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Muscogee/Latin/United States
+ { 195, 66, 162, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38,15906,15906,15997,15997,16019,16019, 477, 500, 0, 5, 22, 10, 3725, 2, 0, 4765, 4778, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 91, 91, 22, 22, 13, 13, 7, 5, 4, 17, 23, 1, 15, 4, 0, 13, 8, {78,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Nama/Latin/Namibia
+ { 197, 66, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 179, 0, 15, 0, 4786, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 5, 0, 11, 0, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Navajo/Latin/United States
+ { 199, 29, 164, 858, 0, 863, 863, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 163, 344, 10, 0,16032,16032,16085,16085,16117,16117, 484, 505, 562, 858, 22, 265, 3740, 15, 0, 4797, 4797, 5, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 13, 5, 53, 53, 32, 32, 17, 17, 9, 7, 4, 19, 23, 4, 14, 5, 0, 6, 5, {78,80,82}, 2, 1, 7, 6, 7, 1, 2, 3 }, // Nepali/Devanagari/Nepal
+ { 199, 29, 110, 858, 0, 863, 863, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 163, 344, 61, 76,16032,16032,16085,16085,16117,16117, 484, 505, 562, 858, 22, 120, 3754, 15, 0, 4797, 664, 5, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 53, 53, 32, 32, 17, 17, 9, 7, 4, 19, 23, 1, 14, 5, 0, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Nepali/Devanagari/India
+ { 201, 66, 40, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 1523, 78, 10, 0,16134,16134,16134,16134, 83, 83, 493, 512, 0, 5, 22, 11, 3768, 15, 0, 4803, 4819, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 32, 8, 13, 5,110,110,110,110, 13, 13, 9, 8, 4, 17, 23, 4, 9, 5, 0, 16, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Ngiemboon/Latin/Cameroon
+ { 202, 66, 40, 870, 870, 881, 897, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 19, 20, 137, 103, 10, 0,16244,16244,16244,16244,16303,16303, 502, 520, 0, 5, 22, 11, 3777, 15, 0, 4826, 4831, 11, 11, 16, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 13, 5, 59, 59, 59, 59, 24, 24, 8, 13, 4, 17, 23, 4, 5, 5, 0, 5, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Ngomba/Latin/Cameroon
+ { 203, 66, 169, 0, 0, 906, 915, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,16327,16327,16378,16378, 83, 83, 510, 533, 877, 5, 22, 124, 3782, 2, 0, 4838, 4852, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 51, 51, 32, 32, 13, 13, 9, 8, 8, 17, 23, 1, 14, 4, 0, 14, 8, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Nigerian Pidgin/Latin/Nigeria
+ { 204, 90, 102, 0, 0, 0, 0, 6, 0, 76, 2, 77, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0,16410,16410,16470,16502,16536,16536, 519, 541, 0, 5, 22, 269, 3796, 15, 0, 4860, 4863, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 60, 60, 32, 34, 13, 13, 1, 1, 4, 17, 23, 1, 22, 5, 0, 3, 6, {71,78,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Nko/Nko/Guinea
+ { 205, 4, 112, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 4869, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 11, 0, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Northern Luri/Arabic/Iran
+ { 205, 4, 113, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 61, 76, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 43, 0, 15, 0, 4869, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 15, 7, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 5, 0, 5, 0, 11, 0, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Northern Luri/Arabic/Iraq
+ { 206, 66, 175, 0, 0, 351, 351, 6, 1, 9, 2, 3, 48, 5, 78, 15, 15, 17, 17, 163, 103, 10, 0,16549,16549,16623,16623,16655,16655, 520, 542, 0, 5, 22, 160, 3818, 4, 0, 4880, 4895, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 17, 10, 13, 5, 74, 74, 32, 32, 13, 13, 11, 13, 4, 17, 23, 2, 14, 5, 0, 15, 5, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Northern Sami/Latin/Norway
+ { 206, 66, 83, 0, 0, 351, 351, 6, 1, 9, 2, 3, 48, 5, 78, 15, 15, 17, 17, 113, 49, 10, 0,16668,16668,16737,16737,16757,16757, 531, 185, 0, 5, 22, 22, 405, 4, 0, 4880, 4900, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 16, 10, 13, 5, 69, 69, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 15, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Northern Sami/Latin/Finland
+ { 206, 66, 225, 0, 0, 351, 351, 6, 1, 9, 2, 3, 48, 5, 78, 15, 15, 17, 17, 163, 103, 10, 0,16549,16549,16623,16623,16655,16655, 520, 542, 0, 5, 22, 160, 3832, 4, 0, 4880, 4906, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 17, 10, 13, 5, 74, 74, 32, 32, 13, 13, 11, 13, 4, 17, 23, 2, 14, 5, 0, 15, 6, {83,69,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Northern Sami/Latin/Sweden
+ { 207, 66, 216, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 10, 0,16770,16770,16833,16833,16859,16859, 0, 0, 0, 5, 22, 9, 0, 2, 0, 4912, 4928, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 63, 63, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 16, 12, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Northern Sotho/Latin/South Africa
+ { 208, 66, 261, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,16872,16872,16921,16921,16948,16948, 0, 0, 0, 5, 22, 179, 3846, 2, 9, 4940, 2434, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 49, 49, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 17, 4, 6, 10, 8, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // North Ndebele/Latin/Zimbabwe
+ { 209, 66, 175, 0, 0, 289, 289, 6, 1, 9, 2, 3, 48, 5, 10, 11, 12, 16, 17, 698, 49, 10, 0, 4788, 4788,16961,16961, 4874, 4874, 168, 168, 0, 5, 22, 160, 3863, 15, 58, 4950, 4962, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 50, 50, 34, 34, 13, 13, 4, 4, 4, 17, 23, 2, 13, 5, 7, 12, 5, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Norwegian Bokmal/Latin/Norway
+ { 209, 66, 224, 0, 0, 289, 289, 6, 1, 9, 2, 3, 48, 5, 10, 11, 12, 16, 17, 698, 49, 10, 0, 4788, 4788,16961,16961, 4874, 4874, 168, 168, 0, 5, 22, 160, 3863, 15, 58, 4950, 4967, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 50, 50, 34, 34, 13, 13, 4, 4, 4, 17, 23, 2, 13, 5, 7, 12, 21, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Norwegian Bokmal/Latin/Svalbard and Jan Mayen
+ { 210, 66, 175, 0, 0, 289, 289, 6, 1, 9, 2, 3, 48, 5, 10, 11, 12, 16, 17, 698, 49, 502, 0,16995,16995,17045,17072, 4874, 4874, 533, 555, 0, 5, 22, 160, 3863, 4, 0, 4988, 5001, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 19, 5, 50, 50, 27, 27, 13, 13, 4, 4, 4, 17, 23, 2, 13, 5, 0, 13, 5, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Norwegian Nynorsk/Latin/Norway
+ { 211, 66, 219, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 187, 521, 38,17099,17099,17177,17177,17214,17214, 537, 559, 0, 5, 22, 94, 0, 2, 9, 5006, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 9, 15, 7, 78, 78, 37, 37, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 6, 9, 0, {83,83,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Nuer/Latin/South Sudan
+ { 212, 66, 142, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 23, 38,17227,17227,17293,17293, 83, 83, 0, 0, 0, 5, 22, 0, 1521, 15, 0, 5015, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 66, 66, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 15, 5, 0, 6, 0, {77,87,75}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Nyanja/Latin/Malawi
+ { 213, 66, 243, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 4053, 4053, 4126, 4126, 4153, 4153, 0, 0, 0, 5, 22, 147, 805, 2, 0, 5021, 983, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 73, 73, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 19, 4, 0, 10, 6, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Nyankole/Latin/Uganda
+ { 214, 66, 84, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 11, 12, 1555, 79, 10, 536,17320,17320,17320,17320,17376,17376, 0, 0, 376, 232, 249, 22, 405, 0, 45, 5031, 807, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 7, 13, 6, 56, 56, 56, 56, 20, 20, 2, 2, 6, 17, 23, 1, 4, 4, 6, 7, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Occitan/Latin/France
+ { 214, 66, 220, 0, 0, 414, 414, 6, 0, 1, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 79, 99, 1,17396,17396,17453,17453,17480,17480, 0, 0, 376, 232, 249, 22, 405, 0, 0, 5031, 5038, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 7, 14, 4, 57, 57, 27, 27, 13, 13, 2, 2, 6, 17, 23, 1, 4, 4, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Occitan/Latin/Spain
+ { 215, 91, 110, 0, 0, 923, 931, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 61, 76,17493,17493,17546,17546,17578,17578, 0, 0, 885, 5, 22, 120, 3876, 2, 9, 5045, 5050, 6, 6, 8, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 53, 53, 32, 32, 17, 17, 2, 2, 5, 17, 23, 1, 12, 4, 6, 5, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Odia/Odia/India
+ { 220, 66, 77, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 78, 23, 38,17595,17595,17649,17649, 83, 83, 539, 561, 0, 5, 22, 1, 3888, 2, 0, 5054, 5060, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 15, 7, 54, 54, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 17, 4, 0, 6, 10, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Oromo/Latin/Ethiopia
+ { 220, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 78, 10, 0,17595,17595,17649,17649,17676,17676, 539, 561, 0, 5, 22, 176, 0, 2, 0, 5054, 5070, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 54, 54, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 4, 0, 6, 8, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Oromo/Latin/Kenya
+ { 221, 101, 248, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 61, 76,17689,17689,17689,17689, 83,17869, 0, 0, 0, 5, 22, 10, 0, 15, 0, 5078, 964, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7,180,180,180,180, 13, 20, 2, 2, 4, 17, 23, 1, 0, 5, 0, 12, 13, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Osage/Osage/United States
+ { 222, 27, 90, 0, 0, 938, 938, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 1576, 49, 10, 0,17889,17949,18009,18036,18063,18063, 541, 563, 0, 5, 22, 0, 3905, 15, 0, 5090, 5094, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 13, 5, 60, 60, 27, 27, 13, 13, 15, 15, 4, 17, 23, 1, 3, 5, 0, 4, 11, {71,69,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ossetic/Cyrillic/Georgia
+ { 222, 27, 193, 0, 0, 938, 938, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 1576, 49, 10, 0,17889,17949,18009,18036,18063,18063, 541, 563, 0, 5, 22, 133, 3908, 15, 0, 5090, 5105, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 13, 5, 60, 60, 27, 27, 13, 13, 15, 15, 4, 17, 23, 1, 3, 5, 0, 4, 6, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ossetic/Cyrillic/Russia
+ { 226, 66, 62, 0, 0, 143, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 394, 10, 0,18076,18076,18076,18076,18138,18138, 0, 0, 0, 5, 22, 0, 3911, 15, 0, 5111, 5121, 6, 6, 7, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 62, 62, 62, 62, 20, 20, 2, 2, 4, 17, 23, 0, 6, 5, 0, 10, 6, {65,78,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Papiamento/Latin/Curacao
+ { 226, 66, 13, 0, 0, 143, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 394, 10, 0,18076,18076,18076,18076,18138,18138, 0, 0, 0, 5, 22, 0, 3917, 15, 0, 5111, 1227, 6, 6, 7, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 62, 62, 62, 62, 20, 20, 2, 2, 4, 17, 23, 0, 15, 5, 0, 10, 5, {65,87,71}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Papiamento/Latin/Aruba
+ { 227, 4, 1, 661, 661, 947, 956, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 1599, 505, 99, 1,18158,18158,18158,18158, 83, 83, 556, 578, 890, 5, 22, 270, 3932, 2, 9, 5127, 5131, 6, 6, 9, 8, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 20, 8, 14, 4, 38, 38, 38, 38, 13, 13, 4, 4, 5, 17, 23, 1, 6, 4, 6, 4, 9, {65,70,78}, 0, 0, 6, 4, 5, 1, 3, 3 }, // Pashto/Arabic/Afghanistan
+ { 227, 4, 178, 661, 661, 947, 956, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 1599, 505, 61, 76,18158,18158,18158,18158, 83, 83, 556, 578, 890, 5, 22, 196, 3938, 2, 9, 5127, 5140, 6, 6, 9, 8, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 20, 8, 15, 7, 38, 38, 38, 38, 13, 13, 4, 4, 5, 17, 23, 2, 15, 4, 6, 4, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Pashto/Arabic/Pakistan
+ { 228, 4, 112, 964, 964, 971, 979, 67, 21, 22, 23, 40, 82, 37, 44, 11, 12, 19, 20, 113, 505, 99, 1,18196,18196,18196,18196,18244,18244, 560, 582, 798, 5, 22, 271, 3953, 103, 109, 5147, 4674, 7, 7, 8, 7, 1, 1, 1, 1, 1, 2, 2, 4, 1, 1, 1, 1, 16, 8, 14, 4, 48, 48, 48, 48, 13, 13, 9, 8, 4, 17, 23, 4, 10, 6, 8, 5, 5, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Persian/Arabic/Iran
+ { 228, 4, 1, 964, 964, 971, 979, 67, 21, 22, 23, 40, 82, 37, 44, 11, 12, 19, 20, 113, 505, 99, 1,18196,18196,18196,18196,18244,18244, 560, 582, 798, 5, 22, 270, 3963, 15, 109, 5152, 5131, 7, 7, 8, 7, 1, 1, 1, 1, 1, 2, 2, 4, 1, 1, 1, 1, 16, 8, 14, 4, 48, 48, 48, 48, 13, 13, 9, 8, 4, 17, 23, 1, 16, 5, 8, 3, 9, {65,70,78}, 0, 0, 6, 4, 5, 1, 3, 3 }, // Persian/Arabic/Afghanistan
+ { 230, 66, 187, 0, 0, 143, 143, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 11, 12, 0, 50, 10, 0,18257,18257,18315,18315,18348,18361, 0, 0, 311, 5, 22, 275, 3979, 4, 20, 5155, 5161, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 9, 13, 5, 58, 58, 33, 33, 13, 13, 2, 2, 5, 17, 23, 2, 12, 5, 7, 6, 6, {80,76,78}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Polish/Latin/Poland
+ { 231, 66, 32, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 186, 10, 0,18374,18374,18452,18452,18486,18486, 0, 0, 0, 5, 22, 9, 3991, 15, 0, 5167, 5176, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 10, 13, 5, 78, 78, 34, 34, 13, 13, 2, 2, 5, 17, 23, 2, 15, 5, 0, 9, 6, {66,82,76}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Portuguese/Latin/Brazil
+ { 231, 66, 7, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 255, 4006, 4, 20, 5167, 5182, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 2, 15, 5, 7, 9, 6, {65,79,65}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Portuguese/Latin/Angola
+ { 231, 66, 43, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 243, 4021, 4, 20, 5167, 5188, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 1, 20, 5, 7, 9, 10, {67,86,69}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Cape Verde
+ { 231, 66, 73, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 11, 4041, 4, 20, 5167, 5198, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 4, 17, 5, 7, 9, 16, {88,65,70}, 0, 0, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Equatorial Guinea
+ { 231, 66, 101, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 127, 4058, 4, 20, 5167, 5214, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 5, 18, 5, 7, 9, 12, {88,79,70}, 0, 0, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Guinea-Bissau
+ { 231, 66, 138, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 22, 405, 4, 20, 5167, 5226, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 1, 4, 5, 7, 9, 10, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Luxembourg
+ { 231, 66, 139, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 23, 38,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 151, 4076, 4, 20, 5167, 5236, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 15, 7, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 4, 15, 5, 7, 9, 19, {77,79,80}, 2, 1, 7, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Macao
+ { 231, 66, 160, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 261, 4091, 4, 20, 5167, 5255, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 3, 19, 5, 7, 9, 10, {77,90,78}, 2, 1, 7, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Mozambique
+ { 231, 66, 188, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 22, 405, 4, 20, 5265, 5282, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 1, 4, 5, 7, 17, 8, {69,85,82}, 2, 1, 7, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Portugal
+ { 231, 66, 204, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 277, 4110, 4, 20, 5167, 5290, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 2, 28, 5, 7, 9, 19, {83,84,78}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Sao Tome and Principe
+ { 231, 66, 226, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 0, 4138, 4, 20, 5167, 5309, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 0, 12, 5, 7, 9, 5, {67,72,70}, 2, 0, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Switzerland
+ { 231, 66, 232, 0, 0, 414, 414, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 78, 10, 0,18374,18374,18499,18499,18486,18486, 569, 590, 0, 5, 22, 179, 4150, 4, 20, 5167, 5314, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 78, 78, 48, 48, 13, 13, 8, 8, 5, 17, 23, 3, 24, 5, 7, 9, 11, {85,83,68}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Portuguese/Latin/Timor-Leste
+ { 232, 66, 187, 0, 0, 986, 986, 6, 1, 9, 2, 3, 4, 5, 10, 13, 14, 13, 14, 1619, 49, 10, 0,18547,18547,18615,18615,18642,18642, 577, 598, 0, 5, 22, 275, 0, 4, 0, 5325, 5334, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 68, 68, 27, 27, 13, 13, 10, 14, 4, 17, 23, 2, 0, 5, 0, 9, 4, {80,76,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Prussian/Latin/Poland
+ { 233, 41, 110, 0, 0, 994, 994, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 61, 76,18655,18655,18711,18711,18746,18746, 587, 612, 895, 5, 22, 120, 4174, 15, 0, 5338, 5344, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 56, 56, 35, 35, 22, 22, 6, 6, 4, 17, 23, 1, 11, 5, 0, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Punjabi/Gurmukhi/India
+ { 233, 4, 178, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 786, 186, 61, 76,18768,18768,18768,18768, 83, 83, 0, 0, 0, 5, 22, 78, 4185, 15, 0, 5348, 5140, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 18, 10, 15, 7, 36, 36, 36, 36, 13, 13, 2, 2, 4, 17, 23, 1, 6, 5, 0, 6, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Punjabi/Arabic/Pakistan
+ { 234, 66, 184, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 23, 38,18804,18804,18856,18856,18883,18883, 168, 168, 0, 5, 22, 279, 4191, 15, 0, 5354, 5362, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 52, 52, 27, 27, 13, 13, 4, 4, 4, 17, 23, 2, 11, 5, 0, 8, 4, {80,69,78}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Quechua/Latin/Peru
+ { 234, 66, 28, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 23, 38,18804,18804,18856,18856,18883,18883, 168, 168, 0, 5, 22, 281, 4202, 15, 0, 5354, 5366, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 52, 52, 27, 27, 13, 13, 4, 4, 4, 17, 23, 2, 9, 5, 0, 8, 7, {66,79,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Quechua/Latin/Bolivia
+ { 234, 66, 70, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 23, 38,18804,18804,18856,18856,18883,18883, 168, 168, 0, 5, 22, 10, 4211, 15, 0, 5354, 5373, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 52, 52, 27, 27, 13, 13, 4, 4, 4, 17, 23, 1, 15, 5, 0, 8, 7, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Quechua/Latin/Ecuador
+ { 235, 66, 192, 0, 0, 1003, 1003, 6, 1, 0, 2, 3, 4, 5, 10, 13, 15, 11, 12, 0, 49, 10, 0,18896,18896,18943,18943, 6778, 6778, 168, 168, 899, 5, 22, 283, 4226, 4, 20, 5380, 5386, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 47, 47, 33, 33, 13, 13, 4, 4, 4, 17, 23, 3, 12, 5, 7, 6, 7, {82,79,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Romanian/Latin/Romania
+ { 235, 66, 154, 0, 0, 1003, 1003, 6, 1, 0, 2, 3, 4, 5, 10, 13, 15, 11, 12, 0, 49, 10, 0,18896,18896,18976,18976,19003,19003, 168, 168, 899, 5, 22, 18, 4238, 4, 20, 5380, 5393, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 47, 47, 27, 27, 15, 15, 4, 4, 4, 17, 23, 1, 15, 5, 7, 6, 17, {77,68,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Romanian/Latin/Moldova
+ { 236, 66, 226, 0, 0, 414, 414, 6, 0, 17, 2, 3, 48, 5, 10, 11, 12, 19, 20, 1646, 394, 10, 0,19018,19018,19073,19073,19095,19095, 0, 0, 0, 5, 22, 0, 4253, 4, 0, 5410, 5419, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 8, 13, 5, 55, 55, 22, 22, 13, 13, 2, 2, 5, 17, 23, 0, 13, 5, 0, 9, 6, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Romansh/Latin/Switzerland
+ { 237, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,19108,19108,19172,19172,14208,14208, 593, 618, 0, 5, 22, 121, 4266, 2, 0, 5425, 2268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 64, 64, 28, 28, 13, 13, 8, 7, 4, 17, 23, 3, 18, 4, 0, 9, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Rombo/Latin/Tanzania
+ { 238, 66, 38, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 15, 15, 17, 17, 113, 129, 10, 0,19200,19200,19288,19288, 83, 83, 601, 625, 0, 5, 22, 182, 4284, 0, 0, 5434, 5442, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 88, 88, 33, 33, 13, 13, 5, 5, 4, 17, 23, 3, 20, 4, 0, 8, 8, {66,73,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Rundi/Latin/Burundi
+ { 239, 27, 193, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 49, 10, 0,19321,19321,19382,19382,19402,19402, 0, 0, 196, 841, 22, 133, 4304, 4, 0, 5450, 5457, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 13, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 16, 5, 0, 7, 6, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Russian/Cyrillic/Russia
+ { 239, 27, 22, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 49, 10, 0,19321,19321,19382,19382,19402,19402, 0, 0, 196, 841, 22, 1, 4320, 4, 0, 5450, 618, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 13, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 2, 17, 5, 0, 7, 8, {66,89,78}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Russian/Cyrillic/Belarus
+ { 239, 27, 123, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 49, 10, 0,19321,19321,19382,19382,19402,19402, 0, 0, 196, 841, 22, 244, 4337, 4, 0, 5450, 5463, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 13, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 15, 5, 0, 7, 9, {75,90,84}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Russian/Cyrillic/Kazakhstan
+ { 239, 27, 128, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 49, 10, 0,19321,19321,19382,19382,19402,19402, 0, 0, 196, 841, 22, 251, 4352, 4, 0, 5450, 5472, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 13, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 3, 14, 5, 0, 7, 8, {75,71,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Russian/Cyrillic/Kyrgyzstan
+ { 239, 27, 154, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 49, 10, 0,19321,19321,19382,19382,19402,19402, 0, 0, 196, 841, 22, 18, 4366, 4, 0, 5450, 5480, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 13, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 14, 5, 0, 7, 7, {77,68,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Russian/Cyrillic/Moldova
+ { 239, 27, 244, 0, 0, 150, 150, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 350, 49, 10, 0,19321,19321,19382,19382,19402,19402, 0, 0, 196, 841, 22, 286, 4380, 4, 0, 5450, 5487, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 10, 13, 5, 61, 61, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 17, 5, 0, 7, 7, {85,65,72}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Russian/Cyrillic/Ukraine
+ { 240, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,13800,13800,13861,13861, 1284, 1284, 430, 446, 0, 5, 22, 121, 3492, 0, 0, 5494, 2268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 61, 61, 27, 27, 13, 13, 5, 9, 4, 17, 23, 3, 20, 4, 0, 6, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Rwa/Latin/Tanzania
+ { 241, 66, 74, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 59, 78, 23, 38,19415,19415,19470,19470,19497,19497, 0, 0, 0, 5, 22, 6, 0, 2, 0, 5500, 34, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 15, 7, 55, 55, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 0, 4, 0, 4, 7, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Saho/Latin/Eritrea
+ { 242, 27, 193, 0, 0, 1011, 1011, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 14, 1669, 344, 10, 0,19510,19510,19580,19580,19600,19600, 606, 630, 903, 908, 22, 133, 4397, 4, 0, 5504, 5513, 6, 6, 11, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 30, 6, 13, 5, 70, 70, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 20, 5, 0, 9, 9, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Sakha/Cyrillic/Russia
+ { 243, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,19613,19613,19717,19717,19744,19744, 608, 632, 0, 5, 22, 176, 4417, 2, 9, 5522, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5,104,104, 27, 27, 13, 13, 7, 5, 4, 17, 23, 3, 18, 4, 6, 8, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Samburu/Latin/Kenya
+ { 245, 66, 46, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 113, 129, 10, 0,19757,19757,19822,19822,19849,19849, 615, 637, 0, 5, 22, 11, 4435, 2, 65, 5530, 5535, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 65, 65, 27, 27, 13, 13, 2, 2, 4, 17, 23, 4, 18, 4, 5, 5, 22, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Sango/Latin/Central African Republic
+ { 246, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,19862,19862,19921,19921,19948,19948, 617, 639, 0, 5, 22, 121, 4453, 0, 0, 5557, 5566, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 59, 59, 27, 27, 13, 13, 9, 9, 4, 17, 23, 3, 18, 4, 0, 9, 9, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Sangu/Latin/Tanzania
+ { 247, 29, 110, 0, 0, 1022, 1032, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 0, 129, 61, 76,19961,19961, 8574, 8574, 8605, 8605, 484, 505, 0, 5, 22, 120, 4471, 15, 0, 5575, 5587, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 66, 66, 31, 31, 18, 18, 9, 7, 4, 17, 23, 1, 15, 5, 0, 12, 5, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Sanskrit/Devanagari/India
+ { 248, 93, 110, 0, 0, 0, 0, 6, 0, 1, 2, 84, 4, 5, 10, 14, 15, 16, 17, 0, 129, 61, 76,20027,20027,20068,20068,20093,20093, 626, 648, 0, 5, 22, 120, 4486, 15, 0, 5592, 5599, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 41, 41, 25, 25, 13, 13, 5, 5, 4, 17, 23, 1, 16, 5, 0, 7, 6, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Santali/Ol Chiki/India
+ { 248, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 0, 129, 61, 76, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 120, 0, 15, 0, 5605, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 8, 0, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Santali/Devanagari/India
+ { 249, 66, 117, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 1699, 186, 10, 0,20106,20106,20160,20160,20187,20187, 0, 0, 0, 5, 22, 22, 4502, 4, 0, 5613, 813, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 31, 10, 13, 5, 54, 54, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 0, 5, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Sardinian/Latin/Italy
+ { 251, 66, 160, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 10, 0,20200,20200,20254,20254,20281,20281, 0, 0, 0, 5, 22, 261, 4506, 0, 0, 5618, 5255, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 13, 5, 54, 54, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 21, 4, 0, 4, 10, {77,90,78}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Sena/Latin/Mozambique
+ { 252, 27, 207, 0, 0, 150, 150, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 10, 0,20294,20294,20345,20345, 2891, 2891, 0, 0, 925, 5, 22, 0, 4527, 4, 20, 5622, 5628, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 13, 5, 51, 51, 27, 27, 13, 13, 2, 2, 7, 17, 23, 0, 12, 5, 7, 6, 6, {82,83,68}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Serbian/Cyrillic/Serbia
+ { 252, 27, 29, 0, 0, 150, 150, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 10, 0, 2809, 2809, 2864, 2864, 2891, 2891, 104, 653, 925, 5, 22, 137, 4539, 4, 20, 5622, 713, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 13, 5, 55, 55, 27, 27, 13, 13, 11, 8, 7, 17, 23, 2, 40, 5, 7, 6, 19, {66,65,77}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Cyrillic/Bosnia and Herzegovina
+ { 252, 27, 126, 0, 0, 150, 150, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 10, 0,20294,20294,20345,20345, 2891, 2891, 0, 0, 925, 5, 22, 22, 4579, 4, 20, 5622, 5634, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 13, 5, 51, 51, 27, 27, 13, 13, 2, 2, 7, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Cyrillic/Kosovo
+ { 252, 27, 157, 0, 0, 150, 150, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 10, 0,20372,20372,20345,20345, 2891, 2891, 104, 653, 925, 5, 22, 22, 4579, 4, 20, 5622, 5640, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 13, 5, 54, 54, 27, 27, 13, 13, 11, 8, 7, 17, 23, 1, 4, 5, 7, 6, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Cyrillic/Montenegro
+ { 252, 66, 29, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 10, 0, 2699, 2699, 2756, 2756, 2783, 2783, 631, 661, 218, 5, 22, 135, 597, 4, 20, 5649, 686, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 13, 5, 57, 57, 27, 27, 13, 13, 11, 8, 7, 17, 23, 2, 40, 5, 7, 6, 19, {66,65,77}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Latin/Bosnia and Herzegovina
+ { 252, 66, 126, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 10, 0,20426,20426,20479,20479, 2783, 2783, 0, 0, 218, 5, 22, 22, 4583, 4, 20, 5649, 5655, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 13, 5, 53, 53, 27, 27, 13, 13, 2, 2, 7, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Latin/Kosovo
+ { 252, 66, 157, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 10, 0,20506,20506,20479,20479, 2783, 2783, 631, 661, 218, 5, 22, 22, 4583, 4, 20, 5649, 5661, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 13, 5, 56, 56, 27, 27, 13, 13, 11, 8, 7, 17, 23, 1, 4, 5, 7, 6, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Serbian/Latin/Montenegro
+ { 252, 66, 207, 0, 0, 143, 143, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 16, 16, 404, 454, 10, 0,20426,20426,20479,20479, 2783, 2783, 0, 0, 218, 5, 22, 0, 4587, 4, 20, 5649, 5670, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 7, 13, 5, 53, 53, 27, 27, 13, 13, 2, 2, 7, 17, 23, 0, 12, 5, 7, 6, 6, {82,83,68}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Serbian/Latin/Serbia
+ { 253, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,20562,20562,20624,20624,20651,20651, 642, 669, 0, 5, 22, 121, 4599, 0, 0, 5676, 2268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 62, 62, 27, 27, 13, 13, 5, 8, 4, 17, 23, 3, 20, 4, 0, 9, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Shambala/Latin/Tanzania
+ { 254, 66, 261, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 15, 15, 17, 17, 163, 103, 10, 0,20664,20664,20718,20718,20745,20745, 0, 0, 0, 5, 22, 179, 4619, 2, 9, 5685, 2434, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 54, 54, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 15, 4, 6, 8, 8, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Shona/Latin/Zimbabwe
+ { 255, 141, 50, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0,20758,20758,20785,20785,20805,20805, 647, 677, 0, 5, 22, 150, 0, 15, 0, 5693, 5696, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 3, 2, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Sichuan Yi/Yi/China
+ { 256, 66, 117, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0,20818,20818,20818,20818, 83, 83, 0, 0, 0, 5, 22, 22, 0, 15, 0, 5698, 3728, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 62, 62, 62, 62, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 9, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Sicilian/Latin/Italy
+ { 257, 66, 77, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 59, 78, 23, 38,20880,20880,20930,20930,20957,20957, 0, 0, 0, 5, 22, 1, 0, 2, 0, 5707, 5718, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 15, 7, 50, 50, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 4, 0, 11, 11, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Sidamo/Latin/Ethiopia
+ { 258, 66, 187, 0, 0, 143, 143, 6, 1, 9, 2, 3, 4, 5, 10, 13, 15, 12, 11, 0, 49, 10, 0,20970,20970,21030,21030,13193,13193, 649, 679, 311, 5, 22, 275, 0, 15, 0, 5729, 5161, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 60, 60, 27, 27, 13, 13, 11, 11, 5, 17, 23, 2, 0, 5, 0, 7, 6, {80,76,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Silesian/Latin/Poland
+ { 259, 4, 178, 0, 0, 1041, 1049, 67, 21, 22, 23, 25, 26, 28, 59, 14, 15, 16, 17, 549, 103, 61, 76,21057,21057,21057,21057,21091,21091, 660, 690, 932, 938, 22, 196, 4634, 4, 0, 5736, 5740, 6, 6, 8, 7, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 18, 10, 15, 7, 34, 34, 34, 34, 30, 30, 11, 11, 6, 25, 23, 2, 12, 5, 0, 4, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Sindhi/Arabic/Pakistan
+ { 259, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 61, 76,21121,21148,21189,21211,21239,21239, 671, 701, 0, 5, 22, 120, 4646, 15, 0, 5747, 664, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 27, 41, 22, 28, 20, 20, 8, 6, 4, 17, 23, 1, 17, 5, 0, 6, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Sindhi/Devanagari/India
+ { 260, 119, 221, 0, 0, 1056, 1065, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 212, 212,21259,21259,21320,21320,21358,21358, 679, 707, 963, 968, 22, 287, 4663, 2, 9, 5753, 5758, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 61, 61, 38, 38, 18, 18, 5, 4, 5, 42, 23, 3, 17, 4, 6, 5, 11, {76,75,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Sinhala/Sinhala/Sri Lanka
+ { 261, 66, 83, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 22, 0, 15, 0, 5769, 5779, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 10, 12, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Skolt Sami/Latin/Finland
+ { 262, 66, 212, 0, 0, 781, 282, 6, 1, 9, 2, 3, 4, 5, 6, 13, 14, 18, 16, 698, 423, 11, 1,21376,21376,21427,21427,21447,21447, 0, 0, 311, 5, 22, 22, 405, 4, 20, 5791, 5801, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 12, 4, 51, 51, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 4, 5, 7, 10, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Slovak/Latin/Slovakia
+ { 263, 66, 213, 0, 0, 1073, 1073, 6, 1, 0, 2, 3, 48, 5, 6, 13, 14, 18, 16, 404, 423, 10, 0,21460,21460,21511,21511,21545,21545, 172, 711, 50, 5, 22, 22, 4680, 4, 20, 5810, 5821, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 51, 51, 34, 34, 13, 13, 4, 4, 4, 17, 23, 1, 4, 5, 7, 11, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Slovenian/Latin/Slovenia
+ { 264, 66, 243, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,21558,21558,21622,21622,21656,21656, 684, 715, 0, 5, 22, 147, 2829, 4, 0, 5830, 3330, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 64, 64, 34, 34, 13, 13, 6, 6, 4, 17, 23, 3, 19, 5, 0, 7, 7, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Soga/Latin/Uganda
+ { 265, 66, 215, 0, 0, 1081, 1081, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 78, 23, 38,21669,21669,21715,21715,21746,21746, 690, 721, 1010, 1016, 22, 93, 4684, 2, 9, 5837, 5845, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 15, 7, 46, 46, 31, 31, 14, 14, 2, 2, 6, 17, 23, 1, 20, 4, 6, 8, 10, {83,79,83}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Somali/Latin/Somalia
+ { 265, 66, 67, 0, 0, 1081, 1081, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 78, 23, 38,21669,21669,21715,21715,21746,21746, 690, 721, 1010, 1016, 22, 3, 4704, 2, 9, 5837, 5855, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 15, 7, 46, 46, 31, 31, 14, 14, 2, 2, 6, 17, 23, 3, 13, 4, 6, 8, 7, {68,74,70}, 0, 0, 6, 6, 7, 1, 3, 3 }, // Somali/Latin/Djibouti
+ { 265, 66, 77, 0, 0, 1081, 1081, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 78, 23, 38,21669,21669,21715,21715,21746,21746, 690, 721, 1010, 1016, 22, 1, 4717, 2, 9, 5837, 5862, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 15, 7, 46, 46, 31, 31, 14, 14, 2, 2, 6, 17, 23, 2, 15, 4, 6, 8, 8, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Somali/Latin/Ethiopia
+ { 265, 66, 124, 0, 0, 1081, 1081, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 78, 10, 0,21669,21669,21715,21715,21746,21746, 690, 721, 1010, 1016, 22, 176, 4732, 2, 9, 5837, 1307, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 46, 46, 31, 31, 14, 14, 2, 2, 6, 17, 23, 3, 15, 4, 6, 8, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Somali/Latin/Kenya
+ { 266, 4, 112, 0, 0, 0, 0, 67, 21, 22, 23, 25, 26, 28, 59, 11, 12, 19, 20, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 5870, 0, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 11, 0, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Southern Kurdish/Arabic/Iran
+ { 266, 4, 113, 0, 0, 0, 0, 67, 21, 22, 23, 25, 26, 28, 59, 11, 12, 19, 20, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 5870, 0, 6, 6, 6, 6, 1, 1, 1, 2, 1, 2, 2, 2, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 11, 0, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Southern Kurdish/Arabic/Iraq
+ { 267, 66, 225, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 160, 0, 15, 0, 5881, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 19, 0, {83,69,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Southern Sami/Latin/Sweden
+ { 267, 66, 175, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 160, 0, 15, 0, 5881, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 19, 0, {78,79,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Southern Sami/Latin/Norway
+ { 268, 66, 216, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 10, 0,21760,21760,21820,21820, 83, 83, 0, 0, 0, 5, 22, 9, 0, 2, 0, 4912, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 60, 60, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 7, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Southern Sotho/Latin/South Africa
+ { 268, 66, 133, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 23, 38,21760,21760,21820,21820, 83, 83, 0, 0, 0, 5, 22, 9, 0, 2, 0, 4912, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 60, 60, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 7, 0, {90,65,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Southern Sotho/Latin/Lesotho
+ { 269, 66, 216, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 10, 0,21846,21846,21911,21911, 83, 83, 0, 0, 0, 5, 22, 9, 0, 2, 0, 4940, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 65, 65, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 10, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // South Ndebele/Latin/South Africa
+ { 270, 66, 220, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 99, 1,21937,21937,21989,21989,18883,18883, 132, 128, 0, 5, 22, 22, 405, 4, 0, 5900, 455, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 14, 4, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 4, 5, 0, 17, 6, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Spanish/Latin/Spain
+ { 270, 66, 11, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 10, 4747, 15, 58, 5900, 5917, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 14, 5, 7, 7, 9, {65,82,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Argentina
+ { 270, 66, 24, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 10, 0,21937,21937,21989,21989, 6778, 6778, 168, 168, 0, 5, 22, 10, 4761, 2, 0, 5900, 5926, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 13, 5, 52, 52, 27, 27, 13, 13, 4, 4, 5, 17, 23, 1, 14, 4, 0, 7, 6, {66,90,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Belize
+ { 270, 66, 28, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 281, 4775, 2, 0, 5900, 5366, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 2, 9, 4, 0, 7, 7, {66,79,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Bolivia
+ { 270, 66, 32, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 10, 0,21937,21937,21989,21989, 6778, 6778, 168, 168, 0, 5, 22, 9, 4784, 2, 0, 5900, 5176, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 13, 5, 52, 52, 27, 27, 13, 13, 4, 4, 5, 17, 23, 2, 14, 4, 0, 7, 6, {66,82,76}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Brazil
+ { 270, 66, 42, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 99, 1,21937,21937,21989,21989,18883,18883, 132, 128, 0, 5, 22, 22, 405, 4, 0, 5900, 5932, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 14, 4, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 4, 5, 0, 7, 8, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Spanish/Latin/Canary Islands
+ { 270, 66, 47, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 99, 1,21937,21937,21989,21989,18883,18883, 132, 128, 0, 5, 22, 22, 405, 4, 0, 5900, 5940, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 14, 4, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 4, 5, 0, 7, 15, {69,85,82}, 2, 1, 1, 6, 7, 2, 3, 3 }, // Spanish/Latin/Ceuta and Melilla
+ { 270, 66, 49, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 394, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 10, 4798, 2, 65, 5900, 5955, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 12, 4, 5, 7, 5, {67,76,80}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Chile
+ { 270, 66, 54, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 79, 23, 38,21937,21937,21989,21989, 9387,22016, 132, 128, 0, 5, 22, 10, 4810, 15, 0, 5900, 5960, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 7, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 15, 5, 0, 7, 8, {67,79,80}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Colombia
+ { 270, 66, 59, 0, 0, 68, 68, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 290, 4825, 2, 0, 5900, 5968, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 19, 4, 0, 7, 10, {67,82,67}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Costa Rica
+ { 270, 66, 61, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 168, 168, 0, 5, 22, 10, 4844, 2, 0, 5900, 5978, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 4, 4, 5, 17, 23, 1, 11, 4, 0, 7, 4, {67,85,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Cuba
+ { 270, 66, 69, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 291, 4855, 2, 9, 5900, 5982, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 3, 15, 4, 6, 7, 20, {68,79,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Dominican Republic
+ { 270, 66, 70, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 10, 4870, 2, 65, 5900, 5373, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 20, 4, 5, 7, 7, {85,83,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Ecuador
+ { 270, 66, 72, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 10, 4870, 2, 0, 5900, 6002, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 20, 4, 0, 7, 11, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/El Salvador
+ { 270, 66, 73, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 99, 1,21937,21937,21989,21989,18883,18883, 132, 128, 0, 5, 22, 11, 4890, 2, 0, 5900, 6013, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 14, 4, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 4, 28, 4, 0, 7, 17, {88,65,70}, 0, 0, 1, 6, 7, 2, 3, 3 }, // Spanish/Latin/Equatorial Guinea
+ { 270, 66, 99, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 79, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 246, 4918, 2, 0, 5900, 6030, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 7, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 7, 4, 0, 7, 9, {71,84,81}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Guatemala
+ { 270, 66, 106, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1730, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 18, 4925, 2, 0, 5900, 6039, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 17, 4, 0, 7, 8, {72,78,76}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Honduras
+ { 270, 66, 130, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 168, 168, 0, 5, 22, 0, 0, 2, 0, 6047, 6070, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 4, 4, 5, 17, 23, 0, 0, 4, 0, 23, 13, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Latin America
+ { 270, 66, 152, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 78, 23, 38,21937,21937,21989,21989, 6778, 6778, 168, 168, 0, 5, 22, 10, 4942, 2, 0, 6083, 6100, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 15, 7, 52, 52, 27, 27, 13, 13, 4, 4, 5, 17, 23, 1, 13, 4, 0, 17, 6, {77,88,78}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Mexico
+ { 270, 66, 168, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 294, 4955, 2, 0, 5900, 6106, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 2, 20, 4, 0, 7, 9, {78,73,79}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Nicaragua
+ { 270, 66, 181, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 1121, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 296, 4975, 2, 0, 5900, 6115, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 3, 15, 4, 0, 7, 6, {80,65,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Panama
+ { 270, 66, 183, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 299, 4990, 15, 86, 5900, 6121, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 3, 17, 5, 6, 7, 8, {80,89,71}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Paraguay
+ { 270, 66, 184, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 79, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 279, 5007, 15, 0, 5900, 5362, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 7, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 2, 11, 5, 0, 7, 4, {80,69,78}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Peru
+ { 270, 66, 185, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989,18883,18883, 132, 128, 0, 5, 22, 146, 5018, 4, 0, 5900, 6129, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 13, 5, 0, 7, 9, {80,72,80}, 2, 1, 7, 6, 7, 2, 3, 3 }, // Spanish/Latin/Philippines
+ { 270, 66, 189, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 1121, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 10, 4870, 2, 0, 5900, 2080, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 20, 4, 0, 7, 11, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Puerto Rico
+ { 270, 66, 248, 0, 0, 68, 68, 6, 0, 1, 2, 3, 4, 5, 10, 11, 12, 14, 15, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 168, 168, 0, 5, 22, 10, 4870, 2, 0, 5900, 6138, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 8, 15, 7, 52, 52, 27, 27, 13, 13, 4, 4, 5, 17, 23, 1, 20, 4, 0, 7, 14, {85,83,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/United States
+ { 270, 66, 250, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 10, 5031, 15, 58, 5900, 6152, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 1, 13, 5, 7, 7, 7, {85,89,85}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Spanish/Latin/Uruguay
+ { 270, 66, 254, 0, 0, 68, 68, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 958, 129, 23, 38,21937,21937,21989,21989, 6778, 6778, 132, 128, 0, 5, 22, 302, 5044, 2, 65, 5900, 6159, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 27, 6, 15, 7, 52, 52, 27, 27, 13, 13, 5, 5, 5, 17, 23, 4, 16, 4, 5, 7, 9, {86,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Spanish/Latin/Venezuela
+ { 271, 135, 159, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 15, 113, 129, 10, 0,22029,22029,22076,22076, 83, 83, 692, 723, 0, 5, 22, 0, 5060, 0, 0, 6168, 6176, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 47, 47, 29, 29, 13, 13, 6, 8, 4, 17, 23, 0, 14, 4, 0, 8, 6, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Standard Moroccan Tamazight/Tifinagh/Morocco
+ { 272, 66, 111, 0, 0, 1090, 1103, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 213, 213,22105,22105,22148,22148, 9291, 9291, 0, 0, 0, 5, 22, 186, 5074, 2, 0, 6182, 1776, 6, 6, 13, 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 12, 4, 43, 43, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 15, 4, 0, 10, 9, {73,68,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Sundanese/Latin/Indonesia
+ { 273, 66, 230, 0, 0, 566, 566, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 1198, 1198, 1198, 1198, 83, 83, 0, 0, 749, 1033, 22, 121, 3492, 15, 0, 6192, 2268, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 59, 59, 59, 59, 13, 13, 2, 2, 5, 51, 23, 3, 20, 5, 0, 9, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Swahili/Latin/Tanzania
+ { 273, 66, 57, 0, 0, 566, 566, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 1198, 1198, 1198, 1198, 83, 83, 0, 0, 749, 1033, 22, 11, 5089, 15, 0, 6192, 6201, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 59, 59, 59, 59, 13, 13, 2, 2, 5, 51, 23, 2, 16, 5, 0, 9, 32, {67,68,70}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Swahili/Latin/Congo - Kinshasa
+ { 273, 66, 124, 0, 0, 566, 566, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 1198, 1198, 1198, 1198, 83, 83, 0, 0, 749, 1033, 22, 176, 991, 15, 0, 6192, 1307, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 59, 59, 59, 59, 13, 13, 2, 2, 5, 51, 23, 3, 17, 5, 0, 9, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Swahili/Latin/Kenya
+ { 273, 66, 243, 0, 0, 566, 566, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0, 1198, 1198, 1198, 1198, 83, 83, 0, 0, 749, 1033, 22, 147, 5105, 15, 0, 6192, 983, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 59, 59, 59, 59, 13, 13, 2, 2, 5, 51, 23, 3, 18, 5, 0, 9, 6, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Swahili/Latin/Uganda
+ { 274, 66, 216, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 10, 0,22175,22175,22242,22242, 83, 83, 0, 0, 0, 5, 22, 9, 0, 2, 0, 6233, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 67, 67, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 7, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Swati/Latin/South Africa
+ { 274, 66, 76, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 23, 38,22175,22175,22242,22242, 83, 83, 0, 0, 0, 5, 22, 155, 0, 2, 0, 6233, 6240, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 67, 67, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 7, 8, {83,90,76}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Swati/Latin/Eswatini
+ { 275, 66, 225, 0, 0, 1115, 1115, 6, 1, 9, 2, 3, 48, 5, 63, 15, 15, 17, 17, 113, 103, 10, 0,22268,22268,22317,22317, 4874, 4874, 698, 731, 0, 5, 22, 160, 5123, 4, 0, 6248, 6255, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 16, 10, 13, 5, 49, 49, 28, 28, 13, 13, 2, 2, 4, 17, 23, 2, 12, 5, 0, 7, 7, {83,69,75}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Swedish/Latin/Sweden
+ { 275, 66, 2, 0, 0, 1115, 1115, 6, 1, 9, 2, 3, 48, 5, 63, 15, 15, 17, 17, 113, 103, 10, 0,22268,22268,22317,22317, 4874, 4874, 698, 731, 0, 5, 22, 22, 405, 4, 0, 6248, 6262, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 16, 10, 13, 5, 49, 49, 28, 28, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 7, 5, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Swedish/Latin/Aland Islands
+ { 275, 66, 83, 0, 0, 1115, 1115, 6, 1, 9, 2, 3, 48, 5, 63, 15, 15, 17, 17, 113, 103, 10, 0,22268,22268,22317,22317, 4874, 4874, 698, 731, 0, 5, 22, 22, 405, 4, 0, 6248, 1698, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 16, 10, 13, 5, 49, 49, 28, 28, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 7, 7, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Swedish/Latin/Finland
+ { 276, 66, 226, 0, 0, 463, 463, 6, 0, 17, 2, 3, 48, 5, 10, 11, 12, 19, 20, 404, 49, 10, 0,22345,22345,22407,22407, 4510, 4510, 700, 733, 0, 5, 22, 0, 5135, 4, 0, 6267, 6267, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 62, 62, 27, 27, 13, 13, 12, 11, 4, 17, 23, 0, 16, 5, 0, 16, 7, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Swiss German/Latin/Switzerland
+ { 276, 66, 84, 0, 0, 463, 463, 6, 0, 17, 2, 3, 48, 5, 10, 11, 12, 19, 20, 404, 49, 10, 0,22345,22345,22407,22407, 4510, 4510, 700, 733, 0, 5, 22, 22, 83, 4, 0, 6267, 6283, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 62, 62, 27, 27, 13, 13, 12, 11, 4, 17, 23, 1, 4, 5, 0, 16, 10, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Swiss German/Latin/France
+ { 276, 66, 136, 0, 0, 463, 463, 6, 0, 17, 2, 3, 48, 5, 10, 11, 12, 19, 20, 404, 49, 10, 0,22345,22345,22407,22407, 4510, 4510, 700, 733, 0, 5, 22, 0, 5135, 4, 0, 6267, 6293, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 62, 62, 27, 27, 13, 13, 12, 11, 4, 17, 23, 0, 16, 5, 0, 16, 13, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Swiss German/Latin/Liechtenstein
+ { 277, 123, 113, 1124, 1124, 1124, 1124, 6, 0, 1, 2, 3, 4, 5, 10, 15, 14, 17, 16, 1757, 395, 61, 76,22434,22434,22486,22486,22515,22515, 712, 744, 1084, 5, 22, 0, 0, 15, 0, 6306, 6312, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 9, 15, 7, 52, 52, 29, 29, 13, 13, 4, 4, 4, 17, 23, 0, 0, 5, 0, 6, 4, {73,81,68}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Syriac/Syriac/Iraq
+ { 277, 123, 227, 1124, 1124, 1124, 1124, 6, 0, 1, 2, 3, 4, 5, 10, 15, 14, 17, 16, 1757, 395, 61, 76,22434,22434,22486,22486,22515,22515, 712, 744, 1084, 5, 22, 99, 0, 15, 0, 6306, 6316, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 9, 15, 7, 52, 52, 29, 29, 13, 13, 4, 4, 4, 17, 23, 5, 0, 5, 0, 6, 5, {83,89,80}, 0, 0, 6, 5, 6, 1, 3, 3 }, // Syriac/Syriac/Syria
+ { 278, 135, 159, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 15, 113, 129, 10, 0,22528,22528,22076,22076, 83, 83, 692, 723, 0, 5, 22, 0, 5060, 0, 0, 6321, 6176, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 46, 46, 29, 29, 13, 13, 6, 8, 4, 17, 23, 0, 14, 4, 0, 7, 6, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tachelhit/Tifinagh/Morocco
+ { 278, 66, 159, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 13, 15, 113, 129, 10, 0,22574,22574,22621,22621, 83, 83, 716, 748, 0, 5, 22, 0, 5151, 0, 0, 6328, 6338, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 47, 47, 29, 29, 13, 13, 6, 8, 4, 17, 23, 0, 14, 4, 0, 10, 6, {77,65,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tachelhit/Latin/Morocco
+ { 280, 127, 255, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 306, 0, 15, 0, 6344, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 4, 0, {86,78,68}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Tai Dam/Tai Viet/Vietnam
+ { 281, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,22650,22650,22754,22754,22781,22781, 722, 756, 0, 5, 22, 176, 991, 2, 9, 6348, 1307, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5,104,104, 27, 27, 13, 13, 10, 10, 4, 17, 23, 3, 17, 4, 6, 7, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Taita/Latin/Kenya
+ { 282, 27, 229, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 12, 11, 16, 17, 786, 78, 10, 0,22794,22794,22848,22848,22875,22875, 0, 0, 0, 5, 22, 307, 5165, 4, 0, 6355, 6361, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 54, 54, 27, 27, 13, 13, 2, 2, 4, 17, 23, 4, 6, 5, 0, 6, 10, {84,74,83}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tajik/Cyrillic/Tajikistan
+ { 283, 129, 110, 0, 0, 1130, 1130, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 127, 127,22888,22888,22936,22936,22974,22974, 0, 766, 1088, 5, 22, 120, 5171, 2, 9, 6371, 6376, 6, 6, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 48, 48, 38, 38, 19, 19, 2, 8, 7, 17, 23, 1, 13, 4, 6, 5, 7, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Tamil/Tamil/India
+ { 283, 129, 143, 0, 0, 1130, 1130, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 127, 127,22888,22888,22936,22936,22974,22974, 0, 766, 1088, 5, 22, 192, 5184, 2, 9, 6371, 6383, 6, 6, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 48, 48, 38, 38, 19, 19, 2, 8, 7, 17, 23, 2, 17, 4, 6, 5, 7, {77,89,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tamil/Tamil/Malaysia
+ { 283, 129, 210, 0, 0, 1130, 1130, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 127, 127,22888,22888,22936,22936,22974,22974, 0, 766, 1088, 5, 22, 10, 5201, 2, 9, 6371, 6390, 6, 6, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 48, 48, 38, 38, 19, 19, 2, 8, 7, 17, 23, 1, 17, 4, 6, 5, 11, {83,71,68}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Tamil/Tamil/Singapore
+ { 283, 129, 221, 0, 0, 1130, 1130, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 10, 0,22888,22888,22936,22936,22974,22974, 0, 766, 1088, 5, 22, 311, 5218, 2, 9, 6371, 6401, 6, 6, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 13, 5, 48, 48, 38, 38, 19, 19, 2, 8, 7, 17, 23, 3, 13, 4, 6, 5, 6, {76,75,82}, 2, 1, 1, 6, 7, 1, 2, 3 }, // Tamil/Tamil/Sri Lanka
+ { 284, 66, 228, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 137, 103, 23, 38,22993,22993,23164,23164,23191,23191, 0, 0, 0, 5, 22, 314, 5231, 15, 0, 6407, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 15, 7,171,171, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 11, 5, 0, 12, 0, {84,87,68}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Taroko/Latin/Taiwan
+ { 285, 66, 170, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0,11682,11682,11735,11735,11762,11762, 732, 774, 0, 5, 22, 127, 3285, 0, 0, 6419, 6432, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 53, 53, 27, 27, 13, 13, 8, 10, 4, 17, 23, 5, 16, 4, 0, 13, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Tasawaq/Latin/Niger
+ { 286, 27, 193, 0, 0, 1143, 1143, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1775, 49, 11, 1,23204,23204,23259,23259,23294,23294, 0, 0, 0, 5, 22, 133, 5242, 4, 0, 6437, 5457, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 12, 4, 55, 55, 35, 35, 13, 13, 2, 2, 4, 17, 23, 1, 11, 5, 0, 5, 6, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tatar/Cyrillic/Russia
+ { 287, 131, 110, 0, 0, 1152, 1152, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1798, 394, 61, 76,23307,23307,23366,23366,23397,23397, 0, 0, 1095, 1102, 22, 120, 5253, 2, 9, 6442, 6448, 6, 6, 11, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 15, 7, 59, 59, 31, 31, 17, 17, 2, 2, 7, 29, 23, 1, 14, 4, 6, 6, 8, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Telugu/Telugu/India
+ { 288, 66, 243, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,23414,23414,23482,23482,23509,23509, 740, 784, 0, 5, 22, 147, 5267, 2, 9, 6456, 983, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 68, 68, 27, 27, 13, 13, 9, 6, 4, 17, 23, 3, 21, 4, 6, 6, 6, {85,71,88}, 0, 0, 1, 7, 7, 1, 3, 3 }, // Teso/Latin/Uganda
+ { 288, 66, 124, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,23414,23414,23482,23482,23509,23509, 740, 784, 0, 5, 22, 176, 5288, 2, 9, 6456, 6462, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 68, 68, 27, 27, 13, 13, 9, 6, 4, 17, 23, 3, 20, 4, 6, 6, 5, {75,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Teso/Latin/Kenya
+ { 289, 133, 231, 24, 24, 1163, 1171, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1816, 129, 542, 0,23522,23522,23589,23589,23611,23611, 749, 790, 1131, 5, 22, 317, 5308, 2, 9, 6467, 6467, 5, 5, 8, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 6, 31, 5, 67, 67, 22, 22, 15, 15, 10, 10, 4, 17, 23, 1, 3, 4, 6, 3, 3, {84,72,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Thai/Thai/Thailand
+ { 290, 134, 50, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1835, 103, 10, 0,23626,23626,23704,23704,23754,23754, 759, 800, 0, 5, 22, 150, 5311, 15, 0, 6470, 6478, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 13, 5, 78, 78, 50, 50, 26, 26, 7, 8, 4, 17, 23, 1, 6, 5, 0, 8, 6, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tibetan/Tibetan/China
+ { 290, 134, 110, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1835, 103, 61, 76,23626,23626,23704,23704,23754,23754, 759, 800, 0, 5, 22, 120, 5317, 15, 0, 6470, 6484, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 15, 7, 78, 78, 50, 50, 26, 26, 7, 8, 4, 17, 23, 1, 12, 5, 0, 8, 7, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Tibetan/Tibetan/India
+ { 291, 33, 74, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1858, 78, 61, 76,23780,23780,23820,23820,23846,23846, 0, 0, 0, 5, 22, 6, 0, 2, 0, 6491, 671, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 8, 15, 7, 40, 40, 26, 26, 13, 13, 2, 2, 4, 17, 23, 3, 0, 4, 0, 3, 4, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tigre/Ethiopic/Eritrea
+ { 292, 33, 77, 38, 38, 1178, 1178, 6, 0, 1, 2, 3, 4, 5, 10, 11, 12, 14, 15, 1879, 78, 61, 76,23859,23859,23887,23887,23907,23907, 766, 808, 0, 5, 22, 1, 112, 2, 0, 6494, 143, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 15, 7, 28, 28, 20, 20, 13, 13, 4, 4, 4, 17, 23, 2, 2, 4, 0, 4, 5, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Tigrinya/Ethiopic/Ethiopia
+ { 292, 33, 74, 38, 38, 1178, 1178, 6, 0, 1, 2, 3, 4, 5, 10, 16, 17, 14, 15, 1879, 78, 61, 76,23859,23859,23887,23887,23907,23907, 766, 808, 0, 5, 22, 6, 5329, 2, 0, 6494, 671, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 15, 7, 28, 28, 20, 20, 13, 13, 4, 4, 4, 17, 23, 3, 3, 4, 0, 4, 4, {69,82,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tigrinya/Ethiopic/Eritrea
+ { 294, 66, 182, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 787, 78, 573, 589,23920,23920,23964,23964, 83, 83, 0, 0, 0, 5, 22, 0, 0, 4, 0, 6498, 6507, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 16, 8, 44, 44, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 9, 13, {80,71,75}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tok Pisin/Latin/Papua New Guinea
+ { 295, 66, 235, 1185, 1185, 1185, 1185, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 23, 38,23991,23991,24050,24050,24078,24078, 770, 812, 1135, 1140, 1199, 205, 5332, 15, 0, 6520, 2283, 8, 8, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 6, 15, 7, 59, 59, 28, 28, 13, 13, 10, 6, 5, 59, 65, 2, 17, 5, 0, 13, 5, {84,79,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tongan/Latin/Tonga
+ { 296, 66, 216, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 10, 0,24091,24091,24162,24162, 83, 83, 0, 0, 0, 5, 22, 9, 0, 15, 0, 6533, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 71, 71, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 8, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Tsonga/Latin/South Africa
+ { 297, 66, 216, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 10, 0,24188,24188,24251,24251, 83, 83, 0, 0, 0, 5, 22, 9, 0, 2, 0, 6541, 6549, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 63, 63, 31, 31, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 8, 13, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Tswana/Latin/South Africa
+ { 297, 66, 30, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 10, 0,24188,24188,24251,24251, 83, 83, 0, 0, 0, 5, 22, 153, 0, 2, 0, 6541, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 63, 63, 31, 31, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 8, 0, {66,87,80}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Tswana/Latin/Botswana
+ { 298, 66, 239, 0, 0, 1193, 1193, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1896, 50, 10, 0,24282,24282,24335,24335,24362,24362, 780, 818, 185, 5, 22, 126, 5349, 2, 9, 6562, 6568, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 9, 13, 5, 53, 53, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 11, 4, 6, 6, 7, {84,82,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Turkish/Latin/Turkey
+ { 298, 66, 63, 0, 0, 1193, 1193, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1896, 50, 23, 38,24282,24282,24335,24335,24362,24362, 780, 818, 185, 5, 22, 22, 83, 2, 9, 6562, 6575, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 9, 15, 7, 53, 53, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 4, 6, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Turkish/Latin/Cyprus
+ { 299, 66, 240, 0, 0, 1201, 1201, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 14, 15, 1896, 49, 10, 0,24375,24428,24481,24508,24535,24535, 782, 820, 1264, 5, 22, 0, 5360, 4, 0, 6581, 6593, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 10, 13, 5, 53, 53, 27, 27, 13, 13, 13, 14, 4, 17, 23, 0, 14, 5, 0, 12, 12, {84,77,84}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Turkmen/Latin/Turkmenistan
+ { 301, 66, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 137, 155, 10, 0,24548,24548,24589,24589, 83, 83, 0, 0, 0, 5, 22, 124, 5374, 15, 0, 6605, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 41, 41, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 5, 0, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Tyap/Latin/Nigeria
+ { 303, 27, 244, 0, 0, 117, 117, 6, 1, 9, 2, 3, 4, 5, 85, 11, 12, 13, 14, 1912, 49, 10, 0,24616,24671, 3049, 3049, 4289, 4289, 795, 834, 1268, 841, 22, 286, 5378, 4, 0, 6610, 6620, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 8, 13, 5, 55, 55, 20, 20, 13, 13, 2, 2, 5, 17, 23, 1, 17, 5, 0, 10, 7, {85,65,72}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ukrainian/Cyrillic/Ukraine
+ { 304, 66, 91, 0, 0, 781, 781, 6, 1, 0, 2, 3, 4, 5, 10, 13, 14, 18, 16, 404, 180, 11, 597,24726,24726,24778,24778,24805,24805, 402, 836, 1273, 5, 22, 22, 405, 4, 0, 6627, 6642, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 12, 12, 52, 52, 27, 27, 13, 13, 9, 9, 5, 17, 23, 1, 4, 5, 0, 15, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Upper Sorbian/Latin/Germany
+ { 305, 4, 178, 661, 661, 1209, 1219, 6, 0, 1, 2, 3, 35, 37, 10, 15, 14, 17, 16, 1934, 129, 61, 76,24818,24818,24818,24818, 83, 83, 0, 0, 1278, 1282, 22, 196, 5395, 2, 9, 6648, 5140, 6, 6, 10, 9, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 18, 6, 15, 7, 35, 35, 35, 35, 13, 13, 2, 2, 4, 20, 23, 2, 14, 4, 6, 4, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Urdu/Arabic/Pakistan
+ { 305, 4, 110, 661, 661, 1209, 1219, 6, 21, 22, 2, 40, 35, 41, 44, 15, 14, 17, 16, 1934, 129, 61, 76,24818,24818,24818,24818, 83, 83, 0, 0, 1278, 1282, 22, 120, 5409, 2, 9, 6648, 6652, 6, 6, 10, 9, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 18, 6, 15, 7, 35, 35, 35, 35, 13, 13, 2, 2, 4, 20, 23, 1, 12, 4, 6, 4, 5, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Urdu/Arabic/India
+ { 306, 4, 50, 0, 0, 323, 333, 6, 0, 1, 2, 3, 4, 5, 10, 12, 11, 20, 19, 1952, 103, 10, 0,24853,24853,24907,24907,24927,24927, 797, 845, 0, 5, 22, 145, 5421, 2, 9, 6657, 6665, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 54, 54, 20, 20, 13, 13, 12, 12, 4, 17, 23, 1, 11, 4, 6, 8, 5, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Uyghur/Arabic/China
+ { 307, 66, 251, 0, 0, 1228, 1228, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 17, 16, 1969, 78, 99, 0,24940,24940,25000,25000,25031,25031, 360, 857, 185, 5, 22, 318, 5432, 2, 9, 6670, 6676, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 14, 5, 60, 60, 31, 31, 13, 13, 2, 2, 4, 17, 23, 4, 17, 4, 6, 6, 11, {85,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Uzbek/Latin/Uzbekistan
+ { 307, 4, 1, 0, 0, 0, 0, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 1987, 505, 99, 1,18196,18196,25044,25044, 83, 83, 0, 0, 0, 5, 22, 270, 3963, 4, 0, 6687, 5131, 6, 6, 6, 6, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 33, 8, 14, 4, 48, 48, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 6, 5, 0, 6, 9, {65,70,78}, 0, 0, 6, 4, 5, 1, 3, 3 }, // Uzbek/Arabic/Afghanistan
+ { 307, 27, 251, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1008, 78, 98, 0,25064,25064,25116,25116,25143,25143, 809, 859, 0, 5, 22, 322, 5449, 4, 0, 6693, 6700, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 15, 5, 52, 52, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 14, 5, 0, 7, 10, {85,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Uzbek/Cyrillic/Uzbekistan
+ { 308, 139, 134, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 61, 76,25156,25156,25156,25156, 83, 83, 0, 0, 0, 5, 22, 10, 5463, 2, 9, 6710, 6712, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 29, 29, 29, 29, 13, 13, 2, 2, 4, 17, 23, 1, 8, 4, 6, 2, 4, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Vai/Vai/Liberia
+ { 308, 66, 134, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38,25185,25185,25185,25185, 83, 83, 0, 0, 0, 5, 22, 10, 5471, 2, 9, 6716, 6719, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 47, 47, 47, 47, 13, 13, 2, 2, 4, 17, 23, 1, 13, 4, 6, 3, 8, {76,82,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Vai/Latin/Liberia
+ { 309, 66, 216, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 16, 17, 14, 15, 163, 103, 10, 0,25232,25232,25301,25301, 83, 83, 0, 0, 0, 5, 22, 9, 0, 2, 0, 6727, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 69, 69, 26, 26, 13, 13, 2, 2, 4, 17, 23, 1, 0, 4, 0, 9, 0, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Venda/Latin/South Africa
+ { 310, 66, 255, 0, 0, 1236, 1236, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 10, 0,25327,25327,25381,25381,25413,25413, 811, 861, 0, 5, 22, 306, 5484, 4, 0, 6736, 6746, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 13, 5, 54, 54, 32, 32, 20, 20, 2, 2, 4, 17, 23, 1, 13, 5, 0, 10, 8, {86,78,68}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Vietnamese/Latin/Vietnam
+ { 311, 66, 258, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 2020, 103, 10, 0,25433,25433,25475,25495,25522,25522, 0, 0, 0, 5, 22, 0, 0, 15, 0, 6754, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 13, 5, 42, 42, 20, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 7, 0, {0,0,0}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Volapuk/Latin/world
+ { 312, 66, 230, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,13800,13800,13861,13861, 1284, 1284, 430, 446, 0, 5, 22, 121, 3492, 2, 0, 6761, 2268, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 61, 61, 27, 27, 13, 13, 5, 9, 4, 17, 23, 3, 20, 4, 0, 8, 8, {84,90,83}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Vunjo/Latin/Tanzania
+ { 313, 66, 23, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 22, 0, 15, 0, 6769, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 5, 0, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Walloon/Latin/Belgium
+ { 314, 66, 226, 0, 0, 463, 463, 6, 1, 17, 2, 3, 4, 5, 10, 11, 12, 19, 20, 404, 103, 10, 0,25535,25535,25587,25587,25614,25614, 0, 0, 0, 5, 22, 0, 0, 15, 0, 6774, 6780, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 10, 13, 5, 52, 52, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 6, 6, {67,72,70}, 2, 0, 1, 6, 7, 1, 3, 3 }, // Walser/Latin/Switzerland
+ { 315, 66, 15, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 241, 0, 15, 0, 6786, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 0, 5, 0, 8, 0, {65,85,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Warlpiri/Latin/Australia
+ { 316, 66, 246, 0, 0, 1244, 1255, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 78, 10, 0,25627,25627,25703,25731,25760,25760, 813, 863, 1302, 5, 22, 94, 5497, 2, 9, 6794, 6801, 6, 6, 11, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 13, 5, 76, 76, 28, 29, 14, 14, 2, 2, 7, 17, 23, 1, 12, 4, 6, 7, 16, {71,66,80}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Welsh/Latin/United Kingdom
+ { 317, 4, 178, 661, 661, 971, 979, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 196, 5509, 15, 0, 6817, 0, 6, 6, 8, 7, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 2, 13, 5, 0, 14, 0, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Western Balochi/Arabic/Pakistan
+ { 317, 4, 1, 661, 661, 971, 979, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 270, 5522, 15, 0, 6817, 0, 6, 6, 8, 7, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 17, 5, 0, 14, 0, {65,70,78}, 0, 0, 6, 4, 5, 1, 3, 3 }, // Western Balochi/Arabic/Afghanistan
+ { 317, 4, 112, 661, 661, 971, 979, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 271, 5539, 15, 0, 6817, 0, 6, 6, 8, 7, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 4, 11, 5, 0, 14, 0, {73,82,82}, 0, 0, 6, 5, 5, 1, 3, 3 }, // Western Balochi/Arabic/Iran
+ { 317, 4, 176, 661, 661, 971, 979, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 6817, 6831, 6, 6, 8, 7, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 14, 5, {79,77,82}, 3, 0, 6, 5, 6, 1, 3, 3 }, // Western Balochi/Arabic/Oman
+ { 317, 4, 245, 661, 661, 971, 979, 67, 21, 22, 23, 40, 35, 41, 44, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 0, 0, 15, 0, 6817, 6836, 6, 6, 8, 7, 1, 1, 1, 1, 1, 3, 3, 4, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 0, 0, 5, 0, 14, 19, {65,69,68}, 2, 1, 6, 6, 7, 1, 3, 3 }, // Western Balochi/Arabic/United Arab Emirates
+ { 318, 66, 165, 0, 0, 16, 16, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 394, 10, 0,25774,25774,25827,25827, 83, 83, 0, 0, 0, 5, 22, 22, 83, 15, 58, 6855, 6860, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 53, 53, 20, 20, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 7, 5, 8, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Western Frisian/Latin/Netherlands
+ { 319, 33, 77, 0, 0, 0, 0, 6, 0, 17, 2, 3, 4, 5, 10, 14, 15, 16, 17, 2043, 78, 61, 76,25847,25847,25847,25847,25873,25873, 0, 0, 0, 5, 22, 1, 105, 2, 0, 6868, 143, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 22, 8, 15, 7, 26, 26, 26, 26, 13, 13, 2, 2, 4, 17, 23, 2, 9, 4, 0, 5, 5, {69,84,66}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Wolaytta/Ethiopic/Ethiopia
+ { 320, 66, 206, 0, 0, 0, 0, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 2065, 394, 10, 0,25886,25886,25935,25935,25935,25935, 732, 865, 0, 5, 22, 127, 5550, 15, 0, 6873, 2999, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 49, 49, 27, 27, 27, 27, 3, 3, 4, 17, 23, 5, 29, 5, 0, 5, 8, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Wolof/Latin/Senegal
+ { 321, 66, 216, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 0,25962,25962,26022,26049,26078,26098, 0, 0, 0, 5, 22, 9, 5579, 2, 0, 6878, 6886, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 13, 5, 60, 60, 27, 29, 20, 21, 2, 2, 4, 17, 23, 1, 25, 4, 0, 8, 15, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Xhosa/Latin/South Africa
+ { 322, 66, 40, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 11, 12, 113, 129, 10, 0,26119,26119,26189,26189,26209,26209, 815, 868, 0, 5, 22, 11, 0, 4, 20, 6901, 6907, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 70, 70, 20, 20, 13, 13, 8, 8, 4, 17, 23, 4, 0, 5, 7, 6, 7, {88,65,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Yangben/Latin/Cameroon
+ { 323, 47, 244, 0, 0, 1265, 1265, 6, 0, 1, 2, 3, 4, 5, 10, 15, 15, 17, 17, 2082, 78, 10, 0,26222,26222,26222,26222, 83, 83, 823, 876, 0, 5, 22, 286, 0, 15, 0, 6914, 6920, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 8, 13, 5, 53, 53, 53, 53, 13, 13, 11, 10, 4, 17, 23, 1, 0, 5, 0, 6, 9, {85,65,72}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Yiddish/Hebrew/Ukraine
+ { 324, 66, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 2101, 129, 10, 1,26275,26318,26386,26386,26418,26418, 834, 886, 1309, 1320, 22, 124, 5604, 2, 9, 6929, 6939, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 3, 43, 68, 32, 32, 13, 13, 5, 5, 11, 37, 23, 1, 14, 4, 6, 10, 8, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Yoruba/Latin/Nigeria
+ { 324, 66, 25, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 2101, 129, 10, 1,26431,26474,26542,26542,26574,26574, 839, 891, 1357, 1320, 22, 127, 5618, 2, 9, 6929, 6947, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 3, 43, 68, 32, 32, 13, 13, 5, 5, 11, 37, 23, 5, 26, 4, 6, 10, 6, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Yoruba/Latin/Benin
+ { 325, 66, 170, 0, 0, 0, 0, 6, 0, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 129, 10, 0,26587,26587,11735,11735,26639,26639, 732, 774, 0, 5, 22, 127, 3285, 0, 0, 6953, 6432, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 52, 52, 27, 27, 13, 13, 8, 10, 4, 17, 23, 5, 16, 4, 0, 10, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Zarma/Latin/Niger
+ { 326, 66, 50, 0, 0, 1274, 1274, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0,26652,26652,26652,26652, 83, 83, 844, 896, 0, 5, 22, 150, 5644, 15, 0, 6963, 6972, 6, 6, 11, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 89, 89, 89, 89, 13, 13, 7, 12, 4, 17, 23, 1, 10, 5, 0, 9, 8, {67,78,89}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Zhuang/Latin/China
+ { 327, 66, 216, 0, 0, 1285, 1294, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 549, 567, 10, 0,26741,26741,26814,26814,26841,26841, 0, 0, 0, 5, 22, 9, 5654, 2, 9, 6980, 6987, 6, 6, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 13, 5, 73, 73, 27, 27, 13, 13, 2, 2, 5, 17, 23, 1, 20, 4, 6, 7, 17, {90,65,82}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Zulu/Latin/South Africa
+ { 328, 66, 32, 0, 0, 1302, 1302, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 2117, 186, 10, 0,26854,26854,26940,26940,26974,26974, 0, 0, 1368, 5, 22, 9, 5674, 15, 0, 7004, 7011, 6, 6, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 10, 13, 5, 86, 86, 34, 34, 20, 20, 2, 2, 7, 17, 23, 2, 12, 5, 0, 7, 6, {66,82,76}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Kaingang/Latin/Brazil
+ { 329, 66, 32, 0, 0, 1311, 1311, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 10, 0,26994,26994,27058,27058,27085,27085, 0, 0, 1375, 5, 22, 9, 5686, 15, 0, 7017, 7025, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 64, 64, 27, 27, 13, 13, 2, 2, 8, 17, 23, 2, 15, 5, 0, 8, 6, {66,82,76}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Nheengatu/Latin/Brazil
+ { 329, 66, 54, 0, 0, 1311, 1311, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38,26994,26994,27058,27058,27085,27085, 132, 128, 1375, 5, 22, 10, 5701, 15, 0, 7031, 7038, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 64, 64, 27, 27, 13, 13, 5, 5, 8, 17, 23, 1, 17, 5, 0, 7, 8, {67,79,80}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Nheengatu/Latin/Colombia
+ { 329, 66, 254, 0, 0, 1311, 1311, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 186, 23, 38,26994,26994,27058,27058,27085,27085, 132, 128, 1375, 5, 22, 302, 5718, 15, 0, 7031, 7046, 6, 6, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 64, 64, 27, 27, 13, 13, 5, 5, 8, 17, 23, 4, 22, 5, 0, 7, 9, {86,69,83}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Nheengatu/Latin/Venezuela
+ { 330, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 163, 103, 61, 76,27098,27098,27098,27098, 83, 83, 851, 83, 0, 5, 22, 120, 0, 15, 0, 7055, 664, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 54, 54, 54, 54, 13, 13, 4, 4, 4, 17, 23, 1, 0, 5, 0, 8, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Haryanvi/Devanagari/India
+ { 331, 66, 91, 0, 0, 915, 915, 6, 1, 0, 2, 3, 4, 5, 10, 14, 15, 16, 17, 404, 78, 10, 0,27152,27152,27208,27208, 83, 83, 0, 0, 0, 5, 22, 22, 83, 15, 0, 7063, 7073, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 8, 13, 5, 56, 56, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 0, 10, 9, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Northern Frisian/Latin/Germany
+ { 332, 29, 110, 0, 0, 0, 0, 6, 0, 1, 2, 49, 4, 5, 10, 14, 15, 16, 17, 163, 103, 61, 76, 8522, 8522, 8522, 8522, 83, 83, 855, 908, 0, 5, 22, 120, 0, 15, 0, 7082, 664, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 52, 52, 52, 52, 13, 13, 5, 4, 4, 17, 23, 1, 0, 5, 0, 9, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 3, 3 }, // Rajasthani/Devanagari/India
+ { 333, 27, 193, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 133, 0, 15, 0, 7091, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 12, 0, {82,85,66}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Moksha/Cyrillic/Russia
+ { 334, 66, 258, 0, 0, 0, 0, 6, 1, 9, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0,27235,27235,27235,27235, 83, 83, 860, 912, 0, 5, 22, 0, 0, 2, 0, 7103, 7112, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 90, 90, 90, 90, 13, 13, 12, 12, 4, 17, 23, 0, 0, 4, 0, 9, 6, {0,0,0}, 2, 1, 1, 6, 7, 1, 2, 2 }, // Toki Pona/Latin/world
+ { 335, 66, 214, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0,27325,27325,27325,27325, 83, 83, 0, 0, 0, 5, 22, 10, 0, 15, 0, 7118, 7123, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 46, 46, 46, 46, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 5, 13, {83,66,68}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Pijin/Latin/Solomon Islands
+ { 336, 66, 169, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 0, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 124, 0, 15, 0, 7136, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 5, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 5, 0, {78,71,78}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Obolo/Latin/Nigeria
+ { 337, 4, 178, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 367, 383,27371,27371,27417,27417, 83, 83, 0, 0, 0, 5, 22, 196, 5395, 15, 0, 7141, 5140, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 16, 8, 46, 46, 24, 24, 13, 13, 2, 2, 4, 17, 23, 2, 13, 5, 0, 5, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Baluchi/Arabic/Pakistan
+ { 337, 66, 178, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 265, 129, 573, 589,27441,27441,27511,27511, 83, 83, 0, 0, 0, 5, 22, 196, 5740, 15, 0, 7146, 7153, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 16, 8, 70, 70, 26, 26, 13, 13, 2, 2, 4, 17, 23, 2, 14, 5, 0, 7, 8, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Baluchi/Latin/Pakistan
+ { 338, 66, 117, 0, 0, 414, 414, 6, 1, 0, 2, 3, 4, 5, 10, 11, 12, 14, 15, 2140, 78, 10, 0,27537,27537,27591,27591,27625,27625, 0, 0, 0, 5, 22, 22, 405, 4, 20, 7161, 3728, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 8, 13, 5, 54, 54, 34, 34, 13, 13, 2, 2, 4, 17, 23, 1, 4, 5, 7, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Ligurian/Latin/Italy
+ { 339, 142, 161, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 10, 1, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 134, 0, 15, 0, 7167, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 13, 4, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 18, 0, {77,77,75}, 0, 0, 7, 6, 7, 1, 3, 3 }, // Rohingya/Hanifi/Myanmar
+ { 339, 142, 20, 0, 0, 0, 0, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 163, 103, 61, 76, 56, 56, 56, 56, 83, 83, 0, 0, 0, 5, 22, 132, 0, 15, 0, 7167, 0, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 10, 15, 7, 27, 27, 27, 27, 13, 13, 2, 2, 4, 17, 23, 1, 0, 5, 0, 18, 0, {66,68,84}, 2, 1, 7, 6, 7, 1, 3, 3 }, // Rohingya/Hanifi/Bangladesh
+ { 340, 4, 178, 1321, 1321, 1326, 1335, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 1934, 129, 61, 76,27638,27638,27638,27638,27695,27695, 0, 0, 1278, 1282, 22, 196, 5395, 15, 0, 7185, 5140, 5, 5, 9, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 18, 6, 15, 7, 57, 57, 57, 57, 13, 13, 2, 2, 4, 20, 23, 2, 14, 5, 0, 7, 7, {80,75,82}, 2, 0, 7, 6, 7, 1, 3, 3 }, // Torwali/Arabic/Pakistan
+ { 341, 66, 25, 0, 0, 566, 566, 6, 1, 9, 2, 3, 4, 5, 10, 11, 12, 14, 15, 2161, 2178, 10, 0,27708,27708,27766,27766,27800,27800, 872, 924, 0, 5, 22, 127, 5754, 15, 86, 7192, 7203, 6, 6, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 8, 13, 5, 58, 58, 34, 34, 20, 20, 13, 13, 4, 17, 23, 5, 33, 5, 6, 11, 5, {88,79,70}, 0, 0, 1, 6, 7, 1, 3, 3 }, // Anii/Latin/Benin
+ { 342, 29, 110, 0, 0, 1343, 1353, 6, 0, 1, 2, 3, 4, 5, 10, 14, 15, 16, 17, 0, 129, 61, 76,27820,27820,27872,27872,27905,27905, 885, 937, 0, 5, 22, 120, 5787, 2, 0, 7208, 664, 6, 6, 10, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, 6, 15, 7, 52, 52, 33, 33, 18, 18, 6, 11, 4, 17, 23, 1, 14, 4, 0, 7, 4, {73,78,82}, 2, 1, 7, 7, 7, 1, 2, 3 }, // Kangri/Devanagari/India
+ { 343, 66, 117, 0, 0, 414, 414, 6, 1, 68, 2, 3, 4, 5, 10, 14, 15, 16, 17, 113, 78, 10, 0,27923,27923,27967,27967,27625,27625, 0, 0, 0, 5, 22, 155, 405, 117, 0, 7215, 3728, 6, 6, 7, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 8, 13, 5, 44, 44, 27, 27, 13, 13, 2, 2, 4, 17, 23, 3, 4, 5, 0, 6, 6, {69,85,82}, 2, 1, 1, 6, 7, 1, 3, 3 }, // Venetian/Latin/Italy
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0,0,0}, 0, 0, 0, 0, 0, 0, 0, 0 } // trailing zeros
};
static constexpr char16_t list_pattern_part_data[] = {
-0x25, 0x31, 0x2c, 0x20, 0x25, 0x32, 0x3b, 0x25, 0x31, 0x20, 0x65, 0x6e, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x64, 0x68,
-0x65, 0x20, 0x25, 0x32, 0x25, 0x31, 0x1363, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x12a5, 0x1293, 0x20, 0x25, 0x32, 0x25,
-0x31, 0x20, 0x12a5, 0x1293, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x648, 0x25, 0x32, 0x61b, 0x25, 0x31, 0x20, 0x587, 0x20, 0x25,
-0x32, 0x25, 0x31, 0x20, 0x986, 0x9f0, 0x9c1, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x79, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20,
-0x76, 0x259, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x98f, 0x9ac, 0x982, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x65, 0x74, 0x61,
-0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x456, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x906, 0x930, 0x94b, 0x20, 0x25, 0x32,
-0x25, 0x31, 0x20, 0x906, 0x930, 0x94b, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x69, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x438,
-0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x68, 0x61, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x2d, 0x20, 0x25, 0x32, 0x25, 0x31,
-0x1014, 0x103e, 0x1004, 0x1037, 0x103a, 0x20, 0x25, 0x32, 0x104a, 0x25, 0x31, 0x3001, 0x25, 0x32, 0x25, 0x31, 0x540c, 0x25, 0x32, 0x25,
-0x31, 0x2c, 0x20, 0x75, 0x67, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x75, 0x67, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0xd804,
-0xdd03, 0xd804, 0xdd33, 0xd804, 0xdd03, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x13a0, 0x13b4, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20,
-0x13a0, 0x13b4, 0x20, 0x25, 0x32, 0x25, 0x31, 0x548c, 0x25, 0x32, 0x25, 0x31, 0x53ca, 0x25, 0x32, 0x25, 0x31, 0x20, 0x442, 0x430,
-0x442, 0x430, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x75, 0x6e, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x61, 0xa0, 0x25, 0x32,
-0x25, 0x31, 0x20, 0x6f, 0x67, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x924, 0x947, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20,
-0x924, 0x947, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0xf51, 0xf44, 0xf0b, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x61, 0x6e,
-0x64, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x6b, 0x61, 0x6a, 0x20,
-0x25, 0x32, 0x25, 0x31, 0x20, 0x6a, 0x61, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x6b, 0x70, 0x6c, 0x65, 0x20, 0x25,
-0x32, 0x25, 0x31, 0x20, 0x6b, 0x70, 0x6c, 0x65, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x61, 0x74, 0x20, 0x25, 0x32,
-0x25, 0x31, 0x20, 0x61, 0x74, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x65, 0x74, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x65,
-0x20, 0x25, 0x32, 0x25, 0x31, 0x2e41, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2e41, 0x20, 0xd83a, 0xdd2b, 0x20, 0x25, 0x32, 0x25, 0x31,
-0x20, 0xd83a, 0xdd2b, 0x20, 0x25, 0x32, 0x204f, 0x25, 0x31, 0x20, 0x61, 0x67, 0x75, 0x73, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20,
-0x10d3, 0x10d0, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x75, 0x6e, 0x64, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x3ba, 0x3b1, 0x3b9,
-0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0xa85, 0xaa8, 0xac7, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x64, 0x61, 0x20, 0x25,
-0x32, 0x25, 0x31, 0x20, 0x64, 0x61, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x5d5, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x914,
-0x930, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x914, 0x930, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x61, 0x75, 0x72, 0x20,
-0x25, 0x32, 0x25, 0x31, 0x20, 0x61, 0x75, 0x72, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0xe9, 0x73, 0x20, 0x25, 0x32, 0x25,
-0x31, 0x2c, 0x20, 0x6e, 0x61, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x6e, 0x61, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20,
-0x64, 0x61, 0x6e, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x64, 0x61, 0x6e, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x6c,
-0x61, 0x6e, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x6c, 0x61, 0x6e, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x64, 0x20,
-0x25, 0x32, 0x25, 0x31, 0x20, 0x64, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x61, 0x61, 0x6d, 0x6d, 0x61, 0x20, 0x25, 0x32,
-0x25, 0x31, 0x2c, 0x20, 0xcae, 0xca4, 0xccd, 0xca4, 0xcc1, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0xcae, 0xca4, 0xccd, 0xca4, 0xcc1,
-0x20, 0x25, 0x32, 0x25, 0x31, 0x60c, 0x20, 0x25, 0x32, 0x25, 0x31, 0x60c, 0x20, 0x62a, 0x655, 0x6c1, 0x20, 0x25, 0x32, 0x25,
-0x31, 0x20, 0x62a, 0x655, 0x6c1, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x924, 0x93f, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20,
-0x924, 0x93f, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x436, 0x4d9, 0x43d, 0x435, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x1793, 0x17b7,
-0x1784, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x1793, 0x17b7, 0x1784, 0x200b, 0x25, 0x32, 0x25, 0x31, 0x20, 0xbc0f, 0x20, 0x25, 0x32,
-0x25, 0x31, 0x20, 0xfb, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x436, 0x430, 0x43d, 0x430, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20,
-0xec1, 0xea5, 0xeb0, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x6d, 0x70, 0xe9, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x69, 0x72,
-0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x61, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x61, 0x28, 0x6e, 0x29, 0x20, 0x25, 0x32,
-0x25, 0x31, 0x2c, 0x20, 0x25, 0x32, 0x20, 0xd0e, 0xd28, 0xd4d, 0xd28, 0xd3f, 0xd35, 0x25, 0x31, 0x20, 0xd15, 0xd42, 0xd1f, 0xd3e,
-0xd24, 0xd46, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x75, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x75, 0x20, 0x25, 0x32,
-0x25, 0x31, 0x20, 0x985, 0x9ae, 0x9b8, 0x9c1, 0x982, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x906, 0x923, 0x93f, 0x20, 0x25, 0x32,
-0x25, 0x31, 0x2c, 0x25, 0x32, 0x25, 0x31, 0x20, 0x930, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x14b, 0x301, 0x67, 0x25b,
-0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x1e3f, 0x62, 0x25b, 0x6e, 0x20, 0x14b, 0x301, 0x67, 0x25b, 0x20, 0x25, 0x32, 0x25,
-0x31, 0x20, 0x70, 0x254, 0x70, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x61, 0x6e, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20,
-0x61, 0x6e, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x65, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0xb13, 0x20, 0x25,
-0x32, 0x25, 0x31, 0x20, 0xb13, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x4d5, 0x43c, 0x4d5, 0x20, 0x25, 0x32, 0x25, 0x31, 0x60c,
-0x20, 0x627, 0x648, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x627, 0x648, 0x20, 0x25, 0x32, 0x25, 0x31, 0x60c, 0x200f, 0x20, 0x25,
-0x32, 0x25, 0x31, 0x60c, 0x20, 0x648, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x648, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0xa05,
-0xa24, 0xa47, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x219, 0x69, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x443, 0x43e, 0x43d, 0x43d,
-0x430, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x924, 0x925, 0x93e, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x924, 0x925, 0x93e,
-0x20, 0x25, 0x32, 0x25, 0x31, 0x60c, 0x20, 0x6fd, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x6fd, 0x20, 0x25, 0x32, 0x25, 0x31,
-0x2c, 0x20, 0xdc3, 0xdc4, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0xdc3, 0xdc4, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x69, 0x6e,
-0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x69, 0x79, 0x6f, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x73, 0x61, 0x72, 0x65,
-0x6e, 0x67, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x73, 0x61, 0x72, 0x65, 0x6e, 0x67, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20,
-0x6f, 0x63, 0x68, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0xbae, 0xbb1, 0xbcd, 0xbb1, 0xbc1, 0xbae, 0xbcd, 0x20, 0x25, 0x32, 0x25,
-0x31, 0x20, 0x4bb, 0x4d9, 0x43c, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0xc2e, 0xc30, 0xc3f, 0xc2f, 0xc41, 0x20, 0x25, 0x32, 0x25,
-0x31, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0xe41, 0xe25, 0xe30, 0x25, 0x32, 0x25, 0x31, 0xe41, 0xe25, 0xe30, 0x25, 0x32, 0x25,
-0x31, 0x1295, 0x20, 0x25, 0x32, 0x1295, 0x25, 0x31, 0x20, 0x6d, 0x6f, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x76, 0x65, 0x20,
-0x25, 0x32, 0x25, 0x31, 0x20, 0x77, 0x65, 0x20, 0x25, 0x32, 0x25, 0x31, 0x60c, 0x20, 0x627, 0x648, 0x631, 0x20, 0x25, 0x32,
-0x25, 0x31, 0x20, 0x627, 0x648, 0x631, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x76, 0x61, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20,
-0x76, 0xe0, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x61, 0x28, 0x63, 0x29, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x61,
-0x28, 0x63, 0x29, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x5d0, 0x5d5, 0x5df, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x6e,
-0x65, 0x2d, 0x25, 0x32, 0x25, 0x31, 0x20, 0x6e, 0x65, 0x2d, 0x25, 0x32, 0x25, 0x31, 0x20, 0x6b, 0x61, 0x72, 0x20, 0x25,
-0x32, 0x25, 0x31, 0x20, 0x61, 0x73, 0x75, 0xed, 0x20, 0x25, 0x32
+0x25, 0x31, 0x2c, 0x20, 0x25, 0x32, 0x3b, 0x25, 0x31, 0x2d, 0x438, 0x20,
+0x25, 0x32, 0x2d, 0x438, 0x25, 0x31, 0x20, 0x65, 0x6e, 0x20, 0x25, 0x32,
+0x25, 0x31, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x64, 0x68, 0x65, 0x20,
+0x25, 0x32, 0x25, 0x31, 0x1363, 0x20, 0x25, 0x32, 0x25, 0x31, 0x1363, 0x20,
+0x12a5, 0x1293, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x12a5, 0x1293, 0x20, 0x25,
+0x32, 0x25, 0x31, 0x20, 0x648, 0x25, 0x32, 0x61b, 0x25, 0x31, 0x20, 0x79,
+0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x587, 0x20, 0x25, 0x32, 0x25, 0x31,
+0x20, 0x986, 0x9f0, 0x9c1, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x76, 0x259,
+0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x98f, 0x9ac, 0x982, 0x20, 0x25, 0x32,
+0x25, 0x31, 0x20, 0x65, 0x74, 0x61, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20,
+0x456, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x906, 0x930, 0x94b, 0x20,
+0x25, 0x32, 0x25, 0x31, 0x20, 0x906, 0x930, 0x94b, 0x20, 0x25, 0x32, 0x25,
+0x31, 0x20, 0x69, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x438, 0x20, 0x25,
+0x32, 0x25, 0x31, 0x20, 0x68, 0x61, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20,
+0x2d, 0x20, 0x25, 0x32, 0x25, 0x31, 0x1014, 0x103e, 0x1004, 0x1037, 0x103a, 0x20,
+0x25, 0x32, 0x104a, 0x25, 0x31, 0x3001, 0x25, 0x32, 0x25, 0x31, 0x540c, 0x25,
+0x32, 0x25, 0x31, 0x2c, 0x20, 0x75, 0x67, 0x20, 0x25, 0x32, 0x25, 0x31,
+0x20, 0x75, 0x67, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0xd804, 0xdd03, 0xd804,
+0xdd33, 0xd804, 0xdd03, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x13a0, 0x13b4,
+0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x13a0, 0x13b4, 0x20, 0x25, 0x32, 0x25,
+0x31, 0x548c, 0x25, 0x32, 0x25, 0x31, 0x53ca, 0x25, 0x32, 0x25, 0x31, 0x20,
+0x438, 0x486, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x442, 0x430, 0x442, 0x430,
+0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x75, 0x6e, 0x20, 0x25, 0x32, 0x25,
+0x31, 0x20, 0xe8, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x61, 0xa0, 0x25,
+0x32, 0x25, 0x31, 0x20, 0x6f, 0x67, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c,
+0x20, 0x924, 0x947, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x924, 0x947, 0x20,
+0x25, 0x32, 0x25, 0x31, 0x20, 0xf51, 0xf44, 0xf0b, 0x20, 0x25, 0x32, 0x25,
+0x31, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20,
+0x61, 0x6e, 0x64, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x6b, 0x61, 0x6a,
+0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x6a, 0x61, 0x20, 0x25, 0x32, 0x25,
+0x31, 0x2c, 0x20, 0x6b, 0x70, 0x6c, 0x65, 0x20, 0x25, 0x32, 0x25, 0x31,
+0x20, 0x6b, 0x70, 0x6c, 0x65, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20,
+0x6f, 0x67, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x61, 0x74, 0x20,
+0x25, 0x32, 0x25, 0x31, 0x20, 0x61, 0x74, 0x20, 0x25, 0x32, 0x25, 0x31,
+0x20, 0x65, 0x74, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x65, 0x20, 0x25,
+0x32, 0x25, 0x31, 0x2e41, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2e41, 0x20, 0xd83a,
+0xdd2b, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0xd83a, 0xdd2b, 0x20, 0x25, 0x32,
+0x204f, 0x25, 0x31, 0x20, 0x61, 0x67, 0x75, 0x73, 0x20, 0x25, 0x32, 0x25,
+0x31, 0x20, 0x10d3, 0x10d0, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x75, 0x6e,
+0x64, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x3ba, 0x3b1, 0x3b9, 0x20, 0x25,
+0x32, 0x25, 0x31, 0x20, 0xa85, 0xaa8, 0xac7, 0x20, 0x25, 0x32, 0x25, 0x31,
+0x2c, 0x20, 0x64, 0x61, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x64, 0x61,
+0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x5d5, 0x25, 0x32, 0x25, 0x31, 0x2c,
+0x20, 0x914, 0x930, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x914, 0x930, 0x20,
+0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x61, 0x75, 0x72, 0x20, 0x25, 0x32,
+0x25, 0x31, 0x20, 0x61, 0x75, 0x72, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20,
+0xe9, 0x73, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x6e, 0x61, 0x20,
+0x25, 0x32, 0x25, 0x31, 0x20, 0x6e, 0x61, 0x20, 0x25, 0x32, 0x25, 0x31,
+0x2c, 0x20, 0x64, 0x61, 0x6e, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x64,
+0x61, 0x6e, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x6c, 0x61, 0x6e,
+0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x6c, 0x61, 0x6e, 0x20, 0x25, 0x32,
+0x25, 0x31, 0x2c, 0x20, 0x64, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x64,
+0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x61, 0x61, 0x6d, 0x6d, 0x61, 0x20,
+0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0xcae, 0xca4, 0xccd, 0xca4, 0xcc1, 0x20,
+0x25, 0x32, 0x25, 0x31, 0x20, 0xcae, 0xca4, 0xccd, 0xca4, 0xcc1, 0x20, 0x25,
+0x32, 0x25, 0x31, 0x60c, 0x20, 0x25, 0x32, 0x25, 0x31, 0x60c, 0x20, 0x62a,
+0x655, 0x6c1, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x62a, 0x655, 0x6c1, 0x20,
+0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x924, 0x93f, 0x20, 0x25, 0x32, 0x25,
+0x31, 0x20, 0x924, 0x93f, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x436, 0x4d9,
+0x43d, 0x435, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x1793, 0x17b7, 0x1784, 0x20,
+0x25, 0x32, 0x25, 0x31, 0x20, 0x1793, 0x17b7, 0x1784, 0x200b, 0x25, 0x32, 0x25,
+0x31, 0x20, 0xbc0f, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0xfb, 0x20, 0x25,
+0x32, 0x25, 0x31, 0x20, 0x436, 0x430, 0x43d, 0x430, 0x20, 0x25, 0x32, 0x25,
+0x31, 0x20, 0xec1, 0xea5, 0xeb0, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x6d,
+0x70, 0xe9, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x69, 0x72, 0x20, 0x25,
+0x32, 0x25, 0x31, 0x20, 0x61, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x61,
+0x28, 0x6e, 0x29, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x25, 0x32,
+0x20, 0xd0e, 0xd28, 0xd4d, 0xd28, 0xd3f, 0xd35, 0x25, 0x31, 0x20, 0xd15, 0xd42,
+0xd1f, 0xd3e, 0xd24, 0xd46, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x75,
+0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x75, 0x20, 0x25, 0x32, 0x25, 0x31,
+0x20, 0x985, 0x9ae, 0x9b8, 0x9c1, 0x982, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20,
+0x906, 0x923, 0x93f, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x25, 0x32, 0x25,
+0x31, 0x20, 0x930, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x14b, 0x301,
+0x67, 0x25b, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x1e3f, 0x62, 0x25b,
+0x6e, 0x20, 0x14b, 0x301, 0x67, 0x25b, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20,
+0x70, 0x254, 0x70, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x61, 0x6e,
+0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x61, 0x6e, 0x20, 0x25, 0x32, 0x25,
+0x31, 0x2c, 0x20, 0xb13, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0xb13, 0x20,
+0x25, 0x32, 0x25, 0x31, 0x20, 0x4d5, 0x43c, 0x4d5, 0x20, 0x25, 0x32, 0x25,
+0x31, 0x60c, 0x20, 0x627, 0x648, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x627,
+0x648, 0x20, 0x25, 0x32, 0x25, 0x31, 0x60c, 0x200f, 0x20, 0x25, 0x32, 0x25,
+0x31, 0x60c, 0x20, 0x648, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x648, 0x20,
+0x25, 0x32, 0x25, 0x31, 0x20, 0x62, 0x65, 0x20, 0x25, 0x32, 0x25, 0x31,
+0x20, 0xa05, 0xa24, 0xa47, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x219, 0x69,
+0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x443, 0x43e, 0x43d, 0x43d, 0x430, 0x20,
+0x25, 0x32, 0x25, 0x31, 0x2c, 0x20, 0x924, 0x925, 0x93e, 0x20, 0x25, 0x32,
+0x25, 0x31, 0x20, 0x924, 0x925, 0x93e, 0x20, 0x25, 0x32, 0x25, 0x31, 0x60c,
+0x20, 0x6fd, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x6fd, 0x20, 0x25, 0x32,
+0x25, 0x31, 0x2c, 0x20, 0xdc3, 0xdc4, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20,
+0xdc3, 0xdc4, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x69, 0x6e, 0x20, 0x25,
+0x32, 0x25, 0x31, 0x20, 0x69, 0x79, 0x6f, 0x20, 0x25, 0x32, 0x25, 0x31,
+0x2c, 0x20, 0x73, 0x61, 0x72, 0x65, 0x6e, 0x67, 0x20, 0x25, 0x32, 0x25,
+0x31, 0x20, 0x73, 0x61, 0x72, 0x65, 0x6e, 0x67, 0x20, 0x25, 0x32, 0x25,
+0x31, 0x20, 0x6f, 0x63, 0x68, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x718,
+0x25, 0x32, 0x25, 0x31, 0x20, 0xbae, 0xbb1, 0xbcd, 0xbb1, 0xbc1, 0xbae, 0xbcd,
+0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x4bb, 0x4d9, 0x43c, 0x20, 0x25, 0x32,
+0x25, 0x31, 0x20, 0xc2e, 0xc30, 0xc3f, 0xc2f, 0xc41, 0x20, 0x25, 0x32, 0x25,
+0x31, 0x20, 0xe41, 0xe25, 0xe30, 0x25, 0x32, 0x25, 0x31, 0xe41, 0xe25, 0xe30,
+0x25, 0x32, 0x25, 0x31, 0x1295, 0x20, 0x25, 0x32, 0x1295, 0x25, 0x31, 0x20,
+0x6d, 0x6f, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x76, 0x65, 0x20, 0x25,
+0x32, 0x25, 0x31, 0x20, 0x77, 0x65, 0x20, 0x25, 0x32, 0x25, 0x31, 0x60c,
+0x20, 0x627, 0x648, 0x631, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x627, 0x648,
+0x631, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x76, 0x61, 0x20, 0x25, 0x32,
+0x25, 0x31, 0x20, 0x76, 0xe0, 0x20, 0x25, 0x32, 0x25, 0x31, 0x2c, 0x20,
+0x61, 0x28, 0x63, 0x29, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x61, 0x28,
+0x63, 0x29, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x5d0, 0x5d5, 0x5df, 0x20,
+0x25, 0x32, 0x25, 0x31, 0x20, 0x63, 0x61, 0x65, 0x75, 0x71, 0x20, 0x25,
+0x32, 0x25, 0x31, 0x2c, 0x20, 0x6e, 0x65, 0x2d, 0x25, 0x32, 0x25, 0x31,
+0x20, 0x6e, 0x65, 0x2d, 0x25, 0x32, 0x25, 0x31, 0x20, 0x6b, 0x61, 0x72,
+0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x61, 0x73, 0x75, 0xed, 0x20, 0x25,
+0x32, 0x25, 0x31, 0x60c, 0x25, 0x32, 0x25, 0x31, 0x20, 0x60c, 0x622, 0x6ba,
+0x20, 0x25, 0x32, 0x25, 0x31, 0x20, 0x622, 0x6ba, 0x20, 0x25, 0x32, 0x25,
+0x31, 0x2c, 0x20, 0x915, 0x928, 0x947, 0x20, 0x25, 0x32, 0x25, 0x31, 0x20,
+0x915, 0x928, 0x947, 0x20, 0x25, 0x32
};
static constexpr char16_t single_character_data[] = {
-0x2e, 0x2c, 0x25, 0x30, 0x2d, 0x2b, 0x65, 0x22, 0x27, 0x45, 0x201c, 0x201d, 0x2018, 0x2019, 0xa0, 0x201e, 0x201a, 0xab, 0xbb, 0x2039,
-0x203a, 0x66b, 0x66c, 0x66a, 0x61c, 0x660, 0x61c, 0x2d, 0x61c, 0x2b, 0x627, 0x633, 0x200e, 0x25, 0x200e, 0x200e, 0x2d, 0x200e, 0x2b, 0x9e6,
-0x2212, 0x966, 0x1040, 0x300c, 0x300d, 0x300e, 0x300f, 0x200f, 0x2d, 0x200f, 0x2b, 0xd804, 0xdd36, 0xd7, 0x31, 0x30, 0x5e, 0xf20, 0x202f, 0x2e41,
-0xd83a, 0xdd50, 0xd83a, 0xdd09, 0x6f0, 0x200e, 0x2b, 0x200e, 0xd7, 0x6f1, 0x6f0, 0x5e, 0xb7, 0x31, 0x30, 0x5e, 0x200e, 0x2212, 0x1c50, 0x415
+0x2e, 0x2c, 0x25, 0x30, 0x2d, 0x2b, 0x65, 0x22, 0x27, 0xa0, 0x45, 0xab,
+0xbb, 0x201e, 0x201c, 0x201d, 0x2018, 0x2019, 0x201a, 0x2039, 0x203a, 0x66b, 0x66c, 0x66a,
+0x61c, 0x660, 0x61c, 0x2d, 0x61c, 0x2b, 0x623, 0x633, 0x200e, 0x25, 0x200e, 0x200e,
+0x2d, 0x200e, 0x2b, 0x9e6, 0x6f0, 0x200e, 0x2b, 0x200e, 0xd7, 0x6f1, 0x6f0, 0x5e,
+0x2212, 0x966, 0x1040, 0x300c, 0x300d, 0x300e, 0x300f, 0x200f, 0x2d, 0x200f, 0x2b, 0x627,
+0x633, 0xd804, 0xdd36, 0xd7, 0x31, 0x30, 0x5e, 0xf20, 0x202f, 0x2e41, 0xd83a, 0xdd50,
+0xd83a, 0xdd09, 0x12c8, 0xabf0, 0x60c, 0x7c0, 0xb7, 0x31, 0x30, 0x5e, 0x200e, 0x2212,
+0x1c50, 0x415
};
static constexpr char16_t date_format_data[] = {
-0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x20, 0x4d,
-0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x2c, 0x20,
-0x64, 0x64, 0x64, 0x64, 0x79, 0x79, 0x79, 0x79, 0x2d, 0x4d, 0x4d, 0x2d, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x20, 0x64,
-0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x20, 0x64, 0x20, 0x4d, 0x4d,
-0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x2f, 0x4d, 0x2f, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c,
-0x20, 0x79, 0x79, 0x79, 0x79, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x64, 0x79, 0x79, 0x2f, 0x4d, 0x4d, 0x2f, 0x64,
-0x64, 0x64, 0x2e, 0x4d, 0x2e, 0x79, 0x79, 0x64, 0x64, 0x2f, 0x4d, 0x4d, 0x2f, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64,
-0x64, 0x60c, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x200f, 0x2f, 0x4d, 0x200f, 0x2f,
-0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x20, 0x569, 0x2e, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x2c, 0x20,
-0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x2e, 0x4d, 0x4d, 0x2e, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x20,
-0x4d, 0x4d, 0x4d, 0x4d, 0x2c, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x2d, 0x4d, 0x2d, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64,
-0x64, 0x64, 0x2c, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x27, 0x64, 0x65, 0x27, 0x20, 0x79, 0x79, 0x79, 0x79,
-0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x79, 0x79, 0x79,
-0x79, 0x28, 0x27, 0x65, 0x27, 0x29, 0x27, 0x6b, 0x6f, 0x27, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x27, 0x72, 0x65, 0x6e, 0x27,
-0x20, 0x64, 0x28, 0x27, 0x61, 0x27, 0x29, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x79, 0x79, 0x2f, 0x4d, 0x2f, 0x64, 0x64,
-0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x202f, 0x27, 0x433, 0x27,
-0x2e, 0x64, 0x64, 0x2d, 0x4d, 0x4d, 0x2d, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x2e, 0x20,
-0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x2e, 0x64, 0x2e, 0x20, 0x4d, 0x2e, 0x20, 0x79, 0x79, 0x79, 0x79,
-0x2e, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x64, 0x2e, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79,
-0x2e, 0x64, 0x2e, 0x4d, 0x2e, 0x79, 0x79, 0x2e, 0x64, 0x2e, 0x4d, 0x4d, 0x2e, 0x79, 0x79, 0x202f, 0x27, 0x433, 0x27, 0x2e,
-0x79, 0x79, 0x79, 0x79, 0x104a, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x104a, 0x20, 0x64, 0x64, 0x64, 0x64, 0x79, 0x79,
-0x79, 0x79, 0x5e74, 0x4d, 0x6708, 0x64, 0x65e5, 0x20, 0x64, 0x64, 0x64, 0x64, 0x79, 0x79, 0x79, 0x79, 0x2f, 0x4d, 0x2f, 0x64,
-0x79, 0x79, 0x79, 0x79, 0x5e74, 0x4d, 0x6708, 0x64, 0x65e5, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x4d,
-0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x2c, 0x20, 0x79, 0x79, 0x79, 0x79, 0x4d, 0x2f, 0x64, 0x2f, 0x79, 0x79, 0x64, 0x64, 0x64,
-0x64, 0x2c, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x202f, 0x27, 0x4ab, 0x27, 0x2e, 0x64,
-0x64, 0x2e, 0x4d, 0x4d, 0x2e, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x27, 0x64, 0xe4, 0x27, 0x20,
-0x64, 0x2e, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x2e, 0x20, 0x4d, 0x4d, 0x2e, 0x20,
-0x79, 0x79, 0x79, 0x79, 0x2e, 0x64, 0x2e, 0x20, 0x4d, 0x2e, 0x20, 0x79, 0x79, 0x2e, 0x64, 0x64, 0x64, 0x64, 0x20, 0x64,
-0x2e, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x20, 0x27, 0x64, 0x65, 0x6e,
-0x27, 0x20, 0x64, 0x2e, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20,
-0x64, 0x2c, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0xf66, 0xfa4,
-0xfb1, 0xf72, 0xf0b, 0xf63, 0xf7c, 0xf0b, 0x79, 0x79, 0x79, 0x79, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0xf5a, 0xf7a, 0xf66, 0xf0b,
-0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79,
-0x79, 0x79, 0x79, 0x79, 0x2f, 0x4d, 0x4d, 0x2f, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x2d, 0x27, 0x61,
-0x27, 0x20, 0x27, 0x64, 0x65, 0x27, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64,
-0x2c, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x20, 0x27, 0x6c, 0x69, 0x61, 0x27, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64,
-0x2e, 0x4d, 0x2e, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x20, 0x64, 0x20, 0x27, 0x64, 0x69, 0x27, 0x20, 0x4d,
-0x4d, 0x4d, 0x4d, 0x20, 0x27, 0x64, 0x61, 0x6c, 0x27, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x20, 0x64,
-0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x2e41, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x27, 0x6d,
-0x68, 0x27, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x20,
-0x27, 0x64, 0x65, 0x27, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x27, 0x64, 0x65, 0x27, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64,
-0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x2c, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64,
-0x64, 0x64, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x2c, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c,
-0x20, 0x64, 0x20, 0x5d1, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x2e, 0x20, 0x4d,
-0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x2e, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x79, 0x79, 0x79, 0x79, 0x2e, 0x20, 0x4d, 0x4d,
-0x2e, 0x20, 0x64, 0x64, 0x2e, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x2e, 0x20, 0x79,
-0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x20, 0x27, 0x6c, 0x65, 0x27, 0x20, 0x64, 0x20, 0x27, 0x64, 0x65, 0x27, 0x20,
-0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x20, 0x27, 0x64, 0x69,
-0x27, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x27, 0x64, 0x69, 0x27, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x2f, 0x4d,
-0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x202f, 0x27, 0x436, 0x27, 0x2e, 0x20, 0x64, 0x20, 0x4d, 0x4d,
-0x4d, 0x4d, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x79, 0x79, 0x79, 0x79, 0xb144, 0x20, 0x4d, 0xc6d4, 0x20, 0x64, 0xc77c, 0x20,
-0x64, 0x64, 0x64, 0x64, 0x79, 0x79, 0x2e, 0x20, 0x4d, 0x2e, 0x20, 0x64, 0x2e, 0x79, 0x79, 0x79, 0x79, 0x2d, 0x27, 0x436,
-0x27, 0x2e, 0x2c, 0x20, 0x64, 0x2d, 0x4d, 0x4d, 0x4d, 0x4d, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
-0x20, 0xe97, 0xeb5, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c,
-0x20, 0x79, 0x79, 0x79, 0x79, 0x2e, 0x20, 0x27, 0x67, 0x61, 0x64, 0x61, 0x27, 0x20, 0x64, 0x2e, 0x20, 0x4d, 0x4d, 0x4d,
-0x4d, 0x79, 0x79, 0x79, 0x79, 0x20, 0x27, 0x6d, 0x27, 0x2e, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x20, 0x27, 0x64,
-0x27, 0x2e, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x27, 0x64, 0x65, 0x27, 0x20, 0x64,
-0x2e, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x2c, 0x20, 0x4d, 0x4d, 0x4d,
-0x4d, 0x20, 0x64, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x20, 0x27, 0x74, 0x61,
-0x27, 0x2019, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x2c, 0x20,
-0x79, 0x79, 0x79, 0x79, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x79, 0x79, 0x79, 0x79, 0x202f, 0x27, 0x43e, 0x43d, 0x44b, 0x27,
-0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x27, 0x44b, 0x43d, 0x27, 0x20, 0x64, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x20, 0x27, 0x433,
-0x430, 0x440, 0x430, 0x433, 0x27, 0x79, 0x79, 0x79, 0x79, 0x2e, 0x4d, 0x4d, 0x2e, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x20,
-0x2c, 0x20, 0x27, 0x6c, 0x79, 0x25b, 0x27, 0x30c, 0x2bc, 0x20, 0x64, 0x20, 0x27, 0x6e, 0x61, 0x27, 0x20, 0x4d, 0x4d, 0x4d,
-0x4d, 0x2c, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x27,
-0x64, 0x65, 0x27, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d,
-0x2c, 0x20, 0x79, 0x79, 0x79, 0x79, 0x202f, 0x27, 0x430, 0x437, 0x27, 0x64, 0x64, 0x64, 0x64, 0x20, 0x62f, 0x20, 0x79, 0x79,
-0x79, 0x79, 0x20, 0x62f, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x27, 0x69, 0x6c,
-0x73, 0x27, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x202f, 0x27,
-0x441, 0x44b, 0x43b, 0x27, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x20, 0x27, 0x43a, 0x4af, 0x43d, 0x44d, 0x27, 0x2c, 0x20,
-0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x20, 0x64, 0x20, 0x27, 0x64, 0x65, 0x27, 0x20, 0x4d, 0x4d, 0x4d, 0x4d,
-0x20, 0x27, 0x64, 0x65, 0x27, 0x20, 0x27, 0x73, 0x75, 0x27, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x20,
-0x64, 0x64, 0x20, 0x27, 0x64, 0x65, 0x27, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x27, 0x64, 0x65, 0x27, 0x20, 0x79, 0x79,
-0x79, 0x79, 0x4d, 0x4d, 0x2f, 0x64, 0x64, 0x2f, 0x79, 0x79, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x2c, 0x20, 0x79, 0x79,
-0x79, 0x79, 0x202f, 0x27, 0x435, 0x43b, 0x27, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x4d, 0x4d, 0x4d, 0x4d,
-0x20, 0x79, 0x79, 0x79, 0x79, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0xe17, 0xe35, 0xe48, 0x20, 0x64,
-0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0xf60,
-0xf72, 0xf0b, 0xf5a, 0xf7a, 0xf66, 0xf0b, 0x64, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x1363, 0x20, 0x64,
-0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79,
-0x79, 0x20, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79,
-0x79, 0x79, 0x79, 0x202f, 0x27, 0x440, 0x27, 0x2e, 0x64, 0x64, 0x64, 0x64, 0x60c, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d,
-0x60c, 0x20, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x20, 0x64, 0x2d, 0x4d, 0x4d, 0x4d, 0x4d, 0x60c, 0x20, 0x64,
-0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x2d, 0x4d, 0x4d, 0x4d, 0x4d, 0x2c, 0x20, 0x79, 0x79, 0x79,
-0x79, 0x79, 0x79, 0x79, 0x79, 0x20, 0x646, 0x686, 0x6cc, 0x20, 0x6cc, 0x6cc, 0x644, 0x20, 0x64, 0x20, 0x646, 0x686, 0x6cc, 0x20,
-0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x64, 0x64, 0x64, 0x20, 0x6a9, 0x648, 0x646, 0x6cc, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20,
-0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x2c, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x5d8, 0x5df,
-0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x20, 0x4d, 0x4d,
-0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x20, 0x27, 0x6e, 0x65, 0x27, 0x20, 0x4d,
-0x4d, 0x4d, 0x4d, 0x2c, 0x20, 0x79, 0x79, 0x79, 0x79
+0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d,
+0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x20, 0x79,
+0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x20, 0x4d,
+0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x20, 0x27, 0x448, 0x27,
+0x2e, 0x64, 0x64, 0x2e, 0x4d, 0x4d, 0x2e, 0x79, 0x79, 0x79, 0x79, 0x64,
+0x64, 0x64, 0x64, 0x2c, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x64,
+0x2c, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x2f, 0x4d, 0x4d, 0x2f,
+0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x20, 0x64, 0x64, 0x20, 0x4d, 0x4d,
+0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x2d,
+0x4d, 0x4d, 0x2d, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x20, 0x64, 0x20,
+0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x2f, 0x4d,
+0x2f, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x79,
+0x79, 0x79, 0x79, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x64, 0x79,
+0x79, 0x2f, 0x4d, 0x4d, 0x2f, 0x64, 0x64, 0x79, 0x79, 0x79, 0x79, 0x20,
+0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64,
+0x64, 0x2e, 0x4d, 0x2e, 0x79, 0x79, 0x64, 0x64, 0x2f, 0x4d, 0x4d, 0x2f,
+0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x60c, 0x20, 0x64, 0x20,
+0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x200f, 0x2f,
+0x4d, 0x200f, 0x2f, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c,
+0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x27, 0x64, 0x65, 0x27,
+0x20, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x20, 0x569, 0x2e,
+0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x2c, 0x20, 0x64, 0x64, 0x64,
+0x64, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d,
+0x4d, 0x2c, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x2d, 0x4d, 0x2d, 0x79,
+0x79, 0x79, 0x79, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79,
+0x79, 0x79, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x79, 0x79, 0x79, 0x79,
+0x28, 0x27, 0x65, 0x27, 0x29, 0x27, 0x6b, 0x6f, 0x27, 0x20, 0x4d, 0x4d,
+0x4d, 0x4d, 0x27, 0x72, 0x65, 0x6e, 0x27, 0x20, 0x64, 0x28, 0x27, 0x61,
+0x27, 0x29, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x79, 0x79, 0x2f, 0x4d,
+0x2f, 0x64, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x20, 0x4d, 0x4d,
+0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x202f, 0x27, 0x433, 0x27, 0x2e,
+0x64, 0x64, 0x64, 0x64, 0x1361, 0x20, 0x64, 0x64, 0x20, 0x4d, 0x4d, 0x4d,
+0x4d, 0x20, 0x130d, 0x122d, 0x130b, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64,
+0x2d, 0x4d, 0x4d, 0x2d, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64,
+0x2c, 0x20, 0x64, 0x2e, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79,
+0x79, 0x79, 0x2e, 0x64, 0x2e, 0x20, 0x4d, 0x2e, 0x20, 0x79, 0x79, 0x79,
+0x79, 0x2e, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x64, 0x2e, 0x20,
+0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x2e, 0x64, 0x2e,
+0x4d, 0x2e, 0x79, 0x79, 0x2e, 0x64, 0x2e, 0x4d, 0x4d, 0x2e, 0x79, 0x79,
+0x202f, 0x27, 0x433, 0x27, 0x2e, 0x79, 0x79, 0x79, 0x79, 0x104a, 0x20, 0x4d,
+0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x104a, 0x20, 0x64, 0x64, 0x64, 0x64, 0x79,
+0x79, 0x79, 0x79, 0x5e74, 0x4d, 0x6708, 0x64, 0x65e5, 0x20, 0x64, 0x64, 0x64,
+0x64, 0x79, 0x79, 0x79, 0x79, 0x2f, 0x4d, 0x2f, 0x64, 0x79, 0x79, 0x79,
+0x79, 0x5e74, 0x4d, 0x6708, 0x64, 0x65e5, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
+0x64, 0x64, 0x2c, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x27,
+0x64, 0x65, 0x6c, 0x27, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64,
+0x64, 0x2c, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x2c, 0x20, 0x79,
+0x79, 0x79, 0x79, 0x4d, 0x2f, 0x64, 0x2f, 0x79, 0x79, 0x64, 0x64, 0x64,
+0x64, 0x2c, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x27, 0x43b,
+0x27, 0x2e, 0x20, 0x79, 0x79, 0x79, 0x79, 0x2e, 0x79, 0x79, 0x79, 0x79,
+0x2e, 0x4d, 0x4d, 0x2e, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20,
+0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x202f,
+0x27, 0x4ab, 0x27, 0x2e, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x27, 0x64,
+0xe4, 0x27, 0x20, 0x64, 0x2e, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79,
+0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x20, 0x64, 0x20, 0x4d, 0x4d,
+0x4d, 0x4d, 0x20, 0x27, 0x64, 0x69, 0x27, 0x20, 0x27, 0x75, 0x27, 0x20,
+0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x2e, 0x20, 0x4d, 0x4d, 0x2e, 0x20,
+0x79, 0x79, 0x79, 0x79, 0x2e, 0x64, 0x2e, 0x20, 0x4d, 0x2e, 0x20, 0x79,
+0x79, 0x2e, 0x64, 0x64, 0x64, 0x64, 0x20, 0x64, 0x2e, 0x20, 0x4d, 0x4d,
+0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x20,
+0x27, 0x64, 0x65, 0x6e, 0x27, 0x20, 0x64, 0x2e, 0x20, 0x4d, 0x4d, 0x4d,
+0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20,
+0x64, 0x2c, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79,
+0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0xf66, 0xfa4, 0xfb1, 0xf72, 0xf0b, 0xf63,
+0xf7c, 0xf0b, 0x79, 0x79, 0x79, 0x79, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20,
+0xf5a, 0xf7a, 0xf66, 0xf0b, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20,
+0x64, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79,
+0x64, 0x64, 0x64, 0x64, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x2c,
+0x20, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x2f, 0x4d, 0x4d,
+0x2f, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x27, 0x6c, 0x61,
+0x27, 0x20, 0x64, 0x2d, 0x27, 0x61, 0x27, 0x20, 0x27, 0x64, 0x65, 0x27,
+0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64,
+0x64, 0x64, 0x2c, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x20, 0x27,
+0x6c, 0x69, 0x61, 0x27, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x2e, 0x4d,
+0x2e, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x20, 0x64, 0x20,
+0x27, 0x64, 0x69, 0x27, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x27, 0x64,
+0x61, 0x6c, 0x27, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64,
+0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x2e41, 0x20, 0x79, 0x79, 0x79,
+0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x27, 0x6d, 0x68, 0x27,
+0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64,
+0x64, 0x64, 0x2c, 0x20, 0x64, 0x20, 0x27, 0x64, 0x65, 0x27, 0x20, 0x4d,
+0x4d, 0x4d, 0x4d, 0x20, 0x27, 0x64, 0x65, 0x27, 0x20, 0x79, 0x79, 0x79,
+0x79, 0x64, 0x64, 0x64, 0x64, 0x1365, 0x20, 0x64, 0x64, 0x20, 0x4d, 0x4d,
+0x4d, 0x4d, 0x20, 0x1218, 0x12d3, 0x120d, 0x1275, 0x20, 0x79, 0x79, 0x79, 0x79,
+0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x64, 0x20, 0x4d, 0x4d, 0x4d,
+0x4d, 0x2c, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c,
+0x20, 0x64, 0x20, 0x5d1, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79,
+0x79, 0x79, 0x79, 0x79, 0x79, 0x2e, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20,
+0x64, 0x2e, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x79, 0x79, 0x79, 0x79,
+0x2e, 0x20, 0x4d, 0x4d, 0x2e, 0x20, 0x64, 0x64, 0x2e, 0x64, 0x64, 0x64,
+0x64, 0x2c, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x2e, 0x20, 0x79,
+0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x20, 0x27, 0x6c, 0x65, 0x27,
+0x20, 0x64, 0x20, 0x27, 0x64, 0x65, 0x27, 0x20, 0x4d, 0x4d, 0x4d, 0x4d,
+0x20, 0x79, 0x79, 0x79, 0x79, 0x4d, 0x4d, 0x2f, 0x64, 0x64, 0x2f, 0x79,
+0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x20, 0x27,
+0x64, 0x69, 0x27, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x27, 0x64, 0x69,
+0x27, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x2f, 0x4d, 0x4d, 0x20,
+0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x202f, 0x27, 0x436, 0x27,
+0x2e, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x2c, 0x20, 0x64, 0x64,
+0x64, 0x64, 0x79, 0x79, 0x79, 0x79, 0xb144, 0x20, 0x4d, 0x4d, 0x4d, 0x4d,
+0x20, 0x64, 0xc77c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x79, 0x79, 0x2e, 0x20,
+0x4d, 0x2e, 0x20, 0x64, 0x2e, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64,
+0x27, 0xea, 0x27, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x27, 0x61, 0x27, 0x20,
+0x79, 0x79, 0x79, 0x79, 0x27, 0x61, 0x6e, 0x27, 0x79, 0x79, 0x79, 0x79,
+0x2d, 0x27, 0x436, 0x27, 0x2e, 0x2c, 0x20, 0x64, 0x2d, 0x4d, 0x4d, 0x4d,
+0x4d, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x20,
+0xe97, 0xeb5, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79,
+0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x27, 0x64, 0x69, 0x65,
+0x27, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79,
+0x79, 0x64, 0x20, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64,
+0x64, 0x2c, 0x20, 0x79, 0x79, 0x79, 0x79, 0x2e, 0x20, 0x27, 0x67, 0x61,
+0x64, 0x61, 0x27, 0x20, 0x64, 0x2e, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x79,
+0x79, 0x79, 0x79, 0x20, 0x27, 0x6d, 0x27, 0x2e, 0x20, 0x4d, 0x4d, 0x4d,
+0x4d, 0x20, 0x64, 0x20, 0x27, 0x64, 0x27, 0x2e, 0x2c, 0x20, 0x64, 0x64,
+0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x27, 0x64, 0x65, 0x27,
+0x20, 0x64, 0x2e, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79,
+0x79, 0x79, 0x79, 0x79, 0x79, 0x2c, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20,
+0x64, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x2c,
+0x20, 0x64, 0x20, 0x27, 0x74, 0x61, 0x27, 0x2019, 0x20, 0x4d, 0x4d, 0x4d,
+0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64,
+0x2c, 0x20, 0x79, 0x79, 0x79, 0x79, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64,
+0x79, 0x79, 0x79, 0x79, 0x202f, 0x27, 0x43e, 0x43d, 0x44b, 0x27, 0x20, 0x4d,
+0x4d, 0x4d, 0x4d, 0x27, 0x44b, 0x43d, 0x27, 0x20, 0x64, 0x2c, 0x20, 0x64,
+0x64, 0x64, 0x64, 0x20, 0x27, 0x433, 0x430, 0x440, 0x430, 0x433, 0x27, 0x79,
+0x79, 0x79, 0x79, 0x20, 0x1823, 0x1828, 0x20, 0x180e, 0x180e, 0x180e, 0x1824, 0x20,
+0x4d, 0x4d, 0x4d, 0x4d, 0x180e, 0x180e, 0x1822, 0x1822, 0x1828, 0x64, 0x2e, 0x20,
+0x64, 0x64, 0x64, 0x64, 0x20, 0x180b, 0x182d, 0x1820, 0x1837, 0x1820, 0x182d, 0x64,
+0x64, 0x64, 0x64, 0x20, 0x2c, 0x20, 0x27, 0x6c, 0x79, 0x25b, 0x27, 0x30c,
+0x2bc, 0x20, 0x64, 0x20, 0x27, 0x6e, 0x61, 0x27, 0x20, 0x4d, 0x4d, 0x4d,
+0x4d, 0x2c, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x20,
+0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x27, 0x64, 0x65, 0x27, 0x20,
+0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x20,
+0x4d, 0x4d, 0x4d, 0x4d, 0x2c, 0x20, 0x79, 0x79, 0x79, 0x79, 0x202f, 0x27,
+0x430, 0x437, 0x27, 0x64, 0x64, 0x64, 0x64, 0x20, 0x62f, 0x20, 0x79, 0x79,
+0x79, 0x79, 0x20, 0x62f, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x64,
+0x64, 0x64, 0x64, 0x2c, 0x20, 0x79, 0x79, 0x79, 0x79, 0x20, 0x27, 0x6d,
+0x65, 0x74, 0x74, 0x61, 0x73, 0x27, 0x20, 0x64, 0x2e, 0x20, 0x4d, 0x4d,
+0x4d, 0x4d, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x27, 0x69, 0x6c, 0x73,
+0x27, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79,
+0x79, 0x79, 0x79, 0x79, 0x79, 0x202f, 0x27, 0x441, 0x44b, 0x43b, 0x27, 0x20,
+0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x20, 0x27, 0x43a, 0x4af, 0x43d, 0x44d,
+0x27, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x20,
+0x64, 0x20, 0x27, 0x64, 0x65, 0x27, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20,
+0x27, 0x64, 0x65, 0x27, 0x20, 0x27, 0x73, 0x75, 0x27, 0x20, 0x79, 0x79,
+0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x20, 0x64, 0x64, 0x20, 0x27, 0x64,
+0x65, 0x27, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x27, 0x64, 0x65, 0x27,
+0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x60c, 0x20, 0x64,
+0x20, 0x712, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64,
+0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x2c, 0x20, 0x79, 0x79, 0x79, 0x79, 0x202f,
+0x27, 0x435, 0x43b, 0x27, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x64, 0x2c,
+0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x2c, 0x20,
+0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0xe17, 0xe35, 0xe48, 0x20,
+0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x79,
+0x79, 0x79, 0x79, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0xf60, 0xf72, 0xf0b, 0xf5a,
+0xf7a, 0xf66, 0xf0b, 0x64, 0x2c, 0x20, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
+0x64, 0x64, 0x1361, 0x20, 0x64, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20,
+0x12ee, 0x121d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x1363,
+0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79,
+0x64, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x20,
+0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x20,
+0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79, 0x79, 0x202f, 0x27, 0x440,
+0x27, 0x2e, 0x64, 0x64, 0x64, 0x64, 0x60c, 0x20, 0x64, 0x20, 0x4d, 0x4d,
+0x4d, 0x4d, 0x60c, 0x20, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79,
+0x20, 0x64, 0x2d, 0x4d, 0x4d, 0x4d, 0x4d, 0x60c, 0x20, 0x64, 0x64, 0x64,
+0x64, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x2d, 0x4d, 0x4d, 0x4d,
+0x4d, 0x2c, 0x20, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x20,
+0x646, 0x686, 0x6cc, 0x20, 0x6cc, 0x6cc, 0x644, 0x20, 0x64, 0x20, 0x646, 0x686,
+0x6cc, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x64, 0x64, 0x64, 0x64, 0x20,
+0x6a9, 0x648, 0x646, 0x6cc, 0x79, 0x79, 0x79, 0x79, 0x20, 0x4d, 0x4d, 0x4d,
+0x4d, 0x27, 0x61, 0x27, 0x20, 0x27, 0x64, 0x27, 0x2e, 0x20, 0x64, 0x27,
+0x69, 0x64, 0x27, 0x64, 0x64, 0x64, 0x64, 0x1365, 0x20, 0x64, 0x64, 0x20,
+0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x130b, 0x120b, 0x1233, 0x20, 0x79, 0x79, 0x79,
+0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d,
+0x2c, 0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20,
+0x64, 0x5d8, 0x5df, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20, 0x79, 0x79, 0x79,
+0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64, 0x20, 0x4d, 0x4d, 0x4d,
+0x20, 0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x64,
+0x20, 0x27, 0x6e, 0x65, 0x27, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x2c, 0x20,
+0x79, 0x79, 0x79, 0x79, 0x64, 0x64, 0x64, 0x64, 0x20, 0x64, 0x20, 0x4d,
+0x4d, 0x4d, 0x4d, 0x20, 0x27, 0x64, 0x6f, 0x27, 0x20, 0x79, 0x79, 0x79,
+0x79, 0x64, 0x64, 0x64, 0x64, 0x2c, 0x20, 0x4d, 0x4d, 0x4d, 0x4d, 0x20,
+0x64, 0x20, 0x79, 0x79, 0x79, 0x79, 0x4d, 0x2f, 0x64, 0x2f, 0x79, 0x79,
+0x79, 0x79
};
static constexpr char16_t time_format_data[] = {
-0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x74, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x202f, 0x41, 0x50,
-0x20, 0x74, 0x68, 0x3a, 0x6d, 0x6d, 0x202f, 0x41, 0x50, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x202f, 0x41, 0x50, 0x2c,
-0x20, 0x74, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x41, 0x50, 0x20, 0x74, 0x68, 0x3a, 0x6d, 0x6d, 0x20, 0x41,
-0x50, 0x41, 0x50, 0x20, 0x68, 0x2e, 0x6d, 0x6d, 0x2e, 0x73, 0x73, 0x20, 0x74, 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x3a, 0x73,
-0x73, 0x20, 0x28, 0x74, 0x29, 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x2c, 0x20, 0x74, 0x41, 0x50, 0x20, 0x68,
-0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x74, 0x41, 0x50, 0x20, 0x928, 0x93f, 0x20, 0x68, 0x3a, 0x6d, 0x6d, 0x48, 0x3a,
-0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x27, 0x447, 0x27, 0x2e, 0x20, 0x74, 0x48, 0x3a, 0x6d, 0x6d, 0x20, 0x27, 0x447, 0x27,
-0x2e, 0x74, 0x20, 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x41, 0x50, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73,
-0x20, 0x5b, 0x74, 0x5d, 0x74, 0x20, 0x41, 0x50, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x42, 0x68, 0x3a, 0x6d, 0x6d,
-0x3a, 0x73, 0x73, 0x20, 0x5b, 0x74, 0x5d, 0x48, 0x48, 0x2e, 0x6d, 0x6d, 0x2e, 0x73, 0x73, 0x20, 0x74, 0xf46, 0xf74, 0xf0b,
-0xf5a, 0xf7c, 0xf51, 0xf0b, 0x20, 0x68, 0x20, 0xf66, 0xf90, 0xf62, 0xf0b, 0xf58, 0xf0b, 0x20, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20,
-0x41, 0x50, 0x20, 0x74, 0xf46, 0xf74, 0xf0b, 0xf5a, 0xf7c, 0xf51, 0xf0b, 0x20, 0x68, 0x20, 0xf66, 0xf90, 0xf62, 0xf0b, 0xf58, 0xf0b,
-0x20, 0x6d, 0x6d, 0x20, 0x41, 0x50, 0x48, 0x2d, 0x27, 0x61, 0x27, 0x20, 0x27, 0x68, 0x6f, 0x72, 0x6f, 0x27, 0x20, 0x27,
-0x6b, 0x61, 0x6a, 0x27, 0x20, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x74, 0x41, 0x50, 0x20, 0x27, 0x67, 0x61, 0x27, 0x20, 0x68,
-0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x74, 0x48, 0x20, 0x27, 0x68, 0x27, 0x20, 0x6d, 0x6d, 0x20, 0x27, 0x6d, 0x69,
-0x6e, 0x27, 0x20, 0x73, 0x73, 0x20, 0x27, 0x73, 0x27, 0x20, 0x74, 0x48, 0x48, 0x20, 0x27, 0x68, 0x27, 0x20, 0x6d, 0x6d,
-0x20, 0x27, 0x6d, 0x69, 0x6e, 0x27, 0x20, 0x73, 0x73, 0x20, 0x27, 0x73, 0x27, 0x20, 0x74, 0x48, 0x48, 0x2e, 0x6d, 0x6d,
-0x3a, 0x73, 0x73, 0x20, 0x27, 0x68, 0x27, 0x20, 0x74, 0x68, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x41, 0x50,
-0x20, 0x74, 0x68, 0x68, 0x3a, 0x6d, 0x6d, 0x20, 0x41, 0x50, 0x48, 0x6642, 0x6d, 0x6d, 0x5206, 0x73, 0x73, 0x79d2, 0x20, 0x74,
-0x41, 0x50, 0x20, 0x68, 0xc2dc, 0x20, 0x6d, 0xbd84, 0x20, 0x73, 0xcd08, 0x20, 0x74, 0x48, 0x20, 0xec2, 0xea1, 0xe87, 0x20, 0x6d,
-0x20, 0xe99, 0xeb2, 0xe97, 0xeb5, 0x20, 0x73, 0x73, 0x20, 0xea7, 0xeb4, 0xe99, 0xeb2, 0xe97, 0xeb5, 0x20, 0x74, 0x27, 0x4b, 0x6c,
-0x6f, 0x63, 0x6b, 0x27, 0x20, 0x48, 0x2e, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x28, 0x74, 0x29, 0x27, 0x4b, 0x6c, 0x27,
-0x2e, 0x20, 0x48, 0x2e, 0x6d, 0x6d, 0x27, 0x6b, 0x6c, 0x27, 0x2e, 0x20, 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73,
-0x20, 0x74, 0x74, 0x20, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x202f, 0x41, 0x50, 0x48, 0x27, 0x68, 0x27, 0x6d, 0x6d,
-0x48, 0x20, 0xe19, 0xe32, 0xe2c, 0xe34, 0xe01, 0xe32, 0x20, 0x6d, 0x6d, 0x20, 0xe19, 0xe32, 0xe17, 0xe35, 0x20, 0x73, 0x73, 0x20,
-0xe27, 0xe34, 0xe19, 0xe32, 0xe17, 0xe35, 0x20, 0x74, 0x48, 0x3a, 0x6d, 0x6d, 0x20, 0x27, 0x68, 0x6f, 0x64, 0x17a, 0x27, 0x2e
+0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x74, 0x48, 0x48,
+0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x74, 0x74, 0x74, 0x74, 0x68,
+0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x202f, 0x41, 0x70, 0x20, 0x74, 0x74,
+0x74, 0x74, 0x68, 0x3a, 0x6d, 0x6d, 0x202f, 0x41, 0x70, 0x68, 0x3a, 0x6d,
+0x6d, 0x3a, 0x73, 0x73, 0x202f, 0x41, 0x70, 0x2c, 0x20, 0x74, 0x74, 0x74,
+0x74, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x41, 0x70, 0x20,
+0x74, 0x74, 0x74, 0x74, 0x68, 0x3a, 0x6d, 0x6d, 0x20, 0x41, 0x70, 0x41,
+0x70, 0x20, 0x68, 0x2e, 0x6d, 0x6d, 0x2e, 0x73, 0x73, 0x20, 0x74, 0x74,
+0x74, 0x74, 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x28,
+0x74, 0x74, 0x74, 0x74, 0x29, 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x3a, 0x73,
+0x73, 0x2c, 0x20, 0x74, 0x74, 0x74, 0x74, 0x41, 0x70, 0x20, 0x68, 0x3a,
+0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x74, 0x74, 0x74, 0x74, 0x41, 0x70,
+0x20, 0x928, 0x93f, 0x20, 0x68, 0x3a, 0x6d, 0x6d, 0x48, 0x3a, 0x6d, 0x6d,
+0x3a, 0x73, 0x73, 0x20, 0x27, 0x447, 0x27, 0x2e, 0x20, 0x74, 0x74, 0x74,
+0x74, 0x74, 0x74, 0x74, 0x74, 0x20, 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x3a,
+0x73, 0x73, 0x41, 0x70, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20,
+0x5b, 0x74, 0x74, 0x74, 0x74, 0x5d, 0x74, 0x74, 0x74, 0x74, 0x20, 0x41,
+0x70, 0x68, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x48, 0x48, 0x2e, 0x6d,
+0x6d, 0x2e, 0x73, 0x73, 0x20, 0x74, 0x74, 0x74, 0x74, 0xf46, 0xf74, 0xf0b,
+0xf5a, 0xf7c, 0xf51, 0xf0b, 0x20, 0x68, 0x20, 0xf66, 0xf90, 0xf62, 0xf0b, 0xf58,
+0xf0b, 0x20, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x41, 0x70, 0x20, 0x74,
+0x74, 0x74, 0x74, 0xf46, 0xf74, 0xf0b, 0xf5a, 0xf7c, 0xf51, 0xf0b, 0x20, 0x68,
+0x20, 0xf66, 0xf90, 0xf62, 0xf0b, 0xf58, 0xf0b, 0x20, 0x6d, 0x6d, 0x20, 0x41,
+0x70, 0x41, 0x70, 0x20, 0x27, 0x67, 0x61, 0x27, 0x20, 0x68, 0x3a, 0x6d,
+0x6d, 0x3a, 0x73, 0x73, 0x20, 0x74, 0x74, 0x74, 0x74, 0x48, 0x20, 0x27,
+0x68, 0x27, 0x20, 0x6d, 0x6d, 0x20, 0x27, 0x6d, 0x69, 0x6e, 0x27, 0x20,
+0x73, 0x73, 0x20, 0x27, 0x73, 0x27, 0x20, 0x74, 0x74, 0x74, 0x74, 0x48,
+0x48, 0x20, 0x27, 0x68, 0x27, 0x20, 0x6d, 0x6d, 0x20, 0x27, 0x6d, 0x69,
+0x6e, 0x27, 0x20, 0x73, 0x73, 0x20, 0x27, 0x73, 0x27, 0x20, 0x74, 0x74,
+0x74, 0x74, 0x48, 0x48, 0x2e, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x27,
+0x68, 0x27, 0x20, 0x74, 0x74, 0x74, 0x74, 0x68, 0x68, 0x3a, 0x6d, 0x6d,
+0x3a, 0x73, 0x73, 0x20, 0x41, 0x70, 0x20, 0x74, 0x74, 0x74, 0x74, 0x68,
+0x68, 0x3a, 0x6d, 0x6d, 0x20, 0x41, 0x70, 0x48, 0x6642, 0x6d, 0x6d, 0x5206,
+0x73, 0x73, 0x79d2, 0x20, 0x74, 0x74, 0x74, 0x74, 0x41, 0x70, 0x20, 0x68,
+0xc2dc, 0x20, 0x6d, 0xbd84, 0x20, 0x73, 0xcd08, 0x20, 0x74, 0x74, 0x74, 0x74,
+0x48, 0x20, 0xec2, 0xea1, 0xe87, 0x20, 0x6d, 0x20, 0xe99, 0xeb2, 0xe97, 0xeb5,
+0x20, 0x73, 0x73, 0x20, 0xea7, 0xeb4, 0xe99, 0xeb2, 0xe97, 0xeb5, 0x20, 0x74,
+0x74, 0x74, 0x74, 0x27, 0x4b, 0x6c, 0x6f, 0x63, 0x6b, 0x27, 0x20, 0x48,
+0x2e, 0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x20, 0x28, 0x74, 0x74, 0x74, 0x74,
+0x29, 0x27, 0x4b, 0x6c, 0x27, 0x2e, 0x20, 0x48, 0x2e, 0x6d, 0x6d, 0x68,
+0x2e, 0x6d, 0x6d, 0x2e, 0x73, 0x73, 0x20, 0x41, 0x70, 0x20, 0x74, 0x74,
+0x74, 0x74, 0x68, 0x2e, 0x6d, 0x6d, 0x2e, 0x20, 0x41, 0x70, 0x27, 0x6b,
+0x6c, 0x27, 0x2e, 0x20, 0x48, 0x48, 0x3a, 0x6d, 0x6d, 0x3a, 0x73, 0x73,
+0x20, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x20, 0x68, 0x3a,
+0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x202f, 0x41, 0x70, 0x48, 0x27, 0x68, 0x27,
+0x6d, 0x6d, 0x48, 0x20, 0xe19, 0xe32, 0xe2c, 0xe34, 0xe01, 0xe32, 0x20, 0x6d,
+0x6d, 0x20, 0xe19, 0xe32, 0xe17, 0xe35, 0x20, 0x73, 0x73, 0x20, 0xe27, 0xe34,
+0xe19, 0xe32, 0xe17, 0xe35, 0x20, 0x74, 0x74, 0x74, 0x74, 0x68, 0x68, 0x3a,
+0x6d, 0x6d, 0x3a, 0x73, 0x73, 0x202f, 0x41, 0x70, 0x20, 0x74, 0x74, 0x74,
+0x74, 0x68, 0x68, 0x3a, 0x6d, 0x6d, 0x202f, 0x41, 0x70, 0x48, 0x3a, 0x6d,
+0x6d, 0x20, 0x27, 0x68, 0x6f, 0x64, 0x17a, 0x27, 0x2e
};
static constexpr char16_t days_data[] = {
-0x53, 0x75, 0x6e, 0x64, 0x61, 0x79, 0x3b, 0x4d, 0x6f, 0x6e, 0x64, 0x61, 0x79, 0x3b, 0x54, 0x75, 0x65, 0x73, 0x64, 0x61,
-0x79, 0x3b, 0x57, 0x65, 0x64, 0x6e, 0x65, 0x73, 0x64, 0x61, 0x79, 0x3b, 0x54, 0x68, 0x75, 0x72, 0x73, 0x64, 0x61, 0x79,
-0x3b, 0x46, 0x72, 0x69, 0x64, 0x61, 0x79, 0x3b, 0x53, 0x61, 0x74, 0x75, 0x72, 0x64, 0x61, 0x79, 0x53, 0x75, 0x6e, 0x3b,
-0x4d, 0x6f, 0x6e, 0x3b, 0x54, 0x75, 0x65, 0x3b, 0x57, 0x65, 0x64, 0x3b, 0x54, 0x68, 0x75, 0x3b, 0x46, 0x72, 0x69, 0x3b,
-0x53, 0x61, 0x74, 0x53, 0x3b, 0x4d, 0x3b, 0x54, 0x3b, 0x57, 0x3b, 0x54, 0x3b, 0x46, 0x3b, 0x53, 0x37, 0x3b, 0x31, 0x3b,
-0x32, 0x3b, 0x33, 0x3b, 0x34, 0x3b, 0x35, 0x3b, 0x36, 0x53, 0x6f, 0x6e, 0x64, 0x61, 0x67, 0x3b, 0x4d, 0x61, 0x61, 0x6e,
-0x64, 0x61, 0x67, 0x3b, 0x44, 0x69, 0x6e, 0x73, 0x64, 0x61, 0x67, 0x3b, 0x57, 0x6f, 0x65, 0x6e, 0x73, 0x64, 0x61, 0x67,
-0x3b, 0x44, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x64, 0x61, 0x67, 0x3b, 0x56, 0x72, 0x79, 0x64, 0x61, 0x67, 0x3b, 0x53, 0x61,
-0x74, 0x65, 0x72, 0x64, 0x61, 0x67, 0x53, 0x6f, 0x2e, 0x3b, 0x4d, 0x61, 0x2e, 0x3b, 0x44, 0x69, 0x2e, 0x3b, 0x57, 0x6f,
-0x2e, 0x3b, 0x44, 0x6f, 0x2e, 0x3b, 0x56, 0x72, 0x2e, 0x3b, 0x53, 0x61, 0x2e, 0x53, 0x3b, 0x4d, 0x3b, 0x44, 0x3b, 0x57,
-0x3b, 0x44, 0x3b, 0x56, 0x3b, 0x53, 0x74, 0x73, 0x75, 0x294, 0x6e, 0x74, 0x73, 0x268, 0x3b, 0x74, 0x73, 0x75, 0x294, 0x75,
-0x6b, 0x70, 0xe0, 0x3b, 0x74, 0x73, 0x75, 0x294, 0x75, 0x67, 0x68, 0x254, 0x65, 0x3b, 0x74, 0x73, 0x75, 0x294, 0x75, 0x74,
-0x254, 0x300, 0x6d, 0x6c, 0xf2, 0x3b, 0x74, 0x73, 0x75, 0x294, 0x75, 0x6d, 0xe8, 0x3b, 0x74, 0x73, 0x75, 0x294, 0x75, 0x67,
-0x68, 0x268, 0x302, 0x6d, 0x3b, 0x74, 0x73, 0x75, 0x294, 0x6e, 0x64, 0x7a, 0x268, 0x6b, 0x254, 0x294, 0x254, 0x6e, 0x74, 0x73,
-0x3b, 0x6b, 0x70, 0x61, 0x3b, 0x67, 0x68, 0x254, 0x3b, 0x74, 0x254, 0x6d, 0x3b, 0x75, 0x6d, 0x65, 0x3b, 0x67, 0x68, 0x268,
-0x3b, 0x64, 0x7a, 0x6b, 0x6e, 0x3b, 0x6b, 0x3b, 0x67, 0x3b, 0x74, 0x3b, 0x75, 0x3b, 0x67, 0x3b, 0x64, 0x4b, 0x77, 0x65,
-0x73, 0x69, 0x64, 0x61, 0x3b, 0x44, 0x77, 0x6f, 0x77, 0x64, 0x61, 0x3b, 0x42, 0x65, 0x6e, 0x61, 0x64, 0x61, 0x3b, 0x57,
-0x75, 0x6b, 0x75, 0x64, 0x61, 0x3b, 0x59, 0x61, 0x77, 0x64, 0x61, 0x3b, 0x46, 0x69, 0x64, 0x61, 0x3b, 0x4d, 0x65, 0x6d,
-0x65, 0x6e, 0x65, 0x64, 0x61, 0x4b, 0x77, 0x65, 0x3b, 0x44, 0x77, 0x6f, 0x3b, 0x42, 0x65, 0x6e, 0x3b, 0x57, 0x75, 0x6b,
-0x3b, 0x59, 0x61, 0x77, 0x3b, 0x46, 0x69, 0x61, 0x3b, 0x4d, 0x65, 0x6d, 0x4b, 0x3b, 0x44, 0x3b, 0x42, 0x3b, 0x57, 0x3b,
-0x59, 0x3b, 0x46, 0x3b, 0x4d, 0x65, 0x20, 0x64, 0x69, 0x65, 0x6c, 0x3b, 0x65, 0x20, 0x68, 0xeb, 0x6e, 0xeb, 0x3b, 0x65,
-0x20, 0x6d, 0x61, 0x72, 0x74, 0xeb, 0x3b, 0x65, 0x20, 0x6d, 0xeb, 0x72, 0x6b, 0x75, 0x72, 0xeb, 0x3b, 0x65, 0x20, 0x65,
-0x6e, 0x6a, 0x74, 0x65, 0x3b, 0x65, 0x20, 0x70, 0x72, 0x65, 0x6d, 0x74, 0x65, 0x3b, 0x65, 0x20, 0x73, 0x68, 0x74, 0x75,
-0x6e, 0xeb, 0x64, 0x69, 0x65, 0x3b, 0x68, 0xeb, 0x6e, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x6d, 0xeb, 0x72, 0x3b, 0x65, 0x6e,
-0x6a, 0x3b, 0x70, 0x72, 0x65, 0x3b, 0x73, 0x68, 0x74, 0x44, 0x69, 0x65, 0x3b, 0x48, 0xeb, 0x6e, 0x3b, 0x4d, 0x61, 0x72,
-0x3b, 0x4d, 0xeb, 0x72, 0x3b, 0x45, 0x6e, 0x6a, 0x3b, 0x50, 0x72, 0x65, 0x3b, 0x53, 0x68, 0x74, 0x64, 0x3b, 0x68, 0x3b,
-0x6d, 0x3b, 0x6d, 0x3b, 0x65, 0x3b, 0x70, 0x3b, 0x73, 0x68, 0x12a5, 0x1211, 0x12f5, 0x3b, 0x1230, 0x129e, 0x3b, 0x121b, 0x12ad, 0x1230,
-0x129e, 0x3b, 0x1228, 0x1261, 0x12d5, 0x3b, 0x1210, 0x1219, 0x1235, 0x3b, 0x12d3, 0x122d, 0x1265, 0x3b, 0x1245, 0x12f3, 0x121c, 0x12a5, 0x1211, 0x12f5,
-0x3b, 0x1230, 0x129e, 0x3b, 0x121b, 0x12ad, 0x1230, 0x3b, 0x1228, 0x1261, 0x12d5, 0x3b, 0x1210, 0x1219, 0x1235, 0x3b, 0x12d3, 0x122d, 0x1265, 0x3b,
-0x1245, 0x12f3, 0x121c, 0x12a5, 0x3b, 0x1230, 0x3b, 0x121b, 0x3b, 0x1228, 0x3b, 0x1210, 0x3b, 0x12d3, 0x3b, 0x1245, 0x627, 0x644, 0x623, 0x62d,
-0x62f, 0x3b, 0x627, 0x644, 0x627, 0x62b, 0x646, 0x64a, 0x646, 0x3b, 0x627, 0x644, 0x62b, 0x644, 0x627, 0x62b, 0x627, 0x621, 0x3b, 0x627,
-0x644, 0x623, 0x631, 0x628, 0x639, 0x627, 0x621, 0x3b, 0x627, 0x644, 0x62e, 0x645, 0x64a, 0x633, 0x3b, 0x627, 0x644, 0x62c, 0x645, 0x639,
-0x629, 0x3b, 0x627, 0x644, 0x633, 0x628, 0x62a, 0x62d, 0x3b, 0x646, 0x3b, 0x62b, 0x3b, 0x631, 0x3b, 0x62e, 0x3b, 0x62c, 0x3b, 0x633,
-0x56f, 0x56b, 0x580, 0x561, 0x56f, 0x56b, 0x3b, 0x565, 0x580, 0x56f, 0x578, 0x582, 0x577, 0x561, 0x562, 0x569, 0x56b, 0x3b, 0x565, 0x580,
-0x565, 0x584, 0x577, 0x561, 0x562, 0x569, 0x56b, 0x3b, 0x579, 0x578, 0x580, 0x565, 0x584, 0x577, 0x561, 0x562, 0x569, 0x56b, 0x3b, 0x570,
-0x56b, 0x576, 0x563, 0x577, 0x561, 0x562, 0x569, 0x56b, 0x3b, 0x578, 0x582, 0x580, 0x562, 0x561, 0x569, 0x3b, 0x577, 0x561, 0x562, 0x561,
-0x569, 0x56f, 0x56b, 0x580, 0x3b, 0x565, 0x580, 0x56f, 0x3b, 0x565, 0x580, 0x584, 0x3b, 0x579, 0x580, 0x584, 0x3b, 0x570, 0x576, 0x563,
-0x3b, 0x578, 0x582, 0x580, 0x3b, 0x577, 0x562, 0x569, 0x53f, 0x3b, 0x535, 0x3b, 0x535, 0x3b, 0x549, 0x3b, 0x540, 0x3b, 0x548, 0x3b,
-0x547, 0x9a6, 0x9c7, 0x993, 0x9ac, 0x9be, 0x9f0, 0x3b, 0x9b8, 0x9cb, 0x9ae, 0x9ac, 0x9be, 0x9f0, 0x3b, 0x9ae, 0x999, 0x9cd, 0x997, 0x9b2,
-0x9ac, 0x9be, 0x9f0, 0x3b, 0x9ac, 0x9c1, 0x9a7, 0x9ac, 0x9be, 0x9f0, 0x3b, 0x9ac, 0x9c3, 0x9b9, 0x9b8, 0x9cd, 0x9aa, 0x9a4, 0x9bf, 0x9ac,
-0x9be, 0x9f0, 0x3b, 0x9b6, 0x9c1, 0x995, 0x9cd, 0x9f0, 0x9ac, 0x9be, 0x9f0, 0x3b, 0x9b6, 0x9a8, 0x9bf, 0x9ac, 0x9be, 0x9f0, 0x9a6, 0x9c7,
-0x993, 0x3b, 0x9b8, 0x9cb, 0x9ae, 0x3b, 0x9ae, 0x999, 0x9cd, 0x997, 0x9b2, 0x3b, 0x9ac, 0x9c1, 0x9a7, 0x3b, 0x9ac, 0x9c3, 0x9b9, 0x3b,
-0x9b6, 0x9c1, 0x995, 0x9cd, 0x9f0, 0x3b, 0x9b6, 0x9a8, 0x9bf, 0x9a6, 0x3b, 0x9b8, 0x3b, 0x9ae, 0x3b, 0x9ac, 0x3b, 0x9ac, 0x3b, 0x9b6,
-0x3b, 0x9b6, 0x64, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x75, 0x3b, 0x6c, 0x6c, 0x75, 0x6e, 0x65, 0x73, 0x3b, 0x6d, 0x61, 0x72,
-0x74, 0x65, 0x73, 0x3b, 0x6d, 0x69, 0xe9, 0x72, 0x63, 0x6f, 0x6c, 0x65, 0x73, 0x3b, 0x78, 0x75, 0x65, 0x76, 0x65, 0x73,
-0x3b, 0x76, 0x69, 0x65, 0x6e, 0x72, 0x65, 0x73, 0x3b, 0x73, 0xe1, 0x62, 0x61, 0x64, 0x75, 0x64, 0x6f, 0x6d, 0x3b, 0x6c,
-0x6c, 0x75, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x6d, 0x69, 0xe9, 0x3b, 0x78, 0x75, 0x65, 0x3b, 0x76, 0x69, 0x65, 0x3b, 0x73,
-0xe1, 0x62, 0x44, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x58, 0x3b, 0x56, 0x3b, 0x53, 0x4a, 0x75, 0x6d, 0x61, 0x70,
-0x69, 0x6c, 0x69, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0x61, 0x74, 0x75, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x6e, 0x6e, 0x65,
-0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x41, 0x6c, 0x68, 0x61, 0x6d, 0x69, 0x73, 0x69, 0x3b, 0x49,
-0x6a, 0x75, 0x6d, 0x61, 0x61, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x6d, 0x6f, 0x73, 0x69, 0x4a, 0x70, 0x69, 0x3b, 0x4a, 0x74,
-0x74, 0x3b, 0x4a, 0x6e, 0x6e, 0x3b, 0x4a, 0x74, 0x6e, 0x3b, 0x41, 0x6c, 0x68, 0x3b, 0x49, 0x6a, 0x6d, 0x3b, 0x4a, 0x6d,
-0x6f, 0x4a, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x41, 0x3b, 0x49, 0x3b, 0x4a, 0x62, 0x61, 0x7a, 0x61, 0x72, 0x3b,
-0x62, 0x61, 0x7a, 0x61, 0x72, 0x20, 0x65, 0x72, 0x74, 0x259, 0x73, 0x69, 0x3b, 0xe7, 0x259, 0x72, 0x15f, 0x259, 0x6e, 0x62,
-0x259, 0x20, 0x61, 0x78, 0x15f, 0x61, 0x6d, 0x131, 0x3b, 0xe7, 0x259, 0x72, 0x15f, 0x259, 0x6e, 0x62, 0x259, 0x3b, 0x63, 0xfc,
-0x6d, 0x259, 0x20, 0x61, 0x78, 0x15f, 0x61, 0x6d, 0x131, 0x3b, 0x63, 0xfc, 0x6d, 0x259, 0x3b, 0x15f, 0x259, 0x6e, 0x62, 0x259,
-0x42, 0x2e, 0x3b, 0x42, 0x2e, 0x45, 0x2e, 0x3b, 0xc7, 0x2e, 0x41, 0x2e, 0x3b, 0xc7, 0x2e, 0x3b, 0x43, 0x2e, 0x41, 0x2e,
-0x3b, 0x43, 0x2e, 0x3b, 0x15e, 0x2e, 0x42, 0x2e, 0x3b, 0x42, 0x2e, 0x65, 0x2e, 0x3b, 0xc7, 0x2e, 0x61, 0x2e, 0x3b, 0xc7,
-0x2e, 0x3b, 0x43, 0x2e, 0x61, 0x2e, 0x3b, 0x43, 0x2e, 0x3b, 0x15e, 0x2e, 0x431, 0x430, 0x437, 0x430, 0x440, 0x3b, 0x431, 0x430,
-0x437, 0x430, 0x440, 0x20, 0x435, 0x440, 0x442, 0x4d9, 0x441, 0x438, 0x3b, 0x447, 0x4d9, 0x440, 0x448, 0x4d9, 0x43d, 0x431, 0x4d9, 0x20,
-0x430, 0x445, 0x448, 0x430, 0x43c, 0x44b, 0x3b, 0x447, 0x4d9, 0x440, 0x448, 0x4d9, 0x43d, 0x431, 0x4d9, 0x3b, 0x4b9, 0x4af, 0x43c, 0x4d9,
-0x20, 0x430, 0x445, 0x448, 0x430, 0x43c, 0x44b, 0x3b, 0x4b9, 0x4af, 0x43c, 0x4d9, 0x3b, 0x448, 0x4d9, 0x43d, 0x431, 0x4d9, 0x411, 0x2e,
-0x3b, 0x411, 0x2e, 0x415, 0x2e, 0x3b, 0x427, 0x2e, 0x410, 0x2e, 0x3b, 0x427, 0x2e, 0x3b, 0x4b8, 0x2e, 0x410, 0x2e, 0x3b, 0x4b8,
-0x2e, 0x3b, 0x428, 0x2e, 0x73, 0x254, 0x301, 0x6e, 0x64, 0x1dd, 0x3b, 0x6c, 0x1dd, 0x6e, 0x64, 0xed, 0x3b, 0x6d, 0x61, 0x61,
-0x64, 0xed, 0x3b, 0x6d, 0x25b, 0x6b, 0x72, 0x25b, 0x64, 0xed, 0x3b, 0x6a, 0x1dd, 0x1dd, 0x64, 0xed, 0x3b, 0x6a, 0xfa, 0x6d,
-0x62, 0xe1, 0x3b, 0x73, 0x61, 0x6d, 0x64, 0xed, 0x73, 0x254, 0x301, 0x6e, 0x3b, 0x6c, 0x1dd, 0x6e, 0x3b, 0x6d, 0x61, 0x61,
-0x3b, 0x6d, 0x25b, 0x6b, 0x3b, 0x6a, 0x1dd, 0x1dd, 0x3b, 0x6a, 0xfa, 0x6d, 0x3b, 0x73, 0x61, 0x6d, 0x73, 0x3b, 0x6c, 0x3b,
-0x6d, 0x3b, 0x6d, 0x3b, 0x6a, 0x3b, 0x6a, 0x3b, 0x73, 0x6b, 0x61, 0x72, 0x69, 0x3b, 0x6e, 0x74, 0x25b, 0x6e, 0x25b, 0x3b,
-0x74, 0x61, 0x72, 0x61, 0x74, 0x61, 0x3b, 0x61, 0x72, 0x61, 0x62, 0x61, 0x3b, 0x61, 0x6c, 0x61, 0x6d, 0x69, 0x73, 0x61,
-0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x3b, 0x73, 0x69, 0x62, 0x69, 0x72, 0x69, 0x6b, 0x61, 0x72, 0x3b, 0x6e, 0x74, 0x25b, 0x3b,
-0x74, 0x61, 0x72, 0x3b, 0x61, 0x72, 0x61, 0x3b, 0x61, 0x6c, 0x61, 0x3b, 0x6a, 0x75, 0x6d, 0x3b, 0x73, 0x69, 0x62, 0x4b,
-0x3b, 0x4e, 0x3b, 0x54, 0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x4a, 0x3b, 0x53, 0x9b0, 0x9ac, 0x9bf, 0x9ac, 0x9be, 0x9b0, 0x3b, 0x9b8,
-0x9cb, 0x9ae, 0x9ac, 0x9be, 0x9b0, 0x3b, 0x9ae, 0x999, 0x9cd, 0x997, 0x9b2, 0x9ac, 0x9be, 0x9b0, 0x3b, 0x9ac, 0x9c1, 0x9a7, 0x9ac, 0x9be,
-0x9b0, 0x3b, 0x9ac, 0x9c3, 0x9b9, 0x9b8, 0x9cd, 0x9aa, 0x9a4, 0x9bf, 0x9ac, 0x9be, 0x9b0, 0x3b, 0x9b6, 0x9c1, 0x995, 0x9cd, 0x9b0, 0x9ac,
-0x9be, 0x9b0, 0x3b, 0x9b6, 0x9a8, 0x9bf, 0x9ac, 0x9be, 0x9b0, 0x9b0, 0x9ac, 0x9bf, 0x3b, 0x9b8, 0x9cb, 0x9ae, 0x3b, 0x9ae, 0x999, 0x9cd,
-0x997, 0x9b2, 0x3b, 0x9ac, 0x9c1, 0x9a7, 0x3b, 0x9ac, 0x9c3, 0x9b9, 0x9b8, 0x9cd, 0x9aa, 0x9a4, 0x9bf, 0x3b, 0x9b6, 0x9c1, 0x995, 0x9cd,
-0x9b0, 0x3b, 0x9b6, 0x9a8, 0x9bf, 0x9b0, 0x3b, 0x9b8, 0x9cb, 0x3b, 0x9ae, 0x3b, 0x9ac, 0x9c1, 0x3b, 0x9ac, 0x9c3, 0x3b, 0x9b6, 0x9c1,
-0x3b, 0x9b6, 0x14b, 0x67, 0x77, 0xe0, 0x20, 0x6e, 0x254, 0x302, 0x79, 0x3b, 0x14b, 0x67, 0x77, 0xe0, 0x20, 0x6e, 0x6a, 0x61,
-0x14b, 0x67, 0x75, 0x6d, 0x62, 0x61, 0x3b, 0x14b, 0x67, 0x77, 0xe0, 0x20, 0xfb, 0x6d, 0x3b, 0x14b, 0x67, 0x77, 0xe0, 0x20,
-0x14b, 0x67, 0xea, 0x3b, 0x14b, 0x67, 0x77, 0xe0, 0x20, 0x6d, 0x62, 0x254, 0x6b, 0x3b, 0x14b, 0x67, 0x77, 0xe0, 0x20, 0x6b,
-0x254, 0x254, 0x3b, 0x14b, 0x67, 0x77, 0xe0, 0x20, 0x6a, 0xf4, 0x6e, 0x6e, 0x254, 0x79, 0x3b, 0x6e, 0x6a, 0x61, 0x3b, 0x75,
-0x75, 0x6d, 0x3b, 0x14b, 0x67, 0x65, 0x3b, 0x6d, 0x62, 0x254, 0x3b, 0x6b, 0x254, 0x254, 0x3b, 0x6a, 0x6f, 0x6e, 0x6e, 0x3b,
-0x6e, 0x3b, 0x75, 0x3b, 0x14b, 0x3b, 0x6d, 0x3b, 0x6b, 0x3b, 0x6a, 0x69, 0x67, 0x61, 0x6e, 0x64, 0x65, 0x61, 0x3b, 0x61,
-0x73, 0x74, 0x65, 0x6c, 0x65, 0x68, 0x65, 0x6e, 0x61, 0x3b, 0x61, 0x73, 0x74, 0x65, 0x61, 0x72, 0x74, 0x65, 0x61, 0x3b,
-0x61, 0x73, 0x74, 0x65, 0x61, 0x7a, 0x6b, 0x65, 0x6e, 0x61, 0x3b, 0x6f, 0x73, 0x74, 0x65, 0x67, 0x75, 0x6e, 0x61, 0x3b,
-0x6f, 0x73, 0x74, 0x69, 0x72, 0x61, 0x6c, 0x61, 0x3b, 0x6c, 0x61, 0x72, 0x75, 0x6e, 0x62, 0x61, 0x74, 0x61, 0x69, 0x67,
-0x2e, 0x3b, 0x61, 0x6c, 0x2e, 0x3b, 0x61, 0x72, 0x2e, 0x3b, 0x61, 0x7a, 0x2e, 0x3b, 0x6f, 0x67, 0x2e, 0x3b, 0x6f, 0x72,
-0x2e, 0x3b, 0x6c, 0x72, 0x2e, 0x49, 0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x4f, 0x3b, 0x4f, 0x3b, 0x4c, 0x43d, 0x44f,
-0x434, 0x437, 0x435, 0x43b, 0x44f, 0x3b, 0x43f, 0x430, 0x43d, 0x44f, 0x434, 0x437, 0x435, 0x43b, 0x430, 0x43a, 0x3b, 0x430, 0x45e, 0x442,
-0x43e, 0x440, 0x430, 0x43a, 0x3b, 0x441, 0x435, 0x440, 0x430, 0x434, 0x430, 0x3b, 0x447, 0x430, 0x446, 0x432, 0x435, 0x440, 0x3b, 0x43f,
-0x44f, 0x442, 0x43d, 0x456, 0x446, 0x430, 0x3b, 0x441, 0x443, 0x431, 0x43e, 0x442, 0x430, 0x43d, 0x434, 0x3b, 0x43f, 0x43d, 0x3b, 0x430,
-0x45e, 0x3b, 0x441, 0x440, 0x3b, 0x447, 0x446, 0x3b, 0x43f, 0x442, 0x3b, 0x441, 0x431, 0x43d, 0x3b, 0x43f, 0x3b, 0x430, 0x3b, 0x441,
-0x3b, 0x447, 0x3b, 0x43f, 0x3b, 0x441, 0x50, 0x61, 0x20, 0x4d, 0x75, 0x6c, 0x75, 0x6e, 0x67, 0x75, 0x3b, 0x50, 0x61, 0x6c,
-0x69, 0x63, 0x68, 0x69, 0x6d, 0x6f, 0x3b, 0x50, 0x61, 0x6c, 0x69, 0x63, 0x68, 0x69, 0x62, 0x75, 0x6c, 0x69, 0x3b, 0x50,
-0x61, 0x6c, 0x69, 0x63, 0x68, 0x69, 0x74, 0x61, 0x74, 0x75, 0x3b, 0x50, 0x61, 0x6c, 0x69, 0x63, 0x68, 0x69, 0x6e, 0x65,
-0x3b, 0x50, 0x61, 0x6c, 0x69, 0x63, 0x68, 0x69, 0x73, 0x61, 0x6e, 0x6f, 0x3b, 0x50, 0x61, 0x63, 0x68, 0x69, 0x62, 0x65,
-0x6c, 0x75, 0x73, 0x68, 0x69, 0x70, 0x61, 0x20, 0x6d, 0x75, 0x6c, 0x75, 0x6e, 0x67, 0x75, 0x3b, 0x70, 0x61, 0x20, 0x73,
-0x68, 0x61, 0x68, 0x75, 0x76, 0x69, 0x6c, 0x75, 0x68, 0x61, 0x3b, 0x70, 0x61, 0x20, 0x68, 0x69, 0x76, 0x69, 0x6c, 0x69,
-0x3b, 0x70, 0x61, 0x20, 0x68, 0x69, 0x64, 0x61, 0x74, 0x75, 0x3b, 0x70, 0x61, 0x20, 0x68, 0x69, 0x74, 0x61, 0x79, 0x69,
-0x3b, 0x70, 0x61, 0x20, 0x68, 0x69, 0x68, 0x61, 0x6e, 0x75, 0x3b, 0x70, 0x61, 0x20, 0x73, 0x68, 0x61, 0x68, 0x75, 0x6c,
-0x65, 0x6d, 0x62, 0x65, 0x6c, 0x61, 0x4d, 0x75, 0x6c, 0x3b, 0x56, 0x69, 0x6c, 0x3b, 0x48, 0x69, 0x76, 0x3b, 0x48, 0x69,
-0x64, 0x3b, 0x48, 0x69, 0x74, 0x3b, 0x48, 0x69, 0x68, 0x3b, 0x4c, 0x65, 0x6d, 0x4d, 0x3b, 0x4a, 0x3b, 0x48, 0x3b, 0x48,
-0x3b, 0x48, 0x3b, 0x57, 0x3b, 0x4a, 0x930, 0x92c, 0x940, 0x92c, 0x93e, 0x930, 0x3b, 0x938, 0x94b, 0x92e, 0x92c, 0x93e, 0x930, 0x3b,
-0x92e, 0x902, 0x917, 0x932, 0x92c, 0x93e, 0x930, 0x3b, 0x92c, 0x941, 0x927, 0x92c, 0x93e, 0x930, 0x3b, 0x92c, 0x943, 0x939, 0x938, 0x94d,
-0x92a, 0x924, 0x93f, 0x92c, 0x93e, 0x930, 0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930, 0x92c, 0x93e, 0x930, 0x3b, 0x938, 0x928, 0x940, 0x91a,
-0x930, 0x930, 0x92c, 0x93f, 0x92c, 0x93e, 0x930, 0x3b, 0x938, 0x92e, 0x92c, 0x93e, 0x930, 0x3b, 0x92e, 0x902, 0x917, 0x932, 0x92c, 0x93e,
-0x930, 0x3b, 0x92c, 0x941, 0x927, 0x92c, 0x93e, 0x930, 0x3b, 0x92c, 0x93f, 0x938, 0x94d, 0x925, 0x93f, 0x92c, 0x93e, 0x930, 0x3b, 0x938,
-0x941, 0x941, 0x916, 0x941, 0x930, 0x92c, 0x93e, 0x930, 0x3b, 0x938, 0x928, 0x93f, 0x92c, 0x93e, 0x930, 0x930, 0x92c, 0x93f, 0x92c, 0x93e,
-0x930, 0x3b, 0x938, 0x92e, 0x92c, 0x93e, 0x930, 0x3b, 0x92e, 0x902, 0x917, 0x932, 0x92c, 0x93e, 0x930, 0x3b, 0x92c, 0x941, 0x927, 0x92c,
-0x93e, 0x930, 0x3b, 0x92c, 0x93f, 0x938, 0x94d, 0x925, 0x93f, 0x92c, 0x93e, 0x930, 0x3b, 0x938, 0x941, 0x916, 0x941, 0x930, 0x92c, 0x93e,
-0x930, 0x3b, 0x938, 0x928, 0x93f, 0x92c, 0x93e, 0x930, 0x930, 0x92c, 0x93f, 0x3b, 0x938, 0x92e, 0x3b, 0x92e, 0x902, 0x917, 0x932, 0x3b,
-0x92c, 0x941, 0x927, 0x3b, 0x92c, 0x93f, 0x938, 0x94d, 0x925, 0x93f, 0x3b, 0x938, 0x941, 0x916, 0x941, 0x930, 0x3b, 0x938, 0x928, 0x93f,
-0x930, 0x3b, 0x938, 0x3b, 0x92e, 0x902, 0x3b, 0x92c, 0x941, 0x3b, 0x92c, 0x93f, 0x3b, 0x938, 0x941, 0x3b, 0x938, 0x6e, 0x65, 0x64,
-0x6a, 0x65, 0x6c, 0x6a, 0x61, 0x3b, 0x70, 0x6f, 0x6e, 0x65, 0x64, 0x6a, 0x65, 0x6c, 0x6a, 0x61, 0x6b, 0x3b, 0x75, 0x74,
-0x6f, 0x72, 0x61, 0x6b, 0x3b, 0x73, 0x72, 0x69, 0x6a, 0x65, 0x64, 0x61, 0x3b, 0x10d, 0x65, 0x74, 0x76, 0x72, 0x74, 0x61,
-0x6b, 0x3b, 0x70, 0x65, 0x74, 0x61, 0x6b, 0x3b, 0x73, 0x75, 0x62, 0x6f, 0x74, 0x61, 0x6e, 0x65, 0x64, 0x3b, 0x70, 0x6f,
-0x6e, 0x3b, 0x75, 0x74, 0x6f, 0x3b, 0x73, 0x72, 0x69, 0x3b, 0x10d, 0x65, 0x74, 0x3b, 0x70, 0x65, 0x74, 0x3b, 0x73, 0x75,
-0x62, 0x6e, 0x3b, 0x70, 0x3b, 0x75, 0x3b, 0x73, 0x3b, 0x10d, 0x3b, 0x70, 0x3b, 0x73, 0x4e, 0x3b, 0x50, 0x3b, 0x55, 0x3b,
-0x53, 0x3b, 0x10c, 0x3b, 0x50, 0x3b, 0x53, 0x43d, 0x435, 0x434, 0x458, 0x435, 0x459, 0x430, 0x3b, 0x43f, 0x43e, 0x43d, 0x435, 0x434,
-0x458, 0x435, 0x459, 0x430, 0x43a, 0x3b, 0x443, 0x442, 0x43e, 0x440, 0x430, 0x43a, 0x3b, 0x441, 0x440, 0x438, 0x458, 0x435, 0x434, 0x430,
-0x3b, 0x447, 0x435, 0x442, 0x432, 0x440, 0x442, 0x430, 0x43a, 0x3b, 0x43f, 0x435, 0x442, 0x430, 0x43a, 0x3b, 0x441, 0x443, 0x431, 0x43e,
-0x442, 0x430, 0x43d, 0x435, 0x434, 0x3b, 0x43f, 0x43e, 0x43d, 0x3b, 0x443, 0x442, 0x43e, 0x3b, 0x441, 0x440, 0x438, 0x3b, 0x447, 0x435,
-0x442, 0x3b, 0x43f, 0x435, 0x442, 0x3b, 0x441, 0x443, 0x431, 0x43d, 0x3b, 0x43f, 0x3b, 0x443, 0x3b, 0x441, 0x3b, 0x447, 0x3b, 0x43f,
-0x3b, 0x441, 0x53, 0x75, 0x6c, 0x3b, 0x4c, 0x75, 0x6e, 0x3b, 0x4d, 0x65, 0x75, 0x72, 0x7a, 0x68, 0x3b, 0x4d, 0x65, 0x72,
-0x63, 0x2bc, 0x68, 0x65, 0x72, 0x3b, 0x59, 0x61, 0x6f, 0x75, 0x3b, 0x47, 0x77, 0x65, 0x6e, 0x65, 0x72, 0x3b, 0x53, 0x61,
-0x64, 0x6f, 0x72, 0x6e, 0x53, 0x75, 0x6c, 0x3b, 0x4c, 0x75, 0x6e, 0x3b, 0x4d, 0x65, 0x75, 0x2e, 0x3b, 0x4d, 0x65, 0x72,
-0x2e, 0x3b, 0x59, 0x61, 0x6f, 0x75, 0x3b, 0x47, 0x77, 0x65, 0x2e, 0x3b, 0x53, 0x61, 0x64, 0x2e, 0x53, 0x75, 0x3b, 0x4c,
-0x3b, 0x4d, 0x7a, 0x3b, 0x4d, 0x63, 0x3b, 0x59, 0x3b, 0x47, 0x3b, 0x53, 0x61, 0x43d, 0x435, 0x434, 0x435, 0x43b, 0x44f, 0x3b,
-0x43f, 0x43e, 0x43d, 0x435, 0x434, 0x435, 0x43b, 0x43d, 0x438, 0x43a, 0x3b, 0x432, 0x442, 0x43e, 0x440, 0x43d, 0x438, 0x43a, 0x3b, 0x441,
-0x440, 0x44f, 0x434, 0x430, 0x3b, 0x447, 0x435, 0x442, 0x432, 0x44a, 0x440, 0x442, 0x44a, 0x43a, 0x3b, 0x43f, 0x435, 0x442, 0x44a, 0x43a,
-0x3b, 0x441, 0x44a, 0x431, 0x43e, 0x442, 0x430, 0x43d, 0x434, 0x3b, 0x43f, 0x43d, 0x3b, 0x432, 0x442, 0x3b, 0x441, 0x440, 0x3b, 0x447,
-0x442, 0x3b, 0x43f, 0x442, 0x3b, 0x441, 0x431, 0x43d, 0x3b, 0x43f, 0x3b, 0x432, 0x3b, 0x441, 0x3b, 0x447, 0x3b, 0x43f, 0x3b, 0x441,
-0x1010, 0x1014, 0x1004, 0x103a, 0x1039, 0x1002, 0x1014, 0x103d, 0x1031, 0x3b, 0x1010, 0x1014, 0x1004, 0x103a, 0x1039, 0x101c, 0x102c, 0x3b, 0x1021, 0x1004,
-0x103a, 0x1039, 0x1002, 0x102b, 0x3b, 0x1017, 0x102f, 0x1012, 0x1039, 0x1013, 0x101f, 0x1030, 0x1038, 0x3b, 0x1000, 0x103c, 0x102c, 0x101e, 0x1015, 0x1010,
-0x1031, 0x1038, 0x3b, 0x101e, 0x1031, 0x102c, 0x1000, 0x103c, 0x102c, 0x3b, 0x1005, 0x1014, 0x1031, 0x1010, 0x3b, 0x1010, 0x3b, 0x1021, 0x3b, 0x1017,
-0x3b, 0x1000, 0x3b, 0x101e, 0x3b, 0x1005, 0x661f, 0x671f, 0x65e5, 0x3b, 0x661f, 0x671f, 0x4e00, 0x3b, 0x661f, 0x671f, 0x4e8c, 0x3b, 0x661f, 0x671f,
-0x4e09, 0x3b, 0x661f, 0x671f, 0x56db, 0x3b, 0x661f, 0x671f, 0x4e94, 0x3b, 0x661f, 0x671f, 0x516d, 0x65e5, 0x3b, 0x4e00, 0x3b, 0x4e8c, 0x3b, 0x4e09,
-0x3b, 0x56db, 0x3b, 0x4e94, 0x3b, 0x516d, 0x5468, 0x65e5, 0x3b, 0x5468, 0x4e00, 0x3b, 0x5468, 0x4e8c, 0x3b, 0x5468, 0x4e09, 0x3b, 0x5468, 0x56db,
-0x3b, 0x5468, 0x4e94, 0x3b, 0x5468, 0x516d, 0x64, 0x69, 0x75, 0x6d, 0x65, 0x6e, 0x67, 0x65, 0x3b, 0x64, 0x69, 0x6c, 0x6c, 0x75,
-0x6e, 0x73, 0x3b, 0x64, 0x69, 0x6d, 0x61, 0x72, 0x74, 0x73, 0x3b, 0x64, 0x69, 0x6d, 0x65, 0x63, 0x72, 0x65, 0x73, 0x3b,
-0x64, 0x69, 0x6a, 0x6f, 0x75, 0x73, 0x3b, 0x64, 0x69, 0x76, 0x65, 0x6e, 0x64, 0x72, 0x65, 0x73, 0x3b, 0x64, 0x69, 0x73,
-0x73, 0x61, 0x62, 0x74, 0x65, 0x64, 0x67, 0x2e, 0x3b, 0x64, 0x6c, 0x2e, 0x3b, 0x64, 0x74, 0x2e, 0x3b, 0x64, 0x63, 0x2e,
-0x3b, 0x64, 0x6a, 0x2e, 0x3b, 0x64, 0x76, 0x2e, 0x3b, 0x64, 0x73, 0x2e, 0x64, 0x67, 0x3b, 0x64, 0x6c, 0x3b, 0x64, 0x74,
-0x3b, 0x64, 0x63, 0x3b, 0x64, 0x6a, 0x3b, 0x64, 0x76, 0x3b, 0x64, 0x73, 0x44, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x6f, 0x3b,
-0x4c, 0x75, 0x6e, 0x65, 0x73, 0x3b, 0x4d, 0x61, 0x72, 0x74, 0x65, 0x73, 0x3b, 0x4d, 0x69, 0x79, 0x65, 0x72, 0x6b, 0x75,
-0x6c, 0x65, 0x73, 0x3b, 0x48, 0x75, 0x77, 0x65, 0x62, 0x65, 0x73, 0x3b, 0x42, 0x69, 0x79, 0x65, 0x72, 0x6e, 0x65, 0x73,
-0x3b, 0x53, 0x61, 0x62, 0x61, 0x64, 0x6f, 0x44, 0x6f, 0x6d, 0x3b, 0x4c, 0x75, 0x6e, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x4d,
-0x69, 0x79, 0x3b, 0x48, 0x75, 0x77, 0x3b, 0x42, 0x69, 0x79, 0x3b, 0x53, 0x61, 0x62, 0x44, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b,
-0x4d, 0x3b, 0x48, 0x3b, 0x42, 0x3b, 0x53, 0x41, 0x73, 0x61, 0x6d, 0x61, 0x73, 0x3b, 0x41, 0x79, 0x6e, 0x61, 0x73, 0x3b,
-0x41, 0x73, 0x69, 0x6e, 0x61, 0x73, 0x3b, 0x41, 0x6b, 0x72, 0x61, 0x73, 0x3b, 0x41, 0x6b, 0x77, 0x61, 0x73, 0x3b, 0x41,
-0x73, 0x69, 0x6d, 0x77, 0x61, 0x73, 0x3b, 0x41, 0x73, 0x69, 0x1e0d, 0x79, 0x61, 0x73, 0x41, 0x73, 0x61, 0x3b, 0x41, 0x79,
-0x6e, 0x3b, 0x41, 0x73, 0x6e, 0x3b, 0x41, 0x6b, 0x72, 0x3b, 0x41, 0x6b, 0x77, 0x3b, 0x41, 0x73, 0x6d, 0x3b, 0x41, 0x73,
-0x1e0d, 0x41, 0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x41, 0x6cc, 0x6d5, 0x6a9, 0x634, 0x6d5, 0x645,
-0x645, 0x6d5, 0x3b, 0x62f, 0x648, 0x648, 0x634, 0x6d5, 0x645, 0x645, 0x6d5, 0x3b, 0x633, 0x6ce, 0x634, 0x6d5, 0x645, 0x645, 0x6d5, 0x3b,
-0x686, 0x648, 0x627, 0x631, 0x634, 0x6d5, 0x645, 0x645, 0x6d5, 0x3b, 0x67e, 0x6ce, 0x646, 0x62c, 0x634, 0x6d5, 0x645, 0x645, 0x6d5, 0x3b,
-0x6be, 0x6d5, 0x6cc, 0x646, 0x6cc, 0x3b, 0x634, 0x6d5, 0x645, 0x645, 0x6d5, 0x6cc, 0x3b, 0x62f, 0x3b, 0x633, 0x3b, 0x686, 0x3b, 0x67e,
-0x3b, 0x6be, 0x3b, 0x634, 0xd804, 0xdd22, 0xd804, 0xdd27, 0xd804, 0xdd1d, 0xd804, 0xdd28, 0xd804, 0xdd1d, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804,
-0xdd25, 0xd804, 0xdd27, 0xd804, 0xdd1f, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd1f, 0xd804, 0xdd27, 0xd804, 0xdd01,
-0xd804, 0xdd09, 0xd804, 0xdd27, 0xd804, 0xdd23, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd1d, 0xd804, 0xdd2a, 0xd804,
-0xdd16, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd1d, 0xd804, 0xdd33, 0xd804, 0xdd22, 0xd804, 0xdd28, 0xd804, 0xdd25,
-0xd804, 0xdd2a, 0xd804, 0xdd1b, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd25, 0xd804, 0xdd2a, 0xd804, 0xdd07, 0xd804,
-0xdd34, 0xd804, 0xdd07, 0xd804, 0xdd2e, 0xd804, 0xdd22, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd25, 0xd804, 0xdd27,
-0xd804, 0xdd1a, 0xd804, 0xdd28, 0xd804, 0xdd1d, 0xd804, 0xdd22, 0xd804, 0xdd34, 0xd804, 0xdd22, 0xd804, 0xdd27, 0xd804, 0xdd1d, 0xd804, 0xdd28, 0x3b, 0xd804,
-0xdd25, 0xd804, 0xdd27, 0xd804, 0xdd1f, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd1f, 0xd804, 0xdd27, 0xd804, 0xdd01, 0xd804, 0xdd09, 0xd804, 0xdd27, 0xd804, 0xdd23,
-0xd804, 0xdd34, 0x3b, 0xd804, 0xdd1d, 0xd804, 0xdd2a, 0xd804, 0xdd16, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd1d, 0xd804, 0xdd33, 0xd804, 0xdd22, 0xd804, 0xdd28,
-0xd804, 0xdd25, 0xd804, 0xdd2a, 0xd804, 0xdd1b, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd25, 0xd804, 0xdd2a, 0xd804, 0xdd07, 0xd804, 0xdd34, 0xd804, 0xdd07, 0xd804,
-0xdd2e, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd25, 0xd804, 0xdd27, 0xd804, 0xdd1a, 0xd804, 0xdd28, 0xd804, 0xdd22, 0xd804, 0xdd27, 0x3b, 0xd804,
-0xdd25, 0xd804, 0xdd27, 0x3b, 0xd804, 0xdd1f, 0xd804, 0xdd27, 0x3b, 0xd804, 0xdd1d, 0xd804, 0xdd2a, 0x3b, 0xd804, 0xdd1d, 0xd804, 0xdd33, 0xd804, 0xdd22,
-0xd804, 0xdd28, 0x3b, 0xd804, 0xdd25, 0xd804, 0xdd2a, 0x3b, 0xd804, 0xdd25, 0xd804, 0xdd27, 0x43a, 0x4c0, 0x438, 0x440, 0x430, 0x3b, 0x43e, 0x440,
-0x448, 0x43e, 0x442, 0x3b, 0x448, 0x438, 0x43d, 0x430, 0x440, 0x430, 0x3b, 0x43a, 0x445, 0x430, 0x430, 0x440, 0x430, 0x3b, 0x435, 0x430,
-0x440, 0x430, 0x3b, 0x43f, 0x4c0, 0x435, 0x440, 0x430, 0x441, 0x43a, 0x430, 0x3b, 0x448, 0x443, 0x43e, 0x442, 0x43a, 0x4c0, 0x438, 0x3b,
-0x43e, 0x440, 0x3b, 0x448, 0x438, 0x3b, 0x43a, 0x445, 0x430, 0x3b, 0x435, 0x430, 0x3b, 0x43f, 0x4c0, 0x435, 0x3b, 0x448, 0x443, 0x43e,
-0x43a, 0x4c0, 0x3b, 0x43e, 0x3b, 0x448, 0x3b, 0x43a, 0x445, 0x3b, 0x435, 0x3b, 0x43f, 0x4c0, 0x3b, 0x448, 0x13a4, 0x13be, 0x13d9, 0x13d3,
-0x13c6, 0x13cd, 0x13ac, 0x3b, 0x13a4, 0x13be, 0x13d9, 0x13d3, 0x13c9, 0x13c5, 0x13af, 0x3b, 0x13d4, 0x13b5, 0x13c1, 0x13a2, 0x13a6, 0x3b, 0x13e6, 0x13a2,
-0x13c1, 0x13a2, 0x13a6, 0x3b, 0x13c5, 0x13a9, 0x13c1, 0x13a2, 0x13a6, 0x3b, 0x13e7, 0x13be, 0x13a9, 0x13b6, 0x13cd, 0x13d7, 0x3b, 0x13a4, 0x13be, 0x13d9,
-0x13d3, 0x13c8, 0x13d5, 0x13be, 0x13c6, 0x13cd, 0x13ac, 0x3b, 0x13c9, 0x13c5, 0x13af, 0x3b, 0x13d4, 0x13b5, 0x13c1, 0x3b, 0x13e6, 0x13a2, 0x13c1, 0x3b,
-0x13c5, 0x13a9, 0x13c1, 0x3b, 0x13e7, 0x13be, 0x13a9, 0x3b, 0x13c8, 0x13d5, 0x13be, 0x13c6, 0x3b, 0x13c9, 0x3b, 0x13d4, 0x3b, 0x13e6, 0x3b, 0x13c5,
-0x3b, 0x13e7, 0x3b, 0x13a4, 0x53, 0x61, 0x6e, 0x64, 0x65, 0x3b, 0x4f, 0x72, 0x77, 0x6f, 0x6b, 0x75, 0x62, 0x61, 0x6e, 0x7a,
-0x61, 0x3b, 0x4f, 0x72, 0x77, 0x61, 0x6b, 0x61, 0x62, 0x69, 0x72, 0x69, 0x3b, 0x4f, 0x72, 0x77, 0x61, 0x6b, 0x61, 0x73,
-0x68, 0x61, 0x74, 0x75, 0x3b, 0x4f, 0x72, 0x77, 0x61, 0x6b, 0x61, 0x6e, 0x61, 0x3b, 0x4f, 0x72, 0x77, 0x61, 0x6b, 0x61,
-0x74, 0x61, 0x61, 0x6e, 0x6f, 0x3b, 0x4f, 0x72, 0x77, 0x61, 0x6d, 0x75, 0x6b, 0x61, 0x61, 0x67, 0x61, 0x53, 0x41, 0x4e,
-0x3b, 0x4f, 0x52, 0x4b, 0x3b, 0x4f, 0x4b, 0x42, 0x3b, 0x4f, 0x4b, 0x53, 0x3b, 0x4f, 0x4b, 0x4e, 0x3b, 0x4f, 0x4b, 0x54,
-0x3b, 0x4f, 0x4d, 0x4b, 0x53, 0x3b, 0x4b, 0x3b, 0x52, 0x3b, 0x53, 0x3b, 0x4e, 0x3b, 0x54, 0x3b, 0x4d, 0x9031, 0x65e5, 0x3b,
-0x9031, 0x4e00, 0x3b, 0x9031, 0x4e8c, 0x3b, 0x9031, 0x4e09, 0x3b, 0x9031, 0x56db, 0x3b, 0x9031, 0x4e94, 0x3b, 0x9031, 0x516d, 0x432, 0x44b, 0x440,
-0x441, 0x430, 0x440, 0x43d, 0x438, 0x43a, 0x443, 0x43d, 0x3b, 0x442, 0x443, 0x43d, 0x442, 0x438, 0x43a, 0x443, 0x43d, 0x3b, 0x44b, 0x442,
-0x43b, 0x430, 0x440, 0x438, 0x43a, 0x443, 0x43d, 0x3b, 0x44e, 0x43d, 0x43a, 0x443, 0x43d, 0x3b, 0x43a, 0x4d7, 0x4ab, 0x43d, 0x435, 0x440,
-0x43d, 0x438, 0x43a, 0x443, 0x43d, 0x3b, 0x44d, 0x440, 0x43d, 0x435, 0x43a, 0x443, 0x43d, 0x3b, 0x448, 0x4d1, 0x43c, 0x430, 0x442, 0x43a,
-0x443, 0x43d, 0x432, 0x44b, 0x440, 0x2e, 0x3b, 0x442, 0x443, 0x43d, 0x2e, 0x3b, 0x44b, 0x442, 0x43b, 0x2e, 0x3b, 0x44e, 0x43d, 0x2e,
-0x3b, 0x43a, 0x4d7, 0x4ab, 0x2e, 0x3b, 0x44d, 0x440, 0x2e, 0x3b, 0x448, 0x4d1, 0x43c, 0x2e, 0x412, 0x3b, 0x422, 0x3b, 0x42b, 0x3b,
-0x42e, 0x3b, 0x41a, 0x3b, 0x42d, 0x3b, 0x428, 0x53, 0x75, 0x6e, 0x6e, 0x64, 0x61, 0x61, 0x63, 0x68, 0x3b, 0x4d, 0x6f, 0x68,
-0x6e, 0x64, 0x61, 0x61, 0x63, 0x68, 0x3b, 0x44, 0x69, 0x6e, 0x6e, 0x73, 0x64, 0x61, 0x61, 0x63, 0x68, 0x3b, 0x4d, 0x65,
-0x74, 0x77, 0x6f, 0x63, 0x68, 0x3b, 0x44, 0x75, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x64, 0x61, 0x61, 0x63, 0x68, 0x3b, 0x46,
-0x72, 0x69, 0x69, 0x64, 0x61, 0x61, 0x63, 0x68, 0x3b, 0x53, 0x61, 0x6d, 0x73, 0x64, 0x61, 0x61, 0x63, 0x68, 0x53, 0x75,
-0x2e, 0x3b, 0x4d, 0x6f, 0x2e, 0x3b, 0x44, 0x69, 0x2e, 0x3b, 0x4d, 0x65, 0x2e, 0x3b, 0x44, 0x75, 0x2e, 0x3b, 0x46, 0x72,
-0x2e, 0x3b, 0x53, 0x61, 0x2e, 0x53, 0x3b, 0x4d, 0x3b, 0x44, 0x3b, 0x4d, 0x3b, 0x44, 0x3b, 0x46, 0x3b, 0x53, 0x64, 0x79,
-0x20, 0x53, 0x75, 0x6c, 0x3b, 0x64, 0x79, 0x20, 0x4c, 0x75, 0x6e, 0x3b, 0x64, 0x79, 0x20, 0x4d, 0x65, 0x75, 0x72, 0x74,
-0x68, 0x3b, 0x64, 0x79, 0x20, 0x4d, 0x65, 0x72, 0x68, 0x65, 0x72, 0x3b, 0x64, 0x79, 0x20, 0x59, 0x6f, 0x77, 0x3b, 0x64,
-0x79, 0x20, 0x47, 0x77, 0x65, 0x6e, 0x65, 0x72, 0x3b, 0x64, 0x79, 0x20, 0x53, 0x61, 0x64, 0x6f, 0x72, 0x6e, 0x53, 0x75,
-0x6c, 0x3b, 0x4c, 0x75, 0x6e, 0x3b, 0x4d, 0x74, 0x68, 0x3b, 0x4d, 0x68, 0x72, 0x3b, 0x59, 0x6f, 0x77, 0x3b, 0x47, 0x77,
-0x65, 0x3b, 0x53, 0x61, 0x64, 0x6e, 0x65, 0x64, 0x11b, 0x6c, 0x65, 0x3b, 0x70, 0x6f, 0x6e, 0x64, 0x11b, 0x6c, 0xed, 0x3b,
-0xfa, 0x74, 0x65, 0x72, 0xfd, 0x3b, 0x73, 0x74, 0x159, 0x65, 0x64, 0x61, 0x3b, 0x10d, 0x74, 0x76, 0x72, 0x74, 0x65, 0x6b,
-0x3b, 0x70, 0xe1, 0x74, 0x65, 0x6b, 0x3b, 0x73, 0x6f, 0x62, 0x6f, 0x74, 0x61, 0x6e, 0x65, 0x3b, 0x70, 0x6f, 0x3b, 0xfa,
-0x74, 0x3b, 0x73, 0x74, 0x3b, 0x10d, 0x74, 0x3b, 0x70, 0xe1, 0x3b, 0x73, 0x6f, 0x4e, 0x3b, 0x50, 0x3b, 0xda, 0x3b, 0x53,
-0x3b, 0x10c, 0x3b, 0x50, 0x3b, 0x53, 0x73, 0xf8, 0x6e, 0x64, 0x61, 0x67, 0x3b, 0x6d, 0x61, 0x6e, 0x64, 0x61, 0x67, 0x3b,
-0x74, 0x69, 0x72, 0x73, 0x64, 0x61, 0x67, 0x3b, 0x6f, 0x6e, 0x73, 0x64, 0x61, 0x67, 0x3b, 0x74, 0x6f, 0x72, 0x73, 0x64,
-0x61, 0x67, 0x3b, 0x66, 0x72, 0x65, 0x64, 0x61, 0x67, 0x3b, 0x6c, 0xf8, 0x72, 0x64, 0x61, 0x67, 0x73, 0xf8, 0x6e, 0x2e,
-0x3b, 0x6d, 0x61, 0x6e, 0x2e, 0x3b, 0x74, 0x69, 0x72, 0x73, 0x2e, 0x3b, 0x6f, 0x6e, 0x73, 0x2e, 0x3b, 0x74, 0x6f, 0x72,
-0x73, 0x2e, 0x3b, 0x66, 0x72, 0x65, 0x2e, 0x3b, 0x6c, 0xf8, 0x72, 0x2e, 0x53, 0x3b, 0x4d, 0x3b, 0x54, 0x3b, 0x4f, 0x3b,
-0x54, 0x3b, 0x46, 0x3b, 0x4c, 0x910, 0x924, 0x92c, 0x93e, 0x930, 0x3b, 0x938, 0x94b, 0x92e, 0x92c, 0x93e, 0x930, 0x3b, 0x92e, 0x902,
-0x917, 0x932, 0x92c, 0x93e, 0x930, 0x3b, 0x92c, 0x941, 0x927, 0x92c, 0x93e, 0x930, 0x3b, 0x92c, 0x940, 0x930, 0x92c, 0x93e, 0x930, 0x3b,
-0x936, 0x941, 0x915, 0x94d, 0x930, 0x92c, 0x93e, 0x930, 0x3b, 0x936, 0x928, 0x93f, 0x92c, 0x93e, 0x930, 0x910, 0x924, 0x3b, 0x938, 0x94b,
-0x92e, 0x3b, 0x92e, 0x902, 0x917, 0x932, 0x3b, 0x92c, 0x941, 0x927, 0x3b, 0x92c, 0x940, 0x930, 0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930,
-0x3b, 0x936, 0x928, 0x93f, 0x910, 0x3b, 0x938, 0x94b, 0x3b, 0x92e, 0x2e, 0x3b, 0x92c, 0x941, 0x2e, 0x3b, 0x92c, 0x940, 0x2e, 0x3b,
-0x936, 0x941, 0x2e, 0x3b, 0x936, 0x2e, 0x910, 0x2e, 0x3b, 0x938, 0x94b, 0x2e, 0x3b, 0x92e, 0x2e, 0x3b, 0x92c, 0x941, 0x2e, 0x3b,
-0x92c, 0x940, 0x2e, 0x3b, 0x936, 0x941, 0x2e, 0x3b, 0x936, 0x2e, 0xe9, 0x74, 0x69, 0x3b, 0x6d, 0x254, 0x301, 0x73, 0xfa, 0x3b,
-0x6b, 0x77, 0x61, 0x73, 0xfa, 0x3b, 0x6d, 0x75, 0x6b, 0x254, 0x301, 0x73, 0xfa, 0x3b, 0x14b, 0x67, 0x69, 0x73, 0xfa, 0x3b,
-0x257, 0xf3, 0x6e, 0x25b, 0x73, 0xfa, 0x3b, 0x65, 0x73, 0x61, 0x253, 0x61, 0x73, 0xfa, 0xe9, 0x74, 0x3b, 0x6d, 0x254, 0x301,
-0x73, 0x3b, 0x6b, 0x77, 0x61, 0x3b, 0x6d, 0x75, 0x6b, 0x3b, 0x14b, 0x67, 0x69, 0x3b, 0x257, 0xf3, 0x6e, 0x3b, 0x65, 0x73,
-0x61, 0x65, 0x3b, 0x6d, 0x3b, 0x6b, 0x3b, 0x6d, 0x3b, 0x14b, 0x3b, 0x257, 0x3b, 0x65, 0x7a, 0x6f, 0x6e, 0x64, 0x61, 0x67,
-0x3b, 0x6d, 0x61, 0x61, 0x6e, 0x64, 0x61, 0x67, 0x3b, 0x64, 0x69, 0x6e, 0x73, 0x64, 0x61, 0x67, 0x3b, 0x77, 0x6f, 0x65,
-0x6e, 0x73, 0x64, 0x61, 0x67, 0x3b, 0x64, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x64, 0x61, 0x67, 0x3b, 0x76, 0x72, 0x69, 0x6a,
-0x64, 0x61, 0x67, 0x3b, 0x7a, 0x61, 0x74, 0x65, 0x72, 0x64, 0x61, 0x67, 0x7a, 0x6f, 0x3b, 0x6d, 0x61, 0x3b, 0x64, 0x69,
-0x3b, 0x77, 0x6f, 0x3b, 0x64, 0x6f, 0x3b, 0x76, 0x72, 0x3b, 0x7a, 0x61, 0x5a, 0x3b, 0x4d, 0x3b, 0x44, 0x3b, 0x57, 0x3b,
-0x44, 0x3b, 0x56, 0x3b, 0x5a, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0x3b, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf58,
-0xf72, 0xf42, 0xf0b, 0xf51, 0xf58, 0xf62, 0xf0b, 0x3b, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf63, 0xfb7, 0xf42, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf42,
-0xf5f, 0xf60, 0xf0b, 0xf55, 0xf74, 0xf62, 0xf0b, 0xf56, 0xf74, 0xf0b, 0x3b, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf54, 0xf0b, 0xf66, 0xf44, 0xf66,
-0xf0b, 0x3b, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf66, 0xfa4, 0xf7a, 0xf53, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf49, 0xf72,
-0xf0b, 0xf58, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0x3b, 0xf58, 0xf72, 0xf62, 0xf0b, 0x3b, 0xf63, 0xfb7, 0xf42, 0xf0b, 0x3b, 0xf55, 0xf74, 0xf62,
-0xf0b, 0x3b, 0xf66, 0xf44, 0xf66, 0xf0b, 0x3b, 0xf66, 0xfa4, 0xf7a, 0xf53, 0xf0b, 0x3b, 0xf49, 0xf72, 0xf0b, 0xf5f, 0xfb3, 0x3b, 0xf58,
-0xf72, 0xf62, 0x3b, 0xf63, 0xfb7, 0xf42, 0x3b, 0xf55, 0xf74, 0xf62, 0x3b, 0xf66, 0xf44, 0xfb6, 0x3b, 0xf66, 0xfa4, 0xf7a, 0xf53, 0x3b,
-0xf49, 0xf72, 0x4b, 0x69, 0x75, 0x6d, 0x69, 0x61, 0x3b, 0x4e, 0x6a, 0x75, 0x6d, 0x61, 0x74, 0x61, 0x74, 0x75, 0x3b, 0x4e,
-0x6a, 0x75, 0x6d, 0x61, 0x69, 0x6e, 0x65, 0x3b, 0x4e, 0x6a, 0x75, 0x6d, 0x61, 0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x41, 0x72,
-0x61, 0x6d, 0x69, 0x74, 0x68, 0x69, 0x3b, 0x4e, 0x6a, 0x75, 0x6d, 0x61, 0x61, 0x3b, 0x4e, 0x4a, 0x75, 0x6d, 0x61, 0x6d,
-0x6f, 0x74, 0x68, 0x69, 0x69, 0x4b, 0x6d, 0x61, 0x3b, 0x54, 0x61, 0x74, 0x3b, 0x49, 0x6e, 0x65, 0x3b, 0x54, 0x61, 0x6e,
-0x3b, 0x41, 0x72, 0x6d, 0x3b, 0x4d, 0x61, 0x61, 0x3b, 0x4e, 0x4d, 0x4d, 0x4b, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b,
-0x41, 0x3b, 0x4d, 0x3b, 0x4e, 0x53, 0x75, 0x2e, 0x3b, 0x4d, 0x2e, 0x3b, 0x54, 0x75, 0x2e, 0x3b, 0x57, 0x2e, 0x3b, 0x54,
-0x68, 0x2e, 0x3b, 0x46, 0x2e, 0x3b, 0x53, 0x61, 0x2e, 0x64, 0x69, 0x6d, 0x61, 0x6e, 0x109, 0x6f, 0x3b, 0x6c, 0x75, 0x6e,
-0x64, 0x6f, 0x3b, 0x6d, 0x61, 0x72, 0x64, 0x6f, 0x3b, 0x6d, 0x65, 0x72, 0x6b, 0x72, 0x65, 0x64, 0x6f, 0x3b, 0x135, 0x61,
-0x16d, 0x64, 0x6f, 0x3b, 0x76, 0x65, 0x6e, 0x64, 0x72, 0x65, 0x64, 0x6f, 0x3b, 0x73, 0x61, 0x62, 0x61, 0x74, 0x6f, 0x64,
-0x69, 0x3b, 0x6c, 0x75, 0x3b, 0x6d, 0x61, 0x3b, 0x6d, 0x65, 0x3b, 0x135, 0x61, 0x3b, 0x76, 0x65, 0x3b, 0x73, 0x61, 0x44,
-0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x134, 0x3b, 0x56, 0x3b, 0x53, 0x70, 0xfc, 0x68, 0x61, 0x70, 0xe4, 0x65, 0x76,
-0x3b, 0x65, 0x73, 0x6d, 0x61, 0x73, 0x70, 0xe4, 0x65, 0x76, 0x3b, 0x74, 0x65, 0x69, 0x73, 0x69, 0x70, 0xe4, 0x65, 0x76,
-0x3b, 0x6b, 0x6f, 0x6c, 0x6d, 0x61, 0x70, 0xe4, 0x65, 0x76, 0x3b, 0x6e, 0x65, 0x6c, 0x6a, 0x61, 0x70, 0xe4, 0x65, 0x76,
-0x3b, 0x72, 0x65, 0x65, 0x64, 0x65, 0x3b, 0x6c, 0x61, 0x75, 0x70, 0xe4, 0x65, 0x76, 0x50, 0x3b, 0x45, 0x3b, 0x54, 0x3b,
-0x4b, 0x3b, 0x4e, 0x3b, 0x52, 0x3b, 0x4c, 0x6b, 0x254, 0x73, 0x69, 0x256, 0x61, 0x3b, 0x64, 0x7a, 0x6f, 0x256, 0x61, 0x3b,
-0x62, 0x6c, 0x61, 0x256, 0x61, 0x3b, 0x6b, 0x75, 0x256, 0x61, 0x3b, 0x79, 0x61, 0x77, 0x6f, 0x256, 0x61, 0x3b, 0x66, 0x69,
-0x256, 0x61, 0x3b, 0x6d, 0x65, 0x6d, 0x6c, 0x65, 0x256, 0x61, 0x6b, 0x254, 0x73, 0x3b, 0x64, 0x7a, 0x6f, 0x3b, 0x62, 0x6c,
-0x61, 0x3b, 0x6b, 0x75, 0x256, 0x3b, 0x79, 0x61, 0x77, 0x3b, 0x66, 0x69, 0x256, 0x3b, 0x6d, 0x65, 0x6d, 0x6b, 0x3b, 0x64,
-0x3b, 0x62, 0x3b, 0x6b, 0x3b, 0x79, 0x3b, 0x66, 0x3b, 0x6d, 0x73, 0x254, 0x301, 0x6e, 0x64, 0x254, 0x3b, 0x6d, 0x254, 0x301,
-0x6e, 0x64, 0x69, 0x3b, 0x73, 0x254, 0x301, 0x6e, 0x64, 0x254, 0x20, 0x6d, 0x259, 0x6c, 0xfa, 0x20, 0x6d, 0x259, 0x301, 0x62,
-0x25b, 0x30c, 0x3b, 0x73, 0x254, 0x301, 0x6e, 0x64, 0x254, 0x20, 0x6d, 0x259, 0x6c, 0xfa, 0x20, 0x6d, 0x259, 0x301, 0x6c, 0x25b,
-0x301, 0x3b, 0x73, 0x254, 0x301, 0x6e, 0x64, 0x254, 0x20, 0x6d, 0x259, 0x6c, 0xfa, 0x20, 0x6d, 0x259, 0x301, 0x6e, 0x79, 0x69,
-0x3b, 0x66, 0xfa, 0x6c, 0x61, 0x64, 0xe9, 0x3b, 0x73, 0xe9, 0x72, 0x61, 0x64, 0xe9, 0x73, 0x254, 0x301, 0x6e, 0x3b, 0x6d,
-0x254, 0x301, 0x6e, 0x3b, 0x73, 0x6d, 0x62, 0x3b, 0x73, 0x6d, 0x6c, 0x3b, 0x73, 0x6d, 0x6e, 0x3b, 0x66, 0xfa, 0x6c, 0x3b,
-0x73, 0xe9, 0x72, 0x73, 0x3b, 0x6d, 0x3b, 0x73, 0x3b, 0x73, 0x3b, 0x73, 0x3b, 0x66, 0x3b, 0x73, 0x73, 0x75, 0x6e, 0x6e,
-0x75, 0x64, 0x61, 0x67, 0x75, 0x72, 0x3b, 0x6d, 0xe1, 0x6e, 0x61, 0x64, 0x61, 0x67, 0x75, 0x72, 0x3b, 0x74, 0xfd, 0x73,
-0x64, 0x61, 0x67, 0x75, 0x72, 0x3b, 0x6d, 0x69, 0x6b, 0x75, 0x64, 0x61, 0x67, 0x75, 0x72, 0x3b, 0x68, 0xf3, 0x73, 0x64,
-0x61, 0x67, 0x75, 0x72, 0x3b, 0x66, 0x72, 0xed, 0x67, 0x67, 0x6a, 0x61, 0x64, 0x61, 0x67, 0x75, 0x72, 0x3b, 0x6c, 0x65,
-0x79, 0x67, 0x61, 0x72, 0x64, 0x61, 0x67, 0x75, 0x72, 0x73, 0x75, 0x6e, 0x3b, 0x6d, 0xe1, 0x6e, 0x3b, 0x74, 0xfd, 0x73,
-0x3b, 0x6d, 0x69, 0x6b, 0x3b, 0x68, 0xf3, 0x73, 0x3b, 0x66, 0x72, 0xed, 0x3b, 0x6c, 0x65, 0x79, 0x73, 0x75, 0x6e, 0x2e,
-0x3b, 0x6d, 0xe1, 0x6e, 0x2e, 0x3b, 0x74, 0xfd, 0x73, 0x2e, 0x3b, 0x6d, 0x69, 0x6b, 0x2e, 0x3b, 0x68, 0xf3, 0x73, 0x2e,
-0x3b, 0x66, 0x72, 0xed, 0x2e, 0x3b, 0x6c, 0x65, 0x79, 0x2e, 0x53, 0x3b, 0x4d, 0x3b, 0x54, 0x3b, 0x4d, 0x3b, 0x48, 0x3b,
-0x46, 0x3b, 0x4c, 0x4c, 0x69, 0x6e, 0x67, 0x67, 0x6f, 0x3b, 0x4c, 0x75, 0x6e, 0x65, 0x73, 0x3b, 0x4d, 0x61, 0x72, 0x74,
-0x65, 0x73, 0x3b, 0x4d, 0x69, 0x79, 0x65, 0x72, 0x6b, 0x75, 0x6c, 0x65, 0x73, 0x3b, 0x48, 0x75, 0x77, 0x65, 0x62, 0x65,
-0x73, 0x3b, 0x42, 0x69, 0x79, 0x65, 0x72, 0x6e, 0x65, 0x73, 0x3b, 0x53, 0x61, 0x62, 0x61, 0x64, 0x6f, 0x4c, 0x69, 0x6e,
-0x3b, 0x4c, 0x75, 0x6e, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x4d, 0x69, 0x79, 0x3b, 0x48, 0x75, 0x77, 0x3b, 0x42, 0x69, 0x79,
-0x3b, 0x53, 0x61, 0x62, 0x73, 0x75, 0x6e, 0x6e, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x3b, 0x6d, 0x61, 0x61, 0x6e, 0x61, 0x6e,
-0x74, 0x61, 0x69, 0x3b, 0x74, 0x69, 0x69, 0x73, 0x74, 0x61, 0x69, 0x3b, 0x6b, 0x65, 0x73, 0x6b, 0x69, 0x76, 0x69, 0x69,
-0x6b, 0x6b, 0x6f, 0x3b, 0x74, 0x6f, 0x72, 0x73, 0x74, 0x61, 0x69, 0x3b, 0x70, 0x65, 0x72, 0x6a, 0x61, 0x6e, 0x74, 0x61,
-0x69, 0x3b, 0x6c, 0x61, 0x75, 0x61, 0x6e, 0x74, 0x61, 0x69, 0x73, 0x75, 0x6e, 0x6e, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e,
-0x61, 0x3b, 0x6d, 0x61, 0x61, 0x6e, 0x61, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x61, 0x3b, 0x74, 0x69, 0x69, 0x73, 0x74, 0x61,
-0x69, 0x6e, 0x61, 0x3b, 0x6b, 0x65, 0x73, 0x6b, 0x69, 0x76, 0x69, 0x69, 0x6b, 0x6b, 0x6f, 0x6e, 0x61, 0x3b, 0x74, 0x6f,
-0x72, 0x73, 0x74, 0x61, 0x69, 0x6e, 0x61, 0x3b, 0x70, 0x65, 0x72, 0x6a, 0x61, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x61, 0x3b,
-0x6c, 0x61, 0x75, 0x61, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x61, 0x73, 0x75, 0x3b, 0x6d, 0x61, 0x3b, 0x74, 0x69, 0x3b, 0x6b,
-0x65, 0x3b, 0x74, 0x6f, 0x3b, 0x70, 0x65, 0x3b, 0x6c, 0x61, 0x53, 0x3b, 0x4d, 0x3b, 0x54, 0x3b, 0x4b, 0x3b, 0x54, 0x3b,
-0x50, 0x3b, 0x4c, 0x64, 0x69, 0x6d, 0x61, 0x6e, 0x63, 0x68, 0x65, 0x3b, 0x6c, 0x75, 0x6e, 0x64, 0x69, 0x3b, 0x6d, 0x61,
-0x72, 0x64, 0x69, 0x3b, 0x6d, 0x65, 0x72, 0x63, 0x72, 0x65, 0x64, 0x69, 0x3b, 0x6a, 0x65, 0x75, 0x64, 0x69, 0x3b, 0x76,
-0x65, 0x6e, 0x64, 0x72, 0x65, 0x64, 0x69, 0x3b, 0x73, 0x61, 0x6d, 0x65, 0x64, 0x69, 0x64, 0x69, 0x6d, 0x2e, 0x3b, 0x6c,
-0x75, 0x6e, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x6d, 0x65, 0x72, 0x2e, 0x3b, 0x6a, 0x65, 0x75, 0x2e, 0x3b, 0x76,
-0x65, 0x6e, 0x2e, 0x3b, 0x73, 0x61, 0x6d, 0x2e, 0x44, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x56, 0x3b,
-0x53, 0x64, 0x6f, 0x6d, 0x65, 0x6e, 0x69, 0x65, 0x3b, 0x6c, 0x75, 0x6e, 0x69, 0x73, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x61,
-0x72, 0x73, 0x3b, 0x6d, 0x69, 0x65, 0x72, 0x63, 0x75, 0x73, 0x3b, 0x6a, 0x6f, 0x69, 0x62, 0x65, 0x3b, 0x76, 0x69, 0x6e,
-0x61, 0x72, 0x73, 0x3b, 0x73, 0x61, 0x62, 0x69, 0x64, 0x65, 0x64, 0x6f, 0x6d, 0x3b, 0x6c, 0x75, 0x6e, 0x3b, 0x6d, 0x61,
-0x72, 0x3b, 0x6d, 0x69, 0x65, 0x3b, 0x6a, 0x6f, 0x69, 0x3b, 0x76, 0x69, 0x6e, 0x3b, 0x73, 0x61, 0x62, 0x64, 0x65, 0x77,
-0x6f, 0x3b, 0x61, 0x61, 0x253, 0x6e, 0x64, 0x65, 0x3b, 0x6d, 0x61, 0x77, 0x62, 0x61, 0x61, 0x72, 0x65, 0x3b, 0x6e, 0x6a,
-0x65, 0x73, 0x6c, 0x61, 0x61, 0x72, 0x65, 0x3b, 0x6e, 0x61, 0x61, 0x73, 0x61, 0x61, 0x6e, 0x64, 0x65, 0x3b, 0x6d, 0x61,
-0x77, 0x6e, 0x64, 0x65, 0x3b, 0x68, 0x6f, 0x6f, 0x72, 0x65, 0x2d, 0x62, 0x69, 0x69, 0x72, 0x64, 0x65, 0x77, 0x3b, 0x61,
-0x61, 0x253, 0x3b, 0x6d, 0x61, 0x77, 0x3b, 0x6e, 0x6a, 0x65, 0x3b, 0x6e, 0x61, 0x61, 0x3b, 0x6d, 0x77, 0x64, 0x3b, 0x68,
-0x62, 0x69, 0x64, 0x3b, 0x61, 0x3b, 0x6d, 0x3b, 0x6e, 0x3b, 0x6e, 0x3b, 0x6d, 0x3b, 0x68, 0xd83a, 0xdd08, 0xd83a, 0xdd2b, 0xd83a,
-0xdd2c, 0xd83a, 0xdd26, 0xd83a, 0xdd2d, 0xd83a, 0xdd2a, 0xd83a, 0xdd46, 0xd83a, 0xdd2b, 0x3b, 0xd83a, 0xdd00, 0xd83a, 0xdd44, 0xd83a, 0xdd29, 0xd83a, 0xdd35,
-0xd83a, 0xdd32, 0xd83a, 0xdd4b, 0xd83a, 0xdd23, 0xd83a, 0xdd2b, 0x3b, 0xd83a, 0xdd03, 0xd83a, 0xdd22, 0xd83a, 0xdd31, 0xd83a, 0xdd26, 0xd83a, 0xdd22, 0xd83a,
-0xdd44, 0xd83a, 0xdd2a, 0xd83a, 0xdd2b, 0x3b, 0xd83a, 0xdd10, 0xd83a, 0xdd36, 0xd83a, 0xdd2b, 0xd83a, 0xdd27, 0xd83a, 0xdd24, 0xd83a, 0xdd22, 0xd83a, 0xdd44,
-0xd83a, 0xdd2a, 0xd83a, 0xdd2b, 0x3b, 0xd83a, 0xdd10, 0xd83a, 0xdd22, 0xd83a, 0xdd44, 0xd83a, 0xdd27, 0xd83a, 0xdd22, 0xd83a, 0xdd44, 0xd83a, 0xdd32, 0xd83a,
-0xdd23, 0xd83a, 0xdd2b, 0x3b, 0xd83a, 0xdd03, 0xd83a, 0xdd22, 0xd83a, 0xdd31, 0xd83a, 0xdd32, 0xd83a, 0xdd23, 0xd83a, 0xdd2b, 0x3b, 0xd83a, 0xdd16, 0xd83a,
-0xdd2e, 0xd83a, 0xdd2a, 0xd83a, 0xdd26, 0xd83a, 0xdd2d, 0xd83a, 0xdd2a, 0xd83a, 0xdd46, 0xd83a, 0xdd2b, 0xd83a, 0xdd08, 0xd83a, 0xdd2b, 0xd83a, 0xdd2c, 0x3b,
-0xd83a, 0xdd00, 0xd83a, 0xdd44, 0xd83a, 0xdd29, 0xd83a, 0xdd35, 0x3b, 0xd83a, 0xdd03, 0xd83a, 0xdd22, 0xd83a, 0xdd26, 0x3b, 0xd83a, 0xdd14, 0xd83a, 0xdd2b,
-0xd83a, 0xdd27, 0x3b, 0xd83a, 0xdd10, 0xd83a, 0xdd22, 0xd83a, 0xdd44, 0xd83a, 0xdd27, 0x3b, 0xd83a, 0xdd03, 0xd83a, 0xdd22, 0xd83a, 0xdd23, 0x3b, 0xd83a,
-0xdd16, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0xd83a, 0xdd08, 0x3b, 0xd83a, 0xdd00, 0xd83a, 0xdd44, 0x3b, 0xd83a, 0xdd03, 0x3b, 0xd83a, 0xdd14, 0x3b, 0xd83a,
-0xdd10, 0x3b, 0xd83a, 0xdd03, 0x3b, 0xd83a, 0xdd16, 0x44, 0x69, 0x44, 0xf2, 0x6d, 0x68, 0x6e, 0x61, 0x69, 0x63, 0x68, 0x3b, 0x44,
-0x69, 0x4c, 0x75, 0x61, 0x69, 0x6e, 0x3b, 0x44, 0x69, 0x4d, 0xe0, 0x69, 0x72, 0x74, 0x3b, 0x44, 0x69, 0x43, 0x69, 0x61,
-0x64, 0x61, 0x69, 0x6e, 0x3b, 0x44, 0x69, 0x61, 0x72, 0x44, 0x61, 0x6f, 0x69, 0x6e, 0x3b, 0x44, 0x69, 0x68, 0x41, 0x6f,
-0x69, 0x6e, 0x65, 0x3b, 0x44, 0x69, 0x53, 0x61, 0x74, 0x68, 0x61, 0x69, 0x72, 0x6e, 0x65, 0x44, 0x69, 0x44, 0x3b, 0x44,
-0x69, 0x4c, 0x3b, 0x44, 0x69, 0x4d, 0x3b, 0x44, 0x69, 0x43, 0x3b, 0x44, 0x69, 0x61, 0x3b, 0x44, 0x69, 0x68, 0x3b, 0x44,
-0x69, 0x53, 0x44, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x43, 0x3b, 0x41, 0x3b, 0x48, 0x3b, 0x53, 0x44, 0x6f, 0x6d, 0x69, 0x6e,
-0x67, 0x6f, 0x3b, 0x4c, 0x75, 0x6e, 0x73, 0x3b, 0x4d, 0x61, 0x72, 0x74, 0x65, 0x73, 0x3b, 0x4d, 0xe9, 0x72, 0x63, 0x6f,
-0x72, 0x65, 0x73, 0x3b, 0x58, 0x6f, 0x76, 0x65, 0x73, 0x3b, 0x56, 0x65, 0x6e, 0x72, 0x65, 0x73, 0x3b, 0x53, 0xe1, 0x62,
-0x61, 0x64, 0x6f, 0x64, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x6f, 0x3b, 0x6c, 0x75, 0x6e, 0x73, 0x3b, 0x6d, 0x61, 0x72, 0x74,
-0x65, 0x73, 0x3b, 0x6d, 0xe9, 0x72, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x3b, 0x78, 0x6f, 0x76, 0x65, 0x73, 0x3b, 0x76, 0x65,
-0x6e, 0x72, 0x65, 0x73, 0x3b, 0x73, 0xe1, 0x62, 0x61, 0x64, 0x6f, 0x44, 0x6f, 0x6d, 0x2e, 0x3b, 0x4c, 0x75, 0x6e, 0x73,
-0x3b, 0x4d, 0x61, 0x72, 0x2e, 0x3b, 0x4d, 0xe9, 0x72, 0x2e, 0x3b, 0x58, 0x6f, 0x76, 0x2e, 0x3b, 0x56, 0x65, 0x6e, 0x2e,
-0x3b, 0x53, 0xe1, 0x62, 0x2e, 0x64, 0x6f, 0x6d, 0x2e, 0x3b, 0x6c, 0x75, 0x6e, 0x73, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b,
-0x6d, 0xe9, 0x72, 0x2e, 0x3b, 0x78, 0x6f, 0x76, 0x2e, 0x3b, 0x76, 0x65, 0x6e, 0x2e, 0x3b, 0x73, 0xe1, 0x62, 0x2e, 0x64,
-0x2e, 0x3b, 0x6c, 0x2e, 0x3b, 0x6d, 0x2e, 0x3b, 0x6d, 0x2e, 0x3b, 0x78, 0x2e, 0x3b, 0x76, 0x2e, 0x3b, 0x73, 0x2e, 0x53,
-0x61, 0x62, 0x62, 0x69, 0x69, 0x74, 0x69, 0x3b, 0x42, 0x61, 0x6c, 0x61, 0x7a, 0x61, 0x3b, 0x4c, 0x77, 0x61, 0x6b, 0x75,
-0x62, 0x69, 0x72, 0x69, 0x3b, 0x4c, 0x77, 0x61, 0x6b, 0x75, 0x73, 0x61, 0x74, 0x75, 0x3b, 0x4c, 0x77, 0x61, 0x6b, 0x75,
-0x6e, 0x61, 0x3b, 0x4c, 0x77, 0x61, 0x6b, 0x75, 0x74, 0x61, 0x61, 0x6e, 0x6f, 0x3b, 0x4c, 0x77, 0x61, 0x6d, 0x75, 0x6b,
-0x61, 0x61, 0x67, 0x61, 0x53, 0x61, 0x62, 0x3b, 0x42, 0x61, 0x6c, 0x3b, 0x4c, 0x77, 0x32, 0x3b, 0x4c, 0x77, 0x33, 0x3b,
-0x4c, 0x77, 0x34, 0x3b, 0x4c, 0x77, 0x35, 0x3b, 0x4c, 0x77, 0x36, 0x53, 0x3b, 0x42, 0x3b, 0x4c, 0x3b, 0x4c, 0x3b, 0x4c,
-0x3b, 0x4c, 0x3b, 0x4c, 0x10d9, 0x10d5, 0x10d8, 0x10e0, 0x10d0, 0x3b, 0x10dd, 0x10e0, 0x10e8, 0x10d0, 0x10d1, 0x10d0, 0x10d7, 0x10d8, 0x3b, 0x10e1,
-0x10d0, 0x10db, 0x10e8, 0x10d0, 0x10d1, 0x10d0, 0x10d7, 0x10d8, 0x3b, 0x10dd, 0x10d7, 0x10ee, 0x10e8, 0x10d0, 0x10d1, 0x10d0, 0x10d7, 0x10d8, 0x3b, 0x10ee,
-0x10e3, 0x10d7, 0x10e8, 0x10d0, 0x10d1, 0x10d0, 0x10d7, 0x10d8, 0x3b, 0x10de, 0x10d0, 0x10e0, 0x10d0, 0x10e1, 0x10d9, 0x10d4, 0x10d5, 0x10d8, 0x3b, 0x10e8,
-0x10d0, 0x10d1, 0x10d0, 0x10d7, 0x10d8, 0x10d9, 0x10d5, 0x10d8, 0x3b, 0x10dd, 0x10e0, 0x10e8, 0x3b, 0x10e1, 0x10d0, 0x10db, 0x3b, 0x10dd, 0x10d7, 0x10ee,
-0x3b, 0x10ee, 0x10e3, 0x10d7, 0x3b, 0x10de, 0x10d0, 0x10e0, 0x3b, 0x10e8, 0x10d0, 0x10d1, 0x10d9, 0x3b, 0x10dd, 0x3b, 0x10e1, 0x3b, 0x10dd, 0x3b,
-0x10ee, 0x3b, 0x10de, 0x3b, 0x10e8, 0x53, 0x6f, 0x6e, 0x6e, 0x74, 0x61, 0x67, 0x3b, 0x4d, 0x6f, 0x6e, 0x74, 0x61, 0x67, 0x3b,
-0x44, 0x69, 0x65, 0x6e, 0x73, 0x74, 0x61, 0x67, 0x3b, 0x4d, 0x69, 0x74, 0x74, 0x77, 0x6f, 0x63, 0x68, 0x3b, 0x44, 0x6f,
-0x6e, 0x6e, 0x65, 0x72, 0x73, 0x74, 0x61, 0x67, 0x3b, 0x46, 0x72, 0x65, 0x69, 0x74, 0x61, 0x67, 0x3b, 0x53, 0x61, 0x6d,
-0x73, 0x74, 0x61, 0x67, 0x53, 0x6f, 0x3b, 0x4d, 0x6f, 0x3b, 0x44, 0x69, 0x3b, 0x4d, 0x69, 0x3b, 0x44, 0x6f, 0x3b, 0x46,
-0x72, 0x3b, 0x53, 0x61, 0x53, 0x6f, 0x2e, 0x3b, 0x4d, 0x6f, 0x2e, 0x3b, 0x44, 0x69, 0x2e, 0x3b, 0x4d, 0x69, 0x2e, 0x3b,
-0x44, 0x6f, 0x2e, 0x3b, 0x46, 0x72, 0x2e, 0x3b, 0x53, 0x61, 0x2e, 0x39a, 0x3c5, 0x3c1, 0x3b9, 0x3b1, 0x3ba, 0x3ae, 0x3b, 0x394,
-0x3b5, 0x3c5, 0x3c4, 0x3ad, 0x3c1, 0x3b1, 0x3b, 0x3a4, 0x3c1, 0x3af, 0x3c4, 0x3b7, 0x3b, 0x3a4, 0x3b5, 0x3c4, 0x3ac, 0x3c1, 0x3c4, 0x3b7,
-0x3b, 0x3a0, 0x3ad, 0x3bc, 0x3c0, 0x3c4, 0x3b7, 0x3b, 0x3a0, 0x3b1, 0x3c1, 0x3b1, 0x3c3, 0x3ba, 0x3b5, 0x3c5, 0x3ae, 0x3b, 0x3a3, 0x3ac,
-0x3b2, 0x3b2, 0x3b1, 0x3c4, 0x3bf, 0x39a, 0x3c5, 0x3c1, 0x3b, 0x394, 0x3b5, 0x3c5, 0x3b, 0x3a4, 0x3c1, 0x3af, 0x3b, 0x3a4, 0x3b5, 0x3c4,
-0x3b, 0x3a0, 0x3ad, 0x3bc, 0x3b, 0x3a0, 0x3b1, 0x3c1, 0x3b, 0x3a3, 0x3ac, 0x3b2, 0x39a, 0x3b, 0x394, 0x3b, 0x3a4, 0x3b, 0x3a4, 0x3b,
-0x3a0, 0x3b, 0x3a0, 0x3b, 0x3a3, 0xab0, 0xab5, 0xabf, 0xab5, 0xabe, 0xab0, 0x3b, 0xab8, 0xacb, 0xaae, 0xab5, 0xabe, 0xab0, 0x3b, 0xaae,
-0xa82, 0xa97, 0xab3, 0xab5, 0xabe, 0xab0, 0x3b, 0xaac, 0xac1, 0xaa7, 0xab5, 0xabe, 0xab0, 0x3b, 0xa97, 0xac1, 0xab0, 0xac1, 0xab5, 0xabe,
-0xab0, 0x3b, 0xab6, 0xac1, 0xa95, 0xacd, 0xab0, 0xab5, 0xabe, 0xab0, 0x3b, 0xab6, 0xaa8, 0xabf, 0xab5, 0xabe, 0xab0, 0xab0, 0xab5, 0xabf,
-0x3b, 0xab8, 0xacb, 0xaae, 0x3b, 0xaae, 0xa82, 0xa97, 0xab3, 0x3b, 0xaac, 0xac1, 0xaa7, 0x3b, 0xa97, 0xac1, 0xab0, 0xac1, 0x3b, 0xab6,
-0xac1, 0xa95, 0xacd, 0xab0, 0x3b, 0xab6, 0xaa8, 0xabf, 0xab0, 0x3b, 0xab8, 0xacb, 0x3b, 0xaae, 0xa82, 0x3b, 0xaac, 0xac1, 0x3b, 0xa97,
-0xac1, 0x3b, 0xab6, 0xac1, 0x3b, 0xab6, 0x43, 0x68, 0x75, 0x6d, 0x61, 0x70, 0x69, 0x72, 0x69, 0x3b, 0x43, 0x68, 0x75, 0x6d,
-0x61, 0x74, 0x61, 0x74, 0x6f, 0x3b, 0x43, 0x68, 0x75, 0x6d, 0x61, 0x69, 0x6e, 0x65, 0x3b, 0x43, 0x68, 0x75, 0x6d, 0x61,
-0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x41, 0x72, 0x61, 0x6d, 0x69, 0x73, 0x69, 0x3b, 0x49, 0x63, 0x68, 0x75, 0x6d, 0x61, 0x3b,
-0x45, 0x73, 0x61, 0x62, 0x61, 0x74, 0x6f, 0x43, 0x70, 0x72, 0x3b, 0x43, 0x74, 0x74, 0x3b, 0x43, 0x6d, 0x6e, 0x3b, 0x43,
-0x6d, 0x74, 0x3b, 0x41, 0x72, 0x73, 0x3b, 0x49, 0x63, 0x6d, 0x3b, 0x45, 0x73, 0x74, 0x43, 0x3b, 0x43, 0x3b, 0x43, 0x3b,
-0x43, 0x3b, 0x41, 0x3b, 0x49, 0x3b, 0x45, 0x4c, 0x61, 0x68, 0x61, 0x64, 0x69, 0x3b, 0x4c, 0x69, 0x74, 0x69, 0x6e, 0x69,
-0x6e, 0x3b, 0x54, 0x61, 0x6c, 0x61, 0x74, 0x61, 0x3b, 0x4c, 0x61, 0x72, 0x61, 0x62, 0x61, 0x3b, 0x41, 0x6c, 0x68, 0x61,
-0x6d, 0x69, 0x73, 0x3b, 0x4a, 0x75, 0x6d, 0x6d, 0x61, 0x2bc, 0x61, 0x3b, 0x41, 0x73, 0x61, 0x62, 0x61, 0x72, 0x4c, 0x61,
-0x68, 0x3b, 0x4c, 0x69, 0x74, 0x3b, 0x54, 0x61, 0x6c, 0x3b, 0x4c, 0x61, 0x72, 0x3b, 0x41, 0x6c, 0x68, 0x3b, 0x4a, 0x75,
-0x6d, 0x3b, 0x41, 0x73, 0x61, 0x4c, 0x3b, 0x4c, 0x3b, 0x54, 0x3b, 0x4c, 0x3b, 0x41, 0x3b, 0x4a, 0x3b, 0x41, 0x4c, 0x101,
-0x70, 0x75, 0x6c, 0x65, 0x3b, 0x50, 0x6f, 0x2bb, 0x61, 0x6b, 0x61, 0x68, 0x69, 0x3b, 0x50, 0x6f, 0x2bb, 0x61, 0x6c, 0x75,
-0x61, 0x3b, 0x50, 0x6f, 0x2bb, 0x61, 0x6b, 0x6f, 0x6c, 0x75, 0x3b, 0x50, 0x6f, 0x2bb, 0x61, 0x68, 0x101, 0x3b, 0x50, 0x6f,
-0x2bb, 0x61, 0x6c, 0x69, 0x6d, 0x61, 0x3b, 0x50, 0x6f, 0x2bb, 0x61, 0x6f, 0x6e, 0x6f, 0x4c, 0x50, 0x3b, 0x50, 0x31, 0x3b,
-0x50, 0x32, 0x3b, 0x50, 0x33, 0x3b, 0x50, 0x34, 0x3b, 0x50, 0x35, 0x3b, 0x50, 0x36, 0x5d9, 0x5d5, 0x5dd, 0x20, 0x5e8, 0x5d0,
-0x5e9, 0x5d5, 0x5df, 0x3b, 0x5d9, 0x5d5, 0x5dd, 0x20, 0x5e9, 0x5e0, 0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5dd, 0x20, 0x5e9, 0x5dc, 0x5d9, 0x5e9,
-0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5dd, 0x20, 0x5e8, 0x5d1, 0x5d9, 0x5e2, 0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5dd, 0x20, 0x5d7, 0x5de, 0x5d9, 0x5e9,
-0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5dd, 0x20, 0x5e9, 0x5d9, 0x5e9, 0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5dd, 0x20, 0x5e9, 0x5d1, 0x5ea, 0x5d9, 0x5d5,
-0x5dd, 0x20, 0x5d0, 0x5f3, 0x3b, 0x5d9, 0x5d5, 0x5dd, 0x20, 0x5d1, 0x5f3, 0x3b, 0x5d9, 0x5d5, 0x5dd, 0x20, 0x5d2, 0x5f3, 0x3b, 0x5d9,
-0x5d5, 0x5dd, 0x20, 0x5d3, 0x5f3, 0x3b, 0x5d9, 0x5d5, 0x5dd, 0x20, 0x5d4, 0x5f3, 0x3b, 0x5d9, 0x5d5, 0x5dd, 0x20, 0x5d5, 0x5f3, 0x3b,
-0x5e9, 0x5d1, 0x5ea, 0x5d0, 0x5f3, 0x3b, 0x5d1, 0x5f3, 0x3b, 0x5d2, 0x5f3, 0x3b, 0x5d3, 0x5f3, 0x3b, 0x5d4, 0x5f3, 0x3b, 0x5d5, 0x5f3,
-0x3b, 0x5e9, 0x5f3, 0x930, 0x935, 0x93f, 0x935, 0x93e, 0x930, 0x3b, 0x938, 0x94b, 0x92e, 0x935, 0x93e, 0x930, 0x3b, 0x92e, 0x902, 0x917,
-0x932, 0x935, 0x93e, 0x930, 0x3b, 0x92c, 0x941, 0x927, 0x935, 0x93e, 0x930, 0x3b, 0x917, 0x941, 0x930, 0x941, 0x935, 0x93e, 0x930, 0x3b,
-0x936, 0x941, 0x915, 0x94d, 0x930, 0x935, 0x93e, 0x930, 0x3b, 0x936, 0x928, 0x93f, 0x935, 0x93e, 0x930, 0x930, 0x935, 0x93f, 0x3b, 0x938,
-0x94b, 0x92e, 0x3b, 0x92e, 0x902, 0x917, 0x932, 0x3b, 0x92c, 0x941, 0x927, 0x3b, 0x917, 0x941, 0x930, 0x941, 0x3b, 0x936, 0x941, 0x915,
-0x94d, 0x930, 0x3b, 0x936, 0x928, 0x93f, 0x930, 0x3b, 0x938, 0x94b, 0x3b, 0x92e, 0x902, 0x3b, 0x92c, 0x941, 0x3b, 0x917, 0x941, 0x3b,
-0x936, 0x941, 0x3b, 0x936, 0x52, 0x61, 0x76, 0x69, 0x77, 0x61, 0x61, 0x72, 0x3b, 0x53, 0x6f, 0x6d, 0x77, 0x61, 0x61, 0x72,
-0x3b, 0x4d, 0x61, 0x6e, 0x67, 0x61, 0x6c, 0x77, 0x61, 0x61, 0x72, 0x3b, 0x42, 0x75, 0x64, 0x68, 0x77, 0x61, 0x61, 0x72,
-0x3b, 0x47, 0x75, 0x72, 0x75, 0x77, 0x61, 0x61, 0x72, 0x3b, 0x53, 0x68, 0x75, 0x6b, 0x72, 0x61, 0x77, 0x61, 0x61, 0x72,
-0x3b, 0x53, 0x68, 0x61, 0x6e, 0x69, 0x77, 0x61, 0x61, 0x72, 0x52, 0x61, 0x76, 0x69, 0x3b, 0x53, 0x6f, 0x6d, 0x3b, 0x4d,
-0x61, 0x6e, 0x67, 0x61, 0x6c, 0x3b, 0x42, 0x75, 0x64, 0x68, 0x3b, 0x47, 0x75, 0x72, 0x75, 0x3b, 0x53, 0x68, 0x75, 0x6b,
-0x72, 0x61, 0x3b, 0x53, 0x68, 0x61, 0x6e, 0x69, 0x52, 0x61, 0x3b, 0x53, 0x6f, 0x3b, 0x4d, 0x61, 0x3b, 0x42, 0x75, 0x3b,
-0x47, 0x75, 0x3b, 0x53, 0x68, 0x3b, 0x53, 0x68, 0x61, 0x76, 0x61, 0x73, 0xe1, 0x72, 0x6e, 0x61, 0x70, 0x3b, 0x68, 0xe9,
-0x74, 0x66, 0x151, 0x3b, 0x6b, 0x65, 0x64, 0x64, 0x3b, 0x73, 0x7a, 0x65, 0x72, 0x64, 0x61, 0x3b, 0x63, 0x73, 0xfc, 0x74,
-0xf6, 0x72, 0x74, 0xf6, 0x6b, 0x3b, 0x70, 0xe9, 0x6e, 0x74, 0x65, 0x6b, 0x3b, 0x73, 0x7a, 0x6f, 0x6d, 0x62, 0x61, 0x74,
-0x56, 0x3b, 0x48, 0x3b, 0x4b, 0x3b, 0x53, 0x7a, 0x65, 0x3b, 0x43, 0x73, 0x3b, 0x50, 0x3b, 0x53, 0x7a, 0x6f, 0x56, 0x3b,
-0x48, 0x3b, 0x4b, 0x3b, 0x53, 0x7a, 0x3b, 0x43, 0x73, 0x3b, 0x50, 0x3b, 0x53, 0x7a, 0x73, 0x75, 0x6e, 0x6e, 0x75, 0x64,
-0x61, 0x67, 0x75, 0x72, 0x3b, 0x6d, 0xe1, 0x6e, 0x75, 0x64, 0x61, 0x67, 0x75, 0x72, 0x3b, 0xfe, 0x72, 0x69, 0xf0, 0x6a,
-0x75, 0x64, 0x61, 0x67, 0x75, 0x72, 0x3b, 0x6d, 0x69, 0xf0, 0x76, 0x69, 0x6b, 0x75, 0x64, 0x61, 0x67, 0x75, 0x72, 0x3b,
-0x66, 0x69, 0x6d, 0x6d, 0x74, 0x75, 0x64, 0x61, 0x67, 0x75, 0x72, 0x3b, 0x66, 0xf6, 0x73, 0x74, 0x75, 0x64, 0x61, 0x67,
-0x75, 0x72, 0x3b, 0x6c, 0x61, 0x75, 0x67, 0x61, 0x72, 0x64, 0x61, 0x67, 0x75, 0x72, 0x73, 0x75, 0x6e, 0x2e, 0x3b, 0x6d,
-0xe1, 0x6e, 0x2e, 0x3b, 0xfe, 0x72, 0x69, 0x2e, 0x3b, 0x6d, 0x69, 0xf0, 0x2e, 0x3b, 0x66, 0x69, 0x6d, 0x2e, 0x3b, 0x66,
-0xf6, 0x73, 0x2e, 0x3b, 0x6c, 0x61, 0x75, 0x2e, 0x53, 0x3b, 0x4d, 0x3b, 0xde, 0x3b, 0x4d, 0x3b, 0x46, 0x3b, 0x46, 0x3b,
-0x4c, 0x53, 0x1ecd, 0x6e, 0x64, 0x65, 0x65, 0x3b, 0x4d, 0x1ecd, 0x6e, 0x64, 0x65, 0x3b, 0x54, 0x69, 0x75, 0x7a, 0x64, 0x65,
-0x65, 0x3b, 0x57, 0x65, 0x6e, 0x65, 0x7a, 0x64, 0x65, 0x65, 0x3b, 0x54, 0x1ecd, 0x1ecd, 0x7a, 0x64, 0x65, 0x65, 0x3b, 0x46,
-0x72, 0x61, 0x1ecb, 0x64, 0x65, 0x65, 0x3b, 0x53, 0x61, 0x74, 0x1ecd, 0x64, 0x65, 0x65, 0x53, 0x1ecd, 0x6e, 0x3b, 0x4d, 0x1ecd,
-0x6e, 0x3b, 0x54, 0x69, 0x75, 0x3b, 0x57, 0x65, 0x6e, 0x3b, 0x54, 0x1ecd, 0x1ecd, 0x3b, 0x46, 0x72, 0x61, 0x1ecb, 0x3b, 0x53,
-0x61, 0x74, 0x70, 0x61, 0x73, 0x65, 0x70, 0x65, 0x69, 0x76, 0x69, 0x3b, 0x76, 0x75, 0x6f, 0x73, 0x73, 0x61, 0x72, 0x67,
-0xe2, 0x3b, 0x6d, 0x61, 0x6a, 0x65, 0x62, 0x61, 0x72, 0x67, 0xe2, 0x3b, 0x6b, 0x6f, 0x73, 0x6b, 0x6f, 0x6b, 0x6b, 0x6f,
-0x3b, 0x74, 0x75, 0x6f, 0x72, 0xe2, 0x73, 0x74, 0xe2, 0x68, 0x3b, 0x76, 0xe1, 0x73, 0x74, 0x75, 0x70, 0x70, 0x65, 0x69,
-0x76, 0x69, 0x3b, 0x6c, 0xe1, 0x76, 0x75, 0x72, 0x64, 0xe2, 0x68, 0x70, 0x61, 0x73, 0x65, 0x70, 0x65, 0x65, 0x69, 0x76,
-0x69, 0x3b, 0x76, 0x75, 0x6f, 0x73, 0x73, 0x61, 0x61, 0x72, 0x67, 0xe2, 0x3b, 0x6d, 0x61, 0x6a, 0x65, 0x62, 0x61, 0x61,
-0x72, 0x67, 0xe2, 0x3b, 0x6b, 0x6f, 0x73, 0x6b, 0x6f, 0x68, 0x6f, 0x3b, 0x74, 0x75, 0x6f, 0x72, 0xe2, 0x73, 0x74, 0x75,
-0x76, 0x3b, 0x76, 0xe1, 0x73, 0x74, 0x75, 0x70, 0x70, 0x65, 0x65, 0x69, 0x76, 0x69, 0x3b, 0x6c, 0xe1, 0x76, 0x75, 0x72,
-0x64, 0x75, 0x76, 0x70, 0x61, 0x73, 0x3b, 0x76, 0x75, 0x6f, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6b, 0x6f, 0x73, 0x3b, 0x74,
-0x75, 0x6f, 0x3b, 0x76, 0xe1, 0x73, 0x3b, 0x6c, 0xe1, 0x76, 0x70, 0x3b, 0x56, 0x3b, 0x4d, 0x3b, 0x4b, 0x3b, 0x54, 0x3b,
-0x56, 0x3b, 0x4c, 0x4d, 0x69, 0x6e, 0x67, 0x67, 0x75, 0x3b, 0x53, 0x65, 0x6e, 0x69, 0x6e, 0x3b, 0x53, 0x65, 0x6c, 0x61,
-0x73, 0x61, 0x3b, 0x52, 0x61, 0x62, 0x75, 0x3b, 0x4b, 0x61, 0x6d, 0x69, 0x73, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0x3b,
-0x53, 0x61, 0x62, 0x74, 0x75, 0x4d, 0x69, 0x6e, 0x3b, 0x53, 0x65, 0x6e, 0x3b, 0x53, 0x65, 0x6c, 0x3b, 0x52, 0x61, 0x62,
-0x3b, 0x4b, 0x61, 0x6d, 0x3b, 0x4a, 0x75, 0x6d, 0x3b, 0x53, 0x61, 0x62, 0x4d, 0x3b, 0x53, 0x3b, 0x53, 0x3b, 0x52, 0x3b,
-0x4b, 0x3b, 0x4a, 0x3b, 0x53, 0x64, 0x6f, 0x6d, 0x69, 0x6e, 0x69, 0x63, 0x61, 0x3b, 0x6c, 0x75, 0x6e, 0x65, 0x64, 0x69,
-0x3b, 0x6d, 0x61, 0x72, 0x74, 0x65, 0x64, 0x69, 0x3b, 0x6d, 0x65, 0x72, 0x63, 0x75, 0x72, 0x69, 0x64, 0x69, 0x3b, 0x6a,
-0x6f, 0x76, 0x65, 0x64, 0x69, 0x3b, 0x76, 0x65, 0x6e, 0x65, 0x72, 0x64, 0x69, 0x3b, 0x73, 0x61, 0x62, 0x62, 0x61, 0x74,
-0x6f, 0x64, 0x6f, 0x6d, 0x3b, 0x6c, 0x75, 0x6e, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x6d, 0x65, 0x72, 0x3b, 0x6a, 0x6f, 0x76,
-0x3b, 0x76, 0x65, 0x6e, 0x3b, 0x73, 0x61, 0x62, 0x64, 0x3b, 0x6c, 0x3b, 0x6d, 0x3b, 0x6d, 0x3b, 0x6a, 0x3b, 0x76, 0x3b,
-0x73, 0x44, 0xe9, 0x20, 0x44, 0x6f, 0x6d, 0x68, 0x6e, 0x61, 0x69, 0x67, 0x68, 0x3b, 0x44, 0xe9, 0x20, 0x4c, 0x75, 0x61,
-0x69, 0x6e, 0x3b, 0x44, 0xe9, 0x20, 0x4d, 0xe1, 0x69, 0x72, 0x74, 0x3b, 0x44, 0xe9, 0x20, 0x43, 0xe9, 0x61, 0x64, 0x61,
-0x6f, 0x69, 0x6e, 0x3b, 0x44, 0xe9, 0x61, 0x72, 0x64, 0x61, 0x6f, 0x69, 0x6e, 0x3b, 0x44, 0xe9, 0x20, 0x68, 0x41, 0x6f,
-0x69, 0x6e, 0x65, 0x3b, 0x44, 0xe9, 0x20, 0x53, 0x61, 0x74, 0x68, 0x61, 0x69, 0x72, 0x6e, 0x44, 0x6f, 0x6d, 0x68, 0x3b,
-0x4c, 0x75, 0x61, 0x6e, 0x3b, 0x4d, 0xe1, 0x69, 0x72, 0x74, 0x3b, 0x43, 0xe9, 0x61, 0x64, 0x3b, 0x44, 0xe9, 0x61, 0x72,
-0x3b, 0x41, 0x6f, 0x69, 0x6e, 0x65, 0x3b, 0x53, 0x61, 0x74, 0x68, 0x44, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x43, 0x3b, 0x44,
-0x3b, 0x41, 0x3b, 0x53, 0x64, 0x6f, 0x6d, 0x65, 0x6e, 0x69, 0x63, 0x61, 0x3b, 0x6c, 0x75, 0x6e, 0x65, 0x64, 0xec, 0x3b,
-0x6d, 0x61, 0x72, 0x74, 0x65, 0x64, 0xec, 0x3b, 0x6d, 0x65, 0x72, 0x63, 0x6f, 0x6c, 0x65, 0x64, 0xec, 0x3b, 0x67, 0x69,
-0x6f, 0x76, 0x65, 0x64, 0xec, 0x3b, 0x76, 0x65, 0x6e, 0x65, 0x72, 0x64, 0xec, 0x3b, 0x73, 0x61, 0x62, 0x61, 0x74, 0x6f,
-0x64, 0x6f, 0x6d, 0x3b, 0x6c, 0x75, 0x6e, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x6d, 0x65, 0x72, 0x3b, 0x67, 0x69, 0x6f, 0x3b,
-0x76, 0x65, 0x6e, 0x3b, 0x73, 0x61, 0x62, 0x44, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x47, 0x3b, 0x56, 0x3b, 0x53,
-0x65e5, 0x66dc, 0x65e5, 0x3b, 0x6708, 0x66dc, 0x65e5, 0x3b, 0x706b, 0x66dc, 0x65e5, 0x3b, 0x6c34, 0x66dc, 0x65e5, 0x3b, 0x6728, 0x66dc, 0x65e5, 0x3b,
-0x91d1, 0x66dc, 0x65e5, 0x3b, 0x571f, 0x66dc, 0x65e5, 0x65e5, 0x3b, 0x6708, 0x3b, 0x706b, 0x3b, 0x6c34, 0x3b, 0x6728, 0x3b, 0x91d1, 0x3b, 0x571f,
-0x41, 0x68, 0x61, 0x64, 0x3b, 0x53, 0x65, 0x6e, 0x69, 0x6e, 0x3b, 0x53, 0x65, 0x6c, 0x61, 0x73, 0x61, 0x3b, 0x52, 0x61,
-0x62, 0x75, 0x3b, 0x4b, 0x61, 0x6d, 0x69, 0x73, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0x3b, 0x53, 0x61, 0x62, 0x74, 0x75,
-0x41, 0x68, 0x61, 0x64, 0x3b, 0x53, 0x65, 0x6e, 0x3b, 0x53, 0x65, 0x6c, 0x3b, 0x52, 0x61, 0x62, 0x3b, 0x4b, 0x61, 0x6d,
-0x3b, 0x4a, 0x75, 0x6d, 0x3b, 0x53, 0x61, 0x62, 0x41, 0x3b, 0x53, 0x3b, 0x53, 0x3b, 0x52, 0x3b, 0x4b, 0x3b, 0x4a, 0x3b,
-0x53, 0x44, 0x69, 0x6d, 0x61, 0x73, 0x3b, 0x54, 0x65, 0x6e, 0x65, 0x14b, 0x3b, 0x54, 0x61, 0x6c, 0x61, 0x74, 0x61, 0x3b,
-0x41, 0x6c, 0x61, 0x72, 0x62, 0x61, 0x79, 0x3b, 0x41, 0x72, 0x61, 0x6d, 0x69, 0x73, 0x61, 0x79, 0x3b, 0x41, 0x72, 0x6a,
-0x75, 0x6d, 0x61, 0x3b, 0x53, 0x69, 0x62, 0x69, 0x74, 0x69, 0x44, 0x69, 0x6d, 0x3b, 0x54, 0x65, 0x6e, 0x3b, 0x54, 0x61,
-0x6c, 0x3b, 0x41, 0x6c, 0x61, 0x3b, 0x41, 0x72, 0x61, 0x3b, 0x41, 0x72, 0x6a, 0x3b, 0x53, 0x69, 0x62, 0x44, 0x3b, 0x54,
-0x3b, 0x54, 0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x53, 0x64, 0x75, 0x6d, 0x69, 0x6e, 0x67, 0x75, 0x3b, 0x73, 0x69,
-0x67, 0x75, 0x6e, 0x64, 0x61, 0x2d, 0x66, 0x65, 0x72, 0x61, 0x3b, 0x74, 0x65, 0x72, 0x73, 0x61, 0x2d, 0x66, 0x65, 0x72,
-0x61, 0x3b, 0x6b, 0x75, 0x61, 0x72, 0x74, 0x61, 0x2d, 0x66, 0x65, 0x72, 0x61, 0x3b, 0x6b, 0x69, 0x6e, 0x74, 0x61, 0x2d,
-0x66, 0x65, 0x72, 0x61, 0x3b, 0x73, 0x65, 0x73, 0x74, 0x61, 0x2d, 0x66, 0x65, 0x72, 0x61, 0x3b, 0x73, 0xe1, 0x62, 0x61,
-0x64, 0x75, 0x64, 0x75, 0x6d, 0x3b, 0x73, 0x69, 0x67, 0x3b, 0x74, 0x65, 0x72, 0x3b, 0x6b, 0x75, 0x61, 0x3b, 0x6b, 0x69,
-0x6e, 0x3b, 0x73, 0x65, 0x73, 0x3b, 0x73, 0x61, 0x62, 0x44, 0x3b, 0x53, 0x3b, 0x54, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x53,
-0x3b, 0x53, 0x41, 0x63, 0x65, 0x72, 0x3b, 0x41, 0x72, 0x69, 0x6d, 0x3b, 0x41, 0x72, 0x61, 0x6d, 0x3b, 0x41, 0x68, 0x61,
-0x64, 0x3b, 0x41, 0x6d, 0x68, 0x61, 0x64, 0x3b, 0x53, 0x65, 0x6d, 0x3b, 0x53, 0x65, 0x64, 0x59, 0x61, 0x6e, 0x61, 0x73,
-0x73, 0x3b, 0x53, 0x61, 0x6e, 0x61, 0x73, 0x73, 0x3b, 0x4b, 0x72, 0x61, 0x1e0d, 0x61, 0x73, 0x73, 0x3b, 0x4b, 0x75, 0x1e93,
-0x61, 0x73, 0x73, 0x3b, 0x53, 0x61, 0x6d, 0x61, 0x73, 0x73, 0x3b, 0x53, 0x1e0d, 0x69, 0x73, 0x61, 0x73, 0x73, 0x3b, 0x53,
-0x61, 0x79, 0x61, 0x73, 0x73, 0x41, 0x63, 0x65, 0x3b, 0x41, 0x72, 0x69, 0x3b, 0x41, 0x72, 0x61, 0x3b, 0x41, 0x68, 0x61,
-0x3b, 0x41, 0x6d, 0x68, 0x3b, 0x53, 0x65, 0x6d, 0x3b, 0x53, 0x65, 0x64, 0x59, 0x61, 0x6e, 0x3b, 0x53, 0x61, 0x6e, 0x3b,
-0x4b, 0x72, 0x61, 0x1e0d, 0x3b, 0x4b, 0x75, 0x1e93, 0x3b, 0x53, 0x61, 0x6d, 0x3b, 0x53, 0x1e0d, 0x69, 0x73, 0x3b, 0x53, 0x61,
-0x79, 0x59, 0x3b, 0x53, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x53, 0x3b, 0x53, 0x3b, 0x53, 0x43, 0x3b, 0x52, 0x3b, 0x52, 0x3b,
-0x48, 0x3b, 0x4d, 0x3b, 0x53, 0x3b, 0x53, 0x73, 0x254, 0x6e, 0x64, 0x69, 0x3b, 0x6c, 0x75, 0x6e, 0x64, 0x69, 0x3b, 0x6d,
-0x61, 0x72, 0x64, 0x69, 0x3b, 0x6d, 0x25b, 0x72, 0x6b, 0x25b, 0x72, 0x25b, 0x64, 0x69, 0x3b, 0x79, 0x65, 0x64, 0x69, 0x3b,
-0x76, 0x61, 0x14b, 0x64, 0x25b, 0x72, 0x25b, 0x64, 0x69, 0x3b, 0x6d, 0x254, 0x6e, 0x254, 0x20, 0x73, 0x254, 0x6e, 0x64, 0x69,
-0x73, 0x6f, 0x3b, 0x6c, 0x75, 0x3b, 0x6d, 0x61, 0x3b, 0x6d, 0x25b, 0x3b, 0x79, 0x65, 0x3b, 0x76, 0x61, 0x3b, 0x6d, 0x73,
-0x73, 0x61, 0x70, 0x61, 0x61, 0x74, 0x3b, 0x61, 0x74, 0x61, 0x61, 0x73, 0x69, 0x6e, 0x6e, 0x67, 0x6f, 0x72, 0x6e, 0x65,
-0x71, 0x3b, 0x6d, 0x61, 0x72, 0x6c, 0x75, 0x6e, 0x6e, 0x67, 0x6f, 0x72, 0x6e, 0x65, 0x71, 0x3b, 0x70, 0x69, 0x6e, 0x67,
-0x61, 0x73, 0x75, 0x6e, 0x6e, 0x67, 0x6f, 0x72, 0x6e, 0x65, 0x71, 0x3b, 0x73, 0x69, 0x73, 0x61, 0x6d, 0x61, 0x6e, 0x6e,
-0x67, 0x6f, 0x72, 0x6e, 0x65, 0x71, 0x3b, 0x74, 0x61, 0x6c, 0x6c, 0x69, 0x6d, 0x61, 0x6e, 0x6e, 0x67, 0x6f, 0x72, 0x6e,
-0x65, 0x71, 0x3b, 0x61, 0x72, 0x66, 0x69, 0x6e, 0x69, 0x6e, 0x6e, 0x67, 0x6f, 0x72, 0x6e, 0x65, 0x71, 0x73, 0x61, 0x70,
-0x3b, 0x61, 0x74, 0x61, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x70, 0x69, 0x6e, 0x3b, 0x73, 0x69, 0x73, 0x3b, 0x74, 0x61, 0x6c,
-0x3b, 0x61, 0x72, 0x66, 0x53, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x50, 0x3b, 0x53, 0x3b, 0x54, 0x3b, 0x41, 0x4b, 0x6f, 0x74,
-0x69, 0x73, 0x61, 0x70, 0x3b, 0x4b, 0x6f, 0x74, 0x61, 0x61, 0x69, 0x3b, 0x4b, 0x6f, 0x61, 0x65, 0x6e, 0x67, 0x2019, 0x3b,
-0x4b, 0x6f, 0x73, 0x6f, 0x6d, 0x6f, 0x6b, 0x3b, 0x4b, 0x6f, 0x61, 0x6e, 0x67, 0x2019, 0x77, 0x61, 0x6e, 0x3b, 0x4b, 0x6f,
-0x6d, 0x75, 0x75, 0x74, 0x3b, 0x4b, 0x6f, 0x6c, 0x6f, 0x4b, 0x74, 0x73, 0x3b, 0x4b, 0x6f, 0x74, 0x3b, 0x4b, 0x6f, 0x6f,
-0x3b, 0x4b, 0x6f, 0x73, 0x3b, 0x4b, 0x6f, 0x61, 0x3b, 0x4b, 0x6f, 0x6d, 0x3b, 0x4b, 0x6f, 0x6c, 0x54, 0x3b, 0x54, 0x3b,
-0x4f, 0x3b, 0x53, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4c, 0x57, 0x61, 0x20, 0x6b, 0x79, 0x75, 0x6d, 0x77, 0x61, 0x3b, 0x57,
-0x61, 0x20, 0x6b, 0x77, 0x61, 0x6d, 0x62, 0x129, 0x6c, 0x129, 0x6c, 0x79, 0x61, 0x3b, 0x57, 0x61, 0x20, 0x6b, 0x65, 0x6c,
-0x129, 0x3b, 0x57, 0x61, 0x20, 0x6b, 0x61, 0x74, 0x61, 0x74, 0x169, 0x3b, 0x57, 0x61, 0x20, 0x6b, 0x61, 0x6e, 0x61, 0x3b,
-0x57, 0x61, 0x20, 0x6b, 0x61, 0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x57, 0x61, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x74, 0x68, 0x61,
-0x74, 0x169, 0x57, 0x6b, 0x79, 0x3b, 0x57, 0x6b, 0x77, 0x3b, 0x57, 0x6b, 0x6c, 0x3b, 0x57, 0x74, 0x169, 0x3b, 0x57, 0x6b,
-0x6e, 0x3b, 0x57, 0x74, 0x6e, 0x3b, 0x57, 0x74, 0x68, 0x59, 0x3b, 0x57, 0x3b, 0x45, 0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x41,
-0x3b, 0x41, 0xcad, 0xcbe, 0xca8, 0xcc1, 0xcb5, 0xcbe, 0xcb0, 0x3b, 0xcb8, 0xccb, 0xcae, 0xcb5, 0xcbe, 0xcb0, 0x3b, 0xcae, 0xc82, 0xc97,
-0xcb3, 0xcb5, 0xcbe, 0xcb0, 0x3b, 0xcac, 0xcc1, 0xca7, 0xcb5, 0xcbe, 0xcb0, 0x3b, 0xc97, 0xcc1, 0xcb0, 0xcc1, 0xcb5, 0xcbe, 0xcb0, 0x3b,
-0xcb6, 0xcc1, 0xc95, 0xccd, 0xcb0, 0xcb5, 0xcbe, 0xcb0, 0x3b, 0xcb6, 0xca8, 0xcbf, 0xcb5, 0xcbe, 0xcb0, 0xcad, 0xcbe, 0xca8, 0xcc1, 0x3b,
-0xcb8, 0xccb, 0xcae, 0x3b, 0xcae, 0xc82, 0xc97, 0xcb3, 0x3b, 0xcac, 0xcc1, 0xca7, 0x3b, 0xc97, 0xcc1, 0xcb0, 0xcc1, 0x3b, 0xcb6, 0xcc1,
-0xc95, 0xccd, 0xcb0, 0x3b, 0xcb6, 0xca8, 0xcbf, 0xcad, 0xcbe, 0x3b, 0xcb8, 0xccb, 0x3b, 0xcae, 0xc82, 0x3b, 0xcac, 0xcc1, 0x3b, 0xc97,
-0xcc1, 0x3b, 0xcb6, 0xcc1, 0x3b, 0xcb6, 0x627, 0x64e, 0x62a, 0x6be, 0x648, 0x627, 0x631, 0x3b, 0x698, 0x654, 0x646, 0x62f, 0x631, 0x655,
-0x631, 0x648, 0x627, 0x631, 0x3b, 0x628, 0x6c6, 0x645, 0x648, 0x627, 0x631, 0x3b, 0x628, 0x648, 0x62f, 0x648, 0x627, 0x631, 0x3b, 0x628,
-0x631, 0x620, 0x633, 0x648, 0x627, 0x631, 0x3b, 0x62c, 0x64f, 0x645, 0x6c1, 0x3b, 0x628, 0x679, 0x648, 0x627, 0x631, 0x622, 0x62a, 0x6be,
-0x648, 0x627, 0x631, 0x3b, 0x698, 0x654, 0x646, 0x62f, 0x655, 0x631, 0x648, 0x627, 0x631, 0x3b, 0x628, 0x6c6, 0x645, 0x648, 0x627, 0x631,
-0x3b, 0x628, 0x648, 0x62f, 0x648, 0x627, 0x631, 0x3b, 0x628, 0x631, 0x620, 0x633, 0x648, 0x627, 0x631, 0x3b, 0x62c, 0x64f, 0x645, 0x6c1,
-0x3b, 0x628, 0x679, 0x648, 0x627, 0x631, 0x627, 0x3b, 0x698, 0x3b, 0x628, 0x3b, 0x628, 0x3b, 0x628, 0x3b, 0x62c, 0x3b, 0x628, 0x906,
-0x925, 0x935, 0x93e, 0x930, 0x3b, 0x91a, 0x902, 0x926, 0x93f, 0x930, 0x935, 0x93e, 0x930, 0x3b, 0x92c, 0x941, 0x935, 0x93e, 0x930, 0x3b,
-0x92c, 0x94b, 0x926, 0x935, 0x93e, 0x930, 0x3b, 0x92c, 0x94d, 0x930, 0x947, 0x938, 0x935, 0x93e, 0x930, 0x3b, 0x91c, 0x941, 0x92e, 0x94d,
-0x92e, 0x93e, 0x3b, 0x92c, 0x91f, 0x935, 0x93e, 0x930, 0x905, 0x3b, 0x91a, 0x3b, 0x92c, 0x3b, 0x92c, 0x3b, 0x92c, 0x3b, 0x91c, 0x3b,
-0x92c, 0x436, 0x435, 0x43a, 0x441, 0x435, 0x43d, 0x431, 0x456, 0x3b, 0x434, 0x4af, 0x439, 0x441, 0x435, 0x43d, 0x431, 0x456, 0x3b, 0x441,
-0x435, 0x439, 0x441, 0x435, 0x43d, 0x431, 0x456, 0x3b, 0x441, 0x4d9, 0x440, 0x441, 0x435, 0x43d, 0x431, 0x456, 0x3b, 0x431, 0x435, 0x439,
-0x441, 0x435, 0x43d, 0x431, 0x456, 0x3b, 0x436, 0x4b1, 0x43c, 0x430, 0x3b, 0x441, 0x435, 0x43d, 0x431, 0x456, 0x436, 0x441, 0x3b, 0x434,
-0x441, 0x3b, 0x441, 0x441, 0x3b, 0x441, 0x440, 0x3b, 0x431, 0x441, 0x3b, 0x436, 0x43c, 0x3b, 0x441, 0x431, 0x416, 0x3b, 0x414, 0x3b,
-0x421, 0x3b, 0x421, 0x3b, 0x411, 0x3b, 0x416, 0x3b, 0x421, 0x17a2, 0x17b6, 0x1791, 0x17b7, 0x178f, 0x17d2, 0x1799, 0x3b, 0x1785, 0x1793, 0x17d2,
-0x1791, 0x3b, 0x17a2, 0x1784, 0x17d2, 0x1782, 0x17b6, 0x179a, 0x3b, 0x1796, 0x17bb, 0x1792, 0x3b, 0x1796, 0x17d2, 0x179a, 0x17a0, 0x179f, 0x17d2, 0x1794,
-0x178f, 0x17b7, 0x17cd, 0x3b, 0x179f, 0x17bb, 0x1780, 0x17d2, 0x179a, 0x3b, 0x179f, 0x17c5, 0x179a, 0x17cd, 0x17a2, 0x17b6, 0x1791, 0x17b7, 0x178f, 0x17d2,
-0x1799, 0x3b, 0x1785, 0x17d0, 0x1793, 0x17d2, 0x1791, 0x3b, 0x17a2, 0x1784, 0x17d2, 0x1782, 0x17b6, 0x179a, 0x3b, 0x1796, 0x17bb, 0x1792, 0x3b, 0x1796,
-0x17d2, 0x179a, 0x17a0, 0x179f, 0x17d2, 0x1794, 0x178f, 0x17b7, 0x17cd, 0x3b, 0x179f, 0x17bb, 0x1780, 0x17d2, 0x179a, 0x3b, 0x179f, 0x17c5, 0x179a, 0x17cd,
-0x17a2, 0x17b6, 0x1791, 0x17b7, 0x178f, 0x17d2, 0x1799, 0x3b, 0x1785, 0x1793, 0x17d2, 0x1791, 0x3b, 0x17a2, 0x1784, 0x17d2, 0x1782, 0x17b6, 0x179a, 0x3b,
-0x1796, 0x17bb, 0x1792, 0x3b, 0x1796, 0x17d2, 0x179a, 0x17a0, 0x3b, 0x179f, 0x17bb, 0x1780, 0x17d2, 0x179a, 0x3b, 0x179f, 0x17c5, 0x179a, 0x17cd, 0x17a2,
-0x3b, 0x1785, 0x3b, 0x17a2, 0x3b, 0x1796, 0x3b, 0x1796, 0x3b, 0x179f, 0x3b, 0x179f, 0x4b, 0x69, 0x75, 0x6d, 0x69, 0x61, 0x3b, 0x4e,
-0x6a, 0x75, 0x6d, 0x61, 0x74, 0x61, 0x74, 0x169, 0x3b, 0x4e, 0x6a, 0x75, 0x6d, 0x61, 0x69, 0x6e, 0x65, 0x3b, 0x4e, 0x6a,
-0x75, 0x6d, 0x61, 0x74, 0x61, 0x6e, 0x61, 0x3b, 0x41, 0x72, 0x61, 0x6d, 0x69, 0x74, 0x68, 0x69, 0x3b, 0x4e, 0x6a, 0x75,
-0x6d, 0x61, 0x61, 0x3b, 0x4e, 0x6a, 0x75, 0x6d, 0x61, 0x6d, 0x6f, 0x74, 0x68, 0x69, 0x4b, 0x4d, 0x41, 0x3b, 0x4e, 0x54,
-0x54, 0x3b, 0x4e, 0x4d, 0x4e, 0x3b, 0x4e, 0x4d, 0x54, 0x3b, 0x41, 0x52, 0x54, 0x3b, 0x4e, 0x4d, 0x41, 0x3b, 0x4e, 0x4d,
-0x4d, 0x4b, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b, 0x41, 0x3b, 0x4e, 0x3b, 0x4e, 0x4b, 0x75, 0x20, 0x63, 0x79, 0x75,
-0x6d, 0x77, 0x65, 0x72, 0x75, 0x3b, 0x4b, 0x75, 0x77, 0x61, 0x20, 0x6d, 0x62, 0x65, 0x72, 0x65, 0x3b, 0x4b, 0x75, 0x77,
-0x61, 0x20, 0x6b, 0x61, 0x62, 0x69, 0x72, 0x69, 0x3b, 0x4b, 0x75, 0x77, 0x61, 0x20, 0x67, 0x61, 0x74, 0x61, 0x74, 0x75,
-0x3b, 0x4b, 0x75, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x6e, 0x65, 0x3b, 0x4b, 0x75, 0x77, 0x61, 0x20, 0x67, 0x61, 0x74, 0x61,
-0x6e, 0x75, 0x3b, 0x4b, 0x75, 0x77, 0x61, 0x20, 0x67, 0x61, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x74, 0x75, 0x63, 0x79, 0x75,
-0x2e, 0x3b, 0x6d, 0x62, 0x65, 0x2e, 0x3b, 0x6b, 0x61, 0x62, 0x2e, 0x3b, 0x67, 0x74, 0x75, 0x2e, 0x3b, 0x6b, 0x61, 0x6e,
-0x2e, 0x3b, 0x67, 0x6e, 0x75, 0x2e, 0x3b, 0x67, 0x6e, 0x64, 0x2e, 0x906, 0x92f, 0x924, 0x93e, 0x930, 0x3b, 0x938, 0x94b, 0x92e,
-0x93e, 0x930, 0x3b, 0x92e, 0x902, 0x917, 0x933, 0x93e, 0x930, 0x3b, 0x92c, 0x941, 0x927, 0x935, 0x93e, 0x930, 0x3b, 0x92c, 0x93f, 0x930,
-0x947, 0x938, 0x94d, 0x924, 0x93e, 0x930, 0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930, 0x93e, 0x930, 0x3b, 0x936, 0x947, 0x928, 0x935, 0x93e,
-0x930, 0x906, 0x3b, 0x938, 0x94b, 0x3b, 0x92e, 0x902, 0x3b, 0x92c, 0x941, 0x3b, 0x92c, 0x3b, 0x936, 0x941, 0x3b, 0x936, 0x947, 0x906,
-0x3b, 0x938, 0x94b, 0x3b, 0x92e, 0x902, 0x3b, 0x92c, 0x941, 0x3b, 0x92c, 0x93f, 0x3b, 0x936, 0x941, 0x3b, 0x936, 0x947, 0xc77c, 0xc694,
-0xc77c, 0x3b, 0xc6d4, 0xc694, 0xc77c, 0x3b, 0xd654, 0xc694, 0xc77c, 0x3b, 0xc218, 0xc694, 0xc77c, 0x3b, 0xbaa9, 0xc694, 0xc77c, 0x3b, 0xae08, 0xc694,
-0xc77c, 0x3b, 0xd1a0, 0xc694, 0xc77c, 0xc77c, 0x3b, 0xc6d4, 0x3b, 0xd654, 0x3b, 0xc218, 0x3b, 0xbaa9, 0x3b, 0xae08, 0x3b, 0xd1a0, 0x41, 0x6c,
-0x68, 0x61, 0x64, 0x69, 0x3b, 0x41, 0x74, 0x69, 0x6e, 0x6e, 0x69, 0x3b, 0x41, 0x74, 0x61, 0x6c, 0x61, 0x61, 0x74, 0x61,
-0x3b, 0x41, 0x6c, 0x61, 0x72, 0x62, 0x61, 0x3b, 0x41, 0x6c, 0x68, 0x61, 0x6d, 0x69, 0x69, 0x73, 0x61, 0x3b, 0x41, 0x6c,
-0x7a, 0x75, 0x6d, 0x61, 0x3b, 0x41, 0x73, 0x69, 0x62, 0x74, 0x69, 0x41, 0x6c, 0x68, 0x3b, 0x41, 0x74, 0x69, 0x3b, 0x41,
-0x74, 0x61, 0x3b, 0x41, 0x6c, 0x61, 0x3b, 0x41, 0x6c, 0x6d, 0x3b, 0x41, 0x6c, 0x7a, 0x3b, 0x41, 0x73, 0x69, 0x48, 0x3b,
-0x54, 0x3b, 0x54, 0x3b, 0x4c, 0x3b, 0x4c, 0x3b, 0x4c, 0x3b, 0x53, 0x41, 0x6c, 0x68, 0x61, 0x64, 0x69, 0x3b, 0x41, 0x74,
-0x69, 0x6e, 0x69, 0x3b, 0x41, 0x74, 0x61, 0x6c, 0x61, 0x74, 0x61, 0x3b, 0x41, 0x6c, 0x61, 0x72, 0x62, 0x61, 0x3b, 0x41,
-0x6c, 0x68, 0x61, 0x6d, 0x69, 0x69, 0x73, 0x61, 0x3b, 0x41, 0x6c, 0x6a, 0x75, 0x6d, 0x61, 0x3b, 0x41, 0x73, 0x73, 0x61,
-0x62, 0x64, 0x75, 0x41, 0x6c, 0x68, 0x3b, 0x41, 0x74, 0x69, 0x3b, 0x41, 0x74, 0x61, 0x3b, 0x41, 0x6c, 0x61, 0x3b, 0x41,
-0x6c, 0x6d, 0x3b, 0x41, 0x6c, 0x6a, 0x3b, 0x41, 0x73, 0x73, 0x79, 0x65, 0x6b, 0x15f, 0x65, 0x6d, 0x3b, 0x64, 0x75, 0x15f,
-0x65, 0x6d, 0x3b, 0x73, 0xea, 0x15f, 0x65, 0x6d, 0x3b, 0xe7, 0x61, 0x72, 0x15f, 0x65, 0x6d, 0x3b, 0x70, 0xea, 0x6e, 0x63,
-0x15f, 0x65, 0x6d, 0x3b, 0xee, 0x6e, 0x3b, 0x15f, 0x65, 0x6d, 0xee, 0x79, 0x15f, 0x3b, 0x64, 0x15f, 0x3b, 0x73, 0x15f, 0x3b,
-0xe7, 0x15f, 0x3b, 0x70, 0x15f, 0x3b, 0xee, 0x6e, 0x3b, 0x15f, 0x59, 0x3b, 0x44, 0x3b, 0x53, 0x3b, 0xc7, 0x3b, 0x50, 0x3b,
-0xce, 0x3b, 0x15e, 0x73, 0x254, 0x301, 0x6e, 0x64, 0x254, 0x3b, 0x6d, 0x254, 0x301, 0x6e, 0x64, 0x254, 0x3b, 0x73, 0x254, 0x301,
-0x6e, 0x64, 0x254, 0x20, 0x6d, 0x61, 0x66, 0xfa, 0x20, 0x6d, 0xe1, 0x62, 0x61, 0x3b, 0x73, 0x254, 0x301, 0x6e, 0x64, 0x254,
-0x20, 0x6d, 0x61, 0x66, 0xfa, 0x20, 0x6d, 0xe1, 0x6c, 0x61, 0x6c, 0x3b, 0x73, 0x254, 0x301, 0x6e, 0x64, 0x254, 0x20, 0x6d,
-0x61, 0x66, 0xfa, 0x20, 0x6d, 0xe1, 0x6e, 0x61, 0x3b, 0x6d, 0x61, 0x62, 0xe1, 0x67, 0xe1, 0x20, 0x6d, 0xe1, 0x20, 0x73,
-0x75, 0x6b, 0x75, 0x6c, 0x3b, 0x73, 0xe1, 0x73, 0x61, 0x64, 0x69, 0x73, 0x254, 0x301, 0x6e, 0x3b, 0x6d, 0x254, 0x301, 0x6e,
-0x3b, 0x73, 0x6d, 0x62, 0x3b, 0x73, 0x6d, 0x6c, 0x3b, 0x73, 0x6d, 0x6e, 0x3b, 0x6d, 0x62, 0x73, 0x3b, 0x73, 0x61, 0x73,
-0x73, 0x3b, 0x6d, 0x3b, 0x73, 0x3b, 0x73, 0x3b, 0x73, 0x3b, 0x6d, 0x3b, 0x73, 0x436, 0x435, 0x43a, 0x448, 0x435, 0x43c, 0x431,
-0x438, 0x3b, 0x434, 0x4af, 0x439, 0x448, 0x4e9, 0x43c, 0x431, 0x4af, 0x3b, 0x448, 0x435, 0x439, 0x448, 0x435, 0x43c, 0x431, 0x438, 0x3b,
-0x448, 0x430, 0x440, 0x448, 0x435, 0x43c, 0x431, 0x438, 0x3b, 0x431, 0x435, 0x439, 0x448, 0x435, 0x43c, 0x431, 0x438, 0x3b, 0x436, 0x443,
-0x43c, 0x430, 0x3b, 0x438, 0x448, 0x435, 0x43c, 0x431, 0x438, 0x436, 0x435, 0x43a, 0x2e, 0x3b, 0x434, 0x4af, 0x439, 0x2e, 0x3b, 0x448,
-0x435, 0x439, 0x448, 0x2e, 0x3b, 0x448, 0x430, 0x440, 0x448, 0x2e, 0x3b, 0x431, 0x435, 0x439, 0x448, 0x2e, 0x3b, 0x436, 0x443, 0x43c,
-0x430, 0x3b, 0x438, 0x448, 0x43c, 0x2e, 0x416, 0x3b, 0x414, 0x3b, 0x428, 0x3b, 0x428, 0x3b, 0x411, 0x3b, 0x416, 0x3b, 0x418, 0x41,
-0x14b, 0x70, 0xe9, 0x74, 0x75, 0x77, 0x61, 0x6b, 0x21f, 0x61, 0x14b, 0x3b, 0x41, 0x14b, 0x70, 0xe9, 0x74, 0x75, 0x77, 0x61,
-0x14b, 0x17e, 0x69, 0x3b, 0x41, 0x14b, 0x70, 0xe9, 0x74, 0x75, 0x6e, 0x75, 0x14b, 0x70, 0x61, 0x3b, 0x41, 0x14b, 0x70, 0xe9,
-0x74, 0x75, 0x79, 0x61, 0x6d, 0x6e, 0x69, 0x3b, 0x41, 0x14b, 0x70, 0xe9, 0x74, 0x75, 0x74, 0x6f, 0x70, 0x61, 0x3b, 0x41,
-0x14b, 0x70, 0xe9, 0x74, 0x75, 0x7a, 0x61, 0x70, 0x74, 0x61, 0x14b, 0x3b, 0x4f, 0x77, 0xe1, 0x14b, 0x67, 0x79, 0x75, 0x17e,
-0x61, 0x17e, 0x61, 0x70, 0x69, 0x41, 0x3b, 0x57, 0x3b, 0x4e, 0x3b, 0x59, 0x3b, 0x54, 0x3b, 0x5a, 0x3b, 0x4f, 0x4a, 0x75,
-0x6d, 0x61, 0x70, 0xed, 0x69, 0x72, 0x69, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0xe1, 0x74, 0x75, 0x3b, 0x4a, 0x75, 0x6d,
-0x61, 0xed, 0x6e, 0x65, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0xe1, 0x61, 0x6e, 0x6f, 0x3b, 0x41, 0x6c, 0x61, 0x6d, 0xed,
-0x69, 0x73, 0x69, 0x3b, 0x49, 0x6a, 0x75, 0x6d, 0xe1, 0x61, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x6d, 0xf3, 0x6f, 0x73, 0x69,
-0x50, 0xed, 0x69, 0x6c, 0x69, 0x3b, 0x54, 0xe1, 0x61, 0x74, 0x75, 0x3b, 0xcd, 0x6e, 0x65, 0x3b, 0x54, 0xe1, 0x61, 0x6e,
-0x6f, 0x3b, 0x41, 0x6c, 0x68, 0x3b, 0x49, 0x6a, 0x6d, 0x3b, 0x4d, 0xf3, 0x6f, 0x73, 0x69, 0x50, 0x3b, 0x54, 0x3b, 0x45,
-0x3b, 0x4f, 0x3b, 0x41, 0x3b, 0x49, 0x3b, 0x4d, 0xea7, 0xeb1, 0xe99, 0xead, 0xeb2, 0xe97, 0xeb4, 0xe94, 0x3b, 0xea7, 0xeb1, 0xe99,
-0xe88, 0xeb1, 0xe99, 0x3b, 0xea7, 0xeb1, 0xe99, 0xead, 0xeb1, 0xe87, 0xe84, 0xeb2, 0xe99, 0x3b, 0xea7, 0xeb1, 0xe99, 0xe9e, 0xeb8, 0xe94,
-0x3b, 0xea7, 0xeb1, 0xe99, 0xe9e, 0xeb0, 0xeab, 0xeb1, 0xe94, 0x3b, 0xea7, 0xeb1, 0xe99, 0xeaa, 0xeb8, 0xe81, 0x3b, 0xea7, 0xeb1, 0xe99,
-0xec0, 0xeaa, 0xebb, 0xeb2, 0xead, 0xeb2, 0xe97, 0xeb4, 0xe94, 0x3b, 0xe88, 0xeb1, 0xe99, 0x3b, 0xead, 0xeb1, 0xe87, 0xe84, 0xeb2, 0xe99,
-0x3b, 0xe9e, 0xeb8, 0xe94, 0x3b, 0xe9e, 0xeb0, 0xeab, 0xeb1, 0xe94, 0x3b, 0xeaa, 0xeb8, 0xe81, 0x3b, 0xec0, 0xeaa, 0xebb, 0xeb2, 0xead,
-0xeb2, 0x3b, 0xe88, 0x3b, 0xead, 0x3b, 0xe9e, 0x3b, 0xe9e, 0xeab, 0x3b, 0xeaa, 0xeb8, 0x3b, 0xeaa, 0x53, 0x76, 0x113, 0x74, 0x64,
-0x69, 0x65, 0x6e, 0x61, 0x3b, 0x50, 0x69, 0x72, 0x6d, 0x64, 0x69, 0x65, 0x6e, 0x61, 0x3b, 0x4f, 0x74, 0x72, 0x64, 0x69,
-0x65, 0x6e, 0x61, 0x3b, 0x54, 0x72, 0x65, 0x161, 0x64, 0x69, 0x65, 0x6e, 0x61, 0x3b, 0x43, 0x65, 0x74, 0x75, 0x72, 0x74,
-0x64, 0x69, 0x65, 0x6e, 0x61, 0x3b, 0x50, 0x69, 0x65, 0x6b, 0x74, 0x64, 0x69, 0x65, 0x6e, 0x61, 0x3b, 0x53, 0x65, 0x73,
-0x74, 0x64, 0x69, 0x65, 0x6e, 0x61, 0x73, 0x76, 0x113, 0x74, 0x64, 0x69, 0x65, 0x6e, 0x61, 0x3b, 0x70, 0x69, 0x72, 0x6d,
-0x64, 0x69, 0x65, 0x6e, 0x61, 0x3b, 0x6f, 0x74, 0x72, 0x64, 0x69, 0x65, 0x6e, 0x61, 0x3b, 0x74, 0x72, 0x65, 0x161, 0x64,
-0x69, 0x65, 0x6e, 0x61, 0x3b, 0x63, 0x65, 0x74, 0x75, 0x72, 0x74, 0x64, 0x69, 0x65, 0x6e, 0x61, 0x3b, 0x70, 0x69, 0x65,
-0x6b, 0x74, 0x64, 0x69, 0x65, 0x6e, 0x61, 0x3b, 0x73, 0x65, 0x73, 0x74, 0x64, 0x69, 0x65, 0x6e, 0x61, 0x53, 0x76, 0x113,
-0x74, 0x64, 0x2e, 0x3b, 0x50, 0x69, 0x72, 0x6d, 0x64, 0x2e, 0x3b, 0x4f, 0x74, 0x72, 0x64, 0x2e, 0x3b, 0x54, 0x72, 0x65,
-0x161, 0x64, 0x2e, 0x3b, 0x43, 0x65, 0x74, 0x75, 0x72, 0x74, 0x64, 0x2e, 0x3b, 0x50, 0x69, 0x65, 0x6b, 0x74, 0x64, 0x2e,
-0x3b, 0x53, 0x65, 0x73, 0x74, 0x64, 0x2e, 0x73, 0x76, 0x113, 0x74, 0x64, 0x2e, 0x3b, 0x70, 0x69, 0x72, 0x6d, 0x64, 0x2e,
-0x3b, 0x6f, 0x74, 0x72, 0x64, 0x2e, 0x3b, 0x74, 0x72, 0x65, 0x161, 0x64, 0x2e, 0x3b, 0x63, 0x65, 0x74, 0x75, 0x72, 0x74,
-0x64, 0x2e, 0x3b, 0x70, 0x69, 0x65, 0x6b, 0x74, 0x64, 0x2e, 0x3b, 0x73, 0x65, 0x73, 0x74, 0x64, 0x2e, 0x53, 0x3b, 0x50,
-0x3b, 0x4f, 0x3b, 0x54, 0x3b, 0x43, 0x3b, 0x50, 0x3b, 0x53, 0x65, 0x79, 0x65, 0x6e, 0x67, 0x61, 0x3b, 0x6d, 0x6f, 0x6b,
-0x254, 0x6c, 0x254, 0x20, 0x6d, 0x77, 0x61, 0x20, 0x79, 0x61, 0x6d, 0x62, 0x6f, 0x3b, 0x6d, 0x6f, 0x6b, 0x254, 0x6c, 0x254,
-0x20, 0x6d, 0x77, 0x61, 0x20, 0x6d, 0xed, 0x62, 0x61, 0x6c, 0xe9, 0x3b, 0x6d, 0x6f, 0x6b, 0x254, 0x6c, 0x254, 0x20, 0x6d,
-0x77, 0x61, 0x20, 0x6d, 0xed, 0x73, 0xe1, 0x74, 0x6f, 0x3b, 0x6d, 0x6f, 0x6b, 0x254, 0x6c, 0x254, 0x20, 0x79, 0x61, 0x20,
-0x6d, 0xed, 0x6e, 0xe9, 0x69, 0x3b, 0x6d, 0x6f, 0x6b, 0x254, 0x6c, 0x254, 0x20, 0x79, 0x61, 0x20, 0x6d, 0xed, 0x74, 0xe1,
-0x6e, 0x6f, 0x3b, 0x6d, 0x70, 0x254, 0x301, 0x73, 0x254, 0x65, 0x79, 0x65, 0x3b, 0x79, 0x62, 0x6f, 0x3b, 0x6d, 0x62, 0x6c,
-0x3b, 0x6d, 0x73, 0x74, 0x3b, 0x6d, 0x69, 0x6e, 0x3b, 0x6d, 0x74, 0x6e, 0x3b, 0x6d, 0x70, 0x73, 0x65, 0x3b, 0x79, 0x3b,
-0x6d, 0x3b, 0x6d, 0x3b, 0x6d, 0x3b, 0x6d, 0x3b, 0x70, 0x73, 0x65, 0x6b, 0x6d, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x69, 0x73,
-0x3b, 0x70, 0x69, 0x72, 0x6d, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x69, 0x73, 0x3b, 0x61, 0x6e, 0x74, 0x72, 0x61, 0x64, 0x69,
-0x65, 0x6e, 0x69, 0x73, 0x3b, 0x74, 0x72, 0x65, 0x10d, 0x69, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x69, 0x73, 0x3b, 0x6b, 0x65,
-0x74, 0x76, 0x69, 0x72, 0x74, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x69, 0x73, 0x3b, 0x70, 0x65, 0x6e, 0x6b, 0x74, 0x61, 0x64,
-0x69, 0x65, 0x6e, 0x69, 0x73, 0x3b, 0x161, 0x65, 0x161, 0x74, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x69, 0x73, 0x73, 0x6b, 0x3b,
-0x70, 0x72, 0x3b, 0x61, 0x6e, 0x3b, 0x74, 0x72, 0x3b, 0x6b, 0x74, 0x3b, 0x70, 0x6e, 0x3b, 0x161, 0x74, 0x53, 0x3b, 0x50,
-0x3b, 0x41, 0x3b, 0x54, 0x3b, 0x4b, 0x3b, 0x50, 0x3b, 0x160, 0x6e, 0x6a, 0x65, 0x17a, 0x65, 0x6c, 0x61, 0x3b, 0x70, 0xf3,
-0x6e, 0x6a, 0x65, 0x17a, 0x65, 0x6c, 0x65, 0x3b, 0x77, 0x61, 0x142, 0x74, 0x6f, 0x72, 0x61, 0x3b, 0x73, 0x72, 0x6a, 0x6f,
-0x64, 0x61, 0x3b, 0x73, 0x74, 0x77, 0xf3, 0x72, 0x74, 0x6b, 0x3b, 0x70, 0x11b, 0x74, 0x6b, 0x3b, 0x73, 0x6f, 0x62, 0x6f,
-0x74, 0x61, 0x6e, 0x6a, 0x65, 0x3b, 0x70, 0xf3, 0x6e, 0x3b, 0x77, 0x61, 0x142, 0x3b, 0x73, 0x72, 0x6a, 0x3b, 0x73, 0x74,
-0x77, 0x3b, 0x70, 0x11b, 0x74, 0x3b, 0x73, 0x6f, 0x62, 0x6e, 0x3b, 0x70, 0x3b, 0x77, 0x3b, 0x73, 0x3b, 0x73, 0x3b, 0x70,
-0x3b, 0x73, 0x53, 0xfc, 0x6e, 0x6e, 0x64, 0x61, 0x67, 0x3b, 0x4d, 0x61, 0x61, 0x6e, 0x64, 0x61, 0x67, 0x3b, 0x44, 0x69,
-0x6e, 0x67, 0x73, 0x64, 0x61, 0x67, 0x3b, 0x4d, 0x69, 0x64, 0x64, 0x65, 0x77, 0x65, 0x6b, 0x65, 0x6e, 0x3b, 0x44, 0x75,
-0x6e, 0x6e, 0x65, 0x72, 0x73, 0x64, 0x61, 0x67, 0x3b, 0x46, 0x72, 0x65, 0x65, 0x64, 0x61, 0x67, 0x3b, 0x53, 0xfc, 0x6e,
-0x6e, 0x61, 0x76, 0x65, 0x6e, 0x64, 0x53, 0xfc, 0x2e, 0x3b, 0x4d, 0x61, 0x2e, 0x3b, 0x44, 0x69, 0x2e, 0x3b, 0x4d, 0x69,
-0x2e, 0x3b, 0x44, 0x75, 0x2e, 0x3b, 0x46, 0x72, 0x2e, 0x3b, 0x53, 0x61, 0x2e, 0x4c, 0x75, 0x6d, 0x69, 0x6e, 0x67, 0x75,
-0x3b, 0x4e, 0x6b, 0x6f, 0x64, 0x79, 0x61, 0x3b, 0x4e, 0x64, 0xe0, 0x61, 0x79, 0xe0, 0x3b, 0x4e, 0x64, 0x61, 0x6e, 0x67,
-0xf9, 0x3b, 0x4e, 0x6a, 0xf2, 0x77, 0x61, 0x3b, 0x4e, 0x67, 0xf2, 0x76, 0x79, 0x61, 0x3b, 0x4c, 0x75, 0x62, 0x69, 0x6e,
-0x67, 0x75, 0x4c, 0x75, 0x6d, 0x3b, 0x4e, 0x6b, 0x6f, 0x3b, 0x4e, 0x64, 0x79, 0x3b, 0x4e, 0x64, 0x67, 0x3b, 0x4e, 0x6a,
-0x77, 0x3b, 0x4e, 0x67, 0x76, 0x3b, 0x4c, 0x75, 0x62, 0x4c, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b, 0x4e,
-0x3b, 0x4c, 0x4a, 0x75, 0x6d, 0x61, 0x70, 0x69, 0x6c, 0x3b, 0x57, 0x75, 0x6f, 0x6b, 0x20, 0x54, 0x69, 0x63, 0x68, 0x3b,
-0x54, 0x69, 0x63, 0x68, 0x20, 0x41, 0x72, 0x69, 0x79, 0x6f, 0x3b, 0x54, 0x69, 0x63, 0x68, 0x20, 0x41, 0x64, 0x65, 0x6b,
-0x3b, 0x54, 0x69, 0x63, 0x68, 0x20, 0x41, 0x6e, 0x67, 0x2019, 0x77, 0x65, 0x6e, 0x3b, 0x54, 0x69, 0x63, 0x68, 0x20, 0x41,
-0x62, 0x69, 0x63, 0x68, 0x3b, 0x4e, 0x67, 0x65, 0x73, 0x6f, 0x4a, 0x4d, 0x50, 0x3b, 0x57, 0x55, 0x54, 0x3b, 0x54, 0x41,
-0x52, 0x3b, 0x54, 0x41, 0x44, 0x3b, 0x54, 0x41, 0x4e, 0x3b, 0x54, 0x41, 0x42, 0x3b, 0x4e, 0x47, 0x53, 0x4a, 0x3b, 0x57,
-0x3b, 0x54, 0x3b, 0x54, 0x3b, 0x54, 0x3b, 0x54, 0x3b, 0x4e, 0x53, 0x6f, 0x6e, 0x6e, 0x64, 0x65, 0x67, 0x3b, 0x4d, 0xe9,
-0x69, 0x6e, 0x64, 0x65, 0x67, 0x3b, 0x44, 0xeb, 0x6e, 0x73, 0x63, 0x68, 0x64, 0x65, 0x67, 0x3b, 0x4d, 0xeb, 0x74, 0x74,
-0x77, 0x6f, 0x63, 0x68, 0x3b, 0x44, 0x6f, 0x6e, 0x6e, 0x65, 0x73, 0x63, 0x68, 0x64, 0x65, 0x67, 0x3b, 0x46, 0x72, 0x65,
-0x69, 0x64, 0x65, 0x67, 0x3b, 0x53, 0x61, 0x6d, 0x73, 0x63, 0x68, 0x64, 0x65, 0x67, 0x53, 0x6f, 0x6e, 0x3b, 0x4d, 0xe9,
-0x69, 0x3b, 0x44, 0xeb, 0x6e, 0x3b, 0x4d, 0xeb, 0x74, 0x3b, 0x44, 0x6f, 0x6e, 0x3b, 0x46, 0x72, 0x65, 0x3b, 0x53, 0x61,
-0x6d, 0x53, 0x6f, 0x6e, 0x2e, 0x3b, 0x4d, 0xe9, 0x69, 0x2e, 0x3b, 0x44, 0xeb, 0x6e, 0x2e, 0x3b, 0x4d, 0xeb, 0x74, 0x2e,
-0x3b, 0x44, 0x6f, 0x6e, 0x2e, 0x3b, 0x46, 0x72, 0x65, 0x2e, 0x3b, 0x53, 0x61, 0x6d, 0x2e, 0x4a, 0x75, 0x6d, 0x61, 0x70,
-0x69, 0x72, 0x69, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0x61, 0x74, 0x75, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x6e, 0x6e, 0x65,
-0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x4d, 0x75, 0x72, 0x77, 0x61, 0x20, 0x77, 0x61, 0x20, 0x4b,
-0x61, 0x6e, 0x6e, 0x65, 0x3b, 0x4d, 0x75, 0x72, 0x77, 0x61, 0x20, 0x77, 0x61, 0x20, 0x4b, 0x61, 0x74, 0x61, 0x6e, 0x6f,
-0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x6d, 0x6f, 0x73, 0x69, 0x4a, 0x32, 0x3b, 0x4a, 0x33, 0x3b, 0x4a, 0x34, 0x3b, 0x4a, 0x35,
-0x3b, 0x41, 0x6c, 0x3b, 0x49, 0x6a, 0x3b, 0x4a, 0x31, 0x43d, 0x435, 0x434, 0x435, 0x43b, 0x430, 0x3b, 0x43f, 0x43e, 0x43d, 0x435,
-0x434, 0x435, 0x43b, 0x43d, 0x438, 0x43a, 0x3b, 0x432, 0x442, 0x43e, 0x440, 0x43d, 0x438, 0x43a, 0x3b, 0x441, 0x440, 0x435, 0x434, 0x430,
-0x3b, 0x447, 0x435, 0x442, 0x432, 0x440, 0x442, 0x43e, 0x43a, 0x3b, 0x43f, 0x435, 0x442, 0x43e, 0x43a, 0x3b, 0x441, 0x430, 0x431, 0x43e,
-0x442, 0x430, 0x43d, 0x435, 0x434, 0x2e, 0x3b, 0x43f, 0x43e, 0x43d, 0x2e, 0x3b, 0x432, 0x442, 0x43e, 0x2e, 0x3b, 0x441, 0x440, 0x435,
-0x2e, 0x3b, 0x447, 0x435, 0x442, 0x2e, 0x3b, 0x43f, 0x435, 0x442, 0x2e, 0x3b, 0x441, 0x430, 0x431, 0x2e, 0x4a, 0x75, 0x6d, 0x61,
-0x70, 0x69, 0x6c, 0x79, 0x69, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0x61, 0x74, 0x75, 0x75, 0x3b, 0x4a, 0x75, 0x6d, 0x61,
-0x6e, 0x6e, 0x65, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0x61, 0x6e, 0x75, 0x3b, 0x41, 0x6c, 0x68, 0x61, 0x6d, 0x69, 0x73,
-0x69, 0x3b, 0x49, 0x6a, 0x75, 0x6d, 0x61, 0x61, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x6d, 0x6f, 0x73, 0x69, 0x4a, 0x70, 0x69,
-0x3b, 0x4a, 0x74, 0x74, 0x3b, 0x4a, 0x6e, 0x6e, 0x3b, 0x4a, 0x74, 0x6e, 0x3b, 0x41, 0x6c, 0x68, 0x3b, 0x49, 0x6a, 0x75,
-0x3b, 0x4a, 0x6d, 0x6f, 0x930, 0x935, 0x93f, 0x20, 0x926, 0x93f, 0x928, 0x3b, 0x938, 0x94b, 0x92e, 0x20, 0x926, 0x93f, 0x928, 0x3b,
-0x92e, 0x902, 0x917, 0x932, 0x20, 0x926, 0x93f, 0x928, 0x3b, 0x92c, 0x941, 0x927, 0x20, 0x926, 0x93f, 0x928, 0x3b, 0x92c, 0x943, 0x939,
-0x938, 0x94d, 0x92a, 0x924, 0x93f, 0x20, 0x926, 0x93f, 0x928, 0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930, 0x20, 0x926, 0x93f, 0x928, 0x3b,
-0x936, 0x928, 0x93f, 0x20, 0x926, 0x93f, 0x928, 0x53, 0x61, 0x62, 0x61, 0x74, 0x6f, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0x61,
-0x74, 0x75, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x6e, 0x6e, 0x65, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0x61, 0x6e, 0x6f, 0x3b,
-0x41, 0x72, 0x61, 0x68, 0x61, 0x6d, 0x69, 0x73, 0x69, 0x3b, 0x49, 0x6a, 0x75, 0x6d, 0x61, 0x61, 0x3b, 0x4a, 0x75, 0x6d,
-0x61, 0x6d, 0x6f, 0x73, 0x69, 0x53, 0x61, 0x62, 0x3b, 0x4a, 0x74, 0x74, 0x3b, 0x4a, 0x6e, 0x6e, 0x3b, 0x4a, 0x74, 0x6e,
-0x3b, 0x41, 0x72, 0x61, 0x3b, 0x49, 0x6a, 0x75, 0x3b, 0x4a, 0x6d, 0x6f, 0x53, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b,
-0x41, 0x3b, 0x49, 0x3b, 0x4a, 0x4c, 0x69, 0x64, 0x75, 0x76, 0x61, 0x20, 0x6c, 0x79, 0x61, 0x70, 0x69, 0x6c, 0x69, 0x3b,
-0x4c, 0x69, 0x64, 0x75, 0x76, 0x61, 0x20, 0x6c, 0x79, 0x61, 0x74, 0x61, 0x74, 0x75, 0x3b, 0x4c, 0x69, 0x64, 0x75, 0x76,
-0x61, 0x20, 0x6c, 0x79, 0x61, 0x6e, 0x63, 0x68, 0x65, 0x63, 0x68, 0x69, 0x3b, 0x4c, 0x69, 0x64, 0x75, 0x76, 0x61, 0x20,
-0x6c, 0x79, 0x61, 0x6e, 0x6e, 0x79, 0x61, 0x6e, 0x6f, 0x3b, 0x4c, 0x69, 0x64, 0x75, 0x76, 0x61, 0x20, 0x6c, 0x79, 0x61,
-0x6e, 0x6e, 0x79, 0x61, 0x6e, 0x6f, 0x20, 0x6e, 0x61, 0x20, 0x6c, 0x69, 0x6e, 0x6a, 0x69, 0x3b, 0x4c, 0x69, 0x64, 0x75,
-0x76, 0x61, 0x20, 0x6c, 0x79, 0x61, 0x6e, 0x6e, 0x79, 0x61, 0x6e, 0x6f, 0x20, 0x6e, 0x61, 0x20, 0x6d, 0x61, 0x76, 0x69,
-0x6c, 0x69, 0x3b, 0x4c, 0x69, 0x64, 0x75, 0x76, 0x61, 0x20, 0x6c, 0x69, 0x74, 0x61, 0x6e, 0x64, 0x69, 0x4c, 0x6c, 0x32,
-0x3b, 0x4c, 0x6c, 0x33, 0x3b, 0x4c, 0x6c, 0x34, 0x3b, 0x4c, 0x6c, 0x35, 0x3b, 0x4c, 0x6c, 0x36, 0x3b, 0x4c, 0x6c, 0x37,
-0x3b, 0x4c, 0x6c, 0x31, 0x32, 0x3b, 0x33, 0x3b, 0x34, 0x3b, 0x35, 0x3b, 0x36, 0x3b, 0x37, 0x3b, 0x31, 0x41, 0x6c, 0x61,
-0x68, 0x61, 0x64, 0x79, 0x3b, 0x41, 0x6c, 0x61, 0x74, 0x73, 0x69, 0x6e, 0x61, 0x69, 0x6e, 0x79, 0x3b, 0x54, 0x61, 0x6c,
-0x61, 0x74, 0x61, 0x3b, 0x41, 0x6c, 0x61, 0x72, 0x6f, 0x62, 0x69, 0x61, 0x3b, 0x41, 0x6c, 0x61, 0x6b, 0x61, 0x6d, 0x69,
-0x73, 0x79, 0x3b, 0x5a, 0x6f, 0x6d, 0x61, 0x3b, 0x41, 0x73, 0x61, 0x62, 0x6f, 0x74, 0x73, 0x79, 0x41, 0x6c, 0x61, 0x68,
-0x3b, 0x41, 0x6c, 0x61, 0x74, 0x73, 0x3b, 0x54, 0x61, 0x6c, 0x3b, 0x41, 0x6c, 0x61, 0x72, 0x3b, 0x41, 0x6c, 0x61, 0x6b,
-0x3b, 0x5a, 0x6f, 0x6d, 0x3b, 0x41, 0x73, 0x61, 0x62, 0x41, 0x3b, 0x41, 0x3b, 0x54, 0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x5a,
-0x3b, 0x41, 0xd1e, 0xd3e, 0xd2f, 0xd31, 0xd3e, 0xd34, 0xd4d, 0x200c, 0xd1a, 0x3b, 0xd24, 0xd3f, 0xd19, 0xd4d, 0xd15, 0xd33, 0xd3e, 0xd34,
-0xd4d, 0x200c, 0xd1a, 0x3b, 0xd1a, 0xd4a, 0xd35, 0xd4d, 0xd35, 0xd3e, 0xd34, 0xd4d, 0x200c, 0xd1a, 0x3b, 0xd2c, 0xd41, 0xd27, 0xd28, 0xd3e,
-0xd34, 0xd4d, 0x200c, 0xd1a, 0x3b, 0xd35, 0xd4d, 0xd2f, 0xd3e, 0xd34, 0xd3e, 0xd34, 0xd4d, 0x200c, 0xd1a, 0x3b, 0xd35, 0xd46, 0xd33, 0xd4d,
-0xd33, 0xd3f, 0xd2f, 0xd3e, 0xd34, 0xd4d, 0x200c, 0xd1a, 0x3b, 0xd36, 0xd28, 0xd3f, 0xd2f, 0xd3e, 0xd34, 0xd4d, 0x200c, 0xd1a, 0xd1e, 0xd3e,
-0xd2f, 0xd31, 0xd3e, 0xd34, 0xd4d, 0x200c, 0xd1a, 0x3b, 0xd24, 0xd3f, 0xd19, 0xd4d, 0xd15, 0xd33, 0xd3e, 0xd34, 0xd4d, 0x200c, 0xd1a, 0x3b,
-0xd1a, 0xd4a, 0xd35, 0xd4d, 0xd35, 0xd3e, 0xd34, 0xd4d, 0xd1a, 0x3b, 0xd2c, 0xd41, 0xd27, 0xd28, 0xd3e, 0xd34, 0xd4d, 0x200c, 0xd1a, 0x3b,
-0xd35, 0xd4d, 0xd2f, 0xd3e, 0xd34, 0xd3e, 0xd34, 0xd4d, 0x200c, 0xd1a, 0x3b, 0xd35, 0xd46, 0xd33, 0xd4d, 0xd33, 0xd3f, 0xd2f, 0xd3e, 0xd34,
-0xd4d, 0x200c, 0xd1a, 0x3b, 0xd36, 0xd28, 0xd3f, 0xd2f, 0xd3e, 0xd34, 0xd4d, 0x200c, 0xd1a, 0xd1e, 0xd3e, 0xd2f, 0xd7c, 0x3b, 0xd24, 0xd3f,
-0xd19, 0xd4d, 0xd15, 0xd7e, 0x3b, 0xd1a, 0xd4a, 0xd35, 0xd4d, 0xd35, 0x3b, 0xd2c, 0xd41, 0xd27, 0xd7b, 0x3b, 0xd35, 0xd4d, 0xd2f, 0xd3e,
-0xd34, 0xd02, 0x3b, 0xd35, 0xd46, 0xd33, 0xd4d, 0xd33, 0xd3f, 0x3b, 0xd36, 0xd28, 0xd3f, 0xd1e, 0xd3e, 0x3b, 0xd24, 0xd3f, 0x3b, 0xd1a,
-0xd4a, 0x3b, 0xd2c, 0xd41, 0x3b, 0xd35, 0xd4d, 0xd2f, 0xd3e, 0x3b, 0xd35, 0xd46, 0x3b, 0xd36, 0xd1e, 0x3b, 0xd24, 0xd3f, 0x3b, 0xd1a,
-0xd4a, 0x3b, 0xd2c, 0xd41, 0x3b, 0xd35, 0xd4d, 0xd2f, 0xd3e, 0x3b, 0xd35, 0xd46, 0x3b, 0xd36, 0x41, 0x68, 0x61, 0x64, 0x3b, 0x49,
-0x73, 0x6e, 0x69, 0x6e, 0x3b, 0x53, 0x65, 0x6c, 0x61, 0x73, 0x61, 0x3b, 0x52, 0x61, 0x62, 0x75, 0x3b, 0x4b, 0x68, 0x61,
-0x6d, 0x69, 0x73, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x61, 0x74, 0x3b, 0x53, 0x61, 0x62, 0x74, 0x75, 0x41, 0x68, 0x64, 0x3b,
-0x49, 0x73, 0x6e, 0x3b, 0x53, 0x65, 0x6c, 0x3b, 0x52, 0x61, 0x62, 0x3b, 0x4b, 0x68, 0x61, 0x3b, 0x4a, 0x75, 0x6d, 0x3b,
-0x53, 0x61, 0x62, 0x41, 0x3b, 0x49, 0x3b, 0x53, 0x3b, 0x52, 0x3b, 0x4b, 0x3b, 0x4a, 0x3b, 0x53, 0x49, 0x6c, 0x2d, 0x126,
-0x61, 0x64, 0x64, 0x3b, 0x49, 0x74, 0x2d, 0x54, 0x6e, 0x65, 0x6a, 0x6e, 0x3b, 0x49, 0x74, 0x2d, 0x54, 0x6c, 0x69, 0x65,
-0x74, 0x61, 0x3b, 0x4c, 0x2d, 0x45, 0x72, 0x62, 0x67, 0x127, 0x61, 0x3b, 0x49, 0x6c, 0x2d, 0x126, 0x61, 0x6d, 0x69, 0x73,
-0x3b, 0x49, 0x6c, 0x2d, 0x120, 0x69, 0x6d, 0x67, 0x127, 0x61, 0x3b, 0x49, 0x73, 0x2d, 0x53, 0x69, 0x62, 0x74, 0x126, 0x61,
-0x64, 0x3b, 0x54, 0x6e, 0x65, 0x3b, 0x54, 0x6c, 0x69, 0x3b, 0x45, 0x72, 0x62, 0x3b, 0x126, 0x61, 0x6d, 0x3b, 0x120, 0x69,
-0x6d, 0x3b, 0x53, 0x69, 0x62, 0x126, 0x64, 0x3b, 0x54, 0x6e, 0x3b, 0x54, 0x6c, 0x3b, 0x45, 0x72, 0x3b, 0x126, 0x6d, 0x3b,
-0x120, 0x6d, 0x3b, 0x53, 0x62, 0x126, 0x64, 0x3b, 0x54, 0x3b, 0x54, 0x6c, 0x3b, 0x45, 0x72, 0x3b, 0x126, 0x6d, 0x3b, 0x120,
-0x6d, 0x3b, 0x53, 0x62, 0x9a8, 0x9cb, 0x982, 0x9ae, 0x9be, 0x987, 0x99c, 0x9bf, 0x982, 0x3b, 0x9a8, 0x9bf, 0x982, 0x9a5, 0x9cc, 0x995,
-0x9be, 0x9ac, 0x9be, 0x3b, 0x9b2, 0x9c8, 0x9ac, 0x9be, 0x995, 0x9aa, 0x9cb, 0x995, 0x9aa, 0x9be, 0x3b, 0x9af, 0x9bc, 0x9c1, 0x9ae, 0x9b6,
-0x995, 0x9c8, 0x9b6, 0x9be, 0x3b, 0x9b6, 0x997, 0x9cb, 0x9b2, 0x9b6, 0x9c7, 0x9a8, 0x3b, 0x987, 0x9b0, 0x9be, 0x987, 0x3b, 0x9a5, 0x9be,
-0x982, 0x99c, 0x9a8, 0x9cb, 0x3b, 0x9a8, 0x9bf, 0x982, 0x3b, 0x9b2, 0x9c8, 0x3b, 0x9af, 0x9bc, 0x9c1, 0x9ae, 0x3b, 0x9b6, 0x997, 0x3b,
-0x987, 0x9b0, 0x9be, 0x3b, 0x9a5, 0x9be, 0x982, 0x9a8, 0x9cb, 0x982, 0x3b, 0x9a8, 0x9bf, 0x982, 0x3b, 0x9b2, 0x9c8, 0x9ac, 0x9be, 0x3b,
-0x9af, 0x9bc, 0x9c1, 0x9ae, 0x3b, 0x9b6, 0x997, 0x9cb, 0x3b, 0x987, 0x9b0, 0x9be, 0x3b, 0x9a5, 0x9be, 0x982, 0x4a, 0x65, 0x64, 0x6f,
-0x6f, 0x6e, 0x65, 0x65, 0x3b, 0x4a, 0x65, 0x6c, 0x68, 0x65, 0x69, 0x6e, 0x3b, 0x4a, 0x65, 0x6d, 0x61, 0x79, 0x72, 0x74,
-0x3b, 0x4a, 0x65, 0x72, 0x63, 0x65, 0x61, 0x6e, 0x3b, 0x4a, 0x65, 0x72, 0x64, 0x65, 0x69, 0x6e, 0x3b, 0x4a, 0x65, 0x68,
-0x65, 0x69, 0x6e, 0x65, 0x79, 0x3b, 0x4a, 0x65, 0x73, 0x61, 0x72, 0x6e, 0x4a, 0x65, 0x64, 0x3b, 0x4a, 0x65, 0x6c, 0x3b,
-0x4a, 0x65, 0x6d, 0x3b, 0x4a, 0x65, 0x72, 0x63, 0x3b, 0x4a, 0x65, 0x72, 0x64, 0x3b, 0x4a, 0x65, 0x68, 0x3b, 0x4a, 0x65,
-0x73, 0x52, 0x101, 0x74, 0x61, 0x70, 0x75, 0x3b, 0x4d, 0x61, 0x6e, 0x65, 0x3b, 0x54, 0x16b, 0x72, 0x65, 0x69, 0x3b, 0x57,
-0x65, 0x6e, 0x65, 0x72, 0x65, 0x69, 0x3b, 0x54, 0x101, 0x69, 0x74, 0x65, 0x3b, 0x50, 0x61, 0x72, 0x61, 0x69, 0x72, 0x65,
-0x3b, 0x52, 0x101, 0x68, 0x6f, 0x72, 0x6f, 0x69, 0x52, 0x101, 0x74, 0x3b, 0x4d, 0x61, 0x6e, 0x65, 0x3b, 0x54, 0x16b, 0x72,
-0x3b, 0x57, 0x65, 0x6e, 0x65, 0x3b, 0x54, 0x101, 0x69, 0x74, 0x3b, 0x50, 0x61, 0x72, 0x3b, 0x52, 0x101, 0x68, 0x52, 0x74,
-0x3b, 0x4d, 0x3b, 0x54, 0x3b, 0x57, 0x3b, 0x54, 0x3b, 0x50, 0x3b, 0x52, 0x68, 0x52, 0x74, 0x3b, 0x4d, 0x3b, 0x54, 0x3b,
-0x45, 0x3b, 0x54, 0x3b, 0x50, 0x3b, 0x52, 0x68, 0x930, 0x935, 0x93f, 0x935, 0x93e, 0x930, 0x3b, 0x938, 0x94b, 0x92e, 0x935, 0x93e,
-0x930, 0x3b, 0x92e, 0x902, 0x917, 0x933, 0x935, 0x93e, 0x930, 0x3b, 0x92c, 0x941, 0x927, 0x935, 0x93e, 0x930, 0x3b, 0x917, 0x941, 0x930,
-0x941, 0x935, 0x93e, 0x930, 0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930, 0x935, 0x93e, 0x930, 0x3b, 0x936, 0x928, 0x93f, 0x935, 0x93e, 0x930,
-0x930, 0x935, 0x93f, 0x3b, 0x938, 0x94b, 0x92e, 0x3b, 0x92e, 0x902, 0x917, 0x933, 0x3b, 0x92c, 0x941, 0x927, 0x3b, 0x917, 0x941, 0x930,
-0x941, 0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930, 0x3b, 0x936, 0x928, 0x93f, 0x4a, 0x75, 0x6d, 0x61, 0x70, 0xed, 0x6c, 0xed, 0x3b,
-0x4a, 0x75, 0x6d, 0x61, 0x74, 0xe1, 0x74, 0x75, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x6e, 0x65, 0x3b, 0x4a, 0x75, 0x6d, 0x61,
-0x74, 0xe1, 0x6e, 0x254, 0x3b, 0x41, 0x6c, 0x61, 0xe1, 0x6d, 0x69, 0x73, 0x69, 0x3b, 0x4a, 0x75, 0x6d, 0xe1, 0x61, 0x3b,
-0x4a, 0x75, 0x6d, 0x61, 0x6d, 0xf3, 0x73, 0x69, 0x4b, 0x69, 0x75, 0x6d, 0x69, 0x61, 0x3b, 0x4d, 0x75, 0x72, 0x61, 0x6d,
-0x75, 0x6b, 0x6f, 0x3b, 0x57, 0x61, 0x69, 0x72, 0x69, 0x3b, 0x57, 0x65, 0x74, 0x68, 0x61, 0x74, 0x75, 0x3b, 0x57, 0x65,
-0x6e, 0x61, 0x3b, 0x57, 0x65, 0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x6d, 0x6f, 0x73, 0x69, 0x4b, 0x49,
-0x55, 0x3b, 0x4d, 0x52, 0x41, 0x3b, 0x57, 0x41, 0x49, 0x3b, 0x57, 0x45, 0x54, 0x3b, 0x57, 0x45, 0x4e, 0x3b, 0x57, 0x54,
-0x4e, 0x3b, 0x4a, 0x55, 0x4d, 0x4b, 0x3b, 0x4d, 0x3b, 0x57, 0x3b, 0x57, 0x3b, 0x57, 0x3b, 0x57, 0x3b, 0x4a, 0x41, 0x6e,
-0x65, 0x67, 0x20, 0x31, 0x3b, 0x41, 0x6e, 0x65, 0x67, 0x20, 0x32, 0x3b, 0x41, 0x6e, 0x65, 0x67, 0x20, 0x33, 0x3b, 0x41,
-0x6e, 0x65, 0x67, 0x20, 0x34, 0x3b, 0x41, 0x6e, 0x65, 0x67, 0x20, 0x35, 0x3b, 0x41, 0x6e, 0x65, 0x67, 0x20, 0x36, 0x3b,
-0x41, 0x6e, 0x65, 0x67, 0x20, 0x37, 0x41, 0x31, 0x3b, 0x41, 0x32, 0x3b, 0x41, 0x33, 0x3b, 0x41, 0x34, 0x3b, 0x41, 0x35,
-0x3b, 0x41, 0x36, 0x3b, 0x41, 0x37, 0x41d, 0x44f, 0x43c, 0x3b, 0x414, 0x430, 0x432, 0x430, 0x430, 0x3b, 0x41c, 0x44f, 0x433, 0x43c,
-0x430, 0x440, 0x3b, 0x41b, 0x445, 0x430, 0x433, 0x432, 0x430, 0x3b, 0x41f, 0x4af, 0x440, 0x44d, 0x432, 0x3b, 0x411, 0x430, 0x430, 0x441,
-0x430, 0x43d, 0x3b, 0x411, 0x44f, 0x43c, 0x431, 0x430, 0x43d, 0x44f, 0x43c, 0x3b, 0x434, 0x430, 0x432, 0x430, 0x430, 0x3b, 0x43c, 0x44f,
-0x433, 0x43c, 0x430, 0x440, 0x3b, 0x43b, 0x445, 0x430, 0x433, 0x432, 0x430, 0x3b, 0x43f, 0x4af, 0x440, 0x44d, 0x432, 0x3b, 0x431, 0x430,
-0x430, 0x441, 0x430, 0x43d, 0x3b, 0x431, 0x44f, 0x43c, 0x431, 0x430, 0x41d, 0x44f, 0x3b, 0x414, 0x430, 0x3b, 0x41c, 0x44f, 0x3b, 0x41b,
-0x445, 0x3b, 0x41f, 0x4af, 0x3b, 0x411, 0x430, 0x3b, 0x411, 0x44f, 0x64, 0x69, 0x6d, 0x61, 0x6e, 0x73, 0x3b, 0x6c, 0x69, 0x6e,
-0x64, 0x69, 0x3b, 0x6d, 0x61, 0x72, 0x64, 0x69, 0x3b, 0x6d, 0x65, 0x72, 0x6b, 0x72, 0x65, 0x64, 0x69, 0x3b, 0x7a, 0x65,
-0x64, 0x69, 0x3b, 0x76, 0x61, 0x6e, 0x64, 0x72, 0x65, 0x64, 0x69, 0x3b, 0x73, 0x61, 0x6d, 0x64, 0x69, 0x64, 0x69, 0x6d,
-0x3b, 0x6c, 0x69, 0x6e, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x6d, 0x65, 0x72, 0x3b, 0x7a, 0x65, 0x3b, 0x76, 0x61, 0x6e, 0x3b,
-0x73, 0x61, 0x6d, 0x64, 0x3b, 0x6c, 0x3b, 0x6d, 0x3b, 0x6d, 0x3b, 0x7a, 0x3b, 0x76, 0x3b, 0x73, 0x43, 0x6f, 0x6d, 0x2019,
-0x79, 0x61, 0x6b, 0x6b, 0x65, 0x3b, 0x43, 0x6f, 0x6d, 0x6c, 0x61, 0x61, 0x257, 0x69, 0x69, 0x3b, 0x43, 0x6f, 0x6d, 0x7a,
-0x79, 0x69, 0x69, 0x257, 0x69, 0x69, 0x3b, 0x43, 0x6f, 0x6d, 0x6b, 0x6f, 0x6c, 0x6c, 0x65, 0x3b, 0x43, 0x6f, 0x6d, 0x6b,
-0x61, 0x6c, 0x64, 0x1dd, 0x253, 0x6c, 0x69, 0x69, 0x3b, 0x43, 0x6f, 0x6d, 0x67, 0x61, 0x69, 0x73, 0x75, 0x75, 0x3b, 0x43,
-0x6f, 0x6d, 0x7a, 0x79, 0x65, 0x253, 0x73, 0x75, 0x75, 0x43, 0x79, 0x61, 0x3b, 0x43, 0x6c, 0x61, 0x3b, 0x43, 0x7a, 0x69,
-0x3b, 0x43, 0x6b, 0x6f, 0x3b, 0x43, 0x6b, 0x61, 0x3b, 0x43, 0x67, 0x61, 0x3b, 0x43, 0x7a, 0x65, 0x59, 0x3b, 0x4c, 0x3b,
-0x5a, 0x3b, 0x4f, 0x3b, 0x41, 0x3b, 0x47, 0x3b, 0x45, 0x53, 0x6f, 0x6e, 0x74, 0x61, 0x78, 0x74, 0x73, 0x65, 0x65, 0x73,
-0x3b, 0x4d, 0x61, 0x6e, 0x74, 0x61, 0x78, 0x74, 0x73, 0x65, 0x65, 0x73, 0x3b, 0x44, 0x65, 0x6e, 0x73, 0x74, 0x61, 0x78,
-0x74, 0x73, 0x65, 0x65, 0x73, 0x3b, 0x57, 0x75, 0x6e, 0x73, 0x74, 0x61, 0x78, 0x74, 0x73, 0x65, 0x65, 0x73, 0x3b, 0x44,
-0x6f, 0x6e, 0x64, 0x65, 0x72, 0x74, 0x61, 0x78, 0x74, 0x73, 0x65, 0x65, 0x73, 0x3b, 0x46, 0x72, 0x61, 0x69, 0x74, 0x61,
-0x78, 0x74, 0x73, 0x65, 0x65, 0x73, 0x3b, 0x53, 0x61, 0x74, 0x65, 0x72, 0x74, 0x61, 0x78, 0x74, 0x73, 0x65, 0x65, 0x73,
-0x53, 0x6f, 0x6e, 0x3b, 0x4d, 0x61, 0x3b, 0x44, 0x65, 0x3b, 0x57, 0x75, 0x3b, 0x44, 0x6f, 0x3b, 0x46, 0x72, 0x3b, 0x53,
-0x61, 0x74, 0x53, 0x3b, 0x4d, 0x3b, 0x45, 0x3b, 0x57, 0x3b, 0x44, 0x3b, 0x46, 0x3b, 0x41, 0x906, 0x907, 0x924, 0x92c, 0x93e,
-0x930, 0x3b, 0x938, 0x94b, 0x92e, 0x92c, 0x93e, 0x930, 0x3b, 0x92e, 0x919, 0x94d, 0x917, 0x932, 0x92c, 0x93e, 0x930, 0x3b, 0x92c, 0x941,
-0x927, 0x92c, 0x93e, 0x930, 0x3b, 0x92c, 0x93f, 0x939, 0x93f, 0x92c, 0x93e, 0x930, 0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930, 0x92c, 0x93e,
-0x930, 0x3b, 0x936, 0x928, 0x93f, 0x92c, 0x93e, 0x930, 0x906, 0x907, 0x924, 0x3b, 0x938, 0x94b, 0x92e, 0x3b, 0x92e, 0x919, 0x94d, 0x917,
-0x932, 0x3b, 0x92c, 0x941, 0x927, 0x3b, 0x92c, 0x93f, 0x939, 0x93f, 0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930, 0x3b, 0x936, 0x928, 0x93f,
-0x906, 0x3b, 0x938, 0x94b, 0x3b, 0x92e, 0x3b, 0x92c, 0x941, 0x3b, 0x92c, 0x93f, 0x3b, 0x936, 0x941, 0x3b, 0x936, 0x6c, 0x79, 0x25b,
-0x2bc, 0x25b, 0x301, 0x20, 0x73, 0x1e85, 0xed, 0x14b, 0x74, 0xe8, 0x3b, 0x6d, 0x76, 0x66, 0xf2, 0x20, 0x6c, 0x79, 0x25b, 0x30c,
-0x2bc, 0x3b, 0x6d, 0x62, 0x254, 0x301, 0x254, 0x6e, 0x74, 0xe8, 0x20, 0x6d, 0x76, 0x66, 0xf2, 0x20, 0x6c, 0x79, 0x25b, 0x30c,
-0x2bc, 0x3b, 0x74, 0x73, 0xe8, 0x74, 0x73, 0x25b, 0x300, 0x25b, 0x20, 0x6c, 0x79, 0x25b, 0x30c, 0x2bc, 0x3b, 0x6d, 0x62, 0x254,
-0x301, 0x254, 0x6e, 0x74, 0xe8, 0x20, 0x74, 0x73, 0x65, 0x74, 0x73, 0x25b, 0x300, 0x25b, 0x20, 0x6c, 0x79, 0x25b, 0x30c, 0x2bc,
-0x3b, 0x6d, 0x76, 0x66, 0xf2, 0x20, 0x6d, 0xe0, 0x67, 0x61, 0x20, 0x6c, 0x79, 0x25b, 0x30c, 0x2bc, 0x3b, 0x6d, 0xe0, 0x67,
-0x61, 0x20, 0x6c, 0x79, 0x25b, 0x30c, 0x2bc, 0x53, 0x254, 0x301, 0x6e, 0x64, 0x69, 0x3b, 0x4d, 0x254, 0x301, 0x6e, 0x64, 0x69,
-0x3b, 0xc1, 0x70, 0x74, 0x61, 0x20, 0x4d, 0x254, 0x301, 0x6e, 0x64, 0x69, 0x3b, 0x57, 0x25b, 0x301, 0x6e, 0x25b, 0x73, 0x25b,
-0x64, 0x25b, 0x3b, 0x54, 0x254, 0x301, 0x73, 0x25b, 0x64, 0x25b, 0x3b, 0x46, 0x25b, 0x6c, 0xe2, 0x79, 0x25b, 0x64, 0x25b, 0x3b,
-0x53, 0xe1, 0x73, 0x69, 0x64, 0x25b, 0x53, 0x254, 0x301, 0x3b, 0x4d, 0x254, 0x301, 0x3b, 0xc1, 0x4d, 0x3b, 0x57, 0x25b, 0x301,
-0x3b, 0x54, 0x254, 0x301, 0x3b, 0x46, 0x25b, 0x3b, 0x53, 0xe1, 0x53, 0x1ecd, 0x301, 0x6e, 0x64, 0xe8, 0x3b, 0x4d, 0x1ecd, 0x301,
-0x6e, 0x64, 0xe8, 0x3b, 0x54, 0x69, 0xfa, 0x7a, 0x64, 0xe8, 0x3b, 0x57, 0x1eb9, 0x301, 0x6e, 0x1eb9, 0x301, 0x7a, 0x64, 0xe8,
-0x3b, 0x54, 0x1ecd, 0x301, 0x7a, 0x64, 0xe8, 0x3b, 0x46, 0x72, 0x61, 0xed, 0x64, 0xe8, 0x3b, 0x53, 0xe1, 0x74, 0x1ecd, 0x64,
-0xe8, 0x53, 0x1ecd, 0x301, 0x6e, 0x3b, 0x4d, 0x1ecd, 0x301, 0x6e, 0x3b, 0x54, 0x69, 0xfa, 0x3b, 0x57, 0x1eb9, 0x301, 0x6e, 0x3b,
-0x54, 0x1ecd, 0x301, 0x7a, 0x3b, 0x46, 0x72, 0x61, 0xed, 0x3b, 0x53, 0xe1, 0x74, 0x73, 0x6f, 0x74, 0x6e, 0x61, 0x62, 0x65,
-0x61, 0x69, 0x76, 0x69, 0x3b, 0x76, 0x75, 0x6f, 0x73, 0x73, 0xe1, 0x72, 0x67, 0x61, 0x3b, 0x6d, 0x61, 0x14b, 0x14b, 0x65,
-0x62, 0xe1, 0x72, 0x67, 0x61, 0x3b, 0x67, 0x61, 0x73, 0x6b, 0x61, 0x76, 0x61, 0x68, 0x6b, 0x6b, 0x75, 0x3b, 0x64, 0x75,
-0x6f, 0x72, 0x61, 0x73, 0x64, 0x61, 0x74, 0x3b, 0x62, 0x65, 0x61, 0x72, 0x6a, 0x61, 0x64, 0x61, 0x74, 0x3b, 0x6c, 0xe1,
-0x76, 0x76, 0x61, 0x72, 0x64, 0x61, 0x74, 0x73, 0x6f, 0x74, 0x6e, 0x3b, 0x76, 0x75, 0x6f, 0x73, 0x3b, 0x6d, 0x61, 0x14b,
-0x3b, 0x67, 0x61, 0x73, 0x6b, 0x3b, 0x64, 0x75, 0x6f, 0x72, 0x3b, 0x62, 0x65, 0x61, 0x72, 0x3b, 0x6c, 0xe1, 0x76, 0x53,
-0x3b, 0x56, 0x3b, 0x4d, 0x3b, 0x47, 0x3b, 0x44, 0x3b, 0x42, 0x3b, 0x4c, 0x73, 0x6f, 0x74, 0x6e, 0x61, 0x62, 0x65, 0x61,
-0x69, 0x76, 0x69, 0x3b, 0x6d, 0xe1, 0x6e, 0x6e, 0x6f, 0x64, 0x61, 0x74, 0x3b, 0x64, 0x69, 0x73, 0x64, 0x61, 0x74, 0x3b,
-0x67, 0x61, 0x73, 0x6b, 0x61, 0x76, 0x61, 0x68, 0x6b, 0x6b, 0x75, 0x3b, 0x64, 0x75, 0x6f, 0x72, 0x61, 0x73, 0x74, 0x61,
-0x74, 0x3b, 0x62, 0x65, 0x61, 0x72, 0x6a, 0x61, 0x64, 0x61, 0x74, 0x3b, 0x6c, 0xe1, 0x76, 0x76, 0x6f, 0x72, 0x64, 0x61,
-0x74, 0x73, 0x6f, 0x3b, 0x6d, 0xe1, 0x3b, 0x64, 0x69, 0x3b, 0x67, 0x61, 0x3b, 0x64, 0x75, 0x3b, 0x62, 0x65, 0x3b, 0x6c,
-0xe1, 0x53, 0x3b, 0x4d, 0x3b, 0x44, 0x3b, 0x47, 0x3b, 0x44, 0x3b, 0x42, 0x3b, 0x4c, 0x53, 0x6f, 0x6e, 0x74, 0x6f, 0x3b,
-0x4d, 0x76, 0x75, 0x6c, 0x6f, 0x3b, 0x53, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x3b, 0x53, 0x69, 0x74, 0x68, 0x61, 0x74, 0x68,
-0x75, 0x3b, 0x53, 0x69, 0x6e, 0x65, 0x3b, 0x53, 0x69, 0x68, 0x6c, 0x61, 0x6e, 0x75, 0x3b, 0x4d, 0x67, 0x71, 0x69, 0x62,
-0x65, 0x6c, 0x6f, 0x53, 0x6f, 0x6e, 0x3b, 0x4d, 0x76, 0x75, 0x3b, 0x53, 0x69, 0x62, 0x3b, 0x53, 0x69, 0x74, 0x3b, 0x53,
-0x69, 0x6e, 0x3b, 0x53, 0x69, 0x68, 0x3b, 0x4d, 0x67, 0x71, 0x53, 0x3b, 0x4d, 0x3b, 0x53, 0x3b, 0x53, 0x3b, 0x53, 0x3b,
-0x53, 0x3b, 0x4d, 0x73, 0xf8, 0x6e, 0x2e, 0x3b, 0x6d, 0x61, 0x6e, 0x2e, 0x3b, 0x74, 0x69, 0x72, 0x2e, 0x3b, 0x6f, 0x6e,
-0x73, 0x2e, 0x3b, 0x74, 0x6f, 0x72, 0x2e, 0x3b, 0x66, 0x72, 0x65, 0x2e, 0x3b, 0x6c, 0xf8, 0x72, 0x2e, 0x73, 0xf8, 0x6e,
-0x64, 0x61, 0x67, 0x3b, 0x6d, 0xe5, 0x6e, 0x64, 0x61, 0x67, 0x3b, 0x74, 0x79, 0x73, 0x64, 0x61, 0x67, 0x3b, 0x6f, 0x6e,
-0x73, 0x64, 0x61, 0x67, 0x3b, 0x74, 0x6f, 0x72, 0x73, 0x64, 0x61, 0x67, 0x3b, 0x66, 0x72, 0x65, 0x64, 0x61, 0x67, 0x3b,
-0x6c, 0x61, 0x75, 0x72, 0x64, 0x61, 0x67, 0x73, 0xf8, 0x6e, 0x3b, 0x6d, 0xe5, 0x6e, 0x3b, 0x74, 0x79, 0x73, 0x3b, 0x6f,
-0x6e, 0x73, 0x3b, 0x74, 0x6f, 0x72, 0x3b, 0x66, 0x72, 0x65, 0x3b, 0x6c, 0x61, 0x75, 0x73, 0xf8, 0x2e, 0x3b, 0x6d, 0xe5,
-0x2e, 0x3b, 0x74, 0x79, 0x2e, 0x3b, 0x6f, 0x6e, 0x2e, 0x3b, 0x74, 0x6f, 0x2e, 0x3b, 0x66, 0x72, 0x2e, 0x3b, 0x6c, 0x61,
-0x2e, 0x43, 0xe4, 0x14b, 0x20, 0x6b, 0x75, 0x254, 0x74, 0x68, 0x3b, 0x4a, 0x69, 0x65, 0x63, 0x20, 0x6c, 0x61, 0x331, 0x74,
-0x3b, 0x52, 0x25b, 0x77, 0x20, 0x6c, 0xe4, 0x74, 0x6e, 0x69, 0x3b, 0x44, 0x69, 0x254, 0x331, 0x6b, 0x20, 0x6c, 0xe4, 0x74,
-0x6e, 0x69, 0x3b, 0x14a, 0x75, 0x61, 0x61, 0x6e, 0x20, 0x6c, 0xe4, 0x74, 0x6e, 0x69, 0x3b, 0x44, 0x68, 0x69, 0x65, 0x65,
-0x63, 0x20, 0x6c, 0xe4, 0x74, 0x6e, 0x69, 0x3b, 0x42, 0xe4, 0x6b, 0x25b, 0x6c, 0x20, 0x6c, 0xe4, 0x74, 0x6e, 0x69, 0x43,
-0xe4, 0x14b, 0x3b, 0x4a, 0x69, 0x65, 0x63, 0x3b, 0x52, 0x25b, 0x77, 0x3b, 0x44, 0x69, 0x254, 0x331, 0x6b, 0x3b, 0x14a, 0x75,
-0x61, 0x61, 0x6e, 0x3b, 0x44, 0x68, 0x69, 0x65, 0x65, 0x63, 0x3b, 0x42, 0xe4, 0x6b, 0x25b, 0x6c, 0x43, 0x3b, 0x4a, 0x3b,
-0x52, 0x3b, 0x44, 0x3b, 0x14a, 0x3b, 0x44, 0x3b, 0x42, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x67, 0x65, 0x3b, 0x64, 0x69, 0x6c,
-0x75, 0x6e, 0x73, 0x3b, 0x64, 0x69, 0x6d, 0x61, 0x72, 0x73, 0x3b, 0x64, 0x69, 0x6d, 0xe8, 0x63, 0x72, 0x65, 0x73, 0x3b,
-0x64, 0x69, 0x6a, 0xf2, 0x75, 0x73, 0x3b, 0x64, 0x69, 0x76, 0x65, 0x6e, 0x64, 0x72, 0x65, 0x73, 0x3b, 0x64, 0x69, 0x73,
-0x73, 0x61, 0x62, 0x74, 0x65, 0x44, 0x67, 0x3b, 0x44, 0x6c, 0x3b, 0x44, 0x6d, 0x3b, 0x44, 0x63, 0x3b, 0x44, 0x6a, 0x3b,
-0x44, 0x76, 0x3b, 0x44, 0x73, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x67, 0x65, 0x3b, 0x64, 0x65, 0x6c, 0x75, 0x6e, 0x73, 0x3b,
-0x64, 0x69, 0x6d, 0x61, 0x72, 0x73, 0x3b, 0x64, 0x69, 0x6d, 0xe8, 0x72, 0x63, 0x6c, 0x65, 0x73, 0x3b, 0x64, 0x69, 0x6a,
-0x61, 0x75, 0x73, 0x3b, 0x64, 0x69, 0x75, 0x65, 0x6e, 0x64, 0x72, 0x65, 0x73, 0x3b, 0x64, 0x69, 0x73, 0x73, 0x61, 0x62,
-0x74, 0x65, 0x64, 0x69, 0x6d, 0x3b, 0x64, 0x65, 0x6c, 0x3b, 0x64, 0x6d, 0x61, 0x3b, 0x64, 0x6d, 0xe8, 0x3b, 0x64, 0x69,
-0x6a, 0x3b, 0x64, 0x69, 0x75, 0x3b, 0x64, 0x69, 0x73, 0x44, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x58, 0x3b, 0x4a, 0x3b, 0x55,
-0x3b, 0x53, 0xb30, 0xb2c, 0xb3f, 0xb2c, 0xb3e, 0xb30, 0x3b, 0xb38, 0xb4b, 0xb2e, 0xb2c, 0xb3e, 0xb30, 0x3b, 0xb2e, 0xb19, 0xb4d, 0xb17,
-0xb33, 0xb2c, 0xb3e, 0xb30, 0x3b, 0xb2c, 0xb41, 0xb27, 0xb2c, 0xb3e, 0xb30, 0x3b, 0xb17, 0xb41, 0xb30, 0xb41, 0xb2c, 0xb3e, 0xb30, 0x3b,
-0xb36, 0xb41, 0xb15, 0xb4d, 0xb30, 0xb2c, 0xb3e, 0xb30, 0x3b, 0xb36, 0xb28, 0xb3f, 0xb2c, 0xb3e, 0xb30, 0xb30, 0xb2c, 0xb3f, 0x3b, 0xb38,
-0xb4b, 0xb2e, 0x3b, 0xb2e, 0xb19, 0xb4d, 0xb17, 0xb33, 0x3b, 0xb2c, 0xb41, 0xb27, 0x3b, 0xb17, 0xb41, 0xb30, 0xb41, 0x3b, 0xb36, 0xb41,
-0xb15, 0xb4d, 0xb30, 0x3b, 0xb36, 0xb28, 0xb3f, 0xb30, 0x3b, 0xb38, 0xb4b, 0x3b, 0xb2e, 0x3b, 0xb2c, 0xb41, 0x3b, 0xb17, 0xb41, 0x3b,
-0xb36, 0xb41, 0x3b, 0xb36, 0x44, 0x69, 0x6c, 0x62, 0x61, 0x74, 0x61, 0x3b, 0x57, 0x69, 0x69, 0x78, 0x61, 0x74, 0x61, 0x3b,
-0x51, 0x69, 0x62, 0x78, 0x61, 0x74, 0x61, 0x3b, 0x52, 0x6f, 0x6f, 0x62, 0x69, 0x69, 0x3b, 0x4b, 0x61, 0x6d, 0x69, 0x69,
-0x73, 0x61, 0x3b, 0x4a, 0x69, 0x6d, 0x61, 0x61, 0x74, 0x61, 0x3b, 0x53, 0x61, 0x6e, 0x62, 0x61, 0x74, 0x61, 0x44, 0x69,
-0x6c, 0x3b, 0x57, 0x69, 0x78, 0x3b, 0x51, 0x69, 0x62, 0x3b, 0x52, 0x6f, 0x62, 0x3b, 0x4b, 0x61, 0x6d, 0x3b, 0x4a, 0x69,
-0x6d, 0x3b, 0x53, 0x61, 0x6e, 0x44, 0x3b, 0x57, 0x3b, 0x51, 0x3b, 0x52, 0x3b, 0x4b, 0x3b, 0x4a, 0x3b, 0x53, 0x425, 0x443,
-0x44b, 0x446, 0x430, 0x443, 0x431, 0x43e, 0x43d, 0x3b, 0x41a, 0x44a, 0x443, 0x44b, 0x440, 0x438, 0x441, 0x4d5, 0x440, 0x3b, 0x414, 0x44b,
-0x446, 0x446, 0x4d5, 0x433, 0x3b, 0x4d4, 0x440, 0x442, 0x44b, 0x446, 0x446, 0x4d5, 0x433, 0x3b, 0x426, 0x44b, 0x43f, 0x43f, 0x4d5, 0x440,
-0x4d5, 0x43c, 0x3b, 0x41c, 0x430, 0x439, 0x440, 0x4d5, 0x43c, 0x431, 0x43e, 0x43d, 0x3b, 0x421, 0x430, 0x431, 0x430, 0x442, 0x445, 0x443,
-0x44b, 0x446, 0x430, 0x443, 0x431, 0x43e, 0x43d, 0x3b, 0x43a, 0x44a, 0x443, 0x44b, 0x440, 0x438, 0x441, 0x4d5, 0x440, 0x3b, 0x434, 0x44b,
-0x446, 0x446, 0x4d5, 0x433, 0x3b, 0x4d5, 0x440, 0x442, 0x44b, 0x446, 0x446, 0x4d5, 0x433, 0x3b, 0x446, 0x44b, 0x43f, 0x43f, 0x4d5, 0x440,
-0x4d5, 0x43c, 0x3b, 0x43c, 0x430, 0x439, 0x440, 0x4d5, 0x43c, 0x431, 0x43e, 0x43d, 0x3b, 0x441, 0x430, 0x431, 0x430, 0x442, 0x425, 0x446,
-0x431, 0x3b, 0x41a, 0x440, 0x441, 0x3b, 0x414, 0x446, 0x433, 0x3b, 0x4d4, 0x440, 0x442, 0x3b, 0x426, 0x43f, 0x440, 0x3b, 0x41c, 0x440,
-0x431, 0x3b, 0x421, 0x431, 0x442, 0x445, 0x446, 0x431, 0x3b, 0x43a, 0x440, 0x441, 0x3b, 0x434, 0x446, 0x433, 0x3b, 0x4d5, 0x440, 0x442,
-0x3b, 0x446, 0x43f, 0x440, 0x3b, 0x43c, 0x440, 0x431, 0x3b, 0x441, 0x431, 0x442, 0x425, 0x3b, 0x41a, 0x3b, 0x414, 0x3b, 0x4d4, 0x3b,
-0x426, 0x3b, 0x41c, 0x3b, 0x421, 0x64a, 0x648, 0x646, 0x6cd, 0x3b, 0x62f, 0x648, 0x646, 0x6cd, 0x3b, 0x62f, 0x631, 0x6d0, 0x646, 0x6cd,
-0x3b, 0x685, 0x644, 0x631, 0x646, 0x6cd, 0x3b, 0x67e, 0x64a, 0x646, 0x681, 0x646, 0x6cd, 0x3b, 0x62c, 0x645, 0x639, 0x647, 0x3b, 0x627,
-0x648, 0x646, 0x6cd, 0x6cc, 0x6a9, 0x634, 0x646, 0x628, 0x647, 0x3b, 0x62f, 0x648, 0x634, 0x646, 0x628, 0x647, 0x3b, 0x633, 0x647, 0x200c,
-0x634, 0x646, 0x628, 0x647, 0x3b, 0x686, 0x647, 0x627, 0x631, 0x634, 0x646, 0x628, 0x647, 0x3b, 0x67e, 0x646, 0x62c, 0x634, 0x646, 0x628,
-0x647, 0x3b, 0x62c, 0x645, 0x639, 0x647, 0x3b, 0x634, 0x646, 0x628, 0x647, 0x6cc, 0x3b, 0x62f, 0x3b, 0x633, 0x3b, 0x686, 0x3b, 0x67e,
-0x3b, 0x62c, 0x3b, 0x634, 0x6e, 0x69, 0x65, 0x64, 0x7a, 0x69, 0x65, 0x6c, 0x61, 0x3b, 0x70, 0x6f, 0x6e, 0x69, 0x65, 0x64,
-0x7a, 0x69, 0x61, 0x142, 0x65, 0x6b, 0x3b, 0x77, 0x74, 0x6f, 0x72, 0x65, 0x6b, 0x3b, 0x15b, 0x72, 0x6f, 0x64, 0x61, 0x3b,
-0x63, 0x7a, 0x77, 0x61, 0x72, 0x74, 0x65, 0x6b, 0x3b, 0x70, 0x69, 0x105, 0x74, 0x65, 0x6b, 0x3b, 0x73, 0x6f, 0x62, 0x6f,
-0x74, 0x61, 0x6e, 0x69, 0x65, 0x64, 0x7a, 0x2e, 0x3b, 0x70, 0x6f, 0x6e, 0x2e, 0x3b, 0x77, 0x74, 0x2e, 0x3b, 0x15b, 0x72,
-0x2e, 0x3b, 0x63, 0x7a, 0x77, 0x2e, 0x3b, 0x70, 0x74, 0x2e, 0x3b, 0x73, 0x6f, 0x62, 0x2e, 0x4e, 0x3b, 0x50, 0x3b, 0x57,
-0x3b, 0x15a, 0x3b, 0x43, 0x3b, 0x50, 0x3b, 0x53, 0x6e, 0x3b, 0x70, 0x3b, 0x77, 0x3b, 0x15b, 0x3b, 0x63, 0x3b, 0x70, 0x3b,
-0x73, 0x64, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x6f, 0x3b, 0x73, 0x65, 0x67, 0x75, 0x6e, 0x64, 0x61, 0x2d, 0x66, 0x65, 0x69,
-0x72, 0x61, 0x3b, 0x74, 0x65, 0x72, 0xe7, 0x61, 0x2d, 0x66, 0x65, 0x69, 0x72, 0x61, 0x3b, 0x71, 0x75, 0x61, 0x72, 0x74,
-0x61, 0x2d, 0x66, 0x65, 0x69, 0x72, 0x61, 0x3b, 0x71, 0x75, 0x69, 0x6e, 0x74, 0x61, 0x2d, 0x66, 0x65, 0x69, 0x72, 0x61,
-0x3b, 0x73, 0x65, 0x78, 0x74, 0x61, 0x2d, 0x66, 0x65, 0x69, 0x72, 0x61, 0x3b, 0x73, 0xe1, 0x62, 0x61, 0x64, 0x6f, 0x64,
-0x6f, 0x6d, 0x2e, 0x3b, 0x73, 0x65, 0x67, 0x2e, 0x3b, 0x74, 0x65, 0x72, 0x2e, 0x3b, 0x71, 0x75, 0x61, 0x2e, 0x3b, 0x71,
-0x75, 0x69, 0x2e, 0x3b, 0x73, 0x65, 0x78, 0x2e, 0x3b, 0x73, 0xe1, 0x62, 0x2e, 0x44, 0x3b, 0x53, 0x3b, 0x54, 0x3b, 0x51,
-0x3b, 0x51, 0x3b, 0x53, 0x3b, 0x53, 0x64, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x6f, 0x3b, 0x73, 0x65, 0x67, 0x75, 0x6e, 0x64,
-0x61, 0x3b, 0x74, 0x65, 0x72, 0xe7, 0x61, 0x3b, 0x71, 0x75, 0x61, 0x72, 0x74, 0x61, 0x3b, 0x71, 0x75, 0x69, 0x6e, 0x74,
-0x61, 0x3b, 0x73, 0x65, 0x78, 0x74, 0x61, 0x3b, 0x73, 0xe1, 0x62, 0x61, 0x64, 0x6f, 0xa10, 0xa24, 0xa35, 0xa3e, 0xa30, 0x3b,
-0xa38, 0xa4b, 0xa2e, 0xa35, 0xa3e, 0xa30, 0x3b, 0xa2e, 0xa70, 0xa17, 0xa32, 0xa35, 0xa3e, 0xa30, 0x3b, 0xa2c, 0xa41, 0xa71, 0xa27, 0xa35,
-0xa3e, 0xa30, 0x3b, 0xa35, 0xa40, 0xa30, 0xa35, 0xa3e, 0xa30, 0x3b, 0xa38, 0xa3c, 0xa41, 0xa71, 0xa15, 0xa30, 0xa35, 0xa3e, 0xa30, 0x3b,
-0xa38, 0xa3c, 0xa28, 0xa3f, 0xa71, 0xa1a, 0xa30, 0xa35, 0xa3e, 0xa30, 0xa10, 0xa24, 0x3b, 0xa38, 0xa4b, 0xa2e, 0x3b, 0xa2e, 0xa70, 0xa17,
-0xa32, 0x3b, 0xa2c, 0xa41, 0xa71, 0xa27, 0x3b, 0xa35, 0xa40, 0xa30, 0x3b, 0xa38, 0xa3c, 0xa41, 0xa71, 0xa15, 0xa30, 0x3b, 0xa38, 0xa3c,
-0xa28, 0xa3f, 0xa71, 0xa1a, 0xa30, 0xa10, 0x3b, 0xa38, 0xa4b, 0x3b, 0xa2e, 0xa70, 0x3b, 0xa2c, 0xa41, 0xa71, 0x3b, 0xa35, 0xa40, 0x3b,
-0xa38, 0xa3c, 0xa41, 0xa71, 0x3b, 0xa38, 0xa3c, 0x627, 0x62a, 0x648, 0x627, 0x631, 0x3b, 0x67e, 0x6cc, 0x631, 0x3b, 0x645, 0x646, 0x6af,
-0x644, 0x3b, 0x628, 0x64f, 0x62f, 0x6be, 0x3b, 0x62c, 0x645, 0x639, 0x631, 0x627, 0x62a, 0x3b, 0x62c, 0x645, 0x639, 0x6c1, 0x3b, 0x6c1,
-0x641, 0x62a, 0x6c1, 0x44, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x6f, 0x3b, 0x4c, 0x75, 0x6e, 0x65, 0x73, 0x3b, 0x4d, 0x61, 0x72,
-0x74, 0x65, 0x73, 0x3b, 0x4d, 0x69, 0xe9, 0x72, 0x63, 0x6f, 0x6c, 0x65, 0x73, 0x3b, 0x4a, 0x75, 0x65, 0x76, 0x65, 0x73,
-0x3b, 0x56, 0x69, 0x65, 0x72, 0x6e, 0x65, 0x73, 0x3b, 0x53, 0xe1, 0x62, 0x61, 0x64, 0x6f, 0x44, 0x6f, 0x6d, 0x3b, 0x4c,
-0x75, 0x6e, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x4d, 0x69, 0xe9, 0x3b, 0x4a, 0x75, 0x65, 0x3b, 0x56, 0x69, 0x65, 0x3b, 0x53,
-0x61, 0x62, 0x44, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x58, 0x3b, 0x4a, 0x3b, 0x56, 0x3b, 0x53, 0x64, 0x75, 0x6d, 0x69, 0x6e,
-0x69, 0x63, 0x103, 0x3b, 0x6c, 0x75, 0x6e, 0x69, 0x3b, 0x6d, 0x61, 0x72, 0x21b, 0x69, 0x3b, 0x6d, 0x69, 0x65, 0x72, 0x63,
-0x75, 0x72, 0x69, 0x3b, 0x6a, 0x6f, 0x69, 0x3b, 0x76, 0x69, 0x6e, 0x65, 0x72, 0x69, 0x3b, 0x73, 0xe2, 0x6d, 0x62, 0x103,
-0x74, 0x103, 0x64, 0x75, 0x6d, 0x2e, 0x3b, 0x6c, 0x75, 0x6e, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x6d, 0x69, 0x65,
-0x2e, 0x3b, 0x6a, 0x6f, 0x69, 0x3b, 0x76, 0x69, 0x6e, 0x2e, 0x3b, 0x73, 0xe2, 0x6d, 0x2e, 0x44, 0x75, 0x6d, 0x3b, 0x4c,
-0x75, 0x6e, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x4d, 0x69, 0x65, 0x3b, 0x4a, 0x6f, 0x69, 0x3b, 0x56, 0x69, 0x6e, 0x3b, 0x53,
-0xe2, 0x6d, 0x44, 0x3b, 0x4c, 0x3b, 0x4d, 0x61, 0x3b, 0x4d, 0x69, 0x3b, 0x4a, 0x3b, 0x56, 0x3b, 0x53, 0x64, 0x75, 0x6d,
-0x65, 0x6e, 0x67, 0x69, 0x61, 0x3b, 0x67, 0x6c, 0x69, 0x6e, 0x64, 0x65, 0x73, 0x64, 0x69, 0x3b, 0x6d, 0x61, 0x72, 0x64,
-0x69, 0x3b, 0x6d, 0x65, 0x73, 0x65, 0x6d, 0x6e, 0x61, 0x3b, 0x67, 0x69, 0x65, 0x76, 0x67, 0x69, 0x61, 0x3b, 0x76, 0x65,
-0x6e, 0x64, 0x65, 0x72, 0x64, 0x69, 0x3b, 0x73, 0x6f, 0x6e, 0x64, 0x61, 0x64, 0x75, 0x3b, 0x67, 0x6c, 0x69, 0x3b, 0x6d,
-0x61, 0x3b, 0x6d, 0x65, 0x3b, 0x67, 0x69, 0x65, 0x3b, 0x76, 0x65, 0x3b, 0x73, 0x6f, 0x44, 0x3b, 0x47, 0x3b, 0x4d, 0x3b,
-0x4d, 0x3b, 0x47, 0x3b, 0x56, 0x3b, 0x53, 0x49, 0x6a, 0x75, 0x6d, 0x61, 0x70, 0x69, 0x6c, 0x69, 0x3b, 0x49, 0x6a, 0x75,
-0x6d, 0x61, 0x74, 0x61, 0x74, 0x75, 0x3b, 0x49, 0x6a, 0x75, 0x6d, 0x61, 0x6e, 0x6e, 0x65, 0x3b, 0x49, 0x6a, 0x75, 0x6d,
-0x61, 0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x41, 0x6c, 0x68, 0x61, 0x6d, 0x69, 0x73, 0x69, 0x3b, 0x49, 0x6a, 0x75, 0x6d, 0x61,
-0x61, 0x3b, 0x49, 0x6a, 0x75, 0x6d, 0x61, 0x6d, 0x6f, 0x73, 0x69, 0x49, 0x6a, 0x70, 0x3b, 0x49, 0x6a, 0x74, 0x3b, 0x49,
-0x6a, 0x6e, 0x3b, 0x49, 0x6a, 0x74, 0x6e, 0x3b, 0x41, 0x6c, 0x68, 0x3b, 0x49, 0x6a, 0x75, 0x3b, 0x49, 0x6a, 0x6d, 0x4b,
-0x75, 0x20, 0x77, 0x2019, 0x69, 0x6e, 0x64, 0x77, 0x69, 0x3b, 0x4b, 0x75, 0x20, 0x77, 0x61, 0x20, 0x6d, 0x62, 0x65, 0x72,
-0x65, 0x3b, 0x4b, 0x75, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x62, 0x69, 0x72, 0x69, 0x3b, 0x4b, 0x75, 0x20, 0x77, 0x61,
-0x20, 0x67, 0x61, 0x74, 0x61, 0x74, 0x75, 0x3b, 0x4b, 0x75, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x6e, 0x65, 0x3b, 0x4b,
-0x75, 0x20, 0x77, 0x61, 0x20, 0x67, 0x61, 0x74, 0x61, 0x6e, 0x75, 0x3b, 0x4b, 0x75, 0x20, 0x77, 0x61, 0x20, 0x67, 0x61,
-0x74, 0x61, 0x6e, 0x64, 0x61, 0x74, 0x75, 0x63, 0x75, 0x2e, 0x3b, 0x6d, 0x62, 0x65, 0x2e, 0x3b, 0x6b, 0x61, 0x62, 0x2e,
-0x3b, 0x67, 0x74, 0x75, 0x2e, 0x3b, 0x6b, 0x61, 0x6e, 0x2e, 0x3b, 0x67, 0x6e, 0x75, 0x2e, 0x3b, 0x67, 0x6e, 0x64, 0x2e,
-0x432, 0x43e, 0x441, 0x43a, 0x440, 0x435, 0x441, 0x435, 0x43d, 0x44c, 0x435, 0x3b, 0x43f, 0x43e, 0x43d, 0x435, 0x434, 0x435, 0x43b, 0x44c,
-0x43d, 0x438, 0x43a, 0x3b, 0x432, 0x442, 0x43e, 0x440, 0x43d, 0x438, 0x43a, 0x3b, 0x441, 0x440, 0x435, 0x434, 0x430, 0x3b, 0x447, 0x435,
-0x442, 0x432, 0x435, 0x440, 0x433, 0x3b, 0x43f, 0x44f, 0x442, 0x43d, 0x438, 0x446, 0x430, 0x3b, 0x441, 0x443, 0x431, 0x431, 0x43e, 0x442,
-0x430, 0x432, 0x441, 0x3b, 0x43f, 0x43d, 0x3b, 0x432, 0x442, 0x3b, 0x441, 0x440, 0x3b, 0x447, 0x442, 0x3b, 0x43f, 0x442, 0x3b, 0x441,
-0x431, 0x412, 0x3b, 0x41f, 0x3b, 0x412, 0x3b, 0x421, 0x3b, 0x427, 0x3b, 0x41f, 0x3b, 0x421, 0x431, 0x430, 0x441, 0x43a, 0x44b, 0x4bb,
-0x44b, 0x430, 0x43d, 0x43d, 0x44c, 0x430, 0x3b, 0x431, 0x44d, 0x43d, 0x438, 0x434, 0x438, 0x44d, 0x43d, 0x43d, 0x44c, 0x438, 0x43a, 0x3b,
-0x43e, 0x43f, 0x442, 0x443, 0x43e, 0x440, 0x443, 0x43d, 0x43d, 0x44c, 0x443, 0x43a, 0x3b, 0x441, 0x44d, 0x440, 0x44d, 0x434, 0x44d, 0x3b,
-0x447, 0x44d, 0x43f, 0x43f, 0x438, 0x44d, 0x440, 0x3b, 0x411, 0x44d, 0x44d, 0x442, 0x438, 0x4a5, 0x441, 0x44d, 0x3b, 0x441, 0x443, 0x431,
-0x443, 0x43e, 0x442, 0x430, 0x431, 0x441, 0x3b, 0x431, 0x43d, 0x3b, 0x43e, 0x43f, 0x3b, 0x441, 0x44d, 0x3b, 0x447, 0x43f, 0x3b, 0x431,
-0x44d, 0x3b, 0x441, 0x431, 0x411, 0x3b, 0x411, 0x3b, 0x41e, 0x3b, 0x421, 0x3b, 0x427, 0x3b, 0x411, 0x3b, 0x421, 0x4d, 0x64, 0x65,
-0x72, 0x6f, 0x74, 0x20, 0x65, 0x65, 0x20, 0x61, 0x72, 0x65, 0x3b, 0x4d, 0x64, 0x65, 0x72, 0x6f, 0x74, 0x20, 0x65, 0x65,
-0x20, 0x6b, 0x75, 0x6e, 0x69, 0x3b, 0x4d, 0x64, 0x65, 0x72, 0x6f, 0x74, 0x20, 0x65, 0x65, 0x20, 0x6f, 0x6e, 0x67, 0x2019,
-0x77, 0x61, 0x6e, 0x3b, 0x4d, 0x64, 0x65, 0x72, 0x6f, 0x74, 0x20, 0x65, 0x65, 0x20, 0x69, 0x6e, 0x65, 0x74, 0x3b, 0x4d,
-0x64, 0x65, 0x72, 0x6f, 0x74, 0x20, 0x65, 0x65, 0x20, 0x69, 0x6c, 0x65, 0x3b, 0x4d, 0x64, 0x65, 0x72, 0x6f, 0x74, 0x20,
-0x65, 0x65, 0x20, 0x73, 0x61, 0x70, 0x61, 0x3b, 0x4d, 0x64, 0x65, 0x72, 0x6f, 0x74, 0x20, 0x65, 0x65, 0x20, 0x6b, 0x77,
-0x65, 0x41, 0x72, 0x65, 0x3b, 0x4b, 0x75, 0x6e, 0x3b, 0x4f, 0x6e, 0x67, 0x3b, 0x49, 0x6e, 0x65, 0x3b, 0x49, 0x6c, 0x65,
-0x3b, 0x53, 0x61, 0x70, 0x3b, 0x4b, 0x77, 0x65, 0x41, 0x3b, 0x4b, 0x3b, 0x4f, 0x3b, 0x49, 0x3b, 0x49, 0x3b, 0x53, 0x3b,
-0x4b, 0x42, 0x69, 0x6b, 0x75, 0x61, 0x2d, 0xf4, 0x6b, 0x6f, 0x3b, 0x42, 0xef, 0x6b, 0x75, 0x61, 0x2d, 0xfb, 0x73, 0x65,
-0x3b, 0x42, 0xef, 0x6b, 0x75, 0x61, 0x2d, 0x70, 0x74, 0xe2, 0x3b, 0x42, 0xef, 0x6b, 0x75, 0x61, 0x2d, 0x75, 0x73, 0xef,
-0xf6, 0x3b, 0x42, 0xef, 0x6b, 0x75, 0x61, 0x2d, 0x6f, 0x6b, 0xfc, 0x3b, 0x4c, 0xe2, 0x70, 0xf4, 0x73, 0xf6, 0x3b, 0x4c,
-0xe2, 0x79, 0x65, 0x6e, 0x67, 0x61, 0x42, 0x6b, 0x31, 0x3b, 0x42, 0x6b, 0x32, 0x3b, 0x42, 0x6b, 0x33, 0x3b, 0x42, 0x6b,
-0x34, 0x3b, 0x42, 0x6b, 0x35, 0x3b, 0x4c, 0xe2, 0x70, 0x3b, 0x4c, 0xe2, 0x79, 0x4b, 0x3b, 0x53, 0x3b, 0x54, 0x3b, 0x53,
-0x3b, 0x4b, 0x3b, 0x50, 0x3b, 0x59, 0x4d, 0x75, 0x6c, 0x75, 0x6e, 0x67, 0x75, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0x61,
-0x74, 0x75, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x6e, 0x6e, 0x65, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0x61, 0x6e, 0x6f, 0x3b,
-0x41, 0x6c, 0x61, 0x68, 0x61, 0x6d, 0x69, 0x73, 0x69, 0x3b, 0x49, 0x6a, 0x75, 0x6d, 0x61, 0x61, 0x3b, 0x4a, 0x75, 0x6d,
-0x61, 0x6d, 0x6f, 0x73, 0x69, 0x4d, 0x75, 0x6c, 0x3b, 0x4a, 0x74, 0x74, 0x3b, 0x4a, 0x6e, 0x6e, 0x3b, 0x4a, 0x74, 0x6e,
-0x3b, 0x41, 0x6c, 0x68, 0x3b, 0x49, 0x6a, 0x75, 0x3b, 0x4a, 0x6d, 0x6f, 0x4d, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b,
-0x41, 0x3b, 0x49, 0x3b, 0x4a, 0x930, 0x935, 0x93f, 0x935, 0x93e, 0x938, 0x930, 0x903, 0x3b, 0x938, 0x94b, 0x92e, 0x935, 0x93e, 0x938,
-0x930, 0x903, 0x3b, 0x92e, 0x902, 0x917, 0x932, 0x935, 0x93e, 0x938, 0x930, 0x903, 0x3b, 0x92c, 0x941, 0x927, 0x935, 0x93e, 0x938, 0x930,
-0x903, 0x3b, 0x917, 0x941, 0x930, 0x941, 0x935, 0x93e, 0x938, 0x930, 0x3a, 0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930, 0x935, 0x93e, 0x938,
-0x930, 0x903, 0x3b, 0x936, 0x928, 0x93f, 0x935, 0x93e, 0x938, 0x930, 0x903, 0x1c65, 0x1c64, 0x1c78, 0x1c5c, 0x1c6e, 0x3b, 0x1c5a, 0x1c5b, 0x1c6e,
-0x3b, 0x1c75, 0x1c5f, 0x1c5e, 0x1c6e, 0x3b, 0x1c65, 0x1c5f, 0x1c79, 0x1c5c, 0x1c69, 0x1c71, 0x3b, 0x1c65, 0x1c5f, 0x1c79, 0x1c68, 0x1c6b, 0x1c64, 0x3b,
-0x1c61, 0x1c5f, 0x1c79, 0x1c68, 0x1c69, 0x1c62, 0x3b, 0x1c67, 0x1c69, 0x1c66, 0x1c69, 0x1c62, 0x1c65, 0x1c64, 0x1c78, 0x3b, 0x1c5a, 0x1c5b, 0x3b, 0x1c75,
-0x1c5f, 0x3b, 0x1c65, 0x1c5f, 0x1c79, 0x3b, 0x1c65, 0x1c5f, 0x1c79, 0x1c68, 0x3b, 0x1c61, 0x1c5f, 0x1c79, 0x3b, 0x1c67, 0x1c69, 0x1c65, 0x3b, 0x1c5a,
-0x3b, 0x1c75, 0x3b, 0x1c65, 0x3b, 0x1c65, 0x3b, 0x1c61, 0x3b, 0x1c67, 0x64, 0x6f, 0x6d, 0xec, 0x6e, 0x69, 0x67, 0x61, 0x3b, 0x6c,
-0x75, 0x6e, 0x69, 0x73, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x69, 0x73, 0x3b, 0x6d, 0xe8, 0x72, 0x63, 0x75, 0x72, 0x69, 0x73,
-0x3b, 0x67, 0x69, 0xf2, 0x62, 0x69, 0x61, 0x3b, 0x63, 0x68, 0x65, 0x6e, 0xe0, 0x62, 0x75, 0x72, 0x61, 0x3b, 0x73, 0xe0,
-0x62, 0x61, 0x64, 0x75, 0x64, 0x6f, 0x6d, 0x3b, 0x6c, 0x75, 0x6e, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x6d, 0xe8, 0x72, 0x3b,
-0x67, 0x69, 0xf2, 0x3b, 0x63, 0x68, 0x65, 0x3b, 0x73, 0xe0, 0x62, 0x44, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x47,
-0x3b, 0x43, 0x3b, 0x53, 0x44, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x75, 0x3b, 0x43, 0x68, 0x69, 0x70, 0x6f, 0x73, 0x69, 0x3b,
-0x43, 0x68, 0x69, 0x70, 0x69, 0x72, 0x69, 0x3b, 0x43, 0x68, 0x69, 0x74, 0x61, 0x74, 0x75, 0x3b, 0x43, 0x68, 0x69, 0x6e,
-0x61, 0x69, 0x3b, 0x43, 0x68, 0x69, 0x73, 0x68, 0x61, 0x6e, 0x75, 0x3b, 0x53, 0x61, 0x62, 0x75, 0x64, 0x75, 0x44, 0x69,
-0x6d, 0x3b, 0x50, 0x6f, 0x73, 0x3b, 0x50, 0x69, 0x72, 0x3b, 0x54, 0x61, 0x74, 0x3b, 0x4e, 0x61, 0x69, 0x3b, 0x53, 0x68,
-0x61, 0x3b, 0x53, 0x61, 0x62, 0x44, 0x3b, 0x50, 0x3b, 0x43, 0x3b, 0x54, 0x3b, 0x4e, 0x3b, 0x53, 0x3b, 0x53, 0x43d, 0x435,
-0x434, 0x435, 0x459, 0x430, 0x3b, 0x43f, 0x43e, 0x43d, 0x435, 0x434, 0x435, 0x459, 0x430, 0x43a, 0x3b, 0x443, 0x442, 0x43e, 0x440, 0x430,
-0x43a, 0x3b, 0x441, 0x440, 0x435, 0x434, 0x430, 0x3b, 0x447, 0x435, 0x442, 0x432, 0x440, 0x442, 0x430, 0x43a, 0x3b, 0x43f, 0x435, 0x442,
-0x430, 0x43a, 0x3b, 0x441, 0x443, 0x431, 0x43e, 0x442, 0x430, 0x43d, 0x435, 0x434, 0x3b, 0x43f, 0x43e, 0x43d, 0x3b, 0x443, 0x442, 0x43e,
-0x3b, 0x441, 0x440, 0x435, 0x3b, 0x447, 0x435, 0x442, 0x3b, 0x43f, 0x435, 0x442, 0x3b, 0x441, 0x443, 0x431, 0x43d, 0x435, 0x434, 0x458,
-0x435, 0x459, 0x430, 0x3b, 0x43f, 0x43e, 0x43d, 0x435, 0x434, 0x435, 0x459, 0x430, 0x43a, 0x3b, 0x443, 0x442, 0x43e, 0x440, 0x430, 0x43a,
-0x3b, 0x441, 0x440, 0x438, 0x458, 0x435, 0x434, 0x430, 0x3b, 0x447, 0x435, 0x442, 0x432, 0x440, 0x442, 0x430, 0x43a, 0x3b, 0x43f, 0x435,
-0x442, 0x430, 0x43a, 0x3b, 0x441, 0x443, 0x431, 0x43e, 0x442, 0x430, 0x6e, 0x65, 0x64, 0x65, 0x6c, 0x6a, 0x61, 0x3b, 0x70, 0x6f,
-0x6e, 0x65, 0x64, 0x65, 0x6c, 0x6a, 0x61, 0x6b, 0x3b, 0x75, 0x74, 0x6f, 0x72, 0x61, 0x6b, 0x3b, 0x73, 0x72, 0x65, 0x64,
-0x61, 0x3b, 0x10d, 0x65, 0x74, 0x76, 0x72, 0x74, 0x61, 0x6b, 0x3b, 0x70, 0x65, 0x74, 0x61, 0x6b, 0x3b, 0x73, 0x75, 0x62,
-0x6f, 0x74, 0x61, 0x6e, 0x65, 0x64, 0x3b, 0x70, 0x6f, 0x6e, 0x3b, 0x75, 0x74, 0x6f, 0x3b, 0x73, 0x72, 0x65, 0x3b, 0x10d,
-0x65, 0x74, 0x3b, 0x70, 0x65, 0x74, 0x3b, 0x73, 0x75, 0x62, 0x6e, 0x65, 0x64, 0x6a, 0x65, 0x6c, 0x6a, 0x61, 0x3b, 0x70,
-0x6f, 0x6e, 0x65, 0x64, 0x65, 0x6c, 0x6a, 0x61, 0x6b, 0x3b, 0x75, 0x74, 0x6f, 0x72, 0x61, 0x6b, 0x3b, 0x73, 0x72, 0x69,
-0x6a, 0x65, 0x64, 0x61, 0x3b, 0x10d, 0x65, 0x74, 0x76, 0x72, 0x74, 0x61, 0x6b, 0x3b, 0x70, 0x65, 0x74, 0x61, 0x6b, 0x3b,
-0x73, 0x75, 0x62, 0x6f, 0x74, 0x61, 0x4a, 0x75, 0x6d, 0x61, 0x61, 0x70, 0x69, 0x69, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x61,
-0x74, 0x61, 0x74, 0x75, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x61, 0x6e, 0x65, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x61, 0x74, 0x61,
-0x6e, 0x6f, 0x3b, 0x41, 0x6c, 0x68, 0x61, 0x6d, 0x69, 0x73, 0x69, 0x3b, 0x49, 0x6a, 0x75, 0x6d, 0x61, 0x61, 0x3b, 0x4a,
-0x75, 0x6d, 0x61, 0x61, 0x6d, 0x6f, 0x73, 0x69, 0x4a, 0x70, 0x69, 0x3b, 0x4a, 0x74, 0x74, 0x3b, 0x4a, 0x6d, 0x6e, 0x3b,
-0x4a, 0x74, 0x6e, 0x3b, 0x41, 0x6c, 0x68, 0x3b, 0x49, 0x6a, 0x75, 0x3b, 0x4a, 0x6d, 0x6f, 0x32, 0x3b, 0x33, 0x3b, 0x34,
-0x3b, 0x35, 0x3b, 0x41, 0x3b, 0x49, 0x3b, 0x31, 0x53, 0x76, 0x6f, 0x6e, 0x64, 0x6f, 0x3b, 0x4d, 0x75, 0x76, 0x68, 0x75,
-0x72, 0x6f, 0x3b, 0x43, 0x68, 0x69, 0x70, 0x69, 0x72, 0x69, 0x3b, 0x43, 0x68, 0x69, 0x74, 0x61, 0x74, 0x75, 0x3b, 0x43,
-0x68, 0x69, 0x6e, 0x61, 0x3b, 0x43, 0x68, 0x69, 0x73, 0x68, 0x61, 0x6e, 0x75, 0x3b, 0x4d, 0x75, 0x67, 0x6f, 0x76, 0x65,
-0x72, 0x61, 0x53, 0x76, 0x6f, 0x3b, 0x4d, 0x75, 0x76, 0x3b, 0x43, 0x68, 0x70, 0x3b, 0x43, 0x68, 0x74, 0x3b, 0x43, 0x68,
-0x6e, 0x3b, 0x43, 0x68, 0x73, 0x3b, 0x4d, 0x75, 0x67, 0x53, 0x3b, 0x4d, 0x3b, 0x43, 0x3b, 0x43, 0x3b, 0x43, 0x3b, 0x43,
-0x3b, 0x4d, 0xa46d, 0xa18f, 0xa44d, 0x3b, 0xa18f, 0xa282, 0xa2cd, 0x3b, 0xa18f, 0xa282, 0xa44d, 0x3b, 0xa18f, 0xa282, 0xa315, 0x3b, 0xa18f, 0xa282,
-0xa1d6, 0x3b, 0xa18f, 0xa282, 0xa26c, 0x3b, 0xa18f, 0xa282, 0xa0d8, 0xa46d, 0xa18f, 0x3b, 0xa18f, 0xa2cd, 0x3b, 0xa18f, 0xa44d, 0x3b, 0xa18f, 0xa315,
-0x3b, 0xa18f, 0xa1d6, 0x3b, 0xa18f, 0xa26c, 0x3b, 0xa18f, 0xa0d8, 0xa18f, 0x3b, 0xa2cd, 0x3b, 0xa44d, 0x3b, 0xa315, 0x3b, 0xa1d6, 0x3b, 0xa26c,
-0x3b, 0xa0d8, 0x622, 0x686, 0x631, 0x3b, 0x633, 0x648, 0x645, 0x631, 0x3b, 0x627, 0x6b1, 0x627, 0x631, 0x648, 0x3b, 0x627, 0x631, 0x628,
-0x639, 0x3b, 0x62e, 0x645, 0x64a, 0x633, 0x3b, 0x62c, 0x645, 0x639, 0x648, 0x3b, 0x687, 0x646, 0x687, 0x631, 0x622, 0x686, 0x631, 0x3b,
-0x633, 0x648, 0x3b, 0x627, 0x6b1, 0x627, 0x631, 0x648, 0x3b, 0x627, 0x631, 0x628, 0x639, 0x3b, 0x62e, 0x645, 0x3b, 0x62c, 0x645, 0x639,
-0x648, 0x3b, 0x687, 0x646, 0x687, 0x631, 0x906, 0x930, 0x94d, 0x924, 0x3b, 0x938, 0x942, 0x3b, 0x92e, 0x902, 0x3b, 0x92c, 0x941, 0x952,
-0x927, 0x3b, 0x935, 0x93f, 0x938, 0x3b, 0x91c, 0x941, 0x92e, 0x3b, 0x91b, 0x902, 0x91b, 0x906, 0x930, 0x94d, 0x924, 0x935, 0x93e, 0x930,
-0x3b, 0x938, 0x942, 0x92e, 0x930, 0x3b, 0x92e, 0x902, 0x917, 0x932, 0x941, 0x3b, 0x92c, 0x941, 0x952, 0x927, 0x930, 0x3b, 0x935, 0x93f,
-0x938, 0x94d, 0x92a, 0x924, 0x3b, 0x91c, 0x941, 0x92e, 0x94b, 0x3b, 0x91b, 0x902, 0x91b, 0x930, 0x906, 0x3b, 0x938, 0x942, 0x3b, 0x92e,
-0x902, 0x3b, 0x92c, 0x941, 0x927, 0x3b, 0x935, 0x93f, 0x938, 0x3b, 0x91c, 0x941, 0x3b, 0x91b, 0x902, 0x91b, 0x906, 0x930, 0x94d, 0x924,
-0x3b, 0x938, 0x942, 0x3b, 0x92e, 0x902, 0x917, 0x3b, 0x92c, 0x941, 0x952, 0x927, 0x3b, 0x935, 0x93f, 0x938, 0x3b, 0x91c, 0x941, 0x92e,
-0x3b, 0x91b, 0x902, 0x91b, 0x906, 0x3b, 0x938, 0x942, 0x3b, 0x92e, 0x902, 0x3b, 0x92c, 0x941, 0x952, 0x3b, 0x935, 0x93f, 0x3b, 0x91c,
-0x941, 0x3b, 0x91b, 0x902, 0xd89, 0xdbb, 0xdd2, 0xdaf, 0xdcf, 0x3b, 0xdc3, 0xdb3, 0xdd4, 0xdaf, 0xdcf, 0x3b, 0xd85, 0xd9f, 0xdc4, 0xdbb,
-0xdd4, 0xdc0, 0xdcf, 0xdaf, 0xdcf, 0x3b, 0xdb6, 0xdaf, 0xdcf, 0xdaf, 0xdcf, 0x3b, 0xdb6, 0xdca, 0x200d, 0xdbb, 0xdc4, 0xdc3, 0xdca, 0xdb4,
-0xdad, 0xdd2, 0xdb1, 0xdca, 0xdaf, 0xdcf, 0x3b, 0xdc3, 0xdd2, 0xd9a, 0xdd4, 0xdbb, 0xdcf, 0xdaf, 0xdcf, 0x3b, 0xdc3, 0xdd9, 0xdb1, 0xdc3,
-0xdd4, 0xdbb, 0xdcf, 0xdaf, 0xdcf, 0xd89, 0xdbb, 0xdd2, 0xdaf, 0xdcf, 0x3b, 0xdc3, 0xdb3, 0xdd4, 0xdaf, 0xdcf, 0x3b, 0xd85, 0xd9f, 0xdc4,
-0x3b, 0xdb6, 0xdaf, 0xdcf, 0xdaf, 0xdcf, 0x3b, 0xdb6, 0xdca, 0x200d, 0xdbb, 0xdc4, 0xdc3, 0xdca, 0x3b, 0xdc3, 0xdd2, 0xd9a, 0xdd4, 0x3b,
-0xdc3, 0xdd9, 0xdb1, 0xd89, 0x3b, 0xdc3, 0x3b, 0xd85, 0x3b, 0xdb6, 0x3b, 0xdb6, 0xdca, 0x200d, 0xdbb, 0x3b, 0xdc3, 0xdd2, 0x3b, 0xdc3,
-0xdd9, 0x6e, 0x65, 0x64, 0x65, 0x13e, 0x61, 0x3b, 0x70, 0x6f, 0x6e, 0x64, 0x65, 0x6c, 0x6f, 0x6b, 0x3b, 0x75, 0x74, 0x6f,
-0x72, 0x6f, 0x6b, 0x3b, 0x73, 0x74, 0x72, 0x65, 0x64, 0x61, 0x3b, 0x161, 0x74, 0x76, 0x72, 0x74, 0x6f, 0x6b, 0x3b, 0x70,
-0x69, 0x61, 0x74, 0x6f, 0x6b, 0x3b, 0x73, 0x6f, 0x62, 0x6f, 0x74, 0x61, 0x6e, 0x65, 0x3b, 0x70, 0x6f, 0x3b, 0x75, 0x74,
-0x3b, 0x73, 0x74, 0x3b, 0x161, 0x74, 0x3b, 0x70, 0x69, 0x3b, 0x73, 0x6f, 0x6e, 0x3b, 0x70, 0x3b, 0x75, 0x3b, 0x73, 0x3b,
-0x161, 0x3b, 0x70, 0x3b, 0x73, 0x6e, 0x65, 0x64, 0x65, 0x6c, 0x6a, 0x61, 0x3b, 0x70, 0x6f, 0x6e, 0x65, 0x64, 0x65, 0x6c,
-0x6a, 0x65, 0x6b, 0x3b, 0x74, 0x6f, 0x72, 0x65, 0x6b, 0x3b, 0x73, 0x72, 0x65, 0x64, 0x61, 0x3b, 0x10d, 0x65, 0x74, 0x72,
-0x74, 0x65, 0x6b, 0x3b, 0x70, 0x65, 0x74, 0x65, 0x6b, 0x3b, 0x73, 0x6f, 0x62, 0x6f, 0x74, 0x61, 0x6e, 0x65, 0x64, 0x2e,
-0x3b, 0x70, 0x6f, 0x6e, 0x2e, 0x3b, 0x74, 0x6f, 0x72, 0x2e, 0x3b, 0x73, 0x72, 0x65, 0x2e, 0x3b, 0x10d, 0x65, 0x74, 0x2e,
-0x3b, 0x70, 0x65, 0x74, 0x2e, 0x3b, 0x73, 0x6f, 0x62, 0x2e, 0x6e, 0x3b, 0x70, 0x3b, 0x74, 0x3b, 0x73, 0x3b, 0x10d, 0x3b,
-0x70, 0x3b, 0x73, 0x53, 0x61, 0x62, 0x69, 0x69, 0x74, 0x69, 0x3b, 0x42, 0x61, 0x6c, 0x61, 0x7a, 0x61, 0x3b, 0x4f, 0x77,
-0x6f, 0x6b, 0x75, 0x62, 0x69, 0x6c, 0x69, 0x3b, 0x4f, 0x77, 0x6f, 0x6b, 0x75, 0x73, 0x61, 0x74, 0x75, 0x3b, 0x4f, 0x6c,
-0x6f, 0x6b, 0x75, 0x6e, 0x61, 0x3b, 0x4f, 0x6c, 0x6f, 0x6b, 0x75, 0x74, 0x61, 0x61, 0x6e, 0x75, 0x3b, 0x4f, 0x6c, 0x6f,
-0x6d, 0x75, 0x6b, 0x61, 0x61, 0x67, 0x61, 0x53, 0x61, 0x62, 0x69, 0x3b, 0x42, 0x61, 0x6c, 0x61, 0x3b, 0x4b, 0x75, 0x62,
-0x69, 0x3b, 0x4b, 0x75, 0x73, 0x61, 0x3b, 0x4b, 0x75, 0x6e, 0x61, 0x3b, 0x4b, 0x75, 0x74, 0x61, 0x3b, 0x4d, 0x75, 0x6b,
-0x61, 0x53, 0x3b, 0x42, 0x3b, 0x42, 0x3b, 0x53, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x4d, 0x41, 0x78, 0x61, 0x64, 0x3b, 0x49,
-0x73, 0x6e, 0x69, 0x69, 0x6e, 0x3b, 0x54, 0x61, 0x6c, 0x61, 0x61, 0x64, 0x6f, 0x3b, 0x41, 0x72, 0x62, 0x61, 0x63, 0x6f,
-0x3b, 0x4b, 0x68, 0x61, 0x6d, 0x69, 0x69, 0x73, 0x3b, 0x4a, 0x69, 0x6d, 0x63, 0x6f, 0x3b, 0x53, 0x61, 0x62, 0x74, 0x69,
-0x41, 0x78, 0x64, 0x3b, 0x49, 0x73, 0x6e, 0x3b, 0x54, 0x6c, 0x64, 0x6f, 0x3b, 0x41, 0x72, 0x62, 0x63, 0x3b, 0x4b, 0x68,
-0x6d, 0x73, 0x3b, 0x4a, 0x6d, 0x63, 0x3b, 0x53, 0x62, 0x74, 0x69, 0x41, 0x3b, 0x49, 0x3b, 0x54, 0x3b, 0x41, 0x3b, 0x4b,
-0x68, 0x3b, 0x4a, 0x3b, 0x53, 0x64, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x6f, 0x3b, 0x6c, 0x75, 0x6e, 0x65, 0x73, 0x3b, 0x6d,
-0x61, 0x72, 0x74, 0x65, 0x73, 0x3b, 0x6d, 0x69, 0xe9, 0x72, 0x63, 0x6f, 0x6c, 0x65, 0x73, 0x3b, 0x6a, 0x75, 0x65, 0x76,
-0x65, 0x73, 0x3b, 0x76, 0x69, 0x65, 0x72, 0x6e, 0x65, 0x73, 0x3b, 0x73, 0xe1, 0x62, 0x61, 0x64, 0x6f, 0x64, 0x6f, 0x6d,
-0x3b, 0x6c, 0x75, 0x6e, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x6d, 0x69, 0xe9, 0x3b, 0x6a, 0x75, 0x65, 0x3b, 0x76, 0x69, 0x65,
-0x3b, 0x73, 0xe1, 0x62, 0x2d30, 0x2d59, 0x2d30, 0x2d4e, 0x2d30, 0x2d59, 0x3b, 0x2d30, 0x2d62, 0x2d4f, 0x2d30, 0x2d59, 0x3b, 0x2d30, 0x2d59, 0x2d49,
-0x2d4f, 0x2d30, 0x2d59, 0x3b, 0x2d30, 0x2d3d, 0x2d55, 0x2d30, 0x2d59, 0x3b, 0x2d30, 0x2d3d, 0x2d61, 0x2d30, 0x2d59, 0x3b, 0x2d30, 0x2d59, 0x2d49, 0x2d4e,
-0x2d61, 0x2d30, 0x2d59, 0x3b, 0x2d30, 0x2d59, 0x2d49, 0x2d39, 0x2d62, 0x2d30, 0x2d59, 0x2d30, 0x2d59, 0x2d30, 0x3b, 0x2d30, 0x2d62, 0x2d4f, 0x3b, 0x2d30,
-0x2d59, 0x2d49, 0x3b, 0x2d30, 0x2d3d, 0x2d55, 0x3b, 0x2d30, 0x2d3d, 0x2d61, 0x3b, 0x2d30, 0x2d59, 0x2d49, 0x2d4e, 0x3b, 0x2d30, 0x2d59, 0x2d49, 0x2d39,
-0x4d, 0x69, 0x6e, 0x67, 0x67, 0x75, 0x3b, 0x53, 0x65, 0x6e, 0xe9, 0x6e, 0x3b, 0x53, 0x61, 0x6c, 0x61, 0x73, 0x61, 0x3b,
-0x52, 0x65, 0x62, 0x6f, 0x3b, 0x4b, 0x65, 0x6d, 0x69, 0x73, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x61, 0x68, 0x3b, 0x53, 0x61,
-0x70, 0x74, 0x75, 0x4d, 0x6e, 0x67, 0x3b, 0x53, 0x65, 0x6e, 0x3b, 0x53, 0x61, 0x6c, 0x3b, 0x52, 0x65, 0x62, 0x3b, 0x4b,
-0x65, 0x6d, 0x3b, 0x4a, 0x75, 0x6d, 0x3b, 0x53, 0x61, 0x70, 0x73, 0xf6, 0x6e, 0x64, 0x61, 0x67, 0x3b, 0x6d, 0xe5, 0x6e,
-0x64, 0x61, 0x67, 0x3b, 0x74, 0x69, 0x73, 0x64, 0x61, 0x67, 0x3b, 0x6f, 0x6e, 0x73, 0x64, 0x61, 0x67, 0x3b, 0x74, 0x6f,
-0x72, 0x73, 0x64, 0x61, 0x67, 0x3b, 0x66, 0x72, 0x65, 0x64, 0x61, 0x67, 0x3b, 0x6c, 0xf6, 0x72, 0x64, 0x61, 0x67, 0x73,
-0xf6, 0x6e, 0x3b, 0x6d, 0xe5, 0x6e, 0x3b, 0x74, 0x69, 0x73, 0x3b, 0x6f, 0x6e, 0x73, 0x3b, 0x74, 0x6f, 0x72, 0x73, 0x3b,
-0x66, 0x72, 0x65, 0x3b, 0x6c, 0xf6, 0x72, 0x53, 0x75, 0x6e, 0x6e, 0x74, 0x69, 0x67, 0x3b, 0x4d, 0xe4, 0xe4, 0x6e, 0x74,
-0x69, 0x67, 0x3b, 0x5a, 0x69, 0x69, 0x73, 0x63, 0x68, 0x74, 0x69, 0x67, 0x3b, 0x4d, 0x69, 0x74, 0x74, 0x77, 0x75, 0x63,
-0x68, 0x3b, 0x44, 0x75, 0x6e, 0x73, 0x63, 0x68, 0x74, 0x69, 0x67, 0x3b, 0x46, 0x72, 0x69, 0x69, 0x74, 0x69, 0x67, 0x3b,
-0x53, 0x61, 0x6d, 0x73, 0x63, 0x68, 0x74, 0x69, 0x67, 0x53, 0x75, 0x2e, 0x3b, 0x4d, 0xe4, 0x2e, 0x3b, 0x5a, 0x69, 0x2e,
-0x3b, 0x4d, 0x69, 0x2e, 0x3b, 0x44, 0x75, 0x2e, 0x3b, 0x46, 0x72, 0x2e, 0x3b, 0x53, 0x61, 0x2e, 0x2d30, 0x2d59, 0x2d30, 0x2d4e,
-0x2d30, 0x2d59, 0x3b, 0x2d30, 0x2d62, 0x2d4f, 0x2d30, 0x2d59, 0x3b, 0x2d30, 0x2d59, 0x2d49, 0x2d4f, 0x2d30, 0x2d59, 0x3b, 0x2d30, 0x2d3d, 0x2d55, 0x2d30,
-0x2d59, 0x3b, 0x2d30, 0x2d3d, 0x2d61, 0x2d30, 0x2d59, 0x3b, 0x2d59, 0x2d49, 0x2d4e, 0x2d61, 0x2d30, 0x2d59, 0x3b, 0x2d30, 0x2d59, 0x2d49, 0x2d39, 0x2d62,
-0x2d30, 0x2d59, 0x61, 0x73, 0x61, 0x6d, 0x61, 0x73, 0x3b, 0x61, 0x79, 0x6e, 0x61, 0x73, 0x3b, 0x61, 0x73, 0x69, 0x6e, 0x61,
-0x73, 0x3b, 0x61, 0x6b, 0x1e5b, 0x61, 0x73, 0x3b, 0x61, 0x6b, 0x77, 0x61, 0x73, 0x3b, 0x61, 0x73, 0x69, 0x6d, 0x77, 0x61,
-0x73, 0x3b, 0x61, 0x73, 0x69, 0x1e0d, 0x79, 0x61, 0x73, 0x61, 0x73, 0x61, 0x3b, 0x61, 0x79, 0x6e, 0x3b, 0x61, 0x73, 0x69,
-0x3b, 0x61, 0x6b, 0x1e5b, 0x3b, 0x61, 0x6b, 0x77, 0x3b, 0x61, 0x73, 0x69, 0x6d, 0x3b, 0x61, 0x73, 0x69, 0x1e0d, 0x49, 0x74,
-0x75, 0x6b, 0x75, 0x20, 0x6a, 0x61, 0x20, 0x6a, 0x75, 0x6d, 0x77, 0x61, 0x3b, 0x4b, 0x75, 0x72, 0x61, 0x6d, 0x75, 0x6b,
-0x61, 0x20, 0x6a, 0x69, 0x6d, 0x77, 0x65, 0x72, 0x69, 0x3b, 0x4b, 0x75, 0x72, 0x61, 0x6d, 0x75, 0x6b, 0x61, 0x20, 0x6b,
-0x61, 0x77, 0x69, 0x3b, 0x4b, 0x75, 0x72, 0x61, 0x6d, 0x75, 0x6b, 0x61, 0x20, 0x6b, 0x61, 0x64, 0x61, 0x64, 0x75, 0x3b,
-0x4b, 0x75, 0x72, 0x61, 0x6d, 0x75, 0x6b, 0x61, 0x20, 0x6b, 0x61, 0x6e, 0x61, 0x3b, 0x4b, 0x75, 0x72, 0x61, 0x6d, 0x75,
-0x6b, 0x61, 0x20, 0x6b, 0x61, 0x73, 0x61, 0x6e, 0x75, 0x3b, 0x4b, 0x69, 0x66, 0x75, 0x6c, 0x61, 0x20, 0x6e, 0x67, 0x75,
-0x77, 0x6f, 0x4a, 0x75, 0x6d, 0x3b, 0x4a, 0x69, 0x6d, 0x3b, 0x4b, 0x61, 0x77, 0x3b, 0x4b, 0x61, 0x64, 0x3b, 0x4b, 0x61,
-0x6e, 0x3b, 0x4b, 0x61, 0x73, 0x3b, 0x4e, 0x67, 0x75, 0x4a, 0x3b, 0x4a, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x4b,
-0x3b, 0x4e, 0x42f, 0x43a, 0x448, 0x430, 0x43d, 0x431, 0x435, 0x3b, 0x414, 0x443, 0x448, 0x430, 0x43d, 0x431, 0x435, 0x3b, 0x421, 0x435,
-0x448, 0x430, 0x43d, 0x431, 0x435, 0x3b, 0x427, 0x43e, 0x440, 0x448, 0x430, 0x43d, 0x431, 0x435, 0x3b, 0x41f, 0x430, 0x43d, 0x4b7, 0x448,
-0x430, 0x43d, 0x431, 0x435, 0x3b, 0x4b6, 0x443, 0x43c, 0x44a, 0x430, 0x3b, 0x428, 0x430, 0x43d, 0x431, 0x435, 0x42f, 0x448, 0x431, 0x3b,
-0x414, 0x448, 0x431, 0x3b, 0x421, 0x448, 0x431, 0x3b, 0x427, 0x448, 0x431, 0x3b, 0x41f, 0x448, 0x431, 0x3b, 0x4b6, 0x43c, 0x44a, 0x3b,
-0x428, 0x43d, 0x431, 0x42f, 0x3b, 0x414, 0x3b, 0x421, 0x3b, 0x427, 0x3b, 0x41f, 0x3b, 0x4b6, 0x3b, 0x428, 0xb9e, 0xbbe, 0xbaf, 0xbbf,
-0xbb1, 0xbc1, 0x3b, 0xba4, 0xbbf, 0xb99, 0xbcd, 0xb95, 0xbb3, 0xbcd, 0x3b, 0xb9a, 0xbc6, 0xbb5, 0xbcd, 0xbb5, 0xbbe, 0xbaf, 0xbcd, 0x3b,
-0xbaa, 0xbc1, 0xba4, 0xba9, 0xbcd, 0x3b, 0xbb5, 0xbbf, 0xbaf, 0xbbe, 0xbb4, 0xba9, 0xbcd, 0x3b, 0xbb5, 0xbc6, 0xbb3, 0xbcd, 0xbb3, 0xbbf,
-0x3b, 0xb9a, 0xba9, 0xbbf, 0xb9e, 0xbbe, 0xbaf, 0xbbf, 0x2e, 0x3b, 0xba4, 0xbbf, 0xb99, 0xbcd, 0x2e, 0x3b, 0xb9a, 0xbc6, 0xbb5, 0xbcd,
-0x2e, 0x3b, 0xbaa, 0xbc1, 0xba4, 0x2e, 0x3b, 0xbb5, 0xbbf, 0xbaf, 0xbbe, 0x2e, 0x3b, 0xbb5, 0xbc6, 0xbb3, 0xbcd, 0x2e, 0x3b, 0xb9a,
-0xba9, 0xbbf, 0xb9e, 0xbbe, 0x3b, 0xba4, 0xbbf, 0x3b, 0xb9a, 0xbc6, 0x3b, 0xbaa, 0xbc1, 0x3b, 0xbb5, 0xbbf, 0x3b, 0xbb5, 0xbc6, 0x3b,
-0xb9a, 0x44f, 0x43a, 0x448, 0x4d9, 0x43c, 0x431, 0x435, 0x3b, 0x434, 0x4af, 0x448, 0x4d9, 0x43c, 0x431, 0x435, 0x3b, 0x441, 0x438, 0x448,
-0x4d9, 0x43c, 0x431, 0x435, 0x3b, 0x447, 0x4d9, 0x440, 0x448, 0x4d9, 0x43c, 0x431, 0x435, 0x3b, 0x43f, 0x4d9, 0x43d, 0x497, 0x435, 0x448,
-0x4d9, 0x43c, 0x431, 0x435, 0x3b, 0x497, 0x43e, 0x43c, 0x433, 0x430, 0x3b, 0x448, 0x438, 0x43c, 0x431, 0x4d9, 0x44f, 0x43a, 0x448, 0x2e,
-0x3b, 0x434, 0x4af, 0x448, 0x2e, 0x3b, 0x441, 0x438, 0x448, 0x2e, 0x3b, 0x447, 0x4d9, 0x440, 0x2e, 0x3b, 0x43f, 0x4d9, 0x43d, 0x497,
-0x2e, 0x3b, 0x497, 0x43e, 0x43c, 0x2e, 0x3b, 0x448, 0x438, 0x43c, 0x2e, 0x42f, 0x3b, 0x414, 0x3b, 0x421, 0x3b, 0x427, 0x3b, 0x41f,
-0x3b, 0x496, 0x3b, 0x428, 0xc06, 0xc26, 0xc3f, 0xc35, 0xc3e, 0xc30, 0xc02, 0x3b, 0xc38, 0xc4b, 0xc2e, 0xc35, 0xc3e, 0xc30, 0xc02, 0x3b,
-0xc2e, 0xc02, 0xc17, 0xc33, 0xc35, 0xc3e, 0xc30, 0xc02, 0x3b, 0xc2c, 0xc41, 0xc27, 0xc35, 0xc3e, 0xc30, 0xc02, 0x3b, 0xc17, 0xc41, 0xc30,
-0xc41, 0xc35, 0xc3e, 0xc30, 0xc02, 0x3b, 0xc36, 0xc41, 0xc15, 0xc4d, 0xc30, 0xc35, 0xc3e, 0xc30, 0xc02, 0x3b, 0xc36, 0xc28, 0xc3f, 0xc35,
-0xc3e, 0xc30, 0xc02, 0xc06, 0xc26, 0xc3f, 0x3b, 0xc38, 0xc4b, 0xc2e, 0x3b, 0xc2e, 0xc02, 0xc17, 0xc33, 0x3b, 0xc2c, 0xc41, 0xc27, 0x3b,
-0xc17, 0xc41, 0xc30, 0xc41, 0x3b, 0xc36, 0xc41, 0xc15, 0xc4d, 0xc30, 0x3b, 0xc36, 0xc28, 0xc3f, 0xc06, 0x3b, 0xc38, 0xc4b, 0x3b, 0xc2e,
-0x3b, 0xc2c, 0xc41, 0x3b, 0xc17, 0xc41, 0x3b, 0xc36, 0xc41, 0x3b, 0xc36, 0x4e, 0x61, 0x6b, 0x61, 0x65, 0x6a, 0x75, 0x6d, 0x61,
-0x3b, 0x4e, 0x61, 0x6b, 0x61, 0x65, 0x62, 0x61, 0x72, 0x61, 0x73, 0x61, 0x3b, 0x4e, 0x61, 0x6b, 0x61, 0x61, 0x72, 0x65,
-0x3b, 0x4e, 0x61, 0x6b, 0x61, 0x75, 0x6e, 0x69, 0x3b, 0x4e, 0x61, 0x6b, 0x61, 0x75, 0x6e, 0x67, 0x2019, 0x6f, 0x6e, 0x3b,
-0x4e, 0x61, 0x6b, 0x61, 0x6b, 0x61, 0x6e, 0x79, 0x3b, 0x4e, 0x61, 0x6b, 0x61, 0x73, 0x61, 0x62, 0x69, 0x74, 0x69, 0x4a,
-0x75, 0x6d, 0x3b, 0x42, 0x61, 0x72, 0x3b, 0x41, 0x61, 0x72, 0x3b, 0x55, 0x6e, 0x69, 0x3b, 0x55, 0x6e, 0x67, 0x3b, 0x4b,
-0x61, 0x6e, 0x3b, 0x53, 0x61, 0x62, 0x4a, 0x3b, 0x42, 0x3b, 0x41, 0x3b, 0x55, 0x3b, 0x55, 0x3b, 0x4b, 0x3b, 0x53, 0xe27,
-0xe31, 0xe19, 0xe2d, 0xe32, 0xe17, 0xe34, 0xe15, 0xe22, 0xe4c, 0x3b, 0xe27, 0xe31, 0xe19, 0xe08, 0xe31, 0xe19, 0xe17, 0xe23, 0xe4c, 0x3b,
-0xe27, 0xe31, 0xe19, 0xe2d, 0xe31, 0xe07, 0xe04, 0xe32, 0xe23, 0x3b, 0xe27, 0xe31, 0xe19, 0xe1e, 0xe38, 0xe18, 0x3b, 0xe27, 0xe31, 0xe19,
-0xe1e, 0xe24, 0xe2b, 0xe31, 0xe2a, 0xe1a, 0xe14, 0xe35, 0x3b, 0xe27, 0xe31, 0xe19, 0xe28, 0xe38, 0xe01, 0xe23, 0xe4c, 0x3b, 0xe27, 0xe31,
-0xe19, 0xe40, 0xe2a, 0xe32, 0xe23, 0xe4c, 0xe2d, 0xe32, 0x2e, 0x3b, 0xe08, 0x2e, 0x3b, 0xe2d, 0x2e, 0x3b, 0xe1e, 0x2e, 0x3b, 0xe1e,
-0xe24, 0x2e, 0x3b, 0xe28, 0x2e, 0x3b, 0xe2a, 0x2e, 0xe2d, 0xe32, 0x3b, 0xe08, 0x3b, 0xe2d, 0x3b, 0xe1e, 0x3b, 0xe1e, 0xe24, 0x3b,
-0xe28, 0x3b, 0xe2a, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf49, 0xf72, 0xf0b, 0xf58, 0xf0b, 0x3b, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf5f, 0xfb3, 0xf0b,
-0xf56, 0xf0b, 0x3b, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf58, 0xf72, 0xf42, 0xf0b, 0xf51, 0xf58, 0xf62, 0xf0b, 0x3b, 0xf42, 0xf5f, 0xf60, 0xf0b,
-0xf63, 0xfb7, 0xf42, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf55, 0xf74, 0xf62, 0xf0b, 0xf56, 0xf74, 0xf0b, 0x3b, 0xf42,
-0xf5f, 0xf60, 0xf0b, 0xf54, 0xf0b, 0xf66, 0xf44, 0xf66, 0xf0b, 0x3b, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf66, 0xfa4, 0xf7a, 0xf53, 0xf0b, 0xf54,
-0xf0b, 0xf49, 0xf72, 0xf0b, 0xf58, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0x3b, 0xf58, 0xf72, 0xf42, 0xf0b, 0xf51, 0xf58, 0xf62,
-0xf0b, 0x3b, 0xf63, 0xfb7, 0xf42, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf55, 0xf74, 0xf62, 0xf0b, 0xf56, 0xf74, 0xf0b, 0x3b, 0xf54, 0xf0b, 0xf66,
-0xf44, 0xf66, 0xf0b, 0x3b, 0xf66, 0xfa4, 0xf7a, 0xf53, 0xf0b, 0xf54, 0xf0b, 0xf49, 0xf72, 0x3b, 0xf5f, 0xfb3, 0x3b, 0xf58, 0xf72, 0xf42,
-0x3b, 0xf63, 0xfb7, 0xf42, 0x3b, 0xf55, 0xf74, 0xf62, 0x3b, 0xf66, 0xf44, 0xf66, 0x3b, 0xf66, 0xfa4, 0xf7a, 0xf53, 0x1230, 0x1295, 0x1260,
-0x1275, 0x3b, 0x1230, 0x1291, 0x12ed, 0x3b, 0x1230, 0x1209, 0x1235, 0x3b, 0x1228, 0x1261, 0x12d5, 0x3b, 0x1213, 0x1219, 0x1235, 0x3b, 0x12d3, 0x122d,
-0x1262, 0x3b, 0x1240, 0x12f3, 0x121d, 0x1230, 0x1295, 0x3b, 0x1230, 0x1291, 0x3b, 0x1230, 0x1209, 0x3b, 0x1228, 0x1261, 0x3b, 0x1213, 0x1219, 0x3b,
-0x12d3, 0x122d, 0x3b, 0x1240, 0x12f3, 0x1230, 0x3b, 0x1230, 0x3b, 0x1230, 0x3b, 0x1228, 0x3b, 0x1213, 0x3b, 0x12d3, 0x3b, 0x1240, 0x53, 0x101,
-0x70, 0x61, 0x74, 0x65, 0x3b, 0x4d, 0x14d, 0x6e, 0x69, 0x74, 0x65, 0x3b, 0x54, 0x16b, 0x73, 0x69, 0x74, 0x65, 0x3b, 0x50,
-0x75, 0x6c, 0x65, 0x6c, 0x75, 0x6c, 0x75, 0x3b, 0x54, 0x75, 0x2bb, 0x61, 0x70, 0x75, 0x6c, 0x65, 0x6c, 0x75, 0x6c, 0x75,
-0x3b, 0x46, 0x61, 0x6c, 0x61, 0x69, 0x74, 0x65, 0x3b, 0x54, 0x6f, 0x6b, 0x6f, 0x6e, 0x61, 0x6b, 0x69, 0x53, 0x101, 0x70,
-0x3b, 0x4d, 0x14d, 0x6e, 0x3b, 0x54, 0x16b, 0x73, 0x3b, 0x50, 0x75, 0x6c, 0x3b, 0x54, 0x75, 0x2bb, 0x61, 0x3b, 0x46, 0x61,
-0x6c, 0x3b, 0x54, 0x6f, 0x6b, 0x53, 0x3b, 0x4d, 0x3b, 0x54, 0x3b, 0x50, 0x3b, 0x54, 0x3b, 0x46, 0x3b, 0x54, 0x50, 0x61,
-0x7a, 0x61, 0x72, 0x3b, 0x50, 0x61, 0x7a, 0x61, 0x72, 0x74, 0x65, 0x73, 0x69, 0x3b, 0x53, 0x61, 0x6c, 0x131, 0x3b, 0xc7,
-0x61, 0x72, 0x15f, 0x61, 0x6d, 0x62, 0x61, 0x3b, 0x50, 0x65, 0x72, 0x15f, 0x65, 0x6d, 0x62, 0x65, 0x3b, 0x43, 0x75, 0x6d,
-0x61, 0x3b, 0x43, 0x75, 0x6d, 0x61, 0x72, 0x74, 0x65, 0x73, 0x69, 0x50, 0x61, 0x7a, 0x3b, 0x50, 0x7a, 0x74, 0x3b, 0x53,
-0x61, 0x6c, 0x3b, 0xc7, 0x61, 0x72, 0x3b, 0x50, 0x65, 0x72, 0x3b, 0x43, 0x75, 0x6d, 0x3b, 0x43, 0x6d, 0x74, 0x50, 0x3b,
-0x50, 0x3b, 0x53, 0x3b, 0xc7, 0x3b, 0x50, 0x3b, 0x43, 0x3b, 0x43, 0xdd, 0x65, 0x6b, 0x15f, 0x65, 0x6e, 0x62, 0x65, 0x3b,
-0x44, 0x75, 0x15f, 0x65, 0x6e, 0x62, 0x65, 0x3b, 0x53, 0x69, 0x15f, 0x65, 0x6e, 0x62, 0x65, 0x3b, 0xc7, 0x61, 0x72, 0x15f,
-0x65, 0x6e, 0x62, 0x65, 0x3b, 0x50, 0x65, 0x6e, 0x15f, 0x65, 0x6e, 0x62, 0x65, 0x3b, 0x41, 0x6e, 0x6e, 0x61, 0x3b, 0x15e,
-0x65, 0x6e, 0x62, 0x65, 0xfd, 0x65, 0x6b, 0x15f, 0x65, 0x6e, 0x62, 0x65, 0x3b, 0x64, 0x75, 0x15f, 0x65, 0x6e, 0x62, 0x65,
-0x3b, 0x73, 0x69, 0x15f, 0x65, 0x6e, 0x62, 0x65, 0x3b, 0xe7, 0x61, 0x72, 0x15f, 0x65, 0x6e, 0x62, 0x65, 0x3b, 0x70, 0x65,
-0x6e, 0x15f, 0x65, 0x6e, 0x62, 0x65, 0x3b, 0x61, 0x6e, 0x6e, 0x61, 0x3b, 0x15f, 0x65, 0x6e, 0x62, 0x65, 0xdd, 0x65, 0x6b,
-0x3b, 0x44, 0x75, 0x15f, 0x3b, 0x53, 0x69, 0x15f, 0x3b, 0xc7, 0x61, 0x72, 0x3b, 0x50, 0x65, 0x6e, 0x3b, 0x41, 0x6e, 0x6e,
-0x3b, 0x15e, 0x65, 0x6e, 0xfd, 0x65, 0x6b, 0x3b, 0x64, 0x75, 0x15f, 0x3b, 0x73, 0x69, 0x15f, 0x3b, 0xe7, 0x61, 0x72, 0x3b,
-0x70, 0x65, 0x6e, 0x3b, 0x61, 0x6e, 0x6e, 0x3b, 0x15f, 0x65, 0x6e, 0xdd, 0x3b, 0x44, 0x3b, 0x53, 0x3b, 0xc7, 0x3b, 0x50,
-0x3b, 0x41, 0x3b, 0x15e, 0x43d, 0x435, 0x434, 0x456, 0x43b, 0x44f, 0x3b, 0x43f, 0x43e, 0x43d, 0x435, 0x434, 0x456, 0x43b, 0x43e, 0x43a,
-0x3b, 0x432, 0x456, 0x432, 0x442, 0x43e, 0x440, 0x43e, 0x43a, 0x3b, 0x441, 0x435, 0x440, 0x435, 0x434, 0x430, 0x3b, 0x447, 0x435, 0x442,
-0x432, 0x435, 0x440, 0x3b, 0x43f, 0x2bc, 0x44f, 0x442, 0x43d, 0x438, 0x446, 0x44f, 0x3b, 0x441, 0x443, 0x431, 0x43e, 0x442, 0x430, 0x41d,
-0x3b, 0x41f, 0x3b, 0x412, 0x3b, 0x421, 0x3b, 0x427, 0x3b, 0x41f, 0x3b, 0x421, 0x6e, 0x6a, 0x65, 0x64, 0x17a, 0x65, 0x6c, 0x61,
-0x3b, 0x70, 0xf3, 0x6e, 0x64, 0x17a, 0x65, 0x6c, 0x61, 0x3b, 0x77, 0x75, 0x74, 0x6f, 0x72, 0x61, 0x3b, 0x73, 0x72, 0x6a,
-0x65, 0x64, 0x61, 0x3b, 0x161, 0x74, 0x77, 0xf3, 0x72, 0x74, 0x6b, 0x3b, 0x70, 0x6a, 0x61, 0x74, 0x6b, 0x3b, 0x73, 0x6f,
-0x62, 0x6f, 0x74, 0x61, 0x6e, 0x6a, 0x65, 0x3b, 0x70, 0xf3, 0x6e, 0x3b, 0x77, 0x75, 0x74, 0x3b, 0x73, 0x72, 0x6a, 0x3b,
-0x161, 0x74, 0x77, 0x3b, 0x70, 0x6a, 0x61, 0x3b, 0x73, 0x6f, 0x62, 0x6e, 0x3b, 0x70, 0x3b, 0x77, 0x3b, 0x73, 0x3b, 0x161,
-0x3b, 0x70, 0x3b, 0x73, 0x627, 0x62a, 0x648, 0x627, 0x631, 0x3b, 0x67e, 0x6cc, 0x631, 0x3b, 0x645, 0x646, 0x6af, 0x644, 0x3b, 0x628,
-0x62f, 0x6be, 0x3b, 0x62c, 0x645, 0x639, 0x631, 0x627, 0x62a, 0x3b, 0x62c, 0x645, 0x639, 0x6c1, 0x3b, 0x6c1, 0x641, 0x62a, 0x6c1, 0x64a,
-0x6d5, 0x643, 0x634, 0x6d5, 0x646, 0x628, 0x6d5, 0x3b, 0x62f, 0x6c8, 0x634, 0x6d5, 0x646, 0x628, 0x6d5, 0x3b, 0x633, 0x6d5, 0x64a, 0x634,
-0x6d5, 0x646, 0x628, 0x6d5, 0x3b, 0x686, 0x627, 0x631, 0x634, 0x6d5, 0x646, 0x628, 0x6d5, 0x3b, 0x67e, 0x6d5, 0x64a, 0x634, 0x6d5, 0x646,
-0x628, 0x6d5, 0x3b, 0x62c, 0x6c8, 0x645, 0x6d5, 0x3b, 0x634, 0x6d5, 0x646, 0x628, 0x6d5, 0x64a, 0x6d5, 0x3b, 0x62f, 0x6c8, 0x3b, 0x633,
-0x6d5, 0x3b, 0x686, 0x627, 0x3b, 0x67e, 0x6d5, 0x3b, 0x62c, 0x6c8, 0x3b, 0x634, 0x6d5, 0x64a, 0x3b, 0x62f, 0x3b, 0x633, 0x3b, 0x686,
-0x3b, 0x67e, 0x3b, 0x62c, 0x3b, 0x634, 0x79, 0x61, 0x6b, 0x73, 0x68, 0x61, 0x6e, 0x62, 0x61, 0x3b, 0x64, 0x75, 0x73, 0x68,
-0x61, 0x6e, 0x62, 0x61, 0x3b, 0x73, 0x65, 0x73, 0x68, 0x61, 0x6e, 0x62, 0x61, 0x3b, 0x63, 0x68, 0x6f, 0x72, 0x73, 0x68,
-0x61, 0x6e, 0x62, 0x61, 0x3b, 0x70, 0x61, 0x79, 0x73, 0x68, 0x61, 0x6e, 0x62, 0x61, 0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x3b,
-0x73, 0x68, 0x61, 0x6e, 0x62, 0x61, 0x59, 0x61, 0x6b, 0x3b, 0x44, 0x75, 0x73, 0x68, 0x3b, 0x53, 0x65, 0x73, 0x68, 0x3b,
-0x43, 0x68, 0x6f, 0x72, 0x3b, 0x50, 0x61, 0x79, 0x3b, 0x4a, 0x75, 0x6d, 0x3b, 0x53, 0x68, 0x61, 0x6e, 0x59, 0x3b, 0x44,
-0x3b, 0x53, 0x3b, 0x43, 0x3b, 0x50, 0x3b, 0x4a, 0x3b, 0x53, 0x6cc, 0x2e, 0x3b, 0x62f, 0x2e, 0x3b, 0x633, 0x2e, 0x3b, 0x686,
-0x2e, 0x3b, 0x67e, 0x2e, 0x3b, 0x62c, 0x2e, 0x3b, 0x634, 0x2e, 0x44f, 0x43a, 0x448, 0x430, 0x43d, 0x431, 0x430, 0x3b, 0x434, 0x443,
-0x448, 0x430, 0x43d, 0x431, 0x430, 0x3b, 0x441, 0x435, 0x448, 0x430, 0x43d, 0x431, 0x430, 0x3b, 0x447, 0x43e, 0x440, 0x448, 0x430, 0x43d,
-0x431, 0x430, 0x3b, 0x43f, 0x430, 0x439, 0x448, 0x430, 0x43d, 0x431, 0x430, 0x3b, 0x436, 0x443, 0x43c, 0x430, 0x3b, 0x448, 0x430, 0x43d,
-0x431, 0x430, 0x44f, 0x43a, 0x448, 0x3b, 0x434, 0x443, 0x448, 0x3b, 0x441, 0x435, 0x448, 0x3b, 0x447, 0x43e, 0x440, 0x3b, 0x43f, 0x430,
-0x439, 0x3b, 0x436, 0x443, 0x43c, 0x3b, 0x448, 0x430, 0x43d, 0x42f, 0x3b, 0x414, 0x3b, 0x421, 0x3b, 0x427, 0x3b, 0x41f, 0x3b, 0x416,
-0x3b, 0x428, 0xa55e, 0xa54c, 0xa535, 0x3b, 0xa5f3, 0xa5e1, 0xa609, 0x3b, 0xa55a, 0xa55e, 0xa55a, 0x3b, 0xa549, 0xa55e, 0xa552, 0x3b, 0xa549, 0xa524,
-0xa546, 0xa562, 0x3b, 0xa549, 0xa524, 0xa540, 0xa56e, 0x3b, 0xa53b, 0xa52c, 0xa533, 0x6c, 0x61, 0x68, 0x61, 0x64, 0x69, 0x3b, 0x74, 0x25b,
-0x25b, 0x6e, 0x25b, 0x25b, 0x3b, 0x74, 0x61, 0x6c, 0x61, 0x74, 0x61, 0x3b, 0x61, 0x6c, 0x61, 0x62, 0x61, 0x3b, 0x61, 0x69,
-0x6d, 0x69, 0x73, 0x61, 0x3b, 0x61, 0x69, 0x6a, 0x69, 0x6d, 0x61, 0x3b, 0x73, 0x69, 0x253, 0x69, 0x74, 0x69, 0x43, 0x68,
-0x1ee7, 0x20, 0x4e, 0x68, 0x1ead, 0x74, 0x3b, 0x54, 0x68, 0x1ee9, 0x20, 0x48, 0x61, 0x69, 0x3b, 0x54, 0x68, 0x1ee9, 0x20, 0x42,
-0x61, 0x3b, 0x54, 0x68, 0x1ee9, 0x20, 0x54, 0x1b0, 0x3b, 0x54, 0x68, 0x1ee9, 0x20, 0x4e, 0x103, 0x6d, 0x3b, 0x54, 0x68, 0x1ee9,
-0x20, 0x53, 0xe1, 0x75, 0x3b, 0x54, 0x68, 0x1ee9, 0x20, 0x42, 0x1ea3, 0x79, 0x43, 0x4e, 0x3b, 0x54, 0x68, 0x20, 0x32, 0x3b,
-0x54, 0x68, 0x20, 0x33, 0x3b, 0x54, 0x68, 0x20, 0x34, 0x3b, 0x54, 0x68, 0x20, 0x35, 0x3b, 0x54, 0x68, 0x20, 0x36, 0x3b,
-0x54, 0x68, 0x20, 0x37, 0x43, 0x4e, 0x3b, 0x54, 0x32, 0x3b, 0x54, 0x33, 0x3b, 0x54, 0x34, 0x3b, 0x54, 0x35, 0x3b, 0x54,
-0x36, 0x3b, 0x54, 0x37, 0x53, 0x75, 0x6e, 0x6e, 0x74, 0x61, 0x67, 0x3b, 0x4d, 0xe4, 0x6e, 0x74, 0x61, 0x67, 0x3b, 0x5a,
-0x69, 0x161, 0x74, 0x61, 0x67, 0x3b, 0x4d, 0x69, 0x74, 0x74, 0x77, 0x75, 0x10d, 0x3b, 0x46, 0x72, 0xf3, 0x6e, 0x74, 0x61,
-0x67, 0x3b, 0x46, 0x72, 0x69, 0x74, 0x61, 0x67, 0x3b, 0x53, 0x61, 0x6d, 0x161, 0x74, 0x61, 0x67, 0x53, 0x75, 0x6e, 0x3b,
-0x4d, 0xe4, 0x6e, 0x3b, 0x5a, 0x69, 0x161, 0x3b, 0x4d, 0x69, 0x74, 0x3b, 0x46, 0x72, 0xf3, 0x3b, 0x46, 0x72, 0x69, 0x3b,
-0x53, 0x61, 0x6d, 0x53, 0x3b, 0x4d, 0x3b, 0x5a, 0x3b, 0x4d, 0x3b, 0x46, 0x3b, 0x46, 0x3b, 0x53, 0x44, 0x79, 0x64, 0x64,
-0x20, 0x53, 0x75, 0x6c, 0x3b, 0x44, 0x79, 0x64, 0x64, 0x20, 0x4c, 0x6c, 0x75, 0x6e, 0x3b, 0x44, 0x79, 0x64, 0x64, 0x20,
-0x4d, 0x61, 0x77, 0x72, 0x74, 0x68, 0x3b, 0x44, 0x79, 0x64, 0x64, 0x20, 0x4d, 0x65, 0x72, 0x63, 0x68, 0x65, 0x72, 0x3b,
-0x44, 0x79, 0x64, 0x64, 0x20, 0x49, 0x61, 0x75, 0x3b, 0x44, 0x79, 0x64, 0x64, 0x20, 0x47, 0x77, 0x65, 0x6e, 0x65, 0x72,
-0x3b, 0x44, 0x79, 0x64, 0x64, 0x20, 0x53, 0x61, 0x64, 0x77, 0x72, 0x6e, 0x53, 0x75, 0x6c, 0x3b, 0x4c, 0x6c, 0x75, 0x6e,
-0x3b, 0x4d, 0x61, 0x77, 0x3b, 0x4d, 0x65, 0x72, 0x3b, 0x49, 0x61, 0x75, 0x3b, 0x47, 0x77, 0x65, 0x3b, 0x53, 0x61, 0x64,
-0x53, 0x75, 0x6c, 0x3b, 0x4c, 0x6c, 0x75, 0x6e, 0x3b, 0x4d, 0x61, 0x77, 0x3b, 0x4d, 0x65, 0x72, 0x3b, 0x49, 0x61, 0x75,
-0x3b, 0x47, 0x77, 0x65, 0x6e, 0x3b, 0x53, 0x61, 0x64, 0x53, 0x3b, 0x4c, 0x6c, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x49, 0x3b,
-0x47, 0x3b, 0x53, 0x73, 0x6e, 0x65, 0x69, 0x6e, 0x3b, 0x6d, 0x6f, 0x61, 0x6e, 0x64, 0x65, 0x69, 0x3b, 0x74, 0x69, 0x69,
-0x73, 0x64, 0x65, 0x69, 0x3b, 0x77, 0x6f, 0x61, 0x6e, 0x73, 0x64, 0x65, 0x69, 0x3b, 0x74, 0x6f, 0x6e, 0x67, 0x65, 0x72,
-0x73, 0x64, 0x65, 0x69, 0x3b, 0x66, 0x72, 0x65, 0x65, 0x64, 0x3b, 0x73, 0x6e, 0x65, 0x6f, 0x6e, 0x73, 0x69, 0x3b, 0x6d,
-0x6f, 0x3b, 0x74, 0x69, 0x3b, 0x77, 0x6f, 0x3b, 0x74, 0x6f, 0x3b, 0x66, 0x72, 0x3b, 0x73, 0x6f, 0x44, 0x69, 0x62, 0xe9,
-0x65, 0x72, 0x3b, 0x41, 0x6c, 0x74, 0x69, 0x6e, 0x65, 0x3b, 0x54, 0x61, 0x6c, 0x61, 0x61, 0x74, 0x61, 0x3b, 0xc0, 0x6c,
-0x61, 0x72, 0x62, 0x61, 0x3b, 0x41, 0x6c, 0x78, 0x61, 0x6d, 0x69, 0x73, 0x3b, 0xc0, 0x6a, 0x6a, 0x75, 0x6d, 0x61, 0x3b,
-0x41, 0x73, 0x65, 0x65, 0x72, 0x44, 0x69, 0x62, 0x3b, 0x41, 0x6c, 0x74, 0x3b, 0x54, 0x61, 0x6c, 0x3b, 0xc0, 0x6c, 0x61,
-0x3b, 0x41, 0x6c, 0x78, 0x3b, 0xc0, 0x6a, 0x6a, 0x3b, 0x41, 0x73, 0x65, 0x43, 0x61, 0x77, 0x65, 0x3b, 0x4d, 0x76, 0x75,
-0x6c, 0x6f, 0x3b, 0x4c, 0x77, 0x65, 0x73, 0x69, 0x62, 0x69, 0x6e, 0x69, 0x3b, 0x4c, 0x77, 0x65, 0x73, 0x69, 0x74, 0x68,
-0x61, 0x74, 0x68, 0x75, 0x3b, 0x4c, 0x77, 0x65, 0x73, 0x69, 0x6e, 0x65, 0x3b, 0x4c, 0x77, 0x65, 0x73, 0x69, 0x68, 0x6c,
-0x61, 0x6e, 0x75, 0x3b, 0x4d, 0x67, 0x71, 0x69, 0x62, 0x65, 0x6c, 0x6f, 0x43, 0x61, 0x77, 0x3b, 0x4d, 0x76, 0x75, 0x3b,
-0x42, 0x69, 0x6e, 0x3b, 0x54, 0x68, 0x61, 0x3b, 0x53, 0x69, 0x6e, 0x3b, 0x48, 0x6c, 0x61, 0x3b, 0x4d, 0x67, 0x71, 0x43,
-0x61, 0x77, 0x3b, 0x4d, 0x76, 0x75, 0x3b, 0x4c, 0x77, 0x65, 0x73, 0x62, 0x3b, 0x54, 0x68, 0x61, 0x3b, 0x53, 0x69, 0x6e,
-0x3b, 0x48, 0x6c, 0x61, 0x3b, 0x4d, 0x67, 0x71, 0x43, 0x3b, 0x4d, 0x3b, 0x53, 0x62, 0x3b, 0x53, 0x74, 0x3b, 0x53, 0x69,
-0x6e, 0x3b, 0x48, 0x6c, 0x3b, 0x4d, 0x67, 0x71, 0x43, 0x3b, 0x4d, 0x3b, 0x53, 0x62, 0x3b, 0x54, 0x68, 0x74, 0x3b, 0x53,
-0x69, 0x6e, 0x3b, 0x48, 0x6c, 0x3b, 0x4d, 0x67, 0x71, 0x73, 0x254, 0x301, 0x6e, 0x64, 0x69, 0x25b, 0x3b, 0x6d, 0xf3, 0x6e,
-0x64, 0x69, 0x65, 0x3b, 0x6d, 0x75, 0xe1, 0x6e, 0x79, 0xe1, 0x14b, 0x6d, 0xf3, 0x6e, 0x64, 0x69, 0x65, 0x3b, 0x6d, 0x65,
-0x74, 0xfa, 0x6b, 0x70, 0xed, 0xe1, 0x70, 0x25b, 0x3b, 0x6b, 0xfa, 0x70, 0xe9, 0x6c, 0x69, 0x6d, 0x65, 0x74, 0xfa, 0x6b,
-0x70, 0x69, 0x61, 0x70, 0x25b, 0x3b, 0x66, 0x65, 0x6c, 0xe9, 0x74, 0x65, 0x3b, 0x73, 0xe9, 0x73, 0x65, 0x6c, 0xe9, 0x73,
-0x64, 0x3b, 0x6d, 0x64, 0x3b, 0x6d, 0x77, 0x3b, 0x65, 0x74, 0x3b, 0x6b, 0x6c, 0x3b, 0x66, 0x6c, 0x3b, 0x73, 0x73, 0x73,
-0x3b, 0x6d, 0x3b, 0x6d, 0x3b, 0x65, 0x3b, 0x6b, 0x3b, 0x66, 0x3b, 0x73, 0x5d6, 0x5d5, 0x5e0, 0x5d8, 0x5d9, 0x5e7, 0x3b, 0x5de,
-0x5d0, 0x5b8, 0x5e0, 0x5d8, 0x5d9, 0x5e7, 0x3b, 0x5d3, 0x5d9, 0x5e0, 0x5e1, 0x5d8, 0x5d9, 0x5e7, 0x3b, 0x5de, 0x5d9, 0x5d8, 0x5d5, 0x5d5,
-0x5d0, 0x5da, 0x3b, 0x5d3, 0x5d0, 0x5e0, 0x5e2, 0x5e8, 0x5e9, 0x5d8, 0x5d9, 0x5e7, 0x3b, 0x5e4, 0x5bf, 0x5e8, 0x5f2, 0x5b7, 0x5d8, 0x5d9,
-0x5e7, 0x3b, 0x5e9, 0x5d1, 0x5ea, 0xc0, 0xec, 0x6b, 0xfa, 0x3b, 0x41, 0x6a, 0xe9, 0x3b, 0xcc, 0x73, 0x1eb9, 0x301, 0x67, 0x75,
-0x6e, 0x3b, 0x1ecc, 0x6a, 0x1ecd, 0x301, 0x72, 0xfa, 0x3b, 0x1ecc, 0x6a, 0x1ecd, 0x301, 0x62, 0x1ecd, 0x3b, 0x1eb8, 0x74, 0xec, 0x3b,
-0xc0, 0x62, 0xe1, 0x6d, 0x1eb9, 0x301, 0x74, 0x61, 0x1ecc, 0x6a, 0x1ecd, 0x301, 0x20, 0xc0, 0xec, 0x6b, 0xfa, 0x3b, 0x1ecc, 0x6a,
-0x1ecd, 0x301, 0x20, 0x41, 0x6a, 0xe9, 0x3b, 0x1ecc, 0x6a, 0x1ecd, 0x301, 0x20, 0xcc, 0x73, 0x1eb9, 0x301, 0x67, 0x75, 0x6e, 0x3b,
-0x1ecc, 0x6a, 0x1ecd, 0x301, 0x72, 0xfa, 0x3b, 0x1ecc, 0x6a, 0x1ecd, 0x301, 0x62, 0x1ecd, 0x3b, 0x1ecc, 0x6a, 0x1ecd, 0x301, 0x20, 0x1eb8,
-0x74, 0xec, 0x3b, 0x1ecc, 0x6a, 0x1ecd, 0x301, 0x20, 0xc0, 0x62, 0xe1, 0x6d, 0x1eb9, 0x301, 0x74, 0x61, 0xc0, 0xec, 0x6b, 0x3b,
-0x41, 0x6a, 0x3b, 0xcc, 0x73, 0x1eb9, 0x301, 0x67, 0x3b, 0x1ecc, 0x6a, 0x1ecd, 0x301, 0x72, 0x3b, 0x1ecc, 0x6a, 0x1ecd, 0x301, 0x62,
-0x3b, 0x1eb8, 0x74, 0x3b, 0xc0, 0x62, 0xe1, 0x6d, 0xc0, 0x3b, 0x41, 0x3b, 0xcc, 0x3b, 0x1ecc, 0x3b, 0x1ecc, 0x3b, 0x1eb8, 0x3b,
-0xc0, 0xc0, 0xec, 0x6b, 0xfa, 0x3b, 0x41, 0x6a, 0xe9, 0x3b, 0xcc, 0x73, 0x25b, 0x301, 0x67, 0x75, 0x6e, 0x3b, 0x186, 0x6a,
-0x254, 0x301, 0x72, 0xfa, 0x3b, 0x186, 0x6a, 0x254, 0x301, 0x62, 0x254, 0x3b, 0x190, 0x74, 0xec, 0x3b, 0xc0, 0x62, 0xe1, 0x6d,
-0x25b, 0x301, 0x74, 0x61, 0x186, 0x6a, 0x254, 0x301, 0x20, 0xc0, 0xec, 0x6b, 0xfa, 0x3b, 0x186, 0x6a, 0x254, 0x301, 0x20, 0x41,
-0x6a, 0xe9, 0x3b, 0x186, 0x6a, 0x254, 0x301, 0x20, 0xcc, 0x73, 0x25b, 0x301, 0x67, 0x75, 0x6e, 0x3b, 0x186, 0x6a, 0x254, 0x301,
-0x72, 0xfa, 0x3b, 0x186, 0x6a, 0x254, 0x301, 0x62, 0x254, 0x3b, 0x186, 0x6a, 0x254, 0x301, 0x20, 0x190, 0x74, 0xec, 0x3b, 0x186,
-0x6a, 0x254, 0x301, 0x20, 0xc0, 0x62, 0xe1, 0x6d, 0x25b, 0x301, 0x74, 0x61, 0xc0, 0xec, 0x6b, 0x3b, 0x41, 0x6a, 0x3b, 0xcc,
-0x73, 0x25b, 0x301, 0x67, 0x3b, 0x186, 0x6a, 0x254, 0x301, 0x72, 0x3b, 0x186, 0x6a, 0x254, 0x301, 0x62, 0x3b, 0x190, 0x74, 0x3b,
-0xc0, 0x62, 0xe1, 0x6d, 0xc0, 0x3b, 0x41, 0x3b, 0xcc, 0x3b, 0x186, 0x3b, 0x186, 0x3b, 0x190, 0x3b, 0xc0, 0x41, 0x6c, 0x68,
-0x61, 0x64, 0x69, 0x3b, 0x41, 0x74, 0x69, 0x6e, 0x6e, 0x69, 0x3b, 0x41, 0x74, 0x61, 0x6c, 0x61, 0x61, 0x74, 0x61, 0x3b,
-0x41, 0x6c, 0x61, 0x72, 0x62, 0x61, 0x3b, 0x41, 0x6c, 0x68, 0x61, 0x6d, 0x69, 0x73, 0x69, 0x3b, 0x41, 0x6c, 0x7a, 0x75,
-0x6d, 0x61, 0x3b, 0x41, 0x73, 0x69, 0x62, 0x74, 0x69, 0x48, 0x3b, 0x54, 0x3b, 0x54, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x5a,
-0x3b, 0x53, 0x49, 0x53, 0x6f, 0x6e, 0x74, 0x6f, 0x3b, 0x55, 0x4d, 0x73, 0x6f, 0x6d, 0x62, 0x75, 0x6c, 0x75, 0x6b, 0x6f,
-0x3b, 0x55, 0x4c, 0x77, 0x65, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x3b, 0x55, 0x4c, 0x77, 0x65, 0x73, 0x69, 0x74, 0x68,
-0x61, 0x74, 0x68, 0x75, 0x3b, 0x55, 0x4c, 0x77, 0x65, 0x73, 0x69, 0x6e, 0x65, 0x3b, 0x55, 0x4c, 0x77, 0x65, 0x73, 0x69,
-0x68, 0x6c, 0x61, 0x6e, 0x75, 0x3b, 0x55, 0x4d, 0x67, 0x71, 0x69, 0x62, 0x65, 0x6c, 0x6f, 0x53, 0x6f, 0x6e, 0x3b, 0x4d,
-0x73, 0x6f, 0x3b, 0x42, 0x69, 0x6c, 0x3b, 0x54, 0x68, 0x61, 0x3b, 0x53, 0x69, 0x6e, 0x3b, 0x48, 0x6c, 0x61, 0x3b, 0x4d,
-0x67, 0x71, 0x53, 0x3b, 0x4d, 0x3b, 0x42, 0x3b, 0x54, 0x3b, 0x53, 0x3b, 0x48, 0x3b, 0x4d, 0x6e, 0x75, 0x6d, 0x129, 0x67,
-0x67, 0x75, 0x3b, 0x70, 0x69, 0x72, 0x2d, 0x6b, 0x75, 0x72, 0xe3, 0x2d, 0x68, 0xe1, 0x3b, 0x72, 0xe9, 0x67, 0x72, 0x65,
-0x2d, 0x6b, 0x75, 0x72, 0xe3, 0x2d, 0x68, 0xe1, 0x3b, 0x74, 0x1ebd, 0x67, 0x74, 0x169, 0x2d, 0x6b, 0x75, 0x72, 0xe3, 0x2d,
-0x68, 0xe1, 0x3b, 0x76, 0x1ebd, 0x6e, 0x68, 0x6b, 0xe3, 0x67, 0x72, 0x61, 0x2d, 0x6b, 0x75, 0x72, 0xe3, 0x2d, 0x68, 0xe1,
-0x3b, 0x70, 0xe9, 0x6e, 0x6b, 0x61, 0x72, 0x2d, 0x6b, 0x75, 0x72, 0xe3, 0x2d, 0x68, 0xe1, 0x3b, 0x73, 0x61, 0x76, 0x6e,
-0x75, 0x6e, 0x75, 0x6d, 0x2e, 0x3b, 0x70, 0x69, 0x72, 0x2e, 0x3b, 0x72, 0xe9, 0x67, 0x2e, 0x3b, 0x74, 0x1ebd, 0x67, 0x2e,
-0x3b, 0x76, 0x1ebd, 0x6e, 0x2e, 0x3b, 0x70, 0xe9, 0x6e, 0x2e, 0x3b, 0x73, 0x61, 0x76, 0x2e, 0x4e, 0x2e, 0x3b, 0x50, 0x2e,
-0x3b, 0x52, 0x2e, 0x3b, 0x54, 0x2e, 0x3b, 0x56, 0x2e, 0x3b, 0x50, 0x2e, 0x3b, 0x53, 0x2e, 0x6d, 0x69, 0x74, 0x75, 0xfa,
-0x3b, 0x6d, 0x75, 0x72, 0x61, 0x6b, 0x69, 0x70, 0xed, 0x3b, 0x6d, 0x75, 0x72, 0x61, 0x6b, 0xed, 0x2d, 0x6d, 0x75, 0x6b,
-0x169, 0x69, 0x3b, 0x6d, 0x75, 0x72, 0x61, 0x6b, 0xed, 0x2d, 0x6d, 0x75, 0x73, 0x61, 0x70, 0xed, 0x72, 0x69, 0x3b, 0x73,
-0x75, 0x70, 0x61, 0x70, 0xe1, 0x3b, 0x79, 0x75, 0x6b, 0x75, 0x61, 0x6b, 0xfa, 0x3b, 0x73, 0x61, 0x75, 0x72, 0xfa, 0x6d,
-0x69, 0x74, 0x3b, 0x6d, 0x75, 0x72, 0x3b, 0x6d, 0x6d, 0x6b, 0x3b, 0x6d, 0x6d, 0x73, 0x3b, 0x73, 0x75, 0x70, 0x3b, 0x79,
-0x75, 0x6b, 0x3b, 0x73, 0x61, 0x75, 0x4d, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x53, 0x3b, 0x59, 0x3b, 0x53, 0x910,
-0x924, 0x935, 0x93e, 0x930, 0x3b, 0x938, 0x94b, 0x92e, 0x935, 0x93e, 0x930, 0x3b, 0x92e, 0x902, 0x917, 0x932, 0x935, 0x93e, 0x930, 0x3b,
-0x92c, 0x941, 0x927, 0x935, 0x93e, 0x930, 0x3b, 0x92c, 0x943, 0x939, 0x938, 0x94d, 0x92a, 0x924, 0x935, 0x93e, 0x930, 0x3b, 0x936, 0x941,
-0x915, 0x94d, 0x930, 0x935, 0x93e, 0x930, 0x3b, 0x936, 0x928, 0x93f, 0x935, 0x93e, 0x930, 0x53, 0xf6, 0x6e, 0x64, 0x61, 0x69, 0x3b,
-0x4d, 0x75, 0x6e, 0x64, 0x61, 0x69, 0x3b, 0x54, 0x65, 0x69, 0x73, 0x64, 0x61, 0x69, 0x3b, 0x57, 0x65, 0x65, 0x64, 0x65,
-0x6e, 0x73, 0x64, 0x61, 0x69, 0x3b, 0x54, 0xfc, 0xfc, 0x72, 0x73, 0x64, 0x61, 0x69, 0x3b, 0x46, 0x72, 0x65, 0x69, 0x64,
-0x61, 0x69, 0x3b, 0x53, 0x61, 0x6e, 0x69, 0x6e, 0x6a, 0x53, 0xf6, 0x6e, 0x3b, 0x4d, 0x75, 0x6e, 0x3b, 0x54, 0x65, 0x69,
-0x3b, 0x57, 0x65, 0x64, 0x3b, 0x54, 0xfc, 0x72, 0x3b, 0x46, 0x72, 0x65, 0x3b, 0x53, 0x61, 0x6e, 0x53, 0x61, 0x6e, 0x64,
-0x65, 0x3b, 0x4d, 0x61, 0x6e, 0x64, 0x65, 0x3b, 0x54, 0x69, 0x75, 0x73, 0x64, 0x65, 0x3b, 0x57, 0x65, 0x6e, 0x65, 0x73,
-0x64, 0x65, 0x3b, 0x54, 0x6f, 0x73, 0x64, 0x65, 0x3b, 0x46, 0x72, 0x61, 0x65, 0x64, 0x65, 0x3b, 0x53, 0x61, 0x74, 0x61,
-0x64, 0x65
+0x53, 0x75, 0x6e, 0x64, 0x61, 0x79, 0x3b, 0x4d, 0x6f, 0x6e, 0x64, 0x61,
+0x79, 0x3b, 0x54, 0x75, 0x65, 0x73, 0x64, 0x61, 0x79, 0x3b, 0x57, 0x65,
+0x64, 0x6e, 0x65, 0x73, 0x64, 0x61, 0x79, 0x3b, 0x54, 0x68, 0x75, 0x72,
+0x73, 0x64, 0x61, 0x79, 0x3b, 0x46, 0x72, 0x69, 0x64, 0x61, 0x79, 0x3b,
+0x53, 0x61, 0x74, 0x75, 0x72, 0x64, 0x61, 0x79, 0x53, 0x75, 0x6e, 0x3b,
+0x4d, 0x6f, 0x6e, 0x3b, 0x54, 0x75, 0x65, 0x3b, 0x57, 0x65, 0x64, 0x3b,
+0x54, 0x68, 0x75, 0x3b, 0x46, 0x72, 0x69, 0x3b, 0x53, 0x61, 0x74, 0x53,
+0x3b, 0x4d, 0x3b, 0x54, 0x3b, 0x57, 0x3b, 0x54, 0x3b, 0x46, 0x3b, 0x53,
+0x37, 0x3b, 0x31, 0x3b, 0x32, 0x3b, 0x33, 0x3b, 0x34, 0x3b, 0x35, 0x3b,
+0x36, 0x410, 0x43c, 0x4bd, 0x44b, 0x448, 0x430, 0x3b, 0x410, 0x448, 0x4d9, 0x430,
+0x445, 0x44c, 0x430, 0x3b, 0x410, 0x4a9, 0x430, 0x448, 0x430, 0x3b, 0x410, 0x445,
+0x430, 0x448, 0x430, 0x3b, 0x410, 0x525, 0x448, 0x44c, 0x430, 0x448, 0x430, 0x3b,
+0x410, 0x445, 0x4d9, 0x430, 0x448, 0x430, 0x3b, 0x410, 0x441, 0x430, 0x431, 0x448,
+0x430, 0x410, 0x43c, 0x3b, 0x410, 0x448, 0x4d9, 0x3b, 0x410, 0x4a9, 0x3b, 0x410,
+0x445, 0x3b, 0x410, 0x525, 0x3b, 0x410, 0x445, 0x4d9, 0x3b, 0x410, 0x441, 0x41c,
+0x3b, 0x428, 0x4d9, 0x3b, 0x4a8, 0x3b, 0x425, 0x3b, 0x524, 0x3b, 0x425, 0x4d9,
+0x3b, 0x421, 0x41, 0x63, 0x61, 0x61, 0x64, 0x61, 0x3b, 0x45, 0x74, 0x6c,
+0x65, 0x65, 0x6e, 0x69, 0x3b, 0x54, 0x61, 0x6c, 0x61, 0x61, 0x74, 0x61,
+0x3b, 0x41, 0x72, 0x62, 0x61, 0x71, 0x61, 0x3b, 0x4b, 0x61, 0x6d, 0x69,
+0x69, 0x73, 0x69, 0x3b, 0x47, 0x75, 0x6d, 0x71, 0x61, 0x74, 0x61, 0x3b,
+0x53, 0x61, 0x62, 0x74, 0x69, 0x41, 0x63, 0x61, 0x3b, 0x45, 0x74, 0x6c,
+0x3b, 0x54, 0x61, 0x6c, 0x3b, 0x41, 0x72, 0x62, 0x3b, 0x4b, 0x61, 0x6d,
+0x3b, 0x47, 0x75, 0x6d, 0x3b, 0x53, 0x61, 0x62, 0x41, 0x3b, 0x45, 0x3b,
+0x54, 0x3b, 0x41, 0x3b, 0x4b, 0x3b, 0x47, 0x3b, 0x53, 0x53, 0x6f, 0x6e,
+0x64, 0x61, 0x67, 0x3b, 0x4d, 0x61, 0x61, 0x6e, 0x64, 0x61, 0x67, 0x3b,
+0x44, 0x69, 0x6e, 0x73, 0x64, 0x61, 0x67, 0x3b, 0x57, 0x6f, 0x65, 0x6e,
+0x73, 0x64, 0x61, 0x67, 0x3b, 0x44, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x64,
+0x61, 0x67, 0x3b, 0x56, 0x72, 0x79, 0x64, 0x61, 0x67, 0x3b, 0x53, 0x61,
+0x74, 0x65, 0x72, 0x64, 0x61, 0x67, 0x53, 0x6f, 0x2e, 0x3b, 0x4d, 0x61,
+0x2e, 0x3b, 0x44, 0x69, 0x2e, 0x3b, 0x57, 0x6f, 0x2e, 0x3b, 0x44, 0x6f,
+0x2e, 0x3b, 0x56, 0x72, 0x2e, 0x3b, 0x53, 0x61, 0x2e, 0x53, 0x3b, 0x4d,
+0x3b, 0x44, 0x3b, 0x57, 0x3b, 0x44, 0x3b, 0x56, 0x3b, 0x53, 0x74, 0x73,
+0x75, 0x294, 0x6e, 0x74, 0x73, 0x268, 0x3b, 0x74, 0x73, 0x75, 0x294, 0x75,
+0x6b, 0x70, 0xe0, 0x3b, 0x74, 0x73, 0x75, 0x294, 0x75, 0x67, 0x68, 0x254,
+0x65, 0x3b, 0x74, 0x73, 0x75, 0x294, 0x75, 0x74, 0x254, 0x300, 0x6d, 0x6c,
+0xf2, 0x3b, 0x74, 0x73, 0x75, 0x294, 0x75, 0x6d, 0xe8, 0x3b, 0x74, 0x73,
+0x75, 0x294, 0x75, 0x67, 0x68, 0x268, 0x302, 0x6d, 0x3b, 0x74, 0x73, 0x75,
+0x294, 0x6e, 0x64, 0x7a, 0x268, 0x6b, 0x254, 0x294, 0x254, 0x6e, 0x74, 0x73,
+0x3b, 0x6b, 0x70, 0x61, 0x3b, 0x67, 0x68, 0x254, 0x3b, 0x74, 0x254, 0x6d,
+0x3b, 0x75, 0x6d, 0x65, 0x3b, 0x67, 0x68, 0x268, 0x3b, 0x64, 0x7a, 0x6b,
+0x6e, 0x3b, 0x6b, 0x3b, 0x67, 0x3b, 0x74, 0x3b, 0x75, 0x3b, 0x67, 0x3b,
+0x64, 0x4b, 0x77, 0x65, 0x73, 0x69, 0x64, 0x61, 0x3b, 0x44, 0x77, 0x6f,
+0x77, 0x64, 0x61, 0x3b, 0x42, 0x65, 0x6e, 0x61, 0x64, 0x61, 0x3b, 0x57,
+0x75, 0x6b, 0x75, 0x64, 0x61, 0x3b, 0x59, 0x61, 0x77, 0x64, 0x61, 0x3b,
+0x46, 0x69, 0x64, 0x61, 0x3b, 0x4d, 0x65, 0x6d, 0x65, 0x6e, 0x65, 0x64,
+0x61, 0x4b, 0x77, 0x65, 0x3b, 0x44, 0x77, 0x6f, 0x3b, 0x42, 0x65, 0x6e,
+0x3b, 0x57, 0x75, 0x6b, 0x3b, 0x59, 0x61, 0x77, 0x3b, 0x46, 0x69, 0x61,
+0x3b, 0x4d, 0x65, 0x6d, 0x4b, 0x3b, 0x44, 0x3b, 0x42, 0x3b, 0x57, 0x3b,
+0x59, 0x3b, 0x46, 0x3b, 0x4d, 0x65, 0x20, 0x64, 0x69, 0x65, 0x6c, 0x3b,
+0x65, 0x20, 0x68, 0xeb, 0x6e, 0xeb, 0x3b, 0x65, 0x20, 0x6d, 0x61, 0x72,
+0x74, 0xeb, 0x3b, 0x65, 0x20, 0x6d, 0xeb, 0x72, 0x6b, 0x75, 0x72, 0xeb,
+0x3b, 0x65, 0x20, 0x65, 0x6e, 0x6a, 0x74, 0x65, 0x3b, 0x65, 0x20, 0x70,
+0x72, 0x65, 0x6d, 0x74, 0x65, 0x3b, 0x65, 0x20, 0x73, 0x68, 0x74, 0x75,
+0x6e, 0xeb, 0x64, 0x69, 0x65, 0x3b, 0x68, 0xeb, 0x6e, 0x3b, 0x6d, 0x61,
+0x72, 0x3b, 0x6d, 0xeb, 0x72, 0x3b, 0x65, 0x6e, 0x6a, 0x3b, 0x70, 0x72,
+0x65, 0x3b, 0x73, 0x68, 0x74, 0x64, 0x3b, 0x68, 0x3b, 0x6d, 0x3b, 0x6d,
+0x3b, 0x65, 0x3b, 0x70, 0x3b, 0x73, 0x68, 0x12a5, 0x1211, 0x12f5, 0x3b, 0x1230,
+0x129e, 0x3b, 0x121b, 0x12ad, 0x1230, 0x129e, 0x3b, 0x1228, 0x1261, 0x12d5, 0x3b, 0x1210,
+0x1219, 0x1235, 0x3b, 0x12d3, 0x122d, 0x1265, 0x3b, 0x1245, 0x12f3, 0x121c, 0x12a5, 0x1211,
+0x12f5, 0x3b, 0x1230, 0x129e, 0x3b, 0x121b, 0x12ad, 0x1230, 0x3b, 0x1228, 0x1261, 0x12d5,
+0x3b, 0x1210, 0x1219, 0x1235, 0x3b, 0x12d3, 0x122d, 0x1265, 0x3b, 0x1245, 0x12f3, 0x121c,
+0x12a5, 0x3b, 0x1230, 0x3b, 0x121b, 0x3b, 0x1228, 0x3b, 0x1210, 0x3b, 0x12d3, 0x3b,
+0x1245, 0x627, 0x644, 0x623, 0x62d, 0x62f, 0x3b, 0x627, 0x644, 0x627, 0x62b, 0x646,
+0x64a, 0x646, 0x3b, 0x627, 0x644, 0x62b, 0x644, 0x627, 0x62b, 0x627, 0x621, 0x3b,
+0x627, 0x644, 0x623, 0x631, 0x628, 0x639, 0x627, 0x621, 0x3b, 0x627, 0x644, 0x62e,
+0x645, 0x64a, 0x633, 0x3b, 0x627, 0x644, 0x62c, 0x645, 0x639, 0x629, 0x3b, 0x627,
+0x644, 0x633, 0x628, 0x62a, 0x62d, 0x3b, 0x646, 0x3b, 0x62b, 0x3b, 0x631, 0x3b,
+0x62e, 0x3b, 0x62c, 0x3b, 0x633, 0x64, 0x6f, 0x6d, 0x69, 0x6e, 0x63, 0x68,
+0x65, 0x3b, 0x6c, 0x75, 0x6e, 0x73, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x7a,
+0x3b, 0x6d, 0x69, 0x65, 0x72, 0x63, 0x72, 0x65, 0x73, 0x3b, 0x63, 0x68,
+0x75, 0x65, 0x76, 0x65, 0x73, 0x3b, 0x76, 0x69, 0x65, 0x72, 0x6e, 0x65,
+0x73, 0x3b, 0x73, 0x61, 0x62, 0x61, 0x64, 0x6f, 0x64, 0x6f, 0x6d, 0x3b,
+0x6c, 0x75, 0x6e, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x6d, 0x69, 0x65, 0x3b,
+0x63, 0x68, 0x75, 0x3b, 0x76, 0x69, 0x65, 0x3b, 0x73, 0x61, 0x62, 0x44,
+0x3b, 0x4c, 0x3b, 0x4d, 0x61, 0x3b, 0x4d, 0x69, 0x3b, 0x43, 0x68, 0x3b,
+0x56, 0x3b, 0x53, 0x56f, 0x56b, 0x580, 0x561, 0x56f, 0x56b, 0x3b, 0x565, 0x580,
+0x56f, 0x578, 0x582, 0x577, 0x561, 0x562, 0x569, 0x56b, 0x3b, 0x565, 0x580, 0x565,
+0x584, 0x577, 0x561, 0x562, 0x569, 0x56b, 0x3b, 0x579, 0x578, 0x580, 0x565, 0x584,
+0x577, 0x561, 0x562, 0x569, 0x56b, 0x3b, 0x570, 0x56b, 0x576, 0x563, 0x577, 0x561,
+0x562, 0x569, 0x56b, 0x3b, 0x578, 0x582, 0x580, 0x562, 0x561, 0x569, 0x3b, 0x577,
+0x561, 0x562, 0x561, 0x569, 0x56f, 0x56b, 0x580, 0x3b, 0x565, 0x580, 0x56f, 0x3b,
+0x565, 0x580, 0x584, 0x3b, 0x579, 0x580, 0x584, 0x3b, 0x570, 0x576, 0x563, 0x3b,
+0x578, 0x582, 0x580, 0x3b, 0x577, 0x562, 0x569, 0x53f, 0x3b, 0x535, 0x3b, 0x535,
+0x3b, 0x549, 0x3b, 0x540, 0x3b, 0x548, 0x3b, 0x547, 0x9a6, 0x9c7, 0x993, 0x9ac,
+0x9be, 0x9f0, 0x3b, 0x9b8, 0x9cb, 0x9ae, 0x9ac, 0x9be, 0x9f0, 0x3b, 0x9ae, 0x999,
+0x9cd, 0x997, 0x9b2, 0x9ac, 0x9be, 0x9f0, 0x3b, 0x9ac, 0x9c1, 0x9a7, 0x9ac, 0x9be,
+0x9f0, 0x3b, 0x9ac, 0x9c3, 0x9b9, 0x9b8, 0x9cd, 0x9aa, 0x9a4, 0x9bf, 0x9ac, 0x9be,
+0x9f0, 0x3b, 0x9b6, 0x9c1, 0x995, 0x9cd, 0x9f0, 0x9ac, 0x9be, 0x9f0, 0x3b, 0x9b6,
+0x9a8, 0x9bf, 0x9ac, 0x9be, 0x9f0, 0x9a6, 0x9c7, 0x993, 0x3b, 0x9b8, 0x9cb, 0x9ae,
+0x3b, 0x9ae, 0x999, 0x9cd, 0x997, 0x9b2, 0x3b, 0x9ac, 0x9c1, 0x9a7, 0x3b, 0x9ac,
+0x9c3, 0x9b9, 0x3b, 0x9b6, 0x9c1, 0x995, 0x9cd, 0x9f0, 0x3b, 0x9b6, 0x9a8, 0x9bf,
+0x9a6, 0x3b, 0x9b8, 0x3b, 0x9ae, 0x3b, 0x9ac, 0x3b, 0x9ac, 0x3b, 0x9b6, 0x3b,
+0x9b6, 0x64, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x75, 0x3b, 0x6c, 0x6c, 0x75,
+0x6e, 0x65, 0x73, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x65, 0x73, 0x3b, 0x6d,
+0x69, 0xe9, 0x72, 0x63, 0x6f, 0x6c, 0x65, 0x73, 0x3b, 0x78, 0x75, 0x65,
+0x76, 0x65, 0x73, 0x3b, 0x76, 0x69, 0x65, 0x6e, 0x72, 0x65, 0x73, 0x3b,
+0x73, 0xe1, 0x62, 0x61, 0x64, 0x75, 0x64, 0x6f, 0x6d, 0x3b, 0x6c, 0x6c,
+0x75, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x6d, 0x69, 0xe9, 0x3b, 0x78, 0x75,
+0x65, 0x3b, 0x76, 0x69, 0x65, 0x3b, 0x73, 0xe1, 0x62, 0x44, 0x3b, 0x4c,
+0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x58, 0x3b, 0x56, 0x3b, 0x53, 0x4a, 0x75,
+0x6d, 0x61, 0x70, 0x69, 0x6c, 0x69, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74,
+0x61, 0x74, 0x75, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x6e, 0x6e, 0x65, 0x3b,
+0x4a, 0x75, 0x6d, 0x61, 0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x41, 0x6c, 0x68,
+0x61, 0x6d, 0x69, 0x73, 0x69, 0x3b, 0x49, 0x6a, 0x75, 0x6d, 0x61, 0x61,
+0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x6d, 0x6f, 0x73, 0x69, 0x4a, 0x70, 0x69,
+0x3b, 0x4a, 0x74, 0x74, 0x3b, 0x4a, 0x6e, 0x6e, 0x3b, 0x4a, 0x74, 0x6e,
+0x3b, 0x41, 0x6c, 0x68, 0x3b, 0x49, 0x6a, 0x6d, 0x3b, 0x4a, 0x6d, 0x6f,
+0x4a, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x41, 0x3b, 0x49, 0x3b,
+0x4a, 0x57, 0x61, 0x69, 0x20, 0x59, 0x6f, 0x6b, 0x61, 0x20, 0x42, 0x61,
+0x77, 0x61, 0x69, 0x3b, 0x57, 0x61, 0x69, 0x20, 0x54, 0x75, 0x6e, 0x67,
+0x61, 0x3b, 0x54, 0x6f, 0x6b, 0x69, 0x20, 0x47, 0x69, 0x74, 0x75, 0x6e,
+0x67, 0x3b, 0x54, 0x73, 0x61, 0x6d, 0x20, 0x4b, 0x61, 0x73, 0x75, 0x77,
+0x61, 0x3b, 0x57, 0x61, 0x69, 0x20, 0x4e, 0x61, 0x20, 0x4e, 0x61, 0x73,
+0x3b, 0x57, 0x61, 0x69, 0x20, 0x4e, 0x61, 0x20, 0x54, 0x69, 0x79, 0x6f,
+0x6e, 0x3b, 0x57, 0x61, 0x69, 0x20, 0x4e, 0x61, 0x20, 0x43, 0x68, 0x69,
+0x72, 0x69, 0x6d, 0x59, 0x6f, 0x6b, 0x3b, 0x54, 0x75, 0x6e, 0x67, 0x3b,
+0x47, 0x69, 0x74, 0x75, 0x6e, 0x67, 0x3b, 0x54, 0x73, 0x61, 0x6e, 0x3b,
+0x4e, 0x61, 0x73, 0x3b, 0x4e, 0x61, 0x74, 0x3b, 0x43, 0x68, 0x69, 0x72,
+0x62, 0x61, 0x7a, 0x61, 0x72, 0x3b, 0x62, 0x61, 0x7a, 0x61, 0x72, 0x20,
+0x65, 0x72, 0x74, 0x259, 0x73, 0x69, 0x3b, 0xe7, 0x259, 0x72, 0x15f, 0x259,
+0x6e, 0x62, 0x259, 0x20, 0x61, 0x78, 0x15f, 0x61, 0x6d, 0x131, 0x3b, 0xe7,
+0x259, 0x72, 0x15f, 0x259, 0x6e, 0x62, 0x259, 0x3b, 0x63, 0xfc, 0x6d, 0x259,
+0x20, 0x61, 0x78, 0x15f, 0x61, 0x6d, 0x131, 0x3b, 0x63, 0xfc, 0x6d, 0x259,
+0x3b, 0x15f, 0x259, 0x6e, 0x62, 0x259, 0x42, 0x2e, 0x3b, 0x42, 0x2e, 0x45,
+0x2e, 0x3b, 0xc7, 0x2e, 0x41, 0x2e, 0x3b, 0xc7, 0x2e, 0x3b, 0x43, 0x2e,
+0x41, 0x2e, 0x3b, 0x43, 0x2e, 0x3b, 0x15e, 0x2e, 0x42, 0x2e, 0x3b, 0x42,
+0x2e, 0x65, 0x2e, 0x3b, 0xc7, 0x2e, 0x61, 0x2e, 0x3b, 0xc7, 0x2e, 0x3b,
+0x43, 0x2e, 0x61, 0x2e, 0x3b, 0x43, 0x2e, 0x3b, 0x15e, 0x2e, 0x431, 0x430,
+0x437, 0x430, 0x440, 0x3b, 0x431, 0x430, 0x437, 0x430, 0x440, 0x20, 0x435, 0x440,
+0x442, 0x4d9, 0x441, 0x438, 0x3b, 0x447, 0x4d9, 0x440, 0x448, 0x4d9, 0x43d, 0x431,
+0x4d9, 0x20, 0x430, 0x445, 0x448, 0x430, 0x43c, 0x44b, 0x3b, 0x447, 0x4d9, 0x440,
+0x448, 0x4d9, 0x43d, 0x431, 0x4d9, 0x3b, 0x4b9, 0x4af, 0x43c, 0x4d9, 0x20, 0x430,
+0x445, 0x448, 0x430, 0x43c, 0x44b, 0x3b, 0x4b9, 0x4af, 0x43c, 0x4d9, 0x3b, 0x448,
+0x4d9, 0x43d, 0x431, 0x4d9, 0x411, 0x2e, 0x3b, 0x411, 0x2e, 0x415, 0x2e, 0x3b,
+0x427, 0x2e, 0x410, 0x2e, 0x3b, 0x427, 0x2e, 0x3b, 0x4b8, 0x2e, 0x410, 0x2e,
+0x3b, 0x4b8, 0x2e, 0x3b, 0x428, 0x2e, 0x73, 0x254, 0x301, 0x6e, 0x64, 0x1dd,
+0x3b, 0x6c, 0x1dd, 0x6e, 0x64, 0xed, 0x3b, 0x6d, 0x61, 0x61, 0x64, 0xed,
+0x3b, 0x6d, 0x25b, 0x6b, 0x72, 0x25b, 0x64, 0xed, 0x3b, 0x6a, 0x1dd, 0x1dd,
+0x64, 0xed, 0x3b, 0x6a, 0xfa, 0x6d, 0x62, 0xe1, 0x3b, 0x73, 0x61, 0x6d,
+0x64, 0xed, 0x73, 0x254, 0x301, 0x6e, 0x3b, 0x6c, 0x1dd, 0x6e, 0x3b, 0x6d,
+0x61, 0x61, 0x3b, 0x6d, 0x25b, 0x6b, 0x3b, 0x6a, 0x1dd, 0x1dd, 0x3b, 0x6a,
+0xfa, 0x6d, 0x3b, 0x73, 0x61, 0x6d, 0x73, 0x3b, 0x6c, 0x3b, 0x6d, 0x3b,
+0x6d, 0x3b, 0x6a, 0x3b, 0x6a, 0x3b, 0x73, 0x6b, 0x61, 0x72, 0x69, 0x3b,
+0x6e, 0x74, 0x25b, 0x6e, 0x25b, 0x3b, 0x74, 0x61, 0x72, 0x61, 0x74, 0x61,
+0x3b, 0x61, 0x72, 0x61, 0x62, 0x61, 0x3b, 0x61, 0x6c, 0x61, 0x6d, 0x69,
+0x73, 0x61, 0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x3b, 0x73, 0x69, 0x62, 0x69,
+0x72, 0x69, 0x6b, 0x61, 0x72, 0x3b, 0x6e, 0x74, 0x25b, 0x3b, 0x74, 0x61,
+0x72, 0x3b, 0x61, 0x72, 0x61, 0x3b, 0x61, 0x6c, 0x61, 0x3b, 0x6a, 0x75,
+0x6d, 0x3b, 0x73, 0x69, 0x62, 0x4b, 0x3b, 0x4e, 0x3b, 0x54, 0x3b, 0x41,
+0x3b, 0x41, 0x3b, 0x4a, 0x3b, 0x53, 0x9b0, 0x9ac, 0x9bf, 0x9ac, 0x9be, 0x9b0,
+0x3b, 0x9b8, 0x9cb, 0x9ae, 0x9ac, 0x9be, 0x9b0, 0x3b, 0x9ae, 0x999, 0x9cd, 0x997,
+0x9b2, 0x9ac, 0x9be, 0x9b0, 0x3b, 0x9ac, 0x9c1, 0x9a7, 0x9ac, 0x9be, 0x9b0, 0x3b,
+0x9ac, 0x9c3, 0x9b9, 0x9b8, 0x9cd, 0x9aa, 0x9a4, 0x9bf, 0x9ac, 0x9be, 0x9b0, 0x3b,
+0x9b6, 0x9c1, 0x995, 0x9cd, 0x9b0, 0x9ac, 0x9be, 0x9b0, 0x3b, 0x9b6, 0x9a8, 0x9bf,
+0x9ac, 0x9be, 0x9b0, 0x9b0, 0x9ac, 0x9bf, 0x3b, 0x9b8, 0x9cb, 0x9ae, 0x3b, 0x9ae,
+0x999, 0x9cd, 0x997, 0x9b2, 0x3b, 0x9ac, 0x9c1, 0x9a7, 0x3b, 0x9ac, 0x9c3, 0x9b9,
+0x9b8, 0x9cd, 0x9aa, 0x9a4, 0x9bf, 0x3b, 0x9b6, 0x9c1, 0x995, 0x9cd, 0x9b0, 0x3b,
+0x9b6, 0x9a8, 0x9bf, 0x9b0, 0x3b, 0x9b8, 0x9cb, 0x3b, 0x9ae, 0x3b, 0x9ac, 0x9c1,
+0x3b, 0x9ac, 0x9c3, 0x3b, 0x9b6, 0x9c1, 0x3b, 0x9b6, 0x14b, 0x67, 0x77, 0xe0,
+0x20, 0x6e, 0x254, 0x302, 0x79, 0x3b, 0x14b, 0x67, 0x77, 0xe0, 0x20, 0x6e,
+0x6a, 0x61, 0x14b, 0x67, 0x75, 0x6d, 0x62, 0x61, 0x3b, 0x14b, 0x67, 0x77,
+0xe0, 0x20, 0xfb, 0x6d, 0x3b, 0x14b, 0x67, 0x77, 0xe0, 0x20, 0x14b, 0x67,
+0xea, 0x3b, 0x14b, 0x67, 0x77, 0xe0, 0x20, 0x6d, 0x62, 0x254, 0x6b, 0x3b,
+0x14b, 0x67, 0x77, 0xe0, 0x20, 0x6b, 0x254, 0x254, 0x3b, 0x14b, 0x67, 0x77,
+0xe0, 0x20, 0x6a, 0xf4, 0x6e, 0x6e, 0x254, 0x79, 0x3b, 0x6e, 0x6a, 0x61,
+0x3b, 0x75, 0x75, 0x6d, 0x3b, 0x14b, 0x67, 0x65, 0x3b, 0x6d, 0x62, 0x254,
+0x3b, 0x6b, 0x254, 0x254, 0x3b, 0x6a, 0x6f, 0x6e, 0x6e, 0x3b, 0x6e, 0x3b,
+0x75, 0x3b, 0x14b, 0x3b, 0x6d, 0x3b, 0x6b, 0x3b, 0x6a, 0x69, 0x67, 0x61,
+0x6e, 0x64, 0x65, 0x61, 0x3b, 0x61, 0x73, 0x74, 0x65, 0x6c, 0x65, 0x68,
+0x65, 0x6e, 0x61, 0x3b, 0x61, 0x73, 0x74, 0x65, 0x61, 0x72, 0x74, 0x65,
+0x61, 0x3b, 0x61, 0x73, 0x74, 0x65, 0x61, 0x7a, 0x6b, 0x65, 0x6e, 0x61,
+0x3b, 0x6f, 0x73, 0x74, 0x65, 0x67, 0x75, 0x6e, 0x61, 0x3b, 0x6f, 0x73,
+0x74, 0x69, 0x72, 0x61, 0x6c, 0x61, 0x3b, 0x6c, 0x61, 0x72, 0x75, 0x6e,
+0x62, 0x61, 0x74, 0x61, 0x69, 0x67, 0x2e, 0x3b, 0x61, 0x6c, 0x2e, 0x3b,
+0x61, 0x72, 0x2e, 0x3b, 0x61, 0x7a, 0x2e, 0x3b, 0x6f, 0x67, 0x2e, 0x3b,
+0x6f, 0x72, 0x2e, 0x3b, 0x6c, 0x72, 0x2e, 0x49, 0x3b, 0x41, 0x3b, 0x41,
+0x3b, 0x41, 0x3b, 0x4f, 0x3b, 0x4f, 0x3b, 0x4c, 0x43d, 0x44f, 0x434, 0x437,
+0x435, 0x43b, 0x44f, 0x3b, 0x43f, 0x430, 0x43d, 0x44f, 0x434, 0x437, 0x435, 0x43b,
+0x430, 0x43a, 0x3b, 0x430, 0x45e, 0x442, 0x43e, 0x440, 0x430, 0x43a, 0x3b, 0x441,
+0x435, 0x440, 0x430, 0x434, 0x430, 0x3b, 0x447, 0x430, 0x446, 0x432, 0x435, 0x440,
+0x3b, 0x43f, 0x44f, 0x442, 0x43d, 0x456, 0x446, 0x430, 0x3b, 0x441, 0x443, 0x431,
+0x43e, 0x442, 0x430, 0x43d, 0x434, 0x3b, 0x43f, 0x43d, 0x3b, 0x430, 0x45e, 0x3b,
+0x441, 0x440, 0x3b, 0x447, 0x446, 0x3b, 0x43f, 0x442, 0x3b, 0x441, 0x431, 0x43d,
+0x3b, 0x43f, 0x3b, 0x430, 0x3b, 0x441, 0x3b, 0x447, 0x3b, 0x43f, 0x3b, 0x441,
+0x50, 0x61, 0x20, 0x4d, 0x75, 0x6c, 0x75, 0x6e, 0x67, 0x75, 0x3b, 0x50,
+0x61, 0x6c, 0x69, 0x63, 0x68, 0x69, 0x6d, 0x6f, 0x3b, 0x50, 0x61, 0x6c,
+0x69, 0x63, 0x68, 0x69, 0x62, 0x75, 0x6c, 0x69, 0x3b, 0x50, 0x61, 0x6c,
+0x69, 0x63, 0x68, 0x69, 0x74, 0x61, 0x74, 0x75, 0x3b, 0x50, 0x61, 0x6c,
+0x69, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x3b, 0x50, 0x61, 0x6c, 0x69, 0x63,
+0x68, 0x69, 0x73, 0x61, 0x6e, 0x6f, 0x3b, 0x50, 0x61, 0x63, 0x68, 0x69,
+0x62, 0x65, 0x6c, 0x75, 0x73, 0x68, 0x69, 0x70, 0x61, 0x20, 0x6d, 0x75,
+0x6c, 0x75, 0x6e, 0x67, 0x75, 0x3b, 0x70, 0x61, 0x20, 0x73, 0x68, 0x61,
+0x68, 0x75, 0x76, 0x69, 0x6c, 0x75, 0x68, 0x61, 0x3b, 0x70, 0x61, 0x20,
+0x68, 0x69, 0x76, 0x69, 0x6c, 0x69, 0x3b, 0x70, 0x61, 0x20, 0x68, 0x69,
+0x64, 0x61, 0x74, 0x75, 0x3b, 0x70, 0x61, 0x20, 0x68, 0x69, 0x74, 0x61,
+0x79, 0x69, 0x3b, 0x70, 0x61, 0x20, 0x68, 0x69, 0x68, 0x61, 0x6e, 0x75,
+0x3b, 0x70, 0x61, 0x20, 0x73, 0x68, 0x61, 0x68, 0x75, 0x6c, 0x65, 0x6d,
+0x62, 0x65, 0x6c, 0x61, 0x4d, 0x75, 0x6c, 0x3b, 0x56, 0x69, 0x6c, 0x3b,
+0x48, 0x69, 0x76, 0x3b, 0x48, 0x69, 0x64, 0x3b, 0x48, 0x69, 0x74, 0x3b,
+0x48, 0x69, 0x68, 0x3b, 0x4c, 0x65, 0x6d, 0x4d, 0x3b, 0x4a, 0x3b, 0x48,
+0x3b, 0x48, 0x3b, 0x48, 0x3b, 0x57, 0x3b, 0x4a, 0x930, 0x92c, 0x940, 0x92c,
+0x93e, 0x930, 0x3b, 0x938, 0x94b, 0x92e, 0x92c, 0x93e, 0x930, 0x3b, 0x92e, 0x902,
+0x917, 0x932, 0x92c, 0x93e, 0x930, 0x3b, 0x92c, 0x941, 0x927, 0x92c, 0x93e, 0x930,
+0x3b, 0x92c, 0x943, 0x939, 0x938, 0x94d, 0x92a, 0x924, 0x93f, 0x92c, 0x93e, 0x930,
+0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930, 0x92c, 0x93e, 0x930, 0x3b, 0x938, 0x928,
+0x940, 0x91a, 0x930, 0x1230, 0x1295, 0x1260, 0x122d, 0x20, 0x1245, 0x12f3, 0x12c5, 0x3b,
+0x1230, 0x1291, 0x3b, 0x1230, 0x120a, 0x131d, 0x3b, 0x1208, 0x1313, 0x20, 0x12c8, 0x122a,
+0x20, 0x1208, 0x1265, 0x12cb, 0x3b, 0x12a3, 0x121d, 0x12f5, 0x3b, 0x12a3, 0x122d, 0x1265,
+0x3b, 0x1230, 0x1295, 0x1260, 0x122d, 0x20, 0x123d, 0x1313, 0x12c5, 0x1230, 0x2f, 0x1245,
+0x3b, 0x1230, 0x1291, 0x3b, 0x1230, 0x120a, 0x131d, 0x3b, 0x1208, 0x1313, 0x3b, 0x12a3,
+0x121d, 0x12f5, 0x3b, 0x12a3, 0x122d, 0x1265, 0x3b, 0x1230, 0x2f, 0x123d, 0x1230, 0x3b,
+0x1230, 0x3b, 0x1230, 0x3b, 0x1208, 0x3b, 0x12a3, 0x3b, 0x12a3, 0x3b, 0x1230, 0x930,
+0x92c, 0x93f, 0x92c, 0x93e, 0x930, 0x3b, 0x938, 0x92e, 0x92c, 0x93e, 0x930, 0x3b,
+0x92e, 0x902, 0x917, 0x932, 0x92c, 0x93e, 0x930, 0x3b, 0x92c, 0x941, 0x927, 0x92c,
+0x93e, 0x930, 0x3b, 0x92c, 0x93f, 0x938, 0x94d, 0x925, 0x93f, 0x92c, 0x93e, 0x930,
+0x3b, 0x938, 0x941, 0x941, 0x916, 0x941, 0x930, 0x92c, 0x93e, 0x930, 0x3b, 0x938,
+0x928, 0x93f, 0x92c, 0x93e, 0x930, 0x930, 0x92c, 0x93f, 0x92c, 0x93e, 0x930, 0x3b,
+0x938, 0x92e, 0x92c, 0x93e, 0x930, 0x3b, 0x92e, 0x902, 0x917, 0x932, 0x92c, 0x93e,
+0x930, 0x3b, 0x92c, 0x941, 0x927, 0x92c, 0x93e, 0x930, 0x3b, 0x92c, 0x93f, 0x938,
+0x94d, 0x925, 0x93f, 0x92c, 0x93e, 0x930, 0x3b, 0x938, 0x941, 0x916, 0x941, 0x930,
+0x92c, 0x93e, 0x930, 0x3b, 0x938, 0x928, 0x93f, 0x92c, 0x93e, 0x930, 0x930, 0x92c,
+0x93f, 0x3b, 0x938, 0x92e, 0x3b, 0x92e, 0x902, 0x917, 0x932, 0x3b, 0x92c, 0x941,
+0x927, 0x3b, 0x92c, 0x93f, 0x938, 0x94d, 0x925, 0x93f, 0x3b, 0x938, 0x941, 0x916,
+0x941, 0x930, 0x3b, 0x938, 0x928, 0x93f, 0x930, 0x3b, 0x938, 0x3b, 0x92e, 0x902,
+0x3b, 0x92c, 0x941, 0x3b, 0x92c, 0x93f, 0x3b, 0x938, 0x941, 0x3b, 0x938, 0x6e,
+0x65, 0x64, 0x6a, 0x65, 0x6c, 0x6a, 0x61, 0x3b, 0x70, 0x6f, 0x6e, 0x65,
+0x64, 0x6a, 0x65, 0x6c, 0x6a, 0x61, 0x6b, 0x3b, 0x75, 0x74, 0x6f, 0x72,
+0x61, 0x6b, 0x3b, 0x73, 0x72, 0x69, 0x6a, 0x65, 0x64, 0x61, 0x3b, 0x10d,
+0x65, 0x74, 0x76, 0x72, 0x74, 0x61, 0x6b, 0x3b, 0x70, 0x65, 0x74, 0x61,
+0x6b, 0x3b, 0x73, 0x75, 0x62, 0x6f, 0x74, 0x61, 0x6e, 0x65, 0x64, 0x3b,
+0x70, 0x6f, 0x6e, 0x3b, 0x75, 0x74, 0x6f, 0x3b, 0x73, 0x72, 0x69, 0x3b,
+0x10d, 0x65, 0x74, 0x3b, 0x70, 0x65, 0x74, 0x3b, 0x73, 0x75, 0x62, 0x6e,
+0x3b, 0x70, 0x3b, 0x75, 0x3b, 0x73, 0x3b, 0x10d, 0x3b, 0x70, 0x3b, 0x73,
+0x4e, 0x3b, 0x50, 0x3b, 0x55, 0x3b, 0x53, 0x3b, 0x10c, 0x3b, 0x50, 0x3b,
+0x53, 0x43d, 0x435, 0x434, 0x458, 0x435, 0x459, 0x430, 0x3b, 0x43f, 0x43e, 0x43d,
+0x435, 0x434, 0x458, 0x435, 0x459, 0x430, 0x43a, 0x3b, 0x443, 0x442, 0x43e, 0x440,
+0x430, 0x43a, 0x3b, 0x441, 0x440, 0x438, 0x458, 0x435, 0x434, 0x430, 0x3b, 0x447,
+0x435, 0x442, 0x432, 0x440, 0x442, 0x430, 0x43a, 0x3b, 0x43f, 0x435, 0x442, 0x430,
+0x43a, 0x3b, 0x441, 0x443, 0x431, 0x43e, 0x442, 0x430, 0x43d, 0x435, 0x434, 0x3b,
+0x43f, 0x43e, 0x43d, 0x3b, 0x443, 0x442, 0x43e, 0x3b, 0x441, 0x440, 0x438, 0x3b,
+0x447, 0x435, 0x442, 0x3b, 0x43f, 0x435, 0x442, 0x3b, 0x441, 0x443, 0x431, 0x43d,
+0x3b, 0x43f, 0x3b, 0x443, 0x3b, 0x441, 0x3b, 0x447, 0x3b, 0x43f, 0x3b, 0x441,
+0x53, 0x75, 0x6c, 0x3b, 0x4c, 0x75, 0x6e, 0x3b, 0x4d, 0x65, 0x75, 0x72,
+0x7a, 0x68, 0x3b, 0x4d, 0x65, 0x72, 0x63, 0x2bc, 0x68, 0x65, 0x72, 0x3b,
+0x59, 0x61, 0x6f, 0x75, 0x3b, 0x47, 0x77, 0x65, 0x6e, 0x65, 0x72, 0x3b,
+0x53, 0x61, 0x64, 0x6f, 0x72, 0x6e, 0x53, 0x75, 0x6c, 0x3b, 0x4c, 0x75,
+0x6e, 0x3b, 0x4d, 0x65, 0x75, 0x2e, 0x3b, 0x4d, 0x65, 0x72, 0x2e, 0x3b,
+0x59, 0x61, 0x6f, 0x75, 0x3b, 0x47, 0x77, 0x65, 0x2e, 0x3b, 0x53, 0x61,
+0x64, 0x2e, 0x53, 0x75, 0x3b, 0x4c, 0x3b, 0x4d, 0x7a, 0x3b, 0x4d, 0x63,
+0x3b, 0x59, 0x3b, 0x47, 0x3b, 0x53, 0x61, 0x43d, 0x435, 0x434, 0x435, 0x43b,
+0x44f, 0x3b, 0x43f, 0x43e, 0x43d, 0x435, 0x434, 0x435, 0x43b, 0x43d, 0x438, 0x43a,
+0x3b, 0x432, 0x442, 0x43e, 0x440, 0x43d, 0x438, 0x43a, 0x3b, 0x441, 0x440, 0x44f,
+0x434, 0x430, 0x3b, 0x447, 0x435, 0x442, 0x432, 0x44a, 0x440, 0x442, 0x44a, 0x43a,
+0x3b, 0x43f, 0x435, 0x442, 0x44a, 0x43a, 0x3b, 0x441, 0x44a, 0x431, 0x43e, 0x442,
+0x430, 0x43d, 0x434, 0x3b, 0x43f, 0x43d, 0x3b, 0x432, 0x442, 0x3b, 0x441, 0x440,
+0x3b, 0x447, 0x442, 0x3b, 0x43f, 0x442, 0x3b, 0x441, 0x431, 0x43d, 0x3b, 0x43f,
+0x3b, 0x432, 0x3b, 0x441, 0x3b, 0x447, 0x3b, 0x43f, 0x3b, 0x441, 0x1010, 0x1014,
+0x1004, 0x103a, 0x1039, 0x1002, 0x1014, 0x103d, 0x1031, 0x3b, 0x1010, 0x1014, 0x1004, 0x103a,
+0x1039, 0x101c, 0x102c, 0x3b, 0x1021, 0x1004, 0x103a, 0x1039, 0x1002, 0x102b, 0x3b, 0x1017,
+0x102f, 0x1012, 0x1039, 0x1013, 0x101f, 0x1030, 0x1038, 0x3b, 0x1000, 0x103c, 0x102c, 0x101e,
+0x1015, 0x1010, 0x1031, 0x1038, 0x3b, 0x101e, 0x1031, 0x102c, 0x1000, 0x103c, 0x102c, 0x3b,
+0x1005, 0x1014, 0x1031, 0x1010, 0x3b, 0x1010, 0x3b, 0x1021, 0x3b, 0x1017, 0x3b, 0x1000,
+0x3b, 0x101e, 0x3b, 0x1005, 0x661f, 0x671f, 0x65e5, 0x3b, 0x661f, 0x671f, 0x4e00, 0x3b,
+0x661f, 0x671f, 0x4e8c, 0x3b, 0x661f, 0x671f, 0x4e09, 0x3b, 0x661f, 0x671f, 0x56db, 0x3b,
+0x661f, 0x671f, 0x4e94, 0x3b, 0x661f, 0x671f, 0x516d, 0x65e5, 0x3b, 0x4e00, 0x3b, 0x4e8c,
+0x3b, 0x4e09, 0x3b, 0x56db, 0x3b, 0x4e94, 0x3b, 0x516d, 0x5468, 0x65e5, 0x3b, 0x5468,
+0x4e00, 0x3b, 0x5468, 0x4e8c, 0x3b, 0x5468, 0x4e09, 0x3b, 0x5468, 0x56db, 0x3b, 0x5468,
+0x4e94, 0x3b, 0x5468, 0x516d, 0x64, 0x69, 0x75, 0x6d, 0x65, 0x6e, 0x67, 0x65,
+0x3b, 0x64, 0x69, 0x6c, 0x6c, 0x75, 0x6e, 0x73, 0x3b, 0x64, 0x69, 0x6d,
+0x61, 0x72, 0x74, 0x73, 0x3b, 0x64, 0x69, 0x6d, 0x65, 0x63, 0x72, 0x65,
+0x73, 0x3b, 0x64, 0x69, 0x6a, 0x6f, 0x75, 0x73, 0x3b, 0x64, 0x69, 0x76,
+0x65, 0x6e, 0x64, 0x72, 0x65, 0x73, 0x3b, 0x64, 0x69, 0x73, 0x73, 0x61,
+0x62, 0x74, 0x65, 0x64, 0x67, 0x2e, 0x3b, 0x64, 0x6c, 0x2e, 0x3b, 0x64,
+0x74, 0x2e, 0x3b, 0x64, 0x63, 0x2e, 0x3b, 0x64, 0x6a, 0x2e, 0x3b, 0x64,
+0x76, 0x2e, 0x3b, 0x64, 0x73, 0x2e, 0x44, 0x6f, 0x6d, 0x69, 0x6e, 0x67,
+0x6f, 0x3b, 0x4c, 0x75, 0x6e, 0x65, 0x73, 0x3b, 0x4d, 0x61, 0x72, 0x74,
+0x65, 0x73, 0x3b, 0x4d, 0x69, 0x79, 0x65, 0x72, 0x6b, 0x75, 0x6c, 0x65,
+0x73, 0x3b, 0x48, 0x75, 0x77, 0x65, 0x62, 0x65, 0x73, 0x3b, 0x42, 0x69,
+0x79, 0x65, 0x72, 0x6e, 0x65, 0x73, 0x3b, 0x53, 0x61, 0x62, 0x61, 0x64,
+0x6f, 0x44, 0x6f, 0x6d, 0x3b, 0x4c, 0x75, 0x6e, 0x3b, 0x4d, 0x61, 0x72,
+0x3b, 0x4d, 0x69, 0x79, 0x3b, 0x48, 0x75, 0x77, 0x3b, 0x42, 0x69, 0x79,
+0x3b, 0x53, 0x61, 0x62, 0x44, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b,
+0x48, 0x3b, 0x42, 0x3b, 0x53, 0x41, 0x73, 0x61, 0x6d, 0x61, 0x73, 0x3b,
+0x41, 0x79, 0x6e, 0x61, 0x73, 0x3b, 0x41, 0x73, 0x69, 0x6e, 0x61, 0x73,
+0x3b, 0x41, 0x6b, 0x72, 0x61, 0x73, 0x3b, 0x41, 0x6b, 0x77, 0x61, 0x73,
+0x3b, 0x41, 0x73, 0x69, 0x6d, 0x77, 0x61, 0x73, 0x3b, 0x41, 0x73, 0x69,
+0x1e0d, 0x79, 0x61, 0x73, 0x41, 0x73, 0x61, 0x3b, 0x41, 0x79, 0x6e, 0x3b,
+0x41, 0x73, 0x6e, 0x3b, 0x41, 0x6b, 0x72, 0x3b, 0x41, 0x6b, 0x77, 0x3b,
+0x41, 0x73, 0x6d, 0x3b, 0x41, 0x73, 0x1e0d, 0x41, 0x3b, 0x41, 0x3b, 0x41,
+0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x41, 0x6cc, 0x6d5, 0x6a9, 0x634,
+0x6d5, 0x645, 0x645, 0x6d5, 0x3b, 0x62f, 0x648, 0x648, 0x634, 0x6d5, 0x645, 0x645,
+0x6d5, 0x3b, 0x633, 0x6ce, 0x634, 0x6d5, 0x645, 0x645, 0x6d5, 0x3b, 0x686, 0x648,
+0x627, 0x631, 0x634, 0x6d5, 0x645, 0x645, 0x6d5, 0x3b, 0x67e, 0x6ce, 0x646, 0x62c,
+0x634, 0x6d5, 0x645, 0x645, 0x6d5, 0x3b, 0x6be, 0x6d5, 0x6cc, 0x646, 0x6cc, 0x3b,
+0x634, 0x6d5, 0x645, 0x645, 0x6d5, 0x6cc, 0x3b, 0x62f, 0x3b, 0x633, 0x3b, 0x686,
+0x3b, 0x67e, 0x3b, 0x6be, 0x3b, 0x634, 0xd804, 0xdd22, 0xd804, 0xdd27, 0xd804, 0xdd1d,
+0xd804, 0xdd28, 0xd804, 0xdd1d, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd25, 0xd804,
+0xdd27, 0xd804, 0xdd1f, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b,
+0xd804, 0xdd1f, 0xd804, 0xdd27, 0xd804, 0xdd01, 0xd804, 0xdd09, 0xd804, 0xdd27, 0xd804, 0xdd23,
+0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd1d, 0xd804,
+0xdd2a, 0xd804, 0xdd16, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b,
+0xd804, 0xdd1d, 0xd804, 0xdd33, 0xd804, 0xdd22, 0xd804, 0xdd28, 0xd804, 0xdd25, 0xd804, 0xdd2a,
+0xd804, 0xdd1b, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804,
+0xdd25, 0xd804, 0xdd2a, 0xd804, 0xdd07, 0xd804, 0xdd34, 0xd804, 0xdd07, 0xd804, 0xdd2e, 0xd804,
+0xdd22, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd25,
+0xd804, 0xdd27, 0xd804, 0xdd1a, 0xd804, 0xdd28, 0xd804, 0xdd1d, 0xd804, 0xdd22, 0xd804, 0xdd34,
+0xd804, 0xdd22, 0xd804, 0xdd27, 0xd804, 0xdd1d, 0xd804, 0xdd28, 0x3b, 0xd804, 0xdd25, 0xd804,
+0xdd27, 0xd804, 0xdd1f, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd1f, 0xd804, 0xdd27, 0xd804, 0xdd01,
+0xd804, 0xdd09, 0xd804, 0xdd27, 0xd804, 0xdd23, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd1d, 0xd804,
+0xdd2a, 0xd804, 0xdd16, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd1d, 0xd804, 0xdd33, 0xd804, 0xdd22,
+0xd804, 0xdd28, 0xd804, 0xdd25, 0xd804, 0xdd2a, 0xd804, 0xdd1b, 0xd804, 0xdd34, 0x3b, 0xd804,
+0xdd25, 0xd804, 0xdd2a, 0xd804, 0xdd07, 0xd804, 0xdd34, 0xd804, 0xdd07, 0xd804, 0xdd2e, 0xd804,
+0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd25, 0xd804, 0xdd27, 0xd804, 0xdd1a, 0xd804, 0xdd28,
+0xd804, 0xdd22, 0xd804, 0xdd27, 0x3b, 0xd804, 0xdd25, 0xd804, 0xdd27, 0x3b, 0xd804, 0xdd1f,
+0xd804, 0xdd27, 0x3b, 0xd804, 0xdd1d, 0xd804, 0xdd2a, 0x3b, 0xd804, 0xdd1d, 0xd804, 0xdd33,
+0xd804, 0xdd22, 0xd804, 0xdd28, 0x3b, 0xd804, 0xdd25, 0xd804, 0xdd2a, 0x3b, 0xd804, 0xdd25,
+0xd804, 0xdd27, 0x43a, 0x4c0, 0x438, 0x440, 0x430, 0x3b, 0x43e, 0x440, 0x448, 0x43e,
+0x442, 0x3b, 0x448, 0x438, 0x43d, 0x430, 0x440, 0x430, 0x3b, 0x43a, 0x445, 0x430,
+0x430, 0x440, 0x430, 0x3b, 0x435, 0x430, 0x440, 0x430, 0x3b, 0x43f, 0x4c0, 0x435,
+0x440, 0x430, 0x441, 0x43a, 0x430, 0x3b, 0x448, 0x443, 0x43e, 0x442, 0x43a, 0x4c0,
+0x438, 0x3b, 0x43e, 0x440, 0x3b, 0x448, 0x438, 0x3b, 0x43a, 0x445, 0x430, 0x3b,
+0x435, 0x430, 0x3b, 0x43f, 0x4c0, 0x435, 0x3b, 0x448, 0x443, 0x43e, 0x43a, 0x4c0,
+0x3b, 0x43e, 0x3b, 0x448, 0x3b, 0x43a, 0x445, 0x3b, 0x435, 0x3b, 0x43f, 0x4c0,
+0x3b, 0x448, 0x13a4, 0x13be, 0x13d9, 0x13d3, 0x13c6, 0x13cd, 0x13ac, 0x3b, 0x13a4, 0x13be,
+0x13d9, 0x13d3, 0x13c9, 0x13c5, 0x13af, 0x3b, 0x13d4, 0x13b5, 0x13c1, 0x13a2, 0x13a6, 0x3b,
+0x13e6, 0x13a2, 0x13c1, 0x13a2, 0x13a6, 0x3b, 0x13c5, 0x13a9, 0x13c1, 0x13a2, 0x13a6, 0x3b,
+0x13e7, 0x13be, 0x13a9, 0x13b6, 0x13cd, 0x13d7, 0x3b, 0x13a4, 0x13be, 0x13d9, 0x13d3, 0x13c8,
+0x13d5, 0x13be, 0x13c6, 0x13cd, 0x13ac, 0x3b, 0x13c9, 0x13c5, 0x13af, 0x3b, 0x13d4, 0x13b5,
+0x13c1, 0x3b, 0x13e6, 0x13a2, 0x13c1, 0x3b, 0x13c5, 0x13a9, 0x13c1, 0x3b, 0x13e7, 0x13be,
+0x13a9, 0x3b, 0x13c8, 0x13d5, 0x13be, 0x13c6, 0x3b, 0x13c9, 0x3b, 0x13d4, 0x3b, 0x13e6,
+0x3b, 0x13c5, 0x3b, 0x13e7, 0x3b, 0x13a4, 0x4e, 0x69, 0x74, 0x74, 0x61, 0x6b,
+0x20, 0x48, 0x6f, 0x6c, 0x6c, 0x6f, 0x2bc, 0x3b, 0x4d, 0x61, 0x6e, 0x74,
+0x69, 0x2bc, 0x3b, 0x43, 0x68, 0x6f, 0x73, 0x74, 0x69, 0x2bc, 0x3b, 0x57,
+0x69, 0x6e, 0x73, 0x74, 0x69, 0x2bc, 0x3b, 0x53, 0x6f, 0x69, 0x73, 0x74,
+0x69, 0x2bc, 0x3b, 0x4e, 0x61, 0x6e, 0x6e, 0x61, 0x6c, 0x68, 0x63, 0x68,
+0x69, 0x66, 0x61, 0x2bc, 0x20, 0x4e, 0x69, 0x74, 0x74, 0x61, 0x6b, 0x3b,
+0x4e, 0x69, 0x74, 0x74, 0x61, 0x6b, 0x20, 0x48, 0x6f, 0x6c, 0x6c, 0x6f,
+0x2bc, 0x20, 0x4e, 0x61, 0x6b, 0x66, 0x69, 0x73, 0x68, 0x53, 0x61, 0x6e,
+0x64, 0x65, 0x3b, 0x4f, 0x72, 0x77, 0x6f, 0x6b, 0x75, 0x62, 0x61, 0x6e,
+0x7a, 0x61, 0x3b, 0x4f, 0x72, 0x77, 0x61, 0x6b, 0x61, 0x62, 0x69, 0x72,
+0x69, 0x3b, 0x4f, 0x72, 0x77, 0x61, 0x6b, 0x61, 0x73, 0x68, 0x61, 0x74,
+0x75, 0x3b, 0x4f, 0x72, 0x77, 0x61, 0x6b, 0x61, 0x6e, 0x61, 0x3b, 0x4f,
+0x72, 0x77, 0x61, 0x6b, 0x61, 0x74, 0x61, 0x61, 0x6e, 0x6f, 0x3b, 0x4f,
+0x72, 0x77, 0x61, 0x6d, 0x75, 0x6b, 0x61, 0x61, 0x67, 0x61, 0x53, 0x41,
+0x4e, 0x3b, 0x4f, 0x52, 0x4b, 0x3b, 0x4f, 0x4b, 0x42, 0x3b, 0x4f, 0x4b,
+0x53, 0x3b, 0x4f, 0x4b, 0x4e, 0x3b, 0x4f, 0x4b, 0x54, 0x3b, 0x4f, 0x4d,
+0x4b, 0x53, 0x3b, 0x4b, 0x3b, 0x52, 0x3b, 0x53, 0x3b, 0x4e, 0x3b, 0x54,
+0x3b, 0x4d, 0x9031, 0x65e5, 0x3b, 0x9031, 0x4e00, 0x3b, 0x9031, 0x4e8c, 0x3b, 0x9031,
+0x4e09, 0x3b, 0x9031, 0x56db, 0x3b, 0x9031, 0x4e94, 0x3b, 0x9031, 0x516d, 0x43d, 0x435,
+0x434, 0x463, 0x301, 0x43b, 0x467, 0x3b, 0x43f, 0x43e, 0x43d, 0x435, 0x434, 0x463,
+0x301, 0x43b, 0x44c, 0x43d, 0x438, 0x43a, 0x44a, 0x3b, 0x432, 0x442, 0x43e, 0x301,
+0x440, 0x43d, 0x438, 0x43a, 0x44a, 0x3b, 0x441, 0x440, 0x435, 0x434, 0x430, 0x300,
+0x3b, 0x447, 0x435, 0x442, 0x432, 0x435, 0x440, 0x442, 0x43e, 0x301, 0x43a, 0x44a,
+0x3b, 0x43f, 0x467, 0x442, 0x43e, 0x301, 0x43a, 0x44a, 0x3b, 0x441, 0xa64b, 0x431,
+0x431, 0x461, 0x301, 0x442, 0x430, 0x43d, 0x434, 0x2de7, 0x487, 0x467, 0x3b, 0x43f,
+0x43d, 0x2de3, 0x435, 0x3b, 0x432, 0x442, 0x43e, 0x2dec, 0x487, 0x3b, 0x441, 0x440,
+0x2de3, 0x435, 0x3b, 0x447, 0x435, 0x2de6, 0x487, 0x3b, 0x43f, 0x467, 0x2de6, 0x487,
+0x3b, 0x441, 0xa64b, 0x2de0, 0x487, 0x41d, 0x3b, 0x41f, 0x3b, 0x412, 0x3b, 0x421,
+0x3b, 0x427, 0x3b, 0x41f, 0x3b, 0x421, 0x432, 0x44b, 0x440, 0x441, 0x430, 0x440,
+0x43d, 0x438, 0x43a, 0x443, 0x43d, 0x3b, 0x442, 0x443, 0x43d, 0x442, 0x438, 0x43a,
+0x443, 0x43d, 0x3b, 0x44b, 0x442, 0x43b, 0x430, 0x440, 0x438, 0x43a, 0x443, 0x43d,
+0x3b, 0x44e, 0x43d, 0x43a, 0x443, 0x43d, 0x3b, 0x43a, 0x4d7, 0x4ab, 0x43d, 0x435,
+0x440, 0x43d, 0x438, 0x43a, 0x443, 0x43d, 0x3b, 0x44d, 0x440, 0x43d, 0x435, 0x43a,
+0x443, 0x43d, 0x3b, 0x448, 0x4d1, 0x43c, 0x430, 0x442, 0x43a, 0x443, 0x43d, 0x432,
+0x44b, 0x440, 0x2e, 0x3b, 0x442, 0x443, 0x43d, 0x2e, 0x3b, 0x44b, 0x442, 0x43b,
+0x2e, 0x3b, 0x44e, 0x43d, 0x2e, 0x3b, 0x43a, 0x4d7, 0x4ab, 0x2e, 0x3b, 0x44d,
+0x440, 0x2e, 0x3b, 0x448, 0x4d1, 0x43c, 0x2e, 0x412, 0x3b, 0x422, 0x3b, 0x42b,
+0x3b, 0x42e, 0x3b, 0x41a, 0x3b, 0x42d, 0x3b, 0x428, 0x53, 0x75, 0x6e, 0x6e,
+0x64, 0x61, 0x61, 0x63, 0x68, 0x3b, 0x4d, 0x6f, 0x68, 0x6e, 0x64, 0x61,
+0x61, 0x63, 0x68, 0x3b, 0x44, 0x69, 0x6e, 0x6e, 0x73, 0x64, 0x61, 0x61,
+0x63, 0x68, 0x3b, 0x4d, 0x65, 0x74, 0x77, 0x6f, 0x63, 0x68, 0x3b, 0x44,
+0x75, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x64, 0x61, 0x61, 0x63, 0x68, 0x3b,
+0x46, 0x72, 0x69, 0x69, 0x64, 0x61, 0x61, 0x63, 0x68, 0x3b, 0x53, 0x61,
+0x6d, 0x73, 0x64, 0x61, 0x61, 0x63, 0x68, 0x53, 0x75, 0x2e, 0x3b, 0x4d,
+0x6f, 0x2e, 0x3b, 0x44, 0x69, 0x2e, 0x3b, 0x4d, 0x65, 0x2e, 0x3b, 0x44,
+0x75, 0x2e, 0x3b, 0x46, 0x72, 0x2e, 0x3b, 0x53, 0x61, 0x2e, 0x53, 0x3b,
+0x4d, 0x3b, 0x44, 0x3b, 0x4d, 0x3b, 0x44, 0x3b, 0x46, 0x3b, 0x53, 0x64,
+0x79, 0x20, 0x53, 0x75, 0x6c, 0x3b, 0x64, 0x79, 0x20, 0x4c, 0x75, 0x6e,
+0x3b, 0x64, 0x79, 0x20, 0x4d, 0x65, 0x75, 0x72, 0x74, 0x68, 0x3b, 0x64,
+0x79, 0x20, 0x4d, 0x65, 0x72, 0x68, 0x65, 0x72, 0x3b, 0x64, 0x79, 0x20,
+0x59, 0x6f, 0x77, 0x3b, 0x64, 0x79, 0x20, 0x47, 0x77, 0x65, 0x6e, 0x65,
+0x72, 0x3b, 0x64, 0x79, 0x20, 0x53, 0x61, 0x64, 0x6f, 0x72, 0x6e, 0x53,
+0x75, 0x6c, 0x3b, 0x4c, 0x75, 0x6e, 0x3b, 0x4d, 0x74, 0x68, 0x3b, 0x4d,
+0x68, 0x72, 0x3b, 0x59, 0x6f, 0x77, 0x3b, 0x47, 0x77, 0x65, 0x3b, 0x53,
+0x61, 0x64, 0x64, 0x75, 0x6d, 0x65, 0x6e, 0x69, 0x63, 0x61, 0x3b, 0x6c,
+0x75, 0x6e, 0x69, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x69, 0x3b, 0x6d, 0x65,
+0x72, 0x63, 0x75, 0x72, 0x69, 0x3b, 0x67, 0x68, 0x6a, 0x6f, 0x76, 0x69,
+0x3b, 0x76, 0x65, 0x6e, 0x6e, 0x65, 0x72, 0x69, 0x3b, 0x73, 0x61, 0x62,
+0x62, 0x61, 0x74, 0x75, 0x64, 0x75, 0x6d, 0x2e, 0x3b, 0x6c, 0x75, 0x6e,
+0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x6d, 0x65, 0x72, 0x2e, 0x3b,
+0x67, 0x68, 0x6a, 0x2e, 0x3b, 0x76, 0x65, 0x6e, 0x2e, 0x3b, 0x73, 0x61,
+0x62, 0x2e, 0x44, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x47, 0x3b,
+0x56, 0x3b, 0x53, 0x6e, 0x65, 0x64, 0x11b, 0x6c, 0x65, 0x3b, 0x70, 0x6f,
+0x6e, 0x64, 0x11b, 0x6c, 0xed, 0x3b, 0xfa, 0x74, 0x65, 0x72, 0xfd, 0x3b,
+0x73, 0x74, 0x159, 0x65, 0x64, 0x61, 0x3b, 0x10d, 0x74, 0x76, 0x72, 0x74,
+0x65, 0x6b, 0x3b, 0x70, 0xe1, 0x74, 0x65, 0x6b, 0x3b, 0x73, 0x6f, 0x62,
+0x6f, 0x74, 0x61, 0x6e, 0x65, 0x3b, 0x70, 0x6f, 0x3b, 0xfa, 0x74, 0x3b,
+0x73, 0x74, 0x3b, 0x10d, 0x74, 0x3b, 0x70, 0xe1, 0x3b, 0x73, 0x6f, 0x4e,
+0x3b, 0x50, 0x3b, 0xda, 0x3b, 0x53, 0x3b, 0x10c, 0x3b, 0x50, 0x3b, 0x53,
+0x73, 0xf8, 0x6e, 0x64, 0x61, 0x67, 0x3b, 0x6d, 0x61, 0x6e, 0x64, 0x61,
+0x67, 0x3b, 0x74, 0x69, 0x72, 0x73, 0x64, 0x61, 0x67, 0x3b, 0x6f, 0x6e,
+0x73, 0x64, 0x61, 0x67, 0x3b, 0x74, 0x6f, 0x72, 0x73, 0x64, 0x61, 0x67,
+0x3b, 0x66, 0x72, 0x65, 0x64, 0x61, 0x67, 0x3b, 0x6c, 0xf8, 0x72, 0x64,
+0x61, 0x67, 0x73, 0xf8, 0x6e, 0x2e, 0x3b, 0x6d, 0x61, 0x6e, 0x2e, 0x3b,
+0x74, 0x69, 0x72, 0x73, 0x2e, 0x3b, 0x6f, 0x6e, 0x73, 0x2e, 0x3b, 0x74,
+0x6f, 0x72, 0x73, 0x2e, 0x3b, 0x66, 0x72, 0x65, 0x2e, 0x3b, 0x6c, 0xf8,
+0x72, 0x2e, 0x53, 0x3b, 0x4d, 0x3b, 0x54, 0x3b, 0x4f, 0x3b, 0x54, 0x3b,
+0x46, 0x3b, 0x4c, 0x910, 0x924, 0x92c, 0x93e, 0x930, 0x3b, 0x938, 0x94b, 0x92e,
+0x92c, 0x93e, 0x930, 0x3b, 0x92e, 0x902, 0x917, 0x932, 0x92c, 0x93e, 0x930, 0x3b,
+0x92c, 0x941, 0x927, 0x92c, 0x93e, 0x930, 0x3b, 0x92c, 0x940, 0x930, 0x92c, 0x93e,
+0x930, 0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930, 0x92c, 0x93e, 0x930, 0x3b, 0x936,
+0x928, 0x93f, 0x92c, 0x93e, 0x930, 0x910, 0x924, 0x3b, 0x938, 0x94b, 0x92e, 0x3b,
+0x92e, 0x902, 0x917, 0x932, 0x3b, 0x92c, 0x941, 0x927, 0x3b, 0x92c, 0x940, 0x930,
+0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930, 0x3b, 0x936, 0x928, 0x93f, 0x910, 0x3b,
+0x938, 0x94b, 0x3b, 0x92e, 0x2e, 0x3b, 0x92c, 0x941, 0x2e, 0x3b, 0x92c, 0x940,
+0x2e, 0x3b, 0x936, 0x941, 0x2e, 0x3b, 0x936, 0x2e, 0x910, 0x2e, 0x3b, 0x938,
+0x94b, 0x2e, 0x3b, 0x92e, 0x2e, 0x3b, 0x92c, 0x941, 0x2e, 0x3b, 0x92c, 0x940,
+0x2e, 0x3b, 0x936, 0x941, 0x2e, 0x3b, 0x936, 0x2e, 0xe9, 0x74, 0x69, 0x3b,
+0x6d, 0x254, 0x301, 0x73, 0xfa, 0x3b, 0x6b, 0x77, 0x61, 0x73, 0xfa, 0x3b,
+0x6d, 0x75, 0x6b, 0x254, 0x301, 0x73, 0xfa, 0x3b, 0x14b, 0x67, 0x69, 0x73,
+0xfa, 0x3b, 0x257, 0xf3, 0x6e, 0x25b, 0x73, 0xfa, 0x3b, 0x65, 0x73, 0x61,
+0x253, 0x61, 0x73, 0xfa, 0xe9, 0x74, 0x3b, 0x6d, 0x254, 0x301, 0x73, 0x3b,
+0x6b, 0x77, 0x61, 0x3b, 0x6d, 0x75, 0x6b, 0x3b, 0x14b, 0x67, 0x69, 0x3b,
+0x257, 0xf3, 0x6e, 0x3b, 0x65, 0x73, 0x61, 0x65, 0x3b, 0x6d, 0x3b, 0x6b,
+0x3b, 0x6d, 0x3b, 0x14b, 0x3b, 0x257, 0x3b, 0x65, 0x7a, 0x6f, 0x6e, 0x64,
+0x61, 0x67, 0x3b, 0x6d, 0x61, 0x61, 0x6e, 0x64, 0x61, 0x67, 0x3b, 0x64,
+0x69, 0x6e, 0x73, 0x64, 0x61, 0x67, 0x3b, 0x77, 0x6f, 0x65, 0x6e, 0x73,
+0x64, 0x61, 0x67, 0x3b, 0x64, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x64, 0x61,
+0x67, 0x3b, 0x76, 0x72, 0x69, 0x6a, 0x64, 0x61, 0x67, 0x3b, 0x7a, 0x61,
+0x74, 0x65, 0x72, 0x64, 0x61, 0x67, 0x7a, 0x6f, 0x3b, 0x6d, 0x61, 0x3b,
+0x64, 0x69, 0x3b, 0x77, 0x6f, 0x3b, 0x64, 0x6f, 0x3b, 0x76, 0x72, 0x3b,
+0x7a, 0x61, 0x5a, 0x3b, 0x4d, 0x3b, 0x44, 0x3b, 0x57, 0x3b, 0x44, 0x3b,
+0x56, 0x3b, 0x5a, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b,
+0x3b, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf58, 0xf72, 0xf42, 0xf0b, 0xf51, 0xf58, 0xf62,
+0xf0b, 0x3b, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf63, 0xfb7, 0xf42, 0xf0b, 0xf54, 0xf0b,
+0x3b, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf55, 0xf74, 0xf62, 0xf0b, 0xf56, 0xf74, 0xf0b,
+0x3b, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf54, 0xf0b, 0xf66, 0xf44, 0xf66, 0xf0b, 0x3b,
+0xf42, 0xf5f, 0xf60, 0xf0b, 0xf66, 0xfa4, 0xf7a, 0xf53, 0xf0b, 0xf54, 0xf0b, 0x3b,
+0xf42, 0xf5f, 0xf60, 0xf0b, 0xf49, 0xf72, 0xf0b, 0xf58, 0xf0b, 0xf5f, 0xfb3, 0xf0b,
+0x3b, 0xf58, 0xf72, 0xf62, 0xf0b, 0x3b, 0xf63, 0xfb7, 0xf42, 0xf0b, 0x3b, 0xf55,
+0xf74, 0xf62, 0xf0b, 0x3b, 0xf66, 0xf44, 0xf66, 0xf0b, 0x3b, 0xf66, 0xfa4, 0xf7a,
+0xf53, 0xf0b, 0x3b, 0xf49, 0xf72, 0xf0b, 0xf5f, 0xfb3, 0x3b, 0xf58, 0xf72, 0xf62,
+0x3b, 0xf63, 0xfb7, 0xf42, 0x3b, 0xf55, 0xf74, 0xf62, 0x3b, 0xf66, 0xf44, 0xfb6,
+0x3b, 0xf66, 0xfa4, 0xf7a, 0xf53, 0x3b, 0xf49, 0xf72, 0x4b, 0x69, 0x75, 0x6d,
+0x69, 0x61, 0x3b, 0x4e, 0x6a, 0x75, 0x6d, 0x61, 0x74, 0x61, 0x74, 0x75,
+0x3b, 0x4e, 0x6a, 0x75, 0x6d, 0x61, 0x69, 0x6e, 0x65, 0x3b, 0x4e, 0x6a,
+0x75, 0x6d, 0x61, 0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x41, 0x72, 0x61, 0x6d,
+0x69, 0x74, 0x68, 0x69, 0x3b, 0x4e, 0x6a, 0x75, 0x6d, 0x61, 0x61, 0x3b,
+0x4e, 0x4a, 0x75, 0x6d, 0x61, 0x6d, 0x6f, 0x74, 0x68, 0x69, 0x69, 0x4b,
+0x6d, 0x61, 0x3b, 0x54, 0x61, 0x74, 0x3b, 0x49, 0x6e, 0x65, 0x3b, 0x54,
+0x61, 0x6e, 0x3b, 0x41, 0x72, 0x6d, 0x3b, 0x4d, 0x61, 0x61, 0x3b, 0x4e,
+0x4d, 0x4d, 0x4b, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b, 0x41, 0x3b,
+0x4d, 0x3b, 0x4e, 0xd801, 0xdc1d, 0xd801, 0xdc32, 0xd801, 0xdc4c, 0xd801, 0xdc3c, 0xd801,
+0xdc29, 0x3b, 0xd801, 0xdc23, 0xd801, 0xdc32, 0xd801, 0xdc4c, 0xd801, 0xdc3c, 0xd801, 0xdc29,
+0x3b, 0xd801, 0xdc13, 0xd801, 0xdc2d, 0xd801, 0xdc46, 0xd801, 0xdc3c, 0xd801, 0xdc29, 0x3b,
+0xd801, 0xdc0e, 0xd801, 0xdc2f, 0xd801, 0xdc4c, 0xd801, 0xdc46, 0xd801, 0xdc3c, 0xd801, 0xdc29,
+0x3b, 0xd801, 0xdc1b, 0xd801, 0xdc32, 0xd801, 0xdc49, 0xd801, 0xdc46, 0xd801, 0xdc3c, 0xd801,
+0xdc29, 0x3b, 0xd801, 0xdc19, 0xd801, 0xdc49, 0xd801, 0xdc34, 0xd801, 0xdc3c, 0xd801, 0xdc29,
+0x3b, 0xd801, 0xdc1d, 0xd801, 0xdc30, 0xd801, 0xdc3b, 0xd801, 0xdc32, 0xd801, 0xdc49, 0xd801,
+0xdc3c, 0xd801, 0xdc29, 0xd801, 0xdc1d, 0xd801, 0xdc32, 0xd801, 0xdc4c, 0x3b, 0xd801, 0xdc23,
+0xd801, 0xdc32, 0xd801, 0xdc4c, 0x3b, 0xd801, 0xdc13, 0xd801, 0xdc2d, 0xd801, 0xdc46, 0x3b,
+0xd801, 0xdc0e, 0xd801, 0xdc2f, 0xd801, 0xdc4c, 0x3b, 0xd801, 0xdc1b, 0xd801, 0xdc32, 0xd801,
+0xdc49, 0x3b, 0xd801, 0xdc19, 0xd801, 0xdc49, 0xd801, 0xdc34, 0x3b, 0xd801, 0xdc1d, 0xd801,
+0xdc30, 0xd801, 0xdc3b, 0xd801, 0xdc1d, 0x3b, 0xd801, 0xdc23, 0x3b, 0xd801, 0xdc13, 0x3b,
+0xd801, 0xdc0e, 0x3b, 0xd801, 0xdc1b, 0x3b, 0xd801, 0xdc19, 0x3b, 0xd801, 0xdc1d, 0x53,
+0x75, 0x2e, 0x3b, 0x4d, 0x2e, 0x3b, 0x54, 0x75, 0x2e, 0x3b, 0x57, 0x2e,
+0x3b, 0x54, 0x68, 0x2e, 0x3b, 0x46, 0x2e, 0x3b, 0x53, 0x61, 0x2e, 0xb7,
+0xd801, 0xdc55, 0xd801, 0xdc6d, 0xd801, 0xdc59, 0xd801, 0xdc5b, 0xd801, 0xdc71, 0x3b, 0xb7,
+0xd801, 0xdc65, 0xd801, 0xdc6d, 0xd801, 0xdc59, 0xd801, 0xdc5b, 0xd801, 0xdc71, 0x3b, 0xb7,
+0xd801, 0xdc51, 0xd801, 0xdc75, 0xd801, 0xdc5f, 0xd801, 0xdc5b, 0xd801, 0xdc71, 0x3b, 0xb7,
+0xd801, 0xdc62, 0xd801, 0xdc67, 0xd801, 0xdc59, 0xd801, 0xdc5f, 0xd801, 0xdc5b, 0xd801, 0xdc71,
+0x3b, 0xb7, 0xd801, 0xdc54, 0xd801, 0xdc7b, 0xd801, 0xdc5f, 0xd801, 0xdc5b, 0xd801, 0xdc71,
+0x3b, 0xb7, 0xd801, 0xdc53, 0xd801, 0xdc6e, 0xd801, 0xdc72, 0xd801, 0xdc5b, 0xd801, 0xdc71,
+0x3b, 0xb7, 0xd801, 0xdc55, 0xd801, 0xdc68, 0xd801, 0xdc5b, 0xd801, 0xdc7b, 0xd801, 0xdc5b,
+0xd801, 0xdc71, 0xb7, 0xd801, 0xdc55, 0xd801, 0xdc6d, 0x3b, 0xb7, 0xd801, 0xdc65, 0xd801,
+0xdc6d, 0x3b, 0xb7, 0xd801, 0xdc51, 0xd801, 0xdc75, 0x3b, 0xb7, 0xd801, 0xdc62, 0xd801,
+0xdc67, 0x3b, 0xb7, 0xd801, 0xdc54, 0xd801, 0xdc7b, 0x3b, 0xb7, 0xd801, 0xdc53, 0xd801,
+0xdc6e, 0x3b, 0xb7, 0xd801, 0xdc55, 0xd801, 0xdc68, 0xd801, 0xdc55, 0x3b, 0xd801, 0xdc65,
+0x3b, 0xd801, 0xdc51, 0x3b, 0xd801, 0xdc62, 0x3b, 0xd801, 0xdc54, 0x3b, 0xd801, 0xdc53,
+0x3b, 0xd801, 0xdc55, 0x442, 0x430, 0x440, 0x433, 0x43e, 0x447, 0x438, 0x3b, 0x430,
+0x442, 0x44f, 0x43d, 0x44c, 0x447, 0x438, 0x3b, 0x432, 0x430, 0x441, 0x442, 0x430,
+0x43d, 0x44c, 0x447, 0x438, 0x3b, 0x43a, 0x443, 0x43d, 0x448, 0x43a, 0x430, 0x447,
+0x438, 0x3b, 0x43a, 0x430, 0x43b, 0x43e, 0x43d, 0x44c, 0x447, 0x438, 0x3b, 0x441,
+0x44e, 0x43a, 0x43e, 0x43d, 0x44c, 0x447, 0x438, 0x3b, 0x448, 0x43b, 0x44f, 0x43c,
+0x43e, 0x447, 0x438, 0x442, 0x430, 0x440, 0x433, 0x43e, 0x447, 0x438, 0x441, 0x442,
+0x44d, 0x3b, 0x430, 0x442, 0x44f, 0x43d, 0x44c, 0x447, 0x438, 0x441, 0x442, 0x44d,
+0x3b, 0x432, 0x430, 0x441, 0x442, 0x430, 0x43d, 0x44c, 0x447, 0x438, 0x441, 0x442,
+0x44d, 0x3b, 0x43a, 0x443, 0x43d, 0x448, 0x43a, 0x430, 0x447, 0x438, 0x441, 0x442,
+0x44d, 0x3b, 0x43a, 0x430, 0x43b, 0x43e, 0x43d, 0x44c, 0x447, 0x438, 0x441, 0x442,
+0x44d, 0x3b, 0x441, 0x44e, 0x43a, 0x43e, 0x43d, 0x44c, 0x447, 0x438, 0x441, 0x442,
+0x44d, 0x3b, 0x448, 0x43b, 0x44f, 0x43c, 0x43e, 0x447, 0x438, 0x441, 0x442, 0x44d,
+0x442, 0x430, 0x440, 0x3b, 0x430, 0x442, 0x44f, 0x3b, 0x432, 0x430, 0x441, 0x3b,
+0x43a, 0x443, 0x43d, 0x3b, 0x43a, 0x430, 0x43b, 0x3b, 0x441, 0x44e, 0x43a, 0x3b,
+0x448, 0x43b, 0x44f, 0x64, 0x69, 0x6d, 0x61, 0x6e, 0x109, 0x6f, 0x3b, 0x6c,
+0x75, 0x6e, 0x64, 0x6f, 0x3b, 0x6d, 0x61, 0x72, 0x64, 0x6f, 0x3b, 0x6d,
+0x65, 0x72, 0x6b, 0x72, 0x65, 0x64, 0x6f, 0x3b, 0x135, 0x61, 0x16d, 0x64,
+0x6f, 0x3b, 0x76, 0x65, 0x6e, 0x64, 0x72, 0x65, 0x64, 0x6f, 0x3b, 0x73,
+0x61, 0x62, 0x61, 0x74, 0x6f, 0x64, 0x69, 0x3b, 0x6c, 0x75, 0x3b, 0x6d,
+0x61, 0x3b, 0x6d, 0x65, 0x3b, 0x135, 0x61, 0x3b, 0x76, 0x65, 0x3b, 0x73,
+0x61, 0x64, 0x3b, 0x6c, 0x3b, 0x6d, 0x3b, 0x6d, 0x3b, 0x135, 0x3b, 0x76,
+0x3b, 0x73, 0x70, 0xfc, 0x68, 0x61, 0x70, 0xe4, 0x65, 0x76, 0x3b, 0x65,
+0x73, 0x6d, 0x61, 0x73, 0x70, 0xe4, 0x65, 0x76, 0x3b, 0x74, 0x65, 0x69,
+0x73, 0x69, 0x70, 0xe4, 0x65, 0x76, 0x3b, 0x6b, 0x6f, 0x6c, 0x6d, 0x61,
+0x70, 0xe4, 0x65, 0x76, 0x3b, 0x6e, 0x65, 0x6c, 0x6a, 0x61, 0x70, 0xe4,
+0x65, 0x76, 0x3b, 0x72, 0x65, 0x65, 0x64, 0x65, 0x3b, 0x6c, 0x61, 0x75,
+0x70, 0xe4, 0x65, 0x76, 0x50, 0x3b, 0x45, 0x3b, 0x54, 0x3b, 0x4b, 0x3b,
+0x4e, 0x3b, 0x52, 0x3b, 0x4c, 0x6b, 0x254, 0x73, 0x69, 0x256, 0x61, 0x3b,
+0x64, 0x7a, 0x6f, 0x256, 0x61, 0x3b, 0x62, 0x6c, 0x61, 0x256, 0x61, 0x3b,
+0x6b, 0x75, 0x256, 0x61, 0x3b, 0x79, 0x61, 0x77, 0x6f, 0x256, 0x61, 0x3b,
+0x66, 0x69, 0x256, 0x61, 0x3b, 0x6d, 0x65, 0x6d, 0x6c, 0x65, 0x256, 0x61,
+0x6b, 0x254, 0x73, 0x3b, 0x64, 0x7a, 0x6f, 0x3b, 0x62, 0x6c, 0x61, 0x3b,
+0x6b, 0x75, 0x256, 0x3b, 0x79, 0x61, 0x77, 0x3b, 0x66, 0x69, 0x256, 0x3b,
+0x6d, 0x65, 0x6d, 0x6b, 0x3b, 0x64, 0x3b, 0x62, 0x3b, 0x6b, 0x3b, 0x79,
+0x3b, 0x66, 0x3b, 0x6d, 0x73, 0x254, 0x301, 0x6e, 0x64, 0x254, 0x3b, 0x6d,
+0x254, 0x301, 0x6e, 0x64, 0x69, 0x3b, 0x73, 0x254, 0x301, 0x6e, 0x64, 0x254,
+0x20, 0x6d, 0x259, 0x6c, 0xfa, 0x20, 0x6d, 0x259, 0x301, 0x62, 0x25b, 0x30c,
+0x3b, 0x73, 0x254, 0x301, 0x6e, 0x64, 0x254, 0x20, 0x6d, 0x259, 0x6c, 0xfa,
+0x20, 0x6d, 0x259, 0x301, 0x6c, 0x25b, 0x301, 0x3b, 0x73, 0x254, 0x301, 0x6e,
+0x64, 0x254, 0x20, 0x6d, 0x259, 0x6c, 0xfa, 0x20, 0x6d, 0x259, 0x301, 0x6e,
+0x79, 0x69, 0x3b, 0x66, 0xfa, 0x6c, 0x61, 0x64, 0xe9, 0x3b, 0x73, 0xe9,
+0x72, 0x61, 0x64, 0xe9, 0x73, 0x254, 0x301, 0x6e, 0x3b, 0x6d, 0x254, 0x301,
+0x6e, 0x3b, 0x73, 0x6d, 0x62, 0x3b, 0x73, 0x6d, 0x6c, 0x3b, 0x73, 0x6d,
+0x6e, 0x3b, 0x66, 0xfa, 0x6c, 0x3b, 0x73, 0xe9, 0x72, 0x73, 0x3b, 0x6d,
+0x3b, 0x73, 0x3b, 0x73, 0x3b, 0x73, 0x3b, 0x66, 0x3b, 0x73, 0x73, 0x75,
+0x6e, 0x6e, 0x75, 0x64, 0x61, 0x67, 0x75, 0x72, 0x3b, 0x6d, 0xe1, 0x6e,
+0x61, 0x64, 0x61, 0x67, 0x75, 0x72, 0x3b, 0x74, 0xfd, 0x73, 0x64, 0x61,
+0x67, 0x75, 0x72, 0x3b, 0x6d, 0x69, 0x6b, 0x75, 0x64, 0x61, 0x67, 0x75,
+0x72, 0x3b, 0x68, 0xf3, 0x73, 0x64, 0x61, 0x67, 0x75, 0x72, 0x3b, 0x66,
+0x72, 0xed, 0x67, 0x67, 0x6a, 0x61, 0x64, 0x61, 0x67, 0x75, 0x72, 0x3b,
+0x6c, 0x65, 0x79, 0x67, 0x61, 0x72, 0x64, 0x61, 0x67, 0x75, 0x72, 0x73,
+0x75, 0x6e, 0x3b, 0x6d, 0xe1, 0x6e, 0x3b, 0x74, 0xfd, 0x73, 0x3b, 0x6d,
+0x69, 0x6b, 0x3b, 0x68, 0xf3, 0x73, 0x3b, 0x66, 0x72, 0xed, 0x3b, 0x6c,
+0x65, 0x79, 0x73, 0x75, 0x6e, 0x2e, 0x3b, 0x6d, 0xe1, 0x6e, 0x2e, 0x3b,
+0x74, 0xfd, 0x73, 0x2e, 0x3b, 0x6d, 0x69, 0x6b, 0x2e, 0x3b, 0x68, 0xf3,
+0x73, 0x2e, 0x3b, 0x66, 0x72, 0xed, 0x2e, 0x3b, 0x6c, 0x65, 0x79, 0x2e,
+0x53, 0x3b, 0x4d, 0x3b, 0x54, 0x3b, 0x4d, 0x3b, 0x48, 0x3b, 0x46, 0x3b,
+0x4c, 0x4c, 0x69, 0x6e, 0x67, 0x67, 0x6f, 0x3b, 0x4c, 0x75, 0x6e, 0x65,
+0x73, 0x3b, 0x4d, 0x61, 0x72, 0x74, 0x65, 0x73, 0x3b, 0x4d, 0x69, 0x79,
+0x65, 0x72, 0x6b, 0x75, 0x6c, 0x65, 0x73, 0x3b, 0x48, 0x75, 0x77, 0x65,
+0x62, 0x65, 0x73, 0x3b, 0x42, 0x69, 0x79, 0x65, 0x72, 0x6e, 0x65, 0x73,
+0x3b, 0x53, 0x61, 0x62, 0x61, 0x64, 0x6f, 0x4c, 0x69, 0x6e, 0x3b, 0x4c,
+0x75, 0x6e, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x4d, 0x69, 0x79, 0x3b, 0x48,
+0x75, 0x77, 0x3b, 0x42, 0x69, 0x79, 0x3b, 0x53, 0x61, 0x62, 0x73, 0x75,
+0x6e, 0x6e, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x3b, 0x6d, 0x61, 0x61, 0x6e,
+0x61, 0x6e, 0x74, 0x61, 0x69, 0x3b, 0x74, 0x69, 0x69, 0x73, 0x74, 0x61,
+0x69, 0x3b, 0x6b, 0x65, 0x73, 0x6b, 0x69, 0x76, 0x69, 0x69, 0x6b, 0x6b,
+0x6f, 0x3b, 0x74, 0x6f, 0x72, 0x73, 0x74, 0x61, 0x69, 0x3b, 0x70, 0x65,
+0x72, 0x6a, 0x61, 0x6e, 0x74, 0x61, 0x69, 0x3b, 0x6c, 0x61, 0x75, 0x61,
+0x6e, 0x74, 0x61, 0x69, 0x73, 0x75, 0x6e, 0x6e, 0x75, 0x6e, 0x74, 0x61,
+0x69, 0x6e, 0x61, 0x3b, 0x6d, 0x61, 0x61, 0x6e, 0x61, 0x6e, 0x74, 0x61,
+0x69, 0x6e, 0x61, 0x3b, 0x74, 0x69, 0x69, 0x73, 0x74, 0x61, 0x69, 0x6e,
+0x61, 0x3b, 0x6b, 0x65, 0x73, 0x6b, 0x69, 0x76, 0x69, 0x69, 0x6b, 0x6b,
+0x6f, 0x6e, 0x61, 0x3b, 0x74, 0x6f, 0x72, 0x73, 0x74, 0x61, 0x69, 0x6e,
+0x61, 0x3b, 0x70, 0x65, 0x72, 0x6a, 0x61, 0x6e, 0x74, 0x61, 0x69, 0x6e,
+0x61, 0x3b, 0x6c, 0x61, 0x75, 0x61, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x61,
+0x73, 0x75, 0x3b, 0x6d, 0x61, 0x3b, 0x74, 0x69, 0x3b, 0x6b, 0x65, 0x3b,
+0x74, 0x6f, 0x3b, 0x70, 0x65, 0x3b, 0x6c, 0x61, 0x53, 0x3b, 0x4d, 0x3b,
+0x54, 0x3b, 0x4b, 0x3b, 0x54, 0x3b, 0x50, 0x3b, 0x4c, 0x64, 0x69, 0x6d,
+0x61, 0x6e, 0x63, 0x68, 0x65, 0x3b, 0x6c, 0x75, 0x6e, 0x64, 0x69, 0x3b,
+0x6d, 0x61, 0x72, 0x64, 0x69, 0x3b, 0x6d, 0x65, 0x72, 0x63, 0x72, 0x65,
+0x64, 0x69, 0x3b, 0x6a, 0x65, 0x75, 0x64, 0x69, 0x3b, 0x76, 0x65, 0x6e,
+0x64, 0x72, 0x65, 0x64, 0x69, 0x3b, 0x73, 0x61, 0x6d, 0x65, 0x64, 0x69,
+0x64, 0x69, 0x6d, 0x2e, 0x3b, 0x6c, 0x75, 0x6e, 0x2e, 0x3b, 0x6d, 0x61,
+0x72, 0x2e, 0x3b, 0x6d, 0x65, 0x72, 0x2e, 0x3b, 0x6a, 0x65, 0x75, 0x2e,
+0x3b, 0x76, 0x65, 0x6e, 0x2e, 0x3b, 0x73, 0x61, 0x6d, 0x2e, 0x44, 0x3b,
+0x4c, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x56, 0x3b, 0x53, 0x64,
+0x6f, 0x6d, 0x65, 0x6e, 0x69, 0x65, 0x3b, 0x6c, 0x75, 0x6e, 0x69, 0x73,
+0x3b, 0x6d, 0x61, 0x72, 0x74, 0x61, 0x72, 0x73, 0x3b, 0x6d, 0x69, 0x65,
+0x72, 0x63, 0x75, 0x73, 0x3b, 0x6a, 0x6f, 0x69, 0x62, 0x65, 0x3b, 0x76,
+0x69, 0x6e, 0x61, 0x72, 0x73, 0x3b, 0x73, 0x61, 0x62, 0x69, 0x64, 0x65,
+0x64, 0x6f, 0x6d, 0x3b, 0x6c, 0x75, 0x6e, 0x3b, 0x6d, 0x61, 0x72, 0x3b,
+0x6d, 0x69, 0x65, 0x3b, 0x6a, 0x6f, 0x69, 0x3b, 0x76, 0x69, 0x6e, 0x3b,
+0x73, 0x61, 0x62, 0x64, 0x65, 0x77, 0x6f, 0x3b, 0x61, 0x61, 0x253, 0x6e,
+0x64, 0x65, 0x3b, 0x6d, 0x61, 0x77, 0x62, 0x61, 0x61, 0x72, 0x65, 0x3b,
+0x6e, 0x6a, 0x65, 0x73, 0x6c, 0x61, 0x61, 0x72, 0x65, 0x3b, 0x6e, 0x61,
+0x61, 0x73, 0x61, 0x61, 0x6e, 0x64, 0x65, 0x3b, 0x6d, 0x61, 0x77, 0x6e,
+0x64, 0x65, 0x3b, 0x68, 0x6f, 0x6f, 0x72, 0x65, 0x2d, 0x62, 0x69, 0x69,
+0x72, 0x64, 0x65, 0x77, 0x3b, 0x61, 0x61, 0x253, 0x3b, 0x6d, 0x61, 0x77,
+0x3b, 0x6e, 0x6a, 0x65, 0x3b, 0x6e, 0x61, 0x61, 0x3b, 0x6d, 0x77, 0x64,
+0x3b, 0x68, 0x62, 0x69, 0x64, 0x3b, 0x61, 0x3b, 0x6d, 0x3b, 0x6e, 0x3b,
+0x6e, 0x3b, 0x6d, 0x3b, 0x68, 0xd83a, 0xdd08, 0xd83a, 0xdd2b, 0xd83a, 0xdd2c, 0xd83a,
+0xdd26, 0xd83a, 0xdd2d, 0xd83a, 0xdd2a, 0xd83a, 0xdd46, 0xd83a, 0xdd2b, 0x3b, 0xd83a, 0xdd00,
+0xd83a, 0xdd44, 0xd83a, 0xdd29, 0xd83a, 0xdd35, 0xd83a, 0xdd32, 0xd83a, 0xdd4b, 0xd83a, 0xdd23,
+0xd83a, 0xdd2b, 0x3b, 0xd83a, 0xdd03, 0xd83a, 0xdd22, 0xd83a, 0xdd31, 0xd83a, 0xdd26, 0xd83a,
+0xdd22, 0xd83a, 0xdd44, 0xd83a, 0xdd2a, 0xd83a, 0xdd2b, 0x3b, 0xd83a, 0xdd10, 0xd83a, 0xdd36,
+0xd83a, 0xdd2b, 0xd83a, 0xdd27, 0xd83a, 0xdd24, 0xd83a, 0xdd22, 0xd83a, 0xdd44, 0xd83a, 0xdd2a,
+0xd83a, 0xdd2b, 0x3b, 0xd83a, 0xdd10, 0xd83a, 0xdd22, 0xd83a, 0xdd44, 0xd83a, 0xdd27, 0xd83a,
+0xdd22, 0xd83a, 0xdd44, 0xd83a, 0xdd32, 0xd83a, 0xdd23, 0xd83a, 0xdd2b, 0x3b, 0xd83a, 0xdd03,
+0xd83a, 0xdd22, 0xd83a, 0xdd31, 0xd83a, 0xdd32, 0xd83a, 0xdd23, 0xd83a, 0xdd2b, 0x3b, 0xd83a,
+0xdd16, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0xd83a, 0xdd26, 0xd83a, 0xdd2d, 0xd83a, 0xdd2a, 0xd83a,
+0xdd46, 0xd83a, 0xdd2b, 0xd83a, 0xdd08, 0xd83a, 0xdd2b, 0xd83a, 0xdd2c, 0x3b, 0xd83a, 0xdd00,
+0xd83a, 0xdd44, 0xd83a, 0xdd29, 0xd83a, 0xdd35, 0x3b, 0xd83a, 0xdd03, 0xd83a, 0xdd22, 0xd83a,
+0xdd26, 0x3b, 0xd83a, 0xdd14, 0xd83a, 0xdd2b, 0xd83a, 0xdd27, 0x3b, 0xd83a, 0xdd10, 0xd83a,
+0xdd22, 0xd83a, 0xdd44, 0xd83a, 0xdd27, 0x3b, 0xd83a, 0xdd03, 0xd83a, 0xdd22, 0xd83a, 0xdd23,
+0x3b, 0xd83a, 0xdd16, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0xd83a, 0xdd08, 0x3b, 0xd83a, 0xdd00,
+0xd83a, 0xdd44, 0x3b, 0xd83a, 0xdd03, 0x3b, 0xd83a, 0xdd14, 0x3b, 0xd83a, 0xdd10, 0x3b,
+0xd83a, 0xdd03, 0x3b, 0xd83a, 0xdd16, 0x44, 0x69, 0x44, 0xf2, 0x6d, 0x68, 0x6e,
+0x61, 0x69, 0x63, 0x68, 0x3b, 0x44, 0x69, 0x4c, 0x75, 0x61, 0x69, 0x6e,
+0x3b, 0x44, 0x69, 0x4d, 0xe0, 0x69, 0x72, 0x74, 0x3b, 0x44, 0x69, 0x43,
+0x69, 0x61, 0x64, 0x61, 0x69, 0x6e, 0x3b, 0x44, 0x69, 0x61, 0x72, 0x44,
+0x61, 0x6f, 0x69, 0x6e, 0x3b, 0x44, 0x69, 0x68, 0x41, 0x6f, 0x69, 0x6e,
+0x65, 0x3b, 0x44, 0x69, 0x53, 0x61, 0x74, 0x68, 0x61, 0x69, 0x72, 0x6e,
+0x65, 0x44, 0x69, 0x44, 0x3b, 0x44, 0x69, 0x4c, 0x3b, 0x44, 0x69, 0x4d,
+0x3b, 0x44, 0x69, 0x43, 0x3b, 0x44, 0x69, 0x61, 0x3b, 0x44, 0x69, 0x68,
+0x3b, 0x44, 0x69, 0x53, 0x44, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x43, 0x3b,
+0x41, 0x3b, 0x48, 0x3b, 0x53, 0x48, 0x254, 0x67, 0x62, 0x61, 0x61, 0x3b,
+0x4a, 0x75, 0x3b, 0x4a, 0x75, 0x66, 0x254, 0x3b, 0x53, 0x68, 0x254, 0x3b,
+0x53, 0x6f, 0x6f, 0x3b, 0x53, 0x6f, 0x68, 0x61, 0x61, 0x3b, 0x48, 0x254,
+0x254, 0x48, 0x254, 0x67, 0x3b, 0x4a, 0x75, 0x3b, 0x4a, 0x75, 0x66, 0x3b,
+0x53, 0x68, 0x254, 0x3b, 0x53, 0x6f, 0x6f, 0x3b, 0x53, 0x6f, 0x68, 0x3b,
+0x48, 0x254, 0x254, 0x48, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x53, 0x3b, 0x53,
+0x3b, 0x53, 0x3b, 0x48, 0x64, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x6f, 0x3b,
+0x6c, 0x75, 0x6e, 0x73, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x65, 0x73, 0x3b,
+0x6d, 0xe9, 0x72, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x3b, 0x78, 0x6f, 0x76,
+0x65, 0x73, 0x3b, 0x76, 0x65, 0x6e, 0x72, 0x65, 0x73, 0x3b, 0x73, 0xe1,
+0x62, 0x61, 0x64, 0x6f, 0x64, 0x6f, 0x6d, 0x2e, 0x3b, 0x6c, 0x75, 0x6e,
+0x73, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x6d, 0xe9, 0x72, 0x2e, 0x3b,
+0x78, 0x6f, 0x76, 0x2e, 0x3b, 0x76, 0x65, 0x6e, 0x2e, 0x3b, 0x73, 0xe1,
+0x62, 0x2e, 0x64, 0x2e, 0x3b, 0x6c, 0x2e, 0x3b, 0x6d, 0x2e, 0x3b, 0x6d,
+0x2e, 0x3b, 0x78, 0x2e, 0x3b, 0x76, 0x2e, 0x3b, 0x73, 0x2e, 0x53, 0x61,
+0x62, 0x62, 0x69, 0x69, 0x74, 0x69, 0x3b, 0x42, 0x61, 0x6c, 0x61, 0x7a,
+0x61, 0x3b, 0x4c, 0x77, 0x61, 0x6b, 0x75, 0x62, 0x69, 0x72, 0x69, 0x3b,
+0x4c, 0x77, 0x61, 0x6b, 0x75, 0x73, 0x61, 0x74, 0x75, 0x3b, 0x4c, 0x77,
+0x61, 0x6b, 0x75, 0x6e, 0x61, 0x3b, 0x4c, 0x77, 0x61, 0x6b, 0x75, 0x74,
+0x61, 0x61, 0x6e, 0x6f, 0x3b, 0x4c, 0x77, 0x61, 0x6d, 0x75, 0x6b, 0x61,
+0x61, 0x67, 0x61, 0x53, 0x61, 0x62, 0x3b, 0x42, 0x61, 0x6c, 0x3b, 0x4c,
+0x77, 0x32, 0x3b, 0x4c, 0x77, 0x33, 0x3b, 0x4c, 0x77, 0x34, 0x3b, 0x4c,
+0x77, 0x35, 0x3b, 0x4c, 0x77, 0x36, 0x53, 0x3b, 0x42, 0x3b, 0x4c, 0x3b,
+0x4c, 0x3b, 0x4c, 0x3b, 0x4c, 0x3b, 0x4c, 0x12a5, 0x1281, 0x12f5, 0x3b, 0x1230,
+0x1291, 0x12ed, 0x3b, 0x1220, 0x1209, 0x1235, 0x3b, 0x122b, 0x1265, 0x12d5, 0x3b, 0x1210,
+0x1219, 0x1235, 0x3b, 0x12d3, 0x122d, 0x1260, 0x3b, 0x1240, 0x12f3, 0x121a, 0x1275, 0x12a5,
+0x3b, 0x1230, 0x3b, 0x1220, 0x3b, 0x122b, 0x3b, 0x1210, 0x3b, 0x12d3, 0x3b, 0x1240,
+0x10d9, 0x10d5, 0x10d8, 0x10e0, 0x10d0, 0x3b, 0x10dd, 0x10e0, 0x10e8, 0x10d0, 0x10d1, 0x10d0,
+0x10d7, 0x10d8, 0x3b, 0x10e1, 0x10d0, 0x10db, 0x10e8, 0x10d0, 0x10d1, 0x10d0, 0x10d7, 0x10d8,
+0x3b, 0x10dd, 0x10d7, 0x10ee, 0x10e8, 0x10d0, 0x10d1, 0x10d0, 0x10d7, 0x10d8, 0x3b, 0x10ee,
+0x10e3, 0x10d7, 0x10e8, 0x10d0, 0x10d1, 0x10d0, 0x10d7, 0x10d8, 0x3b, 0x10de, 0x10d0, 0x10e0,
+0x10d0, 0x10e1, 0x10d9, 0x10d4, 0x10d5, 0x10d8, 0x3b, 0x10e8, 0x10d0, 0x10d1, 0x10d0, 0x10d7,
+0x10d8, 0x10d9, 0x10d5, 0x10d8, 0x3b, 0x10dd, 0x10e0, 0x10e8, 0x3b, 0x10e1, 0x10d0, 0x10db,
+0x3b, 0x10dd, 0x10d7, 0x10ee, 0x3b, 0x10ee, 0x10e3, 0x10d7, 0x3b, 0x10de, 0x10d0, 0x10e0,
+0x3b, 0x10e8, 0x10d0, 0x10d1, 0x10d9, 0x3b, 0x10dd, 0x3b, 0x10e1, 0x3b, 0x10dd, 0x3b,
+0x10ee, 0x3b, 0x10de, 0x3b, 0x10e8, 0x53, 0x6f, 0x6e, 0x6e, 0x74, 0x61, 0x67,
+0x3b, 0x4d, 0x6f, 0x6e, 0x74, 0x61, 0x67, 0x3b, 0x44, 0x69, 0x65, 0x6e,
+0x73, 0x74, 0x61, 0x67, 0x3b, 0x4d, 0x69, 0x74, 0x74, 0x77, 0x6f, 0x63,
+0x68, 0x3b, 0x44, 0x6f, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x74, 0x61, 0x67,
+0x3b, 0x46, 0x72, 0x65, 0x69, 0x74, 0x61, 0x67, 0x3b, 0x53, 0x61, 0x6d,
+0x73, 0x74, 0x61, 0x67, 0x53, 0x6f, 0x3b, 0x4d, 0x6f, 0x3b, 0x44, 0x69,
+0x3b, 0x4d, 0x69, 0x3b, 0x44, 0x6f, 0x3b, 0x46, 0x72, 0x3b, 0x53, 0x61,
+0x53, 0x6f, 0x2e, 0x3b, 0x4d, 0x6f, 0x2e, 0x3b, 0x44, 0x69, 0x2e, 0x3b,
+0x4d, 0x69, 0x2e, 0x3b, 0x44, 0x6f, 0x2e, 0x3b, 0x46, 0x72, 0x2e, 0x3b,
+0x53, 0x61, 0x2e, 0x39a, 0x3c5, 0x3c1, 0x3b9, 0x3b1, 0x3ba, 0x3ae, 0x3b, 0x394,
+0x3b5, 0x3c5, 0x3c4, 0x3ad, 0x3c1, 0x3b1, 0x3b, 0x3a4, 0x3c1, 0x3af, 0x3c4, 0x3b7,
+0x3b, 0x3a4, 0x3b5, 0x3c4, 0x3ac, 0x3c1, 0x3c4, 0x3b7, 0x3b, 0x3a0, 0x3ad, 0x3bc,
+0x3c0, 0x3c4, 0x3b7, 0x3b, 0x3a0, 0x3b1, 0x3c1, 0x3b1, 0x3c3, 0x3ba, 0x3b5, 0x3c5,
+0x3ae, 0x3b, 0x3a3, 0x3ac, 0x3b2, 0x3b2, 0x3b1, 0x3c4, 0x3bf, 0x39a, 0x3c5, 0x3c1,
+0x3b, 0x394, 0x3b5, 0x3c5, 0x3b, 0x3a4, 0x3c1, 0x3af, 0x3b, 0x3a4, 0x3b5, 0x3c4,
+0x3b, 0x3a0, 0x3ad, 0x3bc, 0x3b, 0x3a0, 0x3b1, 0x3c1, 0x3b, 0x3a3, 0x3ac, 0x3b2,
+0x39a, 0x3b, 0x394, 0x3b, 0x3a4, 0x3b, 0x3a4, 0x3b, 0x3a0, 0x3b, 0x3a0, 0x3b,
+0x3a3, 0x41, 0x72, 0x61, 0x74, 0x65, 0x129, 0x3b, 0x41, 0x72, 0x61, 0x6b,
+0xf5, 0x69, 0x3b, 0x41, 0x72, 0x61, 0x61, 0x70, 0x79, 0x3b, 0x41, 0x72,
+0x61, 0x72, 0x75, 0x6e, 0x64, 0x79, 0x3b, 0x41, 0x72, 0x61, 0x70, 0x6f,
+0x3b, 0x41, 0x72, 0x61, 0x70, 0x6f, 0x74, 0x65, 0x129, 0x3b, 0x41, 0x72,
+0x61, 0x70, 0x6f, 0x6b, 0xf5, 0x69, 0xab0, 0xab5, 0xabf, 0xab5, 0xabe, 0xab0,
+0x3b, 0xab8, 0xacb, 0xaae, 0xab5, 0xabe, 0xab0, 0x3b, 0xaae, 0xa82, 0xa97, 0xab3,
+0xab5, 0xabe, 0xab0, 0x3b, 0xaac, 0xac1, 0xaa7, 0xab5, 0xabe, 0xab0, 0x3b, 0xa97,
+0xac1, 0xab0, 0xac1, 0xab5, 0xabe, 0xab0, 0x3b, 0xab6, 0xac1, 0xa95, 0xacd, 0xab0,
+0xab5, 0xabe, 0xab0, 0x3b, 0xab6, 0xaa8, 0xabf, 0xab5, 0xabe, 0xab0, 0xab0, 0xab5,
+0xabf, 0x3b, 0xab8, 0xacb, 0xaae, 0x3b, 0xaae, 0xa82, 0xa97, 0xab3, 0x3b, 0xaac,
+0xac1, 0xaa7, 0x3b, 0xa97, 0xac1, 0xab0, 0xac1, 0x3b, 0xab6, 0xac1, 0xa95, 0xacd,
+0xab0, 0x3b, 0xab6, 0xaa8, 0xabf, 0xab0, 0x3b, 0xab8, 0xacb, 0x3b, 0xaae, 0xa82,
+0x3b, 0xaac, 0xac1, 0x3b, 0xa97, 0xac1, 0x3b, 0xab6, 0xac1, 0x3b, 0xab6, 0x43,
+0x68, 0x75, 0x6d, 0x61, 0x70, 0x69, 0x72, 0x69, 0x3b, 0x43, 0x68, 0x75,
+0x6d, 0x61, 0x74, 0x61, 0x74, 0x6f, 0x3b, 0x43, 0x68, 0x75, 0x6d, 0x61,
+0x69, 0x6e, 0x65, 0x3b, 0x43, 0x68, 0x75, 0x6d, 0x61, 0x74, 0x61, 0x6e,
+0x6f, 0x3b, 0x41, 0x72, 0x61, 0x6d, 0x69, 0x73, 0x69, 0x3b, 0x49, 0x63,
+0x68, 0x75, 0x6d, 0x61, 0x3b, 0x45, 0x73, 0x61, 0x62, 0x61, 0x74, 0x6f,
+0x43, 0x70, 0x72, 0x3b, 0x43, 0x74, 0x74, 0x3b, 0x43, 0x6d, 0x6e, 0x3b,
+0x43, 0x6d, 0x74, 0x3b, 0x41, 0x72, 0x73, 0x3b, 0x49, 0x63, 0x6d, 0x3b,
+0x45, 0x73, 0x74, 0x43, 0x3b, 0x43, 0x3b, 0x43, 0x3b, 0x43, 0x3b, 0x41,
+0x3b, 0x49, 0x3b, 0x45, 0x4c, 0x61, 0x68, 0x61, 0x64, 0x69, 0x3b, 0x4c,
+0x69, 0x74, 0x69, 0x6e, 0x69, 0x6e, 0x3b, 0x54, 0x61, 0x6c, 0x61, 0x74,
+0x61, 0x3b, 0x4c, 0x61, 0x72, 0x61, 0x62, 0x61, 0x3b, 0x41, 0x6c, 0x68,
+0x61, 0x6d, 0x69, 0x73, 0x3b, 0x4a, 0x75, 0x6d, 0x6d, 0x61, 0x2bc, 0x61,
+0x3b, 0x41, 0x73, 0x61, 0x62, 0x61, 0x72, 0x4c, 0x61, 0x68, 0x3b, 0x4c,
+0x69, 0x74, 0x3b, 0x54, 0x61, 0x6c, 0x3b, 0x4c, 0x61, 0x72, 0x3b, 0x41,
+0x6c, 0x68, 0x3b, 0x4a, 0x75, 0x6d, 0x3b, 0x41, 0x73, 0x61, 0x4c, 0x3b,
+0x4c, 0x3b, 0x54, 0x3b, 0x4c, 0x3b, 0x41, 0x3b, 0x4a, 0x3b, 0x41, 0x644,
+0x64e, 0x62d, 0x64e, 0x62f, 0x650, 0x3b, 0x644, 0x650, 0x62a, 0x650, 0x646, 0x650,
+0x646, 0x652, 0x3b, 0x62a, 0x64e, 0x644, 0x64e, 0x62a, 0x64e, 0x3b, 0x644, 0x64e,
+0x631, 0x64e, 0x628, 0x64e, 0x3b, 0x623, 0x64e, 0x644, 0x652, 0x62d, 0x64e, 0x645,
+0x650, 0x633, 0x652, 0x3b, 0x62c, 0x64f, 0x645, 0x64e, 0x639, 0x64e, 0x3b, 0x623,
+0x64e, 0x633, 0x64e, 0x628, 0x64e, 0x631, 0x652, 0x644, 0x64e, 0x62d, 0x3b, 0x644,
+0x650, 0x62a, 0x3b, 0x62a, 0x64e, 0x644, 0x3b, 0x644, 0x64e, 0x631, 0x3b, 0x623,
+0x64e, 0x644, 0x652, 0x62d, 0x3b, 0x62c, 0x64f, 0x645, 0x3b, 0x623, 0x64e, 0x633,
+0x64e, 0x4c, 0x101, 0x70, 0x75, 0x6c, 0x65, 0x3b, 0x50, 0x6f, 0x2bb, 0x61,
+0x6b, 0x61, 0x68, 0x69, 0x3b, 0x50, 0x6f, 0x2bb, 0x61, 0x6c, 0x75, 0x61,
+0x3b, 0x50, 0x6f, 0x2bb, 0x61, 0x6b, 0x6f, 0x6c, 0x75, 0x3b, 0x50, 0x6f,
+0x2bb, 0x61, 0x68, 0x101, 0x3b, 0x50, 0x6f, 0x2bb, 0x61, 0x6c, 0x69, 0x6d,
+0x61, 0x3b, 0x50, 0x6f, 0x2bb, 0x61, 0x6f, 0x6e, 0x6f, 0x4c, 0x50, 0x3b,
+0x50, 0x31, 0x3b, 0x50, 0x32, 0x3b, 0x50, 0x33, 0x3b, 0x50, 0x34, 0x3b,
+0x50, 0x35, 0x3b, 0x50, 0x36, 0x5d9, 0x5d5, 0x5dd, 0x20, 0x5e8, 0x5d0, 0x5e9,
+0x5d5, 0x5df, 0x3b, 0x5d9, 0x5d5, 0x5dd, 0x20, 0x5e9, 0x5e0, 0x5d9, 0x3b, 0x5d9,
+0x5d5, 0x5dd, 0x20, 0x5e9, 0x5dc, 0x5d9, 0x5e9, 0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5dd,
+0x20, 0x5e8, 0x5d1, 0x5d9, 0x5e2, 0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5dd, 0x20, 0x5d7,
+0x5de, 0x5d9, 0x5e9, 0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5dd, 0x20, 0x5e9, 0x5d9, 0x5e9,
+0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5dd, 0x20, 0x5e9, 0x5d1, 0x5ea, 0x5d9, 0x5d5, 0x5dd,
+0x20, 0x5d0, 0x5f3, 0x3b, 0x5d9, 0x5d5, 0x5dd, 0x20, 0x5d1, 0x5f3, 0x3b, 0x5d9,
+0x5d5, 0x5dd, 0x20, 0x5d2, 0x5f3, 0x3b, 0x5d9, 0x5d5, 0x5dd, 0x20, 0x5d3, 0x5f3,
+0x3b, 0x5d9, 0x5d5, 0x5dd, 0x20, 0x5d4, 0x5f3, 0x3b, 0x5d9, 0x5d5, 0x5dd, 0x20,
+0x5d5, 0x5f3, 0x3b, 0x5e9, 0x5d1, 0x5ea, 0x5d0, 0x5f3, 0x3b, 0x5d1, 0x5f3, 0x3b,
+0x5d2, 0x5f3, 0x3b, 0x5d3, 0x5f3, 0x3b, 0x5d4, 0x5f3, 0x3b, 0x5d5, 0x5f3, 0x3b,
+0x5e9, 0x5f3, 0x930, 0x935, 0x93f, 0x935, 0x93e, 0x930, 0x3b, 0x938, 0x94b, 0x92e,
+0x935, 0x93e, 0x930, 0x3b, 0x92e, 0x902, 0x917, 0x932, 0x935, 0x93e, 0x930, 0x3b,
+0x92c, 0x941, 0x927, 0x935, 0x93e, 0x930, 0x3b, 0x917, 0x941, 0x930, 0x941, 0x935,
+0x93e, 0x930, 0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930, 0x935, 0x93e, 0x930, 0x3b,
+0x936, 0x928, 0x93f, 0x935, 0x93e, 0x930, 0x930, 0x935, 0x93f, 0x3b, 0x938, 0x94b,
+0x92e, 0x3b, 0x92e, 0x902, 0x917, 0x932, 0x3b, 0x92c, 0x941, 0x927, 0x3b, 0x917,
+0x941, 0x930, 0x941, 0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930, 0x3b, 0x936, 0x928,
+0x93f, 0x930, 0x3b, 0x938, 0x94b, 0x3b, 0x92e, 0x902, 0x3b, 0x92c, 0x941, 0x3b,
+0x917, 0x941, 0x3b, 0x936, 0x941, 0x3b, 0x936, 0x52, 0x61, 0x76, 0x69, 0x77,
+0x61, 0x61, 0x72, 0x3b, 0x53, 0x6f, 0x6d, 0x77, 0x61, 0x61, 0x72, 0x3b,
+0x4d, 0x61, 0x6e, 0x67, 0x61, 0x6c, 0x77, 0x61, 0x61, 0x72, 0x3b, 0x42,
+0x75, 0x64, 0x68, 0x77, 0x61, 0x61, 0x72, 0x3b, 0x47, 0x75, 0x72, 0x75,
+0x77, 0x61, 0x61, 0x72, 0x3b, 0x53, 0x68, 0x75, 0x6b, 0x72, 0x61, 0x77,
+0x61, 0x61, 0x72, 0x3b, 0x53, 0x68, 0x61, 0x6e, 0x69, 0x77, 0x61, 0x61,
+0x72, 0x52, 0x61, 0x76, 0x69, 0x3b, 0x53, 0x6f, 0x6d, 0x3b, 0x4d, 0x61,
+0x6e, 0x67, 0x61, 0x6c, 0x3b, 0x42, 0x75, 0x64, 0x68, 0x3b, 0x47, 0x75,
+0x72, 0x75, 0x3b, 0x53, 0x68, 0x75, 0x6b, 0x72, 0x61, 0x3b, 0x53, 0x68,
+0x61, 0x6e, 0x69, 0x52, 0x61, 0x3b, 0x53, 0x6f, 0x3b, 0x4d, 0x61, 0x3b,
+0x42, 0x75, 0x3b, 0x47, 0x75, 0x3b, 0x53, 0x68, 0x3b, 0x53, 0x68, 0x61,
+0x76, 0x61, 0x73, 0xe1, 0x72, 0x6e, 0x61, 0x70, 0x3b, 0x68, 0xe9, 0x74,
+0x66, 0x151, 0x3b, 0x6b, 0x65, 0x64, 0x64, 0x3b, 0x73, 0x7a, 0x65, 0x72,
+0x64, 0x61, 0x3b, 0x63, 0x73, 0xfc, 0x74, 0xf6, 0x72, 0x74, 0xf6, 0x6b,
+0x3b, 0x70, 0xe9, 0x6e, 0x74, 0x65, 0x6b, 0x3b, 0x73, 0x7a, 0x6f, 0x6d,
+0x62, 0x61, 0x74, 0x56, 0x3b, 0x48, 0x3b, 0x4b, 0x3b, 0x53, 0x7a, 0x65,
+0x3b, 0x43, 0x73, 0x3b, 0x50, 0x3b, 0x53, 0x7a, 0x6f, 0x56, 0x3b, 0x48,
+0x3b, 0x4b, 0x3b, 0x53, 0x7a, 0x3b, 0x43, 0x73, 0x3b, 0x50, 0x3b, 0x53,
+0x7a, 0x73, 0x75, 0x6e, 0x6e, 0x75, 0x64, 0x61, 0x67, 0x75, 0x72, 0x3b,
+0x6d, 0xe1, 0x6e, 0x75, 0x64, 0x61, 0x67, 0x75, 0x72, 0x3b, 0xfe, 0x72,
+0x69, 0xf0, 0x6a, 0x75, 0x64, 0x61, 0x67, 0x75, 0x72, 0x3b, 0x6d, 0x69,
+0xf0, 0x76, 0x69, 0x6b, 0x75, 0x64, 0x61, 0x67, 0x75, 0x72, 0x3b, 0x66,
+0x69, 0x6d, 0x6d, 0x74, 0x75, 0x64, 0x61, 0x67, 0x75, 0x72, 0x3b, 0x66,
+0xf6, 0x73, 0x74, 0x75, 0x64, 0x61, 0x67, 0x75, 0x72, 0x3b, 0x6c, 0x61,
+0x75, 0x67, 0x61, 0x72, 0x64, 0x61, 0x67, 0x75, 0x72, 0x73, 0x75, 0x6e,
+0x2e, 0x3b, 0x6d, 0xe1, 0x6e, 0x2e, 0x3b, 0xfe, 0x72, 0x69, 0x2e, 0x3b,
+0x6d, 0x69, 0xf0, 0x2e, 0x3b, 0x66, 0x69, 0x6d, 0x2e, 0x3b, 0x66, 0xf6,
+0x73, 0x2e, 0x3b, 0x6c, 0x61, 0x75, 0x2e, 0x53, 0x3b, 0x4d, 0x3b, 0xde,
+0x3b, 0x4d, 0x3b, 0x46, 0x3b, 0x46, 0x3b, 0x4c, 0x53, 0x1ecd, 0x6e, 0x64,
+0x65, 0x65, 0x3b, 0x4d, 0x1ecd, 0x6e, 0x64, 0x65, 0x3b, 0x54, 0x69, 0x75,
+0x7a, 0x64, 0x65, 0x65, 0x3b, 0x57, 0x65, 0x6e, 0x65, 0x7a, 0x64, 0x65,
+0x65, 0x3b, 0x54, 0x1ecd, 0x1ecd, 0x7a, 0x64, 0x65, 0x65, 0x3b, 0x46, 0x72,
+0x61, 0x1ecb, 0x64, 0x65, 0x65, 0x3b, 0x53, 0x61, 0x74, 0x1ecd, 0x64, 0x65,
+0x65, 0x53, 0x1ecd, 0x6e, 0x3b, 0x4d, 0x1ecd, 0x6e, 0x3b, 0x54, 0x69, 0x75,
+0x3b, 0x57, 0x65, 0x6e, 0x3b, 0x54, 0x1ecd, 0x1ecd, 0x3b, 0x46, 0x72, 0x61,
+0x1ecb, 0x3b, 0x53, 0x61, 0x74, 0x70, 0x61, 0x73, 0x65, 0x70, 0x65, 0x69,
+0x76, 0x69, 0x3b, 0x76, 0x75, 0x6f, 0x73, 0x73, 0x61, 0x72, 0x67, 0xe2,
+0x3b, 0x6d, 0x61, 0x6a, 0x65, 0x62, 0x61, 0x72, 0x67, 0xe2, 0x3b, 0x6b,
+0x6f, 0x73, 0x6b, 0x6f, 0x6b, 0x6b, 0x6f, 0x3b, 0x74, 0x75, 0x6f, 0x72,
+0xe2, 0x73, 0x74, 0xe2, 0x68, 0x3b, 0x76, 0xe1, 0x73, 0x74, 0x75, 0x70,
+0x70, 0x65, 0x69, 0x76, 0x69, 0x3b, 0x6c, 0xe1, 0x76, 0x75, 0x72, 0x64,
+0xe2, 0x68, 0x70, 0x61, 0x73, 0x65, 0x70, 0x65, 0x65, 0x69, 0x76, 0x69,
+0x3b, 0x76, 0x75, 0x6f, 0x73, 0x73, 0x61, 0x61, 0x72, 0x67, 0xe2, 0x3b,
+0x6d, 0x61, 0x6a, 0x65, 0x62, 0x61, 0x61, 0x72, 0x67, 0xe2, 0x3b, 0x6b,
+0x6f, 0x73, 0x6b, 0x6f, 0x68, 0x6f, 0x3b, 0x74, 0x75, 0x6f, 0x72, 0xe2,
+0x73, 0x74, 0x75, 0x76, 0x3b, 0x76, 0xe1, 0x73, 0x74, 0x75, 0x70, 0x70,
+0x65, 0x65, 0x69, 0x76, 0x69, 0x3b, 0x6c, 0xe1, 0x76, 0x75, 0x72, 0x64,
+0x75, 0x76, 0x70, 0x61, 0x73, 0x3b, 0x76, 0x75, 0x6f, 0x3b, 0x6d, 0x61,
+0x6a, 0x3b, 0x6b, 0x6f, 0x73, 0x3b, 0x74, 0x75, 0x6f, 0x3b, 0x76, 0xe1,
+0x73, 0x3b, 0x6c, 0xe1, 0x76, 0x70, 0x3b, 0x56, 0x3b, 0x4d, 0x3b, 0x4b,
+0x3b, 0x54, 0x3b, 0x56, 0x3b, 0x4c, 0x4d, 0x69, 0x6e, 0x67, 0x67, 0x75,
+0x3b, 0x53, 0x65, 0x6e, 0x69, 0x6e, 0x3b, 0x53, 0x65, 0x6c, 0x61, 0x73,
+0x61, 0x3b, 0x52, 0x61, 0x62, 0x75, 0x3b, 0x4b, 0x61, 0x6d, 0x69, 0x73,
+0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0x3b, 0x53, 0x61, 0x62, 0x74, 0x75,
+0x4d, 0x69, 0x6e, 0x3b, 0x53, 0x65, 0x6e, 0x3b, 0x53, 0x65, 0x6c, 0x3b,
+0x52, 0x61, 0x62, 0x3b, 0x4b, 0x61, 0x6d, 0x3b, 0x4a, 0x75, 0x6d, 0x3b,
+0x53, 0x61, 0x62, 0x4d, 0x3b, 0x53, 0x3b, 0x53, 0x3b, 0x52, 0x3b, 0x4b,
+0x3b, 0x4a, 0x3b, 0x53, 0x64, 0x6f, 0x6d, 0x69, 0x6e, 0x69, 0x63, 0x61,
+0x3b, 0x6c, 0x75, 0x6e, 0x65, 0x64, 0x69, 0x3b, 0x6d, 0x61, 0x72, 0x74,
+0x65, 0x64, 0x69, 0x3b, 0x6d, 0x65, 0x72, 0x63, 0x75, 0x72, 0x69, 0x64,
+0x69, 0x3b, 0x6a, 0x6f, 0x76, 0x65, 0x64, 0x69, 0x3b, 0x76, 0x65, 0x6e,
+0x65, 0x72, 0x64, 0x69, 0x3b, 0x73, 0x61, 0x62, 0x62, 0x61, 0x74, 0x6f,
+0x64, 0x6f, 0x6d, 0x3b, 0x6c, 0x75, 0x6e, 0x3b, 0x6d, 0x61, 0x72, 0x3b,
+0x6d, 0x65, 0x72, 0x3b, 0x6a, 0x6f, 0x76, 0x3b, 0x76, 0x65, 0x6e, 0x3b,
+0x73, 0x61, 0x62, 0x64, 0x3b, 0x6c, 0x3b, 0x6d, 0x3b, 0x6d, 0x3b, 0x6a,
+0x3b, 0x76, 0x3b, 0x73, 0x73, 0x6f, 0x6c, 0x65, 0x64, 0xed, 0x3b, 0x6c,
+0x75, 0x6e, 0x65, 0x64, 0xed, 0x3b, 0x6d, 0x61, 0x72, 0x64, 0xed, 0x3b,
+0x6d, 0x65, 0x72, 0x63, 0x75, 0x72, 0x64, 0xed, 0x3b, 0x6a, 0x6f, 0x76,
+0x65, 0x64, 0xed, 0x3b, 0x76, 0x65, 0x6e, 0x65, 0x72, 0x64, 0xed, 0x3b,
+0x73, 0x61, 0x74, 0x75, 0x72, 0x64, 0xed, 0x73, 0x6f, 0x6c, 0x2e, 0x3b,
+0x6c, 0x75, 0x6e, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x6d, 0x65,
+0x72, 0x2e, 0x3b, 0x6a, 0x6f, 0x76, 0x2e, 0x3b, 0x76, 0x65, 0x6e, 0x2e,
+0x3b, 0x73, 0x61, 0x74, 0x2e, 0x53, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x4d,
+0x3b, 0x4a, 0x3b, 0x56, 0x3b, 0x53, 0x14c8, 0x1466, 0x144f, 0x1591, 0x152d, 0x1585,
+0x3b, 0x14c7, 0x14a1, 0x1490, 0x153e, 0x152d, 0x1405, 0x3b, 0x14c7, 0x14a1, 0x1490, 0x153e,
+0x152d, 0x1405, 0x14d5, 0x1585, 0x146d, 0x3b, 0x1431, 0x1593, 0x1466, 0x14ef, 0x1585, 0x3b,
+0x14ef, 0x1455, 0x14bb, 0x14a5, 0x1585, 0x3b, 0x1455, 0x14ea, 0x14d5, 0x14bb, 0x14a5, 0x1405,
+0x1466, 0x3b, 0x14c8, 0x1466, 0x14f0, 0x1591, 0x152d, 0x14db, 0x1550, 0x14c2, 0x140a, 0x1585,
+0x44, 0xe9, 0x20, 0x44, 0x6f, 0x6d, 0x68, 0x6e, 0x61, 0x69, 0x67, 0x68,
+0x3b, 0x44, 0xe9, 0x20, 0x4c, 0x75, 0x61, 0x69, 0x6e, 0x3b, 0x44, 0xe9,
+0x20, 0x4d, 0xe1, 0x69, 0x72, 0x74, 0x3b, 0x44, 0xe9, 0x20, 0x43, 0xe9,
+0x61, 0x64, 0x61, 0x6f, 0x69, 0x6e, 0x3b, 0x44, 0xe9, 0x61, 0x72, 0x64,
+0x61, 0x6f, 0x69, 0x6e, 0x3b, 0x44, 0xe9, 0x20, 0x68, 0x41, 0x6f, 0x69,
+0x6e, 0x65, 0x3b, 0x44, 0xe9, 0x20, 0x53, 0x61, 0x74, 0x68, 0x61, 0x69,
+0x72, 0x6e, 0x44, 0x6f, 0x6d, 0x68, 0x3b, 0x4c, 0x75, 0x61, 0x6e, 0x3b,
+0x4d, 0xe1, 0x69, 0x72, 0x74, 0x3b, 0x43, 0xe9, 0x61, 0x64, 0x3b, 0x44,
+0xe9, 0x61, 0x72, 0x3b, 0x41, 0x6f, 0x69, 0x6e, 0x65, 0x3b, 0x53, 0x61,
+0x74, 0x68, 0x44, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x43, 0x3b, 0x44, 0x3b,
+0x41, 0x3b, 0x53, 0x64, 0x6f, 0x6d, 0x65, 0x6e, 0x69, 0x63, 0x61, 0x3b,
+0x6c, 0x75, 0x6e, 0x65, 0x64, 0xec, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x65,
+0x64, 0xec, 0x3b, 0x6d, 0x65, 0x72, 0x63, 0x6f, 0x6c, 0x65, 0x64, 0xec,
+0x3b, 0x67, 0x69, 0x6f, 0x76, 0x65, 0x64, 0xec, 0x3b, 0x76, 0x65, 0x6e,
+0x65, 0x72, 0x64, 0xec, 0x3b, 0x73, 0x61, 0x62, 0x61, 0x74, 0x6f, 0x64,
+0x6f, 0x6d, 0x3b, 0x6c, 0x75, 0x6e, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x6d,
+0x65, 0x72, 0x3b, 0x67, 0x69, 0x6f, 0x3b, 0x76, 0x65, 0x6e, 0x3b, 0x73,
+0x61, 0x62, 0x65e5, 0x66dc, 0x65e5, 0x3b, 0x6708, 0x66dc, 0x65e5, 0x3b, 0x706b, 0x66dc,
+0x65e5, 0x3b, 0x6c34, 0x66dc, 0x65e5, 0x3b, 0x6728, 0x66dc, 0x65e5, 0x3b, 0x91d1, 0x66dc,
+0x65e5, 0x3b, 0x571f, 0x66dc, 0x65e5, 0x65e5, 0x3b, 0x6708, 0x3b, 0x706b, 0x3b, 0x6c34,
+0x3b, 0x6728, 0x3b, 0x91d1, 0x3b, 0x571f, 0x41, 0x68, 0x61, 0x64, 0x3b, 0x53,
+0x65, 0x6e, 0x69, 0x6e, 0x3b, 0x53, 0x65, 0x6c, 0x61, 0x73, 0x61, 0x3b,
+0x52, 0x61, 0x62, 0x75, 0x3b, 0x4b, 0x61, 0x6d, 0x69, 0x73, 0x3b, 0x4a,
+0x75, 0x6d, 0x61, 0x74, 0x3b, 0x53, 0x61, 0x62, 0x74, 0x75, 0x41, 0x68,
+0x61, 0x64, 0x3b, 0x53, 0x65, 0x6e, 0x3b, 0x53, 0x65, 0x6c, 0x3b, 0x52,
+0x61, 0x62, 0x3b, 0x4b, 0x61, 0x6d, 0x3b, 0x4a, 0x75, 0x6d, 0x3b, 0x53,
+0x61, 0x62, 0x41, 0x3b, 0x53, 0x3b, 0x53, 0x3b, 0x52, 0x3b, 0x4b, 0x3b,
+0x4a, 0x3b, 0x53, 0x4c, 0x61, 0x64, 0x69, 0x3b, 0x4c, 0x69, 0x6e, 0x74,
+0x61, 0x6e, 0x69, 0x3b, 0x54, 0x61, 0x6c, 0x61, 0x74, 0x61, 0x3b, 0x4c,
+0x61, 0x72, 0x62, 0x61, 0x3b, 0x4c, 0x61, 0x6d, 0x69, 0x74, 0x3b, 0x4a,
+0x75, 0x6d, 0x61, 0x3b, 0x41, 0x73, 0x61, 0x62, 0x61, 0x72, 0x4c, 0x61,
+0x64, 0x3b, 0x4c, 0x69, 0x6e, 0x3b, 0x54, 0x61, 0x6c, 0x3b, 0x4c, 0x61,
+0x72, 0x3b, 0x4c, 0x61, 0x6d, 0x3b, 0x4a, 0x75, 0x6d, 0x3b, 0x41, 0x73,
+0x61, 0x44, 0x69, 0x6d, 0x61, 0x73, 0x3b, 0x54, 0x65, 0x6e, 0x65, 0x14b,
+0x3b, 0x54, 0x61, 0x6c, 0x61, 0x74, 0x61, 0x3b, 0x41, 0x6c, 0x61, 0x72,
+0x62, 0x61, 0x79, 0x3b, 0x41, 0x72, 0x61, 0x6d, 0x69, 0x73, 0x61, 0x79,
+0x3b, 0x41, 0x72, 0x6a, 0x75, 0x6d, 0x61, 0x3b, 0x53, 0x69, 0x62, 0x69,
+0x74, 0x69, 0x44, 0x69, 0x6d, 0x3b, 0x54, 0x65, 0x6e, 0x3b, 0x54, 0x61,
+0x6c, 0x3b, 0x41, 0x6c, 0x61, 0x3b, 0x41, 0x72, 0x61, 0x3b, 0x41, 0x72,
+0x6a, 0x3b, 0x53, 0x69, 0x62, 0x44, 0x3b, 0x54, 0x3b, 0x54, 0x3b, 0x41,
+0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x53, 0x64, 0x75, 0x6d, 0x69, 0x6e, 0x67,
+0x75, 0x3b, 0x73, 0x69, 0x67, 0x75, 0x6e, 0x64, 0x61, 0x2d, 0x66, 0x65,
+0x72, 0x61, 0x3b, 0x74, 0x65, 0x72, 0x73, 0x61, 0x2d, 0x66, 0x65, 0x72,
+0x61, 0x3b, 0x6b, 0x75, 0x61, 0x72, 0x74, 0x61, 0x2d, 0x66, 0x65, 0x72,
+0x61, 0x3b, 0x6b, 0x69, 0x6e, 0x74, 0x61, 0x2d, 0x66, 0x65, 0x72, 0x61,
+0x3b, 0x73, 0x65, 0x73, 0x74, 0x61, 0x2d, 0x66, 0x65, 0x72, 0x61, 0x3b,
+0x73, 0xe1, 0x62, 0x61, 0x64, 0x75, 0x64, 0x75, 0x6d, 0x3b, 0x73, 0x69,
+0x67, 0x3b, 0x74, 0x65, 0x72, 0x3b, 0x6b, 0x75, 0x61, 0x3b, 0x6b, 0x69,
+0x6e, 0x3b, 0x73, 0x65, 0x73, 0x3b, 0x73, 0x61, 0x62, 0x44, 0x3b, 0x53,
+0x3b, 0x54, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x53, 0x3b, 0x53, 0x41, 0x63,
+0x65, 0x72, 0x3b, 0x41, 0x72, 0x69, 0x6d, 0x3b, 0x41, 0x72, 0x61, 0x6d,
+0x3b, 0x41, 0x68, 0x61, 0x64, 0x3b, 0x41, 0x6d, 0x68, 0x61, 0x64, 0x3b,
+0x53, 0x65, 0x6d, 0x3b, 0x53, 0x65, 0x64, 0x59, 0x61, 0x6e, 0x61, 0x73,
+0x73, 0x3b, 0x53, 0x61, 0x6e, 0x61, 0x73, 0x73, 0x3b, 0x4b, 0x72, 0x61,
+0x1e0d, 0x61, 0x73, 0x73, 0x3b, 0x4b, 0x75, 0x1e93, 0x61, 0x73, 0x73, 0x3b,
+0x53, 0x61, 0x6d, 0x61, 0x73, 0x73, 0x3b, 0x53, 0x1e0d, 0x69, 0x73, 0x61,
+0x73, 0x73, 0x3b, 0x53, 0x61, 0x79, 0x61, 0x73, 0x73, 0x41, 0x63, 0x65,
+0x3b, 0x41, 0x72, 0x69, 0x3b, 0x41, 0x72, 0x61, 0x3b, 0x41, 0x68, 0x61,
+0x3b, 0x41, 0x6d, 0x68, 0x3b, 0x53, 0x65, 0x6d, 0x3b, 0x53, 0x65, 0x64,
+0x59, 0x61, 0x6e, 0x3b, 0x53, 0x61, 0x6e, 0x3b, 0x4b, 0x72, 0x61, 0x1e0d,
+0x3b, 0x4b, 0x75, 0x1e93, 0x3b, 0x53, 0x61, 0x6d, 0x3b, 0x53, 0x1e0d, 0x69,
+0x73, 0x3b, 0x53, 0x61, 0x79, 0x59, 0x3b, 0x53, 0x3b, 0x4b, 0x3b, 0x4b,
+0x3b, 0x53, 0x3b, 0x53, 0x3b, 0x53, 0x43, 0x3b, 0x52, 0x3b, 0x52, 0x3b,
+0x48, 0x3b, 0x4d, 0x3b, 0x53, 0x3b, 0x53, 0x73, 0x254, 0x6e, 0x64, 0x69,
+0x3b, 0x6c, 0x75, 0x6e, 0x64, 0x69, 0x3b, 0x6d, 0x61, 0x72, 0x64, 0x69,
+0x3b, 0x6d, 0x25b, 0x72, 0x6b, 0x25b, 0x72, 0x25b, 0x64, 0x69, 0x3b, 0x79,
+0x65, 0x64, 0x69, 0x3b, 0x76, 0x61, 0x14b, 0x64, 0x25b, 0x72, 0x25b, 0x64,
+0x69, 0x3b, 0x6d, 0x254, 0x6e, 0x254, 0x20, 0x73, 0x254, 0x6e, 0x64, 0x69,
+0x73, 0x6f, 0x3b, 0x6c, 0x75, 0x3b, 0x6d, 0x61, 0x3b, 0x6d, 0x25b, 0x3b,
+0x79, 0x65, 0x3b, 0x76, 0x61, 0x3b, 0x6d, 0x73, 0x73, 0x61, 0x70, 0x61,
+0x61, 0x74, 0x3b, 0x61, 0x74, 0x61, 0x61, 0x73, 0x69, 0x6e, 0x6e, 0x67,
+0x6f, 0x72, 0x6e, 0x65, 0x71, 0x3b, 0x6d, 0x61, 0x72, 0x6c, 0x75, 0x6e,
+0x6e, 0x67, 0x6f, 0x72, 0x6e, 0x65, 0x71, 0x3b, 0x70, 0x69, 0x6e, 0x67,
+0x61, 0x73, 0x75, 0x6e, 0x6e, 0x67, 0x6f, 0x72, 0x6e, 0x65, 0x71, 0x3b,
+0x73, 0x69, 0x73, 0x61, 0x6d, 0x61, 0x6e, 0x6e, 0x67, 0x6f, 0x72, 0x6e,
+0x65, 0x71, 0x3b, 0x74, 0x61, 0x6c, 0x6c, 0x69, 0x6d, 0x61, 0x6e, 0x6e,
+0x67, 0x6f, 0x72, 0x6e, 0x65, 0x71, 0x3b, 0x61, 0x72, 0x66, 0x69, 0x6e,
+0x69, 0x6e, 0x6e, 0x67, 0x6f, 0x72, 0x6e, 0x65, 0x71, 0x73, 0x61, 0x70,
+0x3b, 0x61, 0x74, 0x61, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x70, 0x69, 0x6e,
+0x3b, 0x73, 0x69, 0x73, 0x3b, 0x74, 0x61, 0x6c, 0x3b, 0x61, 0x72, 0x66,
+0x53, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x50, 0x3b, 0x53, 0x3b, 0x54, 0x3b,
+0x41, 0x4b, 0x6f, 0x74, 0x69, 0x73, 0x61, 0x70, 0x3b, 0x4b, 0x6f, 0x74,
+0x61, 0x61, 0x69, 0x3b, 0x4b, 0x6f, 0x61, 0x65, 0x6e, 0x67, 0x2019, 0x3b,
+0x4b, 0x6f, 0x73, 0x6f, 0x6d, 0x6f, 0x6b, 0x3b, 0x4b, 0x6f, 0x61, 0x6e,
+0x67, 0x2019, 0x77, 0x61, 0x6e, 0x3b, 0x4b, 0x6f, 0x6d, 0x75, 0x75, 0x74,
+0x3b, 0x4b, 0x6f, 0x6c, 0x6f, 0x4b, 0x74, 0x73, 0x3b, 0x4b, 0x6f, 0x74,
+0x3b, 0x4b, 0x6f, 0x6f, 0x3b, 0x4b, 0x6f, 0x73, 0x3b, 0x4b, 0x6f, 0x61,
+0x3b, 0x4b, 0x6f, 0x6d, 0x3b, 0x4b, 0x6f, 0x6c, 0x54, 0x3b, 0x54, 0x3b,
+0x4f, 0x3b, 0x53, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4c, 0x57, 0x61, 0x20,
+0x6b, 0x79, 0x75, 0x6d, 0x77, 0x61, 0x3b, 0x57, 0x61, 0x20, 0x6b, 0x77,
+0x61, 0x6d, 0x62, 0x129, 0x6c, 0x129, 0x6c, 0x79, 0x61, 0x3b, 0x57, 0x61,
+0x20, 0x6b, 0x65, 0x6c, 0x129, 0x3b, 0x57, 0x61, 0x20, 0x6b, 0x61, 0x74,
+0x61, 0x74, 0x169, 0x3b, 0x57, 0x61, 0x20, 0x6b, 0x61, 0x6e, 0x61, 0x3b,
+0x57, 0x61, 0x20, 0x6b, 0x61, 0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x57, 0x61,
+0x20, 0x74, 0x68, 0x61, 0x6e, 0x74, 0x68, 0x61, 0x74, 0x169, 0x57, 0x6b,
+0x79, 0x3b, 0x57, 0x6b, 0x77, 0x3b, 0x57, 0x6b, 0x6c, 0x3b, 0x57, 0x74,
+0x169, 0x3b, 0x57, 0x6b, 0x6e, 0x3b, 0x57, 0x74, 0x6e, 0x3b, 0x57, 0x74,
+0x68, 0x59, 0x3b, 0x57, 0x3b, 0x45, 0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x41,
+0x3b, 0x41, 0xcad, 0xcbe, 0xca8, 0xcc1, 0xcb5, 0xcbe, 0xcb0, 0x3b, 0xcb8, 0xccb,
+0xcae, 0xcb5, 0xcbe, 0xcb0, 0x3b, 0xcae, 0xc82, 0xc97, 0xcb3, 0xcb5, 0xcbe, 0xcb0,
+0x3b, 0xcac, 0xcc1, 0xca7, 0xcb5, 0xcbe, 0xcb0, 0x3b, 0xc97, 0xcc1, 0xcb0, 0xcc1,
+0xcb5, 0xcbe, 0xcb0, 0x3b, 0xcb6, 0xcc1, 0xc95, 0xccd, 0xcb0, 0xcb5, 0xcbe, 0xcb0,
+0x3b, 0xcb6, 0xca8, 0xcbf, 0xcb5, 0xcbe, 0xcb0, 0xcad, 0xcbe, 0xca8, 0xcc1, 0x3b,
+0xcb8, 0xccb, 0xcae, 0x3b, 0xcae, 0xc82, 0xc97, 0xcb3, 0x3b, 0xcac, 0xcc1, 0xca7,
+0x3b, 0xc97, 0xcc1, 0xcb0, 0xcc1, 0x3b, 0xcb6, 0xcc1, 0xc95, 0xccd, 0xcb0, 0x3b,
+0xcb6, 0xca8, 0xcbf, 0xcad, 0xcbe, 0x3b, 0xcb8, 0xccb, 0x3b, 0xcae, 0xc82, 0x3b,
+0xcac, 0xcc1, 0x3b, 0xc97, 0xcc1, 0x3b, 0xcb6, 0xcc1, 0x3b, 0xcb6, 0x627, 0x64e,
+0x62a, 0x6be, 0x648, 0x627, 0x631, 0x3b, 0x698, 0x654, 0x646, 0x62f, 0x631, 0x655,
+0x631, 0x648, 0x627, 0x631, 0x3b, 0x628, 0x6c6, 0x645, 0x648, 0x627, 0x631, 0x3b,
+0x628, 0x648, 0x62f, 0x648, 0x627, 0x631, 0x3b, 0x628, 0x631, 0x620, 0x633, 0x648,
+0x627, 0x631, 0x3b, 0x62c, 0x64f, 0x645, 0x6c1, 0x3b, 0x628, 0x679, 0x648, 0x627,
+0x631, 0x622, 0x62a, 0x6be, 0x648, 0x627, 0x631, 0x3b, 0x698, 0x654, 0x646, 0x62f,
+0x655, 0x631, 0x648, 0x627, 0x631, 0x3b, 0x628, 0x6c6, 0x645, 0x648, 0x627, 0x631,
+0x3b, 0x628, 0x648, 0x62f, 0x648, 0x627, 0x631, 0x3b, 0x628, 0x631, 0x620, 0x633,
+0x648, 0x627, 0x631, 0x3b, 0x62c, 0x64f, 0x645, 0x6c1, 0x3b, 0x628, 0x679, 0x648,
+0x627, 0x631, 0x627, 0x3b, 0x698, 0x3b, 0x628, 0x3b, 0x628, 0x3b, 0x628, 0x3b,
+0x62c, 0x3b, 0x628, 0x906, 0x925, 0x935, 0x93e, 0x930, 0x3b, 0x91a, 0x902, 0x926,
+0x93f, 0x930, 0x935, 0x93e, 0x930, 0x3b, 0x92c, 0x941, 0x935, 0x93e, 0x930, 0x3b,
+0x92c, 0x94b, 0x926, 0x935, 0x93e, 0x930, 0x3b, 0x92c, 0x94d, 0x930, 0x947, 0x938,
+0x935, 0x93e, 0x930, 0x3b, 0x91c, 0x941, 0x92e, 0x94d, 0x92e, 0x93e, 0x3b, 0x92c,
+0x91f, 0x935, 0x93e, 0x930, 0x906, 0x925, 0x935, 0x93e, 0x930, 0x3b, 0x91a, 0x93c,
+0x902, 0x926, 0x93f, 0x930, 0x935, 0x93e, 0x930, 0x3b, 0x92c, 0x94b, 0x92e, 0x935,
+0x93e, 0x930, 0x3b, 0x92c, 0x94b, 0x926, 0x935, 0x93e, 0x930, 0x3b, 0x92c, 0x94d,
+0x930, 0x947, 0x938, 0x935, 0x93e, 0x930, 0x3b, 0x91c, 0x941, 0x92e, 0x93e, 0x3b,
+0x92c, 0x91f, 0x935, 0x93e, 0x930, 0x906, 0x925, 0x935, 0x93e, 0x930, 0x3b, 0x91a,
+0x902, 0x926, 0x93f, 0x930, 0x935, 0x93e, 0x930, 0x3b, 0x92c, 0x941, 0x935, 0x93e,
+0x930, 0x3b, 0x92c, 0x94b, 0x926, 0x935, 0x93e, 0x930, 0x3b, 0x92c, 0x94d, 0x930,
+0x947, 0x938, 0x935, 0x93e, 0x930, 0x3b, 0x91c, 0x941, 0x92e, 0x93e, 0x3b, 0x92c,
+0x91f, 0x935, 0x93e, 0x930, 0x905, 0x3b, 0x91a, 0x3b, 0x92c, 0x3b, 0x92c, 0x3b,
+0x92c, 0x3b, 0x91c, 0x3b, 0x92c, 0x436, 0x435, 0x43a, 0x441, 0x435, 0x43d, 0x431,
+0x456, 0x3b, 0x434, 0x4af, 0x439, 0x441, 0x435, 0x43d, 0x431, 0x456, 0x3b, 0x441,
+0x435, 0x439, 0x441, 0x435, 0x43d, 0x431, 0x456, 0x3b, 0x441, 0x4d9, 0x440, 0x441,
+0x435, 0x43d, 0x431, 0x456, 0x3b, 0x431, 0x435, 0x439, 0x441, 0x435, 0x43d, 0x431,
+0x456, 0x3b, 0x436, 0x4b1, 0x43c, 0x430, 0x3b, 0x441, 0x435, 0x43d, 0x431, 0x456,
+0x436, 0x441, 0x3b, 0x434, 0x441, 0x3b, 0x441, 0x441, 0x3b, 0x441, 0x440, 0x3b,
+0x431, 0x441, 0x3b, 0x436, 0x43c, 0x3b, 0x441, 0x431, 0x416, 0x3b, 0x414, 0x3b,
+0x421, 0x3b, 0x421, 0x3b, 0x411, 0x3b, 0x416, 0x3b, 0x421, 0x17a2, 0x17b6, 0x1791,
+0x17b7, 0x178f, 0x17d2, 0x1799, 0x3b, 0x1785, 0x1793, 0x17d2, 0x1791, 0x3b, 0x17a2, 0x1784,
+0x17d2, 0x1782, 0x17b6, 0x179a, 0x3b, 0x1796, 0x17bb, 0x1792, 0x3b, 0x1796, 0x17d2, 0x179a,
+0x17a0, 0x179f, 0x17d2, 0x1794, 0x178f, 0x17b7, 0x17cd, 0x3b, 0x179f, 0x17bb, 0x1780, 0x17d2,
+0x179a, 0x3b, 0x179f, 0x17c5, 0x179a, 0x17cd, 0x17a2, 0x17b6, 0x1791, 0x17b7, 0x178f, 0x17d2,
+0x1799, 0x3b, 0x1785, 0x17d0, 0x1793, 0x17d2, 0x1791, 0x3b, 0x17a2, 0x1784, 0x17d2, 0x1782,
+0x17b6, 0x179a, 0x3b, 0x1796, 0x17bb, 0x1792, 0x3b, 0x1796, 0x17d2, 0x179a, 0x17a0, 0x179f,
+0x17d2, 0x1794, 0x178f, 0x17b7, 0x17cd, 0x3b, 0x179f, 0x17bb, 0x1780, 0x17d2, 0x179a, 0x3b,
+0x179f, 0x17c5, 0x179a, 0x17cd, 0x17a2, 0x17b6, 0x1791, 0x17b7, 0x178f, 0x17d2, 0x1799, 0x3b,
+0x1785, 0x1793, 0x17d2, 0x1791, 0x3b, 0x17a2, 0x1784, 0x17d2, 0x1782, 0x17b6, 0x179a, 0x3b,
+0x1796, 0x17bb, 0x1792, 0x3b, 0x1796, 0x17d2, 0x179a, 0x17a0, 0x3b, 0x179f, 0x17bb, 0x1780,
+0x17d2, 0x179a, 0x3b, 0x179f, 0x17c5, 0x179a, 0x17cd, 0x17a2, 0x3b, 0x1785, 0x3b, 0x17a2,
+0x3b, 0x1796, 0x3b, 0x1796, 0x3b, 0x179f, 0x3b, 0x179f, 0x4b, 0x69, 0x75, 0x6d,
+0x69, 0x61, 0x3b, 0x4e, 0x6a, 0x75, 0x6d, 0x61, 0x74, 0x61, 0x74, 0x169,
+0x3b, 0x4e, 0x6a, 0x75, 0x6d, 0x61, 0x69, 0x6e, 0x65, 0x3b, 0x4e, 0x6a,
+0x75, 0x6d, 0x61, 0x74, 0x61, 0x6e, 0x61, 0x3b, 0x41, 0x72, 0x61, 0x6d,
+0x69, 0x74, 0x68, 0x69, 0x3b, 0x4e, 0x6a, 0x75, 0x6d, 0x61, 0x61, 0x3b,
+0x4e, 0x6a, 0x75, 0x6d, 0x61, 0x6d, 0x6f, 0x74, 0x68, 0x69, 0x4b, 0x4d,
+0x41, 0x3b, 0x4e, 0x54, 0x54, 0x3b, 0x4e, 0x4d, 0x4e, 0x3b, 0x4e, 0x4d,
+0x54, 0x3b, 0x41, 0x52, 0x54, 0x3b, 0x4e, 0x4d, 0x41, 0x3b, 0x4e, 0x4d,
+0x4d, 0x4b, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b, 0x41, 0x3b, 0x4e,
+0x3b, 0x4e, 0x4b, 0x75, 0x20, 0x63, 0x79, 0x75, 0x6d, 0x77, 0x65, 0x72,
+0x75, 0x3b, 0x4b, 0x75, 0x77, 0x61, 0x20, 0x6d, 0x62, 0x65, 0x72, 0x65,
+0x3b, 0x4b, 0x75, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x62, 0x69, 0x72, 0x69,
+0x3b, 0x4b, 0x75, 0x77, 0x61, 0x20, 0x67, 0x61, 0x74, 0x61, 0x74, 0x75,
+0x3b, 0x4b, 0x75, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x6e, 0x65, 0x3b, 0x4b,
+0x75, 0x77, 0x61, 0x20, 0x67, 0x61, 0x74, 0x61, 0x6e, 0x75, 0x3b, 0x4b,
+0x75, 0x77, 0x61, 0x20, 0x67, 0x61, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x74,
+0x75, 0x63, 0x79, 0x75, 0x2e, 0x3b, 0x6d, 0x62, 0x65, 0x2e, 0x3b, 0x6b,
+0x61, 0x62, 0x2e, 0x3b, 0x67, 0x74, 0x75, 0x2e, 0x3b, 0x6b, 0x61, 0x6e,
+0x2e, 0x3b, 0x67, 0x6e, 0x75, 0x2e, 0x3b, 0x67, 0x6e, 0x64, 0x2e, 0x906,
+0x92f, 0x924, 0x93e, 0x930, 0x3b, 0x938, 0x94b, 0x92e, 0x93e, 0x930, 0x3b, 0x92e,
+0x902, 0x917, 0x933, 0x93e, 0x930, 0x3b, 0x92c, 0x941, 0x927, 0x935, 0x93e, 0x930,
+0x3b, 0x92c, 0x93f, 0x930, 0x947, 0x938, 0x94d, 0x924, 0x93e, 0x930, 0x3b, 0x936,
+0x941, 0x915, 0x94d, 0x930, 0x93e, 0x930, 0x3b, 0x936, 0x947, 0x928, 0x935, 0x93e,
+0x930, 0x906, 0x3b, 0x938, 0x94b, 0x3b, 0x92e, 0x902, 0x3b, 0x92c, 0x941, 0x3b,
+0x92c, 0x3b, 0x936, 0x941, 0x3b, 0x936, 0x947, 0x906, 0x3b, 0x938, 0x94b, 0x3b,
+0x92e, 0x902, 0x3b, 0x92c, 0x941, 0x3b, 0x92c, 0x93f, 0x3b, 0x936, 0x941, 0x3b,
+0x936, 0x947, 0xc77c, 0xc694, 0xc77c, 0x3b, 0xc6d4, 0xc694, 0xc77c, 0x3b, 0xd654, 0xc694,
+0xc77c, 0x3b, 0xc218, 0xc694, 0xc77c, 0x3b, 0xbaa9, 0xc694, 0xc77c, 0x3b, 0xae08, 0xc694,
+0xc77c, 0x3b, 0xd1a0, 0xc694, 0xc77c, 0xc77c, 0x3b, 0xc6d4, 0x3b, 0xd654, 0x3b, 0xc218,
+0x3b, 0xbaa9, 0x3b, 0xae08, 0x3b, 0xd1a0, 0x41, 0x6c, 0x68, 0x61, 0x64, 0x69,
+0x3b, 0x41, 0x74, 0x69, 0x6e, 0x6e, 0x69, 0x3b, 0x41, 0x74, 0x61, 0x6c,
+0x61, 0x61, 0x74, 0x61, 0x3b, 0x41, 0x6c, 0x61, 0x72, 0x62, 0x61, 0x3b,
+0x41, 0x6c, 0x68, 0x61, 0x6d, 0x69, 0x69, 0x73, 0x61, 0x3b, 0x41, 0x6c,
+0x7a, 0x75, 0x6d, 0x61, 0x3b, 0x41, 0x73, 0x69, 0x62, 0x74, 0x69, 0x41,
+0x6c, 0x68, 0x3b, 0x41, 0x74, 0x69, 0x3b, 0x41, 0x74, 0x61, 0x3b, 0x41,
+0x6c, 0x61, 0x3b, 0x41, 0x6c, 0x6d, 0x3b, 0x41, 0x6c, 0x7a, 0x3b, 0x41,
+0x73, 0x69, 0x48, 0x3b, 0x54, 0x3b, 0x54, 0x3b, 0x4c, 0x3b, 0x4c, 0x3b,
+0x4c, 0x3b, 0x53, 0x41, 0x6c, 0x68, 0x61, 0x64, 0x69, 0x3b, 0x41, 0x74,
+0x69, 0x6e, 0x69, 0x3b, 0x41, 0x74, 0x61, 0x6c, 0x61, 0x74, 0x61, 0x3b,
+0x41, 0x6c, 0x61, 0x72, 0x62, 0x61, 0x3b, 0x41, 0x6c, 0x68, 0x61, 0x6d,
+0x69, 0x69, 0x73, 0x61, 0x3b, 0x41, 0x6c, 0x6a, 0x75, 0x6d, 0x61, 0x3b,
+0x41, 0x73, 0x73, 0x61, 0x62, 0x64, 0x75, 0x41, 0x6c, 0x68, 0x3b, 0x41,
+0x74, 0x69, 0x3b, 0x41, 0x74, 0x61, 0x3b, 0x41, 0x6c, 0x61, 0x3b, 0x41,
+0x6c, 0x6d, 0x3b, 0x41, 0x6c, 0x6a, 0x3b, 0x41, 0x73, 0x73, 0x79, 0x65,
+0x6b, 0x15f, 0x65, 0x6d, 0x3b, 0x64, 0x75, 0x15f, 0x65, 0x6d, 0x3b, 0x73,
+0xea, 0x15f, 0x65, 0x6d, 0x3b, 0xe7, 0x61, 0x72, 0x15f, 0x65, 0x6d, 0x3b,
+0x70, 0xea, 0x6e, 0x63, 0x15f, 0x65, 0x6d, 0x3b, 0xee, 0x6e, 0xee, 0x3b,
+0x15f, 0x65, 0x6d, 0xee, 0x79, 0x15f, 0x6d, 0x3b, 0x64, 0x15f, 0x6d, 0x3b,
+0x73, 0x15f, 0x6d, 0x3b, 0xe7, 0x15f, 0x6d, 0x3b, 0x70, 0x15f, 0x6d, 0x3b,
+0xee, 0x6e, 0xee, 0x3b, 0x15f, 0x65, 0x6d, 0x59, 0x3b, 0x44, 0x3b, 0x53,
+0x3b, 0xc7, 0x3b, 0x50, 0x3b, 0xce, 0x3b, 0x15e, 0x73, 0x254, 0x301, 0x6e,
+0x64, 0x254, 0x3b, 0x6d, 0x254, 0x301, 0x6e, 0x64, 0x254, 0x3b, 0x73, 0x254,
+0x301, 0x6e, 0x64, 0x254, 0x20, 0x6d, 0x61, 0x66, 0xfa, 0x20, 0x6d, 0xe1,
+0x62, 0x61, 0x3b, 0x73, 0x254, 0x301, 0x6e, 0x64, 0x254, 0x20, 0x6d, 0x61,
+0x66, 0xfa, 0x20, 0x6d, 0xe1, 0x6c, 0x61, 0x6c, 0x3b, 0x73, 0x254, 0x301,
+0x6e, 0x64, 0x254, 0x20, 0x6d, 0x61, 0x66, 0xfa, 0x20, 0x6d, 0xe1, 0x6e,
+0x61, 0x3b, 0x6d, 0x61, 0x62, 0xe1, 0x67, 0xe1, 0x20, 0x6d, 0xe1, 0x20,
+0x73, 0x75, 0x6b, 0x75, 0x6c, 0x3b, 0x73, 0xe1, 0x73, 0x61, 0x64, 0x69,
+0x73, 0x254, 0x301, 0x6e, 0x3b, 0x6d, 0x254, 0x301, 0x6e, 0x3b, 0x73, 0x6d,
+0x62, 0x3b, 0x73, 0x6d, 0x6c, 0x3b, 0x73, 0x6d, 0x6e, 0x3b, 0x6d, 0x62,
+0x73, 0x3b, 0x73, 0x61, 0x73, 0x73, 0x3b, 0x6d, 0x3b, 0x73, 0x3b, 0x73,
+0x3b, 0x73, 0x3b, 0x6d, 0x3b, 0x73, 0x436, 0x435, 0x43a, 0x448, 0x435, 0x43c,
+0x431, 0x438, 0x3b, 0x434, 0x4af, 0x439, 0x448, 0x4e9, 0x43c, 0x431, 0x4af, 0x3b,
+0x448, 0x435, 0x439, 0x448, 0x435, 0x43c, 0x431, 0x438, 0x3b, 0x448, 0x430, 0x440,
+0x448, 0x435, 0x43c, 0x431, 0x438, 0x3b, 0x431, 0x435, 0x439, 0x448, 0x435, 0x43c,
+0x431, 0x438, 0x3b, 0x436, 0x443, 0x43c, 0x430, 0x3b, 0x438, 0x448, 0x435, 0x43c,
+0x431, 0x438, 0x436, 0x435, 0x43a, 0x2e, 0x3b, 0x434, 0x4af, 0x439, 0x2e, 0x3b,
+0x448, 0x435, 0x439, 0x448, 0x2e, 0x3b, 0x448, 0x430, 0x440, 0x448, 0x2e, 0x3b,
+0x431, 0x435, 0x439, 0x448, 0x2e, 0x3b, 0x436, 0x443, 0x43c, 0x430, 0x3b, 0x438,
+0x448, 0x43c, 0x2e, 0x416, 0x3b, 0x414, 0x3b, 0x428, 0x3b, 0x428, 0x3b, 0x411,
+0x3b, 0x416, 0x3b, 0x418, 0x41, 0x14b, 0x70, 0xe9, 0x74, 0x75, 0x77, 0x61,
+0x6b, 0x21f, 0x61, 0x14b, 0x3b, 0x41, 0x14b, 0x70, 0xe9, 0x74, 0x75, 0x77,
+0x61, 0x14b, 0x17e, 0x69, 0x3b, 0x41, 0x14b, 0x70, 0xe9, 0x74, 0x75, 0x6e,
+0x75, 0x14b, 0x70, 0x61, 0x3b, 0x41, 0x14b, 0x70, 0xe9, 0x74, 0x75, 0x79,
+0x61, 0x6d, 0x6e, 0x69, 0x3b, 0x41, 0x14b, 0x70, 0xe9, 0x74, 0x75, 0x74,
+0x6f, 0x70, 0x61, 0x3b, 0x41, 0x14b, 0x70, 0xe9, 0x74, 0x75, 0x7a, 0x61,
+0x70, 0x74, 0x61, 0x14b, 0x3b, 0x4f, 0x77, 0xe1, 0x14b, 0x67, 0x79, 0x75,
+0x17e, 0x61, 0x17e, 0x61, 0x70, 0x69, 0x41, 0x3b, 0x57, 0x3b, 0x4e, 0x3b,
+0x59, 0x3b, 0x54, 0x3b, 0x5a, 0x3b, 0x4f, 0x4a, 0x75, 0x6d, 0x61, 0x70,
+0xed, 0x69, 0x72, 0x69, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0xe1, 0x74,
+0x75, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0xed, 0x6e, 0x65, 0x3b, 0x4a, 0x75,
+0x6d, 0x61, 0x74, 0xe1, 0x61, 0x6e, 0x6f, 0x3b, 0x41, 0x6c, 0x61, 0x6d,
+0xed, 0x69, 0x73, 0x69, 0x3b, 0x49, 0x6a, 0x75, 0x6d, 0xe1, 0x61, 0x3b,
+0x4a, 0x75, 0x6d, 0x61, 0x6d, 0xf3, 0x6f, 0x73, 0x69, 0x50, 0xed, 0x69,
+0x6c, 0x69, 0x3b, 0x54, 0xe1, 0x61, 0x74, 0x75, 0x3b, 0xcd, 0x6e, 0x65,
+0x3b, 0x54, 0xe1, 0x61, 0x6e, 0x6f, 0x3b, 0x41, 0x6c, 0x68, 0x3b, 0x49,
+0x6a, 0x6d, 0x3b, 0x4d, 0xf3, 0x6f, 0x73, 0x69, 0x50, 0x3b, 0x54, 0x3b,
+0x45, 0x3b, 0x4f, 0x3b, 0x41, 0x3b, 0x49, 0x3b, 0x4d, 0xea7, 0xeb1, 0xe99,
+0xead, 0xeb2, 0xe97, 0xeb4, 0xe94, 0x3b, 0xea7, 0xeb1, 0xe99, 0xe88, 0xeb1, 0xe99,
+0x3b, 0xea7, 0xeb1, 0xe99, 0xead, 0xeb1, 0xe87, 0xe84, 0xeb2, 0xe99, 0x3b, 0xea7,
+0xeb1, 0xe99, 0xe9e, 0xeb8, 0xe94, 0x3b, 0xea7, 0xeb1, 0xe99, 0xe9e, 0xeb0, 0xeab,
+0xeb1, 0xe94, 0x3b, 0xea7, 0xeb1, 0xe99, 0xeaa, 0xeb8, 0xe81, 0x3b, 0xea7, 0xeb1,
+0xe99, 0xec0, 0xeaa, 0xebb, 0xeb2, 0xead, 0xeb2, 0xe97, 0xeb4, 0xe94, 0x3b, 0xe88,
+0xeb1, 0xe99, 0x3b, 0xead, 0xeb1, 0xe87, 0xe84, 0xeb2, 0xe99, 0x3b, 0xe9e, 0xeb8,
+0xe94, 0x3b, 0xe9e, 0xeb0, 0xeab, 0xeb1, 0xe94, 0x3b, 0xeaa, 0xeb8, 0xe81, 0x3b,
+0xec0, 0xeaa, 0xebb, 0xeb2, 0xead, 0xeb2, 0x3b, 0xe88, 0x3b, 0xead, 0x3b, 0xe9e,
+0x3b, 0xe9e, 0xeab, 0x3b, 0xeaa, 0xeb8, 0x3b, 0xeaa, 0x64, 0x69, 0x65, 0x73,
+0x20, 0x53, 0x6f, 0x6c, 0x69, 0x73, 0x3b, 0x64, 0x69, 0x65, 0x73, 0x20,
+0x4c, 0x75, 0x6e, 0x61, 0x65, 0x3b, 0x64, 0x69, 0x65, 0x73, 0x20, 0x4d,
+0x61, 0x72, 0x74, 0x69, 0x73, 0x3b, 0x64, 0x69, 0x65, 0x73, 0x20, 0x4d,
+0x65, 0x72, 0x63, 0x75, 0x72, 0x69, 0x69, 0x3b, 0x64, 0x69, 0x65, 0x73,
+0x20, 0x49, 0x6f, 0x76, 0x69, 0x73, 0x3b, 0x64, 0x69, 0x65, 0x73, 0x20,
+0x56, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x73, 0x3b, 0x64, 0x69, 0x65, 0x73,
+0x20, 0x53, 0x61, 0x74, 0x75, 0x72, 0x6e, 0x69, 0x53, 0x6f, 0x6c, 0x3b,
+0x4c, 0x75, 0x6e, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x4d, 0x65, 0x72, 0x3b,
+0x49, 0x6f, 0x76, 0x3b, 0x56, 0x65, 0x6e, 0x3b, 0x53, 0x61, 0x74, 0x53,
+0x76, 0x113, 0x74, 0x64, 0x69, 0x65, 0x6e, 0x61, 0x3b, 0x50, 0x69, 0x72,
+0x6d, 0x64, 0x69, 0x65, 0x6e, 0x61, 0x3b, 0x4f, 0x74, 0x72, 0x64, 0x69,
+0x65, 0x6e, 0x61, 0x3b, 0x54, 0x72, 0x65, 0x161, 0x64, 0x69, 0x65, 0x6e,
+0x61, 0x3b, 0x43, 0x65, 0x74, 0x75, 0x72, 0x74, 0x64, 0x69, 0x65, 0x6e,
+0x61, 0x3b, 0x50, 0x69, 0x65, 0x6b, 0x74, 0x64, 0x69, 0x65, 0x6e, 0x61,
+0x3b, 0x53, 0x65, 0x73, 0x74, 0x64, 0x69, 0x65, 0x6e, 0x61, 0x73, 0x76,
+0x113, 0x74, 0x64, 0x69, 0x65, 0x6e, 0x61, 0x3b, 0x70, 0x69, 0x72, 0x6d,
+0x64, 0x69, 0x65, 0x6e, 0x61, 0x3b, 0x6f, 0x74, 0x72, 0x64, 0x69, 0x65,
+0x6e, 0x61, 0x3b, 0x74, 0x72, 0x65, 0x161, 0x64, 0x69, 0x65, 0x6e, 0x61,
+0x3b, 0x63, 0x65, 0x74, 0x75, 0x72, 0x74, 0x64, 0x69, 0x65, 0x6e, 0x61,
+0x3b, 0x70, 0x69, 0x65, 0x6b, 0x74, 0x64, 0x69, 0x65, 0x6e, 0x61, 0x3b,
+0x73, 0x65, 0x73, 0x74, 0x64, 0x69, 0x65, 0x6e, 0x61, 0x53, 0x76, 0x113,
+0x74, 0x64, 0x2e, 0x3b, 0x50, 0x69, 0x72, 0x6d, 0x64, 0x2e, 0x3b, 0x4f,
+0x74, 0x72, 0x64, 0x2e, 0x3b, 0x54, 0x72, 0x65, 0x161, 0x64, 0x2e, 0x3b,
+0x43, 0x65, 0x74, 0x75, 0x72, 0x74, 0x64, 0x2e, 0x3b, 0x50, 0x69, 0x65,
+0x6b, 0x74, 0x64, 0x2e, 0x3b, 0x53, 0x65, 0x73, 0x74, 0x64, 0x2e, 0x73,
+0x76, 0x113, 0x74, 0x64, 0x2e, 0x3b, 0x70, 0x69, 0x72, 0x6d, 0x64, 0x2e,
+0x3b, 0x6f, 0x74, 0x72, 0x64, 0x2e, 0x3b, 0x74, 0x72, 0x65, 0x161, 0x64,
+0x2e, 0x3b, 0x63, 0x65, 0x74, 0x75, 0x72, 0x74, 0x64, 0x2e, 0x3b, 0x70,
+0x69, 0x65, 0x6b, 0x74, 0x64, 0x2e, 0x3b, 0x73, 0x65, 0x73, 0x74, 0x64,
+0x2e, 0x53, 0x3b, 0x50, 0x3b, 0x4f, 0x3b, 0x54, 0x3b, 0x43, 0x3b, 0x50,
+0x3b, 0x53, 0x65, 0x79, 0x65, 0x6e, 0x67, 0x61, 0x3b, 0x6d, 0x6f, 0x6b,
+0x254, 0x6c, 0x254, 0x20, 0x6d, 0x77, 0x61, 0x20, 0x79, 0x61, 0x6d, 0x62,
+0x6f, 0x3b, 0x6d, 0x6f, 0x6b, 0x254, 0x6c, 0x254, 0x20, 0x6d, 0x77, 0x61,
+0x20, 0x6d, 0xed, 0x62, 0x61, 0x6c, 0xe9, 0x3b, 0x6d, 0x6f, 0x6b, 0x254,
+0x6c, 0x254, 0x20, 0x6d, 0x77, 0x61, 0x20, 0x6d, 0xed, 0x73, 0xe1, 0x74,
+0x6f, 0x3b, 0x6d, 0x6f, 0x6b, 0x254, 0x6c, 0x254, 0x20, 0x79, 0x61, 0x20,
+0x6d, 0xed, 0x6e, 0xe9, 0x69, 0x3b, 0x6d, 0x6f, 0x6b, 0x254, 0x6c, 0x254,
+0x20, 0x79, 0x61, 0x20, 0x6d, 0xed, 0x74, 0xe1, 0x6e, 0x6f, 0x3b, 0x6d,
+0x70, 0x254, 0x301, 0x73, 0x254, 0x65, 0x79, 0x65, 0x3b, 0x79, 0x62, 0x6f,
+0x3b, 0x6d, 0x62, 0x6c, 0x3b, 0x6d, 0x73, 0x74, 0x3b, 0x6d, 0x69, 0x6e,
+0x3b, 0x6d, 0x74, 0x6e, 0x3b, 0x6d, 0x70, 0x73, 0x65, 0x3b, 0x79, 0x3b,
+0x6d, 0x3b, 0x6d, 0x3b, 0x6d, 0x3b, 0x6d, 0x3b, 0x70, 0x73, 0x65, 0x6b,
+0x6d, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x69, 0x73, 0x3b, 0x70, 0x69, 0x72,
+0x6d, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x69, 0x73, 0x3b, 0x61, 0x6e, 0x74,
+0x72, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x69, 0x73, 0x3b, 0x74, 0x72, 0x65,
+0x10d, 0x69, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x69, 0x73, 0x3b, 0x6b, 0x65,
+0x74, 0x76, 0x69, 0x72, 0x74, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x69, 0x73,
+0x3b, 0x70, 0x65, 0x6e, 0x6b, 0x74, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x69,
+0x73, 0x3b, 0x161, 0x65, 0x161, 0x74, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x69,
+0x73, 0x73, 0x6b, 0x3b, 0x70, 0x72, 0x3b, 0x61, 0x6e, 0x3b, 0x74, 0x72,
+0x3b, 0x6b, 0x74, 0x3b, 0x70, 0x6e, 0x3b, 0x161, 0x74, 0x53, 0x3b, 0x50,
+0x3b, 0x41, 0x3b, 0x54, 0x3b, 0x4b, 0x3b, 0x50, 0x3b, 0x160, 0x6e, 0x6a,
+0x65, 0x17a, 0x65, 0x6c, 0x61, 0x3b, 0x70, 0xf3, 0x6e, 0x6a, 0x65, 0x17a,
+0x65, 0x6c, 0x65, 0x3b, 0x77, 0x61, 0x142, 0x74, 0x6f, 0x72, 0x61, 0x3b,
+0x73, 0x72, 0x6a, 0x6f, 0x64, 0x61, 0x3b, 0x73, 0x74, 0x77, 0xf3, 0x72,
+0x74, 0x6b, 0x3b, 0x70, 0x11b, 0x74, 0x6b, 0x3b, 0x73, 0x6f, 0x62, 0x6f,
+0x74, 0x61, 0x6e, 0x6a, 0x65, 0x3b, 0x70, 0xf3, 0x6e, 0x3b, 0x77, 0x61,
+0x142, 0x3b, 0x73, 0x72, 0x6a, 0x3b, 0x73, 0x74, 0x77, 0x3b, 0x70, 0x11b,
+0x74, 0x3b, 0x73, 0x6f, 0x62, 0x6e, 0x3b, 0x70, 0x3b, 0x77, 0x3b, 0x73,
+0x3b, 0x73, 0x3b, 0x70, 0x3b, 0x73, 0x53, 0xfc, 0x6e, 0x6e, 0x64, 0x61,
+0x67, 0x3b, 0x4d, 0x61, 0x61, 0x6e, 0x64, 0x61, 0x67, 0x3b, 0x44, 0x69,
+0x6e, 0x67, 0x73, 0x64, 0x61, 0x67, 0x3b, 0x4d, 0x69, 0x64, 0x64, 0x65,
+0x77, 0x65, 0x6b, 0x65, 0x6e, 0x3b, 0x44, 0x75, 0x6e, 0x6e, 0x65, 0x72,
+0x73, 0x64, 0x61, 0x67, 0x3b, 0x46, 0x72, 0x65, 0x65, 0x64, 0x61, 0x67,
+0x3b, 0x53, 0xfc, 0x6e, 0x6e, 0x61, 0x76, 0x65, 0x6e, 0x64, 0x53, 0xfc,
+0x2e, 0x3b, 0x4d, 0x61, 0x2e, 0x3b, 0x44, 0x69, 0x2e, 0x3b, 0x4d, 0x69,
+0x2e, 0x3b, 0x44, 0x75, 0x2e, 0x3b, 0x46, 0x72, 0x2e, 0x3b, 0x53, 0x61,
+0x2e, 0x4c, 0x75, 0x6d, 0x69, 0x6e, 0x67, 0x75, 0x3b, 0x4e, 0x6b, 0x6f,
+0x64, 0x79, 0x61, 0x3b, 0x4e, 0x64, 0xe0, 0x61, 0x79, 0xe0, 0x3b, 0x4e,
+0x64, 0x61, 0x6e, 0x67, 0xf9, 0x3b, 0x4e, 0x6a, 0xf2, 0x77, 0x61, 0x3b,
+0x4e, 0x67, 0xf2, 0x76, 0x79, 0x61, 0x3b, 0x4c, 0x75, 0x62, 0x69, 0x6e,
+0x67, 0x75, 0x4c, 0x75, 0x6d, 0x3b, 0x4e, 0x6b, 0x6f, 0x3b, 0x4e, 0x64,
+0x79, 0x3b, 0x4e, 0x64, 0x67, 0x3b, 0x4e, 0x6a, 0x77, 0x3b, 0x4e, 0x67,
+0x76, 0x3b, 0x4c, 0x75, 0x62, 0x4c, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b, 0x4e,
+0x3b, 0x4e, 0x3b, 0x4e, 0x3b, 0x4c, 0x4a, 0x75, 0x6d, 0x61, 0x70, 0x69,
+0x6c, 0x3b, 0x57, 0x75, 0x6f, 0x6b, 0x20, 0x54, 0x69, 0x63, 0x68, 0x3b,
+0x54, 0x69, 0x63, 0x68, 0x20, 0x41, 0x72, 0x69, 0x79, 0x6f, 0x3b, 0x54,
+0x69, 0x63, 0x68, 0x20, 0x41, 0x64, 0x65, 0x6b, 0x3b, 0x54, 0x69, 0x63,
+0x68, 0x20, 0x41, 0x6e, 0x67, 0x2019, 0x77, 0x65, 0x6e, 0x3b, 0x54, 0x69,
+0x63, 0x68, 0x20, 0x41, 0x62, 0x69, 0x63, 0x68, 0x3b, 0x4e, 0x67, 0x65,
+0x73, 0x6f, 0x4a, 0x4d, 0x50, 0x3b, 0x57, 0x55, 0x54, 0x3b, 0x54, 0x41,
+0x52, 0x3b, 0x54, 0x41, 0x44, 0x3b, 0x54, 0x41, 0x4e, 0x3b, 0x54, 0x41,
+0x42, 0x3b, 0x4e, 0x47, 0x53, 0x4a, 0x3b, 0x57, 0x3b, 0x54, 0x3b, 0x54,
+0x3b, 0x54, 0x3b, 0x54, 0x3b, 0x4e, 0x53, 0x6f, 0x6e, 0x6e, 0x64, 0x65,
+0x67, 0x3b, 0x4d, 0xe9, 0x69, 0x6e, 0x64, 0x65, 0x67, 0x3b, 0x44, 0xeb,
+0x6e, 0x73, 0x63, 0x68, 0x64, 0x65, 0x67, 0x3b, 0x4d, 0xeb, 0x74, 0x74,
+0x77, 0x6f, 0x63, 0x68, 0x3b, 0x44, 0x6f, 0x6e, 0x6e, 0x65, 0x73, 0x63,
+0x68, 0x64, 0x65, 0x67, 0x3b, 0x46, 0x72, 0x65, 0x69, 0x64, 0x65, 0x67,
+0x3b, 0x53, 0x61, 0x6d, 0x73, 0x63, 0x68, 0x64, 0x65, 0x67, 0x53, 0x6f,
+0x6e, 0x3b, 0x4d, 0xe9, 0x69, 0x3b, 0x44, 0xeb, 0x6e, 0x3b, 0x4d, 0xeb,
+0x74, 0x3b, 0x44, 0x6f, 0x6e, 0x3b, 0x46, 0x72, 0x65, 0x3b, 0x53, 0x61,
+0x6d, 0x53, 0x6f, 0x6e, 0x2e, 0x3b, 0x4d, 0xe9, 0x69, 0x2e, 0x3b, 0x44,
+0xeb, 0x6e, 0x2e, 0x3b, 0x4d, 0xeb, 0x74, 0x2e, 0x3b, 0x44, 0x6f, 0x6e,
+0x2e, 0x3b, 0x46, 0x72, 0x65, 0x2e, 0x3b, 0x53, 0x61, 0x6d, 0x2e, 0x4a,
+0x75, 0x6d, 0x61, 0x70, 0x69, 0x72, 0x69, 0x3b, 0x4a, 0x75, 0x6d, 0x61,
+0x74, 0x61, 0x74, 0x75, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x6e, 0x6e, 0x65,
+0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x4d, 0x75,
+0x72, 0x77, 0x61, 0x20, 0x77, 0x61, 0x20, 0x4b, 0x61, 0x6e, 0x6e, 0x65,
+0x3b, 0x4d, 0x75, 0x72, 0x77, 0x61, 0x20, 0x77, 0x61, 0x20, 0x4b, 0x61,
+0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x6d, 0x6f, 0x73,
+0x69, 0x4a, 0x32, 0x3b, 0x4a, 0x33, 0x3b, 0x4a, 0x34, 0x3b, 0x4a, 0x35,
+0x3b, 0x41, 0x6c, 0x3b, 0x49, 0x6a, 0x3b, 0x4a, 0x31, 0x43d, 0x435, 0x434,
+0x435, 0x43b, 0x430, 0x3b, 0x43f, 0x43e, 0x43d, 0x435, 0x434, 0x435, 0x43b, 0x43d,
+0x438, 0x43a, 0x3b, 0x432, 0x442, 0x43e, 0x440, 0x43d, 0x438, 0x43a, 0x3b, 0x441,
+0x440, 0x435, 0x434, 0x430, 0x3b, 0x447, 0x435, 0x442, 0x432, 0x440, 0x442, 0x43e,
+0x43a, 0x3b, 0x43f, 0x435, 0x442, 0x43e, 0x43a, 0x3b, 0x441, 0x430, 0x431, 0x43e,
+0x442, 0x430, 0x43d, 0x435, 0x434, 0x2e, 0x3b, 0x43f, 0x43e, 0x43d, 0x2e, 0x3b,
+0x432, 0x442, 0x43e, 0x2e, 0x3b, 0x441, 0x440, 0x435, 0x2e, 0x3b, 0x447, 0x435,
+0x442, 0x2e, 0x3b, 0x43f, 0x435, 0x442, 0x2e, 0x3b, 0x441, 0x430, 0x431, 0x2e,
+0x4a, 0x75, 0x6d, 0x61, 0x70, 0x69, 0x6c, 0x79, 0x69, 0x3b, 0x4a, 0x75,
+0x6d, 0x61, 0x74, 0x61, 0x74, 0x75, 0x75, 0x3b, 0x4a, 0x75, 0x6d, 0x61,
+0x6e, 0x6e, 0x65, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0x61, 0x6e, 0x75,
+0x3b, 0x41, 0x6c, 0x68, 0x61, 0x6d, 0x69, 0x73, 0x69, 0x3b, 0x49, 0x6a,
+0x75, 0x6d, 0x61, 0x61, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x6d, 0x6f, 0x73,
+0x69, 0x4a, 0x70, 0x69, 0x3b, 0x4a, 0x74, 0x74, 0x3b, 0x4a, 0x6e, 0x6e,
+0x3b, 0x4a, 0x74, 0x6e, 0x3b, 0x41, 0x6c, 0x68, 0x3b, 0x49, 0x6a, 0x75,
+0x3b, 0x4a, 0x6d, 0x6f, 0x930, 0x935, 0x93f, 0x20, 0x926, 0x93f, 0x928, 0x3b,
+0x938, 0x94b, 0x92e, 0x20, 0x926, 0x93f, 0x928, 0x3b, 0x92e, 0x902, 0x917, 0x932,
+0x20, 0x926, 0x93f, 0x928, 0x3b, 0x92c, 0x941, 0x927, 0x20, 0x926, 0x93f, 0x928,
+0x3b, 0x92c, 0x943, 0x939, 0x938, 0x94d, 0x92a, 0x924, 0x93f, 0x20, 0x926, 0x93f,
+0x928, 0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930, 0x20, 0x926, 0x93f, 0x928, 0x3b,
+0x936, 0x928, 0x93f, 0x20, 0x926, 0x93f, 0x928, 0x53, 0x61, 0x62, 0x61, 0x74,
+0x6f, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0x61, 0x74, 0x75, 0x3b, 0x4a,
+0x75, 0x6d, 0x61, 0x6e, 0x6e, 0x65, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74,
+0x61, 0x6e, 0x6f, 0x3b, 0x41, 0x72, 0x61, 0x68, 0x61, 0x6d, 0x69, 0x73,
+0x69, 0x3b, 0x49, 0x6a, 0x75, 0x6d, 0x61, 0x61, 0x3b, 0x4a, 0x75, 0x6d,
+0x61, 0x6d, 0x6f, 0x73, 0x69, 0x53, 0x61, 0x62, 0x3b, 0x4a, 0x74, 0x74,
+0x3b, 0x4a, 0x6e, 0x6e, 0x3b, 0x4a, 0x74, 0x6e, 0x3b, 0x41, 0x72, 0x61,
+0x3b, 0x49, 0x6a, 0x75, 0x3b, 0x4a, 0x6d, 0x6f, 0x53, 0x3b, 0x4a, 0x3b,
+0x4a, 0x3b, 0x4a, 0x3b, 0x41, 0x3b, 0x49, 0x3b, 0x4a, 0x4c, 0x69, 0x64,
+0x75, 0x76, 0x61, 0x20, 0x6c, 0x79, 0x61, 0x70, 0x69, 0x6c, 0x69, 0x3b,
+0x4c, 0x69, 0x64, 0x75, 0x76, 0x61, 0x20, 0x6c, 0x79, 0x61, 0x74, 0x61,
+0x74, 0x75, 0x3b, 0x4c, 0x69, 0x64, 0x75, 0x76, 0x61, 0x20, 0x6c, 0x79,
+0x61, 0x6e, 0x63, 0x68, 0x65, 0x63, 0x68, 0x69, 0x3b, 0x4c, 0x69, 0x64,
+0x75, 0x76, 0x61, 0x20, 0x6c, 0x79, 0x61, 0x6e, 0x6e, 0x79, 0x61, 0x6e,
+0x6f, 0x3b, 0x4c, 0x69, 0x64, 0x75, 0x76, 0x61, 0x20, 0x6c, 0x79, 0x61,
+0x6e, 0x6e, 0x79, 0x61, 0x6e, 0x6f, 0x20, 0x6e, 0x61, 0x20, 0x6c, 0x69,
+0x6e, 0x6a, 0x69, 0x3b, 0x4c, 0x69, 0x64, 0x75, 0x76, 0x61, 0x20, 0x6c,
+0x79, 0x61, 0x6e, 0x6e, 0x79, 0x61, 0x6e, 0x6f, 0x20, 0x6e, 0x61, 0x20,
+0x6d, 0x61, 0x76, 0x69, 0x6c, 0x69, 0x3b, 0x4c, 0x69, 0x64, 0x75, 0x76,
+0x61, 0x20, 0x6c, 0x69, 0x74, 0x61, 0x6e, 0x64, 0x69, 0x4c, 0x6c, 0x32,
+0x3b, 0x4c, 0x6c, 0x33, 0x3b, 0x4c, 0x6c, 0x34, 0x3b, 0x4c, 0x6c, 0x35,
+0x3b, 0x4c, 0x6c, 0x36, 0x3b, 0x4c, 0x6c, 0x37, 0x3b, 0x4c, 0x6c, 0x31,
+0x32, 0x3b, 0x33, 0x3b, 0x34, 0x3b, 0x35, 0x3b, 0x36, 0x3b, 0x37, 0x3b,
+0x31, 0x41, 0x6c, 0x61, 0x68, 0x61, 0x64, 0x79, 0x3b, 0x41, 0x6c, 0x61,
+0x74, 0x73, 0x69, 0x6e, 0x61, 0x69, 0x6e, 0x79, 0x3b, 0x54, 0x61, 0x6c,
+0x61, 0x74, 0x61, 0x3b, 0x41, 0x6c, 0x61, 0x72, 0x6f, 0x62, 0x69, 0x61,
+0x3b, 0x41, 0x6c, 0x61, 0x6b, 0x61, 0x6d, 0x69, 0x73, 0x79, 0x3b, 0x5a,
+0x6f, 0x6d, 0x61, 0x3b, 0x41, 0x73, 0x61, 0x62, 0x6f, 0x74, 0x73, 0x79,
+0x41, 0x6c, 0x61, 0x68, 0x3b, 0x41, 0x6c, 0x61, 0x74, 0x73, 0x3b, 0x54,
+0x61, 0x6c, 0x3b, 0x41, 0x6c, 0x61, 0x72, 0x3b, 0x41, 0x6c, 0x61, 0x6b,
+0x3b, 0x5a, 0x6f, 0x6d, 0x3b, 0x41, 0x73, 0x61, 0x62, 0x41, 0x3b, 0x41,
+0x3b, 0x54, 0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x5a, 0x3b, 0x41, 0xd1e, 0xd3e,
+0xd2f, 0xd31, 0xd3e, 0xd34, 0xd4d, 0x200c, 0xd1a, 0x3b, 0xd24, 0xd3f, 0xd19, 0xd4d,
+0xd15, 0xd33, 0xd3e, 0xd34, 0xd4d, 0x200c, 0xd1a, 0x3b, 0xd1a, 0xd4a, 0xd35, 0xd4d,
+0xd35, 0xd3e, 0xd34, 0xd4d, 0x200c, 0xd1a, 0x3b, 0xd2c, 0xd41, 0xd27, 0xd28, 0xd3e,
+0xd34, 0xd4d, 0x200c, 0xd1a, 0x3b, 0xd35, 0xd4d, 0xd2f, 0xd3e, 0xd34, 0xd3e, 0xd34,
+0xd4d, 0x200c, 0xd1a, 0x3b, 0xd35, 0xd46, 0xd33, 0xd4d, 0xd33, 0xd3f, 0xd2f, 0xd3e,
+0xd34, 0xd4d, 0x200c, 0xd1a, 0x3b, 0xd36, 0xd28, 0xd3f, 0xd2f, 0xd3e, 0xd34, 0xd4d,
+0x200c, 0xd1a, 0xd1e, 0xd3e, 0xd2f, 0xd31, 0xd3e, 0xd34, 0xd4d, 0x200c, 0xd1a, 0x3b,
+0xd24, 0xd3f, 0xd19, 0xd4d, 0xd15, 0xd33, 0xd3e, 0xd34, 0xd4d, 0x200c, 0xd1a, 0x3b,
+0xd1a, 0xd4a, 0xd35, 0xd4d, 0xd35, 0xd3e, 0xd34, 0xd4d, 0xd1a, 0x3b, 0xd2c, 0xd41,
+0xd27, 0xd28, 0xd3e, 0xd34, 0xd4d, 0x200c, 0xd1a, 0x3b, 0xd35, 0xd4d, 0xd2f, 0xd3e,
+0xd34, 0xd3e, 0xd34, 0xd4d, 0x200c, 0xd1a, 0x3b, 0xd35, 0xd46, 0xd33, 0xd4d, 0xd33,
+0xd3f, 0xd2f, 0xd3e, 0xd34, 0xd4d, 0x200c, 0xd1a, 0x3b, 0xd36, 0xd28, 0xd3f, 0xd2f,
+0xd3e, 0xd34, 0xd4d, 0x200c, 0xd1a, 0xd1e, 0xd3e, 0xd2f, 0xd7c, 0x3b, 0xd24, 0xd3f,
+0xd19, 0xd4d, 0xd15, 0xd7e, 0x3b, 0xd1a, 0xd4a, 0xd35, 0xd4d, 0xd35, 0x3b, 0xd2c,
+0xd41, 0xd27, 0xd7b, 0x3b, 0xd35, 0xd4d, 0xd2f, 0xd3e, 0xd34, 0xd02, 0x3b, 0xd35,
+0xd46, 0xd33, 0xd4d, 0xd33, 0xd3f, 0x3b, 0xd36, 0xd28, 0xd3f, 0xd1e, 0xd3e, 0x3b,
+0xd24, 0xd3f, 0x3b, 0xd1a, 0xd4a, 0x3b, 0xd2c, 0xd41, 0x3b, 0xd35, 0xd4d, 0xd2f,
+0xd3e, 0x3b, 0xd35, 0xd46, 0x3b, 0xd36, 0xd1e, 0x3b, 0xd24, 0xd3f, 0x3b, 0xd1a,
+0xd4a, 0x3b, 0xd2c, 0xd41, 0x3b, 0xd35, 0xd4d, 0xd2f, 0xd3e, 0x3b, 0xd35, 0xd46,
+0x3b, 0xd36, 0x41, 0x68, 0x61, 0x64, 0x3b, 0x49, 0x73, 0x6e, 0x69, 0x6e,
+0x3b, 0x53, 0x65, 0x6c, 0x61, 0x73, 0x61, 0x3b, 0x52, 0x61, 0x62, 0x75,
+0x3b, 0x4b, 0x68, 0x61, 0x6d, 0x69, 0x73, 0x3b, 0x4a, 0x75, 0x6d, 0x61,
+0x61, 0x74, 0x3b, 0x53, 0x61, 0x62, 0x74, 0x75, 0x41, 0x68, 0x64, 0x3b,
+0x49, 0x73, 0x6e, 0x3b, 0x53, 0x65, 0x6c, 0x3b, 0x52, 0x61, 0x62, 0x3b,
+0x4b, 0x68, 0x61, 0x3b, 0x4a, 0x75, 0x6d, 0x3b, 0x53, 0x61, 0x62, 0x41,
+0x3b, 0x49, 0x3b, 0x53, 0x3b, 0x52, 0x3b, 0x4b, 0x3b, 0x4a, 0x3b, 0x53,
+0x627, 0x62d, 0x62f, 0x3b, 0x627, 0x62b, 0x646, 0x64a, 0x646, 0x3b, 0x62b, 0x644,
+0x627, 0x62b, 0x3b, 0x631, 0x627, 0x628, 0x648, 0x3b, 0x62e, 0x645, 0x64a, 0x633,
+0x3b, 0x62c, 0x645, 0x639, 0x629, 0x3b, 0x633, 0x628, 0x62a, 0x648, 0x49, 0x6c,
+0x2d, 0x126, 0x61, 0x64, 0x64, 0x3b, 0x49, 0x74, 0x2d, 0x54, 0x6e, 0x65,
+0x6a, 0x6e, 0x3b, 0x49, 0x74, 0x2d, 0x54, 0x6c, 0x69, 0x65, 0x74, 0x61,
+0x3b, 0x4c, 0x2d, 0x45, 0x72, 0x62, 0x67, 0x127, 0x61, 0x3b, 0x49, 0x6c,
+0x2d, 0x126, 0x61, 0x6d, 0x69, 0x73, 0x3b, 0x49, 0x6c, 0x2d, 0x120, 0x69,
+0x6d, 0x67, 0x127, 0x61, 0x3b, 0x49, 0x73, 0x2d, 0x53, 0x69, 0x62, 0x74,
+0x126, 0x61, 0x64, 0x3b, 0x54, 0x6e, 0x65, 0x3b, 0x54, 0x6c, 0x69, 0x3b,
+0x45, 0x72, 0x62, 0x3b, 0x126, 0x61, 0x6d, 0x3b, 0x120, 0x69, 0x6d, 0x3b,
+0x53, 0x69, 0x62, 0x126, 0x64, 0x3b, 0x54, 0x6e, 0x3b, 0x54, 0x6c, 0x3b,
+0x45, 0x72, 0x3b, 0x126, 0x6d, 0x3b, 0x120, 0x6d, 0x3b, 0x53, 0x62, 0x126,
+0x64, 0x3b, 0x54, 0x3b, 0x54, 0x6c, 0x3b, 0x45, 0x72, 0x3b, 0x126, 0x6d,
+0x3b, 0x120, 0x6d, 0x3b, 0x53, 0x62, 0x9a8, 0x9cb, 0x982, 0x9ae, 0x9be, 0x987,
+0x99c, 0x9bf, 0x982, 0x3b, 0x9a8, 0x9bf, 0x982, 0x9a5, 0x9cc, 0x995, 0x9be, 0x9ac,
+0x9be, 0x3b, 0x9b2, 0x9c8, 0x9ac, 0x9be, 0x995, 0x9aa, 0x9cb, 0x995, 0x9aa, 0x9be,
+0x3b, 0x9af, 0x9bc, 0x9c1, 0x9ae, 0x9b6, 0x995, 0x9c8, 0x9b6, 0x9be, 0x3b, 0x9b6,
+0x997, 0x9cb, 0x9b2, 0x9b6, 0x9c7, 0x9a8, 0x3b, 0x987, 0x9b0, 0x9be, 0x987, 0x3b,
+0x9a5, 0x9be, 0x982, 0x99c, 0x9a8, 0x9cb, 0x3b, 0x9a8, 0x9bf, 0x982, 0x3b, 0x9b2,
+0x9c8, 0x3b, 0x9af, 0x9bc, 0x9c1, 0x9ae, 0x3b, 0x9b6, 0x997, 0x3b, 0x987, 0x9b0,
+0x9be, 0x3b, 0x9a5, 0x9be, 0x982, 0x9a8, 0x9cb, 0x982, 0x3b, 0x9a8, 0x9bf, 0x982,
+0x3b, 0x9b2, 0x9c8, 0x9ac, 0x9be, 0x3b, 0x9af, 0x9bc, 0x9c1, 0x9ae, 0x3b, 0x9b6,
+0x997, 0x9cb, 0x3b, 0x987, 0x9b0, 0x9be, 0x3b, 0x9a5, 0x9be, 0x982, 0x4a, 0x65,
+0x64, 0x6f, 0x6f, 0x6e, 0x65, 0x65, 0x3b, 0x4a, 0x65, 0x6c, 0x68, 0x65,
+0x69, 0x6e, 0x3b, 0x4a, 0x65, 0x6d, 0x61, 0x79, 0x72, 0x74, 0x3b, 0x4a,
+0x65, 0x72, 0x63, 0x65, 0x61, 0x6e, 0x3b, 0x4a, 0x65, 0x72, 0x64, 0x65,
+0x69, 0x6e, 0x3b, 0x4a, 0x65, 0x68, 0x65, 0x69, 0x6e, 0x65, 0x79, 0x3b,
+0x4a, 0x65, 0x73, 0x61, 0x72, 0x6e, 0x4a, 0x65, 0x64, 0x3b, 0x4a, 0x65,
+0x6c, 0x3b, 0x4a, 0x65, 0x6d, 0x3b, 0x4a, 0x65, 0x72, 0x63, 0x3b, 0x4a,
+0x65, 0x72, 0x64, 0x3b, 0x4a, 0x65, 0x68, 0x3b, 0x4a, 0x65, 0x73, 0x52,
+0x101, 0x74, 0x61, 0x70, 0x75, 0x3b, 0x4d, 0x61, 0x6e, 0x65, 0x3b, 0x54,
+0x16b, 0x72, 0x65, 0x69, 0x3b, 0x57, 0x65, 0x6e, 0x65, 0x72, 0x65, 0x69,
+0x3b, 0x54, 0x101, 0x69, 0x74, 0x65, 0x3b, 0x50, 0x61, 0x72, 0x61, 0x69,
+0x72, 0x65, 0x3b, 0x52, 0x101, 0x68, 0x6f, 0x72, 0x6f, 0x69, 0x52, 0x101,
+0x74, 0x3b, 0x4d, 0x61, 0x6e, 0x3b, 0x54, 0x16b, 0x72, 0x3b, 0x57, 0x65,
+0x6e, 0x3b, 0x54, 0x101, 0x69, 0x3b, 0x50, 0x61, 0x72, 0x3b, 0x52, 0x101,
+0x68, 0x52, 0x74, 0x3b, 0x4d, 0x3b, 0x54, 0x3b, 0x57, 0x3b, 0x54, 0x3b,
+0x50, 0x3b, 0x52, 0x68, 0x930, 0x935, 0x93f, 0x935, 0x93e, 0x930, 0x3b, 0x938,
+0x94b, 0x92e, 0x935, 0x93e, 0x930, 0x3b, 0x92e, 0x902, 0x917, 0x933, 0x935, 0x93e,
+0x930, 0x3b, 0x92c, 0x941, 0x927, 0x935, 0x93e, 0x930, 0x3b, 0x917, 0x941, 0x930,
+0x941, 0x935, 0x93e, 0x930, 0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930, 0x935, 0x93e,
+0x930, 0x3b, 0x936, 0x928, 0x93f, 0x935, 0x93e, 0x930, 0x930, 0x935, 0x93f, 0x3b,
+0x938, 0x94b, 0x92e, 0x3b, 0x92e, 0x902, 0x917, 0x933, 0x3b, 0x92c, 0x941, 0x927,
+0x3b, 0x917, 0x941, 0x930, 0x941, 0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930, 0x3b,
+0x936, 0x928, 0x93f, 0x4a, 0x75, 0x6d, 0x61, 0x70, 0xed, 0x6c, 0xed, 0x3b,
+0x4a, 0x75, 0x6d, 0x61, 0x74, 0xe1, 0x74, 0x75, 0x3b, 0x4a, 0x75, 0x6d,
+0x61, 0x6e, 0x65, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0xe1, 0x6e, 0x254,
+0x3b, 0x41, 0x6c, 0x61, 0xe1, 0x6d, 0x69, 0x73, 0x69, 0x3b, 0x4a, 0x75,
+0x6d, 0xe1, 0x61, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x6d, 0xf3, 0x73, 0x69,
+0x4b, 0x69, 0x75, 0x6d, 0x69, 0x61, 0x3b, 0x4d, 0x75, 0x72, 0x61, 0x6d,
+0x75, 0x6b, 0x6f, 0x3b, 0x57, 0x61, 0x69, 0x72, 0x69, 0x3b, 0x57, 0x65,
+0x74, 0x68, 0x61, 0x74, 0x75, 0x3b, 0x57, 0x65, 0x6e, 0x61, 0x3b, 0x57,
+0x65, 0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x6d, 0x6f,
+0x73, 0x69, 0x4b, 0x49, 0x55, 0x3b, 0x4d, 0x52, 0x41, 0x3b, 0x57, 0x41,
+0x49, 0x3b, 0x57, 0x45, 0x54, 0x3b, 0x57, 0x45, 0x4e, 0x3b, 0x57, 0x54,
+0x4e, 0x3b, 0x4a, 0x55, 0x4d, 0x4b, 0x3b, 0x4d, 0x3b, 0x57, 0x3b, 0x57,
+0x3b, 0x57, 0x3b, 0x57, 0x3b, 0x4a, 0x41, 0x6e, 0x65, 0x67, 0x20, 0x31,
+0x3b, 0x41, 0x6e, 0x65, 0x67, 0x20, 0x32, 0x3b, 0x41, 0x6e, 0x65, 0x67,
+0x20, 0x33, 0x3b, 0x41, 0x6e, 0x65, 0x67, 0x20, 0x34, 0x3b, 0x41, 0x6e,
+0x65, 0x67, 0x20, 0x35, 0x3b, 0x41, 0x6e, 0x65, 0x67, 0x20, 0x36, 0x3b,
+0x41, 0x6e, 0x65, 0x67, 0x20, 0x37, 0x41, 0x31, 0x3b, 0x41, 0x32, 0x3b,
+0x41, 0x33, 0x3b, 0x41, 0x34, 0x3b, 0x41, 0x35, 0x3b, 0x41, 0x36, 0x3b,
+0x41, 0x37, 0x41d, 0x44f, 0x43c, 0x3b, 0x414, 0x430, 0x432, 0x430, 0x430, 0x3b,
+0x41c, 0x44f, 0x433, 0x43c, 0x430, 0x440, 0x3b, 0x41b, 0x445, 0x430, 0x433, 0x432,
+0x430, 0x3b, 0x41f, 0x4af, 0x440, 0x44d, 0x432, 0x3b, 0x411, 0x430, 0x430, 0x441,
+0x430, 0x43d, 0x3b, 0x411, 0x44f, 0x43c, 0x431, 0x430, 0x43d, 0x44f, 0x43c, 0x3b,
+0x434, 0x430, 0x432, 0x430, 0x430, 0x3b, 0x43c, 0x44f, 0x433, 0x43c, 0x430, 0x440,
+0x3b, 0x43b, 0x445, 0x430, 0x433, 0x432, 0x430, 0x3b, 0x43f, 0x4af, 0x440, 0x44d,
+0x432, 0x3b, 0x431, 0x430, 0x430, 0x441, 0x430, 0x43d, 0x3b, 0x431, 0x44f, 0x43c,
+0x431, 0x430, 0x41d, 0x44f, 0x3b, 0x414, 0x430, 0x3b, 0x41c, 0x44f, 0x3b, 0x41b,
+0x445, 0x3b, 0x41f, 0x4af, 0x3b, 0x411, 0x430, 0x3b, 0x411, 0x44f, 0x1828, 0x1822,
+0x182e, 0x180e, 0x1820, 0x3b, 0x1833, 0x1820, 0x1838, 0x1820, 0x3b, 0x182e, 0x1822, 0x1820,
+0x1820, 0x182e, 0x1820, 0x1837, 0x3b, 0x1840, 0x1820, 0x182d, 0x182a, 0x1820, 0x3b, 0x182b,
+0x1826, 0x1837, 0x182a, 0x1826, 0x3b, 0x182a, 0x1820, 0x1830, 0x1820, 0x1829, 0x3b, 0x182a,
+0x1822, 0x182e, 0x182a, 0x1820, 0x1828, 0x1822, 0x3b, 0x1833, 0x1820, 0x3b, 0x182e, 0x1822,
+0x182d, 0x3b, 0x1840, 0x1820, 0x3b, 0x182b, 0x1826, 0x1837, 0x3b, 0x182a, 0x1820, 0x3b,
+0x182a, 0x1822, 0x182e, 0x1828, 0x1822, 0x3b, 0x1832, 0x1820, 0x3b, 0x182e, 0x1822, 0x182d,
+0x3b, 0x1840, 0x1820, 0x3b, 0x182b, 0x1825, 0x1837, 0x3b, 0x182a, 0x1820, 0x3b, 0x182a,
+0x1822, 0x182e, 0x1828, 0x1822, 0x3b, 0x1833, 0x1820, 0x3b, 0x182e, 0x1822, 0x182d, 0x3b,
+0x1840, 0x1820, 0x3b, 0x182b, 0x1825, 0x1837, 0x3b, 0x182a, 0x1820, 0x3b, 0x182a, 0x1822,
+0x182e, 0x64, 0x69, 0x6d, 0x61, 0x6e, 0x73, 0x3b, 0x6c, 0x69, 0x6e, 0x64,
+0x69, 0x3b, 0x6d, 0x61, 0x72, 0x64, 0x69, 0x3b, 0x6d, 0x65, 0x72, 0x6b,
+0x72, 0x65, 0x64, 0x69, 0x3b, 0x7a, 0x65, 0x64, 0x69, 0x3b, 0x76, 0x61,
+0x6e, 0x64, 0x72, 0x65, 0x64, 0x69, 0x3b, 0x73, 0x61, 0x6d, 0x64, 0x69,
+0x64, 0x69, 0x6d, 0x3b, 0x6c, 0x69, 0x6e, 0x3b, 0x6d, 0x61, 0x72, 0x3b,
+0x6d, 0x65, 0x72, 0x3b, 0x7a, 0x65, 0x3b, 0x76, 0x61, 0x6e, 0x3b, 0x73,
+0x61, 0x6d, 0x64, 0x3b, 0x6c, 0x3b, 0x6d, 0x3b, 0x6d, 0x3b, 0x7a, 0x3b,
+0x76, 0x3b, 0x73, 0x43, 0x6f, 0x6d, 0x2019, 0x79, 0x61, 0x6b, 0x6b, 0x65,
+0x3b, 0x43, 0x6f, 0x6d, 0x6c, 0x61, 0x61, 0x257, 0x69, 0x69, 0x3b, 0x43,
+0x6f, 0x6d, 0x7a, 0x79, 0x69, 0x69, 0x257, 0x69, 0x69, 0x3b, 0x43, 0x6f,
+0x6d, 0x6b, 0x6f, 0x6c, 0x6c, 0x65, 0x3b, 0x43, 0x6f, 0x6d, 0x6b, 0x61,
+0x6c, 0x64, 0x1dd, 0x253, 0x6c, 0x69, 0x69, 0x3b, 0x43, 0x6f, 0x6d, 0x67,
+0x61, 0x69, 0x73, 0x75, 0x75, 0x3b, 0x43, 0x6f, 0x6d, 0x7a, 0x79, 0x65,
+0x253, 0x73, 0x75, 0x75, 0x43, 0x79, 0x61, 0x3b, 0x43, 0x6c, 0x61, 0x3b,
+0x43, 0x7a, 0x69, 0x3b, 0x43, 0x6b, 0x6f, 0x3b, 0x43, 0x6b, 0x61, 0x3b,
+0x43, 0x67, 0x61, 0x3b, 0x43, 0x7a, 0x65, 0x59, 0x3b, 0x4c, 0x3b, 0x5a,
+0x3b, 0x4f, 0x3b, 0x41, 0x3b, 0x47, 0x3b, 0x45, 0x4e, 0x65, 0x74, 0x74,
+0x76, 0x20, 0x43, 0x61, 0x6b, 0x6f, 0x3b, 0x45, 0x6e, 0x68, 0x76, 0x74,
+0x65, 0x63, 0x65, 0x73, 0x6b, 0x76, 0x3b, 0x45, 0x6e, 0x68, 0x76, 0x74,
+0x65, 0x63, 0x65, 0x73, 0x6b, 0x76, 0x20, 0x45, 0x6e, 0x68, 0x76, 0x79,
+0x76, 0x74, 0x6b, 0x65, 0x3b, 0x45, 0x6e, 0x6e, 0x76, 0x72, 0x6b, 0x76,
+0x70, 0x76, 0x3b, 0x45, 0x6e, 0x6e, 0x76, 0x72, 0x6b, 0x76, 0x70, 0x76,
+0x20, 0x45, 0x6e, 0x68, 0x76, 0x79, 0x76, 0x74, 0x6b, 0x65, 0x3b, 0x4e,
+0x61, 0x6b, 0x20, 0x4f, 0x6b, 0x6b, 0x6f, 0x73, 0x6b, 0x76, 0x20, 0x4e,
+0x65, 0x74, 0x74, 0x76, 0x3b, 0x4e, 0x65, 0x74, 0x74, 0x76, 0x20, 0x43,
+0x61, 0x6b, 0x63, 0x75, 0x73, 0x65, 0x53, 0x6f, 0x6e, 0x74, 0x61, 0x78,
+0x74, 0x73, 0x65, 0x65, 0x73, 0x3b, 0x4d, 0x61, 0x6e, 0x74, 0x61, 0x78,
+0x74, 0x73, 0x65, 0x65, 0x73, 0x3b, 0x44, 0x65, 0x6e, 0x73, 0x74, 0x61,
+0x78, 0x74, 0x73, 0x65, 0x65, 0x73, 0x3b, 0x57, 0x75, 0x6e, 0x73, 0x74,
+0x61, 0x78, 0x74, 0x73, 0x65, 0x65, 0x73, 0x3b, 0x44, 0x6f, 0x6e, 0x64,
+0x65, 0x72, 0x74, 0x61, 0x78, 0x74, 0x73, 0x65, 0x65, 0x73, 0x3b, 0x46,
+0x72, 0x61, 0x69, 0x74, 0x61, 0x78, 0x74, 0x73, 0x65, 0x65, 0x73, 0x3b,
+0x53, 0x61, 0x74, 0x65, 0x72, 0x74, 0x61, 0x78, 0x74, 0x73, 0x65, 0x65,
+0x73, 0x53, 0x6f, 0x6e, 0x3b, 0x4d, 0x61, 0x3b, 0x44, 0x65, 0x3b, 0x57,
+0x75, 0x3b, 0x44, 0x6f, 0x3b, 0x46, 0x72, 0x3b, 0x53, 0x61, 0x74, 0x53,
+0x3b, 0x4d, 0x3b, 0x45, 0x3b, 0x57, 0x3b, 0x44, 0x3b, 0x46, 0x3b, 0x41,
+0x906, 0x907, 0x924, 0x92c, 0x93e, 0x930, 0x3b, 0x938, 0x94b, 0x92e, 0x92c, 0x93e,
+0x930, 0x3b, 0x92e, 0x919, 0x94d, 0x917, 0x932, 0x92c, 0x93e, 0x930, 0x3b, 0x92c,
+0x941, 0x927, 0x92c, 0x93e, 0x930, 0x3b, 0x92c, 0x93f, 0x939, 0x93f, 0x92c, 0x93e,
+0x930, 0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930, 0x92c, 0x93e, 0x930, 0x3b, 0x936,
+0x928, 0x93f, 0x92c, 0x93e, 0x930, 0x906, 0x907, 0x924, 0x3b, 0x938, 0x94b, 0x92e,
+0x3b, 0x92e, 0x919, 0x94d, 0x917, 0x932, 0x3b, 0x92c, 0x941, 0x927, 0x3b, 0x92c,
+0x93f, 0x939, 0x93f, 0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930, 0x3b, 0x936, 0x928,
+0x93f, 0x906, 0x3b, 0x938, 0x94b, 0x3b, 0x92e, 0x3b, 0x92c, 0x941, 0x3b, 0x92c,
+0x93f, 0x3b, 0x936, 0x941, 0x3b, 0x936, 0x6c, 0x79, 0x25b, 0x2bc, 0x25b, 0x301,
+0x20, 0x73, 0x1e85, 0xed, 0x14b, 0x74, 0xe8, 0x3b, 0x6d, 0x76, 0x66, 0xf2,
+0x20, 0x6c, 0x79, 0x25b, 0x30c, 0x2bc, 0x3b, 0x6d, 0x62, 0x254, 0x301, 0x254,
+0x6e, 0x74, 0xe8, 0x20, 0x6d, 0x76, 0x66, 0xf2, 0x20, 0x6c, 0x79, 0x25b,
+0x30c, 0x2bc, 0x3b, 0x74, 0x73, 0xe8, 0x74, 0x73, 0x25b, 0x300, 0x25b, 0x20,
+0x6c, 0x79, 0x25b, 0x30c, 0x2bc, 0x3b, 0x6d, 0x62, 0x254, 0x301, 0x254, 0x6e,
+0x74, 0xe8, 0x20, 0x74, 0x73, 0x65, 0x74, 0x73, 0x25b, 0x300, 0x25b, 0x20,
+0x6c, 0x79, 0x25b, 0x30c, 0x2bc, 0x3b, 0x6d, 0x76, 0x66, 0xf2, 0x20, 0x6d,
+0xe0, 0x67, 0x61, 0x20, 0x6c, 0x79, 0x25b, 0x30c, 0x2bc, 0x3b, 0x6d, 0xe0,
+0x67, 0x61, 0x20, 0x6c, 0x79, 0x25b, 0x30c, 0x2bc, 0x53, 0x254, 0x301, 0x6e,
+0x64, 0x69, 0x3b, 0x4d, 0x254, 0x301, 0x6e, 0x64, 0x69, 0x3b, 0xc1, 0x70,
+0x74, 0x61, 0x20, 0x4d, 0x254, 0x301, 0x6e, 0x64, 0x69, 0x3b, 0x57, 0x25b,
+0x301, 0x6e, 0x25b, 0x73, 0x25b, 0x64, 0x25b, 0x3b, 0x54, 0x254, 0x301, 0x73,
+0x25b, 0x64, 0x25b, 0x3b, 0x46, 0x25b, 0x6c, 0xe2, 0x79, 0x25b, 0x64, 0x25b,
+0x3b, 0x53, 0xe1, 0x73, 0x69, 0x64, 0x25b, 0x53, 0x254, 0x301, 0x3b, 0x4d,
+0x254, 0x301, 0x3b, 0xc1, 0x4d, 0x3b, 0x57, 0x25b, 0x301, 0x3b, 0x54, 0x254,
+0x301, 0x3b, 0x46, 0x25b, 0x3b, 0x53, 0xe1, 0x53, 0x1ecd, 0x301, 0x6e, 0x64,
+0xe8, 0x3b, 0x4d, 0x1ecd, 0x301, 0x6e, 0x64, 0xe8, 0x3b, 0x54, 0x69, 0xfa,
+0x7a, 0x64, 0xe8, 0x3b, 0x57, 0x1eb9, 0x301, 0x6e, 0x1eb9, 0x301, 0x7a, 0x64,
+0xe8, 0x3b, 0x54, 0x1ecd, 0x301, 0x7a, 0x64, 0xe8, 0x3b, 0x46, 0x72, 0x61,
+0xed, 0x64, 0xe8, 0x3b, 0x53, 0xe1, 0x74, 0x1ecd, 0x64, 0xe8, 0x53, 0x1ecd,
+0x301, 0x6e, 0x3b, 0x4d, 0x1ecd, 0x301, 0x6e, 0x3b, 0x54, 0x69, 0xfa, 0x3b,
+0x57, 0x1eb9, 0x301, 0x6e, 0x3b, 0x54, 0x1ecd, 0x301, 0x7a, 0x3b, 0x46, 0x72,
+0x61, 0xed, 0x3b, 0x53, 0xe1, 0x74, 0x7de, 0x7ca, 0x7ef, 0x7d9, 0x7cc, 0x7df,
+0x7cf, 0x7f2, 0x3b, 0x7de, 0x7d0, 0x7ec, 0x7d3, 0x7ca, 0x7ec, 0x7df, 0x7cf, 0x7f2,
+0x3b, 0x7de, 0x7d0, 0x7ec, 0x7df, 0x7cf, 0x7f2, 0x3b, 0x7de, 0x7ce, 0x7e3, 0x7ce,
+0x7f2, 0x7df, 0x7cf, 0x7f2, 0x3b, 0x7d3, 0x7cc, 0x7df, 0x7cf, 0x7f2, 0x3b, 0x7db,
+0x7cc, 0x7ec, 0x7e3, 0x7cc, 0x7f2, 0x7ec, 0x7df, 0x7cf, 0x7f2, 0x3b, 0x7de, 0x7cd,
+0x7f2, 0x7d8, 0x7cd, 0x7df, 0x7cf, 0x7f2, 0x7de, 0x7ca, 0x7ef, 0x7d9, 0x3b, 0x7de,
+0x7d0, 0x7ec, 0x7d3, 0x3b, 0x7de, 0x7d0, 0x7ec, 0x7df, 0x3b, 0x7de, 0x7ce, 0x7e3,
+0x3b, 0x7d3, 0x7cc, 0x7df, 0x3b, 0x7db, 0x7cc, 0x7ec, 0x7e3, 0x3b, 0x7de, 0x7cd,
+0x7f2, 0x7d8, 0x7de, 0x7ca, 0x7ef, 0x7d9, 0x3b, 0x7de, 0x7d0, 0x7ec, 0x7d3, 0x3b,
+0x7de, 0x7d0, 0x7ec, 0x7df, 0x7cf, 0x7f2, 0x3b, 0x7de, 0x7ce, 0x7e3, 0x3b, 0x7d3,
+0x7cc, 0x7df, 0x3b, 0x7db, 0x7cc, 0x7ec, 0x7e3, 0x3b, 0x7de, 0x7cd, 0x7f2, 0x7d8,
+0x7de, 0x3b, 0x7de, 0x3b, 0x7de, 0x3b, 0x7de, 0x3b, 0x7d3, 0x3b, 0x7db, 0x3b,
+0x7de, 0x73, 0x6f, 0x74, 0x6e, 0x61, 0x62, 0x65, 0x61, 0x69, 0x76, 0x69,
+0x3b, 0x76, 0x75, 0x6f, 0x73, 0x73, 0xe1, 0x72, 0x67, 0x61, 0x3b, 0x6d,
+0x61, 0x14b, 0x14b, 0x65, 0x62, 0xe1, 0x72, 0x67, 0x61, 0x3b, 0x67, 0x61,
+0x73, 0x6b, 0x61, 0x76, 0x61, 0x68, 0x6b, 0x6b, 0x75, 0x3b, 0x64, 0x75,
+0x6f, 0x72, 0x61, 0x73, 0x64, 0x61, 0x74, 0x3b, 0x62, 0x65, 0x61, 0x72,
+0x6a, 0x61, 0x64, 0x61, 0x74, 0x3b, 0x6c, 0xe1, 0x76, 0x76, 0x61, 0x72,
+0x64, 0x61, 0x74, 0x73, 0x6f, 0x74, 0x6e, 0x3b, 0x76, 0x75, 0x6f, 0x73,
+0x3b, 0x6d, 0x61, 0x14b, 0x3b, 0x67, 0x61, 0x73, 0x6b, 0x3b, 0x64, 0x75,
+0x6f, 0x72, 0x3b, 0x62, 0x65, 0x61, 0x72, 0x3b, 0x6c, 0xe1, 0x76, 0x53,
+0x3b, 0x56, 0x3b, 0x4d, 0x3b, 0x47, 0x3b, 0x44, 0x3b, 0x42, 0x3b, 0x4c,
+0x73, 0x6f, 0x74, 0x6e, 0x61, 0x62, 0x65, 0x61, 0x69, 0x76, 0x69, 0x3b,
+0x6d, 0xe1, 0x6e, 0x6e, 0x6f, 0x64, 0x61, 0x74, 0x3b, 0x64, 0x69, 0x73,
+0x64, 0x61, 0x74, 0x3b, 0x67, 0x61, 0x73, 0x6b, 0x61, 0x76, 0x61, 0x68,
+0x6b, 0x6b, 0x75, 0x3b, 0x64, 0x75, 0x6f, 0x72, 0x61, 0x73, 0x74, 0x61,
+0x74, 0x3b, 0x62, 0x65, 0x61, 0x72, 0x6a, 0x61, 0x64, 0x61, 0x74, 0x3b,
+0x6c, 0xe1, 0x76, 0x76, 0x6f, 0x72, 0x64, 0x61, 0x74, 0x73, 0x6f, 0x3b,
+0x6d, 0xe1, 0x3b, 0x64, 0x69, 0x3b, 0x67, 0x61, 0x3b, 0x64, 0x75, 0x3b,
+0x62, 0x65, 0x3b, 0x6c, 0xe1, 0x53, 0x3b, 0x4d, 0x3b, 0x44, 0x3b, 0x47,
+0x3b, 0x44, 0x3b, 0x42, 0x3b, 0x4c, 0x4c, 0x61, 0x6d, 0x6f, 0x72, 0x65,
+0x6e, 0x61, 0x3b, 0x4d, 0x75, 0x73, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67,
+0x6f, 0x3b, 0x4c, 0x61, 0x62, 0x6f, 0x62, 0x65, 0x64, 0x69, 0x3b, 0x4c,
+0x61, 0x62, 0x6f, 0x72, 0x61, 0x72, 0x6f, 0x3b, 0x4c, 0x61, 0x62, 0x6f,
+0x6e, 0x65, 0x3b, 0x4c, 0x61, 0x62, 0x6f, 0x68, 0x6c, 0x61, 0x6e, 0x6f,
+0x3b, 0x4d, 0x6f, 0x6b, 0x69, 0x62, 0x65, 0x6c, 0x6f, 0x4c, 0x61, 0x6d,
+0x3b, 0x4d, 0x6f, 0x73, 0x3b, 0x42, 0x65, 0x64, 0x3b, 0x52, 0x61, 0x72,
+0x3b, 0x4e, 0x65, 0x3b, 0x48, 0x6c, 0x61, 0x3b, 0x4d, 0x6f, 0x6b, 0x4c,
+0x3b, 0x4d, 0x3b, 0x42, 0x3b, 0x52, 0x3b, 0x4e, 0x3b, 0x48, 0x3b, 0x4d,
+0x53, 0x6f, 0x6e, 0x74, 0x6f, 0x3b, 0x4d, 0x76, 0x75, 0x6c, 0x6f, 0x3b,
+0x53, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x3b, 0x53, 0x69, 0x74, 0x68, 0x61,
+0x74, 0x68, 0x75, 0x3b, 0x53, 0x69, 0x6e, 0x65, 0x3b, 0x53, 0x69, 0x68,
+0x6c, 0x61, 0x6e, 0x75, 0x3b, 0x4d, 0x67, 0x71, 0x69, 0x62, 0x65, 0x6c,
+0x6f, 0x53, 0x6f, 0x6e, 0x3b, 0x4d, 0x76, 0x75, 0x3b, 0x53, 0x69, 0x62,
+0x3b, 0x53, 0x69, 0x74, 0x3b, 0x53, 0x69, 0x6e, 0x3b, 0x53, 0x69, 0x68,
+0x3b, 0x4d, 0x67, 0x71, 0x53, 0x3b, 0x4d, 0x3b, 0x53, 0x3b, 0x53, 0x3b,
+0x53, 0x3b, 0x53, 0x3b, 0x4d, 0x73, 0xf8, 0x6e, 0x2e, 0x3b, 0x6d, 0x61,
+0x6e, 0x2e, 0x3b, 0x74, 0x69, 0x72, 0x2e, 0x3b, 0x6f, 0x6e, 0x73, 0x2e,
+0x3b, 0x74, 0x6f, 0x72, 0x2e, 0x3b, 0x66, 0x72, 0x65, 0x2e, 0x3b, 0x6c,
+0xf8, 0x72, 0x2e, 0x73, 0xf8, 0x6e, 0x64, 0x61, 0x67, 0x3b, 0x6d, 0xe5,
+0x6e, 0x64, 0x61, 0x67, 0x3b, 0x74, 0x79, 0x73, 0x64, 0x61, 0x67, 0x3b,
+0x6f, 0x6e, 0x73, 0x64, 0x61, 0x67, 0x3b, 0x74, 0x6f, 0x72, 0x73, 0x64,
+0x61, 0x67, 0x3b, 0x66, 0x72, 0x65, 0x64, 0x61, 0x67, 0x3b, 0x6c, 0x61,
+0x75, 0x72, 0x64, 0x61, 0x67, 0x73, 0xf8, 0x6e, 0x3b, 0x6d, 0xe5, 0x6e,
+0x3b, 0x74, 0x79, 0x73, 0x3b, 0x6f, 0x6e, 0x73, 0x3b, 0x74, 0x6f, 0x72,
+0x3b, 0x66, 0x72, 0x65, 0x3b, 0x6c, 0x61, 0x75, 0x73, 0xf8, 0x2e, 0x3b,
+0x6d, 0xe5, 0x2e, 0x3b, 0x74, 0x79, 0x2e, 0x3b, 0x6f, 0x6e, 0x2e, 0x3b,
+0x74, 0x6f, 0x2e, 0x3b, 0x66, 0x72, 0x2e, 0x3b, 0x6c, 0x61, 0x2e, 0x43,
+0xe4, 0x14b, 0x20, 0x6b, 0x75, 0x254, 0x74, 0x68, 0x3b, 0x4a, 0x69, 0x65,
+0x63, 0x20, 0x6c, 0x61, 0x331, 0x74, 0x3b, 0x52, 0x25b, 0x77, 0x20, 0x6c,
+0xe4, 0x74, 0x6e, 0x69, 0x3b, 0x44, 0x69, 0x254, 0x331, 0x6b, 0x20, 0x6c,
+0xe4, 0x74, 0x6e, 0x69, 0x3b, 0x14a, 0x75, 0x61, 0x61, 0x6e, 0x20, 0x6c,
+0xe4, 0x74, 0x6e, 0x69, 0x3b, 0x44, 0x68, 0x69, 0x65, 0x65, 0x63, 0x20,
+0x6c, 0xe4, 0x74, 0x6e, 0x69, 0x3b, 0x42, 0xe4, 0x6b, 0x25b, 0x6c, 0x20,
+0x6c, 0xe4, 0x74, 0x6e, 0x69, 0x43, 0xe4, 0x14b, 0x3b, 0x4a, 0x69, 0x65,
+0x63, 0x3b, 0x52, 0x25b, 0x77, 0x3b, 0x44, 0x69, 0x254, 0x331, 0x6b, 0x3b,
+0x14a, 0x75, 0x61, 0x61, 0x6e, 0x3b, 0x44, 0x68, 0x69, 0x65, 0x65, 0x63,
+0x3b, 0x42, 0xe4, 0x6b, 0x25b, 0x6c, 0x43, 0x3b, 0x4a, 0x3b, 0x52, 0x3b,
+0x44, 0x3b, 0x14a, 0x3b, 0x44, 0x3b, 0x42, 0x4c, 0x61, 0x6d, 0x75, 0x6c,
+0x75, 0x6e, 0x67, 0x75, 0x3b, 0x4c, 0x6f, 0x6c, 0x65, 0x6d, 0x62, 0x61,
+0x3b, 0x4c, 0x61, 0x63, 0x68, 0x69, 0x77, 0x69, 0x72, 0x69, 0x3b, 0x4c,
+0x61, 0x63, 0x68, 0x69, 0x74, 0x61, 0x74, 0x75, 0x3b, 0x4c, 0x61, 0x63,
+0x68, 0x69, 0x6e, 0x61, 0x79, 0x69, 0x3b, 0x4c, 0x61, 0x63, 0x68, 0x69,
+0x73, 0x61, 0x6e, 0x75, 0x3b, 0x4c, 0x6f, 0x77, 0x65, 0x72, 0x75, 0x6b,
+0x61, 0x4d, 0x75, 0x6c, 0x3b, 0x4c, 0x65, 0x6d, 0x3b, 0x57, 0x69, 0x72,
+0x3b, 0x54, 0x61, 0x74, 0x3b, 0x4e, 0x61, 0x69, 0x3b, 0x53, 0x61, 0x6e,
+0x3b, 0x57, 0x65, 0x72, 0x64, 0x69, 0x6d, 0x65, 0x6e, 0x67, 0x65, 0x3b,
+0x64, 0x69, 0x6c, 0x75, 0x6e, 0x73, 0x3b, 0x64, 0x69, 0x6d, 0x61, 0x72,
+0x73, 0x3b, 0x64, 0x69, 0x6d, 0xe8, 0x63, 0x72, 0x65, 0x73, 0x3b, 0x64,
+0x69, 0x6a, 0xf2, 0x75, 0x73, 0x3b, 0x64, 0x69, 0x76, 0x65, 0x6e, 0x64,
+0x72, 0x65, 0x73, 0x3b, 0x64, 0x69, 0x73, 0x73, 0x61, 0x62, 0x74, 0x65,
+0x44, 0x67, 0x3b, 0x44, 0x6c, 0x3b, 0x44, 0x6d, 0x3b, 0x44, 0x63, 0x3b,
+0x44, 0x6a, 0x3b, 0x44, 0x76, 0x3b, 0x44, 0x73, 0x64, 0x69, 0x6d, 0x65,
+0x6e, 0x67, 0x65, 0x3b, 0x64, 0x65, 0x6c, 0x75, 0x6e, 0x73, 0x3b, 0x64,
+0x69, 0x6d, 0x61, 0x72, 0x73, 0x3b, 0x64, 0x69, 0x6d, 0xe8, 0x72, 0x63,
+0x6c, 0x65, 0x73, 0x3b, 0x64, 0x69, 0x6a, 0x61, 0x75, 0x73, 0x3b, 0x64,
+0x69, 0x75, 0x65, 0x6e, 0x64, 0x72, 0x65, 0x73, 0x3b, 0x64, 0x69, 0x73,
+0x73, 0x61, 0x62, 0x74, 0x65, 0x64, 0x69, 0x6d, 0x3b, 0x64, 0x65, 0x6c,
+0x3b, 0x64, 0x6d, 0x61, 0x3b, 0x64, 0x6d, 0xe8, 0x3b, 0x64, 0x69, 0x6a,
+0x3b, 0x64, 0x69, 0x75, 0x3b, 0x64, 0x69, 0x73, 0x44, 0x3b, 0x4c, 0x3b,
+0x4d, 0x3b, 0x58, 0x3b, 0x4a, 0x3b, 0x55, 0x3b, 0x53, 0xb30, 0xb2c, 0xb3f,
+0xb2c, 0xb3e, 0xb30, 0x3b, 0xb38, 0xb4b, 0xb2e, 0xb2c, 0xb3e, 0xb30, 0x3b, 0xb2e,
+0xb19, 0xb4d, 0xb17, 0xb33, 0xb2c, 0xb3e, 0xb30, 0x3b, 0xb2c, 0xb41, 0xb27, 0xb2c,
+0xb3e, 0xb30, 0x3b, 0xb17, 0xb41, 0xb30, 0xb41, 0xb2c, 0xb3e, 0xb30, 0x3b, 0xb36,
+0xb41, 0xb15, 0xb4d, 0xb30, 0xb2c, 0xb3e, 0xb30, 0x3b, 0xb36, 0xb28, 0xb3f, 0xb2c,
+0xb3e, 0xb30, 0xb30, 0xb2c, 0xb3f, 0x3b, 0xb38, 0xb4b, 0xb2e, 0x3b, 0xb2e, 0xb19,
+0xb4d, 0xb17, 0xb33, 0x3b, 0xb2c, 0xb41, 0xb27, 0x3b, 0xb17, 0xb41, 0xb30, 0xb41,
+0x3b, 0xb36, 0xb41, 0xb15, 0xb4d, 0xb30, 0x3b, 0xb36, 0xb28, 0xb3f, 0xb30, 0x3b,
+0xb38, 0xb4b, 0x3b, 0xb2e, 0x3b, 0xb2c, 0xb41, 0x3b, 0xb17, 0xb41, 0x3b, 0xb36,
+0xb41, 0x3b, 0xb36, 0x44, 0x69, 0x6c, 0x62, 0x61, 0x74, 0x61, 0x3b, 0x57,
+0x69, 0x69, 0x78, 0x61, 0x74, 0x61, 0x3b, 0x51, 0x69, 0x62, 0x78, 0x61,
+0x74, 0x61, 0x3b, 0x52, 0x6f, 0x6f, 0x62, 0x69, 0x69, 0x3b, 0x4b, 0x61,
+0x6d, 0x69, 0x69, 0x73, 0x61, 0x3b, 0x4a, 0x69, 0x6d, 0x61, 0x61, 0x74,
+0x61, 0x3b, 0x53, 0x61, 0x6e, 0x62, 0x61, 0x74, 0x61, 0x44, 0x69, 0x6c,
+0x3b, 0x57, 0x69, 0x78, 0x3b, 0x51, 0x69, 0x62, 0x3b, 0x52, 0x6f, 0x62,
+0x3b, 0x4b, 0x61, 0x6d, 0x3b, 0x4a, 0x69, 0x6d, 0x3b, 0x53, 0x61, 0x6e,
+0x44, 0x3b, 0x57, 0x3b, 0x51, 0x3b, 0x52, 0x3b, 0x4b, 0x3b, 0x4a, 0x3b,
+0x53, 0xd801, 0xdcb9, 0xd801, 0xdcd8, 0x358, 0xd801, 0xdcec, 0xd801, 0xdcd8, 0x20, 0xd801,
+0xdccf, 0xd801, 0xdcd8, 0xd801, 0xdce4, 0xd801, 0xdcd8, 0x358, 0xd801, 0xdcf0, 0xd801, 0xdcd8,
+0xd801, 0xdce4, 0xd801, 0xdce3, 0x3b, 0xd801, 0xdcb9, 0xd801, 0xdcd8, 0x358, 0xd801, 0xdcec,
+0xd801, 0xdcd8, 0x20, 0xd801, 0xdcc4, 0xd801, 0xdcd8, 0xd801, 0xdce1, 0xd801, 0xdcdb, 0x358,
+0xd801, 0xdce7, 0xd801, 0xdce3, 0x3b, 0xd801, 0xdcb9, 0xd801, 0xdcd8, 0x358, 0xd801, 0xdcec,
+0xd801, 0xdcd8, 0x20, 0xd801, 0xdccf, 0xd801, 0xdcdf, 0xd801, 0xdcf5, 0xd801, 0xdcea, 0x358,
+0xd801, 0xdcec, 0xd801, 0xdcd8, 0x3b, 0xd801, 0xdcb9, 0xd801, 0xdcd8, 0x358, 0xd801, 0xdcec,
+0xd801, 0xdcd8, 0x20, 0xd801, 0xdccf, 0xd801, 0xdcdf, 0xd801, 0xdcf5, 0xd801, 0xdcd8, 0xd801,
+0xdcdc, 0xd801, 0xdce3, 0x3b, 0xd801, 0xdcb9, 0xd801, 0xdcd8, 0x358, 0xd801, 0xdcec, 0xd801,
+0xdcd8, 0x20, 0xd801, 0xdccf, 0xd801, 0xdcdf, 0xd801, 0xdcf0, 0xd801, 0xdcea, 0xd801, 0xdcec,
+0xd801, 0xdcd8, 0x3b, 0xd801, 0xdcb9, 0xd801, 0xdcd8, 0x358, 0xd801, 0xdcec, 0xd801, 0xdcd8,
+0x20, 0xd801, 0xdcc8, 0xd801, 0xdcd8, 0x20, 0xd801, 0xdcf5, 0xd801, 0xdcd8, 0xd801, 0xdcf2,
+0xd801, 0xdcd8, 0x20, 0xd801, 0xdcfb, 0xd801, 0xdce3, 0x358, 0x3b, 0xd801, 0xdcb9, 0xd801,
+0xdcd8, 0x358, 0xd801, 0xdcec, 0xd801, 0xdcd8, 0x20, 0xd801, 0xdcc2, 0xd801, 0xdce4, 0xd801,
+0xdcd8, 0xd801, 0xdcf8, 0xd801, 0xdcdf, 0x20, 0xd801, 0xdce3, 0x358, 0xd801, 0xdce4, 0xd801,
+0xdcdf, 0xd801, 0xdccf, 0x3b, 0xd801, 0xdcc4, 0x3b, 0xd801, 0xdccd, 0x3b, 0xd801, 0xdcb4,
+0x3b, 0xd801, 0xdcc8, 0x3b, 0xd801, 0xdcca, 0x3b, 0xd801, 0xdcf8, 0x425, 0x443, 0x44b,
+0x446, 0x430, 0x443, 0x431, 0x43e, 0x43d, 0x3b, 0x41a, 0x44a, 0x443, 0x44b, 0x440,
+0x438, 0x441, 0x4d5, 0x440, 0x3b, 0x414, 0x44b, 0x446, 0x446, 0x4d5, 0x433, 0x3b,
+0x4d4, 0x440, 0x442, 0x44b, 0x446, 0x446, 0x4d5, 0x433, 0x3b, 0x426, 0x44b, 0x43f,
+0x43f, 0x4d5, 0x440, 0x4d5, 0x43c, 0x3b, 0x41c, 0x430, 0x439, 0x440, 0x4d5, 0x43c,
+0x431, 0x43e, 0x43d, 0x3b, 0x421, 0x430, 0x431, 0x430, 0x442, 0x445, 0x443, 0x44b,
+0x446, 0x430, 0x443, 0x431, 0x43e, 0x43d, 0x3b, 0x43a, 0x44a, 0x443, 0x44b, 0x440,
+0x438, 0x441, 0x4d5, 0x440, 0x3b, 0x434, 0x44b, 0x446, 0x446, 0x4d5, 0x433, 0x3b,
+0x4d5, 0x440, 0x442, 0x44b, 0x446, 0x446, 0x4d5, 0x433, 0x3b, 0x446, 0x44b, 0x43f,
+0x43f, 0x4d5, 0x440, 0x4d5, 0x43c, 0x3b, 0x43c, 0x430, 0x439, 0x440, 0x4d5, 0x43c,
+0x431, 0x43e, 0x43d, 0x3b, 0x441, 0x430, 0x431, 0x430, 0x442, 0x425, 0x446, 0x431,
+0x3b, 0x41a, 0x440, 0x441, 0x3b, 0x414, 0x446, 0x433, 0x3b, 0x4d4, 0x440, 0x442,
+0x3b, 0x426, 0x43f, 0x440, 0x3b, 0x41c, 0x440, 0x431, 0x3b, 0x421, 0x431, 0x442,
+0x445, 0x446, 0x431, 0x3b, 0x43a, 0x440, 0x441, 0x3b, 0x434, 0x446, 0x433, 0x3b,
+0x4d5, 0x440, 0x442, 0x3b, 0x446, 0x43f, 0x440, 0x3b, 0x43c, 0x440, 0x431, 0x3b,
+0x441, 0x431, 0x442, 0x425, 0x3b, 0x41a, 0x3b, 0x414, 0x3b, 0x4d4, 0x3b, 0x426,
+0x3b, 0x41c, 0x3b, 0x421, 0x64, 0x6a, 0x61, 0x64, 0x75, 0x6d, 0x69, 0x6e,
+0x67, 0x75, 0x3b, 0x64, 0x6a, 0x61, 0x6c, 0x75, 0x6e, 0x61, 0x3b, 0x64,
+0x6a, 0x61, 0x6d, 0x61, 0x72, 0x73, 0x3b, 0x64, 0x6a, 0x61, 0x72, 0x61,
+0x73, 0x6f, 0x6e, 0x3b, 0x64, 0x6a, 0x61, 0x77, 0x65, 0x70, 0x73, 0x3b,
+0x64, 0x6a, 0x61, 0x62, 0x69, 0xe8, 0x72, 0x6e, 0xe8, 0x3b, 0x64, 0x6a,
+0x61, 0x73, 0x61, 0x62, 0x72, 0x61, 0x64, 0x64, 0x3b, 0x64, 0x6c, 0x3b,
+0x64, 0x6d, 0x3b, 0x64, 0x72, 0x3b, 0x64, 0x77, 0x3b, 0x64, 0x62, 0x3b,
+0x64, 0x73, 0x64a, 0x648, 0x646, 0x6cd, 0x3b, 0x62f, 0x648, 0x646, 0x6cd, 0x3b,
+0x62f, 0x631, 0x6d0, 0x646, 0x6cd, 0x3b, 0x685, 0x644, 0x631, 0x646, 0x6cd, 0x3b,
+0x67e, 0x64a, 0x646, 0x681, 0x646, 0x6cd, 0x3b, 0x62c, 0x645, 0x639, 0x647, 0x3b,
+0x627, 0x648, 0x646, 0x6cd, 0x6cc, 0x6a9, 0x634, 0x646, 0x628, 0x647, 0x3b, 0x62f,
+0x648, 0x634, 0x646, 0x628, 0x647, 0x3b, 0x633, 0x647, 0x200c, 0x634, 0x646, 0x628,
+0x647, 0x3b, 0x686, 0x647, 0x627, 0x631, 0x634, 0x646, 0x628, 0x647, 0x3b, 0x67e,
+0x646, 0x62c, 0x634, 0x646, 0x628, 0x647, 0x3b, 0x62c, 0x645, 0x639, 0x647, 0x3b,
+0x634, 0x646, 0x628, 0x647, 0x6cc, 0x3b, 0x62f, 0x3b, 0x633, 0x3b, 0x686, 0x3b,
+0x67e, 0x3b, 0x62c, 0x3b, 0x634, 0x6e, 0x69, 0x65, 0x64, 0x7a, 0x69, 0x65,
+0x6c, 0x61, 0x3b, 0x70, 0x6f, 0x6e, 0x69, 0x65, 0x64, 0x7a, 0x69, 0x61,
+0x142, 0x65, 0x6b, 0x3b, 0x77, 0x74, 0x6f, 0x72, 0x65, 0x6b, 0x3b, 0x15b,
+0x72, 0x6f, 0x64, 0x61, 0x3b, 0x63, 0x7a, 0x77, 0x61, 0x72, 0x74, 0x65,
+0x6b, 0x3b, 0x70, 0x69, 0x105, 0x74, 0x65, 0x6b, 0x3b, 0x73, 0x6f, 0x62,
+0x6f, 0x74, 0x61, 0x6e, 0x69, 0x65, 0x64, 0x7a, 0x2e, 0x3b, 0x70, 0x6f,
+0x6e, 0x2e, 0x3b, 0x77, 0x74, 0x2e, 0x3b, 0x15b, 0x72, 0x2e, 0x3b, 0x63,
+0x7a, 0x77, 0x2e, 0x3b, 0x70, 0x74, 0x2e, 0x3b, 0x73, 0x6f, 0x62, 0x2e,
+0x4e, 0x3b, 0x50, 0x3b, 0x57, 0x3b, 0x15a, 0x3b, 0x43, 0x3b, 0x50, 0x3b,
+0x53, 0x6e, 0x3b, 0x70, 0x3b, 0x77, 0x3b, 0x15b, 0x3b, 0x63, 0x3b, 0x70,
+0x3b, 0x73, 0x64, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x6f, 0x3b, 0x73, 0x65,
+0x67, 0x75, 0x6e, 0x64, 0x61, 0x2d, 0x66, 0x65, 0x69, 0x72, 0x61, 0x3b,
+0x74, 0x65, 0x72, 0xe7, 0x61, 0x2d, 0x66, 0x65, 0x69, 0x72, 0x61, 0x3b,
+0x71, 0x75, 0x61, 0x72, 0x74, 0x61, 0x2d, 0x66, 0x65, 0x69, 0x72, 0x61,
+0x3b, 0x71, 0x75, 0x69, 0x6e, 0x74, 0x61, 0x2d, 0x66, 0x65, 0x69, 0x72,
+0x61, 0x3b, 0x73, 0x65, 0x78, 0x74, 0x61, 0x2d, 0x66, 0x65, 0x69, 0x72,
+0x61, 0x3b, 0x73, 0xe1, 0x62, 0x61, 0x64, 0x6f, 0x64, 0x6f, 0x6d, 0x2e,
+0x3b, 0x73, 0x65, 0x67, 0x2e, 0x3b, 0x74, 0x65, 0x72, 0x2e, 0x3b, 0x71,
+0x75, 0x61, 0x2e, 0x3b, 0x71, 0x75, 0x69, 0x2e, 0x3b, 0x73, 0x65, 0x78,
+0x2e, 0x3b, 0x73, 0xe1, 0x62, 0x2e, 0x44, 0x3b, 0x53, 0x3b, 0x54, 0x3b,
+0x51, 0x3b, 0x51, 0x3b, 0x53, 0x3b, 0x53, 0x64, 0x6f, 0x6d, 0x69, 0x6e,
+0x67, 0x6f, 0x3b, 0x73, 0x65, 0x67, 0x75, 0x6e, 0x64, 0x61, 0x3b, 0x74,
+0x65, 0x72, 0xe7, 0x61, 0x3b, 0x71, 0x75, 0x61, 0x72, 0x74, 0x61, 0x3b,
+0x71, 0x75, 0x69, 0x6e, 0x74, 0x61, 0x3b, 0x73, 0x65, 0x78, 0x74, 0x61,
+0x3b, 0x73, 0xe1, 0x62, 0x61, 0x64, 0x6f, 0x6e, 0x61, 0x64, 0x12b, 0x6c,
+0x69, 0x3b, 0x70, 0x61, 0x6e, 0x61, 0x64, 0x12b, 0x6c, 0x69, 0x3b, 0x77,
+0x69, 0x73, 0x61, 0x73, 0x12b, 0x64, 0x69, 0x73, 0x3b, 0x70, 0x75, 0x73,
+0x73, 0x69, 0x73, 0x61, 0x77, 0x61, 0x69, 0x74, 0x69, 0x3b, 0x6b, 0x65,
+0x74, 0x77, 0x69, 0x72, 0x74, 0x69, 0x6b, 0x73, 0x3b, 0x70, 0x113, 0x6e,
+0x74, 0x6e, 0x69, 0x6b, 0x73, 0x3b, 0x73, 0x61, 0x62, 0x61, 0x74, 0x74,
+0x69, 0x6b, 0x61, 0x6e, 0x61, 0x64, 0x3b, 0x70, 0x61, 0x6e, 0x3b, 0x77,
+0x69, 0x73, 0x3b, 0x70, 0x75, 0x73, 0x3b, 0x6b, 0x65, 0x74, 0x3b, 0x70,
+0x113, 0x6e, 0x3b, 0x73, 0x61, 0x62, 0x4e, 0x3b, 0x50, 0x3b, 0x57, 0x3b,
+0x50, 0x3b, 0x4b, 0x3b, 0x50, 0x3b, 0x53, 0xa10, 0xa24, 0xa35, 0xa3e, 0xa30,
+0x3b, 0xa38, 0xa4b, 0xa2e, 0xa35, 0xa3e, 0xa30, 0x3b, 0xa2e, 0xa70, 0xa17, 0xa32,
+0xa35, 0xa3e, 0xa30, 0x3b, 0xa2c, 0xa41, 0xa71, 0xa27, 0xa35, 0xa3e, 0xa30, 0x3b,
+0xa35, 0xa40, 0xa30, 0xa35, 0xa3e, 0xa30, 0x3b, 0xa38, 0xa3c, 0xa41, 0xa71, 0xa15,
+0xa30, 0xa35, 0xa3e, 0xa30, 0x3b, 0xa38, 0xa3c, 0xa28, 0xa3f, 0xa71, 0xa1a, 0xa30,
+0xa35, 0xa3e, 0xa30, 0xa10, 0xa24, 0x3b, 0xa38, 0xa4b, 0xa2e, 0x3b, 0xa2e, 0xa70,
+0xa17, 0xa32, 0x3b, 0xa2c, 0xa41, 0xa71, 0xa27, 0x3b, 0xa35, 0xa40, 0xa30, 0x3b,
+0xa38, 0xa3c, 0xa41, 0xa71, 0xa15, 0xa30, 0x3b, 0xa38, 0xa3c, 0xa28, 0xa3f, 0xa71,
+0xa1a, 0xa30, 0xa10, 0x3b, 0xa38, 0xa4b, 0x3b, 0xa2e, 0xa70, 0x3b, 0xa2c, 0xa41,
+0xa71, 0x3b, 0xa35, 0xa40, 0x3b, 0xa38, 0xa3c, 0xa41, 0xa71, 0x3b, 0xa38, 0xa3c,
+0x627, 0x62a, 0x648, 0x627, 0x631, 0x3b, 0x67e, 0x6cc, 0x631, 0x3b, 0x645, 0x646,
+0x6af, 0x644, 0x3b, 0x628, 0x64f, 0x62f, 0x6be, 0x3b, 0x62c, 0x645, 0x639, 0x631,
+0x627, 0x62a, 0x3b, 0x62c, 0x645, 0x639, 0x6c1, 0x3b, 0x6c1, 0x641, 0x62a, 0x6c1,
+0x44, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x6f, 0x3b, 0x4c, 0x75, 0x6e, 0x65,
+0x73, 0x3b, 0x4d, 0x61, 0x72, 0x74, 0x65, 0x73, 0x3b, 0x4d, 0x69, 0xe9,
+0x72, 0x63, 0x6f, 0x6c, 0x65, 0x73, 0x3b, 0x4a, 0x75, 0x65, 0x76, 0x65,
+0x73, 0x3b, 0x56, 0x69, 0x65, 0x72, 0x6e, 0x65, 0x73, 0x3b, 0x53, 0xe1,
+0x62, 0x61, 0x64, 0x6f, 0x44, 0x6f, 0x6d, 0x3b, 0x4c, 0x75, 0x6e, 0x3b,
+0x4d, 0x61, 0x72, 0x3b, 0x4d, 0x69, 0xe9, 0x3b, 0x4a, 0x75, 0x65, 0x3b,
+0x56, 0x69, 0x65, 0x3b, 0x53, 0x61, 0x62, 0x44, 0x3b, 0x4c, 0x3b, 0x4d,
+0x3b, 0x58, 0x3b, 0x4a, 0x3b, 0x56, 0x3b, 0x53, 0x64, 0x75, 0x6d, 0x69,
+0x6e, 0x69, 0x63, 0x103, 0x3b, 0x6c, 0x75, 0x6e, 0x69, 0x3b, 0x6d, 0x61,
+0x72, 0x21b, 0x69, 0x3b, 0x6d, 0x69, 0x65, 0x72, 0x63, 0x75, 0x72, 0x69,
+0x3b, 0x6a, 0x6f, 0x69, 0x3b, 0x76, 0x69, 0x6e, 0x65, 0x72, 0x69, 0x3b,
+0x73, 0xe2, 0x6d, 0x62, 0x103, 0x74, 0x103, 0x64, 0x75, 0x6d, 0x2e, 0x3b,
+0x6c, 0x75, 0x6e, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x6d, 0x69,
+0x65, 0x2e, 0x3b, 0x6a, 0x6f, 0x69, 0x3b, 0x76, 0x69, 0x6e, 0x2e, 0x3b,
+0x73, 0xe2, 0x6d, 0x2e, 0x44, 0x75, 0x6d, 0x3b, 0x4c, 0x75, 0x6e, 0x3b,
+0x4d, 0x61, 0x72, 0x3b, 0x4d, 0x69, 0x65, 0x3b, 0x4a, 0x6f, 0x69, 0x3b,
+0x56, 0x69, 0x6e, 0x3b, 0x53, 0xe2, 0x6d, 0x44, 0x3b, 0x4c, 0x3b, 0x4d,
+0x61, 0x3b, 0x4d, 0x69, 0x3b, 0x4a, 0x3b, 0x56, 0x3b, 0x53, 0x64, 0x75,
+0x6d, 0x65, 0x6e, 0x67, 0x69, 0x61, 0x3b, 0x67, 0x6c, 0x69, 0x6e, 0x64,
+0x65, 0x73, 0x64, 0x69, 0x3b, 0x6d, 0x61, 0x72, 0x64, 0x69, 0x3b, 0x6d,
+0x65, 0x73, 0x65, 0x6d, 0x6e, 0x61, 0x3b, 0x67, 0x69, 0x65, 0x76, 0x67,
+0x69, 0x61, 0x3b, 0x76, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x64, 0x69, 0x3b,
+0x73, 0x6f, 0x6e, 0x64, 0x61, 0x64, 0x75, 0x3b, 0x67, 0x6c, 0x69, 0x3b,
+0x6d, 0x61, 0x3b, 0x6d, 0x65, 0x3b, 0x67, 0x69, 0x65, 0x3b, 0x76, 0x65,
+0x3b, 0x73, 0x6f, 0x44, 0x3b, 0x47, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x47,
+0x3b, 0x56, 0x3b, 0x53, 0x49, 0x6a, 0x75, 0x6d, 0x61, 0x70, 0x69, 0x6c,
+0x69, 0x3b, 0x49, 0x6a, 0x75, 0x6d, 0x61, 0x74, 0x61, 0x74, 0x75, 0x3b,
+0x49, 0x6a, 0x75, 0x6d, 0x61, 0x6e, 0x6e, 0x65, 0x3b, 0x49, 0x6a, 0x75,
+0x6d, 0x61, 0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x41, 0x6c, 0x68, 0x61, 0x6d,
+0x69, 0x73, 0x69, 0x3b, 0x49, 0x6a, 0x75, 0x6d, 0x61, 0x61, 0x3b, 0x49,
+0x6a, 0x75, 0x6d, 0x61, 0x6d, 0x6f, 0x73, 0x69, 0x49, 0x6a, 0x70, 0x3b,
+0x49, 0x6a, 0x74, 0x3b, 0x49, 0x6a, 0x6e, 0x3b, 0x49, 0x6a, 0x74, 0x6e,
+0x3b, 0x41, 0x6c, 0x68, 0x3b, 0x49, 0x6a, 0x75, 0x3b, 0x49, 0x6a, 0x6d,
+0x4b, 0x75, 0x20, 0x77, 0x2019, 0x69, 0x6e, 0x64, 0x77, 0x69, 0x3b, 0x4b,
+0x75, 0x20, 0x77, 0x61, 0x20, 0x6d, 0x62, 0x65, 0x72, 0x65, 0x3b, 0x4b,
+0x75, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x62, 0x69, 0x72, 0x69, 0x3b,
+0x4b, 0x75, 0x20, 0x77, 0x61, 0x20, 0x67, 0x61, 0x74, 0x61, 0x74, 0x75,
+0x3b, 0x4b, 0x75, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x6e, 0x65, 0x3b,
+0x4b, 0x75, 0x20, 0x77, 0x61, 0x20, 0x67, 0x61, 0x74, 0x61, 0x6e, 0x75,
+0x3b, 0x4b, 0x75, 0x20, 0x77, 0x61, 0x20, 0x67, 0x61, 0x74, 0x61, 0x6e,
+0x64, 0x61, 0x74, 0x75, 0x63, 0x75, 0x2e, 0x3b, 0x6d, 0x62, 0x65, 0x2e,
+0x3b, 0x6b, 0x61, 0x62, 0x2e, 0x3b, 0x67, 0x74, 0x75, 0x2e, 0x3b, 0x6b,
+0x61, 0x6e, 0x2e, 0x3b, 0x67, 0x6e, 0x75, 0x2e, 0x3b, 0x67, 0x6e, 0x64,
+0x2e, 0x432, 0x43e, 0x441, 0x43a, 0x440, 0x435, 0x441, 0x435, 0x43d, 0x44c, 0x435,
+0x3b, 0x43f, 0x43e, 0x43d, 0x435, 0x434, 0x435, 0x43b, 0x44c, 0x43d, 0x438, 0x43a,
+0x3b, 0x432, 0x442, 0x43e, 0x440, 0x43d, 0x438, 0x43a, 0x3b, 0x441, 0x440, 0x435,
+0x434, 0x430, 0x3b, 0x447, 0x435, 0x442, 0x432, 0x435, 0x440, 0x433, 0x3b, 0x43f,
+0x44f, 0x442, 0x43d, 0x438, 0x446, 0x430, 0x3b, 0x441, 0x443, 0x431, 0x431, 0x43e,
+0x442, 0x430, 0x432, 0x441, 0x3b, 0x43f, 0x43d, 0x3b, 0x432, 0x442, 0x3b, 0x441,
+0x440, 0x3b, 0x447, 0x442, 0x3b, 0x43f, 0x442, 0x3b, 0x441, 0x431, 0x412, 0x3b,
+0x41f, 0x3b, 0x412, 0x3b, 0x421, 0x3b, 0x427, 0x3b, 0x41f, 0x3b, 0x421, 0x4e,
+0x61, 0x62, 0x61, 0x20, 0x53, 0x61, 0x6d, 0x62, 0x61, 0x74, 0x3b, 0x53,
+0x61, 0x6e, 0x69, 0x3b, 0x53, 0x61, 0x6c, 0x75, 0x73, 0x3b, 0x52, 0x61,
+0x62, 0x75, 0x71, 0x3b, 0x43, 0x61, 0x6d, 0x75, 0x73, 0x3b, 0x4a, 0x75,
+0x6d, 0x71, 0x61, 0x74, 0x61, 0x3b, 0x51, 0x75, 0x6e, 0x78, 0x61, 0x20,
+0x53, 0x61, 0x6d, 0x62, 0x61, 0x74, 0x4e, 0x61, 0x62, 0x3b, 0x53, 0x61,
+0x6e, 0x3b, 0x53, 0x61, 0x6c, 0x3b, 0x52, 0x61, 0x62, 0x3b, 0x43, 0x61,
+0x6d, 0x3b, 0x4a, 0x75, 0x6d, 0x3b, 0x51, 0x75, 0x6e, 0x4e, 0x3b, 0x53,
+0x3b, 0x53, 0x3b, 0x52, 0x3b, 0x43, 0x3b, 0x4a, 0x3b, 0x51, 0x431, 0x430,
+0x441, 0x43a, 0x44b, 0x4bb, 0x44b, 0x430, 0x43d, 0x43d, 0x44c, 0x430, 0x3b, 0x431,
+0x44d, 0x43d, 0x438, 0x434, 0x438, 0x44d, 0x43d, 0x43d, 0x44c, 0x438, 0x43a, 0x3b,
+0x43e, 0x43f, 0x442, 0x443, 0x43e, 0x440, 0x443, 0x43d, 0x43d, 0x44c, 0x443, 0x43a,
+0x3b, 0x441, 0x44d, 0x440, 0x44d, 0x434, 0x44d, 0x3b, 0x447, 0x44d, 0x43f, 0x43f,
+0x438, 0x44d, 0x440, 0x3b, 0x411, 0x44d, 0x44d, 0x442, 0x438, 0x4a5, 0x441, 0x44d,
+0x3b, 0x441, 0x443, 0x431, 0x443, 0x43e, 0x442, 0x430, 0x431, 0x441, 0x3b, 0x431,
+0x43d, 0x3b, 0x43e, 0x43f, 0x3b, 0x441, 0x44d, 0x3b, 0x447, 0x43f, 0x3b, 0x431,
+0x44d, 0x3b, 0x441, 0x431, 0x411, 0x3b, 0x411, 0x3b, 0x41e, 0x3b, 0x421, 0x3b,
+0x427, 0x3b, 0x411, 0x3b, 0x421, 0x4d, 0x64, 0x65, 0x72, 0x6f, 0x74, 0x20,
+0x65, 0x65, 0x20, 0x61, 0x72, 0x65, 0x3b, 0x4d, 0x64, 0x65, 0x72, 0x6f,
+0x74, 0x20, 0x65, 0x65, 0x20, 0x6b, 0x75, 0x6e, 0x69, 0x3b, 0x4d, 0x64,
+0x65, 0x72, 0x6f, 0x74, 0x20, 0x65, 0x65, 0x20, 0x6f, 0x6e, 0x67, 0x2019,
+0x77, 0x61, 0x6e, 0x3b, 0x4d, 0x64, 0x65, 0x72, 0x6f, 0x74, 0x20, 0x65,
+0x65, 0x20, 0x69, 0x6e, 0x65, 0x74, 0x3b, 0x4d, 0x64, 0x65, 0x72, 0x6f,
+0x74, 0x20, 0x65, 0x65, 0x20, 0x69, 0x6c, 0x65, 0x3b, 0x4d, 0x64, 0x65,
+0x72, 0x6f, 0x74, 0x20, 0x65, 0x65, 0x20, 0x73, 0x61, 0x70, 0x61, 0x3b,
+0x4d, 0x64, 0x65, 0x72, 0x6f, 0x74, 0x20, 0x65, 0x65, 0x20, 0x6b, 0x77,
+0x65, 0x41, 0x72, 0x65, 0x3b, 0x4b, 0x75, 0x6e, 0x3b, 0x4f, 0x6e, 0x67,
+0x3b, 0x49, 0x6e, 0x65, 0x3b, 0x49, 0x6c, 0x65, 0x3b, 0x53, 0x61, 0x70,
+0x3b, 0x4b, 0x77, 0x65, 0x41, 0x3b, 0x4b, 0x3b, 0x4f, 0x3b, 0x49, 0x3b,
+0x49, 0x3b, 0x53, 0x3b, 0x4b, 0x42, 0x69, 0x6b, 0x75, 0x61, 0x2d, 0xf4,
+0x6b, 0x6f, 0x3b, 0x42, 0xef, 0x6b, 0x75, 0x61, 0x2d, 0xfb, 0x73, 0x65,
+0x3b, 0x42, 0xef, 0x6b, 0x75, 0x61, 0x2d, 0x70, 0x74, 0xe2, 0x3b, 0x42,
+0xef, 0x6b, 0x75, 0x61, 0x2d, 0x75, 0x73, 0xef, 0xf6, 0x3b, 0x42, 0xef,
+0x6b, 0x75, 0x61, 0x2d, 0x6f, 0x6b, 0xfc, 0x3b, 0x4c, 0xe2, 0x70, 0xf4,
+0x73, 0xf6, 0x3b, 0x4c, 0xe2, 0x79, 0x65, 0x6e, 0x67, 0x61, 0x42, 0x6b,
+0x31, 0x3b, 0x42, 0x6b, 0x32, 0x3b, 0x42, 0x6b, 0x33, 0x3b, 0x42, 0x6b,
+0x34, 0x3b, 0x42, 0x6b, 0x35, 0x3b, 0x4c, 0xe2, 0x70, 0x3b, 0x4c, 0xe2,
+0x79, 0x4b, 0x3b, 0x53, 0x3b, 0x54, 0x3b, 0x53, 0x3b, 0x4b, 0x3b, 0x50,
+0x3b, 0x59, 0x4d, 0x75, 0x6c, 0x75, 0x6e, 0x67, 0x75, 0x3b, 0x4a, 0x75,
+0x6d, 0x61, 0x74, 0x61, 0x74, 0x75, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x6e,
+0x6e, 0x65, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x74, 0x61, 0x6e, 0x6f, 0x3b,
+0x41, 0x6c, 0x61, 0x68, 0x61, 0x6d, 0x69, 0x73, 0x69, 0x3b, 0x49, 0x6a,
+0x75, 0x6d, 0x61, 0x61, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x6d, 0x6f, 0x73,
+0x69, 0x4d, 0x75, 0x6c, 0x3b, 0x4a, 0x74, 0x74, 0x3b, 0x4a, 0x6e, 0x6e,
+0x3b, 0x4a, 0x74, 0x6e, 0x3b, 0x41, 0x6c, 0x68, 0x3b, 0x49, 0x6a, 0x75,
+0x3b, 0x4a, 0x6d, 0x6f, 0x4d, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b,
+0x41, 0x3b, 0x49, 0x3b, 0x4a, 0x930, 0x935, 0x93f, 0x935, 0x93e, 0x938, 0x930,
+0x903, 0x3b, 0x938, 0x94b, 0x92e, 0x935, 0x93e, 0x938, 0x930, 0x903, 0x3b, 0x92e,
+0x902, 0x917, 0x932, 0x935, 0x93e, 0x938, 0x930, 0x903, 0x3b, 0x92c, 0x941, 0x927,
+0x935, 0x93e, 0x938, 0x930, 0x903, 0x3b, 0x917, 0x941, 0x930, 0x941, 0x935, 0x93e,
+0x938, 0x930, 0x3a, 0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930, 0x935, 0x93e, 0x938,
+0x930, 0x903, 0x3b, 0x936, 0x928, 0x93f, 0x935, 0x93e, 0x938, 0x930, 0x903, 0x1c65,
+0x1c64, 0x1c78, 0x1c5c, 0x1c6e, 0x3b, 0x1c5a, 0x1c5b, 0x1c6e, 0x3b, 0x1c75, 0x1c5f, 0x1c5e,
+0x1c6e, 0x3b, 0x1c65, 0x1c5f, 0x1c79, 0x1c5c, 0x1c69, 0x1c71, 0x3b, 0x1c65, 0x1c5f, 0x1c79,
+0x1c68, 0x1c6b, 0x1c64, 0x3b, 0x1c61, 0x1c5f, 0x1c79, 0x1c68, 0x1c69, 0x1c62, 0x3b, 0x1c67,
+0x1c69, 0x1c66, 0x1c69, 0x1c62, 0x1c65, 0x1c64, 0x1c78, 0x3b, 0x1c5a, 0x1c5b, 0x3b, 0x1c75,
+0x1c5f, 0x3b, 0x1c65, 0x1c5f, 0x1c79, 0x3b, 0x1c65, 0x1c5f, 0x1c79, 0x1c68, 0x3b, 0x1c61,
+0x1c5f, 0x1c79, 0x3b, 0x1c67, 0x1c69, 0x1c65, 0x3b, 0x1c5a, 0x3b, 0x1c75, 0x3b, 0x1c65,
+0x3b, 0x1c65, 0x3b, 0x1c61, 0x3b, 0x1c67, 0x64, 0x6f, 0x6d, 0xec, 0x6e, 0x69,
+0x67, 0x61, 0x3b, 0x6c, 0x75, 0x6e, 0x69, 0x73, 0x3b, 0x6d, 0x61, 0x72,
+0x74, 0x69, 0x73, 0x3b, 0x6d, 0xe8, 0x72, 0x63, 0x75, 0x72, 0x69, 0x73,
+0x3b, 0x67, 0x69, 0xf2, 0x62, 0x69, 0x61, 0x3b, 0x63, 0x68, 0x65, 0x6e,
+0xe0, 0x62, 0x75, 0x72, 0x61, 0x3b, 0x73, 0xe0, 0x62, 0x61, 0x64, 0x75,
+0x64, 0x6f, 0x6d, 0x3b, 0x6c, 0x75, 0x6e, 0x3b, 0x6d, 0x61, 0x72, 0x3b,
+0x6d, 0xe8, 0x72, 0x3b, 0x67, 0x69, 0xf2, 0x3b, 0x63, 0x68, 0x65, 0x3b,
+0x73, 0xe0, 0x62, 0x44, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x47,
+0x3b, 0x43, 0x3b, 0x53, 0x44, 0x69, 0x6d, 0x69, 0x6e, 0x67, 0x75, 0x3b,
+0x43, 0x68, 0x69, 0x70, 0x6f, 0x73, 0x69, 0x3b, 0x43, 0x68, 0x69, 0x70,
+0x69, 0x72, 0x69, 0x3b, 0x43, 0x68, 0x69, 0x74, 0x61, 0x74, 0x75, 0x3b,
+0x43, 0x68, 0x69, 0x6e, 0x61, 0x69, 0x3b, 0x43, 0x68, 0x69, 0x73, 0x68,
+0x61, 0x6e, 0x75, 0x3b, 0x53, 0x61, 0x62, 0x75, 0x64, 0x75, 0x44, 0x69,
+0x6d, 0x3b, 0x50, 0x6f, 0x73, 0x3b, 0x50, 0x69, 0x72, 0x3b, 0x54, 0x61,
+0x74, 0x3b, 0x4e, 0x61, 0x69, 0x3b, 0x53, 0x68, 0x61, 0x3b, 0x53, 0x61,
+0x62, 0x44, 0x3b, 0x50, 0x3b, 0x43, 0x3b, 0x54, 0x3b, 0x4e, 0x3b, 0x53,
+0x3b, 0x53, 0x43d, 0x435, 0x434, 0x435, 0x459, 0x430, 0x3b, 0x43f, 0x43e, 0x43d,
+0x435, 0x434, 0x435, 0x459, 0x430, 0x43a, 0x3b, 0x443, 0x442, 0x43e, 0x440, 0x430,
+0x43a, 0x3b, 0x441, 0x440, 0x435, 0x434, 0x430, 0x3b, 0x447, 0x435, 0x442, 0x432,
+0x440, 0x442, 0x430, 0x43a, 0x3b, 0x43f, 0x435, 0x442, 0x430, 0x43a, 0x3b, 0x441,
+0x443, 0x431, 0x43e, 0x442, 0x430, 0x43d, 0x435, 0x434, 0x3b, 0x43f, 0x43e, 0x43d,
+0x3b, 0x443, 0x442, 0x43e, 0x3b, 0x441, 0x440, 0x435, 0x3b, 0x447, 0x435, 0x442,
+0x3b, 0x43f, 0x435, 0x442, 0x3b, 0x441, 0x443, 0x431, 0x43d, 0x435, 0x434, 0x458,
+0x435, 0x459, 0x430, 0x3b, 0x43f, 0x43e, 0x43d, 0x435, 0x434, 0x435, 0x459, 0x430,
+0x43a, 0x3b, 0x443, 0x442, 0x43e, 0x440, 0x430, 0x43a, 0x3b, 0x441, 0x440, 0x438,
+0x458, 0x435, 0x434, 0x430, 0x3b, 0x447, 0x435, 0x442, 0x432, 0x440, 0x442, 0x430,
+0x43a, 0x3b, 0x43f, 0x435, 0x442, 0x430, 0x43a, 0x3b, 0x441, 0x443, 0x431, 0x43e,
+0x442, 0x430, 0x6e, 0x65, 0x64, 0x65, 0x6c, 0x6a, 0x61, 0x3b, 0x70, 0x6f,
+0x6e, 0x65, 0x64, 0x65, 0x6c, 0x6a, 0x61, 0x6b, 0x3b, 0x75, 0x74, 0x6f,
+0x72, 0x61, 0x6b, 0x3b, 0x73, 0x72, 0x65, 0x64, 0x61, 0x3b, 0x10d, 0x65,
+0x74, 0x76, 0x72, 0x74, 0x61, 0x6b, 0x3b, 0x70, 0x65, 0x74, 0x61, 0x6b,
+0x3b, 0x73, 0x75, 0x62, 0x6f, 0x74, 0x61, 0x6e, 0x65, 0x64, 0x3b, 0x70,
+0x6f, 0x6e, 0x3b, 0x75, 0x74, 0x6f, 0x3b, 0x73, 0x72, 0x65, 0x3b, 0x10d,
+0x65, 0x74, 0x3b, 0x70, 0x65, 0x74, 0x3b, 0x73, 0x75, 0x62, 0x6e, 0x65,
+0x64, 0x6a, 0x65, 0x6c, 0x6a, 0x61, 0x3b, 0x70, 0x6f, 0x6e, 0x65, 0x64,
+0x65, 0x6c, 0x6a, 0x61, 0x6b, 0x3b, 0x75, 0x74, 0x6f, 0x72, 0x61, 0x6b,
+0x3b, 0x73, 0x72, 0x69, 0x6a, 0x65, 0x64, 0x61, 0x3b, 0x10d, 0x65, 0x74,
+0x76, 0x72, 0x74, 0x61, 0x6b, 0x3b, 0x70, 0x65, 0x74, 0x61, 0x6b, 0x3b,
+0x73, 0x75, 0x62, 0x6f, 0x74, 0x61, 0x4a, 0x75, 0x6d, 0x61, 0x61, 0x70,
+0x69, 0x69, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x61, 0x74, 0x61, 0x74, 0x75,
+0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x61, 0x6e, 0x65, 0x3b, 0x4a, 0x75, 0x6d,
+0x61, 0x61, 0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x41, 0x6c, 0x68, 0x61, 0x6d,
+0x69, 0x73, 0x69, 0x3b, 0x49, 0x6a, 0x75, 0x6d, 0x61, 0x61, 0x3b, 0x4a,
+0x75, 0x6d, 0x61, 0x61, 0x6d, 0x6f, 0x73, 0x69, 0x4a, 0x70, 0x69, 0x3b,
+0x4a, 0x74, 0x74, 0x3b, 0x4a, 0x6d, 0x6e, 0x3b, 0x4a, 0x74, 0x6e, 0x3b,
+0x41, 0x6c, 0x68, 0x3b, 0x49, 0x6a, 0x75, 0x3b, 0x4a, 0x6d, 0x6f, 0x32,
+0x3b, 0x33, 0x3b, 0x34, 0x3b, 0x35, 0x3b, 0x41, 0x3b, 0x49, 0x3b, 0x31,
+0x53, 0x76, 0x6f, 0x6e, 0x64, 0x6f, 0x3b, 0x4d, 0x75, 0x76, 0x68, 0x75,
+0x72, 0x6f, 0x3b, 0x43, 0x68, 0x69, 0x70, 0x69, 0x72, 0x69, 0x3b, 0x43,
+0x68, 0x69, 0x74, 0x61, 0x74, 0x75, 0x3b, 0x43, 0x68, 0x69, 0x6e, 0x61,
+0x3b, 0x43, 0x68, 0x69, 0x73, 0x68, 0x61, 0x6e, 0x75, 0x3b, 0x4d, 0x75,
+0x67, 0x6f, 0x76, 0x65, 0x72, 0x61, 0x53, 0x76, 0x6f, 0x3b, 0x4d, 0x75,
+0x76, 0x3b, 0x43, 0x68, 0x70, 0x3b, 0x43, 0x68, 0x74, 0x3b, 0x43, 0x68,
+0x6e, 0x3b, 0x43, 0x68, 0x73, 0x3b, 0x4d, 0x75, 0x67, 0x53, 0x3b, 0x4d,
+0x3b, 0x43, 0x3b, 0x43, 0x3b, 0x43, 0x3b, 0x43, 0x3b, 0x4d, 0xa46d, 0xa18f,
+0xa44d, 0x3b, 0xa18f, 0xa282, 0xa2cd, 0x3b, 0xa18f, 0xa282, 0xa44d, 0x3b, 0xa18f, 0xa282,
+0xa315, 0x3b, 0xa18f, 0xa282, 0xa1d6, 0x3b, 0xa18f, 0xa282, 0xa26c, 0x3b, 0xa18f, 0xa282,
+0xa0d8, 0xa46d, 0xa18f, 0x3b, 0xa18f, 0xa2cd, 0x3b, 0xa18f, 0xa44d, 0x3b, 0xa18f, 0xa315,
+0x3b, 0xa18f, 0xa1d6, 0x3b, 0xa18f, 0xa26c, 0x3b, 0xa18f, 0xa0d8, 0xa18f, 0x3b, 0xa2cd,
+0x3b, 0xa44d, 0x3b, 0xa315, 0x3b, 0xa1d6, 0x3b, 0xa26c, 0x3b, 0xa0d8, 0x64, 0x75,
+0x6d, 0xec, 0x6e, 0x69, 0x63, 0x61, 0x3b, 0x6c, 0x75, 0x6e, 0x6e, 0x69,
+0x64, 0xec, 0x61, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x69, 0x64, 0xec, 0x61,
+0x3b, 0x6d, 0x65, 0x72, 0x63, 0x75, 0x72, 0x69, 0x64, 0xec, 0x61, 0x3b,
+0x6a, 0x6f, 0x76, 0x69, 0x64, 0xec, 0x61, 0x3b, 0x76, 0x65, 0x6e, 0x6e,
+0x69, 0x64, 0xec, 0x61, 0x3b, 0x73, 0xe0, 0x62, 0x62, 0x61, 0x74, 0x75,
+0x53, 0x61, 0x6d, 0x62, 0x61, 0x74, 0x61, 0x3b, 0x53, 0x61, 0x6e, 0x79,
+0x6f, 0x3b, 0x4d, 0x61, 0x61, 0x6b, 0x69, 0x73, 0x61, 0x6e, 0x79, 0x6f,
+0x3b, 0x52, 0x6f, 0x6f, 0x77, 0x65, 0x3b, 0x48, 0x61, 0x6d, 0x75, 0x73,
+0x65, 0x3b, 0x41, 0x72, 0x62, 0x65, 0x3b, 0x51, 0x69, 0x64, 0x61, 0x61,
+0x6d, 0x65, 0x53, 0x61, 0x6d, 0x3b, 0x53, 0x61, 0x6e, 0x3b, 0x4d, 0x61,
+0x6b, 0x3b, 0x52, 0x6f, 0x77, 0x3b, 0x48, 0x61, 0x6d, 0x3b, 0x41, 0x72,
+0x62, 0x3b, 0x51, 0x69, 0x64, 0x53, 0x3b, 0x53, 0x3b, 0x4d, 0x3b, 0x52,
+0x3b, 0x48, 0x3b, 0x41, 0x3b, 0x51, 0x6e, 0x69, 0x79, 0x64, 0x7a, 0x69,
+0x65, 0x6c, 0x61, 0x3b, 0x70, 0x79, 0x144, 0x64, 0x7a, 0x69, 0x61, 0x142,
+0x65, 0x6b, 0x3b, 0x77, 0x74, 0x6f, 0x72, 0x65, 0x6b, 0x3b, 0x73, 0x74,
+0x72, 0x7a, 0x6f, 0x64, 0x61, 0x3b, 0x73, 0x7a, 0x74, 0x77, 0x6f, 0x72,
+0x74, 0x65, 0x6b, 0x3b, 0x70, 0x69, 0x14d, 0x6e, 0x74, 0x65, 0x6b, 0x3b,
+0x73, 0x6f, 0x62, 0x6f, 0x74, 0x61, 0x6e, 0x69, 0x79, 0x3b, 0x70, 0x79,
+0x144, 0x3b, 0x77, 0x74, 0x6f, 0x3b, 0x73, 0x74, 0x72, 0x3b, 0x73, 0x7a,
+0x74, 0x3b, 0x70, 0x69, 0x14d, 0x3b, 0x73, 0x6f, 0x62, 0x622, 0x686, 0x631,
+0x3b, 0x633, 0x648, 0x645, 0x631, 0x3b, 0x627, 0x6b1, 0x627, 0x631, 0x648, 0x3b,
+0x627, 0x631, 0x628, 0x639, 0x3b, 0x62e, 0x645, 0x64a, 0x633, 0x3b, 0x62c, 0x645,
+0x639, 0x648, 0x3b, 0x687, 0x646, 0x687, 0x631, 0x622, 0x686, 0x631, 0x3b, 0x633,
+0x648, 0x3b, 0x627, 0x6b1, 0x627, 0x631, 0x648, 0x3b, 0x627, 0x631, 0x628, 0x639,
+0x3b, 0x62e, 0x645, 0x3b, 0x62c, 0x645, 0x639, 0x648, 0x3b, 0x687, 0x646, 0x687,
+0x631, 0x906, 0x930, 0x94d, 0x924, 0x3b, 0x938, 0x942, 0x3b, 0x92e, 0x902, 0x3b,
+0x92c, 0x941, 0x952, 0x927, 0x3b, 0x935, 0x93f, 0x938, 0x3b, 0x91c, 0x941, 0x92e,
+0x3b, 0x91b, 0x902, 0x91b, 0x906, 0x930, 0x94d, 0x924, 0x935, 0x93e, 0x930, 0x3b,
+0x938, 0x942, 0x92e, 0x930, 0x3b, 0x92e, 0x902, 0x917, 0x932, 0x941, 0x3b, 0x92c,
+0x941, 0x952, 0x927, 0x930, 0x3b, 0x935, 0x93f, 0x938, 0x94d, 0x92a, 0x924, 0x3b,
+0x91c, 0x941, 0x92e, 0x94b, 0x3b, 0x91b, 0x902, 0x91b, 0x930, 0x906, 0x3b, 0x938,
+0x942, 0x3b, 0x92e, 0x902, 0x3b, 0x92c, 0x941, 0x927, 0x3b, 0x935, 0x93f, 0x938,
+0x3b, 0x91c, 0x941, 0x3b, 0x91b, 0x902, 0x91b, 0x906, 0x930, 0x94d, 0x924, 0x3b,
+0x938, 0x942, 0x3b, 0x92e, 0x902, 0x917, 0x3b, 0x92c, 0x941, 0x952, 0x927, 0x3b,
+0x935, 0x93f, 0x938, 0x3b, 0x91c, 0x941, 0x92e, 0x3b, 0x91b, 0x902, 0x91b, 0x906,
+0x3b, 0x938, 0x942, 0x3b, 0x92e, 0x902, 0x3b, 0x92c, 0x941, 0x952, 0x3b, 0x935,
+0x93f, 0x3b, 0x91c, 0x941, 0x3b, 0x91b, 0x902, 0xd89, 0xdbb, 0xdd2, 0xdaf, 0xdcf,
+0x3b, 0xdc3, 0xdb3, 0xdd4, 0xdaf, 0xdcf, 0x3b, 0xd85, 0xd9f, 0xdc4, 0xdbb, 0xdd4,
+0xdc0, 0xdcf, 0xdaf, 0xdcf, 0x3b, 0xdb6, 0xdaf, 0xdcf, 0xdaf, 0xdcf, 0x3b, 0xdb6,
+0xdca, 0x200d, 0xdbb, 0xdc4, 0xdc3, 0xdca, 0xdb4, 0xdad, 0xdd2, 0xdb1, 0xdca, 0xdaf,
+0xdcf, 0x3b, 0xdc3, 0xdd2, 0xd9a, 0xdd4, 0xdbb, 0xdcf, 0xdaf, 0xdcf, 0x3b, 0xdc3,
+0xdd9, 0xdb1, 0xdc3, 0xdd4, 0xdbb, 0xdcf, 0xdaf, 0xdcf, 0xd89, 0xdbb, 0xdd2, 0xdaf,
+0xdcf, 0x3b, 0xdc3, 0xdb3, 0xdd4, 0xdaf, 0xdcf, 0x3b, 0xd85, 0xd9f, 0xdc4, 0x3b,
+0xdb6, 0xdaf, 0xdcf, 0xdaf, 0xdcf, 0x3b, 0xdb6, 0xdca, 0x200d, 0xdbb, 0xdc4, 0xdc3,
+0xdca, 0x3b, 0xdc3, 0xdd2, 0xd9a, 0xdd4, 0x3b, 0xdc3, 0xdd9, 0xdb1, 0xd89, 0x3b,
+0xdc3, 0x3b, 0xd85, 0x3b, 0xdb6, 0x3b, 0xdb6, 0xdca, 0x200d, 0xdbb, 0x3b, 0xdc3,
+0xdd2, 0x3b, 0xdc3, 0xdd9, 0x6e, 0x65, 0x64, 0x65, 0x13e, 0x61, 0x3b, 0x70,
+0x6f, 0x6e, 0x64, 0x65, 0x6c, 0x6f, 0x6b, 0x3b, 0x75, 0x74, 0x6f, 0x72,
+0x6f, 0x6b, 0x3b, 0x73, 0x74, 0x72, 0x65, 0x64, 0x61, 0x3b, 0x161, 0x74,
+0x76, 0x72, 0x74, 0x6f, 0x6b, 0x3b, 0x70, 0x69, 0x61, 0x74, 0x6f, 0x6b,
+0x3b, 0x73, 0x6f, 0x62, 0x6f, 0x74, 0x61, 0x6e, 0x65, 0x3b, 0x70, 0x6f,
+0x3b, 0x75, 0x74, 0x3b, 0x73, 0x74, 0x3b, 0x161, 0x74, 0x3b, 0x70, 0x69,
+0x3b, 0x73, 0x6f, 0x6e, 0x3b, 0x70, 0x3b, 0x75, 0x3b, 0x73, 0x3b, 0x161,
+0x3b, 0x70, 0x3b, 0x73, 0x6e, 0x65, 0x64, 0x65, 0x6c, 0x6a, 0x61, 0x3b,
+0x70, 0x6f, 0x6e, 0x65, 0x64, 0x65, 0x6c, 0x6a, 0x65, 0x6b, 0x3b, 0x74,
+0x6f, 0x72, 0x65, 0x6b, 0x3b, 0x73, 0x72, 0x65, 0x64, 0x61, 0x3b, 0x10d,
+0x65, 0x74, 0x72, 0x74, 0x65, 0x6b, 0x3b, 0x70, 0x65, 0x74, 0x65, 0x6b,
+0x3b, 0x73, 0x6f, 0x62, 0x6f, 0x74, 0x61, 0x6e, 0x65, 0x64, 0x2e, 0x3b,
+0x70, 0x6f, 0x6e, 0x2e, 0x3b, 0x74, 0x6f, 0x72, 0x2e, 0x3b, 0x73, 0x72,
+0x65, 0x2e, 0x3b, 0x10d, 0x65, 0x74, 0x2e, 0x3b, 0x70, 0x65, 0x74, 0x2e,
+0x3b, 0x73, 0x6f, 0x62, 0x2e, 0x6e, 0x3b, 0x70, 0x3b, 0x74, 0x3b, 0x73,
+0x3b, 0x10d, 0x3b, 0x70, 0x3b, 0x73, 0x53, 0x61, 0x62, 0x69, 0x69, 0x74,
+0x69, 0x3b, 0x42, 0x61, 0x6c, 0x61, 0x7a, 0x61, 0x3b, 0x4f, 0x77, 0x6f,
+0x6b, 0x75, 0x62, 0x69, 0x6c, 0x69, 0x3b, 0x4f, 0x77, 0x6f, 0x6b, 0x75,
+0x73, 0x61, 0x74, 0x75, 0x3b, 0x4f, 0x6c, 0x6f, 0x6b, 0x75, 0x6e, 0x61,
+0x3b, 0x4f, 0x6c, 0x6f, 0x6b, 0x75, 0x74, 0x61, 0x61, 0x6e, 0x75, 0x3b,
+0x4f, 0x6c, 0x6f, 0x6d, 0x75, 0x6b, 0x61, 0x61, 0x67, 0x61, 0x53, 0x61,
+0x62, 0x69, 0x3b, 0x42, 0x61, 0x6c, 0x61, 0x3b, 0x4b, 0x75, 0x62, 0x69,
+0x3b, 0x4b, 0x75, 0x73, 0x61, 0x3b, 0x4b, 0x75, 0x6e, 0x61, 0x3b, 0x4b,
+0x75, 0x74, 0x61, 0x3b, 0x4d, 0x75, 0x6b, 0x61, 0x53, 0x3b, 0x42, 0x3b,
+0x42, 0x3b, 0x53, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x4d, 0x41, 0x78, 0x61,
+0x64, 0x3b, 0x49, 0x73, 0x6e, 0x69, 0x69, 0x6e, 0x3b, 0x54, 0x61, 0x6c,
+0x61, 0x61, 0x64, 0x6f, 0x3b, 0x41, 0x72, 0x62, 0x61, 0x63, 0x6f, 0x3b,
+0x4b, 0x68, 0x61, 0x6d, 0x69, 0x69, 0x73, 0x3b, 0x4a, 0x69, 0x6d, 0x63,
+0x6f, 0x3b, 0x53, 0x61, 0x62, 0x74, 0x69, 0x41, 0x78, 0x64, 0x3b, 0x49,
+0x73, 0x6e, 0x3b, 0x54, 0x6c, 0x64, 0x6f, 0x3b, 0x41, 0x72, 0x62, 0x63,
+0x3b, 0x4b, 0x68, 0x6d, 0x73, 0x3b, 0x4a, 0x6d, 0x63, 0x3b, 0x53, 0x62,
+0x74, 0x69, 0x41, 0x3b, 0x49, 0x3b, 0x54, 0x3b, 0x41, 0x3b, 0x4b, 0x68,
+0x3b, 0x4a, 0x3b, 0x53, 0x53, 0x6f, 0x6e, 0x74, 0x61, 0x68, 0x61, 0x3b,
+0x4d, 0x6d, 0x61, 0x6e, 0x74, 0x61, 0x68, 0x61, 0x3b, 0x4c, 0x61, 0x62,
+0x6f, 0x62, 0x65, 0x64, 0x69, 0x3b, 0x4c, 0x61, 0x62, 0x6f, 0x72, 0x61,
+0x72, 0x75, 0x3b, 0x4c, 0x61, 0x62, 0x6f, 0x6e, 0x65, 0x3b, 0x4c, 0x61,
+0x62, 0x6f, 0x68, 0x6c, 0x61, 0x6e, 0x65, 0x3b, 0x4d, 0x6f, 0x71, 0x65,
+0x62, 0x65, 0x6c, 0x6f, 0x53, 0x6f, 0x6e, 0x3b, 0x4d, 0x6d, 0x61, 0x3b,
+0x42, 0x65, 0x64, 0x3b, 0x52, 0x61, 0x72, 0x3b, 0x4e, 0x65, 0x3b, 0x48,
+0x6c, 0x61, 0x3b, 0x4d, 0x6f, 0x71, 0x75, 0x53, 0x6f, 0x6e, 0x74, 0x6f,
+0x3b, 0x75, 0x4d, 0x76, 0x75, 0x6c, 0x6f, 0x3b, 0x75, 0x4c, 0x65, 0x73,
+0x69, 0x62, 0x69, 0x6c, 0x69, 0x3b, 0x4c, 0x65, 0x73, 0x69, 0x74, 0x68,
+0x61, 0x74, 0x68, 0x75, 0x3b, 0x75, 0x4c, 0x65, 0x73, 0x69, 0x6e, 0x65,
+0x3b, 0x6e, 0x67, 0x6f, 0x4c, 0x65, 0x73, 0x69, 0x68, 0x6c, 0x61, 0x6e,
+0x75, 0x3b, 0x75, 0x6d, 0x47, 0x71, 0x69, 0x62, 0x65, 0x6c, 0x6f, 0x53,
+0x6f, 0x6e, 0x3b, 0x4d, 0x76, 0x75, 0x3b, 0x42, 0x69, 0x6c, 0x3b, 0x54,
+0x68, 0x61, 0x3b, 0x4e, 0x65, 0x3b, 0x48, 0x6c, 0x61, 0x3b, 0x47, 0x71,
+0x69, 0x64, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x6f, 0x3b, 0x6c, 0x75, 0x6e,
+0x65, 0x73, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x65, 0x73, 0x3b, 0x6d, 0x69,
+0xe9, 0x72, 0x63, 0x6f, 0x6c, 0x65, 0x73, 0x3b, 0x6a, 0x75, 0x65, 0x76,
+0x65, 0x73, 0x3b, 0x76, 0x69, 0x65, 0x72, 0x6e, 0x65, 0x73, 0x3b, 0x73,
+0xe1, 0x62, 0x61, 0x64, 0x6f, 0x64, 0x6f, 0x6d, 0x3b, 0x6c, 0x75, 0x6e,
+0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x6d, 0x69, 0xe9, 0x3b, 0x6a, 0x75, 0x65,
+0x3b, 0x76, 0x69, 0x65, 0x3b, 0x73, 0xe1, 0x62, 0x44, 0x3b, 0x4c, 0x3b,
+0x4d, 0x3b, 0x6d, 0x3b, 0x4a, 0x3b, 0x56, 0x3b, 0x53, 0x2d30, 0x2d59, 0x2d30,
+0x2d4e, 0x2d30, 0x2d59, 0x3b, 0x2d30, 0x2d62, 0x2d4f, 0x2d30, 0x2d59, 0x3b, 0x2d30, 0x2d59,
+0x2d49, 0x2d4f, 0x2d30, 0x2d59, 0x3b, 0x2d30, 0x2d3d, 0x2d55, 0x2d30, 0x2d59, 0x3b, 0x2d30,
+0x2d3d, 0x2d61, 0x2d30, 0x2d59, 0x3b, 0x2d30, 0x2d59, 0x2d49, 0x2d4e, 0x2d61, 0x2d30, 0x2d59,
+0x3b, 0x2d30, 0x2d59, 0x2d49, 0x2d39, 0x2d62, 0x2d30, 0x2d59, 0x2d30, 0x2d59, 0x2d30, 0x3b,
+0x2d30, 0x2d62, 0x2d4f, 0x3b, 0x2d30, 0x2d59, 0x2d49, 0x3b, 0x2d30, 0x2d3d, 0x2d55, 0x3b,
+0x2d30, 0x2d3d, 0x2d61, 0x3b, 0x2d30, 0x2d59, 0x2d49, 0x2d4e, 0x3b, 0x2d30, 0x2d59, 0x2d49,
+0x2d39, 0x4d, 0x69, 0x6e, 0x67, 0x67, 0x75, 0x3b, 0x53, 0x65, 0x6e, 0xe9,
+0x6e, 0x3b, 0x53, 0x61, 0x6c, 0x61, 0x73, 0x61, 0x3b, 0x52, 0x65, 0x62,
+0x6f, 0x3b, 0x4b, 0x65, 0x6d, 0x69, 0x73, 0x3b, 0x4a, 0x75, 0x6d, 0x61,
+0x61, 0x68, 0x3b, 0x53, 0x61, 0x70, 0x74, 0x75, 0x4d, 0x6e, 0x67, 0x3b,
+0x53, 0x65, 0x6e, 0x3b, 0x53, 0x61, 0x6c, 0x3b, 0x52, 0x65, 0x62, 0x3b,
+0x4b, 0x65, 0x6d, 0x3b, 0x4a, 0x75, 0x6d, 0x3b, 0x53, 0x61, 0x70, 0x4c,
+0x69, 0x73, 0x6f, 0x6e, 0x74, 0x66, 0x6f, 0x3b, 0x75, 0x4d, 0x73, 0x6f,
+0x6d, 0x62, 0x75, 0x6c, 0x75, 0x6b, 0x6f, 0x3b, 0x4c, 0x65, 0x73, 0x69,
+0x62, 0x69, 0x6c, 0x69, 0x3b, 0x4c, 0x65, 0x73, 0x69, 0x74, 0x73, 0x61,
+0x74, 0x66, 0x75, 0x3b, 0x4c, 0x65, 0x73, 0x69, 0x6e, 0x65, 0x3b, 0x4c,
+0x65, 0x73, 0x69, 0x68, 0x6c, 0x61, 0x6e, 0x75, 0x3b, 0x75, 0x4d, 0x67,
+0x63, 0x69, 0x62, 0x65, 0x6c, 0x6f, 0x53, 0x6f, 0x6e, 0x3b, 0x4d, 0x73,
+0x6f, 0x3b, 0x42, 0x69, 0x6c, 0x3b, 0x54, 0x73, 0x61, 0x3b, 0x4e, 0x65,
+0x3b, 0x48, 0x6c, 0x61, 0x3b, 0x4d, 0x67, 0x63, 0x73, 0xf6, 0x6e, 0x64,
+0x61, 0x67, 0x3b, 0x6d, 0xe5, 0x6e, 0x64, 0x61, 0x67, 0x3b, 0x74, 0x69,
+0x73, 0x64, 0x61, 0x67, 0x3b, 0x6f, 0x6e, 0x73, 0x64, 0x61, 0x67, 0x3b,
+0x74, 0x6f, 0x72, 0x73, 0x64, 0x61, 0x67, 0x3b, 0x66, 0x72, 0x65, 0x64,
+0x61, 0x67, 0x3b, 0x6c, 0xf6, 0x72, 0x64, 0x61, 0x67, 0x73, 0xf6, 0x6e,
+0x3b, 0x6d, 0xe5, 0x6e, 0x3b, 0x74, 0x69, 0x73, 0x3b, 0x6f, 0x6e, 0x73,
+0x3b, 0x74, 0x6f, 0x72, 0x73, 0x3b, 0x66, 0x72, 0x65, 0x3b, 0x6c, 0xf6,
+0x72, 0x53, 0x75, 0x6e, 0x6e, 0x74, 0x69, 0x67, 0x3b, 0x4d, 0xe4, 0xe4,
+0x6e, 0x74, 0x69, 0x67, 0x3b, 0x5a, 0x69, 0x69, 0x73, 0x63, 0x68, 0x74,
+0x69, 0x67, 0x3b, 0x4d, 0x69, 0x74, 0x74, 0x77, 0x75, 0x63, 0x68, 0x3b,
+0x44, 0x75, 0x6e, 0x73, 0x63, 0x68, 0x74, 0x69, 0x67, 0x3b, 0x46, 0x72,
+0x69, 0x69, 0x74, 0x69, 0x67, 0x3b, 0x53, 0x61, 0x6d, 0x73, 0x63, 0x68,
+0x74, 0x69, 0x67, 0x53, 0x75, 0x2e, 0x3b, 0x4d, 0xe4, 0x2e, 0x3b, 0x5a,
+0x69, 0x2e, 0x3b, 0x4d, 0x69, 0x2e, 0x3b, 0x44, 0x75, 0x2e, 0x3b, 0x46,
+0x72, 0x2e, 0x3b, 0x53, 0x61, 0x2e, 0x71a, 0x715, 0x712, 0x72b, 0x712, 0x710,
+0x3b, 0x72c, 0x72a, 0x71d, 0x722, 0x712, 0x72b, 0x712, 0x710, 0x3b, 0x72c, 0x720,
+0x72c, 0x712, 0x72b, 0x712, 0x710, 0x3b, 0x710, 0x72a, 0x712, 0x725, 0x712, 0x72b,
+0x712, 0x710, 0x3b, 0x71a, 0x721, 0x72b, 0x712, 0x72b, 0x712, 0x710, 0x3b, 0x725,
+0x72a, 0x718, 0x712, 0x72c, 0x710, 0x3b, 0x72b, 0x712, 0x72c, 0x710, 0x71a, 0x715,
+0x3b, 0x72c, 0x72a, 0x71d, 0x722, 0x3b, 0x72c, 0x720, 0x72c, 0x3b, 0x710, 0x72a,
+0x712, 0x725, 0x3b, 0x71a, 0x721, 0x72b, 0x3b, 0x725, 0x72a, 0x718, 0x3b, 0x72b,
+0x712, 0x72c, 0x710, 0x71a, 0x3b, 0x72c, 0x3b, 0x72c, 0x3b, 0x710, 0x3b, 0x71a,
+0x3b, 0x725, 0x3b, 0x72b, 0x2d30, 0x2d59, 0x2d30, 0x2d4e, 0x2d30, 0x2d59, 0x3b, 0x2d30,
+0x2d62, 0x2d4f, 0x2d30, 0x2d59, 0x3b, 0x2d30, 0x2d59, 0x2d49, 0x2d4f, 0x2d30, 0x2d59, 0x3b,
+0x2d30, 0x2d3d, 0x2d55, 0x2d30, 0x2d59, 0x3b, 0x2d30, 0x2d3d, 0x2d61, 0x2d30, 0x2d59, 0x3b,
+0x2d59, 0x2d49, 0x2d4e, 0x2d61, 0x2d30, 0x2d59, 0x3b, 0x2d30, 0x2d59, 0x2d49, 0x2d39, 0x2d62,
+0x2d30, 0x2d59, 0x61, 0x73, 0x61, 0x6d, 0x61, 0x73, 0x3b, 0x61, 0x79, 0x6e,
+0x61, 0x73, 0x3b, 0x61, 0x73, 0x69, 0x6e, 0x61, 0x73, 0x3b, 0x61, 0x6b,
+0x1e5b, 0x61, 0x73, 0x3b, 0x61, 0x6b, 0x77, 0x61, 0x73, 0x3b, 0x61, 0x73,
+0x69, 0x6d, 0x77, 0x61, 0x73, 0x3b, 0x61, 0x73, 0x69, 0x1e0d, 0x79, 0x61,
+0x73, 0x61, 0x73, 0x61, 0x3b, 0x61, 0x79, 0x6e, 0x3b, 0x61, 0x73, 0x69,
+0x3b, 0x61, 0x6b, 0x1e5b, 0x3b, 0x61, 0x6b, 0x77, 0x3b, 0x61, 0x73, 0x69,
+0x6d, 0x3b, 0x61, 0x73, 0x69, 0x1e0d, 0x49, 0x74, 0x75, 0x6b, 0x75, 0x20,
+0x6a, 0x61, 0x20, 0x6a, 0x75, 0x6d, 0x77, 0x61, 0x3b, 0x4b, 0x75, 0x72,
+0x61, 0x6d, 0x75, 0x6b, 0x61, 0x20, 0x6a, 0x69, 0x6d, 0x77, 0x65, 0x72,
+0x69, 0x3b, 0x4b, 0x75, 0x72, 0x61, 0x6d, 0x75, 0x6b, 0x61, 0x20, 0x6b,
+0x61, 0x77, 0x69, 0x3b, 0x4b, 0x75, 0x72, 0x61, 0x6d, 0x75, 0x6b, 0x61,
+0x20, 0x6b, 0x61, 0x64, 0x61, 0x64, 0x75, 0x3b, 0x4b, 0x75, 0x72, 0x61,
+0x6d, 0x75, 0x6b, 0x61, 0x20, 0x6b, 0x61, 0x6e, 0x61, 0x3b, 0x4b, 0x75,
+0x72, 0x61, 0x6d, 0x75, 0x6b, 0x61, 0x20, 0x6b, 0x61, 0x73, 0x61, 0x6e,
+0x75, 0x3b, 0x4b, 0x69, 0x66, 0x75, 0x6c, 0x61, 0x20, 0x6e, 0x67, 0x75,
+0x77, 0x6f, 0x4a, 0x75, 0x6d, 0x3b, 0x4a, 0x69, 0x6d, 0x3b, 0x4b, 0x61,
+0x77, 0x3b, 0x4b, 0x61, 0x64, 0x3b, 0x4b, 0x61, 0x6e, 0x3b, 0x4b, 0x61,
+0x73, 0x3b, 0x4e, 0x67, 0x75, 0x4a, 0x3b, 0x4a, 0x3b, 0x4b, 0x3b, 0x4b,
+0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x4e, 0x42f, 0x43a, 0x448, 0x430, 0x43d, 0x431,
+0x435, 0x3b, 0x414, 0x443, 0x448, 0x430, 0x43d, 0x431, 0x435, 0x3b, 0x421, 0x435,
+0x448, 0x430, 0x43d, 0x431, 0x435, 0x3b, 0x427, 0x43e, 0x440, 0x448, 0x430, 0x43d,
+0x431, 0x435, 0x3b, 0x41f, 0x430, 0x43d, 0x4b7, 0x448, 0x430, 0x43d, 0x431, 0x435,
+0x3b, 0x4b6, 0x443, 0x43c, 0x44a, 0x430, 0x3b, 0x428, 0x430, 0x43d, 0x431, 0x435,
+0x42f, 0x448, 0x431, 0x3b, 0x414, 0x448, 0x431, 0x3b, 0x421, 0x448, 0x431, 0x3b,
+0x427, 0x448, 0x431, 0x3b, 0x41f, 0x448, 0x431, 0x3b, 0x4b6, 0x43c, 0x44a, 0x3b,
+0x428, 0x43d, 0x431, 0x42f, 0x3b, 0x414, 0x3b, 0x421, 0x3b, 0x427, 0x3b, 0x41f,
+0x3b, 0x4b6, 0x3b, 0x428, 0xb9e, 0xbbe, 0xbaf, 0xbbf, 0xbb1, 0xbc1, 0x3b, 0xba4,
+0xbbf, 0xb99, 0xbcd, 0xb95, 0xbb3, 0xbcd, 0x3b, 0xb9a, 0xbc6, 0xbb5, 0xbcd, 0xbb5,
+0xbbe, 0xbaf, 0xbcd, 0x3b, 0xbaa, 0xbc1, 0xba4, 0xba9, 0xbcd, 0x3b, 0xbb5, 0xbbf,
+0xbaf, 0xbbe, 0xbb4, 0xba9, 0xbcd, 0x3b, 0xbb5, 0xbc6, 0xbb3, 0xbcd, 0xbb3, 0xbbf,
+0x3b, 0xb9a, 0xba9, 0xbbf, 0xb9e, 0xbbe, 0xbaf, 0xbbf, 0x2e, 0x3b, 0xba4, 0xbbf,
+0xb99, 0xbcd, 0x2e, 0x3b, 0xb9a, 0xbc6, 0xbb5, 0xbcd, 0x2e, 0x3b, 0xbaa, 0xbc1,
+0xba4, 0x2e, 0x3b, 0xbb5, 0xbbf, 0xbaf, 0xbbe, 0x2e, 0x3b, 0xbb5, 0xbc6, 0xbb3,
+0xbcd, 0x2e, 0x3b, 0xb9a, 0xba9, 0xbbf, 0xb9e, 0xbbe, 0x3b, 0xba4, 0xbbf, 0x3b,
+0xb9a, 0xbc6, 0x3b, 0xbaa, 0xbc1, 0x3b, 0xbb5, 0xbbf, 0x3b, 0xbb5, 0xbc6, 0x3b,
+0xb9a, 0x4a, 0x69, 0x79, 0x61, 0x78, 0x20, 0x73, 0x6e, 0x67, 0x61, 0x79,
+0x61, 0x6e, 0x3b, 0x74, 0x67, 0x4b, 0x69, 0x6e, 0x67, 0x61, 0x6c, 0x20,
+0x6a, 0x69, 0x79, 0x61, 0x78, 0x20, 0x69, 0x79, 0x61, 0x78, 0x20, 0x73,
+0x6e, 0x67, 0x61, 0x79, 0x61, 0x6e, 0x3b, 0x74, 0x67, 0x44, 0x68, 0x61,
+0x20, 0x6a, 0x69, 0x79, 0x61, 0x78, 0x20, 0x69, 0x79, 0x61, 0x78, 0x20,
+0x73, 0x6e, 0x67, 0x61, 0x79, 0x61, 0x6e, 0x3b, 0x74, 0x67, 0x54, 0x72,
+0x75, 0x20, 0x6a, 0x69, 0x79, 0x61, 0x78, 0x20, 0x69, 0x79, 0x61, 0x78,
+0x20, 0x73, 0x6e, 0x67, 0x61, 0x79, 0x61, 0x6e, 0x3b, 0x74, 0x67, 0x53,
+0x70, 0x61, 0x63, 0x20, 0x6a, 0x69, 0x79, 0x61, 0x78, 0x20, 0x69, 0x79,
+0x61, 0x78, 0x20, 0x73, 0x6e, 0x67, 0x61, 0x79, 0x61, 0x6e, 0x3b, 0x74,
+0x67, 0x52, 0x69, 0x6d, 0x61, 0x20, 0x6a, 0x69, 0x79, 0x61, 0x78, 0x20,
+0x69, 0x79, 0x61, 0x78, 0x20, 0x73, 0x6e, 0x67, 0x61, 0x79, 0x61, 0x6e,
+0x3b, 0x74, 0x67, 0x4d, 0x61, 0x74, 0x61, 0x72, 0x75, 0x20, 0x6a, 0x69,
+0x79, 0x61, 0x78, 0x20, 0x69, 0x79, 0x61, 0x78, 0x20, 0x73, 0x6e, 0x67,
+0x61, 0x79, 0x61, 0x6e, 0x45, 0x6d, 0x70, 0x3b, 0x4b, 0x69, 0x6e, 0x3b,
+0x44, 0x68, 0x61, 0x3b, 0x54, 0x72, 0x75, 0x3b, 0x53, 0x70, 0x61, 0x3b,
+0x52, 0x69, 0x6d, 0x3b, 0x4d, 0x61, 0x74, 0x45, 0x3b, 0x4b, 0x3b, 0x44,
+0x3b, 0x54, 0x3b, 0x53, 0x3b, 0x52, 0x3b, 0x4d, 0x44f, 0x43a, 0x448, 0x4d9,
+0x43c, 0x431, 0x435, 0x3b, 0x434, 0x4af, 0x448, 0x4d9, 0x43c, 0x431, 0x435, 0x3b,
+0x441, 0x438, 0x448, 0x4d9, 0x43c, 0x431, 0x435, 0x3b, 0x447, 0x4d9, 0x440, 0x448,
+0x4d9, 0x43c, 0x431, 0x435, 0x3b, 0x43f, 0x4d9, 0x43d, 0x497, 0x435, 0x448, 0x4d9,
+0x43c, 0x431, 0x435, 0x3b, 0x497, 0x43e, 0x43c, 0x433, 0x430, 0x3b, 0x448, 0x438,
+0x43c, 0x431, 0x4d9, 0x44f, 0x43a, 0x448, 0x2e, 0x3b, 0x434, 0x4af, 0x448, 0x2e,
+0x3b, 0x441, 0x438, 0x448, 0x2e, 0x3b, 0x447, 0x4d9, 0x440, 0x2e, 0x3b, 0x43f,
+0x4d9, 0x43d, 0x497, 0x2e, 0x3b, 0x497, 0x43e, 0x43c, 0x2e, 0x3b, 0x448, 0x438,
+0x43c, 0x2e, 0x42f, 0x3b, 0x414, 0x3b, 0x421, 0x3b, 0x427, 0x3b, 0x41f, 0x3b,
+0x496, 0x3b, 0x428, 0xc06, 0xc26, 0xc3f, 0xc35, 0xc3e, 0xc30, 0xc02, 0x3b, 0xc38,
+0xc4b, 0xc2e, 0xc35, 0xc3e, 0xc30, 0xc02, 0x3b, 0xc2e, 0xc02, 0xc17, 0xc33, 0xc35,
+0xc3e, 0xc30, 0xc02, 0x3b, 0xc2c, 0xc41, 0xc27, 0xc35, 0xc3e, 0xc30, 0xc02, 0x3b,
+0xc17, 0xc41, 0xc30, 0xc41, 0xc35, 0xc3e, 0xc30, 0xc02, 0x3b, 0xc36, 0xc41, 0xc15,
+0xc4d, 0xc30, 0xc35, 0xc3e, 0xc30, 0xc02, 0x3b, 0xc36, 0xc28, 0xc3f, 0xc35, 0xc3e,
+0xc30, 0xc02, 0xc06, 0xc26, 0xc3f, 0x3b, 0xc38, 0xc4b, 0xc2e, 0x3b, 0xc2e, 0xc02,
+0xc17, 0xc33, 0x3b, 0xc2c, 0xc41, 0xc27, 0x3b, 0xc17, 0xc41, 0xc30, 0xc41, 0x3b,
+0xc36, 0xc41, 0xc15, 0xc4d, 0xc30, 0x3b, 0xc36, 0xc28, 0xc3f, 0xc06, 0x3b, 0xc38,
+0xc4b, 0x3b, 0xc2e, 0x3b, 0xc2c, 0xc41, 0x3b, 0xc17, 0xc41, 0x3b, 0xc36, 0xc41,
+0x3b, 0xc36, 0x4e, 0x61, 0x6b, 0x61, 0x65, 0x6a, 0x75, 0x6d, 0x61, 0x3b,
+0x4e, 0x61, 0x6b, 0x61, 0x65, 0x62, 0x61, 0x72, 0x61, 0x73, 0x61, 0x3b,
+0x4e, 0x61, 0x6b, 0x61, 0x61, 0x72, 0x65, 0x3b, 0x4e, 0x61, 0x6b, 0x61,
+0x75, 0x6e, 0x69, 0x3b, 0x4e, 0x61, 0x6b, 0x61, 0x75, 0x6e, 0x67, 0x2019,
+0x6f, 0x6e, 0x3b, 0x4e, 0x61, 0x6b, 0x61, 0x6b, 0x61, 0x6e, 0x79, 0x3b,
+0x4e, 0x61, 0x6b, 0x61, 0x73, 0x61, 0x62, 0x69, 0x74, 0x69, 0x4a, 0x75,
+0x6d, 0x3b, 0x42, 0x61, 0x72, 0x3b, 0x41, 0x61, 0x72, 0x3b, 0x55, 0x6e,
+0x69, 0x3b, 0x55, 0x6e, 0x67, 0x3b, 0x4b, 0x61, 0x6e, 0x3b, 0x53, 0x61,
+0x62, 0x4a, 0x3b, 0x42, 0x3b, 0x41, 0x3b, 0x55, 0x3b, 0x55, 0x3b, 0x4b,
+0x3b, 0x53, 0xe27, 0xe31, 0xe19, 0xe2d, 0xe32, 0xe17, 0xe34, 0xe15, 0xe22, 0xe4c,
+0x3b, 0xe27, 0xe31, 0xe19, 0xe08, 0xe31, 0xe19, 0xe17, 0xe23, 0xe4c, 0x3b, 0xe27,
+0xe31, 0xe19, 0xe2d, 0xe31, 0xe07, 0xe04, 0xe32, 0xe23, 0x3b, 0xe27, 0xe31, 0xe19,
+0xe1e, 0xe38, 0xe18, 0x3b, 0xe27, 0xe31, 0xe19, 0xe1e, 0xe24, 0xe2b, 0xe31, 0xe2a,
+0xe1a, 0xe14, 0xe35, 0x3b, 0xe27, 0xe31, 0xe19, 0xe28, 0xe38, 0xe01, 0xe23, 0xe4c,
+0x3b, 0xe27, 0xe31, 0xe19, 0xe40, 0xe2a, 0xe32, 0xe23, 0xe4c, 0xe2d, 0xe32, 0x2e,
+0x3b, 0xe08, 0x2e, 0x3b, 0xe2d, 0x2e, 0x3b, 0xe1e, 0x2e, 0x3b, 0xe1e, 0xe24,
+0x2e, 0x3b, 0xe28, 0x2e, 0x3b, 0xe2a, 0x2e, 0xe2d, 0xe32, 0x3b, 0xe08, 0x3b,
+0xe2d, 0x3b, 0xe1e, 0x3b, 0xe1e, 0xe24, 0x3b, 0xe28, 0x3b, 0xe2a, 0xf42, 0xf5f,
+0xf60, 0xf0b, 0xf49, 0xf72, 0xf0b, 0xf58, 0xf0b, 0x3b, 0xf42, 0xf5f, 0xf60, 0xf0b,
+0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0x3b, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf58, 0xf72,
+0xf42, 0xf0b, 0xf51, 0xf58, 0xf62, 0xf0b, 0x3b, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf63,
+0xfb7, 0xf42, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf55, 0xf74,
+0xf62, 0xf0b, 0xf56, 0xf74, 0xf0b, 0x3b, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf54, 0xf0b,
+0xf66, 0xf44, 0xf66, 0xf0b, 0x3b, 0xf42, 0xf5f, 0xf60, 0xf0b, 0xf66, 0xfa4, 0xf7a,
+0xf53, 0xf0b, 0xf54, 0xf0b, 0xf49, 0xf72, 0xf0b, 0xf58, 0xf0b, 0x3b, 0xf5f, 0xfb3,
+0xf0b, 0xf56, 0xf0b, 0x3b, 0xf58, 0xf72, 0xf42, 0xf0b, 0xf51, 0xf58, 0xf62, 0xf0b,
+0x3b, 0xf63, 0xfb7, 0xf42, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf55, 0xf74, 0xf62, 0xf0b,
+0xf56, 0xf74, 0xf0b, 0x3b, 0xf54, 0xf0b, 0xf66, 0xf44, 0xf66, 0xf0b, 0x3b, 0xf66,
+0xfa4, 0xf7a, 0xf53, 0xf0b, 0xf54, 0xf0b, 0xf49, 0xf72, 0x3b, 0xf5f, 0xfb3, 0x3b,
+0xf58, 0xf72, 0xf42, 0x3b, 0xf63, 0xfb7, 0xf42, 0x3b, 0xf55, 0xf74, 0xf62, 0x3b,
+0xf66, 0xf44, 0xf66, 0x3b, 0xf66, 0xfa4, 0xf7a, 0xf53, 0x1230, 0x1295, 0x1260, 0x1275,
+0x20, 0x12d3, 0x1263, 0x12ed, 0x3b, 0x1230, 0x1296, 0x3b, 0x1273, 0x120b, 0x1238, 0x1296,
+0x3b, 0x12a3, 0x1228, 0x122d, 0x1263, 0x12d3, 0x3b, 0x12a8, 0x121a, 0x123d, 0x3b, 0x1305,
+0x121d, 0x12d3, 0x1275, 0x3b, 0x1230, 0x1295, 0x1260, 0x1275, 0x20, 0x1295, 0x12a2, 0x123d,
+0x1230, 0x2f, 0x12d3, 0x3b, 0x1230, 0x1296, 0x3b, 0x1273, 0x120b, 0x1238, 0x3b, 0x12a3,
+0x1228, 0x122d, 0x3b, 0x12a8, 0x121a, 0x123d, 0x3b, 0x1305, 0x121d, 0x12d3, 0x3b, 0x1230,
+0x2f, 0x1295, 0x1230, 0x3b, 0x1230, 0x3b, 0x1273, 0x3b, 0x12a3, 0x3b, 0x12a8, 0x3b,
+0x1305, 0x3b, 0x1230, 0x1230, 0x1295, 0x1260, 0x1275, 0x3b, 0x1230, 0x1291, 0x12ed, 0x3b,
+0x1230, 0x1209, 0x1235, 0x3b, 0x1228, 0x1261, 0x12d5, 0x3b, 0x1213, 0x1219, 0x1235, 0x3b,
+0x12d3, 0x122d, 0x1262, 0x3b, 0x1240, 0x12f3, 0x121d, 0x1230, 0x1295, 0x3b, 0x1230, 0x1291,
+0x3b, 0x1230, 0x1209, 0x3b, 0x1228, 0x1261, 0x3b, 0x1213, 0x1219, 0x3b, 0x12d3, 0x122d,
+0x3b, 0x1240, 0x12f3, 0x1230, 0x3b, 0x1230, 0x3b, 0x1230, 0x3b, 0x1228, 0x3b, 0x1213,
+0x3b, 0x12d3, 0x3b, 0x1240, 0x53, 0x61, 0x6e, 0x64, 0x65, 0x3b, 0x4d, 0x61,
+0x6e, 0x64, 0x65, 0x3b, 0x54, 0x75, 0x6e, 0x64, 0x65, 0x3b, 0x54, 0x72,
+0x69, 0x6e, 0x64, 0x65, 0x3b, 0x46, 0x6f, 0x6e, 0x64, 0x65, 0x3b, 0x46,
+0x72, 0x61, 0x69, 0x64, 0x65, 0x3b, 0x53, 0x61, 0x72, 0x65, 0x72, 0x65,
+0x53, 0x61, 0x6e, 0x3b, 0x4d, 0x61, 0x6e, 0x3b, 0x54, 0x75, 0x6e, 0x3b,
+0x54, 0x72, 0x69, 0x3b, 0x46, 0x6f, 0x6e, 0x3b, 0x46, 0x72, 0x61, 0x3b,
+0x53, 0x61, 0x72, 0x53, 0x101, 0x70, 0x61, 0x74, 0x65, 0x3b, 0x4d, 0x14d,
+0x6e, 0x69, 0x74, 0x65, 0x3b, 0x54, 0x16b, 0x73, 0x69, 0x74, 0x65, 0x3b,
+0x50, 0x75, 0x6c, 0x65, 0x6c, 0x75, 0x6c, 0x75, 0x3b, 0x54, 0x75, 0x2bb,
+0x61, 0x70, 0x75, 0x6c, 0x65, 0x6c, 0x75, 0x6c, 0x75, 0x3b, 0x46, 0x61,
+0x6c, 0x61, 0x69, 0x74, 0x65, 0x3b, 0x54, 0x6f, 0x6b, 0x6f, 0x6e, 0x61,
+0x6b, 0x69, 0x53, 0x101, 0x70, 0x3b, 0x4d, 0x14d, 0x6e, 0x3b, 0x54, 0x16b,
+0x73, 0x3b, 0x50, 0x75, 0x6c, 0x3b, 0x54, 0x75, 0x2bb, 0x61, 0x3b, 0x46,
+0x61, 0x6c, 0x3b, 0x54, 0x6f, 0x6b, 0x53, 0x3b, 0x4d, 0x3b, 0x54, 0x3b,
+0x50, 0x3b, 0x54, 0x3b, 0x46, 0x3b, 0x54, 0x53, 0x6f, 0x6e, 0x74, 0x61,
+0x3b, 0x4d, 0x75, 0x73, 0x75, 0x6d, 0x62, 0x68, 0x75, 0x6e, 0x75, 0x6b,
+0x75, 0x3b, 0x52, 0x61, 0x76, 0x75, 0x6d, 0x62, 0x69, 0x72, 0x68, 0x69,
+0x3b, 0x52, 0x61, 0x76, 0x75, 0x6e, 0x68, 0x61, 0x72, 0x68, 0x75, 0x3b,
+0x52, 0x61, 0x76, 0x75, 0x6d, 0x75, 0x6e, 0x65, 0x3b, 0x52, 0x61, 0x76,
+0x75, 0x6e, 0x74, 0x6c, 0x68, 0x61, 0x6e, 0x75, 0x3b, 0x4d, 0x75, 0x67,
+0x71, 0x69, 0x76, 0x65, 0x6c, 0x61, 0x53, 0x6f, 0x6e, 0x3b, 0x4d, 0x75,
+0x73, 0x3b, 0x42, 0x69, 0x72, 0x3b, 0x48, 0x61, 0x72, 0x3b, 0x4e, 0x65,
+0x3b, 0x54, 0x6c, 0x68, 0x3b, 0x4d, 0x75, 0x67, 0x54, 0x73, 0x68, 0x69,
+0x70, 0x69, 0x3b, 0x4d, 0x6f, 0x73, 0x6f, 0x70, 0x75, 0x6c, 0x6f, 0x67,
+0x6f, 0x3b, 0x4c, 0x61, 0x62, 0x6f, 0x62, 0x65, 0x64, 0x69, 0x3b, 0x4c,
+0x61, 0x62, 0x6f, 0x72, 0x61, 0x72, 0x6f, 0x3b, 0x4c, 0x61, 0x62, 0x6f,
+0x6e, 0x65, 0x3b, 0x4c, 0x61, 0x62, 0x6f, 0x74, 0x6c, 0x68, 0x61, 0x6e,
+0x6f, 0x3b, 0x4d, 0x61, 0x74, 0x6c, 0x68, 0x61, 0x74, 0x73, 0x6f, 0x54,
+0x73, 0x68, 0x3b, 0x4d, 0x6f, 0x73, 0x3b, 0x4c, 0x61, 0x62, 0x62, 0x3b,
+0x4c, 0x61, 0x62, 0x72, 0x3b, 0x4c, 0x61, 0x62, 0x6e, 0x3b, 0x4c, 0x61,
+0x62, 0x74, 0x3b, 0x4d, 0x61, 0x74, 0x50, 0x61, 0x7a, 0x61, 0x72, 0x3b,
+0x50, 0x61, 0x7a, 0x61, 0x72, 0x74, 0x65, 0x73, 0x69, 0x3b, 0x53, 0x61,
+0x6c, 0x131, 0x3b, 0xc7, 0x61, 0x72, 0x15f, 0x61, 0x6d, 0x62, 0x61, 0x3b,
+0x50, 0x65, 0x72, 0x15f, 0x65, 0x6d, 0x62, 0x65, 0x3b, 0x43, 0x75, 0x6d,
+0x61, 0x3b, 0x43, 0x75, 0x6d, 0x61, 0x72, 0x74, 0x65, 0x73, 0x69, 0x50,
+0x61, 0x7a, 0x3b, 0x50, 0x7a, 0x74, 0x3b, 0x53, 0x61, 0x6c, 0x3b, 0xc7,
+0x61, 0x72, 0x3b, 0x50, 0x65, 0x72, 0x3b, 0x43, 0x75, 0x6d, 0x3b, 0x43,
+0x6d, 0x74, 0x50, 0x3b, 0x50, 0x3b, 0x53, 0x3b, 0xc7, 0x3b, 0x50, 0x3b,
+0x43, 0x3b, 0x43, 0xdd, 0x65, 0x6b, 0x15f, 0x65, 0x6e, 0x62, 0x65, 0x3b,
+0x44, 0x75, 0x15f, 0x65, 0x6e, 0x62, 0x65, 0x3b, 0x53, 0x69, 0x15f, 0x65,
+0x6e, 0x62, 0x65, 0x3b, 0xc7, 0x61, 0x72, 0x15f, 0x65, 0x6e, 0x62, 0x65,
+0x3b, 0x50, 0x65, 0x6e, 0x15f, 0x65, 0x6e, 0x62, 0x65, 0x3b, 0x41, 0x6e,
+0x6e, 0x61, 0x3b, 0x15e, 0x65, 0x6e, 0x62, 0x65, 0xfd, 0x65, 0x6b, 0x15f,
+0x65, 0x6e, 0x62, 0x65, 0x3b, 0x64, 0x75, 0x15f, 0x65, 0x6e, 0x62, 0x65,
+0x3b, 0x73, 0x69, 0x15f, 0x65, 0x6e, 0x62, 0x65, 0x3b, 0xe7, 0x61, 0x72,
+0x15f, 0x65, 0x6e, 0x62, 0x65, 0x3b, 0x70, 0x65, 0x6e, 0x15f, 0x65, 0x6e,
+0x62, 0x65, 0x3b, 0x61, 0x6e, 0x6e, 0x61, 0x3b, 0x15f, 0x65, 0x6e, 0x62,
+0x65, 0xdd, 0x65, 0x6b, 0x3b, 0x44, 0x75, 0x15f, 0x3b, 0x53, 0x69, 0x15f,
+0x3b, 0xc7, 0x61, 0x72, 0x3b, 0x50, 0x65, 0x6e, 0x3b, 0x41, 0x6e, 0x6e,
+0x3b, 0x15e, 0x65, 0x6e, 0xfd, 0x65, 0x6b, 0x3b, 0x64, 0x75, 0x15f, 0x3b,
+0x73, 0x69, 0x15f, 0x3b, 0xe7, 0x61, 0x72, 0x3b, 0x70, 0x65, 0x6e, 0x3b,
+0x61, 0x6e, 0x6e, 0x3b, 0x15f, 0x65, 0x6e, 0xdd, 0x3b, 0x44, 0x3b, 0x53,
+0x3b, 0xc7, 0x3b, 0x50, 0x3b, 0x41, 0x3b, 0x15e, 0x4c, 0x61, 0x64, 0x69,
+0x3b, 0x54, 0x61, 0x6e, 0x69, 0x69, 0x3b, 0x54, 0x61, 0x6c, 0x61, 0x74,
+0x61, 0x3b, 0x4c, 0x61, 0x72, 0x62, 0x61, 0x3b, 0x4c, 0x61, 0x6d, 0x69,
+0x74, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x3b, 0x41, 0x73, 0x61, 0x62, 0x61,
+0x74, 0x4c, 0x61, 0x64, 0x3b, 0x54, 0x61, 0x6e, 0x3b, 0x54, 0x61, 0x6c,
+0x3b, 0x4c, 0x61, 0x72, 0x3b, 0x4c, 0x61, 0x6d, 0x3b, 0x4a, 0x75, 0x6d,
+0x3b, 0x41, 0x73, 0x61, 0x43d, 0x435, 0x434, 0x456, 0x43b, 0x44f, 0x3b, 0x43f,
+0x43e, 0x43d, 0x435, 0x434, 0x456, 0x43b, 0x43e, 0x43a, 0x3b, 0x432, 0x456, 0x432,
+0x442, 0x43e, 0x440, 0x43e, 0x43a, 0x3b, 0x441, 0x435, 0x440, 0x435, 0x434, 0x430,
+0x3b, 0x447, 0x435, 0x442, 0x432, 0x435, 0x440, 0x3b, 0x43f, 0x2bc, 0x44f, 0x442,
+0x43d, 0x438, 0x446, 0x44f, 0x3b, 0x441, 0x443, 0x431, 0x43e, 0x442, 0x430, 0x43d,
+0x435, 0x434, 0x456, 0x43b, 0x44e, 0x3b, 0x43f, 0x43e, 0x43d, 0x435, 0x434, 0x456,
+0x43b, 0x43e, 0x43a, 0x3b, 0x432, 0x456, 0x432, 0x442, 0x43e, 0x440, 0x43e, 0x43a,
+0x3b, 0x441, 0x435, 0x440, 0x435, 0x434, 0x443, 0x3b, 0x447, 0x435, 0x442, 0x432,
+0x435, 0x440, 0x3b, 0x43f, 0x2bc, 0x44f, 0x442, 0x43d, 0x438, 0x446, 0x44e, 0x3b,
+0x441, 0x443, 0x431, 0x43e, 0x442, 0x443, 0x6e, 0x6a, 0x65, 0x64, 0x17a, 0x65,
+0x6c, 0x61, 0x3b, 0x70, 0xf3, 0x6e, 0x64, 0x17a, 0x65, 0x6c, 0x61, 0x3b,
+0x77, 0x75, 0x74, 0x6f, 0x72, 0x61, 0x3b, 0x73, 0x72, 0x6a, 0x65, 0x64,
+0x61, 0x3b, 0x161, 0x74, 0x77, 0xf3, 0x72, 0x74, 0x6b, 0x3b, 0x70, 0x6a,
+0x61, 0x74, 0x6b, 0x3b, 0x73, 0x6f, 0x62, 0x6f, 0x74, 0x61, 0x6e, 0x6a,
+0x65, 0x3b, 0x70, 0xf3, 0x6e, 0x3b, 0x77, 0x75, 0x74, 0x3b, 0x73, 0x72,
+0x6a, 0x3b, 0x161, 0x74, 0x77, 0x3b, 0x70, 0x6a, 0x61, 0x3b, 0x73, 0x6f,
+0x62, 0x6e, 0x3b, 0x70, 0x3b, 0x77, 0x3b, 0x73, 0x3b, 0x161, 0x3b, 0x70,
+0x3b, 0x73, 0x627, 0x62a, 0x648, 0x627, 0x631, 0x3b, 0x67e, 0x6cc, 0x631, 0x3b,
+0x645, 0x646, 0x6af, 0x644, 0x3b, 0x628, 0x62f, 0x6be, 0x3b, 0x62c, 0x645, 0x639,
+0x631, 0x627, 0x62a, 0x3b, 0x62c, 0x645, 0x639, 0x6c1, 0x3b, 0x6c1, 0x641, 0x62a,
+0x6c1, 0x64a, 0x6d5, 0x643, 0x634, 0x6d5, 0x646, 0x628, 0x6d5, 0x3b, 0x62f, 0x6c8,
+0x634, 0x6d5, 0x646, 0x628, 0x6d5, 0x3b, 0x633, 0x6d5, 0x64a, 0x634, 0x6d5, 0x646,
+0x628, 0x6d5, 0x3b, 0x686, 0x627, 0x631, 0x634, 0x6d5, 0x646, 0x628, 0x6d5, 0x3b,
+0x67e, 0x6d5, 0x64a, 0x634, 0x6d5, 0x646, 0x628, 0x6d5, 0x3b, 0x62c, 0x6c8, 0x645,
+0x6d5, 0x3b, 0x634, 0x6d5, 0x646, 0x628, 0x6d5, 0x64a, 0x6d5, 0x3b, 0x62f, 0x6c8,
+0x3b, 0x633, 0x6d5, 0x3b, 0x686, 0x627, 0x3b, 0x67e, 0x6d5, 0x3b, 0x62c, 0x6c8,
+0x3b, 0x634, 0x6d5, 0x64a, 0x3b, 0x62f, 0x3b, 0x633, 0x3b, 0x686, 0x3b, 0x67e,
+0x3b, 0x62c, 0x3b, 0x634, 0x79, 0x61, 0x6b, 0x73, 0x68, 0x61, 0x6e, 0x62,
+0x61, 0x3b, 0x64, 0x75, 0x73, 0x68, 0x61, 0x6e, 0x62, 0x61, 0x3b, 0x73,
+0x65, 0x73, 0x68, 0x61, 0x6e, 0x62, 0x61, 0x3b, 0x63, 0x68, 0x6f, 0x72,
+0x73, 0x68, 0x61, 0x6e, 0x62, 0x61, 0x3b, 0x70, 0x61, 0x79, 0x73, 0x68,
+0x61, 0x6e, 0x62, 0x61, 0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x3b, 0x73, 0x68,
+0x61, 0x6e, 0x62, 0x61, 0x59, 0x61, 0x6b, 0x3b, 0x44, 0x75, 0x73, 0x68,
+0x3b, 0x53, 0x65, 0x73, 0x68, 0x3b, 0x43, 0x68, 0x6f, 0x72, 0x3b, 0x50,
+0x61, 0x79, 0x3b, 0x4a, 0x75, 0x6d, 0x3b, 0x53, 0x68, 0x61, 0x6e, 0x59,
+0x3b, 0x44, 0x3b, 0x53, 0x3b, 0x43, 0x3b, 0x50, 0x3b, 0x4a, 0x3b, 0x53,
+0x6cc, 0x2e, 0x3b, 0x62f, 0x2e, 0x3b, 0x633, 0x2e, 0x3b, 0x686, 0x2e, 0x3b,
+0x67e, 0x2e, 0x3b, 0x62c, 0x2e, 0x3b, 0x634, 0x2e, 0x44f, 0x43a, 0x448, 0x430,
+0x43d, 0x431, 0x430, 0x3b, 0x434, 0x443, 0x448, 0x430, 0x43d, 0x431, 0x430, 0x3b,
+0x441, 0x435, 0x448, 0x430, 0x43d, 0x431, 0x430, 0x3b, 0x447, 0x43e, 0x440, 0x448,
+0x430, 0x43d, 0x431, 0x430, 0x3b, 0x43f, 0x430, 0x439, 0x448, 0x430, 0x43d, 0x431,
+0x430, 0x3b, 0x436, 0x443, 0x43c, 0x430, 0x3b, 0x448, 0x430, 0x43d, 0x431, 0x430,
+0x44f, 0x43a, 0x448, 0x3b, 0x434, 0x443, 0x448, 0x3b, 0x441, 0x435, 0x448, 0x3b,
+0x447, 0x43e, 0x440, 0x3b, 0x43f, 0x430, 0x439, 0x3b, 0x436, 0x443, 0x43c, 0x3b,
+0x448, 0x430, 0x43d, 0x42f, 0x3b, 0x414, 0x3b, 0x421, 0x3b, 0x427, 0x3b, 0x41f,
+0x3b, 0x416, 0x3b, 0x428, 0xa55e, 0xa54c, 0xa535, 0x3b, 0xa5f3, 0xa5e1, 0xa609, 0x3b,
+0xa55a, 0xa55e, 0xa55a, 0x3b, 0xa549, 0xa55e, 0xa552, 0x3b, 0xa549, 0xa524, 0xa546, 0xa562,
+0x3b, 0xa549, 0xa524, 0xa540, 0xa56e, 0x3b, 0xa53b, 0xa52c, 0xa533, 0x6c, 0x61, 0x68,
+0x61, 0x64, 0x69, 0x3b, 0x74, 0x25b, 0x25b, 0x6e, 0x25b, 0x25b, 0x3b, 0x74,
+0x61, 0x6c, 0x61, 0x74, 0x61, 0x3b, 0x61, 0x6c, 0x61, 0x62, 0x61, 0x3b,
+0x61, 0x69, 0x6d, 0x69, 0x73, 0x61, 0x3b, 0x61, 0x69, 0x6a, 0x69, 0x6d,
+0x61, 0x3b, 0x73, 0x69, 0x253, 0x69, 0x74, 0x69, 0x53, 0x77, 0x6f, 0x6e,
+0x64, 0x61, 0x68, 0x61, 0x3b, 0x4d, 0x75, 0x73, 0x75, 0x6d, 0x62, 0x75,
+0x6c, 0x75, 0x77, 0x6f, 0x3b, 0x1e3c, 0x61, 0x76, 0x68, 0x75, 0x76, 0x68,
+0x69, 0x6c, 0x69, 0x3b, 0x1e3c, 0x61, 0x76, 0x68, 0x75, 0x72, 0x61, 0x72,
+0x75, 0x3b, 0x1e3c, 0x61, 0x76, 0x68, 0x75, 0x1e4b, 0x61, 0x3b, 0x1e3c, 0x61,
+0x76, 0x68, 0x75, 0x1e71, 0x61, 0x6e, 0x75, 0x3b, 0x4d, 0x75, 0x67, 0x69,
+0x76, 0x68, 0x65, 0x6c, 0x61, 0x53, 0x77, 0x6f, 0x3b, 0x4d, 0x75, 0x73,
+0x3b, 0x56, 0x68, 0x69, 0x3b, 0x52, 0x61, 0x72, 0x3b, 0x1e4a, 0x61, 0x3b,
+0x1e70, 0x61, 0x6e, 0x3b, 0x4d, 0x75, 0x67, 0x43, 0x68, 0x1ee7, 0x20, 0x4e,
+0x68, 0x1ead, 0x74, 0x3b, 0x54, 0x68, 0x1ee9, 0x20, 0x48, 0x61, 0x69, 0x3b,
+0x54, 0x68, 0x1ee9, 0x20, 0x42, 0x61, 0x3b, 0x54, 0x68, 0x1ee9, 0x20, 0x54,
+0x1b0, 0x3b, 0x54, 0x68, 0x1ee9, 0x20, 0x4e, 0x103, 0x6d, 0x3b, 0x54, 0x68,
+0x1ee9, 0x20, 0x53, 0xe1, 0x75, 0x3b, 0x54, 0x68, 0x1ee9, 0x20, 0x42, 0x1ea3,
+0x79, 0x43, 0x4e, 0x3b, 0x54, 0x68, 0x20, 0x32, 0x3b, 0x54, 0x68, 0x20,
+0x33, 0x3b, 0x54, 0x68, 0x20, 0x34, 0x3b, 0x54, 0x68, 0x20, 0x35, 0x3b,
+0x54, 0x68, 0x20, 0x36, 0x3b, 0x54, 0x68, 0x20, 0x37, 0x43, 0x4e, 0x3b,
+0x54, 0x32, 0x3b, 0x54, 0x33, 0x3b, 0x54, 0x34, 0x3b, 0x54, 0x35, 0x3b,
+0x54, 0x36, 0x3b, 0x54, 0x37, 0x73, 0x75, 0x64, 0x65, 0x6c, 0x3b, 0x6d,
+0x75, 0x64, 0x65, 0x6c, 0x3b, 0x74, 0x75, 0x64, 0x65, 0x6c, 0x3b, 0x76,
+0x65, 0x64, 0x65, 0x6c, 0x3b, 0x64, 0xf6, 0x64, 0x65, 0x6c, 0x3b, 0x66,
+0x72, 0x69, 0x64, 0x65, 0x6c, 0x3b, 0x7a, 0xe4, 0x64, 0x65, 0x6c, 0x53,
+0x75, 0x3b, 0x4d, 0x75, 0x3b, 0x54, 0x75, 0x3b, 0x56, 0x65, 0x3b, 0x44,
+0xf6, 0x3b, 0x46, 0x72, 0x3b, 0x5a, 0xe4, 0x73, 0x75, 0x2e, 0x3b, 0x6d,
+0x75, 0x2e, 0x3b, 0x74, 0x75, 0x2e, 0x3b, 0x76, 0x65, 0x2e, 0x3b, 0x64,
+0xf6, 0x2e, 0x3b, 0x66, 0x72, 0x2e, 0x3b, 0x7a, 0xe4, 0x2e, 0x53, 0x3b,
+0x4d, 0x3b, 0x54, 0x3b, 0x56, 0x3b, 0x44, 0x3b, 0x46, 0x3b, 0x5a, 0x53,
+0x75, 0x6e, 0x6e, 0x74, 0x61, 0x67, 0x3b, 0x4d, 0xe4, 0x6e, 0x74, 0x61,
+0x67, 0x3b, 0x5a, 0x69, 0x161, 0x74, 0x61, 0x67, 0x3b, 0x4d, 0x69, 0x74,
+0x74, 0x77, 0x75, 0x10d, 0x3b, 0x46, 0x72, 0xf3, 0x6e, 0x74, 0x61, 0x67,
+0x3b, 0x46, 0x72, 0x69, 0x74, 0x61, 0x67, 0x3b, 0x53, 0x61, 0x6d, 0x161,
+0x74, 0x61, 0x67, 0x53, 0x75, 0x6e, 0x3b, 0x4d, 0xe4, 0x6e, 0x3b, 0x5a,
+0x69, 0x161, 0x3b, 0x4d, 0x69, 0x74, 0x3b, 0x46, 0x72, 0xf3, 0x3b, 0x46,
+0x72, 0x69, 0x3b, 0x53, 0x61, 0x6d, 0x53, 0x3b, 0x4d, 0x3b, 0x5a, 0x3b,
+0x4d, 0x3b, 0x46, 0x3b, 0x46, 0x3b, 0x53, 0x44, 0x79, 0x64, 0x64, 0x20,
+0x53, 0x75, 0x6c, 0x3b, 0x44, 0x79, 0x64, 0x64, 0x20, 0x4c, 0x6c, 0x75,
+0x6e, 0x3b, 0x44, 0x79, 0x64, 0x64, 0x20, 0x4d, 0x61, 0x77, 0x72, 0x74,
+0x68, 0x3b, 0x44, 0x79, 0x64, 0x64, 0x20, 0x4d, 0x65, 0x72, 0x63, 0x68,
+0x65, 0x72, 0x3b, 0x44, 0x79, 0x64, 0x64, 0x20, 0x49, 0x61, 0x75, 0x3b,
+0x44, 0x79, 0x64, 0x64, 0x20, 0x47, 0x77, 0x65, 0x6e, 0x65, 0x72, 0x3b,
+0x44, 0x79, 0x64, 0x64, 0x20, 0x53, 0x61, 0x64, 0x77, 0x72, 0x6e, 0x53,
+0x75, 0x6c, 0x3b, 0x4c, 0x6c, 0x75, 0x6e, 0x3b, 0x4d, 0x61, 0x77, 0x3b,
+0x4d, 0x65, 0x72, 0x3b, 0x49, 0x61, 0x75, 0x3b, 0x47, 0x77, 0x65, 0x3b,
+0x53, 0x61, 0x64, 0x53, 0x75, 0x6c, 0x3b, 0x4c, 0x6c, 0x75, 0x6e, 0x3b,
+0x4d, 0x61, 0x77, 0x3b, 0x4d, 0x65, 0x72, 0x3b, 0x49, 0x61, 0x75, 0x3b,
+0x47, 0x77, 0x65, 0x6e, 0x3b, 0x53, 0x61, 0x64, 0x53, 0x3b, 0x4c, 0x6c,
+0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x49, 0x3b, 0x47, 0x3b, 0x53, 0x73, 0x6e,
+0x65, 0x69, 0x6e, 0x3b, 0x6d, 0x6f, 0x61, 0x6e, 0x64, 0x65, 0x69, 0x3b,
+0x74, 0x69, 0x69, 0x73, 0x64, 0x65, 0x69, 0x3b, 0x77, 0x6f, 0x61, 0x6e,
+0x73, 0x64, 0x65, 0x69, 0x3b, 0x74, 0x6f, 0x6e, 0x67, 0x65, 0x72, 0x73,
+0x64, 0x65, 0x69, 0x3b, 0x66, 0x72, 0x65, 0x65, 0x64, 0x3b, 0x73, 0x6e,
+0x65, 0x6f, 0x6e, 0x73, 0x69, 0x3b, 0x6d, 0x6f, 0x3b, 0x74, 0x69, 0x3b,
+0x77, 0x6f, 0x3b, 0x74, 0x6f, 0x3b, 0x66, 0x72, 0x3b, 0x73, 0x6f, 0x12c8,
+0x130b, 0x3b, 0x1233, 0x12ed, 0x1296, 0x3b, 0x121b, 0x1246, 0x1233, 0x129b, 0x3b, 0x12a0,
+0x1229, 0x12cb, 0x3b, 0x1203, 0x1219, 0x1233, 0x3b, 0x12a0, 0x122d, 0x1263, 0x3b, 0x1244,
+0x122b, 0x12c8, 0x3b, 0x1233, 0x3b, 0x121b, 0x3b, 0x12a0, 0x3b, 0x1203, 0x3b, 0x12a0,
+0x3b, 0x1244, 0x44, 0x69, 0x62, 0xe9, 0x65, 0x72, 0x3b, 0x41, 0x6c, 0x74,
+0x69, 0x6e, 0x65, 0x3b, 0x54, 0x61, 0x6c, 0x61, 0x61, 0x74, 0x61, 0x3b,
+0xc0, 0x6c, 0x61, 0x72, 0x62, 0x61, 0x3b, 0x41, 0x6c, 0x78, 0x61, 0x6d,
+0x69, 0x73, 0x3b, 0xc0, 0x6a, 0x6a, 0x75, 0x6d, 0x61, 0x3b, 0x41, 0x73,
+0x65, 0x65, 0x72, 0x44, 0x69, 0x62, 0x3b, 0x41, 0x6c, 0x74, 0x3b, 0x54,
+0x61, 0x6c, 0x3b, 0xc0, 0x6c, 0x61, 0x3b, 0x41, 0x6c, 0x78, 0x3b, 0xc0,
+0x6a, 0x6a, 0x3b, 0x41, 0x73, 0x65, 0x43, 0x61, 0x77, 0x65, 0x3b, 0x4d,
+0x76, 0x75, 0x6c, 0x6f, 0x3b, 0x4c, 0x77, 0x65, 0x73, 0x69, 0x62, 0x69,
+0x6e, 0x69, 0x3b, 0x4c, 0x77, 0x65, 0x73, 0x69, 0x74, 0x68, 0x61, 0x74,
+0x68, 0x75, 0x3b, 0x4c, 0x77, 0x65, 0x73, 0x69, 0x6e, 0x65, 0x3b, 0x4c,
+0x77, 0x65, 0x73, 0x69, 0x68, 0x6c, 0x61, 0x6e, 0x75, 0x3b, 0x4d, 0x67,
+0x71, 0x69, 0x62, 0x65, 0x6c, 0x6f, 0x43, 0x61, 0x77, 0x3b, 0x4d, 0x76,
+0x75, 0x3b, 0x42, 0x69, 0x6e, 0x3b, 0x54, 0x68, 0x61, 0x3b, 0x53, 0x69,
+0x6e, 0x3b, 0x48, 0x6c, 0x61, 0x3b, 0x4d, 0x67, 0x71, 0x43, 0x61, 0x77,
+0x3b, 0x4d, 0x76, 0x75, 0x3b, 0x4c, 0x77, 0x65, 0x73, 0x62, 0x3b, 0x54,
+0x68, 0x61, 0x3b, 0x53, 0x69, 0x6e, 0x3b, 0x48, 0x6c, 0x61, 0x3b, 0x4d,
+0x67, 0x71, 0x43, 0x3b, 0x4d, 0x3b, 0x53, 0x62, 0x3b, 0x53, 0x74, 0x3b,
+0x53, 0x69, 0x6e, 0x3b, 0x48, 0x6c, 0x3b, 0x4d, 0x67, 0x71, 0x43, 0x3b,
+0x4d, 0x3b, 0x53, 0x62, 0x3b, 0x54, 0x68, 0x74, 0x3b, 0x53, 0x69, 0x6e,
+0x3b, 0x48, 0x6c, 0x3b, 0x4d, 0x67, 0x71, 0x73, 0x254, 0x301, 0x6e, 0x64,
+0x69, 0x25b, 0x3b, 0x6d, 0xf3, 0x6e, 0x64, 0x69, 0x65, 0x3b, 0x6d, 0x75,
+0xe1, 0x6e, 0x79, 0xe1, 0x14b, 0x6d, 0xf3, 0x6e, 0x64, 0x69, 0x65, 0x3b,
+0x6d, 0x65, 0x74, 0xfa, 0x6b, 0x70, 0xed, 0xe1, 0x70, 0x25b, 0x3b, 0x6b,
+0xfa, 0x70, 0xe9, 0x6c, 0x69, 0x6d, 0x65, 0x74, 0xfa, 0x6b, 0x70, 0x69,
+0x61, 0x70, 0x25b, 0x3b, 0x66, 0x65, 0x6c, 0xe9, 0x74, 0x65, 0x3b, 0x73,
+0xe9, 0x73, 0x65, 0x6c, 0xe9, 0x73, 0x64, 0x3b, 0x6d, 0x64, 0x3b, 0x6d,
+0x77, 0x3b, 0x65, 0x74, 0x3b, 0x6b, 0x6c, 0x3b, 0x66, 0x6c, 0x3b, 0x73,
+0x73, 0x73, 0x3b, 0x6d, 0x3b, 0x6d, 0x3b, 0x65, 0x3b, 0x6b, 0x3b, 0x66,
+0x3b, 0x73, 0x5d6, 0x5d5, 0x5e0, 0x5d8, 0x5d9, 0x5e7, 0x3b, 0x5de, 0x5d0, 0x5b8,
+0x5e0, 0x5d8, 0x5d9, 0x5e7, 0x3b, 0x5d3, 0x5d9, 0x5e0, 0x5e1, 0x5d8, 0x5d9, 0x5e7,
+0x3b, 0x5de, 0x5d9, 0x5d8, 0x5d5, 0x5d5, 0x5d0, 0x5da, 0x3b, 0x5d3, 0x5d0, 0x5e0,
+0x5e2, 0x5e8, 0x5e9, 0x5d8, 0x5d9, 0x5e7, 0x3b, 0x5e4, 0x5bf, 0x5e8, 0x5f2, 0x5b7,
+0x5d8, 0x5d9, 0x5e7, 0x3b, 0x5e9, 0x5d1, 0x5ea, 0xc0, 0xec, 0x6b, 0xfa, 0x3b,
+0x41, 0x6a, 0xe9, 0x3b, 0xcc, 0x73, 0x1eb9, 0x301, 0x67, 0x75, 0x6e, 0x3b,
+0x1ecc, 0x6a, 0x1ecd, 0x301, 0x72, 0xfa, 0x3b, 0x1ecc, 0x6a, 0x1ecd, 0x301, 0x62,
+0x1ecd, 0x3b, 0x1eb8, 0x74, 0xec, 0x3b, 0xc0, 0x62, 0xe1, 0x6d, 0x1eb9, 0x301,
+0x74, 0x61, 0x1ecc, 0x6a, 0x1ecd, 0x301, 0x20, 0xc0, 0xec, 0x6b, 0xfa, 0x3b,
+0x1ecc, 0x6a, 0x1ecd, 0x301, 0x20, 0x41, 0x6a, 0xe9, 0x3b, 0x1ecc, 0x6a, 0x1ecd,
+0x301, 0x20, 0xcc, 0x73, 0x1eb9, 0x301, 0x67, 0x75, 0x6e, 0x3b, 0x1ecc, 0x6a,
+0x1ecd, 0x301, 0x72, 0xfa, 0x3b, 0x1ecc, 0x6a, 0x1ecd, 0x301, 0x62, 0x1ecd, 0x3b,
+0x1ecc, 0x6a, 0x1ecd, 0x301, 0x20, 0x1eb8, 0x74, 0xec, 0x3b, 0x1ecc, 0x6a, 0x1ecd,
+0x301, 0x20, 0xc0, 0x62, 0xe1, 0x6d, 0x1eb9, 0x301, 0x74, 0x61, 0xc0, 0xec,
+0x6b, 0x3b, 0x41, 0x6a, 0x3b, 0xcc, 0x73, 0x1eb9, 0x301, 0x67, 0x3b, 0x1ecc,
+0x6a, 0x1ecd, 0x301, 0x72, 0x3b, 0x1ecc, 0x6a, 0x1ecd, 0x301, 0x62, 0x3b, 0x1eb8,
+0x74, 0x3b, 0xc0, 0x62, 0xe1, 0x6d, 0xc0, 0x3b, 0x41, 0x3b, 0xcc, 0x3b,
+0x1ecc, 0x3b, 0x1ecc, 0x3b, 0x1eb8, 0x3b, 0xc0, 0xc0, 0xec, 0x6b, 0xfa, 0x3b,
+0x41, 0x6a, 0xe9, 0x3b, 0xcc, 0x73, 0x25b, 0x301, 0x67, 0x75, 0x6e, 0x3b,
+0x186, 0x6a, 0x254, 0x301, 0x72, 0xfa, 0x3b, 0x186, 0x6a, 0x254, 0x301, 0x62,
+0x254, 0x3b, 0x190, 0x74, 0xec, 0x3b, 0xc0, 0x62, 0xe1, 0x6d, 0x25b, 0x301,
+0x74, 0x61, 0x186, 0x6a, 0x254, 0x301, 0x20, 0xc0, 0xec, 0x6b, 0xfa, 0x3b,
+0x186, 0x6a, 0x254, 0x301, 0x20, 0x41, 0x6a, 0xe9, 0x3b, 0x186, 0x6a, 0x254,
+0x301, 0x20, 0xcc, 0x73, 0x25b, 0x301, 0x67, 0x75, 0x6e, 0x3b, 0x186, 0x6a,
+0x254, 0x301, 0x72, 0xfa, 0x3b, 0x186, 0x6a, 0x254, 0x301, 0x62, 0x254, 0x3b,
+0x186, 0x6a, 0x254, 0x301, 0x20, 0x190, 0x74, 0xec, 0x3b, 0x186, 0x6a, 0x254,
+0x301, 0x20, 0xc0, 0x62, 0xe1, 0x6d, 0x25b, 0x301, 0x74, 0x61, 0xc0, 0xec,
+0x6b, 0x3b, 0x41, 0x6a, 0x3b, 0xcc, 0x73, 0x25b, 0x301, 0x67, 0x3b, 0x186,
+0x6a, 0x254, 0x301, 0x72, 0x3b, 0x186, 0x6a, 0x254, 0x301, 0x62, 0x3b, 0x190,
+0x74, 0x3b, 0xc0, 0x62, 0xe1, 0x6d, 0xc0, 0x3b, 0x41, 0x3b, 0xcc, 0x3b,
+0x186, 0x3b, 0x186, 0x3b, 0x190, 0x3b, 0xc0, 0x41, 0x6c, 0x68, 0x61, 0x64,
+0x69, 0x3b, 0x41, 0x74, 0x69, 0x6e, 0x6e, 0x69, 0x3b, 0x41, 0x74, 0x61,
+0x6c, 0x61, 0x61, 0x74, 0x61, 0x3b, 0x41, 0x6c, 0x61, 0x72, 0x62, 0x61,
+0x3b, 0x41, 0x6c, 0x68, 0x61, 0x6d, 0x69, 0x73, 0x69, 0x3b, 0x41, 0x6c,
+0x7a, 0x75, 0x6d, 0x61, 0x3b, 0x41, 0x73, 0x69, 0x62, 0x74, 0x69, 0x48,
+0x3b, 0x54, 0x3b, 0x54, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x5a, 0x3b, 0x53,
+0x6e, 0x67, 0x6f, 0x65, 0x6e, 0x7a, 0x73, 0x69, 0x6e, 0x67, 0x68, 0x67,
+0x69, 0x7a, 0x3b, 0x73, 0x69, 0x6e, 0x67, 0x68, 0x67, 0x69, 0x7a, 0x69,
+0x74, 0x3b, 0x73, 0x69, 0x6e, 0x67, 0x68, 0x67, 0x69, 0x7a, 0x6e, 0x67,
+0x65, 0x69, 0x68, 0x3b, 0x73, 0x69, 0x6e, 0x67, 0x68, 0x67, 0x69, 0x7a,
+0x73, 0x61, 0x6d, 0x3b, 0x73, 0x69, 0x6e, 0x67, 0x68, 0x67, 0x69, 0x7a,
+0x73, 0x65, 0x69, 0x71, 0x3b, 0x73, 0x69, 0x6e, 0x67, 0x68, 0x67, 0x69,
+0x7a, 0x68, 0x61, 0x6a, 0x3b, 0x73, 0x69, 0x6e, 0x67, 0x68, 0x67, 0x69,
+0x7a, 0x72, 0x6f, 0x65, 0x6b, 0x49, 0x53, 0x6f, 0x6e, 0x74, 0x6f, 0x3b,
+0x55, 0x4d, 0x73, 0x6f, 0x6d, 0x62, 0x75, 0x6c, 0x75, 0x6b, 0x6f, 0x3b,
+0x55, 0x4c, 0x77, 0x65, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x3b, 0x55,
+0x4c, 0x77, 0x65, 0x73, 0x69, 0x74, 0x68, 0x61, 0x74, 0x68, 0x75, 0x3b,
+0x55, 0x4c, 0x77, 0x65, 0x73, 0x69, 0x6e, 0x65, 0x3b, 0x55, 0x4c, 0x77,
+0x65, 0x73, 0x69, 0x68, 0x6c, 0x61, 0x6e, 0x75, 0x3b, 0x55, 0x4d, 0x67,
+0x71, 0x69, 0x62, 0x65, 0x6c, 0x6f, 0x53, 0x6f, 0x6e, 0x3b, 0x4d, 0x73,
+0x6f, 0x3b, 0x42, 0x69, 0x6c, 0x3b, 0x54, 0x68, 0x61, 0x3b, 0x53, 0x69,
+0x6e, 0x3b, 0x48, 0x6c, 0x61, 0x3b, 0x4d, 0x67, 0x71, 0x53, 0x3b, 0x4d,
+0x3b, 0x42, 0x3b, 0x54, 0x3b, 0x53, 0x3b, 0x48, 0x3b, 0x4d, 0x6e, 0x75,
+0x6d, 0x129, 0x67, 0x67, 0x75, 0x3b, 0x70, 0x69, 0x72, 0x2d, 0x6b, 0x75,
+0x72, 0xe3, 0x2d, 0x68, 0xe1, 0x3b, 0x72, 0xe9, 0x67, 0x72, 0x65, 0x2d,
+0x6b, 0x75, 0x72, 0xe3, 0x2d, 0x68, 0xe1, 0x3b, 0x74, 0x1ebd, 0x67, 0x74,
+0x169, 0x2d, 0x6b, 0x75, 0x72, 0xe3, 0x2d, 0x68, 0xe1, 0x3b, 0x76, 0x1ebd,
+0x6e, 0x68, 0x6b, 0xe3, 0x67, 0x72, 0x61, 0x2d, 0x6b, 0x75, 0x72, 0xe3,
+0x2d, 0x68, 0xe1, 0x3b, 0x70, 0xe9, 0x6e, 0x6b, 0x61, 0x72, 0x2d, 0x6b,
+0x75, 0x72, 0xe3, 0x2d, 0x68, 0xe1, 0x3b, 0x73, 0x61, 0x76, 0x6e, 0x75,
+0x6e, 0x75, 0x6d, 0x2e, 0x3b, 0x70, 0x69, 0x72, 0x2e, 0x3b, 0x72, 0xe9,
+0x67, 0x2e, 0x3b, 0x74, 0x1ebd, 0x67, 0x2e, 0x3b, 0x76, 0x1ebd, 0x6e, 0x2e,
+0x3b, 0x70, 0xe9, 0x6e, 0x2e, 0x3b, 0x73, 0x61, 0x76, 0x2e, 0x4e, 0x2e,
+0x3b, 0x50, 0x2e, 0x3b, 0x52, 0x2e, 0x3b, 0x54, 0x2e, 0x3b, 0x56, 0x2e,
+0x3b, 0x50, 0x2e, 0x3b, 0x53, 0x2e, 0x6d, 0x69, 0x74, 0x75, 0xfa, 0x3b,
+0x6d, 0x75, 0x72, 0x61, 0x6b, 0x69, 0x70, 0xed, 0x3b, 0x6d, 0x75, 0x72,
+0x61, 0x6b, 0xed, 0x2d, 0x6d, 0x75, 0x6b, 0x169, 0x69, 0x3b, 0x6d, 0x75,
+0x72, 0x61, 0x6b, 0xed, 0x2d, 0x6d, 0x75, 0x73, 0x61, 0x70, 0xed, 0x72,
+0x69, 0x3b, 0x73, 0x75, 0x70, 0x61, 0x70, 0xe1, 0x3b, 0x79, 0x75, 0x6b,
+0x75, 0x61, 0x6b, 0xfa, 0x3b, 0x73, 0x61, 0x75, 0x72, 0xfa, 0x6d, 0x69,
+0x74, 0x3b, 0x6d, 0x75, 0x72, 0x3b, 0x6d, 0x6d, 0x6b, 0x3b, 0x6d, 0x6d,
+0x73, 0x3b, 0x73, 0x75, 0x70, 0x3b, 0x79, 0x75, 0x6b, 0x3b, 0x73, 0x61,
+0x75, 0x4d, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x53, 0x3b, 0x59,
+0x3b, 0x53, 0x910, 0x924, 0x935, 0x93e, 0x930, 0x3b, 0x938, 0x94b, 0x92e, 0x935,
+0x93e, 0x930, 0x3b, 0x92e, 0x902, 0x917, 0x932, 0x935, 0x93e, 0x930, 0x3b, 0x92c,
+0x941, 0x927, 0x935, 0x93e, 0x930, 0x3b, 0x92c, 0x943, 0x939, 0x938, 0x94d, 0x92a,
+0x924, 0x935, 0x93e, 0x930, 0x3b, 0x936, 0x941, 0x915, 0x94d, 0x930, 0x935, 0x93e,
+0x930, 0x3b, 0x936, 0x928, 0x93f, 0x935, 0x93e, 0x930, 0x53, 0xf6, 0x6e, 0x64,
+0x61, 0x69, 0x3b, 0x4d, 0x75, 0x6e, 0x64, 0x61, 0x69, 0x3b, 0x54, 0x65,
+0x69, 0x73, 0x64, 0x61, 0x69, 0x3b, 0x57, 0x65, 0x65, 0x64, 0x65, 0x6e,
+0x73, 0x64, 0x61, 0x69, 0x3b, 0x54, 0xfc, 0xfc, 0x72, 0x73, 0x64, 0x61,
+0x69, 0x3b, 0x46, 0x72, 0x65, 0x69, 0x64, 0x61, 0x69, 0x3b, 0x53, 0x61,
+0x6e, 0x69, 0x6e, 0x6a, 0x53, 0xf6, 0x6e, 0x3b, 0x4d, 0x75, 0x6e, 0x3b,
+0x54, 0x65, 0x69, 0x3b, 0x57, 0x65, 0x64, 0x3b, 0x54, 0xfc, 0x72, 0x3b,
+0x46, 0x72, 0x65, 0x3b, 0x53, 0x61, 0x6e, 0x73, 0x75, 0x6e, 0x6f, 0x20,
+0x65, 0x73, 0x75, 0x6e, 0x20, 0x23, 0x37, 0x3b, 0x73, 0x75, 0x6e, 0x6f,
+0x20, 0x65, 0x73, 0x75, 0x6e, 0x20, 0x23, 0x31, 0x3b, 0x73, 0x75, 0x6e,
+0x6f, 0x20, 0x65, 0x73, 0x75, 0x6e, 0x20, 0x23, 0x32, 0x3b, 0x73, 0x75,
+0x6e, 0x6f, 0x20, 0x65, 0x73, 0x75, 0x6e, 0x20, 0x23, 0x33, 0x3b, 0x73,
+0x75, 0x6e, 0x6f, 0x20, 0x65, 0x73, 0x75, 0x6e, 0x20, 0x23, 0x34, 0x3b,
+0x73, 0x75, 0x6e, 0x6f, 0x20, 0x65, 0x73, 0x75, 0x6e, 0x20, 0x23, 0x35,
+0x3b, 0x73, 0x75, 0x6e, 0x6f, 0x20, 0x65, 0x73, 0x75, 0x6e, 0x20, 0x23,
+0x36, 0x53, 0x61, 0x6e, 0x64, 0x65, 0x3b, 0x4d, 0x61, 0x6e, 0x64, 0x65,
+0x3b, 0x54, 0x69, 0x75, 0x73, 0x64, 0x65, 0x3b, 0x57, 0x65, 0x6e, 0x65,
+0x73, 0x64, 0x65, 0x3b, 0x54, 0x6f, 0x73, 0x64, 0x65, 0x3b, 0x46, 0x72,
+0x61, 0x65, 0x64, 0x65, 0x3b, 0x53, 0x61, 0x74, 0x61, 0x64, 0x65, 0x6cc,
+0x6a9, 0x634, 0x645, 0x628, 0x647, 0x3b, 0x62f, 0x648, 0x634, 0x645, 0x628, 0x647,
+0x3b, 0x633, 0x626, 0x6cc, 0x634, 0x645, 0x628, 0x647, 0x3b, 0x686, 0x627, 0x631,
+0x634, 0x645, 0x628, 0x647, 0x3b, 0x67e, 0x646, 0x686, 0x634, 0x645, 0x628, 0x647,
+0x3b, 0x62c, 0x645, 0x647, 0x3b, 0x634, 0x645, 0x628, 0x647, 0x6cc, 0x6a9, 0x3b,
+0x62f, 0x648, 0x3b, 0x633, 0x626, 0x6d2, 0x3b, 0x686, 0x627, 0x631, 0x3b, 0x67e,
+0x646, 0x686, 0x3b, 0x62c, 0x645, 0x647, 0x3b, 0x634, 0x645, 0x59, 0x61, 0x6b,
+0x73, 0x68, 0x61, 0x6d, 0x62, 0x65, 0x68, 0x3b, 0x44, 0x6f, 0x73, 0x68,
+0x61, 0x6d, 0x62, 0x65, 0x68, 0x3b, 0x53, 0x61, 0x79, 0x73, 0x68, 0x61,
+0x6d, 0x62, 0x65, 0x68, 0x3b, 0x43, 0x68, 0xe1, 0x72, 0x73, 0x68, 0x61,
+0x6d, 0x62, 0x65, 0x68, 0x3b, 0x50, 0x61, 0x6e, 0x63, 0x68, 0x73, 0x68,
+0x61, 0x6d, 0x62, 0x65, 0x68, 0x3b, 0x4a, 0x6f, 0x6d, 0x61, 0x68, 0x3b,
+0x53, 0x68, 0x61, 0x6d, 0x62, 0x65, 0x68, 0x59, 0x61, 0x6b, 0x3b, 0x44,
+0x6f, 0x3b, 0x53, 0x61, 0x79, 0x3b, 0x43, 0x68, 0xe1, 0x3b, 0x50, 0x61,
+0x6e, 0x3b, 0x4a, 0x6f, 0x6d, 0x3b, 0x53, 0x68, 0x61, 0x64, 0x6f, 0x6d,
+0x65, 0x6e, 0x65, 0x67, 0x61, 0x3b, 0x6c, 0x75, 0x6e, 0x65, 0x73, 0x64,
+0xec, 0x3b, 0x6d, 0xe4, 0x74, 0x65, 0x73, 0x64, 0xec, 0x3b, 0x6d, 0xe4,
+0x63, 0x6f, 0x72, 0x64, 0xec, 0x3b, 0x7a, 0x65, 0x75, 0x67, 0x67, 0x69,
+0x61, 0x3b, 0x76, 0x65, 0x6e, 0x61, 0x72, 0x64, 0xec, 0x3b, 0x73, 0x61,
+0x62, 0x62, 0x6f, 0x64, 0x6f, 0x6d, 0x2e, 0x3b, 0x6c, 0x75, 0x6e, 0x2e,
+0x3b, 0x6d, 0xe4, 0x74, 0x2e, 0x3b, 0x6d, 0xe4, 0x63, 0x2e, 0x3b, 0x7a,
+0x65, 0x75, 0x2e, 0x3b, 0x76, 0x65, 0x6e, 0x2e, 0x3b, 0x73, 0x61, 0x62,
+0x2e, 0x44, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x5a, 0x3b, 0x56,
+0x3b, 0x53, 0x627, 0x6cc, 0x6a9, 0x634, 0x6cc, 0x645, 0x6d2, 0x3b, 0x62f, 0x64f,
+0x648, 0x634, 0x6cc, 0x645, 0x6d2, 0x3b, 0x6af, 0x6be, 0x646, 0x20, 0x622, 0x646,
+0x6af, 0x627, 0x3b, 0x686, 0x627, 0x631, 0x634, 0x6cc, 0x645, 0x6d2, 0x3b, 0x67e,
+0x64e, 0x626, 0x20, 0x634, 0x6cc, 0x645, 0x6d2, 0x3b, 0x634, 0x64f, 0x648, 0x6af,
+0x627, 0x631, 0x3b, 0x644, 0x64e, 0x648, 0x20, 0x622, 0x646, 0x6af, 0x627, 0x627,
+0x3b, 0x62f, 0x3b, 0x6af, 0x3b, 0x686, 0x3b, 0x67e, 0x3b, 0x634, 0x3b, 0x644,
+0x61, 0x6c, 0x61, 0x68, 0x61, 0x256, 0x269, 0x3b, 0x61, 0x256, 0x269, 0x74,
+0x25b, 0x6e, 0x25b, 0x25b, 0x3b, 0x61, 0x74, 0x61, 0x6c, 0x61, 0x61, 0x74,
+0x61, 0x3b, 0x61, 0x6c, 0x61, 0x61, 0x72, 0x62, 0x61, 0x3b, 0x61, 0x6c,
+0x61, 0x61, 0x6d, 0x269, 0x73, 0x68, 0x269, 0x3b, 0x61, 0x72, 0x269, 0x73,
+0x1dd, 0x6d, 0x61, 0x3b, 0x61, 0x73, 0x69, 0x69, 0x62, 0x69, 0x61, 0x6c,
+0x61, 0x68, 0x3b, 0x61, 0x256, 0x269, 0x74, 0x3b, 0x61, 0x74, 0x61, 0x6c,
+0x3b, 0x61, 0x6c, 0x61, 0x72, 0x3b, 0x61, 0x6c, 0x61, 0x6d, 0x3b, 0x61,
+0x72, 0x269, 0x73, 0x3b, 0x61, 0x73, 0x69, 0x62, 0x6c, 0x68, 0x3b, 0x256,
+0x74, 0x3b, 0x74, 0x6c, 0x3b, 0x6c, 0x72, 0x3b, 0x6c, 0x6d, 0x3b, 0x72,
+0x73, 0x3b, 0x73, 0x62, 0x924, 0x94b, 0x906, 0x930, 0x3b, 0x938, 0x94b, 0x906,
+0x930, 0x3b, 0x92e, 0x902, 0x917, 0x932, 0x935, 0x93e, 0x930, 0x3b, 0x92c, 0x941,
+0x927, 0x935, 0x93e, 0x930, 0x3b, 0x935, 0x940, 0x930, 0x935, 0x93e, 0x930, 0x3b,
+0x936, 0x941, 0x915, 0x94d, 0x915, 0x930, 0x935, 0x93e, 0x930, 0x3b, 0x936, 0x928,
+0x93f, 0x91a, 0x94d, 0x91a, 0x930, 0x935, 0x93e, 0x930, 0x924, 0x94b, 0x906, 0x930,
+0x3b, 0x938, 0x94b, 0x906, 0x930, 0x3b, 0x92e, 0x902, 0x917, 0x932, 0x3b, 0x92c,
+0x941, 0x927, 0x3b, 0x935, 0x940, 0x930, 0x3b, 0x936, 0x941, 0x915, 0x94d, 0x915,
+0x930, 0x3b, 0x936, 0x928, 0x93f, 0x924, 0x3b, 0x938, 0x94b, 0x3b, 0x92e, 0x902,
+0x3b, 0x92c, 0x941, 0x3b, 0x935, 0x940, 0x3b, 0x936, 0x941, 0x3b, 0x936, 0x64,
+0x6f, 0x6d, 0xe9, 0x6e, 0x65, 0x67, 0x61, 0x3b, 0x6c, 0x75, 0x6e, 0x69,
+0x3b, 0x6d, 0x61, 0x72, 0x74, 0x69, 0x3b, 0x6d, 0xe8, 0x72, 0x63, 0x6f,
+0x72, 0x65, 0x3b, 0x7a, 0x6f, 0x62, 0x61, 0x3b, 0x76, 0xe8, 0x6e, 0x61,
+0x72, 0x65, 0x3b, 0x73, 0x61, 0x62, 0x6f, 0x64, 0x6f, 0x6d, 0x3b, 0x6c,
+0x75, 0x6e, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x6d, 0x65, 0x72, 0x3b, 0x7a,
+0x6f, 0x62, 0x3b, 0x76, 0xe8, 0x6e, 0x3b, 0x73, 0x61, 0x62
};
static constexpr char16_t byte_unit_data[] = {
-0x62, 0x79, 0x74, 0x65, 0x73, 0x6b, 0x42, 0x3b, 0x4d, 0x42, 0x3b, 0x47, 0x42, 0x3b, 0x54, 0x42, 0x3b, 0x50, 0x42, 0x3b,
-0x45, 0x42, 0x4b, 0x69, 0x42, 0x3b, 0x4d, 0x69, 0x42, 0x3b, 0x47, 0x69, 0x42, 0x3b, 0x54, 0x69, 0x42, 0x3b, 0x50, 0x69,
-0x42, 0x3b, 0x45, 0x69, 0x42, 0x67, 0x72, 0x65, 0x65, 0x70, 0x62, 0x61, 0x6a, 0x74, 0x1263, 0x12ed, 0x1275, 0x12aa, 0x1263, 0x3b,
-0x121c, 0x130b, 0x1263, 0x12ed, 0x1275, 0x3b, 0x130a, 0x1263, 0x3b, 0x1274, 0x122b, 0x1263, 0x12ed, 0x1275, 0x3b, 0x1354, 0x1263, 0x3b, 0x45, 0x42,
-0x628, 0x627, 0x64a, 0x62a, 0x643, 0x64a, 0x644, 0x648, 0x628, 0x627, 0x64a, 0x62a, 0x3b, 0x645, 0x2e, 0x628, 0x3b, 0x63a, 0x2e, 0x628,
-0x3b, 0x62a, 0x64a, 0x631, 0x627, 0x628, 0x627, 0x64a, 0x62a, 0x3b, 0x628, 0x64a, 0x62a, 0x627, 0x628, 0x627, 0x64a, 0x62a, 0x3b, 0x45,
-0x42, 0x562, 0x561, 0x575, 0x569, 0x565, 0x580, 0x56f, 0x532, 0x3b, 0x544, 0x532, 0x3b, 0x533, 0x532, 0x3b, 0x54f, 0x532, 0x3b, 0x54a,
-0x532, 0x3b, 0x45, 0x42, 0x9ac, 0x9be, 0x987, 0x99f, 0x995, 0x9bf, 0x983, 0x20, 0x9ac, 0x9be, 0x983, 0x3b, 0x9ae, 0x9c7, 0x983, 0x20,
-0x9ac, 0x9be, 0x983, 0x3b, 0x997, 0x9bf, 0x983, 0x20, 0x9ac, 0x9be, 0x983, 0x3b, 0x99f, 0x9c7, 0x983, 0x20, 0x9ac, 0x9be, 0x983, 0x3b,
-0x50, 0x42, 0x3b, 0x45, 0x42, 0x62, 0x61, 0x79, 0x74, 0x62, 0x79, 0x74, 0x65, 0x2d, 0x61, 0x6b, 0x431, 0x430, 0x439, 0x442,
-0x44b, 0x41a, 0x411, 0x3b, 0x41c, 0x411, 0x3b, 0x413, 0x411, 0x3b, 0x422, 0x411, 0x3b, 0x41f, 0x411, 0x3b, 0x45, 0x42, 0x62, 0x61,
-0x6a, 0x74, 0x6f, 0x76, 0x69, 0x6f, 0x6b, 0x74, 0x65, 0x64, 0x6f, 0xf9, 0x6b, 0x6f, 0x3b, 0x4d, 0x6f, 0x3b, 0x47, 0x6f,
-0x3b, 0x54, 0x6f, 0x3b, 0x50, 0x6f, 0x3b, 0x45, 0x6f, 0x4b, 0x69, 0x6f, 0x3b, 0x4d, 0x69, 0x6f, 0x3b, 0x47, 0x69, 0x6f,
-0x3b, 0x54, 0x69, 0x6f, 0x3b, 0x50, 0x69, 0x6f, 0x3b, 0x45, 0x69, 0x6f, 0x431, 0x430, 0x439, 0x442, 0x43e, 0x432, 0x435, 0x1018,
-0x102d, 0x102f, 0x1000, 0x103a, 0x6d, 0x67, 0x61, 0x20, 0x62, 0x79, 0x74, 0x65, 0xd804, 0xdd1d, 0xd804, 0xdd2d, 0xd804, 0xdd16, 0xd804, 0xdd34,
-0x13d7, 0x13d3, 0x13cd, 0x13a6, 0x13b5, 0x13a9, 0x5b57, 0x8282, 0x4f4d, 0x5143, 0x7d44, 0x62, 0x61, 0x6a, 0x74, 0x79, 0x62, 0x61, 0x6a, 0x74,
-0x6f, 0x6a, 0x62, 0x61, 0x69, 0x64, 0x69, 0x64, 0x62, 0xfd, 0x74, 0x74, 0x61, 0x76, 0x75, 0x74, 0x6b, 0x74, 0x3b, 0x4d,
-0x74, 0x3b, 0x47, 0x74, 0x3b, 0x54, 0x74, 0x3b, 0x50, 0x74, 0x3b, 0x45, 0x74, 0x4b, 0x69, 0x74, 0x3b, 0x4d, 0x69, 0x74,
-0x3b, 0x47, 0x69, 0x74, 0x3b, 0x54, 0x69, 0x74, 0x3b, 0x50, 0x69, 0x74, 0x3b, 0x45, 0x69, 0x74, 0x6f, 0x63, 0x74, 0x65,
-0x74, 0x73, 0xd83a, 0xdd36, 0xd83a, 0xdd2b, 0xd83a, 0xdd45, 0xd83a, 0xdd3c, 0xd83a, 0xdd46, 0xd83a, 0xdd2d, 0xd83a, 0xdd33, 0xd83a, 0xdd14, 0x3b, 0xd83a,
-0xdd03, 0xd83a, 0xdd14, 0x3b, 0xd83a, 0xdd18, 0xd83a, 0xdd14, 0x3b, 0xd83a, 0xdd1a, 0xd83a, 0xdd14, 0x3b, 0xd83a, 0xdd06, 0xd83a, 0xdd14, 0x3b, 0x45,
-0x42, 0x62, 0x61, 0x69, 0x64, 0x68, 0x74, 0x10d1, 0x10d0, 0x10d8, 0x10e2, 0x10d8, 0x10d9, 0x10d1, 0x10d0, 0x10d8, 0x10e2, 0x10d8, 0x3b, 0x4d,
-0x42, 0x3b, 0x47, 0x42, 0x3b, 0x10e2, 0x10d1, 0x10d0, 0x10d8, 0x10e2, 0x10d8, 0x3b, 0x10de, 0x10d1, 0x10d0, 0x10d8, 0x10e2, 0x10d8, 0x3b, 0x45,
-0x42, 0x42, 0x79, 0x74, 0x65, 0x73, 0xaac, 0xabe, 0xa87, 0xa9f, 0x6b, 0x42, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x4d, 0x42, 0x20,
-0x7b, 0x30, 0x7d, 0x3b, 0x47, 0x42, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x54, 0x42, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x50, 0x42,
-0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x45, 0x42, 0x20, 0x7b, 0x30, 0x7d, 0x4b, 0x69, 0x42, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x4d,
-0x69, 0x42, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x47, 0x69, 0x42, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x54, 0x69, 0x42, 0x20, 0x7b,
-0x30, 0x7d, 0x3b, 0x50, 0x69, 0x42, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x45, 0x69, 0x42, 0x20, 0x7b, 0x30, 0x7d, 0x5d1, 0x5d9,
-0x5d9, 0x5d8, 0x92c, 0x93e, 0x907, 0x91f, 0x62, 0xe1, 0x6a, 0x74, 0x62, 0xe6, 0x74, 0x69, 0x62, 0x65, 0x61, 0x72, 0x74, 0x61,
-0x30d0, 0x30a4, 0x30c8, 0x4b, 0x42, 0x3b, 0x4d, 0x42, 0x3b, 0x47, 0x42, 0x3b, 0x54, 0x42, 0x3b, 0x50, 0x42, 0x3b, 0x45, 0x42,
-0x62, 0x69, 0x74, 0x65, 0x61, 0x1e6d, 0x61, 0x6d, 0x1e0d, 0x61, 0x6e, 0x6b, 0x41, 0x1e6c, 0x3b, 0x4d, 0x41, 0x1e6c, 0x3b, 0x47,
-0x41, 0x1e6c, 0x3b, 0x54, 0x41, 0x1e6c, 0x3b, 0x50, 0x42, 0x3b, 0x45, 0x42, 0xcac, 0xcc8, 0xc9f, 0xccd, 0x200c, 0xc97, 0xcb3, 0xcc1,
-0xc95, 0xcbf, 0x2e, 0xcac, 0xcc8, 0x2e, 0x3b, 0xcae, 0xcc6, 0x2e, 0xcac, 0xcc8, 0x2e, 0x3b, 0xc97, 0xcbf, 0x2e, 0xcac, 0xcc8, 0x2e,
-0x3b, 0xc9f, 0xcc6, 0x2e, 0xcac, 0xcc8, 0x2e, 0x3b, 0xcaa, 0xcc6, 0xcac, 0xcc8, 0x3b, 0x45, 0x42, 0x43a, 0x411, 0x3b, 0x4d, 0x411,
-0x3b, 0x413, 0x411, 0x3b, 0x54, 0x411, 0x3b, 0x41f, 0x411, 0x3b, 0x45, 0x411, 0x4b, 0x69, 0x411, 0x3b, 0x4d, 0x69, 0x411, 0x3b,
-0x47, 0x69, 0x411, 0x3b, 0x54, 0x69, 0x411, 0x3b, 0x50, 0x69, 0x411, 0x3b, 0x45, 0x69, 0x411, 0x1794, 0x17c3, 0x92c, 0x93e, 0x92f,
-0x91f, 0xbc14, 0xc774, 0xd2b8, 0x43a, 0x411, 0x3b, 0x41c, 0x411, 0x3b, 0x413, 0x411, 0x3b, 0x422, 0x411, 0x3b, 0x41f, 0x442, 0x431, 0x3b,
-0x45, 0x42, 0x62, 0x61, 0x69, 0x74, 0x69, 0x62, 0x61, 0x69, 0x74, 0x61, 0x69, 0x431, 0x430, 0x458, 0x442, 0x438, 0xd2c, 0xd48,
-0xd31, 0xd4d, 0xd31, 0xd4d, 0xd15, 0xd46, 0xd2c, 0xd3f, 0x3b, 0xd0e, 0xd02, 0xd2c, 0xd3f, 0x3b, 0xd1c, 0xd3f, 0xd2c, 0xd3f, 0x3b, 0xd1f,
-0xd3f, 0xd2c, 0xd3f, 0x3b, 0xd2a, 0xd3f, 0xd2c, 0xd3f, 0x3b, 0x45, 0x42, 0x628, 0x627, 0x6cc, 0x62a, 0x6a9, 0x6cc, 0x644, 0x648, 0x628,
-0x627, 0x6cc, 0x62a, 0x3b, 0x645, 0x6af, 0x627, 0x628, 0x627, 0x6cc, 0x62a, 0x3b, 0x6af, 0x6cc, 0x6af, 0x627, 0x628, 0x627, 0x6cc, 0x62a,
-0x3b, 0x62a, 0x631, 0x627, 0x628, 0x627, 0x6cc, 0x62a, 0x3b, 0x50, 0x42, 0x3b, 0x45, 0x42, 0x43a, 0x411, 0x3b, 0x41c, 0x411, 0x3b,
-0x413, 0x411, 0x3b, 0x422, 0x411, 0x3b, 0x41f, 0x411, 0x3b, 0x45, 0x42, 0x6b, 0x42, 0x3b, 0x4d, 0x42, 0x3b, 0x47, 0x42, 0x3b,
-0x54, 0x42, 0x3b, 0x92a, 0x93f, 0x91f, 0x93e, 0x3b, 0x45, 0x42, 0x42, 0x61, 0x69, 0x74, 0x2d, 0x64, 0x1eb9, 0x6d, 0xb2c, 0xb3e,
-0xb07, 0xb1f, 0xb4d, 0x628, 0x627, 0x64a, 0x67c, 0x633, 0xa2c, 0xa3e, 0xa07, 0xa1f, 0x62, 0x79, 0x21b, 0x69, 0x431, 0x430, 0x430, 0x439,
-0x442, 0x43a, 0x411, 0x3b, 0x41c, 0x411, 0x3b, 0x47, 0x42, 0x3b, 0x54, 0x42, 0x3b, 0x50, 0x42, 0x3b, 0x45, 0x42, 0x431, 0x430,
-0x458, 0x442, 0x43e, 0x432, 0x438, 0x628, 0x627, 0x626, 0x64a, 0x67d, 0x632, 0x6aa, 0x644, 0x648, 0x20, 0x628, 0x627, 0x626, 0x64a, 0x67d,
-0x632, 0x3b, 0x4d, 0x42, 0x3b, 0x47, 0x42, 0x3b, 0x54, 0x42, 0x3b, 0x50, 0x42, 0x3b, 0x45, 0x42, 0xdb6, 0xdba, 0xdd2, 0xda7,
-0xdca, 0xd9a, 0xdd2, 0xdb6, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0xdb8, 0xdd9, 0xdb6, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0xd9c, 0xdd2, 0xdb6,
-0x20, 0x7b, 0x30, 0x7d, 0x3b, 0xda7, 0xdd9, 0xdb6, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0xdb4, 0xdd9, 0xdb6, 0x20, 0x7b, 0x30, 0x7d,
-0x3b, 0x45, 0x42, 0x62, 0x65, 0x79, 0x74, 0x69, 0x73, 0x6b, 0x42, 0x3b, 0x4d, 0x42, 0x3b, 0x47, 0x42, 0x3b, 0x54, 0x42,
-0x3b, 0x42, 0x42, 0x3b, 0x45, 0x42, 0x6b, 0x69, 0x6c, 0x6f, 0x62, 0x61, 0x69, 0x74, 0x69, 0x20, 0x7b, 0x30, 0x7d, 0x3b,
-0x4d, 0x42, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x47, 0x42, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x74, 0x65, 0x72, 0x61, 0x62, 0x61,
-0x69, 0x74, 0x69, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x50, 0x42, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x45, 0x42, 0xbaa, 0xbc8, 0xb9f,
-0xbcd, 0xb95, 0xbb3, 0xbcd, 0xc2c, 0xc48, 0xc1f, 0xc4d, 0x200c, 0xc32, 0xc41, 0xc15, 0xc47, 0xc2c, 0xc40, 0x3b, 0xc0e, 0xc2e, 0xc4d, 0x200c,
-0xc2c, 0xc3f, 0x3b, 0xc1c, 0xc40, 0xc2c, 0xc40, 0x3b, 0xc1f, 0xc40, 0xc2c, 0xc40, 0x3b, 0xc2a, 0xc40, 0xc2c, 0xc40, 0x3b, 0x45, 0x42,
-0xe44, 0xe1a, 0xe15, 0xe4c, 0x70, 0x61, 0x69, 0x74, 0x69, 0x6b, 0x42, 0x20, 0x2bb, 0x65, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x4d,
-0x42, 0x20, 0x2bb, 0x65, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x47, 0x42, 0x20, 0x2bb, 0x65, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x54,
-0x42, 0x20, 0x2bb, 0x65, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x50, 0x42, 0x20, 0x2bb, 0x65, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x45,
-0x42, 0x20, 0x2bb, 0x65, 0x20, 0x7b, 0x30, 0x7d, 0x4b, 0x69, 0x42, 0x20, 0x2bb, 0x65, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x4d,
-0x69, 0x42, 0x20, 0x2bb, 0x65, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x47, 0x69, 0x42, 0x20, 0x2bb, 0x65, 0x20, 0x7b, 0x30, 0x7d,
-0x3b, 0x54, 0x69, 0x42, 0x20, 0x2bb, 0x65, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x50, 0x69, 0x42, 0x20, 0x2bb, 0x65, 0x20, 0x7b,
-0x30, 0x7d, 0x3b, 0x45, 0x69, 0x42, 0x20, 0x2bb, 0x65, 0x20, 0x7b, 0x30, 0x7d, 0x62, 0x61, 0xfd, 0x74, 0x431, 0x430, 0x439,
-0x442, 0x438, 0x62, 0x79, 0x74, 0x65, 0x79, 0x628, 0x627, 0x626, 0x679, 0x6b, 0x42, 0x3b, 0x4d, 0x42, 0x3b, 0x47, 0x42, 0x3b,
-0x54, 0x42, 0x3b, 0x67e, 0x6cc, 0x20, 0x628, 0x6cc, 0x3b, 0x45, 0x42, 0x62, 0x65, 0x69, 0x74, 0x69, 0x61, 0x75, 0xe0, 0x77,
-0x1ecd, 0x301, 0x6e, 0x20, 0x62, 0xe1, 0xec, 0x74, 0xec, 0x6b, 0xe9, 0x62, 0xe1, 0xec, 0x74, 0xec, 0x3b, 0x4d, 0x42, 0x3b,
-0x6a, 0xed, 0x62, 0xe1, 0xec, 0x74, 0xec, 0x3b, 0x54, 0xed, 0x62, 0xe1, 0xec, 0x74, 0xec, 0x3b, 0x50, 0xed, 0x62, 0xe1,
-0xec, 0x74, 0xec, 0x3b, 0x45, 0x42, 0xe0, 0x77, 0x254, 0x301, 0x6e, 0x20, 0x62, 0xe1, 0xec, 0x74, 0xec, 0x62, 0x79, 0x74,
-0x65, 0x20, 0x61, 0x67, 0x62, 0x79, 0x74, 0x65, 0x2d, 0x69, 0x74, 0x61
+0x62, 0x79, 0x74, 0x65, 0x73, 0x6b, 0x42, 0x3b, 0x4d, 0x42, 0x3b, 0x47,
+0x42, 0x3b, 0x54, 0x42, 0x3b, 0x50, 0x42, 0x3b, 0x45, 0x42, 0x4b, 0x69,
+0x42, 0x3b, 0x4d, 0x69, 0x42, 0x3b, 0x47, 0x69, 0x42, 0x3b, 0x54, 0x69,
+0x42, 0x3b, 0x50, 0x69, 0x42, 0x3b, 0x45, 0x69, 0x42, 0x67, 0x72, 0x65,
+0x65, 0x70, 0x62, 0x61, 0x6a, 0x74, 0x1263, 0x12ed, 0x1275, 0x12aa, 0x1263, 0x3b,
+0x121c, 0x130b, 0x1263, 0x12ed, 0x1275, 0x3b, 0x130a, 0x1263, 0x3b, 0x1274, 0x122b, 0x1263,
+0x12ed, 0x1275, 0x3b, 0x1354, 0x1263, 0x3b, 0x45, 0x42, 0x628, 0x627, 0x64a, 0x62a,
+0x643, 0x64a, 0x644, 0x648, 0x628, 0x627, 0x64a, 0x62a, 0x3b, 0x645, 0x2e, 0x628,
+0x3b, 0x63a, 0x2e, 0x628, 0x3b, 0x62a, 0x64a, 0x631, 0x627, 0x628, 0x627, 0x64a,
+0x62a, 0x3b, 0x628, 0x64a, 0x62a, 0x627, 0x628, 0x627, 0x64a, 0x62a, 0x3b, 0x45,
+0x42, 0x562, 0x561, 0x575, 0x569, 0x565, 0x580, 0x56f, 0x532, 0x3b, 0x544, 0x532,
+0x3b, 0x533, 0x532, 0x3b, 0x54f, 0x532, 0x3b, 0x54a, 0x532, 0x3b, 0x45, 0x42,
+0x9ac, 0x9be, 0x987, 0x99f, 0x995, 0x9bf, 0x983, 0x20, 0x9ac, 0x9be, 0x983, 0x3b,
+0x9ae, 0x9c7, 0x983, 0x20, 0x9ac, 0x9be, 0x983, 0x3b, 0x997, 0x9bf, 0x983, 0x20,
+0x9ac, 0x9be, 0x983, 0x3b, 0x99f, 0x9c7, 0x983, 0x20, 0x9ac, 0x9be, 0x983, 0x3b,
+0x50, 0x42, 0x3b, 0x45, 0x42, 0x62, 0x61, 0x79, 0x74, 0x62, 0x79, 0x74,
+0x65, 0x2d, 0x61, 0x6b, 0x431, 0x430, 0x439, 0x442, 0x44b, 0x41a, 0x411, 0x3b,
+0x41c, 0x411, 0x3b, 0x413, 0x411, 0x3b, 0x422, 0x411, 0x3b, 0x41f, 0x411, 0x3b,
+0x45, 0x42, 0x62, 0x61, 0x6a, 0x74, 0x6f, 0x76, 0x69, 0x6f, 0x6b, 0x74,
+0x65, 0x64, 0x6f, 0xf9, 0x6b, 0x6f, 0x3b, 0x4d, 0x6f, 0x3b, 0x47, 0x6f,
+0x3b, 0x54, 0x6f, 0x3b, 0x50, 0x6f, 0x3b, 0x45, 0x6f, 0x4b, 0x69, 0x6f,
+0x3b, 0x4d, 0x69, 0x6f, 0x3b, 0x47, 0x69, 0x6f, 0x3b, 0x54, 0x69, 0x6f,
+0x3b, 0x50, 0x69, 0x6f, 0x3b, 0x45, 0x69, 0x6f, 0x431, 0x430, 0x439, 0x442,
+0x43e, 0x432, 0x435, 0x1018, 0x102d, 0x102f, 0x1000, 0x103a, 0x6d, 0x67, 0x61, 0x20,
+0x62, 0x79, 0x74, 0x65, 0xd804, 0xdd1d, 0xd804, 0xdd2d, 0xd804, 0xdd16, 0xd804, 0xdd34,
+0x13d7, 0x13d3, 0x13cd, 0x13a6, 0x13b5, 0x13a9, 0x5b57, 0x8282, 0x4f4d, 0x5143, 0x7d44, 0x62,
+0x61, 0x6a, 0x74, 0x79, 0x62, 0x61, 0x6a, 0x74, 0x6f, 0x6a, 0x62, 0x61,
+0x69, 0x64, 0x69, 0x64, 0x62, 0xfd, 0x74, 0x74, 0x61, 0x76, 0x75, 0x74,
+0x6b, 0x74, 0x3b, 0x4d, 0x74, 0x3b, 0x47, 0x74, 0x3b, 0x54, 0x74, 0x3b,
+0x50, 0x74, 0x3b, 0x45, 0x74, 0x4b, 0x69, 0x74, 0x3b, 0x4d, 0x69, 0x74,
+0x3b, 0x47, 0x69, 0x74, 0x3b, 0x54, 0x69, 0x74, 0x3b, 0x50, 0x69, 0x74,
+0x3b, 0x45, 0x69, 0x74, 0x6f, 0x63, 0x74, 0x65, 0x74, 0x73, 0xd83a, 0xdd36,
+0xd83a, 0xdd2b, 0xd83a, 0xdd45, 0xd83a, 0xdd3c, 0xd83a, 0xdd46, 0xd83a, 0xdd2d, 0xd83a, 0xdd33,
+0xd83a, 0xdd14, 0x3b, 0xd83a, 0xdd03, 0xd83a, 0xdd14, 0x3b, 0xd83a, 0xdd18, 0xd83a, 0xdd14,
+0x3b, 0xd83a, 0xdd1a, 0xd83a, 0xdd14, 0x3b, 0xd83a, 0xdd06, 0xd83a, 0xdd14, 0x3b, 0x45,
+0x42, 0x62, 0x61, 0x69, 0x64, 0x68, 0x74, 0x10d1, 0x10d0, 0x10d8, 0x10e2, 0x10d8,
+0x10d9, 0x10d1, 0x10d0, 0x10d8, 0x10e2, 0x10d8, 0x3b, 0x4d, 0x42, 0x3b, 0x47, 0x42,
+0x3b, 0x10e2, 0x10d1, 0x10d0, 0x10d8, 0x10e2, 0x10d8, 0x3b, 0x10de, 0x10d1, 0x10d0, 0x10d8,
+0x10e2, 0x10d8, 0x3b, 0x45, 0x42, 0x42, 0x79, 0x74, 0x65, 0x73, 0xaac, 0xabe,
+0xa87, 0xa9f, 0x6b, 0x42, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x4d, 0x42, 0x20,
+0x7b, 0x30, 0x7d, 0x3b, 0x47, 0x42, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x54,
+0x42, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x50, 0x42, 0x20, 0x7b, 0x30, 0x7d,
+0x3b, 0x45, 0x42, 0x20, 0x7b, 0x30, 0x7d, 0x4b, 0x69, 0x42, 0x20, 0x7b,
+0x30, 0x7d, 0x3b, 0x4d, 0x69, 0x42, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x47,
+0x69, 0x42, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x54, 0x69, 0x42, 0x20, 0x7b,
+0x30, 0x7d, 0x3b, 0x50, 0x69, 0x42, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x45,
+0x69, 0x42, 0x20, 0x7b, 0x30, 0x7d, 0x5d1, 0x5d9, 0x5d9, 0x5d8, 0x92c, 0x93e,
+0x907, 0x91f, 0x62, 0xe1, 0x6a, 0x74, 0x62, 0xe6, 0x74, 0x69, 0x6f, 0x63,
+0x74, 0x65, 0x74, 0x65, 0x73, 0x62, 0x65, 0x61, 0x72, 0x74, 0x61, 0x30d0,
+0x30a4, 0x30c8, 0x4b, 0x42, 0x3b, 0x4d, 0x42, 0x3b, 0x47, 0x42, 0x3b, 0x54,
+0x42, 0x3b, 0x50, 0x42, 0x3b, 0x45, 0x42, 0x62, 0x69, 0x74, 0x65, 0x61,
+0x1e6d, 0x61, 0x6d, 0x1e0d, 0x61, 0x6e, 0x6b, 0x41, 0x1e6c, 0x3b, 0x4d, 0x41,
+0x1e6c, 0x3b, 0x47, 0x41, 0x1e6c, 0x3b, 0x54, 0x41, 0x1e6c, 0x3b, 0x50, 0x42,
+0x3b, 0x45, 0x42, 0xcac, 0xcc8, 0xc9f, 0xccd, 0x200c, 0xc97, 0xcb3, 0xcc1, 0xc95,
+0xcbf, 0x2e, 0xcac, 0xcc8, 0x2e, 0x3b, 0xcae, 0xcc6, 0x2e, 0xcac, 0xcc8, 0x2e,
+0x3b, 0xc97, 0xcbf, 0x2e, 0xcac, 0xcc8, 0x2e, 0x3b, 0xc9f, 0xcc6, 0x2e, 0xcac,
+0xcc8, 0x2e, 0x3b, 0xcaa, 0xcc6, 0xcac, 0xcc8, 0x3b, 0x45, 0x42, 0x43a, 0x411,
+0x3b, 0x4d, 0x411, 0x3b, 0x413, 0x411, 0x3b, 0x54, 0x411, 0x3b, 0x41f, 0x411,
+0x3b, 0x45, 0x411, 0x4b, 0x69, 0x411, 0x3b, 0x4d, 0x69, 0x411, 0x3b, 0x47,
+0x69, 0x411, 0x3b, 0x54, 0x69, 0x411, 0x3b, 0x50, 0x69, 0x411, 0x3b, 0x45,
+0x69, 0x411, 0x1794, 0x17c3, 0x92c, 0x93e, 0x92f, 0x91f, 0xbc14, 0xc774, 0xd2b8, 0x43a,
+0x411, 0x3b, 0x41c, 0x411, 0x3b, 0x413, 0x411, 0x3b, 0x422, 0x411, 0x3b, 0x41f,
+0x442, 0x431, 0x3b, 0x45, 0x42, 0x62, 0x61, 0x69, 0x74, 0x69, 0x62, 0x61,
+0x69, 0x74, 0x61, 0x69, 0x431, 0x430, 0x458, 0x442, 0x438, 0xd2c, 0xd48, 0xd31,
+0xd4d, 0xd31, 0xd4d, 0xd15, 0xd46, 0xd2c, 0xd3f, 0x3b, 0xd0e, 0xd02, 0xd2c, 0xd3f,
+0x3b, 0xd1c, 0xd3f, 0xd2c, 0xd3f, 0x3b, 0xd1f, 0xd3f, 0xd2c, 0xd3f, 0x3b, 0xd2a,
+0xd3f, 0xd2c, 0xd3f, 0x3b, 0x45, 0x42, 0x628, 0x627, 0x6cc, 0x62a, 0x6a9, 0x6cc,
+0x644, 0x648, 0x628, 0x627, 0x6cc, 0x62a, 0x3b, 0x645, 0x6af, 0x627, 0x628, 0x627,
+0x6cc, 0x62a, 0x3b, 0x6af, 0x6cc, 0x6af, 0x627, 0x628, 0x627, 0x6cc, 0x62a, 0x3b,
+0x62a, 0x631, 0x627, 0x628, 0x627, 0x6cc, 0x62a, 0x3b, 0x50, 0x42, 0x3b, 0x45,
+0x42, 0x43a, 0x411, 0x3b, 0x41c, 0x411, 0x3b, 0x413, 0x411, 0x3b, 0x422, 0x411,
+0x3b, 0x41f, 0x411, 0x3b, 0x45, 0x42, 0x6b, 0x42, 0x3b, 0x4d, 0x42, 0x3b,
+0x47, 0x42, 0x3b, 0x54, 0x42, 0x3b, 0x92a, 0x93f, 0x91f, 0x93e, 0x3b, 0x45,
+0x42, 0x42, 0x61, 0x69, 0x74, 0x2d, 0x64, 0x1eb9, 0x6d, 0xb2c, 0xb3e, 0xb07,
+0xb1f, 0xb4d, 0x628, 0x627, 0x64a, 0x67c, 0x633, 0xa2c, 0xa3e, 0xa07, 0xa1f, 0x62,
+0x79, 0x21b, 0x69, 0x431, 0x430, 0x430, 0x439, 0x442, 0x43a, 0x411, 0x3b, 0x41c,
+0x411, 0x3b, 0x47, 0x42, 0x3b, 0x54, 0x42, 0x3b, 0x50, 0x42, 0x3b, 0x45,
+0x42, 0x431, 0x430, 0x458, 0x442, 0x43e, 0x432, 0x438, 0x628, 0x627, 0x626, 0x64a,
+0x67d, 0x632, 0x6aa, 0x644, 0x648, 0x20, 0x628, 0x627, 0x626, 0x64a, 0x67d, 0x632,
+0x3b, 0x4d, 0x42, 0x3b, 0x47, 0x42, 0x3b, 0x54, 0x42, 0x3b, 0x50, 0x42,
+0x3b, 0x45, 0x42, 0xdb6, 0xdba, 0xdd2, 0xda7, 0xdca, 0xd9a, 0xdd2, 0xdb6, 0x20,
+0x7b, 0x30, 0x7d, 0x3b, 0xdb8, 0xdd9, 0xdb6, 0x20, 0x7b, 0x30, 0x7d, 0x3b,
+0xd9c, 0xdd2, 0xdb6, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0xda7, 0xdd9, 0xdb6, 0x20,
+0x7b, 0x30, 0x7d, 0x3b, 0xdb4, 0xdd9, 0xdb6, 0x20, 0x7b, 0x30, 0x7d, 0x3b,
+0x45, 0x42, 0x62, 0x65, 0x79, 0x74, 0x69, 0x73, 0x6b, 0x42, 0x3b, 0x4d,
+0x42, 0x3b, 0x47, 0x42, 0x3b, 0x54, 0x42, 0x3b, 0x42, 0x42, 0x3b, 0x45,
+0x42, 0x6b, 0x69, 0x6c, 0x6f, 0x62, 0x61, 0x69, 0x74, 0x69, 0x20, 0x7b,
+0x30, 0x7d, 0x3b, 0x4d, 0x42, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x47, 0x42,
+0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x74, 0x65, 0x72, 0x61, 0x62, 0x61, 0x69,
+0x74, 0x69, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x50, 0x42, 0x20, 0x7b, 0x30,
+0x7d, 0x3b, 0x45, 0x42, 0x712, 0x710, 0x71d, 0x72c, 0xbaa, 0xbc8, 0xb9f, 0xbcd,
+0xb95, 0xbb3, 0xbcd, 0xc2c, 0xc48, 0xc1f, 0xc4d, 0x200c, 0xc32, 0xc41, 0xc15, 0xc47,
+0xc2c, 0xc40, 0x3b, 0xc0e, 0xc2e, 0xc4d, 0x200c, 0xc2c, 0xc3f, 0x3b, 0xc1c, 0xc40,
+0xc2c, 0xc40, 0x3b, 0xc1f, 0xc40, 0xc2c, 0xc40, 0x3b, 0xc2a, 0xc40, 0xc2c, 0xc40,
+0x3b, 0x45, 0x42, 0xe44, 0xe1a, 0xe15, 0xe4c, 0x70, 0x61, 0x69, 0x74, 0x69,
+0x6b, 0x42, 0x20, 0x2bb, 0x65, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x4d, 0x42,
+0x20, 0x2bb, 0x65, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x47, 0x42, 0x20, 0x2bb,
+0x65, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x54, 0x42, 0x20, 0x2bb, 0x65, 0x20,
+0x7b, 0x30, 0x7d, 0x3b, 0x50, 0x42, 0x20, 0x2bb, 0x65, 0x20, 0x7b, 0x30,
+0x7d, 0x3b, 0x45, 0x42, 0x20, 0x2bb, 0x65, 0x20, 0x7b, 0x30, 0x7d, 0x4b,
+0x69, 0x42, 0x20, 0x2bb, 0x65, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x4d, 0x69,
+0x42, 0x20, 0x2bb, 0x65, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x47, 0x69, 0x42,
+0x20, 0x2bb, 0x65, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x54, 0x69, 0x42, 0x20,
+0x2bb, 0x65, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x50, 0x69, 0x42, 0x20, 0x2bb,
+0x65, 0x20, 0x7b, 0x30, 0x7d, 0x3b, 0x45, 0x69, 0x42, 0x20, 0x2bb, 0x65,
+0x20, 0x7b, 0x30, 0x7d, 0x62, 0x61, 0xfd, 0x74, 0x431, 0x430, 0x439, 0x442,
+0x438, 0x62, 0x79, 0x74, 0x65, 0x79, 0x628, 0x627, 0x626, 0x679, 0x6b, 0x42,
+0x3b, 0x4d, 0x42, 0x3b, 0x47, 0x42, 0x3b, 0x54, 0x42, 0x3b, 0x67e, 0x6cc,
+0x20, 0x628, 0x6cc, 0x3b, 0x45, 0x42, 0x62, 0x65, 0x69, 0x74, 0x69, 0x61,
+0x75, 0xe0, 0x77, 0x1ecd, 0x301, 0x6e, 0x20, 0x62, 0xe1, 0xec, 0x74, 0xec,
+0x6b, 0xe9, 0x62, 0xe1, 0xec, 0x74, 0xec, 0x3b, 0x4d, 0x42, 0x3b, 0x6a,
+0xed, 0x62, 0xe1, 0xec, 0x74, 0xec, 0x3b, 0x54, 0xed, 0x62, 0xe1, 0xec,
+0x74, 0xec, 0x3b, 0x50, 0xed, 0x62, 0xe1, 0xec, 0x74, 0xec, 0x3b, 0x45,
+0x42, 0xe0, 0x77, 0x254, 0x301, 0x6e, 0x20, 0x62, 0xe1, 0xec, 0x74, 0xec,
+0x62, 0x79, 0x74, 0x65, 0x20, 0x61, 0x67, 0x62, 0x79, 0x74, 0x65, 0x2d,
+0x69, 0x74, 0x61
};
static constexpr char16_t am_data[] = {
-0x41, 0x4d, 0x76, 0x6d, 0x2e, 0x61, 0x2e, 0x67, 0x41, 0x4e, 0x65, 0x20, 0x70, 0x61, 0x72, 0x61, 0x64, 0x69, 0x74, 0x65,
-0x73, 0x1325, 0x12cb, 0x1275, 0x635, 0x9aa, 0x9c2, 0x9f0, 0x9cd, 0x9ac, 0x9be, 0x9b9, 0x9cd, 0x9a8, 0x64, 0x65, 0x20, 0x6c, 0x61, 0x20,
-0x6d, 0x61, 0xf1, 0x61, 0x6e, 0x61, 0x69, 0x63, 0x68, 0x65, 0x68, 0x65, 0x61, 0x76, 0x6f, 0x410, 0x41c, 0x73, 0xe1, 0x72,
-0xfa, 0x77, 0xe1, 0x49, 0x20, 0x62, 0x69, 0x6b, 0x25b, 0x302, 0x67, 0x6c, 0xe0, 0x75, 0x6c, 0x75, 0x63, 0x68, 0x65, 0x6c,
-0x6f, 0x70, 0x61, 0x6d, 0x69, 0x6c, 0x61, 0x75, 0x92d, 0x94b, 0x930, 0x92b, 0x941, 0x902, 0x70, 0x72, 0x69, 0x6a, 0x65, 0x70,
-0x6f, 0x64, 0x6e, 0x65, 0x43f, 0x440, 0x438, 0x458, 0x435, 0x20, 0x43f, 0x43e, 0x434, 0x43d, 0x435, 0x41, 0x2e, 0x4d, 0x2e, 0x43f,
-0x440, 0x2e, 0x43e, 0x431, 0x2e, 0x1014, 0x1036, 0x1014, 0x1000, 0x103a, 0x4e0a, 0x5348, 0x61, 0x2e, 0xa0, 0x6d, 0x2e, 0x5a, 0x64, 0x61,
-0x74, 0x20, 0x61, 0x7a, 0x61, 0x6c, 0x628, 0x2e, 0x646, 0x13cc, 0x13be, 0x13b4, 0x55, 0x68, 0x72, 0x20, 0x76, 0xf6, 0x72, 0x6d,
-0x69, 0x64, 0x64, 0x61, 0x61, 0x63, 0x68, 0x73, 0x61, 0x2e, 0x6d, 0x2e, 0x64, 0x6f, 0x70, 0x2e, 0x938, 0x935, 0x947, 0x930,
-0x69, 0x64, 0x69, 0x253, 0x61, 0xf66, 0xf94, 0xf0b, 0xf46, 0xf0b, 0x4b, 0x49, 0x61, 0x74, 0x6d, 0x14b, 0x64, 0x69, 0x6b, 0xed,
-0x6b, 0xed, 0x72, 0xed, 0x67, 0x61, 0x70, 0x2e, 0x6d, 0x61, 0x74, 0x69, 0x6e, 0x73, 0x75, 0x62, 0x61, 0x6b, 0x61, 0xd83a,
-0xdd00, 0xd83a, 0xdd0e, 0x3c0, 0x2e, 0x3bc, 0x2e, 0x4d, 0x61, 0x6d, 0x62, 0x69, 0x61, 0x53, 0x61, 0x66, 0x69, 0x79, 0x61, 0x5dc,
-0x5e4, 0x5e0, 0x5d4, 0x5f4, 0x5e6, 0x64, 0x65, 0x2e, 0x66, 0x2e, 0x68, 0x2e, 0x4e, 0x2019, 0x1ee5, 0x74, 0x1ee5, 0x74, 0x1ee5, 0x69,
-0x70, 0x2e, 0x72, 0x2e, 0x6e, 0x2e, 0x5348, 0x524d, 0x49, 0x73, 0x75, 0x6b, 0x6e, 0x20, 0x74, 0x75, 0x66, 0x61, 0x74, 0x6b,
-0x61, 0x72, 0x6f, 0x6f, 0x6e, 0x128, 0x79, 0x61, 0x6b, 0x77, 0x61, 0x6b, 0x79, 0x61, 0xcaa, 0xcc2, 0xcb0, 0xccd, 0xcb5, 0xcbe,
-0xcb9, 0xccd, 0xca8, 0x627, 0x6d2, 0x20, 0x627, 0x6cc, 0x645, 0x92f, 0x947, 0x20, 0x90f, 0x92e, 0x4b, 0x69, 0x72, 0x6f, 0x6b, 0x6f,
-0x938, 0x915, 0x93e, 0x933, 0xc624, 0xc804, 0x41, 0x64, 0x64, 0x75, 0x68, 0x61, 0x42, 0x4e, 0x6d, 0x61, 0x6e, 0xe1, 0x442, 0x430,
-0x4a3, 0x43a, 0x44b, 0x54, 0x4f, 0x4f, 0xe81, 0xec8, 0xead, 0xe99, 0xe97, 0xec8, 0xebd, 0xe87, 0x70, 0x72, 0x69, 0x65, 0x6b, 0x161,
-0x70, 0x75, 0x73, 0x64, 0x69, 0x65, 0x6e, 0x101, 0x6e, 0x74, 0x254, 0x301, 0x6e, 0x67, 0x254, 0x301, 0x70, 0x72, 0x69, 0x65,
-0x161, 0x70, 0x69, 0x65, 0x74, 0x64, 0x6f, 0x70, 0x6f, 0x142, 0x64, 0x6e, 0x6a, 0x61, 0x44, 0x69, 0x6e, 0x64, 0x61, 0x4f,
-0x44, 0x6d, 0x6f, 0x69, 0x65, 0x73, 0x43f, 0x440, 0x435, 0x442, 0x43f, 0x43b, 0x2e, 0x75, 0x74, 0x75, 0x6b, 0x6f, 0x77, 0x69,
-0x63, 0x68, 0x69, 0x73, 0x68, 0x75, 0x4d, 0x75, 0x68, 0x69, 0x50, 0x47, 0x98f, 0x20, 0x98f, 0x9ae, 0x190, 0x6e, 0x6b, 0x61,
-0x6b, 0x25b, 0x6e, 0x79, 0xe1, 0x52, 0x168, 0x4af, 0x2e, 0x4e9, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x1c1, 0x67, 0x6f, 0x61,
-0x67, 0x61, 0x73, 0x92a, 0x942, 0x930, 0x94d, 0x935, 0x93e, 0x939, 0x94d, 0x928, 0x6d, 0x62, 0x61, 0x2bc, 0xe1, 0x6d, 0x62, 0x61,
-0x2bc, 0x6d, 0x62, 0x61, 0xa78c, 0x6d, 0x62, 0x61, 0xa78c, 0x46, 0x1ecd, 0x20, 0x6d, 0x1ecd, 0x301, 0x6e, 0x69, 0x6e, 0x69, 0x111,
-0x69, 0x74, 0x62, 0x65, 0x61, 0x69, 0x76, 0x65, 0x74, 0x69, 0x62, 0x52, 0x57, 0x57, 0x44, 0x4d5, 0x43c, 0x431, 0x438, 0x441,
-0x431, 0x43e, 0x43d, 0x44b, 0x20, 0x440, 0x430, 0x437, 0x43c, 0x4d5, 0x63a, 0x2e, 0x645, 0x2e, 0x642, 0x628, 0x644, 0x200c, 0x627, 0x632,
-0x638, 0x647, 0x631, 0x64, 0x61, 0x20, 0x6d, 0x61, 0x6e, 0x68, 0xe3, 0xa2a, 0xa42, 0x2e, 0xa26, 0xa41, 0x2e, 0x6b, 0x61, 0x6e,
-0x67, 0x2019, 0x61, 0x6d, 0x61, 0x5a, 0x2e, 0x4d, 0x55, 0x2e, 0x42d, 0x418, 0x54, 0x65, 0x73, 0x69, 0x72, 0x61, 0x6e, 0x4e,
-0x44, 0x4c, 0x77, 0x61, 0x6d, 0x69, 0x6c, 0x61, 0x77, 0x75, 0x1c65, 0x1c6e, 0x1c5b, 0x1c5f, 0x1c5c, 0x70, 0x72, 0x69, 0x6a, 0x65,
-0x20, 0x70, 0x6f, 0x64, 0x6e, 0x65, 0x6d, 0x61, 0x6b, 0x65, 0x6f, 0xa3b8, 0xa111, 0x635, 0x628, 0x62d, 0x60c, 0x20, 0x645, 0x646,
-0x62c, 0x647, 0x646, 0x62f, 0x938, 0x941, 0x92c, 0x941, 0x939, 0x20, 0x91c, 0x93e, 0xdb4, 0xdd9, 0x2e, 0xdc0, 0x2e, 0x4d, 0x75, 0x6e,
-0x6b, 0x79, 0x6f, 0x47, 0x48, 0x2d5c, 0x2d49, 0x2d3c, 0x2d30, 0x2d61, 0x2d5c, 0x66, 0x6d, 0x61, 0x6d, 0x20, 0x56, 0x6f, 0x72, 0x6d,
-0x69, 0x74, 0x74, 0x61, 0x67, 0x74, 0x69, 0x66, 0x61, 0x77, 0x74, 0x4c, 0x75, 0x6d, 0x61, 0x20, 0x6c, 0x77, 0x61, 0x20,
-0x4b, 0xbae, 0xbc1, 0xbb1, 0xbcd, 0xbaa, 0xb95, 0xbb2, 0xbcd, 0x53, 0x75, 0x62, 0x62, 0x61, 0x61, 0x68, 0x69, 0x54, 0x61, 0x70,
-0x61, 0x72, 0x61, 0x63, 0x68, 0x75, 0xe01, 0xe48, 0xe2d, 0xe19, 0xe40, 0xe17, 0xe35, 0xe48, 0xe22, 0xe07, 0xf66, 0xf94, 0xf0b, 0xf51,
-0xfb2, 0xf7c, 0xf0b, 0x1245, 0x2e, 0x1240, 0x2e, 0x68, 0x65, 0x6e, 0x67, 0x69, 0x68, 0x65, 0x6e, 0x67, 0x69, 0xd6, 0xd6, 0x67,
-0xfc, 0x6e, 0x6f, 0x72, 0x74, 0x61, 0x64, 0x61, 0x6e, 0x20, 0xf6, 0x148, 0x434, 0x43f, 0x686, 0x6c8, 0x634, 0x62a, 0x649, 0x646,
-0x20, 0x628, 0x6c7, 0x631, 0x6c7, 0x646, 0x422, 0x41e, 0x53, 0x41, 0x79, 0x62, 0x6b, 0x69, 0x25b, 0x6d, 0x25b, 0x301, 0x25b, 0x6d,
-0x5e4, 0x5bf, 0x5d0, 0x5b7, 0x5e8, 0x5de, 0x5d9, 0x5d8, 0x5d0, 0x5b8, 0x5d2, 0xc0, 0xe1, 0x72, 0x1ecd, 0x300, 0xc0, 0xe1, 0x72, 0x254,
-0x300, 0x924, 0x921, 0x915, 0x947, 0x938, 0x92c, 0x947, 0x930, 0x947
+0x41, 0x4d, 0x76, 0x6d, 0x2e, 0x61, 0x2e, 0x67, 0x41, 0x4e, 0x65, 0x20,
+0x70, 0x61, 0x72, 0x61, 0x64, 0x69, 0x74, 0x65, 0x73, 0x1325, 0x12cb, 0x1275,
+0x635, 0x9aa, 0x9c2, 0x9f0, 0x9cd, 0x9ac, 0x9be, 0x9b9, 0x9cd, 0x9a8, 0x64, 0x65,
+0x20, 0x6c, 0x61, 0x20, 0x6d, 0x61, 0xf1, 0x61, 0x6e, 0x61, 0x69, 0x63,
+0x68, 0x65, 0x68, 0x65, 0x61, 0x76, 0x6f, 0x410, 0x41c, 0x73, 0xe1, 0x72,
+0xfa, 0x77, 0xe1, 0x49, 0x20, 0x62, 0x69, 0x6b, 0x25b, 0x302, 0x67, 0x6c,
+0xe0, 0x75, 0x6c, 0x75, 0x63, 0x68, 0x65, 0x6c, 0x6f, 0x70, 0x61, 0x6d,
+0x69, 0x6c, 0x61, 0x75, 0x92d, 0x94b, 0x930, 0x92b, 0x941, 0x902, 0x70, 0x72,
+0x69, 0x6a, 0x65, 0x70, 0x6f, 0x64, 0x6e, 0x65, 0x43f, 0x440, 0x438, 0x458,
+0x435, 0x20, 0x43f, 0x43e, 0x434, 0x43d, 0x435, 0x41, 0x2e, 0x4d, 0x2e, 0x43f,
+0x440, 0x2e, 0x43e, 0x431, 0x2e, 0x1014, 0x1036, 0x1014, 0x1000, 0x103a, 0x4e0a, 0x5348,
+0x61, 0x2e, 0xa0, 0x6d, 0x2e, 0x5a, 0x64, 0x61, 0x74, 0x20, 0x61, 0x7a,
+0x61, 0x6c, 0x628, 0x2e, 0x646, 0x13cc, 0x13be, 0x13b4, 0x55, 0x68, 0x72, 0x20,
+0x76, 0xf6, 0x72, 0x6d, 0x69, 0x64, 0x64, 0x61, 0x61, 0x63, 0x68, 0x73,
+0x61, 0x2e, 0x6d, 0x2e, 0x64, 0x6f, 0x70, 0x2e, 0x938, 0x935, 0x947, 0x930,
+0x69, 0x64, 0x69, 0x253, 0x61, 0xf66, 0xf94, 0xf0b, 0xf46, 0xf0b, 0x4b, 0x49,
+0xd801, 0xdc08, 0xd801, 0xdc23, 0xd801, 0xdc68, 0xd801, 0xdc65, 0x61, 0x74, 0x6d, 0x14b,
+0x64, 0x69, 0x6b, 0xed, 0x6b, 0xed, 0x72, 0xed, 0x67, 0x61, 0x70, 0x2e,
+0x6d, 0x61, 0x74, 0x69, 0x6e, 0x73, 0x75, 0x62, 0x61, 0x6b, 0x61, 0xd83a,
+0xdd00, 0xd83a, 0xdd0e, 0x3c0, 0x2e, 0x3bc, 0x2e, 0x4d, 0x61, 0x6d, 0x62, 0x69,
+0x61, 0x53, 0x61, 0x66, 0x69, 0x79, 0x61, 0x5dc, 0x5e4, 0x5e0, 0x5d4, 0x5f4,
+0x5e6, 0x64, 0x65, 0x2e, 0x66, 0x2e, 0x68, 0x2e, 0x4e, 0x2019, 0x1ee5, 0x74,
+0x1ee5, 0x74, 0x1ee5, 0x69, 0x70, 0x2e, 0x61, 0x6e, 0x74, 0x65, 0x20, 0x6d,
+0x69, 0x64, 0xed, 0x72, 0x2e, 0x6e, 0x2e, 0x5348, 0x524d, 0x49, 0x73, 0x75,
+0x6b, 0x6e, 0x20, 0x74, 0x75, 0x66, 0x61, 0x74, 0x6b, 0x61, 0x72, 0x6f,
+0x6f, 0x6e, 0x128, 0x79, 0x61, 0x6b, 0x77, 0x61, 0x6b, 0x79, 0x61, 0xcaa,
+0xcc2, 0xcb0, 0xccd, 0xcb5, 0xcbe, 0xcb9, 0xccd, 0xca8, 0x627, 0x6d2, 0x20, 0x627,
+0x6cc, 0x645, 0x92f, 0x947, 0x20, 0x90f, 0x92e, 0x4b, 0x69, 0x72, 0x6f, 0x6b,
+0x6f, 0x938, 0x915, 0x93e, 0x933, 0xc624, 0xc804, 0x41, 0x64, 0x64, 0x75, 0x68,
+0x61, 0x42, 0x4e, 0x6d, 0x61, 0x6e, 0xe1, 0x442, 0x430, 0x4a3, 0x43a, 0x44b,
+0x54, 0x4f, 0x4f, 0xe81, 0xec8, 0xead, 0xe99, 0xe97, 0xec8, 0xebd, 0xe87, 0x70,
+0x72, 0x69, 0x65, 0x6b, 0x161, 0x70, 0x75, 0x73, 0x64, 0x69, 0x65, 0x6e,
+0x101, 0x6e, 0x74, 0x254, 0x301, 0x6e, 0x67, 0x254, 0x301, 0x70, 0x72, 0x69,
+0x65, 0x161, 0x70, 0x69, 0x65, 0x74, 0x64, 0x6f, 0x70, 0x6f, 0x142, 0x64,
+0x6e, 0x6a, 0x61, 0x44, 0x69, 0x6e, 0x64, 0x61, 0x4f, 0x44, 0x6d, 0x6f,
+0x69, 0x65, 0x73, 0x43f, 0x440, 0x435, 0x442, 0x43f, 0x43b, 0x2e, 0x75, 0x74,
+0x75, 0x6b, 0x6f, 0x77, 0x69, 0x63, 0x68, 0x69, 0x73, 0x68, 0x75, 0x4d,
+0x75, 0x68, 0x69, 0x50, 0x47, 0x98f, 0x20, 0x98f, 0x9ae, 0x190, 0x6e, 0x6b,
+0x61, 0x6b, 0x25b, 0x6e, 0x79, 0xe1, 0x52, 0x168, 0x4af, 0x2e, 0x4e9, 0x2e,
+0x1826, 0x1802, 0x20, 0x1825, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x1c1, 0x67, 0x6f,
+0x61, 0x67, 0x61, 0x73, 0x92a, 0x942, 0x930, 0x94d, 0x935, 0x93e, 0x939, 0x94d,
+0x928, 0x6d, 0x62, 0x61, 0x2bc, 0xe1, 0x6d, 0x62, 0x61, 0x2bc, 0x6d, 0x62,
+0x61, 0xa78c, 0x6d, 0x62, 0x61, 0xa78c, 0x46, 0x1ecd, 0x20, 0x6d, 0x1ecd, 0x301,
+0x6e, 0x69, 0x6e, 0x7db, 0x69, 0x111, 0x69, 0x74, 0x62, 0x65, 0x61, 0x69,
+0x76, 0x65, 0x74, 0x69, 0x62, 0x66, 0x2e, 0x6d, 0x2e, 0x52, 0x57, 0x57,
+0x44, 0x4d5, 0x43c, 0x431, 0x438, 0x441, 0x431, 0x43e, 0x43d, 0x44b, 0x20, 0x440,
+0x430, 0x437, 0x43c, 0x4d5, 0x63a, 0x2e, 0x645, 0x2e, 0x642, 0x628, 0x644, 0x200c,
+0x627, 0x632, 0x638, 0x647, 0x631, 0x64, 0x61, 0x20, 0x6d, 0x61, 0x6e, 0x68,
+0xe3, 0x61, 0x6e, 0x6b, 0x73, 0x74, 0x101, 0x69, 0x6e, 0x61, 0x6e, 0xa2a,
+0xa42, 0x2e, 0xa26, 0xa41, 0x2e, 0x6b, 0x61, 0x6e, 0x67, 0x2019, 0x61, 0x6d,
+0x61, 0x5a, 0x2e, 0x4d, 0x55, 0x2e, 0x42d, 0x418, 0x54, 0x65, 0x73, 0x69,
+0x72, 0x61, 0x6e, 0x4e, 0x44, 0x4c, 0x77, 0x61, 0x6d, 0x69, 0x6c, 0x61,
+0x77, 0x75, 0x1c65, 0x1c6e, 0x1c5b, 0x1c5f, 0x1c5c, 0x70, 0x72, 0x69, 0x6a, 0x65,
+0x20, 0x70, 0x6f, 0x64, 0x6e, 0x65, 0x6d, 0x61, 0x6b, 0x65, 0x6f, 0xa3b8,
+0xa111, 0x64, 0x6f, 0x20, 0x70, 0x6f, 0x142, 0x65, 0x64, 0x6e, 0x69, 0x14f,
+0x635, 0x628, 0x62d, 0x60c, 0x20, 0x645, 0x646, 0x62c, 0x647, 0x646, 0x62f, 0x938,
+0x941, 0x92c, 0x941, 0x939, 0x20, 0x91c, 0x93e, 0xdb4, 0xdd9, 0x2e, 0xdc0, 0x2e,
+0x4d, 0x75, 0x6e, 0x6b, 0x79, 0x6f, 0x47, 0x48, 0x2d5c, 0x2d49, 0x2d3c, 0x2d30,
+0x2d61, 0x2d5c, 0x66, 0x6d, 0x61, 0x6d, 0x20, 0x56, 0x6f, 0x72, 0x6d, 0x69,
+0x74, 0x74, 0x61, 0x67, 0x70f, 0x729, 0x71b, 0x200c, 0x74, 0x69, 0x66, 0x61,
+0x77, 0x74, 0x4c, 0x75, 0x6d, 0x61, 0x20, 0x6c, 0x77, 0x61, 0x20, 0x4b,
+0x53, 0x75, 0x62, 0x62, 0x61, 0x61, 0x68, 0x69, 0x54, 0x61, 0x70, 0x61,
+0x72, 0x61, 0x63, 0x68, 0x75, 0xe01, 0xe48, 0xe2d, 0xe19, 0xe40, 0xe17, 0xe35,
+0xe48, 0xe22, 0xe07, 0xf66, 0xf94, 0xf0b, 0xf51, 0xfb2, 0xf7c, 0xf0b, 0x1245, 0x2e,
+0x1240, 0x2e, 0x68, 0x65, 0x6e, 0x67, 0x69, 0x68, 0x65, 0x6e, 0x67, 0x69,
+0xd6, 0xd6, 0x67, 0xfc, 0x6e, 0x6f, 0x72, 0x74, 0x61, 0x64, 0x61, 0x6e,
+0x20, 0xf6, 0x148, 0x434, 0x43f, 0x686, 0x6c8, 0x634, 0x62a, 0x649, 0x646, 0x20,
+0x628, 0x6c7, 0x631, 0x6c7, 0x646, 0x422, 0x41e, 0x53, 0x41, 0x79, 0x62, 0x6b,
+0x69, 0x25b, 0x6d, 0x25b, 0x301, 0x25b, 0x6d, 0x5e4, 0x5bf, 0x5d0, 0x5b7, 0x5e8,
+0x5de, 0x5d9, 0x5d8, 0x5d0, 0x5b8, 0x5d2, 0xc0, 0xe1, 0x72, 0x1ecd, 0x300, 0xc0,
+0xe1, 0x72, 0x254, 0x300, 0x62, 0x61, 0x6e, 0x68, 0x61, 0x65, 0x74, 0x924,
+0x921, 0x915, 0x947, 0x938, 0x92c, 0x947, 0x930, 0x947, 0x70, 0x69, 0x20, 0x6f,
+0x70, 0x65, 0x6e, 0x20, 0x73, 0x75, 0x6e, 0x6f, 0x28a, 0x73, 0x68, 0x69,
+0x6c, 0xe8, 0x20, 0x6b, 0x28a, 0x62, 0x6f, 0x256, 0x75, 0x92d, 0x94d, 0x92f,
+0x93e, 0x917, 0x93e
};
static constexpr char16_t pm_data[] = {
-0x50, 0x4d, 0x6e, 0x6d, 0x2e, 0x61, 0x2e, 0x6b, 0x45, 0x57, 0x65, 0x20, 0x70, 0x61, 0x73, 0x64, 0x69, 0x74, 0x65, 0x73,
-0x12a8, 0x1230, 0x12d3, 0x1275, 0x645, 0x985, 0x9aa, 0x9f0, 0x9be, 0x9b9, 0x9cd, 0x9a8, 0x64, 0x65, 0x20, 0x6c, 0x61, 0x20, 0x74, 0x61,
-0x72, 0x64, 0x65, 0x69, 0x63, 0x68, 0x61, 0x6d, 0x74, 0x68, 0x69, 0x41f, 0x41c, 0x63, 0x25b, 0x25b, 0x301, 0x6e, 0x6b, 0x6f,
-0x49, 0x20, 0x253, 0x75, 0x67, 0x61, 0x6a, 0x254, 0x70, 0x61, 0x6b, 0x61, 0x73, 0x75, 0x62, 0x61, 0x70, 0x61, 0x6d, 0x75,
-0x6e, 0x79, 0x69, 0x938, 0x93e, 0x902, 0x91d, 0x92c, 0x947, 0x932, 0x93e, 0x938, 0x947, 0x70, 0x6f, 0x70, 0x6f, 0x64, 0x6e, 0x65,
-0x43f, 0x43e, 0x441, 0x43b, 0x438, 0x458, 0x435, 0x20, 0x43f, 0x43e, 0x434, 0x43d, 0x435, 0x47, 0x2e, 0x4d, 0x2e, 0x441, 0x43b, 0x2e,
-0x43e, 0x431, 0x2e, 0x100a, 0x1014, 0x1031, 0x4e0b, 0x5348, 0x70, 0x2e, 0xa0, 0x6d, 0x2e, 0x1e0c, 0x65, 0x66, 0x66, 0x69, 0x72, 0x20,
-0x61, 0x7a, 0x61, 0x62f, 0x2e, 0x646, 0x13d2, 0x13af, 0x13f1, 0x13a2, 0x13d7, 0x13e2, 0x55, 0x68, 0x72, 0x20, 0x6e, 0x6f, 0x6d, 0x6d,
-0x65, 0x6e, 0x64, 0x61, 0x61, 0x63, 0x68, 0x73, 0x70, 0x2e, 0x6d, 0x2e, 0x6f, 0x64, 0x70, 0x2e, 0x926, 0x92a, 0x948, 0x939,
-0x930, 0x20, 0x92c, 0x93e, 0x926, 0x65, 0x62, 0x79, 0xe1, 0x6d, 0x75, 0xf55, 0xfb1, 0xf72, 0xf0b, 0xf46, 0xf0b, 0x55, 0x54, 0x70,
-0x6d, 0x70, 0x74, 0x6d, 0x263, 0x65, 0x74, 0x72, 0x254, 0x6e, 0x67, 0x259, 0x67, 0xf3, 0x67, 0x259, 0x6c, 0x65, 0x69, 0x70,
-0x2e, 0x73, 0x6f, 0x69, 0x72, 0x6b, 0x69, 0x6b, 0x69, 0x69, 0x257, 0x65, 0xd83a, 0xdd07, 0xd83a, 0xdd0e, 0x3bc, 0x2e, 0x3bc, 0x2e,
-0x4d, 0x6f, 0x67, 0x59, 0x61, 0x6d, 0x6d, 0x61, 0x5d0, 0x5d7, 0x5d4, 0x5f4, 0x5e6, 0x64, 0x75, 0x2e, 0x65, 0x2e, 0x68, 0x2e,
-0x4e, 0x2019, 0x61, 0x62, 0x61, 0x6c, 0x69, 0x65, 0x70, 0x2e, 0x69, 0x2e, 0x6e, 0x2e, 0x5348, 0x5f8c, 0x57, 0x65, 0x6e, 0x67,
-0x69, 0x6e, 0x20, 0x74, 0x6d, 0x65, 0x64, 0x64, 0x69, 0x74, 0x6b, 0x6f, 0x6f, 0x73, 0x6b, 0x6f, 0x6c, 0x69, 0x6e, 0x79,
-0x128, 0x79, 0x61, 0x77, 0x129, 0x6f, 0x6f, 0xc85, 0xcaa, 0xcb0, 0xcbe, 0xcb9, 0xccd, 0xca8, 0x67e, 0x6cc, 0x20, 0x627, 0x6cc, 0x645,
-0x92a, 0x940, 0x20, 0x90f, 0x92e, 0x48, 0x77, 0x61, 0x129, 0x2d, 0x69, 0x6e, 0x129, 0x938, 0x93e, 0x902, 0x91c, 0xc624, 0xd6c4, 0x41,
-0x6c, 0x75, 0x75, 0x6c, 0x61, 0x50, 0x4e, 0x6b, 0x75, 0x67, 0xfa, 0x442, 0x4af, 0x448, 0x442, 0x4e9, 0x43d, 0x20, 0x43a, 0x438,
-0x439, 0x438, 0x43d, 0x43a, 0x438, 0x4d, 0x55, 0x55, 0xeab, 0xebc, 0xeb1, 0xe87, 0xe97, 0xec8, 0xebd, 0xe87, 0x70, 0x113, 0x63, 0x70,
-0x75, 0x73, 0x64, 0x69, 0x65, 0x6e, 0x101, 0x6d, 0x70, 0xf3, 0x6b, 0x77, 0x61, 0x70, 0x6f, 0x70, 0x69, 0x65, 0x74, 0x77,
-0xf3, 0x74, 0x70, 0x6f, 0x142, 0x64, 0x6e, 0x6a, 0x61, 0x44, 0x69, 0x6c, 0x6f, 0x6c, 0x6f, 0x4f, 0x54, 0x6e, 0x6f, 0x6d,
-0xeb, 0x74, 0x74, 0x65, 0x73, 0x43f, 0x43e, 0x43f, 0x43b, 0x2e, 0x6b, 0x79, 0x69, 0x75, 0x6b, 0x6f, 0x6e, 0x79, 0x69, 0x6d,
-0x63, 0x68, 0x6f, 0x63, 0x68, 0x69, 0x6c, 0x2019, 0x6c, 0x43, 0x68, 0x69, 0x6c, 0x6f, 0x50, 0x54, 0x47, 0x9aa, 0x9bf, 0x20,
-0x98f, 0x9ae, 0x190, 0x6e, 0x64, 0xe1, 0x6d, 0xe2, 0x168, 0x47, 0x4af, 0x2e, 0x445, 0x2e, 0x6c, 0x69, 0x6c, 0x6c, 0x69, 0x1c3,
-0x75, 0x69, 0x61, 0x73, 0x905, 0x92a, 0x930, 0x93e, 0x939, 0x94d, 0x928, 0x6e, 0x63, 0x77, 0xf2, 0x6e, 0x7a, 0xe9, 0x6d, 0x14b,
-0x6b, 0x61, 0x20, 0x6d, 0x62, 0x254, 0x301, 0x74, 0x20, 0x6e, 0x6a, 0x69, 0x46, 0x1ecd, 0x20, 0xed, 0x76, 0x6e, 0x69, 0x6e,
-0x65, 0x61, 0x68, 0x6b, 0x65, 0x74, 0x62, 0x65, 0x61, 0x69, 0x76, 0x65, 0x74, 0x54, 0x14a, 0x57, 0x42, 0x4d5, 0x43c, 0x431,
-0x438, 0x441, 0x431, 0x43e, 0x43d, 0x44b, 0x20, 0x444, 0x4d5, 0x441, 0x442, 0x4d5, 0x63a, 0x2e, 0x648, 0x2e, 0x628, 0x639, 0x62f, 0x627,
-0x632, 0x638, 0x647, 0x631, 0x64, 0x61, 0x20, 0x74, 0x61, 0x72, 0x64, 0x65, 0xa2c, 0xa3e, 0x2e, 0xa26, 0xa41, 0x2e, 0x6b, 0x69,
-0x6e, 0x67, 0x6f, 0x74, 0x6f, 0x5a, 0x2e, 0x4d, 0x57, 0x2e, 0x42d, 0x41a, 0x54, 0x65, 0x69, 0x70, 0x61, 0x4c, 0x4b, 0x50,
-0x61, 0x73, 0x68, 0x61, 0x6d, 0x69, 0x68, 0x65, 0x1c67, 0x1c64, 0x1c6b, 0x1c5f, 0x1c79, 0x43f, 0x43e, 0x20, 0x43f, 0x43e, 0x434, 0x43d,
-0x435, 0x70, 0x6f, 0x20, 0x70, 0x6f, 0x64, 0x6e, 0x65, 0x6e, 0x79, 0x69, 0x61, 0x67, 0x68, 0x75, 0x6f, 0xa06f, 0xa2d2, 0x645,
-0x646, 0x62c, 0x647, 0x646, 0x62f, 0x60c, 0x20, 0x634, 0x627, 0x645, 0x936, 0x93e, 0x92e, 0x20, 0x91c, 0x93e, 0xdb4, 0x2e, 0xdc0, 0x2e,
-0x70, 0x6f, 0x70, 0x2e, 0x45, 0x69, 0x67, 0x75, 0x6c, 0x6f, 0x47, 0x44, 0x2d5c, 0x2d30, 0x2d37, 0x2d33, 0x2d33, 0x2d6f, 0x2d30, 0x2d5c,
-0x65, 0x6d, 0x61, 0x6d, 0x20, 0x4e, 0x61, 0x6d, 0x69, 0x74, 0x74, 0x61, 0x67, 0x74, 0x61, 0x64, 0x67, 0x67, 0x2b7, 0x61,
-0x74, 0x6c, 0x75, 0x6d, 0x61, 0x20, 0x6c, 0x77, 0x61, 0x20, 0x70, 0xbaa, 0xbbf, 0xbb1, 0xbcd, 0xbaa, 0xb95, 0xbb2, 0xbcd, 0x5a,
-0x61, 0x61, 0x72, 0x69, 0x6b, 0x61, 0x79, 0x20, 0x62, 0x45, 0x62, 0x6f, 0x6e, 0x67, 0x69, 0xe2b, 0xe25, 0xe31, 0xe07, 0xe40,
-0xe17, 0xe35, 0xe48, 0xe22, 0xe07, 0xf55, 0xfb1, 0xf72, 0xf0b, 0xf51, 0xfb2, 0xf7c, 0xf0b, 0x12f5, 0x2e, 0x1240, 0x2e, 0x65, 0x66, 0x69,
-0x61, 0x66, 0x69, 0xd6, 0x53, 0x67, 0xfc, 0x6e, 0x6f, 0x72, 0x74, 0x61, 0x64, 0x61, 0x6e, 0x20, 0x73, 0x6f, 0x148, 0x43f,
-0x43f, 0x70, 0x6f, 0x70, 0x6f, 0x142, 0x64, 0x6e, 0x6a, 0x75, 0x686, 0x6c8, 0x634, 0x62a, 0x649, 0x646, 0x20, 0x643, 0x6d0, 0x64a,
-0x649, 0x646, 0x54, 0x4b, 0x422, 0x41a, 0x43, 0x48, 0x79, 0x68, 0x4e, 0x67, 0x6f, 0x6b, 0x69, 0x73, 0x25b, 0x301, 0x6e, 0x64,
-0x25b, 0x5e0, 0x5d0, 0x5b8, 0x5db, 0x5de, 0x5d9, 0x5d8, 0x5d0, 0x5b8, 0x5d2, 0x1ecc, 0x300, 0x73, 0xe1, 0x6e, 0x186, 0x300, 0x73, 0xe1,
-0x6e, 0x938, 0x93e, 0x902, 0x92e
+0x50, 0x4d, 0x6e, 0x6d, 0x2e, 0x61, 0x2e, 0x6b, 0x45, 0x57, 0x65, 0x20,
+0x70, 0x61, 0x73, 0x64, 0x69, 0x74, 0x65, 0x73, 0x12a8, 0x1230, 0x12d3, 0x1275,
+0x645, 0x985, 0x9aa, 0x9f0, 0x9be, 0x9b9, 0x9cd, 0x9a8, 0x64, 0x65, 0x20, 0x6c,
+0x61, 0x20, 0x74, 0x61, 0x72, 0x64, 0x65, 0x69, 0x63, 0x68, 0x61, 0x6d,
+0x74, 0x68, 0x69, 0x41f, 0x41c, 0x63, 0x25b, 0x25b, 0x301, 0x6e, 0x6b, 0x6f,
+0x49, 0x20, 0x253, 0x75, 0x67, 0x61, 0x6a, 0x254, 0x70, 0x61, 0x6b, 0x61,
+0x73, 0x75, 0x62, 0x61, 0x70, 0x61, 0x6d, 0x75, 0x6e, 0x79, 0x69, 0x938,
+0x93e, 0x902, 0x91d, 0x92c, 0x947, 0x932, 0x93e, 0x938, 0x947, 0x70, 0x6f, 0x70,
+0x6f, 0x64, 0x6e, 0x65, 0x43f, 0x43e, 0x441, 0x43b, 0x438, 0x458, 0x435, 0x20,
+0x43f, 0x43e, 0x434, 0x43d, 0x435, 0x47, 0x2e, 0x4d, 0x2e, 0x441, 0x43b, 0x2e,
+0x43e, 0x431, 0x2e, 0x100a, 0x1014, 0x1031, 0x4e0b, 0x5348, 0x70, 0x2e, 0xa0, 0x6d,
+0x2e, 0x1e0c, 0x65, 0x66, 0x66, 0x69, 0x72, 0x20, 0x61, 0x7a, 0x61, 0x62f,
+0x2e, 0x646, 0x13d2, 0x13af, 0x13f1, 0x13a2, 0x13d7, 0x13e2, 0x55, 0x68, 0x72, 0x20,
+0x6e, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x61, 0x61, 0x63, 0x68, 0x73,
+0x70, 0x2e, 0x6d, 0x2e, 0x6f, 0x64, 0x70, 0x2e, 0x926, 0x92a, 0x948, 0x939,
+0x930, 0x20, 0x92c, 0x93e, 0x926, 0x65, 0x62, 0x79, 0xe1, 0x6d, 0x75, 0xf55,
+0xfb1, 0xf72, 0xf0b, 0xf46, 0xf0b, 0x55, 0x54, 0xd801, 0xdc11, 0xd801, 0xdc23, 0x70,
+0x6d, 0xd801, 0xdc50, 0xd801, 0xdc65, 0x70, 0x74, 0x6d, 0x263, 0x65, 0x74, 0x72,
+0x254, 0x6e, 0x67, 0x259, 0x67, 0xf3, 0x67, 0x259, 0x6c, 0x65, 0x69, 0x70,
+0x2e, 0x73, 0x6f, 0x69, 0x72, 0x6b, 0x69, 0x6b, 0x69, 0x69, 0x257, 0x65,
+0xd83a, 0xdd07, 0xd83a, 0xdd0e, 0x3bc, 0x2e, 0x3bc, 0x2e, 0x4d, 0x6f, 0x67, 0x59,
+0x61, 0x6d, 0x6d, 0x61, 0x5d0, 0x5d7, 0x5d4, 0x5f4, 0x5e6, 0x64, 0x75, 0x2e,
+0x65, 0x2e, 0x68, 0x2e, 0x4e, 0x2019, 0x61, 0x62, 0x61, 0x6c, 0x69, 0x65,
+0x70, 0x2e, 0x70, 0x6f, 0x73, 0x20, 0x6d, 0x69, 0x64, 0xed, 0x69, 0x2e,
+0x6e, 0x2e, 0x5348, 0x5f8c, 0x57, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x20, 0x74,
+0x6d, 0x65, 0x64, 0x64, 0x69, 0x74, 0x6b, 0x6f, 0x6f, 0x73, 0x6b, 0x6f,
+0x6c, 0x69, 0x6e, 0x79, 0x128, 0x79, 0x61, 0x77, 0x129, 0x6f, 0x6f, 0xc85,
+0xcaa, 0xcb0, 0xcbe, 0xcb9, 0xccd, 0xca8, 0x67e, 0x6cc, 0x20, 0x627, 0x6cc, 0x645,
+0x92a, 0x940, 0x20, 0x90f, 0x92e, 0x48, 0x77, 0x61, 0x129, 0x2d, 0x69, 0x6e,
+0x129, 0x938, 0x93e, 0x902, 0x91c, 0xc624, 0xd6c4, 0x41, 0x6c, 0x75, 0x75, 0x6c,
+0x61, 0x50, 0x4e, 0x6b, 0x75, 0x67, 0xfa, 0x442, 0x4af, 0x448, 0x442, 0x4e9,
+0x43d, 0x20, 0x43a, 0x438, 0x439, 0x438, 0x43d, 0x43a, 0x438, 0x4d, 0x55, 0x55,
+0xeab, 0xebc, 0xeb1, 0xe87, 0xe97, 0xec8, 0xebd, 0xe87, 0x70, 0x113, 0x63, 0x70,
+0x75, 0x73, 0x64, 0x69, 0x65, 0x6e, 0x101, 0x6d, 0x70, 0xf3, 0x6b, 0x77,
+0x61, 0x70, 0x6f, 0x70, 0x69, 0x65, 0x74, 0x77, 0xf3, 0x74, 0x70, 0x6f,
+0x142, 0x64, 0x6e, 0x6a, 0x61, 0x44, 0x69, 0x6c, 0x6f, 0x6c, 0x6f, 0x4f,
+0x54, 0x6e, 0x6f, 0x6d, 0xeb, 0x74, 0x74, 0x65, 0x73, 0x43f, 0x43e, 0x43f,
+0x43b, 0x2e, 0x6b, 0x79, 0x69, 0x75, 0x6b, 0x6f, 0x6e, 0x79, 0x69, 0x6d,
+0x63, 0x68, 0x6f, 0x63, 0x68, 0x69, 0x6c, 0x2019, 0x6c, 0x43, 0x68, 0x69,
+0x6c, 0x6f, 0x50, 0x54, 0x47, 0x9aa, 0x9bf, 0x20, 0x98f, 0x9ae, 0x190, 0x6e,
+0x64, 0xe1, 0x6d, 0xe2, 0x168, 0x47, 0x4af, 0x2e, 0x445, 0x2e, 0x1826, 0x1802,
+0x20, 0x182c, 0x1823, 0x6c, 0x69, 0x6c, 0x6c, 0x69, 0x1c3, 0x75, 0x69, 0x61,
+0x73, 0x905, 0x92a, 0x930, 0x93e, 0x939, 0x94d, 0x928, 0x6e, 0x63, 0x77, 0xf2,
+0x6e, 0x7a, 0xe9, 0x6d, 0x14b, 0x6b, 0x61, 0x20, 0x6d, 0x62, 0x254, 0x301,
+0x74, 0x20, 0x6e, 0x6a, 0x69, 0x46, 0x1ecd, 0x20, 0xed, 0x76, 0x6e, 0x69,
+0x6e, 0x7e5, 0x65, 0x61, 0x68, 0x6b, 0x65, 0x74, 0x62, 0x65, 0x61, 0x69,
+0x76, 0x65, 0x74, 0x65, 0x2e, 0x6d, 0x2e, 0x54, 0x14a, 0x57, 0x42, 0x4d5,
+0x43c, 0x431, 0x438, 0x441, 0x431, 0x43e, 0x43d, 0x44b, 0x20, 0x444, 0x4d5, 0x441,
+0x442, 0x4d5, 0x63a, 0x2e, 0x648, 0x2e, 0x628, 0x639, 0x62f, 0x627, 0x632, 0x638,
+0x647, 0x631, 0x64, 0x61, 0x20, 0x74, 0x61, 0x72, 0x64, 0x65, 0x70, 0x61,
+0x20, 0x70, 0x75, 0x73, 0x73, 0x69, 0x64, 0x65, 0x69, 0x6e, 0x61, 0x6e,
+0xa2c, 0xa3e, 0x2e, 0xa26, 0xa41, 0x2e, 0x6b, 0x69, 0x6e, 0x67, 0x6f, 0x74,
+0x6f, 0x5a, 0x2e, 0x4d, 0x57, 0x2e, 0x42d, 0x41a, 0x54, 0x65, 0x69, 0x70,
+0x61, 0x4c, 0x4b, 0x50, 0x61, 0x73, 0x68, 0x61, 0x6d, 0x69, 0x68, 0x65,
+0x1c67, 0x1c64, 0x1c6b, 0x1c5f, 0x1c79, 0x43f, 0x43e, 0x20, 0x43f, 0x43e, 0x434, 0x43d,
+0x435, 0x70, 0x6f, 0x20, 0x70, 0x6f, 0x64, 0x6e, 0x65, 0x6e, 0x79, 0x69,
+0x61, 0x67, 0x68, 0x75, 0x6f, 0xa06f, 0xa2d2, 0x70, 0x6f, 0x20, 0x70, 0x6f,
+0x142, 0x65, 0x64, 0x6e, 0x69, 0x75, 0x645, 0x646, 0x62c, 0x647, 0x646, 0x62f,
+0x60c, 0x20, 0x634, 0x627, 0x645, 0x936, 0x93e, 0x92e, 0x20, 0x91c, 0x93e, 0xdb4,
+0x2e, 0xdc0, 0x2e, 0x70, 0x6f, 0x70, 0x2e, 0x45, 0x69, 0x67, 0x75, 0x6c,
+0x6f, 0x47, 0x44, 0x2d5c, 0x2d30, 0x2d37, 0x2d33, 0x2d33, 0x2d6f, 0x2d30, 0x2d5c, 0x65,
+0x6d, 0x61, 0x6d, 0x20, 0x4e, 0x61, 0x6d, 0x69, 0x74, 0x74, 0x61, 0x67,
+0x70f, 0x712, 0x71b, 0x200c, 0x74, 0x61, 0x64, 0x67, 0x67, 0x2b7, 0x61, 0x74,
+0x6c, 0x75, 0x6d, 0x61, 0x20, 0x6c, 0x77, 0x61, 0x20, 0x70, 0xbaa, 0xbbf,
+0xbb1, 0xbcd, 0xbaa, 0xb95, 0xbb2, 0xbcd, 0x5a, 0x61, 0x61, 0x72, 0x69, 0x6b,
+0x61, 0x79, 0x20, 0x62, 0x45, 0x62, 0x6f, 0x6e, 0x67, 0x69, 0xe2b, 0xe25,
+0xe31, 0xe07, 0xe40, 0xe17, 0xe35, 0xe48, 0xe22, 0xe07, 0xf55, 0xfb1, 0xf72, 0xf0b,
+0xf51, 0xfb2, 0xf7c, 0xf0b, 0x12f5, 0x2e, 0x1240, 0x2e, 0x65, 0x66, 0x69, 0x61,
+0x66, 0x69, 0xd6, 0x53, 0x67, 0xfc, 0x6e, 0x6f, 0x72, 0x74, 0x61, 0x64,
+0x61, 0x6e, 0x20, 0x73, 0x6f, 0x148, 0x43f, 0x43f, 0x70, 0x6f, 0x70, 0x6f,
+0x142, 0x64, 0x6e, 0x6a, 0x75, 0x686, 0x6c8, 0x634, 0x62a, 0x649, 0x646, 0x20,
+0x643, 0x6d0, 0x64a, 0x649, 0x646, 0x54, 0x4b, 0x422, 0x41a, 0x43, 0x48, 0x79,
+0x68, 0x4e, 0x67, 0x6f, 0x6b, 0x69, 0x73, 0x25b, 0x301, 0x6e, 0x64, 0x25b,
+0x5e0, 0x5d0, 0x5b8, 0x5db, 0x5de, 0x5d9, 0x5d8, 0x5d0, 0x5b8, 0x5d2, 0x1ecc, 0x300,
+0x73, 0xe1, 0x6e, 0x186, 0x300, 0x73, 0xe1, 0x6e, 0x62, 0x61, 0x6e, 0x72,
+0x69, 0x6e, 0x67, 0x7a, 0x67, 0x76, 0x61, 0x71, 0x938, 0x93e, 0x902, 0x92e,
+0x70, 0x69, 0x20, 0x70, 0x69, 0x6e, 0x69, 0x20, 0x73, 0x75, 0x6e, 0x6f,
+0x28a, 0x73, 0x68, 0x69, 0x6c, 0xe8, 0x20, 0x6b, 0x28a, 0x73, 0x61, 0x73,
+0x28a, 0x926, 0x92a, 0x947, 0x939, 0x930, 0x93e, 0x2f, 0x938, 0x902, 0x91c, 0x93e
};
static constexpr char16_t currency_symbol_data[] = {
-0x20be, 0x52, 0x24, 0x46, 0x43, 0x46, 0x41, 0x47, 0x48, 0x20b5, 0x4c, 0x65, 0x6b, 0xeb, 0x20ac, 0x64, 0x65, 0x6e, 0x1265, 0x122d,
-0x62c, 0x2e, 0x645, 0x2e, 0x200f, 0x62f, 0x2e, 0x62c, 0x2e, 0x200f, 0x62f, 0x2e, 0x628, 0x2e, 0x200f, 0x46, 0x64, 0x6a, 0x4e, 0x66,
-0x6b, 0x62f, 0x2e, 0x639, 0x2e, 0x200f, 0x20aa, 0x62f, 0x2e, 0x623, 0x2e, 0x200f, 0x62f, 0x2e, 0x643, 0x2e, 0x200f, 0x644, 0x2e, 0x644,
-0x2e, 0x200f, 0x62f, 0x2e, 0x644, 0x2e, 0x200f, 0x623, 0x2e, 0x645, 0x2e, 0x62f, 0x2e, 0x645, 0x2e, 0x200f, 0x631, 0x2e, 0x639, 0x2e,
-0x200f, 0x631, 0x2e, 0x642, 0x2e, 0x200f, 0x631, 0x2e, 0x633, 0x2e, 0x200f, 0x53, 0xa3, 0x62c, 0x2e, 0x633, 0x2e, 0x644, 0x2e, 0x633,
-0x2e, 0x200f, 0x62f, 0x2e, 0x62a, 0x2e, 0x200f, 0x62f, 0x2e, 0x625, 0x2e, 0x200f, 0x631, 0x2e, 0x64a, 0x2e, 0x200f, 0x58f, 0x20b9, 0x54,
-0x53, 0x68, 0x20a6, 0x20bc, 0x46, 0x202f, 0x43, 0x46, 0x41, 0x9f3, 0x20bd, 0x42, 0x72, 0x4b, 0x4b, 0x4d, 0x41a, 0x41c, 0x43b, 0x432,
-0x2e, 0x48, 0x4b, 0x24, 0xffe5, 0x20b1, 0x55, 0x53, 0x24, 0x55, 0x53, 0x68, 0xa5, 0x4d, 0x4f, 0x50, 0x24, 0x4b, 0x10d, 0x6b,
-0x72, 0x2e, 0x41, 0x66, 0x6c, 0x2e, 0x4e, 0x41, 0x66, 0x2e, 0x4e, 0x75, 0x2e, 0x4b, 0x73, 0x68, 0x46, 0x42, 0x75, 0x45,
-0x44, 0x41, 0x72, 0x4d, 0x4b, 0x52, 0x4d, 0x52, 0x66, 0x52, 0x73, 0x52, 0x46, 0x57, 0x53, 0x24, 0x53, 0x52, 0x54, 0x24,
-0x41, 0x45, 0x44, 0x56, 0x54, 0x46, 0x43, 0x46, 0x50, 0x46, 0x47, 0x55, 0x4d, 0x4d, 0x41, 0x44, 0x43, 0x48, 0x46, 0x4c,
-0x53, 0x44, 0x54, 0xd83a, 0xdd05, 0xd83a, 0xdd0a, 0xd83a, 0xdd00, 0xd83a, 0xdd0a, 0xd83a, 0xdd05, 0xd83a, 0xdd0a, 0xd83a, 0xdd00, 0x20b2, 0x46, 0x74,
-0x52, 0x70, 0x43, 0x41, 0x24, 0x200b, 0x20b8, 0x17db, 0x51, 0x20a9, 0x4b, 0x50, 0x57, 0x20ba, 0x441, 0x43e, 0x43c, 0x20ad, 0x4b, 0x7a,
-0x434, 0x435, 0x43d, 0x2e, 0x4d, 0x54, 0x6e, 0x49, 0x52, 0x52, 0x20ae, 0x43, 0x4e, 0xa5, 0x928, 0x947, 0x930, 0x942, 0x60b, 0x631,
-0x6cc, 0x627, 0x644, 0x7a, 0x142, 0x44, 0x62, 0x53, 0x2f, 0x42, 0x73, 0x52, 0x4f, 0x4e, 0x20b4, 0x52, 0x53, 0x44, 0xdbb, 0xdd4,
-0x2e, 0x20a1, 0x52, 0x44, 0x24, 0x43, 0x24, 0x42, 0x2f, 0x2e, 0x47, 0x73, 0x2e, 0x42, 0x73, 0x2e, 0x53, 0x20ab, 0x441, 0x43e,
-0x43c, 0x2e, 0x52, 0x73, 0x2e, 0x4e, 0x54, 0x24, 0xe3f, 0x54, 0x4d, 0x54, 0x73, 0x6f, 0x2bb, 0x6d, 0x441, 0x45e, 0x43c
+0x20be, 0x42, 0x72, 0x46, 0x64, 0x6a, 0x4e, 0x66, 0x6b, 0x52, 0x24, 0x46,
+0x43, 0x46, 0x41, 0x47, 0x48, 0x20b5, 0x4c, 0x65, 0x6b, 0xeb, 0x20ac, 0x64,
+0x65, 0x6e, 0x1265, 0x122d, 0x62c, 0x2e, 0x645, 0x2e, 0x200f, 0x62f, 0x2e, 0x62c,
+0x2e, 0x200f, 0x62f, 0x2e, 0x628, 0x2e, 0x200f, 0x62f, 0x2e, 0x639, 0x2e, 0x200f,
+0x20aa, 0x62f, 0x2e, 0x623, 0x2e, 0x200f, 0x62f, 0x2e, 0x643, 0x2e, 0x200f, 0x644,
+0x2e, 0x644, 0x2e, 0x200f, 0x62f, 0x2e, 0x644, 0x2e, 0x200f, 0x623, 0x2e, 0x645,
+0x2e, 0x62f, 0x2e, 0x645, 0x2e, 0x200f, 0x631, 0x2e, 0x639, 0x2e, 0x200f, 0x631,
+0x2e, 0x642, 0x2e, 0x200f, 0x631, 0x2e, 0x633, 0x2e, 0x200f, 0x53, 0xa3, 0x62c,
+0x2e, 0x633, 0x2e, 0x644, 0x2e, 0x633, 0x2e, 0x200f, 0x62f, 0x2e, 0x62a, 0x2e,
+0x200f, 0x62f, 0x2e, 0x625, 0x2e, 0x200f, 0x631, 0x2e, 0x64a, 0x2e, 0x200f, 0x58f,
+0x20b9, 0x54, 0x53, 0x68, 0x20a6, 0x20bc, 0x20ba, 0x46, 0x202f, 0x43, 0x46, 0x41,
+0x9f3, 0x20bd, 0x4b, 0x4b, 0x4d, 0x41a, 0x41c, 0x43b, 0x432, 0x2e, 0x48, 0x4b,
+0x24, 0xffe5, 0x20b1, 0x55, 0x53, 0x68, 0xa5, 0x4d, 0x4f, 0x50, 0x24, 0x45,
+0x55, 0x52, 0x4b, 0x10d, 0x6b, 0x72, 0x2e, 0x783, 0x2e, 0x41, 0x66, 0x6c,
+0x2e, 0x4e, 0x41, 0x66, 0x2e, 0x4e, 0x75, 0x2e, 0x4b, 0x73, 0x68, 0x55,
+0x53, 0x24, 0x46, 0x42, 0x75, 0x44, 0x52, 0x70, 0x41, 0x72, 0x4d, 0x4b,
+0x52, 0x4d, 0x52, 0x66, 0x52, 0x73, 0x52, 0x46, 0x57, 0x53, 0x24, 0x53,
+0x52, 0x54, 0x24, 0x56, 0x54, 0x44, 0x41, 0x46, 0x43, 0x46, 0x50, 0x46,
+0x47, 0x55, 0x4d, 0x4c, 0x53, 0x44, 0x54, 0xd83a, 0xdd05, 0xd83a, 0xdd0a, 0xd83a,
+0xdd00, 0xd83a, 0xdd0a, 0xd83a, 0xdd05, 0xd83a, 0xdd0a, 0xd83a, 0xdd00, 0x20b2, 0x46, 0x74,
+0x43, 0x41, 0x24, 0x200b, 0x20b8, 0x17db, 0x51, 0x20a9, 0x43, 0x4e, 0xa5, 0x441,
+0x43e, 0x43c, 0x20ad, 0x4b, 0x7a, 0x434, 0x435, 0x43d, 0x2e, 0x4d, 0x54, 0x6e,
+0x20ae, 0x928, 0x947, 0x930, 0x942, 0x7ff, 0x60b, 0x631, 0x6cc, 0x627, 0x644, 0x7a,
+0x142, 0x44, 0x62, 0x53, 0x2f, 0x42, 0x73, 0x6c, 0x65, 0x69, 0x20b4, 0xdbb,
+0xdd4, 0x2e, 0x20a1, 0x52, 0x44, 0x24, 0x43, 0x24, 0x42, 0x2f, 0x2e, 0x47,
+0x73, 0x2e, 0x42, 0x73, 0x2e, 0x53, 0x20ab, 0x441, 0x43e, 0x43c, 0x2e, 0x52,
+0x73, 0x2e, 0x4e, 0x54, 0x24, 0xe3f, 0x73, 0x6f, 0x2bb, 0x6d, 0x441, 0x45e,
+0x43c
};
static constexpr char16_t currency_display_name_data[] = {
-0x53, 0x75, 0x69, 0x64, 0x2d, 0x41, 0x66, 0x72, 0x69, 0x6b, 0x61, 0x61, 0x6e, 0x73, 0x65, 0x20, 0x72, 0x61, 0x6e, 0x64,
-0x4e, 0x61, 0x6d, 0x69, 0x62, 0x69, 0x65, 0x73, 0x65, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x43, 0x46, 0x41, 0x20,
-0x46, 0xe0, 0x6c, 0xe2, 0x14b, 0x20, 0x42, 0x45, 0x41, 0x43, 0x47, 0x68, 0x61, 0x6e, 0x61, 0x20, 0x53, 0x69, 0x64, 0x69,
-0x4c, 0x65, 0x6b, 0x75, 0x20, 0x73, 0x68, 0x71, 0x69, 0x70, 0x74, 0x61, 0x72, 0x45, 0x75, 0x72, 0x6f, 0x6a, 0x61, 0x44,
-0x65, 0x6e, 0x61, 0x72, 0x69, 0x20, 0x6d, 0x61, 0x71, 0x65, 0x64, 0x6f, 0x6e, 0x61, 0x73, 0x12e8, 0x12a2, 0x1275, 0x12ee, 0x1335,
-0x12eb, 0x20, 0x1265, 0x122d, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x645, 0x635, 0x631, 0x64a, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x62c,
-0x632, 0x627, 0x626, 0x631, 0x64a, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x628, 0x62d, 0x631, 0x64a, 0x646, 0x64a, 0x641, 0x631, 0x646,
-0x643, 0x20, 0x648, 0x633, 0x637, 0x20, 0x623, 0x641, 0x631, 0x64a, 0x642, 0x64a, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x632, 0x631,
-0x20, 0x627, 0x644, 0x642, 0x645, 0x631, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c, 0x64a, 0x628, 0x648, 0x62a, 0x64a, 0x646, 0x627, 0x643,
-0x641, 0x627, 0x20, 0x623, 0x631, 0x64a, 0x62a, 0x631, 0x64a, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x639, 0x631, 0x627, 0x642, 0x64a,
-0x634, 0x64a, 0x643, 0x644, 0x20, 0x625, 0x633, 0x631, 0x627, 0x626, 0x64a, 0x644, 0x64a, 0x20, 0x62c, 0x62f, 0x64a, 0x62f, 0x62f, 0x64a,
-0x646, 0x627, 0x631, 0x20, 0x623, 0x631, 0x62f, 0x646, 0x64a, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x643, 0x648, 0x64a, 0x62a, 0x64a,
-0x62c, 0x646, 0x64a, 0x647, 0x20, 0x644, 0x628, 0x646, 0x627, 0x646, 0x64a, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x644, 0x64a, 0x628,
-0x64a, 0x623, 0x648, 0x642, 0x64a, 0x629, 0x20, 0x645, 0x648, 0x631, 0x64a, 0x62a, 0x627, 0x646, 0x64a, 0x629, 0x62f, 0x631, 0x647, 0x645,
-0x20, 0x645, 0x63a, 0x631, 0x628, 0x64a, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x639, 0x645, 0x627, 0x646, 0x64a, 0x631, 0x64a, 0x627, 0x644,
-0x20, 0x642, 0x637, 0x631, 0x64a, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x633, 0x639, 0x648, 0x62f, 0x64a, 0x634, 0x644, 0x646, 0x20, 0x635,
-0x648, 0x645, 0x627, 0x644, 0x64a, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x62c, 0x646, 0x648, 0x628, 0x20, 0x627, 0x644, 0x633, 0x648, 0x62f,
-0x627, 0x646, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x633, 0x648, 0x62f, 0x627, 0x646, 0x64a, 0x644, 0x64a, 0x631, 0x629, 0x20, 0x633, 0x648,
-0x631, 0x64a, 0x629, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x62a, 0x648, 0x646, 0x633, 0x64a, 0x62f, 0x631, 0x647, 0x645, 0x20, 0x625,
-0x645, 0x627, 0x631, 0x627, 0x62a, 0x64a, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x64a, 0x645, 0x646, 0x64a, 0x570, 0x561, 0x575, 0x56f, 0x561,
-0x56f, 0x561, 0x576, 0x20, 0x564, 0x580, 0x561, 0x574, 0x9ad, 0x9be, 0x9f0, 0x9a4, 0x9c0, 0x9af, 0x9bc, 0x20, 0x9f0, 0x9c1, 0x9aa, 0x9c0,
-0x65, 0x75, 0x72, 0x6f, 0x73, 0x68, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x69, 0x20, 0x79, 0x61, 0x20, 0x54, 0x61, 0x6e, 0x64,
-0x68, 0x61, 0x6e, 0x69, 0x61, 0x41, 0x7a, 0x259, 0x72, 0x62, 0x61, 0x79, 0x63, 0x61, 0x6e, 0x20, 0x4d, 0x61, 0x6e, 0x61,
-0x74, 0x131, 0x43c, 0x430, 0x43d, 0x430, 0x442, 0x66, 0x72, 0xe1, 0x14b, 0x73, 0x65, 0x66, 0x61, 0x20, 0x46, 0x72, 0x61, 0x14b,
-0x20, 0x28, 0x42, 0x43, 0x45, 0x41, 0x4f, 0x29, 0x9ac, 0x9be, 0x982, 0x9b2, 0x9be, 0x9a6, 0x9c7, 0x9b6, 0x9c0, 0x20, 0x99f, 0x9be,
-0x995, 0x9be, 0x9ad, 0x9be, 0x9b0, 0x9a4, 0x9c0, 0x9af, 0x9bc, 0x20, 0x9b0, 0x9c1, 0x9aa, 0x9bf, 0x46, 0x72, 0x1ce, 0x14b, 0x20, 0x43,
-0x46, 0x41, 0x20, 0x28, 0x42, 0x45, 0x41, 0x43, 0x29, 0x65, 0x75, 0x72, 0x6f, 0x61, 0x431, 0x435, 0x43b, 0x430, 0x440, 0x443,
-0x441, 0x43a, 0x456, 0x20, 0x440, 0x443, 0x431, 0x435, 0x43b, 0x44c, 0x53, 0x68, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x69, 0x20, 0x79,
-0x61, 0x20, 0x48, 0x75, 0x74, 0x61, 0x6e, 0x7a, 0x61, 0x6e, 0x69, 0x61, 0x92d, 0x93e, 0x930, 0x924, 0x928, 0x93f, 0x20, 0x930,
-0x941, 0x92a, 0x940, 0x42, 0x6f, 0x73, 0x61, 0x6e, 0x73, 0x6b, 0x6f, 0x68, 0x65, 0x72, 0x63, 0x65, 0x67, 0x6f, 0x76, 0x61,
-0x10d, 0x6b, 0x61, 0x20, 0x6b, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x69, 0x62, 0x69, 0x6c, 0x6e, 0x61, 0x20, 0x6d, 0x61,
-0x72, 0x6b, 0x61, 0x41a, 0x43e, 0x43d, 0x432, 0x435, 0x440, 0x442, 0x438, 0x431, 0x438, 0x43b, 0x43d, 0x430, 0x20, 0x43c, 0x430, 0x440,
-0x43a, 0x430, 0x411, 0x44a, 0x43b, 0x433, 0x430, 0x440, 0x441, 0x43a, 0x438, 0x20, 0x43b, 0x435, 0x432, 0x1019, 0x103c, 0x1014, 0x103a, 0x1019,
-0x102c, 0x20, 0x1000, 0x103b, 0x1015, 0x103a, 0x6e2f, 0x5e63, 0x4eba, 0x6c11, 0x5e01, 0x50, 0x68, 0x69, 0x6c, 0x69, 0x70, 0x70, 0x69, 0x6e,
-0x65, 0x20, 0x50, 0x65, 0x73, 0x6f, 0x44, 0x65, 0x72, 0x68, 0x65, 0x6d, 0x20, 0x55, 0x6d, 0x65, 0x1e5b, 0x1e5b, 0x75, 0x6b,
-0x69, 0x62f, 0x6cc, 0x646, 0x627, 0x631, 0x6cc, 0x20, 0x639, 0x6ce, 0x631, 0x627, 0x642, 0x6cc, 0x695, 0x6cc, 0x627, 0x6b5, 0x6cc, 0x20,
-0x626, 0x6ce, 0x631, 0x627, 0x646, 0x6cc, 0xd804, 0xdd1d, 0xd804, 0xdd01, 0xd804, 0xdd23, 0xd804, 0xdd18, 0xd804, 0xdd2c, 0xd804, 0xdd25, 0xd804, 0xdd28,
-0x20, 0xd804, 0xdd11, 0xd804, 0xdd2c, 0xd804, 0xdd0b, 0xd804, 0xdd03, 0xd804, 0xdd28, 0xd804, 0xdd1a, 0xd804, 0xdd34, 0xd804, 0xdd18, 0xd804, 0xdd28, 0xd804,
-0xdd20, 0xd804, 0xdd1a, 0xd804, 0xdd34, 0x20, 0xd804, 0xdd22, 0xd804, 0xdd2a, 0xd804, 0xdd1b, 0xd804, 0xdd28, 0x420, 0x43e, 0x441, 0x441, 0x438, 0x439,
-0x43d, 0x20, 0x441, 0x43e, 0x43c, 0x55, 0x53, 0x20, 0x13a0, 0x13d5, 0x13b3, 0x45, 0x73, 0x68, 0x69, 0x72, 0x69, 0x6e, 0x67, 0x69,
-0x20, 0x79, 0x61, 0x20, 0x55, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x6e2f, 0x5143, 0x6fb3, 0x95e8, 0x5e01, 0x65b0, 0x52a0, 0x5761, 0x5143, 0x6fb3,
-0x9580, 0x5143, 0x65b0, 0x53f0, 0x5e63, 0x420, 0x430, 0x4ab, 0x4ab, 0x435, 0x439, 0x20, 0x442, 0x435, 0x43d, 0x43a, 0x4d7, 0x10d, 0x65, 0x73,
-0x6b, 0xe1, 0x20, 0x6b, 0x6f, 0x72, 0x75, 0x6e, 0x61, 0x64, 0x61, 0x6e, 0x73, 0x6b, 0x20, 0x6b, 0x72, 0x6f, 0x6e, 0x65,
-0x92d, 0x93e, 0x930, 0x924, 0x940, 0x20, 0x930, 0x92a, 0x947, 0x93d, 0x41, 0x72, 0x75, 0x62, 0x61, 0x61, 0x6e, 0x73, 0x65, 0x20,
-0x67, 0x75, 0x6c, 0x64, 0x65, 0x6e, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x6b, 0x61, 0x61, 0x6e, 0x73, 0x65, 0x20, 0x64, 0x6f,
-0x6c, 0x6c, 0x61, 0x72, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x2d, 0x41, 0x6e, 0x74, 0x69, 0x6c,
-0x6c, 0x69, 0x61, 0x61, 0x6e, 0x73, 0x65, 0x20, 0x67, 0x75, 0x6c, 0x64, 0x65, 0x6e, 0x53, 0x75, 0x72, 0x69, 0x6e, 0x61,
-0x61, 0x6d, 0x73, 0x65, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0xf51, 0xf44, 0xf74, 0xf63, 0xf0b, 0xf40, 0xfb2, 0xf58, 0x53,
-0x68, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x69, 0x20, 0x79, 0x61, 0x20, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x55, 0x53, 0x20, 0x44,
-0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x45, 0x61, 0x73, 0x74, 0x20, 0x43, 0x61, 0x72, 0x69, 0x62, 0x62, 0x65, 0x61, 0x6e, 0x20,
-0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c,
-0x6c, 0x61, 0x72, 0x42, 0x61, 0x68, 0x61, 0x6d, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x42, 0x61,
-0x72, 0x62, 0x61, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x42, 0x65, 0x6c, 0x69, 0x7a, 0x65,
-0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x42, 0x65, 0x72, 0x6d, 0x75, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c,
-0x6c, 0x61, 0x72, 0x42, 0x6f, 0x74, 0x73, 0x77, 0x61, 0x6e, 0x61, 0x6e, 0x20, 0x50, 0x75, 0x6c, 0x61, 0x42, 0x75, 0x72,
-0x75, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20,
-0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x6e, 0x20, 0x43, 0x46, 0x41, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x43, 0x61, 0x6e,
-0x61, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x43, 0x61, 0x79, 0x6d, 0x61, 0x6e, 0x20, 0x49,
-0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x4e, 0x65, 0x77, 0x20, 0x5a, 0x65, 0x61,
-0x6c, 0x61, 0x6e, 0x64, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x44, 0x61, 0x6e, 0x69, 0x73, 0x68, 0x20, 0x4b, 0x72,
-0x6f, 0x6e, 0x65, 0x45, 0x72, 0x69, 0x74, 0x72, 0x65, 0x61, 0x6e, 0x20, 0x4e, 0x61, 0x6b, 0x66, 0x61, 0x53, 0x77, 0x61,
-0x7a, 0x69, 0x20, 0x4c, 0x69, 0x6c, 0x61, 0x6e, 0x67, 0x65, 0x6e, 0x69, 0x46, 0x61, 0x6c, 0x6b, 0x6c, 0x61, 0x6e, 0x64,
-0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x50, 0x6f, 0x75, 0x6e, 0x64, 0x46, 0x69, 0x6a, 0x69, 0x61, 0x6e,
-0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x47, 0x61, 0x6d, 0x62, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x61, 0x6c, 0x61, 0x73,
-0x69, 0x47, 0x68, 0x61, 0x6e, 0x61, 0x69, 0x61, 0x6e, 0x20, 0x43, 0x65, 0x64, 0x69, 0x47, 0x69, 0x62, 0x72, 0x61, 0x6c,
-0x74, 0x61, 0x72, 0x20, 0x50, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x4b, 0x20, 0x50, 0x6f, 0x75, 0x6e, 0x64, 0x47, 0x75, 0x79,
-0x61, 0x6e, 0x61, 0x65, 0x73, 0x65, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x48, 0x6f, 0x6e, 0x67, 0x20, 0x4b, 0x6f,
-0x6e, 0x67, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x52, 0x75, 0x70, 0x65,
-0x65, 0x49, 0x73, 0x72, 0x61, 0x65, 0x6c, 0x69, 0x20, 0x4e, 0x65, 0x77, 0x20, 0x53, 0x68, 0x65, 0x6b, 0x65, 0x6c, 0x4a,
-0x61, 0x6d, 0x61, 0x69, 0x63, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x6e,
-0x20, 0x53, 0x68, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x41, 0x66, 0x72, 0x69, 0x63,
-0x61, 0x6e, 0x20, 0x52, 0x61, 0x6e, 0x64, 0x4c, 0x69, 0x62, 0x65, 0x72, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c,
-0x61, 0x72, 0x4d, 0x61, 0x63, 0x61, 0x6e, 0x65, 0x73, 0x65, 0x20, 0x50, 0x61, 0x74, 0x61, 0x63, 0x61, 0x4d, 0x61, 0x6c,
-0x61, 0x67, 0x61, 0x73, 0x79, 0x20, 0x41, 0x72, 0x69, 0x61, 0x72, 0x79, 0x4d, 0x61, 0x6c, 0x61, 0x77, 0x69, 0x61, 0x6e,
-0x20, 0x4b, 0x77, 0x61, 0x63, 0x68, 0x61, 0x4d, 0x61, 0x6c, 0x61, 0x79, 0x73, 0x69, 0x61, 0x6e, 0x20, 0x52, 0x69, 0x6e,
-0x67, 0x67, 0x69, 0x74, 0x4d, 0x61, 0x6c, 0x64, 0x69, 0x76, 0x69, 0x61, 0x6e, 0x20, 0x52, 0x75, 0x66, 0x69, 0x79, 0x61,
-0x61, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x69, 0x61, 0x6e, 0x20, 0x52, 0x75, 0x70, 0x65, 0x65, 0x4e, 0x61, 0x6d, 0x69,
-0x62, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x4e, 0x69, 0x67, 0x65, 0x72, 0x69, 0x61, 0x6e, 0x20,
-0x4e, 0x61, 0x69, 0x72, 0x61, 0x50, 0x61, 0x6b, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x69, 0x20, 0x52, 0x75, 0x70, 0x65, 0x65,
-0x50, 0x61, 0x70, 0x75, 0x61, 0x20, 0x4e, 0x65, 0x77, 0x20, 0x47, 0x75, 0x69, 0x6e, 0x65, 0x61, 0x6e, 0x20, 0x4b, 0x69,
-0x6e, 0x61, 0x52, 0x77, 0x61, 0x6e, 0x64, 0x61, 0x6e, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x53, 0x74, 0x20, 0x48, 0x65,
-0x6c, 0x65, 0x6e, 0x61, 0x20, 0x50, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x61, 0x6d, 0x6f, 0x61, 0x6e, 0x20, 0x54, 0x61, 0x6c,
-0x61, 0x53, 0x65, 0x79, 0x63, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x69, 0x73, 0x20, 0x52, 0x75, 0x70, 0x65, 0x65, 0x53, 0x69,
-0x65, 0x72, 0x72, 0x61, 0x20, 0x4c, 0x65, 0x6f, 0x6e, 0x65, 0x61, 0x6e, 0x20, 0x4c, 0x65, 0x6f, 0x6e, 0x65, 0x53, 0x69,
-0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x4e, 0x65, 0x74, 0x68, 0x65, 0x72,
-0x6c, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x41, 0x6e, 0x74, 0x69, 0x6c, 0x6c, 0x65, 0x61, 0x6e, 0x20, 0x47, 0x75, 0x69, 0x6c,
-0x64, 0x65, 0x72, 0x53, 0x6f, 0x6c, 0x6f, 0x6d, 0x6f, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x44,
-0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x53, 0x75, 0x64, 0x61, 0x6e, 0x65, 0x73, 0x65, 0x20,
-0x50, 0x6f, 0x75, 0x6e, 0x64, 0x53, 0x75, 0x64, 0x61, 0x6e, 0x65, 0x73, 0x65, 0x20, 0x50, 0x6f, 0x75, 0x6e, 0x64, 0x53,
-0x77, 0x65, 0x64, 0x69, 0x73, 0x68, 0x20, 0x4b, 0x72, 0x6f, 0x6e, 0x61, 0x53, 0x77, 0x69, 0x73, 0x73, 0x20, 0x46, 0x72,
-0x61, 0x6e, 0x63, 0x54, 0x61, 0x6e, 0x7a, 0x61, 0x6e, 0x69, 0x61, 0x6e, 0x20, 0x53, 0x68, 0x69, 0x6c, 0x6c, 0x69, 0x6e,
-0x67, 0x54, 0x6f, 0x6e, 0x67, 0x61, 0x6e, 0x20, 0x50, 0x61, 0x2bb, 0x61, 0x6e, 0x67, 0x61, 0x54, 0x72, 0x69, 0x6e, 0x69,
-0x64, 0x61, 0x64, 0x20, 0x26, 0x20, 0x54, 0x6f, 0x62, 0x61, 0x67, 0x6f, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x55,
-0x67, 0x61, 0x6e, 0x64, 0x61, 0x6e, 0x20, 0x53, 0x68, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x55, 0x6e, 0x69, 0x74, 0x65,
-0x64, 0x20, 0x41, 0x72, 0x61, 0x62, 0x20, 0x45, 0x6d, 0x69, 0x72, 0x61, 0x74, 0x65, 0x73, 0x20, 0x44, 0x69, 0x72, 0x68,
-0x61, 0x6d, 0x42, 0x72, 0x69, 0x74, 0x69, 0x73, 0x68, 0x20, 0x50, 0x6f, 0x75, 0x6e, 0x64, 0x56, 0x61, 0x6e, 0x75, 0x61,
-0x74, 0x75, 0x20, 0x56, 0x61, 0x74, 0x75, 0x5a, 0x61, 0x6d, 0x62, 0x69, 0x61, 0x6e, 0x20, 0x4b, 0x77, 0x61, 0x63, 0x68,
-0x61, 0x67, 0x68, 0x61, 0x6e, 0x61, 0x20, 0x73, 0x69, 0x256, 0x69, 0x263, 0x65, 0x74, 0x6f, 0x256, 0x6f, 0x66, 0x65, 0x20,
-0x61, 0x66, 0x72, 0x69, 0x6b, 0x61, 0x67, 0x61, 0x20, 0x43, 0x46, 0x41, 0x20, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x42,
-0x43, 0x45, 0x41, 0x4f, 0x46, 0x259, 0x6c, 0xe1, 0x14b, 0x20, 0x43, 0x46, 0x41, 0x20, 0x28, 0x42, 0x45, 0x41, 0x43, 0x29,
-0x64, 0x6f, 0x6e, 0x73, 0x6b, 0x20, 0x6b, 0x72, 0xf3, 0x6e, 0x61, 0x50, 0x69, 0x73, 0x6f, 0x20, 0x6e, 0x67, 0x20, 0x50,
-0x69, 0x6c, 0x69, 0x70, 0x69, 0x6e, 0x61, 0x73, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x20, 0x61, 0x6c, 0x67, 0xe9, 0x72, 0x69,
-0x65, 0x6e, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x43, 0x46, 0x41, 0x20, 0x28, 0x42, 0x43, 0x45, 0x41, 0x4f, 0x29, 0x66,
-0x72, 0x61, 0x6e, 0x63, 0x20, 0x62, 0x75, 0x72, 0x75, 0x6e, 0x64, 0x61, 0x69, 0x73, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20,
-0x43, 0x46, 0x41, 0x20, 0x28, 0x42, 0x45, 0x41, 0x43, 0x29, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x20, 0x63, 0x61, 0x6e,
-0x61, 0x64, 0x69, 0x65, 0x6e, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x63, 0x6f, 0x6d, 0x6f, 0x72, 0x69, 0x65, 0x6e, 0x66,
-0x72, 0x61, 0x6e, 0x63, 0x20, 0x63, 0x6f, 0x6e, 0x67, 0x6f, 0x6c, 0x61, 0x69, 0x73, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20,
-0x64, 0x6a, 0x69, 0x62, 0x6f, 0x75, 0x74, 0x69, 0x65, 0x6e, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x43, 0x46, 0x50, 0x66,
-0x72, 0x61, 0x6e, 0x63, 0x20, 0x67, 0x75, 0x69, 0x6e, 0xe9, 0x65, 0x6e, 0x67, 0x6f, 0x75, 0x72, 0x64, 0x65, 0x20, 0x68,
-0x61, 0xef, 0x74, 0x69, 0x65, 0x6e, 0x6e, 0x65, 0x61, 0x72, 0x69, 0x61, 0x72, 0x79, 0x20, 0x6d, 0x61, 0x6c, 0x67, 0x61,
-0x63, 0x68, 0x65, 0x6f, 0x75, 0x67, 0x75, 0x69, 0x79, 0x61, 0x20, 0x6d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x61, 0x6e, 0x69,
-0x65, 0x6e, 0x72, 0x6f, 0x75, 0x70, 0x69, 0x65, 0x20, 0x6d, 0x61, 0x75, 0x72, 0x69, 0x63, 0x69, 0x65, 0x6e, 0x6e, 0x65,
-0x64, 0x69, 0x72, 0x68, 0x61, 0x6d, 0x20, 0x6d, 0x61, 0x72, 0x6f, 0x63, 0x61, 0x69, 0x6e, 0x66, 0x72, 0x61, 0x6e, 0x63,
-0x20, 0x72, 0x77, 0x61, 0x6e, 0x64, 0x61, 0x69, 0x73, 0x72, 0x6f, 0x75, 0x70, 0x69, 0x65, 0x20, 0x64, 0x65, 0x73, 0x20,
-0x53, 0x65, 0x79, 0x63, 0x68, 0x65, 0x6c, 0x6c, 0x65, 0x73, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x73, 0x75, 0x69, 0x73,
-0x73, 0x65, 0x6c, 0x69, 0x76, 0x72, 0x65, 0x20, 0x73, 0x79, 0x72, 0x69, 0x65, 0x6e, 0x6e, 0x65, 0x64, 0x69, 0x6e, 0x61,
-0x72, 0x20, 0x74, 0x75, 0x6e, 0x69, 0x73, 0x69, 0x65, 0x6e, 0x76, 0x61, 0x74, 0x75, 0x20, 0x76, 0x61, 0x6e, 0x75, 0x61,
-0x74, 0x75, 0x61, 0x6e, 0x4d, 0x62, 0x75, 0x75, 0x257, 0x75, 0x20, 0x53, 0x65, 0x65, 0x66, 0x61, 0x61, 0x20, 0x42, 0x43,
-0x45, 0x41, 0x4f, 0xd83a, 0xdd0a, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0x20, 0xd83a, 0xdd05, 0xd83a, 0xdd0a, 0xd83a, 0xdd00,
-0x20, 0xd83a, 0xdd16, 0xd83a, 0xdd2d, 0xd83a, 0xdd45, 0xd83a, 0xdd2a, 0xd83a, 0xdd32, 0xd83a, 0xdd22, 0xd83a, 0xdd44, 0xd83a, 0xdd32, 0xd83a, 0xdd3a, 0xd83a,
-0xdd2b, 0x20, 0xd83a, 0xdd00, 0xd83a, 0xdd2c, 0xd83a, 0xdd2a, 0xd83a, 0xdd2d, 0xd83a, 0xdd33, 0xd83a, 0xdd22, 0xd83a, 0xdd0a, 0xd83a, 0xdd22, 0xd83a, 0xdd2a,
-0xd83a, 0xdd22, 0xd83a, 0xdd32, 0x20, 0xd83a, 0xdd1a, 0xd83a, 0xdd35, 0xd83a, 0xdd26, 0xd83a, 0xdd2e, 0xd83a, 0xdd45, 0xd83a, 0xdd2a, 0xd83a, 0xdd2d, 0x20,
-0xd83a, 0xdd00, 0xd83a, 0xdd2c, 0xd83a, 0xdd2a, 0xd83a, 0xdd2d, 0xd83a, 0xdd33, 0xd83a, 0xdd2d, 0xd83a, 0xdd32, 0xd83a, 0xdd33, 0xd83a, 0xdd2e, 0xd83a, 0xdd01,
-0xd83a, 0xdd22, 0xd83a, 0xdd24, 0xd83a, 0xdd22, 0xd83a, 0xdd27, 0xd83a, 0xdd2d, 0x20, 0xd83a, 0xdd18, 0xd83a, 0xdd22, 0xd83a, 0xdd25, 0xd83a, 0xdd26, 0xd83a,
-0xdd2d, 0xd83a, 0xdd32, 0xd83a, 0xdd33, 0xd83a, 0xdd2e, 0xd83a, 0xdd05, 0xd83a, 0xdd2d, 0xd83a, 0xdd23, 0xd83a, 0xdd2d, 0x20, 0xd83a, 0xdd18, 0xd83a, 0xdd22,
-0xd83a, 0xdd32, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0xd83a, 0xdd33, 0xd83a, 0xdd2e, 0xd83a, 0xdd0a, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd22, 0xd83a, 0xdd32,
-0x20, 0xd83a, 0xdd18, 0xd83a, 0xdd2d, 0xd83a, 0xdd32, 0xd83a, 0xdd2b, 0xd83a, 0xdd32, 0xd83a, 0xdd33, 0xd83a, 0xdd2e, 0xd83a, 0xdd01, 0xd83a, 0xdd22, 0xd83a,
-0xdd24, 0xd83a, 0xdd22, 0x20, 0xd83a, 0xdd02, 0xd83a, 0xdd2d, 0xd83a, 0xdd26, 0xd83a, 0xdd2b, 0xd83a, 0xdd2a, 0xd83a, 0xdd2d, 0xd83a, 0xdd34, 0xd83a, 0xdd22,
-0xd83a, 0xdd32, 0xd83a, 0xdd33, 0xd83a, 0xdd2e, 0xd83a, 0xdd13, 0xd83a, 0xdd3a, 0xd83a, 0xdd2d, 0xd83a, 0xdd34, 0xd83a, 0xdd22, 0x20, 0xd83a, 0xdd03, 0xd83a,
-0xdd2e, 0xd83a, 0xdd2a, 0xd83a, 0xdd2d, 0xd83a, 0xdd3c, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0xd83a, 0xdd2d, 0xd83a, 0xdd34, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0xd83a,
-0xdd33, 0xd83a, 0xdd2e, 0xd83a, 0xdd10, 0xd83a, 0xdd22, 0xd83a, 0xdd34, 0xd83a, 0xdd2a, 0xd83a, 0xdd22, 0x20, 0xd83a, 0xdd10, 0xd83a, 0xdd22, 0xd83a, 0xdd36,
-0xd83a, 0xdd2d, 0xd83a, 0xdd2a, 0xd83a, 0xdd22, 0xd83a, 0xdd34, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0xd83a, 0xdd33, 0xd83a, 0xdd2e, 0x4d, 0x62, 0x75, 0x75,
-0x257, 0x69, 0x20, 0x53, 0x65, 0x65, 0x66, 0x61, 0x61, 0x20, 0x42, 0x45, 0x41, 0x43, 0x44, 0x61, 0x6c, 0x61, 0x73, 0x69,
-0x20, 0x47, 0x61, 0x6d, 0x6d, 0x62, 0x69, 0x44, 0x6f, 0x6c, 0x61, 0x61, 0x72, 0x20, 0x4c, 0x69, 0x62, 0x65, 0x72, 0x69,
-0x79, 0x61, 0x61, 0x55, 0x67, 0x69, 0x79, 0x79, 0x61, 0x20, 0x4d, 0x75, 0x72, 0x69, 0x74, 0x61, 0x6e, 0x69, 0x4e, 0x61,
-0x79, 0x72, 0x61, 0x61, 0x20, 0x4e, 0x69, 0x6a, 0x65, 0x72, 0x69, 0x79, 0x61, 0x61, 0x50, 0x75, 0x6e, 0x6e, 0x64, 0x20,
-0x53, 0x61, 0x73, 0x61, 0x6e, 0x6e, 0x61, 0x63, 0x68, 0x53, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x69, 0x20, 0x65, 0x79, 0x61,
-0x20, 0x59, 0x75, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x10e5, 0x10d0, 0x10e0, 0x10d7, 0x10e3, 0x10da, 0x10d8, 0x20, 0x10da, 0x10d0, 0x10e0, 0x10d8,
-0x53, 0x63, 0x68, 0x77, 0x65, 0x69, 0x7a, 0x65, 0x72, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x6b, 0x65, 0x6e, 0x395, 0x3c5, 0x3c1,
-0x3ce, 0xaad, 0xabe, 0xab0, 0xaa4, 0xac0, 0xaaf, 0x20, 0xab0, 0xac2, 0xaaa, 0xabf, 0xaaf, 0xabe, 0x4e, 0x61, 0x69, 0x72, 0x61, 0x72,
-0x20, 0x4e, 0x61, 0x6a, 0x65, 0x72, 0x69, 0x79, 0x61, 0x53, 0x69, 0x64, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x47, 0x68, 0x61,
-0x6e, 0x61, 0x4b, 0x75, 0x257, 0x69, 0x6e, 0x20, 0x53, 0x65, 0x66, 0x61, 0x20, 0x6e, 0x61, 0x20, 0x41, 0x66, 0x69, 0x72,
-0x6b, 0x61, 0x20, 0x54, 0x61, 0x20, 0x59, 0x61, 0x6d, 0x6d, 0x61, 0x5e9, 0x5e7, 0x5dc, 0x20, 0x5d7, 0x5d3, 0x5e9, 0x92d, 0x93e,
-0x930, 0x924, 0x940, 0x92f, 0x20, 0x930, 0x941, 0x92a, 0x92f, 0x93e, 0x6d, 0x61, 0x67, 0x79, 0x61, 0x72, 0x20, 0x66, 0x6f, 0x72,
-0x69, 0x6e, 0x74, 0xed, 0x73, 0x6c, 0x65, 0x6e, 0x73, 0x6b, 0x20, 0x6b, 0x72, 0xf3, 0x6e, 0x61, 0x4e, 0x61, 0x1ecb, 0x72,
-0x61, 0x52, 0x75, 0x70, 0x69, 0x61, 0x68, 0x20, 0x49, 0x6e, 0x64, 0x6f, 0x6e, 0x65, 0x73, 0x69, 0x61, 0x50, 0x75, 0x6e,
-0x74, 0x20, 0x53, 0x74, 0x65, 0x69, 0x72, 0x6c, 0x69, 0x6e, 0x67, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x6f, 0x20, 0x73, 0x76,
-0x69, 0x7a, 0x7a, 0x65, 0x72, 0x6f, 0x65e5, 0x672c, 0x5186, 0x73, 0x65, 0x65, 0x66, 0x61, 0x20, 0x79, 0x61, 0x74, 0x69, 0x20,
-0x42, 0x43, 0x45, 0x41, 0x4f, 0x53, 0x6b, 0x75, 0x64, 0x75, 0x20, 0x4b, 0x61, 0x62, 0x75, 0x76, 0x65, 0x72, 0x64, 0x69,
-0x61, 0x6e, 0x75, 0x41, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x20, 0x41, 0x7a, 0x7a, 0x61, 0x79, 0x72, 0x69, 0x46, 0x72, 0x61,
-0x6e, 0x63, 0x20, 0x43, 0x46, 0x41, 0x64, 0x61, 0x6e, 0x6d, 0x61, 0x72, 0x6b, 0x69, 0x6d, 0x75, 0x74, 0x20, 0x6b, 0x6f,
-0x72, 0x75, 0x75, 0x6e, 0x69, 0x53, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x69, 0x74, 0x61, 0x62, 0x20, 0x79, 0x61, 0x20, 0x4b,
-0x65, 0x6e, 0x79, 0x61, 0x53, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x69, 0x20, 0x79, 0x61, 0x20, 0x4b, 0x65, 0x6e, 0x79, 0x61,
-0xcad, 0xcbe, 0xcb0, 0xca4, 0xcc0, 0xcaf, 0x20, 0xcb0, 0xcc2, 0xcaa, 0xcbe, 0xcaf, 0xcbf, 0x6c1, 0x650, 0x646, 0x62f, 0x64f, 0x633, 0x62a,
-0x672, 0x646, 0x6cd, 0x20, 0x631, 0x6c4, 0x67e, 0x64e, 0x6d2, 0x907, 0x902, 0x921, 0x93f, 0x92f, 0x928, 0x20, 0x930, 0x942, 0x92a, 0x940,
-0x49a, 0x430, 0x437, 0x430, 0x49b, 0x441, 0x442, 0x430, 0x43d, 0x20, 0x442, 0x435, 0x4a3, 0x433, 0x435, 0x441, 0x456, 0x179a, 0x17c0, 0x179b,
-0x200b, 0x1780, 0x1798, 0x17d2, 0x1796, 0x17bb, 0x1787, 0x17b6, 0x43, 0x69, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x20, 0x79, 0x61, 0x20, 0x4b,
-0x65, 0x6e, 0x79, 0x61, 0xb300, 0xd55c, 0xbbfc, 0xad6d, 0x20, 0xc6d0, 0xc870, 0xc120, 0x20, 0xbbfc, 0xc8fc, 0xc8fc, 0xc758, 0x20, 0xc778, 0xbbfc,
-0x20, 0xacf5, 0xd654, 0xad6d, 0x20, 0xc6d0, 0x43, 0x46, 0x41, 0x20, 0x46, 0x72, 0x61, 0x14b, 0x20, 0x28, 0x42, 0x43, 0x45, 0x41,
-0x4f, 0x29, 0x46, 0x72, 0x61, 0x14b, 0x20, 0x43, 0x46, 0x41, 0x20, 0x42, 0x45, 0x41, 0x43, 0x41a, 0x44b, 0x440, 0x433, 0x44b,
-0x437, 0x441, 0x442, 0x430, 0x43d, 0x20, 0x441, 0x43e, 0x43c, 0x443, 0x53, 0x68, 0x69, 0x6c, 0xed, 0x69, 0x6e, 0x67, 0x69, 0x20,
-0x79, 0x61, 0x20, 0x54, 0x61, 0x61, 0x6e, 0x73, 0x61, 0x6e, 0xed, 0x61, 0xea5, 0xeb2, 0xea7, 0x20, 0xe81, 0xeb5, 0xe9a, 0x65,
-0x69, 0x72, 0x6f, 0x46, 0x61, 0x6c, 0xe1, 0x6e, 0x67, 0x61, 0x20, 0x79, 0x61, 0x20, 0x4b, 0x6f, 0x6e, 0x67, 0xf3, 0x4b,
-0x77, 0x61, 0x6e, 0x7a, 0x61, 0x20, 0x79, 0x61, 0x20, 0x41, 0x6e, 0x67, 0xf3, 0x6c, 0x61, 0x46, 0x61, 0x6c, 0xe1, 0x6e,
-0x67, 0x61, 0x20, 0x43, 0x46, 0x41, 0x20, 0x42, 0x45, 0x41, 0x43, 0x45, 0x75, 0x72, 0x61, 0x73, 0x4e, 0x66, 0x61, 0x6c,
-0x61, 0x6e, 0x67, 0x61, 0x20, 0x77, 0x61, 0x20, 0x4b, 0x6f, 0x6e, 0x67, 0x75, 0x53, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x20,
-0x6d, 0x61, 0x72, 0x20, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x53, 0x69, 0x72, 0x69, 0x6e, 0x6a, 0x69, 0x20, 0x79, 0x61, 0x20,
-0x4b, 0x65, 0x6e, 0x79, 0x61, 0x41c, 0x430, 0x43a, 0x435, 0x434, 0x43e, 0x43d, 0x441, 0x43a, 0x438, 0x20, 0x434, 0x435, 0x43d, 0x430,
-0x440, 0x53, 0x68, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x69, 0x20, 0x79, 0x61, 0x20, 0x54, 0x61, 0x6e, 0x7a, 0x61, 0x6e, 0x69,
-0x61, 0xd07, 0xd28, 0xd4d, 0xd24, 0xd4d, 0xd2f, 0xd7b, 0x20, 0xd30, 0xd42, 0xd2a, 0x52, 0x69, 0x6e, 0x67, 0x67, 0x69, 0x74, 0x20,
-0x4d, 0x61, 0x6c, 0x61, 0x79, 0x73, 0x69, 0x61, 0x44, 0x6f, 0x6c, 0x61, 0x72, 0x20, 0x42, 0x72, 0x75, 0x6e, 0x65, 0x69,
-0x44, 0x6f, 0x6c, 0x61, 0x72, 0x20, 0x53, 0x69, 0x6e, 0x67, 0x61, 0x70, 0x75, 0x72, 0x61, 0x65, 0x77, 0x72, 0x6f, 0x987,
-0x9a8, 0x9cd, 0x9a6, 0x9bf, 0x9af, 0x9bc, 0x9be, 0x9a8, 0x20, 0x9b0, 0x9c1, 0x9aa, 0x9c0, 0x54, 0x101, 0x72, 0x61, 0x20, 0x6f, 0x20,
-0x41, 0x6f, 0x74, 0x65, 0x61, 0x72, 0x6f, 0x61, 0x49, 0x72, 0x6f, 0x70, 0x69, 0x79, 0x69, 0x61, 0x6e, 0xed, 0x20, 0x65,
-0x20, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x49, 0x72, 0x6f, 0x70, 0x69, 0x79, 0x69, 0x61, 0x6e, 0xed, 0x20, 0x65, 0x20, 0x54,
-0x61, 0x6e, 0x7a, 0x61, 0x6e, 0x69, 0x61, 0x627, 0x6cc, 0x631, 0x627, 0x646, 0x20, 0x631, 0x6cc, 0x627, 0x644, 0x73, 0x68, 0x69,
-0x72, 0xe8, 0x41c, 0x43e, 0x43d, 0x433, 0x43e, 0x43b, 0x20, 0x442, 0x4e9, 0x433, 0x440, 0x4e9, 0x433, 0x72, 0x6f, 0x75, 0x70, 0x69,
-0x20, 0x6d, 0x6f, 0x72, 0x69, 0x73, 0x69, 0x65, 0x6e, 0x73, 0x6f, 0x6c, 0x61, 0x69, 0x20, 0x42, 0x45, 0x41, 0x43, 0x4e,
-0x61, 0x6d, 0x69, 0x62, 0x69, 0x61, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x69, 0x928, 0x947, 0x92a, 0x93e, 0x932, 0x940,
-0x20, 0x930, 0x942, 0x92a, 0x948, 0x92f, 0x93e, 0x901, 0x92d, 0x93e, 0x930, 0x924, 0x940, 0x92f, 0x20, 0x930, 0x942, 0x92a, 0x93f, 0x901,
-0x92f, 0x93e, 0x66, 0x65, 0x6c, 0xe1, 0x14b, 0x20, 0x43, 0x46, 0x41, 0x46, 0x25b, 0x6c, 0xe2, 0x14b, 0x4e, 0x61, 0x69, 0x6a,
-0xed, 0x72, 0x69, 0xe1, 0x20, 0x4e, 0x61, 0xed, 0x72, 0x61, 0x6e, 0x6f, 0x72, 0x67, 0x67, 0x61, 0x20, 0x6b, 0x72, 0x75,
-0x76, 0x64, 0x6e, 0x6f, 0x72, 0x75, 0x6f, 0x167, 0x167, 0x61, 0x20, 0x6b, 0x72, 0x75, 0x76, 0x64, 0x6e, 0x6f, 0x44, 0x6f,
-0x6c, 0x61, 0x20, 0x79, 0x61, 0x73, 0x65, 0x20, 0x41, 0x6d, 0x65, 0x6c, 0x69, 0x6b, 0x61, 0x6e, 0x6f, 0x72, 0x73, 0x6b,
-0x65, 0x20, 0x6b, 0x72, 0x6f, 0x6e, 0x65, 0x72, 0xb2d, 0xb3e, 0xb30, 0xb24, 0xb40, 0xb5f, 0x20, 0xb1f, 0xb19, 0xb4d, 0xb15, 0xb3e,
-0x49, 0x74, 0x6f, 0x6f, 0x70, 0x68, 0x69, 0x79, 0x61, 0x61, 0x20, 0x42, 0x69, 0x72, 0x72, 0x69, 0x69, 0x41b, 0x430, 0x440,
-0x421, 0x43e, 0x43c, 0x627, 0x641, 0x63a, 0x627, 0x646, 0x6cd, 0x67e, 0x627, 0x6a9, 0x633, 0x62a, 0x627, 0x646, 0x6cd, 0x20, 0x6a9, 0x644,
-0x62f, 0x627, 0x631, 0x647, 0x631, 0x6cc, 0x627, 0x644, 0x20, 0x627, 0x6cc, 0x631, 0x627, 0x646, 0x627, 0x641, 0x63a, 0x627, 0x646, 0x6cc,
-0x20, 0x627, 0x641, 0x63a, 0x627, 0x646, 0x633, 0x62a, 0x627, 0x646, 0x7a, 0x142, 0x6f, 0x74, 0x79, 0x20, 0x70, 0x6f, 0x6c, 0x73,
-0x6b, 0x69, 0x52, 0x65, 0x61, 0x6c, 0x20, 0x62, 0x72, 0x61, 0x73, 0x69, 0x6c, 0x65, 0x69, 0x72, 0x6f, 0x6b, 0x77, 0x61,
-0x6e, 0x7a, 0x61, 0x20, 0x61, 0x6e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x6f, 0x65, 0x73, 0x63, 0x75, 0x64, 0x6f, 0x20, 0x63,
-0x61, 0x62, 0x6f, 0x2d, 0x76, 0x65, 0x72, 0x64, 0x69, 0x61, 0x6e, 0x6f, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x6f, 0x20, 0x43,
-0x46, 0x41, 0x20, 0x28, 0x42, 0x45, 0x41, 0x43, 0x29, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x6f, 0x20, 0x43, 0x46, 0x41, 0x20,
-0x28, 0x42, 0x43, 0x45, 0x41, 0x4f, 0x29, 0x70, 0x61, 0x74, 0x61, 0x63, 0x61, 0x20, 0x6d, 0x61, 0x63, 0x61, 0x65, 0x6e,
-0x73, 0x65, 0x6d, 0x65, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x6f, 0xe7, 0x61, 0x6d, 0x62, 0x69, 0x63, 0x61, 0x6e,
-0x6f, 0x64, 0x6f, 0x62, 0x72, 0x61, 0x20, 0x64, 0x65, 0x20, 0x53, 0xe3, 0x6f, 0x20, 0x54, 0x6f, 0x6d, 0xe9, 0x20, 0x65,
-0x20, 0x50, 0x72, 0xed, 0x6e, 0x63, 0x69, 0x70, 0x65, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x6f, 0x20, 0x73, 0x75, 0xed, 0xe7,
-0x6f, 0x64, 0xf3, 0x6c, 0x61, 0x72, 0x20, 0x64, 0x6f, 0x73, 0x20, 0x45, 0x73, 0x74, 0x61, 0x64, 0x6f, 0x73, 0x20, 0x55,
-0x6e, 0x69, 0x64, 0x6f, 0x73, 0xa2d, 0xa3e, 0xa30, 0xa24, 0xa40, 0x20, 0xa30, 0xa41, 0xa2a, 0xa07, 0xa06, 0x631, 0x648, 0x67e, 0x626,
-0x6cc, 0x6c1, 0x53, 0x6f, 0x6c, 0x20, 0x50, 0x65, 0x72, 0x75, 0x61, 0x6e, 0x6f, 0x42, 0x6f, 0x6c, 0x69, 0x76, 0x69, 0x61,
-0x6e, 0x6f, 0x44, 0xf3, 0x6c, 0x61, 0x72, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6e, 0x6f, 0x6c, 0x65, 0x75,
-0x20, 0x72, 0x6f, 0x6d, 0xe2, 0x6e, 0x65, 0x73, 0x63, 0x6c, 0x65, 0x75, 0x20, 0x6d, 0x6f, 0x6c, 0x64, 0x6f, 0x76, 0x65,
-0x6e, 0x65, 0x73, 0x63, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x73, 0x76, 0x69, 0x7a, 0x7a, 0x65, 0x72, 0x68, 0x65, 0x6c,
-0x65, 0x72, 0x69, 0x20, 0x73, 0x61, 0x20, 0x54, 0x61, 0x6e, 0x7a, 0x61, 0x6e, 0x69, 0x61, 0x49, 0x66, 0x61, 0x72, 0x61,
-0x6e, 0x67, 0x61, 0x20, 0x72, 0x79, 0x2019, 0x55, 0x62, 0x75, 0x72, 0x75, 0x6e, 0x64, 0x69, 0x440, 0x43e, 0x441, 0x441, 0x438,
-0x439, 0x441, 0x43a, 0x438, 0x439, 0x20, 0x440, 0x443, 0x431, 0x43b, 0x44c, 0x431, 0x435, 0x43b, 0x43e, 0x440, 0x443, 0x441, 0x441, 0x43a,
-0x438, 0x439, 0x20, 0x440, 0x443, 0x431, 0x43b, 0x44c, 0x43a, 0x430, 0x437, 0x430, 0x445, 0x441, 0x43a, 0x438, 0x439, 0x20, 0x442, 0x435,
-0x43d, 0x433, 0x435, 0x43a, 0x438, 0x440, 0x433, 0x438, 0x437, 0x441, 0x43a, 0x438, 0x439, 0x20, 0x441, 0x43e, 0x43c, 0x43c, 0x43e, 0x43b,
-0x434, 0x430, 0x432, 0x441, 0x43a, 0x438, 0x439, 0x20, 0x43b, 0x435, 0x439, 0x443, 0x43a, 0x440, 0x430, 0x438, 0x43d, 0x441, 0x43a, 0x430,
-0x44f, 0x20, 0x433, 0x440, 0x438, 0x432, 0x43d, 0x430, 0x410, 0x440, 0x430, 0x441, 0x441, 0x44b, 0x44b, 0x439, 0x430, 0x20, 0x441, 0x43e,
-0x43b, 0x43a, 0x443, 0x43e, 0x431, 0x430, 0x439, 0x430, 0x4e, 0x6a, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x69, 0x20, 0x65, 0x65, 0x6c,
-0x20, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x66, 0x61, 0x72, 0xe2, 0x6e, 0x67, 0x61, 0x20, 0x43, 0x46, 0x41, 0x20, 0x28, 0x42,
-0x45, 0x41, 0x43, 0x29, 0x49, 0x68, 0x65, 0x6c, 0x61, 0x20, 0x79, 0x61, 0x20, 0x54, 0x61, 0x6e, 0x73, 0x61, 0x6e, 0x69,
-0x79, 0x61, 0x92d, 0x93e, 0x930, 0x924, 0x940, 0x92f, 0x20, 0x930, 0x942, 0x92a, 0x94d, 0x92f, 0x915, 0x92e, 0x94d, 0x1c65, 0x1c64, 0x1c67,
-0x1c5a, 0x1c5b, 0x20, 0x1c68, 0x1c6e, 0x1c71, 0x1c5f, 0x1c5c, 0x20, 0x1c74, 0x1c5f, 0x1c60, 0x1c5f, 0xe8, 0x75, 0x72, 0x6f, 0x4d, 0x65, 0x74,
-0x69, 0x63, 0x61, 0x6c, 0x20, 0x64, 0x65, 0x20, 0x4d, 0x6f, 0xe7, 0x61, 0x6d, 0x62, 0x69, 0x71, 0x75, 0x65, 0x441, 0x440,
-0x43f, 0x441, 0x43a, 0x438, 0x20, 0x434, 0x438, 0x43d, 0x430, 0x440, 0x411, 0x43e, 0x441, 0x430, 0x43d, 0x441, 0x43a, 0x43e, 0x445, 0x435,
-0x440, 0x446, 0x435, 0x433, 0x43e, 0x432, 0x430, 0x447, 0x43a, 0x430, 0x20, 0x43a, 0x43e, 0x43d, 0x432, 0x435, 0x440, 0x442, 0x438, 0x431,
-0x438, 0x43b, 0x43d, 0x430, 0x20, 0x43c, 0x430, 0x440, 0x43a, 0x430, 0x415, 0x432, 0x440, 0x43e, 0x45, 0x76, 0x72, 0x6f, 0x73, 0x72,
-0x70, 0x73, 0x6b, 0x69, 0x20, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x73, 0x68, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x69, 0x20, 0x79,
-0x61, 0x20, 0x54, 0x61, 0x6e, 0x7a, 0x61, 0x6e, 0x69, 0x61, 0x44, 0x6f, 0x72, 0x61, 0x20, 0x72, 0x65, 0x20, 0x41, 0x6d,
-0x65, 0x72, 0x69, 0x6b, 0x61, 0x67e, 0x627, 0x6aa, 0x633, 0x62a, 0x627, 0x646, 0x64a, 0x20, 0x631, 0x67e, 0x64a, 0x939, 0x93f, 0x902,
-0x926, 0x941, 0x938, 0x94d, 0x924, 0x93e, 0x928, 0x940, 0x20, 0x930, 0x941, 0x92a, 0x92f, 0x94b, 0xdc1, 0xdca, 0x200d, 0xdbb, 0xdd3, 0x20,
-0xdbd, 0xd82, 0xd9a, 0xdcf, 0x20, 0xdbb, 0xdd4, 0xdb4, 0xdd2, 0xdba, 0xdbd, 0x65, 0x76, 0x72, 0x6f, 0x53, 0x68, 0x69, 0x6c, 0x69,
-0x6e, 0x67, 0x6b, 0x61, 0x20, 0x53, 0x6f, 0x6f, 0x6d, 0x61, 0x61, 0x6c, 0x69, 0x79, 0x61, 0x46, 0x61, 0x72, 0x61, 0x6e,
-0x20, 0x4a, 0x61, 0x62, 0x75, 0x75, 0x74, 0x69, 0x42, 0x69, 0x72, 0x74, 0x61, 0x20, 0x49, 0x74, 0x6f, 0x6f, 0x62, 0x62,
-0x69, 0x79, 0x61, 0x53, 0x68, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x6b, 0x61, 0x20, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x70, 0x65,
-0x73, 0x6f, 0x20, 0x61, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x6f, 0x64, 0xf3, 0x6c, 0x61, 0x72, 0x20, 0x62, 0x65,
-0x6c, 0x69, 0x63, 0x65, 0xf1, 0x6f, 0x62, 0x6f, 0x6c, 0x69, 0x76, 0x69, 0x61, 0x6e, 0x6f, 0x72, 0x65, 0x61, 0x6c, 0x20,
-0x62, 0x72, 0x61, 0x73, 0x69, 0x6c, 0x65, 0xf1, 0x6f, 0x50, 0x65, 0x73, 0x6f, 0x20, 0x63, 0x68, 0x69, 0x6c, 0x65, 0x6e,
-0x6f, 0x70, 0x65, 0x73, 0x6f, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x6d, 0x62, 0x69, 0x61, 0x6e, 0x6f, 0x63, 0x6f, 0x6c, 0xf3,
-0x6e, 0x20, 0x63, 0x6f, 0x73, 0x74, 0x61, 0x72, 0x72, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x70, 0x65, 0x73, 0x6f, 0x20,
-0x63, 0x75, 0x62, 0x61, 0x6e, 0x6f, 0x70, 0x65, 0x73, 0x6f, 0x20, 0x64, 0x6f, 0x6d, 0x69, 0x6e, 0x69, 0x63, 0x61, 0x6e,
-0x6f, 0x64, 0xf3, 0x6c, 0x61, 0x72, 0x20, 0x65, 0x73, 0x74, 0x61, 0x64, 0x6f, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x73,
-0x65, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x6f, 0x20, 0x43, 0x46, 0x41, 0x20, 0x64, 0x65, 0x20, 0xc1, 0x66, 0x72, 0x69, 0x63,
-0x61, 0x20, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x71, 0x75, 0x65, 0x74, 0x7a, 0x61, 0x6c, 0x6c, 0x65, 0x6d, 0x70,
-0x69, 0x72, 0x61, 0x20, 0x68, 0x6f, 0x6e, 0x64, 0x75, 0x72, 0x65, 0xf1, 0x6f, 0x70, 0x65, 0x73, 0x6f, 0x20, 0x6d, 0x65,
-0x78, 0x69, 0x63, 0x61, 0x6e, 0x6f, 0x63, 0xf3, 0x72, 0x64, 0x6f, 0x62, 0x61, 0x20, 0x6e, 0x69, 0x63, 0x61, 0x72, 0x61,
-0x67, 0xfc, 0x65, 0x6e, 0x73, 0x65, 0x62, 0x61, 0x6c, 0x62, 0x6f, 0x61, 0x20, 0x70, 0x61, 0x6e, 0x61, 0x6d, 0x65, 0xf1,
-0x6f, 0x67, 0x75, 0x61, 0x72, 0x61, 0x6e, 0xed, 0x20, 0x70, 0x61, 0x72, 0x61, 0x67, 0x75, 0x61, 0x79, 0x6f, 0x73, 0x6f,
-0x6c, 0x20, 0x70, 0x65, 0x72, 0x75, 0x61, 0x6e, 0x6f, 0x70, 0x65, 0x73, 0x6f, 0x20, 0x66, 0x69, 0x6c, 0x69, 0x70, 0x69,
-0x6e, 0x6f, 0x70, 0x65, 0x73, 0x6f, 0x20, 0x75, 0x72, 0x75, 0x67, 0x75, 0x61, 0x79, 0x6f, 0x62, 0x6f, 0x6c, 0xed, 0x76,
-0x61, 0x72, 0x20, 0x73, 0x6f, 0x62, 0x65, 0x72, 0x61, 0x6e, 0x6f, 0x2d30, 0x2d37, 0x2d54, 0x2d49, 0x2d4e, 0x20, 0x2d4f, 0x20, 0x2d4d,
-0x2d4e, 0x2d56, 0x2d54, 0x2d49, 0x2d31, 0x52, 0x75, 0x70, 0x65, 0x65, 0x20, 0x49, 0x6e, 0x64, 0x6f, 0x6e, 0xe9, 0x73, 0x69, 0x61,
-0x46, 0x61, 0x72, 0x61, 0x6e, 0x67, 0x61, 0x20, 0x79, 0x61, 0x20, 0x4b, 0x6f, 0x6e, 0x67, 0x6f, 0x53, 0x68, 0x69, 0x6c,
-0x69, 0x6e, 0x67, 0x69, 0x20, 0x79, 0x61, 0x20, 0x55, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x73, 0x76, 0x65, 0x6e, 0x73, 0x6b,
-0x20, 0x6b, 0x72, 0x6f, 0x6e, 0x61, 0x53, 0x63, 0x68, 0x77, 0x69, 0x69, 0x7a, 0x65, 0x72, 0x20, 0x46, 0x72, 0x61, 0x6e,
-0x6b, 0x65, 0x61, 0x64, 0x72, 0x69, 0x6d, 0x20, 0x6e, 0x20, 0x6c, 0x6d, 0x263, 0x72, 0x69, 0x62, 0x421, 0x43e, 0x43c, 0x43e,
-0x43d, 0x4e3, 0xb87, 0xba8, 0xbcd, 0xba4, 0xbbf, 0xbaf, 0x20, 0xbb0, 0xbc2, 0xbaa, 0xbbe, 0xbaf, 0xbcd, 0xbae, 0xbb2, 0xbc7, 0xbb7, 0xbbf,
-0xbaf, 0xba9, 0xbcd, 0x20, 0xbb0, 0xbbf, 0xb99, 0xbcd, 0xb95, 0xbbf, 0xb9f, 0xbcd, 0xb9a, 0xbbf, 0xb99, 0xbcd, 0xb95, 0xbaa, 0xbcd, 0xbaa,
-0xbc2, 0xbb0, 0xbcd, 0x20, 0xb9f, 0xbbe, 0xbb2, 0xbb0, 0xbcd, 0xb87, 0xbb2, 0xb99, 0xbcd, 0xb95, 0xbc8, 0x20, 0xbb0, 0xbc2, 0xbaa, 0xbbe,
-0xbaf, 0xbcd, 0x420, 0x43e, 0x441, 0x441, 0x438, 0x44f, 0x20, 0x441, 0x443, 0x43c, 0x44b, 0xc2d, 0xc3e, 0xc30, 0xc24, 0xc26, 0xc47, 0xc36,
-0x20, 0xc30, 0xc42, 0xc2a, 0xc3e, 0xc2f, 0xc3f, 0x41, 0x6e, 0x67, 0x6f, 0x2019, 0x6f, 0x74, 0x6f, 0x6c, 0x20, 0x6c, 0x6f, 0x6b,
-0x2019, 0x20, 0x55, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x41, 0x6e, 0x67, 0x6f, 0x2019, 0x6f, 0x74, 0x6f, 0x6c, 0x20, 0x6c, 0x6f,
-0x6b, 0x2019, 0x20, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0xe1a, 0xe32, 0xe17, 0xf61, 0xf74, 0xf0b, 0xf68, 0xf53, 0xf0b, 0xf62, 0xf92, 0xfb1,
-0xf0b, 0xf42, 0xf62, 0xf0b, 0xf66, 0xf92, 0xf7c, 0xf62, 0xf0b, 0x1293, 0x1255, 0x134b, 0x50, 0x61, 0x2bb, 0x61, 0x6e, 0x67, 0x61, 0x20,
-0x66, 0x61, 0x6b, 0x61, 0x74, 0x6f, 0x6e, 0x67, 0x61, 0x54, 0xfc, 0x72, 0x6b, 0x20, 0x4c, 0x69, 0x72, 0x61, 0x73, 0x131,
-0x54, 0xfc, 0x72, 0x6b, 0x6d, 0x65, 0x6e, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x64, 0x79, 0x443, 0x43a, 0x440, 0x430, 0x457, 0x43d,
-0x441, 0x44c, 0x43a, 0x430, 0x20, 0x433, 0x440, 0x438, 0x432, 0x43d, 0x44f, 0x67e, 0x627, 0x6a9, 0x633, 0x62a, 0x627, 0x646, 0x6cc, 0x20,
-0x631, 0x648, 0x67e, 0x6cc, 0x6c1, 0x628, 0x6be, 0x627, 0x631, 0x62a, 0x6cc, 0x20, 0x631, 0x648, 0x67e, 0x6cc, 0x6c1, 0x62c, 0x6c7, 0x6ad,
-0x6af, 0x648, 0x20, 0x64a, 0x6c8, 0x6d5, 0x646, 0x649, 0x4f, 0x2018, 0x7a, 0x62, 0x65, 0x6b, 0x69, 0x73, 0x74, 0x6f, 0x6e, 0x20,
-0x73, 0x6f, 0x2018, 0x6d, 0x69, 0x40e, 0x437, 0x431, 0x435, 0x43a, 0x438, 0x441, 0x442, 0x43e, 0x43d, 0x20, 0x441, 0x45e, 0x43c, 0xa55e,
-0xa524, 0xa52b, 0xa569, 0x20, 0xa55c, 0xa55e, 0xa54c, 0x4c, 0x61, 0x69, 0x62, 0x68, 0x69, 0x79, 0x61, 0x20, 0x44, 0x61, 0x6c, 0x61,
-0x110, 0x1ed3, 0x6e, 0x67, 0x20, 0x56, 0x69, 0x1ec7, 0x74, 0x20, 0x4e, 0x61, 0x6d, 0x50, 0x75, 0x6e, 0x74, 0x20, 0x50, 0x72,
-0x79, 0x64, 0x61, 0x69, 0x6e, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x43, 0x46, 0x41, 0x20, 0x62, 0x75, 0x20, 0x41, 0x66,
-0x72, 0x69, 0x6b, 0x20, 0x53, 0x6f, 0x77, 0x77, 0x75, 0x2d, 0x6a, 0x61, 0x6e, 0x74, 0x49, 0x52, 0x61, 0x6e, 0x64, 0x69,
-0x20, 0x79, 0x61, 0x73, 0x65, 0x4d, 0x7a, 0x61, 0x6e, 0x74, 0x73, 0x69, 0x20, 0x41, 0x66, 0x72, 0x69, 0x6b, 0x61, 0x4e,
-0xe1, 0xed, 0x72, 0xe0, 0x20, 0x4e, 0xe0, 0xec, 0x6a, 0xed, 0x72, 0xed, 0xe0, 0x46, 0x61, 0x72, 0x61, 0x6e, 0x73, 0xec,
-0x20, 0xec, 0x77, 0x254, 0x300, 0x2d, 0x6f, 0x6f, 0x72, 0xf9, 0x6e, 0x20, 0x41, 0x66, 0xed, 0x72, 0xed, 0x6b, 0xe0, 0x69,
-0x2d, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x6e, 0x20, 0x52, 0x61, 0x6e, 0x64, 0x4d,
-0x72, 0x61, 0x73, 0x69, 0x72, 0x20, 0x52, 0x65, 0x6a, 0x61, 0x72, 0x52, 0x65, 0x61, 0x75, 0x20, 0x42, 0x72, 0x61, 0x73,
-0x69, 0x75, 0x77, 0x61, 0x72, 0x61, 0x50, 0x65, 0x73, 0x6f, 0x20, 0x4b, 0x75, 0x72, 0x169, 0x62, 0x69, 0x79, 0x61, 0x77,
-0x61, 0x72, 0x61, 0x42, 0x75, 0x72, 0x69, 0x77, 0x61, 0x72, 0x69, 0x20, 0x57, 0x65, 0x6e, 0x65, 0x73, 0x75, 0x65, 0x72,
-0x61, 0x77, 0x61, 0x72, 0x61
+0x53, 0x75, 0x69, 0x64, 0x2d, 0x41, 0x66, 0x72, 0x69, 0x6b, 0x61, 0x61,
+0x6e, 0x73, 0x65, 0x20, 0x72, 0x61, 0x6e, 0x64, 0x4e, 0x61, 0x6d, 0x69,
+0x62, 0x69, 0x65, 0x73, 0x65, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72,
+0x43, 0x46, 0x41, 0x20, 0x46, 0xe0, 0x6c, 0xe2, 0x14b, 0x20, 0x42, 0x45,
+0x41, 0x43, 0x47, 0x68, 0x61, 0x6e, 0x61, 0x20, 0x53, 0x69, 0x64, 0x69,
+0x46, 0x72, 0xe2, 0x6e, 0x6b, 0x65, 0x20, 0x43, 0x46, 0x41, 0x4c, 0x65,
+0x6b, 0x75, 0x20, 0x73, 0x68, 0x71, 0x69, 0x70, 0x74, 0x61, 0x72, 0x45,
+0x75, 0x72, 0x6f, 0x6a, 0x61, 0x44, 0x65, 0x6e, 0x61, 0x72, 0x69, 0x20,
+0x6d, 0x61, 0x71, 0x65, 0x64, 0x6f, 0x6e, 0x61, 0x73, 0x12e8, 0x12a2, 0x1275,
+0x12ee, 0x1335, 0x12eb, 0x20, 0x1265, 0x122d, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x645,
+0x635, 0x631, 0x64a, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x62c, 0x632, 0x627,
+0x626, 0x631, 0x64a, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x628, 0x62d, 0x631,
+0x64a, 0x646, 0x64a, 0x641, 0x631, 0x646, 0x643, 0x20, 0x648, 0x633, 0x637, 0x20,
+0x623, 0x641, 0x631, 0x64a, 0x642, 0x64a, 0x641, 0x631, 0x646, 0x643, 0x20, 0x62c,
+0x632, 0x631, 0x20, 0x627, 0x644, 0x642, 0x645, 0x631, 0x641, 0x631, 0x646, 0x643,
+0x20, 0x62c, 0x64a, 0x628, 0x648, 0x62a, 0x64a, 0x646, 0x627, 0x643, 0x641, 0x627,
+0x20, 0x623, 0x631, 0x64a, 0x62a, 0x631, 0x64a, 0x62f, 0x64a, 0x646, 0x627, 0x631,
+0x20, 0x639, 0x631, 0x627, 0x642, 0x64a, 0x634, 0x64a, 0x643, 0x644, 0x20, 0x625,
+0x633, 0x631, 0x627, 0x626, 0x64a, 0x644, 0x64a, 0x20, 0x62c, 0x62f, 0x64a, 0x62f,
+0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x623, 0x631, 0x62f, 0x646, 0x64a, 0x62f,
+0x64a, 0x646, 0x627, 0x631, 0x20, 0x643, 0x648, 0x64a, 0x62a, 0x64a, 0x62c, 0x646,
+0x64a, 0x647, 0x20, 0x644, 0x628, 0x646, 0x627, 0x646, 0x64a, 0x62f, 0x64a, 0x646,
+0x627, 0x631, 0x20, 0x644, 0x64a, 0x628, 0x64a, 0x623, 0x648, 0x642, 0x64a, 0x629,
+0x20, 0x645, 0x648, 0x631, 0x64a, 0x62a, 0x627, 0x646, 0x64a, 0x629, 0x62f, 0x631,
+0x647, 0x645, 0x20, 0x645, 0x63a, 0x631, 0x628, 0x64a, 0x631, 0x64a, 0x627, 0x644,
+0x20, 0x639, 0x645, 0x627, 0x646, 0x64a, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x642,
+0x637, 0x631, 0x64a, 0x631, 0x64a, 0x627, 0x644, 0x20, 0x633, 0x639, 0x648, 0x62f,
+0x64a, 0x634, 0x644, 0x646, 0x20, 0x635, 0x648, 0x645, 0x627, 0x644, 0x64a, 0x62c,
+0x646, 0x64a, 0x647, 0x20, 0x62c, 0x646, 0x648, 0x628, 0x20, 0x627, 0x644, 0x633,
+0x648, 0x62f, 0x627, 0x646, 0x62c, 0x646, 0x64a, 0x647, 0x20, 0x633, 0x648, 0x62f,
+0x627, 0x646, 0x64a, 0x644, 0x64a, 0x631, 0x629, 0x20, 0x633, 0x648, 0x631, 0x64a,
+0x629, 0x62f, 0x64a, 0x646, 0x627, 0x631, 0x20, 0x62a, 0x648, 0x646, 0x633, 0x64a,
+0x62f, 0x631, 0x647, 0x645, 0x20, 0x625, 0x645, 0x627, 0x631, 0x627, 0x62a, 0x64a,
+0x631, 0x64a, 0x627, 0x644, 0x20, 0x64a, 0x645, 0x646, 0x64a, 0x65, 0x75, 0x72,
+0x6f, 0x570, 0x561, 0x575, 0x56f, 0x561, 0x56f, 0x561, 0x576, 0x20, 0x564, 0x580,
+0x561, 0x574, 0x9ad, 0x9be, 0x9f0, 0x9a4, 0x9c0, 0x9af, 0x9bc, 0x20, 0x9f0, 0x9c1,
+0x9aa, 0x9c0, 0x73, 0x68, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x69, 0x20, 0x79,
+0x61, 0x20, 0x54, 0x61, 0x6e, 0x64, 0x68, 0x61, 0x6e, 0x69, 0x61, 0x41,
+0x6d, 0x61, 0x6e, 0x41, 0x7a, 0x259, 0x72, 0x62, 0x61, 0x79, 0x63, 0x61,
+0x6e, 0x20, 0x4d, 0x61, 0x6e, 0x61, 0x74, 0x131, 0x43c, 0x430, 0x43d, 0x430,
+0x442, 0x66, 0x72, 0xe1, 0x14b, 0x73, 0x65, 0x66, 0x61, 0x20, 0x46, 0x72,
+0x61, 0x14b, 0x20, 0x28, 0x42, 0x43, 0x45, 0x41, 0x4f, 0x29, 0x9ac, 0x9be,
+0x982, 0x9b2, 0x9be, 0x9a6, 0x9c7, 0x9b6, 0x9c0, 0x20, 0x99f, 0x9be, 0x995, 0x9be,
+0x9ad, 0x9be, 0x9b0, 0x9a4, 0x9c0, 0x9af, 0x9bc, 0x20, 0x9b0, 0x9c1, 0x9aa, 0x9bf,
+0x46, 0x72, 0x1ce, 0x14b, 0x20, 0x43, 0x46, 0x41, 0x20, 0x28, 0x42, 0x45,
+0x41, 0x43, 0x29, 0x65, 0x75, 0x72, 0x6f, 0x61, 0x431, 0x435, 0x43b, 0x430,
+0x440, 0x443, 0x441, 0x43a, 0x456, 0x20, 0x440, 0x443, 0x431, 0x435, 0x43b, 0x44c,
+0x53, 0x68, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x69, 0x20, 0x79, 0x61, 0x20,
+0x48, 0x75, 0x74, 0x61, 0x6e, 0x7a, 0x61, 0x6e, 0x69, 0x61, 0x92d, 0x93e,
+0x930, 0x924, 0x928, 0x93f, 0x20, 0x930, 0x941, 0x92a, 0x940, 0x42, 0x6f, 0x73,
+0x61, 0x6e, 0x73, 0x6b, 0x6f, 0x68, 0x65, 0x72, 0x63, 0x65, 0x67, 0x6f,
+0x76, 0x61, 0x10d, 0x6b, 0x61, 0x20, 0x6b, 0x6f, 0x6e, 0x76, 0x65, 0x72,
+0x74, 0x69, 0x62, 0x69, 0x6c, 0x6e, 0x61, 0x20, 0x6d, 0x61, 0x72, 0x6b,
+0x61, 0x41a, 0x43e, 0x43d, 0x432, 0x435, 0x440, 0x442, 0x438, 0x431, 0x438, 0x43b,
+0x43d, 0x430, 0x20, 0x43c, 0x430, 0x440, 0x43a, 0x430, 0x411, 0x44a, 0x43b, 0x433,
+0x430, 0x440, 0x441, 0x43a, 0x438, 0x20, 0x43b, 0x435, 0x432, 0x1019, 0x103c, 0x1014,
+0x103a, 0x1019, 0x102c, 0x20, 0x1000, 0x103b, 0x1015, 0x103a, 0x6e2f, 0x5e63, 0x4eba, 0x6c11,
+0x5e01, 0x50, 0x68, 0x69, 0x6c, 0x69, 0x70, 0x70, 0x69, 0x6e, 0x65, 0x20,
+0x50, 0x65, 0x73, 0x6f, 0x44, 0x65, 0x72, 0x68, 0x65, 0x6d, 0x20, 0x55,
+0x6d, 0x65, 0x1e5b, 0x1e5b, 0x75, 0x6b, 0x69, 0x62f, 0x6cc, 0x646, 0x627, 0x631,
+0x6cc, 0x20, 0x639, 0x6ce, 0x631, 0x627, 0x642, 0x6cc, 0x695, 0x6cc, 0x627, 0x6b5,
+0x6cc, 0x20, 0x626, 0x6ce, 0x631, 0x627, 0x646, 0x6cc, 0xd804, 0xdd1d, 0xd804, 0xdd01,
+0xd804, 0xdd23, 0xd804, 0xdd18, 0xd804, 0xdd2c, 0xd804, 0xdd25, 0xd804, 0xdd28, 0x20, 0xd804,
+0xdd11, 0xd804, 0xdd2c, 0xd804, 0xdd0b, 0xd804, 0xdd03, 0xd804, 0xdd28, 0xd804, 0xdd1a, 0xd804,
+0xdd34, 0xd804, 0xdd18, 0xd804, 0xdd28, 0xd804, 0xdd20, 0xd804, 0xdd1a, 0xd804, 0xdd34, 0x20,
+0xd804, 0xdd22, 0xd804, 0xdd2a, 0xd804, 0xdd1b, 0xd804, 0xdd28, 0x420, 0x43e, 0x441, 0x441,
+0x438, 0x439, 0x43d, 0x20, 0x441, 0x43e, 0x43c, 0x55, 0x53, 0x20, 0x13a0, 0x13d5,
+0x13b3, 0x45, 0x73, 0x68, 0x69, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x20, 0x79,
+0x61, 0x20, 0x55, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x6e2f, 0x5143, 0x6fb3, 0x95e8,
+0x5e01, 0x65b0, 0x52a0, 0x5761, 0x5143, 0x6fb3, 0x9580, 0x5143, 0x65b0, 0x53f0, 0x5e63, 0x440,
+0x461, 0x441, 0x441, 0x456, 0x301, 0x439, 0x441, 0x43a, 0x457, 0x439, 0x20, 0x440,
+0xa64b, 0x301, 0x431, 0x43b, 0x44c, 0x420, 0x430, 0x4ab, 0x4ab, 0x435, 0x439, 0x20,
+0x442, 0x435, 0x43d, 0x43a, 0x4d7, 0x10d, 0x65, 0x73, 0x6b, 0xe1, 0x20, 0x6b,
+0x6f, 0x72, 0x75, 0x6e, 0x61, 0x64, 0x61, 0x6e, 0x73, 0x6b, 0x20, 0x6b,
+0x72, 0x6f, 0x6e, 0x65, 0x92d, 0x93e, 0x930, 0x924, 0x940, 0x20, 0x930, 0x92a,
+0x947, 0x93d, 0x41, 0x72, 0x75, 0x62, 0x61, 0x61, 0x6e, 0x73, 0x65, 0x20,
+0x67, 0x75, 0x6c, 0x64, 0x65, 0x6e, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x6b,
+0x61, 0x61, 0x6e, 0x73, 0x65, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72,
+0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x2d, 0x41,
+0x6e, 0x74, 0x69, 0x6c, 0x6c, 0x69, 0x61, 0x61, 0x6e, 0x73, 0x65, 0x20,
+0x67, 0x75, 0x6c, 0x64, 0x65, 0x6e, 0x53, 0x75, 0x72, 0x69, 0x6e, 0x61,
+0x61, 0x6d, 0x73, 0x65, 0x20, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0xf51,
+0xf44, 0xf74, 0xf63, 0xf0b, 0xf40, 0xfb2, 0xf58, 0x53, 0x68, 0x69, 0x6c, 0x69,
+0x6e, 0x67, 0x69, 0x20, 0x79, 0x61, 0x20, 0x4b, 0x65, 0x6e, 0x79, 0x61,
+0x55, 0x53, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x45, 0x61, 0x73,
+0x74, 0x20, 0x43, 0x61, 0x72, 0x69, 0x62, 0x62, 0x65, 0x61, 0x6e, 0x20,
+0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61,
+0x6c, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x42,
+0x61, 0x68, 0x61, 0x6d, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c,
+0x61, 0x72, 0x42, 0x61, 0x72, 0x62, 0x61, 0x64, 0x69, 0x61, 0x6e, 0x20,
+0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x42, 0x65, 0x6c, 0x69, 0x7a, 0x65,
+0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x42, 0x65, 0x72, 0x6d, 0x75,
+0x64, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x42,
+0x6f, 0x74, 0x73, 0x77, 0x61, 0x6e, 0x61, 0x6e, 0x20, 0x50, 0x75, 0x6c,
+0x61, 0x42, 0x75, 0x72, 0x75, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x46,
+0x72, 0x61, 0x6e, 0x63, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20,
+0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x6e, 0x20, 0x43, 0x46, 0x41, 0x20,
+0x46, 0x72, 0x61, 0x6e, 0x63, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x69, 0x61,
+0x6e, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x43, 0x61, 0x79, 0x6d,
+0x61, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x44,
+0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x4e, 0x65, 0x77, 0x20, 0x5a, 0x65, 0x61,
+0x6c, 0x61, 0x6e, 0x64, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x44,
+0x61, 0x6e, 0x69, 0x73, 0x68, 0x20, 0x4b, 0x72, 0x6f, 0x6e, 0x65, 0x45,
+0x72, 0x69, 0x74, 0x72, 0x65, 0x61, 0x6e, 0x20, 0x4e, 0x61, 0x6b, 0x66,
+0x61, 0x53, 0x77, 0x61, 0x7a, 0x69, 0x20, 0x4c, 0x69, 0x6c, 0x61, 0x6e,
+0x67, 0x65, 0x6e, 0x69, 0x46, 0x61, 0x6c, 0x6b, 0x6c, 0x61, 0x6e, 0x64,
+0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x50, 0x6f, 0x75,
+0x6e, 0x64, 0x46, 0x69, 0x6a, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c,
+0x6c, 0x61, 0x72, 0x47, 0x61, 0x6d, 0x62, 0x69, 0x61, 0x6e, 0x20, 0x44,
+0x61, 0x6c, 0x61, 0x73, 0x69, 0x47, 0x68, 0x61, 0x6e, 0x61, 0x69, 0x61,
+0x6e, 0x20, 0x43, 0x65, 0x64, 0x69, 0x47, 0x69, 0x62, 0x72, 0x61, 0x6c,
+0x74, 0x61, 0x72, 0x20, 0x50, 0x6f, 0x75, 0x6e, 0x64, 0x55, 0x4b, 0x20,
+0x50, 0x6f, 0x75, 0x6e, 0x64, 0x47, 0x75, 0x79, 0x61, 0x6e, 0x61, 0x65,
+0x73, 0x65, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x48, 0x6f, 0x6e,
+0x67, 0x20, 0x4b, 0x6f, 0x6e, 0x67, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61,
+0x72, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x52, 0x75, 0x70, 0x65,
+0x65, 0x49, 0x6e, 0x64, 0x6f, 0x6e, 0x65, 0x73, 0x69, 0x61, 0x6e, 0x20,
+0x52, 0x75, 0x70, 0x69, 0x61, 0x68, 0x49, 0x73, 0x72, 0x61, 0x65, 0x6c,
+0x69, 0x20, 0x4e, 0x65, 0x77, 0x20, 0x53, 0x68, 0x65, 0x6b, 0x65, 0x6c,
+0x4a, 0x61, 0x6d, 0x61, 0x69, 0x63, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c,
+0x6c, 0x61, 0x72, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x6e, 0x20, 0x53, 0x68,
+0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20,
+0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x6e, 0x20, 0x52, 0x61, 0x6e, 0x64,
+0x4c, 0x69, 0x62, 0x65, 0x72, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f, 0x6c,
+0x6c, 0x61, 0x72, 0x4d, 0x61, 0x63, 0x61, 0x6e, 0x65, 0x73, 0x65, 0x20,
+0x50, 0x61, 0x74, 0x61, 0x63, 0x61, 0x4d, 0x61, 0x6c, 0x61, 0x67, 0x61,
+0x73, 0x79, 0x20, 0x41, 0x72, 0x69, 0x61, 0x72, 0x79, 0x4d, 0x61, 0x6c,
+0x61, 0x77, 0x69, 0x61, 0x6e, 0x20, 0x4b, 0x77, 0x61, 0x63, 0x68, 0x61,
+0x4d, 0x61, 0x6c, 0x61, 0x79, 0x73, 0x69, 0x61, 0x6e, 0x20, 0x52, 0x69,
+0x6e, 0x67, 0x67, 0x69, 0x74, 0x4d, 0x61, 0x6c, 0x64, 0x69, 0x76, 0x69,
+0x61, 0x6e, 0x20, 0x52, 0x75, 0x66, 0x69, 0x79, 0x61, 0x61, 0x4d, 0x61,
+0x75, 0x72, 0x69, 0x74, 0x69, 0x61, 0x6e, 0x20, 0x52, 0x75, 0x70, 0x65,
+0x65, 0x4e, 0x61, 0x6d, 0x69, 0x62, 0x69, 0x61, 0x6e, 0x20, 0x44, 0x6f,
+0x6c, 0x6c, 0x61, 0x72, 0x4e, 0x69, 0x67, 0x65, 0x72, 0x69, 0x61, 0x6e,
+0x20, 0x4e, 0x61, 0x69, 0x72, 0x61, 0x50, 0x61, 0x6b, 0x69, 0x73, 0x74,
+0x61, 0x6e, 0x69, 0x20, 0x52, 0x75, 0x70, 0x65, 0x65, 0x50, 0x61, 0x70,
+0x75, 0x61, 0x20, 0x4e, 0x65, 0x77, 0x20, 0x47, 0x75, 0x69, 0x6e, 0x65,
+0x61, 0x6e, 0x20, 0x4b, 0x69, 0x6e, 0x61, 0x52, 0x77, 0x61, 0x6e, 0x64,
+0x61, 0x6e, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x53, 0x74, 0x20, 0x48,
+0x65, 0x6c, 0x65, 0x6e, 0x61, 0x20, 0x50, 0x6f, 0x75, 0x6e, 0x64, 0x53,
+0x61, 0x6d, 0x6f, 0x61, 0x6e, 0x20, 0x54, 0x61, 0x6c, 0x61, 0x53, 0x65,
+0x79, 0x63, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x69, 0x73, 0x20, 0x52, 0x75,
+0x70, 0x65, 0x65, 0x53, 0x69, 0x65, 0x72, 0x72, 0x61, 0x20, 0x4c, 0x65,
+0x6f, 0x6e, 0x65, 0x61, 0x6e, 0x20, 0x4c, 0x65, 0x6f, 0x6e, 0x65, 0x53,
+0x69, 0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, 0x20, 0x44, 0x6f, 0x6c,
+0x6c, 0x61, 0x72, 0x4e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x61, 0x6e,
+0x64, 0x73, 0x20, 0x41, 0x6e, 0x74, 0x69, 0x6c, 0x6c, 0x65, 0x61, 0x6e,
+0x20, 0x47, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x53, 0x6f, 0x6c, 0x6f,
+0x6d, 0x6f, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x20,
+0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20,
+0x53, 0x75, 0x64, 0x61, 0x6e, 0x65, 0x73, 0x65, 0x20, 0x50, 0x6f, 0x75,
+0x6e, 0x64, 0x53, 0x75, 0x64, 0x61, 0x6e, 0x65, 0x73, 0x65, 0x20, 0x50,
+0x6f, 0x75, 0x6e, 0x64, 0x53, 0x77, 0x65, 0x64, 0x69, 0x73, 0x68, 0x20,
+0x4b, 0x72, 0x6f, 0x6e, 0x61, 0x53, 0x77, 0x69, 0x73, 0x73, 0x20, 0x46,
+0x72, 0x61, 0x6e, 0x63, 0x54, 0x61, 0x6e, 0x7a, 0x61, 0x6e, 0x69, 0x61,
+0x6e, 0x20, 0x53, 0x68, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x54, 0x6f,
+0x6e, 0x67, 0x61, 0x6e, 0x20, 0x50, 0x61, 0x2bb, 0x61, 0x6e, 0x67, 0x61,
+0x54, 0x72, 0x69, 0x6e, 0x69, 0x64, 0x61, 0x64, 0x20, 0x26, 0x20, 0x54,
+0x6f, 0x62, 0x61, 0x67, 0x6f, 0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72,
+0x55, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x6e, 0x20, 0x53, 0x68, 0x69, 0x6c,
+0x6c, 0x69, 0x6e, 0x67, 0x55, 0x6e, 0x69, 0x74, 0x65, 0x64, 0x20, 0x41,
+0x72, 0x61, 0x62, 0x20, 0x45, 0x6d, 0x69, 0x72, 0x61, 0x74, 0x65, 0x73,
+0x20, 0x44, 0x69, 0x72, 0x68, 0x61, 0x6d, 0x42, 0x72, 0x69, 0x74, 0x69,
+0x73, 0x68, 0x20, 0x50, 0x6f, 0x75, 0x6e, 0x64, 0x56, 0x61, 0x6e, 0x75,
+0x61, 0x74, 0x75, 0x20, 0x56, 0x61, 0x74, 0x75, 0x5a, 0x61, 0x6d, 0x62,
+0x69, 0x61, 0x6e, 0x20, 0x4b, 0x77, 0x61, 0x63, 0x68, 0x61, 0x67, 0x68,
+0x61, 0x6e, 0x61, 0x20, 0x73, 0x69, 0x256, 0x69, 0x263, 0x65, 0x74, 0x6f,
+0x256, 0x6f, 0x66, 0x65, 0x20, 0x61, 0x66, 0x72, 0x69, 0x6b, 0x61, 0x67,
+0x61, 0x20, 0x43, 0x46, 0x41, 0x20, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20,
+0x42, 0x43, 0x45, 0x41, 0x4f, 0x46, 0x259, 0x6c, 0xe1, 0x14b, 0x20, 0x43,
+0x46, 0x41, 0x20, 0x28, 0x42, 0x45, 0x41, 0x43, 0x29, 0x64, 0x6f, 0x6e,
+0x73, 0x6b, 0x20, 0x6b, 0x72, 0xf3, 0x6e, 0x61, 0x50, 0x69, 0x73, 0x6f,
+0x20, 0x6e, 0x67, 0x20, 0x50, 0x69, 0x6c, 0x69, 0x70, 0x69, 0x6e, 0x61,
+0x73, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x20, 0x61, 0x6c, 0x67, 0xe9, 0x72,
+0x69, 0x65, 0x6e, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x43, 0x46, 0x41,
+0x20, 0x28, 0x42, 0x43, 0x45, 0x41, 0x4f, 0x29, 0x66, 0x72, 0x61, 0x6e,
+0x63, 0x20, 0x62, 0x75, 0x72, 0x75, 0x6e, 0x64, 0x61, 0x69, 0x73, 0x66,
+0x72, 0x61, 0x6e, 0x63, 0x20, 0x43, 0x46, 0x41, 0x20, 0x28, 0x42, 0x45,
+0x41, 0x43, 0x29, 0x64, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x20, 0x63, 0x61,
+0x6e, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20,
+0x63, 0x6f, 0x6d, 0x6f, 0x72, 0x69, 0x65, 0x6e, 0x66, 0x72, 0x61, 0x6e,
+0x63, 0x20, 0x63, 0x6f, 0x6e, 0x67, 0x6f, 0x6c, 0x61, 0x69, 0x73, 0x66,
+0x72, 0x61, 0x6e, 0x63, 0x20, 0x64, 0x6a, 0x69, 0x62, 0x6f, 0x75, 0x74,
+0x69, 0x65, 0x6e, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x43, 0x46, 0x50,
+0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x67, 0x75, 0x69, 0x6e, 0xe9, 0x65,
+0x6e, 0x67, 0x6f, 0x75, 0x72, 0x64, 0x65, 0x20, 0x68, 0x61, 0xef, 0x74,
+0x69, 0x65, 0x6e, 0x6e, 0x65, 0x61, 0x72, 0x69, 0x61, 0x72, 0x79, 0x20,
+0x6d, 0x61, 0x6c, 0x67, 0x61, 0x63, 0x68, 0x65, 0x6f, 0x75, 0x67, 0x75,
+0x69, 0x79, 0x61, 0x20, 0x6d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x61, 0x6e,
+0x69, 0x65, 0x6e, 0x72, 0x6f, 0x75, 0x70, 0x69, 0x65, 0x20, 0x6d, 0x61,
+0x75, 0x72, 0x69, 0x63, 0x69, 0x65, 0x6e, 0x6e, 0x65, 0x64, 0x69, 0x72,
+0x68, 0x61, 0x6d, 0x20, 0x6d, 0x61, 0x72, 0x6f, 0x63, 0x61, 0x69, 0x6e,
+0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x72, 0x77, 0x61, 0x6e, 0x64, 0x61,
+0x69, 0x73, 0x72, 0x6f, 0x75, 0x70, 0x69, 0x65, 0x20, 0x64, 0x65, 0x73,
+0x20, 0x53, 0x65, 0x79, 0x63, 0x68, 0x65, 0x6c, 0x6c, 0x65, 0x73, 0x66,
+0x72, 0x61, 0x6e, 0x63, 0x20, 0x73, 0x75, 0x69, 0x73, 0x73, 0x65, 0x6c,
+0x69, 0x76, 0x72, 0x65, 0x20, 0x73, 0x79, 0x72, 0x69, 0x65, 0x6e, 0x6e,
+0x65, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x20, 0x74, 0x75, 0x6e, 0x69, 0x73,
+0x69, 0x65, 0x6e, 0x76, 0x61, 0x74, 0x75, 0x20, 0x76, 0x61, 0x6e, 0x75,
+0x61, 0x74, 0x75, 0x61, 0x6e, 0x4d, 0x62, 0x75, 0x75, 0x257, 0x75, 0x20,
+0x53, 0x65, 0x65, 0x66, 0x61, 0x61, 0x20, 0x42, 0x43, 0x45, 0x41, 0x4f,
+0xd83a, 0xdd0a, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0x20, 0xd83a,
+0xdd05, 0xd83a, 0xdd0a, 0xd83a, 0xdd00, 0x20, 0xd83a, 0xdd16, 0xd83a, 0xdd2d, 0xd83a, 0xdd45,
+0xd83a, 0xdd2a, 0xd83a, 0xdd32, 0xd83a, 0xdd22, 0xd83a, 0xdd44, 0xd83a, 0xdd32, 0xd83a, 0xdd3a,
+0xd83a, 0xdd2b, 0x20, 0xd83a, 0xdd00, 0xd83a, 0xdd2c, 0xd83a, 0xdd2a, 0xd83a, 0xdd2d, 0xd83a,
+0xdd33, 0xd83a, 0xdd22, 0xd83a, 0xdd0a, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd22, 0xd83a,
+0xdd32, 0x20, 0xd83a, 0xdd1a, 0xd83a, 0xdd35, 0xd83a, 0xdd26, 0xd83a, 0xdd2e, 0xd83a, 0xdd45,
+0xd83a, 0xdd2a, 0xd83a, 0xdd2d, 0x20, 0xd83a, 0xdd00, 0xd83a, 0xdd2c, 0xd83a, 0xdd2a, 0xd83a,
+0xdd2d, 0xd83a, 0xdd33, 0xd83a, 0xdd2d, 0xd83a, 0xdd32, 0xd83a, 0xdd33, 0xd83a, 0xdd2e, 0xd83a,
+0xdd01, 0xd83a, 0xdd22, 0xd83a, 0xdd24, 0xd83a, 0xdd22, 0xd83a, 0xdd27, 0xd83a, 0xdd2d, 0x20,
+0xd83a, 0xdd18, 0xd83a, 0xdd22, 0xd83a, 0xdd25, 0xd83a, 0xdd26, 0xd83a, 0xdd2d, 0xd83a, 0xdd32,
+0xd83a, 0xdd33, 0xd83a, 0xdd2e, 0xd83a, 0xdd05, 0xd83a, 0xdd2d, 0xd83a, 0xdd23, 0xd83a, 0xdd2d,
+0x20, 0xd83a, 0xdd18, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0xd83a,
+0xdd33, 0xd83a, 0xdd2e, 0xd83a, 0xdd0a, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd22, 0xd83a,
+0xdd32, 0x20, 0xd83a, 0xdd18, 0xd83a, 0xdd2d, 0xd83a, 0xdd32, 0xd83a, 0xdd2b, 0xd83a, 0xdd32,
+0xd83a, 0xdd33, 0xd83a, 0xdd2e, 0xd83a, 0xdd01, 0xd83a, 0xdd22, 0xd83a, 0xdd24, 0xd83a, 0xdd22,
+0x20, 0xd83a, 0xdd02, 0xd83a, 0xdd2d, 0xd83a, 0xdd26, 0xd83a, 0xdd2b, 0xd83a, 0xdd2a, 0xd83a,
+0xdd2d, 0xd83a, 0xdd34, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0xd83a, 0xdd33, 0xd83a, 0xdd2e, 0xd83a,
+0xdd13, 0xd83a, 0xdd3a, 0xd83a, 0xdd2d, 0xd83a, 0xdd34, 0xd83a, 0xdd22, 0x20, 0xd83a, 0xdd03,
+0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0xd83a, 0xdd2d, 0xd83a, 0xdd3c, 0xd83a, 0xdd22, 0xd83a, 0xdd32,
+0xd83a, 0xdd2d, 0xd83a, 0xdd34, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0xd83a, 0xdd33, 0xd83a, 0xdd2e,
+0xd83a, 0xdd10, 0xd83a, 0xdd22, 0xd83a, 0xdd34, 0xd83a, 0xdd2a, 0xd83a, 0xdd22, 0x20, 0xd83a,
+0xdd10, 0xd83a, 0xdd22, 0xd83a, 0xdd36, 0xd83a, 0xdd2d, 0xd83a, 0xdd2a, 0xd83a, 0xdd22, 0xd83a,
+0xdd34, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0xd83a, 0xdd33, 0xd83a, 0xdd2e, 0xd83a, 0xdd02, 0xd83a,
+0xdd2b, 0xd83a, 0xdd34, 0xd83a, 0xdd2e, 0xd83a, 0xdd32, 0x20, 0xd83a, 0xdd05, 0xd83a, 0xdd2b,
+0xd83a, 0xdd2a, 0xd83a, 0xdd22, 0xd83a, 0xdd24, 0xd83a, 0xdd2d, 0xd83a, 0xdd34, 0xd83a, 0xdd22,
+0xd83a, 0xdd32, 0xd83a, 0xdd33, 0xd83a, 0xdd2e, 0x4d, 0x62, 0x75, 0x75, 0x257, 0x69,
+0x20, 0x53, 0x65, 0x65, 0x66, 0x61, 0x61, 0x20, 0x42, 0x45, 0x41, 0x43,
+0x44, 0x61, 0x6c, 0x61, 0x73, 0x69, 0x20, 0x47, 0x61, 0x6d, 0x6d, 0x62,
+0x69, 0x44, 0x6f, 0x6c, 0x61, 0x61, 0x72, 0x20, 0x4c, 0x69, 0x62, 0x65,
+0x72, 0x69, 0x79, 0x61, 0x61, 0x55, 0x67, 0x69, 0x79, 0x79, 0x61, 0x20,
+0x4d, 0x75, 0x72, 0x69, 0x74, 0x61, 0x6e, 0x69, 0x4e, 0x61, 0x79, 0x72,
+0x61, 0x61, 0x20, 0x4e, 0x69, 0x6a, 0x65, 0x72, 0x69, 0x79, 0x61, 0x61,
+0x4c, 0x65, 0x77, 0x6f, 0x6f, 0x6e, 0x20, 0x53, 0x65, 0x72, 0x61, 0x61,
+0x20, 0x4c, 0x69, 0x79, 0x6f, 0x6e, 0x50, 0x75, 0x6e, 0x6e, 0x64, 0x20,
+0x53, 0x61, 0x73, 0x61, 0x6e, 0x6e, 0x61, 0x63, 0x68, 0x53, 0x69, 0x6c,
+0x69, 0x6e, 0x67, 0x69, 0x20, 0x65, 0x79, 0x61, 0x20, 0x59, 0x75, 0x67,
+0x61, 0x6e, 0x64, 0x61, 0x10e5, 0x10d0, 0x10e0, 0x10d7, 0x10e3, 0x10da, 0x10d8, 0x20,
+0x10da, 0x10d0, 0x10e0, 0x10d8, 0x53, 0x63, 0x68, 0x77, 0x65, 0x69, 0x7a, 0x65,
+0x72, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x6b, 0x65, 0x6e, 0x395, 0x3c5, 0x3c1,
+0x3ce, 0xaad, 0xabe, 0xab0, 0xaa4, 0xac0, 0xaaf, 0x20, 0xab0, 0xac2, 0xaaa, 0xabf,
+0xaaf, 0xabe, 0x4e, 0x61, 0x69, 0x72, 0x61, 0x72, 0x20, 0x4e, 0x61, 0x6a,
+0x65, 0x72, 0x69, 0x79, 0x61, 0x646, 0x64e, 0x64a, 0x652, 0x631, 0x64e, 0x53,
+0x69, 0x64, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x47, 0x68, 0x61, 0x6e, 0x61,
+0x4b, 0x75, 0x257, 0x69, 0x6e, 0x20, 0x53, 0x65, 0x66, 0x61, 0x20, 0x6e,
+0x61, 0x20, 0x41, 0x66, 0x69, 0x72, 0x6b, 0x61, 0x20, 0x54, 0x61, 0x20,
+0x59, 0x61, 0x6d, 0x6d, 0x61, 0x5e9, 0x5e7, 0x5dc, 0x20, 0x5d7, 0x5d3, 0x5e9,
+0x92d, 0x93e, 0x930, 0x924, 0x940, 0x92f, 0x20, 0x930, 0x941, 0x92a, 0x92f, 0x93e,
+0x6d, 0x61, 0x67, 0x79, 0x61, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x69, 0x6e,
+0x74, 0xed, 0x73, 0x6c, 0x65, 0x6e, 0x73, 0x6b, 0x20, 0x6b, 0x72, 0xf3,
+0x6e, 0x61, 0x4e, 0x61, 0x1ecb, 0x72, 0x61, 0x52, 0x75, 0x70, 0x69, 0x61,
+0x68, 0x20, 0x49, 0x6e, 0x64, 0x6f, 0x6e, 0x65, 0x73, 0x69, 0x61, 0x50,
+0x75, 0x6e, 0x74, 0x20, 0x53, 0x74, 0x65, 0x69, 0x72, 0x6c, 0x69, 0x6e,
+0x67, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x6f, 0x20, 0x73, 0x76, 0x69, 0x7a,
+0x7a, 0x65, 0x72, 0x6f, 0x65e5, 0x672c, 0x5186, 0x41, 0x331, 0x6e, 0x61, 0x69,
+0x72, 0x61, 0x73, 0x65, 0x65, 0x66, 0x61, 0x20, 0x79, 0x61, 0x74, 0x69,
+0x20, 0x42, 0x43, 0x45, 0x41, 0x4f, 0x53, 0x6b, 0x75, 0x64, 0x75, 0x20,
+0x4b, 0x61, 0x62, 0x75, 0x76, 0x65, 0x72, 0x64, 0x69, 0x61, 0x6e, 0x75,
+0x41, 0x64, 0x69, 0x6e, 0x61, 0x72, 0x20, 0x41, 0x7a, 0x7a, 0x61, 0x79,
+0x72, 0x69, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x43, 0x46, 0x41, 0x64,
+0x61, 0x6e, 0x6d, 0x61, 0x72, 0x6b, 0x69, 0x6d, 0x75, 0x74, 0x20, 0x6b,
+0x6f, 0x72, 0x75, 0x75, 0x6e, 0x69, 0x53, 0x69, 0x6c, 0x69, 0x6e, 0x67,
+0x69, 0x74, 0x61, 0x62, 0x20, 0x79, 0x61, 0x20, 0x4b, 0x65, 0x6e, 0x79,
+0x61, 0x53, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x69, 0x20, 0x79, 0x61, 0x20,
+0x4b, 0x65, 0x6e, 0x79, 0x61, 0xcad, 0xcbe, 0xcb0, 0xca4, 0xcc0, 0xcaf, 0x20,
+0xcb0, 0xcc2, 0xcaa, 0xcbe, 0xcaf, 0xcbf, 0x6c1, 0x650, 0x646, 0x62f, 0x64f, 0x633,
+0x62a, 0x672, 0x646, 0x6cd, 0x20, 0x631, 0x6c4, 0x67e, 0x64e, 0x6d2, 0x907, 0x902,
+0x921, 0x93f, 0x92f, 0x928, 0x20, 0x930, 0x942, 0x92a, 0x940, 0x49a, 0x430, 0x437,
+0x430, 0x49b, 0x441, 0x442, 0x430, 0x43d, 0x20, 0x442, 0x435, 0x4a3, 0x433, 0x435,
+0x441, 0x456, 0x179a, 0x17c0, 0x179b, 0x200b, 0x1780, 0x1798, 0x17d2, 0x1796, 0x17bb, 0x1787,
+0x17b6, 0x43, 0x69, 0x72, 0x69, 0x6e, 0x67, 0x69, 0x20, 0x79, 0x61, 0x20,
+0x4b, 0x65, 0x6e, 0x79, 0x61, 0xb300, 0xd55c, 0xbbfc, 0xad6d, 0x20, 0xc6d0, 0xc911,
+0xad6d, 0x20, 0xc704, 0xc548, 0xd654, 0xc870, 0xc120, 0x20, 0xbbfc, 0xc8fc, 0xc8fc, 0xc758,
+0x20, 0xc778, 0xbbfc, 0x20, 0xacf5, 0xd654, 0xad6d, 0x20, 0xc6d0, 0x43, 0x46, 0x41,
+0x20, 0x46, 0x72, 0x61, 0x14b, 0x20, 0x28, 0x42, 0x43, 0x45, 0x41, 0x4f,
+0x29, 0x6c, 0xee, 0x72, 0x65, 0x79, 0xea, 0x20, 0x74, 0x69, 0x72, 0x6b,
+0xee, 0x46, 0x72, 0x61, 0x14b, 0x20, 0x43, 0x46, 0x41, 0x20, 0x42, 0x45,
+0x41, 0x43, 0x41a, 0x44b, 0x440, 0x433, 0x44b, 0x437, 0x441, 0x442, 0x430, 0x43d,
+0x20, 0x441, 0x43e, 0x43c, 0x443, 0x53, 0x68, 0x69, 0x6c, 0xed, 0x69, 0x6e,
+0x67, 0x69, 0x20, 0x79, 0x61, 0x20, 0x54, 0x61, 0x61, 0x6e, 0x73, 0x61,
+0x6e, 0xed, 0x61, 0xea5, 0xeb2, 0xea7, 0x20, 0xe81, 0xeb5, 0xe9a, 0x65, 0x69,
+0x72, 0x6f, 0x46, 0x61, 0x6c, 0xe1, 0x6e, 0x67, 0x61, 0x20, 0x79, 0x61,
+0x20, 0x4b, 0x6f, 0x6e, 0x67, 0xf3, 0x4b, 0x77, 0x61, 0x6e, 0x7a, 0x61,
+0x20, 0x79, 0x61, 0x20, 0x41, 0x6e, 0x67, 0xf3, 0x6c, 0x61, 0x46, 0x61,
+0x6c, 0xe1, 0x6e, 0x67, 0x61, 0x20, 0x43, 0x46, 0x41, 0x20, 0x42, 0x45,
+0x41, 0x43, 0x45, 0x75, 0x72, 0x61, 0x73, 0x4e, 0x66, 0x61, 0x6c, 0x61,
+0x6e, 0x67, 0x61, 0x20, 0x77, 0x61, 0x20, 0x4b, 0x6f, 0x6e, 0x67, 0x75,
+0x53, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x61, 0x72, 0x20, 0x4b,
+0x65, 0x6e, 0x79, 0x61, 0x53, 0x69, 0x72, 0x69, 0x6e, 0x6a, 0x69, 0x20,
+0x79, 0x61, 0x20, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x41c, 0x430, 0x43a, 0x435,
+0x434, 0x43e, 0x43d, 0x441, 0x43a, 0x438, 0x20, 0x434, 0x435, 0x43d, 0x430, 0x440,
+0x53, 0x68, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x69, 0x20, 0x79, 0x61, 0x20,
+0x54, 0x61, 0x6e, 0x7a, 0x61, 0x6e, 0x69, 0x61, 0xd07, 0xd28, 0xd4d, 0xd24,
+0xd4d, 0xd2f, 0xd7b, 0x20, 0xd30, 0xd42, 0xd2a, 0x52, 0x69, 0x6e, 0x67, 0x67,
+0x69, 0x74, 0x20, 0x4d, 0x61, 0x6c, 0x61, 0x79, 0x73, 0x69, 0x61, 0x62f,
+0x648, 0x644, 0x631, 0x20, 0x628, 0x631, 0x648, 0x646, 0x64a, 0x631, 0x64a, 0x6a0,
+0x762, 0x64a, 0x62a, 0x20, 0x645, 0x644, 0x64a, 0x633, 0x64a, 0x627, 0x44, 0x6f,
+0x6c, 0x61, 0x72, 0x20, 0x42, 0x72, 0x75, 0x6e, 0x65, 0x69, 0x44, 0x6f,
+0x6c, 0x61, 0x72, 0x20, 0x53, 0x69, 0x6e, 0x67, 0x61, 0x70, 0x75, 0x72,
+0x61, 0x65, 0x77, 0x72, 0x6f, 0x987, 0x9a8, 0x9cd, 0x9a6, 0x9bf, 0x9af, 0x9bc,
+0x9be, 0x9a8, 0x20, 0x9b0, 0x9c1, 0x9aa, 0x9c0, 0x54, 0x101, 0x72, 0x61, 0x20,
+0x6f, 0x20, 0x41, 0x6f, 0x74, 0x65, 0x61, 0x72, 0x6f, 0x61, 0x49, 0x72,
+0x6f, 0x70, 0x69, 0x79, 0x69, 0x61, 0x6e, 0xed, 0x20, 0x65, 0x20, 0x4b,
+0x65, 0x6e, 0x79, 0x61, 0x49, 0x72, 0x6f, 0x70, 0x69, 0x79, 0x69, 0x61,
+0x6e, 0xed, 0x20, 0x65, 0x20, 0x54, 0x61, 0x6e, 0x7a, 0x61, 0x6e, 0x69,
+0x61, 0x627, 0x6cc, 0x631, 0x627, 0x646, 0x20, 0x631, 0x6cc, 0x627, 0x644, 0x73,
+0x68, 0x69, 0x72, 0xe8, 0x41c, 0x43e, 0x43d, 0x433, 0x43e, 0x43b, 0x20, 0x442,
+0x4e9, 0x433, 0x440, 0x4e9, 0x433, 0x44e, 0x430, 0x43d, 0x44c, 0x1833, 0x1825, 0x182c,
+0x1825, 0x1837, 0x1822, 0x182d, 0x180c, 0x72, 0x6f, 0x75, 0x70, 0x69, 0x20, 0x6d,
+0x6f, 0x72, 0x69, 0x73, 0x69, 0x65, 0x6e, 0x73, 0x6f, 0x6c, 0x61, 0x69,
+0x20, 0x42, 0x45, 0x41, 0x43, 0x4e, 0x61, 0x6d, 0x69, 0x62, 0x69, 0x61,
+0x20, 0x44, 0x6f, 0x6c, 0x6c, 0x61, 0x72, 0x69, 0x928, 0x947, 0x92a, 0x93e,
+0x932, 0x940, 0x20, 0x930, 0x942, 0x92a, 0x948, 0x92f, 0x93e, 0x901, 0x92d, 0x93e,
+0x930, 0x924, 0x940, 0x92f, 0x20, 0x930, 0x942, 0x92a, 0x93f, 0x901, 0x92f, 0x93e,
+0x66, 0x65, 0x6c, 0xe1, 0x14b, 0x20, 0x43, 0x46, 0x41, 0x46, 0x25b, 0x6c,
+0xe2, 0x14b, 0x4e, 0x61, 0x69, 0x6a, 0xed, 0x72, 0x69, 0xe1, 0x20, 0x4e,
+0x61, 0xed, 0x72, 0x61, 0x7d6, 0x7cc, 0x7ec, 0x7e3, 0x7cd, 0x7ec, 0x7de, 0x7ca,
+0x20, 0x7df, 0x7ce, 0x7ec, 0x20, 0x7df, 0x7ca, 0x7eb, 0x20, 0x7dd, 0x7ca, 0x7d9,
+0x7ca, 0x7f2, 0x6e, 0x6f, 0x72, 0x67, 0x67, 0x61, 0x20, 0x6b, 0x72, 0x75,
+0x76, 0x64, 0x6e, 0x6f, 0x72, 0x75, 0x6f, 0x167, 0x167, 0x61, 0x20, 0x6b,
+0x72, 0x75, 0x76, 0x64, 0x6e, 0x6f, 0x44, 0x6f, 0x6c, 0x61, 0x20, 0x79,
+0x61, 0x73, 0x65, 0x20, 0x41, 0x6d, 0x65, 0x6c, 0x69, 0x6b, 0x61, 0x6e,
+0x6f, 0x72, 0x73, 0x6b, 0x65, 0x20, 0x6b, 0x72, 0x6f, 0x6e, 0x65, 0x72,
+0xb2d, 0xb3e, 0xb30, 0xb24, 0xb40, 0xb5f, 0x20, 0xb1f, 0xb19, 0xb4d, 0xb15, 0xb3e,
+0x49, 0x74, 0x6f, 0x6f, 0x70, 0x68, 0x69, 0x79, 0x61, 0x61, 0x20, 0x42,
+0x69, 0x72, 0x72, 0x69, 0x69, 0x41b, 0x430, 0x440, 0x421, 0x43e, 0x43c, 0x46,
+0x6c, 0x6f, 0x72, 0x69, 0x6e, 0x46, 0x6c, 0x6f, 0x72, 0x69, 0x6e, 0x20,
+0x64, 0x69, 0x20, 0x41, 0x72, 0x75, 0x62, 0x61, 0x627, 0x641, 0x63a, 0x627,
+0x646, 0x6cd, 0x67e, 0x627, 0x6a9, 0x633, 0x62a, 0x627, 0x646, 0x6cd, 0x20, 0x6a9,
+0x644, 0x62f, 0x627, 0x631, 0x647, 0x631, 0x6cc, 0x627, 0x644, 0x20, 0x627, 0x6cc,
+0x631, 0x627, 0x646, 0x627, 0x641, 0x63a, 0x627, 0x646, 0x6cc, 0x20, 0x627, 0x641,
+0x63a, 0x627, 0x646, 0x633, 0x62a, 0x627, 0x646, 0x7a, 0x142, 0x6f, 0x74, 0x79,
+0x20, 0x70, 0x6f, 0x6c, 0x73, 0x6b, 0x69, 0x52, 0x65, 0x61, 0x6c, 0x20,
+0x62, 0x72, 0x61, 0x73, 0x69, 0x6c, 0x65, 0x69, 0x72, 0x6f, 0x6b, 0x77,
+0x61, 0x6e, 0x7a, 0x61, 0x20, 0x61, 0x6e, 0x67, 0x6f, 0x6c, 0x61, 0x6e,
+0x6f, 0x65, 0x73, 0x63, 0x75, 0x64, 0x6f, 0x20, 0x63, 0x61, 0x62, 0x6f,
+0x2d, 0x76, 0x65, 0x72, 0x64, 0x69, 0x61, 0x6e, 0x6f, 0x66, 0x72, 0x61,
+0x6e, 0x63, 0x6f, 0x20, 0x43, 0x46, 0x41, 0x20, 0x28, 0x42, 0x45, 0x41,
+0x43, 0x29, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x6f, 0x20, 0x43, 0x46, 0x41,
+0x20, 0x28, 0x42, 0x43, 0x45, 0x41, 0x4f, 0x29, 0x70, 0x61, 0x74, 0x61,
+0x63, 0x61, 0x20, 0x6d, 0x61, 0x63, 0x61, 0x65, 0x6e, 0x73, 0x65, 0x6d,
+0x65, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x6f, 0xe7, 0x61, 0x6d,
+0x62, 0x69, 0x63, 0x61, 0x6e, 0x6f, 0x64, 0x6f, 0x62, 0x72, 0x61, 0x20,
+0x64, 0x65, 0x20, 0x53, 0xe3, 0x6f, 0x20, 0x54, 0x6f, 0x6d, 0xe9, 0x20,
+0x65, 0x20, 0x50, 0x72, 0xed, 0x6e, 0x63, 0x69, 0x70, 0x65, 0x66, 0x72,
+0x61, 0x6e, 0x63, 0x6f, 0x20, 0x73, 0x75, 0xed, 0xe7, 0x6f, 0x64, 0xf3,
+0x6c, 0x61, 0x72, 0x20, 0x64, 0x6f, 0x73, 0x20, 0x45, 0x73, 0x74, 0x61,
+0x64, 0x6f, 0x73, 0x20, 0x55, 0x6e, 0x69, 0x64, 0x6f, 0x73, 0xa2d, 0xa3e,
+0xa30, 0xa24, 0xa40, 0x20, 0xa30, 0xa41, 0xa2a, 0xa07, 0xa06, 0x631, 0x648, 0x67e,
+0x626, 0x6cc, 0x6c1, 0x53, 0x6f, 0x6c, 0x20, 0x50, 0x65, 0x72, 0x75, 0x61,
+0x6e, 0x6f, 0x42, 0x6f, 0x6c, 0x69, 0x76, 0x69, 0x61, 0x6e, 0x6f, 0x44,
+0xf3, 0x6c, 0x61, 0x72, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
+0x6e, 0x6f, 0x6c, 0x65, 0x75, 0x20, 0x72, 0x6f, 0x6d, 0xe2, 0x6e, 0x65,
+0x73, 0x63, 0x6c, 0x65, 0x75, 0x20, 0x6d, 0x6f, 0x6c, 0x64, 0x6f, 0x76,
+0x65, 0x6e, 0x65, 0x73, 0x63, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x20, 0x73,
+0x76, 0x69, 0x7a, 0x7a, 0x65, 0x72, 0x68, 0x65, 0x6c, 0x65, 0x72, 0x69,
+0x20, 0x73, 0x61, 0x20, 0x54, 0x61, 0x6e, 0x7a, 0x61, 0x6e, 0x69, 0x61,
+0x49, 0x66, 0x61, 0x72, 0x61, 0x6e, 0x67, 0x61, 0x20, 0x72, 0x79, 0x2019,
+0x55, 0x62, 0x75, 0x72, 0x75, 0x6e, 0x64, 0x69, 0x440, 0x43e, 0x441, 0x441,
+0x438, 0x439, 0x441, 0x43a, 0x438, 0x439, 0x20, 0x440, 0x443, 0x431, 0x43b, 0x44c,
+0x431, 0x435, 0x43b, 0x43e, 0x440, 0x443, 0x441, 0x441, 0x43a, 0x438, 0x439, 0x20,
+0x440, 0x443, 0x431, 0x43b, 0x44c, 0x43a, 0x430, 0x437, 0x430, 0x445, 0x441, 0x43a,
+0x438, 0x439, 0x20, 0x442, 0x435, 0x43d, 0x433, 0x435, 0x43a, 0x438, 0x440, 0x433,
+0x438, 0x437, 0x441, 0x43a, 0x438, 0x439, 0x20, 0x441, 0x43e, 0x43c, 0x43c, 0x43e,
+0x43b, 0x434, 0x430, 0x432, 0x441, 0x43a, 0x438, 0x439, 0x20, 0x43b, 0x435, 0x439,
+0x443, 0x43a, 0x440, 0x430, 0x438, 0x43d, 0x441, 0x43a, 0x430, 0x44f, 0x20, 0x433,
+0x440, 0x438, 0x432, 0x43d, 0x430, 0x410, 0x440, 0x430, 0x441, 0x441, 0x44b, 0x44b,
+0x439, 0x430, 0x20, 0x441, 0x43e, 0x43b, 0x43a, 0x443, 0x43e, 0x431, 0x430, 0x439,
+0x430, 0x4e, 0x6a, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x69, 0x20, 0x65, 0x65,
+0x6c, 0x20, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x66, 0x61, 0x72, 0xe2, 0x6e,
+0x67, 0x61, 0x20, 0x43, 0x46, 0x41, 0x20, 0x28, 0x42, 0x45, 0x41, 0x43,
+0x29, 0x49, 0x68, 0x65, 0x6c, 0x61, 0x20, 0x79, 0x61, 0x20, 0x54, 0x61,
+0x6e, 0x73, 0x61, 0x6e, 0x69, 0x79, 0x61, 0x92d, 0x93e, 0x930, 0x924, 0x940,
+0x92f, 0x20, 0x930, 0x942, 0x92a, 0x94d, 0x92f, 0x915, 0x92e, 0x94d, 0x1c65, 0x1c64,
+0x1c67, 0x1c5a, 0x1c5b, 0x20, 0x1c68, 0x1c6e, 0x1c71, 0x1c5f, 0x1c5c, 0x20, 0x1c74, 0x1c5f,
+0x1c60, 0x1c5f, 0xe8, 0x75, 0x72, 0x6f, 0x4d, 0x65, 0x74, 0x69, 0x63, 0x61,
+0x6c, 0x20, 0x64, 0x65, 0x20, 0x4d, 0x6f, 0xe7, 0x61, 0x6d, 0x62, 0x69,
+0x71, 0x75, 0x65, 0x441, 0x440, 0x43f, 0x441, 0x43a, 0x438, 0x20, 0x434, 0x438,
+0x43d, 0x430, 0x440, 0x411, 0x43e, 0x441, 0x430, 0x43d, 0x441, 0x43a, 0x43e, 0x445,
+0x435, 0x440, 0x446, 0x435, 0x433, 0x43e, 0x432, 0x430, 0x447, 0x43a, 0x430, 0x20,
+0x43a, 0x43e, 0x43d, 0x432, 0x435, 0x440, 0x442, 0x438, 0x431, 0x438, 0x43b, 0x43d,
+0x430, 0x20, 0x43c, 0x430, 0x440, 0x43a, 0x430, 0x415, 0x432, 0x440, 0x43e, 0x45,
+0x76, 0x72, 0x6f, 0x73, 0x72, 0x70, 0x73, 0x6b, 0x69, 0x20, 0x64, 0x69,
+0x6e, 0x61, 0x72, 0x73, 0x68, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x69, 0x20,
+0x79, 0x61, 0x20, 0x54, 0x61, 0x6e, 0x7a, 0x61, 0x6e, 0x69, 0x61, 0x44,
+0x6f, 0x72, 0x61, 0x20, 0x72, 0x65, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69,
+0x6b, 0x61, 0x67e, 0x627, 0x6aa, 0x633, 0x62a, 0x627, 0x646, 0x64a, 0x20, 0x631,
+0x67e, 0x64a, 0x939, 0x93f, 0x902, 0x926, 0x941, 0x938, 0x94d, 0x924, 0x93e, 0x928,
+0x940, 0x20, 0x930, 0x941, 0x92a, 0x92f, 0x94b, 0xdc1, 0xdca, 0x200d, 0xdbb, 0xdd3,
+0x20, 0xdbd, 0xd82, 0xd9a, 0xdcf, 0x20, 0xdbb, 0xdd4, 0xdb4, 0xdd2, 0xdba, 0xdbd,
+0x65, 0x76, 0x72, 0x6f, 0x53, 0x68, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x6b,
+0x61, 0x20, 0x53, 0x6f, 0x6f, 0x6d, 0x61, 0x61, 0x6c, 0x69, 0x79, 0x61,
+0x46, 0x61, 0x72, 0x61, 0x6e, 0x20, 0x4a, 0x61, 0x62, 0x75, 0x75, 0x74,
+0x69, 0x42, 0x69, 0x72, 0x74, 0x61, 0x20, 0x49, 0x74, 0x6f, 0x6f, 0x62,
+0x62, 0x69, 0x79, 0x61, 0x53, 0x68, 0x69, 0x6c, 0x69, 0x6e, 0x67, 0x6b,
+0x61, 0x20, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x70, 0x65, 0x73, 0x6f, 0x20,
+0x61, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x6f, 0x64, 0xf3, 0x6c,
+0x61, 0x72, 0x20, 0x62, 0x65, 0x6c, 0x69, 0x63, 0x65, 0xf1, 0x6f, 0x62,
+0x6f, 0x6c, 0x69, 0x76, 0x69, 0x61, 0x6e, 0x6f, 0x72, 0x65, 0x61, 0x6c,
+0x20, 0x62, 0x72, 0x61, 0x73, 0x69, 0x6c, 0x65, 0xf1, 0x6f, 0x50, 0x65,
+0x73, 0x6f, 0x20, 0x63, 0x68, 0x69, 0x6c, 0x65, 0x6e, 0x6f, 0x70, 0x65,
+0x73, 0x6f, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x6d, 0x62, 0x69, 0x61, 0x6e,
+0x6f, 0x63, 0x6f, 0x6c, 0xf3, 0x6e, 0x20, 0x63, 0x6f, 0x73, 0x74, 0x61,
+0x72, 0x72, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x70, 0x65, 0x73, 0x6f,
+0x20, 0x63, 0x75, 0x62, 0x61, 0x6e, 0x6f, 0x70, 0x65, 0x73, 0x6f, 0x20,
+0x64, 0x6f, 0x6d, 0x69, 0x6e, 0x69, 0x63, 0x61, 0x6e, 0x6f, 0x64, 0xf3,
+0x6c, 0x61, 0x72, 0x20, 0x65, 0x73, 0x74, 0x61, 0x64, 0x6f, 0x75, 0x6e,
+0x69, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x66, 0x72, 0x61, 0x6e, 0x63, 0x6f,
+0x20, 0x43, 0x46, 0x41, 0x20, 0x64, 0x65, 0x20, 0xc1, 0x66, 0x72, 0x69,
+0x63, 0x61, 0x20, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x71, 0x75,
+0x65, 0x74, 0x7a, 0x61, 0x6c, 0x6c, 0x65, 0x6d, 0x70, 0x69, 0x72, 0x61,
+0x20, 0x68, 0x6f, 0x6e, 0x64, 0x75, 0x72, 0x65, 0xf1, 0x6f, 0x70, 0x65,
+0x73, 0x6f, 0x20, 0x6d, 0x65, 0x78, 0x69, 0x63, 0x61, 0x6e, 0x6f, 0x63,
+0xf3, 0x72, 0x64, 0x6f, 0x62, 0x61, 0x20, 0x6e, 0x69, 0x63, 0x61, 0x72,
+0x61, 0x67, 0xfc, 0x65, 0x6e, 0x73, 0x65, 0x62, 0x61, 0x6c, 0x62, 0x6f,
+0x61, 0x20, 0x70, 0x61, 0x6e, 0x61, 0x6d, 0x65, 0xf1, 0x6f, 0x67, 0x75,
+0x61, 0x72, 0x61, 0x6e, 0xed, 0x20, 0x70, 0x61, 0x72, 0x61, 0x67, 0x75,
+0x61, 0x79, 0x6f, 0x73, 0x6f, 0x6c, 0x20, 0x70, 0x65, 0x72, 0x75, 0x61,
+0x6e, 0x6f, 0x70, 0x65, 0x73, 0x6f, 0x20, 0x66, 0x69, 0x6c, 0x69, 0x70,
+0x69, 0x6e, 0x6f, 0x70, 0x65, 0x73, 0x6f, 0x20, 0x75, 0x72, 0x75, 0x67,
+0x75, 0x61, 0x79, 0x6f, 0x62, 0x6f, 0x6c, 0xed, 0x76, 0x61, 0x72, 0x20,
+0x73, 0x6f, 0x62, 0x65, 0x72, 0x61, 0x6e, 0x6f, 0x2d30, 0x2d37, 0x2d54, 0x2d49,
+0x2d4e, 0x20, 0x2d4f, 0x20, 0x2d4d, 0x2d4e, 0x2d56, 0x2d54, 0x2d49, 0x2d31, 0x52, 0x75,
+0x70, 0x65, 0x65, 0x20, 0x49, 0x6e, 0x64, 0x6f, 0x6e, 0xe9, 0x73, 0x69,
+0x61, 0x46, 0x61, 0x72, 0x61, 0x6e, 0x67, 0x61, 0x20, 0x79, 0x61, 0x20,
+0x4b, 0x6f, 0x6e, 0x67, 0x6f, 0x53, 0x68, 0x69, 0x6c, 0x69, 0x6e, 0x67,
+0x69, 0x20, 0x79, 0x61, 0x20, 0x55, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x73,
+0x76, 0x65, 0x6e, 0x73, 0x6b, 0x20, 0x6b, 0x72, 0x6f, 0x6e, 0x61, 0x53,
+0x63, 0x68, 0x77, 0x69, 0x69, 0x7a, 0x65, 0x72, 0x20, 0x46, 0x72, 0x61,
+0x6e, 0x6b, 0x65, 0x61, 0x64, 0x72, 0x69, 0x6d, 0x20, 0x6e, 0x20, 0x6c,
+0x6d, 0x263, 0x72, 0x69, 0x62, 0x421, 0x43e, 0x43c, 0x43e, 0x43d, 0x4e3, 0xb87,
+0xba8, 0xbcd, 0xba4, 0xbbf, 0xbaf, 0x20, 0xbb0, 0xbc2, 0xbaa, 0xbbe, 0xbaf, 0xbcd,
+0xbae, 0xbb2, 0xbc7, 0xbb7, 0xbbf, 0xbaf, 0xba9, 0xbcd, 0x20, 0xbb0, 0xbbf, 0xb99,
+0xbcd, 0xb95, 0xbbf, 0xb9f, 0xbcd, 0xb9a, 0xbbf, 0xb99, 0xbcd, 0xb95, 0xbaa, 0xbcd,
+0xbaa, 0xbc2, 0xbb0, 0xbcd, 0x20, 0xb9f, 0xbbe, 0xbb2, 0xbb0, 0xbcd, 0xb87, 0xbb2,
+0xb99, 0xbcd, 0xb95, 0xbc8, 0x20, 0xbb0, 0xbc2, 0xbaa, 0xbbe, 0xbaf, 0xbcd, 0x70,
+0x69, 0x6c, 0x61, 0x20, 0x54, 0x61, 0x69, 0x77, 0x61, 0x6e, 0x420, 0x43e,
+0x441, 0x441, 0x438, 0x44f, 0x20, 0x441, 0x443, 0x43c, 0x44b, 0xc2d, 0xc3e, 0xc30,
+0xc24, 0xc26, 0xc47, 0xc36, 0x20, 0xc30, 0xc42, 0xc2a, 0xc3e, 0xc2f, 0xc3f, 0x41,
+0x6e, 0x67, 0x6f, 0x2019, 0x6f, 0x74, 0x6f, 0x6c, 0x20, 0x6c, 0x6f, 0x6b,
+0x2019, 0x20, 0x55, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x41, 0x6e, 0x67, 0x6f,
+0x2019, 0x6f, 0x74, 0x6f, 0x6c, 0x20, 0x6c, 0x6f, 0x6b, 0x2019, 0x20, 0x4b,
+0x65, 0x6e, 0x79, 0x61, 0xe1a, 0xe32, 0xe17, 0xf61, 0xf74, 0xf0b, 0xf68, 0xf53,
+0xf0b, 0xf62, 0xf92, 0xfb1, 0xf0b, 0xf42, 0xf62, 0xf0b, 0xf66, 0xf92, 0xf7c, 0xf62,
+0xf0b, 0x1293, 0x1255, 0x134b, 0x50, 0x61, 0x2bb, 0x61, 0x6e, 0x67, 0x61, 0x20,
+0x66, 0x61, 0x6b, 0x61, 0x74, 0x6f, 0x6e, 0x67, 0x61, 0x54, 0xfc, 0x72,
+0x6b, 0x20, 0x6c, 0x69, 0x72, 0x61, 0x73, 0x131, 0x54, 0xfc, 0x72, 0x6b,
+0x6d, 0x65, 0x6e, 0x20, 0x6d, 0x61, 0x6e, 0x61, 0x64, 0x79, 0x4e, 0x65,
+0x72, 0x61, 0x443, 0x43a, 0x440, 0x430, 0x457, 0x43d, 0x441, 0x44c, 0x43a, 0x430,
+0x20, 0x433, 0x440, 0x438, 0x432, 0x43d, 0x44f, 0x67e, 0x627, 0x6a9, 0x633, 0x62a,
+0x627, 0x646, 0x6cc, 0x20, 0x631, 0x648, 0x67e, 0x6cc, 0x6c1, 0x628, 0x6be, 0x627,
+0x631, 0x62a, 0x6cc, 0x20, 0x631, 0x648, 0x67e, 0x6cc, 0x6c1, 0x62c, 0x6c7, 0x6ad,
+0x6af, 0x648, 0x20, 0x64a, 0x6c8, 0x6d5, 0x646, 0x649, 0x4f, 0x2018, 0x7a, 0x62,
+0x65, 0x6b, 0x69, 0x73, 0x74, 0x6f, 0x6e, 0x20, 0x73, 0x6f, 0x2018, 0x6d,
+0x69, 0x40e, 0x437, 0x431, 0x435, 0x43a, 0x438, 0x441, 0x442, 0x43e, 0x43d, 0x20,
+0x441, 0x45e, 0x43c, 0xa55e, 0xa524, 0xa52b, 0xa569, 0x20, 0xa55c, 0xa55e, 0xa54c, 0x4c,
+0x61, 0x69, 0x62, 0x68, 0x69, 0x79, 0x61, 0x20, 0x44, 0x61, 0x6c, 0x61,
+0x110, 0x1ed3, 0x6e, 0x67, 0x20, 0x56, 0x69, 0x1ec7, 0x74, 0x20, 0x4e, 0x61,
+0x6d, 0x50, 0x75, 0x6e, 0x74, 0x20, 0x50, 0x72, 0x79, 0x64, 0x61, 0x69,
+0x6e, 0x67e, 0x627, 0x6a9, 0x633, 0x62a, 0x627, 0x646, 0x626, 0x20, 0x631, 0x648,
+0x67e, 0x6cc, 0x627, 0x648, 0x6af, 0x627, 0x646, 0x633, 0x62a, 0x627, 0x646, 0x626,
+0x20, 0x627, 0x648, 0x6af, 0x627, 0x646, 0x6cc, 0x627, 0x6cc, 0x631, 0x627, 0x646,
+0x626, 0x20, 0x631, 0x6cc, 0x627, 0x644, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x20,
+0x43, 0x46, 0x41, 0x20, 0x62, 0x75, 0x20, 0x41, 0x66, 0x72, 0x69, 0x6b,
+0x20, 0x53, 0x6f, 0x77, 0x77, 0x75, 0x2d, 0x6a, 0x61, 0x6e, 0x74, 0x49,
+0x52, 0x61, 0x6e, 0x64, 0x69, 0x20, 0x79, 0x61, 0x73, 0x65, 0x4d, 0x7a,
+0x61, 0x6e, 0x74, 0x73, 0x69, 0x20, 0x41, 0x66, 0x72, 0x69, 0x6b, 0x61,
+0x4e, 0xe1, 0xed, 0x72, 0xe0, 0x20, 0x4e, 0xe0, 0xec, 0x6a, 0xed, 0x72,
+0xed, 0xe0, 0x46, 0x61, 0x72, 0x61, 0x6e, 0x73, 0xec, 0x20, 0xec, 0x77,
+0x254, 0x300, 0x2d, 0x6f, 0x6f, 0x72, 0xf9, 0x6e, 0x20, 0x41, 0x66, 0xed,
+0x72, 0xed, 0x6b, 0xe0, 0x79, 0x69, 0x6e, 0x7a, 0x6d, 0x69, 0x6e, 0x7a,
+0x62, 0x69, 0x69, 0x2d, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x41, 0x66,
+0x72, 0x69, 0x63, 0x61, 0x6e, 0x20, 0x52, 0x61, 0x6e, 0x64, 0x4d, 0x72,
+0x61, 0x73, 0x69, 0x72, 0x20, 0x52, 0x65, 0x6a, 0x61, 0x72, 0x52, 0x65,
+0x61, 0x75, 0x20, 0x42, 0x72, 0x61, 0x73, 0x69, 0x75, 0x77, 0x61, 0x72,
+0x61, 0x50, 0x65, 0x73, 0x6f, 0x20, 0x4b, 0x75, 0x72, 0x169, 0x62, 0x69,
+0x79, 0x61, 0x77, 0x61, 0x72, 0x61, 0x42, 0x75, 0x72, 0x69, 0x77, 0x61,
+0x72, 0x69, 0x20, 0x57, 0x65, 0x6e, 0x65, 0x73, 0x75, 0x65, 0x72, 0x61,
+0x77, 0x61, 0x72, 0x61, 0x50, 0xe1, 0x6b, 0x65, 0x73, 0x74, 0xe1, 0x6e,
+0x69, 0x20, 0x72, 0x75, 0x70, 0x69, 0x47, 0x61, 0x72, 0x269, 0x256, 0x6f,
+0x6e, 0x74, 0x1dd, 0x6e, 0x61, 0x20, 0x67, 0x269, 0x74, 0x65, 0x14b, 0x73,
+0x68, 0x69, 0x6c, 0x65, 0x6c, 0x61, 0x14b, 0x20, 0x6b, 0x61, 0x73, 0x25b,
+0x25b, 0x66, 0x61, 0x92d, 0x93e, 0x930, 0x924, 0x947, 0x20, 0x926, 0x93e, 0x20,
+0x930, 0x941, 0x92a, 0x92f, 0x93e
};
static constexpr char16_t currency_format_data[] = {
-0x25, 0x31, 0x25, 0x32, 0x25, 0x32, 0xa0, 0x25, 0x31, 0x25, 0x32, 0x25, 0x31, 0x28, 0x25, 0x32, 0x25, 0x31, 0x29, 0x25,
-0x31, 0xa0, 0x25, 0x32, 0x28, 0x25, 0x31, 0xa0, 0x25, 0x32, 0x29, 0x200f, 0x25, 0x31, 0xa0, 0x25, 0x32, 0x61c, 0x25, 0x31,
-0x25, 0x32, 0x28, 0x61c, 0x25, 0x31, 0x25, 0x32, 0x29, 0x28, 0x25, 0x31, 0x25, 0x32, 0x29, 0x28, 0x25, 0x32, 0xa0, 0x25,
-0x31, 0x29, 0x25, 0x32, 0x2d, 0x25, 0x31, 0x200f, 0x25, 0x31, 0xa0, 0x200f, 0x25, 0x32, 0x200f, 0x200e, 0x2d, 0x25, 0x31, 0xa0,
-0x200f, 0x25, 0x32, 0x25, 0x32, 0x2212, 0x25, 0x31, 0x25, 0x32, 0x2d, 0xa0, 0x25, 0x31, 0x200e, 0x25, 0x32, 0xa0, 0x25, 0x31,
-0x200e, 0x28, 0x25, 0x32, 0xa0, 0x25, 0x31, 0x29
+0x25, 0x31, 0x25, 0x32, 0x25, 0x31, 0xa0, 0x25, 0x32, 0x28, 0x25, 0x32,
+0x25, 0x31, 0x29, 0x25, 0x32, 0xa0, 0x25, 0x31, 0x28, 0x25, 0x31, 0xa0,
+0x25, 0x32, 0x29, 0x200f, 0x25, 0x31, 0xa0, 0x25, 0x32, 0x61c, 0x25, 0x31,
+0x25, 0x32, 0x28, 0x61c, 0x25, 0x31, 0x25, 0x32, 0x29, 0x28, 0x25, 0x31,
+0x25, 0x32, 0x29, 0x28, 0x25, 0x31, 0x29, 0xa0, 0x25, 0x32, 0x28, 0x25,
+0x32, 0xa0, 0x25, 0x31, 0x29, 0x25, 0x32, 0x2d, 0x25, 0x31, 0x200f, 0x25,
+0x31, 0xa0, 0x200f, 0x25, 0x32, 0x200f, 0x200e, 0x2d, 0x25, 0x31, 0xa0, 0x200f,
+0x25, 0x32, 0x25, 0x32, 0xa0, 0x2d, 0x25, 0x31, 0x25, 0x32, 0x2212, 0x25,
+0x31, 0x25, 0x32, 0x2d, 0xa0, 0x25, 0x31, 0x200e, 0x25, 0x32, 0xa0, 0x25,
+0x31, 0x200e, 0x28, 0x25, 0x32, 0xa0, 0x25, 0x31, 0x29, 0x25, 0x31, 0x202f,
+0x25, 0x32
};
static constexpr char16_t endonyms_data[] = {
-0x41, 0x66, 0x72, 0x69, 0x6b, 0x61, 0x61, 0x6e, 0x73, 0x53, 0x75, 0x69, 0x64, 0x2d, 0x41, 0x66, 0x72, 0x69, 0x6b, 0x61,
-0x4e, 0x61, 0x6d, 0x69, 0x62, 0x69, 0xeb, 0x41, 0x67, 0x68, 0x65, 0x6d, 0x4b, 0xe0, 0x6d, 0xe0, 0x6c, 0xfb, 0x14b, 0x41,
-0x6b, 0x61, 0x6e, 0x47, 0x61, 0x61, 0x6e, 0x61, 0x73, 0x68, 0x71, 0x69, 0x70, 0x53, 0x68, 0x71, 0x69, 0x70, 0xeb, 0x72,
-0x69, 0x4b, 0x6f, 0x73, 0x6f, 0x76, 0xeb, 0x4d, 0x61, 0x71, 0x65, 0x64, 0x6f, 0x6e, 0x69, 0x61, 0x20, 0x65, 0x20, 0x56,
-0x65, 0x72, 0x69, 0x75, 0x74, 0x12a0, 0x121b, 0x122d, 0x129b, 0x12a2, 0x1275, 0x12ee, 0x1335, 0x12eb, 0x627, 0x644, 0x639, 0x631, 0x628, 0x64a,
-0x629, 0x645, 0x635, 0x631, 0x627, 0x644, 0x62c, 0x632, 0x627, 0x626, 0x631, 0x627, 0x644, 0x628, 0x62d, 0x631, 0x64a, 0x646, 0x62a, 0x634,
-0x627, 0x62f, 0x62c, 0x632, 0x631, 0x20, 0x627, 0x644, 0x642, 0x645, 0x631, 0x62c, 0x64a, 0x628, 0x648, 0x62a, 0x64a, 0x625, 0x631, 0x64a,
-0x62a, 0x631, 0x64a, 0x627, 0x627, 0x644, 0x639, 0x631, 0x627, 0x642, 0x625, 0x633, 0x631, 0x627, 0x626, 0x64a, 0x644, 0x627, 0x644, 0x623,
-0x631, 0x62f, 0x646, 0x627, 0x644, 0x643, 0x648, 0x64a, 0x62a, 0x644, 0x628, 0x646, 0x627, 0x646, 0x644, 0x64a, 0x628, 0x64a, 0x627, 0x645,
-0x648, 0x631, 0x64a, 0x62a, 0x627, 0x646, 0x64a, 0x627, 0x627, 0x644, 0x645, 0x63a, 0x631, 0x628, 0x639, 0x64f, 0x645, 0x627, 0x646, 0x627,
-0x644, 0x623, 0x631, 0x627, 0x636, 0x64a, 0x20, 0x627, 0x644, 0x641, 0x644, 0x633, 0x637, 0x64a, 0x646, 0x64a, 0x629, 0x642, 0x637, 0x631,
-0x627, 0x644, 0x645, 0x645, 0x644, 0x643, 0x629, 0x20, 0x627, 0x644, 0x639, 0x631, 0x628, 0x64a, 0x629, 0x20, 0x627, 0x644, 0x633, 0x639,
-0x648, 0x62f, 0x64a, 0x629, 0x627, 0x644, 0x635, 0x648, 0x645, 0x627, 0x644, 0x62c, 0x646, 0x648, 0x628, 0x20, 0x627, 0x644, 0x633, 0x648,
-0x62f, 0x627, 0x646, 0x627, 0x644, 0x633, 0x648, 0x62f, 0x627, 0x646, 0x633, 0x648, 0x631, 0x64a, 0x627, 0x62a, 0x648, 0x646, 0x633, 0x627,
-0x644, 0x625, 0x645, 0x627, 0x631, 0x627, 0x62a, 0x20, 0x627, 0x644, 0x639, 0x631, 0x628, 0x64a, 0x629, 0x20, 0x627, 0x644, 0x645, 0x62a,
-0x62d, 0x62f, 0x629, 0x627, 0x644, 0x635, 0x62d, 0x631, 0x627, 0x621, 0x20, 0x627, 0x644, 0x63a, 0x631, 0x628, 0x64a, 0x629, 0x627, 0x644,
-0x639, 0x631, 0x628, 0x64a, 0x629, 0x20, 0x627, 0x644, 0x641, 0x635, 0x62d, 0x649, 0x20, 0x627, 0x644, 0x62d, 0x62f, 0x64a, 0x62b, 0x629,
-0x627, 0x644, 0x639, 0x627, 0x644, 0x645, 0x627, 0x644, 0x64a, 0x645, 0x646, 0x570, 0x561, 0x575, 0x565, 0x580, 0x565, 0x576, 0x540, 0x561,
-0x575, 0x561, 0x57d, 0x57f, 0x561, 0x576, 0x985, 0x9b8, 0x9ae, 0x9c0, 0x9af, 0x9bc, 0x9be, 0x9ad, 0x9be, 0x9f0, 0x9a4, 0x61, 0x73, 0x74,
-0x75, 0x72, 0x69, 0x61, 0x6e, 0x75, 0x45, 0x73, 0x70, 0x61, 0xf1, 0x61, 0x4b, 0x69, 0x70, 0x61, 0x72, 0x65, 0x54, 0x61,
-0x64, 0x68, 0x61, 0x6e, 0x69, 0x61, 0x61, 0x7a, 0x259, 0x72, 0x62, 0x61, 0x79, 0x63, 0x61, 0x6e, 0x41, 0x7a, 0x259, 0x72,
-0x62, 0x61, 0x79, 0x63, 0x61, 0x6e, 0x430, 0x437, 0x4d9, 0x440, 0x431, 0x430, 0x458, 0x4b9, 0x430, 0x43d, 0x410, 0x437, 0x4d9, 0x440,
-0x431, 0x430, 0x458, 0x4b9, 0x430, 0x43d, 0x72, 0x69, 0x6b, 0x70, 0x61, 0x6b, 0x61, 0x6d, 0x25b, 0x72, 0xfa, 0x6e, 0x62, 0x61,
-0x6d, 0x61, 0x6e, 0x61, 0x6b, 0x61, 0x6e, 0x4d, 0x61, 0x6c, 0x69, 0x9ac, 0x9be, 0x982, 0x9b2, 0x9be, 0x9ac, 0x9be, 0x982, 0x9b2,
-0x9be, 0x9a6, 0x9c7, 0x9b6, 0x9ad, 0x9be, 0x9b0, 0x9a4, 0x181, 0xe0, 0x73, 0xe0, 0x61, 0x4b, 0xe0, 0x6d, 0x25b, 0x300, 0x72, 0xfb,
-0x6e, 0x65, 0x75, 0x73, 0x6b, 0x61, 0x72, 0x61, 0x45, 0x73, 0x70, 0x61, 0x69, 0x6e, 0x69, 0x61, 0x431, 0x435, 0x43b, 0x430,
-0x440, 0x443, 0x441, 0x43a, 0x430, 0x44f, 0x411, 0x435, 0x43b, 0x430, 0x440, 0x443, 0x441, 0x44c, 0x49, 0x63, 0x68, 0x69, 0x62, 0x65,
-0x6d, 0x62, 0x61, 0x5a, 0x61, 0x6d, 0x62, 0x69, 0x61, 0x48, 0x69, 0x62, 0x65, 0x6e, 0x61, 0x48, 0x75, 0x74, 0x61, 0x6e,
-0x7a, 0x61, 0x6e, 0x69, 0x61, 0x92d, 0x94b, 0x91c, 0x92a, 0x941, 0x930, 0x940, 0x92d, 0x93e, 0x930, 0x924, 0x92c, 0x930, 0x2019, 0x62,
-0x6f, 0x73, 0x61, 0x6e, 0x73, 0x6b, 0x69, 0x42, 0x6f, 0x73, 0x6e, 0x61, 0x20, 0x69, 0x20, 0x48, 0x65, 0x72, 0x63, 0x65,
-0x67, 0x6f, 0x76, 0x69, 0x6e, 0x61, 0x431, 0x43e, 0x441, 0x430, 0x43d, 0x441, 0x43a, 0x438, 0x411, 0x43e, 0x441, 0x43d, 0x430, 0x20,
-0x438, 0x20, 0x425, 0x435, 0x440, 0x446, 0x435, 0x433, 0x43e, 0x432, 0x438, 0x43d, 0x430, 0x62, 0x72, 0x65, 0x7a, 0x68, 0x6f, 0x6e,
-0x65, 0x67, 0x46, 0x72, 0x61, 0xf1, 0x73, 0x431, 0x44a, 0x43b, 0x433, 0x430, 0x440, 0x441, 0x43a, 0x438, 0x411, 0x44a, 0x43b, 0x433,
-0x430, 0x440, 0x438, 0x44f, 0x1019, 0x103c, 0x1014, 0x103a, 0x1019, 0x102c, 0x7cb5, 0x8a9e, 0x4e2d, 0x83ef, 0x4eba, 0x6c11, 0x5171, 0x548c, 0x570b, 0x9999,
-0x6e2f, 0x7279, 0x5225, 0x884c, 0x653f, 0x5340, 0x7ca4, 0x8bed, 0x4e2d, 0x534e, 0x4eba, 0x6c11, 0x5171, 0x548c, 0x56fd, 0x63, 0x61, 0x74, 0x61, 0x6c,
-0xe0, 0x45, 0x73, 0x70, 0x61, 0x6e, 0x79, 0x61, 0x41, 0x6e, 0x64, 0x6f, 0x72, 0x72, 0x61, 0x46, 0x72, 0x61, 0x6e, 0xe7,
-0x61, 0x49, 0x74, 0xe0, 0x6c, 0x69, 0x61, 0x43, 0x65, 0x62, 0x75, 0x61, 0x6e, 0x6f, 0x50, 0x69, 0x6c, 0x69, 0x70, 0x69,
-0x6e, 0x61, 0x73, 0x54, 0x61, 0x6d, 0x61, 0x7a, 0x69, 0x263, 0x74, 0x20, 0x6e, 0x20, 0x6c, 0x61, 0x1e6d, 0x6c, 0x61, 0x1e63,
-0x4d, 0x65, 0x1e5b, 0x1e5b, 0x75, 0x6b, 0x6a9, 0x648, 0x631, 0x62f, 0x6cc, 0x6cc, 0x20, 0x646, 0x627, 0x648, 0x6d5, 0x646, 0x62f, 0x6cc,
-0x639, 0x6ce, 0x631, 0x627, 0x642, 0x626, 0x6ce, 0x631, 0x627, 0x646, 0xd804, 0xdd0c, 0xd804, 0xdd0b, 0xd804, 0xdd34, 0xd804, 0xdd1f, 0xd804, 0xdd33,
-0xd804, 0xdd26, 0xd804, 0xdd1d, 0xd804, 0xdd01, 0xd804, 0xdd23, 0xd804, 0xdd18, 0xd804, 0xdd2c, 0xd804, 0xdd0c, 0xd804, 0xdd34, 0xd804, 0xdd1e, 0xd804, 0xdd22,
-0xd804, 0xdd27, 0xd804, 0xdd16, 0xd804, 0xdd34, 0x43d, 0x43e, 0x445, 0x447, 0x438, 0x439, 0x43d, 0x420, 0x43e, 0x441, 0x441, 0x438, 0x13e3, 0x13b3,
-0x13a9, 0x13cc, 0x13ca, 0x20, 0x13a2, 0x13f3, 0x13be, 0x13b5, 0x13cd, 0x13d4, 0x13c5, 0x20, 0x13cd, 0x13a6, 0x13da, 0x13a9, 0x52, 0x75, 0x6b, 0x69,
-0x67, 0x61, 0x55, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x7b80, 0x4f53, 0x4e2d, 0x6587, 0x4e2d, 0x56fd, 0x4e2d, 0x56fd, 0x9999, 0x6e2f, 0x7279, 0x522b,
-0x884c, 0x653f, 0x533a, 0x4e2d, 0x56fd, 0x6fb3, 0x95e8, 0x7279, 0x522b, 0x884c, 0x653f, 0x533a, 0x65b0, 0x52a0, 0x5761, 0x7e41, 0x9ad4, 0x4e2d, 0x6587, 0x4e2d,
-0x570b, 0x9999, 0x6e2f, 0x7279, 0x5225, 0x884c, 0x653f, 0x5340, 0x4e2d, 0x570b, 0x6fb3, 0x9580, 0x7279, 0x5225, 0x884c, 0x653f, 0x5340, 0x53f0, 0x7063, 0x447,
-0x4d1, 0x432, 0x430, 0x448, 0x420, 0x430, 0x4ab, 0x4ab, 0x435, 0x439, 0x4b, 0xf6, 0x6c, 0x73, 0x63, 0x68, 0x44, 0x6f, 0xfc, 0x74,
-0x73, 0x63, 0x68, 0x6c, 0x61, 0x6e, 0x64, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x77, 0x65, 0x6b, 0x52, 0x79, 0x77, 0x76, 0x61,
-0x6e, 0x65, 0x74, 0x68, 0x20, 0x55, 0x6e, 0x79, 0x73, 0x68, 0x72, 0x76, 0x61, 0x74, 0x73, 0x6b, 0x69, 0x48, 0x72, 0x76,
-0x61, 0x74, 0x73, 0x6b, 0x61, 0x10d, 0x65, 0x161, 0x74, 0x69, 0x6e, 0x61, 0x10c, 0x65, 0x73, 0x6b, 0x6f, 0x64, 0x61, 0x6e,
-0x73, 0x6b, 0x44, 0x61, 0x6e, 0x6d, 0x61, 0x72, 0x6b, 0x47, 0x72, 0xf8, 0x6e, 0x6c, 0x61, 0x6e, 0x64, 0x921, 0x94b, 0x917,
-0x930, 0x940, 0x64, 0x75, 0xe1, 0x6c, 0xe1, 0x43, 0x61, 0x6d, 0x65, 0x72, 0x6f, 0x75, 0x6e, 0x4e, 0x65, 0x64, 0x65, 0x72,
-0x6c, 0x61, 0x6e, 0x64, 0x73, 0x41, 0x72, 0x75, 0x62, 0x61, 0x56, 0x6c, 0x61, 0x61, 0x6d, 0x73, 0x42, 0x65, 0x6c, 0x67,
-0x69, 0xeb, 0x43, 0x61, 0x72, 0x69, 0x62, 0x69, 0x73, 0x63, 0x68, 0x20, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e,
-0x64, 0x43, 0x75, 0x72, 0x61, 0xe7, 0x61, 0x6f, 0x53, 0x69, 0x6e, 0x74, 0x2d, 0x4d, 0x61, 0x61, 0x72, 0x74, 0x65, 0x6e,
-0x53, 0x75, 0x72, 0x69, 0x6e, 0x61, 0x6d, 0x65, 0xf62, 0xfab, 0xf7c, 0xf44, 0xf0b, 0xf41, 0xf60, 0xf56, 0xfb2, 0xf74, 0xf42, 0x4b,
-0x129, 0x65, 0x6d, 0x62, 0x75, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6e, 0x20, 0x45,
-0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68, 0x55, 0x6e, 0x69, 0x74, 0x65, 0x64, 0x20, 0x53, 0x74, 0x61, 0x74, 0x65, 0x73, 0x41,
-0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6e, 0x20, 0x53, 0x61, 0x6d, 0x6f, 0x61, 0x41, 0x6e, 0x67, 0x75, 0x69, 0x6c, 0x6c,
-0x61, 0x41, 0x6e, 0x74, 0x69, 0x67, 0x75, 0x61, 0x20, 0x26, 0x20, 0x42, 0x61, 0x72, 0x62, 0x75, 0x64, 0x61, 0x41, 0x75,
-0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x6e, 0x20, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68, 0x41, 0x75, 0x73, 0x74,
-0x72, 0x69, 0x61, 0x42, 0x61, 0x68, 0x61, 0x6d, 0x61, 0x73, 0x42, 0x61, 0x72, 0x62, 0x61, 0x64, 0x6f, 0x73, 0x42, 0x65,
-0x6c, 0x67, 0x69, 0x75, 0x6d, 0x42, 0x65, 0x6c, 0x69, 0x7a, 0x65, 0x42, 0x65, 0x72, 0x6d, 0x75, 0x64, 0x61, 0x42, 0x6f,
-0x74, 0x73, 0x77, 0x61, 0x6e, 0x61, 0x42, 0x72, 0x69, 0x74, 0x69, 0x73, 0x68, 0x20, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e,
-0x20, 0x4f, 0x63, 0x65, 0x61, 0x6e, 0x20, 0x54, 0x65, 0x72, 0x72, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x42, 0x72, 0x69, 0x74,
-0x69, 0x73, 0x68, 0x20, 0x56, 0x69, 0x72, 0x67, 0x69, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x42, 0x75,
-0x72, 0x75, 0x6e, 0x64, 0x69, 0x43, 0x61, 0x6d, 0x65, 0x72, 0x6f, 0x6f, 0x6e, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x69, 0x61,
-0x6e, 0x20, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x43, 0x61, 0x79, 0x6d, 0x61,
-0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x43, 0x68, 0x72, 0x69, 0x73, 0x74, 0x6d, 0x61, 0x73, 0x20, 0x49,
-0x73, 0x6c, 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x63, 0x6f, 0x73, 0x20, 0x28, 0x4b, 0x65, 0x65, 0x6c, 0x69, 0x6e, 0x67, 0x29,
-0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x43, 0x6f, 0x6f, 0x6b, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73,
-0x43, 0x79, 0x70, 0x72, 0x75, 0x73, 0x44, 0x65, 0x6e, 0x6d, 0x61, 0x72, 0x6b, 0x44, 0x69, 0x65, 0x67, 0x6f, 0x20, 0x47,
-0x61, 0x72, 0x63, 0x69, 0x61, 0x44, 0x6f, 0x6d, 0x69, 0x6e, 0x69, 0x63, 0x61, 0x45, 0x72, 0x69, 0x74, 0x72, 0x65, 0x61,
-0x45, 0x73, 0x77, 0x61, 0x74, 0x69, 0x6e, 0x69, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x46, 0x61, 0x6c, 0x6b, 0x6c, 0x61,
-0x6e, 0x64, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x46, 0x69, 0x6a, 0x69, 0x46, 0x69, 0x6e, 0x6c, 0x61, 0x6e,
-0x64, 0x47, 0x61, 0x6d, 0x62, 0x69, 0x61, 0x47, 0x65, 0x72, 0x6d, 0x61, 0x6e, 0x79, 0x47, 0x68, 0x61, 0x6e, 0x61, 0x47,
-0x69, 0x62, 0x72, 0x61, 0x6c, 0x74, 0x61, 0x72, 0x47, 0x72, 0x65, 0x6e, 0x61, 0x64, 0x61, 0x47, 0x75, 0x61, 0x6d, 0x47,
-0x75, 0x65, 0x72, 0x6e, 0x73, 0x65, 0x79, 0x47, 0x75, 0x79, 0x61, 0x6e, 0x61, 0x48, 0x6f, 0x6e, 0x67, 0x20, 0x4b, 0x6f,
-0x6e, 0x67, 0x20, 0x53, 0x41, 0x52, 0x20, 0x43, 0x68, 0x69, 0x6e, 0x61, 0x49, 0x72, 0x65, 0x6c, 0x61, 0x6e, 0x64, 0x49,
-0x73, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x4d, 0x61, 0x6e, 0x49, 0x73, 0x72, 0x61, 0x65, 0x6c, 0x4a, 0x61, 0x6d, 0x61,
-0x69, 0x63, 0x61, 0x4a, 0x65, 0x72, 0x73, 0x65, 0x79, 0x4b, 0x69, 0x72, 0x69, 0x62, 0x61, 0x74, 0x69, 0x4c, 0x65, 0x73,
-0x6f, 0x74, 0x68, 0x6f, 0x4c, 0x69, 0x62, 0x65, 0x72, 0x69, 0x61, 0x4d, 0x61, 0x63, 0x61, 0x6f, 0x20, 0x53, 0x41, 0x52,
-0x20, 0x43, 0x68, 0x69, 0x6e, 0x61, 0x4d, 0x61, 0x64, 0x61, 0x67, 0x61, 0x73, 0x63, 0x61, 0x72, 0x4d, 0x61, 0x6c, 0x61,
-0x77, 0x69, 0x4d, 0x61, 0x6c, 0x61, 0x79, 0x73, 0x69, 0x61, 0x4d, 0x61, 0x6c, 0x64, 0x69, 0x76, 0x65, 0x73, 0x4d, 0x61,
-0x6c, 0x74, 0x61, 0x4d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x6c, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x4d,
-0x61, 0x75, 0x72, 0x69, 0x74, 0x69, 0x75, 0x73, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x6e, 0x65, 0x73, 0x69, 0x61, 0x4d, 0x6f,
-0x6e, 0x74, 0x73, 0x65, 0x72, 0x72, 0x61, 0x74, 0x4e, 0x61, 0x6d, 0x69, 0x62, 0x69, 0x61, 0x4e, 0x61, 0x75, 0x72, 0x75,
-0x4e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x4e, 0x65, 0x77, 0x20, 0x5a, 0x65, 0x61, 0x6c, 0x61,
-0x6e, 0x64, 0x4e, 0x69, 0x67, 0x65, 0x72, 0x69, 0x61, 0x4e, 0x69, 0x75, 0x65, 0x4e, 0x6f, 0x72, 0x66, 0x6f, 0x6c, 0x6b,
-0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x20, 0x4d, 0x61, 0x72, 0x69,
-0x61, 0x6e, 0x61, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x50, 0x61, 0x6b, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x50,
-0x61, 0x6c, 0x61, 0x75, 0x50, 0x61, 0x70, 0x75, 0x61, 0x20, 0x4e, 0x65, 0x77, 0x20, 0x47, 0x75, 0x69, 0x6e, 0x65, 0x61,
-0x50, 0x68, 0x69, 0x6c, 0x69, 0x70, 0x70, 0x69, 0x6e, 0x65, 0x73, 0x50, 0x69, 0x74, 0x63, 0x61, 0x69, 0x72, 0x6e, 0x20,
-0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x50, 0x75, 0x65, 0x72, 0x74, 0x6f, 0x20, 0x52, 0x69, 0x63, 0x6f, 0x52, 0x77,
-0x61, 0x6e, 0x64, 0x61, 0x53, 0x74, 0x20, 0x48, 0x65, 0x6c, 0x65, 0x6e, 0x61, 0x53, 0x74, 0x20, 0x4b, 0x69, 0x74, 0x74,
-0x73, 0x20, 0x26, 0x20, 0x4e, 0x65, 0x76, 0x69, 0x73, 0x53, 0x74, 0x20, 0x4c, 0x75, 0x63, 0x69, 0x61, 0x53, 0x74, 0x20,
-0x56, 0x69, 0x6e, 0x63, 0x65, 0x6e, 0x74, 0x20, 0x26, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x72, 0x65, 0x6e, 0x61, 0x64,
-0x69, 0x6e, 0x65, 0x73, 0x53, 0x65, 0x79, 0x63, 0x68, 0x65, 0x6c, 0x6c, 0x65, 0x73, 0x53, 0x69, 0x65, 0x72, 0x72, 0x61,
-0x20, 0x4c, 0x65, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, 0x53, 0x69, 0x6e, 0x74, 0x20,
-0x4d, 0x61, 0x61, 0x72, 0x74, 0x65, 0x6e, 0x53, 0x6c, 0x6f, 0x76, 0x65, 0x6e, 0x69, 0x61, 0x53, 0x6f, 0x6c, 0x6f, 0x6d,
-0x6f, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x41, 0x66, 0x72, 0x69,
-0x63, 0x61, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x53, 0x75, 0x64, 0x61, 0x6e, 0x53, 0x75, 0x64, 0x61, 0x6e, 0x53, 0x77,
-0x65, 0x64, 0x65, 0x6e, 0x53, 0x77, 0x69, 0x74, 0x7a, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x54, 0x61, 0x6e, 0x7a, 0x61,
-0x6e, 0x69, 0x61, 0x54, 0x6f, 0x6b, 0x65, 0x6c, 0x61, 0x75, 0x54, 0x6f, 0x6e, 0x67, 0x61, 0x54, 0x72, 0x69, 0x6e, 0x69,
-0x64, 0x61, 0x64, 0x20, 0x26, 0x20, 0x54, 0x6f, 0x62, 0x61, 0x67, 0x6f, 0x54, 0x75, 0x72, 0x6b, 0x73, 0x20, 0x26, 0x20,
-0x43, 0x61, 0x69, 0x63, 0x6f, 0x73, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x54, 0x75, 0x76, 0x61, 0x6c, 0x75,
-0x55, 0x6e, 0x69, 0x74, 0x65, 0x64, 0x20, 0x41, 0x72, 0x61, 0x62, 0x20, 0x45, 0x6d, 0x69, 0x72, 0x61, 0x74, 0x65, 0x73,
-0x42, 0x72, 0x69, 0x74, 0x69, 0x73, 0x68, 0x20, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68, 0x55, 0x6e, 0x69, 0x74, 0x65,
-0x64, 0x20, 0x4b, 0x69, 0x6e, 0x67, 0x64, 0x6f, 0x6d, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x4f, 0x75, 0x74, 0x6c, 0x79, 0x69,
-0x6e, 0x67, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x56, 0x69, 0x72, 0x67, 0x69,
-0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x56, 0x61, 0x6e, 0x75, 0x61, 0x74, 0x75, 0x77, 0x6f, 0x72, 0x6c,
-0x64, 0x5a, 0x69, 0x6d, 0x62, 0x61, 0x62, 0x77, 0x65, 0x65, 0x73, 0x70, 0x65, 0x72, 0x61, 0x6e, 0x74, 0x6f, 0x4d, 0x6f,
-0x6e, 0x64, 0x6f, 0x65, 0x65, 0x73, 0x74, 0x69, 0x45, 0x65, 0x73, 0x74, 0x69, 0x45, 0x28b, 0x65, 0x67, 0x62, 0x65, 0x47,
-0x68, 0x61, 0x6e, 0x61, 0x20, 0x6e, 0x75, 0x74, 0x6f, 0x6d, 0x65, 0x54, 0x6f, 0x67, 0x6f, 0x20, 0x6e, 0x75, 0x74, 0x6f,
-0x6d, 0x65, 0x65, 0x77, 0x6f, 0x6e, 0x64, 0x6f, 0x4b, 0x61, 0x6d, 0x259, 0x72, 0xfa, 0x6e, 0x66, 0xf8, 0x72, 0x6f, 0x79,
-0x73, 0x6b, 0x74, 0x46, 0xf8, 0x72, 0x6f, 0x79, 0x61, 0x72, 0x46, 0x69, 0x6c, 0x69, 0x70, 0x69, 0x6e, 0x6f, 0x73, 0x75,
-0x6f, 0x6d, 0x69, 0x53, 0x75, 0x6f, 0x6d, 0x69, 0x66, 0x72, 0x61, 0x6e, 0xe7, 0x61, 0x69, 0x73, 0x46, 0x72, 0x61, 0x6e,
-0x63, 0x65, 0x41, 0x6c, 0x67, 0xe9, 0x72, 0x69, 0x65, 0x42, 0x65, 0x6c, 0x67, 0x69, 0x71, 0x75, 0x65, 0x42, 0xe9, 0x6e,
-0x69, 0x6e, 0x42, 0x75, 0x72, 0x6b, 0x69, 0x6e, 0x61, 0x20, 0x46, 0x61, 0x73, 0x6f, 0x66, 0x72, 0x61, 0x6e, 0xe7, 0x61,
-0x69, 0x73, 0x20, 0x63, 0x61, 0x6e, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x52, 0xe9, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x71, 0x75,
-0x65, 0x20, 0x63, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x66, 0x72, 0x69, 0x63, 0x61, 0x69, 0x6e, 0x65, 0x54, 0x63, 0x68, 0x61,
-0x64, 0x43, 0x6f, 0x6d, 0x6f, 0x72, 0x65, 0x73, 0x43, 0x6f, 0x6e, 0x67, 0x6f, 0x2d, 0x42, 0x72, 0x61, 0x7a, 0x7a, 0x61,
-0x76, 0x69, 0x6c, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x67, 0x6f, 0x2d, 0x4b, 0x69, 0x6e, 0x73, 0x68, 0x61, 0x73, 0x61, 0x44,
-0x6a, 0x69, 0x62, 0x6f, 0x75, 0x74, 0x69, 0x47, 0x75, 0x69, 0x6e, 0xe9, 0x65, 0x20, 0xe9, 0x71, 0x75, 0x61, 0x74, 0x6f,
-0x72, 0x69, 0x61, 0x6c, 0x65, 0x47, 0x75, 0x79, 0x61, 0x6e, 0x65, 0x20, 0x66, 0x72, 0x61, 0x6e, 0xe7, 0x61, 0x69, 0x73,
-0x65, 0x50, 0x6f, 0x6c, 0x79, 0x6e, 0xe9, 0x73, 0x69, 0x65, 0x20, 0x66, 0x72, 0x61, 0x6e, 0xe7, 0x61, 0x69, 0x73, 0x65,
-0x47, 0x61, 0x62, 0x6f, 0x6e, 0x47, 0x75, 0x61, 0x64, 0x65, 0x6c, 0x6f, 0x75, 0x70, 0x65, 0x48, 0x61, 0xef, 0x74, 0x69,
-0x43, 0xf4, 0x74, 0x65, 0x20, 0x64, 0x2019, 0x49, 0x76, 0x6f, 0x69, 0x72, 0x65, 0x4c, 0x75, 0x78, 0x65, 0x6d, 0x62, 0x6f,
-0x75, 0x72, 0x67, 0x4d, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x61,
-0x6e, 0x69, 0x65, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x63, 0x65, 0x4d, 0x61, 0x79, 0x6f, 0x74, 0x74, 0x65, 0x4d, 0x6f, 0x6e,
-0x61, 0x63, 0x6f, 0x4d, 0x61, 0x72, 0x6f, 0x63, 0x4e, 0x6f, 0x75, 0x76, 0x65, 0x6c, 0x6c, 0x65, 0x2d, 0x43, 0x61, 0x6c,
-0xe9, 0x64, 0x6f, 0x6e, 0x69, 0x65, 0x4c, 0x61, 0x20, 0x52, 0xe9, 0x75, 0x6e, 0x69, 0x6f, 0x6e, 0x53, 0x61, 0x69, 0x6e,
-0x74, 0x2d, 0x42, 0x61, 0x72, 0x74, 0x68, 0xe9, 0x6c, 0x65, 0x6d, 0x79, 0x53, 0x61, 0x69, 0x6e, 0x74, 0x2d, 0x4d, 0x61,
-0x72, 0x74, 0x69, 0x6e, 0x53, 0x61, 0x69, 0x6e, 0x74, 0x2d, 0x50, 0x69, 0x65, 0x72, 0x72, 0x65, 0x2d, 0x65, 0x74, 0x2d,
-0x4d, 0x69, 0x71, 0x75, 0x65, 0x6c, 0x6f, 0x6e, 0x53, 0xe9, 0x6e, 0xe9, 0x67, 0x61, 0x6c, 0x66, 0x72, 0x61, 0x6e, 0xe7,
-0x61, 0x69, 0x73, 0x20, 0x73, 0x75, 0x69, 0x73, 0x73, 0x65, 0x53, 0x75, 0x69, 0x73, 0x73, 0x65, 0x53, 0x79, 0x72, 0x69,
-0x65, 0x54, 0x75, 0x6e, 0x69, 0x73, 0x69, 0x65, 0x57, 0x61, 0x6c, 0x6c, 0x69, 0x73, 0x2d, 0x65, 0x74, 0x2d, 0x46, 0x75,
-0x74, 0x75, 0x6e, 0x61, 0x66, 0x75, 0x72, 0x6c, 0x61, 0x6e, 0x49, 0x74, 0x61, 0x6c, 0x69, 0x65, 0x50, 0x75, 0x6c, 0x61,
-0x61, 0x72, 0x53, 0x65, 0x6e, 0x65, 0x67, 0x61, 0x61, 0x6c, 0xd83a, 0xdd06, 0xd83a, 0xdd35, 0xd83a, 0xdd24, 0xd83a, 0xdd22, 0xd83a, 0xdd2a,
-0xd83a, 0xdd04, 0xd83a, 0xdd35, 0xd83a, 0xdd2a, 0xd83a, 0xdd33, 0xd83a, 0xdd2d, 0xd83a, 0xdd32, 0xd83a, 0xdd22, 0x20, 0xd83a, 0xdd0a, 0xd83a, 0xdd22, 0xd83a,
-0xdd27, 0xd83a, 0xdd2e, 0xd83a, 0xdd45, 0xd83a, 0xdd11, 0xd83a, 0xdd22, 0xd83a, 0xdd25, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd35, 0xd83a, 0xdd45, 0xd83a,
-0xdd32, 0xd83a, 0xdd18, 0xd83a, 0xdd22, 0xd83a, 0xdd25, 0xd83a, 0xdd26, 0xd83a, 0xdd2d, 0xd83a, 0xdd34, 0xd83a, 0xdd22, 0xd83a, 0xdd18, 0xd83a, 0xdd22, 0xd83a,
-0xdd32, 0xd83a, 0xdd22, 0xd83a, 0xdd18, 0xd83a, 0xdd2d, 0xd83a, 0xdd32, 0xd83a, 0xdd2b, 0x2d, 0xd83a, 0xdd04, 0xd83a, 0xdd2d, 0xd83a, 0xdd27, 0xd83a, 0xdd22,
-0xd83a, 0xdd31, 0xd83a, 0xdd2e, 0xd83a, 0xdd45, 0xd83a, 0xdd02, 0xd83a, 0xdd22, 0xd83a, 0xdd26, 0xd83a, 0xdd2d, 0xd83a, 0xdd2a, 0xd83a, 0xdd2d, 0xd83a, 0xdd34,
-0xd83a, 0xdd22, 0xd83a, 0xdd44, 0xd83a, 0xdd03, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0xd83a, 0xdd3c, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0xd83a, 0xdd2d, 0xd83a, 0xdd45,
-0xd83a, 0xdd10, 0xd83a, 0xdd22, 0xd83a, 0xdd36, 0xd83a, 0xdd2b, 0xd83a, 0xdd2a, 0xd83a, 0xdd2d, 0xd83a, 0xdd34, 0xd83a, 0xdd22, 0xd83a, 0xdd44, 0xd83a, 0xdd10,
-0xd83a, 0xdd2d, 0xd83a, 0xdd45, 0xd83a, 0xdd36, 0xd83a, 0xdd2b, 0xd83a, 0xdd2a, 0xd83a, 0xdd05, 0xd83a, 0xdd2b, 0xd83a, 0xdd32, 0xd83a, 0xdd2b, 0xd83a, 0xdd3a,
-0xd83a, 0xdd22, 0xd83a, 0xdd44, 0xd83a, 0xdd24, 0xd83a, 0xdd05, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd22, 0xd83a, 0xdd24, 0xd83a, 0xdd2e, 0xd83a, 0xdd32,
-0x42, 0x75, 0x72, 0x6b, 0x69, 0x62, 0x61, 0x61, 0x20, 0x46, 0x61, 0x61, 0x73, 0x6f, 0x4b, 0x61, 0x6d, 0x65, 0x72, 0x75,
-0x75, 0x6e, 0x47, 0x61, 0x6d, 0x6d, 0x62, 0x69, 0x47, 0x61, 0x6e, 0x61, 0x61, 0x47, 0x69, 0x6e, 0x65, 0x2d, 0x42, 0x69,
-0x73, 0x61, 0x61, 0x77, 0x6f, 0x4c, 0x69, 0x62, 0x65, 0x72, 0x69, 0x79, 0x61, 0x61, 0x4d, 0x75, 0x72, 0x69, 0x74, 0x61,
-0x6e, 0x69, 0x4e, 0x69, 0x6a, 0x65, 0x72, 0x69, 0x79, 0x61, 0x61, 0x4e, 0x69, 0x6a, 0x65, 0x65, 0x72, 0x53, 0x65, 0x72,
-0x61, 0x61, 0x20, 0x6c, 0x69, 0x79, 0x6f, 0x6e, 0x47, 0xe0, 0x69, 0x64, 0x68, 0x6c, 0x69, 0x67, 0x41, 0x6e, 0x20, 0x52,
-0xec, 0x6f, 0x67, 0x68, 0x61, 0x63, 0x68, 0x64, 0x20, 0x41, 0x6f, 0x6e, 0x61, 0x69, 0x63, 0x68, 0x74, 0x65, 0x67, 0x61,
-0x6c, 0x65, 0x67, 0x6f, 0x4c, 0x75, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x59, 0x75, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x10e5, 0x10d0,
-0x10e0, 0x10d7, 0x10e3, 0x10da, 0x10d8, 0x10e1, 0x10d0, 0x10e5, 0x10d0, 0x10e0, 0x10d7, 0x10d5, 0x10d4, 0x10da, 0x10dd, 0x44, 0x65, 0x75, 0x74, 0x73,
-0x63, 0x68, 0x44, 0x65, 0x75, 0x74, 0x73, 0x63, 0x68, 0x6c, 0x61, 0x6e, 0x64, 0xd6, 0x73, 0x74, 0x65, 0x72, 0x72, 0x65,
-0x69, 0x63, 0x68, 0x69, 0x73, 0x63, 0x68, 0x65, 0x73, 0x20, 0x44, 0x65, 0x75, 0x74, 0x73, 0x63, 0x68, 0x42, 0x65, 0x6c,
-0x67, 0x69, 0x65, 0x6e, 0x49, 0x74, 0x61, 0x6c, 0x69, 0x65, 0x6e, 0x4c, 0x69, 0x65, 0x63, 0x68, 0x74, 0x65, 0x6e, 0x73,
-0x74, 0x65, 0x69, 0x6e, 0x4c, 0x75, 0x78, 0x65, 0x6d, 0x62, 0x75, 0x72, 0x67, 0x53, 0x63, 0x68, 0x77, 0x65, 0x69, 0x7a,
-0x65, 0x72, 0x20, 0x48, 0x6f, 0x63, 0x68, 0x64, 0x65, 0x75, 0x74, 0x73, 0x63, 0x68, 0x395, 0x3bb, 0x3bb, 0x3b7, 0x3bd, 0x3b9,
-0x3ba, 0x3ac, 0x395, 0x3bb, 0x3bb, 0x3ac, 0x3b4, 0x3b1, 0x39a, 0x3cd, 0x3c0, 0x3c1, 0x3bf, 0x3c2, 0xa97, 0xac1, 0xa9c, 0xab0, 0xabe, 0xaa4,
-0xac0, 0xaad, 0xabe, 0xab0, 0xaa4, 0x45, 0x6b, 0x65, 0x67, 0x75, 0x73, 0x69, 0x69, 0x48, 0x61, 0x75, 0x73, 0x61, 0x4e, 0x69,
-0x6a, 0x61, 0x72, 0x2bb, 0x14c, 0x6c, 0x65, 0x6c, 0x6f, 0x20, 0x48, 0x61, 0x77, 0x61, 0x69, 0x2bb, 0x69, 0x2bb, 0x41, 0x6d,
-0x65, 0x6c, 0x69, 0x6b, 0x61, 0x20, 0x48, 0x75, 0x69, 0x20, 0x50, 0x16b, 0x20, 0x2bb, 0x49, 0x61, 0x5e2, 0x5d1, 0x5e8, 0x5d9,
-0x5ea, 0x5d9, 0x5e9, 0x5e8, 0x5d0, 0x5dc, 0x939, 0x93f, 0x928, 0x94d, 0x926, 0x940, 0x48, 0x69, 0x6e, 0x64, 0x69, 0x6d, 0x61, 0x67,
-0x79, 0x61, 0x72, 0x4d, 0x61, 0x67, 0x79, 0x61, 0x72, 0x6f, 0x72, 0x73, 0x7a, 0xe1, 0x67, 0xed, 0x73, 0x6c, 0x65, 0x6e,
-0x73, 0x6b, 0x61, 0xcd, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x49, 0x67, 0x62, 0x6f, 0x4e, 0x61, 0x1ecb, 0x6a, 0x1ecb, 0x72, 0x1ecb,
-0x61, 0x61, 0x6e, 0x61, 0x72, 0xe2, 0x161, 0x6b, 0x69, 0x65, 0x6c, 0xe2, 0x53, 0x75, 0x6f, 0x6d, 0xe2, 0x49, 0x6e, 0x64,
-0x6f, 0x6e, 0x65, 0x73, 0x69, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x67, 0x75, 0x61, 0x4d, 0x75, 0x6e,
-0x64, 0x6f, 0x47, 0x61, 0x65, 0x69, 0x6c, 0x67, 0x65, 0xc9, 0x69, 0x72, 0x65, 0x61, 0x6e, 0x20, 0x52, 0xed, 0x6f, 0x63,
-0x68, 0x74, 0x20, 0x41, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x74, 0x68, 0x65, 0x69, 0x74, 0x61, 0x6c, 0x69, 0x61, 0x6e, 0x6f,
-0x49, 0x74, 0x61, 0x6c, 0x69, 0x61, 0x53, 0x61, 0x6e, 0x20, 0x4d, 0x61, 0x72, 0x69, 0x6e, 0x6f, 0x53, 0x76, 0x69, 0x7a,
-0x7a, 0x65, 0x72, 0x61, 0x43, 0x69, 0x74, 0x74, 0xe0, 0x20, 0x64, 0x65, 0x6c, 0x20, 0x56, 0x61, 0x74, 0x69, 0x63, 0x61,
-0x6e, 0x6f, 0x65e5, 0x672c, 0x8a9e, 0x4a, 0x61, 0x77, 0x61, 0x49, 0x6e, 0x64, 0x6f, 0x6e, 0xe9, 0x73, 0x69, 0x61, 0x6a, 0x6f,
-0x6f, 0x6c, 0x61, 0x53, 0x65, 0x6e, 0x65, 0x67, 0x61, 0x6c, 0x6b, 0x61, 0x62, 0x75, 0x76, 0x65, 0x72, 0x64, 0x69, 0x61,
-0x6e, 0x75, 0x4b, 0x61, 0x62, 0x75, 0x20, 0x56, 0x65, 0x72, 0x64, 0x69, 0x54, 0x61, 0x71, 0x62, 0x61, 0x79, 0x6c, 0x69,
-0x74, 0x4c, 0x65, 0x7a, 0x7a, 0x61, 0x79, 0x65, 0x72, 0x6b, 0x61, 0x6b, 0x254, 0x4b, 0x61, 0x6d, 0x25b, 0x72, 0x75, 0x6e,
-0x6b, 0x61, 0x6c, 0x61, 0x61, 0x6c, 0x6c, 0x69, 0x73, 0x75, 0x74, 0x4b, 0x61, 0x6c, 0x61, 0x61, 0x6c, 0x6c, 0x69, 0x74,
-0x20, 0x4e, 0x75, 0x6e, 0x61, 0x61, 0x74, 0x4b, 0x61, 0x6c, 0x65, 0x6e, 0x6a, 0x69, 0x6e, 0x45, 0x6d, 0x65, 0x74, 0x61,
-0x62, 0x20, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x4b, 0x69, 0x6b, 0x61, 0x6d, 0x62, 0x61, 0xc95, 0xca8, 0xccd, 0xca8, 0xca1, 0xcad,
-0xcbe, 0xcb0, 0xca4, 0x6a9, 0x672, 0x634, 0x64f, 0x631, 0x6c1, 0x650, 0x646, 0x62f, 0x648, 0x633, 0x62a, 0x627, 0x646, 0x915, 0x949, 0x936,
-0x941, 0x930, 0x939, 0x93f, 0x902, 0x926, 0x94b, 0x938, 0x94d, 0x924, 0x93e, 0x928, 0x49b, 0x430, 0x437, 0x430, 0x49b, 0x20, 0x442, 0x456,
-0x43b, 0x456, 0x49a, 0x430, 0x437, 0x430, 0x49b, 0x441, 0x442, 0x430, 0x43d, 0x1781, 0x17d2, 0x1798, 0x17c2, 0x179a, 0x1780, 0x1798, 0x17d2, 0x1796,
-0x17bb, 0x1787, 0x17b6, 0x47, 0x69, 0x6b, 0x75, 0x79, 0x75, 0x4b, 0x69, 0x6e, 0x79, 0x61, 0x72, 0x77, 0x61, 0x6e, 0x64, 0x61,
-0x55, 0x20, 0x52, 0x77, 0x61, 0x6e, 0x64, 0x61, 0x915, 0x94b, 0x902, 0x915, 0x923, 0x940, 0xd55c, 0xad6d, 0xc5b4, 0xb300, 0xd55c, 0xbbfc,
-0xad6d, 0xc870, 0xc120, 0xbbfc, 0xc8fc, 0xc8fc, 0xc758, 0xc778, 0xbbfc, 0xacf5, 0xd654, 0xad6d, 0x4b, 0x6f, 0x79, 0x72, 0x61, 0x62, 0x6f, 0x72,
-0x6f, 0x20, 0x73, 0x65, 0x6e, 0x6e, 0x69, 0x4d, 0x61, 0x61, 0x6c, 0x69, 0x4b, 0x6f, 0x79, 0x72, 0x61, 0x20, 0x63, 0x69,
-0x69, 0x6e, 0x69, 0x6b, 0x75, 0x72, 0x64, 0xee, 0x54, 0x69, 0x72, 0x6b, 0x69, 0x79, 0x65, 0x4b, 0x77, 0x61, 0x73, 0x69,
-0x6f, 0x4b, 0x61, 0x6d, 0x65, 0x72, 0x75, 0x6e, 0x43a, 0x44b, 0x440, 0x433, 0x44b, 0x437, 0x447, 0x430, 0x41a, 0x44b, 0x440, 0x433,
-0x44b, 0x437, 0x441, 0x442, 0x430, 0x43d, 0x4c, 0x61, 0x6b, 0x21f, 0xf3, 0x6c, 0x2bc, 0x69, 0x79, 0x61, 0x70, 0x69, 0x4d, 0xed,
-0x6c, 0x61, 0x68, 0x61, 0x14b, 0x73, 0x6b, 0x61, 0x20, 0x54, 0x21f, 0x61, 0x6d, 0xe1, 0x6b, 0x21f, 0x6f, 0x10d, 0x68, 0x65,
-0x4b, 0x268, 0x6c, 0x61, 0x61, 0x6e, 0x67, 0x69, 0x54, 0x61, 0x61, 0x6e, 0x73, 0x61, 0x6e, 0xed, 0x61, 0xea5, 0xeb2, 0xea7,
-0x6c, 0x61, 0x74, 0x76, 0x69, 0x65, 0x161, 0x75, 0x4c, 0x61, 0x74, 0x76, 0x69, 0x6a, 0x61, 0x6c, 0x69, 0x6e, 0x67, 0xe1,
-0x6c, 0x61, 0x52, 0x65, 0x70, 0x75, 0x62, 0x6c, 0xed, 0x6b, 0x69, 0x20, 0x79, 0x61, 0x20, 0x4b, 0x6f, 0x6e, 0x67, 0xf3,
-0x20, 0x44, 0x65, 0x6d, 0x6f, 0x6b, 0x72, 0x61, 0x74, 0xed, 0x6b, 0x69, 0x41, 0x6e, 0x67, 0xf3, 0x6c, 0x61, 0x52, 0x65,
-0x70, 0x69, 0x62, 0x69, 0x6b, 0x69, 0x20, 0x79, 0x61, 0x20, 0x41, 0x66, 0x72, 0xed, 0x6b, 0x61, 0x20, 0x79, 0x61, 0x20,
-0x4b, 0xe1, 0x74, 0x69, 0x4b, 0x6f, 0x6e, 0x67, 0x6f, 0x6c, 0x69, 0x65, 0x74, 0x75, 0x76, 0x69, 0x173, 0x4c, 0x69, 0x65,
-0x74, 0x75, 0x76, 0x61, 0x64, 0x6f, 0x6c, 0x6e, 0x6f, 0x73, 0x65, 0x72, 0x62, 0x161, 0x107, 0x69, 0x6e, 0x61, 0x4e, 0x69,
-0x6d, 0x73, 0x6b, 0x61, 0x4e, 0x65, 0x64, 0x64, 0x65, 0x72, 0x73, 0x61, 0x73, 0x73, 0x2019, 0x73, 0x63, 0x68, 0x44, 0xfc,
-0xfc, 0x74, 0x73, 0x63, 0x68, 0x6c, 0x61, 0x6e, 0x64, 0x4e, 0x65, 0x64, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x6e, 0x65,
-0x6e, 0x54, 0x73, 0x68, 0x69, 0x6c, 0x75, 0x62, 0x61, 0x44, 0x69, 0x74, 0x75, 0x6e, 0x67, 0x61, 0x20, 0x77, 0x61, 0x20,
-0x4b, 0x6f, 0x6e, 0x67, 0x75, 0x44, 0x68, 0x6f, 0x6c, 0x75, 0x6f, 0x4c, 0xeb, 0x74, 0x7a, 0x65, 0x62, 0x75, 0x65, 0x72,
-0x67, 0x65, 0x73, 0x63, 0x68, 0x4c, 0x75, 0x6c, 0x75, 0x68, 0x69, 0x61, 0x43c, 0x430, 0x43a, 0x435, 0x434, 0x43e, 0x43d, 0x441,
-0x43a, 0x438, 0x421, 0x435, 0x432, 0x435, 0x440, 0x43d, 0x430, 0x20, 0x41c, 0x430, 0x43a, 0x435, 0x434, 0x43e, 0x43d, 0x438, 0x458, 0x430,
-0x4b, 0x69, 0x6d, 0x61, 0x63, 0x68, 0x61, 0x6d, 0x65, 0x92e, 0x948, 0x925, 0x93f, 0x932, 0x940, 0x4d, 0x61, 0x6b, 0x75, 0x61,
-0x55, 0x6d, 0x6f, 0x7a, 0x61, 0x6d, 0x62, 0x69, 0x6b, 0x69, 0x43, 0x68, 0x69, 0x6d, 0x61, 0x6b, 0x6f, 0x6e, 0x64, 0x65,
-0x4d, 0x61, 0x6c, 0x61, 0x67, 0x61, 0x73, 0x79, 0x4d, 0x61, 0x64, 0x61, 0x67, 0x61, 0x73, 0x69, 0x6b, 0x61, 0x72, 0x61,
-0xd2e, 0xd32, 0xd2f, 0xd3e, 0xd33, 0xd02, 0xd07, 0xd28, 0xd4d, 0xd24, 0xd4d, 0xd2f, 0x4d, 0x65, 0x6c, 0x61, 0x79, 0x75, 0x42, 0x72,
-0x75, 0x6e, 0x65, 0x69, 0x53, 0x69, 0x6e, 0x67, 0x61, 0x70, 0x75, 0x72, 0x61, 0x4d, 0x61, 0x6c, 0x74, 0x69, 0x9ae, 0x9c8,
-0x9a4, 0x9c8, 0x9b2, 0x9cb, 0x9a8, 0x9cd, 0x987, 0x9a8, 0x9cd, 0x9a6, 0x9bf, 0x9af, 0x9bc, 0x9be, 0x47, 0x61, 0x65, 0x6c, 0x67, 0x45,
-0x6c, 0x6c, 0x61, 0x6e, 0x20, 0x56, 0x61, 0x6e, 0x6e, 0x69, 0x6e, 0x4d, 0x101, 0x6f, 0x72, 0x69, 0x41, 0x6f, 0x74, 0x65,
-0x61, 0x72, 0x6f, 0x61, 0x92e, 0x930, 0x93e, 0x920, 0x940, 0x54, 0x61, 0x6e, 0x73, 0x61, 0x6e, 0x69, 0x61, 0x645, 0x627, 0x632,
-0x631, 0x648, 0x646, 0x6cc, 0x627, 0x6cc, 0x631, 0x627, 0x646, 0x4b, 0x129, 0x6d, 0x129, 0x72, 0x169, 0x6d, 0x65, 0x74, 0x61, 0x2bc,
-0x4b, 0x61, 0x6d, 0x61, 0x6c, 0x75, 0x6e, 0x43c, 0x43e, 0x43d, 0x433, 0x43e, 0x43b, 0x41c, 0x43e, 0x43d, 0x433, 0x43e, 0x43b, 0x6b,
-0x72, 0x65, 0x6f, 0x6c, 0x20, 0x6d, 0x6f, 0x72, 0x69, 0x73, 0x69, 0x65, 0x6e, 0x4d, 0x6f, 0x72, 0x69, 0x73, 0x4d, 0x55,
-0x4e, 0x44, 0x41, 0x14a, 0x6b, 0x61, 0x6d, 0x65, 0x72, 0x75, 0x14b, 0x4b, 0x68, 0x6f, 0x65, 0x6b, 0x68, 0x6f, 0x65, 0x67,
-0x6f, 0x77, 0x61, 0x62, 0x4e, 0x61, 0x6d, 0x69, 0x62, 0x69, 0x61, 0x62, 0x928, 0x947, 0x92a, 0x93e, 0x932, 0x940, 0x53, 0x68,
-0x77, 0xf3, 0x14b, 0xf2, 0x20, 0x6e, 0x67, 0x69, 0x65, 0x6d, 0x62, 0x254, 0x254, 0x6e, 0x4b, 0xe0, 0x6d, 0x61, 0x6c, 0xfb,
-0x6d, 0x4e, 0x64, 0x61, 0xa78c, 0x61, 0x4b, 0x61, 0x6d, 0x25b, 0x6c, 0xfb, 0x6e, 0x4e, 0x61, 0x69, 0x6a, 0xed, 0x72, 0x69,
-0xe1, 0x20, 0x50, 0xed, 0x6a, 0x69, 0x6e, 0x4e, 0x61, 0x69, 0x6a, 0xed, 0x72, 0x69, 0x61, 0x644, 0x6ca, 0x631, 0x6cc, 0x20,
-0x634, 0x648, 0x645, 0x627, 0x644, 0x6cc, 0x64, 0x61, 0x76, 0x76, 0x69, 0x73, 0xe1, 0x6d, 0x65, 0x67, 0x69, 0x65, 0x6c, 0x6c,
-0x61, 0x4e, 0x6f, 0x72, 0x67, 0x61, 0x53, 0x75, 0x6f, 0x70, 0x6d, 0x61, 0x52, 0x75, 0x6f, 0x167, 0x167, 0x61, 0x69, 0x73,
-0x69, 0x4e, 0x64, 0x65, 0x62, 0x65, 0x6c, 0x65, 0x6e, 0x6f, 0x72, 0x73, 0x6b, 0x20, 0x62, 0x6f, 0x6b, 0x6d, 0xe5, 0x6c,
-0x4e, 0x6f, 0x72, 0x67, 0x65, 0x53, 0x76, 0x61, 0x6c, 0x62, 0x61, 0x72, 0x64, 0x20, 0x6f, 0x67, 0x20, 0x4a, 0x61, 0x6e,
-0x20, 0x4d, 0x61, 0x79, 0x65, 0x6e, 0x6e, 0x6f, 0x72, 0x73, 0x6b, 0x20, 0x6e, 0x79, 0x6e, 0x6f, 0x72, 0x73, 0x6b, 0x4e,
-0x6f, 0x72, 0x65, 0x67, 0x54, 0x68, 0x6f, 0x6b, 0x20, 0x4e, 0x61, 0x74, 0x68, 0x52, 0x75, 0x6e, 0x79, 0x61, 0x6e, 0x6b,
-0x6f, 0x72, 0x65, 0x6f, 0x63, 0x63, 0x69, 0x74, 0x61, 0x6e, 0x45, 0x73, 0x70, 0x61, 0x6e, 0x68, 0x61, 0xb13, 0xb21, 0xb3c,
-0xb3f, 0xb06, 0xb2d, 0xb3e, 0xb30, 0xb24, 0x4f, 0x72, 0x6f, 0x6d, 0x6f, 0x6f, 0x49, 0x74, 0x6f, 0x6f, 0x70, 0x68, 0x69, 0x79,
-0x61, 0x61, 0x4b, 0x65, 0x65, 0x6e, 0x69, 0x79, 0x61, 0x61, 0x438, 0x440, 0x43e, 0x43d, 0x413, 0x443, 0x44b, 0x440, 0x434, 0x437,
-0x44b, 0x441, 0x442, 0x43e, 0x43d, 0x423, 0x4d5, 0x440, 0x4d5, 0x441, 0x435, 0x67e, 0x69a, 0x62a, 0x648, 0x627, 0x641, 0x63a, 0x627, 0x646,
-0x633, 0x62a, 0x627, 0x646, 0x67e, 0x627, 0x6a9, 0x633, 0x62a, 0x627, 0x646, 0x641, 0x627, 0x631, 0x633, 0x6cc, 0x62f, 0x631, 0x6cc, 0x70,
-0x6f, 0x6c, 0x73, 0x6b, 0x69, 0x50, 0x6f, 0x6c, 0x73, 0x6b, 0x61, 0x70, 0x6f, 0x72, 0x74, 0x75, 0x67, 0x75, 0xea, 0x73,
-0x42, 0x72, 0x61, 0x73, 0x69, 0x6c, 0x41, 0x6e, 0x67, 0x6f, 0x6c, 0x61, 0x43, 0x61, 0x62, 0x6f, 0x20, 0x56, 0x65, 0x72,
-0x64, 0x65, 0x47, 0x75, 0x69, 0x6e, 0xe9, 0x20, 0x45, 0x71, 0x75, 0x61, 0x74, 0x6f, 0x72, 0x69, 0x61, 0x6c, 0x47, 0x75,
-0x69, 0x6e, 0xe9, 0x2d, 0x42, 0x69, 0x73, 0x73, 0x61, 0x75, 0x4c, 0x75, 0x78, 0x65, 0x6d, 0x62, 0x75, 0x72, 0x67, 0x6f,
-0x4d, 0x61, 0x63, 0x61, 0x75, 0x2c, 0x20, 0x52, 0x41, 0x45, 0x20, 0x64, 0x61, 0x20, 0x43, 0x68, 0x69, 0x6e, 0x61, 0x4d,
-0x6f, 0xe7, 0x61, 0x6d, 0x62, 0x69, 0x71, 0x75, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x75, 0x67, 0x75, 0xea, 0x73, 0x20, 0x65,
-0x75, 0x72, 0x6f, 0x70, 0x65, 0x75, 0x50, 0x6f, 0x72, 0x74, 0x75, 0x67, 0x61, 0x6c, 0x53, 0xe3, 0x6f, 0x20, 0x54, 0x6f,
-0x6d, 0xe9, 0x20, 0x65, 0x20, 0x50, 0x72, 0xed, 0x6e, 0x63, 0x69, 0x70, 0x65, 0x53, 0x75, 0xed, 0xe7, 0x61, 0x54, 0x69,
-0x6d, 0x6f, 0x72, 0x2d, 0x4c, 0x65, 0x73, 0x74, 0x65, 0xa2a, 0xa70, 0xa1c, 0xa3e, 0xa2c, 0xa40, 0xa2d, 0xa3e, 0xa30, 0xa24, 0x67e,
-0x646, 0x62c, 0x627, 0x628, 0x6cc, 0x52, 0x75, 0x6e, 0x61, 0x73, 0x69, 0x6d, 0x69, 0x50, 0x65, 0x72, 0xfa, 0x42, 0x6f, 0x6c,
-0x69, 0x76, 0x69, 0x61, 0x45, 0x63, 0x75, 0x61, 0x64, 0x6f, 0x72, 0x72, 0x6f, 0x6d, 0xe2, 0x6e, 0x103, 0x52, 0x6f, 0x6d,
-0xe2, 0x6e, 0x69, 0x61, 0x52, 0x65, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x20, 0x4d, 0x6f, 0x6c, 0x64, 0x6f, 0x76,
-0x61, 0x72, 0x75, 0x6d, 0x61, 0x6e, 0x74, 0x73, 0x63, 0x68, 0x53, 0x76, 0x69, 0x7a, 0x72, 0x61, 0x4b, 0x69, 0x68, 0x6f,
-0x72, 0x6f, 0x6d, 0x62, 0x6f, 0x49, 0x6b, 0x69, 0x72, 0x75, 0x6e, 0x64, 0x69, 0x55, 0x62, 0x75, 0x72, 0x75, 0x6e, 0x64,
-0x69, 0x440, 0x443, 0x441, 0x441, 0x43a, 0x438, 0x439, 0x420, 0x43e, 0x441, 0x441, 0x438, 0x44f, 0x41a, 0x430, 0x437, 0x430, 0x445, 0x441,
-0x442, 0x430, 0x43d, 0x41a, 0x438, 0x440, 0x433, 0x438, 0x437, 0x438, 0x44f, 0x41c, 0x43e, 0x43b, 0x434, 0x43e, 0x432, 0x430, 0x423, 0x43a,
-0x440, 0x430, 0x438, 0x43d, 0x430, 0x4b, 0x69, 0x72, 0x75, 0x77, 0x61, 0x441, 0x430, 0x445, 0x430, 0x20, 0x442, 0x44b, 0x43b, 0x430,
-0x410, 0x440, 0x430, 0x441, 0x441, 0x44b, 0x44b, 0x439, 0x430, 0x4b, 0x69, 0x73, 0x61, 0x6d, 0x70, 0x75, 0x72, 0x53, 0xe4, 0x6e,
-0x67, 0xf6, 0x4b, 0xf6, 0x64, 0xf6, 0x72, 0xf6, 0x73, 0xea, 0x73, 0x65, 0x20, 0x74, 0xee, 0x20, 0x42, 0xea, 0x61, 0x66,
-0x72, 0xee, 0x6b, 0x61, 0x49, 0x73, 0x68, 0x69, 0x73, 0x61, 0x6e, 0x67, 0x75, 0x54, 0x61, 0x6e, 0x73, 0x61, 0x6e, 0x69,
-0x79, 0x61, 0x938, 0x902, 0x938, 0x94d, 0x915, 0x943, 0x924, 0x20, 0x92d, 0x93e, 0x937, 0x93e, 0x92d, 0x93e, 0x930, 0x924, 0x903, 0x1c65,
-0x1c5f, 0x1c71, 0x1c5b, 0x1c5f, 0x1c72, 0x1c64, 0x1c64, 0x1c71, 0x1c70, 0x1c64, 0x1c6d, 0x1c5f, 0x73, 0x61, 0x72, 0x64, 0x75, 0x73, 0x65, 0x6e,
-0x61, 0x441, 0x440, 0x43f, 0x441, 0x43a, 0x438, 0x421, 0x440, 0x431, 0x438, 0x458, 0x430, 0x41a, 0x43e, 0x441, 0x43e, 0x432, 0x43e, 0x426,
-0x440, 0x43d, 0x430, 0x20, 0x413, 0x43e, 0x440, 0x430, 0x73, 0x72, 0x70, 0x73, 0x6b, 0x69, 0x4b, 0x6f, 0x73, 0x6f, 0x76, 0x6f,
-0x43, 0x72, 0x6e, 0x61, 0x20, 0x47, 0x6f, 0x72, 0x61, 0x53, 0x72, 0x62, 0x69, 0x6a, 0x61, 0x4b, 0x69, 0x73, 0x68, 0x61,
-0x6d, 0x62, 0x61, 0x61, 0x63, 0x68, 0x69, 0x53, 0x68, 0x6f, 0x6e, 0x61, 0xa188, 0xa320, 0xa259, 0xa34f, 0xa1e9, 0x633, 0x646, 0x68c,
-0x64a, 0x67e, 0x627, 0x6aa, 0x633, 0x62a, 0x627, 0x646, 0x938, 0x93f, 0x928, 0x94d, 0x927, 0x940, 0xdc3, 0xdd2, 0xd82, 0xdc4, 0xdbd, 0xdc1,
-0xdca, 0x200d, 0xdbb, 0xdd3, 0x20, 0xdbd, 0xd82, 0xd9a, 0xdcf, 0xdc0, 0x73, 0xe4, 0xe4, 0x2b9, 0x6d, 0x1e9, 0x69, 0xf5, 0x6c, 0x6c,
-0x4c, 0xe4, 0xe4, 0x2b9, 0x64, 0x64, 0x6a, 0xe2, 0x6e, 0x6e, 0x61, 0x6d, 0x73, 0x6c, 0x6f, 0x76, 0x65, 0x6e, 0x10d, 0x69,
-0x6e, 0x61, 0x53, 0x6c, 0x6f, 0x76, 0x65, 0x6e, 0x73, 0x6b, 0x6f, 0x73, 0x6c, 0x6f, 0x76, 0x65, 0x6e, 0x161, 0x10d, 0x69,
-0x6e, 0x61, 0x53, 0x6c, 0x6f, 0x76, 0x65, 0x6e, 0x69, 0x6a, 0x61, 0x4f, 0x6c, 0x75, 0x73, 0x6f, 0x67, 0x61, 0x53, 0x6f,
-0x6f, 0x6d, 0x61, 0x61, 0x6c, 0x69, 0x53, 0x6f, 0x6f, 0x6d, 0x61, 0x61, 0x6c, 0x69, 0x79, 0x61, 0x4a, 0x61, 0x62, 0x75,
-0x75, 0x74, 0x69, 0x49, 0x74, 0x6f, 0x6f, 0x62, 0x69, 0x79, 0x61, 0x65, 0x73, 0x70, 0x61, 0xf1, 0x6f, 0x6c, 0x20, 0x64,
-0x65, 0x20, 0x45, 0x73, 0x70, 0x61, 0xf1, 0x61, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x42, 0x65, 0x6c,
-0x69, 0x63, 0x65, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x61, 0x73, 0x43, 0x65, 0x75, 0x74, 0x61, 0x20, 0x79, 0x20, 0x4d,
-0x65, 0x6c, 0x69, 0x6c, 0x6c, 0x61, 0x43, 0x68, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6f, 0x6d, 0x62, 0x69, 0x61, 0x43,
-0x6f, 0x73, 0x74, 0x61, 0x20, 0x52, 0x69, 0x63, 0x61, 0x43, 0x75, 0x62, 0x61, 0x52, 0x65, 0x70, 0xfa, 0x62, 0x6c, 0x69,
-0x63, 0x61, 0x20, 0x44, 0x6f, 0x6d, 0x69, 0x6e, 0x69, 0x63, 0x61, 0x6e, 0x61, 0x45, 0x6c, 0x20, 0x53, 0x61, 0x6c, 0x76,
-0x61, 0x64, 0x6f, 0x72, 0x47, 0x75, 0x69, 0x6e, 0x65, 0x61, 0x20, 0x45, 0x63, 0x75, 0x61, 0x74, 0x6f, 0x72, 0x69, 0x61,
-0x6c, 0x47, 0x75, 0x61, 0x74, 0x65, 0x6d, 0x61, 0x6c, 0x61, 0x48, 0x6f, 0x6e, 0x64, 0x75, 0x72, 0x61, 0x73, 0x65, 0x73,
-0x70, 0x61, 0xf1, 0x6f, 0x6c, 0x20, 0x6c, 0x61, 0x74, 0x69, 0x6e, 0x6f, 0x61, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6e,
-0x6f, 0x4c, 0x61, 0x74, 0x69, 0x6e, 0x6f, 0x61, 0x6d, 0xe9, 0x72, 0x69, 0x63, 0x61, 0x65, 0x73, 0x70, 0x61, 0xf1, 0x6f,
-0x6c, 0x20, 0x64, 0x65, 0x20, 0x4d, 0xe9, 0x78, 0x69, 0x63, 0x6f, 0x4d, 0xe9, 0x78, 0x69, 0x63, 0x6f, 0x4e, 0x69, 0x63,
-0x61, 0x72, 0x61, 0x67, 0x75, 0x61, 0x50, 0x61, 0x6e, 0x61, 0x6d, 0xe1, 0x50, 0x61, 0x72, 0x61, 0x67, 0x75, 0x61, 0x79,
-0x46, 0x69, 0x6c, 0x69, 0x70, 0x69, 0x6e, 0x61, 0x73, 0x45, 0x73, 0x74, 0x61, 0x64, 0x6f, 0x73, 0x20, 0x55, 0x6e, 0x69,
-0x64, 0x6f, 0x73, 0x55, 0x72, 0x75, 0x67, 0x75, 0x61, 0x79, 0x56, 0x65, 0x6e, 0x65, 0x7a, 0x75, 0x65, 0x6c, 0x61, 0x2d5c,
-0x2d30, 0x2d4e, 0x2d30, 0x2d63, 0x2d49, 0x2d56, 0x2d5c, 0x2d4d, 0x2d4e, 0x2d56, 0x2d54, 0x2d49, 0x2d31, 0x42, 0x61, 0x73, 0x61, 0x20, 0x53, 0x75,
-0x6e, 0x64, 0x61, 0x4b, 0x69, 0x73, 0x77, 0x61, 0x68, 0x69, 0x6c, 0x69, 0x4a, 0x61, 0x6d, 0x68, 0x75, 0x72, 0x69, 0x20,
-0x79, 0x61, 0x20, 0x4b, 0x69, 0x64, 0x65, 0x6d, 0x6f, 0x6b, 0x72, 0x61, 0x73, 0x69, 0x61, 0x20, 0x79, 0x61, 0x20, 0x4b,
-0x6f, 0x6e, 0x67, 0x6f, 0x73, 0x76, 0x65, 0x6e, 0x73, 0x6b, 0x61, 0x53, 0x76, 0x65, 0x72, 0x69, 0x67, 0x65, 0xc5, 0x6c,
-0x61, 0x6e, 0x64, 0x53, 0x63, 0x68, 0x77, 0x69, 0x69, 0x7a, 0x65, 0x72, 0x74, 0xfc, 0xfc, 0x74, 0x73, 0x63, 0x68, 0x46,
-0x72, 0x61, 0x6e, 0x6b, 0x72, 0x69, 0x69, 0x63, 0x68, 0x4c, 0x69, 0xe4, 0x63, 0x68, 0x74, 0x65, 0x73, 0x63, 0x68, 0x74,
-0xe4, 0x69, 0x2d5c, 0x2d30, 0x2d5b, 0x2d4d, 0x2d43, 0x2d49, 0x2d5c, 0x54, 0x61, 0x73, 0x68, 0x65, 0x6c, 0x1e25, 0x69, 0x79, 0x74, 0x6c,
-0x6d, 0x263, 0x72, 0x69, 0x62, 0x4b, 0x69, 0x74, 0x61, 0x69, 0x74, 0x61, 0x442, 0x43e, 0x4b7, 0x438, 0x43a, 0x4e3, 0x422, 0x43e,
-0x4b7, 0x438, 0x43a, 0x438, 0x441, 0x442, 0x43e, 0x43d, 0xba4, 0xbae, 0xbbf, 0xbb4, 0xbcd, 0xb87, 0xba8, 0xbcd, 0xba4, 0xbbf, 0xbaf, 0xbbe,
-0xbae, 0xbb2, 0xbc7, 0xb9a, 0xbbf, 0xbaf, 0xbbe, 0xb9a, 0xbbf, 0xb99, 0xbcd, 0xb95, 0xbaa, 0xbcd, 0xbaa, 0xbc2, 0xbb0, 0xbcd, 0xb87, 0xbb2,
-0xb99, 0xbcd, 0xb95, 0xbc8, 0x54, 0x61, 0x73, 0x61, 0x77, 0x61, 0x71, 0x20, 0x73, 0x65, 0x6e, 0x6e, 0x69, 0x4e, 0x69, 0x17e,
-0x65, 0x72, 0x442, 0x430, 0x442, 0x430, 0x440, 0xc24, 0xc46, 0xc32, 0xc41, 0xc17, 0xc41, 0xc2d, 0xc3e, 0xc30, 0xc24, 0xc26, 0xc47, 0xc36,
-0xc02, 0x4b, 0x69, 0x74, 0x65, 0x73, 0x6f, 0x4b, 0x65, 0x6e, 0x69, 0x61, 0xe44, 0xe17, 0xe22, 0xf56, 0xf7c, 0xf51, 0xf0b, 0xf66,
-0xf90, 0xf51, 0xf0b, 0xf62, 0xf92, 0xfb1, 0xf0b, 0xf53, 0xf42, 0xf62, 0xf92, 0xfb1, 0xf0b, 0xf42, 0xf62, 0xf0b, 0x1275, 0x130d, 0x122d, 0x129b,
-0x12a4, 0x122d, 0x1275, 0x122b, 0x6c, 0x65, 0x61, 0x20, 0x66, 0x61, 0x6b, 0x61, 0x74, 0x6f, 0x6e, 0x67, 0x61, 0x54, 0xfc, 0x72,
-0x6b, 0xe7, 0x65, 0x54, 0xfc, 0x72, 0x6b, 0x69, 0x79, 0x65, 0x4b, 0x131, 0x62, 0x72, 0x131, 0x73, 0x74, 0xfc, 0x72, 0x6b,
-0x6d, 0x65, 0x6e, 0x20, 0x64, 0x69, 0x6c, 0x69, 0x54, 0xfc, 0x72, 0x6b, 0x6d, 0x65, 0x6e, 0x69, 0x73, 0x74, 0x61, 0x6e,
-0x443, 0x43a, 0x440, 0x430, 0x457, 0x43d, 0x441, 0x44c, 0x43a, 0x430, 0x423, 0x43a, 0x440, 0x430, 0x457, 0x43d, 0x430, 0x68, 0x6f, 0x72,
-0x6e, 0x6a, 0x6f, 0x73, 0x65, 0x72, 0x62, 0x161, 0x107, 0x69, 0x6e, 0x61, 0x4e, 0x11b, 0x6d, 0x73, 0x6b, 0x61, 0x627, 0x631,
-0x62f, 0x648, 0x628, 0x6be, 0x627, 0x631, 0x62a, 0x626, 0x6c7, 0x64a, 0x63a, 0x6c7, 0x631, 0x686, 0x6d5, 0x62c, 0x6c7, 0x6ad, 0x6af, 0x648,
-0x6f, 0x2018, 0x7a, 0x62, 0x65, 0x6b, 0x4f, 0x2bb, 0x7a, 0x62, 0x65, 0x6b, 0x69, 0x73, 0x74, 0x6f, 0x6e, 0x627, 0x648, 0x632,
-0x628, 0x6cc, 0x6a9, 0x45e, 0x437, 0x431, 0x435, 0x43a, 0x447, 0x430, 0x40e, 0x437, 0x431, 0x435, 0x43a, 0x438, 0x441, 0x442, 0x43e, 0x43d,
-0xa559, 0xa524, 0xa55e, 0xa524, 0xa52b, 0xa569, 0x56, 0x61, 0x69, 0x4c, 0x61, 0x69, 0x62, 0x68, 0x69, 0x79, 0x61, 0x54, 0x69, 0x1ebf,
-0x6e, 0x67, 0x20, 0x56, 0x69, 0x1ec7, 0x74, 0x56, 0x69, 0x1ec7, 0x74, 0x20, 0x4e, 0x61, 0x6d, 0x4b, 0x79, 0x69, 0x76, 0x75,
-0x6e, 0x6a, 0x6f, 0x57, 0x61, 0x6c, 0x73, 0x65, 0x72, 0x53, 0x63, 0x68, 0x77, 0x69, 0x7a, 0x43, 0x79, 0x6d, 0x72, 0x61,
-0x65, 0x67, 0x59, 0x20, 0x44, 0x65, 0x79, 0x72, 0x6e, 0x61, 0x73, 0x20, 0x55, 0x6e, 0x65, 0x64, 0x69, 0x67, 0x46, 0x72,
-0x79, 0x73, 0x6b, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0xe2, 0x6e, 0x57, 0x6f, 0x6c, 0x6f, 0x66, 0x49, 0x73, 0x69, 0x58,
-0x68, 0x6f, 0x73, 0x61, 0x45, 0x4d, 0x7a, 0x61, 0x6e, 0x74, 0x73, 0x69, 0x20, 0x41, 0x66, 0x72, 0x69, 0x6b, 0x61, 0x6e,
-0x75, 0x61, 0x73, 0x75, 0x65, 0x4b, 0x65, 0x6d, 0x65, 0x6c, 0xfa, 0x6e, 0x5d9, 0x5d9, 0x5b4, 0x5d3, 0x5d9, 0x5e9, 0x5d5, 0x5d5,
-0x5e2, 0x5dc, 0x5d8, 0xc8, 0x64, 0xe8, 0x20, 0x59, 0x6f, 0x72, 0xf9, 0x62, 0xe1, 0x4e, 0xe0, 0xec, 0x6a, 0xed, 0x72, 0xed,
-0xe0, 0x42, 0x25b, 0x300, 0x6e, 0x25b, 0x300, 0x5a, 0x61, 0x72, 0x6d, 0x61, 0x63, 0x69, 0x69, 0x6e, 0x65, 0x69, 0x73, 0x69,
-0x5a, 0x75, 0x6c, 0x75, 0x69, 0x4e, 0x69, 0x6e, 0x67, 0x69, 0x7a, 0x69, 0x6d, 0x75, 0x20, 0x41, 0x66, 0x72, 0x69, 0x6b,
-0x61, 0x6b, 0x61, 0x6e, 0x68, 0x67, 0xe1, 0x67, 0x4d, 0x72, 0x61, 0x73, 0x69, 0x72, 0x6e, 0x68, 0x65, 0x1ebd, 0x67, 0x61,
-0x74, 0x75, 0x42, 0x72, 0x61, 0x73, 0x69, 0x75, 0xf1, 0x65, 0x6e, 0x67, 0x61, 0x74, 0xfa, 0x4b, 0x75, 0x72, 0x169, 0x62,
-0x69, 0x79, 0x61, 0x57, 0x65, 0x6e, 0x65, 0x73, 0x75, 0x65, 0x72, 0x61, 0x939, 0x930, 0x93f, 0x92f, 0x93e, 0x923, 0x935, 0x940,
-0x4e, 0x6f, 0x72, 0x64, 0x66, 0x72, 0x69, 0x69, 0x73, 0x6b, 0x54, 0x6a, 0x69, 0x69, 0x73, 0x6b, 0x6c, 0x75, 0x6e, 0x930,
-0x93e, 0x91c, 0x938, 0x94d, 0x925, 0x93e, 0x928, 0x940, 0x43c, 0x43e, 0x43a, 0x448, 0x435, 0x43d, 0x44c, 0x20, 0x43a, 0x44f, 0x43b, 0x44c,
-0x54, 0x6f, 0x6b, 0x69, 0x20, 0x50, 0x6f, 0x6e, 0x61, 0x6d, 0x61, 0x20, 0x61, 0x6c, 0x65, 0x50, 0x69, 0x6a, 0x69, 0x6e,
-0x53, 0x6f, 0x6c, 0x6f, 0x6d, 0x6f, 0x6e, 0x20, 0x41, 0x65, 0x6c, 0x61, 0x6e, 0x4f, 0x62, 0x6f, 0x6c, 0x6f
+0x410, 0x525, 0x441, 0x448, 0x4d9, 0x430, 0x49a, 0x44b, 0x440, 0x4ad, 0x442, 0x4d9,
+0x44b, 0x43b, 0x430, 0x51, 0x61, 0x66, 0x61, 0x72, 0x4f, 0x74, 0x6f, 0x62,
+0x62, 0x69, 0x61, 0x59, 0x61, 0x62, 0x75, 0x75, 0x74, 0x69, 0x45, 0x72,
+0x65, 0x74, 0x72, 0x69, 0x61, 0x41, 0x66, 0x72, 0x69, 0x6b, 0x61, 0x61,
+0x6e, 0x73, 0x53, 0x75, 0x69, 0x64, 0x2d, 0x41, 0x66, 0x72, 0x69, 0x6b,
+0x61, 0x4e, 0x61, 0x6d, 0x69, 0x62, 0x69, 0xeb, 0x41, 0x67, 0x68, 0x65,
+0x6d, 0x4b, 0xe0, 0x6d, 0xe0, 0x6c, 0xfb, 0x14b, 0x41, 0x6b, 0x61, 0x6e,
+0x47, 0x61, 0x61, 0x6e, 0x61, 0x41, 0x6b, 0x6f, 0x6f, 0x73, 0x65, 0x4b,
+0x61, 0x6d, 0x65, 0x72, 0xfb, 0x6e, 0x73, 0x68, 0x71, 0x69, 0x70, 0x53,
+0x68, 0x71, 0x69, 0x70, 0xeb, 0x72, 0x69, 0x4b, 0x6f, 0x73, 0x6f, 0x76,
+0xeb, 0x4d, 0x61, 0x71, 0x65, 0x64, 0x6f, 0x6e, 0x69, 0x61, 0x20, 0x65,
+0x20, 0x56, 0x65, 0x72, 0x69, 0x75, 0x74, 0x12a0, 0x121b, 0x122d, 0x129b, 0x12a2,
+0x1275, 0x12ee, 0x1335, 0x12eb, 0x627, 0x644, 0x639, 0x631, 0x628, 0x64a, 0x629, 0x645,
+0x635, 0x631, 0x627, 0x644, 0x62c, 0x632, 0x627, 0x626, 0x631, 0x627, 0x644, 0x628,
+0x62d, 0x631, 0x64a, 0x646, 0x62a, 0x634, 0x627, 0x62f, 0x62c, 0x632, 0x631, 0x20,
+0x627, 0x644, 0x642, 0x645, 0x631, 0x62c, 0x64a, 0x628, 0x648, 0x62a, 0x64a, 0x625,
+0x631, 0x64a, 0x62a, 0x631, 0x64a, 0x627, 0x627, 0x644, 0x639, 0x631, 0x627, 0x642,
+0x625, 0x633, 0x631, 0x627, 0x626, 0x64a, 0x644, 0x627, 0x644, 0x623, 0x631, 0x62f,
+0x646, 0x627, 0x644, 0x643, 0x648, 0x64a, 0x62a, 0x644, 0x628, 0x646, 0x627, 0x646,
+0x644, 0x64a, 0x628, 0x64a, 0x627, 0x645, 0x648, 0x631, 0x64a, 0x62a, 0x627, 0x646,
+0x64a, 0x627, 0x627, 0x644, 0x645, 0x63a, 0x631, 0x628, 0x639, 0x64f, 0x645, 0x627,
+0x646, 0x627, 0x644, 0x623, 0x631, 0x627, 0x636, 0x64a, 0x20, 0x627, 0x644, 0x641,
+0x644, 0x633, 0x637, 0x64a, 0x646, 0x64a, 0x629, 0x642, 0x637, 0x631, 0x627, 0x644,
+0x645, 0x645, 0x644, 0x643, 0x629, 0x20, 0x627, 0x644, 0x639, 0x631, 0x628, 0x64a,
+0x629, 0x20, 0x627, 0x644, 0x633, 0x639, 0x648, 0x62f, 0x64a, 0x629, 0x627, 0x644,
+0x635, 0x648, 0x645, 0x627, 0x644, 0x62c, 0x646, 0x648, 0x628, 0x20, 0x627, 0x644,
+0x633, 0x648, 0x62f, 0x627, 0x646, 0x627, 0x644, 0x633, 0x648, 0x62f, 0x627, 0x646,
+0x633, 0x648, 0x631, 0x64a, 0x627, 0x62a, 0x648, 0x646, 0x633, 0x627, 0x644, 0x625,
+0x645, 0x627, 0x631, 0x627, 0x62a, 0x20, 0x627, 0x644, 0x639, 0x631, 0x628, 0x64a,
+0x629, 0x20, 0x627, 0x644, 0x645, 0x62a, 0x62d, 0x62f, 0x629, 0x627, 0x644, 0x635,
+0x62d, 0x631, 0x627, 0x621, 0x20, 0x627, 0x644, 0x63a, 0x631, 0x628, 0x64a, 0x629,
+0x627, 0x644, 0x639, 0x631, 0x628, 0x64a, 0x629, 0x20, 0x627, 0x644, 0x641, 0x635,
+0x62d, 0x649, 0x20, 0x627, 0x644, 0x62d, 0x62f, 0x64a, 0x62b, 0x629, 0x627, 0x644,
+0x639, 0x627, 0x644, 0x645, 0x627, 0x644, 0x64a, 0x645, 0x646, 0x61, 0x72, 0x61,
+0x67, 0x6f, 0x6e, 0xe9, 0x73, 0x45, 0x73, 0x70, 0x61, 0x6e, 0x79, 0x61,
+0x570, 0x561, 0x575, 0x565, 0x580, 0x565, 0x576, 0x540, 0x561, 0x575, 0x561, 0x57d,
+0x57f, 0x561, 0x576, 0x985, 0x9b8, 0x9ae, 0x9c0, 0x9af, 0x9bc, 0x9be, 0x9ad, 0x9be,
+0x9f0, 0x9a4, 0x61, 0x73, 0x74, 0x75, 0x72, 0x69, 0x61, 0x6e, 0x75, 0x45,
+0x73, 0x70, 0x61, 0xf1, 0x61, 0x4b, 0x69, 0x70, 0x61, 0x72, 0x65, 0x54,
+0x61, 0x64, 0x68, 0x61, 0x6e, 0x69, 0x61, 0x41, 0x74, 0x73, 0x61, 0x6d,
+0x61, 0x7a, 0x259, 0x72, 0x62, 0x61, 0x79, 0x63, 0x61, 0x6e, 0x41, 0x7a,
+0x259, 0x72, 0x62, 0x61, 0x79, 0x63, 0x61, 0x6e, 0x62a, 0x6c6, 0x631, 0x6a9,
+0x62c, 0x647, 0x430, 0x437, 0x4d9, 0x440, 0x431, 0x430, 0x458, 0x4b9, 0x430, 0x43d,
+0x410, 0x437, 0x4d9, 0x440, 0x431, 0x430, 0x458, 0x4b9, 0x430, 0x43d, 0x72, 0x69,
+0x6b, 0x70, 0x61, 0x6b, 0x61, 0x6d, 0x25b, 0x72, 0xfa, 0x6e, 0x62, 0x61,
+0x6d, 0x61, 0x6e, 0x61, 0x6b, 0x61, 0x6e, 0x4d, 0x61, 0x6c, 0x69, 0x9ac,
+0x9be, 0x982, 0x9b2, 0x9be, 0x9ac, 0x9be, 0x982, 0x9b2, 0x9be, 0x9a6, 0x9c7, 0x9b6,
+0x9ad, 0x9be, 0x9b0, 0x9a4, 0x181, 0xe0, 0x73, 0xe0, 0x61, 0x4b, 0xe0, 0x6d,
+0x25b, 0x300, 0x72, 0xfb, 0x6e, 0x431, 0x430, 0x448, 0x4a1, 0x43e, 0x440, 0x442,
+0x20, 0x442, 0x435, 0x43b, 0x435, 0x65, 0x75, 0x73, 0x6b, 0x61, 0x72, 0x61,
+0x45, 0x73, 0x70, 0x61, 0x69, 0x6e, 0x69, 0x61, 0x431, 0x435, 0x43b, 0x430,
+0x440, 0x443, 0x441, 0x43a, 0x430, 0x44f, 0x411, 0x435, 0x43b, 0x430, 0x440, 0x443,
+0x441, 0x44c, 0x49, 0x63, 0x68, 0x69, 0x62, 0x65, 0x6d, 0x62, 0x61, 0x5a,
+0x61, 0x6d, 0x62, 0x69, 0x61, 0x48, 0x69, 0x62, 0x65, 0x6e, 0x61, 0x48,
+0x75, 0x74, 0x61, 0x6e, 0x7a, 0x61, 0x6e, 0x69, 0x61, 0x92d, 0x94b, 0x91c,
+0x92a, 0x941, 0x930, 0x940, 0x92d, 0x93e, 0x930, 0x924, 0x1265, 0x120a, 0x1295, 0x12a4,
+0x122d, 0x1275, 0x122b, 0x92c, 0x930, 0x2019, 0x62, 0x6f, 0x73, 0x61, 0x6e, 0x73,
+0x6b, 0x69, 0x42, 0x6f, 0x73, 0x6e, 0x61, 0x20, 0x69, 0x20, 0x48, 0x65,
+0x72, 0x63, 0x65, 0x67, 0x6f, 0x76, 0x69, 0x6e, 0x61, 0x431, 0x43e, 0x441,
+0x430, 0x43d, 0x441, 0x43a, 0x438, 0x411, 0x43e, 0x441, 0x43d, 0x430, 0x20, 0x438,
+0x20, 0x425, 0x435, 0x440, 0x446, 0x435, 0x433, 0x43e, 0x432, 0x438, 0x43d, 0x430,
+0x62, 0x72, 0x65, 0x7a, 0x68, 0x6f, 0x6e, 0x65, 0x67, 0x46, 0x72, 0x61,
+0xf1, 0x73, 0x431, 0x44a, 0x43b, 0x433, 0x430, 0x440, 0x441, 0x43a, 0x438, 0x411,
+0x44a, 0x43b, 0x433, 0x430, 0x440, 0x438, 0x44f, 0x1019, 0x103c, 0x1014, 0x103a, 0x1019,
+0x102c, 0x7cb5, 0x8a9e, 0x4e2d, 0x83ef, 0x4eba, 0x6c11, 0x5171, 0x548c, 0x570b, 0x9999, 0x6e2f,
+0x7279, 0x5225, 0x884c, 0x653f, 0x5340, 0x7ca4, 0x8bed, 0x4e2d, 0x534e, 0x4eba, 0x6c11, 0x5171,
+0x548c, 0x56fd, 0x63, 0x61, 0x74, 0x61, 0x6c, 0xe0, 0x41, 0x6e, 0x64, 0x6f,
+0x72, 0x72, 0x61, 0x46, 0x72, 0x61, 0x6e, 0xe7, 0x61, 0x49, 0x74, 0xe0,
+0x6c, 0x69, 0x61, 0x43, 0x65, 0x62, 0x75, 0x61, 0x6e, 0x6f, 0x50, 0x69,
+0x6c, 0x69, 0x70, 0x69, 0x6e, 0x61, 0x73, 0x54, 0x61, 0x6d, 0x61, 0x7a,
+0x69, 0x263, 0x74, 0x20, 0x6e, 0x20, 0x6c, 0x61, 0x1e6d, 0x6c, 0x61, 0x1e63,
+0x4d, 0x65, 0x1e5b, 0x1e5b, 0x75, 0x6b, 0x6a9, 0x648, 0x631, 0x62f, 0x6cc, 0x6cc,
+0x20, 0x646, 0x627, 0x648, 0x6d5, 0x646, 0x62f, 0x6cc, 0x639, 0x6ce, 0x631, 0x627,
+0x642, 0x626, 0x6ce, 0x631, 0x627, 0x646, 0xd804, 0xdd0c, 0xd804, 0xdd0b, 0xd804, 0xdd34,
+0xd804, 0xdd1f, 0xd804, 0xdd33, 0xd804, 0xdd26, 0xd804, 0xdd1d, 0xd804, 0xdd01, 0xd804, 0xdd23,
+0xd804, 0xdd18, 0xd804, 0xdd2c, 0xd804, 0xdd0c, 0xd804, 0xdd34, 0xd804, 0xdd1e, 0xd804, 0xdd22,
+0xd804, 0xdd27, 0xd804, 0xdd16, 0xd804, 0xdd34, 0x43d, 0x43e, 0x445, 0x447, 0x438, 0x439,
+0x43d, 0x420, 0x43e, 0x441, 0x441, 0x438, 0x13e3, 0x13b3, 0x13a9, 0x13cc, 0x13ca, 0x20,
+0x13a2, 0x13f3, 0x13be, 0x13b5, 0x13cd, 0x13d4, 0x13c5, 0x20, 0x13cd, 0x13a6, 0x13da, 0x13a9,
+0x43, 0x68, 0x69, 0x6b, 0x61, 0x73, 0x68, 0x73, 0x68, 0x61, 0x6e, 0x6f,
+0x6d, 0x70, 0x61, 0x2bc, 0x55, 0x6e, 0x69, 0x74, 0x65, 0x64, 0x20, 0x53,
+0x74, 0x61, 0x74, 0x65, 0x73, 0x52, 0x75, 0x6b, 0x69, 0x67, 0x61, 0x55,
+0x67, 0x61, 0x6e, 0x64, 0x61, 0x7b80, 0x4f53, 0x4e2d, 0x6587, 0x4e2d, 0x56fd, 0x4e2d,
+0x56fd, 0x9999, 0x6e2f, 0x7279, 0x522b, 0x884c, 0x653f, 0x533a, 0x4e2d, 0x56fd, 0x6fb3, 0x95e8,
+0x7279, 0x522b, 0x884c, 0x653f, 0x533a, 0x65b0, 0x52a0, 0x5761, 0x7e41, 0x9ad4, 0x4e2d, 0x6587,
+0x4e2d, 0x570b, 0x9999, 0x6e2f, 0x7279, 0x5225, 0x884c, 0x653f, 0x5340, 0x4e2d, 0x570b, 0x6fb3,
+0x9580, 0x7279, 0x5225, 0x884c, 0x653f, 0x5340, 0x53f0, 0x7063, 0x446, 0x435, 0x440, 0x43a,
+0x43e, 0x432, 0x43d, 0x43e, 0x441, 0x43b, 0x43e, 0x432, 0x435, 0x301, 0x43d, 0x441,
+0x43a, 0x457, 0x439, 0x440, 0x461, 0x441, 0x441, 0x456, 0x301, 0x430, 0x447, 0x4d1,
+0x432, 0x430, 0x448, 0x420, 0x430, 0x4ab, 0x4ab, 0x435, 0x439, 0x4b, 0xf6, 0x6c,
+0x73, 0x63, 0x68, 0x44, 0x6f, 0xfc, 0x74, 0x73, 0x63, 0x68, 0x6c, 0x61,
+0x6e, 0x64, 0x6b, 0x65, 0x72, 0x6e, 0x65, 0x77, 0x65, 0x6b, 0x52, 0x79,
+0x77, 0x76, 0x61, 0x6e, 0x65, 0x74, 0x68, 0x20, 0x55, 0x6e, 0x79, 0x73,
+0x63, 0x6f, 0x72, 0x73, 0x75, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x69, 0x61,
+0x68, 0x72, 0x76, 0x61, 0x74, 0x73, 0x6b, 0x69, 0x48, 0x72, 0x76, 0x61,
+0x74, 0x73, 0x6b, 0x61, 0x10d, 0x65, 0x161, 0x74, 0x69, 0x6e, 0x61, 0x10c,
+0x65, 0x73, 0x6b, 0x6f, 0x64, 0x61, 0x6e, 0x73, 0x6b, 0x44, 0x61, 0x6e,
+0x6d, 0x61, 0x72, 0x6b, 0x47, 0x72, 0xf8, 0x6e, 0x6c, 0x61, 0x6e, 0x64,
+0x78b, 0x7a8, 0x788, 0x7ac, 0x780, 0x7a8, 0x784, 0x7a6, 0x790, 0x7b0, 0x78b, 0x7a8,
+0x788, 0x7ac, 0x780, 0x7a8, 0x20, 0x783, 0x7a7, 0x787, 0x7b0, 0x796, 0x7ac, 0x921,
+0x94b, 0x917, 0x930, 0x940, 0x64, 0x75, 0xe1, 0x6c, 0xe1, 0x43, 0x61, 0x6d,
+0x65, 0x72, 0x6f, 0x75, 0x6e, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c, 0x61,
+0x6e, 0x64, 0x73, 0x41, 0x72, 0x75, 0x62, 0x61, 0x56, 0x6c, 0x61, 0x61,
+0x6d, 0x73, 0x42, 0x65, 0x6c, 0x67, 0x69, 0xeb, 0x43, 0x61, 0x72, 0x69,
+0x62, 0x69, 0x73, 0x63, 0x68, 0x20, 0x4e, 0x65, 0x64, 0x65, 0x72, 0x6c,
+0x61, 0x6e, 0x64, 0x43, 0x75, 0x72, 0x61, 0xe7, 0x61, 0x6f, 0x53, 0x69,
+0x6e, 0x74, 0x2d, 0x4d, 0x61, 0x61, 0x72, 0x74, 0x65, 0x6e, 0x53, 0x75,
+0x72, 0x69, 0x6e, 0x61, 0x6d, 0x65, 0xf62, 0xfab, 0xf7c, 0xf44, 0xf0b, 0xf41,
+0xf60, 0xf56, 0xfb2, 0xf74, 0xf42, 0x4b, 0x129, 0x65, 0x6d, 0x62, 0x75, 0x4b,
+0x65, 0x6e, 0x79, 0x61, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6e,
+0x20, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68, 0xd801, 0xdc00, 0xd801, 0xdc4d,
+0xd801, 0xdc4a, 0xd801, 0xdc2e, 0xd801, 0xdc47, 0xd801, 0xdc0f, 0xd801, 0xdc2d, 0xd801, 0xdc4c,
+0xd801, 0xdc34, 0xd801, 0xdc3b, 0xd801, 0xdc32, 0xd801, 0xdc3c, 0x20, 0xd801, 0xdc1d, 0xd801,
+0xdc3b, 0xd801, 0xdc29, 0xd801, 0xdc3b, 0xd801, 0xdc45, 0x41, 0x6d, 0x65, 0x72, 0x69,
+0x63, 0x61, 0x6e, 0x20, 0x53, 0x61, 0x6d, 0x6f, 0x61, 0x41, 0x6e, 0x67,
+0x75, 0x69, 0x6c, 0x6c, 0x61, 0x41, 0x6e, 0x74, 0x69, 0x67, 0x75, 0x61,
+0x20, 0x26, 0x20, 0x42, 0x61, 0x72, 0x62, 0x75, 0x64, 0x61, 0x41, 0x75,
+0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x6e, 0x20, 0x45, 0x6e, 0x67,
+0x6c, 0x69, 0x73, 0x68, 0x41, 0x75, 0x73, 0x74, 0x72, 0x69, 0x61, 0x42,
+0x61, 0x68, 0x61, 0x6d, 0x61, 0x73, 0x42, 0x61, 0x72, 0x62, 0x61, 0x64,
+0x6f, 0x73, 0x42, 0x65, 0x6c, 0x67, 0x69, 0x75, 0x6d, 0x42, 0x65, 0x6c,
+0x69, 0x7a, 0x65, 0x42, 0x65, 0x72, 0x6d, 0x75, 0x64, 0x61, 0x42, 0x6f,
+0x74, 0x73, 0x77, 0x61, 0x6e, 0x61, 0x42, 0x72, 0x69, 0x74, 0x69, 0x73,
+0x68, 0x20, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x4f, 0x63, 0x65,
+0x61, 0x6e, 0x20, 0x54, 0x65, 0x72, 0x72, 0x69, 0x74, 0x6f, 0x72, 0x79,
+0x42, 0x72, 0x69, 0x74, 0x69, 0x73, 0x68, 0x20, 0x56, 0x69, 0x72, 0x67,
+0x69, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x42, 0x75,
+0x72, 0x75, 0x6e, 0x64, 0x69, 0x43, 0x61, 0x6d, 0x65, 0x72, 0x6f, 0x6f,
+0x6e, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x69, 0x61, 0x6e, 0x20, 0x45, 0x6e,
+0x67, 0x6c, 0x69, 0x73, 0x68, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x43,
+0x61, 0x79, 0x6d, 0x61, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64,
+0x73, 0x43, 0x68, 0x72, 0x69, 0x73, 0x74, 0x6d, 0x61, 0x73, 0x20, 0x49,
+0x73, 0x6c, 0x61, 0x6e, 0x64, 0x43, 0x6f, 0x63, 0x6f, 0x73, 0x20, 0x28,
+0x4b, 0x65, 0x65, 0x6c, 0x69, 0x6e, 0x67, 0x29, 0x20, 0x49, 0x73, 0x6c,
+0x61, 0x6e, 0x64, 0x73, 0x43, 0x6f, 0x6f, 0x6b, 0x20, 0x49, 0x73, 0x6c,
+0x61, 0x6e, 0x64, 0x73, 0x43, 0x79, 0x70, 0x72, 0x75, 0x73, 0x44, 0x65,
+0x6e, 0x6d, 0x61, 0x72, 0x6b, 0x44, 0x69, 0x65, 0x67, 0x6f, 0x20, 0x47,
+0x61, 0x72, 0x63, 0x69, 0x61, 0x44, 0x6f, 0x6d, 0x69, 0x6e, 0x69, 0x63,
+0x61, 0x45, 0x72, 0x69, 0x74, 0x72, 0x65, 0x61, 0x45, 0x73, 0x77, 0x61,
+0x74, 0x69, 0x6e, 0x69, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x46, 0x61,
+0x6c, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e,
+0x64, 0x73, 0x46, 0x69, 0x6a, 0x69, 0x46, 0x69, 0x6e, 0x6c, 0x61, 0x6e,
+0x64, 0x47, 0x61, 0x6d, 0x62, 0x69, 0x61, 0x47, 0x65, 0x72, 0x6d, 0x61,
+0x6e, 0x79, 0x47, 0x68, 0x61, 0x6e, 0x61, 0x47, 0x69, 0x62, 0x72, 0x61,
+0x6c, 0x74, 0x61, 0x72, 0x47, 0x72, 0x65, 0x6e, 0x61, 0x64, 0x61, 0x47,
+0x75, 0x61, 0x6d, 0x47, 0x75, 0x65, 0x72, 0x6e, 0x73, 0x65, 0x79, 0x47,
+0x75, 0x79, 0x61, 0x6e, 0x61, 0x48, 0x6f, 0x6e, 0x67, 0x20, 0x4b, 0x6f,
+0x6e, 0x67, 0x20, 0x53, 0x41, 0x52, 0x20, 0x43, 0x68, 0x69, 0x6e, 0x61,
+0x49, 0x6e, 0x64, 0x6f, 0x6e, 0x65, 0x73, 0x69, 0x61, 0x49, 0x72, 0x65,
+0x6c, 0x61, 0x6e, 0x64, 0x49, 0x73, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20,
+0x4d, 0x61, 0x6e, 0x49, 0x73, 0x72, 0x61, 0x65, 0x6c, 0x4a, 0x61, 0x6d,
+0x61, 0x69, 0x63, 0x61, 0x4a, 0x65, 0x72, 0x73, 0x65, 0x79, 0x4b, 0x69,
+0x72, 0x69, 0x62, 0x61, 0x74, 0x69, 0x4c, 0x65, 0x73, 0x6f, 0x74, 0x68,
+0x6f, 0x4c, 0x69, 0x62, 0x65, 0x72, 0x69, 0x61, 0x4d, 0x61, 0x63, 0x61,
+0x6f, 0x20, 0x53, 0x41, 0x52, 0x20, 0x43, 0x68, 0x69, 0x6e, 0x61, 0x4d,
+0x61, 0x64, 0x61, 0x67, 0x61, 0x73, 0x63, 0x61, 0x72, 0x4d, 0x61, 0x6c,
+0x61, 0x77, 0x69, 0x4d, 0x61, 0x6c, 0x61, 0x79, 0x73, 0x69, 0x61, 0x4d,
+0x61, 0x6c, 0x64, 0x69, 0x76, 0x65, 0x73, 0x4d, 0x61, 0x6c, 0x74, 0x61,
+0x4d, 0x61, 0x72, 0x73, 0x68, 0x61, 0x6c, 0x6c, 0x20, 0x49, 0x73, 0x6c,
+0x61, 0x6e, 0x64, 0x73, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x69, 0x75,
+0x73, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x6e, 0x65, 0x73, 0x69, 0x61, 0x4d,
+0x6f, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x72, 0x61, 0x74, 0x4e, 0x61, 0x6d,
+0x69, 0x62, 0x69, 0x61, 0x4e, 0x61, 0x75, 0x72, 0x75, 0x4e, 0x65, 0x74,
+0x68, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x4e, 0x65, 0x77, 0x20,
+0x5a, 0x65, 0x61, 0x6c, 0x61, 0x6e, 0x64, 0x4e, 0x69, 0x67, 0x65, 0x72,
+0x69, 0x61, 0x4e, 0x69, 0x75, 0x65, 0x4e, 0x6f, 0x72, 0x66, 0x6f, 0x6c,
+0x6b, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x4e, 0x6f, 0x72, 0x74,
+0x68, 0x65, 0x72, 0x6e, 0x20, 0x4d, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x61,
+0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x50, 0x61, 0x6b, 0x69,
+0x73, 0x74, 0x61, 0x6e, 0x50, 0x61, 0x6c, 0x61, 0x75, 0x50, 0x61, 0x70,
+0x75, 0x61, 0x20, 0x4e, 0x65, 0x77, 0x20, 0x47, 0x75, 0x69, 0x6e, 0x65,
+0x61, 0x50, 0x68, 0x69, 0x6c, 0x69, 0x70, 0x70, 0x69, 0x6e, 0x65, 0x73,
+0x50, 0x69, 0x74, 0x63, 0x61, 0x69, 0x72, 0x6e, 0x20, 0x49, 0x73, 0x6c,
+0x61, 0x6e, 0x64, 0x73, 0x50, 0x75, 0x65, 0x72, 0x74, 0x6f, 0x20, 0x52,
+0x69, 0x63, 0x6f, 0x52, 0x77, 0x61, 0x6e, 0x64, 0x61, 0x53, 0x74, 0x20,
+0x48, 0x65, 0x6c, 0x65, 0x6e, 0x61, 0x53, 0x74, 0x20, 0x4b, 0x69, 0x74,
+0x74, 0x73, 0x20, 0x26, 0x20, 0x4e, 0x65, 0x76, 0x69, 0x73, 0x53, 0x74,
+0x20, 0x4c, 0x75, 0x63, 0x69, 0x61, 0x53, 0x74, 0x20, 0x56, 0x69, 0x6e,
+0x63, 0x65, 0x6e, 0x74, 0x20, 0x26, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47,
+0x72, 0x65, 0x6e, 0x61, 0x64, 0x69, 0x6e, 0x65, 0x73, 0x53, 0x65, 0x79,
+0x63, 0x68, 0x65, 0x6c, 0x6c, 0x65, 0x73, 0x53, 0x69, 0x65, 0x72, 0x72,
+0x61, 0x20, 0x4c, 0x65, 0x6f, 0x6e, 0x65, 0x53, 0x69, 0x6e, 0x67, 0x61,
+0x70, 0x6f, 0x72, 0x65, 0x53, 0x69, 0x6e, 0x74, 0x20, 0x4d, 0x61, 0x61,
+0x72, 0x74, 0x65, 0x6e, 0x53, 0x6c, 0x6f, 0x76, 0x65, 0x6e, 0x69, 0x61,
+0x53, 0x6f, 0x6c, 0x6f, 0x6d, 0x6f, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61,
+0x6e, 0x64, 0x73, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x41, 0x66, 0x72,
+0x69, 0x63, 0x61, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x53, 0x75, 0x64,
+0x61, 0x6e, 0x53, 0x75, 0x64, 0x61, 0x6e, 0x53, 0x77, 0x65, 0x64, 0x65,
+0x6e, 0x53, 0x77, 0x69, 0x74, 0x7a, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x64,
+0x54, 0x61, 0x6e, 0x7a, 0x61, 0x6e, 0x69, 0x61, 0x54, 0x6f, 0x6b, 0x65,
+0x6c, 0x61, 0x75, 0x54, 0x6f, 0x6e, 0x67, 0x61, 0x54, 0x72, 0x69, 0x6e,
+0x69, 0x64, 0x61, 0x64, 0x20, 0x26, 0x20, 0x54, 0x6f, 0x62, 0x61, 0x67,
+0x6f, 0x54, 0x75, 0x72, 0x6b, 0x73, 0x20, 0x26, 0x20, 0x43, 0x61, 0x69,
+0x63, 0x6f, 0x73, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x54,
+0x75, 0x76, 0x61, 0x6c, 0x75, 0x55, 0x6e, 0x69, 0x74, 0x65, 0x64, 0x20,
+0x41, 0x72, 0x61, 0x62, 0x20, 0x45, 0x6d, 0x69, 0x72, 0x61, 0x74, 0x65,
+0x73, 0x42, 0x72, 0x69, 0x74, 0x69, 0x73, 0x68, 0x20, 0x45, 0x6e, 0x67,
+0x6c, 0x69, 0x73, 0x68, 0x55, 0x6e, 0x69, 0x74, 0x65, 0x64, 0x20, 0x4b,
+0x69, 0x6e, 0x67, 0x64, 0x6f, 0x6d, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x4f,
+0x75, 0x74, 0x6c, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x49, 0x73, 0x6c, 0x61,
+0x6e, 0x64, 0x73, 0x55, 0x2e, 0x53, 0x2e, 0x20, 0x56, 0x69, 0x72, 0x67,
+0x69, 0x6e, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x56, 0x61,
+0x6e, 0x75, 0x61, 0x74, 0x75, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x5a, 0x69,
+0x6d, 0x62, 0x61, 0x62, 0x77, 0x65, 0x44d, 0x440, 0x437, 0x44f, 0x43d, 0x44c,
+0x20, 0x43a, 0x435, 0x43b, 0x44c, 0x420, 0x443, 0x437, 0x43e, 0x43d, 0x44c, 0x20,
+0x43c, 0x430, 0x441, 0x442, 0x43e, 0x440, 0x45, 0x73, 0x70, 0x65, 0x72, 0x61,
+0x6e, 0x74, 0x6f, 0x6d, 0x6f, 0x6e, 0x64, 0x6f, 0x65, 0x65, 0x73, 0x74,
+0x69, 0x45, 0x65, 0x73, 0x74, 0x69, 0x45, 0x28b, 0x65, 0x67, 0x62, 0x65,
+0x47, 0x68, 0x61, 0x6e, 0x61, 0x20, 0x6e, 0x75, 0x74, 0x6f, 0x6d, 0x65,
+0x54, 0x6f, 0x67, 0x6f, 0x20, 0x6e, 0x75, 0x74, 0x6f, 0x6d, 0x65, 0x65,
+0x77, 0x6f, 0x6e, 0x64, 0x6f, 0x4b, 0x61, 0x6d, 0x259, 0x72, 0xfa, 0x6e,
+0x66, 0xf8, 0x72, 0x6f, 0x79, 0x73, 0x6b, 0x74, 0x46, 0xf8, 0x72, 0x6f,
+0x79, 0x61, 0x72, 0x46, 0x69, 0x6c, 0x69, 0x70, 0x69, 0x6e, 0x6f, 0x73,
+0x75, 0x6f, 0x6d, 0x69, 0x53, 0x75, 0x6f, 0x6d, 0x69, 0x66, 0x72, 0x61,
+0x6e, 0xe7, 0x61, 0x69, 0x73, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x65, 0x41,
+0x6c, 0x67, 0xe9, 0x72, 0x69, 0x65, 0x42, 0x65, 0x6c, 0x67, 0x69, 0x71,
+0x75, 0x65, 0x42, 0xe9, 0x6e, 0x69, 0x6e, 0x42, 0x75, 0x72, 0x6b, 0x69,
+0x6e, 0x61, 0x20, 0x46, 0x61, 0x73, 0x6f, 0x66, 0x72, 0x61, 0x6e, 0xe7,
+0x61, 0x69, 0x73, 0x20, 0x63, 0x61, 0x6e, 0x61, 0x64, 0x69, 0x65, 0x6e,
+0x52, 0xe9, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x71, 0x75, 0x65, 0x20, 0x63,
+0x65, 0x6e, 0x74, 0x72, 0x61, 0x66, 0x72, 0x69, 0x63, 0x61, 0x69, 0x6e,
+0x65, 0x54, 0x63, 0x68, 0x61, 0x64, 0x43, 0x6f, 0x6d, 0x6f, 0x72, 0x65,
+0x73, 0x43, 0x6f, 0x6e, 0x67, 0x6f, 0x2d, 0x42, 0x72, 0x61, 0x7a, 0x7a,
+0x61, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x43, 0x6f, 0x6e, 0x67, 0x6f, 0x2d,
+0x4b, 0x69, 0x6e, 0x73, 0x68, 0x61, 0x73, 0x61, 0x44, 0x6a, 0x69, 0x62,
+0x6f, 0x75, 0x74, 0x69, 0x47, 0x75, 0x69, 0x6e, 0xe9, 0x65, 0x20, 0xe9,
+0x71, 0x75, 0x61, 0x74, 0x6f, 0x72, 0x69, 0x61, 0x6c, 0x65, 0x47, 0x75,
+0x79, 0x61, 0x6e, 0x65, 0x20, 0x66, 0x72, 0x61, 0x6e, 0xe7, 0x61, 0x69,
+0x73, 0x65, 0x50, 0x6f, 0x6c, 0x79, 0x6e, 0xe9, 0x73, 0x69, 0x65, 0x20,
+0x66, 0x72, 0x61, 0x6e, 0xe7, 0x61, 0x69, 0x73, 0x65, 0x47, 0x61, 0x62,
+0x6f, 0x6e, 0x47, 0x75, 0x61, 0x64, 0x65, 0x6c, 0x6f, 0x75, 0x70, 0x65,
+0x48, 0x61, 0xef, 0x74, 0x69, 0x43, 0xf4, 0x74, 0x65, 0x20, 0x64, 0x2019,
+0x49, 0x76, 0x6f, 0x69, 0x72, 0x65, 0x4c, 0x75, 0x78, 0x65, 0x6d, 0x62,
+0x6f, 0x75, 0x72, 0x67, 0x4d, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x69, 0x71,
+0x75, 0x65, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x61, 0x6e, 0x69, 0x65,
+0x4d, 0x61, 0x75, 0x72, 0x69, 0x63, 0x65, 0x4d, 0x61, 0x79, 0x6f, 0x74,
+0x74, 0x65, 0x4d, 0x6f, 0x6e, 0x61, 0x63, 0x6f, 0x4d, 0x61, 0x72, 0x6f,
+0x63, 0x4e, 0x6f, 0x75, 0x76, 0x65, 0x6c, 0x6c, 0x65, 0x2d, 0x43, 0x61,
+0x6c, 0xe9, 0x64, 0x6f, 0x6e, 0x69, 0x65, 0x4c, 0x61, 0x20, 0x52, 0xe9,
+0x75, 0x6e, 0x69, 0x6f, 0x6e, 0x53, 0x61, 0x69, 0x6e, 0x74, 0x2d, 0x42,
+0x61, 0x72, 0x74, 0x68, 0xe9, 0x6c, 0x65, 0x6d, 0x79, 0x53, 0x61, 0x69,
+0x6e, 0x74, 0x2d, 0x4d, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x53, 0x61, 0x69,
+0x6e, 0x74, 0x2d, 0x50, 0x69, 0x65, 0x72, 0x72, 0x65, 0x2d, 0x65, 0x74,
+0x2d, 0x4d, 0x69, 0x71, 0x75, 0x65, 0x6c, 0x6f, 0x6e, 0x53, 0xe9, 0x6e,
+0xe9, 0x67, 0x61, 0x6c, 0x66, 0x72, 0x61, 0x6e, 0xe7, 0x61, 0x69, 0x73,
+0x20, 0x73, 0x75, 0x69, 0x73, 0x73, 0x65, 0x53, 0x75, 0x69, 0x73, 0x73,
+0x65, 0x53, 0x79, 0x72, 0x69, 0x65, 0x54, 0x75, 0x6e, 0x69, 0x73, 0x69,
+0x65, 0x57, 0x61, 0x6c, 0x6c, 0x69, 0x73, 0x2d, 0x65, 0x74, 0x2d, 0x46,
+0x75, 0x74, 0x75, 0x6e, 0x61, 0x66, 0x75, 0x72, 0x6c, 0x61, 0x6e, 0x49,
+0x74, 0x61, 0x6c, 0x69, 0x65, 0x50, 0x75, 0x6c, 0x61, 0x61, 0x72, 0x53,
+0x65, 0x6e, 0x65, 0x67, 0x61, 0x61, 0x6c, 0xd83a, 0xdd06, 0xd83a, 0xdd35, 0xd83a,
+0xdd24, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd04, 0xd83a, 0xdd35, 0xd83a, 0xdd2a, 0xd83a,
+0xdd33, 0xd83a, 0xdd2d, 0xd83a, 0xdd32, 0xd83a, 0xdd22, 0x20, 0xd83a, 0xdd0a, 0xd83a, 0xdd22,
+0xd83a, 0xdd27, 0xd83a, 0xdd2e, 0xd83a, 0xdd45, 0xd83a, 0xdd11, 0xd83a, 0xdd22, 0xd83a, 0xdd25,
+0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd35, 0xd83a, 0xdd45, 0xd83a, 0xdd32, 0xd83a, 0xdd18,
+0xd83a, 0xdd22, 0xd83a, 0xdd25, 0xd83a, 0xdd26, 0xd83a, 0xdd2d, 0xd83a, 0xdd34, 0xd83a, 0xdd22,
+0xd83a, 0xdd18, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0xd83a, 0xdd22, 0xd83a, 0xdd18, 0xd83a, 0xdd2d,
+0xd83a, 0xdd32, 0xd83a, 0xdd2b, 0x2d, 0xd83a, 0xdd04, 0xd83a, 0xdd2d, 0xd83a, 0xdd27, 0xd83a,
+0xdd22, 0xd83a, 0xdd31, 0xd83a, 0xdd2e, 0xd83a, 0xdd45, 0xd83a, 0xdd02, 0xd83a, 0xdd22, 0xd83a,
+0xdd26, 0xd83a, 0xdd2d, 0xd83a, 0xdd2a, 0xd83a, 0xdd2d, 0xd83a, 0xdd34, 0xd83a, 0xdd22, 0xd83a,
+0xdd44, 0xd83a, 0xdd03, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0xd83a, 0xdd3c, 0xd83a, 0xdd22, 0xd83a,
+0xdd32, 0xd83a, 0xdd2d, 0xd83a, 0xdd45, 0xd83a, 0xdd10, 0xd83a, 0xdd22, 0xd83a, 0xdd36, 0xd83a,
+0xdd2b, 0xd83a, 0xdd2a, 0xd83a, 0xdd2d, 0xd83a, 0xdd34, 0xd83a, 0xdd22, 0xd83a, 0xdd44, 0xd83a,
+0xdd10, 0xd83a, 0xdd2d, 0xd83a, 0xdd45, 0xd83a, 0xdd36, 0xd83a, 0xdd2b, 0xd83a, 0xdd2a, 0xd83a,
+0xdd05, 0xd83a, 0xdd2b, 0xd83a, 0xdd32, 0xd83a, 0xdd2b, 0xd83a, 0xdd3a, 0xd83a, 0xdd22, 0xd83a,
+0xdd44, 0xd83a, 0xdd24, 0xd83a, 0xdd05, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd22, 0xd83a,
+0xdd24, 0xd83a, 0xdd2e, 0xd83a, 0xdd32, 0x42, 0x75, 0x72, 0x6b, 0x69, 0x62, 0x61,
+0x61, 0x20, 0x46, 0x61, 0x61, 0x73, 0x6f, 0x4b, 0x61, 0x6d, 0x65, 0x72,
+0x75, 0x75, 0x6e, 0x47, 0x61, 0x6d, 0x6d, 0x62, 0x69, 0x47, 0x61, 0x6e,
+0x61, 0x61, 0x47, 0x69, 0x6e, 0x65, 0x2d, 0x42, 0x69, 0x73, 0x61, 0x61,
+0x77, 0x6f, 0x4c, 0x69, 0x62, 0x65, 0x72, 0x69, 0x79, 0x61, 0x61, 0x4d,
+0x75, 0x72, 0x69, 0x74, 0x61, 0x6e, 0x69, 0x4e, 0x69, 0x6a, 0x65, 0x72,
+0x69, 0x79, 0x61, 0x61, 0x4e, 0x69, 0x6a, 0x65, 0x65, 0x72, 0x53, 0x65,
+0x72, 0x61, 0x61, 0x20, 0x6c, 0x69, 0x79, 0x6f, 0x6e, 0x47, 0xe0, 0x69,
+0x64, 0x68, 0x6c, 0x69, 0x67, 0x41, 0x6e, 0x20, 0x52, 0xec, 0x6f, 0x67,
+0x68, 0x61, 0x63, 0x68, 0x64, 0x20, 0x41, 0x6f, 0x6e, 0x61, 0x69, 0x63,
+0x68, 0x74, 0x65, 0x47, 0xe3, 0x67, 0x61, 0x6c, 0x65, 0x67, 0x6f, 0x4c,
+0x75, 0x67, 0x61, 0x6e, 0x64, 0x61, 0x59, 0x75, 0x67, 0x61, 0x6e, 0x64,
+0x61, 0x130d, 0x12d5, 0x12dd, 0x129b, 0x10e5, 0x10d0, 0x10e0, 0x10d7, 0x10e3, 0x10da, 0x10d8,
+0x10e1, 0x10d0, 0x10e5, 0x10d0, 0x10e0, 0x10d7, 0x10d5, 0x10d4, 0x10da, 0x10dd, 0x44, 0x65,
+0x75, 0x74, 0x73, 0x63, 0x68, 0x44, 0x65, 0x75, 0x74, 0x73, 0x63, 0x68,
+0x6c, 0x61, 0x6e, 0x64, 0xd6, 0x73, 0x74, 0x65, 0x72, 0x72, 0x65, 0x69,
+0x63, 0x68, 0x69, 0x73, 0x63, 0x68, 0x65, 0x73, 0x20, 0x44, 0x65, 0x75,
+0x74, 0x73, 0x63, 0x68, 0x42, 0x65, 0x6c, 0x67, 0x69, 0x65, 0x6e, 0x49,
+0x74, 0x61, 0x6c, 0x69, 0x65, 0x6e, 0x4c, 0x69, 0x65, 0x63, 0x68, 0x74,
+0x65, 0x6e, 0x73, 0x74, 0x65, 0x69, 0x6e, 0x4c, 0x75, 0x78, 0x65, 0x6d,
+0x62, 0x75, 0x72, 0x67, 0x53, 0x63, 0x68, 0x77, 0x65, 0x69, 0x7a, 0x65,
+0x72, 0x20, 0x48, 0x6f, 0x63, 0x68, 0x64, 0x65, 0x75, 0x74, 0x73, 0x63,
+0x68, 0x395, 0x3bb, 0x3bb, 0x3b7, 0x3bd, 0x3b9, 0x3ba, 0x3ac, 0x395, 0x3bb, 0x3bb,
+0x3ac, 0x3b4, 0x3b1, 0x39a, 0x3cd, 0x3c0, 0x3c1, 0x3bf, 0x3c2, 0x61, 0x76, 0x61,
+0xf1, 0x65, 0x2019, 0x1ebd, 0x50, 0x61, 0x72, 0x61, 0x67, 0x75, 0x61, 0x69,
+0xa97, 0xac1, 0xa9c, 0xab0, 0xabe, 0xaa4, 0xac0, 0xaad, 0xabe, 0xab0, 0xaa4, 0x45,
+0x6b, 0x65, 0x67, 0x75, 0x73, 0x69, 0x69, 0x48, 0x61, 0x75, 0x73, 0x61,
+0x4e, 0x69, 0x6a, 0x61, 0x72, 0x2bb, 0x14c, 0x6c, 0x65, 0x6c, 0x6f, 0x20,
+0x48, 0x61, 0x77, 0x61, 0x69, 0x2bb, 0x69, 0x2bb, 0x41, 0x6d, 0x65, 0x6c,
+0x69, 0x6b, 0x61, 0x20, 0x48, 0x75, 0x69, 0x20, 0x50, 0x16b, 0x20, 0x2bb,
+0x49, 0x61, 0x5e2, 0x5d1, 0x5e8, 0x5d9, 0x5ea, 0x5d9, 0x5e9, 0x5e8, 0x5d0, 0x5dc,
+0x939, 0x93f, 0x928, 0x94d, 0x926, 0x940, 0x48, 0x69, 0x6e, 0x64, 0x69, 0x20,
+0x28, 0x4c, 0x61, 0x74, 0x69, 0x6e, 0x29, 0x6d, 0x61, 0x67, 0x79, 0x61,
+0x72, 0x4d, 0x61, 0x67, 0x79, 0x61, 0x72, 0x6f, 0x72, 0x73, 0x7a, 0xe1,
+0x67, 0xed, 0x73, 0x6c, 0x65, 0x6e, 0x73, 0x6b, 0x61, 0xcd, 0x73, 0x6c,
+0x61, 0x6e, 0x64, 0x49, 0x64, 0x6f, 0x49, 0x67, 0x62, 0x6f, 0x4e, 0x61,
+0x1ecb, 0x6a, 0x1ecb, 0x72, 0x1ecb, 0x61, 0x61, 0x6e, 0x61, 0x72, 0xe2, 0x161,
+0x6b, 0x69, 0x65, 0x6c, 0xe2, 0x53, 0x75, 0x6f, 0x6d, 0xe2, 0x69, 0x6e,
+0x74, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x67, 0x75, 0x61, 0x4d, 0x75, 0x6e,
+0x64, 0x6f, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x67, 0x75,
+0x65, 0x45, 0x73, 0x74, 0x6f, 0x6e, 0x69, 0x61, 0x1403, 0x14c4, 0x1483, 0x144e,
+0x1450, 0x1466, 0x1472, 0x14c7, 0x1455, 0x14a5, 0x47, 0x61, 0x65, 0x69, 0x6c, 0x67,
+0x65, 0xc9, 0x69, 0x72, 0x65, 0x61, 0x6e, 0x20, 0x52, 0xed, 0x6f, 0x63,
+0x68, 0x74, 0x20, 0x41, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x74, 0x68, 0x65,
+0x69, 0x74, 0x61, 0x6c, 0x69, 0x61, 0x6e, 0x6f, 0x49, 0x74, 0x61, 0x6c,
+0x69, 0x61, 0x53, 0x61, 0x6e, 0x20, 0x4d, 0x61, 0x72, 0x69, 0x6e, 0x6f,
+0x53, 0x76, 0x69, 0x7a, 0x7a, 0x65, 0x72, 0x61, 0x43, 0x69, 0x74, 0x74,
+0xe0, 0x20, 0x64, 0x65, 0x6c, 0x20, 0x56, 0x61, 0x74, 0x69, 0x63, 0x61,
+0x6e, 0x6f, 0x65e5, 0x672c, 0x8a9e, 0x4a, 0x61, 0x77, 0x61, 0x49, 0x6e, 0x64,
+0x6f, 0x6e, 0xe9, 0x73, 0x69, 0x61, 0x4b, 0x61, 0x6a, 0x65, 0x6a, 0x6f,
+0x6f, 0x6c, 0x61, 0x53, 0x65, 0x6e, 0x65, 0x67, 0x61, 0x6c, 0x6b, 0x61,
+0x62, 0x75, 0x76, 0x65, 0x72, 0x64, 0x69, 0x61, 0x6e, 0x75, 0x4b, 0x61,
+0x62, 0x75, 0x20, 0x56, 0x65, 0x72, 0x64, 0x69, 0x54, 0x61, 0x71, 0x62,
+0x61, 0x79, 0x6c, 0x69, 0x74, 0x4c, 0x65, 0x7a, 0x7a, 0x61, 0x79, 0x65,
+0x72, 0x6b, 0x61, 0x6b, 0x254, 0x4b, 0x61, 0x6d, 0x25b, 0x72, 0x75, 0x6e,
+0x6b, 0x61, 0x6c, 0x61, 0x61, 0x6c, 0x6c, 0x69, 0x73, 0x75, 0x74, 0x4b,
+0x61, 0x6c, 0x61, 0x61, 0x6c, 0x6c, 0x69, 0x74, 0x20, 0x4e, 0x75, 0x6e,
+0x61, 0x61, 0x74, 0x4b, 0x61, 0x6c, 0x65, 0x6e, 0x6a, 0x69, 0x6e, 0x45,
+0x6d, 0x65, 0x74, 0x61, 0x62, 0x20, 0x4b, 0x65, 0x6e, 0x79, 0x61, 0x4b,
+0x69, 0x6b, 0x61, 0x6d, 0x62, 0x61, 0xc95, 0xca8, 0xccd, 0xca8, 0xca1, 0xcad,
+0xcbe, 0xcb0, 0xca4, 0x6a9, 0x672, 0x634, 0x64f, 0x631, 0x6c1, 0x650, 0x646, 0x62f,
+0x648, 0x633, 0x62a, 0x627, 0x646, 0x915, 0x949, 0x936, 0x941, 0x930, 0x939, 0x93f,
+0x902, 0x926, 0x94b, 0x938, 0x94d, 0x924, 0x93e, 0x928, 0x49b, 0x430, 0x437, 0x430,
+0x49b, 0x20, 0x442, 0x456, 0x43b, 0x456, 0x49a, 0x430, 0x437, 0x430, 0x49b, 0x441,
+0x442, 0x430, 0x43d, 0x4b, 0x25b, 0x6e, 0x79, 0x61, 0x14b, 0x1781, 0x17d2, 0x1798,
+0x17c2, 0x179a, 0x1780, 0x1798, 0x17d2, 0x1796, 0x17bb, 0x1787, 0x17b6, 0x4b, 0x2bc, 0x69,
+0x63, 0x68, 0x65, 0x2bc, 0x47, 0x69, 0x6b, 0x75, 0x79, 0x75, 0x4b, 0x69,
+0x6e, 0x79, 0x61, 0x72, 0x77, 0x61, 0x6e, 0x64, 0x61, 0x55, 0x20, 0x52,
+0x77, 0x61, 0x6e, 0x64, 0x61, 0x915, 0x94b, 0x902, 0x915, 0x923, 0x940, 0xd55c,
+0xad6d, 0xc5b4, 0xb300, 0xd55c, 0xbbfc, 0xad6d, 0xc911, 0xad6d, 0xc870, 0xc120, 0xbbfc, 0xc8fc,
+0xc8fc, 0xc758, 0xc778, 0xbbfc, 0xacf5, 0xd654, 0xad6d, 0x4b, 0x6f, 0x79, 0x72, 0x61,
+0x62, 0x6f, 0x72, 0x6f, 0x20, 0x73, 0x65, 0x6e, 0x6e, 0x69, 0x4d, 0x61,
+0x61, 0x6c, 0x69, 0x4b, 0x6f, 0x79, 0x72, 0x61, 0x20, 0x63, 0x69, 0x69,
+0x6e, 0x69, 0x4b, 0x70, 0x25b, 0x6c, 0x25b, 0x25b, 0x6b, 0x75, 0x72, 0x64,
+0xee, 0x20, 0x28, 0x6b, 0x75, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0xee, 0x29,
+0x54, 0x69, 0x72, 0x6b, 0x69, 0x79, 0x65, 0x4b, 0x77, 0x61, 0x73, 0x69,
+0x6f, 0x4b, 0x61, 0x6d, 0x65, 0x72, 0x75, 0x6e, 0x43a, 0x44b, 0x440, 0x433,
+0x44b, 0x437, 0x447, 0x430, 0x41a, 0x44b, 0x440, 0x433, 0x44b, 0x437, 0x441, 0x442,
+0x430, 0x43d, 0x4c, 0x61, 0x6b, 0x21f, 0xf3, 0x6c, 0x2bc, 0x69, 0x79, 0x61,
+0x70, 0x69, 0x4d, 0xed, 0x6c, 0x61, 0x68, 0x61, 0x14b, 0x73, 0x6b, 0x61,
+0x20, 0x54, 0x21f, 0x61, 0x6d, 0xe1, 0x6b, 0x21f, 0x6f, 0x10d, 0x68, 0x65,
+0x4b, 0x268, 0x6c, 0x61, 0x61, 0x6e, 0x67, 0x69, 0x54, 0x61, 0x61, 0x6e,
+0x73, 0x61, 0x6e, 0xed, 0x61, 0xea5, 0xeb2, 0xea7, 0x4c, 0x61, 0x74, 0x69,
+0x6e, 0x61, 0x43, 0x69, 0x76, 0x69, 0x74, 0x61, 0x73, 0x20, 0x56, 0x61,
+0x74, 0x69, 0x63, 0x61, 0x6e, 0x61, 0x6c, 0x61, 0x74, 0x76, 0x69, 0x65,
+0x161, 0x75, 0x4c, 0x61, 0x74, 0x76, 0x69, 0x6a, 0x61, 0x6c, 0x69, 0x6e,
+0x67, 0xe1, 0x6c, 0x61, 0x52, 0x65, 0x70, 0x75, 0x62, 0x6c, 0xed, 0x6b,
+0x69, 0x20, 0x79, 0x61, 0x20, 0x4b, 0x6f, 0x6e, 0x67, 0xf3, 0x20, 0x44,
+0x65, 0x6d, 0x6f, 0x6b, 0x72, 0x61, 0x74, 0xed, 0x6b, 0x69, 0x41, 0x6e,
+0x67, 0xf3, 0x6c, 0x61, 0x52, 0x65, 0x70, 0x69, 0x62, 0x69, 0x6b, 0x69,
+0x20, 0x79, 0x61, 0x20, 0x41, 0x66, 0x72, 0xed, 0x6b, 0x61, 0x20, 0x79,
+0x61, 0x20, 0x4b, 0xe1, 0x74, 0x69, 0x4b, 0x6f, 0x6e, 0x67, 0x6f, 0x6c,
+0x69, 0x65, 0x74, 0x75, 0x76, 0x69, 0x173, 0x4c, 0x69, 0x65, 0x74, 0x75,
+0x76, 0x61, 0x6c, 0x61, 0x20, 0x2e, 0x6c, 0x6f, 0x6a, 0x62, 0x61, 0x6e,
+0x2e, 0x64, 0x6f, 0x6c, 0x6e, 0x6f, 0x73, 0x65, 0x72, 0x62, 0x161, 0x107,
+0x69, 0x6e, 0x61, 0x4e, 0x69, 0x6d, 0x73, 0x6b, 0x61, 0x4e, 0x65, 0x64,
+0x64, 0x65, 0x72, 0x73, 0x61, 0x73, 0x73, 0x2019, 0x73, 0x63, 0x68, 0x44,
+0xfc, 0xfc, 0x74, 0x73, 0x63, 0x68, 0x6c, 0x61, 0x6e, 0x64, 0x4e, 0x65,
+0x64, 0x64, 0x65, 0x72, 0x6c, 0x61, 0x6e, 0x6e, 0x65, 0x6e, 0x54, 0x73,
+0x68, 0x69, 0x6c, 0x75, 0x62, 0x61, 0x44, 0x69, 0x74, 0x75, 0x6e, 0x67,
+0x61, 0x20, 0x77, 0x61, 0x20, 0x4b, 0x6f, 0x6e, 0x67, 0x75, 0x6a, 0x75,
+0x6c, 0x65, 0x76, 0x73, 0xe1, 0x6d, 0x65, 0x67, 0x69, 0x65, 0x6c, 0x6c,
+0x61, 0x44, 0x68, 0x6f, 0x6c, 0x75, 0x6f, 0x4c, 0xeb, 0x74, 0x7a, 0x65,
+0x62, 0x75, 0x65, 0x72, 0x67, 0x65, 0x73, 0x63, 0x68, 0x4c, 0x75, 0x6c,
+0x75, 0x68, 0x69, 0x61, 0x43c, 0x430, 0x43a, 0x435, 0x434, 0x43e, 0x43d, 0x441,
+0x43a, 0x438, 0x421, 0x435, 0x432, 0x435, 0x440, 0x43d, 0x430, 0x20, 0x41c, 0x430,
+0x43a, 0x435, 0x434, 0x43e, 0x43d, 0x438, 0x458, 0x430, 0x4b, 0x69, 0x6d, 0x61,
+0x63, 0x68, 0x61, 0x6d, 0x65, 0x92e, 0x948, 0x925, 0x93f, 0x932, 0x940, 0x4d,
+0x61, 0x6b, 0x75, 0x61, 0x55, 0x6d, 0x6f, 0x7a, 0x61, 0x6d, 0x62, 0x69,
+0x6b, 0x69, 0x43, 0x68, 0x69, 0x6d, 0x61, 0x6b, 0x6f, 0x6e, 0x64, 0x65,
+0x4d, 0x61, 0x6c, 0x61, 0x67, 0x61, 0x73, 0x79, 0x4d, 0x61, 0x64, 0x61,
+0x67, 0x61, 0x73, 0x69, 0x6b, 0x61, 0x72, 0x61, 0xd2e, 0xd32, 0xd2f, 0xd3e,
+0xd33, 0xd02, 0xd07, 0xd28, 0xd4d, 0xd24, 0xd4d, 0xd2f, 0x4d, 0x65, 0x6c, 0x61,
+0x79, 0x75, 0x628, 0x647, 0x627, 0x633, 0x20, 0x645, 0x644, 0x627, 0x64a, 0x648,
+0x628, 0x631, 0x648, 0x646, 0x64a, 0x645, 0x644, 0x64a, 0x633, 0x64a, 0x627, 0x42,
+0x72, 0x75, 0x6e, 0x65, 0x69, 0x53, 0x69, 0x6e, 0x67, 0x61, 0x70, 0x75,
+0x72, 0x61, 0x4d, 0x61, 0x6c, 0x74, 0x69, 0x9ae, 0x9c8, 0x9a4, 0x9c8, 0x9b2,
+0x9cb, 0x9a8, 0x9cd, 0x987, 0x9a8, 0x9cd, 0x9a6, 0x9bf, 0x9af, 0x9bc, 0x9be, 0xabc3,
+0xabe4, 0xabc7, 0xabe9, 0xabc2, 0xabe3, 0xabdf, 0x47, 0x61, 0x65, 0x6c, 0x67, 0x45,
+0x6c, 0x6c, 0x61, 0x6e, 0x20, 0x56, 0x61, 0x6e, 0x6e, 0x69, 0x6e, 0x4d,
+0x101, 0x6f, 0x72, 0x69, 0x41, 0x6f, 0x74, 0x65, 0x61, 0x72, 0x6f, 0x61,
+0x4d, 0x61, 0x70, 0x75, 0x64, 0x75, 0x6e, 0x67, 0x75, 0x6e, 0x92e, 0x930,
+0x93e, 0x920, 0x940, 0x54, 0x61, 0x6e, 0x73, 0x61, 0x6e, 0x69, 0x61, 0x645,
+0x627, 0x632, 0x631, 0x648, 0x646, 0x6cc, 0x627, 0x6cc, 0x631, 0x627, 0x646, 0x4b,
+0x129, 0x6d, 0x129, 0x72, 0x169, 0x6d, 0x65, 0x74, 0x61, 0x2bc, 0x4b, 0x61,
+0x6d, 0x61, 0x6c, 0x75, 0x6e, 0x4b, 0x61, 0x6e, 0x69, 0x65, 0x6e, 0x2bc,
+0x6b, 0xe9, 0x68, 0x61, 0x43c, 0x43e, 0x43d, 0x433, 0x43e, 0x43b, 0x41c, 0x43e,
+0x43d, 0x433, 0x43e, 0x43b, 0x182e, 0x1823, 0x1829, 0x182d, 0x1823, 0x182f, 0x6b, 0x72,
+0x65, 0x6f, 0x6c, 0x20, 0x6d, 0x6f, 0x72, 0x69, 0x73, 0x69, 0x65, 0x6e,
+0x4d, 0x6f, 0x72, 0x69, 0x73, 0x4d, 0x55, 0x4e, 0x44, 0x41, 0x14a, 0x6b,
+0x61, 0x6d, 0x65, 0x72, 0x75, 0x14b, 0x4d, 0x76, 0x73, 0x6b, 0x6f, 0x6b,
+0x65, 0x4b, 0x68, 0x6f, 0x65, 0x6b, 0x68, 0x6f, 0x65, 0x67, 0x6f, 0x77,
+0x61, 0x62, 0x4e, 0x61, 0x6d, 0x69, 0x62, 0x69, 0x61, 0x62, 0x44, 0x69,
+0x6e, 0xe9, 0x20, 0x42, 0x69, 0x7a, 0x61, 0x61, 0x64, 0x928, 0x947, 0x92a,
+0x93e, 0x932, 0x940, 0x53, 0x68, 0x77, 0xf3, 0x14b, 0xf2, 0x20, 0x6e, 0x67,
+0x69, 0x65, 0x6d, 0x62, 0x254, 0x254, 0x6e, 0x4b, 0xe0, 0x6d, 0x61, 0x6c,
+0xfb, 0x6d, 0x4e, 0x64, 0x61, 0xa78c, 0x61, 0x4b, 0x61, 0x6d, 0x25b, 0x6c,
+0xfb, 0x6e, 0x4e, 0x61, 0x69, 0x6a, 0xed, 0x72, 0x69, 0xe1, 0x20, 0x50,
+0xed, 0x6a, 0x69, 0x6e, 0x4e, 0x61, 0x69, 0x6a, 0xed, 0x72, 0x69, 0x61,
+0x7d2, 0x7de, 0x7cf, 0x7d6, 0x7cc, 0x7ec, 0x7e3, 0x7cd, 0x7eb, 0x644, 0x6ca, 0x631,
+0x6cc, 0x20, 0x634, 0x648, 0x645, 0x627, 0x644, 0x6cc, 0x64, 0x61, 0x76, 0x76,
+0x69, 0x73, 0xe1, 0x6d, 0x65, 0x67, 0x69, 0x65, 0x6c, 0x6c, 0x61, 0x4e,
+0x6f, 0x72, 0x67, 0x61, 0x53, 0x75, 0x6f, 0x70, 0x6d, 0x61, 0x52, 0x75,
+0x6f, 0x167, 0x167, 0x61, 0x53, 0x65, 0x73, 0x6f, 0x74, 0x68, 0x6f, 0x20,
+0x73, 0x61, 0x20, 0x4c, 0x65, 0x62, 0x6f, 0x61, 0x41, 0x66, 0x72, 0x69,
+0x6b, 0x61, 0x20, 0x42, 0x6f, 0x72, 0x77, 0x61, 0x69, 0x73, 0x69, 0x4e,
+0x64, 0x65, 0x62, 0x65, 0x6c, 0x65, 0x6e, 0x6f, 0x72, 0x73, 0x6b, 0x20,
+0x62, 0x6f, 0x6b, 0x6d, 0xe5, 0x6c, 0x4e, 0x6f, 0x72, 0x67, 0x65, 0x53,
+0x76, 0x61, 0x6c, 0x62, 0x61, 0x72, 0x64, 0x20, 0x6f, 0x67, 0x20, 0x4a,
+0x61, 0x6e, 0x20, 0x4d, 0x61, 0x79, 0x65, 0x6e, 0x6e, 0x6f, 0x72, 0x73,
+0x6b, 0x20, 0x6e, 0x79, 0x6e, 0x6f, 0x72, 0x73, 0x6b, 0x4e, 0x6f, 0x72,
+0x65, 0x67, 0x54, 0x68, 0x6f, 0x6b, 0x20, 0x4e, 0x61, 0x74, 0x68, 0x4e,
+0x79, 0x61, 0x6e, 0x6a, 0x61, 0x52, 0x75, 0x6e, 0x79, 0x61, 0x6e, 0x6b,
+0x6f, 0x72, 0x65, 0x6f, 0x63, 0x63, 0x69, 0x74, 0x61, 0x6e, 0x45, 0x73,
+0x70, 0x61, 0x6e, 0x68, 0x61, 0xb13, 0xb21, 0xb3c, 0xb3f, 0xb06, 0xb2d, 0xb3e,
+0xb30, 0xb24, 0x4f, 0x72, 0x6f, 0x6d, 0x6f, 0x6f, 0x49, 0x74, 0x6f, 0x6f,
+0x70, 0x68, 0x69, 0x79, 0x61, 0x61, 0x4b, 0x65, 0x65, 0x6e, 0x69, 0x79,
+0x61, 0x61, 0xd801, 0xdccf, 0xd801, 0xdcd8, 0xd801, 0xdcfb, 0xd801, 0xdcd8, 0xd801, 0xdcfb,
+0xd801, 0xdcdf, 0x438, 0x440, 0x43e, 0x43d, 0x413, 0x443, 0x44b, 0x440, 0x434, 0x437,
+0x44b, 0x441, 0x442, 0x43e, 0x43d, 0x423, 0x4d5, 0x440, 0x4d5, 0x441, 0x435, 0x50,
+0x61, 0x70, 0x69, 0x61, 0x6d, 0x65, 0x6e, 0x74, 0x75, 0x4b, 0xf2, 0x72,
+0x73, 0x6f, 0x75, 0x67e, 0x69a, 0x62a, 0x648, 0x627, 0x641, 0x63a, 0x627, 0x646,
+0x633, 0x62a, 0x627, 0x646, 0x67e, 0x627, 0x6a9, 0x633, 0x62a, 0x627, 0x646, 0x641,
+0x627, 0x631, 0x633, 0x6cc, 0x62f, 0x631, 0x6cc, 0x70, 0x6f, 0x6c, 0x73, 0x6b,
+0x69, 0x50, 0x6f, 0x6c, 0x73, 0x6b, 0x61, 0x70, 0x6f, 0x72, 0x74, 0x75,
+0x67, 0x75, 0xea, 0x73, 0x42, 0x72, 0x61, 0x73, 0x69, 0x6c, 0x41, 0x6e,
+0x67, 0x6f, 0x6c, 0x61, 0x43, 0x61, 0x62, 0x6f, 0x20, 0x56, 0x65, 0x72,
+0x64, 0x65, 0x47, 0x75, 0x69, 0x6e, 0xe9, 0x20, 0x45, 0x71, 0x75, 0x61,
+0x74, 0x6f, 0x72, 0x69, 0x61, 0x6c, 0x47, 0x75, 0x69, 0x6e, 0xe9, 0x2d,
+0x42, 0x69, 0x73, 0x73, 0x61, 0x75, 0x4c, 0x75, 0x78, 0x65, 0x6d, 0x62,
+0x75, 0x72, 0x67, 0x6f, 0x4d, 0x61, 0x63, 0x61, 0x75, 0x2c, 0x20, 0x52,
+0x41, 0x45, 0x20, 0x64, 0x61, 0x20, 0x43, 0x68, 0x69, 0x6e, 0x61, 0x4d,
+0x6f, 0xe7, 0x61, 0x6d, 0x62, 0x69, 0x71, 0x75, 0x65, 0x70, 0x6f, 0x72,
+0x74, 0x75, 0x67, 0x75, 0xea, 0x73, 0x20, 0x65, 0x75, 0x72, 0x6f, 0x70,
+0x65, 0x75, 0x50, 0x6f, 0x72, 0x74, 0x75, 0x67, 0x61, 0x6c, 0x53, 0xe3,
+0x6f, 0x20, 0x54, 0x6f, 0x6d, 0xe9, 0x20, 0x65, 0x20, 0x50, 0x72, 0xed,
+0x6e, 0x63, 0x69, 0x70, 0x65, 0x53, 0x75, 0xed, 0xe7, 0x61, 0x54, 0x69,
+0x6d, 0x6f, 0x72, 0x2d, 0x4c, 0x65, 0x73, 0x74, 0x65, 0x70, 0x72, 0x16b,
+0x73, 0x69, 0x73, 0x6b, 0x61, 0x6e, 0x50, 0x14d, 0x6c, 0x69, 0xa2a, 0xa70,
+0xa1c, 0xa3e, 0xa2c, 0xa40, 0xa2d, 0xa3e, 0xa30, 0xa24, 0x67e, 0x646, 0x62c, 0x627,
+0x628, 0x6cc, 0x52, 0x75, 0x6e, 0x61, 0x73, 0x69, 0x6d, 0x69, 0x50, 0x65,
+0x72, 0xfa, 0x42, 0x6f, 0x6c, 0x69, 0x76, 0x69, 0x61, 0x45, 0x63, 0x75,
+0x61, 0x64, 0x6f, 0x72, 0x72, 0x6f, 0x6d, 0xe2, 0x6e, 0x103, 0x52, 0x6f,
+0x6d, 0xe2, 0x6e, 0x69, 0x61, 0x52, 0x65, 0x70, 0x75, 0x62, 0x6c, 0x69,
+0x63, 0x61, 0x20, 0x4d, 0x6f, 0x6c, 0x64, 0x6f, 0x76, 0x61, 0x72, 0x75,
+0x6d, 0x61, 0x6e, 0x74, 0x73, 0x63, 0x68, 0x53, 0x76, 0x69, 0x7a, 0x72,
+0x61, 0x4b, 0x69, 0x68, 0x6f, 0x72, 0x6f, 0x6d, 0x62, 0x6f, 0x49, 0x6b,
+0x69, 0x72, 0x75, 0x6e, 0x64, 0x69, 0x55, 0x62, 0x75, 0x72, 0x75, 0x6e,
+0x64, 0x69, 0x440, 0x443, 0x441, 0x441, 0x43a, 0x438, 0x439, 0x420, 0x43e, 0x441,
+0x441, 0x438, 0x44f, 0x41a, 0x430, 0x437, 0x430, 0x445, 0x441, 0x442, 0x430, 0x43d,
+0x41a, 0x438, 0x440, 0x433, 0x438, 0x437, 0x438, 0x44f, 0x41c, 0x43e, 0x43b, 0x434,
+0x43e, 0x432, 0x430, 0x423, 0x43a, 0x440, 0x430, 0x438, 0x43d, 0x430, 0x4b, 0x69,
+0x72, 0x75, 0x77, 0x61, 0x53, 0x61, 0x68, 0x6f, 0x441, 0x430, 0x445, 0x430,
+0x20, 0x442, 0x44b, 0x43b, 0x430, 0x410, 0x440, 0x430, 0x441, 0x441, 0x44b, 0x44b,
+0x439, 0x430, 0x4b, 0x69, 0x73, 0x61, 0x6d, 0x70, 0x75, 0x72, 0x53, 0xe4,
+0x6e, 0x67, 0xf6, 0x4b, 0xf6, 0x64, 0xf6, 0x72, 0xf6, 0x73, 0xea, 0x73,
+0x65, 0x20, 0x74, 0xee, 0x20, 0x42, 0xea, 0x61, 0x66, 0x72, 0xee, 0x6b,
+0x61, 0x49, 0x73, 0x68, 0x69, 0x73, 0x61, 0x6e, 0x67, 0x75, 0x54, 0x61,
+0x6e, 0x73, 0x61, 0x6e, 0x69, 0x79, 0x61, 0x938, 0x902, 0x938, 0x94d, 0x915,
+0x943, 0x924, 0x20, 0x92d, 0x93e, 0x937, 0x93e, 0x92d, 0x93e, 0x930, 0x924, 0x903,
+0x1c65, 0x1c5f, 0x1c71, 0x1c5b, 0x1c5f, 0x1c72, 0x1c64, 0x1c64, 0x1c71, 0x1c70, 0x1c64, 0x1c6d,
+0x1c5f, 0x938, 0x93e, 0x928, 0x924, 0x93e, 0x921, 0x93c, 0x940, 0x73, 0x61, 0x72,
+0x64, 0x75, 0x73, 0x65, 0x6e, 0x61, 0x441, 0x440, 0x43f, 0x441, 0x43a, 0x438,
+0x421, 0x440, 0x431, 0x438, 0x458, 0x430, 0x41a, 0x43e, 0x441, 0x43e, 0x432, 0x43e,
+0x426, 0x440, 0x43d, 0x430, 0x20, 0x413, 0x43e, 0x440, 0x430, 0x73, 0x72, 0x70,
+0x73, 0x6b, 0x69, 0x4b, 0x6f, 0x73, 0x6f, 0x76, 0x6f, 0x43, 0x72, 0x6e,
+0x61, 0x20, 0x47, 0x6f, 0x72, 0x61, 0x53, 0x72, 0x62, 0x69, 0x6a, 0x61,
+0x4b, 0x69, 0x73, 0x68, 0x61, 0x6d, 0x62, 0x61, 0x61, 0x63, 0x68, 0x69,
+0x53, 0x68, 0x6f, 0x6e, 0x61, 0xa188, 0xa320, 0xa259, 0xa34f, 0xa1e9, 0x73, 0x69,
+0x63, 0x69, 0x6c, 0x69, 0x61, 0x6e, 0x75, 0x53, 0x69, 0x64, 0x61, 0x61,
+0x6d, 0x75, 0x20, 0x41, 0x66, 0x6f, 0x49, 0x74, 0x69, 0x79, 0x6f, 0x6f,
+0x70, 0x68, 0x69, 0x79, 0x61, 0x15b, 0x6c, 0x14d, 0x6e, 0x73, 0x6b, 0x69,
+0x633, 0x646, 0x68c, 0x64a, 0x67e, 0x627, 0x6aa, 0x633, 0x62a, 0x627, 0x646, 0x938,
+0x93f, 0x928, 0x94d, 0x927, 0x940, 0xdc3, 0xdd2, 0xd82, 0xdc4, 0xdbd, 0xdc1, 0xdca,
+0x200d, 0xdbb, 0xdd3, 0x20, 0xdbd, 0xd82, 0xd9a, 0xdcf, 0xdc0, 0x73, 0xe4, 0xe4,
+0x2b9, 0x6d, 0x1e9, 0x69, 0xf5, 0x6c, 0x6c, 0x4c, 0xe4, 0xe4, 0x2b9, 0x64,
+0x64, 0x6a, 0xe2, 0x6e, 0x6e, 0x61, 0x6d, 0x73, 0x6c, 0x6f, 0x76, 0x65,
+0x6e, 0x10d, 0x69, 0x6e, 0x61, 0x53, 0x6c, 0x6f, 0x76, 0x65, 0x6e, 0x73,
+0x6b, 0x6f, 0x73, 0x6c, 0x6f, 0x76, 0x65, 0x6e, 0x161, 0x10d, 0x69, 0x6e,
+0x61, 0x53, 0x6c, 0x6f, 0x76, 0x65, 0x6e, 0x69, 0x6a, 0x61, 0x4f, 0x6c,
+0x75, 0x73, 0x6f, 0x67, 0x61, 0x53, 0x6f, 0x6f, 0x6d, 0x61, 0x61, 0x6c,
+0x69, 0x53, 0x6f, 0x6f, 0x6d, 0x61, 0x61, 0x6c, 0x69, 0x79, 0x61, 0x4a,
+0x61, 0x62, 0x75, 0x75, 0x74, 0x69, 0x49, 0x74, 0x6f, 0x6f, 0x62, 0x69,
+0x79, 0x61, 0x6a9, 0x648, 0x631, 0x62f, 0x6cc, 0x20, 0x62e, 0x648, 0x627, 0x631,
+0x6af, 0xc5, 0x61, 0x72, 0x6a, 0x65, 0x6c, 0x73, 0x61, 0x65, 0x6d, 0x69,
+0x65, 0x6e, 0x20, 0x67, 0xef, 0x65, 0x6c, 0x65, 0x65, 0x73, 0x70, 0x61,
+0xf1, 0x6f, 0x6c, 0x20, 0x64, 0x65, 0x20, 0x45, 0x73, 0x70, 0x61, 0xf1,
+0x61, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x42, 0x65,
+0x6c, 0x69, 0x63, 0x65, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x61, 0x73,
+0x43, 0x65, 0x75, 0x74, 0x61, 0x20, 0x79, 0x20, 0x4d, 0x65, 0x6c, 0x69,
+0x6c, 0x6c, 0x61, 0x43, 0x68, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x6c, 0x6f,
+0x6d, 0x62, 0x69, 0x61, 0x43, 0x6f, 0x73, 0x74, 0x61, 0x20, 0x52, 0x69,
+0x63, 0x61, 0x43, 0x75, 0x62, 0x61, 0x52, 0x65, 0x70, 0xfa, 0x62, 0x6c,
+0x69, 0x63, 0x61, 0x20, 0x44, 0x6f, 0x6d, 0x69, 0x6e, 0x69, 0x63, 0x61,
+0x6e, 0x61, 0x45, 0x6c, 0x20, 0x53, 0x61, 0x6c, 0x76, 0x61, 0x64, 0x6f,
+0x72, 0x47, 0x75, 0x69, 0x6e, 0x65, 0x61, 0x20, 0x45, 0x63, 0x75, 0x61,
+0x74, 0x6f, 0x72, 0x69, 0x61, 0x6c, 0x47, 0x75, 0x61, 0x74, 0x65, 0x6d,
+0x61, 0x6c, 0x61, 0x48, 0x6f, 0x6e, 0x64, 0x75, 0x72, 0x61, 0x73, 0x65,
+0x73, 0x70, 0x61, 0xf1, 0x6f, 0x6c, 0x20, 0x6c, 0x61, 0x74, 0x69, 0x6e,
+0x6f, 0x61, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x6e, 0x6f, 0x4c, 0x61,
+0x74, 0x69, 0x6e, 0x6f, 0x61, 0x6d, 0xe9, 0x72, 0x69, 0x63, 0x61, 0x65,
+0x73, 0x70, 0x61, 0xf1, 0x6f, 0x6c, 0x20, 0x64, 0x65, 0x20, 0x4d, 0xe9,
+0x78, 0x69, 0x63, 0x6f, 0x4d, 0xe9, 0x78, 0x69, 0x63, 0x6f, 0x4e, 0x69,
+0x63, 0x61, 0x72, 0x61, 0x67, 0x75, 0x61, 0x50, 0x61, 0x6e, 0x61, 0x6d,
+0xe1, 0x50, 0x61, 0x72, 0x61, 0x67, 0x75, 0x61, 0x79, 0x46, 0x69, 0x6c,
+0x69, 0x70, 0x69, 0x6e, 0x61, 0x73, 0x45, 0x73, 0x74, 0x61, 0x64, 0x6f,
+0x73, 0x20, 0x55, 0x6e, 0x69, 0x64, 0x6f, 0x73, 0x55, 0x72, 0x75, 0x67,
+0x75, 0x61, 0x79, 0x56, 0x65, 0x6e, 0x65, 0x7a, 0x75, 0x65, 0x6c, 0x61,
+0x2d5c, 0x2d30, 0x2d4e, 0x2d30, 0x2d63, 0x2d49, 0x2d56, 0x2d5c, 0x2d4d, 0x2d4e, 0x2d56, 0x2d54,
+0x2d49, 0x2d31, 0x42, 0x61, 0x73, 0x61, 0x20, 0x53, 0x75, 0x6e, 0x64, 0x61,
+0x4b, 0x69, 0x73, 0x77, 0x61, 0x68, 0x69, 0x6c, 0x69, 0x4a, 0x61, 0x6d,
+0x68, 0x75, 0x72, 0x69, 0x20, 0x79, 0x61, 0x20, 0x4b, 0x69, 0x64, 0x65,
+0x6d, 0x6f, 0x6b, 0x72, 0x61, 0x73, 0x69, 0x61, 0x20, 0x79, 0x61, 0x20,
+0x4b, 0x6f, 0x6e, 0x67, 0x6f, 0x73, 0x69, 0x53, 0x77, 0x61, 0x74, 0x69,
+0x65, 0x53, 0x77, 0x61, 0x74, 0x69, 0x6e, 0x69, 0x73, 0x76, 0x65, 0x6e,
+0x73, 0x6b, 0x61, 0x53, 0x76, 0x65, 0x72, 0x69, 0x67, 0x65, 0xc5, 0x6c,
+0x61, 0x6e, 0x64, 0x53, 0x63, 0x68, 0x77, 0x69, 0x69, 0x7a, 0x65, 0x72,
+0x74, 0xfc, 0xfc, 0x74, 0x73, 0x63, 0x68, 0x46, 0x72, 0x61, 0x6e, 0x6b,
+0x72, 0x69, 0x69, 0x63, 0x68, 0x4c, 0x69, 0xe4, 0x63, 0x68, 0x74, 0x65,
+0x73, 0x63, 0x68, 0x74, 0xe4, 0x69, 0x723, 0x718, 0x72a, 0x71d, 0x71d, 0x710,
+0x725, 0x71d, 0x72a, 0x729, 0x723, 0x718, 0x72a, 0x71d, 0x710, 0x2d5c, 0x2d30, 0x2d5b,
+0x2d4d, 0x2d43, 0x2d49, 0x2d5c, 0x54, 0x61, 0x73, 0x68, 0x65, 0x6c, 0x1e25, 0x69,
+0x79, 0x74, 0x6c, 0x6d, 0x263, 0x72, 0x69, 0x62, 0xaabc, 0xaa95, 0xaa92, 0xaabe,
+0x4b, 0x69, 0x74, 0x61, 0x69, 0x74, 0x61, 0x442, 0x43e, 0x4b7, 0x438, 0x43a,
+0x4e3, 0x422, 0x43e, 0x4b7, 0x438, 0x43a, 0x438, 0x441, 0x442, 0x43e, 0x43d, 0xba4,
+0xbae, 0xbbf, 0xbb4, 0xbcd, 0xb87, 0xba8, 0xbcd, 0xba4, 0xbbf, 0xbaf, 0xbbe, 0xbae,
+0xbb2, 0xbc7, 0xb9a, 0xbbf, 0xbaf, 0xbbe, 0xb9a, 0xbbf, 0xb99, 0xbcd, 0xb95, 0xbaa,
+0xbcd, 0xbaa, 0xbc2, 0xbb0, 0xbcd, 0xb87, 0xbb2, 0xb99, 0xbcd, 0xb95, 0xbc8, 0x70,
+0x61, 0x74, 0x61, 0x73, 0x20, 0x54, 0x61, 0x72, 0x6f, 0x6b, 0x6f, 0x54,
+0x61, 0x73, 0x61, 0x77, 0x61, 0x71, 0x20, 0x73, 0x65, 0x6e, 0x6e, 0x69,
+0x4e, 0x69, 0x17e, 0x65, 0x72, 0x442, 0x430, 0x442, 0x430, 0x440, 0xc24, 0xc46,
+0xc32, 0xc41, 0xc17, 0xc41, 0xc2d, 0xc3e, 0xc30, 0xc24, 0xc26, 0xc47, 0xc36, 0xc02,
+0x4b, 0x69, 0x74, 0x65, 0x73, 0x6f, 0x4b, 0x65, 0x6e, 0x69, 0x61, 0xe44,
+0xe17, 0xe22, 0xf56, 0xf7c, 0xf51, 0xf0b, 0xf66, 0xf90, 0xf51, 0xf0b, 0xf62, 0xf92,
+0xfb1, 0xf0b, 0xf53, 0xf42, 0xf62, 0xf92, 0xfb1, 0xf0b, 0xf42, 0xf62, 0xf0b, 0x1275,
+0x130d, 0x1228, 0x1275, 0x130d, 0x122d, 0x129b, 0x54, 0x6f, 0x6b, 0x20, 0x50, 0x69,
+0x73, 0x69, 0x6e, 0x50, 0x61, 0x70, 0x75, 0x61, 0x20, 0x4e, 0x69, 0x75,
+0x67, 0x69, 0x6e, 0x69, 0x6c, 0x65, 0x61, 0x20, 0x66, 0x61, 0x6b, 0x61,
+0x74, 0x6f, 0x6e, 0x67, 0x61, 0x58, 0x69, 0x74, 0x73, 0x6f, 0x6e, 0x67,
+0x61, 0x53, 0x65, 0x74, 0x73, 0x77, 0x61, 0x6e, 0x61, 0x41, 0x66, 0x6f,
+0x72, 0x69, 0x6b, 0x61, 0x20, 0x42, 0x6f, 0x72, 0x77, 0x61, 0x54, 0xfc,
+0x72, 0x6b, 0xe7, 0x65, 0x54, 0xfc, 0x72, 0x6b, 0x69, 0x79, 0x65, 0x4b,
+0x131, 0x62, 0x72, 0x131, 0x73, 0x74, 0xfc, 0x72, 0x6b, 0x6d, 0x65, 0x6e,
+0x20, 0x64, 0x69, 0x6c, 0x69, 0x54, 0xfc, 0x72, 0x6b, 0x6d, 0x65, 0x6e,
+0x69, 0x73, 0x74, 0x61, 0x6e, 0x4b, 0x61, 0x74, 0x61, 0x62, 0x443, 0x43a,
+0x440, 0x430, 0x457, 0x43d, 0x441, 0x44c, 0x43a, 0x430, 0x423, 0x43a, 0x440, 0x430,
+0x457, 0x43d, 0x430, 0x68, 0x6f, 0x72, 0x6e, 0x6a, 0x6f, 0x73, 0x65, 0x72,
+0x62, 0x161, 0x107, 0x69, 0x6e, 0x61, 0x4e, 0x11b, 0x6d, 0x73, 0x6b, 0x61,
+0x627, 0x631, 0x62f, 0x648, 0x628, 0x6be, 0x627, 0x631, 0x62a, 0x626, 0x6c7, 0x64a,
+0x63a, 0x6c7, 0x631, 0x686, 0x6d5, 0x62c, 0x6c7, 0x6ad, 0x6af, 0x648, 0x6f, 0x2018,
+0x7a, 0x62, 0x65, 0x6b, 0x4f, 0x2bb, 0x7a, 0x62, 0x65, 0x6b, 0x69, 0x73,
+0x74, 0x6f, 0x6e, 0x627, 0x648, 0x632, 0x628, 0x6cc, 0x6a9, 0x45e, 0x437, 0x431,
+0x435, 0x43a, 0x447, 0x430, 0x40e, 0x437, 0x431, 0x435, 0x43a, 0x438, 0x441, 0x442,
+0x43e, 0x43d, 0xa559, 0xa524, 0xa55e, 0xa524, 0xa52b, 0xa569, 0x56, 0x61, 0x69, 0x4c,
+0x61, 0x69, 0x62, 0x68, 0x69, 0x79, 0x61, 0x54, 0x73, 0x68, 0x69, 0x76,
+0x65, 0x6e, 0x1e13, 0x61, 0x54, 0x69, 0x1ebf, 0x6e, 0x67, 0x20, 0x56, 0x69,
+0x1ec7, 0x74, 0x56, 0x69, 0x1ec7, 0x74, 0x20, 0x4e, 0x61, 0x6d, 0x56, 0x6f,
+0x6c, 0x61, 0x70, 0xfc, 0x6b, 0x4b, 0x79, 0x69, 0x76, 0x75, 0x6e, 0x6a,
+0x6f, 0x77, 0x61, 0x6c, 0x6f, 0x6e, 0x57, 0x61, 0x6c, 0x73, 0x65, 0x72,
+0x53, 0x63, 0x68, 0x77, 0x69, 0x7a, 0x57, 0x61, 0x72, 0x6c, 0x70, 0x69,
+0x72, 0x69, 0x43, 0x79, 0x6d, 0x72, 0x61, 0x65, 0x67, 0x59, 0x20, 0x44,
+0x65, 0x79, 0x72, 0x6e, 0x61, 0x73, 0x20, 0x55, 0x6e, 0x65, 0x64, 0x69,
+0x67, 0x628, 0x644, 0x648, 0x686, 0x6cc, 0x20, 0x28, 0x631, 0x62e, 0x634, 0x627,
+0x646, 0x6cc, 0x29, 0x626, 0x648, 0x645, 0x627, 0x646, 0x645, 0x62a, 0x62d, 0x62f,
+0x6cc, 0x646, 0x20, 0x639, 0x631, 0x628, 0x6cc, 0x646, 0x20, 0x627, 0x645, 0x627,
+0x631, 0x627, 0x62a, 0x46, 0x72, 0x79, 0x73, 0x6b, 0x4e, 0x65, 0x64, 0x65,
+0x72, 0x6c, 0xe2, 0x6e, 0x12c8, 0x120b, 0x12ed, 0x1273, 0x1271, 0x57, 0x6f, 0x6c,
+0x6f, 0x66, 0x49, 0x73, 0x69, 0x58, 0x68, 0x6f, 0x73, 0x61, 0x45, 0x4d,
+0x7a, 0x61, 0x6e, 0x74, 0x73, 0x69, 0x20, 0x41, 0x66, 0x72, 0x69, 0x6b,
+0x61, 0x6e, 0x75, 0x61, 0x73, 0x75, 0x65, 0x4b, 0x65, 0x6d, 0x65, 0x6c,
+0xfa, 0x6e, 0x5d9, 0x5d9, 0x5b4, 0x5d3, 0x5d9, 0x5e9, 0x5d0, 0x5d5, 0x5e7, 0x5e8,
+0x5d0, 0x5b7, 0x5d9, 0x5e0, 0x5e2, 0xc8, 0x64, 0xe8, 0x20, 0x59, 0x6f, 0x72,
+0xf9, 0x62, 0xe1, 0x4e, 0xe0, 0xec, 0x6a, 0xed, 0x72, 0xed, 0xe0, 0x42,
+0x25b, 0x300, 0x6e, 0x25b, 0x300, 0x5a, 0x61, 0x72, 0x6d, 0x61, 0x63, 0x69,
+0x69, 0x6e, 0x65, 0x56, 0x61, 0x68, 0x63, 0x75, 0x65, 0x6e, 0x67, 0x68,
+0x43, 0x75, 0x6e, 0x67, 0x68, 0x67, 0x6f, 0x7a, 0x69, 0x73, 0x69, 0x5a,
+0x75, 0x6c, 0x75, 0x69, 0x4e, 0x69, 0x6e, 0x67, 0x69, 0x7a, 0x69, 0x6d,
+0x75, 0x20, 0x41, 0x66, 0x72, 0x69, 0x6b, 0x61, 0x6b, 0x61, 0x6e, 0x68,
+0x67, 0xe1, 0x67, 0x4d, 0x72, 0x61, 0x73, 0x69, 0x72, 0x6e, 0x68, 0x65,
+0x1ebd, 0x67, 0x61, 0x74, 0x75, 0x42, 0x72, 0x61, 0x73, 0x69, 0x75, 0xf1,
+0x65, 0x6e, 0x67, 0x61, 0x74, 0xfa, 0x4b, 0x75, 0x72, 0x169, 0x62, 0x69,
+0x79, 0x61, 0x57, 0x65, 0x6e, 0x65, 0x73, 0x75, 0x65, 0x72, 0x61, 0x939,
+0x930, 0x93f, 0x92f, 0x93e, 0x923, 0x935, 0x940, 0x4e, 0x6f, 0x72, 0x64, 0x66,
+0x72, 0x69, 0x69, 0x73, 0x6b, 0x54, 0x6a, 0x69, 0x69, 0x73, 0x6b, 0x6c,
+0x75, 0x6e, 0x930, 0x93e, 0x91c, 0x938, 0x94d, 0x925, 0x93e, 0x928, 0x940, 0x43c,
+0x43e, 0x43a, 0x448, 0x435, 0x43d, 0x44c, 0x20, 0x43a, 0x44f, 0x43b, 0x44c, 0x74,
+0x6f, 0x6b, 0x69, 0x20, 0x70, 0x6f, 0x6e, 0x61, 0x6d, 0x61, 0x20, 0x61,
+0x6c, 0x65, 0x50, 0x69, 0x6a, 0x69, 0x6e, 0x53, 0x6f, 0x6c, 0x6f, 0x6d,
+0x6f, 0x6e, 0x20, 0x41, 0x65, 0x6c, 0x61, 0x6e, 0x4f, 0x62, 0x6f, 0x6c,
+0x6f, 0x628, 0x644, 0x6c6, 0x686, 0x6cc, 0x42, 0x61, 0x6c, 0xf3, 0x63, 0x68,
+0x69, 0x50, 0xe1, 0x6b, 0x65, 0x73, 0x74, 0xe1, 0x6e, 0x6c, 0x69, 0x67,
+0x75, 0x72, 0x65, 0xd803, 0xdd0c, 0xd803, 0xdd17, 0xd803, 0xdd25, 0xd803, 0xdd1d, 0xd803,
+0xdd19, 0xd803, 0xdd1a, 0xd803, 0xdd12, 0xd803, 0xdd19, 0xd803, 0xdd1d, 0x62a, 0x648, 0x631,
+0x648, 0x627, 0x644, 0x6cc, 0x61, 0x6e, 0x69, 0x69, 0x20, 0x6b, 0x61, 0x67,
+0x269, 0x6a, 0x61, 0x42, 0x65, 0x6e, 0x25b, 0x25b, 0x915, 0x93e, 0x902, 0x917,
+0x921, 0x93c, 0x940, 0x76, 0x65, 0x6e, 0x65, 0x74, 0x6f
};
static constexpr char language_name_list[] =
@@ -3995,7 +6253,7 @@ static constexpr char language_name_list[] =
"Chickasaw\0"
"Chiga\0"
"Chinese\0"
-"Church\0"
+"Church Slavic\0"
"Chuvash\0"
"Colognian\0"
"Coptic\0"
@@ -4023,8 +6281,8 @@ static constexpr char language_name_list[] =
"Finnish\0"
"French\0"
"Friulian\0"
-"Fulah\0"
-"Gaelic\0"
+"Fula\0" // Fulah
+"Scottish Gaelic\0"
"Ga\0"
"Galician\0"
"Ganda\0"
@@ -4036,7 +6294,7 @@ static constexpr char language_name_list[] =
"Guarani\0"
"Gujarati\0"
"Gusii\0"
-"Haitian\0"
+"Haitian Creole\0"
"Hausa\0"
"Hawaiian\0"
"Hebrew\0"
@@ -4059,7 +6317,7 @@ static constexpr char language_name_list[] =
"Japanese\0"
"Javanese\0"
"Jju\0"
-"Jola Fonyi\0"
+"Jola-Fonyi\0"
"Kabuverdianu\0"
"Kabyle\0"
"Kako\0"
@@ -4072,7 +6330,7 @@ static constexpr char language_name_list[] =
"Kazakh\0"
"Kenyang\0"
"Khmer\0"
-"Kiche\0"
+"Kʼicheʼ\0"
"Kikuyu\0"
"Kinyarwanda\0"
"Komi\0"
@@ -4100,7 +6358,7 @@ static constexpr char language_name_list[] =
"Lojban\0"
"Lower Sorbian\0"
"Low German\0"
-"Luba Katanga\0"
+"Luba-Katanga\0"
"Lule Sami\0"
"Luo\0"
"Luxembourgish\0"
@@ -4108,7 +6366,7 @@ static constexpr char language_name_list[] =
"Macedonian\0"
"Machame\0"
"Maithili\0"
-"Makhuwa Meetto\0"
+"Makhuwa-Meetto\0"
"Makonde\0"
"Malagasy\0"
"Malayalam\0"
@@ -4117,7 +6375,7 @@ static constexpr char language_name_list[] =
"Mandingo\0"
"Manipuri\0"
"Manx\0"
-"Maori\0"
+"Māori\0"
"Mapuche\0"
"Marathi\0"
"Marshallese\0"
@@ -4125,7 +6383,7 @@ static constexpr char language_name_list[] =
"Mazanderani\0"
"Mende\0"
"Meru\0"
-"Meta\0"
+"Metaʼ\0"
"Mohawk\0"
"Mongolian\0"
"Morisyen\0"
@@ -4140,12 +6398,12 @@ static constexpr char language_name_list[] =
"Ngiemboon\0"
"Ngomba\0"
"Nigerian Pidgin\0"
-"Nko\0"
+"N’Ko\0"
"Northern Luri\0"
"Northern Sami\0"
"Northern Sotho\0"
"North Ndebele\0"
-"Norwegian Bokmal\0"
+"Norwegian Bokmål\0"
"Norwegian Nynorsk\0"
"Nuer\0"
"Nyanja\0"
@@ -4178,7 +6436,7 @@ static constexpr char language_name_list[] =
"Russian\0"
"Rwa\0"
"Saho\0"
-"Sakha\0"
+"Yakut\0" // Sakha
"Samburu\0"
"Samoan\0"
"Sango\0"
@@ -4247,7 +6505,7 @@ static constexpr char language_name_list[] =
"Vai\0"
"Venda\0"
"Vietnamese\0"
-"Volapuk\0"
+"Volapük\0"
"Vunjo\0"
"Walloon\0"
"Walser\0"
@@ -4273,6 +6531,13 @@ static constexpr char language_name_list[] =
"Toki Pona\0"
"Pijin\0"
"Obolo\0"
+"Baluchi\0"
+"Ligurian\0"
+"Rohingya\0"
+"Torwali\0"
+"Anii\0"
+"Kangri\0"
+"Venetian\0"
;
static constexpr quint16 language_name_index[] = {
@@ -4336,283 +6601,290 @@ static constexpr quint16 language_name_index[] = {
497, // Chiga
503, // Chinese
511, // Church
- 518, // Chuvash
- 526, // Colognian
- 536, // Coptic
- 543, // Cornish
- 551, // Corsican
- 560, // Cree
- 565, // Croatian
- 574, // Czech
- 580, // Danish
- 587, // Divehi
- 594, // Dogri
- 600, // Duala
- 606, // Dutch
- 612, // Dzongkha
- 621, // Embu
- 626, // English
- 634, // Erzya
- 640, // Esperanto
- 650, // Estonian
- 659, // Ewe
- 663, // Ewondo
- 670, // Faroese
- 678, // Fijian
- 685, // Filipino
- 694, // Finnish
- 702, // French
- 709, // Friulian
- 718, // Fulah
- 724, // Gaelic
- 731, // Ga
- 734, // Galician
- 743, // Ganda
- 749, // Geez
- 754, // Georgian
- 763, // German
- 770, // Gothic
- 777, // Greek
- 783, // Guarani
- 791, // Gujarati
- 800, // Gusii
- 806, // Haitian
- 814, // Hausa
- 820, // Hawaiian
- 829, // Hebrew
- 836, // Herero
- 843, // Hindi
- 849, // Hiri Motu
- 859, // Hungarian
- 869, // Icelandic
- 879, // Ido
- 883, // Igbo
- 888, // Inari Sami
- 899, // Indonesian
- 910, // Ingush
- 917, // Interlingua
- 929, // Interlingue
- 941, // Inuktitut
- 951, // Inupiaq
- 959, // Irish
- 965, // Italian
- 973, // Japanese
- 982, // Javanese
- 991, // Jju
- 995, // Jola Fonyi
- 1006, // Kabuverdianu
- 1019, // Kabyle
- 1026, // Kako
- 1031, // Kalaallisut
- 1043, // Kalenjin
- 1052, // Kamba
- 1058, // Kannada
- 1066, // Kanuri
- 1073, // Kashmiri
- 1082, // Kazakh
- 1089, // Kenyang
- 1097, // Khmer
- 1103, // Kiche
- 1109, // Kikuyu
- 1116, // Kinyarwanda
- 1128, // Komi
- 1133, // Kongo
- 1139, // Konkani
- 1147, // Korean
- 1154, // Koro
- 1159, // Koyraboro Senni
- 1175, // Koyra Chiini
- 1188, // Kpelle
- 1195, // Kuanyama
- 1204, // Kurdish
- 1212, // Kwasio
- 1219, // Kyrgyz
- 1226, // Lakota
- 1233, // Langi
- 1239, // Lao
- 1243, // Latin
- 1249, // Latvian
- 1257, // Lezghian
- 1266, // Limburgish
- 1277, // Lingala
- 1285, // Literary Chinese
- 1302, // Lithuanian
- 1313, // Lojban
- 1320, // Lower Sorbian
- 1334, // Low German
- 1345, // Luba Katanga
- 1358, // Lule Sami
- 1368, // Luo
- 1372, // Luxembourgish
- 1386, // Luyia
- 1392, // Macedonian
- 1403, // Machame
- 1411, // Maithili
- 1420, // Makhuwa Meetto
- 1435, // Makonde
- 1443, // Malagasy
- 1452, // Malayalam
- 1462, // Malay
- 1468, // Maltese
- 1476, // Mandingo
- 1485, // Manipuri
- 1494, // Manx
- 1499, // Maori
- 1505, // Mapuche
- 1513, // Marathi
- 1521, // Marshallese
- 1533, // Masai
- 1539, // Mazanderani
- 1551, // Mende
- 1557, // Meru
- 1562, // Meta
- 1567, // Mohawk
- 1574, // Mongolian
- 1584, // Morisyen
- 1593, // Mundang
- 1601, // Muscogee
- 1610, // Nama
- 1615, // Nauru
- 1621, // Navajo
- 1628, // Ndonga
- 1635, // Nepali
- 1642, // Newari
- 1649, // Ngiemboon
- 1659, // Ngomba
- 1666, // Nigerian Pidgin
- 1682, // Nko
- 1686, // Northern Luri
- 1700, // Northern Sami
- 1714, // Northern Sotho
- 1729, // North Ndebele
- 1743, // Norwegian Bokmal
- 1760, // Norwegian Nynorsk
- 1778, // Nuer
- 1783, // Nyanja
- 1790, // Nyankole
- 1799, // Occitan
- 1807, // Odia
- 1812, // Ojibwa
- 1819, // Old Irish
- 1829, // Old Norse
- 1839, // Old Persian
- 1851, // Oromo
- 1857, // Osage
- 1863, // Ossetic
- 1871, // Pahlavi
- 1879, // Palauan
- 1887, // Pali
- 1892, // Papiamento
- 1903, // Pashto
- 1910, // Persian
- 1918, // Phoenician
- 1929, // Polish
- 1936, // Portuguese
- 1947, // Prussian
- 1956, // Punjabi
- 1964, // Quechua
- 1972, // Romanian
- 1981, // Romansh
- 1989, // Rombo
- 1995, // Rundi
- 2001, // Russian
- 2009, // Rwa
- 2013, // Saho
- 2018, // Sakha
- 2024, // Samburu
- 2032, // Samoan
- 2039, // Sango
- 2045, // Sangu
- 2051, // Sanskrit
- 2060, // Santali
- 2068, // Sardinian
- 2078, // Saurashtra
- 2089, // Sena
- 2094, // Serbian
- 2102, // Shambala
- 2111, // Shona
- 2117, // Sichuan Yi
- 2128, // Sicilian
- 2137, // Sidamo
- 2144, // Silesian
- 2153, // Sindhi
- 2160, // Sinhala
- 2168, // Skolt Sami
- 2179, // Slovak
- 2186, // Slovenian
- 2196, // Soga
- 2201, // Somali
- 2208, // Southern Kurdish
- 2225, // Southern Sami
- 2239, // Southern Sotho
- 2254, // South Ndebele
- 2268, // Spanish
- 2276, // Standard Moroccan Tamazight
- 2304, // Sundanese
- 2314, // Swahili
- 2322, // Swati
- 2328, // Swedish
- 2336, // Swiss German
- 2349, // Syriac
- 2356, // Tachelhit
- 2366, // Tahitian
- 2375, // Tai Dam
- 2383, // Taita
- 2389, // Tajik
- 2395, // Tamil
- 2401, // Taroko
- 2408, // Tasawaq
- 2416, // Tatar
- 2422, // Telugu
- 2429, // Teso
- 2434, // Thai
- 2439, // Tibetan
- 2447, // Tigre
- 2453, // Tigrinya
- 2462, // Tokelau
- 2470, // Tok Pisin
- 2480, // Tongan
- 2487, // Tsonga
- 2494, // Tswana
- 2501, // Turkish
- 2509, // Turkmen
- 2517, // Tuvalu
- 2524, // Tyap
- 2529, // Ugaritic
- 2538, // Ukrainian
- 2548, // Upper Sorbian
- 2562, // Urdu
- 2567, // Uyghur
- 2574, // Uzbek
- 2580, // Vai
- 2584, // Venda
- 2590, // Vietnamese
- 2601, // Volapuk
- 2609, // Vunjo
- 2615, // Walloon
- 2623, // Walser
- 2630, // Warlpiri
- 2639, // Welsh
- 2645, // Western Balochi
- 2661, // Western Frisian
- 2677, // Wolaytta
- 2686, // Wolof
- 2692, // Xhosa
- 2698, // Yangben
- 2706, // Yiddish
- 2714, // Yoruba
- 2721, // Zarma
- 2727, // Zhuang
- 2734, // Zulu
- 2739, // Kaingang
- 2748, // Nheengatu
- 2758, // Haryanvi
- 2767, // Northern Frisian
- 2784, // Rajasthani
- 2795, // Moksha
- 2802, // Toki Pona
- 2812, // Pijin
- 2818, // Obolo
+ 525, // Chuvash
+ 533, // Colognian
+ 543, // Coptic
+ 550, // Cornish
+ 558, // Corsican
+ 567, // Cree
+ 572, // Croatian
+ 581, // Czech
+ 587, // Danish
+ 594, // Divehi
+ 601, // Dogri
+ 607, // Duala
+ 613, // Dutch
+ 619, // Dzongkha
+ 628, // Embu
+ 633, // English
+ 641, // Erzya
+ 647, // Esperanto
+ 657, // Estonian
+ 666, // Ewe
+ 670, // Ewondo
+ 677, // Faroese
+ 685, // Fijian
+ 692, // Filipino
+ 701, // Finnish
+ 709, // French
+ 716, // Friulian
+ 725, // Fulah
+ 730, // Gaelic
+ 746, // Ga
+ 749, // Galician
+ 758, // Ganda
+ 764, // Geez
+ 769, // Georgian
+ 778, // German
+ 785, // Gothic
+ 792, // Greek
+ 798, // Guarani
+ 806, // Gujarati
+ 815, // Gusii
+ 821, // Haitian
+ 836, // Hausa
+ 842, // Hawaiian
+ 851, // Hebrew
+ 858, // Herero
+ 865, // Hindi
+ 871, // Hiri Motu
+ 881, // Hungarian
+ 891, // Icelandic
+ 901, // Ido
+ 905, // Igbo
+ 910, // Inari Sami
+ 921, // Indonesian
+ 932, // Ingush
+ 939, // Interlingua
+ 951, // Interlingue
+ 963, // Inuktitut
+ 973, // Inupiaq
+ 981, // Irish
+ 987, // Italian
+ 995, // Japanese
+ 1004, // Javanese
+ 1013, // Jju
+ 1017, // Jola-Fonyi
+ 1028, // Kabuverdianu
+ 1041, // Kabyle
+ 1048, // Kako
+ 1053, // Kalaallisut
+ 1065, // Kalenjin
+ 1074, // Kamba
+ 1080, // Kannada
+ 1088, // Kanuri
+ 1095, // Kashmiri
+ 1104, // Kazakh
+ 1111, // Kenyang
+ 1119, // Khmer
+ 1125, // Kiche
+ 1135, // Kikuyu
+ 1142, // Kinyarwanda
+ 1154, // Komi
+ 1159, // Kongo
+ 1165, // Konkani
+ 1173, // Korean
+ 1180, // Koro
+ 1185, // Koyraboro Senni
+ 1201, // Koyra Chiini
+ 1214, // Kpelle
+ 1221, // Kuanyama
+ 1230, // Kurdish
+ 1238, // Kwasio
+ 1245, // Kyrgyz
+ 1252, // Lakota
+ 1259, // Langi
+ 1265, // Lao
+ 1269, // Latin
+ 1275, // Latvian
+ 1283, // Lezghian
+ 1292, // Limburgish
+ 1303, // Lingala
+ 1311, // Literary Chinese
+ 1328, // Lithuanian
+ 1339, // Lojban
+ 1346, // Lower Sorbian
+ 1360, // Low German
+ 1371, // Luba-Katanga
+ 1384, // Lule Sami
+ 1394, // Luo
+ 1398, // Luxembourgish
+ 1412, // Luyia
+ 1418, // Macedonian
+ 1429, // Machame
+ 1437, // Maithili
+ 1446, // Makhuwa-Meetto
+ 1461, // Makonde
+ 1469, // Malagasy
+ 1478, // Malayalam
+ 1488, // Malay
+ 1494, // Maltese
+ 1502, // Mandingo
+ 1511, // Manipuri
+ 1520, // Manx
+ 1525, // Maori
+ 1532, // Mapuche
+ 1540, // Marathi
+ 1548, // Marshallese
+ 1560, // Masai
+ 1566, // Mazanderani
+ 1578, // Mende
+ 1584, // Meru
+ 1589, // Meta
+ 1596, // Mohawk
+ 1603, // Mongolian
+ 1613, // Morisyen
+ 1622, // Mundang
+ 1630, // Muscogee
+ 1639, // Nama
+ 1644, // Nauru
+ 1650, // Navajo
+ 1657, // Ndonga
+ 1664, // Nepali
+ 1671, // Newari
+ 1678, // Ngiemboon
+ 1688, // Ngomba
+ 1695, // Nigerian Pidgin
+ 1711, // Nko
+ 1718, // Northern Luri
+ 1732, // Northern Sami
+ 1746, // Northern Sotho
+ 1761, // North Ndebele
+ 1775, // Norwegian Bokmal
+ 1793, // Norwegian Nynorsk
+ 1811, // Nuer
+ 1816, // Nyanja
+ 1823, // Nyankole
+ 1832, // Occitan
+ 1840, // Odia
+ 1845, // Ojibwa
+ 1852, // Old Irish
+ 1862, // Old Norse
+ 1872, // Old Persian
+ 1884, // Oromo
+ 1890, // Osage
+ 1896, // Ossetic
+ 1904, // Pahlavi
+ 1912, // Palauan
+ 1920, // Pali
+ 1925, // Papiamento
+ 1936, // Pashto
+ 1943, // Persian
+ 1951, // Phoenician
+ 1962, // Polish
+ 1969, // Portuguese
+ 1980, // Prussian
+ 1989, // Punjabi
+ 1997, // Quechua
+ 2005, // Romanian
+ 2014, // Romansh
+ 2022, // Rombo
+ 2028, // Rundi
+ 2034, // Russian
+ 2042, // Rwa
+ 2046, // Saho
+ 2051, // Sakha
+ 2057, // Samburu
+ 2065, // Samoan
+ 2072, // Sango
+ 2078, // Sangu
+ 2084, // Sanskrit
+ 2093, // Santali
+ 2101, // Sardinian
+ 2111, // Saurashtra
+ 2122, // Sena
+ 2127, // Serbian
+ 2135, // Shambala
+ 2144, // Shona
+ 2150, // Sichuan Yi
+ 2161, // Sicilian
+ 2170, // Sidamo
+ 2177, // Silesian
+ 2186, // Sindhi
+ 2193, // Sinhala
+ 2201, // Skolt Sami
+ 2212, // Slovak
+ 2219, // Slovenian
+ 2229, // Soga
+ 2234, // Somali
+ 2241, // Southern Kurdish
+ 2258, // Southern Sami
+ 2272, // Southern Sotho
+ 2287, // South Ndebele
+ 2301, // Spanish
+ 2309, // Standard Moroccan Tamazight
+ 2337, // Sundanese
+ 2347, // Swahili
+ 2355, // Swati
+ 2361, // Swedish
+ 2369, // Swiss German
+ 2382, // Syriac
+ 2389, // Tachelhit
+ 2399, // Tahitian
+ 2408, // Tai Dam
+ 2416, // Taita
+ 2422, // Tajik
+ 2428, // Tamil
+ 2434, // Taroko
+ 2441, // Tasawaq
+ 2449, // Tatar
+ 2455, // Telugu
+ 2462, // Teso
+ 2467, // Thai
+ 2472, // Tibetan
+ 2480, // Tigre
+ 2486, // Tigrinya
+ 2495, // Tokelau
+ 2503, // Tok Pisin
+ 2513, // Tongan
+ 2520, // Tsonga
+ 2527, // Tswana
+ 2534, // Turkish
+ 2542, // Turkmen
+ 2550, // Tuvalu
+ 2557, // Tyap
+ 2562, // Ugaritic
+ 2571, // Ukrainian
+ 2581, // Upper Sorbian
+ 2595, // Urdu
+ 2600, // Uyghur
+ 2607, // Uzbek
+ 2613, // Vai
+ 2617, // Venda
+ 2623, // Vietnamese
+ 2634, // Volapuk
+ 2643, // Vunjo
+ 2649, // Walloon
+ 2657, // Walser
+ 2664, // Warlpiri
+ 2673, // Welsh
+ 2679, // Western Balochi
+ 2695, // Western Frisian
+ 2711, // Wolaytta
+ 2720, // Wolof
+ 2726, // Xhosa
+ 2732, // Yangben
+ 2740, // Yiddish
+ 2748, // Yoruba
+ 2755, // Zarma
+ 2761, // Zhuang
+ 2768, // Zulu
+ 2773, // Kaingang
+ 2782, // Nheengatu
+ 2792, // Haryanvi
+ 2801, // Northern Frisian
+ 2818, // Rajasthani
+ 2829, // Moksha
+ 2836, // Toki Pona
+ 2846, // Pijin
+ 2852, // Obolo
+ 2858, // Baluchi
+ 2866, // Ligurian
+ 2875, // Rohingya
+ 2884, // Torwali
+ 2892, // Anii
+ 2897, // Kangri
+ 2904, // Venetian
};
static constexpr char script_name_list[] =
@@ -4634,20 +6906,20 @@ static constexpr char script_name_list[] =
"Braille\0"
"Buginese\0"
"Buhid\0"
-"Canadian Aboriginal\0"
+"Unified Canadian Aboriginal Syllabics\0"
"Carian\0"
"Caucasian Albanian\0"
"Chakma\0"
"Cham\0"
"Cherokee\0"
"Coptic\0"
-"Cuneiform\0"
+"Sumero-Akkadian Cuneiform\0"
"Cypriot\0"
"Cyrillic\0"
"Deseret\0"
"Devanagari\0"
-"Duployan\0"
-"Egyptian Hieroglyphs\0"
+"Duployan shorthand\0"
+"Egyptian hieroglyphs\0"
"Elbasan\0"
"Ethiopic\0"
"Fraser\0"
@@ -4706,7 +6978,7 @@ static constexpr char script_name_list[] =
"Nabataean\0"
"Newa\0"
"New Tai Lue\0"
-"Nko\0"
+"N’Ko\0"
"Odia\0"
"Ogham\0"
"Ol Chiki\0"
@@ -4722,7 +6994,7 @@ static constexpr char script_name_list[] =
"Pahawh Hmong\0"
"Palmyrene\0"
"Pau Cin Hau\0"
-"Phags Pa\0"
+"Phags-pa\0"
"Phoenician\0"
"Pollard Phonetic\0"
"Psalter Pahlavi\0"
@@ -4733,7 +7005,7 @@ static constexpr char script_name_list[] =
"Sharada\0"
"Shavian\0"
"Siddham\0"
-"Sign Writing\0"
+"SignWriting\0"
"Simplified Han\0"
"Sinhala\0"
"Sora Sompeng\0"
@@ -4758,6 +7030,7 @@ static constexpr char script_name_list[] =
"Vai\0"
"Varang Kshiti\0"
"Yi\0"
+"Hanifi Rohingya\0"
;
static constexpr quint16 script_name_index[] = {
@@ -4780,135 +7053,136 @@ static constexpr quint16 script_name_index[] = {
137, // Buginese
146, // Buhid
152, // Canadian Aboriginal
- 172, // Carian
- 179, // Caucasian Albanian
- 198, // Chakma
- 205, // Cham
- 210, // Cherokee
- 219, // Coptic
- 226, // Cuneiform
- 236, // Cypriot
- 244, // Cyrillic
- 253, // Deseret
- 261, // Devanagari
- 272, // Duployan
- 281, // Egyptian Hieroglyphs
- 302, // Elbasan
- 310, // Ethiopic
- 319, // Fraser
- 326, // Georgian
- 335, // Glagolitic
- 346, // Gothic
- 353, // Grantha
- 361, // Greek
- 367, // Gujarati
- 376, // Gurmukhi
- 385, // Hangul
- 392, // Han
- 396, // Hanunoo
- 404, // Han with Bopomofo
- 422, // Hatran
- 429, // Hebrew
- 436, // Hiragana
- 445, // Imperial Aramaic
- 462, // Inscriptional Pahlavi
- 484, // Inscriptional Parthian
- 507, // Jamo
- 512, // Japanese
- 521, // Javanese
- 530, // Kaithi
- 537, // Kannada
- 545, // Katakana
- 554, // Kayah Li
- 563, // Kharoshthi
- 574, // Khmer
- 580, // Khojki
- 587, // Khudawadi
- 597, // Korean
- 604, // Lanna
- 610, // Lao
- 614, // Latin
- 620, // Lepcha
- 627, // Limbu
- 633, // Linear A
- 642, // Linear B
- 651, // Lycian
- 658, // Lydian
- 665, // Mahajani
- 674, // Malayalam
- 684, // Mandaean
- 693, // Manichaean
- 704, // Marchen
- 712, // Meitei Mayek
- 725, // Mende
- 731, // Meroitic Cursive
- 748, // Meroitic
- 757, // Modi
- 762, // Mongolian
- 772, // Mro
- 776, // Multani
- 784, // Myanmar
- 792, // Nabataean
- 802, // Newa
- 807, // New Tai Lue
- 819, // Nko
- 823, // Odia
- 828, // Ogham
- 834, // Ol Chiki
- 843, // Old Hungarian
- 857, // Old Italic
- 868, // Old North Arabian
- 886, // Old Permic
- 897, // Old Persian
- 909, // Old South Arabian
- 927, // Orkhon
- 934, // Osage
- 940, // Osmanya
- 948, // Pahawh Hmong
- 961, // Palmyrene
- 971, // Pau Cin Hau
- 983, // Phags Pa
- 992, // Phoenician
- 1003, // Pollard Phonetic
- 1020, // Psalter Pahlavi
- 1036, // Rejang
- 1043, // Runic
- 1049, // Samaritan
- 1059, // Saurashtra
- 1070, // Sharada
- 1078, // Shavian
- 1086, // Siddham
- 1094, // Sign Writing
- 1107, // Simplified Han
- 1122, // Sinhala
- 1130, // Sora Sompeng
- 1143, // Sundanese
- 1153, // Syloti Nagri
- 1166, // Syriac
- 1173, // Tagalog
- 1181, // Tagbanwa
- 1190, // Tai Le
- 1197, // Tai Viet
- 1206, // Takri
- 1212, // Tamil
- 1218, // Tangut
- 1225, // Telugu
- 1232, // Thaana
- 1239, // Thai
- 1244, // Tibetan
- 1252, // Tifinagh
- 1261, // Tirhuta
- 1269, // Traditional Han
- 1285, // Ugaritic
- 1294, // Vai
- 1298, // Varang Kshiti
- 1312, // Yi
+ 190, // Carian
+ 197, // Caucasian Albanian
+ 216, // Chakma
+ 223, // Cham
+ 228, // Cherokee
+ 237, // Coptic
+ 244, // Cuneiform
+ 270, // Cypriot
+ 278, // Cyrillic
+ 287, // Deseret
+ 295, // Devanagari
+ 306, // Duployan
+ 325, // Egyptian hieroglyphs
+ 346, // Elbasan
+ 354, // Ethiopic
+ 363, // Fraser
+ 370, // Georgian
+ 379, // Glagolitic
+ 390, // Gothic
+ 397, // Grantha
+ 405, // Greek
+ 411, // Gujarati
+ 420, // Gurmukhi
+ 429, // Hangul
+ 436, // Han
+ 440, // Hanunoo
+ 448, // Han with Bopomofo
+ 466, // Hatran
+ 473, // Hebrew
+ 480, // Hiragana
+ 489, // Imperial Aramaic
+ 506, // Inscriptional Pahlavi
+ 528, // Inscriptional Parthian
+ 551, // Jamo
+ 556, // Japanese
+ 565, // Javanese
+ 574, // Kaithi
+ 581, // Kannada
+ 589, // Katakana
+ 598, // Kayah Li
+ 607, // Kharoshthi
+ 618, // Khmer
+ 624, // Khojki
+ 631, // Khudawadi
+ 641, // Korean
+ 648, // Lanna
+ 654, // Lao
+ 658, // Latin
+ 664, // Lepcha
+ 671, // Limbu
+ 677, // Linear A
+ 686, // Linear B
+ 695, // Lycian
+ 702, // Lydian
+ 709, // Mahajani
+ 718, // Malayalam
+ 728, // Mandaean
+ 737, // Manichaean
+ 748, // Marchen
+ 756, // Meitei Mayek
+ 769, // Mende
+ 775, // Meroitic Cursive
+ 792, // Meroitic
+ 801, // Modi
+ 806, // Mongolian
+ 816, // Mro
+ 820, // Multani
+ 828, // Myanmar
+ 836, // Nabataean
+ 846, // Newa
+ 851, // New Tai Lue
+ 863, // Nko
+ 870, // Odia
+ 875, // Ogham
+ 881, // Ol Chiki
+ 890, // Old Hungarian
+ 904, // Old Italic
+ 915, // Old North Arabian
+ 933, // Old Permic
+ 944, // Old Persian
+ 956, // Old South Arabian
+ 974, // Orkhon
+ 981, // Osage
+ 987, // Osmanya
+ 995, // Pahawh Hmong
+ 1008, // Palmyrene
+ 1018, // Pau Cin Hau
+ 1030, // Phags-pa
+ 1039, // Phoenician
+ 1050, // Pollard Phonetic
+ 1067, // Psalter Pahlavi
+ 1083, // Rejang
+ 1090, // Runic
+ 1096, // Samaritan
+ 1106, // Saurashtra
+ 1117, // Sharada
+ 1125, // Shavian
+ 1133, // Siddham
+ 1141, // SignWriting
+ 1153, // Simplified Han
+ 1168, // Sinhala
+ 1176, // Sora Sompeng
+ 1189, // Sundanese
+ 1199, // Syloti Nagri
+ 1212, // Syriac
+ 1219, // Tagalog
+ 1227, // Tagbanwa
+ 1236, // Tai Le
+ 1243, // Tai Viet
+ 1252, // Takri
+ 1258, // Tamil
+ 1264, // Tangut
+ 1271, // Telugu
+ 1278, // Thaana
+ 1285, // Thai
+ 1290, // Tibetan
+ 1298, // Tifinagh
+ 1307, // Tirhuta
+ 1315, // Traditional Han
+ 1331, // Ugaritic
+ 1340, // Vai
+ 1344, // Varang Kshiti
+ 1358, // Yi
+ 1361, // Hanifi
};
static constexpr char territory_name_list[] =
"Default\0"
"Afghanistan\0"
-"Aland Islands\0"
+"Åland Islands\0"
"Albania\0"
"Algeria\0"
"American Samoa\0"
@@ -4916,7 +7190,7 @@ static constexpr char territory_name_list[] =
"Angola\0"
"Anguilla\0"
"Antarctica\0"
-"Antigua And Barbuda\0"
+"Antigua & Barbuda\0"
"Argentina\0"
"Armenia\0"
"Aruba\0"
@@ -4935,7 +7209,7 @@ static constexpr char territory_name_list[] =
"Bermuda\0"
"Bhutan\0"
"Bolivia\0"
-"Bosnia And Herzegovina\0"
+"Bosnia & Herzegovina\0"
"Botswana\0"
"Bouvet Island\0"
"Brazil\0"
@@ -4953,22 +7227,22 @@ static constexpr char territory_name_list[] =
"Caribbean Netherlands\0"
"Cayman Islands\0"
"Central African Republic\0"
-"Ceuta And Melilla\0"
+"Ceuta & Melilla\0"
"Chad\0"
"Chile\0"
"China\0"
"Christmas Island\0"
"Clipperton Island\0"
-"Cocos Islands\0"
+"Cocos (Keeling) Islands\0"
"Colombia\0"
"Comoros\0"
-"Congo Brazzaville\0"
-"Congo Kinshasa\0"
+"Congo - Brazzaville\0"
+"Congo - Kinshasa\0"
"Cook Islands\0"
"Costa Rica\0"
"Croatia\0"
"Cuba\0"
-"Curacao\0"
+"Curaçao\0"
"Cyprus\0"
"Czechia\0"
"Denmark\0"
@@ -5007,13 +7281,13 @@ static constexpr char territory_name_list[] =
"Guam\0"
"Guatemala\0"
"Guernsey\0"
-"Guinea Bissau\0"
+"Guinea-Bissau\0"
"Guinea\0"
"Guyana\0"
"Haiti\0"
-"Heard And McDonald Islands\0"
+"Heard & McDonald Islands\0"
"Honduras\0"
-"Hong Kong\0"
+"Hong Kong SAR China\0"
"Hungary\0"
"Iceland\0"
"India\0"
@@ -5021,10 +7295,10 @@ static constexpr char territory_name_list[] =
"Iran\0"
"Iraq\0"
"Ireland\0"
-"Isle Of Man\0"
+"Isle of Man\0"
"Israel\0"
"Italy\0"
-"Ivory Coast\0"
+"Côte d’Ivoire\0" // Ivory Coast
"Jamaica\0"
"Japan\0"
"Jersey\0"
@@ -5045,8 +7319,8 @@ static constexpr char territory_name_list[] =
"Liechtenstein\0"
"Lithuania\0"
"Luxembourg\0"
-"Macao\0"
-"Macedonia\0"
+"Macao SAR China\0"
+"North Macedonia\0"
"Madagascar\0"
"Malawi\0"
"Malaysia\0"
@@ -5067,7 +7341,7 @@ static constexpr char territory_name_list[] =
"Montserrat\0"
"Morocco\0"
"Mozambique\0"
-"Myanmar\0"
+"Myanmar (Burma)\0"
"Namibia\0"
"Nauru\0"
"Nepal\0"
@@ -5092,25 +7366,25 @@ static constexpr char territory_name_list[] =
"Paraguay\0"
"Peru\0"
"Philippines\0"
-"Pitcairn\0"
+"Pitcairn Islands\0"
"Poland\0"
"Portugal\0"
"Puerto Rico\0"
"Qatar\0"
-"Reunion\0"
+"Réunion\0"
"Romania\0"
"Russia\0"
"Rwanda\0"
-"Saint Barthelemy\0"
-"Saint Helena\0"
-"Saint Kitts And Nevis\0"
-"Saint Lucia\0"
-"Saint Martin\0"
-"Saint Pierre And Miquelon\0"
-"Saint Vincent And Grenadines\0"
+"St. Barthélemy\0"
+"St. Helena\0"
+"St. Kitts & Nevis\0"
+"St. Lucia\0"
+"St. Martin\0"
+"St. Pierre & Miquelon\0"
+"St. Vincent & Grenadines\0"
"Samoa\0"
"San Marino\0"
-"Sao Tome And Principe\0"
+"São Tomé & Príncipe\0"
"Saudi Arabia\0"
"Senegal\0"
"Serbia\0"
@@ -5123,14 +7397,14 @@ static constexpr char territory_name_list[] =
"Solomon Islands\0"
"Somalia\0"
"South Africa\0"
-"South Georgia And South Sandwich Islands\0"
+"South Georgia & South Sandwich Islands\0"
"South Korea\0"
"South Sudan\0"
"Spain\0"
"Sri Lanka\0"
"Sudan\0"
"Suriname\0"
-"Svalbard And Jan Mayen\0"
+"Svalbard & Jan Mayen\0"
"Sweden\0"
"Switzerland\0"
"Syria\0"
@@ -5142,29 +7416,29 @@ static constexpr char territory_name_list[] =
"Togo\0"
"Tokelau\0"
"Tonga\0"
-"Trinidad And Tobago\0"
-"Tristan Da Cunha\0"
+"Trinidad & Tobago\0"
+"Tristan da Cunha\0"
"Tunisia\0"
-"Turkey\0"
+"Türkiye\0" // Turkey
"Turkmenistan\0"
-"Turks And Caicos Islands\0"
+"Turks & Caicos Islands\0"
"Tuvalu\0"
"Uganda\0"
"Ukraine\0"
"United Arab Emirates\0"
"United Kingdom\0"
-"United States Outlying Islands\0"
+"U.S. Outlying Islands\0"
"United States\0"
-"United States Virgin Islands\0"
+"U.S. Virgin Islands\0"
"Uruguay\0"
"Uzbekistan\0"
"Vanuatu\0"
"Vatican City\0"
"Venezuela\0"
"Vietnam\0"
-"Wallis And Futuna\0"
+"Wallis & Futuna\0"
"Western Sahara\0"
-"World\0"
+"world\0"
"Yemen\0"
"Zambia\0"
"Zimbabwe\0"
@@ -5174,268 +7448,268 @@ static constexpr quint16 territory_name_index[] = {
0, // AnyTerritory
8, // Afghanistan
20, // Aland Islands
- 34, // Albania
- 42, // Algeria
- 50, // American Samoa
- 65, // Andorra
- 73, // Angola
- 80, // Anguilla
- 89, // Antarctica
- 100, // Antigua And Barbuda
- 120, // Argentina
- 130, // Armenia
- 138, // Aruba
- 144, // Ascension Island
- 161, // Australia
- 171, // Austria
- 179, // Azerbaijan
- 190, // Bahamas
- 198, // Bahrain
- 206, // Bangladesh
- 217, // Barbados
- 226, // Belarus
- 234, // Belgium
- 242, // Belize
- 249, // Benin
- 255, // Bermuda
- 263, // Bhutan
- 270, // Bolivia
- 278, // Bosnia And Herzegovina
- 301, // Botswana
- 310, // Bouvet Island
- 324, // Brazil
- 331, // British Indian Ocean Territory
- 362, // British Virgin Islands
- 385, // Brunei
- 392, // Bulgaria
- 401, // Burkina Faso
- 414, // Burundi
- 422, // Cambodia
- 431, // Cameroon
- 440, // Canada
- 447, // Canary Islands
- 462, // Cape Verde
- 473, // Caribbean Netherlands
- 495, // Cayman Islands
- 510, // Central African Republic
- 535, // Ceuta And Melilla
- 553, // Chad
- 558, // Chile
- 564, // China
- 570, // Christmas Island
- 587, // Clipperton Island
- 605, // Cocos Islands
- 619, // Colombia
- 628, // Comoros
- 636, // Congo Brazzaville
- 654, // Congo Kinshasa
- 669, // Cook Islands
- 682, // Costa Rica
- 693, // Croatia
- 701, // Cuba
- 706, // Curacao
- 714, // Cyprus
- 721, // Czechia
- 729, // Denmark
- 737, // Diego Garcia
- 750, // Djibouti
- 759, // Dominica
- 768, // Dominican Republic
- 787, // Ecuador
- 795, // Egypt
- 801, // El Salvador
- 813, // Equatorial Guinea
- 831, // Eritrea
- 839, // Estonia
- 847, // Eswatini
- 856, // Ethiopia
- 865, // Europe
- 872, // European Union
- 887, // Falkland Islands
- 904, // Faroe Islands
- 918, // Fiji
- 923, // Finland
- 931, // France
- 938, // French Guiana
- 952, // French Polynesia
- 969, // French Southern Territories
- 997, // Gabon
- 1003, // Gambia
- 1010, // Georgia
- 1018, // Germany
- 1026, // Ghana
- 1032, // Gibraltar
- 1042, // Greece
- 1049, // Greenland
- 1059, // Grenada
- 1067, // Guadeloupe
- 1078, // Guam
- 1083, // Guatemala
- 1093, // Guernsey
- 1102, // Guinea Bissau
- 1116, // Guinea
- 1123, // Guyana
- 1130, // Haiti
- 1136, // Heard And McDonald Islands
- 1163, // Honduras
- 1172, // Hong Kong
- 1182, // Hungary
- 1190, // Iceland
- 1198, // India
- 1204, // Indonesia
- 1214, // Iran
- 1219, // Iraq
- 1224, // Ireland
- 1232, // Isle Of Man
- 1244, // Israel
- 1251, // Italy
- 1257, // Ivory Coast
- 1269, // Jamaica
- 1277, // Japan
- 1283, // Jersey
- 1290, // Jordan
- 1297, // Kazakhstan
- 1308, // Kenya
- 1314, // Kiribati
- 1323, // Kosovo
- 1330, // Kuwait
- 1337, // Kyrgyzstan
- 1348, // Laos
- 1353, // Latin America
- 1367, // Latvia
- 1374, // Lebanon
- 1382, // Lesotho
- 1390, // Liberia
- 1398, // Libya
- 1404, // Liechtenstein
- 1418, // Lithuania
- 1428, // Luxembourg
- 1439, // Macao
- 1445, // Macedonia
- 1455, // Madagascar
- 1466, // Malawi
- 1473, // Malaysia
- 1482, // Maldives
- 1491, // Mali
- 1496, // Malta
- 1502, // Marshall Islands
- 1519, // Martinique
- 1530, // Mauritania
- 1541, // Mauritius
- 1551, // Mayotte
- 1559, // Mexico
- 1566, // Micronesia
- 1577, // Moldova
- 1585, // Monaco
- 1592, // Mongolia
- 1601, // Montenegro
- 1612, // Montserrat
- 1623, // Morocco
- 1631, // Mozambique
- 1642, // Myanmar
- 1650, // Namibia
- 1658, // Nauru
- 1664, // Nepal
- 1670, // Netherlands
- 1682, // New Caledonia
- 1696, // New Zealand
- 1708, // Nicaragua
- 1718, // Nigeria
- 1726, // Niger
- 1732, // Niue
- 1737, // Norfolk Island
- 1752, // Northern Mariana Islands
- 1777, // North Korea
- 1789, // Norway
- 1796, // Oman
- 1801, // Outlying Oceania
- 1818, // Pakistan
- 1827, // Palau
- 1833, // Palestinian Territories
- 1857, // Panama
- 1864, // Papua New Guinea
- 1881, // Paraguay
- 1890, // Peru
- 1895, // Philippines
- 1907, // Pitcairn
- 1916, // Poland
- 1923, // Portugal
- 1932, // Puerto Rico
- 1944, // Qatar
- 1950, // Reunion
- 1958, // Romania
- 1966, // Russia
- 1973, // Rwanda
- 1980, // Saint Barthelemy
- 1997, // Saint Helena
- 2010, // Saint Kitts And Nevis
- 2032, // Saint Lucia
- 2044, // Saint Martin
- 2057, // Saint Pierre And Miquelon
- 2083, // Saint Vincent And Grenadines
- 2112, // Samoa
- 2118, // San Marino
- 2129, // Sao Tome And Principe
- 2151, // Saudi Arabia
- 2164, // Senegal
- 2172, // Serbia
- 2179, // Seychelles
- 2190, // Sierra Leone
- 2203, // Singapore
- 2213, // Sint Maarten
- 2226, // Slovakia
- 2235, // Slovenia
- 2244, // Solomon Islands
- 2260, // Somalia
- 2268, // South Africa
- 2281, // South Georgia And South Sandwich Islands
- 2322, // South Korea
- 2334, // South Sudan
- 2346, // Spain
- 2352, // Sri Lanka
- 2362, // Sudan
- 2368, // Suriname
- 2377, // Svalbard And Jan Mayen
- 2400, // Sweden
- 2407, // Switzerland
- 2419, // Syria
- 2425, // Taiwan
- 2432, // Tajikistan
- 2443, // Tanzania
- 2452, // Thailand
- 2461, // Timor-Leste
- 2473, // Togo
- 2478, // Tokelau
- 2486, // Tonga
- 2492, // Trinidad And Tobago
- 2512, // Tristan Da Cunha
- 2529, // Tunisia
- 2537, // Turkey
- 2544, // Turkmenistan
- 2557, // Turks And Caicos Islands
- 2582, // Tuvalu
- 2589, // Uganda
- 2596, // Ukraine
- 2604, // United Arab Emirates
- 2625, // United Kingdom
- 2640, // United States Outlying Islands
- 2671, // United States
- 2685, // United States Virgin Islands
- 2714, // Uruguay
- 2722, // Uzbekistan
- 2733, // Vanuatu
- 2741, // Vatican City
- 2754, // Venezuela
- 2764, // Vietnam
- 2772, // Wallis And Futuna
- 2790, // Western Sahara
- 2805, // World
- 2811, // Yemen
- 2817, // Zambia
- 2824, // Zimbabwe
+ 35, // Albania
+ 43, // Algeria
+ 51, // American Samoa
+ 66, // Andorra
+ 74, // Angola
+ 81, // Anguilla
+ 90, // Antarctica
+ 101, // Antigua and Barbuda
+ 119, // Argentina
+ 129, // Armenia
+ 137, // Aruba
+ 143, // Ascension Island
+ 160, // Australia
+ 170, // Austria
+ 178, // Azerbaijan
+ 189, // Bahamas
+ 197, // Bahrain
+ 205, // Bangladesh
+ 216, // Barbados
+ 225, // Belarus
+ 233, // Belgium
+ 241, // Belize
+ 248, // Benin
+ 254, // Bermuda
+ 262, // Bhutan
+ 269, // Bolivia
+ 277, // Bosnia and Herzegovina
+ 298, // Botswana
+ 307, // Bouvet Island
+ 321, // Brazil
+ 328, // British Indian Ocean Territory
+ 359, // British Virgin Islands
+ 382, // Brunei
+ 389, // Bulgaria
+ 398, // Burkina Faso
+ 411, // Burundi
+ 419, // Cambodia
+ 428, // Cameroon
+ 437, // Canada
+ 444, // Canary Islands
+ 459, // Cape Verde
+ 470, // Caribbean Netherlands
+ 492, // Cayman Islands
+ 507, // Central African Republic
+ 532, // Ceuta and Melilla
+ 548, // Chad
+ 553, // Chile
+ 559, // China
+ 565, // Christmas Island
+ 582, // Clipperton Island
+ 600, // Cocos Islands
+ 624, // Colombia
+ 633, // Comoros
+ 641, // Congo - Brazzaville
+ 661, // Congo - Kinshasa
+ 678, // Cook Islands
+ 691, // Costa Rica
+ 702, // Croatia
+ 710, // Cuba
+ 715, // Curacao
+ 724, // Cyprus
+ 731, // Czechia
+ 739, // Denmark
+ 747, // Diego Garcia
+ 760, // Djibouti
+ 769, // Dominica
+ 778, // Dominican Republic
+ 797, // Ecuador
+ 805, // Egypt
+ 811, // El Salvador
+ 823, // Equatorial Guinea
+ 841, // Eritrea
+ 849, // Estonia
+ 857, // Eswatini
+ 866, // Ethiopia
+ 875, // Europe
+ 882, // European Union
+ 897, // Falkland Islands
+ 914, // Faroe Islands
+ 928, // Fiji
+ 933, // Finland
+ 941, // France
+ 948, // French Guiana
+ 962, // French Polynesia
+ 979, // French Southern Territories
+ 1007, // Gabon
+ 1013, // Gambia
+ 1020, // Georgia
+ 1028, // Germany
+ 1036, // Ghana
+ 1042, // Gibraltar
+ 1052, // Greece
+ 1059, // Greenland
+ 1069, // Grenada
+ 1077, // Guadeloupe
+ 1088, // Guam
+ 1093, // Guatemala
+ 1103, // Guernsey
+ 1112, // Guinea-Bissau
+ 1126, // Guinea
+ 1133, // Guyana
+ 1140, // Haiti
+ 1146, // Heard and McDonald Islands
+ 1171, // Honduras
+ 1180, // Hong Kong
+ 1200, // Hungary
+ 1208, // Iceland
+ 1216, // India
+ 1222, // Indonesia
+ 1232, // Iran
+ 1237, // Iraq
+ 1242, // Ireland
+ 1250, // Isle of Man
+ 1262, // Israel
+ 1269, // Italy
+ 1275, // Ivory Coast
+ 1292, // Jamaica
+ 1300, // Japan
+ 1306, // Jersey
+ 1313, // Jordan
+ 1320, // Kazakhstan
+ 1331, // Kenya
+ 1337, // Kiribati
+ 1346, // Kosovo
+ 1353, // Kuwait
+ 1360, // Kyrgyzstan
+ 1371, // Laos
+ 1376, // Latin America
+ 1390, // Latvia
+ 1397, // Lebanon
+ 1405, // Lesotho
+ 1413, // Liberia
+ 1421, // Libya
+ 1427, // Liechtenstein
+ 1441, // Lithuania
+ 1451, // Luxembourg
+ 1462, // Macao
+ 1478, // Macedonia
+ 1494, // Madagascar
+ 1505, // Malawi
+ 1512, // Malaysia
+ 1521, // Maldives
+ 1530, // Mali
+ 1535, // Malta
+ 1541, // Marshall Islands
+ 1558, // Martinique
+ 1569, // Mauritania
+ 1580, // Mauritius
+ 1590, // Mayotte
+ 1598, // Mexico
+ 1605, // Micronesia
+ 1616, // Moldova
+ 1624, // Monaco
+ 1631, // Mongolia
+ 1640, // Montenegro
+ 1651, // Montserrat
+ 1662, // Morocco
+ 1670, // Mozambique
+ 1681, // Myanmar
+ 1697, // Namibia
+ 1705, // Nauru
+ 1711, // Nepal
+ 1717, // Netherlands
+ 1729, // New Caledonia
+ 1743, // New Zealand
+ 1755, // Nicaragua
+ 1765, // Nigeria
+ 1773, // Niger
+ 1779, // Niue
+ 1784, // Norfolk Island
+ 1799, // Northern Mariana Islands
+ 1824, // North Korea
+ 1836, // Norway
+ 1843, // Oman
+ 1848, // Outlying Oceania
+ 1865, // Pakistan
+ 1874, // Palau
+ 1880, // Palestinian Territories
+ 1904, // Panama
+ 1911, // Papua New Guinea
+ 1928, // Paraguay
+ 1937, // Peru
+ 1942, // Philippines
+ 1954, // Pitcairn
+ 1971, // Poland
+ 1978, // Portugal
+ 1987, // Puerto Rico
+ 1999, // Qatar
+ 2005, // Reunion
+ 2014, // Romania
+ 2022, // Russia
+ 2029, // Rwanda
+ 2036, // Saint Barthelemy
+ 2052, // Saint Helena
+ 2063, // Saint Kitts and Nevis
+ 2081, // Saint Lucia
+ 2091, // Saint Martin
+ 2102, // Saint Pierre and Miquelon
+ 2124, // Saint Vincent and Grenadines
+ 2149, // Samoa
+ 2155, // San Marino
+ 2166, // Sao Tome and Principe
+ 2189, // Saudi Arabia
+ 2202, // Senegal
+ 2210, // Serbia
+ 2217, // Seychelles
+ 2228, // Sierra Leone
+ 2241, // Singapore
+ 2251, // Sint Maarten
+ 2264, // Slovakia
+ 2273, // Slovenia
+ 2282, // Solomon Islands
+ 2298, // Somalia
+ 2306, // South Africa
+ 2319, // South Georgia and South Sandwich Islands
+ 2358, // South Korea
+ 2370, // South Sudan
+ 2382, // Spain
+ 2388, // Sri Lanka
+ 2398, // Sudan
+ 2404, // Suriname
+ 2413, // Svalbard and Jan Mayen
+ 2434, // Sweden
+ 2441, // Switzerland
+ 2453, // Syria
+ 2459, // Taiwan
+ 2466, // Tajikistan
+ 2477, // Tanzania
+ 2486, // Thailand
+ 2495, // Timor-Leste
+ 2507, // Togo
+ 2512, // Tokelau
+ 2520, // Tonga
+ 2526, // Trinidad and Tobago
+ 2544, // Tristan da Cunha
+ 2561, // Tunisia
+ 2569, // Turkey
+ 2578, // Turkmenistan
+ 2591, // Turks and Caicos Islands
+ 2614, // Tuvalu
+ 2621, // Uganda
+ 2628, // Ukraine
+ 2636, // United Arab Emirates
+ 2657, // United Kingdom
+ 2672, // United States Outlying Islands
+ 2694, // United States
+ 2708, // United States Virgin Islands
+ 2728, // Uruguay
+ 2736, // Uzbekistan
+ 2747, // Vanuatu
+ 2755, // Vatican City
+ 2768, // Venezuela
+ 2778, // Vietnam
+ 2786, // Wallis and Futuna
+ 2802, // Western Sahara
+ 2817, // world
+ 2823, // Yemen
+ 2829, // Zambia
+ 2836, // Zimbabwe
};
-constexpr std::array<LanguageCodeEntry, 337> languageCodeList {
+constexpr std::array<LanguageCodeEntry, 344> languageCodeList {
LanguageCodeEntry {{}, {'u', 'n', 'd'}, {'u', 'n', 'd'}, {'u', 'n', 'd'}}, // AnyLanguage
LanguageCodeEntry {{}, {'u', 'n', 'd'}, {'u', 'n', 'd'}, {'u', 'n', 'd'}}, // C
LanguageCodeEntry {{'a', 'b'}, {'a', 'b', 'k'}, {'a', 'b', 'k'}, {'a', 'b', 'k'}}, // Abkhazian
@@ -5559,7 +7833,7 @@ constexpr std::array<LanguageCodeEntry, 337> languageCodeList {
LanguageCodeEntry {{'j', 'a'}, {'j', 'p', 'n'}, {'j', 'p', 'n'}, {'j', 'p', 'n'}}, // Japanese
LanguageCodeEntry {{'j', 'v'}, {'j', 'a', 'v'}, {'j', 'a', 'v'}, {'j', 'a', 'v'}}, // Javanese
LanguageCodeEntry {{}, {}, {}, {'k', 'a', 'j'}}, // Jju
- LanguageCodeEntry {{}, {}, {}, {'d', 'y', 'o'}}, // Jola Fonyi
+ LanguageCodeEntry {{}, {}, {}, {'d', 'y', 'o'}}, // Jola-Fonyi
LanguageCodeEntry {{}, {}, {}, {'k', 'e', 'a'}}, // Kabuverdianu
LanguageCodeEntry {{}, {'k', 'a', 'b'}, {'k', 'a', 'b'}, {'k', 'a', 'b'}}, // Kabyle
LanguageCodeEntry {{}, {}, {}, {'k', 'k', 'j'}}, // Kako
@@ -5600,7 +7874,7 @@ constexpr std::array<LanguageCodeEntry, 337> languageCodeList {
LanguageCodeEntry {{}, {'j', 'b', 'o'}, {'j', 'b', 'o'}, {'j', 'b', 'o'}}, // Lojban
LanguageCodeEntry {{}, {'d', 's', 'b'}, {'d', 's', 'b'}, {'d', 's', 'b'}}, // Lower Sorbian
LanguageCodeEntry {{}, {'n', 'd', 's'}, {'n', 'd', 's'}, {'n', 'd', 's'}}, // Low German
- LanguageCodeEntry {{'l', 'u'}, {'l', 'u', 'b'}, {'l', 'u', 'b'}, {'l', 'u', 'b'}}, // Luba Katanga
+ LanguageCodeEntry {{'l', 'u'}, {'l', 'u', 'b'}, {'l', 'u', 'b'}, {'l', 'u', 'b'}}, // Luba-Katanga
LanguageCodeEntry {{}, {'s', 'm', 'j'}, {'s', 'm', 'j'}, {'s', 'm', 'j'}}, // Lule Sami
LanguageCodeEntry {{}, {'l', 'u', 'o'}, {'l', 'u', 'o'}, {'l', 'u', 'o'}}, // Luo
LanguageCodeEntry {{'l', 'b'}, {'l', 't', 'z'}, {'l', 't', 'z'}, {'l', 't', 'z'}}, // Luxembourgish
@@ -5608,7 +7882,7 @@ constexpr std::array<LanguageCodeEntry, 337> languageCodeList {
LanguageCodeEntry {{'m', 'k'}, {'m', 'a', 'c'}, {'m', 'k', 'd'}, {'m', 'k', 'd'}}, // Macedonian
LanguageCodeEntry {{}, {}, {}, {'j', 'm', 'c'}}, // Machame
LanguageCodeEntry {{}, {'m', 'a', 'i'}, {'m', 'a', 'i'}, {'m', 'a', 'i'}}, // Maithili
- LanguageCodeEntry {{}, {}, {}, {'m', 'g', 'h'}}, // Makhuwa Meetto
+ LanguageCodeEntry {{}, {}, {}, {'m', 'g', 'h'}}, // Makhuwa-Meetto
LanguageCodeEntry {{}, {}, {}, {'k', 'd', 'e'}}, // Makonde
LanguageCodeEntry {{'m', 'g'}, {'m', 'l', 'g'}, {'m', 'l', 'g'}, {'m', 'l', 'g'}}, // Malagasy
LanguageCodeEntry {{'m', 'l'}, {'m', 'a', 'l'}, {'m', 'a', 'l'}, {'m', 'a', 'l'}}, // Malayalam
@@ -5773,6 +8047,13 @@ constexpr std::array<LanguageCodeEntry, 337> languageCodeList {
LanguageCodeEntry {{}, {}, {}, {'t', 'o', 'k'}}, // Toki Pona
LanguageCodeEntry {{}, {}, {}, {'p', 'i', 's'}}, // Pijin
LanguageCodeEntry {{}, {}, {}, {'a', 'n', 'n'}}, // Obolo
+ LanguageCodeEntry {{}, {'b', 'a', 'l'}, {'b', 'a', 'l'}, {'b', 'a', 'l'}}, // Baluchi
+ LanguageCodeEntry {{}, {}, {}, {'l', 'i', 'j'}}, // Ligurian
+ LanguageCodeEntry {{}, {}, {}, {'r', 'h', 'g'}}, // Rohingya
+ LanguageCodeEntry {{}, {}, {}, {'t', 'r', 'w'}}, // Torwali
+ LanguageCodeEntry {{}, {}, {}, {'b', 'l', 'o'}}, // Anii
+ LanguageCodeEntry {{}, {}, {}, {'x', 'n', 'r'}}, // Kangri
+ LanguageCodeEntry {{}, {}, {}, {'v', 'e', 'c'}}, // Venetian
};
static constexpr unsigned char script_code_list[] =
@@ -5807,7 +8088,7 @@ static constexpr unsigned char script_code_list[] =
"Dsrt" // Deseret
"Deva" // Devanagari
"Dupl" // Duployan
-"Egyp" // Egyptian Hieroglyphs
+"Egyp" // Egyptian hieroglyphs
"Elba" // Elbasan
"Ethi" // Ethiopic
"Lisu" // Fraser
@@ -5882,7 +8163,7 @@ static constexpr unsigned char script_code_list[] =
"Hmng" // Pahawh Hmong
"Palm" // Palmyrene
"Pauc" // Pau Cin Hau
-"Phag" // Phags Pa
+"Phag" // Phags-pa
"Phnx" // Phoenician
"Plrd" // Pollard Phonetic
"Phlp" // Psalter Pahlavi
@@ -5893,7 +8174,7 @@ static constexpr unsigned char script_code_list[] =
"Shrd" // Sharada
"Shaw" // Shavian
"Sidd" // Siddham
-"Sgnw" // Sign Writing
+"Sgnw" // SignWriting
"Hans" // Simplified Han
"Sinh" // Sinhala
"Sora" // Sora Sompeng
@@ -5918,6 +8199,7 @@ static constexpr unsigned char script_code_list[] =
"Vaii" // Vai
"Wara" // Varang Kshiti
"Yiii" // Yi
+"Rohg" // Hanifi
;
static constexpr unsigned char territory_code_list[] =
@@ -5931,7 +8213,7 @@ static constexpr unsigned char territory_code_list[] =
"AO\0" // Angola
"AI\0" // Anguilla
"AQ\0" // Antarctica
-"AG\0" // Antigua And Barbuda
+"AG\0" // Antigua and Barbuda
"AR\0" // Argentina
"AM\0" // Armenia
"AW\0" // Aruba
@@ -5950,7 +8232,7 @@ static constexpr unsigned char territory_code_list[] =
"BM\0" // Bermuda
"BT\0" // Bhutan
"BO\0" // Bolivia
-"BA\0" // Bosnia And Herzegovina
+"BA\0" // Bosnia and Herzegovina
"BW\0" // Botswana
"BV\0" // Bouvet Island
"BR\0" // Brazil
@@ -5968,7 +8250,7 @@ static constexpr unsigned char territory_code_list[] =
"BQ\0" // Caribbean Netherlands
"KY\0" // Cayman Islands
"CF\0" // Central African Republic
-"EA\0" // Ceuta And Melilla
+"EA\0" // Ceuta and Melilla
"TD\0" // Chad
"CL\0" // Chile
"CN\0" // China
@@ -5977,8 +8259,8 @@ static constexpr unsigned char territory_code_list[] =
"CC\0" // Cocos Islands
"CO\0" // Colombia
"KM\0" // Comoros
-"CG\0" // Congo Brazzaville
-"CD\0" // Congo Kinshasa
+"CG\0" // Congo - Brazzaville
+"CD\0" // Congo - Kinshasa
"CK\0" // Cook Islands
"CR\0" // Costa Rica
"HR\0" // Croatia
@@ -6022,11 +8304,11 @@ static constexpr unsigned char territory_code_list[] =
"GU\0" // Guam
"GT\0" // Guatemala
"GG\0" // Guernsey
-"GW\0" // Guinea Bissau
+"GW\0" // Guinea-Bissau
"GN\0" // Guinea
"GY\0" // Guyana
"HT\0" // Haiti
-"HM\0" // Heard And McDonald Islands
+"HM\0" // Heard and McDonald Islands
"HN\0" // Honduras
"HK\0" // Hong Kong
"HU\0" // Hungary
@@ -6036,7 +8318,7 @@ static constexpr unsigned char territory_code_list[] =
"IR\0" // Iran
"IQ\0" // Iraq
"IE\0" // Ireland
-"IM\0" // Isle Of Man
+"IM\0" // Isle of Man
"IL\0" // Israel
"IT\0" // Italy
"CI\0" // Ivory Coast
@@ -6118,14 +8400,14 @@ static constexpr unsigned char territory_code_list[] =
"RW\0" // Rwanda
"BL\0" // Saint Barthelemy
"SH\0" // Saint Helena
-"KN\0" // Saint Kitts And Nevis
+"KN\0" // Saint Kitts and Nevis
"LC\0" // Saint Lucia
"MF\0" // Saint Martin
-"PM\0" // Saint Pierre And Miquelon
-"VC\0" // Saint Vincent And Grenadines
+"PM\0" // Saint Pierre and Miquelon
+"VC\0" // Saint Vincent and Grenadines
"WS\0" // Samoa
"SM\0" // San Marino
-"ST\0" // Sao Tome And Principe
+"ST\0" // Sao Tome and Principe
"SA\0" // Saudi Arabia
"SN\0" // Senegal
"RS\0" // Serbia
@@ -6138,14 +8420,14 @@ static constexpr unsigned char territory_code_list[] =
"SB\0" // Solomon Islands
"SO\0" // Somalia
"ZA\0" // South Africa
-"GS\0" // South Georgia And South Sandwich Islands
+"GS\0" // South Georgia and South Sandwich Islands
"KR\0" // South Korea
"SS\0" // South Sudan
"ES\0" // Spain
"LK\0" // Sri Lanka
"SD\0" // Sudan
"SR\0" // Suriname
-"SJ\0" // Svalbard And Jan Mayen
+"SJ\0" // Svalbard and Jan Mayen
"SE\0" // Sweden
"CH\0" // Switzerland
"SY\0" // Syria
@@ -6157,12 +8439,12 @@ static constexpr unsigned char territory_code_list[] =
"TG\0" // Togo
"TK\0" // Tokelau
"TO\0" // Tonga
-"TT\0" // Trinidad And Tobago
-"TA\0" // Tristan Da Cunha
+"TT\0" // Trinidad and Tobago
+"TA\0" // Tristan da Cunha
"TN\0" // Tunisia
"TR\0" // Turkey
"TM\0" // Turkmenistan
-"TC\0" // Turks And Caicos Islands
+"TC\0" // Turks and Caicos Islands
"TV\0" // Tuvalu
"UG\0" // Uganda
"UA\0" // Ukraine
@@ -6177,9 +8459,9 @@ static constexpr unsigned char territory_code_list[] =
"VA\0" // Vatican City
"VE\0" // Venezuela
"VN\0" // Vietnam
-"WF\0" // Wallis And Futuna
+"WF\0" // Wallis and Futuna
"EH\0" // Western Sahara
-"001" // World
+"001" // world
"YE\0" // Yemen
"ZM\0" // Zambia
"ZW\0" // Zimbabwe
diff --git a/src/corelib/text/qlocale_mac.mm b/src/corelib/text/qlocale_mac.mm
index f3ca942845..89339be2eb 100644
--- a/src/corelib/text/qlocale_mac.mm
+++ b/src/corelib/text/qlocale_mac.mm
@@ -14,6 +14,9 @@
#include <CoreFoundation/CoreFoundation.h>
#endif
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qcoreapplication.h>
+
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
@@ -22,6 +25,41 @@ using namespace Qt::StringLiterals;
** Wrappers for Mac locale system functions
*/
+Q_LOGGING_CATEGORY(lcLocale, "qt.core.locale")
+
+static void printLocalizationInformation()
+{
+ if (!lcLocale().isDebugEnabled())
+ return;
+
+#if defined(Q_OS_MACOS)
+ // Trigger initialization of standard user defaults, so that Foundation picks
+ // up -AppleLanguages and -AppleLocale passed on the command line.
+ Q_UNUSED(NSUserDefaults.standardUserDefaults);
+#endif
+
+ auto singleLineDescription = [](NSArray *array) {
+ NSString *str = [array description];
+ str = [str stringByReplacingOccurrencesOfString:@"\n" withString:@""];
+ return [str stringByReplacingOccurrencesOfString:@" " withString:@""];
+ };
+
+ bool allowMixedLocalizations = [NSBundle.mainBundle.infoDictionary[@"CFBundleAllowMixedLocalizations"] boolValue];
+
+ NSBundle *foundation = [NSBundle bundleForClass:NSBundle.class];
+ qCDebug(lcLocale).nospace() << "Launched with locale \"" << NSLocale.currentLocale.localeIdentifier
+ << "\" based on user's preferred languages " << singleLineDescription(NSLocale.preferredLanguages)
+ << ", main bundle localizations " << singleLineDescription(NSBundle.mainBundle.localizations)
+ << ", and allowing mixed localizations " << allowMixedLocalizations
+ << "; resulting in main bundle preferred localizations "
+ << singleLineDescription(NSBundle.mainBundle.preferredLocalizations)
+ << " and Foundation preferred localizations "
+ << singleLineDescription(foundation.preferredLocalizations);
+ qCDebug(lcLocale) << "Reflected by Qt as system locale"
+ << QLocale::system() << "with UI languges " << QLocale::system().uiLanguages();
+}
+Q_COREAPP_STARTUP_FUNCTION(printLocalizationInformation);
+
static QString getMacLocaleName()
{
QCFType<CFLocaleRef> l = CFLocaleCopyCurrent();
@@ -118,14 +156,26 @@ static QVariant macDayName(int day, QSystemLocale::QueryType type)
static QString macZeroDigit()
{
- QCFType<CFLocaleRef> locale = CFLocaleCopyCurrent();
- QCFType<CFNumberFormatterRef> numberFormatter =
- CFNumberFormatterCreate(nullptr, locale, kCFNumberFormatterNoStyle);
- const int zeroDigit = 0;
- QCFType<CFStringRef> value
- = CFNumberFormatterCreateStringWithValue(nullptr, numberFormatter,
- kCFNumberIntType, &zeroDigit);
- return QString::fromCFString(value);
+ static QString cachedZeroDigit;
+
+ if (cachedZeroDigit.isNull()) {
+ QCFType<CFLocaleRef> locale = CFLocaleCopyCurrent();
+ QCFType<CFNumberFormatterRef> numberFormatter =
+ CFNumberFormatterCreate(nullptr, locale, kCFNumberFormatterNoStyle);
+ const int zeroDigit = 0;
+ QCFType<CFStringRef> value
+ = CFNumberFormatterCreateStringWithValue(nullptr, numberFormatter,
+ kCFNumberIntType, &zeroDigit);
+ cachedZeroDigit = QString::fromCFString(value);
+ }
+
+ static QMacNotificationObserver localeChangeObserver = QMacNotificationObserver(
+ nil, NSCurrentLocaleDidChangeNotification, [&] {
+ qCDebug(lcLocale) << "System locale changed";
+ cachedZeroDigit = QString();
+ });
+
+ return cachedZeroDigit;
}
static QString zeroPad(QString &&number, qsizetype minDigits, const QString &zero)
@@ -188,12 +238,16 @@ static QString fourDigitYear(int year, const QString &zero)
static QString macDateToStringImpl(QDate date, CFDateFormatterStyle style)
{
- QCFType<CFDateRef> myDate = date.startOfDay().toCFDate();
+ // Use noon on the given date, to avoid complications that can arise for
+ // dates before 1900 (see QTBUG-54955) using different UTC offset than
+ // QDateTime extrapolates backwards from time_t functions that only work
+ // back to 1900. (Alaska and Phillipines may still be borked, though.)
+ QCFType<CFDateRef> myDate = QDateTime(date, QTime(12, 0)).toCFDate();
QCFType<CFLocaleRef> mylocale = CFLocaleCopyCurrent();
QCFType<CFDateFormatterRef> myFormatter
= CFDateFormatterCreate(kCFAllocatorDefault, mylocale, style,
kCFDateFormatterNoStyle);
- QCFType<CFStringRef> text = CFDateFormatterCreateStringWithDate(0, myFormatter, myDate);
+ QCFType<CFStringRef> text = CFDateFormatterCreateStringWithDate(nullptr, myFormatter, myDate);
return QString::fromCFString(text);
}
@@ -201,12 +255,14 @@ static QVariant macDateToString(QDate date, bool short_format)
{
const int year = date.year();
QString fakeYear, trueYear;
- if (year < 0) {
+ if (year < 1583) {
// System API (in macOS 11.0, at least) discards sign :-(
// Simply negating the year won't do as the resulting year typically has
// a different pattern of week-days.
+ // Furthermore (see QTBUG-54955), Darwin uses the Julian calendar for
+ // dates before 1582-10-15, leading to discrepancies.
int matcher = QGregorianCalendar::yearSharingWeekDays(date);
- Q_ASSERT(matcher > 0);
+ Q_ASSERT(matcher >= 1583);
Q_ASSERT(matcher % 100 != date.month());
Q_ASSERT(matcher % 100 != date.day());
// i.e. there can't be any confusion between the two-digit year and
@@ -219,7 +275,7 @@ static QVariant macDateToString(QDate date, bool short_format)
QString text = macDateToStringImpl(date, short_format
? kCFDateFormatterShortStyle
: kCFDateFormatterLongStyle);
- if (year < 0) {
+ if (year < 1583) {
if (text.contains(fakeYear))
return std::move(text).replace(fakeYear, trueYear);
// Cope with two-digit year:
@@ -267,99 +323,107 @@ static QVariant macToQtFormat(QStringView sys_fmt)
}
QChar c = sys_fmt.at(i);
- qsizetype repeat = qt_repeatCount(sys_fmt.mid(i));
+ qsizetype repeat = qt_repeatCount(sys_fmt.sliced(i));
switch (c.unicode()) {
// Qt does not support the following options
- case 'G': // Era (1..5): 4 = long, 1..3 = short, 5 = narrow
- case 'Y': // Year of Week (1..n): 1..n = padded number
- case 'U': // Cyclic Year Name (1..5): 4 = long, 1..3 = short, 5 = narrow
- case 'Q': // Quarter (1..4): 4 = long, 3 = short, 1..2 = padded number
- case 'q': // Standalone Quarter (1..4): 4 = long, 3 = short, 1..2 = padded number
- case 'w': // Week of Year (1..2): 1..2 = padded number
- case 'W': // Week of Month (1): 1 = number
- case 'D': // Day of Year (1..3): 1..3 = padded number
- case 'F': // Day of Week in Month (1): 1 = number
- case 'g': // Modified Julian Day (1..n): 1..n = padded number
- case 'A': // Milliseconds in Day (1..n): 1..n = padded number
- break;
-
- case 'y': // Year (1..n): 2 = short year, 1 & 3..n = padded number
- case 'u': // Extended Year (1..n): 2 = short year, 1 & 3..n = padded number
- // Qt only supports long (4) or short (2) year, use long for all others
- if (repeat == 2)
- result += "yy"_L1;
- else
- result += "yyyy"_L1;
- break;
- case 'M': // Month (1..5): 4 = long, 3 = short, 1..2 = number, 5 = narrow
- case 'L': // Standalone Month (1..5): 4 = long, 3 = short, 1..2 = number, 5 = narrow
- // Qt only supports long, short and number, use short for narrow
- if (repeat == 5)
- result += "MMM"_L1;
- else
- result += QString(repeat, u'M');
- break;
- case 'd': // Day of Month (1..2): 1..2 padded number
- result += QString(repeat, c);
- break;
- case 'E': // Day of Week (1..6): 4 = long, 1..3 = short, 5..6 = narrow
- // Qt only supports long, short and padded number, use short for narrow
- if (repeat == 4)
- result += "dddd"_L1;
- else
- result += "ddd"_L1;
- break;
- case 'e': // Local Day of Week (1..6): 4 = long, 3 = short, 5..6 = narrow, 1..2 padded number
- case 'c': // Standalone Local Day of Week (1..6): 4 = long, 3 = short, 5..6 = narrow, 1..2 padded number
- // Qt only supports long, short and padded number, use short for narrow
- if (repeat >= 5)
- result += "ddd"_L1;
- else
- result += QString(repeat, 'd'_L1);
- break;
- case 'a': // AM/PM (1): 1 = short
- // Translate to Qt uppercase AM/PM
- result += "AP"_L1;
- break;
- case 'h': // Hour [1..12] (1..2): 1..2 = padded number
- case 'K': // Hour [0..11] (1..2): 1..2 = padded number
- case 'j': // Local Hour [12 or 24] (1..2): 1..2 = padded number
- // Qt h is local hour
- result += QString(repeat, 'h'_L1);
- break;
- case 'H': // Hour [0..23] (1..2): 1..2 = padded number
- case 'k': // Hour [1..24] (1..2): 1..2 = padded number
- // Qt H is 0..23 hour
- result += QString(repeat, 'H'_L1);
- break;
- case 'm': // Minutes (1..2): 1..2 = padded number
- case 's': // Seconds (1..2): 1..2 = padded number
+ case 'A': // Milliseconds in Day (1..n): 1..n = padded number
+ case 'C': // Input skeleton symbol.
+ case 'D': // Day of Year (1..3): 1..3 = padded number
+ case 'F': // Day of Week in Month (1): 1 = number
+ case 'g': // Modified Julian Day (1..n): 1..n = padded number
+ case 'G': // Era (1..5): 4 = long, 1..3 = short, 5 = narrow
+ case 'j': // Input skeleton symbol.
+ case 'J': // Input skeleton symbol.
+ case 'l': // Deprecated Chinese leap month indicator.
+ case 'q': // Standalone Quarter (1..4): 4 = long, 3 = short, 1,2 = padded number
+ case 'Q': // Quarter (1..4): 4 = long, 3 = short, 1,2 = padded number
+ case 'U': // Cyclic Year Name (1..5): 4 = long, 1..3 = short, 5 = narrow
+ case 'w': // Week of Year (1,2): 1,2 = padded number
+ case 'W': // Week of Month (1): 1 = number
+ case 'Y': // Year for Week-of-year calendars (1..n): 1..n = padded number
+ break;
+
+ case 'u': // Extended Year (1..n), padded number.
+ // Explicitly has no special case for 'uu' as only the last two digits.
+ result += "yyyy"_L1;
+ break;
+ case 'y': // Year (1..n): 2 = short year, 1 & 3..n = padded number
+ // Qt only supports long (4) or short (2) year, use long for all others
+ if (repeat == 2)
+ result += "yy"_L1;
+ else
+ result += "yyyy"_L1;
+ break;
+ case 'L': // Standalone Month (1..5): 4 = long, 3 = short, 1,2 = number, 5 = narrow
+ case 'M': // Month (1..5): 4 = long, 3 = short, 1,2 = number, 5 = narrow
+ // Qt only supports long, short and number, use short for narrow
+ if (repeat == 5)
+ result += "MMM"_L1;
+ else
+ result += QString(repeat, u'M');
+ break;
+ case 'd': // Day of Month (1,2): 1,2 padded number
+ result += QString(repeat, c);
+ break;
+ case 'c': // Standalone version of 'e'
+ case 'e': // Local Day of Week (1..6): 4 = long, 3 = short, 5,6 = narrow, 1,2 padded number
+ // "Local" only affects numeric form: depends on locale's start-day of the week.
+ case 'E': // Day of Week (1..6): 4 = long, 1..3 = short, 5,6 = narrow
+ // Qt only supports long, short: use short for narrow and padded number.
+ if (repeat == 4)
+ result += "dddd"_L1;
+ else
+ result += "ddd"_L1;
+ break;
+ case 'a': // AM/PM (1..n): Qt supports no distinctions
+ case 'b': // Like a, but also distinguishing noon, midnight (ignore difference).
+ case 'B': // Flexible day period (at night, &c.)
+ // Translate to Qt AM/PM, using locale-appropriate case:
+ result += "Ap"_L1;
+ break;
+ case 'h': // Hour [1..12] (1,2): 1,2 = padded number
+ case 'K': // Hour [0..11] (1,2): 1,2 = padded number
+ result += QString(repeat, 'h'_L1);
+ break;
+ case 'H': // Hour [0..23] (1,2): 1,2 = padded number
+ case 'k': // Hour [1..24] (1,2): 1,2 = padded number
+ // Qt H is 0..23 hour
+ result += QString(repeat, 'H'_L1);
+ break;
+ case 'm': // Minutes (1,2): 1,2 = padded number
+ case 's': // Seconds (1,2): 1,2 = padded number
+ result += QString(repeat, c);
+ break;
+ case 'S': // Fractional second (1..n): 1..n = truncates to decimal places
+ // Qt uses msecs either unpadded or padded to 3 places
+ if (repeat < 3)
+ result += u'z';
+ else
+ result += "zzz"_L1;
+ break;
+ case 'O': // Time Zone (1, 4)
+ result += u't';
+ break;
+ case 'v': // Time Zone (1, 4)
+ case 'V': // Time Zone (1..4)
+ result += "tttt"_L1;
+ break;
+ case 'x': // Time Zone (1..5)
+ case 'X': // Time Zone (1..5)
+ result += (repeat > 1 && (repeat & 1)) ? "ttt"_L1 : "tt"_L1;
+ break;
+ case 'z': // Time Zone (1..4)
+ case 'Z': // Time Zone (1..5)
+ result += repeat < 4 ? "tt"_L1 : repeat > 4 ? "ttt"_L1 : "t"_L1;
+ break;
+ default:
+ // a..z and A..Z are reserved for format codes, so any occurrence of these not
+ // already processed are not known and so unsupported formats to be ignored.
+ // All other chars are allowed as literals.
+ if (c < u'A' || c > u'z' || (c > u'Z' && c < u'a'))
result += QString(repeat, c);
- break;
- case 'S': // Fractional second (1..n): 1..n = truncates to decimal places
- // Qt uses msecs either unpadded or padded to 3 places
- if (repeat < 3)
- result += u'z';
- else
- result += "zzz"_L1;
- break;
- case 'z': // Time Zone (1..4)
- case 'Z': // Time Zone (1..5)
- case 'O': // Time Zone (1, 4)
- case 'v': // Time Zone (1, 4)
- case 'V': // Time Zone (1..4)
- case 'X': // Time Zone (1..5)
- case 'x': // Time Zone (1..5)
- result += u't';
- break;
- default:
- // a..z and A..Z are reserved for format codes, so any occurrence of these not
- // already processed are not known and so unsupported formats to be ignored.
- // All other chars are allowed as literals.
- if (c < u'A' || c > u'z' || (c > u'Z' && c < u'a'))
- result += QString(repeat, c);
- break;
+ break;
}
i += repeat;
@@ -517,7 +581,7 @@ static QLocale::Language codeToLanguage(QStringView s)
return QLocalePrivate::codeToLanguage(s);
}
-QVariant QSystemLocale::query(QueryType type, QVariant in) const
+QVariant QSystemLocale::query(QueryType type, QVariant &&in) const
{
QMacAutoReleasePool pool;
@@ -585,7 +649,7 @@ QVariant QSystemLocale::query(QueryType type, QVariant in) const
case CurrencySymbol:
return macCurrencySymbol(QLocale::CurrencySymbolFormat(in.toUInt()));
case CurrencyToString:
- return macFormatCurrency(in.value<QSystemLocale::CurrencyToStringArgument>());
+ return macFormatCurrency(in.value<CurrencyToStringArgument>());
case UILanguages: {
QStringList result;
QCFType<CFArrayRef> languages = CFLocaleCopyPreferredLanguages();
diff --git a/src/corelib/text/qlocale_p.h b/src/corelib/text/qlocale_p.h
index 649f75fbeb..3044d137b9 100644
--- a/src/corelib/text/qlocale_p.h
+++ b/src/corelib/text/qlocale_p.h
@@ -18,13 +18,16 @@
#include "qlocale.h"
-#include <QtCore/private/qglobal_p.h>
#include <QtCore/qcalendar.h>
#include <QtCore/qlist.h>
#include <QtCore/qnumeric.h>
+#include <QtCore/private/qnumeric_p.h>
#include <QtCore/qstring.h>
#include <QtCore/qvariant.h>
#include <QtCore/qvarlengtharray.h>
+#ifdef Q_OS_WASM
+#include <private/qstdweb_p.h>
+#endif
#include <limits>
#include <cmath>
@@ -32,6 +35,14 @@
QT_BEGIN_NAMESPACE
+template <typename T> struct QSimpleParsedNumber
+{
+ T result;
+ // When used < 0, -used is how much was used, but it was an error.
+ qsizetype used;
+ bool ok() const { return used > 0; }
+};
+
template <typename MaskType, uchar Lowest> struct QCharacterSetMatch
{
static constexpr int MaxRange = std::numeric_limits<MaskType>::digits;
@@ -94,7 +105,9 @@ struct QLocaleData;
// Subclassed by Android platform plugin:
class Q_CORE_EXPORT QSystemLocale
{
+ Q_DISABLE_COPY_MOVE(QSystemLocale)
QSystemLocale *next = nullptr; // Maintains a stack.
+
public:
QSystemLocale();
virtual ~QSystemLocale();
@@ -157,7 +170,7 @@ public:
StandaloneDayNameShort, // QString, in: int
StandaloneDayNameNarrow // QString, in: int
};
- virtual QVariant query(QueryType type, QVariant in = QVariant()) const;
+ virtual QVariant query(QueryType type, QVariant &&in = QVariant()) const;
virtual QLocale fallbackLocale() const;
inline qsizetype fallbackLocaleIndex() const;
@@ -214,6 +227,18 @@ Q_DECLARE_TYPEINFO(QLocaleId, Q_PRIMITIVE_TYPE);
using CharBuff = QVarLengthArray<char, 256>;
+struct ParsingResult
+{
+ enum State { // A duplicate of QValidator::State
+ Invalid,
+ Intermediate,
+ Acceptable
+ };
+
+ State state = Invalid;
+ CharBuff buff;
+};
+
struct QLocaleData
{
public:
@@ -280,36 +305,28 @@ public:
unsigned flags = NoFlags) const;
// this function is meant to be called with the result of stringToDouble or bytearrayToDouble
+ // so *ok must have been properly set (if not null)
[[nodiscard]] static float convertDoubleToFloat(double d, bool *ok)
{
- if (qIsInf(d))
- return float(d);
- if (std::fabs(d) > (std::numeric_limits<float>::max)()) {
- if (ok)
- *ok = false;
- const float huge = std::numeric_limits<float>::infinity();
- return d < 0 ? -huge : huge;
- }
- if (d != 0 && float(d) == 0) {
- // Values that underflow double already failed. Match them:
- if (ok)
- *ok = false;
- return 0;
- }
- return float(d);
+ float result;
+ bool b = convertDoubleTo<float>(d, &result);
+ if (ok && *ok)
+ *ok = b;
+ return result;
}
[[nodiscard]] double stringToDouble(QStringView str, bool *ok,
QLocale::NumberOptions options) const;
- [[nodiscard]] qint64 stringToLongLong(QStringView str, int base, bool *ok,
- QLocale::NumberOptions options) const;
- [[nodiscard]] quint64 stringToUnsLongLong(QStringView str, int base, bool *ok,
- QLocale::NumberOptions options) const;
+ [[nodiscard]] QSimpleParsedNumber<qint64>
+ stringToLongLong(QStringView str, int base, QLocale::NumberOptions options) const;
+ [[nodiscard]] QSimpleParsedNumber<quint64>
+ stringToUnsLongLong(QStringView str, int base, QLocale::NumberOptions options) const;
// this function is used in QIntValidator (QtGui)
- [[nodiscard]] Q_CORE_EXPORT static qint64 bytearrayToLongLong(QByteArrayView num, int base,
- bool *ok);
- [[nodiscard]] static quint64 bytearrayToUnsLongLong(QByteArrayView num, int base, bool *ok);
+ [[nodiscard]] Q_CORE_EXPORT
+ static QSimpleParsedNumber<qint64> bytearrayToLongLong(QByteArrayView num, int base);
+ [[nodiscard]] static QSimpleParsedNumber<quint64>
+ bytearrayToUnsLongLong(QByteArrayView num, int base);
[[nodiscard]] bool numberToCLocale(QStringView s, QLocale::NumberOptions number_options,
NumberMode mode, CharBuff *result) const;
@@ -361,9 +378,9 @@ public:
[[nodiscard]] inline NumericData numericData(NumberMode mode) const;
// this function is used in QIntValidator (QtGui)
- [[nodiscard]] Q_CORE_EXPORT bool validateChars(
- QStringView str, NumberMode numMode, QByteArray *buff, int decDigits = -1,
- QLocale::NumberOptions number_options = QLocale::DefaultNumberOptions) const;
+ [[nodiscard]] Q_CORE_EXPORT ParsingResult
+ validateChars(QStringView str, NumberMode numMode, int decDigits = -1,
+ QLocale::NumberOptions number_options = QLocale::DefaultNumberOptions) const;
// Access to assorted data members:
[[nodiscard]] QLocaleId id() const
@@ -465,7 +482,7 @@ public:
quint8 m_first_day_of_week : 3;
quint8 m_weekend_start : 3;
quint8 m_weekend_end : 3;
- quint8 m_grouping_top : 2; // Must have this many before the first grouping separator
+ quint8 m_grouping_top : 2; // Don't group until more significant group has this many digits.
quint8 m_grouping_higher : 3; // Number of digits between grouping separators
quint8 m_grouping_least : 3; // Number of digits after last grouping separator (before decimal).
};
@@ -511,7 +528,7 @@ public:
// System locale has an m_data all its own; all others have m_data = locale_data + m_index
const QLocaleData *const m_data;
QBasicAtomicInt ref;
- const qsizetype m_index;
+ qsizetype m_index; // System locale needs this updated when m_data->id() changes.
QLocale::NumberOptions m_numberOptions;
static QBasicAtomicInt s_generation;
diff --git a/src/corelib/text/qlocale_tools.cpp b/src/corelib/text/qlocale_tools.cpp
index 0402203c27..b6639bcb71 100644
--- a/src/corelib/text/qlocale_tools.cpp
+++ b/src/corelib/text/qlocale_tools.cpp
@@ -310,8 +310,8 @@ QSimpleParsedNumber<double> qt_asciiToDouble(const char *num, qsizetype numLen,
d = conv.StringToDouble(num, int(numLen), &processed);
}
- if (!qIsFinite(d)) {
- if (qIsNaN(d)) {
+ if (!qt_is_finite(d)) {
+ if (qt_is_nan(d)) {
// Garbage found. We don't accept it and return 0.
return {};
} else {
@@ -329,12 +329,12 @@ QSimpleParsedNumber<double> qt_asciiToDouble(const char *num, qsizetype numLen,
if (qDoubleSscanf(num, QT_CLOCALE, fmt, &d, &processed) < 1)
processed = 0;
- if ((strayCharMode == TrailingJunkProhibited && processed != numLen) || qIsNaN(d)) {
+ if ((strayCharMode == TrailingJunkProhibited && processed != numLen) || qt_is_nan(d)) {
// Implementation defined nan symbol or garbage found. We don't accept it.
return {};
}
- if (!qIsFinite(d)) {
+ if (!qt_is_finite(d)) {
// Overflow. Check for implementation-defined infinity symbols and reject them.
// We assume that any infinity symbol has to contain a character that cannot be part of a
// "normal" number (that is 0-9, ., -, +, e).
@@ -651,7 +651,7 @@ static T dtoString(double d, QLocaleData::DoubleForm form, int precision, bool u
int bufSize = 1;
if (precision == QLocale::FloatingPointShortest)
bufSize += D::max_digits10;
- else if (form == QLocaleData::DFDecimal && qIsFinite(d))
+ else if (form == QLocaleData::DFDecimal && qt_is_finite(d))
bufSize += wholePartSpace(qAbs(d)) + precision;
else // Add extra digit due to different interpretations of precision.
bufSize += qMax(2, precision) + 1; // Must also be big enough for "nan" or "inf"
@@ -666,7 +666,7 @@ static T dtoString(double d, QLocaleData::DoubleForm form, int precision, bool u
QLatin1StringView view(buffer.data(), length);
const bool succinct = form == QLocaleData::DFSignificantDigits;
qsizetype total = (negative ? 1 : 0) + length;
- if (qIsFinite(d)) {
+ if (qt_is_finite(d)) {
if (succinct)
form = resolveFormat(precision, decpt, view.size());
@@ -708,7 +708,7 @@ static T dtoString(double d, QLocaleData::DoubleForm form, int precision, bool u
if (negative && !isZero(d)) // We don't return "-0"
result.append(Char('-'));
- if (!qIsFinite(d)) {
+ if (!qt_is_finite(d)) {
result.append(view);
if (uppercase)
result = std::move(result).toUpper();
@@ -729,7 +729,7 @@ static T dtoString(double d, QLocaleData::DoubleForm form, int precision, bool u
result.append(Char(uppercase ? 'E' : 'e'));
result.append(Char(exponent < 0 ? '-' : '+'));
exponent = std::abs(exponent);
- Q_ASSUME(exponent <= D::max_exponent10 + D::max_digits10);
+ Q_ASSERT(exponent <= D::max_exponent10 + D::max_digits10);
int exponentDigits = digits(exponent);
// C's printf guarantees a two-digit exponent, and so do we:
if (exponentDigits == 1)
diff --git a/src/corelib/text/qlocale_tools_p.h b/src/corelib/text/qlocale_tools_p.h
index 3e1d441f93..9b02403ea4 100644
--- a/src/corelib/text/qlocale_tools_p.h
+++ b/src/corelib/text/qlocale_tools_p.h
@@ -26,14 +26,6 @@ enum StrayCharacterMode {
WhitespacesAllowed
};
-template <typename T> struct QSimpleParsedNumber
-{
- T result;
- // When used < 0, -used is how much was used, but it was an error.
- qsizetype used;
- bool ok() const { return used > 0; }
-};
-
// API note: this function can't process a number with more than 2.1 billion digits
[[nodiscard]] QSimpleParsedNumber<double>
qt_asciiToDouble(const char *num, qsizetype numLen,
@@ -90,7 +82,8 @@ template <typename UcsInt>
return qstrntod(s00, len, se, ok);
}
-[[nodiscard]] QSimpleParsedNumber<qlonglong> qstrntoll(const char *nptr, qsizetype size, int base);
+[[nodiscard]] Q_AUTOTEST_EXPORT
+QSimpleParsedNumber<qlonglong> qstrntoll(const char *nptr, qsizetype size, int base);
[[nodiscard]] QSimpleParsedNumber<qulonglong> qstrntoull(const char *nptr, qsizetype size, int base);
QT_END_NAMESPACE
diff --git a/src/corelib/text/qlocale_unix.cpp b/src/corelib/text/qlocale_unix.cpp
index 6f6884d366..a934f24c01 100644
--- a/src/corelib/text/qlocale_unix.cpp
+++ b/src/corelib/text/qlocale_unix.cpp
@@ -124,7 +124,7 @@ QLocale QSystemLocale::fallbackLocale() const
return QLocale(lang);
}
-QVariant QSystemLocale::query(QueryType type, QVariant in) const
+QVariant QSystemLocale::query(QueryType type, QVariant &&in) const
{
QSystemLocaleData *d = qSystemLocaleData();
@@ -258,13 +258,15 @@ QVariant QSystemLocale::query(QueryType type, QVariant in) const
return d->uiLanguages.isEmpty() ? QVariant() : QVariant(d->uiLanguages);
}
case StringToStandardQuotation:
- return lc_messages.quoteString(qvariant_cast<QStringView>(in));
+ return lc_messages.quoteString(qvariant_cast<QStringView>(std::move(in)));
case StringToAlternateQuotation:
- return lc_messages.quoteString(qvariant_cast<QStringView>(in), QLocale::AlternateQuotation);
+ return lc_messages.quoteString(qvariant_cast<QStringView>(std::move(in)),
+ QLocale::AlternateQuotation);
case ListToSeparatedString:
return lc_messages.createSeparatedList(in.toStringList());
case LocaleChanged:
Q_ASSERT(false);
+ [[fallthrough]];
default:
break;
}
diff --git a/src/corelib/text/qlocale_wasm.cpp b/src/corelib/text/qlocale_wasm.cpp
new file mode 100644
index 0000000000..6b011af4a7
--- /dev/null
+++ b/src/corelib/text/qlocale_wasm.cpp
@@ -0,0 +1,54 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qlocale_p.h"
+
+#include <emscripten/val.h>
+
+#include <string>
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_SYSTEMLOCALE
+
+namespace {
+
+QStringList navigatorLanguages()
+{
+ using emscripten::val;
+ const val navigator = val::global("navigator");
+ const auto languages = emscripten::vecFromJSArray<std::string>(navigator["languages"]);
+ QStringList qtLanguages;
+ for (const std::string& language : languages)
+ qtLanguages.append(QString::fromStdString(language));
+ return qtLanguages;
+}
+
+}
+
+QVariant QSystemLocale::query(QueryType query, QVariant &&in) const
+{
+ Q_UNUSED(in);
+
+ switch (query) {
+ case QSystemLocale::UILanguages:
+ return QVariant(navigatorLanguages());
+ default:
+ break;
+ }
+
+ return QVariant();
+}
+
+QLocale QSystemLocale::fallbackLocale() const
+{
+ const QStringList languages = navigatorLanguages();
+ if (languages.isEmpty())
+ return QLocale(u"en-US");
+ return QLocale(languages[0]);
+}
+
+#endif // QT_NO_SYSTEMLOCALE
+
+QT_END_NAMESPACE
diff --git a/src/corelib/text/qlocale_win.cpp b/src/corelib/text/qlocale_win.cpp
index 43324fbfb6..9fdb46a4c9 100644
--- a/src/corelib/text/qlocale_win.cpp
+++ b/src/corelib/text/qlocale_win.cpp
@@ -14,10 +14,9 @@
#include <q20algorithm.h>
-#ifdef Q_OS_WIN
-# include <qt_windows.h>
-# include <time.h>
-#endif
+// TODO QTBUG-121193: port away from the use of LCID to always use names.
+#include <qt_windows.h>
+#include <time.h>
#if QT_CONFIG(cpp_winrt)
# include <QtCore/private/qt_winrtbase_p.h>
@@ -31,9 +30,42 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
+// Shared interpretation of %LANG%
+static auto scanLangEnv()
+{
+ struct R
+ {
+ QByteArray name; // empty means unknown; lookup from id may work
+ LCID id = 0; // 0 means unknown; lookup from name may work
+ } result;
+ const QByteArray lang = qgetenv("LANG");
+ if (lang.size() && (lang == "C" || qt_splitLocaleName(QString::fromLocal8Bit(lang)))) {
+ // See if we have a Windows locale code instead of a locale name:
+ const auto [id, used] = qstrntoll(lang.data(), lang.size(), 0);
+ if (used > 0 && id && INT_MIN <= id && id <= INT_MAX)
+ return R {QByteArray(), static_cast<LCID>(id)};
+ return R {lang, 0};
+ }
+ return R{};
+}
+
+static auto getDefaultWinId()
+{
+ const auto [name, id] = scanLangEnv();
+ if (id)
+ return id;
+
+ if (!name.isEmpty()) {
+ LCID id = LocaleNameToLCID(static_cast<LPCWSTR>(
+ QString::fromUtf8(name).toStdWString().data()), 0);
+ if (id)
+ return id;
+ }
+
+ return GetUserDefaultLCID();
+}
+
static QByteArray getWinLocaleName(LCID id = LOCALE_USER_DEFAULT);
-static QString winIso639LangName(LCID id = LOCALE_USER_DEFAULT);
-static QString winIso3116CtryName(LCID id = LOCALE_USER_DEFAULT);
#ifndef QT_NO_SYSTEMLOCALE
@@ -59,6 +91,17 @@ static QString winIso3116CtryName(LCID id = LOCALE_USER_DEFAULT);
# define LOCALE_SSHORTTIME 0x00000079
#endif
+namespace {
+template <typename T>
+static QVariant nullIfEmpty(T &&value)
+{
+ // For use where we should fall back to CLDR if we got an empty value.
+ if (value.isEmpty())
+ return {};
+ return std::move(value);
+}
+}
+
struct QSystemLocalePrivate
{
QSystemLocalePrivate();
@@ -100,7 +143,7 @@ private:
// cached values:
LCID lcid;
- SubstitutionType substitutionType;
+ SubstitutionType substitutionType = SUnknown;
QString zero; // cached value for zeroDigit()
int getLocaleInfo(LCTYPE type, LPWSTR data, int size);
@@ -113,6 +156,7 @@ private:
SubstitutionType substitution();
QString substituteDigits(QString &&string);
+ QString correctDigits(QString &&string);
QString yearFix(int year, int fakeYear, QString &&formatted);
static QString winToQtFormat(QStringView sys_fmt);
@@ -121,9 +165,8 @@ private:
Q_GLOBAL_STATIC(QSystemLocalePrivate, systemLocalePrivate)
QSystemLocalePrivate::QSystemLocalePrivate()
- : substitutionType(SUnknown)
+ : lcid(getDefaultWinId())
{
- lcid = GetUserDefaultLCID();
}
inline int QSystemLocalePrivate::getCurrencyFormat(DWORD flags, LPCWSTR value, const CURRENCYFMTW *format, LPWSTR data, int size)
@@ -187,25 +230,25 @@ QSystemLocalePrivate::SubstitutionType QSystemLocalePrivate::substitution()
if (substitutionType == SUnknown) {
wchar_t buf[8];
if (!getLocaleInfo(LOCALE_IDIGITSUBSTITUTION, buf, 8)) {
- substitutionType = QSystemLocalePrivate::SNever;
+ substitutionType = SNever;
return substitutionType;
}
if (buf[0] == '1')
- substitutionType = QSystemLocalePrivate::SNever;
+ substitutionType = SNever;
else if (buf[0] == '0')
- substitutionType = QSystemLocalePrivate::SContext;
+ substitutionType = SContext;
else if (buf[0] == '2')
- substitutionType = QSystemLocalePrivate::SAlways;
+ substitutionType = SAlways;
else {
wchar_t digits[11]; // See zeroDigit() for why 11.
if (!getLocaleInfo(LOCALE_SNATIVEDIGITS, digits, 11)) {
- substitutionType = QSystemLocalePrivate::SNever;
+ substitutionType = SNever;
return substitutionType;
}
if (buf[0] == digits[0] + 2)
- substitutionType = QSystemLocalePrivate::SAlways;
+ substitutionType = SAlways;
else
- substitutionType = QSystemLocalePrivate::SNever;
+ substitutionType = SNever;
}
}
return substitutionType;
@@ -246,6 +289,11 @@ QString QSystemLocalePrivate::substituteDigits(QString &&string)
return std::move(string);
}
+QString QSystemLocalePrivate::correctDigits(QString &&string)
+{
+ return substitution() == SAlways ? substituteDigits(std::move(string)) : std::move(string);
+}
+
QVariant QSystemLocalePrivate::zeroDigit()
{
if (zero.isEmpty()) {
@@ -263,36 +311,36 @@ QVariant QSystemLocalePrivate::zeroDigit()
zero = QString::fromWCharArray(digits, 1);
}
}
- return zero;
+ return nullIfEmpty(zero); // Do not std::move().
}
QVariant QSystemLocalePrivate::decimalPoint()
{
- return getLocaleInfo(LOCALE_SDECIMAL);
+ return nullIfEmpty(getLocaleInfo(LOCALE_SDECIMAL).toString());
}
QVariant QSystemLocalePrivate::groupSeparator()
{
- return getLocaleInfo(LOCALE_STHOUSAND);
+ return getLocaleInfo(LOCALE_STHOUSAND); // Empty means don't group digits.
}
QVariant QSystemLocalePrivate::negativeSign()
{
- return getLocaleInfo(LOCALE_SNEGATIVESIGN);
+ return nullIfEmpty(getLocaleInfo(LOCALE_SNEGATIVESIGN).toString());
}
QVariant QSystemLocalePrivate::positiveSign()
{
- return getLocaleInfo(LOCALE_SPOSITIVESIGN);
+ return nullIfEmpty(getLocaleInfo(LOCALE_SPOSITIVESIGN).toString());
}
QVariant QSystemLocalePrivate::dateFormat(QLocale::FormatType type)
{
switch (type) {
case QLocale::ShortFormat:
- return winToQtFormat(getLocaleInfo(LOCALE_SSHORTDATE).toString());
+ return nullIfEmpty(winToQtFormat(getLocaleInfo(LOCALE_SSHORTDATE).toString()));
case QLocale::LongFormat:
- return winToQtFormat(getLocaleInfo(LOCALE_SLONGDATE).toString());
+ return nullIfEmpty(winToQtFormat(getLocaleInfo(LOCALE_SLONGDATE).toString()));
case QLocale::NarrowFormat:
break;
}
@@ -303,9 +351,9 @@ QVariant QSystemLocalePrivate::timeFormat(QLocale::FormatType type)
{
switch (type) {
case QLocale::ShortFormat:
- return winToQtFormat(getLocaleInfo(LOCALE_SSHORTTIME).toString());
+ return nullIfEmpty(winToQtFormat(getLocaleInfo(LOCALE_SSHORTTIME).toString()));
case QLocale::LongFormat:
- return winToQtFormat(getLocaleInfo(LOCALE_STIMEFORMAT).toString());
+ return nullIfEmpty(winToQtFormat(getLocaleInfo(LOCALE_STIMEFORMAT).toString()));
case QLocale::NarrowFormat:
break;
}
@@ -314,48 +362,48 @@ QVariant QSystemLocalePrivate::timeFormat(QLocale::FormatType type)
QVariant QSystemLocalePrivate::dateTimeFormat(QLocale::FormatType type)
{
- return QString(dateFormat(type).toString() + u' ' + timeFormat(type).toString());
+ QVariant d = dateFormat(type), t = timeFormat(type);
+ if (d.typeId() == QMetaType::QString && t.typeId() == QMetaType::QString)
+ return QString(d.toString() + u' ' + t.toString());
+ return {};
}
QVariant QSystemLocalePrivate::dayName(int day, QLocale::FormatType type)
{
if (day < 1 || day > 7)
- return QString();
+ return {};
- static const LCTYPE short_day_map[]
+ static constexpr LCTYPE short_day_map[]
= { LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
LOCALE_SABBREVDAYNAME6, LOCALE_SABBREVDAYNAME7 };
- static const LCTYPE long_day_map[]
+ static constexpr LCTYPE long_day_map[]
= { LOCALE_SDAYNAME1, LOCALE_SDAYNAME2,
LOCALE_SDAYNAME3, LOCALE_SDAYNAME4, LOCALE_SDAYNAME5,
LOCALE_SDAYNAME6, LOCALE_SDAYNAME7 };
- static const LCTYPE narrow_day_map[]
+ static constexpr LCTYPE narrow_day_map[]
= { LOCALE_SSHORTESTDAYNAME1, LOCALE_SSHORTESTDAYNAME2,
LOCALE_SSHORTESTDAYNAME3, LOCALE_SSHORTESTDAYNAME4,
LOCALE_SSHORTESTDAYNAME5, LOCALE_SSHORTESTDAYNAME6,
LOCALE_SSHORTESTDAYNAME7 };
- day -= 1;
-
- if (type == QLocale::LongFormat)
- return getLocaleInfo(long_day_map[day]);
- if (type == QLocale::NarrowFormat)
- return getLocaleInfo(narrow_day_map[day]);
- return getLocaleInfo(short_day_map[day]);
+ return nullIfEmpty(getLocaleInfo(
+ (type == QLocale::LongFormat ? long_day_map
+ : type == QLocale::NarrowFormat ? narrow_day_map
+ : short_day_map)[day - 1]).toString());
}
QVariant QSystemLocalePrivate::standaloneMonthName(int month, QLocale::FormatType type)
{
- static const LCTYPE short_month_map[]
+ static constexpr LCTYPE short_month_map[]
= { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
- static const LCTYPE long_month_map[]
+ static constexpr LCTYPE long_month_map[]
= { LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3,
LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6,
LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9,
@@ -365,8 +413,8 @@ QVariant QSystemLocalePrivate::standaloneMonthName(int month, QLocale::FormatTyp
return {};
// Month is Jan = 1, ... Dec = 12; adjust by 1 to match array indexing from 0:
- return getLocaleInfo(
- (type == QLocale::LongFormat ? long_month_map : short_month_map)[month - 1]);
+ return nullIfEmpty(getLocaleInfo(
+ (type == QLocale::LongFormat ? long_month_map : short_month_map)[month - 1]).toString());
}
QVariant QSystemLocalePrivate::monthName(int month, QLocale::FormatType type)
@@ -385,10 +433,7 @@ QVariant QSystemLocalePrivate::monthName(int month, QLocale::FormatType type)
wchar_t buf[255];
if (getDateFormat(flags, &st, format, buf, 255) > 2) {
// Elide the two digits of day number
- QString text = QString::fromWCharArray(buf + 2);
- if (substitution() == SAlways)
- text = substituteDigits(std::move(text));
- return text;
+ return nullIfEmpty(correctDigits(QString::fromWCharArray(buf + 2)));
}
return {};
}
@@ -420,7 +465,7 @@ QString QSystemLocalePrivate::yearFix(int year, int fakeYear, QString &&formatte
return std::move(formatted).replace(tail.toString(), sign + trueYear.last(2));
}
- // Localized digits, perhaps ?
+ // Localized digits (regardless of SAlways), perhaps ?
// First call to substituteDigits() ensures zero is initialized:
trueYear = substituteDigits(std::move(trueYear));
if (zero != u'0') {
@@ -465,9 +510,7 @@ QVariant QSystemLocalePrivate::toString(QDate date, QLocale::FormatType type)
QString text = QString::fromWCharArray(buf);
if (fixup)
text = yearFix(year, st.wYear, std::move(text));
- if (substitution() == SAlways)
- text = substituteDigits(std::move(text));
- return text;
+ return nullIfEmpty(correctDigits(std::move(text)));
}
return {};
}
@@ -488,19 +531,17 @@ QVariant QSystemLocalePrivate::toString(QTime time, QLocale::FormatType type)
auto formatStr = reinterpret_cast<const wchar_t *>(format.isEmpty() ? nullptr : format.utf16());
wchar_t buf[255];
- if (getTimeFormat(flags, &st, formatStr, buf, int(std::size(buf)))) {
- QString text = QString::fromWCharArray(buf);
- if (substitution() == SAlways)
- text = substituteDigits(std::move(text));
- return text;
- }
+ if (getTimeFormat(flags, &st, formatStr, buf, int(std::size(buf))))
+ return nullIfEmpty(correctDigits(QString::fromWCharArray(buf)));
return {};
}
QVariant QSystemLocalePrivate::toString(const QDateTime &dt, QLocale::FormatType type)
{
- return QString(toString(dt.date(), type).toString() + u' '
- + toString(dt.time(), type).toString());
+ QVariant d = toString(dt.date(), type), t = toString(dt.time(), type);
+ if (d.typeId() == QMetaType::QString && t.typeId() == QMetaType::QString)
+ return QString(d.toString() + u' ' + t.toString());
+ return {};
}
QVariant QSystemLocalePrivate::measurementSystem()
@@ -525,7 +566,7 @@ QVariant QSystemLocalePrivate::amText()
wchar_t output[15]; // maximum length including terminating zero character for Win2003+
if (getLocaleInfo(LOCALE_S1159, output, 15))
- return QString::fromWCharArray(output);
+ return nullIfEmpty(QString::fromWCharArray(output));
return QVariant();
}
@@ -535,7 +576,7 @@ QVariant QSystemLocalePrivate::pmText()
wchar_t output[15]; // maximum length including terminating zero character for Win2003+
if (getLocaleInfo(LOCALE_S2359, output, 15))
- return QString::fromWCharArray(output);
+ return nullIfEmpty(QString::fromWCharArray(output));
return QVariant();
}
@@ -555,12 +596,14 @@ QVariant QSystemLocalePrivate::currencySymbol(QLocale::CurrencySymbolFormat form
wchar_t buf[13];
switch (format) {
case QLocale::CurrencySymbol:
+ // Some locales do have empty currency symbol. All the same, fall back
+ // to CLDR for confirmation if MS claims that applies.
if (getLocaleInfo(LOCALE_SCURRENCY, buf, 13))
- return QString::fromWCharArray(buf);
+ return nullIfEmpty(QString::fromWCharArray(buf));
break;
case QLocale::CurrencyIsoCode:
if (getLocaleInfo(LOCALE_SINTLSYMBOL, buf, 9))
- return QString::fromWCharArray(buf);
+ return nullIfEmpty(QString::fromWCharArray(buf));
break;
case QLocale::CurrencyDisplayName: {
QVarLengthArray<wchar_t, 64> buf(64);
@@ -571,7 +614,7 @@ QVariant QSystemLocalePrivate::currencySymbol(QLocale::CurrencySymbolFormat form
if (!getLocaleInfo(LOCALE_SNATIVECURRNAME, buf.data(), buf.size()))
break;
}
- return QString::fromWCharArray(buf.data());
+ return nullIfEmpty(QString::fromWCharArray(buf.data()));
}
default:
break;
@@ -649,10 +692,7 @@ QVariant QSystemLocalePrivate::toCurrencyString(const QSystemLocale::CurrencyToS
pformat, out.data(), out.size());
}
- value = QString::fromWCharArray(out.data());
- if (substitution() == SAlways)
- value = substituteDigits(std::move(value));
- return value;
+ return nullIfEmpty(correctDigits(QString::fromWCharArray(out.data())));
}
QVariant QSystemLocalePrivate::uiLanguages()
@@ -682,7 +722,7 @@ QVariant QSystemLocalePrivate::uiLanguages()
GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &cnt, NULL, &size)) {
buf.resize(size);
if (!GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &cnt, buf.data(), &size))
- return QStringList();
+ return {};
}
}
# endif // !QT_BOOTSTRAPPED
@@ -695,7 +735,7 @@ QVariant QSystemLocalePrivate::uiLanguages()
result.append(s);
str += s.size() + 1;
}
- return result;
+ return nullIfEmpty(std::move(result));
}
QVariant QSystemLocalePrivate::nativeLanguageName()
@@ -711,7 +751,7 @@ QVariant QSystemLocalePrivate::nativeTerritoryName()
void QSystemLocalePrivate::update()
{
- lcid = GetUserDefaultLCID();
+ lcid = getDefaultWinId();
substitutionType = SUnknown;
zero.resize(0);
}
@@ -785,7 +825,7 @@ QLocale QSystemLocale::fallbackLocale() const
return QLocale(QString::fromLatin1(getWinLocaleName()));
}
-QVariant QSystemLocale::query(QueryType type, QVariant in) const
+QVariant QSystemLocale::query(QueryType type, QVariant &&in) const
{
QSystemLocalePrivate *d = systemLocalePrivate();
switch(type) {
@@ -869,7 +909,7 @@ QVariant QSystemLocale::query(QueryType type, QVariant in) const
case CurrencySymbol:
return d->currencySymbol(QLocale::CurrencySymbolFormat(in.toUInt()));
case CurrencyToString:
- return d->toCurrencyString(in.value<QSystemLocale::CurrencyToStringArgument>());
+ return d->toCurrencyString(in.value<CurrencyToStringArgument>());
case UILanguages:
return d->uiLanguages();
case LocaleChanged:
@@ -1114,20 +1154,15 @@ static QByteArray getWinLocaleName(LCID id)
{
QByteArray result;
if (id == LOCALE_USER_DEFAULT) {
- static const QByteArray langEnvVar = qgetenv("LANG");
- result = langEnvVar;
- if (result == "C"
- || (!result.isEmpty() && qt_splitLocaleName(QString::fromLocal8Bit(result)))) {
- // See if we have a Windows locale code instead of a locale name:
- auto [id, used] = qstrntoll(result.data(), result.size(), 0);
- if (used <= 0 || id == 0 || id < INT_MIN || id > INT_MAX) // Assume real locale name
- return result;
- return winLangCodeToIsoName(int(id));
- }
- }
+ const auto [name, lcid] = scanLangEnv();
+ if (!name.isEmpty())
+ return name;
+ if (lcid)
+ return winLangCodeToIsoName(lcid);
- if (id == LOCALE_USER_DEFAULT)
id = GetUserDefaultLCID();
+ }
+
QString resultusage = winIso639LangName(id);
QString country = winIso3116CtryName(id);
if (!country.isEmpty())
@@ -1136,6 +1171,7 @@ static QByteArray getWinLocaleName(LCID id)
return std::move(resultusage).toLatin1();
}
+// Helper for plugins/platforms/windows/
Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id)
{
return QLocale(QString::fromLatin1(getWinLocaleName(id)));
diff --git a/src/corelib/text/qregularexpression.cpp b/src/corelib/text/qregularexpression.cpp
index 2c83d122a3..67c422568b 100644
--- a/src/corelib/text/qregularexpression.cpp
+++ b/src/corelib/text/qregularexpression.cpp
@@ -721,7 +721,7 @@ struct QRegularExpressionPrivate : QSharedData
CheckSubjectStringOption checkSubjectStringOption = CheckSubjectString,
const QRegularExpressionMatchPrivate *previous = nullptr) const;
- int captureIndexForName(QStringView name) const;
+ int captureIndexForName(QAnyStringView name) const;
// sizeof(QSharedData) == 4, so start our members with an enum
QRegularExpression::PatternOptions patternOptions;
@@ -1013,7 +1013,7 @@ void QRegularExpressionPrivate::optimizePattern()
Returns the capturing group number for the given name. Duplicated names for
capturing groups are not supported.
*/
-int QRegularExpressionPrivate::captureIndexForName(QStringView name) const
+int QRegularExpressionPrivate::captureIndexForName(QAnyStringView name) const
{
Q_ASSERT(!name.isEmpty());
@@ -1104,7 +1104,7 @@ void QRegularExpressionPrivate::doMatch(QRegularExpressionMatchPrivate *priv,
const QRegularExpressionMatchPrivate *previous) const
{
Q_ASSERT(priv);
- Q_ASSUME(priv != previous);
+ Q_ASSERT(priv != previous);
const qsizetype subjectLength = priv->subject.size();
@@ -1508,7 +1508,7 @@ QStringList QRegularExpression::namedCaptureGroups() const
reinterpret_cast<const char16_t *>(namedCapturingTable) + namedCapturingTableEntrySize * i;
const int index = *currentNamedCapturingTableRow;
- result[index] = QString::fromUtf16(currentNamedCapturingTableRow + 1);
+ result[index] = QStringView(currentNamedCapturingTableRow + 1).toString();
}
return result;
@@ -1857,9 +1857,8 @@ QString QRegularExpression::escape(QStringView str)
The conversion will not anchor the pattern. This allows for partial string matches of
wildcard expressions.
- \value NonPathWildcardConversion
+ \value [since 6.6] NonPathWildcardConversion
The conversion will \e{not} interpret the pattern as filepath globbing.
- This enum value has been introduced in Qt 6.6.
\sa QRegularExpression::wildcardToRegularExpression
*/
@@ -1942,7 +1941,9 @@ QString QRegularExpression::wildcardToRegularExpression(QStringView pattern, Wil
const GlobSettings settings = [options]() {
if (options.testFlag(NonPathWildcardConversion)) {
- return GlobSettings{ u'\0', u".*", u"." };
+ // using [\d\D] to mean "match everything";
+ // dot doesn't match newlines, unless in /s mode
+ return GlobSettings{ u'\0', u"[\\d\\D]*", u"[\\d\\D]" };
} else {
#ifdef Q_OS_WIN
return GlobSettings{ u'\\', u"[^/\\\\]*", u"[^/\\\\]" };
@@ -2216,8 +2217,7 @@ int QRegularExpressionMatch::lastCapturedIndex() const
}
/*!
- \fn bool QRegularExpressionMatch::hasCaptured(const QString &name) const
- \fn bool QRegularExpressionMatch::hasCaptured(QStringView name) const
+ \fn bool QRegularExpressionMatch::hasCaptured(QAnyStringView name) const
\since 6.3
Returns true if the capturing group named \a name captured something
@@ -2234,9 +2234,12 @@ int QRegularExpressionMatch::lastCapturedIndex() const
Similarly, a capturing group may capture a substring of length 0;
this function will return \c{true} for such a capturing group.
+ \note In Qt versions prior to 6.8, this function took QString or
+ QStringView, not QAnyStringView.
+
\sa captured(), hasMatch()
*/
-bool QRegularExpressionMatch::hasCaptured(QStringView name) const
+bool QRegularExpressionMatch::hasCaptured(QAnyStringView name) const
{
const int nth = d->regularExpression.d->captureIndexForName(name);
return hasCaptured(nth);
@@ -2316,17 +2319,6 @@ QStringView QRegularExpressionMatch::capturedView(int nth) const
return d->subject.mid(start, capturedLength(nth));
}
-/*! \fn QString QRegularExpressionMatch::captured(const QString &name) const
-
- Returns the substring captured by the capturing group named \a name.
-
- If the named capturing group \a name did not capture a string, or if
- there is no capturing group named \a name, returns a null QString.
-
- \sa capturedView(), capturedStart(), capturedEnd(), capturedLength(),
- QString::isNull()
-*/
-
/*!
\since 5.10
@@ -2335,10 +2327,13 @@ QStringView QRegularExpressionMatch::capturedView(int nth) const
If the named capturing group \a name did not capture a string, or if
there is no capturing group named \a name, returns a null QString.
+ \note In Qt versions prior to 6.8, this function took QString or
+ QStringView, not QAnyStringView.
+
\sa capturedView(), capturedStart(), capturedEnd(), capturedLength(),
QString::isNull()
*/
-QString QRegularExpressionMatch::captured(QStringView name) const
+QString QRegularExpressionMatch::captured(QAnyStringView name) const
{
if (name.isEmpty()) {
qWarning("QRegularExpressionMatch::captured: empty capturing group name passed");
@@ -2357,10 +2352,13 @@ QString QRegularExpressionMatch::captured(QStringView name) const
If the named capturing group \a name did not capture a string, or if
there is no capturing group named \a name, returns a null QStringView.
+ \note In Qt versions prior to 6.8, this function took QString or
+ QStringView, not QAnyStringView.
+
\sa captured(), capturedStart(), capturedEnd(), capturedLength(),
QStringView::isNull()
*/
-QStringView QRegularExpressionMatch::capturedView(QStringView name) const
+QStringView QRegularExpressionMatch::capturedView(QAnyStringView name) const
{
if (name.isEmpty()) {
qWarning("QRegularExpressionMatch::capturedView: empty capturing group name passed");
@@ -2432,37 +2430,6 @@ qsizetype QRegularExpressionMatch::capturedEnd(int nth) const
return d->capturedOffsets.at(nth * 2 + 1);
}
-/*! \fn qsizetype QRegularExpressionMatch::capturedStart(const QString &name) const
-
- Returns the offset inside the subject string corresponding to the starting
- position of the substring captured by the capturing group named \a name.
- If the capturing group named \a name did not capture a string or doesn't
- exist, returns -1.
-
- \sa capturedEnd(), capturedLength(), captured()
-*/
-
-/*! \fn qsizetype QRegularExpressionMatch::capturedLength(const QString &name) const
-
- Returns the length of the substring captured by the capturing group named
- \a name.
-
- \note This function returns 0 if the capturing group named \a name did not
- capture a string or doesn't exist.
-
- \sa capturedStart(), capturedEnd(), captured()
-*/
-
-/*! \fn qsizetype QRegularExpressionMatch::capturedEnd(const QString &name) const
-
- Returns the offset inside the subject string immediately after the ending
- position of the substring captured by the capturing group named \a name. If
- the capturing group named \a name did not capture a string or doesn't
- exist, returns -1.
-
- \sa capturedStart(), capturedLength(), captured()
-*/
-
/*!
\since 5.10
@@ -2471,9 +2438,12 @@ qsizetype QRegularExpressionMatch::capturedEnd(int nth) const
If the capturing group named \a name did not capture a string or doesn't
exist, returns -1.
+ \note In Qt versions prior to 6.8, this function took QString or
+ QStringView, not QAnyStringView.
+
\sa capturedEnd(), capturedLength(), captured()
*/
-qsizetype QRegularExpressionMatch::capturedStart(QStringView name) const
+qsizetype QRegularExpressionMatch::capturedStart(QAnyStringView name) const
{
if (name.isEmpty()) {
qWarning("QRegularExpressionMatch::capturedStart: empty capturing group name passed");
@@ -2494,9 +2464,12 @@ qsizetype QRegularExpressionMatch::capturedStart(QStringView name) const
\note This function returns 0 if the capturing group named \a name did not
capture a string or doesn't exist.
+ \note In Qt versions prior to 6.8, this function took QString or
+ QStringView, not QAnyStringView.
+
\sa capturedStart(), capturedEnd(), captured()
*/
-qsizetype QRegularExpressionMatch::capturedLength(QStringView name) const
+qsizetype QRegularExpressionMatch::capturedLength(QAnyStringView name) const
{
if (name.isEmpty()) {
qWarning("QRegularExpressionMatch::capturedLength: empty capturing group name passed");
@@ -2516,9 +2489,12 @@ qsizetype QRegularExpressionMatch::capturedLength(QStringView name) const
the capturing group named \a name did not capture a string or doesn't
exist, returns -1.
+ \note In Qt versions prior to 6.8, this function took QString or
+ QStringView, not QAnyStringView.
+
\sa capturedStart(), capturedLength(), captured()
*/
-qsizetype QRegularExpressionMatch::capturedEnd(QStringView name) const
+qsizetype QRegularExpressionMatch::capturedEnd(QAnyStringView name) const
{
if (name.isEmpty()) {
qWarning("QRegularExpressionMatch::capturedEnd: empty capturing group name passed");
@@ -3099,7 +3075,8 @@ static const char *pcreCompileErrorCodes[] =
QT_TRANSLATE_NOOP("QRegularExpression", "heap limit exceeded"),
QT_TRANSLATE_NOOP("QRegularExpression", "invalid syntax"),
QT_TRANSLATE_NOOP("QRegularExpression", "internal error - duplicate substitution match"),
- QT_TRANSLATE_NOOP("QRegularExpression", "PCRE2_MATCH_INVALID_UTF is not supported for DFA matching")
+ QT_TRANSLATE_NOOP("QRegularExpression", "PCRE2_MATCH_INVALID_UTF is not supported for DFA matching"),
+ QT_TRANSLATE_NOOP("QRegularExpression", "INTERNAL ERROR: invalid substring offset")
};
#endif // #if 0
diff --git a/src/corelib/text/qregularexpression.h b/src/corelib/text/qregularexpression.h
index a264717b28..2b51b94b15 100644
--- a/src/corelib/text/qregularexpression.h
+++ b/src/corelib/text/qregularexpression.h
@@ -175,6 +175,7 @@ private:
Q_DECLARE_SHARED(QRegularExpression)
Q_DECLARE_OPERATORS_FOR_FLAGS(QRegularExpression::PatternOptions)
Q_DECLARE_OPERATORS_FOR_FLAGS(QRegularExpression::MatchOptions)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QRegularExpression::WildcardConversionOptions)
#ifndef QT_NO_DATASTREAM
Q_CORE_EXPORT QDataStream &operator<<(QDataStream &out, const QRegularExpression &re);
@@ -212,18 +213,26 @@ public:
int lastCapturedIndex() const;
+#if QT_CORE_REMOVED_SINCE(6, 8)
bool hasCaptured(const QString &name) const
- { return hasCaptured(QStringView(name)); }
+ { return hasCaptured(qToAnyStringViewIgnoringNull(name)); }
bool hasCaptured(QStringView name) const;
+#endif
+ bool hasCaptured(QAnyStringView name) const;
bool hasCaptured(int nth) const;
QString captured(int nth = 0) const;
QStringView capturedView(int nth = 0) const;
+#if QT_CORE_REMOVED_SINCE(6, 8)
QString captured(const QString &name) const
- { return captured(QStringView(name)); }
+ { return captured(qToAnyStringViewIgnoringNull(name)); }
+
QString captured(QStringView name) const;
QStringView capturedView(QStringView name) const;
+#endif
+ QString captured(QAnyStringView name) const;
+ QStringView capturedView(QAnyStringView name) const;
QStringList capturedTexts() const;
@@ -231,16 +240,21 @@ public:
qsizetype capturedLength(int nth = 0) const;
qsizetype capturedEnd(int nth = 0) const;
+#if QT_CORE_REMOVED_SINCE(6, 8)
qsizetype capturedStart(const QString &name) const
- { return capturedStart(QStringView(name)); }
+ { return capturedStart(qToAnyStringViewIgnoringNull(name)); }
qsizetype capturedLength(const QString &name) const
- { return capturedLength(QStringView(name)); }
+ { return capturedLength(qToAnyStringViewIgnoringNull(name)); }
qsizetype capturedEnd(const QString &name) const
- { return capturedEnd(QStringView(name)); }
+ { return capturedEnd(qToAnyStringViewIgnoringNull(name)); }
qsizetype capturedStart(QStringView name) const;
qsizetype capturedLength(QStringView name) const;
qsizetype capturedEnd(QStringView name) const;
+#endif
+ qsizetype capturedStart(QAnyStringView name) const;
+ qsizetype capturedLength(QAnyStringView name) const;
+ qsizetype capturedEnd(QAnyStringView name) const;
private:
friend class QRegularExpression;
diff --git a/src/corelib/text/qstaticlatin1stringmatcher.h b/src/corelib/text/qstaticlatin1stringmatcher.h
new file mode 100644
index 0000000000..d80ebd8547
--- /dev/null
+++ b/src/corelib/text/qstaticlatin1stringmatcher.h
@@ -0,0 +1,140 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSTATICLATIN1STRINGMATCHER_H
+#define QSTATICLATIN1STRINGMATCHER_H
+
+#include <functional>
+#include <iterator>
+#include <limits>
+
+#include <QtCore/q20algorithm.h>
+#include <QtCore/qlatin1stringmatcher.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_CC_GHS
+# define QT_STATIC_BOYER_MOORE_NOT_SUPPORTED
+#else
+namespace QtPrivate {
+template <class RandomIt1,
+ class Hash = std::hash<typename std::iterator_traits<RandomIt1>::value_type>,
+ class BinaryPredicate = std::equal_to<>>
+class q_boyer_moore_searcher
+{
+public:
+ constexpr q_boyer_moore_searcher(RandomIt1 pat_first, RandomIt1 pat_last) : m_skiptable{}
+ {
+ const size_t n = std::distance(pat_first, pat_last);
+ constexpr auto uchar_max = (std::numeric_limits<uchar>::max)();
+ uchar max = n > uchar_max ? uchar_max : uchar(n);
+ q20::fill(std::begin(m_skiptable), std::end(m_skiptable), max);
+ Hash hf;
+ RandomIt1 pattern = std::next(pat_first, n - max);
+ while (max--)
+ m_skiptable[hf(*pattern++)] = max;
+ }
+
+ template <class RandomIt2>
+ constexpr auto operator()(RandomIt2 first, RandomIt2 last, RandomIt1 pat_first,
+ RandomIt1 pat_last) const
+ {
+ struct R
+ {
+ RandomIt2 begin, end;
+ };
+ Hash hf;
+ BinaryPredicate pred;
+ auto pat_length = std::distance(pat_first, pat_last);
+ if (pat_length == 0)
+ return R{ first, first };
+
+ auto haystack_length = std::distance(first, last);
+ if (haystack_length < pat_length)
+ return R{ last, last };
+
+ const qsizetype pl_minus_one = qsizetype(pat_length - 1);
+ RandomIt2 current = first + pl_minus_one;
+
+ qsizetype skip = 0;
+ while (current < last - skip) {
+ current += skip;
+ skip = m_skiptable[hf(*current)];
+ if (!skip) {
+ // possible match
+ while (skip < pat_length) {
+ if (!pred(hf(*(current - skip)), hf(pat_first[pl_minus_one - skip])))
+ break;
+ skip++;
+ }
+ if (skip > pl_minus_one) { // we have a match
+ auto match = current + 1 - skip;
+ return R{ match, match + pat_length };
+ }
+
+ // If we don't have a match we are a bit inefficient as we only skip by one
+ // when we have the non matching char in the string.
+ if (m_skiptable[hf(*(current - skip))] == pat_length)
+ skip = pat_length - skip;
+ else
+ skip = 1;
+ }
+ }
+
+ return R{ last, last };
+ }
+
+private:
+ alignas(16) uchar m_skiptable[256];
+};
+} // namespace QtPrivate
+
+template <Qt::CaseSensitivity CS, size_t N>
+class QStaticLatin1StringMatcher
+{
+ static_assert(N > 2,
+ "QStaticLatin1StringMatcher makes no sense for finding a single-char pattern");
+
+ QLatin1StringView m_pattern;
+ using Hasher = std::conditional_t<CS == Qt::CaseSensitive, QtPrivate::QCaseSensitiveLatin1Hash,
+ QtPrivate::QCaseInsensitiveLatin1Hash>;
+ QtPrivate::q_boyer_moore_searcher<const char *, Hasher> m_searcher;
+
+public:
+ explicit constexpr QStaticLatin1StringMatcher(QLatin1StringView patternToMatch) noexcept
+ : m_pattern(patternToMatch),
+ m_searcher(patternToMatch.begin(), patternToMatch.begin() + N - 1)
+ {
+ }
+
+ constexpr qsizetype indexIn(QLatin1StringView haystack, qsizetype from = 0) const noexcept
+ {
+ if (from >= haystack.size())
+ return -1;
+ const char *begin = haystack.begin() + from;
+ const char *end = haystack.end();
+ const auto r = m_searcher(begin, end, m_pattern.begin(), m_pattern.end());
+ return r.begin == end ? -1 : std::distance(haystack.begin(), r.begin);
+ }
+};
+
+template <size_t N>
+constexpr auto qMakeStaticCaseSensitiveLatin1StringMatcher(const char (&patternToMatch)[N]) noexcept
+{
+ return QStaticLatin1StringMatcher<Qt::CaseSensitive, N>(
+ QLatin1StringView(patternToMatch, qsizetype(N) - 1));
+}
+
+template <size_t N>
+constexpr auto
+qMakeStaticCaseInsensitiveLatin1StringMatcher(const char (&patternToMatch)[N]) noexcept
+{
+ return QStaticLatin1StringMatcher<Qt::CaseInsensitive, N>(
+ QLatin1StringView(patternToMatch, qsizetype(N) - 1));
+}
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QSTATICLATIN1STRINGMATCHER_H
diff --git a/src/corelib/text/qstaticlatin1stringmatcher.qdoc b/src/corelib/text/qstaticlatin1stringmatcher.qdoc
new file mode 100644
index 0000000000..6577f985b2
--- /dev/null
+++ b/src/corelib/text/qstaticlatin1stringmatcher.qdoc
@@ -0,0 +1,86 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*! \class QStaticLatin1StringMatcher
+ \inmodule QtCore
+ \brief The QStaticLatin1StringMatcher class is a compile-time version
+ of QLatin1StringMatcher.
+
+ \since 6.7
+ \ingroup tools
+ \ingroup string-processing
+
+ This class is useful when your code needs to search efficiently
+ in Latin-1 strings for a substring that's known at compile-time.
+ This is common, for example, in parsers. Using a matcher
+ object's indexIn() is faster than using the indexOf() member method of
+ the string you are searching in, especially when the string to
+ be found will be searched for repeatedly or within a large
+ Latin-1 string that may contain many matches to prefixes of the
+ substring to be found.
+
+ Unlike QLatin1StringMatcher, this class calculates the internal
+ representation at \e{compile-time}, so it can be beneficial even if you
+ are doing one-off Latin-1 string matches.
+
+ Create the QStaticLatin1StringMatcher by calling
+ qMakeStaticCaseSensitiveLatin1StringMatcher() or
+ qMakeStaticCaseInsensitiveLatin1StringMatcher() passing the Latin-1
+ string to search for as a C string literal. Store the return value of
+ that function in a \c{static constexpr auto} variable, so you don't
+ need to pass the \c{N} template parameter explicitly.
+
+ Then call indexIn() on the QLatin1StringView in which you want to search,
+ just like with QLatin1StringMatcher.
+
+ Since this class is designed to do all the up-front calculations at
+ compile-time, it does not offer setPattern() or setCaseSensitivity()
+ methods.
+
+ \note INTEGRITY operating system is currently not supported.
+
+ \sa QLatin1StringMatcher, QStaticByteArrayMatcher, QByteArrayMatcher
+*/
+
+/*!
+ \fn template<Qt::CaseSensitivity CS, size_t N> constexpr qsizetype QStaticLatin1StringMatcher<CS, N>::indexIn(QLatin1StringView haystack, qsizetype from) const
+
+ Searches the QLatin1StringView \a haystack, from byte position \a from
+ (default 0, i.e. from the first byte), for QLatin1StringView pattern()
+ that was set in the constructor. Using the case sensitivity that was also
+ set in the constructor.
+
+ Returns the position where the pattern() matched in \a haystack, or -1 if no match was found.
+*/
+
+/*!
+ \fn template<size_t N> constexpr auto qMakeStaticCaseSensitiveLatin1StringMatcher(const char
+ (&patternToMatch)[N])
+
+ \since 6.7
+ \relates QStaticLatin1StringMatcher
+
+ Return a QStaticLatin1StringMatcher with the correct \c{N} determined
+ automatically from the \a patternToMatch passed, and with case sensitivity.
+
+ To take full advantage of this function, assign the result to a
+ \c{static constexpr auto} variable:
+
+ \snippet code/src_corelib_text_qstaticlatin1stringmatcher.cpp 0
+*/
+
+/*!
+ \fn template<size_t N> constexpr auto qMakeStaticCaseInsensitiveLatin1StringMatcher(const char
+ (&patternToMatch)[N])
+
+ \since 6.7
+ \relates QStaticLatin1StringMatcher
+
+ Return a QStaticLatin1StringMatcher with the correct \c{N} determined
+ automatically from the \a patternToMatch passed, and without case sensitivity.
+
+ To take full advantage of this function, assign the result to a
+ \c{static constexpr auto} variable:
+
+ \snippet code/src_corelib_text_qstaticlatin1stringmatcher.cpp 1
+*/
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp
index 64ad2c537b..f0bf0c50a3 100644
--- a/src/corelib/text/qstring.cpp
+++ b/src/corelib/text/qstring.cpp
@@ -17,6 +17,7 @@
#include <qlist.h>
#include "qlocale.h"
#include "qlocale_p.h"
+#include "qspan.h"
#include "qstringbuilder.h"
#include "qstringmatcher.h"
#include "qvarlengtharray.h"
@@ -50,23 +51,17 @@
#ifdef Q_OS_WIN
# include <qt_windows.h>
+# if !defined(QT_BOOTSTRAPPED) && (defined(QT_NO_CAST_FROM_ASCII) || defined(QT_NO_CAST_TO_ASCII))
+// MSVC requires this, but let's apply it to MinGW compilers too, just in case
+# error "This file cannot be compiled with QT_NO_CAST_{TO,FROM}_ASCII, " \
+ "otherwise some QString functions will not get exported."
+# endif
#endif
#ifdef truncate
# undef truncate
#endif
-#ifndef LLONG_MAX
-#define LLONG_MAX qint64_C(9223372036854775807)
-#endif
-#ifndef LLONG_MIN
-#define LLONG_MIN (-LLONG_MAX - qint64_C(1))
-#endif
-#ifndef ULLONG_MAX
-#define ULLONG_MAX quint64_C(18446744073709551615)
-#endif
-
-#define IS_RAW_DATA(d) ((d.d)->flags & QArrayData::RawDataType)
#define REHASH(a) \
if (sl_minus_1 < sizeof(std::size_t) * CHAR_BIT) \
hashHaystack -= std::size_t(a) << sl_minus_1; \
@@ -133,31 +128,6 @@ static inline bool foldAndCompare(const T a, const T b)
searching forward from index
position \a from. Returns -1 if \a ch could not be found.
*/
-static inline qsizetype qFindChar(QStringView str, QChar ch, qsizetype from, Qt::CaseSensitivity cs) noexcept
-{
- if (-from > str.size())
- return -1;
- if (from < 0)
- from = qMax(from + str.size(), qsizetype(0));
- if (from < str.size()) {
- const char16_t *s = str.utf16();
- char16_t c = ch.unicode();
- const char16_t *n = s + from;
- const char16_t *e = s + str.size();
- if (cs == Qt::CaseSensitive) {
- n = QtPrivate::qustrchr(QStringView(n, e), c);
- if (n != e)
- return n - s;
- } else {
- c = foldCase(c);
- auto it = std::find_if(n, e, [c](const auto &ch) { return foldAndCompare(ch, c); });
- if (it != e)
- return std::distance(s, it);
- }
- }
- return -1;
-}
-
template <typename Haystack>
static inline qsizetype qLastIndexOf(Haystack haystack, QChar needle,
qsizetype from, Qt::CaseSensitivity cs) noexcept
@@ -264,7 +234,7 @@ bool qt_starts_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity c
if (needleLen > haystackLen)
return false;
- return QtPrivate::compareStrings(haystack.left(needleLen), needle, cs) == 0;
+ return QtPrivate::compareStrings(haystack.first(needleLen), needle, cs) == 0;
}
template <typename Haystack, typename Needle>
@@ -279,7 +249,7 @@ bool qt_ends_with_impl(Haystack haystack, Needle needle, Qt::CaseSensitivity cs)
if (haystackLen < needleLen)
return false;
- return QtPrivate::compareStrings(haystack.right(needleLen), needle, cs) == 0;
+ return QtPrivate::compareStrings(haystack.last(needleLen), needle, cs) == 0;
}
template <typename T>
@@ -472,7 +442,7 @@ static bool simdTestMask(const char *&ptr, const char *end, quint32 maskval)
if constexpr (UseSse4_1) {
# ifndef Q_OS_QNX // compiler fails in the code below
__m128i mask;
- auto updatePtrSimd = [&](__m128i data) {
+ auto updatePtrSimd = [&](__m128i data) -> bool {
__m128i masked = _mm_and_si128(mask, data);
__m128i comparison = _mm_cmpeq_epi16(masked, _mm_setzero_si128());
uint result = _mm_movemask_epi8(comparison);
@@ -684,6 +654,7 @@ static int ucstrncmp_sse2(const char16_t *a, const Char *b, size_t l)
}
#endif
+Q_NEVER_INLINE
qsizetype QtPrivate::qustrlen(const char16_t *str) noexcept
{
#if defined(__SSE2__) && !(defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer))
@@ -699,6 +670,11 @@ qsizetype QtPrivate::qustrlen(const char16_t *str) noexcept
return result;
}
+qsizetype QtPrivate::qustrnlen(const char16_t *str, qsizetype maxlen) noexcept
+{
+ return qustrchr({ str, maxlen }, u'\0') - str;
+}
+
/*!
* \internal
*
@@ -707,6 +683,7 @@ qsizetype QtPrivate::qustrlen(const char16_t *str) noexcept
* character is not found, this function returns a pointer to the end of the
* string -- that is, \c{str.end()}.
*/
+Q_NEVER_INLINE
const char16_t *QtPrivate::qustrchr(QStringView str, char16_t c) noexcept
{
const char16_t *n = str.utf16();
@@ -787,6 +764,23 @@ const char16_t *QtPrivate::qustrchr(QStringView str, char16_t c) noexcept
return std::find(n, e, c);
}
+/*!
+ * \internal
+ *
+ * Searches case-insensitively for character \a c in the string \a str and
+ * returns a pointer to it. Iif the character is not found, this function
+ * returns a pointer to the end of the string -- that is, \c{str.end()}.
+ */
+Q_NEVER_INLINE
+const char16_t *QtPrivate::qustrcasechr(QStringView str, char16_t c) noexcept
+{
+ const QChar *n = str.begin();
+ const QChar *e = str.end();
+ c = foldCase(c);
+ auto it = std::find_if(n, e, [c](auto ch) { return foldAndCompare(ch, QChar(c)); });
+ return reinterpret_cast<const char16_t *>(it);
+}
+
// Note: ptr on output may be off by one and point to a preceding US-ASCII
// character. Usually harmless.
bool qt_is_ascii(const char *&ptr, const char *end) noexcept
@@ -981,7 +975,7 @@ Q_CORE_EXPORT void qt_from_latin1(char16_t *dst, const char *str, size_t size) n
return;
} else {
size = size % 4;
- return UnrollTailLoop<3>::exec(qsizetype(size), [=](int i) { dst[i] = (uchar)str[i]; });
+ return UnrollTailLoop<3>::exec(qsizetype(size), [=](qsizetype i) { dst[i] = uchar(str[i]); });
}
# endif
#endif
@@ -1354,10 +1348,8 @@ static int ucstrncmp(const char16_t *a, const char *b, size_t l)
// Unicode case-sensitive equality
template <typename Char2>
-static bool ucstreq(const char16_t *a, size_t alen, const Char2 *b, size_t blen)
+static bool ucstreq(const char16_t *a, size_t alen, const Char2 *b)
{
- if (alen != blen)
- return false;
if constexpr (std::is_same_v<decltype(a), decltype(b)>) {
if (a == b)
return true;
@@ -1400,12 +1392,14 @@ static int latin1nicmp(const char *lhsChar, qsizetype lSize, const char *rhsChar
bool QtPrivate::equalStrings(QStringView lhs, QStringView rhs) noexcept
{
- return ucstreq(lhs.utf16(), lhs.size(), rhs.utf16(), rhs.size());
+ Q_ASSERT(lhs.size() == rhs.size());
+ return ucstreq(lhs.utf16(), lhs.size(), rhs.utf16());
}
bool QtPrivate::equalStrings(QStringView lhs, QLatin1StringView rhs) noexcept
{
- return ucstreq(lhs.utf16(), lhs.size(), rhs.latin1(), rhs.size());
+ Q_ASSERT(lhs.size() == rhs.size());
+ return ucstreq(lhs.utf16(), lhs.size(), rhs.latin1());
}
bool QtPrivate::equalStrings(QLatin1StringView lhs, QStringView rhs) noexcept
@@ -1415,7 +1409,8 @@ bool QtPrivate::equalStrings(QLatin1StringView lhs, QStringView rhs) noexcept
bool QtPrivate::equalStrings(QLatin1StringView lhs, QLatin1StringView rhs) noexcept
{
- return QByteArrayView(lhs) == QByteArrayView(rhs);
+ Q_ASSERT(lhs.size() == rhs.size());
+ return (!lhs.size() || memcmp(lhs.data(), rhs.data(), lhs.size()) == 0);
}
bool QtPrivate::equalStrings(QBasicUtf8StringView<false> lhs, QStringView rhs) noexcept
@@ -1440,7 +1435,14 @@ bool QtPrivate::equalStrings(QBasicUtf8StringView<false> lhs, QLatin1StringView
bool QtPrivate::equalStrings(QBasicUtf8StringView<false> lhs, QBasicUtf8StringView<false> rhs) noexcept
{
- return lhs.size() == rhs.size() && (!lhs.size() || memcmp(lhs.data(), rhs.data(), lhs.size()) == 0);
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) || defined(QT_BOOTSTRAPPED) || defined(QT_STATIC)
+ Q_ASSERT(lhs.size() == rhs.size());
+#else
+ // operator== didn't enforce size prior to Qt 6.2
+ if (lhs.size() != rhs.size())
+ return false;
+#endif
+ return (!lhs.size() || memcmp(lhs.data(), rhs.data(), lhs.size()) == 0);
}
bool QAnyStringView::equal(QAnyStringView lhs, QAnyStringView rhs) noexcept
@@ -1605,7 +1607,7 @@ int QAnyStringView::compare(QAnyStringView lhs, QAnyStringView rhs, Qt::CaseSens
// ### Qt 7: do not allow anything but ASCII digits
// in arg()'s replacements.
-#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
static bool supportUnicodeDigitValuesInArg()
{
static const bool result = []() {
@@ -1628,7 +1630,7 @@ static bool supportUnicodeDigitValuesInArg()
static int qArgDigitValue(QChar ch) noexcept
{
-#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
if (supportUnicodeDigitValuesInArg())
return ch.digitValue();
#endif
@@ -1708,10 +1710,18 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
\ingroup shared
\ingroup string-processing
+ \compares strong
+ \compareswith strong QChar QLatin1StringView {const char16_t *} \
+ QStringView QUtf8StringView
+ \endcompareswith
+ \compareswith strong QByteArray QByteArrayView {const char *}
+ When comparing with byte arrays, their content is interpreted as utf-8.
+ \endcompareswith
+
QString stores a string of 16-bit \l{QChar}s, where each QChar
corresponds to one UTF-16 code unit. (Unicode characters
with code values above 65535 are stored using surrogate pairs,
- i.e., two consecutive \l{QChar}s.)
+ that is, two consecutive \l{QChar}s.)
\l{Unicode} is an international standard that supports most of the
writing systems in use today. It is a superset of US-ASCII (ANSI
@@ -1727,17 +1737,15 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
store raw bytes and traditional 8-bit '\\0'-terminated strings.
For most purposes, QString is the class you want to use. It is
used throughout the Qt API, and the Unicode support ensures that
- your applications will be easy to translate if you want to expand
- your application's market at some point. The two main cases where
- QByteArray is appropriate are when you need to store raw binary
- data, and when memory conservation is critical (like in embedded
- systems).
-
- \tableofcontents
+ your applications are easy to translate if you want to expand
+ your application's market at some point. Two prominent cases
+ where QByteArray is appropriate are when you need to store raw
+ binary data, and when memory conservation is critical (like in
+ embedded systems).
- \section1 Initializing a String
+ \section1 Initializing a string
- One way to initialize a QString is simply to pass a \c{const char
+ One way to initialize a QString is to pass a \c{const char
*} to its constructor. For example, the following code creates a
QString of size 5 containing the data "Hello":
@@ -1748,17 +1756,18 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
In all of the QString functions that take \c{const char *}
parameters, the \c{const char *} is interpreted as a classic
- C-style '\\0'-terminated string encoded in UTF-8. It is legal for
- the \c{const char *} parameter to be \nullptr.
+ C-style \c{'\\0'}-terminated string. Except where the function's
+ name overtly indicates some other encoding, such \c{const char *}
+ parameters are assumed to be encoded in UTF-8.
You can also provide string data as an array of \l{QChar}s:
\snippet qstring/main.cpp 1
QString makes a deep copy of the QChar data, so you can modify it
- later without experiencing side effects. (If for performance
- reasons you don't want to take a deep copy of the character data,
- use QString::fromRawData() instead.)
+ later without experiencing side effects. You can avoid taking a
+ deep copy of the character data by using QStringView or
+ QString::fromRawData() instead.
Another approach is to set the size of the string using resize()
and to initialize the data character per character. QString uses
@@ -1775,7 +1784,7 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
\snippet qstring/main.cpp 3
- The at() function can be faster than \l operator[](), because it
+ The at() function can be faster than \l operator[]() because it
never causes a \l{deep copy} to occur. Alternatively, use the
first(), last(), or sliced() functions to extract several characters
at a time.
@@ -1797,11 +1806,11 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
You can also pass string literals to functions that take QStrings
as arguments, invoking the QString(const char *)
constructor. Similarly, you can pass a QString to a function that
- takes a \c{const char *} argument using the \l qPrintable() macro
+ takes a \c{const char *} argument using the \l qPrintable() macro,
which returns the given QString as a \c{const char *}. This is
equivalent to calling <QString>.toLocal8Bit().constData().
- \section1 Manipulating String Data
+ \section1 Manipulating string data
QString provides the following basic functions for modifying the
character data: append(), prepend(), insert(), replace(), and
@@ -1809,19 +1818,19 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
\snippet qstring/main.cpp 5
- In the above example the replace() function's first two arguments are the
+ In the above example, the replace() function's first two arguments are the
position from which to start replacing and the number of characters that
should be replaced.
When data-modifying functions increase the size of the string,
- they may lead to reallocation of memory for the QString object. When
+ QString may reallocate the memory in which it holds its data. When
this happens, QString expands by more than it immediately needs so as
to have space for further expansion without reallocation until the size
- of the string has greatly increased.
+ of the string has significantly increased.
- The insert(), remove() and, when replacing a sub-string with one of
+ The insert(), remove(), and, when replacing a sub-string with one of
different size, replace() functions can be slow (\l{linear time}) for
- large strings, because they require moving many characters in the string
+ large strings because they require moving many characters in the string
by at least one position in memory.
If you are building a QString gradually and know in advance
@@ -1839,32 +1848,32 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
method of the QString is called. Accessing such an iterator or reference
after the call to a non-\c{const} method leads to undefined behavior. When
stability for iterator-like functionality is required, you should use
- indexes instead of iterators as they are not tied to QString's internal
+ indexes instead of iterators, as they are not tied to QString's internal
state and thus do not get invalidated.
\note Due to \l{implicit sharing}, the first non-\c{const} operator or
- function used on a given QString may cause it to, internally, perform a deep
+ function used on a given QString may cause it to internally perform a deep
copy of its data. This invalidates all iterators over the string and
- references to individual characters within it. After the first non-\c{const}
- operator, operations that modify QString may completely (in case of
- reallocation) or partially invalidate iterators and references, but other
- methods (such as begin() or end()) will not. Accessing an iterator or
- reference after it has been invalidated leads to undefined behavior.
-
- A frequent requirement is to remove whitespace characters from a
- string ('\\n', '\\t', ' ', etc.). If you want to remove whitespace
- from both ends of a QString, use the trimmed() function. If you
- want to remove whitespace from both ends and replace multiple
- consecutive whitespaces with a single space character within the
- string, use simplified().
+ references to individual characters within it. Do not call non-const
+ functions while keeping iterators. Accessing an iterator or reference
+ after it has been invalidated leads to undefined behavior. See the
+ \l{Implicit sharing iterator problem} section for more information.
+
+ A frequent requirement is to remove or simplify the spacing between
+ visible characters in a string. The characters that make up that spacing
+ are those for which \l {QChar::}{isSpace()} returns \c true, such as
+ the simple space \c{' '}, the horizontal tab \c{'\\t'} and the newline \c{'\\n'}.
+ To obtain a copy of a string leaving out any spacing from its start and end,
+ use \l trimmed(). To also replace each sequence of spacing characters within
+ the string with a simple space, \c{' '}, use \l simplified().
If you want to find all occurrences of a particular character or
substring in a QString, use the indexOf() or lastIndexOf()
- functions. The former searches forward starting from a given index
- position, the latter searches backward. Both return the index
- position of the character or substring if they find it; otherwise,
- they return -1. For example, here is a typical loop that finds all
- occurrences of a particular substring:
+ functions.The former searches forward, the latter searches backward.
+ Either can be told an index position from which to start their search.
+ Each returns the index position of the character or substring if they
+ find it; otherwise, they return -1. For example, here is a typical loop
+ that finds all occurrences of a particular substring:
\snippet qstring/main.cpp 6
@@ -1873,52 +1882,57 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
setNum() functions, the number() static functions, and the
toInt(), toDouble(), and similar functions.
- To get an upper- or lowercase version of a string use toUpper() or
+ To get an uppercase or lowercase version of a string, use toUpper() or
toLower().
Lists of strings are handled by the QStringList class. You can
split a string into a list of strings using the split() function,
and join a list of strings into a single string with an optional
- separator using QStringList::join(). You can obtain a list of
- strings from a string list that contain a particular substring or
- that match a particular QRegularExpression using the QStringList::filter()
- function.
+ separator using QStringList::join(). You can obtain a filtered list
+ from a string list by selecting the entries in it that contain a
+ particular substring or match a particular QRegularExpression.
+ See QStringList::filter() for details.
- \section1 Querying String Data
+ \section1 Querying string data
- If you want to see if a QString starts or ends with a particular
- substring use startsWith() or endsWith(). If you simply want to
- check whether a QString contains a particular character or
- substring, use the contains() function. If you want to find out
- how many times a particular character or substring occurs in the
- string, use count().
+ To see if a QString starts or ends with a particular substring, use
+ startsWith() or endsWith(). To check whether a QString contains a
+ specific character or substring, use the contains() function. To
+ find out how many times a particular character or substring occurs
+ in a string, use count().
To obtain a pointer to the actual character data, call data() or
constData(). These functions return a pointer to the beginning of
the QChar data. The pointer is guaranteed to remain valid until a
non-\c{const} function is called on the QString.
- \section2 Comparing Strings
+ \section2 Comparing strings
QStrings can be compared using overloaded operators such as \l
operator<(), \l operator<=(), \l operator==(), \l operator>=(),
- and so on. Note that the comparison is based exclusively on the
- numeric Unicode values of the characters. It is very fast, but is
- not what a human would expect; the QString::localeAwareCompare()
- function is usually a better choice for sorting user-interface
- strings, when such a comparison is available.
-
- On Unix-like platforms (including Linux, \macos and iOS), when Qt
- is linked with the ICU library (which it usually is), its
- locale-aware sorting is used. Otherwise, on \macos and iOS, \l
- localeAwareCompare() compares according the "Order for sorted
- lists" setting in the International preferences panel. On other
- Unix-like systems without ICU, the comparison falls back to the
- system library's \c strcoll(),
-
- \section1 Converting Between Encoded Strings Data and QString
-
- QString provides the following three functions that return a
+ and so on. The comparison is based exclusively on the lexicographical
+ order of the two strings, seen as sequences of UTF-16 code units.
+ It is very fast but is not what a human would expect; the
+ QString::localeAwareCompare() function is usually a better choice for
+ sorting user-interface strings, when such a comparison is available.
+
+ When Qt is linked with the ICU library (which it usually is), its
+ locale-aware sorting is used. Otherwise, platform-specific solutions
+ are used:
+ \list
+ \li On Windows, localeAwareCompare() uses the current user locale,
+ as set in the \uicontrol{regional} and \uicontrol{language}
+ options portion of \uicontrol{Control Panel}.
+ \li On \macos and iOS, \l localeAwareCompare() compares according
+ to the \uicontrol{Order for sorted lists} setting in the
+ \uicontrol{International preferences} panel.
+ \li On other Unix-like systems, the comparison falls back to the
+ system library's \c strcoll().
+ \endlist
+
+ \section1 Converting between encoded string data and QString
+
+ QString provides the following functions that return a
\c{const char *} version of the string as QByteArray: toUtf8(),
toLatin1(), and toLocal8Bit().
@@ -1949,7 +1963,7 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
\li \l QT_NO_CAST_FROM_ASCII disables automatic conversions from
C string literals and pointers to Unicode.
\li \l QT_RESTRICTED_CAST_FROM_ASCII allows automatic conversions
- from C characters and character arrays, but disables automatic
+ from C characters and character arrays but disables automatic
conversions from character pointers to Unicode.
\li \l QT_NO_CAST_TO_ASCII disables automatic conversion from QString
to C strings.
@@ -1957,7 +1971,7 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
You then need to explicitly call fromUtf8(), fromLatin1(),
or fromLocal8Bit() to construct a QString from an
- 8-bit string, or use the lightweight QLatin1StringView class, for
+ 8-bit string, or use the lightweight QLatin1StringView class. For
example:
\snippet code/src_corelib_text_qstring.cpp 1
@@ -1978,7 +1992,7 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
\snippet qstring/main.cpp 7
- The \c result variable, is a normal variable allocated on the
+ The \c result variable is a normal variable allocated on the
stack. When \c return is called, and because we're returning by
value, the copy constructor is called and a copy of the string is
returned. No actual copying takes place thanks to the implicit
@@ -1986,12 +2000,12 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
\endtable
- \section1 Distinction Between Null and Empty Strings
+ \section1 Distinction between null and empty strings
- For historical reasons, QString distinguishes between a null
- string and an empty string. A \e null string is a string that is
+ For historical reasons, QString distinguishes between null
+ and empty strings. A \e null string is a string that is
initialized using QString's default constructor or by passing
- (\c{const char *})0 to the constructor. An \e empty string is any
+ \nullptr to the constructor. An \e empty string is any
string with size 0. A null string is always empty, but an empty
string isn't necessarily null:
@@ -1999,10 +2013,10 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
All functions except isNull() treat null strings the same as empty
strings. For example, toUtf8().constData() returns a valid pointer
- (\e not nullptr) to a '\\0' character for a null string. We
+ (not \nullptr) to a '\\0' character for a null string. We
recommend that you always use the isEmpty() function and avoid isNull().
- \section1 Number Formats
+ \section1 Number formats
When a QString::arg() \c{'%'} format specifier includes the \c{'L'} locale
qualifier, and the base is ten (its default), the default locale is
@@ -2012,16 +2026,16 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
C locale's representation of numbers.
When QString::arg() applies left-padding to numbers, the fill character
- \c{'0'} is treated specially. If the number is negative, its minus sign will
- appear before the zero-padding. If the field is localized, the
+ \c{'0'} is treated specially. If the number is negative, its minus sign
+ appears before the zero-padding. If the field is localized, the
locale-appropriate zero character is used in place of \c{'0'}. For
floating-point numbers, this special treatment only applies if the number is
finite.
- \section2 Floating-point Formats
+ \section2 Floating-point formats
- In member functions (e.g., arg(), number()) that represent floating-point
- numbers (\c float or \c double) as strings, the form of display can be
+ In member functions (for example, arg() and number()) that format floating-point
+ numbers (\c float or \c double) as strings, the representation used can be
controlled by a choice of \e format and \e precision, whose meanings are as
for \l {QLocale::toString(double, char, int)}.
@@ -2030,19 +2044,15 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
the exponent shows its sign and includes at least two digits, left-padding
with zero if needed.
- \section1 More Efficient String Construction
-
- Many strings are known at compile time. But the trivial
- constructor QString("Hello"), will copy the contents of the string,
- treating the contents as Latin-1. To avoid this, one can use the
- QStringLiteral macro to directly create the required data at compile
- time. Constructing a QString out of the literal does then not cause
- any overhead at runtime.
+ \section1 More efficient string construction
- A slightly less efficient way is to use QLatin1StringView. This class wraps
- a C string literal, precalculates it length at compile time and can
- then be used for faster comparison with QStrings and conversion to
- QStrings than a regular C string literal.
+ Many strings are known at compile time. The QString constructor from
+ C++ string literals will copy the contents of the string,
+ treating the contents as UTF-8. This requires memory allocation and
+ re-encoding string data, operations that will happen at runtime.
+ If the string data is known at compile time, you can use the QStringLiteral
+ macro or similarly \c{operator""_s} to create QString's payload at compile
+ time instead.
Using the QString \c{'+'} operator, it is easy to construct a
complex string from multiple substrings. You will often write code
@@ -2051,16 +2061,15 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
\snippet qstring/stringbuilder.cpp 0
There is nothing wrong with either of these string constructions,
- but there are a few hidden inefficiencies. Beginning with Qt 4.6,
- you can eliminate them.
+ but there are a few hidden inefficiencies:
- First, multiple uses of the \c{'+'} operator usually means
+ First, repeated use of the \c{'+'} operator may lead to
multiple memory allocations. When concatenating \e{n} substrings,
where \e{n > 2}, there can be as many as \e{n - 1} calls to the
memory allocator.
- In 4.6, an internal template class \c{QStringBuilder} has been
- added along with a few helper functions. This class is marked
+ These allocations can be optimized by an internal class
+ \c{QStringBuilder}. This class is marked
internal and does not appear in the documentation, because you
aren't meant to instantiate it in your code. Its use will be
automatic, as described below. The class is found in
@@ -2076,54 +2085,57 @@ void qtWarnAboutInvalidRegularExpression(const QString &pattern, const char *whe
then called \e{once} to get the required space, and the substrings
are copied into it one by one.
- Additional efficiency is gained by inlining and reduced reference
- counting (the QString created from a \c{QStringBuilder} typically
+ Additional efficiency is gained by inlining and reducing reference
+ counting (the QString created from a \c{QStringBuilder}
has a ref count of 1, whereas QString::append() needs an extra
test).
There are two ways you can access this improved method of string
construction. The straightforward way is to include
- \c{QStringBuilder} wherever you want to use it, and use the
+ \c{QStringBuilder} wherever you want to use it and use the
\c{'%'} operator instead of \c{'+'} when concatenating strings:
\snippet qstring/stringbuilder.cpp 5
- A more global approach, which is more convenient but not entirely source
- compatible, is to define \c QT_USE_QSTRINGBUILDER (by adding it to the compiler
- flags) at build time. This will make concatenating strings with \c{'+'} work the
- same way as \c{QStringBuilder} \c{'%'}.
+ A more global approach, which is more convenient but not entirely
+ source-compatible, is to define \c QT_USE_QSTRINGBUILDER (by adding
+ it to the compiler flags) at build time. This will make concatenating
+ strings with \c{'+'} work the same way as \c{QStringBuilder's} \c{'%'}.
+
+ \note Using automatic type deduction (for example, by using the \c
+ auto keyword) with the result of string concatenation when QStringBuilder
+ is enabled will show that the concatenation is indeed an object of a
+ QStringBuilder specialization:
- \note Take care when using the \c auto keyword with the result of
- string concatenation using QStringBuilder:
\snippet qstring/stringbuilder.cpp 6
- Typically this is not what is expected (and can result in undefined behavior).
- This issue can be fixed by specifying the return type:
- \snippet qstring/stringbuilder.cpp 7
+ This does not cause any harm, as QStringBuilder will implicitly convert to
+ QString when required. If this is undesirable, then one should specify
+ the necessary types instead of having the compiler deduce them:
- \note \l {https://invent.kde.org/sdk/clazy} {Clazy} has a check, auto-unexpected-qstringbuilder,
- that catches this issue.
+ \snippet qstring/stringbuilder.cpp 7
- \section1 Maximum Size and Out-of-memory Conditions
+ \section1 Maximum size and out-of-memory conditions
The maximum size of QString depends on the architecture. Most 64-bit
systems can allocate more than 2 GB of memory, with a typical limit
of 2^63 bytes. The actual value also depends on the overhead required for
- managing the data block. As a result, you can expect the maximum size
- of 2 GB minus overhead on 32-bit platforms, and 2^63 bytes minus overhead
+ managing the data block. As a result, you can expect a maximum size
+ of 2 GB minus overhead on 32-bit platforms and 2^63 bytes minus overhead
on 64-bit platforms. The number of elements that can be stored in a
QString is this maximum size divided by the size of QChar.
When memory allocation fails, QString throws a \c std::bad_alloc
exception if the application was compiled with exception support.
- Out of memory conditions in Qt containers are the only case where Qt
+ Out-of-memory conditions in Qt containers are the only cases where Qt
will throw exceptions. If exceptions are disabled, then running out of
memory is undefined behavior.
- Note that the operating system may impose further limits on applications
- holding a lot of allocated memory, especially large, contiguous blocks.
- Such considerations, the configuration of such behavior or any mitigation
- are outside the scope of the Qt API.
+ \note Target operating systems may impose limits on how much memory an
+ application can allocate, in total, or on the size of individual allocations.
+ This may further restrict the size of string a QString can hold.
+ Mitigating or controlling the behavior these limits cause is beyond the
+ scope of the Qt API.
\sa fromRawData(), QChar, QStringView, QLatin1StringView, QByteArray
*/
@@ -2409,8 +2421,8 @@ encoded in \1, and is converted to QString using the \2 function.
/*! \fn std::wstring QString::toStdWString() const
Returns a std::wstring object with the data contained in this
- QString. The std::wstring is encoded in utf16 on platforms where
- wchar_t is 2 bytes wide (e.g. windows) and in ucs4 on platforms
+ QString. The std::wstring is encoded in UTF-16 on platforms where
+ wchar_t is 2 bytes wide (for example, Windows) and in UTF-32 on platforms
where wchar_t is 4 bytes wide (most Unix systems).
This method is mostly useful to pass a QString to a function
@@ -2483,15 +2495,12 @@ QString::QString(const QChar *unicode, qsizetype size)
if (!unicode) {
d.clear();
} else {
- if (size < 0) {
- size = 0;
- while (!unicode[size].isNull())
- ++size;
- }
+ if (size < 0)
+ size = QtPrivate::qustrlen(reinterpret_cast<const char16_t *>(unicode));
if (!size) {
d = DataPointer::fromRawData(&_empty, 0);
} else {
- d = DataPointer(Data::allocate(size), size);
+ d = DataPointer(size, size);
Q_CHECK_PTR(d.data());
memcpy(d.data(), unicode, size * sizeof(QChar));
d.data()[size] = '\0';
@@ -2510,7 +2519,7 @@ QString::QString(qsizetype size, QChar ch)
if (size <= 0) {
d = DataPointer::fromRawData(&_empty, 0);
} else {
- d = DataPointer(Data::allocate(size), size);
+ d = DataPointer(size, size);
Q_CHECK_PTR(d.data());
d.data()[size] = '\0';
char16_t *b = d.data();
@@ -2531,7 +2540,7 @@ QString::QString(qsizetype size, Qt::Initialization)
if (size <= 0) {
d = DataPointer::fromRawData(&_empty, 0);
} else {
- d = DataPointer(Data::allocate(size), size);
+ d = DataPointer(size, size);
Q_CHECK_PTR(d.data());
d.data()[size] = '\0';
}
@@ -2549,7 +2558,7 @@ QString::QString(qsizetype size, Qt::Initialization)
*/
QString::QString(QChar ch)
{
- d = DataPointer(Data::allocate(1), 1);
+ d = DataPointer(1, 1);
Q_CHECK_PTR(d.data());
d.data()[0] = ch.unicode();
d.data()[1] = '\0';
@@ -2565,7 +2574,7 @@ QString::QString(QChar ch)
can be useful if you want to ensure that all user-visible strings
go through QObject::tr(), for example.
- \note: any null ('\\0') bytes in the byte array will be included in this
+ \note Any null ('\\0') bytes in the byte array will be included in this
string, converted to Unicode null characters (U+0000). This behavior is
different from Qt 5.x.
@@ -2613,6 +2622,12 @@ QString::QString(QChar ch)
\internal
*/
+/*! \fn QString::operator std::u16string_view() const
+ \since 6.7
+
+ Converts this QString object to a \c{std::u16string_view} object.
+*/
+
static bool needsReallocate(const QString &str, qsizetype newSize)
{
const auto capacityAtEnd = str.capacity() - str.data_ptr().freeSpaceAtBegin();
@@ -2681,6 +2696,24 @@ void QString::resize(qsizetype newSize, QChar fillChar)
std::fill_n(d.data() + oldSize, difference, fillChar.unicode());
}
+
+/*!
+ \since 6.8
+
+ Sets the size of the string to \a size characters. If the size of
+ the string grows, the new characters are uninitialized.
+
+ The behavior is identical to \c{resize(size)}.
+
+ \sa resize()
+*/
+
+void QString::resizeForOverwrite(qsizetype size)
+{
+ resize(size);
+}
+
+
/*! \fn qsizetype QString::capacity() const
Returns the maximum number of characters that can be stored in
@@ -2706,20 +2739,20 @@ void QString::resize(qsizetype newSize, QChar fillChar)
Ensures the string has space for at least \a size characters.
- If you know in advance how large the string will be, you can call this
- function to save repeated reallocation in the course of building it.
+ If you know in advance how large a string will be, you can call this
+ function to save repeated reallocation while building it.
This can improve performance when building a string incrementally.
A long sequence of operations that add to a string may trigger several
reallocations, the last of which may leave you with significantly more
- space than you really need, which is less efficient than doing a single
+ space than you need. This is less efficient than doing a single
allocation of the right size at the start.
If in doubt about how much space shall be needed, it is usually better to
use an upper bound as \a size, or a high estimate of the most likely size,
if a strict upper bound would be much bigger than this. If \a size is an
underestimate, the string will grow as needed once the reserved size is
- exceeded, which may lead to a larger allocation than your best overestimate
- would have and will slow the operation that triggers it.
+ exceeded, which may lead to a larger allocation than your best
+ overestimate would have and will slow the operation that triggers it.
\warning reserve() reserves memory but does not change the size of the
string. Accessing data beyond the end of the string is undefined behavior.
@@ -2761,7 +2794,7 @@ void QString::reallocData(qsizetype alloc, QArrayData::AllocationOption option)
const bool cannotUseReallocate = d.freeSpaceAtBegin() > 0;
if (d->needsDetach() || cannotUseReallocate) {
- DataPointer dd(Data::allocate(alloc, option), qMin(alloc, d.size));
+ DataPointer dd(alloc, qMin(alloc, d.size), option);
Q_CHECK_PTR(dd.data());
if (dd.size > 0)
::memcpy(dd.data(), d.data(), dd.size * sizeof(QChar));
@@ -2867,16 +2900,7 @@ QString &QString::operator=(QLatin1StringView other)
*/
QString &QString::operator=(QChar ch)
{
- const qsizetype capacityAtEnd = capacity() - d.freeSpaceAtBegin();
- if (isDetached() && capacityAtEnd >= 1) { // assumes d->alloc == 0 -> !isDetached() (sharedNull)
- // re-use existing capacity:
- d.data()[0] = ch.unicode();
- d.data()[1] = 0;
- d.size = 1;
- } else {
- operator=(QString(ch));
- }
- return *this;
+ return assign(1, ch);
}
/*!
@@ -3057,11 +3081,10 @@ QString &QString::insert(qsizetype i, QUtf8StringView s)
} else {
// Optimal insertion of Utf8 data is at the end, anywhere else could
// potentially lead to moving characters twice if Utf8 data size
- // (variable-width) is less than the equiavalent Utf16 data size
+ // (variable-width) is less than the equivalent Utf16 data size
QVarLengthArray<char16_t> buffer(insert_size); // ### optimize (QTBUG-108546)
char16_t *b = QUtf8::convertToUnicode(buffer.data(), s);
- buffer.resize(std::distance(buffer.begin(), b));
- insert_helper(*this, i, buffer);
+ insert_helper(*this, i, QStringView(buffer.data(), b));
}
return *this;
@@ -3086,7 +3109,8 @@ QString& QString::insert(qsizetype i, const QChar *unicode, qsizetype size)
// In case when data points into "this"
if (!d->needsDetach() && QtPrivate::q_points_into_range(unicode, *this)) {
- insert_helper(*this, i, QVarLengthArray<QChar>(unicode, unicode + size));
+ QVarLengthArray copy(unicode, unicode + size);
+ insert(i, copy.data(), size);
} else {
insert_helper(*this, i, QStringView(unicode, size));
}
@@ -3134,7 +3158,10 @@ QString &QString::append(const QString &str)
{
if (!str.isNull()) {
if (isNull()) {
- operator=(str);
+ if (Q_UNLIKELY(!str.d.isMutable()))
+ assign(str); // fromRawData, so we do a deep copy
+ else
+ operator=(str);
} else if (str.size()) {
append(str.constData(), str.size());
}
@@ -3310,6 +3337,111 @@ QString &QString::append(QChar ch)
*/
/*!
+ \fn QString &QString::assign(QAnyStringView v)
+ \since 6.6
+
+ Replaces the contents of this string with a copy of \a v and returns a
+ reference to this string.
+
+ The size of this string will be equal to the size of \a v, converted to
+ UTF-16 as if by \c{v.toString()}. Unlike QAnyStringView::toString(), however,
+ this function only allocates memory if the estimated size exceeds the capacity
+ of this string or this string is shared.
+
+ \sa QAnyStringView::toString()
+*/
+
+/*!
+ \fn QString &QString::assign(qsizetype n, QChar c)
+ \since 6.6
+
+ Replaces the contents of this string with \a n copies of \a c and
+ returns a reference to this string.
+
+ The size of this string will be equal to \a n, which has to be non-negative.
+
+ This function will only allocate memory if \a n exceeds the capacity of this
+ string or this string is shared.
+
+ \sa fill()
+*/
+
+/*!
+ \fn template <typename InputIterator, QString::if_compatible_iterator<InputIterator>> QString &QString::assign(InputIterator first, InputIterator last)
+ \since 6.6
+
+ Replaces the contents of this string with a copy of the elements in the
+ iterator range [\a first, \a last) and returns a reference to this string.
+
+ The size of this string will be equal to the decoded length of the elements
+ in the range [\a first, \a last), which need not be the same as the length of
+ the range itself, because this function transparently recodes the input
+ character set to UTF-16.
+
+ This function will only allocate memory if the number of elements in the
+ range, or, for non-UTF-16-encoded input, the maximum possible size of the
+ resulting string, exceeds the capacity of this string, or if this string is
+ shared.
+
+ \note This function overload only participates in overload resolution if
+ \c InputIterator meets the requirements of a
+ \l {https://en.cppreference.com/w/cpp/named_req/InputIterator} {LegacyInputIterator}
+ and the \c{value_type} of \c InputIterator is one of the following character types:
+ \list
+ \li QChar
+ \li QLatin1Char
+ \li \c {char}
+ \li \c {unsigned char}
+ \li \c {signed char}
+ \li \c {char8_t}
+ \li \c char16_t
+ \li (on platforms, such as Windows, where it is a 16-bit type) \c wchar_t
+ \li \c char32_t
+ \endlist
+
+ \note The behavior is undefined if either argument is an iterator into *this or
+ [\a first, \a last) is not a valid range.
+*/
+
+QString &QString::assign(QAnyStringView s)
+{
+ if (s.size() <= capacity() && isDetached()) {
+ const auto offset = d.freeSpaceAtBegin();
+ if (offset)
+ d.setBegin(d.begin() - offset);
+ resize(0);
+ s.visit([this](auto input) {
+ this->append(input);
+ });
+ } else {
+ *this = s.toString();
+ }
+ return *this;
+}
+
+#ifndef QT_BOOTSTRAPPED
+QString &QString::assign_helper(const char32_t *data, qsizetype len)
+{
+ // worst case: each char32_t requires a surrogate pair, so
+ const auto requiredCapacity = len * 2;
+ if (requiredCapacity <= capacity() && isDetached()) {
+ const auto offset = d.freeSpaceAtBegin();
+ if (offset)
+ d.setBegin(d.begin() - offset);
+ auto begin = reinterpret_cast<QChar *>(d.begin());
+ auto ba = QByteArrayView(reinterpret_cast<const std::byte*>(data), len * sizeof(char32_t));
+ QStringConverter::State state;
+ const auto end = QUtf32::convertToUnicode(begin, ba, &state, DetectEndianness);
+ d.size = end - begin;
+ d.data()[d.size] = u'\0';
+ } else {
+ *this = QString::fromUcs4(data, len);
+ }
+ return *this;
+}
+#endif
+
+/*!
\fn QString &QString::remove(qsizetype position, qsizetype n)
Removes \a n characters from the string, starting at the given \a
@@ -3522,7 +3654,7 @@ QString &QString::remove(QChar ch, Qt::CaseSensitivity cs)
it = std::remove_copy_if(first_match + 1, end, it, match);
copy.d.size = std::distance(dst, it);
copy.d.data()[copy.d.size] = u'\0';
- *this = copy;
+ *this = std::move(copy);
}
return *this;
}
@@ -3557,7 +3689,7 @@ QString &QString::remove(QChar ch, Qt::CaseSensitivity cs)
and there isn't enough capacity, create a new string, copy characters to it
as needed, then swap it with "str".
*/
-static void replace_with_copy(QString &str, size_t *indices, qsizetype nIndices, qsizetype blen,
+static void replace_with_copy(QString &str, QSpan<size_t> indices, qsizetype blen,
QStringView after)
{
const qsizetype alen = after.size();
@@ -3565,12 +3697,12 @@ static void replace_with_copy(QString &str, size_t *indices, qsizetype nIndices,
const QString::DataPointer &str_d = str.data_ptr();
auto src_start = str_d.begin();
- const qsizetype newSize = str_d.size + nIndices * (alen - blen);
+ const qsizetype newSize = str_d.size + indices.size() * (alen - blen);
QString copy{ newSize, Qt::Uninitialized };
QString::DataPointer &copy_d = copy.data_ptr();
auto dst = copy_d.begin();
- for (int i = 0; i < nIndices; ++i) {
- auto hit = str_d.begin() + indices[i];
+ for (size_t index : indices) {
+ auto hit = str_d.begin() + index;
dst = std::copy(src_start, hit, dst);
dst = std::copy_n(after_b, alen, dst);
src_start = hit + blen;
@@ -3580,7 +3712,7 @@ static void replace_with_copy(QString &str, size_t *indices, qsizetype nIndices,
}
// No detaching or reallocation is needed
-static void replace_in_place(QString &str, size_t *indices, qsizetype nIndices,
+static void replace_in_place(QString &str, QSpan<size_t> indices,
qsizetype blen, QStringView after)
{
const qsizetype alen = after.size();
@@ -3588,16 +3720,16 @@ static void replace_in_place(QString &str, size_t *indices, qsizetype nIndices,
const char16_t *after_e = after.utf16() + after.size();
if (blen == alen) { // Replace in place
- for (qsizetype i = 0; i < nIndices; ++i)
- std::copy_n(after_b, alen, str.data_ptr().begin() + indices[i]);
+ for (size_t index : indices)
+ std::copy_n(after_b, alen, str.data_ptr().begin() + index);
} else if (blen > alen) { // Replace from front
char16_t *begin = str.data_ptr().begin();
- char16_t *hit = begin + indices[0];
+ char16_t *hit = begin + indices.front();
char16_t *to = hit;
to = std::copy_n(after_b, alen, to);
char16_t *movestart = hit + blen;
- for (qsizetype i = 1; i < nIndices; ++i) {
- hit = begin + indices[i];
+ for (size_t index : indices.sliced(1)) {
+ hit = begin + index;
to = std::move(movestart, hit, to);
to = std::copy_n(after_b, alen, to);
movestart = hit + blen;
@@ -3606,7 +3738,7 @@ static void replace_in_place(QString &str, size_t *indices, qsizetype nIndices,
str.resize(std::distance(begin, to));
} else { // blen < alen, Replace from back
const qsizetype oldSize = str.data_ptr().size;
- const qsizetype adjust = nIndices * (alen - blen);
+ const qsizetype adjust = indices.size() * (alen - blen);
const qsizetype newSize = oldSize + adjust;
str.resize(newSize);
@@ -3614,9 +3746,8 @@ static void replace_in_place(QString &str, size_t *indices, qsizetype nIndices,
char16_t *moveend = begin + oldSize;
char16_t *to = str.data_ptr().end();
- while (nIndices) {
- --nIndices;
- char16_t *hit = begin + indices[nIndices];
+ for (auto it = indices.rbegin(), end = indices.rend(); it != end; ++it) {
+ char16_t *hit = begin + *it;
char16_t *movestart = hit + blen;
to = std::move_backward(movestart, moveend, to);
to = std::copy_backward(after_b, after_e, to);
@@ -3625,22 +3756,22 @@ static void replace_in_place(QString &str, size_t *indices, qsizetype nIndices,
}
}
-static void replace_helper(QString &str, size_t *indices, qsizetype nIndices, qsizetype blen, QStringView after)
+static void replace_helper(QString &str, QSpan<size_t> indices, qsizetype blen, QStringView after)
{
const qsizetype oldSize = str.data_ptr().size;
- const qsizetype adjust = nIndices * (after.size() - blen);
+ const qsizetype adjust = indices.size() * (after.size() - blen);
const qsizetype newSize = oldSize + adjust;
if (str.data_ptr().needsDetach() || needsReallocate(str, newSize)) {
- replace_with_copy(str, indices, nIndices, blen, after);
+ replace_with_copy(str, indices, blen, after);
return;
}
if (QtPrivate::q_points_into_range(after.begin(), str))
// Copy after if it lies inside our own d.b area (which we could
// possibly invalidate via a realloc or modify by replacement)
- replace_in_place(str, indices, nIndices, blen, QVarLengthArray(after.begin(), after.end()));
+ replace_in_place(str, indices, blen, QVarLengthArray(after.begin(), after.end()));
else
- replace_in_place(str, indices, nIndices, blen, after);
+ replace_in_place(str, indices, blen, after);
}
/*!
@@ -3679,7 +3810,7 @@ QString &QString::replace(qsizetype pos, qsizetype len, const QChar *after, qsiz
len = this->size() - pos;
size_t index = pos;
- replace_helper(*this, &index, 1, len, QStringView{after, alen});
+ replace_helper(*this, QSpan(&index, 1), len, QStringView{after, alen});
return *this;
}
@@ -3758,7 +3889,7 @@ QString &QString::replace(const QChar *before, qsizetype blen,
if (indices.isEmpty())
return *this;
- replace_helper(*this, indices.data(), indices.size(), blen, QStringView{after, alen});
+ replace_helper(*this, indices, blen, QStringView{after, alen});
return *this;
}
@@ -3800,7 +3931,7 @@ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs
if (indices.isEmpty())
return *this;
- replace_helper(*this, indices.data(), indices.size(), 1, after);
+ replace_helper(*this, indices, 1, after);
return *this;
}
@@ -3939,10 +4070,10 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
}
/*!
- \fn bool QString::operator==(const QString &s1, const QString &s2)
+ \fn bool QString::operator==(const QString &lhs, const QString &rhs)
\overload operator==()
- Returns \c true if string \a s1 is equal to string \a s2; otherwise
+ Returns \c true if string \a lhs is equal to string \a rhs; otherwise
returns \c false.
\include qstring.cpp compare-isNull-vs-isEmpty
@@ -3951,45 +4082,43 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
*/
/*!
- \fn bool QString::operator==(const QString &s1, QLatin1StringView s2)
+ \fn bool QString::operator==(const QString &lhs, const QLatin1StringView &rhs)
\overload operator==()
- Returns \c true if \a s1 is equal to \a s2; otherwise
+ Returns \c true if \a lhs is equal to \a rhs; otherwise
returns \c false.
*/
/*!
- \fn bool QString::operator==(QLatin1StringView s1, const QString &s2)
+ \fn bool QString::operator==(const QLatin1StringView &lhs, const QString &rhs)
\overload operator==()
- Returns \c true if \a s1 is equal to \a s2; otherwise
+ Returns \c true if \a lhs is equal to \a rhs; otherwise
returns \c false.
*/
-/*! \fn bool QString::operator==(const QByteArray &other) const
+/*! \fn bool QString::operator==(const QString &lhs, const QByteArray &rhs)
\overload operator==()
- The \a other byte array is converted to a QString using the
- fromUtf8() function.
+ The \a rhs byte array is converted to a QUtf8StringView.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
can be useful if you want to ensure that all user-visible strings
go through QObject::tr(), for example.
- Returns \c true if this string is lexically equal to the parameter
- string \a other. Otherwise returns \c false.
+ Returns \c true if string \a lhs is lexically equal to \a rhs.
+ Otherwise returns \c false.
*/
-/*! \fn bool QString::operator==(const char *other) const
+/*! \fn bool QString::operator==(const QString &lhs, const char * const &rhs)
\overload operator==()
- The \a other const char pointer is converted to a QString using
- the fromUtf8() function.
+ The \a rhs const char pointer is converted to a QUtf8StringView.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -3998,41 +4127,41 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
*/
/*!
- \fn bool QString::operator<(const QString &s1, const QString &s2)
+ \fn bool QString::operator<(const QString &lhs, const QString &rhs)
\overload operator<()
- Returns \c true if string \a s1 is lexically less than string
- \a s2; otherwise returns \c false.
+ Returns \c true if string \a lhs is lexically less than string
+ \a rhs; otherwise returns \c false.
\sa {Comparing Strings}
*/
/*!
- \fn bool QString::operator<(const QString &s1, QLatin1StringView s2)
+ \fn bool QString::operator<(const QString &lhs, const QLatin1StringView &rhs)
\overload operator<()
- Returns \c true if \a s1 is lexically less than \a s2;
+ Returns \c true if \a lhs is lexically less than \a rhs;
otherwise returns \c false.
*/
/*!
- \fn bool QString::operator<(QLatin1StringView s1, const QString &s2)
+ \fn bool QString::operator<(const QLatin1StringView &lhs, const QString &rhs)
\overload operator<()
- Returns \c true if \a s1 is lexically less than \a s2;
+ Returns \c true if \a lhs is lexically less than \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QString::operator<(const QByteArray &other) const
+/*! \fn bool QString::operator<(const QString &lhs, const QByteArray &rhs)
\overload operator<()
- The \a other byte array is converted to a QString using the
- fromUtf8() function. If any NUL characters ('\\0') are embedded
- in the byte array, they will be included in the transformation.
+ The \a rhs byte array is converted to a QUtf8StringView.
+ If any NUL characters ('\\0') are embedded in the byte array, they will be
+ included in the transformation.
You can disable this operator
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -4040,15 +4169,14 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
go through QObject::tr(), for example.
*/
-/*! \fn bool QString::operator<(const char *other) const
+/*! \fn bool QString::operator<(const QString &lhs, const char * const &rhs)
- Returns \c true if this string is lexically less than string \a other.
+ Returns \c true if string \a lhs is lexically less than string \a rhs.
Otherwise returns \c false.
\overload operator<()
- The \a other const char pointer is converted to a QString using
- the fromUtf8() function.
+ The \a rhs const char pointer is converted to a QUtf8StringView.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -4056,39 +4184,39 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
go through QObject::tr(), for example.
*/
-/*! \fn bool QString::operator<=(const QString &s1, const QString &s2)
+/*! \fn bool QString::operator<=(const QString &lhs, const QString &rhs)
- Returns \c true if string \a s1 is lexically less than or equal to
- string \a s2; otherwise returns \c false.
+ Returns \c true if string \a lhs is lexically less than or equal to
+ string \a rhs; otherwise returns \c false.
\sa {Comparing Strings}
*/
/*!
- \fn bool QString::operator<=(const QString &s1, QLatin1StringView s2)
+ \fn bool QString::operator<=(const QString &lhs, const QLatin1StringView &rhs)
\overload operator<=()
- Returns \c true if \a s1 is lexically less than or equal to \a s2;
+ Returns \c true if \a lhs is lexically less than or equal to \a rhs;
otherwise returns \c false.
*/
/*!
- \fn bool QString::operator<=(QLatin1StringView s1, const QString &s2)
+ \fn bool QString::operator<=(const QLatin1StringView &lhs, const QString &rhs)
\overload operator<=()
- Returns \c true if \a s1 is lexically less than or equal to \a s2;
+ Returns \c true if \a lhs is lexically less than or equal to \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QString::operator<=(const QByteArray &other) const
+/*! \fn bool QString::operator<=(const QString &lhs, const QByteArray &rhs)
\overload operator<=()
- The \a other byte array is converted to a QString using the
- fromUtf8() function. If any NUL characters ('\\0') are embedded
- in the byte array, they will be included in the transformation.
+ The \a rhs byte array is converted to a QUtf8StringView.
+ If any NUL characters ('\\0') are embedded in the byte array, they will be
+ included in the transformation.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -4096,12 +4224,11 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
go through QObject::tr(), for example.
*/
-/*! \fn bool QString::operator<=(const char *other) const
+/*! \fn bool QString::operator<=(const QString &lhs, const char * const &rhs)
\overload operator<=()
- The \a other const char pointer is converted to a QString using
- the fromUtf8() function.
+ The \a rhs const char pointer is converted to a QUtf8StringView.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -4109,39 +4236,39 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
go through QObject::tr(), for example.
*/
-/*! \fn bool QString::operator>(const QString &s1, const QString &s2)
+/*! \fn bool QString::operator>(const QString &lhs, const QString &rhs)
- Returns \c true if string \a s1 is lexically greater than string \a s2;
+ Returns \c true if string \a lhs is lexically greater than string \a rhs;
otherwise returns \c false.
\sa {Comparing Strings}
*/
/*!
- \fn bool QString::operator>(const QString &s1, QLatin1StringView s2)
+ \fn bool QString::operator>(const QString &lhs, const QLatin1StringView &rhs)
\overload operator>()
- Returns \c true if \a s1 is lexically greater than \a s2;
+ Returns \c true if \a lhs is lexically greater than \a rhs;
otherwise returns \c false.
*/
/*!
- \fn bool QString::operator>(QLatin1StringView s1, const QString &s2)
+ \fn bool QString::operator>(const QLatin1StringView &lhs, const QString &rhs)
\overload operator>()
- Returns \c true if \a s1 is lexically greater than \a s2;
+ Returns \c true if \a lhs is lexically greater than \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QString::operator>(const QByteArray &other) const
+/*! \fn bool QString::operator>(const QString &lhs, const QByteArray &rhs)
\overload operator>()
- The \a other byte array is converted to a QString using the
- fromUtf8() function. If any NUL characters ('\\0') are embedded
- in the byte array, they will be included in the transformation.
+ The \a rhs byte array is converted to a QUtf8StringView.
+ If any NUL characters ('\\0') are embedded in the byte array, they will be
+ included in the transformation.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -4149,12 +4276,11 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
go through QObject::tr(), for example.
*/
-/*! \fn bool QString::operator>(const char *other) const
+/*! \fn bool QString::operator>(const QString &lhs, const char * const &rhs)
\overload operator>()
- The \a other const char pointer is converted to a QString using
- the fromUtf8() function.
+ The \a rhs const char pointer is converted to a QUtf8StringView.
You can disable this operator by defining \l QT_NO_CAST_FROM_ASCII
when you compile your applications. This can be useful if you want
@@ -4162,39 +4288,39 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
for example.
*/
-/*! \fn bool QString::operator>=(const QString &s1, const QString &s2)
+/*! \fn bool QString::operator>=(const QString &lhs, const QString &rhs)
- Returns \c true if string \a s1 is lexically greater than or equal to
- string \a s2; otherwise returns \c false.
+ Returns \c true if string \a lhs is lexically greater than or equal to
+ string \a rhs; otherwise returns \c false.
\sa {Comparing Strings}
*/
/*!
- \fn bool QString::operator>=(const QString &s1, QLatin1StringView s2)
+ \fn bool QString::operator>=(const QString &lhs, const QLatin1StringView &rhs)
\overload operator>=()
- Returns \c true if \a s1 is lexically greater than or equal to \a s2;
+ Returns \c true if \a lhs is lexically greater than or equal to \a rhs;
otherwise returns \c false.
*/
/*!
- \fn bool QString::operator>=(QLatin1StringView s1, const QString &s2)
+ \fn bool QString::operator>=(const QLatin1StringView &lhs, const QString &rhs)
\overload operator>=()
- Returns \c true if \a s1 is lexically greater than or equal to \a s2;
+ Returns \c true if \a lhs is lexically greater than or equal to \a rhs;
otherwise returns \c false.
*/
-/*! \fn bool QString::operator>=(const QByteArray &other) const
+/*! \fn bool QString::operator>=(const QString &lhs, const QByteArray &rhs)
\overload operator>=()
- The \a other byte array is converted to a QString using the
- fromUtf8() function. If any NUL characters ('\\0') are embedded in
- the byte array, they will be included in the transformation.
+ The \a rhs byte array is converted to a QUtf8StringView.
+ If any NUL characters ('\\0') are embedded in the byte array, they will be
+ included in the transformation.
You can disable this operator by defining \l QT_NO_CAST_FROM_ASCII
when you compile your applications. This can be useful if you want
@@ -4202,12 +4328,11 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
for example.
*/
-/*! \fn bool QString::operator>=(const char *other) const
+/*! \fn bool QString::operator>=(const QString &lhs, const char * const &rhs)
\overload operator>=()
- The \a other const char pointer is converted to a QString using
- the fromUtf8() function.
+ The \a rhs const char pointer is converted to a QUtf8StringView.
You can disable this operator by defining \l QT_NO_CAST_FROM_ASCII
when you compile your applications. This can be useful if you want
@@ -4215,29 +4340,29 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
for example.
*/
-/*! \fn bool QString::operator!=(const QString &s1, const QString &s2)
+/*! \fn bool QString::operator!=(const QString &lhs, const QString &rhs)
- Returns \c true if string \a s1 is not equal to string \a s2;
+ Returns \c true if string \a lhs is not equal to string \a rhs;
otherwise returns \c false.
\sa {Comparing Strings}
*/
-/*! \fn bool QString::operator!=(const QString &s1, QLatin1StringView s2)
+/*! \fn bool QString::operator!=(const QString &lhs, const QLatin1StringView &rhs)
- Returns \c true if string \a s1 is not equal to string \a s2.
+ Returns \c true if string \a lhs is not equal to string \a rhs.
Otherwise returns \c false.
\overload operator!=()
*/
-/*! \fn bool QString::operator!=(const QByteArray &other) const
+/*! \fn bool QString::operator!=(const QString &lhs, const QByteArray &rhs)
\overload operator!=()
- The \a other byte array is converted to a QString using the
- fromUtf8() function. If any NUL characters ('\\0') are embedded
- in the byte array, they will be included in the transformation.
+ The \a rhs byte array is converted to a QUtf8StringView.
+ If any NUL characters ('\\0') are embedded in the byte array, they will be
+ included in the transformation.
You can disable this operator by defining \l QT_NO_CAST_FROM_ASCII
when you compile your applications. This can be useful if you want
@@ -4245,12 +4370,11 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
for example.
*/
-/*! \fn bool QString::operator!=(const char *other) const
+/*! \fn bool QString::operator!=(const QString &lhs, const char * const &rhs)
\overload operator!=()
- The \a other const char pointer is converted to a QString using
- the fromUtf8() function.
+ The \a rhs const char pointer is converted to a QUtf8StringView.
You can disable this operator by defining
\l QT_NO_CAST_FROM_ASCII when you compile your applications. This
@@ -4258,6 +4382,90 @@ QString &QString::replace(QChar c, QLatin1StringView after, Qt::CaseSensitivity
go through QObject::tr(), for example.
*/
+/*! \fn bool QString::operator==(const QByteArray &lhs, const QString &rhs)
+
+ Returns \c true if byte array \a lhs is equal to the UTF-8 encoding of
+ \a rhs; otherwise returns \c false.
+
+ The comparison is case sensitive.
+
+ You can disable this operator by defining \c
+ QT_NO_CAST_FROM_ASCII when you compile your applications. You
+ then need to call QString::fromUtf8(), QString::fromLatin1(),
+ or QString::fromLocal8Bit() explicitly if you want to convert the byte
+ array to a QString before doing the comparison.
+*/
+
+/*! \fn bool QString::operator!=(const QByteArray &lhs, const QString &rhs)
+
+ Returns \c true if byte array \a lhs is not equal to the UTF-8 encoding of
+ \a rhs; otherwise returns \c false.
+
+ The comparison is case sensitive.
+
+ You can disable this operator by defining \c
+ QT_NO_CAST_FROM_ASCII when you compile your applications. You
+ then need to call QString::fromUtf8(), QString::fromLatin1(),
+ or QString::fromLocal8Bit() explicitly if you want to convert the byte
+ array to a QString before doing the comparison.
+*/
+
+/*! \fn bool QString::operator<(const QByteArray &lhs, const QString &rhs)
+
+ Returns \c true if byte array \a lhs is lexically less than the UTF-8 encoding
+ of \a rhs; otherwise returns \c false.
+
+ The comparison is case sensitive.
+
+ You can disable this operator by defining \c
+ QT_NO_CAST_FROM_ASCII when you compile your applications. You
+ then need to call QString::fromUtf8(), QString::fromLatin1(),
+ or QString::fromLocal8Bit() explicitly if you want to convert the byte
+ array to a QString before doing the comparison.
+*/
+
+/*! \fn bool QString::operator>(const QByteArray &lhs, const QString &rhs)
+
+ Returns \c true if byte array \a lhs is lexically greater than the UTF-8
+ encoding of \a rhs; otherwise returns \c false.
+
+ The comparison is case sensitive.
+
+ You can disable this operator by defining \c
+ QT_NO_CAST_FROM_ASCII when you compile your applications. You
+ then need to call QString::fromUtf8(), QString::fromLatin1(),
+ or QString::fromLocal8Bit() explicitly if you want to convert the byte
+ array to a QString before doing the comparison.
+*/
+
+/*! \fn bool QString::operator<=(const QByteArray &lhs, const QString &rhs)
+
+ Returns \c true if byte array \a lhs is lexically less than or equal to the
+ UTF-8 encoding of \a rhs; otherwise returns \c false.
+
+ The comparison is case sensitive.
+
+ You can disable this operator by defining \c
+ QT_NO_CAST_FROM_ASCII when you compile your applications. You
+ then need to call QString::fromUtf8(), QString::fromLatin1(),
+ or QString::fromLocal8Bit() explicitly if you want to convert the byte
+ array to a QString before doing the comparison.
+*/
+
+/*! \fn bool QString::operator>=(const QByteArray &lhs, const QString &rhs)
+
+ Returns \c true if byte array \a lhs is greater than or equal to the UTF-8
+ encoding of \a rhs; otherwise returns \c false.
+
+ The comparison is case sensitive.
+
+ You can disable this operator by defining \c
+ QT_NO_CAST_FROM_ASCII when you compile your applications. You
+ then need to call QString::fromUtf8(), QString::fromLatin1(),
+ or QString::fromLocal8Bit() explicitly if you want to convert the byte
+ array to a QString before doing the comparison.
+*/
+
/*!
\include qstring.qdocinc {qstring-first-index-of} {string} {str}
@@ -4312,14 +4520,11 @@ qsizetype QString::indexOf(QLatin1StringView str, qsizetype from, Qt::CaseSensit
}
/*!
+ \fn qsizetype QString::indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const
\overload indexOf()
\include qstring.qdocinc {qstring-first-index-of} {character} {ch}
*/
-qsizetype QString::indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const
-{
- return qFindChar(QStringView(unicode(), size()), ch, from, cs);
-}
/*!
\include qstring.qdocinc {qstring-last-index-of} {string} {str}
@@ -4414,14 +4619,11 @@ qsizetype QString::lastIndexOf(QLatin1StringView str, qsizetype from, Qt::CaseSe
*/
/*!
+ \fn qsizetype QString::lastIndexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const
\overload lastIndexOf()
\include qstring.qdocinc {qstring-last-index-of} {character} {ch}
*/
-qsizetype QString::lastIndexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const
-{
- return qLastIndexOf(QStringView(*this), ch, from, cs);
-}
/*!
\fn QString::lastIndexOf(QChar ch, Qt::CaseSensitivity) const
@@ -4510,7 +4712,7 @@ QString &QString::replace(const QRegularExpression &re, const QString &after)
// 1. build the backreferences list, holding where the backreferences
// are in the replacement string
- QList<QStringCapture> backReferences;
+ QVarLengthArray<QStringCapture> backReferences;
const qsizetype al = after.size();
const QChar *ac = after.unicode();
@@ -4542,7 +4744,7 @@ QString &QString::replace(const QRegularExpression &re, const QString &after)
qsizetype newLength = 0; // length of the new string, with all the replacements
qsizetype lastEnd = 0;
- QList<QStringView> chunks;
+ QVarLengthArray<QStringView> chunks;
const QStringView copyView{ copy }, afterView{ after };
while (iterator.hasNext()) {
QRegularExpressionMatch match = iterator.next();
@@ -4941,7 +5143,7 @@ public:
};
Q_DECLARE_TYPEINFO(qt_section_chunk, Q_RELOCATABLE_TYPE);
-static QString extractSections(const QList<qt_section_chunk> &sections, qsizetype start, qsizetype end,
+static QString extractSections(QSpan<qt_section_chunk> sections, qsizetype start, qsizetype end,
QString::SectionFlags flags)
{
const qsizetype sectionsSize = sections.size();
@@ -4954,7 +5156,7 @@ static QString extractSections(const QList<qt_section_chunk> &sections, qsizetyp
} else {
qsizetype skip = 0;
for (qsizetype k = 0; k < sectionsSize; ++k) {
- const qt_section_chunk &section = sections.at(k);
+ const qt_section_chunk &section = sections[k];
if (section.length == section.string.size())
skip++;
}
@@ -4970,7 +5172,7 @@ static QString extractSections(const QList<qt_section_chunk> &sections, qsizetyp
qsizetype x = 0;
qsizetype first_i = start, last_i = end;
for (qsizetype i = 0; x <= end && i < sectionsSize; ++i) {
- const qt_section_chunk &section = sections.at(i);
+ const qt_section_chunk &section = sections[i];
const bool empty = (section.length == section.string.size());
if (x >= start) {
if (x == start)
@@ -4987,13 +5189,13 @@ static QString extractSections(const QList<qt_section_chunk> &sections, qsizetyp
}
if ((flags & QString::SectionIncludeLeadingSep) && first_i >= 0) {
- const qt_section_chunk &section = sections.at(first_i);
+ const qt_section_chunk &section = sections[first_i];
ret.prepend(section.string.left(section.length));
}
if ((flags & QString::SectionIncludeTrailingSep)
&& last_i < sectionsSize - 1) {
- const qt_section_chunk &section = sections.at(last_i+1);
+ const qt_section_chunk &section = sections[last_i + 1];
ret += section.string.left(section.length);
}
@@ -5029,7 +5231,7 @@ QString QString::section(const QRegularExpression &re, qsizetype start, qsizetyp
if (flags & SectionCaseInsensitiveSeps)
sep.setPatternOptions(sep.patternOptions() | QRegularExpression::CaseInsensitiveOption);
- QList<qt_section_chunk> sections;
+ QVarLengthArray<qt_section_chunk> sections;
qsizetype n = size(), m = 0, last_m = 0, last_len = 0;
QRegularExpressionMatchIterator iterator = sep.globalMatch(*this);
while (iterator.hasNext()) {
@@ -5046,6 +5248,9 @@ QString QString::section(const QRegularExpression &re, qsizetype start, qsizetyp
#endif // QT_CONFIG(regularexpression)
/*!
+ \fn QString QString::left(qsizetype n) const &
+ \fn QString QString::left(qsizetype n) &&
+
Returns a substring that contains the \a n leftmost characters
of the string.
@@ -5057,14 +5262,11 @@ QString QString::section(const QRegularExpression &re, qsizetype start, qsizetyp
\sa first(), last(), startsWith(), chopped(), chop(), truncate()
*/
-QString QString::left(qsizetype n) const
-{
- if (size_t(n) >= size_t(size()))
- return *this;
- return QString((const QChar*) d.data(), n);
-}
/*!
+ \fn QString QString::right(qsizetype n) const &
+ \fn QString QString::right(qsizetype n) &&
+
Returns a substring that contains the \a n rightmost characters
of the string.
@@ -5074,16 +5276,13 @@ QString QString::left(qsizetype n) const
The entire string is returned if \a n is greater than or equal
to size(), or less than zero.
- \sa endsWith(), last(), first(), sliced(), chopped(), chop(), truncate()
+ \sa endsWith(), last(), first(), sliced(), chopped(), chop(), truncate(), slice()
*/
-QString QString::right(qsizetype n) const
-{
- if (size_t(n) >= size_t(size()))
- return *this;
- return QString(constData() + size() - n, n);
-}
/*!
+ \fn QString QString::mid(qsizetype position, qsizetype n) const &
+ \fn QString QString::mid(qsizetype position, qsizetype n) &&
+
Returns a string that contains \a n characters of this string,
starting at the specified \a position index.
@@ -5096,11 +5295,9 @@ QString QString::right(qsizetype n) const
\a n is -1 (default), the function returns all characters that
are available from the specified \a position.
-
- \sa first(), last(), sliced(), chopped(), chop(), truncate()
+ \sa first(), last(), sliced(), chopped(), chop(), truncate(), slice()
*/
-
-QString QString::mid(qsizetype position, qsizetype n) const
+QString QString::mid(qsizetype position, qsizetype n) const &
{
qsizetype p = position;
qsizetype l = n;
@@ -5113,13 +5310,33 @@ QString QString::mid(qsizetype position, qsizetype n) const
case QContainerImplHelper::Full:
return *this;
case QContainerImplHelper::Subset:
- return QString(constData() + p, l);
+ return sliced(p, l);
+ }
+ Q_UNREACHABLE_RETURN(QString());
+}
+
+QString QString::mid(qsizetype position, qsizetype n) &&
+{
+ qsizetype p = position;
+ qsizetype l = n;
+ using namespace QtPrivate;
+ switch (QContainerImplHelper::mid(size(), &p, &l)) {
+ case QContainerImplHelper::Null:
+ return QString();
+ case QContainerImplHelper::Empty:
+ resize(0); // keep capacity if we've reserve()d
+ [[fallthrough]];
+ case QContainerImplHelper::Full:
+ return std::move(*this);
+ case QContainerImplHelper::Subset:
+ return std::move(*this).sliced(p, l);
}
Q_UNREACHABLE_RETURN(QString());
}
/*!
- \fn QString QString::first(qsizetype n) const
+ \fn QString QString::first(qsizetype n) const &
+ \fn QString QString::first(qsizetype n) &&
\since 6.0
Returns a string that contains the first \a n characters
@@ -5129,11 +5346,12 @@ QString QString::mid(qsizetype position, qsizetype n) const
\snippet qstring/main.cpp 31
- \sa last(), sliced(), startsWith(), chopped(), chop(), truncate()
+ \sa last(), sliced(), startsWith(), chopped(), chop(), truncate(), slice()
*/
/*!
- \fn QString QString::last(qsizetype n) const
+ \fn QString QString::last(qsizetype n) const &
+ \fn QString QString::last(qsizetype n) &&
\since 6.0
Returns the string that contains the last \a n characters of this string.
@@ -5142,11 +5360,12 @@ QString QString::mid(qsizetype position, qsizetype n) const
\snippet qstring/main.cpp 48
- \sa first(), sliced(), endsWith(), chopped(), chop(), truncate()
+ \sa first(), sliced(), endsWith(), chopped(), chop(), truncate(), slice()
*/
/*!
- \fn QString QString::sliced(qsizetype pos, qsizetype n) const
+ \fn QString QString::sliced(qsizetype pos, qsizetype n) const &
+ \fn QString QString::sliced(qsizetype pos, qsizetype n) &&
\since 6.0
Returns a string that contains \a n characters of this string,
@@ -5157,11 +5376,20 @@ QString QString::mid(qsizetype position, qsizetype n) const
\snippet qstring/main.cpp 34
- \sa first(), last(), chopped(), chop(), truncate()
+ \sa first(), last(), chopped(), chop(), truncate(), slice()
*/
+QString QString::sliced_helper(QString &str, qsizetype pos, qsizetype n)
+{
+ if (n == 0)
+ return QString(DataPointer::fromRawData(&_empty, 0));
+ DataPointer d = std::move(str.d).sliced(pos, n);
+ d.data()[n] = 0;
+ return QString(std::move(d));
+}
/*!
- \fn QString QString::sliced(qsizetype pos) const
+ \fn QString QString::sliced(qsizetype pos) const &
+ \fn QString QString::sliced(qsizetype pos) &&
\since 6.0
\overload
@@ -5170,11 +5398,40 @@ QString QString::mid(qsizetype position, qsizetype n) const
\note The behavior is undefined when \a pos < 0 or \a pos > size().
- \sa first(), last(), sliced(), chopped(), chop(), truncate()
+ \sa first(), last(), chopped(), chop(), truncate(), slice()
+*/
+
+/*!
+ \fn QString &QString::slice(qsizetype pos, qsizetype n)
+ \since 6.8
+
+ Modifies this string to start at position \a pos, extending for \a n
+ characters (code points), and returns a reference to this string.
+
+ \note The behavior is undefined if \a pos < 0, \a n < 0,
+ or \a pos + \a n > size().
+
+ \snippet qstring/main.cpp 86
+
+ \sa sliced(), first(), last(), chopped(), chop(), truncate()
+*/
+
+/*!
+ \fn QString &QString::slice(qsizetype pos)
+ \since 6.8
+ \overload
+
+ Modifies this string to start at position \a pos and extending to its end,
+ and returns a reference to this string.
+
+ \note The behavior is undefined if \a pos < 0 or \a pos > size().
+
+ \sa sliced(), first(), last(), chopped(), chop(), truncate()
*/
/*!
- \fn QString QString::chopped(qsizetype len) const
+ \fn QString QString::chopped(qsizetype len) const &
+ \fn QString QString::chopped(qsizetype len) &&
\since 5.10
Returns a string that contains the size() - \a len leftmost characters
@@ -5182,7 +5439,7 @@ QString QString::mid(qsizetype position, qsizetype n) const
\note The behavior is undefined if \a len is negative or greater than size().
- \sa endsWith(), first(), last(), sliced(), chop(), truncate()
+ \sa endsWith(), first(), last(), sliced(), chop(), truncate(), slice()
*/
/*!
@@ -5286,6 +5543,27 @@ bool QString::endsWith(QChar c, Qt::CaseSensitivity cs) const
return foldCase(at(size() - 1)) == foldCase(c);
}
+static bool checkCase(QStringView s, QUnicodeTables::Case c) noexcept
+{
+ QStringIterator it(s);
+ while (it.hasNext()) {
+ const char32_t uc = it.next();
+ if (qGetProp(uc)->cases[c].diff)
+ return false;
+ }
+ return true;
+}
+
+bool QtPrivate::isLower(QStringView s) noexcept
+{
+ return checkCase(s, QUnicodeTables::LowerCase);
+}
+
+bool QtPrivate::isUpper(QStringView s) noexcept
+{
+ return checkCase(s, QUnicodeTables::UpperCase);
+}
+
/*!
Returns \c true if the string is uppercase, that is, it's identical
to its toUpper() folding.
@@ -5301,15 +5579,7 @@ bool QString::endsWith(QChar c, Qt::CaseSensitivity cs) const
*/
bool QString::isUpper() const
{
- QStringIterator it(*this);
-
- while (it.hasNext()) {
- const char32_t uc = it.next();
- if (qGetProp(uc)->cases[QUnicodeTables::UpperCase].diff)
- return false;
- }
-
- return true;
+ return QtPrivate::isUpper(qToStringViewIgnoringNull(*this));
}
/*!
@@ -5327,15 +5597,7 @@ bool QString::isUpper() const
*/
bool QString::isLower() const
{
- QStringIterator it(*this);
-
- while (it.hasNext()) {
- const char32_t uc = it.next();
- if (qGetProp(uc)->cases[QUnicodeTables::LowerCase].diff)
- return false;
- }
-
- return true;
+ return QtPrivate::isLower(qToStringViewIgnoringNull(*this));
}
static QByteArray qt_convert_to_latin1(QStringView string);
@@ -5614,7 +5876,7 @@ QString QString::fromLatin1(QByteArrayView ba)
} else if (ba.size() == 0) {
d = DataPointer::fromRawData(&_empty, 0);
} else {
- d = DataPointer(Data::allocate(ba.size()), ba.size());
+ d = DataPointer(ba.size(), ba.size());
Q_CHECK_PTR(d.data());
d.data()[ba.size()] = '\0';
char16_t *dst = d.data();
@@ -5762,6 +6024,7 @@ QString QString::fromUtf8(QByteArrayView ba)
return QUtf8::convertToUnicode(ba);
}
+#ifndef QT_BOOTSTRAPPED
/*!
\since 5.3
Returns a QString initialized with the first \a size characters
@@ -5823,7 +6086,7 @@ QString QString::fromUcs4(const char32_t *unicode, qsizetype size)
QStringDecoder toUtf16(QStringDecoder::Utf32, QStringDecoder::Flag::Stateless);
return toUtf16(QByteArrayView(reinterpret_cast<const char *>(unicode), size * 4));
}
-
+#endif // !QT_BOOTSTRAPPED
/*!
Resizes the string to \a size characters and copies \a unicode
@@ -5888,9 +6151,7 @@ namespace {
template <typename StringView>
StringView qt_trimmed(StringView s) noexcept
{
- auto begin = s.begin();
- auto end = s.end();
- QStringAlgorithms<const StringView>::trimmed_helper_positions(begin, end);
+ const auto [begin, end] = QStringAlgorithms<const StringView>::trimmed_helper_positions(s);
return StringView{begin, end};
}
}
@@ -6097,11 +6358,8 @@ void QString::chop(qsizetype n)
QString& QString::fill(QChar ch, qsizetype size)
{
resize(size < 0 ? d.size : size);
- if (d.size) {
- QChar *i = (QChar*)d.data() + d.size;
- QChar *b = (QChar*)d.data();
- std::fill(b, i, ch);
- }
+ if (d.size)
+ std::fill(d.data(), d.data() + d.size, ch.unicode());
return *this;
}
@@ -6127,6 +6385,16 @@ QString& QString::fill(QChar ch, qsizetype size)
\sa isEmpty(), resize()
*/
+/*!
+ \fn qsizetype QString::max_size()
+ \since 6.8
+
+ This function is provided for STL compatibility.
+ It returns the maximum number of elements that the string can
+ theoretically hold. In practice, the number can be much smaller,
+ limited by the amount of memory available to the system.
+*/
+
/*! \fn bool QString::isNull() const
Returns \c true if this string is null; otherwise returns \c false.
@@ -6229,61 +6497,61 @@ QString& QString::fill(QChar ch, qsizetype size)
*/
/*!
- \fn bool QString::operator==(const char *s1, const QString &s2)
+ \fn bool QString::operator==(const char * const &lhs, const QString &rhs)
\overload operator==()
- Returns \c true if \a s1 is equal to \a s2; otherwise returns \c false.
- Note that no string is equal to \a s1 being 0.
+ Returns \c true if \a lhs is equal to \a rhs; otherwise returns \c false.
+ Note that no string is equal to \a lhs being 0.
- Equivalent to \c {s1 != 0 && compare(s1, s2) == 0}.
+ Equivalent to \c {lhs != 0 && compare(lhs, rhs) == 0}.
*/
/*!
- \fn bool QString::operator!=(const char *s1, const QString &s2)
+ \fn bool QString::operator!=(const char * const &lhs, const QString &rhs)
- Returns \c true if \a s1 is not equal to \a s2; otherwise returns
+ Returns \c true if \a lhs is not equal to \a rhs; otherwise returns
\c false.
- For \a s1 != 0, this is equivalent to \c {compare(} \a s1, \a s2
- \c {) != 0}. Note that no string is equal to \a s1 being 0.
+ For \a lhs != 0, this is equivalent to \c {compare(} \a lhs, \a rhs
+ \c {) != 0}. Note that no string is equal to \a lhs being 0.
*/
/*!
- \fn bool QString::operator<(const char *s1, const QString &s2)
+ \fn bool QString::operator<(const char * const &lhs, const QString &rhs)
- Returns \c true if \a s1 is lexically less than \a s2; otherwise
- returns \c false. For \a s1 != 0, this is equivalent to \c
- {compare(s1, s2) < 0}.
+ Returns \c true if \a lhs is lexically less than \a rhs; otherwise
+ returns \c false. For \a lhs != 0, this is equivalent to \c
+ {compare(lhs, rhs) < 0}.
\sa {Comparing Strings}
*/
/*!
- \fn bool QString::operator<=(const char *s1, const QString &s2)
+ \fn bool QString::operator<=(const char * const &lhs, const QString &rhs)
- Returns \c true if \a s1 is lexically less than or equal to \a s2;
- otherwise returns \c false. For \a s1 != 0, this is equivalent to \c
- {compare(s1, s2) <= 0}.
+ Returns \c true if \a lhs is lexically less than or equal to \a rhs;
+ otherwise returns \c false. For \a lhs != 0, this is equivalent to \c
+ {compare(lhs, rhs) <= 0}.
\sa {Comparing Strings}
*/
/*!
- \fn bool QString::operator>(const char *s1, const QString &s2)
+ \fn bool QString::operator>(const char * const &lhs, const QString &rhs)
- Returns \c true if \a s1 is lexically greater than \a s2; otherwise
- returns \c false. Equivalent to \c {compare(s1, s2) > 0}.
+ Returns \c true if \a lhs is lexically greater than \a rhs; otherwise
+ returns \c false. Equivalent to \c {compare(lhs, rhs) > 0}.
\sa {Comparing Strings}
*/
/*!
- \fn bool QString::operator>=(const char *s1, const QString &s2)
+ \fn bool QString::operator>=(const char * const &lhs, const QString &rhs)
- Returns \c true if \a s1 is lexically greater than or equal to \a s2;
- otherwise returns \c false. For \a s1 != 0, this is equivalent to \c
- {compare(s1, s2) >= 0}.
+ Returns \c true if \a lhs is lexically greater than or equal to \a rhs;
+ otherwise returns \c false. For \a lhs != 0, this is equivalent to \c
+ {compare(lhs, rhs) >= 0}.
\sa {Comparing Strings}
*/
@@ -6323,9 +6591,9 @@ QString& QString::fill(QChar ch, qsizetype size)
\fn int QString::compare(const QString &s1, const QString &s2, Qt::CaseSensitivity cs)
\since 4.2
- Compares \a s1 with \a s2 and returns an integer less than, equal
- to, or greater than zero if \a s1 is less than, equal to, or
- greater than \a s2.
+ Compares the string \a s1 with the string \a s2 and returns a negative integer
+ if \a s1 is less than \a s2, a positive integer if it is greater than \a s2,
+ and zero if they are equal.
\include qstring.qdocinc {search-comparison-case-sensitivity} {comparison}
@@ -6387,10 +6655,9 @@ QString& QString::fill(QChar ch, qsizetype size)
\overload compare()
\since 4.2
- Lexically compares this string with the \a other string and
- returns an integer less than, equal to, or greater than zero if
- this string is less than, equal to, or greater than the other
- string.
+ Lexically compares this string with the string \a other and returns
+ a negative integer if this string is less than \a other, a positive
+ integer if it is greater than \a other, and zero if they are equal.
Same as compare(*this, \a other, \a cs).
*/
@@ -6451,6 +6718,110 @@ int QString::compare_helper(const QChar *data1, qsizetype length1, const char *d
\overload compare()
*/
+bool comparesEqual(const QByteArrayView &lhs, const QChar &rhs) noexcept
+{
+ return QtPrivate::equalStrings(QUtf8StringView(lhs), QStringView(&rhs, 1));
+}
+
+Qt::strong_ordering compareThreeWay(const QByteArrayView &lhs, const QChar &rhs) noexcept
+{
+ const int res = QtPrivate::compareStrings(QUtf8StringView(lhs), QStringView(&rhs, 1));
+ return Qt::compareThreeWay(res, 0);
+}
+
+bool comparesEqual(const QByteArrayView &lhs, char16_t rhs) noexcept
+{
+ return QtPrivate::equalStrings(QUtf8StringView(lhs), QStringView(&rhs, 1));
+}
+
+Qt::strong_ordering compareThreeWay(const QByteArrayView &lhs, char16_t rhs) noexcept
+{
+ const int res = QtPrivate::compareStrings(QUtf8StringView(lhs), QStringView(&rhs, 1));
+ return Qt::compareThreeWay(res, 0);
+}
+
+bool comparesEqual(const QByteArray &lhs, const QChar &rhs) noexcept
+{
+ return QtPrivate::equalStrings(QUtf8StringView(lhs), QStringView(&rhs, 1));
+}
+
+Qt::strong_ordering compareThreeWay(const QByteArray &lhs, const QChar &rhs) noexcept
+{
+ const int res = QtPrivate::compareStrings(QUtf8StringView(lhs), QStringView(&rhs, 1));
+ return Qt::compareThreeWay(res, 0);
+}
+
+bool comparesEqual(const QByteArray &lhs, char16_t rhs) noexcept
+{
+ return QtPrivate::equalStrings(QUtf8StringView(lhs), QStringView(&rhs, 1));
+}
+
+Qt::strong_ordering compareThreeWay(const QByteArray &lhs, char16_t rhs) noexcept
+{
+ const int res = QtPrivate::compareStrings(QUtf8StringView(lhs), QStringView(&rhs, 1));
+ return Qt::compareThreeWay(res, 0);
+}
+
+/*!
+ \internal
+ \since 6.8
+*/
+bool QT_FASTCALL QChar::equal_helper(QChar lhs, const char *rhs) noexcept
+{
+ return QtPrivate::equalStrings(QStringView(&lhs, 1), QUtf8StringView(rhs));
+}
+
+int QT_FASTCALL QChar::compare_helper(QChar lhs, const char *rhs) noexcept
+{
+ return QtPrivate::compareStrings(QStringView(&lhs, 1), QUtf8StringView(rhs));
+}
+
+/*!
+ \internal
+ \since 6.8
+*/
+bool QStringView::equal_helper(QStringView sv, const char *data, qsizetype len)
+{
+ Q_ASSERT(len >= 0);
+ Q_ASSERT(data || len == 0);
+ return QtPrivate::equalStrings(sv, QUtf8StringView(data, len));
+}
+
+/*!
+ \internal
+ \since 6.8
+*/
+int QStringView::compare_helper(QStringView sv, const char *data, qsizetype len)
+{
+ Q_ASSERT(len >= 0);
+ Q_ASSERT(data || len == 0);
+ return QtPrivate::compareStrings(sv, QUtf8StringView(data, len));
+}
+
+/*!
+ \internal
+ \since 6.8
+*/
+bool QLatin1StringView::equal_helper(QLatin1StringView s1, const char *s2, qsizetype len) noexcept
+{
+ // because qlatin1stringview.h can't include qutf8stringview.h
+ Q_ASSERT(len >= 0);
+ Q_ASSERT(s2 || len == 0);
+ return QtPrivate::equalStrings(s1, QUtf8StringView(s2, len));
+}
+
+/*!
+ \internal
+ \since 6.6
+*/
+int QLatin1StringView::compare_helper(const QLatin1StringView &s1, const char *s2, qsizetype len) noexcept
+{
+ // because qlatin1stringview.h can't include qutf8stringview.h
+ Q_ASSERT(len >= 0);
+ Q_ASSERT(s2 || len == 0);
+ return QtPrivate::compareStrings(s1, QUtf8StringView(s2, len));
+}
+
/*!
\internal
\since 4.5
@@ -7275,10 +7646,14 @@ static Int toIntegral(QStringView string, bool *ok, int base)
QVarLengthArray<uchar> latin1(string.size());
qt_to_latin1(latin1.data(), string.utf16(), string.size());
+ QSimpleParsedNumber<Int> r;
if constexpr (std::is_signed_v<Int>)
- return QLocaleData::bytearrayToLongLong(latin1, base, ok);
+ r = QLocaleData::bytearrayToLongLong(latin1, base);
else
- return QLocaleData::bytearrayToUnsLongLong(latin1, base, ok);
+ r = QLocaleData::bytearrayToUnsLongLong(latin1, base);
+ if (ok)
+ *ok = r.ok();
+ return r.result;
}
qlonglong QString::toIntegral_helper(QStringView string, bool *ok, int base)
@@ -7953,6 +8328,7 @@ QStringList QString::split(const QRegularExpression &re, Qt::SplitBehavior behav
}
/*!
+ \overload
\since 6.0
Splits the string into substring views wherever the regular expression \a re
@@ -8103,7 +8479,7 @@ QString QString::normalized(QString::NormalizationForm mode, QChar::UnicodeVersi
return copy;
}
-#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
static void checkArgEscape(QStringView s)
{
// If we're in here, it means that qArgDigitValue has accepted the
@@ -8177,7 +8553,7 @@ static ArgEscapeData findArgEscapes(QStringView s)
// ### Qt 7: do not allow anything but ASCII digits
// in arg()'s replacements.
-#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
+#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
const QChar *escapeBegin = c;
const QChar *escapeEnd = escapeBegin + 1;
#endif
@@ -8189,13 +8565,13 @@ static ArgEscapeData findArgEscapes(QStringView s)
if (next_escape != -1) {
escape = (10 * escape) + next_escape;
++c;
-#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
+#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
++escapeEnd;
#endif
}
}
-#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
+#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
checkArgEscape(QStringView(escapeBegin, escapeEnd));
#endif
@@ -8275,7 +8651,8 @@ static QString replaceArgEscapes(QStringView s, const ArgEscapeData &d, qsizetyp
rc = std::fill_n(rc, pad_chars, fillChar);
}
- memcpy(rc, use.data(), use.size() * sizeof(QChar));
+ if (use.size())
+ memcpy(rc, use.data(), use.size() * sizeof(QChar));
rc += use.size();
if (field_width < 0) { // right padded
@@ -8507,8 +8884,7 @@ QString QString::arg(qlonglong a, int fieldWidth, int base, QChar fillChar) cons
QString arg;
if (d.occurrences > d.locale_occurrences) {
arg = QLocaleData::c()->longLongToString(a, -1, base, fieldWidth, flags);
- Q_ASSERT(fillChar != u'0' || !qIsFinite(a)
- || fieldWidth <= arg.size());
+ Q_ASSERT(fillChar != u'0' || fieldWidth <= arg.size());
}
QString localeArg;
@@ -8517,8 +8893,7 @@ QString QString::arg(qlonglong a, int fieldWidth, int base, QChar fillChar) cons
if (!(locale.numberOptions() & QLocale::OmitGroupSeparator))
flags |= QLocaleData::GroupDigits;
localeArg = locale.d->m_data->longLongToString(a, -1, base, fieldWidth, flags);
- Q_ASSERT(fillChar != u'0' || !qIsFinite(a)
- || fieldWidth <= localeArg.size());
+ Q_ASSERT(fillChar != u'0' || fieldWidth <= localeArg.size());
}
return replaceArgEscapes(*this, d, fieldWidth, arg, localeArg, fillChar);
@@ -8555,8 +8930,7 @@ QString QString::arg(qulonglong a, int fieldWidth, int base, QChar fillChar) con
QString arg;
if (d.occurrences > d.locale_occurrences) {
arg = QLocaleData::c()->unsLongLongToString(a, -1, base, fieldWidth, flags);
- Q_ASSERT(fillChar != u'0' || !qIsFinite(a)
- || fieldWidth <= arg.size());
+ Q_ASSERT(fillChar != u'0' || fieldWidth <= arg.size());
}
QString localeArg;
@@ -8565,8 +8939,7 @@ QString QString::arg(qulonglong a, int fieldWidth, int base, QChar fillChar) con
if (!(locale.numberOptions() & QLocale::OmitGroupSeparator))
flags |= QLocaleData::GroupDigits;
localeArg = locale.d->m_data->unsLongLongToString(a, -1, base, fieldWidth, flags);
- Q_ASSERT(fillChar != u'0' || !qIsFinite(a)
- || fieldWidth <= localeArg.size());
+ Q_ASSERT(fillChar != u'0' || fieldWidth <= localeArg.size());
}
return replaceArgEscapes(*this, d, fieldWidth, arg, localeArg, fillChar);
@@ -8677,7 +9050,7 @@ QString QString::arg(double a, int fieldWidth, char format, int precision, QChar
if (d.occurrences > d.locale_occurrences) {
arg = QLocaleData::c()->doubleToString(a, precision, form, fieldWidth,
flags | QLocaleData::ZeroPadExponent);
- Q_ASSERT(fillChar != u'0' || !qIsFinite(a)
+ Q_ASSERT(fillChar != u'0' || !qt_is_finite(a)
|| fieldWidth <= arg.size());
}
@@ -8693,7 +9066,7 @@ QString QString::arg(double a, int fieldWidth, char format, int precision, QChar
if (numberOptions & QLocale::IncludeTrailingZeroesAfterDot)
flags |= QLocaleData::AddTrailingZeroes;
localeArg = locale.d->m_data->doubleToString(a, precision, form, fieldWidth, flags);
- Q_ASSERT(fillChar != u'0' || !qIsFinite(a)
+ Q_ASSERT(fillChar != u'0' || !qt_is_finite(a)
|| fieldWidth <= localeArg.size());
}
@@ -8704,7 +9077,7 @@ static inline char16_t to_unicode(const QChar c) { return c.unicode(); }
static inline char16_t to_unicode(const char c) { return QLatin1Char{c}.unicode(); }
template <typename Char>
-static int getEscape(const Char *uc, qsizetype *pos, qsizetype len, int maxNumber = 999)
+static int getEscape(const Char *uc, qsizetype *pos, qsizetype len)
{
qsizetype i = *pos;
++i;
@@ -8715,17 +9088,16 @@ static int getEscape(const Char *uc, qsizetype *pos, qsizetype len, int maxNumbe
if (uint(escape) >= 10U)
return -1;
++i;
- while (i < len) {
+ if (i < len) {
+ // there's a second digit
int digit = to_unicode(uc[i]) - '0';
- if (uint(digit) >= 10U)
- break;
- escape = (escape * 10) + digit;
- ++i;
- }
- if (escape <= maxNumber) {
- *pos = i;
- return escape;
+ if (uint(digit) < 10U) {
+ escape = (escape * 10) + digit;
+ ++i;
+ }
}
+ *pos = i;
+ return escape;
}
return -1;
}
@@ -8926,26 +9298,6 @@ QString QtPrivate::argToQString(QLatin1StringView pattern, size_t n, const ArgBa
return argToQStringImpl(pattern, n, args);
}
-/*! \fn bool QString::isSimpleText() const
-
- \internal
-*/
-bool QString::isSimpleText() const
-{
- const char16_t *p = d.data();
- const char16_t * const end = p + d.size;
- while (p < end) {
- char16_t uc = *p;
- // sort out regions of complex text formatting
- if (uc > 0x058f && (uc < 0x1100 || uc > 0xfb0f)) {
- return false;
- }
- p++;
- }
-
- return true;
-}
-
/*! \fn bool QString::isRightToLeft() const
Returns \c true if the string is read right to left.
@@ -9067,6 +9419,7 @@ QString::iterator QString::erase(QString::const_iterator first, QString::const_i
/*!
\fn QString::iterator QString::erase(QString::const_iterator it)
+ \overload
\since 6.5
Removes the character denoted by \c it from the string.
@@ -9192,7 +9545,7 @@ QString &QString::setRawData(const QChar *unicode, qsizetype size)
\sa toUcs4(), toStdWString(), toStdU16String()
*/
-#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
+#if !defined(QT_NO_DATASTREAM)
/*!
\fn QDataStream &operator<<(QDataStream &stream, const QString &string)
\relates QString
@@ -9210,16 +9563,15 @@ QDataStream &operator<<(QDataStream &out, const QString &str)
if (!str.isNull() || out.version() < 3) {
if ((out.byteOrder() == QDataStream::BigEndian) == (QSysInfo::ByteOrder == QSysInfo::BigEndian)) {
out.writeBytes(reinterpret_cast<const char *>(str.unicode()),
- static_cast<uint>(sizeof(QChar) * str.size()));
+ static_cast<qsizetype>(sizeof(QChar) * str.size()));
} else {
QVarLengthArray<char16_t> buffer(str.size());
qbswap<sizeof(char16_t)>(str.constData(), str.size(), buffer.data());
out.writeBytes(reinterpret_cast<const char *>(buffer.data()),
- static_cast<uint>(sizeof(char16_t) * buffer.size()));
+ static_cast<qsizetype>(sizeof(char16_t) * buffer.size()));
}
} else {
- // write null marker
- out << (quint32)0xffffffff;
+ QDataStream::writeQSizeType(out, -1); // write null marker
}
}
return out;
@@ -9241,20 +9593,25 @@ QDataStream &operator>>(QDataStream &in, QString &str)
in >> l;
str = QString::fromLatin1(l);
} else {
- quint32 bytes = 0;
- in >> bytes; // read size of string
- if (bytes == 0xffffffff) { // null string
+ qint64 size = QDataStream::readQSizeType(in);
+ qsizetype bytes = size;
+ if (size != bytes || size < -1) {
str.clear();
- } else if (bytes > 0) { // not empty
+ in.setStatus(QDataStream::SizeLimitExceeded);
+ return in;
+ }
+ if (bytes == -1) { // null string
+ str = QString();
+ } else if (bytes > 0) {
if (bytes & 0x1) {
str.clear();
in.setStatus(QDataStream::ReadCorruptData);
return in;
}
- const quint32 Step = 1024 * 1024;
- quint32 len = bytes / 2;
- quint32 allocated = 0;
+ const qsizetype Step = 1024 * 1024;
+ qsizetype len = bytes / 2;
+ qsizetype allocated = 0;
while (allocated < len) {
int blockSize = qMin(Step, len - allocated);
@@ -9519,6 +9876,8 @@ qsizetype QtPrivate::findString(QStringView haystack0, qsizetype from, QStringVi
{
const qsizetype l = haystack0.size();
const qsizetype sl = needle0.size();
+ if (sl == 1)
+ return findString(haystack0, from, needle0[0], cs);
if (from < 0)
from += l;
if (std::size_t(sl + from) > std::size_t(l))
@@ -9528,9 +9887,6 @@ qsizetype QtPrivate::findString(QStringView haystack0, qsizetype from, QStringVi
if (!l)
return -1;
- if (sl == 1)
- return qFindChar(haystack0, needle0[0], from, cs);
-
/*
We use the Boyer-Moore algorithm in cases where the overhead
for the skip table should pay off, otherwise we use a simple
@@ -9632,7 +9988,7 @@ qsizetype QtPrivate::findString(QLatin1StringView haystack, qsizetype from, QLat
if (cs == Qt::CaseSensitive) {
if (needle.size() == 1) {
- Q_ASSUME(haystack.data() != nullptr); // see size check above
+ Q_ASSERT(haystack.data() != nullptr); // see size check above
if (auto it = memchr(haystack.data() + from, needle.front().toLatin1(), adjustedSize))
return static_cast<const char *>(it) - haystack.data();
return -1;
@@ -9661,7 +10017,7 @@ qsizetype QtPrivate::findString(QLatin1StringView haystack, qsizetype from, QLat
const auto end = haystack.end() - needle.size() + 1;
auto ciMatch = CaseInsensitiveL1::matcher(needle[0].toLatin1());
const qsizetype nlen1 = needle.size() - 1;
- for (auto it = std::find_if(begin + from, end, ciMatch); it < end;
+ for (auto it = std::find_if(begin + from, end, ciMatch); it != end;
it = std::find_if(it + 1, end, ciMatch)) {
// In this comparison we skip the first character because we know it's a match
if (!nlen1 || QLatin1StringView(it + 1, nlen1).compare(needle.sliced(1), cs) == 0)
@@ -9674,6 +10030,11 @@ qsizetype QtPrivate::findString(QLatin1StringView haystack, qsizetype from, QLat
return matcher.indexIn(haystack, from);
}
+qsizetype QtPrivate::lastIndexOf(QStringView haystack, qsizetype from, char16_t needle, Qt::CaseSensitivity cs) noexcept
+{
+ return qLastIndexOf(haystack, QChar(needle), from, cs);
+}
+
qsizetype QtPrivate::lastIndexOf(QStringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs) noexcept
{
return qLastIndexOf(haystack, from, needle, cs);
@@ -9812,10 +10173,14 @@ qsizetype QtPrivate::count(QStringView haystack, const QRegularExpression &re)
*/
QString QString::toHtmlEscaped() const
{
+ const auto pos = std::u16string_view(*this).find_first_of(u"<>&\"");
+ if (pos == std::u16string_view::npos)
+ return *this;
QString rich;
const qsizetype len = size();
rich.reserve(qsizetype(len * 1.1));
- for (QChar ch : *this) {
+ rich += qToStringViewIgnoringNull(*this).first(pos);
+ for (auto ch : qToStringViewIgnoringNull(*this).sliced(pos)) {
if (ch == u'<')
rich += "&lt;"_L1;
else if (ch == u'>')
@@ -10020,5 +10385,4 @@ void QAbstractConcatenable::appendLatin1To(QLatin1StringView in, QChar *out) noe
QT_END_NAMESPACE
-#undef IS_RAW_DATA
#undef REHASH
diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h
index 26fb4e44ca..895ec4b5c0 100644
--- a/src/corelib/text/qstring.h
+++ b/src/corelib/text/qstring.h
@@ -12,6 +12,7 @@
#endif
#include <QtCore/qchar.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qbytearrayview.h>
#include <QtCore/qarraydata.h>
@@ -24,6 +25,8 @@
#include <string>
#include <iterator>
+#include <QtCore/q20memory.h>
+#include <string_view>
#include <stdarg.h>
@@ -36,6 +39,8 @@ Q_FORWARD_DECLARE_CF_TYPE(CFString);
Q_FORWARD_DECLARE_OBJC_CLASS(NSString);
#endif
+class tst_QString;
+
QT_BEGIN_NAMESPACE
class QRegularExpression;
@@ -44,6 +49,13 @@ class QString;
namespace QtPrivate {
template <bool...B> class BoolList;
+
+template <typename Char>
+using IsCompatibleChar32TypeHelper =
+ std::is_same<Char, char32_t>;
+template <typename Char>
+using IsCompatibleChar32Type
+ = IsCompatibleChar32TypeHelper<q20::remove_cvref_t<Char>>;
}
// Qt 4.x compatibility
@@ -79,7 +91,7 @@ qsizetype QStringView::count(QLatin1StringView s, Qt::CaseSensitivity cs) const
//
constexpr QAnyStringView::QAnyStringView(QLatin1StringView str) noexcept
- : m_data{str.data()}, m_size{size_t(str.size()) | Tag::Latin1} {}
+ : m_data{str.data()}, m_size{size_t(str.size() << SizeShift) | Tag::Latin1} {}
constexpr QLatin1StringView QAnyStringView::asLatin1StringView() const
{
@@ -116,14 +128,46 @@ constexpr QChar QAnyStringView::back() const
class Q_CORE_EXPORT QString
{
typedef QTypedArrayData<char16_t> Data;
+
+ friend class ::tst_QString;
+
+ template <typename Iterator>
+ static constexpr bool is_contiguous_iterator_v =
+ // Can't use contiguous_iterator_tag here, as STL impls can't agree on feature macro.
+ // To avoid differences in C++20 and C++17 builds, treat only pointers as contiguous
+ // for now:
+ // std::contiguous_iterator<Iterator>;
+ std::is_pointer_v<Iterator>;
+
+ template <typename Char>
+ using is_compatible_char_helper = std::disjunction<
+ QtPrivate::IsCompatibleCharType<Char>,
+ QtPrivate::IsCompatibleChar32Type<Char>,
+ QtPrivate::IsCompatibleChar8Type<Char>,
+ std::is_same<Char, QLatin1Char> // special case
+ >;
+
+ template <typename Iterator>
+ static constexpr bool is_compatible_iterator_v = std::conjunction_v<
+ std::is_convertible<
+ typename std::iterator_traits<Iterator>::iterator_category,
+ std::input_iterator_tag
+ >,
+ is_compatible_char_helper<typename std::iterator_traits<Iterator>::value_type>
+ >;
+
+ template <typename Iterator>
+ using if_compatible_iterator = std::enable_if_t<is_compatible_iterator_v<Iterator>, bool>;
+
public:
typedef QStringPrivate DataPointer;
- inline constexpr QString() noexcept;
+ constexpr QString() noexcept;
explicit QString(const QChar *unicode, qsizetype size = -1);
QString(QChar c);
QString(qsizetype size, QChar c);
inline QString(QLatin1StringView latin1);
+ explicit QString(QStringView sv) : QString(sv.data(), sv.size()) {}
#if defined(__cpp_char8_t) || defined(Q_QDOC)
Q_WEAK_OVERLOAD
inline QString(const char8_t *str)
@@ -139,20 +183,32 @@ public:
= default;
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QString)
void swap(QString &other) noexcept { d.swap(other.d); }
- inline qsizetype size() const { return d.size; }
+ inline qsizetype size() const noexcept { return d.size; }
#if QT_DEPRECATED_SINCE(6, 4)
QT_DEPRECATED_VERSION_X_6_4("Use size() or length() instead.")
inline qsizetype count() const { return d.size; }
#endif
- inline qsizetype length() const { return d.size; }
- inline bool isEmpty() const;
+ inline qsizetype length() const noexcept { return d.size; }
+ inline bool isEmpty() const noexcept { return d.size == 0; }
void resize(qsizetype size);
void resize(qsizetype size, QChar fillChar);
+ void resizeForOverwrite(qsizetype size);
QString &fill(QChar c, qsizetype size = -1);
void truncate(qsizetype pos);
void chop(qsizetype n);
+ QString &slice(qsizetype pos)
+ { verify(pos, 0); return remove(0, pos); }
+ QString &slice(qsizetype pos, qsizetype n)
+ {
+ verify(pos, n);
+ if (isNull())
+ return *this;
+ resize(pos + n);
+ return remove(0, pos);
+ }
+
inline qsizetype capacity() const;
inline void reserve(qsizetype size);
inline void squeeze();
@@ -165,11 +221,11 @@ public:
inline void detach();
inline bool isDetached() const;
inline bool isSharedWith(const QString &other) const { return d.isSharedWith(other.d); }
- void clear();
+ inline void clear();
inline const QChar at(qsizetype i) const;
- const QChar operator[](qsizetype i) const;
- [[nodiscard]] QChar &operator[](qsizetype i);
+ inline const QChar operator[](qsizetype i) const;
+ [[nodiscard]] inline QChar &operator[](qsizetype i);
[[nodiscard]] inline QChar front() const { return at(0); }
[[nodiscard]] inline QChar &front();
@@ -180,17 +236,17 @@ public:
QChar fillChar = u' ') const;
[[nodiscard]] QString arg(qulonglong a, int fieldwidth=0, int base=10,
QChar fillChar = u' ') const;
- [[nodiscard]] QString arg(long a, int fieldwidth=0, int base=10,
+ [[nodiscard]] inline QString arg(long a, int fieldwidth=0, int base=10,
QChar fillChar = u' ') const;
- [[nodiscard]] QString arg(ulong a, int fieldwidth=0, int base=10,
+ [[nodiscard]] inline QString arg(ulong a, int fieldwidth=0, int base=10,
QChar fillChar = u' ') const;
- [[nodiscard]] QString arg(int a, int fieldWidth = 0, int base = 10,
+ [[nodiscard]] inline QString arg(int a, int fieldWidth = 0, int base = 10,
QChar fillChar = u' ') const;
- [[nodiscard]] QString arg(uint a, int fieldWidth = 0, int base = 10,
+ [[nodiscard]] inline QString arg(uint a, int fieldWidth = 0, int base = 10,
QChar fillChar = u' ') const;
- [[nodiscard]] QString arg(short a, int fieldWidth = 0, int base = 10,
+ [[nodiscard]] inline QString arg(short a, int fieldWidth = 0, int base = 10,
QChar fillChar = u' ') const;
- [[nodiscard]] QString arg(ushort a, int fieldWidth = 0, int base = 10,
+ [[nodiscard]] inline QString arg(ushort a, int fieldWidth = 0, int base = 10,
QChar fillChar = u' ') const;
[[nodiscard]] QString arg(double a, int fieldWidth = 0, char format = 'g', int precision = -1,
QChar fillChar = u' ') const;
@@ -231,14 +287,16 @@ public:
static QString vasprintf(const char *format, va_list ap) Q_ATTRIBUTE_FORMAT_PRINTF(1, 0);
static QString asprintf(const char *format, ...) Q_ATTRIBUTE_FORMAT_PRINTF(1, 2);
- [[nodiscard]] qsizetype indexOf(QChar c, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+ [[nodiscard]] QT_CORE_INLINE_SINCE(6, 7)
+ qsizetype indexOf(QChar c, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
[[nodiscard]] qsizetype indexOf(QLatin1StringView s, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
[[nodiscard]] qsizetype indexOf(const QString &s, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
[[nodiscard]] qsizetype indexOf(QStringView s, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return QtPrivate::findString(*this, from, s, cs); }
[[nodiscard]] qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return lastIndexOf(c, -1, cs); }
- [[nodiscard]] qsizetype lastIndexOf(QChar c, qsizetype from, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+ [[nodiscard]] QT_CORE_INLINE_SINCE(6, 7)
+ qsizetype lastIndexOf(QChar c, qsizetype from, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
[[nodiscard]] qsizetype lastIndexOf(QLatin1StringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
{ return lastIndexOf(s, size(), cs); }
[[nodiscard]] qsizetype lastIndexOf(QLatin1StringView s, qsizetype from, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
@@ -285,27 +343,76 @@ public:
};
Q_DECLARE_FLAGS(SectionFlags, SectionFlag)
- [[nodiscard]] QString section(QChar sep, qsizetype start, qsizetype end = -1, SectionFlags flags = SectionDefault) const;
+ [[nodiscard]] inline QString section(QChar sep, qsizetype start, qsizetype end = -1, SectionFlags flags = SectionDefault) const;
[[nodiscard]] QString section(const QString &in_sep, qsizetype start, qsizetype end = -1, SectionFlags flags = SectionDefault) const;
#if QT_CONFIG(regularexpression)
[[nodiscard]] QString section(const QRegularExpression &re, qsizetype start, qsizetype end = -1, SectionFlags flags = SectionDefault) const;
#endif
- [[nodiscard]] QString left(qsizetype n) const;
- [[nodiscard]] QString right(qsizetype n) const;
- [[nodiscard]] QString mid(qsizetype position, qsizetype n = -1) const;
-
- [[nodiscard]] QString first(qsizetype n) const
- { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); return QString(data(), n); }
- [[nodiscard]] QString last(qsizetype n) const
- { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); return QString(data() + size() - n, n); }
- [[nodiscard]] QString sliced(qsizetype pos) const
- { Q_ASSERT(pos >= 0); Q_ASSERT(pos <= size()); return QString(data() + pos, size() - pos); }
- [[nodiscard]] QString sliced(qsizetype pos, qsizetype n) const
- { Q_ASSERT(pos >= 0); Q_ASSERT(n >= 0); Q_ASSERT(size_t(pos) + size_t(n) <= size_t(size())); return QString(data() + pos, n); }
- [[nodiscard]] QString chopped(qsizetype n) const
- { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); return first(size() - n); }
+#if QT_CORE_REMOVED_SINCE(6, 7)
+ QString left(qsizetype n) const;
+ QString right(qsizetype n) const;
+ QString mid(qsizetype position, qsizetype n = -1) const;
+ QString first(qsizetype n) const;
+ QString last(qsizetype n) const;
+ QString sliced(qsizetype pos) const;
+ QString sliced(qsizetype pos, qsizetype n) const;
+ QString chopped(qsizetype n) const;
+#else
+ [[nodiscard]] QString left(qsizetype n) const &
+ {
+ if (size_t(n) >= size_t(size()))
+ return *this;
+ return first(n);
+ }
+ [[nodiscard]] QString left(qsizetype n) &&
+ {
+ if (size_t(n) >= size_t(size()))
+ return std::move(*this);
+ return std::move(*this).first(n);
+ }
+ [[nodiscard]] QString right(qsizetype n) const &
+ {
+ if (size_t(n) >= size_t(size()))
+ return *this;
+ return last(n);
+ }
+ [[nodiscard]] QString right(qsizetype n) &&
+ {
+ if (size_t(n) >= size_t(size()))
+ return std::move(*this);
+ return std::move(*this).last(n);
+ }
+ [[nodiscard]] QString mid(qsizetype position, qsizetype n = -1) const &;
+ [[nodiscard]] QString mid(qsizetype position, qsizetype n = -1) &&;
+
+ [[nodiscard]] QString first(qsizetype n) const &
+ { verify(0, n); return sliced(0, n); }
+ [[nodiscard]] QString last(qsizetype n) const &
+ { verify(0, n); return sliced(size() - n, n); }
+ [[nodiscard]] QString sliced(qsizetype pos) const &
+ { verify(pos, 0); return sliced(pos, size() - pos); }
+ [[nodiscard]] QString sliced(qsizetype pos, qsizetype n) const &
+ { verify(pos, n); return QString(begin() + pos, n); }
+ [[nodiscard]] QString chopped(qsizetype n) const &
+ { verify(0, n); return sliced(0, size() - n); }
+
+ [[nodiscard]] QString first(qsizetype n) &&
+ {
+ verify(0, n);
+ resize(n); // may detach and allocate memory
+ return std::move(*this);
+ }
+ [[nodiscard]] QString last(qsizetype n) &&
+ { verify(0, n); return sliced_helper(*this, size() - n, n); }
+ [[nodiscard]] QString sliced(qsizetype pos) &&
+ { verify(pos, 0); return sliced_helper(*this, pos, size() - pos); }
+ [[nodiscard]] QString sliced(qsizetype pos, qsizetype n) &&
+ { verify(pos, n); return sliced_helper(*this, pos, n); }
+ [[nodiscard]] QString chopped(qsizetype n) &&
+ { verify(0, n); return std::move(*this).first(size() - n); }
+#endif
bool startsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
[[nodiscard]] bool startsWith(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return QtPrivate::startsWith(*this, s, cs); }
@@ -375,6 +482,53 @@ public:
inline QString &prepend(QLatin1StringView s) { return insert(0, s); }
QString &prepend(QUtf8StringView s) { return insert(0, s); }
+ QString &assign(QAnyStringView s);
+ inline QString &assign(qsizetype n, QChar c)
+ {
+ Q_ASSERT(n >= 0);
+ return fill(c, n);
+ }
+ template <typename InputIterator, if_compatible_iterator<InputIterator> = true>
+ QString &assign(InputIterator first, InputIterator last)
+ {
+ using V = typename std::iterator_traits<InputIterator>::value_type;
+ constexpr bool IsL1C = std::is_same_v<std::remove_cv_t<V>, QLatin1Char>;
+ constexpr bool IsFwdIt = std::is_convertible_v<
+ typename std::iterator_traits<InputIterator>::iterator_category,
+ std::forward_iterator_tag
+ >;
+
+ if constexpr (is_contiguous_iterator_v<InputIterator>) {
+ const auto p = q20::to_address(first);
+ const auto len = qsizetype(last - first);
+ if constexpr (IsL1C)
+ return assign(QLatin1StringView(reinterpret_cast<const char*>(p), len));
+ else if constexpr (sizeof(V) == 4)
+ return assign_helper(p, len);
+ else
+ return assign(QAnyStringView(p, len));
+ } else if constexpr (sizeof(V) == 4) { // non-contiguous iterator, feed data piecemeal
+ resize(0);
+ if constexpr (IsFwdIt) {
+ const qsizetype requiredCapacity = 2 * std::distance(first, last);
+ reserve(requiredCapacity);
+ }
+ while (first != last) {
+ append(QChar::fromUcs4(*first));
+ ++first;
+ }
+ return *this;
+ } else if constexpr (QtPrivate::IsCompatibleChar8Type<V>::value) {
+ assign_helper_char8(first, last);
+ d.data()[d.size] = u'\0';
+ return *this;
+ } else {
+ d.assign(first, last, [](QChar ch) -> char16_t { return ch.unicode(); });
+ d.data()[d.size] = u'\0';
+ return *this;
+ }
+ }
+
inline QString &operator+=(QChar c) { return append(c); }
inline QString &operator+=(const QString &s) { return append(s); }
@@ -564,11 +718,11 @@ public:
{ return -s2.compare(s1, cs); }
int localeAwareCompare(const QString& s) const;
- int localeAwareCompare(QStringView s) const;
+ inline int localeAwareCompare(QStringView s) const;
static int localeAwareCompare(const QString& s1, const QString& s2)
{ return s1.localeAwareCompare(s2); }
- static int localeAwareCompare(QStringView s1, QStringView s2);
+ static inline int localeAwareCompare(QStringView s1, QStringView s2);
short toShort(bool *ok=nullptr, int base=10) const
{ return toIntegral_helper<short>(*this, ok, base); }
@@ -589,15 +743,15 @@ public:
float toFloat(bool *ok=nullptr) const;
double toDouble(bool *ok=nullptr) const;
- QString &setNum(short, int base=10);
- QString &setNum(ushort, int base=10);
- QString &setNum(int, int base=10);
- QString &setNum(uint, int base=10);
- QString &setNum(long, int base=10);
- QString &setNum(ulong, int base=10);
+ inline QString &setNum(short, int base=10);
+ inline QString &setNum(ushort, int base=10);
+ inline QString &setNum(int, int base=10);
+ inline QString &setNum(uint, int base=10);
+ inline QString &setNum(long, int base=10);
+ inline QString &setNum(ulong, int base=10);
QString &setNum(qlonglong, int base=10);
QString &setNum(qulonglong, int base=10);
- QString &setNum(float, char format='g', int precision=6);
+ inline QString &setNum(float, char format='g', int precision=6);
QString &setNum(double, char format='g', int precision=6);
static QString number(int, int base=10);
@@ -608,78 +762,63 @@ public:
static QString number(qulonglong, int base=10);
static QString number(double, char format='g', int precision=6);
- friend bool operator==(const QString &s1, const QString &s2) noexcept
- { return (s1.size() == s2.size()) && QtPrivate::compareStrings(s1, s2, Qt::CaseSensitive) == 0; }
- friend bool operator< (const QString &s1, const QString &s2) noexcept
- { return QtPrivate::compareStrings(s1, s2, Qt::CaseSensitive) < 0; }
- friend bool operator> (const QString &s1, const QString &s2) noexcept { return s2 < s1; }
- friend bool operator!=(const QString &s1, const QString &s2) noexcept { return !(s1 == s2); }
- friend bool operator<=(const QString &s1, const QString &s2) noexcept { return !(s1 > s2); }
- friend bool operator>=(const QString &s1, const QString &s2) noexcept { return !(s1 < s2); }
-
- friend bool operator==(const QString &s1, QLatin1StringView s2) noexcept
- { return (s1.size() == s2.size()) && QtPrivate::compareStrings(s1, s2, Qt::CaseSensitive) == 0; }
- friend bool operator< (const QString &s1, QLatin1StringView s2) noexcept
- { return QtPrivate::compareStrings(s1, s2, Qt::CaseSensitive) < 0; }
- friend bool operator> (const QString &s1, QLatin1StringView s2) noexcept
- { return QtPrivate::compareStrings(s1, s2, Qt::CaseSensitive) > 0; }
- friend bool operator!=(const QString &s1, QLatin1StringView s2) noexcept { return !(s1 == s2); }
- friend bool operator<=(const QString &s1, QLatin1StringView s2) noexcept { return !(s1 > s2); }
- friend bool operator>=(const QString &s1, QLatin1StringView s2) noexcept { return !(s1 < s2); }
-
- friend bool operator==(QLatin1StringView s1, const QString &s2) noexcept { return s2 == s1; }
- friend bool operator< (QLatin1StringView s1, const QString &s2) noexcept { return s2 > s1; }
- friend bool operator> (QLatin1StringView s1, const QString &s2) noexcept { return s2 < s1; }
- friend bool operator!=(QLatin1StringView s1, const QString &s2) noexcept { return s2 != s1; }
- friend bool operator<=(QLatin1StringView s1, const QString &s2) noexcept { return s2 >= s1; }
- friend bool operator>=(QLatin1StringView s1, const QString &s2) noexcept { return s2 <= s1; }
+ friend bool comparesEqual(const QString &s1, const QString &s2) noexcept
+ { return comparesEqual(QStringView(s1), QStringView(s2)); }
+ friend Qt::strong_ordering compareThreeWay(const QString &s1, const QString &s2) noexcept
+ { return compareThreeWay(QStringView(s1), QStringView(s2)); }
+ Q_DECLARE_STRONGLY_ORDERED(QString)
+
+ Q_WEAK_OVERLOAD
+ friend bool comparesEqual(const QString &s1, QUtf8StringView s2) noexcept
+ { return QtPrivate::equalStrings(s1, s2); }
+ Q_WEAK_OVERLOAD
+ friend Qt::strong_ordering compareThreeWay(const QString &s1, QUtf8StringView s2) noexcept
+ {
+ const int res = QtPrivate::compareStrings(s1, s2, Qt::CaseSensitive);
+ return Qt::compareThreeWay(res, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QString, QUtf8StringView, Q_WEAK_OVERLOAD)
+
+#ifdef __cpp_char8_t
+ friend bool comparesEqual(const QString &s1, const char8_t *s2) noexcept
+ { return comparesEqual(s1, QUtf8StringView(s2)); }
+ friend Qt::strong_ordering compareThreeWay(const QString &s1, const char8_t *s2) noexcept
+ { return compareThreeWay(s1, QUtf8StringView(s2)); }
+ Q_DECLARE_STRONGLY_ORDERED(QString, const char8_t *)
+#endif // __cpp_char8_t
+
+ friend bool comparesEqual(const QString &s1, QLatin1StringView s2) noexcept
+ { return (s1.size() == s2.size()) && QtPrivate::equalStrings(s1, s2); }
+ friend Qt::strong_ordering
+ compareThreeWay(const QString &s1, QLatin1StringView s2) noexcept
+ {
+ const int res = QtPrivate::compareStrings(s1, s2, Qt::CaseSensitive);
+ return Qt::compareThreeWay(res, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QString, QLatin1StringView)
// Check isEmpty() instead of isNull() for backwards compatibility.
- friend bool operator==(const QString &s1, std::nullptr_t) noexcept { return s1.isEmpty(); }
- friend bool operator!=(const QString &s1, std::nullptr_t) noexcept { return !s1.isEmpty(); }
- friend bool operator< (const QString & , std::nullptr_t) noexcept { return false; }
- friend bool operator> (const QString &s1, std::nullptr_t) noexcept { return !s1.isEmpty(); }
- friend bool operator<=(const QString &s1, std::nullptr_t) noexcept { return s1.isEmpty(); }
- friend bool operator>=(const QString & , std::nullptr_t) noexcept { return true; }
- friend bool operator==(std::nullptr_t, const QString &s2) noexcept { return s2 == nullptr; }
- friend bool operator!=(std::nullptr_t, const QString &s2) noexcept { return s2 != nullptr; }
- friend bool operator< (std::nullptr_t, const QString &s2) noexcept { return s2 > nullptr; }
- friend bool operator> (std::nullptr_t, const QString &s2) noexcept { return s2 < nullptr; }
- friend bool operator<=(std::nullptr_t, const QString &s2) noexcept { return s2 >= nullptr; }
- friend bool operator>=(std::nullptr_t, const QString &s2) noexcept { return s2 <= nullptr; }
-
- friend bool operator==(const QString &s1, const char16_t *s2) noexcept { return s1 == QStringView(s2); }
- friend bool operator!=(const QString &s1, const char16_t *s2) noexcept { return s1 != QStringView(s2); }
- friend bool operator< (const QString &s1, const char16_t *s2) noexcept { return s1 < QStringView(s2); }
- friend bool operator> (const QString &s1, const char16_t *s2) noexcept { return s1 > QStringView(s2); }
- friend bool operator<=(const QString &s1, const char16_t *s2) noexcept { return s1 <= QStringView(s2); }
- friend bool operator>=(const QString &s1, const char16_t *s2) noexcept { return s1 >= QStringView(s2); }
-
- friend bool operator==(const char16_t *s1, const QString &s2) noexcept { return s2 == s1; }
- friend bool operator!=(const char16_t *s1, const QString &s2) noexcept { return s2 != s1; }
- friend bool operator< (const char16_t *s1, const QString &s2) noexcept { return s2 > s1; }
- friend bool operator> (const char16_t *s1, const QString &s2) noexcept { return s2 < s1; }
- friend bool operator<=(const char16_t *s1, const QString &s2) noexcept { return s2 >= s1; }
- friend bool operator>=(const char16_t *s1, const QString &s2) noexcept { return s2 <= s1; }
+ friend bool comparesEqual(const QString &s1, std::nullptr_t) noexcept
+ { return s1.isEmpty(); }
+ friend Qt::strong_ordering compareThreeWay(const QString &s1, std::nullptr_t) noexcept
+ { return s1.isEmpty() ? Qt::strong_ordering::equivalent : Qt::strong_ordering::greater; }
+ Q_DECLARE_STRONGLY_ORDERED(QString, std::nullptr_t)
+
+ friend bool comparesEqual(const QString &s1, const char16_t *s2) noexcept
+ { return comparesEqual(s1, QStringView(s2)); }
+ friend Qt::strong_ordering compareThreeWay(const QString &s1, const char16_t *s2) noexcept
+ { return compareThreeWay(s1, QStringView(s2)); }
+ Q_DECLARE_STRONGLY_ORDERED(QString, const char16_t *)
// QChar <> QString
- friend inline bool operator==(QChar lhs, const QString &rhs) noexcept
- { return rhs.size() == 1 && lhs == rhs.front(); }
- friend inline bool operator< (QChar lhs, const QString &rhs) noexcept
- { return compare_helper(&lhs, 1, rhs.data(), rhs.size()) < 0; }
- friend inline bool operator> (QChar lhs, const QString &rhs) noexcept
- { return compare_helper(&lhs, 1, rhs.data(), rhs.size()) > 0; }
-
- friend inline bool operator!=(QChar lhs, const QString &rhs) noexcept { return !(lhs == rhs); }
- friend inline bool operator<=(QChar lhs, const QString &rhs) noexcept { return !(lhs > rhs); }
- friend inline bool operator>=(QChar lhs, const QString &rhs) noexcept { return !(lhs < rhs); }
-
- friend inline bool operator==(const QString &lhs, QChar rhs) noexcept { return rhs == lhs; }
- friend inline bool operator!=(const QString &lhs, QChar rhs) noexcept { return !(rhs == lhs); }
- friend inline bool operator< (const QString &lhs, QChar rhs) noexcept { return rhs > lhs; }
- friend inline bool operator> (const QString &lhs, QChar rhs) noexcept { return rhs < lhs; }
- friend inline bool operator<=(const QString &lhs, QChar rhs) noexcept { return !(rhs < lhs); }
- friend inline bool operator>=(const QString &lhs, QChar rhs) noexcept { return !(rhs > lhs); }
+ friend bool comparesEqual(const QString &lhs, QChar rhs) noexcept
+ { return lhs.size() == 1 && rhs == lhs.front(); }
+ friend Qt::strong_ordering compareThreeWay(const QString &lhs, QChar rhs) noexcept
+ {
+ const int res = compare_helper(lhs.data(), lhs.size(), &rhs, 1);
+ return Qt::compareThreeWay(res, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QString, QChar)
// ASCII compatibility
#if defined(QT_RESTRICTED_CAST_FROM_ASCII)
@@ -703,10 +842,21 @@ public:
: QString(fromUtf8(a))
{}
QT_ASCII_CAST_WARN inline QString &operator=(const char *ch)
- { return (*this = fromUtf8(ch)); }
+ {
+ if (!ch) {
+ clear();
+ return *this;
+ }
+ return assign(ch);
+ }
QT_ASCII_CAST_WARN inline QString &operator=(const QByteArray &a)
- { return (*this = fromUtf8(a)); }
-
+ {
+ if (a.isNull()) {
+ clear();
+ return *this;
+ }
+ return assign(a);
+ }
// these are needed, so it compiles with STL support enabled
QT_ASCII_CAST_WARN inline QString &prepend(const char *s)
{ return prepend(QUtf8StringView(s)); }
@@ -725,6 +875,7 @@ public:
QT_ASCII_CAST_WARN inline QString &operator+=(const QByteArray &s)
{ return append(QUtf8StringView(s)); }
+#if QT_CORE_REMOVED_SINCE(6, 8)
QT_ASCII_CAST_WARN inline bool operator==(const char *s) const;
QT_ASCII_CAST_WARN inline bool operator!=(const char *s) const;
QT_ASCII_CAST_WARN inline bool operator<(const char *s) const;
@@ -738,20 +889,41 @@ public:
QT_ASCII_CAST_WARN inline bool operator>(const QByteArray &s) const;
QT_ASCII_CAST_WARN inline bool operator<=(const QByteArray &s) const;
QT_ASCII_CAST_WARN inline bool operator>=(const QByteArray &s) const;
+#else
+ friend bool comparesEqual(const QString &lhs, QByteArrayView rhs) noexcept
+ {
+ return QString::compare_helper(lhs.constData(), lhs.size(),
+ rhs.constData(), rhs.size()) == 0;
+ }
+ friend Qt::strong_ordering
+ compareThreeWay(const QString &lhs, QByteArrayView rhs) noexcept
+ {
+ const int res = QString::compare_helper(lhs.constData(), lhs.size(),
+ rhs.constData(), rhs.size());
+ return Qt::compareThreeWay(res, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QString, QByteArrayView, QT_ASCII_CAST_WARN)
- QT_ASCII_CAST_WARN friend bool operator==(const char *s1, const QString &s2)
- { return QString::compare_helper(s2.constData(), s2.size(), s1, -1) == 0; }
- QT_ASCII_CAST_WARN friend bool operator!=(const char *s1, const QString &s2)
- { return QString::compare_helper(s2.constData(), s2.size(), s1, -1) != 0; }
- QT_ASCII_CAST_WARN friend bool operator< (const char *s1, const QString &s2)
- { return QString::compare_helper(s2.constData(), s2.size(), s1, -1) > 0; }
- QT_ASCII_CAST_WARN friend bool operator> (const char *s1, const QString &s2)
- { return QString::compare_helper(s2.constData(), s2.size(), s1, -1) < 0; }
- QT_ASCII_CAST_WARN friend bool operator<=(const char *s1, const QString &s2)
- { return QString::compare_helper(s2.constData(), s2.size(), s1, -1) >= 0; }
- QT_ASCII_CAST_WARN friend bool operator>=(const char *s1, const QString &s2)
- { return QString::compare_helper(s2.constData(), s2.size(), s1, -1) <= 0; }
-#endif
+ friend bool comparesEqual(const QString &lhs, const QByteArray &rhs) noexcept
+ { return comparesEqual(lhs, QByteArrayView(rhs)); }
+ friend Qt::strong_ordering
+ compareThreeWay(const QString &lhs, const QByteArray &rhs) noexcept
+ {
+ return compareThreeWay(lhs, QByteArrayView(rhs));
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QString, QByteArray, QT_ASCII_CAST_WARN)
+
+ friend bool comparesEqual(const QString &lhs, const char *rhs) noexcept
+ { return comparesEqual(lhs, QByteArrayView(rhs)); }
+ friend Qt::strong_ordering
+ compareThreeWay(const QString &lhs, const char *rhs) noexcept
+ {
+ return compareThreeWay(lhs, QByteArrayView(rhs));
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QString, const char *, QT_ASCII_CAST_WARN)
+#endif // QT_CORE_REMOVED_SINCE(6, 8)
+
+#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
typedef QChar *iterator;
typedef const QChar *const_iterator;
@@ -789,6 +961,11 @@ public:
void shrink_to_fit() { squeeze(); }
iterator erase(const_iterator first, const_iterator last);
inline iterator erase(const_iterator it) { return erase(it, it + 1); }
+ static constexpr qsizetype max_size() noexcept
+ {
+ // -1 to deal with the NUL terminator
+ return Data::max_size() - 1;
+ }
static inline QString fromStdString(const std::string &s);
inline std::string toStdString() const;
@@ -800,6 +977,8 @@ public:
static inline QString fromStdU32String(const std::u32string &s);
inline std::u32string toStdU32String() const;
+ Q_IMPLICIT inline operator std::u16string_view() const noexcept;
+
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
static QString fromCFString(CFStringRef string);
CFStringRef toCFString() const Q_DECL_CF_RETURNS_RETAINED;
@@ -808,14 +987,12 @@ public:
#endif
#if defined(Q_OS_WASM) || defined(Q_QDOC)
- static QString fromJsString(emscripten::val jsString);
- emscripten::val toJsString() const;
+ static QString fromEcmaString(emscripten::val jsString);
+ emscripten::val toEcmaString() const;
#endif
inline bool isNull() const { return d->isNull(); }
-
- bool isSimpleText() const;
bool isRightToLeft() const;
[[nodiscard]] bool isValidUtf16() const noexcept
{ return QStringView(*this).isValidUtf16(); }
@@ -838,6 +1015,11 @@ private:
void reallocData(qsizetype alloc, QArrayData::AllocationOption option);
void reallocGrowData(qsizetype n);
+ // ### remove once QAnyStringView supports UTF-32:
+ QString &assign_helper(const char32_t *data, qsizetype len);
+ // Defined in qstringconverter.h
+ template <typename InputIterator>
+ void assign_helper_char8(InputIterator first, InputIterator last);
static int compare_helper(const QChar *data1, qsizetype length1,
const QChar *data2, qsizetype length2,
Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
@@ -846,6 +1028,7 @@ private:
Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
static int localeAwareCompare_helper(const QChar *data1, qsizetype length1,
const QChar *data2, qsizetype length2);
+ static QString sliced_helper(QString &str, qsizetype pos, qsizetype n);
static QString toLower_helper(const QString &str);
static QString toLower_helper(QString &str);
static QString toUpper_helper(const QString &str);
@@ -897,6 +1080,15 @@ private:
return T(val);
}
+ Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos = 0,
+ [[maybe_unused]] qsizetype n = 1) const
+ {
+ Q_ASSERT(pos >= 0);
+ Q_ASSERT(pos <= d.size);
+ Q_ASSERT(n >= 0);
+ Q_ASSERT(n <= d.size - pos);
+ }
+
public:
inline DataPointer &data_ptr() { return d; }
inline const DataPointer &data_ptr() const { return d; }
@@ -927,7 +1119,7 @@ int QStringView::compare(QUtf8StringView other, Qt::CaseSensitivity cs) const no
//
QString QStringView::toString() const
-{ return QString(data(), size()); }
+{ return QString(*this); }
qint64 QStringView::toLongLong(bool *ok, int base) const
{ return QString::toIntegral_helper<qint64>(*this, ok, base); }
@@ -951,14 +1143,31 @@ ushort QStringView::toUShort(bool *ok, int base) const
//
template <bool UseChar8T>
+int QBasicUtf8StringView<UseChar8T>::compare(QChar other, Qt::CaseSensitivity cs) const noexcept
+{
+ return QtPrivate::compareStrings(*this, QStringView(&other, 1), cs);
+}
+
+template <bool UseChar8T>
int QBasicUtf8StringView<UseChar8T>::compare(QStringView other, Qt::CaseSensitivity cs) const noexcept
{
return QtPrivate::compareStrings(*this, other, cs);
}
+template <bool UseChar8T>
+[[nodiscard]] bool QBasicUtf8StringView<UseChar8T>::equal(QChar other) const noexcept
+{
+ return QtPrivate::equalStrings(*this, QStringView(&other, 1));
+}
+
+template <bool UseChar8T>
+[[nodiscard]] bool QBasicUtf8StringView<UseChar8T>::equal(QStringView other) const noexcept
+{
+ return QtPrivate::equalStrings(*this, other);
+}
//
-// QUtf8StringView inline members that require QString:
+// QUtf8StringView inline members that require QString, QL1SV or QBA:
//
template <bool UseChar8T>
@@ -974,6 +1183,29 @@ template<bool UseChar8T>
return QtPrivate::compareStrings(*this, other, cs);
}
+template<bool UseChar8T>
+[[nodiscard]] int QBasicUtf8StringView<UseChar8T>::compare(const QByteArray &other,
+ Qt::CaseSensitivity cs) const noexcept
+{
+ return QtPrivate::compareStrings(*this,
+ QBasicUtf8StringView<UseChar8T>(other.data(), other.size()),
+ cs);
+}
+
+template <bool UseChar8T>
+[[nodiscard]] bool QBasicUtf8StringView<UseChar8T>::equal(QLatin1StringView other) const noexcept
+{
+ return QtPrivate::equalStrings(*this, other);
+}
+
+template <bool UseChar8T>
+[[nodiscard]] bool QBasicUtf8StringView<UseChar8T>::equal(const QByteArray &other) const noexcept
+{
+ return size() == other.size()
+ && QtPrivate::equalStrings(*this, QBasicUtf8StringView<UseChar8T>(other.data(),
+ other.size()));
+}
+
//
// QAnyStringView inline members that require QString:
//
@@ -989,17 +1221,15 @@ QString QAnyStringView::toString() const
//
// QString inline members
//
-inline QString::QString(QLatin1StringView latin1)
+QString::QString(QLatin1StringView latin1)
{ *this = QString::fromLatin1(latin1.data(), latin1.size()); }
-inline const QChar QString::at(qsizetype i) const
-{ Q_ASSERT(size_t(i) < size_t(size())); return QChar(d.data()[i]); }
-inline const QChar QString::operator[](qsizetype i) const
-{ Q_ASSERT(size_t(i) < size_t(size())); return QChar(d.data()[i]); }
-inline bool QString::isEmpty() const
-{ return d.size == 0; }
-inline const QChar *QString::unicode() const
+const QChar QString::at(qsizetype i) const
+{ verify(i, 1); return QChar(d.data()[i]); }
+const QChar QString::operator[](qsizetype i) const
+{ verify(i, 1); return QChar(d.data()[i]); }
+const QChar *QString::unicode() const
{ return data(); }
-inline const QChar *QString::data() const
+const QChar *QString::data() const
{
#if QT5_NULL_STRINGS == 1
return reinterpret_cast<const QChar *>(d.data() ? d.data() : &_empty);
@@ -1007,58 +1237,58 @@ inline const QChar *QString::data() const
return reinterpret_cast<const QChar *>(d.data());
#endif
}
-inline QChar *QString::data()
+QChar *QString::data()
{
detach();
Q_ASSERT(d.data());
return reinterpret_cast<QChar *>(d.data());
}
-inline const QChar *QString::constData() const
+const QChar *QString::constData() const
{ return data(); }
-inline void QString::detach()
+void QString::detach()
{ if (d->needsDetach()) reallocData(d.size, QArrayData::KeepSize); }
-inline bool QString::isDetached() const
+bool QString::isDetached() const
{ return !d->isShared(); }
-inline void QString::clear()
+void QString::clear()
{ if (!isNull()) *this = QString(); }
-inline QString::QString(const QString &other) noexcept : d(other.d)
+QString::QString(const QString &other) noexcept : d(other.d)
{ }
-inline qsizetype QString::capacity() const { return qsizetype(d->constAllocatedCapacity()); }
-inline QString &QString::setNum(short n, int base)
+qsizetype QString::capacity() const { return qsizetype(d->constAllocatedCapacity()); }
+QString &QString::setNum(short n, int base)
{ return setNum(qlonglong(n), base); }
-inline QString &QString::setNum(ushort n, int base)
+QString &QString::setNum(ushort n, int base)
{ return setNum(qulonglong(n), base); }
-inline QString &QString::setNum(int n, int base)
+QString &QString::setNum(int n, int base)
{ return setNum(qlonglong(n), base); }
-inline QString &QString::setNum(uint n, int base)
+QString &QString::setNum(uint n, int base)
{ return setNum(qulonglong(n), base); }
-inline QString &QString::setNum(long n, int base)
+QString &QString::setNum(long n, int base)
{ return setNum(qlonglong(n), base); }
-inline QString &QString::setNum(ulong n, int base)
+QString &QString::setNum(ulong n, int base)
{ return setNum(qulonglong(n), base); }
-inline QString &QString::setNum(float n, char f, int prec)
+QString &QString::setNum(float n, char f, int prec)
{ return setNum(double(n),f,prec); }
-inline QString QString::arg(int a, int fieldWidth, int base, QChar fillChar) const
+QString QString::arg(int a, int fieldWidth, int base, QChar fillChar) const
{ return arg(qlonglong(a), fieldWidth, base, fillChar); }
-inline QString QString::arg(uint a, int fieldWidth, int base, QChar fillChar) const
+QString QString::arg(uint a, int fieldWidth, int base, QChar fillChar) const
{ return arg(qulonglong(a), fieldWidth, base, fillChar); }
-inline QString QString::arg(long a, int fieldWidth, int base, QChar fillChar) const
+QString QString::arg(long a, int fieldWidth, int base, QChar fillChar) const
{ return arg(qlonglong(a), fieldWidth, base, fillChar); }
-inline QString QString::arg(ulong a, int fieldWidth, int base, QChar fillChar) const
+QString QString::arg(ulong a, int fieldWidth, int base, QChar fillChar) const
{ return arg(qulonglong(a), fieldWidth, base, fillChar); }
-inline QString QString::arg(short a, int fieldWidth, int base, QChar fillChar) const
+QString QString::arg(short a, int fieldWidth, int base, QChar fillChar) const
{ return arg(qlonglong(a), fieldWidth, base, fillChar); }
-inline QString QString::arg(ushort a, int fieldWidth, int base, QChar fillChar) const
+QString QString::arg(ushort a, int fieldWidth, int base, QChar fillChar) const
{ return arg(qulonglong(a), fieldWidth, base, fillChar); }
-inline QString QString::section(QChar asep, qsizetype astart, qsizetype aend, SectionFlags aflags) const
+QString QString::section(QChar asep, qsizetype astart, qsizetype aend, SectionFlags aflags) const
{ return section(QString(asep), astart, aend, aflags); }
QT_WARNING_PUSH
QT_WARNING_DISABLE_MSVC(4127) // "conditional expression is constant"
QT_WARNING_DISABLE_INTEL(111) // "statement is unreachable"
-inline qsizetype QString::toWCharArray(wchar_t *array) const
+qsizetype QString::toWCharArray(wchar_t *array) const
{
return qToStringViewIgnoringNull(*this).toWCharArray(array);
}
@@ -1076,16 +1306,23 @@ qsizetype QStringView::toWCharArray(wchar_t *array) const
QT_WARNING_POP
-inline QString QString::fromWCharArray(const wchar_t *string, qsizetype size)
+QString QString::fromWCharArray(const wchar_t *string, qsizetype size)
{
- return sizeof(wchar_t) == sizeof(QChar) ? fromUtf16(reinterpret_cast<const char16_t *>(string), size)
- : fromUcs4(reinterpret_cast<const char32_t *>(string), size);
+ if constexpr (sizeof(wchar_t) == sizeof(QChar)) {
+ return QString(reinterpret_cast<const QChar *>(string), size);
+ } else {
+#ifdef QT_BOOTSTRAPPED
+ Q_UNREACHABLE_RETURN(QString());
+#else
+ return fromUcs4(reinterpret_cast<const char32_t *>(string), size);
+#endif
+ }
}
-inline constexpr QString::QString() noexcept {}
-inline QString::~QString() {}
+constexpr QString::QString() noexcept {}
+QString::~QString() {}
-inline void QString::reserve(qsizetype asize)
+void QString::reserve(qsizetype asize)
{
if (d->needsDetach() || asize >= capacity() - d.freeSpaceAtBegin())
reallocData(qMax(asize, size()), QArrayData::KeepSize);
@@ -1093,7 +1330,7 @@ inline void QString::reserve(qsizetype asize)
d->setFlag(Data::CapacityReserved);
}
-inline void QString::squeeze()
+void QString::squeeze()
{
if (!d.isMutable())
return;
@@ -1103,111 +1340,78 @@ inline void QString::squeeze()
d->clearFlag(Data::CapacityReserved);
}
-inline QString &QString::setUtf16(const ushort *autf16, qsizetype asize)
+QString &QString::setUtf16(const ushort *autf16, qsizetype asize)
{ return setUnicode(reinterpret_cast<const QChar *>(autf16), asize); }
-inline QChar &QString::operator[](qsizetype i)
-{ Q_ASSERT(i >= 0 && i < size()); return data()[i]; }
-inline QChar &QString::front() { return operator[](0); }
-inline QChar &QString::back() { return operator[](size() - 1); }
-inline QString::iterator QString::begin()
+QChar &QString::operator[](qsizetype i)
+{ verify(i, 1); return data()[i]; }
+QChar &QString::front() { return operator[](0); }
+QChar &QString::back() { return operator[](size() - 1); }
+QString::iterator QString::begin()
{ detach(); return reinterpret_cast<QChar*>(d.data()); }
-inline QString::const_iterator QString::begin() const
+QString::const_iterator QString::begin() const
{ return reinterpret_cast<const QChar*>(d.data()); }
-inline QString::const_iterator QString::cbegin() const
+QString::const_iterator QString::cbegin() const
{ return reinterpret_cast<const QChar*>(d.data()); }
-inline QString::const_iterator QString::constBegin() const
+QString::const_iterator QString::constBegin() const
{ return reinterpret_cast<const QChar*>(d.data()); }
-inline QString::iterator QString::end()
+QString::iterator QString::end()
{ detach(); return reinterpret_cast<QChar*>(d.data() + d.size); }
-inline QString::const_iterator QString::end() const
+QString::const_iterator QString::end() const
{ return reinterpret_cast<const QChar*>(d.data() + d.size); }
-inline QString::const_iterator QString::cend() const
+QString::const_iterator QString::cend() const
{ return reinterpret_cast<const QChar*>(d.data() + d.size); }
-inline QString::const_iterator QString::constEnd() const
+QString::const_iterator QString::constEnd() const
{ return reinterpret_cast<const QChar*>(d.data() + d.size); }
-inline bool QString::contains(const QString &s, Qt::CaseSensitivity cs) const
+bool QString::contains(const QString &s, Qt::CaseSensitivity cs) const
{ return indexOf(s, 0, cs) != -1; }
-inline bool QString::contains(QLatin1StringView s, Qt::CaseSensitivity cs) const
+bool QString::contains(QLatin1StringView s, Qt::CaseSensitivity cs) const
{ return indexOf(s, 0, cs) != -1; }
-inline bool QString::contains(QChar c, Qt::CaseSensitivity cs) const
+bool QString::contains(QChar c, Qt::CaseSensitivity cs) const
{ return indexOf(c, 0, cs) != -1; }
-inline bool QString::contains(QStringView s, Qt::CaseSensitivity cs) const noexcept
+bool QString::contains(QStringView s, Qt::CaseSensitivity cs) const noexcept
{ return indexOf(s, 0, cs) != -1; }
#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
-inline bool QString::operator==(const char *s) const
+#if QT_CORE_REMOVED_SINCE(6, 8)
+bool QString::operator==(const char *s) const
{ return QString::compare_helper(constData(), size(), s, -1) == 0; }
-inline bool QString::operator!=(const char *s) const
+bool QString::operator!=(const char *s) const
{ return QString::compare_helper(constData(), size(), s, -1) != 0; }
-inline bool QString::operator<(const char *s) const
+bool QString::operator<(const char *s) const
{ return QString::compare_helper(constData(), size(), s, -1) < 0; }
-inline bool QString::operator>(const char *s) const
+bool QString::operator>(const char *s) const
{ return QString::compare_helper(constData(), size(), s, -1) > 0; }
-inline bool QString::operator<=(const char *s) const
+bool QString::operator<=(const char *s) const
{ return QString::compare_helper(constData(), size(), s, -1) <= 0; }
-inline bool QString::operator>=(const char *s) const
+bool QString::operator>=(const char *s) const
{ return QString::compare_helper(constData(), size(), s, -1) >= 0; }
-//
-// QLatin1StringView inline members that require QString:
-//
-QT_ASCII_CAST_WARN inline bool QLatin1StringView::operator==(const char *s) const
-{ return QString::fromUtf8(s) == *this; }
-QT_ASCII_CAST_WARN inline bool QLatin1StringView::operator!=(const char *s) const
-{ return QString::fromUtf8(s) != *this; }
-QT_ASCII_CAST_WARN inline bool QLatin1StringView::operator<(const char *s) const
-{ return QString::fromUtf8(s) > *this; }
-QT_ASCII_CAST_WARN inline bool QLatin1StringView::operator>(const char *s) const
-{ return QString::fromUtf8(s) < *this; }
-QT_ASCII_CAST_WARN inline bool QLatin1StringView::operator<=(const char *s) const
-{ return QString::fromUtf8(s) >= *this; }
-QT_ASCII_CAST_WARN inline bool QLatin1StringView::operator>=(const char *s) const
-{ return QString::fromUtf8(s) <= *this; }
-
-QT_ASCII_CAST_WARN inline bool QLatin1StringView::operator==(const QByteArray &s) const
-{ return QString::fromUtf8(s) == *this; }
-QT_ASCII_CAST_WARN inline bool QLatin1StringView::operator!=(const QByteArray &s) const
-{ return QString::fromUtf8(s) != *this; }
-QT_ASCII_CAST_WARN inline bool QLatin1StringView::operator<(const QByteArray &s) const
-{ return QString::fromUtf8(s) > *this; }
-QT_ASCII_CAST_WARN inline bool QLatin1StringView::operator>(const QByteArray &s) const
-{ return QString::fromUtf8(s) < *this; }
-QT_ASCII_CAST_WARN inline bool QLatin1StringView::operator<=(const QByteArray &s) const
-{ return QString::fromUtf8(s) >= *this; }
-QT_ASCII_CAST_WARN inline bool QLatin1StringView::operator>=(const QByteArray &s) const
-{ return QString::fromUtf8(s) <= *this; }
-
-inline int QLatin1StringView::compare_helper(const QLatin1StringView &s1, const char *s2)
-{
- return QString::compare(s1, QString::fromUtf8(s2));
-}
-
-
-QT_ASCII_CAST_WARN inline bool QString::operator==(const QByteArray &s) const
+QT_ASCII_CAST_WARN bool QString::operator==(const QByteArray &s) const
{ return QString::compare_helper(constData(), size(), s.constData(), s.size()) == 0; }
-QT_ASCII_CAST_WARN inline bool QString::operator!=(const QByteArray &s) const
+QT_ASCII_CAST_WARN bool QString::operator!=(const QByteArray &s) const
{ return QString::compare_helper(constData(), size(), s.constData(), s.size()) != 0; }
-QT_ASCII_CAST_WARN inline bool QString::operator<(const QByteArray &s) const
+QT_ASCII_CAST_WARN bool QString::operator<(const QByteArray &s) const
{ return QString::compare_helper(constData(), size(), s.constData(), s.size()) < 0; }
-QT_ASCII_CAST_WARN inline bool QString::operator>(const QByteArray &s) const
+QT_ASCII_CAST_WARN bool QString::operator>(const QByteArray &s) const
{ return QString::compare_helper(constData(), size(), s.constData(), s.size()) > 0; }
-QT_ASCII_CAST_WARN inline bool QString::operator<=(const QByteArray &s) const
+QT_ASCII_CAST_WARN bool QString::operator<=(const QByteArray &s) const
{ return QString::compare_helper(constData(), size(), s.constData(), s.size()) <= 0; }
-QT_ASCII_CAST_WARN inline bool QString::operator>=(const QByteArray &s) const
+QT_ASCII_CAST_WARN bool QString::operator>=(const QByteArray &s) const
{ return QString::compare_helper(constData(), size(), s.constData(), s.size()) >= 0; }
-inline bool QByteArray::operator==(const QString &s) const
+bool QByteArray::operator==(const QString &s) const
{ return QString::compare_helper(s.constData(), s.size(), constData(), size()) == 0; }
-inline bool QByteArray::operator!=(const QString &s) const
+bool QByteArray::operator!=(const QString &s) const
{ return QString::compare_helper(s.constData(), s.size(), constData(), size()) != 0; }
-inline bool QByteArray::operator<(const QString &s) const
+bool QByteArray::operator<(const QString &s) const
{ return QString::compare_helper(s.constData(), s.size(), constData(), size()) > 0; }
-inline bool QByteArray::operator>(const QString &s) const
+bool QByteArray::operator>(const QString &s) const
{ return QString::compare_helper(s.constData(), s.size(), constData(), size()) < 0; }
-inline bool QByteArray::operator<=(const QString &s) const
+bool QByteArray::operator<=(const QString &s) const
{ return QString::compare_helper(s.constData(), s.size(), constData(), size()) >= 0; }
-inline bool QByteArray::operator>=(const QString &s) const
+bool QByteArray::operator>=(const QString &s) const
{ return QString::compare_helper(s.constData(), s.size(), constData(), size()) <= 0; }
+#endif // QT_CORE_REMOVED_SINCE(6, 8)
#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
#if !defined(QT_USE_FAST_OPERATOR_PLUS) && !defined(QT_USE_QSTRINGBUILDER)
@@ -1237,13 +1441,13 @@ QT_ASCII_CAST_WARN inline QString operator+(QString &&lhs, const QByteArray &rhs
# endif // QT_NO_CAST_FROM_ASCII
#endif // QT_USE_QSTRINGBUILDER
-inline std::string QString::toStdString() const
+std::string QString::toStdString() const
{ return toUtf8().toStdString(); }
-inline QString QString::fromStdString(const std::string &s)
+QString QString::fromStdString(const std::string &s)
{ return fromUtf8(s.data(), qsizetype(s.size())); }
-inline std::wstring QString::toStdWString() const
+std::wstring QString::toStdWString() const
{
std::wstring str;
str.resize(size());
@@ -1251,19 +1455,19 @@ inline std::wstring QString::toStdWString() const
return str;
}
-inline QString QString::fromStdWString(const std::wstring &s)
+QString QString::fromStdWString(const std::wstring &s)
{ return fromWCharArray(s.data(), qsizetype(s.size())); }
-inline QString QString::fromStdU16String(const std::u16string &s)
+QString QString::fromStdU16String(const std::u16string &s)
{ return fromUtf16(s.data(), qsizetype(s.size())); }
-inline std::u16string QString::toStdU16String() const
+std::u16string QString::toStdU16String() const
{ return std::u16string(reinterpret_cast<const char16_t*>(data()), size()); }
-inline QString QString::fromStdU32String(const std::u32string &s)
+QString QString::fromStdU32String(const std::u32string &s)
{ return fromUcs4(s.data(), qsizetype(s.size())); }
-inline std::u32string QString::toStdU32String() const
+std::u32string QString::toStdU32String() const
{
std::u32string u32str(size(), char32_t(0));
const qsizetype len = toUcs4_helper(reinterpret_cast<const char16_t *>(data()),
@@ -1272,6 +1476,11 @@ inline std::u32string QString::toStdU32String() const
return u32str;
}
+QString::operator std::u16string_view() const noexcept
+{
+ return std::u16string_view(d.data(), size_t(d.size));
+}
+
#if !defined(QT_NO_DATASTREAM) || defined(QT_BOOTSTRAPPED)
Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QString &);
Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QString &);
@@ -1280,14 +1489,14 @@ Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QString &);
Q_DECLARE_SHARED(QString)
Q_DECLARE_OPERATORS_FOR_FLAGS(QString::SectionFlags)
-inline int QString::compare(QStringView s, Qt::CaseSensitivity cs) const noexcept
+int QString::compare(QStringView s, Qt::CaseSensitivity cs) const noexcept
{ return -s.compare(*this, cs); }
-inline int QString::localeAwareCompare(QStringView s) const
+int QString::localeAwareCompare(QStringView s) const
{ return localeAwareCompare_helper(constData(), size(), s.constData(), s.size()); }
-inline int QString::localeAwareCompare(QStringView s1, QStringView s2)
+int QString::localeAwareCompare(QStringView s1, QStringView s2)
{ return localeAwareCompare_helper(s1.constData(), s1.size(), s2.constData(), s2.size()); }
-inline int QStringView::localeAwareCompare(QStringView other) const
+int QStringView::localeAwareCompare(QStringView other) const
{ return QString::localeAwareCompare(*this, other); }
#if QT_CORE_INLINE_IMPL_SINCE(6, 5)
@@ -1301,6 +1510,16 @@ quint64 QString::toULongLong(bool *ok, int base) const
return toIntegral_helper<qulonglong>(*this, ok, base);
}
#endif
+#if QT_CORE_INLINE_IMPL_SINCE(6, 7)
+qsizetype QString::indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const
+{
+ return qToStringViewIgnoringNull(*this).indexOf(ch, from, cs);
+}
+qsizetype QString::lastIndexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const
+{
+ return qToStringViewIgnoringNull(*this).lastIndexOf(ch, from, cs);
+}
+#endif
namespace QtPrivate {
// used by qPrintable() and qUtf8Printable() macros
@@ -1393,7 +1612,7 @@ qsizetype erase_if(QString &s, Predicate pred)
namespace Qt {
inline namespace Literals {
inline namespace StringLiterals {
-inline QString operator"" _s(const char16_t *str, size_t size) noexcept
+inline QString operator""_s(const char16_t *str, size_t size) noexcept
{
return QString(QStringPrivate(nullptr, const_cast<char16_t *>(str), qsizetype(size)));
}
@@ -1406,7 +1625,7 @@ inline namespace QtLiterals {
#if QT_DEPRECATED_SINCE(6, 8)
QT_DEPRECATED_VERSION_X_6_8("Use _s from Qt::StringLiterals namespace instead.")
-inline QString operator"" _qs(const char16_t *str, size_t size) noexcept
+inline QString operator""_qs(const char16_t *str, size_t size) noexcept
{
return Qt::StringLiterals::operator""_s(str, size);
}
@@ -1416,9 +1635,8 @@ inline QString operator"" _qs(const char16_t *str, size_t size) noexcept
QT_END_NAMESPACE
-#if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER)
#include <QtCore/qstringbuilder.h>
-#endif
+#include <QtCore/qstringconverter.h>
#ifdef Q_L1S_VIEW_IS_PRIMARY
# undef Q_L1S_VIEW_IS_PRIMARY
diff --git a/src/corelib/text/qstringalgorithms.h b/src/corelib/text/qstringalgorithms.h
index 888bad5dd3..71a1dbd526 100644
--- a/src/corelib/text/qstringalgorithms.h
+++ b/src/corelib/text/qstringalgorithms.h
@@ -4,19 +4,27 @@
#ifndef QSTRINGALGORITHMS_H
#define QSTRINGALGORITHMS_H
+#include <QtCore/qbytearrayalgorithms.h>
+#include <QtCore/qcontainerfwd.h>
#include <QtCore/qnamespace.h>
#include <QtCore/qstringfwd.h>
-#include <QtCore/qcontainerfwd.h>
#if 0
#pragma qt_class(QStringAlgorithms)
#endif
+#include <algorithm> // std::find
+#include <iterator> // std::size
+
+#include <QtCore/q20type_traits.h> // q20::is_constant_evaluated
+
QT_BEGIN_NAMESPACE
namespace QtPrivate {
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype qustrlen(const char16_t *str) noexcept;
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype qustrnlen(const char16_t *str, qsizetype maxlen) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION const char16_t *qustrchr(QStringView str, char16_t ch) noexcept;
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION const char16_t *qustrcasechr(QStringView str, char16_t ch) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION int compareStrings(QStringView lhs, QStringView rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION int compareStrings(QStringView lhs, QLatin1StringView rhs, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
@@ -48,11 +56,14 @@ namespace QtPrivate {
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool endsWith(QLatin1StringView haystack, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool endsWith(QLatin1StringView haystack, QLatin1StringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype findStringInsensitive(QStringView haystack, qsizetype from, char16_t needle) noexcept;
+[[nodiscard]] inline qsizetype findString(QStringView str, qsizetype from, QChar needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype findString(QStringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype findString(QStringView haystack, qsizetype from, QLatin1StringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype findString(QLatin1StringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype findString(QLatin1StringView haystack, qsizetype from, QLatin1StringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype lastIndexOf(QStringView haystack, qsizetype from, char16_t needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype lastIndexOf(QStringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype lastIndexOf(QStringView haystack, qsizetype from, QLatin1StringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype lastIndexOf(QLatin1StringView haystack, qsizetype from, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
@@ -61,6 +72,9 @@ namespace QtPrivate {
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION QStringView trimmed(QStringView s) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION QLatin1StringView trimmed(QLatin1StringView s) noexcept;
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool isLower(QStringView s) noexcept;
+[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool isUpper(QStringView s) noexcept;
+
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype count(QStringView haystack, QChar needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype count(QStringView haystack, QStringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION qsizetype count(QStringView haystack, QLatin1StringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive);
@@ -114,7 +128,82 @@ namespace QtPrivate {
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool isLatin1(QStringView s) noexcept;
[[nodiscard]] Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool isValidUtf16(QStringView s) noexcept;
-} // namespace QtPRivate
+template <typename Char, size_t N> [[nodiscard]] constexpr Q_ALWAYS_INLINE
+qsizetype lengthHelperContainerLoop(const Char (&str)[N])
+{
+#if defined(__cpp_lib_constexpr_algorithms) && defined(Q_CC_GNU_ONLY)
+ // libstdc++'s std::find / std::find_if manages to execute more steps
+ // than the loop below
+ const auto it = std::find(str, str + N, Char(0));
+ return it - str;
+#else
+ // std::char_traits<C> is deprecated for C not one of the standard char
+ // types, so we have to roll out our own loop.
+ for (size_t i = 0; i < N; ++i) {
+ if (str[i] == Char(0))
+ return qsizetype(i);
+ }
+ return qsizetype(N);
+#endif
+}
+
+template <typename Char, size_t N> [[nodiscard]] constexpr Q_ALWAYS_INLINE
+std::enable_if_t<sizeof(Char) == sizeof(char16_t), qsizetype>
+lengthHelperContainer(const Char (&str)[N])
+{
+ // The following values were empirically determined to detect the threshold
+ // at which the compiler gives up pre-calculating the std::find() below and
+ // instead inserts code to be executed at runtime.
+ constexpr size_t RuntimeThreshold =
+#if defined(Q_CC_CLANG)
+ // tested on Clang 15, 16 & 17
+ 1023
+#elif defined(Q_CC_GNU)
+ // tested through GCC 13.1 at -O3 compilation level
+ // note: at -O2, GCC always generates a loop!
+ __cplusplus >= 202002L ? 39 : 17
+#else
+ 0
+#endif
+ ;
+ if constexpr (N == 1) {
+ return str[0] == Char(0) ? 0 : 1;
+ } else if constexpr (N > RuntimeThreshold) {
+#ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED
+ if (!q20::is_constant_evaluated())
+ return QtPrivate::qustrnlen(reinterpret_cast<const char16_t *>(str), N);
+#endif
+ }
+
+ return lengthHelperContainerLoop(str);
+}
+
+inline qsizetype qstrnlen_helper(const char *str, size_t maxlen)
+{
+#if !defined(Q_COMPILER_SLOW_QSTRNLEN_COMPILATION)
+ return qstrnlen(str, maxlen);
+#else
+ return strnlen_s(str, maxlen);
+#endif
+}
+
+template <typename Char, size_t N> [[nodiscard]] constexpr inline
+std::enable_if_t<sizeof(Char) == 1, qsizetype> lengthHelperContainer(const Char (&str)[N])
+{
+#ifdef QT_SUPPORTS_IS_CONSTANT_EVALUATED
+ if (!q20::is_constant_evaluated())
+ return qstrnlen_helper(reinterpret_cast<const char *>(str), N);
+#endif
+
+ return lengthHelperContainerLoop(str);
+}
+
+template <typename Container>
+constexpr qsizetype lengthHelperContainer(const Container &c) noexcept
+{
+ return qsizetype(std::size(c));
+}
+} // namespace QtPrivate
QT_END_NAMESPACE
diff --git a/src/corelib/text/qstringalgorithms_p.h b/src/corelib/text/qstringalgorithms_p.h
index 0b8118a858..f34acb01e8 100644
--- a/src/corelib/text/qstringalgorithms_p.h
+++ b/src/corelib/text/qstringalgorithms_p.h
@@ -50,22 +50,31 @@ template <typename StringType> struct QStringAlgorithms
Q_UNREACHABLE_RETURN(StringType());
}
- static inline void trimmed_helper_positions(const Char *&begin, const Char *&end)
+ struct TrimPositions {
+ const Char *begin;
+ const Char *end;
+ };
+ // Returns {begin, end} where:
+ // - "begin" refers to the first non-space character
+ // - if there is a sequence of one or more space chacaters at the end,
+ // "end" refers to the first character in that sequence, otherwise
+ // "end" is str.cend()
+ [[nodiscard]] static TrimPositions trimmed_helper_positions(const StringType &str)
{
+ const Char *begin = str.cbegin();
+ const Char *end = str.cend();
// skip white space from end
while (begin < end && isSpace(end[-1]))
--end;
// skip white space from start
while (begin < end && isSpace(*begin))
begin++;
+ return {begin, end};
}
static inline StringType trimmed_helper(StringType &str)
{
- const Char *begin = str.cbegin();
- const Char *end = str.cend();
- trimmed_helper_positions(begin, end);
-
+ const auto [begin, end] = trimmed_helper_positions(str);
if (begin == str.cbegin() && end == str.cend())
return str;
if (!isConst && str.isDetached())
diff --git a/src/corelib/text/qstringbuilder.cpp b/src/corelib/text/qstringbuilder.cpp
index 47da2e5051..738ce833ef 100644
--- a/src/corelib/text/qstringbuilder.cpp
+++ b/src/corelib/text/qstringbuilder.cpp
@@ -57,9 +57,9 @@ QT_BEGIN_NAMESPACE
if there are three or more of them, and performs equally well in other
cases.
- \note Definnig \c QT_USE_STRINGBUILDER at build time (this is the default
- when building Qt libraries and tools), will make using \c {'+'} when
- concatenating strings work the same way as \c operator%().
+ \note Defining \c QT_USE_QSTRINGBUILDER at build time (this is the
+ default when building Qt libraries and tools), will make using \c {'+'}
+ when concatenating strings work the same way as \c operator%().
\sa QLatin1StringView, QString
*/
diff --git a/src/corelib/text/qstringbuilder.h b/src/corelib/text/qstringbuilder.h
index 4318e219ed..853033b2d9 100644
--- a/src/corelib/text/qstringbuilder.h
+++ b/src/corelib/text/qstringbuilder.h
@@ -1,6 +1,8 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include <QtCore/qstring.h>
+
#ifndef QSTRINGBUILDER_H
#define QSTRINGBUILDER_H
@@ -11,7 +13,6 @@
#pragma qt_sync_stop_processing
#endif
-#include <QtCore/qstring.h>
#include <QtCore/qbytearray.h>
#include <string.h>
@@ -30,13 +31,25 @@ protected:
static void appendLatin1To(QLatin1StringView in, QChar *out) noexcept;
};
-template <typename T> struct QConcatenable {};
+template <typename T> struct QConcatenable;
+
+template <typename T>
+using QConcatenableEx = QConcatenable<q20::remove_cvref_t<T>>;
namespace QtStringBuilder {
template <typename A, typename B> struct ConvertToTypeHelper
{ typedef A ConvertTo; };
template <typename T> struct ConvertToTypeHelper<T, QString>
{ typedef QString ConvertTo; };
+
+ template <typename T> using HasIsNull = decltype(std::declval<const T &>().isNull());
+ template <typename T> bool isNull(const T &t)
+ {
+ if constexpr (qxp::is_detected_v<HasIsNull, T>)
+ return t.isNull();
+ else
+ return false;
+ }
}
template<typename Builder, typename T>
@@ -63,28 +76,50 @@ struct QStringBuilderBase<Builder, QString> : public QStringBuilderCommon<Builde
};
template <typename A, typename B>
-class QStringBuilder : public QStringBuilderBase<QStringBuilder<A, B>, typename QtStringBuilder::ConvertToTypeHelper<typename QConcatenable<A>::ConvertTo, typename QConcatenable<B>::ConvertTo>::ConvertTo>
+class QStringBuilder : public QStringBuilderBase<QStringBuilder<A, B>,
+ typename QtStringBuilder::ConvertToTypeHelper<
+ typename QConcatenableEx<A>::ConvertTo,
+ typename QConcatenableEx<B>::ConvertTo
+ >::ConvertTo
+ >
{
public:
- QStringBuilder(const A &a_, const B &b_) : a(a_), b(b_) {}
+ QStringBuilder(A &&a_, B &&b_) : a(std::forward<A>(a_)), b(std::forward<B>(b_)) {}
+
+ QStringBuilder(QStringBuilder &&) = default;
+ QStringBuilder(const QStringBuilder &) = default;
+ ~QStringBuilder() = default;
+
private:
friend class QByteArray;
friend class QString;
template <typename T> T convertTo() const
{
- const qsizetype len = QConcatenable< QStringBuilder<A, B> >::size(*this);
- T s(len, Qt::Uninitialized);
+ if (isNull()) {
+ // appending two null strings must give back a null string,
+ // so we're special casing this one out, QTBUG-114206
+ return T();
+ }
- // we abuse const_cast / constData here because we know we've just
- // allocated the data and we're the only reference count
- typename T::iterator d = const_cast<typename T::iterator>(s.constData());
- typename T::const_iterator const start = d;
- QConcatenable< QStringBuilder<A, B> >::appendTo(*this, d);
+ const qsizetype len = Concatenable::size(*this);
+ T s(len, Qt::Uninitialized);
- if (!QConcatenable< QStringBuilder<A, B> >::ExactSize && len != d - start) {
- // this resize is necessary since we allocate a bit too much
- // when dealing with variable sized 8-bit encodings
- s.resize(d - start);
+ // Using data_ptr() here (private API) so we can bypass the
+ // isDetached() and the replacement of a null pointer with _empty in
+ // both QString and QByteArray's data() and constData(). The result is
+ // the same if len != 0.
+ auto d = reinterpret_cast<typename T::iterator>(s.data_ptr().data());
+ const auto start = d;
+ Concatenable::appendTo(*this, d);
+
+ if constexpr (Concatenable::ExactSize) {
+ Q_UNUSED(start)
+ } else {
+ if (len != d - start) {
+ // this resize is necessary since we allocate a bit too much
+ // when dealing with variable sized 8-bit encodings
+ s.resize(d - start);
+ }
}
return s;
}
@@ -96,45 +131,19 @@ public:
qsizetype size() const { return Concatenable::size(*this); }
- const A &a;
- const B &b;
-};
-
-template <>
-class QStringBuilder <QString, QString> : public QStringBuilderBase<QStringBuilder<QString, QString>, QString>
-{
- public:
- QStringBuilder(const QString &a_, const QString &b_) : a(a_), b(b_) {}
- QStringBuilder(const QStringBuilder &other) : a(other.a), b(other.b) {}
-
- operator QString() const
- { QString r(a); r += b; return r; }
-
- const QString &a;
- const QString &b;
-
- private:
- QStringBuilder &operator=(const QStringBuilder &) = delete;
-};
-
-template <>
-class QStringBuilder <QByteArray, QByteArray> : public QStringBuilderBase<QStringBuilder<QByteArray, QByteArray>, QByteArray>
-{
- public:
- QStringBuilder(const QByteArray &a_, const QByteArray &b_) : a(a_), b(b_) {}
- QStringBuilder(const QStringBuilder &other) : a(other.a), b(other.b) {}
-
- operator QByteArray() const
- { QByteArray r(a); r += b; return r; }
+ bool isNull() const
+ {
+ return QtStringBuilder::isNull(a) && QtStringBuilder::isNull(b);
+ }
- const QByteArray &a;
- const QByteArray &b;
+ A a;
+ B b;
- private:
- QStringBuilder &operator=(const QStringBuilder &) = delete;
+private:
+ QStringBuilder &operator=(QStringBuilder &&) = delete;
+ QStringBuilder &operator=(const QStringBuilder &) = delete;
};
-
template <> struct QConcatenable<char> : private QAbstractConcatenable
{
typedef char type;
@@ -364,10 +373,10 @@ template <> struct QConcatenable<QByteArray> : private QAbstractConcatenable
#endif
static inline void appendTo(const QByteArray &ba, char *&out)
{
- const char *a = ba.constData();
- const char * const end = ba.end();
- while (a != end)
- *out++ = *a++;
+ const qsizetype n = ba.size();
+ if (n)
+ memcpy(out, ba.begin(), n);
+ out += n;
}
};
@@ -376,34 +385,37 @@ template <typename A, typename B>
struct QConcatenable< QStringBuilder<A, B> >
{
typedef QStringBuilder<A, B> type;
- typedef typename QtStringBuilder::ConvertToTypeHelper<typename QConcatenable<A>::ConvertTo, typename QConcatenable<B>::ConvertTo>::ConvertTo ConvertTo;
- enum { ExactSize = QConcatenable<A>::ExactSize && QConcatenable<B>::ExactSize };
+ using ConvertTo = typename QtStringBuilder::ConvertToTypeHelper<
+ typename QConcatenableEx<A>::ConvertTo,
+ typename QConcatenableEx<B>::ConvertTo
+ >::ConvertTo;
+ enum { ExactSize = QConcatenableEx<A>::ExactSize && QConcatenableEx<B>::ExactSize };
static qsizetype size(const type &p)
{
- return QConcatenable<A>::size(p.a) + QConcatenable<B>::size(p.b);
+ return QConcatenableEx<A>::size(p.a) + QConcatenableEx<B>::size(p.b);
}
template<typename T> static inline void appendTo(const type &p, T *&out)
{
- QConcatenable<A>::appendTo(p.a, out);
- QConcatenable<B>::appendTo(p.b, out);
+ QConcatenableEx<A>::appendTo(p.a, out);
+ QConcatenableEx<B>::appendTo(p.b, out);
}
};
-template <typename A, typename B>
-QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>
-operator%(const A &a, const B &b)
+template <typename A, typename B,
+ typename = std::void_t<typename QConcatenableEx<A>::type, typename QConcatenableEx<B>::type>>
+auto operator%(A &&a, B &&b)
{
- return QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>(a, b);
+ return QStringBuilder<A, B>(std::forward<A>(a), std::forward<B>(b));
}
// QT_USE_FAST_OPERATOR_PLUS was introduced in 4.7, QT_USE_QSTRINGBUILDER is to be used from 4.8 onwards
// QT_USE_FAST_OPERATOR_PLUS does not remove the normal operator+ for QByteArray
#if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER)
-template <typename A, typename B>
-QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>
-operator+(const A &a, const B &b)
+template <typename A, typename B,
+ typename = std::void_t<typename QConcatenableEx<A>::type, typename QConcatenableEx<B>::type>>
+auto operator+(A &&a, B &&b)
{
- return QStringBuilder<typename QConcatenable<A>::type, typename QConcatenable<B>::type>(a, b);
+ return std::forward<A>(a) % std::forward<B>(b);
}
#endif
diff --git a/src/corelib/text/qstringconverter.cpp b/src/corelib/text/qstringconverter.cpp
index 90f277ba61..67c75d708e 100644
--- a/src/corelib/text/qstringconverter.cpp
+++ b/src/corelib/text/qstringconverter.cpp
@@ -10,6 +10,8 @@
#include "private/qstringiterator_p.h"
#include "private/qtools_p.h"
#include "qbytearraymatcher.h"
+#include "qcontainertools_impl.h"
+#include <QtCore/qbytearraylist.h>
#if QT_CONFIG(icu)
#include <unicode/ucnv.h>
@@ -22,9 +24,13 @@
#include <qt_windows.h>
#ifndef QT_BOOTSTRAPPED
#include <QtCore/qvarlengtharray.h>
+#include <QtCore/q20iterator.h>
+#include <QtCore/private/qnumeric_p.h>
#endif // !QT_BOOTSTRAPPED
#endif
+#include <array>
+
#if __has_include(<bit>) && __cplusplus > 201703L
#include <bit>
#endif
@@ -202,7 +208,7 @@ static inline const uchar *simdFindNonAscii(const uchar *src, const uchar *end,
continue;
uint n = _mm256_movemask_epi8(data);
- Q_ASSUME(n);
+ Q_ASSERT(n);
// find the next probable ASCII character
// we don't want to load 32 bytes again in this loop if we know there are non-ASCII
@@ -936,6 +942,7 @@ int QUtf8::compareUtf8(QByteArrayView lhs, QByteArrayView rhs, Qt::CaseSensitivi
return (end1 > src1) - (end2 > src2);
}
+#ifndef QT_BOOTSTRAPPED
QByteArray QUtf16::convertFromUnicode(QStringView in, QStringConverter::State *state, DataEndianness endian)
{
bool writeBom = !(state->internalState & HeaderDone) && state->flags & QStringConverter::Flag::WriteBom;
@@ -1245,6 +1252,7 @@ QChar *QUtf32::convertToUnicode(QChar *out, QByteArrayView in, QStringConverter:
return out;
}
+#endif // !QT_BOOTSTRAPPED
#if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED)
int QLocal8Bit::checkUtf8()
@@ -1252,186 +1260,365 @@ int QLocal8Bit::checkUtf8()
return GetACP() == CP_UTF8 ? 1 : -1;
}
-static QString convertToUnicodeCharByChar(QByteArrayView in, QStringConverter::State *state)
+QString QLocal8Bit::convertToUnicode_sys(QByteArrayView in, QStringConverter::State *state)
{
- qsizetype length = in.size();
- const char *chars = in.data();
-
- Q_ASSERT(state);
- if (state->flags & QStringConverter::Flag::Stateless) // temporary
- state = nullptr;
-
- if (!chars || !length)
- return QString();
-
- qsizetype copyLocation = 0;
- qsizetype extra = 2;
- if (state && state->remainingChars) {
- copyLocation = state->remainingChars;
- extra += copyLocation;
- }
- qsizetype newLength = length + extra;
- char *mbcs = new char[newLength];
- //ensure that we have a NULL terminated string
- mbcs[newLength-1] = 0;
- mbcs[newLength-2] = 0;
- memcpy(&(mbcs[copyLocation]), chars, length);
- if (copyLocation) {
- //copy the last character from the state
- mbcs[0] = (char)state->state_data[0];
- state->remainingChars = 0;
- }
- const char *mb = mbcs;
- const char *next = 0;
- QString s;
- while ((next = CharNextExA(CP_ACP, mb, 0)) != mb) {
- wchar_t wc[2] ={0};
- int charlength = int(next - mb); // always just a few bytes
- int len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED|MB_ERR_INVALID_CHARS, mb, charlength, wc, 2);
- if (len>0) {
- s.append(QChar(wc[0]));
- } else {
- int r = GetLastError();
- //check if the character being dropped is the last character
- if (r == ERROR_NO_UNICODE_TRANSLATION && mb == (mbcs+newLength -3) && state) {
- state->remainingChars = 1;
- state->state_data[0] = (char)*mb;
- }
- }
- mb = next;
- }
- delete [] mbcs;
- return s;
+ return convertToUnicode_sys(in, CP_ACP, state);
}
-
-QString QLocal8Bit::convertToUnicode_sys(QByteArrayView in, QStringConverter::State *state)
+QString QLocal8Bit::convertToUnicode_sys(QByteArrayView in, quint32 codePage,
+ QStringConverter::State *state)
{
- qsizetype length = in.size();
-
- Q_ASSERT(length < INT_MAX); // ### FIXME
const char *mb = in.data();
- int mblen = length;
+ qsizetype mblen = in.size();
+
+ Q_ASSERT(state);
+ qsizetype &invalidChars = state->invalidChars;
+ using Flag = QStringConverter::Flag;
+ const bool useNullForReplacement = !!(state->flags & Flag::ConvertInvalidToNull);
+ const char16_t replacementCharacter = useNullForReplacement ? QChar::Null
+ : QChar::ReplacementCharacter;
+ if (state->flags & Flag::Stateless) {
+ Q_ASSERT(state->remainingChars == 0);
+ state = nullptr;
+ }
if (!mb || !mblen)
return QString();
- QVarLengthArray<wchar_t, 4096> wc(4096);
- int len;
+ // Use a local stack-buffer at first to allow us a decently large container
+ // to avoid a lot of resizing, without also returning an overallocated
+ // QString to the user for small strings.
+ // Then we can be fast for small strings and take the hit of extra resizes
+ // and measuring how much storage is needed for large strings.
+ std::array<wchar_t, 4096> buf;
+ wchar_t *out = buf.data();
+ qsizetype outlen = buf.size();
+
QString sp;
- bool prepend = false;
- char state_data = 0;
- int remainingChars = 0;
-
- //save the current state information
- if (state) {
- state_data = (char)state->state_data[0];
- remainingChars = state->remainingChars;
- }
- //convert the pending character (if available)
- if (state && remainingChars) {
- char prev[3] = {0};
- prev[0] = state_data;
- prev[1] = mb[0];
- remainingChars = 0;
- len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
- prev, 2, wc.data(), wc.length());
- if (len) {
- sp.append(QChar(wc[0]));
- if (mblen == 1) {
- state->remainingChars = 0;
- return sp;
- }
- prepend = true;
- mb++;
- mblen--;
- wc[0] = 0;
+ // Return a pointer to storage where we have enough space for `size`
+ const auto growOut = [&](qsizetype size) -> std::tuple<wchar_t *, qsizetype> {
+ if (outlen >= size)
+ return {out, outlen};
+ const bool wasStackBuffer = sp.isEmpty();
+ const auto begin = wasStackBuffer ? buf.data() : reinterpret_cast<wchar_t *>(sp.data());
+ const qsizetype offset = qsizetype(std::distance(begin, out));
+ qsizetype newSize = 0;
+ if (Q_UNLIKELY(qAddOverflow(offset, size, &newSize))) {
+ Q_CHECK_PTR(false);
+ return {nullptr, 0};
+ }
+ sp.resize(newSize);
+ auto it = reinterpret_cast<wchar_t *>(sp.data());
+ if (wasStackBuffer)
+ it = std::copy_n(buf.data(), offset, it);
+ else
+ it += offset;
+ return {it, size};
+ };
+
+ // Convert the pending characters (if available)
+ while (state && state->remainingChars && mblen) {
+ QStringConverter::State localState;
+ localState.flags = state->flags;
+ // Use at most 6 characters as a guess for the longest encoded character
+ // in any multibyte encoding.
+ // Even with a total of 2 bytes of overhead that would leave around
+ // 2^(4 * 8) possible characters
+ std::array<char, 6> prev = {0};
+ Q_ASSERT(state->remainingChars <= q20::ssize(state->state_data));
+ qsizetype index = 0;
+ for (; index < state->remainingChars; ++index)
+ prev[index] = state->state_data[index];
+ const qsizetype toCopy = std::min(q20::ssize(prev) - index, mblen);
+ for (qsizetype i = 0; i < toCopy; ++i, ++index)
+ prev[index] = mb[i];
+ mb += toCopy;
+ mblen -= toCopy;
+
+ // Recursing:
+ // Since we are using a clean local state it will try to decode what was
+ // stored in our state + some extra octets from input (`prev`). If some
+ // part fails we will have those characters stored in the local state's
+ // storage, and we can extract those. It may also output some
+ // replacement characters, which we'll count in the invalidChars.
+ // In the best case we only do this once, but we will loop until we have
+ // resolved all the remaining characters or we have run out of new input
+ // in which case we may still have remaining characters.
+ const QString tmp = convertToUnicode_sys(QByteArrayView(prev.data(), index), codePage,
+ &localState);
+ std::tie(out, outlen) = growOut(tmp.size());
+ if (!out)
+ return {};
+ out = std::copy_n(reinterpret_cast<const wchar_t *>(tmp.constData()), tmp.size(), out);
+ outlen -= tmp.size();
+ const qsizetype tail = toCopy - localState.remainingChars;
+ if (tail >= 0) {
+ // Everything left to process comes from `in`, so we can stop
+ // looping. Adjust the window for `in` and unset remainingChars to
+ // signal that we're done.
+ mb -= localState.remainingChars;
+ mblen += localState.remainingChars;
+ localState.remainingChars = 0;
}
+ state->remainingChars = localState.remainingChars;
+ state->invalidChars += localState.invalidChars;
+ std::copy_n(localState.state_data, state->remainingChars, state->state_data);
}
- while (!(len=MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED|MB_ERR_INVALID_CHARS,
- mb, mblen, wc.data(), wc.length()))) {
- int r = GetLastError();
- if (r == ERROR_INSUFFICIENT_BUFFER) {
- const int wclen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
- mb, mblen, 0, 0);
- wc.resize(wclen);
- } else if (r == ERROR_NO_UNICODE_TRANSLATION) {
- //find the last non NULL character
- while (mblen > 1 && !(mb[mblen-1]))
- mblen--;
- //check whether, we hit an invalid character in the middle
- if ((mblen <= 1) || (remainingChars && state_data))
- return convertToUnicodeCharByChar(in, state);
- //Remove the last character and try again...
- state_data = mb[mblen-1];
- remainingChars = 1;
- mblen--;
+ Q_ASSERT(!state || state->remainingChars == 0 || mblen == 0);
+
+ // Need it in this scope, since we try to decrease our window size if we
+ // encounter an error
+ int nextIn = qt_saturate<int>(mblen);
+ while (mblen > 0) {
+ std::tie(out, outlen) = growOut(1); // Need space for at least one character
+ if (!out)
+ return {};
+ const int nextOut = qt_saturate<int>(outlen);
+ int len = MultiByteToWideChar(codePage, MB_ERR_INVALID_CHARS, mb, nextIn, out, nextOut);
+ if (len) {
+ mb += nextIn;
+ mblen -= nextIn;
+ out += len;
+ outlen -= len;
} else {
- // Fail.
- qWarning("MultiByteToWideChar: Cannot convert multibyte text");
- break;
+ int r = GetLastError();
+ if (r == ERROR_INSUFFICIENT_BUFFER) {
+ const int wclen = MultiByteToWideChar(codePage, 0, mb, nextIn, 0, 0);
+ std::tie(out, outlen) = growOut(wclen);
+ if (!out)
+ return {};
+ } else if (r == ERROR_NO_UNICODE_TRANSLATION) {
+ // Can't decode the current window, so either store the state,
+ // reduce window size or output a replacement character.
+
+ // Check if we can store all remaining characters in the state
+ // to be used next time we're called:
+ if (state && mblen <= q20::ssize(state->state_data)) {
+ state->remainingChars = mblen;
+ std::copy_n(mb, mblen, state->state_data);
+ mb += mblen;
+ mblen = 0;
+ break;
+ }
+
+ // .. if not, try to find the last valid character in the window
+ // and try again with a shrunken window:
+ if (nextIn > 1) {
+ // There may be some incomplete data at the end of our current
+ // window, so decrease the window size and try again.
+ // In the worst case scenario there is gigs of undecodable
+ // garbage, but what are we supposed to do about that?
+ const auto it = CharPrevExA(codePage, mb, mb + nextIn, 0);
+ if (it != mb)
+ nextIn = int(it - mb);
+ else
+ --nextIn;
+ continue;
+ }
+
+ // Finally, we are forced to output a replacement character for
+ // the first byte in the window:
+ std::tie(out, outlen) = growOut(1);
+ if (!out)
+ return {};
+ *out = replacementCharacter;
+ ++invalidChars;
+ ++out;
+ --outlen;
+ ++mb;
+ --mblen;
+ } else {
+ // Fail.
+ qWarning("MultiByteToWideChar: Cannot convert multibyte text");
+ break;
+ }
}
+ nextIn = qt_saturate<int>(mblen);
}
- if (len <= 0)
- return QString();
+ if (sp.isEmpty()) {
+ // We must have only used the stack buffer
+ if (out != buf.data()) // else: we return null-string
+ sp = QStringView(buf.data(), out).toString();
+ } else{
+ const auto begin = reinterpret_cast<wchar_t *>(sp.data());
+ sp.truncate(std::distance(begin, out));
+ }
- if (wc[len-1] == 0) // len - 1: we don't want terminator
- --len;
+ if (sp.size() && sp.back().isNull())
+ sp.chop(1);
- //save the new state information
- if (state) {
- state->state_data[0] = (char)state_data;
- state->remainingChars = remainingChars;
+ if (!state && mblen > 0) {
+ // We have trailing character(s) that could not be converted, and
+ // nowhere to cache them
+ sp.resize(sp.size() + mblen, replacementCharacter);
+ invalidChars += mblen;
}
- QString s((QChar*)wc.data(), len);
- if (prepend) {
- return sp+s;
- }
- return s;
+ return sp;
}
QByteArray QLocal8Bit::convertFromUnicode_sys(QStringView in, QStringConverter::State *state)
{
- const QChar *ch = in.data();
+ return convertFromUnicode_sys(in, CP_ACP, state);
+}
+
+QByteArray QLocal8Bit::convertFromUnicode_sys(QStringView in, quint32 codePage,
+ QStringConverter::State *state)
+{
+ const wchar_t *ch = reinterpret_cast<const wchar_t *>(in.data());
qsizetype uclen = in.size();
- Q_ASSERT(uclen < INT_MAX); // ### FIXME
Q_ASSERT(state);
- Q_UNUSED(state); // ### Fixme
- if (state->flags & QStringConverter::Flag::Stateless) // temporary
+ // The Windows API has a *boolean* out-parameter that says if a replacement
+ // character was used, but it gives us no way to know _how many_ were used.
+ // Since we cannot simply scan the string for replacement characters
+ // (which is potentially a question mark, and thus a valid character),
+ // we simply do not track the number of invalid characters here.
+ // auto &invalidChars = state->invalidChars;
+
+ using Flag = QStringConverter::Flag;
+ if (state->flags & Flag::Stateless) { // temporary
+ Q_ASSERT(state->remainingChars == 0);
state = nullptr;
+ }
if (!ch)
return QByteArray();
if (uclen == 0)
return QByteArray("");
- BOOL used_def;
- QByteArray mb(4096, 0);
- int len;
- while (!(len=WideCharToMultiByte(CP_ACP, 0, (const wchar_t*)ch, uclen,
- mb.data(), mb.size()-1, 0, &used_def)))
- {
- int r = GetLastError();
- if (r == ERROR_INSUFFICIENT_BUFFER) {
- mb.resize(1+WideCharToMultiByte(CP_ACP, 0,
- (const wchar_t*)ch, uclen,
- 0, 0, 0, &used_def));
- // and try again...
+
+ // Use a local stack-buffer at first to allow us a decently large container
+ // to avoid a lot of resizing, without also returning an overallocated
+ // QByteArray to the user for small strings.
+ // Then we can be fast for small strings and take the hit of extra resizes
+ // and measuring how much storage is needed for large strings.
+ std::array<char, 4096> buf;
+ char *out = buf.data();
+ qsizetype outlen = buf.size();
+ QByteArray mb;
+
+ if (state && state->remainingChars > 0) {
+ Q_ASSERT(state->remainingChars == 1);
+ // Let's try to decode the pending character
+ wchar_t wc[2] = { wchar_t(state->state_data[0]), ch[0] };
+ // Check if the second character is a valid low surrogate,
+ // otherwise we'll just decode the first character, for which windows
+ // will output a replacement character.
+ const bool validCodePoint = QChar::isLowSurrogate(wc[1]);
+ int len = WideCharToMultiByte(codePage, 0, wc, validCodePoint ? 2 : 1, out, outlen, nullptr,
+ nullptr);
+ if (!len)
+ return {}; // Cannot recover, and I refuse to believe it was a size limitation
+ out += len;
+ outlen -= len;
+ if (validCodePoint) {
+ ++ch;
+ --uclen;
+ }
+ state->remainingChars = 0;
+ state->state_data[0] = 0;
+ if (uclen == 0)
+ return QByteArrayView(buf.data(), len).toByteArray();
+ }
+
+ if (state && QChar::isHighSurrogate(ch[uclen - 1])) {
+ // We can handle a missing low surrogate at the end of the string,
+ // so if there is one, exclude it now and store it in the state.
+ state->remainingChars = 1;
+ state->state_data[0] = ch[uclen - 1];
+ --uclen;
+ if (uclen == 0)
+ return QByteArray();
+ }
+
+ Q_ASSERT(uclen > 0);
+
+ // Return a pointer to storage where we have enough space for `size`
+ const auto growOut = [&](qsizetype size) -> std::tuple<char *, qsizetype> {
+ if (outlen >= size)
+ return {out, outlen};
+ const bool wasStackBuffer = mb.isEmpty();
+ const auto begin = wasStackBuffer ? buf.data() : mb.data();
+ const qsizetype offset = qsizetype(std::distance(begin, out));
+ qsizetype newSize = 0;
+ if (Q_UNLIKELY(qAddOverflow(offset, size, &newSize))) {
+ Q_CHECK_PTR(false);
+ return {nullptr, 0};
+ }
+ mb.resize(newSize);
+ auto it = mb.data();
+ if (wasStackBuffer)
+ it = std::copy_n(buf.data(), offset, it);
+ else
+ it += offset;
+ return {it, size};
+ };
+
+ const auto getNextWindowSize = [&]() {
+ int nextIn = qt_saturate<int>(uclen);
+ // The Windows API has some issues if the current window ends in the
+ // middle of a surrogate pair, so we avoid that:
+ if (nextIn > 1 && QChar::isHighSurrogate(ch[nextIn - 1]))
+ --nextIn;
+ return nextIn;
+ };
+
+ int len = 0;
+ while (uclen > 0) {
+ const int nextIn = getNextWindowSize();
+ std::tie(out, outlen) = growOut(1); // We need at least one byte
+ if (!out)
+ return {};
+ const int nextOut = qt_saturate<int>(outlen);
+ len = WideCharToMultiByte(codePage, 0, ch, nextIn, out, nextOut, nullptr, nullptr);
+ if (len > 0) {
+ ch += nextIn;
+ uclen -= nextIn;
+ out += len;
+ outlen -= len;
} else {
- // Fail. Probably can't happen in fact (dwFlags is 0).
+ int r = GetLastError();
+ if (r == ERROR_INSUFFICIENT_BUFFER) {
+ int neededLength = WideCharToMultiByte(codePage, 0, ch, nextIn, nullptr, 0,
+ nullptr, nullptr);
+ if (neededLength <= 0) {
+ // Fail. Observed with UTF8 where the input window was max int and ended in an
+ // incomplete sequence, probably a Windows bug. We try to avoid that from
+ // happening by reducing the window size in that case. But let's keep this
+ // branch just in case of other bugs.
+#ifndef QT_NO_DEBUG
+ r = GetLastError();
+ fprintf(stderr,
+ "WideCharToMultiByte: Cannot convert multibyte text (error %d)\n", r);
+#endif // !QT_NO_DEBUG
+ break;
+ }
+ std::tie(out, outlen) = growOut(neededLength);
+ if (!out)
+ return {};
+ // and try again...
+ } else {
+ // Fail. Probably can't happen in fact (dwFlags is 0).
#ifndef QT_NO_DEBUG
- // Can't use qWarning(), as it'll recurse to handle %ls
- fprintf(stderr,
- "WideCharToMultiByte: Cannot convert multibyte text (error %d): %ls\n",
- r, reinterpret_cast<const wchar_t*>(QString(ch, uclen).utf16()));
+ // Can't use qWarning(), as it'll recurse to handle %ls
+ fprintf(stderr,
+ "WideCharToMultiByte: Cannot convert multibyte text (error %d): %ls\n", r,
+ reinterpret_cast<const wchar_t *>(
+ QStringView(ch, uclen).left(100).toString().utf16()));
#endif
- break;
+ break;
+ }
}
}
- mb.resize(len);
+ if (mb.isEmpty()) {
+ // We must have only used the stack buffer
+ if (out != buf.data()) // else: we return null-array
+ mb = QByteArrayView(buf.data(), out).toByteArray();
+ } else {
+ mb.truncate(std::distance(mb.data(), out));
+ }
return mb;
}
#endif
@@ -1462,6 +1649,7 @@ void QStringConverter::State::reset() noexcept
}
}
+#ifndef QT_BOOTSTRAPPED
static QChar *fromUtf16(QChar *out, QByteArrayView in, QStringConverter::State *state)
{
return QUtf16::convertToUnicode(out, in, state, DetectEndianness);
@@ -1521,6 +1709,7 @@ static char *toUtf32LE(char *out, QStringView in, QStringConverter::State *state
{
return QUtf32::convertFromUnicode(out, in, state, LittleEndianness);
}
+#endif // !QT_BOOTSTRAPPED
char *QLatin1::convertFromUnicode(char *out, QStringView in, QStringConverter::State *state) noexcept
{
@@ -1562,11 +1751,13 @@ static char *toLocal8Bit(char *out, QStringView in, QStringConverter::State *sta
static qsizetype fromUtf8Len(qsizetype l) { return l + 1; }
static qsizetype toUtf8Len(qsizetype l) { return 3*(l + 1); }
+#ifndef QT_BOOTSTRAPPED
static qsizetype fromUtf16Len(qsizetype l) { return l/2 + 2; }
static qsizetype toUtf16Len(qsizetype l) { return 2*(l + 1); }
static qsizetype fromUtf32Len(qsizetype l) { return l/2 + 2; }
static qsizetype toUtf32Len(qsizetype l) { return 4*(l + 1); }
+#endif
static qsizetype fromLatin1Len(qsizetype l) { return l + 1; }
static qsizetype toLatin1Len(qsizetype l) { return l + 1; }
@@ -1599,7 +1790,7 @@ static qsizetype toLatin1Len(qsizetype l) { return l + 1; }
operation, encoding UTF-16 encoded data (usually in the form of a QString) to
the requested encoding.
- The supported encodings are:
+ The following encodings are always supported:
\list
\li UTF-8
@@ -1613,6 +1804,10 @@ static qsizetype toLatin1Len(qsizetype l) { return l + 1; }
\li The system encoding
\endlist
+ QStringConverter may support more encodings depending on how Qt was
+ compiled. If more codecs are supported, they can be listed using
+ availableCodecs().
+
\l {QStringConverter}s can be used as follows to convert some encoded
string to and from UTF-16.
@@ -1702,12 +1897,14 @@ static qsizetype toLatin1Len(qsizetype l) { return l + 1; }
const QStringConverter::Interface QStringConverter::encodingInterfaces[QStringConverter::LastEncoding + 1] =
{
{ "UTF-8", QUtf8::convertToUnicode, fromUtf8Len, QUtf8::convertFromUnicode, toUtf8Len },
+#ifndef QT_BOOTSTRAPPED
{ "UTF-16", fromUtf16, fromUtf16Len, toUtf16, toUtf16Len },
{ "UTF-16LE", fromUtf16LE, fromUtf16Len, toUtf16LE, toUtf16Len },
{ "UTF-16BE", fromUtf16BE, fromUtf16Len, toUtf16BE, toUtf16Len },
{ "UTF-32", fromUtf32, fromUtf32Len, toUtf32, toUtf32Len },
{ "UTF-32LE", fromUtf32LE, fromUtf32Len, toUtf32LE, toUtf32Len },
{ "UTF-32BE", fromUtf32BE, fromUtf32Len, toUtf32BE, toUtf32Len },
+#endif
{ "ISO-8859-1", QLatin1::convertToUnicode, fromLatin1Len, QLatin1::convertFromUnicode, toLatin1Len },
{ "Locale", fromLocal8Bit, fromUtf8Len, toLocal8Bit, toUtf8Len }
};
@@ -1715,21 +1912,16 @@ const QStringConverter::Interface QStringConverter::encodingInterfaces[QStringCo
// match names case insensitive and skipping '-' and '_'
static bool nameMatch(const char *a, const char *b)
{
- while (*a && *b) {
- if (*a == '-' || *a == '_') {
+ do {
+ while (*a == '-' || *a == '_')
++a;
- continue;
- }
- if (*b == '-' || *b == '_') {
+ while (*b == '-' || *b == '_')
++b;
- continue;
- }
- if (QtMiscUtils::toAsciiLower(*a) != QtMiscUtils::toAsciiLower(*b))
- return false;
- ++a;
- ++b;
- }
- return !*a && !*b;
+ if (!*a && !*b) // end of both strings
+ return true;
+ } while (QtMiscUtils::toAsciiLower(*a++) == QtMiscUtils::toAsciiLower(*b++));
+
+ return false;
}
@@ -1784,7 +1976,7 @@ struct QStringConverterICU : QStringConverter
const void *context;
ucnv_getToUCallBack(icu_conv, &action, &context);
if (context != state)
- ucnv_setToUCallBack(icu_conv, action, &state, nullptr, nullptr, &err);
+ ucnv_setToUCallBack(icu_conv, action, state, nullptr, nullptr, &err);
ucnv_toUnicode(icu_conv, &target, targetLimit, &source, sourceLimit, nullptr, flush, &err);
// We did reserve enough space:
@@ -1817,7 +2009,7 @@ struct QStringConverterICU : QStringConverter
const void *context;
ucnv_getFromUCallBack(icu_conv, &action, &context);
if (context != state)
- ucnv_setFromUCallBack(icu_conv, action, &state, nullptr, nullptr, &err);
+ ucnv_setFromUCallBack(icu_conv, action, state, nullptr, nullptr, &err);
ucnv_fromUnicode(icu_conv, &target, targetLimit, &source, sourceLimit, nullptr, flush, &err);
// We did reserve enough space:
@@ -2032,6 +2224,7 @@ const char *QStringConverter::name() const noexcept
Returns the canonical name of the encoding this QStringConverter can encode or decode.
Returns a nullptr if the converter is not valid.
+ The returned name is UTF-8 encoded.
\sa isValid()
*/
@@ -2043,9 +2236,13 @@ const char *QStringConverter::name() const noexcept
\c{std::nullopt} is returned. Such a name may, none the less, be accepted by
the QStringConverter constructor when Qt is built with ICU, if ICU provides a
converter with the given name.
+
+ \a name is expected to be UTF-8 encoded.
*/
std::optional<QStringConverter::Encoding> QStringConverter::encodingForName(const char *name) noexcept
{
+ if (!name)
+ return std::nullopt;
for (qsizetype i = 0; i < LastEncoding + 1; ++i) {
if (nameMatch(encodingInterfaces[i].name, name))
return QStringConverter::Encoding(i);
@@ -2055,6 +2252,7 @@ std::optional<QStringConverter::Encoding> QStringConverter::encodingForName(cons
return std::nullopt;
}
+#ifndef QT_BOOTSTRAPPED
/*!
Returns the encoding for the content of \a data if it can be determined.
\a expectedFirstCharacter can be passed as an additional hint to help determine
@@ -2163,6 +2361,63 @@ std::optional<QStringConverter::Encoding> QStringConverter::encodingForHtml(QByt
return Utf8;
}
+static qsizetype availableCodecCount()
+{
+#if !QT_CONFIG(icu)
+ return QStringConverter::Encoding::LastEncoding;
+#else
+ /* icu contains also the names of what Qt provides
+ except for the special Locale one (so add one for it)
+ */
+ return 1 + ucnv_countAvailable();
+#endif
+}
+
+/*!
+ Returns a list of names of supported codecs. The names returned
+ by this function can be passed to QStringEncoder's and
+ QStringDecoder's constructor to create a en- or decoder for
+ the given codec.
+
+ This function may be used to obtain a listing of additional codecs beyond
+ the standard ones. Support for additional codecs requires Qt be compiled
+ with support for the ICU library.
+
+ \note The order of codecs is an internal implementation detail
+ and not guaranteed to be stable.
+ */
+QStringList QStringConverter::availableCodecs()
+{
+ auto availableCodec = [](qsizetype index) -> QString
+ {
+ #if !QT_CONFIG(icu)
+ return QString::fromLatin1(encodingInterfaces[index].name);
+ #else
+ if (index == 0) // "Locale", not provided by icu
+ return QString::fromLatin1(
+ encodingInterfaces[QStringConverter::Encoding::System].name);
+ // this mirrors the setup we do to set a converters name
+ UErrorCode status = U_ZERO_ERROR;
+ auto icuName = ucnv_getAvailableName(int32_t(index - 1));
+ const char *standardName = ucnv_getStandardName(icuName, "MIME", &status);
+ if (U_FAILURE(status) || !standardName) {
+ status = U_ZERO_ERROR;
+ standardName = ucnv_getStandardName(icuName, "IANA", &status);
+ }
+ if (!standardName)
+ standardName = icuName;
+ return QString::fromLatin1(standardName);
+ #endif
+ };
+
+ qsizetype codecCount = availableCodecCount();
+ QStringList result;
+ result.reserve(codecCount);
+ for (qsizetype i = 0; i < codecCount; ++i)
+ result.push_back(availableCodec(i));
+ return result;
+}
+
/*!
Tries to determine the encoding of the HTML in \a data by looking at leading byte
order marks or a charset specifier in the HTML meta tag and returns a QStringDecoder
@@ -2186,7 +2441,7 @@ QStringDecoder QStringDecoder::decoderForHtml(QByteArrayView data)
return QStringDecoder(Utf8);
}
-
+#endif // !QT_BOOTSTRAPPED
/*!
Returns the canonical name for encoding \a e.
@@ -2255,12 +2510,24 @@ const char *QStringConverter::nameForEncoding(QStringConverter::Encoding e)
*/
/*!
- \fn QByteArray QStringEncoder::encode(const QString &in)
- \fn QByteArray QStringEncoder::encode(QStringView in)
- \fn QByteArray QStringEncoder::operator()(const QString &in)
- \fn QByteArray QStringEncoder::operator()(QStringView in)
+ \fn constexpr QStringEncoder::QStringEncoder(const QString &name, Flags flags = Flag::Default)
+ \since 6.8
+
+ Creates an encoder object using \a name and \a flags.
+ If \a name is not the name of a known encoding an invalid converter will get created.
- Converts \a in and returns the data as a byte array.
+ \sa isValid()
+*/
+
+/*!
+ \fn QStringEncoder::DecodedData<const QString &> QStringEncoder::encode(const QString &in)
+ \fn QStringEncoder::DecodedData<QStringView> QStringEncoder::encode(QStringView in)
+ \fn QStringEncoder::DecodedData<const QString &> QStringEncoder::operator()(const QString &in)
+ \fn QStringEncoder::DecodedData<QStringView> QStringEncoder::operator()(QStringView in)
+
+ Converts \a in and returns a struct that is implicitly convertible to QByteArray.
+
+ \snippet code/src_corelib_text_qstringconverter.cpp 5
*/
/*!
@@ -2344,12 +2611,25 @@ const char *QStringConverter::nameForEncoding(QStringConverter::Encoding e)
*/
/*!
- \fn QString QStringDecoder::operator()(const QByteArray &ba)
- \fn QString QStringDecoder::decode(const QByteArray &ba)
- \fn QString QStringDecoder::operator()(QByteArrayView ba)
- \fn QString QStringDecoder::decode(QByteArrayView ba)
+ \fn constexpr QStringDecoder::QStringDecoder(const QString &name, Flags flags = Flag::Default)
+ \since 6.8
+
+ Creates an decoder object using \a name and \a flags.
+ If \a name is not the name of a known encoding an invalid converter will get created.
- Converts \a ba and returns the data as a QString.
+ \sa isValid()
+*/
+
+/*!
+ \fn QStringDecoder::EncodedData<const QByteArray &> QStringDecoder::operator()(const QByteArray &ba)
+ \fn QStringDecoder::EncodedData<const QByteArray &> QStringDecoder::decode(const QByteArray &ba)
+ \fn QStringDecoder::EncodedData<QByteArrayView> QStringDecoder::operator()(QByteArrayView ba)
+ \fn QStringDecoder::EncodedData<QByteArrayView> QStringDecoder::decode(QByteArrayView ba)
+
+ Converts \a ba and returns a struct that is implicitly convertible to QString.
+
+
+ \snippet code/src_corelib_text_qstringconverter.cpp 4
*/
/*!
@@ -2374,4 +2654,10 @@ const char *QStringConverter::nameForEncoding(QStringConverter::Encoding e)
\sa requiredSpace
*/
+/*!
+ \fn char16_t *QStringDecoder::appendToBuffer(char16_t *out, QByteArrayView in)
+ \since 6.6
+ \overload
+*/
+
QT_END_NAMESPACE
diff --git a/src/corelib/text/qstringconverter.h b/src/corelib/text/qstringconverter.h
index f10aa3b6d3..40791f8e26 100644
--- a/src/corelib/text/qstringconverter.h
+++ b/src/corelib/text/qstringconverter.h
@@ -13,9 +13,7 @@
#include <QtCore/qstringconverter_base.h>
#include <QtCore/qstring.h>
-#if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER)
#include <QtCore/qstringbuilder.h>
-#endif
QT_BEGIN_NAMESPACE
@@ -35,13 +33,10 @@ public:
explicit QStringEncoder(const char *name, Flags flags = Flag::Default)
: QStringConverter(name, flags)
{}
+ Q_WEAK_OVERLOAD explicit QStringEncoder(const QString &name, Flags flags = Flag::Default)
+ : QStringEncoder(name.toLatin1().constData(), flags)
+ {}
-#if defined(Q_QDOC)
- QByteArray operator()(const QString &in);
- QByteArray operator()(QStringView in);
- QByteArray encode(const QString &in);
- QByteArray encode(QStringView in);
-#else
template<typename T>
struct DecodedData
{
@@ -59,7 +54,6 @@ public:
{ return DecodedData<const QString &>{this, str}; }
DecodedData<QStringView> encode(QStringView in)
{ return DecodedData<QStringView>{this, in}; }
-#endif
qsizetype requiredSpace(qsizetype inputLength) const
{ return iface ? iface->fromUtf16Len(inputLength) : 0; }
@@ -104,13 +98,10 @@ public:
explicit QStringDecoder(const char *name, Flags f = Flag::Default)
: QStringConverter(name, f)
{}
+ Q_WEAK_OVERLOAD explicit QStringDecoder(const QString &name, Flags f = Flag::Default)
+ : QStringDecoder(name.toLatin1().constData(), f)
+ {}
-#if defined(Q_QDOC)
- QString operator()(const QByteArray &ba);
- QString operator()(QByteArrayView ba);
- QString decode(const QByteArray &ba);
- QString decode(QByteArrayView ba);
-#else
template<typename T>
struct EncodedData
{
@@ -128,7 +119,6 @@ public:
{ return EncodedData<const QByteArray &>{this, ba}; }
EncodedData<QByteArrayView> decode(QByteArrayView ba)
{ return EncodedData<QByteArrayView>{this, ba}; }
-#endif
qsizetype requiredSpace(qsizetype inputLength) const
{ return iface ? iface->toUtf16Len(inputLength) : 0; }
@@ -140,6 +130,8 @@ public:
}
return iface->toUtf16(out, ba, &state);
}
+ char16_t *appendToBuffer(char16_t *out, QByteArrayView ba)
+ { return reinterpret_cast<char16_t *>(appendToBuffer(reinterpret_cast<QChar *>(out), ba)); }
Q_CORE_EXPORT static QStringDecoder decoderForHtml(QByteArrayView data);
@@ -211,6 +203,66 @@ QByteArray &operator+=(QByteArray &a, const QStringEncoder::DecodedData<T> &b)
}
#endif
+template <typename InputIterator>
+void QString::assign_helper_char8(InputIterator first, InputIterator last)
+{
+ static_assert(!QString::is_contiguous_iterator_v<InputIterator>,
+ "Internal error: Should have been handed over to the QAnyStringView overload."
+ );
+
+ using ValueType = typename std::iterator_traits<InputIterator>::value_type;
+ constexpr bool IsFwdIt = std::is_convertible_v<
+ typename std::iterator_traits<InputIterator>::iterator_category,
+ std::forward_iterator_tag
+ >;
+
+ resize(0);
+ // In case of not being shared, there is the possibility of having free space at begin
+ // even after the resize to zero.
+ if (const auto offset = d.freeSpaceAtBegin())
+ d.setBegin(d.begin() - offset);
+
+ if constexpr (IsFwdIt)
+ reserve(static_cast<qsizetype>(std::distance(first, last)));
+
+ auto toUtf16 = QStringDecoder(QStringDecoder::Utf8);
+ auto availableCapacity = d.constAllocatedCapacity();
+ auto *dst = d.data();
+ auto *dend = d.data() + availableCapacity;
+
+ while (true) {
+ if (first == last) { // ran out of input elements
+ Q_ASSERT(!std::less<>{}(dend, dst));
+ d.size = dst - d.begin();
+ return;
+ }
+ const ValueType next = *first; // decays proxies, if any
+ const auto chunk = QUtf8StringView(&next, 1);
+ // UTF-8 characters can have a maximum size of 4 bytes and may result in a surrogate
+ // pair of UTF-16 code units. In the input-iterator case, we don't know the size
+ // and would need to always reserve space for 2 code units. To keep our promise
+ // of 'not allocating if it fits', we have to pre-check this condition.
+ // We know that it fits in the forward-iterator case.
+ if constexpr (!IsFwdIt) {
+ constexpr qsizetype Pair = 2;
+ char16_t buf[Pair];
+ const qptrdiff n = toUtf16.appendToBuffer(buf, chunk) - buf;
+ if (dend - dst < n) { // ran out of allocated memory
+ const auto offset = dst - d.begin();
+ reallocData(d.constAllocatedCapacity() + Pair, QArrayData::Grow);
+ // update the pointers since we've re-allocated
+ availableCapacity = d.constAllocatedCapacity();
+ dst = d.data() + offset;
+ dend = d.data() + availableCapacity;
+ }
+ dst = std::copy_n(buf, n, dst);
+ } else { // take the fast path
+ dst = toUtf16.appendToBuffer(dst, chunk);
+ }
+ ++first;
+ }
+}
+
QT_END_NAMESPACE
#endif
diff --git a/src/corelib/text/qstringconverter_base.h b/src/corelib/text/qstringconverter_base.h
index bf464cbb6f..d6b6fcb484 100644
--- a/src/corelib/text/qstringconverter_base.h
+++ b/src/corelib/text/qstringconverter_base.h
@@ -13,6 +13,7 @@
#include <QtCore/qglobal.h> // QT_{BEGIN,END}_NAMESPACE
#include <QtCore/qflags.h> // Q_DECLARE_FLAGS
+#include <QtCore/qcontainerfwd.h>
#include <cstring>
@@ -88,12 +89,14 @@ public:
enum Encoding {
Utf8,
+#ifndef QT_BOOTSTRAPPED
Utf16,
Utf16LE,
Utf16BE,
Utf32,
Utf32LE,
Utf32BE,
+#endif
Latin1,
System,
LastEncoding = System
@@ -159,6 +162,8 @@ public:
encodingForData(QByteArrayView data, char16_t expectedFirstCharacter = 0) noexcept;
Q_CORE_EXPORT static std::optional<Encoding> encodingForHtml(QByteArrayView data);
+ Q_CORE_EXPORT static QStringList availableCodecs();
+
protected:
const Interface *iface;
State state;
diff --git a/src/corelib/text/qstringconverter_p.h b/src/corelib/text/qstringconverter_p.h
index edbe1b5484..e68ffb2bb0 100644
--- a/src/corelib/text/qstringconverter_p.h
+++ b/src/corelib/text/qstringconverter_p.h
@@ -69,18 +69,27 @@ struct QUtf8BaseTraits
static void appendByte(qchar8_t *&ptr, qchar8_t b)
{ *ptr++ = b; }
+ static uchar peekByte(const char *ptr, qsizetype n = 0)
+ { return ptr[n]; }
+
static uchar peekByte(const uchar *ptr, qsizetype n = 0)
{ return ptr[n]; }
static uchar peekByte(const qchar8_t *ptr, qsizetype n = 0)
{ return ptr[n]; }
+ static qptrdiff availableBytes(const char *ptr, const char *end)
+ { return end - ptr; }
+
static qptrdiff availableBytes(const uchar *ptr, const uchar *end)
{ return end - ptr; }
static qptrdiff availableBytes(const qchar8_t *ptr, const qchar8_t *end)
{ return end - ptr; }
+ static void advanceByte(const char *&ptr, qsizetype n = 1)
+ { ptr += n; }
+
static void advanceByte(const uchar *&ptr, qsizetype n = 1)
{ ptr += n; }
@@ -362,6 +371,7 @@ struct Q_CORE_EXPORT QLocal8Bit
}
return r > 0;
}
+ static QString convertToUnicode_sys(QByteArrayView, quint32, QStringConverter::State *);
static QString convertToUnicode_sys(QByteArrayView, QStringConverter::State *);
static QString convertToUnicode(QByteArrayView in, QStringConverter::State *state)
{
@@ -369,6 +379,7 @@ struct Q_CORE_EXPORT QLocal8Bit
return QUtf8::convertToUnicode(in, state);
return convertToUnicode_sys(in, state);
}
+ static QByteArray convertFromUnicode_sys(QStringView, quint32, QStringConverter::State *);
static QByteArray convertFromUnicode_sys(QStringView, QStringConverter::State *);
static QByteArray convertFromUnicode(QStringView in, QStringConverter::State *state)
{
diff --git a/src/corelib/text/qstringlist.cpp b/src/corelib/text/qstringlist.cpp
index d55f751303..61923e0b3f 100644
--- a/src/corelib/text/qstringlist.cpp
+++ b/src/corelib/text/qstringlist.cpp
@@ -189,8 +189,11 @@ QT_BEGIN_NAMESPACE
\fn void QStringList::sort(Qt::CaseSensitivity cs)
Sorts the list of strings in ascending order.
+
+//! [comparison-case-sensitivity]
If \a cs is \l Qt::CaseSensitive (the default), the string comparison
is case sensitive; otherwise the comparison is case insensitive.
+//! [comparison-case-sensitivity]
Sorting is performed using the STL's std::sort() algorithm,
which averages \l{linear-logarithmic time}, i.e. O(\e{n} log \e{n}).
@@ -203,22 +206,16 @@ QT_BEGIN_NAMESPACE
integer index.
*/
-namespace {
-struct CaseInsensitiveLessThan {
- typedef bool result_type;
- result_type operator()(const QString &s1, const QString &s2) const
- {
- return s1.compare(s2, Qt::CaseInsensitive) < 0;
- }
-};
-}
-
void QtPrivate::QStringList_sort(QStringList *that, Qt::CaseSensitivity cs)
{
- if (cs == Qt::CaseSensitive)
+ if (cs == Qt::CaseSensitive) {
std::sort(that->begin(), that->end());
- else
- std::sort(that->begin(), that->end(), CaseInsensitiveLessThan());
+ } else {
+ auto CISCompare = [](const auto &s1, const auto &s2) {
+ return s1.compare(s2, Qt::CaseInsensitive) < 0;
+ };
+ std::sort(that->begin(), that->end(), CISCompare);
+ }
}
@@ -227,9 +224,7 @@ void QtPrivate::QStringList_sort(QStringList *that, Qt::CaseSensitivity cs)
Returns a list of all the strings containing the substring \a str.
- If \a cs is \l Qt::CaseSensitive (the default), the string
- comparison is case sensitive; otherwise the comparison is case
- insensitive.
+ \include qstringlist.cpp comparison-case-sensitivity
\snippet qstringlist/main.cpp 5
\snippet qstringlist/main.cpp 10
@@ -242,6 +237,17 @@ void QtPrivate::QStringList_sort(QStringList *that, Qt::CaseSensitivity cs)
\sa contains()
*/
+template <typename String>
+static QStringList filter_helper(const QStringList &that, const String &needle, Qt::CaseSensitivity cs)
+{
+ QStringList res;
+ for (const auto &s : that) {
+ if (s.contains(needle, cs))
+ res.append(s);
+ }
+ return res;
+}
+
/*!
\fn QStringList QStringList::filter(QStringView str, Qt::CaseSensitivity cs) const
\overload
@@ -250,14 +256,48 @@ void QtPrivate::QStringList_sort(QStringList *that, Qt::CaseSensitivity cs)
QStringList QtPrivate::QStringList_filter(const QStringList *that, QStringView str,
Qt::CaseSensitivity cs)
{
- QStringMatcher matcher(str, cs);
+ return filter_helper(*that, str, cs);
+}
+
+/*!
+ \fn QStringList QStringList::filter(const QStringMatcher &matcher) const
+ \since 6.7
+ \overload
+
+ Returns a list of all the strings matched by \a matcher (i.e. for which
+ \c matcher.indexIn() returns an index >= 0).
+
+ Using a QStringMatcher may be faster when searching in large lists and/or
+ in lists with long strings (the best way to find out is benchmarking).
+
+ For example:
+ \snippet qstringlist/main.cpp 18
+
+ \sa contains()
+*/
+
+QStringList QtPrivate::QStringList_filter(const QStringList &that, const QStringMatcher &matcher)
+{
QStringList res;
- for (qsizetype i = 0; i < that->size(); ++i)
- if (matcher.indexIn(that->at(i)) != -1)
- res << that->at(i);
+ for (const auto &s : that) {
+ if (matcher.indexIn(s) != -1)
+ res.append(s);
+ }
return res;
}
+/*!
+ \fn QStringList QStringList::filter(QLatin1StringView str, Qt::CaseSensitivity cs) const
+ \since 6.7
+ \overload
+*/
+
+QStringList QtPrivate::QStringList_filter(const QStringList &that, QLatin1StringView needle,
+ Qt::CaseSensitivity cs)
+{
+ return filter_helper(that, needle, cs);
+}
+
template<typename T>
static bool stringList_contains(const QStringList &stringList, const T &str, Qt::CaseSensitivity cs)
{
@@ -273,8 +313,9 @@ static bool stringList_contains(const QStringList &stringList, const T &str, Qt:
\fn bool QStringList::contains(const QString &str, Qt::CaseSensitivity cs) const
Returns \c true if the list contains the string \a str; otherwise
- returns \c false. The search is case insensitive if \a cs is
- Qt::CaseInsensitive; the search is case sensitive by default.
+ returns \c false.
+
+ \include qstringlist.cpp comparison-case-sensitivity
\sa indexOf(), lastIndexOf(), QString::contains()
*/
@@ -285,8 +326,9 @@ static bool stringList_contains(const QStringList &stringList, const T &str, Qt:
\since 5.12
Returns \c true if the list contains the string \a str; otherwise
- returns \c false. The search is case insensitive if \a cs is
- Qt::CaseInsensitive; the search is case sensitive by default.
+ returns \c false.
+
+ \include qstringlist.cpp comparison-case-sensitivity
*/
bool QtPrivate::QStringList_contains(const QStringList *that, QStringView str,
Qt::CaseSensitivity cs)
@@ -300,8 +342,9 @@ bool QtPrivate::QStringList_contains(const QStringList *that, QStringView str,
\since 5.10
Returns \c true if the list contains the Latin-1 string viewed by \a str; otherwise
- returns \c false. The search is case insensitive if \a cs is Qt::CaseInsensitive;
- the search is case sensitive by default.
+ returns \c false.
+
+ \include qstringlist.cpp comparison-case-sensitivity
\sa indexOf(), lastIndexOf(), QString::contains()
*/
@@ -324,9 +367,9 @@ bool QtPrivate::QStringList_contains(const QStringList *that, QLatin1StringView
QStringList QtPrivate::QStringList_filter(const QStringList *that, const QRegularExpression &re)
{
QStringList res;
- for (qsizetype i = 0; i < that->size(); ++i) {
- if (that->at(i).contains(re))
- res << that->at(i);
+ for (const auto &str : *that) {
+ if (str.contains(re))
+ res.append(str);
}
return res;
}
@@ -337,8 +380,9 @@ QStringList QtPrivate::QStringList_filter(const QStringList *that, const QRegula
Returns a string list where every string has had the \a before
text replaced with the \a after text wherever the \a before text
- is found. The \a before text is matched case-sensitively or not
- depending on the \a cs flag.
+ is found.
+
+ \include qstringlist.cpp comparison-case-sensitivity
For example:
@@ -368,7 +412,18 @@ QStringList QtPrivate::QStringList_filter(const QStringList *that, const QRegula
void QtPrivate::QStringList_replaceInStrings(QStringList *that, QStringView before,
QStringView after, Qt::CaseSensitivity cs)
{
- for (qsizetype i = 0; i < that->size(); ++i)
+ // Before potentially detaching "that" list, check if any string contains "before"
+ qsizetype i = -1;
+ for (qsizetype j = 0; j < that->size(); ++j) {
+ if (that->at(j).contains(before, cs)) {
+ i = j;
+ break;
+ }
+ }
+ if (i == -1)
+ return;
+
+ for (; i < that->size(); ++i)
(*that)[i].replace(before.data(), before.size(), after.data(), after.size(), cs);
}
@@ -396,9 +451,21 @@ void QtPrivate::QStringList_replaceInStrings(QStringList *that, QStringView befo
\snippet qstringlist/main.cpp 5
\snippet qstringlist/main.cpp 17
*/
-void QtPrivate::QStringList_replaceInStrings(QStringList *that, const QRegularExpression &re, const QString &after)
+void QtPrivate::QStringList_replaceInStrings(QStringList *that, const QRegularExpression &re,
+ const QString &after)
{
- for (qsizetype i = 0; i < that->size(); ++i)
+ // Before potentially detaching "that" list, check if any string contains "before"
+ qsizetype i = -1;
+ for (qsizetype j = 0; j < that->size(); ++j) {
+ if (that->at(j).contains(re)) {
+ i = j;
+ break;
+ }
+ }
+ if (i == -1)
+ return;
+
+ for (; i < that->size(); ++i)
(*that)[i].replace(re, after);
}
#endif // QT_CONFIG(regularexpression)
@@ -514,6 +581,102 @@ QString QtPrivate::QStringList_join(const QStringList *that, QStringView sep)
the latter string list.
*/
+/*!
+ \fn qsizetype QStringList::indexOf(const QString &str, qsizetype from, Qt::CaseSensitivity cs) const
+ \fn qsizetype QStringList::indexOf(QStringView str, qsizetype from, Qt::CaseSensitivity cs) const
+ \fn qsizetype QStringList::indexOf(QLatin1StringView str, qsizetype from, Qt::CaseSensitivity cs) const
+
+ Returns the index position of the first match of \a str in the list,
+ searching forward from index position \a from. Returns -1 if no item
+ matched.
+
+ \include qstringlist.cpp comparison-case-sensitivity
+
+//! [overloading-base-class-methods]
+ \note The \a cs parameter was added in Qt 6.7, i.e. these methods now overload
+ the methods inherited from the base class. Prior to that these methods only
+ had two parameters. This change is source compatible and existing code should
+ continue to work.
+//! [overloading-base-class-methods]
+
+ \sa lastIndexOf()
+*/
+
+template <typename String>
+qsizetype indexOf_helper(const QStringList &that, String needle, qsizetype from,
+ Qt::CaseSensitivity cs)
+{
+ if (from < 0) // Historical behavior
+ from = qMax(from + that.size(), 0);
+
+ if (from >= that.size())
+ return -1;
+
+ for (qsizetype i = from; i < that.size(); ++i) {
+ if (needle.compare(that.at(i), cs) == 0)
+ return i;
+ }
+ return -1;
+}
+
+qsizetype QtPrivate::QStringList_indexOf(const QStringList &that, QStringView needle,
+ qsizetype from, Qt::CaseSensitivity cs)
+{
+ return indexOf_helper(that, needle, from, cs);
+}
+
+qsizetype QtPrivate::QStringList_indexOf(const QStringList &that, QLatin1StringView needle,
+ qsizetype from, Qt::CaseSensitivity cs)
+{
+ return indexOf_helper(that, needle, from, cs);
+}
+
+/*!
+ \fn qsizetype QStringList::lastIndexOf(const QString &str, qsizetype from, Qt::CaseSensitivity cs) const
+ \fn qsizetype QStringList::lastIndexOf(QStringView str, qsizetype from, Qt::CaseSensitivity cs) const
+ \fn qsizetype QStringList::lastIndexOf(QLatin1StringView str, qsizetype from, Qt::CaseSensitivity cs) const
+
+ Returns the index position of the last match of \a str in the list,
+ searching backward from index position \a from. If \a from is -1 (the
+ default), the search starts at the last item. Returns -1 if no item
+ matched.
+
+ \include qstringlist.cpp comparison-case-sensitivity
+
+ \include qstringlist.cpp overloading-base-class-methods
+
+ \sa indexOf()
+*/
+
+template <typename String>
+qsizetype lastIndexof_helper(const QStringList &that, String needle, qsizetype from,
+ Qt::CaseSensitivity cs)
+{
+ if (from < 0)
+ from += that.size();
+ else if (from >= that.size())
+ from = that.size() - 1;
+
+ for (qsizetype i = from; i >= 0; --i) {
+ if (needle.compare(that.at(i), cs) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+qsizetype QtPrivate::QStringList_lastIndexOf(const QStringList &that, QLatin1StringView needle,
+ qsizetype from, Qt::CaseSensitivity cs)
+{
+ return lastIndexof_helper(that, needle, from, cs);
+}
+
+qsizetype QtPrivate::QStringList_lastIndexOf(const QStringList &that, QStringView needle,
+ qsizetype from, Qt::CaseSensitivity cs)
+{
+ return lastIndexof_helper(that, needle, from, cs);
+}
+
#if QT_CONFIG(regularexpression)
/*!
\fn qsizetype QStringList::indexOf(const QRegularExpression &re, qsizetype from) const
diff --git a/src/corelib/text/qstringlist.h b/src/corelib/text/qstringlist.h
index 31e4cf6dc9..fc5c49bfe1 100644
--- a/src/corelib/text/qstringlist.h
+++ b/src/corelib/text/qstringlist.h
@@ -30,11 +30,26 @@ namespace QtPrivate {
Q_CORE_EXPORT QString QStringList_join(const QStringList &list, QLatin1StringView sep);
QStringList Q_CORE_EXPORT QStringList_filter(const QStringList *that, QStringView str,
Qt::CaseSensitivity cs);
+ Q_CORE_EXPORT QStringList QStringList_filter(const QStringList &that, QLatin1StringView needle,
+ Qt::CaseSensitivity cs);
+ Q_CORE_EXPORT QStringList QStringList_filter(const QStringList &that,
+ const QStringMatcher &matcher);
+
bool Q_CORE_EXPORT QStringList_contains(const QStringList *that, QStringView str, Qt::CaseSensitivity cs);
bool Q_CORE_EXPORT QStringList_contains(const QStringList *that, QLatin1StringView str, Qt::CaseSensitivity cs);
void Q_CORE_EXPORT QStringList_replaceInStrings(QStringList *that, QStringView before, QStringView after,
Qt::CaseSensitivity cs);
+ qsizetype Q_CORE_EXPORT QStringList_indexOf(const QStringList &that, QStringView str,
+ qsizetype from, Qt::CaseSensitivity cs);
+ qsizetype Q_CORE_EXPORT QStringList_indexOf(const QStringList &that, QLatin1StringView str,
+ qsizetype from, Qt::CaseSensitivity cs);
+
+ Q_CORE_EXPORT qsizetype QStringList_lastIndexOf(const QStringList &that, QStringView str,
+ qsizetype from, Qt::CaseSensitivity cs);
+ Q_CORE_EXPORT qsizetype QStringList_lastIndexOf(const QStringList &that, QLatin1StringView str,
+ qsizetype from, Qt::CaseSensitivity cs);
+
#if QT_CONFIG(regularexpression)
void Q_CORE_EXPORT QStringList_replaceInStrings(QStringList *that, const QRegularExpression &rx, const QString &after);
QStringList Q_CORE_EXPORT QStringList_filter(const QStringList *that, const QRegularExpression &re);
@@ -78,6 +93,10 @@ public:
inline QString join(QChar sep) const
{ return QtPrivate::QStringList_join(self(), &sep, 1); }
+ QStringList filter(const QStringMatcher &matcher) const
+ { return QtPrivate::QStringList_filter(*self(), matcher); }
+ QStringList filter(QLatin1StringView needle, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
+ { return QtPrivate::QStringList_filter(*self(), needle, cs); }
inline QStringList filter(QStringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
{ return QtPrivate::QStringList_filter(self(), str, cs); }
inline QStringList &replaceInStrings(QStringView before, QStringView after, Qt::CaseSensitivity cs = Qt::CaseSensitive)
@@ -116,10 +135,26 @@ public:
inline bool contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return QtPrivate::QStringList_contains(self(), str, cs); }
- qsizetype indexOf(const QString &str, qsizetype from = 0) const noexcept
- { return indexOf(QStringView(str), from); }
- qsizetype lastIndexOf(const QString &str, qsizetype from = -1) const noexcept
- { return lastIndexOf(QStringView(str), from); }
+
+ qsizetype indexOf(const QString &str, qsizetype from = 0,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
+ { return indexOf(QStringView(str), from, cs); }
+ qsizetype indexOf(QStringView needle, qsizetype from = 0,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
+ { return QtPrivate::QStringList_indexOf(*self(), needle, from, cs); }
+ qsizetype indexOf(QLatin1StringView needle, qsizetype from = 0,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
+ { return QtPrivate::QStringList_indexOf(*self(), needle, from, cs); }
+
+ qsizetype lastIndexOf(const QString &str, qsizetype from = -1,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
+ { return lastIndexOf(QStringView(str), from, cs); }
+ qsizetype lastIndexOf(QStringView str, qsizetype from = -1,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
+ { return QtPrivate::QStringList_lastIndexOf(*self(), str, from, cs); }
+ qsizetype lastIndexOf(QLatin1StringView needle, qsizetype from = -1,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
+ { return QtPrivate::QStringList_lastIndexOf(*self(), needle, from, cs); }
#if QT_CONFIG(regularexpression)
inline QStringList filter(const QRegularExpression &re) const
diff --git a/src/corelib/text/qstringmatcher.cpp b/src/corelib/text/qstringmatcher.cpp
index 39fd45cfff..379d555e54 100644
--- a/src/corelib/text/qstringmatcher.cpp
+++ b/src/corelib/text/qstringmatcher.cpp
@@ -13,7 +13,7 @@ static void bm_init_skiptable(QStringView needle, uchar *skiptable, Qt::CaseSens
const char16_t *uc = needle.utf16();
const qsizetype len =
cs == Qt::CaseSensitive ? needle.size() : qMin(needle.size(), FoldBufferCapacity);
- qsizetype l = qMin(len, qsizetype(255));
+ int l = qMin(int(len), 255);
memset(skiptable, l, 256 * sizeof(uchar));
uc += len - l;
if (cs == Qt::CaseSensitive) {
@@ -243,6 +243,15 @@ QString QStringMatcher::pattern() const
}
/*!
+ \fn QStringView QStringMatcher::patternView() const noexcept
+ \since 6.7
+
+ Returns a string view of the pattern that this string matcher will search for.
+
+ \sa setPattern()
+*/
+
+/*!
Sets the case sensitivity setting of this string matcher to \a
cs.
diff --git a/src/corelib/text/qstringmatcher.h b/src/corelib/text/qstringmatcher.h
index 581d8931e4..937f17df0a 100644
--- a/src/corelib/text/qstringmatcher.h
+++ b/src/corelib/text/qstringmatcher.h
@@ -40,6 +40,9 @@ public:
{ return indexIn(QStringView(str, length), from); }
qsizetype indexIn(QStringView str, qsizetype from = 0) const;
QString pattern() const;
+ QStringView patternView() const noexcept
+ { return q_sv; }
+
inline Qt::CaseSensitivity caseSensitivity() const { return q_cs; }
private:
diff --git a/src/corelib/text/qstringtokenizer.h b/src/corelib/text/qstringtokenizer.h
index 2b679608f9..7a627b4508 100644
--- a/src/corelib/text/qstringtokenizer.h
+++ b/src/corelib/text/qstringtokenizer.h
@@ -5,6 +5,7 @@
#include <QtCore/qnamespace.h>
#include <QtCore/qcontainerfwd.h>
+#include <iterator>
QT_BEGIN_NAMESPACE
diff --git a/src/corelib/text/qstringview.cpp b/src/corelib/text/qstringview.cpp
index e72980ef89..29b83ffe8f 100644
--- a/src/corelib/text/qstringview.cpp
+++ b/src/corelib/text/qstringview.cpp
@@ -179,7 +179,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn template <typename Char> QStringView::QStringView(const Char *str, qsizetype len)
+ \fn template <typename Char, QStringView::if_compatible_char<Char> = true> QStringView::QStringView(const Char *str, qsizetype len)
Constructs a string view on \a str with length \a len.
@@ -195,7 +195,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn template <typename Char> QStringView::QStringView(const Char *first, const Char *last)
+ \fn template <typename Char, QStringView::if_compatible_char<Char> = true> QStringView::QStringView(const Char *first, const Char *last)
Constructs a string view on \a first with length (\a last - \a first).
@@ -262,26 +262,26 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn template <typename Container, if_compatible_container<Container>> QStringView::QStringView(const Container &str)
+ \fn template <typename Container, QStringView::if_compatible_container<Container>> QStringView::QStringView(const Container &str)
- Constructs a string view on \a str. The length is taken from \c{str.size()}.
+ Constructs a string view on \a str. The length is taken from \c{std::size(str)}.
- \c{str.data()} must remain valid for the lifetime of this string view object.
+ \c{std::data(str)} must remain valid for the lifetime of this string view object.
- This constructor only participates in overload resolution if \c StdBasicString is an
- instantiation of \c std::basic_string with a compatible character type. The
+ This constructor only participates in overload resolution if \c Container is a
+ container with a compatible character type as \c{value_type}. The
compatible character types are: \c QChar, \c ushort, \c char16_t and
(on platforms, such as Windows, where it is a 16-bit type) \c wchar_t.
- The string view will be empty if and only if \c{str.empty()}. It is unspecified
- whether this constructor can result in a null string view (\c{str.data()} would
+ The string view will be empty if and only if \c{std::size(str) == 0}. It is unspecified
+ whether this constructor can result in a null string view (\c{std::data(str)} would
have to return \nullptr for this).
\sa isNull(), isEmpty()
*/
/*!
- \fn template <typename Char, size_t Size> static QStringView QStringView::fromArray(const Char (&string)[Size]) noexcept
+ \fn template <typename Char, size_t Size, QStringView::if_compatible_char<Char> = true> static QStringView QStringView::fromArray(const Char (&string)[Size]) noexcept
Constructs a string view on the full character string literal \a string,
including any trailing \c{Char(0)}. If you don't want the
@@ -471,7 +471,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn qsizetype QStringView::size() const
- Returns the size of this string view, in UTF-16 code points (that is,
+ Returns the size of this string view, in UTF-16 code units (that is,
surrogate pairs count as two for the purposes of this function, the same
as in QString).
@@ -654,8 +654,10 @@ QT_BEGIN_NAMESPACE
Returns a string view that points to \a n characters of this string view,
starting at position \a pos.
+//! [UB-sliced-index-length]
\note The behavior is undefined when \a pos < 0, \a n < 0,
or \a pos + \a n > size().
+//! [UB-sliced-index-length]
\sa first(), last(), chopped(), chop(), truncate()
*/
@@ -668,7 +670,9 @@ QT_BEGIN_NAMESPACE
Returns a string view starting at position \a pos in this object,
and extending to its end.
+//! [UB-sliced-index-only]
\note The behavior is undefined when \a pos < 0 or \a pos > size().
+//! [UB-sliced-index-only]
\sa first(), last(), chopped(), chop(), truncate()
*/
@@ -724,8 +728,9 @@ QT_BEGIN_NAMESPACE
\fn int QStringView::compare(QStringView str, Qt::CaseSensitivity cs) const
\since 5.12
- Returns an integer that compares to zero as this string view compares to the
- string view \a str.
+ Compares this string view with string view \a str and returns a negative integer if
+ this string view is less than \a str, a positive integer if it is greater than
+ \a str, and zero if they are equal.
\include qstring.qdocinc {search-comparison-case-sensitivity} {comparison}
@@ -736,8 +741,9 @@ QT_BEGIN_NAMESPACE
\fn int QStringView::compare(QUtf8StringView str, Qt::CaseSensitivity cs) const
\since 6.5
- Returns an integer that compares to zero as this string view compares to the
- string view \a str.
+ Compares this string view with QUtf8StringView \a str and returns a negative integer if
+ this string view is less than \a str, a positive integer if it is greater than
+ \a str, and zero if they are equal.
\include qstring.qdocinc {search-comparison-case-sensitivity} {comparison}
@@ -750,8 +756,9 @@ QT_BEGIN_NAMESPACE
\fn int QStringView::compare(QChar ch, Qt::CaseSensitivity cs) const
\since 5.15
- Returns an integer that compares to zero as this string view compares to the
- Latin-1 string viewed by \a l1, or the character \a ch, respectively.
+ Compares this string view to the Latin-1 string view \a l1, or the character \a ch.
+ Returns a negative integer if this string view is less than \a l1 or \a ch,
+ a positive integer if it is greater than \a l1 or \a ch, and zero if they are equal.
\include qstring.qdocinc {search-comparison-case-sensitivity} {comparison}
@@ -759,12 +766,12 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn QStringView::operator==(QStringView lhs, QStringView rhs)
- \fn QStringView::operator!=(QStringView lhs, QStringView rhs)
- \fn QStringView::operator< (QStringView lhs, QStringView rhs)
- \fn QStringView::operator<=(QStringView lhs, QStringView rhs)
- \fn QStringView::operator> (QStringView lhs, QStringView rhs)
- \fn QStringView::operator>=(QStringView lhs, QStringView rhs)
+ \fn QStringView::operator==(const QStringView &lhs, const QStringView &rhs)
+ \fn QStringView::operator!=(const QStringView &lhs, const QStringView &rhs)
+ \fn QStringView::operator< (const QStringView &lhs, const QStringView &rhs)
+ \fn QStringView::operator<=(const QStringView &lhs, const QStringView &rhs)
+ \fn QStringView::operator> (const QStringView &lhs, const QStringView &rhs)
+ \fn QStringView::operator>=(const QStringView &lhs, const QStringView &rhs)
Operators for comparing \a lhs to \a rhs.
@@ -1090,6 +1097,32 @@ or the character \a ch
*/
/*!
+ \fn bool QStringView::isLower() const
+ \since 6.7
+ Returns \c true if this view is identical to its lowercase folding.
+
+ Note that this does \e not mean that the string view does not contain
+ uppercase letters (some uppercase letters do not have a lowercase
+ folding; they are left unchanged by toString().toLower()).
+ For more information, refer to the Unicode standard, section 3.13.
+
+ \sa QChar::toLower(), isUpper()
+*/
+
+/*!
+ \fn bool QStringView::isUpper() const
+ \since 6.7
+ Returns \c true if this view is identical to its uppercase folding.
+
+ Note that this does \e not mean that the the string view does not contain
+ lowercase letters (some lowercase letters do not have a uppercase
+ folding; they are left unchanged by toString().toUpper()).
+ For more information, refer to the Unicode standard, section 3.13.
+
+ \sa QChar::toUpper(), isLower()
+*/
+
+/*!
\fn QStringView::toWCharArray(wchar_t *array) const
\since 5.14
@@ -1411,4 +1444,13 @@ or the character \a ch
\sa QStringTokenizer, qTokenize()
*/
+/*!
+ \fn QStringView::operator std::u16string_view() const
+ \since 6.7
+
+ Converts this QStringView object to a \c{std::u16string_view} object.
+ The returned view will have the same data pointer and length of
+ this view.
+*/
+
QT_END_NAMESPACE
diff --git a/src/corelib/text/qstringview.h b/src/corelib/text/qstringview.h
index 3dc8b5ce0b..ab97d834d3 100644
--- a/src/corelib/text/qstringview.h
+++ b/src/corelib/text/qstringview.h
@@ -5,11 +5,13 @@
#define QSTRINGVIEW_H
#include <QtCore/qchar.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qstringliteral.h>
#include <QtCore/qstringalgorithms.h>
#include <string>
+#include <string_view>
#include <QtCore/q20type_traits.h>
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
@@ -105,13 +107,8 @@ private:
template <typename Char>
static constexpr qsizetype lengthHelperPointer(const Char *str) noexcept
{
-#if defined(__cpp_lib_is_constant_evaluated)
- if (std::is_constant_evaluated())
+ if (q20::is_constant_evaluated())
return std::char_traits<Char>::length(str);
-#elif defined(Q_CC_GNU) && !defined(Q_CC_CLANG)
- if (__builtin_constant_p(*str))
- return std::char_traits<Char>::length(str);
-#endif
return QtPrivate::qustrlen(reinterpret_cast<const char16_t *>(str));
}
static qsizetype lengthHelperPointer(const QChar *str) noexcept
@@ -119,20 +116,6 @@ private:
return QtPrivate::qustrlen(reinterpret_cast<const char16_t *>(str));
}
- template <typename Container>
- static constexpr qsizetype lengthHelperContainer(const Container &c) noexcept
- {
- return qsizetype(std::size(c));
- }
-
- template <typename Char, size_t N>
- static constexpr qsizetype lengthHelperContainer(const Char (&str)[N]) noexcept
- {
- const auto it = std::char_traits<Char>::find(str, N, Char(0));
- const auto end = it ? it : std::end(str);
- return qsizetype(std::distance(str, end));
- }
-
template <typename Char>
static const storage_type *castHelper(const Char *str) noexcept
{ return reinterpret_cast<const storage_type*>(str); }
@@ -181,8 +164,8 @@ public:
#endif
template <typename Container, if_compatible_container<Container> = true>
- constexpr QStringView(const Container &c) noexcept
- : QStringView(std::data(c), lengthHelperContainer(c)) {}
+ constexpr Q_ALWAYS_INLINE QStringView(const Container &c) noexcept
+ : QStringView(std::data(c), QtPrivate::lengthHelperContainer(c)) {}
template <typename Char, size_t Size, if_compatible_char<Char> = true>
[[nodiscard]] constexpr static QStringView fromArray(const Char (&string)[Size]) noexcept
@@ -201,7 +184,7 @@ public:
[[nodiscard]] constexpr const storage_type *utf16() const noexcept { return m_data; }
[[nodiscard]] constexpr QChar operator[](qsizetype n) const
- { return Q_ASSERT(n >= 0), Q_ASSERT(n < size()), QChar(m_data[n]); }
+ { verify(n, 1); return QChar(m_data[n]); }
//
// QString API
@@ -237,20 +220,20 @@ public:
}
[[nodiscard]] constexpr QStringView first(qsizetype n) const noexcept
- { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); return QStringView(m_data, n); }
+ { verify(0, n); return sliced(0, n); }
[[nodiscard]] constexpr QStringView last(qsizetype n) const noexcept
- { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); return QStringView(m_data + size() - n, n); }
+ { verify(0, n); return sliced(size() - n, n); }
[[nodiscard]] constexpr QStringView sliced(qsizetype pos) const noexcept
- { Q_ASSERT(pos >= 0); Q_ASSERT(pos <= size()); return QStringView(m_data + pos, size() - pos); }
+ { verify(pos, 0); return QStringView(m_data + pos, size() - pos); }
[[nodiscard]] constexpr QStringView sliced(qsizetype pos, qsizetype n) const noexcept
- { Q_ASSERT(pos >= 0); Q_ASSERT(n >= 0); Q_ASSERT(size_t(pos) + size_t(n) <= size_t(size())); return QStringView(m_data + pos, n); }
+ { verify(pos, n); return QStringView(m_data + pos, n); }
[[nodiscard]] constexpr QStringView chopped(qsizetype n) const noexcept
- { return Q_ASSERT(n >= 0), Q_ASSERT(n <= size()), QStringView(m_data, m_size - n); }
+ { verify(0, n); return sliced(0, m_size - n); }
constexpr void truncate(qsizetype n) noexcept
- { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); m_size = n; }
+ { verify(0, n); ; m_size = n; }
constexpr void chop(qsizetype n) noexcept
- { Q_ASSERT(n >= 0); Q_ASSERT(n <= size()); m_size -= n; }
+ { verify(0, n); m_size -= n; }
[[nodiscard]] QStringView trimmed() const noexcept { return QtPrivate::trimmed(*this); }
@@ -288,7 +271,7 @@ public:
{ return QtPrivate::endsWith(*this, QStringView(&c, 1), cs); }
[[nodiscard]] qsizetype indexOf(QChar c, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
- { return QtPrivate::findString(*this, from, QStringView(&c, 1), cs); }
+ { return QtPrivate::findString(*this, from, c.unicode(), cs); }
[[nodiscard]] qsizetype indexOf(QStringView s, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return QtPrivate::findString(*this, from, s, cs); }
[[nodiscard]] inline qsizetype indexOf(QLatin1StringView s, qsizetype from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
@@ -308,7 +291,7 @@ public:
[[nodiscard]] qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return lastIndexOf(c, -1, cs); }
[[nodiscard]] qsizetype lastIndexOf(QChar c, qsizetype from, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
- { return QtPrivate::lastIndexOf(*this, from, QStringView(&c, 1), cs); }
+ { return QtPrivate::lastIndexOf(*this, from, c.unicode(), cs); }
[[nodiscard]] qsizetype lastIndexOf(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return lastIndexOf(s, size(), cs); }
[[nodiscard]] qsizetype lastIndexOf(QStringView s, qsizetype from, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
@@ -350,6 +333,11 @@ public:
[[nodiscard]] bool isValidUtf16() const noexcept
{ return QtPrivate::isValidUtf16(*this); }
+ [[nodiscard]] bool isUpper() const noexcept
+ { return QtPrivate::isUpper(*this); }
+ [[nodiscard]] bool isLower() const noexcept
+ { return QtPrivate::isLower(*this); }
+
[[nodiscard]] inline short toShort(bool *ok = nullptr, int base = 10) const;
[[nodiscard]] inline ushort toUShort(bool *ok = nullptr, int base = 10) const;
[[nodiscard]] inline int toInt(bool *ok = nullptr, int base = 10) const;
@@ -379,27 +367,22 @@ public:
#endif
// QStringView <> QStringView
- friend bool operator==(QStringView lhs, QStringView rhs) noexcept { return lhs.size() == rhs.size() && QtPrivate::equalStrings(lhs, rhs); }
- friend bool operator!=(QStringView lhs, QStringView rhs) noexcept { return !(lhs == rhs); }
- friend bool operator< (QStringView lhs, QStringView rhs) noexcept { return QtPrivate::compareStrings(lhs, rhs) < 0; }
- friend bool operator<=(QStringView lhs, QStringView rhs) noexcept { return QtPrivate::compareStrings(lhs, rhs) <= 0; }
- friend bool operator> (QStringView lhs, QStringView rhs) noexcept { return QtPrivate::compareStrings(lhs, rhs) > 0; }
- friend bool operator>=(QStringView lhs, QStringView rhs) noexcept { return QtPrivate::compareStrings(lhs, rhs) >= 0; }
+ friend bool comparesEqual(const QStringView &lhs, const QStringView &rhs) noexcept
+ { return lhs.size() == rhs.size() && QtPrivate::equalStrings(lhs, rhs); }
+ friend Qt::strong_ordering
+ compareThreeWay(const QStringView &lhs, const QStringView &rhs) noexcept
+ {
+ const int res = QtPrivate::compareStrings(lhs, rhs);
+ return Qt::compareThreeWay(res, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QStringView)
// QStringView <> QChar
- friend bool operator==(QStringView lhs, QChar rhs) noexcept { return lhs == QStringView(&rhs, 1); }
- friend bool operator!=(QStringView lhs, QChar rhs) noexcept { return lhs != QStringView(&rhs, 1); }
- friend bool operator< (QStringView lhs, QChar rhs) noexcept { return lhs < QStringView(&rhs, 1); }
- friend bool operator<=(QStringView lhs, QChar rhs) noexcept { return lhs <= QStringView(&rhs, 1); }
- friend bool operator> (QStringView lhs, QChar rhs) noexcept { return lhs > QStringView(&rhs, 1); }
- friend bool operator>=(QStringView lhs, QChar rhs) noexcept { return lhs >= QStringView(&rhs, 1); }
-
- friend bool operator==(QChar lhs, QStringView rhs) noexcept { return QStringView(&lhs, 1) == rhs; }
- friend bool operator!=(QChar lhs, QStringView rhs) noexcept { return QStringView(&lhs, 1) != rhs; }
- friend bool operator< (QChar lhs, QStringView rhs) noexcept { return QStringView(&lhs, 1) < rhs; }
- friend bool operator<=(QChar lhs, QStringView rhs) noexcept { return QStringView(&lhs, 1) <= rhs; }
- friend bool operator> (QChar lhs, QStringView rhs) noexcept { return QStringView(&lhs, 1) > rhs; }
- friend bool operator>=(QChar lhs, QStringView rhs) noexcept { return QStringView(&lhs, 1) >= rhs; }
+ friend bool comparesEqual(const QStringView &lhs, QChar rhs) noexcept
+ { return lhs.size() == 1 && lhs[0] == rhs; }
+ friend Qt::strong_ordering compareThreeWay(const QStringView &lhs, QChar rhs) noexcept
+ { return compareThreeWay(lhs, QStringView(&rhs, 1)); }
+ Q_DECLARE_STRONGLY_ORDERED(QStringView, QChar)
//
// STL compatibility API:
@@ -417,6 +400,9 @@ public:
[[nodiscard]] constexpr QChar front() const { return Q_ASSERT(!empty()), QChar(m_data[0]); }
[[nodiscard]] constexpr QChar back() const { return Q_ASSERT(!empty()), QChar(m_data[m_size - 1]); }
+ [[nodiscard]] Q_IMPLICIT operator std::u16string_view() const noexcept
+ { return std::u16string_view(m_data, size_t(m_size)); }
+
//
// Qt compatibility API:
//
@@ -437,8 +423,34 @@ private:
const storage_type *m_data = nullptr;
#endif
+ Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos = 0,
+ [[maybe_unused]] qsizetype n = 1) const
+ {
+ Q_ASSERT(pos >= 0);
+ Q_ASSERT(pos <= size());
+ Q_ASSERT(n >= 0);
+ Q_ASSERT(n <= size() - pos);
+ }
+
constexpr int compare_single_char_helper(int diff) const noexcept
{ return diff ? diff : size() > 1 ? 1 : 0; }
+
+ Q_CORE_EXPORT static bool equal_helper(QStringView sv, const char *data, qsizetype len);
+ Q_CORE_EXPORT static int compare_helper(QStringView sv, const char *data, qsizetype len);
+
+#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
+ friend bool comparesEqual(const QStringView &lhs, const QByteArrayView &rhs) noexcept
+ { return equal_helper(lhs, rhs.data(), rhs.size()); }
+ friend Qt::strong_ordering
+ compareThreeWay(const QStringView &lhs, const QByteArrayView &rhs) noexcept
+ {
+ const int res = compare_helper(lhs, rhs.data(), rhs.size());
+ return Qt::compareThreeWay(res, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QStringView, QByteArrayView, QT_ASCII_CAST_WARN)
+ Q_DECLARE_STRONGLY_ORDERED(QStringView, QByteArray, QT_ASCII_CAST_WARN)
+ Q_DECLARE_STRONGLY_ORDERED(QStringView, const char *, QT_ASCII_CAST_WARN)
+#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
};
Q_DECLARE_TYPEINFO(QStringView, Q_PRIMITIVE_TYPE);
@@ -446,7 +458,7 @@ template <typename QStringLike, typename std::enable_if<
std::is_same<QStringLike, QString>::value,
bool>::type = true>
inline QStringView qToStringViewIgnoringNull(const QStringLike &s) noexcept
-{ return QStringView(s.data(), s.size()); }
+{ return QStringView(s.begin(), s.size()); }
// QChar inline functions:
@@ -464,6 +476,27 @@ inline QStringView qToStringViewIgnoringNull(const QStringLike &s) noexcept
R{{char16_t(c), u'\0'}} ;
}
+qsizetype QtPrivate::findString(QStringView str, qsizetype from, QChar ch, Qt::CaseSensitivity cs) noexcept
+{
+ if (from < -str.size()) // from < 0 && abs(from) > str.size(), avoiding overflow
+ return -1;
+ if (from < 0)
+ from = qMax(from + str.size(), qsizetype(0));
+ if (from < str.size()) {
+ const char16_t *s = str.utf16();
+ char16_t c = ch.unicode();
+ const char16_t *n = s + from;
+ const char16_t *e = s + str.size();
+ if (cs == Qt::CaseSensitive)
+ n = qustrchr(QStringView(n, e), c);
+ else
+ n = qustrcasechr(QStringView(n, e), c);
+ if (n != e)
+ return n - s;
+ }
+ return -1;
+}
+
QT_END_NAMESPACE
#endif /* QSTRINGVIEW_H */
diff --git a/src/corelib/text/qt_attribution.json b/src/corelib/text/qt_attribution.json
index e051918a53..6235ec5c16 100644
--- a/src/corelib/text/qt_attribution.json
+++ b/src/corelib/text/qt_attribution.json
@@ -4,18 +4,22 @@
"Name": "Unicode Character Database (UCD)",
"QDocModule": "qtcore",
"QtUsage": "Qt Core uses data obtained from UCD files for working with characters and strings.",
- "Files": "For update, see qtbase/util/unicode/README",
- "Files": "qunicodetables_p.h qunicodetables.cpp",
+ "Comment": { "Files": "For update, see qtbase/util/unicode/README" },
+ "Files": [ "qunicodetables_p.h", "qunicodetables.cpp" ],
"Description": "The Unicode Character Database (UCD) is a set of files that
define the Unicode character properties and internal mappings.",
"Homepage": "https://www.unicode.org/ucd/",
- "Version": "Don't use the Unicode standard version;
- UCD has its own 'Revision' numbers, see the 'UAX #44, UCD' page (https://www.unicode.org/reports/tr44/)",
+ "Comment": {
+ "Version": [ "Don't use the Unicode standard version;",
+ "UCD has its own 'Revision' numbers",
+ "see the 'UAX #44, UCD' page (https://www.unicode.org/reports/tr44/)" ],
+ "License": [ "Will change to Unicode-3.0 on next update",
+ "util/unicode/main.cpp is updated to do that already",
+ "Please update the following and delete this note when that happens" ] },
"Version": "30",
"License": "Unicode License Agreement - Data Files and Software (2016)",
"LicenseId": "Unicode-DFS-2016",
- "LicenseFile": "UNICODE_LICENSE.txt",
"Copyright": "Copyright (C) 1991-2022 Unicode, Inc."
},
{
@@ -23,18 +27,18 @@
"Name": "Unicode Common Locale Data Repository (CLDR)",
"QDocModule": "qtcore",
"QtUsage": "Used in Qt Core (QTimeZone, QLocale).",
- "Files": "For update, see qtbase/util/locale_database/cldr2qlocalexml.py",
- "Files": "qlocale_data_p.h ../time/qtimezoneprivate_data_p.h",
+ "Comment": { "Files": "For update, see qtbase/util/locale_database/cldr2qlocalexml.py" },
+ "Files": [ "qlocale_data_p.h",
+ "../time/qtimezoneprivate_data_p.h", "../time/qhijricalendar_data_p.h",
+ "../time/qjalalicalendar_data_p.h", "../time/qromancalendar_data_p.h" ],
"Description": "The Unicode CLDR provides key building blocks for software to support the
world's languages, with the largest and most extensive standard repository of locale data
available.",
"Homepage": "https://cldr.unicode.org/",
- "Version": "v42",
- "License": "// as specified in https://spdx.org/licenses/Unicode-DFS-2016.html",
- "License": "Unicode License Agreement - Data Files and Software (2016)",
- "LicenseId": "Unicode-DFS-2016",
- "LicenseFile": "UNICODE_LICENSE.txt",
- "Copyright": "Copyright (C) 1991-2022 Unicode, Inc."
+ "Version": "v44.1",
+ "License": "Unicode License v3",
+ "LicenseId": "Unicode-3.0",
+ "Copyright": "Copyright (C) 2004-2023 Unicode, Inc."
}
]
diff --git a/src/corelib/text/qtextboundaryfinder.cpp b/src/corelib/text/qtextboundaryfinder.cpp
index 8f20967a1d..21d4c5153e 100644
--- a/src/corelib/text/qtextboundaryfinder.cpp
+++ b/src/corelib/text/qtextboundaryfinder.cpp
@@ -173,9 +173,7 @@ QTextBoundaryFinder::QTextBoundaryFinder(BoundaryType type, const QString &strin
: t(type)
, s(string)
, sv(s)
- , pos(0)
, freeBuffer(true)
- , attributes(nullptr)
{
if (sv.size() > 0) {
attributes = (QCharAttributes *) malloc((sv.size() + 1) * sizeof(QCharAttributes));
@@ -208,9 +206,7 @@ QTextBoundaryFinder::QTextBoundaryFinder(BoundaryType type, const QString &strin
QTextBoundaryFinder::QTextBoundaryFinder(BoundaryType type, QStringView string, unsigned char *buffer, qsizetype bufferSize)
: t(type)
, sv(string)
- , pos(0)
, freeBuffer(true)
- , attributes(nullptr)
{
if (!sv.isEmpty()) {
if (buffer && bufferSize / int(sizeof(QCharAttributes)) >= sv.size() + 1) {
diff --git a/src/corelib/text/qtextboundaryfinder.h b/src/corelib/text/qtextboundaryfinder.h
index 336096d2d0..04e64fd69b 100644
--- a/src/corelib/text/qtextboundaryfinder.h
+++ b/src/corelib/text/qtextboundaryfinder.h
@@ -63,7 +63,7 @@ private:
BoundaryType t = Grapheme;
QString s;
QStringView sv;
- qsizetype pos;
+ qsizetype pos = 0;
uint freeBuffer : 1;
uint unused : 31;
QCharAttributes *attributes = nullptr;
diff --git a/src/corelib/text/qtliterals.qdoc b/src/corelib/text/qtliterals.qdoc
index c42066045d..d108aeb615 100644
--- a/src/corelib/text/qtliterals.qdoc
+++ b/src/corelib/text/qtliterals.qdoc
@@ -11,6 +11,7 @@
/*!
\namespace Qt::Literals
\inmodule QtCore
+ \inheaderfile QString
\brief The Literals inline namespace declares literal operators for Qt types.
*/
@@ -18,6 +19,7 @@
/*!
\namespace Qt::Literals::StringLiterals
\inmodule QtCore
+ \inheaderfile QString
\brief The StringLiterals namespace declares string literal operators
for Qt types.
diff --git a/src/corelib/text/qunicodetables.cpp b/src/corelib/text/qunicodetables.cpp
index e8ca5c1807..dc93b99668 100644
--- a/src/corelib/text/qunicodetables.cpp
+++ b/src/corelib/text/qunicodetables.cpp
@@ -1,7 +1,7 @@
// Copyright (C) 2020 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: Unicode-DFS-2016
-/* This file is autogenerated from the Unicode 14.0 database. Do not edit */
+/* This file is autogenerated from the Unicode 15.1 database. Do not edit */
#include "qunicodetables_p.h"
@@ -364,42 +364,42 @@ static constexpr unsigned short uc_property_trie[] = {
47024, 47024, 47024, 47024, 47024, 47024, 47024, 47024,
47024, 47024, 47024, 47024, 47024, 47024, 47024, 47024,
47024, 47024, 47024, 47024, 47024, 47024, 47024, 47024,
- 47024, 47024, 47024, 47280, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47792, 48048, 48304, 47536, 47536, 47536, 47536, 48560,
- 48816, 48816, 48816, 48816, 48816, 48816, 48816, 48816,
- 48816, 48816, 48816, 48816, 48816, 48816, 48816, 48816,
- 48816, 48816, 48816, 49072, 49328, 49328, 49328, 49328,
+ 47024, 47024, 47024, 47280, 47536, 47536, 47792, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48304, 48560, 48816, 48048, 48048, 48048, 48048, 49072,
49328, 49328, 49328, 49328, 49328, 49328, 49328, 49328,
- 49328, 49328, 49328, 49584, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
+ 49328, 49328, 49328, 49328, 49328, 49328, 49328, 49328,
+ 49328, 49328, 49328, 49584, 49840, 49840, 49840, 49840,
+ 49840, 49840, 49840, 49840, 49840, 49840, 49840, 49840,
+ 49840, 49840, 49840, 50096, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 47536,
- 47536, 47536, 47536, 47536, 47536, 47536, 47536, 48560,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 48048,
+ 48048, 48048, 48048, 48048, 48048, 48048, 48048, 49072,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
@@ -432,7 +432,7 @@ static constexpr unsigned short uc_property_trie[] = {
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
- 29360, 29360, 29360, 29360, 29360, 29360, 29360, 49840,
+ 29360, 29360, 29360, 29360, 29360, 29360, 29360, 50352,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
@@ -465,7 +465,7 @@ static constexpr unsigned short uc_property_trie[] = {
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
- 29360, 29360, 29360, 29360, 29360, 29360, 29360, 49840,
+ 29360, 29360, 29360, 29360, 29360, 29360, 29360, 50352,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
@@ -498,7 +498,7 @@ static constexpr unsigned short uc_property_trie[] = {
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
- 29360, 29360, 29360, 29360, 29360, 29360, 29360, 49840,
+ 29360, 29360, 29360, 29360, 29360, 29360, 29360, 50352,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
@@ -531,7 +531,7 @@ static constexpr unsigned short uc_property_trie[] = {
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
- 29360, 29360, 29360, 29360, 29360, 29360, 29360, 49840,
+ 29360, 29360, 29360, 29360, 29360, 29360, 29360, 50352,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
@@ -564,7 +564,7 @@ static constexpr unsigned short uc_property_trie[] = {
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
- 29360, 29360, 29360, 29360, 29360, 29360, 29360, 49840,
+ 29360, 29360, 29360, 29360, 29360, 29360, 29360, 50352,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
@@ -597,7 +597,7 @@ static constexpr unsigned short uc_property_trie[] = {
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
- 29360, 29360, 29360, 29360, 29360, 29360, 29360, 49840,
+ 29360, 29360, 29360, 29360, 29360, 29360, 29360, 50352,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
@@ -630,7 +630,7 @@ static constexpr unsigned short uc_property_trie[] = {
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
- 29360, 29360, 29360, 29360, 29360, 29360, 29360, 49840,
+ 29360, 29360, 29360, 29360, 29360, 29360, 29360, 50352,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
@@ -663,7 +663,7 @@ static constexpr unsigned short uc_property_trie[] = {
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
- 29360, 29360, 29360, 29360, 29360, 29360, 29360, 49840,
+ 29360, 29360, 29360, 29360, 29360, 29360, 29360, 50352,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
@@ -696,7 +696,7 @@ static constexpr unsigned short uc_property_trie[] = {
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
- 29360, 29360, 29360, 29360, 29360, 29360, 29360, 49840,
+ 29360, 29360, 29360, 29360, 29360, 29360, 29360, 50352,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
@@ -729,9 +729,9 @@ static constexpr unsigned short uc_property_trie[] = {
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
- 29360, 29360, 29360, 29360, 29360, 29360, 29360, 49840,
- 50096, 50352, 50608, 50608, 50608, 50608, 50608, 50608,
- 50608, 50608, 50608, 50608, 50608, 50608, 50608, 50608,
+ 29360, 29360, 29360, 29360, 29360, 29360, 29360, 50352,
+ 50608, 50864, 51120, 51120, 51120, 51120, 51120, 51120,
+ 51120, 51120, 51120, 51120, 51120, 51120, 51120, 51120,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
@@ -762,73 +762,73 @@ static constexpr unsigned short uc_property_trie[] = {
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
29360, 29360, 29360, 29360, 29360, 29360, 29360, 29360,
- 29360, 29360, 29360, 29360, 29360, 29360, 29360, 49840,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
+ 29360, 29360, 29360, 29360, 29360, 29360, 29360, 50352,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 51120,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51632,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 50864,
- 50864, 50864, 50864, 50864, 50864, 50864, 50864, 51120,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51376,
+ 51376, 51376, 51376, 51376, 51376, 51376, 51376, 51632,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -1669,40 +1669,40 @@ static constexpr unsigned short uc_property_trie[] = {
1042, 1042, 1042, 1042, 1042, 1042, 1043, 1042,
1042, 1043, 1043, 1043, 1043, 1043, 1043, 1043,
1043, 1043, 1044, 1043, 1045, 1045, 1046, 1047,
- 1045, 1048, 1045, 1049, 1040, 1050, 221, 221,
-
- 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058,
- 1059, 1060, 221, 221, 221, 221, 221, 221,
- 1061, 1061, 1061, 1061, 1061, 1061, 1061, 1061,
- 1061, 1061, 221, 221, 221, 221, 221, 221,
-
- 1062, 1062, 1063, 1064, 1065, 1066, 1067, 1068,
- 1069, 1070, 1071, 1072, 1072, 1072, 1073, 1074,
- 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082,
- 1083, 1084, 221, 221, 221, 221, 221, 221,
-
- 1085, 1085, 1085, 1085, 1085, 1085, 1085, 1085,
- 1085, 1085, 1085, 1085, 1085, 1085, 1085, 1085,
- 1085, 1085, 1085, 1085, 1085, 1085, 1085, 1085,
- 1085, 1085, 1085, 1085, 1085, 1085, 1085, 1085,
-
- 1085, 1085, 1085, 1086, 1085, 1085, 1085, 1085,
- 1085, 1085, 1085, 1085, 1085, 1085, 1085, 1085,
- 1085, 1085, 1085, 1085, 1085, 1085, 1085, 1085,
- 1085, 1085, 1085, 1085, 1085, 1085, 1085, 1085,
-
- 1085, 1085, 1085, 1085, 1085, 1085, 1085, 1085,
- 1085, 1085, 1085, 1085, 1085, 1085, 1085, 1085,
- 1085, 1085, 1085, 1085, 1085, 1085, 1085, 1085,
- 1087, 221, 221, 221, 221, 221, 221, 221,
-
- 1088, 1088, 1088, 1088, 1088, 1089, 1089, 1085,
- 1085, 1085, 1085, 1085, 1085, 1085, 1085, 1085,
- 1085, 1085, 1085, 1085, 1085, 1085, 1085, 1085,
- 1085, 1085, 1085, 1085, 1085, 1085, 1085, 1085,
-
- 1085, 1085, 1085, 1085, 1085, 1085, 1085, 1085,
- 1085, 1090, 1091, 221, 221, 221, 221, 221,
+ 1048, 1049, 1048, 1050, 1040, 1051, 221, 221,
+
+ 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059,
+ 1060, 1061, 221, 221, 221, 221, 221, 221,
+ 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
+ 1062, 1062, 221, 221, 221, 221, 221, 221,
+
+ 1063, 1063, 1064, 1065, 1066, 1067, 1068, 1069,
+ 1070, 1071, 1072, 1073, 1073, 1073, 1074, 1075,
+ 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083,
+ 1084, 1085, 221, 221, 221, 221, 221, 221,
+
+ 1086, 1086, 1086, 1086, 1086, 1086, 1086, 1086,
+ 1086, 1086, 1086, 1086, 1086, 1086, 1086, 1086,
+ 1086, 1086, 1086, 1086, 1086, 1086, 1086, 1086,
+ 1086, 1086, 1086, 1086, 1086, 1086, 1086, 1086,
+
+ 1086, 1086, 1086, 1087, 1086, 1086, 1086, 1086,
+ 1086, 1086, 1086, 1086, 1086, 1086, 1086, 1086,
+ 1086, 1086, 1086, 1086, 1086, 1086, 1086, 1086,
+ 1086, 1086, 1086, 1086, 1086, 1086, 1086, 1086,
+
+ 1086, 1086, 1086, 1086, 1086, 1086, 1086, 1086,
+ 1086, 1086, 1086, 1086, 1086, 1086, 1086, 1086,
+ 1086, 1086, 1086, 1086, 1086, 1086, 1086, 1086,
+ 1088, 221, 221, 221, 221, 221, 221, 221,
+
+ 1089, 1089, 1089, 1089, 1089, 1090, 1090, 1086,
+ 1086, 1086, 1086, 1086, 1086, 1086, 1086, 1086,
+ 1086, 1086, 1086, 1086, 1086, 1086, 1086, 1086,
+ 1086, 1086, 1086, 1086, 1086, 1086, 1086, 1086,
+
+ 1086, 1086, 1086, 1086, 1086, 1086, 1086, 1086,
+ 1086, 1091, 1092, 221, 221, 221, 221, 221,
1018, 1018, 1018, 1018, 1018, 1018, 1018, 1018,
1018, 1018, 1018, 1018, 1018, 1018, 1018, 1018,
@@ -1716,200 +1716,200 @@ static constexpr unsigned short uc_property_trie[] = {
1018, 1018, 1018, 1018, 1018, 1018, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 1092, 1092, 1092, 1092, 1092, 1092, 1092, 1092,
- 1092, 1092, 1092, 1092, 1092, 1092, 1092, 1092,
- 1092, 1092, 1092, 1092, 1092, 1092, 1092, 1092,
- 1092, 1092, 1092, 1092, 1092, 1093, 1093, 221,
-
- 1094, 1094, 1094, 1095, 1095, 1095, 1095, 1094,
- 1094, 1095, 1095, 1095, 221, 221, 221, 221,
- 1095, 1095, 1094, 1095, 1095, 1095, 1095, 1095,
- 1095, 1096, 1097, 1098, 221, 221, 221, 221,
+ 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093,
+ 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093,
+ 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093,
+ 1093, 1093, 1093, 1093, 1093, 1094, 1094, 221,
- 1099, 221, 221, 221, 1100, 1100, 1101, 1102,
- 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110,
- 1111, 1111, 1111, 1111, 1111, 1111, 1111, 1111,
- 1111, 1111, 1111, 1111, 1111, 1111, 1111, 1111,
+ 1095, 1095, 1095, 1096, 1096, 1096, 1096, 1095,
+ 1095, 1096, 1096, 1096, 221, 221, 221, 221,
+ 1096, 1096, 1095, 1096, 1096, 1096, 1096, 1096,
+ 1096, 1097, 1098, 1099, 221, 221, 221, 221,
- 1111, 1111, 1111, 1111, 1111, 1111, 1111, 1111,
- 1111, 1111, 1111, 1111, 1111, 1111, 221, 221,
- 1111, 1111, 1111, 1111, 1111, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
-
- 1112, 1112, 1112, 1112, 1112, 1112, 1112, 1112,
- 1112, 1112, 1112, 1112, 1112, 1112, 1112, 1112,
+ 1100, 221, 221, 221, 1101, 1101, 1102, 1103,
+ 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111,
1112, 1112, 1112, 1112, 1112, 1112, 1112, 1112,
1112, 1112, 1112, 1112, 1112, 1112, 1112, 1112,
1112, 1112, 1112, 1112, 1112, 1112, 1112, 1112,
- 1112, 1112, 1113, 1113, 221, 221, 221, 221,
- 1112, 1112, 1112, 1112, 1112, 1112, 1112, 1112,
- 1112, 1112, 1112, 1112, 1112, 1112, 1112, 1112,
+ 1112, 1112, 1112, 1112, 1112, 1112, 221, 221,
+ 1112, 1112, 1112, 1112, 1112, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
- 1112, 1112, 1112, 1112, 1112, 1112, 1112, 1112,
- 1112, 1112, 221, 221, 221, 221, 221, 221,
- 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121,
- 1122, 1123, 1124, 221, 221, 221, 1125, 1125,
+ 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113,
+ 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113,
+ 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113,
+ 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113,
- 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
- 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
- 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
- 1126, 1126, 1126, 1126, 1126, 1126, 1126, 1126,
+ 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113,
+ 1113, 1113, 1114, 1114, 221, 221, 221, 221,
+ 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113,
+ 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113,
+
+ 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113,
+ 1113, 1113, 221, 221, 221, 221, 221, 221,
+ 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122,
+ 1123, 1124, 1125, 221, 221, 221, 1126, 1126,
1127, 1127, 1127, 1127, 1127, 1127, 1127, 1127,
1127, 1127, 1127, 1127, 1127, 1127, 1127, 1127,
- 1127, 1127, 1127, 1127, 1127, 1127, 1127, 1128,
- 1129, 1130, 1130, 1131, 221, 221, 1132, 1132,
-
- 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133,
- 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133,
- 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133,
- 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133,
-
- 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133,
- 1133, 1133, 1133, 1133, 1133, 1133, 1133, 1133,
- 1133, 1133, 1133, 1133, 1133, 1134, 1135, 1134,
- 1135, 1135, 1135, 1135, 1135, 1135, 1135, 221,
-
- 1136, 1137, 1135, 1137, 1137, 1135, 1135, 1135,
- 1135, 1135, 1135, 1135, 1135, 1134, 1134, 1134,
- 1134, 1134, 1134, 1135, 1135, 1138, 1138, 1138,
- 1138, 1138, 1138, 1138, 1138, 221, 221, 1139,
-
- 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147,
- 1148, 1149, 221, 221, 221, 221, 221, 221,
- 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147,
- 1148, 1149, 221, 221, 221, 221, 221, 221,
-
- 1150, 1150, 1150, 1150, 1150, 1150, 1150, 1151,
- 1152, 1152, 1152, 1152, 1150, 1150, 221, 221,
- 1153, 1153, 1153, 1153, 1153, 1154, 1154, 1154,
- 1154, 1154, 1154, 1153, 1153, 1154, 1155, 1156,
-
- 1156, 1157, 1157, 1158, 1158, 1157, 1157, 1157,
- 1157, 1157, 1158, 1157, 1157, 1157, 1157, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
-
- 1159, 1159, 1159, 1159, 1160, 1161, 1162, 1161,
- 1162, 1161, 1162, 1161, 1162, 1161, 1162, 1161,
- 1161, 1161, 1162, 1161, 1161, 1161, 1161, 1161,
- 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161,
-
- 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161,
- 1161, 1161, 1161, 1161, 1161, 1161, 1161, 1161,
- 1161, 1161, 1161, 1161, 1163, 1164, 1159, 1159,
- 1159, 1159, 1159, 1165, 1159, 1165, 1160, 1160,
-
- 1165, 1165, 1159, 1165, 1166, 1161, 1161, 1161,
- 1161, 1161, 1161, 1161, 1167, 221, 221, 221,
- 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175,
- 1176, 1177, 1178, 1178, 1179, 1180, 1178, 1178,
-
- 1180, 1181, 1181, 1181, 1181, 1181, 1181, 1181,
- 1181, 1181, 1181, 1182, 1183, 1182, 1182, 1182,
- 1182, 1182, 1182, 1182, 1181, 1181, 1181, 1181,
- 1181, 1181, 1181, 1181, 1181, 1184, 1184, 221,
-
- 1185, 1185, 1186, 1187, 1187, 1187, 1187, 1187,
- 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187,
- 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187,
- 1187, 1187, 1187, 1187, 1187, 1187, 1187, 1187,
-
- 1187, 1186, 1185, 1185, 1185, 1185, 1186, 1186,
- 1185, 1185, 1188, 1189, 1190, 1190, 1187, 1187,
- 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198,
- 1199, 1200, 1201, 1201, 1201, 1201, 1201, 1201,
-
- 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202,
- 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202,
- 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202,
- 1202, 1202, 1202, 1202, 1202, 1202, 1202, 1202,
-
- 1202, 1202, 1202, 1202, 1202, 1202, 1203, 1204,
- 1205, 1205, 1204, 1204, 1204, 1205, 1204, 1205,
- 1205, 1205, 1206, 1206, 221, 221, 221, 221,
- 221, 221, 221, 221, 1207, 1207, 1207, 1207,
-
- 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208,
- 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208,
- 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208,
- 1208, 1208, 1208, 1208, 1208, 1208, 1208, 1208,
-
- 1208, 1208, 1208, 1208, 1209, 1209, 1209, 1209,
- 1209, 1209, 1209, 1209, 1210, 1210, 1210, 1210,
- 1210, 1210, 1210, 1210, 1209, 1209, 1210, 1211,
- 221, 221, 221, 1212, 1212, 1213, 1213, 1213,
-
- 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221,
- 1222, 1223, 221, 221, 221, 1208, 1208, 1208,
- 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231,
- 1232, 1233, 1234, 1234, 1234, 1234, 1234, 1234,
-
- 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234,
- 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234,
- 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234,
- 1235, 1235, 1235, 1235, 1235, 1235, 1236, 1236,
+ 1127, 1127, 1127, 1127, 1127, 1127, 1127, 1127,
+ 1127, 1127, 1127, 1127, 1127, 1127, 1127, 1127,
- 1237, 1238, 1239, 1240, 1240, 1241, 1242, 1243,
- 1244, 221, 221, 221, 221, 221, 221, 221,
- 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245,
- 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245,
+ 1128, 1128, 1128, 1128, 1128, 1128, 1128, 1128,
+ 1128, 1128, 1128, 1128, 1128, 1128, 1128, 1128,
+ 1128, 1128, 1128, 1128, 1128, 1128, 1128, 1129,
+ 1130, 1131, 1131, 1132, 221, 221, 1133, 1133,
+
+ 1134, 1134, 1134, 1134, 1134, 1134, 1134, 1134,
+ 1134, 1134, 1134, 1134, 1134, 1134, 1134, 1134,
+ 1134, 1134, 1134, 1134, 1134, 1134, 1134, 1134,
+ 1134, 1134, 1134, 1134, 1134, 1134, 1134, 1134,
+
+ 1134, 1134, 1134, 1134, 1134, 1134, 1134, 1134,
+ 1134, 1134, 1134, 1134, 1134, 1134, 1134, 1134,
+ 1134, 1134, 1134, 1134, 1134, 1135, 1136, 1135,
+ 1136, 1136, 1136, 1136, 1136, 1136, 1136, 221,
+
+ 1137, 1138, 1136, 1138, 1138, 1136, 1136, 1136,
+ 1136, 1136, 1136, 1136, 1136, 1135, 1135, 1135,
+ 1135, 1135, 1135, 1136, 1136, 1139, 1139, 1139,
+ 1139, 1139, 1139, 1139, 1139, 221, 221, 1140,
+
+ 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148,
+ 1149, 1150, 221, 221, 221, 221, 221, 221,
+ 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148,
+ 1149, 1150, 221, 221, 221, 221, 221, 221,
+
+ 1151, 1151, 1151, 1151, 1151, 1151, 1151, 1152,
+ 1153, 1153, 1153, 1153, 1151, 1151, 221, 221,
+ 1154, 1154, 1154, 1154, 1154, 1155, 1155, 1155,
+ 1155, 1155, 1155, 1154, 1154, 1155, 1156, 1157,
+
+ 1157, 1158, 1158, 1159, 1159, 1158, 1158, 1158,
+ 1158, 1158, 1159, 1158, 1158, 1158, 1158, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+
+ 1160, 1160, 1160, 1160, 1161, 1162, 1163, 1162,
+ 1163, 1162, 1163, 1162, 1163, 1162, 1163, 1162,
+ 1162, 1162, 1163, 1162, 1162, 1162, 1162, 1162,
+ 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162,
+
+ 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162,
+ 1162, 1162, 1162, 1162, 1162, 1162, 1162, 1162,
+ 1162, 1162, 1162, 1162, 1164, 1165, 1160, 1160,
+ 1160, 1160, 1160, 1166, 1160, 1166, 1161, 1161,
+
+ 1166, 1166, 1160, 1166, 1167, 1162, 1162, 1162,
+ 1162, 1162, 1162, 1162, 1168, 221, 221, 221,
+ 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176,
+ 1177, 1178, 1179, 1179, 1180, 1181, 1179, 1179,
+
+ 1181, 1182, 1182, 1182, 1182, 1182, 1182, 1182,
+ 1182, 1182, 1182, 1183, 1184, 1183, 1183, 1183,
+ 1183, 1183, 1183, 1183, 1182, 1182, 1182, 1182,
+ 1182, 1182, 1182, 1182, 1182, 1185, 1185, 221,
+
+ 1186, 1186, 1187, 1188, 1188, 1188, 1188, 1188,
+ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188,
+ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188,
+ 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188,
+
+ 1188, 1187, 1186, 1186, 1186, 1186, 1187, 1187,
+ 1186, 1186, 1189, 1190, 1191, 1191, 1188, 1188,
+ 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199,
+ 1200, 1201, 1202, 1202, 1202, 1202, 1202, 1202,
+
+ 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203,
+ 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203,
+ 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203,
+ 1203, 1203, 1203, 1203, 1203, 1203, 1203, 1203,
+
+ 1203, 1203, 1203, 1203, 1203, 1203, 1204, 1205,
+ 1206, 1206, 1205, 1205, 1205, 1206, 1205, 1206,
+ 1206, 1206, 1207, 1207, 221, 221, 221, 221,
+ 221, 221, 221, 221, 1208, 1208, 1208, 1208,
+
+ 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209,
+ 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209,
+ 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209,
+ 1209, 1209, 1209, 1209, 1209, 1209, 1209, 1209,
- 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245,
- 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245,
- 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245,
- 1245, 1245, 1245, 221, 221, 1245, 1245, 1245,
+ 1209, 1209, 1209, 1209, 1210, 1210, 1210, 1210,
+ 1210, 1210, 1210, 1210, 1211, 1211, 1211, 1211,
+ 1211, 1211, 1211, 1211, 1210, 1210, 1211, 1212,
+ 221, 221, 221, 1213, 1213, 1214, 1214, 1214,
+
+ 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222,
+ 1223, 1224, 221, 221, 221, 1209, 1209, 1209,
+ 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232,
+ 1233, 1234, 1235, 1235, 1235, 1235, 1235, 1235,
+
+ 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235,
+ 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235,
+ 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235,
+ 1236, 1236, 1236, 1236, 1236, 1236, 1237, 1237,
+
+ 1238, 1239, 1240, 1241, 1241, 1242, 1243, 1244,
+ 1245, 221, 221, 221, 221, 221, 221, 221,
+ 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246,
+ 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246,
1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246,
+ 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246,
+ 1246, 1246, 1246, 1246, 1246, 1246, 1246, 1246,
+ 1246, 1246, 1246, 221, 221, 1246, 1246, 1246,
+
+ 1247, 1247, 1247, 1247, 1247, 1247, 1247, 1247,
221, 221, 221, 221, 221, 221, 221, 221,
- 1247, 1247, 1247, 1248, 1249, 1250, 1250, 1250,
- 1250, 1250, 1247, 1247, 1250, 1250, 1250, 1250,
+ 1248, 1248, 1248, 1249, 1250, 1251, 1251, 1251,
+ 1251, 1251, 1248, 1248, 1251, 1251, 1251, 1251,
- 1247, 1251, 1249, 1249, 1249, 1249, 1249, 1249,
- 1249, 1252, 1252, 1252, 1252, 1250, 1252, 1252,
- 1252, 1252, 1252, 1253, 1254, 1253, 1253, 1255,
- 1153, 1153, 1256, 221, 221, 221, 221, 221,
+ 1248, 1252, 1250, 1250, 1250, 1250, 1250, 1250,
+ 1250, 1253, 1253, 1253, 1253, 1251, 1253, 1253,
+ 1253, 1253, 1253, 1254, 1255, 1254, 1254, 1256,
+ 1154, 1154, 1257, 221, 221, 221, 221, 221,
129, 129, 129, 129, 129, 129, 129, 129,
129, 129, 129, 129, 129, 129, 129, 129,
129, 129, 129, 129, 129, 129, 129, 129,
129, 129, 129, 129, 129, 129, 129, 129,
- 129, 129, 129, 129, 129, 129, 1257, 1257,
- 1257, 1257, 1257, 1258, 1259, 1259, 1259, 1260,
- 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259,
- 1259, 1259, 1259, 1260, 1259, 1259, 1259, 1259,
+ 129, 129, 129, 129, 129, 129, 1258, 1258,
+ 1258, 1258, 1258, 1259, 1260, 1260, 1260, 1261,
+ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260,
+ 1260, 1260, 1260, 1261, 1260, 1260, 1260, 1260,
- 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259,
- 1259, 1259, 1259, 1259, 1259, 1259, 1260, 1259,
- 1259, 1259, 1259, 1259, 1259, 1259, 1259, 1259,
- 1259, 1259, 1259, 1259, 1259, 1261, 1261, 1261,
+ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260,
+ 1260, 1260, 1260, 1260, 1260, 1260, 1261, 1260,
+ 1260, 1260, 1260, 1260, 1260, 1260, 1260, 1260,
+ 1260, 1260, 1260, 1260, 1260, 1262, 1262, 1262,
- 1261, 1261, 1259, 1259, 1259, 1259, 1261, 1261,
- 1261, 1261, 1261, 129, 130, 130, 130, 130,
+ 1262, 1262, 1260, 1260, 1260, 1260, 1262, 1262,
+ 1262, 1262, 1262, 129, 130, 130, 130, 130,
130, 130, 130, 130, 130, 130, 130, 130,
- 1262, 1263, 130, 130, 130, 1264, 130, 130,
+ 1263, 1264, 130, 130, 130, 1265, 130, 130,
130, 130, 130, 130, 130, 130, 130, 130,
- 130, 130, 130, 130, 130, 130, 1265, 130,
+ 130, 130, 130, 130, 130, 130, 1266, 130,
130, 130, 130, 130, 130, 130, 130, 130,
- 130, 130, 130, 1266, 1266, 1266, 1266, 1266,
+ 130, 130, 130, 1267, 1267, 1267, 1267, 1267,
- 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266,
- 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266,
- 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1266,
- 1266, 1266, 1266, 1266, 1266, 1266, 1266, 1267,
+ 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267,
+ 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267,
+ 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1267,
+ 1267, 1267, 1267, 1267, 1267, 1267, 1267, 1268,
- 1268, 1268, 1269, 1268, 1270, 1270, 1270, 1270,
- 1270, 1270, 1271, 1272, 1272, 1273, 1274, 1275,
- 1276, 1272, 1272, 1272, 1272, 1272, 1272, 1272,
- 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1272,
+ 1269, 1269, 1270, 1269, 1271, 1271, 1271, 1271,
+ 1271, 1271, 1272, 1273, 1273, 1274, 1275, 1276,
+ 1277, 1273, 1273, 1273, 1273, 1273, 1273, 1273,
+ 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1273,
- 1272, 1272, 1272, 1272, 1272, 1272, 1272, 1153,
- 1153, 1153, 1153, 1153, 1153, 1153, 1153, 1153,
- 1153, 1153, 1153, 1153, 1153, 1153, 1277, 1278,
- 1278, 1279, 1280, 1281, 1282, 1250, 1270, 1271,
+ 1273, 1273, 1273, 1273, 1273, 1273, 1273, 1154,
+ 1154, 1154, 1154, 1154, 1154, 1154, 1154, 1154,
+ 1154, 1154, 1154, 1154, 1154, 1154, 1278, 1279,
+ 1279, 1280, 1281, 1282, 1283, 1251, 1271, 1272,
81, 83, 81, 83, 81, 83, 81, 83,
81, 83, 81, 83, 81, 83, 81, 83,
@@ -1918,528 +1918,528 @@ static constexpr unsigned short uc_property_trie[] = {
81, 83, 81, 83, 81, 83, 81, 83,
81, 83, 81, 83, 81, 83, 81, 83,
- 81, 83, 81, 83, 81, 83, 1283, 1284,
- 1285, 1286, 1287, 1288, 1289, 1289, 1290, 1289,
+ 81, 83, 81, 83, 81, 83, 1284, 1285,
+ 1286, 1287, 1288, 1289, 1290, 1290, 1291, 1290,
81, 83, 81, 83, 81, 83, 81, 83,
81, 83, 81, 83, 81, 83, 81, 83,
81, 83, 81, 83, 81, 83, 81, 83,
- 81, 83, 1291, 1292, 1291, 1292, 1291, 1292,
+ 81, 83, 1292, 1293, 1292, 1293, 1292, 1293,
- 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293,
1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294,
- 1293, 1293, 1293, 1293, 1293, 1293, 221, 221,
+ 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295,
1294, 1294, 1294, 1294, 1294, 1294, 221, 221,
+ 1295, 1295, 1295, 1295, 1295, 1295, 221, 221,
- 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293,
1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294,
- 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293,
+ 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295,
1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294,
+ 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295,
- 1293, 1293, 1293, 1293, 1293, 1293, 221, 221,
1294, 1294, 1294, 1294, 1294, 1294, 221, 221,
- 1295, 1293, 1296, 1293, 1297, 1293, 1298, 1293,
- 221, 1294, 221, 1294, 221, 1294, 221, 1294,
+ 1295, 1295, 1295, 1295, 1295, 1295, 221, 221,
+ 1296, 1294, 1297, 1294, 1298, 1294, 1299, 1294,
+ 221, 1295, 221, 1295, 221, 1295, 221, 1295,
- 1293, 1293, 1293, 1293, 1293, 1293, 1293, 1293,
1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294,
- 1299, 1300, 1301, 1302, 1301, 1302, 1303, 1304,
- 1305, 1306, 1307, 1308, 1309, 1310, 221, 221,
-
- 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318,
- 1319, 1320, 1321, 1322, 1323, 1324, 1325, 1326,
- 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1334,
- 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342,
-
- 1343, 1344, 1345, 1346, 1347, 1348, 1349, 1350,
- 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358,
- 1293, 1293, 1359, 1360, 1361, 221, 1362, 1363,
- 1294, 1294, 1364, 1365, 1366, 226, 1367, 226,
-
- 226, 1368, 1369, 1370, 1371, 221, 1372, 1373,
- 1374, 1375, 1374, 1375, 1376, 1368, 1368, 1368,
- 1293, 1293, 1377, 1378, 221, 221, 1379, 1380,
- 1294, 1294, 1381, 1382, 221, 1368, 1368, 1368,
-
- 1293, 1293, 1383, 1384, 1385, 1386, 1387, 1388,
- 1294, 1294, 1389, 1390, 1391, 1368, 1392, 1392,
- 221, 221, 1393, 1394, 1395, 221, 1396, 1397,
- 1398, 1399, 1400, 1401, 1402, 1403, 226, 221,
-
- 1404, 1404, 1405, 1405, 1405, 1405, 1405, 1406,
- 1405, 1405, 1405, 1407, 1408, 1409, 1410, 1411,
- 1412, 1413, 1414, 1415, 1416, 1417, 54, 1418,
- 1419, 1420, 1421, 1422, 1423, 1424, 1421, 1422,
-
- 54, 54, 54, 1425, 1426, 1427, 1427, 1428,
- 1429, 1430, 1431, 1432, 1433, 1434, 1435, 1436,
- 1437, 1438, 1437, 1439, 1440, 1441, 1442, 1442,
- 1425, 1443, 1444, 54, 1445, 1446, 1447, 1448,
-
- 1448, 1425, 1425, 1425, 1449, 1450, 1451, 1452,
- 1453, 1454, 1455, 1455, 1455, 1455, 1456, 1456,
- 1456, 1456, 1457, 1458, 1459, 1460, 1461, 1462,
- 1461, 1461, 1461, 1461, 1460, 1461, 1461, 1463,
-
- 1464, 1465, 1465, 1465, 1466, 1467, 1468, 1469,
- 1470, 1471, 1472, 1472, 1472, 1472, 1472, 1472,
- 1473, 1474, 221, 221, 1475, 1476, 1477, 1478,
- 1479, 1480, 1481, 1482, 1483, 1484, 1485, 1486,
-
- 1473, 70, 65, 66, 1475, 1476, 1477, 1478,
- 1479, 1480, 1481, 1482, 1483, 1484, 1485, 221,
- 1266, 1266, 1266, 1266, 1266, 1487, 1487, 1487,
- 1487, 1487, 1487, 1487, 1487, 221, 221, 221,
-
- 768, 768, 768, 768, 768, 768, 768, 1488,
- 1489, 1490, 768, 1491, 1492, 1493, 1493, 1493,
- 1494, 1494, 1495, 1495, 1495, 1495, 1496, 1497,
- 1497, 1498, 1499, 1500, 1501, 1501, 1502, 1503,
-
- 1504, 1505, 1505, 1505, 1505, 1505, 1505, 1505,
- 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505,
- 288, 288, 1506, 1506, 288, 288, 288, 288,
- 1506, 1506, 1506, 288, 288, 1507, 1507, 1507,
-
- 1507, 288, 1508, 1508, 1509, 1510, 1510, 1511,
- 1512, 1511, 1510, 1513, 1271, 1271, 1271, 1271,
- 1272, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
-
- 1514, 1514, 1515, 1516, 1517, 1518, 1514, 1515,
- 1517, 1516, 1519, 1515, 1515, 1515, 1519, 1519,
- 1515, 1515, 1515, 1520, 1517, 1515, 1521, 1517,
- 1522, 1515, 1515, 1515, 1515, 1515, 1517, 1517,
-
- 1523, 1524, 1525, 1517, 1515, 1517, 1526, 1517,
- 1515, 1517, 1527, 1528, 1515, 1515, 1529, 1519,
- 1515, 1515, 1530, 1515, 1519, 1531, 1531, 1531,
- 1531, 1532, 1533, 1534, 1535, 1536, 1537, 1537,
-
- 1538, 1457, 1457, 1457, 1457, 1537, 1536, 1536,
- 1536, 1536, 1539, 1457, 1540, 1541, 1542, 1543,
- 1544, 1544, 1544, 72, 72, 1545, 1545, 1545,
- 1545, 1545, 1545, 72, 72, 72, 72, 1545,
-
- 1546, 1546, 1546, 1546, 1546, 1546, 1546, 1546,
- 1546, 1546, 1546, 1546, 1547, 1547, 1547, 1547,
- 1548, 1548, 1548, 1548, 1548, 1548, 1548, 1548,
- 1548, 1548, 1549, 1549, 1549, 1549, 1549, 1549,
-
- 1550, 1550, 1550, 1551, 138, 1552, 1552, 1552,
- 1552, 1553, 1554, 1554, 221, 221, 221, 221,
- 75, 75, 75, 75, 1555, 61, 61, 61,
- 61, 61, 1556, 1556, 1517, 1517, 1517, 1517,
-
- 1522, 1517, 1517, 1522, 1517, 1517, 1522, 1517,
- 1517, 56, 56, 1517, 1517, 1517, 1556, 1517,
- 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517,
- 1557, 1557, 1517, 1517, 1517, 1517, 1517, 1517,
-
- 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517,
- 1517, 1517, 1517, 1517, 1517, 1558, 1556, 1556,
- 1517, 1517, 75, 1517, 75, 1517, 1517, 1517,
- 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517,
+ 1295, 1295, 1295, 1295, 1295, 1295, 1295, 1295,
+ 1300, 1301, 1302, 1303, 1302, 1303, 1304, 1305,
+ 1306, 1307, 1308, 1309, 1310, 1311, 221, 221,
+
+ 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319,
+ 1320, 1321, 1322, 1323, 1324, 1325, 1326, 1327,
+ 1328, 1329, 1330, 1331, 1332, 1333, 1334, 1335,
+ 1336, 1337, 1338, 1339, 1340, 1341, 1342, 1343,
+
+ 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1351,
+ 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359,
+ 1294, 1294, 1360, 1361, 1362, 221, 1363, 1364,
+ 1295, 1295, 1365, 1366, 1367, 226, 1368, 226,
+
+ 226, 1369, 1370, 1371, 1372, 221, 1373, 1374,
+ 1375, 1376, 1375, 1376, 1377, 1369, 1369, 1369,
+ 1294, 1294, 1378, 1379, 221, 221, 1380, 1381,
+ 1295, 1295, 1382, 1383, 221, 1369, 1369, 1369,
+
+ 1294, 1294, 1384, 1385, 1386, 1387, 1388, 1389,
+ 1295, 1295, 1390, 1391, 1392, 1369, 1393, 1393,
+ 221, 221, 1394, 1395, 1396, 221, 1397, 1398,
+ 1399, 1400, 1401, 1402, 1403, 1404, 226, 221,
+
+ 1405, 1405, 1406, 1406, 1406, 1406, 1406, 1407,
+ 1406, 1406, 1406, 1408, 1409, 1410, 1411, 1412,
+ 1413, 1414, 1415, 1416, 1417, 1418, 54, 1419,
+ 1420, 1421, 1422, 1423, 1424, 1425, 1422, 1423,
+
+ 54, 54, 54, 1426, 1427, 1428, 1428, 1429,
+ 1430, 1431, 1432, 1433, 1434, 1435, 1436, 1437,
+ 1438, 1439, 1438, 1440, 1441, 1442, 1443, 1443,
+ 1426, 1444, 1445, 54, 1446, 1447, 1448, 1449,
+
+ 1449, 1426, 1426, 1426, 1450, 1451, 1452, 1453,
+ 1454, 1455, 1456, 1456, 1456, 1456, 1457, 1457,
+ 1457, 1457, 1458, 1459, 1460, 1461, 1462, 1463,
+ 1462, 1462, 1462, 1462, 1461, 1462, 1462, 1464,
+
+ 1465, 1466, 1466, 1466, 1467, 1468, 1469, 1470,
+ 1471, 1472, 1473, 1473, 1473, 1473, 1473, 1473,
+ 1474, 1475, 221, 221, 1476, 1477, 1478, 1479,
+ 1480, 1481, 1482, 1483, 1484, 1485, 1486, 1487,
+
+ 1474, 70, 65, 66, 1476, 1477, 1478, 1479,
+ 1480, 1481, 1482, 1483, 1484, 1485, 1486, 221,
+ 1267, 1267, 1267, 1267, 1267, 1488, 1488, 1488,
+ 1488, 1488, 1488, 1488, 1488, 221, 221, 221,
+
+ 768, 768, 768, 768, 768, 768, 768, 1489,
+ 1490, 1491, 768, 1492, 1493, 1494, 1494, 1494,
+ 1495, 1495, 1496, 1496, 1496, 1496, 1497, 1498,
+ 1498, 1499, 1500, 1501, 1502, 1502, 1503, 1504,
+
+ 1505, 1506, 1506, 1506, 1506, 1506, 1506, 1506,
+ 1506, 1506, 1506, 1506, 1506, 1506, 1506, 1506,
+ 288, 288, 1507, 1507, 288, 288, 288, 288,
+ 1507, 1507, 1507, 288, 288, 1508, 1508, 1508,
+
+ 1508, 288, 1509, 1509, 1510, 1511, 1511, 1512,
+ 1513, 1512, 1511, 1514, 1272, 1272, 1272, 1272,
+ 1273, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+
+ 1515, 1515, 1516, 1517, 1518, 1519, 1515, 1516,
+ 1518, 1517, 1520, 1516, 1516, 1516, 1520, 1520,
+ 1516, 1516, 1516, 1521, 1518, 1516, 1522, 1518,
+ 1523, 1516, 1516, 1516, 1516, 1516, 1518, 1518,
+
+ 1524, 1525, 1526, 1518, 1516, 1518, 1527, 1518,
+ 1516, 1518, 1528, 1529, 1516, 1516, 1530, 1520,
+ 1516, 1516, 1531, 1516, 1520, 1532, 1532, 1532,
+ 1532, 1533, 1534, 1535, 1536, 1537, 1538, 1538,
+
+ 1539, 1458, 1458, 1458, 1458, 1538, 1537, 1537,
+ 1537, 1537, 1540, 1458, 1541, 1542, 1543, 1544,
+ 1545, 1545, 1545, 72, 72, 1546, 1546, 1546,
+ 1546, 1546, 1546, 72, 72, 72, 72, 1546,
+
+ 1547, 1547, 1547, 1547, 1547, 1547, 1547, 1547,
+ 1547, 1547, 1547, 1547, 1548, 1548, 1548, 1548,
+ 1549, 1549, 1549, 1549, 1549, 1549, 1549, 1549,
+ 1549, 1549, 1550, 1550, 1550, 1550, 1550, 1550,
+
+ 1551, 1551, 1551, 1552, 138, 1553, 1553, 1553,
+ 1553, 1554, 1555, 1555, 221, 221, 221, 221,
+ 75, 75, 75, 75, 1556, 61, 61, 61,
+ 61, 61, 1557, 1557, 1518, 1518, 1518, 1518,
+
+ 1523, 1518, 1518, 1523, 1518, 1518, 1523, 1518,
+ 1518, 56, 56, 1518, 1518, 1518, 1557, 1518,
+ 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1518,
+ 1558, 1558, 1518, 1518, 1518, 1518, 1518, 1518,
+
+ 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1518,
+ 1518, 1518, 1518, 1518, 1518, 1559, 1557, 1557,
+ 1518, 1518, 75, 1518, 75, 1518, 1518, 1518,
+ 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1518,
+
+ 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1558,
+ 1518, 1518, 1518, 1534, 1534, 1534, 1534, 1534,
+ 1534, 1534, 1534, 1534, 1458, 1458, 1458, 1458,
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+
+ 75, 1523, 75, 75, 1557, 1523, 1523, 75,
+ 1560, 1561, 1562, 1563, 1564, 1565, 1523, 75,
+ 1523, 75, 1566, 1567, 1523, 1568, 1523, 1523,
+ 1523, 1523, 75, 1523, 1523, 75, 75, 1569,
+
+ 1570, 1571, 1572, 75, 1573, 75, 1557, 75,
+ 75, 75, 75, 75, 1574, 1575, 75, 1575,
+ 1575, 1523, 1523, 1523, 75, 75, 75, 75,
+ 1523, 1523, 1523, 1523, 1576, 1577, 1523, 1523,
+
+ 1523, 1557, 1523, 1578, 1557, 1579, 1523, 1557,
+ 75, 1557, 1523, 1523, 1580, 1523, 1523, 1523,
+ 1523, 1523, 1576, 1581, 1582, 1581, 1523, 1523,
+ 1523, 1523, 1523, 1523, 1523, 1523, 1523, 1523,
+
+ 1583, 75, 1557, 1523, 1576, 1577, 1576, 1577,
+ 1582, 1581, 1576, 1577, 1523, 1557, 1584, 1585,
+ 1586, 1587, 1582, 1581, 1586, 1587, 1582, 1581,
+ 1586, 1587, 1582, 1581, 1582, 1581, 1582, 1581,
+
+ 1586, 1587, 1576, 1577, 1586, 1587, 1576, 1577,
+ 1586, 1587, 1582, 1581, 1523, 1523, 1523, 1582,
+ 1581, 1582, 1581, 1523, 1523, 75, 1523, 1523,
+ 1588, 75, 1523, 1523, 1523, 1523, 1523, 1523,
+
+ 1523, 1523, 1582, 1581, 1523, 75, 1589, 1523,
+ 1590, 1591, 1523, 1591, 1557, 1557, 1557, 1557,
+ 1582, 1581, 1582, 1581, 1582, 1581, 1582, 1581,
+ 1592, 1523, 1523, 1523, 1523, 1523, 1523, 75,
+
+ 1523, 1523, 1523, 1523, 1523, 1523, 1523, 1523,
+ 1523, 1582, 1581, 1582, 1581, 1593, 1523, 1523,
+ 1582, 1581, 1523, 1523, 1523, 1523, 1582, 1581,
+ 1582, 1581, 1582, 1581, 1582, 1581, 1582, 1581,
+
+ 1586, 1587, 1586, 1587, 1582, 1581, 1582, 1581,
+ 1582, 1581, 1586, 1587, 1586, 1587, 1523, 1594,
+ 1582, 1581, 1595, 1595, 1595, 1458, 1596, 1596,
+ 1458, 1458, 1597, 1597, 1597, 1598, 1598, 1458,
+
+ 1518, 1534, 1518, 1518, 1518, 1518, 1518, 1518,
+ 1451, 1452, 1451, 1452, 1518, 1518, 1518, 1518,
+ 1518, 1518, 1558, 1518, 1518, 1518, 1518, 1518,
+ 1518, 1518, 1599, 1599, 1518, 1518, 1518, 1518,
+
+ 1523, 1523, 1518, 1518, 1518, 1518, 1518, 1518,
+ 56, 1600, 1601, 1518, 1518, 1518, 1518, 1518,
+ 1518, 1518, 1518, 1518, 1518, 1518, 1602, 1602,
+ 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602,
+
+ 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602,
+ 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602,
+ 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602,
+ 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602,
+
+ 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602,
+ 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602,
+ 1602, 1602, 1602, 1602, 1602, 1602, 1602, 1602,
+ 1602, 1602, 1602, 1534, 1458, 1534, 1534, 1534,
+
+ 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534,
+ 1603, 1534, 1534, 1534, 1534, 1534, 1534, 1534,
+ 1534, 1534, 1534, 1534, 1534, 1604, 1534, 1534,
+ 1534, 1534, 1534, 1458, 1458, 1458, 1458, 1458,
+
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+ 1458, 1458, 1458, 1458, 1540, 1540, 1540, 1540,
+ 1540, 1540, 1540, 1540, 1540, 1540, 1540, 1540,
+
+ 1540, 1540, 1540, 1540, 1540, 1540, 1540, 1540,
+ 1540, 1540, 1540, 1540, 1540, 1540, 1540, 1605,
+ 1606, 1541, 1541, 1541, 1541, 1541, 1541, 1541,
+ 1541, 1541, 1541, 1541, 1607, 1607, 1607, 1607,
- 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1557,
- 1517, 1517, 1517, 1533, 1533, 1533, 1533, 1533,
- 1533, 1533, 1533, 1533, 1457, 1457, 1457, 1457,
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457,
+ 1607, 1607, 1542, 1542, 1542, 1542, 1542, 1542,
+ 1608, 1609, 1609, 1609, 1609, 1610, 1610, 1610,
+ 1611, 1612, 1612, 1611, 1613, 1613, 1613, 1613,
+ 1614, 1614, 1614, 1615, 1615, 1615, 1615, 1616,
- 75, 1522, 75, 75, 1556, 1522, 1522, 75,
- 1559, 1560, 1561, 1562, 1563, 1564, 1522, 75,
- 1522, 75, 1565, 1566, 1522, 1567, 1522, 1522,
- 1522, 1522, 75, 1522, 1522, 75, 75, 1568,
+ 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1518,
+ 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1518,
+ 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1518,
+ 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1518,
- 1569, 1570, 1571, 75, 1572, 75, 1556, 75,
- 75, 75, 75, 75, 1573, 1574, 75, 1574,
- 1574, 1522, 1522, 1522, 75, 75, 75, 75,
- 1522, 1522, 1522, 1522, 1575, 1576, 1522, 1522,
-
- 1522, 1556, 1522, 1577, 1556, 1578, 1522, 1556,
- 75, 1556, 1522, 1522, 1579, 1522, 1522, 1522,
- 1522, 1522, 1575, 1580, 1581, 1580, 1522, 1522,
- 1522, 1522, 1522, 1522, 1522, 1522, 1522, 1522,
-
- 1582, 75, 1556, 1522, 1575, 1576, 1575, 1576,
- 1581, 1580, 1575, 1576, 1522, 1556, 1583, 1584,
- 1585, 1586, 1581, 1580, 1585, 1586, 1581, 1580,
- 1585, 1586, 1581, 1580, 1581, 1580, 1581, 1580,
-
- 1585, 1586, 1575, 1576, 1585, 1586, 1575, 1576,
- 1585, 1586, 1581, 1580, 1522, 1522, 1522, 1581,
- 1580, 1581, 1580, 1522, 1522, 75, 1522, 1522,
- 1587, 75, 1522, 1522, 1522, 1522, 1522, 1522,
-
- 1522, 1522, 1581, 1580, 1522, 75, 1588, 1522,
- 1589, 1590, 1522, 1590, 1556, 1556, 1556, 1556,
- 1581, 1580, 1581, 1580, 1581, 1580, 1581, 1580,
- 1591, 1522, 1522, 1522, 1522, 1522, 1522, 75,
-
- 1522, 1522, 1522, 1522, 1522, 1522, 1522, 1522,
- 1522, 1581, 1580, 1581, 1580, 1592, 1522, 1522,
- 1581, 1580, 1522, 1522, 1522, 1522, 1581, 1580,
- 1581, 1580, 1581, 1580, 1581, 1580, 1581, 1580,
-
- 1585, 1586, 1585, 1586, 1581, 1580, 1581, 1580,
- 1581, 1580, 1585, 1586, 1585, 1586, 1522, 1593,
- 1581, 1580, 1594, 1594, 1594, 1457, 1595, 1595,
- 1457, 1457, 1596, 1596, 1596, 1597, 1597, 1457,
-
- 1517, 1533, 1517, 1517, 1517, 1517, 1517, 1517,
- 1450, 1451, 1450, 1451, 1517, 1517, 1517, 1517,
- 1517, 1517, 1557, 1517, 1517, 1517, 1517, 1517,
- 1517, 1517, 1598, 1598, 1517, 1517, 1517, 1517,
-
- 1522, 1522, 1517, 1517, 1517, 1517, 1517, 1517,
- 56, 1599, 1600, 1517, 1517, 1517, 1517, 1517,
- 1517, 1517, 1517, 1517, 1517, 1517, 1601, 1601,
- 1601, 1601, 1601, 1601, 1601, 1601, 1601, 1601,
-
- 1601, 1601, 1601, 1601, 1601, 1601, 1601, 1601,
- 1601, 1601, 1601, 1601, 1601, 1601, 1601, 1601,
- 1601, 1601, 1601, 1601, 1601, 1601, 1601, 1601,
- 1601, 1601, 1601, 1601, 1601, 1601, 1601, 1601,
-
- 1601, 1601, 1601, 1601, 1601, 1601, 1601, 1601,
- 1601, 1601, 1601, 1601, 1601, 1601, 1601, 1601,
- 1601, 1601, 1601, 1601, 1601, 1601, 1601, 1601,
- 1601, 1601, 1601, 1533, 1457, 1533, 1533, 1533,
-
- 1533, 1533, 1533, 1533, 1533, 1533, 1533, 1533,
- 1602, 1533, 1533, 1533, 1533, 1533, 1533, 1533,
- 1533, 1533, 1533, 1533, 1533, 1603, 1533, 1533,
- 1533, 1533, 1533, 1457, 1457, 1457, 1457, 1457,
-
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457,
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457,
- 1457, 1457, 1457, 1457, 1539, 1539, 1539, 1539,
- 1539, 1539, 1539, 1539, 1539, 1539, 1539, 1539,
-
- 1539, 1539, 1539, 1539, 1539, 1539, 1539, 1539,
- 1539, 1539, 1539, 1539, 1539, 1539, 1539, 1604,
- 1605, 1540, 1540, 1540, 1540, 1540, 1540, 1540,
- 1540, 1540, 1540, 1540, 1606, 1606, 1606, 1606,
-
- 1606, 1606, 1541, 1541, 1541, 1541, 1541, 1541,
- 1607, 1608, 1608, 1608, 1608, 1609, 1609, 1609,
- 1610, 1611, 1611, 1610, 1612, 1612, 1612, 1612,
- 1613, 1613, 1613, 1614, 1614, 1614, 1614, 1615,
-
- 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517,
- 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517,
- 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517,
- 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517,
-
- 1517, 1517, 1517, 1517, 1517, 1533, 1533, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
+ 1518, 1518, 1518, 1518, 1518, 1534, 1534, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
- 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517,
- 1517, 1517, 1517, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
+ 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1518,
+ 1518, 1518, 1518, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 1616, 1617, 1618, 1619, 1620, 1621, 1622, 1623,
- 1624, 72, 72, 72, 72, 72, 72, 72,
- 72, 72, 72, 72, 1625, 1626, 1627, 1628,
- 1629, 1630, 1631, 1632, 1633, 1634, 1634, 1634,
+ 1617, 1618, 1619, 1620, 1621, 1622, 1623, 1624,
+ 1625, 72, 72, 72, 72, 72, 72, 72,
+ 72, 72, 72, 72, 1626, 1627, 1628, 1629,
+ 1630, 1631, 1632, 1633, 1634, 1635, 1635, 1635,
- 1634, 1634, 1634, 1634, 1634, 1634, 1634, 1634,
- 1635, 1636, 1637, 1638, 1639, 1640, 1641, 1642,
- 1643, 1644, 1644, 1644, 1644, 1644, 1644, 1644,
- 1644, 1644, 1644, 1644, 1645, 1645, 1645, 1645,
+ 1635, 1635, 1635, 1635, 1635, 1635, 1635, 1635,
+ 1636, 1637, 1638, 1639, 1640, 1641, 1642, 1643,
+ 1644, 1645, 1645, 1645, 1645, 1645, 1645, 1645,
+ 1645, 1645, 1645, 1645, 1646, 1646, 1646, 1646,
- 1645, 1645, 1645, 1645, 1645, 1645, 1645, 1645,
- 1645, 1645, 1645, 1645, 1645, 1645, 1645, 1645,
- 1645, 1645, 1645, 1645, 1645, 1645, 1646, 1646,
1646, 1646, 1646, 1646, 1646, 1646, 1646, 1646,
-
- 1646, 1646, 1647, 1646, 1646, 1646, 1646, 1646,
1646, 1646, 1646, 1646, 1646, 1646, 1646, 1646,
- 1648, 1648, 1648, 1648, 1648, 1648, 1648, 1648,
- 1648, 1648, 1648, 1648, 1648, 1648, 1648, 1648,
-
- 1648, 1648, 1648, 1648, 1648, 1648, 1648, 1648,
- 1648, 1648, 1649, 1650, 1650, 1650, 1650, 1650,
- 1650, 1650, 1650, 1650, 1650, 1651, 1652, 1653,
- 1654, 1655, 1656, 1657, 1658, 1659, 1650, 1660,
-
- 1557, 1557, 1557, 1557, 1557, 1557, 1557, 1557,
- 1557, 1557, 1557, 1557, 1557, 1557, 1557, 1557,
- 1557, 1557, 1557, 1557, 1557, 1557, 1557, 1557,
- 1557, 1557, 1557, 1557, 1557, 1557, 1557, 1557,
-
- 1557, 1557, 1557, 1557, 1557, 1557, 1557, 1557,
- 1557, 1557, 1557, 1557, 1517, 1517, 1517, 1517,
- 1557, 1557, 1557, 1557, 1557, 1557, 1557, 1557,
- 1557, 1557, 1557, 1557, 1557, 1557, 1557, 1557,
-
- 1557, 1557, 1557, 1557, 1557, 1557, 1557, 1557,
- 1557, 1557, 1557, 1557, 1557, 1557, 1557, 1557,
- 1557, 1557, 1557, 1557, 1517, 1517, 1517, 1517,
- 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517,
-
- 1557, 1557, 1557, 1557, 1557, 1557, 1557, 1557,
- 1557, 1557, 1557, 1557, 1557, 1557, 1557, 1557,
- 1517, 1517, 1557, 1557, 1557, 1557, 1539, 1539,
- 1539, 1539, 1539, 1539, 1539, 1539, 1539, 1539,
-
- 1557, 1557, 1517, 1557, 1557, 1557, 1557, 1557,
- 1557, 1557, 56, 56, 1517, 1517, 1517, 1517,
- 1517, 1517, 1557, 1557, 1517, 1517, 61, 75,
- 1517, 1517, 1517, 1517, 1557, 1557, 1517, 1517,
-
- 61, 75, 1517, 1517, 1517, 1517, 1557, 1557,
- 1557, 1517, 1517, 1557, 1517, 1517, 1557, 1557,
- 1557, 1557, 1517, 1517, 1517, 1517, 1517, 1517,
- 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517,
-
- 1517, 1517, 1557, 1557, 1557, 1557, 1517, 1517,
- 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1557,
- 1533, 1533, 1533, 1533, 1533, 1533, 1533, 1533,
- 1457, 1457, 1457, 1661, 1661, 1662, 1662, 1457,
-
- 1663, 1663, 1663, 1663, 56, 61, 1557, 56,
+ 1646, 1646, 1646, 1646, 1646, 1646, 1647, 1647,
+ 1647, 1647, 1647, 1647, 1647, 1647, 1647, 1647,
+
+ 1647, 1647, 1648, 1647, 1647, 1647, 1647, 1647,
+ 1647, 1647, 1647, 1647, 1647, 1647, 1647, 1647,
+ 1649, 1649, 1649, 1649, 1649, 1649, 1649, 1649,
+ 1649, 1649, 1649, 1649, 1649, 1649, 1649, 1649,
+
+ 1649, 1649, 1649, 1649, 1649, 1649, 1649, 1649,
+ 1649, 1649, 1650, 1651, 1651, 1651, 1651, 1651,
+ 1651, 1651, 1651, 1651, 1651, 1652, 1653, 1654,
+ 1655, 1656, 1657, 1658, 1659, 1660, 1651, 1661,
+
+ 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558,
+ 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558,
+ 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558,
+ 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558,
+
+ 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558,
+ 1558, 1558, 1558, 1558, 1518, 1518, 1518, 1518,
+ 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558,
+ 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558,
+
+ 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558,
+ 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558,
+ 1558, 1558, 1558, 1558, 1518, 1518, 1518, 1518,
+ 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1518,
+
+ 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558,
+ 1558, 1558, 1558, 1558, 1558, 1558, 1558, 1558,
+ 1518, 1518, 1558, 1558, 1558, 1558, 1540, 1540,
+ 1540, 1540, 1540, 1540, 1540, 1540, 1540, 1540,
+
+ 1558, 1558, 1518, 1558, 1558, 1558, 1558, 1558,
+ 1558, 1558, 56, 56, 1518, 1518, 1518, 1518,
+ 1518, 1518, 1558, 1558, 1518, 1518, 61, 75,
+ 1518, 1518, 1518, 1518, 1558, 1558, 1518, 1518,
+
+ 61, 75, 1518, 1518, 1518, 1518, 1558, 1558,
+ 1558, 1518, 1518, 1558, 1518, 1518, 1558, 1558,
+ 1558, 1558, 1518, 1518, 1518, 1518, 1518, 1518,
+ 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1518,
+
+ 1518, 1518, 1558, 1558, 1558, 1558, 1518, 1518,
+ 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1558,
+ 1534, 1534, 1534, 1534, 1534, 1534, 1534, 1534,
+ 1458, 1458, 1458, 1662, 1662, 1663, 1663, 1458,
+
+ 1664, 1664, 1664, 1664, 56, 61, 1558, 56,
56, 61, 56, 56, 56, 56, 61, 61,
- 56, 56, 56, 1517, 1664, 1664, 1665, 1665,
- 1666, 1602, 1663, 1663, 1667, 1668, 1667, 1663,
+ 56, 56, 56, 1518, 1665, 1665, 1666, 1666,
+ 1667, 1603, 1664, 1664, 1668, 1669, 1668, 1664,
56, 56, 56, 56, 56, 56, 56, 56,
56, 56, 56, 56, 56, 56, 56, 56,
56, 56, 56, 56, 56, 56, 56, 56,
- 56, 1663, 1663, 1663, 56, 56, 56, 56,
+ 56, 1664, 1664, 1664, 56, 56, 56, 56,
61, 56, 61, 56, 56, 56, 56, 56,
- 1669, 1669, 1669, 1669, 1669, 1669, 1669, 1669,
- 1669, 1669, 1669, 1669, 56, 56, 56, 56,
+ 1670, 1670, 1670, 1670, 1670, 1670, 1670, 1670,
+ 1670, 1670, 1670, 1670, 56, 56, 56, 56,
56, 56, 56, 56, 56, 56, 56, 56,
61, 61, 56, 61, 61, 61, 56, 61,
- 1667, 61, 61, 56, 61, 61, 56, 1555,
- 1602, 1602, 1665, 1665, 1665, 1665, 1665, 1665,
- 1665, 1665, 1665, 1665, 1665, 1665, 1670, 1671,
-
- 1665, 1665, 1665, 1665, 1665, 1665, 1539, 1539,
- 1539, 1539, 1605, 1605, 1605, 1605, 1605, 1605,
- 1604, 1604, 1670, 1672, 1670, 1670, 1670, 1670,
- 1670, 1670, 1670, 1670, 1670, 1673, 1674, 1674,
-
- 1604, 1675, 1670, 1670, 1670, 1670, 1670, 1670,
- 1670, 1670, 1672, 1672, 1676, 1670, 1670, 1670,
- 1670, 1670, 1677, 1673, 1673, 1673, 1673, 1673,
- 1673, 1673, 1673, 1673, 1673, 1678, 1678, 1679,
-
- 1680, 1680, 1680, 1680, 1678, 1678, 1679, 1679,
- 1679, 1674, 1674, 1674, 1674, 1679, 1608, 1679,
- 1679, 1679, 1674, 1679, 1678, 1674, 1674, 1674,
- 1679, 1679, 1674, 1674, 1679, 1674, 1674, 1679,
-
- 1679, 1679, 1609, 1674, 1609, 1609, 1609, 1609,
- 1674, 1674, 1678, 1674, 1674, 1674, 1674, 1674,
- 1674, 1679, 1678, 1678, 1679, 1678, 1674, 1679,
- 1679, 1681, 1678, 1674, 1674, 1678, 1679, 1679,
-
- 1682, 1663, 1663, 1663, 1663, 1608, 1517, 1517,
- 1663, 1663, 1683, 1683, 1668, 1668, 56, 56,
- 56, 56, 56, 1517, 56, 1517, 56, 1517,
- 1517, 1517, 1517, 1517, 1517, 56, 1517, 1517,
-
- 1517, 56, 1517, 1517, 1517, 1517, 1517, 1517,
- 1608, 1517, 1517, 1517, 1517, 1517, 1517, 1517,
- 1517, 1517, 1517, 56, 56, 1517, 1517, 1517,
- 1517, 1517, 1517, 1517, 1517, 1557, 1517, 1517,
-
- 1517, 1517, 1517, 1517, 56, 1517, 1517, 56,
- 1517, 1517, 1517, 1517, 1608, 1517, 1608, 1517,
- 1517, 1517, 1517, 1608, 1608, 1608, 1517, 1684,
- 1517, 1517, 1517, 1685, 1685, 1685, 1685, 1686,
-
- 1686, 1517, 1687, 1688, 1663, 56, 56, 56,
- 1689, 1690, 1689, 1690, 1689, 1690, 1689, 1690,
- 1689, 1690, 1689, 1690, 1689, 1690, 1691, 1692,
- 1693, 1694, 1695, 1696, 1697, 1698, 1699, 1700,
-
- 1701, 1702, 1703, 1704, 1705, 1706, 1707, 1708,
- 1709, 1710, 1701, 1702, 1703, 1704, 1705, 1706,
- 1707, 1708, 1709, 1710, 1517, 1608, 1608, 1608,
- 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517,
-
- 1517, 56, 1517, 1517, 1517, 1517, 1517, 1517,
- 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1517,
- 1608, 1517, 1517, 1517, 1517, 1517, 1517, 1517,
- 1517, 1517, 1517, 1517, 1517, 1517, 1517, 1608,
-
- 1711, 1711, 1711, 1712, 1713, 1714, 1715, 1606,
- 1716, 1717, 1606, 1718, 1719, 1720, 1721, 1721,
- 1457, 1457, 1457, 1457, 1457, 1722, 1723, 1457,
- 1457, 1457, 1457, 1457, 1724, 1722, 1723, 1457,
-
- 1457, 1457, 1722, 1723, 1722, 1723, 1725, 1726,
- 1725, 1726, 1725, 1726, 1727, 1728, 1729, 1730,
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457,
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457,
-
- 1731, 1731, 1731, 1731, 1731, 1731, 1731, 1731,
- 1731, 1731, 1731, 1731, 1731, 1731, 1731, 1731,
- 1731, 1731, 1731, 1731, 1731, 1731, 1731, 1731,
- 1731, 1731, 1731, 1731, 1731, 1731, 1731, 1731,
-
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457,
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457,
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457,
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457,
-
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457,
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457,
- 1457, 1457, 1457, 1457, 1661, 1661, 1457, 1457,
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457,
-
- 1457, 1457, 1457, 1689, 1690, 1725, 1726, 1689,
- 1690, 1689, 1690, 1689, 1690, 1732, 1733, 1734,
- 1735, 1689, 1690, 1689, 1690, 1689, 1690, 1689,
- 1690, 1457, 1457, 1736, 1457, 1457, 1457, 1457,
-
- 1737, 1457, 1457, 1738, 1722, 1723, 1457, 1457,
- 1722, 1723, 1722, 1723, 1722, 1723, 1722, 1723,
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457,
- 1739, 1457, 1457, 1457, 1457, 1457, 1457, 1457,
-
- 1722, 1723, 1457, 1457, 1722, 1723, 1457, 1457,
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1722,
- 1723, 1722, 1723, 1457, 1722, 1723, 1457, 1457,
- 1689, 1690, 1689, 1690, 1457, 1457, 1457, 1457,
-
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457,
- 1722, 1723, 1457, 1457, 1457, 1457, 1457, 1457,
- 1457, 1457, 1457, 1457, 1457, 1740, 1457, 1457,
- 1722, 1723, 1457, 1457, 1689, 1690, 1457, 1457,
-
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457,
- 1457, 1457, 1457, 1457, 1538, 1457, 1457, 1457,
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457,
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457,
-
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457,
- 1457, 1457, 1457, 1722, 1723, 1722, 1723, 1457,
- 1457, 1457, 1457, 1457, 1722, 1723, 1457, 1457,
- 1457, 1457, 1457, 1457, 1722, 1723, 1457, 1457,
-
- 1457, 1457, 1457, 1457, 1722, 1723, 1457, 1457,
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1457,
- 1457, 1457, 1457, 1457, 1741, 1741, 1741, 1457,
- 1457, 1722, 1723, 1722, 1723, 1722, 1723, 1722,
-
- 1723, 1722, 1723, 1722, 1723, 1722, 1723, 1722,
- 1723, 1722, 1723, 1722, 1723, 1722, 1723, 1722,
- 1723, 1722, 1723, 1722, 1723, 1722, 1723, 1722,
- 1723, 1722, 1723, 1722, 1723, 1722, 1723, 1722,
-
- 1723, 1722, 1723, 1457, 1457, 1457, 1722, 1723,
- 1722, 1723, 1722, 1723, 1722, 1723, 1457, 1722,
- 1723, 1722, 1723, 1722, 1723, 1722, 1723, 1722,
- 1723, 1722, 1723, 1722, 1723, 1722, 1723, 1722,
-
- 1723, 1722, 1723, 1722, 1723, 1722, 1723, 1722,
- 1723, 1722, 1723, 1722, 1723, 1722, 1723, 1722,
- 1723, 1722, 1723, 1722, 1723, 1722, 1723, 1457,
- 1457, 1457, 1457, 1457, 1742, 1457, 1743, 1457,
-
- 1457, 1457, 1457, 1744, 1745, 1744, 1457, 1457,
- 1457, 1457, 1457, 1457, 1722, 1723, 1746, 1457,
- 1457, 1457, 1457, 1457, 1457, 1457, 1457, 1722,
- 1723, 1722, 1723, 1457, 1457, 1457, 1457, 1457,
-
- 1605, 1605, 1605, 1605, 1605, 1604, 1604, 1604,
- 1605, 1605, 1605, 1605, 1605, 1605, 1540, 1540,
- 1540, 1540, 1540, 1540, 1541, 1541, 1541, 1541,
- 1541, 1541, 1541, 1747, 1747, 1748, 1748, 1748,
-
- 1541, 1541, 1541, 1541, 1748, 1748, 1748, 1748,
- 1748, 1748, 1748, 1748, 1748, 1748, 1748, 1748,
- 1719, 1719, 1719, 1719, 1719, 1719, 1719, 1719,
- 1719, 1719, 1719, 1719, 1719, 1719, 1719, 1719,
-
- 1719, 1719, 1719, 1719, 1719, 1748, 1748, 1719,
- 1719, 1719, 1719, 1719, 1719, 1612, 1612, 1612,
- 1747, 1748, 1748, 1748, 1748, 1684, 1749, 1749,
- 1749, 1749, 1612, 1612, 1612, 1612, 1612, 1612,
-
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 221, 221, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
-
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 221, 1750,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
-
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1751, 1751, 1751, 1612, 1612, 1612,
-
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1752, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1615, 1751, 1751, 1751, 1751, 1751,
- 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
-
- 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
- 1751, 1751, 1751, 1751, 1554, 1554, 1554, 1554,
- 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
- 1751, 1751, 1751, 1751, 1751, 1751, 1753, 1752,
-
- 1754, 1754, 1754, 1754, 1754, 1754, 1754, 1754,
- 1754, 1754, 1754, 1754, 1754, 1754, 1754, 1754,
- 1754, 1754, 1754, 1754, 1754, 1754, 1754, 1754,
- 1754, 1754, 1754, 1754, 1754, 1754, 1754, 1754,
-
- 1754, 1754, 1754, 1754, 1754, 1754, 1754, 1754,
- 1754, 1754, 1754, 1754, 1754, 1754, 1754, 1755,
- 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756,
- 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756,
-
- 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756,
- 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756,
- 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1756,
- 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1757,
-
- 142, 138, 1758, 1759, 1760, 1761, 1762, 142,
- 138, 142, 138, 142, 138, 1763, 1764, 1765,
- 1766, 1289, 1291, 1292, 1767, 142, 138, 1767,
- 1289, 1289, 1289, 1289, 1768, 1768, 1769, 1770,
-
- 1771, 1772, 1771, 1772, 1771, 1772, 1771, 1772,
- 1771, 1772, 1771, 1772, 1771, 1772, 1771, 1772,
- 1771, 1772, 1771, 1772, 1771, 1772, 1771, 1772,
- 1771, 1772, 1771, 1772, 1771, 1772, 1771, 1772,
-
- 1771, 1772, 1771, 1772, 1773, 1774, 1774, 1774,
- 1774, 1774, 1774, 1775, 1776, 1775, 1776, 1777,
- 1777, 1777, 1778, 1779, 221, 221, 221, 221,
- 221, 1780, 1781, 1781, 1781, 1782, 1780, 1781,
-
- 1783, 1783, 1783, 1783, 1783, 1783, 1783, 1783,
- 1783, 1783, 1783, 1783, 1783, 1783, 1783, 1783,
- 1783, 1783, 1783, 1783, 1783, 1783, 1783, 1783,
- 1783, 1783, 1783, 1783, 1783, 1783, 1783, 1783,
-
- 1783, 1783, 1783, 1783, 1783, 1783, 221, 1784,
- 221, 221, 221, 221, 221, 1784, 221, 221,
- 1785, 1785, 1785, 1785, 1785, 1785, 1785, 1785,
- 1785, 1785, 1785, 1785, 1785, 1785, 1785, 1785,
-
- 1785, 1785, 1785, 1785, 1785, 1785, 1785, 1785,
- 1785, 1785, 1785, 1785, 1785, 1785, 1785, 1785,
- 1785, 1785, 1785, 1785, 1785, 1785, 1785, 1785,
- 1785, 1785, 1785, 1785, 1785, 1785, 1785, 1785,
-
- 1785, 1785, 1785, 1785, 1785, 1785, 1786, 1786,
- 221, 221, 221, 221, 221, 221, 221, 1787,
- 1788, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 1789,
+ 1668, 61, 61, 56, 61, 61, 56, 1556,
+ 1603, 1603, 1666, 1666, 1666, 1666, 1666, 1666,
+ 1666, 1666, 1666, 1666, 1666, 1666, 1671, 1672,
+
+ 1666, 1666, 1666, 1666, 1666, 1666, 1540, 1540,
+ 1540, 1540, 1606, 1606, 1606, 1606, 1606, 1606,
+ 1605, 1605, 1671, 1673, 1671, 1671, 1671, 1671,
+ 1671, 1671, 1671, 1671, 1671, 1674, 1675, 1675,
+
+ 1605, 1676, 1671, 1671, 1671, 1671, 1671, 1671,
+ 1671, 1671, 1673, 1673, 1677, 1671, 1671, 1671,
+ 1671, 1671, 1678, 1674, 1674, 1674, 1674, 1674,
+ 1674, 1674, 1674, 1674, 1674, 1679, 1679, 1680,
+
+ 1681, 1681, 1681, 1681, 1679, 1679, 1680, 1680,
+ 1680, 1675, 1675, 1675, 1675, 1680, 1609, 1680,
+ 1680, 1680, 1675, 1680, 1679, 1675, 1675, 1675,
+ 1680, 1680, 1675, 1675, 1680, 1675, 1675, 1680,
+
+ 1680, 1680, 1610, 1675, 1610, 1610, 1610, 1610,
+ 1675, 1675, 1679, 1675, 1675, 1675, 1675, 1675,
+ 1675, 1680, 1679, 1679, 1680, 1679, 1675, 1680,
+ 1680, 1682, 1679, 1675, 1675, 1679, 1680, 1680,
+
+ 1683, 1664, 1664, 1664, 1664, 1609, 1518, 1518,
+ 1664, 1664, 1684, 1684, 1669, 1669, 56, 56,
+ 56, 56, 56, 1518, 56, 1518, 56, 1518,
+ 1518, 1518, 1518, 1518, 1518, 56, 1518, 1518,
+
+ 1518, 56, 1518, 1518, 1518, 1518, 1518, 1518,
+ 1609, 1518, 1518, 1518, 1518, 1518, 1518, 1518,
+ 1518, 1518, 1518, 56, 56, 1518, 1518, 1518,
+ 1518, 1518, 1518, 1518, 1518, 1558, 1518, 1518,
+
+ 1518, 1518, 1518, 1518, 56, 1518, 1518, 56,
+ 1518, 1518, 1518, 1518, 1609, 1518, 1609, 1518,
+ 1518, 1518, 1518, 1609, 1609, 1609, 1518, 1685,
+ 1518, 1518, 1518, 1686, 1686, 1686, 1686, 1687,
+
+ 1687, 1518, 1688, 1689, 1664, 56, 56, 56,
+ 1690, 1691, 1690, 1691, 1690, 1691, 1690, 1691,
+ 1690, 1691, 1690, 1691, 1690, 1691, 1692, 1693,
+ 1694, 1695, 1696, 1697, 1698, 1699, 1700, 1701,
+
+ 1702, 1703, 1704, 1705, 1706, 1707, 1708, 1709,
+ 1710, 1711, 1702, 1703, 1704, 1705, 1706, 1707,
+ 1708, 1709, 1710, 1711, 1518, 1609, 1609, 1609,
+ 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1518,
+
+ 1518, 56, 1518, 1518, 1518, 1518, 1518, 1518,
+ 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1518,
+ 1609, 1518, 1518, 1518, 1518, 1518, 1518, 1518,
+ 1518, 1518, 1518, 1518, 1518, 1518, 1518, 1609,
+
+ 1712, 1712, 1712, 1713, 1714, 1715, 1716, 1607,
+ 1717, 1718, 1607, 1719, 1720, 1721, 1722, 1722,
+ 1458, 1458, 1458, 1458, 1458, 1723, 1724, 1458,
+ 1458, 1458, 1458, 1458, 1725, 1723, 1724, 1458,
+
+ 1458, 1458, 1723, 1724, 1723, 1724, 1726, 1727,
+ 1726, 1727, 1726, 1727, 1728, 1729, 1730, 1731,
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+
+ 1732, 1732, 1732, 1732, 1732, 1732, 1732, 1732,
+ 1732, 1732, 1732, 1732, 1732, 1732, 1732, 1732,
+ 1732, 1732, 1732, 1732, 1732, 1732, 1732, 1732,
+ 1732, 1732, 1732, 1732, 1732, 1732, 1732, 1732,
+
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+ 1458, 1458, 1458, 1458, 1662, 1662, 1458, 1458,
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+
+ 1458, 1458, 1458, 1690, 1691, 1726, 1727, 1690,
+ 1691, 1690, 1691, 1690, 1691, 1733, 1734, 1735,
+ 1736, 1690, 1691, 1690, 1691, 1690, 1691, 1690,
+ 1691, 1458, 1458, 1737, 1458, 1458, 1458, 1458,
+
+ 1738, 1458, 1458, 1739, 1723, 1724, 1458, 1458,
+ 1723, 1724, 1723, 1724, 1723, 1724, 1723, 1724,
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+ 1740, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+
+ 1723, 1724, 1458, 1458, 1723, 1724, 1458, 1458,
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1723,
+ 1724, 1723, 1724, 1458, 1723, 1724, 1458, 1458,
+ 1690, 1691, 1690, 1691, 1458, 1458, 1458, 1458,
+
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+ 1723, 1724, 1458, 1458, 1458, 1458, 1458, 1458,
+ 1458, 1458, 1458, 1458, 1458, 1741, 1458, 1458,
+ 1723, 1724, 1458, 1458, 1690, 1691, 1458, 1458,
+
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+ 1458, 1458, 1458, 1458, 1539, 1458, 1458, 1458,
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+ 1458, 1458, 1458, 1723, 1724, 1723, 1724, 1458,
+ 1458, 1458, 1458, 1458, 1723, 1724, 1458, 1458,
+ 1458, 1458, 1458, 1458, 1723, 1724, 1458, 1458,
+
+ 1458, 1458, 1458, 1458, 1723, 1724, 1458, 1458,
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1458,
+ 1458, 1458, 1458, 1458, 1742, 1742, 1742, 1458,
+ 1458, 1723, 1724, 1723, 1724, 1723, 1724, 1723,
+
+ 1724, 1723, 1724, 1723, 1724, 1723, 1724, 1723,
+ 1724, 1723, 1724, 1723, 1724, 1723, 1724, 1723,
+ 1724, 1723, 1724, 1723, 1724, 1723, 1724, 1723,
+ 1724, 1723, 1724, 1723, 1724, 1723, 1724, 1723,
+
+ 1724, 1723, 1724, 1458, 1458, 1458, 1723, 1724,
+ 1723, 1724, 1723, 1724, 1723, 1724, 1458, 1723,
+ 1724, 1723, 1724, 1723, 1724, 1723, 1724, 1723,
+ 1724, 1723, 1724, 1723, 1724, 1723, 1724, 1723,
+
+ 1724, 1723, 1724, 1723, 1724, 1723, 1724, 1723,
+ 1724, 1723, 1724, 1723, 1724, 1723, 1724, 1723,
+ 1724, 1723, 1724, 1723, 1724, 1723, 1724, 1458,
+ 1458, 1458, 1458, 1458, 1743, 1458, 1744, 1458,
+
+ 1458, 1458, 1458, 1745, 1746, 1745, 1458, 1458,
+ 1458, 1458, 1458, 1458, 1723, 1724, 1747, 1458,
+ 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1723,
+ 1724, 1723, 1724, 1458, 1458, 1458, 1458, 1458,
+
+ 1606, 1606, 1606, 1606, 1606, 1605, 1605, 1605,
+ 1606, 1606, 1606, 1606, 1606, 1606, 1541, 1541,
+ 1541, 1541, 1541, 1541, 1542, 1542, 1542, 1542,
+ 1542, 1542, 1542, 1748, 1748, 1749, 1749, 1749,
+
+ 1542, 1542, 1542, 1542, 1749, 1749, 1749, 1749,
+ 1749, 1749, 1749, 1749, 1749, 1749, 1749, 1749,
+ 1720, 1720, 1720, 1720, 1720, 1720, 1720, 1720,
+ 1720, 1720, 1720, 1720, 1720, 1720, 1720, 1720,
+
+ 1720, 1720, 1720, 1720, 1720, 1749, 1749, 1720,
+ 1720, 1720, 1720, 1720, 1720, 1613, 1613, 1613,
+ 1748, 1749, 1749, 1749, 1749, 1685, 1750, 1750,
+ 1750, 1750, 1613, 1613, 1613, 1613, 1613, 1613,
+
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 221, 221, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 221, 1751,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1752, 1752, 1752, 1613, 1613, 1613,
+
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1753, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1616, 1752, 1752, 1752, 1752, 1752,
+ 1752, 1752, 1752, 1752, 1752, 1752, 1752, 1752,
+
+ 1752, 1752, 1752, 1752, 1752, 1752, 1752, 1752,
+ 1752, 1752, 1752, 1752, 1555, 1555, 1555, 1555,
+ 1752, 1752, 1752, 1752, 1752, 1752, 1752, 1752,
+ 1752, 1752, 1752, 1752, 1752, 1752, 1754, 1753,
+
+ 1755, 1755, 1755, 1755, 1755, 1755, 1755, 1755,
+ 1755, 1755, 1755, 1755, 1755, 1755, 1755, 1755,
+ 1755, 1755, 1755, 1755, 1755, 1755, 1755, 1755,
+ 1755, 1755, 1755, 1755, 1755, 1755, 1755, 1755,
+
+ 1755, 1755, 1755, 1755, 1755, 1755, 1755, 1755,
+ 1755, 1755, 1755, 1755, 1755, 1755, 1755, 1756,
+ 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757,
+ 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757,
+
+ 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757,
+ 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757,
+ 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757,
+ 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1758,
+
+ 142, 138, 1759, 1760, 1761, 1762, 1763, 142,
+ 138, 142, 138, 142, 138, 1764, 1765, 1766,
+ 1767, 1290, 1292, 1293, 1768, 142, 138, 1768,
+ 1290, 1290, 1290, 1290, 1769, 1769, 1770, 1771,
+
+ 1772, 1773, 1772, 1773, 1772, 1773, 1772, 1773,
+ 1772, 1773, 1772, 1773, 1772, 1773, 1772, 1773,
+ 1772, 1773, 1772, 1773, 1772, 1773, 1772, 1773,
+ 1772, 1773, 1772, 1773, 1772, 1773, 1772, 1773,
+
+ 1772, 1773, 1772, 1773, 1774, 1775, 1775, 1775,
+ 1775, 1775, 1775, 1776, 1777, 1776, 1777, 1778,
+ 1778, 1778, 1779, 1780, 221, 221, 221, 221,
+ 221, 1781, 1782, 1782, 1782, 1783, 1781, 1782,
+
+ 1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784,
+ 1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784,
+ 1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784,
+ 1784, 1784, 1784, 1784, 1784, 1784, 1784, 1784,
+
+ 1784, 1784, 1784, 1784, 1784, 1784, 221, 1785,
+ 221, 221, 221, 221, 221, 1785, 221, 221,
+ 1786, 1786, 1786, 1786, 1786, 1786, 1786, 1786,
+ 1786, 1786, 1786, 1786, 1786, 1786, 1786, 1786,
+
+ 1786, 1786, 1786, 1786, 1786, 1786, 1786, 1786,
+ 1786, 1786, 1786, 1786, 1786, 1786, 1786, 1786,
+ 1786, 1786, 1786, 1786, 1786, 1786, 1786, 1786,
+ 1786, 1786, 1786, 1786, 1786, 1786, 1786, 1786,
+
+ 1786, 1786, 1786, 1786, 1786, 1786, 1787, 1787,
+ 221, 221, 221, 221, 221, 221, 221, 1788,
+ 1789, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 1790,
913, 913, 913, 913, 913, 913, 913, 913,
913, 913, 913, 913, 913, 913, 913, 913,
@@ -2456,35 +2456,25 @@ static constexpr unsigned short uc_property_trie[] = {
289, 289, 289, 289, 289, 289, 289, 289,
289, 289, 289, 289, 289, 289, 289, 289,
- 1790, 1790, 1791, 1792, 1791, 1792, 1790, 1790,
- 1790, 1791, 1792, 1790, 1791, 1792, 1461, 1461,
- 1461, 1461, 1461, 1461, 1461, 1461, 1460, 1793,
- 1794, 1795, 1796, 1797, 1791, 1792, 1797, 1797,
-
- 1798, 1799, 1729, 1730, 1729, 1730, 1729, 1730,
- 1729, 1730, 1795, 1795, 1795, 1795, 1800, 1801,
- 1795, 1802, 1803, 1804, 1804, 1803, 1803, 1803,
- 1803, 1803, 1805, 1805, 1806, 1807, 1807, 1808,
+ 1791, 1791, 1792, 1793, 1792, 1793, 1791, 1791,
+ 1791, 1792, 1793, 1791, 1792, 1793, 1462, 1462,
+ 1462, 1462, 1462, 1462, 1462, 1462, 1461, 1794,
+ 1795, 1796, 1797, 1798, 1792, 1793, 1798, 1798,
- 1809, 1807, 1810, 1811, 1811, 1812, 1812, 1812,
- 1812, 1812, 1813, 1814, 1813, 1814, 1813, 1815,
- 1750, 1750, 1816, 1817, 1817, 1818, 1819, 1818,
- 1819, 1818, 1819, 1818, 1819, 1820, 221, 221,
+ 1799, 1800, 1730, 1731, 1730, 1731, 1730, 1731,
+ 1730, 1731, 1796, 1796, 1796, 1796, 1801, 1802,
+ 1796, 1803, 1804, 1805, 1805, 1804, 1804, 1804,
+ 1804, 1804, 1806, 1806, 1807, 1808, 1808, 1809,
- 1821, 1821, 1821, 1821, 1821, 1821, 1821, 1821,
- 1821, 1821, 1821, 1821, 1821, 1821, 1821, 1821,
- 1821, 1821, 1821, 1821, 1821, 1821, 1821, 1821,
- 1821, 1821, 221, 1821, 1821, 1821, 1821, 1822,
+ 1810, 1808, 1811, 1812, 1812, 1813, 1813, 1813,
+ 1813, 1813, 1814, 1815, 1814, 1815, 1814, 1816,
+ 1751, 1751, 1817, 1818, 1818, 1819, 1820, 1819,
+ 1820, 1819, 1820, 1819, 1820, 1821, 221, 221,
- 1821, 1821, 1821, 1821, 1821, 1821, 1821, 1821,
- 1821, 1821, 1821, 1821, 1821, 1821, 1821, 1821,
- 1821, 1821, 1821, 1821, 1821, 1821, 1821, 1821,
- 1821, 1821, 1821, 1821, 1821, 1821, 1821, 1821,
-
- 1821, 1821, 1821, 1821, 1821, 1821, 1821, 1821,
- 1821, 1821, 1821, 1821, 1821, 1821, 1821, 1821,
- 1821, 1821, 1821, 1822, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
+ 1822, 1822, 1822, 1822, 1822, 1822, 1822, 1822,
+ 1822, 1822, 1822, 1822, 1822, 1822, 1822, 1822,
+ 1822, 1822, 1822, 1822, 1822, 1822, 1822, 1822,
+ 1822, 1822, 221, 1822, 1822, 1822, 1822, 1823,
1822, 1822, 1822, 1822, 1822, 1822, 1822, 1822,
1822, 1822, 1822, 1822, 1822, 1822, 1822, 1822,
@@ -2493,163 +2483,143 @@ static constexpr unsigned short uc_property_trie[] = {
1822, 1822, 1822, 1822, 1822, 1822, 1822, 1822,
1822, 1822, 1822, 1822, 1822, 1822, 1822, 1822,
- 1822, 1822, 1822, 1822, 1822, 1822, 221, 221,
+ 1822, 1822, 1822, 1823, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+
+ 1823, 1823, 1823, 1823, 1823, 1823, 1823, 1823,
+ 1823, 1823, 1823, 1823, 1823, 1823, 1823, 1823,
+ 1823, 1823, 1823, 1823, 1823, 1823, 1823, 1823,
+ 1823, 1823, 1823, 1823, 1823, 1823, 1823, 1823,
+
+ 1823, 1823, 1823, 1823, 1823, 1823, 1823, 1823,
+ 1823, 1823, 1823, 1823, 1823, 1823, 1823, 1823,
+ 1823, 1823, 1823, 1823, 1823, 1823, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 1823, 1823, 1823, 1823, 1823, 1823, 1823, 1823,
- 1823, 1823, 1823, 1823, 221, 221, 221, 221,
-
- 1824, 1825, 1826, 1827, 1828, 1829, 1830, 1831,
- 1832, 1833, 1832, 1833, 1832, 1833, 1832, 1833,
- 1832, 1833, 1828, 1828, 1832, 1833, 1832, 1833,
- 1832, 1833, 1832, 1833, 1834, 1835, 1836, 1836,
-
- 1828, 1831, 1831, 1831, 1831, 1831, 1831, 1831,
- 1831, 1831, 1837, 1838, 1839, 1840, 1841, 1841,
- 1842, 1843, 1843, 1843, 1843, 1844, 1845, 1828,
- 1846, 1846, 1846, 1847, 1848, 1849, 1850, 1851,
-
- 221, 1852, 1853, 1852, 1853, 1852, 1853, 1852,
- 1853, 1852, 1853, 1853, 1854, 1853, 1854, 1853,
- 1854, 1853, 1854, 1853, 1854, 1853, 1854, 1853,
- 1854, 1853, 1854, 1853, 1854, 1853, 1854, 1853,
-
- 1854, 1853, 1854, 1852, 1853, 1854, 1853, 1854,
- 1853, 1854, 1853, 1853, 1853, 1853, 1853, 1853,
- 1854, 1854, 1853, 1854, 1854, 1853, 1854, 1854,
- 1853, 1854, 1854, 1853, 1854, 1854, 1853, 1853,
-
- 1853, 1853, 1853, 1852, 1853, 1852, 1853, 1852,
- 1853, 1853, 1853, 1853, 1853, 1853, 1852, 1853,
- 1853, 1853, 1853, 1853, 1854, 1855, 1855, 221,
- 221, 1856, 1856, 1857, 1857, 1858, 1859, 1860,
-
- 1861, 1862, 1863, 1862, 1863, 1862, 1863, 1862,
- 1863, 1862, 1863, 1863, 1864, 1863, 1864, 1863,
- 1864, 1863, 1864, 1863, 1864, 1863, 1864, 1863,
- 1864, 1863, 1864, 1863, 1864, 1863, 1864, 1863,
-
- 1864, 1863, 1864, 1862, 1863, 1864, 1863, 1864,
- 1863, 1864, 1863, 1863, 1863, 1863, 1863, 1863,
- 1864, 1864, 1863, 1864, 1864, 1863, 1864, 1864,
- 1863, 1864, 1864, 1863, 1864, 1864, 1863, 1863,
-
- 1863, 1863, 1863, 1862, 1863, 1862, 1863, 1862,
- 1863, 1863, 1863, 1863, 1863, 1863, 1862, 1863,
- 1863, 1863, 1863, 1863, 1864, 1862, 1862, 1864,
- 1864, 1864, 1864, 1865, 1866, 1867, 1868, 1869,
-
- 221, 221, 221, 221, 221, 1870, 1870, 1870,
- 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870,
- 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870,
- 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870,
-
- 1870, 1870, 1870, 1870, 1870, 1870, 1870, 1870,
- 1870, 1870, 1870, 1870, 1870, 1871, 1872, 1873,
- 221, 1874, 1874, 1874, 1874, 1874, 1874, 1874,
- 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874,
-
- 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874,
- 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874,
- 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874,
- 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874,
-
- 1874, 1874, 1874, 1874, 1875, 1874, 1874, 1874,
- 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874,
- 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874,
- 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874,
-
- 1874, 1874, 1874, 1874, 1874, 1874, 1874, 1874,
- 1874, 1874, 1874, 1874, 1874, 1874, 1874, 221,
- 1876, 1876, 1877, 1877, 1877, 1877, 1878, 1878,
- 1878, 1878, 1878, 1878, 1878, 1878, 1878, 1878,
+ 1824, 1824, 1824, 1824, 1824, 1824, 1824, 1824,
+ 1824, 1824, 1824, 1824, 1825, 1825, 1825, 1825,
- 1879, 1879, 1879, 1879, 1879, 1879, 1879, 1879,
- 1879, 1879, 1879, 1879, 1879, 1879, 1879, 1879,
- 1879, 1879, 1879, 1879, 1879, 1879, 1879, 1879,
- 1880, 1880, 1880, 1881, 1881, 1881, 1881, 1881,
+ 1826, 1827, 1828, 1829, 1830, 1831, 1832, 1833,
+ 1834, 1835, 1834, 1835, 1834, 1835, 1834, 1835,
+ 1834, 1835, 1830, 1830, 1834, 1835, 1834, 1835,
+ 1834, 1835, 1834, 1835, 1836, 1837, 1838, 1838,
- 1882, 1882, 1882, 1882, 1882, 1882, 1882, 1882,
- 1882, 1882, 1882, 1882, 1882, 1882, 1882, 1882,
- 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883,
- 1883, 1883, 1883, 1883, 1883, 1883, 1883, 1883,
+ 1830, 1833, 1833, 1833, 1833, 1833, 1833, 1833,
+ 1833, 1833, 1839, 1840, 1841, 1842, 1843, 1843,
+ 1844, 1845, 1845, 1845, 1845, 1846, 1847, 1830,
+ 1848, 1848, 1848, 1849, 1850, 1851, 1852, 1853,
+
+ 221, 1854, 1855, 1854, 1855, 1854, 1855, 1854,
+ 1855, 1854, 1855, 1855, 1856, 1855, 1856, 1855,
+ 1856, 1855, 1856, 1855, 1856, 1855, 1856, 1855,
+ 1856, 1855, 1856, 1855, 1856, 1855, 1856, 1855,
+
+ 1856, 1855, 1856, 1854, 1855, 1856, 1855, 1856,
+ 1855, 1856, 1855, 1855, 1855, 1855, 1855, 1855,
+ 1856, 1856, 1855, 1856, 1856, 1855, 1856, 1856,
+ 1855, 1856, 1856, 1855, 1856, 1856, 1855, 1855,
+
+ 1855, 1855, 1855, 1854, 1855, 1854, 1855, 1854,
+ 1855, 1855, 1855, 1855, 1855, 1855, 1854, 1855,
+ 1855, 1855, 1855, 1855, 1856, 1857, 1857, 221,
+ 221, 1858, 1858, 1859, 1859, 1860, 1861, 1862,
+
+ 1863, 1864, 1865, 1864, 1865, 1864, 1865, 1864,
+ 1865, 1864, 1865, 1865, 1866, 1865, 1866, 1865,
+ 1866, 1865, 1866, 1865, 1866, 1865, 1866, 1865,
+ 1866, 1865, 1866, 1865, 1866, 1865, 1866, 1865,
+
+ 1866, 1865, 1866, 1864, 1865, 1866, 1865, 1866,
+ 1865, 1866, 1865, 1865, 1865, 1865, 1865, 1865,
+ 1866, 1866, 1865, 1866, 1866, 1865, 1866, 1866,
+ 1865, 1866, 1866, 1865, 1866, 1866, 1865, 1865,
+
+ 1865, 1865, 1865, 1864, 1865, 1864, 1865, 1864,
+ 1865, 1865, 1865, 1865, 1865, 1865, 1864, 1865,
+ 1865, 1865, 1865, 1865, 1866, 1864, 1864, 1866,
+ 1866, 1866, 1866, 1867, 1868, 1869, 1870, 1871,
+
+ 221, 221, 221, 221, 221, 1872, 1872, 1872,
+ 1872, 1872, 1872, 1872, 1872, 1872, 1872, 1872,
+ 1872, 1872, 1872, 1872, 1872, 1872, 1872, 1872,
+ 1872, 1872, 1872, 1872, 1872, 1872, 1872, 1872,
+
+ 1872, 1872, 1872, 1872, 1872, 1872, 1872, 1872,
+ 1872, 1872, 1872, 1872, 1872, 1873, 1874, 1875,
+ 221, 1876, 1876, 1876, 1876, 1876, 1876, 1876,
+ 1876, 1876, 1876, 1876, 1876, 1876, 1876, 1876,
+
+ 1876, 1876, 1876, 1876, 1876, 1876, 1876, 1876,
+ 1876, 1876, 1876, 1876, 1876, 1876, 1876, 1876,
+ 1876, 1876, 1876, 1876, 1876, 1876, 1876, 1876,
+ 1876, 1876, 1876, 1876, 1876, 1876, 1876, 1876,
+
+ 1876, 1876, 1876, 1876, 1877, 1876, 1876, 1876,
+ 1876, 1876, 1876, 1876, 1876, 1876, 1876, 1876,
+ 1876, 1876, 1876, 1876, 1876, 1876, 1876, 1876,
+ 1876, 1876, 1876, 1876, 1876, 1876, 1876, 1876,
+
+ 1876, 1876, 1876, 1876, 1876, 1876, 1876, 1876,
+ 1876, 1876, 1876, 1876, 1876, 1876, 1876, 221,
+ 1878, 1878, 1879, 1879, 1879, 1879, 1880, 1880,
+ 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1880,
+
+ 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881,
+ 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881,
+ 1881, 1881, 1881, 1881, 1881, 1881, 1881, 1881,
+ 1882, 1882, 1882, 1883, 1883, 1883, 1883, 1883,
- 1883, 1883, 1883, 1883, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
1884, 1884, 1884, 1884, 1884, 1884, 1884, 1884,
1884, 1884, 1884, 1884, 1884, 1884, 1884, 1884,
-
- 1885, 1885, 1885, 1885, 1885, 1885, 1885, 1885,
1885, 1885, 1885, 1885, 1885, 1885, 1885, 1885,
1885, 1885, 1885, 1885, 1885, 1885, 1885, 1885,
- 1885, 1885, 1885, 1885, 1885, 1886, 1886, 221,
+ 1885, 1885, 1885, 1885, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 1825,
+ 1886, 1886, 1886, 1886, 1886, 1886, 1886, 1886,
+ 1886, 1886, 1886, 1886, 1886, 1886, 1886, 1886,
+
+ 1887, 1887, 1887, 1887, 1887, 1887, 1887, 1887,
+ 1887, 1887, 1887, 1887, 1887, 1887, 1887, 1887,
1887, 1887, 1887, 1887, 1887, 1887, 1887, 1887,
- 1887, 1887, 1888, 1888, 1888, 1888, 1888, 1888,
- 1888, 1888, 1888, 1888, 1888, 1888, 1888, 1888,
- 1888, 1888, 1888, 1888, 1888, 1888, 1888, 1888,
+ 1887, 1887, 1887, 1887, 1887, 1888, 1888, 221,
- 1888, 1888, 1888, 1888, 1889, 1889, 1889, 1889,
+ 1889, 1889, 1889, 1889, 1889, 1889, 1889, 1889,
+ 1889, 1889, 1890, 1890, 1890, 1890, 1890, 1890,
+ 1890, 1890, 1890, 1890, 1890, 1890, 1890, 1890,
1890, 1890, 1890, 1890, 1890, 1890, 1890, 1890,
- 1891, 1892, 1892, 1892, 1892, 1892, 1892, 1892,
+
+ 1890, 1890, 1890, 1890, 1891, 1891, 1891, 1891,
1892, 1892, 1892, 1892, 1892, 1892, 1892, 1892,
+ 1893, 1894, 1894, 1894, 1894, 1894, 1894, 1894,
+ 1894, 1894, 1894, 1894, 1894, 1894, 1894, 1894,
- 1893, 1893, 1893, 1893, 1893, 1893, 1893, 1893,
- 1893, 1893, 1893, 1893, 1893, 1893, 1893, 1893,
- 1893, 1893, 1893, 1893, 1893, 1893, 1893, 1893,
- 1893, 1893, 1893, 1893, 1894, 1894, 1895, 1876,
+ 1895, 1895, 1895, 1895, 1895, 1895, 1895, 1895,
+ 1895, 1895, 1895, 1895, 1895, 1895, 1895, 1895,
+ 1895, 1895, 1895, 1895, 1895, 1895, 1895, 1895,
+ 1895, 1895, 1895, 1895, 1896, 1896, 1897, 1878,
- 1877, 1877, 1877, 1877, 1877, 1877, 1877, 1877,
- 1877, 1877, 1878, 1878, 1878, 1878, 1878, 1878,
- 1878, 1878, 1878, 1878, 1878, 1878, 1878, 1896,
- 1878, 1896, 1878, 1878, 1878, 1878, 1878, 1878,
+ 1879, 1879, 1879, 1879, 1879, 1879, 1879, 1879,
+ 1879, 1879, 1880, 1880, 1880, 1880, 1880, 1880,
+ 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1898,
+ 1880, 1898, 1880, 1880, 1880, 1880, 1880, 1880,
- 1878, 1878, 1878, 1878, 1878, 1878, 1878, 1878,
- 1878, 1878, 1878, 1878, 1878, 1878, 1878, 1878,
- 1878, 1892, 1892, 1892, 1892, 1892, 1892, 1892,
- 1892, 1892, 1892, 1892, 1892, 1892, 1892, 1892,
+ 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1880,
+ 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1880,
+ 1880, 1894, 1894, 1894, 1894, 1894, 1894, 1894,
+ 1894, 1894, 1894, 1894, 1894, 1894, 1894, 1894,
- 1878, 1878, 1878, 1878, 1878, 1878, 1878, 1878,
- 1878, 1878, 1878, 1878, 1891, 1891, 1891, 1891,
- 1897, 1897, 1897, 1897, 1897, 1897, 1897, 1897,
- 1897, 1897, 1897, 1897, 1897, 1897, 1897, 1897,
-
- 1897, 1897, 1897, 1897, 1897, 1897, 1897, 1897,
- 1897, 1897, 1897, 1897, 1897, 1897, 1897, 1897,
- 1897, 1897, 1897, 1897, 1897, 1897, 1897, 1897,
- 1897, 1897, 1897, 1897, 1897, 1897, 1897, 1898,
-
- 1897, 1897, 1897, 1897, 1897, 1897, 1897, 1897,
- 1897, 1897, 1897, 1897, 1897, 1897, 1897, 1897,
- 1897, 1897, 1897, 1897, 1897, 1897, 1897, 1897,
- 1897, 1897, 1897, 1897, 1897, 1897, 1897, 1897,
-
- 1897, 1897, 1897, 1897, 1897, 1897, 1897, 1897,
- 1897, 1897, 1897, 1897, 1897, 1897, 1897, 1897,
- 1897, 1897, 1897, 1897, 1897, 1897, 1897, 1897,
- 1878, 1878, 1878, 1878, 1878, 1878, 1878, 1878,
-
- 1878, 1878, 1878, 1878, 1878, 1878, 1878, 1878,
- 1878, 1878, 1878, 1878, 1878, 1878, 1878, 1878,
- 1878, 1878, 1878, 1878, 1878, 1878, 1878, 1891,
- 1891, 1891, 1891, 1878, 1878, 1878, 1878, 1878,
-
- 1878, 1878, 1878, 1878, 1878, 1878, 1878, 1878,
- 1878, 1878, 1878, 1878, 1878, 1878, 1878, 1878,
- 1878, 1878, 1878, 1878, 1878, 1878, 1878, 1878,
- 1878, 1878, 1878, 1878, 1878, 1878, 1878, 1878,
-
- 1878, 1878, 1888, 1878, 1878, 1878, 1878, 1888,
- 1878, 1878, 1878, 1878, 1878, 1878, 1878, 1878,
- 1878, 1878, 1878, 1878, 1878, 1878, 1878, 1878,
- 1888, 1878, 1878, 1878, 1878, 1878, 1891, 1891,
-
- 1878, 1878, 1878, 1878, 1878, 1878, 1878, 1878,
- 1878, 1878, 1878, 1878, 1878, 1878, 1878, 1878,
- 1878, 1878, 1878, 1878, 1878, 1878, 1878, 1878,
- 1878, 1878, 1878, 1878, 1878, 1878, 1878, 1891,
+ 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1880,
+ 1880, 1880, 1880, 1880, 1893, 1893, 1893, 1893,
+ 1899, 1899, 1899, 1899, 1899, 1899, 1899, 1899,
+ 1899, 1899, 1899, 1899, 1899, 1899, 1899, 1899,
+
+ 1899, 1899, 1899, 1899, 1899, 1899, 1899, 1899,
+ 1899, 1899, 1899, 1899, 1899, 1899, 1899, 1899,
+ 1899, 1899, 1899, 1899, 1899, 1899, 1899, 1899,
+ 1899, 1899, 1899, 1899, 1899, 1899, 1899, 1900,
1899, 1899, 1899, 1899, 1899, 1899, 1899, 1899,
1899, 1899, 1899, 1899, 1899, 1899, 1899, 1899,
@@ -2658,76 +2628,106 @@ static constexpr unsigned short uc_property_trie[] = {
1899, 1899, 1899, 1899, 1899, 1899, 1899, 1899,
1899, 1899, 1899, 1899, 1899, 1899, 1899, 1899,
- 1899, 1899, 1899, 1899, 1899, 1899, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
+ 1899, 1899, 1899, 1899, 1899, 1899, 1899, 1899,
+ 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1880,
+
+ 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1880,
+ 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1880,
+ 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1893,
+ 1893, 1893, 1893, 1880, 1880, 1880, 1880, 1880,
+
+ 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1880,
+ 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1880,
+ 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1880,
+ 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1880,
- 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
- 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
- 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
- 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
+ 1880, 1880, 1890, 1880, 1880, 1880, 1880, 1890,
+ 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1880,
+ 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1880,
+ 1890, 1880, 1880, 1880, 1880, 1880, 1893, 1893,
+
+ 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1880,
+ 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1880,
+ 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1880,
+ 1880, 1880, 1880, 1880, 1880, 1880, 1880, 1893,
1901, 1901, 1901, 1901, 1901, 1901, 1901, 1901,
1901, 1901, 1901, 1901, 1901, 1901, 1901, 1901,
1901, 1901, 1901, 1901, 1901, 1901, 1901, 1901,
1901, 1901, 1901, 1901, 1901, 1901, 1901, 1901,
+ 1901, 1901, 1901, 1901, 1901, 1901, 1901, 1901,
+ 1901, 1901, 1901, 1901, 1901, 1901, 1901, 1901,
1901, 1901, 1901, 1901, 1901, 1901, 1902, 1902,
1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+
+ 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606,
+ 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606,
+ 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606,
+ 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606,
+
+ 1903, 1903, 1903, 1903, 1903, 1903, 1903, 1903,
+ 1903, 1903, 1903, 1903, 1903, 1903, 1903, 1903,
+ 1903, 1903, 1903, 1903, 1903, 1903, 1903, 1903,
+ 1903, 1903, 1903, 1903, 1903, 1903, 1903, 1903,
+
+ 1903, 1903, 1903, 1903, 1903, 1903, 1904, 1904,
+ 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
+ 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
+ 1904, 1904, 1904, 1904, 1905, 1905, 1905, 1905,
+
+ 1905, 1905, 1905, 1905, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1907, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1910, 1910, 1910, 1910, 1910,
1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
- 1902, 1902, 1902, 1902, 1903, 1903, 1903, 1903,
-
- 1903, 1903, 1903, 1903, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1905, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
-
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1908, 1908, 1908, 1908, 1908,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1909, 1909, 1909,
-
- 1910, 1910, 1910, 1910, 1910, 1910, 1910, 1910,
- 1910, 1910, 1910, 1910, 1910, 1910, 1910, 1910,
- 1910, 1910, 1910, 1910, 1910, 1911, 1910, 1910,
- 1910, 1910, 1910, 1910, 1910, 1910, 1910, 1910,
-
- 1910, 1910, 1910, 1910, 1910, 1910, 1910, 1910,
- 1910, 1910, 1910, 1910, 1910, 1910, 1910, 1910,
- 1910, 1910, 1910, 1910, 1910, 1910, 1910, 1910,
- 1910, 1910, 1910, 1910, 1910, 1910, 1910, 1910,
-
- 1910, 1910, 1910, 1910, 1910, 1910, 1910, 1910,
- 1910, 1910, 1910, 1910, 1910, 221, 221, 221,
+ 1902, 1902, 1902, 1902, 1902, 1911, 1911, 1911,
+
+ 1912, 1912, 1912, 1912, 1912, 1912, 1912, 1912,
1912, 1912, 1912, 1912, 1912, 1912, 1912, 1912,
+ 1912, 1912, 1912, 1912, 1912, 1913, 1912, 1912,
1912, 1912, 1912, 1912, 1912, 1912, 1912, 1912,
- 1912, 1912, 1913, 1913, 1912, 1912, 1912, 1912,
1912, 1912, 1912, 1912, 1912, 1912, 1912, 1912,
- 1912, 1912, 1912, 1912, 1913, 1912, 1912, 1912,
+ 1912, 1912, 1912, 1912, 1912, 1912, 1912, 1912,
+ 1912, 1912, 1912, 1912, 1912, 1912, 1912, 1912,
1912, 1912, 1912, 1912, 1912, 1912, 1912, 1912,
- 1912, 1913, 1912, 1912, 1912, 1913, 1912, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
+ 1912, 1912, 1912, 1912, 1912, 1912, 1912, 1912,
+ 1912, 1912, 1912, 1912, 1912, 221, 221, 221,
1914, 1914, 1914, 1914, 1914, 1914, 1914, 1914,
1914, 1914, 1914, 1914, 1914, 1914, 1914, 1914,
+ 1914, 1914, 1915, 1915, 1914, 1914, 1914, 1914,
1914, 1914, 1914, 1914, 1914, 1914, 1914, 1914,
+ 1914, 1914, 1914, 1914, 1915, 1914, 1914, 1914,
1914, 1914, 1914, 1914, 1914, 1914, 1914, 1914,
- 1914, 1914, 1914, 1914, 1914, 1914, 1914, 1914,
- 1915, 1915, 1915, 1915, 1915, 1915, 1916, 1917,
- 1918, 1918, 1918, 1918, 1918, 1918, 1918, 1918,
- 1918, 1918, 1918, 1918, 1918, 1918, 1918, 1918,
- 1918, 1918, 1918, 1918, 1918, 1918, 1918, 1918,
- 1918, 1918, 1918, 1918, 1918, 1918, 1918, 1918,
+ 1914, 1915, 1914, 1914, 1914, 1915, 1914, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 1916, 1916, 1916, 1916, 1916, 1916, 1916, 1916,
+ 1916, 1916, 1916, 1916, 1916, 1916, 1916, 1916,
+
+ 1916, 1916, 1916, 1916, 1916, 1916, 1916, 1916,
+ 1916, 1916, 1916, 1916, 1916, 1916, 1916, 1916,
+ 1916, 1916, 1916, 1916, 1916, 1916, 1916, 1916,
+ 1917, 1917, 1917, 1917, 1917, 1917, 1918, 1919,
- 1918, 1918, 1918, 1918, 1918, 1918, 1918, 1918,
- 1918, 1918, 1918, 1918, 1919, 1920, 1921, 1922,
- 1918, 1918, 1918, 1918, 1918, 1918, 1918, 1918,
- 1918, 1918, 1918, 1918, 1918, 1918, 1918, 1918,
+ 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920,
+ 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920,
+ 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920,
+ 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920,
- 1923, 1924, 1925, 1926, 1927, 1928, 1929, 1930,
- 1931, 1932, 1918, 1918, 221, 221, 221, 221,
+ 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920,
+ 1920, 1920, 1920, 1920, 1921, 1922, 1923, 1924,
+ 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920,
+ 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920,
+
+ 1925, 1926, 1927, 1928, 1929, 1930, 1931, 1932,
+ 1933, 1934, 1920, 1920, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -2737,261 +2737,261 @@ static constexpr unsigned short uc_property_trie[] = {
303, 304, 303, 304, 303, 304, 303, 304,
307, 308, 303, 304, 303, 304, 303, 304,
- 303, 304, 303, 304, 303, 304, 1933, 289,
- 1934, 1934, 1934, 1935, 1936, 1936, 1936, 1936,
- 1936, 1936, 1936, 1936, 289, 289, 1935, 1937,
+ 303, 304, 303, 304, 303, 304, 1935, 289,
+ 1936, 1936, 1936, 1937, 1938, 1938, 1938, 1938,
+ 1938, 1938, 1938, 1938, 289, 289, 1937, 1939,
303, 304, 303, 304, 303, 304, 303, 304,
303, 304, 303, 304, 303, 304, 303, 304,
303, 304, 303, 304, 303, 304, 303, 304,
- 309, 310, 309, 310, 1938, 1938, 1939, 1936,
+ 309, 310, 309, 310, 1940, 1940, 1941, 1938,
- 1940, 1940, 1940, 1940, 1940, 1940, 1940, 1940,
- 1940, 1940, 1940, 1940, 1940, 1940, 1940, 1940,
- 1940, 1940, 1940, 1940, 1940, 1940, 1940, 1940,
- 1940, 1940, 1940, 1940, 1940, 1940, 1940, 1940,
+ 1942, 1942, 1942, 1942, 1942, 1942, 1942, 1942,
+ 1942, 1942, 1942, 1942, 1942, 1942, 1942, 1942,
+ 1942, 1942, 1942, 1942, 1942, 1942, 1942, 1942,
+ 1942, 1942, 1942, 1942, 1942, 1942, 1942, 1942,
- 1940, 1940, 1940, 1940, 1940, 1940, 1941, 1941,
- 1941, 1941, 1941, 1941, 1941, 1941, 1941, 1941,
- 1942, 1942, 1943, 1944, 1945, 1945, 1945, 1944,
+ 1942, 1942, 1942, 1942, 1942, 1942, 1943, 1943,
+ 1943, 1943, 1943, 1943, 1943, 1943, 1943, 1943,
+ 1944, 1944, 1945, 1946, 1947, 1947, 1947, 1946,
221, 221, 221, 221, 221, 221, 221, 221,
- 1946, 1946, 1946, 1946, 1946, 1946, 1946, 1946,
- 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1947,
- 1947, 1947, 1947, 1947, 1947, 1947, 1947, 1948,
- 1948, 1948, 1948, 1801, 1801, 1801, 1801, 1801,
+ 1948, 1948, 1948, 1948, 1948, 1948, 1948, 1948,
+ 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1949,
+ 1949, 1949, 1949, 1949, 1949, 1949, 1949, 1950,
+ 1950, 1950, 1950, 1802, 1802, 1802, 1802, 1802,
- 1949, 1949, 1291, 1292, 1291, 1292, 1291, 1292,
- 1291, 1292, 1291, 1292, 1291, 1292, 1291, 1292,
- 1289, 1289, 1291, 1292, 1291, 1292, 1291, 1292,
- 1291, 1292, 1291, 1292, 1291, 1292, 1291, 1292,
+ 1951, 1951, 1292, 1293, 1292, 1293, 1292, 1293,
+ 1292, 1293, 1292, 1293, 1292, 1293, 1292, 1293,
+ 1290, 1290, 1292, 1293, 1292, 1293, 1292, 1293,
+ 1292, 1293, 1292, 1293, 1292, 1293, 1292, 1293,
- 1291, 1292, 1291, 1292, 1291, 1292, 1291, 1292,
- 1291, 1292, 1291, 1292, 1291, 1292, 1291, 1292,
- 1291, 1292, 1291, 1292, 1291, 1292, 1291, 1292,
- 1291, 1292, 1291, 1292, 1291, 1292, 1291, 1292,
+ 1292, 1293, 1292, 1293, 1292, 1293, 1292, 1293,
+ 1292, 1293, 1292, 1293, 1292, 1293, 1292, 1293,
+ 1292, 1293, 1292, 1293, 1292, 1293, 1292, 1293,
+ 1292, 1293, 1292, 1293, 1292, 1293, 1292, 1293,
- 1291, 1292, 1291, 1292, 1291, 1292, 1291, 1292,
- 1291, 1292, 1291, 1292, 1291, 1292, 1291, 1292,
- 1768, 1289, 1289, 1289, 1289, 1289, 1289, 1289,
- 1289, 1291, 1292, 1291, 1292, 1950, 1291, 1292,
+ 1292, 1293, 1292, 1293, 1292, 1293, 1292, 1293,
+ 1292, 1293, 1292, 1293, 1292, 1293, 1292, 1293,
+ 1769, 1290, 1290, 1290, 1290, 1290, 1290, 1290,
+ 1290, 1292, 1293, 1292, 1293, 1952, 1292, 1293,
- 1291, 1292, 1291, 1292, 1291, 1292, 1291, 1292,
- 1801, 1951, 1951, 1291, 1292, 1952, 1953, 1954,
- 1955, 1956, 1957, 1958, 1959, 1960, 1961, 1962,
- 1961, 1962, 1961, 1962, 1961, 1962, 1961, 1962,
+ 1292, 1293, 1292, 1293, 1292, 1293, 1292, 1293,
+ 1802, 1953, 1953, 1292, 1293, 1954, 1955, 1956,
+ 1957, 1958, 1959, 1960, 1961, 1962, 1963, 1964,
+ 1963, 1964, 1963, 1964, 1963, 1964, 1963, 1964,
- 1955, 1956, 1955, 1956, 1955, 1956, 1955, 1956,
- 1955, 1956, 1963, 1964, 1965, 1966, 1967, 1968,
- 1969, 1970, 1971, 1972, 1973, 1974, 1973, 1974,
- 1975, 1976, 1977, 1978, 1977, 1978, 1977, 1978,
+ 1957, 1958, 1957, 1958, 1957, 1958, 1957, 1958,
+ 1957, 1958, 1965, 1966, 1967, 1968, 1969, 1970,
+ 1971, 1972, 1973, 1974, 1975, 1976, 1975, 1976,
+ 1977, 1978, 1979, 1980, 1979, 1980, 1979, 1980,
- 1979, 1980, 1977, 1978, 1981, 1982, 1983, 1984,
- 1985, 1984, 1985, 221, 221, 221, 221, 221,
- 1979, 1980, 221, 1986, 221, 1986, 1979, 1980,
- 1979, 1980, 221, 221, 221, 221, 221, 221,
+ 1981, 1982, 1979, 1980, 1983, 1984, 1985, 1986,
+ 1987, 1986, 1987, 221, 221, 221, 221, 221,
+ 1981, 1982, 221, 1988, 221, 1988, 1981, 1982,
+ 1981, 1982, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 1987, 1987, 1987, 1984, 1985, 1988,
- 1989, 1989, 1953, 1990, 1990, 1990, 1990, 1990,
+ 221, 221, 1989, 1989, 1989, 1986, 1987, 1990,
+ 1991, 1991, 1955, 1992, 1992, 1992, 1992, 1992,
- 1991, 1991, 1992, 1991, 1991, 1991, 1993, 1991,
- 1991, 1991, 1991, 1992, 1991, 1991, 1991, 1991,
- 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991,
- 1991, 1991, 1991, 1991, 1991, 1991, 1991, 1991,
+ 1993, 1993, 1994, 1993, 1993, 1993, 1995, 1993,
+ 1993, 1993, 1993, 1994, 1993, 1993, 1993, 1993,
+ 1993, 1993, 1993, 1993, 1993, 1993, 1993, 1993,
+ 1993, 1993, 1993, 1993, 1993, 1993, 1993, 1993,
- 1991, 1991, 1991, 1994, 1994, 1992, 1992, 1994,
- 1995, 1995, 1995, 1995, 1996, 221, 221, 221,
- 1997, 1997, 1997, 1997, 1997, 1997, 853, 853,
- 1496, 1998, 221, 221, 221, 221, 221, 221,
+ 1993, 1993, 1993, 1996, 1996, 1994, 1994, 1996,
+ 1997, 1997, 1997, 1997, 1998, 221, 221, 221,
+ 1999, 1999, 1999, 1999, 1999, 1999, 853, 853,
+ 1497, 2000, 221, 221, 221, 221, 221, 221,
- 1999, 1999, 1999, 1999, 1999, 1999, 1999, 1999,
- 1999, 1999, 1999, 1999, 1999, 1999, 1999, 1999,
- 1999, 1999, 1999, 1999, 1999, 1999, 1999, 1999,
- 1999, 1999, 1999, 1999, 1999, 1999, 1999, 1999,
+ 2001, 2001, 2001, 2001, 2001, 2001, 2001, 2001,
+ 2001, 2001, 2001, 2001, 2001, 2001, 2001, 2001,
+ 2001, 2001, 2001, 2001, 2001, 2001, 2001, 2001,
+ 2001, 2001, 2001, 2001, 2001, 2001, 2001, 2001,
- 1999, 1999, 1999, 1999, 1999, 1999, 1999, 1999,
- 1999, 1999, 1999, 1999, 1999, 1999, 1999, 1999,
- 1999, 1999, 2000, 2001, 2002, 2002, 2003, 2003,
+ 2001, 2001, 2001, 2001, 2001, 2001, 2001, 2001,
+ 2001, 2001, 2001, 2001, 2001, 2001, 2001, 2001,
+ 2001, 2001, 2002, 2003, 2004, 2004, 2005, 2005,
221, 221, 221, 221, 221, 221, 221, 221,
- 2004, 2004, 2005, 2005, 2005, 2005, 2005, 2005,
- 2005, 2005, 2005, 2005, 2005, 2005, 2005, 2005,
- 2005, 2005, 2005, 2005, 2005, 2005, 2005, 2005,
- 2005, 2005, 2005, 2005, 2005, 2005, 2005, 2005,
+ 2006, 2006, 2007, 2007, 2007, 2007, 2007, 2007,
+ 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007,
+ 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007,
+ 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007,
- 2005, 2005, 2005, 2005, 2005, 2005, 2005, 2005,
- 2005, 2005, 2005, 2005, 2005, 2005, 2005, 2005,
- 2005, 2005, 2005, 2005, 2004, 2004, 2004, 2004,
- 2004, 2004, 2004, 2004, 2004, 2004, 2004, 2004,
+ 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007,
+ 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007,
+ 2007, 2007, 2007, 2007, 2006, 2006, 2006, 2006,
+ 2006, 2006, 2006, 2006, 2006, 2006, 2006, 2006,
- 2004, 2004, 2004, 2004, 2006, 2007, 221, 221,
- 221, 221, 221, 221, 221, 221, 2008, 2008,
- 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
- 2017, 2018, 221, 221, 221, 221, 221, 221,
+ 2006, 2006, 2006, 2006, 2008, 2009, 221, 221,
+ 221, 221, 221, 221, 221, 221, 2010, 2010,
+ 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018,
+ 2019, 2020, 221, 221, 221, 221, 221, 221,
- 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019,
- 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019,
- 2019, 2019, 542, 542, 542, 542, 542, 542,
- 2020, 2020, 2020, 542, 2021, 2022, 2023, 2024,
+ 2021, 2021, 2021, 2021, 2021, 2021, 2021, 2021,
+ 2021, 2021, 2021, 2021, 2021, 2021, 2021, 2021,
+ 2021, 2021, 542, 542, 542, 542, 542, 542,
+ 2022, 2022, 2022, 542, 2023, 2024, 2025, 2026,
- 2025, 2026, 2027, 2028, 2029, 2030, 2031, 2032,
- 2033, 2034, 2035, 2035, 2035, 2035, 2035, 2035,
- 2035, 2035, 2035, 2035, 2035, 2035, 2035, 2035,
- 2035, 2035, 2035, 2035, 2035, 2035, 2035, 2035,
+ 2027, 2028, 2029, 2030, 2031, 2032, 2033, 2034,
+ 2035, 2036, 2037, 2037, 2037, 2037, 2037, 2037,
+ 2037, 2037, 2037, 2037, 2037, 2037, 2037, 2037,
+ 2037, 2037, 2037, 2037, 2037, 2037, 2037, 2037,
- 2035, 2035, 2035, 2035, 2035, 2035, 2036, 2036,
- 2036, 2036, 2036, 2037, 2037, 2037, 2038, 2039,
- 2040, 2040, 2040, 2040, 2040, 2040, 2040, 2040,
- 2040, 2040, 2040, 2040, 2040, 2040, 2040, 2040,
+ 2037, 2037, 2037, 2037, 2037, 2037, 2038, 2038,
+ 2038, 2038, 2038, 2039, 2039, 2039, 2040, 2041,
+ 2042, 2042, 2042, 2042, 2042, 2042, 2042, 2042,
+ 2042, 2042, 2042, 2042, 2042, 2042, 2042, 2042,
- 2040, 2040, 2040, 2040, 2040, 2040, 2040, 2041,
- 2041, 2041, 2041, 2041, 2041, 2041, 2041, 2041,
- 2041, 2041, 2042, 2043, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 2044,
+ 2042, 2042, 2042, 2042, 2042, 2042, 2042, 2043,
+ 2043, 2043, 2043, 2043, 2043, 2043, 2043, 2043,
+ 2043, 2043, 2044, 2045, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 2046,
903, 903, 903, 903, 903, 903, 903, 903,
903, 903, 903, 903, 903, 903, 903, 903,
903, 903, 903, 903, 903, 903, 903, 903,
903, 903, 903, 903, 903, 221, 221, 221,
- 2045, 2045, 2045, 2046, 2047, 2047, 2047, 2047,
- 2047, 2047, 2047, 2047, 2047, 2047, 2047, 2047,
- 2047, 2047, 2047, 2047, 2047, 2047, 2047, 2047,
- 2047, 2047, 2047, 2047, 2047, 2047, 2047, 2047,
+ 2047, 2047, 2047, 2048, 2049, 2049, 2049, 2049,
+ 2049, 2049, 2049, 2049, 2049, 2049, 2049, 2049,
+ 2049, 2049, 2049, 2049, 2049, 2049, 2049, 2049,
+ 2049, 2049, 2049, 2049, 2049, 2049, 2049, 2049,
+
+ 2049, 2049, 2049, 2049, 2049, 2049, 2049, 2049,
+ 2049, 2049, 2049, 2049, 2049, 2049, 2049, 2049,
+ 2049, 2049, 2049, 2050, 2048, 2048, 2047, 2047,
+ 2047, 2047, 2048, 2048, 2047, 2047, 2048, 2048,
- 2047, 2047, 2047, 2047, 2047, 2047, 2047, 2047,
- 2047, 2047, 2047, 2047, 2047, 2047, 2047, 2047,
- 2047, 2047, 2047, 2048, 2046, 2046, 2045, 2045,
- 2045, 2045, 2046, 2046, 2045, 2045, 2046, 2046,
+ 2051, 2052, 2052, 2052, 2052, 2052, 2052, 2053,
+ 2054, 2054, 2052, 2052, 2052, 2052, 221, 2055,
+ 2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063,
+ 2064, 2065, 221, 221, 221, 221, 2052, 2052,
- 2049, 2050, 2050, 2050, 2050, 2050, 2050, 2051,
- 2052, 2052, 2050, 2050, 2050, 2050, 221, 2053,
- 2054, 2055, 2056, 2057, 2058, 2059, 2060, 2061,
- 2062, 2063, 221, 221, 221, 221, 2050, 2050,
+ 2066, 2066, 2066, 2066, 2066, 2067, 2068, 2066,
+ 2066, 2066, 2066, 2066, 2066, 2066, 2066, 2066,
+ 2069, 2070, 2071, 2072, 2073, 2074, 2075, 2076,
+ 2077, 2078, 2066, 2066, 2066, 2066, 2066, 221,
- 2064, 2064, 2064, 2064, 2064, 2065, 2066, 2064,
- 2064, 2064, 2064, 2064, 2064, 2064, 2064, 2064,
- 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2074,
- 2075, 2076, 2064, 2064, 2064, 2064, 2064, 221,
+ 2079, 2079, 2079, 2079, 2079, 2079, 2079, 2079,
+ 2079, 2079, 2079, 2079, 2079, 2079, 2079, 2079,
+ 2079, 2079, 2079, 2079, 2079, 2079, 2079, 2079,
+ 2079, 2079, 2079, 2079, 2079, 2079, 2079, 2079,
- 2077, 2077, 2077, 2077, 2077, 2077, 2077, 2077,
- 2077, 2077, 2077, 2077, 2077, 2077, 2077, 2077,
- 2077, 2077, 2077, 2077, 2077, 2077, 2077, 2077,
- 2077, 2077, 2077, 2077, 2077, 2077, 2077, 2077,
+ 2079, 2079, 2079, 2079, 2079, 2079, 2079, 2079,
+ 2079, 2080, 2080, 2080, 2080, 2080, 2080, 2081,
+ 2081, 2080, 2080, 2081, 2081, 2080, 2080, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
- 2077, 2077, 2077, 2077, 2077, 2077, 2077, 2077,
- 2077, 2078, 2078, 2078, 2078, 2078, 2078, 2079,
- 2079, 2078, 2078, 2079, 2079, 2078, 2078, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
+ 2082, 2082, 2082, 2080, 2082, 2082, 2082, 2082,
+ 2082, 2082, 2082, 2082, 2080, 2081, 221, 221,
+ 2083, 2084, 2085, 2086, 2087, 2088, 2089, 2090,
+ 2091, 2092, 221, 221, 2093, 2094, 2094, 2094,
- 2077, 2077, 2077, 2078, 2077, 2077, 2077, 2077,
- 2077, 2077, 2077, 2077, 2078, 2079, 221, 221,
- 2080, 2081, 2082, 2083, 2084, 2085, 2086, 2087,
- 2088, 2089, 221, 221, 2090, 2091, 2091, 2091,
-
- 2092, 2092, 2092, 2092, 2092, 2092, 2092, 2092,
- 2092, 2092, 2092, 2092, 2092, 2092, 2092, 2092,
- 2093, 2092, 2092, 2092, 2092, 2092, 2092, 2094,
- 2094, 2094, 2092, 891, 2065, 2095, 2064, 2064,
+ 2095, 2095, 2095, 2095, 2095, 2095, 2095, 2095,
+ 2095, 2095, 2095, 2095, 2095, 2095, 2095, 2095,
+ 2096, 2095, 2095, 2095, 2095, 2095, 2095, 2097,
+ 2097, 2097, 2095, 891, 2067, 2098, 2066, 2066,
- 2096, 2096, 2096, 2096, 2096, 2096, 2096, 2096,
- 2096, 2096, 2096, 2096, 2096, 2096, 2096, 2096,
- 2096, 2096, 2096, 2096, 2096, 2096, 2096, 2096,
- 2096, 2096, 2096, 2096, 2096, 2096, 2096, 2096,
+ 2099, 2099, 2099, 2099, 2099, 2099, 2099, 2099,
+ 2099, 2099, 2099, 2099, 2099, 2099, 2099, 2099,
+ 2099, 2099, 2099, 2099, 2099, 2099, 2099, 2099,
+ 2099, 2099, 2099, 2099, 2099, 2099, 2099, 2099,
- 2096, 2096, 2096, 2096, 2096, 2096, 2096, 2096,
- 2096, 2096, 2096, 2096, 2096, 2096, 2096, 2096,
- 2097, 2096, 2097, 2097, 2098, 2096, 2096, 2097,
- 2097, 2096, 2096, 2096, 2096, 2096, 2097, 2097,
+ 2099, 2099, 2099, 2099, 2099, 2099, 2099, 2099,
+ 2099, 2099, 2099, 2099, 2099, 2099, 2099, 2099,
+ 2100, 2099, 2100, 2100, 2101, 2099, 2099, 2100,
+ 2100, 2099, 2099, 2099, 2099, 2099, 2100, 2100,
- 2096, 2097, 2096, 221, 221, 221, 221, 221,
+ 2099, 2100, 2099, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 2096, 2096, 2099, 2100, 2100,
+ 221, 221, 221, 2099, 2099, 2102, 2103, 2103,
- 2101, 2101, 2101, 2101, 2101, 2101, 2101, 2101,
- 2101, 2101, 2101, 2102, 2103, 2103, 2102, 2102,
- 2104, 2104, 2101, 2105, 2105, 2102, 2106, 221,
+ 2104, 2104, 2104, 2104, 2104, 2104, 2104, 2104,
+ 2104, 2104, 2104, 2105, 2106, 2106, 2105, 2105,
+ 2107, 2107, 2104, 2108, 2108, 2105, 2109, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 221, 2107, 2107, 2107, 2107, 2107, 2107, 221,
- 221, 2107, 2107, 2107, 2107, 2107, 2107, 221,
- 221, 2107, 2107, 2107, 2107, 2107, 2107, 221,
+ 221, 2110, 2110, 2110, 2110, 2110, 2110, 221,
+ 221, 2110, 2110, 2110, 2110, 2110, 2110, 221,
+ 221, 2110, 2110, 2110, 2110, 2110, 2110, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2107, 2107, 2107, 2107, 2107, 2107, 2107, 221,
- 2107, 2107, 2107, 2107, 2107, 2107, 2107, 221,
- 1960, 1960, 1960, 1960, 1960, 1960, 1960, 1960,
- 1960, 1960, 1960, 1960, 1960, 1960, 1960, 1960,
+ 2110, 2110, 2110, 2110, 2110, 2110, 2110, 221,
+ 2110, 2110, 2110, 2110, 2110, 2110, 2110, 221,
+ 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962,
+ 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962,
- 1960, 1960, 1960, 1960, 1960, 1960, 1960, 1960,
- 1960, 1960, 1960, 1960, 1960, 1960, 1960, 1960,
- 1960, 1960, 1960, 2108, 1960, 1960, 1960, 1960,
- 1960, 1960, 1960, 2109, 2110, 2110, 2110, 2110,
+ 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962,
+ 1962, 1962, 1962, 1962, 1962, 1962, 1962, 1962,
+ 1962, 1962, 1962, 2111, 1962, 1962, 1962, 1962,
+ 1962, 1962, 1962, 2112, 2113, 2113, 2113, 2113,
- 2111, 2111, 2111, 2111, 1960, 2112, 2113, 2113,
- 2114, 2115, 2116, 2116, 221, 221, 221, 221,
- 2117, 2118, 2119, 2120, 2121, 2122, 2123, 2124,
- 2125, 2126, 2127, 2128, 2129, 2130, 2131, 2132,
+ 2114, 2114, 2114, 2114, 1962, 2115, 2116, 2116,
+ 2117, 2118, 2119, 2119, 221, 221, 221, 221,
+ 2120, 2121, 2122, 2123, 2124, 2125, 2126, 2127,
+ 2128, 2129, 2130, 2131, 2132, 2133, 2134, 2135,
- 2133, 2134, 2135, 2136, 2137, 2138, 2139, 2140,
- 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148,
- 2149, 2150, 2151, 2152, 2153, 2154, 2155, 2156,
- 2157, 2158, 2159, 2160, 2161, 2162, 2163, 2164,
+ 2136, 2137, 2138, 2139, 2140, 2141, 2142, 2143,
+ 2144, 2145, 2146, 2147, 2148, 2149, 2150, 2151,
+ 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159,
+ 2160, 2161, 2162, 2163, 2164, 2165, 2166, 2167,
- 2165, 2166, 2167, 2168, 2169, 2170, 2171, 2172,
- 2173, 2174, 2175, 2176, 2177, 2178, 2179, 2180,
- 2181, 2182, 2183, 2184, 2185, 2186, 2187, 2188,
- 2189, 2190, 2191, 2192, 2193, 2194, 2195, 2196,
+ 2168, 2169, 2170, 2171, 2172, 2173, 2174, 2175,
+ 2176, 2177, 2178, 2179, 2180, 2181, 2182, 2183,
+ 2184, 2185, 2186, 2187, 2188, 2189, 2190, 2191,
+ 2192, 2193, 2194, 2195, 2196, 2197, 2198, 2199,
- 2197, 2197, 2197, 2197, 2197, 2197, 2197, 2197,
- 2197, 2197, 2197, 2197, 2197, 2197, 2197, 2197,
- 2197, 2197, 2197, 2197, 2197, 2197, 2197, 2197,
- 2197, 2197, 2197, 2197, 2197, 2197, 2197, 2197,
+ 2200, 2200, 2200, 2200, 2200, 2200, 2200, 2200,
+ 2200, 2200, 2200, 2200, 2200, 2200, 2200, 2200,
+ 2200, 2200, 2200, 2200, 2200, 2200, 2200, 2200,
+ 2200, 2200, 2200, 2200, 2200, 2200, 2200, 2200,
- 2197, 2197, 2197, 2198, 2198, 2199, 2198, 2198,
- 2199, 2198, 2198, 2200, 2198, 2201, 221, 221,
- 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209,
- 2210, 2211, 221, 221, 221, 221, 221, 221,
+ 2200, 2200, 2200, 2201, 2201, 2202, 2201, 2201,
+ 2202, 2201, 2201, 2203, 2201, 2204, 221, 221,
+ 2205, 2206, 2207, 2208, 2209, 2210, 2211, 2212,
+ 2213, 2214, 221, 221, 221, 221, 221, 221,
- 2212, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
- 2213, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
- 2213, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
- 2213, 2213, 2213, 2213, 2212, 2213, 2213, 2213,
+ 2215, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
+ 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
+ 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
+ 2216, 2216, 2216, 2216, 2215, 2216, 2216, 2216,
- 2213, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
- 2213, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
- 2213, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
- 2212, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
+ 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
+ 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
+ 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
+ 2215, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
- 2213, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
- 2213, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
- 2213, 2213, 2213, 2213, 2212, 2213, 2213, 2213,
- 2213, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
+ 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
+ 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
+ 2216, 2216, 2216, 2216, 2215, 2216, 2216, 2216,
+ 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
- 2213, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
- 2213, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
- 2212, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
- 2213, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
+ 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
+ 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
+ 2215, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
+ 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
- 2213, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
- 2213, 2213, 2213, 2213, 2212, 2213, 2213, 2213,
- 2213, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
- 2213, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
+ 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
+ 2216, 2216, 2216, 2216, 2215, 2216, 2216, 2216,
+ 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
+ 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
- 2213, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
- 2212, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
- 2213, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
- 2213, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
+ 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
+ 2215, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
+ 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
+ 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
- 2213, 2213, 2213, 2213, 2212, 2213, 2213, 2213,
- 2213, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
- 2213, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
- 2213, 2213, 2213, 2213, 2213, 2213, 2213, 2213,
+ 2216, 2216, 2216, 2216, 2215, 2216, 2216, 2216,
+ 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
+ 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
+ 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
- 2213, 2213, 2213, 2213, 221, 221, 221, 221,
+ 2216, 2216, 2216, 2216, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
908, 908, 908, 908, 908, 908, 908, 908,
908, 908, 908, 908, 908, 908, 908, 908,
@@ -3006,38 +3006,28 @@ static constexpr unsigned short uc_property_trie[] = {
911, 911, 911, 911, 911, 911, 911, 911,
911, 911, 911, 911, 221, 221, 221, 221,
- 2214, 2214, 2214, 2214, 2214, 2214, 2214, 2214,
- 2214, 2214, 2214, 2214, 2214, 2214, 2214, 2214,
- 2214, 2214, 2214, 2214, 2214, 2214, 2214, 2214,
- 2214, 2214, 2214, 2214, 2214, 2214, 2214, 2214,
-
- 2215, 2215, 2215, 2215, 2215, 2215, 2215, 2215,
- 2215, 2215, 2215, 2215, 2215, 2215, 2215, 2215,
- 2215, 2215, 2215, 2215, 2215, 2215, 2215, 2215,
- 2215, 2215, 2215, 2215, 2215, 2215, 2215, 2215,
-
- 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
- 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
- 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
- 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
-
- 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216,
- 2216, 2216, 2216, 2216, 2216, 2216, 1901, 1901,
- 2216, 1901, 2216, 1901, 1901, 2216, 2216, 2216,
- 2216, 2216, 2216, 2216, 2216, 2216, 2216, 1901,
-
- 2216, 1901, 2216, 1901, 1901, 2216, 2216, 1901,
- 1901, 1901, 2216, 2216, 2216, 2216, 2217, 2217,
- 2218, 2218, 2218, 2218, 2218, 2218, 2218, 2218,
- 2218, 2218, 2218, 2218, 2218, 2218, 2218, 2218,
+ 2217, 2217, 2217, 2217, 2217, 2217, 2217, 2217,
+ 2217, 2217, 2217, 2217, 2217, 2217, 2217, 2217,
+ 2217, 2217, 2217, 2217, 2217, 2217, 2217, 2217,
+ 2217, 2217, 2217, 2217, 2217, 2217, 2217, 2217,
2218, 2218, 2218, 2218, 2218, 2218, 2218, 2218,
2218, 2218, 2218, 2218, 2218, 2218, 2218, 2218,
2218, 2218, 2218, 2218, 2218, 2218, 2218, 2218,
2218, 2218, 2218, 2218, 2218, 2218, 2218, 2218,
- 2218, 2218, 2218, 2218, 2218, 2218, 2218, 2218,
- 2218, 2218, 2218, 2219, 2219, 2219, 2220, 2220,
+ 2219, 2219, 2219, 2219, 2219, 2219, 2219, 2219,
+ 2219, 2219, 2219, 2219, 2219, 2219, 2219, 2219,
+ 2219, 2219, 2219, 2219, 2219, 2219, 2219, 2219,
+ 2219, 2219, 2219, 2219, 2219, 2219, 2219, 2219,
+
+ 2219, 2219, 2219, 2219, 2219, 2219, 2219, 2219,
+ 2219, 2219, 2219, 2219, 2219, 2219, 1903, 1903,
+ 2219, 1903, 2219, 1903, 1903, 2219, 2219, 2219,
+ 2219, 2219, 2219, 2219, 2219, 2219, 2219, 1903,
+
+ 2219, 1903, 2219, 1903, 1903, 2219, 2219, 1903,
+ 1903, 1903, 2219, 2219, 2219, 2219, 2220, 2220,
2221, 2221, 2221, 2221, 2221, 2221, 2221, 2221,
2221, 2221, 2221, 2221, 2221, 2221, 2221, 2221,
@@ -3047,392 +3037,402 @@ static constexpr unsigned short uc_property_trie[] = {
2221, 2221, 2221, 2221, 2221, 2221, 2221, 2221,
2221, 2221, 2221, 2221, 2221, 2221, 2221, 2221,
- 2221, 2221, 2221, 2221, 2221, 2221, 2221, 2221,
- 2221, 2221, 2221, 2221, 2221, 2221, 2221, 2221,
- 2221, 2221, 2220, 2220, 2220, 2220, 2220, 2220,
+ 2221, 2221, 2221, 2222, 2222, 2222, 2223, 2223,
+ 2224, 2224, 2224, 2224, 2224, 2224, 2224, 2224,
+ 2224, 2224, 2224, 2224, 2224, 2224, 2224, 2224,
+
+ 2224, 2224, 2224, 2224, 2224, 2224, 2224, 2224,
+ 2224, 2224, 2224, 2224, 2224, 2224, 2224, 2224,
+ 2224, 2224, 2224, 2224, 2224, 2224, 2224, 2224,
+ 2224, 2224, 2224, 2224, 2224, 2224, 2224, 2224,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
+ 2224, 2224, 2224, 2224, 2224, 2224, 2224, 2224,
+ 2224, 2224, 2224, 2224, 2224, 2224, 2224, 2224,
+ 2224, 2224, 2224, 2224, 2224, 2224, 2224, 2224,
+ 2224, 2224, 2223, 2223, 2223, 2223, 2223, 2223,
- 2222, 2223, 2224, 2225, 2226, 2227, 2227, 221,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+
+ 2225, 2226, 2227, 2228, 2229, 2230, 2231, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 2228, 2229, 2230, 2231, 2232,
- 221, 221, 221, 221, 221, 2233, 2234, 2235,
+ 221, 221, 221, 2232, 2233, 2234, 2235, 2236,
+ 221, 221, 221, 221, 221, 2237, 2238, 2239,
- 2236, 2236, 2236, 2236, 2236, 2236, 2236, 2236,
- 2236, 2237, 2235, 2235, 2235, 2235, 2235, 2235,
- 2235, 2235, 2235, 2235, 2235, 2235, 2235, 323,
- 2235, 2235, 2235, 2235, 2235, 323, 2235, 323,
+ 2240, 2240, 2240, 2240, 2240, 2240, 2240, 2240,
+ 2240, 2241, 2239, 2239, 2239, 2239, 2239, 2239,
+ 2239, 2239, 2239, 2239, 2239, 2239, 2239, 323,
+ 2239, 2239, 2239, 2239, 2239, 323, 2239, 323,
- 2235, 2235, 323, 2235, 2235, 323, 2235, 2235,
- 2235, 2235, 2235, 2235, 2235, 2235, 2235, 2236,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
+ 2239, 2239, 323, 2239, 2239, 323, 2239, 2239,
+ 2239, 2239, 2239, 2239, 2239, 2239, 2239, 2240,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2239, 2239, 2239, 2239, 2239, 2239,
- 2239, 2239, 2239, 2239, 2239, 2239, 2239, 2239,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2243, 2243, 2243, 2243, 2243, 2243,
+ 2243, 2243, 2243, 2243, 2243, 2243, 2243, 2243,
- 2239, 2239, 489, 437, 437, 437, 437, 437,
+ 2243, 2243, 489, 437, 437, 437, 437, 437,
437, 437, 437, 437, 437, 437, 437, 437,
- 437, 437, 437, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
+ 437, 437, 437, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2244, 2244,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 2238, 2240, 2240,
+ 2244, 2244, 2244, 2244, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
- 2240, 2240, 2240, 2240, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2245, 1422,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 2238, 2241, 1421,
+ 2246, 2246, 2246, 2246, 2246, 2246, 2246, 2246,
+ 2246, 2246, 2246, 2246, 2246, 2246, 2246, 2246,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
+ 437, 437, 2242, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 437, 437, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+ 437, 437, 437, 437, 437, 437, 437, 2246,
+ 2247, 2247, 2247, 2247, 2247, 2247, 2247, 2247,
+ 2247, 2247, 2247, 2247, 2247, 2247, 2247, 2247,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 437, 437, 437, 437, 437, 437, 437, 2242,
- 2243, 2243, 2243, 2243, 2243, 2243, 2243, 2243,
- 2243, 2243, 2243, 2243, 2243, 2243, 2243, 2243,
+ 2247, 2247, 2247, 2247, 2247, 2247, 2247, 2247,
+ 2247, 2247, 2247, 2247, 2247, 2247, 2247, 2247,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2244, 2244, 2248, 363, 2246, 2246,
- 2243, 2243, 2243, 2243, 2243, 2243, 2243, 2243,
- 2243, 2243, 2243, 2243, 2243, 2243, 2243, 2243,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2240, 2240, 2244, 363, 2242, 2242,
-
- 2245, 2245, 2245, 2245, 2245, 2245, 2245, 2245,
- 2245, 2245, 2245, 2245, 2245, 2245, 2245, 2245,
- 2246, 2247, 2248, 2249, 2250, 2251, 2251, 2252,
- 2253, 2254, 221, 221, 221, 221, 221, 221,
-
- 288, 288, 288, 288, 1272, 1272, 1272, 1154,
- 1154, 1154, 1154, 1154, 1154, 1154, 1939, 1939,
- 2255, 2256, 2256, 2257, 2257, 2258, 2259, 2258,
- 2259, 2260, 2261, 2260, 2261, 2260, 2261, 2260,
-
- 2261, 2260, 2261, 2260, 2261, 2262, 2262, 2263,
- 2264, 2255, 2255, 2255, 2255, 2257, 2257, 2257,
- 2265, 2266, 2267, 221, 2268, 2269, 2270, 2270,
- 2256, 2271, 2272, 2271, 2272, 2273, 2274, 2275,
-
- 2255, 2255, 2276, 2277, 2278, 2279, 2280, 221,
- 2255, 2281, 2282, 2255, 221, 221, 221, 221,
- 2240, 2238, 2240, 2283, 2240, 437, 2240, 2238,
- 2240, 2238, 2240, 2238, 2240, 2238, 2240, 2238,
-
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 2238, 2238, 2238,
- 2238, 2238, 2238, 2238, 2238, 437, 437, 2284,
-
- 221, 2285, 2286, 2287, 2288, 2289, 2286, 2290,
- 2291, 2292, 2286, 2293, 2294, 2295, 2296, 2297,
- 2298, 2299, 2300, 2301, 2302, 2303, 2304, 2305,
- 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2285,
-
- 2286, 2313, 2313, 2313, 2313, 2313, 2313, 2313,
- 2313, 2313, 2313, 2313, 2313, 2313, 2313, 2313,
- 2313, 2313, 2313, 2313, 2313, 2313, 2313, 2313,
- 2313, 2313, 2313, 2314, 2286, 2315, 2316, 2317,
-
- 2316, 2318, 2318, 2318, 2318, 2318, 2318, 2318,
- 2318, 2318, 2318, 2318, 2318, 2318, 2318, 2318,
- 2318, 2318, 2318, 2318, 2318, 2318, 2318, 2318,
- 2318, 2318, 2318, 2314, 2311, 2315, 2311, 2319,
-
- 2320, 2321, 2322, 2323, 2324, 2325, 2326, 2327,
- 2327, 2327, 2327, 2327, 2327, 2327, 2327, 2327,
- 2328, 2326, 2326, 2326, 2326, 2326, 2326, 2326,
- 2326, 2326, 2326, 2326, 2326, 2326, 2326, 2326,
-
- 2326, 2326, 2326, 2326, 2326, 2326, 2326, 2326,
- 2326, 2326, 2326, 2326, 2326, 2326, 2326, 2326,
- 2326, 2326, 2326, 2326, 2326, 2326, 2326, 2326,
- 2326, 2326, 2326, 2326, 2326, 2326, 2329, 2329,
-
- 2330, 2331, 2331, 2331, 2331, 2331, 2331, 2331,
- 2331, 2331, 2331, 2331, 2331, 2331, 2331, 2331,
+ 2249, 2249, 2249, 2249, 2249, 2249, 2249, 2249,
+ 2249, 2249, 2249, 2249, 2249, 2249, 2249, 2249,
+ 2250, 2251, 2252, 2253, 2254, 2255, 2255, 2256,
+ 2257, 2258, 221, 221, 221, 221, 221, 221,
+
+ 288, 288, 288, 288, 1273, 1273, 1273, 1155,
+ 1155, 1155, 1155, 1155, 1155, 1155, 1941, 1941,
+ 2259, 2260, 2260, 2261, 2261, 2262, 2263, 2262,
+ 2263, 2264, 2265, 2264, 2265, 2264, 2265, 2264,
+
+ 2265, 2264, 2265, 2264, 2265, 2266, 2266, 2267,
+ 2268, 2259, 2259, 2259, 2259, 2261, 2261, 2261,
+ 2269, 2270, 2271, 221, 2272, 2273, 2274, 2274,
+ 2260, 2275, 2276, 2275, 2276, 2277, 2278, 2279,
+
+ 2259, 2259, 2280, 2281, 2282, 2283, 2284, 221,
+ 2259, 2285, 2286, 2259, 221, 221, 221, 221,
+ 2244, 2242, 2244, 2287, 2244, 437, 2244, 2242,
+ 2244, 2242, 2244, 2242, 2244, 2242, 2244, 2242,
+
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2242, 2242, 2242, 2242, 2242, 2242,
+ 2242, 2242, 2242, 2242, 2242, 437, 437, 2288,
+
+ 221, 2289, 2290, 2291, 2292, 2293, 2290, 2294,
+ 2295, 2296, 2290, 2297, 2298, 2299, 2300, 2301,
+ 2302, 2303, 2304, 2305, 2306, 2307, 2308, 2309,
+ 2310, 2311, 2312, 2313, 2314, 2315, 2316, 2289,
+
+ 2290, 2317, 2317, 2317, 2317, 2317, 2317, 2317,
+ 2317, 2317, 2317, 2317, 2317, 2317, 2317, 2317,
+ 2317, 2317, 2317, 2317, 2317, 2317, 2317, 2317,
+ 2317, 2317, 2317, 2318, 2290, 2319, 2320, 2321,
+
+ 2320, 2322, 2322, 2322, 2322, 2322, 2322, 2322,
+ 2322, 2322, 2322, 2322, 2322, 2322, 2322, 2322,
+ 2322, 2322, 2322, 2322, 2322, 2322, 2322, 2322,
+ 2322, 2322, 2322, 2318, 2315, 2319, 2315, 2323,
+
+ 2324, 2325, 2326, 2327, 2328, 2329, 2330, 2331,
2331, 2331, 2331, 2331, 2331, 2331, 2331, 2331,
- 2331, 2331, 2331, 2331, 2331, 2331, 2331, 221,
-
- 221, 221, 2331, 2331, 2331, 2331, 2331, 2331,
- 221, 221, 2331, 2331, 2331, 2331, 2331, 2331,
- 221, 221, 2331, 2331, 2331, 2331, 2331, 2331,
- 221, 221, 2331, 2331, 2331, 221, 221, 221,
-
- 2332, 2333, 2334, 2316, 2335, 2333, 2333, 221,
- 2336, 2337, 2337, 2337, 2337, 2336, 2336, 221,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 2338, 2338, 2338, 2339, 2340, 2341, 2341,
-
- 2342, 2342, 2342, 2342, 2342, 2342, 2342, 2342,
- 2342, 2342, 2342, 2342, 221, 2342, 2342, 2342,
- 2342, 2342, 2342, 2342, 2342, 2342, 2342, 2342,
- 2342, 2342, 2342, 2342, 2342, 2342, 2342, 2342,
-
- 2342, 2342, 2342, 2342, 2342, 2342, 2342, 221,
- 2342, 2342, 2342, 2342, 2342, 2342, 2342, 2342,
- 2342, 2342, 2342, 2342, 2342, 2342, 2342, 2342,
- 2342, 2342, 2342, 221, 2342, 2342, 221, 2342,
-
- 2342, 2342, 2342, 2342, 2342, 2342, 2342, 2342,
- 2342, 2342, 2342, 2342, 2342, 2342, 221, 221,
- 2342, 2342, 2342, 2342, 2342, 2342, 2342, 2342,
- 2342, 2342, 2342, 2342, 2342, 2342, 221, 221,
-
- 2342, 2342, 2342, 2342, 2342, 2342, 2342, 2342,
- 2342, 2342, 2342, 2342, 2342, 2342, 2342, 2342,
- 2342, 2342, 2342, 2342, 2342, 2342, 2342, 2342,
- 2342, 2342, 2342, 2342, 2342, 2342, 2342, 2342,
-
- 2342, 2342, 2342, 2342, 2342, 2342, 2342, 2342,
- 2342, 2342, 2342, 2342, 2342, 2342, 2342, 2342,
- 2342, 2342, 2342, 2342, 2342, 2342, 2342, 2342,
- 2342, 2342, 2342, 221, 221, 221, 221, 221,
-
- 2343, 2344, 2343, 221, 221, 221, 221, 2345,
- 2345, 2345, 2345, 2345, 2345, 2345, 2345, 2345,
- 2345, 2345, 2345, 2345, 2345, 2345, 2345, 2345,
- 2345, 2345, 2345, 2345, 2345, 2345, 2345, 2345,
-
- 2345, 2345, 2345, 2345, 2345, 2345, 2345, 2345,
- 2345, 2345, 2345, 2345, 2345, 2345, 2345, 2345,
- 2345, 2345, 2345, 2345, 221, 221, 221, 2346,
+ 2332, 2330, 2330, 2330, 2330, 2330, 2330, 2330,
+ 2330, 2330, 2330, 2330, 2330, 2330, 2330, 2330,
+
+ 2330, 2330, 2330, 2330, 2330, 2330, 2330, 2330,
+ 2330, 2330, 2330, 2330, 2330, 2330, 2330, 2330,
+ 2330, 2330, 2330, 2330, 2330, 2330, 2330, 2330,
+ 2330, 2330, 2330, 2330, 2330, 2330, 2333, 2333,
+
+ 2334, 2335, 2335, 2335, 2335, 2335, 2335, 2335,
+ 2335, 2335, 2335, 2335, 2335, 2335, 2335, 2335,
+ 2335, 2335, 2335, 2335, 2335, 2335, 2335, 2335,
+ 2335, 2335, 2335, 2335, 2335, 2335, 2335, 221,
+
+ 221, 221, 2335, 2335, 2335, 2335, 2335, 2335,
+ 221, 221, 2335, 2335, 2335, 2335, 2335, 2335,
+ 221, 221, 2335, 2335, 2335, 2335, 2335, 2335,
+ 221, 221, 2335, 2335, 2335, 221, 221, 221,
+
+ 2336, 2337, 2338, 2320, 2339, 2337, 2337, 221,
+ 2340, 2341, 2341, 2341, 2341, 2340, 2340, 221,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 2342, 2342, 2342, 2343, 2344, 2345, 2345,
+
+ 2346, 2346, 2346, 2346, 2346, 2346, 2346, 2346,
+ 2346, 2346, 2346, 2346, 221, 2346, 2346, 2346,
+ 2346, 2346, 2346, 2346, 2346, 2346, 2346, 2346,
+ 2346, 2346, 2346, 2346, 2346, 2346, 2346, 2346,
+
+ 2346, 2346, 2346, 2346, 2346, 2346, 2346, 221,
+ 2346, 2346, 2346, 2346, 2346, 2346, 2346, 2346,
2346, 2346, 2346, 2346, 2346, 2346, 2346, 2346,
+ 2346, 2346, 2346, 221, 2346, 2346, 221, 2346,
- 2347, 2347, 2347, 2347, 2347, 2347, 2347, 2347,
- 2347, 2347, 2347, 2347, 2347, 2347, 2347, 2347,
- 2347, 2347, 2347, 2347, 2347, 2347, 2347, 2347,
- 2347, 2347, 2347, 2347, 2347, 2347, 2347, 2347,
+ 2346, 2346, 2346, 2346, 2346, 2346, 2346, 2346,
+ 2346, 2346, 2346, 2346, 2346, 2346, 221, 221,
+ 2346, 2346, 2346, 2346, 2346, 2346, 2346, 2346,
+ 2346, 2346, 2346, 2346, 2346, 2346, 221, 221,
+
+ 2346, 2346, 2346, 2346, 2346, 2346, 2346, 2346,
+ 2346, 2346, 2346, 2346, 2346, 2346, 2346, 2346,
+ 2346, 2346, 2346, 2346, 2346, 2346, 2346, 2346,
+ 2346, 2346, 2346, 2346, 2346, 2346, 2346, 2346,
- 2347, 2347, 2347, 2347, 2347, 2347, 2347, 2347,
- 2347, 2347, 2347, 2347, 2347, 2347, 2347, 2347,
- 2347, 2347, 2347, 2347, 2347, 2348, 2348, 2348,
- 2348, 2349, 2349, 2349, 2349, 2349, 2349, 2349,
+ 2346, 2346, 2346, 2346, 2346, 2346, 2346, 2346,
+ 2346, 2346, 2346, 2346, 2346, 2346, 2346, 2346,
+ 2346, 2346, 2346, 2346, 2346, 2346, 2346, 2346,
+ 2346, 2346, 2346, 221, 221, 221, 221, 221,
+ 2347, 2348, 2347, 221, 221, 221, 221, 2349,
2349, 2349, 2349, 2349, 2349, 2349, 2349, 2349,
- 2349, 2349, 2348, 2350, 2351, 2352, 2352, 221,
- 1748, 1748, 1748, 1748, 1748, 1748, 1748, 1748,
- 1748, 1748, 1748, 1748, 1750, 221, 221, 221,
+ 2349, 2349, 2349, 2349, 2349, 2349, 2349, 2349,
+ 2349, 2349, 2349, 2349, 2349, 2349, 2349, 2349,
+
+ 2349, 2349, 2349, 2349, 2349, 2349, 2349, 2349,
+ 2349, 2349, 2349, 2349, 2349, 2349, 2349, 2349,
+ 2349, 2349, 2349, 2349, 221, 221, 221, 2350,
+ 2350, 2350, 2350, 2350, 2350, 2350, 2350, 2350,
+
+ 2351, 2351, 2351, 2351, 2351, 2351, 2351, 2351,
+ 2351, 2351, 2351, 2351, 2351, 2351, 2351, 2351,
+ 2351, 2351, 2351, 2351, 2351, 2351, 2351, 2351,
+ 2351, 2351, 2351, 2351, 2351, 2351, 2351, 2351,
+
+ 2351, 2351, 2351, 2351, 2351, 2351, 2351, 2351,
+ 2351, 2351, 2351, 2351, 2351, 2351, 2351, 2351,
+ 2351, 2351, 2351, 2351, 2351, 2352, 2352, 2352,
+ 2352, 2353, 2353, 2353, 2353, 2353, 2353, 2353,
+
+ 2353, 2353, 2353, 2353, 2353, 2353, 2353, 2353,
+ 2353, 2353, 2352, 2354, 2355, 2356, 2356, 221,
+ 1749, 1749, 1749, 1749, 1749, 1749, 1749, 1749,
+ 1749, 1749, 1749, 1749, 1751, 221, 221, 221,
- 2351, 221, 221, 221, 221, 221, 221, 221,
+ 2355, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 1543, 1543, 1543, 1543, 1543, 1543, 1543, 1543,
- 1543, 1543, 1543, 1543, 1543, 1543, 1543, 1543,
+ 1544, 1544, 1544, 1544, 1544, 1544, 1544, 1544,
+ 1544, 1544, 1544, 1544, 1544, 1544, 1544, 1544,
- 1543, 1543, 1543, 1543, 1543, 1543, 1543, 1543,
- 1543, 1543, 1543, 1543, 1543, 1543, 1543, 1543,
- 1543, 1543, 1543, 1543, 1543, 1543, 1543, 1543,
- 1543, 1543, 1543, 1543, 1543, 1275, 221, 221,
+ 1544, 1544, 1544, 1544, 1544, 1544, 1544, 1544,
+ 1544, 1544, 1544, 1544, 1544, 1544, 1544, 1544,
+ 1544, 1544, 1544, 1544, 1544, 1544, 1544, 1544,
+ 1544, 1544, 1544, 1544, 1544, 1276, 221, 221,
- 2353, 2353, 2353, 2353, 2353, 2353, 2353, 2353,
- 2353, 2353, 2353, 2353, 2353, 2353, 2353, 2353,
- 2353, 2353, 2353, 2353, 2353, 2353, 2353, 2353,
- 2353, 2353, 2353, 2353, 2353, 221, 221, 221,
+ 2357, 2357, 2357, 2357, 2357, 2357, 2357, 2357,
+ 2357, 2357, 2357, 2357, 2357, 2357, 2357, 2357,
+ 2357, 2357, 2357, 2357, 2357, 2357, 2357, 2357,
+ 2357, 2357, 2357, 2357, 2357, 221, 221, 221,
- 2354, 2354, 2354, 2354, 2354, 2354, 2354, 2354,
- 2354, 2354, 2354, 2354, 2354, 2354, 2354, 2354,
- 2354, 2354, 2354, 2354, 2354, 2354, 2354, 2354,
- 2354, 2354, 2354, 2354, 2354, 2354, 2354, 2354,
+ 2358, 2358, 2358, 2358, 2358, 2358, 2358, 2358,
+ 2358, 2358, 2358, 2358, 2358, 2358, 2358, 2358,
+ 2358, 2358, 2358, 2358, 2358, 2358, 2358, 2358,
+ 2358, 2358, 2358, 2358, 2358, 2358, 2358, 2358,
- 2354, 2354, 2354, 2354, 2354, 2354, 2354, 2354,
- 2354, 2354, 2354, 2354, 2354, 2354, 2354, 2354,
- 2354, 221, 221, 221, 221, 221, 221, 221,
+ 2358, 2358, 2358, 2358, 2358, 2358, 2358, 2358,
+ 2358, 2358, 2358, 2358, 2358, 2358, 2358, 2358,
+ 2358, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 1154, 2355, 2355, 2355, 2355, 2355, 2355, 2355,
- 2355, 2355, 2355, 2355, 2355, 2355, 2355, 2355,
- 2355, 2355, 2355, 2355, 2355, 2355, 2355, 2355,
- 2355, 2355, 2355, 2355, 221, 221, 221, 221,
+ 1155, 2359, 2359, 2359, 2359, 2359, 2359, 2359,
+ 2359, 2359, 2359, 2359, 2359, 2359, 2359, 2359,
+ 2359, 2359, 2359, 2359, 2359, 2359, 2359, 2359,
+ 2359, 2359, 2359, 2359, 221, 221, 221, 221,
- 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356,
- 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356,
- 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2356,
- 2356, 2356, 2356, 2356, 2356, 2356, 2356, 2357,
-
- 2358, 2358, 2358, 2358, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 2359, 2359, 2359,
2360, 2360, 2360, 2360, 2360, 2360, 2360, 2360,
2360, 2360, 2360, 2360, 2360, 2360, 2360, 2360,
+ 2360, 2360, 2360, 2360, 2360, 2360, 2360, 2360,
+ 2360, 2360, 2360, 2360, 2360, 2360, 2360, 2361,
- 2360, 2361, 2360, 2360, 2360, 2360, 2360, 2360,
- 2360, 2360, 2361, 221, 221, 221, 221, 221,
- 2362, 2362, 2362, 2362, 2362, 2362, 2362, 2362,
- 2362, 2362, 2362, 2362, 2362, 2362, 2362, 2362,
-
- 2362, 2362, 2362, 2362, 2362, 2362, 2362, 2362,
- 2362, 2362, 2362, 2362, 2362, 2362, 2362, 2362,
- 2362, 2362, 2362, 2362, 2362, 2362, 2363, 2363,
- 2363, 2363, 2363, 221, 221, 221, 221, 221,
-
- 2364, 2364, 2364, 2364, 2364, 2364, 2364, 2364,
+ 2362, 2362, 2362, 2362, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 2363, 2363, 2363,
2364, 2364, 2364, 2364, 2364, 2364, 2364, 2364,
2364, 2364, 2364, 2364, 2364, 2364, 2364, 2364,
- 2364, 2364, 2364, 2364, 2364, 2364, 221, 2365,
- 2366, 2366, 2366, 2366, 2366, 2366, 2366, 2366,
- 2366, 2366, 2366, 2366, 2366, 2366, 2366, 2366,
+ 2364, 2365, 2364, 2364, 2364, 2364, 2364, 2364,
+ 2364, 2364, 2365, 221, 221, 221, 221, 221,
2366, 2366, 2366, 2366, 2366, 2366, 2366, 2366,
2366, 2366, 2366, 2366, 2366, 2366, 2366, 2366,
- 2366, 2366, 2366, 2366, 221, 221, 221, 221,
2366, 2366, 2366, 2366, 2366, 2366, 2366, 2366,
- 2367, 2368, 2368, 2368, 2368, 2368, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
+ 2366, 2366, 2366, 2366, 2366, 2366, 2366, 2366,
+ 2366, 2366, 2366, 2366, 2366, 2366, 2367, 2367,
+ 2367, 2367, 2367, 221, 221, 221, 221, 221,
- 2369, 2369, 2369, 2369, 2369, 2369, 2369, 2369,
- 2369, 2369, 2369, 2369, 2369, 2369, 2369, 2369,
- 2369, 2369, 2369, 2369, 2369, 2369, 2369, 2369,
- 2369, 2369, 2369, 2369, 2369, 2369, 2369, 2369,
+ 2368, 2368, 2368, 2368, 2368, 2368, 2368, 2368,
+ 2368, 2368, 2368, 2368, 2368, 2368, 2368, 2368,
+ 2368, 2368, 2368, 2368, 2368, 2368, 2368, 2368,
+ 2368, 2368, 2368, 2368, 2368, 2368, 221, 2369,
- 2369, 2369, 2369, 2369, 2369, 2369, 2370, 2370,
- 2371, 2371, 2371, 2371, 2371, 2371, 2371, 2371,
- 2371, 2371, 2371, 2371, 2371, 2371, 2371, 2371,
- 2371, 2371, 2371, 2371, 2371, 2371, 2371, 2371,
+ 2370, 2370, 2370, 2370, 2370, 2370, 2370, 2370,
+ 2370, 2370, 2370, 2370, 2370, 2370, 2370, 2370,
+ 2370, 2370, 2370, 2370, 2370, 2370, 2370, 2370,
+ 2370, 2370, 2370, 2370, 2370, 2370, 2370, 2370,
- 2371, 2371, 2371, 2371, 2371, 2371, 2371, 2371,
- 2371, 2371, 2371, 2371, 2371, 2371, 2372, 2372,
- 2373, 2373, 2373, 2373, 2373, 2373, 2373, 2373,
- 2373, 2373, 2373, 2373, 2373, 2373, 2373, 2373,
+ 2370, 2370, 2370, 2370, 221, 221, 221, 221,
+ 2370, 2370, 2370, 2370, 2370, 2370, 2370, 2370,
+ 2371, 2372, 2372, 2372, 2372, 2372, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
2373, 2373, 2373, 2373, 2373, 2373, 2373, 2373,
2373, 2373, 2373, 2373, 2373, 2373, 2373, 2373,
2373, 2373, 2373, 2373, 2373, 2373, 2373, 2373,
2373, 2373, 2373, 2373, 2373, 2373, 2373, 2373,
- 2374, 2374, 2374, 2374, 2374, 2374, 2374, 2374,
- 2374, 2374, 2374, 2374, 2374, 2374, 2374, 2374,
- 2374, 2374, 2374, 2374, 2374, 2374, 2374, 2374,
- 2374, 2374, 2374, 2374, 2374, 2374, 221, 221,
-
- 2375, 2376, 2377, 2378, 2379, 2380, 2381, 2382,
- 2383, 2384, 221, 221, 221, 221, 221, 221,
- 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
- 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
-
- 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
- 2385, 2385, 2385, 2385, 2385, 2385, 2385, 2385,
- 2385, 2385, 2385, 2385, 221, 221, 221, 221,
- 2386, 2386, 2386, 2386, 2386, 2386, 2386, 2386,
-
- 2386, 2386, 2386, 2386, 2386, 2386, 2386, 2386,
- 2386, 2386, 2386, 2386, 2386, 2386, 2386, 2386,
- 2386, 2386, 2386, 2386, 2386, 2386, 2386, 2386,
- 2386, 2386, 2386, 2386, 221, 221, 221, 221,
-
- 2387, 2387, 2387, 2387, 2387, 2387, 2387, 2387,
- 2387, 2387, 2387, 2387, 2387, 2387, 2387, 2387,
- 2387, 2387, 2387, 2387, 2387, 2387, 2387, 2387,
- 2387, 2387, 2387, 2387, 2387, 2387, 2387, 2387,
-
- 2387, 2387, 2387, 2387, 2387, 2387, 2387, 2387,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 2388, 2388, 2388, 2388, 2388, 2388, 2388, 2388,
- 2388, 2388, 2388, 2388, 2388, 2388, 2388, 2388,
-
- 2388, 2388, 2388, 2388, 2388, 2388, 2388, 2388,
- 2388, 2388, 2388, 2388, 2388, 2388, 2388, 2388,
- 2388, 2388, 2388, 2388, 2388, 2388, 2388, 2388,
- 2388, 2388, 2388, 2388, 2388, 2388, 2388, 2388,
-
- 2388, 2388, 2388, 2388, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 2389,
+ 2373, 2373, 2373, 2373, 2373, 2373, 2374, 2374,
+ 2375, 2375, 2375, 2375, 2375, 2375, 2375, 2375,
+ 2375, 2375, 2375, 2375, 2375, 2375, 2375, 2375,
+ 2375, 2375, 2375, 2375, 2375, 2375, 2375, 2375,
+
+ 2375, 2375, 2375, 2375, 2375, 2375, 2375, 2375,
+ 2375, 2375, 2375, 2375, 2375, 2375, 2376, 2376,
+ 2377, 2377, 2377, 2377, 2377, 2377, 2377, 2377,
+ 2377, 2377, 2377, 2377, 2377, 2377, 2377, 2377,
+
+ 2377, 2377, 2377, 2377, 2377, 2377, 2377, 2377,
+ 2377, 2377, 2377, 2377, 2377, 2377, 2377, 2377,
+ 2377, 2377, 2377, 2377, 2377, 2377, 2377, 2377,
+ 2377, 2377, 2377, 2377, 2377, 2377, 2377, 2377,
+
+ 2378, 2378, 2378, 2378, 2378, 2378, 2378, 2378,
+ 2378, 2378, 2378, 2378, 2378, 2378, 2378, 2378,
+ 2378, 2378, 2378, 2378, 2378, 2378, 2378, 2378,
+ 2378, 2378, 2378, 2378, 2378, 2378, 221, 221,
+
+ 2379, 2380, 2381, 2382, 2383, 2384, 2385, 2386,
+ 2387, 2388, 221, 221, 221, 221, 221, 221,
+ 2389, 2389, 2389, 2389, 2389, 2389, 2389, 2389,
+ 2389, 2389, 2389, 2389, 2389, 2389, 2389, 2389,
+
+ 2389, 2389, 2389, 2389, 2389, 2389, 2389, 2389,
+ 2389, 2389, 2389, 2389, 2389, 2389, 2389, 2389,
+ 2389, 2389, 2389, 2389, 221, 221, 221, 221,
2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
- 2390, 2390, 2390, 221, 2390, 2390, 2390, 2390,
2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
- 2390, 2390, 2390, 221, 2390, 2390, 2390, 2390,
- 2390, 2390, 2390, 221, 2390, 2390, 221, 2391,
- 2391, 2391, 2391, 2391, 2391, 2391, 2391, 2391,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 221, 221, 221, 221,
- 2391, 2391, 221, 2391, 2391, 2391, 2391, 2391,
2391, 2391, 2391, 2391, 2391, 2391, 2391, 2391,
- 2391, 2391, 221, 2391, 2391, 2391, 2391, 2391,
- 2391, 2391, 221, 2391, 2391, 221, 221, 221,
+ 2391, 2391, 2391, 2391, 2391, 2391, 2391, 2391,
+ 2391, 2391, 2391, 2391, 2391, 2391, 2391, 2391,
+ 2391, 2391, 2391, 2391, 2391, 2391, 2391, 2391,
+ 2391, 2391, 2391, 2391, 2391, 2391, 2391, 2391,
+ 221, 221, 221, 221, 221, 221, 221, 221,
2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392,
2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392,
+
2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392,
2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392,
-
2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392,
2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392,
- 2392, 2392, 2392, 2392, 2392, 2392, 2392, 221,
+
+ 2392, 2392, 2392, 2392, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 2393,
+ 2394, 2394, 2394, 2394, 2394, 2394, 2394, 2394,
+ 2394, 2394, 2394, 221, 2394, 2394, 2394, 2394,
+
+ 2394, 2394, 2394, 2394, 2394, 2394, 2394, 2394,
+ 2394, 2394, 2394, 221, 2394, 2394, 2394, 2394,
+ 2394, 2394, 2394, 221, 2394, 2394, 221, 2395,
+ 2395, 2395, 2395, 2395, 2395, 2395, 2395, 2395,
+
+ 2395, 2395, 221, 2395, 2395, 2395, 2395, 2395,
+ 2395, 2395, 2395, 2395, 2395, 2395, 2395, 2395,
+ 2395, 2395, 221, 2395, 2395, 2395, 2395, 2395,
+ 2395, 2395, 221, 2395, 2395, 221, 221, 221,
+
+ 2396, 2396, 2396, 2396, 2396, 2396, 2396, 2396,
+ 2396, 2396, 2396, 2396, 2396, 2396, 2396, 2396,
+ 2396, 2396, 2396, 2396, 2396, 2396, 2396, 2396,
+ 2396, 2396, 2396, 2396, 2396, 2396, 2396, 2396,
+
+ 2396, 2396, 2396, 2396, 2396, 2396, 2396, 2396,
+ 2396, 2396, 2396, 2396, 2396, 2396, 2396, 2396,
+ 2396, 2396, 2396, 2396, 2396, 2396, 2396, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392,
- 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392,
- 2392, 2392, 2392, 2392, 2392, 2392, 221, 221,
+ 2396, 2396, 2396, 2396, 2396, 2396, 2396, 2396,
+ 2396, 2396, 2396, 2396, 2396, 2396, 2396, 2396,
+ 2396, 2396, 2396, 2396, 2396, 2396, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2392, 2392, 2392, 2392, 2392, 2392, 2392, 2392,
+ 2396, 2396, 2396, 2396, 2396, 2396, 2396, 2396,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2393, 2394, 2394, 1987, 1987, 1987, 221, 1987,
- 1987, 1987, 1987, 1987, 1987, 1987, 1987, 1987,
- 1987, 1987, 1987, 1987, 1987, 1987, 1987, 1987,
- 1987, 1987, 1987, 1987, 1987, 1987, 1987, 1987,
-
- 1987, 1987, 1987, 1987, 1987, 1987, 1987, 1987,
- 1987, 1987, 1987, 1987, 1987, 1987, 1987, 1987,
- 1987, 221, 1987, 1987, 1987, 1987, 1987, 1987,
- 1987, 1987, 1987, 221, 221, 221, 221, 221,
+ 2397, 2398, 2398, 1989, 1989, 1989, 221, 1989,
+ 1989, 1989, 1989, 1989, 1989, 1989, 1989, 1989,
+ 1989, 1989, 1989, 1989, 1989, 1989, 1989, 1989,
+ 1989, 1989, 1989, 1989, 1989, 1989, 1989, 1989,
- 2395, 2395, 2395, 2395, 2395, 2395, 323, 323,
- 2395, 323, 2395, 2395, 2395, 2395, 2395, 2395,
- 2395, 2395, 2395, 2395, 2395, 2395, 2395, 2395,
- 2395, 2395, 2395, 2395, 2395, 2395, 2395, 2395,
-
- 2395, 2395, 2395, 2395, 2395, 2395, 2395, 2395,
- 2395, 2395, 2395, 2395, 2395, 2395, 2395, 2395,
- 2395, 2395, 2395, 2395, 2395, 2395, 323, 2395,
- 2395, 323, 323, 323, 2395, 323, 323, 2395,
+ 1989, 1989, 1989, 1989, 1989, 1989, 1989, 1989,
+ 1989, 1989, 1989, 1989, 1989, 1989, 1989, 1989,
+ 1989, 221, 1989, 1989, 1989, 1989, 1989, 1989,
+ 1989, 1989, 1989, 221, 221, 221, 221, 221,
- 2396, 2396, 2396, 2396, 2396, 2396, 2396, 2396,
- 2396, 2396, 2396, 2396, 2396, 2396, 2396, 2396,
- 2396, 2396, 2396, 2396, 2396, 2396, 323, 2397,
- 2398, 2398, 2398, 2398, 2398, 2398, 2398, 2398,
+ 2399, 2399, 2399, 2399, 2399, 2399, 323, 323,
+ 2399, 323, 2399, 2399, 2399, 2399, 2399, 2399,
+ 2399, 2399, 2399, 2399, 2399, 2399, 2399, 2399,
+ 2399, 2399, 2399, 2399, 2399, 2399, 2399, 2399,
2399, 2399, 2399, 2399, 2399, 2399, 2399, 2399,
2399, 2399, 2399, 2399, 2399, 2399, 2399, 2399,
- 2399, 2399, 2399, 2399, 2399, 2399, 2399, 2400,
- 2400, 2401, 2401, 2401, 2401, 2401, 2401, 2401,
+ 2399, 2399, 2399, 2399, 2399, 2399, 323, 2399,
+ 2399, 323, 323, 323, 2399, 323, 323, 2399,
+ 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400,
+ 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400,
+ 2400, 2400, 2400, 2400, 2400, 2400, 323, 2401,
2402, 2402, 2402, 2402, 2402, 2402, 2402, 2402,
- 2402, 2402, 2402, 2402, 2402, 2402, 2402, 2402,
- 2402, 2402, 2402, 2402, 2402, 2402, 2402, 2402,
- 2402, 2402, 2402, 2402, 2402, 2402, 2402, 323,
- 323, 323, 323, 323, 323, 323, 323, 2403,
2403, 2403, 2403, 2403, 2403, 2403, 2403, 2403,
+ 2403, 2403, 2403, 2403, 2403, 2403, 2403, 2403,
+ 2403, 2403, 2403, 2403, 2403, 2403, 2403, 2404,
+ 2404, 2405, 2405, 2405, 2405, 2405, 2405, 2405,
+
+ 2406, 2406, 2406, 2406, 2406, 2406, 2406, 2406,
+ 2406, 2406, 2406, 2406, 2406, 2406, 2406, 2406,
+ 2406, 2406, 2406, 2406, 2406, 2406, 2406, 2406,
+ 2406, 2406, 2406, 2406, 2406, 2406, 2406, 323,
+
+ 323, 323, 323, 323, 323, 323, 323, 2407,
+ 2407, 2407, 2407, 2407, 2407, 2407, 2407, 2407,
323, 323, 323, 323, 323, 323, 323, 323,
323, 323, 323, 323, 323, 323, 323, 323,
@@ -3441,281 +3441,281 @@ static constexpr unsigned short uc_property_trie[] = {
323, 323, 323, 323, 323, 323, 323, 323,
323, 323, 323, 323, 323, 323, 323, 323,
- 2404, 2404, 2404, 2404, 2404, 2404, 2404, 2404,
- 2404, 2404, 2404, 2404, 2404, 2404, 2404, 2404,
- 2404, 2404, 2404, 323, 2404, 2404, 323, 323,
- 323, 323, 323, 2405, 2405, 2405, 2405, 2405,
+ 2408, 2408, 2408, 2408, 2408, 2408, 2408, 2408,
+ 2408, 2408, 2408, 2408, 2408, 2408, 2408, 2408,
+ 2408, 2408, 2408, 323, 2408, 2408, 323, 323,
+ 323, 323, 323, 2409, 2409, 2409, 2409, 2409,
- 2406, 2406, 2406, 2406, 2406, 2406, 2406, 2406,
- 2406, 2406, 2406, 2406, 2406, 2406, 2406, 2406,
- 2406, 2406, 2406, 2406, 2406, 2406, 2407, 2407,
- 2407, 2407, 2408, 2408, 323, 323, 323, 2409,
-
- 2410, 2410, 2410, 2410, 2410, 2410, 2410, 2410,
2410, 2410, 2410, 2410, 2410, 2410, 2410, 2410,
2410, 2410, 2410, 2410, 2410, 2410, 2410, 2410,
- 2410, 2410, 323, 323, 323, 323, 323, 2411,
-
- 2412, 2412, 2412, 2412, 2412, 2412, 2412, 2412,
- 2412, 2412, 2412, 2412, 2412, 2412, 2412, 2412,
- 2412, 2412, 2412, 2412, 2412, 2412, 2412, 2412,
- 2412, 2412, 2412, 2412, 2412, 2412, 2412, 2412,
-
- 2413, 2413, 2413, 2413, 2413, 2413, 2413, 2413,
- 2413, 2413, 2413, 2413, 2413, 2413, 2413, 2413,
- 2413, 2413, 2413, 2413, 2413, 2413, 2413, 2413,
- 323, 323, 323, 323, 2414, 2414, 2413, 2413,
+ 2410, 2410, 2410, 2410, 2410, 2410, 2411, 2411,
+ 2411, 2411, 2412, 2412, 323, 323, 323, 2413,
2414, 2414, 2414, 2414, 2414, 2414, 2414, 2414,
2414, 2414, 2414, 2414, 2414, 2414, 2414, 2414,
- 323, 323, 2414, 2414, 2414, 2414, 2414, 2414,
2414, 2414, 2414, 2414, 2414, 2414, 2414, 2414,
-
- 2414, 2414, 2414, 2414, 2414, 2414, 2414, 2414,
- 2414, 2414, 2414, 2414, 2414, 2414, 2414, 2414,
- 2414, 2414, 2414, 2414, 2414, 2414, 2414, 2414,
- 2414, 2414, 2414, 2414, 2414, 2414, 2414, 2414,
-
- 2415, 2416, 2416, 2416, 323, 2416, 2416, 323,
- 323, 323, 323, 323, 2416, 2417, 2416, 2418,
- 2415, 2415, 2415, 2415, 323, 2415, 2415, 2415,
- 323, 2415, 2415, 2415, 2415, 2415, 2415, 2415,
-
- 2415, 2415, 2415, 2415, 2415, 2415, 2415, 2415,
- 2415, 2415, 2415, 2415, 2415, 2415, 2415, 2415,
- 2415, 2415, 2415, 2415, 2419, 2419, 323, 323,
- 2418, 2420, 2417, 323, 323, 323, 323, 2421,
-
- 2422, 2423, 2424, 2425, 2426, 2426, 2426, 2426,
- 2427, 323, 323, 323, 323, 323, 323, 323,
- 2428, 2428, 2428, 2428, 2428, 2428, 2429, 2429,
- 2430, 323, 323, 323, 323, 323, 323, 323,
-
- 2431, 2431, 2431, 2431, 2431, 2431, 2431, 2431,
- 2431, 2431, 2431, 2431, 2431, 2431, 2431, 2431,
- 2431, 2431, 2431, 2431, 2431, 2431, 2431, 2431,
- 2431, 2431, 2431, 2431, 2431, 2432, 2432, 2433,
-
- 2434, 2434, 2434, 2434, 2434, 2434, 2434, 2434,
- 2434, 2434, 2434, 2434, 2434, 2434, 2434, 2434,
- 2434, 2434, 2434, 2434, 2434, 2434, 2434, 2434,
- 2434, 2434, 2434, 2434, 2434, 2435, 2435, 2435,
-
- 2436, 2436, 2436, 2436, 2436, 2437, 2438, 2437,
- 2439, 2437, 2437, 2438, 2438, 2440, 2437, 2437,
- 2437, 2437, 2437, 2436, 2436, 2436, 2436, 2440,
- 2436, 2436, 2436, 2436, 2436, 2437, 2436, 2436,
-
- 2436, 2437, 2438, 2438, 2437, 2441, 2442, 323,
- 323, 323, 323, 2443, 2443, 2443, 2443, 2444,
- 2445, 2445, 2445, 2445, 2445, 2445, 2446, 323,
+ 2414, 2414, 323, 323, 323, 323, 323, 2415,
+
+ 2416, 2416, 2416, 2416, 2416, 2416, 2416, 2416,
+ 2416, 2416, 2416, 2416, 2416, 2416, 2416, 2416,
+ 2416, 2416, 2416, 2416, 2416, 2416, 2416, 2416,
+ 2416, 2416, 2416, 2416, 2416, 2416, 2416, 2416,
+
+ 2417, 2417, 2417, 2417, 2417, 2417, 2417, 2417,
+ 2417, 2417, 2417, 2417, 2417, 2417, 2417, 2417,
+ 2417, 2417, 2417, 2417, 2417, 2417, 2417, 2417,
+ 323, 323, 323, 323, 2418, 2418, 2417, 2417,
+
+ 2418, 2418, 2418, 2418, 2418, 2418, 2418, 2418,
+ 2418, 2418, 2418, 2418, 2418, 2418, 2418, 2418,
+ 323, 323, 2418, 2418, 2418, 2418, 2418, 2418,
+ 2418, 2418, 2418, 2418, 2418, 2418, 2418, 2418,
+
+ 2418, 2418, 2418, 2418, 2418, 2418, 2418, 2418,
+ 2418, 2418, 2418, 2418, 2418, 2418, 2418, 2418,
+ 2418, 2418, 2418, 2418, 2418, 2418, 2418, 2418,
+ 2418, 2418, 2418, 2418, 2418, 2418, 2418, 2418,
+
+ 2419, 2420, 2420, 2420, 323, 2420, 2420, 323,
+ 323, 323, 323, 323, 2420, 2421, 2420, 2422,
+ 2419, 2419, 2419, 2419, 323, 2419, 2419, 2419,
+ 323, 2419, 2419, 2419, 2419, 2419, 2419, 2419,
+
+ 2419, 2419, 2419, 2419, 2419, 2419, 2419, 2419,
+ 2419, 2419, 2419, 2419, 2419, 2419, 2419, 2419,
+ 2419, 2419, 2419, 2419, 2423, 2423, 323, 323,
+ 2422, 2424, 2421, 323, 323, 323, 323, 2425,
+
+ 2426, 2427, 2428, 2429, 2430, 2430, 2430, 2430,
+ 2431, 323, 323, 323, 323, 323, 323, 323,
+ 2432, 2432, 2432, 2432, 2432, 2432, 2433, 2433,
+ 2434, 323, 323, 323, 323, 323, 323, 323,
+
+ 2435, 2435, 2435, 2435, 2435, 2435, 2435, 2435,
+ 2435, 2435, 2435, 2435, 2435, 2435, 2435, 2435,
+ 2435, 2435, 2435, 2435, 2435, 2435, 2435, 2435,
+ 2435, 2435, 2435, 2435, 2435, 2436, 2436, 2437,
+
+ 2438, 2438, 2438, 2438, 2438, 2438, 2438, 2438,
+ 2438, 2438, 2438, 2438, 2438, 2438, 2438, 2438,
+ 2438, 2438, 2438, 2438, 2438, 2438, 2438, 2438,
+ 2438, 2438, 2438, 2438, 2438, 2439, 2439, 2439,
+
+ 2440, 2440, 2440, 2440, 2440, 2441, 2442, 2441,
+ 2443, 2441, 2441, 2442, 2442, 2444, 2441, 2441,
+ 2441, 2441, 2441, 2440, 2440, 2440, 2440, 2444,
+ 2440, 2440, 2440, 2440, 2440, 2441, 2440, 2440,
+
+ 2440, 2441, 2442, 2442, 2441, 2445, 2446, 323,
+ 323, 323, 323, 2447, 2447, 2447, 2447, 2448,
+ 2449, 2449, 2449, 2449, 2449, 2449, 2450, 323,
323, 323, 323, 323, 323, 323, 323, 323,
- 2447, 2447, 2447, 2447, 2447, 2447, 2447, 2447,
- 2447, 2447, 2447, 2447, 2447, 2447, 2447, 2447,
- 2447, 2447, 2447, 2447, 2447, 2447, 2447, 2447,
- 2447, 2447, 2447, 2447, 2447, 2447, 2447, 2447,
-
- 2447, 2447, 2447, 2447, 2447, 2447, 2447, 2447,
- 2447, 2447, 2447, 2447, 2447, 2447, 2447, 2447,
- 2447, 2447, 2447, 2447, 2447, 2447, 323, 323,
- 323, 2448, 2448, 2448, 2448, 2448, 2448, 2448,
-
- 2449, 2449, 2449, 2449, 2449, 2449, 2449, 2449,
- 2449, 2449, 2449, 2449, 2449, 2449, 2449, 2449,
- 2449, 2449, 2449, 2449, 2449, 2449, 323, 323,
- 2450, 2450, 2450, 2450, 2450, 2450, 2450, 2450,
+ 2451, 2451, 2451, 2451, 2451, 2451, 2451, 2451,
+ 2451, 2451, 2451, 2451, 2451, 2451, 2451, 2451,
+ 2451, 2451, 2451, 2451, 2451, 2451, 2451, 2451,
+ 2451, 2451, 2451, 2451, 2451, 2451, 2451, 2451,
2451, 2451, 2451, 2451, 2451, 2451, 2451, 2451,
2451, 2451, 2451, 2451, 2451, 2451, 2451, 2451,
- 2451, 2451, 2451, 323, 323, 323, 323, 323,
- 2452, 2452, 2452, 2452, 2452, 2452, 2452, 2452,
+ 2451, 2451, 2451, 2451, 2451, 2451, 323, 323,
+ 323, 2452, 2452, 2452, 2452, 2452, 2452, 2452,
+
+ 2453, 2453, 2453, 2453, 2453, 2453, 2453, 2453,
+ 2453, 2453, 2453, 2453, 2453, 2453, 2453, 2453,
+ 2453, 2453, 2453, 2453, 2453, 2453, 323, 323,
+ 2454, 2454, 2454, 2454, 2454, 2454, 2454, 2454,
- 2453, 2454, 2453, 2454, 2454, 2454, 2453, 2453,
- 2453, 2454, 2453, 2453, 2454, 2453, 2454, 2454,
- 2453, 2454, 323, 323, 323, 323, 323, 323,
- 323, 2455, 2455, 2455, 2455, 323, 323, 323,
+ 2455, 2455, 2455, 2455, 2455, 2455, 2455, 2455,
+ 2455, 2455, 2455, 2455, 2455, 2455, 2455, 2455,
+ 2455, 2455, 2455, 323, 323, 323, 323, 323,
+ 2456, 2456, 2456, 2456, 2456, 2456, 2456, 2456,
+
+ 2457, 2458, 2457, 2458, 2458, 2458, 2457, 2457,
+ 2457, 2458, 2457, 2457, 2458, 2457, 2458, 2458,
+ 2457, 2458, 323, 323, 323, 323, 323, 323,
+ 323, 2459, 2459, 2459, 2459, 323, 323, 323,
323, 323, 323, 323, 323, 323, 323, 323,
- 323, 2456, 2456, 2456, 2456, 2457, 2457, 2458,
+ 323, 2460, 2460, 2460, 2460, 2461, 2461, 2462,
323, 323, 323, 323, 323, 323, 323, 323,
323, 323, 323, 323, 323, 323, 323, 323,
- 2459, 2459, 2459, 2459, 2459, 2459, 2459, 2459,
- 2459, 2459, 2459, 2459, 2459, 2459, 2459, 2459,
- 2459, 2459, 2459, 2459, 2459, 2459, 2459, 2459,
- 2459, 2459, 2459, 2459, 2459, 2459, 2459, 2459,
+ 2463, 2463, 2463, 2463, 2463, 2463, 2463, 2463,
+ 2463, 2463, 2463, 2463, 2463, 2463, 2463, 2463,
+ 2463, 2463, 2463, 2463, 2463, 2463, 2463, 2463,
+ 2463, 2463, 2463, 2463, 2463, 2463, 2463, 2463,
- 2459, 2459, 2459, 2459, 2459, 2459, 2459, 2459,
- 2459, 323, 323, 323, 323, 323, 323, 323,
+ 2463, 2463, 2463, 2463, 2463, 2463, 2463, 2463,
+ 2463, 323, 323, 323, 323, 323, 323, 323,
323, 323, 323, 323, 323, 323, 323, 323,
323, 323, 323, 323, 323, 323, 323, 323,
- 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460,
- 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460,
- 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460,
- 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460,
+ 2464, 2464, 2464, 2464, 2464, 2464, 2464, 2464,
+ 2464, 2464, 2464, 2464, 2464, 2464, 2464, 2464,
+ 2464, 2464, 2464, 2464, 2464, 2464, 2464, 2464,
+ 2464, 2464, 2464, 2464, 2464, 2464, 2464, 2464,
- 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460,
- 2460, 2460, 2460, 2460, 2460, 2460, 2460, 2460,
- 2460, 2460, 2460, 323, 323, 323, 323, 323,
+ 2464, 2464, 2464, 2464, 2464, 2464, 2464, 2464,
+ 2464, 2464, 2464, 2464, 2464, 2464, 2464, 2464,
+ 2464, 2464, 2464, 323, 323, 323, 323, 323,
323, 323, 323, 323, 323, 323, 323, 323,
- 2461, 2461, 2461, 2461, 2461, 2461, 2461, 2461,
- 2461, 2461, 2461, 2461, 2461, 2461, 2461, 2461,
- 2461, 2461, 2461, 2461, 2461, 2461, 2461, 2461,
- 2461, 2461, 2461, 2461, 2461, 2461, 2461, 2461,
+ 2465, 2465, 2465, 2465, 2465, 2465, 2465, 2465,
+ 2465, 2465, 2465, 2465, 2465, 2465, 2465, 2465,
+ 2465, 2465, 2465, 2465, 2465, 2465, 2465, 2465,
+ 2465, 2465, 2465, 2465, 2465, 2465, 2465, 2465,
- 2461, 2461, 2461, 2461, 2461, 2461, 2461, 2461,
- 2461, 2461, 2461, 2461, 2461, 2461, 2461, 2461,
- 2461, 2461, 2461, 323, 323, 323, 323, 323,
- 323, 323, 2462, 2462, 2462, 2462, 2462, 2462,
+ 2465, 2465, 2465, 2465, 2465, 2465, 2465, 2465,
+ 2465, 2465, 2465, 2465, 2465, 2465, 2465, 2465,
+ 2465, 2465, 2465, 323, 323, 323, 323, 323,
+ 323, 323, 2466, 2466, 2466, 2466, 2466, 2466,
- 2463, 2464, 2464, 2464, 2464, 2464, 2464, 2464,
- 2464, 2464, 2464, 2464, 2464, 2464, 2464, 2464,
- 2464, 2464, 2464, 2464, 2464, 2464, 2464, 2464,
- 2464, 2464, 2464, 2464, 2464, 2464, 2464, 2464,
+ 2467, 2468, 2468, 2468, 2468, 2468, 2468, 2468,
+ 2468, 2468, 2468, 2468, 2468, 2468, 2468, 2468,
+ 2468, 2468, 2468, 2468, 2468, 2468, 2468, 2468,
+ 2468, 2468, 2468, 2468, 2468, 2468, 2468, 2468,
- 2464, 2464, 2465, 2464, 2466, 2466, 2466, 2466,
+ 2468, 2468, 2469, 2468, 2470, 2470, 2470, 2470,
323, 323, 323, 323, 323, 323, 323, 323,
- 2467, 2468, 2469, 2470, 2471, 2472, 2473, 2474,
- 2475, 2476, 323, 323, 323, 323, 323, 323,
-
- 2477, 2478, 2479, 2480, 2481, 2482, 2483, 2484,
- 2485, 2486, 2486, 2486, 2486, 2486, 2486, 2486,
- 2486, 2486, 2486, 2486, 2486, 2486, 2486, 2486,
- 2486, 2486, 2486, 2486, 2486, 2486, 2486, 323,
-
- 2487, 2487, 2487, 2487, 2487, 2487, 2487, 2487,
- 2487, 2487, 2487, 2487, 2487, 2487, 2487, 2487,
- 2487, 2487, 2487, 2487, 2487, 2487, 2487, 2487,
- 2487, 2487, 2487, 2487, 2487, 2487, 2487, 2487,
-
- 2487, 2487, 2487, 2487, 2487, 2487, 2487, 2487,
- 2487, 2487, 323, 2488, 2488, 2489, 323, 323,
- 2487, 2487, 323, 323, 323, 323, 323, 323,
+ 2471, 2472, 2473, 2474, 2475, 2476, 2477, 2478,
+ 2479, 2480, 323, 323, 323, 323, 323, 323,
+
+ 2481, 2482, 2483, 2484, 2485, 2486, 2487, 2488,
+ 2489, 2490, 2490, 2490, 2490, 2490, 2490, 2490,
+ 2490, 2490, 2490, 2490, 2490, 2490, 2490, 2490,
+ 2490, 2490, 2490, 2490, 2490, 2490, 2490, 323,
+
+ 2491, 2491, 2491, 2491, 2491, 2491, 2491, 2491,
+ 2491, 2491, 2491, 2491, 2491, 2491, 2491, 2491,
+ 2491, 2491, 2491, 2491, 2491, 2491, 2491, 2491,
+ 2491, 2491, 2491, 2491, 2491, 2491, 2491, 2491,
+
+ 2491, 2491, 2491, 2491, 2491, 2491, 2491, 2491,
+ 2491, 2491, 323, 2492, 2492, 2493, 323, 323,
+ 2491, 2491, 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, 2490, 2490, 2490,
+ 323, 323, 323, 323, 323, 2494, 2494, 2494,
- 2491, 2491, 2491, 2491, 2491, 2491, 2491, 2491,
- 2491, 2491, 2491, 2491, 2491, 2491, 2491, 2491,
- 2491, 2491, 2491, 2491, 2491, 2491, 2491, 2491,
- 2491, 2491, 2491, 2491, 2491, 2492, 2492, 2492,
+ 2495, 2495, 2495, 2495, 2495, 2495, 2495, 2495,
+ 2495, 2495, 2495, 2495, 2495, 2495, 2495, 2495,
+ 2495, 2495, 2495, 2495, 2495, 2495, 2495, 2495,
+ 2495, 2495, 2495, 2495, 2495, 2496, 2496, 2496,
- 2492, 2492, 2492, 2492, 2492, 2492, 2492, 2491,
+ 2496, 2496, 2496, 2496, 2496, 2496, 2496, 2495,
323, 323, 323, 323, 323, 323, 323, 323,
- 2493, 2493, 2493, 2494, 2493, 2493, 2493, 2493,
- 2493, 2493, 2493, 2493, 2493, 2493, 2493, 2493,
+ 2497, 2497, 2497, 2498, 2497, 2497, 2497, 2497,
+ 2497, 2497, 2497, 2497, 2497, 2497, 2497, 2497,
- 2493, 2493, 2493, 2493, 2493, 2495, 2496, 2496,
- 2497, 2497, 2497, 2496, 2497, 2496, 2496, 2496,
- 2496, 2498, 2498, 2498, 2499, 2500, 2500, 2500,
- 2500, 2500, 323, 323, 323, 323, 323, 323,
+ 2497, 2497, 2497, 2497, 2497, 2499, 2500, 2500,
+ 2501, 2501, 2501, 2500, 2501, 2500, 2500, 2500,
+ 2500, 2502, 2502, 2502, 2503, 2504, 2504, 2504,
+ 2504, 2504, 323, 323, 323, 323, 323, 323,
323, 323, 323, 323, 323, 323, 323, 323,
323, 323, 323, 323, 323, 323, 323, 323,
- 2501, 2501, 2501, 2501, 2502, 2502, 2501, 2501,
- 2501, 2501, 2501, 2501, 2501, 2501, 2501, 2501,
+ 2505, 2505, 2505, 2505, 2506, 2506, 2505, 2505,
+ 2505, 2505, 2505, 2505, 2505, 2505, 2505, 2505,
- 2501, 2501, 2503, 2504, 2503, 2504, 2505, 2505,
- 2505, 2505, 323, 323, 323, 323, 323, 323,
+ 2505, 2505, 2507, 2508, 2507, 2508, 2509, 2509,
+ 2509, 2509, 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,
- 2506, 2507, 2506, 2506, 2508, 2508, 2508, 2507,
- 2506, 2508, 2508, 2506, 2506, 2508, 2506, 2506,
+ 2510, 2511, 2510, 2510, 2512, 2512, 2512, 2511,
+ 2510, 2512, 2512, 2510, 2510, 2512, 2510, 2510,
- 2507, 2506, 2508, 2508, 2506, 2509, 2509, 2509,
- 2509, 2510, 2511, 2512, 323, 323, 323, 323,
+ 2511, 2510, 2512, 2512, 2510, 2513, 2513, 2513,
+ 2513, 2514, 2515, 2516, 323, 323, 323, 323,
323, 323, 323, 323, 323, 323, 323, 323,
323, 323, 323, 323, 323, 323, 323, 323,
- 2513, 2513, 2513, 2513, 2513, 2513, 2513, 2513,
- 2513, 2513, 2513, 2513, 2513, 2513, 2513, 2513,
- 2513, 2513, 2513, 2513, 2513, 2513, 2513, 323,
+ 2517, 2517, 2517, 2517, 2517, 2517, 2517, 2517,
+ 2517, 2517, 2517, 2517, 2517, 2517, 2517, 2517,
+ 2517, 2517, 2517, 2517, 2517, 2517, 2517, 323,
323, 323, 323, 323, 323, 323, 323, 323,
- 2514, 2515, 2514, 2516, 2516, 2516, 2516, 2516,
- 2516, 2516, 2516, 2516, 2516, 2516, 2516, 2516,
- 2516, 2516, 2516, 2516, 2516, 2516, 2516, 2516,
- 2516, 2516, 2516, 2516, 2516, 2516, 2516, 2516,
- 2516, 2516, 2516, 2516, 2516, 2516, 2516, 2516,
- 2516, 2516, 2516, 2516, 2516, 2516, 2516, 2516,
- 2516, 2516, 2516, 2516, 2516, 2516, 2516, 2516,
- 2515, 2515, 2515, 2515, 2515, 2515, 2515, 2515,
- 2515, 2515, 2515, 2515, 2515, 2515, 2517, 2518,
- 2518, 2519, 2519, 2519, 2519, 2519, 221, 221,
- 221, 221, 2520, 2521, 2522, 2523, 2524, 2525,
- 2526, 2527, 2528, 2529, 2529, 2529, 2529, 2529,
- 2529, 2529, 2529, 2529, 2529, 2529, 2530, 2531,
- 2532, 2533, 2534, 2535, 2536, 2537, 2538, 2539,
- 2540, 2541, 2541, 2542, 2542, 2541, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 2543,
- 2544, 2544, 2545, 2546, 2546, 2546, 2546, 2546,
- 2546, 2546, 2546, 2546, 2546, 2546, 2546, 2546,
- 2546, 2546, 2546, 2546, 2546, 2546, 2546, 2546,
- 2546, 2546, 2547, 2546, 2547, 2546, 2546, 2546,
- 2546, 2546, 2546, 2546, 2546, 2546, 2546, 2546,
- 2546, 2546, 2546, 2547, 2546, 2546, 2546, 2546,
- 2545, 2545, 2545, 2544, 2544, 2544, 2544, 2545,
- 2545, 2548, 2549, 2550, 2550, 2551, 2552, 2552,
- 2552, 2552, 2553, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 2554, 221, 221,
- 2555, 2555, 2555, 2555, 2555, 2555, 2555, 2555,
- 2555, 2555, 2555, 2555, 2555, 2555, 2555, 2555,
- 2555, 2555, 2555, 2555, 2555, 2555, 2555, 2555,
- 2555, 221, 221, 221, 221, 221, 221, 221,
- 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563,
- 2564, 2565, 221, 221, 221, 221, 221, 221,
-
- 2566, 2566, 2566, 2567, 2567, 2567, 2567, 2567,
- 2567, 2567, 2567, 2567, 2567, 2567, 2567, 2567,
- 2567, 2567, 2567, 2567, 2567, 2567, 2567, 2567,
- 2567, 2567, 2567, 2567, 2567, 2567, 2567, 2567,
- 2567, 2567, 2567, 2567, 2567, 2567, 2567, 2568,
- 2569, 2569, 2569, 2569, 2570, 2569, 2571, 2571,
- 2569, 2569, 2569, 2572, 2572, 221, 2573, 2574,
- 2575, 2576, 2577, 2578, 2579, 2580, 2581, 2582,
- 2583, 2584, 2584, 2584, 2585, 2586, 2586, 2587,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 2588, 2588, 2588, 2588, 2588, 2588, 2588, 2588,
- 2588, 2588, 2588, 2588, 2588, 2588, 2588, 2588,
- 2588, 2588, 2588, 2588, 2588, 2588, 2588, 2588,
- 2588, 2588, 2588, 2588, 2588, 2588, 2588, 2588,
- 2588, 2588, 2588, 2589, 2590, 2591, 2588, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 2592, 2592, 2593, 2594, 2594, 2594, 2594, 2594,
- 2594, 2594, 2594, 2594, 2594, 2594, 2594, 2594,
- 2594, 2594, 2594, 2594, 2594, 2594, 2594, 2594,
- 2594, 2594, 2594, 2594, 2594, 2594, 2594, 2594,
- 2594, 2594, 2594, 2594, 2594, 2594, 2594, 2594,
- 2594, 2594, 2594, 2594, 2594, 2594, 2594, 2594,
- 2594, 2594, 2594, 2593, 2593, 2593, 2592, 2592,
- 2592, 2592, 2592, 2592, 2592, 2592, 2592, 2593,
- 2595, 2594, 2596, 2596, 2594, 2597, 2597, 2598,
- 2599, 2600, 2601, 2600, 2600, 2602, 2603, 2604,
- 2605, 2606, 2607, 2608, 2609, 2610, 2611, 2612,
- 2613, 2614, 2615, 2616, 2617, 2618, 2619, 2619,
- 221, 2620, 2620, 2620, 2620, 2620, 2620, 2620,
- 2620, 2620, 2620, 2620, 2620, 2620, 2620, 2620,
- 2620, 2620, 2620, 2620, 2620, 221, 221, 221,
+ 2518, 2519, 2518, 2520, 2520, 2520, 2520, 2520,
+ 2520, 2520, 2520, 2520, 2520, 2520, 2520, 2520,
+ 2520, 2520, 2520, 2520, 2520, 2520, 2520, 2520,
+ 2520, 2520, 2520, 2520, 2520, 2520, 2520, 2520,
+ 2520, 2520, 2520, 2520, 2520, 2520, 2520, 2520,
+ 2520, 2520, 2520, 2520, 2520, 2520, 2520, 2520,
+ 2520, 2520, 2520, 2520, 2520, 2520, 2520, 2520,
+ 2519, 2519, 2519, 2519, 2519, 2519, 2519, 2519,
+ 2519, 2519, 2519, 2519, 2519, 2519, 2521, 2522,
+ 2522, 2523, 2523, 2523, 2523, 2523, 221, 221,
+ 221, 221, 2524, 2525, 2526, 2527, 2528, 2529,
+ 2530, 2531, 2532, 2533, 2533, 2533, 2533, 2533,
+ 2533, 2533, 2533, 2533, 2533, 2533, 2534, 2535,
+ 2536, 2537, 2538, 2539, 2540, 2541, 2542, 2543,
+ 2544, 2545, 2545, 2546, 2546, 2545, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 2547,
+ 2548, 2548, 2549, 2550, 2550, 2550, 2550, 2550,
+ 2550, 2550, 2550, 2550, 2550, 2550, 2550, 2550,
+ 2550, 2550, 2550, 2550, 2550, 2550, 2550, 2550,
+ 2550, 2550, 2551, 2550, 2551, 2550, 2550, 2550,
+ 2550, 2550, 2550, 2550, 2550, 2550, 2550, 2550,
+ 2550, 2550, 2550, 2551, 2550, 2550, 2550, 2550,
+ 2549, 2549, 2549, 2548, 2548, 2548, 2548, 2549,
+ 2549, 2552, 2553, 2554, 2554, 2555, 2556, 2556,
+ 2556, 2556, 2557, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 2558, 221, 221,
+ 2559, 2559, 2559, 2559, 2559, 2559, 2559, 2559,
+ 2559, 2559, 2559, 2559, 2559, 2559, 2559, 2559,
+ 2559, 2559, 2559, 2559, 2559, 2559, 2559, 2559,
+ 2559, 221, 221, 221, 221, 221, 221, 221,
+ 2560, 2561, 2562, 2563, 2564, 2565, 2566, 2567,
+ 2568, 2569, 221, 221, 221, 221, 221, 221,
+
+ 2570, 2570, 2570, 2571, 2571, 2571, 2571, 2571,
+ 2571, 2571, 2571, 2571, 2571, 2571, 2571, 2571,
+ 2571, 2571, 2571, 2571, 2571, 2571, 2571, 2571,
+ 2571, 2571, 2571, 2571, 2571, 2571, 2571, 2571,
+ 2571, 2571, 2571, 2571, 2571, 2571, 2571, 2572,
+ 2573, 2573, 2573, 2573, 2574, 2573, 2575, 2575,
+ 2573, 2573, 2573, 2576, 2576, 221, 2577, 2578,
+ 2579, 2580, 2581, 2582, 2583, 2584, 2585, 2586,
+ 2587, 2588, 2588, 2588, 2589, 2590, 2590, 2591,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 2592, 2592, 2592, 2592, 2592, 2592, 2592, 2592,
+ 2592, 2592, 2592, 2592, 2592, 2592, 2592, 2592,
+ 2592, 2592, 2592, 2592, 2592, 2592, 2592, 2592,
+ 2592, 2592, 2592, 2592, 2592, 2592, 2592, 2592,
+ 2592, 2592, 2592, 2593, 2594, 2595, 2592, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 2596, 2596, 2597, 2598, 2598, 2598, 2598, 2598,
+ 2598, 2598, 2598, 2598, 2598, 2598, 2598, 2598,
+ 2598, 2598, 2598, 2598, 2598, 2598, 2598, 2598,
+ 2598, 2598, 2598, 2598, 2598, 2598, 2598, 2598,
+ 2598, 2598, 2598, 2598, 2598, 2598, 2598, 2598,
+ 2598, 2598, 2598, 2598, 2598, 2598, 2598, 2598,
+ 2598, 2598, 2598, 2597, 2597, 2597, 2596, 2596,
+ 2596, 2596, 2596, 2596, 2596, 2596, 2596, 2597,
+ 2599, 2598, 2600, 2600, 2598, 2601, 2601, 2602,
+ 2603, 2604, 2605, 2604, 2604, 2606, 2607, 2608,
+ 2609, 2610, 2611, 2612, 2613, 2614, 2615, 2616,
+ 2617, 2618, 2619, 2620, 2621, 2622, 2623, 2623,
+ 221, 2624, 2624, 2624, 2624, 2624, 2624, 2624,
+ 2624, 2624, 2624, 2624, 2624, 2624, 2624, 2624,
+ 2624, 2624, 2624, 2624, 2624, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2621, 2621, 2621, 2621, 2621, 2621, 2621, 2621,
- 2621, 2621, 2621, 2621, 2621, 2621, 2621, 2621,
- 2621, 2621, 221, 2621, 2621, 2621, 2621, 2621,
- 2621, 2621, 2621, 2621, 2621, 2621, 2621, 2621,
- 2621, 2621, 2621, 2621, 2621, 2621, 2621, 2621,
- 2621, 2621, 2621, 2621, 2622, 2622, 2622, 2623,
- 2623, 2623, 2622, 2622, 2623, 2624, 2625, 2623,
- 2626, 2626, 2627, 2626, 2626, 2627, 2628, 2629,
- 2629, 2630, 221, 221, 221, 221, 221, 221,
+ 2625, 2625, 2625, 2625, 2625, 2625, 2625, 2625,
+ 2625, 2625, 2625, 2625, 2625, 2625, 2625, 2625,
+ 2625, 2625, 221, 2625, 2625, 2625, 2625, 2625,
+ 2625, 2625, 2625, 2625, 2625, 2625, 2625, 2625,
+ 2625, 2625, 2625, 2625, 2625, 2625, 2625, 2625,
+ 2625, 2625, 2625, 2625, 2626, 2626, 2626, 2627,
+ 2627, 2627, 2626, 2626, 2627, 2628, 2629, 2627,
+ 2630, 2630, 2631, 2630, 2630, 2631, 2632, 2633,
+ 2633, 2634, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -3723,38 +3723,38 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2631, 2631, 2631, 2631, 2631, 2631, 2631, 221,
- 2631, 221, 2631, 2631, 2631, 2631, 221, 2631,
- 2631, 2631, 2631, 2631, 2631, 2631, 2631, 2631,
- 2631, 2631, 2631, 2631, 2631, 2631, 221, 2631,
- 2631, 2631, 2631, 2631, 2631, 2631, 2631, 2631,
- 2631, 2632, 221, 221, 221, 221, 221, 221,
- 2633, 2633, 2633, 2633, 2633, 2633, 2633, 2633,
- 2633, 2633, 2633, 2633, 2633, 2633, 2633, 2633,
- 2633, 2633, 2633, 2633, 2633, 2633, 2633, 2633,
- 2633, 2633, 2633, 2633, 2633, 2633, 2633, 2633,
- 2633, 2633, 2633, 2633, 2633, 2633, 2633, 2633,
- 2633, 2633, 2633, 2633, 2633, 2633, 2633, 2634,
- 2635, 2635, 2635, 2634, 2634, 2634, 2634, 2634,
- 2634, 2636, 2637, 221, 221, 221, 221, 221,
- 2638, 2639, 2640, 2641, 2642, 2643, 2644, 2645,
- 2646, 2647, 221, 221, 221, 221, 221, 221,
+ 2635, 2635, 2635, 2635, 2635, 2635, 2635, 221,
+ 2635, 221, 2635, 2635, 2635, 2635, 221, 2635,
+ 2635, 2635, 2635, 2635, 2635, 2635, 2635, 2635,
+ 2635, 2635, 2635, 2635, 2635, 2635, 221, 2635,
+ 2635, 2635, 2635, 2635, 2635, 2635, 2635, 2635,
+ 2635, 2636, 221, 221, 221, 221, 221, 221,
+ 2637, 2637, 2637, 2637, 2637, 2637, 2637, 2637,
+ 2637, 2637, 2637, 2637, 2637, 2637, 2637, 2637,
+ 2637, 2637, 2637, 2637, 2637, 2637, 2637, 2637,
+ 2637, 2637, 2637, 2637, 2637, 2637, 2637, 2637,
+ 2637, 2637, 2637, 2637, 2637, 2637, 2637, 2637,
+ 2637, 2637, 2637, 2637, 2637, 2637, 2637, 2638,
+ 2639, 2639, 2639, 2638, 2638, 2638, 2638, 2638,
+ 2638, 2640, 2641, 221, 221, 221, 221, 221,
+ 2642, 2643, 2644, 2645, 2646, 2647, 2648, 2649,
+ 2650, 2651, 221, 221, 221, 221, 221, 221,
- 2648, 2649, 2650, 2650, 221, 2651, 2651, 2651,
- 2651, 2651, 2651, 2651, 2651, 221, 221, 2651,
- 2651, 221, 221, 2651, 2651, 2651, 2651, 2651,
- 2651, 2651, 2651, 2651, 2651, 2651, 2651, 2651,
- 2651, 2651, 2651, 2651, 2651, 2651, 2651, 2651,
- 2651, 221, 2651, 2651, 2651, 2651, 2651, 2651,
- 2651, 221, 2651, 2651, 221, 2651, 2651, 2651,
- 2651, 2651, 221, 2652, 2653, 2651, 2654, 2650,
- 2649, 2650, 2650, 2650, 2650, 221, 221, 2650,
- 2650, 221, 221, 2655, 2655, 2656, 221, 221,
- 2657, 221, 221, 221, 221, 221, 221, 2654,
- 221, 221, 221, 221, 221, 2651, 2651, 2651,
- 2651, 2651, 2650, 2650, 221, 221, 2658, 2658,
- 2658, 2658, 2658, 2658, 2658, 221, 221, 221,
- 2658, 2658, 2658, 2658, 2658, 221, 221, 221,
+ 2652, 2653, 2654, 2654, 221, 2655, 2655, 2655,
+ 2655, 2655, 2655, 2655, 2655, 221, 221, 2655,
+ 2655, 221, 221, 2655, 2655, 2655, 2655, 2655,
+ 2655, 2655, 2655, 2655, 2655, 2655, 2655, 2655,
+ 2655, 2655, 2655, 2655, 2655, 2655, 2655, 2655,
+ 2655, 221, 2655, 2655, 2655, 2655, 2655, 2655,
+ 2655, 221, 2655, 2655, 221, 2655, 2655, 2655,
+ 2655, 2655, 221, 2656, 2657, 2658, 2659, 2654,
+ 2653, 2654, 2654, 2654, 2654, 221, 221, 2654,
+ 2654, 221, 221, 2660, 2660, 2661, 221, 221,
+ 2662, 221, 221, 221, 221, 221, 221, 2659,
+ 221, 221, 221, 221, 221, 2658, 2655, 2655,
+ 2655, 2655, 2654, 2654, 221, 221, 2663, 2663,
+ 2663, 2663, 2663, 2663, 2663, 221, 221, 221,
+ 2663, 2663, 2663, 2663, 2663, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -3773,34 +3773,34 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2659, 2659, 2659, 2659, 2659, 2659, 2659, 2659,
- 2659, 2659, 2659, 2659, 2659, 2659, 2659, 2659,
- 2659, 2659, 2659, 2659, 2659, 2659, 2659, 2659,
- 2659, 2659, 2659, 2659, 2659, 2659, 2659, 2659,
- 2659, 2659, 2659, 2659, 2659, 2659, 2659, 2659,
- 2659, 2659, 2659, 2659, 2659, 2659, 2659, 2659,
- 2659, 2659, 2659, 2659, 2659, 2660, 2660, 2660,
- 2661, 2661, 2661, 2661, 2661, 2661, 2661, 2661,
- 2660, 2660, 2662, 2661, 2661, 2660, 2663, 2659,
- 2659, 2659, 2659, 2664, 2664, 2665, 2665, 2666,
- 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674,
- 2675, 2676, 2677, 2665, 221, 2666, 2678, 2679,
- 2680, 2680, 221, 221, 221, 221, 221, 221,
+ 2664, 2664, 2664, 2664, 2664, 2664, 2664, 2664,
+ 2664, 2664, 2664, 2664, 2664, 2664, 2664, 2664,
+ 2664, 2664, 2664, 2664, 2664, 2664, 2664, 2664,
+ 2664, 2664, 2664, 2664, 2664, 2664, 2664, 2664,
+ 2664, 2664, 2664, 2664, 2664, 2664, 2664, 2664,
+ 2664, 2664, 2664, 2664, 2664, 2664, 2664, 2664,
+ 2664, 2664, 2664, 2664, 2664, 2665, 2665, 2665,
+ 2666, 2666, 2666, 2666, 2666, 2666, 2666, 2666,
+ 2665, 2665, 2667, 2666, 2666, 2665, 2668, 2664,
+ 2664, 2664, 2664, 2669, 2669, 2670, 2670, 2671,
+ 2672, 2673, 2674, 2675, 2676, 2677, 2678, 2679,
+ 2680, 2681, 2682, 2670, 221, 2671, 2683, 2684,
+ 2685, 2685, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2681, 2681, 2681, 2681, 2681, 2681, 2681, 2681,
- 2681, 2681, 2681, 2681, 2681, 2681, 2681, 2681,
- 2681, 2681, 2681, 2681, 2681, 2681, 2681, 2681,
- 2681, 2681, 2681, 2681, 2681, 2681, 2681, 2681,
- 2681, 2681, 2681, 2681, 2681, 2681, 2681, 2681,
- 2681, 2681, 2681, 2681, 2681, 2681, 2681, 2681,
- 2682, 2683, 2683, 2684, 2684, 2684, 2684, 2684,
- 2684, 2683, 2685, 2686, 2686, 2682, 2686, 2684,
- 2684, 2683, 2687, 2688, 2681, 2681, 2689, 2681,
+ 2686, 2686, 2686, 2686, 2686, 2686, 2686, 2686,
+ 2686, 2686, 2686, 2686, 2686, 2686, 2686, 2686,
+ 2686, 2686, 2686, 2686, 2686, 2686, 2686, 2686,
+ 2686, 2686, 2686, 2686, 2686, 2686, 2686, 2686,
+ 2686, 2686, 2686, 2686, 2686, 2686, 2686, 2686,
+ 2686, 2686, 2686, 2686, 2686, 2686, 2686, 2686,
+ 2687, 2688, 2688, 2689, 2689, 2689, 2689, 2689,
+ 2689, 2688, 2690, 2691, 2691, 2687, 2691, 2689,
+ 2689, 2688, 2692, 2693, 2686, 2686, 2694, 2686,
221, 221, 221, 221, 221, 221, 221, 221,
- 2690, 2691, 2692, 2693, 2694, 2695, 2696, 2697,
- 2698, 2699, 221, 221, 221, 221, 221, 221,
+ 2695, 2696, 2697, 2698, 2699, 2700, 2701, 2702,
+ 2703, 2704, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -3822,49 +3822,49 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700,
- 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700,
- 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700,
- 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700,
- 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700,
- 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2701,
- 2702, 2702, 2703, 2703, 2703, 2703, 221, 221,
- 2702, 2702, 2704, 2704, 2703, 2703, 2702, 2705,
- 2706, 2707, 2708, 2708, 2709, 2709, 2710, 2710,
- 2710, 2708, 2711, 2711, 2711, 2711, 2711, 2711,
- 2711, 2711, 2711, 2711, 2711, 2711, 2711, 2711,
- 2712, 2712, 2712, 2712, 2713, 2713, 221, 221,
+ 2705, 2705, 2705, 2705, 2705, 2705, 2705, 2705,
+ 2705, 2705, 2705, 2705, 2705, 2705, 2705, 2705,
+ 2705, 2705, 2705, 2705, 2705, 2705, 2705, 2705,
+ 2705, 2705, 2705, 2705, 2705, 2705, 2705, 2705,
+ 2705, 2705, 2705, 2705, 2705, 2705, 2705, 2705,
+ 2705, 2705, 2705, 2705, 2705, 2705, 2705, 2706,
+ 2707, 2707, 2708, 2708, 2708, 2708, 221, 221,
+ 2707, 2707, 2709, 2709, 2708, 2708, 2707, 2710,
+ 2711, 2712, 2713, 2713, 2714, 2714, 2715, 2715,
+ 2715, 2713, 2716, 2716, 2716, 2716, 2716, 2716,
+ 2716, 2716, 2716, 2716, 2716, 2716, 2716, 2716,
+ 2717, 2717, 2717, 2717, 2718, 2718, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2714, 2714, 2714, 2714, 2714, 2714, 2714, 2714,
- 2714, 2714, 2714, 2714, 2714, 2714, 2714, 2714,
- 2714, 2714, 2714, 2714, 2714, 2714, 2714, 2714,
- 2714, 2714, 2714, 2714, 2714, 2714, 2714, 2714,
- 2714, 2714, 2714, 2714, 2714, 2714, 2714, 2714,
- 2714, 2714, 2714, 2714, 2714, 2714, 2714, 2714,
- 2715, 2715, 2715, 2716, 2716, 2716, 2716, 2716,
- 2716, 2716, 2716, 2715, 2715, 2716, 2715, 2717,
- 2716, 2718, 2718, 2719, 2714, 221, 221, 221,
+ 2719, 2719, 2719, 2719, 2719, 2719, 2719, 2719,
+ 2719, 2719, 2719, 2719, 2719, 2719, 2719, 2719,
+ 2719, 2719, 2719, 2719, 2719, 2719, 2719, 2719,
+ 2719, 2719, 2719, 2719, 2719, 2719, 2719, 2719,
+ 2719, 2719, 2719, 2719, 2719, 2719, 2719, 2719,
+ 2719, 2719, 2719, 2719, 2719, 2719, 2719, 2719,
+ 2720, 2720, 2720, 2721, 2721, 2721, 2721, 2721,
+ 2721, 2721, 2721, 2720, 2720, 2721, 2720, 2722,
+ 2721, 2723, 2723, 2724, 2719, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2720, 2721, 2722, 2723, 2724, 2725, 2726, 2727,
- 2728, 2729, 221, 221, 221, 221, 221, 221,
- 2730, 2730, 2730, 2730, 2730, 2730, 2730, 2730,
- 2730, 2730, 2730, 2730, 2730, 221, 221, 221,
+ 2725, 2726, 2727, 2728, 2729, 2730, 2731, 2732,
+ 2733, 2734, 221, 221, 221, 221, 221, 221,
+ 2735, 2735, 2735, 2735, 2735, 2735, 2735, 2735,
+ 2735, 2735, 2735, 2735, 2735, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2731, 2731, 2731, 2731, 2731, 2731, 2731, 2731,
- 2731, 2731, 2731, 2731, 2731, 2731, 2731, 2731,
- 2731, 2731, 2731, 2731, 2731, 2731, 2731, 2731,
- 2731, 2731, 2731, 2731, 2731, 2731, 2731, 2731,
- 2731, 2731, 2731, 2731, 2731, 2731, 2731, 2731,
- 2731, 2731, 2731, 2732, 2733, 2732, 2733, 2733,
- 2732, 2732, 2732, 2732, 2732, 2732, 2734, 2735,
- 2736, 2737, 221, 221, 221, 221, 221, 221,
- 2738, 2739, 2740, 2741, 2742, 2743, 2744, 2745,
- 2746, 2747, 221, 221, 221, 221, 221, 221,
+ 2736, 2736, 2736, 2736, 2736, 2736, 2736, 2736,
+ 2736, 2736, 2736, 2736, 2736, 2736, 2736, 2736,
+ 2736, 2736, 2736, 2736, 2736, 2736, 2736, 2736,
+ 2736, 2736, 2736, 2736, 2736, 2736, 2736, 2736,
+ 2736, 2736, 2736, 2736, 2736, 2736, 2736, 2736,
+ 2736, 2736, 2736, 2737, 2738, 2737, 2738, 2738,
+ 2737, 2737, 2737, 2737, 2737, 2737, 2739, 2740,
+ 2741, 2742, 221, 221, 221, 221, 221, 221,
+ 2743, 2744, 2745, 2746, 2747, 2748, 2749, 2750,
+ 2751, 2752, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -3872,15 +3872,15 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2748, 2748, 2748, 2748, 2748, 2748, 2748, 2748,
- 2748, 2748, 2748, 2748, 2748, 2748, 2748, 2748,
- 2748, 2748, 2748, 2748, 2748, 2748, 2748, 2748,
- 2748, 2748, 2749, 221, 221, 2750, 2750, 2750,
- 2751, 2751, 2750, 2750, 2750, 2750, 2752, 2750,
- 2750, 2750, 2750, 2753, 221, 221, 221, 221,
- 2754, 2755, 2756, 2757, 2758, 2759, 2760, 2761,
- 2762, 2763, 2764, 2764, 2765, 2765, 2765, 2766,
- 2767, 2767, 2767, 2767, 2767, 2767, 2767, 221,
+ 2753, 2753, 2753, 2753, 2753, 2753, 2753, 2753,
+ 2753, 2753, 2753, 2753, 2753, 2753, 2753, 2753,
+ 2753, 2753, 2753, 2753, 2753, 2753, 2753, 2753,
+ 2753, 2753, 2754, 221, 221, 2755, 2755, 2755,
+ 2756, 2756, 2755, 2755, 2755, 2755, 2757, 2755,
+ 2755, 2755, 2755, 2758, 221, 221, 221, 221,
+ 2759, 2760, 2761, 2762, 2763, 2764, 2765, 2766,
+ 2767, 2768, 2769, 2769, 2770, 2770, 2770, 2771,
+ 2772, 2772, 2772, 2772, 2772, 2772, 2772, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -3905,14 +3905,14 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2768, 2768, 2768, 2768, 2768, 2768, 2768, 2768,
- 2768, 2768, 2768, 2768, 2768, 2768, 2768, 2768,
- 2768, 2768, 2768, 2768, 2768, 2768, 2768, 2768,
- 2768, 2768, 2768, 2768, 2768, 2768, 2768, 2768,
- 2768, 2768, 2768, 2768, 2768, 2768, 2768, 2768,
- 2768, 2768, 2768, 2768, 2769, 2769, 2769, 2770,
- 2770, 2770, 2770, 2770, 2770, 2770, 2770, 2770,
- 2769, 2771, 2772, 2773, 221, 221, 221, 221,
+ 2773, 2773, 2773, 2773, 2773, 2773, 2773, 2773,
+ 2773, 2773, 2773, 2773, 2773, 2773, 2773, 2773,
+ 2773, 2773, 2773, 2773, 2773, 2773, 2773, 2773,
+ 2773, 2773, 2773, 2773, 2773, 2773, 2773, 2773,
+ 2773, 2773, 2773, 2773, 2773, 2773, 2773, 2773,
+ 2773, 2773, 2773, 2773, 2774, 2774, 2774, 2775,
+ 2775, 2775, 2775, 2775, 2775, 2775, 2775, 2775,
+ 2774, 2776, 2777, 2778, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -3925,87 +3925,87 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2774, 2774, 2774, 2774, 2774, 2774, 2774, 2774,
- 2774, 2774, 2774, 2774, 2774, 2774, 2774, 2774,
- 2774, 2774, 2774, 2774, 2774, 2774, 2774, 2774,
- 2774, 2774, 2774, 2774, 2774, 2774, 2774, 2774,
- 2775, 2775, 2775, 2775, 2775, 2775, 2775, 2775,
- 2775, 2775, 2775, 2775, 2775, 2775, 2775, 2775,
- 2775, 2775, 2775, 2775, 2775, 2775, 2775, 2775,
- 2775, 2775, 2775, 2775, 2775, 2775, 2775, 2775,
- 2776, 2777, 2778, 2779, 2780, 2781, 2782, 2783,
- 2784, 2785, 2786, 2786, 2786, 2786, 2786, 2786,
- 2786, 2786, 2786, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 2787,
+ 2779, 2779, 2779, 2779, 2779, 2779, 2779, 2779,
+ 2779, 2779, 2779, 2779, 2779, 2779, 2779, 2779,
+ 2779, 2779, 2779, 2779, 2779, 2779, 2779, 2779,
+ 2779, 2779, 2779, 2779, 2779, 2779, 2779, 2779,
+ 2780, 2780, 2780, 2780, 2780, 2780, 2780, 2780,
+ 2780, 2780, 2780, 2780, 2780, 2780, 2780, 2780,
+ 2780, 2780, 2780, 2780, 2780, 2780, 2780, 2780,
+ 2780, 2780, 2780, 2780, 2780, 2780, 2780, 2780,
+ 2781, 2782, 2783, 2784, 2785, 2786, 2787, 2788,
+ 2789, 2790, 2791, 2791, 2791, 2791, 2791, 2791,
+ 2791, 2791, 2791, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 2792,
- 2788, 2788, 2788, 2788, 2788, 2788, 2788, 221,
- 221, 2788, 221, 221, 2788, 2788, 2788, 2788,
- 2788, 2788, 2788, 2788, 221, 2788, 2788, 221,
- 2788, 2788, 2788, 2788, 2788, 2788, 2788, 2788,
- 2788, 2788, 2788, 2788, 2788, 2788, 2788, 2788,
- 2788, 2788, 2788, 2788, 2788, 2788, 2788, 2788,
- 2789, 2790, 2790, 2790, 2790, 2790, 221, 2790,
- 2791, 221, 221, 2792, 2792, 2793, 2794, 2795,
- 2790, 2795, 2790, 2796, 2797, 2798, 2797, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 2799, 2800, 2801, 2802, 2803, 2804, 2805, 2806,
- 2807, 2808, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
+ 2793, 2793, 2793, 2793, 2793, 2793, 2793, 221,
+ 221, 2793, 221, 221, 2793, 2793, 2793, 2793,
+ 2793, 2793, 2793, 2793, 221, 2793, 2793, 221,
+ 2793, 2793, 2793, 2793, 2793, 2793, 2793, 2793,
+ 2793, 2793, 2793, 2793, 2793, 2793, 2793, 2793,
+ 2793, 2793, 2793, 2793, 2793, 2793, 2793, 2793,
+ 2794, 2795, 2795, 2795, 2795, 2795, 221, 2795,
+ 2796, 221, 221, 2797, 2797, 2798, 2799, 2800,
+ 2795, 2800, 2795, 2801, 2802, 2803, 2802, 221,
221, 221, 221, 221, 221, 221, 221, 221,
+ 2804, 2805, 2806, 2807, 2808, 2809, 2810, 2811,
+ 2812, 2813, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2809, 2809, 2809, 2809, 2809, 2809, 2809, 2809,
- 221, 221, 2809, 2809, 2809, 2809, 2809, 2809,
- 2809, 2809, 2809, 2809, 2809, 2809, 2809, 2809,
- 2809, 2809, 2809, 2809, 2809, 2809, 2809, 2809,
- 2809, 2809, 2809, 2809, 2809, 2809, 2809, 2809,
- 2809, 2809, 2809, 2809, 2809, 2809, 2809, 2809,
- 2809, 2810, 2810, 2810, 2811, 2811, 2811, 2811,
- 221, 221, 2811, 2811, 2810, 2810, 2810, 2810,
- 2812, 2809, 2813, 2809, 2810, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
-
- 2814, 2815, 2815, 2815, 2815, 2815, 2815, 2816,
- 2816, 2815, 2815, 2814, 2814, 2814, 2814, 2814,
2814, 2814, 2814, 2814, 2814, 2814, 2814, 2814,
+ 221, 221, 2814, 2814, 2814, 2814, 2814, 2814,
2814, 2814, 2814, 2814, 2814, 2814, 2814, 2814,
2814, 2814, 2814, 2814, 2814, 2814, 2814, 2814,
2814, 2814, 2814, 2814, 2814, 2814, 2814, 2814,
- 2814, 2814, 2814, 2815, 2817, 2815, 2815, 2815,
- 2815, 2818, 2819, 2815, 2815, 2815, 2815, 2820,
- 2821, 2822, 2823, 2823, 2822, 2820, 2821, 2817,
+ 2814, 2814, 2814, 2814, 2814, 2814, 2814, 2814,
+ 2814, 2815, 2815, 2815, 2816, 2816, 2816, 2816,
+ 221, 221, 2816, 2816, 2815, 2815, 2815, 2815,
+ 2817, 2814, 2818, 2814, 2815, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+
+ 2819, 2820, 2820, 2820, 2820, 2820, 2820, 2821,
+ 2821, 2820, 2820, 2819, 2819, 2819, 2819, 2819,
+ 2819, 2819, 2819, 2819, 2819, 2819, 2819, 2819,
+ 2819, 2819, 2819, 2819, 2819, 2819, 2819, 2819,
+ 2819, 2819, 2819, 2819, 2819, 2819, 2819, 2819,
+ 2819, 2819, 2819, 2819, 2819, 2819, 2819, 2819,
+ 2819, 2819, 2819, 2820, 2822, 2820, 2820, 2820,
+ 2820, 2823, 2824, 2820, 2820, 2820, 2820, 2825,
+ 2826, 2827, 2828, 2828, 2827, 2825, 2826, 2822,
221, 221, 221, 221, 221, 221, 221, 221,
- 2824, 2825, 2825, 2825, 2825, 2825, 2825, 2826,
- 2826, 2825, 2825, 2825, 2824, 2824, 2824, 2824,
- 2824, 2824, 2824, 2824, 2824, 2824, 2824, 2824,
- 2824, 2824, 2824, 2824, 2824, 2824, 2824, 2824,
- 2824, 2824, 2824, 2824, 2824, 2824, 2824, 2824,
- 2824, 2824, 2824, 2824, 2824, 2824, 2824, 2824,
- 2824, 2824, 2824, 2824, 2827, 2827, 2828, 2828,
- 2828, 2828, 2825, 2825, 2825, 2825, 2825, 2825,
- 2825, 2825, 2825, 2825, 2825, 2825, 2825, 2826,
- 2825, 2829, 2830, 2831, 2831, 2832, 2833, 2833,
- 2833, 2830, 2830, 221, 221, 221, 221, 221,
+ 2829, 2830, 2830, 2830, 2830, 2830, 2830, 2831,
+ 2831, 2830, 2830, 2830, 2829, 2829, 2829, 2829,
+ 2829, 2829, 2829, 2829, 2829, 2829, 2829, 2829,
+ 2829, 2829, 2829, 2829, 2829, 2829, 2829, 2829,
+ 2829, 2829, 2829, 2829, 2829, 2829, 2829, 2829,
+ 2829, 2829, 2829, 2829, 2829, 2829, 2829, 2829,
+ 2829, 2829, 2829, 2829, 2832, 2832, 2833, 2833,
+ 2833, 2833, 2830, 2830, 2830, 2830, 2830, 2830,
+ 2830, 2830, 2830, 2830, 2830, 2830, 2830, 2831,
+ 2830, 2834, 2835, 2836, 2836, 2837, 2838, 2838,
+ 2838, 2835, 2835, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2834, 2834, 2834, 2834, 2834, 2834, 2834, 2834,
- 2834, 2834, 2834, 2834, 2834, 2834, 2834, 2834,
- 2835, 2835, 2835, 2835, 2835, 2835, 2835, 2835,
- 2835, 2835, 2835, 2835, 2835, 2835, 2835, 2835,
- 2835, 2835, 2835, 2835, 2835, 2835, 2835, 2835,
- 2835, 2835, 2835, 2835, 2835, 2835, 2835, 2835,
- 2835, 2835, 2835, 2835, 2835, 2835, 2835, 2835,
- 2835, 2835, 2835, 2835, 2835, 2835, 2835, 2835,
- 2835, 2835, 2835, 2835, 2835, 2835, 2835, 2835,
- 2835, 221, 221, 221, 221, 221, 221, 221,
+ 2839, 2839, 2839, 2839, 2839, 2839, 2839, 2839,
+ 2839, 2839, 2839, 2839, 2839, 2839, 2839, 2839,
+ 2840, 2840, 2840, 2840, 2840, 2840, 2840, 2840,
+ 2840, 2840, 2840, 2840, 2840, 2840, 2840, 2840,
+ 2840, 2840, 2840, 2840, 2840, 2840, 2840, 2840,
+ 2840, 2840, 2840, 2840, 2840, 2840, 2840, 2840,
+ 2840, 2840, 2840, 2840, 2840, 2840, 2840, 2840,
+ 2840, 2840, 2840, 2840, 2840, 2840, 2840, 2840,
+ 2840, 2840, 2840, 2840, 2840, 2840, 2840, 2840,
+ 2840, 221, 221, 221, 221, 221, 221, 221,
- 2836, 2836, 2836, 2836, 2836, 2836, 2836, 2836,
- 2836, 2836, 221, 221, 221, 221, 221, 221,
+ 2841, 2841, 2841, 2841, 2841, 2841, 2841, 2841,
+ 2841, 2841, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -4037,29 +4037,29 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2837, 2837, 2837, 2837, 2837, 2837, 2837, 2837,
- 2837, 221, 2837, 2837, 2837, 2837, 2837, 2837,
- 2837, 2837, 2837, 2837, 2837, 2837, 2837, 2837,
- 2837, 2837, 2837, 2837, 2837, 2837, 2837, 2837,
- 2837, 2837, 2837, 2837, 2837, 2837, 2837, 2837,
- 2837, 2837, 2837, 2837, 2837, 2837, 2837, 2838,
- 2839, 2839, 2839, 2839, 2839, 2839, 2839, 221,
- 2839, 2839, 2839, 2839, 2839, 2839, 2838, 2840,
- 2837, 2841, 2841, 2842, 2842, 2842, 221, 221,
+ 2842, 2842, 2842, 2842, 2842, 2842, 2842, 2842,
+ 2842, 221, 2842, 2842, 2842, 2842, 2842, 2842,
+ 2842, 2842, 2842, 2842, 2842, 2842, 2842, 2842,
+ 2842, 2842, 2842, 2842, 2842, 2842, 2842, 2842,
+ 2842, 2842, 2842, 2842, 2842, 2842, 2842, 2842,
+ 2842, 2842, 2842, 2842, 2842, 2842, 2842, 2843,
+ 2844, 2844, 2844, 2844, 2844, 2844, 2844, 221,
+ 2844, 2844, 2844, 2844, 2844, 2844, 2843, 2845,
+ 2842, 2846, 2846, 2847, 2847, 2847, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2843, 2844, 2845, 2846, 2847, 2848, 2849, 2850,
- 2851, 2852, 2853, 2853, 2853, 2853, 2853, 2853,
- 2853, 2853, 2853, 2853, 2853, 2853, 2853, 2853,
- 2853, 2853, 2853, 2853, 2853, 221, 221, 221,
- 2854, 2855, 2856, 2856, 2856, 2856, 2856, 2856,
- 2856, 2856, 2856, 2856, 2856, 2856, 2856, 2856,
- 2856, 2856, 2856, 2856, 2856, 2856, 2856, 2856,
- 2856, 2856, 2856, 2856, 2856, 2856, 2856, 2856,
- 221, 221, 2857, 2857, 2857, 2857, 2857, 2857,
- 2857, 2857, 2857, 2857, 2857, 2857, 2857, 2857,
- 2857, 2857, 2857, 2857, 2857, 2857, 2857, 2857,
- 221, 2858, 2857, 2857, 2857, 2857, 2857, 2857,
- 2857, 2858, 2857, 2857, 2858, 2857, 2857, 221,
+ 2848, 2849, 2850, 2851, 2852, 2853, 2854, 2855,
+ 2856, 2857, 2858, 2858, 2858, 2858, 2858, 2858,
+ 2858, 2858, 2858, 2858, 2858, 2858, 2858, 2858,
+ 2858, 2858, 2858, 2858, 2858, 221, 221, 221,
+ 2859, 2860, 2861, 2861, 2861, 2861, 2861, 2861,
+ 2861, 2861, 2861, 2861, 2861, 2861, 2861, 2861,
+ 2861, 2861, 2861, 2861, 2861, 2861, 2861, 2861,
+ 2861, 2861, 2861, 2861, 2861, 2861, 2861, 2861,
+ 221, 221, 2862, 2862, 2862, 2862, 2862, 2862,
+ 2862, 2862, 2862, 2862, 2862, 2862, 2862, 2862,
+ 2862, 2862, 2862, 2862, 2862, 2862, 2862, 2862,
+ 221, 2863, 2862, 2862, 2862, 2862, 2862, 2862,
+ 2862, 2863, 2862, 2862, 2863, 2862, 2862, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -4070,28 +4070,28 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2859, 2859, 2859, 2859, 2859, 2859, 2859, 221,
- 2859, 2859, 221, 2859, 2859, 2859, 2859, 2859,
- 2859, 2859, 2859, 2859, 2859, 2859, 2859, 2859,
- 2859, 2859, 2859, 2859, 2859, 2859, 2859, 2859,
- 2859, 2859, 2859, 2859, 2859, 2859, 2859, 2859,
- 2859, 2859, 2859, 2859, 2859, 2859, 2859, 2859,
- 2859, 2860, 2860, 2860, 2860, 2860, 2860, 221,
- 221, 221, 2860, 221, 2860, 2860, 221, 2860,
- 2860, 2860, 2861, 2860, 2862, 2862, 2863, 2860,
+ 2864, 2864, 2864, 2864, 2864, 2864, 2864, 221,
+ 2864, 2864, 221, 2864, 2864, 2864, 2864, 2864,
+ 2864, 2864, 2864, 2864, 2864, 2864, 2864, 2864,
+ 2864, 2864, 2864, 2864, 2864, 2864, 2864, 2864,
+ 2864, 2864, 2864, 2864, 2864, 2864, 2864, 2864,
+ 2864, 2864, 2864, 2864, 2864, 2864, 2864, 2864,
+ 2864, 2865, 2865, 2865, 2865, 2865, 2865, 221,
+ 221, 221, 2865, 221, 2865, 2865, 221, 2865,
+ 2865, 2865, 2866, 2865, 2867, 2867, 2868, 2865,
221, 221, 221, 221, 221, 221, 221, 221,
- 2864, 2865, 2866, 2867, 2868, 2869, 2870, 2871,
- 2872, 2873, 221, 221, 221, 221, 221, 221,
- 2874, 2874, 2874, 2874, 2874, 2874, 221, 2874,
- 2874, 221, 2874, 2874, 2874, 2874, 2874, 2874,
- 2874, 2874, 2874, 2874, 2874, 2874, 2874, 2874,
- 2874, 2874, 2874, 2874, 2874, 2874, 2874, 2874,
- 2874, 2874, 2874, 2874, 2874, 2874, 2874, 2874,
- 2874, 2874, 2875, 2875, 2875, 2875, 2875, 221,
- 2876, 2876, 221, 2875, 2875, 2876, 2875, 2877,
- 2874, 221, 221, 221, 221, 221, 221, 221,
- 2878, 2879, 2880, 2881, 2882, 2883, 2884, 2885,
- 2886, 2887, 221, 221, 221, 221, 221, 221,
+ 2869, 2870, 2871, 2872, 2873, 2874, 2875, 2876,
+ 2877, 2878, 221, 221, 221, 221, 221, 221,
+ 2879, 2879, 2879, 2879, 2879, 2879, 221, 2879,
+ 2879, 221, 2879, 2879, 2879, 2879, 2879, 2879,
+ 2879, 2879, 2879, 2879, 2879, 2879, 2879, 2879,
+ 2879, 2879, 2879, 2879, 2879, 2879, 2879, 2879,
+ 2879, 2879, 2879, 2879, 2879, 2879, 2879, 2879,
+ 2879, 2879, 2880, 2880, 2880, 2880, 2880, 221,
+ 2881, 2881, 221, 2880, 2880, 2881, 2880, 2882,
+ 2879, 221, 221, 221, 221, 221, 221, 221,
+ 2883, 2884, 2885, 2886, 2887, 2888, 2889, 2890,
+ 2891, 2892, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -4131,23 +4131,23 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888,
- 2888, 2888, 2888, 2888, 2888, 2888, 2888, 2888,
- 2888, 2888, 2888, 2889, 2889, 2890, 2890, 2891,
- 2891, 221, 221, 221, 221, 221, 221, 221,
+ 2893, 2893, 2893, 2893, 2893, 2893, 2893, 2893,
+ 2893, 2893, 2893, 2893, 2893, 2893, 2893, 2893,
+ 2893, 2893, 2894, 2895, 2895, 2896, 2896, 2897,
+ 2897, 221, 221, 221, 221, 221, 221, 221,
- 2892, 2892, 2893, 2894, 2895, 2895, 2895, 2895,
- 2895, 2895, 2895, 2895, 2895, 2895, 2895, 2895,
- 2895, 221, 2895, 2895, 2895, 2895, 2895, 2895,
- 2895, 2895, 2895, 2895, 2895, 2895, 2895, 2895,
- 2895, 2895, 2895, 2895, 2895, 2895, 2895, 2895,
- 2895, 2895, 2895, 2895, 2895, 2895, 2895, 2895,
- 2895, 2895, 2895, 2895, 2894, 2894, 2892, 2892,
- 2892, 2892, 2892, 221, 221, 221, 2894, 2894,
- 2892, 2896, 2897, 2898, 2898, 2899, 2899, 2899,
- 2899, 2899, 2899, 2899, 2899, 2899, 2899, 2899,
- 2900, 2901, 2902, 2903, 2904, 2905, 2906, 2907,
- 2908, 2909, 221, 221, 221, 221, 221, 221,
+ 2898, 2898, 2899, 2900, 2901, 2901, 2901, 2901,
+ 2901, 2901, 2901, 2901, 2901, 2901, 2901, 2901,
+ 2901, 221, 2901, 2901, 2901, 2901, 2901, 2901,
+ 2901, 2901, 2901, 2901, 2901, 2901, 2901, 2901,
+ 2901, 2901, 2901, 2901, 2901, 2901, 2901, 2901,
+ 2901, 2901, 2901, 2901, 2901, 2901, 2901, 2901,
+ 2901, 2901, 2901, 2901, 2900, 2900, 2898, 2898,
+ 2898, 2898, 2898, 221, 221, 221, 2900, 2900,
+ 2898, 2902, 2903, 2904, 2904, 2905, 2905, 2905,
+ 2905, 2905, 2905, 2905, 2905, 2905, 2905, 2905,
+ 2906, 2907, 2908, 2909, 2910, 2911, 2912, 2913,
+ 2914, 2915, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -4158,70 +4158,70 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2910, 221, 221, 221, 221, 221, 221, 221,
+ 2916, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2911, 2911, 2911, 2911, 2911, 2911, 2911, 2911,
- 2911, 2911, 2911, 2911, 2911, 2911, 2911, 2911,
- 2911, 2911, 2911, 2911, 2911, 2912, 2912, 2912,
- 2912, 2912, 2912, 2912, 2912, 2913, 2913, 2913,
- 2913, 2912, 2912, 2912, 2912, 2912, 2912, 2912,
- 2912, 2912, 2912, 2912, 2912, 2912, 2912, 2912,
- 2912, 2912, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 2914,
-
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
-
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2915,
- 2915, 2915, 2915, 2915, 2915, 2915, 2915, 2916,
- 2916, 2916, 2916, 2916, 2916, 2916, 2916, 2916,
- 2916, 2916, 2916, 2916, 2916, 2916, 2916, 2916,
- 2916, 2916, 2916, 2916, 2916, 2916, 2916, 2916,
- 2916, 2916, 2916, 2916, 2916, 2916, 2916, 2916,
- 2916, 2916, 2916, 2916, 2916, 2916, 2916, 2916,
- 2916, 2917, 221, 221, 221, 221, 221, 221,
+ 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
+ 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
+ 2917, 2917, 2917, 2917, 2917, 2918, 2918, 2918,
+ 2918, 2918, 2918, 2918, 2918, 2919, 2919, 2919,
+ 2919, 2918, 2918, 2918, 2918, 2918, 2918, 2918,
+ 2918, 2918, 2918, 2918, 2918, 2918, 2918, 2918,
+ 2918, 2918, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 2920,
+
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2921,
+ 2921, 2921, 2921, 2921, 2921, 2921, 2921, 2922,
+ 2922, 2922, 2922, 2922, 2922, 2922, 2922, 2922,
+ 2922, 2922, 2922, 2922, 2922, 2922, 2922, 2922,
+ 2922, 2922, 2922, 2922, 2922, 2922, 2922, 2922,
+ 2922, 2922, 2922, 2922, 2922, 2922, 2922, 2922,
+ 2922, 2922, 2922, 2922, 2922, 2922, 2922, 2922,
+ 2922, 2923, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -4235,48 +4235,48 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2918, 2918, 2918, 2918, 2918, 2918, 2918, 2918,
- 2918, 2918, 2918, 2918, 2918, 2918, 2918, 2918,
- 2918, 2918, 2918, 2918, 2918, 2918, 2918, 2918,
- 2918, 2918, 2918, 2918, 2918, 2918, 2918, 2918,
- 2918, 2918, 2918, 2918, 2918, 2918, 2918, 2918,
- 2918, 2918, 2918, 2918, 2918, 2918, 2918, 2918,
- 2918, 2918, 2918, 2918, 2918, 2918, 2918, 2918,
- 2918, 2918, 2918, 2918, 2918, 2918, 2918, 2918,
- 2918, 2918, 2918, 2918, 2918, 2918, 2918, 2918,
- 2918, 2918, 2918, 2918, 2918, 2918, 2918, 2918,
- 2918, 2918, 2918, 2918, 2918, 2918, 2918, 2918,
- 2918, 2918, 2918, 2918, 2918, 2918, 2918, 2918,
- 2918, 2918, 2918, 2919, 2919, 2919, 2919, 2919,
- 2919, 2919, 2919, 2919, 2919, 2919, 2919, 221,
- 2920, 2920, 2920, 2920, 2921, 221, 221, 221,
+ 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
+ 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
+ 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
+ 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
+ 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
+ 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
+ 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
+ 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
+ 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
+ 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
+ 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
+ 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
+ 2924, 2924, 2924, 2925, 2925, 2925, 2925, 2925,
+ 2925, 2925, 2925, 2925, 2925, 2925, 2925, 221,
+ 2926, 2926, 2926, 2926, 2927, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 2917, 2917, 2917, 2917,
- 2917, 2917, 2917, 2917, 221, 221, 221, 221,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 2923, 2923, 2923, 2923,
+ 2923, 2923, 2923, 2923, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -4352,336 +4352,336 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2922, 2922, 2922, 2922, 2922, 2922, 2922, 2922,
- 2922, 2922, 2922, 2922, 2922, 2922, 2922, 2922,
- 2922, 2922, 2922, 2922, 2922, 2922, 2922, 2922,
- 2922, 2922, 2922, 2922, 2922, 2922, 2922, 2922,
- 2922, 2922, 2922, 2922, 2922, 2922, 2922, 2922,
- 2922, 2922, 2922, 2922, 2922, 2922, 2922, 2922,
- 2922, 2922, 2922, 2922, 2922, 2922, 2922, 2922,
- 2922, 2922, 2922, 2922, 2922, 2922, 2922, 2922,
- 2922, 2922, 2922, 2922, 2922, 2922, 2922, 2922,
- 2922, 2922, 2922, 2922, 2922, 2922, 2922, 2922,
- 2922, 2922, 2922, 2922, 2922, 2922, 2922, 2922,
- 2922, 2922, 2922, 2922, 2922, 2922, 2922, 2922,
- 2922, 2923, 2923, 221, 221, 221, 221, 221,
+ 2928, 2928, 2928, 2928, 2928, 2928, 2928, 2928,
+ 2928, 2928, 2928, 2928, 2928, 2928, 2928, 2928,
+ 2928, 2928, 2928, 2928, 2928, 2928, 2928, 2928,
+ 2928, 2928, 2928, 2928, 2928, 2928, 2928, 2928,
+ 2928, 2928, 2928, 2928, 2928, 2928, 2928, 2928,
+ 2928, 2928, 2928, 2928, 2928, 2928, 2928, 2928,
+ 2928, 2928, 2928, 2928, 2928, 2928, 2928, 2928,
+ 2928, 2928, 2928, 2928, 2928, 2928, 2928, 2928,
+ 2928, 2928, 2928, 2928, 2928, 2928, 2928, 2928,
+ 2928, 2928, 2928, 2928, 2928, 2928, 2928, 2928,
+ 2928, 2928, 2928, 2928, 2928, 2928, 2928, 2928,
+ 2928, 2928, 2928, 2928, 2928, 2928, 2928, 2928,
+ 2928, 2929, 2929, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
-
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2925, 2925, 2925, 2926, 2926, 2926, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2926, 2924, 2924, 2924, 2925, 2926,
- 2925, 2926, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
-
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2925, 2926, 2926, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2924,
- 2924, 2924, 2924, 2924, 2924, 2924, 2924, 2927,
- 2928, 2928, 2928, 2928, 2928, 2928, 2928, 2929,
- 2930, 2931, 2931, 2931, 2932, 2933, 2932, 2933,
- 2934, 2927, 2927, 2927, 2927, 2927, 2927, 2934,
- 2934, 2934, 2934, 2934, 2934, 2934, 2934, 2934,
- 2934, 2934, 2934, 2934, 2934, 2934, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2931, 2931, 2931, 2932, 2932, 2932, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2932, 2930, 2930, 2930, 2931, 2932,
+ 2931, 2932, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2931, 2932, 2932, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2930,
+ 2930, 2930, 2930, 2930, 2930, 2930, 2930, 2933,
+ 2934, 2934, 2934, 2934, 2934, 2934, 2934, 2935,
+ 2936, 2937, 2937, 2937, 2938, 2939, 2938, 2939,
+ 2940, 2941, 2941, 2941, 2941, 2941, 2941, 2940,
+ 2940, 2940, 2940, 2940, 2940, 2940, 2940, 2940,
+ 2940, 2940, 2940, 2940, 2940, 2940, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2936, 2937,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2943, 2944,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 2935,
- 2935, 2935, 2935, 2935, 2935, 2935, 2935, 221,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 2942,
+ 2942, 2942, 2942, 2942, 2942, 2942, 2942, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
-
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 2938, 2938, 2938, 2938, 2938, 2938, 2938,
- 2938, 221, 221, 221, 221, 221, 221, 221,
- 2939, 2939, 2939, 2939, 2939, 2939, 2939, 2939,
- 2939, 2939, 2939, 2939, 2939, 2939, 2939, 2939,
- 2939, 2939, 2939, 2939, 2939, 2939, 2939, 2939,
- 2939, 2939, 2939, 2939, 2939, 2939, 2939, 221,
- 2940, 2941, 2942, 2943, 2944, 2945, 2946, 2947,
- 2948, 2949, 221, 221, 221, 221, 2950, 2950,
- 2951, 2951, 2951, 2951, 2951, 2951, 2951, 2951,
- 2951, 2951, 2951, 2951, 2951, 2951, 2951, 2951,
- 2951, 2951, 2951, 2951, 2951, 2951, 2951, 2951,
- 2951, 2951, 2951, 2951, 2951, 2951, 2951, 2951,
- 2951, 2951, 2951, 2951, 2951, 2951, 2951, 2951,
- 2951, 2951, 2951, 2951, 2951, 2951, 2951, 2951,
- 2951, 2951, 2951, 2951, 2951, 2951, 2951, 2951,
- 2951, 2951, 2951, 2951, 2951, 2951, 2951, 2951,
- 2951, 2951, 2951, 2951, 2951, 2951, 2951, 2951,
- 2951, 2951, 2951, 2951, 2951, 2951, 2951, 221,
- 2952, 2953, 2954, 2955, 2956, 2957, 2958, 2959,
- 2960, 2961, 221, 221, 221, 221, 221, 221,
- 2962, 2962, 2962, 2962, 2962, 2962, 2962, 2962,
- 2962, 2962, 2962, 2962, 2962, 2962, 2962, 2962,
- 2962, 2962, 2962, 2962, 2962, 2962, 2962, 2962,
- 2962, 2962, 2962, 2962, 2962, 2962, 221, 221,
- 2963, 2963, 2963, 2963, 2963, 2964, 221, 221,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 2945, 2945, 2945, 2945, 2945, 2945, 2945,
+ 2945, 221, 221, 221, 221, 221, 221, 221,
+ 2946, 2946, 2946, 2946, 2946, 2946, 2946, 2946,
+ 2946, 2946, 2946, 2946, 2946, 2946, 2946, 2946,
+ 2946, 2946, 2946, 2946, 2946, 2946, 2946, 2946,
+ 2946, 2946, 2946, 2946, 2946, 2946, 2946, 221,
+ 2947, 2948, 2949, 2950, 2951, 2952, 2953, 2954,
+ 2955, 2956, 221, 221, 221, 221, 2957, 2957,
+ 2958, 2958, 2958, 2958, 2958, 2958, 2958, 2958,
+ 2958, 2958, 2958, 2958, 2958, 2958, 2958, 2958,
+ 2958, 2958, 2958, 2958, 2958, 2958, 2958, 2958,
+ 2958, 2958, 2958, 2958, 2958, 2958, 2958, 2958,
+ 2958, 2958, 2958, 2958, 2958, 2958, 2958, 2958,
+ 2958, 2958, 2958, 2958, 2958, 2958, 2958, 2958,
+ 2958, 2958, 2958, 2958, 2958, 2958, 2958, 2958,
+ 2958, 2958, 2958, 2958, 2958, 2958, 2958, 2958,
+ 2958, 2958, 2958, 2958, 2958, 2958, 2958, 2958,
+ 2958, 2958, 2958, 2958, 2958, 2958, 2958, 221,
+ 2959, 2960, 2961, 2962, 2963, 2964, 2965, 2966,
+ 2967, 2968, 221, 221, 221, 221, 221, 221,
+ 2969, 2969, 2969, 2969, 2969, 2969, 2969, 2969,
+ 2969, 2969, 2969, 2969, 2969, 2969, 2969, 2969,
+ 2969, 2969, 2969, 2969, 2969, 2969, 2969, 2969,
+ 2969, 2969, 2969, 2969, 2969, 2969, 221, 221,
+ 2970, 2970, 2970, 2970, 2970, 2971, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2965, 2965, 2965, 2965, 2965, 2965, 2965, 2965,
- 2965, 2965, 2965, 2965, 2965, 2965, 2965, 2965,
- 2965, 2965, 2965, 2965, 2965, 2965, 2965, 2965,
- 2965, 2965, 2965, 2965, 2965, 2965, 2965, 2965,
- 2965, 2965, 2965, 2965, 2965, 2965, 2965, 2965,
- 2965, 2965, 2965, 2965, 2965, 2965, 2965, 2965,
- 2966, 2966, 2966, 2966, 2966, 2966, 2966, 2967,
- 2967, 2968, 2969, 2969, 2970, 2970, 2970, 2970,
- 2971, 2971, 2971, 2971, 2967, 2970, 221, 221,
+ 2972, 2972, 2972, 2972, 2972, 2972, 2972, 2972,
+ 2972, 2972, 2972, 2972, 2972, 2972, 2972, 2972,
+ 2972, 2972, 2972, 2972, 2972, 2972, 2972, 2972,
+ 2972, 2972, 2972, 2972, 2972, 2972, 2972, 2972,
+ 2972, 2972, 2972, 2972, 2972, 2972, 2972, 2972,
+ 2972, 2972, 2972, 2972, 2972, 2972, 2972, 2972,
+ 2973, 2973, 2973, 2973, 2973, 2973, 2973, 2974,
+ 2974, 2975, 2976, 2976, 2977, 2977, 2977, 2977,
+ 2978, 2978, 2978, 2978, 2974, 2977, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2972, 2973, 2974, 2975, 2976, 2977, 2978, 2979,
- 2980, 2981, 221, 2982, 2982, 2982, 2982, 2982,
- 2982, 2982, 221, 2965, 2965, 2965, 2965, 2965,
- 2965, 2965, 2965, 2965, 2965, 2965, 2965, 2965,
- 2965, 2965, 2965, 2965, 2965, 2965, 2965, 2965,
- 221, 221, 221, 221, 221, 2965, 2965, 2965,
- 2965, 2965, 2965, 2965, 2965, 2965, 2965, 2965,
- 2965, 2965, 2965, 2965, 2965, 2965, 2965, 2965,
+ 2979, 2980, 2981, 2982, 2983, 2984, 2985, 2986,
+ 2987, 2988, 221, 2989, 2989, 2989, 2989, 2989,
+ 2989, 2989, 221, 2972, 2972, 2972, 2972, 2972,
+ 2972, 2972, 2972, 2972, 2972, 2972, 2972, 2972,
+ 2972, 2972, 2972, 2972, 2972, 2972, 2972, 2972,
+ 221, 221, 221, 221, 221, 2972, 2972, 2972,
+ 2972, 2972, 2972, 2972, 2972, 2972, 2972, 2972,
+ 2972, 2972, 2972, 2972, 2972, 2972, 2972, 2972,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -4700,23 +4700,23 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 2983, 2983, 2983, 2983, 2983, 2983, 2983, 2983,
- 2983, 2983, 2983, 2983, 2983, 2983, 2983, 2983,
- 2983, 2983, 2983, 2983, 2983, 2983, 2983, 2983,
- 2983, 2983, 2983, 2983, 2983, 2983, 2983, 2983,
- 2984, 2984, 2984, 2984, 2984, 2984, 2984, 2984,
- 2984, 2984, 2984, 2984, 2984, 2984, 2984, 2984,
- 2984, 2984, 2984, 2984, 2984, 2984, 2984, 2984,
- 2984, 2984, 2984, 2984, 2984, 2984, 2984, 2984,
- 2985, 2985, 2985, 2985, 2985, 2985, 2985, 2985,
- 2985, 2985, 2985, 2985, 2985, 2985, 2985, 2985,
- 2985, 2985, 2985, 2985, 2985, 2985, 2985, 2986,
- 2987, 2988, 2988, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 2990, 2990, 2990, 2990, 2990, 2990, 2990, 2990,
+ 2990, 2990, 2990, 2990, 2990, 2990, 2990, 2990,
+ 2990, 2990, 2990, 2990, 2990, 2990, 2990, 2990,
+ 2990, 2990, 2990, 2990, 2990, 2990, 2990, 2990,
+ 2991, 2991, 2991, 2991, 2991, 2991, 2991, 2991,
+ 2991, 2991, 2991, 2991, 2991, 2991, 2991, 2991,
+ 2991, 2991, 2991, 2991, 2991, 2991, 2991, 2991,
+ 2991, 2991, 2991, 2991, 2991, 2991, 2991, 2991,
+ 2992, 2992, 2992, 2992, 2992, 2992, 2992, 2992,
+ 2992, 2992, 2992, 2992, 2992, 2992, 2992, 2992,
+ 2992, 2992, 2992, 2992, 2992, 2992, 2992, 2993,
+ 2994, 2995, 2995, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -4730,206 +4730,206 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2989, 2989, 2989, 2989, 2989, 2989, 2989, 2989,
- 2989, 2989, 2989, 2989, 2989, 2989, 2989, 2989,
- 2989, 2989, 2989, 2989, 2989, 2989, 2989, 2989,
- 2989, 2989, 2989, 2989, 2989, 2989, 2989, 2989,
- 2989, 2989, 2989, 2989, 2989, 2989, 2989, 2989,
- 2989, 2989, 2989, 2989, 2989, 2989, 2989, 2989,
- 2989, 2989, 2989, 2989, 2989, 2989, 2989, 2989,
- 2989, 2989, 2989, 2989, 2989, 2989, 2989, 2989,
- 2989, 2989, 2989, 2989, 2989, 2990, 2990, 2990,
- 2990, 2990, 2990, 221, 221, 221, 221, 2991,
- 2989, 2992, 2992, 2992, 2992, 2992, 2992, 2992,
- 2992, 2992, 2992, 2992, 2992, 2992, 2992, 2992,
- 2992, 2992, 2992, 2992, 2992, 2992, 2992, 2992,
- 2992, 2992, 2992, 2992, 2992, 2992, 2992, 2992,
- 2992, 2992, 2992, 2992, 2992, 2992, 2992, 2992,
- 2992, 2992, 2992, 2992, 2992, 2992, 2992, 2993,
- 2993, 2993, 2993, 2993, 2993, 2993, 2993, 2993,
- 221, 221, 221, 221, 221, 221, 221, 2994,
- 2994, 2994, 2994, 2995, 2995, 2995, 2995, 2995,
- 2995, 2995, 2995, 2995, 2995, 2995, 2995, 2995,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
+ 2996, 2996, 2996, 2996, 2996, 2996, 2996, 2996,
+ 2996, 2996, 2996, 2996, 2996, 2996, 2996, 2996,
+ 2996, 2996, 2996, 2996, 2996, 2996, 2996, 2996,
+ 2996, 2996, 2996, 2996, 2996, 2996, 2996, 2996,
+ 2996, 2996, 2996, 2996, 2996, 2996, 2996, 2996,
+ 2996, 2996, 2996, 2996, 2996, 2996, 2996, 2996,
+ 2996, 2996, 2996, 2996, 2996, 2996, 2996, 2996,
+ 2996, 2996, 2996, 2996, 2996, 2996, 2996, 2996,
+ 2996, 2996, 2996, 2996, 2996, 2997, 2997, 2997,
+ 2997, 2997, 2997, 221, 221, 221, 221, 2998,
+ 2996, 2999, 2999, 2999, 2999, 2999, 2999, 2999,
+ 2999, 2999, 2999, 2999, 2999, 2999, 2999, 2999,
+ 2999, 2999, 2999, 2999, 2999, 2999, 2999, 2999,
+ 2999, 2999, 2999, 2999, 2999, 2999, 2999, 2999,
+ 2999, 2999, 2999, 2999, 2999, 2999, 2999, 2999,
+ 2999, 2999, 2999, 2999, 2999, 2999, 2999, 3000,
+ 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000,
+ 221, 221, 221, 221, 221, 221, 221, 3001,
+ 3001, 3001, 3001, 3002, 3002, 3002, 3002, 3002,
+ 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2996, 2997, 2998, 2999, 3000, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 3001, 3001, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
-
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
-
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3003, 3003, 3003,
- 3003, 3003, 3004, 3004, 3004, 3004, 3004, 3004,
221, 221, 221, 221, 221, 221, 221, 221,
+ 3003, 3004, 3005, 3006, 3007, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 3008, 3008, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3010, 3010, 3010,
+ 3010, 3010, 3011, 3011, 3011, 3011, 3011, 3011,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3009, 3009, 3009, 3009, 3009,
+ 3009, 3009, 3009, 3012, 3012, 3012, 3012, 3012,
+ 3012, 3012, 3012, 3012, 3012, 3012, 3012, 3012,
+
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3002, 3002, 3002, 3002, 3002,
- 3002, 3002, 3002, 3005, 3005, 3005, 3005, 3005,
- 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005,
-
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
-
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 3006, 3006,
- 3006, 3006, 3006, 3006, 3006, 3006, 221, 221,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 3013, 3013,
+ 3013, 3013, 3013, 3013, 3013, 3013, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 3005, 3005, 3005, 3005, 3005, 3005, 3005, 3005,
- 3005, 221, 221, 221, 221, 221, 221, 221,
+ 3012, 3012, 3012, 3012, 3012, 3012, 3012, 3012,
+ 3012, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -4991,62 +4991,10 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 3007, 3007, 3007, 3007, 221, 3007, 3007, 3007,
- 3007, 3007, 3007, 3007, 221, 3007, 3007, 221,
-
- 3008, 3009, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
+ 3014, 3014, 3014, 3014, 221, 3014, 3014, 3014,
+ 3014, 3014, 3014, 3014, 221, 3014, 3014, 221,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3010,
- 3010, 3010, 3010, 3010, 3010, 3010, 3010, 3011,
- 3012, 3012, 3012, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 3013, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 3014, 3014, 3014, 221, 221, 3015, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 3016, 3016, 3016, 3016,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
- 3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
- 3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
- 3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
- 3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
- 3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
+ 3015, 3016, 3017, 3017, 3017, 3017, 3017, 3017,
3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
@@ -5059,16 +5007,6 @@ static constexpr unsigned short uc_property_trie[] = {
3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
-
- 3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
- 3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
- 3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
- 3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
- 3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
- 3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
- 3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
- 3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
- 3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
@@ -5088,54 +5026,74 @@ static constexpr unsigned short uc_property_trie[] = {
3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
+
3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
3017, 3017, 3017, 3017, 3017, 3017, 3017, 3017,
- 3017, 3017, 3017, 3017, 221, 221, 221, 221,
-
- 3018, 3018, 3018, 3018, 3018, 3018, 3018, 3018,
- 3018, 3018, 3018, 3018, 3018, 3018, 3018, 3018,
- 3018, 3018, 3018, 3018, 3018, 3018, 3018, 3018,
- 3018, 3018, 3018, 3018, 3018, 3018, 3018, 3018,
- 3018, 3018, 3018, 3018, 3018, 3018, 3018, 3018,
- 3018, 3018, 3018, 3018, 3018, 3018, 3018, 3018,
- 3018, 3018, 3018, 3018, 3018, 3018, 3018, 3018,
- 3018, 3018, 3018, 3018, 3018, 3018, 3018, 3018,
- 3018, 3018, 3018, 3018, 3018, 3018, 3018, 3018,
- 3018, 3018, 3018, 3018, 3018, 3018, 3018, 3018,
- 3018, 3018, 3018, 3018, 3018, 3018, 3018, 3018,
- 3018, 3018, 3018, 3018, 3018, 3018, 3018, 3018,
- 3018, 3018, 3018, 3018, 3018, 3018, 3018, 3018,
- 3018, 3018, 3018, 221, 221, 221, 221, 221,
- 3018, 3018, 3018, 3018, 3018, 3018, 3018, 3018,
- 3018, 3018, 3018, 3018, 3018, 221, 221, 221,
- 3018, 3018, 3018, 3018, 3018, 3018, 3018, 3018,
- 3018, 221, 221, 221, 221, 221, 221, 221,
- 3018, 3018, 3018, 3018, 3018, 3018, 3018, 3018,
- 3018, 3018, 221, 221, 3019, 3020, 3021, 3022,
- 3023, 3023, 3023, 3023, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
+ 3017, 3017, 3017, 3017, 3017, 3017, 3017, 3018,
+ 3019, 3019, 3019, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 3020, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
+ 3021, 3021, 3021, 221, 221, 3022, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 3023, 3023, 3023, 3023,
221, 221, 221, 221, 221, 221, 221, 221,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
- 3024, 3024, 3024, 3024, 3024, 3024, 221, 221,
3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
- 3024, 3024, 3024, 3024, 3024, 3024, 3024, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 3024, 3024, 3024, 3024,
+ 3024, 3024, 3024, 3024, 221, 221, 221, 221,
+
+ 3025, 3025, 3025, 3025, 3025, 3025, 3025, 3025,
3025, 3025, 3025, 3025, 3025, 3025, 3025, 3025,
3025, 3025, 3025, 3025, 3025, 3025, 3025, 3025,
3025, 3025, 3025, 3025, 3025, 3025, 3025, 3025,
@@ -5148,92 +5106,134 @@ static constexpr unsigned short uc_property_trie[] = {
3025, 3025, 3025, 3025, 3025, 3025, 3025, 3025,
3025, 3025, 3025, 3025, 3025, 3025, 3025, 3025,
3025, 3025, 3025, 3025, 3025, 3025, 3025, 3025,
+ 3025, 3025, 3025, 221, 221, 221, 221, 221,
3025, 3025, 3025, 3025, 3025, 3025, 3025, 3025,
+ 3025, 3025, 3025, 3025, 3025, 221, 221, 221,
3025, 3025, 3025, 3025, 3025, 3025, 3025, 3025,
- 3025, 3025, 3025, 3025, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
-
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
-
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 221,
- 221, 1543, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3027, 3027,
- 3027, 3027, 3027, 3027, 3027, 3028, 3029, 3030,
- 3030, 3030, 3026, 3026, 3026, 3031, 3028, 3028,
- 3028, 3028, 3028, 3032, 3032, 3032, 3032, 3032,
- 3032, 3032, 3032, 3033, 3033, 3033, 3033, 3033,
- 3033, 3033, 3033, 3026, 3026, 3034, 3034, 3034,
- 3034, 3034, 3033, 3033, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3034, 3034, 3034, 3034, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3027, 3027, 3027, 3027, 3027,
- 3027, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3026, 3026,
- 3026, 3026, 3026, 3026, 3026, 3026, 3035, 3035,
- 3035, 3035, 3035, 3035, 3035, 3035, 3035, 3035,
- 3035, 3036, 3036, 221, 221, 221, 221, 221,
+ 3025, 221, 221, 221, 221, 221, 221, 221,
+ 3025, 3025, 3025, 3025, 3025, 3025, 3025, 3025,
+ 3025, 3025, 221, 221, 3026, 3027, 3028, 3029,
+ 3030, 3030, 3030, 3030, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+
+ 3031, 3031, 3031, 3031, 3031, 3031, 3031, 3031,
+ 3031, 3031, 3031, 3031, 3031, 3031, 3031, 3031,
+ 3031, 3031, 3031, 3031, 3031, 3031, 3031, 3031,
+ 3031, 3031, 3031, 3031, 3031, 3031, 3031, 3031,
+ 3031, 3031, 3031, 3031, 3031, 3031, 3031, 3031,
+ 3031, 3031, 3031, 3031, 3031, 3031, 221, 221,
+ 3031, 3031, 3031, 3031, 3031, 3031, 3031, 3031,
+ 3031, 3031, 3031, 3031, 3031, 3031, 3031, 3031,
+ 3031, 3031, 3031, 3031, 3031, 3031, 3031, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 3032, 3032, 3032, 3032, 3032, 3032, 3032, 3032,
+ 3032, 3032, 3032, 3032, 3032, 3032, 3032, 3032,
+ 3032, 3032, 3032, 3032, 3032, 3032, 3032, 3032,
+ 3032, 3032, 3032, 3032, 3032, 3032, 3032, 3032,
+ 3032, 3032, 3032, 3032, 3032, 3032, 3032, 3032,
+ 3032, 3032, 3032, 3032, 3032, 3032, 3032, 3032,
+ 3032, 3032, 3032, 3032, 3032, 3032, 3032, 3032,
+ 3032, 3032, 3032, 3032, 3032, 3032, 3032, 3032,
+ 3032, 3032, 3032, 3032, 3032, 3032, 3032, 3032,
+ 3032, 3032, 3032, 3032, 3032, 3032, 3032, 3032,
+ 3032, 3032, 3032, 3032, 3032, 3032, 3032, 3032,
+ 3032, 3032, 3032, 3032, 3032, 3032, 3032, 3032,
+ 3032, 3032, 3032, 3032, 3032, 3032, 3032, 3032,
+ 3032, 3032, 3032, 3032, 3032, 3032, 3032, 3032,
+ 3032, 3032, 3032, 3032, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 221,
+ 221, 1544, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3034, 3034,
+ 3034, 3034, 3034, 3034, 3034, 3035, 3036, 3037,
+ 3037, 3037, 3033, 3033, 3033, 3038, 3035, 3035,
+ 3035, 3035, 3035, 3039, 3039, 3039, 3039, 3039,
+ 3039, 3039, 3039, 3040, 3040, 3040, 3040, 3040,
+ 3040, 3040, 3040, 3033, 3033, 3041, 3041, 3041,
+ 3041, 3041, 3040, 3040, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3041, 3041, 3041, 3041, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3034, 3034, 3034, 3034, 3034,
+ 3034, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3033, 3033,
+ 3033, 3033, 3033, 3033, 3033, 3033, 3042, 3042,
+ 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
+ 3042, 3043, 3043, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 2349, 2349, 2349, 2349, 2349, 2349, 2349, 2349,
- 2349, 2349, 2349, 2349, 2349, 2349, 2349, 2349,
- 2349, 2349, 2349, 2349, 2349, 2349, 2349, 2349,
- 2349, 2349, 2349, 2349, 2349, 2349, 2349, 2349,
- 2349, 2349, 2349, 2349, 2349, 2349, 2349, 2349,
- 2349, 2349, 2349, 2349, 2349, 2349, 2349, 2349,
- 2349, 2349, 2349, 2349, 2349, 2349, 2349, 2349,
- 2349, 2349, 2349, 2349, 2349, 2349, 2349, 2349,
- 2349, 2349, 3037, 3037, 3037, 2349, 221, 221,
+ 2353, 2353, 2353, 2353, 2353, 2353, 2353, 2353,
+ 2353, 2353, 2353, 2353, 2353, 2353, 2353, 2353,
+ 2353, 2353, 2353, 2353, 2353, 2353, 2353, 2353,
+ 2353, 2353, 2353, 2353, 2353, 2353, 2353, 2353,
+ 2353, 2353, 2353, 2353, 2353, 2353, 2353, 2353,
+ 2353, 2353, 2353, 2353, 2353, 2353, 2353, 2353,
+ 2353, 2353, 2353, 2353, 2353, 2353, 2353, 2353,
+ 2353, 2353, 2353, 2353, 2353, 2353, 2353, 2353,
+ 2353, 2353, 3044, 3044, 3044, 2353, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -5249,31 +5249,31 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 3038, 3038, 3038, 3038, 3038, 3038, 3038, 3038,
- 3038, 3038, 3038, 3038, 3038, 3038, 3038, 3038,
- 3038, 3038, 3038, 3038, 221, 221, 221, 221,
+ 3045, 3045, 3045, 3045, 3045, 3045, 3045, 3045,
+ 3045, 3045, 3045, 3045, 3045, 3045, 3045, 3045,
+ 3045, 3045, 3045, 3045, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 3039, 3039, 3039, 3039, 3039, 3039, 3039, 3039,
- 3039, 3039, 3039, 3039, 3039, 3039, 3039, 3039,
- 3039, 3039, 3039, 3039, 221, 221, 221, 221,
+ 3046, 3046, 3046, 3046, 3046, 3046, 3046, 3046,
+ 3046, 3046, 3046, 3046, 3046, 3046, 3046, 3046,
+ 3046, 3046, 3046, 3046, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
- 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
- 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
- 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
- 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
- 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
- 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
- 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
- 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
- 1605, 1605, 1605, 1605, 1605, 1605, 1605, 1605,
- 1605, 1605, 1605, 1605, 1605, 1605, 1605, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 3040, 3040, 3040, 3040, 3040, 3040, 3040, 3040,
- 3040, 3040, 3040, 3040, 3040, 3040, 3040, 3040,
- 3040, 3040, 3039, 3039, 3039, 3039, 3039, 3039,
- 3039, 221, 221, 221, 221, 221, 221, 221,
+ 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606,
+ 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606,
+ 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606,
+ 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606,
+ 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606,
+ 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606,
+ 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606,
+ 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606,
+ 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606,
+ 1606, 1606, 1606, 1606, 1606, 1606, 1606, 1606,
+ 1606, 1606, 1606, 1606, 1606, 1606, 1606, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 3047, 3047, 3047, 3047, 3047, 3047, 3047, 3047,
+ 3047, 3047, 3047, 3047, 3047, 3047, 3047, 3047,
+ 3047, 3047, 3046, 3046, 3046, 3046, 3046, 3046,
+ 3046, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -5291,193 +5291,193 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 221, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3041, 221, 3041, 3041,
- 221, 221, 3041, 221, 221, 3041, 3041, 221,
- 221, 3041, 3041, 3041, 3041, 221, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3042, 3042,
- 3042, 3042, 221, 3042, 221, 3042, 3042, 3042,
- 3042, 3043, 3042, 3042, 221, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
-
- 3042, 3042, 3042, 3042, 3041, 3041, 221, 3041,
- 3041, 3041, 3041, 221, 221, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 221, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 221, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3041, 3041, 221, 3041, 3041, 3041, 3041, 221,
- 3041, 3041, 3041, 3041, 3041, 221, 3041, 221,
- 221, 221, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 221, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
-
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 1535, 1535, 221, 221,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3044, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3045, 3042, 3042, 3042, 3042,
- 3042, 3042, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3044, 3042, 3042, 3042, 3042,
-
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3045, 3042, 3042,
- 3042, 3042, 3042, 3042, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3044, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3045,
- 3042, 3042, 3042, 3042, 3042, 3042, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3044,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3045, 3042, 3042, 3042, 3042, 3042, 3042,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3041, 3041, 3041, 3041, 3041, 3041, 3041,
- 3041, 3044, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3042, 3042, 3042, 3042, 3042,
- 3042, 3042, 3042, 3045, 3042, 3042, 3042, 3042,
- 3042, 3042, 3046, 3047, 221, 221, 3048, 3049,
- 3050, 3051, 3052, 3053, 3054, 3055, 3056, 3057,
- 3048, 3049, 3050, 3051, 3052, 3053, 3054, 3055,
- 3056, 3057, 3048, 3049, 3050, 3051, 3052, 3053,
- 3054, 3055, 3056, 3057, 3048, 3049, 3050, 3051,
- 3052, 3053, 3054, 3055, 3056, 3057, 3048, 3049,
- 3050, 3051, 3052, 3053, 3054, 3055, 3056, 3057,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 221, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3048, 221, 3048, 3048,
+ 221, 221, 3048, 221, 221, 3048, 3048, 221,
+ 221, 3048, 3048, 3048, 3048, 221, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3049, 3049,
+ 3049, 3049, 221, 3049, 221, 3049, 3049, 3049,
+ 3049, 3050, 3049, 3049, 221, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+
+ 3049, 3049, 3049, 3049, 3048, 3048, 221, 3048,
+ 3048, 3048, 3048, 221, 221, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 221, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 221, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3048, 3048, 221, 3048, 3048, 3048, 3048, 221,
+ 3048, 3048, 3048, 3048, 3048, 221, 3048, 221,
+ 221, 221, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 221, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 1536, 1536, 221, 221,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3051, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3052, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3051, 3049, 3049, 3049, 3049,
+
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3052, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3051, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3052,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3051,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3052, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3048, 3048, 3048, 3048, 3048, 3048, 3048,
+ 3048, 3051, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3049, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3049, 3052, 3049, 3049, 3049, 3049,
+ 3049, 3049, 3053, 3054, 221, 221, 3055, 3056,
+ 3057, 3058, 3059, 3060, 3061, 3062, 3063, 3064,
+ 3055, 3056, 3057, 3058, 3059, 3060, 3061, 3062,
+ 3063, 3064, 3055, 3056, 3057, 3058, 3059, 3060,
+ 3061, 3062, 3063, 3064, 3055, 3056, 3057, 3058,
+ 3059, 3060, 3061, 3062, 3063, 3064, 3055, 3056,
+ 3057, 3058, 3059, 3060, 3061, 3062, 3063, 3064,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
- 3059, 3059, 3059, 3059, 3059, 3059, 3059, 3059,
- 3059, 3059, 3059, 3059, 3059, 3059, 3059, 3059,
- 3059, 3059, 3059, 3059, 3059, 3059, 3059, 3059,
- 3059, 3059, 3059, 3059, 3059, 3059, 3059, 3059,
- 3059, 3059, 3059, 3059, 3059, 3059, 3059, 3059,
- 3059, 3059, 3059, 3059, 3059, 3059, 3059, 3059,
- 3059, 3059, 3059, 3059, 3059, 3059, 3059, 3058,
- 3058, 3058, 3058, 3059, 3059, 3059, 3059, 3059,
- 3059, 3059, 3059, 3059, 3059, 3059, 3059, 3059,
- 3059, 3059, 3059, 3059, 3059, 3059, 3059, 3059,
- 3059, 3059, 3059, 3059, 3059, 3059, 3059, 3059,
- 3059, 3059, 3059, 3059, 3059, 3059, 3059, 3059,
- 3059, 3059, 3059, 3059, 3059, 3059, 3059, 3059,
- 3059, 3059, 3059, 3059, 3059, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3059, 3058, 3058,
- 3058, 3058, 3058, 3058, 3058, 3058, 3058, 3058,
- 3058, 3058, 3058, 3058, 3059, 3058, 3058, 3060,
- 3061, 3060, 3060, 3062, 221, 221, 221, 221,
+ 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3066,
+ 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3066,
+ 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3066,
+ 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3066,
+ 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3066,
+ 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3066,
+ 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3065,
+ 3065, 3065, 3065, 3066, 3066, 3066, 3066, 3066,
+ 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3066,
+ 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3066,
+ 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3066,
+ 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3066,
+ 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3066,
+ 3066, 3066, 3066, 3066, 3066, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3066, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
+ 3065, 3065, 3065, 3065, 3066, 3065, 3065, 3067,
+ 3068, 3067, 3067, 3069, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 3059, 3059, 3059, 3059, 3059,
- 221, 3059, 3059, 3059, 3059, 3059, 3059, 3059,
- 3059, 3059, 3059, 3059, 3059, 3059, 3059, 3059,
+ 221, 221, 221, 3066, 3066, 3066, 3066, 3066,
+ 221, 3066, 3066, 3066, 3066, 3066, 3066, 3066,
+ 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3066,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -5489,12 +5489,12 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 1986, 1986, 1986, 1986, 1986, 1986, 1986, 1986,
- 1986, 1986, 3063, 1986, 1986, 1986, 1986, 1986,
- 1986, 1986, 1986, 1986, 1986, 1986, 1986, 1986,
- 1986, 1986, 1986, 1986, 1986, 1986, 1986, 221,
- 221, 221, 221, 221, 221, 3064, 3064, 3064,
- 3064, 3064, 3064, 221, 221, 221, 221, 221,
+ 1988, 1988, 1988, 1988, 1988, 1988, 1988, 1988,
+ 1988, 1988, 3070, 1988, 1988, 1988, 1988, 1988,
+ 1988, 1988, 1988, 1988, 1988, 1988, 1988, 1988,
+ 1988, 1988, 1988, 1988, 1988, 1988, 1988, 221,
+ 221, 221, 221, 221, 221, 3071, 3071, 3071,
+ 3071, 3071, 3071, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -5522,24 +5522,24 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 3065, 3065, 3065, 3065, 3065, 3065, 3065, 221,
- 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
- 3065, 3065, 3065, 3065, 3065, 3065, 3065, 3065,
- 3065, 221, 221, 3065, 3065, 3065, 3065, 3065,
- 3065, 3065, 221, 3065, 3065, 221, 3065, 3065,
- 3065, 3065, 3065, 221, 221, 221, 221, 221,
- 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3066,
- 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3066,
- 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3066,
- 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3066,
- 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3066,
- 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3066,
- 3066, 3066, 3066, 3066, 3066, 3066, 3066, 3066,
- 3066, 3066, 3066, 3066, 3066, 3066, 221, 221,
+ 3072, 3072, 3072, 3072, 3072, 3072, 3072, 221,
+ 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072,
+ 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072,
+ 3072, 221, 221, 3072, 3072, 3072, 3072, 3072,
+ 3072, 3072, 221, 3072, 3072, 221, 3072, 3072,
+ 3072, 3072, 3072, 221, 221, 221, 221, 221,
+ 3073, 3073, 3073, 3073, 3073, 3073, 3073, 3073,
+ 3073, 3073, 3073, 3073, 3073, 3073, 3073, 3073,
+ 3073, 3073, 3073, 3073, 3073, 3073, 3073, 3073,
+ 3073, 3073, 3073, 3073, 3073, 3073, 3073, 3073,
+ 3073, 3073, 3073, 3073, 3073, 3073, 3073, 3073,
+ 3073, 3073, 3073, 3073, 3073, 3073, 3073, 3073,
+ 3073, 3073, 3073, 3073, 3073, 3073, 3073, 3073,
+ 3073, 3073, 3073, 3073, 3073, 3073, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 3067,
+ 221, 221, 221, 221, 221, 221, 221, 3074,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -5555,16 +5555,16 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 3068, 3068, 3068, 3068, 3068, 3068, 3068, 3068,
- 3068, 3068, 3068, 3068, 3068, 3068, 3068, 3068,
- 3068, 3068, 3068, 3068, 3068, 3068, 3068, 3068,
- 3068, 3068, 3068, 3068, 3068, 3068, 3068, 3068,
- 3068, 3068, 3068, 3068, 3068, 3068, 3068, 3068,
- 3068, 3068, 3068, 3068, 3068, 221, 221, 221,
- 3069, 3069, 3069, 3069, 3069, 3069, 3069, 3070,
- 3070, 3070, 3070, 3070, 3070, 3070, 221, 221,
- 3071, 3072, 3073, 3074, 3075, 3076, 3077, 3078,
- 3079, 3080, 221, 221, 221, 221, 3068, 3081,
+ 3075, 3075, 3075, 3075, 3075, 3075, 3075, 3075,
+ 3075, 3075, 3075, 3075, 3075, 3075, 3075, 3075,
+ 3075, 3075, 3075, 3075, 3075, 3075, 3075, 3075,
+ 3075, 3075, 3075, 3075, 3075, 3075, 3075, 3075,
+ 3075, 3075, 3075, 3075, 3075, 3075, 3075, 3075,
+ 3075, 3075, 3075, 3075, 3075, 221, 221, 221,
+ 3076, 3076, 3076, 3076, 3076, 3076, 3076, 3077,
+ 3077, 3077, 3077, 3077, 3077, 3077, 221, 221,
+ 3078, 3079, 3080, 3081, 3082, 3083, 3084, 3085,
+ 3086, 3087, 221, 221, 221, 221, 3075, 3088,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -5606,20 +5606,20 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 3082, 3082, 3082, 3082, 3082, 3082, 3082, 3082,
- 3082, 3082, 3082, 3082, 3082, 3082, 3082, 3082,
- 3082, 3082, 3082, 3082, 3082, 3082, 3082, 3082,
- 3082, 3082, 3082, 3082, 3082, 3082, 3083, 221,
+ 3089, 3089, 3089, 3089, 3089, 3089, 3089, 3089,
+ 3089, 3089, 3089, 3089, 3089, 3089, 3089, 3089,
+ 3089, 3089, 3089, 3089, 3089, 3089, 3089, 3089,
+ 3089, 3089, 3089, 3089, 3089, 3089, 3090, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 3084, 3084, 3084, 3084, 3084, 3084, 3084, 3084,
- 3084, 3084, 3084, 3084, 3084, 3084, 3084, 3084,
- 3084, 3084, 3084, 3084, 3084, 3084, 3084, 3084,
- 3084, 3084, 3084, 3084, 3084, 3084, 3084, 3084,
- 3084, 3084, 3084, 3084, 3084, 3084, 3084, 3084,
- 3084, 3084, 3084, 3084, 3085, 3085, 3085, 3085,
- 3086, 3087, 3088, 3089, 3090, 3091, 3092, 3093,
- 3094, 3095, 221, 221, 221, 221, 221, 3096,
+ 3091, 3091, 3091, 3091, 3091, 3091, 3091, 3091,
+ 3091, 3091, 3091, 3091, 3091, 3091, 3091, 3091,
+ 3091, 3091, 3091, 3091, 3091, 3091, 3091, 3091,
+ 3091, 3091, 3091, 3091, 3091, 3091, 3091, 3091,
+ 3091, 3091, 3091, 3091, 3091, 3091, 3091, 3091,
+ 3091, 3091, 3091, 3091, 3092, 3092, 3092, 3092,
+ 3093, 3094, 3095, 3096, 3097, 3098, 3099, 3100,
+ 3101, 3102, 221, 221, 221, 221, 221, 3103,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -5647,12 +5647,12 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 3097, 3097, 3097, 3097, 3097, 3097, 3097, 3097,
- 3097, 3097, 3097, 3097, 3097, 3097, 3097, 3097,
- 3097, 3097, 3097, 3097, 3097, 3097, 3097, 3097,
- 3097, 3097, 3097, 3098, 3099, 3099, 3100, 3101,
- 3102, 3103, 3104, 3105, 3106, 3107, 3108, 3109,
- 3110, 3111, 221, 221, 221, 221, 221, 221,
+ 3104, 3104, 3104, 3104, 3104, 3104, 3104, 3104,
+ 3104, 3104, 3104, 3104, 3104, 3104, 3104, 3104,
+ 3104, 3104, 3104, 3104, 3104, 3104, 3104, 3104,
+ 3104, 3104, 3104, 3105, 3106, 3106, 3107, 3108,
+ 3109, 3110, 3111, 3112, 3113, 3114, 3115, 3116,
+ 3117, 3118, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
@@ -5682,56 +5682,56 @@ static constexpr unsigned short uc_property_trie[] = {
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
221, 221, 221, 221, 221, 221, 221, 221,
- 3112, 3112, 3112, 3112, 3112, 3112, 3112, 221,
- 3112, 3112, 3112, 3112, 221, 3112, 3112, 221,
- 3112, 3112, 3112, 3112, 3112, 3112, 3112, 3112,
- 3112, 3112, 3112, 3112, 3112, 3112, 3112, 221,
+ 3119, 3119, 3119, 3119, 3119, 3119, 3119, 221,
+ 3119, 3119, 3119, 3119, 221, 3119, 3119, 221,
+ 3119, 3119, 3119, 3119, 3119, 3119, 3119, 3119,
+ 3119, 3119, 3119, 3119, 3119, 3119, 3119, 221,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 3113, 3113, 3113,
- 3113, 3113, 3113, 3113, 3113, 323, 323, 3114,
- 3114, 3114, 3114, 3114, 3114, 3114, 3114, 3114,
- 3115, 3115, 3115, 3115, 3115, 3115, 3115, 323,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 3120, 3120, 3120,
+ 3120, 3120, 3120, 3120, 3120, 323, 323, 3121,
+ 3121, 3121, 3121, 3121, 3121, 3121, 3121, 3121,
+ 3122, 3122, 3122, 3122, 3122, 3122, 3122, 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,
- 3116, 3116, 3116, 3116, 3116, 3116, 3116, 3116,
- 3116, 3116, 3116, 3116, 3116, 3116, 3116, 3116,
- 3116, 3116, 3116, 3116, 3116, 3116, 3116, 3116,
- 3116, 3116, 3116, 3116, 3116, 3116, 3116, 3116,
- 3116, 3116, 3117, 3117, 3117, 3117, 3117, 3117,
- 3117, 3117, 3117, 3117, 3117, 3117, 3117, 3117,
- 3117, 3117, 3117, 3117, 3117, 3117, 3117, 3117,
- 3117, 3117, 3117, 3117, 3117, 3117, 3117, 3117,
- 3117, 3117, 3117, 3117, 3118, 3118, 3118, 3118,
- 3118, 3118, 3119, 3120, 323, 323, 323, 323,
- 3121, 3122, 3123, 3124, 3125, 3126, 3127, 3128,
- 3129, 3130, 323, 323, 323, 323, 3131, 3131,
+ 3123, 3123, 3123, 3123, 3123, 3123, 3123, 3123,
+ 3123, 3123, 3123, 3123, 3123, 3123, 3123, 3123,
+ 3123, 3123, 3123, 3123, 3123, 3123, 3123, 3123,
+ 3123, 3123, 3123, 3123, 3123, 3123, 3123, 3123,
+ 3123, 3123, 3124, 3124, 3124, 3124, 3124, 3124,
+ 3124, 3124, 3124, 3124, 3124, 3124, 3124, 3124,
+ 3124, 3124, 3124, 3124, 3124, 3124, 3124, 3124,
+ 3124, 3124, 3124, 3124, 3124, 3124, 3124, 3124,
+ 3124, 3124, 3124, 3124, 3125, 3125, 3125, 3125,
+ 3125, 3125, 3126, 3127, 323, 323, 323, 323,
+ 3128, 3129, 3130, 3131, 3132, 3133, 3134, 3135,
+ 3136, 3137, 323, 323, 323, 323, 3138, 3138,
323, 323, 323, 323, 323, 323, 323, 323,
323, 323, 323, 323, 323, 323, 323, 323,
323, 323, 323, 323, 323, 323, 323, 323,
@@ -5800,15 +5800,15 @@ static constexpr unsigned short uc_property_trie[] = {
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, 3132, 3132, 3132, 3132, 3132, 3132, 3132,
- 3132, 3132, 3132, 3132, 3132, 3132, 3132, 3132,
- 3132, 3132, 3132, 3132, 3132, 3132, 3132, 3132,
- 3132, 3132, 3132, 3132, 3132, 3132, 3132, 3132,
- 3132, 3132, 3132, 3132, 3132, 3132, 3132, 3132,
- 3132, 3132, 3132, 3132, 3132, 3132, 3132, 3132,
- 3132, 3132, 3132, 3132, 3132, 3132, 3132, 3132,
- 3132, 3132, 3132, 3132, 3133, 3132, 3132, 3132,
- 3134, 3132, 3132, 3132, 3132, 323, 323, 323,
+ 323, 3139, 3139, 3139, 3139, 3139, 3139, 3139,
+ 3139, 3139, 3139, 3139, 3139, 3139, 3139, 3139,
+ 3139, 3139, 3139, 3139, 3139, 3139, 3139, 3139,
+ 3139, 3139, 3139, 3139, 3139, 3139, 3139, 3139,
+ 3139, 3139, 3139, 3139, 3139, 3139, 3139, 3139,
+ 3139, 3139, 3139, 3139, 3139, 3139, 3139, 3139,
+ 3139, 3139, 3139, 3139, 3139, 3139, 3139, 3139,
+ 3139, 3139, 3139, 3139, 3140, 3139, 3139, 3139,
+ 3141, 3139, 3139, 3139, 3139, 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,
@@ -5819,14 +5819,14 @@ static constexpr unsigned short uc_property_trie[] = {
323, 323, 323, 323, 323, 323, 323, 323,
323, 323, 323, 323, 323, 323, 323, 323,
- 323, 3135, 3135, 3135, 3135, 3135, 3135, 3135,
- 3135, 3135, 3135, 3135, 3135, 3135, 3135, 3135,
- 3135, 3135, 3135, 3135, 3135, 3135, 3135, 3135,
- 3135, 3135, 3135, 3135, 3135, 3135, 3135, 3135,
- 3135, 3135, 3135, 3135, 3135, 3135, 3135, 3135,
- 3135, 3135, 3135, 3135, 3135, 3135, 3136, 3135,
- 3135, 3135, 3135, 3135, 3135, 3135, 3135, 3135,
- 3135, 3135, 3135, 3135, 3135, 3135, 323, 323,
+ 323, 3142, 3142, 3142, 3142, 3142, 3142, 3142,
+ 3142, 3142, 3142, 3142, 3142, 3142, 3142, 3142,
+ 3142, 3142, 3142, 3142, 3142, 3142, 3142, 3142,
+ 3142, 3142, 3142, 3142, 3142, 3142, 3142, 3142,
+ 3142, 3142, 3142, 3142, 3142, 3142, 3142, 3142,
+ 3142, 3142, 3142, 3142, 3142, 3142, 3143, 3142,
+ 3142, 3142, 3142, 3142, 3142, 3142, 3142, 3142,
+ 3142, 3142, 3142, 3142, 3142, 3142, 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,
@@ -5852,1226 +5852,500 @@ static constexpr unsigned short uc_property_trie[] = {
323, 323, 323, 323, 323, 323, 323, 323,
323, 323, 323, 323, 323, 323, 323, 323,
- 3137, 3137, 3137, 3137, 437, 3137, 3137, 3137,
- 3137, 3137, 3137, 3137, 3137, 3137, 3137, 3137,
- 3137, 3137, 3137, 3137, 3137, 3137, 3137, 3137,
- 3137, 3137, 3137, 3137, 3137, 3137, 3137, 3137,
- 437, 3137, 3137, 437, 3137, 437, 437, 3137,
- 437, 3137, 3137, 3137, 3137, 3137, 3137, 3137,
- 3137, 3137, 3137, 437, 3137, 3137, 3137, 3137,
- 437, 3137, 437, 3137, 437, 437, 437, 437,
- 437, 437, 3137, 437, 437, 437, 437, 3137,
- 437, 3137, 437, 3137, 437, 3137, 3137, 3137,
- 437, 3137, 3137, 437, 3137, 437, 437, 3137,
- 437, 3137, 437, 3137, 437, 3137, 437, 3137,
- 437, 3137, 3137, 437, 3137, 437, 437, 3137,
- 3137, 3137, 3137, 437, 3137, 3137, 3137, 3137,
- 3137, 3137, 3137, 437, 3137, 3137, 3137, 3137,
- 437, 3137, 3137, 3137, 3137, 437, 3137, 437,
- 3137, 3137, 3137, 3137, 3137, 3137, 3137, 3137,
- 3137, 3137, 437, 3137, 3137, 3137, 3137, 3137,
- 3137, 3137, 3137, 3137, 3137, 3137, 3137, 3137,
- 3137, 3137, 3137, 3137, 437, 437, 437, 437,
- 437, 3137, 3137, 3137, 437, 3137, 3137, 3137,
- 3137, 3137, 437, 3137, 3137, 3137, 3137, 3137,
- 3137, 3137, 3137, 3137, 3137, 3137, 3137, 3137,
- 3137, 3137, 3137, 3137, 437, 437, 437, 437,
+ 3144, 3144, 3144, 3144, 437, 3144, 3144, 3144,
+ 3144, 3144, 3144, 3144, 3144, 3144, 3144, 3144,
+ 3144, 3144, 3144, 3144, 3144, 3144, 3144, 3144,
+ 3144, 3144, 3144, 3144, 3144, 3144, 3144, 3144,
+ 437, 3144, 3144, 437, 3144, 437, 437, 3144,
+ 437, 3144, 3144, 3144, 3144, 3144, 3144, 3144,
+ 3144, 3144, 3144, 437, 3144, 3144, 3144, 3144,
+ 437, 3144, 437, 3144, 437, 437, 437, 437,
+ 437, 437, 3144, 437, 437, 437, 437, 3144,
+ 437, 3144, 437, 3144, 437, 3144, 3144, 3144,
+ 437, 3144, 3144, 437, 3144, 437, 437, 3144,
+ 437, 3144, 437, 3144, 437, 3144, 437, 3144,
+ 437, 3144, 3144, 437, 3144, 437, 437, 3144,
+ 3144, 3144, 3144, 437, 3144, 3144, 3144, 3144,
+ 3144, 3144, 3144, 437, 3144, 3144, 3144, 3144,
+ 437, 3144, 3144, 3144, 3144, 437, 3144, 437,
+ 3144, 3144, 3144, 3144, 3144, 3144, 3144, 3144,
+ 3144, 3144, 437, 3144, 3144, 3144, 3144, 3144,
+ 3144, 3144, 3144, 3144, 3144, 3144, 3144, 3144,
+ 3144, 3144, 3144, 3144, 437, 437, 437, 437,
+ 437, 3144, 3144, 3144, 437, 3144, 3144, 3144,
+ 3144, 3144, 437, 3144, 3144, 3144, 3144, 3144,
+ 3144, 3144, 3144, 3144, 3144, 3144, 3144, 3144,
+ 3144, 3144, 3144, 3144, 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,
- 3138, 3138, 437, 437, 437, 437, 437, 437,
+ 3145, 3145, 437, 437, 437, 437, 437, 437,
437, 437, 437, 437, 437, 437, 437, 437,
- 1680, 1680, 1680, 1680, 3139, 1680, 1680, 1680,
- 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680,
- 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680,
- 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680,
- 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680,
- 1680, 1680, 1680, 1680, 3140, 3140, 3140, 3140,
- 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680,
- 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680,
- 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680,
- 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680,
- 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680,
- 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680,
- 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680,
- 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680,
- 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680,
- 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680,
- 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680,
- 1680, 1680, 1680, 1680, 1680, 1680, 1680, 1680,
- 1680, 1680, 1680, 1680, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
- 1611, 1611, 1611, 1611, 1611, 1611, 1611, 3140,
- 3140, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
- 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1682,
- 3140, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
- 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1610,
- 3140, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
- 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
- 1682, 1682, 1682, 1682, 1682, 1682, 1682, 1682,
- 1682, 1682, 1682, 1682, 1682, 1682, 1682, 1682,
- 1682, 1682, 1682, 1682, 1682, 1682, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
-
- 3141, 3141, 3142, 3143, 3144, 3145, 3146, 3147,
- 3148, 3149, 3150, 3151, 3151, 3152, 3152, 3152,
- 3153, 3153, 3153, 3153, 3153, 3153, 3153, 3153,
- 3153, 3153, 3153, 3153, 3153, 3153, 3153, 3153,
- 3153, 3153, 3153, 3153, 3153, 3153, 3153, 3153,
- 3153, 3153, 3154, 3154, 3154, 3154, 3155, 3156,
- 3157, 3158, 3157, 3157, 3157, 3157, 3157, 3157,
- 3157, 3157, 3157, 3157, 3157, 3158, 3157, 3158,
- 3157, 3157, 3158, 3157, 3157, 3157, 3158, 3157,
- 3157, 3157, 3154, 3154, 3154, 3154, 3154, 3159,
- 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3161,
- 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3161,
- 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160,
- 3160, 3160, 3162, 3162, 3163, 3152, 3152, 3152,
- 3164, 3164, 3160, 3160, 3160, 3160, 3160, 3160,
- 3160, 3161, 3160, 3161, 3161, 3160, 3164, 3165,
- 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160,
- 3160, 3160, 3166, 3166, 3166, 3166, 3167, 3168,
- 3154, 3167, 3167, 3167, 3167, 3167, 3167, 3167,
- 3167, 3167, 3167, 3169, 3169, 3169, 3169, 3169,
- 3169, 3169, 3169, 3169, 3169, 3169, 3169, 3169,
- 3169, 3169, 3169, 3169, 3169, 3152, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3170, 3170,
- 3170, 3170, 3170, 3170, 3170, 3170, 3170, 3170,
- 3170, 3170, 3170, 3170, 3170, 3170, 3170, 3170,
- 3170, 3170, 3170, 3170, 3170, 3170, 3170, 3170,
-
- 3171, 3172, 3172, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 1889, 1889, 1889, 1889, 1889, 1889, 1889, 1889,
- 1889, 1889, 3173, 1889, 1889, 1889, 1889, 1889,
- 1889, 1889, 1889, 1889, 1889, 1889, 1889, 1889,
- 1889, 1889, 1889, 1889, 1889, 1889, 1889, 3173,
- 1889, 1889, 3172, 3172, 3172, 3172, 3172, 3172,
- 3172, 3172, 3172, 3174, 3140, 3140, 3140, 3140,
- 1889, 1889, 1889, 1889, 1889, 1889, 1889, 1889,
- 1889, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3172, 3172, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3175, 3175, 3175, 3175, 3175, 3175, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
-
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1682, 1682, 1682, 1682, 1682, 1682, 1682,
- 1682, 1682, 1682, 1682, 1682, 3176, 3176, 3176,
- 1610, 1610, 1610, 1610, 1610, 1610, 1682, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1682, 3176, 3176,
- 1610, 1610, 1610, 1610, 1610, 1683, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1682, 1682, 1682, 1682,
- 1682, 1682, 1682, 1682, 1613, 1613, 1682, 1682,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1608, 1608, 1610,
- 1610, 1610, 1610, 1610, 1608, 1610, 1610, 1610,
- 1610, 1610, 1683, 1683, 1683, 3177, 1610, 1683,
- 1610, 1610, 1683, 3178, 3178, 1682, 1682, 3176,
- 3176, 3176, 3176, 3176, 1682, 1682, 1682, 1682,
- 1682, 1682, 1682, 1682, 1682, 1682, 1682, 1682,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1682, 1682, 1682, 3177, 1682, 1682, 1682,
- 3176, 3176, 3176, 3179, 3179, 3179, 3179, 3179,
-
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1682,
- 1610, 1682, 1683, 1683, 1610, 1610, 1683, 1683,
- 1683, 1683, 1683, 1683, 1683, 1683, 1683, 1683,
- 1683, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1683, 1683,
- 1683, 1683, 1683, 1683, 1683, 1683, 1683, 1683,
- 1683, 1683, 1683, 1683, 1683, 1683, 1683, 1683,
- 1683, 1610, 1610, 1610, 1683, 1610, 1610, 1610,
- 1610, 1683, 1683, 1683, 1610, 1683, 1683, 1683,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1683,
- 1610, 1683, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1608, 1610, 1608, 1610, 1608, 1610, 1610, 1610,
- 1610, 1610, 1683, 1610, 1610, 1610, 1610, 1608,
- 1610, 1608, 1608, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 3177, 1610, 1610, 1610, 1610, 1682, 1682, 3176,
-
- 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1608,
- 1608, 1608, 1608, 1608, 1608, 1608, 1608, 1608,
- 1608, 1608, 1608, 1608, 1608, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1608, 1608, 1608, 1608, 1608, 1608,
- 1608, 1608, 1608, 1608, 1608, 1608, 1612, 1612,
- 3180, 3180, 3180, 3180, 1612, 1612, 1613, 1613,
- 1613, 1613, 1682, 3176, 3176, 3176, 3176, 3181,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1682, 1682, 1682, 1682, 1682, 1682, 1682, 1682,
- 1682, 1682, 1682, 1682, 3178, 3178, 1682, 1682,
- 1682, 1682, 3182, 1682, 1682, 1682, 1682, 1682,
- 1682, 1682, 1682, 1682, 1682, 1682, 1682, 1682,
- 1682, 1682, 1682, 1682, 1682, 1682, 1682, 1682,
- 3178, 1682, 1682, 1682, 1682, 3183, 3183, 1682,
- 1682, 1682, 1682, 1682, 1682, 1682, 1682, 1682,
- 1682, 1682, 1682, 1682, 3184, 1682, 1682, 1682,
- 1682, 1682, 1682, 1682, 1682, 1682, 1682, 1682,
- 1682, 1682, 1682, 1682, 1682, 1682, 1682, 1682,
- 1682, 1682, 1682, 1682, 1682, 1682, 1682, 1682,
- 1682, 1682, 1682, 1682, 1682, 1682, 1682, 1682,
- 1682, 1682, 1682, 1682, 1682, 1682, 1682, 1682,
- 1682, 1682, 1682, 1682, 1613, 1613, 1613, 1613,
- 1613, 1613, 1613, 1613, 1682, 1682, 1682, 1682,
- 1682, 1682, 1682, 1682, 1682, 1682, 1682, 1682,
- 1682, 1682, 1682, 1682, 1682, 1682, 1682, 1682,
- 1682, 1682, 1682, 1682, 1613, 1613, 1613, 1613,
- 1613, 1613, 1682, 1610, 1610, 1610, 1610, 1610,
-
- 3185, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 3185, 1610, 1610, 1610, 3185, 1610, 3185,
- 1610, 3185, 1610, 3185, 1610, 1610, 1610, 3185,
- 1610, 1610, 1610, 1610, 1610, 1610, 3185, 3185,
- 1610, 1610, 1610, 1610, 3185, 1610, 3185, 3185,
- 1610, 1610, 1610, 1610, 3185, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 3177, 3177, 3176, 3176, 1683, 1683, 1683,
- 1610, 1610, 1610, 1683, 1683, 1683, 1683, 1683,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
+ 1681, 1681, 1681, 1681, 3146, 1681, 1681, 1681,
+ 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681,
+ 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681,
+ 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681,
+ 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681,
+ 1681, 1681, 1681, 1681, 3147, 3147, 3147, 3147,
+ 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681,
+ 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681,
+ 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681,
+ 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681,
+ 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681,
+ 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681,
+ 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681,
+ 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681,
+ 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681,
+ 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681,
+ 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681,
+ 1681, 1681, 1681, 1681, 1681, 1681, 1681, 1681,
+ 1681, 1681, 1681, 1681, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
+ 1612, 1612, 1612, 1612, 1612, 1612, 1612, 3147,
+ 3147, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
+ 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1683,
+ 3147, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
+ 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1611,
+ 3147, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 3186, 3186,
- 3186, 3187, 3187, 3187, 1612, 1612, 1612, 1612,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1683, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1610, 1610, 1610, 1610, 1683, 1683, 1683, 1610,
- 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
- 1683, 1610, 1610, 1610, 1610, 1610, 1682, 1682,
- 1682, 1682, 1682, 1682, 3183, 1682, 1682, 1682,
- 3176, 3184, 3184, 3188, 3188, 3189, 3190, 3190,
- 3140, 3140, 3140, 3140, 3191, 3192, 3192, 3192,
- 1682, 1682, 1682, 1682, 1682, 1682, 1682, 1682,
- 1682, 1682, 1682, 3177, 3177, 3140, 3140, 3140,
- 1682, 1682, 1682, 1682, 3184, 3184, 3184, 3175,
- 3175, 3193, 3189, 3190, 3190, 3140, 3140, 3140,
-
- 3194, 3194, 3194, 3194, 3194, 3194, 3194, 3194,
- 3194, 3194, 3194, 3194, 3194, 3194, 3194, 3194,
- 3194, 3194, 3194, 3194, 3194, 3194, 3194, 3194,
- 3194, 3194, 3194, 3194, 3194, 3194, 3194, 3194,
- 3194, 3194, 3194, 3194, 3194, 3194, 3194, 3194,
- 3194, 3194, 3194, 3194, 3194, 3194, 3194, 3194,
- 3194, 3194, 3194, 3194, 3194, 3194, 3194, 3194,
- 3194, 3194, 3194, 3194, 3194, 3194, 3194, 3194,
- 3194, 3194, 3194, 3194, 3194, 3194, 3194, 3194,
- 3194, 3194, 3194, 3194, 3194, 3194, 3194, 3194,
- 3194, 3194, 3194, 3194, 3194, 3194, 3194, 3194,
- 3194, 3194, 3194, 3194, 3194, 3194, 3194, 3194,
- 3194, 3194, 3194, 3194, 3194, 3194, 3194, 3194,
- 3194, 3194, 3194, 3194, 3194, 3194, 3194, 3194,
- 3194, 3194, 3194, 3194, 3195, 3195, 3195, 3140,
- 3140, 3140, 3140, 3195, 3195, 3195, 3195, 3195,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 3196, 3196, 3196,
- 3196, 3195, 3140, 3140, 3140, 3140, 3140, 3140,
- 3189, 3189, 3189, 3189, 3189, 3189, 3189, 3189,
- 3189, 3189, 3189, 3189, 3140, 3140, 3140, 3140,
- 3192, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
+ 1683, 1683, 1683, 1683, 1683, 1683, 1683, 1683,
+ 1683, 1683, 1683, 1683, 1683, 1683, 1683, 1683,
+ 1683, 1683, 1683, 1683, 1683, 1683, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 3140, 3140, 3140, 3140,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 3140, 3140, 3140, 3140, 3140, 3140,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 1612, 1612,
- 1612, 1612, 1612, 1612, 1612, 1612, 3140, 3140,
- 3152, 3152, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
-
- 1615, 1615, 1615, 1615, 1615, 1615, 1615, 1615,
- 1615, 1615, 1615, 1615, 3197, 3189, 3189, 3198,
+ 3148, 3148, 3149, 3150, 3151, 3152, 3153, 3154,
+ 3155, 3156, 3157, 3158, 3158, 3159, 3159, 3159,
+ 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160,
+ 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160,
+ 3160, 3160, 3160, 3160, 3160, 3160, 3160, 3160,
+ 3160, 3160, 3161, 3161, 3161, 3161, 3162, 3163,
+ 3164, 3165, 3164, 3164, 3164, 3164, 3164, 3164,
+ 3164, 3164, 3164, 3164, 3164, 3165, 3164, 3165,
+ 3164, 3164, 3165, 3164, 3164, 3164, 3165, 3164,
+ 3164, 3164, 3161, 3161, 3161, 3161, 3161, 3166,
+ 3167, 3167, 3167, 3167, 3167, 3167, 3167, 3168,
+ 3167, 3167, 3167, 3167, 3167, 3167, 3167, 3168,
+ 3167, 3167, 3167, 3167, 3167, 3167, 3167, 3167,
+ 3167, 3167, 3169, 3169, 3170, 3159, 3159, 3159,
+ 3171, 3171, 3167, 3167, 3167, 3167, 3167, 3167,
+ 3167, 3168, 3167, 3168, 3168, 3167, 3171, 3172,
+ 3167, 3167, 3167, 3167, 3167, 3167, 3167, 3167,
+ 3167, 3167, 3173, 3173, 3173, 3173, 3174, 3175,
+ 3161, 3174, 3174, 3174, 3174, 3174, 3174, 3174,
+ 3174, 3174, 3174, 3176, 3176, 3176, 3176, 3176,
3176, 3176, 3176, 3176, 3176, 3176, 3176, 3176,
- 3199, 3182, 3182, 3182, 3182, 3182, 3182, 3200,
- 3184, 3184, 3184, 3184, 3184, 3184, 3182, 3184,
- 3175, 3175, 3175, 3175, 3175, 3175, 3175, 3175,
- 3182, 3200, 3200, 3182, 3182, 3182, 3182, 3182,
- 3182, 3182, 3184, 3201, 3182, 3182, 3182, 3189,
- 3184, 3184, 3184, 3184, 3184, 3184, 3201, 3184,
- 3184, 3184, 3184, 3184, 3175, 3193, 3193, 3193,
- 3184, 3184, 3184, 3184, 3184, 3184, 3184, 3184,
- 3184, 3184, 3184, 3184, 3184, 3184, 3184, 3175,
- 3175, 3175, 3175, 3175, 3175, 3175, 3175, 3175,
- 3175, 3175, 3175, 3175, 3193, 3193, 3193, 3193,
- 3193, 3189, 3190, 3193, 3193, 3193, 3193, 3197,
- 3190, 3192, 3193, 3189, 3193, 3193, 3193, 3193,
- 3176, 3176, 3176, 3176, 3176, 3184, 3184, 3184,
- 3184, 3184, 3184, 3184, 3184, 3184, 3184, 3184,
- 3184, 3184, 3175, 3175, 3175, 3175, 3175, 3175,
- 3193, 3193, 3193, 3193, 3193, 3193, 3193, 3193,
- 3193, 3193, 3193, 3190, 3190, 3189, 3189, 3189,
- 3189, 3189, 3189, 3190, 3190, 3190, 3189, 3189,
- 3193, 3193, 3193, 3193, 3193, 3202, 3202, 3193,
- 3202, 3202, 3189, 3198, 3189, 3189, 3189, 3189,
- 3176, 3193, 3193, 3189, 3189, 3189, 3189, 3189,
- 3189, 3189, 3189, 3190, 3192, 3198, 3198, 3198,
- 3175, 3200, 3200, 3200, 3200, 3200, 3200, 3200,
- 3200, 3200, 3200, 3200, 3200, 3200, 3175, 3175,
- 3175, 3175, 3175, 3175, 3175, 3175, 3175, 3193,
- 3193, 3193, 3193, 3193, 3193, 3193, 3193, 3193,
- 3193, 3193, 3193, 3193, 3193, 3193, 3193, 3193,
- 3193, 3193, 3193, 3193, 3193, 3193, 3193, 3193,
-
- 3203, 3203, 3203, 3203, 3203, 3203, 3203, 3203,
- 3203, 3203, 3203, 3203, 3203, 3203, 3203, 3203,
- 3203, 3203, 3203, 3203, 3203, 3203, 3203, 3203,
- 3203, 3203, 3203, 3203, 3203, 3203, 3203, 3203,
- 3203, 3203, 3203, 3203, 3203, 3203, 3203, 3203,
- 3203, 3203, 3203, 3203, 3203, 3203, 3203, 3203,
- 3203, 3203, 3203, 3203, 3203, 3203, 3203, 3203,
- 3203, 3203, 3203, 3203, 3203, 3203, 3203, 3203,
- 3203, 3203, 3203, 3203, 3203, 3203, 3203, 3203,
- 3203, 3203, 3203, 3203, 3203, 3203, 3203, 3203,
- 3203, 3203, 3203, 3203, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3196, 3196, 3196, 3196, 3196, 3196, 3196, 3196,
- 3196, 3196, 3196, 3196, 3196, 3196, 3140, 3140,
- 3189, 3189, 3189, 3189, 3190, 3191, 3191, 3191,
- 3189, 3189, 3189, 3192, 3192, 3140, 3140, 3140,
- 3189, 3189, 3189, 3190, 3190, 3190, 3190, 3191,
- 3191, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3189, 3189, 3189, 3189, 3189, 3189, 3190, 3190,
- 3190, 3190, 3190, 3190, 3190, 3190, 3190, 3190,
- 3190, 3190, 3190, 3190, 3190, 3190, 3190, 3190,
- 3190, 3192, 3192, 3192, 3192, 3191, 3191, 3191,
- 3190, 3190, 3190, 3190, 3190, 3190, 3190, 3192,
- 3192, 3192, 3192, 3191, 3191, 3191, 3140, 3191,
- 3190, 3190, 3190, 3204, 3204, 3204, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3191, 3191,
- 3190, 3190, 3190, 3190, 3190, 3190, 3190, 3192,
- 3192, 3192, 3191, 3191, 3140, 3140, 3140, 3140,
- 3192, 3192, 3192, 3192, 3192, 3192, 3192, 3192,
- 3191, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3204, 3204, 3204, 3204, 3204, 3204, 3204, 3205,
- 3205, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
-
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 221, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
- 1750, 1750, 1750, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 3206, 3207, 3208, 3209, 3210, 3211, 3212, 3213,
- 3214, 3215, 221, 221, 221, 221, 221, 221,
-
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
-
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3140, 3140,
- 3140, 3140, 3140, 3140, 3140, 3140, 3216, 3216,
-
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
-
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 3217,
- 3217, 3217, 3217, 3217, 3217, 3217, 3217, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1909, 1909,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
+ 3176, 3176, 3176, 3176, 3176, 3159, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3177, 3177,
+ 3177, 3177, 3177, 3177, 3177, 3177, 3177, 3177,
+ 3177, 3177, 3177, 3177, 3177, 3177, 3177, 3177,
+ 3177, 3177, 3177, 3177, 3177, 3177, 3177, 3177,
+
+ 3178, 3179, 3179, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891,
+ 1891, 1891, 3180, 1891, 1891, 1891, 1891, 1891,
+ 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891,
+ 1891, 1891, 1891, 1891, 1891, 1891, 1891, 3180,
+ 1891, 1891, 3179, 3179, 3179, 3179, 3179, 3179,
+ 3179, 3179, 3179, 3181, 3147, 3147, 3147, 3147,
+ 1891, 1891, 1891, 1891, 1891, 1891, 1891, 1891,
+ 1891, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3179, 3179, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3182, 3182, 3182, 3182, 3182, 3182, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1683, 1683, 1683, 1683, 1683, 1683, 1683,
+ 1683, 1683, 1683, 1683, 1683, 3183, 3183, 3183,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1683, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1683, 3183, 3183,
+ 1611, 1611, 1611, 1611, 1611, 1684, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1683, 1683, 1683, 1683,
+ 1683, 1683, 1683, 1683, 1614, 1614, 1683, 1683,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1609, 1609, 1611,
+ 1611, 1611, 1611, 1611, 1609, 1611, 1611, 1611,
+ 1611, 1611, 1684, 1684, 1684, 3184, 1611, 1684,
+ 1611, 1611, 1684, 3185, 3185, 1683, 1683, 3183,
+ 3183, 3183, 3183, 3183, 1683, 1683, 1683, 1683,
+ 1683, 1683, 1683, 1683, 1683, 1683, 1683, 1683,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1683, 1683, 1683, 3184, 1683, 1683, 1683,
+ 3183, 3183, 3183, 3186, 3186, 3186, 3186, 3186,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1904, 1904, 1904,
- 1904, 1904, 1904, 1904, 1904, 1909, 1909, 1909,
- 1909, 3218, 2220, 2220, 2220, 2220, 2220, 2220,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
-
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 3219, 3219,
- 3219, 3219, 3219, 3219, 3219, 3219, 2220, 2220,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1683,
+ 1611, 1683, 1684, 1684, 1611, 1611, 1684, 1684,
+ 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684,
+ 1684, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1684, 1684,
+ 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684,
+ 1684, 1684, 1684, 1684, 1684, 1684, 1684, 1684,
+ 1684, 1611, 1611, 1611, 1684, 1611, 1611, 1611,
+ 1611, 1684, 1684, 1684, 1611, 1684, 1684, 1684,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1684,
+ 1611, 1684, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1609, 1611, 1609, 1611, 1609, 1611, 1611, 1611,
+ 1611, 1611, 1684, 1611, 1611, 1611, 1611, 1609,
+ 1611, 1609, 1609, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 3184, 1611, 1611, 1611, 1611, 1683, 1683, 3183,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1609,
+ 1609, 1609, 1609, 1609, 1609, 1609, 1609, 1609,
+ 1609, 1609, 1609, 1609, 1609, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1609, 1609, 1609, 1609, 1609, 1609,
+ 1609, 1609, 1609, 1609, 1609, 1609, 1613, 1613,
+ 3187, 3187, 3187, 3187, 1613, 1613, 1614, 1614,
+ 1614, 1614, 1683, 3183, 3183, 3183, 3183, 3188,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1683, 1683, 1683, 1683, 1683, 1683, 1683, 1683,
+ 1683, 1683, 1683, 1683, 3185, 3185, 1683, 1683,
+ 1683, 1683, 3189, 1683, 1683, 1683, 1683, 1683,
+ 1683, 1683, 1683, 1683, 1683, 1683, 1683, 1683,
+ 1683, 1683, 1683, 1683, 1683, 1683, 1683, 1683,
+ 3185, 1683, 1683, 1683, 1683, 3190, 3190, 1683,
+ 1683, 1683, 1683, 1683, 1683, 1683, 1683, 1683,
+ 1683, 1683, 1683, 1683, 3191, 1683, 1683, 1683,
+ 1683, 1683, 1683, 1683, 1683, 1683, 1683, 1683,
+ 1683, 1683, 1683, 1683, 1683, 1683, 1683, 1683,
+ 1683, 1683, 1683, 1683, 1683, 1683, 1683, 1683,
+ 1683, 1683, 1683, 1683, 1683, 1683, 1683, 1683,
+ 1683, 1683, 1683, 1683, 1683, 1683, 1683, 1683,
+ 1683, 1683, 1683, 1683, 1614, 1614, 1614, 1614,
+ 1614, 1614, 1614, 1614, 1683, 1683, 1683, 1683,
+ 1683, 1683, 1683, 1683, 1683, 1683, 1683, 1683,
+ 1683, 1683, 1683, 1683, 1683, 1683, 1683, 1683,
+ 1683, 1683, 1683, 1683, 1614, 1614, 1614, 1614,
+ 1614, 1614, 1683, 1611, 1611, 1611, 1611, 1611,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
- 1906, 1906, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
-
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
-
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 1907, 1907, 1907, 1907, 1907, 1907, 1907,
- 1907, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
-
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
-
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3221, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3221, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
-
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3221,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3221,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3221,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
-
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 3220, 3220,
- 3220, 3220, 3220, 3220, 3220, 3220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
-
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 3216, 3216,
-
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
-
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 1900, 1900, 1900, 1900, 1900,
- 1900, 1900, 1900, 2220, 2220, 2220, 2220, 2220,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
-
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
-
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 3218, 3218, 3218, 3218, 3218, 3218, 3218, 3218,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
- 2220, 2220, 2220, 2220, 2220, 2220, 2220, 2220,
-
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 221, 221,
- 221, 221, 221, 221, 221, 221, 3216, 3216,
-
- 1467, 3032, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 3222, 3222, 3222, 3222, 3222, 3222, 3222, 3222,
- 3222, 3222, 3222, 3222, 3222, 3222, 3222, 3222,
- 3222, 3222, 3222, 3222, 3222, 3222, 3222, 3222,
- 3222, 3222, 3222, 3222, 3222, 3222, 3222, 3222,
- 3222, 3222, 3222, 3222, 3222, 3222, 3222, 3222,
- 3222, 3222, 3222, 3222, 3222, 3222, 3222, 3222,
- 3222, 3222, 3222, 3222, 3222, 3222, 3222, 3222,
- 3222, 3222, 3222, 3222, 3222, 3222, 3222, 3222,
- 3222, 3222, 3222, 3222, 3222, 3222, 3222, 3222,
- 3222, 3222, 3222, 3222, 3222, 3222, 3222, 3222,
- 3222, 3222, 3222, 3222, 3222, 3222, 3222, 3222,
- 3222, 3222, 3222, 3222, 3222, 3222, 3222, 3222,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
-
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 3223, 3223, 3223, 3223, 3223, 3223, 3223, 3223,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
+ 3192, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 3192, 1611, 1611, 1611, 3192, 1611, 3192,
+ 1611, 3192, 1611, 3192, 1611, 1611, 1611, 3192,
+ 1611, 1611, 1611, 1611, 1611, 1611, 3192, 3192,
+ 1611, 1611, 1611, 1611, 3192, 1611, 3192, 3192,
+ 1611, 1611, 1611, 1611, 3192, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 3184, 3184, 3183, 3183, 1684, 1684, 1684,
+ 1611, 1611, 1611, 1684, 1684, 1684, 1684, 1684,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 3193, 3193,
+ 3193, 3194, 3194, 3194, 1613, 1613, 1613, 1613,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1684, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1611, 1611, 1611, 1611, 1684, 1684, 1684, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1611, 1611,
+ 1684, 1611, 1611, 1611, 1611, 1611, 1683, 1683,
+ 1683, 1683, 1683, 1683, 3190, 1683, 1683, 1683,
+ 3183, 3191, 3191, 3195, 3195, 3196, 3197, 3197,
+ 3147, 3147, 3147, 3147, 3198, 3199, 3199, 3199,
+ 1683, 1683, 1683, 1683, 1683, 1683, 1683, 1683,
+ 1683, 1683, 1683, 3184, 3184, 3147, 3147, 3147,
+ 1683, 1683, 1683, 1683, 3191, 3191, 3191, 3182,
+ 3182, 3200, 3196, 3197, 3197, 3147, 3147, 3147,
+
+ 3201, 3201, 3201, 3201, 3201, 3201, 3201, 3201,
+ 3201, 3201, 3201, 3201, 3201, 3201, 3201, 3201,
+ 3201, 3201, 3201, 3201, 3201, 3201, 3201, 3201,
+ 3201, 3201, 3201, 3201, 3201, 3201, 3201, 3201,
+ 3201, 3201, 3201, 3201, 3201, 3201, 3201, 3201,
+ 3201, 3201, 3201, 3201, 3201, 3201, 3201, 3201,
+ 3201, 3201, 3201, 3201, 3201, 3201, 3201, 3201,
+ 3201, 3201, 3201, 3201, 3201, 3201, 3201, 3201,
+ 3201, 3201, 3201, 3201, 3201, 3201, 3201, 3201,
+ 3201, 3201, 3201, 3201, 3201, 3201, 3201, 3201,
+ 3201, 3201, 3201, 3201, 3201, 3201, 3201, 3201,
+ 3201, 3201, 3201, 3201, 3201, 3201, 3201, 3201,
+ 3201, 3201, 3201, 3201, 3201, 3201, 3201, 3201,
+ 3201, 3201, 3201, 3201, 3201, 3201, 3201, 3201,
+ 3201, 3201, 3201, 3201, 3202, 3202, 3202, 3147,
+ 3147, 3147, 3147, 3202, 3202, 3202, 3202, 3202,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 3203, 3203, 3203,
+ 3203, 3202, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3196, 3196, 3196, 3196, 3196, 3196, 3196, 3196,
+ 3196, 3196, 3196, 3196, 3147, 3147, 3147, 3147,
+ 3199, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 3147, 3147, 3147, 3147,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 3147, 3147, 3147, 3147, 3147, 3147,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1613, 1613, 1613, 1613, 1613, 1613, 3147, 3147,
+ 3159, 3159, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 3204, 3196, 3196, 3205,
+ 3183, 3183, 3183, 3183, 3183, 3183, 3183, 3183,
+ 3206, 3189, 3189, 3189, 3189, 3189, 3189, 3207,
+ 3191, 3191, 3191, 3191, 3191, 3191, 3189, 3191,
+ 3182, 3182, 3182, 3182, 3182, 3182, 3182, 3182,
+ 3189, 3207, 3207, 3189, 3189, 3189, 3189, 3189,
+ 3189, 3189, 3191, 3208, 3189, 3189, 3189, 3196,
+ 3191, 3191, 3191, 3191, 3191, 3191, 3208, 3191,
+ 3191, 3191, 3191, 3191, 3182, 3200, 3200, 3200,
+ 3191, 3191, 3191, 3191, 3191, 3191, 3191, 3191,
+ 3191, 3191, 3191, 3191, 3191, 3191, 3191, 3182,
+ 3182, 3182, 3182, 3182, 3182, 3182, 3182, 3182,
+ 3182, 3182, 3182, 3182, 3200, 3200, 3200, 3200,
+ 3200, 3196, 3197, 3200, 3200, 3200, 3200, 3204,
+ 3197, 3199, 3200, 3196, 3200, 3200, 3200, 3200,
+ 3183, 3183, 3183, 3183, 3183, 3191, 3191, 3191,
+ 3191, 3191, 3191, 3191, 3191, 3191, 3191, 3191,
+ 3191, 3191, 3182, 3182, 3182, 3182, 3182, 3182,
+ 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200,
+ 3200, 3200, 3200, 3197, 3197, 3196, 3196, 3196,
+ 3196, 3196, 3196, 3197, 3197, 3197, 3196, 3196,
+ 3200, 3200, 3200, 3200, 3200, 3209, 3209, 3200,
+ 3209, 3209, 3196, 3205, 3196, 3196, 3196, 3196,
+ 3183, 3200, 3200, 3196, 3196, 3196, 3196, 3196,
+ 3196, 3196, 3196, 3197, 3199, 3205, 3205, 3205,
+ 3182, 3207, 3207, 3207, 3207, 3207, 3207, 3207,
+ 3207, 3207, 3207, 3207, 3207, 3207, 3182, 3182,
+ 3182, 3182, 3182, 3182, 3182, 3182, 3182, 3200,
+ 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200,
+ 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200,
+ 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200,
+
+ 3210, 3210, 3210, 3210, 3210, 3210, 3210, 3210,
+ 3210, 3210, 3210, 3210, 3210, 3210, 3210, 3210,
+ 3210, 3210, 3210, 3210, 3210, 3210, 3210, 3210,
+ 3210, 3210, 3210, 3210, 3210, 3210, 3210, 3210,
+ 3210, 3210, 3210, 3210, 3210, 3210, 3210, 3210,
+ 3210, 3210, 3210, 3210, 3210, 3210, 3210, 3210,
+ 3210, 3210, 3210, 3210, 3210, 3210, 3210, 3210,
+ 3210, 3210, 3210, 3210, 3210, 3210, 3210, 3210,
+ 3210, 3210, 3210, 3210, 3210, 3210, 3210, 3210,
+ 3210, 3210, 3210, 3210, 3210, 3210, 3210, 3210,
+ 3210, 3210, 3210, 3210, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3203, 3203, 3203, 3203, 3203, 3203, 3203, 3203,
+ 3203, 3203, 3203, 3203, 3203, 3203, 3147, 3147,
+ 3196, 3196, 3196, 3196, 3197, 3198, 3198, 3198,
+ 3196, 3196, 3196, 3199, 3199, 3147, 3147, 3147,
+ 3196, 3196, 3196, 3197, 3197, 3197, 3197, 3198,
+ 3198, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3196, 3196, 3196, 3196, 3196, 3196, 3197, 3197,
+ 3197, 3197, 3197, 3197, 3197, 3197, 3197, 3197,
+ 3197, 3197, 3197, 3197, 3197, 3197, 3197, 3197,
+ 3197, 3199, 3199, 3199, 3199, 3198, 3198, 3198,
+ 3197, 3197, 3197, 3197, 3197, 3197, 3197, 3199,
+ 3199, 3199, 3199, 3198, 3198, 3198, 3147, 3198,
+ 3197, 3197, 3197, 3211, 3211, 3211, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3198, 3198,
+ 3197, 3197, 3197, 3197, 3197, 3197, 3197, 3199,
+ 3199, 3199, 3198, 3198, 3147, 3147, 3147, 3147,
+ 3199, 3199, 3199, 3199, 3199, 3199, 3199, 3199,
+ 3198, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3211, 3211, 3211, 3211, 3211, 3211, 3211, 3212,
+ 3212, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
- 1467, 1467, 1467, 1467, 1467, 1467, 1467, 1467,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 221, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751,
+ 1751, 1751, 1751, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 3213, 3214, 3215, 3216, 3217, 3218, 3219, 3220,
+ 3221, 3222, 221, 221, 221, 221, 221, 221,
+
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3147, 3147,
+ 3147, 3147, 3147, 3147, 3147, 3147, 3223, 3223,
3224, 3224, 3224, 3224, 3224, 3224, 3224, 3224,
3224, 3224, 3224, 3224, 3224, 3224, 3224, 3224,
@@ -7132,3240 +6406,4040 @@ static constexpr unsigned short uc_property_trie[] = {
3224, 3224, 3224, 3224, 3224, 3224, 3224, 3224,
3224, 3224, 3224, 3224, 3224, 3224, 3224, 3224,
3224, 3224, 3224, 3224, 3224, 3224, 3224, 3224,
- 3224, 3224, 3224, 3224, 3224, 3224, 3224, 3224,
- 3224, 3224, 3224, 3224, 3224, 3224, 3224, 3224,
- 3224, 3224, 3224, 3224, 3224, 3224, 3224, 3224,
- 3224, 3224, 3224, 3224, 3224, 3224, 3224, 3224,
- 3224, 3224, 3224, 3224, 3224, 3224, 3224, 3224,
- 3224, 3224, 3224, 3224, 3224, 3224, 3216, 3216
+ 3224, 3224, 3224, 3224, 3224, 3224, 3224, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1911, 1911,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1906, 1906, 1906,
+ 1906, 1906, 1906, 1906, 1906, 1911, 1911, 1911,
+ 1911, 3225, 2223, 2223, 2223, 2223, 2223, 2223,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 3226, 3226,
+ 3226, 3226, 3226, 3226, 3226, 3226, 2223, 2223,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 1908, 1908, 1908, 1908, 1908, 1908,
+ 1908, 1908, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 1909, 1909, 1909, 1909, 1909, 1909, 1909,
+ 1909, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 3227, 3227,
+ 3227, 3227, 3227, 3227, 3227, 3227, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3229, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3229, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3229,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3229,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3229,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 3228, 3228,
+ 3228, 3228, 3228, 3228, 3228, 3228, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 3223, 3223,
+
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 1902, 1902, 1902, 1902, 1902,
+ 1902, 1902, 1902, 2223, 2223, 2223, 2223, 2223,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 3225, 3225, 3225, 3225, 3225, 3225, 3225, 3225,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+ 2223, 2223, 2223, 2223, 2223, 2223, 2223, 2223,
+
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 3223, 3223,
+
+ 1468, 3039, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 3230, 3230, 3230, 3230, 3230, 3230, 3230, 3230,
+ 3230, 3230, 3230, 3230, 3230, 3230, 3230, 3230,
+ 3230, 3230, 3230, 3230, 3230, 3230, 3230, 3230,
+ 3230, 3230, 3230, 3230, 3230, 3230, 3230, 3230,
+ 3230, 3230, 3230, 3230, 3230, 3230, 3230, 3230,
+ 3230, 3230, 3230, 3230, 3230, 3230, 3230, 3230,
+ 3230, 3230, 3230, 3230, 3230, 3230, 3230, 3230,
+ 3230, 3230, 3230, 3230, 3230, 3230, 3230, 3230,
+ 3230, 3230, 3230, 3230, 3230, 3230, 3230, 3230,
+ 3230, 3230, 3230, 3230, 3230, 3230, 3230, 3230,
+ 3230, 3230, 3230, 3230, 3230, 3230, 3230, 3230,
+ 3230, 3230, 3230, 3230, 3230, 3230, 3230, 3230,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 3231, 3231, 3231, 3231, 3231, 3231, 3231, 3231,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+ 1468, 1468, 1468, 1468, 1468, 1468, 1468, 1468,
+
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3232, 3232,
+ 3232, 3232, 3232, 3232, 3232, 3232, 3223, 3223
};
static constexpr Properties uc_properties[] = {
- { 9, 18, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 0, 21, 0, 0, 2 },
- { 9, 8, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 0, 17, 5, 0, 2 },
- { 9, 7, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 2, 2, 37, 2, 0, 2 },
- { 9, 8, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 3, 38, 5, 0, 2 },
- { 9, 9, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 3, 38, 5, 0, 2 },
- { 9, 7, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 1, 1, 36, 1, 0, 2 },
- { 9, 7, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 0, 21, 0, 0, 2 },
- { 9, 8, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 0, 21, 0, 0, 2 },
- { 6, 9, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 18, 35, 5, 0, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 12, 0, 2 },
+ { 9, 18, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 0, 23, 0, 0, 2 },
+ { 9, 8, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 0, 19, 5, 0, 2 },
+ { 9, 7, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 2, 2, 39, 2, 0, 2 },
+ { 9, 8, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 3, 40, 5, 0, 2 },
+ { 9, 9, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 3, 40, 5, 0, 2 },
+ { 9, 7, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 1, 1, 38, 1, 0, 2 },
+ { 9, 7, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 0, 23, 0, 0, 2 },
+ { 9, 8, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 0, 23, 0, 0, 2 },
+ { 6, 9, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 18, 37, 5, 0, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 12, 0, 2 },
{ 25, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 12, 3, 13, 0, 2 },
+ { 25, 4, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 27, 4, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 0, 2 },
{ 25, 4, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 27, 4, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 0, 2 },
- { 25, 4, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 0, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
{ 25, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 11, 3, 13, 0, 2 },
{ 21, 10, 0, 0, -1, 1, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 0, 2 },
{ 22, 10, 0, 0, -1, -1, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 2, 13, 0, 2 },
- { 26, 3, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 0, 2 },
- { 25, 6, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 8, 11, 0, 2 },
- { 20, 3, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 11, 1, 2 },
- { 25, 6, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 8, 10, 1, 2 },
- { 25, 6, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 7, 0, 0, 2 },
- { 3, 2, 0, 0, 0, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 2 },
- { 3, 2, 0, 0, 1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 2 },
- { 3, 2, 0, 0, 2, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 2 },
- { 3, 2, 0, 0, 3, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 2 },
- { 3, 2, 0, 0, 4, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 2 },
- { 3, 2, 0, 0, 5, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 2 },
- { 3, 2, 0, 0, 6, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 2 },
- { 3, 2, 0, 0, 7, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 2 },
- { 3, 2, 0, 0, 8, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 2 },
- { 3, 2, 0, 0, 9, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 2 },
- { 25, 6, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 11, 0, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 8, 0, 0, 2 },
- { 26, 10, 0, 0, -1, 2, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 26, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 26, 10, 0, 0, -1, -2, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 14, 0, 0, 0, -1, 0, 1, 4, 0, { {0, 32}, {0, 0}, {0, 0}, {0, 32} }, 0, 10, 12, 7, 3, 3 },
+ { 26, 3, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 0, 2 },
+ { 25, 6, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 10, 11, 0, 2 },
+ { 20, 3, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 11, 1, 2 },
+ { 25, 6, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 10, 10, 1, 2 },
+ { 25, 6, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 0, 2 },
+ { 3, 2, 0, 0, 0, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 2 },
+ { 3, 2, 0, 0, 1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 2 },
+ { 3, 2, 0, 0, 2, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 2 },
+ { 3, 2, 0, 0, 3, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 2 },
+ { 3, 2, 0, 0, 4, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 2 },
+ { 3, 2, 0, 0, 5, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 2 },
+ { 3, 2, 0, 0, 6, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 2 },
+ { 3, 2, 0, 0, 7, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 2 },
+ { 3, 2, 0, 0, 8, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 2 },
+ { 3, 2, 0, 0, 9, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 2 },
+ { 25, 6, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 11, 0, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 10, 0, 0, 2 },
+ { 26, 10, 0, 0, -1, 2, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 26, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 26, 10, 0, 0, -1, -2, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 14, 0, 0, 0, -1, 0, 1, 4, 0, { {0, 32}, {0, 0}, {0, 0}, {0, 32} }, 0, 10, 14, 7, 3, 3 },
{ 21, 10, 0, 0, -1, 2, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 0, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 0, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 0, 2 },
{ 22, 10, 0, 0, -1, -2, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 2, 13, 0, 2 },
- { 28, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 19, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 17, 12, 0, 1, 2 },
- { 15, 0, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 26, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 0, 2 },
+ { 28, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 19, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 17, 14, 0, 1, 2 },
+ { 15, 0, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 26, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 0, 2 },
{ 22, 10, 0, 0, -1, -2, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 0, 2 },
- { 9, 7, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 3, 38, 3, 0, 2 },
- { 6, 6, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 4, 5, 0, 2 },
+ { 9, 7, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 3, 40, 3, 0, 2 },
+ { 6, 6, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 5, 0, 2 },
{ 25, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 0, 1, 2 },
- { 27, 4, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 1, 2 },
- { 27, 4, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 2 },
- { 27, 4, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 28, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
- { 18, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
+ { 27, 4, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
+ { 27, 4, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 2 },
+ { 27, 4, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 28, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
+ { 18, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
{ 23, 10, 0, 0, -1, 16, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 3, 13, 1, 2 },
- { 26, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 10, 18, 0, 5, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 17, 4, 2, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
- { 28, 10, 0, 0, -1, 0, 1, 4, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 29, 4, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 1, 2 },
- { 26, 4, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 2 },
- { 5, 2, 0, 0, 2, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 5, 2, 0, 0, 3, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 28, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 0, 0, 2 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 743}, {0, 743}, {0, 775} }, 0, 10, 12, 6, 3, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 14, 12, 0, 1, 2 },
- { 5, 2, 0, 0, 1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
+ { 26, 10, 0, 0, -1, 0, 1, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 10, 18, 0, 5, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 19, 4, 2, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
+ { 28, 10, 0, 0, -1, 0, 1, 4, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 29, 4, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
+ { 26, 4, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 2 },
+ { 5, 2, 0, 0, 2, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 5, 2, 0, 0, 3, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 28, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 20, 0, 0, 2 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 743}, {0, 743}, {0, 775} }, 0, 10, 14, 6, 3, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 14, 14, 0, 1, 2 },
+ { 5, 2, 0, 0, 1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
{ 24, 10, 0, 0, -1, -16, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 3, 13, 1, 2 },
- { 5, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 32}, {0, 0}, {0, 0}, {0, 32} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 32}, {0, 0}, {0, 0}, {0, 32} }, 0, 10, 12, 7, 3, 3 },
- { 26, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 15, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {1, 418}, {1, 415}, {0, 0} }, 0, 10, 12, 6, 4, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 0, 17, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 121}, {0, 121}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 0, 17, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {1, 421}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, -232}, {0, -232}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {1, 500}, {1, 500}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -121}, {0, 0}, {0, 0}, {0, -121} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, -300}, {0, -300}, {0, -268} }, 0, 10, 12, 6, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 195}, {0, 195}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 210}, {0, 0}, {0, 0}, {0, 210} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 206}, {0, 0}, {0, 0}, {0, 206} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 205}, {0, 0}, {0, 0}, {0, 205} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 79}, {0, 0}, {0, 0}, {0, 79} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 202}, {0, 0}, {0, 0}, {0, 202} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 203}, {0, 0}, {0, 0}, {0, 203} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 207}, {0, 0}, {0, 0}, {0, 207} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 97}, {0, 97}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 211}, {0, 0}, {0, 0}, {0, 211} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 209}, {0, 0}, {0, 0}, {0, 209} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 163}, {0, 163}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 213}, {0, 0}, {0, 0}, {0, 213} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 130}, {0, 130}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 214}, {0, 0}, {0, 0}, {0, 214} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 218}, {0, 0}, {0, 0}, {0, 218} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 217}, {0, 0}, {0, 0}, {0, 217} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 219}, {0, 0}, {0, 0}, {0, 219} }, 0, 10, 12, 7, 3, 3 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 56}, {0, 56}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 2}, {0, 0}, {0, 1}, {0, 2} }, 0, 10, 12, 7, 3, 3 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 1}, {0, -1}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, -2}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -79}, {0, -79}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 511}, {1, 511}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {0, -97}, {0, 0}, {0, 0}, {0, -97} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {0, -56}, {0, 0}, {0, 0}, {0, -56} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 17, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 4, 3, 17, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 6, 3, 0, { {0, -130}, {0, 0}, {0, 0}, {0, -130} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 8, 3, 0, { {1, 1}, {0, 0}, {0, 0}, {1, 1} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 8, 3, 0, { {0, -163}, {0, 0}, {0, 0}, {0, -163} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 8, 3, 0, { {1, 3}, {0, 0}, {0, 0}, {1, 3} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {1, 5}, {1, 5}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {1, 7}, {1, 7}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 9, 3, 0, { {0, -195}, {0, 0}, {0, 0}, {0, -195} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 69}, {0, 0}, {0, 0}, {0, 69} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 71}, {0, 0}, {0, 0}, {0, 71} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 9}, {1, 9}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {1, 11}, {1, 11}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 13}, {1, 13}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -210}, {0, -210}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -206}, {0, -206}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -205}, {0, -205}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -202}, {0, -202}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -203}, {0, -203}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 15}, {1, 15}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {1, 17}, {1, 17}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -207}, {0, -207}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 19}, {1, 19}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 21}, {1, 21}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -209}, {0, -209}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -211}, {0, -211}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 23}, {1, 23}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 25}, {1, 25}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 27}, {1, 27}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 29}, {1, 29}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -213}, {0, -213}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -214}, {0, -214}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 31}, {1, 31}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -218}, {0, -218}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 33}, {1, 33}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 35}, {1, 35}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -69}, {0, -69}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -217}, {0, -217}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -71}, {0, -71}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -219}, {0, -219}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 37}, {1, 37}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 39}, {1, 39}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 17, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 17, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 2 },
- { 17, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 2 },
- { 17, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 2 },
- { 28, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 0, 1, 2 },
- { 28, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 0, 1, 2 },
- { 17, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 2 },
- { 17, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 18, 8, 1, 2 },
- { 17, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 2 },
- { 28, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 28, 10, 0, 0, -1, 0, 4, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 18, 0, 1, 2 },
- { 28, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 0, 1, 36 },
- { 17, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 2 },
- { 28, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 0, 1, 2 },
- { 17, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 2 },
- { 28, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 0, 1, 2 },
- { 0, 17, 230, 5, -1, 0, 1, 0, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 230, 5, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 232, 5, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 220, 5, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 216, 5, -1, 0, 1, 0, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 202, 5, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 220, 5, -1, 0, 1, 0, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 202, 5, -1, 0, 1, 0, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 1, 5, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 1, 5, -1, 0, 1, 0, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 230, 5, -1, 0, 1, 0, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 3, 1 },
- { 0, 17, 240, 5, -1, 0, 1, 0, 204, { {0, 0}, {0, 84}, {0, 84}, {0, 116} }, 4, 4, 21, 4, 3, 1 },
- { 0, 17, 230, 5, -1, 0, 4, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 220, 5, -1, 0, 4, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 0, 5, -1, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 4, 4, 2, 1 },
- { 0, 17, 230, 5, -1, 0, 7, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 220, 5, -1, 0, 7, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 232, 5, -1, 0, 8, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 220, 5, -1, 0, 8, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 230, 5, -1, 0, 8, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 233, 5, -1, 0, 8, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 4, 4, 1, 1 },
- { 0, 17, 234, 5, -1, 0, 7, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 4, 4, 1, 1 },
- { 0, 17, 233, 5, -1, 0, 7, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 4, 4, 1, 1 },
- { 0, 17, 234, 5, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 4, 4, 1, 1 },
- { 0, 17, 233, 5, -1, 0, 4, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 4, 4, 1, 1 },
- { 0, 17, 230, 5, -1, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 14, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 17, 10, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 3, 2 },
- { 28, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 4 },
- { 13, 0, 0, 0, -1, 0, 0, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 0 },
- { 17, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 0, 4 },
- { 15, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 130}, {0, 130}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 25, 10, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 8, 0, 0, 2 },
- { 14, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 116}, {0, 0}, {0, 0}, {0, 116} }, 0, 10, 12, 7, 3, 4 },
- { 28, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 4 },
- { 28, 10, 0, 0, -1, 0, 1, 3, 81, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 38}, {0, 0}, {0, 0}, {0, 38} }, 0, 10, 12, 7, 3, 4 },
- { 25, 10, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 14, 12, 0, 3, 2 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 37}, {0, 0}, {0, 0}, {0, 37} }, 0, 10, 12, 7, 3, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 64}, {0, 0}, {0, 0}, {0, 64} }, 0, 10, 12, 7, 3, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 63}, {0, 0}, {0, 0}, {0, 63} }, 0, 10, 12, 7, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 503}, {1, 503}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 32}, {0, 0}, {0, 0}, {0, 32} }, 0, 10, 12, 7, 3, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 32}, {0, 0}, {0, 0}, {0, 32} }, 0, 10, 12, 7, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, -38}, {0, -38}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, -37}, {0, -37}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 507}, {1, 507}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -31}, {0, -31}, {0, 1} }, 0, 10, 12, 6, 4, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, -64}, {0, -64}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, -63}, {0, -63}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 14, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 8}, {0, 0}, {0, 0}, {0, 8} }, 0, 10, 12, 7, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, -62}, {0, -62}, {0, -30} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, -57}, {0, -57}, {0, -25} }, 0, 10, 12, 6, 3, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 3, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 81, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, -47}, {0, -47}, {0, -15} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, -54}, {0, -54}, {0, -22} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, -8}, {0, -8}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 14, 0, 0, 0, -1, 0, 6, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 46 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 46 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, -86}, {0, -86}, {0, -54} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, -80}, {0, -80}, {0, -48} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 7}, {0, 7}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -116}, {0, -116}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 14, 0, 0, 0, -1, 0, 5, 3, 80, { {0, -60}, {0, 0}, {0, 0}, {0, -60} }, 0, 10, 12, 7, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 5, 3, 80, { {0, 0}, {0, -96}, {0, -96}, {0, -64} }, 0, 10, 12, 6, 3, 4 },
- { 26, 10, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 4 },
- { 14, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 14, 0, 0, 0, -1, 0, 7, 3, 80, { {0, -7}, {0, 0}, {0, 0}, {0, -7} }, 0, 10, 12, 7, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 14, 0, 0, 0, -1, 0, 8, 3, 0, { {0, -130}, {0, 0}, {0, 0}, {0, -130} }, 0, 10, 12, 7, 3, 4 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 17, { {0, 80}, {0, 0}, {0, 0}, {0, 80} }, 0, 10, 12, 7, 3, 5 },
- { 14, 0, 0, 0, -1, 0, 1, 0, 17, { {0, 80}, {0, 0}, {0, 0}, {0, 80} }, 0, 10, 12, 7, 3, 5 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 80}, {0, 0}, {0, 0}, {0, 80} }, 0, 10, 12, 7, 3, 5 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 80}, {0, 0}, {0, 0}, {0, 80} }, 0, 10, 12, 7, 3, 5 },
- { 14, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 32}, {0, 0}, {0, 0}, {0, 32} }, 0, 10, 12, 7, 3, 5 },
- { 14, 0, 0, 0, -1, 0, 1, 0, 17, { {0, 32}, {0, 0}, {0, 0}, {0, 32} }, 0, 10, 12, 7, 3, 5 },
- { 15, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 12, 6, 1, 5 },
- { 15, 0, 0, 0, -1, 0, 1, 0, 17, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 12, 6, 1, 5 },
- { 15, 0, 0, 0, -1, 0, 4, 3, 17, { {0, 0}, {0, -80}, {0, -80}, {0, 0} }, 0, 10, 12, 6, 1, 5 },
- { 15, 0, 0, 0, -1, 0, 1, 0, 17, { {0, 0}, {0, -80}, {0, -80}, {0, 0} }, 0, 10, 12, 6, 1, 5 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -80}, {0, -80}, {0, 0} }, 0, 10, 12, 6, 1, 5 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, -80}, {0, -80}, {0, 0} }, 0, 10, 12, 6, 1, 5 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 5 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 5 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 5 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 5 },
- { 29, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 5 },
- { 0, 17, 230, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 5 },
- { 0, 17, 230, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 230, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 5 },
- { 2, 17, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 5 },
- { 14, 0, 0, 0, -1, 0, 6, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 5 },
- { 15, 0, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 5 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 5 },
- { 15, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 5 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 15}, {0, 0}, {0, 0}, {0, 15} }, 0, 10, 12, 7, 0, 5 },
- { 15, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, -15}, {0, -15}, {0, 0} }, 0, 10, 12, 6, 1, 5 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 17, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 5 },
- { 15, 0, 0, 0, -1, 0, 4, 3, 17, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 5 },
- { 14, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 5 },
- { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 5 },
- { 14, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 5 },
- { 15, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 5 },
- { 14, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 5 },
- { 15, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 5 },
- { 14, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 5 },
- { 15, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 5 },
- { 14, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 5 },
- { 15, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 5 },
- { 14, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 5 },
- { 15, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 5 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 48}, {0, 0}, {0, 0}, {0, 48} }, 0, 10, 12, 7, 3, 6 },
- { 17, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 6 },
- { 25, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 0, 1, 6 },
- { 25, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 11, 1, 6 },
- { 25, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 14, 12, 0, 1, 6 },
- { 15, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 6 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -48}, {0, -48}, {0, 0} }, 0, 10, 12, 6, 1, 6 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 467}, {1, 464}, {0, 0} }, 0, 10, 12, 6, 3, 6 },
- { 25, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 8, 12, 1, 6 },
- { 20, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 17, 0, 1, 6 },
- { 29, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 6 },
- { 27, 4, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 6 },
- { 13, 1, 0, 0, -1, 0, 0, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 0 },
- { 0, 17, 220, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 0, 17, 230, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 0, 17, 222, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 0, 17, 220, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 0, 17, 228, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 0, 17, 10, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 0, 17, 11, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 0, 17, 12, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 0, 17, 13, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 0, 17, 14, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 0, 17, 15, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 0, 17, 16, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 0, 17, 17, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 0, 17, 18, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 0, 17, 19, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 0, 17, 19, 5, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 0, 17, 20, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 0, 17, 21, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 0, 17, 22, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 20, 1, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 7 },
- { 0, 17, 23, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 25, 1, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 7 },
- { 0, 17, 24, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 0, 17, 25, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 25, 1, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 0, 1, 7 },
- { 0, 17, 18, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 18, 1, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 9, 13, 8, 1, 7 },
- { 18, 1, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 9, 13, 8, 1, 7 },
- { 25, 1, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 7 },
- { 25, 1, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 14, 12, 0, 1, 7 },
- { 10, 5, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 6, 12, 4, 0, 8 },
- { 10, 5, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 6, 12, 4, 0, 8 },
- { 10, 5, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 6, 12, 4, 0, 2 },
- { 26, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
- { 26, 13, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
- { 25, 4, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 1, 8 },
- { 27, 13, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 1, 8 },
- { 25, 6, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 8, 11, 1, 2 },
- { 25, 13, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 8, 11, 1, 8 },
- { 29, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
- { 0, 17, 230, 5, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 0, 17, 230, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 0, 17, 30, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 0, 17, 31, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 0, 17, 32, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 25, 13, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 0, 1, 2 },
- { 10, 13, 0, 5, -1, 0, 15, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 21, 4, 0, 8 },
- { 25, 13, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 12, 1, 8 },
- { 25, 13, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 12, 1, 8 },
- { 25, 13, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 12, 1, 2 },
- { 18, 13, 0, 2, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 3, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 2, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 3, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 2, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 2, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 17, 13, 0, 1, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 2 },
- { 0, 17, 27, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 28, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 29, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 30, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 31, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 32, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 33, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 34, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 230, 5, -1, 0, 4, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 220, 5, -1, 0, 4, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 220, 5, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 0, 17, 230, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 0, 17, 220, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 0, 17, 220, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 3, 5, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 3, 5, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 3, 5, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 3, 5, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 3, 5, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 3, 5, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 3, 5, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 3, 5, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 3, 5, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 3, 5, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 25, 4, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 1, 8 },
- { 25, 5, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 25, 5, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 11, 9, 1, 8 },
- { 25, 13, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
- { 18, 13, 0, 2, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 0, 17, 35, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 18, 13, 0, 3, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 3, 8 },
- { 18, 13, 0, 2, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 3, 8 },
- { 18, 13, 0, 2, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 3, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 25, 13, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 12, 1, 8 },
- { 0, 17, 230, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 10, 5, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 6, 12, 4, 0, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
- { 0, 17, 220, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 17, 13, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 3, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 3, 2, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 3, 2, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 3, 2, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 3, 2, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 3, 2, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 3, 2, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 3, 2, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 3, 2, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 3, 2, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 3, 2, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 8 },
- { 29, 13, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
- { 18, 13, 0, 2, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 25, 13, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 12, 1, 9 },
- { 25, 13, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 9 },
- { 13, 13, 0, 0, -1, 0, 0, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 0 },
- { 10, 13, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 6, 12, 4, 0, 9 },
- { 18, 13, 0, 3, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 9 },
- { 0, 17, 36, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 9 },
- { 18, 13, 0, 2, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 9 },
- { 18, 13, 0, 2, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 9 },
- { 18, 13, 0, 3, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 9 },
- { 0, 17, 230, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 9 },
- { 0, 17, 220, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 9 },
- { 18, 13, 0, 2, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 3, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 3, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 10 },
- { 0, 17, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 10 },
- { 18, 13, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 10 },
- { 3, 1, 0, 0, 0, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 66 },
- { 3, 1, 0, 0, 1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 66 },
- { 3, 1, 0, 0, 2, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 66 },
- { 3, 1, 0, 0, 3, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 66 },
- { 3, 1, 0, 0, 4, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 66 },
- { 3, 1, 0, 0, 5, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 66 },
- { 3, 1, 0, 0, 6, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 66 },
- { 3, 1, 0, 0, 7, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 66 },
- { 3, 1, 0, 0, 8, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 66 },
- { 3, 1, 0, 0, 9, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 66 },
- { 18, 1, 0, 2, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 66 },
- { 0, 17, 230, 5, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 66 },
- { 0, 17, 220, 5, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 66 },
- { 17, 1, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 66 },
- { 29, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 66 },
- { 25, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 66 },
- { 25, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 8, 11, 1, 66 },
- { 25, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 12, 1, 66 },
- { 17, 1, 0, 1, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 66 },
- { 0, 17, 220, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 66 },
- { 27, 1, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 66 },
- { 18, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 82 },
- { 0, 17, 230, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 82 },
- { 17, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 82 },
- { 25, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 82 },
- { 25, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 12, 1, 82 },
- { 18, 1, 0, 3, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 95 },
- { 18, 1, 0, 2, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 95 },
- { 0, 17, 220, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 95 },
- { 25, 1, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 95 },
- { 18, 13, 0, 2, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 9 },
- { 18, 13, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 9 },
- { 18, 13, 0, 3, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 9 },
- { 18, 13, 0, 3, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 1, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 2, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 28, 13, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
- { 10, 5, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 6, 12, 4, 0, 8 },
- { 0, 17, 230, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 0, 17, 220, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 18, 13, 0, 2, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 2, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 3, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 3, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 2, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 2, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 3, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 18, 13, 0, 2, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 17, 13, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 0, 17, 220, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 0, 17, 230, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 10, 5, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 6, 12, 4, 0, 2 },
- { 0, 17, 220, 5, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 0, 17, 230, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 0, 17, 220, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 0, 17, 27, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 0, 17, 28, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 0, 17, 29, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 0, 17, 230, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 0, 17, 0, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 11 },
- { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 11 },
- { 1, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 11 },
- { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 11 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 11 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 11 },
- { 0, 17, 0, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 11 },
- { 1, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 11 },
- { 0, 17, 7, 5, -1, 0, 1, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 11 },
- { 0, 17, 9, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 11 },
- { 1, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 11 },
- { 0, 17, 220, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 3, 11 },
- { 25, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 2 },
- { 3, 0, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 11 },
- { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 11 },
- { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 11 },
- { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 11 },
- { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 11 },
- { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 11 },
- { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 11 },
- { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 11 },
- { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 11 },
- { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 11 },
- { 25, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 11 },
- { 17, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 11 },
- { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 11 },
- { 18, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 11 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 11 },
- { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 11 },
- { 18, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 11 },
- { 18, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 11 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 12 },
- { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 12 },
- { 1, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 12 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 12 },
- { 0, 17, 7, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 12 },
- { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 12 },
- { 1, 0, 0, 0, -1, 0, 1, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 12 },
- { 1, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 12 },
- { 0, 17, 9, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 12 },
- { 18, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 12 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 3, 12 },
- { 3, 0, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 12 },
- { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 12 },
- { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 12 },
- { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 12 },
- { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 12 },
- { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 12 },
- { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 12 },
- { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 12 },
- { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 12 },
- { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 12 },
- { 27, 4, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 1, 12 },
+ { 5, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 32}, {0, 0}, {0, 0}, {0, 32} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 32}, {0, 0}, {0, 0}, {0, 32} }, 0, 10, 14, 7, 3, 3 },
+ { 26, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 15, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {1, 418}, {1, 415}, {0, 0} }, 0, 10, 14, 6, 4, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 0, 17, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 121}, {0, 121}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 0, 17, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {1, 421}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, -232}, {0, -232}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {1, 500}, {1, 500}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -121}, {0, 0}, {0, 0}, {0, -121} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, -300}, {0, -300}, {0, -268} }, 0, 10, 14, 6, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 195}, {0, 195}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 210}, {0, 0}, {0, 0}, {0, 210} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 206}, {0, 0}, {0, 0}, {0, 206} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 205}, {0, 0}, {0, 0}, {0, 205} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 79}, {0, 0}, {0, 0}, {0, 79} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 202}, {0, 0}, {0, 0}, {0, 202} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 203}, {0, 0}, {0, 0}, {0, 203} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 207}, {0, 0}, {0, 0}, {0, 207} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 97}, {0, 97}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 211}, {0, 0}, {0, 0}, {0, 211} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 209}, {0, 0}, {0, 0}, {0, 209} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 163}, {0, 163}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 213}, {0, 0}, {0, 0}, {0, 213} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 130}, {0, 130}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 214}, {0, 0}, {0, 0}, {0, 214} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 218}, {0, 0}, {0, 0}, {0, 218} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 217}, {0, 0}, {0, 0}, {0, 217} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 219}, {0, 0}, {0, 0}, {0, 219} }, 0, 10, 14, 7, 3, 3 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 56}, {0, 56}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 2}, {0, 0}, {0, 1}, {0, 2} }, 0, 10, 14, 7, 3, 3 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 1}, {0, -1}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, -2}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -79}, {0, -79}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 511}, {1, 511}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {0, -97}, {0, 0}, {0, 0}, {0, -97} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {0, -56}, {0, 0}, {0, 0}, {0, -56} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 17, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 4, 3, 17, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 6, 3, 0, { {0, -130}, {0, 0}, {0, 0}, {0, -130} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 8, 3, 0, { {1, 1}, {0, 0}, {0, 0}, {1, 1} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 8, 3, 0, { {0, -163}, {0, 0}, {0, 0}, {0, -163} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 8, 3, 0, { {1, 3}, {0, 0}, {0, 0}, {1, 3} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {1, 5}, {1, 5}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {1, 7}, {1, 7}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 9, 3, 0, { {0, -195}, {0, 0}, {0, 0}, {0, -195} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 69}, {0, 0}, {0, 0}, {0, 69} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 71}, {0, 0}, {0, 0}, {0, 71} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 9}, {1, 9}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {1, 11}, {1, 11}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 13}, {1, 13}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -210}, {0, -210}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -206}, {0, -206}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -205}, {0, -205}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -202}, {0, -202}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -203}, {0, -203}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 15}, {1, 15}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {1, 17}, {1, 17}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -207}, {0, -207}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 19}, {1, 19}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 21}, {1, 21}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -209}, {0, -209}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -211}, {0, -211}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 23}, {1, 23}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 25}, {1, 25}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 27}, {1, 27}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 29}, {1, 29}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -213}, {0, -213}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -214}, {0, -214}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 31}, {1, 31}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -218}, {0, -218}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 33}, {1, 33}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 35}, {1, 35}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -69}, {0, -69}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -217}, {0, -217}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -71}, {0, -71}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -219}, {0, -219}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 37}, {1, 37}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {1, 39}, {1, 39}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 17, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 17, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 2 },
+ { 17, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 2 },
+ { 17, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 2 },
+ { 28, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 0, 1, 2 },
+ { 28, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 0, 1, 2 },
+ { 17, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 2 },
+ { 17, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 20, 8, 1, 2 },
+ { 17, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 2 },
+ { 28, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 28, 10, 0, 0, -1, 0, 4, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 20, 0, 1, 2 },
+ { 28, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 0, 1, 36 },
+ { 17, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 2 },
+ { 28, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 0, 1, 2 },
+ { 17, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 2 },
+ { 28, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 0, 1, 2 },
+ { 0, 17, 230, 5, -1, 0, 1, 0, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 230, 5, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 232, 5, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 220, 5, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 216, 5, -1, 0, 1, 0, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 202, 5, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 220, 5, -1, 0, 1, 0, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 202, 5, -1, 0, 1, 0, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 1, 5, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 1, 5, -1, 0, 1, 0, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 230, 5, -1, 0, 1, 0, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 3, 1 },
+ { 0, 17, 240, 5, -1, 0, 1, 0, 204, { {0, 0}, {0, 84}, {0, 84}, {0, 116} }, 4, 4, 23, 4, 3, 1 },
+ { 0, 17, 230, 5, -1, 0, 4, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 220, 5, -1, 0, 4, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 0, 5, -1, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 6, 4, 2, 1 },
+ { 0, 17, 230, 5, -1, 0, 7, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 220, 5, -1, 0, 7, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 232, 5, -1, 0, 8, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 220, 5, -1, 0, 8, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 230, 5, -1, 0, 8, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 233, 5, -1, 0, 8, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 6, 4, 1, 1 },
+ { 0, 17, 234, 5, -1, 0, 7, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 6, 4, 1, 1 },
+ { 0, 17, 233, 5, -1, 0, 7, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 6, 4, 1, 1 },
+ { 0, 17, 234, 5, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 6, 4, 1, 1 },
+ { 0, 17, 233, 5, -1, 0, 4, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 6, 4, 1, 1 },
+ { 0, 17, 230, 5, -1, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 14, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 17, 10, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 3, 2 },
+ { 28, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 4 },
+ { 13, 0, 0, 0, -1, 0, 0, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 0 },
+ { 17, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 0, 4 },
+ { 15, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 130}, {0, 130}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 25, 10, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 10, 0, 0, 2 },
+ { 14, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 116}, {0, 0}, {0, 0}, {0, 116} }, 0, 10, 14, 7, 3, 4 },
+ { 28, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 4 },
+ { 28, 10, 0, 0, -1, 0, 1, 3, 81, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 38}, {0, 0}, {0, 0}, {0, 38} }, 0, 10, 14, 7, 3, 4 },
+ { 25, 10, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 14, 14, 0, 3, 2 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 37}, {0, 0}, {0, 0}, {0, 37} }, 0, 10, 14, 7, 3, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 64}, {0, 0}, {0, 0}, {0, 64} }, 0, 10, 14, 7, 3, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 63}, {0, 0}, {0, 0}, {0, 63} }, 0, 10, 14, 7, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 503}, {1, 503}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 32}, {0, 0}, {0, 0}, {0, 32} }, 0, 10, 14, 7, 3, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 32}, {0, 0}, {0, 0}, {0, 32} }, 0, 10, 14, 7, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, -38}, {0, -38}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, -37}, {0, -37}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 507}, {1, 507}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -31}, {0, -31}, {0, 1} }, 0, 10, 14, 6, 4, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, -64}, {0, -64}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, -63}, {0, -63}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 14, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 8}, {0, 0}, {0, 0}, {0, 8} }, 0, 10, 14, 7, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, -62}, {0, -62}, {0, -30} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, -57}, {0, -57}, {0, -25} }, 0, 10, 14, 6, 3, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 3, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 81, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, -47}, {0, -47}, {0, -15} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, -54}, {0, -54}, {0, -22} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, -8}, {0, -8}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 14, 0, 0, 0, -1, 0, 6, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 46 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 46 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, -86}, {0, -86}, {0, -54} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, -80}, {0, -80}, {0, -48} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 7}, {0, 7}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -116}, {0, -116}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 14, 0, 0, 0, -1, 0, 5, 3, 80, { {0, -60}, {0, 0}, {0, 0}, {0, -60} }, 0, 10, 14, 7, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 5, 3, 80, { {0, 0}, {0, -96}, {0, -96}, {0, -64} }, 0, 10, 14, 6, 3, 4 },
+ { 26, 10, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 4 },
+ { 14, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 14, 0, 0, 0, -1, 0, 7, 3, 80, { {0, -7}, {0, 0}, {0, 0}, {0, -7} }, 0, 10, 14, 7, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 14, 0, 0, 0, -1, 0, 8, 3, 0, { {0, -130}, {0, 0}, {0, 0}, {0, -130} }, 0, 10, 14, 7, 3, 4 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 17, { {0, 80}, {0, 0}, {0, 0}, {0, 80} }, 0, 10, 14, 7, 3, 5 },
+ { 14, 0, 0, 0, -1, 0, 1, 0, 17, { {0, 80}, {0, 0}, {0, 0}, {0, 80} }, 0, 10, 14, 7, 3, 5 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 80}, {0, 0}, {0, 0}, {0, 80} }, 0, 10, 14, 7, 3, 5 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 80}, {0, 0}, {0, 0}, {0, 80} }, 0, 10, 14, 7, 3, 5 },
+ { 14, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 32}, {0, 0}, {0, 0}, {0, 32} }, 0, 10, 14, 7, 3, 5 },
+ { 14, 0, 0, 0, -1, 0, 1, 0, 17, { {0, 32}, {0, 0}, {0, 0}, {0, 32} }, 0, 10, 14, 7, 3, 5 },
+ { 15, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 14, 6, 1, 5 },
+ { 15, 0, 0, 0, -1, 0, 1, 0, 17, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 14, 6, 1, 5 },
+ { 15, 0, 0, 0, -1, 0, 4, 3, 17, { {0, 0}, {0, -80}, {0, -80}, {0, 0} }, 0, 10, 14, 6, 1, 5 },
+ { 15, 0, 0, 0, -1, 0, 1, 0, 17, { {0, 0}, {0, -80}, {0, -80}, {0, 0} }, 0, 10, 14, 6, 1, 5 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -80}, {0, -80}, {0, 0} }, 0, 10, 14, 6, 1, 5 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, -80}, {0, -80}, {0, 0} }, 0, 10, 14, 6, 1, 5 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 5 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 5 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 5 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 5 },
+ { 29, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 5 },
+ { 0, 17, 230, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 5 },
+ { 0, 17, 230, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 230, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 5 },
+ { 2, 17, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 5 },
+ { 14, 0, 0, 0, -1, 0, 6, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 5 },
+ { 15, 0, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 5 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 5 },
+ { 15, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 5 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 15}, {0, 0}, {0, 0}, {0, 15} }, 0, 10, 14, 7, 0, 5 },
+ { 15, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, -15}, {0, -15}, {0, 0} }, 0, 10, 14, 6, 1, 5 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 17, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 5 },
+ { 15, 0, 0, 0, -1, 0, 4, 3, 17, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 5 },
+ { 14, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 5 },
+ { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 5 },
+ { 14, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 5 },
+ { 15, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 5 },
+ { 14, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 5 },
+ { 15, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 5 },
+ { 14, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 5 },
+ { 15, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 5 },
+ { 14, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 5 },
+ { 15, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 5 },
+ { 14, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 5 },
+ { 15, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 5 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 48}, {0, 0}, {0, 0}, {0, 48} }, 0, 10, 14, 7, 3, 6 },
+ { 17, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 6 },
+ { 25, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 0, 1, 6 },
+ { 25, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 11, 1, 6 },
+ { 25, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 14, 14, 0, 1, 6 },
+ { 15, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 6 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, -48}, {0, -48}, {0, 0} }, 0, 10, 14, 6, 1, 6 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 467}, {1, 464}, {0, 0} }, 0, 10, 14, 6, 3, 6 },
+ { 25, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 10, 12, 1, 6 },
+ { 20, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 19, 0, 1, 6 },
+ { 29, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 6 },
+ { 27, 4, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 6 },
+ { 13, 1, 0, 0, -1, 0, 0, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 0 },
+ { 0, 17, 220, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 0, 17, 230, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 0, 17, 222, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 0, 17, 220, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 0, 17, 228, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 0, 17, 10, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 0, 17, 11, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 0, 17, 12, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 0, 17, 13, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 0, 17, 14, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 0, 17, 15, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 0, 17, 16, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 0, 17, 17, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 0, 17, 18, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 0, 17, 19, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 0, 17, 19, 5, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 0, 17, 20, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 0, 17, 21, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 0, 17, 22, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 20, 1, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 7 },
+ { 0, 17, 23, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 25, 1, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 7 },
+ { 0, 17, 24, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 0, 17, 25, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 25, 1, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 0, 1, 7 },
+ { 0, 17, 18, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 18, 1, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 9, 15, 8, 1, 7 },
+ { 18, 1, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 9, 15, 8, 1, 7 },
+ { 25, 1, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 7 },
+ { 25, 1, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 14, 14, 0, 1, 7 },
+ { 10, 5, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 16, 13, 9, 0, 8 },
+ { 10, 5, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 16, 13, 9, 0, 8 },
+ { 10, 5, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 16, 13, 9, 0, 2 },
+ { 26, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 8 },
+ { 26, 13, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 8 },
+ { 25, 4, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
+ { 27, 13, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
+ { 25, 6, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 10, 11, 1, 2 },
+ { 25, 13, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 10, 11, 1, 8 },
+ { 29, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 8 },
+ { 0, 17, 230, 5, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 0, 17, 230, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 0, 17, 30, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 0, 17, 31, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 0, 17, 32, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 25, 13, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 0, 1, 2 },
+ { 10, 13, 0, 5, -1, 0, 15, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 23, 4, 0, 8 },
+ { 25, 13, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 12, 1, 8 },
+ { 25, 13, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 12, 1, 8 },
+ { 25, 13, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 12, 1, 2 },
+ { 18, 13, 0, 2, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 3, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 2, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 3, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 2, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 2, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 17, 13, 0, 1, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 2 },
+ { 0, 17, 27, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 28, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 29, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 30, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 31, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 32, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 33, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 34, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 230, 5, -1, 0, 4, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 220, 5, -1, 0, 4, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 220, 5, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 0, 17, 230, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 0, 17, 220, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 0, 17, 220, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 3, 5, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 3, 5, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 3, 5, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 3, 5, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 3, 5, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 3, 5, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 3, 5, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 3, 5, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 3, 5, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 3, 5, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 25, 4, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
+ { 25, 5, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 25, 5, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 13, 9, 1, 8 },
+ { 25, 13, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 8 },
+ { 18, 13, 0, 2, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 0, 17, 35, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 18, 13, 0, 3, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 3, 8 },
+ { 18, 13, 0, 2, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 3, 8 },
+ { 18, 13, 0, 2, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 3, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 25, 13, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 12, 1, 8 },
+ { 0, 17, 230, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 10, 5, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 16, 13, 9, 0, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 8 },
+ { 0, 17, 220, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 17, 13, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 3, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 3, 2, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 3, 2, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 3, 2, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 3, 2, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 3, 2, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 3, 2, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 3, 2, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 3, 2, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 3, 2, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 3, 2, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 8 },
+ { 29, 13, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 8 },
+ { 18, 13, 0, 2, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 25, 13, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 12, 1, 9 },
+ { 25, 13, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 9 },
+ { 13, 13, 0, 0, -1, 0, 0, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 0 },
+ { 10, 13, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 10, 14, 4, 0, 9 },
+ { 18, 13, 0, 3, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 9 },
+ { 0, 17, 36, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 9 },
+ { 18, 13, 0, 2, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 9 },
+ { 18, 13, 0, 2, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 9 },
+ { 18, 13, 0, 3, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 9 },
+ { 0, 17, 230, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 9 },
+ { 0, 17, 220, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 9 },
+ { 18, 13, 0, 2, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 3, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 3, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 10 },
+ { 0, 17, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 10 },
+ { 18, 13, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 10 },
+ { 3, 1, 0, 0, 0, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 66 },
+ { 3, 1, 0, 0, 1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 66 },
+ { 3, 1, 0, 0, 2, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 66 },
+ { 3, 1, 0, 0, 3, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 66 },
+ { 3, 1, 0, 0, 4, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 66 },
+ { 3, 1, 0, 0, 5, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 66 },
+ { 3, 1, 0, 0, 6, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 66 },
+ { 3, 1, 0, 0, 7, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 66 },
+ { 3, 1, 0, 0, 8, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 66 },
+ { 3, 1, 0, 0, 9, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 66 },
+ { 18, 1, 0, 2, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 66 },
+ { 0, 17, 230, 5, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 66 },
+ { 0, 17, 220, 5, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 66 },
+ { 17, 1, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 66 },
+ { 29, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 66 },
+ { 25, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 66 },
+ { 25, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 10, 11, 1, 66 },
+ { 25, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 12, 1, 66 },
+ { 17, 1, 0, 1, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 66 },
+ { 0, 17, 220, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 66 },
+ { 27, 1, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 66 },
+ { 18, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 82 },
+ { 0, 17, 230, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 82 },
+ { 17, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 82 },
+ { 25, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 82 },
+ { 25, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 12, 1, 82 },
+ { 18, 1, 0, 3, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 95 },
+ { 18, 1, 0, 2, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 95 },
+ { 0, 17, 220, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 95 },
+ { 25, 1, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 95 },
+ { 18, 13, 0, 2, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 9 },
+ { 18, 13, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 9 },
+ { 18, 13, 0, 3, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 9 },
+ { 18, 13, 0, 3, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 1, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 2, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 28, 13, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 8 },
+ { 10, 5, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 16, 13, 9, 0, 8 },
+ { 0, 17, 230, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 0, 17, 220, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 18, 13, 0, 2, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 2, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 3, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 3, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 2, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 2, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 3, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 18, 13, 0, 2, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 17, 13, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 0, 17, 220, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 0, 17, 230, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 10, 5, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 16, 13, 9, 0, 2 },
+ { 0, 17, 220, 5, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 0, 17, 230, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 0, 17, 220, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 0, 17, 27, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 0, 17, 28, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 0, 17, 29, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 0, 17, 230, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 0, 17, 0, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 11 },
+ { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 11 },
+ { 1, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 11 },
+ { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 11 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 11 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 11 },
+ { 0, 17, 0, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 11 },
+ { 1, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 11 },
+ { 0, 17, 7, 5, -1, 0, 1, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 11 },
+ { 0, 17, 9, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 11 },
+ { 1, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 11 },
+ { 0, 17, 220, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 3, 11 },
+ { 25, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 2 },
+ { 3, 0, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 11 },
+ { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 11 },
+ { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 11 },
+ { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 11 },
+ { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 11 },
+ { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 11 },
+ { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 11 },
+ { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 11 },
+ { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 11 },
+ { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 11 },
+ { 25, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 11 },
+ { 17, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 11 },
+ { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 11 },
+ { 18, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 11 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 11 },
+ { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 11 },
+ { 18, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 11 },
+ { 18, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 11 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 12 },
+ { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 12 },
+ { 1, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 12 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 12 },
+ { 0, 17, 7, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 12 },
+ { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 12 },
+ { 1, 0, 0, 0, -1, 0, 1, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 12 },
+ { 1, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 12 },
+ { 0, 17, 9, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 12 },
+ { 18, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 12 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 3, 12 },
+ { 3, 0, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 12 },
+ { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 12 },
+ { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 12 },
+ { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 12 },
+ { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 12 },
+ { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 12 },
+ { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 12 },
+ { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 12 },
+ { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 12 },
+ { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 12 },
+ { 27, 4, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 12 },
+ { 5, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 12 },
{ 5, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 12 },
- { 5, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 1, 12 },
- { 29, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 12 },
- { 27, 4, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 12 },
- { 18, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 12 },
- { 25, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 12 },
- { 0, 17, 230, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 12 },
- { 0, 17, 0, 5, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 13 },
- { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 13 },
- { 1, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 13 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 13 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 3, 13 },
- { 0, 17, 7, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 13 },
- { 1, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 13 },
- { 0, 17, 9, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 13 },
- { 0, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 13 },
- { 3, 0, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 13 },
- { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 13 },
- { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 13 },
- { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 13 },
- { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 13 },
- { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 13 },
- { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 13 },
- { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 13 },
- { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 13 },
- { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 13 },
- { 25, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 13 },
- { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 14 },
- { 1, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 14 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 14 },
- { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 14 },
- { 0, 17, 7, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 14 },
- { 0, 17, 9, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 14 },
- { 0, 17, 0, 5, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 14 },
- { 3, 0, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 14 },
- { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 14 },
- { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 14 },
- { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 14 },
- { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 14 },
- { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 14 },
- { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 14 },
- { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 14 },
- { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 14 },
- { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 14 },
- { 25, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 14 },
- { 27, 4, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 14 },
- { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 14 },
- { 0, 17, 0, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 14 },
- { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 15 },
- { 1, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 15 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 15 },
- { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 15 },
- { 0, 17, 7, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 15 },
- { 1, 0, 0, 0, -1, 0, 1, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 15 },
- { 0, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 15 },
- { 1, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 15 },
- { 0, 17, 9, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 15 },
- { 0, 17, 0, 5, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 15 },
- { 0, 17, 0, 5, -1, 0, 1, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 15 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 3, 15 },
- { 3, 0, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 15 },
- { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 15 },
- { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 15 },
- { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 15 },
- { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 15 },
- { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 15 },
- { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 15 },
- { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 15 },
- { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 15 },
- { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 15 },
- { 29, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 15 },
- { 5, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 15 },
- { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 16 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 16 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 16 },
- { 18, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 16 },
- { 1, 0, 0, 0, -1, 0, 1, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 16 },
- { 1, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 16 },
- { 1, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 16 },
- { 0, 17, 9, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 16 },
- { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 16 },
- { 3, 0, 0, 0, 0, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 16 },
- { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 16 },
- { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 16 },
- { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 16 },
- { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 16 },
- { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 16 },
- { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 16 },
- { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 16 },
- { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 16 },
- { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 16 },
- { 5, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 16 },
- { 29, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 16 },
- { 27, 4, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 16 },
- { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 17 },
- { 1, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 17 },
- { 0, 17, 0, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 17 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 17 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 17 },
- { 0, 17, 7, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 17 },
- { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 17 },
- { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 17 },
- { 0, 17, 0, 5, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 17 },
- { 0, 17, 9, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 17 },
- { 0, 17, 84, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 17 },
- { 0, 17, 91, 5, -1, 0, 1, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 17 },
- { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 17 },
- { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 17 },
- { 0, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 17 },
- { 3, 0, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 17 },
- { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 17 },
- { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 17 },
- { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 17 },
- { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 17 },
- { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 17 },
- { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 17 },
- { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 17 },
- { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 17 },
- { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 17 },
- { 25, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 0, 1, 17 },
- { 5, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 17 },
- { 29, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 17 },
- { 18, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 18 },
- { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 18 },
- { 1, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 18 },
- { 25, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 0, 1, 18 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 18 },
- { 0, 17, 7, 5, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 18 },
- { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 18 },
- { 0, 0, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 18 },
- { 1, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 18 },
- { 1, 0, 0, 0, -1, 0, 1, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 18 },
- { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 18 },
- { 0, 17, 9, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 18 },
- { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 18 },
- { 0, 17, 0, 5, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 18 },
- { 3, 0, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 18 },
- { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 18 },
- { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 18 },
- { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 18 },
- { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 18 },
- { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 18 },
- { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 18 },
- { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 18 },
- { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 18 },
- { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 18 },
- { 18, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 18 },
- { 1, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 18 },
- { 0, 17, 0, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 19 },
- { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 19 },
- { 1, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 19 },
- { 18, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 19 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 19 },
- { 18, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 19 },
- { 0, 17, 9, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 19 },
- { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 19 },
- { 1, 0, 0, 0, -1, 0, 1, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 19 },
- { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 19 },
- { 0, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 19 },
- { 1, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 19 },
- { 0, 17, 9, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 19 },
- { 18, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 10, 12, 8, 1, 19 },
- { 29, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 19 },
- { 18, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 19 },
- { 5, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 19 },
- { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 19 },
- { 3, 0, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 19 },
- { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 19 },
- { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 19 },
- { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 19 },
- { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 19 },
- { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 19 },
- { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 19 },
- { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 19 },
- { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 19 },
- { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 19 },
- { 5, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 19 },
- { 29, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 1, 19 },
- { 0, 17, 0, 5, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 20 },
- { 1, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 20 },
- { 18, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 20 },
- { 0, 17, 9, 5, -1, 0, 4, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 20 },
- { 1, 0, 0, 0, -1, 0, 4, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 20 },
- { 0, 17, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 20 },
- { 1, 0, 0, 0, -1, 0, 4, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 20 },
- { 3, 0, 0, 0, 0, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 20 },
- { 3, 0, 0, 0, 1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 20 },
- { 3, 0, 0, 0, 2, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 20 },
- { 3, 0, 0, 0, 3, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 20 },
- { 3, 0, 0, 0, 4, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 20 },
- { 3, 0, 0, 0, 5, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 20 },
- { 3, 0, 0, 0, 6, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 20 },
- { 3, 0, 0, 0, 7, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 20 },
- { 3, 0, 0, 0, 8, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 20 },
- { 3, 0, 0, 0, 9, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 20 },
- { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 20 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 21 },
- { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 21 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 0, 33, 8, 3, 21 },
- { 0, 17, 103, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 21 },
- { 0, 17, 9, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 21 },
- { 27, 4, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 2 },
- { 17, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 21 },
- { 0, 17, 107, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 21 },
- { 25, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 21 },
- { 3, 0, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 21 },
- { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 21 },
- { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 21 },
- { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 21 },
- { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 21 },
- { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 21 },
- { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 21 },
- { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 21 },
- { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 21 },
- { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 21 },
- { 25, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 21 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 22 },
- { 18, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 22 },
- { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 22 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 0, 33, 8, 3, 22 },
- { 0, 17, 118, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 22 },
- { 0, 17, 9, 5, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 22 },
- { 17, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 22 },
- { 0, 17, 122, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 22 },
- { 0, 17, 0, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 22 },
- { 3, 0, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 22 },
- { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 22 },
- { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 22 },
- { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 22 },
- { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 22 },
- { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 22 },
- { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 22 },
- { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 22 },
- { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 22 },
- { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 22 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 3, 22 },
- { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 22 },
- { 18, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 23 },
- { 29, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 0, 1, 23 },
- { 25, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 0, 1, 23 },
- { 25, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 23 },
- { 25, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 4, 0, 1, 23 },
- { 25, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 23 },
- { 25, 0, 0, 0, -1, 0, 2, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 4, 0, 3, 23 },
+ { 29, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 12 },
+ { 27, 4, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 12 },
+ { 18, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 12 },
+ { 25, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 12 },
+ { 0, 17, 230, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 12 },
+ { 0, 17, 0, 5, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 13 },
+ { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 13 },
+ { 1, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 13 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 13 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 3, 13 },
+ { 0, 17, 7, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 13 },
+ { 1, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 13 },
+ { 0, 17, 9, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 13 },
+ { 0, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 13 },
+ { 3, 0, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 13 },
+ { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 13 },
+ { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 13 },
+ { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 13 },
+ { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 13 },
+ { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 13 },
+ { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 13 },
+ { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 13 },
+ { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 13 },
+ { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 13 },
+ { 25, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 13 },
+ { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 14 },
+ { 1, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 14 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 14 },
+ { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 14 },
+ { 0, 17, 7, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 14 },
+ { 0, 17, 9, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 14 },
+ { 0, 17, 0, 5, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 14 },
+ { 3, 0, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 14 },
+ { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 14 },
+ { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 14 },
+ { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 14 },
+ { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 14 },
+ { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 14 },
+ { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 14 },
+ { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 14 },
+ { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 14 },
+ { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 14 },
+ { 25, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 14 },
+ { 27, 4, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 14 },
+ { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 14 },
+ { 0, 17, 0, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 14 },
+ { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 15 },
+ { 1, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 15 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 15 },
+ { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 15 },
+ { 0, 17, 7, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 15 },
+ { 1, 0, 0, 0, -1, 0, 1, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 15 },
+ { 0, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 15 },
+ { 1, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 15 },
+ { 0, 17, 9, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 15 },
+ { 0, 17, 0, 5, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 15 },
+ { 0, 17, 0, 5, -1, 0, 1, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 15 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 3, 15 },
+ { 3, 0, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 15 },
+ { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 15 },
+ { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 15 },
+ { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 15 },
+ { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 15 },
+ { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 15 },
+ { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 15 },
+ { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 15 },
+ { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 15 },
+ { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 15 },
+ { 29, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 15 },
+ { 5, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 15 },
+ { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 16 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 16 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 16 },
+ { 18, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 16 },
+ { 1, 0, 0, 0, -1, 0, 1, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 16 },
+ { 1, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 16 },
+ { 1, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 16 },
+ { 0, 17, 9, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 16 },
+ { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 16 },
+ { 3, 0, 0, 0, 0, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 16 },
+ { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 16 },
+ { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 16 },
+ { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 16 },
+ { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 16 },
+ { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 16 },
+ { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 16 },
+ { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 16 },
+ { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 16 },
+ { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 16 },
+ { 5, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 16 },
+ { 29, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 16 },
+ { 27, 4, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 16 },
+ { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 17 },
+ { 1, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 17 },
+ { 0, 17, 0, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 17 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 17 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 17 },
+ { 0, 17, 7, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 17 },
+ { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 17 },
+ { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 17 },
+ { 0, 17, 0, 5, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 17 },
+ { 0, 17, 9, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 17 },
+ { 0, 17, 84, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 17 },
+ { 0, 17, 91, 5, -1, 0, 1, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 17 },
+ { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 17 },
+ { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 17 },
+ { 0, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 17 },
+ { 3, 0, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 17 },
+ { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 17 },
+ { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 17 },
+ { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 17 },
+ { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 17 },
+ { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 17 },
+ { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 17 },
+ { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 17 },
+ { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 17 },
+ { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 17 },
+ { 25, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 20, 0, 1, 17 },
+ { 5, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 17 },
+ { 29, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 17 },
+ { 18, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 18 },
+ { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 18 },
+ { 1, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 18 },
+ { 25, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 20, 0, 1, 18 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 18 },
+ { 0, 17, 7, 5, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 18 },
+ { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 18 },
+ { 0, 0, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 18 },
+ { 1, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 18 },
+ { 1, 0, 0, 0, -1, 0, 1, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 18 },
+ { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 18 },
+ { 0, 17, 9, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 18 },
+ { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 18 },
+ { 0, 17, 0, 5, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 18 },
+ { 3, 0, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 18 },
+ { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 18 },
+ { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 18 },
+ { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 18 },
+ { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 18 },
+ { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 18 },
+ { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 18 },
+ { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 18 },
+ { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 18 },
+ { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 18 },
+ { 18, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 18 },
+ { 1, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 18 },
+ { 0, 17, 0, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 19 },
+ { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 19 },
+ { 1, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 19 },
+ { 18, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 19 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 19 },
+ { 18, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 19 },
+ { 0, 17, 9, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 19 },
+ { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 19 },
+ { 1, 0, 0, 0, -1, 0, 1, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 19 },
+ { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 19 },
+ { 0, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 19 },
+ { 1, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 19 },
+ { 0, 17, 9, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 19 },
+ { 18, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 10, 14, 8, 1, 19 },
+ { 29, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 19 },
+ { 18, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 19 },
+ { 5, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 19 },
+ { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 19 },
+ { 3, 0, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 19 },
+ { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 19 },
+ { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 19 },
+ { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 19 },
+ { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 19 },
+ { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 19 },
+ { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 19 },
+ { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 19 },
+ { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 19 },
+ { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 19 },
+ { 5, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 19 },
+ { 29, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 19 },
+ { 0, 17, 0, 5, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 20 },
+ { 1, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 20 },
+ { 18, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 20 },
+ { 0, 17, 9, 5, -1, 0, 4, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 20 },
+ { 1, 0, 0, 0, -1, 0, 4, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 20 },
+ { 0, 17, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 20 },
+ { 1, 0, 0, 0, -1, 0, 4, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 20 },
+ { 3, 0, 0, 0, 0, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 20 },
+ { 3, 0, 0, 0, 1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 20 },
+ { 3, 0, 0, 0, 2, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 20 },
+ { 3, 0, 0, 0, 3, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 20 },
+ { 3, 0, 0, 0, 4, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 20 },
+ { 3, 0, 0, 0, 5, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 20 },
+ { 3, 0, 0, 0, 6, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 20 },
+ { 3, 0, 0, 0, 7, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 20 },
+ { 3, 0, 0, 0, 8, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 20 },
+ { 3, 0, 0, 0, 9, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 20 },
+ { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 20 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 21 },
+ { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 21 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 0, 35, 8, 3, 21 },
+ { 0, 17, 103, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 21 },
+ { 0, 17, 9, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 21 },
+ { 27, 4, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 2 },
+ { 17, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 21 },
+ { 0, 17, 107, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 21 },
+ { 25, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 21 },
+ { 3, 0, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 21 },
+ { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 21 },
+ { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 21 },
+ { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 21 },
+ { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 21 },
+ { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 21 },
+ { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 21 },
+ { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 21 },
+ { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 21 },
+ { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 21 },
+ { 25, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 21 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 22 },
+ { 18, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 22 },
+ { 0, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 22 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 0, 35, 8, 3, 22 },
+ { 0, 17, 118, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 22 },
+ { 0, 17, 9, 5, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 22 },
+ { 17, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 22 },
+ { 0, 17, 122, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 22 },
+ { 0, 17, 0, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 22 },
+ { 3, 0, 0, 0, 0, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 22 },
+ { 3, 0, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 22 },
+ { 3, 0, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 22 },
+ { 3, 0, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 22 },
+ { 3, 0, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 22 },
+ { 3, 0, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 22 },
+ { 3, 0, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 22 },
+ { 3, 0, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 22 },
+ { 3, 0, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 22 },
+ { 3, 0, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 22 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 3, 22 },
+ { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 22 },
+ { 18, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 23 },
+ { 29, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 20, 0, 1, 23 },
+ { 25, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 20, 0, 1, 23 },
+ { 25, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 23 },
{ 25, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 0, 1, 23 },
- { 29, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 23 },
- { 0, 17, 220, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 23 },
- { 3, 0, 0, 0, 0, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 23 },
- { 3, 0, 0, 0, 1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 23 },
- { 3, 0, 0, 0, 2, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 23 },
- { 3, 0, 0, 0, 3, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 23 },
- { 3, 0, 0, 0, 4, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 23 },
- { 3, 0, 0, 0, 5, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 23 },
- { 3, 0, 0, 0, 6, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 23 },
- { 3, 0, 0, 0, 7, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 23 },
- { 3, 0, 0, 0, 8, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 23 },
- { 3, 0, 0, 0, 9, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 23 },
- { 5, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 23 },
- { 29, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 23 },
- { 0, 17, 216, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 23 },
+ { 25, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 23 },
+ { 25, 0, 0, 0, -1, 0, 2, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 0, 3, 23 },
+ { 25, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 0, 1, 23 },
+ { 29, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 23 },
+ { 0, 17, 220, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 23 },
+ { 3, 0, 0, 0, 0, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 23 },
+ { 3, 0, 0, 0, 1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 23 },
+ { 3, 0, 0, 0, 2, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 23 },
+ { 3, 0, 0, 0, 3, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 23 },
+ { 3, 0, 0, 0, 4, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 23 },
+ { 3, 0, 0, 0, 5, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 23 },
+ { 3, 0, 0, 0, 6, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 23 },
+ { 3, 0, 0, 0, 7, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 23 },
+ { 3, 0, 0, 0, 8, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 23 },
+ { 3, 0, 0, 0, 9, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 23 },
+ { 5, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 23 },
+ { 29, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 23 },
+ { 0, 17, 216, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 23 },
{ 21, 10, 0, 0, -1, 1, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 1, 23 },
{ 22, 10, 0, 0, -1, -1, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 1, 23 },
- { 1, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 23 },
- { 18, 0, 0, 0, -1, 0, 2, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 3, 23 },
- { 18, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 23 },
- { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 23 },
- { 0, 17, 129, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 23 },
- { 0, 17, 130, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 23 },
- { 0, 17, 0, 5, -1, 0, 2, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 3, 23 },
- { 0, 17, 132, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 23 },
- { 0, 17, 0, 5, -1, 0, 2, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 3, 23 },
- { 0, 17, 0, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 23 },
- { 1, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 17, 4, 1, 23 },
- { 0, 17, 230, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 23 },
- { 0, 17, 9, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 23 },
- { 18, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 23 },
- { 0, 17, 0, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 23 },
- { 0, 17, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 23 },
- { 29, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 23 },
- { 29, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 23 },
- { 0, 17, 220, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 23 },
- { 29, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 23 },
- { 25, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 0, 1, 23 },
- { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 23 },
- { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 0, 1, 23 },
- { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 23 },
- { 29, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 25, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 4, 0, 1, 23 },
- { 18, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 24 },
- { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 24 },
- { 18, 0, 0, 0, -1, 0, 4, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 24 },
- { 1, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 4, 33, 4, 1, 24 },
- { 1, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 4, 33, 4, 1, 24 },
- { 0, 17, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 24 },
- { 0, 17, 0, 5, -1, 0, 4, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 24 },
- { 1, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 33, 4, 1, 24 },
- { 0, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 24 },
- { 0, 17, 7, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 24 },
- { 0, 17, 9, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 24 },
- { 0, 17, 9, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 24 },
- { 1, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 33, 4, 1, 24 },
- { 3, 0, 0, 0, 0, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 2, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 3, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 4, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 5, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 6, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 7, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 8, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 9, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 24 },
- { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 24 },
- { 0, 17, 220, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 24 },
- { 3, 0, 0, 0, 0, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 2, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 3, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 4, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 5, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 6, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 7, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 8, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 9, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 1, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 4, 33, 4, 1, 24 },
- { 0, 17, 0, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 24 },
- { 29, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 0, 1, 24 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 7264}, {0, 0}, {0, 0}, {0, 7264} }, 0, 10, 12, 7, 0, 25 },
- { 14, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 7264}, {0, 0}, {0, 0}, {0, 7264} }, 0, 10, 12, 7, 3, 25 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 3008}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 25 },
- { 15, 0, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 3008}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 25 },
- { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 3008}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 25 },
- { 25, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 17, 0, 0, 0, -1, 0, 8, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 25 },
- { 15, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 3008}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 25 },
- { 18, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 9, 10, 25, 8, 1, 26 },
- { 18, 0, 0, 0, -1, 0, 11, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 9, 10, 25, 8, 1, 26 },
- { 18, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 9, 10, 25, 8, 0, 26 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 10, 10, 26, 8, 0, 26 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 10, 10, 26, 8, 1, 26 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 10, 10, 26, 8, 1, 26 },
- { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 10, 10, 26, 8, 1, 26 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 11, 10, 27, 8, 1, 26 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 11, 10, 27, 8, 1, 26 },
- { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 11, 10, 27, 8, 1, 26 },
- { 18, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 27 },
- { 18, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 27 },
- { 0, 17, 230, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 27 },
- { 0, 17, 230, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 27 },
- { 25, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 27 },
- { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 27 },
- { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 12, 1, 27 },
- { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 27 },
- { 5, 0, 0, 0, 1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 27 },
- { 5, 0, 0, 0, 2, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 27 },
- { 5, 0, 0, 0, 3, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 27 },
- { 5, 0, 0, 0, 4, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 27 },
- { 5, 0, 0, 0, 5, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 27 },
- { 5, 0, 0, 0, 6, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 27 },
- { 5, 0, 0, 0, 7, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 27 },
- { 5, 0, 0, 0, 8, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 27 },
- { 5, 0, 0, 0, 9, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 27 },
- { 5, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 27 },
- { 29, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 27 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 41}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 43}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 45}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 47}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 49}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 51}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 53}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 55}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 57}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 59}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 61}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 63}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 65}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 67}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 69}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 71}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 73}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 75}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 77}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 79}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 81}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 83}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 85}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 87}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 89}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 91}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 93}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 95}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 97}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 99}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 101}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 103}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 105}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 107}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 109}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 111}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 113}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 115}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 117}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 119}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 121}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 123}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 125}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 127}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 129}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 131}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 133}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 135}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 137}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 139}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 141}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 143}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 145}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 147}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 149}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 151}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 153}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 155}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 157}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 159}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 161}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 163}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 165}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 167}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 169}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 171}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 173}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 175}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 177}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 179}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 181}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 183}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 185}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 187}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 189}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 191}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 193}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 195}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 197}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 199}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 8}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 14, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 8}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, -8}, {0, -8}, {0, -8} }, 0, 10, 12, 6, 3, 28 },
- { 20, 10, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 29 },
- { 18, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 29 },
- { 29, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 29 },
- { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 12, 1, 29 },
- { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 29 },
- { 6, 9, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 18, 17, 5, 0, 30 },
- { 18, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 30 },
+ { 1, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 23 },
+ { 18, 0, 0, 0, -1, 0, 2, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 3, 23 },
+ { 18, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 23 },
+ { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 23 },
+ { 0, 17, 129, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 23 },
+ { 0, 17, 130, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 23 },
+ { 0, 17, 0, 5, -1, 0, 2, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 3, 23 },
+ { 0, 17, 132, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 23 },
+ { 0, 17, 0, 5, -1, 0, 2, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 3, 23 },
+ { 0, 17, 0, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 23 },
+ { 1, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 19, 4, 1, 23 },
+ { 0, 17, 230, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 23 },
+ { 0, 17, 9, 5, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 23 },
+ { 18, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 23 },
+ { 0, 17, 0, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 23 },
+ { 0, 17, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 23 },
+ { 29, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 23 },
+ { 29, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 23 },
+ { 0, 17, 220, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 23 },
+ { 29, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 23 },
+ { 25, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 20, 0, 1, 23 },
+ { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 23 },
+ { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 20, 0, 1, 23 },
+ { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 23 },
+ { 29, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 25, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 0, 1, 23 },
+ { 18, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 24 },
+ { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 24 },
+ { 18, 0, 0, 0, -1, 0, 4, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 24 },
+ { 1, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 4, 35, 4, 1, 24 },
+ { 1, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 4, 35, 4, 1, 24 },
+ { 0, 17, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 24 },
+ { 0, 17, 0, 5, -1, 0, 4, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 24 },
+ { 1, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 35, 4, 1, 24 },
+ { 0, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 24 },
+ { 0, 17, 7, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 24 },
+ { 0, 17, 9, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 24 },
+ { 0, 17, 9, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 24 },
+ { 1, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 35, 4, 1, 24 },
+ { 3, 0, 0, 0, 0, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 2, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 3, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 4, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 5, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 6, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 7, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 8, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 9, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 24 },
+ { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 24 },
+ { 0, 17, 220, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 24 },
+ { 3, 0, 0, 0, 0, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 2, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 3, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 4, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 5, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 6, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 7, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 8, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 9, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 1, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 4, 35, 4, 1, 24 },
+ { 0, 17, 0, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 24 },
+ { 29, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 0, 1, 24 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 7264}, {0, 0}, {0, 0}, {0, 7264} }, 0, 10, 14, 7, 0, 25 },
+ { 14, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 7264}, {0, 0}, {0, 0}, {0, 7264} }, 0, 10, 14, 7, 3, 25 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 3008}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 25 },
+ { 15, 0, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 3008}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 25 },
+ { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 3008}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 25 },
+ { 25, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 17, 0, 0, 0, -1, 0, 8, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 25 },
+ { 15, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 3008}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 25 },
+ { 18, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 9, 10, 27, 8, 1, 26 },
+ { 18, 0, 0, 0, -1, 0, 11, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 9, 10, 27, 8, 1, 26 },
+ { 18, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 9, 10, 27, 8, 0, 26 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 10, 10, 28, 8, 0, 26 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 10, 10, 28, 8, 1, 26 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 10, 10, 28, 8, 1, 26 },
+ { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 10, 10, 28, 8, 1, 26 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 11, 10, 29, 8, 1, 26 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 11, 10, 29, 8, 1, 26 },
+ { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 11, 10, 29, 8, 1, 26 },
+ { 18, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 27 },
+ { 18, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 27 },
+ { 0, 17, 230, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 27 },
+ { 0, 17, 230, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 27 },
+ { 25, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 27 },
+ { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 27 },
+ { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 12, 1, 27 },
+ { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 27 },
+ { 5, 0, 0, 0, 1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 27 },
+ { 5, 0, 0, 0, 2, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 27 },
+ { 5, 0, 0, 0, 3, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 27 },
+ { 5, 0, 0, 0, 4, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 27 },
+ { 5, 0, 0, 0, 5, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 27 },
+ { 5, 0, 0, 0, 6, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 27 },
+ { 5, 0, 0, 0, 7, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 27 },
+ { 5, 0, 0, 0, 8, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 27 },
+ { 5, 0, 0, 0, 9, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 27 },
+ { 5, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 27 },
+ { 29, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 27 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 41}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 43}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 45}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 47}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 49}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 51}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 53}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 55}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 57}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 59}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 61}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 63}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 65}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 67}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 69}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 71}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 73}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 75}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 77}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 79}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 81}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 83}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 85}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 87}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 89}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 91}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 93}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 95}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 97}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 99}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 101}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 103}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 105}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 107}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 109}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 111}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 113}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 115}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 117}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 119}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 121}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 123}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 125}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 127}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 129}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 131}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 133}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 135}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 137}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 139}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 141}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 143}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 145}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 147}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 149}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 151}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 153}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 155}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 157}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 159}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 161}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 163}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 165}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 167}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 169}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 171}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 173}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 175}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 177}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 179}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 181}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 183}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 185}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 187}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 189}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 191}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 193}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 195}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 197}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {1, 199}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 8}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 14, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 8}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, -8}, {0, -8}, {0, -8} }, 0, 10, 14, 6, 3, 28 },
+ { 20, 10, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 29 },
+ { 18, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 29 },
+ { 29, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 29 },
+ { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 12, 1, 29 },
+ { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 29 },
+ { 6, 9, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 18, 19, 5, 0, 30 },
+ { 18, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 30 },
{ 21, 10, 0, 0, -1, 1, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 1, 30 },
{ 22, 10, 0, 0, -1, -1, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 1, 30 },
- { 18, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 31 },
- { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 2 },
- { 4, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 31 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 31 },
- { 18, 0, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 42 },
- { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 42 },
- { 0, 17, 0, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 42 },
- { 0, 17, 9, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 42 },
- { 1, 0, 9, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 42 },
- { 18, 0, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 43 },
- { 0, 17, 0, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 43 },
- { 1, 0, 9, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 43 },
- { 25, 0, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 2 },
- { 18, 0, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 44 },
- { 0, 17, 0, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 44 },
- { 18, 0, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 45 },
- { 0, 17, 0, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 45 },
- { 18, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 32 },
- { 0, 17, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 0, 32 },
- { 1, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 33, 4, 1, 32 },
- { 0, 17, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 32 },
- { 0, 17, 9, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 32 },
- { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 32 },
- { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 5, 0, 1, 32 },
- { 17, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 32 },
- { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 32 },
- { 27, 4, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 32 },
- { 0, 17, 230, 5, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 32 },
- { 3, 0, 0, 0, 0, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 32 },
- { 3, 0, 0, 0, 1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 32 },
- { 3, 0, 0, 0, 2, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 32 },
- { 3, 0, 0, 0, 3, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 32 },
- { 3, 0, 0, 0, 4, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 32 },
- { 3, 0, 0, 0, 5, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 32 },
- { 3, 0, 0, 0, 6, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 32 },
- { 3, 0, 0, 0, 7, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 32 },
- { 3, 0, 0, 0, 8, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 32 },
- { 3, 0, 0, 0, 9, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 32 },
- { 5, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 32 },
- { 25, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 33 },
- { 25, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 11, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 12, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 33 },
- { 25, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 2 },
- { 20, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 0, 0, 33 },
- { 25, 10, 0, 2, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 33 },
- { 25, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 11, 1, 33 },
- { 25, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 12, 1, 33 },
- { 25, 10, 0, 1, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 33 },
- { 0, 17, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 2, 33 },
- { 10, 18, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 4, 4, 0, 33 },
- { 0, 17, 0, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 2, 33 },
- { 3, 0, 0, 0, 0, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 33 },
- { 3, 0, 0, 0, 1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 33 },
- { 3, 0, 0, 0, 2, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 33 },
- { 3, 0, 0, 0, 3, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 33 },
- { 3, 0, 0, 0, 4, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 33 },
- { 3, 0, 0, 0, 5, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 33 },
- { 3, 0, 0, 0, 6, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 33 },
- { 3, 0, 0, 0, 7, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 33 },
- { 3, 0, 0, 0, 8, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 33 },
- { 3, 0, 0, 0, 9, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 33 },
- { 18, 0, 0, 2, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 33 },
- { 17, 0, 0, 2, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 33 },
- { 18, 0, 0, 2, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 33 },
- { 18, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 33 },
- { 0, 17, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 33 },
- { 0, 17, 228, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 33 },
- { 18, 0, 0, 2, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 33 },
- { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 47 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 47 },
- { 0, 17, 0, 5, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 47 },
- { 1, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 47 },
- { 0, 17, 222, 5, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 47 },
- { 0, 17, 230, 5, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 47 },
- { 0, 17, 220, 5, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 47 },
- { 29, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 47 },
- { 25, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 12, 1, 47 },
- { 3, 0, 0, 0, 0, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 47 },
- { 3, 0, 0, 0, 1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 47 },
- { 3, 0, 0, 0, 2, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 47 },
- { 3, 0, 0, 0, 3, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 47 },
- { 3, 0, 0, 0, 4, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 47 },
- { 3, 0, 0, 0, 5, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 47 },
- { 3, 0, 0, 0, 6, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 47 },
- { 3, 0, 0, 0, 7, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 47 },
- { 3, 0, 0, 0, 8, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 47 },
- { 3, 0, 0, 0, 9, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 47 },
- { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 48 },
- { 18, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 56 },
- { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 56 },
- { 3, 0, 0, 0, 0, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 56 },
- { 3, 0, 0, 0, 1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 56 },
- { 3, 0, 0, 0, 2, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 56 },
- { 3, 0, 0, 0, 3, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 56 },
- { 3, 0, 0, 0, 4, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 56 },
- { 3, 0, 0, 0, 5, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 56 },
- { 3, 0, 0, 0, 6, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 56 },
- { 3, 0, 0, 0, 7, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 56 },
- { 3, 0, 0, 0, 8, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 56 },
- { 3, 0, 0, 0, 9, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 56 },
- { 5, 0, 0, 0, 1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 0, 1, 56 },
- { 29, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 0, 1, 56 },
- { 29, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 32 },
- { 18, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 55 },
- { 0, 17, 230, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 55 },
- { 0, 17, 220, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 55 },
- { 1, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 55 },
- { 0, 17, 0, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 55 },
- { 25, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 55 },
- { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 78 },
- { 1, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 33, 4, 1, 78 },
- { 0, 17, 0, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 78 },
- { 0, 17, 9, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 78 },
- { 1, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 4, 33, 4, 1, 78 },
- { 0, 17, 230, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 78 },
- { 0, 17, 220, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 78 },
- { 3, 0, 0, 0, 0, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 78 },
- { 3, 0, 0, 0, 1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 78 },
- { 3, 0, 0, 0, 2, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 78 },
- { 3, 0, 0, 0, 3, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 78 },
- { 3, 0, 0, 0, 4, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 78 },
- { 3, 0, 0, 0, 5, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 78 },
- { 3, 0, 0, 0, 6, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 78 },
- { 3, 0, 0, 0, 7, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 78 },
- { 3, 0, 0, 0, 8, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 78 },
- { 3, 0, 0, 0, 9, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 78 },
- { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 0, 1, 78 },
- { 17, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 78 },
- { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 12, 1, 78 },
- { 0, 17, 230, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 220, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 2, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 220, 5, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 230, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 220, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 0, 5, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 62 },
- { 1, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 62 },
- { 18, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 62 },
- { 18, 0, 0, 0, -1, 0, 9, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 62 },
- { 0, 17, 7, 5, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 62 },
- { 1, 0, 0, 0, -1, 0, 9, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 62 },
- { 1, 0, 0, 0, -1, 0, 9, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 62 },
- { 1, 0, 9, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 62 },
- { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 62 },
- { 3, 0, 0, 0, 0, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 62 },
- { 3, 0, 0, 0, 1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 62 },
- { 3, 0, 0, 0, 2, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 62 },
- { 3, 0, 0, 0, 3, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 62 },
- { 3, 0, 0, 0, 4, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 62 },
- { 3, 0, 0, 0, 5, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 62 },
- { 3, 0, 0, 0, 6, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 62 },
- { 3, 0, 0, 0, 7, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 62 },
- { 3, 0, 0, 0, 8, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 62 },
- { 3, 0, 0, 0, 9, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 62 },
- { 25, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 62 },
- { 25, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 62 },
- { 25, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 62 },
- { 29, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 62 },
- { 0, 17, 230, 5, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 62 },
- { 0, 17, 220, 5, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 62 },
- { 25, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 62 },
- { 0, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 67 },
- { 1, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 67 },
- { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 67 },
- { 1, 0, 9, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 67 },
- { 0, 17, 9, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 67 },
- { 0, 17, 0, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 67 },
- { 3, 0, 0, 0, 0, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 67 },
- { 3, 0, 0, 0, 1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 67 },
- { 3, 0, 0, 0, 2, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 67 },
- { 3, 0, 0, 0, 3, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 67 },
- { 3, 0, 0, 0, 4, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 67 },
- { 3, 0, 0, 0, 5, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 67 },
- { 3, 0, 0, 0, 6, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 67 },
- { 3, 0, 0, 0, 7, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 67 },
- { 3, 0, 0, 0, 8, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 67 },
- { 3, 0, 0, 0, 9, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 67 },
- { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 67 },
- { 18, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 93 },
- { 0, 17, 7, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 93 },
- { 1, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 93 },
- { 0, 17, 0, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 93 },
- { 1, 0, 9, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 93 },
- { 25, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 93 },
- { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 68 },
- { 1, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 68 },
- { 0, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 68 },
- { 0, 17, 7, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 68 },
- { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 68 },
- { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 68 },
- { 3, 0, 0, 0, 0, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 68 },
- { 3, 0, 0, 0, 1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 68 },
- { 3, 0, 0, 0, 2, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 68 },
- { 3, 0, 0, 0, 3, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 68 },
- { 3, 0, 0, 0, 4, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 68 },
- { 3, 0, 0, 0, 5, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 68 },
- { 3, 0, 0, 0, 6, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 68 },
- { 3, 0, 0, 0, 7, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 68 },
- { 3, 0, 0, 0, 8, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 68 },
- { 3, 0, 0, 0, 9, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 68 },
- { 3, 0, 0, 0, 0, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 69 },
- { 3, 0, 0, 0, 1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 69 },
- { 3, 0, 0, 0, 2, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 69 },
- { 3, 0, 0, 0, 3, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 69 },
- { 3, 0, 0, 0, 4, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 69 },
- { 3, 0, 0, 0, 5, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 69 },
- { 3, 0, 0, 0, 6, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 69 },
- { 3, 0, 0, 0, 7, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 69 },
- { 3, 0, 0, 0, 8, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 69 },
- { 3, 0, 0, 0, 9, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 69 },
- { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 69 },
- { 17, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 69 },
- { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 69 },
- { 15, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, -6254}, {0, -6254}, {0, -6222} }, 0, 10, 12, 6, 3, 5 },
- { 15, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, -6253}, {0, -6253}, {0, -6221} }, 0, 10, 12, 6, 3, 5 },
- { 15, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, -6244}, {0, -6244}, {0, -6212} }, 0, 10, 12, 6, 3, 5 },
- { 15, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, -6242}, {0, -6242}, {0, -6210} }, 0, 10, 12, 6, 3, 5 },
- { 15, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, -6243}, {0, -6243}, {0, -6211} }, 0, 10, 12, 6, 3, 5 },
- { 15, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, -6236}, {0, -6236}, {0, -6204} }, 0, 10, 12, 6, 3, 5 },
- { 15, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, -6181}, {0, -6181}, {0, -6180} }, 0, 10, 12, 6, 3, 5 },
- { 15, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {1, 201}, {1, 201}, {1, 719} }, 0, 10, 12, 6, 3, 5 },
- { 14, 0, 0, 0, -1, 0, 20, 3, 0, { {0, -3008}, {0, 0}, {0, 0}, {0, -3008} }, 0, 10, 12, 8, 3, 25 },
- { 25, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 67 },
- { 0, 17, 230, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 0, 17, 1, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 220, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 1, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 2 },
- { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 2 },
- { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 2 },
- { 0, 17, 230, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 1, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 2 },
- { 18, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 2 },
- { 15, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 5 },
- { 17, 0, 0, 0, -1, 0, 7, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 17, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 17, 0, 0, 0, -1, 0, 7, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 17, 0, 0, 0, -1, 0, 8, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 5 },
- { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {1, 203}, {1, 203}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 3814}, {0, 3814}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {1, 205}, {1, 205}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 17, 0, 0, 0, -1, 0, 8, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 17, 0, 0, 0, -1, 0, 8, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 0, 17, 230, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 220, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 230, 5, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 220, 5, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 230, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 234, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 4, 4, 1, 1 },
- { 0, 17, 214, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 220, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 202, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 232, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 228, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 220, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 218, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 230, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 233, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 4, 4, 1, 1 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 514}, {1, 514}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 517}, {1, 517}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 520}, {1, 520}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 523}, {1, 523}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 526}, {1, 526}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 2, 3, 81, { {0, 0}, {0, -59}, {0, -59}, {0, -58} }, 0, 10, 12, 6, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 10, 3, 0, { {0, -7615}, {0, 0}, {0, 0}, {0, -7615} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 8}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {0, 0}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 529}, {1, 529}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 532}, {1, 532}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 536}, {1, 536}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 540}, {1, 540}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 74}, {0, 74}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 74}, {0, 74}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 86}, {0, 86}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 86}, {0, 86}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 100}, {0, 100}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 100}, {0, 100}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 128}, {0, 128}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 128}, {0, 128}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 112}, {0, 112}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 112}, {0, 112}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 126}, {0, 126}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 126}, {0, 126}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 578}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 581}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 584}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 587}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 590}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 593}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 596}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 599}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 578}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 581}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 584}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 587}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 590}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 593}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 596}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 599}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 602}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 605}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 608}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 611}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 614}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 617}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 620}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 623}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 602}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 605}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 608}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 611}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 614}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 617}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 620}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 623}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 626}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 629}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 632}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 635}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 638}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 641}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 644}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 647}, {0, 8}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 626}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 629}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 632}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 635}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 638}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 641}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 644}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 647}, {0, 0}, {0, -8} }, 0, 10, 12, 7, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 662}, {1, 659}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 650}, {0, 9}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 668}, {1, 665}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 544}, {1, 544}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 699}, {1, 695}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -74}, {0, 0}, {0, 0}, {0, -74} }, 0, 10, 12, 7, 3, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 85, { {0, -74}, {0, 0}, {0, 0}, {0, -74} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -9}, {1, 650}, {0, 0}, {0, -9} }, 0, 10, 12, 7, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, -7205}, {0, -7205}, {0, -7173} }, 0, 10, 12, 6, 3, 4 },
- { 28, 10, 0, 0, -1, 0, 1, 3, 81, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 674}, {1, 671}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 653}, {0, 9}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 680}, {1, 677}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 547}, {1, 547}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 707}, {1, 703}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -86}, {0, 0}, {0, 0}, {0, -86} }, 0, 10, 12, 7, 3, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 85, { {0, -86}, {0, 0}, {0, 0}, {0, -86} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -9}, {1, 653}, {0, 0}, {0, -9} }, 0, 10, 12, 7, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 550}, {1, 550}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {1, 503}, {1, 503}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 554}, {1, 554}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 557}, {1, 557}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -100}, {0, 0}, {0, 0}, {0, -100} }, 0, 10, 12, 7, 3, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 85, { {0, -100}, {0, 0}, {0, 0}, {0, -100} }, 0, 10, 12, 7, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 561}, {1, 561}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {1, 507}, {1, 507}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 565}, {1, 565}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 7}, {0, 7}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 568}, {1, 568}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 571}, {1, 571}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -112}, {0, 0}, {0, 0}, {0, -112} }, 0, 10, 12, 7, 3, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 85, { {0, -112}, {0, 0}, {0, 0}, {0, -112} }, 0, 10, 12, 7, 3, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -7}, {0, 0}, {0, 0}, {0, -7} }, 0, 10, 12, 7, 3, 4 },
- { 28, 10, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 686}, {1, 683}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 656}, {0, 9}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 692}, {1, 689}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 575}, {1, 575}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 715}, {1, 711}, {0, 0} }, 0, 10, 12, 6, 3, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -128}, {0, 0}, {0, 0}, {0, -128} }, 0, 10, 12, 7, 3, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 85, { {0, -128}, {0, 0}, {0, 0}, {0, -128} }, 0, 10, 12, 7, 3, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -126}, {0, 0}, {0, 0}, {0, -126} }, 0, 10, 12, 7, 3, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 85, { {0, -126}, {0, 0}, {0, 0}, {0, -126} }, 0, 10, 12, 7, 3, 4 },
- { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -9}, {1, 656}, {0, 0}, {0, -9} }, 0, 10, 12, 7, 3, 4 },
- { 28, 10, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 0, 0, 4 },
- { 6, 9, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 18, 17, 5, 0, 2 },
- { 6, 9, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 18, 17, 5, 0, 2 },
- { 6, 9, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 4, 5, 0, 2 },
- { 10, 18, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 0, 20, 4, 2, 2 },
- { 10, 18, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 4, 1 },
- { 10, 18, 0, 1, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 5, 5, 32, 4, 4, 1 },
- { 10, 0, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 21, 4, 0, 2 },
- { 10, 1, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 21, 4, 0, 2 },
- { 20, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 2 },
- { 20, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 4, 0, 3, 2 },
- { 20, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 2 },
- { 20, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 11, 1, 2 },
+ { 18, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 31 },
+ { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 2 },
+ { 4, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 31 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 31 },
+ { 18, 0, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 42 },
+ { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 42 },
+ { 0, 17, 0, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 42 },
+ { 0, 17, 9, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 42 },
+ { 1, 0, 9, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 42 },
+ { 18, 0, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 43 },
+ { 0, 17, 0, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 43 },
+ { 1, 0, 9, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 43 },
+ { 25, 0, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 2 },
+ { 18, 0, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 44 },
+ { 0, 17, 0, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 44 },
+ { 18, 0, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 45 },
+ { 0, 17, 0, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 45 },
+ { 18, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 32 },
+ { 0, 17, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 0, 32 },
+ { 1, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 35, 4, 1, 32 },
+ { 0, 17, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 32 },
+ { 0, 17, 9, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 32 },
+ { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 32 },
+ { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 7, 0, 1, 32 },
+ { 17, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 32 },
+ { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 32 },
+ { 25, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 32 },
+ { 27, 4, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 32 },
+ { 0, 17, 230, 5, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 32 },
+ { 3, 0, 0, 0, 0, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 32 },
+ { 3, 0, 0, 0, 1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 32 },
+ { 3, 0, 0, 0, 2, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 32 },
+ { 3, 0, 0, 0, 3, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 32 },
+ { 3, 0, 0, 0, 4, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 32 },
+ { 3, 0, 0, 0, 5, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 32 },
+ { 3, 0, 0, 0, 6, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 32 },
+ { 3, 0, 0, 0, 7, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 32 },
+ { 3, 0, 0, 0, 8, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 32 },
+ { 3, 0, 0, 0, 9, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 32 },
+ { 5, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 32 },
+ { 25, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 33 },
+ { 25, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 11, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 12, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 33 },
+ { 25, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 2 },
+ { 20, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 20, 0, 0, 33 },
+ { 25, 10, 0, 2, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 33 },
+ { 25, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 11, 1, 33 },
+ { 25, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 12, 1, 33 },
+ { 25, 10, 0, 1, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 33 },
+ { 0, 17, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 2, 33 },
+ { 10, 18, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 6, 4, 0, 33 },
+ { 0, 17, 0, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 2, 33 },
+ { 3, 0, 0, 0, 0, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 33 },
+ { 3, 0, 0, 0, 1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 33 },
+ { 3, 0, 0, 0, 2, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 33 },
+ { 3, 0, 0, 0, 3, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 33 },
+ { 3, 0, 0, 0, 4, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 33 },
+ { 3, 0, 0, 0, 5, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 33 },
+ { 3, 0, 0, 0, 6, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 33 },
+ { 3, 0, 0, 0, 7, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 33 },
+ { 3, 0, 0, 0, 8, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 33 },
+ { 3, 0, 0, 0, 9, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 33 },
+ { 18, 0, 0, 2, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 33 },
+ { 17, 0, 0, 2, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 33 },
+ { 18, 0, 0, 2, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 33 },
+ { 18, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 33 },
+ { 0, 17, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 33 },
+ { 0, 17, 228, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 33 },
+ { 18, 0, 0, 2, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 33 },
+ { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 47 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 47 },
+ { 0, 17, 0, 5, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 47 },
+ { 1, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 47 },
+ { 0, 17, 222, 5, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 47 },
+ { 0, 17, 230, 5, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 47 },
+ { 0, 17, 220, 5, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 47 },
+ { 29, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 47 },
+ { 25, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 12, 1, 47 },
+ { 3, 0, 0, 0, 0, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 47 },
+ { 3, 0, 0, 0, 1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 47 },
+ { 3, 0, 0, 0, 2, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 47 },
+ { 3, 0, 0, 0, 3, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 47 },
+ { 3, 0, 0, 0, 4, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 47 },
+ { 3, 0, 0, 0, 5, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 47 },
+ { 3, 0, 0, 0, 6, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 47 },
+ { 3, 0, 0, 0, 7, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 47 },
+ { 3, 0, 0, 0, 8, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 47 },
+ { 3, 0, 0, 0, 9, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 47 },
+ { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 48 },
+ { 18, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 56 },
+ { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 56 },
+ { 3, 0, 0, 0, 0, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 56 },
+ { 3, 0, 0, 0, 1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 56 },
+ { 3, 0, 0, 0, 2, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 56 },
+ { 3, 0, 0, 0, 3, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 56 },
+ { 3, 0, 0, 0, 4, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 56 },
+ { 3, 0, 0, 0, 5, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 56 },
+ { 3, 0, 0, 0, 6, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 56 },
+ { 3, 0, 0, 0, 7, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 56 },
+ { 3, 0, 0, 0, 8, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 56 },
+ { 3, 0, 0, 0, 9, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 56 },
+ { 5, 0, 0, 0, 1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 0, 1, 56 },
+ { 29, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 0, 1, 56 },
+ { 29, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 32 },
+ { 18, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 55 },
+ { 0, 17, 230, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 55 },
+ { 0, 17, 220, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 55 },
+ { 1, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 55 },
+ { 0, 17, 0, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 55 },
+ { 25, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 55 },
+ { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 78 },
+ { 1, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 35, 4, 1, 78 },
+ { 0, 17, 0, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 78 },
+ { 0, 17, 9, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 78 },
+ { 1, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 4, 35, 4, 1, 78 },
+ { 0, 17, 230, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 78 },
+ { 0, 17, 220, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 78 },
+ { 3, 0, 0, 0, 0, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 78 },
+ { 3, 0, 0, 0, 1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 78 },
+ { 3, 0, 0, 0, 2, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 78 },
+ { 3, 0, 0, 0, 3, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 78 },
+ { 3, 0, 0, 0, 4, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 78 },
+ { 3, 0, 0, 0, 5, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 78 },
+ { 3, 0, 0, 0, 6, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 78 },
+ { 3, 0, 0, 0, 7, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 78 },
+ { 3, 0, 0, 0, 8, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 78 },
+ { 3, 0, 0, 0, 9, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 78 },
+ { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 0, 1, 78 },
+ { 17, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 78 },
+ { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 12, 1, 78 },
+ { 0, 17, 230, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 220, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 2, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 220, 5, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 230, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 220, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 0, 5, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 62 },
+ { 1, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 62 },
+ { 18, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 62 },
+ { 18, 0, 0, 0, -1, 0, 9, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 62 },
+ { 0, 17, 7, 5, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 62 },
+ { 1, 0, 0, 0, -1, 0, 9, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 62 },
+ { 1, 0, 0, 0, -1, 0, 9, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 62 },
+ { 1, 0, 9, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 62 },
+ { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 62 },
+ { 3, 0, 0, 0, 0, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 62 },
+ { 3, 0, 0, 0, 1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 62 },
+ { 3, 0, 0, 0, 2, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 62 },
+ { 3, 0, 0, 0, 3, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 62 },
+ { 3, 0, 0, 0, 4, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 62 },
+ { 3, 0, 0, 0, 5, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 62 },
+ { 3, 0, 0, 0, 6, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 62 },
+ { 3, 0, 0, 0, 7, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 62 },
+ { 3, 0, 0, 0, 8, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 62 },
+ { 3, 0, 0, 0, 9, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 62 },
+ { 25, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 62 },
+ { 25, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 62 },
+ { 25, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 62 },
+ { 29, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 62 },
+ { 0, 17, 230, 5, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 62 },
+ { 0, 17, 220, 5, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 62 },
+ { 25, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 62 },
+ { 0, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 67 },
+ { 1, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 67 },
+ { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 67 },
+ { 1, 0, 9, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 67 },
+ { 0, 17, 9, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 67 },
+ { 0, 17, 0, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 67 },
+ { 3, 0, 0, 0, 0, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 67 },
+ { 3, 0, 0, 0, 1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 67 },
+ { 3, 0, 0, 0, 2, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 67 },
+ { 3, 0, 0, 0, 3, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 67 },
+ { 3, 0, 0, 0, 4, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 67 },
+ { 3, 0, 0, 0, 5, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 67 },
+ { 3, 0, 0, 0, 6, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 67 },
+ { 3, 0, 0, 0, 7, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 67 },
+ { 3, 0, 0, 0, 8, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 67 },
+ { 3, 0, 0, 0, 9, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 67 },
+ { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 67 },
+ { 18, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 93 },
+ { 0, 17, 7, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 93 },
+ { 1, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 93 },
+ { 0, 17, 0, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 93 },
+ { 1, 0, 9, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 93 },
+ { 25, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 93 },
+ { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 68 },
+ { 1, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 68 },
+ { 0, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 68 },
+ { 0, 17, 7, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 68 },
+ { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 68 },
+ { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 68 },
+ { 3, 0, 0, 0, 0, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 68 },
+ { 3, 0, 0, 0, 1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 68 },
+ { 3, 0, 0, 0, 2, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 68 },
+ { 3, 0, 0, 0, 3, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 68 },
+ { 3, 0, 0, 0, 4, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 68 },
+ { 3, 0, 0, 0, 5, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 68 },
+ { 3, 0, 0, 0, 6, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 68 },
+ { 3, 0, 0, 0, 7, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 68 },
+ { 3, 0, 0, 0, 8, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 68 },
+ { 3, 0, 0, 0, 9, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 68 },
+ { 3, 0, 0, 0, 0, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 69 },
+ { 3, 0, 0, 0, 1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 69 },
+ { 3, 0, 0, 0, 2, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 69 },
+ { 3, 0, 0, 0, 3, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 69 },
+ { 3, 0, 0, 0, 4, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 69 },
+ { 3, 0, 0, 0, 5, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 69 },
+ { 3, 0, 0, 0, 6, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 69 },
+ { 3, 0, 0, 0, 7, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 69 },
+ { 3, 0, 0, 0, 8, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 69 },
+ { 3, 0, 0, 0, 9, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 69 },
+ { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 69 },
+ { 17, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 69 },
+ { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 69 },
+ { 15, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, -6254}, {0, -6254}, {0, -6222} }, 0, 10, 14, 6, 3, 5 },
+ { 15, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, -6253}, {0, -6253}, {0, -6221} }, 0, 10, 14, 6, 3, 5 },
+ { 15, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, -6244}, {0, -6244}, {0, -6212} }, 0, 10, 14, 6, 3, 5 },
+ { 15, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, -6242}, {0, -6242}, {0, -6210} }, 0, 10, 14, 6, 3, 5 },
+ { 15, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, -6243}, {0, -6243}, {0, -6211} }, 0, 10, 14, 6, 3, 5 },
+ { 15, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, -6236}, {0, -6236}, {0, -6204} }, 0, 10, 14, 6, 3, 5 },
+ { 15, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, -6181}, {0, -6181}, {0, -6180} }, 0, 10, 14, 6, 3, 5 },
+ { 15, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {1, 201}, {1, 201}, {1, 719} }, 0, 10, 14, 6, 3, 5 },
+ { 14, 0, 0, 0, -1, 0, 20, 3, 0, { {0, -3008}, {0, 0}, {0, 0}, {0, -3008} }, 0, 10, 14, 8, 3, 25 },
+ { 25, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 67 },
+ { 0, 17, 230, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 0, 17, 1, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 220, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 1, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 2 },
+ { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 2 },
+ { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 2 },
+ { 0, 17, 230, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 1, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 2 },
+ { 18, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 2 },
+ { 15, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 5 },
+ { 17, 0, 0, 0, -1, 0, 7, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 17, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 17, 0, 0, 0, -1, 0, 7, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 17, 0, 0, 0, -1, 0, 8, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 5 },
+ { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {1, 203}, {1, 203}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 3814}, {0, 3814}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {1, 205}, {1, 205}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 17, 0, 0, 0, -1, 0, 8, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 17, 0, 0, 0, -1, 0, 8, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 0, 17, 230, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 220, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 230, 5, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 220, 5, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 230, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 234, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 6, 4, 1, 1 },
+ { 0, 17, 214, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 220, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 202, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 232, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 228, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 220, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 218, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 230, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 233, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 6, 4, 1, 1 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 514}, {1, 514}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 517}, {1, 517}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 520}, {1, 520}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 523}, {1, 523}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 526}, {1, 526}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 2, 3, 81, { {0, 0}, {0, -59}, {0, -59}, {0, -58} }, 0, 10, 14, 6, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 10, 3, 0, { {0, -7615}, {0, 0}, {0, 0}, {0, -7615} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 8}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {0, 0}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 529}, {1, 529}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 532}, {1, 532}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 536}, {1, 536}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 540}, {1, 540}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 74}, {0, 74}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 74}, {0, 74}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 86}, {0, 86}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 86}, {0, 86}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 100}, {0, 100}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 100}, {0, 100}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 128}, {0, 128}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 128}, {0, 128}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 112}, {0, 112}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 112}, {0, 112}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 126}, {0, 126}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 126}, {0, 126}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 578}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 581}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 584}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 587}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 590}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 593}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 596}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 599}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 578}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 581}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 584}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 587}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 590}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 593}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 596}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 599}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 602}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 605}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 608}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 611}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 614}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 617}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 620}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 623}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 602}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 605}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 608}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 611}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 614}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 617}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 620}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 623}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 626}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 629}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 632}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 635}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 638}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 641}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 644}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 647}, {0, 8}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 626}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 629}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 632}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 635}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 638}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 641}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 644}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -8}, {1, 647}, {0, 0}, {0, -8} }, 0, 10, 14, 7, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 662}, {1, 659}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 650}, {0, 9}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 668}, {1, 665}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 544}, {1, 544}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 699}, {1, 695}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -74}, {0, 0}, {0, 0}, {0, -74} }, 0, 10, 14, 7, 3, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 85, { {0, -74}, {0, 0}, {0, 0}, {0, -74} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -9}, {1, 650}, {0, 0}, {0, -9} }, 0, 10, 14, 7, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, -7205}, {0, -7205}, {0, -7173} }, 0, 10, 14, 6, 3, 4 },
+ { 28, 10, 0, 0, -1, 0, 1, 3, 81, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 674}, {1, 671}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 653}, {0, 9}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 680}, {1, 677}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 547}, {1, 547}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 707}, {1, 703}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -86}, {0, 0}, {0, 0}, {0, -86} }, 0, 10, 14, 7, 3, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 85, { {0, -86}, {0, 0}, {0, 0}, {0, -86} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -9}, {1, 653}, {0, 0}, {0, -9} }, 0, 10, 14, 7, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 550}, {1, 550}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {1, 503}, {1, 503}, {0, -7235} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 554}, {1, 554}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 557}, {1, 557}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -100}, {0, 0}, {0, 0}, {0, -100} }, 0, 10, 14, 7, 3, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 85, { {0, -100}, {0, 0}, {0, 0}, {0, -100} }, 0, 10, 14, 7, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 561}, {1, 561}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {1, 507}, {1, 507}, {0, -7219} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 565}, {1, 565}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 7}, {0, 7}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 568}, {1, 568}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 571}, {1, 571}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -112}, {0, 0}, {0, 0}, {0, -112} }, 0, 10, 14, 7, 3, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 85, { {0, -112}, {0, 0}, {0, 0}, {0, -112} }, 0, 10, 14, 7, 3, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -7}, {0, 0}, {0, 0}, {0, -7} }, 0, 10, 14, 7, 3, 4 },
+ { 28, 10, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 686}, {1, 683}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 656}, {0, 9}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 692}, {1, 689}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 575}, {1, 575}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {1, 715}, {1, 711}, {0, 0} }, 0, 10, 14, 6, 3, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -128}, {0, 0}, {0, 0}, {0, -128} }, 0, 10, 14, 7, 3, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 85, { {0, -128}, {0, 0}, {0, 0}, {0, -128} }, 0, 10, 14, 7, 3, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -126}, {0, 0}, {0, 0}, {0, -126} }, 0, 10, 14, 7, 3, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 85, { {0, -126}, {0, 0}, {0, 0}, {0, -126} }, 0, 10, 14, 7, 3, 4 },
+ { 16, 0, 0, 0, -1, 0, 1, 3, 17, { {0, -9}, {1, 656}, {0, 0}, {0, -9} }, 0, 10, 14, 7, 3, 4 },
+ { 28, 10, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 20, 0, 0, 4 },
+ { 6, 9, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 18, 19, 5, 0, 2 },
+ { 6, 9, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 18, 19, 5, 0, 2 },
+ { 6, 9, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 5, 0, 2 },
+ { 10, 18, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 0, 22, 4, 2, 2 },
+ { 10, 18, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 4, 1 },
+ { 10, 18, 0, 1, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 5, 5, 34, 4, 4, 1 },
+ { 10, 0, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 23, 4, 0, 2 },
+ { 10, 1, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 23, 4, 0, 2 },
+ { 20, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 2 },
+ { 20, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 0, 3, 2 },
+ { 20, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 2 },
{ 20, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 11, 1, 2 },
- { 20, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
+ { 20, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 21, 11, 1, 2 },
+ { 20, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
{ 23, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 13, 3, 13, 1, 2 },
{ 24, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 13, 3, 13, 1, 2 },
{ 21, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 1, 2 },
{ 23, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 3, 13, 1, 2 },
{ 23, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 3, 13, 1, 2 },
{ 24, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 3, 13, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 13, 15, 10, 0, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 15, 0, 0, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 14, 17, 0, 1, 2 },
- { 7, 9, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 3, 38, 3, 0, 2 },
- { 8, 7, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 3, 38, 3, 0, 2 },
- { 10, 11, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 21, 4, 0, 2 },
- { 10, 14, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 21, 4, 0, 2 },
- { 10, 16, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 21, 4, 0, 2 },
- { 10, 12, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 21, 4, 0, 2 },
- { 10, 15, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 21, 4, 0, 2 },
- { 6, 6, 0, 0, -1, 0, 4, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 17, 4, 5, 0, 2 },
- { 25, 4, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 1, 2 },
- { 25, 4, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 1, 2 },
- { 25, 4, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 3, 2 },
- { 25, 4, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 3, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 3, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 13, 17, 10, 0, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 0, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 14, 19, 0, 1, 2 },
+ { 7, 9, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 3, 40, 3, 0, 2 },
+ { 8, 7, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 3, 40, 3, 0, 2 },
+ { 10, 11, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 23, 4, 0, 2 },
+ { 10, 14, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 23, 4, 0, 2 },
+ { 10, 16, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 23, 4, 0, 2 },
+ { 10, 12, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 23, 4, 0, 2 },
+ { 10, 15, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 23, 4, 0, 2 },
+ { 6, 6, 0, 0, -1, 0, 4, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 17, 6, 5, 0, 2 },
+ { 25, 4, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
+ { 25, 4, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
+ { 25, 4, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
+ { 25, 4, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
{ 23, 10, 0, 0, -1, 1, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 3, 13, 1, 2 },
{ 24, 10, 0, 0, -1, -1, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 3, 13, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 5, 12, 0, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 5, 12, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 19, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 17, 12, 0, 1, 2 },
- { 26, 6, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 8, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 7, 12, 0, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 7, 12, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 19, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 17, 14, 0, 1, 2 },
+ { 26, 6, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 10, 0, 1, 2 },
{ 21, 10, 0, 0, -1, 1, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 1, 2 },
{ 22, 10, 0, 0, -1, -1, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 6, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 5, 12, 0, 2 },
- { 25, 10, 0, 0, -1, 0, 4, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 5, 12, 0, 2 },
- { 25, 10, 0, 0, -1, 0, 4, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 5, 12, 0, 2 },
- { 25, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 19, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 17, 12, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 6, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 3, 2 },
- { 6, 9, 0, 0, -1, 0, 6, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 18, 17, 5, 0, 2 },
- { 10, 18, 0, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 22, 4, 2, 2 },
- { 10, 18, 0, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 12, 4, 0, 2 },
- { 10, 18, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 12, 4, 2, 2 },
- { 13, 18, 0, 0, -1, 0, 0, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 0, 12, 0, 0, 0 },
- { 10, 19, 0, 0, -1, 0, 15, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 21, 4, 0, 2 },
- { 10, 20, 0, 0, -1, 0, 15, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 21, 4, 0, 2 },
- { 10, 21, 0, 0, -1, 0, 15, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 21, 4, 0, 2 },
- { 10, 22, 0, 0, -1, 0, 15, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 21, 4, 0, 2 },
- { 10, 18, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 21, 4, 0, 2 },
- { 5, 2, 0, 0, 0, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 17, 0, 0, 0, -1, 0, 6, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 5, 2, 0, 0, 4, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 5, 2, 0, 0, 5, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 5, 2, 0, 0, 6, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 5, 2, 0, 0, 7, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 5, 2, 0, 0, 8, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 5, 2, 0, 0, 9, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 26, 3, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 26, 3, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 26, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
+ { 25, 10, 0, 0, -1, 0, 6, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 7, 12, 0, 2 },
+ { 25, 10, 0, 0, -1, 0, 4, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 7, 12, 0, 2 },
+ { 25, 10, 0, 0, -1, 0, 4, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 7, 12, 0, 2 },
+ { 25, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 19, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 17, 14, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 6, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
+ { 6, 9, 0, 0, -1, 0, 6, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 18, 19, 5, 0, 2 },
+ { 10, 18, 0, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 24, 4, 2, 2 },
+ { 10, 18, 0, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 14, 4, 0, 2 },
+ { 10, 18, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 14, 4, 2, 2 },
+ { 13, 18, 0, 0, -1, 0, 0, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 0, 14, 0, 0, 0 },
+ { 10, 19, 0, 0, -1, 0, 15, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 23, 4, 0, 2 },
+ { 10, 20, 0, 0, -1, 0, 15, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 23, 4, 0, 2 },
+ { 10, 21, 0, 0, -1, 0, 15, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 23, 4, 0, 2 },
+ { 10, 22, 0, 0, -1, 0, 15, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 23, 4, 0, 2 },
+ { 10, 18, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 23, 4, 0, 2 },
+ { 5, 2, 0, 0, 0, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 17, 0, 0, 0, -1, 0, 6, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 5, 2, 0, 0, 4, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 5, 2, 0, 0, 5, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 5, 2, 0, 0, 6, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 5, 2, 0, 0, 7, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 5, 2, 0, 0, 8, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 5, 2, 0, 0, 9, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 26, 3, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 26, 3, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 26, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
{ 21, 10, 0, 0, -1, 1, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 0, 2 },
{ 22, 10, 0, 0, -1, -1, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 0, 2 },
- { 17, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 17, 0, 0, 0, -1, 0, 12, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 27, 4, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 1, 2 },
- { 27, 4, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 3, 2 },
- { 27, 4, 0, 0, -1, 0, 1, 2, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 2 },
- { 27, 4, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 2 },
- { 27, 4, 0, 0, -1, 0, 3, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 2 },
- { 27, 4, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 2 },
- { 27, 4, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 2 },
- { 27, 4, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 2 },
- { 27, 4, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 1, 2 },
- { 27, 4, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 2 },
- { 27, 4, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 2 },
- { 27, 4, 0, 0, -1, 0, 14, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 2 },
- { 27, 4, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 1, 2 },
- { 27, 4, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 2 },
- { 27, 4, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 1, 2 },
- { 27, 4, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 2 },
- { 27, 4, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 1, 2 },
- { 13, 4, 0, 0, -1, 0, 0, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 0, 0 },
- { 0, 17, 1, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 2, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 2, 17, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 2, 17, 0, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 1, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 230, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 220, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 1, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 29, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 3, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 3, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 2 },
- { 15, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 3, 2 },
- { 26, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
+ { 17, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 17, 0, 0, 0, -1, 0, 12, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 27, 4, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
+ { 27, 4, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 3, 2 },
+ { 27, 4, 0, 0, -1, 0, 1, 2, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 2 },
+ { 27, 4, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 2 },
+ { 27, 4, 0, 0, -1, 0, 3, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 2 },
+ { 27, 4, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 2 },
+ { 27, 4, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 2 },
+ { 27, 4, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 2 },
+ { 27, 4, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
+ { 27, 4, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 2 },
+ { 27, 4, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 2 },
+ { 27, 4, 0, 0, -1, 0, 14, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 2 },
+ { 27, 4, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
+ { 27, 4, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 2 },
+ { 27, 4, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
+ { 27, 4, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 2 },
+ { 27, 4, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
+ { 13, 4, 0, 0, -1, 0, 0, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 0, 0 },
+ { 0, 17, 1, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 2, 17, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 2, 17, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 2, 17, 0, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 1, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 230, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 220, 5, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 1, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 29, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 3, 2 },
{ 29, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 3, 2 },
- { 14, 0, 0, 0, -1, 0, 1, 0, 85, { {0, -7517}, {0, 0}, {0, 0}, {0, -7517} }, 0, 10, 12, 7, 3, 4 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 85, { {1, 207}, {0, 0}, {0, 0}, {1, 207} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 1, 0, 85, { {1, 209}, {0, 0}, {0, 0}, {1, 209} }, 0, 10, 12, 7, 3, 3 },
- { 29, 4, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 28}, {0, 0}, {0, 0}, {0, 28} }, 0, 10, 12, 7, 0, 3 },
- { 18, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 3, 2 },
- { 15, 0, 0, 0, -1, 0, 4, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 10, 12, 6, 3, 2 },
- { 29, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 7, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 15, 0, 0, 0, -1, 0, 8, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 2 },
- { 15, 0, 0, 0, -1, 0, 6, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 2 },
- { 14, 0, 0, 0, -1, 0, 6, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 3, 2 },
- { 26, 10, 0, 0, -1, 0, 6, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 29, 10, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 15, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, -28}, {0, -28}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 29, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, -1, 0, 11, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 5, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 4, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 16}, {0, 0}, {0, 0}, {0, 16} }, 0, 10, 12, 7, 3, 3 },
- { 4, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 16}, {0, 0}, {0, 0}, {0, 16} }, 0, 10, 12, 7, 3, 3 },
- { 4, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, -16}, {0, -16}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 4, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, -16}, {0, -16}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 4, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 0, 3 },
- { 4, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 3 },
- { 5, 10, 0, 0, -1, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 29, 10, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 3, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 3, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 3, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -3, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -3, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -3, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 3, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 2 },
- { 26, 4, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 2016, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 2527, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 1923, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 1914, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 1918, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 2250, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 26, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 26, 10, 0, 0, -1, 1, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -1, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 138, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 7, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -7, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -1, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 1, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 0, 1, 0, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 26, 10, 0, 0, -1, 1, 1, 0, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 26, 10, 0, 0, -1, -1, 1, 0, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 26, 10, 0, 0, -1, 1, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -1, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 1824, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 2104, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 2108, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 2106, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 1316, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -138, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 15, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 8, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 7, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -8, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -7, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 2 },
+ { 15, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 3, 2 },
+ { 26, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 3, 2 },
+ { 14, 0, 0, 0, -1, 0, 1, 0, 85, { {0, -7517}, {0, 0}, {0, 0}, {0, -7517} }, 0, 10, 14, 7, 3, 4 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 85, { {1, 207}, {0, 0}, {0, 0}, {1, 207} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 1, 0, 85, { {1, 209}, {0, 0}, {0, 0}, {1, 209} }, 0, 10, 14, 7, 3, 3 },
+ { 29, 4, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 14, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 28}, {0, 0}, {0, 0}, {0, 28} }, 0, 10, 14, 7, 0, 3 },
+ { 18, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 3, 2 },
+ { 15, 0, 0, 0, -1, 0, 4, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 10, 14, 6, 3, 2 },
+ { 29, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 7, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 15, 0, 0, 0, -1, 0, 8, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 2 },
+ { 15, 0, 0, 0, -1, 0, 6, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 2 },
+ { 14, 0, 0, 0, -1, 0, 6, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 3, 2 },
+ { 26, 10, 0, 0, -1, 0, 6, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 29, 10, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 15, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, -28}, {0, -28}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 29, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, -1, 0, 11, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 5, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 4, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 16}, {0, 0}, {0, 0}, {0, 16} }, 0, 10, 14, 7, 3, 3 },
+ { 4, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 16}, {0, 0}, {0, 0}, {0, 16} }, 0, 10, 14, 7, 3, 3 },
+ { 4, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, -16}, {0, -16}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 4, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, -16}, {0, -16}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 4, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 0, 3 },
+ { 4, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 3 },
+ { 5, 10, 0, 0, -1, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 29, 10, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 3, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 3, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 3, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -3, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -3, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -3, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 3, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 2 },
+ { 26, 4, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 2016, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 2527, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 1923, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 1914, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 1918, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 2250, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 26, 10, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 26, 10, 0, 0, -1, 1, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -1, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 138, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 7, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -7, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -1, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 1, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 0, 1, 0, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 1, 1, 0, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -1, 1, 0, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 1, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -1, 1, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 1824, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 2104, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 2108, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 2106, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 1316, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -138, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 8, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 7, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -8, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -7, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
{ 21, 10, 0, 0, -1, 1, 1, 5, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 3, 2 },
{ 22, 10, 0, 0, -1, -1, 1, 5, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 3, 2 },
- { 29, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
- { 29, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 12, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
+ { 29, 0, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
+ { 29, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
{ 29, 10, 0, 0, -1, 0, 12, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
{ 29, 10, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 5, 10, 0, 0, 2, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 5, 10, 0, 0, 3, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 5, 10, 0, 0, 4, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 5, 10, 0, 0, 5, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 5, 10, 0, 0, 6, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 5, 10, 0, 0, 7, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 5, 10, 0, 0, 8, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 5, 10, 0, 0, 9, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 5, 10, 0, 0, 1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 10, 0, 0, 2, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 10, 0, 0, 3, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 10, 0, 0, 4, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 10, 0, 0, 5, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 10, 0, 0, 6, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 10, 0, 0, 7, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 10, 0, 0, 8, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 10, 0, 0, 9, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 2, 0, 0, 1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 2, 0, 0, 2, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 2, 0, 0, 3, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 2, 0, 0, 4, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 2, 0, 0, 5, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 2, 0, 0, 6, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 2, 0, 0, 7, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 2, 0, 0, 8, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 2, 0, 0, 9, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 2, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 29, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 29, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 26}, {0, 0}, {0, 0}, {0, 26} }, 0, 10, 12, 7, 3, 2 },
- { 29, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 26}, {0, 0}, {0, 0}, {0, 26} }, 14, 10, 12, 7, 3, 2 },
- { 29, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, -26}, {0, -26}, {0, 0} }, 0, 10, 12, 6, 3, 2 },
- { 5, 10, 0, 0, 0, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 5, 10, 0, 0, -1, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 1, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 2, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 3, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 4, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 5, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 6, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 7, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 8, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 9, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 0, 0, 7, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 0, 6, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 7, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 12, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 5, 10, 0, 0, 2, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 5, 10, 0, 0, 3, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 5, 10, 0, 0, 4, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 5, 10, 0, 0, 5, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 5, 10, 0, 0, 6, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 5, 10, 0, 0, 7, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 5, 10, 0, 0, 8, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 5, 10, 0, 0, 9, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 5, 10, 0, 0, 1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 10, 0, 0, 2, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 10, 0, 0, 3, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 10, 0, 0, 4, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 10, 0, 0, 5, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 10, 0, 0, 6, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 10, 0, 0, 7, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 10, 0, 0, 8, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 10, 0, 0, 9, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 10, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 2, 0, 0, 1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 2, 0, 0, 2, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 2, 0, 0, 3, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 2, 0, 0, 4, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 2, 0, 0, 5, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 2, 0, 0, 6, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 2, 0, 0, 7, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 2, 0, 0, 8, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 2, 0, 0, 9, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 2, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 29, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 29, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 26}, {0, 0}, {0, 0}, {0, 26} }, 0, 10, 14, 7, 3, 2 },
+ { 29, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 26}, {0, 0}, {0, 0}, {0, 26} }, 14, 10, 14, 7, 3, 2 },
+ { 29, 0, 0, 0, -1, 0, 1, 0, 80, { {0, 0}, {0, -26}, {0, -26}, {0, 0} }, 0, 10, 14, 6, 3, 2 },
+ { 5, 10, 0, 0, 0, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 5, 10, 0, 0, -1, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 1, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 2, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 3, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 4, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 5, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 6, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 7, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 8, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 9, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 0, 0, 7, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 0, 6, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 7, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 32, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
{ 29, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 30, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 8, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
{ 29, 10, 0, 0, -1, 0, 8, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 8, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 11, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 7, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
- { 29, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 11, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 11, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
{ 29, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 11, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 30, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 12, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 30, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 11, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 11, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 7, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
+ { 29, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 11, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 11, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 11, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 32, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 12, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 32, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 11, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
{ 29, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 3, 13, 1, 2 },
{ 29, 10, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 3, 13, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 6, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 8, 0, 1, 2 },
{ 21, 10, 0, 0, -1, 1, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 1, 2 },
{ 22, 10, 0, 0, -1, -1, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 1, 2 },
- { 5, 10, 0, 0, 1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 2, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 3, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 4, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 5, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 6, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 7, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 8, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 9, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 1, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -1, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
+ { 5, 10, 0, 0, 1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 2, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 3, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 4, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 5, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 6, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 7, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 8, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 9, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 2, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 3, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 4, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 5, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 6, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 7, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 8, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, 9, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 1, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -1, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
{ 21, 10, 0, 0, -1, 1, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 1, 2 },
{ 22, 10, 0, 0, -1, -1, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 1, 2 },
- { 26, 10, 0, 0, -1, 1, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -1, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 2, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -2, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 1, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -1, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -1316, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 1, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -1, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 2, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -2, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 1, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -1, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -1316, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
{ 21, 10, 0, 0, -1, 1, 6, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 1, 2 },
{ 22, 10, 0, 0, -1, -1, 6, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 1, 2 },
{ 21, 10, 0, 0, -1, 1, 10, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 1, 2 },
{ 22, 10, 0, 0, -1, -1, 10, 4, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 1, 2 },
{ 21, 10, 0, 0, -1, 1, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 1, 2 },
{ 22, 10, 0, 0, -1, -1, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 1, 2 },
- { 29, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 54 },
+ { 29, 0, 0, 0, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 54 },
{ 21, 10, 0, 0, -1, 3, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 1, 2 },
{ 22, 10, 0, 0, -1, 1, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 1, 2 },
{ 21, 10, 0, 0, -1, -1, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 1, 2 },
{ 22, 10, 0, 0, -1, -3, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 1, 2 },
- { 26, 10, 0, 0, -1, -1914, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -1918, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -1923, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -1824, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -2016, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, 0, 6, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 26, 10, 0, 0, -1, 0, 6, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 26, 10, 0, 0, -1, -2104, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -2106, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -2108, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 26, 10, 0, 0, -1, -2250, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 10, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 11, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, -2527, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 14, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 48}, {0, 0}, {0, 0}, {0, 48} }, 0, 10, 12, 7, 3, 57 },
- { 14, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 48}, {0, 0}, {0, 0}, {0, 48} }, 0, 10, 12, 7, 3, 57 },
- { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, -48}, {0, -48}, {0, 0} }, 0, 10, 12, 6, 1, 57 },
- { 15, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, -48}, {0, -48}, {0, 0} }, 0, 10, 12, 6, 1, 57 },
- { 14, 0, 0, 0, -1, 0, 9, 3, 0, { {1, 211}, {0, 0}, {0, 0}, {1, 211} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 9, 3, 0, { {0, -3814}, {0, 0}, {0, 0}, {0, -3814} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 9, 3, 0, { {1, 213}, {0, 0}, {0, 0}, {1, 213} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {1, 215}, {1, 215}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {1, 217}, {1, 217}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 10, 3, 0, { {1, 219}, {0, 0}, {0, 0}, {1, 219} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 10, 3, 0, { {1, 221}, {0, 0}, {0, 0}, {1, 221} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 10, 3, 0, { {1, 223}, {0, 0}, {0, 0}, {1, 223} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 11, 3, 0, { {1, 225}, {0, 0}, {0, 0}, {1, 225} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 17, 0, 0, 0, -1, 0, 10, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 11, 3, 0, { {1, 227}, {0, 0}, {0, 0}, {1, 227} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 11, 3, 0, { {1, 229}, {0, 0}, {0, 0}, {1, 229} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 46 },
- { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 46 },
- { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 46 },
- { 29, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 46 },
- { 14, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 46 },
- { 15, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 46 },
- { 0, 17, 230, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 46 },
- { 14, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 46 },
- { 15, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 46 },
- { 25, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 0, 1, 46 },
- { 25, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 46 },
- { 5, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 46 },
- { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, -7264}, {0, -7264}, {0, 0} }, 0, 10, 12, 6, 1, 25 },
- { 15, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, -7264}, {0, -7264}, {0, 0} }, 0, 10, 12, 6, 1, 25 },
- { 18, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 58 },
- { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 58 },
- { 17, 0, 0, 0, -1, 0, 8, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 3, 58 },
- { 25, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 58 },
- { 0, 17, 9, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 58 },
+ { 26, 10, 0, 0, -1, -1914, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -1918, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -1923, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -1824, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -2016, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, 0, 6, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 26, 10, 0, 0, -1, 0, 6, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 26, 10, 0, 0, -1, -2104, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -2106, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -2108, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 26, 10, 0, 0, -1, -2250, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 10, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 11, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, -2527, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 14, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 48}, {0, 0}, {0, 0}, {0, 48} }, 0, 10, 14, 7, 3, 57 },
+ { 14, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 48}, {0, 0}, {0, 0}, {0, 48} }, 0, 10, 14, 7, 3, 57 },
+ { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, -48}, {0, -48}, {0, 0} }, 0, 10, 14, 6, 1, 57 },
+ { 15, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, -48}, {0, -48}, {0, 0} }, 0, 10, 14, 6, 1, 57 },
+ { 14, 0, 0, 0, -1, 0, 9, 3, 0, { {1, 211}, {0, 0}, {0, 0}, {1, 211} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 9, 3, 0, { {0, -3814}, {0, 0}, {0, 0}, {0, -3814} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 9, 3, 0, { {1, 213}, {0, 0}, {0, 0}, {1, 213} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {1, 215}, {1, 215}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {1, 217}, {1, 217}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 10, 3, 0, { {1, 219}, {0, 0}, {0, 0}, {1, 219} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 10, 3, 0, { {1, 221}, {0, 0}, {0, 0}, {1, 221} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 10, 3, 0, { {1, 223}, {0, 0}, {0, 0}, {1, 223} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 11, 3, 0, { {1, 225}, {0, 0}, {0, 0}, {1, 225} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 17, 0, 0, 0, -1, 0, 10, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 11, 3, 0, { {1, 227}, {0, 0}, {0, 0}, {1, 227} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 11, 3, 0, { {1, 229}, {0, 0}, {0, 0}, {1, 229} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 46 },
+ { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 46 },
+ { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 46 },
+ { 29, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 46 },
+ { 14, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 46 },
+ { 15, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 46 },
+ { 0, 17, 230, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 46 },
+ { 14, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 46 },
+ { 15, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 46 },
+ { 25, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 0, 1, 46 },
+ { 25, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 46 },
+ { 5, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 46 },
+ { 15, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, -7264}, {0, -7264}, {0, 0} }, 0, 10, 14, 6, 1, 25 },
+ { 15, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, -7264}, {0, -7264}, {0, 0} }, 0, 10, 14, 6, 1, 25 },
+ { 18, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 58 },
+ { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 58 },
+ { 17, 0, 0, 0, -1, 0, 8, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 3, 58 },
+ { 25, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 58 },
+ { 0, 17, 9, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 58 },
{ 25, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 3, 13, 1, 2 },
{ 23, 10, 0, 0, -1, 1, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 3, 13, 1, 2 },
{ 24, 10, 0, 0, -1, -1, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 3, 13, 1, 2 },
- { 20, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 2 },
+ { 20, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 2 },
{ 25, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 2 },
- { 20, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 2 },
+ { 20, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
{ 23, 10, 0, 0, -1, 1, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 3, 13, 1, 2 },
{ 24, 10, 0, 0, -1, -1, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 3, 13, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 12, 1, 2 },
- { 17, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 2 },
- { 20, 10, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 20, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 12, 1, 2 },
+ { 17, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 2 },
+ { 20, 10, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 21, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 20, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 2 },
{ 21, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 12, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 12, 1, 2 },
{ 21, 10, 0, 0, -1, 1, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 1, 2 },
{ 22, 10, 0, 0, -1, -1, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 1, 2 },
- { 20, 10, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 4, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 37 },
- { 29, 10, 0, 0, -1, 0, 4, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 37 },
- { 29, 10, 0, 0, -1, 0, 4, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
- { 6, 9, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 18, 17, 5, 0, 2 },
+ { 20, 10, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 4, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 37 },
+ { 29, 10, 0, 0, -1, 0, 4, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 3, 37 },
+ { 29, 10, 0, 0, -1, 0, 4, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 2 },
+ { 29, 10, 0, 0, -1, 0, 26, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 2 },
+ { 6, 9, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 18, 19, 5, 0, 2 },
{ 25, 10, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 11, 1, 2 },
{ 25, 10, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 12, 3, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
- { 17, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 5, 8, 1, 37 },
- { 18, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 2 },
- { 4, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 37 },
+ { 25, 10, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 2 },
+ { 17, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 7, 8, 1, 37 },
+ { 18, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 2 },
+ { 4, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 37 },
{ 21, 10, 0, 0, -1, 1, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 1, 2 },
{ 22, 10, 0, 0, -1, -1, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 1, 2 },
- { 20, 10, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 5, 0, 1, 2 },
+ { 20, 10, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 7, 0, 1, 2 },
{ 21, 10, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 1, 2 },
{ 22, 10, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 1, 2 },
- { 0, 17, 218, 5, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 228, 5, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 232, 5, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 222, 5, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 1, 0, 224, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 26 },
- { 20, 10, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 17, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 14, 8, 1, 2 },
- { 17, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 21, 8, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
- { 4, 0, 0, 0, -1, 0, 4, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 3, 37 },
- { 17, 0, 0, 0, -1, 0, 6, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 5, 8, 1, 37 },
- { 18, 0, 0, 0, -1, 0, 6, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 5, 8, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 6, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 4, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
- { 18, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 5, 8, 1, 34 },
- { 18, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 34 },
- { 18, 0, 0, 0, -1, 0, 1, 5, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 34 },
- { 18, 0, 0, 0, -1, 0, 6, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 5, 8, 1, 34 },
- { 0, 17, 8, 5, -1, 0, 1, 5, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 28, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 5, 0, 0, 2 },
- { 17, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 5, 8, 1, 34 },
- { 17, 0, 0, 0, -1, 0, 1, 5, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 5, 8, 1, 34 },
- { 18, 0, 0, 0, -1, 0, 6, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 3, 34 },
- { 20, 10, 0, 0, -1, 0, 6, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 5, 0, 1, 2 },
- { 18, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 5, 8, 1, 35 },
- { 18, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 14, 8, 1, 35 },
- { 18, 0, 0, 0, -1, 0, 1, 5, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 14, 8, 1, 35 },
- { 25, 10, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 5, 0, 1, 2 },
- { 17, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 5, 8, 1, 2 },
- { 17, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 5, 8, 1, 35 },
- { 17, 0, 0, 0, -1, 0, 1, 5, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 5, 8, 1, 35 },
- { 18, 0, 0, 0, -1, 0, 6, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 14, 8, 3, 35 },
- { 18, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 36 },
- { 18, 0, 0, 0, -1, 0, 10, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 36 },
- { 18, 0, 0, 0, -1, 0, 19, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 36 },
- { 18, 0, 0, 0, -1, 0, 20, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 36 },
- { 18, 0, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 3, 26 },
- { 18, 0, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 0, 26 },
- { 29, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
- { 5, 0, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
- { 29, 0, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
- { 18, 0, 0, 0, -1, 0, 4, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 36 },
- { 18, 0, 0, 0, -1, 0, 12, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 36 },
- { 18, 0, 0, 0, -1, 0, 23, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 36 },
- { 29, 10, 0, 0, -1, 0, 8, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 10, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
- { 18, 0, 0, 0, -1, 0, 6, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 5, 8, 1, 35 },
- { 29, 0, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 26 },
- { 29, 10, 0, 0, -1, 0, 7, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 26 },
- { 5, 0, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
- { 29, 0, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
- { 29, 0, 0, 0, -1, 0, 11, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
- { 5, 0, 0, 0, -1, 0, 11, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 7, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
- { 5, 10, 0, 0, -1, 0, 6, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
- { 29, 0, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 26 },
- { 29, 10, 0, 0, -1, 0, 7, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 26 },
- { 29, 10, 0, 0, -1, 0, 8, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 26 },
- { 29, 0, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 3, 2 },
- { 29, 0, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 14, 0, 3, 35 },
- { 29, 0, 0, 0, -1, 0, 22, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
- { 18, 0, 0, 0, -1, 0, 4, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 37 },
- { 18, 0, 0, 0, -1, 0, 23, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 37 },
- { 18, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 37 },
- { 18, 0, 0, 0, -1, 0, 8, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 37 },
- { 18, 0, 0, 0, -1, 0, 10, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 37 },
- { 18, 0, 0, 0, -1, 0, 11, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 37 },
- { 18, 0, 0, 0, -1, 0, 13, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 37 },
- { 18, 0, 0, 0, -1, 0, 17, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 37 },
- { 18, 0, 0, 0, -1, 0, 19, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 37 },
- { 18, 0, 0, 0, -1, 0, 20, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 37 },
- { 18, 0, 0, 0, -1, 0, 24, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 37 },
- { 18, 0, 0, 0, -1, 0, 4, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 38 },
- { 17, 0, 0, 0, -1, 0, 4, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 5, 8, 1, 38 },
- { 29, 10, 0, 0, -1, 0, 4, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 38 },
- { 29, 10, 0, 0, -1, 0, 6, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 38 },
- { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 83 },
- { 17, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 83 },
- { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 83 },
- { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 83 },
- { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 70 },
- { 17, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 70 },
- { 25, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 70 },
- { 25, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 12, 1, 70 },
- { 25, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 70 },
- { 3, 0, 0, 0, 0, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 70 },
- { 3, 0, 0, 0, 1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 70 },
- { 3, 0, 0, 0, 2, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 70 },
- { 3, 0, 0, 0, 3, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 70 },
- { 3, 0, 0, 0, 4, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 70 },
- { 3, 0, 0, 0, 5, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 70 },
- { 3, 0, 0, 0, 6, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 70 },
- { 3, 0, 0, 0, 7, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 70 },
- { 3, 0, 0, 0, 8, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 70 },
- { 3, 0, 0, 0, 9, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 70 },
- { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 5 },
- { 2, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 5 },
- { 25, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 5 },
- { 0, 17, 230, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 5 },
- { 17, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 5 },
- { 17, 0, 0, 0, -1, 0, 16, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 5 },
- { 0, 17, 230, 5, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 5 },
- { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 84 },
- { 4, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 84 },
- { 0, 17, 230, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 84 },
- { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 84 },
- { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 84 },
- { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 84 },
- { 28, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 28, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 0, 1, 2 },
- { 17, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 2 },
- { 28, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 0, 1, 2 },
- { 14, 0, 0, 0, -1, 0, 10, 3, 0, { {1, 231}, {0, 0}, {0, 0}, {1, 231} }, 0, 10, 12, 7, 3, 3 },
- { 28, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 0, 1, 2 },
- { 14, 0, 0, 0, -1, 0, 12, 3, 0, { {1, 233}, {0, 0}, {0, 0}, {1, 233} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 48}, {0, 48}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 13, 3, 0, { {1, 235}, {0, 0}, {0, 0}, {1, 235} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 16, 3, 0, { {1, 237}, {0, 0}, {0, 0}, {1, 237} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 16, 3, 0, { {1, 239}, {0, 0}, {0, 0}, {1, 239} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 16, 3, 0, { {1, 241}, {0, 0}, {0, 0}, {1, 241} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 18, 3, 0, { {1, 243}, {0, 0}, {0, 0}, {1, 243} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 16, 3, 0, { {1, 245}, {0, 0}, {0, 0}, {1, 245} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 16, 3, 0, { {1, 247}, {0, 0}, {0, 0}, {1, 247} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 17, 3, 0, { {1, 249}, {0, 0}, {0, 0}, {1, 249} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 928}, {0, 0}, {0, 0}, {0, 928} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 14, 0, 0, 0, -1, 0, 21, 3, 0, { {0, -48}, {0, 0}, {0, 0}, {0, -48} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 21, 3, 0, { {1, 251}, {0, 0}, {0, 0}, {1, 251} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 21, 3, 0, { {1, 253}, {0, 0}, {0, 0}, {1, 253} }, 0, 10, 12, 7, 3, 3 },
- { 14, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 12, 7, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 17, 0, 0, 0, -1, 0, 24, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 3 },
- { 17, 0, 0, 0, -1, 0, 13, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 3 },
- { 18, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 59 },
- { 0, 17, 0, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 59 },
- { 0, 17, 9, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 59 },
- { 1, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 59 },
- { 29, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 59 },
- { 0, 17, 9, 5, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 59 },
- { 5, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 4, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 18, 0, 0, 2, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 65 },
- { 18, 0, 0, 4, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 65 },
- { 18, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 65 },
- { 25, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 0, 1, 65 },
- { 25, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 12, 1, 65 },
- { 1, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 71 },
- { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 71 },
- { 0, 17, 9, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 71 },
- { 0, 17, 0, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 71 },
- { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 71 },
- { 3, 0, 0, 0, 0, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 71 },
- { 3, 0, 0, 0, 1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 71 },
- { 3, 0, 0, 0, 2, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 71 },
- { 3, 0, 0, 0, 3, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 71 },
- { 3, 0, 0, 0, 4, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 71 },
- { 3, 0, 0, 0, 5, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 71 },
- { 3, 0, 0, 0, 6, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 71 },
- { 3, 0, 0, 0, 7, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 71 },
- { 3, 0, 0, 0, 8, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 71 },
- { 3, 0, 0, 0, 9, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 71 },
- { 0, 17, 230, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 11 },
- { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 11 },
- { 25, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 0, 1, 11 },
- { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 11 },
- { 18, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 11 },
- { 0, 17, 0, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 11 },
- { 3, 0, 0, 0, 0, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 72 },
- { 3, 0, 0, 0, 1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 72 },
- { 3, 0, 0, 0, 2, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 72 },
- { 3, 0, 0, 0, 3, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 72 },
- { 3, 0, 0, 0, 4, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 72 },
- { 3, 0, 0, 0, 5, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 72 },
- { 3, 0, 0, 0, 6, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 72 },
- { 3, 0, 0, 0, 7, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 72 },
- { 3, 0, 0, 0, 8, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 72 },
- { 3, 0, 0, 0, 9, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 72 },
- { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 72 },
- { 0, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 72 },
- { 0, 17, 220, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 72 },
- { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 2 },
- { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 72 },
- { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 73 },
- { 0, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 73 },
- { 1, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 73 },
- { 1, 0, 9, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 73 },
- { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 73 },
- { 0, 17, 0, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 85 },
- { 1, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 85 },
- { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 85 },
- { 0, 17, 7, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 85 },
- { 1, 0, 9, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 85 },
- { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 85 },
- { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 85 },
- { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 85 },
- { 17, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 2 },
- { 3, 0, 0, 0, 0, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 85 },
- { 3, 0, 0, 0, 1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 85 },
- { 3, 0, 0, 0, 2, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 85 },
- { 3, 0, 0, 0, 3, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 85 },
- { 3, 0, 0, 0, 4, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 85 },
- { 3, 0, 0, 0, 5, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 85 },
- { 3, 0, 0, 0, 6, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 85 },
- { 3, 0, 0, 0, 7, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 85 },
- { 3, 0, 0, 0, 8, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 85 },
- { 3, 0, 0, 0, 9, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 85 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 24 },
- { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 24 },
- { 17, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 24 },
- { 3, 0, 0, 0, 0, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 2, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 3, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 4, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 5, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 6, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 7, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 8, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 3, 0, 0, 0, 9, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 24 },
- { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 77 },
- { 0, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 77 },
- { 1, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 77 },
- { 3, 0, 0, 0, 0, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 77 },
- { 3, 0, 0, 0, 1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 77 },
- { 3, 0, 0, 0, 2, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 77 },
- { 3, 0, 0, 0, 3, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 77 },
- { 3, 0, 0, 0, 4, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 77 },
- { 3, 0, 0, 0, 5, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 77 },
- { 3, 0, 0, 0, 6, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 77 },
- { 3, 0, 0, 0, 7, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 77 },
- { 3, 0, 0, 0, 8, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 77 },
- { 3, 0, 0, 0, 9, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 77 },
- { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 77 },
- { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 77 },
- { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 24 },
- { 17, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 24 },
- { 29, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 0, 1, 24 },
- { 1, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 4, 33, 4, 1, 24 },
- { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 79 },
- { 0, 17, 230, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 79 },
- { 0, 17, 220, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 79 },
- { 17, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 79 },
- { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 0, 1, 79 },
- { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 86 },
- { 1, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 86 },
- { 0, 17, 0, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 86 },
- { 25, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 86 },
- { 17, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 86 },
- { 0, 17, 9, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 86 },
- { 18, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 27 },
- { 15, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, -928}, {0, -928}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 28, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 0, 1, 2 },
- { 17, 0, 0, 0, -1, 0, 16, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 4 },
- { 15, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 17, 0, 0, 0, -1, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 28, 10, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 255}, {1, 255}, {1, 255} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 257}, {1, 257}, {1, 257} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 259}, {1, 259}, {1, 259} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 261}, {1, 261}, {1, 261} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 263}, {1, 263}, {1, 263} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 265}, {1, 265}, {1, 265} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 267}, {1, 267}, {1, 267} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 269}, {1, 269}, {1, 269} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 271}, {1, 271}, {1, 271} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 273}, {1, 273}, {1, 273} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 275}, {1, 275}, {1, 275} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 277}, {1, 277}, {1, 277} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 279}, {1, 279}, {1, 279} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 281}, {1, 281}, {1, 281} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 283}, {1, 283}, {1, 283} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 285}, {1, 285}, {1, 285} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 287}, {1, 287}, {1, 287} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 289}, {1, 289}, {1, 289} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 291}, {1, 291}, {1, 291} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 293}, {1, 293}, {1, 293} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 295}, {1, 295}, {1, 295} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 297}, {1, 297}, {1, 297} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 299}, {1, 299}, {1, 299} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 301}, {1, 301}, {1, 301} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 303}, {1, 303}, {1, 303} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 305}, {1, 305}, {1, 305} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 307}, {1, 307}, {1, 307} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 309}, {1, 309}, {1, 309} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 311}, {1, 311}, {1, 311} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 313}, {1, 313}, {1, 313} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 315}, {1, 315}, {1, 315} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 317}, {1, 317}, {1, 317} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 319}, {1, 319}, {1, 319} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 321}, {1, 321}, {1, 321} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 323}, {1, 323}, {1, 323} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 325}, {1, 325}, {1, 325} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 327}, {1, 327}, {1, 327} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 329}, {1, 329}, {1, 329} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 331}, {1, 331}, {1, 331} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 333}, {1, 333}, {1, 333} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 335}, {1, 335}, {1, 335} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 337}, {1, 337}, {1, 337} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 339}, {1, 339}, {1, 339} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 341}, {1, 341}, {1, 341} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 343}, {1, 343}, {1, 343} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 345}, {1, 345}, {1, 345} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 347}, {1, 347}, {1, 347} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 349}, {1, 349}, {1, 349} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 351}, {1, 351}, {1, 351} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 353}, {1, 353}, {1, 353} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 355}, {1, 355}, {1, 355} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 357}, {1, 357}, {1, 357} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 359}, {1, 359}, {1, 359} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 361}, {1, 361}, {1, 361} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 363}, {1, 363}, {1, 363} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 365}, {1, 365}, {1, 365} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 367}, {1, 367}, {1, 367} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 369}, {1, 369}, {1, 369} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 371}, {1, 371}, {1, 371} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 373}, {1, 373}, {1, 373} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 375}, {1, 375}, {1, 375} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 377}, {1, 377}, {1, 377} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 379}, {1, 379}, {1, 379} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 381}, {1, 381}, {1, 381} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 383}, {1, 383}, {1, 383} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 385}, {1, 385}, {1, 385} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 387}, {1, 387}, {1, 387} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 389}, {1, 389}, {1, 389} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 391}, {1, 391}, {1, 391} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 393}, {1, 393}, {1, 393} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 395}, {1, 395}, {1, 395} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 397}, {1, 397}, {1, 397} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 399}, {1, 399}, {1, 399} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 401}, {1, 401}, {1, 401} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 403}, {1, 403}, {1, 403} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 405}, {1, 405}, {1, 405} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 407}, {1, 407}, {1, 407} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 409}, {1, 409}, {1, 409} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 411}, {1, 411}, {1, 411} }, 0, 10, 12, 6, 3, 28 },
- { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 413}, {1, 413}, {1, 413} }, 0, 10, 12, 6, 3, 28 },
- { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 86 },
- { 1, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 86 },
- { 0, 17, 0, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 86 },
- { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 86 },
- { 0, 17, 9, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 86 },
- { 3, 0, 0, 0, 0, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 86 },
- { 3, 0, 0, 0, 1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 86 },
- { 3, 0, 0, 0, 2, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 86 },
- { 3, 0, 0, 0, 3, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 86 },
- { 3, 0, 0, 0, 4, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 86 },
- { 3, 0, 0, 0, 5, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 86 },
- { 3, 0, 0, 0, 6, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 86 },
- { 3, 0, 0, 0, 7, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 86 },
- { 3, 0, 0, 0, 8, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 86 },
- { 3, 0, 0, 0, 9, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 86 },
- { 18, 0, 0, 0, -1, 0, 2, 5, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 12, 10, 23, 8, 1, 26 },
- { 18, 0, 0, 0, -1, 0, 2, 5, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 13, 10, 24, 8, 1, 26 },
- { 11, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 34, 0, 0, 0 },
- { 12, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 0 },
- { 18, 0, 0, 0, -1, 0, 1, 5, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 3, 37 },
- { 18, 0, 0, 0, -1, 0, 13, 5, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 3, 37 },
- { 18, 0, 0, 0, -1, 0, 6, 5, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 3, 37 },
- { 18, 0, 0, 0, -1, 0, 11, 5, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 3, 37 },
- { 13, 0, 0, 0, -1, 0, 0, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 0 },
- { 18, 0, 0, 0, -1, 0, 8, 5, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 3, 37 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 427}, {1, 424}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 433}, {1, 430}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 439}, {1, 436}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 446}, {1, 442}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 454}, {1, 450}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 461}, {1, 458}, {0, 0} }, 0, 10, 12, 6, 3, 3 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 473}, {1, 470}, {0, 0} }, 0, 10, 12, 6, 3, 6 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 479}, {1, 476}, {0, 0} }, 0, 10, 12, 6, 3, 6 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 485}, {1, 482}, {0, 0} }, 0, 10, 12, 6, 3, 6 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 491}, {1, 488}, {0, 0} }, 0, 10, 12, 6, 3, 6 },
- { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 497}, {1, 494}, {0, 0} }, 0, 10, 12, 6, 3, 6 },
- { 18, 1, 0, 0, -1, 0, 4, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 9, 13, 8, 3, 7 },
- { 0, 17, 26, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 7 },
- { 18, 1, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 9, 13, 8, 3, 7 },
- { 18, 1, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 9, 13, 8, 3, 7 },
- { 26, 3, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 7 },
- { 18, 13, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 3, 8 },
- { 28, 13, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
- { 18, 13, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 0, 8 },
+ { 0, 17, 218, 5, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 228, 5, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 232, 5, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 222, 5, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 1, 0, 224, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 26 },
+ { 20, 10, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 17, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 16, 8, 1, 2 },
+ { 17, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 23, 8, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 3, 2 },
+ { 4, 0, 0, 0, -1, 0, 4, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 3, 37 },
+ { 17, 0, 0, 0, -1, 0, 6, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 7, 8, 1, 37 },
+ { 18, 0, 0, 0, -1, 0, 6, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 7, 8, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 6, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 4, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 2 },
+ { 18, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 7, 8, 1, 34 },
+ { 18, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 34 },
+ { 18, 0, 0, 0, -1, 0, 1, 5, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 34 },
+ { 18, 0, 0, 0, -1, 0, 6, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 7, 8, 1, 34 },
+ { 0, 17, 8, 5, -1, 0, 1, 5, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 28, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 7, 0, 0, 2 },
+ { 17, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 7, 8, 1, 34 },
+ { 17, 0, 0, 0, -1, 0, 1, 5, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 7, 8, 1, 34 },
+ { 18, 0, 0, 0, -1, 0, 6, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 3, 34 },
+ { 20, 10, 0, 0, -1, 0, 6, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 7, 0, 1, 2 },
+ { 18, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 7, 8, 1, 35 },
+ { 18, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 16, 8, 1, 35 },
+ { 18, 0, 0, 0, -1, 0, 1, 5, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 16, 8, 1, 35 },
+ { 25, 10, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 7, 0, 1, 2 },
+ { 17, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 7, 8, 1, 2 },
+ { 17, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 7, 8, 1, 35 },
+ { 17, 0, 0, 0, -1, 0, 1, 5, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 7, 8, 1, 35 },
+ { 18, 0, 0, 0, -1, 0, 6, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 16, 8, 3, 35 },
+ { 18, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 16, 8, 1, 36 },
+ { 18, 0, 0, 0, -1, 0, 10, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 16, 8, 1, 36 },
+ { 18, 0, 0, 0, -1, 0, 19, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 16, 8, 1, 36 },
+ { 18, 0, 0, 0, -1, 0, 20, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 16, 8, 1, 36 },
+ { 18, 0, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 16, 8, 3, 26 },
+ { 18, 0, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 16, 8, 0, 26 },
+ { 29, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 2 },
+ { 5, 0, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 3, 2 },
+ { 29, 0, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 3, 2 },
+ { 18, 0, 0, 0, -1, 0, 4, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 16, 8, 1, 36 },
+ { 18, 0, 0, 0, -1, 0, 12, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 16, 8, 1, 36 },
+ { 18, 0, 0, 0, -1, 0, 23, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 16, 8, 1, 36 },
+ { 29, 10, 0, 0, -1, 0, 8, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 10, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 2 },
+ { 18, 0, 0, 0, -1, 0, 6, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 7, 8, 1, 35 },
+ { 29, 0, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 26 },
+ { 29, 10, 0, 0, -1, 0, 7, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 26 },
+ { 5, 0, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 2 },
+ { 29, 0, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 2 },
+ { 29, 0, 0, 0, -1, 0, 11, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 3, 2 },
+ { 5, 0, 0, 0, -1, 0, 11, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 7, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 3, 2 },
+ { 5, 10, 0, 0, -1, 0, 6, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 3, 2 },
+ { 29, 0, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 3, 26 },
+ { 29, 10, 0, 0, -1, 0, 7, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 3, 26 },
+ { 29, 10, 0, 0, -1, 0, 8, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 3, 26 },
+ { 29, 0, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 3, 2 },
+ { 29, 0, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 16, 0, 3, 35 },
+ { 29, 0, 0, 0, -1, 0, 22, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 3, 2 },
+ { 18, 0, 0, 0, -1, 0, 4, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 37 },
+ { 18, 0, 0, 0, -1, 0, 23, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 37 },
+ { 18, 0, 0, 0, -1, 0, 1, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 37 },
+ { 18, 0, 0, 0, -1, 0, 8, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 37 },
+ { 18, 0, 0, 0, -1, 0, 10, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 37 },
+ { 18, 0, 0, 0, -1, 0, 11, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 37 },
+ { 18, 0, 0, 0, -1, 0, 13, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 37 },
+ { 18, 0, 0, 0, -1, 0, 17, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 37 },
+ { 18, 0, 0, 0, -1, 0, 19, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 37 },
+ { 18, 0, 0, 0, -1, 0, 20, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 37 },
+ { 18, 0, 0, 0, -1, 0, 24, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 37 },
+ { 18, 0, 0, 0, -1, 0, 4, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 16, 8, 1, 38 },
+ { 17, 0, 0, 0, -1, 0, 4, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 7, 8, 1, 38 },
+ { 29, 10, 0, 0, -1, 0, 4, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 38 },
+ { 29, 10, 0, 0, -1, 0, 6, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 38 },
+ { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 83 },
+ { 17, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 83 },
+ { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 83 },
+ { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 83 },
+ { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 70 },
+ { 17, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 70 },
+ { 25, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 70 },
+ { 25, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 12, 1, 70 },
+ { 25, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 70 },
+ { 3, 0, 0, 0, 0, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 70 },
+ { 3, 0, 0, 0, 1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 70 },
+ { 3, 0, 0, 0, 2, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 70 },
+ { 3, 0, 0, 0, 3, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 70 },
+ { 3, 0, 0, 0, 4, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 70 },
+ { 3, 0, 0, 0, 5, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 70 },
+ { 3, 0, 0, 0, 6, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 70 },
+ { 3, 0, 0, 0, 7, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 70 },
+ { 3, 0, 0, 0, 8, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 70 },
+ { 3, 0, 0, 0, 9, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 70 },
+ { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 5 },
+ { 2, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 5 },
+ { 25, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 5 },
+ { 0, 17, 230, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 5 },
+ { 17, 10, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 5 },
+ { 17, 0, 0, 0, -1, 0, 16, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 5 },
+ { 0, 17, 230, 5, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 5 },
+ { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 84 },
+ { 4, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 84 },
+ { 0, 17, 230, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 84 },
+ { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 84 },
+ { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 84 },
+ { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 84 },
+ { 28, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 28, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 0, 1, 2 },
+ { 17, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 2 },
+ { 28, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 0, 1, 2 },
+ { 14, 0, 0, 0, -1, 0, 10, 3, 0, { {1, 231}, {0, 0}, {0, 0}, {1, 231} }, 0, 10, 14, 7, 3, 3 },
+ { 28, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 0, 1, 2 },
+ { 14, 0, 0, 0, -1, 0, 12, 3, 0, { {1, 233}, {0, 0}, {0, 0}, {1, 233} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 48}, {0, 48}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 13, 3, 0, { {1, 235}, {0, 0}, {0, 0}, {1, 235} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 16, 3, 0, { {1, 237}, {0, 0}, {0, 0}, {1, 237} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 16, 3, 0, { {1, 239}, {0, 0}, {0, 0}, {1, 239} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 16, 3, 0, { {1, 241}, {0, 0}, {0, 0}, {1, 241} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 18, 3, 0, { {1, 243}, {0, 0}, {0, 0}, {1, 243} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 16, 3, 0, { {1, 245}, {0, 0}, {0, 0}, {1, 245} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 16, 3, 0, { {1, 247}, {0, 0}, {0, 0}, {1, 247} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 17, 3, 0, { {1, 249}, {0, 0}, {0, 0}, {1, 249} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 928}, {0, 0}, {0, 0}, {0, 928} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 14, 0, 0, 0, -1, 0, 21, 3, 0, { {0, -48}, {0, 0}, {0, 0}, {0, -48} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 21, 3, 0, { {1, 251}, {0, 0}, {0, 0}, {1, 251} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 21, 3, 0, { {1, 253}, {0, 0}, {0, 0}, {1, 253} }, 0, 10, 14, 7, 3, 3 },
+ { 14, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 1}, {0, 0}, {0, 0}, {0, 1} }, 0, 10, 14, 7, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, -1}, {0, -1}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 17, 0, 0, 0, -1, 0, 24, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 3 },
+ { 17, 0, 0, 0, -1, 0, 13, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 3 },
+ { 18, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 59 },
+ { 0, 17, 0, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 59 },
+ { 0, 17, 9, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 59 },
+ { 1, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 59 },
+ { 29, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 59 },
+ { 0, 17, 9, 5, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 59 },
+ { 5, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 4, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 18, 0, 0, 2, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 65 },
+ { 18, 0, 0, 4, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 65 },
+ { 18, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 65 },
+ { 25, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 20, 0, 1, 65 },
+ { 25, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 12, 1, 65 },
+ { 1, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 71 },
+ { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 71 },
+ { 0, 17, 9, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 71 },
+ { 0, 17, 0, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 71 },
+ { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 71 },
+ { 3, 0, 0, 0, 0, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 71 },
+ { 3, 0, 0, 0, 1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 71 },
+ { 3, 0, 0, 0, 2, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 71 },
+ { 3, 0, 0, 0, 3, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 71 },
+ { 3, 0, 0, 0, 4, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 71 },
+ { 3, 0, 0, 0, 5, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 71 },
+ { 3, 0, 0, 0, 6, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 71 },
+ { 3, 0, 0, 0, 7, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 71 },
+ { 3, 0, 0, 0, 8, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 71 },
+ { 3, 0, 0, 0, 9, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 71 },
+ { 0, 17, 230, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 11 },
+ { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 11 },
+ { 25, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 20, 0, 1, 11 },
+ { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 11 },
+ { 18, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 11 },
+ { 0, 17, 0, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 11 },
+ { 3, 0, 0, 0, 0, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 72 },
+ { 3, 0, 0, 0, 1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 72 },
+ { 3, 0, 0, 0, 2, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 72 },
+ { 3, 0, 0, 0, 3, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 72 },
+ { 3, 0, 0, 0, 4, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 72 },
+ { 3, 0, 0, 0, 5, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 72 },
+ { 3, 0, 0, 0, 6, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 72 },
+ { 3, 0, 0, 0, 7, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 72 },
+ { 3, 0, 0, 0, 8, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 72 },
+ { 3, 0, 0, 0, 9, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 72 },
+ { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 72 },
+ { 0, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 72 },
+ { 0, 17, 220, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 72 },
+ { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 2 },
+ { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 72 },
+ { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 73 },
+ { 0, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 73 },
+ { 1, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 73 },
+ { 1, 0, 9, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 73 },
+ { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 73 },
+ { 0, 17, 0, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 85 },
+ { 1, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 85 },
+ { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 85 },
+ { 0, 17, 7, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 85 },
+ { 1, 0, 9, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 85 },
+ { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 85 },
+ { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 85 },
+ { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 85 },
+ { 17, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 19, 8, 1, 2 },
+ { 3, 0, 0, 0, 0, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 85 },
+ { 3, 0, 0, 0, 1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 85 },
+ { 3, 0, 0, 0, 2, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 85 },
+ { 3, 0, 0, 0, 3, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 85 },
+ { 3, 0, 0, 0, 4, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 85 },
+ { 3, 0, 0, 0, 5, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 85 },
+ { 3, 0, 0, 0, 6, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 85 },
+ { 3, 0, 0, 0, 7, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 85 },
+ { 3, 0, 0, 0, 8, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 85 },
+ { 3, 0, 0, 0, 9, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 85 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 24 },
+ { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 24 },
+ { 17, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 24 },
+ { 3, 0, 0, 0, 0, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 2, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 3, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 4, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 5, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 6, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 7, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 8, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 3, 0, 0, 0, 9, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 24 },
+ { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 77 },
+ { 0, 17, 0, 5, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 77 },
+ { 1, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 77 },
+ { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 19, 8, 1, 77 },
+ { 3, 0, 0, 0, 0, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 77 },
+ { 3, 0, 0, 0, 1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 77 },
+ { 3, 0, 0, 0, 2, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 77 },
+ { 3, 0, 0, 0, 3, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 77 },
+ { 3, 0, 0, 0, 4, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 77 },
+ { 3, 0, 0, 0, 5, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 77 },
+ { 3, 0, 0, 0, 6, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 77 },
+ { 3, 0, 0, 0, 7, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 77 },
+ { 3, 0, 0, 0, 8, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 77 },
+ { 3, 0, 0, 0, 9, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 77 },
+ { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 77 },
+ { 25, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 77 },
+ { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 24 },
+ { 17, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 24 },
+ { 29, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 0, 1, 24 },
+ { 1, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 4, 35, 4, 1, 24 },
+ { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 79 },
+ { 0, 17, 230, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 79 },
+ { 0, 17, 220, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 79 },
+ { 17, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 79 },
+ { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 0, 1, 79 },
+ { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 86 },
+ { 1, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 86 },
+ { 0, 17, 0, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 86 },
+ { 25, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 86 },
+ { 17, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 86 },
+ { 0, 17, 9, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 86 },
+ { 18, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 27 },
+ { 15, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, -928}, {0, -928}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 28, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 0, 1, 2 },
+ { 17, 0, 0, 0, -1, 0, 16, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 4 },
+ { 15, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 17, 0, 0, 0, -1, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 28, 10, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 255}, {1, 255}, {1, 255} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 257}, {1, 257}, {1, 257} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 259}, {1, 259}, {1, 259} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 261}, {1, 261}, {1, 261} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 263}, {1, 263}, {1, 263} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 265}, {1, 265}, {1, 265} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 267}, {1, 267}, {1, 267} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 269}, {1, 269}, {1, 269} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 271}, {1, 271}, {1, 271} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 273}, {1, 273}, {1, 273} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 275}, {1, 275}, {1, 275} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 277}, {1, 277}, {1, 277} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 279}, {1, 279}, {1, 279} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 281}, {1, 281}, {1, 281} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 283}, {1, 283}, {1, 283} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 285}, {1, 285}, {1, 285} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 287}, {1, 287}, {1, 287} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 289}, {1, 289}, {1, 289} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 291}, {1, 291}, {1, 291} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 293}, {1, 293}, {1, 293} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 295}, {1, 295}, {1, 295} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 297}, {1, 297}, {1, 297} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 299}, {1, 299}, {1, 299} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 301}, {1, 301}, {1, 301} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 303}, {1, 303}, {1, 303} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 305}, {1, 305}, {1, 305} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 307}, {1, 307}, {1, 307} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 309}, {1, 309}, {1, 309} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 311}, {1, 311}, {1, 311} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 313}, {1, 313}, {1, 313} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 315}, {1, 315}, {1, 315} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 317}, {1, 317}, {1, 317} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 319}, {1, 319}, {1, 319} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 321}, {1, 321}, {1, 321} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 323}, {1, 323}, {1, 323} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 325}, {1, 325}, {1, 325} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 327}, {1, 327}, {1, 327} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 329}, {1, 329}, {1, 329} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 331}, {1, 331}, {1, 331} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 333}, {1, 333}, {1, 333} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 335}, {1, 335}, {1, 335} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 337}, {1, 337}, {1, 337} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 339}, {1, 339}, {1, 339} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 341}, {1, 341}, {1, 341} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 343}, {1, 343}, {1, 343} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 345}, {1, 345}, {1, 345} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 347}, {1, 347}, {1, 347} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 349}, {1, 349}, {1, 349} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 351}, {1, 351}, {1, 351} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 353}, {1, 353}, {1, 353} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 355}, {1, 355}, {1, 355} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 357}, {1, 357}, {1, 357} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 359}, {1, 359}, {1, 359} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 361}, {1, 361}, {1, 361} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 363}, {1, 363}, {1, 363} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 365}, {1, 365}, {1, 365} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 367}, {1, 367}, {1, 367} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 369}, {1, 369}, {1, 369} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 371}, {1, 371}, {1, 371} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 373}, {1, 373}, {1, 373} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 375}, {1, 375}, {1, 375} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 377}, {1, 377}, {1, 377} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 379}, {1, 379}, {1, 379} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 381}, {1, 381}, {1, 381} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 383}, {1, 383}, {1, 383} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 385}, {1, 385}, {1, 385} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 387}, {1, 387}, {1, 387} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 389}, {1, 389}, {1, 389} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 391}, {1, 391}, {1, 391} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 393}, {1, 393}, {1, 393} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 395}, {1, 395}, {1, 395} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 397}, {1, 397}, {1, 397} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 399}, {1, 399}, {1, 399} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 401}, {1, 401}, {1, 401} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 403}, {1, 403}, {1, 403} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 405}, {1, 405}, {1, 405} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 407}, {1, 407}, {1, 407} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 409}, {1, 409}, {1, 409} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 411}, {1, 411}, {1, 411} }, 0, 10, 14, 6, 3, 28 },
+ { 15, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {1, 413}, {1, 413}, {1, 413} }, 0, 10, 14, 6, 3, 28 },
+ { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 86 },
+ { 1, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 86 },
+ { 0, 17, 0, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 86 },
+ { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 86 },
+ { 0, 17, 9, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 86 },
+ { 3, 0, 0, 0, 0, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 86 },
+ { 3, 0, 0, 0, 1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 86 },
+ { 3, 0, 0, 0, 2, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 86 },
+ { 3, 0, 0, 0, 3, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 86 },
+ { 3, 0, 0, 0, 4, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 86 },
+ { 3, 0, 0, 0, 5, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 86 },
+ { 3, 0, 0, 0, 6, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 86 },
+ { 3, 0, 0, 0, 7, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 86 },
+ { 3, 0, 0, 0, 8, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 86 },
+ { 3, 0, 0, 0, 9, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 86 },
+ { 18, 0, 0, 0, -1, 0, 2, 5, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 12, 10, 25, 8, 1, 26 },
+ { 18, 0, 0, 0, -1, 0, 2, 5, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 13, 10, 26, 8, 1, 26 },
+ { 11, 0, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 36, 0, 0, 0 },
+ { 12, 0, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 0 },
+ { 18, 0, 0, 0, -1, 0, 1, 5, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 3, 37 },
+ { 18, 0, 0, 0, -1, 0, 13, 5, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 3, 37 },
+ { 18, 0, 0, 0, -1, 0, 6, 5, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 3, 37 },
+ { 18, 0, 0, 0, -1, 0, 11, 5, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 3, 37 },
+ { 13, 0, 0, 0, -1, 0, 0, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 0 },
+ { 18, 0, 0, 0, -1, 0, 8, 5, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 3, 37 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 427}, {1, 424}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 433}, {1, 430}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 439}, {1, 436}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 446}, {1, 442}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 454}, {1, 450}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 461}, {1, 458}, {0, 1} }, 0, 10, 14, 6, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 461}, {1, 458}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 473}, {1, 470}, {0, 0} }, 0, 10, 14, 6, 3, 6 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 479}, {1, 476}, {0, 0} }, 0, 10, 14, 6, 3, 6 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 485}, {1, 482}, {0, 0} }, 0, 10, 14, 6, 3, 6 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 491}, {1, 488}, {0, 0} }, 0, 10, 14, 6, 3, 6 },
+ { 15, 0, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {1, 497}, {1, 494}, {0, 0} }, 0, 10, 14, 6, 3, 6 },
+ { 18, 1, 0, 0, -1, 0, 4, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 9, 15, 8, 3, 7 },
+ { 0, 17, 26, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 7 },
+ { 18, 1, 0, 0, -1, 0, 1, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 9, 15, 8, 3, 7 },
+ { 18, 1, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 9, 15, 8, 3, 7 },
+ { 26, 3, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 7 },
+ { 18, 13, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 3, 8 },
+ { 28, 13, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 8 },
+ { 18, 13, 0, 0, -1, 0, 1, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 0, 8 },
{ 22, 10, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
- { 13, 18, 0, 0, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 0 },
- { 27, 13, 0, 0, -1, 0, 6, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 3, 8 },
- { 0, 17, 0, 5, -1, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 2, 1 },
- { 25, 10, 0, 0, -1, 0, 8, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 8, 11, 0, 2 },
+ { 29, 10, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 8 },
+ { 13, 18, 0, 0, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 0 },
+ { 27, 13, 0, 0, -1, 0, 6, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 8 },
+ { 0, 17, 0, 5, -1, 0, 6, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 2, 1 },
+ { 25, 10, 0, 0, -1, 0, 8, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 10, 11, 0, 2 },
{ 25, 10, 0, 0, -1, 0, 8, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 11, 3, 2 },
{ 25, 10, 0, 0, -1, 0, 8, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 0, 0, 2 },
- { 25, 10, 0, 0, -1, 0, 8, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 14, 8, 11, 0, 2 },
- { 25, 10, 0, 0, -1, 0, 8, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 8, 0, 0, 2 },
- { 25, 10, 0, 0, -1, 0, 8, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 0, 0, 2 },
+ { 25, 10, 0, 0, -1, 0, 8, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 14, 10, 11, 0, 2 },
+ { 25, 10, 0, 0, -1, 0, 8, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 10, 0, 0, 2 },
+ { 25, 10, 0, 0, -1, 0, 8, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 0, 0, 2 },
{ 21, 10, 0, 0, -1, 0, 8, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 3, 2 },
{ 22, 10, 0, 0, -1, 0, 8, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 3, 2 },
- { 25, 10, 0, 0, -1, 0, 8, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 15, 0, 0, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
- { 20, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 11, 3, 2 },
- { 19, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 17, 14, 0, 3, 2 },
+ { 25, 10, 0, 0, -1, 0, 8, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 0, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 2 },
+ { 20, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 11, 3, 2 },
+ { 19, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 17, 16, 0, 3, 2 },
{ 21, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 0, 2 },
{ 22, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 0, 2 },
{ 21, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 3, 2 },
{ 22, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 3, 2 },
- { 25, 10, 0, 0, -1, 0, 6, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 6, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 2 },
{ 21, 10, 0, 0, -1, 0, 7, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 0, 2 },
{ 22, 10, 0, 0, -1, 0, 7, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 0, 2 },
{ 25, 6, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 1, 11, 0, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 11, 3, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 11, 3, 2 },
{ 25, 6, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 13, 1, 10, 0, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 5, 0, 0, 2 },
- { 25, 6, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 14, 5, 11, 0, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 12, 0, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 7, 0, 0, 2 },
+ { 25, 6, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 14, 7, 11, 0, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 12, 0, 2 },
{ 21, 10, 0, 0, -1, 1, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 0, 2 },
{ 22, 10, 0, 0, -1, -1, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 0, 2 },
{ 21, 10, 0, 0, -1, 1, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 3, 2 },
{ 22, 10, 0, 0, -1, -1, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 3, 2 },
- { 25, 4, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
- { 26, 3, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
- { 20, 3, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 11, 3, 2 },
- { 26, 10, 0, 0, -1, 1, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
- { 26, 10, 0, 0, -1, -1, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
- { 26, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
- { 27, 4, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 0, 2 },
- { 25, 4, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 0, 2 },
- { 18, 13, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 8 },
- { 10, 18, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 22, 4, 2, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 12, 0, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
- { 25, 4, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
- { 27, 4, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 0, 2 },
- { 25, 4, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 0, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 13, 14, 0, 0, 2 },
+ { 25, 4, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 2 },
+ { 26, 3, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 2 },
+ { 20, 3, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 11, 3, 2 },
+ { 26, 10, 0, 0, -1, 1, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 2 },
+ { 26, 10, 0, 0, -1, -1, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 2 },
+ { 26, 10, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 2 },
+ { 27, 4, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 0, 2 },
+ { 25, 4, 0, 0, -1, 0, 1, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
+ { 18, 13, 0, 0, -1, 0, 6, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 8 },
+ { 10, 18, 0, 5, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 24, 4, 2, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 12, 0, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 2 },
+ { 25, 4, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 2 },
+ { 27, 4, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 0, 2 },
+ { 25, 4, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 13, 16, 0, 0, 2 },
{ 21, 10, 0, 0, -1, 1, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 0, 2 },
{ 22, 10, 0, 0, -1, -1, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 0, 2 },
- { 26, 3, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 26, 3, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 2 },
{ 25, 6, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 1, 11, 0, 2 },
- { 20, 3, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 11, 3, 2 },
+ { 20, 3, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 11, 3, 2 },
{ 25, 6, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 13, 1, 10, 3, 2 },
- { 25, 6, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
- { 3, 2, 0, 0, 0, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 3, 2 },
- { 3, 2, 0, 0, 1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 3, 2 },
- { 3, 2, 0, 0, 2, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 3, 2 },
- { 3, 2, 0, 0, 3, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 3, 2 },
- { 3, 2, 0, 0, 4, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 3, 2 },
- { 3, 2, 0, 0, 5, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 3, 2 },
- { 3, 2, 0, 0, 6, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 3, 2 },
- { 3, 2, 0, 0, 7, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 3, 2 },
- { 3, 2, 0, 0, 8, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 3, 2 },
- { 3, 2, 0, 0, 9, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 3, 2 },
- { 25, 6, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 14, 5, 11, 0, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 5, 0, 0, 2 },
- { 26, 10, 0, 0, -1, 2, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
- { 26, 10, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
- { 26, 10, 0, 0, -1, -2, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
- { 14, 0, 0, 0, -1, 0, 1, 1, 80, { {0, 32}, {0, 0}, {0, 0}, {0, 32} }, 0, 10, 14, 7, 3, 3 },
+ { 25, 6, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 2 },
+ { 3, 2, 0, 0, 0, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 3, 2 },
+ { 3, 2, 0, 0, 1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 3, 2 },
+ { 3, 2, 0, 0, 2, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 3, 2 },
+ { 3, 2, 0, 0, 3, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 3, 2 },
+ { 3, 2, 0, 0, 4, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 3, 2 },
+ { 3, 2, 0, 0, 5, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 3, 2 },
+ { 3, 2, 0, 0, 6, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 3, 2 },
+ { 3, 2, 0, 0, 7, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 3, 2 },
+ { 3, 2, 0, 0, 8, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 3, 2 },
+ { 3, 2, 0, 0, 9, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 3, 2 },
+ { 25, 6, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 14, 7, 11, 0, 2 },
+ { 25, 10, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 15, 7, 0, 0, 2 },
+ { 26, 10, 0, 0, -1, 2, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 2 },
+ { 26, 10, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 2 },
+ { 26, 10, 0, 0, -1, -2, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 2 },
+ { 14, 0, 0, 0, -1, 0, 1, 1, 80, { {0, 32}, {0, 0}, {0, 0}, {0, 32} }, 0, 10, 16, 7, 3, 3 },
{ 21, 10, 0, 0, -1, 2, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 0, 2 },
{ 22, 10, 0, 0, -1, -2, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 0, 2 },
- { 28, 10, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
- { 19, 10, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 17, 14, 0, 3, 2 },
- { 15, 0, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 14, 6, 3, 3 },
+ { 28, 10, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 0, 2 },
+ { 19, 10, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 17, 16, 0, 3, 2 },
+ { 15, 0, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 16, 6, 3, 3 },
{ 21, 10, 0, 0, -1, 1, 6, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 3, 2 },
{ 22, 10, 0, 0, -1, -1, 6, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 3, 2 },
{ 25, 10, 0, 0, -1, 0, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 12, 3, 2 },
{ 21, 10, 0, 0, -1, 1, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 13, 3, 2 },
{ 22, 10, 0, 0, -1, -1, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 13, 3, 2 },
{ 25, 10, 0, 0, -1, 0, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 1, 11, 3, 2 },
- { 25, 10, 0, 0, -1, 0, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 5, 0, 3, 2 },
- { 18, 0, 0, 0, -1, 0, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 14, 8, 3, 35 },
- { 18, 0, 0, 0, -1, 0, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 5, 8, 3, 35 },
- { 17, 0, 0, 0, -1, 0, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 5, 8, 3, 2 },
- { 17, 0, 0, 0, -1, 0, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 5, 4, 3, 2 },
- { 18, 0, 0, 0, -1, 0, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 0, 26 },
- { 18, 0, 0, 0, -1, 0, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 3, 26 },
- { 27, 4, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 3, 2 },
- { 27, 4, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 3, 2 },
- { 26, 10, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 26, 10, 0, 0, -1, 0, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 10, 10, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 21, 4, 0, 2 },
- { 29, 10, 0, 0, -1, 0, 3, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 29, 0, 0, 2 },
- { 29, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 13, 18, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 0 },
- { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 49 },
- { 25, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 2 },
- { 25, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 2 },
- { 5, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 4, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 4 },
- { 5, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 4 },
- { 29, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 4 },
- { 5, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 4 },
- { 29, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 4 },
- { 29, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 4 },
- { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 74 },
- { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 75 },
- { 5, 2, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 18, 0, 0, 0, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 39 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 39 },
- { 5, 0, 0, 0, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 39 },
- { 18, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 39 },
- { 18, 0, 0, 0, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 40 },
- { 4, 0, 0, 0, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 40 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 120 },
- { 0, 17, 230, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 120 },
- { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 50 },
- { 25, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 50 },
- { 18, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 60 },
- { 25, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 60 },
- { 4, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 60 },
- { 14, 0, 0, 0, -1, 0, 5, 3, 0, { {0, 40}, {0, 0}, {0, 0}, {0, 40} }, 0, 10, 12, 7, 3, 41 },
- { 14, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 40}, {0, 0}, {0, 0}, {0, 40} }, 0, 10, 12, 7, 3, 41 },
- { 15, 0, 0, 0, -1, 0, 5, 3, 0, { {0, 0}, {0, -40}, {0, -40}, {0, 0} }, 0, 10, 12, 6, 1, 41 },
- { 15, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, -40}, {0, -40}, {0, 0} }, 0, 10, 12, 6, 1, 41 },
- { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 51 },
- { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 52 },
- { 3, 0, 0, 0, 0, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 52 },
- { 3, 0, 0, 0, 1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 52 },
- { 3, 0, 0, 0, 2, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 52 },
- { 3, 0, 0, 0, 3, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 52 },
- { 3, 0, 0, 0, 4, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 52 },
- { 3, 0, 0, 0, 5, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 52 },
- { 3, 0, 0, 0, 6, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 52 },
- { 3, 0, 0, 0, 7, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 52 },
- { 3, 0, 0, 0, 8, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 52 },
- { 3, 0, 0, 0, 9, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 52 },
- { 14, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 40}, {0, 0}, {0, 0}, {0, 40} }, 0, 10, 12, 7, 3, 136 },
- { 15, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, -40}, {0, -40}, {0, 0} }, 0, 10, 12, 6, 1, 136 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 106 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 103 },
- { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 103 },
- { 14, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 39}, {0, 0}, {0, 0}, {0, 39} }, 0, 10, 12, 7, 3, 161 },
- { 15, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, -39}, {0, -39}, {0, 0} }, 0, 10, 12, 6, 1, 161 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 110 },
- { 17, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 17, 0, 0, 0, -1, 0, 24, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 3, 3 },
- { 18, 1, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 53 },
- { 18, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 87 },
- { 25, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 87 },
- { 5, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 87 },
- { 18, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 118 },
- { 29, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 118 },
- { 5, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 118 },
- { 18, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 117 },
- { 5, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 117 },
- { 18, 1, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 128 },
- { 5, 1, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 128 },
- { 18, 1, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 64 },
- { 5, 1, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 64 },
- { 5, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 64 },
- { 25, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 64 },
- { 18, 1, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 76 },
- { 25, 1, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 76 },
- { 18, 1, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 98 },
- { 18, 1, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 97 },
- { 5, 1, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 97 },
- { 18, 1, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 61 },
- { 0, 17, 0, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 61 },
- { 0, 17, 220, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 61 },
- { 0, 17, 230, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 61 },
- { 18, 1, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 61 },
- { 0, 17, 1, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 61 },
- { 0, 17, 9, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 61 },
- { 5, 1, 0, 0, 1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 61 },
- { 5, 1, 0, 0, 2, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 61 },
- { 5, 1, 0, 0, 3, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 61 },
- { 5, 1, 0, 0, 4, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 61 },
- { 5, 1, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 61 },
- { 5, 1, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 61 },
- { 25, 1, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 61 },
- { 25, 1, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 61 },
- { 25, 1, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 61 },
- { 18, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 88 },
- { 5, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 88 },
- { 25, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 88 },
- { 18, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 116 },
- { 5, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 116 },
- { 18, 1, 0, 2, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 112 },
- { 18, 1, 0, 3, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 112 },
- { 18, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 112 },
- { 29, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 112 },
- { 18, 1, 0, 4, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 112 },
- { 0, 17, 230, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 112 },
- { 0, 17, 220, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 112 },
- { 5, 1, 0, 2, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 112 },
- { 5, 1, 0, 3, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 112 },
+ { 25, 10, 0, 0, -1, 0, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 7, 0, 3, 2 },
+ { 18, 0, 0, 0, -1, 0, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 16, 8, 3, 35 },
+ { 18, 0, 0, 0, -1, 0, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 7, 8, 3, 35 },
+ { 17, 0, 0, 0, -1, 0, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 7, 8, 3, 2 },
+ { 17, 0, 0, 0, -1, 0, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 7, 4, 3, 2 },
+ { 18, 0, 0, 0, -1, 0, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 16, 8, 0, 26 },
+ { 18, 0, 0, 0, -1, 0, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 16, 8, 3, 26 },
+ { 27, 4, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
+ { 27, 4, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 3, 2 },
+ { 26, 10, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 3, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 1, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 3, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 26, 10, 0, 0, -1, 0, 1, 2, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 10, 10, 0, 5, -1, 0, 4, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 23, 4, 0, 2 },
+ { 29, 10, 0, 0, -1, 0, 3, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 31, 0, 0, 2 },
+ { 29, 10, 0, 0, -1, 0, 1, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 13, 18, 0, 0, -1, 0, 1, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 0 },
+ { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 49 },
+ { 25, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 2 },
+ { 25, 10, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 2 },
+ { 5, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 4, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 4 },
+ { 5, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 4 },
+ { 29, 10, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 4 },
+ { 5, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 4 },
+ { 29, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 4 },
+ { 29, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 4 },
+ { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 74 },
+ { 18, 0, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 75 },
+ { 5, 2, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 18, 0, 0, 0, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 39 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 39 },
+ { 5, 0, 0, 0, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 39 },
+ { 18, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 39 },
+ { 18, 0, 0, 0, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 40 },
+ { 4, 0, 0, 0, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 40 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 120 },
+ { 0, 17, 230, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 120 },
+ { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 50 },
+ { 25, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 50 },
+ { 18, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 60 },
+ { 25, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 60 },
+ { 4, 0, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 60 },
+ { 14, 0, 0, 0, -1, 0, 5, 3, 0, { {0, 40}, {0, 0}, {0, 0}, {0, 40} }, 0, 10, 14, 7, 3, 41 },
+ { 14, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 40}, {0, 0}, {0, 0}, {0, 40} }, 0, 10, 14, 7, 3, 41 },
+ { 15, 0, 0, 0, -1, 0, 5, 3, 0, { {0, 0}, {0, -40}, {0, -40}, {0, 0} }, 0, 10, 14, 6, 1, 41 },
+ { 15, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, -40}, {0, -40}, {0, 0} }, 0, 10, 14, 6, 1, 41 },
+ { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 51 },
+ { 18, 0, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 52 },
+ { 3, 0, 0, 0, 0, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 52 },
+ { 3, 0, 0, 0, 1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 52 },
+ { 3, 0, 0, 0, 2, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 52 },
+ { 3, 0, 0, 0, 3, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 52 },
+ { 3, 0, 0, 0, 4, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 52 },
+ { 3, 0, 0, 0, 5, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 52 },
+ { 3, 0, 0, 0, 6, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 52 },
+ { 3, 0, 0, 0, 7, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 52 },
+ { 3, 0, 0, 0, 8, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 52 },
+ { 3, 0, 0, 0, 9, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 52 },
+ { 14, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 40}, {0, 0}, {0, 0}, {0, 40} }, 0, 10, 14, 7, 3, 136 },
+ { 15, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, -40}, {0, -40}, {0, 0} }, 0, 10, 14, 6, 1, 136 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 106 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 103 },
+ { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 103 },
+ { 14, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 39}, {0, 0}, {0, 0}, {0, 39} }, 0, 10, 14, 7, 3, 161 },
+ { 15, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, -39}, {0, -39}, {0, 0} }, 0, 10, 14, 6, 1, 161 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 110 },
+ { 17, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 17, 0, 0, 0, -1, 0, 24, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 3, 3 },
+ { 18, 1, 0, 0, -1, 0, 7, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 53 },
+ { 18, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 87 },
+ { 25, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 87 },
+ { 5, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 87 },
+ { 18, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 118 },
+ { 29, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 118 },
+ { 5, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 118 },
+ { 18, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 117 },
+ { 5, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 117 },
+ { 18, 1, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 128 },
+ { 5, 1, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 128 },
+ { 18, 1, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 64 },
+ { 5, 1, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 64 },
+ { 5, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 64 },
+ { 25, 10, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 64 },
+ { 18, 1, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 76 },
+ { 25, 1, 0, 0, -1, 0, 10, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 76 },
+ { 18, 1, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 98 },
+ { 18, 1, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 97 },
+ { 5, 1, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 97 },
+ { 18, 1, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 61 },
+ { 0, 17, 0, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 61 },
+ { 0, 17, 220, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 61 },
+ { 0, 17, 230, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 61 },
+ { 18, 1, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 61 },
+ { 0, 17, 1, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 61 },
+ { 0, 17, 9, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 61 },
+ { 5, 1, 0, 0, 1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 61 },
+ { 5, 1, 0, 0, 2, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 61 },
+ { 5, 1, 0, 0, 3, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 61 },
+ { 5, 1, 0, 0, 4, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 61 },
+ { 5, 1, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 61 },
+ { 5, 1, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 61 },
+ { 25, 1, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 61 },
+ { 25, 1, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 61 },
+ { 25, 1, 0, 0, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 61 },
+ { 18, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 88 },
+ { 5, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 88 },
+ { 25, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 88 },
+ { 18, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 116 },
+ { 5, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 116 },
+ { 18, 1, 0, 2, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 112 },
+ { 18, 1, 0, 3, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 112 },
+ { 18, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 112 },
+ { 29, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 112 },
+ { 18, 1, 0, 4, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 112 },
+ { 0, 17, 230, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 112 },
+ { 0, 17, 220, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 112 },
+ { 5, 1, 0, 2, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 112 },
+ { 5, 1, 0, 3, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 112 },
+ { 25, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 112 },
{ 25, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 112 },
- { 25, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 15, 0, 1, 112 },
- { 18, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 80 },
- { 25, 10, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 80 },
- { 18, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 89 },
- { 5, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 89 },
- { 18, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 90 },
- { 5, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 90 },
- { 18, 1, 0, 2, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 121 },
- { 18, 1, 0, 3, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 121 },
- { 25, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 121 },
- { 5, 1, 0, 3, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 121 },
- { 5, 1, 0, 2, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 121 },
- { 5, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 121 },
- { 18, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 91 },
- { 14, 1, 0, 0, -1, 0, 17, 3, 0, { {0, 64}, {0, 0}, {0, 0}, {0, 64} }, 0, 10, 12, 7, 3, 130 },
- { 15, 1, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, -64}, {0, -64}, {0, 0} }, 0, 10, 12, 6, 1, 130 },
- { 5, 1, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 130 },
- { 18, 13, 0, 4, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 144 },
- { 18, 13, 0, 2, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 144 },
- { 18, 13, 0, 3, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 144 },
- { 0, 17, 230, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 144 },
- { 3, 5, 0, 0, 0, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 144 },
- { 3, 5, 0, 0, 1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 144 },
- { 3, 5, 0, 0, 2, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 144 },
- { 3, 5, 0, 0, 3, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 144 },
- { 3, 5, 0, 0, 4, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 144 },
- { 3, 5, 0, 0, 5, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 144 },
- { 3, 5, 0, 0, 6, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 144 },
- { 3, 5, 0, 0, 7, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 144 },
- { 3, 5, 0, 0, 8, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 144 },
- { 3, 5, 0, 0, 9, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 144 },
- { 5, 5, 0, 0, 1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
- { 5, 5, 0, 0, 2, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
- { 5, 5, 0, 0, 3, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
- { 5, 5, 0, 0, 4, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
- { 5, 5, 0, 0, 5, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
- { 5, 5, 0, 0, 6, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
- { 5, 5, 0, 0, 7, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
- { 5, 5, 0, 0, 8, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
- { 5, 5, 0, 0, 9, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
- { 5, 5, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
- { 18, 1, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 156 },
- { 0, 17, 230, 5, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 156 },
- { 20, 1, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 156 },
- { 0, 17, 220, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 8 },
- { 18, 1, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 147 },
- { 5, 1, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 147 },
- { 18, 13, 0, 2, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 148 },
- { 18, 13, 0, 3, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 148 },
- { 18, 13, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 148 },
- { 0, 17, 220, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 148 },
- { 0, 17, 230, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 148 },
- { 5, 13, 0, 2, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 148 },
- { 5, 13, 0, 3, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 148 },
- { 25, 13, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 12, 1, 148 },
- { 18, 1, 0, 2, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 158 },
- { 18, 1, 0, 3, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 158 },
- { 0, 17, 230, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 158 },
- { 0, 17, 220, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 158 },
- { 25, 1, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 12, 1, 158 },
- { 18, 1, 0, 2, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 153 },
- { 18, 1, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 153 },
- { 18, 1, 0, 3, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 153 },
- { 5, 1, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 153 },
- { 5, 1, 0, 3, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 153 },
- { 5, 1, 0, 2, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 153 },
- { 5, 1, 0, 4, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 153 },
- { 18, 1, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 149 },
- { 1, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 94 },
- { 0, 17, 0, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 94 },
- { 18, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 94 },
- { 0, 17, 9, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 94 },
- { 25, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 94 },
- { 25, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 94 },
- { 5, 10, 0, 0, 1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 94 },
- { 5, 10, 0, 0, 2, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 94 },
- { 5, 10, 0, 0, 3, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 94 },
- { 5, 10, 0, 0, 4, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 94 },
- { 5, 10, 0, 0, 5, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 94 },
- { 5, 10, 0, 0, 6, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 94 },
- { 5, 10, 0, 0, 7, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 94 },
- { 5, 10, 0, 0, 8, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 94 },
- { 5, 10, 0, 0, 9, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 94 },
- { 5, 10, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 94 },
- { 3, 0, 0, 0, 0, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 94 },
- { 3, 0, 0, 0, 1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 94 },
- { 3, 0, 0, 0, 2, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 94 },
- { 3, 0, 0, 0, 3, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 94 },
- { 3, 0, 0, 0, 4, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 94 },
- { 3, 0, 0, 0, 5, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 94 },
- { 3, 0, 0, 0, 6, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 94 },
- { 3, 0, 0, 0, 7, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 94 },
- { 3, 0, 0, 0, 8, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 94 },
- { 3, 0, 0, 0, 9, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 94 },
- { 0, 17, 9, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 94 },
- { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 94 },
- { 0, 17, 0, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 94 },
- { 0, 17, 9, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 94 },
- { 0, 17, 0, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 92 },
- { 1, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 92 },
- { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 92 },
- { 18, 0, 0, 0, -1, 0, 11, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 92 },
- { 0, 17, 9, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 92 },
- { 0, 17, 7, 5, -1, 0, 11, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 92 },
- { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 92 },
- { 10, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 6, 12, 4, 0, 92 },
- { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 92 },
- { 0, 17, 0, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 92 },
- { 10, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 6, 12, 4, 0, 92 },
- { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 101 },
- { 3, 0, 0, 0, 0, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 101 },
- { 3, 0, 0, 0, 1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 101 },
- { 3, 0, 0, 0, 2, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 101 },
- { 3, 0, 0, 0, 3, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 101 },
- { 3, 0, 0, 0, 4, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 101 },
- { 3, 0, 0, 0, 5, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 101 },
- { 3, 0, 0, 0, 6, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 101 },
- { 3, 0, 0, 0, 7, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 101 },
- { 3, 0, 0, 0, 8, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 101 },
- { 3, 0, 0, 0, 9, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 101 },
- { 0, 17, 230, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 96 },
- { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 96 },
- { 0, 17, 0, 5, -1, 0, 13, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 96 },
- { 0, 17, 0, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 96 },
- { 1, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 96 },
- { 0, 17, 0, 5, -1, 0, 13, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 96 },
- { 0, 17, 9, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 96 },
- { 3, 0, 0, 0, 0, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 96 },
- { 3, 0, 0, 0, 1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 96 },
- { 3, 0, 0, 0, 2, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 96 },
- { 3, 0, 0, 0, 3, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 96 },
- { 3, 0, 0, 0, 4, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 96 },
- { 3, 0, 0, 0, 5, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 96 },
- { 3, 0, 0, 0, 6, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 96 },
- { 3, 0, 0, 0, 7, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 96 },
- { 3, 0, 0, 0, 8, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 96 },
- { 3, 0, 0, 0, 9, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 96 },
- { 25, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 96 },
- { 25, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 96 },
- { 18, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 96 },
- { 1, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 96 },
- { 18, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 96 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 111 },
- { 0, 17, 7, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 111 },
- { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 111 },
- { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 0, 1, 111 },
- { 0, 17, 0, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 100 },
- { 1, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 100 },
- { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 100 },
- { 1, 0, 9, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 100 },
- { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 10, 12, 8, 1, 100 },
- { 25, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 100 },
- { 25, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 100 },
- { 25, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 100 },
- { 0, 17, 0, 5, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 100 },
- { 0, 17, 7, 5, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 100 },
- { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 12, 1, 100 },
- { 1, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 100 },
- { 0, 17, 0, 5, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 100 },
- { 3, 0, 0, 0, 0, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 100 },
- { 3, 0, 0, 0, 1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 100 },
- { 3, 0, 0, 0, 2, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 100 },
- { 3, 0, 0, 0, 3, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 100 },
- { 3, 0, 0, 0, 4, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 100 },
- { 3, 0, 0, 0, 5, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 100 },
- { 3, 0, 0, 0, 6, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 100 },
- { 3, 0, 0, 0, 7, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 100 },
- { 3, 0, 0, 0, 8, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 100 },
- { 3, 0, 0, 0, 9, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 100 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 100 },
- { 25, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 0, 1, 100 },
- { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 100 },
- { 25, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 100 },
- { 25, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 100 },
- { 5, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 20 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 109 },
- { 1, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 109 },
- { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 109 },
- { 1, 0, 9, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 109 },
- { 0, 17, 7, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 109 },
- { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 109 },
- { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 109 },
- { 0, 17, 0, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 109 },
- { 18, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 109 },
- { 0, 17, 0, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 109 },
- { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 129 },
- { 25, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 129 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 123 },
- { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 123 },
- { 1, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 123 },
- { 0, 17, 7, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 123 },
- { 0, 17, 9, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 123 },
- { 3, 0, 0, 0, 0, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 123 },
- { 3, 0, 0, 0, 1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 123 },
- { 3, 0, 0, 0, 2, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 123 },
- { 3, 0, 0, 0, 3, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 123 },
- { 3, 0, 0, 0, 4, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 123 },
- { 3, 0, 0, 0, 5, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 123 },
- { 3, 0, 0, 0, 6, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 123 },
- { 3, 0, 0, 0, 7, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 123 },
- { 3, 0, 0, 0, 8, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 123 },
- { 3, 0, 0, 0, 9, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 123 },
- { 0, 17, 0, 5, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 107 },
- { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 107 },
- { 1, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 107 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 107 },
- { 0, 17, 7, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 7, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 107 },
- { 1, 0, 0, 0, -1, 0, 16, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 107 },
- { 1, 0, 0, 0, -1, 0, 16, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 107 },
- { 1, 0, 9, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 107 },
- { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 107 },
- { 0, 17, 230, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 107 },
- { 18, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 135 },
- { 1, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 135 },
- { 0, 17, 0, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 135 },
- { 0, 17, 9, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 135 },
- { 0, 17, 7, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 135 },
- { 25, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 135 },
- { 25, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 135 },
- { 25, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 135 },
- { 3, 0, 0, 0, 0, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 135 },
- { 3, 0, 0, 0, 1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 135 },
- { 3, 0, 0, 0, 2, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 135 },
- { 3, 0, 0, 0, 3, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 135 },
- { 3, 0, 0, 0, 4, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 135 },
- { 3, 0, 0, 0, 5, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 135 },
- { 3, 0, 0, 0, 6, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 135 },
- { 3, 0, 0, 0, 7, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 135 },
- { 3, 0, 0, 0, 8, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 135 },
- { 3, 0, 0, 0, 9, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 135 },
- { 25, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 135 },
- { 0, 17, 230, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 135 },
- { 18, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 135 },
- { 18, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 135 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 124 },
- { 1, 0, 0, 0, -1, 0, 16, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 124 },
- { 1, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 124 },
- { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 124 },
- { 0, 17, 0, 5, -1, 0, 16, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 124 },
- { 1, 0, 0, 0, -1, 0, 16, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 124 },
- { 0, 17, 9, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 124 },
- { 0, 17, 7, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 124 },
- { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 124 },
- { 3, 0, 0, 0, 0, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 124 },
- { 3, 0, 0, 0, 1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 124 },
- { 3, 0, 0, 0, 2, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 124 },
- { 3, 0, 0, 0, 3, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 124 },
- { 3, 0, 0, 0, 4, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 124 },
- { 3, 0, 0, 0, 5, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 124 },
- { 3, 0, 0, 0, 6, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 124 },
- { 3, 0, 0, 0, 7, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 124 },
- { 3, 0, 0, 0, 8, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 124 },
- { 3, 0, 0, 0, 9, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 124 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 122 },
- { 1, 0, 0, 0, -1, 0, 16, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 122 },
- { 1, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 122 },
- { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 122 },
- { 1, 0, 0, 0, -1, 0, 16, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 122 },
- { 0, 17, 9, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 122 },
- { 0, 17, 7, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 122 },
- { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 0, 1, 122 },
- { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 122 },
- { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 0, 1, 122 },
- { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 122 },
- { 25, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 122 },
- { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 122 },
- { 0, 17, 0, 5, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 122 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 114 },
- { 1, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 114 },
- { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 114 },
- { 0, 17, 9, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 114 },
- { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 114 },
- { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 114 },
- { 3, 0, 0, 0, 0, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 114 },
- { 3, 0, 0, 0, 1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 114 },
- { 3, 0, 0, 0, 2, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 114 },
- { 3, 0, 0, 0, 3, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 114 },
- { 3, 0, 0, 0, 4, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 114 },
- { 3, 0, 0, 0, 5, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 114 },
- { 3, 0, 0, 0, 6, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 114 },
- { 3, 0, 0, 0, 7, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 114 },
- { 3, 0, 0, 0, 8, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 114 },
- { 3, 0, 0, 0, 9, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 114 },
- { 25, 10, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 0, 1, 33 },
- { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 102 },
- { 0, 17, 0, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 102 },
- { 1, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 102 },
- { 1, 0, 9, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 102 },
- { 0, 17, 7, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 102 },
- { 18, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 102 },
- { 25, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 102 },
- { 3, 0, 0, 0, 0, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 102 },
- { 3, 0, 0, 0, 1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 102 },
- { 3, 0, 0, 0, 2, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 102 },
- { 3, 0, 0, 0, 3, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 102 },
- { 3, 0, 0, 0, 4, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 102 },
- { 3, 0, 0, 0, 5, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 102 },
- { 3, 0, 0, 0, 6, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 102 },
- { 3, 0, 0, 0, 7, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 102 },
- { 3, 0, 0, 0, 8, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 102 },
- { 3, 0, 0, 0, 9, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 102 },
- { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 126 },
- { 18, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 126 },
- { 0, 17, 0, 5, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 126 },
- { 1, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 4, 33, 4, 1, 126 },
- { 1, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 33, 4, 1, 126 },
- { 0, 17, 9, 5, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 4, 1, 126 },
- { 3, 0, 0, 0, 0, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 126 },
- { 3, 0, 0, 0, 1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 126 },
- { 3, 0, 0, 0, 2, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 126 },
- { 3, 0, 0, 0, 3, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 126 },
- { 3, 0, 0, 0, 4, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 126 },
- { 3, 0, 0, 0, 5, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 126 },
- { 3, 0, 0, 0, 6, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 126 },
- { 3, 0, 0, 0, 7, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 126 },
- { 3, 0, 0, 0, 8, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 126 },
- { 3, 0, 0, 0, 9, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 126 },
- { 5, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 0, 1, 126 },
- { 25, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 126 },
- { 29, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 0, 1, 126 },
- { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 33, 8, 1, 126 },
- { 18, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 142 },
- { 1, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 142 },
- { 0, 17, 0, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 142 },
- { 0, 17, 9, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 142 },
- { 0, 17, 7, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 142 },
- { 25, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 142 },
- { 14, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 32}, {0, 0}, {0, 0}, {0, 32} }, 0, 10, 12, 7, 3, 125 },
- { 15, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 12, 6, 1, 125 },
- { 3, 0, 0, 0, 0, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 125 },
- { 3, 0, 0, 0, 1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 125 },
- { 3, 0, 0, 0, 2, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 125 },
- { 3, 0, 0, 0, 3, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 125 },
- { 3, 0, 0, 0, 4, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 125 },
- { 3, 0, 0, 0, 5, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 125 },
- { 3, 0, 0, 0, 6, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 125 },
- { 3, 0, 0, 0, 7, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 125 },
- { 3, 0, 0, 0, 8, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 125 },
- { 3, 0, 0, 0, 9, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 125 },
- { 5, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 125 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 125 },
- { 18, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 154 },
- { 1, 0, 0, 0, -1, 0, 23, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 154 },
- { 1, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 154 },
- { 1, 0, 0, 0, -1, 0, 23, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 154 },
- { 0, 17, 0, 5, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 154 },
- { 1, 0, 9, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 154 },
- { 0, 17, 9, 5, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 154 },
- { 18, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 10, 12, 8, 1, 154 },
- { 0, 17, 7, 5, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 154 },
- { 25, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 154 },
- { 25, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 154 },
- { 3, 0, 0, 0, 0, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 154 },
- { 3, 0, 0, 0, 1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 154 },
- { 3, 0, 0, 0, 2, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 154 },
- { 3, 0, 0, 0, 3, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 154 },
- { 3, 0, 0, 0, 4, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 154 },
- { 3, 0, 0, 0, 5, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 154 },
- { 3, 0, 0, 0, 6, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 154 },
- { 3, 0, 0, 0, 7, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 154 },
- { 3, 0, 0, 0, 8, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 154 },
- { 3, 0, 0, 0, 9, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 154 },
- { 18, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 150 },
- { 1, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 150 },
- { 0, 17, 0, 5, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 150 },
- { 0, 17, 9, 5, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 150 },
- { 25, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 0, 1, 150 },
- { 18, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 141 },
- { 0, 17, 0, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 141 },
- { 0, 0, 0, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 141 },
- { 0, 17, 9, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 141 },
- { 1, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 141 },
- { 18, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 10, 12, 8, 1, 141 },
- { 25, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 0, 1, 141 },
- { 25, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 141 },
- { 25, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 141 },
- { 25, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 141 },
- { 18, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 140 },
- { 0, 17, 0, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 140 },
- { 1, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 140 },
- { 18, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 10, 12, 8, 1, 140 },
- { 18, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 10, 12, 8, 1, 140 },
- { 0, 17, 9, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 140 },
- { 25, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 140 },
- { 25, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 140 },
- { 18, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 140 },
- { 25, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 0, 1, 140 },
- { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 29 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 119 },
- { 25, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 0, 1, 11 },
- { 18, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 133 },
- { 1, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 133 },
- { 0, 17, 0, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 133 },
- { 0, 0, 9, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 133 },
- { 25, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 133 },
- { 25, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 133 },
- { 3, 0, 0, 0, 0, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 133 },
- { 3, 0, 0, 0, 1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 133 },
- { 3, 0, 0, 0, 2, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 133 },
- { 3, 0, 0, 0, 3, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 133 },
- { 3, 0, 0, 0, 4, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 133 },
- { 3, 0, 0, 0, 5, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 133 },
- { 3, 0, 0, 0, 6, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 133 },
- { 3, 0, 0, 0, 7, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 133 },
- { 3, 0, 0, 0, 8, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 133 },
- { 3, 0, 0, 0, 9, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 133 },
- { 5, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 133 },
- { 25, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 18, 0, 1, 134 },
- { 25, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 6, 0, 1, 134 },
- { 18, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 134 },
- { 0, 17, 0, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 134 },
- { 1, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 134 },
- { 18, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 138 },
- { 0, 17, 0, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 138 },
- { 0, 17, 7, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 138 },
- { 0, 17, 9, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 138 },
- { 18, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 10, 12, 8, 1, 138 },
- { 3, 0, 0, 0, 0, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 138 },
- { 3, 0, 0, 0, 1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 138 },
- { 3, 0, 0, 0, 2, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 138 },
- { 3, 0, 0, 0, 3, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 138 },
- { 3, 0, 0, 0, 4, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 138 },
- { 3, 0, 0, 0, 5, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 138 },
- { 3, 0, 0, 0, 6, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 138 },
- { 3, 0, 0, 0, 7, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 138 },
- { 3, 0, 0, 0, 8, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 138 },
- { 3, 0, 0, 0, 9, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 138 },
- { 18, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 143 },
- { 1, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 143 },
- { 0, 17, 0, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 143 },
- { 0, 17, 9, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 143 },
- { 3, 0, 0, 0, 0, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 143 },
- { 3, 0, 0, 0, 1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 143 },
- { 3, 0, 0, 0, 2, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 143 },
- { 3, 0, 0, 0, 3, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 143 },
- { 3, 0, 0, 0, 4, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 143 },
- { 3, 0, 0, 0, 5, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 143 },
- { 3, 0, 0, 0, 6, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 143 },
- { 3, 0, 0, 0, 7, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 143 },
- { 3, 0, 0, 0, 8, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 143 },
- { 3, 0, 0, 0, 9, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 143 },
- { 18, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 145 },
- { 0, 17, 0, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 145 },
- { 1, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 145 },
- { 25, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 12, 1, 145 },
- { 0, 17, 0, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 162 },
- { 18, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 10, 12, 8, 1, 162 },
- { 1, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 162 },
- { 18, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 162 },
- { 1, 0, 9, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 162 },
- { 0, 17, 9, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 162 },
- { 25, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 162 },
- { 25, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 162 },
- { 3, 0, 0, 0, 0, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 162 },
- { 3, 0, 0, 0, 1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 162 },
- { 3, 0, 0, 0, 2, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 162 },
- { 3, 0, 0, 0, 3, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 162 },
- { 3, 0, 0, 0, 4, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 162 },
- { 3, 0, 0, 0, 5, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 162 },
- { 3, 0, 0, 0, 6, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 162 },
- { 3, 0, 0, 0, 7, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 162 },
- { 3, 0, 0, 0, 8, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 162 },
- { 3, 0, 0, 0, 9, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 162 },
- { 18, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 83 },
- { 5, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 16 },
- { 29, 10, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 16 },
- { 27, 4, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 1, 16 },
- { 25, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 16 },
- { 18, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 63 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 63 },
- { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 63 },
- { 4, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 63 },
- { 4, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 63 },
- { 25, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 63 },
- { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 63 },
- { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 157 },
- { 25, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 157 },
- { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 81 },
+ { 18, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 80 },
+ { 25, 10, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 80 },
+ { 18, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 89 },
+ { 5, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 89 },
+ { 18, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 90 },
+ { 5, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 90 },
+ { 18, 1, 0, 2, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 121 },
+ { 18, 1, 0, 3, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 121 },
+ { 25, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 121 },
+ { 5, 1, 0, 3, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 121 },
+ { 5, 1, 0, 2, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 121 },
+ { 5, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 121 },
+ { 18, 1, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 91 },
+ { 14, 1, 0, 0, -1, 0, 17, 3, 0, { {0, 64}, {0, 0}, {0, 0}, {0, 64} }, 0, 10, 14, 7, 3, 130 },
+ { 15, 1, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, -64}, {0, -64}, {0, 0} }, 0, 10, 14, 6, 1, 130 },
+ { 5, 1, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 130 },
+ { 18, 13, 0, 4, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 144 },
+ { 18, 13, 0, 2, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 144 },
+ { 18, 13, 0, 3, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 144 },
+ { 0, 17, 230, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 144 },
+ { 3, 5, 0, 0, 0, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 144 },
+ { 3, 5, 0, 0, 1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 144 },
+ { 3, 5, 0, 0, 2, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 144 },
+ { 3, 5, 0, 0, 3, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 144 },
+ { 3, 5, 0, 0, 4, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 144 },
+ { 3, 5, 0, 0, 5, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 144 },
+ { 3, 5, 0, 0, 6, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 144 },
+ { 3, 5, 0, 0, 7, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 144 },
+ { 3, 5, 0, 0, 8, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 144 },
+ { 3, 5, 0, 0, 9, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 144 },
+ { 5, 5, 0, 0, 1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 8 },
+ { 5, 5, 0, 0, 2, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 8 },
+ { 5, 5, 0, 0, 3, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 8 },
+ { 5, 5, 0, 0, 4, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 8 },
+ { 5, 5, 0, 0, 5, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 8 },
+ { 5, 5, 0, 0, 6, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 8 },
+ { 5, 5, 0, 0, 7, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 8 },
+ { 5, 5, 0, 0, 8, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 8 },
+ { 5, 5, 0, 0, 9, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 8 },
+ { 5, 5, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 8 },
+ { 18, 1, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 156 },
+ { 0, 17, 230, 5, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 156 },
+ { 20, 1, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 156 },
+ { 0, 17, 220, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 8 },
+ { 18, 1, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 147 },
+ { 5, 1, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 147 },
+ { 18, 13, 0, 2, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 148 },
+ { 18, 13, 0, 3, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 148 },
+ { 18, 13, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 148 },
+ { 0, 17, 220, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 148 },
+ { 0, 17, 230, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 148 },
+ { 5, 13, 0, 2, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 148 },
+ { 5, 13, 0, 3, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 148 },
+ { 25, 13, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 12, 1, 148 },
+ { 18, 1, 0, 2, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 158 },
+ { 18, 1, 0, 3, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 158 },
+ { 0, 17, 230, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 158 },
+ { 0, 17, 220, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 158 },
+ { 25, 1, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 12, 1, 158 },
+ { 18, 1, 0, 2, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 153 },
+ { 18, 1, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 153 },
+ { 18, 1, 0, 3, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 153 },
+ { 5, 1, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 153 },
+ { 5, 1, 0, 3, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 153 },
+ { 5, 1, 0, 2, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 153 },
+ { 5, 1, 0, 4, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 153 },
+ { 18, 1, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 149 },
+ { 1, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 94 },
+ { 0, 17, 0, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 94 },
+ { 18, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 94 },
+ { 0, 17, 9, 5, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 94 },
+ { 25, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 94 },
+ { 25, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 94 },
+ { 5, 10, 0, 0, 1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 94 },
+ { 5, 10, 0, 0, 2, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 94 },
+ { 5, 10, 0, 0, 3, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 94 },
+ { 5, 10, 0, 0, 4, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 94 },
+ { 5, 10, 0, 0, 5, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 94 },
+ { 5, 10, 0, 0, 6, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 94 },
+ { 5, 10, 0, 0, 7, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 94 },
+ { 5, 10, 0, 0, 8, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 94 },
+ { 5, 10, 0, 0, 9, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 94 },
+ { 5, 10, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 94 },
+ { 3, 0, 0, 0, 0, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 1, 94 },
+ { 3, 0, 0, 0, 1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 1, 94 },
+ { 3, 0, 0, 0, 2, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 1, 94 },
+ { 3, 0, 0, 0, 3, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 1, 94 },
+ { 3, 0, 0, 0, 4, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 1, 94 },
+ { 3, 0, 0, 0, 5, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 1, 94 },
+ { 3, 0, 0, 0, 6, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 1, 94 },
+ { 3, 0, 0, 0, 7, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 1, 94 },
+ { 3, 0, 0, 0, 8, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 1, 94 },
+ { 3, 0, 0, 0, 9, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 1, 94 },
+ { 0, 17, 9, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 94 },
+ { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 94 },
+ { 0, 17, 0, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 94 },
+ { 0, 17, 9, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 6, 4, 1, 94 },
+ { 0, 17, 0, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 92 },
+ { 1, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 92 },
+ { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 92 },
+ { 18, 0, 0, 0, -1, 0, 11, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 92 },
+ { 0, 17, 9, 5, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 92 },
+ { 0, 17, 7, 5, -1, 0, 11, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 92 },
+ { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 92 },
+ { 10, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 16, 13, 9, 0, 92 },
+ { 25, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 92 },
+ { 0, 17, 0, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 92 },
+ { 10, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 16, 13, 9, 0, 92 },
+ { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 101 },
+ { 3, 0, 0, 0, 0, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 101 },
+ { 3, 0, 0, 0, 1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 101 },
+ { 3, 0, 0, 0, 2, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 101 },
+ { 3, 0, 0, 0, 3, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 101 },
+ { 3, 0, 0, 0, 4, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 101 },
+ { 3, 0, 0, 0, 5, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 101 },
+ { 3, 0, 0, 0, 6, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 101 },
+ { 3, 0, 0, 0, 7, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 101 },
+ { 3, 0, 0, 0, 8, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 101 },
+ { 3, 0, 0, 0, 9, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 101 },
+ { 0, 17, 230, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 96 },
+ { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 96 },
+ { 0, 17, 0, 5, -1, 0, 13, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 96 },
+ { 0, 17, 0, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 96 },
+ { 1, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 96 },
+ { 0, 17, 0, 5, -1, 0, 13, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 96 },
+ { 0, 17, 9, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 96 },
+ { 3, 0, 0, 0, 0, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 96 },
+ { 3, 0, 0, 0, 1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 96 },
+ { 3, 0, 0, 0, 2, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 96 },
+ { 3, 0, 0, 0, 3, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 96 },
+ { 3, 0, 0, 0, 4, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 96 },
+ { 3, 0, 0, 0, 5, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 96 },
+ { 3, 0, 0, 0, 6, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 96 },
+ { 3, 0, 0, 0, 7, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 96 },
+ { 3, 0, 0, 0, 8, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 96 },
+ { 3, 0, 0, 0, 9, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 96 },
+ { 25, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 96 },
+ { 25, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 96 },
+ { 18, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 96 },
+ { 1, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 96 },
+ { 18, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 96 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 111 },
+ { 0, 17, 7, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 111 },
+ { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 111 },
+ { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 20, 0, 1, 111 },
+ { 0, 17, 0, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 100 },
+ { 1, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 100 },
+ { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 100 },
+ { 1, 0, 9, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 100 },
+ { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 10, 14, 8, 1, 100 },
+ { 25, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 100 },
+ { 25, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 100 },
+ { 25, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 100 },
+ { 0, 17, 0, 5, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 100 },
+ { 0, 17, 7, 5, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 100 },
+ { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 12, 1, 100 },
+ { 1, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 100 },
+ { 0, 17, 0, 5, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 100 },
+ { 3, 0, 0, 0, 0, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 100 },
+ { 3, 0, 0, 0, 1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 100 },
+ { 3, 0, 0, 0, 2, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 100 },
+ { 3, 0, 0, 0, 3, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 100 },
+ { 3, 0, 0, 0, 4, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 100 },
+ { 3, 0, 0, 0, 5, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 100 },
+ { 3, 0, 0, 0, 6, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 100 },
+ { 3, 0, 0, 0, 7, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 100 },
+ { 3, 0, 0, 0, 8, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 100 },
+ { 3, 0, 0, 0, 9, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 100 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 100 },
+ { 25, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 20, 0, 1, 100 },
+ { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 100 },
+ { 25, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 100 },
+ { 25, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 100 },
+ { 5, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 20 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 109 },
+ { 1, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 109 },
+ { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 109 },
+ { 1, 0, 9, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 109 },
+ { 0, 17, 7, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 109 },
+ { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 109 },
+ { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 109 },
+ { 0, 17, 0, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 109 },
+ { 18, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 109 },
+ { 0, 17, 0, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 109 },
+ { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 129 },
+ { 25, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 129 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 123 },
+ { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 123 },
+ { 1, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 123 },
+ { 0, 17, 7, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 123 },
+ { 0, 17, 9, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 123 },
+ { 3, 0, 0, 0, 0, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 123 },
+ { 3, 0, 0, 0, 1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 123 },
+ { 3, 0, 0, 0, 2, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 123 },
+ { 3, 0, 0, 0, 3, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 123 },
+ { 3, 0, 0, 0, 4, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 123 },
+ { 3, 0, 0, 0, 5, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 123 },
+ { 3, 0, 0, 0, 6, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 123 },
+ { 3, 0, 0, 0, 7, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 123 },
+ { 3, 0, 0, 0, 8, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 123 },
+ { 3, 0, 0, 0, 9, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 123 },
+ { 0, 17, 0, 5, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 107 },
+ { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 107 },
+ { 1, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 107 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 107 },
+ { 0, 17, 7, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 7, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 107 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 19, 8, 1, 107 },
+ { 1, 0, 0, 0, -1, 0, 16, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 107 },
+ { 1, 0, 0, 0, -1, 0, 16, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 107 },
+ { 1, 0, 9, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 107 },
+ { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 107 },
+ { 0, 17, 230, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 107 },
+ { 18, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 135 },
+ { 1, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 135 },
+ { 0, 17, 0, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 135 },
+ { 0, 17, 9, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 135 },
+ { 0, 17, 7, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 135 },
+ { 25, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 135 },
+ { 25, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 135 },
+ { 25, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 135 },
+ { 3, 0, 0, 0, 0, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 135 },
+ { 3, 0, 0, 0, 1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 135 },
+ { 3, 0, 0, 0, 2, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 135 },
+ { 3, 0, 0, 0, 3, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 135 },
+ { 3, 0, 0, 0, 4, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 135 },
+ { 3, 0, 0, 0, 5, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 135 },
+ { 3, 0, 0, 0, 6, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 135 },
+ { 3, 0, 0, 0, 7, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 135 },
+ { 3, 0, 0, 0, 8, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 135 },
+ { 3, 0, 0, 0, 9, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 135 },
+ { 25, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 135 },
+ { 0, 17, 230, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 135 },
+ { 18, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 135 },
+ { 18, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 135 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 124 },
+ { 1, 0, 0, 0, -1, 0, 16, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 124 },
+ { 1, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 124 },
+ { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 124 },
+ { 0, 17, 0, 5, -1, 0, 16, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 124 },
+ { 1, 0, 0, 0, -1, 0, 16, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 124 },
+ { 0, 17, 9, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 124 },
+ { 0, 17, 7, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 124 },
+ { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 124 },
+ { 3, 0, 0, 0, 0, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 124 },
+ { 3, 0, 0, 0, 1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 124 },
+ { 3, 0, 0, 0, 2, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 124 },
+ { 3, 0, 0, 0, 3, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 124 },
+ { 3, 0, 0, 0, 4, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 124 },
+ { 3, 0, 0, 0, 5, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 124 },
+ { 3, 0, 0, 0, 6, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 124 },
+ { 3, 0, 0, 0, 7, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 124 },
+ { 3, 0, 0, 0, 8, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 124 },
+ { 3, 0, 0, 0, 9, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 124 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 122 },
+ { 1, 0, 0, 0, -1, 0, 16, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 122 },
+ { 1, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 122 },
+ { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 122 },
+ { 1, 0, 0, 0, -1, 0, 16, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 122 },
+ { 0, 17, 9, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 122 },
+ { 0, 17, 7, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 122 },
+ { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 20, 0, 1, 122 },
+ { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 122 },
+ { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 0, 1, 122 },
+ { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 122 },
+ { 25, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 122 },
+ { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 122 },
+ { 0, 17, 0, 5, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 122 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 114 },
+ { 1, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 114 },
+ { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 114 },
+ { 0, 17, 9, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 114 },
+ { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 114 },
+ { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 114 },
+ { 3, 0, 0, 0, 0, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 114 },
+ { 3, 0, 0, 0, 1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 114 },
+ { 3, 0, 0, 0, 2, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 114 },
+ { 3, 0, 0, 0, 3, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 114 },
+ { 3, 0, 0, 0, 4, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 114 },
+ { 3, 0, 0, 0, 5, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 114 },
+ { 3, 0, 0, 0, 6, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 114 },
+ { 3, 0, 0, 0, 7, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 114 },
+ { 3, 0, 0, 0, 8, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 114 },
+ { 3, 0, 0, 0, 9, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 114 },
+ { 25, 10, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 20, 0, 1, 33 },
+ { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 102 },
+ { 0, 17, 0, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 102 },
+ { 1, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 102 },
+ { 1, 0, 9, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 102 },
+ { 0, 17, 7, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 102 },
+ { 18, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 102 },
+ { 25, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 102 },
+ { 3, 0, 0, 0, 0, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 102 },
+ { 3, 0, 0, 0, 1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 102 },
+ { 3, 0, 0, 0, 2, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 102 },
+ { 3, 0, 0, 0, 3, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 102 },
+ { 3, 0, 0, 0, 4, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 102 },
+ { 3, 0, 0, 0, 5, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 102 },
+ { 3, 0, 0, 0, 6, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 102 },
+ { 3, 0, 0, 0, 7, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 102 },
+ { 3, 0, 0, 0, 8, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 102 },
+ { 3, 0, 0, 0, 9, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 102 },
+ { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 126 },
+ { 18, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 126 },
+ { 0, 17, 0, 5, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 126 },
+ { 1, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 4, 35, 4, 1, 126 },
+ { 1, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 35, 4, 1, 126 },
+ { 0, 17, 9, 5, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 35, 4, 1, 126 },
+ { 3, 0, 0, 0, 0, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 126 },
+ { 3, 0, 0, 0, 1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 126 },
+ { 3, 0, 0, 0, 2, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 126 },
+ { 3, 0, 0, 0, 3, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 126 },
+ { 3, 0, 0, 0, 4, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 126 },
+ { 3, 0, 0, 0, 5, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 126 },
+ { 3, 0, 0, 0, 6, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 126 },
+ { 3, 0, 0, 0, 7, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 126 },
+ { 3, 0, 0, 0, 8, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 126 },
+ { 3, 0, 0, 0, 9, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 126 },
+ { 5, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 0, 1, 126 },
+ { 25, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 126 },
+ { 29, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 0, 1, 126 },
+ { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 35, 8, 1, 126 },
+ { 18, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 142 },
+ { 1, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 142 },
+ { 0, 17, 0, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 142 },
+ { 0, 17, 9, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 142 },
+ { 0, 17, 7, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 142 },
+ { 25, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 142 },
+ { 14, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 32}, {0, 0}, {0, 0}, {0, 32} }, 0, 10, 14, 7, 3, 125 },
+ { 15, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 14, 6, 1, 125 },
+ { 3, 0, 0, 0, 0, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 125 },
+ { 3, 0, 0, 0, 1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 125 },
+ { 3, 0, 0, 0, 2, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 125 },
+ { 3, 0, 0, 0, 3, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 125 },
+ { 3, 0, 0, 0, 4, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 125 },
+ { 3, 0, 0, 0, 5, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 125 },
+ { 3, 0, 0, 0, 6, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 125 },
+ { 3, 0, 0, 0, 7, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 125 },
+ { 3, 0, 0, 0, 8, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 125 },
+ { 3, 0, 0, 0, 9, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 125 },
+ { 5, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 125 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 125 },
+ { 18, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 154 },
+ { 1, 0, 0, 0, -1, 0, 23, 3, 204, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 154 },
+ { 1, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 154 },
+ { 1, 0, 0, 0, -1, 0, 23, 3, 17, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 154 },
+ { 0, 17, 0, 5, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 154 },
+ { 1, 0, 9, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 154 },
+ { 0, 17, 9, 5, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 154 },
+ { 18, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 10, 14, 8, 1, 154 },
+ { 0, 17, 7, 5, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 154 },
+ { 25, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 154 },
+ { 25, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 154 },
+ { 3, 0, 0, 0, 0, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 154 },
+ { 3, 0, 0, 0, 1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 154 },
+ { 3, 0, 0, 0, 2, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 154 },
+ { 3, 0, 0, 0, 3, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 154 },
+ { 3, 0, 0, 0, 4, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 154 },
+ { 3, 0, 0, 0, 5, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 154 },
+ { 3, 0, 0, 0, 6, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 154 },
+ { 3, 0, 0, 0, 7, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 154 },
+ { 3, 0, 0, 0, 8, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 154 },
+ { 3, 0, 0, 0, 9, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 16, 9, 1, 154 },
+ { 18, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 150 },
+ { 1, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 150 },
+ { 0, 17, 0, 5, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 150 },
+ { 0, 17, 9, 5, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 150 },
+ { 25, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 20, 0, 1, 150 },
+ { 18, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 141 },
+ { 0, 17, 0, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 141 },
+ { 0, 0, 0, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 141 },
+ { 0, 17, 9, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 141 },
+ { 1, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 141 },
+ { 18, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 10, 14, 8, 1, 141 },
+ { 25, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 20, 0, 1, 141 },
+ { 25, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 141 },
+ { 25, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 141 },
+ { 25, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 141 },
+ { 18, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 140 },
+ { 0, 17, 0, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 140 },
+ { 1, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 140 },
+ { 18, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 10, 14, 8, 1, 140 },
+ { 18, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 10, 14, 8, 1, 140 },
+ { 0, 17, 9, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 140 },
+ { 25, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 140 },
+ { 25, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 140 },
+ { 18, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 140 },
+ { 25, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 20, 0, 1, 140 },
+ { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 29 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 119 },
+ { 25, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 20, 0, 1, 11 },
+ { 18, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 133 },
+ { 1, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 133 },
+ { 0, 17, 0, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 133 },
+ { 0, 0, 9, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 133 },
+ { 25, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 133 },
+ { 25, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 133 },
+ { 3, 0, 0, 0, 0, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 133 },
+ { 3, 0, 0, 0, 1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 133 },
+ { 3, 0, 0, 0, 2, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 133 },
+ { 3, 0, 0, 0, 3, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 133 },
+ { 3, 0, 0, 0, 4, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 133 },
+ { 3, 0, 0, 0, 5, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 133 },
+ { 3, 0, 0, 0, 6, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 133 },
+ { 3, 0, 0, 0, 7, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 133 },
+ { 3, 0, 0, 0, 8, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 133 },
+ { 3, 0, 0, 0, 9, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 133 },
+ { 5, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 133 },
+ { 25, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 20, 0, 1, 134 },
+ { 25, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 8, 0, 1, 134 },
+ { 18, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 134 },
+ { 0, 17, 0, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 134 },
+ { 1, 0, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 134 },
+ { 18, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 138 },
+ { 0, 17, 0, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 138 },
+ { 0, 17, 7, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 138 },
+ { 0, 17, 9, 5, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 138 },
+ { 18, 0, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 10, 14, 8, 1, 138 },
+ { 3, 0, 0, 0, 0, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 138 },
+ { 3, 0, 0, 0, 1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 138 },
+ { 3, 0, 0, 0, 2, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 138 },
+ { 3, 0, 0, 0, 3, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 138 },
+ { 3, 0, 0, 0, 4, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 138 },
+ { 3, 0, 0, 0, 5, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 138 },
+ { 3, 0, 0, 0, 6, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 138 },
+ { 3, 0, 0, 0, 7, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 138 },
+ { 3, 0, 0, 0, 8, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 138 },
+ { 3, 0, 0, 0, 9, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 138 },
+ { 18, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 143 },
+ { 1, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 143 },
+ { 0, 17, 0, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 143 },
+ { 0, 17, 9, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 143 },
+ { 3, 0, 0, 0, 0, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 143 },
+ { 3, 0, 0, 0, 1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 143 },
+ { 3, 0, 0, 0, 2, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 143 },
+ { 3, 0, 0, 0, 3, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 143 },
+ { 3, 0, 0, 0, 4, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 143 },
+ { 3, 0, 0, 0, 5, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 143 },
+ { 3, 0, 0, 0, 6, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 143 },
+ { 3, 0, 0, 0, 7, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 143 },
+ { 3, 0, 0, 0, 8, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 143 },
+ { 3, 0, 0, 0, 9, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 143 },
+ { 18, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 145 },
+ { 18, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 19, 8, 1, 145 },
+ { 0, 17, 0, 5, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 145 },
+ { 1, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 145 },
+ { 25, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 145 },
+ { 0, 17, 0, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 162 },
+ { 18, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 7, 10, 14, 8, 1, 162 },
+ { 1, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 162 },
+ { 18, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 162 },
+ { 1, 0, 9, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 162 },
+ { 0, 17, 9, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 162 },
+ { 25, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 162 },
+ { 25, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 162 },
+ { 3, 0, 0, 0, 0, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 1, 162 },
+ { 3, 0, 0, 0, 1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 1, 162 },
+ { 3, 0, 0, 0, 2, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 1, 162 },
+ { 3, 0, 0, 0, 3, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 1, 162 },
+ { 3, 0, 0, 0, 4, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 1, 162 },
+ { 3, 0, 0, 0, 5, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 1, 162 },
+ { 3, 0, 0, 0, 6, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 1, 162 },
+ { 3, 0, 0, 0, 7, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 1, 162 },
+ { 3, 0, 0, 0, 8, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 1, 162 },
+ { 3, 0, 0, 0, 9, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 14, 9, 1, 162 },
+ { 18, 0, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 83 },
+ { 5, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 16 },
+ { 29, 10, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 16 },
+ { 27, 4, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 16 },
+ { 25, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 16 },
+ { 18, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 63 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 63 },
+ { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 63 },
+ { 4, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 63 },
+ { 4, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 63 },
+ { 25, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 63 },
+ { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 63 },
+ { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 157 },
+ { 25, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 157 },
+ { 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 81 },
{ 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 0, 8, 1, 81 },
{ 18, 0, 0, 0, -1, 0, 11, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 1, 8, 1, 81 },
- { 18, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 81 },
- { 10, 0, 0, 5, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 4, 4, 0, 81 },
+ { 18, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 0, 8, 1, 81 },
+ { 10, 0, 0, 5, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 6, 4, 0, 81 },
{ 10, 0, 0, 5, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 0, 4, 0, 81 },
{ 10, 0, 0, 5, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 1, 4, 0, 81 },
- { 10, 0, 0, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 4, 4, 0, 81 },
+ { 10, 0, 0, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 6, 4, 0, 81 },
{ 10, 0, 0, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 0, 4, 0, 81 },
{ 10, 0, 0, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 1, 4, 0, 81 },
- { 0, 17, 0, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 81 },
- { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 127 },
+ { 0, 17, 0, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 81 },
+ { 18, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 81 },
+ { 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 127 },
{ 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 0, 8, 1, 127 },
{ 18, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 1, 8, 1, 127 },
- { 18, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 84 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 115 },
- { 3, 0, 0, 0, 0, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 115 },
- { 3, 0, 0, 0, 1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 115 },
- { 3, 0, 0, 0, 2, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 115 },
- { 3, 0, 0, 0, 3, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 115 },
- { 3, 0, 0, 0, 4, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 115 },
- { 3, 0, 0, 0, 5, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 115 },
- { 3, 0, 0, 0, 6, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 115 },
- { 3, 0, 0, 0, 7, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 115 },
- { 3, 0, 0, 0, 8, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 115 },
- { 3, 0, 0, 0, 9, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 115 },
- { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 115 },
- { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 159 },
- { 3, 0, 0, 0, 0, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 159 },
- { 3, 0, 0, 0, 1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 159 },
- { 3, 0, 0, 0, 2, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 159 },
- { 3, 0, 0, 0, 3, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 159 },
- { 3, 0, 0, 0, 4, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 159 },
- { 3, 0, 0, 0, 5, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 159 },
- { 3, 0, 0, 0, 6, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 159 },
- { 3, 0, 0, 0, 7, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 159 },
- { 3, 0, 0, 0, 8, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 159 },
- { 3, 0, 0, 0, 9, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 159 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 104 },
- { 0, 17, 1, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 104 },
- { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 104 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 108 },
- { 0, 17, 230, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 108 },
- { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 108 },
- { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 108 },
- { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 108 },
- { 29, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 108 },
- { 17, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 108 },
- { 3, 0, 0, 0, 0, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 108 },
- { 3, 0, 0, 0, 1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 108 },
- { 3, 0, 0, 0, 2, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 108 },
- { 3, 0, 0, 0, 3, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 108 },
- { 3, 0, 0, 0, 4, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 108 },
- { 3, 0, 0, 0, 5, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 108 },
- { 3, 0, 0, 0, 6, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 108 },
- { 3, 0, 0, 0, 7, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 108 },
- { 3, 0, 0, 0, 8, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 108 },
- { 3, 0, 0, 0, 9, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 108 },
- { 5, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 108 },
- { 14, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 32}, {0, 0}, {0, 0}, {0, 32} }, 0, 10, 12, 7, 3, 146 },
- { 15, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 12, 6, 1, 146 },
- { 5, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 146 },
- { 25, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 146 },
- { 25, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 146 },
- { 25, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 146 },
- { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 99 },
- { 18, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 99 },
- { 0, 17, 0, 5, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 99 },
- { 1, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 99 },
- { 1, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 99 },
- { 0, 17, 0, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 99 },
- { 17, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 99 },
- { 17, 0, 0, 0, -1, 0, 18, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 5, 8, 1, 137 },
- { 17, 0, 0, 0, -1, 0, 19, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 5, 8, 1, 139 },
- { 25, 10, 0, 0, -1, 0, 21, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 5, 0, 1, 37 },
- { 17, 0, 0, 0, -1, 0, 21, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 5, 8, 1, 37 },
- { 0, 17, 0, 5, -1, 0, 23, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 4, 4, 1, 155 },
- { 1, 0, 6, 0, -1, 0, 23, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 37 },
- { 18, 0, 0, 0, -1, 0, 18, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 137 },
- { 18, 0, 0, 0, -1, 0, 20, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 137 },
- { 18, 0, 0, 0, -1, 0, 21, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 137 },
- { 18, 0, 0, 0, -1, 0, 23, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 137 },
- { 18, 0, 0, 0, -1, 0, 23, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 8, 1, 155 },
- { 17, 0, 0, 0, -1, 0, 24, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 12, 8, 1, 35 },
- { 18, 0, 0, 0, -1, 0, 12, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 14, 8, 1, 35 },
- { 18, 0, 0, 0, -1, 0, 12, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 34 },
- { 18, 0, 0, 0, -1, 0, 19, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 34 },
- { 18, 0, 0, 0, -1, 0, 24, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 34 },
- { 18, 0, 0, 0, -1, 0, 24, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 14, 8, 1, 35 },
- { 18, 0, 0, 0, -1, 0, 25, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 5, 8, 1, 34 },
- { 18, 0, 0, 0, -1, 0, 21, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 5, 8, 1, 34 },
- { 18, 0, 0, 0, -1, 0, 25, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 5, 8, 1, 35 },
- { 18, 0, 0, 0, -1, 0, 21, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 5, 8, 1, 35 },
- { 18, 0, 0, 0, -1, 0, 19, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 139 },
- { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 105 },
- { 29, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 105 },
- { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 105 },
- { 0, 17, 1, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 105 },
- { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 105 },
- { 10, 18, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 21, 4, 2, 2 },
- { 0, 17, 0, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 29, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 0, 0, 0, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 0, 0, 0, -1, 0, 5, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 1, 0, 216, 0, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 2 },
- { 1, 0, 216, 0, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 2 },
- { 0, 17, 1, 5, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 1, 0, 226, 0, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 21, 4, 1, 2 },
- { 10, 18, 0, 5, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 21, 4, 0, 2 },
- { 0, 17, 220, 5, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 0, 17, 230, 5, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 1 },
- { 29, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 0, 17, 230, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 4 },
- { 5, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 5, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 14, 0, 0, 0, -1, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 3, 2 },
- { 15, 0, 0, 0, -1, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 2 },
- { 15, 0, 0, 0, -1, 0, 7, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 2 },
- { 26, 0, 0, 0, -1, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 26, 10, 0, 0, -1, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 14, 0, 0, 0, -1, 0, 9, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 3, 2 },
- { 15, 0, 0, 0, -1, 0, 9, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 2 },
- { 3, 2, 0, 0, 0, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 3, 2 },
- { 3, 2, 0, 0, 1, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 3, 2 },
- { 3, 2, 0, 0, 2, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 3, 2 },
- { 3, 2, 0, 0, 3, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 3, 2 },
- { 3, 2, 0, 0, 4, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 3, 2 },
- { 3, 2, 0, 0, 5, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 3, 2 },
- { 3, 2, 0, 0, 6, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 3, 2 },
- { 3, 2, 0, 0, 7, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 3, 2 },
- { 3, 2, 0, 0, 8, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 3, 2 },
- { 3, 2, 0, 0, 9, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 3, 2 },
- { 29, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 131 },
- { 0, 17, 0, 5, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 131 },
- { 25, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 0, 1, 131 },
- { 25, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 17, 12, 1, 131 },
- { 25, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 131 },
- { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 3 },
- { 15, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 1, 3 },
- { 0, 17, 230, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 57 },
- { 17, 0, 0, 0, -1, 0, 25, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 6, 3, 5 },
- { 0, 17, 230, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 5 },
- { 18, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 151 },
- { 0, 17, 230, 5, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 151 },
- { 17, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 151 },
- { 3, 0, 0, 0, 0, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 151 },
- { 3, 0, 0, 0, 1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 151 },
- { 3, 0, 0, 0, 2, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 151 },
- { 3, 0, 0, 0, 3, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 151 },
- { 3, 0, 0, 0, 4, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 151 },
- { 3, 0, 0, 0, 5, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 151 },
- { 3, 0, 0, 0, 6, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 151 },
- { 3, 0, 0, 0, 7, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 151 },
- { 3, 0, 0, 0, 8, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 151 },
- { 3, 0, 0, 0, 9, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 151 },
- { 29, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 151 },
- { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 160 },
- { 0, 17, 230, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 160 },
- { 18, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 152 },
- { 0, 17, 230, 5, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 152 },
- { 3, 0, 0, 0, 0, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 152 },
- { 3, 0, 0, 0, 1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 152 },
- { 3, 0, 0, 0, 2, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 152 },
- { 3, 0, 0, 0, 3, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 152 },
- { 3, 0, 0, 0, 4, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 152 },
- { 3, 0, 0, 0, 5, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 152 },
- { 3, 0, 0, 0, 6, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 152 },
- { 3, 0, 0, 0, 7, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 152 },
- { 3, 0, 0, 0, 8, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 152 },
- { 3, 0, 0, 0, 9, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 152 },
- { 27, 4, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 9, 0, 1, 152 },
- { 18, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 163 },
- { 17, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 163 },
- { 0, 17, 232, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 163 },
- { 0, 17, 220, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 163 },
- { 0, 17, 230, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 163 },
- { 3, 0, 0, 0, 0, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 163 },
- { 3, 0, 0, 0, 1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 163 },
- { 3, 0, 0, 0, 2, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 163 },
- { 3, 0, 0, 0, 3, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 163 },
- { 3, 0, 0, 0, 4, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 163 },
- { 3, 0, 0, 0, 5, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 163 },
- { 3, 0, 0, 0, 6, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 163 },
- { 3, 0, 0, 0, 7, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 163 },
- { 3, 0, 0, 0, 8, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 163 },
- { 3, 0, 0, 0, 9, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 163 },
- { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 27 },
- { 18, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 113 },
- { 5, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 113 },
- { 0, 17, 220, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 113 },
- { 14, 1, 0, 2, -1, 0, 18, 3, 0, { {0, 34}, {0, 0}, {0, 0}, {0, 34} }, 0, 10, 12, 7, 3, 132 },
- { 15, 1, 0, 2, -1, 0, 18, 3, 0, { {0, 0}, {0, -34}, {0, -34}, {0, 0} }, 0, 10, 12, 6, 1, 132 },
- { 0, 17, 230, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 132 },
- { 0, 17, 7, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 1, 132 },
- { 17, 1, 0, 5, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 1, 132 },
- { 3, 1, 0, 0, 0, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 132 },
- { 3, 1, 0, 0, 1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 132 },
- { 3, 1, 0, 0, 2, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 132 },
- { 3, 1, 0, 0, 3, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 132 },
- { 3, 1, 0, 0, 4, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 132 },
- { 3, 1, 0, 0, 5, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 132 },
- { 3, 1, 0, 0, 6, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 132 },
- { 3, 1, 0, 0, 7, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 132 },
- { 3, 1, 0, 0, 8, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 132 },
- { 3, 1, 0, 0, 9, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 1, 132 },
+ { 18, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 84 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 115 },
+ { 3, 0, 0, 0, 0, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 115 },
+ { 3, 0, 0, 0, 1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 115 },
+ { 3, 0, 0, 0, 2, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 115 },
+ { 3, 0, 0, 0, 3, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 115 },
+ { 3, 0, 0, 0, 4, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 115 },
+ { 3, 0, 0, 0, 5, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 115 },
+ { 3, 0, 0, 0, 6, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 115 },
+ { 3, 0, 0, 0, 7, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 115 },
+ { 3, 0, 0, 0, 8, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 115 },
+ { 3, 0, 0, 0, 9, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 115 },
+ { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 115 },
+ { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 159 },
+ { 3, 0, 0, 0, 0, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 159 },
+ { 3, 0, 0, 0, 1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 159 },
+ { 3, 0, 0, 0, 2, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 159 },
+ { 3, 0, 0, 0, 3, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 159 },
+ { 3, 0, 0, 0, 4, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 159 },
+ { 3, 0, 0, 0, 5, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 159 },
+ { 3, 0, 0, 0, 6, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 159 },
+ { 3, 0, 0, 0, 7, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 159 },
+ { 3, 0, 0, 0, 8, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 159 },
+ { 3, 0, 0, 0, 9, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 159 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 104 },
+ { 0, 17, 1, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 104 },
+ { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 104 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 108 },
+ { 0, 17, 230, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 108 },
+ { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 108 },
+ { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 108 },
+ { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 108 },
+ { 29, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 108 },
+ { 17, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 108 },
+ { 3, 0, 0, 0, 0, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 108 },
+ { 3, 0, 0, 0, 1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 108 },
+ { 3, 0, 0, 0, 2, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 108 },
+ { 3, 0, 0, 0, 3, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 108 },
+ { 3, 0, 0, 0, 4, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 108 },
+ { 3, 0, 0, 0, 5, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 108 },
+ { 3, 0, 0, 0, 6, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 108 },
+ { 3, 0, 0, 0, 7, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 108 },
+ { 3, 0, 0, 0, 8, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 108 },
+ { 3, 0, 0, 0, 9, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 108 },
+ { 5, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 108 },
+ { 14, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 32}, {0, 0}, {0, 0}, {0, 32} }, 0, 10, 14, 7, 3, 146 },
+ { 15, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, -32}, {0, -32}, {0, 0} }, 0, 10, 14, 6, 1, 146 },
+ { 5, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 146 },
+ { 25, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 146 },
+ { 25, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 146 },
+ { 25, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 146 },
+ { 18, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 99 },
+ { 18, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 99 },
+ { 0, 17, 0, 5, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 99 },
+ { 1, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 99 },
+ { 1, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 99 },
+ { 0, 17, 0, 5, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 99 },
+ { 17, 0, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 99 },
+ { 17, 0, 0, 0, -1, 0, 18, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 7, 8, 1, 137 },
+ { 17, 0, 0, 0, -1, 0, 19, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 7, 8, 1, 139 },
+ { 25, 10, 0, 0, -1, 0, 21, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 7, 0, 1, 37 },
+ { 17, 0, 0, 0, -1, 0, 21, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 7, 8, 1, 37 },
+ { 0, 17, 0, 5, -1, 0, 23, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 6, 4, 1, 155 },
+ { 1, 0, 6, 0, -1, 0, 23, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 37 },
+ { 18, 0, 0, 0, -1, 0, 18, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 137 },
+ { 18, 0, 0, 0, -1, 0, 20, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 137 },
+ { 18, 0, 0, 0, -1, 0, 21, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 137 },
+ { 18, 0, 0, 0, -1, 0, 23, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 137 },
+ { 18, 0, 0, 0, -1, 0, 23, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 155 },
+ { 17, 0, 0, 0, -1, 0, 24, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 14, 8, 1, 35 },
+ { 18, 0, 0, 0, -1, 0, 12, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 16, 8, 1, 35 },
+ { 18, 0, 0, 0, -1, 0, 12, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 34 },
+ { 18, 0, 0, 0, -1, 0, 19, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 34 },
+ { 18, 0, 0, 0, -1, 0, 24, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 34 },
+ { 18, 0, 0, 0, -1, 0, 24, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 16, 8, 1, 35 },
+ { 18, 0, 0, 0, -1, 0, 25, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 7, 8, 1, 34 },
+ { 18, 0, 0, 0, -1, 0, 21, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 7, 8, 1, 34 },
+ { 18, 0, 0, 0, -1, 0, 25, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 7, 8, 1, 35 },
+ { 18, 0, 0, 0, -1, 0, 21, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 8, 7, 8, 1, 35 },
+ { 18, 0, 0, 0, -1, 0, 19, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 139 },
+ { 18, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 105 },
+ { 29, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 105 },
+ { 0, 17, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 105 },
+ { 0, 17, 1, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 105 },
+ { 25, 0, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 105 },
+ { 10, 18, 0, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 23, 4, 2, 2 },
+ { 0, 17, 0, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 29, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 0, 0, 0, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 0, 0, 0, -1, 0, 5, 3, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 1, 0, 216, 0, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 2 },
+ { 1, 0, 216, 0, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 2 },
+ { 0, 17, 1, 5, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 1, 0, 226, 0, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 8, 4, 23, 4, 1, 2 },
+ { 10, 18, 0, 5, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 3, 6, 23, 4, 0, 2 },
+ { 0, 17, 220, 5, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 0, 17, 230, 5, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 1 },
+ { 29, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 0, 17, 230, 5, -1, 0, 8, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 4 },
+ { 5, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 0, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 5, 0, 0, 0, -1, 0, 9, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 14, 0, 0, 0, -1, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 3, 2 },
+ { 15, 0, 0, 0, -1, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 2 },
+ { 15, 0, 0, 0, -1, 0, 7, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 2 },
+ { 26, 0, 0, 0, -1, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 26, 10, 0, 0, -1, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 14, 0, 0, 0, -1, 0, 9, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 3, 2 },
+ { 15, 0, 0, 0, -1, 0, 9, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 2 },
+ { 3, 2, 0, 0, 0, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 3, 2 },
+ { 3, 2, 0, 0, 1, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 3, 2 },
+ { 3, 2, 0, 0, 2, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 3, 2 },
+ { 3, 2, 0, 0, 3, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 3, 2 },
+ { 3, 2, 0, 0, 4, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 3, 2 },
+ { 3, 2, 0, 0, 5, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 3, 2 },
+ { 3, 2, 0, 0, 6, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 3, 2 },
+ { 3, 2, 0, 0, 7, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 3, 2 },
+ { 3, 2, 0, 0, 8, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 3, 2 },
+ { 3, 2, 0, 0, 9, 0, 5, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 3, 2 },
+ { 29, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 131 },
+ { 0, 17, 0, 5, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 131 },
+ { 25, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 0, 1, 131 },
+ { 25, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 19, 12, 1, 131 },
+ { 25, 0, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 131 },
+ { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 3 },
+ { 15, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 1, 3 },
+ { 0, 17, 230, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 57 },
+ { 17, 0, 0, 0, -1, 0, 25, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 6, 3, 5 },
+ { 0, 17, 230, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 5 },
+ { 18, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 151 },
+ { 0, 17, 230, 5, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 151 },
+ { 17, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 151 },
+ { 3, 0, 0, 0, 0, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 151 },
+ { 3, 0, 0, 0, 1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 151 },
+ { 3, 0, 0, 0, 2, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 151 },
+ { 3, 0, 0, 0, 3, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 151 },
+ { 3, 0, 0, 0, 4, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 151 },
+ { 3, 0, 0, 0, 5, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 151 },
+ { 3, 0, 0, 0, 6, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 151 },
+ { 3, 0, 0, 0, 7, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 151 },
+ { 3, 0, 0, 0, 8, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 151 },
+ { 3, 0, 0, 0, 9, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 151 },
+ { 29, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 151 },
+ { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 160 },
+ { 0, 17, 230, 5, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 160 },
+ { 18, 0, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 152 },
+ { 0, 17, 230, 5, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 152 },
+ { 3, 0, 0, 0, 0, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 152 },
+ { 3, 0, 0, 0, 1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 152 },
+ { 3, 0, 0, 0, 2, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 152 },
+ { 3, 0, 0, 0, 3, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 152 },
+ { 3, 0, 0, 0, 4, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 152 },
+ { 3, 0, 0, 0, 5, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 152 },
+ { 3, 0, 0, 0, 6, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 152 },
+ { 3, 0, 0, 0, 7, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 152 },
+ { 3, 0, 0, 0, 8, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 152 },
+ { 3, 0, 0, 0, 9, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 152 },
+ { 27, 4, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 11, 0, 1, 152 },
+ { 18, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 163 },
+ { 17, 0, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 163 },
+ { 0, 17, 232, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 163 },
+ { 0, 17, 220, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 163 },
+ { 0, 17, 230, 5, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 163 },
+ { 3, 0, 0, 0, 0, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 163 },
+ { 3, 0, 0, 0, 1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 163 },
+ { 3, 0, 0, 0, 2, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 163 },
+ { 3, 0, 0, 0, 3, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 163 },
+ { 3, 0, 0, 0, 4, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 163 },
+ { 3, 0, 0, 0, 5, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 163 },
+ { 3, 0, 0, 0, 6, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 163 },
+ { 3, 0, 0, 0, 7, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 163 },
+ { 3, 0, 0, 0, 8, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 163 },
+ { 3, 0, 0, 0, 9, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 163 },
+ { 18, 0, 0, 0, -1, 0, 24, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 27 },
+ { 18, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 113 },
+ { 5, 1, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 113 },
+ { 0, 17, 220, 5, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 113 },
+ { 14, 1, 0, 2, -1, 0, 18, 3, 0, { {0, 34}, {0, 0}, {0, 0}, {0, 34} }, 0, 10, 14, 7, 3, 132 },
+ { 15, 1, 0, 2, -1, 0, 18, 3, 0, { {0, 0}, {0, -34}, {0, -34}, {0, 0} }, 0, 10, 14, 6, 1, 132 },
+ { 0, 17, 230, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 132 },
+ { 0, 17, 7, 5, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 1, 132 },
+ { 17, 1, 0, 5, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 1, 132 },
+ { 3, 1, 0, 0, 0, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 132 },
+ { 3, 1, 0, 0, 1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 132 },
+ { 3, 1, 0, 0, 2, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 132 },
+ { 3, 1, 0, 0, 3, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 132 },
+ { 3, 1, 0, 0, 4, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 132 },
+ { 3, 1, 0, 0, 5, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 132 },
+ { 3, 1, 0, 0, 6, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 132 },
+ { 3, 1, 0, 0, 7, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 132 },
+ { 3, 1, 0, 0, 8, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 132 },
+ { 3, 1, 0, 0, 9, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 1, 132 },
{ 25, 1, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 0, 0, 1, 132 },
- { 5, 13, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 13, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 1, 2 },
- { 27, 13, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 10, 0, 1, 2 },
- { 5, 13, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 13, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 18, 13, 0, 0, -1, 0, 13, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 8, 3, 8 },
- { 26, 10, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 8 },
- { 29, 10, 0, 0, -1, 0, 10, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 13, 0, 0, 0, -1, 0, 0, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 0, 0 },
- { 5, 2, 0, 0, 0, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 2, 0, 0, 1, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 2, 0, 0, 2, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 2, 0, 0, 3, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 2, 0, 0, 4, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 2, 0, 0, 5, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 2, 0, 0, 6, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 2, 0, 0, 7, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 2, 0, 0, 8, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 2, 0, 0, 9, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 5, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 0, 0, 0, -1, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 2 },
- { 29, 0, 0, 0, -1, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 29, 0, 0, 0, -1, 0, 11, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 29, 10, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
- { 29, 0, 0, 0, -1, 0, 12, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 3, 2 },
- { 29, 0, 0, 0, -1, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 3, 2 },
- { 29, 0, 0, 0, -1, 0, 12, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 29, 0, 0, 0, -1, 0, 12, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 2 },
- { 29, 0, 0, 0, -1, 0, 11, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 12, 7, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 13, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 3, 2 },
- { 29, 10, 0, 0, -1, 0, 21, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 3, 2 },
- { 29, 0, 0, 0, -1, 0, 12, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 10, 12, 7, 1, 2 },
- { 29, 0, 0, 0, -1, 0, 11, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 10, 12, 7, 1, 2 },
- { 29, 0, 0, 0, -1, 0, 11, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 0, 0, 0, -1, 0, 12, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
- { 29, 0, 0, 0, -1, 0, 12, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 0, 0, 0, -1, 0, 18, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 6, 7, 28, 0, 1, 2 },
- { 29, 0, 0, 0, -1, 0, 11, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 34 },
- { 29, 0, 0, 0, -1, 0, 12, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 3, 2 },
- { 29, 0, 0, 0, -1, 0, 11, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 3, 2 },
- { 29, 0, 0, 0, -1, 0, 18, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
- { 29, 10, 0, 0, -1, 0, 19, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 17, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 16, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 30, 0, 1, 2 },
- { 28, 10, 0, 0, -1, 0, 17, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 31, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 18, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 30, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 16, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 30, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 18, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 13, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 3, 13, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 5, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 21, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 23, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 25, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 24, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 20, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
+ { 5, 13, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 13, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
+ { 27, 13, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 1, 2 },
+ { 5, 13, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 13, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 18, 13, 0, 0, -1, 0, 13, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 8, 3, 8 },
+ { 26, 10, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 8 },
+ { 29, 10, 0, 0, -1, 0, 10, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 13, 0, 0, 0, -1, 0, 0, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 0, 0 },
+ { 5, 2, 0, 0, 0, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 2, 0, 0, 1, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 2, 0, 0, 2, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 2, 0, 0, 3, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 2, 0, 0, 4, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 2, 0, 0, 5, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 2, 0, 0, 6, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 2, 0, 0, 7, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 2, 0, 0, 8, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 2, 0, 0, 9, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 5, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 23, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 0, 0, 0, -1, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 2 },
+ { 29, 0, 0, 0, -1, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 29, 0, 0, 0, -1, 0, 11, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
{ 29, 10, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 23, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 30, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 21, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 30, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 17, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 30, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 19, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 30, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 20, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 30, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 12, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 24, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 30, 0, 1, 2 },
- { 29, 10, 0, 0, -1, 0, 25, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 30, 0, 1, 2 },
- { 3, 2, 0, 0, 0, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 3, 2 },
- { 3, 2, 0, 0, 1, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 3, 2 },
- { 3, 2, 0, 0, 2, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 3, 2 },
- { 3, 2, 0, 0, 3, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 3, 2 },
- { 3, 2, 0, 0, 4, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 3, 2 },
- { 3, 2, 0, 0, 5, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 3, 2 },
- { 3, 2, 0, 0, 6, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 3, 2 },
- { 3, 2, 0, 0, 7, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 3, 2 },
- { 3, 2, 0, 0, 8, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 3, 2 },
- { 3, 2, 0, 0, 9, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 11, 9, 3, 2 },
- { 13, 18, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 0 },
- { 18, 0, 0, 0, -1, 0, 5, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 37 },
- { 18, 0, 0, 0, -1, 0, 25, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 37 },
- { 18, 0, 0, 0, -1, 0, 12, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 1, 37 },
- { 18, 0, 0, 0, -1, 0, 5, 5, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 3, 37 },
- { 18, 0, 0, 0, -1, 0, 5, 5, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 8, 0, 37 },
- { 10, 18, 0, 5, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 0, 2 },
- { 0, 17, 0, 5, -1, 0, 7, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 21, 4, 2, 1 },
- { 12, 0, 0, 0, -1, 0, 2, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 12, 0, 0, 0 }
+ { 29, 0, 0, 0, -1, 0, 12, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 3, 2 },
+ { 29, 0, 0, 0, -1, 0, 11, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 3, 2 },
+ { 29, 0, 0, 0, -1, 0, 12, 0, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 29, 0, 0, 0, -1, 0, 12, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 2 },
+ { 29, 0, 0, 0, -1, 0, 11, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 10, 14, 7, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 13, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 3, 2 },
+ { 29, 10, 0, 0, -1, 0, 21, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 3, 2 },
+ { 29, 0, 0, 0, -1, 0, 12, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 10, 14, 7, 1, 2 },
+ { 29, 0, 0, 0, -1, 0, 11, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 10, 14, 7, 1, 2 },
+ { 29, 0, 0, 0, -1, 0, 11, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 0, 0, 0, -1, 0, 12, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
+ { 29, 0, 0, 0, -1, 0, 12, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 0, 0, 0, -1, 0, 18, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 0, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 6, 7, 30, 0, 1, 2 },
+ { 29, 0, 0, 0, -1, 0, 11, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 3, 34 },
+ { 29, 0, 0, 0, -1, 0, 12, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 3, 2 },
+ { 29, 0, 0, 0, -1, 0, 11, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 3, 2 },
+ { 29, 0, 0, 0, -1, 0, 18, 5, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 3, 2 },
+ { 29, 10, 0, 0, -1, 0, 19, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 17, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 16, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 32, 0, 1, 2 },
+ { 28, 10, 0, 0, -1, 0, 17, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 33, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 13, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 17, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 18, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 32, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 16, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 32, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 18, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 13, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 3, 13, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 16, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 7, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 19, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 21, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 23, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 25, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 24, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 20, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 12, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 25, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 20, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 23, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 32, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 21, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 32, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 17, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 32, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 19, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 32, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 18, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 20, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 32, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 21, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 14, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 24, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 32, 0, 1, 2 },
+ { 29, 10, 0, 0, -1, 0, 25, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 14, 0, 32, 0, 1, 2 },
+ { 3, 2, 0, 0, 0, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 3, 2 },
+ { 3, 2, 0, 0, 1, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 3, 2 },
+ { 3, 2, 0, 0, 2, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 3, 2 },
+ { 3, 2, 0, 0, 3, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 3, 2 },
+ { 3, 2, 0, 0, 4, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 3, 2 },
+ { 3, 2, 0, 0, 5, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 3, 2 },
+ { 3, 2, 0, 0, 6, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 3, 2 },
+ { 3, 2, 0, 0, 7, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 3, 2 },
+ { 3, 2, 0, 0, 8, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 3, 2 },
+ { 3, 2, 0, 0, 9, 0, 23, 3, 80, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 16, 13, 9, 3, 2 },
+ { 13, 18, 0, 0, -1, 0, 2, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 0 },
+ { 18, 0, 0, 0, -1, 0, 5, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 37 },
+ { 18, 0, 0, 0, -1, 0, 25, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 37 },
+ { 18, 0, 0, 0, -1, 0, 12, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 37 },
+ { 18, 0, 0, 0, -1, 0, 26, 5, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 1, 37 },
+ { 18, 0, 0, 0, -1, 0, 5, 5, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 3, 37 },
+ { 18, 0, 0, 0, -1, 0, 5, 5, 85, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 16, 8, 0, 37 },
+ { 10, 18, 0, 5, -1, 0, 5, 3, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 0, 2 },
+ { 0, 17, 0, 5, -1, 0, 7, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 4, 4, 23, 4, 2, 1 },
+ { 12, 0, 0, 0, -1, 0, 2, 0, 0, { {0, 0}, {0, 0}, {0, 0}, {0, 0} }, 0, 0, 14, 0, 0, 0 }
};
Q_DECL_CONST_FUNCTION static inline const Properties *qGetProp(char32_t ucs4) noexcept
@@ -16091,7 +16165,7 @@ static constexpr IdnaMapEntry idnaMap[] = {
{ 0x1e94, 1, { 0x1e95, 0 } },
{ 0x1e9a, 2, { 0x61, 0x2be } },
{ 0x1e9b, 1, { 0x1e61, 0 } },
- { 0x1e9e, 2, { 0x73, 0x73 } },
+ { 0x1e9e, 1, { 0xdf, 0 } },
{ 0x1ea0, 1, { 0x1ea1, 0 } },
{ 0x1ea2, 1, { 0x1ea3, 0 } },
{ 0x1ea4, 1, { 0x1ea5, 0 } },
diff --git a/src/corelib/text/qunicodetables_p.h b/src/corelib/text/qunicodetables_p.h
index 0cf18a98c1..eabdc919cb 100644
--- a/src/corelib/text/qunicodetables_p.h
+++ b/src/corelib/text/qunicodetables_p.h
@@ -1,7 +1,7 @@
// Copyright (C) 2020 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: Unicode-DFS-2016
-/* This file is autogenerated from the Unicode 14.0 database. Do not edit */
+/* This file is autogenerated from the Unicode 15.1 database. Do not edit */
//
// W A R N I N G
@@ -23,7 +23,7 @@
QT_BEGIN_NAMESPACE
-#define UNICODE_DATA_VERSION QChar::Unicode_14_0
+#define UNICODE_DATA_VERSION QChar::Unicode_15_1
namespace QUnicodeTables {
@@ -142,9 +142,11 @@ enum SentenceBreakClass {
};
// see http://www.unicode.org/reports/tr14/tr14-30.html
-// we don't use the XX and AI classes and map them to AL instead.
+// we don't use the XX, AK, AP, AS and AI classes and map them to AL instead.
+// VI and VF classes are mapped to CM.
enum LineBreakClass {
- LineBreak_OP, LineBreak_CL, LineBreak_CP, LineBreak_QU, LineBreak_GL,
+ LineBreak_OP, LineBreak_CL, LineBreak_CP,
+ LineBreak_QU, LineBreak_QU_Pi, LineBreak_QU_Pf, LineBreak_GL,
LineBreak_NS, LineBreak_EX, LineBreak_SY, LineBreak_IS, LineBreak_PR,
LineBreak_PO, LineBreak_NU, LineBreak_AL, LineBreak_HL, LineBreak_ID,
LineBreak_IN, LineBreak_HY, LineBreak_BA, LineBreak_BB, LineBreak_B2,
diff --git a/src/corelib/text/qunicodetools.cpp b/src/corelib/text/qunicodetools.cpp
index 59cf6f7634..2917804830 100644
--- a/src/corelib/text/qunicodetools.cpp
+++ b/src/corelib/text/qunicodetools.cpp
@@ -559,45 +559,49 @@ enum Action {
IndirectBreakIfNarrow, IN = IndirectBreakIfNarrow, // For LB30
};
+// See https://www.unicode.org/reports/tr14/tr14-37.html for the information
+// about the table. It was removed in the later versions of the standard.
static const uchar breakTable[QUnicodeTables::LineBreak_ZWJ][QUnicodeTables::LineBreak_ZWJ] = {
-/* OP CL CP QU GL NS EX SY IS PR PO NU AL HL ID IN HY BA BB B2 ZW CM WJ H2 H3 JL JV JT RI CB EB EM*/
-/* OP */ { PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, CP, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB },
-/* CL */ { DB, PB, PB, IB, IB, PB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
-/* CP */ { DB, PB, PB, IB, IB, PB, PB, PB, PB, DB, DB, IB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
-/* QU */ { PB, PB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB },
-/* GL */ { IB, PB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB },
-/* NS */ { DB, PB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
-/* EX */ { DB, PB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
-/* SY */ { DB, PB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
-/* IS */ { DB, PB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
-/* PR */ { DB, PB, PB, IB, IB, IB, PB, PB, PB, DB, DB, IB, IB, IB, IB, IB, IB, IB, DB, DB, PB, CI, PB, IB, IB, IB, IB, IB, DB, DB, IB, IB },
-/* PO */ { DB, PB, PB, IB, IB, IB, PB, PB, PB, DB, DB, IB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
-/* NU */ { IN, PB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
-/* AL */ { IN, PB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
-/* HL */ { IN, PB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, DB, IB, CI, CI, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
-/* ID */ { DB, PB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
-/* IN */ { DB, PB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
-/* HY */ { HH, PB, PB, IB, HH, IB, PB, PB, PB, HH, HH, IB, HH, HH, HH, IB, IB, IB, HH, HH, PB, CI, PB, HH, HH, HH, HH, HH, HH, DB, DB, DB },
-/* BA */ { HH, PB, PB, IB, HH, IB, PB, PB, PB, HH, HH, HH, HH, HH, HH, IB, IB, IB, HH, HH, PB, CI, PB, HH, HH, HH, HH, HH, HH, DB, DB, DB },
-/* BB */ { IB, PB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB, IB, DB, IB, IB },
-/* B2 */ { DB, PB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, IB, DB, PB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
-/* ZW */ { DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
-/* CM */ { IB, PB, PB, IB, IB, IB, PB, PB, PB, DB, DB, IB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
-/* WJ */ { IB, PB, PB, IB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB },
-/* H2 */ { DB, PB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, IB, IB, DB, DB, DB, DB },
-/* H3 */ { DB, PB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, IB, DB, DB, DB, DB },
-/* JL */ { DB, PB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, IB, IB, IB, IB, DB, DB, DB, DB, DB },
-/* JV */ { DB, PB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, IB, IB, DB, DB, DB, DB },
-/* JT */ { DB, PB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, IB, DB, DB, DB, DB },
-/* RI */ { DB, PB, PB, IB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, IB, DB, DB, DB },
-/* CB */ { DB, PB, PB, IB, IB, DB, PB, PB, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
-/* EB */ { DB, PB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, IB },
-/* EM */ { DB, PB, PB, IB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
+/* 1↓ 2→ OP CL CP QU +Pi +Pf GL NS EX SY IS PR PO NU AL HL ID IN HY BA BB B2 ZW CM WJ H2 H3 JL JV JT RI CB EB EM*/
+/* OP */ { PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, CP, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB },
+/* CL */ { DB, PB, PB, IB, IB, PB, IB, PB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
+/* CP */ { DB, PB, PB, IB, IB, PB, IB, PB, PB, PB, PB, DB, DB, IB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
+/* QU */ { IB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB },
+/* +Pi*/ { PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB, CP, PB, PB, PB, PB, PB, PB, PB, PB, PB, PB },
+/* +Pf*/ { IB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB },
+/* GL */ { IB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB },
+/* NS */ { DB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
+/* EX */ { DB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
+/* SY */ { DB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, DB, DB, DB, DB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
+/* IS */ { DB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, DB, DB, DB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
+/* PR */ { DB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, DB, DB, IB, IB, IB, IB, IB, IB, IB, DB, DB, PB, CI, PB, IB, IB, IB, IB, IB, DB, DB, IB, IB },
+/* PO */ { DB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, DB, DB, IB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
+/* NU */ { IN, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
+/* AL */ { IN, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
+/* HL */ { IN, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, DB, IB, CI, CI, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
+/* ID */ { DB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
+/* IN */ { DB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
+/* HY */ { HH, PB, PB, IB, IB, PB, HH, IB, PB, PB, PB, HH, HH, IB, HH, HH, HH, IB, IB, IB, HH, HH, PB, CI, PB, HH, HH, HH, HH, HH, HH, DB, DB, DB },
+/* BA */ { HH, PB, PB, IB, IB, PB, HH, IB, PB, PB, PB, HH, HH, HH, HH, HH, HH, IB, IB, IB, HH, HH, PB, CI, PB, HH, HH, HH, HH, HH, HH, DB, DB, DB },
+/* BB */ { IB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB, IB, DB, IB, IB },
+/* B2 */ { DB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, IB, DB, PB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
+/* ZW */ { DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
+/* CM */ { IB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, DB, DB, IB, IB, IB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
+/* WJ */ { IB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, IB, PB, CI, PB, IB, IB, IB, IB, IB, IB, IB, IB, IB },
+/* H2 */ { DB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, IB, IB, DB, DB, DB, DB },
+/* H3 */ { DB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, IB, DB, DB, DB, DB },
+/* JL */ { DB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, IB, IB, IB, IB, DB, DB, DB, DB, DB },
+/* JV */ { DB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, IB, IB, DB, DB, DB, DB },
+/* JT */ { DB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, IB, DB, DB, DB, DB },
+/* RI */ { DB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, DB, DB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, IB, DB, DB, DB },
+/* CB */ { DB, PB, PB, IB, IB, PB, IB, DB, PB, PB, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
+/* EB */ { DB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, IB },
+/* EM */ { DB, PB, PB, IB, IB, PB, IB, IB, PB, PB, PB, DB, IB, DB, DB, DB, DB, IB, IB, IB, DB, DB, PB, CI, PB, DB, DB, DB, DB, DB, DB, DB, DB, DB },
};
// The following line break classes are not treated by the pair table
// and must be resolved outside:
-// AI, BK, CB, CJ, CR, LF, NL, ZWJ, SA, SG, SP, XX
+// AI, AK, AP, AS, BK, CB, CJ, CR, LF, NL, SA, SG, SP, VF, VI, XX, ZWJ
} // namespace LB
@@ -657,6 +661,61 @@ static void getLineBreaks(const char16_t *string, qsizetype len, QCharAttributes
ncls = QUnicodeTables::LineBreak_CM;
}
+ if (Q_UNLIKELY(ncls == QUnicodeTables::LineBreak_QU)) {
+ if (prop->category == QChar::Punctuation_InitialQuote) {
+ // LB15a: Do not break after an unresolved initial punctuation
+ // that lies at the start of the line, after a space, after
+ // opening punctuation, or after an unresolved quotation mark,
+ // even after spaces.
+ // (sot | BK | CR | LF | NL | OP | QU | GL | SP | ZW)
+ // [\p{Pi}&QU] SP* ×
+ // Note: sot is treated as LF here due to initial loop setup.
+ constexpr QUnicodeTables::LineBreakClass lb15a[] = {
+ QUnicodeTables::LineBreak_BK, QUnicodeTables::LineBreak_CR,
+ QUnicodeTables::LineBreak_LF, QUnicodeTables::LineBreak_OP,
+ QUnicodeTables::LineBreak_QU, QUnicodeTables::LineBreak_QU_Pi,
+ QUnicodeTables::LineBreak_QU_Pf, QUnicodeTables::LineBreak_GL,
+ QUnicodeTables::LineBreak_SP, QUnicodeTables::LineBreak_ZW};
+ if (std::any_of(std::begin(lb15a), std::end(lb15a),
+ [lcls](auto x) { return x == lcls; })) {
+ ncls = QUnicodeTables::LineBreak_QU_Pi;
+ }
+ } else if (prop->category == QChar::Punctuation_FinalQuote) {
+ // LB15b: Do not break before an unresolved final punctuation
+ // that lies at the end of the line, before a space, before
+ // a prohibited break, or before an unresolved quotation mark,
+ // even after spaces.
+ // × [\p{Pf}&QU] ( SP | GL | WJ | CL | QU | CP | EX | IS
+ // | SY | BK | CR | LF | NL | ZW | eot)
+ auto nncls = QUnicodeTables::LineBreak_LF;
+
+ if (i + 1 < len) {
+ char32_t c = string[i + 1];
+ if (QChar::isHighSurrogate(c) && i + 2 != len) {
+ ushort low = string[i + 2];
+ if (QChar::isLowSurrogate(low))
+ c = QChar::surrogateToUcs4(c, low);
+ }
+ nncls = QUnicodeTables::LineBreakClass(
+ QUnicodeTables::properties(c)->lineBreakClass);
+ }
+
+ constexpr QUnicodeTables::LineBreakClass lb15b[] = {
+ QUnicodeTables::LineBreak_SP, QUnicodeTables::LineBreak_GL,
+ QUnicodeTables::LineBreak_WJ, QUnicodeTables::LineBreak_CL,
+ QUnicodeTables::LineBreak_QU, QUnicodeTables::LineBreak_QU_Pi,
+ QUnicodeTables::LineBreak_QU_Pf, QUnicodeTables::LineBreak_CP,
+ QUnicodeTables::LineBreak_EX, QUnicodeTables::LineBreak_IS,
+ QUnicodeTables::LineBreak_SY, QUnicodeTables::LineBreak_BK,
+ QUnicodeTables::LineBreak_CR, QUnicodeTables::LineBreak_LF,
+ QUnicodeTables::LineBreak_ZW};
+ if (std::any_of(std::begin(lb15b), std::end(lb15b),
+ [nncls](auto x) { return x == nncls; })) {
+ ncls = QUnicodeTables::LineBreak_QU_Pf;
+ }
+ }
+ }
+
if (Q_UNLIKELY(lcls >= QUnicodeTables::LineBreak_CR)) {
// LB4: BK!, LB5: (CRxLF|CR|LF|NL)!
if (lcls > QUnicodeTables::LineBreak_CR || ncls != QUnicodeTables::LineBreak_LF)
@@ -1355,6 +1414,7 @@ static qsizetype indic_nextSyllableBoundary(QChar::Script script, const char16_t
// ### needs proper testing for correct two/three part matras
break;
}
+ Q_FALLTHROUGH();
case IndependentVowel:
case Invalid:
case Other:
diff --git a/src/corelib/text/qutf8stringview.h b/src/corelib/text/qutf8stringview.h
index 9d7f01b708..fe105e283e 100644
--- a/src/corelib/text/qutf8stringview.h
+++ b/src/corelib/text/qutf8stringview.h
@@ -11,8 +11,10 @@
#include <QtCore/qstringfwd.h>
#include <QtCore/qarraydata.h> // for QContainerImplHelper
#include <QtCore/qbytearrayview.h>
+#include <QtCore/qcompare.h>
#include <string>
+#include <string_view>
#include <QtCore/q20type_traits.h>
QT_BEGIN_NAMESPACE
@@ -201,13 +203,13 @@ public:
[[nodiscard]] inline QString toString() const; // defined in qstring.h
[[nodiscard]] constexpr qsizetype size() const noexcept { return m_size; }
- [[nodiscard]] const_pointer data() const noexcept { return reinterpret_cast<const_pointer>(m_data); }
+ [[nodiscard]] constexpr const_pointer data() const noexcept { return m_data; }
#ifdef __cpp_char8_t
[[nodiscard]] const char8_t *utf8() const noexcept { return reinterpret_cast<const char8_t*>(m_data); }
#endif
[[nodiscard]] constexpr storage_type operator[](qsizetype n) const
- { return Q_ASSERT(n >= 0), Q_ASSERT(n < size()), m_data[n]; }
+ { verify(n, 1); return m_data[n]; }
//
// QString API
@@ -238,20 +240,20 @@ public:
}
[[nodiscard]] constexpr QBasicUtf8StringView sliced(qsizetype pos) const
- { verify(pos); return QBasicUtf8StringView{m_data + pos, m_size - pos}; }
+ { verify(pos, 0); return QBasicUtf8StringView{m_data + pos, m_size - pos}; }
[[nodiscard]] constexpr QBasicUtf8StringView sliced(qsizetype pos, qsizetype n) const
{ verify(pos, n); return QBasicUtf8StringView(m_data + pos, n); }
[[nodiscard]] constexpr QBasicUtf8StringView first(qsizetype n) const
- { verify(n); return QBasicUtf8StringView(m_data, n); }
+ { verify(0, n); return sliced(0, n); }
[[nodiscard]] constexpr QBasicUtf8StringView last(qsizetype n) const
- { verify(n); return QBasicUtf8StringView(m_data + m_size - n, n); }
+ { verify(0, n); return sliced(m_size - n, n); }
[[nodiscard]] constexpr QBasicUtf8StringView chopped(qsizetype n) const
- { verify(n); return QBasicUtf8StringView(m_data, m_size - n); }
+ { verify(0, n); return sliced(0, m_size - n); }
constexpr void truncate(qsizetype n)
- { verify(n); m_size = n; }
+ { verify(0, n); m_size = n; }
constexpr void chop(qsizetype n)
- { verify(n); m_size -= n; }
+ { verify(0, n); m_size -= n; }
[[nodiscard]] inline bool isValidUtf8() const noexcept
{
@@ -274,6 +276,9 @@ public:
[[nodiscard]] constexpr storage_type front() const { return Q_ASSERT(!empty()), m_data[0]; }
[[nodiscard]] constexpr storage_type back() const { return Q_ASSERT(!empty()), m_data[m_size - 1]; }
+ [[nodiscard]] Q_IMPLICIT operator std::basic_string_view<storage_type>() const noexcept
+ { return std::basic_string_view<storage_type>(data(), size_t(size())); }
+
//
// Qt compatibility API:
//
@@ -288,10 +293,19 @@ public:
return QtPrivate::compareStrings(*this, other, cs);
}
+ [[nodiscard]] int compare(QChar other,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
[[nodiscard]] int compare(QStringView other,
Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
[[nodiscard]] int compare(QLatin1StringView other,
Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
+ [[nodiscard]] int compare(const QByteArray &other,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
+
+ [[nodiscard]] bool equal(QChar other) const noexcept;
+ [[nodiscard]] bool equal(QStringView other) const noexcept;
+ [[nodiscard]] bool equal(QLatin1StringView other) const noexcept;
+ [[nodiscard]] bool equal(const QByteArray &other) const noexcept;
private:
[[nodiscard]] static inline int compare(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept
@@ -300,30 +314,96 @@ private:
QBasicUtf8StringView<false>(rhs.data(), rhs.size()));
}
- [[nodiscard]] friend inline bool operator==(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept
+ friend bool
+ comparesEqual(const QBasicUtf8StringView &lhs, const QBasicUtf8StringView &rhs) noexcept
{
return lhs.size() == rhs.size()
- && QtPrivate::equalStrings(QBasicUtf8StringView<false>(lhs.data(), lhs.size()),
- QBasicUtf8StringView<false>(rhs.data(), rhs.size()));
+ && QtPrivate::equalStrings(QBasicUtf8StringView<false>(lhs.data(), lhs.size()),
+ QBasicUtf8StringView<false>(rhs.data(), rhs.size()));
}
- [[nodiscard]] friend inline bool operator!=(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept
- { return !operator==(lhs, rhs); }
+ friend Qt::strong_ordering
+ compareThreeWay(const QBasicUtf8StringView &lhs, const QBasicUtf8StringView &rhs) noexcept
+ {
+ const int res = QBasicUtf8StringView::compare(lhs, rhs);
+ return Qt::compareThreeWay(res, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QBasicUtf8StringView)
-#ifdef __cpp_impl_three_way_comparison
- [[nodiscard]] friend inline auto operator<=>(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept
- { return QBasicUtf8StringView::compare(lhs, rhs) <=> 0; }
-#else
- [[nodiscard]] friend inline bool operator<=(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept
- { return QBasicUtf8StringView::compare(lhs, rhs) <= 0; }
- [[nodiscard]] friend inline bool operator>=(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept
- { return QBasicUtf8StringView::compare(lhs, rhs) >= 0; }
- [[nodiscard]] friend inline bool operator<(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept
- { return QBasicUtf8StringView::compare(lhs, rhs) < 0; }
- [[nodiscard]] friend inline bool operator>(QBasicUtf8StringView lhs, QBasicUtf8StringView rhs) noexcept
- { return QBasicUtf8StringView::compare(lhs, rhs) > 0; }
-#endif
+ friend bool
+ comparesEqual(const QBasicUtf8StringView &lhs, const QLatin1StringView &rhs) noexcept
+ {
+ return lhs.equal(rhs);
+ }
+ friend Qt::strong_ordering
+ compareThreeWay(const QBasicUtf8StringView &lhs, const QLatin1StringView &rhs) noexcept
+ {
+ const int res = lhs.compare(rhs);
+ return Qt::compareThreeWay(res, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QBasicUtf8StringView, QLatin1StringView)
+
+ friend bool
+ comparesEqual(const QBasicUtf8StringView &lhs, const QStringView &rhs) noexcept
+ { return lhs.equal(rhs); }
+ friend Qt::strong_ordering
+ compareThreeWay(const QBasicUtf8StringView &lhs, const QStringView &rhs) noexcept
+ {
+ const int res = lhs.compare(rhs);
+ return Qt::compareThreeWay(res, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QBasicUtf8StringView, QStringView)
- Q_ALWAYS_INLINE constexpr void verify(qsizetype pos, qsizetype n = 0) const
+ friend bool comparesEqual(const QBasicUtf8StringView &lhs, const QChar &rhs) noexcept
+ { return lhs.equal(rhs); }
+ friend Qt::strong_ordering
+ compareThreeWay(const QBasicUtf8StringView &lhs, const QChar &rhs) noexcept
+ {
+ const int res = lhs.compare(rhs);
+ return Qt::compareThreeWay(res, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QBasicUtf8StringView, QChar)
+ Q_DECLARE_STRONGLY_ORDERED(QBasicUtf8StringView, char16_t)
+
+#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
+ friend bool
+ comparesEqual(const QBasicUtf8StringView &lhs, const QByteArrayView &rhs) noexcept
+ {
+ return lhs.size() == rhs.size()
+ && QtPrivate::equalStrings(QBasicUtf8StringView<false>(lhs.data(), lhs.size()),
+ QBasicUtf8StringView<false>(rhs.data(), rhs.size()));
+ }
+ friend Qt::strong_ordering
+ compareThreeWay(const QBasicUtf8StringView &lhs, const QByteArrayView &rhs) noexcept
+ {
+ const int res = QtPrivate::compareStrings(QBasicUtf8StringView<false>(lhs.data(), lhs.size()),
+ QBasicUtf8StringView<false>(rhs.data(), rhs.size()));
+ return Qt::compareThreeWay(res, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QBasicUtf8StringView, QByteArrayView, QT_ASCII_CAST_WARN)
+
+ friend bool
+ comparesEqual(const QBasicUtf8StringView &lhs, const QByteArray &rhs) noexcept
+ {
+ return lhs.equal(rhs);
+ }
+ friend Qt::strong_ordering
+ compareThreeWay(const QBasicUtf8StringView &lhs, const QByteArray &rhs) noexcept
+ {
+ const int res = lhs.compare(rhs);
+ return Qt::compareThreeWay(res, 0);
+ }
+ Q_DECLARE_STRONGLY_ORDERED(QBasicUtf8StringView, QByteArray, QT_ASCII_CAST_WARN)
+
+ friend bool comparesEqual(const QBasicUtf8StringView &lhs, const char *rhs) noexcept
+ { return comparesEqual(lhs, QByteArrayView(rhs)); }
+ friend Qt::strong_ordering
+ compareThreeWay(const QBasicUtf8StringView &lhs, const char *rhs) noexcept
+ { return compareThreeWay(lhs, QByteArrayView(rhs)); }
+ Q_DECLARE_STRONGLY_ORDERED(QBasicUtf8StringView, const char *, QT_ASCII_CAST_WARN)
+#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
+
+ Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos = 0,
+ [[maybe_unused]] qsizetype n = 1) const
{
Q_ASSERT(pos >= 0);
Q_ASSERT(pos <= size());
@@ -334,6 +414,10 @@ private:
qsizetype m_size;
};
+constexpr QByteArrayView::QByteArrayView(QUtf8StringView v) noexcept
+ : QByteArrayView(v.data(), v.size())
+{}
+
#ifdef Q_QDOC
#undef QBasicUtf8StringView
#else
@@ -342,7 +426,7 @@ Q_DECLARE_TYPEINFO_BODY(QBasicUtf8StringView<UseChar8T>, Q_PRIMITIVE_TYPE);
template <typename QStringLike, std::enable_if_t<std::is_same_v<QStringLike, QByteArray>, bool> = true>
[[nodiscard]] inline q_no_char8_t::QUtf8StringView qToUtf8StringViewIgnoringNull(const QStringLike &s) noexcept
-{ return q_no_char8_t::QUtf8StringView(s.data(), s.size()); }
+{ return q_no_char8_t::QUtf8StringView(s.begin(), s.size()); }
#endif // Q_QDOC
QT_END_NAMESPACE
diff --git a/src/corelib/text/qutf8stringview.qdoc b/src/corelib/text/qutf8stringview.qdoc
index 60ebe954ed..b433e5b995 100644
--- a/src/corelib/text/qutf8stringview.qdoc
+++ b/src/corelib/text/qutf8stringview.qdoc
@@ -11,6 +11,14 @@
\ingroup tools
\ingroup string-processing
+ \compares strong
+ \compareswith strong char16_t QChar {const char16_t *} QString QStringView \
+ QLatin1StringView
+ \endcompareswith
+ \compareswith strong {const char *} QByteArray QByteArrayView
+ The contents of byte arrays is interpreted as utf-8.
+ \endcompareswith
+
A QUtf8StringView references a contiguous portion of a UTF-8
string it does not own. It acts as an interface type to all kinds
of UTF-8 string, without the need to construct a QString or
@@ -217,7 +225,7 @@
*/
/*!
- \fn template <typename Char> QUtf8StringView::QUtf8StringView(const Char *str, qsizetype len)
+ \fn template <typename Char, QUtf8StringView::if_compatible_char<Char> = true> QUtf8StringView::QUtf8StringView(const Char *str, qsizetype len)
Constructs a string view on \a str with length \a len.
@@ -233,7 +241,7 @@
*/
/*!
- \fn template <typename Char> QUtf8StringView::QUtf8StringView(const Char *first, const Char *last)
+ \fn template <typename Char, QUtf8StringView::if_compatible_char<Char> = true> QUtf8StringView::QUtf8StringView(const Char *first, const Char *last)
Constructs a string view on \a first with length (\a last - \a first).
@@ -287,26 +295,26 @@
*/
/*!
- \fn template <typename Container, if_compatible_container<Container>> QUtf8StringView::QUtf8StringView(const Container &str)
+ \fn template <typename Container, QUtf8StringView::if_compatible_container<Container>> QUtf8StringView::QUtf8StringView(const Container &str)
- Constructs a string view on \a str. The length is taken from \c{str.size()}.
+ Constructs a string view on \a str. The length is taken from \c{std::size(str)}.
- \c{str.data()} must remain valid for the lifetime of this string view object.
+ \c{std::data(str)} must remain valid for the lifetime of this string view object.
- This constructor only participates in overload resolution if \c Container is an
- instantiation of \c std::basic_string with a compatible character type. The
+ This constructor only participates in overload resolution if \c Container is a
+ container with a compatible character type as \c{value_type}. The
compatible character types are: \c char8_t, \c char, \c{signed char} and
\c{unsigned char}.
- The string view will be empty if and only if \c{str.empty()}. It is unspecified
- whether this constructor can result in a null string view (\c{str.data()} would
+ The string view will be empty if and only if \c{std::size(str) == 0}. It is unspecified
+ whether this constructor can result in a null string view (\c{std::data(str)} would
have to return \nullptr for this).
\sa isNull(), isEmpty()
*/
/*!
- \fn template <typename Char, size_t Size, if_compatible_char<Char>> QUtf8StringView::fromArray(const Char (&string)[Size])
+ \fn template <typename Char, size_t Size, QUtf8StringView::if_compatible_char<Char>> QUtf8StringView::fromArray(const Char (&string)[Size])
Constructs a string view on the full character string literal \a string,
including any trailing \c{Char(0)}. If you don't want the
@@ -605,8 +613,10 @@
Returns a string view containing \a n code points of this string view,
starting at position \a pos.
+//! [UB-sliced-index-length]
\note The behavior is undefined when \a pos < 0, \a n < 0,
or \a pos + \a n > size().
+//! [UB-sliced-index-length]
\sa first(), last(), chopped(), chop(), truncate()
*/
@@ -617,7 +627,9 @@
Returns a string view starting at position \a pos in this object,
and extending to its end.
+//! [UB-sliced-index-only]
\note The behavior is undefined when \a pos < 0 or \a pos > size().
+//! [UB-sliced-index-only]
\sa first(), last(), chopped(), chop(), truncate()
*/
@@ -665,8 +677,9 @@
\fn int QUtf8StringView::compare(QStringView str, Qt::CaseSensitivity cs) const
\since 6.5
- Returns an integer that compares to zero as this string view compares to the
- string view \a str.
+ Compares this string view with \a str and returns a negative integer if
+ this string view is less than \a str, a positive integer if it is greater than
+ \a str, and zero if they are equal.
\include qstring.qdocinc {search-comparison-case-sensitivity} {comparison}
*/
@@ -695,3 +708,13 @@
\sa QByteArray::isNull(), QUtf8StringView
*/
+
+
+/*! \fn QUtf8StringView::operator std::basic_string_view<storage_type>() const
+ \since 6.7
+
+ Converts this QUtf8StringView object to a
+ \c{std::basic_string_view} object. The returned view will have the
+ same data pointer and length of this view. The character type of
+ the returned view will be \c{storage_type}.
+*/
diff --git a/src/corelib/thread/qatomic.cpp b/src/corelib/thread/qatomic.cpp
index 210218d72d..a437eb3319 100644
--- a/src/corelib/thread/qatomic.cpp
+++ b/src/corelib/thread/qatomic.cpp
@@ -32,8 +32,8 @@
The template parameter \c T must be a C++ integer type:
\list
\li 8-bit: bool, char, signed char, unsigned char, qint8, quint8, char8_t (C++20)
- \li 16-bit: short, unsigned short, qint16, quint16, char16_t (C++11)
- \li 32-bit: int, unsigned int, qint32, quint32, char32_t (C++11)
+ \li 16-bit: short, unsigned short, qint16, quint16, char16_t
+ \li 32-bit: int, unsigned int, qint32, quint32, char32_t
\li 64-bit: long long, unsigned long long, qint64, quint64
\li platform-specific size: long, unsigned long
\li pointer size: qintptr, quintptr, qptrdiff
@@ -1359,7 +1359,7 @@
\endlist
- \sa QAtomicInteger
+ \sa QAtomicInteger, qYieldCpu()
*/
/*!
diff --git a/src/corelib/thread/qatomic.h b/src/corelib/thread/qatomic.h
index 24f2616e82..7fe5ac69b9 100644
--- a/src/corelib/thread/qatomic.h
+++ b/src/corelib/thread/qatomic.h
@@ -2,8 +2,6 @@
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <QtCore/qglobal.h>
-
#ifndef QATOMIC_H
#define QATOMIC_H
diff --git a/src/corelib/thread/qatomic_cxx11.h b/src/corelib/thread/qatomic_cxx11.h
index 4f55a53ae3..47a7bc9a10 100644
--- a/src/corelib/thread/qatomic_cxx11.h
+++ b/src/corelib/thread/qatomic_cxx11.h
@@ -6,6 +6,7 @@
#define QATOMIC_CXX11_H
#include <QtCore/qgenericatomic.h>
+#include <QtCore/qyieldcpu.h>
#include <atomic>
QT_BEGIN_NAMESPACE
diff --git a/src/corelib/thread/qbasicatomic.h b/src/corelib/thread/qbasicatomic.h
index d03c270ed6..6d061ea49a 100644
--- a/src/corelib/thread/qbasicatomic.h
+++ b/src/corelib/thread/qbasicatomic.h
@@ -2,8 +2,6 @@
// Copyright (C) 2018 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <QtCore/qglobal.h>
-
#ifndef QBASICATOMIC_H
#define QBASICATOMIC_H
@@ -21,8 +19,6 @@ QT_END_NAMESPACE
#pragma qt_sync_stop_processing
#endif
-// New atomics
-
template <typename T>
class QBasicAtomicInteger
{
diff --git a/src/corelib/thread/qfutex_freebsd_p.h b/src/corelib/thread/qfutex_freebsd_p.h
new file mode 100644
index 0000000000..b31774d28d
--- /dev/null
+++ b/src/corelib/thread/qfutex_freebsd_p.h
@@ -0,0 +1,82 @@
+// Copyright (C) 2023 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QFUTEX_FREEBSD_P_H
+#define QFUTEX_FREEBSD_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 <private/qcore_unix_p.h>
+#include <qdeadlinetimer.h>
+
+// https://man.freebsd.org/cgi/man.cgi?query=_umtx_op
+#include <sys/umtx.h>
+
+#define QT_ALWAYS_USE_FUTEX
+
+QT_BEGIN_NAMESPACE
+
+namespace QtFreeBSDFutex {
+constexpr inline bool futexAvailable() { return true; }
+
+template <typename Atomic>
+inline int do_wait(Atomic &futex, typename Atomic::Type expectedValue, _umtx_time *tmp = nullptr)
+{
+ // FreeBSD UMTX_OP_WAIT does not apply acquire or release memory barriers,
+ // so there are no QtTsan calls here.
+
+ int op = UMTX_OP_WAIT_UINT_PRIVATE;
+ if (sizeof(futex) > sizeof(quint32))
+ op = UMTX_OP_WAIT; // no _PRIVATE version
+
+ // The timeout is passed in uaddr2, with its size in uaddr
+ void *uaddr = reinterpret_cast<void *>(tmp ? sizeof(*tmp) : 0);
+ void *uaddr2 = tmp;
+ int ret = _umtx_op(&futex, op, u_long(expectedValue), uaddr, uaddr2);
+
+ return ret;
+}
+
+template <typename Atomic>
+inline void futexWait(Atomic &futex, typename Atomic::Type expectedValue)
+{
+ do_wait(futex, expectedValue);
+}
+
+template <typename Atomic>
+inline bool futexWait(Atomic &futex, typename Atomic::Type expectedValue, QDeadlineTimer timer)
+{
+ struct _umtx_time tm = {};
+ auto deadline = timer.deadline<std::chrono::steady_clock>();
+ tm._timeout = durationToTimespec(deadline.time_since_epoch());
+ tm._flags = UMTX_ABSTIME;
+ tm._clockid = CLOCK_MONOTONIC;
+ int r = do_wait(futex, expectedValue, &tm);
+ return r == 0 || errno != ETIMEDOUT;
+}
+
+template <typename Atomic> inline void futexWakeOne(Atomic &futex)
+{
+ _umtx_op(&futex, UMTX_OP_WAKE_PRIVATE, 1, nullptr, nullptr);
+}
+
+template <typename Atomic> inline void futexWakeAll(Atomic &futex)
+{
+ _umtx_op(&futex, UMTX_OP_WAKE_PRIVATE, INT_MAX, nullptr, nullptr);
+}
+} //namespace QtFreeBSDFutex
+
+namespace QtFutex = QtFreeBSDFutex;
+
+QT_END_NAMESPACE
+
+#endif // QFUTEX_FREEBSD_P_H
diff --git a/src/corelib/thread/qfutex_linux_p.h b/src/corelib/thread/qfutex_linux_p.h
new file mode 100644
index 0000000000..e114dfca72
--- /dev/null
+++ b/src/corelib/thread/qfutex_linux_p.h
@@ -0,0 +1,95 @@
+// Copyright (C) 2023 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QFUTEX_LINUX_P_H
+#define QFUTEX_LINUX_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 <private/qcore_unix_p.h>
+#include <qdeadlinetimer.h>
+#include <qtsan_impl.h>
+
+#include <asm/unistd.h>
+#include <errno.h>
+#include <limits.h>
+#include <linux/futex.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+// RISC-V does not supply __NR_futex
+#ifndef __NR_futex
+# define __NR_futex __NR_futex_time64
+#endif
+
+#define QT_ALWAYS_USE_FUTEX
+
+QT_BEGIN_NAMESPACE
+
+namespace QtLinuxFutex {
+constexpr inline bool futexAvailable() { return true; }
+
+inline int _q_futex(int *addr, int op, int val, quintptr val2 = 0,
+ int *addr2 = nullptr, int val3 = 0) noexcept
+{
+ QtTsan::futexRelease(addr, addr2);
+
+ // we use __NR_futex because some libcs (like Android's bionic) don't
+ // provide SYS_futex etc.
+ int result = syscall(__NR_futex, addr, op | FUTEX_PRIVATE_FLAG, val, val2, addr2, val3);
+
+ QtTsan::futexAcquire(addr, addr2);
+
+ return result;
+}
+template <typename T> int *addr(T *ptr)
+{
+ int *int_addr = reinterpret_cast<int *>(ptr);
+#if Q_BYTE_ORDER == Q_BIG_ENDIAN
+ if (sizeof(T) > sizeof(int))
+ int_addr++; //We want a pointer to the least significant half
+#endif
+ return int_addr;
+}
+
+template <typename Atomic>
+inline void futexWait(Atomic &futex, typename Atomic::Type expectedValue)
+{
+ _q_futex(addr(&futex), FUTEX_WAIT, qintptr(expectedValue));
+}
+template <typename Atomic>
+inline bool futexWait(Atomic &futex, typename Atomic::Type expectedValue, QDeadlineTimer deadline)
+{
+ auto timeout = deadline.deadline<std::chrono::steady_clock>().time_since_epoch();
+ struct timespec ts = durationToTimespec(timeout);
+ int r = _q_futex(addr(&futex), FUTEX_WAIT_BITSET, qintptr(expectedValue), quintptr(&ts),
+ nullptr, FUTEX_BITSET_MATCH_ANY);
+ return r == 0 || errno != ETIMEDOUT;
+}
+template <typename Atomic> inline void futexWakeOne(Atomic &futex)
+{
+ _q_futex(addr(&futex), FUTEX_WAKE, 1);
+}
+template <typename Atomic> inline void futexWakeAll(Atomic &futex)
+{
+ _q_futex(addr(&futex), FUTEX_WAKE, INT_MAX);
+}
+template <typename Atomic> inline
+void futexWakeOp(Atomic &futex1, int wake1, int wake2, Atomic &futex2, quint32 op)
+{
+ _q_futex(addr(&futex1), FUTEX_WAKE_OP, wake1, wake2, addr(&futex2), op);
+}} // namespace QtLinuxFutex
+namespace QtFutex = QtLinuxFutex;
+
+QT_END_NAMESPACE
+
+#endif // QFUTEX_LINUX_P_H
diff --git a/src/corelib/thread/qfutex_mac_p.h b/src/corelib/thread/qfutex_mac_p.h
new file mode 100644
index 0000000000..0de08954ab
--- /dev/null
+++ b/src/corelib/thread/qfutex_mac_p.h
@@ -0,0 +1,140 @@
+// Copyright (C) 2023 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QFUTEX_MAC_P_H
+#define QFUTEX_MAC_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 <qdeadlinetimer.h>
+#include <qtsan_impl.h>
+#include <private/qglobal_p.h>
+
+// The Darwin kernel exposes a set of __ulock_{wait,wait2,wake} APIs in
+// https://github.com/apple-oss-distributions/xnu/blob/xnu-8792.81.2/bsd/sys/ulock.h,
+// but these APIs are marked as private, so we cannot rely on them being
+// stable, nor we can use these APIs in builds of Qt intended for
+// the Apple App Store. By wholesale disabling the use of the APIs
+// in App Store compliant builds, and runtime checking availability
+// of the APIs when we do build them in, we should be safe, unless
+// the semantics of the APIs change in ways we haven't accounted for,
+// but that's a risk we're willing to take.
+
+#if QT_CONFIG(appstore_compliant)
+QT_BEGIN_NAMESPACE
+namespace QtFutex = QtDummyFutex;
+QT_END_NAMESPACE
+#else
+
+extern "C" {
+// -------- BEGIN OS Declarations --------
+// Source: https://github.com/apple-oss-distributions/xnu/blob/xnu-8792.81.2/bsd/sys/ulock.h
+// Modification: added __attribute((__weak__))
+// Copyright (c) 2015 Apple Inc. All rights reserved.
+
+__attribute((__weak__))
+extern int __ulock_wait2(uint32_t operation, void *addr, uint64_t value,
+ uint64_t timeout, uint64_t value2);
+__attribute((__weak__))
+extern int __ulock_wake(uint32_t operation, void *addr, uint64_t wake_value);
+
+/*
+ * operation bits [7, 0] contain the operation code.
+ */
+#define UL_COMPARE_AND_WAIT 1
+#define UL_COMPARE_AND_WAIT_SHARED 3
+#define UL_COMPARE_AND_WAIT64 5
+#define UL_COMPARE_AND_WAIT64_SHARED 6
+
+/*
+ * operation bits [15, 8] contain the flags for __ulock_wake
+ */
+#define ULF_WAKE_ALL 0x00000100
+#define ULF_WAKE_THREAD 0x00000200
+#define ULF_WAKE_ALLOW_NON_OWNER 0x00000400
+
+/*
+ * operation bits [15, 8] contain the flags for __ulock_wake
+ */
+#define ULF_WAKE_ALL 0x00000100
+#define ULF_WAKE_THREAD 0x00000200
+#define ULF_WAKE_ALLOW_NON_OWNER 0x00000400
+
+/*
+ * operation bits [31, 24] contain the generic flags
+ */
+#define ULF_NO_ERRNO 0x01000000
+
+// -------- END OS Declarations --------
+} // extern "C"
+
+QT_BEGIN_NAMESPACE
+
+namespace QtDarwinFutex {
+
+/*not constexpr*/ inline bool futexAvailable() { return __ulock_wake && __ulock_wait2; }
+
+template <typename Atomic>
+inline uint32_t baseOperation(Atomic &)
+{
+ static_assert(sizeof(Atomic) >= sizeof(quint32), "Can only operate on 32- or 64-bit atomics");
+
+ uint32_t operation = ULF_NO_ERRNO;
+ if (sizeof(Atomic) == sizeof(quint32))
+ operation |= UL_COMPARE_AND_WAIT;
+ else
+ operation |= UL_COMPARE_AND_WAIT64;
+ return operation;
+}
+
+template <typename Atomic> inline int
+do_wait(Atomic &futex, typename Atomic::Type expectedValue, QDeadlineTimer timer)
+{
+ // source code inspection shows __ulock_wait2 uses nanoseconds for timeout
+ QtTsan::futexRelease(&futex);
+ int ret = __ulock_wait2(baseOperation(futex), &futex, uint64_t(expectedValue),
+ timer.remainingTimeNSecs(), 0);
+ QtTsan::futexAcquire(&futex);
+ return ret;
+}
+
+template <typename Atomic>
+inline void futexWait(Atomic &futex, typename Atomic::Type expectedValue)
+{
+ do_wait(futex, expectedValue, {});
+}
+
+template <typename Atomic>
+inline bool futexWait(Atomic &futex, typename Atomic::Type expectedValue, QDeadlineTimer timer)
+{
+ int r = do_wait(futex, expectedValue, timer);
+ return r == 0 || r != -ETIMEDOUT;
+}
+
+template <typename Atomic> inline void futexWakeAll(Atomic &futex)
+{
+ __ulock_wake(baseOperation(futex) | ULF_WAKE_ALL, &futex, 0);
+}
+
+template <typename Atomic> inline void futexWakeOne(Atomic &futex)
+{
+ __ulock_wake(baseOperation(futex), &futex, 0);
+}
+} //namespace QtDarwinMutex
+
+namespace QtFutex = QtDarwinFutex;
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(appstore_compliant)
+
+#endif // QFUTEX_MAC_P_H
diff --git a/src/corelib/thread/qfutex_p.h b/src/corelib/thread/qfutex_p.h
index 48f03f5ed0..8ba798f920 100644
--- a/src/corelib/thread/qfutex_p.h
+++ b/src/corelib/thread/qfutex_p.h
@@ -15,15 +15,15 @@
// We mean it.
//
+#include <qdeadlinetimer.h>
#include <private/qglobal_p.h>
-#include <QtCore/qtsan_impl.h>
QT_BEGIN_NAMESPACE
namespace QtDummyFutex {
constexpr inline bool futexAvailable() { return false; }
template <typename Atomic>
- inline bool futexWait(Atomic &, typename Atomic::Type, int = 0)
+ inline bool futexWait(Atomic &, typename Atomic::Type, QDeadlineTimer = {})
{ Q_UNREACHABLE_RETURN(false); }
template <typename Atomic> inline void futexWakeOne(Atomic &)
{ Q_UNREACHABLE(); }
@@ -33,115 +33,16 @@ namespace QtDummyFutex {
QT_END_NAMESPACE
-#if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
+#if defined(Q_OS_DARWIN)
+# include "qfutex_mac_p.h"
+#elif defined(Q_OS_FREEBSD)
+# include "qfutex_freebsd_p.h"
+#elif defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
// use Linux mutexes everywhere except for LSB builds
-# include <sys/syscall.h>
-# include <errno.h>
-# include <limits.h>
-# include <unistd.h>
-# include <asm/unistd.h>
-# include <linux/futex.h>
-# define QT_ALWAYS_USE_FUTEX
-
-// if not defined in linux/futex.h
-# define FUTEX_PRIVATE_FLAG 128 // added in v2.6.22
-
-// RISC-V does not supply __NR_futex
-# ifndef __NR_futex
-# define __NR_futex __NR_futex_time64
-# endif
-
-QT_BEGIN_NAMESPACE
-namespace QtLinuxFutex {
- constexpr inline bool futexAvailable() { return true; }
- inline int _q_futex(int *addr, int op, int val, quintptr val2 = 0,
- int *addr2 = nullptr, int val3 = 0) noexcept
- {
- QtTsan::futexRelease(addr, addr2);
-
- // we use __NR_futex because some libcs (like Android's bionic) don't
- // provide SYS_futex etc.
- int result = syscall(__NR_futex, addr, op | FUTEX_PRIVATE_FLAG, val, val2, addr2, val3);
-
- QtTsan::futexAcquire(addr, addr2);
-
- return result;
- }
- template <typename T> int *addr(T *ptr)
- {
- int *int_addr = reinterpret_cast<int *>(ptr);
-#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- if (sizeof(T) > sizeof(int))
- int_addr++; //We want a pointer to the least significant half
-#endif
- return int_addr;
- }
-
- template <typename Atomic>
- inline void futexWait(Atomic &futex, typename Atomic::Type expectedValue)
- {
- _q_futex(addr(&futex), FUTEX_WAIT, qintptr(expectedValue));
- }
- template <typename Atomic>
- inline bool futexWait(Atomic &futex, typename Atomic::Type expectedValue, qint64 nstimeout)
- {
- struct timespec ts;
- ts.tv_sec = nstimeout / 1000 / 1000 / 1000;
- ts.tv_nsec = nstimeout % (1000 * 1000 * 1000);
- int r = _q_futex(addr(&futex), FUTEX_WAIT, qintptr(expectedValue), quintptr(&ts));
- return r == 0 || errno != ETIMEDOUT;
- }
- template <typename Atomic> inline void futexWakeOne(Atomic &futex)
- {
- _q_futex(addr(&futex), FUTEX_WAKE, 1);
- }
- template <typename Atomic> inline void futexWakeAll(Atomic &futex)
- {
- _q_futex(addr(&futex), FUTEX_WAKE, INT_MAX);
- }
- template <typename Atomic> inline
- void futexWakeOp(Atomic &futex1, int wake1, int wake2, Atomic &futex2, quint32 op)
- {
- _q_futex(addr(&futex1), FUTEX_WAKE_OP, wake1, wake2, addr(&futex2), op);
- }
-}
-namespace QtFutex = QtLinuxFutex;
-QT_END_NAMESPACE
-
+# include "qfutex_linux_p.h"
#elif defined(Q_OS_WIN)
-# include <qt_windows.h>
-
-QT_BEGIN_NAMESPACE
-namespace QtWindowsFutex {
-#define QT_ALWAYS_USE_FUTEX
-constexpr inline bool futexAvailable() { return true; }
-
-template <typename Atomic>
-inline void futexWait(Atomic &futex, typename Atomic::Type expectedValue)
-{
- QtTsan::futexRelease(&futex);
- WaitOnAddress(&futex, &expectedValue, sizeof(expectedValue), INFINITE);
- QtTsan::futexAcquire(&futex);
-}
-template <typename Atomic>
-inline bool futexWait(Atomic &futex, typename Atomic::Type expectedValue, qint64 nstimeout)
-{
- BOOL r = WaitOnAddress(&futex, &expectedValue, sizeof(expectedValue), DWORD(nstimeout / 1000 / 1000));
- return r || GetLastError() != ERROR_TIMEOUT;
-}
-template <typename Atomic> inline void futexWakeAll(Atomic &futex)
-{
- WakeByAddressAll(&futex);
-}
-template <typename Atomic> inline void futexWakeOne(Atomic &futex)
-{
- WakeByAddressSingle(&futex);
-}
-}
-namespace QtFutex = QtWindowsFutex;
-QT_END_NAMESPACE
+# include "qfutex_win_p.h"
#else
-
QT_BEGIN_NAMESPACE
namespace QtFutex = QtDummyFutex;
QT_END_NAMESPACE
diff --git a/src/corelib/thread/qfutex_win_p.h b/src/corelib/thread/qfutex_win_p.h
new file mode 100644
index 0000000000..75a12bd82c
--- /dev/null
+++ b/src/corelib/thread/qfutex_win_p.h
@@ -0,0 +1,58 @@
+// Copyright (C) 2023 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QFUTEX_WIN_P_H
+#define QFUTEX_WIN_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 <private/qglobal_p.h>
+#include <qdeadlinetimer.h>
+#include <qtsan_impl.h>
+
+#include <qt_windows.h>
+
+#define QT_ALWAYS_USE_FUTEX
+
+QT_BEGIN_NAMESPACE
+
+namespace QtWindowsFutex {
+constexpr inline bool futexAvailable() { return true; }
+
+template <typename Atomic>
+inline void futexWait(Atomic &futex, typename Atomic::Type expectedValue)
+{
+ QtTsan::futexRelease(&futex);
+ WaitOnAddress(&futex, &expectedValue, sizeof(expectedValue), INFINITE);
+ QtTsan::futexAcquire(&futex);
+}
+template <typename Atomic>
+inline bool futexWait(Atomic &futex, typename Atomic::Type expectedValue, QDeadlineTimer deadline)
+{
+ using namespace std::chrono;
+ BOOL r = WaitOnAddress(&futex, &expectedValue, sizeof(expectedValue), DWORD(deadline.remainingTime()));
+ return r || GetLastError() != ERROR_TIMEOUT;
+}
+template <typename Atomic> inline void futexWakeAll(Atomic &futex)
+{
+ WakeByAddressAll(&futex);
+}
+template <typename Atomic> inline void futexWakeOne(Atomic &futex)
+{
+ WakeByAddressSingle(&futex);
+}
+} // namespace QtWindowsFutex
+namespace QtFutex = QtWindowsFutex;
+
+QT_END_NAMESPACE
+
+#endif // QFUTEX_WIN_P_H
diff --git a/src/corelib/thread/qfuture.h b/src/corelib/thread/qfuture.h
index 34fb8a039d..5939a93780 100644
--- a/src/corelib/thread/qfuture.h
+++ b/src/corelib/thread/qfuture.h
@@ -522,6 +522,19 @@ QFuture<std::variant<std::decay_t<Futures>...>> whenAny(Futures &&... futures);
#endif // Q_QDOC
+#if QT_DEPRECATED_SINCE(6, 10)
+#if defined(Q_QDOC)
+static QFuture<void> makeReadyFuture()
+#else
+template<typename T = void>
+QT_DEPRECATED_VERSION_X(6, 10, "Use makeReadyVoidFuture() instead.")
+static QFuture<T> makeReadyFuture()
+#endif
+{
+ return makeReadyVoidFuture();
+}
+#endif // QT_DEPRECATED_SINCE(6, 10)
+
} // namespace QtFuture
Q_DECLARE_SEQUENTIAL_ITERATOR(Future)
diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc
index 570f7de8e3..9eda766968 100644
--- a/src/corelib/thread/qfuture.qdoc
+++ b/src/corelib/thread/qfuture.qdoc
@@ -75,6 +75,15 @@
If \c testFuture gets canceled, its state is propagated to the next then(),
which will be also canceled. So in this case \c {Block 6} will be called.
+ The future can have only one continuation. Consider the following example:
+
+ \snippet code/src_corelib_thread_qfuture.cpp 31
+
+ In this case \c f1 and \c f2 are effectively the same QFuture object, as
+ they share the same internal state. As a result, calling
+ \l {QFuture::}{then} on \c f2 will overwrite the continuation specified for
+ \c {f1}. So, only \c {"second"} will be printed when this code is executed.
+
QFuture also offers ways to interact with a running computation. For
instance, the computation can be canceled with the cancel() function. To
suspend or resume the computation, use the setSuspended() function or one of
@@ -109,13 +118,21 @@
combine several futures and track when the last or first of them completes.
A ready QFuture object with a value or a QFuture object holding exception can
- be created using convenience functions QtFuture::makeReadyFuture() and
+ be created using convenience functions QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeReadyRangeFuture(), and
QtFuture::makeExceptionalFuture().
+ \note Some APIs (see \l {QFuture::then()} or various QtConcurrent method
+ overloads) allow scheduling the computation to a specific thread pool.
+ However, QFuture implements a work-stealing algorithm to prevent deadlocks
+ and optimize thread usage. As a result, computations can be executed
+ directly in the thread which requests the QFuture's result.
+
\note To start a computation and store results in a QFuture, use QPromise or
one of the APIs in the \l {Qt Concurrent} framework.
- \sa QPromise, QtFuture::connect(), QtFuture::makeReadyFuture(),
+ \sa QPromise, QtFuture::connect(), QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeReadyRangeFuture(),
QtFuture::makeExceptionalFuture(), QFutureWatcher, {Qt Concurrent}
*/
@@ -373,7 +390,7 @@
computations), i.e. until isFinished() returns \c true.
*/
-/*! \fn template <typename T> T QFuture<T>::result() const
+/*! \fn template <typename T> template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>> T QFuture<T>::result() const
Returns the first result in the future. If the result is not immediately
available, this function will block and wait for the result to become
@@ -388,7 +405,7 @@
\sa resultAt(), results(), takeResult()
*/
-/*! \fn template <typename T> T QFuture<T>::resultAt(int index) const
+/*! \fn template <typename T> template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>> T QFuture<T>::resultAt(int index) const
Returns the result at \a index in the future. If the result is not
immediately available, this function will block and wait for the result to
@@ -400,7 +417,7 @@
\sa result(), results(), takeResult(), resultCount()
*/
-/*! \fn template <typename T> bool QFuture<T>::isResultReadyAt(int index) const
+/*! \fn template <typename T> template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>> bool QFuture<T>::isResultReadyAt(int index) const
Returns \c true if the result at \a index is immediately available; otherwise
returns \c false.
@@ -411,7 +428,7 @@
\sa resultAt(), resultCount(), takeResult()
*/
-/*! \fn template <typename T> QList<T> QFuture<T>::results() const
+/*! \fn template <typename T> template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>> QList<T> QFuture<T>::results() const
Returns all results from the future. If the results are not immediately available,
this function will block and wait for them to become available. Note that
@@ -427,7 +444,7 @@
*/
#if 0
-/*! \fn template <typename T> std::vector<T> QFuture<T>::takeResults()
+/*! \fn template <typename T> template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>> std::vector<T> QFuture<T>::takeResults()
If isValid() returns \c false, calling this function leads to undefined behavior.
takeResults() takes all results from the QFuture object and invalidates it
@@ -446,7 +463,7 @@
*/
#endif
-/*! \fn template <typename T> std::vector<T> QFuture<T>::takeResult()
+/*! \fn template <typename T> template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>> std::vector<T> QFuture<T>::takeResult()
\since 6.0
@@ -481,7 +498,7 @@
\sa takeResult(), result(), results(), resultAt()
*/
-/*! \fn template <typename T> QFuture<T>::const_iterator QFuture<T>::begin() const
+/*! \fn template<typename T> template<class U = T, typename = QtPrivate::EnableForNonVoid<U>> QFuture<T>::const_iterator QFuture<T>::begin() const
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first result in the
future.
@@ -489,7 +506,7 @@
\sa constBegin(), end()
*/
-/*! \fn template <typename T> QFuture<T>::const_iterator QFuture<T>::end() const
+/*! \fn template<typename T> template<class U = T, typename = QtPrivate::EnableForNonVoid<U>> QFuture<T>::const_iterator QFuture<T>::end() const
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary result
after the last result in the future.
@@ -497,7 +514,7 @@
\sa begin(), constEnd()
*/
-/*! \fn template <typename T> QFuture<T>::const_iterator QFuture<T>::constBegin() const
+/*! \fn template<typename T> template<class U = T, typename = QtPrivate::EnableForNonVoid<U>> QFuture<T>::const_iterator QFuture<T>::constBegin() const
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first result in the
future.
@@ -505,7 +522,7 @@
\sa begin(), constEnd()
*/
-/*! \fn template <typename T> QFuture<T>::const_iterator QFuture<T>::constEnd() const
+/*! \fn template<typename T> template<class U = T, typename = QtPrivate::EnableForNonVoid<U>> QFuture<T>::const_iterator QFuture<T>::constEnd() const
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary result
after the last result in the future.
@@ -919,7 +936,7 @@
\sa QtFuture::whenAny()
*/
-/*! \fn template<class Sender, class Signal> static QFuture<ArgsType<Signal>> QtFuture::connect(Sender *sender, Signal signal)
+/*! \fn template<class Sender, class Signal, typename = QtPrivate::EnableIfInvocable<Sender, Signal>> static QFuture<ArgsType<Signal>> QtFuture::connect(Sender *sender, Signal signal)
Creates and returns a QFuture which will become available when the \a sender emits
the \a signal. If the \a signal takes no arguments, a QFuture<void> is returned. If
@@ -958,10 +975,11 @@
\sa QFuture, QFuture::then()
*/
-/*! \fn template<typename T> static QFuture<std::decay_t<T>> QtFuture::makeReadyFuture(T &&value)
+/*! \fn template<typename T, typename = QtPrivate::EnableForNonVoid<T>> static QFuture<std::decay_t<T>> QtFuture::makeReadyFuture(T &&value)
\since 6.1
\overload
+ \deprecated [6.6] Use makeReadyValueFuture() instead.
Creates and returns a QFuture which already has a result \a value.
The returned QFuture has a type of std::decay_t<T>, where T is not void.
@@ -972,13 +990,20 @@
const int result = *f.takeResult(); // result == 42
\endcode
- \sa QFuture, QtFuture::makeExceptionalFuture()
+ The method should be avoided because
+ it has an inconsistent set of overloads. From Qt 6.10 onwards, using it
+ in code will result in compiler warnings.
+
+ \sa QFuture, QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeReadyRangeFuture(),
+ QtFuture::makeExceptionalFuture()
*/
/*! \fn QFuture<void> QtFuture::makeReadyFuture()
\since 6.1
\overload
+ \deprecated [6.6] Use makeReadyVoidFuture() instead.
Creates and returns a void QFuture. Such QFuture can't store any result.
One can use it to query the state of the computation.
@@ -992,14 +1017,21 @@
const bool finished = f.isFinished(); // finished == true
\endcode
+ The method should be avoided because
+ it has an inconsistent set of overloads. From Qt 6.10 onwards, using it
+ in code will result in compiler warnings.
+
\sa QFuture, QFuture::isStarted(), QFuture::isRunning(),
- QFuture::isFinished(), QtFuture::makeExceptionalFuture()
+ QFuture::isFinished(), QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeReadyRangeFuture(),
+ QtFuture::makeExceptionalFuture()
*/
/*! \fn template<typename T> static QFuture<T> QtFuture::makeReadyFuture(const QList<T> &values)
\since 6.1
\overload
+ \deprecated [6.6] Use makeReadyRangeFuture() instead.
Creates and returns a QFuture which already has multiple results set from \a values.
@@ -1011,7 +1043,42 @@
const auto results = f.results(); // results == { 1, 2, 3 }
\endcode
- \sa QFuture, QtFuture::makeExceptionalFuture()
+ The method should be avoided because
+ it has an inconsistent set of overloads. From Qt 6.10 onwards, using it
+ in code will result in compiler warnings.
+
+ \sa QFuture, QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeReadyRangeFuture(),
+ QtFuture::makeExceptionalFuture()
+*/
+
+/*! \fn template<typename T> static QFuture<std::decay_t<T>> QtFuture::makeReadyValueFuture(T &&value)
+
+ \since 6.6
+
+ Creates and returns a QFuture which already has a result \a value.
+ The returned QFuture has a type of std::decay_t<T>, where T is not void.
+ The returned QFuture will already be in the finished state.
+
+ \snippet code/src_corelib_thread_qfuture.cpp 35
+
+ \sa QFuture, QtFuture::makeReadyRangeFuture(),
+ QtFuture::makeReadyVoidFuture(), QtFuture::makeExceptionalFuture()
+*/
+
+/*! \fn QFuture<void> QtFuture::makeReadyVoidFuture()
+
+ \since 6.6
+
+ Creates and returns a void QFuture. Such QFuture can't store any result.
+ One can use it to query the state of the computation.
+ The returned QFuture will already be in the finished state.
+
+ \snippet code/src_corelib_thread_qfuture.cpp 36
+
+ \sa QFuture, QFuture::isStarted(), QFuture::isRunning(),
+ QFuture::isFinished(), QtFuture::makeReadyValueFuture(),
+ QtFuture::makeReadyRangeFuture(), QtFuture::makeExceptionalFuture()
*/
/*! \fn template<typename T> static QFuture<T> QtFuture::makeExceptionalFuture(const QException &exception)
@@ -1031,7 +1098,8 @@
}
\endcode
- \sa QFuture, QException, QtFuture::makeReadyFuture()
+ \sa QFuture, QException, QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture()
*/
/*! \fn template<typename T> static QFuture<T> QtFuture::makeExceptionalFuture(std::exception_ptr exception)
@@ -1056,7 +1124,44 @@
}
\endcode
- \sa QFuture, QException, QtFuture::makeReadyFuture()
+ \sa QFuture, QException, QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture()
+*/
+
+/*! \fn template<typename Container, QtFuture::if_container_with_input_iterators<Container>> static QFuture<QtFuture::ContainedType<Container>> QtFuture::makeReadyRangeFuture(Container &&container)
+
+ \since 6.6
+ \overload
+
+ Takes an input container \a container and returns a QFuture with multiple
+ results of type \c ContainedType initialized from the values of the
+ \a container.
+
+ \note This overload only participates in overload resolution if the
+ \c Container has input iterators.
+
+ \snippet code/src_corelib_thread_qfuture.cpp 32
+ \dots
+ \snippet code/src_corelib_thread_qfuture.cpp 34
+
+ \sa QFuture, QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeExceptionalFuture()
+*/
+
+/*! \fn template<typename ValueType> static QFuture<ValueType> QtFuture::makeReadyRangeFuture(std::initializer_list<ValueType> values)
+
+ \since 6.6
+ \overload
+
+ Returns a QFuture with multiple results of type \c ValueType initialized
+ from the input initializer list \a values.
+
+ \snippet code/src_corelib_thread_qfuture.cpp 33
+ \dots
+ \snippet code/src_corelib_thread_qfuture.cpp 34
+
+ \sa QFuture, QtFuture::makeReadyVoidFuture(),
+ QtFuture::makeReadyValueFuture(), QtFuture::makeExceptionalFuture()
*/
/*! \fn template<class T> template<class Function> QFuture<typename QFuture<T>::ResultType<Function>> QFuture<T>::then(Function &&function)
@@ -1155,8 +1260,7 @@
Attaches a continuation to this future, allowing to chain multiple asynchronous
computations if desired. When the asynchronous computation represented by this
- future finishes, \a function will be invoked in a separate thread taken from the
- QThreadPool \a pool.
+ future finishes, \a function will be scheduled on \a pool.
\sa onFailed(), onCanceled()
*/
@@ -1196,13 +1300,23 @@
is attached. In this case it will be resolved in the current thread. Therefore, when
in doubt, pass the context explicitly.
+ \target context_lifetime
+ If the \a context is destroyed before the chain has finished, the future is canceled.
+ This implies that a cancellation handler might be invoked when the \a context is not valid
+ anymore. To guard against this, capture the \a context as a QPointer:
+
+ \snippet code/src_corelib_thread_qfuture.cpp 37
+
+ When the context object is destroyed, cancellation happens immediately. Previous futures in the
+ chain are \e {not} cancelled and keep running until they are finished.
+
\note When calling this method, it should be guaranteed that the \a context stays alive
- throughout the execution of the chain.
+ during setup of the chain.
\sa onFailed(), onCanceled()
*/
-/*! \fn template<class T> template<class Function> QFuture<T> QFuture<T>::onFailed(Function &&handler)
+/*! \fn template<class T> template<class Function, typename = std::enable_if_t<!QtPrivate::ArgResolver<Function>::HasExtraArgs>> QFuture<T> QFuture<T>::onFailed(Function &&handler)
\since 6.0
@@ -1245,7 +1359,7 @@
\sa then(), onCanceled()
*/
-/*! \fn template<class T> template<class Function> QFuture<T> QFuture<T>::onFailed(QObject *context, Function &&handler)
+/*! \fn template<class T> template<class Function, typename = std::enable_if_t<!QtPrivate::ArgResolver<Function>::HasExtraArgs>> QFuture<T> QFuture<T>::onFailed(QObject *context, Function &&handler)
\since 6.1
\overload
@@ -1262,15 +1376,18 @@
be invoked from a non-gui thread. So \c this is provided as a context to \c .onFailed(),
to make sure that it will be invoked in the main thread.
+ If the \a context is destroyed before the chain has finished, the future is canceled.
+ See \l {context_lifetime}{then()} for details.
+
\note When calling this method, it should be guaranteed that the \a context stays alive
- throughout the execution of the chain.
+ during setup of the chain.
See the documentation of the other overload for more details about \a handler.
\sa then(), onCanceled()
*/
-/*! \fn template<class T> template<class Function> QFuture<T> QFuture<T>::onCanceled(Function &&handler)
+/*! \fn template<class T> template<class Function, typename = std::enable_if_t<std::is_invocable_r_v<T, Function>>> QFuture<T> QFuture<T>::onCanceled(Function &&handler)
\since 6.0
@@ -1315,7 +1432,7 @@
\sa then(), onFailed()
*/
-/*! \fn template<class T> template<class Function> QFuture<T> QFuture<T>::onCanceled(QObject *context, Function &&handler)
+/*! \fn template<class T> template<class Function, typename = std::enable_if_t<std::is_invocable_r_v<T, Function>>> QFuture<T> QFuture<T>::onCanceled(QObject *context, Function &&handler)
\since 6.1
\overload
@@ -1325,8 +1442,11 @@
invoked in the thread of the \a context object. This can be useful if the cancellation
needs to be handled in a specific thread.
+ If the \a context is destroyed before the chain has finished, the future is canceled.
+ See \l {context_lifetime}{then()} for details.
+
\note When calling this method, it should be guaranteed that the \a context stays alive
- throughout the execution of the chain.
+ during setup of the chain.
See the documentation of the other overload for more details about \a handler.
diff --git a/src/corelib/thread/qfuture_impl.h b/src/corelib/thread/qfuture_impl.h
index 58169bd05b..351093adc7 100644
--- a/src/corelib/thread/qfuture_impl.h
+++ b/src/corelib/thread/qfuture_impl.h
@@ -14,7 +14,6 @@
#include <QtCore/qfutureinterface.h>
#include <QtCore/qthreadpool.h>
#include <QtCore/qexception.h>
-#include <QtCore/qpointer.h>
#include <QtCore/qpromise.h>
#include <memory>
@@ -274,6 +273,12 @@ using IsRandomAccessible =
std::begin(std::declval<Sequence>()))>>::iterator_category,
std::random_access_iterator_tag>;
+template<class Sequence>
+using HasInputIterator =
+ std::is_convertible<typename std::iterator_traits<std::decay_t<decltype(
+ std::begin(std::declval<Sequence>()))>>::iterator_category,
+ std::input_iterator_tag>;
+
template<class Iterator>
using IsForwardIterable =
std::is_convertible<typename std::iterator_traits<Iterator>::iterator_category,
@@ -282,6 +287,7 @@ using IsForwardIterable =
template<typename Function, typename ResultType, typename ParentResultType>
class Continuation
{
+ Q_DISABLE_COPY_MOVE(Continuation)
public:
template<typename F = Function>
Continuation(F &&func, const QFuture<ParentResultType> &f, QPromise<ResultType> &&p)
@@ -529,18 +535,18 @@ void Continuation<Function, ResultType, ParentResultType>::create(F &&func,
fi.setLaunchAsync(launchAsync);
- auto continuation = [func = std::forward<F>(func), fi, promise = QPromise(fi), pool,
+ auto continuation = [func = std::forward<F>(func), fi, promise_ = QPromise(fi), pool,
launchAsync](const QFutureInterfaceBase &parentData) mutable {
const auto parent = QFutureInterface<ParentResultType>(parentData).future();
Continuation<Function, ResultType, ParentResultType> *continuationJob = nullptr;
if (launchAsync) {
auto asyncJob = new AsyncContinuation<Function, ResultType, ParentResultType>(
- std::forward<Function>(func), parent, std::move(promise), pool);
+ std::forward<Function>(func), parent, std::move(promise_), pool);
fi.setRunnable(asyncJob);
continuationJob = asyncJob;
} else {
continuationJob = new SyncContinuation<Function, ResultType, ParentResultType>(
- std::forward<Function>(func), parent, std::move(promise));
+ std::forward<Function>(func), parent, std::move(promise_));
}
bool isLaunched = continuationJob->execute();
@@ -567,11 +573,11 @@ void Continuation<Function, ResultType, ParentResultType>::create(F &&func,
fi.setLaunchAsync(true);
fi.setThreadPool(pool);
- auto continuation = [func = std::forward<F>(func), promise = QPromise(fi),
+ auto continuation = [func = std::forward<F>(func), promise_ = QPromise(fi),
pool](const QFutureInterfaceBase &parentData) mutable {
const auto parent = QFutureInterface<ParentResultType>(parentData).future();
auto continuationJob = new AsyncContinuation<Function, ResultType, ParentResultType>(
- std::forward<Function>(func), parent, std::move(promise), pool);
+ std::forward<Function>(func), parent, std::move(promise_), pool);
bool isLaunched = continuationJob->execute();
// If continuation is successfully launched, AsyncContinuation will be deleted
// by the QThreadPool which has started it.
@@ -583,6 +589,15 @@ void Continuation<Function, ResultType, ParentResultType>::create(F &&func,
f->d.setContinuation(ContinuationWrapper(std::move(continuation)), fi.d);
}
+template <typename Continuation>
+void watchContinuation(const QObject *context, Continuation &&c, QFutureInterfaceBase &fi)
+{
+ using Prototype = typename QtPrivate::Callable<Continuation>::Function;
+ watchContinuationImpl(context,
+ QtPrivate::makeCallableObject<Prototype>(std::forward<Continuation>(c)),
+ fi);
+}
+
template<typename Function, typename ResultType, typename ParentResultType>
template<typename F>
void Continuation<Function, ResultType, ParentResultType>::create(F &&func,
@@ -591,21 +606,19 @@ void Continuation<Function, ResultType, ParentResultType>::create(F &&func,
QObject *context)
{
Q_ASSERT(f);
-
- auto continuation = [func = std::forward<F>(func), fi,
- context = QPointer<QObject>(context)](
- const QFutureInterfaceBase &parentData) mutable {
- Q_ASSERT(context);
- const auto parent = QFutureInterface<ParentResultType>(parentData).future();
- QMetaObject::invokeMethod(
- context,
- [func = std::forward<F>(func), promise = QPromise(fi), parent]() mutable {
- SyncContinuation<Function, ResultType, ParentResultType> continuationJob(
- std::forward<Function>(func), parent, std::move(promise));
- continuationJob.execute();
- });
+ Q_ASSERT(context);
+
+ // When the context object is destroyed, the signal-slot connection is broken and the
+ // continuation callback is destroyed. The promise that is created in the capture list is
+ // destroyed and, if it is not yet finished, cancelled.
+ auto continuation = [func = std::forward<F>(func), parent = *f,
+ promise_ = QPromise(fi)]() mutable {
+ SyncContinuation<Function, ResultType, ParentResultType> continuationJob(
+ std::forward<Function>(func), parent, std::move(promise_));
+ continuationJob.execute();
};
- f->d.setContinuation(ContinuationWrapper(std::move(continuation)), fi.d);
+
+ QtPrivate::watchContinuation(context, std::move(continuation), f->d);
}
template<typename Function, typename ResultType, typename ParentResultType>
@@ -671,11 +684,11 @@ void FailureHandler<Function, ResultType>::create(F &&function, QFuture<ResultTy
{
Q_ASSERT(future);
- auto failureContinuation = [function = std::forward<F>(function), promise = QPromise(fi)](
+ auto failureContinuation = [function = std::forward<F>(function), promise_ = QPromise(fi)](
const QFutureInterfaceBase &parentData) mutable {
const auto parent = QFutureInterface<ResultType>(parentData).future();
FailureHandler<Function, ResultType> failureHandler(std::forward<Function>(function),
- parent, std::move(promise));
+ parent, std::move(promise_));
failureHandler.run();
};
@@ -689,22 +702,15 @@ void FailureHandler<Function, ResultType>::create(F &&function, QFuture<ResultTy
QObject *context)
{
Q_ASSERT(future);
+ Q_ASSERT(context);
+ auto failureContinuation = [function = std::forward<F>(function),
+ parent = *future, promise_ = QPromise(fi)]() mutable {
+ FailureHandler<Function, ResultType> failureHandler(
+ std::forward<Function>(function), parent, std::move(promise_));
+ failureHandler.run();
+ };
- auto failureContinuation =
- [function = std::forward<F>(function), fi,
- context = QPointer<QObject>(context)](const QFutureInterfaceBase &parentData) mutable {
- Q_ASSERT(context);
- const auto parent = QFutureInterface<ResultType>(parentData).future();
- QMetaObject::invokeMethod(context,
- [function = std::forward<F>(function),
- promise = QPromise(fi), parent]() mutable {
- FailureHandler<Function, ResultType> failureHandler(
- std::forward<Function>(function), parent, std::move(promise));
- failureHandler.run();
- });
- };
-
- future->d.setContinuation(ContinuationWrapper(std::move(failureContinuation)));
+ QtPrivate::watchContinuation(context, std::move(failureContinuation), future->d);
}
template<class Function, class ResultType>
@@ -721,6 +727,8 @@ void FailureHandler<Function, ResultType>::run()
} else {
handleException<ArgType>();
}
+ } else if (parentFuture.d.isChainCanceled()) {
+ promise.future().cancel();
} else {
QtPrivate::fulfillPromise(promise, parentFuture);
}
@@ -790,19 +798,13 @@ public:
QObject *context)
{
Q_ASSERT(future);
- auto canceledContinuation = [fi, handler = std::forward<F>(handler),
- context = QPointer<QObject>(context)](
- const QFutureInterfaceBase &parentData) mutable {
- Q_ASSERT(context);
- auto parentFuture = QFutureInterface<ResultType>(parentData).future();
- QMetaObject::invokeMethod(context,
- [promise = QPromise(fi), parentFuture,
- handler = std::forward<F>(handler)]() mutable {
- run(std::forward<F>(handler), parentFuture, std::move(promise));
- });
+ Q_ASSERT(context);
+ auto canceledContinuation = [handler = std::forward<F>(handler),
+ parentFuture = *future, promise = QPromise(fi)]() mutable {
+ run(std::forward<F>(handler), parentFuture, std::move(promise));
};
- future->d.setContinuation(ContinuationWrapper(std::move(canceledContinuation)));
+ QtPrivate::watchContinuation(context, std::move(canceledContinuation), future->d);
}
template<class F = Function>
@@ -886,6 +888,16 @@ struct UnwrapHandler
}
};
+template<typename ValueType>
+QFuture<ValueType> makeReadyRangeFutureImpl(const QList<ValueType> &values)
+{
+ QFutureInterface<ValueType> promise;
+ promise.reportStarted();
+ promise.reportResults(values);
+ promise.reportFinished();
+ return promise.future();
+}
+
} // namespace QtPrivate
namespace QtFuture {
@@ -951,8 +963,37 @@ static QFuture<ArgsType<Signal>> connect(Sender *sender, Signal signal)
return promise.future();
}
-template<typename T, typename = QtPrivate::EnableForNonVoid<T>>
-static QFuture<std::decay_t<T>> makeReadyFuture(T &&value)
+template<typename Container>
+using if_container_with_input_iterators =
+ std::enable_if_t<QtPrivate::HasInputIterator<Container>::value, bool>;
+
+template<typename Container>
+using ContainedType =
+ typename std::iterator_traits<decltype(
+ std::cbegin(std::declval<Container&>()))>::value_type;
+
+template<typename Container, if_container_with_input_iterators<Container> = true>
+static QFuture<ContainedType<Container>> makeReadyRangeFuture(Container &&container)
+{
+ // handle QList<T> separately, because reportResults() takes a QList
+ // as an input
+ using ValueType = ContainedType<Container>;
+ if constexpr (std::is_convertible_v<q20::remove_cvref_t<Container>, QList<ValueType>>) {
+ return QtPrivate::makeReadyRangeFutureImpl(container);
+ } else {
+ return QtPrivate::makeReadyRangeFutureImpl(QList<ValueType>{std::cbegin(container),
+ std::cend(container)});
+ }
+}
+
+template<typename ValueType>
+static QFuture<ValueType> makeReadyRangeFuture(std::initializer_list<ValueType> values)
+{
+ return QtPrivate::makeReadyRangeFutureImpl(QList<ValueType>{values});
+}
+
+template<typename T>
+static QFuture<std::decay_t<T>> makeReadyValueFuture(T &&value)
{
QFutureInterface<std::decay_t<T>> promise;
promise.reportStarted();
@@ -962,30 +1003,26 @@ static QFuture<std::decay_t<T>> makeReadyFuture(T &&value)
return promise.future();
}
-#if defined(Q_QDOC)
-static QFuture<void> makeReadyFuture()
-#else
-template<typename T = void>
-static QFuture<T> makeReadyFuture()
-#endif
-{
- QFutureInterface<T> promise;
- promise.reportStarted();
- promise.reportFinished();
+Q_CORE_EXPORT QFuture<void> makeReadyVoidFuture(); // implemented in qfutureinterface.cpp
- return promise.future();
+#if QT_DEPRECATED_SINCE(6, 10)
+template<typename T, typename = QtPrivate::EnableForNonVoid<T>>
+QT_DEPRECATED_VERSION_X(6, 10, "Use makeReadyValueFuture() instead.")
+static QFuture<std::decay_t<T>> makeReadyFuture(T &&value)
+{
+ return makeReadyValueFuture(std::forward<T>(value));
}
+// the void specialization is moved to the end of qfuture.h, because it now
+// uses makeReadyVoidFuture() and required QFuture<void> to be defined.
+
template<typename T>
+QT_DEPRECATED_VERSION_X(6, 10, "Use makeReadyRangeFuture() instead.")
static QFuture<T> makeReadyFuture(const QList<T> &values)
{
- QFutureInterface<T> promise;
- promise.reportStarted();
- promise.reportResults(values);
- promise.reportFinished();
-
- return promise.future();
+ return makeReadyRangeFuture(values);
}
+#endif // QT_DEPRECATED_SINCE(6, 10)
#ifndef QT_NO_EXCEPTIONS
@@ -1065,9 +1102,10 @@ void addCompletionHandlersImpl(const std::shared_ptr<ContextType> &context,
{
auto future = std::get<Index>(t);
using ResultType = typename ContextType::ValueType;
- future.then([context](const std::tuple_element_t<Index, std::tuple<Ts...>> &f) {
+ // Need context=context so that the compiler does not infer the captured variable's type as 'const'
+ future.then([context=context](const std::tuple_element_t<Index, std::tuple<Ts...>> &f) {
context->checkForCompletion(Index, ResultType { std::in_place_index<Index>, f });
- }).onCanceled([context, future]() {
+ }).onCanceled([context=context, future]() {
context->checkForCompletion(Index, ResultType { std::in_place_index<Index>, future });
});
@@ -1087,7 +1125,7 @@ QFuture<OutputSequence> whenAllImpl(InputIt first, InputIt last)
{
const qsizetype size = std::distance(first, last);
if (size == 0)
- return QtFuture::makeReadyFuture(OutputSequence());
+ return QtFuture::makeReadyValueFuture(OutputSequence());
const auto context = std::make_shared<QtPrivate::WhenAllContext<OutputSequence>>(size);
context->futures.resize(size);
@@ -1095,9 +1133,10 @@ QFuture<OutputSequence> whenAllImpl(InputIt first, InputIt last)
qsizetype idx = 0;
for (auto it = first; it != last; ++it, ++idx) {
- it->then([context, idx](const ValueType &f) {
+ // Need context=context so that the compiler does not infer the captured variable's type as 'const'
+ it->then([context=context, idx](const ValueType &f) {
context->checkForCompletion(idx, f);
- }).onCanceled([context, idx, f = *it] {
+ }).onCanceled([context=context, idx, f = *it] {
context->checkForCompletion(idx, f);
});
}
@@ -1126,7 +1165,7 @@ QFuture<QtFuture::WhenAnyResult<typename Future<ValueType>::type>> whenAnyImpl(I
const qsizetype size = std::distance(first, last);
if (size == 0) {
- return QtFuture::makeReadyFuture(
+ return QtFuture::makeReadyValueFuture(
QtFuture::WhenAnyResult { qsizetype(-1), QFuture<PackagedType>() });
}
@@ -1135,9 +1174,10 @@ QFuture<QtFuture::WhenAnyResult<typename Future<ValueType>::type>> whenAnyImpl(I
qsizetype idx = 0;
for (auto it = first; it != last; ++it, ++idx) {
- it->then([context, idx](const ValueType &f) {
+ // Need context=context so that the compiler does not infer the captured variable's type as 'const'
+ it->then([context=context, idx](const ValueType &f) {
context->checkForCompletion(idx, QtFuture::WhenAnyResult { idx, f });
- }).onCanceled([context, idx, f = *it] {
+ }).onCanceled([context=context, idx, f = *it] {
context->checkForCompletion(idx, QtFuture::WhenAnyResult { idx, f });
});
}
diff --git a/src/corelib/thread/qfutureinterface.cpp b/src/corelib/thread/qfutureinterface.cpp
index ed46052fa7..f83306af00 100644
--- a/src/corelib/thread/qfutureinterface.cpp
+++ b/src/corelib/thread/qfutureinterface.cpp
@@ -6,13 +6,11 @@
#include "qfutureinterface_p.h"
#include <QtCore/qatomic.h>
+#include <QtCore/qcoreapplication.h>
#include <QtCore/qthread.h>
-#include <QtCore/private/qsimd_p.h> // for qYieldCpu()
+#include <QtCore/qvarlengtharray.h>
#include <private/qthreadpool_p.h>
-
-#ifdef interface
-# undef interface
-#endif
+#include <private/qobject_p.h>
// GCC 12 gets confused about QFutureInterfaceBase::state, for some non-obvious
// reason
@@ -29,6 +27,7 @@ namespace {
class ThreadPoolThreadReleaser {
QThreadPool *m_pool;
public:
+ Q_NODISCARD_CTOR
explicit ThreadPoolThreadReleaser(QThreadPool *pool)
: m_pool(pool)
{ if (pool) pool->releaseThread(); }
@@ -41,6 +40,63 @@ const auto suspendingOrSuspended =
} // unnamed namespace
+class QObjectContinuationWrapper : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QObjectContinuationWrapper(QObject *parent = nullptr)
+ : QObject(parent)
+ {
+ }
+
+signals:
+ void run();
+};
+
+void QtPrivate::watchContinuationImpl(const QObject *context, QSlotObjectBase *slotObj,
+ QFutureInterfaceBase &fi)
+{
+ Q_ASSERT(context);
+ Q_ASSERT(slotObj);
+
+ auto slot = SlotObjUniquePtr(slotObj);
+
+ auto *watcher = new QObjectContinuationWrapper;
+ watcher->moveToThread(context->thread());
+
+ // We need to protect acccess to the watcher. The context object (and in turn, the watcher)
+ // could be destroyed while the continuation that emits the signal is running. We have to
+ // prevent that.
+ // The mutex has to be recursive, because the continuation itself could delete the context
+ // object (and thus the watcher), which will try to lock the mutex from the same thread twice.
+ auto watcherMutex = std::make_shared<QRecursiveMutex>();
+ const auto destroyWatcher = [watcherMutex, watcher]() mutable {
+ QMutexLocker lock(watcherMutex.get());
+ delete watcher;
+ };
+
+ // ### we're missing a convenient way to `QObject::connect()` to a `QSlotObjectBase`...
+ QObject::connect(watcher, &QObjectContinuationWrapper::run,
+ // for the following, cf. QMetaObject::invokeMethodImpl():
+ // we know `slot` is a lambda returning `void`, so we can just
+ // `call()` with `obj` and `args[0]` set to `nullptr`:
+ context, [slot = std::move(slot)] {
+ void *args[] = { nullptr }; // for `void` return value
+ slot->call(nullptr, args);
+ });
+ QObject::connect(watcher, &QObjectContinuationWrapper::run, watcher, &QObject::deleteLater);
+ QObject::connect(context, &QObject::destroyed, watcher, destroyWatcher);
+
+ fi.setContinuation([watcherMutex, watcher = QPointer(watcher)]
+ (const QFutureInterfaceBase &parentData)
+ {
+ Q_UNUSED(parentData);
+ QMutexLocker lock(watcherMutex.get());
+ if (watcher)
+ emit watcher->run();
+ });
+}
+
QFutureCallOutInterface::~QFutureCallOutInterface()
= default;
@@ -618,7 +674,6 @@ void QFutureInterfaceBase::reset()
{
d->m_progressValue = 0;
d->m_progress.reset();
- d->setState(QFutureInterfaceBase::NoState);
d->progressTime.invalidate();
d->isValid = false;
}
@@ -737,37 +792,36 @@ void QFutureInterfaceBasePrivate::sendCallOuts(const QFutureCallOutEvent &callOu
return;
for (int i = 0; i < outputConnections.size(); ++i) {
- QFutureCallOutInterface *interface = outputConnections.at(i);
- interface->postCallOutEvent(callOutEvent1);
- interface->postCallOutEvent(callOutEvent2);
+ QFutureCallOutInterface *iface = outputConnections.at(i);
+ iface->postCallOutEvent(callOutEvent1);
+ iface->postCallOutEvent(callOutEvent2);
}
}
// This function connects an output interface (for example a QFutureWatcher)
// to this future. While holding the lock we check the state and ready results
-// and add the appropriate callouts to the queue. In order to avoid deadlocks,
-// the actual callouts are made at the end while not holding the lock.
-void QFutureInterfaceBasePrivate::connectOutputInterface(QFutureCallOutInterface *interface)
+// and add the appropriate callouts to the queue.
+void QFutureInterfaceBasePrivate::connectOutputInterface(QFutureCallOutInterface *iface)
{
QMutexLocker locker(&m_mutex);
const auto currentState = state.loadRelaxed();
if (currentState & QFutureInterfaceBase::Started) {
- interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Started));
+ iface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Started));
if (m_progress) {
- interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::ProgressRange,
- m_progress->minimum,
- m_progress->maximum));
- interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Progress,
- m_progressValue,
- m_progress->text));
+ iface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::ProgressRange,
+ m_progress->minimum,
+ m_progress->maximum));
+ iface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Progress,
+ m_progressValue,
+ m_progress->text));
} else {
- interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::ProgressRange,
- 0,
- 0));
- interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Progress,
- m_progressValue,
- QString()));
+ iface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::ProgressRange,
+ 0,
+ 0));
+ iface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Progress,
+ m_progressValue,
+ QString()));
}
}
@@ -776,36 +830,36 @@ void QFutureInterfaceBasePrivate::connectOutputInterface(QFutureCallOutInterface
while (it != data.m_results.end()) {
const int begin = it.resultIndex();
const int end = begin + it.batchSize();
- interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::ResultsReady,
- begin,
- end));
+ iface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::ResultsReady,
+ begin,
+ end));
it.batchedAdvance();
}
}
if (currentState & QFutureInterfaceBase::Suspended)
- interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Suspended));
+ iface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Suspended));
else if (currentState & QFutureInterfaceBase::Suspending)
- interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Suspending));
+ iface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Suspending));
if (currentState & QFutureInterfaceBase::Canceled)
- interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Canceled));
+ iface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Canceled));
if (currentState & QFutureInterfaceBase::Finished)
- interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Finished));
+ iface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Finished));
- outputConnections.append(interface);
+ outputConnections.append(iface);
}
-void QFutureInterfaceBasePrivate::disconnectOutputInterface(QFutureCallOutInterface *interface)
+void QFutureInterfaceBasePrivate::disconnectOutputInterface(QFutureCallOutInterface *iface)
{
QMutexLocker lock(&m_mutex);
- const int index = outputConnections.indexOf(interface);
+ const qsizetype index = outputConnections.indexOf(iface);
if (index == -1)
return;
outputConnections.removeAt(index);
- interface->callOutInterfaceDisconnected();
+ iface->callOutInterfaceDisconnected();
}
void QFutureInterfaceBasePrivate::setState(QFutureInterfaceBase::State newState)
@@ -834,6 +888,10 @@ void QFutureInterfaceBase::setContinuation(std::function<void(const QFutureInter
// store the move-only continuation, to guarantee that the associated
// future's data stays alive.
if (d->continuationState != QFutureInterfaceBasePrivate::Cleaned) {
+ if (d->continuation) {
+ qWarning() << "Adding a continuation to a future which already has a continuation. "
+ "The existing continuation is overwritten.";
+ }
d->continuation = std::move(func);
d->continuationData = continuationFutureData;
}
@@ -885,4 +943,19 @@ bool QFutureInterfaceBase::launchAsync() const
return d->launchAsync;
}
+namespace QtFuture {
+
+QFuture<void> makeReadyVoidFuture()
+{
+ QFutureInterface<void> promise;
+ promise.reportStarted();
+ promise.reportFinished();
+
+ return promise.future();
+}
+
+} // namespace QtFuture
+
QT_END_NAMESPACE
+
+#include "qfutureinterface.moc"
diff --git a/src/corelib/thread/qfutureinterface.h b/src/corelib/thread/qfutureinterface.h
index 418f19866d..180a59a94e 100644
--- a/src/corelib/thread/qfutureinterface.h
+++ b/src/corelib/thread/qfutureinterface.h
@@ -21,6 +21,7 @@ QT_BEGIN_NAMESPACE
template <typename T> class QFuture;
class QThreadPool;
+class QFutureInterfaceBase;
class QFutureInterfaceBasePrivate;
class QFutureWatcherBase;
class QFutureWatcherBasePrivate;
@@ -38,6 +39,10 @@ class CanceledHandler;
template<class Function, class ResultType>
class FailureHandler;
#endif
+
+void Q_CORE_EXPORT watchContinuationImpl(const QObject *context,
+ QtPrivate::QSlotObjectBase *slotObj,
+ QFutureInterfaceBase &fi);
}
class Q_CORE_EXPORT QFutureInterfaceBase
@@ -176,6 +181,9 @@ private:
friend class QtPrivate::FailureHandler;
#endif
+ friend Q_CORE_EXPORT void QtPrivate::watchContinuationImpl(
+ const QObject *context, QtPrivate::QSlotObjectBase *slotObj, QFutureInterfaceBase &fi);
+
template<class T>
friend class QPromise;
@@ -236,6 +244,8 @@ public:
inline QFuture<T> future(); // implemented in qfuture.h
+ template <typename...Args, std::enable_if_t<std::is_constructible_v<T, Args...>, bool> = true>
+ inline bool reportAndEmplaceResult(int index, Args&&...args);
inline bool reportResult(const T *result, int index = -1);
inline bool reportAndMoveResult(T &&result, int index = -1);
inline bool reportResult(T &&result, int index = -1);
@@ -301,7 +311,8 @@ inline bool QFutureInterface<T>::reportResult(const T *result, int index)
}
template<typename T>
-bool QFutureInterface<T>::reportAndMoveResult(T &&result, int index)
+template<typename...Args, std::enable_if_t<std::is_constructible_v<T, Args...>, bool>>
+bool QFutureInterface<T>::reportAndEmplaceResult(int index, Args&&...args)
{
QMutexLocker<QMutex> locker{&mutex()};
if (queryState(Canceled) || queryState(Finished))
@@ -311,7 +322,7 @@ bool QFutureInterface<T>::reportAndMoveResult(T &&result, int index)
QtPrivate::ResultStoreBase &store = resultStoreBase();
const int oldResultCount = store.count();
- const int insertIndex = store.moveResult(index, std::forward<T>(result));
+ const int insertIndex = store.emplaceResult<T>(index, std::forward<Args>(args)...);
// Let's make sure it's not in pending results.
if (insertIndex != -1 && (!store.filterMode() || oldResultCount < store.count()))
reportResultsReady(insertIndex, store.count());
@@ -319,6 +330,12 @@ bool QFutureInterface<T>::reportAndMoveResult(T &&result, int index)
}
template<typename T>
+bool QFutureInterface<T>::reportAndMoveResult(T &&result, int index)
+{
+ return reportAndEmplaceResult(index, std::move(result));
+}
+
+template<typename T>
bool QFutureInterface<T>::reportResult(T &&result, int index)
{
return reportAndMoveResult(std::move(result), index);
@@ -452,7 +469,7 @@ template <>
class QFutureInterface<void> : public QFutureInterfaceBase
{
public:
- explicit QFutureInterface<void>(State initialState = NoState)
+ explicit QFutureInterface(State initialState = NoState)
: QFutureInterfaceBase(initialState)
{ }
diff --git a/src/corelib/thread/qfuturesynchronizer.h b/src/corelib/thread/qfuturesynchronizer.h
index 2cf2ca1b76..a996362bfd 100644
--- a/src/corelib/thread/qfuturesynchronizer.h
+++ b/src/corelib/thread/qfuturesynchronizer.h
@@ -17,22 +17,23 @@ class QFutureSynchronizer
Q_DISABLE_COPY(QFutureSynchronizer)
public:
- QFutureSynchronizer() : m_cancelOnWait(false) { }
- explicit QFutureSynchronizer(const QFuture<T> &future)
+ Q_NODISCARD_CTOR QFutureSynchronizer() : m_cancelOnWait(false) { }
+ Q_NODISCARD_CTOR_X("Use future.waitForFinished() instead.")
+ explicit QFutureSynchronizer(QFuture<T> future)
: m_cancelOnWait(false)
- { addFuture(future); }
+ { addFuture(std::move(future)); }
~QFutureSynchronizer() { waitForFinished(); }
- void setFuture(const QFuture<T> &future)
+ void setFuture(QFuture<T> future)
{
waitForFinished();
m_futures.clear();
- addFuture(future);
+ addFuture(std::move(future));
}
- void addFuture(const QFuture<T> &future)
+ void addFuture(QFuture<T> future)
{
- m_futures.append(future);
+ m_futures.append(std::move(future));
}
void waitForFinished()
diff --git a/src/corelib/thread/qfuturesynchronizer.qdoc b/src/corelib/thread/qfuturesynchronizer.qdoc
index 8dd7d58c4a..7d2d16d6e9 100644
--- a/src/corelib/thread/qfuturesynchronizer.qdoc
+++ b/src/corelib/thread/qfuturesynchronizer.qdoc
@@ -38,7 +38,7 @@
*/
/*!
- \fn template <typename T> QFutureSynchronizer<T>::QFutureSynchronizer(const QFuture<T> &future)
+ \fn template <typename T> QFutureSynchronizer<T>::QFutureSynchronizer(QFuture<T> future)
Constructs a QFutureSynchronizer and begins watching \a future by calling
addFuture().
@@ -56,7 +56,7 @@
*/
/*!
- \fn template <typename T> void QFutureSynchronizer<T>::setFuture(const QFuture<T> &future)
+ \fn template <typename T> void QFutureSynchronizer<T>::setFuture(QFuture<T> future)
Sets \a future to be the only future managed by this QFutureSynchronizer.
This is a convenience function that calls waitForFinished(),
@@ -66,7 +66,7 @@
*/
/*!
- \fn template <typename T> void QFutureSynchronizer<T>::addFuture(const QFuture<T> &future)
+ \fn template <typename T> void QFutureSynchronizer<T>::addFuture(QFuture<T> future)
Adds \a future to the list of managed futures.
diff --git a/src/corelib/thread/qfuturewatcher.cpp b/src/corelib/thread/qfuturewatcher.cpp
index 0ae406d356..2cffadfa5b 100644
--- a/src/corelib/thread/qfuturewatcher.cpp
+++ b/src/corelib/thread/qfuturewatcher.cpp
@@ -552,7 +552,7 @@ QT_WARNING_POP
}
-/*! \fn template <typename T> const T &QFutureWatcher<T>::result() const
+/*! \fn template <typename T> template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>> const T &QFutureWatcher<T>::result() const
Returns the first result in the future(). If the result is not immediately
available, this function will block and wait for the result to become
@@ -561,7 +561,7 @@ QT_WARNING_POP
\sa resultAt()
*/
-/*! \fn template <typename T> const T &QFutureWatcher<T>::resultAt(int index) const
+/*! \fn template <typename T> template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>> const T &QFutureWatcher<T>::resultAt(int index) const
Returns the result at \a index in the future(). If the result is not
immediately available, this function will block and wait for the result to
diff --git a/src/corelib/thread/qgenericatomic.h b/src/corelib/thread/qgenericatomic.h
index b8a022a2ac..91ccbbd1cd 100644
--- a/src/corelib/thread/qgenericatomic.h
+++ b/src/corelib/thread/qgenericatomic.h
@@ -5,8 +5,9 @@
#ifndef QGENERICATOMIC_H
#define QGENERICATOMIC_H
-#include <QtCore/qglobal.h>
-#include <QtCore/qtypeinfo.h>
+#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qtypes.h>
QT_BEGIN_NAMESPACE
@@ -33,335 +34,5 @@ template <typename T> struct QAtomicAdditiveType<T *>
static const int AddScale = sizeof(T);
};
-// not really atomic...
-template <typename BaseClass> struct QGenericAtomicOps
-{
- template <typename T> struct AtomicType { typedef T Type; typedef T *PointerType; };
-
- template <typename T> static void acquireMemoryFence(const T &_q_value) noexcept
- {
- BaseClass::orderedMemoryFence(_q_value);
- }
- template <typename T> static void releaseMemoryFence(const T &_q_value) noexcept
- {
- BaseClass::orderedMemoryFence(_q_value);
- }
- template <typename T> static void orderedMemoryFence(const T &) noexcept
- {
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- T load(const T &_q_value) noexcept
- {
- return _q_value;
- }
-
- template <typename T, typename X> static Q_ALWAYS_INLINE
- void store(T &_q_value, X newValue) noexcept
- {
- _q_value = newValue;
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- T loadRelaxed(const T &_q_value) noexcept
- {
- return _q_value;
- }
-
- template <typename T, typename X> static Q_ALWAYS_INLINE
- void storeRelaxed(T &_q_value, X newValue) noexcept
- {
- _q_value = newValue;
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- T loadAcquire(const T &_q_value) noexcept
- {
- T tmp = *static_cast<const volatile T *>(&_q_value);
- BaseClass::acquireMemoryFence(_q_value);
- return tmp;
- }
-
- template <typename T, typename X> static Q_ALWAYS_INLINE
- void storeRelease(T &_q_value, X newValue) noexcept
- {
- BaseClass::releaseMemoryFence(_q_value);
- *static_cast<volatile T *>(&_q_value) = newValue;
- }
-
- static inline constexpr bool isReferenceCountingNative() noexcept
- { return BaseClass::isFetchAndAddNative(); }
- static inline constexpr bool isReferenceCountingWaitFree() noexcept
- { return BaseClass::isFetchAndAddWaitFree(); }
- template <typename T> static Q_ALWAYS_INLINE
- bool ref(T &_q_value) noexcept
- {
- return BaseClass::fetchAndAddRelaxed(_q_value, 1) != T(-1);
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- bool deref(T &_q_value) noexcept
- {
- return BaseClass::fetchAndAddRelaxed(_q_value, -1) != 1;
- }
-
-#if 0
- // These functions have no default implementation
- // Architectures must implement them
- static inline constexpr bool isTestAndSetNative() noexcept;
- static inline constexpr bool isTestAndSetWaitFree() noexcept;
- template <typename T, typename X> static inline
- bool testAndSetRelaxed(T &_q_value, X expectedValue, X newValue) noexcept;
- template <typename T, typename X> static inline
- bool testAndSetRelaxed(T &_q_value, X expectedValue, X newValue, X *currentValue) noexcept;
-#endif
-
- template <typename T, typename X> static Q_ALWAYS_INLINE
- bool testAndSetAcquire(T &_q_value, X expectedValue, X newValue) noexcept
- {
- bool tmp = BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue);
- BaseClass::acquireMemoryFence(_q_value);
- return tmp;
- }
-
- template <typename T, typename X> static Q_ALWAYS_INLINE
- bool testAndSetRelease(T &_q_value, X expectedValue, X newValue) noexcept
- {
- BaseClass::releaseMemoryFence(_q_value);
- return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue);
- }
-
- template <typename T, typename X> static Q_ALWAYS_INLINE
- bool testAndSetOrdered(T &_q_value, X expectedValue, X newValue) noexcept
- {
- BaseClass::orderedMemoryFence(_q_value);
- return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue);
- }
-
- template <typename T, typename X> static Q_ALWAYS_INLINE
- bool testAndSetAcquire(T &_q_value, X expectedValue, X newValue, X *currentValue) noexcept
- {
- bool tmp = BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue, currentValue);
- BaseClass::acquireMemoryFence(_q_value);
- return tmp;
- }
-
- template <typename T, typename X> static Q_ALWAYS_INLINE
- bool testAndSetRelease(T &_q_value, X expectedValue, X newValue, X *currentValue) noexcept
- {
- BaseClass::releaseMemoryFence(_q_value);
- return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue, currentValue);
- }
-
- template <typename T, typename X> static Q_ALWAYS_INLINE
- bool testAndSetOrdered(T &_q_value, X expectedValue, X newValue, X *currentValue) noexcept
- {
- BaseClass::orderedMemoryFence(_q_value);
- return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue, currentValue);
- }
-
- static inline constexpr bool isFetchAndStoreNative() noexcept { return false; }
- static inline constexpr bool isFetchAndStoreWaitFree() noexcept { return false; }
-
- template <typename T, typename X> static Q_ALWAYS_INLINE
- T fetchAndStoreRelaxed(T &_q_value, X newValue) noexcept
- {
- // implement fetchAndStore on top of testAndSet
- for (;;) {
- T tmp = loadRelaxed(_q_value);
- if (BaseClass::testAndSetRelaxed(_q_value, tmp, newValue))
- return tmp;
- }
- }
-
- template <typename T, typename X> static Q_ALWAYS_INLINE
- T fetchAndStoreAcquire(T &_q_value, X newValue) noexcept
- {
- T tmp = BaseClass::fetchAndStoreRelaxed(_q_value, newValue);
- BaseClass::acquireMemoryFence(_q_value);
- return tmp;
- }
-
- template <typename T, typename X> static Q_ALWAYS_INLINE
- T fetchAndStoreRelease(T &_q_value, X newValue) noexcept
- {
- BaseClass::releaseMemoryFence(_q_value);
- return BaseClass::fetchAndStoreRelaxed(_q_value, newValue);
- }
-
- template <typename T, typename X> static Q_ALWAYS_INLINE
- T fetchAndStoreOrdered(T &_q_value, X newValue) noexcept
- {
- BaseClass::orderedMemoryFence(_q_value);
- return BaseClass::fetchAndStoreRelaxed(_q_value, newValue);
- }
-
- static inline constexpr bool isFetchAndAddNative() noexcept { return false; }
- static inline constexpr bool isFetchAndAddWaitFree() noexcept { return false; }
- template <typename T> static Q_ALWAYS_INLINE
- T fetchAndAddRelaxed(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) noexcept
- {
- // implement fetchAndAdd on top of testAndSet
- for (;;) {
- T tmp = BaseClass::loadRelaxed(_q_value);
- if (BaseClass::testAndSetRelaxed(_q_value, tmp, T(tmp + valueToAdd)))
- return tmp;
- }
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- T fetchAndAddAcquire(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) noexcept
- {
- T tmp = BaseClass::fetchAndAddRelaxed(_q_value, valueToAdd);
- BaseClass::acquireMemoryFence(_q_value);
- return tmp;
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- T fetchAndAddRelease(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) noexcept
- {
- BaseClass::releaseMemoryFence(_q_value);
- return BaseClass::fetchAndAddRelaxed(_q_value, valueToAdd);
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- T fetchAndAddOrdered(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) noexcept
- {
- BaseClass::orderedMemoryFence(_q_value);
- return BaseClass::fetchAndAddRelaxed(_q_value, valueToAdd);
- }
-
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_MSVC(4146) // unary minus operator applied to unsigned type, result still unsigned
- template <typename T> static Q_ALWAYS_INLINE
- T fetchAndSubRelaxed(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT operand) noexcept
- {
- // implement fetchAndSub on top of fetchAndAdd
- return fetchAndAddRelaxed(_q_value, -operand);
- }
-QT_WARNING_POP
-
- template <typename T> static Q_ALWAYS_INLINE
- T fetchAndSubAcquire(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT operand) noexcept
- {
- T tmp = BaseClass::fetchAndSubRelaxed(_q_value, operand);
- BaseClass::acquireMemoryFence(_q_value);
- return tmp;
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- T fetchAndSubRelease(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT operand) noexcept
- {
- BaseClass::releaseMemoryFence(_q_value);
- return BaseClass::fetchAndSubRelaxed(_q_value, operand);
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- T fetchAndSubOrdered(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT operand) noexcept
- {
- BaseClass::orderedMemoryFence(_q_value);
- return BaseClass::fetchAndSubRelaxed(_q_value, operand);
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- T fetchAndAndRelaxed(T &_q_value, typename std::enable_if<std::is_integral_v<T>, T>::type operand) noexcept
- {
- // implement fetchAndAnd on top of testAndSet
- T tmp = BaseClass::loadRelaxed(_q_value);
- for (;;) {
- if (BaseClass::testAndSetRelaxed(_q_value, tmp, T(tmp & operand), &tmp))
- return tmp;
- }
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- T fetchAndAndAcquire(T &_q_value, typename std::enable_if<std::is_integral_v<T>, T>::type operand) noexcept
- {
- T tmp = BaseClass::fetchAndAndRelaxed(_q_value, operand);
- BaseClass::acquireMemoryFence(_q_value);
- return tmp;
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- T fetchAndAndRelease(T &_q_value, typename std::enable_if<std::is_integral_v<T>, T>::type operand) noexcept
- {
- BaseClass::releaseMemoryFence(_q_value);
- return BaseClass::fetchAndAndRelaxed(_q_value, operand);
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- T fetchAndAndOrdered(T &_q_value, typename std::enable_if<std::is_integral_v<T>, T>::type operand) noexcept
- {
- BaseClass::orderedMemoryFence(_q_value);
- return BaseClass::fetchAndAndRelaxed(_q_value, operand);
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- T fetchAndOrRelaxed(T &_q_value, typename std::enable_if<std::is_integral_v<T>, T>::type operand) noexcept
- {
- // implement fetchAndOr on top of testAndSet
- T tmp = BaseClass::loadRelaxed(_q_value);
- for (;;) {
- if (BaseClass::testAndSetRelaxed(_q_value, tmp, T(tmp | operand), &tmp))
- return tmp;
- }
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- T fetchAndOrAcquire(T &_q_value, typename std::enable_if<std::is_integral_v<T>, T>::type operand) noexcept
- {
- T tmp = BaseClass::fetchAndOrRelaxed(_q_value, operand);
- BaseClass::acquireMemoryFence(_q_value);
- return tmp;
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- T fetchAndOrRelease(T &_q_value, typename std::enable_if<std::is_integral_v<T>, T>::type operand) noexcept
- {
- BaseClass::releaseMemoryFence(_q_value);
- return BaseClass::fetchAndOrRelaxed(_q_value, operand);
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- T fetchAndOrOrdered(T &_q_value, typename std::enable_if<std::is_integral_v<T>, T>::type operand) noexcept
- {
- BaseClass::orderedMemoryFence(_q_value);
- return BaseClass::fetchAndOrRelaxed(_q_value, operand);
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- T fetchAndXorRelaxed(T &_q_value, typename std::enable_if<std::is_integral_v<T>, T>::type operand) noexcept
- {
- // implement fetchAndXor on top of testAndSet
- T tmp = BaseClass::loadRelaxed(_q_value);
- for (;;) {
- if (BaseClass::testAndSetRelaxed(_q_value, tmp, T(tmp ^ operand), &tmp))
- return tmp;
- }
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- T fetchAndXorAcquire(T &_q_value, typename std::enable_if<std::is_integral_v<T>, T>::type operand) noexcept
- {
- T tmp = BaseClass::fetchAndXorRelaxed(_q_value, operand);
- BaseClass::acquireMemoryFence(_q_value);
- return tmp;
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- T fetchAndXorRelease(T &_q_value, typename std::enable_if<std::is_integral_v<T>, T>::type operand) noexcept
- {
- BaseClass::releaseMemoryFence(_q_value);
- return BaseClass::fetchAndXorRelaxed(_q_value, operand);
- }
-
- template <typename T> static Q_ALWAYS_INLINE
- T fetchAndXorOrdered(T &_q_value, typename std::enable_if<std::is_integral_v<T>, T>::type operand) noexcept
- {
- BaseClass::orderedMemoryFence(_q_value);
- return BaseClass::fetchAndXorRelaxed(_q_value, operand);
- }
-};
-
QT_END_NAMESPACE
#endif // QGENERICATOMIC_H
diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp
index 293a4a772a..ec6c711a4f 100644
--- a/src/corelib/thread/qmutex.cpp
+++ b/src/corelib/thread/qmutex.cpp
@@ -8,7 +8,6 @@
#include "qmutex.h"
#include <qdebug.h>
#include "qatomic.h"
-#include "qelapsedtimer.h"
#include "qfutex_p.h"
#include "qthread.h"
#include "qmutex_p.h"
@@ -146,6 +145,23 @@ void QBasicMutex::destroyInternal(QMutexPrivate *d)
\sa lock(), unlock()
*/
+/*! \fn bool QMutex::tryLock(QDeadlineTimer timer)
+ \since 6.6
+
+ Attempts to lock the mutex. This function returns \c true if the lock
+ was obtained; otherwise it returns \c false. If another thread has
+ locked the mutex, this function will wait until \a timer expires
+ for the mutex to become available.
+
+ If the lock was obtained, the mutex must be unlocked with unlock()
+ before another thread can successfully lock it.
+
+ Calling this function multiple times on the same mutex from the
+ same thread will cause a \e dead-lock.
+
+ \sa lock(), unlock()
+*/
+
/*! \fn bool QMutex::tryLock()
\overload
@@ -279,6 +295,8 @@ QRecursiveMutex::~QRecursiveMutex()
*/
/*!
+ \fn QRecursiveMutex::tryLock(int timeout)
+
Attempts to lock the mutex. This function returns \c true if the lock
was obtained; otherwise it returns \c false. If another thread has
locked the mutex, this function will wait for at most \a timeout
@@ -296,7 +314,24 @@ QRecursiveMutex::~QRecursiveMutex()
\sa lock(), unlock()
*/
-bool QRecursiveMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT
+
+/*!
+ \since 6.6
+
+ Attempts to lock the mutex. This function returns \c true if the lock
+ was obtained; otherwise it returns \c false. If another thread has
+ locked the mutex, this function will wait until \a timeout expires
+ for the mutex to become available.
+
+ If the lock was obtained, the mutex must be unlocked with unlock()
+ before another thread can successfully lock it.
+
+ Calling this function multiple times on the same mutex from the
+ same thread is allowed.
+
+ \sa lock(), unlock()
+*/
+bool QRecursiveMutex::tryLock(QDeadlineTimer timeout) QT_MUTEX_LOCK_NOEXCEPT
{
unsigned tsanFlags = QtTsan::MutexWriteReentrant | QtTsan::TryLock;
QtTsan::mutexPreLock(this, tsanFlags);
@@ -309,7 +344,7 @@ bool QRecursiveMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT
return true;
}
bool success = true;
- if (timeout == -1) {
+ if (timeout.isForever()) {
mutex.lock();
} else {
success = mutex.tryLock(timeout);
@@ -622,27 +657,38 @@ void QBasicMutex::lockInternal() QT_MUTEX_LOCK_NOEXCEPT
/*!
\internal helper for lock(int)
*/
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT
{
if (timeout == 0)
return false;
+ return lockInternal(QDeadlineTimer(timeout));
+}
+#endif
+
+/*!
+ \internal helper for tryLock(QDeadlineTimer)
+ */
+bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXCEPT
+{
+ if (deadlineTimer.hasExpired())
+ return false;
+
if (futexAvailable()) {
- if (Q_UNLIKELY(timeout < 0)) {
+ if (Q_UNLIKELY(deadlineTimer.isForever())) {
lockInternal();
return true;
}
- QDeadlineTimer deadlineTimer(timeout);
// The mutex is already locked, set a bit indicating we're waiting.
// Note we must set to dummyFutexValue because there could be other threads
// also waiting.
if (d_ptr.fetchAndStoreAcquire(dummyFutexValue()) == nullptr)
return true;
- qint64 remainingTime = deadlineTimer.remainingTimeNSecs();
- Q_FOREVER {
- if (!futexWait(d_ptr, dummyFutexValue(), remainingTime))
+ for (;;) {
+ if (!futexWait(d_ptr, dummyFutexValue(), deadlineTimer))
return false;
// We got woken up, so must try to acquire the mutex. We must set
@@ -651,9 +697,7 @@ bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT
if (d_ptr.fetchAndStoreAcquire(dummyFutexValue()) == nullptr)
return true;
- // calculate the remaining time
- remainingTime = deadlineTimer.remainingTimeNSecs();
- if (remainingTime <= 0)
+ if (deadlineTimer.hasExpired())
return false;
}
}
@@ -665,7 +709,7 @@ bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT
continue;
if (copy == dummyLocked()) {
- if (timeout == 0)
+ if (deadlineTimer.hasExpired())
return false;
// The mutex is locked but does not have a QMutexPrivate yet.
// we need to allocate a QMutexPrivate
@@ -680,7 +724,7 @@ bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT
}
QMutexPrivate *d = static_cast<QMutexPrivate *>(copy);
- if (timeout == 0 && !d->possiblyUnlocked.loadRelaxed())
+ if (deadlineTimer.hasExpired() && !d->possiblyUnlocked.loadRelaxed())
return false;
// At this point we have a pointer to a QMutexPrivate. But the other thread
@@ -733,7 +777,7 @@ bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT
continue;
}
- if (d->wait(timeout)) {
+ if (d->wait(deadlineTimer)) {
// reset the possiblyUnlocked flag if needed (and deref its corresponding reference)
if (d->possiblyUnlocked.loadRelaxed() && d->possiblyUnlocked.testAndSetRelaxed(true, false))
d->deref();
@@ -742,8 +786,7 @@ bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT
Q_ASSERT(d == d_ptr.loadRelaxed());
return true;
} else {
- Q_ASSERT(timeout >= 0);
- //timeout
+ // timed out
d->derefWaiters(1);
//There may be a race in which the mutex is unlocked right after we timed out,
// and before we deref the waiters, so maybe the mutex is actually unlocked.
diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h
index af77f556fd..743b86939e 100644
--- a/src/corelib/thread/qmutex.h
+++ b/src/corelib/thread/qmutex.h
@@ -6,17 +6,13 @@
#include <QtCore/qglobal.h>
#include <QtCore/qatomic.h>
+#include <QtCore/qdeadlinetimer.h>
#include <QtCore/qtsan_impl.h>
-#include <new>
#include <chrono>
-#include <limits>
-
-class tst_QMutex;
QT_BEGIN_NAMESPACE
-
#if QT_CONFIG(thread) || defined(Q_QDOC)
#if defined(Q_OS_LINUX) || defined(Q_OS_WIN) // these platforms use futex
@@ -29,32 +25,6 @@ class QMutex;
class QRecursiveMutex;
class QMutexPrivate;
-namespace QtPrivate
-{
- template<class Rep, class Period>
- static int convertToMilliseconds(std::chrono::duration<Rep, Period> duration)
- {
- // N4606 § 30.4.1.3.5 [thread.timedmutex.requirements] specifies that a
- // duration less than or equal to duration.zero() shall result in a
- // try_lock, unlike QMutex's tryLock with a negative duration which
- // results in a lock.
-
- if (duration <= duration.zero())
- return 0;
-
- // when converting from 'duration' to milliseconds, make sure that
- // the result is not shorter than 'duration':
- std::chrono::milliseconds wait = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
- if (wait < duration)
- wait += std::chrono::milliseconds(1);
- Q_ASSERT(wait >= duration);
- const auto ms = wait.count();
- const auto maxInt = (std::numeric_limits<int>::max)();
-
- return ms < maxInt ? int(ms) : maxInt;
- }
-}
-
class Q_CORE_EXPORT QBasicMutex
{
Q_DISABLE_COPY_MOVE(QBasicMutex)
@@ -102,7 +72,10 @@ public:
bool try_lock() noexcept { return tryLock(); }
private:
- inline bool fastTryLock() noexcept {
+ inline bool fastTryLock() noexcept
+ {
+ if (d_ptr.loadRelaxed() != nullptr)
+ return false;
return d_ptr.testAndSetAcquire(nullptr, dummyLocked());
}
inline bool fastTryUnlock() noexcept {
@@ -110,7 +83,10 @@ private:
}
void lockInternal() QT_MUTEX_LOCK_NOEXCEPT;
+ bool lockInternal(QDeadlineTimer timeout) QT_MUTEX_LOCK_NOEXCEPT;
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
bool lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT;
+#endif
void unlockInternal() noexcept;
void destroyInternal(QMutexPrivate *d);
@@ -147,6 +123,11 @@ public:
using QBasicMutex::tryLock;
bool tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT
{
+ return tryLock(QDeadlineTimer(timeout));
+ }
+
+ bool tryLock(QDeadlineTimer timeout) QT_MUTEX_LOCK_NOEXCEPT
+ {
unsigned tsanFlags = QtTsan::TryLock;
QtTsan::mutexPreLock(this, tsanFlags);
@@ -170,17 +151,14 @@ public:
template <class Rep, class Period>
bool try_lock_for(std::chrono::duration<Rep, Period> duration)
{
- return tryLock(QtPrivate::convertToMilliseconds(duration));
+ return tryLock(QDeadlineTimer(duration));
}
// TimedLockable concept
template<class Clock, class Duration>
bool try_lock_until(std::chrono::time_point<Clock, Duration> timePoint)
{
- // Implemented in terms of try_lock_for to honor the similar
- // requirement in N4606 § 30.4.1.3 [thread.timedmutex.requirements]/12.
-
- return try_lock_for(timePoint - Clock::now());
+ return tryLock(QDeadlineTimer(timePoint));
}
};
@@ -201,8 +179,10 @@ public:
// BasicLockable concept
void lock() QT_MUTEX_LOCK_NOEXCEPT
- { tryLock(-1); }
- bool tryLock(int timeout = 0) QT_MUTEX_LOCK_NOEXCEPT;
+ { tryLock(QDeadlineTimer(QDeadlineTimer::Forever)); }
+ QT_CORE_INLINE_SINCE(6, 6)
+ bool tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT;
+ bool tryLock(QDeadlineTimer timer = {}) QT_MUTEX_LOCK_NOEXCEPT;
// BasicLockable concept
void unlock() noexcept;
@@ -213,24 +193,29 @@ public:
template <class Rep, class Period>
bool try_lock_for(std::chrono::duration<Rep, Period> duration)
{
- return tryLock(QtPrivate::convertToMilliseconds(duration));
+ return tryLock(QDeadlineTimer(duration));
}
// TimedLockable concept
template<class Clock, class Duration>
bool try_lock_until(std::chrono::time_point<Clock, Duration> timePoint)
{
- // Implemented in terms of try_lock_for to honor the similar
- // requirement in N4606 § 30.4.1.3 [thread.timedmutex.requirements]/12.
-
- return try_lock_for(timePoint - Clock::now());
+ return tryLock(QDeadlineTimer(timePoint));
}
};
+#if QT_CORE_INLINE_IMPL_SINCE(6, 6)
+bool QRecursiveMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT
+{
+ return tryLock(QDeadlineTimer(timeout));
+}
+#endif
+
template <typename Mutex>
-class [[nodiscard]] QMutexLocker
+class QMutexLocker
{
public:
+ Q_NODISCARD_CTOR
inline explicit QMutexLocker(Mutex *mutex) QT_MUTEX_LOCK_NOEXCEPT
{
m_mutex = mutex;
@@ -240,6 +225,7 @@ public:
}
}
+ Q_NODISCARD_CTOR
inline QMutexLocker(QMutexLocker &&other) noexcept
: m_mutex(std::exchange(other.m_mutex, nullptr)),
m_isLocked(std::exchange(other.m_isLocked, false))
@@ -323,9 +309,10 @@ private:
class QRecursiveMutex : public QMutex {};
template <typename Mutex>
-class [[nodiscard]] QMutexLocker
+class QMutexLocker
{
public:
+ Q_NODISCARD_CTOR
inline explicit QMutexLocker(Mutex *) noexcept {}
inline ~QMutexLocker() noexcept {}
diff --git a/src/corelib/thread/qmutex_mac.cpp b/src/corelib/thread/qmutex_mac.cpp
index a9e2330bf6..7849133e58 100644
--- a/src/corelib/thread/qmutex_mac.cpp
+++ b/src/corelib/thread/qmutex_mac.cpp
@@ -5,6 +5,8 @@
#include "qmutex.h"
#include "qmutex_p.h"
+#include "private/qcore_unix_p.h"
+
#include <mach/mach.h>
#include <mach/task.h>
@@ -26,18 +28,19 @@ QMutexPrivate::~QMutexPrivate()
qWarning("QMutex: failed to destroy semaphore, error %d", r);
}
-bool QMutexPrivate::wait(int timeout)
+bool QMutexPrivate::wait(QDeadlineTimer timeout)
{
kern_return_t r;
- if (timeout < 0) {
+ if (timeout.isForever()) {
do {
r = semaphore_wait(mach_semaphore);
} while (r == KERN_ABORTED);
Q_ASSERT(r == KERN_SUCCESS);
} else {
+ timespec tv = durationToTimespec(timeout.remainingTimeAsDuration());
mach_timespec_t ts;
- ts.tv_nsec = ((timeout % 1000) * 1000) * 1000;
- ts.tv_sec = (timeout / 1000);
+ ts.tv_nsec = tv.tv_nsec;
+ ts.tv_sec = tv.tv_sec;
r = semaphore_timedwait(mach_semaphore, ts);
}
return (r == KERN_SUCCESS);
diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h
index 13a9f10b01..aabb66fa55 100644
--- a/src/corelib/thread/qmutex_p.h
+++ b/src/corelib/thread/qmutex_p.h
@@ -28,10 +28,7 @@
#if defined(Q_OS_DARWIN)
# include <mach/semaphore.h>
#elif defined(Q_OS_UNIX)
-# if _POSIX_VERSION-0 >= 200112L || _XOPEN_VERSION-0 >= 600
# include <semaphore.h>
-# define QT_UNIX_SEMAPHORE
-# endif
#endif
struct timespec;
@@ -46,7 +43,7 @@ public:
~QMutexPrivate();
QMutexPrivate();
- bool wait(int timeout = -1);
+ bool wait(QDeadlineTimer timeout = QDeadlineTimer::Forever);
void wakeUp() noexcept;
// Control the lifetime of the privates
@@ -87,23 +84,11 @@ public:
//platform specific stuff
#if defined(Q_OS_DARWIN)
semaphore_t mach_semaphore;
-#elif defined(QT_UNIX_SEMAPHORE)
- sem_t semaphore;
#elif defined(Q_OS_UNIX)
- bool wakeup;
- pthread_mutex_t mutex;
- pthread_cond_t cond;
+ sem_t semaphore;
#endif
};
-
-#ifdef Q_OS_UNIX
-// helper functions for qmutex_unix.cpp and qwaitcondition_unix.cpp
-// they are in qwaitcondition_unix.cpp actually
-void qt_initialize_pthread_cond(pthread_cond_t *cond, const char *where);
-void qt_abstime_for_timeout(struct timespec *ts, QDeadlineTimer deadline);
-#endif
-
QT_END_NAMESPACE
#endif // QMUTEX_P_H
diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp
index f665f192a6..4d01deb7d4 100644
--- a/src/corelib/thread/qmutex_unix.cpp
+++ b/src/corelib/thread/qmutex_unix.cpp
@@ -5,7 +5,6 @@
#include "qplatformdefs.h"
#include "qmutex.h"
#include "qstring.h"
-#include "qelapsedtimer.h"
#include "qatomic.h"
#include "qmutex_p.h"
#include <errno.h>
@@ -19,105 +18,48 @@
QT_BEGIN_NAMESPACE
-static void report_error(int code, const char *where, const char *what)
+static void qt_report_error(int code, const char *where, const char *what)
{
if (code != 0)
qErrnoWarning(code, "%s: %s failure", where, what);
}
-#ifdef QT_UNIX_SEMAPHORE
-
QMutexPrivate::QMutexPrivate()
{
- report_error(sem_init(&semaphore, 0, 0), "QMutex", "sem_init");
+ qt_report_error(sem_init(&semaphore, 0, 0), "QMutex", "sem_init");
}
QMutexPrivate::~QMutexPrivate()
{
- report_error(sem_destroy(&semaphore), "QMutex", "sem_destroy");
+ qt_report_error(sem_destroy(&semaphore), "QMutex", "sem_destroy");
}
-bool QMutexPrivate::wait(int timeout)
+bool QMutexPrivate::wait(QDeadlineTimer timeout)
{
int errorCode;
- if (timeout < 0) {
+ if (timeout.isForever()) {
do {
errorCode = sem_wait(&semaphore);
} while (errorCode && errno == EINTR);
- report_error(errorCode, "QMutex::lock()", "sem_wait");
+ qt_report_error(errorCode, "QMutex::lock()", "sem_wait");
} else {
- timespec ts;
- report_error(clock_gettime(CLOCK_REALTIME, &ts), "QMutex::lock()", "clock_gettime");
- ts.tv_sec += timeout / 1000;
- ts.tv_nsec += timeout % 1000 * Q_UINT64_C(1000) * 1000;
- normalizedTimespec(ts);
do {
+ auto tp = timeout.deadline<std::chrono::system_clock>();
+ timespec ts = durationToTimespec(tp.time_since_epoch());
errorCode = sem_timedwait(&semaphore, &ts);
} while (errorCode && errno == EINTR);
if (errorCode && errno == ETIMEDOUT)
return false;
- report_error(errorCode, "QMutex::lock()", "sem_timedwait");
+ qt_report_error(errorCode, "QMutex::lock()", "sem_timedwait");
}
return true;
}
void QMutexPrivate::wakeUp() noexcept
{
- report_error(sem_post(&semaphore), "QMutex::unlock", "sem_post");
-}
-
-#else // QT_UNIX_SEMAPHORE
-
-QMutexPrivate::QMutexPrivate()
- : wakeup(false)
-{
- report_error(pthread_mutex_init(&mutex, NULL), "QMutex", "mutex init");
- qt_initialize_pthread_cond(&cond, "QMutex");
-}
-
-QMutexPrivate::~QMutexPrivate()
-{
- report_error(pthread_cond_destroy(&cond), "QMutex", "cv destroy");
- report_error(pthread_mutex_destroy(&mutex), "QMutex", "mutex destroy");
-}
-
-bool QMutexPrivate::wait(int timeout)
-{
- report_error(pthread_mutex_lock(&mutex), "QMutex::lock", "mutex lock");
- int errorCode = 0;
- while (!wakeup) {
- if (timeout < 0) {
- errorCode = pthread_cond_wait(&cond, &mutex);
- } else {
- timespec ti;
- qt_abstime_for_timeout(&ti, QDeadlineTimer(timeout));
- errorCode = pthread_cond_timedwait(&cond, &mutex, &ti);
- }
- if (errorCode) {
- if (errorCode == ETIMEDOUT) {
- if (wakeup)
- errorCode = 0;
- break;
- }
- report_error(errorCode, "QMutex::lock()", "cv wait");
- }
- }
- bool ret = wakeup;
- wakeup = false;
- report_error(pthread_mutex_unlock(&mutex), "QMutex::lock", "mutex unlock");
- return ret;
-}
-
-void QMutexPrivate::wakeUp() noexcept
-{
- report_error(pthread_mutex_lock(&mutex), "QMutex::unlock", "mutex lock");
- wakeup = true;
- report_error(pthread_cond_signal(&cond), "QMutex::unlock", "cv signal");
- report_error(pthread_mutex_unlock(&mutex), "QMutex::unlock", "mutex unlock");
+ qt_report_error(sem_post(&semaphore), "QMutex::unlock", "sem_post");
}
-#endif
-
QT_END_NAMESPACE
diff --git a/src/corelib/thread/qorderedmutexlocker_p.h b/src/corelib/thread/qorderedmutexlocker_p.h
index 730ba61273..fb2e223e01 100644
--- a/src/corelib/thread/qorderedmutexlocker_p.h
+++ b/src/corelib/thread/qorderedmutexlocker_p.h
@@ -31,6 +31,7 @@ QT_BEGIN_NAMESPACE
class QOrderedMutexLocker
{
public:
+ Q_NODISCARD_CTOR
QOrderedMutexLocker(QBasicMutex *m1, QBasicMutex *m2)
: mtx1((m1 == m2) ? m1 : (std::less<QBasicMutex *>()(m1, m2) ? m1 : m2)),
mtx2((m1 == m2) ? nullptr : (std::less<QBasicMutex *>()(m1, m2) ? m2 : m1)),
@@ -50,6 +51,7 @@ public:
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QOrderedMutexLocker)
+ Q_NODISCARD_CTOR
QOrderedMutexLocker(QOrderedMutexLocker &&other) noexcept
: mtx1(std::exchange(other.mtx1, nullptr))
, mtx2(std::exchange(other.mtx2, nullptr))
@@ -116,42 +118,15 @@ private:
bool locked;
};
-class QBasicMutexLocker
-{
-public:
- inline explicit QBasicMutexLocker(QBasicMutex *m) QT_MUTEX_LOCK_NOEXCEPT
- : m(m), isLocked(true)
- {
- m->lock();
- }
- inline ~QBasicMutexLocker() { if (isLocked) unlock(); }
-
- inline void unlock() noexcept
- {
- isLocked = false;
- m->unlock();
- }
-
- inline void relock() QT_MUTEX_LOCK_NOEXCEPT
- {
- isLocked = true;
- m->lock();
- }
-
-private:
- Q_DISABLE_COPY(QBasicMutexLocker)
-
- QBasicMutex *m;
- bool isLocked;
-};
-
#else
class QOrderedMutexLocker
{
public:
Q_DISABLE_COPY(QOrderedMutexLocker)
+ Q_NODISCARD_CTOR
QOrderedMutexLocker(QBasicMutex *, QBasicMutex *) {}
+ Q_NODISCARD_CTOR
QOrderedMutexLocker(QOrderedMutexLocker &&) = default;
QOrderedMutexLocker& operator=(QOrderedMutexLocker &&other) = default;
~QOrderedMutexLocker() {}
@@ -163,8 +138,6 @@ public:
static bool relock(QBasicMutex *, QBasicMutex *) { return false; }
};
-using QBasicMutexLocker = QMutexLocker<QBasicMutex>;
-
#endif
diff --git a/src/corelib/thread/qpromise.h b/src/corelib/thread/qpromise.h
index 9be9526ef6..c2b6c119ae 100644
--- a/src/corelib/thread/qpromise.h
+++ b/src/corelib/thread/qpromise.h
@@ -46,10 +46,20 @@ public:
// Core QPromise APIs
QFuture<T> future() const { return d.future(); }
- template<typename U, typename = QtPrivate::EnableIfSameOrConvertible<U, T>>
+ template<typename...Args, std::enable_if_t<std::is_constructible_v<T, Args...>, bool> = true>
+ bool emplaceResultAt(int index, Args&&...args)
+ {
+ return d.reportAndEmplaceResult(index, std::forward<Args>(args)...);
+ }
+ template<typename...Args, std::enable_if_t<std::is_constructible_v<T, Args...>, bool> = true>
+ bool emplaceResult(Args&&...args)
+ {
+ return d.reportAndEmplaceResult(-1, std::forward<Args>(args)...);
+ }
+ template<typename U = T, typename = QtPrivate::EnableIfSameOrConvertible<U, T>>
bool addResult(U &&result, int index = -1)
{
- return d.reportResult(std::forward<U>(result), index);
+ return d.reportAndEmplaceResult(index, std::forward<U>(result));
}
bool addResults(const QList<T> &result)
{ return d.reportResults(result); }
diff --git a/src/corelib/thread/qpromise.qdoc b/src/corelib/thread/qpromise.qdoc
index 37ffa8485e..e9c3eb4b7e 100644
--- a/src/corelib/thread/qpromise.qdoc
+++ b/src/corelib/thread/qpromise.qdoc
@@ -91,15 +91,38 @@
/*! \fn template <typename T> bool QPromise<T>::addResult(const T &result, int index = -1)
\fn template <typename T> bool QPromise<T>::addResult(T &&result, int index = -1)
- Adds \a result to the internal result collection at \a index position. If
- index is unspecified, \a result is added to the end of the collection.
+ Same as
+ \code
+ emplaceResultAt(index, result); // first overload
+ emplaceResultAt(index, std::move(result)); // second overload
+ \endcode
+ or, if \c{index == -1} (the default)
+ \code
+ emplaceResult(result); // first overload
+ emplaceResult(std::move(result)); // second overload
+ \endcode
+
+ \sa emplaceResultAt(), emplaceResult(), addResults()
+*/
+
+/*!
+ \fn template <typename T> template <typename...Args, std::enable_if_t<std::is_constructible_v<T, Args...>, bool> = true> bool QPromise<T>::emplaceResultAt(int index, Args&&...args)
+ \fn template <typename T> template <typename...Args, std::enable_if_t<std::is_constructible_v<T, Args...>, bool> = true> bool QPromise<T>::emplaceResult(Args&&...args)
+ \since 6.6
+
+ Adds a result constructed from \a args... to the internal result collection
+ at \a index position (emplaceResultAt()) or the end of of the collection
+ (emplaceResult()).
- Returns \c true when \a result is added to the collection.
+ Returns \c true when the result was added to the collection.
Returns \c false when this promise is in canceled or finished state or when
- \a result is rejected. addResult() rejects \a result if there's already
+ the result was rejected. addResult() rejects to add a result if there's already
another result in the collection stored at the same index.
+ These functions only participate in overload resolutions if \c T is
+ constructible from \a args....
+
You can get a result at a specific index by calling QFuture::resultAt().
\note It is possible to specify an arbitrary index and request result at
@@ -108,7 +131,7 @@
QFuture::const_iterator. In order to get all available results without
thinking if there are index gaps or not, use QFuture::results().
- \sa addResults()
+ \sa addResult(), addResults()
*/
/*!
diff --git a/src/corelib/thread/qreadwritelock.cpp b/src/corelib/thread/qreadwritelock.cpp
index 274d0ba7f8..e79bed2231 100644
--- a/src/corelib/thread/qreadwritelock.cpp
+++ b/src/corelib/thread/qreadwritelock.cpp
@@ -6,11 +6,8 @@
#include "qplatformdefs.h"
#include "qreadwritelock.h"
-#include "qmutex.h"
#include "qthread.h"
-#include "qwaitcondition.h"
#include "qreadwritelock_p.h"
-#include "qelapsedtimer.h"
#include "private/qfreelist_p.h"
#include "private/qlocking_p.h"
@@ -30,21 +27,22 @@ QT_BEGIN_NAMESPACE
* - In any other case, d_ptr points to an actual QReadWriteLockPrivate.
*/
+using namespace QReadWriteLockStates;
namespace {
-using ms = std::chrono::milliseconds;
+using steady_clock = std::chrono::steady_clock;
-enum {
- StateMask = 0x3,
- StateLockedForRead = 0x1,
- StateLockedForWrite = 0x2,
-};
const auto dummyLockedForRead = reinterpret_cast<QReadWriteLockPrivate *>(quintptr(StateLockedForRead));
const auto dummyLockedForWrite = reinterpret_cast<QReadWriteLockPrivate *>(quintptr(StateLockedForWrite));
inline bool isUncontendedLocked(const QReadWriteLockPrivate *d)
{ return quintptr(d) & StateMask; }
}
+static bool contendedTryLockForRead(QAtomicPointer<QReadWriteLockPrivate> &d_ptr,
+ QDeadlineTimer timeout, QReadWriteLockPrivate *d);
+static bool contendedTryLockForWrite(QAtomicPointer<QReadWriteLockPrivate> &d_ptr,
+ QDeadlineTimer timeout, QReadWriteLockPrivate *d);
+
/*! \class QReadWriteLock
\inmodule QtCore
\brief The QReadWriteLock class provides read-write locking.
@@ -102,6 +100,7 @@ inline bool isUncontendedLocked(const QReadWriteLockPrivate *d)
*/
/*!
+ \fn QReadWriteLock::QReadWriteLock(RecursionMode recursionMode)
\since 4.4
Constructs a QReadWriteLock object in the given \a recursionMode.
@@ -110,21 +109,22 @@ inline bool isUncontendedLocked(const QReadWriteLockPrivate *d)
\sa lockForRead(), lockForWrite(), RecursionMode
*/
-QReadWriteLock::QReadWriteLock(RecursionMode recursionMode)
- : d_ptr(recursionMode == Recursive ? new QReadWriteLockPrivate(true) : nullptr)
+QReadWriteLockPrivate *QReadWriteLock::initRecursive()
{
- Q_ASSERT_X(!(quintptr(d_ptr.loadRelaxed()) & StateMask), "QReadWriteLock::QReadWriteLock", "bad d_ptr alignment");
+ auto d = new QReadWriteLockPrivate(true);
+ Q_ASSERT_X(!(quintptr(d) & StateMask), "QReadWriteLock::QReadWriteLock", "bad d_ptr alignment");
+ return d;
}
/*!
+ \fn QReadWriteLock::~QReadWriteLock()
Destroys the QReadWriteLock object.
\warning Destroying a read-write lock that is in use may result
in undefined behavior.
*/
-QReadWriteLock::~QReadWriteLock()
+void QReadWriteLock::destroyRecursive(QReadWriteLockPrivate *d)
{
- auto d = d_ptr.loadAcquire();
if (isUncontendedLocked(d)) {
qWarning("QReadWriteLock: destroying locked QReadWriteLock");
return;
@@ -133,6 +133,7 @@ QReadWriteLock::~QReadWriteLock()
}
/*!
+ \fn QReadWriteLock::lockForRead()
Locks the lock for reading. This function will block the current
thread if another thread has locked for writing.
@@ -141,20 +142,18 @@ QReadWriteLock::~QReadWriteLock()
\sa unlock(), lockForWrite(), tryLockForRead()
*/
-void QReadWriteLock::lockForRead()
-{
- if (d_ptr.testAndSetAcquire(nullptr, dummyLockedForRead))
- return;
- tryLockForRead(-1);
-}
/*!
- Attempts to lock for reading. If the lock was obtained, this
- function returns \c true, otherwise it returns \c false instead of
- waiting for the lock to become available, i.e. it does not block.
+ \fn bool QReadWriteLock::tryLockForRead(int timeout)
+
+ Attempts to lock for reading. This function returns \c true if the
+ lock was obtained; otherwise it returns \c false. If another thread
+ has locked for writing, this function will wait for at most \a
+ timeout milliseconds for the lock to become available.
- The lock attempt will fail if another thread has locked for
- writing.
+ Note: Passing a negative number as the \a timeout is equivalent to
+ calling lockForRead(), i.e. this function will wait forever until
+ lock can be locked for reading when \a timeout is negative.
If the lock was obtained, the lock must be unlocked with unlock()
before another thread can successfully lock it for writing.
@@ -164,21 +163,15 @@ void QReadWriteLock::lockForRead()
\sa unlock(), lockForRead()
*/
-bool QReadWriteLock::tryLockForRead()
-{
- return tryLockForRead(0);
-}
-/*! \overload
-
- Attempts to lock for reading. This function returns \c true if the
- lock was obtained; otherwise it returns \c false. If another thread
- has locked for writing, this function will wait for at most \a
- timeout milliseconds for the lock to become available.
+/*!
+ \overload
+ \since 6.6
- Note: Passing a negative number as the \a timeout is equivalent to
- calling lockForRead(), i.e. this function will wait forever until
- lock can be locked for reading when \a timeout is negative.
+ Attempts to lock for reading. This function returns \c true if the lock was
+ obtained; otherwise it returns \c false. If another thread has locked for
+ writing, this function will wait until \a timeout expires for the lock to
+ become available.
If the lock was obtained, the lock must be unlocked with unlock()
before another thread can successfully lock it for writing.
@@ -188,13 +181,18 @@ bool QReadWriteLock::tryLockForRead()
\sa unlock(), lockForRead()
*/
-bool QReadWriteLock::tryLockForRead(int timeout)
+bool QReadWriteLock::tryLockForRead(QDeadlineTimer timeout)
{
// Fast case: non contended:
- QReadWriteLockPrivate *d;
- if (d_ptr.testAndSetAcquire(nullptr, dummyLockedForRead, d))
+ QReadWriteLockPrivate *d = d_ptr.loadRelaxed();
+ if (d == nullptr && d_ptr.testAndSetAcquire(nullptr, dummyLockedForRead, d))
return true;
+ return contendedTryLockForRead(d_ptr, timeout, d);
+}
+Q_NEVER_INLINE static bool contendedTryLockForRead(QAtomicPointer<QReadWriteLockPrivate> &d_ptr,
+ QDeadlineTimer timeout, QReadWriteLockPrivate *d)
+{
while (true) {
if (d == nullptr) {
if (!d_ptr.testAndSetAcquire(nullptr, dummyLockedForRead, d))
@@ -213,7 +211,7 @@ bool QReadWriteLock::tryLockForRead(int timeout)
}
if (d == dummyLockedForWrite) {
- if (!timeout)
+ if (timeout.hasExpired())
return false;
// locked for write, assign a d_ptr and wait.
@@ -248,6 +246,7 @@ bool QReadWriteLock::tryLockForRead(int timeout)
}
/*!
+ \fn QReadWriteLock::lockForWrite()
Locks the lock for writing. This function will block the current
thread if another thread (including the current) has locked for
reading or writing (unless the lock has been created using the
@@ -258,17 +257,18 @@ bool QReadWriteLock::tryLockForRead(int timeout)
\sa unlock(), lockForRead(), tryLockForWrite()
*/
-void QReadWriteLock::lockForWrite()
-{
- tryLockForWrite(-1);
-}
/*!
- Attempts to lock for writing. If the lock was obtained, this
- function returns \c true; otherwise, it returns \c false immediately.
+ \fn QReadWriteLock::tryLockForWrite(int timeout)
+
+ Attempts to lock for writing. This function returns \c true if the
+ lock was obtained; otherwise it returns \c false. If another thread
+ has locked for reading or writing, this function will wait for at
+ most \a timeout milliseconds for the lock to become available.
- The lock attempt will fail if another thread has locked for
- reading or writing.
+ Note: Passing a negative number as the \a timeout is equivalent to
+ calling lockForWrite(), i.e. this function will wait forever until
+ lock can be locked for writing when \a timeout is negative.
If the lock was obtained, the lock must be unlocked with unlock()
before another thread can successfully lock it.
@@ -278,21 +278,15 @@ void QReadWriteLock::lockForWrite()
\sa unlock(), lockForWrite()
*/
-bool QReadWriteLock::tryLockForWrite()
-{
- return tryLockForWrite(0);
-}
-
-/*! \overload
- Attempts to lock for writing. This function returns \c true if the
- lock was obtained; otherwise it returns \c false. If another thread
- has locked for reading or writing, this function will wait for at
- most \a timeout milliseconds for the lock to become available.
+/*!
+ \overload
+ \since 6.6
- Note: Passing a negative number as the \a timeout is equivalent to
- calling lockForWrite(), i.e. this function will wait forever until
- lock can be locked for writing when \a timeout is negative.
+ Attempts to lock for writing. This function returns \c true if the lock was
+ obtained; otherwise it returns \c false. If another thread has locked for
+ reading or writing, this function will wait until \a timeout expires for
+ the lock to become available.
If the lock was obtained, the lock must be unlocked with unlock()
before another thread can successfully lock it.
@@ -302,13 +296,18 @@ bool QReadWriteLock::tryLockForWrite()
\sa unlock(), lockForWrite()
*/
-bool QReadWriteLock::tryLockForWrite(int timeout)
+bool QReadWriteLock::tryLockForWrite(QDeadlineTimer timeout)
{
// Fast case: non contended:
- QReadWriteLockPrivate *d;
- if (d_ptr.testAndSetAcquire(nullptr, dummyLockedForWrite, d))
+ QReadWriteLockPrivate *d = d_ptr.loadRelaxed();
+ if (d == nullptr && d_ptr.testAndSetAcquire(nullptr, dummyLockedForWrite, d))
return true;
+ return contendedTryLockForWrite(d_ptr, timeout, d);
+}
+Q_NEVER_INLINE static bool contendedTryLockForWrite(QAtomicPointer<QReadWriteLockPrivate> &d_ptr,
+ QDeadlineTimer timeout, QReadWriteLockPrivate *d)
+{
while (true) {
if (d == nullptr) {
if (!d_ptr.testAndSetAcquire(d, dummyLockedForWrite, d))
@@ -317,7 +316,7 @@ bool QReadWriteLock::tryLockForWrite(int timeout)
}
if (isUncontendedLocked(d)) {
- if (!timeout)
+ if (timeout.hasExpired())
return false;
// locked for either read or write, assign a d_ptr and wait.
@@ -411,43 +410,16 @@ void QReadWriteLock::unlock()
}
}
-/*! \internal Helper for QWaitCondition::wait */
-QReadWriteLock::StateForWaitCondition QReadWriteLock::stateForWaitCondition() const
-{
- QReadWriteLockPrivate *d = d_ptr.loadAcquire();
- switch (quintptr(d) & StateMask) {
- case StateLockedForRead: return LockedForRead;
- case StateLockedForWrite: return LockedForWrite;
- }
-
- if (!d)
- return Unlocked;
- const auto lock = qt_scoped_lock(d->mutex);
- if (d->writerCount > 1)
- return RecursivelyLocked;
- else if (d->writerCount == 1)
- return LockedForWrite;
- return LockedForRead;
-
-}
-
-bool QReadWriteLockPrivate::lockForRead(std::unique_lock<QtPrivate::mutex> &lock, int timeout)
+bool QReadWriteLockPrivate::lockForRead(std::unique_lock<std::mutex> &lock, QDeadlineTimer timeout)
{
Q_ASSERT(!mutex.try_lock()); // mutex must be locked when entering this function
- QElapsedTimer t;
- if (timeout > 0)
- t.start();
-
while (waitingWriters || writerCount) {
- if (timeout == 0)
+ if (timeout.hasExpired())
return false;
- if (timeout > 0) {
- auto elapsed = t.elapsed();
- if (elapsed > timeout)
- return false;
+ if (!timeout.isForever()) {
waitingReaders++;
- readerCond.wait_for(lock, ms{timeout - elapsed});
+ readerCond.wait_until(lock, timeout.deadline<steady_clock>());
} else {
waitingReaders++;
readerCond.wait(lock);
@@ -459,29 +431,22 @@ bool QReadWriteLockPrivate::lockForRead(std::unique_lock<QtPrivate::mutex> &lock
return true;
}
-bool QReadWriteLockPrivate::lockForWrite(std::unique_lock<QtPrivate::mutex> &lock, int timeout)
+bool QReadWriteLockPrivate::lockForWrite(std::unique_lock<std::mutex> &lock, QDeadlineTimer timeout)
{
Q_ASSERT(!mutex.try_lock()); // mutex must be locked when entering this function
- QElapsedTimer t;
- if (timeout > 0)
- t.start();
-
while (readerCount || writerCount) {
- if (timeout == 0)
- return false;
- if (timeout > 0) {
- auto elapsed = t.elapsed();
- if (elapsed > timeout) {
- if (waitingReaders && !waitingWriters && !writerCount) {
- // We timed out and now there is no more writers or waiting writers, but some
- // readers were queued (probably because of us). Wake the waiting readers.
- readerCond.notify_all();
- }
- return false;
+ if (timeout.hasExpired()) {
+ if (waitingReaders && !waitingWriters && !writerCount) {
+ // We timed out and now there is no more writers or waiting writers, but some
+ // readers were queued (probably because of us). Wake the waiting readers.
+ readerCond.notify_all();
}
+ return false;
+ }
+ if (!timeout.isForever()) {
waitingWriters++;
- writerCond.wait_for(lock, ms{timeout - elapsed});
+ writerCond.wait_until(lock, timeout.deadline<steady_clock>());
} else {
waitingWriters++;
writerCond.wait(lock);
@@ -509,7 +474,7 @@ static auto handleEquals(Qt::HANDLE handle)
return [handle](QReadWriteLockPrivate::Reader reader) { return reader.handle == handle; };
}
-bool QReadWriteLockPrivate::recursiveLockForRead(int timeout)
+bool QReadWriteLockPrivate::recursiveLockForRead(QDeadlineTimer timeout)
{
Q_ASSERT(recursive);
auto lock = qt_unique_lock(mutex);
@@ -531,7 +496,7 @@ bool QReadWriteLockPrivate::recursiveLockForRead(int timeout)
return true;
}
-bool QReadWriteLockPrivate::recursiveLockForWrite(int timeout)
+bool QReadWriteLockPrivate::recursiveLockForWrite(QDeadlineTimer timeout)
{
Q_ASSERT(recursive);
auto lock = qt_unique_lock(mutex);
diff --git a/src/corelib/thread/qreadwritelock.h b/src/corelib/thread/qreadwritelock.h
index 8e96e23ad2..6ca9be440a 100644
--- a/src/corelib/thread/qreadwritelock.h
+++ b/src/corelib/thread/qreadwritelock.h
@@ -5,10 +5,10 @@
#define QREADWRITELOCK_H
#include <QtCore/qglobal.h>
+#include <QtCore/qdeadlinetimer.h>
QT_BEGIN_NAMESPACE
-
#if QT_CONFIG(thread)
class QReadWriteLockPrivate;
@@ -18,36 +18,81 @@ class Q_CORE_EXPORT QReadWriteLock
public:
enum RecursionMode { NonRecursive, Recursive };
+ QT_CORE_INLINE_SINCE(6, 6)
explicit QReadWriteLock(RecursionMode recursionMode = NonRecursive);
+ QT_CORE_INLINE_SINCE(6, 6)
~QReadWriteLock();
+ QT_CORE_INLINE_SINCE(6, 6)
void lockForRead();
+#if QT_CORE_REMOVED_SINCE(6, 6)
bool tryLockForRead();
+#endif
+ QT_CORE_INLINE_SINCE(6, 6)
bool tryLockForRead(int timeout);
+ bool tryLockForRead(QDeadlineTimer timeout = {});
+ QT_CORE_INLINE_SINCE(6, 6)
void lockForWrite();
+#if QT_CORE_REMOVED_SINCE(6, 6)
bool tryLockForWrite();
+#endif
+ QT_CORE_INLINE_SINCE(6, 6)
bool tryLockForWrite(int timeout);
+ bool tryLockForWrite(QDeadlineTimer timeout = {});
void unlock();
private:
Q_DISABLE_COPY(QReadWriteLock)
QAtomicPointer<QReadWriteLockPrivate> d_ptr;
-
- enum StateForWaitCondition { LockedForRead, LockedForWrite, Unlocked, RecursivelyLocked };
- StateForWaitCondition stateForWaitCondition() const;
- friend class QWaitCondition;
+ friend class QReadWriteLockPrivate;
+ static QReadWriteLockPrivate *initRecursive();
+ static void destroyRecursive(QReadWriteLockPrivate *);
};
+#if QT_CORE_INLINE_IMPL_SINCE(6, 6)
+QReadWriteLock::QReadWriteLock(RecursionMode recursionMode)
+ : d_ptr(recursionMode == Recursive ? initRecursive() : nullptr)
+{
+}
+
+QReadWriteLock::~QReadWriteLock()
+{
+ if (auto d = d_ptr.loadAcquire())
+ destroyRecursive(d);
+}
+
+void QReadWriteLock::lockForRead()
+{
+ tryLockForRead(QDeadlineTimer(QDeadlineTimer::Forever));
+}
+
+bool QReadWriteLock::tryLockForRead(int timeout)
+{
+ return tryLockForRead(QDeadlineTimer(timeout));
+}
+
+void QReadWriteLock::lockForWrite()
+{
+ tryLockForWrite(QDeadlineTimer(QDeadlineTimer::Forever));
+}
+
+bool QReadWriteLock::tryLockForWrite(int timeout)
+{
+ return tryLockForWrite(QDeadlineTimer(timeout));
+}
+#endif // inline since 6.6
+
#if defined(Q_CC_MSVC)
#pragma warning( push )
#pragma warning( disable : 4312 ) // ignoring the warning from /Wp64
#endif
-class Q_CORE_EXPORT QReadLocker
+class QT6_ONLY(Q_CORE_EXPORT) QReadLocker
{
public:
+ Q_NODISCARD_CTOR
inline QReadLocker(QReadWriteLock *readWriteLock);
inline ~QReadLocker()
@@ -89,9 +134,10 @@ inline QReadLocker::QReadLocker(QReadWriteLock *areadWriteLock)
relock();
}
-class Q_CORE_EXPORT QWriteLocker
+class QT6_ONLY(Q_CORE_EXPORT) QWriteLocker
{
public:
+ Q_NODISCARD_CTOR
inline QWriteLocker(QReadWriteLock *readWriteLock);
inline ~QWriteLocker()
@@ -140,7 +186,7 @@ inline QWriteLocker::QWriteLocker(QReadWriteLock *areadWriteLock)
#else // QT_CONFIG(thread)
-class Q_CORE_EXPORT QReadWriteLock
+class QT6_ONLY(Q_CORE_EXPORT) QReadWriteLock
{
public:
enum RecursionMode { NonRecursive, Recursive };
@@ -149,10 +195,12 @@ public:
void lockForRead() noexcept { }
bool tryLockForRead() noexcept { return true; }
+ bool tryLockForRead(QDeadlineTimer) noexcept { return true; }
bool tryLockForRead(int timeout) noexcept { Q_UNUSED(timeout); return true; }
void lockForWrite() noexcept { }
bool tryLockForWrite() noexcept { return true; }
+ bool tryLockForWrite(QDeadlineTimer) noexcept { return true; }
bool tryLockForWrite(int timeout) noexcept { Q_UNUSED(timeout); return true; }
void unlock() noexcept { }
@@ -161,9 +209,10 @@ private:
Q_DISABLE_COPY(QReadWriteLock)
};
-class Q_CORE_EXPORT QReadLocker
+class QT6_ONLY(Q_CORE_EXPORT) QReadLocker
{
public:
+ Q_NODISCARD_CTOR
inline explicit QReadLocker(QReadWriteLock *) noexcept { }
inline ~QReadLocker() noexcept { }
@@ -175,9 +224,10 @@ private:
Q_DISABLE_COPY(QReadLocker)
};
-class Q_CORE_EXPORT QWriteLocker
+class QT6_ONLY(Q_CORE_EXPORT) QWriteLocker
{
public:
+ Q_NODISCARD_CTOR
inline explicit QWriteLocker(QReadWriteLock *) noexcept { }
inline ~QWriteLocker() noexcept { }
diff --git a/src/corelib/thread/qreadwritelock_p.h b/src/corelib/thread/qreadwritelock_p.h
index e1d42fbbf3..68fa642a73 100644
--- a/src/corelib/thread/qreadwritelock_p.h
+++ b/src/corelib/thread/qreadwritelock_p.h
@@ -16,23 +16,39 @@
// We mean it.
//
-#include <QtCore/private/qglobal_p.h>
+#include <QtCore/private/qlocking_p.h>
#include <QtCore/private/qwaitcondition_p.h>
+#include <QtCore/qreadwritelock.h>
#include <QtCore/qvarlengtharray.h>
QT_REQUIRE_CONFIG(thread);
QT_BEGIN_NAMESPACE
+namespace QReadWriteLockStates {
+enum {
+ StateMask = 0x3,
+ StateLockedForRead = 0x1,
+ StateLockedForWrite = 0x2,
+};
+enum StateForWaitCondition {
+ LockedForRead,
+ LockedForWrite,
+ Unlocked,
+ RecursivelyLocked
+};
+}
+
class QReadWriteLockPrivate
{
public:
explicit QReadWriteLockPrivate(bool isRecursive = false)
: recursive(isRecursive) {}
- QtPrivate::mutex mutex;
- QtPrivate::condition_variable writerCond;
- QtPrivate::condition_variable readerCond;
+ alignas(QtPrivate::IdealMutexAlignment) std::condition_variable writerCond;
+ std::condition_variable readerCond;
+
+ alignas(QtPrivate::IdealMutexAlignment) std::mutex mutex;
int readerCount = 0;
int writerCount = 0;
int waitingReaders = 0;
@@ -40,8 +56,8 @@ public:
const bool recursive;
//Called with the mutex locked
- bool lockForWrite(std::unique_lock<QtPrivate::mutex> &lock, int timeout);
- bool lockForRead(std::unique_lock<QtPrivate::mutex> &lock, int timeout);
+ bool lockForWrite(std::unique_lock<std::mutex> &lock, QDeadlineTimer timeout);
+ bool lockForRead(std::unique_lock<std::mutex> &lock, QDeadlineTimer timeout);
void unlock();
//memory management
@@ -60,11 +76,36 @@ public:
QVarLengthArray<Reader, 16> currentReaders;
// called with the mutex unlocked
- bool recursiveLockForWrite(int timeout);
- bool recursiveLockForRead(int timeout);
+ bool recursiveLockForWrite(QDeadlineTimer timeout);
+ bool recursiveLockForRead(QDeadlineTimer timeout);
void recursiveUnlock();
+
+ static QReadWriteLockStates::StateForWaitCondition
+ stateForWaitCondition(const QReadWriteLock *lock);
};
-Q_DECLARE_TYPEINFO(QReadWriteLockPrivate::Reader, Q_PRIMITIVE_TYPE);
+Q_DECLARE_TYPEINFO(QReadWriteLockPrivate::Reader, Q_PRIMITIVE_TYPE);\
+
+/*! \internal Helper for QWaitCondition::wait */
+inline QReadWriteLockStates::StateForWaitCondition
+QReadWriteLockPrivate::stateForWaitCondition(const QReadWriteLock *q)
+{
+ using namespace QReadWriteLockStates;
+ QReadWriteLockPrivate *d = q->d_ptr.loadAcquire();
+ switch (quintptr(d) & StateMask) {
+ case StateLockedForRead: return LockedForRead;
+ case StateLockedForWrite: return LockedForWrite;
+ }
+
+ if (!d)
+ return Unlocked;
+ const auto lock = qt_scoped_lock(d->mutex);
+ if (d->writerCount > 1)
+ return RecursivelyLocked;
+ else if (d->writerCount == 1)
+ return LockedForWrite;
+ return LockedForRead;
+
+}
QT_END_NAMESPACE
diff --git a/src/corelib/thread/qresultstore.h b/src/corelib/thread/qresultstore.h
index af559b7a96..30ce1fe904 100644
--- a/src/corelib/thread/qresultstore.h
+++ b/src/corelib/thread/qresultstore.h
@@ -134,6 +134,14 @@ protected:
}
public:
+ template <typename T, typename...Args>
+ int emplaceResult(int index, Args&&...args)
+ {
+ if (containsValidResultItem(index)) // reject if already present
+ return -1;
+ return addResult(index, static_cast<void *>(new T(std::forward<Args>(args)...)));
+ }
+
template <typename T>
int addResult(int index, const T *result)
{
@@ -149,10 +157,9 @@ public:
template <typename T>
int moveResult(int index, T &&result)
{
- if (containsValidResultItem(index)) // reject if already present
- return -1;
+ static_assert(!std::is_reference_v<T>, "trying to move from an lvalue!");
- return addResult(index, static_cast<void *>(new T(std::move_if_noexcept(result))));
+ return emplaceResult<std::remove_cv_t<T>>(index, std::forward<T>(result));
}
template<typename T>
diff --git a/src/corelib/thread/qrunnable.cpp b/src/corelib/thread/qrunnable.cpp
index 5bb354cbb1..f9d69ed5cb 100644
--- a/src/corelib/thread/qrunnable.cpp
+++ b/src/corelib/thread/qrunnable.cpp
@@ -3,6 +3,8 @@
#include "qrunnable.h"
+#include <QtCore/qlogging.h>
+
QT_BEGIN_NAMESPACE
QRunnable::~QRunnable()
@@ -10,6 +12,27 @@ QRunnable::~QRunnable()
}
/*!
+ \internal
+ Prints a warning and returns nullptr.
+*/
+QRunnable *QRunnable::warnNullCallable()
+{
+ qWarning("Trying to create null QRunnable. This may stop working.");
+ return nullptr;
+}
+
+
+QRunnable::QGenericRunnable::~QGenericRunnable()
+{
+ runHelper->destroy();
+}
+
+void QRunnable::QGenericRunnable::run()
+{
+ runHelper->run();
+}
+
+/*!
\class QRunnable
\inmodule QtCore
\since 4.4
@@ -77,31 +100,20 @@ QRunnable::~QRunnable()
\sa autoDelete(), QThreadPool
*/
-class FunctionRunnable : public QRunnable
-{
- std::function<void()> m_functionToRun;
-public:
- FunctionRunnable(std::function<void()> functionToRun) : m_functionToRun(std::move(functionToRun))
- {
- }
- void run() override
- {
- m_functionToRun();
- }
-};
-
/*!
+ \fn template<typename Callable, QRunnable::if_callable<Callable>> QRunnable *QRunnable::create(Callable &&callableToRun);
\since 5.15
- Creates a QRunnable that calls \a functionToRun in run().
+ Creates a QRunnable that calls \a callableToRun in run().
Auto-deletion is enabled by default.
+ \note This function participates in overload resolution only if \c Callable
+ is a function or function object which can be called with zero arguments.
+
+ \note In Qt versions prior to 6.6, this method took copyable functions only.
+
\sa run(), autoDelete()
*/
-QRunnable *QRunnable::create(std::function<void()> functionToRun)
-{
- return new FunctionRunnable(std::move(functionToRun));
-}
QT_END_NAMESPACE
diff --git a/src/corelib/thread/qrunnable.h b/src/corelib/thread/qrunnable.h
index c77f8eea0a..f0dd0a582e 100644
--- a/src/corelib/thread/qrunnable.h
+++ b/src/corelib/thread/qrunnable.h
@@ -1,11 +1,16 @@
-// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QRUNNABLE_H
#define QRUNNABLE_H
-#include <QtCore/qglobal.h>
+#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qfunctionaltools_impl.h>
+#include <QtCore/qtclasshelpermacros.h>
+#include <QtCore/qtcoreexports.h>
+
#include <functional>
+#include <type_traits>
QT_BEGIN_NAMESPACE
@@ -19,12 +24,114 @@ public:
constexpr QRunnable() noexcept = default;
virtual ~QRunnable();
+#if QT_CORE_REMOVED_SINCE(6, 6)
static QRunnable *create(std::function<void()> functionToRun);
+#endif
+ template <typename Callable>
+ using if_callable = std::enable_if_t<std::is_invocable_r_v<void, Callable>, bool>;
+
+ template <typename Callable, if_callable<Callable> = true>
+ static QRunnable *create(Callable &&functionToRun);
+ static QRunnable *create(std::nullptr_t) = delete;
bool autoDelete() const { return m_autoDelete; }
void setAutoDelete(bool autoDelete) { m_autoDelete = autoDelete; }
+
+private:
+ static Q_DECL_COLD_FUNCTION QRunnable *warnNullCallable();
+ class QGenericRunnable;
};
+class Q_CORE_EXPORT QRunnable::QGenericRunnable : public QRunnable
+{
+ // Type erasure, to only instantiate a non-virtual class per Callable:
+ class HelperBase
+ {
+ protected:
+ enum class Op {
+ Run,
+ Destroy,
+ };
+ using OpFn = void* (*)(Op, HelperBase *, void*);
+ OpFn fn;
+ protected:
+ constexpr explicit HelperBase(OpFn f) noexcept : fn(f) {}
+ ~HelperBase() = default;
+ public:
+ void run() { fn(Op::Run, this, nullptr); }
+ void destroy() { fn(Op::Destroy, this, nullptr); }
+ };
+
+ template <typename Callable>
+ class Helper : public HelperBase, private QtPrivate::CompactStorage<Callable>
+ {
+ using Storage = QtPrivate::CompactStorage<Callable>;
+ static void *impl(Op op, HelperBase *that, [[maybe_unused]] void *arg)
+ {
+ const auto _this = static_cast<Helper*>(that);
+ switch (op) {
+ case Op::Run: _this->object()(); break;
+ case Op::Destroy: delete _this; break;
+ }
+ return nullptr;
+ }
+ public:
+ template <typename UniCallable>
+ explicit Helper(UniCallable &&functionToRun) noexcept
+ : HelperBase(&impl),
+ Storage{std::forward<UniCallable>(functionToRun)}
+ {
+ }
+ };
+
+ HelperBase *runHelper;
+public:
+ template <typename Callable, if_callable<Callable> = true>
+ explicit QGenericRunnable(Callable &&c)
+ : runHelper(new Helper<std::decay_t<Callable>>(std::forward<Callable>(c)))
+ {
+ }
+ ~QGenericRunnable() override;
+
+ void run() override;
+};
+
+namespace QtPrivate {
+
+template <typename T>
+constexpr inline bool is_function_pointer_v = std::conjunction_v<
+ std::is_pointer<T>,
+ std::is_function<std::remove_pointer_t<T>>
+ >;
+template <typename T>
+constexpr inline bool is_std_function_v = false;
+template <typename T>
+constexpr inline bool is_std_function_v<std::function<T>> = true;
+
+} // namespace QtPrivate
+
+template <typename Callable, QRunnable::if_callable<Callable>>
+QRunnable *QRunnable::create(Callable &&functionToRun)
+{
+ using F = std::decay_t<Callable>;
+ constexpr bool is_std_function = QtPrivate::is_std_function_v<F>;
+ constexpr bool is_function_pointer = QtPrivate::is_function_pointer_v<F>;
+ if constexpr (is_std_function || is_function_pointer) {
+ bool is_null;
+ if constexpr (is_std_function) {
+ is_null = !functionToRun;
+ } else if constexpr (is_function_pointer) {
+ // shut up warnings about functions always having a non-null address:
+ const void *functionPtr = reinterpret_cast<void *>(functionToRun);
+ is_null = !functionPtr;
+ }
+ if (is_null)
+ return warnNullCallable();
+ }
+
+ return new QGenericRunnable(std::forward<Callable>(functionToRun));
+}
+
QT_END_NAMESPACE
#endif
diff --git a/src/corelib/thread/qsemaphore.cpp b/src/corelib/thread/qsemaphore.cpp
index 803aa30bef..72781942ac 100644
--- a/src/corelib/thread/qsemaphore.cpp
+++ b/src/corelib/thread/qsemaphore.cpp
@@ -50,7 +50,7 @@ using namespace QtFutex;
A typical application of semaphores is for controlling access to
a circular buffer shared by a producer thread and a consumer
- thread. The \l{Semaphores Example} shows how
+ thread. The \l{Producer and Consumer using Semaphores} example shows how
to use QSemaphore to solve that problem.
A non-computing example of a semaphore would be dining at a
@@ -63,7 +63,8 @@ using namespace QtFutex;
seated (taking the available seats to 5, making the party of 10
people wait longer).
- \sa QSemaphoreReleaser, QMutex, QWaitCondition, QThread, {Semaphores Example}
+ \sa QSemaphoreReleaser, QMutex, QWaitCondition, QThread,
+ {Producer and Consumer using Semaphores}
*/
/*
@@ -145,10 +146,10 @@ static QBasicAtomicInteger<quint32> *futexHigh32(QBasicAtomicInteger<quintptr> *
}
template <bool IsTimed> bool
-futexSemaphoreTryAcquire_loop(QBasicAtomicInteger<quintptr> &u, quintptr curValue, quintptr nn, int timeout)
+futexSemaphoreTryAcquire_loop(QBasicAtomicInteger<quintptr> &u, quintptr curValue, quintptr nn,
+ QDeadlineTimer timer)
{
- QDeadlineTimer timer(IsTimed ? QDeadlineTimer(timeout) : QDeadlineTimer());
- qint64 remainingTime = timeout * Q_INT64_C(1000) * 1000;
+ using namespace std::chrono;
int n = int(unsigned(nn));
// we're called after one testAndSet, so start by waiting first
@@ -165,8 +166,8 @@ futexSemaphoreTryAcquire_loop(QBasicAtomicInteger<quintptr> &u, quintptr curValu
}
}
- if (IsTimed && remainingTime > 0) {
- bool timedout = !futexWait(*ptr, curValue, remainingTime);
+ if (IsTimed) {
+ bool timedout = !futexWait(*ptr, curValue, timer);
if (timedout)
return false;
} else {
@@ -174,8 +175,6 @@ futexSemaphoreTryAcquire_loop(QBasicAtomicInteger<quintptr> &u, quintptr curValu
}
curValue = u.loadAcquire();
- if (IsTimed)
- remainingTime = timer.remainingTimeNSecs();
// try to acquire
while (futexAvailCounter(curValue) >= n) {
@@ -185,13 +184,18 @@ futexSemaphoreTryAcquire_loop(QBasicAtomicInteger<quintptr> &u, quintptr curValu
}
// not enough tokens available, put us to wait
- if (remainingTime == 0)
+ if (IsTimed && timer.hasExpired())
return false;
}
}
-template <bool IsTimed> bool futexSemaphoreTryAcquire(QBasicAtomicInteger<quintptr> &u, int n, int timeout)
+static constexpr QDeadlineTimer::ForeverConstant Expired =
+ QDeadlineTimer::ForeverConstant(1);
+
+template <typename T> bool
+futexSemaphoreTryAcquire(QBasicAtomicInteger<quintptr> &u, int n, T timeout)
{
+ constexpr bool IsTimed = std::is_same_v<QDeadlineTimer, T>;
// Try to acquire without waiting (we still loop because the testAndSet
// call can fail).
quintptr nn = unsigned(n);
@@ -205,8 +209,13 @@ template <bool IsTimed> bool futexSemaphoreTryAcquire(QBasicAtomicInteger<quintp
if (u.testAndSetOrdered(curValue, newValue, curValue))
return true; // succeeded!
}
- if (timeout == 0)
- return false;
+ if constexpr (IsTimed) {
+ if (timeout.hasExpired())
+ return false;
+ } else {
+ if (timeout == Expired)
+ return false;
+ }
// we need to wait
constexpr quintptr oneWaiter = quintptr(Q_UINT64_C(1) << 32); // zero on 32-bit
@@ -240,14 +249,31 @@ template <bool IsTimed> bool futexSemaphoreTryAcquire(QBasicAtomicInteger<quintp
return false;
}
-class QSemaphorePrivate {
-public:
- explicit QSemaphorePrivate(int n) : avail(n) { }
+namespace QtSemaphorePrivate {
+using namespace QtPrivate;
+struct Layout1
+{
+ alignas(IdealMutexAlignment) std::mutex mutex;
+ qsizetype avail = 0;
+ alignas(IdealMutexAlignment) std::condition_variable cond;
+};
- QtPrivate::mutex mutex;
- QtPrivate::condition_variable cond;
+struct Layout2
+{
+ alignas(IdealMutexAlignment) std::mutex mutex;
+ alignas(IdealMutexAlignment) std::condition_variable cond;
+ qsizetype avail = 0;
+};
- int avail;
+// Choose Layout1 if it is smaller than Layout2. That happens for platforms
+// where sizeof(mutex) is 64.
+using Members = std::conditional_t<sizeof(Layout1) <= sizeof(Layout2), Layout1, Layout2>;
+} // namespace QtSemaphorePrivate
+
+class QSemaphorePrivate : public QtSemaphorePrivate::Members
+{
+public:
+ explicit QSemaphorePrivate(qsizetype n) { avail = n; }
};
/*!
@@ -290,10 +316,15 @@ QSemaphore::~QSemaphore()
*/
void QSemaphore::acquire(int n)
{
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+# warning "Move the Q_ASSERT to inline code, make QSemaphore have wide contract, " \
+ "and mark noexcept where futexes are in use."
+#else
Q_ASSERT_X(n >= 0, "QSemaphore::acquire", "parameter 'n' must be non-negative");
+#endif
if (futexAvailable()) {
- futexSemaphoreTryAcquire<false>(u, n, -1);
+ futexSemaphoreTryAcquire(u, n, QDeadlineTimer::Forever);
return;
}
@@ -363,16 +394,15 @@ void QSemaphore::release(int n)
// its acquisition anyway, so it has to wait;
// 2) it did not see the new counter value, in which case its
// futexWait will fail.
- if (futexHasWaiterCount) {
- futexWakeAll(*futexLow32(&u));
+ futexWakeAll(*futexLow32(&u));
+ if (futexHasWaiterCount)
futexWakeAll(*futexHigh32(&u));
- } else {
- futexWakeAll(u);
- }
}
return;
}
+ // Keep mutex locked until after notify_all() lest another thread acquire()s
+ // the semaphore once d->avail == 0 and then destroys it, leaving `d` dangling.
const auto locker = qt_scoped_lock(d->mutex);
d->avail += n;
d->cond.notify_all();
@@ -409,7 +439,7 @@ bool QSemaphore::tryAcquire(int n)
Q_ASSERT_X(n >= 0, "QSemaphore::tryAcquire", "parameter 'n' must be non-negative");
if (futexAvailable())
- return futexSemaphoreTryAcquire<false>(u, n, 0);
+ return futexSemaphoreTryAcquire(u, n, Expired);
const auto locker = qt_scoped_lock(d->mutex);
if (n > d->avail)
@@ -419,6 +449,8 @@ bool QSemaphore::tryAcquire(int n)
}
/*!
+ \fn QSemaphore::tryAcquire(int n, int timeout)
+
Tries to acquire \c n resources guarded by the semaphore and
returns \c true on success. If available() < \a n, this call will
wait for at most \a timeout milliseconds for resources to become
@@ -434,26 +466,40 @@ bool QSemaphore::tryAcquire(int n)
\sa acquire()
*/
-bool QSemaphore::tryAcquire(int n, int timeout)
+
+/*!
+ \since 6.6
+
+ Tries to acquire \c n resources guarded by the semaphore and returns \c
+ true on success. If available() < \a n, this call will wait until \a timer
+ expires for resources to become available.
+
+ Example:
+
+ \snippet code/src_corelib_thread_qsemaphore.cpp tryAcquire-QDeadlineTimer
+
+ \sa acquire()
+*/
+bool QSemaphore::tryAcquire(int n, QDeadlineTimer timer)
{
- if (timeout < 0) {
+ if (timer.isForever()) {
acquire(n);
return true;
}
- if (timeout == 0)
+ if (timer.hasExpired())
return tryAcquire(n);
Q_ASSERT_X(n >= 0, "QSemaphore::tryAcquire", "parameter 'n' must be non-negative");
if (futexAvailable())
- return futexSemaphoreTryAcquire<true>(u, n, timeout);
+ return futexSemaphoreTryAcquire(u, n, timer);
using namespace std::chrono;
const auto sufficientResourcesAvailable = [this, n] { return d->avail >= n; };
auto locker = qt_unique_lock(d->mutex);
- if (!d->cond.wait_for(locker, milliseconds{timeout}, sufficientResourcesAvailable))
+ if (!d->cond.wait_until(locker, timer.deadline<steady_clock>(), sufficientResourcesAvailable))
return false;
d->avail -= n;
return true;
diff --git a/src/corelib/thread/qsemaphore.h b/src/corelib/thread/qsemaphore.h
index 8823468dbc..dda722a582 100644
--- a/src/corelib/thread/qsemaphore.h
+++ b/src/corelib/thread/qsemaphore.h
@@ -5,7 +5,7 @@
#define QSEMAPHORE_H
#include <QtCore/qglobal.h>
-#include <QtCore/qmutex.h> // for convertToMilliseconds()
+#include <QtCore/qdeadlinetimer.h>
#include <chrono>
@@ -14,7 +14,6 @@ QT_REQUIRE_CONFIG(thread);
QT_BEGIN_NAMESPACE
class QSemaphorePrivate;
-
class Q_CORE_EXPORT QSemaphore
{
public:
@@ -23,10 +22,14 @@ public:
void acquire(int n = 1);
bool tryAcquire(int n = 1);
+ QT_CORE_INLINE_SINCE(6, 6)
bool tryAcquire(int n, int timeout);
+ bool tryAcquire(int n, QDeadlineTimer timeout);
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
template <typename Rep, typename Period>
bool tryAcquire(int n, std::chrono::duration<Rep, Period> timeout)
- { return tryAcquire(n, QtPrivate::convertToMilliseconds(timeout)); }
+ { return tryAcquire(n, QDeadlineTimer(timeout)); }
+#endif
void release(int n = 1);
@@ -53,14 +56,25 @@ private:
};
};
+#if QT_CORE_INLINE_IMPL_SINCE(6, 6)
+bool QSemaphore::tryAcquire(int n, int timeout)
+{
+ return tryAcquire(n, QDeadlineTimer(timeout));
+}
+#endif
+
class QSemaphoreReleaser
{
public:
+ Q_NODISCARD_CTOR
QSemaphoreReleaser() = default;
+ Q_NODISCARD_CTOR
explicit QSemaphoreReleaser(QSemaphore &sem, int n = 1) noexcept
: m_sem(&sem), m_n(n) {}
+ Q_NODISCARD_CTOR
explicit QSemaphoreReleaser(QSemaphore *sem, int n = 1) noexcept
: m_sem(sem), m_n(n) {}
+ Q_NODISCARD_CTOR
QSemaphoreReleaser(QSemaphoreReleaser &&other) noexcept
: m_sem(other.cancel()), m_n(other.m_n) {}
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QSemaphoreReleaser)
diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp
index 9f00bf407d..8d8f353aaa 100644
--- a/src/corelib/thread/qthread.cpp
+++ b/src/corelib/thread/qthread.cpp
@@ -65,9 +65,10 @@ QThreadData::~QThreadData()
// crashing during QCoreApplicationData's global static cleanup we need to
// safeguard the main thread here.. This fix is a bit crude, but it solves
// the problem...
- if (this->thread.loadAcquire() == QCoreApplicationPrivate::theMainThread.loadAcquire()) {
- QCoreApplicationPrivate::theMainThread.storeRelease(nullptr);
- QThreadData::clearCurrentThreadData();
+ if (threadId.loadAcquire() == QCoreApplicationPrivate::theMainThreadId.loadAcquire()) {
+ QCoreApplicationPrivate::theMainThread.storeRelease(nullptr);
+ QCoreApplicationPrivate::theMainThreadId.storeRelaxed(nullptr);
+ QThreadData::clearCurrentThreadData();
}
// ~QThread() sets thread to nullptr, so if it isn't null here, it's
@@ -146,7 +147,24 @@ void QAdoptedThread::run()
// this function should never be called
qFatal("QAdoptedThread::run(): Internal error, this implementation should never be called.");
}
+#endif
+
+QScopedScopeLevelCounter::QScopedScopeLevelCounter(QThreadData *threadData)
+ : threadData(threadData)
+{
+ ++threadData->scopeLevel;
+ qCDebug(lcDeleteLater) << "Increased" << threadData->thread
+ << "scope level to" << threadData->scopeLevel;
+}
+
+QScopedScopeLevelCounter::~QScopedScopeLevelCounter()
+{
+ --threadData->scopeLevel;
+ qCDebug(lcDeleteLater) << "Decreased" << threadData->thread
+ << "scope level to" << threadData->scopeLevel;
+}
+#if QT_CONFIG(thread)
/*
QThreadPrivate
*/
@@ -256,22 +274,21 @@ QThreadPrivate::~QThreadPrivate()
documentation for terminate() and setTerminationEnabled() for
detailed information.
- From Qt 4.8 onwards, it is possible to deallocate objects that
- live in a thread that has just ended, by connecting the
- finished() signal to QObject::deleteLater().
+ You often want to deallocate objects that live in a thread when
+ a thread ends. To do this, connect the finished() signal to
+ QObject::deleteLater().
Use wait() to block the calling thread, until the other thread
has finished execution (or until a specified time has passed).
QThread also provides static, platform independent sleep
functions: sleep(), msleep(), and usleep() allow full second,
- millisecond, and microsecond resolution respectively. These
- functions were made public in Qt 5.0.
+ millisecond, and microsecond resolution respectively.
\note wait() and the sleep() functions should be unnecessary in
general, since Qt is an event-driven framework. Instead of
wait(), consider listening for the finished() signal. Instead of
- the sleep() functions, consider using QTimer.
+ the sleep() functions, consider using QChronoTimer.
The static functions currentThreadId() and currentThread() return
identifiers for the currently executing thread. The former
@@ -284,11 +301,12 @@ QThreadPrivate::~QThreadPrivate()
If you don't call \l{QObject::setObjectName()}{setObjectName()},
the name given to your thread will be the class name of the runtime
type of your thread object (for example, \c "RenderThread" in the case of the
- \l{Mandelbrot Example}, as that is the name of the QThread subclass).
+ \l{Mandelbrot} example, as that is the name of the QThread subclass).
Note that this is currently not available with release builds on Windows.
\sa {Thread Support in Qt}, QThreadStorage, {Synchronizing Threads},
- {Mandelbrot Example}, {Semaphores Example}, {Wait Conditions Example}
+ Mandelbrot, {Producer and Consumer using Semaphores},
+ {Producer and Consumer using Wait Conditions}
*/
/*!
@@ -409,6 +427,23 @@ QThread *QThread::currentThread()
}
/*!
+ \since 6.8
+
+ Returns whether the currently executing thread is the main thread.
+
+ The main thread is the thread in which QCoreApplication was created.
+ This is usually the thread that called the \c{main()} function, but not necessarily so.
+ It is the thread that is processing the GUI events and in which graphical objects
+ (QWindow, QWidget) can be created.
+
+ \sa currentThread(), QCoreApplication::instance()
+*/
+bool QThread::isMainThread()
+{
+ return currentThreadId() == QCoreApplicationPrivate::theMainThreadId.loadRelaxed();
+}
+
+/*!
Constructs a new QThread to manage a new thread. The \a parent
takes ownership of the QThread. The thread does not begin
executing until start() is called.
@@ -896,6 +931,36 @@ int QThread::loopLevel() const
return d->data->eventLoops.size();
}
+/*!
+ \internal
+ Returns the thread handle of this thread.
+ It can be compared with the return value of currentThreadId().
+
+ This is used to implement isCurrentThread, and might be useful
+ for debugging (e.g. by comparing the value in gdb with info threads).
+
+ \note Thread handles of destroyed threads might be reused by the
+ operating system. Storing the return value of this function can
+ therefore give surprising results if it outlives the QThread object
+ (threads claimed to be the same even if they aren't).
+*/
+Qt::HANDLE QThreadPrivate::threadId() const
+{
+ return data->threadId.loadRelaxed();
+}
+
+/*!
+ \since 6.8
+ Returns true if this thread is QThread::currentThread.
+
+ \sa currentThreadId()
+*/
+bool QThread::isCurrentThread() const
+{
+ Q_D(const QThread);
+ return QThread::currentThreadId() == d->threadId();
+}
+
#else // QT_CONFIG(thread)
QThread::QThread(QObject *parent)
@@ -968,6 +1033,11 @@ QThread *QThread::currentThread()
return QThreadData::current()->thread.loadAcquire();
}
+bool QThread::isCurrentThread() const
+{
+ return true;
+}
+
int QThread::idealThreadCount() noexcept
{
return 1;
@@ -999,6 +1069,10 @@ bool QThread::isInterruptionRequested() const
return false;
}
+void QThread::setTerminationEnabled(bool)
+{
+}
+
// No threads: so we can just use static variables
Q_CONSTINIT static QThreadData *data = nullptr;
@@ -1010,8 +1084,10 @@ QThreadData *QThreadData::current(bool createIfNecessary)
data->threadId.storeRelaxed(Qt::HANDLE(data->thread.loadAcquire()));
data->deref();
data->isAdopted = true;
- if (!QCoreApplicationPrivate::theMainThread.loadAcquire())
+ if (!QCoreApplicationPrivate::theMainThreadId.loadAcquire()) {
QCoreApplicationPrivate::theMainThread.storeRelease(data->thread.loadRelaxed());
+ QCoreApplicationPrivate::theMainThreadId.storeRelaxed(data->threadId.loadRelaxed());
+ }
}
return data;
}
@@ -1131,11 +1207,11 @@ bool QThread::event(QEvent *event)
void QThread::requestInterruption()
{
- if (this == QCoreApplicationPrivate::theMainThread.loadAcquire()) {
+ Q_D(QThread);
+ if (d->threadId() == QCoreApplicationPrivate::theMainThreadId.loadAcquire()) {
qWarning("QThread::requestInterruption has no effect on the main thread");
return;
}
- Q_D(QThread);
QMutexLocker locker(&d->mutex);
if (!d->running || d->finished || d->isInFinish)
return;
@@ -1201,7 +1277,6 @@ bool QThread::isInterruptionRequested() const
\sa start()
*/
-#if QT_CONFIG(cxx11_future)
class QThreadCreateThread : public QThread
{
public:
@@ -1230,7 +1305,6 @@ QThread *QThread::createThreadImpl(std::future<void> &&future)
{
return new QThreadCreateThread(std::move(future));
}
-#endif // QT_CONFIG(cxx11_future)
/*!
\class QDaemonThread
@@ -1245,7 +1319,9 @@ QDaemonThread::QDaemonThread(QObject *parent)
{
// QThread::started() is emitted from the thread we start
connect(this, &QThread::started,
- [](){ QThreadData::current()->requiresCoreApplication = false; });
+ this,
+ [](){ QThreadData::current()->requiresCoreApplication = false; },
+ Qt::DirectConnection);
}
QDaemonThread::~QDaemonThread()
diff --git a/src/corelib/thread/qthread.h b/src/corelib/thread/qthread.h
index 6929961150..641c8ef68a 100644
--- a/src/corelib/thread/qthread.h
+++ b/src/corelib/thread/qthread.h
@@ -9,10 +9,8 @@
#include <QtCore/qdeadlinetimer.h>
// For QThread::create
-#if QT_CONFIG(cxx11_future)
-# include <future> // for std::async
-# include <functional> // for std::invoke; no guard needed as it's a C++98 header
-#endif
+#include <future> // for std::async
+#include <functional> // for std::invoke; no guard needed as it's a C++98 header
// internal compiler error with mingw 8.1
#if defined(Q_CC_MSVC) && defined(Q_PROCESSOR_X86)
#include <intrin.h>
@@ -24,6 +22,7 @@ QT_BEGIN_NAMESPACE
class QThreadData;
class QThreadPrivate;
class QAbstractEventDispatcher;
+class QEventLoopLocker;
class Q_CORE_EXPORT QThread : public QObject
{
@@ -31,6 +30,7 @@ class Q_CORE_EXPORT QThread : public QObject
public:
static Qt::HANDLE currentThreadId() noexcept Q_DECL_PURE_FUNCTION;
static QThread *currentThread();
+ static bool isMainThread();
static int idealThreadCount() noexcept;
static void yieldCurrentThread();
@@ -69,10 +69,10 @@ public:
bool event(QEvent *event) override;
int loopLevel() const;
-#if QT_CONFIG(cxx11_future) || defined(Q_QDOC)
+ bool isCurrentThread() const;
+
template <typename Function, typename... Args>
[[nodiscard]] static QThread *create(Function &&f, Args &&... args);
-#endif
public Q_SLOTS:
void start(Priority = InheritPriority);
@@ -109,17 +109,15 @@ protected:
private:
Q_DECLARE_PRIVATE(QThread)
+ friend class QEventLoopLocker;
-#if QT_CONFIG(cxx11_future)
[[nodiscard]] static QThread *createThreadImpl(std::future<void> &&future);
-#endif
static Qt::HANDLE currentThreadIdImpl() noexcept Q_DECL_PURE_FUNCTION;
friend class QCoreApplication;
friend class QThreadData;
};
-#if QT_CONFIG(cxx11_future)
template <typename Function, typename... Args>
QThread *QThread::create(Function &&f, Args &&... args)
{
@@ -134,7 +132,6 @@ QThread *QThread::create(Function &&f, Args &&... args)
std::move(threadFunction),
std::forward<Args>(args)...));
}
-#endif // QT_CONFIG(cxx11_future)
/*
On architectures and platforms we know, interpret the thread control
@@ -157,13 +154,13 @@ inline Qt::HANDLE QThread::currentThreadId() noexcept
static_assert(sizeof(tid) == sizeof(void*));
// See https://akkadia.org/drepper/tls.pdf for x86 ABI
#if defined(Q_PROCESSOR_X86_32) && ((defined(Q_OS_LINUX) && defined(__GLIBC__)) || defined(Q_OS_FREEBSD)) // x86 32-bit always uses GS
- __asm__("movl %%gs:%c1, %0" : "=r" (tid) : "i" (2 * sizeof(void*)) : );
-#elif defined(Q_PROCESSOR_X86_64) && defined(Q_OS_DARWIN64)
+ __asm__("mov %%gs:%c1, %0" : "=r" (tid) : "i" (2 * sizeof(void*)) : );
+#elif defined(Q_PROCESSOR_X86_64) && defined(Q_OS_DARWIN)
// 64bit macOS uses GS, see https://github.com/apple/darwin-xnu/blob/master/libsyscall/os/tsd.h
- __asm__("movq %%gs:0, %0" : "=r" (tid) : : );
+ __asm__("mov %%gs:0, %0" : "=r" (tid) : : );
#elif defined(Q_PROCESSOR_X86_64) && ((defined(Q_OS_LINUX) && defined(__GLIBC__)) || defined(Q_OS_FREEBSD))
// x86_64 Linux, BSD uses FS
- __asm__("movq %%fs:%c1, %0" : "=r" (tid) : "i" (2 * sizeof(void*)) : );
+ __asm__("mov %%fs:%c1, %0" : "=r" (tid) : "i" (2 * sizeof(void*)) : );
#elif defined(Q_PROCESSOR_X86_64) && defined(Q_OS_WIN)
// See https://en.wikipedia.org/wiki/Win32_Thread_Information_Block
// First get the pointer to the TIB
diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h
index 9aa0b3ea22..c39e21ec9a 100644
--- a/src/corelib/thread/qthread_p.h
+++ b/src/corelib/thread/qthread_p.h
@@ -170,7 +170,7 @@ public:
~QDaemonThread();
};
-class QThreadPrivate : public QObjectPrivate
+class Q_AUTOTEST_EXPORT QThreadPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QThread)
@@ -179,6 +179,7 @@ public:
~QThreadPrivate();
void setPriority(QThread::Priority prio);
+ Qt::HANDLE threadId() const;
mutable QMutex mutex;
QAtomicInt quitLockRef;
@@ -334,11 +335,8 @@ class QScopedScopeLevelCounter
{
QThreadData *threadData;
public:
- inline QScopedScopeLevelCounter(QThreadData *threadData)
- : threadData(threadData)
- { ++threadData->scopeLevel; }
- inline ~QScopedScopeLevelCounter()
- { --threadData->scopeLevel; }
+ QScopedScopeLevelCounter(QThreadData *threadData);
+ ~QScopedScopeLevelCounter();
};
// thread wrapper for the main() thread
diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp
index ee66e1c3c3..617a5ebf28 100644
--- a/src/corelib/thread/qthread_unix.cpp
+++ b/src/corelib/thread/qthread_unix.cpp
@@ -20,7 +20,9 @@
# endif
#endif
-#include <private/qeventdispatcher_unix_p.h>
+#if !defined(Q_OS_WASM)
+# include <private/qeventdispatcher_unix_p.h>
+#endif
#include "qthreadstorage.h"
@@ -189,8 +191,10 @@ QThreadData *QThreadData::current(bool createIfNecessary)
data->deref();
data->isAdopted = true;
data->threadId.storeRelaxed(to_HANDLE(pthread_self()));
- if (!QCoreApplicationPrivate::theMainThread.loadAcquire())
+ if (!QCoreApplicationPrivate::theMainThreadId.loadAcquire()) {
QCoreApplicationPrivate::theMainThread.storeRelease(data->thread.loadRelaxed());
+ QCoreApplicationPrivate::theMainThreadId.storeRelaxed(data->threadId.loadRelaxed());
+ }
}
return data;
}
@@ -275,7 +279,7 @@ void terminate_on_exception(T &&t)
void *QThreadPrivate::start(void *arg)
{
-#if !defined(Q_OS_ANDROID)
+#ifdef PTHREAD_CANCEL_DISABLE
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr);
#endif
pthread_cleanup_push(QThreadPrivate::finish, arg);
@@ -317,7 +321,7 @@ void *QThreadPrivate::start(void *arg)
#endif
emit thr->started(QThread::QPrivateSignal());
-#if !defined(Q_OS_ANDROID)
+#ifdef PTHREAD_CANCEL_DISABLE
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, nullptr);
pthread_testcancel();
#endif
@@ -345,6 +349,7 @@ void QThreadPrivate::finish(void *arg)
void *data = &d->data->tls;
locker.unlock();
emit thr->finished(QThread::QPrivateSignal());
+ qCDebug(lcDeleteLater) << "Sending deferred delete events as part of finishing thread" << thr;
QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QThreadStorageData::finish((void **)data);
locker.relock();
@@ -360,7 +365,7 @@ void QThreadPrivate::finish(void *arg)
d->running = false;
d->finished = true;
- d->interruptionRequested = false;
+ d->interruptionRequested.store(false, std::memory_order_relaxed);
d->isInFinish = false;
d->data->threadId.storeRelaxed(nullptr);
@@ -502,7 +507,7 @@ static void qt_nanosleep(timespec amount)
// nanosleep is POSIX.1-1993
int r;
- EINTR_LOOP(r, nanosleep(&amount, &amount));
+ QT_EINTR_LOOP(r, nanosleep(&amount, &amount));
}
void QThread::sleep(unsigned long secs)
@@ -637,7 +642,7 @@ void QThread::start(Priority priority)
d->finished = false;
d->returnCode = 0;
d->exited = false;
- d->interruptionRequested = false;
+ d->interruptionRequested.store(false, std::memory_order_relaxed);
pthread_attr_t attr;
pthread_attr_init(&attr);
diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp
index b4a10d2426..74bc1d2650 100644
--- a/src/corelib/thread/qthread_win.cpp
+++ b/src/corelib/thread/qthread_win.cpp
@@ -19,6 +19,17 @@
#endif // _MT
#include <process.h>
+extern "C" {
+// MinGW is missing the declaration of SetThreadDescription:
+WINBASEAPI
+HRESULT
+WINAPI
+SetThreadDescription(
+ _In_ HANDLE hThread,
+ _In_ PCWSTR lpThreadDescription
+ );
+}
+
QT_BEGIN_NAMESPACE
#if QT_CONFIG(thread)
@@ -76,8 +87,9 @@ QThreadData *QThreadData::current(bool createIfNecessary)
threadData->isAdopted = true;
threadData->threadId.storeRelaxed(reinterpret_cast<Qt::HANDLE>(quintptr(GetCurrentThreadId())));
- if (!QCoreApplicationPrivate::theMainThread) {
- QCoreApplicationPrivate::theMainThread = threadData->thread.loadRelaxed();
+ if (!QCoreApplicationPrivate::theMainThreadId) {
+ QCoreApplicationPrivate::theMainThread.storeRelease(threadData->thread.loadRelaxed());
+ QCoreApplicationPrivate::theMainThreadId.storeRelaxed(threadData->threadId.loadRelaxed());
} else {
HANDLE realHandle = INVALID_HANDLE_VALUE;
DuplicateHandle(GetCurrentProcess(),
@@ -212,39 +224,6 @@ DWORD WINAPI qt_adopted_thread_watcher_function(LPVOID)
return 0;
}
-#if !defined(QT_NO_DEBUG) && defined(Q_CC_MSVC)
-
-#ifndef Q_OS_WIN64
-# define ULONG_PTR DWORD
-#endif
-
-typedef struct tagTHREADNAME_INFO
-{
- DWORD dwType; // must be 0x1000
- LPCSTR szName; // pointer to name (in user addr space)
- HANDLE dwThreadID; // thread ID (-1=caller thread)
- DWORD dwFlags; // reserved for future use, must be zero
-} THREADNAME_INFO;
-
-void qt_set_thread_name(HANDLE threadId, LPCSTR threadName)
-{
- THREADNAME_INFO info;
- info.dwType = 0x1000;
- info.szName = threadName;
- info.dwThreadID = threadId;
- info.dwFlags = 0;
-
- __try
- {
- RaiseException(0x406D1388, 0, sizeof(info)/sizeof(DWORD),
- reinterpret_cast<const ULONG_PTR*>(&info));
- }
- __except (EXCEPTION_CONTINUE_EXECUTION)
- {
- }
-}
-#endif // !QT_NO_DEBUG && Q_CC_MSVC
-
/**************************************************************************
** QThreadPrivate
*************************************************************************/
@@ -278,12 +257,11 @@ unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(voi
data->ensureEventDispatcher();
data->eventDispatcher.loadRelaxed()->startingUp();
-#if !defined(QT_NO_DEBUG) && defined(Q_CC_MSVC)
// sets the name of the current thread.
- qt_set_thread_name(HANDLE(-1), thr->d_func()->objectName.isEmpty()
- ? thr->metaObject()->className()
- : std::exchange(thr->d_func()->objectName, {}).toLocal8Bit().constData());
-#endif
+ QString threadName = std::exchange(thr->d_func()->objectName, {});
+ if (Q_LIKELY(threadName.isEmpty()))
+ threadName = QString::fromUtf8(thr->metaObject()->className());
+ SetThreadDescription(GetCurrentThread(), reinterpret_cast<const wchar_t *>(threadName.utf16()));
emit thr->started(QThread::QPrivateSignal());
QThread::setTerminationEnabled(true);
@@ -316,6 +294,7 @@ void QThreadPrivate::finish(void *arg, bool lockAnyway) noexcept
if (lockAnyway)
locker.unlock();
emit thr->finished(QThread::QPrivateSignal());
+ qCDebug(lcDeleteLater) << "Sending deferred delete events as part of finishing thread" << thr;
QCoreApplicationPrivate::sendPostedEvents(nullptr, QEvent::DeferredDelete, d->data);
QThreadStorageData::finish(tls_data);
if (lockAnyway)
@@ -335,7 +314,7 @@ void QThreadPrivate::finish(void *arg, bool lockAnyway) noexcept
d->running = false;
d->finished = true;
d->isInFinish = false;
- d->interruptionRequested = false;
+ d->interruptionRequested.store(false, std::memory_order_relaxed);
if (!d->waiters) {
CloseHandle(d->handle);
@@ -412,7 +391,7 @@ void QThread::start(Priority priority)
d->finished = false;
d->exited = false;
d->returnCode = 0;
- d->interruptionRequested = false;
+ d->interruptionRequested.store(false, std::memory_order_relaxed);
/*
NOTE: we create the thread in the suspended state, set the
diff --git a/src/corelib/thread/qthreadpool.cpp b/src/corelib/thread/qthreadpool.cpp
index 51783321b9..ae584656fe 100644
--- a/src/corelib/thread/qthreadpool.cpp
+++ b/src/corelib/thread/qthreadpool.cpp
@@ -6,6 +6,8 @@
#include "qdeadlinetimer.h"
#include "qcoreapplication.h"
+#include <QtCore/qpointer.h>
+
#include <algorithm>
#include <memory>
@@ -87,7 +89,7 @@ void QThreadPoolThread::run()
if (manager->queue.isEmpty())
break;
- QueuePage *page = manager->queue.first();
+ QueuePage *page = manager->queue.constFirst();
r = page->pop();
if (page->isFinished()) {
@@ -210,7 +212,7 @@ void QThreadPoolPrivate::tryToStartMoreThreads()
{
// try to push tasks on the queue to any available threads
while (!queue.isEmpty()) {
- QueuePage *page = queue.first();
+ QueuePage *page = queue.constFirst();
if (!tryStart(page->first()))
break;
@@ -517,20 +519,21 @@ void QThreadPool::start(QRunnable *runnable, int priority)
}
/*!
+ \fn template<typename Callable, QRunnable::if_callable<Callable>> void QThreadPool::start(Callable &&callableToRun, int priority)
\overload
\since 5.15
- Reserves a thread and uses it to run \a functionToRun, unless this thread will
+ Reserves a thread and uses it to run \a callableToRun, unless this thread will
make the current thread count exceed maxThreadCount(). In that case,
- \a functionToRun is added to a run queue instead. The \a priority argument can
+ \a callableToRun is added to a run queue instead. The \a priority argument can
be used to control the run queue's order of execution.
+
+ \note This function participates in overload resolution only if \c Callable
+ is a function or function object which can be called with zero arguments.
+
+ \note In Qt version prior to 6.6, this function took std::function<void()>,
+ and therefore couldn't handle move-only callables.
*/
-void QThreadPool::start(std::function<void()> functionToRun, int priority)
-{
- if (!functionToRun)
- return;
- start(QRunnable::create(std::move(functionToRun)), priority);
-}
/*!
Attempts to reserve a thread to run \a runnable.
@@ -562,30 +565,21 @@ bool QThreadPool::tryStart(QRunnable *runnable)
}
/*!
+ \fn template<typename Callable, QRunnable::if_callable<Callable>> bool QThreadPool::tryStart(Callable &&callableToRun)
\overload
\since 5.15
- Attempts to reserve a thread to run \a functionToRun.
+ Attempts to reserve a thread to run \a callableToRun.
If no threads are available at the time of calling, then this function
- does nothing and returns \c false. Otherwise, \a functionToRun is run immediately
+ does nothing and returns \c false. Otherwise, \a callableToRun is run immediately
using one available thread and this function returns \c true.
-*/
-bool QThreadPool::tryStart(std::function<void()> functionToRun)
-{
- if (!functionToRun)
- return false;
- Q_D(QThreadPool);
- QMutexLocker locker(&d->mutex);
- if (!d->allThreads.isEmpty() && d->areAllThreadsActive())
- return false;
+ \note This function participates in overload resolution only if \c Callable
+ is a function or function object which can be called with zero arguments.
- QRunnable *runnable = QRunnable::create(std::move(functionToRun));
- if (d->tryStart(runnable))
- return true;
- delete runnable;
- return false;
-}
+ \note In Qt version prior to 6.6, this function took std::function<void()>,
+ and therefore couldn't handle move-only callables.
+*/
/*! \property QThreadPool::expiryTimeout
\brief the thread expiry timeout value in milliseconds.
@@ -799,19 +793,19 @@ void QThreadPool::startOnReservedThread(QRunnable *runnable)
}
/*!
+ \fn template<typename Callable, QRunnable::if_callable<Callable>> void QThreadPool::startOnReservedThread(Callable &&callableToRun)
\overload
\since 6.3
Releases a thread previously reserved with reserveThread() and uses it
- to run \a functionToRun.
-*/
-void QThreadPool::startOnReservedThread(std::function<void()> functionToRun)
-{
- if (!functionToRun)
- return releaseThread();
+ to run \a callableToRun.
- startOnReservedThread(QRunnable::create(std::move(functionToRun)));
-}
+ \note This function participates in overload resolution only if \c Callable
+ is a function or function object which can be called with zero arguments.
+
+ \note In Qt version prior to 6.6, this function took std::function<void()>,
+ and therefore couldn't handle move-only callables.
+*/
/*!
Waits up to \a msecs milliseconds for all threads to exit and removes all
diff --git a/src/corelib/thread/qthreadpool.h b/src/corelib/thread/qthreadpool.h
index e6d0326c4c..a097ace14b 100644
--- a/src/corelib/thread/qthreadpool.h
+++ b/src/corelib/thread/qthreadpool.h
@@ -36,11 +36,22 @@ public:
void start(QRunnable *runnable, int priority = 0);
bool tryStart(QRunnable *runnable);
+#if QT_CORE_REMOVED_SINCE(6, 6)
void start(std::function<void()> functionToRun, int priority = 0);
bool tryStart(std::function<void()> functionToRun);
+#endif
void startOnReservedThread(QRunnable *runnable);
+#if QT_CORE_REMOVED_SINCE(6, 6)
void startOnReservedThread(std::function<void()> functionToRun);
+#endif
+
+ template <typename Callable, QRunnable::if_callable<Callable> = true>
+ void start(Callable &&functionToRun, int priority = 0);
+ template <typename Callable, QRunnable::if_callable<Callable> = true>
+ bool tryStart(Callable &&functionToRun);
+ template <typename Callable, QRunnable::if_callable<Callable> = true>
+ void startOnReservedThread(Callable &&functionToRun);
int expiryTimeout() const;
void setExpiryTimeout(int expiryTimeout);
@@ -68,6 +79,28 @@ public:
[[nodiscard]] bool tryTake(QRunnable *runnable);
};
+template <typename Callable, QRunnable::if_callable<Callable>>
+void QThreadPool::start(Callable &&functionToRun, int priority)
+{
+ start(QRunnable::create(std::forward<Callable>(functionToRun)), priority);
+}
+
+template <typename Callable, QRunnable::if_callable<Callable>>
+bool QThreadPool::tryStart(Callable &&functionToRun)
+{
+ QRunnable *runnable = QRunnable::create(std::forward<Callable>(functionToRun));
+ if (tryStart(runnable))
+ return true;
+ delete runnable;
+ return false;
+}
+
+template <typename Callable, QRunnable::if_callable<Callable>>
+void QThreadPool::startOnReservedThread(Callable &&functionToRun)
+{
+ startOnReservedThread(QRunnable::create(std::forward<Callable>(functionToRun)));
+}
+
QT_END_NAMESPACE
#endif
diff --git a/src/corelib/thread/qwaitcondition.qdoc b/src/corelib/thread/qwaitcondition.qdoc
index 435771e1d8..8466eb13d2 100644
--- a/src/corelib/thread/qwaitcondition.qdoc
+++ b/src/corelib/thread/qwaitcondition.qdoc
@@ -51,12 +51,12 @@
simultaneously are unpredictable.
Wait conditions are a powerful thread synchronization primitive.
- The \l{Wait Conditions Example} example shows how
- to use QWaitCondition as an alternative to QSemaphore for
- controlling access to a circular buffer shared by a producer
+ The \l{Producer and Consumer using Wait Conditions} example
+ shows how to use QWaitCondition as an alternative to QSemaphore
+ for controlling access to a circular buffer shared by a producer
thread and a consumer thread.
- \sa QMutex, QSemaphore, QThread, {Wait Conditions Example}
+ \sa QMutex, QSemaphore, QThread, {Producer and Consumer using Wait Conditions}
*/
/*!
diff --git a/src/corelib/thread/qwaitcondition_p.h b/src/corelib/thread/qwaitcondition_p.h
index cfb36ca30b..14833d56ef 100644
--- a/src/corelib/thread/qwaitcondition_p.h
+++ b/src/corelib/thread/qwaitcondition_p.h
@@ -19,109 +19,19 @@
#include <QtCore/QDeadlineTimer>
#include <QtCore/private/qglobal_p.h>
-// This header always defines a class called "mutex" and one called
-// "condition_variable", so those mustn't be used to mark ELF symbol
-// visibility. Don't add more classes to this header!
-// ELFVERSION:stop
-
#include <condition_variable>
#include <mutex>
-// There's no feature macro for C++11 std::mutex, so we use the C++14 one
-// for shared_mutex to detect it.
-// Needed for: MinGW without gthreads, Integrity
-#if __has_include(<shared_mutex>)
-# include <shared_mutex>
-#endif
-
QT_BEGIN_NAMESPACE
namespace QtPrivate {
-
-#if !defined(__cpp_lib_shared_timed_mutex)
-
-enum class cv_status { no_timeout, timeout };
-class condition_variable;
-
-class mutex : private QMutex
-{
- friend class QtPrivate::condition_variable;
-
-public:
- // all special member functions are ok!
- // do not expose the (QMutex::Recursive) ctor
- // don't use 'using QMutex::lock;' etc as those have the wrong noexcept
-
- void lock() { return QMutex::lock(); }
- void unlock() { return QMutex::unlock(); }
- bool try_lock() { return QMutex::tryLock(); }
-};
-
-class condition_variable : private QWaitCondition
-{
-public:
- // all special member functions are ok!
-
- void notify_one() { QWaitCondition::wakeOne(); }
- void notify_all() { QWaitCondition::wakeAll(); }
-
- void wait(std::unique_lock<QtPrivate::mutex> &lock) { QWaitCondition::wait(lock.mutex()); }
- template <class Predicate>
- void wait(std::unique_lock<QtPrivate::mutex> &lock, Predicate p)
- {
- while (!p())
- wait(lock);
- }
-
- template <typename Rep, typename Period>
- cv_status wait_for(std::unique_lock<QtPrivate::mutex> &lock,
- const std::chrono::duration<Rep, Period> &d)
- {
- return QWaitCondition::wait(lock.mutex(), QDeadlineTimer{d})
- ? cv_status::no_timeout
- : cv_status::timeout;
- }
- template <typename Rep, typename Period, typename Predicate>
- bool wait_for(std::unique_lock<QtPrivate::mutex> &lock,
- const std::chrono::duration<Rep, Period> &d, Predicate p)
- {
- const auto timer = QDeadlineTimer{d};
- while (!p()) {
- if (!QWaitCondition::wait(lock.mutex(), timer))
- return p();
- }
- return true;
- }
-
- template <typename Clock, typename Duration>
- cv_status wait_until(std::unique_lock<QtPrivate::mutex> &lock,
- const std::chrono::time_point<Clock, Duration> &t)
- {
- return QWaitCondition::wait(lock.mutex(), QDeadlineTimer{t})
- ? cv_status::no_timeout
- : cv_status::timeout;
- }
-
- template <typename Clock, typename Duration, typename Predicate>
- bool wait_until(std::unique_lock<QtPrivate::mutex> &lock,
- const std::chrono::time_point<Clock, Duration> &t, Predicate p)
- {
- const auto timer = QDeadlineTimer{t};
- while (!p()) {
- if (!QWaitCondition::wait(lock.mutex(), timer))
- return p();
- }
- return true;
- }
-
-};
-
-#else // C++11 threads
-
-using mutex = std::mutex;
-using condition_variable = std::condition_variable;
-
-#endif // C++11 threads
+// Ideal alignment for mutex and condition_variable: it's the hardware
+// interference size (size of a cache line) if the types are likely to contain
+// the actual data structures, otherwise just that of a pointer.
+static constexpr quintptr IdealMutexAlignment =
+ sizeof(std::mutex) > sizeof(void *) &&
+ sizeof(std::condition_variable) > sizeof(void *) ?
+ 64 : alignof(void*);
} // namespace QtPrivate
diff --git a/src/corelib/thread/qwaitcondition_unix.cpp b/src/corelib/thread/qwaitcondition_unix.cpp
index 84534e9de1..d841183f09 100644
--- a/src/corelib/thread/qwaitcondition_unix.cpp
+++ b/src/corelib/thread/qwaitcondition_unix.cpp
@@ -2,18 +2,16 @@
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qplatformdefs.h"
#include "qwaitcondition.h"
+
+#include "qatomic.h"
+#include "qdeadlinetimer.h"
#include "qmutex.h"
+#include "qplatformdefs.h"
#include "qreadwritelock.h"
-#include "qatomic.h"
#include "qstring.h"
-#include "qdeadlinetimer.h"
-#include "private/qdeadlinetimer_p.h"
-#include "qelapsedtimer.h"
-#include "private/qcore_unix_p.h"
-#include "qmutex_p.h"
+#include "private/qcore_unix_p.h"
#include "qreadwritelock_p.h"
#include <errno.h>
@@ -22,60 +20,61 @@
QT_BEGIN_NAMESPACE
-#ifdef Q_OS_ANDROID
-// pthread_condattr_setclock is available only since Android 5.0. On older versions, there's
-// a private function for relative waits (hidden in 5.0).
-// Use weakref so we can determine at runtime whether each of them is present.
-static int local_condattr_setclock(pthread_condattr_t*, clockid_t)
-__attribute__((weakref("pthread_condattr_setclock")));
-
-static int local_cond_timedwait_relative(pthread_cond_t*, pthread_mutex_t *, const timespec *)
-__attribute__((weakref("__pthread_cond_timedwait_relative")));
+static constexpr clockid_t SteadyClockClockId =
+#if !defined(CLOCK_MONOTONIC)
+ // we don't know how to set the monotonic clock
+ CLOCK_REALTIME
+#elif defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK)
+ // libc++ falling back to system_clock
+ CLOCK_REALTIME
+#elif defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_CLOCK_MONOTONIC)
+ // libstdc++ falling back to system_clock
+ CLOCK_REALTIME
+#elif defined(Q_OS_DARWIN)
+ // Darwin lacks pthread_condattr_setclock()
+ CLOCK_REALTIME
+#elif defined(Q_OS_QNX)
+ // unknown why
+ CLOCK_REALTIME
+#elif defined(__GLIBCXX__) || defined(_LIBCPP_VERSION)
+ // both libstdc++ and libc++ do use CLOCK_MONOTONIC
+ CLOCK_MONOTONIC
+#else
+# warning "Unknown C++ Standard Library implementation - code may be sub-optimal"
+ CLOCK_REALTIME
#endif
+ ;
-static void report_error(int code, const char *where, const char *what)
+static void qt_report_pthread_error(int code, const char *where, const char *what)
{
if (code != 0)
qErrnoWarning(code, "%s: %s failure", where, what);
}
-void qt_initialize_pthread_cond(pthread_cond_t *cond, const char *where)
+static void qt_initialize_pthread_cond(pthread_cond_t *cond, const char *where)
{
+ pthread_condattr_t *attrp = nullptr;
+
+#if defined(CLOCK_MONOTONIC) && !defined(Q_OS_DARWIN)
pthread_condattr_t condattr;
+ attrp = &condattr;
pthread_condattr_init(&condattr);
-#if (_POSIX_MONOTONIC_CLOCK-0 >= 0)
-#if defined(Q_OS_ANDROID)
- if (local_condattr_setclock && QElapsedTimer::clockType() == QElapsedTimer::MonotonicClock)
- local_condattr_setclock(&condattr, CLOCK_MONOTONIC);
-#elif !defined(Q_OS_DARWIN)
- if (QElapsedTimer::clockType() == QElapsedTimer::MonotonicClock)
- pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
-#endif
+ auto destroy = qScopeGuard([&] { pthread_condattr_destroy(&condattr); });
+ if (SteadyClockClockId != CLOCK_REALTIME)
+ pthread_condattr_setclock(&condattr, SteadyClockClockId);
#endif
- report_error(pthread_cond_init(cond, &condattr), where, "cv init");
- pthread_condattr_destroy(&condattr);
+
+ qt_report_pthread_error(pthread_cond_init(cond, attrp), where, "cv init");
}
-void qt_abstime_for_timeout(timespec *ts, QDeadlineTimer deadline)
+static void qt_abstime_for_timeout(timespec *ts, QDeadlineTimer deadline)
{
-#ifdef Q_OS_DARWIN
- // on Mac, qt_gettime() (on qelapsedtimer_mac.cpp) returns ticks related to the Mach absolute time
- // that doesn't work with pthread
- // Mac also doesn't have clock_gettime
- struct timeval tv;
- qint64 nsec = deadline.remainingTimeNSecs();
- gettimeofday(&tv, 0);
- ts->tv_sec = tv.tv_sec + nsec / (1000 * 1000 * 1000);
- ts->tv_nsec = tv.tv_usec * 1000 + nsec % (1000 * 1000 * 1000);
-
- normalizedTimespec(*ts);
-#else
- // depends on QDeadlineTimer's internals!!
- static_assert(QDeadlineTimerNanosecondsInT2);
- ts->tv_sec = deadline._q_data().first;
- ts->tv_nsec = deadline._q_data().second;
-#endif
+ using namespace std::chrono;
+ using Clock =
+ std::conditional_t<SteadyClockClockId == CLOCK_REALTIME, system_clock, steady_clock>;
+ auto timePoint = deadline.deadline<Clock>();
+ *ts = durationToTimespec(timePoint.time_since_epoch());
}
class QWaitConditionPrivate
@@ -89,14 +88,6 @@ public:
int wait_relative(QDeadlineTimer deadline)
{
timespec ti;
-#ifdef Q_OS_ANDROID
- if (!local_condattr_setclock && local_cond_timedwait_relative) {
- qint64 nsec = deadline.remainingTimeNSecs();
- ti.tv_sec = nsec / (1000 * 1000 * 1000);
- ti.tv_nsec = nsec - ti.tv_sec * 1000 * 1000 * 1000;
- return local_cond_timedwait_relative(&cond, &mutex, &ti);
- }
-#endif
qt_abstime_for_timeout(&ti, deadline);
return pthread_cond_timedwait(&cond, &mutex, &ti);
}
@@ -123,10 +114,11 @@ public:
Q_ASSERT_X(wakeups > 0, "QWaitCondition::wait", "internal error (wakeups)");
--wakeups;
}
- report_error(pthread_mutex_unlock(&mutex), "QWaitCondition::wait()", "mutex unlock");
+ qt_report_pthread_error(pthread_mutex_unlock(&mutex), "QWaitCondition::wait()",
+ "mutex unlock");
if (code && code != ETIMEDOUT)
- report_error(code, "QWaitCondition::wait()", "cv wait");
+ qt_report_pthread_error(code, "QWaitCondition::wait()", "cv wait");
return (code == 0);
}
@@ -135,32 +127,38 @@ public:
QWaitCondition::QWaitCondition()
{
d = new QWaitConditionPrivate;
- report_error(pthread_mutex_init(&d->mutex, nullptr), "QWaitCondition", "mutex init");
+ qt_report_pthread_error(pthread_mutex_init(&d->mutex, nullptr), "QWaitCondition", "mutex init");
qt_initialize_pthread_cond(&d->cond, "QWaitCondition");
d->waiters = d->wakeups = 0;
}
QWaitCondition::~QWaitCondition()
{
- report_error(pthread_cond_destroy(&d->cond), "QWaitCondition", "cv destroy");
- report_error(pthread_mutex_destroy(&d->mutex), "QWaitCondition", "mutex destroy");
+ qt_report_pthread_error(pthread_cond_destroy(&d->cond), "QWaitCondition", "cv destroy");
+ qt_report_pthread_error(pthread_mutex_destroy(&d->mutex), "QWaitCondition", "mutex destroy");
delete d;
}
void QWaitCondition::wakeOne()
{
- report_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wakeOne()", "mutex lock");
+ qt_report_pthread_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wakeOne()",
+ "mutex lock");
d->wakeups = qMin(d->wakeups + 1, d->waiters);
- report_error(pthread_cond_signal(&d->cond), "QWaitCondition::wakeOne()", "cv signal");
- report_error(pthread_mutex_unlock(&d->mutex), "QWaitCondition::wakeOne()", "mutex unlock");
+ qt_report_pthread_error(pthread_cond_signal(&d->cond), "QWaitCondition::wakeOne()",
+ "cv signal");
+ qt_report_pthread_error(pthread_mutex_unlock(&d->mutex), "QWaitCondition::wakeOne()",
+ "mutex unlock");
}
void QWaitCondition::wakeAll()
{
- report_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wakeAll()", "mutex lock");
+ qt_report_pthread_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wakeAll()",
+ "mutex lock");
d->wakeups = d->waiters;
- report_error(pthread_cond_broadcast(&d->cond), "QWaitCondition::wakeAll()", "cv broadcast");
- report_error(pthread_mutex_unlock(&d->mutex), "QWaitCondition::wakeAll()", "mutex unlock");
+ qt_report_pthread_error(pthread_cond_broadcast(&d->cond), "QWaitCondition::wakeAll()",
+ "cv broadcast");
+ qt_report_pthread_error(pthread_mutex_unlock(&d->mutex), "QWaitCondition::wakeAll()",
+ "mutex unlock");
}
bool QWaitCondition::wait(QMutex *mutex, unsigned long time)
@@ -175,7 +173,7 @@ bool QWaitCondition::wait(QMutex *mutex, QDeadlineTimer deadline)
if (!mutex)
return false;
- report_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wait()", "mutex lock");
+ qt_report_pthread_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wait()", "mutex lock");
++d->waiters;
mutex->unlock();
@@ -195,24 +193,26 @@ bool QWaitCondition::wait(QReadWriteLock *readWriteLock, unsigned long time)
bool QWaitCondition::wait(QReadWriteLock *readWriteLock, QDeadlineTimer deadline)
{
+ using namespace QReadWriteLockStates;
+
if (!readWriteLock)
return false;
- auto previousState = readWriteLock->stateForWaitCondition();
- if (previousState == QReadWriteLock::Unlocked)
+ auto previousState = QReadWriteLockPrivate::stateForWaitCondition(readWriteLock);
+ if (previousState == Unlocked)
return false;
- if (previousState == QReadWriteLock::RecursivelyLocked) {
+ if (previousState == RecursivelyLocked) {
qWarning("QWaitCondition: cannot wait on QReadWriteLocks with recursive lockForWrite()");
return false;
}
- report_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wait()", "mutex lock");
+ qt_report_pthread_error(pthread_mutex_lock(&d->mutex), "QWaitCondition::wait()", "mutex lock");
++d->waiters;
readWriteLock->unlock();
bool returnValue = d->wait(deadline);
- if (previousState == QReadWriteLock::LockedForWrite)
+ if (previousState == LockedForWrite)
readWriteLock->lockForWrite();
else
readWriteLock->lockForRead();
diff --git a/src/corelib/thread/qwaitcondition_win.cpp b/src/corelib/thread/qwaitcondition_win.cpp
index 2152ae551f..ba53309e1b 100644
--- a/src/corelib/thread/qwaitcondition_win.cpp
+++ b/src/corelib/thread/qwaitcondition_win.cpp
@@ -43,7 +43,7 @@ public:
EventQueue freeQueue;
QWaitConditionEvent *pre();
- bool wait(QWaitConditionEvent *wce, unsigned long time);
+ bool wait(QWaitConditionEvent *wce, QDeadlineTimer deadline);
void post(QWaitConditionEvent *wce, bool ret);
};
@@ -68,19 +68,25 @@ QWaitConditionEvent *QWaitConditionPrivate::pre()
return wce;
}
-bool QWaitConditionPrivate::wait(QWaitConditionEvent *wce, unsigned long time)
+bool QWaitConditionPrivate::wait(QWaitConditionEvent *wce, QDeadlineTimer deadline)
{
// wait for the event
- bool ret = false;
- switch (WaitForSingleObjectEx(wce->event, time, FALSE)) {
- default:
- break;
-
- case WAIT_OBJECT_0:
- ret = true;
- break;
+ while (true) {
+ const DWORD timeout = deadline.isForever()
+ ? INFINITE
+ : DWORD(std::min(deadline.remainingTime(), qint64(INFINITE - 1)));
+
+ switch (WaitForSingleObjectEx(wce->event, timeout, FALSE)) {
+ case WAIT_OBJECT_0:
+ return true;
+ case WAIT_TIMEOUT:
+ if (deadline.hasExpired())
+ return false;
+ break;
+ default:
+ return false;
+ }
}
- return ret;
}
void QWaitConditionPrivate::post(QWaitConditionEvent *wce, bool ret)
@@ -124,13 +130,20 @@ QWaitCondition::~QWaitCondition()
bool QWaitCondition::wait(QMutex *mutex, unsigned long time)
{
+ if (time == std::numeric_limits<unsigned long>::max())
+ return wait(mutex, QDeadlineTimer(QDeadlineTimer::Forever));
+ return wait(mutex, QDeadlineTimer(time));
+}
+
+bool QWaitCondition::wait(QMutex *mutex, QDeadlineTimer deadline)
+{
if (!mutex)
return false;
QWaitConditionEvent *wce = d->pre();
mutex->unlock();
- bool returnValue = d->wait(wce, time);
+ bool returnValue = d->wait(wce, deadline);
mutex->lock();
d->post(wce, returnValue);
@@ -138,19 +151,23 @@ bool QWaitCondition::wait(QMutex *mutex, unsigned long time)
return returnValue;
}
-bool QWaitCondition::wait(QMutex *mutex, QDeadlineTimer deadline)
+bool QWaitCondition::wait(QReadWriteLock *readWriteLock, unsigned long time)
{
- return wait(mutex, deadline.remainingTime());
+ if (time == std::numeric_limits<unsigned long>::max())
+ return wait(readWriteLock, QDeadlineTimer(QDeadlineTimer::Forever));
+ return wait(readWriteLock, QDeadlineTimer(time));
}
-bool QWaitCondition::wait(QReadWriteLock *readWriteLock, unsigned long time)
+bool QWaitCondition::wait(QReadWriteLock *readWriteLock, QDeadlineTimer deadline)
{
+ using namespace QReadWriteLockStates;
+
if (!readWriteLock)
return false;
- auto previousState = readWriteLock->stateForWaitCondition();
- if (previousState == QReadWriteLock::Unlocked)
+ auto previousState = QReadWriteLockPrivate::stateForWaitCondition(readWriteLock);
+ if (previousState == Unlocked)
return false;
- if (previousState == QReadWriteLock::RecursivelyLocked) {
+ if (previousState == RecursivelyLocked) {
qWarning("QWaitCondition: cannot wait on QReadWriteLocks with recursive lockForWrite()");
return false;
}
@@ -158,9 +175,9 @@ bool QWaitCondition::wait(QReadWriteLock *readWriteLock, unsigned long time)
QWaitConditionEvent *wce = d->pre();
readWriteLock->unlock();
- bool returnValue = d->wait(wce, time);
+ bool returnValue = d->wait(wce, deadline);
- if (previousState == QReadWriteLock::LockedForWrite)
+ if (previousState == LockedForWrite)
readWriteLock->lockForWrite();
else
readWriteLock->lockForRead();
@@ -169,11 +186,6 @@ bool QWaitCondition::wait(QReadWriteLock *readWriteLock, unsigned long time)
return returnValue;
}
-bool QWaitCondition::wait(QReadWriteLock *readWriteLock, QDeadlineTimer deadline)
-{
- return wait(readWriteLock, deadline.remainingTime());
-}
-
void QWaitCondition::wakeOne()
{
// wake up the first waiting thread in the queue
diff --git a/src/corelib/thread/qyieldcpu.h b/src/corelib/thread/qyieldcpu.h
new file mode 100644
index 0000000000..d5da58deeb
--- /dev/null
+++ b/src/corelib/thread/qyieldcpu.h
@@ -0,0 +1,64 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2023 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QYIELDCPU_H
+#define QYIELDCPU_H
+
+#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qprocessordetection.h>
+#include <QtCore/qtconfigmacros.h>
+
+#ifdef Q_CC_MSVC_ONLY
+// MSVC defines _YIELD_PROCESSOR() in <xatomic.h>, but as that is a private
+// header, we include the public ones
+# ifdef __cplusplus
+# include <atomic>
+extern "C"
+# endif
+void _mm_pause(void); // the compiler recognizes as intrinsic
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_CC_GNU
+__attribute__((artificial))
+#endif
+Q_ALWAYS_INLINE void qYieldCpu(void) Q_DECL_NOEXCEPT;
+
+void qYieldCpu(void)
+#ifdef __cplusplus
+ noexcept
+#endif
+{
+#if __has_builtin(__yield)
+ __yield(); // Generic
+#elif defined(_YIELD_PROCESSOR) && defined(Q_CC_MSVC)
+ _YIELD_PROCESSOR(); // Generic; MSVC's <atomic>
+
+#elif __has_builtin(__builtin_ia32_pause)
+ __builtin_ia32_pause();
+#elif defined(Q_PROCESSOR_X86) && defined(Q_CC_GNU)
+ // GCC < 10 didn't have __has_builtin()
+ __builtin_ia32_pause();
+#elif defined(Q_PROCESSOR_X86) && defined(Q_CC_MSVC)
+ _mm_pause();
+#elif defined(Q_PROCESSOR_X86)
+ asm("pause"); // hopefully asm() works in this compiler
+
+#elif __has_builtin(__builtin_arm_yield)
+ __builtin_arm_yield();
+#elif defined(Q_PROCESSOR_ARM) && Q_PROCESSOR_ARM >= 7 && defined(Q_CC_GNU)
+ asm("yield"); // this works everywhere
+
+#elif defined(Q_PROCESSOR_RISCV)
+ asm(".word 0x0100000f"); // a.k.a. "pause"
+
+#elif defined(_YIELD_PROCESSOR) && defined(Q_CC_GHS)
+ _YIELD_PROCESSOR; // Green Hills (INTEGRITY), but only on ARM
+#endif
+}
+
+QT_END_NAMESPACE
+
+#endif // QYIELDCPU_H
diff --git a/src/corelib/thread/qyieldcpu.qdoc b/src/corelib/thread/qyieldcpu.qdoc
new file mode 100644
index 0000000000..c55b2c8a73
--- /dev/null
+++ b/src/corelib/thread/qyieldcpu.qdoc
@@ -0,0 +1,59 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2023 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \fn qYieldCpu()
+ \inmodule QtCore
+ \ingroup thread
+ \relates QAtomicInteger
+ //! \relatesalso QAtomicPointer
+ \since 6.7
+
+ Pauses the execution of the current thread for an unspecified time, using
+ hardware instructions, without de-scheduling this thread. This function is
+ meant to be used in high-throughput loops where the code expects another
+ thread to modify an atomic variable. This is completely different from
+ QThread::yieldCurrentThread(), which is an OS-level operation that may take
+ the whole thread off the CPU and allow other threads (possibly belonging to
+ other processes) to run.
+
+ So, instead of
+ \code
+ while (!condition)
+ ;
+ \endcode
+
+ one should write
+ \code
+ while (!condition)
+ qYieldCpu();
+ \endcode
+
+ This is useful both with and without hardware multithreading on the same
+ core. In the case of hardware threads, it serves to prevent further
+ speculative execution filling up the pipeline, which could starve the
+ sibling thread of resources. Across cores and higher levels of separation,
+ it allows the cache coherency protocol to allocate the cache line being
+ modified and inspected to the logical processor whose result this code is
+ expecting.
+
+ It is also recommended to loop around code that does not modify the global
+ variable, to avoid contention in exclusively obtaining the memory location.
+ Therefore, an atomic modification loop such as a spinlock acquisition
+ should be:
+
+ \code
+ while (true) {
+ while (!readOnlyCondition(atomic))
+ qYieldCpu();
+ if (modify(atomic))
+ break;
+ }
+ \endcode
+
+ On x86 processors and on RISC-V processors with the \c{Zihintpause}
+ extension, this will emit the \c PAUSE instruction, which is ignored on
+ processors that don't support it; on ARMv7 or later ARM processors, it will
+ emit the \c{YIELD} instruction.
+*/
diff --git a/src/corelib/time/qcalendar.cpp b/src/corelib/time/qcalendar.cpp
index 5eaecedbbd..c87d4b7cf3 100644
--- a/src/corelib/time/qcalendar.cpp
+++ b/src/corelib/time/qcalendar.cpp
@@ -498,8 +498,8 @@ Q_GLOBAL_STATIC(QtPrivate::QCalendarRegistry, calendarRegistry);
base-classes for custom calendar backends, but cannot be instantiated
themselves.
- \sa calendarId(), QDate, QDateTime, QDateEdit,
- QDateTimeEdit, QCalendarWidget
+ \sa calendarId(), QDate, QDateTime, QDateEdit, QDateTimeEdit,
+ QCalendarWidget, {The Low-Level API: Extending Qt Applications}
*/
/*!
@@ -853,20 +853,75 @@ int QCalendarBackend::maximumMonthsInYear() const
already used in QDate::dayOfWeek() to mean an invalid date). The calendar
should treat the numbers used as an \c enum, whose values need not be
contiguous, nor need they follow closely from the 1 through 7 of the usual
- returns. It suffices that weekDayName() can recognize each such number as
- identifying a distinct name, that it returns to identify the particular
- intercallary day.
+ returns. It suffices that;
+ \list
+ \li weekDayName() can recognize each such number as identifying a distinct
+ name, that it returns to identify the particular intercallary day; and
+ \li matchCenturyToWeekday() can determine what century adjustment aligns a
+ given date within a century to a given day of the week, where this is
+ relevant and possible.
+ \endlist
This base implementation uses the day-numbering that various calendars have
borrowed off the Hebrew calendar.
- \sa weekDayName(), standaloneWeekDayName(), QDate::dayOfWeek()
- */
+ \sa weekDayName(), standaloneWeekDayName(), QDate::dayOfWeek(), Qt::DayOfWeek
+*/
int QCalendarBackend::dayOfWeek(qint64 jd) const
{
return QRoundingDown::qMod<7>(jd) + 1;
}
+/*!
+ \since 6.7
+ Adjusts century of \a parts to match \a dow.
+
+ Preserves parts.month and parts.day while adjusting parts.year by a multiple
+ of 100 (taking the absence of year zero into account, when relevant) to
+ obtain a date for which dayOfWeek() is \a dow. Prefers smaller changes over
+ larger and increases to the century over decreases of the same
+ magnitude. Returns the Julian Day number for the selected date or
+ std::numeric_limits<qint64>::min(), a.k.a. QDate::nullJd(), if there is no
+ date matching these requirements.
+
+ The base-class provides a brute-force implementation that steps outwards
+ from the given date by centures, above and below by up to 14 centuries, in
+ search of a matching date. This is neither computationally efficient nor
+ elegant but should work as advertised for calendars in which every month-day
+ combination does appear on all days of the week, across sufficiently many
+ centuries.
+*/
+qint64 QCalendarBackend::matchCenturyToWeekday(const QCalendar::YearMonthDay &parts, int dow) const
+{
+ Q_ASSERT(parts.isValid());
+ // Brute-force solution as fall-back.
+ const auto checkOffset = [parts, dow, this](int centuries) -> std::optional<qint64> {
+ // Offset parts.year by the given number of centuries:
+ int year = parts.year + centuries * 100;
+ // but take into account the effect of crossing zero, if we did:
+ if (!hasYearZero() && (parts.year > 0) != (year > 0))
+ year += parts.year > 0 ? -1 : +1;
+ qint64 jd;
+ if (isDateValid(year, parts.month, parts.day)
+ && dateToJulianDay(year, parts.month, parts.day, &jd)
+ && dayOfWeek(jd) == dow) {
+ return jd;
+ }
+ return std::nullopt;
+ };
+ // Empirically, aside from Gregorian, each calendar finds every dow within
+ // any 29-century run, so 14 centuries is the biggest offset we ever need.
+ for (int offset = 0; offset < 15; ++offset) {
+ if (auto jd = checkOffset(offset))
+ return *jd;
+ if (offset) {
+ if (auto jd = checkOffset(-offset))
+ return *jd;
+ }
+ }
+ return (std::numeric_limits<qint64>::min)();
+}
+
// Month and week-day name look-ups (implemented in qlocale.cpp):
/*!
\fn QString QCalendarBackend::monthName(const QLocale &locale, int month, int year,
@@ -1425,6 +1480,32 @@ QDate QCalendar::dateFromParts(const QCalendar::YearMonthDay &parts) const
}
/*!
+ \since 6.7
+ Adjusts the century of a date to match a given day of the week.
+
+ For use when given a date's day of week, day of month, month and last two
+ digits of the year. Returns a QDate instance with the given \a dow as its \l
+ {QDate::}{dayOfWeek()}, matching the given \a parts in month and day of the
+ month. The returned QDate's \l {QDate::}{year()} shall differ from
+ \c{parts.year} by a multiple of 100, preferring small multiples over larger
+ and positive multiples over their negations.
+
+ If no date matches these conditions, an invalid QDate is returned: the day
+ of week is incompatible with the other data given. This arises, for example,
+ with the Gregorian calendar, whose 400-year cycle is a whole number of weeks
+ long, so any given month and day of that month only ever falls, in years
+ with a given last two digits, on four days of the week. (In the special case
+ of February 29th at the turn of a century, when that is a leap year, only
+ one day of the week is possible: Tuesday.)
+*/
+QDate QCalendar::matchCenturyToWeekday(const QCalendar::YearMonthDay &parts, int dow) const
+{
+ SAFE_D();
+ return d && parts.isValid()
+ ? QDate::fromJulianDay(d->matchCenturyToWeekday(parts, dow)) : QDate();
+}
+
+/*!
Converts a QDate to a year, month, and day of the month.
The returned structure's isValid() shall be false if the calendar is unable
diff --git a/src/corelib/time/qcalendar.h b/src/corelib/time/qcalendar.h
index ce8845f5e6..434f06d67f 100644
--- a/src/corelib/time/qcalendar.h
+++ b/src/corelib/time/qcalendar.h
@@ -144,6 +144,7 @@ public:
// QDate conversions:
QDate dateFromParts(int year, int month, int day) const;
QDate dateFromParts(const YearMonthDay &parts) const;
+ QDate matchCenturyToWeekday(const YearMonthDay &parts, int dow) const;
YearMonthDay partsFromDate(QDate date) const;
int dayOfWeek(QDate date) const;
diff --git a/src/corelib/time/qcalendarbackend_p.h b/src/corelib/time/qcalendarbackend_p.h
index 6f2782f506..15e0795755 100644
--- a/src/corelib/time/qcalendarbackend_p.h
+++ b/src/corelib/time/qcalendarbackend_p.h
@@ -59,8 +59,10 @@ class Q_CORE_EXPORT QCalendarBackend
{
friend class QCalendar;
friend class QtPrivate::QCalendarRegistry;
+ Q_DISABLE_COPY_MOVE(QCalendarBackend)
public:
+ QCalendarBackend() = default;
virtual ~QCalendarBackend();
virtual QString name() const = 0;
@@ -86,8 +88,9 @@ public:
// Julian Day conversions:
virtual bool dateToJulianDay(int year, int month, int day, qint64 *jd) const = 0;
virtual QCalendar::YearMonthDay julianDayToDate(qint64 jd) const = 0;
- // Day of week and week numbering:
+ // Day of week:
virtual int dayOfWeek(qint64 jd) const;
+ virtual qint64 matchCenturyToWeekday(const QCalendar::YearMonthDay &parts, int dow) const;
// Names of months and week-days (implemented in qlocale.cpp):
virtual QString monthName(const QLocale &locale, int month, int year,
diff --git a/src/corelib/time/qdatetime.cpp b/src/corelib/time/qdatetime.cpp
index fdd2aa7793..687f174c07 100644
--- a/src/corelib/time/qdatetime.cpp
+++ b/src/corelib/time/qdatetime.cpp
@@ -63,9 +63,9 @@ static inline QDate fixedDate(QCalendar::YearMonthDay parts)
{
if (parts.year) {
parts.day = qMin(parts.day, QGregorianCalendar::monthLength(parts.month, parts.year));
- qint64 jd;
- if (QGregorianCalendar::julianFromParts(parts.year, parts.month, parts.day, &jd))
- return QDate::fromJulianDay(jd);
+ const auto jd = QGregorianCalendar::julianFromParts(parts.year, parts.month, parts.day);
+ if (jd)
+ return QDate::fromJulianDay(*jd);
}
return QDate();
}
@@ -130,7 +130,7 @@ ParsedInt readInt(QStringView text)
struct ParsedRfcDateTime {
QDate date;
QTime time;
- int utcOffset;
+ int utcOffset = 0;
};
static int shortDayFromName(QStringView name)
@@ -280,7 +280,7 @@ static ParsedRfcDateTime rfcDateImpl(QStringView s)
}
#endif // datestring
-// Return offset in [+-]HH:mm format
+// Return offset in ±HH:mm format
static QString toOffsetString(Qt::DateFormat format, int offset)
{
return QString::asprintf("%c%02d%s%02d",
@@ -292,12 +292,12 @@ static QString toOffsetString(Qt::DateFormat format, int offset)
}
#if QT_CONFIG(datestring)
-// Parse offset in [+-]HH[[:]mm] format
+// Parse offset in ±HH[[:]mm] format
static int fromOffsetString(QStringView offsetString, bool *valid) noexcept
{
*valid = false;
- const int size = offsetString.size();
+ const qsizetype size = offsetString.size();
if (size < 2 || size > 6)
return 0;
@@ -318,7 +318,7 @@ static int fromOffsetString(QStringView offsetString, bool *valid) noexcept
qsizetype hhLen = time.indexOf(u':');
qsizetype mmIndex;
if (hhLen == -1)
- mmIndex = hhLen = 2; // [+-]HHmm or [+-]HH format
+ mmIndex = hhLen = 2; // ±HHmm or ±HH format
else
mmIndex = hhLen + 1;
@@ -348,6 +348,12 @@ static int fromOffsetString(QStringView offsetString, bool *valid) noexcept
\reentrant
\brief The QDate class provides date functions.
+ \compares strong
+ \compareswith strong std::chrono::year_month_day std::chrono::year_month_day_last \
+ std::chrono::year_month_weekday std::chrono::year_month_weekday_last
+ These comparison operators are only available when using C++20.
+ \endcompareswith
+
A QDate object represents a particular day, regardless of calendar, locale
or other settings used when creating it or supplied by the system. It can
report the year, month and day of the month that represent the day with
@@ -435,8 +441,9 @@ static int fromOffsetString(QStringView offsetString, bool *valid) noexcept
QDate::QDate(int y, int m, int d)
{
- if (!QGregorianCalendar::julianFromParts(y, m, d, &jd))
- jd = nullJd();
+ static_assert(maxJd() == JulianDayMax);
+ static_assert(minJd() == JulianDayMin);
+ jd = QGregorianCalendar::julianFromParts(y, m, d).value_or(nullJd());
}
QDate::QDate(int y, int m, int d, QCalendar cal)
@@ -445,14 +452,14 @@ QDate::QDate(int y, int m, int d, QCalendar cal)
}
/*!
- \fn QDate::QDate(std::chrono::year_month_day ymd)
- \fn QDate::QDate(std::chrono::year_month_day_last ymd)
- \fn QDate::QDate(std::chrono::year_month_weekday ymd)
- \fn QDate::QDate(std::chrono::year_month_weekday_last ymd)
+ \fn QDate::QDate(std::chrono::year_month_day date)
+ \fn QDate::QDate(std::chrono::year_month_day_last date)
+ \fn QDate::QDate(std::chrono::year_month_weekday date)
+ \fn QDate::QDate(std::chrono::year_month_weekday_last date)
\since 6.4
- Constructs a QDate representing the same date as \a ymd. This allows for
+ Constructs a QDate representing the same date as \a date. This allows for
easy interoperability between the Standard Library calendaring classes and
Qt datetime classes.
@@ -461,9 +468,9 @@ QDate::QDate(int y, int m, int d, QCalendar cal)
\snippet code/src_corelib_time_qdatetime.cpp 22
\note Unlike QDate, std::chrono::year and the related classes feature the
- year zero. This means that if \a ymd is in the year zero or before, the
+ year zero. This means that if \a date is in the year zero or before, the
resulting QDate object will have an year one less than the one specified by
- \a ymd.
+ \a date.
\note This function requires C++20.
*/
@@ -695,9 +702,8 @@ int QDate::dayOfYear(QCalendar cal) const
int QDate::dayOfYear() const
{
if (isValid()) {
- qint64 first;
- if (QGregorianCalendar::julianFromParts(year(), 1, 1, &first))
- return jd - first + 1;
+ if (const auto first = QGregorianCalendar::julianFromParts(year(), 1, 1))
+ return jd - *first + 1;
}
return 0;
}
@@ -828,7 +834,9 @@ static QTimeZone asTimeZone(Qt::TimeSpec spec, int offset, const char *warner)
}
#endif // Helper for 6.9 deprecation
-static bool inDateTimeRange(qint64 jd, bool start)
+enum class DaySide { Start, End };
+
+static bool inDateTimeRange(qint64 jd, DaySide side)
{
using Bounds = std::numeric_limits<qint64>;
if (jd < Bounds::min() + JULIAN_DAY_FOR_EPOCH)
@@ -839,15 +847,22 @@ static bool inDateTimeRange(qint64 jd, bool start)
// (Divisions rounded towards zero, as MSECS_PER_DAY is even - so doesn't
// divide max() - and has factors other than two, so doesn't divide min().)
// Range includes start of last day and end of first:
- if (start)
+ switch (side) {
+ case DaySide::Start:
return jd > minDay && jd <= maxDay;
- return jd >= minDay && jd < maxDay;
+ case DaySide::End:
+ return jd >= minDay && jd < maxDay;
+ }
+ Q_UNREACHABLE_RETURN(false);
}
static QDateTime toEarliest(QDate day, const QTimeZone &zone)
{
Q_ASSERT(!zone.isUtcOrFixedOffset());
- const auto moment = [=](QTime time) { return QDateTime(day, time, zone); };
+ // And the day starts in a gap. First find a moment not in that gap.
+ const auto moment = [=](QTime time) {
+ return QDateTime(day, time, zone, QDateTime::TransitionResolution::Reject);
+ };
// Longest routine time-zone transition is 2 hours:
QDateTime when = moment(QTime(2, 0));
if (!when.isValid()) {
@@ -864,8 +879,9 @@ static QDateTime toEarliest(QDate day, const QTimeZone &zone)
int low = 0;
// Binary chop to the right minute
while (high > low + 1) {
- int mid = (high + low) / 2;
- QDateTime probe = moment(QTime(mid / 60, mid % 60));
+ const int mid = (high + low) / 2;
+ const QDateTime probe = QDateTime(day, QTime(mid / 60, mid % 60), zone,
+ QDateTime::TransitionResolution::PreferBefore);
if (probe.isValid() && probe.date() == day) {
high = mid;
when = probe;
@@ -873,6 +889,24 @@ static QDateTime toEarliest(QDate day, const QTimeZone &zone)
low = mid;
}
}
+ // Transitions out of local solar mean time, and the few international
+ // date-line crossings before that (Alaska, Philippines), may have happened
+ // between minute boundaries. Don't try to fix milliseconds.
+ if (QDateTime p = moment(when.time().addSecs(-1)); Q_UNLIKELY(p.isValid() && p.date() == day)) {
+ high *= 60;
+ low *= 60;
+ while (high > low + 1) {
+ const int mid = (high + low) / 2;
+ const int min = mid / 60;
+ const QDateTime probe = moment(QTime(min / 60, min % 60, mid % 60));
+ if (probe.isValid() && probe.date() == day) {
+ high = mid;
+ when = probe;
+ } else {
+ low = mid;
+ }
+ }
+ }
return when.isValid() ? when : QDateTime();
}
@@ -906,27 +940,29 @@ static QDateTime toEarliest(QDate day, const QTimeZone &zone)
*/
QDateTime QDate::startOfDay(const QTimeZone &zone) const
{
- if (!inDateTimeRange(jd, true) || !zone.isValid())
+ if (!inDateTimeRange(jd, DaySide::Start) || !zone.isValid())
return QDateTime();
- QDateTime when(*this, QTime(0, 0), zone);
- if (when.isValid())
- return when;
-
+ QDateTime when(*this, QTime(0, 0), zone,
+ QDateTime::TransitionResolution::RelativeToBefore);
+ if (Q_UNLIKELY(!when.isValid() || when.date() != *this)) {
#if QT_CONFIG(timezone)
- // The start of the day must have fallen in a spring-forward's gap; find the spring-forward:
- if (zone.timeSpec() == Qt::TimeZone && zone.hasTransitions()) {
- QTimeZone::OffsetData tran
- // There's unlikely to be another transition before noon tomorrow.
- // However, the whole of today may have been skipped !
- = zone.previousTransition(QDateTime(addDays(1), QTime(12, 0), zone));
- const QDateTime &at = tran.atUtc.toTimeZone(zone);
- if (at.isValid() && at.date() == *this)
- return at;
- }
+ // The start of the day must have fallen in a spring-forward's gap; find the spring-forward:
+ if (zone.timeSpec() == Qt::TimeZone && zone.hasTransitions()) {
+ QTimeZone::OffsetData tran
+ // There's unlikely to be another transition before noon tomorrow.
+ // However, the whole of today may have been skipped !
+ = zone.previousTransition(QDateTime(addDays(1), QTime(12, 0), zone));
+ const QDateTime &at = tran.atUtc.toTimeZone(zone);
+ if (at.isValid() && at.date() == *this)
+ return at;
+ }
#endif
- return toEarliest(*this, zone);
+ when = toEarliest(*this, zone);
+ }
+
+ return when;
}
/*!
@@ -978,7 +1014,10 @@ QDateTime QDate::startOfDay(Qt::TimeSpec spec, int offsetSeconds) const
static QDateTime toLatest(QDate day, const QTimeZone &zone)
{
Q_ASSERT(!zone.isUtcOrFixedOffset());
- const auto moment = [=](QTime time) { return QDateTime(day, time, zone); };
+ // And the day ends in a gap. First find a moment not in that gap:
+ const auto moment = [=](QTime time) {
+ return QDateTime(day, time, zone, QDateTime::TransitionResolution::Reject);
+ };
// Longest routine time-zone transition is 2 hours:
QDateTime when = moment(QTime(21, 59, 59, 999));
if (!when.isValid()) {
@@ -995,8 +1034,9 @@ static QDateTime toLatest(QDate day, const QTimeZone &zone)
int low = when.time().msecsSinceStartOfDay() / 60000;
// Binary chop to the right minute
while (high > low + 1) {
- int mid = (high + low) / 2;
- QDateTime probe = moment(QTime(mid / 60, mid % 60, 59, 999));
+ const int mid = (high + low) / 2;
+ const QDateTime probe = QDateTime(day, QTime(mid / 60, mid % 60, 59, 999), zone,
+ QDateTime::TransitionResolution::PreferAfter);
if (probe.isValid() && probe.date() == day) {
low = mid;
when = probe;
@@ -1004,6 +1044,24 @@ static QDateTime toLatest(QDate day, const QTimeZone &zone)
high = mid;
}
}
+ // Transitions out of local solar mean time, and the few international
+ // date-line crossings before that (Alaska, Philippines), may have happened
+ // between minute boundaries. Don't try to fix milliseconds.
+ if (QDateTime p = moment(when.time().addSecs(1)); Q_UNLIKELY(p.isValid() && p.date() == day)) {
+ high *= 60;
+ low *= 60;
+ while (high > low + 1) {
+ const int mid = (high + low) / 2;
+ const int min = mid / 60;
+ const QDateTime probe = moment(QTime(min / 60, min % 60, mid % 60, 999));
+ if (probe.isValid() && probe.date() == day) {
+ low = mid;
+ when = probe;
+ } else {
+ high = mid;
+ }
+ }
+ }
return when.isValid() ? when : QDateTime();
}
@@ -1038,27 +1096,28 @@ static QDateTime toLatest(QDate day, const QTimeZone &zone)
*/
QDateTime QDate::endOfDay(const QTimeZone &zone) const
{
- if (!inDateTimeRange(jd, false) || !zone.isValid())
+ if (!inDateTimeRange(jd, DaySide::End) || !zone.isValid())
return QDateTime();
- QDateTime when(*this, QTime(23, 59, 59, 999), zone);
- if (when.isValid())
- return when;
-
+ QDateTime when(*this, QTime(23, 59, 59, 999), zone,
+ QDateTime::TransitionResolution::RelativeToAfter);
+ if (Q_UNLIKELY(!when.isValid() || when.date() != *this)) {
#if QT_CONFIG(timezone)
- // The end of the day must have fallen in a spring-forward's gap; find the spring-forward:
- if (zone.timeSpec() == Qt::TimeZone && zone.hasTransitions()) {
- QTimeZone::OffsetData tran
- // It's unlikely there's been another transition since yesterday noon.
- // However, the whole of today may have been skipped !
- = zone.nextTransition(QDateTime(addDays(-1), QTime(12, 0), zone));
- const QDateTime &at = tran.atUtc.toTimeZone(zone);
- if (at.isValid() && at.date() == *this)
- return at;
- }
+ // The end of the day must have fallen in a spring-forward's gap; find the spring-forward:
+ if (zone.timeSpec() == Qt::TimeZone && zone.hasTransitions()) {
+ QTimeZone::OffsetData tran
+ // It's unlikely there's been another transition since yesterday noon.
+ // However, the whole of today may have been skipped !
+ = zone.nextTransition(QDateTime(addDays(-1), QTime(12, 0), zone));
+ const QDateTime &at = tran.atUtc.toTimeZone(zone);
+ if (at.isValid() && at.date() == *this)
+ return at;
+ }
#endif
- return toLatest(*this, zone);
+ when = toLatest(*this, zone);
+ }
+ return when;
}
/*!
@@ -1182,12 +1241,14 @@ QString QDate::toString(Qt::DateFormat format) const
/*!
\fn QString QDate::toString(const QString &format, QCalendar cal) const
\fn QString QDate::toString(QStringView format, QCalendar cal) const
+ \since 5.14
Returns the date as a string. The \a format parameter determines the format
of the result string. If \a cal is supplied, it determines the calendar used
- to represent the date; it defaults to Gregorian.
+ to represent the date; it defaults to Gregorian. Prior to Qt 5.14, there was
+ no \a cal parameter and the Gregorian calendar was always used.
- These expressions may be used:
+ These expressions may be used in the \a format parameter:
\table
\header \li Expression \li Output
@@ -1238,12 +1299,30 @@ QString QDate::toString(Qt::DateFormat format) const
in May will contribute \c{"MayMay05"} to the output.
\sa fromString(), QDateTime::toString(), QTime::toString(), QLocale::toString()
-
*/
QString QDate::toString(QStringView format, QCalendar cal) const
{
return QLocale::c().toString(*this, format, cal);
}
+
+// Out-of-line no-calendar overloads, since QCalendar is a non-trivial type
+/*!
+ \overload
+ \since 5.10
+*/
+QString QDate::toString(QStringView format) const
+{
+ return QLocale::c().toString(*this, format, QCalendar());
+}
+
+/*!
+ \overload
+ \since 4.6
+*/
+QString QDate::toString(const QString &format) const
+{
+ return QLocale::c().toString(*this, qToStringViewIgnoringNull(format), QCalendar());
+}
#endif // datestring
/*!
@@ -1258,11 +1337,9 @@ QString QDate::toString(QStringView format, QCalendar cal) const
*/
bool QDate::setDate(int year, int month, int day)
{
- if (QGregorianCalendar::julianFromParts(year, month, day, &jd))
- return true;
-
- jd = nullJd();
- return false;
+ const auto maybe = QGregorianCalendar::julianFromParts(year, month, day);
+ jd = maybe.value_or(nullJd());
+ return bool(maybe);
}
/*!
@@ -1451,7 +1528,7 @@ QDate QDate::addYears(int nyears, QCalendar cal) const
int old_y = parts.year;
parts.year += nyears;
- // If we just crossed (or hit) a missing year zero, adjust year by +/- 1:
+ // If we just crossed (or hit) a missing year zero, adjust year by ±1:
if (!cal.hasYearZero() && ((old_y > 0) != (parts.year > 0) || !parts.year))
parts.year += nyears > 0 ? +1 : -1;
@@ -1474,7 +1551,7 @@ QDate QDate::addYears(int nyears) const
int old_y = parts.year;
parts.year += nyears;
- // If we just crossed (or hit) a missing year zero, adjust year by +/- 1:
+ // If we just crossed (or hit) a missing year zero, adjust year by ±1:
if ((old_y > 0) != (parts.year > 0) || !parts.year)
parts.year += nyears > 0 ? +1 : -1;
@@ -1504,14 +1581,14 @@ qint64 QDate::daysTo(QDate d) const
/*!
- \fn bool QDate::operator==(QDate lhs, QDate rhs)
+ \fn bool QDate::operator==(const QDate &lhs, const QDate &rhs)
Returns \c true if \a lhs and \a rhs represent the same day, otherwise
\c false.
*/
/*!
- \fn bool QDate::operator!=(QDate lhs, QDate rhs)
+ \fn bool QDate::operator!=(const QDate &lhs, const QDate &rhs)
Returns \c true if \a lhs and \a rhs represent distinct days; otherwise
returns \c false.
@@ -1520,26 +1597,26 @@ qint64 QDate::daysTo(QDate d) const
*/
/*!
- \fn bool QDate::operator<(QDate lhs, QDate rhs)
+ \fn bool QDate::operator<(const QDate &lhs, const QDate &rhs)
Returns \c true if \a lhs is earlier than \a rhs; otherwise returns \c false.
*/
/*!
- \fn bool QDate::operator<=(QDate lhs, QDate rhs)
+ \fn bool QDate::operator<=(const QDate &lhs, const QDate &rhs)
Returns \c true if \a lhs is earlier than or equal to \a rhs;
otherwise returns \c false.
*/
/*!
- \fn bool QDate::operator>(QDate lhs, QDate rhs)
+ \fn bool QDate::operator>(const QDate &lhs, const QDate &rhs)
Returns \c true if \a lhs is later than \a rhs; otherwise returns \c false.
*/
/*!
- \fn bool QDate::operator>=(QDate lhs, QDate rhs)
+ \fn bool QDate::operator>=(const QDate &lhs, const QDate &rhs)
Returns \c true if \a lhs is later than or equal to \a rhs;
otherwise returns \c false.
@@ -1619,7 +1696,7 @@ QDate QDate::fromString(QStringView string, Qt::DateFormat format)
}
/*!
- \fn QDate QDate::fromString(const QString &string, const QString &format, QCalendar cal)
+ \fn QDate QDate::fromString(const QString &string, const QString &format, int baseYear, QCalendar cal)
Returns the QDate represented by the \a string, using the \a
format given, or an invalid date if the string cannot be parsed.
@@ -1669,11 +1746,22 @@ QDate QDate::fromString(QStringView string, Qt::DateFormat format)
\table
\header \li Field \li Default value
- \row \li Year \li 1900
+ \row \li Year \li \a baseYear (or 1900)
\row \li Month \li 1 (January)
\row \li Day \li 1
\endtable
+ When \a format only specifies the last two digits of a year, the 100 years
+ starting at \a baseYear are the candidates first considered. Prior to 6.7
+ there was no \a baseYear parameter and 1900 was always used. This is the
+ default for \a baseYear, selecting a year from then to 1999. Passing 1976 as
+ \a baseYear will select a year from 1976 through 2075, for example. When the
+ format also includes month, day (of month) and day-of-week, these suffice to
+ imply the century. In such a case, a matching date is selected in the
+ nearest century to the one indicated by \a baseYear, prefering later over
+ earlier. See \l QCalendar::matchCenturyToWeekday() and \l {Date ambiguities}
+ for further details,
+
The following examples demonstrate the default values:
\snippet code/src_corelib_time_qdatetime.cpp 3
@@ -1686,6 +1774,54 @@ QDate QDate::fromString(QStringView string, Qt::DateFormat format)
\c{"MayMay05"} and set the month to May. Likewise, \c{'MMMMMM'} would match
\c{"May08"} and find it inconsistent, leading to an invalid date.
+ \section2 Date ambiguities
+
+ Different cultures use different formats for dates and, as a result, users
+ may mix up the order in which date fields should be given. For example,
+ \c{"Wed 28-Nov-01"} might mean either 2028 November 1st or the 28th of
+ November, 2001 (each of which happens to be a Wednesday). Using format
+ \c{"ddd yy-MMM-dd"} it shall be interpreted the first way, using \c{"ddd
+ dd-MMM-yy"} the second. However, which the user meant may depend on the way
+ the user normally writes dates, rather than the format the code was
+ expecting.
+
+ The example considered above mixed up day of the month and a two-digit year.
+ Similar confusion can arise over interchanging the month and day of the
+ month, when both are given as numbers. In these cases, including a day of
+ the week field in the date format can provide some redundancy, that may help
+ to catch errors of this kind. However, as in the example above, this is not
+ always effective: the interchange of two fields (or their meanings) may
+ produce dates with the same day of the week.
+
+ Including a day of the week in the format can also resolve the century of a
+ date specified using only the last two digits of its year. Unfortunately,
+ when combined with a date in which the user (or other source of data) has
+ mixed up two of the fields, this resolution can lead to finding a date which
+ does match the format's reading but isn't the one intended by its author.
+ Likewise, if the user simply gets the day of the week wrong, in an otherwise
+ correct date, this can lead a date in a different century. In each case,
+ finding a date in a different century can turn a wrongly-input date into a
+ wildly different one.
+
+ The best way to avoid date ambiguities is to use four-digit years and months
+ specified by name (whether full or abbreviated), ideally collected via user
+ interface idioms that make abundantly clear to the user which part of the
+ date they are selecting. Including a day of the week can also help by
+ providing the means to check consistency of the data. Where data comes from
+ the user, using a format supplied by a locale selected by the user, it is
+ best to use a long format as short formats are more likely to use two-digit
+ years. Of course, it is not always possible to control the format - data may
+ come from a source you do not control, for example.
+
+ As a result of these possible sources of confusion, particularly when you
+ cannot be sure an unambiguous format is in use, it is important to check
+ that the result of reading a string as a date is not just valid but
+ reasonable for the purpose for which it was supplied. If the result is
+ outside some range of reasonable values, it may be worth getting the user to
+ confirm their date selection, showing the date read from the string in a
+ long format that does include month name and four-digit year, to make it
+ easier for them to recognize any errors.
+
\sa toString(), QDateTime::fromString(), QTime::fromString(),
QLocale::toDate()
*/
@@ -1700,21 +1836,67 @@ QDate QDate::fromString(QStringView string, Qt::DateFormat format)
\overload
\since 6.0
*/
-QDate QDate::fromString(const QString &string, QStringView format, QCalendar cal)
+QDate QDate::fromString(const QString &string, QStringView format, int baseYear, QCalendar cal)
{
QDate date;
#if QT_CONFIG(datetimeparser)
QDateTimeParser dt(QMetaType::QDate, QDateTimeParser::FromString, cal);
dt.setDefaultLocale(QLocale::c());
if (dt.parseFormat(format))
- dt.fromString(string, &date, nullptr);
+ dt.fromString(string, &date, nullptr, baseYear);
#else
Q_UNUSED(string);
Q_UNUSED(format);
+ Q_UNUSED(baseYear);
Q_UNUSED(cal);
#endif
return date;
}
+
+/*!
+ \fn QDate QDate::fromString(const QString &string, const QString &format, QCalendar cal)
+ \overload
+ \since 5.14
+*/
+
+/*!
+ \fn QDate QDate::fromString(const QString &string, QStringView format, QCalendar cal)
+ \overload
+ \since 6.0
+*/
+
+/*!
+ \fn QDate QDate::fromString(QStringView string, QStringView format, int baseYear, QCalendar cal)
+ \overload
+ \since 6.7
+*/
+
+/*!
+ \fn QDate QDate::fromString(QStringView string, QStringView format, int baseYear)
+ \overload
+ \since 6.7
+
+ Uses a default-constructed QCalendar.
+*/
+
+/*!
+ \overload
+ \since 6.7
+
+ Uses a default-constructed QCalendar.
+*/
+QDate QDate::fromString(const QString &string, QStringView format, int baseYear)
+{
+ return fromString(string, format, baseYear, QCalendar());
+}
+
+/*!
+ \fn QDate QDate::fromString(const QString &string, const QString &format, int baseYear)
+ \overload
+ \since 6.7
+
+ Uses a default-constructed QCalendar.
+*/
#endif // datestring
/*!
@@ -1773,6 +1955,8 @@ bool QDate::isLeapYear(int y)
\brief The QTime class provides clock time functions.
+ \compares strong
+
A QTime object contains a clock time, which it can express as the numbers of
hours, minutes, seconds, and milliseconds since midnight. It provides
functions for comparing times and for manipulating a time by adding a number
@@ -2185,38 +2369,38 @@ int QTime::msecsTo(QTime t) const
/*!
- \fn bool QTime::operator==(QTime lhs, QTime rhs)
+ \fn bool QTime::operator==(const QTime &lhs, const QTime &rhs)
Returns \c true if \a lhs is equal to \a rhs; otherwise returns \c false.
*/
/*!
- \fn bool QTime::operator!=(QTime lhs, QTime rhs)
+ \fn bool QTime::operator!=(const QTime &lhs, const QTime &rhs)
Returns \c true if \a lhs is different from \a rhs; otherwise returns \c false.
*/
/*!
- \fn bool QTime::operator<(QTime lhs, QTime rhs)
+ \fn bool QTime::operator<(const QTime &lhs, const QTime &rhs)
Returns \c true if \a lhs is earlier than \a rhs; otherwise returns \c false.
*/
/*!
- \fn bool QTime::operator<=(QTime lhs, QTime rhs)
+ \fn bool QTime::operator<=(const QTime &lhs, const QTime &rhs)
Returns \c true if \a lhs is earlier than or equal to \a rhs;
otherwise returns \c false.
*/
/*!
- \fn bool QTime::operator>(QTime lhs, QTime rhs)
+ \fn bool QTime::operator>(const QTime &lhs, const QTime &rhs)
Returns \c true if \a lhs is later than \a rhs; otherwise returns \c false.
*/
/*!
- \fn bool QTime::operator>=(QTime lhs, QTime rhs)
+ \fn bool QTime::operator>=(const QTime &lhs, const QTime &rhs)
Returns \c true if \a lhs is later than or equal to \a rhs;
otherwise returns \c false.
@@ -2268,7 +2452,7 @@ static QTime fromIsoTimeString(QStringView string, Qt::DateFormat format, bool *
// TextDate restricts fractional parts to the seconds field.
QStringView tail;
- const int dot = string.indexOf(u'.'), comma = string.indexOf(u',');
+ const qsizetype dot = string.indexOf(u'.'), comma = string.indexOf(u',');
if (dot != -1) {
tail = string.sliced(dot + 1);
if (tail.indexOf(u'.') != -1) // Forbid second dot:
@@ -2288,7 +2472,7 @@ static QTime fromIsoTimeString(QStringView string, Qt::DateFormat format, bool *
Q_ASSERT(frac.ok() ^ tail.isEmpty());
double fraction = frac.ok() ? frac.result * std::pow(0.1, tail.size()) : 0.0;
- const int size = string.size();
+ const qsizetype size = string.size();
if (size < 2 || size > 8)
return QTime();
@@ -2543,8 +2727,8 @@ static QTime msecsToTime(qint64 msecs)
// The inputs should not have opposite signs.
static inline bool daysAndMillisOverflow(qint64 days, qint64 millisInDay, qint64 *sumMillis)
{
- return mul_overflow(days, std::integral_constant<qint64, MSECS_PER_DAY>(), sumMillis)
- || add_overflow(*sumMillis, millisInDay, sumMillis);
+ return qMulOverflow(days, std::integral_constant<qint64, MSECS_PER_DAY>(), sumMillis)
+ || qAddOverflow(*sumMillis, millisInDay, sumMillis);
}
// Converts a date/time value into msecs
@@ -2640,7 +2824,7 @@ QDateTimePrivate::ZoneState QDateTimePrivate::expressUtcAsLocal(qint64 utcMSecs)
#if QT_CONFIG(timezone) // Use the system time-zone.
if (const auto sys = QTimeZone::systemTimeZone(); sys.isValid()) {
result.offset = sys.d->offsetFromUtc(utcMSecs);
- if (add_overflow(utcMSecs, result.offset * MSECS_PER_SEC, &result.when))
+ if (qAddOverflow(utcMSecs, result.offset * MSECS_PER_SEC, &result.when))
return result;
result.dst = sys.d->isDaylightTime(utcMSecs) ? DaylightTime : StandardTime;
result.valid = true;
@@ -2653,18 +2837,19 @@ QDateTimePrivate::ZoneState QDateTimePrivate::expressUtcAsLocal(qint64 utcMSecs)
// dates might be right, and adjust by the number of days that was off:
const qint64 jd = msecsToJulianDay(utcMSecs);
const auto ymd = QGregorianCalendar::partsFromJulian(jd);
- qint64 fakeJd, diffMillis, fakeUtc;
- if (Q_UNLIKELY(!QGregorianCalendar::julianFromParts(systemTimeYearMatching(ymd.year),
- ymd.month, ymd.day, &fakeJd)
- || mul_overflow(jd - fakeJd, std::integral_constant<qint64, MSECS_PER_DAY>(),
+ qint64 diffMillis, fakeUtc;
+ const auto fakeJd = QGregorianCalendar::julianFromParts(systemTimeYearMatching(ymd.year),
+ ymd.month, ymd.day);
+ if (Q_UNLIKELY(!fakeJd
+ || qMulOverflow(jd - *fakeJd, std::integral_constant<qint64, MSECS_PER_DAY>(),
&diffMillis)
- || sub_overflow(utcMSecs, diffMillis, &fakeUtc))) {
+ || qSubOverflow(utcMSecs, diffMillis, &fakeUtc))) {
return result;
}
result = QLocalTime::utcToLocal(fakeUtc);
// Now correct result.when for the use of the fake date:
- if (!result.valid || add_overflow(result.when, diffMillis, &result.when)) {
+ if (!result.valid || qAddOverflow(result.when, diffMillis, &result.when)) {
// If utcToLocal() failed, its return has the fake when; restore utcMSecs.
// Fail on overflow, but preserve offset and DST-ness.
result.when = utcMSecs;
@@ -2679,19 +2864,107 @@ static auto millisToWithinRange(qint64 millis)
qint64 shifted = 0;
bool good = false;
} result;
- qint64 jd = msecsToJulianDay(millis), fakeJd;
+ qint64 jd = msecsToJulianDay(millis);
auto ymd = QGregorianCalendar::partsFromJulian(jd);
- result.good = QGregorianCalendar::julianFromParts(systemTimeYearMatching(ymd.year),
- ymd.month, ymd.day, &fakeJd)
- && !daysAndMillisOverflow(fakeJd - jd, millis, &result.shifted);
+ const auto fakeJd = QGregorianCalendar::julianFromParts(systemTimeYearMatching(ymd.year),
+ ymd.month, ymd.day);
+ result.good = fakeJd && !daysAndMillisOverflow(*fakeJd - jd, millis, &result.shifted);
return result;
}
+/*!
+ \internal
+ \enum QDateTimePrivate::TransitionOption
+
+ This enumeration is used to resolve datetime combinations which fall in \l
+ {Timezone transitions}. The transition is described as a "gap" if there are
+ time representations skipped over by the zone, as is common in the "spring
+ forward" transitions in many zones on entering daylight-saving time. The
+ transition is described as a "fold" if there are time representations
+ repeated in the zone, as in a "fall back" transition out of daylight-saving
+ time.
+
+ When the options specified do not determine a resolution for a datetime, it
+ is marked invalid.
+
+ The prepared option sets above are in fact composed from low-level atomic
+ options. For each of gap and fold you can chose between two candidate times,
+ one before or after the transition, based on the time requested; or you can
+ pick the moment of transition, or the start or end of the transition
+ interval. For a gap, the start and end of the interval are the moment of the
+ transition, but for a repeated interval the start of the first pass is the
+ start of the transition interval, the end of the second pass is the end of
+ the transition interval and the moment of the transition itself is both the
+ end of the first pass and the start of the second.
+
+ \value GapUseBefore For a time in a gap, use a time before the transition,
+ as if stepping back from a later time.
+ \value GapUseAfter For a time in a gap, use a time after the transition, as
+ if stepping forward from an earlier time.
+ \value FoldUseBefore For a repeated time, use the first candidate, which is
+ before the transition.
+ \value FoldUseAfter For a repeated time, use the second candidate, which is
+ after the transition.
+ \value FlipForReverseDst For "reversed" DST, this reverses the preceding
+ four options (see below).
+
+ The last has no effect unless the "daylight-saving" time side of the
+ transition is known to have a lower offset from UTC than the standard time
+ side. (This is the "reversed" DST case of \l {Timezone transitions}.) In
+ that case, if other options would select a time after the transition, a time
+ before is used instead, and vice versa. This effectively turns a preference
+ for the side with lower offset into a preference for the side that is
+ officially standard time, even if it has higher offset; and conversely a
+ preference for higher offset into a preference for daylight-saving time,
+ even if it has a lower offset. This option has no effect on a resolution
+ that selects the moment of transition or the start or end of the transition
+ interval.
+
+ The result of combining more than one of the \c GapUse* options is
+ undefined; likewise for the \c FoldUse*. Each of QDateTime's
+ TransitionResolution values, aside from Reject, maps to a combination that
+ incorporates one from each of these sets.
+*/
+
+constexpr static QDateTimePrivate::TransitionOptions
+toTransitionOptions(QDateTime::TransitionResolution res)
+{
+ switch (res) {
+ case QDateTime::TransitionResolution::RelativeToBefore:
+ return QDateTimePrivate::GapUseAfter | QDateTimePrivate::FoldUseBefore;
+ case QDateTime::TransitionResolution::RelativeToAfter:
+ return QDateTimePrivate::GapUseBefore | QDateTimePrivate::FoldUseAfter;
+ case QDateTime::TransitionResolution::PreferBefore:
+ return QDateTimePrivate::GapUseBefore | QDateTimePrivate::FoldUseBefore;
+ case QDateTime::TransitionResolution::PreferAfter:
+ return QDateTimePrivate::GapUseAfter | QDateTimePrivate::FoldUseAfter;
+ case QDateTime::TransitionResolution::PreferStandard:
+ return QDateTimePrivate::GapUseBefore
+ | QDateTimePrivate::FoldUseAfter
+ | QDateTimePrivate::FlipForReverseDst;
+ case QDateTime::TransitionResolution::PreferDaylightSaving:
+ return QDateTimePrivate::GapUseAfter
+ | QDateTimePrivate::FoldUseBefore
+ | QDateTimePrivate::FlipForReverseDst;
+ case QDateTime::TransitionResolution::Reject: break;
+ }
+ return {};
+}
+
+constexpr static QDateTimePrivate::TransitionOptions
+toTransitionOptions(QDateTimePrivate::DaylightStatus dst)
+{
+ return toTransitionOptions(dst == QDateTimePrivate::DaylightTime
+ ? QDateTime::TransitionResolution::PreferDaylightSaving
+ : QDateTime::TransitionResolution::PreferStandard);
+}
+
QString QDateTimePrivate::localNameAtMillis(qint64 millis, DaylightStatus dst)
{
+ const QDateTimePrivate::TransitionOptions resolve = toTransitionOptions(dst);
QString abbreviation;
if (millisInSystemRange(millis, MSECS_PER_DAY)) {
- abbreviation = QLocalTime::localTimeAbbbreviationAt(millis, dst);
+ abbreviation = QLocalTime::localTimeAbbbreviationAt(millis, resolve);
if (!abbreviation.isEmpty())
return abbreviation;
}
@@ -2701,7 +2974,7 @@ QString QDateTimePrivate::localNameAtMillis(qint64 millis, DaylightStatus dst)
// Use the system zone:
const auto sys = QTimeZone::systemTimeZone();
if (sys.isValid()) {
- ZoneState state = zoneStateAtMillis(sys, millis, dst);
+ ZoneState state = zoneStateAtMillis(sys, millis, resolve);
if (state.valid)
return sys.d->abbreviation(state.when - state.offset * MSECS_PER_SEC);
}
@@ -2711,19 +2984,20 @@ QString QDateTimePrivate::localNameAtMillis(qint64 millis, DaylightStatus dst)
// Use a time in the system range with the same day-of-week pattern to its year:
auto fake = millisToWithinRange(millis);
if (Q_LIKELY(fake.good))
- return QLocalTime::localTimeAbbbreviationAt(fake.shifted, dst);
+ return QLocalTime::localTimeAbbbreviationAt(fake.shifted, resolve);
// Overflow, apparently.
return {};
}
// Determine the offset from UTC at the given local time as millis.
-QDateTimePrivate::ZoneState QDateTimePrivate::localStateAtMillis(qint64 millis, DaylightStatus dst)
+QDateTimePrivate::ZoneState QDateTimePrivate::localStateAtMillis(
+ qint64 millis, QDateTimePrivate::TransitionOptions resolve)
{
// First, if millis is within a day of the viable range, try mktime() in
// case it does fall in the range and gets useful information:
if (millisInSystemRange(millis, MSECS_PER_DAY)) {
- auto result = QLocalTime::mapLocalTime(millis, dst);
+ auto result = QLocalTime::mapLocalTime(millis, resolve);
if (result.valid)
return result;
}
@@ -2733,17 +3007,17 @@ QDateTimePrivate::ZoneState QDateTimePrivate::localStateAtMillis(qint64 millis,
// Use the system zone:
const auto sys = QTimeZone::systemTimeZone();
if (sys.isValid())
- return zoneStateAtMillis(sys, millis, dst);
+ return zoneStateAtMillis(sys, millis, resolve);
#endif // timezone
// Kludge
// Use a time in the system range with the same day-of-week pattern to its year:
auto fake = millisToWithinRange(millis);
if (Q_LIKELY(fake.good)) {
- auto result = QLocalTime::mapLocalTime(fake.shifted, dst);
+ auto result = QLocalTime::mapLocalTime(fake.shifted, resolve);
if (result.valid) {
qint64 adjusted;
- if (Q_UNLIKELY(add_overflow(result.when, millis - fake.shifted, &adjusted))) {
+ if (Q_UNLIKELY(qAddOverflow(result.when, millis - fake.shifted, &adjusted))) {
using Bound = std::numeric_limits<qint64>;
adjusted = millis < fake.shifted ? Bound::min() : Bound::max();
}
@@ -2758,38 +3032,26 @@ QDateTimePrivate::ZoneState QDateTimePrivate::localStateAtMillis(qint64 millis,
}
#if QT_CONFIG(timezone)
-// For a TimeZone and a time expressed in zone msecs encoding, possibly with a
-// hint to DST-ness, compute the actual DST-ness and offset, adjusting the time
-// if needed to escape a spring-forward.
-QDateTimePrivate::ZoneState QDateTimePrivate::zoneStateAtMillis(const QTimeZone &zone,
- qint64 millis, DaylightStatus dst)
+// For a TimeZone and a time expressed in zone msecs encoding, compute the
+// actual DST-ness and offset, adjusting the time if needed to escape a
+// spring-forward.
+QDateTimePrivate::ZoneState QDateTimePrivate::zoneStateAtMillis(
+ const QTimeZone &zone, qint64 millis, QDateTimePrivate::TransitionOptions resolve)
{
Q_ASSERT(zone.isValid());
Q_ASSERT(zone.timeSpec() == Qt::TimeZone);
- // Get the effective data from QTimeZone
- QTimeZonePrivate::Data data = zone.d->dataForLocalTime(millis, int(dst));
- if (data.offsetFromUtc == QTimeZonePrivate::invalidSeconds())
- return {millis};
- Q_ASSERT(zone.d->offsetFromUtc(data.atMSecsSinceEpoch) == data.offsetFromUtc);
- ZoneState state(data.atMSecsSinceEpoch + data.offsetFromUtc * MSECS_PER_SEC,
- data.offsetFromUtc,
- data.daylightTimeOffset ? DaylightTime : StandardTime);
- // Revise offset, when stepping out of a spring-forward, to what makes a
- // fromMSecsSinceEpoch(toMSecsSinceEpoch()) of the resulting QDT work:
- if (millis != state.when)
- state.offset += (millis - state.when) / MSECS_PER_SEC;
- return state;
+ return zone.d->stateAtZoneTime(millis, resolve);
}
#endif // timezone
-static inline QDateTimePrivate::ZoneState stateAtMillis(QTimeZone zone, qint64 millis,
- QDateTimePrivate::DaylightStatus dst)
+static inline QDateTimePrivate::ZoneState stateAtMillis(const QTimeZone &zone, qint64 millis,
+ QDateTimePrivate::TransitionOptions resolve)
{
if (zone.timeSpec() == Qt::LocalTime)
- return QDateTimePrivate::localStateAtMillis(millis, dst);
+ return QDateTimePrivate::localStateAtMillis(millis, resolve);
#if QT_CONFIG(timezone)
if (zone.timeSpec() == Qt::TimeZone && zone.isValid())
- return QDateTimePrivate::zoneStateAtMillis(zone, millis, dst);
+ return QDateTimePrivate::zoneStateAtMillis(zone, millis, resolve);
#endif
return {millis};
}
@@ -2902,32 +3164,55 @@ static inline bool usesSameOffset(const QDateTimeData &a, const QDateTimeData &b
}
// Refresh the LocalTime or TimeZone validity and offset
-static void refreshZonedDateTime(QDateTimeData &d, const QTimeZone &zone)
+static void refreshZonedDateTime(QDateTimeData &d, const QTimeZone &zone,
+ QDateTimePrivate::TransitionOptions resolve)
{
Q_ASSERT(zone.timeSpec() == Qt::TimeZone || zone.timeSpec() == Qt::LocalTime);
auto status = getStatus(d);
Q_ASSERT(extractSpec(status) == zone.timeSpec());
int offsetFromUtc = 0;
+ /* Callers are:
+ * QDTP::create(), where d is too new to be shared yet
+ * reviseTimeZone(), which detach()es if not short before calling this
+ * checkValidDateTime(), always follows a setDateTime() that detach()ed if not short
+
+ So we can assume d is not shared. We only need to detach() if we convert
+ from short to pimpled to accommodate an oversize msecs, which can only be
+ needed in the unlikely event we revise it.
+ */
// If not valid date and time then is invalid
if (!status.testFlags(QDateTimePrivate::ValidDate | QDateTimePrivate::ValidTime)) {
status.setFlag(QDateTimePrivate::ValidDateTime, false);
} else {
- // We have a valid date and time and a Qt::LocalTime or Qt::TimeZone that needs calculating
- // LocalTime and TimeZone might fall into a "missing" DST transition hour
- // Calling toEpochMSecs will adjust the returned date/time if it does
+ // We have a valid date and time and a Qt::LocalTime or Qt::TimeZone
+ // that might fall into a "missing" DST transition hour.
qint64 msecs = getMSecs(d);
- QDateTimePrivate::ZoneState state = stateAtMillis(zone, msecs,
- extractDaylightStatus(status));
- // Save the offset to use in offsetFromUtc() &c., even if the next check
- // marks invalid; this lets fromMSecsSinceEpoch() give a useful fallback
- // for times in spring-forward gaps.
- offsetFromUtc = state.offset;
+ QDateTimePrivate::ZoneState state = stateAtMillis(zone, msecs, resolve);
Q_ASSERT(!state.valid || (state.offset >= -SECS_PER_DAY && state.offset <= SECS_PER_DAY));
- if (state.valid && msecs == state.when)
- status = mergeDaylightStatus(status | QDateTimePrivate::ValidDateTime, state.dst);
- else // msecs changed or failed to convert (e.g. overflow)
+ if (state.dst == QDateTimePrivate::UnknownDaylightTime) { // Overflow
status.setFlag(QDateTimePrivate::ValidDateTime, false);
+ } else if (state.valid) {
+ status = mergeDaylightStatus(status, state.dst);
+ offsetFromUtc = state.offset;
+ status.setFlag(QDateTimePrivate::ValidDateTime, true);
+ if (Q_UNLIKELY(msecs != state.when)) {
+ // Update msecs to the resolution:
+ if (status.testFlag(QDateTimePrivate::ShortData)) {
+ if (msecsCanBeSmall(state.when)) {
+ d.data.msecs = qintptr(state.when);
+ } else {
+ // Convert to long-form so we can hold the revised msecs:
+ status.setFlag(QDateTimePrivate::ShortData, false);
+ d.detach();
+ }
+ }
+ if (!status.testFlag(QDateTimePrivate::ShortData))
+ d->m_msecs = state.when;
+ }
+ } else {
+ status.setFlag(QDateTimePrivate::ValidDateTime, false);
+ }
}
if (status.testFlag(QDateTimePrivate::ShortData)) {
@@ -2953,7 +3238,7 @@ static void refreshSimpleDateTime(QDateTimeData &d)
}
// Clean up and set status after assorted set-up or reworking:
-static void checkValidDateTime(QDateTimeData &d)
+static void checkValidDateTime(QDateTimeData &d, QDateTime::TransitionResolution resolve)
{
auto spec = extractSpec(getStatus(d));
switch (spec) {
@@ -2966,12 +3251,13 @@ static void checkValidDateTime(QDateTimeData &d)
case Qt::LocalTime:
// For these, we need to check whether (the zone is valid and) the time
// is valid for the zone. Expensive, but we have no other option.
- refreshZonedDateTime(d, d.timeZone());
+ refreshZonedDateTime(d, d.timeZone(), toTransitionOptions(resolve));
break;
}
}
-static void reviseTimeZone(QDateTimeData &d, QTimeZone zone)
+static void reviseTimeZone(QDateTimeData &d, const QTimeZone &zone,
+ QDateTime::TransitionResolution resolve)
{
Qt::TimeSpec spec = zone.timeSpec();
auto status = mergeSpec(getStatus(d), spec);
@@ -3010,7 +3296,7 @@ static void reviseTimeZone(QDateTimeData &d, QTimeZone zone)
if (QTimeZone::isUtcOrFixedOffset(spec))
refreshSimpleDateTime(d);
else
- refreshZonedDateTime(d, zone);
+ refreshZonedDateTime(d, zone, toTransitionOptions(resolve));
}
static void setDateTime(QDateTimeData &d, QDate date, QTime time)
@@ -3068,7 +3354,7 @@ static void setDateTime(QDateTimeData &d, QDate date, QTime time)
}
}
-static QPair<QDate, QTime> getDateTime(const QDateTimeData &d)
+static std::pair<QDate, QTime> getDateTime(const QDateTimeData &d)
{
auto status = getStatus(d);
const qint64 msecs = getMSecs(d);
@@ -3207,6 +3493,16 @@ inline void QDateTime::Data::detach()
d = x;
}
+void QDateTime::Data::invalidate()
+{
+ if (isShort()) {
+ data.status &= ~int(QDateTimePrivate::ValidityMask);
+ } else {
+ detach();
+ d->m_status &= ~QDateTimePrivate::ValidityMask;
+ }
+}
+
QTimeZone QDateTime::Data::timeZone() const
{
switch (getSpec(*this)) {
@@ -3245,14 +3541,15 @@ inline QDateTimePrivate *QDateTime::Data::operator->()
*****************************************************************************/
Q_NEVER_INLINE
-QDateTime::Data QDateTimePrivate::create(QDate toDate, QTime toTime, const QTimeZone &zone)
+QDateTime::Data QDateTimePrivate::create(QDate toDate, QTime toTime, const QTimeZone &zone,
+ QDateTime::TransitionResolution resolve)
{
QDateTime::Data result(zone);
setDateTime(result, toDate, toTime);
if (zone.isUtcOrFixedOffset())
refreshSimpleDateTime(result);
else
- refreshZonedDateTime(result, zone);
+ refreshZonedDateTime(result, zone, toTransitionOptions(resolve));
return result;
}
@@ -3267,6 +3564,8 @@ QDateTime::Data QDateTimePrivate::create(QDate toDate, QTime toTime, const QTime
\reentrant
\brief The QDateTime class provides date and time functions.
+ \compares weak
+
A QDateTime object encodes a calendar date and a clock time (a "datetime")
in accordance with a time representation. It combines features of the QDate
and QTime classes. It can read the current datetime from the system
@@ -3282,17 +3581,17 @@ QDateTime::Data QDateTimePrivate::create(QDate toDate, QTime toTime, const QTime
UTC of +3600 seconds is one hour ahead of UTC (usually written in ISO
standard notation as "UTC+01:00"), with no daylight-saving
complications. When using either local time or a specified time zone,
- time-zone transitions (see \l {Daylight-Saving Time (DST)}{below}) are taken
- into account. A QDateTime's timeSpec() will tell you which of the four types
- of time representation is in use; its timeRepresentation() provides a full
- representation of that time representation, as a QTimeZone.
+ time-zone transitions (see \l {Timezone transitions}{below}) are taken into
+ account. A QDateTime's timeSpec() will tell you which of the four types of
+ time representation is in use; its timeRepresentation() provides a full
+ description of that time representation, as a QTimeZone.
A QDateTime object is typically created either by giving a date and time
explicitly in the constructor, or by using a static function such as
currentDateTime() or fromMSecsSinceEpoch(). The date and time can be changed
with setDate() and setTime(). A datetime can also be set using the
setMSecsSinceEpoch() function that takes the time, in milliseconds, since
- the start, in UTC of the year 1970. The fromString() function returns a
+ the start, in UTC, of the year 1970. The fromString() function returns a
QDateTime, given a string and a date format used to interpret the date
within the string.
@@ -3326,10 +3625,10 @@ QDateTime::Data QDateTimePrivate::create(QDate toDate, QTime toTime, const QTime
(whose \l {QTimeZone::timeSpec()}{timeSpec()} is \c {Qt::TimeZone}) to use
that instead.
- \note QDateTime does not account for leap seconds.
-
\section1 Remarks
+ \note QDateTime does not account for leap seconds.
+
\note All conversion to and from string formats is done using the C locale.
For localized conversions, see QLocale.
@@ -3337,15 +3636,21 @@ QDateTime::Data QDateTimePrivate::create(QDate toDate, QTime toTime, const QTime
considered invalid. The year -1 is the year "1 before Christ" or "1 before
common era." The day before 1 January 1 CE is 31 December 1 BCE.
+ \note Using local time (the default) or a specified time zone implies a need
+ to resolve any issues around \l {Timezone transitions}{transitions}. As a
+ result, operations on such QDateTime instances (notably including
+ constructing them) may be more expensive than the equivalent when using UTC
+ or a fixed offset from it.
+
\section2 Range of Valid Dates
The range of values that QDateTime can represent is dependent on the
internal storage implementation. QDateTime is currently stored in a qint64
as a serial msecs value encoding the date and time. This restricts the date
- range to about +/- 292 million years, compared to the QDate range of +/- 2
- billion years. Care must be taken when creating a QDateTime with extreme
- values that you do not overflow the storage. The exact range of supported
- values varies depending on the time representation used.
+ range to about ±292 million years, compared to the QDate range of ±2 billion
+ years. Care must be taken when creating a QDateTime with extreme values that
+ you do not overflow the storage. The exact range of supported values varies
+ depending on the time representation used.
\section2 Use of Timezones
@@ -3363,26 +3668,89 @@ QDateTime::Data QDateTimePrivate::create(QDate toDate, QTime toTime, const QTime
possible. On Windows, where the system doesn't support historical timezone
data, historical accuracy is not maintained with respect to timezone
transitions, notably including DST. However, building Qt with the ICU
- library will equipe QTimeZone with the same timezone database as is used on
+ library will equip QTimeZone with the same timezone database as is used on
Unix.
- \section2 Daylight-Saving Time (DST)
-
- QDateTime takes into account transitions between Standard Time and
- Daylight-Saving Time. For example, if the transition is at 2am and the clock
- goes forward to 3am, then there is a "missing" hour from 02:00:00 to
- 02:59:59.999 which QDateTime considers to be invalid. Any date arithmetic
- performed will take this missing hour into account and return a valid
- result. For example, adding one second to 01:59:59 will get 03:00:00.
+ \section2 Timezone transitions
+
+ QDateTime takes into account timezone transitions, both the transitions
+ between Standard Time and Daylight-Saving Time (DST) and the transitions
+ that arise when a zone changes its standard offset. For example, if the
+ transition is at 2am and the clock goes forward to 3am, then there is a
+ "missing" hour from 02:00:00 to 02:59:59.999. Such a transition is known as
+ a "spring forward" and the times skipped over have no meaning. When a
+ transition goes the other way, known as a "fall back", a time interval is
+ repeated, first in the old zone (usually DST), then in the new zone (usually
+ Standard Time), so times in this interval are ambiguous.
+
+ Some zones use "reversed" DST, using standard time in summer and
+ daylight-saving time (with a lowered offset) in winter. For such zones, the
+ spring forward still happens in spring and skips an hour, but is a
+ transition \e{out of} daylight-saving time, while the fall back still
+ repeats an autumn hour but is a transition \e to daylight-saving time.
+
+ When converting from a UTC time (or a time at fixed offset from UTC), there
+ is always an unambiguous valid result in any timezone. However, when
+ combining a date and time to make a datetime, expressed with respect to
+ local time or a specific time-zone, the nominal result may fall in a
+ transition, making it either invalid or ambiguous. Methods where this
+ situation may arise take a \c resolve parameter: this is always ignored if
+ the requested datetime is valid and unambiguous. See \l TransitionResolution
+ for the options it lets you control. Prior to Qt 6.7, the equivalent of its
+ \l LegacyBehavior was selected.
+
+ For a spring forward's skipped interval, interpreting the requested time
+ with either offset yields an actual time at which the other offset was in
+ use; so passing \c TransitionResolution::RelativeToBefore for \c resolve
+ will actually result in a time after the transition, that would have had the
+ requested representation had the transition not happened. Likewise, \c
+ TransitionResolution::RelativeToAfter for \c resolve results in a time
+ before the transition, that would have had the requested representation, had
+ the transition happened earlier.
+
+ When QDateTime performs arithmetic, as with addDay() or addSecs(), it takes
+ care to produce a valid result. For example, on a day when there is a spring
+ forward from 02:00 to 03:00, adding one second to 01:59:59 will get
+ 03:00:00. Adding one day to 02:30 on the preceding day will get 03:30 on the
+ day of the transition, while subtracting one day, by calling \c{addDay(-1)},
+ to 02:30 on the following day will get 01:30 on the day of the transition.
+ While addSecs() will deliver a time offset by the given number of seconds,
+ addDays() adjusts the date and only adjusts time if it would otherwise get
+ an invalid result. Applying \c{addDays(1)} to 03:00 on the day before the
+ spring-forward will simply get 03:00 on the day of the transition, even
+ though the latter is only 23 hours after the former; but \c{addSecs(24 * 60
+ * 60)} will get 04:00 on the day of the transition, since that's 24 hours
+ later. Typical transitions make some days 23 or 25 hours long.
For datetimes that the system \c time_t can represent (from 1901-12-14 to
2038-01-18 on systems with 32-bit \c time_t; for the full range QDateTime
can represent if the type is 64-bit), the standard system APIs are used to
determine local time's offset from UTC. For datetimes not handled by these
- system APIs, QTimeZone::systemTimeZone() is used. In either case, the offset
- information used depends on the system and may be incomplete or, for past
- times, historically inaccurate. In any case, for future dates, the local
- time zone's offsets and DST rules may change before that date comes around.
+ system APIs (potentially including some within the \c time_t range),
+ QTimeZone::systemTimeZone() is used, if available, or a best effort is made
+ to estimate. In any case, the offset information used depends on the system
+ and may be incomplete or, for past times, historically
+ inaccurate. Furthermore, for future dates, the local time zone's offsets and
+ DST rules may change before that date comes around.
+
+ \section3 Whole day transitions
+
+ A small number of zones have skipped or repeated entire days as part of
+ moving The International Date Line across themselves. For these, daysTo()
+ will be unaware of the duplication or gap, simply using the difference in
+ calendar date; in contrast, msecsTo() and secsTo() know the true time
+ interval. Likewise, addMSecs() and addSecs() correspond directly to elapsed
+ time, where addDays(), addMonths() and addYears() follow the nominal
+ calendar, aside from where landing in a gap or duplication requires
+ resolving an ambiguity or invalidity due to a duplication or omission.
+
+ \note Days "lost" during a change of calendar, such as from Julian to
+ Gregorian, do not affect QDateTime. Although the two calendars describe
+ dates differently, the successive days across the change are described by
+ consecutive QDate instances, each one day later than the previous, as
+ described by either calendar or by their toJulianDay() values. In contrast,
+ a zone skipping or duplicating a day is changing its description of \e time,
+ not date, for all that it does so by a whole 24 hours.
\section2 Offsets From UTC
@@ -3394,10 +3762,11 @@ QDateTime::Data QDateTimePrivate::create(QDate toDate, QTime toTime, const QTime
There is no explicit size restriction on an offset from UTC, but there is an
implicit limit imposed when using the toString() and fromString() methods
- which use a [+|-]hh:mm format, effectively limiting the range to +/- 99
- hours and 59 minutes and whole minutes only. Note that currently no time
- zone has an offset outside the range of ±14 hours and all known offsets are
- multiples of five minutes.
+ which use a ±hh:mm format, effectively limiting the range to ± 99 hours and
+ 59 minutes and whole minutes only. Note that currently no time zone has an
+ offset outside the range of ±14 hours and all known offsets are multiples of
+ five minutes. Historical time zones have a wider range and may have offsets
+ including seconds; these last cannot be faithfully represented in strings.
\sa QDate, QTime, QDateTimeEdit, QTimeZone
*/
@@ -3423,6 +3792,148 @@ QDateTime::Data QDateTimePrivate::create(QDate toDate, QTime toTime, const QTime
*/
/*!
+ \since 6.7
+ \enum QDateTime::TransitionResolution
+
+ This enumeration is used to resolve datetime combinations which fall in \l
+ {Timezone transitions}.
+
+ When constructing a datetime, specified in terms of local time or a
+ time-zone that has daylight-saving time, or revising one with setDate(),
+ setTime() or setTimeZone(), the given parameters may imply a time
+ representation that either has no meaning or has two meanings in the
+ zone. Such time representations are described as being in the transition. In
+ either case, we can simply return an invalid datetime, to indicate that the
+ operation is ill-defined. In the ambiguous case, we can alternatively select
+ one of the two times that could be meant. When there is no meaning, we can
+ select a time either side of it that might plausibly have been meant. For
+ example, when advancing from an earlier time, we can select the time after
+ the transition that is actually the specified amount of time after the
+ earlier time in question. The options specified here configure how such
+ selection is performed.
+
+ \value Reject
+ Treat any time in a transition as invalid. Either it really is, or it
+ is ambiguous.
+ \value RelativeToBefore
+ Selects a time as if stepping forward from a time before the
+ transition. This interprets the requested time using the offset in
+ effect before the transition and, if necessary, converts the result
+ to the offset in effect at the resulting time.
+ \value RelativeToAfter
+ Select a time as if stepping backward from a time after the
+ transition. This interprets the requested time using the offset in
+ effect after the transition and, if necessary, converts the result to
+ the offset in effect at the resulting time.
+ \value PreferBefore
+ Selects a time before the transition,
+ \value PreferAfter
+ Selects a time after the transition.
+ \value PreferStandard
+ Selects a time on the standard time side of the transition.
+ \value PreferDaylightSaving
+ Selects a time on the daylight-saving-time side of the transition.
+ \value LegacyBehavior
+ An alias for RelativeToBefore, which is used as default for
+ TransitionResolution parameters, as this most closely matches the
+ behavior prior to Qt 6.7.
+
+ For \l addDays(), \l addMonths() or \l addYears(), the behavior is and
+ (mostly) was to use \c RelativeToBefore if adding a positive adjustment and \c
+ RelativeToAfter if adding a negative adjustment.
+
+ \note In time zones where daylight-saving increases the offset from UTC in
+ summer (known as "positive DST"), PreferStandard is an alias for
+ RelativeToAfter and PreferDaylightSaving for RelativeToBefore. In time zones
+ where the daylight-saving mechanism is a decrease in offset from UTC in
+ winter (known as "negative DST"), the reverse applies, provided the
+ operating system reports - as it does on most platforms - whether a datetime
+ is in DST or standard time. For some platforms, where transition times are
+ unavailable even for Qt::TimeZone datetimes, QTimeZone is obliged to presume
+ that the side with lower offset from UTC is standard time, effectively
+ assuming positive DST.
+
+ The following tables illustrate how a QDateTime constructor resolves a
+ request for 02:30 on a day when local time has a transition between 02:00
+ and 03:00, with a nominal standard time LST and daylight-saving time LDT on
+ the two sides, in the various possible cases. The transition type may be to
+ skip an hour or repeat it. The type of transition and value of a parameter
+ \c resolve determine which actual time on the given date is selected. First,
+ the common case of positive daylight-saving, where:
+
+ \table
+ \header \li Before \li 02:00--03:00 \li After \li \c resolve \li selected
+ \row \li LST \li skip \li LDT \li RelativeToBefore \li 03:30 LDT
+ \row \li LST \li skip \li LDT \li RelativeToAfter \li 01:30 LST
+ \row \li LST \li skip \li LDT \li PreferBefore \li 01:30 LST
+ \row \li LST \li skip \li LDT \li PreferAfter \li 03:30 LDT
+ \row \li LST \li skip \li LDT \li PreferStandard \li 01:30 LST
+ \row \li LST \li skip \li LDT \li PreferDaylightSaving \li 03:30 LDT
+ \row \li LDT \li repeat \li LST \li RelativeToBefore \li 02:30 LDT
+ \row \li LDT \li repeat \li LST \li RelativeToAfter \li 02:30 LST
+ \row \li LDT \li repeat \li LST \li PreferBefore \li 02:30 LDT
+ \row \li LDT \li repeat \li LST \li PreferAfter \li 02:30 LST
+ \row \li LDT \li repeat \li LST \li PreferStandard \li 02:30 LST
+ \row \li LDT \li repeat \li LST \li PreferDaylightSaving \li 02:30 LDT
+ \endtable
+
+ Second, the case for negative daylight-saving, using LDT in winter and
+ skipping an hour to transition to LST in summer, then repeating an hour at
+ the transition back to winter:
+
+ \table
+ \row \li LDT \li skip \li LST \li RelativeToBefore \li 03:30 LST
+ \row \li LDT \li skip \li LST \li RelativeToAfter \li 01:30 LDT
+ \row \li LDT \li skip \li LST \li PreferBefore \li 01:30 LDT
+ \row \li LDT \li skip \li LST \li PreferAfter \li 03:30 LST
+ \row \li LDT \li skip \li LST \li PreferStandard \li 03:30 LST
+ \row \li LDT \li skip \li LST \li PreferDaylightSaving \li 01:30 LDT
+ \row \li LST \li repeat \li LDT \li RelativeToBefore \li 02:30 LST
+ \row \li LST \li repeat \li LDT \li RelativeToAfter \li 02:30 LDT
+ \row \li LST \li repeat \li LDT \li PreferBefore \li 02:30 LST
+ \row \li LST \li repeat \li LDT \li PreferAfter \li 02:30 LDT
+ \row \li LST \li repeat \li LDT \li PreferStandard \li 02:30 LST
+ \row \li LST \li repeat \li LDT \li PreferDaylightSaving \li 02:30 LDT
+ \endtable
+
+ Reject can be used to prompt relevant QDateTime APIs to return an invalid
+ datetime object so that your code can deal with transitions for itself, for
+ example by alerting a user to the fact that the datetime they have selected
+ is in a transition interval, to offer them the opportunity to resolve a
+ conflict or ambiguity. Code using this may well find the other options above
+ useful to determine relevant information to use in its own (or the user's)
+ resolution. If the start or end of the transition, or the moment of the
+ transition itself, is the right resolution, QTimeZone's transition APIs can
+ be used to obtain that information. You can determine whether the transition
+ is a repeated or skipped interval by using \l secsTo() to measure the actual
+ time between noon on the previous and following days. The result will be
+ less than 48 hours for a skipped interval (such as a spring-forward) and
+ more than 48 hours for a repeated interval (such as a fall-back).
+
+ \note When a resolution other than Reject is specified, a valid QDateTime
+ object is returned, if possible. If the requested date-time falls in a gap,
+ the returned date-time will not have the time() requested - or, in some
+ cases, the date(), if a whole day was skipped. You can thus detect when a
+ gap is hit by comparing date() and time() to what was requested.
+
+ \section2 Relation to other datetime software
+
+ The Python programming language's datetime APIs have a \c fold parameter
+ that corresponds to \c RelativeToBefore (\c{fold = True}) and \c
+ RelativeToAfter (\c{fold = False}).
+
+ The \c Temporal proposal to replace JavaScript's \c Date offers four options
+ for how to resolve a transition, as value for a \c disambiguation
+ parameter. Its \c{'reject'} raises an exception, which roughly corresponds
+ to \c Reject producing an invalid result. Its \c{'earlier'} and \c{'later'}
+ options correspond to \c PreferBefore and \c PreferAfter. Its
+ \c{'compatible'} option corresponds to \c RelativeToBefore (and Python's
+ \c{fold = True}).
+
+ \sa {Timezone transitions}, QDateTime::TransitionResolution
+*/
+
+/*!
Constructs a null datetime, nominally using local time.
A null datetime is invalid, since its date and time are invalid.
@@ -3460,7 +3971,8 @@ QDateTime::QDateTime() noexcept
skipped over the given date and time, the result is invalid.
*/
QDateTime::QDateTime(QDate date, QTime time, Qt::TimeSpec spec, int offsetSeconds)
- : d(QDateTimePrivate::create(date, time, asTimeZone(spec, offsetSeconds, "QDateTime")))
+ : d(QDateTimePrivate::create(date, time, asTimeZone(spec, offsetSeconds, "QDateTime"),
+ TransitionResolution::LegacyBehavior))
{
}
#endif // 6.9 deprecation
@@ -3472,24 +3984,36 @@ QDateTime::QDateTime(QDate date, QTime time, Qt::TimeSpec spec, int offsetSecond
representation described by \a timeZone.
If \a date is valid and \a time is not, the time will be set to midnight.
- If \a timeZone is invalid then the datetime will be invalid.
+ If \a timeZone is invalid then the datetime will be invalid. If \a date and
+ \a time describe a moment close to a transition for \a timeZone, \a resolve
+ controls how that situation is resolved.
+
+//! [pre-resolve-note]
+ \note Prior to Qt 6.7, the version of this function lacked the \a resolve
+ parameter so had no way to resolve the ambiguities related to transitions.
+//! [pre-resolve-note]
*/
-QDateTime::QDateTime(QDate date, QTime time, const QTimeZone &timeZone)
- : d(QDateTimePrivate::create(date, time, timeZone))
+QDateTime::QDateTime(QDate date, QTime time, const QTimeZone &timeZone, TransitionResolution resolve)
+ : d(QDateTimePrivate::create(date, time, timeZone, resolve))
{
}
/*!
\since 6.5
+ \overload
Constructs a datetime with the given \a date and \a time, using local time.
- If \a date is valid and \a time is not, midnight will be used as the time.
+ If \a date is valid and \a time is not, midnight will be used as the
+ time. If \a date and \a time describe a moment close to a transition for
+ local time, \a resolve controls how that situation is resolved.
+
+ \include qdatetime.cpp pre-resolve-note
*/
-QDateTime::QDateTime(QDate date, QTime time)
- : d(QDateTimePrivate::create(date, time, QTimeZone::LocalTime))
+QDateTime::QDateTime(QDate date, QTime time, TransitionResolution resolve)
+ : d(QDateTimePrivate::create(date, time, QTimeZone::LocalTime, resolve))
{
}
@@ -3670,16 +4194,18 @@ QTimeZone QDateTime::timeZone() const
int QDateTime::offsetFromUtc() const
{
+ const auto status = getStatus(d);
+ if (!status.testFlags(QDateTimePrivate::ValidDate | QDateTimePrivate::ValidTime))
+ return 0;
+ // But allow invalid date-time (e.g. gap's resolution) to report its offset.
if (!d.isShort())
return d->m_offsetFromUtc;
- if (!isValid())
- return 0;
- auto spec = getSpec(d);
+ auto spec = extractSpec(status);
if (spec == Qt::LocalTime) {
- // we didn't cache the value, so we need to calculate it now...
- qint64 msecs = getMSecs(d);
- return (msecs - toMSecsSinceEpoch()) / MSECS_PER_SEC;
+ // We didn't cache the value, so we need to calculate it:
+ const auto resolve = toTransitionOptions(extractDaylightStatus(status));
+ return QDateTimePrivate::localStateAtMillis(getMSecs(d), resolve).offset;
}
Q_ASSERT(spec == Qt::UTC);
@@ -3695,7 +4221,7 @@ int QDateTime::offsetFromUtc() const
\list
\li For Qt::UTC it is "UTC".
- \li For Qt::OffsetFromUTC it will be in the format "UTC[+-]00:00".
+ \li For Qt::OffsetFromUTC it will be in the format "UTC±00:00".
\li For Qt::LocalTime, the host system is queried.
\li For Qt::TimeZone, the associated QTimeZone object is queried.
\endlist
@@ -3764,8 +4290,10 @@ bool QDateTime::isDaylightTime() const
#endif // timezone
case Qt::LocalTime: {
auto dst = extractDaylightStatus(getStatus(d));
- if (dst == QDateTimePrivate::UnknownDaylightTime)
- dst = QDateTimePrivate::localStateAtMillis(getMSecs(d), dst).dst;
+ if (dst == QDateTimePrivate::UnknownDaylightTime) {
+ dst = QDateTimePrivate::localStateAtMillis(
+ getMSecs(d), toTransitionOptions(TransitionResolution::LegacyBehavior)).dst;
+ }
return dst == QDateTimePrivate::DaylightTime;
}
}
@@ -3773,16 +4301,24 @@ bool QDateTime::isDaylightTime() const
}
/*!
- Sets the date part of this datetime to \a date. If no time is set yet, it
- is set to midnight. If \a date is invalid, this QDateTime becomes invalid.
+ Sets the date part of this datetime to \a date.
+
+ If no time is set yet, it is set to midnight. If \a date is invalid, this
+ QDateTime becomes invalid.
+
+ If \a date and time() describe a moment close to a transition for this
+ datetime's time representation, \a resolve controls how that situation is
+ resolved.
+
+ \include qdatetime.cpp pre-resolve-note
\sa date(), setTime(), setTimeZone()
*/
-void QDateTime::setDate(QDate date)
+void QDateTime::setDate(QDate date, TransitionResolution resolve)
{
setDateTime(d, date, time());
- checkValidDateTime(d);
+ checkValidDateTime(d, resolve);
}
/*!
@@ -3795,13 +4331,19 @@ void QDateTime::setDate(QDate date)
dt.setTime(QTime());
\endcode
+ If date() and \a time describe a moment close to a transition for this
+ datetime's time representation, \a resolve controls how that situation is
+ resolved.
+
+ \include qdatetime.cpp pre-resolve-note
+
\sa time(), setDate(), setTimeZone()
*/
-void QDateTime::setTime(QTime time)
+void QDateTime::setTime(QTime time, TransitionResolution resolve)
{
setDateTime(d, date(), time);
- checkValidDateTime(d);
+ checkValidDateTime(d, resolve);
}
#if QT_DEPRECATED_SINCE(6, 9)
@@ -3825,7 +4367,8 @@ void QDateTime::setTime(QTime time)
void QDateTime::setTimeSpec(Qt::TimeSpec spec)
{
- reviseTimeZone(d, asTimeZone(spec, 0, "QDateTime::setTimeSpec"));
+ reviseTimeZone(d, asTimeZone(spec, 0, "QDateTime::setTimeSpec"),
+ TransitionResolution::LegacyBehavior);
}
/*!
@@ -3846,7 +4389,8 @@ void QDateTime::setTimeSpec(Qt::TimeSpec spec)
void QDateTime::setOffsetFromUtc(int offsetSeconds)
{
- reviseTimeZone(d, QTimeZone::fromSecondsAheadOfUtc(offsetSeconds));
+ reviseTimeZone(d, QTimeZone::fromSecondsAheadOfUtc(offsetSeconds),
+ TransitionResolution::Reject);
}
#endif // 6.9 deprecations
@@ -3862,12 +4406,17 @@ void QDateTime::setOffsetFromUtc(int offsetSeconds)
If \a toZone is invalid then the datetime will be invalid. Otherwise, this
datetime's timeSpec() after the call will match \c{toZone.timeSpec()}.
+ If date() and time() describe a moment close to a transition for \a toZone,
+ \a resolve controls how that situation is resolved.
+
+ \include qdatetime.cpp pre-resolve-note
+
\sa timeRepresentation(), timeZone(), Qt::TimeSpec
*/
-void QDateTime::setTimeZone(const QTimeZone &toZone)
+void QDateTime::setTimeZone(const QTimeZone &toZone, TransitionResolution resolve)
{
- reviseTimeZone(d, toZone);
+ reviseTimeZone(d, toZone, resolve);
}
/*!
@@ -3890,8 +4439,13 @@ qint64 QDateTime::toMSecsSinceEpoch() const
// Note: QDateTimeParser relies on this producing a useful result, even when
// !isValid(), at least when the invalidity is a time in a fall-back (that
// we'll have adjusted to lie outside it, but marked invalid because it's
- // not what was asked for). Other things may be doing similar.
- switch (getSpec(d)) {
+ // not what was asked for). Other things may be doing similar. But that's
+ // only relevant when we got enough data for resolution to find it invalid.
+ const auto status = getStatus(d);
+ if (!status.testFlags(QDateTimePrivate::ValidDate | QDateTimePrivate::ValidTime))
+ return 0;
+
+ switch (extractSpec(status)) {
case Qt::UTC:
return getMSecs(d);
@@ -3900,10 +4454,10 @@ qint64 QDateTime::toMSecsSinceEpoch() const
return d->m_msecs - d->m_offsetFromUtc * MSECS_PER_SEC;
case Qt::LocalTime:
- if (d.isShort()) {
+ if (status.testFlag(QDateTimePrivate::ShortData)) {
// Short form has nowhere to cache the offset, so recompute.
- auto dst = extractDaylightStatus(getStatus(d));
- auto state = QDateTimePrivate::localStateAtMillis(getMSecs(d), dst);
+ const auto resolve = toTransitionOptions(extractDaylightStatus(getStatus(d)));
+ const auto state = QDateTimePrivate::localStateAtMillis(getMSecs(d), resolve);
return state.when - state.offset * MSECS_PER_SEC;
}
// Use the offset saved by refreshZonedDateTime() on creation.
@@ -3967,7 +4521,7 @@ void QDateTime::setMSecsSinceEpoch(qint64 msecs)
if (QTimeZone::isUtcOrFixedOffset(spec)) {
if (spec == Qt::OffsetFromUTC)
state.offset = d->m_offsetFromUtc;
- if (!state.offset || !add_overflow(msecs, state.offset * MSECS_PER_SEC, &state.when))
+ if (!state.offset || !qAddOverflow(msecs, state.offset * MSECS_PER_SEC, &state.when))
status |= QDateTimePrivate::ValidityMask;
} else if (spec == Qt::LocalTime) {
state = QDateTimePrivate::expressUtcAsLocal(msecs);
@@ -3980,7 +4534,7 @@ void QDateTime::setMSecsSinceEpoch(qint64 msecs)
state.offset = data.offsetFromUtc;
Q_ASSERT(state.offset >= -SECS_PER_DAY && state.offset <= SECS_PER_DAY);
if (!state.offset
- || !Q_UNLIKELY(add_overflow(msecs, state.offset * MSECS_PER_SEC, &state.when))) {
+ || !Q_UNLIKELY(qAddOverflow(msecs, state.offset * MSECS_PER_SEC, &state.when))) {
d->m_status = mergeDaylightStatus(status | QDateTimePrivate::ValidityMask,
data.daylightTimeOffset
? QDateTimePrivate::DaylightTime
@@ -4021,14 +4575,10 @@ void QDateTime::setMSecsSinceEpoch(qint64 msecs)
void QDateTime::setSecsSinceEpoch(qint64 secs)
{
qint64 msecs;
- if (!mul_overflow(secs, std::integral_constant<qint64, MSECS_PER_SEC>(), &msecs)) {
+ if (!qMulOverflow(secs, std::integral_constant<qint64, MSECS_PER_SEC>(), &msecs))
setMSecsSinceEpoch(msecs);
- } else if (d.isShort()) {
- d.data.status &= ~int(QDateTimePrivate::ValidityMask);
- } else {
- d.detach();
- d->m_status &= ~QDateTimePrivate::ValidityMask;
- }
+ else
+ d.invalidate();
}
#if QT_CONFIG(datestring) // depends on, so implies, textdate
@@ -4042,15 +4592,14 @@ void QDateTime::setSecsSinceEpoch(qint64 secs)
formatting is "Wed May 20 03:40:13 1998". For localized formatting, see
\l{QLocale::toString()}.
- If the \a format is Qt::ISODate, the string format corresponds
- to the ISO 8601 extended specification for representations of
- dates and times, taking the form yyyy-MM-ddTHH:mm:ss[Z|[+|-]HH:mm],
- depending on the timeSpec() of the QDateTime. If the timeSpec()
- is Qt::UTC, Z will be appended to the string; if the timeSpec() is
- Qt::OffsetFromUTC, the offset in hours and minutes from UTC will
- be appended to the string. To include milliseconds in the ISO 8601
+ If the \a format is Qt::ISODate, the string format corresponds to the ISO
+ 8601 extended specification for representations of dates and times, taking
+ the form yyyy-MM-ddTHH:mm:ss[Z|±HH:mm], depending on the timeSpec() of the
+ QDateTime. If the timeSpec() is Qt::UTC, Z will be appended to the string;
+ if the timeSpec() is Qt::OffsetFromUTC, the offset in hours and minutes from
+ UTC will be appended to the string. To include milliseconds in the ISO 8601
date, use the \a format Qt::ISODateWithMs, which corresponds to
- yyyy-MM-ddTHH:mm:ss.zzz[Z|[+|-]HH:mm].
+ yyyy-MM-ddTHH:mm:ss.zzz[Z|±HH:mm].
If the \a format is Qt::RFC2822Date, the string is formatted
following \l{RFC 2822}.
@@ -4076,7 +4625,7 @@ QString QDateTime::toString(Qt::DateFormat format) const
return buf;
default:
case Qt::TextDate: {
- const QPair<QDate, QTime> p = getDateTime(d);
+ const std::pair<QDate, QTime> p = getDateTime(d);
buf = toStringTextDate(p.first);
// Insert time between date's day and year:
buf.insert(buf.lastIndexOf(u' '),
@@ -4104,7 +4653,7 @@ QString QDateTime::toString(Qt::DateFormat format) const
}
case Qt::ISODate:
case Qt::ISODateWithMs: {
- const QPair<QDate, QTime> p = getDateTime(d);
+ const std::pair<QDate, QTime> p = getDateTime(d);
buf = toStringIsoDate(p.first);
if (buf.isEmpty())
return QString(); // failed to convert
@@ -4128,12 +4677,14 @@ QString QDateTime::toString(Qt::DateFormat format) const
/*!
\fn QString QDateTime::toString(const QString &format, QCalendar cal) const
\fn QString QDateTime::toString(QStringView format, QCalendar cal) const
+ \since 5.14
Returns the datetime as a string. The \a format parameter determines the
- format of the result string. If \a cal is supplied, it determines the calendar
- used to represent the date; it defaults to Gregorian. See QTime::toString()
- and QDate::toString() for the supported specifiers for time and date,
- respectively.
+ format of the result string. If \a cal is supplied, it determines the
+ calendar used to represent the date; it defaults to Gregorian. Prior to Qt
+ 5.14, there was no \a cal parameter and the Gregorian calendar was always
+ used. See QTime::toString() and QDate::toString() for the supported
+ specifiers for time and date, respectively, in the \a format parameter.
Any sequence of characters enclosed in single quotes will be included
verbatim in the output string (stripped of the quotes), even if it contains
@@ -4170,21 +4721,32 @@ QString QDateTime::toString(QStringView format, QCalendar cal) const
{
return QLocale::c().toString(*this, format, cal);
}
+
+// Out-of-line no-calendar overloads, since QCalendar is a non-trivial type
+/*!
+ \overload
+ \since 5.10
+*/
+QString QDateTime::toString(QStringView format) const
+{
+ return QLocale::c().toString(*this, format, QCalendar());
+}
+
+/*!
+ \overload
+ \since 4.6
+*/
+QString QDateTime::toString(const QString &format) const
+{
+ return QLocale::c().toString(*this, qToStringViewIgnoringNull(format), QCalendar());
+}
#endif // datestring
-static inline void massageAdjustedDateTime(QDateTimeData &d, QDate date, QTime time)
-{
- /*
- If we have just adjusted to a day with a DST transition, our given time
- may lie in the transition hour (either missing or duplicated). For any
- other time, telling mktime() or QTimeZone what we know about DST-ness, of
- the time we adjusted from, will make no difference; it'll just tell us the
- actual DST-ness of the given time. When landing in a transition that
- repeats an hour, passing the prior DST-ness - when known - will get us the
- indicated side of the duplicate (either local or zone). When landing in a
- gap, the zone gives us the other side of the gap and mktime() is wrapped
- to coax it into doing the same (which it does by default on Unix).
- */
+static inline void massageAdjustedDateTime(QDateTimeData &d, QDate date, QTime time, bool forward)
+{
+ const QDateTimePrivate::TransitionOptions resolve = toTransitionOptions(
+ forward ? QDateTime::TransitionResolution::RelativeToBefore
+ : QDateTime::TransitionResolution::RelativeToAfter);
auto status = getStatus(d);
Q_ASSERT(status.testFlags(QDateTimePrivate::ValidDate | QDateTimePrivate::ValidTime
| QDateTimePrivate::ValidDateTime));
@@ -4194,13 +4756,13 @@ static inline void massageAdjustedDateTime(QDateTimeData &d, QDate date, QTime t
refreshSimpleDateTime(d);
return;
}
- auto dst = extractDaylightStatus(status);
qint64 local = timeToMSecs(date, time);
- const QDateTimePrivate::ZoneState state = stateAtMillis(d.timeZone(), local, dst);
- if (state.valid)
- status = mergeDaylightStatus(status | QDateTimePrivate::ValidDateTime, state.dst);
- else
+ const QDateTimePrivate::ZoneState state = stateAtMillis(d.timeZone(), local, resolve);
+ Q_ASSERT(state.valid || state.dst == QDateTimePrivate::UnknownDaylightTime);
+ if (state.dst == QDateTimePrivate::UnknownDaylightTime)
status.setFlag(QDateTimePrivate::ValidDateTime, false);
+ else
+ status = mergeDaylightStatus(status | QDateTimePrivate::ValidDateTime, state.dst);
if (status & QDateTimePrivate::ShortData) {
d.data.msecs = state.when;
@@ -4220,13 +4782,14 @@ static inline void massageAdjustedDateTime(QDateTimeData &d, QDate date, QTime t
later than the datetime of this object (or earlier if \a ndays is
negative).
- If the timeSpec() is Qt::LocalTime or Qt::TimeZone and the resulting
- date and time fall in the Standard Time to Daylight-Saving Time transition
- hour then the result will be adjusted accordingly, i.e. if the transition
- is at 2am and the clock goes forward to 3am and the result falls between
- 2am and 3am then the result will be adjusted to fall after 3am.
+ If the timeSpec() is Qt::LocalTime or Qt::TimeZone and the resulting date
+ and time fall in the Standard Time to Daylight-Saving Time transition hour
+ then the result will be just beyond this gap, in the direction of change.
+ If the transition is at 2am and the clock goes forward to 3am, the result of
+ aiming between 2am and 3am will be adjusted to fall before 2am (if \c{ndays
+ < 0}) or after 3am (otherwise).
- \sa daysTo(), addMonths(), addYears(), addSecs()
+ \sa daysTo(), addMonths(), addYears(), addSecs(), {Timezone transitions}
*/
QDateTime QDateTime::addDays(qint64 ndays) const
@@ -4235,8 +4798,8 @@ QDateTime QDateTime::addDays(qint64 ndays) const
return QDateTime();
QDateTime dt(*this);
- QPair<QDate, QTime> p = getDateTime(d);
- massageAdjustedDateTime(dt.d, p.first.addDays(ndays), p.second);
+ std::pair<QDate, QTime> p = getDateTime(d);
+ massageAdjustedDateTime(dt.d, p.first.addDays(ndays), p.second, ndays >= 0);
return dt;
}
@@ -4245,13 +4808,14 @@ QDateTime QDateTime::addDays(qint64 ndays) const
later than the datetime of this object (or earlier if \a nmonths
is negative).
- If the timeSpec() is Qt::LocalTime or Qt::TimeZone and the resulting
- date and time fall in the Standard Time to Daylight-Saving Time transition
- hour then the result will be adjusted accordingly, i.e. if the transition
- is at 2am and the clock goes forward to 3am and the result falls between
- 2am and 3am then the result will be adjusted to fall after 3am.
+ If the timeSpec() is Qt::LocalTime or Qt::TimeZone and the resulting date
+ and time fall in the Standard Time to Daylight-Saving Time transition hour
+ then the result will be just beyond this gap, in the direction of change.
+ If the transition is at 2am and the clock goes forward to 3am, the result of
+ aiming between 2am and 3am will be adjusted to fall before 2am (if
+ \c{nmonths < 0}) or after 3am (otherwise).
- \sa daysTo(), addDays(), addYears(), addSecs()
+ \sa daysTo(), addDays(), addYears(), addSecs(), {Timezone transitions}
*/
QDateTime QDateTime::addMonths(int nmonths) const
@@ -4260,8 +4824,8 @@ QDateTime QDateTime::addMonths(int nmonths) const
return QDateTime();
QDateTime dt(*this);
- QPair<QDate, QTime> p = getDateTime(d);
- massageAdjustedDateTime(dt.d, p.first.addMonths(nmonths), p.second);
+ std::pair<QDate, QTime> p = getDateTime(d);
+ massageAdjustedDateTime(dt.d, p.first.addMonths(nmonths), p.second, nmonths >= 0);
return dt;
}
@@ -4270,13 +4834,14 @@ QDateTime QDateTime::addMonths(int nmonths) const
later than the datetime of this object (or earlier if \a nyears is
negative).
- If the timeSpec() is Qt::LocalTime or Qt::TimeZone and the resulting
- date and time fall in the Standard Time to Daylight-Saving Time transition
- hour then the result will be adjusted accordingly, i.e. if the transition
- is at 2am and the clock goes forward to 3am and the result falls between
- 2am and 3am then the result will be adjusted to fall after 3am.
+ If the timeSpec() is Qt::LocalTime or Qt::TimeZone and the resulting date
+ and time fall in the Standard Time to Daylight-Saving Time transition hour
+ then the result will be just beyond this gap, in the direction of change.
+ If the transition is at 2am and the clock goes forward to 3am, the result of
+ aiming between 2am and 3am will be adjusted to fall before 2am (if \c{nyears
+ < 0}) or after 3am (otherwise).
- \sa daysTo(), addDays(), addMonths(), addSecs()
+ \sa daysTo(), addDays(), addMonths(), addSecs(), {Timezone transitions}
*/
QDateTime QDateTime::addYears(int nyears) const
@@ -4285,8 +4850,8 @@ QDateTime QDateTime::addYears(int nyears) const
return QDateTime();
QDateTime dt(*this);
- QPair<QDate, QTime> p = getDateTime(d);
- massageAdjustedDateTime(dt.d, p.first.addYears(nyears), p.second);
+ std::pair<QDate, QTime> p = getDateTime(d);
+ massageAdjustedDateTime(dt.d, p.first.addYears(nyears), p.second, nyears >= 0);
return dt;
}
@@ -4303,7 +4868,7 @@ QDateTime QDateTime::addYears(int nyears) const
QDateTime QDateTime::addSecs(qint64 s) const
{
qint64 msecs;
- if (mul_overflow(s, std::integral_constant<qint64, MSECS_PER_SEC>(), &msecs))
+ if (qMulOverflow(s, std::integral_constant<qint64, MSECS_PER_SEC>(), &msecs))
return QDateTime();
return addMSecs(msecs);
}
@@ -4327,33 +4892,18 @@ QDateTime QDateTime::addMSecs(qint64 msecs) const
case Qt::LocalTime:
case Qt::TimeZone:
// Convert to real UTC first in case this crosses a DST transition:
- if (!add_overflow(toMSecsSinceEpoch(), msecs, &msecs)) {
+ if (!qAddOverflow(toMSecsSinceEpoch(), msecs, &msecs))
dt.setMSecsSinceEpoch(msecs);
- } else if (dt.d.isShort()) {
- dt.d.data.status &= ~int(QDateTimePrivate::ValidityMask);
- } else {
- dt.d.detach();
- dt.d->m_status &= ~QDateTimePrivate::ValidityMask;
- }
+ else
+ dt.d.invalidate();
break;
case Qt::UTC:
case Qt::OffsetFromUTC:
// No need to convert, just add on
- if (add_overflow(getMSecs(d), msecs, &msecs)) {
- if (dt.d.isShort()) {
- dt.d.data.status &= ~int(QDateTimePrivate::ValidityMask);
- } else {
- dt.d.detach();
- dt.d->m_status &= ~QDateTimePrivate::ValidityMask;
- }
- } else if (d.isShort()) {
- // need to check if we need to enlarge first
- if (msecsCanBeSmall(msecs)) {
- dt.d.data.msecs = qintptr(msecs);
- } else {
- dt.d.detach();
- dt.d->m_msecs = msecs;
- }
+ if (qAddOverflow(getMSecs(d), msecs, &msecs)) {
+ dt.d.invalidate();
+ } else if (d.isShort() && msecsCanBeSmall(msecs)) {
+ dt.d.data.msecs = qintptr(msecs);
} else {
dt.d.detach();
dt.d->m_msecs = msecs;
@@ -4651,11 +5201,20 @@ bool QDateTime::equals(const QDateTime &other) const
/*!
\fn bool QDateTime::operator==(const QDateTime &lhs, const QDateTime &rhs)
- Returns \c true if \a lhs is the same as \a rhs; otherwise returns \c false.
+ Returns \c true if \a lhs represents the same moment in time as \a rhs;
+ otherwise returns \c false.
+
+//! [datetime-order-details]
+ Two datetimes using different time representations can have different
+ offsets from UTC. In this case, they may compare equivalent even if their \l
+ date() and \l time() differ, if that difference matches the difference in
+ UTC offset. If their \c date() and \c time() coincide, the one with higher
+ offset from UTC is less (earlier) than the one with lower offset. As a
+ result, datetimes are only weakly ordered.
- Two datetimes are different if either the date, the time, or the time zone
- components are different. Since 5.14, all invalid datetime are equal (and
- less than all valid datetimes).
+ Since 5.14, all invalid datetimes are equivalent and less than all valid
+ datetimes.
+//! [datetime-order-details]
\sa operator!=(), operator<(), operator<=(), operator>(), operator>=()
*/
@@ -4666,33 +5225,24 @@ bool QDateTime::equals(const QDateTime &other) const
Returns \c true if \a lhs is different from \a rhs; otherwise returns \c
false.
- Two datetimes are different if either the date, the time, or the time zone
- components are different. Since 5.14, all invalid datetime are equal (and
- less than all valid datetimes).
+ \include qdatetime.cpp datetime-order-details
\sa operator==()
*/
-/*!
- \internal
- Returns \c true if \a lhs is earlier than the \a rhs
- datetime; otherwise returns \c false.
-
- \sa equals(), operator<()
-*/
-
-bool QDateTime::precedes(const QDateTime &other) const
+Qt::weak_ordering compareThreeWay(const QDateTime &lhs, const QDateTime &rhs)
{
- if (!isValid())
- return other.isValid();
- if (!other.isValid())
- return false;
+ if (!lhs.isValid())
+ return rhs.isValid() ? Qt::weak_ordering::less : Qt::weak_ordering::equivalent;
- if (usesSameOffset(d, other.d))
- return getMSecs(d) < getMSecs(other.d);
+ if (!rhs.isValid())
+ return Qt::weak_ordering::greater; // we know that lhs is valid here
+
+ if (usesSameOffset(lhs.d, rhs.d))
+ return Qt::compareThreeWay(getMSecs(lhs.d), getMSecs(rhs.d));
// Convert to UTC and compare
- return toMSecsSinceEpoch() < other.toMSecsSinceEpoch();
+ return Qt::compareThreeWay(lhs.toMSecsSinceEpoch(), rhs.toMSecsSinceEpoch());
}
/*!
@@ -4701,6 +5251,8 @@ bool QDateTime::precedes(const QDateTime &other) const
Returns \c true if \a lhs is earlier than \a rhs;
otherwise returns \c false.
+ \include qdatetime.cpp datetime-order-details
+
\sa operator==()
*/
@@ -4710,6 +5262,8 @@ bool QDateTime::precedes(const QDateTime &other) const
Returns \c true if \a lhs is earlier than or equal to \a rhs; otherwise
returns \c false.
+ \include qdatetime.cpp datetime-order-details
+
\sa operator==()
*/
@@ -4718,6 +5272,8 @@ bool QDateTime::precedes(const QDateTime &other) const
Returns \c true if \a lhs is later than \a rhs; otherwise returns \c false.
+ \include qdatetime.cpp datetime-order-details
+
\sa operator==()
*/
@@ -4727,6 +5283,8 @@ bool QDateTime::precedes(const QDateTime &other) const
Returns \c true if \a lhs is later than or equal to \a rhs;
otherwise returns \c false.
+ \include qdatetime.cpp datetime-order-details
+
\sa operator==()
*/
@@ -4925,7 +5483,7 @@ qint64 QDateTime::currentSecsSinceEpoch() noexcept
daysAfterEpoch * SECS_PER_DAY;
}
-#elif defined(Q_OS_UNIX)
+#elif defined(Q_OS_UNIX) // Assume POSIX-compliant
QDate QDate::currentDate()
{
return QDateTime::currentDateTime().date();
@@ -4943,18 +5501,18 @@ QDateTime QDateTime::currentDateTime(const QTimeZone &zone)
qint64 QDateTime::currentMSecsSinceEpoch() noexcept
{
- // posix compliant system
- // we have milliseconds
- struct timeval tv;
- gettimeofday(&tv, nullptr);
- return tv.tv_sec * MSECS_PER_SEC + tv.tv_usec / 1000;
+ struct timespec when;
+ if (clock_gettime(CLOCK_REALTIME, &when) == 0) // should always succeed
+ return when.tv_sec * MSECS_PER_SEC + (when.tv_nsec + 500'000) / 1'000'000;
+ Q_UNREACHABLE_RETURN(0);
}
qint64 QDateTime::currentSecsSinceEpoch() noexcept
{
- struct timeval tv;
- gettimeofday(&tv, nullptr);
- return tv.tv_sec;
+ struct timespec when;
+ if (clock_gettime(CLOCK_REALTIME, &when) == 0) // should always succeed
+ return when.tv_sec;
+ Q_UNREACHABLE_RETURN(0);
}
#else
#error "What system is this?"
@@ -5022,7 +5580,6 @@ QDateTime QDateTime::fromSecsSinceEpoch(qint64 secs, Qt::TimeSpec spec, int offs
/*!
\since 5.2
- \overload
Returns a datetime representing a moment the given number \a msecs of
milliseconds after the start, in UTC, of the year 1970, described as
@@ -5037,7 +5594,7 @@ QDateTime QDateTime::fromSecsSinceEpoch(qint64 secs, Qt::TimeSpec spec, int offs
QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone)
{
QDateTime dt;
- reviseTimeZone(dt.d, timeZone);
+ reviseTimeZone(dt.d, timeZone, TransitionResolution::Reject);
if (timeZone.isValid())
dt.setMSecsSinceEpoch(msecs);
return dt;
@@ -5054,7 +5611,6 @@ QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs)
/*!
\since 5.8
- \overload
Returns a datetime representing a moment the given number \a secs of seconds
after the start, in UTC, of the year 1970, described as specified by \a
@@ -5069,7 +5625,7 @@ QDateTime QDateTime::fromMSecsSinceEpoch(qint64 msecs)
QDateTime QDateTime::fromSecsSinceEpoch(qint64 secs, const QTimeZone &timeZone)
{
QDateTime dt;
- reviseTimeZone(dt.d, timeZone);
+ reviseTimeZone(dt.d, timeZone, TransitionResolution::Reject);
if (timeZone.isValid())
dt.setSecsSinceEpoch(secs);
return dt;
@@ -5144,7 +5700,7 @@ QDateTime QDateTime::fromString(QStringView string, Qt::DateFormat format)
}
isoString = isoString.sliced(1); // trim 'T' (or space)
- // Check end of string for Time Zone definition, either Z for UTC or [+-]HH:mm for Offset
+ // Check end of string for Time Zone definition, either Z for UTC or ±HH:mm for Offset
if (isoString.endsWith(u'Z', Qt::CaseInsensitive)) {
zone = QTimeZone::UTC;
isoString.chop(1); // trim 'Z'
@@ -5241,13 +5797,15 @@ QDateTime QDateTime::fromString(QStringView string, Qt::DateFormat format)
}
/*!
- \fn QDateTime QDateTime::fromString(const QString &string, const QString &format, QCalendar cal)
+ \fn QDateTime QDateTime::fromString(const QString &string, const QString &format, int baseYear, QCalendar cal)
Returns the QDateTime represented by the \a string, using the \a
format given, or an invalid datetime if the string cannot be parsed.
Uses the calendar \a cal if supplied, else Gregorian.
+ \include qlocale.cpp base-year-for-two-digit
+
In addition to the expressions, recognized in the format string to represent
parts of the date and time, by QDate::fromString() and QTime::fromString(),
this method supports:
@@ -5283,10 +5841,8 @@ QDateTime QDateTime::fromString(QStringView string, Qt::DateFormat format)
If the format is not satisfied, an invalid QDateTime is returned. If the
format is satisfied but \a string represents an invalid datetime (e.g. in a
- gap skipped by a time-zone transition), an invalid QDateTime is returned,
- whose toMSecsSinceEpoch() represents a near-by datetime that is
- valid. Passing that to fromMSecsSinceEpoch() will produce a valid datetime
- that isn't faithfully represented by the string parsed.
+ gap skipped by a time-zone transition), an valid QDateTime is returned, that
+ represents a near-by datetime that is valid.
The expressions that don't have leading zeroes (d, M, h, m, s, z) will be
greedy. This means that they will use two digits (or three, for z) even if this will
@@ -5337,23 +5893,71 @@ QDateTime QDateTime::fromString(QStringView string, Qt::DateFormat format)
\overload
\since 6.0
*/
-QDateTime QDateTime::fromString(const QString &string, QStringView format, QCalendar cal)
+QDateTime QDateTime::fromString(const QString &string, QStringView format, int baseYear,
+ QCalendar cal)
{
#if QT_CONFIG(datetimeparser)
QDateTime datetime;
QDateTimeParser dt(QMetaType::QDateTime, QDateTimeParser::FromString, cal);
dt.setDefaultLocale(QLocale::c());
- if (dt.parseFormat(format) && (dt.fromString(string, &datetime) || !datetime.isValid()))
+ if (dt.parseFormat(format) && (dt.fromString(string, &datetime, baseYear)
+ || !datetime.isValid())) {
return datetime;
+ }
#else
Q_UNUSED(string);
Q_UNUSED(format);
+ Q_UNUSED(baseYear);
Q_UNUSED(cal);
#endif
return QDateTime();
}
+/*!
+ \fn QDateTime QDateTime::fromString(const QString &string, const QString &format, QCalendar cal)
+ \overload
+ \since 5.14
+*/
+
+/*!
+ \fn QDateTime QDateTime::fromString(const QString &string, QStringView format, QCalendar cal)
+ \overload
+ \since 6.0
+*/
+
+/*!
+ \fn QDateTime QDateTime::fromString(QStringView string, QStringView format, int baseYear, QCalendar cal)
+ \overload
+ \since 6.7
+*/
+
+/*!
+ \fn QDateTime QDateTime::fromString(QStringView string, QStringView format, int baseYear)
+ \overload
+ \since 6.7
+
+ Uses a default-constructed QCalendar.
+*/
+
+/*!
+ \overload
+ \since 6.7
+
+ Uses a default-constructed QCalendar.
+*/
+QDateTime QDateTime::fromString(const QString &string, QStringView format, int baseYear)
+{
+ return fromString(string, format, baseYear, QCalendar());
+}
+
+/*!
+ \fn QDateTime QDateTime::fromString(const QString &string, const QString &format, int baseYear)
+ \overload
+ \since 6.7
+
+ Uses a default-constructed QCalendar.
+*/
#endif // datestring
/*****************************************************************************
@@ -5447,7 +6051,7 @@ QDataStream &operator>>(QDataStream &in, QTime &time)
*/
QDataStream &operator<<(QDataStream &out, const QDateTime &dateTime)
{
- QPair<QDate, QTime> dateAndTime;
+ std::pair<QDate, QTime> dateAndTime;
// TODO: new version, route spec and details via QTimeZone
if (out.version() >= QDataStream::Qt_5_2) {
@@ -5537,6 +6141,7 @@ QDataStream &operator>>(QDataStream &in, QDateTime &dateTime)
in >> zone;
break;
}
+ // Note: no way to resolve transition ambiguity, when relevant; use default.
dateTime = QDateTime(dt, tm, zone);
} else if (in.version() == QDataStream::Qt_5_0) {
@@ -5586,7 +6191,11 @@ QDebug operator<<(QDebug dbg, QDate date)
QDebugStateSaver saver(dbg);
dbg.nospace() << "QDate(";
if (date.isValid())
- dbg.nospace() << date.toString(Qt::ISODate);
+ // QTBUG-91070, ISODate only supports years in the range 0-9999
+ if (int y = date.year(); y > 0 && y <= 9999)
+ dbg.nospace() << date.toString(Qt::ISODate);
+ else
+ dbg.nospace() << date.toString(Qt::TextDate);
else
dbg.nospace() << "Invalid";
dbg.nospace() << ')';
diff --git a/src/corelib/time/qdatetime.h b/src/corelib/time/qdatetime.h
index 5f41fa470a..e1c0d29e2a 100644
--- a/src/corelib/time/qdatetime.h
+++ b/src/corelib/time/qdatetime.h
@@ -6,6 +6,8 @@
#define QDATETIME_H
#include <QtCore/qcalendar.h>
+#include <QtCore/qcompare.h>
+#include <QtCore/qlocale.h>
#include <QtCore/qnamespace.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qstring.h>
@@ -32,53 +34,36 @@ public:
QDate(int y, int m, int d, QCalendar cal);
#if __cpp_lib_chrono >= 201907L || defined(Q_QDOC)
QT_POST_CXX17_API_IN_EXPORTED_CLASS
- Q_IMPLICIT QDate(std::chrono::year_month_day ymd)
- {
- if (!ymd.ok())
- jd = nullJd();
- else
- *this = fromStdSysDays(ymd);
- }
+ Q_IMPLICIT constexpr QDate(std::chrono::year_month_day date) noexcept
+ : jd(date.ok() ? stdSysDaysToJulianDay(date) : nullJd())
+ {}
QT_POST_CXX17_API_IN_EXPORTED_CLASS
- Q_IMPLICIT QDate(std::chrono::year_month_day_last ymdl)
- {
- if (!ymdl.ok())
- jd = nullJd();
- else
- *this = fromStdSysDays(ymdl);
- }
+ Q_IMPLICIT constexpr QDate(std::chrono::year_month_day_last date) noexcept
+ : jd(date.ok() ? stdSysDaysToJulianDay(date) : nullJd())
+ {}
QT_POST_CXX17_API_IN_EXPORTED_CLASS
- Q_IMPLICIT QDate(std::chrono::year_month_weekday ymw)
- {
- if (!ymw.ok())
- jd = nullJd();
- else
- *this = fromStdSysDays(ymw);
- }
+ Q_IMPLICIT constexpr QDate(std::chrono::year_month_weekday date) noexcept
+ : jd(date.ok() ? stdSysDaysToJulianDay(date) : nullJd())
+ {}
QT_POST_CXX17_API_IN_EXPORTED_CLASS
- Q_IMPLICIT QDate(std::chrono::year_month_weekday_last ymwl)
- {
- if (!ymwl.ok())
- jd = nullJd();
- else
- *this = fromStdSysDays(ymwl);
- }
+ Q_IMPLICIT constexpr QDate(std::chrono::year_month_weekday_last date) noexcept
+ : jd(date.ok() ? stdSysDaysToJulianDay(date) : nullJd())
+ {}
QT_POST_CXX17_API_IN_EXPORTED_CLASS
- static QDate fromStdSysDays(const std::chrono::sys_days &days)
+ static constexpr QDate fromStdSysDays(const std::chrono::sys_days &days) noexcept
{
- const QDate epoch(unixEpochJd());
- return epoch.addDays(days.time_since_epoch().count());
+ return QDate(stdSysDaysToJulianDay(days));
}
QT_POST_CXX17_API_IN_EXPORTED_CLASS
- std::chrono::sys_days toStdSysDays() const
+ constexpr std::chrono::sys_days toStdSysDays() const noexcept
{
- const QDate epoch(unixEpochJd());
- return std::chrono::sys_days(std::chrono::days(epoch.daysTo(*this)));
+ const qint64 days = isValid() ? jd - unixEpochJd() : 0;
+ return std::chrono::sys_days(std::chrono::days(days));
}
#endif
@@ -117,9 +102,11 @@ public:
#if QT_CONFIG(datestring)
QString toString(Qt::DateFormat format = Qt::TextDate) const;
- QString toString(const QString &format, QCalendar cal = QCalendar()) const
+ QString toString(const QString &format) const;
+ QString toString(const QString &format, QCalendar cal) const
{ return toString(qToStringViewIgnoringNull(format), cal); }
- QString toString(QStringView format, QCalendar cal = QCalendar()) const;
+ QString toString(QStringView format) const;
+ QString toString(QStringView format, QCalendar cal) const;
#endif
bool setDate(int year, int month, int day); // Gregorian-optimized
bool setDate(int year, int month, int day, QCalendar cal);
@@ -143,15 +130,37 @@ public:
static QDate currentDate();
#if QT_CONFIG(datestring)
+ // No DateFormat accepts a two-digit year, so no need for baseYear:
static QDate fromString(QStringView string, Qt::DateFormat format = Qt::TextDate);
- static QDate fromString(QStringView string, QStringView format, QCalendar cal = QCalendar())
- { return fromString(string.toString(), format, cal); }
- static QDate fromString(const QString &string, QStringView format, QCalendar cal = QCalendar());
static QDate fromString(const QString &string, Qt::DateFormat format = Qt::TextDate)
{ return fromString(qToStringViewIgnoringNull(string), format); }
+
+ // Accept calendar without over-ride of base year:
+ static QDate fromString(QStringView string, QStringView format, QCalendar cal)
+ { return fromString(string.toString(), format, QLocale::DefaultTwoDigitBaseYear, cal); }
+ QT_CORE_INLINE_SINCE(6, 7)
+ static QDate fromString(const QString &string, QStringView format, QCalendar cal);
+ static QDate fromString(const QString &string, const QString &format, QCalendar cal)
+ { return fromString(string, qToStringViewIgnoringNull(format), QLocale::DefaultTwoDigitBaseYear, cal); }
+
+ // Overriding base year is likely more common than overriding calendar (and
+ // likely to get more so, as the legacy base drops ever further behind us).
+ static QDate fromString(QStringView string, QStringView format,
+ int baseYear = QLocale::DefaultTwoDigitBaseYear)
+ { return fromString(string.toString(), format, baseYear); }
+ static QDate fromString(QStringView string, QStringView format,
+ int baseYear, QCalendar cal)
+ { return fromString(string.toString(), format, baseYear, cal); }
+ static QDate fromString(const QString &string, QStringView format,
+ int baseYear = QLocale::DefaultTwoDigitBaseYear);
+ static QDate fromString(const QString &string, QStringView format,
+ int baseYear, QCalendar cal);
static QDate fromString(const QString &string, const QString &format,
- QCalendar cal = QCalendar())
- { return fromString(string, qToStringViewIgnoringNull(format), cal); }
+ int baseYear = QLocale::DefaultTwoDigitBaseYear)
+ { return fromString(string, qToStringViewIgnoringNull(format), baseYear); }
+ static QDate fromString(const QString &string, const QString &format,
+ int baseYear, QCalendar cal)
+ { return fromString(string, qToStringViewIgnoringNull(format), baseYear, cal); }
#endif
static bool isValid(int y, int m, int d);
static bool isLeapYear(int year);
@@ -167,17 +176,34 @@ private:
static constexpr inline qint64 maxJd() { return Q_INT64_C( 784354017364); }
static constexpr inline qint64 unixEpochJd() { return Q_INT64_C(2440588); }
+#if __cpp_lib_chrono >= 201907L
+ static constexpr qint64 stdSysDaysToJulianDay(const std::chrono::sys_days &days) noexcept
+ {
+ const auto epochDays = days.time_since_epoch().count();
+ // minJd() and maxJd() fit into 40 bits.
+ if constexpr (sizeof(epochDays) * CHAR_BIT >= 41) {
+ constexpr auto top = maxJd() - unixEpochJd();
+ constexpr auto bottom = minJd() - unixEpochJd();
+ if (epochDays > top || epochDays < bottom)
+ return nullJd();
+ }
+ return unixEpochJd() + epochDays;
+ }
+#endif // __cpp_lib_chrono >= 201907L
+
qint64 jd;
friend class QDateTime;
+ friend class QDateTimeParser;
friend class QDateTimePrivate;
- friend constexpr bool operator==(QDate lhs, QDate rhs) { return lhs.jd == rhs.jd; }
- friend constexpr bool operator!=(QDate lhs, QDate rhs) { return lhs.jd != rhs.jd; }
- friend constexpr bool operator< (QDate lhs, QDate rhs) { return lhs.jd < rhs.jd; }
- friend constexpr bool operator<=(QDate lhs, QDate rhs) { return lhs.jd <= rhs.jd; }
- friend constexpr bool operator> (QDate lhs, QDate rhs) { return lhs.jd > rhs.jd; }
- friend constexpr bool operator>=(QDate lhs, QDate rhs) { return lhs.jd >= rhs.jd; }
+ friend constexpr bool comparesEqual(const QDate &lhs, const QDate &rhs) noexcept
+ { return lhs.jd == rhs.jd; }
+ friend constexpr Qt::strong_ordering
+ compareThreeWay(const QDate &lhs, const QDate &rhs) noexcept
+ { return Qt::compareThreeWay(lhs.jd, rhs.jd); }
+ Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(QDate)
+
#ifndef QT_NO_DATASTREAM
friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, QDate);
friend Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QDate &);
@@ -235,12 +261,12 @@ private:
constexpr inline int ds() const { return mds == -1 ? 0 : mds; }
int mds;
- friend constexpr bool operator==(QTime lhs, QTime rhs) { return lhs.mds == rhs.mds; }
- friend constexpr bool operator!=(QTime lhs, QTime rhs) { return lhs.mds != rhs.mds; }
- friend constexpr bool operator< (QTime lhs, QTime rhs) { return lhs.mds < rhs.mds; }
- friend constexpr bool operator<=(QTime lhs, QTime rhs) { return lhs.mds <= rhs.mds; }
- friend constexpr bool operator> (QTime lhs, QTime rhs) { return lhs.mds > rhs.mds; }
- friend constexpr bool operator>=(QTime lhs, QTime rhs) { return lhs.mds >= rhs.mds; }
+ friend constexpr bool comparesEqual(const QTime &lhs, const QTime &rhs) noexcept
+ { return lhs.mds == rhs.mds; }
+ friend constexpr Qt::strong_ordering
+ compareThreeWay(const QTime &lhs, const QTime &rhs) noexcept
+ { return Qt::compareThreeWay(lhs.mds, rhs.mds); }
+ Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(QTime)
friend class QDateTime;
friend class QDateTimePrivate;
@@ -276,7 +302,7 @@ class Q_CORE_EXPORT QDateTime
quintptr status : 8;
# endif
#endif
- friend constexpr bool operator==(const ShortData &lhs, const ShortData &rhs)
+ friend constexpr bool operator==(ShortData lhs, ShortData rhs)
{ return lhs.status == rhs.status && lhs.msecs == rhs.msecs; }
};
@@ -298,6 +324,7 @@ class Q_CORE_EXPORT QDateTime
{ std::swap(data, other.data); }
bool isShort() const;
+ inline void invalidate();
void detach();
QTimeZone timeZone() const;
@@ -310,12 +337,31 @@ class Q_CORE_EXPORT QDateTime
public:
QDateTime() noexcept;
+
+ enum class TransitionResolution {
+ Reject = 0,
+ RelativeToBefore,
+ RelativeToAfter,
+ PreferBefore,
+ PreferAfter,
+ PreferStandard,
+ PreferDaylightSaving,
+ // Closest match to behavior prior to introducing TransitionResolution:
+ LegacyBehavior = RelativeToBefore
+ };
+
#if QT_DEPRECATED_SINCE(6, 9)
QT_DEPRECATED_VERSION_X_6_9("Pass QTimeZone instead")
QDateTime(QDate date, QTime time, Qt::TimeSpec spec, int offsetSeconds = 0);
#endif
+#if QT_CORE_REMOVED_SINCE(6, 7)
QDateTime(QDate date, QTime time, const QTimeZone &timeZone);
QDateTime(QDate date, QTime time);
+#endif
+ QDateTime(QDate date, QTime time, const QTimeZone &timeZone,
+ TransitionResolution resolve = TransitionResolution::LegacyBehavior);
+ QDateTime(QDate date, QTime time,
+ TransitionResolution resolve = TransitionResolution::LegacyBehavior);
QDateTime(const QDateTime &other) noexcept;
QDateTime(QDateTime &&other) noexcept;
~QDateTime();
@@ -342,23 +388,34 @@ public:
qint64 toMSecsSinceEpoch() const;
qint64 toSecsSinceEpoch() const;
+#if QT_CORE_REMOVED_SINCE(6, 7)
void setDate(QDate date);
void setTime(QTime time);
+#endif
+ void setDate(QDate date, TransitionResolution resolve = TransitionResolution::LegacyBehavior);
+ void setTime(QTime time, TransitionResolution resolve = TransitionResolution::LegacyBehavior);
+
#if QT_DEPRECATED_SINCE(6, 9)
QT_DEPRECATED_VERSION_X_6_9("Use setTimeZone() instead")
void setTimeSpec(Qt::TimeSpec spec);
QT_DEPRECATED_VERSION_X_6_9("Use setTimeZone() instead")
void setOffsetFromUtc(int offsetSeconds);
#endif
+#if QT_CORE_REMOVED_SINCE(6, 7)
void setTimeZone(const QTimeZone &toZone);
+#endif
+ void setTimeZone(const QTimeZone &toZone,
+ TransitionResolution resolve = TransitionResolution::LegacyBehavior);
void setMSecsSinceEpoch(qint64 msecs);
void setSecsSinceEpoch(qint64 secs);
#if QT_CONFIG(datestring)
QString toString(Qt::DateFormat format = Qt::TextDate) const;
- QString toString(const QString &format, QCalendar cal = QCalendar()) const
+ QString toString(const QString &format) const;
+ QString toString(const QString &format, QCalendar cal) const
{ return toString(qToStringViewIgnoringNull(format), cal); }
- QString toString(QStringView format, QCalendar cal = QCalendar()) const;
+ QString toString(QStringView format) const;
+ QString toString(QStringView format, QCalendar cal) const;
#endif
[[nodiscard]] QDateTime addDays(qint64 days) const;
[[nodiscard]] QDateTime addMonths(int months) const;
@@ -387,17 +444,37 @@ public:
static QDateTime currentDateTime();
static QDateTime currentDateTimeUtc();
#if QT_CONFIG(datestring)
+ // No DateFormat accepts a two-digit year, so no need for baseYear:
static QDateTime fromString(QStringView string, Qt::DateFormat format = Qt::TextDate);
- static QDateTime fromString(QStringView string, QStringView format,
- QCalendar cal = QCalendar())
- { return fromString(string.toString(), format, cal); }
- static QDateTime fromString(const QString &string, QStringView format,
- QCalendar cal = QCalendar());
static QDateTime fromString(const QString &string, Qt::DateFormat format = Qt::TextDate)
{ return fromString(qToStringViewIgnoringNull(string), format); }
+
+ // Accept calendar without over-ride of base year:
+ static QDateTime fromString(QStringView string, QStringView format, QCalendar cal)
+ { return fromString(string.toString(), format, QLocale::DefaultTwoDigitBaseYear, cal); }
+ QT_CORE_INLINE_SINCE(6, 7)
+ static QDateTime fromString(const QString &string, QStringView format, QCalendar cal);
+ static QDateTime fromString(const QString &string, const QString &format, QCalendar cal)
+ { return fromString(string, qToStringViewIgnoringNull(format), QLocale::DefaultTwoDigitBaseYear, cal); }
+
+ // Overriding base year is likely more common than overriding calendar (and
+ // likely to get more so, as the legacy base drops ever further behind us).
+ static QDateTime fromString(QStringView string, QStringView format,
+ int baseYear = QLocale::DefaultTwoDigitBaseYear)
+ { return fromString(string.toString(), format, baseYear); }
+ static QDateTime fromString(QStringView string, QStringView format,
+ int baseYear, QCalendar cal)
+ { return fromString(string.toString(), format, baseYear, cal); }
+ static QDateTime fromString(const QString &string, QStringView format,
+ int baseYear = QLocale::DefaultTwoDigitBaseYear);
+ static QDateTime fromString(const QString &string, QStringView format,
+ int baseYear, QCalendar cal);
static QDateTime fromString(const QString &string, const QString &format,
- QCalendar cal = QCalendar())
- { return fromString(string, qToStringViewIgnoringNull(format), cal); }
+ int baseYear = QLocale::DefaultTwoDigitBaseYear)
+ { return fromString(string, qToStringViewIgnoringNull(format), baseYear); }
+ static QDateTime fromString(const QString &string, const QString &format,
+ int baseYear, QCalendar cal)
+ { return fromString(string, qToStringViewIgnoringNull(format), baseYear, cal); }
#endif
#if QT_DEPRECATED_SINCE(6, 9)
@@ -518,17 +595,18 @@ public:
private:
bool equals(const QDateTime &other) const;
+#if QT_CORE_REMOVED_SINCE(6, 7)
bool precedes(const QDateTime &other) const;
+#endif
friend class QDateTimePrivate;
Data d;
- friend bool operator==(const QDateTime &lhs, const QDateTime &rhs) { return lhs.equals(rhs); }
- friend bool operator!=(const QDateTime &lhs, const QDateTime &rhs) { return !(lhs == rhs); }
- friend bool operator<(const QDateTime &lhs, const QDateTime &rhs) { return lhs.precedes(rhs); }
- friend bool operator<=(const QDateTime &lhs, const QDateTime &rhs) { return !(rhs < lhs); }
- friend bool operator>(const QDateTime &lhs, const QDateTime &rhs) { return rhs.precedes(lhs); }
- friend bool operator>=(const QDateTime &lhs, const QDateTime &rhs) { return !(lhs < rhs); }
+ friend bool comparesEqual(const QDateTime &lhs, const QDateTime &rhs)
+ { return lhs.equals(rhs); }
+ friend Q_CORE_EXPORT Qt::weak_ordering
+ compareThreeWay(const QDateTime &lhs, const QDateTime &rhs);
+ Q_DECLARE_WEAKLY_ORDERED(QDateTime)
#ifndef QT_NO_DATASTREAM
friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QDateTime &);
@@ -562,6 +640,18 @@ Q_CORE_EXPORT size_t qHash(const QDateTime &key, size_t seed = 0);
Q_CORE_EXPORT size_t qHash(QDate key, size_t seed = 0) noexcept;
Q_CORE_EXPORT size_t qHash(QTime key, size_t seed = 0) noexcept;
+#if QT_CONFIG(datestring) && QT_CORE_INLINE_IMPL_SINCE(6, 7)
+QDate QDate::fromString(const QString &string, QStringView format, QCalendar cal)
+{
+ return fromString(string, format, QLocale::DefaultTwoDigitBaseYear, cal);
+}
+
+QDateTime QDateTime::fromString(const QString &string, QStringView format, QCalendar cal)
+{
+ return fromString(string, format, QLocale::DefaultTwoDigitBaseYear, cal);
+}
+#endif
+
QT_END_NAMESPACE
#endif // QDATETIME_H
diff --git a/src/corelib/time/qdatetime_p.h b/src/corelib/time/qdatetime_p.h
index ab91ec3333..02b047dd73 100644
--- a/src/corelib/time/qdatetime_p.h
+++ b/src/corelib/time/qdatetime_p.h
@@ -73,6 +73,22 @@ public:
};
Q_DECLARE_FLAGS(StatusFlags, StatusFlag)
+
+ enum TransitionOption {
+ // Handling of a spring-forward (or other gap):
+ GapUseBefore = 2,
+ GapUseAfter = 4,
+ // Handling of a fall-back (or other repeated period):
+ FoldUseBefore = 0x20,
+ FoldUseAfter = 0x40,
+ // Quirk for negative DST:
+ FlipForReverseDst = 0x400,
+
+ GapMask = GapUseBefore | GapUseAfter,
+ FoldMask = FoldUseBefore | FoldUseAfter,
+ };
+ Q_DECLARE_FLAGS(TransitionOptions, TransitionOption)
+
enum {
TimeSpecShift = 4,
};
@@ -89,14 +105,16 @@ public:
: when(w), offset(o), dst(d), valid(v) {}
};
- static QDateTime::Data create(QDate toDate, QTime toTime, const QTimeZone &timeZone);
+ static QDateTime::Data create(QDate toDate, QTime toTime, const QTimeZone &timeZone,
+ QDateTime::TransitionResolution resolve);
#if QT_CONFIG(timezone)
- static ZoneState zoneStateAtMillis(const QTimeZone &zone, qint64 millis, DaylightStatus dst);
+ static ZoneState zoneStateAtMillis(const QTimeZone &zone, qint64 millis,
+ TransitionOptions resolve);
#endif // timezone
static ZoneState expressUtcAsLocal(qint64 utcMSecs);
- static ZoneState localStateAtMillis(qint64 millis, DaylightStatus dst);
+ static ZoneState localStateAtMillis(qint64 millis, TransitionOptions resolve);
static QString localNameAtMillis(qint64 millis, DaylightStatus dst); // empty if unknown
StatusFlags m_status = StatusFlag(Qt::LocalTime << TimeSpecShift);
@@ -106,6 +124,7 @@ public:
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QDateTimePrivate::StatusFlags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDateTimePrivate::TransitionOptions)
namespace QtPrivate {
namespace DateTimeConstants {
@@ -122,6 +141,9 @@ constexpr qint64 MSECS_PER_HOUR = SECS_PER_HOUR * MSECS_PER_SEC;
constexpr qint64 MSECS_PER_DAY = SECS_PER_DAY * MSECS_PER_SEC;
constexpr qint64 JULIAN_DAY_FOR_EPOCH = 2440588; // result of QDate(1970, 1, 1).toJulianDay()
+
+constexpr qint64 JulianDayMax = Q_INT64_C( 784354017364);
+constexpr qint64 JulianDayMin = Q_INT64_C(-784350574879);
}
}
diff --git a/src/corelib/time/qdatetimeparser.cpp b/src/corelib/time/qdatetimeparser.cpp
index aff78eae2f..78520a51aa 100644
--- a/src/corelib/time/qdatetimeparser.cpp
+++ b/src/corelib/time/qdatetimeparser.cpp
@@ -237,9 +237,9 @@ int QDateTimeParser::absoluteMax(int s, const QDateTime &cur) const
case MSecSection:
return 999;
case YearSection2Digits:
- case YearSection:
// sectionMaxSize will prevent people from typing in a larger number in
// count == 2 sections; stepBy() will work on real years anyway.
+ case YearSection:
return 9999;
case MonthSection:
return calendar.maximumMonthsInYear();
@@ -709,6 +709,7 @@ int QDateTimeParser::sectionMaxSize(Section s, int count) const
case DaySectionMask:
qWarning("QDateTimeParser::sectionMaxSize: Invalid section %s",
SectionNode::name(s).toLatin1().constData());
+ break;
case NoSectionIndex:
case FirstSectionIndex:
@@ -727,6 +728,36 @@ int QDateTimeParser::sectionMaxSize(int index) const
return sectionMaxSize(sn.type, sn.count);
}
+// Separator matching
+//
+// QTBUG-114909: user may be oblivious to difference between visibly
+// indistinguishable spacing characters. For now we only treat horizontal
+// spacing characters, excluding tab, as equivalent.
+
+static int matchesSeparator(QStringView text, QStringView separator)
+{
+ const auto isSimpleSpace = [](char32_t ch) {
+ // Distinguish tab, CR and the vertical spaces from the rest:
+ return ch == u' ' || (ch > 127 && QChar::isSpace(ch));
+ };
+ // -1 if not a match, else length of prefix of text that does match.
+ // First check for exact match
+ if (!text.startsWith(separator)) {
+ // Failing that, check for space-identifying match:
+ QStringIterator given(text), sep(separator);
+ while (sep.hasNext()) {
+ if (!given.hasNext())
+ return -1;
+ char32_t s = sep.next(), g = given.next();
+ if (s != g && !(isSimpleSpace(s) && isSimpleSpace(g)))
+ return -1;
+ }
+ // One side may have used a surrogate pair space where the other didn't:
+ return given.index();
+ }
+ return separator.size();
+}
+
/*!
\internal
@@ -768,11 +799,6 @@ QDateTimeParser::parseSection(const QDateTime &currentValue, int sectionIndex, i
&& m_text.at(offset) == u'-');
const int negativeYearOffset = negate ? 1 : 0;
- // If the fields we've read thus far imply a time in a spring-forward,
- // coerce to a nearby valid time:
- const QDateTime defaultValue = currentValue.isValid() ? currentValue
- : QDateTime::fromMSecsSinceEpoch(currentValue.toMSecsSinceEpoch());
-
QStringView sectionTextRef =
QStringView { m_text }.mid(offset + negativeYearOffset, sectionmaxsize);
@@ -808,7 +834,7 @@ QDateTimeParser::parseSection(const QDateTime &currentValue, int sectionIndex, i
m_text.replace(offset, used, sectiontext.constData(), used);
break; }
case TimeZoneSection:
- result = findTimeZone(sectionTextRef, defaultValue,
+ result = findTimeZone(sectionTextRef, currentValue,
absoluteMax(sectionIndex),
absoluteMin(sectionIndex), sn.count);
break;
@@ -820,7 +846,7 @@ QDateTimeParser::parseSection(const QDateTime &currentValue, int sectionIndex, i
int num = 0, used = 0;
if (sn.type == MonthSection) {
const QDate minDate = getMinimum().date();
- const int year = defaultValue.date().year(calendar);
+ const int year = currentValue.date().year(calendar);
const int min = (year == minDate.year(calendar)) ? minDate.month(calendar) : 1;
num = findMonth(sectiontext.toLower(), min, sectionIndex, year, &sectiontext, &used);
} else {
@@ -845,12 +871,26 @@ QDateTimeParser::parseSection(const QDateTime &currentValue, int sectionIndex, i
case MinuteSection:
case SecondSection:
case MSecSection: {
+ const auto checkSeparator = [&result, field=QStringView{m_text}.sliced(offset),
+ negativeYearOffset, sectionIndex, this]() {
+ // No-digit field if next separator is here, otherwise invalid.
+ const auto &sep = separators.at(sectionIndex + 1);
+ if (matchesSeparator(field.sliced(negativeYearOffset), sep) != -1)
+ result = ParsedSection(Intermediate, 0, negativeYearOffset);
+ else if (negativeYearOffset && matchesSeparator(field, sep) != -1)
+ result = ParsedSection(Intermediate, 0, 0);
+ else
+ return false;
+ return true;
+ };
int used = negativeYearOffset;
- // We already sliced off the - sign if it was legitimately present.
+ // We already sliced off the - sign if it was acceptable.
+ // QLocale::toUInt() would accept a sign, so we must reject it overtly:
if (sectionTextRef.startsWith(u'-')
|| sectionTextRef.startsWith(u'+')) {
- if (separators.at(sectionIndex + 1).startsWith(sectionTextRef[0]))
- result = ParsedSection(Intermediate, 0, used);
+ // However, a sign here may indicate a field with no digits, if it
+ // starts the next separator:
+ checkSeparator();
break;
}
QStringView digitsStr = sectionTextRef.left(digitCount(sectionTextRef));
@@ -884,13 +924,10 @@ QDateTimeParser::parseSection(const QDateTime &currentValue, int sectionIndex, i
}
if (lastVal == -1) {
- const auto &sep = separators.at(sectionIndex + 1);
- if (sep.startsWith(sectionTextRef[0])
- || (negate && sep.startsWith(m_text.at(offset))))
- result = ParsedSection(Intermediate, 0, 0);
- else
+ if (!checkSeparator()) {
QDTPDEBUG << "invalid because" << sectionTextRef << "can't become a uint"
<< lastVal;
+ }
} else {
if (negate)
lastVal = -lastVal;
@@ -914,13 +951,13 @@ QDateTimeParser::parseSection(const QDateTime &currentValue, int sectionIndex, i
}
} else if (unfilled && (fi & (FixedWidth | Numeric)) == (FixedWidth | Numeric)) {
- if (skipToNextSection(sectionIndex, defaultValue, digitsStr)) {
+ if (skipToNextSection(sectionIndex, currentValue, digitsStr)) {
const int missingZeroes = sectionmaxsize - digitsStr.size();
result = ParsedSection(Acceptable, lastVal, sectionmaxsize, missingZeroes);
m_text.insert(offset, QString(missingZeroes, u'0'));
++(const_cast<QDateTimeParser*>(this)->sectionNodes[sectionIndex].zeroesAdded);
} else {
- result = ParsedSection(Intermediate, lastVal, used);;
+ result = ParsedSection(Intermediate, lastVal, used);
}
} else {
result = ParsedSection(Acceptable, lastVal, used);
@@ -957,6 +994,17 @@ static int weekDayWithinMonth(QCalendar calendar, int year, int month, int day,
}
/*!
+ \internal
+ Returns whichever of baseYear through baseYear + 99 has its % 100 == y2d.
+*/
+static int yearInCenturyFrom(int y2d, int baseYear)
+{
+ Q_ASSERT(0 <= y2d && y2d < 100);
+ const int year = baseYear - baseYear % 100 + y2d;
+ return year < baseYear ? year + 100 : year;
+}
+
+/*!
\internal
Returns a date consistent with the given data on parts specified by known,
@@ -964,7 +1012,7 @@ static int weekDayWithinMonth(QCalendar calendar, int year, int month, int day,
when on valid date is consistent with the data.
*/
-static QDate actualDate(QDateTimeParser::Sections known, const QCalendar &calendar,
+static QDate actualDate(QDateTimeParser::Sections known, QCalendar calendar, int baseYear,
int year, int year2digits, int month, int day, int dayofweek)
{
QDate actual(year, month, day, calendar);
@@ -978,7 +1026,7 @@ static QDate actualDate(QDateTimeParser::Sections known, const QCalendar &calend
if (year % 100 != year2digits) {
if (known & QDateTimeParser::YearSection2Digits) {
// Over-ride year, even if specified:
- year += year2digits - year % 100;
+ year = yearInCenturyFrom(year2digits, baseYear);
known &= ~QDateTimeParser::YearSection;
} else {
year2digits = year % 100;
@@ -996,7 +1044,7 @@ static QDate actualDate(QDateTimeParser::Sections known, const QCalendar &calend
QDate first(year, month, 1, calendar);
int last = known & QDateTimeParser::MonthSection
- ? (known & QDateTimeParser::YearSection
+ ? (known.testAnyFlag(QDateTimeParser::YearSectionMask)
? calendar.daysInMonth(month, year) : calendar.daysInMonth(month))
: 0;
// We can only fix DOW if we know year as well as month (hence last):
@@ -1073,20 +1121,11 @@ static QDate actualDate(QDateTimeParser::Sections known, const QCalendar &calend
if ((known & QDateTimeParser::YearSection) == 0) {
if (known & QDateTimeParser::YearSection2Digits) {
- /*
- Two-digit year and month are specified; choice of century can only
- fix this if diff is in one of {1, 2, 5} or {2, 4, 6}; but not if
- diff is in the other. It's also only reasonable to consider
- adjacent century, e.g. if year thinks it's 2012 and two-digit year
- is '97, it makes sense to consider 1997. If either adjacent
- century does work, the other won't.
- */
- actual = QDate(year + 100, month, day, calendar);
- if (calendar.dayOfWeek(actual) == dayofweek)
- return actual;
- actual = QDate(year - 100, month, day, calendar);
- if (calendar.dayOfWeek(actual) == dayofweek)
+ actual = calendar.matchCenturyToWeekday({year, month, day}, dayofweek);
+ if (actual.isValid()) {
+ Q_ASSERT(calendar.dayOfWeek(actual) == dayofweek);
return actual;
+ }
} else {
// Offset by 7 is usually enough, but rare cases may need more:
for (int y = 1; y < 12; y++) {
@@ -1142,14 +1181,43 @@ static QTime actualTime(QDateTimeParser::Sections known,
/*
\internal
*/
-static int startsWithLocalTimeZone(QStringView name)
+static int startsWithLocalTimeZone(QStringView name, const QDateTime &when, const QLocale &locale)
{
+ // Pick longest match that we might get.
+ qsizetype longest = 0;
+ // On MS-Win, at least when system zone is UTC, the tzname[]s may be empty.
for (int i = 0; i < 2; ++i) {
const QString zone(qTzName(i));
- if (name.startsWith(zone))
- return zone.size();
+ if (zone.size() > longest && name.startsWith(zone))
+ longest = zone.size();
+ }
+ // Mimic each candidate QLocale::toString() could have used, to ensure round-trips work:
+ const auto consider = [name, &longest](QStringView zone) {
+ if (name.startsWith(zone)) {
+ // UTC-based zone's displayName() only includes seconds if non-zero:
+ if (9 > longest && zone.size() == 6 && zone.startsWith("UTC"_L1)
+ && name.sliced(6, 3) == ":00"_L1) {
+ longest = 9;
+ } else if (zone.size() > longest) {
+ longest = zone.size();
+ }
+ }
+ };
+#if QT_CONFIG(timezone)
+ /* QLocale::toString would skip this if locale == QLocale::system(), but we
+ might not be using the same system locale as whoever generated the text
+ we're parsing. So consider it anyway. */
+ {
+ const auto localWhen = QDateTime(when.date(), when.time());
+ consider(localWhen.timeRepresentation().displayName(
+ localWhen, QTimeZone::ShortName, locale));
}
- return 0;
+#else
+ Q_UNUSED(locale);
+#endif
+ consider(QDateTime(when.date(), when.time()).timeZoneAbbreviation());
+ Q_ASSERT(longest <= INT_MAX); // Timezone names are not that long.
+ return int(longest);
}
/*!
@@ -1182,25 +1250,25 @@ QDateTimeParser::scanString(const QDateTime &defaultValue, bool fixup) const
for (int index = 0; index < sectionNodesCount; ++index) {
Q_ASSERT(state != Invalid);
const QString &separator = separators.at(index);
- if (QStringView{m_text}.mid(pos, separator.size()) != separator) {
- QDTPDEBUG << "invalid because" << QStringView{m_text}.mid(pos, separator.size())
- << "!=" << separator
+ int step = matchesSeparator(QStringView{m_text}.sliced(pos), separator);
+ if (step == -1) {
+ QDTPDEBUG << "invalid because" << QStringView{m_text}.sliced(pos)
+ << "does not start with" << separator
<< index << pos << currentSectionIndex;
return StateNode();
}
- pos += separator.size();
+ pos += step;
sectionNodes[index].pos = pos;
int *current = nullptr;
int zoneOffset; // Needed to serve as *current when setting zone
const SectionNode sn = sectionNodes.at(index);
- ParsedSection sect;
-
- {
- const QDate date = actualDate(isSet, calendar, year, year2digits,
- month, day, dayofweek);
+ const QDateTime usedDateTime = [&] {
+ const QDate date = actualDate(isSet, calendar, defaultCenturyStart,
+ year, year2digits, month, day, dayofweek);
const QTime time = actualTime(isSet, hour, hour12, ampm, minute, second, msec);
- sect = parseSection(QDateTime(date, time, timeZone), index, pos);
- }
+ return QDateTime(date, time, timeZone);
+ }();
+ ParsedSection sect = parseSection(usedDateTime, index, pos);
QDTPDEBUG << "sectionValue" << sn.name() << m_text
<< "pos" << pos << "used" << sect.used << stateName(sect.state);
@@ -1209,7 +1277,7 @@ QDateTimeParser::scanString(const QDateTime &defaultValue, bool fixup) const
if (fixup && sect.state == Intermediate && sect.used < sn.count) {
const FieldInfo fi = fieldInfo(index);
if ((fi & (Numeric|FixedWidth)) == (Numeric|FixedWidth)) {
- const QString newText = QString("%1"_L1).arg(sect.value, sn.count, 10, '0'_L1);
+ const QString newText = QString::asprintf("%0*d", sn.count, sect.value);
m_text.replace(pos, sect.used, newText);
sect.used = sn.count;
}
@@ -1235,18 +1303,14 @@ QDateTimeParser::scanString(const QDateTime &defaultValue, bool fixup) const
if (isUtc || isUtcOffset) {
timeZone = QTimeZone::fromSecondsAheadOfUtc(sect.value);
- } else {
#if QT_CONFIG(timezone)
+ } else if (startsWithLocalTimeZone(zoneName, usedDateTime, locale()) != sect.used) {
QTimeZone namedZone = QTimeZone(zoneName.toLatin1());
- if (namedZone.isValid()) {
- timeZone = namedZone;
- } else {
- Q_ASSERT(startsWithLocalTimeZone(zoneName));
- timeZone = QTimeZone::LocalTime;
- }
-#else
- timeZone = QTimeZone::LocalTime;
+ Q_ASSERT(namedZone.isValid());
+ timeZone = namedZone;
#endif
+ } else {
+ timeZone = QTimeZone::LocalTime;
}
}
break;
@@ -1287,24 +1351,24 @@ QDateTimeParser::scanString(const QDateTime &defaultValue, bool fixup) const
isSet |= sn.type;
}
- if (QStringView{m_text}.sliced(pos) != separators.last()) {
+ int step = matchesSeparator(QStringView{m_text}.sliced(pos), separators.last());
+ if (step == -1 || step + pos < m_text.size()) {
QDTPDEBUG << "invalid because" << QStringView{m_text}.sliced(pos)
- << "!=" << separators.last() << pos;
+ << "does not match" << separators.last() << pos;
return StateNode();
}
if (parserType != QMetaType::QTime) {
if (year % 100 != year2digits && (isSet & YearSection2Digits)) {
+ const QDate date = actualDate(isSet, calendar, defaultCenturyStart,
+ year, year2digits, month, day, dayofweek);
if (!(isSet & YearSection)) {
- year = (year / 100) * 100;
- year += year2digits;
+ year = date.year();
} else {
conflicts = true;
const SectionNode &sn = sectionNode(currentSectionIndex);
- if (sn.type == YearSection2Digits) {
- year = (year / 100) * 100;
- year += year2digits;
- }
+ if (sn.type == YearSection2Digits)
+ year = date.year();
}
}
@@ -1389,31 +1453,40 @@ QDateTimeParser::scanString(const QDateTime &defaultValue, bool fixup) const
const QTime time(hour, minute, second, msec);
const QDateTime when = QDateTime(date, time, timeZone);
- // If hour wasn't specified, check the default we're using exists on the
- // given date (which might be a spring-forward, skipping an hour).
- if (!(isSet & HourSectionMask) && !when.isValid()) {
- switch (parserType) {
- case QMetaType::QDateTime: {
- qint64 msecs = when.toMSecsSinceEpoch();
- // Fortunately, that gets a useful answer, even though when is invalid ...
- const QDateTime replace = QDateTime::fromMSecsSinceEpoch(msecs, timeZone);
- const QTime tick = replace.time();
- if (replace.date() == date
- && (!(isSet & MinuteSection) || tick.minute() == minute)
- && (!(isSet & SecondSection) || tick.second() == second)
- && (!(isSet & MSecSection) || tick.msec() == msec)) {
- return StateNode(replace, state, padding, conflicts);
+ if (when.time() != time || when.date() != date) {
+ // In a spring-forward, if we hit the skipped hour, we may have been
+ // shunted out of it.
+
+ // If hour wasn't specified, so we're using our default, changing it may
+ // fix that.
+ if (!(isSet & HourSectionMask)) {
+ switch (parserType) {
+ case QMetaType::QDateTime: {
+ qint64 msecs = when.toMSecsSinceEpoch();
+ // Fortunately, that gets a useful answer, even though when is invalid ...
+ const QDateTime replace = QDateTime::fromMSecsSinceEpoch(msecs, timeZone);
+ const QTime tick = replace.time();
+ if (replace.date() == date
+ && (!(isSet & MinuteSection) || tick.minute() == minute)
+ && (!(isSet & SecondSection) || tick.second() == second)
+ && (!(isSet & MSecSection) || tick.msec() == msec)) {
+ return StateNode(replace, state, padding, conflicts);
+ }
+ } break;
+ case QMetaType::QDate:
+ // Don't care about time, so just use start of day (and ignore spec):
+ return StateNode(date.startOfDay(QTimeZone::UTC),
+ state, padding, conflicts);
+ break;
+ case QMetaType::QTime:
+ // Don't care about date or representation, so pick a safe representation:
+ return StateNode(QDateTime(date, time, QTimeZone::UTC),
+ state, padding, conflicts);
+ default:
+ Q_UNREACHABLE_RETURN(StateNode());
}
- } break;
- case QMetaType::QDate:
- // Don't care about time, so just use start of day (and ignore spec):
- return StateNode(date.startOfDay(QTimeZone::UTC), state, padding, conflicts);
- break;
- case QMetaType::QTime:
- // Don't care about date or representation, so pick a safe representation:
- return StateNode(QDateTime(date, time, QTimeZone::UTC), state, padding, conflicts);
- default:
- Q_UNREACHABLE_RETURN(StateNode());
+ } else if (state > Intermediate) {
+ state = Intermediate;
}
}
@@ -1564,12 +1637,8 @@ QDateTimeParser::parse(const QString &input, int position,
}
}
- /*
- We might have ended up with an invalid datetime: the non-existent hour
- during dst changes, for instance.
- */
- if (!scan.value.isValid() && scan.state == Acceptable)
- scan.state = Intermediate;
+ // An invalid time should only arise if we set the state to less than acceptable:
+ Q_ASSERT(scan.value.isValid() || scan.state != Acceptable);
return scan;
}
@@ -1585,7 +1654,7 @@ QDateTimeParser::parse(const QString &input, int position,
length of overlap in *used (if \a used is non-NULL) and the first entry that
overlapped this much in *usedText (if \a usedText is non-NULL).
*/
-static int findTextEntry(const QString &text, const ShortVector<QString> &entries, QString *usedText, int *used)
+static int findTextEntry(QStringView text, const ShortVector<QString> &entries, QString *usedText, int *used)
{
if (text.isEmpty())
return -1;
@@ -1622,7 +1691,7 @@ static int findTextEntry(const QString &text, const ShortVector<QString> &entrie
match. Starting from \a index; str should already by lowered
*/
-int QDateTimeParser::findMonth(const QString &str1, int startMonth, int sectionIndex,
+int QDateTimeParser::findMonth(QStringView str, int startMonth, int sectionIndex,
int year, QString *usedMonth, int *used) const
{
const SectionNode &sn = sectionNode(sectionIndex);
@@ -1638,11 +1707,11 @@ int QDateTimeParser::findMonth(const QString &str1, int startMonth, int sectionI
for (int month = startMonth; month <= 12; ++month)
monthNames.append(calendar.monthName(l, month, year, type));
- const int index = findTextEntry(str1, monthNames, usedMonth, used);
+ const int index = findTextEntry(str, monthNames, usedMonth, used);
return index < 0 ? index : index + startMonth;
}
-int QDateTimeParser::findDay(const QString &str1, int startDay, int sectionIndex, QString *usedDay, int *used) const
+int QDateTimeParser::findDay(QStringView str, int startDay, int sectionIndex, QString *usedDay, int *used) const
{
const SectionNode &sn = sectionNode(sectionIndex);
if (!(sn.type & DaySectionMask)) {
@@ -1657,7 +1726,7 @@ int QDateTimeParser::findDay(const QString &str1, int startDay, int sectionIndex
for (int day = startDay; day <= 7; ++day)
daysOfWeek.append(l.dayName(day, type));
- const int index = findTextEntry(str1, daysOfWeek, usedDay, used);
+ const int index = findTextEntry(str, daysOfWeek, usedDay, used);
return index < 0 ? index : index + startDay;
}
@@ -1750,7 +1819,7 @@ QDateTimeParser::ParsedSection QDateTimeParser::findUtcOffset(QStringView str, i
QDateTimeParser::ParsedSection
QDateTimeParser::findTimeZoneName(QStringView str, const QDateTime &when) const
{
- const int systemLength = startsWithLocalTimeZone(str);
+ const int systemLength = startsWithLocalTimeZone(str, when, locale());
#if QT_CONFIG(timezone)
// Collect up plausibly-valid characters; let QTimeZone work out what's
// truly valid.
@@ -2122,22 +2191,22 @@ bool QDateTimeParser::skipToNextSection(int index, const QDateTime &current, QSt
QString QDateTimeParser::SectionNode::name(QDateTimeParser::Section s)
{
switch (s) {
- case QDateTimeParser::AmPmSection: return "AmPmSection"_L1;
- case QDateTimeParser::DaySection: return "DaySection"_L1;
- case QDateTimeParser::DayOfWeekSectionShort: return "DayOfWeekSectionShort"_L1;
- case QDateTimeParser::DayOfWeekSectionLong: return "DayOfWeekSectionLong"_L1;
- case QDateTimeParser::Hour24Section: return "Hour24Section"_L1;
- case QDateTimeParser::Hour12Section: return "Hour12Section"_L1;
- case QDateTimeParser::MSecSection: return "MSecSection"_L1;
- case QDateTimeParser::MinuteSection: return "MinuteSection"_L1;
- case QDateTimeParser::MonthSection: return "MonthSection"_L1;
- case QDateTimeParser::SecondSection: return "SecondSection"_L1;
- case QDateTimeParser::TimeZoneSection: return "TimeZoneSection"_L1;
- case QDateTimeParser::YearSection: return "YearSection"_L1;
- case QDateTimeParser::YearSection2Digits: return "YearSection2Digits"_L1;
- case QDateTimeParser::NoSection: return "NoSection"_L1;
- case QDateTimeParser::FirstSection: return "FirstSection"_L1;
- case QDateTimeParser::LastSection: return "LastSection"_L1;
+ case AmPmSection: return "AmPmSection"_L1;
+ case DaySection: return "DaySection"_L1;
+ case DayOfWeekSectionShort: return "DayOfWeekSectionShort"_L1;
+ case DayOfWeekSectionLong: return "DayOfWeekSectionLong"_L1;
+ case Hour24Section: return "Hour24Section"_L1;
+ case Hour12Section: return "Hour12Section"_L1;
+ case MSecSection: return "MSecSection"_L1;
+ case MinuteSection: return "MinuteSection"_L1;
+ case MonthSection: return "MonthSection"_L1;
+ case SecondSection: return "SecondSection"_L1;
+ case TimeZoneSection: return "TimeZoneSection"_L1;
+ case YearSection: return "YearSection"_L1;
+ case YearSection2Digits: return "YearSection2Digits"_L1;
+ case NoSection: return "NoSection"_L1;
+ case FirstSection: return "FirstSection"_L1;
+ case LastSection: return "LastSection"_L1;
default: return "Unknown section "_L1 + QString::number(int(s));
}
}
@@ -2157,11 +2226,26 @@ QString QDateTimeParser::stateName(State s) const
}
}
+
+/*!
+ \internal
+ Compute a defaultValue to pass to parse().
+*/
+QDateTime QDateTimeParser::baseDate(const QTimeZone &zone) const
+{
+ QDateTime when = QDate(defaultCenturyStart, 1, 1).startOfDay(zone);
+ if (const QDateTime start = getMinimum(); when < start)
+ return start;
+ if (const QDateTime end = getMaximum(); when > end)
+ return end;
+ return when;
+}
+
// Only called when we want only one of date or time; use UTC to avoid bogus DST issues.
-bool QDateTimeParser::fromString(const QString &t, QDate *date, QTime *time) const
+bool QDateTimeParser::fromString(const QString &t, QDate *date, QTime *time, int baseYear) const
{
- QDateTime val(QDate(1900, 1, 1).startOfDay(QTimeZone::UTC));
- const StateNode tmp = parse(t, -1, val, false);
+ defaultCenturyStart = baseYear;
+ const StateNode tmp = parse(t, -1, baseDate(QTimeZone::UTC), false);
if (tmp.state != Acceptable || tmp.conflicts)
return false;
@@ -2184,13 +2268,13 @@ bool QDateTimeParser::fromString(const QString &t, QDate *date, QTime *time) con
}
// Only called when we want both date and time; default to local time.
-bool QDateTimeParser::fromString(const QString &t, QDateTime *datetime) const
+bool QDateTimeParser::fromString(const QString &t, QDateTime *datetime, int baseYear) const
{
- QDateTime val(QDate(1900, 1, 1).startOfDay());
- const StateNode tmp = parse(t, -1, val, false);
+ defaultCenturyStart = baseYear;
+ const StateNode tmp = parse(t, -1, baseDate(QTimeZone::LocalTime), false);
if (datetime)
*datetime = tmp.value;
- return tmp.state == Acceptable && !tmp.conflicts && tmp.value.isValid();
+ return tmp.state >= Intermediate && !tmp.conflicts && tmp.value.isValid();
}
QDateTime QDateTimeParser::getMinimum() const
@@ -2221,8 +2305,8 @@ QString QDateTimeParser::getAmPmText(AmPm ap, Case cs) const
QString raw = ap == AmText ? loc.amText() : loc.pmText();
switch (cs)
{
- case UpperCase: return raw.toUpper();
- case LowerCase: return raw.toLower();
+ case UpperCase: return std::move(raw).toUpper();
+ case LowerCase: return std::move(raw).toLower();
case NativeCase: return raw;
}
Q_UNREACHABLE_RETURN(raw);
@@ -2243,7 +2327,7 @@ bool operator==(const QDateTimeParser::SectionNode &s1, const QDateTimeParser::S
Sets \a cal as the calendar to use. The default is Gregorian.
*/
-void QDateTimeParser::setCalendar(const QCalendar &cal)
+void QDateTimeParser::setCalendar(QCalendar cal)
{
calendar = cal;
}
diff --git a/src/corelib/time/qdatetimeparser_p.h b/src/corelib/time/qdatetimeparser_p.h
index 64ced268c9..faf383f3d7 100644
--- a/src/corelib/time/qdatetimeparser_p.h
+++ b/src/corelib/time/qdatetimeparser_p.h
@@ -46,7 +46,7 @@ public:
FromString,
DateTimeEdit
};
- QDateTimeParser(QMetaType::Type t, Context ctx, const QCalendar &cal = QCalendar())
+ QDateTimeParser(QMetaType::Type t, Context ctx, QCalendar cal = QCalendar())
: parserType(t), context(ctx), calendar(cal)
{
defaultLocale = QLocale::system();
@@ -136,8 +136,9 @@ public:
StateNode parse(const QString &input, int position,
const QDateTime &defaultValue, bool fixup) const;
- bool fromString(const QString &text, QDate *date, QTime *time) const;
- bool fromString(const QString &text, QDateTime* datetime) const;
+ bool fromString(const QString &text, QDate *date, QTime *time,
+ int baseYear = QLocale::DefaultTwoDigitBaseYear) const;
+ bool fromString(const QString &text, QDateTime *datetime, int baseYear) const;
bool parseFormat(QStringView format);
enum FieldInfoFlag {
@@ -152,7 +153,7 @@ public:
void setDefaultLocale(const QLocale &loc) { defaultLocale = loc; }
virtual QString displayText() const { return m_text; }
- void setCalendar(const QCalendar &calendar);
+ void setCalendar(QCalendar calendar);
private:
int sectionMaxSize(Section s, int count) const;
@@ -169,9 +170,9 @@ private:
{}
};
ParsedSection parseSection(const QDateTime &currentValue, int sectionIndex, int offset) const;
- int findMonth(const QString &str1, int monthstart, int sectionIndex,
+ int findMonth(QStringView str, int monthstart, int sectionIndex,
int year, QString *monthName = nullptr, int *used = nullptr) const;
- int findDay(const QString &str1, int intDaystart, int sectionIndex,
+ int findDay(QStringView str, int intDaystart, int sectionIndex,
QString *dayName = nullptr, int *used = nullptr) const;
ParsedSection findUtcOffset(QStringView str, int mode) const;
ParsedSection findTimeZoneName(QStringView str, const QDateTime &when) const;
@@ -203,6 +204,7 @@ private:
};
QString getAmPmText(AmPm ap, Case cs) const;
+ QDateTime baseDate(const QTimeZone &zone) const;
friend class QDTPUnitTestParser;
@@ -234,6 +236,7 @@ protected: // for the benefit of QDateTimeEditPrivate
virtual QLocale locale() const { return defaultLocale; }
mutable int currentSectionIndex = int(NoSectionIndex);
+ mutable int defaultCenturyStart = QLocale::DefaultTwoDigitBaseYear;
Sections display;
/*
This stores the most recently selected day.
diff --git a/src/corelib/time/qgregoriancalendar.cpp b/src/corelib/time/qgregoriancalendar.cpp
index 69a3665eee..d46d24ac30 100644
--- a/src/corelib/time/qgregoriancalendar.cpp
+++ b/src/corelib/time/qgregoriancalendar.cpp
@@ -93,12 +93,15 @@ bool QGregorianCalendar::validParts(int year, int month, int day)
int QGregorianCalendar::weekDayOfJulian(qint64 jd)
{
- return qMod<7>(jd) + 1;
+ return int(qMod<7>(jd) + 1);
}
bool QGregorianCalendar::dateToJulianDay(int year, int month, int day, qint64 *jd) const
{
- return julianFromParts(year, month, day, jd);
+ const auto maybe = julianFromParts(year, month, day);
+ if (maybe)
+ *jd = *maybe;
+ return bool(maybe);
}
QCalendar::YearMonthDay QGregorianCalendar::julianDayToDate(qint64 jd) const
@@ -106,6 +109,59 @@ QCalendar::YearMonthDay QGregorianCalendar::julianDayToDate(qint64 jd) const
return partsFromJulian(jd);
}
+qint64
+QGregorianCalendar::matchCenturyToWeekday(const QCalendar::YearMonthDay &parts, int dow) const
+{
+ /* The Gregorian four-century cycle is a whole number of weeks long, so we
+ only need to consider four centuries, from previous through next-but-one.
+ There are thus three days of the week that can't happen, for any given
+ day-of-month, month and year-mod-100. (Exception: '00 Feb 29 has only one
+ option.)
+ */
+ auto maybe = julianFromParts(parts.year, parts.month, parts.day);
+ if (maybe) {
+ int diff = weekDayOfJulian(*maybe) - dow;
+ if (!diff)
+ return *maybe;
+ int year = parts.year < 0 ? parts.year + 1 : parts.year;
+ // What matters is the placement of leap days, so dates before March
+ // effectively belong with the dates since the preceding March:
+ const auto yearSplit = qDivMod<100>(year - (parts.month < 3 ? 1 : 0));
+ const int centuryMod4 = qMod<4>(yearSplit.quotient);
+ // Week-day shift for a century is 5, unless crossing a multiple of 400's Feb 29th.
+ static_assert(qMod<7>(36524) == 5); // and (3 * 5) % 7 = 1
+ // Formulae arrived at by case-by-case analysis of the values of
+ // centuryMod4 and diff (and the above clue to multiply by -3 = 4):
+ if (qMod<7>(diff * 4 + centuryMod4) < 4) {
+ // Century offset maps qMod<7>(diff) in {5, 6} to -1, {3, 4} to +2, and {1, 2} to +1:
+ year += (((qMod<7>(diff) + 3) / 2) % 4 - 1) * 100;
+ maybe = julianFromParts(year > 0 ? year : year - 1, parts.month, parts.day);
+ if (maybe && weekDayOfJulian(*maybe) == dow)
+ return *maybe;
+ Q_ASSERT(parts.month == 2 && parts.day == 29
+ && dow != int(Qt::Tuesday) && !(year % 100));
+ }
+
+ } else if (parts.month == 2 && parts.day == 29) {
+ int year = parts.year < 0 ? parts.year + 1 : parts.year;
+ // Feb 29th on a century needs to resolve to a multiple of 400 years.
+ const auto yearSplit = qDivMod<100>(year);
+ if (!yearSplit.remainder) {
+ const auto centuryMod4 = qMod<4>(yearSplit.quotient);
+ Q_ASSERT(centuryMod4); // or we'd have got a valid date to begin with.
+ if (centuryMod4 == 1) // round down
+ year -= 100;
+ else // 2 or 3; round up
+ year += (4 - centuryMod4) * 100;
+ maybe = julianFromParts(year > 0 ? year : year - 1, parts.month, parts.day);
+ if (maybe && weekDayOfJulian(*maybe) == dow) // (Can only happen for Tuesday.)
+ return *maybe;
+ Q_ASSERT(dow != int(Qt::Tuesday));
+ }
+ }
+ return (std::numeric_limits<qint64>::min)();
+}
+
int QGregorianCalendar::yearStartWeekDay(int year)
{
// Equivalent to weekDayOfJulian(julianForParts({year, 1, 1})
@@ -175,17 +231,15 @@ constexpr qint64 BaseJd = LeapDayGregorian1Bce;
// Every four centures there are 97 leap years:
constexpr unsigned FourCenturies = 400 * 365 + 97;
-bool QGregorianCalendar::julianFromParts(int year, int month, int day, qint64 *jd)
+std::optional<qint64> QGregorianCalendar::julianFromParts(int year, int month, int day)
{
- Q_ASSERT(jd);
if (!validParts(year, month, day))
- return false;
+ return std::nullopt;
const auto yearDays = yearMonthToYearDays(year, month);
const qint64 y = yearDays.year;
const qint64 fromYear = 365 * y + qDiv<4>(y) - qDiv<100>(y) + qDiv<400>(y);
- *jd = fromYear + yearDays.days + day + BaseJd ;
- return true;
+ return fromYear + yearDays.days + day + BaseJd;
}
QCalendar::YearMonthDay QGregorianCalendar::partsFromJulian(qint64 jd)
diff --git a/src/corelib/time/qgregoriancalendar_p.h b/src/corelib/time/qgregoriancalendar_p.h
index dc40937577..1093a7b9de 100644
--- a/src/corelib/time/qgregoriancalendar_p.h
+++ b/src/corelib/time/qgregoriancalendar_p.h
@@ -17,6 +17,8 @@
#include "qromancalendar_p.h"
+#include <optional>
+
QT_BEGIN_NAMESPACE
class Q_CORE_EXPORT QGregorianCalendar : public QRomanCalendar
@@ -32,12 +34,7 @@ public:
// Julian Day conversions:
bool dateToJulianDay(int year, int month, int day, qint64 *jd) const override;
QCalendar::YearMonthDay julianDayToDate(qint64 jd) const override;
-
- // Names of months (implemented in qlocale.cpp):
- QString monthName(const QLocale &locale, int month, int year,
- QLocale::FormatType format) const override;
- QString standaloneMonthName(const QLocale &locale, int month, int year,
- QLocale::FormatType format) const override;
+ qint64 matchCenturyToWeekday(const QCalendar::YearMonthDay &parts, int dow) const override;
// Static optimized versions for the benefit of QDate:
static int weekDayOfJulian(qint64 jd);
@@ -45,7 +42,7 @@ public:
static int monthLength(int month, int year);
static bool validParts(int year, int month, int day);
static QCalendar::YearMonthDay partsFromJulian(qint64 jd);
- static bool julianFromParts(int year, int month, int day, qint64 *jd);
+ static std::optional<qint64> julianFromParts(int year, int month, int day);
// Used internally:
static int yearStartWeekDay(int year);
static int yearSharingWeekDays(QDate date);
diff --git a/src/corelib/time/qhijricalendar_data_p.h b/src/corelib/time/qhijricalendar_data_p.h
index ea916589d7..a52bf1dc4e 100644
--- a/src/corelib/time/qhijricalendar_data_p.h
+++ b/src/corelib/time/qhijricalendar_data_p.h
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: Unicode-3.0
#ifndef QHIJRI_CALENDAR_DATA_P_H
#define QHIJRI_CALENDAR_DATA_P_H
@@ -25,8 +25,8 @@ namespace QtPrivate::Hijri {
// GENERATED PART STARTS HERE
/*
- This part of the file was generated on 2023-02-02 from the
- Common Locale Data Repository v42
+ This part of the file was generated on 2024-01-09 from the
+ Common Locale Data Repository v44.1
http://www.unicode.org/cldr/
@@ -40,6 +40,8 @@ static constexpr QCalendarLocale locale_data[] = {
{ 1, 0, 0, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// C/AnyScript/AnyTerritory
{ 2, 27, 90, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Abkhazian/Cyrillic/Georgia
{ 3, 66, 77, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Afar/Latin/Ethiopia
+ { 3, 66, 67, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Afar/Latin/Djibouti
+ { 3, 66, 74, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Afar/Latin/Eritrea
{ 4, 66, 216, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Afrikaans/Latin/South Africa
{ 4, 66, 162, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Afrikaans/Latin/Namibia
{ 5, 66, 40, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Aghem/Latin/Cameroon
@@ -75,7 +77,7 @@ static constexpr QCalendarLocale locale_data[] = {
{ 14, 4, 238, 672, 672, 672, 672, 768, 768, 96, 96, 96, 96, 26, 26 },// Arabic/Arabic/Tunisia
{ 14, 4, 245, 672, 672, 672, 672, 768, 768, 96, 96, 96, 96, 26, 26 },// Arabic/Arabic/United Arab Emirates
{ 14, 4, 257, 672, 672, 672, 672, 768, 768, 96, 96, 96, 96, 26, 26 },// Arabic/Arabic/Western Sahara
- { 14, 4, 258, 672, 672, 672, 672, 768, 768, 96, 96, 96, 96, 26, 26 },// Arabic/Arabic/World
+ { 14, 4, 258, 672, 672, 672, 672, 768, 768, 96, 96, 96, 96, 26, 26 },// Arabic/Arabic/world
{ 14, 4, 259, 672, 672, 672, 672, 768, 768, 96, 96, 96, 96, 26, 26 },// Arabic/Arabic/Yemen
{ 15, 66, 220, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Aragonese/Latin/Spain
{ 17, 5, 12, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Armenian/Armenian/Armenia
@@ -85,6 +87,8 @@ static constexpr QCalendarLocale locale_data[] = {
{ 21, 66, 169, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Atsam/Latin/Nigeria
{ 25, 66, 17, 936, 936, 1046, 1046, 184, 184,110,110, 71, 71, 26, 26 },// Azerbaijani/Latin/Azerbaijan
{ 25, 4, 112, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Azerbaijani/Arabic/Iran
+ { 25, 4, 113, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Azerbaijani/Arabic/Iraq
+ { 25, 4, 239, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Azerbaijani/Arabic/Turkey
{ 25, 27, 17, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Azerbaijani/Cyrillic/Azerbaijan
{ 26, 66, 40, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Bafia/Latin/Cameroon
{ 28, 66, 145, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Bambara/Latin/Mali
@@ -100,8 +104,8 @@ static constexpr QCalendarLocale locale_data[] = {
{ 38, 29, 110, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Bhojpuri/Devanagari/India
{ 40, 33, 74, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Blin/Ethiopic/Eritrea
{ 41, 29, 110, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Bodo/Devanagari/India
- { 42, 66, 29, 1247, 1247, 1346, 1346, 184, 184, 99, 99, 74, 74, 26, 26 },// Bosnian/Latin/Bosnia And Herzegovina
- { 42, 27, 29, 1420, 1510, 1607, 1607, 184, 184, 90, 97, 69, 69, 26, 26 },// Bosnian/Cyrillic/Bosnia And Herzegovina
+ { 42, 66, 29, 1247, 1247, 1346, 1346, 184, 184, 99, 99, 74, 74, 26, 26 },// Bosnian/Latin/Bosnia and Herzegovina
+ { 42, 27, 29, 1420, 1510, 1607, 1607, 184, 184, 90, 97, 69, 69, 26, 26 },// Bosnian/Cyrillic/Bosnia and Herzegovina
{ 43, 66, 84, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Breton/Latin/France
{ 45, 27, 36, 1676, 1676, 106, 106, 184, 184, 96, 96, 78, 78, 26, 26 },// Bulgarian/Cyrillic/Bulgaria
{ 46, 86, 161, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Burmese/Myanmar/Myanmar
@@ -134,7 +138,7 @@ static constexpr QCalendarLocale locale_data[] = {
{ 63, 66, 246, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Cornish/Latin/United Kingdom
{ 64, 66, 84, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Corsican/Latin/France
{ 66, 66, 60, 0, 0, 106, 106, 2251, 2251,106,106, 78, 78, 38, 38 },// Croatian/Latin/Croatia
- { 66, 66, 29, 0, 0, 106, 106, 2251, 2251,106,106, 78, 78, 38, 38 },// Croatian/Latin/Bosnia And Herzegovina
+ { 66, 66, 29, 0, 0, 106, 106, 2251, 2251,106,106, 78, 78, 38, 38 },// Croatian/Latin/Bosnia and Herzegovina
{ 67, 66, 64, 2289, 2289, 2418, 2418, 184, 184,129,129, 76, 76, 26, 26 },// Czech/Latin/Czechia
{ 68, 66, 65, 2494, 2494, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Danish/Latin/Denmark
{ 68, 66, 95, 2494, 2494, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Danish/Latin/Greenland
@@ -154,7 +158,7 @@ static constexpr QCalendarLocale locale_data[] = {
{ 75, 28, 248, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Deseret/United States
{ 75, 66, 5, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/American Samoa
{ 75, 66, 8, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Anguilla
- { 75, 66, 10, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Antigua And Barbuda
+ { 75, 66, 10, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Antigua and Barbuda
{ 75, 66, 15, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Australia
{ 75, 66, 16, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Austria
{ 75, 66, 18, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Bahamas
@@ -192,8 +196,9 @@ static constexpr QCalendarLocale locale_data[] = {
{ 75, 66, 103, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Guyana
{ 75, 66, 107, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Hong Kong
{ 75, 66, 110, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/India
+ { 75, 66, 111, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Indonesia
{ 75, 66, 114, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Ireland
- { 75, 66, 115, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Isle Of Man
+ { 75, 66, 115, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Isle of Man
{ 75, 66, 116, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Israel
{ 75, 66, 119, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Jamaica
{ 75, 66, 121, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Jersey
@@ -227,9 +232,9 @@ static constexpr QCalendarLocale locale_data[] = {
{ 75, 66, 189, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Puerto Rico
{ 75, 66, 194, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Rwanda
{ 75, 66, 196, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Saint Helena
- { 75, 66, 197, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Saint Kitts And Nevis
+ { 75, 66, 197, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Saint Kitts and Nevis
{ 75, 66, 198, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Saint Lucia
- { 75, 66, 201, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Saint Vincent And Grenadines
+ { 75, 66, 201, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Saint Vincent and Grenadines
{ 75, 66, 202, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Samoa
{ 75, 66, 208, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Seychelles
{ 75, 66, 209, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Sierra Leone
@@ -245,8 +250,8 @@ static constexpr QCalendarLocale locale_data[] = {
{ 75, 66, 230, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Tanzania
{ 75, 66, 234, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Tokelau
{ 75, 66, 235, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Tonga
- { 75, 66, 236, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Trinidad And Tobago
- { 75, 66, 241, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Turks And Caicos Islands
+ { 75, 66, 236, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Trinidad and Tobago
+ { 75, 66, 241, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Turks and Caicos Islands
{ 75, 66, 242, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Tuvalu
{ 75, 66, 243, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Uganda
{ 75, 66, 245, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/United Arab Emirates
@@ -254,12 +259,12 @@ static constexpr QCalendarLocale locale_data[] = {
{ 75, 66, 247, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/United States Outlying Islands
{ 75, 66, 249, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/United States Virgin Islands
{ 75, 66, 252, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Vanuatu
- { 75, 66, 258, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/World
+ { 75, 66, 258, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/world
{ 75, 66, 260, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Zambia
{ 75, 66, 261, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Latin/Zimbabwe
{ 75, 115, 246, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// English/Shavian/United Kingdom
{ 76, 27, 193, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Erzya/Cyrillic/Russia
- { 77, 66, 258, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Esperanto/Latin/World
+ { 77, 66, 258, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Esperanto/Latin/world
{ 78, 66, 75, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Estonian/Latin/Estonia
{ 79, 66, 92, 2817, 2817, 2903, 2903, 184, 184, 86, 86, 47, 47, 26, 26 },// Ewe/Latin/Ghana
{ 79, 66, 233, 2817, 2817, 2903, 2903, 184, 184, 86, 86, 47, 47, 26, 26 },// Ewe/Latin/Togo
@@ -279,8 +284,8 @@ static constexpr QCalendarLocale locale_data[] = {
{ 85, 66, 46, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Central African Republic
{ 85, 66, 48, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Chad
{ 85, 66, 55, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Comoros
- { 85, 66, 56, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Congo Brazzaville
- { 85, 66, 57, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Congo Kinshasa
+ { 85, 66, 56, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Congo - Brazzaville
+ { 85, 66, 57, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Congo - Kinshasa
{ 85, 66, 67, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Djibouti
{ 85, 66, 73, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Equatorial Guinea
{ 85, 66, 85, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/French Guiana
@@ -305,7 +310,7 @@ static constexpr QCalendarLocale locale_data[] = {
{ 85, 66, 194, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Rwanda
{ 85, 66, 195, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Saint Barthelemy
{ 85, 66, 199, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Saint Martin
- { 85, 66, 200, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Saint Pierre And Miquelon
+ { 85, 66, 200, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Saint Pierre and Miquelon
{ 85, 66, 206, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Senegal
{ 85, 66, 208, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Seychelles
{ 85, 66, 226, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Switzerland
@@ -313,14 +318,14 @@ static constexpr QCalendarLocale locale_data[] = {
{ 85, 66, 233, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Togo
{ 85, 66, 238, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Tunisia
{ 85, 66, 252, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Vanuatu
- { 85, 66, 256, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Wallis And Futuna
+ { 85, 66, 256, 3079, 3079, 3218, 3308, 184, 184,139,139, 90, 90, 26, 26 },// French/Latin/Wallis and Futuna
{ 86, 66, 117, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Friulian/Latin/Italy
{ 87, 66, 206, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Fulah/Latin/Senegal
{ 87, 1, 37, 3398, 3398, 3651, 3651, 3746, 3746,253,253, 95, 95, 41, 41 },// Fulah/Adlam/Burkina Faso
{ 87, 1, 40, 3398, 3398, 3651, 3651, 3746, 3746,253,253, 95, 95, 41, 41 },// Fulah/Adlam/Cameroon
{ 87, 1, 89, 3398, 3398, 3651, 3651, 3746, 3746,253,253, 95, 95, 41, 41 },// Fulah/Adlam/Gambia
{ 87, 1, 92, 3398, 3398, 3651, 3651, 3746, 3746,253,253, 95, 95, 41, 41 },// Fulah/Adlam/Ghana
- { 87, 1, 101, 3398, 3398, 3651, 3651, 3746, 3746,253,253, 95, 95, 41, 41 },// Fulah/Adlam/Guinea Bissau
+ { 87, 1, 101, 3398, 3398, 3651, 3651, 3746, 3746,253,253, 95, 95, 41, 41 },// Fulah/Adlam/Guinea-Bissau
{ 87, 1, 102, 3398, 3398, 3651, 3651, 3746, 3746,253,253, 95, 95, 41, 41 },// Fulah/Adlam/Guinea
{ 87, 1, 134, 3398, 3398, 3651, 3651, 3746, 3746,253,253, 95, 95, 41, 41 },// Fulah/Adlam/Liberia
{ 87, 1, 149, 3398, 3398, 3651, 3651, 3746, 3746,253,253, 95, 95, 41, 41 },// Fulah/Adlam/Mauritania
@@ -332,7 +337,7 @@ static constexpr QCalendarLocale locale_data[] = {
{ 87, 66, 40, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Fulah/Latin/Cameroon
{ 87, 66, 89, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Fulah/Latin/Gambia
{ 87, 66, 92, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Fulah/Latin/Ghana
- { 87, 66, 101, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Fulah/Latin/Guinea Bissau
+ { 87, 66, 101, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Fulah/Latin/Guinea-Bissau
{ 87, 66, 102, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Fulah/Latin/Guinea
{ 87, 66, 134, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Fulah/Latin/Liberia
{ 87, 66, 149, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Fulah/Latin/Mauritania
@@ -344,6 +349,7 @@ static constexpr QCalendarLocale locale_data[] = {
{ 90, 66, 220, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Galician/Latin/Spain
{ 91, 66, 243, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Ganda/Latin/Uganda
{ 92, 33, 77, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Geez/Ethiopic/Ethiopia
+ { 92, 33, 74, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Geez/Ethiopic/Eritrea
{ 93, 35, 90, 3787, 3787, 3911, 3911, 184, 184,124,124, 73, 73, 26, 26 },// Georgian/Georgian/Georgia
{ 94, 66, 91, 3984, 3984, 106, 106, 184, 184,116,116, 78, 78, 26, 26 },// German/Latin/Germany
{ 94, 66, 16, 3984, 3984, 106, 106, 184, 184,116,116, 78, 78, 26, 26 },// German/Latin/Austria
@@ -359,19 +365,21 @@ static constexpr QCalendarLocale locale_data[] = {
{ 99, 66, 124, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Gusii/Latin/Kenya
{ 101, 66, 169, 4272, 4272, 106, 106, 184, 184,107,107, 78, 78, 26, 26 },// Hausa/Latin/Nigeria
{ 101, 4, 169, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Hausa/Arabic/Nigeria
+ { 101, 4, 222, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Hausa/Arabic/Sudan
{ 101, 66, 92, 4272, 4272, 106, 106, 184, 184,107,107, 78, 78, 26, 26 },// Hausa/Latin/Ghana
{ 101, 66, 170, 4272, 4272, 106, 106, 184, 184,107,107, 78, 78, 26, 26 },// Hausa/Latin/Niger
{ 102, 66, 248, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Hawaiian/Latin/United States
{ 103, 47, 116, 4379, 4495, 4611, 4611, 184, 184,116,116, 95, 95, 26, 26 },// Hebrew/Hebrew/Israel
{ 105, 29, 110, 4706, 4706, 106, 106, 184, 184,108,108, 78, 78, 26, 26 },// Hindi/Devanagari/India
- { 105, 66, 110, 4814, 4814, 4944, 4944, 184, 184,130,130, 63, 63, 26, 26 },// Hindi/Latin/India
+ { 105, 66, 110, 0, 4814, 106, 4944, 184, 184,106,130, 78, 63, 26, 26 },// Hindi/Latin/India
{ 107, 66, 108, 5007, 5106, 5233, 5233, 184, 184, 99,127, 76, 76, 26, 26 },// Hungarian/Latin/Hungary
{ 108, 66, 109, 2494, 2494, 5309, 5309, 184, 184,106,106, 78, 78, 26, 26 },// Icelandic/Latin/Iceland
- { 109, 66, 258, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Ido/Latin/World
+ { 109, 66, 258, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Ido/Latin/world
{ 110, 66, 169, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Igbo/Latin/Nigeria
{ 111, 66, 83, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Inari Sami/Latin/Finland
{ 112, 66, 111, 5387, 5387, 5496, 5496, 184, 184,109,109, 86, 86, 26, 26 },// Indonesian/Latin/Indonesia
- { 114, 66, 258, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Interlingua/Latin/World
+ { 114, 66, 258, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Interlingua/Latin/world
+ { 115, 66, 75, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Interlingue/Latin/Estonia
{ 116, 18, 41, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Inuktitut/Canadian Aboriginal/Canada
{ 116, 66, 41, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Inuktitut/Latin/Canada
{ 118, 66, 114, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Irish/Latin/Ireland
@@ -383,7 +391,7 @@ static constexpr QCalendarLocale locale_data[] = {
{ 120, 53, 120, 5582, 5582, 5582, 5582, 184, 184, 97, 97, 97, 97, 26, 26 },// Japanese/Japanese/Japan
{ 121, 66, 111, 5679, 5679, 5765, 5765, 184, 184, 86, 86, 72, 72, 26, 26 },// Javanese/Latin/Indonesia
{ 122, 66, 169, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Jju/Latin/Nigeria
- { 123, 66, 206, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Jola Fonyi/Latin/Senegal
+ { 123, 66, 206, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Jola-Fonyi/Latin/Senegal
{ 124, 66, 43, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Kabuverdianu/Latin/Cape Verde
{ 125, 66, 4, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Kabyle/Latin/Algeria
{ 126, 66, 40, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Kako/Latin/Cameroon
@@ -393,59 +401,63 @@ static constexpr QCalendarLocale locale_data[] = {
{ 130, 56, 110, 5837, 5837, 5937, 5937, 184, 184,100,100, 79, 79, 26, 26 },// Kannada/Kannada/India
{ 132, 4, 110, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Kashmiri/Arabic/India
{ 132, 29, 110, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Kashmiri/Devanagari/India
- { 133, 27, 123, 6016, 6016, 6139, 6139, 184, 184,123,123, 62, 62, 26, 26 },// Kazakh/Cyrillic/Kazakhstan
+ { 133, 27, 123, 6016, 6016, 6139, 6213, 184, 184,123,123, 74, 62, 26, 26 },// Kazakh/Cyrillic/Kazakhstan
{ 134, 66, 40, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Kenyang/Latin/Cameroon
{ 135, 60, 39, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Khmer/Khmer/Cambodia
{ 136, 66, 99, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Kiche/Latin/Guatemala
{ 137, 66, 124, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Kikuyu/Latin/Kenya
{ 138, 66, 194, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Kinyarwanda/Latin/Rwanda
{ 141, 29, 110, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Konkani/Devanagari/India
- { 142, 63, 218, 6201, 6201, 106, 106, 184, 184, 69, 69, 78, 78, 26, 26 },// Korean/Korean/South Korea
- { 142, 63, 174, 6201, 6201, 106, 106, 184, 184, 69, 69, 78, 78, 26, 26 },// Korean/Korean/North Korea
+ { 142, 63, 218, 6275, 6275, 106, 106, 184, 184, 69, 69, 78, 78, 26, 26 },// Korean/Korean/South Korea
+ { 142, 63, 50, 6275, 6275, 106, 106, 184, 184, 69, 69, 78, 78, 26, 26 },// Korean/Korean/China
+ { 142, 63, 174, 6275, 6275, 106, 106, 184, 184, 69, 69, 78, 78, 26, 26 },// Korean/Korean/North Korea
{ 144, 66, 145, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Koyraboro Senni/Latin/Mali
{ 145, 66, 145, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Koyra Chiini/Latin/Mali
{ 146, 66, 134, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Kpelle/Latin/Liberia
- { 148, 66, 239, 6270, 6270, 106, 106, 184, 184,109,109, 78, 78, 26, 26 },// Kurdish/Latin/Turkey
+ { 146, 66, 102, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Kpelle/Latin/Guinea
+ { 148, 66, 239, 6344, 6344, 6453, 6453, 184, 184,109,109, 79, 79, 26, 26 },// Kurdish/Latin/Turkey
{ 149, 66, 40, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Kwasio/Latin/Cameroon
{ 150, 27, 128, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Kyrgyz/Cyrillic/Kyrgyzstan
{ 151, 66, 248, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Lakota/Latin/United States
{ 152, 66, 230, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Langi/Latin/Tanzania
- { 153, 65, 129, 6379, 6379, 6474, 6549, 184, 184, 95, 95, 75, 77, 26, 26 },// Lao/Lao/Laos
+ { 153, 65, 129, 6532, 6532, 6627, 6702, 184, 184, 95, 95, 75, 77, 26, 26 },// Lao/Lao/Laos
{ 154, 66, 253, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Latin/Latin/Vatican City
- { 155, 66, 131, 6626, 6626, 106, 106, 184, 184,108,108, 78, 78, 26, 26 },// Latvian/Latin/Latvia
- { 158, 66, 57, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Lingala/Latin/Congo Kinshasa
+ { 155, 66, 131, 6779, 6779, 106, 106, 184, 184,108,108, 78, 78, 26, 26 },// Latvian/Latin/Latvia
+ { 158, 66, 57, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Lingala/Latin/Congo - Kinshasa
{ 158, 66, 7, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Lingala/Latin/Angola
{ 158, 66, 46, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Lingala/Latin/Central African Republic
- { 158, 66, 56, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Lingala/Latin/Congo Brazzaville
+ { 158, 66, 56, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Lingala/Latin/Congo - Brazzaville
{ 160, 66, 137, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Lithuanian/Latin/Lithuania
- { 161, 66, 258, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Lojban/Latin/World
+ { 161, 66, 258, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Lojban/Latin/world
{ 162, 66, 91, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Lower Sorbian/Latin/Germany
{ 163, 66, 91, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Low German/Latin/Germany
{ 163, 66, 165, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Low German/Latin/Netherlands
- { 164, 66, 57, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Luba Katanga/Latin/Congo Kinshasa
+ { 164, 66, 57, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Luba-Katanga/Latin/Congo - Kinshasa
{ 165, 66, 225, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Lule Sami/Latin/Sweden
+ { 165, 66, 175, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Lule Sami/Latin/Norway
{ 166, 66, 124, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Luo/Latin/Kenya
{ 167, 66, 138, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Luxembourgish/Latin/Luxembourg
{ 168, 66, 124, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Luyia/Latin/Kenya
- { 169, 27, 140, 6734, 6734, 6823, 6823, 184, 184, 89, 89, 71, 71, 26, 26 },// Macedonian/Cyrillic/Macedonia
+ { 169, 27, 140, 6887, 6887, 6976, 6976, 184, 184, 89, 89, 71, 71, 26, 26 },// Macedonian/Cyrillic/Macedonia
{ 170, 66, 230, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Machame/Latin/Tanzania
{ 171, 29, 110, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Maithili/Devanagari/India
- { 172, 66, 160, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Makhuwa Meetto/Latin/Mozambique
+ { 172, 66, 160, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Makhuwa-Meetto/Latin/Mozambique
{ 173, 66, 230, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Makonde/Latin/Tanzania
{ 174, 66, 141, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Malagasy/Latin/Madagascar
- { 175, 74, 110, 6894, 6996, 7098, 7098, 7195, 7195,102,102, 97, 97, 26, 26 },// Malayalam/Malayalam/India
- { 176, 66, 143, 7221, 7221, 7330, 7330, 184, 184,109,109, 73, 73, 26, 26 },// Malay/Latin/Malaysia
+ { 175, 74, 110, 7047, 7149, 7251, 7251, 7348, 7348,102,102, 97, 97, 26, 26 },// Malayalam/Malayalam/India
+ { 176, 66, 143, 7374, 7374, 7483, 7483, 184, 184,109,109, 73, 73, 26, 26 },// Malay/Latin/Malaysia
+ { 176, 4, 35, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Malay/Arabic/Brunei
{ 176, 4, 143, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Malay/Arabic/Malaysia
- { 176, 66, 35, 7221, 7221, 7330, 7330, 184, 184,109,109, 73, 73, 26, 26 },// Malay/Latin/Brunei
- { 176, 66, 111, 7221, 7221, 7330, 7330, 184, 184,109,109, 73, 73, 26, 26 },// Malay/Latin/Indonesia
- { 176, 66, 210, 7221, 7221, 7330, 7330, 184, 184,109,109, 73, 73, 26, 26 },// Malay/Latin/Singapore
+ { 176, 66, 35, 7374, 7374, 7483, 7483, 184, 184,109,109, 73, 73, 26, 26 },// Malay/Latin/Brunei
+ { 176, 66, 111, 7374, 7374, 7483, 7483, 184, 184,109,109, 73, 73, 26, 26 },// Malay/Latin/Indonesia
+ { 176, 66, 210, 7374, 7374, 7483, 7483, 184, 184,109,109, 73, 73, 26, 26 },// Malay/Latin/Singapore
{ 177, 66, 146, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Maltese/Latin/Malta
{ 179, 9, 110, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Manipuri/Bangla/India
{ 179, 78, 110, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Manipuri/Meitei Mayek/India
- { 180, 66, 115, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Manx/Latin/Isle Of Man
+ { 180, 66, 115, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Manx/Latin/Isle of Man
{ 181, 66, 167, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Maori/Latin/New Zealand
{ 182, 66, 49, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Mapuche/Latin/Chile
- { 183, 29, 110, 7403, 7403, 7490, 7490, 7568, 7568, 87, 87, 78, 78, 26, 26 },// Marathi/Devanagari/India
+ { 183, 29, 110, 7556, 7556, 7643, 7643, 7721, 7721, 87, 87, 78, 78, 26, 26 },// Marathi/Devanagari/India
{ 185, 66, 124, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Masai/Latin/Kenya
{ 185, 66, 230, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Masai/Latin/Tanzania
{ 186, 4, 112, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Mazanderani/Arabic/Iran
@@ -454,6 +466,7 @@ static constexpr QCalendarLocale locale_data[] = {
{ 190, 66, 41, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Mohawk/Latin/Canada
{ 191, 27, 156, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Mongolian/Cyrillic/Mongolia
{ 191, 83, 50, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Mongolian/Mongolian/China
+ { 191, 83, 156, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Mongolian/Mongolian/Mongolia
{ 192, 66, 150, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Morisyen/Latin/Mauritius
{ 193, 66, 40, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Mundang/Latin/Cameroon
{ 194, 66, 248, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Muscogee/Latin/United States
@@ -472,9 +485,9 @@ static constexpr QCalendarLocale locale_data[] = {
{ 206, 66, 225, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Northern Sami/Latin/Sweden
{ 207, 66, 216, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Northern Sotho/Latin/South Africa
{ 208, 66, 261, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// North Ndebele/Latin/Zimbabwe
- { 209, 66, 175, 7594, 7594, 7700, 7778, 184, 184,106,106, 78, 78, 26, 26 },// Norwegian Bokmal/Latin/Norway
- { 209, 66, 224, 7594, 7594, 7700, 7778, 184, 184,106,106, 78, 78, 26, 26 },// Norwegian Bokmal/Latin/Svalbard And Jan Mayen
- { 210, 66, 175, 7594, 7594, 7700, 7778, 184, 184,106,106, 78, 78, 26, 26 },// Norwegian Nynorsk/Latin/Norway
+ { 209, 66, 175, 7747, 7747, 7853, 7931, 184, 184,106,106, 78, 78, 26, 26 },// Norwegian Bokmal/Latin/Norway
+ { 209, 66, 224, 7747, 7747, 7853, 7931, 184, 184,106,106, 78, 78, 26, 26 },// Norwegian Bokmal/Latin/Svalbard and Jan Mayen
+ { 210, 66, 175, 7747, 7747, 7853, 7931, 184, 184,106,106, 78, 78, 26, 26 },// Norwegian Nynorsk/Latin/Norway
{ 211, 66, 219, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Nuer/Latin/South Sudan
{ 212, 66, 142, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Nyanja/Latin/Malawi
{ 213, 66, 243, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Nyankole/Latin/Uganda
@@ -486,25 +499,27 @@ static constexpr QCalendarLocale locale_data[] = {
{ 221, 101, 248, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Osage/Osage/United States
{ 222, 27, 90, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Ossetic/Cyrillic/Georgia
{ 222, 27, 193, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Ossetic/Cyrillic/Russia
- { 227, 4, 1, 7856, 7930, 8005, 8078, 184, 184, 74, 75, 73, 73, 26, 26 },// Pashto/Arabic/Afghanistan
- { 227, 4, 178, 8151, 8230, 8005, 8078, 184, 184, 79, 80, 73, 73, 26, 26 },// Pashto/Arabic/Pakistan
- { 228, 4, 112, 8310, 8400, 8310, 8400, 8492, 8492, 90, 92, 90, 92, 23, 23 },// Persian/Arabic/Iran
- { 228, 4, 1, 8310, 8400, 8310, 8400, 8492, 8492, 90, 92, 90, 92, 23, 23 },// Persian/Arabic/Afghanistan
- { 230, 66, 187, 8515, 8515, 8622, 8622, 184, 184,107,107, 77, 77, 26, 26 },// Polish/Latin/Poland
+ { 226, 66, 62, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Papiamento/Latin/Curacao
+ { 226, 66, 13, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Papiamento/Latin/Aruba
+ { 227, 4, 1, 8009, 8009, 8084, 8084, 184, 184, 75, 75, 73, 73, 26, 26 },// Pashto/Arabic/Afghanistan
+ { 227, 4, 178, 8157, 8157, 8084, 8084, 184, 184, 80, 80, 73, 73, 26, 26 },// Pashto/Arabic/Pakistan
+ { 228, 4, 112, 8237, 8237, 8237, 8237, 8327, 8327, 90, 90, 90, 90, 23, 23 },// Persian/Arabic/Iran
+ { 228, 4, 1, 8237, 8237, 8237, 8237, 8327, 8327, 90, 90, 90, 90, 23, 23 },// Persian/Arabic/Afghanistan
+ { 230, 66, 187, 8350, 8350, 8457, 8457, 184, 184,107,107, 77, 77, 26, 26 },// Polish/Latin/Poland
{ 231, 66, 32, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Portuguese/Latin/Brazil
{ 231, 66, 7, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Portuguese/Latin/Angola
{ 231, 66, 43, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Portuguese/Latin/Cape Verde
{ 231, 66, 73, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Portuguese/Latin/Equatorial Guinea
- { 231, 66, 101, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Portuguese/Latin/Guinea Bissau
+ { 231, 66, 101, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Portuguese/Latin/Guinea-Bissau
{ 231, 66, 138, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Portuguese/Latin/Luxembourg
{ 231, 66, 139, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Portuguese/Latin/Macao
{ 231, 66, 160, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Portuguese/Latin/Mozambique
{ 231, 66, 188, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Portuguese/Latin/Portugal
- { 231, 66, 204, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Portuguese/Latin/Sao Tome And Principe
+ { 231, 66, 204, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Portuguese/Latin/Sao Tome and Principe
{ 231, 66, 226, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Portuguese/Latin/Switzerland
{ 231, 66, 232, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Portuguese/Latin/Timor-Leste
- { 232, 66, 258, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Prussian/Latin/World
- { 233, 41, 110, 8699, 8791, 8885, 8885, 184, 184, 92, 94, 77, 77, 26, 26 },// Punjabi/Gurmukhi/India
+ { 232, 66, 187, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Prussian/Latin/Poland
+ { 233, 41, 110, 8534, 8626, 8720, 8720, 184, 184, 92, 94, 77, 77, 26, 26 },// Punjabi/Gurmukhi/India
{ 233, 4, 178, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Punjabi/Arabic/Pakistan
{ 234, 66, 184, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Quechua/Latin/Peru
{ 234, 66, 28, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Quechua/Latin/Bolivia
@@ -514,12 +529,12 @@ static constexpr QCalendarLocale locale_data[] = {
{ 236, 66, 226, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Romansh/Latin/Switzerland
{ 237, 66, 230, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Rombo/Latin/Tanzania
{ 238, 66, 38, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Rundi/Latin/Burundi
- { 239, 27, 193, 8962, 8962, 9093, 9093, 184, 184,131,131, 79, 79, 26, 26 },// Russian/Cyrillic/Russia
- { 239, 27, 22, 8962, 8962, 9093, 9093, 184, 184,131,131, 79, 79, 26, 26 },// Russian/Cyrillic/Belarus
- { 239, 27, 123, 8962, 8962, 9093, 9093, 184, 184,131,131, 79, 79, 26, 26 },// Russian/Cyrillic/Kazakhstan
- { 239, 27, 128, 8962, 8962, 9093, 9093, 184, 184,131,131, 79, 79, 26, 26 },// Russian/Cyrillic/Kyrgyzstan
- { 239, 27, 154, 8962, 8962, 9093, 9093, 184, 184,131,131, 79, 79, 26, 26 },// Russian/Cyrillic/Moldova
- { 239, 27, 244, 8962, 8962, 9093, 9093, 184, 184,131,131, 79, 79, 26, 26 },// Russian/Cyrillic/Ukraine
+ { 239, 27, 193, 8797, 8797, 8928, 8928, 184, 184,131,131, 79, 79, 26, 26 },// Russian/Cyrillic/Russia
+ { 239, 27, 22, 8797, 8797, 8928, 8928, 184, 184,131,131, 79, 79, 26, 26 },// Russian/Cyrillic/Belarus
+ { 239, 27, 123, 8797, 8797, 8928, 8928, 184, 184,131,131, 79, 79, 26, 26 },// Russian/Cyrillic/Kazakhstan
+ { 239, 27, 128, 8797, 8797, 8928, 8928, 184, 184,131,131, 79, 79, 26, 26 },// Russian/Cyrillic/Kyrgyzstan
+ { 239, 27, 154, 8797, 8797, 8928, 8928, 184, 184,131,131, 79, 79, 26, 26 },// Russian/Cyrillic/Moldova
+ { 239, 27, 244, 8797, 8797, 8928, 8928, 184, 184,131,131, 79, 79, 26, 26 },// Russian/Cyrillic/Ukraine
{ 240, 66, 230, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Rwa/Latin/Tanzania
{ 241, 66, 74, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Saho/Latin/Eritrea
{ 242, 27, 193, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Sakha/Cyrillic/Russia
@@ -529,44 +544,47 @@ static constexpr QCalendarLocale locale_data[] = {
{ 247, 29, 110, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Sanskrit/Devanagari/India
{ 248, 93, 110, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Santali/Ol Chiki/India
{ 248, 29, 110, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Santali/Devanagari/India
- { 249, 66, 117, 9172, 9172, 7778, 7778, 184, 184,105,105, 78, 78, 26, 26 },// Sardinian/Latin/Italy
+ { 249, 66, 117, 9007, 9007, 7931, 7931, 184, 184,105,105, 78, 78, 26, 26 },// Sardinian/Latin/Italy
{ 251, 66, 160, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Sena/Latin/Mozambique
- { 252, 27, 207, 1420, 9277, 1607, 1607, 184, 184, 90, 97, 69, 69, 26, 26 },// Serbian/Cyrillic/Serbia
- { 252, 27, 29, 1420, 9277, 1607, 1607, 184, 184, 90, 97, 69, 69, 26, 26 },// Serbian/Cyrillic/Bosnia And Herzegovina
- { 252, 27, 126, 1420, 9277, 1607, 1607, 184, 184, 90, 97, 69, 69, 26, 26 },// Serbian/Cyrillic/Kosovo
- { 252, 27, 157, 1420, 9277, 1607, 1607, 184, 184, 90, 97, 69, 69, 26, 26 },// Serbian/Cyrillic/Montenegro
- { 252, 66, 29, 9374, 9468, 9565, 9565, 184, 184, 94, 97, 72, 72, 26, 26 },// Serbian/Latin/Bosnia And Herzegovina
- { 252, 66, 126, 9374, 9468, 9565, 9565, 184, 184, 94, 97, 72, 72, 26, 26 },// Serbian/Latin/Kosovo
- { 252, 66, 157, 9374, 9468, 9565, 9565, 184, 184, 94, 97, 72, 72, 26, 26 },// Serbian/Latin/Montenegro
- { 252, 66, 207, 9374, 9468, 9565, 9565, 184, 184, 94, 97, 72, 72, 26, 26 },// Serbian/Latin/Serbia
+ { 252, 27, 207, 1420, 9112, 1607, 1607, 184, 184, 90, 97, 69, 69, 26, 26 },// Serbian/Cyrillic/Serbia
+ { 252, 27, 29, 1420, 9112, 1607, 1607, 184, 184, 90, 97, 69, 69, 26, 26 },// Serbian/Cyrillic/Bosnia and Herzegovina
+ { 252, 27, 126, 1420, 9112, 1607, 1607, 184, 184, 90, 97, 69, 69, 26, 26 },// Serbian/Cyrillic/Kosovo
+ { 252, 27, 157, 1420, 9112, 1607, 1607, 184, 184, 90, 97, 69, 69, 26, 26 },// Serbian/Cyrillic/Montenegro
+ { 252, 66, 29, 9209, 9303, 9400, 9400, 184, 184, 94, 97, 72, 72, 26, 26 },// Serbian/Latin/Bosnia and Herzegovina
+ { 252, 66, 126, 9209, 9303, 9400, 9400, 184, 184, 94, 97, 72, 72, 26, 26 },// Serbian/Latin/Kosovo
+ { 252, 66, 157, 9209, 9303, 9400, 9400, 184, 184, 94, 97, 72, 72, 26, 26 },// Serbian/Latin/Montenegro
+ { 252, 66, 207, 9209, 9303, 9400, 9400, 184, 184, 94, 97, 72, 72, 26, 26 },// Serbian/Latin/Serbia
{ 253, 66, 230, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Shambala/Latin/Tanzania
{ 254, 66, 261, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Shona/Latin/Zimbabwe
{ 255, 141, 50, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Sichuan Yi/Yi/China
{ 256, 66, 117, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Sicilian/Latin/Italy
{ 257, 66, 77, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Sidamo/Latin/Ethiopia
{ 258, 66, 187, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Silesian/Latin/Poland
- { 259, 4, 178, 9637, 9637, 9637, 9637, 184, 184, 91, 91, 91, 91, 26, 26 },// Sindhi/Arabic/Pakistan
+ { 259, 4, 178, 9472, 9472, 9472, 9472, 184, 184, 91, 91, 91, 91, 26, 26 },// Sindhi/Arabic/Pakistan
{ 259, 29, 110, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Sindhi/Devanagari/India
{ 260, 119, 221, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Sinhala/Sinhala/Sri Lanka
{ 261, 66, 83, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Skolt Sami/Latin/Finland
- { 262, 66, 212, 9728, 9728, 9863, 9863, 184, 184,135,135, 78, 78, 26, 26 },// Slovak/Latin/Slovakia
+ { 262, 66, 212, 9563, 9563, 9698, 9698, 184, 184,135,135, 78, 78, 26, 26 },// Slovak/Latin/Slovakia
{ 263, 66, 213, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Slovenian/Latin/Slovenia
{ 264, 66, 243, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Soga/Latin/Uganda
- { 265, 66, 215, 9941,10072,10202,10276, 184, 184,131,130, 74, 81, 26, 26 },// Somali/Latin/Somalia
- { 265, 66, 67, 9941,10072,10202,10276, 184, 184,131,130, 74, 81, 26, 26 },// Somali/Latin/Djibouti
- { 265, 66, 77, 9941,10072,10202,10276, 184, 184,131,130, 74, 81, 26, 26 },// Somali/Latin/Ethiopia
- { 265, 66, 124, 9941,10072,10202,10276, 184, 184,131,130, 74, 81, 26, 26 },// Somali/Latin/Kenya
+ { 265, 66, 215, 9776, 9907,10037,10111, 184, 184,131,130, 74, 81, 26, 26 },// Somali/Latin/Somalia
+ { 265, 66, 67, 9776, 9907,10037,10111, 184, 184,131,130, 74, 81, 26, 26 },// Somali/Latin/Djibouti
+ { 265, 66, 77, 9776, 9907,10037,10111, 184, 184,131,130, 74, 81, 26, 26 },// Somali/Latin/Ethiopia
+ { 265, 66, 124, 9776, 9907,10037,10111, 184, 184,131,130, 74, 81, 26, 26 },// Somali/Latin/Kenya
{ 266, 4, 112, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Southern Kurdish/Arabic/Iran
+ { 266, 4, 113, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Southern Kurdish/Arabic/Iraq
{ 267, 66, 225, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Southern Sami/Latin/Sweden
+ { 267, 66, 175, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Southern Sami/Latin/Norway
{ 268, 66, 216, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Southern Sotho/Latin/South Africa
+ { 268, 66, 133, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Southern Sotho/Latin/Lesotho
{ 269, 66, 216, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// South Ndebele/Latin/South Africa
- { 270, 66, 220,10357,10357, 7778, 7778, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Spain
+ { 270, 66, 220,10192,10192, 7931, 7931, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Spain
{ 270, 66, 11, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Argentina
{ 270, 66, 24, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Belize
{ 270, 66, 28, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Bolivia
{ 270, 66, 32, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Brazil
- { 270, 66, 42,10357,10357, 7778, 7778, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Canary Islands
- { 270, 66, 47,10357,10357, 7778, 7778, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Ceuta And Melilla
+ { 270, 66, 42,10192,10192, 7931, 7931, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Canary Islands
+ { 270, 66, 47,10192,10192, 7931, 7931, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Ceuta and Melilla
{ 270, 66, 49, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Chile
{ 270, 66, 54, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Colombia
{ 270, 66, 59, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Costa Rica
@@ -574,7 +592,7 @@ static constexpr QCalendarLocale locale_data[] = {
{ 270, 66, 69, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Dominican Republic
{ 270, 66, 70, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Ecuador
{ 270, 66, 72, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/El Salvador
- { 270, 66, 73,10357,10357, 7778, 7778, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Equatorial Guinea
+ { 270, 66, 73,10192,10192, 7931, 7931, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Equatorial Guinea
{ 270, 66, 99, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Guatemala
{ 270, 66, 106, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Honduras
{ 270, 66, 130, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Latin America
@@ -583,7 +601,7 @@ static constexpr QCalendarLocale locale_data[] = {
{ 270, 66, 181, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Panama
{ 270, 66, 183, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Paraguay
{ 270, 66, 184, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Peru
- { 270, 66, 185,10357,10357, 7778, 7778, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Philippines
+ { 270, 66, 185,10192,10192, 7931, 7931, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Philippines
{ 270, 66, 189, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Puerto Rico
{ 270, 66, 248, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/United States
{ 270, 66, 250, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Spanish/Latin/Uruguay
@@ -591,74 +609,82 @@ static constexpr QCalendarLocale locale_data[] = {
{ 271, 135, 159, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Standard Moroccan Tamazight/Tifinagh/Morocco
{ 272, 66, 111, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Sundanese/Latin/Indonesia
{ 273, 66, 230, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Swahili/Latin/Tanzania
- { 273, 66, 57, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Swahili/Latin/Congo Kinshasa
+ { 273, 66, 57, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Swahili/Latin/Congo - Kinshasa
{ 273, 66, 124, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Swahili/Latin/Kenya
{ 273, 66, 243, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Swahili/Latin/Uganda
{ 274, 66, 216, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Swati/Latin/South Africa
- { 275, 66, 225,10463,10590, 106, 106, 184, 184,127,127, 78, 78, 26, 26 },// Swedish/Latin/Sweden
- { 275, 66, 2,10463,10590, 106, 106, 184, 184,127,127, 78, 78, 26, 26 },// Swedish/Latin/Aland Islands
- { 275, 66, 83,10463,10590, 106, 106, 184, 184,127,127, 78, 78, 26, 26 },// Swedish/Latin/Finland
+ { 274, 66, 76, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Swati/Latin/Eswatini
+ { 275, 66, 225,10298,10425, 106, 106, 184, 184,127,127, 78, 78, 26, 26 },// Swedish/Latin/Sweden
+ { 275, 66, 2,10298,10425, 106, 106, 184, 184,127,127, 78, 78, 26, 26 },// Swedish/Latin/Aland Islands
+ { 275, 66, 83,10298,10425, 106, 106, 184, 184,127,127, 78, 78, 26, 26 },// Swedish/Latin/Finland
{ 276, 66, 226, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Swiss German/Latin/Switzerland
{ 276, 66, 84, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Swiss German/Latin/France
{ 276, 66, 136, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Swiss German/Latin/Liechtenstein
{ 277, 123, 113, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Syriac/Syriac/Iraq
+ { 277, 123, 227, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Syriac/Syriac/Syria
{ 278, 135, 159, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Tachelhit/Tifinagh/Morocco
{ 278, 66, 159, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Tachelhit/Latin/Morocco
{ 280, 127, 255, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Tai Dam/Tai Viet/Vietnam
{ 281, 66, 124, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Taita/Latin/Kenya
- { 282, 27, 229,10717,10827,10937,10937, 184, 184,110,110, 74, 74, 26, 26 },// Tajik/Cyrillic/Tajikistan
- { 283, 129, 110,11011,11011,11102,11102, 184, 184, 91, 91, 72, 72, 26, 26 },// Tamil/Tamil/India
- { 283, 129, 143,11011,11011,11102,11102, 184, 184, 91, 91, 72, 72, 26, 26 },// Tamil/Tamil/Malaysia
- { 283, 129, 210,11011,11011,11102,11102, 184, 184, 91, 91, 72, 72, 26, 26 },// Tamil/Tamil/Singapore
- { 283, 129, 221,11011,11011,11102,11102, 184, 184, 91, 91, 72, 72, 26, 26 },// Tamil/Tamil/Sri Lanka
+ { 282, 27, 229,10552,10662,10772,10772, 184, 184,110,110, 74, 74, 26, 26 },// Tajik/Cyrillic/Tajikistan
+ { 283, 129, 110,10846,10846,10937,10937, 184, 184, 91, 91, 72, 72, 26, 26 },// Tamil/Tamil/India
+ { 283, 129, 143,10846,10846,10937,10937, 184, 184, 91, 91, 72, 72, 26, 26 },// Tamil/Tamil/Malaysia
+ { 283, 129, 210,10846,10846,10937,10937, 184, 184, 91, 91, 72, 72, 26, 26 },// Tamil/Tamil/Singapore
+ { 283, 129, 221,10846,10846,10937,10937, 184, 184, 91, 91, 72, 72, 26, 26 },// Tamil/Tamil/Sri Lanka
{ 284, 66, 228, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Taroko/Latin/Taiwan
{ 285, 66, 170, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Tasawaq/Latin/Niger
{ 286, 27, 193, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Tatar/Cyrillic/Russia
- { 287, 131, 110,11174, 0,11269,11269, 184, 184, 95,106, 74, 74, 26, 26 },// Telugu/Telugu/India
+ { 287, 131, 110,11009, 0,11104,11104, 184, 184, 95,106, 74, 74, 26, 26 },// Telugu/Telugu/India
{ 288, 66, 243, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Teso/Latin/Uganda
{ 288, 66, 124, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Teso/Latin/Kenya
- { 289, 133, 231,11343,11343,11445,11445, 184, 184,102,102, 89, 89, 26, 26 },// Thai/Thai/Thailand
+ { 289, 133, 231,11178,11178,11280,11280, 184, 184,102,102, 89, 89, 26, 26 },// Thai/Thai/Thailand
{ 290, 134, 50, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Tibetan/Tibetan/China
{ 290, 134, 110, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Tibetan/Tibetan/India
{ 291, 33, 74, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Tigre/Ethiopic/Eritrea
{ 292, 33, 77, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Tigrinya/Ethiopic/Ethiopia
{ 292, 33, 74, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Tigrinya/Ethiopic/Eritrea
{ 294, 66, 182, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Tok Pisin/Latin/Papua New Guinea
- { 295, 66, 235,11534,11534,11633,11633, 184, 184, 99, 99, 60, 60, 26, 26 },// Tongan/Latin/Tonga
+ { 295, 66, 235,11369,11369,11468,11468, 184, 184, 99, 99, 60, 60, 26, 26 },// Tongan/Latin/Tonga
{ 296, 66, 216, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Tsonga/Latin/South Africa
{ 297, 66, 216, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Tswana/Latin/South Africa
- { 298, 66, 239,11693,11693,11803,11803, 184, 184,110,110, 83, 83, 26, 26 },// Turkish/Latin/Turkey
- { 298, 66, 63,11693,11693,11803,11803, 184, 184,110,110, 83, 83, 26, 26 },// Turkish/Latin/Cyprus
- { 299, 66, 240,11886,11886,11999,11999, 184, 184,113,113, 59, 59, 26, 26 },// Turkmen/Latin/Turkmenistan
+ { 297, 66, 30, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Tswana/Latin/Botswana
+ { 298, 66, 239,11528,11528,11638,11638, 184, 184,110,110, 83, 83, 26, 26 },// Turkish/Latin/Turkey
+ { 298, 66, 63,11528,11528,11638,11638, 184, 184,110,110, 83, 83, 26, 26 },// Turkish/Latin/Cyprus
+ { 299, 66, 240,11721,11721,11834,11834, 184, 184,113,113, 59, 59, 26, 26 },// Turkmen/Latin/Turkmenistan
{ 301, 66, 169, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Tyap/Latin/Nigeria
- { 303, 27, 244,12058,12058,12161,12232, 184, 184,103,103, 71, 81, 26, 26 },// Ukrainian/Cyrillic/Ukraine
+ { 303, 27, 244,11893,11893,11996,12067, 184, 184,103,103, 71, 81, 26, 26 },// Ukrainian/Cyrillic/Ukraine
{ 304, 66, 91, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Upper Sorbian/Latin/Germany
- { 305, 4, 178,12313,12313,12409,12507, 184, 184, 96, 96, 98, 96, 26, 26 },// Urdu/Arabic/Pakistan
- { 305, 4, 110,12313,12313,12409,12507, 184, 184, 96, 96, 98, 96, 26, 26 },// Urdu/Arabic/India
- { 306, 4, 50,12603,12603,12603,12603, 184, 184,118,118,118,118, 26, 26 },// Uyghur/Arabic/China
- { 307, 66, 251,12721,12721,12843,12843, 184, 184,122,122, 82, 82, 26, 26 },// Uzbek/Latin/Uzbekistan
+ { 305, 4, 178,12148,12148,12244,12342, 184, 184, 96, 96, 98, 96, 26, 26 },// Urdu/Arabic/Pakistan
+ { 305, 4, 110,12148,12148,12244,12342, 184, 184, 96, 96, 98, 96, 26, 26 },// Urdu/Arabic/India
+ { 306, 4, 50,12438,12438,12438,12438, 184, 184,118,118,118,118, 26, 26 },// Uyghur/Arabic/China
+ { 307, 66, 251,12556,12556,12678,12678, 184, 184,122,122, 82, 82, 26, 26 },// Uzbek/Latin/Uzbekistan
{ 307, 4, 1, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Uzbek/Arabic/Afghanistan
- { 307, 27, 251,12925,12925, 106, 106, 184, 184,114,114, 78, 78, 26, 26 },// Uzbek/Cyrillic/Uzbekistan
+ { 307, 27, 251,12760,12760, 106, 106, 184, 184,114,114, 78, 78, 26, 26 },// Uzbek/Cyrillic/Uzbekistan
{ 308, 139, 134, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Vai/Vai/Liberia
{ 308, 66, 134, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Vai/Latin/Liberia
{ 309, 66, 216, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Venda/Latin/South Africa
{ 310, 66, 255, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Vietnamese/Latin/Vietnam
- { 311, 66, 258, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Volapuk/Latin/World
+ { 311, 66, 258, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Volapuk/Latin/world
{ 312, 66, 230, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Vunjo/Latin/Tanzania
{ 313, 66, 23, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Walloon/Latin/Belgium
{ 314, 66, 226, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Walser/Latin/Switzerland
{ 315, 66, 15, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Warlpiri/Latin/Australia
{ 316, 66, 246, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Welsh/Latin/United Kingdom
{ 317, 4, 178, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Western Balochi/Arabic/Pakistan
+ { 317, 4, 1, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Western Balochi/Arabic/Afghanistan
+ { 317, 4, 112, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Western Balochi/Arabic/Iran
+ { 317, 4, 176, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Western Balochi/Arabic/Oman
+ { 317, 4, 245, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Western Balochi/Arabic/United Arab Emirates
{ 318, 66, 165, 2600, 2600, 2734, 2734, 184, 184,134,134, 83, 83, 26, 26 },// Western Frisian/Latin/Netherlands
{ 319, 33, 77, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Wolaytta/Ethiopic/Ethiopia
{ 320, 66, 206, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Wolof/Latin/Senegal
{ 321, 66, 216, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Xhosa/Latin/South Africa
{ 322, 66, 40, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Yangben/Latin/Cameroon
- { 323, 47, 258, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Yiddish/Hebrew/World
+ { 323, 47, 244, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Yiddish/Hebrew/Ukraine
{ 324, 66, 169, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Yoruba/Latin/Nigeria
{ 324, 66, 25, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Yoruba/Latin/Benin
{ 325, 66, 170, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Zarma/Latin/Niger
+ { 326, 66, 50, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Zhuang/Latin/China
{ 327, 66, 216, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Zulu/Latin/South Africa
{ 328, 66, 32, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Kaingang/Latin/Brazil
{ 329, 66, 32, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Nheengatu/Latin/Brazil
@@ -668,665 +694,1095 @@ static constexpr QCalendarLocale locale_data[] = {
{ 331, 66, 91, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Northern Frisian/Latin/Germany
{ 332, 29, 110, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Rajasthani/Devanagari/India
{ 333, 27, 193, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Moksha/Cyrillic/Russia
- { 334, 66, 258, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Toki Pona/Latin/World
+ { 334, 66, 258, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Toki Pona/Latin/world
{ 335, 66, 214, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Pijin/Latin/Solomon Islands
{ 336, 66, 169, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Obolo/Latin/Nigeria
+ { 337, 4, 178, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Baluchi/Arabic/Pakistan
+ { 337, 66, 178, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Baluchi/Latin/Pakistan
+ { 338, 66, 117, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Ligurian/Latin/Italy
+ { 339, 142, 161, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Rohingya/Hanifi/Myanmar
+ { 339, 142, 20, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Rohingya/Hanifi/Bangladesh
+ { 340, 4, 178, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Torwali/Arabic/Pakistan
+ { 341, 66, 25, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Anii/Latin/Benin
+ { 342, 29, 110, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Kangri/Devanagari/India
+ { 343, 66, 117, 0, 0, 106, 106, 184, 184,106,106, 78, 78, 26, 26 },// Venetian/Latin/Italy
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },// trailing zeros
};
static constexpr char16_t months_data[] = {
-0x4d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x53, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x2bb,
-0x20, 0x49, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x49, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49,
-0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x49, 0x3b, 0x52, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x53, 0x68, 0x61,
-0x2bb, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x53, 0x68, 0x61, 0x77, 0x77, 0x61, 0x6c,
-0x3b, 0x44, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x51, 0x69, 0x2bb, 0x64, 0x61, 0x68, 0x3b, 0x44, 0x68, 0x75, 0x2bb, 0x6c, 0x2d,
-0x48, 0x69, 0x6a, 0x6a, 0x61, 0x68, 0x4d, 0x75, 0x68, 0x2e, 0x3b, 0x53, 0x61, 0x66, 0x2e, 0x3b, 0x52, 0x61, 0x62, 0x2e,
-0x20, 0x49, 0x3b, 0x52, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x4a, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x3b, 0x4a, 0x75,
-0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x52, 0x61, 0x6a, 0x2e, 0x3b, 0x53, 0x68, 0x61, 0x2e, 0x3b, 0x52, 0x61, 0x6d, 0x2e,
-0x3b, 0x53, 0x68, 0x61, 0x77, 0x2e, 0x3b, 0x44, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x51, 0x2e, 0x3b, 0x44, 0x68, 0x75, 0x2bb,
-0x6c, 0x2d, 0x48, 0x2e, 0x31, 0x3b, 0x32, 0x3b, 0x33, 0x3b, 0x34, 0x3b, 0x35, 0x3b, 0x36, 0x3b, 0x37, 0x3b, 0x38, 0x3b,
-0x39, 0x3b, 0x31, 0x30, 0x3b, 0x31, 0x31, 0x3b, 0x31, 0x32, 0x4d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x65, 0x6d, 0x3b, 0x53,
-0x65, 0x66, 0x65, 0x72, 0x3b, 0x52, 0x65, 0x62, 0x69, 0x75, 0x6c, 0x2d, 0x65, 0x76, 0x65, 0x6c, 0x3b, 0x52, 0x65, 0x62,
-0x69, 0x75, 0x2d, 0x74, 0x68, 0x65, 0x6e, 0x69, 0x3b, 0x58, 0x68, 0x75, 0x6d, 0x61, 0x64, 0x65, 0x6c, 0x2d, 0x75, 0x6c,
-0x61, 0x3b, 0x58, 0x68, 0x75, 0x6d, 0x61, 0x64, 0x65, 0x2d, 0x74, 0x68, 0x65, 0x6e, 0x69, 0x3b, 0x52, 0x65, 0x78, 0x68,
-0x65, 0x62, 0x3b, 0x53, 0x68, 0x61, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x7a, 0x61, 0x6e, 0x3b, 0x53, 0x68,
-0x65, 0x76, 0x61, 0x6c, 0x3b, 0x44, 0x68, 0x75, 0x6c, 0x2d, 0x6b, 0x61, 0x64, 0x65, 0x3b, 0x44, 0x68, 0x75, 0x6c, 0x2d,
-0x68, 0x69, 0x78, 0x68, 0x65, 0x6d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x65, 0x6d, 0x3b, 0x73, 0x65, 0x66, 0x65, 0x72, 0x3b,
-0x72, 0x65, 0x62, 0x69, 0x75, 0x6c, 0x2d, 0x65, 0x76, 0x65, 0x6c, 0x3b, 0x72, 0x65, 0x62, 0x69, 0x75, 0x2d, 0x74, 0x68,
-0x65, 0x6e, 0x69, 0x3b, 0x78, 0x68, 0x75, 0x6d, 0x61, 0x64, 0x65, 0x6c, 0x2d, 0x75, 0x6c, 0x61, 0x3b, 0x78, 0x68, 0x75,
-0x6d, 0x61, 0x64, 0x65, 0x2d, 0x74, 0x68, 0x65, 0x6e, 0x69, 0x3b, 0x72, 0x65, 0x78, 0x68, 0x65, 0x62, 0x3b, 0x73, 0x68,
-0x61, 0x62, 0x61, 0x6e, 0x3b, 0x72, 0x61, 0x6d, 0x61, 0x7a, 0x61, 0x6e, 0x3b, 0x73, 0x68, 0x65, 0x76, 0x61, 0x6c, 0x3b,
-0x64, 0x68, 0x75, 0x6c, 0x2d, 0x6b, 0x61, 0x64, 0x65, 0x3b, 0x64, 0x68, 0x75, 0x6c, 0x2d, 0x68, 0x69, 0x78, 0x68, 0x65,
-0x4d, 0x75, 0x68, 0x2e, 0x3b, 0x53, 0x65, 0x66, 0x2e, 0x3b, 0x52, 0x65, 0x62, 0x2e, 0x20, 0x49, 0x3b, 0x52, 0x65, 0x62,
-0x2e, 0x20, 0x49, 0x49, 0x3b, 0x58, 0x68, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x3b, 0x58, 0x68, 0x75, 0x6d, 0x2e, 0x20, 0x49,
-0x49, 0x3b, 0x52, 0x65, 0x78, 0x68, 0x2e, 0x3b, 0x53, 0x68, 0x61, 0x2e, 0x3b, 0x52, 0x61, 0x6d, 0x2e, 0x3b, 0x53, 0x68,
-0x65, 0x76, 0x2e, 0x3b, 0x44, 0x68, 0x75, 0x6c, 0x2d, 0x6b, 0x2e, 0x3b, 0x44, 0x68, 0x75, 0x6c, 0x2d, 0x68, 0x2e, 0x6d,
-0x75, 0x68, 0x2e, 0x3b, 0x73, 0x65, 0x66, 0x2e, 0x3b, 0x72, 0x65, 0x62, 0x2e, 0x20, 0x49, 0x3b, 0x72, 0x65, 0x62, 0x2e,
-0x20, 0x49, 0x49, 0x3b, 0x78, 0x68, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x3b, 0x78, 0x68, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x49,
-0x3b, 0x72, 0x65, 0x78, 0x68, 0x2e, 0x3b, 0x73, 0x68, 0x61, 0x2e, 0x3b, 0x72, 0x61, 0x6d, 0x2e, 0x3b, 0x73, 0x68, 0x65,
-0x76, 0x2e, 0x3b, 0x64, 0x68, 0x75, 0x6c, 0x2d, 0x6b, 0x2e, 0x3b, 0x64, 0x68, 0x75, 0x6c, 0x2d, 0x68, 0x2e, 0x1219, 0x1200,
-0x1228, 0x121d, 0x3b, 0x1233, 0x1348, 0x122d, 0x3b, 0x1228, 0x1262, 0x12d1, 0x120d, 0x20, 0x12a0, 0x12c8, 0x120d, 0x3b, 0x1228, 0x1262, 0x12d1, 0x120d,
-0x20, 0x12a0, 0x12ba, 0x122d, 0x3b, 0x1300, 0x121b, 0x12f0, 0x120d, 0x20, 0x12a0, 0x12c8, 0x120d, 0x3b, 0x1300, 0x121b, 0x12f0, 0x120d, 0x20, 0x12a0,
-0x12ba, 0x122d, 0x3b, 0x1228, 0x1300, 0x1265, 0x3b, 0x123b, 0x12a5, 0x1263, 0x1295, 0x3b, 0x1228, 0x1218, 0x12f3, 0x1295, 0x3b, 0x1238, 0x12cb, 0x120d,
-0x3b, 0x12d9, 0x120d, 0x1242, 0x12f3, 0x1205, 0x3b, 0x12d9, 0x120d, 0x1202, 0x1303, 0x1205, 0x645, 0x62d, 0x631, 0x645, 0x3b, 0x635, 0x641, 0x631,
-0x3b, 0x631, 0x628, 0x64a, 0x639, 0x20, 0x627, 0x644, 0x623, 0x648, 0x644, 0x3b, 0x631, 0x628, 0x64a, 0x639, 0x20, 0x627, 0x644, 0x622,
-0x62e, 0x631, 0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x649, 0x20, 0x627, 0x644, 0x623, 0x648, 0x644, 0x649, 0x3b, 0x62c, 0x645, 0x627, 0x62f,
-0x649, 0x20, 0x627, 0x644, 0x622, 0x62e, 0x631, 0x629, 0x3b, 0x631, 0x62c, 0x628, 0x3b, 0x634, 0x639, 0x628, 0x627, 0x646, 0x3b, 0x631,
-0x645, 0x636, 0x627, 0x646, 0x3b, 0x634, 0x648, 0x627, 0x644, 0x3b, 0x630, 0x648, 0x20, 0x627, 0x644, 0x642, 0x639, 0x62f, 0x629, 0x3b,
-0x630, 0x648, 0x20, 0x627, 0x644, 0x62d, 0x62c, 0x629, 0x661, 0x3b, 0x662, 0x3b, 0x663, 0x3b, 0x664, 0x3b, 0x665, 0x3b, 0x666, 0x3b,
-0x667, 0x3b, 0x668, 0x3b, 0x669, 0x3b, 0x661, 0x660, 0x3b, 0x661, 0x661, 0x3b, 0x661, 0x662, 0x64, 0x65, 0x20, 0x4d, 0x75, 0x68,
-0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x64, 0x65, 0x20, 0x53, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x64, 0x65, 0x20, 0x52, 0x61,
-0x62, 0x69, 0x2bb, 0x20, 0x49, 0x3b, 0x64, 0x65, 0x20, 0x52, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x49, 0x3b, 0x64, 0x65,
-0x20, 0x4a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x3b, 0x64, 0x65, 0x20, 0x4a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20,
-0x49, 0x49, 0x3b, 0x64, 0x65, 0x20, 0x52, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x64, 0x65, 0x20, 0x53, 0x68, 0x61, 0x2bb, 0x62,
-0x61, 0x6e, 0x3b, 0x64, 0x65, 0x20, 0x52, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x64, 0x65, 0x20, 0x53, 0x68, 0x61,
-0x77, 0x77, 0x61, 0x6c, 0x3b, 0x64, 0x65, 0x20, 0x44, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x51, 0x69, 0x2bb, 0x64, 0x61, 0x68,
-0x3b, 0x64, 0x65, 0x20, 0x44, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x48, 0x69, 0x6a, 0x6a, 0x61, 0x68, 0x4d, 0x259, 0x68, 0x259,
-0x72, 0x72, 0x259, 0x6d, 0x3b, 0x53, 0x259, 0x66, 0x259, 0x72, 0x3b, 0x52, 0x259, 0x62, 0x69, 0xfc, 0x6c, 0x259, 0x76, 0x76,
-0x259, 0x6c, 0x3b, 0x52, 0x259, 0x62, 0x69, 0xfc, 0x6c, 0x61, 0x78, 0x131, 0x72, 0x3b, 0x43, 0x259, 0x6d, 0x61, 0x64, 0x69,
-0x79, 0x259, 0x6c, 0x259, 0x76, 0x76, 0x259, 0x6c, 0x3b, 0x43, 0x259, 0x6d, 0x61, 0x64, 0x69, 0x79, 0x259, 0x6c, 0x61, 0x78,
-0x131, 0x72, 0x3b, 0x52, 0x259, 0x63, 0x259, 0x62, 0x3b, 0x15e, 0x61, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x7a,
-0x61, 0x6e, 0x3b, 0x15e, 0x259, 0x76, 0x76, 0x61, 0x6c, 0x3b, 0x5a, 0x69, 0x6c, 0x71, 0x259, 0x64, 0x259, 0x3b, 0x5a, 0x69,
-0x6c, 0x68, 0x69, 0x63, 0x63, 0x259, 0x4d, 0x259, 0x68, 0x2e, 0x3b, 0x53, 0x259, 0x66, 0x2e, 0x3b, 0x52, 0x259, 0x62, 0x2e,
-0x20, 0x49, 0x3b, 0x52, 0x259, 0x62, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x43, 0x259, 0x6d, 0x2e, 0x20, 0x49, 0x3b, 0x43, 0x259,
-0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x52, 0x259, 0x63, 0x2e, 0x3b, 0x15e, 0x61, 0x62, 0x2e, 0x3b, 0x52, 0x61, 0x6d, 0x2e,
-0x3b, 0x15e, 0x259, 0x76, 0x2e, 0x3b, 0x5a, 0x69, 0x6c, 0x71, 0x2e, 0x3b, 0x5a, 0x69, 0x6c, 0x68, 0x2e, 0x9ae, 0x9b9, 0x9b0,
-0x9b0, 0x9ae, 0x3b, 0x9b8, 0x9ab, 0x9b0, 0x3b, 0x9b0, 0x9ac, 0x9bf, 0x989, 0x9b2, 0x20, 0x986, 0x989, 0x9af, 0x9bc, 0x9be, 0x9b2, 0x3b,
-0x9b0, 0x9ac, 0x9bf, 0x989, 0x9b8, 0x20, 0x9b8, 0x9be, 0x9a8, 0x9bf, 0x3b, 0x99c, 0x9ae, 0x9be, 0x9a6, 0x9bf, 0x989, 0x9b2, 0x20, 0x986,
-0x989, 0x9af, 0x9bc, 0x9be, 0x9b2, 0x3b, 0x99c, 0x9ae, 0x9be, 0x9a6, 0x9bf, 0x989, 0x9b8, 0x20, 0x9b8, 0x9be, 0x9a8, 0x9bf, 0x3b, 0x9b0,
-0x99c, 0x9ac, 0x3b, 0x9b6, 0x9be, 0x2018, 0x9ac, 0x9be, 0x9a8, 0x3b, 0x9b0, 0x9ae, 0x99c, 0x9be, 0x9a8, 0x3b, 0x9b6, 0x9be, 0x993, 0x9af,
-0x9bc, 0x9be, 0x9b2, 0x3b, 0x99c, 0x9cd, 0x9ac, 0x9bf, 0x9b2, 0x995, 0x9a6, 0x3b, 0x99c, 0x9cd, 0x9ac, 0x9bf, 0x9b2, 0x9b9, 0x99c, 0x9cd,
-0x99c, 0x9e7, 0x3b, 0x9e8, 0x3b, 0x9e9, 0x3b, 0x9ea, 0x3b, 0x9eb, 0x3b, 0x9ec, 0x3b, 0x9ed, 0x3b, 0x9ee, 0x3b, 0x9ef, 0x3b, 0x9e7,
-0x9e6, 0x3b, 0x9e7, 0x9e7, 0x3b, 0x9e7, 0x9e8, 0x6d, 0x75, 0x68, 0x61, 0x72, 0x65, 0x6d, 0x3b, 0x73, 0x61, 0x66, 0x65, 0x72,
-0x3b, 0x72, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x69, 0x3b, 0x72, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x69, 0x69, 0x3b, 0x64, 0x17e,
-0x75, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x69, 0x3b, 0x64, 0x17e, 0x75, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x69, 0x69, 0x3b, 0x72,
-0x65, 0x64, 0x17e, 0x65, 0x62, 0x3b, 0x53, 0x68, 0x61, 0x2bb, 0x62, 0x61, 0x6e, 0x3b, 0x72, 0x61, 0x6d, 0x61, 0x7a, 0x61,
-0x6e, 0x3b, 0x161, 0x65, 0x76, 0x61, 0x6c, 0x3b, 0x7a, 0x75, 0x6c, 0x2d, 0x6b, 0x61, 0x64, 0x65, 0x3b, 0x7a, 0x75, 0x6c,
-0x2d, 0x68, 0x69, 0x64, 0x17e, 0x65, 0x6d, 0x75, 0x68, 0x2e, 0x3b, 0x73, 0x61, 0x66, 0x2e, 0x3b, 0x52, 0x61, 0x62, 0x2e,
-0x20, 0x49, 0x3b, 0x72, 0x61, 0x62, 0x2e, 0x20, 0x69, 0x69, 0x3b, 0x64, 0x17e, 0x75, 0x6d, 0x2e, 0x20, 0x69, 0x3b, 0x64,
-0x17e, 0x75, 0x6d, 0x2e, 0x20, 0x69, 0x69, 0x3b, 0x72, 0x65, 0x64, 0x17e, 0x2e, 0x3b, 0x161, 0x61, 0x2e, 0x3b, 0x72, 0x61,
-0x6d, 0x2e, 0x3b, 0x161, 0x65, 0x2e, 0x3b, 0x7a, 0x75, 0x6c, 0x2d, 0x6b, 0x2e, 0x3b, 0x7a, 0x75, 0x6c, 0x2d, 0x68, 0x2e,
-0x41c, 0x443, 0x445, 0x430, 0x440, 0x435, 0x43c, 0x3b, 0x421, 0x430, 0x444, 0x435, 0x440, 0x3b, 0x420, 0x435, 0x431, 0x438, 0x20, 0x31,
-0x3b, 0x420, 0x435, 0x431, 0x438, 0x20, 0x32, 0x3b, 0x40f, 0x443, 0x43c, 0x430, 0x434, 0x435, 0x20, 0x31, 0x3b, 0x40f, 0x443, 0x43c,
-0x430, 0x434, 0x435, 0x20, 0x32, 0x3b, 0x420, 0x435, 0x45f, 0x435, 0x431, 0x3b, 0x428, 0x430, 0x2bb, 0x431, 0x430, 0x43d, 0x3b, 0x420,
-0x430, 0x43c, 0x430, 0x437, 0x430, 0x43d, 0x3b, 0x428, 0x435, 0x432, 0x430, 0x43b, 0x3b, 0x417, 0x443, 0x43b, 0x2d, 0x43a, 0x430, 0x434,
-0x435, 0x3b, 0x417, 0x443, 0x43b, 0x2d, 0x445, 0x438, 0x45f, 0x435, 0x41c, 0x443, 0x440, 0x430, 0x445, 0x430, 0x43c, 0x3b, 0x421, 0x430,
-0x444, 0x430, 0x440, 0x3b, 0x420, 0x430, 0x431, 0x438, 0x2bb, 0x20, 0x49, 0x3b, 0x420, 0x430, 0x431, 0x438, 0x2bb, 0x20, 0x49, 0x49,
-0x3b, 0x408, 0x443, 0x43c, 0x430, 0x434, 0x430, 0x20, 0x49, 0x3b, 0x408, 0x443, 0x43c, 0x430, 0x434, 0x430, 0x20, 0x49, 0x49, 0x3b,
-0x420, 0x430, 0x452, 0x430, 0x431, 0x3b, 0x428, 0x430, 0x2bb, 0x431, 0x430, 0x43d, 0x3b, 0x420, 0x430, 0x43c, 0x430, 0x434, 0x430, 0x43d,
-0x3b, 0x428, 0x430, 0x432, 0x430, 0x43b, 0x3b, 0x414, 0x443, 0x2bb, 0x43b, 0x2d, 0x41a, 0x438, 0x2bb, 0x434, 0x430, 0x3b, 0x414, 0x443,
-0x2bb, 0x43b, 0x2d, 0x445, 0x438, 0x452, 0x430, 0x41c, 0x443, 0x445, 0x2e, 0x3b, 0x421, 0x430, 0x444, 0x2e, 0x3b, 0x420, 0x435, 0x431,
-0x2e, 0x20, 0x31, 0x3b, 0x420, 0x435, 0x431, 0x2e, 0x20, 0x32, 0x3b, 0x40f, 0x443, 0x43c, 0x2e, 0x20, 0x31, 0x3b, 0x40f, 0x443,
-0x43c, 0x2e, 0x20, 0x32, 0x3b, 0x420, 0x435, 0x45f, 0x2e, 0x3b, 0x428, 0x430, 0x2e, 0x3b, 0x420, 0x430, 0x43c, 0x2e, 0x3b, 0x428,
-0x435, 0x2e, 0x3b, 0x417, 0x443, 0x43b, 0x2d, 0x43a, 0x2e, 0x3b, 0x417, 0x443, 0x43b, 0x2d, 0x445, 0x2e, 0x43c, 0x443, 0x445, 0x430,
-0x440, 0x430, 0x43c, 0x3b, 0x441, 0x430, 0x444, 0x430, 0x440, 0x3b, 0x440, 0x430, 0x431, 0x438, 0x2d, 0x31, 0x3b, 0x440, 0x430, 0x431,
-0x438, 0x2d, 0x32, 0x3b, 0x434, 0x436, 0x443, 0x43c, 0x430, 0x434, 0x430, 0x2d, 0x31, 0x3b, 0x434, 0x436, 0x443, 0x43c, 0x430, 0x434,
-0x430, 0x2d, 0x32, 0x3b, 0x440, 0x430, 0x434, 0x436, 0x430, 0x431, 0x3b, 0x448, 0x430, 0x431, 0x430, 0x43d, 0x3b, 0x440, 0x430, 0x43c,
-0x430, 0x437, 0x430, 0x43d, 0x3b, 0x428, 0x430, 0x432, 0x430, 0x43b, 0x3b, 0x414, 0x445, 0x443, 0x43b, 0x2d, 0x41a, 0x430, 0x430, 0x434,
-0x430, 0x3b, 0x414, 0x445, 0x443, 0x43b, 0x2d, 0x445, 0x438, 0x434, 0x436, 0x430, 0x7a46, 0x54c8, 0x862d, 0x59c6, 0x6708, 0x3b, 0x8272, 0x6cd5,
-0x723e, 0x6708, 0x3b, 0x8cf4, 0x6bd4, 0x6708, 0x20, 0x49, 0x3b, 0x8cf4, 0x6bd4, 0x6708, 0x20, 0x49, 0x49, 0x3b, 0x4e3b, 0x99ac, 0x9054, 0x6708,
-0x20, 0x49, 0x3b, 0x4e3b, 0x99ac, 0x9054, 0x6708, 0x20, 0x49, 0x49, 0x3b, 0x8cf4, 0x54f2, 0x535c, 0x6708, 0x3b, 0x820d, 0x723e, 0x90a6, 0x6708,
-0x3b, 0x8cf4, 0x8cb7, 0x4e39, 0x6708, 0x3b, 0x9583, 0x74e6, 0x9b6f, 0x6708, 0x3b, 0x90fd, 0x723e, 0x5580, 0x723e, 0x5fb7, 0x6708, 0x3b, 0x90fd, 0x723e,
-0x9ed1, 0x54f2, 0x6708, 0x7a46, 0x54c8, 0x5170, 0x59c6, 0x6708, 0x3b, 0x8272, 0x6cd5, 0x5c14, 0x6708, 0x3b, 0x8d56, 0x6bd4, 0x6708, 0x20, 0x49, 0x3b,
-0x8d56, 0x6bd4, 0x6708, 0x20, 0x49, 0x49, 0x3b, 0x4e3b, 0x9a6c, 0x8fbe, 0x6708, 0x20, 0x49, 0x3b, 0x4e3b, 0x9a6c, 0x8fbe, 0x6708, 0x20, 0x49,
-0x49, 0x3b, 0x8d56, 0x54f2, 0x535c, 0x6708, 0x3b, 0x820d, 0x5c14, 0x90a6, 0x6708, 0x3b, 0x8d56, 0x4e70, 0x4e39, 0x6708, 0x3b, 0x95ea, 0x74e6, 0x9c81,
-0x6708, 0x3b, 0x90fd, 0x5c14, 0x5580, 0x5c14, 0x5fb7, 0x6708, 0x3b, 0x90fd, 0x5c14, 0x9ed1, 0x54f2, 0x6708, 0xd804, 0xdd1f, 0xd804, 0xdd27, 0xd804, 0xdd26,
-0xd804, 0xdd27, 0xd804, 0xdd22, 0xd804, 0xdd27, 0xd804, 0xdd1f, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd25, 0xd804, 0xdd27, 0xd804, 0xdd1c, 0xd804, 0xdd22, 0xd804,
-0xdd34, 0x3b, 0xd804, 0xdd22, 0xd804, 0xdd27, 0xd804, 0xdd1d, 0xd804, 0xdd28, 0xd804, 0xdd05, 0xd804, 0xdd23, 0xd804, 0xdd34, 0x20, 0xd804, 0xdd03, 0xd804,
-0xdd03, 0xd804, 0xdd2a, 0xd804, 0xdd20, 0xd804, 0xdd23, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd22, 0xd804, 0xdd27, 0xd804, 0xdd1d, 0xd804, 0xdd28, 0xd804, 0xdd05,
-0xd804, 0xdd25, 0xd804, 0xdd34, 0x20, 0xd804, 0xdd25, 0xd804, 0xdd1a, 0xd804, 0xdd28, 0x3b, 0xd804, 0xdd0e, 0xd804, 0xdd27, 0xd804, 0xdd1f, 0xd804, 0xdd18,
-0xd804, 0xdd28, 0xd804, 0xdd05, 0xd804, 0xdd23, 0xd804, 0xdd34, 0x20, 0xd804, 0xdd03, 0xd804, 0xdd03, 0xd804, 0xdd2a, 0xd804, 0xdd20, 0xd804, 0xdd23, 0xd804,
-0xdd34, 0x3b, 0xd804, 0xdd0e, 0xd804, 0xdd27, 0xd804, 0xdd1f, 0xd804, 0xdd18, 0xd804, 0xdd28, 0xd804, 0xdd05, 0xd804, 0xdd0c, 0xd804, 0xdd34, 0x20, 0xd804,
-0xdd25, 0xd804, 0xdd1a, 0xd804, 0xdd28, 0x3b, 0xd804, 0xdd22, 0xd804, 0xdd27, 0xd804, 0xdd0e, 0xd804, 0xdd27, 0xd804, 0xdd1d, 0xd804, 0xdd34, 0x3b, 0xd804,
-0xdd25, 0xd804, 0xdd33, 0xd804, 0xdd03, 0xd804, 0xdd1d, 0xd804, 0xdd27, 0xd804, 0xdd1a, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd22, 0xd804, 0xdd27, 0xd804, 0xdd1f,
-0xd804, 0xdd34, 0xd804, 0xdd0e, 0xd804, 0xdd1a, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd25, 0xd804, 0xdd24, 0xd804, 0xdd23, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd0e,
-0xd804, 0xdd28, 0xd804, 0xdd23, 0xd804, 0xdd34, 0xd804, 0xdd07, 0xd804, 0xdd27, 0xd804, 0xdd18, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd0e, 0xd804, 0xdd28, 0xd804,
-0xdd23, 0xd804, 0xdd34, 0xd804, 0xdd26, 0xd804, 0xdd27, 0xd804, 0xdd0e, 0xd804, 0xdd34, 0xd804, 0xdd0e, 0xd804, 0xdd27, 0xd804, 0xdd37, 0x3b, 0xd804, 0xdd38,
-0x3b, 0xd804, 0xdd39, 0x3b, 0xd804, 0xdd3a, 0x3b, 0xd804, 0xdd3b, 0x3b, 0xd804, 0xdd3c, 0x3b, 0xd804, 0xdd3d, 0x3b, 0xd804, 0xdd3e, 0x3b, 0xd804,
-0xdd3f, 0x3b, 0xd804, 0xdd37, 0xd804, 0xdd36, 0x3b, 0xd804, 0xdd37, 0xd804, 0xdd37, 0x3b, 0xd804, 0xdd37, 0xd804, 0xdd38, 0x4e00, 0x6708, 0x3b, 0x4e8c,
-0x6708, 0x3b, 0x4e09, 0x6708, 0x3b, 0x56db, 0x6708, 0x3b, 0x4e94, 0x6708, 0x3b, 0x516d, 0x6708, 0x3b, 0x4e03, 0x6708, 0x3b, 0x516b, 0x6708, 0x3b,
-0x4e5d, 0x6708, 0x3b, 0x5341, 0x6708, 0x3b, 0x5341, 0x4e00, 0x6708, 0x3b, 0x5341, 0x4e8c, 0x6708, 0x31, 0x6708, 0x3b, 0x32, 0x6708, 0x3b, 0x33,
-0x6708, 0x3b, 0x34, 0x6708, 0x3b, 0x35, 0x6708, 0x3b, 0x36, 0x6708, 0x3b, 0x37, 0x6708, 0x3b, 0x38, 0x6708, 0x3b, 0x39, 0x6708, 0x3b,
-0x31, 0x30, 0x6708, 0x3b, 0x31, 0x31, 0x6708, 0x3b, 0x31, 0x32, 0x6708, 0x31, 0x2e, 0x3b, 0x32, 0x2e, 0x3b, 0x33, 0x2e, 0x3b,
-0x34, 0x2e, 0x3b, 0x35, 0x2e, 0x3b, 0x36, 0x2e, 0x3b, 0x37, 0x2e, 0x3b, 0x38, 0x2e, 0x3b, 0x39, 0x2e, 0x3b, 0x31, 0x30,
-0x2e, 0x3b, 0x31, 0x31, 0x2e, 0x3b, 0x31, 0x32, 0x2e, 0x6d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x65, 0x6d, 0x3b, 0x73, 0x61,
-0x66, 0x61, 0x72, 0x3b, 0x72, 0x65, 0x62, 0xed, 0x2019, 0x75, 0x20, 0x6c, 0x2d, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x72,
-0x65, 0x62, 0xed, 0x2019, 0x75, 0x20, 0x73, 0x2d, 0x73, 0xe1, 0x6e, 0xed, 0x3b, 0x64, 0x17e, 0x75, 0x6d, 0xe1, 0x64, 0xe1,
-0x20, 0x61, 0x6c, 0x2d, 0xfa, 0x6c, 0xe1, 0x3b, 0x64, 0x17e, 0x75, 0x6d, 0xe1, 0x64, 0xe1, 0x20, 0x61, 0x6c, 0x2d, 0xe1,
-0x63, 0x68, 0x69, 0x72, 0x61, 0x3b, 0x72, 0x65, 0x64, 0x17e, 0x65, 0x62, 0x3b, 0x161, 0x61, 0x2019, 0x62, 0xe1, 0x6e, 0x3b,
-0x72, 0x61, 0x6d, 0x61, 0x64, 0xe1, 0x6e, 0x3b, 0x161, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x7a, 0xfa, 0x20, 0x6c, 0x2d,
-0x6b, 0x61, 0x2019, 0x64, 0x61, 0x3b, 0x7a, 0xfa, 0x20, 0x6c, 0x2d, 0x68, 0x69, 0x64, 0x17e, 0x64, 0x17e, 0x61, 0x6d, 0x75,
-0x68, 0x2e, 0x3b, 0x73, 0x61, 0x66, 0x2e, 0x3b, 0x72, 0x65, 0x62, 0x2e, 0x20, 0x49, 0x3b, 0x72, 0x65, 0x62, 0x2e, 0x20,
-0x49, 0x49, 0x3b, 0x64, 0x17e, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x3b, 0x64, 0x17e, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b,
-0x72, 0x65, 0x64, 0x2e, 0x3b, 0x161, 0x61, 0x2e, 0x3b, 0x72, 0x61, 0x6d, 0x2e, 0x3b, 0x161, 0x61, 0x77, 0x2e, 0x3b, 0x7a,
-0xfa, 0x20, 0x6c, 0x2d, 0x6b, 0x2e, 0x3b, 0x7a, 0xfa, 0x20, 0x6c, 0x2d, 0x68, 0x2e, 0x6d, 0x75, 0x68, 0x61, 0x72, 0x72,
-0x61, 0x6d, 0x3b, 0x73, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x72, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x3b, 0x72, 0x61, 0x62,
-0x69, 0x2bb, 0x20, 0x49, 0x49, 0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x64,
-0x61, 0x20, 0x49, 0x49, 0x3b, 0x72, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x73, 0x68, 0x61, 0x2bb, 0x62, 0x61, 0x6e, 0x3b, 0x72,
-0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x73, 0x68, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x64, 0x68, 0x75, 0x2bb, 0x6c,
-0x2d, 0x51, 0x69, 0x2bb, 0x64, 0x61, 0x68, 0x3b, 0x64, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x48, 0x69, 0x6a, 0x6a, 0x61, 0x68,
-0x4d, 0x6f, 0x65, 0x68, 0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x53, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x52, 0x61, 0x62, 0x69,
-0x2bb, 0x61, 0x20, 0x61, 0x6c, 0x20, 0x61, 0x77, 0x61, 0x6c, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x2bb, 0x61, 0x20, 0x61, 0x6c,
-0x20, 0x74, 0x68, 0x61, 0x6e, 0x69, 0x3b, 0x4a, 0x6f, 0x65, 0x6d, 0x61, 0x64, 0x2bb, 0x61, 0x6c, 0x20, 0x61, 0x77, 0x61,
-0x6c, 0x3b, 0x4a, 0x6f, 0x65, 0x6d, 0x61, 0x64, 0x2bb, 0x61, 0x6c, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x69, 0x3b, 0x52, 0x61,
-0x6a, 0x61, 0x62, 0x3b, 0x53, 0x6a, 0x61, 0x2bb, 0x61, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e,
-0x3b, 0x53, 0x6a, 0x61, 0x77, 0x61, 0x6c, 0x3b, 0x44, 0x6f, 0x65, 0x20, 0x61, 0x6c, 0x20, 0x6b, 0x61, 0x2bb, 0x61, 0x62,
-0x61, 0x3b, 0x44, 0x6f, 0x65, 0x20, 0x61, 0x6c, 0x20, 0x68, 0x69, 0x7a, 0x6a, 0x61, 0x4d, 0x6f, 0x65, 0x68, 0x2e, 0x3b,
-0x53, 0x61, 0x66, 0x2e, 0x3b, 0x52, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x3b, 0x52, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x49, 0x3b,
-0x4a, 0x6f, 0x65, 0x6d, 0x2e, 0x20, 0x49, 0x3b, 0x4a, 0x6f, 0x65, 0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x52, 0x61, 0x6a,
-0x2e, 0x3b, 0x53, 0x6a, 0x61, 0x2e, 0x3b, 0x52, 0x61, 0x6d, 0x2e, 0x3b, 0x53, 0x6a, 0x61, 0x77, 0x2e, 0x3b, 0x44, 0x6f,
-0x65, 0x20, 0x61, 0x6c, 0x20, 0x6b, 0x2e, 0x3b, 0x44, 0x6f, 0x65, 0x20, 0x61, 0x6c, 0x20, 0x68, 0x2e, 0x64, 0x7a, 0x6f,
-0x76, 0x65, 0x3b, 0x64, 0x7a, 0x6f, 0x64, 0x7a, 0x65, 0x3b, 0x74, 0x65, 0x64, 0x6f, 0x78, 0x65, 0x3b, 0x61, 0x66, 0x254,
-0x66, 0x69, 0x1ebd, 0x3b, 0x64, 0x61, 0x6d, 0x25b, 0x3b, 0x6d, 0x61, 0x73, 0x61, 0x3b, 0x73, 0x69, 0x61, 0x6d, 0x6c, 0x254,
-0x6d, 0x3b, 0x64, 0x65, 0x61, 0x73, 0x69, 0x61, 0x6d, 0x69, 0x6d, 0x65, 0x3b, 0x61, 0x6e, 0x79, 0x254, 0x6e, 0x79, 0x254,
-0x3b, 0x6b, 0x65, 0x6c, 0x65, 0x3b, 0x61, 0x64, 0x65, 0x25b, 0x6d, 0x65, 0x6b, 0x70, 0x254, 0x78, 0x65, 0x3b, 0x64, 0x7a,
-0x6f, 0x6d, 0x65, 0x64, 0x7a, 0x76, 0x3b, 0x64, 0x7a, 0x64, 0x3b, 0x74, 0x65, 0x64, 0x3b, 0x61, 0x66, 0x254, 0x3b, 0x64,
-0x61, 0x6d, 0x3b, 0x6d, 0x61, 0x73, 0x3b, 0x73, 0x69, 0x61, 0x3b, 0x64, 0x65, 0x61, 0x3b, 0x61, 0x6e, 0x79, 0x3b, 0x6b,
-0x65, 0x6c, 0x3b, 0x61, 0x64, 0x65, 0x3b, 0x64, 0x7a, 0x6d, 0x6d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x73,
-0x61, 0x66, 0x61, 0x72, 0x3b, 0x72, 0x61, 0x62, 0x69, 0x2019, 0x20, 0x61, 0x6c, 0x2d, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b,
-0x72, 0x61, 0x62, 0x69, 0x2019, 0x20, 0x61, 0x6c, 0x2d, 0x61, 0x6b, 0x68, 0x69, 0x72, 0x3b, 0x64, 0x17e, 0x75, 0x6d, 0x61,
-0x64, 0x61, 0x2d, 0x6c, 0x2d, 0x75, 0x6c, 0x61, 0x3b, 0x64, 0x17e, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x2d, 0x6c, 0x2d, 0x61,
-0x6b, 0x68, 0x69, 0x72, 0x61, 0x3b, 0x72, 0x61, 0x64, 0x17e, 0x61, 0x62, 0x3b, 0x161, 0x61, 0x2019, 0x62, 0x61, 0x6e, 0x3b,
-0x72, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x161, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x64, 0x68, 0x75, 0x2d, 0x6c,
-0x2d, 0x71, 0x61, 0x2019, 0x64, 0x61, 0x3b, 0x64, 0x68, 0x75, 0x2d, 0x6c, 0x2d, 0x68, 0x69, 0x64, 0x64, 0x17e, 0x61, 0x6d,
-0x6f, 0x75, 0x68, 0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x73, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x72, 0x61, 0x62, 0x69, 0x61,
-0x20, 0x61, 0x6c, 0x20, 0x61, 0x77, 0x61, 0x6c, 0x3b, 0x72, 0x61, 0x62, 0x69, 0x61, 0x20, 0x61, 0x74, 0x68, 0x2d, 0x74,
-0x68, 0x61, 0x6e, 0x69, 0x3b, 0x6a, 0x6f, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x61, 0x6c, 0x20, 0x6f, 0x75, 0x6c, 0x61,
-0x3b, 0x6a, 0x6f, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x61, 0x74, 0x68, 0x2d, 0x74, 0x68, 0x61, 0x6e, 0x69, 0x61, 0x3b,
-0x72, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x63, 0x68, 0x61, 0x61, 0x62, 0x61, 0x6e, 0x65, 0x3b, 0x72, 0x61, 0x6d, 0x61, 0x64,
-0x61, 0x6e, 0x3b, 0x63, 0x68, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x64, 0x68, 0x6f, 0x75, 0x20, 0x61, 0x6c, 0x20, 0x71,
-0x69, 0x60, 0x64, 0x61, 0x3b, 0x64, 0x68, 0x6f, 0x75, 0x20, 0x61, 0x6c, 0x2d, 0x68, 0x69, 0x6a, 0x6a, 0x61, 0x6d, 0x6f,
-0x75, 0x68, 0x2e, 0x3b, 0x73, 0x61, 0x66, 0x2e, 0x3b, 0x72, 0x61, 0x62, 0x2e, 0x20, 0x61, 0x77, 0x2e, 0x3b, 0x72, 0x61,
-0x62, 0x2e, 0x20, 0x74, 0x68, 0x2e, 0x3b, 0x6a, 0x6f, 0x75, 0x6d, 0x2e, 0x20, 0x6f, 0x75, 0x2e, 0x3b, 0x6a, 0x6f, 0x75,
-0x6d, 0x2e, 0x20, 0x74, 0x68, 0x2e, 0x3b, 0x72, 0x61, 0x6a, 0x2e, 0x3b, 0x63, 0x68, 0x61, 0x61, 0x2e, 0x3b, 0x72, 0x61,
-0x6d, 0x2e, 0x3b, 0x63, 0x68, 0x61, 0x77, 0x2e, 0x3b, 0x64, 0x68, 0x6f, 0x75, 0x2e, 0x20, 0x71, 0x69, 0x2e, 0x3b, 0x64,
-0x68, 0x6f, 0x75, 0x2e, 0x20, 0x68, 0x69, 0x2e, 0x6d, 0x6f, 0x75, 0x68, 0x2e, 0x3b, 0x73, 0x61, 0x66, 0x2e, 0x3b, 0x72,
-0x61, 0x62, 0x2e, 0x20, 0x61, 0x77, 0x2e, 0x3b, 0x72, 0x61, 0x62, 0x2e, 0x20, 0x74, 0x68, 0x2e, 0x3b, 0x6a, 0x6f, 0x75,
-0x6d, 0x2e, 0x20, 0x6f, 0x75, 0x6c, 0x2e, 0x3b, 0x6a, 0x6f, 0x75, 0x6d, 0x2e, 0x20, 0x74, 0x68, 0x61, 0x2e, 0x3b, 0x72,
-0x61, 0x6a, 0x2e, 0x3b, 0x63, 0x68, 0x61, 0x61, 0x2e, 0x3b, 0x72, 0x61, 0x6d, 0x2e, 0x3b, 0x63, 0x68, 0x61, 0x77, 0x2e,
-0x3b, 0x64, 0x68, 0x6f, 0x75, 0x2e, 0x20, 0x71, 0x2e, 0x3b, 0x64, 0x68, 0x6f, 0x75, 0x2e, 0x20, 0x68, 0x2e, 0xd83a, 0xdd14,
-0xd83a, 0xdd2e, 0xd83a, 0xdd25, 0xd83a, 0xdd26, 0xd83a, 0xdd2b, 0xd83a, 0xdd32, 0xd83a, 0xdd3c, 0xd83a, 0xdd2b, 0x3b, 0xd83a, 0xdd05, 0xd83a, 0xdd22, 0xd83a,
-0xdd26, 0xd83a, 0xdd46, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0xd83a, 0xdd23, 0xd83a, 0xdd35, 0x2d, 0xd83a, 0xdd06, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd22,
-0xd83a, 0xdd32, 0x3b, 0xd83a, 0xdd06, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0x3b, 0xd83a, 0xdd03, 0xd83a, 0xdd2d, 0xd83a, 0xdd25,
-0xd83a, 0xdd28, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0x3b, 0xd83a, 0xdd04, 0xd83a, 0xdd22, 0xd83a, 0xdd28, 0xd83a, 0xdd46, 0xd83a,
-0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0x3b, 0xd83a, 0xdd05, 0xd83a, 0xdd22, 0xd83a, 0xdd26, 0xd83a, 0xdd46, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a,
-0xd83a, 0xdd23, 0xd83a, 0xdd35, 0x2d, 0xd83a, 0xdd08, 0xd83a, 0xdd22, 0xd83a, 0xdd44, 0xd83a, 0xdd36, 0xd83a, 0xdd2d, 0xd83a, 0xdd26, 0xd83a, 0xdd2d, 0x3b,
-0xd83a, 0xdd08, 0xd83a, 0xdd22, 0xd83a, 0xdd44, 0xd83a, 0xdd36, 0xd83a, 0xdd2d, 0xd83a, 0xdd26, 0xd83a, 0xdd2d, 0x3b, 0xd83a, 0xdd05, 0xd83a, 0xdd22, 0xd83a,
-0xdd26, 0xd83a, 0xdd46, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0xd83a, 0xdd23, 0xd83a, 0xdd35, 0x2d, 0xd83a, 0xdd05, 0xd83a, 0xdd35, 0xd83a, 0xdd45, 0xd83a, 0xdd25,
-0xd83a, 0xdd22, 0xd83a, 0xdd34, 0xd83a, 0xdd2b, 0xd83a, 0xdd45, 0x3b, 0xd83a, 0xdd05, 0xd83a, 0xdd35, 0xd83a, 0xdd45, 0xd83a, 0xdd25, 0xd83a, 0xdd22, 0xd83a,
-0xdd34, 0xd83a, 0xdd2b, 0xd83a, 0xdd45, 0x3b, 0xd83a, 0xdd14, 0xd83a, 0xdd35, 0xd83a, 0xdd45, 0xd83a, 0xdd24, 0xd83a, 0xdd23, 0xd83a, 0xdd22, 0xd83a, 0xdd44,
-0xd83a, 0xdd32, 0xd83a, 0xdd4b, 0xd83a, 0xdd23, 0xd83a, 0xdd35, 0x3b, 0xd83a, 0xdd05, 0xd83a, 0xdd22, 0xd83a, 0xdd26, 0xd83a, 0xdd46, 0xd83a, 0xdd2e, 0xd83a,
-0xdd2a, 0xd83a, 0xdd23, 0xd83a, 0xdd35, 0x2d, 0xd83a, 0xdd01, 0xd83a, 0xdd2e, 0xd83a, 0xdd32, 0xd83a, 0xdd33, 0xd83a, 0xdd2d, 0xd83a, 0xdd32, 0x3b, 0xd83a,
-0xdd01, 0xd83a, 0xdd35, 0xd83a, 0xdd32, 0xd83a, 0xdd33, 0xd83a, 0xdd2d, 0xd83a, 0xdd32, 0xd83a, 0xdd14, 0xd83a, 0xdd2e, 0xd83a, 0xdd26, 0x2e, 0x3b, 0xd83a,
-0xdd05, 0xd83a, 0xdd22, 0xd83a, 0xdd28, 0x2e, 0x3b, 0xd83a, 0xdd06, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0x2e, 0x3b, 0xd83a, 0xdd03, 0xd83a, 0xdd2d, 0xd83a,
-0xdd28, 0x2e, 0x3b, 0xd83a, 0xdd04, 0xd83a, 0xdd22, 0xd83a, 0xdd28, 0x2e, 0x3b, 0xd83a, 0xdd05, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0x2e, 0x3b, 0xd83a,
-0xdd08, 0xd83a, 0xdd22, 0xd83a, 0xdd36, 0x2e, 0x3b, 0xd83a, 0xdd05, 0xd83a, 0xdd22, 0xd83a, 0xdd27, 0x2e, 0x3b, 0xd83a, 0xdd05, 0xd83a, 0xdd35, 0xd83a,
-0xdd25, 0x2e, 0x3b, 0xd83a, 0xdd14, 0xd83a, 0xdd35, 0xd83a, 0xdd24, 0x2e, 0x3b, 0xd83a, 0xdd05, 0xd83a, 0xdd22, 0xd83a, 0xdd23, 0x2e, 0x3b, 0xd83a,
-0xdd01, 0xd83a, 0xdd2e, 0xd83a, 0xdd32, 0x2e, 0xd83a, 0xdd51, 0x3b, 0xd83a, 0xdd52, 0x3b, 0xd83a, 0xdd53, 0x3b, 0xd83a, 0xdd54, 0x3b, 0xd83a, 0xdd55,
-0x3b, 0xd83a, 0xdd56, 0x3b, 0xd83a, 0xdd57, 0x3b, 0xd83a, 0xdd58, 0x3b, 0xd83a, 0xdd59, 0x3b, 0xd83a, 0xdd51, 0xd83a, 0xdd50, 0x3b, 0xd83a, 0xdd51,
-0xd83a, 0xdd51, 0x3b, 0xd83a, 0xdd51, 0xd83a, 0xdd52, 0x10db, 0x10e3, 0x10f0, 0x10d0, 0x10e0, 0x10d0, 0x10db, 0x10d8, 0x3b, 0x10e1, 0x10d0, 0x10e4, 0x10d0,
-0x10e0, 0x10d8, 0x3b, 0x10e0, 0x10d0, 0x10d1, 0x10d8, 0x20, 0x10e3, 0x10da, 0x2d, 0x10d0, 0x10d5, 0x10d0, 0x10da, 0x10d8, 0x3b, 0x10e0, 0x10d0, 0x10d1,
-0x10d8, 0x20, 0x10e3, 0x10da, 0x2d, 0x10d0, 0x10ee, 0x10d8, 0x10e0, 0x10d8, 0x3b, 0x10ef, 0x10e3, 0x10db, 0x10d0, 0x10d3, 0x10d0, 0x20, 0x10e3, 0x10da,
-0x2d, 0x10d0, 0x10d5, 0x10d0, 0x10da, 0x10d8, 0x3b, 0x10ef, 0x10e3, 0x10db, 0x10d0, 0x10d3, 0x10d0, 0x20, 0x10e3, 0x10da, 0x2d, 0x10d0, 0x10ee, 0x10d8,
-0x10e0, 0x10d8, 0x3b, 0x10e0, 0x10d0, 0x10ef, 0x10d0, 0x10d1, 0x10d8, 0x3b, 0x10e8, 0x10d0, 0x10d1, 0x10d0, 0x10dc, 0x10d8, 0x3b, 0x10e0, 0x10d0, 0x10db,
-0x10d0, 0x10d3, 0x10d0, 0x10dc, 0x10d8, 0x3b, 0x10e8, 0x10d0, 0x10d5, 0x10d0, 0x10da, 0x10d8, 0x3b, 0x10d6, 0x10e3, 0x10da, 0x2d, 0x10d9, 0x10d0, 0x10d0,
-0x10d3, 0x10d0, 0x3b, 0x10d6, 0x10e3, 0x10da, 0x2d, 0x10f0, 0x10d8, 0x10ef, 0x10d0, 0x10db, 0x10e3, 0x10f0, 0x2e, 0x3b, 0x10e1, 0x10d0, 0x10e4, 0x2e,
-0x3b, 0x10e0, 0x10d0, 0x10d1, 0x2e, 0x20, 0x49, 0x3b, 0x10e0, 0x10d0, 0x10d1, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x10ef, 0x10e3, 0x10db, 0x2e,
-0x20, 0x49, 0x3b, 0x10ef, 0x10e3, 0x10db, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x10e0, 0x10d0, 0x10ef, 0x2e, 0x3b, 0x10e8, 0x10d0, 0x10d1, 0x2e,
-0x3b, 0x10e0, 0x10d0, 0x10db, 0x2e, 0x3b, 0x10e8, 0x10d0, 0x10d5, 0x2e, 0x3b, 0x10d6, 0x10e3, 0x10da, 0x2d, 0x10d9, 0x2e, 0x3b, 0x10d6, 0x10e3,
-0x10da, 0x2d, 0x10f0, 0x2e, 0x4d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x53, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x52,
-0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x49, 0x3b, 0x44, 0x73, 0x63, 0x68,
-0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x3b, 0x44, 0x73, 0x63, 0x68, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x49,
-0x3b, 0x52, 0x61, 0x64, 0x73, 0x63, 0x68, 0x61, 0x62, 0x3b, 0x53, 0x68, 0x61, 0x2bb, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61,
-0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x53, 0x68, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x44, 0x68, 0x75, 0x20, 0x6c, 0x2d,
-0x71, 0x61, 0x2bf, 0x64, 0x61, 0x3b, 0x44, 0x68, 0x75, 0x20, 0x6c, 0x2d, 0x48, 0x69, 0x64, 0x64, 0x73, 0x63, 0x68, 0x61,
-0xaae, 0xac1, 0xab9, 0xab0, 0xacd, 0xab0, 0xaae, 0x3b, 0xab8, 0xaab, 0xab0, 0x3b, 0xab0, 0xabe, 0xaac, 0xac0, 0x2bb, 0x20, 0x49, 0x3b,
-0xab0, 0xabe, 0xaac, 0xac0, 0x2bb, 0x20, 0x49, 0x49, 0x3b, 0xa9c, 0xac1, 0xaae, 0xabe, 0xaa6, 0xabe, 0x20, 0x49, 0x3b, 0xa9c, 0xac1,
-0xaae, 0xabe, 0xaa6, 0xabe, 0x20, 0x49, 0x49, 0x3b, 0xab0, 0xa9c, 0xaac, 0x3b, 0xab6, 0xabe, 0x2bb, 0xaac, 0xabe, 0xaa8, 0x3b, 0xab0,
-0xaae, 0xaa6, 0xabe, 0xaa8, 0x3b, 0xab6, 0xabe, 0xab5, 0xacd, 0xab5, 0xab2, 0x3b, 0xaa7, 0xac1, 0x2bb, 0xab2, 0x2d, 0xa95, 0xacd, 0xab5,
-0xac0, 0x2bb, 0xaa1, 0xabe, 0xab9, 0x3b, 0xaa7, 0xac1, 0x2bb, 0xab2, 0x2d, 0xab9, 0xabf, 0xa9c, 0xacd, 0xa9c, 0xabe, 0xab9, 0xaae, 0xac1,
-0xab9, 0x2e, 0x3b, 0xab8, 0xaab, 0x2e, 0x3b, 0xab0, 0xaac, 0x2e, 0x49, 0x3b, 0xab0, 0xaac, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0xa9c,
-0xac1, 0xaae, 0x2e, 0x20, 0x49, 0x3b, 0xa9c, 0xac1, 0xaae, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0xab0, 0xabe, 0xa9c, 0x2e, 0x3b, 0xab6,
-0xabe, 0x2e, 0x3b, 0xab0, 0xabe, 0xaae, 0x2e, 0x3b, 0xab6, 0xabe, 0xab5, 0x2e, 0x3b, 0xaa7, 0xac1, 0x2bb, 0xab2, 0x2d, 0xa95, 0xacd,
-0xaaf, 0xac1, 0x2e, 0x3b, 0xaa7, 0xac1, 0x2bb, 0xab2, 0x2d, 0xa8f, 0xa9a, 0x2e, 0x4d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x61, 0x6d,
-0x3b, 0x53, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x2bb,
-0x20, 0x49, 0x49, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20,
-0x49, 0x49, 0x3b, 0x52, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x53, 0x68, 0x61, 0x2bc, 0x61, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61,
-0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x53, 0x68, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x44, 0x68, 0x75, 0x2bb, 0x6c, 0x2d,
-0x51, 0x69, 0x2bb, 0x64, 0x61, 0x68, 0x3b, 0x44, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x48, 0x69, 0x6a, 0x6a, 0x61, 0x68, 0x5de,
-0x5d5, 0x5d7, 0x5e8, 0x5dd, 0x3b, 0x5e6, 0x5e4, 0x5e8, 0x3b, 0x5e8, 0x5d1, 0x5d9, 0x5e2, 0x20, 0x5d0, 0x5dc, 0x5be, 0x5d0, 0x5d5, 0x5d5,
-0x5dc, 0x3b, 0x5e8, 0x5d1, 0x5d9, 0x5e2, 0x20, 0x5d0, 0x5be, 0x5ea, 0x5f3, 0x5d0, 0x5e0, 0x5d9, 0x3b, 0x5d2, 0x5f3, 0x5d5, 0x5de, 0x5d0,
-0x5d3, 0x5d0, 0x20, 0x5d0, 0x5dc, 0x5be, 0x5d0, 0x5d5, 0x5dc, 0x5d0, 0x3b, 0x5d2, 0x5f3, 0x5d5, 0x5de, 0x5d0, 0x5d3, 0x5d0, 0x20, 0x5d0,
-0x5be, 0x5ea, 0x5f3, 0x5d0, 0x5e0, 0x5d9, 0x5d4, 0x3b, 0x5e8, 0x5d2, 0x5f3, 0x5d1, 0x3b, 0x5e9, 0x5e2, 0x5d1, 0x5d0, 0x5df, 0x3b, 0x5e8,
-0x5de, 0x5d3, 0x5d0, 0x5df, 0x3b, 0x5e9, 0x5d5, 0x5d5, 0x5d0, 0x5dc, 0x3b, 0x5d3, 0x5f3, 0x5d5, 0x20, 0x5d0, 0x5dc, 0x5be, 0x5e7, 0x5e2,
-0x5d3, 0x5d4, 0x3b, 0x5d3, 0x5f3, 0x5d5, 0x20, 0x5d0, 0x5dc, 0x5be, 0x5d7, 0x5d9, 0x5d2, 0x5f3, 0x5d4, 0x5de, 0x5d5, 0x5d7, 0x5e8, 0x5dd,
-0x3b, 0x5e6, 0x5e4, 0x5e8, 0x3b, 0x5e8, 0x5d1, 0x5d9, 0x5e2, 0x20, 0x5d0, 0x5dc, 0x2d, 0x5d0, 0x5d5, 0x5d5, 0x5dc, 0x3b, 0x5e8, 0x5d1,
-0x5d9, 0x5e2, 0x20, 0x5d0, 0x2d, 0x5ea, 0x5f3, 0x5d0, 0x5e0, 0x5d9, 0x3b, 0x5d2, 0x5f3, 0x5d5, 0x5de, 0x5d0, 0x5d3, 0x5d0, 0x20, 0x5d0,
-0x5dc, 0x2d, 0x5d0, 0x5d5, 0x5dc, 0x5d0, 0x3b, 0x5d2, 0x5f3, 0x5d5, 0x5de, 0x5d0, 0x5d3, 0x5d0, 0x20, 0x5d0, 0x2d, 0x5ea, 0x5f3, 0x5d0,
-0x5e0, 0x5d9, 0x5d4, 0x3b, 0x5e8, 0x5d2, 0x5f3, 0x5d1, 0x3b, 0x5e9, 0x5e2, 0x5d1, 0x5d0, 0x5df, 0x3b, 0x5e8, 0x5de, 0x5d3, 0x5d0, 0x5df,
-0x3b, 0x5e9, 0x5d5, 0x5d5, 0x5d0, 0x5dc, 0x3b, 0x5d3, 0x5f3, 0x5d5, 0x20, 0x5d0, 0x5dc, 0x5be, 0x5e7, 0x5e2, 0x5d3, 0x5d4, 0x3b, 0x5d3,
-0x5f3, 0x5d5, 0x20, 0x5d0, 0x5dc, 0x5be, 0x5d7, 0x5d9, 0x5d2, 0x5f3, 0x5d4, 0x5de, 0x5d5, 0x5d7, 0x5e8, 0x5dd, 0x3b, 0x5e6, 0x5e4, 0x5e8,
-0x3b, 0x5e8, 0x5d1, 0x5d9, 0x5e2, 0x20, 0x5d0, 0x5f3, 0x3b, 0x5e8, 0x5d1, 0x5d9, 0x5e2, 0x20, 0x5d1, 0x5f3, 0x3b, 0x5d2, 0x5f3, 0x5d5,
-0x5de, 0x5d0, 0x5d3, 0x5d0, 0x20, 0x5d0, 0x5f3, 0x3b, 0x5d2, 0x5f3, 0x5d5, 0x5de, 0x5d0, 0x5d3, 0x5d0, 0x20, 0x5d1, 0x5f3, 0x3b, 0x5e8,
-0x5d2, 0x5f3, 0x5d1, 0x3b, 0x5e9, 0x5e2, 0x5d1, 0x5d0, 0x5df, 0x3b, 0x5e8, 0x5de, 0x5d3, 0x5d0, 0x5df, 0x3b, 0x5e9, 0x5d5, 0x5d5, 0x5d0,
-0x5dc, 0x3b, 0x5d3, 0x5f3, 0x5d5, 0x20, 0x5d0, 0x5dc, 0x5be, 0x5e7, 0x5e2, 0x5d3, 0x5d4, 0x3b, 0x5d3, 0x5f3, 0x5d5, 0x20, 0x5d0, 0x5dc,
-0x5be, 0x5d7, 0x5d9, 0x5d2, 0x5f3, 0x5d4, 0x92e, 0x941, 0x939, 0x930, 0x94d, 0x930, 0x92e, 0x3b, 0x938, 0x92b, 0x930, 0x3b, 0x930, 0x93e,
-0x92c, 0x940, 0x20, 0x92a, 0x94d, 0x930, 0x925, 0x92e, 0x3b, 0x930, 0x93e, 0x92c, 0x940, 0x20, 0x926, 0x94d, 0x935, 0x93f, 0x924, 0x940,
-0x92f, 0x3b, 0x91c, 0x941, 0x92e, 0x94d, 0x921, 0x93e, 0x20, 0x92a, 0x94d, 0x930, 0x925, 0x92e, 0x3b, 0x91c, 0x941, 0x92e, 0x94d, 0x921,
-0x93e, 0x20, 0x926, 0x94d, 0x935, 0x93f, 0x924, 0x940, 0x92f, 0x3b, 0x930, 0x91c, 0x92c, 0x3b, 0x936, 0x93e, 0x935, 0x928, 0x3b, 0x930,
-0x92e, 0x91c, 0x93e, 0x928, 0x3b, 0x936, 0x935, 0x94d, 0x935, 0x94d, 0x932, 0x3b, 0x91c, 0x93f, 0x932, 0x2d, 0x915, 0x94d, 0x926, 0x93e,
-0x939, 0x3b, 0x91c, 0x93f, 0x932, 0x94d, 0x2d, 0x939, 0x93f, 0x91c, 0x94d, 0x91c, 0x93e, 0x939, 0x4d, 0x75, 0x68, 0x61, 0x72, 0x72,
-0x61, 0x6d, 0x3b, 0x53, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x20, 0x61, 0x6c, 0x2d, 0x41, 0x77, 0x77,
-0x61, 0x6c, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x20, 0x61, 0x73, 0x2d, 0x53, 0x61, 0x61, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6d,
-0x61, 0x61, 0x64, 0x61, 0x20, 0x61, 0x6c, 0x2d, 0x41, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x61, 0x64,
-0x61, 0x20, 0x61, 0x73, 0x2d, 0x53, 0x61, 0x61, 0x6e, 0x69, 0x3b, 0x52, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x53, 0x68, 0x61,
-0x61, 0x62, 0x61, 0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x7a, 0x61, 0x61, 0x6e, 0x3b, 0x53, 0x68, 0x61, 0x77, 0x77, 0x61,
-0x61, 0x6c, 0x3b, 0x5a, 0x75, 0x2019, 0x6c, 0x2d, 0x51, 0x61, 0x61, 0x64, 0x61, 0x3b, 0x5a, 0x75, 0x2019, 0x6c, 0x2d, 0x48,
-0x69, 0x6a, 0x6a, 0x61, 0x4d, 0x75, 0x68, 0x3b, 0x53, 0x61, 0x66, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x20, 0x31, 0x3b, 0x52,
-0x61, 0x62, 0x69, 0x20, 0x32, 0x3b, 0x4a, 0x75, 0x6d, 0x20, 0x31, 0x3b, 0x4a, 0x75, 0x6d, 0x20, 0x32, 0x3b, 0x52, 0x61,
-0x6a, 0x61, 0x62, 0x3b, 0x53, 0x68, 0x61, 0x62, 0x3b, 0x52, 0x61, 0x6d, 0x3b, 0x53, 0x68, 0x61, 0x77, 0x3b, 0x5a, 0x75,
-0x20, 0x51, 0x3b, 0x5a, 0x75, 0x20, 0x48, 0x4d, 0x6f, 0x68, 0x61, 0x72, 0x72, 0x65, 0x6d, 0x3b, 0x53, 0x61, 0x66, 0x61,
-0x72, 0x3b, 0x52, 0xe9, 0x62, 0x69, 0x20, 0x49, 0x3b, 0x52, 0xe9, 0x62, 0x69, 0x20, 0x49, 0x49, 0x3b, 0x44, 0x73, 0x65,
-0x6d, 0xe1, 0x64, 0x69, 0x20, 0x49, 0x3b, 0x44, 0x73, 0x65, 0x6d, 0xe1, 0x64, 0x69, 0x20, 0x49, 0x49, 0x3b, 0x52, 0x65,
-0x64, 0x73, 0x65, 0x62, 0x3b, 0x53, 0x61, 0x62, 0xe1, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64, 0xe1, 0x6e, 0x3b, 0x53,
-0x65, 0x76, 0x76, 0xe1, 0x6c, 0x3b, 0x44, 0x73, 0xfc, 0x6c, 0x20, 0x6b, 0x61, 0x64, 0x65, 0x3b, 0x44, 0x73, 0xfc, 0x6c,
-0x20, 0x68, 0x65, 0x64, 0x73, 0x65, 0x4d, 0x6f, 0x68, 0x61, 0x72, 0x72, 0x65, 0x6d, 0x3b, 0x53, 0x61, 0x66, 0x61, 0x72,
-0x3b, 0x52, 0xe9, 0x62, 0x69, 0x20, 0x65, 0x6c, 0x20, 0x61, 0x76, 0x76, 0x65, 0x6c, 0x3b, 0x52, 0xe9, 0x62, 0x69, 0x20,
-0x65, 0x6c, 0x20, 0x61, 0x63, 0x63, 0x68, 0x65, 0x72, 0x3b, 0x44, 0x73, 0x65, 0x6d, 0xe1, 0x64, 0x69, 0x20, 0x65, 0x6c,
-0x20, 0x61, 0x76, 0x76, 0x65, 0x6c, 0x3b, 0x44, 0x73, 0x65, 0x6d, 0xe1, 0x64, 0x69, 0x20, 0x65, 0x6c, 0x20, 0x61, 0x63,
-0x63, 0x68, 0x65, 0x72, 0x3b, 0x52, 0x65, 0x64, 0x73, 0x65, 0x62, 0x3b, 0x53, 0x61, 0x62, 0xe1, 0x6e, 0x3b, 0x52, 0x61,
-0x6d, 0x61, 0x64, 0xe1, 0x6e, 0x3b, 0x53, 0x65, 0x76, 0x76, 0xe1, 0x6c, 0x3b, 0x44, 0x73, 0xfc, 0x6c, 0x20, 0x6b, 0x61,
-0x64, 0x65, 0x3b, 0x44, 0x73, 0xfc, 0x6c, 0x20, 0x68, 0x65, 0x64, 0x73, 0x65, 0x4d, 0x6f, 0x68, 0x2e, 0x3b, 0x53, 0x61,
-0x66, 0x2e, 0x3b, 0x52, 0xe9, 0x62, 0x2e, 0x20, 0x31, 0x3b, 0x52, 0xe9, 0x62, 0x2e, 0x20, 0x32, 0x3b, 0x44, 0x73, 0x65,
-0x6d, 0x2e, 0x20, 0x49, 0x3b, 0x44, 0x73, 0x65, 0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x52, 0x65, 0x64, 0x2e, 0x3b, 0x53,
-0x61, 0x62, 0x2e, 0x3b, 0x52, 0x61, 0x6d, 0x2e, 0x3b, 0x53, 0x65, 0x76, 0x2e, 0x3b, 0x44, 0x73, 0xfc, 0x6c, 0x20, 0x6b,
-0x2e, 0x3b, 0x44, 0x73, 0xfc, 0x6c, 0x20, 0x68, 0x2e, 0x6d, 0x75, 0x68, 0x2e, 0x3b, 0x73, 0x61, 0x66, 0x2e, 0x3b, 0x72,
-0x61, 0x62, 0x2e, 0x20, 0x49, 0x3b, 0x72, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x6a, 0x75, 0x6d, 0x2e, 0x20, 0x49,
-0x3b, 0x6a, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x72, 0x61, 0x6a, 0x2e, 0x3b, 0x73, 0x68, 0x61, 0x2e, 0x3b, 0x72,
-0x61, 0x6d, 0x2e, 0x3b, 0x73, 0x68, 0x61, 0x77, 0x2e, 0x3b, 0x64, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x51, 0x2e, 0x3b, 0x64,
-0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x48, 0x2e, 0x4d, 0x75, 0x68, 0x61, 0x72, 0x61, 0x6d, 0x3b, 0x53, 0x61, 0x66, 0x61, 0x72,
-0x3b, 0x52, 0x61, 0x62, 0x69, 0x75, 0x6c, 0x61, 0x77, 0x61, 0x6c, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x75, 0x6c, 0x61, 0x6b,
-0x68, 0x69, 0x72, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x64, 0x69, 0x6c, 0x61, 0x77, 0x61, 0x6c, 0x3b, 0x4a, 0x75, 0x6d, 0x61,
-0x64, 0x69, 0x6c, 0x61, 0x6b, 0x68, 0x69, 0x72, 0x3b, 0x52, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x53, 0x79, 0x61, 0x6b, 0x62,
-0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x53, 0x79, 0x61, 0x77, 0x61, 0x6c, 0x3b, 0x5a, 0x75,
-0x6c, 0x6b, 0x61, 0x69, 0x64, 0x61, 0x68, 0x3b, 0x5a, 0x75, 0x6c, 0x68, 0x69, 0x6a, 0x61, 0x68, 0x4d, 0x75, 0x68, 0x2e,
-0x3b, 0x53, 0x61, 0x66, 0x2e, 0x3b, 0x52, 0x61, 0x62, 0x2e, 0x20, 0x41, 0x77, 0x61, 0x6c, 0x3b, 0x52, 0x61, 0x62, 0x2e,
-0x20, 0x41, 0x6b, 0x68, 0x69, 0x72, 0x3b, 0x4a, 0x75, 0x6d, 0x2e, 0x20, 0x41, 0x77, 0x61, 0x6c, 0x3b, 0x4a, 0x75, 0x6d,
-0x2e, 0x20, 0x41, 0x6b, 0x68, 0x69, 0x72, 0x3b, 0x52, 0x61, 0x6a, 0x2e, 0x3b, 0x53, 0x79, 0x61, 0x2e, 0x3b, 0x52, 0x61,
-0x6d, 0x2e, 0x3b, 0x53, 0x79, 0x61, 0x77, 0x2e, 0x3b, 0x5a, 0x75, 0x6c, 0x6b, 0x61, 0x2e, 0x3b, 0x5a, 0x75, 0x6c, 0x68,
-0x69, 0x2e, 0x30e0, 0x30cf, 0x30c3, 0x30e9, 0x30e0, 0x3b, 0x30b5, 0x30d5, 0x30a2, 0x30eb, 0x3b, 0x30e9, 0x30d3, 0x30fc, 0x30fb, 0x30a6, 0x30eb, 0x30fb,
-0x30a2, 0x30a6, 0x30ef, 0x30eb, 0x3b, 0x30e9, 0x30d3, 0x30fc, 0x30fb, 0x30a6, 0x30c3, 0x30fb, 0x30b5, 0x30fc, 0x30cb, 0x30fc, 0x3b, 0x30b8, 0x30e5, 0x30de,
-0x30fc, 0x30c0, 0x30eb, 0x30fb, 0x30a2, 0x30a6, 0x30ef, 0x30eb, 0x3b, 0x30b8, 0x30e5, 0x30de, 0x30fc, 0x30c0, 0x30c3, 0x30b5, 0x30fc, 0x30cb, 0x30fc, 0x3b,
-0x30e9, 0x30b8, 0x30e3, 0x30d6, 0x3b, 0x30b7, 0x30e3, 0x30a2, 0x30d0, 0x30fc, 0x30f3, 0x3b, 0x30e9, 0x30de, 0x30c0, 0x30fc, 0x30f3, 0x3b, 0x30b7, 0x30e3,
-0x30a6, 0x30ef, 0x30fc, 0x30eb, 0x3b, 0x30ba, 0x30eb, 0x30fb, 0x30ab, 0x30a4, 0x30c0, 0x3b, 0x30ba, 0x30eb, 0x30fb, 0x30d2, 0x30c3, 0x30b8, 0x30e3, 0x53,
-0x75, 0x72, 0x61, 0x3b, 0x53, 0x61, 0x70, 0x61, 0x72, 0x3b, 0x4d, 0x75, 0x6c, 0x75, 0x64, 0x3b, 0x42, 0x61, 0x6b, 0x64,
-0x61, 0x20, 0x4d, 0x75, 0x6c, 0x75, 0x64, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x64, 0x69, 0x6c, 0x61, 0x77, 0x61, 0x6c, 0x3b,
-0x4a, 0x75, 0x6d, 0x61, 0x64, 0x69, 0x6c, 0x61, 0x6b, 0x69, 0x72, 0x3b, 0x52, 0x65, 0x6a, 0x65, 0x62, 0x3b, 0x52, 0x75,
-0x77, 0x61, 0x68, 0x3b, 0x50, 0x61, 0x73, 0x61, 0x3b, 0x53, 0x61, 0x77, 0x61, 0x6c, 0x3b, 0x53, 0x65, 0x6c, 0x6f, 0x3b,
-0x42, 0x65, 0x73, 0x61, 0x72, 0x53, 0x75, 0x72, 0x2e, 0x3b, 0x53, 0x61, 0x70, 0x2e, 0x3b, 0x4d, 0x75, 0x6c, 0x2e, 0x3b,
-0x42, 0x2e, 0x20, 0x4d, 0x75, 0x6c, 0x2e, 0x3b, 0x4a, 0x75, 0x6d, 0x2e, 0x20, 0x41, 0x77, 0x2e, 0x3b, 0x4a, 0x75, 0x6d,
-0x2e, 0x20, 0x41, 0x6b, 0x2e, 0x3b, 0x52, 0x65, 0x6a, 0x2e, 0x3b, 0x52, 0x75, 0x77, 0x2e, 0x3b, 0x50, 0x73, 0x6f, 0x2e,
-0x3b, 0x53, 0x68, 0x61, 0x77, 0x2e, 0x3b, 0x53, 0x6c, 0x6f, 0x2e, 0x3b, 0x42, 0x73, 0x61, 0x72, 0x2e, 0xcae, 0xcc1, 0xcb9,
-0xcb0, 0xcae, 0xccd, 0x3b, 0xcb8, 0xcab, 0xcbe, 0xcb0, 0xccd, 0x3b, 0xcb0, 0xcac, 0xcbf, 0x2018, 0x20, 0x49, 0x3b, 0xcb0, 0xcac, 0xcbf,
-0x2018, 0x20, 0x49, 0x49, 0x3b, 0xc9c, 0xcc1, 0xcae, 0xcbe, 0xca6, 0xcbe, 0x20, 0x49, 0x3b, 0xc9c, 0xcc1, 0xcae, 0xcbe, 0xca6, 0xcbe,
-0x20, 0x49, 0x49, 0x3b, 0xcb0, 0xc9c, 0xcac, 0xccd, 0x3b, 0xcb6, 0x2019, 0xcac, 0xcbe, 0xca8, 0xccd, 0x3b, 0xcb0, 0xcae, 0xca6, 0xcbe,
-0xca8, 0xccd, 0x3b, 0xcb6, 0xcb5, 0xccd, 0xcb5, 0xcbe, 0xcb2, 0xccd, 0x3b, 0xca7, 0xcc1, 0x2018, 0xcb2, 0xccd, 0x2d, 0xc95, 0xcbf, 0x2018,
-0xca1, 0xcbe, 0xcb9, 0xccd, 0x3b, 0xca7, 0xcc1, 0x2018, 0xcb2, 0xccd, 0x2d, 0xcb9, 0xcbf, 0xc9c, 0xcbe, 0xcb9, 0xccd, 0xcae, 0xcc1, 0xcb9,
-0xccd, 0x2e, 0x3b, 0xcb8, 0xcab, 0xcbe, 0x2e, 0x3b, 0xcb0, 0xcac, 0xcbf, 0x2018, 0x20, 0x49, 0x3b, 0xcb0, 0xcac, 0xcbf, 0x2018, 0x20,
-0x49, 0x49, 0x3b, 0xc9c, 0xcc1, 0xcae, 0xccd, 0x2e, 0x20, 0x49, 0x3b, 0xc9c, 0xcc1, 0xcae, 0xccd, 0x2e, 0x20, 0x49, 0x49, 0x3b,
-0xcb0, 0xc9c, 0xccd, 0x2e, 0x3b, 0xcb6, 0x2e, 0x3b, 0xcb0, 0xcae, 0xccd, 0x2e, 0x3b, 0xcb6, 0xcb5, 0xccd, 0x2e, 0x3b, 0xca7, 0xcc1,
-0x2018, 0xcb2, 0xccd, 0x2d, 0xc95, 0xcbf, 0x2e, 0x3b, 0xca7, 0xcc1, 0x2018, 0xcb2, 0xccd, 0x2d, 0xcb9, 0x2e, 0x41c, 0x4b1, 0x445, 0x430,
-0x440, 0x440, 0x430, 0x43c, 0x3b, 0x421, 0x430, 0x444, 0x430, 0x440, 0x3b, 0x420, 0x430, 0x431, 0x438, 0x493, 0x20, 0x4d9, 0x43b, 0x2d,
-0x4d9, 0x443, 0x443, 0x4d9, 0x43b, 0x3b, 0x420, 0x430, 0x431, 0x438, 0x493, 0x20, 0x4d9, 0x441, 0x2d, 0x441, 0x4d9, 0x43d, 0x438, 0x3b,
-0x414, 0x436, 0x443, 0x43c, 0x430, 0x434, 0x430, 0x20, 0x4d9, 0x43b, 0x2d, 0x4d9, 0x443, 0x443, 0x4d9, 0x43b, 0x3b, 0x416, 0x443, 0x43c,
-0x430, 0x434, 0x20, 0x430, 0x441, 0x2d, 0x441, 0x4d9, 0x43d, 0x438, 0x3b, 0x420, 0x430, 0x434, 0x436, 0x430, 0x431, 0x3b, 0x428, 0x430,
-0x493, 0x431, 0x430, 0x43d, 0x3b, 0x420, 0x430, 0x43c, 0x430, 0x434, 0x430, 0x43d, 0x3b, 0x428, 0x4d9, 0x443, 0x443, 0x4d9, 0x43b, 0x3b,
-0x417, 0x443, 0x43b, 0x2d, 0x49a, 0x430, 0x493, 0x434, 0x430, 0x3b, 0x417, 0x443, 0x43b, 0x2d, 0x425, 0x438, 0x434, 0x436, 0x430, 0x49a,
-0x430, 0x4a3, 0x2e, 0x3b, 0x410, 0x49b, 0x43f, 0x2e, 0x3b, 0x41d, 0x430, 0x443, 0x2e, 0x3b, 0x421, 0x4d9, 0x443, 0x2e, 0x3b, 0x41c,
-0x430, 0x43c, 0x2e, 0x3b, 0x4a, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x448, 0x456, 0x43b, 0x2e, 0x3b, 0x442, 0x430, 0x43c,
-0x2e, 0x3b, 0x49a, 0x44b, 0x440, 0x2e, 0x3b, 0x49a, 0x430, 0x437, 0x2e, 0x3b, 0x49a, 0x430, 0x440, 0x2e, 0x3b, 0x416, 0x435, 0x43b,
-0x2e, 0xbb34, 0xd558, 0xb78c, 0x3b, 0xc0ac, 0xd30c, 0xb974, 0x3b, 0xb77c, 0xbe44, 0x20, 0xc54c, 0x20, 0xc544, 0xc648, 0x3b, 0xb77c, 0xbe44, 0x20,
-0xc54c, 0x20, 0xc384, 0xb2c8, 0x3b, 0xc8fc, 0xb9c8, 0xb2e4, 0x20, 0xc54c, 0x20, 0xc544, 0xc648, 0x3b, 0xc8fc, 0xb9c8, 0xb2e4, 0x20, 0xc54c, 0x20,
-0xc384, 0xb2c8, 0x3b, 0xb77c, 0xc7a1, 0x3b, 0xc250, 0xc544, 0xbc18, 0x3b, 0xb77c, 0xb9c8, 0xb2e8, 0x3b, 0xc250, 0xc648, 0x3b, 0xb4c0, 0x20, 0xc54c,
-0x20, 0xae4c, 0xb2e4, 0x3b, 0xb4c0, 0x20, 0xc54c, 0x20, 0xd788, 0xc790, 0x6d, 0x75, 0x1e96, 0x65, 0x72, 0x65, 0x6d, 0x3b, 0x73, 0x65,
-0x66, 0x65, 0x72, 0x3b, 0x72, 0x65, 0x62, 0xee, 0x2bf, 0x75, 0x6c, 0x65, 0x77, 0x65, 0x6c, 0x3b, 0x72, 0x65, 0x62, 0xee,
-0x2bf, 0x75, 0x6c, 0x61, 0x78, 0x65, 0x72, 0x3b, 0x63, 0x65, 0x6d, 0x61, 0x7a, 0xee, 0x79, 0x65, 0x6c, 0x65, 0x77, 0x65,
-0x6c, 0x3b, 0x63, 0x65, 0x6d, 0x61, 0x7a, 0xee, 0x79, 0x65, 0x6c, 0x61, 0x78, 0x65, 0x72, 0x3b, 0x72, 0x65, 0x63, 0x65,
-0x62, 0x3b, 0x15f, 0x65, 0x2bf, 0x62, 0x61, 0x6e, 0x3b, 0x72, 0x65, 0x6d, 0x65, 0x7a, 0x61, 0x6e, 0x3b, 0x15f, 0x65, 0x77,
-0x61, 0x6c, 0x3b, 0x7a, 0xee, 0x6c, 0x71, 0x65, 0x2bf, 0x64, 0x65, 0x3b, 0x7a, 0xee, 0x6c, 0x1e96, 0x65, 0x63, 0x65, 0xea1,
-0xeb8, 0xea3, 0xeb0, 0xeae, 0xead, 0xea1, 0x3b, 0xe8a, 0xeb2, 0xe9f, 0xeb2, 0xea3, 0x3b, 0xeae, 0xead, 0xe94, 0xe9a, 0xeb5, 0x20, 0x31,
-0x3b, 0xeae, 0xead, 0xe94, 0xe9a, 0xeb5, 0x20, 0x32, 0x3b, 0xe88, 0xeb8, 0xea1, 0xeb2, 0xe94, 0xeb2, 0x20, 0x31, 0x3b, 0xe88, 0xeb8,
-0xea1, 0xeb2, 0xe94, 0xeb2, 0x20, 0x32, 0x3b, 0xeae, 0xeb2, 0xe88, 0xeb1, 0xe9a, 0x3b, 0xe8a, 0xeb0, 0xe9a, 0xeb2, 0xe99, 0x3b, 0xeae,
-0xeb2, 0xea1, 0xeb2, 0xe94, 0xead, 0xe99, 0x3b, 0xec0, 0xe8a, 0xebb, 0xeb2, 0xea7, 0xeb1, 0xe94, 0x3b, 0xe94, 0xeb8, 0xead, 0xeb1, 0xe94,
-0xe81, 0xeb4, 0xe94, 0xeb0, 0x3b, 0xe94, 0xeb8, 0xead, 0xeb1, 0xe94, 0xe81, 0xeb4, 0xe88, 0xeb0, 0xea1, 0xeb8, 0xeae, 0xeb1, 0xe94, 0x3b,
-0xec0, 0xe84, 0xeb2, 0xeb0, 0x3b, 0xeae, 0xead, 0xe81, 0xe9a, 0xeb5, 0x20, 0x31, 0x3b, 0xeae, 0xead, 0xe81, 0xe9a, 0xeb5, 0x20, 0x32,
-0x3b, 0xe99, 0xeb8, 0xea1, 0xeb2, 0x20, 0x31, 0x3b, 0xe99, 0xeb8, 0xea1, 0xeb2, 0x20, 0x32, 0x3b, 0xec0, 0xeae, 0xeb2, 0xeb0, 0x3b,
-0xe8a, 0xeb2, 0x3b, 0xec0, 0xeae, 0xeb2, 0xeb0, 0xea1, 0xeb0, 0x3b, 0xec0, 0xe8a, 0xebb, 0xeb2, 0x3b, 0xe8a, 0xeb8, 0xea5, 0xe81, 0xeb4,
-0xead, 0xeb8, 0x3b, 0xe8a, 0xeb8, 0xea5, 0xeab, 0xeb4, 0xe88, 0xea1, 0xeb8, 0xeae, 0xeb1, 0xe94, 0x3b, 0xec0, 0xe84, 0xeb2, 0xeb0, 0x3b,
-0xeae, 0xead, 0xe94, 0xe9a, 0xeb5, 0x20, 0x31, 0x3b, 0xeae, 0xead, 0xe81, 0xe9a, 0xeb5, 0x20, 0x32, 0x3b, 0xe99, 0xeb8, 0xea1, 0xeb2,
-0x20, 0x31, 0x3b, 0xe99, 0xeb8, 0xea1, 0xeb2, 0x20, 0x32, 0x3b, 0xec0, 0xeae, 0xeb2, 0xeb0, 0x3b, 0xe8a, 0xeb0, 0xead, 0xecc, 0x3b,
-0xec0, 0xeae, 0xeb2, 0xeb0, 0xea1, 0xeb0, 0x3b, 0xec0, 0xe8a, 0xebb, 0xeb2, 0x3b, 0xe8a, 0xeb8, 0xea5, 0xe81, 0xeb4, 0xead, 0xeb8, 0x3b,
-0xe8a, 0xeb8, 0xea5, 0xeab, 0xeb4, 0xe88, 0x6d, 0x75, 0x68, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3b, 0x73, 0x61, 0x66, 0x61, 0x72,
-0x73, 0x3b, 0x31, 0x2e, 0x20, 0x72, 0x61, 0x62, 0x12b, 0x3b, 0x32, 0x2e, 0x20, 0x72, 0x61, 0x62, 0x12b, 0x3b, 0x31, 0x2e,
-0x20, 0x64, 0x17e, 0x75, 0x6d, 0x101, 0x64, 0x101, 0x3b, 0x32, 0x2e, 0x20, 0x64, 0x17e, 0x75, 0x6d, 0x101, 0x64, 0x101, 0x3b,
-0x72, 0x61, 0x64, 0x17e, 0x61, 0x62, 0x73, 0x3b, 0x161, 0x61, 0x62, 0x61, 0x6e, 0x73, 0x3b, 0x72, 0x61, 0x6d, 0x61, 0x64,
-0x101, 0x6e, 0x73, 0x3b, 0x161, 0x61, 0x75, 0x76, 0x61, 0x6c, 0x73, 0x3b, 0x64, 0x75, 0x20, 0x61, 0x6c, 0x2d, 0x6b, 0x69,
-0x64, 0x101, 0x3b, 0x64, 0x75, 0x20, 0x61, 0x6c, 0x2d, 0x68, 0x69, 0x64, 0x17e, 0x101, 0x43c, 0x443, 0x445, 0x430, 0x440, 0x435,
-0x43c, 0x3b, 0x441, 0x430, 0x444, 0x430, 0x440, 0x3b, 0x440, 0x430, 0x431, 0x438, 0x20, 0x49, 0x3b, 0x440, 0x430, 0x431, 0x438, 0x20,
-0x49, 0x49, 0x3b, 0x45f, 0x443, 0x43c, 0x430, 0x434, 0x430, 0x20, 0x49, 0x3b, 0x45f, 0x443, 0x43c, 0x430, 0x434, 0x430, 0x20, 0x49,
-0x49, 0x3b, 0x440, 0x430, 0x45f, 0x430, 0x431, 0x3b, 0x448, 0x430, 0x431, 0x430, 0x43d, 0x3b, 0x440, 0x430, 0x43c, 0x430, 0x434, 0x430,
-0x43d, 0x3b, 0x448, 0x430, 0x432, 0x430, 0x43b, 0x3b, 0x434, 0x443, 0x43b, 0x43a, 0x438, 0x434, 0x430, 0x3b, 0x434, 0x443, 0x43b, 0x445,
-0x438, 0x45f, 0x430, 0x43c, 0x443, 0x445, 0x2e, 0x3b, 0x441, 0x430, 0x444, 0x2e, 0x3b, 0x440, 0x430, 0x431, 0x2e, 0x20, 0x49, 0x3b,
-0x440, 0x430, 0x431, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x45f, 0x443, 0x43c, 0x2e, 0x20, 0x49, 0x3b, 0x45f, 0x443, 0x43c, 0x2e, 0x20,
-0x49, 0x49, 0x3b, 0x440, 0x430, 0x45f, 0x2e, 0x3b, 0x448, 0x430, 0x431, 0x2e, 0x3b, 0x440, 0x430, 0x43c, 0x2e, 0x3b, 0x448, 0x430,
-0x432, 0x2e, 0x3b, 0x434, 0x443, 0x43b, 0x43a, 0x2e, 0x3b, 0x434, 0x443, 0x43b, 0x445, 0x2e, 0xd2e, 0xd41, 0xd39, 0xd31, 0xd02, 0x3b,
-0xd38, 0xd2b, 0xd7c, 0x3b, 0xd31, 0xd2c, 0xd40, 0xd39, 0xd41, 0xd7d, 0x20, 0xd05, 0xd35, 0xd4d, 0xd35, 0xd7d, 0x3b, 0xd31, 0xd2c, 0xd40,
-0xd39, 0xd41, 0xd7d, 0x20, 0xd06, 0xd16, 0xd3f, 0xd7c, 0x3b, 0xd1c, 0xd2e, 0xd3e, 0xd26, 0xd41, 0xd7d, 0x20, 0xd05, 0xd35, 0xd4d, 0xd35,
-0xd7d, 0x3b, 0xd1c, 0xd2e, 0xd3e, 0xd26, 0xd41, 0xd7d, 0x20, 0xd06, 0xd16, 0xd3f, 0xd7c, 0x3b, 0xd31, 0xd1c, 0xd2c, 0xd4d, 0x3b, 0xd36,
-0xd39, 0xd2c, 0xd3e, 0xd7b, 0x3b, 0xd31, 0xd2e, 0xd26, 0xd3e, 0xd7b, 0x3b, 0xd36, 0xd35, 0xd4d, 0xd35, 0xd3e, 0xd7d, 0x3b, 0xd26, 0xd41,
-0xd7d, 0x20, 0xd16, 0xd39, 0xd26, 0xd4d, 0x3b, 0xd26, 0xd41, 0xd7d, 0x20, 0xd39, 0xd3f, 0xd1c, 0xd4d, 0xd1c, 0xd2e, 0xd41, 0xd39, 0xd31,
-0xd02, 0x3b, 0xd38, 0xd2b, 0xd7c, 0x3b, 0xd31, 0xd2c, 0xd40, 0xd39, 0xd41, 0xd7d, 0x20, 0xd05, 0xd35, 0xd4d, 0xd35, 0xd7d, 0x3b, 0xd31,
-0xd2c, 0xd40, 0xd39, 0xd41, 0xd7d, 0x20, 0xd06, 0xd16, 0xd3f, 0xd7c, 0x3b, 0xd1c, 0xd2e, 0xd3e, 0xd26, 0xd41, 0xd7d, 0x20, 0xd05, 0xd35,
-0xd4d, 0xd35, 0xd7d, 0x3b, 0xd1c, 0xd2e, 0xd3e, 0xd26, 0xd41, 0xd7d, 0x20, 0xd06, 0xd16, 0xd3f, 0xd7c, 0x3b, 0xd31, 0xd1c, 0xd2c, 0xd4d,
-0x3b, 0xd36, 0xd39, 0xd2c, 0xd3e, 0xd7b, 0x3b, 0xd31, 0xd2e, 0xd33, 0xd3e, 0xd7b, 0x3b, 0xd36, 0xd35, 0xd4d, 0xd35, 0xd3e, 0xd7d, 0x3b,
-0xd26, 0xd41, 0xd7d, 0x20, 0xd16, 0xd39, 0xd26, 0xd4d, 0x3b, 0xd26, 0xd41, 0xd7d, 0x20, 0xd39, 0xd3f, 0xd1c, 0xd4d, 0xd1c, 0xd2e, 0xd41,
-0xd39, 0x2e, 0x3b, 0xd38, 0xd2b, 0x2e, 0x3b, 0xd31, 0xd2c, 0xd40, 0xd39, 0xd41, 0xd7d, 0x20, 0xd05, 0xd35, 0xd4d, 0xd35, 0x2e, 0x3b,
-0xd31, 0xd2c, 0xd40, 0xd39, 0xd41, 0xd7d, 0x20, 0xd06, 0xd16, 0xd3f, 0x2e, 0x3b, 0xd1c, 0xd2e, 0xd3e, 0xd26, 0xd41, 0xd7d, 0x20, 0xd05,
-0xd35, 0xd4d, 0xd35, 0x2e, 0x3b, 0xd1c, 0xd2e, 0xd3e, 0xd26, 0xd41, 0xd7d, 0x20, 0xd06, 0xd16, 0xd3f, 0x2e, 0x3b, 0xd31, 0xd1c, 0x2e,
-0x3b, 0xd36, 0xd39, 0xd2c, 0xd3e, 0x2e, 0x3b, 0xd31, 0xd2e, 0xd26, 0xd3e, 0x2e, 0x3b, 0xd36, 0xd35, 0xd4d, 0xd35, 0xd3e, 0x2e, 0x3b,
-0xd26, 0xd41, 0xd7d, 0x20, 0xd16, 0xd39, 0x2e, 0x3b, 0xd26, 0xd41, 0xd7d, 0x20, 0xd39, 0xd3f, 0x2e, 0xd2e, 0xd41, 0x3b, 0xd38, 0x3b,
-0xd31, 0x3b, 0xd31, 0x3b, 0xd1c, 0x3b, 0xd1c, 0x3b, 0xd31, 0x3b, 0xd36, 0x3b, 0xd31, 0x3b, 0xd36, 0x3b, 0xd26, 0xd41, 0x3b, 0xd26,
-0xd41, 0x4d, 0x75, 0x68, 0x61, 0x72, 0x61, 0x6d, 0x3b, 0x53, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x75,
-0x6c, 0x61, 0x77, 0x61, 0x6c, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x75, 0x6c, 0x61, 0x6b, 0x68, 0x69, 0x72, 0x3b, 0x4a, 0x61,
-0x6d, 0x61, 0x64, 0x69, 0x6c, 0x61, 0x77, 0x61, 0x6c, 0x3b, 0x4a, 0x61, 0x6d, 0x61, 0x64, 0x69, 0x6c, 0x61, 0x6b, 0x68,
-0x69, 0x72, 0x3b, 0x52, 0x65, 0x6a, 0x61, 0x62, 0x3b, 0x53, 0x79, 0x61, 0x61, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d,
-0x61, 0x64, 0x61, 0x6e, 0x3b, 0x53, 0x79, 0x61, 0x77, 0x61, 0x6c, 0x3b, 0x5a, 0x75, 0x6c, 0x6b, 0x61, 0x65, 0x64, 0x61,
-0x68, 0x3b, 0x5a, 0x75, 0x6c, 0x68, 0x69, 0x6a, 0x61, 0x68, 0x4d, 0x75, 0x68, 0x2e, 0x3b, 0x53, 0x61, 0x66, 0x2e, 0x3b,
-0x52, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x3b, 0x52, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x4a, 0x61, 0x6d, 0x2e, 0x20,
-0x49, 0x3b, 0x4a, 0x61, 0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x52, 0x65, 0x6a, 0x2e, 0x3b, 0x53, 0x79, 0x61, 0x61, 0x2e,
-0x3b, 0x52, 0x61, 0x6d, 0x2e, 0x3b, 0x53, 0x79, 0x61, 0x77, 0x2e, 0x3b, 0x5a, 0x75, 0x6c, 0x6b, 0x2e, 0x3b, 0x5a, 0x75,
-0x6c, 0x68, 0x2e, 0x92e, 0x94b, 0x939, 0x930, 0x92e, 0x3b, 0x938, 0x92b, 0x930, 0x3b, 0x930, 0x93e, 0x92c, 0x940, 0x20, 0x49, 0x3b,
-0x930, 0x93e, 0x92c, 0x940, 0x20, 0x49, 0x49, 0x3b, 0x91c, 0x941, 0x92e, 0x93e, 0x926, 0x93e, 0x20, 0x49, 0x3b, 0x91c, 0x941, 0x92e,
-0x93e, 0x926, 0x93e, 0x20, 0x49, 0x49, 0x3b, 0x930, 0x91d, 0x93e, 0x92c, 0x3b, 0x936, 0x93e, 0x92c, 0x93e, 0x928, 0x3b, 0x930, 0x92e,
-0x91c, 0x93e, 0x928, 0x3b, 0x936, 0x935, 0x94d, 0x935, 0x93e, 0x932, 0x3b, 0x927, 0x941, 0x932, 0x2d, 0x915, 0x940, 0x926, 0x93e, 0x939,
-0x3b, 0x927, 0x941, 0x932, 0x2d, 0x939, 0x93f, 0x91c, 0x93e, 0x939, 0x92e, 0x94b, 0x939, 0x2e, 0x3b, 0x938, 0x92b, 0x2e, 0x3b, 0x930,
-0x93e, 0x92c, 0x940, 0x20, 0x49, 0x3b, 0x930, 0x93e, 0x92c, 0x940, 0x20, 0x49, 0x49, 0x3b, 0x91c, 0x941, 0x92e, 0x93e, 0x2e, 0x20,
-0x49, 0x3b, 0x91c, 0x941, 0x92e, 0x93e, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x930, 0x91d, 0x93e, 0x2e, 0x3b, 0x936, 0x93e, 0x92c, 0x93e,
-0x2e, 0x3b, 0x930, 0x92e, 0x2e, 0x3b, 0x936, 0x935, 0x94d, 0x935, 0x93e, 0x2e, 0x3b, 0x927, 0x941, 0x932, 0x2d, 0x915, 0x940, 0x2e,
-0x3b, 0x927, 0x941, 0x932, 0x2d, 0x939, 0x93f, 0x2e, 0x967, 0x3b, 0x968, 0x3b, 0x969, 0x3b, 0x96a, 0x3b, 0x96b, 0x3b, 0x96c, 0x3b,
-0x96d, 0x3b, 0x96e, 0x3b, 0x96f, 0x3b, 0x967, 0x966, 0x3b, 0x967, 0x967, 0x3b, 0x967, 0x968, 0x6d, 0x75, 0x68, 0x61, 0x72, 0x72,
-0x61, 0x6d, 0x3b, 0x73, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x72, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x3b, 0x72, 0x61, 0x62,
-0x69, 0x2bb, 0x20, 0x49, 0x49, 0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x64,
-0x61, 0x20, 0x49, 0x49, 0x3b, 0x72, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x73, 0x68, 0x61, 0x2bb, 0x62, 0x61, 0x6e, 0x3b, 0x72,
-0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x73, 0x68, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x64, 0x68, 0x75, 0x2bb, 0x6c,
-0x2d, 0x71, 0x69, 0x2bb, 0x64, 0x61, 0x68, 0x3b, 0x64, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x68, 0x69, 0x6a, 0x6a, 0x61, 0x68,
-0x6d, 0x75, 0x68, 0x2e, 0x3b, 0x73, 0x61, 0x66, 0x2e, 0x3b, 0x72, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x3b, 0x72, 0x61, 0x62,
-0x2e, 0x20, 0x49, 0x49, 0x3b, 0x6a, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x3b, 0x6a, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b,
-0x72, 0x61, 0x6a, 0x2e, 0x3b, 0x73, 0x68, 0x61, 0x2e, 0x3b, 0x72, 0x61, 0x6d, 0x2e, 0x3b, 0x73, 0x68, 0x61, 0x77, 0x2e,
-0x3b, 0x64, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x71, 0x2e, 0x3b, 0x44, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x48, 0x2e, 0x6d, 0x75,
-0x68, 0x2e, 0x3b, 0x73, 0x61, 0x66, 0x2e, 0x3b, 0x72, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x3b, 0x72, 0x61, 0x62, 0x2e, 0x20,
-0x49, 0x49, 0x3b, 0x6a, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x3b, 0x6a, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x72, 0x61,
-0x6a, 0x2e, 0x3b, 0x73, 0x68, 0x61, 0x2e, 0x3b, 0x72, 0x61, 0x6d, 0x2e, 0x3b, 0x73, 0x68, 0x61, 0x77, 0x2e, 0x3b, 0x64,
-0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x71, 0x2e, 0x3b, 0x64, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x68, 0x2e, 0x645, 0x62d, 0x631, 0x645,
-0x3b, 0x635, 0x641, 0x631, 0x3b, 0x631, 0x628, 0x64a, 0x639, 0x3b, 0x631, 0x628, 0x64a, 0x639, 0x20, 0x49, 0x49, 0x3b, 0x62c, 0x645,
-0x627, 0x639, 0x647, 0x3b, 0x62c, 0x645, 0x648, 0x645, 0x627, 0x20, 0x49, 0x49, 0x3b, 0x631, 0x62c, 0x628, 0x3b, 0x634, 0x639, 0x628,
-0x627, 0x646, 0x3b, 0x631, 0x645, 0x636, 0x627, 0x646, 0x3b, 0x634, 0x648, 0x627, 0x644, 0x3b, 0x62f, 0x627, 0x644, 0x642, 0x627, 0x639,
-0x62f, 0x647, 0x3b, 0x630, 0x64a, 0x20, 0x627, 0x644, 0x62d, 0x62c, 0x645, 0x62d, 0x631, 0x645, 0x3b, 0x635, 0x641, 0x631, 0x3b, 0x631,
-0x628, 0x64a, 0x639, 0x3b, 0x631, 0x628, 0x64a, 0x639, 0x20, 0x49, 0x49, 0x3b, 0x62c, 0x645, 0x627, 0x639, 0x647, 0x3b, 0x62c, 0x645,
-0x648, 0x645, 0x627, 0x20, 0x49, 0x49, 0x3b, 0x631, 0x62c, 0x628, 0x3b, 0x634, 0x639, 0x628, 0x627, 0x646, 0x3b, 0x631, 0x645, 0x636,
-0x627, 0x646, 0x3b, 0x634, 0x648, 0x627, 0x644, 0x3b, 0x630, 0x64a, 0x20, 0x627, 0x644, 0x642, 0x639, 0x62f, 0x647, 0x3b, 0x630, 0x64a,
-0x20, 0x627, 0x644, 0x62d, 0x62c, 0x645, 0x62d, 0x631, 0x645, 0x3b, 0x635, 0x641, 0x631, 0x3b, 0x631, 0x628, 0x64a, 0x639, 0x3b, 0x631,
-0x628, 0x64a, 0x639, 0x20, 0x49, 0x49, 0x3b, 0x62c, 0x645, 0x627, 0x639, 0x647, 0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x64a, 0x20, 0x6f2,
-0x3b, 0x631, 0x62c, 0x628, 0x3b, 0x634, 0x639, 0x628, 0x627, 0x646, 0x3b, 0x631, 0x645, 0x636, 0x627, 0x646, 0x3b, 0x634, 0x648, 0x627,
-0x644, 0x3b, 0x62f, 0x627, 0x644, 0x642, 0x627, 0x639, 0x62f, 0x647, 0x3b, 0x630, 0x64a, 0x20, 0x627, 0x644, 0x62d, 0x62c, 0x645, 0x62d,
-0x631, 0x645, 0x3b, 0x635, 0x641, 0x631, 0x3b, 0x631, 0x628, 0x64a, 0x639, 0x3b, 0x631, 0x628, 0x64a, 0x639, 0x20, 0x49, 0x49, 0x3b,
-0x62c, 0x645, 0x627, 0x62f, 0x20, 0x6f1, 0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x20, 0x6f2, 0x3b, 0x631, 0x62c, 0x628, 0x3b, 0x634, 0x639,
-0x628, 0x627, 0x646, 0x3b, 0x631, 0x645, 0x636, 0x627, 0x646, 0x3b, 0x634, 0x648, 0x627, 0x644, 0x3b, 0x62f, 0x627, 0x644, 0x642, 0x627,
-0x639, 0x62f, 0x647, 0x3b, 0x630, 0x64a, 0x20, 0x627, 0x644, 0x62d, 0x62c, 0x645, 0x62d, 0x631, 0x645, 0x3b, 0x62f, 0x20, 0x635, 0x641,
-0x631, 0x6d2, 0x20, 0x62f, 0x3b, 0x631, 0x628, 0x64a, 0x639, 0x3b, 0x631, 0x628, 0x64a, 0x639, 0x20, 0x49, 0x49, 0x3b, 0x62c, 0x645,
-0x627, 0x639, 0x647, 0x3b, 0x62c, 0x645, 0x648, 0x645, 0x627, 0x20, 0x49, 0x49, 0x3b, 0x631, 0x62c, 0x628, 0x3b, 0x634, 0x639, 0x628,
-0x627, 0x646, 0x3b, 0x631, 0x645, 0x636, 0x627, 0x646, 0x3b, 0x634, 0x648, 0x627, 0x644, 0x3b, 0x62f, 0x627, 0x644, 0x642, 0x627, 0x639,
-0x62f, 0x647, 0x3b, 0x630, 0x64a, 0x20, 0x627, 0x644, 0x62d, 0x62c, 0x645, 0x62d, 0x631, 0x645, 0x3b, 0x62f, 0x20, 0x635, 0x641, 0x631,
-0x6d2, 0x20, 0x62f, 0x3b, 0x631, 0x628, 0x64a, 0x639, 0x3b, 0x631, 0x628, 0x64a, 0x639, 0x20, 0x49, 0x49, 0x3b, 0x62c, 0x645, 0x627,
-0x639, 0x647, 0x3b, 0x62c, 0x645, 0x648, 0x645, 0x627, 0x20, 0x49, 0x49, 0x3b, 0x631, 0x62c, 0x628, 0x3b, 0x634, 0x639, 0x628, 0x627,
-0x646, 0x3b, 0x631, 0x645, 0x636, 0x627, 0x646, 0x3b, 0x634, 0x648, 0x627, 0x644, 0x3b, 0x630, 0x64a, 0x20, 0x627, 0x644, 0x642, 0x639,
-0x62f, 0x647, 0x3b, 0x630, 0x64a, 0x20, 0x627, 0x644, 0x62d, 0x62c, 0x645, 0x62d, 0x631, 0x645, 0x3b, 0x635, 0x641, 0x631, 0x3b, 0x631,
-0x628, 0x6cc, 0x639, 0x200c, 0x627, 0x644, 0x627, 0x648, 0x644, 0x3b, 0x631, 0x628, 0x6cc, 0x639, 0x200c, 0x627, 0x644, 0x62b, 0x627, 0x646,
-0x6cc, 0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x6cc, 0x200c, 0x627, 0x644, 0x627, 0x648, 0x644, 0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x6cc, 0x200c,
-0x627, 0x644, 0x62b, 0x627, 0x646, 0x6cc, 0x3b, 0x631, 0x62c, 0x628, 0x3b, 0x634, 0x639, 0x628, 0x627, 0x646, 0x3b, 0x631, 0x645, 0x636,
-0x627, 0x646, 0x3b, 0x634, 0x648, 0x627, 0x644, 0x3b, 0x630, 0x6cc, 0x642, 0x639, 0x62f, 0x647, 0x3b, 0x630, 0x6cc, 0x62d, 0x62c, 0x647,
-0x645, 0x62d, 0x631, 0x645, 0x3b, 0x635, 0x641, 0x631, 0x3b, 0x631, 0x628, 0x6cc, 0x639, 0x200c, 0x627, 0x644, 0x627, 0x648, 0x644, 0x3b,
-0x631, 0x628, 0x6cc, 0x639, 0x200c, 0x627, 0x644, 0x62b, 0x627, 0x646, 0x6cc, 0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x6cc, 0x200c, 0x627, 0x644,
-0x627, 0x648, 0x644, 0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x6cc, 0x200c, 0x627, 0x644, 0x62b, 0x627, 0x646, 0x6cc, 0x3b, 0x631, 0x62c, 0x628,
-0x3b, 0x634, 0x639, 0x628, 0x627, 0x646, 0x3b, 0x631, 0x645, 0x636, 0x627, 0x646, 0x3b, 0x634, 0x648, 0x627, 0x644, 0x3b, 0x630, 0x6cc,
-0x642, 0x639, 0x62f, 0x647, 0x654, 0x3b, 0x630, 0x6cc, 0x62d, 0x62c, 0x647, 0x654, 0x645, 0x3b, 0x635, 0x3b, 0x631, 0x3b, 0x631, 0x3b,
-0x62c, 0x3b, 0x62c, 0x3b, 0x631, 0x3b, 0x634, 0x3b, 0x631, 0x3b, 0x634, 0x3b, 0x630, 0x3b, 0x630, 0x4d, 0x75, 0x68, 0x61, 0x72,
-0x72, 0x61, 0x6d, 0x3b, 0x53, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x3b, 0x52, 0x61,
-0x62, 0x69, 0x2bb, 0x20, 0x49, 0x49, 0x3b, 0x44, 0x17c, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x3b, 0x44, 0x17c, 0x75,
-0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x49, 0x3b, 0x52, 0x61, 0x64, 0x17c, 0x61, 0x62, 0x3b, 0x53, 0x7a, 0x61, 0x62, 0x61,
-0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x53, 0x7a, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x5a, 0x75,
-0x20, 0x61, 0x6c, 0x2d, 0x6b, 0x61, 0x64, 0x61, 0x3b, 0x5a, 0x75, 0x20, 0x61, 0x6c, 0x2d, 0x68, 0x69, 0x64, 0x17c, 0x64,
-0x17c, 0x61, 0x4d, 0x75, 0x68, 0x2e, 0x3b, 0x53, 0x61, 0x66, 0x2e, 0x3b, 0x52, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x3b, 0x52,
-0x61, 0x62, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x44, 0x17c, 0x75, 0x2e, 0x20, 0x49, 0x3b, 0x44, 0x17c, 0x75, 0x2e, 0x20, 0x49,
-0x49, 0x3b, 0x52, 0x61, 0x2e, 0x3b, 0x53, 0x7a, 0x61, 0x2e, 0x3b, 0x52, 0x61, 0x6d, 0x2e, 0x3b, 0x53, 0x7a, 0x61, 0x77,
-0x2e, 0x3b, 0x5a, 0x75, 0x20, 0x61, 0x6c, 0x2d, 0x6b, 0x2e, 0x3b, 0x5a, 0x75, 0x20, 0x61, 0x6c, 0x2d, 0x68, 0x2e, 0xa2e,
-0xa41, 0xa39, 0xa71, 0xa30, 0xa2e, 0x3b, 0xa38, 0xa2b, 0xa30, 0x3b, 0xa30, 0xa2c, 0xa40, 0x2bb, 0x20, 0x49, 0x3b, 0xa30, 0xa2c, 0xa40,
-0x2bb, 0x20, 0x49, 0x49, 0x3b, 0xa1c, 0xa41, 0xa2e, 0xa3e, 0xa26, 0xa3e, 0x20, 0x49, 0x3b, 0xa1c, 0xa41, 0xa2e, 0xa3e, 0xa26, 0xa3e,
-0x20, 0x49, 0x49, 0x3b, 0xa30, 0xa1c, 0xa2c, 0x3b, 0xa38, 0xa3c, 0xa2c, 0xa3e, 0xa28, 0x3b, 0xa30, 0xa2e, 0xa1c, 0xa3c, 0xa3e, 0xa28,
-0x3b, 0xa38, 0xa3c, 0xa35, 0xa3e, 0xa32, 0x3b, 0xa26, 0xa42, 0x2d, 0xa05, 0xa32, 0x2d, 0xa15, 0xa40, 0xa26, 0xa3e, 0xa39, 0x3b, 0xa26,
-0xa42, 0x2d, 0xa05, 0xa32, 0x2d, 0xa39, 0xa3f, 0xa1c, 0xa4d, 0xa39, 0xa3e, 0xa2e, 0xa41, 0xa39, 0xa71, 0xa30, 0xa2e, 0x3b, 0xa38, 0xa2b,
-0xa30, 0x3b, 0xa30, 0xa2c, 0xa40, 0x20, 0x2bb, 0x20, 0x49, 0x3b, 0xa30, 0xa2c, 0xa40, 0x20, 0x2bb, 0x20, 0x49, 0x49, 0x3b, 0xa1c,
-0xa41, 0xa2e, 0xa3e, 0xa26, 0xa3e, 0x20, 0x49, 0x3b, 0xa1c, 0xa41, 0xa2e, 0xa3e, 0xa26, 0xa3e, 0x20, 0x49, 0x49, 0x3b, 0xa30, 0xa1c,
-0xa2c, 0x3b, 0xa38, 0xa3c, 0xa2c, 0xa3e, 0xa28, 0x3b, 0xa30, 0xa2e, 0xa1c, 0xa3c, 0xa3e, 0xa28, 0x3b, 0xa38, 0xa3c, 0xa35, 0xa3e, 0xa32,
-0x3b, 0xa26, 0xa42, 0x2d, 0xa05, 0xa32, 0x2d, 0xa15, 0xa40, 0xa26, 0xa3e, 0xa39, 0x3b, 0xa26, 0xa42, 0x2d, 0xa05, 0xa32, 0x2d, 0xa39,
-0xa3f, 0xa1c, 0xa4d, 0xa39, 0xa3e, 0xa2e, 0xa41, 0xa39, 0xa71, 0x2e, 0x3b, 0xa38, 0xa2b, 0x2e, 0x3b, 0xa30, 0xa2c, 0x2e, 0x20, 0x49,
-0x3b, 0xa30, 0xa2c, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0xa1c, 0xa41, 0xa2e, 0x2e, 0x20, 0x49, 0x3b, 0xa1c, 0xa41, 0xa2e, 0x2e, 0x20,
-0x49, 0x49, 0x3b, 0xa30, 0xa3e, 0xa1c, 0x2e, 0x3b, 0xa38, 0xa3c, 0xa3e, 0x2e, 0x3b, 0xa30, 0xa3e, 0xa2e, 0x2e, 0x3b, 0xa38, 0xa3c,
-0xa05, 0x2e, 0x3b, 0xa26, 0xa42, 0x2d, 0xa05, 0xa32, 0x2d, 0xa15, 0xa40, 0x2e, 0x3b, 0xa26, 0xa42, 0x2d, 0xa05, 0xa32, 0x2d, 0xa39,
-0xa3f, 0x2e, 0x43c, 0x443, 0x445, 0x430, 0x440, 0x440, 0x430, 0x43c, 0x3b, 0x441, 0x430, 0x444, 0x430, 0x440, 0x3b, 0x440, 0x430, 0x431,
-0x438, 0x2d, 0x443, 0x43b, 0x44c, 0x2d, 0x430, 0x432, 0x432, 0x430, 0x43b, 0x44c, 0x3b, 0x440, 0x430, 0x431, 0x438, 0x2d, 0x443, 0x43b,
-0x44c, 0x2d, 0x430, 0x445, 0x438, 0x440, 0x3b, 0x434, 0x436, 0x443, 0x43c, 0x430, 0x434, 0x2d, 0x443, 0x43b, 0x44c, 0x2d, 0x430, 0x432,
-0x432, 0x430, 0x43b, 0x44c, 0x3b, 0x434, 0x436, 0x443, 0x43c, 0x430, 0x434, 0x2d, 0x443, 0x43b, 0x44c, 0x2d, 0x430, 0x445, 0x438, 0x440,
-0x3b, 0x440, 0x430, 0x434, 0x436, 0x430, 0x431, 0x3b, 0x448, 0x430, 0x430, 0x431, 0x430, 0x43d, 0x3b, 0x440, 0x430, 0x43c, 0x430, 0x434,
-0x430, 0x43d, 0x3b, 0x448, 0x430, 0x432, 0x432, 0x430, 0x43b, 0x44c, 0x3b, 0x437, 0x443, 0x43b, 0x44c, 0x2d, 0x43a, 0x430, 0x430, 0x434,
-0x430, 0x3b, 0x437, 0x443, 0x43b, 0x44c, 0x2d, 0x445, 0x438, 0x434, 0x436, 0x436, 0x430, 0x43c, 0x443, 0x445, 0x2e, 0x3b, 0x441, 0x430,
-0x444, 0x2e, 0x3b, 0x440, 0x430, 0x431, 0x2e, 0x20, 0x49, 0x3b, 0x440, 0x430, 0x431, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x434, 0x436,
-0x443, 0x43c, 0x2e, 0x20, 0x49, 0x3b, 0x434, 0x436, 0x443, 0x43c, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x440, 0x430, 0x434, 0x436, 0x2e,
-0x3b, 0x448, 0x430, 0x430, 0x431, 0x2e, 0x3b, 0x440, 0x430, 0x43c, 0x2e, 0x3b, 0x448, 0x430, 0x432, 0x2e, 0x3b, 0x437, 0x443, 0x43b,
-0x44c, 0x2d, 0x43a, 0x2e, 0x3b, 0x437, 0x443, 0x43b, 0x44c, 0x2d, 0x445, 0x2e, 0x6d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x61, 0x6d,
-0x3b, 0x73, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x72, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x3b, 0x72, 0x61, 0x62, 0x69, 0x2bb,
-0x20, 0x49, 0x49, 0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20,
-0x49, 0x49, 0x3b, 0x72, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x73, 0x68, 0x61, 0x62, 0x61, 0x6e, 0x3b, 0x72, 0x61, 0x6d, 0x61,
-0x64, 0x61, 0x6e, 0x3b, 0x73, 0x68, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x64, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x71, 0x69,
-0x2bb, 0x64, 0x61, 0x68, 0x3b, 0x64, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x68, 0x69, 0x6a, 0x6a, 0x61, 0x68, 0x41c, 0x443, 0x445,
-0x430, 0x440, 0x435, 0x43c, 0x3b, 0x421, 0x430, 0x444, 0x430, 0x440, 0x3b, 0x420, 0x430, 0x431, 0x438, 0x2bb, 0x20, 0x49, 0x3b, 0x420,
-0x430, 0x431, 0x438, 0x2bb, 0x20, 0x49, 0x49, 0x3b, 0x408, 0x443, 0x43c, 0x430, 0x434, 0x430, 0x20, 0x49, 0x3b, 0x408, 0x443, 0x43c,
-0x430, 0x434, 0x430, 0x20, 0x49, 0x49, 0x3b, 0x420, 0x430, 0x452, 0x430, 0x431, 0x3b, 0x428, 0x430, 0x2bb, 0x431, 0x430, 0x43d, 0x3b,
-0x420, 0x430, 0x43c, 0x430, 0x434, 0x430, 0x43d, 0x3b, 0x428, 0x430, 0x432, 0x430, 0x43b, 0x3b, 0x414, 0x443, 0x2bb, 0x43b, 0x2d, 0x41a,
-0x438, 0x2bb, 0x434, 0x430, 0x3b, 0x414, 0x443, 0x2bb, 0x43b, 0x2d, 0x445, 0x438, 0x452, 0x430, 0x4d, 0x75, 0x68, 0x61, 0x72, 0x65,
-0x6d, 0x3b, 0x53, 0x61, 0x66, 0x65, 0x72, 0x3b, 0x52, 0x65, 0x62, 0x69, 0x20, 0x31, 0x3b, 0x52, 0x65, 0x62, 0x69, 0x20,
-0x32, 0x3b, 0x44, 0x17e, 0x75, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x31, 0x3b, 0x44, 0x17e, 0x75, 0x6d, 0x61, 0x64, 0x65, 0x20,
-0x32, 0x3b, 0x52, 0x65, 0x64, 0x17e, 0x65, 0x62, 0x3b, 0x160, 0x61, 0x2bb, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61,
-0x7a, 0x61, 0x6e, 0x3b, 0x160, 0x65, 0x76, 0x61, 0x6c, 0x3b, 0x5a, 0x75, 0x6c, 0x2d, 0x6b, 0x61, 0x64, 0x65, 0x3b, 0x5a,
-0x75, 0x6c, 0x2d, 0x68, 0x69, 0x64, 0x17e, 0x65, 0x4d, 0x75, 0x68, 0x61, 0x72, 0x65, 0x6d, 0x3b, 0x53, 0x61, 0x66, 0x61,
-0x72, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x49, 0x3b, 0x4a,
-0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x49, 0x3b, 0x52, 0x61,
-0x111, 0x61, 0x62, 0x3b, 0x160, 0x61, 0x2bb, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x160,
-0x61, 0x76, 0x61, 0x6c, 0x3b, 0x44, 0x75, 0x2bb, 0x6c, 0x2d, 0x4b, 0x69, 0x2bb, 0x64, 0x61, 0x3b, 0x44, 0x75, 0x2bb, 0x6c,
-0x2d, 0x68, 0x69, 0x111, 0x61, 0x4d, 0x75, 0x68, 0x2e, 0x3b, 0x53, 0x61, 0x66, 0x2e, 0x3b, 0x52, 0x65, 0x62, 0x2e, 0x20,
-0x31, 0x3b, 0x52, 0x65, 0x62, 0x2e, 0x20, 0x32, 0x3b, 0x44, 0x17e, 0x75, 0x6d, 0x2e, 0x20, 0x31, 0x3b, 0x44, 0x17e, 0x75,
-0x6d, 0x2e, 0x20, 0x32, 0x3b, 0x52, 0x65, 0x64, 0x17e, 0x2e, 0x3b, 0x160, 0x61, 0x2e, 0x3b, 0x52, 0x61, 0x6d, 0x2e, 0x3b,
-0x160, 0x65, 0x2e, 0x3b, 0x5a, 0x75, 0x6c, 0x2d, 0x6b, 0x2e, 0x3b, 0x5a, 0x75, 0x6c, 0x2d, 0x68, 0x2e, 0x645, 0x62d, 0x631,
-0x645, 0x3b, 0x635, 0x641, 0x631, 0x3b, 0x631, 0x628, 0x64a, 0x639, 0x20, 0x627, 0x644, 0x627, 0x648, 0x644, 0x3b, 0x631, 0x628, 0x6cc,
-0x639, 0x20, 0x627, 0x644, 0x627, 0x62e, 0x631, 0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x6cc, 0x20, 0x627, 0x644, 0x627, 0x648, 0x644, 0x3b,
-0x62c, 0x645, 0x627, 0x62f, 0x64a, 0x20, 0x627, 0x644, 0x627, 0x62e, 0x631, 0x3b, 0x631, 0x62c, 0x628, 0x3b, 0x634, 0x639, 0x628, 0x627,
-0x646, 0x3b, 0x631, 0x645, 0x636, 0x627, 0x646, 0x3b, 0x634, 0x648, 0x627, 0x644, 0x3b, 0x630, 0x648, 0x627, 0x644, 0x642, 0x639, 0x62f,
-0x3b, 0x630, 0x648, 0x627, 0x644, 0x62d, 0x62c, 0x6c1, 0x61, 0x6c, 0x2d, 0x6d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b,
-0x73, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x72, 0x61, 0x62, 0xed, 0xb4, 0x20, 0x61, 0x6c, 0x2d, 0x61, 0x76, 0x76, 0x61, 0x6c,
-0x3b, 0x72, 0x61, 0x62, 0xed, 0xb4, 0x61, 0x74, 0x68, 0x2d, 0x74, 0x68, 0xe1, 0x6e, 0xed, 0x3b, 0x64, 0x17e, 0x75, 0x6d,
-0xe1, 0x64, 0xe1, 0x20, 0x6c, 0x2d, 0xfa, 0x6c, 0xe1, 0x3b, 0x64, 0x17e, 0x75, 0x6d, 0xe1, 0x64, 0xe1, 0x20, 0x6c, 0x2d,
-0xe1, 0x63, 0x68, 0x69, 0x72, 0x61, 0x3b, 0x72, 0x61, 0x64, 0x17e, 0x61, 0x62, 0x3b, 0x161, 0x61, 0xb4, 0x20, 0x62, 0xe1,
-0x6e, 0x3b, 0x72, 0x61, 0x6d, 0x61, 0x64, 0xe1, 0x6e, 0x3b, 0x161, 0x61, 0x75, 0x76, 0xe1, 0x6c, 0x3b, 0x64, 0x68, 0xfa,
-0x20, 0x6c, 0x2d, 0x6b, 0x61, 0xb4, 0x20, 0x64, 0x61, 0x3b, 0x64, 0x68, 0xfa, 0x20, 0x6c, 0x2d, 0x68, 0x69, 0x64, 0x17e,
-0x64, 0x17e, 0x61, 0x6d, 0x75, 0x68, 0x2e, 0x3b, 0x73, 0x61, 0x66, 0x2e, 0x3b, 0x72, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x3b,
-0x72, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x64, 0x17e, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x3b, 0x64, 0x17e, 0x75, 0x6d,
-0x2e, 0x20, 0x49, 0x49, 0x3b, 0x72, 0x61, 0x64, 0x2e, 0x3b, 0x161, 0x61, 0x2e, 0x3b, 0x72, 0x61, 0x6d, 0x2e, 0x3b, 0x161,
-0x61, 0x75, 0x2e, 0x3b, 0x64, 0x68, 0xfa, 0x20, 0x6c, 0x2d, 0x6b, 0x2e, 0x3b, 0x64, 0x68, 0xfa, 0x20, 0x6c, 0x2d, 0x68,
-0x2e, 0x4d, 0x75, 0x78, 0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x53, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x52, 0x61, 0x62, 0x69,
-0x63, 0x20, 0x61, 0x6c, 0x2d, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x63, 0x20, 0x61, 0x6c, 0x2d,
-0x74, 0x68, 0x61, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x61, 0x6c, 0x2d, 0x61, 0x77, 0x77, 0x61,
-0x6c, 0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x61, 0x6c, 0x2d, 0x74, 0x68, 0x61, 0x6e, 0x69, 0x3b, 0x52, 0x61,
-0x6a, 0x61, 0x62, 0x3b, 0x53, 0x68, 0x61, 0x63, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b,
-0x53, 0x68, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x44, 0x75, 0x6c, 0x20, 0x61, 0x6c, 0x2d, 0x71, 0x61, 0x63, 0x64, 0x61,
-0x68, 0x3b, 0x44, 0x75, 0x6c, 0x20, 0x78, 0x69, 0x6a, 0x6a, 0x61, 0x68, 0x4d, 0x75, 0x78, 0x61, 0x72, 0x72, 0x61, 0x6d,
-0x3b, 0x53, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x63, 0x20, 0x61, 0x6c, 0x2d, 0x61, 0x77, 0x77, 0x61,
-0x6c, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x63, 0x20, 0x61, 0x6c, 0x2d, 0x74, 0x68, 0x61, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6d,
-0x61, 0x64, 0x61, 0x20, 0x61, 0x6c, 0x2d, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20,
-0x61, 0x6c, 0x2d, 0x74, 0x68, 0x61, 0x6e, 0x69, 0x3b, 0x52, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x53, 0x68, 0x61, 0x63, 0x62,
-0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x53, 0x68, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x44,
-0x75, 0x6c, 0x20, 0x61, 0x6c, 0x2d, 0x71, 0x61, 0x63, 0x64, 0x61, 0x3b, 0x44, 0x75, 0x6c, 0x20, 0x78, 0x69, 0x6a, 0x6a,
-0x61, 0x68, 0x4d, 0x75, 0x78, 0x2e, 0x3b, 0x53, 0x61, 0x66, 0x2e, 0x3b, 0x52, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x3b, 0x52,
-0x61, 0x62, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x4a, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x3b, 0x4a, 0x75, 0x6d, 0x2e, 0x20, 0x49,
-0x49, 0x3b, 0x52, 0x61, 0x6a, 0x2e, 0x3b, 0x53, 0x68, 0x61, 0x2e, 0x3b, 0x52, 0x61, 0x6d, 0x2e, 0x3b, 0x53, 0x68, 0x61,
-0x77, 0x2e, 0x3b, 0x44, 0x75, 0x6c, 0x2d, 0x51, 0x2e, 0x3b, 0x44, 0x75, 0x6c, 0x2d, 0x58, 0x2e, 0x4d, 0x75, 0x78, 0x2e,
-0x3b, 0x53, 0x61, 0x66, 0x2e, 0x3b, 0x52, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x3b, 0x52, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x49,
-0x3b, 0x4a, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x3b, 0x4a, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x52, 0x61, 0x6a, 0x2e,
-0x3b, 0x53, 0x68, 0x61, 0x2e, 0x3b, 0x52, 0x61, 0x6d, 0x2e, 0x3b, 0x53, 0x68, 0x61, 0x77, 0x2e, 0x3b, 0x44, 0x75, 0x6c,
-0x2019, 0x2d, 0x51, 0x69, 0x63, 0x64, 0x61, 0x2e, 0x3b, 0x44, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x48, 0x2e, 0x6d, 0x75, 0x68,
-0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x73, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x72, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x3b,
-0x72, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x49, 0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x3b, 0x6a, 0x75,
-0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x49, 0x3b, 0x72, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x73, 0x68, 0x61, 0x2bb, 0x62, 0x61,
-0x6e, 0x3b, 0x72, 0x61, 0x6d, 0x61, 0x64, 0xe1, 0x6e, 0x3b, 0x73, 0x68, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x64, 0x68,
-0x75, 0x2bb, 0x6c, 0x2d, 0x71, 0x69, 0x2bb, 0x64, 0x61, 0x68, 0x3b, 0x64, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x68, 0x69, 0x6a,
-0x6a, 0x61, 0x68, 0x4d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x53, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x52, 0x61,
-0x62, 0x69, 0x2019, 0x20, 0x61, 0x6c, 0x2d, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x2019, 0x20, 0x61,
-0x6c, 0x2d, 0x61, 0x6b, 0x68, 0x69, 0x72, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x2d, 0x6c, 0x2d, 0x75, 0x6c, 0x61,
-0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x2d, 0x6c, 0x2d, 0x61, 0x6b, 0x68, 0x69, 0x72, 0x61, 0x3b, 0x52, 0x61, 0x6a,
-0x61, 0x62, 0x3b, 0x53, 0x68, 0x61, 0x2019, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x53,
-0x68, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x44, 0x68, 0x75, 0x2d, 0x6c, 0x2d, 0x67, 0x61, 0x2019, 0x64, 0x61, 0x3b, 0x44,
-0x68, 0x75, 0x2d, 0x6c, 0x2d, 0x68, 0x69, 0x6a, 0x6a, 0x61, 0x6d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x73,
-0x61, 0x66, 0x61, 0x72, 0x3b, 0x72, 0x61, 0x62, 0x69, 0x2019, 0x20, 0x61, 0x6c, 0x2d, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b,
-0x72, 0x61, 0x62, 0x69, 0x2019, 0x20, 0x61, 0x6c, 0x2d, 0x61, 0x6b, 0x68, 0x69, 0x72, 0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x64,
-0x61, 0x2d, 0x6c, 0x2d, 0x75, 0x6c, 0x61, 0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x2d, 0x6c, 0x2d, 0x61, 0x6b, 0x68,
-0x69, 0x72, 0x61, 0x3b, 0x72, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x73, 0x68, 0x61, 0x2019, 0x62, 0x61, 0x6e, 0x3b, 0x72, 0x61,
-0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x73, 0x68, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x64, 0x68, 0x75, 0x2d, 0x6c, 0x2d,
-0x67, 0x61, 0x2019, 0x64, 0x61, 0x3b, 0x64, 0x68, 0x75, 0x2d, 0x6c, 0x2d, 0x68, 0x69, 0x6a, 0x6a, 0x61, 0x43c, 0x443, 0x4b3,
-0x430, 0x440, 0x440, 0x430, 0x43c, 0x3b, 0x441, 0x430, 0x444, 0x430, 0x440, 0x3b, 0x420, 0x430, 0x431, 0x435, 0x44a, 0x20, 0x49, 0x3b,
-0x420, 0x430, 0x431, 0x435, 0x44a, 0x20, 0x49, 0x49, 0x3b, 0x4b7, 0x438, 0x43c, 0x43e, 0x434, 0x438, 0x2d, 0x443, 0x43b, 0x2d, 0x443,
-0x43b, 0x43e, 0x3b, 0x4b7, 0x438, 0x43c, 0x43e, 0x434, 0x438, 0x2d, 0x443, 0x43b, 0x2d, 0x441, 0x43e, 0x43d, 0x438, 0x3b, 0x440, 0x430,
-0x4b7, 0x430, 0x431, 0x3b, 0x428, 0x430, 0x431, 0x430, 0x43d, 0x3b, 0x420, 0x430, 0x43c, 0x430, 0x434, 0x430, 0x43d, 0x3b, 0x428, 0x430,
-0x432, 0x432, 0x430, 0x43b, 0x3b, 0x414, 0x445, 0x443, 0x43b, 0x2d, 0x49a, 0x438, 0x434, 0x430, 0x4b3, 0x3b, 0x414, 0x445, 0x443, 0x43b,
-0x2d, 0x4b2, 0x438, 0x4b7, 0x4b7, 0x430, 0x4b3, 0x43c, 0x443, 0x4b3, 0x430, 0x440, 0x440, 0x430, 0x43c, 0x3b, 0x441, 0x430, 0x444, 0x430,
-0x440, 0x3b, 0x420, 0x430, 0x431, 0x435, 0x44a, 0x20, 0x49, 0x3b, 0x420, 0x430, 0x431, 0x435, 0x44a, 0x20, 0x49, 0x49, 0x3b, 0x4b7,
-0x438, 0x43c, 0x43e, 0x434, 0x438, 0x2d, 0x443, 0x43b, 0x2d, 0x443, 0x43b, 0x43e, 0x3b, 0x4b7, 0x438, 0x43c, 0x43e, 0x434, 0x438, 0x2d,
-0x443, 0x43b, 0x2d, 0x441, 0x43e, 0x43d, 0x438, 0x3b, 0x440, 0x430, 0x4b7, 0x430, 0x431, 0x3b, 0x428, 0x430, 0x431, 0x430, 0x43d, 0x3b,
-0x420, 0x430, 0x43c, 0x430, 0x434, 0x430, 0x43d, 0x3b, 0x428, 0x430, 0x432, 0x432, 0x430, 0x43b, 0x3b, 0x414, 0x445, 0x443, 0x442, 0x2d,
-0x49a, 0x438, 0x434, 0x430, 0x4b3, 0x3b, 0x414, 0x445, 0x443, 0x442, 0x2d, 0x4b2, 0x438, 0x4b7, 0x4b7, 0x430, 0x4b3, 0x41c, 0x443, 0x4b3,
-0x2e, 0x3b, 0x421, 0x430, 0x444, 0x2e, 0x3b, 0x420, 0x430, 0x431, 0x2e, 0x20, 0x49, 0x3b, 0x420, 0x430, 0x431, 0x2e, 0x20, 0x49,
-0x49, 0x3b, 0x4b6, 0x443, 0x43c, 0x2e, 0x20, 0x49, 0x3b, 0x4b6, 0x443, 0x43c, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x420, 0x430, 0x4b7,
-0x2e, 0x3b, 0x428, 0x430, 0x2e, 0x3b, 0x420, 0x430, 0x43c, 0x2e, 0x3b, 0x428, 0x430, 0x432, 0x2e, 0x3b, 0x414, 0x445, 0x443, 0x43b,
-0x2d, 0x49a, 0x2e, 0x3b, 0x414, 0x445, 0x443, 0x43b, 0x2d, 0x4b2, 0x2e, 0xbae, 0xbc1, 0xbb9, 0xbb0, 0xbcd, 0xbb0, 0xbae, 0xbcd, 0x3b,
-0xb9a, 0xb83, 0xbaa, 0xbb0, 0xbcd, 0x3b, 0xbb0, 0xbaa, 0xbbf, 0x20, 0x31, 0x3b, 0xbb0, 0xbaa, 0xbbf, 0x20, 0x32, 0x3b, 0xb9c, 0xbc1,
-0xbae, 0xba4, 0xbbe, 0x20, 0x31, 0x3b, 0xb9c, 0xbc1, 0xbae, 0xba4, 0xbbe, 0x20, 0x32, 0x3b, 0xbb0, 0xb9c, 0xbaa, 0xbcd, 0x3b, 0xbb7,
-0xb83, 0xbaa, 0xbbe, 0xba9, 0xbcd, 0x3b, 0xbb0, 0xbae, 0xbb2, 0xbbe, 0xba9, 0xbcd, 0x3b, 0xbb7, 0xbb5, 0xbcd, 0xbb5, 0xbbe, 0xbb2, 0xbcd,
-0x3b, 0xba4, 0xbc1, 0xbb2, 0xbcd, 0x20, 0xb95, 0xb83, 0xba4, 0xbbe, 0x3b, 0xba4, 0xbc1, 0xbb2, 0xbcd, 0x20, 0xbb9, 0xbbf, 0xb9c, 0xbcd,
-0xb9c, 0xbbe, 0xbae, 0xbc1, 0xbb9, 0x2e, 0x3b, 0xb9a, 0xb83, 0xbaa, 0x2e, 0x3b, 0xbb0, 0xbaa, 0xbbf, 0x20, 0x31, 0x3b, 0xbb0, 0xbaa,
-0xbbf, 0x20, 0x32, 0x3b, 0xb9c, 0xbc1, 0xbae, 0x2e, 0x20, 0x31, 0x3b, 0xb9c, 0xbc1, 0xbae, 0x2e, 0x20, 0x32, 0x3b, 0xbb0, 0xb9c,
-0x2e, 0x3b, 0xbb7, 0xb83, 0x2e, 0x3b, 0xbb0, 0xbae, 0x2e, 0x3b, 0xbb7, 0xbb5, 0xbcd, 0x2e, 0x3b, 0xba4, 0xbc1, 0xbb2, 0xbcd, 0x20,
-0xb95, 0xb83, 0x2e, 0x3b, 0xba4, 0xbc1, 0xbb2, 0xbcd, 0x20, 0xbb9, 0xbbf, 0xb9c, 0xbcd, 0x2e, 0xc2e, 0xc41, 0xc39, 0xc30, 0xc4d, 0xc30,
-0xc02, 0x3b, 0xc38, 0xc2b, 0xc30, 0xc4d, 0x3b, 0xc30, 0xc2c, 0xc40, 0x20, 0x49, 0x3b, 0xc30, 0xc2c, 0xc40, 0x20, 0x49, 0x49, 0x3b,
-0xc1c, 0xc41, 0xc2e, 0xc26, 0xc3e, 0x20, 0x49, 0x3b, 0xc1c, 0xc41, 0xc2e, 0xc26, 0xc3e, 0x20, 0x49, 0x49, 0x3b, 0xc30, 0xc1c, 0xc2c,
-0xc4d, 0x3b, 0xc37, 0xc2c, 0xc3e, 0xc28, 0xc4d, 0x3b, 0xc30, 0xc02, 0xc1c, 0xc3e, 0xc28, 0xc4d, 0x3b, 0xc37, 0xc35, 0xc4d, 0xc35, 0xc3e,
-0xc32, 0xc4d, 0x3b, 0xc27, 0xc41, 0xc32, 0xc4d, 0x2d, 0xc15, 0xc3f, 0x20, 0xc26, 0xc3e, 0xc39, 0xc4d, 0x3b, 0xc27, 0xc41, 0xc32, 0xc4d,
-0x2d, 0xc39, 0xc3f, 0xc1c, 0xc4d, 0xc1c, 0xc3e, 0xc39, 0xc4d, 0xc2e, 0xc41, 0xc39, 0x2e, 0x3b, 0xc38, 0xc2b, 0x2e, 0x3b, 0xc30, 0x2e,
-0x20, 0x49, 0x3b, 0xc30, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0xc1c, 0xc41, 0xc2e, 0x2e, 0x20, 0x49, 0x3b, 0xc1c, 0xc41, 0xc2e, 0x2e,
-0x20, 0x49, 0x49, 0x3b, 0xc30, 0xc1c, 0x2e, 0x3b, 0xc37, 0xc2c, 0xc3e, 0x2e, 0x3b, 0xc30, 0xc02, 0xc1c, 0xc3e, 0x2e, 0x3b, 0xc37,
-0xc35, 0xc4d, 0xc35, 0xc3e, 0x2e, 0x3b, 0xc27, 0xc41, 0xc32, 0xc4d, 0x2d, 0xc15, 0xc3f, 0x2e, 0x3b, 0xc27, 0xc41, 0xc32, 0xc4d, 0x2d,
-0xc39, 0xc3f, 0x2e, 0xe21, 0xe38, 0xe2e, 0xe30, 0xe23, 0xe4c, 0xe23, 0xe2d, 0xe21, 0x3b, 0xe0b, 0xe2d, 0xe1f, 0xe32, 0xe23, 0xe4c, 0x3b,
-0xe23, 0xe2d, 0xe1a, 0xe35, 0x20, 0x49, 0x3b, 0xe23, 0xe2d, 0xe1a, 0xe35, 0x20, 0x49, 0x49, 0x3b, 0xe08, 0xe38, 0xe21, 0xe32, 0xe14,
-0xe32, 0x20, 0x49, 0x3b, 0xe08, 0xe38, 0xe21, 0xe32, 0xe14, 0xe32, 0x20, 0x49, 0x49, 0x3b, 0xe23, 0xe2d, 0xe08, 0xe31, 0xe1a, 0x3b,
-0xe0a, 0xe30, 0xe2d, 0xe30, 0xe1a, 0xe32, 0xe19, 0x3b, 0xe23, 0xe2d, 0xe21, 0xe30, 0xe14, 0xe2d, 0xe19, 0x3b, 0xe40, 0xe0a, 0xe32, 0xe27,
-0xe31, 0xe25, 0x3b, 0xe0b, 0xe38, 0xe25, 0xe01, 0xe34, 0xe2d, 0xe3a, 0xe14, 0xe30, 0xe2e, 0xe3a, 0x3b, 0xe0b, 0xe38, 0xe25, 0xe2b, 0xe34,
-0xe08, 0xe0d, 0xe30, 0xe2e, 0xe3a, 0xe21, 0xe38, 0xe2e, 0xe31, 0xe23, 0x2e, 0x3b, 0xe40, 0xe28, 0xe32, 0xe30, 0x2e, 0x3b, 0xe23, 0xe2d,
-0xe1a, 0xe35, 0x20, 0x49, 0x3b, 0xe23, 0xe2d, 0xe1a, 0xe35, 0x20, 0x49, 0x49, 0x3b, 0xe08, 0xe38, 0xe21, 0xe32, 0xe14, 0xe32, 0x20,
-0x49, 0x3b, 0xe08, 0xe38, 0xe21, 0xe32, 0xe14, 0xe32, 0x20, 0x49, 0x49, 0x3b, 0xe40, 0xe23, 0xe32, 0xe30, 0x2e, 0x3b, 0xe0a, 0xe30,
-0xe2d, 0xe4c, 0x2e, 0x3b, 0xe40, 0xe23, 0xe32, 0xe30, 0xe21, 0xe30, 0x2e, 0x3b, 0xe40, 0xe0a, 0xe32, 0xe27, 0x2e, 0x3b, 0xe0b, 0xe38,
-0xe25, 0xe01, 0xe34, 0xe2d, 0xe3a, 0x2e, 0x3b, 0xe0b, 0xe38, 0xe25, 0xe2b, 0xe34, 0xe08, 0x2e, 0x4d, 0x75, 0x68, 0x61, 0x6c, 0x61,
-0x6d, 0x69, 0x3b, 0x53, 0x61, 0x66, 0x61, 0x6c, 0x69, 0x3b, 0x4c, 0x61, 0x70, 0x12b, 0x20, 0x49, 0x3b, 0x4c, 0x61, 0x70,
-0x12b, 0x20, 0x49, 0x49, 0x3b, 0x53, 0x75, 0x6d, 0x61, 0x74, 0x101, 0x20, 0x49, 0x3b, 0x53, 0x75, 0x6d, 0x61, 0x74, 0x101,
-0x20, 0x49, 0x49, 0x3b, 0x4c, 0x61, 0x73, 0x61, 0x70, 0x69, 0x3b, 0x53, 0x61, 0x2bb, 0x61, 0x70, 0x101, 0x6e, 0x69, 0x3b,
-0x4c, 0x61, 0x6d, 0x61, 0x74, 0x101, 0x6e, 0x69, 0x3b, 0x53, 0x61, 0x76, 0x101, 0x6c, 0x69, 0x3b, 0x53, 0x16b, 0x2d, 0x6b,
-0x61, 0x2bb, 0x61, 0x74, 0x61, 0x3b, 0x53, 0x16b, 0x2d, 0x68, 0x69, 0x73, 0x61, 0x4d, 0x75, 0x68, 0x3b, 0x53, 0x61, 0x66,
-0x3b, 0x4c, 0x61, 0x70, 0x20, 0x49, 0x3b, 0x4c, 0x61, 0x70, 0x20, 0x49, 0x49, 0x3b, 0x53, 0x75, 0x6d, 0x20, 0x49, 0x3b,
-0x53, 0x75, 0x6d, 0x20, 0x49, 0x49, 0x3b, 0x4c, 0x61, 0x73, 0x3b, 0x53, 0x61, 0x2bb, 0x61, 0x3b, 0x4c, 0x61, 0x6d, 0x3b,
-0x53, 0x61, 0x76, 0x3b, 0x53, 0x16b, 0x2d, 0x6b, 0x3b, 0x53, 0x16b, 0x2d, 0x68, 0x4d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x65,
-0x6d, 0x3b, 0x53, 0x61, 0x66, 0x65, 0x72, 0x3b, 0x52, 0x65, 0x62, 0x69, 0xfc, 0x6c, 0x65, 0x76, 0x76, 0x65, 0x6c, 0x3b,
-0x52, 0x65, 0x62, 0x69, 0xfc, 0x6c, 0x61, 0x68, 0x69, 0x72, 0x3b, 0x43, 0x65, 0x6d, 0x61, 0x7a, 0x69, 0x79, 0x65, 0x6c,
-0x65, 0x76, 0x76, 0x65, 0x6c, 0x3b, 0x43, 0x65, 0x6d, 0x61, 0x7a, 0x69, 0x79, 0x65, 0x6c, 0x61, 0x68, 0x69, 0x72, 0x3b,
-0x52, 0x65, 0x63, 0x65, 0x70, 0x3b, 0x15e, 0x61, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x7a, 0x61, 0x6e, 0x3b,
-0x15e, 0x65, 0x76, 0x76, 0x61, 0x6c, 0x3b, 0x5a, 0x69, 0x6c, 0x6b, 0x61, 0x64, 0x65, 0x3b, 0x5a, 0x69, 0x6c, 0x68, 0x69,
-0x63, 0x63, 0x65, 0x4d, 0x75, 0x68, 0x61, 0x72, 0x2e, 0x3b, 0x53, 0x61, 0x66, 0x65, 0x72, 0x3b, 0x52, 0x2e, 0x65, 0x76,
-0x76, 0x65, 0x6c, 0x3b, 0x52, 0x2e, 0x61, 0x68, 0x69, 0x72, 0x3b, 0x43, 0x2e, 0x65, 0x76, 0x76, 0x65, 0x6c, 0x3b, 0x43,
-0x2e, 0x61, 0x68, 0x69, 0x72, 0x3b, 0x52, 0x65, 0x63, 0x65, 0x70, 0x3b, 0x15e, 0x61, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61,
-0x6d, 0x2e, 0x3b, 0x15e, 0x65, 0x76, 0x76, 0x61, 0x6c, 0x3b, 0x5a, 0x69, 0x6c, 0x6b, 0x61, 0x64, 0x65, 0x3b, 0x5a, 0x69,
-0x6c, 0x68, 0x69, 0x63, 0x63, 0x65, 0x41, 0x15f, 0x79, 0x72, 0x3b, 0x53, 0x61, 0x70, 0x61, 0x72, 0x3b, 0x44, 0xf6, 0x72,
-0x74, 0x20, 0x74, 0x69, 0x72, 0x6b, 0x65, 0x15f, 0x69, 0x6b, 0x20, 0x31, 0x3b, 0x44, 0xf6, 0x72, 0x74, 0x20, 0x74, 0x69,
-0x72, 0x6b, 0x65, 0x15f, 0x69, 0x6b, 0x20, 0x32, 0x3b, 0x44, 0xf6, 0x72, 0x74, 0x20, 0x74, 0x69, 0x72, 0x6b, 0x65, 0x15f,
-0x69, 0x6b, 0x20, 0x33, 0x3b, 0x44, 0xf6, 0x72, 0x74, 0x20, 0x74, 0x69, 0x72, 0x6b, 0x65, 0x15f, 0x69, 0x6b, 0x20, 0x34,
-0x3b, 0x52, 0x65, 0x6a, 0x65, 0x70, 0x3b, 0x4d, 0x65, 0x72, 0x65, 0x74, 0x3b, 0x4f, 0x72, 0x61, 0x7a, 0x61, 0x3b, 0x42,
-0x61, 0xfd, 0x72, 0x61, 0x6d, 0x3b, 0x42, 0x6f, 0x15f, 0x20, 0x61, 0xfd, 0x3b, 0x47, 0x75, 0x72, 0x62, 0x61, 0x6e, 0x41,
-0x15f, 0x79, 0x3b, 0x53, 0x61, 0x70, 0x3b, 0x54, 0x69, 0x72, 0x20, 0x49, 0x3b, 0x54, 0x69, 0x72, 0x20, 0x49, 0x49, 0x3b,
-0x54, 0x69, 0x72, 0x20, 0x49, 0x49, 0x49, 0x3b, 0x54, 0x69, 0x72, 0x20, 0x49, 0x56, 0x3b, 0x52, 0x65, 0x6a, 0x3b, 0x4d,
-0x65, 0x72, 0x3b, 0x4f, 0x72, 0x61, 0x3b, 0x42, 0x61, 0xfd, 0x3b, 0x42, 0x6f, 0x15f, 0x3b, 0x47, 0x75, 0x72, 0x43c, 0x443,
-0x445, 0x430, 0x440, 0x440, 0x430, 0x43c, 0x3b, 0x441, 0x430, 0x444, 0x430, 0x440, 0x3b, 0x440, 0x430, 0x431, 0x456, 0x20, 0x49, 0x3b,
-0x440, 0x430, 0x431, 0x456, 0x20, 0x49, 0x49, 0x3b, 0x434, 0x436, 0x443, 0x43c, 0x430, 0x434, 0x430, 0x20, 0x49, 0x3b, 0x434, 0x436,
-0x443, 0x43c, 0x430, 0x434, 0x430, 0x20, 0x49, 0x49, 0x3b, 0x440, 0x430, 0x434, 0x436, 0x430, 0x431, 0x3b, 0x448, 0x430, 0x430, 0x431,
-0x430, 0x43d, 0x3b, 0x440, 0x430, 0x43c, 0x430, 0x434, 0x430, 0x43d, 0x3b, 0x434, 0x430, 0x432, 0x432, 0x430, 0x43b, 0x3b, 0x437, 0x443,
-0x2d, 0x43b, 0x44c, 0x2d, 0x43a, 0x430, 0x430, 0x434, 0x430, 0x3b, 0x437, 0x443, 0x2d, 0x43b, 0x44c, 0x2d, 0x445, 0x456, 0x434, 0x436,
-0x430, 0x43c, 0x443, 0x445, 0x3b, 0x441, 0x430, 0x444, 0x3b, 0x440, 0x430, 0x431, 0x456, 0x20, 0x49, 0x3b, 0x440, 0x430, 0x431, 0x456,
-0x20, 0x49, 0x49, 0x3b, 0x434, 0x436, 0x443, 0x43c, 0x20, 0x49, 0x3b, 0x434, 0x436, 0x443, 0x43c, 0x20, 0x49, 0x49, 0x3b, 0x440,
-0x430, 0x434, 0x436, 0x3b, 0x448, 0x430, 0x430, 0x431, 0x3b, 0x440, 0x430, 0x43c, 0x3b, 0x434, 0x430, 0x432, 0x3b, 0x437, 0x443, 0x2d,
-0x43b, 0x44c, 0x2d, 0x43a, 0x3b, 0x437, 0x443, 0x2d, 0x43b, 0x44c, 0x2d, 0x445, 0x43c, 0x443, 0x445, 0x2e, 0x3b, 0x441, 0x430, 0x444,
-0x2e, 0x3b, 0x440, 0x430, 0x431, 0x456, 0x20, 0x49, 0x3b, 0x440, 0x430, 0x431, 0x456, 0x20, 0x49, 0x49, 0x3b, 0x434, 0x436, 0x443,
-0x43c, 0x2e, 0x20, 0x49, 0x3b, 0x434, 0x436, 0x443, 0x43c, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x440, 0x430, 0x434, 0x436, 0x2e, 0x3b,
-0x448, 0x430, 0x430, 0x431, 0x2e, 0x3b, 0x440, 0x430, 0x43c, 0x2e, 0x3b, 0x434, 0x430, 0x432, 0x2e, 0x3b, 0x437, 0x443, 0x2d, 0x43b,
-0x44c, 0x2d, 0x43a, 0x2e, 0x3b, 0x437, 0x443, 0x2d, 0x43b, 0x44c, 0x2d, 0x445, 0x2e, 0x645, 0x62d, 0x631, 0x645, 0x3b, 0x635, 0x641,
-0x631, 0x3b, 0x631, 0x20, 0x628, 0x6cc, 0x639, 0x20, 0x627, 0x644, 0x627, 0x648, 0x644, 0x3b, 0x631, 0x20, 0x628, 0x6cc, 0x639, 0x20,
-0x627, 0x644, 0x62b, 0x627, 0x646, 0x6cc, 0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x6cc, 0x20, 0x627, 0x644, 0x627, 0x648, 0x644, 0x3b, 0x62c,
-0x645, 0x627, 0x62f, 0x6cc, 0x20, 0x627, 0x644, 0x62b, 0x627, 0x646, 0x6cc, 0x3b, 0x631, 0x62c, 0x628, 0x3b, 0x634, 0x639, 0x628, 0x627,
-0x646, 0x3b, 0x631, 0x645, 0x636, 0x627, 0x646, 0x3b, 0x634, 0x648, 0x627, 0x644, 0x3b, 0x630, 0x648, 0x627, 0x644, 0x642, 0x639, 0x62f,
-0x6c3, 0x3b, 0x630, 0x648, 0x627, 0x644, 0x62d, 0x62c, 0x6c3, 0x645, 0x62d, 0x631, 0x645, 0x3b, 0x635, 0x641, 0x631, 0x3b, 0x631, 0x628,
-0x6cc, 0x639, 0x20, 0x627, 0x644, 0x627, 0x648, 0x651, 0x644, 0x3b, 0x631, 0x628, 0x6cc, 0x639, 0x20, 0x627, 0x644, 0x62b, 0x651, 0x627,
-0x646, 0x6cc, 0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x6cc, 0x20, 0x627, 0x644, 0x627, 0x648, 0x651, 0x644, 0x3b, 0x62c, 0x645, 0x627, 0x62f,
-0x6cc, 0x20, 0x627, 0x644, 0x62b, 0x651, 0x627, 0x646, 0x6cc, 0x3b, 0x631, 0x62c, 0x628, 0x3b, 0x634, 0x639, 0x628, 0x627, 0x646, 0x3b,
-0x631, 0x645, 0x636, 0x627, 0x646, 0x3b, 0x634, 0x648, 0x627, 0x644, 0x3b, 0x630, 0x648, 0x627, 0x644, 0x642, 0x639, 0x62f, 0x6c3, 0x3b,
-0x630, 0x648, 0x627, 0x644, 0x62d, 0x62c, 0x6c3, 0x645, 0x62d, 0x631, 0x645, 0x3b, 0x635, 0x641, 0x631, 0x3b, 0x631, 0x628, 0x6cc, 0x639,
-0x20, 0x627, 0x644, 0x627, 0x648, 0x651, 0x644, 0x3b, 0x631, 0x628, 0x6cc, 0x639, 0x20, 0x627, 0x644, 0x62b, 0x627, 0x646, 0x6cc, 0x3b,
-0x62c, 0x645, 0x627, 0x62f, 0x6cc, 0x20, 0x627, 0x644, 0x627, 0x648, 0x651, 0x644, 0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x6cc, 0x20, 0x627,
-0x644, 0x62b, 0x627, 0x646, 0x6cc, 0x3b, 0x631, 0x62c, 0x628, 0x3b, 0x634, 0x639, 0x628, 0x627, 0x646, 0x3b, 0x631, 0x645, 0x636, 0x627,
-0x646, 0x3b, 0x634, 0x648, 0x627, 0x644, 0x3b, 0x630, 0x648, 0x627, 0x644, 0x642, 0x639, 0x62f, 0x6c3, 0x3b, 0x630, 0x648, 0x627, 0x644,
-0x62d, 0x62c, 0x6c3, 0x645, 0x6c7, 0x6be, 0x6d5, 0x631, 0x631, 0x6d5, 0x645, 0x3b, 0x633, 0x6d5, 0x67e, 0x6d5, 0x631, 0x3b, 0x631, 0x6d5,
-0x628, 0x649, 0x626, 0x6c7, 0x644, 0x626, 0x6d5, 0x6cb, 0x6cb, 0x6d5, 0x644, 0x3b, 0x631, 0x6d5, 0x628, 0x649, 0x626, 0x6c7, 0x644, 0x626,
-0x627, 0x62e, 0x649, 0x631, 0x3b, 0x62c, 0x6d5, 0x645, 0x627, 0x62f, 0x649, 0x64a, 0x6d5, 0x644, 0x626, 0x6d5, 0x6cb, 0x6cb, 0x6d5, 0x644,
-0x3b, 0x62c, 0x6d5, 0x645, 0x627, 0x62f, 0x649, 0x64a, 0x6d5, 0x644, 0x626, 0x627, 0x62e, 0x649, 0x631, 0x3b, 0x631, 0x6d5, 0x62c, 0x6d5,
-0x628, 0x3b, 0x634, 0x6d5, 0x626, 0x628, 0x627, 0x646, 0x3b, 0x631, 0x627, 0x645, 0x649, 0x632, 0x627, 0x646, 0x3b, 0x634, 0x6d5, 0x6cb,
-0x6cb, 0x627, 0x644, 0x3b, 0x632, 0x6c7, 0x644, 0x642, 0x6d5, 0x626, 0x62f, 0x6d5, 0x3b, 0x632, 0x6c7, 0x644, 0x6be, 0x6d5, 0x62c, 0x62c,
-0x6d5, 0x4d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x53, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x52, 0x6f, 0x62, 0x69,
-0x2019, 0x20, 0x75, 0x6c, 0x2d, 0x61, 0x76, 0x76, 0x61, 0x6c, 0x3b, 0x52, 0x6f, 0x62, 0x69, 0x2019, 0x20, 0x75, 0x6c, 0x2d,
-0x6f, 0x78, 0x69, 0x72, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x64, 0x20, 0x75, 0x6c, 0x2d, 0x61, 0x76, 0x76, 0x61, 0x6c, 0x3b,
-0x4a, 0x75, 0x6d, 0x61, 0x64, 0x20, 0x75, 0x6c, 0x2d, 0x6f, 0x78, 0x69, 0x72, 0x3b, 0x52, 0x61, 0x6a, 0x61, 0x62, 0x3b,
-0x53, 0x68, 0x61, 0x2019, 0x62, 0x6f, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x7a, 0x6f, 0x6e, 0x3b, 0x53, 0x68, 0x61, 0x76,
-0x76, 0x6f, 0x6c, 0x3b, 0x5a, 0x75, 0x6c, 0x2d, 0x71, 0x61, 0x2019, 0x64, 0x61, 0x3b, 0x5a, 0x75, 0x6c, 0x2d, 0x68, 0x69,
-0x6a, 0x6a, 0x61, 0x4d, 0x75, 0x68, 0x2e, 0x3b, 0x53, 0x61, 0x66, 0x2e, 0x3b, 0x52, 0x6f, 0x62, 0x2e, 0x20, 0x61, 0x76,
-0x76, 0x2e, 0x3b, 0x52, 0x6f, 0x62, 0x2e, 0x20, 0x6f, 0x78, 0x2e, 0x3b, 0x4a, 0x75, 0x6d, 0x2e, 0x20, 0x61, 0x76, 0x76,
-0x2e, 0x3b, 0x4a, 0x75, 0x6d, 0x2e, 0x20, 0x6f, 0x78, 0x2e, 0x3b, 0x52, 0x61, 0x6a, 0x2e, 0x3b, 0x53, 0x68, 0x61, 0x2e,
-0x3b, 0x52, 0x61, 0x6d, 0x2e, 0x3b, 0x53, 0x68, 0x61, 0x76, 0x2e, 0x3b, 0x5a, 0x75, 0x6c, 0x2d, 0x71, 0x2e, 0x3b, 0x5a,
-0x75, 0x6c, 0x2d, 0x68, 0x2e, 0x41c, 0x443, 0x4b3, 0x430, 0x440, 0x440, 0x430, 0x43c, 0x3b, 0x421, 0x430, 0x444, 0x430, 0x440, 0x3b,
-0x420, 0x430, 0x431, 0x438, 0x443, 0x43b, 0x2d, 0x430, 0x432, 0x432, 0x430, 0x43b, 0x3b, 0x420, 0x430, 0x431, 0x438, 0x443, 0x43b, 0x2d,
-0x43e, 0x445, 0x438, 0x440, 0x3b, 0x416, 0x443, 0x43c, 0x43e, 0x434, 0x438, 0x443, 0x43b, 0x2d, 0x443, 0x43b, 0x43e, 0x3b, 0x416, 0x443,
-0x43c, 0x43e, 0x434, 0x438, 0x443, 0x43b, 0x2d, 0x443, 0x445, 0x440, 0x43e, 0x3b, 0x420, 0x430, 0x436, 0x430, 0x431, 0x3b, 0x428, 0x430,
-0x44a, 0x431, 0x43e, 0x43d, 0x3b, 0x420, 0x430, 0x43c, 0x430, 0x437, 0x43e, 0x43d, 0x3b, 0x428, 0x430, 0x432, 0x432, 0x43e, 0x43b, 0x3b,
-0x417, 0x438, 0x43b, 0x2d, 0x49b, 0x430, 0x44a, 0x434, 0x430, 0x3b, 0x417, 0x438, 0x43b, 0x2d, 0x4b3, 0x438, 0x436, 0x436, 0x430
+0x4d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x53, 0x61, 0x66,
+0x61, 0x72, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x3b, 0x52,
+0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x49, 0x3b, 0x4a, 0x75, 0x6d, 0x61,
+0x64, 0x61, 0x20, 0x49, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20,
+0x49, 0x49, 0x3b, 0x52, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x53, 0x68, 0x61,
+0x2bb, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e,
+0x3b, 0x53, 0x68, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x44, 0x68, 0x75,
+0x2bb, 0x6c, 0x2d, 0x51, 0x69, 0x2bb, 0x64, 0x61, 0x68, 0x3b, 0x44, 0x68,
+0x75, 0x2bb, 0x6c, 0x2d, 0x48, 0x69, 0x6a, 0x6a, 0x61, 0x68, 0x4d, 0x75,
+0x68, 0x2e, 0x3b, 0x53, 0x61, 0x66, 0x2e, 0x3b, 0x52, 0x61, 0x62, 0x2e,
+0x20, 0x49, 0x3b, 0x52, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x4a,
+0x75, 0x6d, 0x2e, 0x20, 0x49, 0x3b, 0x4a, 0x75, 0x6d, 0x2e, 0x20, 0x49,
+0x49, 0x3b, 0x52, 0x61, 0x6a, 0x2e, 0x3b, 0x53, 0x68, 0x61, 0x2e, 0x3b,
+0x52, 0x61, 0x6d, 0x2e, 0x3b, 0x53, 0x68, 0x61, 0x77, 0x2e, 0x3b, 0x44,
+0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x51, 0x2e, 0x3b, 0x44, 0x68, 0x75, 0x2bb,
+0x6c, 0x2d, 0x48, 0x2e, 0x31, 0x3b, 0x32, 0x3b, 0x33, 0x3b, 0x34, 0x3b,
+0x35, 0x3b, 0x36, 0x3b, 0x37, 0x3b, 0x38, 0x3b, 0x39, 0x3b, 0x31, 0x30,
+0x3b, 0x31, 0x31, 0x3b, 0x31, 0x32, 0x4d, 0x75, 0x68, 0x61, 0x72, 0x72,
+0x65, 0x6d, 0x3b, 0x53, 0x65, 0x66, 0x65, 0x72, 0x3b, 0x52, 0x65, 0x62,
+0x69, 0x75, 0x6c, 0x2d, 0x65, 0x76, 0x65, 0x6c, 0x3b, 0x52, 0x65, 0x62,
+0x69, 0x75, 0x2d, 0x74, 0x68, 0x65, 0x6e, 0x69, 0x3b, 0x58, 0x68, 0x75,
+0x6d, 0x61, 0x64, 0x65, 0x6c, 0x2d, 0x75, 0x6c, 0x61, 0x3b, 0x58, 0x68,
+0x75, 0x6d, 0x61, 0x64, 0x65, 0x2d, 0x74, 0x68, 0x65, 0x6e, 0x69, 0x3b,
+0x52, 0x65, 0x78, 0x68, 0x65, 0x62, 0x3b, 0x53, 0x68, 0x61, 0x62, 0x61,
+0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x7a, 0x61, 0x6e, 0x3b, 0x53, 0x68,
+0x65, 0x76, 0x61, 0x6c, 0x3b, 0x44, 0x68, 0x75, 0x6c, 0x2d, 0x6b, 0x61,
+0x64, 0x65, 0x3b, 0x44, 0x68, 0x75, 0x6c, 0x2d, 0x68, 0x69, 0x78, 0x68,
+0x65, 0x6d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x65, 0x6d, 0x3b, 0x73, 0x65,
+0x66, 0x65, 0x72, 0x3b, 0x72, 0x65, 0x62, 0x69, 0x75, 0x6c, 0x2d, 0x65,
+0x76, 0x65, 0x6c, 0x3b, 0x72, 0x65, 0x62, 0x69, 0x75, 0x2d, 0x74, 0x68,
+0x65, 0x6e, 0x69, 0x3b, 0x78, 0x68, 0x75, 0x6d, 0x61, 0x64, 0x65, 0x6c,
+0x2d, 0x75, 0x6c, 0x61, 0x3b, 0x78, 0x68, 0x75, 0x6d, 0x61, 0x64, 0x65,
+0x2d, 0x74, 0x68, 0x65, 0x6e, 0x69, 0x3b, 0x72, 0x65, 0x78, 0x68, 0x65,
+0x62, 0x3b, 0x73, 0x68, 0x61, 0x62, 0x61, 0x6e, 0x3b, 0x72, 0x61, 0x6d,
+0x61, 0x7a, 0x61, 0x6e, 0x3b, 0x73, 0x68, 0x65, 0x76, 0x61, 0x6c, 0x3b,
+0x64, 0x68, 0x75, 0x6c, 0x2d, 0x6b, 0x61, 0x64, 0x65, 0x3b, 0x64, 0x68,
+0x75, 0x6c, 0x2d, 0x68, 0x69, 0x78, 0x68, 0x65, 0x4d, 0x75, 0x68, 0x2e,
+0x3b, 0x53, 0x65, 0x66, 0x2e, 0x3b, 0x52, 0x65, 0x62, 0x2e, 0x20, 0x49,
+0x3b, 0x52, 0x65, 0x62, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x58, 0x68, 0x75,
+0x6d, 0x2e, 0x20, 0x49, 0x3b, 0x58, 0x68, 0x75, 0x6d, 0x2e, 0x20, 0x49,
+0x49, 0x3b, 0x52, 0x65, 0x78, 0x68, 0x2e, 0x3b, 0x53, 0x68, 0x61, 0x2e,
+0x3b, 0x52, 0x61, 0x6d, 0x2e, 0x3b, 0x53, 0x68, 0x65, 0x76, 0x2e, 0x3b,
+0x44, 0x68, 0x75, 0x6c, 0x2d, 0x6b, 0x2e, 0x3b, 0x44, 0x68, 0x75, 0x6c,
+0x2d, 0x68, 0x2e, 0x6d, 0x75, 0x68, 0x2e, 0x3b, 0x73, 0x65, 0x66, 0x2e,
+0x3b, 0x72, 0x65, 0x62, 0x2e, 0x20, 0x49, 0x3b, 0x72, 0x65, 0x62, 0x2e,
+0x20, 0x49, 0x49, 0x3b, 0x78, 0x68, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x3b,
+0x78, 0x68, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x72, 0x65, 0x78,
+0x68, 0x2e, 0x3b, 0x73, 0x68, 0x61, 0x2e, 0x3b, 0x72, 0x61, 0x6d, 0x2e,
+0x3b, 0x73, 0x68, 0x65, 0x76, 0x2e, 0x3b, 0x64, 0x68, 0x75, 0x6c, 0x2d,
+0x6b, 0x2e, 0x3b, 0x64, 0x68, 0x75, 0x6c, 0x2d, 0x68, 0x2e, 0x1219, 0x1200,
+0x1228, 0x121d, 0x3b, 0x1233, 0x1348, 0x122d, 0x3b, 0x1228, 0x1262, 0x12d1, 0x120d, 0x20,
+0x12a0, 0x12c8, 0x120d, 0x3b, 0x1228, 0x1262, 0x12d1, 0x120d, 0x20, 0x12a0, 0x12ba, 0x122d,
+0x3b, 0x1300, 0x121b, 0x12f0, 0x120d, 0x20, 0x12a0, 0x12c8, 0x120d, 0x3b, 0x1300, 0x121b,
+0x12f0, 0x120d, 0x20, 0x12a0, 0x12ba, 0x122d, 0x3b, 0x1228, 0x1300, 0x1265, 0x3b, 0x123b,
+0x12a5, 0x1263, 0x1295, 0x3b, 0x1228, 0x1218, 0x12f3, 0x1295, 0x3b, 0x1238, 0x12cb, 0x120d,
+0x3b, 0x12d9, 0x120d, 0x1242, 0x12f3, 0x1205, 0x3b, 0x12d9, 0x120d, 0x1202, 0x1303, 0x1205,
+0x645, 0x62d, 0x631, 0x645, 0x3b, 0x635, 0x641, 0x631, 0x3b, 0x631, 0x628, 0x64a,
+0x639, 0x20, 0x627, 0x644, 0x623, 0x648, 0x644, 0x3b, 0x631, 0x628, 0x64a, 0x639,
+0x20, 0x627, 0x644, 0x622, 0x62e, 0x631, 0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x649,
+0x20, 0x627, 0x644, 0x623, 0x648, 0x644, 0x649, 0x3b, 0x62c, 0x645, 0x627, 0x62f,
+0x649, 0x20, 0x627, 0x644, 0x622, 0x62e, 0x631, 0x629, 0x3b, 0x631, 0x62c, 0x628,
+0x3b, 0x634, 0x639, 0x628, 0x627, 0x646, 0x3b, 0x631, 0x645, 0x636, 0x627, 0x646,
+0x3b, 0x634, 0x648, 0x627, 0x644, 0x3b, 0x630, 0x648, 0x20, 0x627, 0x644, 0x642,
+0x639, 0x62f, 0x629, 0x3b, 0x630, 0x648, 0x20, 0x627, 0x644, 0x62d, 0x62c, 0x629,
+0x661, 0x3b, 0x662, 0x3b, 0x663, 0x3b, 0x664, 0x3b, 0x665, 0x3b, 0x666, 0x3b,
+0x667, 0x3b, 0x668, 0x3b, 0x669, 0x3b, 0x661, 0x660, 0x3b, 0x661, 0x661, 0x3b,
+0x661, 0x662, 0x64, 0x65, 0x20, 0x4d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x61,
+0x6d, 0x3b, 0x64, 0x65, 0x20, 0x53, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x64,
+0x65, 0x20, 0x52, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x3b, 0x64, 0x65,
+0x20, 0x52, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x49, 0x3b, 0x64, 0x65,
+0x20, 0x4a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x3b, 0x64, 0x65,
+0x20, 0x4a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x49, 0x3b, 0x64,
+0x65, 0x20, 0x52, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x64, 0x65, 0x20, 0x53,
+0x68, 0x61, 0x2bb, 0x62, 0x61, 0x6e, 0x3b, 0x64, 0x65, 0x20, 0x52, 0x61,
+0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x64, 0x65, 0x20, 0x53, 0x68, 0x61,
+0x77, 0x77, 0x61, 0x6c, 0x3b, 0x64, 0x65, 0x20, 0x44, 0x68, 0x75, 0x2bb,
+0x6c, 0x2d, 0x51, 0x69, 0x2bb, 0x64, 0x61, 0x68, 0x3b, 0x64, 0x65, 0x20,
+0x44, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x48, 0x69, 0x6a, 0x6a, 0x61, 0x68,
+0x4d, 0x259, 0x68, 0x259, 0x72, 0x72, 0x259, 0x6d, 0x3b, 0x53, 0x259, 0x66,
+0x259, 0x72, 0x3b, 0x52, 0x259, 0x62, 0x69, 0xfc, 0x6c, 0x259, 0x76, 0x76,
+0x259, 0x6c, 0x3b, 0x52, 0x259, 0x62, 0x69, 0xfc, 0x6c, 0x61, 0x78, 0x131,
+0x72, 0x3b, 0x43, 0x259, 0x6d, 0x61, 0x64, 0x69, 0x79, 0x259, 0x6c, 0x259,
+0x76, 0x76, 0x259, 0x6c, 0x3b, 0x43, 0x259, 0x6d, 0x61, 0x64, 0x69, 0x79,
+0x259, 0x6c, 0x61, 0x78, 0x131, 0x72, 0x3b, 0x52, 0x259, 0x63, 0x259, 0x62,
+0x3b, 0x15e, 0x61, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x7a,
+0x61, 0x6e, 0x3b, 0x15e, 0x259, 0x76, 0x76, 0x61, 0x6c, 0x3b, 0x5a, 0x69,
+0x6c, 0x71, 0x259, 0x64, 0x259, 0x3b, 0x5a, 0x69, 0x6c, 0x68, 0x69, 0x63,
+0x63, 0x259, 0x4d, 0x259, 0x68, 0x2e, 0x3b, 0x53, 0x259, 0x66, 0x2e, 0x3b,
+0x52, 0x259, 0x62, 0x2e, 0x20, 0x49, 0x3b, 0x52, 0x259, 0x62, 0x2e, 0x20,
+0x49, 0x49, 0x3b, 0x43, 0x259, 0x6d, 0x2e, 0x20, 0x49, 0x3b, 0x43, 0x259,
+0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x52, 0x259, 0x63, 0x2e, 0x3b, 0x15e,
+0x61, 0x62, 0x2e, 0x3b, 0x52, 0x61, 0x6d, 0x2e, 0x3b, 0x15e, 0x259, 0x76,
+0x2e, 0x3b, 0x5a, 0x69, 0x6c, 0x71, 0x2e, 0x3b, 0x5a, 0x69, 0x6c, 0x68,
+0x2e, 0x9ae, 0x9b9, 0x9b0, 0x9b0, 0x9ae, 0x3b, 0x9b8, 0x9ab, 0x9b0, 0x3b, 0x9b0,
+0x9ac, 0x9bf, 0x989, 0x9b2, 0x20, 0x986, 0x989, 0x9af, 0x9bc, 0x9be, 0x9b2, 0x3b,
+0x9b0, 0x9ac, 0x9bf, 0x989, 0x9b8, 0x20, 0x9b8, 0x9be, 0x9a8, 0x9bf, 0x3b, 0x99c,
+0x9ae, 0x9be, 0x9a6, 0x9bf, 0x989, 0x9b2, 0x20, 0x986, 0x989, 0x9af, 0x9bc, 0x9be,
+0x9b2, 0x3b, 0x99c, 0x9ae, 0x9be, 0x9a6, 0x9bf, 0x989, 0x9b8, 0x20, 0x9b8, 0x9be,
+0x9a8, 0x9bf, 0x3b, 0x9b0, 0x99c, 0x9ac, 0x3b, 0x9b6, 0x9be, 0x2018, 0x9ac, 0x9be,
+0x9a8, 0x3b, 0x9b0, 0x9ae, 0x99c, 0x9be, 0x9a8, 0x3b, 0x9b6, 0x9be, 0x993, 0x9af,
+0x9bc, 0x9be, 0x9b2, 0x3b, 0x99c, 0x9cd, 0x9ac, 0x9bf, 0x9b2, 0x995, 0x9a6, 0x3b,
+0x99c, 0x9cd, 0x9ac, 0x9bf, 0x9b2, 0x9b9, 0x99c, 0x9cd, 0x99c, 0x9e7, 0x3b, 0x9e8,
+0x3b, 0x9e9, 0x3b, 0x9ea, 0x3b, 0x9eb, 0x3b, 0x9ec, 0x3b, 0x9ed, 0x3b, 0x9ee,
+0x3b, 0x9ef, 0x3b, 0x9e7, 0x9e6, 0x3b, 0x9e7, 0x9e7, 0x3b, 0x9e7, 0x9e8, 0x6d,
+0x75, 0x68, 0x61, 0x72, 0x65, 0x6d, 0x3b, 0x73, 0x61, 0x66, 0x65, 0x72,
+0x3b, 0x72, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x69, 0x3b, 0x72, 0x61, 0x62,
+0x69, 0x2bb, 0x20, 0x69, 0x69, 0x3b, 0x64, 0x17e, 0x75, 0x6d, 0x61, 0x64,
+0x65, 0x20, 0x69, 0x3b, 0x64, 0x17e, 0x75, 0x6d, 0x61, 0x64, 0x65, 0x20,
+0x69, 0x69, 0x3b, 0x72, 0x65, 0x64, 0x17e, 0x65, 0x62, 0x3b, 0x53, 0x68,
+0x61, 0x2bb, 0x62, 0x61, 0x6e, 0x3b, 0x72, 0x61, 0x6d, 0x61, 0x7a, 0x61,
+0x6e, 0x3b, 0x161, 0x65, 0x76, 0x61, 0x6c, 0x3b, 0x7a, 0x75, 0x6c, 0x2d,
+0x6b, 0x61, 0x64, 0x65, 0x3b, 0x7a, 0x75, 0x6c, 0x2d, 0x68, 0x69, 0x64,
+0x17e, 0x65, 0x6d, 0x75, 0x68, 0x2e, 0x3b, 0x73, 0x61, 0x66, 0x2e, 0x3b,
+0x52, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x3b, 0x72, 0x61, 0x62, 0x2e, 0x20,
+0x69, 0x69, 0x3b, 0x64, 0x17e, 0x75, 0x6d, 0x2e, 0x20, 0x69, 0x3b, 0x64,
+0x17e, 0x75, 0x6d, 0x2e, 0x20, 0x69, 0x69, 0x3b, 0x72, 0x65, 0x64, 0x17e,
+0x2e, 0x3b, 0x161, 0x61, 0x2e, 0x3b, 0x72, 0x61, 0x6d, 0x2e, 0x3b, 0x161,
+0x65, 0x2e, 0x3b, 0x7a, 0x75, 0x6c, 0x2d, 0x6b, 0x2e, 0x3b, 0x7a, 0x75,
+0x6c, 0x2d, 0x68, 0x2e, 0x41c, 0x443, 0x445, 0x430, 0x440, 0x435, 0x43c, 0x3b,
+0x421, 0x430, 0x444, 0x435, 0x440, 0x3b, 0x420, 0x435, 0x431, 0x438, 0x20, 0x31,
+0x3b, 0x420, 0x435, 0x431, 0x438, 0x20, 0x32, 0x3b, 0x40f, 0x443, 0x43c, 0x430,
+0x434, 0x435, 0x20, 0x31, 0x3b, 0x40f, 0x443, 0x43c, 0x430, 0x434, 0x435, 0x20,
+0x32, 0x3b, 0x420, 0x435, 0x45f, 0x435, 0x431, 0x3b, 0x428, 0x430, 0x2bb, 0x431,
+0x430, 0x43d, 0x3b, 0x420, 0x430, 0x43c, 0x430, 0x437, 0x430, 0x43d, 0x3b, 0x428,
+0x435, 0x432, 0x430, 0x43b, 0x3b, 0x417, 0x443, 0x43b, 0x2d, 0x43a, 0x430, 0x434,
+0x435, 0x3b, 0x417, 0x443, 0x43b, 0x2d, 0x445, 0x438, 0x45f, 0x435, 0x41c, 0x443,
+0x440, 0x430, 0x445, 0x430, 0x43c, 0x3b, 0x421, 0x430, 0x444, 0x430, 0x440, 0x3b,
+0x420, 0x430, 0x431, 0x438, 0x2bb, 0x20, 0x49, 0x3b, 0x420, 0x430, 0x431, 0x438,
+0x2bb, 0x20, 0x49, 0x49, 0x3b, 0x408, 0x443, 0x43c, 0x430, 0x434, 0x430, 0x20,
+0x49, 0x3b, 0x408, 0x443, 0x43c, 0x430, 0x434, 0x430, 0x20, 0x49, 0x49, 0x3b,
+0x420, 0x430, 0x452, 0x430, 0x431, 0x3b, 0x428, 0x430, 0x2bb, 0x431, 0x430, 0x43d,
+0x3b, 0x420, 0x430, 0x43c, 0x430, 0x434, 0x430, 0x43d, 0x3b, 0x428, 0x430, 0x432,
+0x430, 0x43b, 0x3b, 0x414, 0x443, 0x2bb, 0x43b, 0x2d, 0x41a, 0x438, 0x2bb, 0x434,
+0x430, 0x3b, 0x414, 0x443, 0x2bb, 0x43b, 0x2d, 0x445, 0x438, 0x452, 0x430, 0x41c,
+0x443, 0x445, 0x2e, 0x3b, 0x421, 0x430, 0x444, 0x2e, 0x3b, 0x420, 0x435, 0x431,
+0x2e, 0x20, 0x31, 0x3b, 0x420, 0x435, 0x431, 0x2e, 0x20, 0x32, 0x3b, 0x40f,
+0x443, 0x43c, 0x2e, 0x20, 0x31, 0x3b, 0x40f, 0x443, 0x43c, 0x2e, 0x20, 0x32,
+0x3b, 0x420, 0x435, 0x45f, 0x2e, 0x3b, 0x428, 0x430, 0x2e, 0x3b, 0x420, 0x430,
+0x43c, 0x2e, 0x3b, 0x428, 0x435, 0x2e, 0x3b, 0x417, 0x443, 0x43b, 0x2d, 0x43a,
+0x2e, 0x3b, 0x417, 0x443, 0x43b, 0x2d, 0x445, 0x2e, 0x43c, 0x443, 0x445, 0x430,
+0x440, 0x430, 0x43c, 0x3b, 0x441, 0x430, 0x444, 0x430, 0x440, 0x3b, 0x440, 0x430,
+0x431, 0x438, 0x2d, 0x31, 0x3b, 0x440, 0x430, 0x431, 0x438, 0x2d, 0x32, 0x3b,
+0x434, 0x436, 0x443, 0x43c, 0x430, 0x434, 0x430, 0x2d, 0x31, 0x3b, 0x434, 0x436,
+0x443, 0x43c, 0x430, 0x434, 0x430, 0x2d, 0x32, 0x3b, 0x440, 0x430, 0x434, 0x436,
+0x430, 0x431, 0x3b, 0x448, 0x430, 0x431, 0x430, 0x43d, 0x3b, 0x440, 0x430, 0x43c,
+0x430, 0x437, 0x430, 0x43d, 0x3b, 0x428, 0x430, 0x432, 0x430, 0x43b, 0x3b, 0x414,
+0x445, 0x443, 0x43b, 0x2d, 0x41a, 0x430, 0x430, 0x434, 0x430, 0x3b, 0x414, 0x445,
+0x443, 0x43b, 0x2d, 0x445, 0x438, 0x434, 0x436, 0x430, 0x7a46, 0x54c8, 0x862d, 0x59c6,
+0x6708, 0x3b, 0x8272, 0x6cd5, 0x723e, 0x6708, 0x3b, 0x8cf4, 0x6bd4, 0x6708, 0x20, 0x49,
+0x3b, 0x8cf4, 0x6bd4, 0x6708, 0x20, 0x49, 0x49, 0x3b, 0x4e3b, 0x99ac, 0x9054, 0x6708,
+0x20, 0x49, 0x3b, 0x4e3b, 0x99ac, 0x9054, 0x6708, 0x20, 0x49, 0x49, 0x3b, 0x8cf4,
+0x54f2, 0x535c, 0x6708, 0x3b, 0x820d, 0x723e, 0x90a6, 0x6708, 0x3b, 0x8cf4, 0x8cb7, 0x4e39,
+0x6708, 0x3b, 0x9583, 0x74e6, 0x9b6f, 0x6708, 0x3b, 0x90fd, 0x723e, 0x5580, 0x723e, 0x5fb7,
+0x6708, 0x3b, 0x90fd, 0x723e, 0x9ed1, 0x54f2, 0x6708, 0x7a46, 0x54c8, 0x5170, 0x59c6, 0x6708,
+0x3b, 0x8272, 0x6cd5, 0x5c14, 0x6708, 0x3b, 0x8d56, 0x6bd4, 0x6708, 0x20, 0x49, 0x3b,
+0x8d56, 0x6bd4, 0x6708, 0x20, 0x49, 0x49, 0x3b, 0x4e3b, 0x9a6c, 0x8fbe, 0x6708, 0x20,
+0x49, 0x3b, 0x4e3b, 0x9a6c, 0x8fbe, 0x6708, 0x20, 0x49, 0x49, 0x3b, 0x8d56, 0x54f2,
+0x535c, 0x6708, 0x3b, 0x820d, 0x5c14, 0x90a6, 0x6708, 0x3b, 0x8d56, 0x4e70, 0x4e39, 0x6708,
+0x3b, 0x95ea, 0x74e6, 0x9c81, 0x6708, 0x3b, 0x90fd, 0x5c14, 0x5580, 0x5c14, 0x5fb7, 0x6708,
+0x3b, 0x90fd, 0x5c14, 0x9ed1, 0x54f2, 0x6708, 0xd804, 0xdd1f, 0xd804, 0xdd27, 0xd804, 0xdd26,
+0xd804, 0xdd27, 0xd804, 0xdd22, 0xd804, 0xdd27, 0xd804, 0xdd1f, 0xd804, 0xdd34, 0x3b, 0xd804,
+0xdd25, 0xd804, 0xdd27, 0xd804, 0xdd1c, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd22,
+0xd804, 0xdd27, 0xd804, 0xdd1d, 0xd804, 0xdd28, 0xd804, 0xdd05, 0xd804, 0xdd23, 0xd804, 0xdd34,
+0x20, 0xd804, 0xdd03, 0xd804, 0xdd03, 0xd804, 0xdd2a, 0xd804, 0xdd20, 0xd804, 0xdd23, 0xd804,
+0xdd34, 0x3b, 0xd804, 0xdd22, 0xd804, 0xdd27, 0xd804, 0xdd1d, 0xd804, 0xdd28, 0xd804, 0xdd05,
+0xd804, 0xdd25, 0xd804, 0xdd34, 0x20, 0xd804, 0xdd25, 0xd804, 0xdd1a, 0xd804, 0xdd28, 0x3b,
+0xd804, 0xdd0e, 0xd804, 0xdd27, 0xd804, 0xdd1f, 0xd804, 0xdd18, 0xd804, 0xdd28, 0xd804, 0xdd05,
+0xd804, 0xdd23, 0xd804, 0xdd34, 0x20, 0xd804, 0xdd03, 0xd804, 0xdd03, 0xd804, 0xdd2a, 0xd804,
+0xdd20, 0xd804, 0xdd23, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd0e, 0xd804, 0xdd27, 0xd804, 0xdd1f,
+0xd804, 0xdd18, 0xd804, 0xdd28, 0xd804, 0xdd05, 0xd804, 0xdd0c, 0xd804, 0xdd34, 0x20, 0xd804,
+0xdd25, 0xd804, 0xdd1a, 0xd804, 0xdd28, 0x3b, 0xd804, 0xdd22, 0xd804, 0xdd27, 0xd804, 0xdd0e,
+0xd804, 0xdd27, 0xd804, 0xdd1d, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd25, 0xd804, 0xdd33, 0xd804,
+0xdd03, 0xd804, 0xdd1d, 0xd804, 0xdd27, 0xd804, 0xdd1a, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd22,
+0xd804, 0xdd27, 0xd804, 0xdd1f, 0xd804, 0xdd34, 0xd804, 0xdd0e, 0xd804, 0xdd1a, 0xd804, 0xdd34,
+0x3b, 0xd804, 0xdd25, 0xd804, 0xdd24, 0xd804, 0xdd23, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd0e,
+0xd804, 0xdd28, 0xd804, 0xdd23, 0xd804, 0xdd34, 0xd804, 0xdd07, 0xd804, 0xdd27, 0xd804, 0xdd18,
+0xd804, 0xdd34, 0x3b, 0xd804, 0xdd0e, 0xd804, 0xdd28, 0xd804, 0xdd23, 0xd804, 0xdd34, 0xd804,
+0xdd26, 0xd804, 0xdd27, 0xd804, 0xdd0e, 0xd804, 0xdd34, 0xd804, 0xdd0e, 0xd804, 0xdd27, 0xd804,
+0xdd37, 0x3b, 0xd804, 0xdd38, 0x3b, 0xd804, 0xdd39, 0x3b, 0xd804, 0xdd3a, 0x3b, 0xd804,
+0xdd3b, 0x3b, 0xd804, 0xdd3c, 0x3b, 0xd804, 0xdd3d, 0x3b, 0xd804, 0xdd3e, 0x3b, 0xd804,
+0xdd3f, 0x3b, 0xd804, 0xdd37, 0xd804, 0xdd36, 0x3b, 0xd804, 0xdd37, 0xd804, 0xdd37, 0x3b,
+0xd804, 0xdd37, 0xd804, 0xdd38, 0x4e00, 0x6708, 0x3b, 0x4e8c, 0x6708, 0x3b, 0x4e09, 0x6708,
+0x3b, 0x56db, 0x6708, 0x3b, 0x4e94, 0x6708, 0x3b, 0x516d, 0x6708, 0x3b, 0x4e03, 0x6708,
+0x3b, 0x516b, 0x6708, 0x3b, 0x4e5d, 0x6708, 0x3b, 0x5341, 0x6708, 0x3b, 0x5341, 0x4e00,
+0x6708, 0x3b, 0x5341, 0x4e8c, 0x6708, 0x31, 0x6708, 0x3b, 0x32, 0x6708, 0x3b, 0x33,
+0x6708, 0x3b, 0x34, 0x6708, 0x3b, 0x35, 0x6708, 0x3b, 0x36, 0x6708, 0x3b, 0x37,
+0x6708, 0x3b, 0x38, 0x6708, 0x3b, 0x39, 0x6708, 0x3b, 0x31, 0x30, 0x6708, 0x3b,
+0x31, 0x31, 0x6708, 0x3b, 0x31, 0x32, 0x6708, 0x31, 0x2e, 0x3b, 0x32, 0x2e,
+0x3b, 0x33, 0x2e, 0x3b, 0x34, 0x2e, 0x3b, 0x35, 0x2e, 0x3b, 0x36, 0x2e,
+0x3b, 0x37, 0x2e, 0x3b, 0x38, 0x2e, 0x3b, 0x39, 0x2e, 0x3b, 0x31, 0x30,
+0x2e, 0x3b, 0x31, 0x31, 0x2e, 0x3b, 0x31, 0x32, 0x2e, 0x6d, 0x75, 0x68,
+0x61, 0x72, 0x72, 0x65, 0x6d, 0x3b, 0x73, 0x61, 0x66, 0x61, 0x72, 0x3b,
+0x72, 0x65, 0x62, 0xed, 0x2019, 0x75, 0x20, 0x6c, 0x2d, 0x61, 0x77, 0x77,
+0x61, 0x6c, 0x3b, 0x72, 0x65, 0x62, 0xed, 0x2019, 0x75, 0x20, 0x73, 0x2d,
+0x73, 0xe1, 0x6e, 0xed, 0x3b, 0x64, 0x17e, 0x75, 0x6d, 0xe1, 0x64, 0xe1,
+0x20, 0x61, 0x6c, 0x2d, 0xfa, 0x6c, 0xe1, 0x3b, 0x64, 0x17e, 0x75, 0x6d,
+0xe1, 0x64, 0xe1, 0x20, 0x61, 0x6c, 0x2d, 0xe1, 0x63, 0x68, 0x69, 0x72,
+0x61, 0x3b, 0x72, 0x65, 0x64, 0x17e, 0x65, 0x62, 0x3b, 0x161, 0x61, 0x2019,
+0x62, 0xe1, 0x6e, 0x3b, 0x72, 0x61, 0x6d, 0x61, 0x64, 0xe1, 0x6e, 0x3b,
+0x161, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x7a, 0xfa, 0x20, 0x6c, 0x2d,
+0x6b, 0x61, 0x2019, 0x64, 0x61, 0x3b, 0x7a, 0xfa, 0x20, 0x6c, 0x2d, 0x68,
+0x69, 0x64, 0x17e, 0x64, 0x17e, 0x61, 0x6d, 0x75, 0x68, 0x2e, 0x3b, 0x73,
+0x61, 0x66, 0x2e, 0x3b, 0x72, 0x65, 0x62, 0x2e, 0x20, 0x49, 0x3b, 0x72,
+0x65, 0x62, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x64, 0x17e, 0x75, 0x6d, 0x2e,
+0x20, 0x49, 0x3b, 0x64, 0x17e, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b,
+0x72, 0x65, 0x64, 0x2e, 0x3b, 0x161, 0x61, 0x2e, 0x3b, 0x72, 0x61, 0x6d,
+0x2e, 0x3b, 0x161, 0x61, 0x77, 0x2e, 0x3b, 0x7a, 0xfa, 0x20, 0x6c, 0x2d,
+0x6b, 0x2e, 0x3b, 0x7a, 0xfa, 0x20, 0x6c, 0x2d, 0x68, 0x2e, 0x6d, 0x75,
+0x68, 0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x73, 0x61, 0x66, 0x61, 0x72,
+0x3b, 0x72, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x3b, 0x72, 0x61, 0x62,
+0x69, 0x2bb, 0x20, 0x49, 0x49, 0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x64, 0x61,
+0x20, 0x49, 0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x49,
+0x3b, 0x72, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x73, 0x68, 0x61, 0x2bb, 0x62,
+0x61, 0x6e, 0x3b, 0x72, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x73,
+0x68, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x64, 0x68, 0x75, 0x2bb, 0x6c,
+0x2d, 0x51, 0x69, 0x2bb, 0x64, 0x61, 0x68, 0x3b, 0x64, 0x68, 0x75, 0x2bb,
+0x6c, 0x2d, 0x48, 0x69, 0x6a, 0x6a, 0x61, 0x68, 0x4d, 0x6f, 0x65, 0x68,
+0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x53, 0x61, 0x66, 0x61, 0x72, 0x3b,
+0x52, 0x61, 0x62, 0x69, 0x2bb, 0x61, 0x20, 0x61, 0x6c, 0x20, 0x61, 0x77,
+0x61, 0x6c, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x2bb, 0x61, 0x20, 0x61, 0x6c,
+0x20, 0x74, 0x68, 0x61, 0x6e, 0x69, 0x3b, 0x4a, 0x6f, 0x65, 0x6d, 0x61,
+0x64, 0x2bb, 0x61, 0x6c, 0x20, 0x61, 0x77, 0x61, 0x6c, 0x3b, 0x4a, 0x6f,
+0x65, 0x6d, 0x61, 0x64, 0x2bb, 0x61, 0x6c, 0x20, 0x74, 0x68, 0x61, 0x6e,
+0x69, 0x3b, 0x52, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x53, 0x6a, 0x61, 0x2bb,
+0x61, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e,
+0x3b, 0x53, 0x6a, 0x61, 0x77, 0x61, 0x6c, 0x3b, 0x44, 0x6f, 0x65, 0x20,
+0x61, 0x6c, 0x20, 0x6b, 0x61, 0x2bb, 0x61, 0x62, 0x61, 0x3b, 0x44, 0x6f,
+0x65, 0x20, 0x61, 0x6c, 0x20, 0x68, 0x69, 0x7a, 0x6a, 0x61, 0x4d, 0x6f,
+0x65, 0x68, 0x2e, 0x3b, 0x53, 0x61, 0x66, 0x2e, 0x3b, 0x52, 0x61, 0x62,
+0x2e, 0x20, 0x49, 0x3b, 0x52, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x49, 0x3b,
+0x4a, 0x6f, 0x65, 0x6d, 0x2e, 0x20, 0x49, 0x3b, 0x4a, 0x6f, 0x65, 0x6d,
+0x2e, 0x20, 0x49, 0x49, 0x3b, 0x52, 0x61, 0x6a, 0x2e, 0x3b, 0x53, 0x6a,
+0x61, 0x2e, 0x3b, 0x52, 0x61, 0x6d, 0x2e, 0x3b, 0x53, 0x6a, 0x61, 0x77,
+0x2e, 0x3b, 0x44, 0x6f, 0x65, 0x20, 0x61, 0x6c, 0x20, 0x6b, 0x2e, 0x3b,
+0x44, 0x6f, 0x65, 0x20, 0x61, 0x6c, 0x20, 0x68, 0x2e, 0x64, 0x7a, 0x6f,
+0x76, 0x65, 0x3b, 0x64, 0x7a, 0x6f, 0x64, 0x7a, 0x65, 0x3b, 0x74, 0x65,
+0x64, 0x6f, 0x78, 0x65, 0x3b, 0x61, 0x66, 0x254, 0x66, 0x69, 0x1ebd, 0x3b,
+0x64, 0x61, 0x6d, 0x25b, 0x3b, 0x6d, 0x61, 0x73, 0x61, 0x3b, 0x73, 0x69,
+0x61, 0x6d, 0x6c, 0x254, 0x6d, 0x3b, 0x64, 0x65, 0x61, 0x73, 0x69, 0x61,
+0x6d, 0x69, 0x6d, 0x65, 0x3b, 0x61, 0x6e, 0x79, 0x254, 0x6e, 0x79, 0x254,
+0x3b, 0x6b, 0x65, 0x6c, 0x65, 0x3b, 0x61, 0x64, 0x65, 0x25b, 0x6d, 0x65,
+0x6b, 0x70, 0x254, 0x78, 0x65, 0x3b, 0x64, 0x7a, 0x6f, 0x6d, 0x65, 0x64,
+0x7a, 0x76, 0x3b, 0x64, 0x7a, 0x64, 0x3b, 0x74, 0x65, 0x64, 0x3b, 0x61,
+0x66, 0x254, 0x3b, 0x64, 0x61, 0x6d, 0x3b, 0x6d, 0x61, 0x73, 0x3b, 0x73,
+0x69, 0x61, 0x3b, 0x64, 0x65, 0x61, 0x3b, 0x61, 0x6e, 0x79, 0x3b, 0x6b,
+0x65, 0x6c, 0x3b, 0x61, 0x64, 0x65, 0x3b, 0x64, 0x7a, 0x6d, 0x6d, 0x75,
+0x68, 0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x73, 0x61, 0x66, 0x61, 0x72,
+0x3b, 0x72, 0x61, 0x62, 0x69, 0x2019, 0x20, 0x61, 0x6c, 0x2d, 0x61, 0x77,
+0x77, 0x61, 0x6c, 0x3b, 0x72, 0x61, 0x62, 0x69, 0x2019, 0x20, 0x61, 0x6c,
+0x2d, 0x61, 0x6b, 0x68, 0x69, 0x72, 0x3b, 0x64, 0x17e, 0x75, 0x6d, 0x61,
+0x64, 0x61, 0x2d, 0x6c, 0x2d, 0x75, 0x6c, 0x61, 0x3b, 0x64, 0x17e, 0x75,
+0x6d, 0x61, 0x64, 0x61, 0x2d, 0x6c, 0x2d, 0x61, 0x6b, 0x68, 0x69, 0x72,
+0x61, 0x3b, 0x72, 0x61, 0x64, 0x17e, 0x61, 0x62, 0x3b, 0x161, 0x61, 0x2019,
+0x62, 0x61, 0x6e, 0x3b, 0x72, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b,
+0x161, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x64, 0x68, 0x75, 0x2d, 0x6c,
+0x2d, 0x71, 0x61, 0x2019, 0x64, 0x61, 0x3b, 0x64, 0x68, 0x75, 0x2d, 0x6c,
+0x2d, 0x68, 0x69, 0x64, 0x64, 0x17e, 0x61, 0x6d, 0x6f, 0x75, 0x68, 0x61,
+0x72, 0x72, 0x61, 0x6d, 0x3b, 0x73, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x72,
+0x61, 0x62, 0x69, 0x61, 0x20, 0x61, 0x6c, 0x20, 0x61, 0x77, 0x61, 0x6c,
+0x3b, 0x72, 0x61, 0x62, 0x69, 0x61, 0x20, 0x61, 0x74, 0x68, 0x2d, 0x74,
+0x68, 0x61, 0x6e, 0x69, 0x3b, 0x6a, 0x6f, 0x75, 0x6d, 0x61, 0x64, 0x61,
+0x20, 0x61, 0x6c, 0x20, 0x6f, 0x75, 0x6c, 0x61, 0x3b, 0x6a, 0x6f, 0x75,
+0x6d, 0x61, 0x64, 0x61, 0x20, 0x61, 0x74, 0x68, 0x2d, 0x74, 0x68, 0x61,
+0x6e, 0x69, 0x61, 0x3b, 0x72, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x63, 0x68,
+0x61, 0x61, 0x62, 0x61, 0x6e, 0x65, 0x3b, 0x72, 0x61, 0x6d, 0x61, 0x64,
+0x61, 0x6e, 0x3b, 0x63, 0x68, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x64,
+0x68, 0x6f, 0x75, 0x20, 0x61, 0x6c, 0x20, 0x71, 0x69, 0x60, 0x64, 0x61,
+0x3b, 0x64, 0x68, 0x6f, 0x75, 0x20, 0x61, 0x6c, 0x2d, 0x68, 0x69, 0x6a,
+0x6a, 0x61, 0x6d, 0x6f, 0x75, 0x68, 0x2e, 0x3b, 0x73, 0x61, 0x66, 0x2e,
+0x3b, 0x72, 0x61, 0x62, 0x2e, 0x20, 0x61, 0x77, 0x2e, 0x3b, 0x72, 0x61,
+0x62, 0x2e, 0x20, 0x74, 0x68, 0x2e, 0x3b, 0x6a, 0x6f, 0x75, 0x6d, 0x2e,
+0x20, 0x6f, 0x75, 0x2e, 0x3b, 0x6a, 0x6f, 0x75, 0x6d, 0x2e, 0x20, 0x74,
+0x68, 0x2e, 0x3b, 0x72, 0x61, 0x6a, 0x2e, 0x3b, 0x63, 0x68, 0x61, 0x61,
+0x2e, 0x3b, 0x72, 0x61, 0x6d, 0x2e, 0x3b, 0x63, 0x68, 0x61, 0x77, 0x2e,
+0x3b, 0x64, 0x68, 0x6f, 0x75, 0x2e, 0x20, 0x71, 0x69, 0x2e, 0x3b, 0x64,
+0x68, 0x6f, 0x75, 0x2e, 0x20, 0x68, 0x69, 0x2e, 0x6d, 0x6f, 0x75, 0x68,
+0x2e, 0x3b, 0x73, 0x61, 0x66, 0x2e, 0x3b, 0x72, 0x61, 0x62, 0x2e, 0x20,
+0x61, 0x77, 0x2e, 0x3b, 0x72, 0x61, 0x62, 0x2e, 0x20, 0x74, 0x68, 0x2e,
+0x3b, 0x6a, 0x6f, 0x75, 0x6d, 0x2e, 0x20, 0x6f, 0x75, 0x6c, 0x2e, 0x3b,
+0x6a, 0x6f, 0x75, 0x6d, 0x2e, 0x20, 0x74, 0x68, 0x61, 0x2e, 0x3b, 0x72,
+0x61, 0x6a, 0x2e, 0x3b, 0x63, 0x68, 0x61, 0x61, 0x2e, 0x3b, 0x72, 0x61,
+0x6d, 0x2e, 0x3b, 0x63, 0x68, 0x61, 0x77, 0x2e, 0x3b, 0x64, 0x68, 0x6f,
+0x75, 0x2e, 0x20, 0x71, 0x2e, 0x3b, 0x64, 0x68, 0x6f, 0x75, 0x2e, 0x20,
+0x68, 0x2e, 0xd83a, 0xdd14, 0xd83a, 0xdd2e, 0xd83a, 0xdd25, 0xd83a, 0xdd26, 0xd83a, 0xdd2b,
+0xd83a, 0xdd32, 0xd83a, 0xdd3c, 0xd83a, 0xdd2b, 0x3b, 0xd83a, 0xdd05, 0xd83a, 0xdd22, 0xd83a,
+0xdd26, 0xd83a, 0xdd46, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0xd83a, 0xdd23, 0xd83a, 0xdd35, 0x2d,
+0xd83a, 0xdd06, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0x3b, 0xd83a,
+0xdd06, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0x3b, 0xd83a, 0xdd03,
+0xd83a, 0xdd2d, 0xd83a, 0xdd25, 0xd83a, 0xdd28, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd22,
+0xd83a, 0xdd32, 0x3b, 0xd83a, 0xdd04, 0xd83a, 0xdd22, 0xd83a, 0xdd28, 0xd83a, 0xdd46, 0xd83a,
+0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0x3b, 0xd83a, 0xdd05, 0xd83a, 0xdd22,
+0xd83a, 0xdd26, 0xd83a, 0xdd46, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0xd83a, 0xdd23, 0xd83a, 0xdd35,
+0x2d, 0xd83a, 0xdd08, 0xd83a, 0xdd22, 0xd83a, 0xdd44, 0xd83a, 0xdd36, 0xd83a, 0xdd2d, 0xd83a,
+0xdd26, 0xd83a, 0xdd2d, 0x3b, 0xd83a, 0xdd08, 0xd83a, 0xdd22, 0xd83a, 0xdd44, 0xd83a, 0xdd36,
+0xd83a, 0xdd2d, 0xd83a, 0xdd26, 0xd83a, 0xdd2d, 0x3b, 0xd83a, 0xdd05, 0xd83a, 0xdd22, 0xd83a,
+0xdd26, 0xd83a, 0xdd46, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0xd83a, 0xdd23, 0xd83a, 0xdd35, 0x2d,
+0xd83a, 0xdd05, 0xd83a, 0xdd35, 0xd83a, 0xdd45, 0xd83a, 0xdd25, 0xd83a, 0xdd22, 0xd83a, 0xdd34,
+0xd83a, 0xdd2b, 0xd83a, 0xdd45, 0x3b, 0xd83a, 0xdd05, 0xd83a, 0xdd35, 0xd83a, 0xdd45, 0xd83a,
+0xdd25, 0xd83a, 0xdd22, 0xd83a, 0xdd34, 0xd83a, 0xdd2b, 0xd83a, 0xdd45, 0x3b, 0xd83a, 0xdd14,
+0xd83a, 0xdd35, 0xd83a, 0xdd45, 0xd83a, 0xdd24, 0xd83a, 0xdd23, 0xd83a, 0xdd22, 0xd83a, 0xdd44,
+0xd83a, 0xdd32, 0xd83a, 0xdd4b, 0xd83a, 0xdd23, 0xd83a, 0xdd35, 0x3b, 0xd83a, 0xdd05, 0xd83a,
+0xdd22, 0xd83a, 0xdd26, 0xd83a, 0xdd46, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0xd83a, 0xdd23, 0xd83a,
+0xdd35, 0x2d, 0xd83a, 0xdd01, 0xd83a, 0xdd2e, 0xd83a, 0xdd32, 0xd83a, 0xdd33, 0xd83a, 0xdd2d,
+0xd83a, 0xdd32, 0x3b, 0xd83a, 0xdd01, 0xd83a, 0xdd35, 0xd83a, 0xdd32, 0xd83a, 0xdd33, 0xd83a,
+0xdd2d, 0xd83a, 0xdd32, 0xd83a, 0xdd14, 0xd83a, 0xdd2e, 0xd83a, 0xdd26, 0x2e, 0x3b, 0xd83a,
+0xdd05, 0xd83a, 0xdd22, 0xd83a, 0xdd28, 0x2e, 0x3b, 0xd83a, 0xdd06, 0xd83a, 0xdd22, 0xd83a,
+0xdd2a, 0x2e, 0x3b, 0xd83a, 0xdd03, 0xd83a, 0xdd2d, 0xd83a, 0xdd28, 0x2e, 0x3b, 0xd83a,
+0xdd04, 0xd83a, 0xdd22, 0xd83a, 0xdd28, 0x2e, 0x3b, 0xd83a, 0xdd05, 0xd83a, 0xdd22, 0xd83a,
+0xdd2a, 0x2e, 0x3b, 0xd83a, 0xdd08, 0xd83a, 0xdd22, 0xd83a, 0xdd36, 0x2e, 0x3b, 0xd83a,
+0xdd05, 0xd83a, 0xdd22, 0xd83a, 0xdd27, 0x2e, 0x3b, 0xd83a, 0xdd05, 0xd83a, 0xdd35, 0xd83a,
+0xdd25, 0x2e, 0x3b, 0xd83a, 0xdd14, 0xd83a, 0xdd35, 0xd83a, 0xdd24, 0x2e, 0x3b, 0xd83a,
+0xdd05, 0xd83a, 0xdd22, 0xd83a, 0xdd23, 0x2e, 0x3b, 0xd83a, 0xdd01, 0xd83a, 0xdd2e, 0xd83a,
+0xdd32, 0x2e, 0xd83a, 0xdd51, 0x3b, 0xd83a, 0xdd52, 0x3b, 0xd83a, 0xdd53, 0x3b, 0xd83a,
+0xdd54, 0x3b, 0xd83a, 0xdd55, 0x3b, 0xd83a, 0xdd56, 0x3b, 0xd83a, 0xdd57, 0x3b, 0xd83a,
+0xdd58, 0x3b, 0xd83a, 0xdd59, 0x3b, 0xd83a, 0xdd51, 0xd83a, 0xdd50, 0x3b, 0xd83a, 0xdd51,
+0xd83a, 0xdd51, 0x3b, 0xd83a, 0xdd51, 0xd83a, 0xdd52, 0x10db, 0x10e3, 0x10f0, 0x10d0, 0x10e0,
+0x10d0, 0x10db, 0x10d8, 0x3b, 0x10e1, 0x10d0, 0x10e4, 0x10d0, 0x10e0, 0x10d8, 0x3b, 0x10e0,
+0x10d0, 0x10d1, 0x10d8, 0x20, 0x10e3, 0x10da, 0x2d, 0x10d0, 0x10d5, 0x10d0, 0x10da, 0x10d8,
+0x3b, 0x10e0, 0x10d0, 0x10d1, 0x10d8, 0x20, 0x10e3, 0x10da, 0x2d, 0x10d0, 0x10ee, 0x10d8,
+0x10e0, 0x10d8, 0x3b, 0x10ef, 0x10e3, 0x10db, 0x10d0, 0x10d3, 0x10d0, 0x20, 0x10e3, 0x10da,
+0x2d, 0x10d0, 0x10d5, 0x10d0, 0x10da, 0x10d8, 0x3b, 0x10ef, 0x10e3, 0x10db, 0x10d0, 0x10d3,
+0x10d0, 0x20, 0x10e3, 0x10da, 0x2d, 0x10d0, 0x10ee, 0x10d8, 0x10e0, 0x10d8, 0x3b, 0x10e0,
+0x10d0, 0x10ef, 0x10d0, 0x10d1, 0x10d8, 0x3b, 0x10e8, 0x10d0, 0x10d1, 0x10d0, 0x10dc, 0x10d8,
+0x3b, 0x10e0, 0x10d0, 0x10db, 0x10d0, 0x10d3, 0x10d0, 0x10dc, 0x10d8, 0x3b, 0x10e8, 0x10d0,
+0x10d5, 0x10d0, 0x10da, 0x10d8, 0x3b, 0x10d6, 0x10e3, 0x10da, 0x2d, 0x10d9, 0x10d0, 0x10d0,
+0x10d3, 0x10d0, 0x3b, 0x10d6, 0x10e3, 0x10da, 0x2d, 0x10f0, 0x10d8, 0x10ef, 0x10d0, 0x10db,
+0x10e3, 0x10f0, 0x2e, 0x3b, 0x10e1, 0x10d0, 0x10e4, 0x2e, 0x3b, 0x10e0, 0x10d0, 0x10d1,
+0x2e, 0x20, 0x49, 0x3b, 0x10e0, 0x10d0, 0x10d1, 0x2e, 0x20, 0x49, 0x49, 0x3b,
+0x10ef, 0x10e3, 0x10db, 0x2e, 0x20, 0x49, 0x3b, 0x10ef, 0x10e3, 0x10db, 0x2e, 0x20,
+0x49, 0x49, 0x3b, 0x10e0, 0x10d0, 0x10ef, 0x2e, 0x3b, 0x10e8, 0x10d0, 0x10d1, 0x2e,
+0x3b, 0x10e0, 0x10d0, 0x10db, 0x2e, 0x3b, 0x10e8, 0x10d0, 0x10d5, 0x2e, 0x3b, 0x10d6,
+0x10e3, 0x10da, 0x2d, 0x10d9, 0x2e, 0x3b, 0x10d6, 0x10e3, 0x10da, 0x2d, 0x10f0, 0x2e,
+0x4d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x53, 0x61, 0x66,
+0x61, 0x72, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x3b, 0x52,
+0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x49, 0x3b, 0x44, 0x73, 0x63, 0x68,
+0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x3b, 0x44, 0x73, 0x63, 0x68,
+0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x49, 0x3b, 0x52, 0x61, 0x64,
+0x73, 0x63, 0x68, 0x61, 0x62, 0x3b, 0x53, 0x68, 0x61, 0x2bb, 0x62, 0x61,
+0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x53, 0x68,
+0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x44, 0x68, 0x75, 0x20, 0x6c, 0x2d,
+0x71, 0x61, 0x2bf, 0x64, 0x61, 0x3b, 0x44, 0x68, 0x75, 0x20, 0x6c, 0x2d,
+0x48, 0x69, 0x64, 0x64, 0x73, 0x63, 0x68, 0x61, 0xaae, 0xac1, 0xab9, 0xab0,
+0xacd, 0xab0, 0xaae, 0x3b, 0xab8, 0xaab, 0xab0, 0x3b, 0xab0, 0xabe, 0xaac, 0xac0,
+0x2bb, 0x20, 0x49, 0x3b, 0xab0, 0xabe, 0xaac, 0xac0, 0x2bb, 0x20, 0x49, 0x49,
+0x3b, 0xa9c, 0xac1, 0xaae, 0xabe, 0xaa6, 0xabe, 0x20, 0x49, 0x3b, 0xa9c, 0xac1,
+0xaae, 0xabe, 0xaa6, 0xabe, 0x20, 0x49, 0x49, 0x3b, 0xab0, 0xa9c, 0xaac, 0x3b,
+0xab6, 0xabe, 0x2bb, 0xaac, 0xabe, 0xaa8, 0x3b, 0xab0, 0xaae, 0xaa6, 0xabe, 0xaa8,
+0x3b, 0xab6, 0xabe, 0xab5, 0xacd, 0xab5, 0xab2, 0x3b, 0xaa7, 0xac1, 0x2bb, 0xab2,
+0x2d, 0xa95, 0xacd, 0xab5, 0xac0, 0x2bb, 0xaa1, 0xabe, 0xab9, 0x3b, 0xaa7, 0xac1,
+0x2bb, 0xab2, 0x2d, 0xab9, 0xabf, 0xa9c, 0xacd, 0xa9c, 0xabe, 0xab9, 0xaae, 0xac1,
+0xab9, 0x2e, 0x3b, 0xab8, 0xaab, 0x2e, 0x3b, 0xab0, 0xaac, 0x2e, 0x49, 0x3b,
+0xab0, 0xaac, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0xa9c, 0xac1, 0xaae, 0x2e, 0x20,
+0x49, 0x3b, 0xa9c, 0xac1, 0xaae, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0xab0, 0xabe,
+0xa9c, 0x2e, 0x3b, 0xab6, 0xabe, 0x2e, 0x3b, 0xab0, 0xabe, 0xaae, 0x2e, 0x3b,
+0xab6, 0xabe, 0xab5, 0x2e, 0x3b, 0xaa7, 0xac1, 0x2bb, 0xab2, 0x2d, 0xa95, 0xacd,
+0xaaf, 0xac1, 0x2e, 0x3b, 0xaa7, 0xac1, 0x2bb, 0xab2, 0x2d, 0xa8f, 0xa9a, 0x2e,
+0x4d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x53, 0x61, 0x66,
+0x61, 0x72, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x3b, 0x52,
+0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x49, 0x3b, 0x4a, 0x75, 0x6d, 0x61,
+0x64, 0x61, 0x20, 0x49, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20,
+0x49, 0x49, 0x3b, 0x52, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x53, 0x68, 0x61,
+0x2bc, 0x61, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64, 0x61,
+0x6e, 0x3b, 0x53, 0x68, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x44, 0x68,
+0x75, 0x2bb, 0x6c, 0x2d, 0x51, 0x69, 0x2bb, 0x64, 0x61, 0x68, 0x3b, 0x44,
+0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x48, 0x69, 0x6a, 0x6a, 0x61, 0x68, 0x5de,
+0x5d5, 0x5d7, 0x5e8, 0x5dd, 0x3b, 0x5e6, 0x5e4, 0x5e8, 0x3b, 0x5e8, 0x5d1, 0x5d9,
+0x5e2, 0x20, 0x5d0, 0x5dc, 0x5be, 0x5d0, 0x5d5, 0x5d5, 0x5dc, 0x3b, 0x5e8, 0x5d1,
+0x5d9, 0x5e2, 0x20, 0x5d0, 0x5be, 0x5ea, 0x5f3, 0x5d0, 0x5e0, 0x5d9, 0x3b, 0x5d2,
+0x5f3, 0x5d5, 0x5de, 0x5d0, 0x5d3, 0x5d0, 0x20, 0x5d0, 0x5dc, 0x5be, 0x5d0, 0x5d5,
+0x5dc, 0x5d0, 0x3b, 0x5d2, 0x5f3, 0x5d5, 0x5de, 0x5d0, 0x5d3, 0x5d0, 0x20, 0x5d0,
+0x5be, 0x5ea, 0x5f3, 0x5d0, 0x5e0, 0x5d9, 0x5d4, 0x3b, 0x5e8, 0x5d2, 0x5f3, 0x5d1,
+0x3b, 0x5e9, 0x5e2, 0x5d1, 0x5d0, 0x5df, 0x3b, 0x5e8, 0x5de, 0x5d3, 0x5d0, 0x5df,
+0x3b, 0x5e9, 0x5d5, 0x5d5, 0x5d0, 0x5dc, 0x3b, 0x5d3, 0x5f3, 0x5d5, 0x20, 0x5d0,
+0x5dc, 0x5be, 0x5e7, 0x5e2, 0x5d3, 0x5d4, 0x3b, 0x5d3, 0x5f3, 0x5d5, 0x20, 0x5d0,
+0x5dc, 0x5be, 0x5d7, 0x5d9, 0x5d2, 0x5f3, 0x5d4, 0x5de, 0x5d5, 0x5d7, 0x5e8, 0x5dd,
+0x3b, 0x5e6, 0x5e4, 0x5e8, 0x3b, 0x5e8, 0x5d1, 0x5d9, 0x5e2, 0x20, 0x5d0, 0x5dc,
+0x2d, 0x5d0, 0x5d5, 0x5d5, 0x5dc, 0x3b, 0x5e8, 0x5d1, 0x5d9, 0x5e2, 0x20, 0x5d0,
+0x2d, 0x5ea, 0x5f3, 0x5d0, 0x5e0, 0x5d9, 0x3b, 0x5d2, 0x5f3, 0x5d5, 0x5de, 0x5d0,
+0x5d3, 0x5d0, 0x20, 0x5d0, 0x5dc, 0x2d, 0x5d0, 0x5d5, 0x5dc, 0x5d0, 0x3b, 0x5d2,
+0x5f3, 0x5d5, 0x5de, 0x5d0, 0x5d3, 0x5d0, 0x20, 0x5d0, 0x2d, 0x5ea, 0x5f3, 0x5d0,
+0x5e0, 0x5d9, 0x5d4, 0x3b, 0x5e8, 0x5d2, 0x5f3, 0x5d1, 0x3b, 0x5e9, 0x5e2, 0x5d1,
+0x5d0, 0x5df, 0x3b, 0x5e8, 0x5de, 0x5d3, 0x5d0, 0x5df, 0x3b, 0x5e9, 0x5d5, 0x5d5,
+0x5d0, 0x5dc, 0x3b, 0x5d3, 0x5f3, 0x5d5, 0x20, 0x5d0, 0x5dc, 0x5be, 0x5e7, 0x5e2,
+0x5d3, 0x5d4, 0x3b, 0x5d3, 0x5f3, 0x5d5, 0x20, 0x5d0, 0x5dc, 0x5be, 0x5d7, 0x5d9,
+0x5d2, 0x5f3, 0x5d4, 0x5de, 0x5d5, 0x5d7, 0x5e8, 0x5dd, 0x3b, 0x5e6, 0x5e4, 0x5e8,
+0x3b, 0x5e8, 0x5d1, 0x5d9, 0x5e2, 0x20, 0x5d0, 0x5f3, 0x3b, 0x5e8, 0x5d1, 0x5d9,
+0x5e2, 0x20, 0x5d1, 0x5f3, 0x3b, 0x5d2, 0x5f3, 0x5d5, 0x5de, 0x5d0, 0x5d3, 0x5d0,
+0x20, 0x5d0, 0x5f3, 0x3b, 0x5d2, 0x5f3, 0x5d5, 0x5de, 0x5d0, 0x5d3, 0x5d0, 0x20,
+0x5d1, 0x5f3, 0x3b, 0x5e8, 0x5d2, 0x5f3, 0x5d1, 0x3b, 0x5e9, 0x5e2, 0x5d1, 0x5d0,
+0x5df, 0x3b, 0x5e8, 0x5de, 0x5d3, 0x5d0, 0x5df, 0x3b, 0x5e9, 0x5d5, 0x5d5, 0x5d0,
+0x5dc, 0x3b, 0x5d3, 0x5f3, 0x5d5, 0x20, 0x5d0, 0x5dc, 0x5be, 0x5e7, 0x5e2, 0x5d3,
+0x5d4, 0x3b, 0x5d3, 0x5f3, 0x5d5, 0x20, 0x5d0, 0x5dc, 0x5be, 0x5d7, 0x5d9, 0x5d2,
+0x5f3, 0x5d4, 0x92e, 0x941, 0x939, 0x930, 0x94d, 0x930, 0x92e, 0x3b, 0x938, 0x92b,
+0x930, 0x3b, 0x930, 0x93e, 0x92c, 0x940, 0x20, 0x92a, 0x94d, 0x930, 0x925, 0x92e,
+0x3b, 0x930, 0x93e, 0x92c, 0x940, 0x20, 0x926, 0x94d, 0x935, 0x93f, 0x924, 0x940,
+0x92f, 0x3b, 0x91c, 0x941, 0x92e, 0x94d, 0x921, 0x93e, 0x20, 0x92a, 0x94d, 0x930,
+0x925, 0x92e, 0x3b, 0x91c, 0x941, 0x92e, 0x94d, 0x921, 0x93e, 0x20, 0x926, 0x94d,
+0x935, 0x93f, 0x924, 0x940, 0x92f, 0x3b, 0x930, 0x91c, 0x92c, 0x3b, 0x936, 0x93e,
+0x935, 0x928, 0x3b, 0x930, 0x92e, 0x91c, 0x93e, 0x928, 0x3b, 0x936, 0x935, 0x94d,
+0x935, 0x94d, 0x932, 0x3b, 0x91c, 0x93f, 0x932, 0x2d, 0x915, 0x94d, 0x926, 0x93e,
+0x939, 0x3b, 0x91c, 0x93f, 0x932, 0x94d, 0x2d, 0x939, 0x93f, 0x91c, 0x94d, 0x91c,
+0x93e, 0x939, 0x4d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x53,
+0x61, 0x66, 0x61, 0x72, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x20, 0x61, 0x6c,
+0x2d, 0x41, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x20,
+0x61, 0x73, 0x2d, 0x53, 0x61, 0x61, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6d,
+0x61, 0x61, 0x64, 0x61, 0x20, 0x61, 0x6c, 0x2d, 0x41, 0x77, 0x77, 0x61,
+0x6c, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x61, 0x64, 0x61, 0x20, 0x61, 0x73,
+0x2d, 0x53, 0x61, 0x61, 0x6e, 0x69, 0x3b, 0x52, 0x61, 0x6a, 0x61, 0x62,
+0x3b, 0x53, 0x68, 0x61, 0x61, 0x62, 0x61, 0x61, 0x6e, 0x3b, 0x52, 0x61,
+0x6d, 0x7a, 0x61, 0x61, 0x6e, 0x3b, 0x53, 0x68, 0x61, 0x77, 0x77, 0x61,
+0x61, 0x6c, 0x3b, 0x5a, 0x75, 0x2019, 0x6c, 0x2d, 0x51, 0x61, 0x61, 0x64,
+0x61, 0x3b, 0x5a, 0x75, 0x2019, 0x6c, 0x2d, 0x48, 0x69, 0x6a, 0x6a, 0x61,
+0x4d, 0x75, 0x68, 0x3b, 0x53, 0x61, 0x66, 0x3b, 0x52, 0x61, 0x62, 0x69,
+0x20, 0x31, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x20, 0x32, 0x3b, 0x4a, 0x75,
+0x6d, 0x20, 0x31, 0x3b, 0x4a, 0x75, 0x6d, 0x20, 0x32, 0x3b, 0x52, 0x61,
+0x6a, 0x61, 0x62, 0x3b, 0x53, 0x68, 0x61, 0x62, 0x3b, 0x52, 0x61, 0x6d,
+0x3b, 0x53, 0x68, 0x61, 0x77, 0x3b, 0x5a, 0x75, 0x20, 0x51, 0x3b, 0x5a,
+0x75, 0x20, 0x48, 0x4d, 0x6f, 0x68, 0x61, 0x72, 0x72, 0x65, 0x6d, 0x3b,
+0x53, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x52, 0xe9, 0x62, 0x69, 0x20, 0x49,
+0x3b, 0x52, 0xe9, 0x62, 0x69, 0x20, 0x49, 0x49, 0x3b, 0x44, 0x73, 0x65,
+0x6d, 0xe1, 0x64, 0x69, 0x20, 0x49, 0x3b, 0x44, 0x73, 0x65, 0x6d, 0xe1,
+0x64, 0x69, 0x20, 0x49, 0x49, 0x3b, 0x52, 0x65, 0x64, 0x73, 0x65, 0x62,
+0x3b, 0x53, 0x61, 0x62, 0xe1, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64,
+0xe1, 0x6e, 0x3b, 0x53, 0x65, 0x76, 0x76, 0xe1, 0x6c, 0x3b, 0x44, 0x73,
+0xfc, 0x6c, 0x20, 0x6b, 0x61, 0x64, 0x65, 0x3b, 0x44, 0x73, 0xfc, 0x6c,
+0x20, 0x68, 0x65, 0x64, 0x73, 0x65, 0x4d, 0x6f, 0x68, 0x61, 0x72, 0x72,
+0x65, 0x6d, 0x3b, 0x53, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x52, 0xe9, 0x62,
+0x69, 0x20, 0x65, 0x6c, 0x20, 0x61, 0x76, 0x76, 0x65, 0x6c, 0x3b, 0x52,
+0xe9, 0x62, 0x69, 0x20, 0x65, 0x6c, 0x20, 0x61, 0x63, 0x63, 0x68, 0x65,
+0x72, 0x3b, 0x44, 0x73, 0x65, 0x6d, 0xe1, 0x64, 0x69, 0x20, 0x65, 0x6c,
+0x20, 0x61, 0x76, 0x76, 0x65, 0x6c, 0x3b, 0x44, 0x73, 0x65, 0x6d, 0xe1,
+0x64, 0x69, 0x20, 0x65, 0x6c, 0x20, 0x61, 0x63, 0x63, 0x68, 0x65, 0x72,
+0x3b, 0x52, 0x65, 0x64, 0x73, 0x65, 0x62, 0x3b, 0x53, 0x61, 0x62, 0xe1,
+0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64, 0xe1, 0x6e, 0x3b, 0x53, 0x65,
+0x76, 0x76, 0xe1, 0x6c, 0x3b, 0x44, 0x73, 0xfc, 0x6c, 0x20, 0x6b, 0x61,
+0x64, 0x65, 0x3b, 0x44, 0x73, 0xfc, 0x6c, 0x20, 0x68, 0x65, 0x64, 0x73,
+0x65, 0x4d, 0x6f, 0x68, 0x2e, 0x3b, 0x53, 0x61, 0x66, 0x2e, 0x3b, 0x52,
+0xe9, 0x62, 0x2e, 0x20, 0x31, 0x3b, 0x52, 0xe9, 0x62, 0x2e, 0x20, 0x32,
+0x3b, 0x44, 0x73, 0x65, 0x6d, 0x2e, 0x20, 0x49, 0x3b, 0x44, 0x73, 0x65,
+0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x52, 0x65, 0x64, 0x2e, 0x3b, 0x53,
+0x61, 0x62, 0x2e, 0x3b, 0x52, 0x61, 0x6d, 0x2e, 0x3b, 0x53, 0x65, 0x76,
+0x2e, 0x3b, 0x44, 0x73, 0xfc, 0x6c, 0x20, 0x6b, 0x2e, 0x3b, 0x44, 0x73,
+0xfc, 0x6c, 0x20, 0x68, 0x2e, 0x6d, 0x75, 0x68, 0x2e, 0x3b, 0x73, 0x61,
+0x66, 0x2e, 0x3b, 0x72, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x3b, 0x72, 0x61,
+0x62, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x6a, 0x75, 0x6d, 0x2e, 0x20, 0x49,
+0x3b, 0x6a, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x72, 0x61, 0x6a,
+0x2e, 0x3b, 0x73, 0x68, 0x61, 0x2e, 0x3b, 0x72, 0x61, 0x6d, 0x2e, 0x3b,
+0x73, 0x68, 0x61, 0x77, 0x2e, 0x3b, 0x64, 0x68, 0x75, 0x2bb, 0x6c, 0x2d,
+0x51, 0x2e, 0x3b, 0x64, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x48, 0x2e, 0x4d,
+0x75, 0x68, 0x61, 0x72, 0x61, 0x6d, 0x3b, 0x53, 0x61, 0x66, 0x61, 0x72,
+0x3b, 0x52, 0x61, 0x62, 0x69, 0x75, 0x6c, 0x61, 0x77, 0x61, 0x6c, 0x3b,
+0x52, 0x61, 0x62, 0x69, 0x75, 0x6c, 0x61, 0x6b, 0x68, 0x69, 0x72, 0x3b,
+0x4a, 0x75, 0x6d, 0x61, 0x64, 0x69, 0x6c, 0x61, 0x77, 0x61, 0x6c, 0x3b,
+0x4a, 0x75, 0x6d, 0x61, 0x64, 0x69, 0x6c, 0x61, 0x6b, 0x68, 0x69, 0x72,
+0x3b, 0x52, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x53, 0x79, 0x61, 0x6b, 0x62,
+0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x53,
+0x79, 0x61, 0x77, 0x61, 0x6c, 0x3b, 0x5a, 0x75, 0x6c, 0x6b, 0x61, 0x69,
+0x64, 0x61, 0x68, 0x3b, 0x5a, 0x75, 0x6c, 0x68, 0x69, 0x6a, 0x61, 0x68,
+0x4d, 0x75, 0x68, 0x2e, 0x3b, 0x53, 0x61, 0x66, 0x2e, 0x3b, 0x52, 0x61,
+0x62, 0x2e, 0x20, 0x41, 0x77, 0x61, 0x6c, 0x3b, 0x52, 0x61, 0x62, 0x2e,
+0x20, 0x41, 0x6b, 0x68, 0x69, 0x72, 0x3b, 0x4a, 0x75, 0x6d, 0x2e, 0x20,
+0x41, 0x77, 0x61, 0x6c, 0x3b, 0x4a, 0x75, 0x6d, 0x2e, 0x20, 0x41, 0x6b,
+0x68, 0x69, 0x72, 0x3b, 0x52, 0x61, 0x6a, 0x2e, 0x3b, 0x53, 0x79, 0x61,
+0x2e, 0x3b, 0x52, 0x61, 0x6d, 0x2e, 0x3b, 0x53, 0x79, 0x61, 0x77, 0x2e,
+0x3b, 0x5a, 0x75, 0x6c, 0x6b, 0x61, 0x2e, 0x3b, 0x5a, 0x75, 0x6c, 0x68,
+0x69, 0x2e, 0x30e0, 0x30cf, 0x30c3, 0x30e9, 0x30e0, 0x3b, 0x30b5, 0x30d5, 0x30a2, 0x30eb,
+0x3b, 0x30e9, 0x30d3, 0x30fc, 0x30fb, 0x30a6, 0x30eb, 0x30fb, 0x30a2, 0x30a6, 0x30ef, 0x30eb,
+0x3b, 0x30e9, 0x30d3, 0x30fc, 0x30fb, 0x30a6, 0x30c3, 0x30fb, 0x30b5, 0x30fc, 0x30cb, 0x30fc,
+0x3b, 0x30b8, 0x30e5, 0x30de, 0x30fc, 0x30c0, 0x30eb, 0x30fb, 0x30a2, 0x30a6, 0x30ef, 0x30eb,
+0x3b, 0x30b8, 0x30e5, 0x30de, 0x30fc, 0x30c0, 0x30c3, 0x30b5, 0x30fc, 0x30cb, 0x30fc, 0x3b,
+0x30e9, 0x30b8, 0x30e3, 0x30d6, 0x3b, 0x30b7, 0x30e3, 0x30a2, 0x30d0, 0x30fc, 0x30f3, 0x3b,
+0x30e9, 0x30de, 0x30c0, 0x30fc, 0x30f3, 0x3b, 0x30b7, 0x30e3, 0x30a6, 0x30ef, 0x30fc, 0x30eb,
+0x3b, 0x30ba, 0x30eb, 0x30fb, 0x30ab, 0x30a4, 0x30c0, 0x3b, 0x30ba, 0x30eb, 0x30fb, 0x30d2,
+0x30c3, 0x30b8, 0x30e3, 0x53, 0x75, 0x72, 0x61, 0x3b, 0x53, 0x61, 0x70, 0x61,
+0x72, 0x3b, 0x4d, 0x75, 0x6c, 0x75, 0x64, 0x3b, 0x42, 0x61, 0x6b, 0x64,
+0x61, 0x20, 0x4d, 0x75, 0x6c, 0x75, 0x64, 0x3b, 0x4a, 0x75, 0x6d, 0x61,
+0x64, 0x69, 0x6c, 0x61, 0x77, 0x61, 0x6c, 0x3b, 0x4a, 0x75, 0x6d, 0x61,
+0x64, 0x69, 0x6c, 0x61, 0x6b, 0x69, 0x72, 0x3b, 0x52, 0x65, 0x6a, 0x65,
+0x62, 0x3b, 0x52, 0x75, 0x77, 0x61, 0x68, 0x3b, 0x50, 0x61, 0x73, 0x61,
+0x3b, 0x53, 0x61, 0x77, 0x61, 0x6c, 0x3b, 0x53, 0x65, 0x6c, 0x6f, 0x3b,
+0x42, 0x65, 0x73, 0x61, 0x72, 0x53, 0x75, 0x72, 0x2e, 0x3b, 0x53, 0x61,
+0x70, 0x2e, 0x3b, 0x4d, 0x75, 0x6c, 0x2e, 0x3b, 0x42, 0x2e, 0x20, 0x4d,
+0x75, 0x6c, 0x2e, 0x3b, 0x4a, 0x75, 0x6d, 0x2e, 0x20, 0x41, 0x77, 0x2e,
+0x3b, 0x4a, 0x75, 0x6d, 0x2e, 0x20, 0x41, 0x6b, 0x2e, 0x3b, 0x52, 0x65,
+0x6a, 0x2e, 0x3b, 0x52, 0x75, 0x77, 0x2e, 0x3b, 0x50, 0x73, 0x6f, 0x2e,
+0x3b, 0x53, 0x68, 0x61, 0x77, 0x2e, 0x3b, 0x53, 0x6c, 0x6f, 0x2e, 0x3b,
+0x42, 0x73, 0x61, 0x72, 0x2e, 0xcae, 0xcc1, 0xcb9, 0xcb0, 0xcae, 0xccd, 0x3b,
+0xcb8, 0xcab, 0xcbe, 0xcb0, 0xccd, 0x3b, 0xcb0, 0xcac, 0xcbf, 0x2018, 0x20, 0x49,
+0x3b, 0xcb0, 0xcac, 0xcbf, 0x2018, 0x20, 0x49, 0x49, 0x3b, 0xc9c, 0xcc1, 0xcae,
+0xcbe, 0xca6, 0xcbe, 0x20, 0x49, 0x3b, 0xc9c, 0xcc1, 0xcae, 0xcbe, 0xca6, 0xcbe,
+0x20, 0x49, 0x49, 0x3b, 0xcb0, 0xc9c, 0xcac, 0xccd, 0x3b, 0xcb6, 0x2019, 0xcac,
+0xcbe, 0xca8, 0xccd, 0x3b, 0xcb0, 0xcae, 0xca6, 0xcbe, 0xca8, 0xccd, 0x3b, 0xcb6,
+0xcb5, 0xccd, 0xcb5, 0xcbe, 0xcb2, 0xccd, 0x3b, 0xca7, 0xcc1, 0x2018, 0xcb2, 0xccd,
+0x2d, 0xc95, 0xcbf, 0x2018, 0xca1, 0xcbe, 0xcb9, 0xccd, 0x3b, 0xca7, 0xcc1, 0x2018,
+0xcb2, 0xccd, 0x2d, 0xcb9, 0xcbf, 0xc9c, 0xcbe, 0xcb9, 0xccd, 0xcae, 0xcc1, 0xcb9,
+0xccd, 0x2e, 0x3b, 0xcb8, 0xcab, 0xcbe, 0x2e, 0x3b, 0xcb0, 0xcac, 0xcbf, 0x2018,
+0x20, 0x49, 0x3b, 0xcb0, 0xcac, 0xcbf, 0x2018, 0x20, 0x49, 0x49, 0x3b, 0xc9c,
+0xcc1, 0xcae, 0xccd, 0x2e, 0x20, 0x49, 0x3b, 0xc9c, 0xcc1, 0xcae, 0xccd, 0x2e,
+0x20, 0x49, 0x49, 0x3b, 0xcb0, 0xc9c, 0xccd, 0x2e, 0x3b, 0xcb6, 0x2e, 0x3b,
+0xcb0, 0xcae, 0xccd, 0x2e, 0x3b, 0xcb6, 0xcb5, 0xccd, 0x2e, 0x3b, 0xca7, 0xcc1,
+0x2018, 0xcb2, 0xccd, 0x2d, 0xc95, 0xcbf, 0x2e, 0x3b, 0xca7, 0xcc1, 0x2018, 0xcb2,
+0xccd, 0x2d, 0xcb9, 0x2e, 0x41c, 0x4b1, 0x445, 0x430, 0x440, 0x440, 0x430, 0x43c,
+0x3b, 0x421, 0x430, 0x444, 0x430, 0x440, 0x3b, 0x420, 0x430, 0x431, 0x438, 0x493,
+0x20, 0x4d9, 0x43b, 0x2d, 0x4d9, 0x443, 0x443, 0x4d9, 0x43b, 0x3b, 0x420, 0x430,
+0x431, 0x438, 0x493, 0x20, 0x4d9, 0x441, 0x2d, 0x441, 0x4d9, 0x43d, 0x438, 0x3b,
+0x414, 0x436, 0x443, 0x43c, 0x430, 0x434, 0x430, 0x20, 0x4d9, 0x43b, 0x2d, 0x4d9,
+0x443, 0x443, 0x4d9, 0x43b, 0x3b, 0x416, 0x443, 0x43c, 0x430, 0x434, 0x20, 0x430,
+0x441, 0x2d, 0x441, 0x4d9, 0x43d, 0x438, 0x3b, 0x420, 0x430, 0x434, 0x436, 0x430,
+0x431, 0x3b, 0x428, 0x430, 0x493, 0x431, 0x430, 0x43d, 0x3b, 0x420, 0x430, 0x43c,
+0x430, 0x434, 0x430, 0x43d, 0x3b, 0x428, 0x4d9, 0x443, 0x443, 0x4d9, 0x43b, 0x3b,
+0x417, 0x443, 0x43b, 0x2d, 0x49a, 0x430, 0x493, 0x434, 0x430, 0x3b, 0x417, 0x443,
+0x43b, 0x2d, 0x425, 0x438, 0x434, 0x436, 0x430, 0x41c, 0x4b1, 0x445, 0x2e, 0x3b,
+0x421, 0x430, 0x444, 0x2e, 0x3b, 0x420, 0x430, 0x431, 0x2e, 0x20, 0x406, 0x3b,
+0x420, 0x430, 0x431, 0x2e, 0x20, 0x406, 0x406, 0x3b, 0x416, 0x443, 0x43c, 0x2e,
+0x20, 0x406, 0x3b, 0x416, 0x443, 0x43c, 0x2e, 0x20, 0x406, 0x406, 0x3b, 0x420,
+0x430, 0x434, 0x436, 0x2e, 0x3b, 0x428, 0x430, 0x493, 0x2e, 0x3b, 0x420, 0x430,
+0x43c, 0x2e, 0x3b, 0x428, 0x4d9, 0x443, 0x2e, 0x3b, 0x417, 0x443, 0x43b, 0x2d,
+0x49a, 0x2e, 0x3b, 0x417, 0x443, 0x43b, 0x2d, 0x425, 0x2e, 0x49a, 0x430, 0x4a3,
+0x2e, 0x3b, 0x410, 0x49b, 0x43f, 0x2e, 0x3b, 0x41d, 0x430, 0x443, 0x2e, 0x3b,
+0x421, 0x4d9, 0x443, 0x2e, 0x3b, 0x41c, 0x430, 0x43c, 0x2e, 0x3b, 0x4a, 0x75,
+0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x448, 0x456, 0x43b, 0x2e, 0x3b, 0x442,
+0x430, 0x43c, 0x2e, 0x3b, 0x49a, 0x44b, 0x440, 0x2e, 0x3b, 0x49a, 0x430, 0x437,
+0x2e, 0x3b, 0x49a, 0x430, 0x440, 0x2e, 0x3b, 0x416, 0x435, 0x43b, 0x2e, 0xbb34,
+0xd558, 0xb78c, 0x3b, 0xc0ac, 0xd30c, 0xb974, 0x3b, 0xb77c, 0xbe44, 0x20, 0xc54c, 0x20,
+0xc544, 0xc648, 0x3b, 0xb77c, 0xbe44, 0x20, 0xc54c, 0x20, 0xc384, 0xb2c8, 0x3b, 0xc8fc,
+0xb9c8, 0xb2e4, 0x20, 0xc54c, 0x20, 0xc544, 0xc648, 0x3b, 0xc8fc, 0xb9c8, 0xb2e4, 0x20,
+0xc54c, 0x20, 0xc384, 0xb2c8, 0x3b, 0xb77c, 0xc7a1, 0x3b, 0xc250, 0xc544, 0xbc18, 0x3b,
+0xb77c, 0xb9c8, 0xb2e8, 0x3b, 0xc250, 0xc648, 0x3b, 0xb4c0, 0x20, 0xc54c, 0x20, 0xae4c,
+0xb2e4, 0x3b, 0xb4c0, 0x20, 0xc54c, 0x20, 0xd788, 0xc790, 0x6d, 0x75, 0x68, 0x65,
+0x72, 0x65, 0x6d, 0x3b, 0x73, 0x65, 0x66, 0x65, 0x72, 0x3b, 0x72, 0x65,
+0x62, 0xee, 0x2bf, 0x75, 0x6c, 0x65, 0x77, 0x65, 0x6c, 0x3b, 0x72, 0x65,
+0x62, 0xee, 0x2bf, 0x75, 0x6c, 0x61, 0x78, 0x65, 0x72, 0x3b, 0x63, 0x65,
+0x6d, 0x61, 0x7a, 0xee, 0x79, 0x65, 0x6c, 0x65, 0x77, 0x65, 0x6c, 0x3b,
+0x63, 0x65, 0x6d, 0x61, 0x7a, 0xee, 0x79, 0x65, 0x6c, 0x61, 0x78, 0x65,
+0x72, 0x3b, 0x72, 0x65, 0x63, 0x65, 0x62, 0x3b, 0x15f, 0x65, 0x2bf, 0x62,
+0x61, 0x6e, 0x3b, 0x72, 0x65, 0x6d, 0x65, 0x7a, 0x61, 0x6e, 0x3b, 0x15f,
+0x65, 0x77, 0x61, 0x6c, 0x3b, 0x7a, 0xee, 0x6c, 0x71, 0x65, 0x2bf, 0x64,
+0x65, 0x3b, 0x7a, 0x69, 0x6c, 0x68, 0x65, 0x63, 0x65, 0x6d, 0x75, 0x68,
+0x2e, 0x3b, 0x73, 0x65, 0x66, 0x2e, 0x3b, 0x72, 0x65, 0x62, 0x2e, 0x20,
+0x49, 0x65, 0x6d, 0x3b, 0x72, 0x65, 0x62, 0x2e, 0x20, 0x49, 0x49, 0x79,
+0x65, 0x6d, 0x3b, 0x63, 0x6d, 0x7a, 0x2e, 0x20, 0x49, 0x65, 0x6d, 0x3b,
+0x63, 0x6d, 0x7a, 0x2e, 0x20, 0x49, 0x49, 0x79, 0x65, 0x6d, 0x3b, 0x72,
+0x63, 0x62, 0x2e, 0x3b, 0x15f, 0x62, 0x6e, 0x2e, 0x3b, 0x72, 0x6d, 0x7a,
+0x2e, 0x3b, 0x15f, 0x77, 0x6c, 0x2e, 0x3b, 0x7a, 0x71, 0x64, 0x2e, 0x3b,
+0x7a, 0x68, 0x63, 0x2e, 0xea1, 0xeb8, 0xea3, 0xeb0, 0xeae, 0xead, 0xea1, 0x3b,
+0xe8a, 0xeb2, 0xe9f, 0xeb2, 0xea3, 0x3b, 0xeae, 0xead, 0xe94, 0xe9a, 0xeb5, 0x20,
+0x31, 0x3b, 0xeae, 0xead, 0xe94, 0xe9a, 0xeb5, 0x20, 0x32, 0x3b, 0xe88, 0xeb8,
+0xea1, 0xeb2, 0xe94, 0xeb2, 0x20, 0x31, 0x3b, 0xe88, 0xeb8, 0xea1, 0xeb2, 0xe94,
+0xeb2, 0x20, 0x32, 0x3b, 0xeae, 0xeb2, 0xe88, 0xeb1, 0xe9a, 0x3b, 0xe8a, 0xeb0,
+0xe9a, 0xeb2, 0xe99, 0x3b, 0xeae, 0xeb2, 0xea1, 0xeb2, 0xe94, 0xead, 0xe99, 0x3b,
+0xec0, 0xe8a, 0xebb, 0xeb2, 0xea7, 0xeb1, 0xe94, 0x3b, 0xe94, 0xeb8, 0xead, 0xeb1,
+0xe94, 0xe81, 0xeb4, 0xe94, 0xeb0, 0x3b, 0xe94, 0xeb8, 0xead, 0xeb1, 0xe94, 0xe81,
+0xeb4, 0xe88, 0xeb0, 0xea1, 0xeb8, 0xeae, 0xeb1, 0xe94, 0x3b, 0xec0, 0xe84, 0xeb2,
+0xeb0, 0x3b, 0xeae, 0xead, 0xe81, 0xe9a, 0xeb5, 0x20, 0x31, 0x3b, 0xeae, 0xead,
+0xe81, 0xe9a, 0xeb5, 0x20, 0x32, 0x3b, 0xe99, 0xeb8, 0xea1, 0xeb2, 0x20, 0x31,
+0x3b, 0xe99, 0xeb8, 0xea1, 0xeb2, 0x20, 0x32, 0x3b, 0xec0, 0xeae, 0xeb2, 0xeb0,
+0x3b, 0xe8a, 0xeb2, 0x3b, 0xec0, 0xeae, 0xeb2, 0xeb0, 0xea1, 0xeb0, 0x3b, 0xec0,
+0xe8a, 0xebb, 0xeb2, 0x3b, 0xe8a, 0xeb8, 0xea5, 0xe81, 0xeb4, 0xead, 0xeb8, 0x3b,
+0xe8a, 0xeb8, 0xea5, 0xeab, 0xeb4, 0xe88, 0xea1, 0xeb8, 0xeae, 0xeb1, 0xe94, 0x3b,
+0xec0, 0xe84, 0xeb2, 0xeb0, 0x3b, 0xeae, 0xead, 0xe94, 0xe9a, 0xeb5, 0x20, 0x31,
+0x3b, 0xeae, 0xead, 0xe81, 0xe9a, 0xeb5, 0x20, 0x32, 0x3b, 0xe99, 0xeb8, 0xea1,
+0xeb2, 0x20, 0x31, 0x3b, 0xe99, 0xeb8, 0xea1, 0xeb2, 0x20, 0x32, 0x3b, 0xec0,
+0xeae, 0xeb2, 0xeb0, 0x3b, 0xe8a, 0xeb0, 0xead, 0xecc, 0x3b, 0xec0, 0xeae, 0xeb2,
+0xeb0, 0xea1, 0xeb0, 0x3b, 0xec0, 0xe8a, 0xebb, 0xeb2, 0x3b, 0xe8a, 0xeb8, 0xea5,
+0xe81, 0xeb4, 0xead, 0xeb8, 0x3b, 0xe8a, 0xeb8, 0xea5, 0xeab, 0xeb4, 0xe88, 0x6d,
+0x75, 0x68, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x3b, 0x73, 0x61, 0x66, 0x61,
+0x72, 0x73, 0x3b, 0x31, 0x2e, 0x20, 0x72, 0x61, 0x62, 0x12b, 0x3b, 0x32,
+0x2e, 0x20, 0x72, 0x61, 0x62, 0x12b, 0x3b, 0x31, 0x2e, 0x20, 0x64, 0x17e,
+0x75, 0x6d, 0x101, 0x64, 0x101, 0x3b, 0x32, 0x2e, 0x20, 0x64, 0x17e, 0x75,
+0x6d, 0x101, 0x64, 0x101, 0x3b, 0x72, 0x61, 0x64, 0x17e, 0x61, 0x62, 0x73,
+0x3b, 0x161, 0x61, 0x62, 0x61, 0x6e, 0x73, 0x3b, 0x72, 0x61, 0x6d, 0x61,
+0x64, 0x101, 0x6e, 0x73, 0x3b, 0x161, 0x61, 0x75, 0x76, 0x61, 0x6c, 0x73,
+0x3b, 0x64, 0x75, 0x20, 0x61, 0x6c, 0x2d, 0x6b, 0x69, 0x64, 0x101, 0x3b,
+0x64, 0x75, 0x20, 0x61, 0x6c, 0x2d, 0x68, 0x69, 0x64, 0x17e, 0x101, 0x43c,
+0x443, 0x445, 0x430, 0x440, 0x435, 0x43c, 0x3b, 0x441, 0x430, 0x444, 0x430, 0x440,
+0x3b, 0x440, 0x430, 0x431, 0x438, 0x20, 0x49, 0x3b, 0x440, 0x430, 0x431, 0x438,
+0x20, 0x49, 0x49, 0x3b, 0x45f, 0x443, 0x43c, 0x430, 0x434, 0x430, 0x20, 0x49,
+0x3b, 0x45f, 0x443, 0x43c, 0x430, 0x434, 0x430, 0x20, 0x49, 0x49, 0x3b, 0x440,
+0x430, 0x45f, 0x430, 0x431, 0x3b, 0x448, 0x430, 0x431, 0x430, 0x43d, 0x3b, 0x440,
+0x430, 0x43c, 0x430, 0x434, 0x430, 0x43d, 0x3b, 0x448, 0x430, 0x432, 0x430, 0x43b,
+0x3b, 0x434, 0x443, 0x43b, 0x43a, 0x438, 0x434, 0x430, 0x3b, 0x434, 0x443, 0x43b,
+0x445, 0x438, 0x45f, 0x430, 0x43c, 0x443, 0x445, 0x2e, 0x3b, 0x441, 0x430, 0x444,
+0x2e, 0x3b, 0x440, 0x430, 0x431, 0x2e, 0x20, 0x49, 0x3b, 0x440, 0x430, 0x431,
+0x2e, 0x20, 0x49, 0x49, 0x3b, 0x45f, 0x443, 0x43c, 0x2e, 0x20, 0x49, 0x3b,
+0x45f, 0x443, 0x43c, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x440, 0x430, 0x45f, 0x2e,
+0x3b, 0x448, 0x430, 0x431, 0x2e, 0x3b, 0x440, 0x430, 0x43c, 0x2e, 0x3b, 0x448,
+0x430, 0x432, 0x2e, 0x3b, 0x434, 0x443, 0x43b, 0x43a, 0x2e, 0x3b, 0x434, 0x443,
+0x43b, 0x445, 0x2e, 0xd2e, 0xd41, 0xd39, 0xd31, 0xd02, 0x3b, 0xd38, 0xd2b, 0xd7c,
+0x3b, 0xd31, 0xd2c, 0xd40, 0xd39, 0xd41, 0xd7d, 0x20, 0xd05, 0xd35, 0xd4d, 0xd35,
+0xd7d, 0x3b, 0xd31, 0xd2c, 0xd40, 0xd39, 0xd41, 0xd7d, 0x20, 0xd06, 0xd16, 0xd3f,
+0xd7c, 0x3b, 0xd1c, 0xd2e, 0xd3e, 0xd26, 0xd41, 0xd7d, 0x20, 0xd05, 0xd35, 0xd4d,
+0xd35, 0xd7d, 0x3b, 0xd1c, 0xd2e, 0xd3e, 0xd26, 0xd41, 0xd7d, 0x20, 0xd06, 0xd16,
+0xd3f, 0xd7c, 0x3b, 0xd31, 0xd1c, 0xd2c, 0xd4d, 0x3b, 0xd36, 0xd39, 0xd2c, 0xd3e,
+0xd7b, 0x3b, 0xd31, 0xd2e, 0xd26, 0xd3e, 0xd7b, 0x3b, 0xd36, 0xd35, 0xd4d, 0xd35,
+0xd3e, 0xd7d, 0x3b, 0xd26, 0xd41, 0xd7d, 0x20, 0xd16, 0xd39, 0xd26, 0xd4d, 0x3b,
+0xd26, 0xd41, 0xd7d, 0x20, 0xd39, 0xd3f, 0xd1c, 0xd4d, 0xd1c, 0xd2e, 0xd41, 0xd39,
+0xd31, 0xd02, 0x3b, 0xd38, 0xd2b, 0xd7c, 0x3b, 0xd31, 0xd2c, 0xd40, 0xd39, 0xd41,
+0xd7d, 0x20, 0xd05, 0xd35, 0xd4d, 0xd35, 0xd7d, 0x3b, 0xd31, 0xd2c, 0xd40, 0xd39,
+0xd41, 0xd7d, 0x20, 0xd06, 0xd16, 0xd3f, 0xd7c, 0x3b, 0xd1c, 0xd2e, 0xd3e, 0xd26,
+0xd41, 0xd7d, 0x20, 0xd05, 0xd35, 0xd4d, 0xd35, 0xd7d, 0x3b, 0xd1c, 0xd2e, 0xd3e,
+0xd26, 0xd41, 0xd7d, 0x20, 0xd06, 0xd16, 0xd3f, 0xd7c, 0x3b, 0xd31, 0xd1c, 0xd2c,
+0xd4d, 0x3b, 0xd36, 0xd39, 0xd2c, 0xd3e, 0xd7b, 0x3b, 0xd31, 0xd2e, 0xd33, 0xd3e,
+0xd7b, 0x3b, 0xd36, 0xd35, 0xd4d, 0xd35, 0xd3e, 0xd7d, 0x3b, 0xd26, 0xd41, 0xd7d,
+0x20, 0xd16, 0xd39, 0xd26, 0xd4d, 0x3b, 0xd26, 0xd41, 0xd7d, 0x20, 0xd39, 0xd3f,
+0xd1c, 0xd4d, 0xd1c, 0xd2e, 0xd41, 0xd39, 0x2e, 0x3b, 0xd38, 0xd2b, 0x2e, 0x3b,
+0xd31, 0xd2c, 0xd40, 0xd39, 0xd41, 0xd7d, 0x20, 0xd05, 0xd35, 0xd4d, 0xd35, 0x2e,
+0x3b, 0xd31, 0xd2c, 0xd40, 0xd39, 0xd41, 0xd7d, 0x20, 0xd06, 0xd16, 0xd3f, 0x2e,
+0x3b, 0xd1c, 0xd2e, 0xd3e, 0xd26, 0xd41, 0xd7d, 0x20, 0xd05, 0xd35, 0xd4d, 0xd35,
+0x2e, 0x3b, 0xd1c, 0xd2e, 0xd3e, 0xd26, 0xd41, 0xd7d, 0x20, 0xd06, 0xd16, 0xd3f,
+0x2e, 0x3b, 0xd31, 0xd1c, 0x2e, 0x3b, 0xd36, 0xd39, 0xd2c, 0xd3e, 0x2e, 0x3b,
+0xd31, 0xd2e, 0xd26, 0xd3e, 0x2e, 0x3b, 0xd36, 0xd35, 0xd4d, 0xd35, 0xd3e, 0x2e,
+0x3b, 0xd26, 0xd41, 0xd7d, 0x20, 0xd16, 0xd39, 0x2e, 0x3b, 0xd26, 0xd41, 0xd7d,
+0x20, 0xd39, 0xd3f, 0x2e, 0xd2e, 0xd41, 0x3b, 0xd38, 0x3b, 0xd31, 0x3b, 0xd31,
+0x3b, 0xd1c, 0x3b, 0xd1c, 0x3b, 0xd31, 0x3b, 0xd36, 0x3b, 0xd31, 0x3b, 0xd36,
+0x3b, 0xd26, 0xd41, 0x3b, 0xd26, 0xd41, 0x4d, 0x75, 0x68, 0x61, 0x72, 0x61,
+0x6d, 0x3b, 0x53, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x52, 0x61, 0x62, 0x69,
+0x75, 0x6c, 0x61, 0x77, 0x61, 0x6c, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x75,
+0x6c, 0x61, 0x6b, 0x68, 0x69, 0x72, 0x3b, 0x4a, 0x61, 0x6d, 0x61, 0x64,
+0x69, 0x6c, 0x61, 0x77, 0x61, 0x6c, 0x3b, 0x4a, 0x61, 0x6d, 0x61, 0x64,
+0x69, 0x6c, 0x61, 0x6b, 0x68, 0x69, 0x72, 0x3b, 0x52, 0x65, 0x6a, 0x61,
+0x62, 0x3b, 0x53, 0x79, 0x61, 0x61, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61,
+0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x53, 0x79, 0x61, 0x77, 0x61, 0x6c,
+0x3b, 0x5a, 0x75, 0x6c, 0x6b, 0x61, 0x65, 0x64, 0x61, 0x68, 0x3b, 0x5a,
+0x75, 0x6c, 0x68, 0x69, 0x6a, 0x61, 0x68, 0x4d, 0x75, 0x68, 0x2e, 0x3b,
+0x53, 0x61, 0x66, 0x2e, 0x3b, 0x52, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x3b,
+0x52, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x4a, 0x61, 0x6d, 0x2e,
+0x20, 0x49, 0x3b, 0x4a, 0x61, 0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x52,
+0x65, 0x6a, 0x2e, 0x3b, 0x53, 0x79, 0x61, 0x61, 0x2e, 0x3b, 0x52, 0x61,
+0x6d, 0x2e, 0x3b, 0x53, 0x79, 0x61, 0x77, 0x2e, 0x3b, 0x5a, 0x75, 0x6c,
+0x6b, 0x2e, 0x3b, 0x5a, 0x75, 0x6c, 0x68, 0x2e, 0x92e, 0x94b, 0x939, 0x930,
+0x92e, 0x3b, 0x938, 0x92b, 0x930, 0x3b, 0x930, 0x93e, 0x92c, 0x940, 0x20, 0x49,
+0x3b, 0x930, 0x93e, 0x92c, 0x940, 0x20, 0x49, 0x49, 0x3b, 0x91c, 0x941, 0x92e,
+0x93e, 0x926, 0x93e, 0x20, 0x49, 0x3b, 0x91c, 0x941, 0x92e, 0x93e, 0x926, 0x93e,
+0x20, 0x49, 0x49, 0x3b, 0x930, 0x91d, 0x93e, 0x92c, 0x3b, 0x936, 0x93e, 0x92c,
+0x93e, 0x928, 0x3b, 0x930, 0x92e, 0x91c, 0x93e, 0x928, 0x3b, 0x936, 0x935, 0x94d,
+0x935, 0x93e, 0x932, 0x3b, 0x927, 0x941, 0x932, 0x2d, 0x915, 0x940, 0x926, 0x93e,
+0x939, 0x3b, 0x927, 0x941, 0x932, 0x2d, 0x939, 0x93f, 0x91c, 0x93e, 0x939, 0x92e,
+0x94b, 0x939, 0x2e, 0x3b, 0x938, 0x92b, 0x2e, 0x3b, 0x930, 0x93e, 0x92c, 0x940,
+0x20, 0x49, 0x3b, 0x930, 0x93e, 0x92c, 0x940, 0x20, 0x49, 0x49, 0x3b, 0x91c,
+0x941, 0x92e, 0x93e, 0x2e, 0x20, 0x49, 0x3b, 0x91c, 0x941, 0x92e, 0x93e, 0x2e,
+0x20, 0x49, 0x49, 0x3b, 0x930, 0x91d, 0x93e, 0x2e, 0x3b, 0x936, 0x93e, 0x92c,
+0x93e, 0x2e, 0x3b, 0x930, 0x92e, 0x2e, 0x3b, 0x936, 0x935, 0x94d, 0x935, 0x93e,
+0x2e, 0x3b, 0x927, 0x941, 0x932, 0x2d, 0x915, 0x940, 0x2e, 0x3b, 0x927, 0x941,
+0x932, 0x2d, 0x939, 0x93f, 0x2e, 0x967, 0x3b, 0x968, 0x3b, 0x969, 0x3b, 0x96a,
+0x3b, 0x96b, 0x3b, 0x96c, 0x3b, 0x96d, 0x3b, 0x96e, 0x3b, 0x96f, 0x3b, 0x967,
+0x966, 0x3b, 0x967, 0x967, 0x3b, 0x967, 0x968, 0x6d, 0x75, 0x68, 0x61, 0x72,
+0x72, 0x61, 0x6d, 0x3b, 0x73, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x72, 0x61,
+0x62, 0x69, 0x2bb, 0x20, 0x49, 0x3b, 0x72, 0x61, 0x62, 0x69, 0x2bb, 0x20,
+0x49, 0x49, 0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x3b,
+0x6a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x49, 0x3b, 0x72, 0x61,
+0x6a, 0x61, 0x62, 0x3b, 0x73, 0x68, 0x61, 0x2bb, 0x62, 0x61, 0x6e, 0x3b,
+0x72, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x73, 0x68, 0x61, 0x77,
+0x77, 0x61, 0x6c, 0x3b, 0x64, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x71, 0x69,
+0x2bb, 0x64, 0x61, 0x68, 0x3b, 0x64, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x68,
+0x69, 0x6a, 0x6a, 0x61, 0x68, 0x6d, 0x75, 0x68, 0x2e, 0x3b, 0x73, 0x61,
+0x66, 0x2e, 0x3b, 0x72, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x3b, 0x72, 0x61,
+0x62, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x6a, 0x75, 0x6d, 0x2e, 0x20, 0x49,
+0x3b, 0x6a, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x72, 0x61, 0x6a,
+0x2e, 0x3b, 0x73, 0x68, 0x61, 0x2e, 0x3b, 0x72, 0x61, 0x6d, 0x2e, 0x3b,
+0x73, 0x68, 0x61, 0x77, 0x2e, 0x3b, 0x64, 0x68, 0x75, 0x2bb, 0x6c, 0x2d,
+0x71, 0x2e, 0x3b, 0x44, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x48, 0x2e, 0x6d,
+0x75, 0x68, 0x2e, 0x3b, 0x73, 0x61, 0x66, 0x2e, 0x3b, 0x72, 0x61, 0x62,
+0x2e, 0x20, 0x49, 0x3b, 0x72, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x49, 0x3b,
+0x6a, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x3b, 0x6a, 0x75, 0x6d, 0x2e, 0x20,
+0x49, 0x49, 0x3b, 0x72, 0x61, 0x6a, 0x2e, 0x3b, 0x73, 0x68, 0x61, 0x2e,
+0x3b, 0x72, 0x61, 0x6d, 0x2e, 0x3b, 0x73, 0x68, 0x61, 0x77, 0x2e, 0x3b,
+0x64, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x71, 0x2e, 0x3b, 0x64, 0x68, 0x75,
+0x2bb, 0x6c, 0x2d, 0x68, 0x2e, 0x645, 0x62d, 0x631, 0x645, 0x3b, 0x635, 0x641,
+0x631, 0x3b, 0x631, 0x628, 0x64a, 0x639, 0x3b, 0x631, 0x628, 0x64a, 0x639, 0x20,
+0x49, 0x49, 0x3b, 0x62c, 0x645, 0x627, 0x639, 0x647, 0x3b, 0x62c, 0x645, 0x627,
+0x639, 0x647, 0x20, 0x49, 0x49, 0x3b, 0x631, 0x62c, 0x628, 0x3b, 0x634, 0x639,
+0x628, 0x627, 0x646, 0x3b, 0x631, 0x645, 0x636, 0x627, 0x646, 0x3b, 0x634, 0x648,
+0x627, 0x644, 0x3b, 0x630, 0x64a, 0x20, 0x627, 0x644, 0x642, 0x639, 0x62f, 0x647,
+0x3b, 0x630, 0x64a, 0x20, 0x627, 0x644, 0x62d, 0x62c, 0x645, 0x62d, 0x631, 0x645,
+0x3b, 0x635, 0x641, 0x631, 0x3b, 0x631, 0x628, 0x64a, 0x639, 0x3b, 0x631, 0x628,
+0x64a, 0x639, 0x20, 0x49, 0x49, 0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x20, 0x6f1,
+0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x20, 0x6f2, 0x3b, 0x631, 0x62c, 0x628, 0x3b,
+0x634, 0x639, 0x628, 0x627, 0x646, 0x3b, 0x631, 0x645, 0x636, 0x627, 0x646, 0x3b,
+0x634, 0x648, 0x627, 0x644, 0x3b, 0x62f, 0x627, 0x644, 0x642, 0x627, 0x639, 0x62f,
+0x647, 0x3b, 0x630, 0x64a, 0x20, 0x627, 0x644, 0x62d, 0x62c, 0x645, 0x62d, 0x631,
+0x645, 0x3b, 0x62f, 0x20, 0x635, 0x641, 0x631, 0x6d2, 0x20, 0x62f, 0x3b, 0x631,
+0x628, 0x64a, 0x639, 0x3b, 0x631, 0x628, 0x64a, 0x639, 0x20, 0x49, 0x49, 0x3b,
+0x62c, 0x645, 0x627, 0x639, 0x647, 0x3b, 0x62c, 0x645, 0x627, 0x639, 0x647, 0x20,
+0x49, 0x49, 0x3b, 0x631, 0x62c, 0x628, 0x3b, 0x634, 0x639, 0x628, 0x627, 0x646,
+0x3b, 0x631, 0x645, 0x636, 0x627, 0x646, 0x3b, 0x634, 0x648, 0x627, 0x644, 0x3b,
+0x630, 0x64a, 0x20, 0x627, 0x644, 0x642, 0x639, 0x62f, 0x647, 0x3b, 0x630, 0x64a,
+0x20, 0x627, 0x644, 0x62d, 0x62c, 0x645, 0x62d, 0x631, 0x645, 0x3b, 0x635, 0x641,
+0x631, 0x3b, 0x631, 0x628, 0x6cc, 0x639, 0x200c, 0x627, 0x644, 0x627, 0x648, 0x644,
+0x3b, 0x631, 0x628, 0x6cc, 0x639, 0x200c, 0x627, 0x644, 0x62b, 0x627, 0x646, 0x6cc,
+0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x6cc, 0x200c, 0x627, 0x644, 0x627, 0x648, 0x644,
+0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x6cc, 0x200c, 0x627, 0x644, 0x62b, 0x627, 0x646,
+0x6cc, 0x3b, 0x631, 0x62c, 0x628, 0x3b, 0x634, 0x639, 0x628, 0x627, 0x646, 0x3b,
+0x631, 0x645, 0x636, 0x627, 0x646, 0x3b, 0x634, 0x648, 0x627, 0x644, 0x3b, 0x630,
+0x6cc, 0x642, 0x639, 0x62f, 0x647, 0x3b, 0x630, 0x6cc, 0x62d, 0x62c, 0x647, 0x645,
+0x3b, 0x635, 0x3b, 0x631, 0x3b, 0x631, 0x3b, 0x62c, 0x3b, 0x62c, 0x3b, 0x631,
+0x3b, 0x634, 0x3b, 0x631, 0x3b, 0x634, 0x3b, 0x630, 0x3b, 0x630, 0x4d, 0x75,
+0x68, 0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x53, 0x61, 0x66, 0x61, 0x72,
+0x3b, 0x52, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x3b, 0x52, 0x61, 0x62,
+0x69, 0x2bb, 0x20, 0x49, 0x49, 0x3b, 0x44, 0x17c, 0x75, 0x6d, 0x61, 0x64,
+0x61, 0x20, 0x49, 0x3b, 0x44, 0x17c, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20,
+0x49, 0x49, 0x3b, 0x52, 0x61, 0x64, 0x17c, 0x61, 0x62, 0x3b, 0x53, 0x7a,
+0x61, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e,
+0x3b, 0x53, 0x7a, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x5a, 0x75, 0x20,
+0x61, 0x6c, 0x2d, 0x6b, 0x61, 0x64, 0x61, 0x3b, 0x5a, 0x75, 0x20, 0x61,
+0x6c, 0x2d, 0x68, 0x69, 0x64, 0x17c, 0x64, 0x17c, 0x61, 0x4d, 0x75, 0x68,
+0x2e, 0x3b, 0x53, 0x61, 0x66, 0x2e, 0x3b, 0x52, 0x61, 0x62, 0x2e, 0x20,
+0x49, 0x3b, 0x52, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x44, 0x17c,
+0x75, 0x2e, 0x20, 0x49, 0x3b, 0x44, 0x17c, 0x75, 0x2e, 0x20, 0x49, 0x49,
+0x3b, 0x52, 0x61, 0x2e, 0x3b, 0x53, 0x7a, 0x61, 0x2e, 0x3b, 0x52, 0x61,
+0x6d, 0x2e, 0x3b, 0x53, 0x7a, 0x61, 0x77, 0x2e, 0x3b, 0x5a, 0x75, 0x20,
+0x61, 0x6c, 0x2d, 0x6b, 0x2e, 0x3b, 0x5a, 0x75, 0x20, 0x61, 0x6c, 0x2d,
+0x68, 0x2e, 0xa2e, 0xa41, 0xa39, 0xa71, 0xa30, 0xa2e, 0x3b, 0xa38, 0xa2b, 0xa30,
+0x3b, 0xa30, 0xa2c, 0xa40, 0x2bb, 0x20, 0x49, 0x3b, 0xa30, 0xa2c, 0xa40, 0x2bb,
+0x20, 0x49, 0x49, 0x3b, 0xa1c, 0xa41, 0xa2e, 0xa3e, 0xa26, 0xa3e, 0x20, 0x49,
+0x3b, 0xa1c, 0xa41, 0xa2e, 0xa3e, 0xa26, 0xa3e, 0x20, 0x49, 0x49, 0x3b, 0xa30,
+0xa1c, 0xa2c, 0x3b, 0xa38, 0xa3c, 0xa2c, 0xa3e, 0xa28, 0x3b, 0xa30, 0xa2e, 0xa1c,
+0xa3c, 0xa3e, 0xa28, 0x3b, 0xa38, 0xa3c, 0xa35, 0xa3e, 0xa32, 0x3b, 0xa26, 0xa42,
+0x2d, 0xa05, 0xa32, 0x2d, 0xa15, 0xa40, 0xa26, 0xa3e, 0xa39, 0x3b, 0xa26, 0xa42,
+0x2d, 0xa05, 0xa32, 0x2d, 0xa39, 0xa3f, 0xa1c, 0xa4d, 0xa39, 0xa3e, 0xa2e, 0xa41,
+0xa39, 0xa71, 0xa30, 0xa2e, 0x3b, 0xa38, 0xa2b, 0xa30, 0x3b, 0xa30, 0xa2c, 0xa40,
+0x20, 0x2bb, 0x20, 0x49, 0x3b, 0xa30, 0xa2c, 0xa40, 0x20, 0x2bb, 0x20, 0x49,
+0x49, 0x3b, 0xa1c, 0xa41, 0xa2e, 0xa3e, 0xa26, 0xa3e, 0x20, 0x49, 0x3b, 0xa1c,
+0xa41, 0xa2e, 0xa3e, 0xa26, 0xa3e, 0x20, 0x49, 0x49, 0x3b, 0xa30, 0xa1c, 0xa2c,
+0x3b, 0xa38, 0xa3c, 0xa2c, 0xa3e, 0xa28, 0x3b, 0xa30, 0xa2e, 0xa1c, 0xa3c, 0xa3e,
+0xa28, 0x3b, 0xa38, 0xa3c, 0xa35, 0xa3e, 0xa32, 0x3b, 0xa26, 0xa42, 0x2d, 0xa05,
+0xa32, 0x2d, 0xa15, 0xa40, 0xa26, 0xa3e, 0xa39, 0x3b, 0xa26, 0xa42, 0x2d, 0xa05,
+0xa32, 0x2d, 0xa39, 0xa3f, 0xa1c, 0xa4d, 0xa39, 0xa3e, 0xa2e, 0xa41, 0xa39, 0xa71,
+0x2e, 0x3b, 0xa38, 0xa2b, 0x2e, 0x3b, 0xa30, 0xa2c, 0x2e, 0x20, 0x49, 0x3b,
+0xa30, 0xa2c, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0xa1c, 0xa41, 0xa2e, 0x2e, 0x20,
+0x49, 0x3b, 0xa1c, 0xa41, 0xa2e, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0xa30, 0xa3e,
+0xa1c, 0x2e, 0x3b, 0xa38, 0xa3c, 0xa3e, 0x2e, 0x3b, 0xa30, 0xa3e, 0xa2e, 0x2e,
+0x3b, 0xa38, 0xa3c, 0xa05, 0x2e, 0x3b, 0xa26, 0xa42, 0x2d, 0xa05, 0xa32, 0x2d,
+0xa15, 0xa40, 0x2e, 0x3b, 0xa26, 0xa42, 0x2d, 0xa05, 0xa32, 0x2d, 0xa39, 0xa3f,
+0x2e, 0x43c, 0x443, 0x445, 0x430, 0x440, 0x440, 0x430, 0x43c, 0x3b, 0x441, 0x430,
+0x444, 0x430, 0x440, 0x3b, 0x440, 0x430, 0x431, 0x438, 0x2d, 0x443, 0x43b, 0x44c,
+0x2d, 0x430, 0x432, 0x432, 0x430, 0x43b, 0x44c, 0x3b, 0x440, 0x430, 0x431, 0x438,
+0x2d, 0x443, 0x43b, 0x44c, 0x2d, 0x430, 0x445, 0x438, 0x440, 0x3b, 0x434, 0x436,
+0x443, 0x43c, 0x430, 0x434, 0x2d, 0x443, 0x43b, 0x44c, 0x2d, 0x430, 0x432, 0x432,
+0x430, 0x43b, 0x44c, 0x3b, 0x434, 0x436, 0x443, 0x43c, 0x430, 0x434, 0x2d, 0x443,
+0x43b, 0x44c, 0x2d, 0x430, 0x445, 0x438, 0x440, 0x3b, 0x440, 0x430, 0x434, 0x436,
+0x430, 0x431, 0x3b, 0x448, 0x430, 0x430, 0x431, 0x430, 0x43d, 0x3b, 0x440, 0x430,
+0x43c, 0x430, 0x434, 0x430, 0x43d, 0x3b, 0x448, 0x430, 0x432, 0x432, 0x430, 0x43b,
+0x44c, 0x3b, 0x437, 0x443, 0x43b, 0x44c, 0x2d, 0x43a, 0x430, 0x430, 0x434, 0x430,
+0x3b, 0x437, 0x443, 0x43b, 0x44c, 0x2d, 0x445, 0x438, 0x434, 0x436, 0x436, 0x430,
+0x43c, 0x443, 0x445, 0x2e, 0x3b, 0x441, 0x430, 0x444, 0x2e, 0x3b, 0x440, 0x430,
+0x431, 0x2e, 0x20, 0x49, 0x3b, 0x440, 0x430, 0x431, 0x2e, 0x20, 0x49, 0x49,
+0x3b, 0x434, 0x436, 0x443, 0x43c, 0x2e, 0x20, 0x49, 0x3b, 0x434, 0x436, 0x443,
+0x43c, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x440, 0x430, 0x434, 0x436, 0x2e, 0x3b,
+0x448, 0x430, 0x430, 0x431, 0x2e, 0x3b, 0x440, 0x430, 0x43c, 0x2e, 0x3b, 0x448,
+0x430, 0x432, 0x2e, 0x3b, 0x437, 0x443, 0x43b, 0x44c, 0x2d, 0x43a, 0x2e, 0x3b,
+0x437, 0x443, 0x43b, 0x44c, 0x2d, 0x445, 0x2e, 0x6d, 0x75, 0x68, 0x61, 0x72,
+0x72, 0x61, 0x6d, 0x3b, 0x73, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x72, 0x61,
+0x62, 0x69, 0x2bb, 0x20, 0x49, 0x3b, 0x72, 0x61, 0x62, 0x69, 0x2bb, 0x20,
+0x49, 0x49, 0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x3b,
+0x6a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x49, 0x3b, 0x72, 0x61,
+0x6a, 0x61, 0x62, 0x3b, 0x73, 0x68, 0x61, 0x62, 0x61, 0x6e, 0x3b, 0x72,
+0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x73, 0x68, 0x61, 0x77, 0x77,
+0x61, 0x6c, 0x3b, 0x64, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x71, 0x69, 0x2bb,
+0x64, 0x61, 0x68, 0x3b, 0x64, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x68, 0x69,
+0x6a, 0x6a, 0x61, 0x68, 0x41c, 0x443, 0x445, 0x430, 0x440, 0x435, 0x43c, 0x3b,
+0x421, 0x430, 0x444, 0x430, 0x440, 0x3b, 0x420, 0x430, 0x431, 0x438, 0x2bb, 0x20,
+0x49, 0x3b, 0x420, 0x430, 0x431, 0x438, 0x2bb, 0x20, 0x49, 0x49, 0x3b, 0x408,
+0x443, 0x43c, 0x430, 0x434, 0x430, 0x20, 0x49, 0x3b, 0x408, 0x443, 0x43c, 0x430,
+0x434, 0x430, 0x20, 0x49, 0x49, 0x3b, 0x420, 0x430, 0x452, 0x430, 0x431, 0x3b,
+0x428, 0x430, 0x2bb, 0x431, 0x430, 0x43d, 0x3b, 0x420, 0x430, 0x43c, 0x430, 0x434,
+0x430, 0x43d, 0x3b, 0x428, 0x430, 0x432, 0x430, 0x43b, 0x3b, 0x414, 0x443, 0x2bb,
+0x43b, 0x2d, 0x41a, 0x438, 0x2bb, 0x434, 0x430, 0x3b, 0x414, 0x443, 0x2bb, 0x43b,
+0x2d, 0x445, 0x438, 0x452, 0x430, 0x4d, 0x75, 0x68, 0x61, 0x72, 0x65, 0x6d,
+0x3b, 0x53, 0x61, 0x66, 0x65, 0x72, 0x3b, 0x52, 0x65, 0x62, 0x69, 0x20,
+0x31, 0x3b, 0x52, 0x65, 0x62, 0x69, 0x20, 0x32, 0x3b, 0x44, 0x17e, 0x75,
+0x6d, 0x61, 0x64, 0x65, 0x20, 0x31, 0x3b, 0x44, 0x17e, 0x75, 0x6d, 0x61,
+0x64, 0x65, 0x20, 0x32, 0x3b, 0x52, 0x65, 0x64, 0x17e, 0x65, 0x62, 0x3b,
+0x160, 0x61, 0x2bb, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x7a,
+0x61, 0x6e, 0x3b, 0x160, 0x65, 0x76, 0x61, 0x6c, 0x3b, 0x5a, 0x75, 0x6c,
+0x2d, 0x6b, 0x61, 0x64, 0x65, 0x3b, 0x5a, 0x75, 0x6c, 0x2d, 0x68, 0x69,
+0x64, 0x17e, 0x65, 0x4d, 0x75, 0x68, 0x61, 0x72, 0x65, 0x6d, 0x3b, 0x53,
+0x61, 0x66, 0x61, 0x72, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49,
+0x3b, 0x52, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x49, 0x3b, 0x4a, 0x75,
+0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x64,
+0x61, 0x20, 0x49, 0x49, 0x3b, 0x52, 0x61, 0x111, 0x61, 0x62, 0x3b, 0x160,
+0x61, 0x2bb, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64, 0x61,
+0x6e, 0x3b, 0x160, 0x61, 0x76, 0x61, 0x6c, 0x3b, 0x44, 0x75, 0x2bb, 0x6c,
+0x2d, 0x4b, 0x69, 0x2bb, 0x64, 0x61, 0x3b, 0x44, 0x75, 0x2bb, 0x6c, 0x2d,
+0x68, 0x69, 0x111, 0x61, 0x4d, 0x75, 0x68, 0x2e, 0x3b, 0x53, 0x61, 0x66,
+0x2e, 0x3b, 0x52, 0x65, 0x62, 0x2e, 0x20, 0x31, 0x3b, 0x52, 0x65, 0x62,
+0x2e, 0x20, 0x32, 0x3b, 0x44, 0x17e, 0x75, 0x6d, 0x2e, 0x20, 0x31, 0x3b,
+0x44, 0x17e, 0x75, 0x6d, 0x2e, 0x20, 0x32, 0x3b, 0x52, 0x65, 0x64, 0x17e,
+0x2e, 0x3b, 0x160, 0x61, 0x2e, 0x3b, 0x52, 0x61, 0x6d, 0x2e, 0x3b, 0x160,
+0x65, 0x2e, 0x3b, 0x5a, 0x75, 0x6c, 0x2d, 0x6b, 0x2e, 0x3b, 0x5a, 0x75,
+0x6c, 0x2d, 0x68, 0x2e, 0x645, 0x62d, 0x631, 0x645, 0x3b, 0x635, 0x641, 0x631,
+0x3b, 0x631, 0x628, 0x64a, 0x639, 0x20, 0x627, 0x644, 0x627, 0x648, 0x644, 0x3b,
+0x631, 0x628, 0x6cc, 0x639, 0x20, 0x627, 0x644, 0x627, 0x62e, 0x631, 0x3b, 0x62c,
+0x645, 0x627, 0x62f, 0x6cc, 0x20, 0x627, 0x644, 0x627, 0x648, 0x644, 0x3b, 0x62c,
+0x645, 0x627, 0x62f, 0x64a, 0x20, 0x627, 0x644, 0x627, 0x62e, 0x631, 0x3b, 0x631,
+0x62c, 0x628, 0x3b, 0x634, 0x639, 0x628, 0x627, 0x646, 0x3b, 0x631, 0x645, 0x636,
+0x627, 0x646, 0x3b, 0x634, 0x648, 0x627, 0x644, 0x3b, 0x630, 0x648, 0x627, 0x644,
+0x642, 0x639, 0x62f, 0x3b, 0x630, 0x648, 0x627, 0x644, 0x62d, 0x62c, 0x6c1, 0x61,
+0x6c, 0x2d, 0x6d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x73,
+0x61, 0x66, 0x61, 0x72, 0x3b, 0x72, 0x61, 0x62, 0xed, 0xb4, 0x20, 0x61,
+0x6c, 0x2d, 0x61, 0x76, 0x76, 0x61, 0x6c, 0x3b, 0x72, 0x61, 0x62, 0xed,
+0xb4, 0x61, 0x74, 0x68, 0x2d, 0x74, 0x68, 0xe1, 0x6e, 0xed, 0x3b, 0x64,
+0x17e, 0x75, 0x6d, 0xe1, 0x64, 0xe1, 0x20, 0x6c, 0x2d, 0xfa, 0x6c, 0xe1,
+0x3b, 0x64, 0x17e, 0x75, 0x6d, 0xe1, 0x64, 0xe1, 0x20, 0x6c, 0x2d, 0xe1,
+0x63, 0x68, 0x69, 0x72, 0x61, 0x3b, 0x72, 0x61, 0x64, 0x17e, 0x61, 0x62,
+0x3b, 0x161, 0x61, 0xb4, 0x20, 0x62, 0xe1, 0x6e, 0x3b, 0x72, 0x61, 0x6d,
+0x61, 0x64, 0xe1, 0x6e, 0x3b, 0x161, 0x61, 0x75, 0x76, 0xe1, 0x6c, 0x3b,
+0x64, 0x68, 0xfa, 0x20, 0x6c, 0x2d, 0x6b, 0x61, 0xb4, 0x20, 0x64, 0x61,
+0x3b, 0x64, 0x68, 0xfa, 0x20, 0x6c, 0x2d, 0x68, 0x69, 0x64, 0x17e, 0x64,
+0x17e, 0x61, 0x6d, 0x75, 0x68, 0x2e, 0x3b, 0x73, 0x61, 0x66, 0x2e, 0x3b,
+0x72, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x3b, 0x72, 0x61, 0x62, 0x2e, 0x20,
+0x49, 0x49, 0x3b, 0x64, 0x17e, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x3b, 0x64,
+0x17e, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x72, 0x61, 0x64, 0x2e,
+0x3b, 0x161, 0x61, 0x2e, 0x3b, 0x72, 0x61, 0x6d, 0x2e, 0x3b, 0x161, 0x61,
+0x75, 0x2e, 0x3b, 0x64, 0x68, 0xfa, 0x20, 0x6c, 0x2d, 0x6b, 0x2e, 0x3b,
+0x64, 0x68, 0xfa, 0x20, 0x6c, 0x2d, 0x68, 0x2e, 0x4d, 0x75, 0x78, 0x61,
+0x72, 0x72, 0x61, 0x6d, 0x3b, 0x53, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x52,
+0x61, 0x62, 0x69, 0x63, 0x20, 0x61, 0x6c, 0x2d, 0x61, 0x77, 0x77, 0x61,
+0x6c, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x63, 0x20, 0x61, 0x6c, 0x2d, 0x74,
+0x68, 0x61, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20,
+0x61, 0x6c, 0x2d, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x6a, 0x75, 0x6d,
+0x61, 0x64, 0x61, 0x20, 0x61, 0x6c, 0x2d, 0x74, 0x68, 0x61, 0x6e, 0x69,
+0x3b, 0x52, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x53, 0x68, 0x61, 0x63, 0x62,
+0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x53,
+0x68, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x44, 0x75, 0x6c, 0x20, 0x61,
+0x6c, 0x2d, 0x71, 0x61, 0x63, 0x64, 0x61, 0x68, 0x3b, 0x44, 0x75, 0x6c,
+0x20, 0x78, 0x69, 0x6a, 0x6a, 0x61, 0x68, 0x4d, 0x75, 0x78, 0x61, 0x72,
+0x72, 0x61, 0x6d, 0x3b, 0x53, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x52, 0x61,
+0x62, 0x69, 0x63, 0x20, 0x61, 0x6c, 0x2d, 0x61, 0x77, 0x77, 0x61, 0x6c,
+0x3b, 0x52, 0x61, 0x62, 0x69, 0x63, 0x20, 0x61, 0x6c, 0x2d, 0x74, 0x68,
+0x61, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x61,
+0x6c, 0x2d, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x6a, 0x75, 0x6d, 0x61,
+0x64, 0x61, 0x20, 0x61, 0x6c, 0x2d, 0x74, 0x68, 0x61, 0x6e, 0x69, 0x3b,
+0x52, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x53, 0x68, 0x61, 0x63, 0x62, 0x61,
+0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x53, 0x68,
+0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x44, 0x75, 0x6c, 0x20, 0x61, 0x6c,
+0x2d, 0x71, 0x61, 0x63, 0x64, 0x61, 0x3b, 0x44, 0x75, 0x6c, 0x20, 0x78,
+0x69, 0x6a, 0x6a, 0x61, 0x68, 0x4d, 0x75, 0x78, 0x2e, 0x3b, 0x53, 0x61,
+0x66, 0x2e, 0x3b, 0x52, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x3b, 0x52, 0x61,
+0x62, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x4a, 0x75, 0x6d, 0x2e, 0x20, 0x49,
+0x3b, 0x4a, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x52, 0x61, 0x6a,
+0x2e, 0x3b, 0x53, 0x68, 0x61, 0x2e, 0x3b, 0x52, 0x61, 0x6d, 0x2e, 0x3b,
+0x53, 0x68, 0x61, 0x77, 0x2e, 0x3b, 0x44, 0x75, 0x6c, 0x2d, 0x51, 0x2e,
+0x3b, 0x44, 0x75, 0x6c, 0x2d, 0x58, 0x2e, 0x4d, 0x75, 0x78, 0x2e, 0x3b,
+0x53, 0x61, 0x66, 0x2e, 0x3b, 0x52, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x3b,
+0x52, 0x61, 0x62, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x4a, 0x75, 0x6d, 0x2e,
+0x20, 0x49, 0x3b, 0x4a, 0x75, 0x6d, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x52,
+0x61, 0x6a, 0x2e, 0x3b, 0x53, 0x68, 0x61, 0x2e, 0x3b, 0x52, 0x61, 0x6d,
+0x2e, 0x3b, 0x53, 0x68, 0x61, 0x77, 0x2e, 0x3b, 0x44, 0x75, 0x6c, 0x2019,
+0x2d, 0x51, 0x69, 0x63, 0x64, 0x61, 0x2e, 0x3b, 0x44, 0x68, 0x75, 0x2bb,
+0x6c, 0x2d, 0x48, 0x2e, 0x6d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x61, 0x6d,
+0x3b, 0x73, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x72, 0x61, 0x62, 0x69, 0x2bb,
+0x20, 0x49, 0x3b, 0x72, 0x61, 0x62, 0x69, 0x2bb, 0x20, 0x49, 0x49, 0x3b,
+0x6a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x20, 0x49, 0x3b, 0x6a, 0x75, 0x6d,
+0x61, 0x64, 0x61, 0x20, 0x49, 0x49, 0x3b, 0x72, 0x61, 0x6a, 0x61, 0x62,
+0x3b, 0x73, 0x68, 0x61, 0x2bb, 0x62, 0x61, 0x6e, 0x3b, 0x72, 0x61, 0x6d,
+0x61, 0x64, 0xe1, 0x6e, 0x3b, 0x73, 0x68, 0x61, 0x77, 0x77, 0x61, 0x6c,
+0x3b, 0x64, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x71, 0x69, 0x2bb, 0x64, 0x61,
+0x68, 0x3b, 0x64, 0x68, 0x75, 0x2bb, 0x6c, 0x2d, 0x68, 0x69, 0x6a, 0x6a,
+0x61, 0x68, 0x4d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x53,
+0x61, 0x66, 0x61, 0x72, 0x3b, 0x52, 0x61, 0x62, 0x69, 0x2019, 0x20, 0x61,
+0x6c, 0x2d, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x52, 0x61, 0x62, 0x69,
+0x2019, 0x20, 0x61, 0x6c, 0x2d, 0x61, 0x6b, 0x68, 0x69, 0x72, 0x3b, 0x4a,
+0x75, 0x6d, 0x61, 0x64, 0x61, 0x2d, 0x6c, 0x2d, 0x75, 0x6c, 0x61, 0x3b,
+0x4a, 0x75, 0x6d, 0x61, 0x64, 0x61, 0x2d, 0x6c, 0x2d, 0x61, 0x6b, 0x68,
+0x69, 0x72, 0x61, 0x3b, 0x52, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x53, 0x68,
+0x61, 0x2019, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x64, 0x61,
+0x6e, 0x3b, 0x53, 0x68, 0x61, 0x77, 0x77, 0x61, 0x6c, 0x3b, 0x44, 0x68,
+0x75, 0x2d, 0x6c, 0x2d, 0x67, 0x61, 0x2019, 0x64, 0x61, 0x3b, 0x44, 0x68,
+0x75, 0x2d, 0x6c, 0x2d, 0x68, 0x69, 0x6a, 0x6a, 0x61, 0x6d, 0x75, 0x68,
+0x61, 0x72, 0x72, 0x61, 0x6d, 0x3b, 0x73, 0x61, 0x66, 0x61, 0x72, 0x3b,
+0x72, 0x61, 0x62, 0x69, 0x2019, 0x20, 0x61, 0x6c, 0x2d, 0x61, 0x77, 0x77,
+0x61, 0x6c, 0x3b, 0x72, 0x61, 0x62, 0x69, 0x2019, 0x20, 0x61, 0x6c, 0x2d,
+0x61, 0x6b, 0x68, 0x69, 0x72, 0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x64, 0x61,
+0x2d, 0x6c, 0x2d, 0x75, 0x6c, 0x61, 0x3b, 0x6a, 0x75, 0x6d, 0x61, 0x64,
+0x61, 0x2d, 0x6c, 0x2d, 0x61, 0x6b, 0x68, 0x69, 0x72, 0x61, 0x3b, 0x72,
+0x61, 0x6a, 0x61, 0x62, 0x3b, 0x73, 0x68, 0x61, 0x2019, 0x62, 0x61, 0x6e,
+0x3b, 0x72, 0x61, 0x6d, 0x61, 0x64, 0x61, 0x6e, 0x3b, 0x73, 0x68, 0x61,
+0x77, 0x77, 0x61, 0x6c, 0x3b, 0x64, 0x68, 0x75, 0x2d, 0x6c, 0x2d, 0x67,
+0x61, 0x2019, 0x64, 0x61, 0x3b, 0x64, 0x68, 0x75, 0x2d, 0x6c, 0x2d, 0x68,
+0x69, 0x6a, 0x6a, 0x61, 0x43c, 0x443, 0x4b3, 0x430, 0x440, 0x440, 0x430, 0x43c,
+0x3b, 0x441, 0x430, 0x444, 0x430, 0x440, 0x3b, 0x420, 0x430, 0x431, 0x435, 0x44a,
+0x20, 0x49, 0x3b, 0x420, 0x430, 0x431, 0x435, 0x44a, 0x20, 0x49, 0x49, 0x3b,
+0x4b7, 0x438, 0x43c, 0x43e, 0x434, 0x438, 0x2d, 0x443, 0x43b, 0x2d, 0x443, 0x43b,
+0x43e, 0x3b, 0x4b7, 0x438, 0x43c, 0x43e, 0x434, 0x438, 0x2d, 0x443, 0x43b, 0x2d,
+0x441, 0x43e, 0x43d, 0x438, 0x3b, 0x440, 0x430, 0x4b7, 0x430, 0x431, 0x3b, 0x428,
+0x430, 0x431, 0x430, 0x43d, 0x3b, 0x420, 0x430, 0x43c, 0x430, 0x434, 0x430, 0x43d,
+0x3b, 0x428, 0x430, 0x432, 0x432, 0x430, 0x43b, 0x3b, 0x414, 0x445, 0x443, 0x43b,
+0x2d, 0x49a, 0x438, 0x434, 0x430, 0x4b3, 0x3b, 0x414, 0x445, 0x443, 0x43b, 0x2d,
+0x4b2, 0x438, 0x4b7, 0x4b7, 0x430, 0x4b3, 0x43c, 0x443, 0x4b3, 0x430, 0x440, 0x440,
+0x430, 0x43c, 0x3b, 0x441, 0x430, 0x444, 0x430, 0x440, 0x3b, 0x420, 0x430, 0x431,
+0x435, 0x44a, 0x20, 0x49, 0x3b, 0x420, 0x430, 0x431, 0x435, 0x44a, 0x20, 0x49,
+0x49, 0x3b, 0x4b7, 0x438, 0x43c, 0x43e, 0x434, 0x438, 0x2d, 0x443, 0x43b, 0x2d,
+0x443, 0x43b, 0x43e, 0x3b, 0x4b7, 0x438, 0x43c, 0x43e, 0x434, 0x438, 0x2d, 0x443,
+0x43b, 0x2d, 0x441, 0x43e, 0x43d, 0x438, 0x3b, 0x440, 0x430, 0x4b7, 0x430, 0x431,
+0x3b, 0x428, 0x430, 0x431, 0x430, 0x43d, 0x3b, 0x420, 0x430, 0x43c, 0x430, 0x434,
+0x430, 0x43d, 0x3b, 0x428, 0x430, 0x432, 0x432, 0x430, 0x43b, 0x3b, 0x414, 0x445,
+0x443, 0x442, 0x2d, 0x49a, 0x438, 0x434, 0x430, 0x4b3, 0x3b, 0x414, 0x445, 0x443,
+0x442, 0x2d, 0x4b2, 0x438, 0x4b7, 0x4b7, 0x430, 0x4b3, 0x41c, 0x443, 0x4b3, 0x2e,
+0x3b, 0x421, 0x430, 0x444, 0x2e, 0x3b, 0x420, 0x430, 0x431, 0x2e, 0x20, 0x49,
+0x3b, 0x420, 0x430, 0x431, 0x2e, 0x20, 0x49, 0x49, 0x3b, 0x4b6, 0x443, 0x43c,
+0x2e, 0x20, 0x49, 0x3b, 0x4b6, 0x443, 0x43c, 0x2e, 0x20, 0x49, 0x49, 0x3b,
+0x420, 0x430, 0x4b7, 0x2e, 0x3b, 0x428, 0x430, 0x2e, 0x3b, 0x420, 0x430, 0x43c,
+0x2e, 0x3b, 0x428, 0x430, 0x432, 0x2e, 0x3b, 0x414, 0x445, 0x443, 0x43b, 0x2d,
+0x49a, 0x2e, 0x3b, 0x414, 0x445, 0x443, 0x43b, 0x2d, 0x4b2, 0x2e, 0xbae, 0xbc1,
+0xbb9, 0xbb0, 0xbcd, 0xbb0, 0xbae, 0xbcd, 0x3b, 0xb9a, 0xb83, 0xbaa, 0xbb0, 0xbcd,
+0x3b, 0xbb0, 0xbaa, 0xbbf, 0x20, 0x31, 0x3b, 0xbb0, 0xbaa, 0xbbf, 0x20, 0x32,
+0x3b, 0xb9c, 0xbc1, 0xbae, 0xba4, 0xbbe, 0x20, 0x31, 0x3b, 0xb9c, 0xbc1, 0xbae,
+0xba4, 0xbbe, 0x20, 0x32, 0x3b, 0xbb0, 0xb9c, 0xbaa, 0xbcd, 0x3b, 0xbb7, 0xb83,
+0xbaa, 0xbbe, 0xba9, 0xbcd, 0x3b, 0xbb0, 0xbae, 0xbb2, 0xbbe, 0xba9, 0xbcd, 0x3b,
+0xbb7, 0xbb5, 0xbcd, 0xbb5, 0xbbe, 0xbb2, 0xbcd, 0x3b, 0xba4, 0xbc1, 0xbb2, 0xbcd,
+0x20, 0xb95, 0xb83, 0xba4, 0xbbe, 0x3b, 0xba4, 0xbc1, 0xbb2, 0xbcd, 0x20, 0xbb9,
+0xbbf, 0xb9c, 0xbcd, 0xb9c, 0xbbe, 0xbae, 0xbc1, 0xbb9, 0x2e, 0x3b, 0xb9a, 0xb83,
+0xbaa, 0x2e, 0x3b, 0xbb0, 0xbaa, 0xbbf, 0x20, 0x31, 0x3b, 0xbb0, 0xbaa, 0xbbf,
+0x20, 0x32, 0x3b, 0xb9c, 0xbc1, 0xbae, 0x2e, 0x20, 0x31, 0x3b, 0xb9c, 0xbc1,
+0xbae, 0x2e, 0x20, 0x32, 0x3b, 0xbb0, 0xb9c, 0x2e, 0x3b, 0xbb7, 0xb83, 0x2e,
+0x3b, 0xbb0, 0xbae, 0x2e, 0x3b, 0xbb7, 0xbb5, 0xbcd, 0x2e, 0x3b, 0xba4, 0xbc1,
+0xbb2, 0xbcd, 0x20, 0xb95, 0xb83, 0x2e, 0x3b, 0xba4, 0xbc1, 0xbb2, 0xbcd, 0x20,
+0xbb9, 0xbbf, 0xb9c, 0xbcd, 0x2e, 0xc2e, 0xc41, 0xc39, 0xc30, 0xc4d, 0xc30, 0xc02,
+0x3b, 0xc38, 0xc2b, 0xc30, 0xc4d, 0x3b, 0xc30, 0xc2c, 0xc40, 0x20, 0x49, 0x3b,
+0xc30, 0xc2c, 0xc40, 0x20, 0x49, 0x49, 0x3b, 0xc1c, 0xc41, 0xc2e, 0xc26, 0xc3e,
+0x20, 0x49, 0x3b, 0xc1c, 0xc41, 0xc2e, 0xc26, 0xc3e, 0x20, 0x49, 0x49, 0x3b,
+0xc30, 0xc1c, 0xc2c, 0xc4d, 0x3b, 0xc37, 0xc2c, 0xc3e, 0xc28, 0xc4d, 0x3b, 0xc30,
+0xc02, 0xc1c, 0xc3e, 0xc28, 0xc4d, 0x3b, 0xc37, 0xc35, 0xc4d, 0xc35, 0xc3e, 0xc32,
+0xc4d, 0x3b, 0xc27, 0xc41, 0xc32, 0xc4d, 0x2d, 0xc15, 0xc3f, 0x20, 0xc26, 0xc3e,
+0xc39, 0xc4d, 0x3b, 0xc27, 0xc41, 0xc32, 0xc4d, 0x2d, 0xc39, 0xc3f, 0xc1c, 0xc4d,
+0xc1c, 0xc3e, 0xc39, 0xc4d, 0xc2e, 0xc41, 0xc39, 0x2e, 0x3b, 0xc38, 0xc2b, 0x2e,
+0x3b, 0xc30, 0x2e, 0x20, 0x49, 0x3b, 0xc30, 0x2e, 0x20, 0x49, 0x49, 0x3b,
+0xc1c, 0xc41, 0xc2e, 0x2e, 0x20, 0x49, 0x3b, 0xc1c, 0xc41, 0xc2e, 0x2e, 0x20,
+0x49, 0x49, 0x3b, 0xc30, 0xc1c, 0x2e, 0x3b, 0xc37, 0xc2c, 0xc3e, 0x2e, 0x3b,
+0xc30, 0xc02, 0xc1c, 0xc3e, 0x2e, 0x3b, 0xc37, 0xc35, 0xc4d, 0xc35, 0xc3e, 0x2e,
+0x3b, 0xc27, 0xc41, 0xc32, 0xc4d, 0x2d, 0xc15, 0xc3f, 0x2e, 0x3b, 0xc27, 0xc41,
+0xc32, 0xc4d, 0x2d, 0xc39, 0xc3f, 0x2e, 0xe21, 0xe38, 0xe2e, 0xe30, 0xe23, 0xe4c,
+0xe23, 0xe2d, 0xe21, 0x3b, 0xe0b, 0xe2d, 0xe1f, 0xe32, 0xe23, 0xe4c, 0x3b, 0xe23,
+0xe2d, 0xe1a, 0xe35, 0x20, 0x49, 0x3b, 0xe23, 0xe2d, 0xe1a, 0xe35, 0x20, 0x49,
+0x49, 0x3b, 0xe08, 0xe38, 0xe21, 0xe32, 0xe14, 0xe32, 0x20, 0x49, 0x3b, 0xe08,
+0xe38, 0xe21, 0xe32, 0xe14, 0xe32, 0x20, 0x49, 0x49, 0x3b, 0xe23, 0xe2d, 0xe08,
+0xe31, 0xe1a, 0x3b, 0xe0a, 0xe30, 0xe2d, 0xe30, 0xe1a, 0xe32, 0xe19, 0x3b, 0xe23,
+0xe2d, 0xe21, 0xe30, 0xe14, 0xe2d, 0xe19, 0x3b, 0xe40, 0xe0a, 0xe32, 0xe27, 0xe31,
+0xe25, 0x3b, 0xe0b, 0xe38, 0xe25, 0xe01, 0xe34, 0xe2d, 0xe3a, 0xe14, 0xe30, 0xe2e,
+0xe3a, 0x3b, 0xe0b, 0xe38, 0xe25, 0xe2b, 0xe34, 0xe08, 0xe0d, 0xe30, 0xe2e, 0xe3a,
+0xe21, 0xe38, 0xe2e, 0xe31, 0xe23, 0x2e, 0x3b, 0xe40, 0xe28, 0xe32, 0xe30, 0x2e,
+0x3b, 0xe23, 0xe2d, 0xe1a, 0xe35, 0x20, 0x49, 0x3b, 0xe23, 0xe2d, 0xe1a, 0xe35,
+0x20, 0x49, 0x49, 0x3b, 0xe08, 0xe38, 0xe21, 0xe32, 0xe14, 0xe32, 0x20, 0x49,
+0x3b, 0xe08, 0xe38, 0xe21, 0xe32, 0xe14, 0xe32, 0x20, 0x49, 0x49, 0x3b, 0xe40,
+0xe23, 0xe32, 0xe30, 0x2e, 0x3b, 0xe0a, 0xe30, 0xe2d, 0xe4c, 0x2e, 0x3b, 0xe40,
+0xe23, 0xe32, 0xe30, 0xe21, 0xe30, 0x2e, 0x3b, 0xe40, 0xe0a, 0xe32, 0xe27, 0x2e,
+0x3b, 0xe0b, 0xe38, 0xe25, 0xe01, 0xe34, 0xe2d, 0xe3a, 0x2e, 0x3b, 0xe0b, 0xe38,
+0xe25, 0xe2b, 0xe34, 0xe08, 0x2e, 0x4d, 0x75, 0x68, 0x61, 0x6c, 0x61, 0x6d,
+0x69, 0x3b, 0x53, 0x61, 0x66, 0x61, 0x6c, 0x69, 0x3b, 0x4c, 0x61, 0x70,
+0x12b, 0x20, 0x49, 0x3b, 0x4c, 0x61, 0x70, 0x12b, 0x20, 0x49, 0x49, 0x3b,
+0x53, 0x75, 0x6d, 0x61, 0x74, 0x101, 0x20, 0x49, 0x3b, 0x53, 0x75, 0x6d,
+0x61, 0x74, 0x101, 0x20, 0x49, 0x49, 0x3b, 0x4c, 0x61, 0x73, 0x61, 0x70,
+0x69, 0x3b, 0x53, 0x61, 0x2bb, 0x61, 0x70, 0x101, 0x6e, 0x69, 0x3b, 0x4c,
+0x61, 0x6d, 0x61, 0x74, 0x101, 0x6e, 0x69, 0x3b, 0x53, 0x61, 0x76, 0x101,
+0x6c, 0x69, 0x3b, 0x53, 0x16b, 0x2d, 0x6b, 0x61, 0x2bb, 0x61, 0x74, 0x61,
+0x3b, 0x53, 0x16b, 0x2d, 0x68, 0x69, 0x73, 0x61, 0x4d, 0x75, 0x68, 0x3b,
+0x53, 0x61, 0x66, 0x3b, 0x4c, 0x61, 0x70, 0x20, 0x49, 0x3b, 0x4c, 0x61,
+0x70, 0x20, 0x49, 0x49, 0x3b, 0x53, 0x75, 0x6d, 0x20, 0x49, 0x3b, 0x53,
+0x75, 0x6d, 0x20, 0x49, 0x49, 0x3b, 0x4c, 0x61, 0x73, 0x3b, 0x53, 0x61,
+0x2bb, 0x61, 0x3b, 0x4c, 0x61, 0x6d, 0x3b, 0x53, 0x61, 0x76, 0x3b, 0x53,
+0x16b, 0x2d, 0x6b, 0x3b, 0x53, 0x16b, 0x2d, 0x68, 0x4d, 0x75, 0x68, 0x61,
+0x72, 0x72, 0x65, 0x6d, 0x3b, 0x53, 0x61, 0x66, 0x65, 0x72, 0x3b, 0x52,
+0x65, 0x62, 0x69, 0xfc, 0x6c, 0x65, 0x76, 0x76, 0x65, 0x6c, 0x3b, 0x52,
+0x65, 0x62, 0x69, 0xfc, 0x6c, 0x61, 0x68, 0x69, 0x72, 0x3b, 0x43, 0x65,
+0x6d, 0x61, 0x7a, 0x69, 0x79, 0x65, 0x6c, 0x65, 0x76, 0x76, 0x65, 0x6c,
+0x3b, 0x43, 0x65, 0x6d, 0x61, 0x7a, 0x69, 0x79, 0x65, 0x6c, 0x61, 0x68,
+0x69, 0x72, 0x3b, 0x52, 0x65, 0x63, 0x65, 0x70, 0x3b, 0x15e, 0x61, 0x62,
+0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x7a, 0x61, 0x6e, 0x3b, 0x15e,
+0x65, 0x76, 0x76, 0x61, 0x6c, 0x3b, 0x5a, 0x69, 0x6c, 0x6b, 0x61, 0x64,
+0x65, 0x3b, 0x5a, 0x69, 0x6c, 0x68, 0x69, 0x63, 0x63, 0x65, 0x4d, 0x75,
+0x68, 0x61, 0x72, 0x2e, 0x3b, 0x53, 0x61, 0x66, 0x65, 0x72, 0x3b, 0x52,
+0x2e, 0x65, 0x76, 0x76, 0x65, 0x6c, 0x3b, 0x52, 0x2e, 0x61, 0x68, 0x69,
+0x72, 0x3b, 0x43, 0x2e, 0x65, 0x76, 0x76, 0x65, 0x6c, 0x3b, 0x43, 0x2e,
+0x61, 0x68, 0x69, 0x72, 0x3b, 0x52, 0x65, 0x63, 0x65, 0x70, 0x3b, 0x15e,
+0x61, 0x62, 0x61, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x2e, 0x3b, 0x15e, 0x65,
+0x76, 0x76, 0x61, 0x6c, 0x3b, 0x5a, 0x69, 0x6c, 0x6b, 0x61, 0x64, 0x65,
+0x3b, 0x5a, 0x69, 0x6c, 0x68, 0x69, 0x63, 0x63, 0x65, 0x41, 0x15f, 0x79,
+0x72, 0x3b, 0x53, 0x61, 0x70, 0x61, 0x72, 0x3b, 0x44, 0xf6, 0x72, 0x74,
+0x20, 0x74, 0x69, 0x72, 0x6b, 0x65, 0x15f, 0x69, 0x6b, 0x20, 0x31, 0x3b,
+0x44, 0xf6, 0x72, 0x74, 0x20, 0x74, 0x69, 0x72, 0x6b, 0x65, 0x15f, 0x69,
+0x6b, 0x20, 0x32, 0x3b, 0x44, 0xf6, 0x72, 0x74, 0x20, 0x74, 0x69, 0x72,
+0x6b, 0x65, 0x15f, 0x69, 0x6b, 0x20, 0x33, 0x3b, 0x44, 0xf6, 0x72, 0x74,
+0x20, 0x74, 0x69, 0x72, 0x6b, 0x65, 0x15f, 0x69, 0x6b, 0x20, 0x34, 0x3b,
+0x52, 0x65, 0x6a, 0x65, 0x70, 0x3b, 0x4d, 0x65, 0x72, 0x65, 0x74, 0x3b,
+0x4f, 0x72, 0x61, 0x7a, 0x61, 0x3b, 0x42, 0x61, 0xfd, 0x72, 0x61, 0x6d,
+0x3b, 0x42, 0x6f, 0x15f, 0x20, 0x61, 0xfd, 0x3b, 0x47, 0x75, 0x72, 0x62,
+0x61, 0x6e, 0x41, 0x15f, 0x79, 0x3b, 0x53, 0x61, 0x70, 0x3b, 0x54, 0x69,
+0x72, 0x20, 0x49, 0x3b, 0x54, 0x69, 0x72, 0x20, 0x49, 0x49, 0x3b, 0x54,
+0x69, 0x72, 0x20, 0x49, 0x49, 0x49, 0x3b, 0x54, 0x69, 0x72, 0x20, 0x49,
+0x56, 0x3b, 0x52, 0x65, 0x6a, 0x3b, 0x4d, 0x65, 0x72, 0x3b, 0x4f, 0x72,
+0x61, 0x3b, 0x42, 0x61, 0xfd, 0x3b, 0x42, 0x6f, 0x15f, 0x3b, 0x47, 0x75,
+0x72, 0x43c, 0x443, 0x445, 0x430, 0x440, 0x440, 0x430, 0x43c, 0x3b, 0x441, 0x430,
+0x444, 0x430, 0x440, 0x3b, 0x440, 0x430, 0x431, 0x456, 0x20, 0x49, 0x3b, 0x440,
+0x430, 0x431, 0x456, 0x20, 0x49, 0x49, 0x3b, 0x434, 0x436, 0x443, 0x43c, 0x430,
+0x434, 0x430, 0x20, 0x49, 0x3b, 0x434, 0x436, 0x443, 0x43c, 0x430, 0x434, 0x430,
+0x20, 0x49, 0x49, 0x3b, 0x440, 0x430, 0x434, 0x436, 0x430, 0x431, 0x3b, 0x448,
+0x430, 0x430, 0x431, 0x430, 0x43d, 0x3b, 0x440, 0x430, 0x43c, 0x430, 0x434, 0x430,
+0x43d, 0x3b, 0x434, 0x430, 0x432, 0x432, 0x430, 0x43b, 0x3b, 0x437, 0x443, 0x2d,
+0x43b, 0x44c, 0x2d, 0x43a, 0x430, 0x430, 0x434, 0x430, 0x3b, 0x437, 0x443, 0x2d,
+0x43b, 0x44c, 0x2d, 0x445, 0x456, 0x434, 0x436, 0x430, 0x43c, 0x443, 0x445, 0x3b,
+0x441, 0x430, 0x444, 0x3b, 0x440, 0x430, 0x431, 0x456, 0x20, 0x49, 0x3b, 0x440,
+0x430, 0x431, 0x456, 0x20, 0x49, 0x49, 0x3b, 0x434, 0x436, 0x443, 0x43c, 0x20,
+0x49, 0x3b, 0x434, 0x436, 0x443, 0x43c, 0x20, 0x49, 0x49, 0x3b, 0x440, 0x430,
+0x434, 0x436, 0x3b, 0x448, 0x430, 0x430, 0x431, 0x3b, 0x440, 0x430, 0x43c, 0x3b,
+0x434, 0x430, 0x432, 0x3b, 0x437, 0x443, 0x2d, 0x43b, 0x44c, 0x2d, 0x43a, 0x3b,
+0x437, 0x443, 0x2d, 0x43b, 0x44c, 0x2d, 0x445, 0x43c, 0x443, 0x445, 0x2e, 0x3b,
+0x441, 0x430, 0x444, 0x2e, 0x3b, 0x440, 0x430, 0x431, 0x456, 0x20, 0x49, 0x3b,
+0x440, 0x430, 0x431, 0x456, 0x20, 0x49, 0x49, 0x3b, 0x434, 0x436, 0x443, 0x43c,
+0x2e, 0x20, 0x49, 0x3b, 0x434, 0x436, 0x443, 0x43c, 0x2e, 0x20, 0x49, 0x49,
+0x3b, 0x440, 0x430, 0x434, 0x436, 0x2e, 0x3b, 0x448, 0x430, 0x430, 0x431, 0x2e,
+0x3b, 0x440, 0x430, 0x43c, 0x2e, 0x3b, 0x434, 0x430, 0x432, 0x2e, 0x3b, 0x437,
+0x443, 0x2d, 0x43b, 0x44c, 0x2d, 0x43a, 0x2e, 0x3b, 0x437, 0x443, 0x2d, 0x43b,
+0x44c, 0x2d, 0x445, 0x2e, 0x645, 0x62d, 0x631, 0x645, 0x3b, 0x635, 0x641, 0x631,
+0x3b, 0x631, 0x20, 0x628, 0x6cc, 0x639, 0x20, 0x627, 0x644, 0x627, 0x648, 0x644,
+0x3b, 0x631, 0x20, 0x628, 0x6cc, 0x639, 0x20, 0x627, 0x644, 0x62b, 0x627, 0x646,
+0x6cc, 0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x6cc, 0x20, 0x627, 0x644, 0x627, 0x648,
+0x644, 0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x6cc, 0x20, 0x627, 0x644, 0x62b, 0x627,
+0x646, 0x6cc, 0x3b, 0x631, 0x62c, 0x628, 0x3b, 0x634, 0x639, 0x628, 0x627, 0x646,
+0x3b, 0x631, 0x645, 0x636, 0x627, 0x646, 0x3b, 0x634, 0x648, 0x627, 0x644, 0x3b,
+0x630, 0x648, 0x627, 0x644, 0x642, 0x639, 0x62f, 0x6c3, 0x3b, 0x630, 0x648, 0x627,
+0x644, 0x62d, 0x62c, 0x6c3, 0x645, 0x62d, 0x631, 0x645, 0x3b, 0x635, 0x641, 0x631,
+0x3b, 0x631, 0x628, 0x6cc, 0x639, 0x20, 0x627, 0x644, 0x627, 0x648, 0x651, 0x644,
+0x3b, 0x631, 0x628, 0x6cc, 0x639, 0x20, 0x627, 0x644, 0x62b, 0x651, 0x627, 0x646,
+0x6cc, 0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x6cc, 0x20, 0x627, 0x644, 0x627, 0x648,
+0x651, 0x644, 0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x6cc, 0x20, 0x627, 0x644, 0x62b,
+0x651, 0x627, 0x646, 0x6cc, 0x3b, 0x631, 0x62c, 0x628, 0x3b, 0x634, 0x639, 0x628,
+0x627, 0x646, 0x3b, 0x631, 0x645, 0x636, 0x627, 0x646, 0x3b, 0x634, 0x648, 0x627,
+0x644, 0x3b, 0x630, 0x648, 0x627, 0x644, 0x642, 0x639, 0x62f, 0x6c3, 0x3b, 0x630,
+0x648, 0x627, 0x644, 0x62d, 0x62c, 0x6c3, 0x645, 0x62d, 0x631, 0x645, 0x3b, 0x635,
+0x641, 0x631, 0x3b, 0x631, 0x628, 0x6cc, 0x639, 0x20, 0x627, 0x644, 0x627, 0x648,
+0x651, 0x644, 0x3b, 0x631, 0x628, 0x6cc, 0x639, 0x20, 0x627, 0x644, 0x62b, 0x627,
+0x646, 0x6cc, 0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x6cc, 0x20, 0x627, 0x644, 0x627,
+0x648, 0x651, 0x644, 0x3b, 0x62c, 0x645, 0x627, 0x62f, 0x6cc, 0x20, 0x627, 0x644,
+0x62b, 0x627, 0x646, 0x6cc, 0x3b, 0x631, 0x62c, 0x628, 0x3b, 0x634, 0x639, 0x628,
+0x627, 0x646, 0x3b, 0x631, 0x645, 0x636, 0x627, 0x646, 0x3b, 0x634, 0x648, 0x627,
+0x644, 0x3b, 0x630, 0x648, 0x627, 0x644, 0x642, 0x639, 0x62f, 0x6c3, 0x3b, 0x630,
+0x648, 0x627, 0x644, 0x62d, 0x62c, 0x6c3, 0x645, 0x6c7, 0x6be, 0x6d5, 0x631, 0x631,
+0x6d5, 0x645, 0x3b, 0x633, 0x6d5, 0x67e, 0x6d5, 0x631, 0x3b, 0x631, 0x6d5, 0x628,
+0x649, 0x626, 0x6c7, 0x644, 0x626, 0x6d5, 0x6cb, 0x6cb, 0x6d5, 0x644, 0x3b, 0x631,
+0x6d5, 0x628, 0x649, 0x626, 0x6c7, 0x644, 0x626, 0x627, 0x62e, 0x649, 0x631, 0x3b,
+0x62c, 0x6d5, 0x645, 0x627, 0x62f, 0x649, 0x64a, 0x6d5, 0x644, 0x626, 0x6d5, 0x6cb,
+0x6cb, 0x6d5, 0x644, 0x3b, 0x62c, 0x6d5, 0x645, 0x627, 0x62f, 0x649, 0x64a, 0x6d5,
+0x644, 0x626, 0x627, 0x62e, 0x649, 0x631, 0x3b, 0x631, 0x6d5, 0x62c, 0x6d5, 0x628,
+0x3b, 0x634, 0x6d5, 0x626, 0x628, 0x627, 0x646, 0x3b, 0x631, 0x627, 0x645, 0x649,
+0x632, 0x627, 0x646, 0x3b, 0x634, 0x6d5, 0x6cb, 0x6cb, 0x627, 0x644, 0x3b, 0x632,
+0x6c7, 0x644, 0x642, 0x6d5, 0x626, 0x62f, 0x6d5, 0x3b, 0x632, 0x6c7, 0x644, 0x6be,
+0x6d5, 0x62c, 0x62c, 0x6d5, 0x4d, 0x75, 0x68, 0x61, 0x72, 0x72, 0x61, 0x6d,
+0x3b, 0x53, 0x61, 0x66, 0x61, 0x72, 0x3b, 0x52, 0x6f, 0x62, 0x69, 0x2019,
+0x20, 0x75, 0x6c, 0x2d, 0x61, 0x76, 0x76, 0x61, 0x6c, 0x3b, 0x52, 0x6f,
+0x62, 0x69, 0x2019, 0x20, 0x75, 0x6c, 0x2d, 0x6f, 0x78, 0x69, 0x72, 0x3b,
+0x4a, 0x75, 0x6d, 0x61, 0x64, 0x20, 0x75, 0x6c, 0x2d, 0x61, 0x76, 0x76,
+0x61, 0x6c, 0x3b, 0x4a, 0x75, 0x6d, 0x61, 0x64, 0x20, 0x75, 0x6c, 0x2d,
+0x6f, 0x78, 0x69, 0x72, 0x3b, 0x52, 0x61, 0x6a, 0x61, 0x62, 0x3b, 0x53,
+0x68, 0x61, 0x2019, 0x62, 0x6f, 0x6e, 0x3b, 0x52, 0x61, 0x6d, 0x61, 0x7a,
+0x6f, 0x6e, 0x3b, 0x53, 0x68, 0x61, 0x76, 0x76, 0x6f, 0x6c, 0x3b, 0x5a,
+0x75, 0x6c, 0x2d, 0x71, 0x61, 0x2019, 0x64, 0x61, 0x3b, 0x5a, 0x75, 0x6c,
+0x2d, 0x68, 0x69, 0x6a, 0x6a, 0x61, 0x4d, 0x75, 0x68, 0x2e, 0x3b, 0x53,
+0x61, 0x66, 0x2e, 0x3b, 0x52, 0x6f, 0x62, 0x2e, 0x20, 0x61, 0x76, 0x76,
+0x2e, 0x3b, 0x52, 0x6f, 0x62, 0x2e, 0x20, 0x6f, 0x78, 0x2e, 0x3b, 0x4a,
+0x75, 0x6d, 0x2e, 0x20, 0x61, 0x76, 0x76, 0x2e, 0x3b, 0x4a, 0x75, 0x6d,
+0x2e, 0x20, 0x6f, 0x78, 0x2e, 0x3b, 0x52, 0x61, 0x6a, 0x2e, 0x3b, 0x53,
+0x68, 0x61, 0x2e, 0x3b, 0x52, 0x61, 0x6d, 0x2e, 0x3b, 0x53, 0x68, 0x61,
+0x76, 0x2e, 0x3b, 0x5a, 0x75, 0x6c, 0x2d, 0x71, 0x2e, 0x3b, 0x5a, 0x75,
+0x6c, 0x2d, 0x68, 0x2e, 0x41c, 0x443, 0x4b3, 0x430, 0x440, 0x440, 0x430, 0x43c,
+0x3b, 0x421, 0x430, 0x444, 0x430, 0x440, 0x3b, 0x420, 0x430, 0x431, 0x438, 0x443,
+0x43b, 0x2d, 0x430, 0x432, 0x432, 0x430, 0x43b, 0x3b, 0x420, 0x430, 0x431, 0x438,
+0x443, 0x43b, 0x2d, 0x43e, 0x445, 0x438, 0x440, 0x3b, 0x416, 0x443, 0x43c, 0x43e,
+0x434, 0x438, 0x443, 0x43b, 0x2d, 0x443, 0x43b, 0x43e, 0x3b, 0x416, 0x443, 0x43c,
+0x43e, 0x434, 0x438, 0x443, 0x43b, 0x2d, 0x443, 0x445, 0x440, 0x43e, 0x3b, 0x420,
+0x430, 0x436, 0x430, 0x431, 0x3b, 0x428, 0x430, 0x44a, 0x431, 0x43e, 0x43d, 0x3b,
+0x420, 0x430, 0x43c, 0x430, 0x437, 0x43e, 0x43d, 0x3b, 0x428, 0x430, 0x432, 0x432,
+0x43e, 0x43b, 0x3b, 0x417, 0x438, 0x43b, 0x2d, 0x49b, 0x430, 0x44a, 0x434, 0x430,
+0x3b, 0x417, 0x438, 0x43b, 0x2d, 0x4b3, 0x438, 0x436, 0x436, 0x430
};
// GENERATED PART ENDS HERE
diff --git a/src/corelib/time/qjalalicalendar.cpp b/src/corelib/time/qjalalicalendar.cpp
index f33e9f3097..fcbdf14395 100644
--- a/src/corelib/time/qjalalicalendar.cpp
+++ b/src/corelib/time/qjalalicalendar.cpp
@@ -15,8 +15,9 @@ using namespace QRoundingDown;
constexpr qint64 cycleDays = 1029983;
constexpr int cycleYears = 2820;
-constexpr double yearLength = 365.24219858156028368; // 365 + leapRatio;
+constexpr double yearLength = 365.24219858156028368; // 365 + 683 / 2820.
constexpr qint64 jalaliEpoch = 2121446; // 475/01/01 AP, start of 2820 cycle
+// This appears to be based on Ahmad Birashk's algorithm.
// Calendar implementation
@@ -75,7 +76,7 @@ qint64 firstDayOfYear(int year, int cycleNo)
Source: \l {https://en.wikipedia.org/wiki/Solar_Hijri_calendar}{Wikipedia
page on Solar Hijri Calendar}
- */
+*/
QString QJalaliCalendar::name() const
{
diff --git a/src/corelib/time/qjalalicalendar_data_p.h b/src/corelib/time/qjalalicalendar_data_p.h
index 68418785e6..0e3c3cedb9 100644
--- a/src/corelib/time/qjalalicalendar_data_p.h
+++ b/src/corelib/time/qjalalicalendar_data_p.h
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: Unicode-3.0
#ifndef QPERSIANCALENDAR_DATA_P_H
#define QPERSIANCALENDAR_DATA_P_H
@@ -25,8 +25,8 @@ namespace QtPrivate::Jalali {
// GENERATED PART STARTS HERE
/*
- This part of the file was generated on 2023-02-02 from the
- Common Locale Data Repository v42
+ This part of the file was generated on 2024-01-09 from the
+ Common Locale Data Repository v44.1
http://www.unicode.org/cldr/
@@ -40,6 +40,8 @@ static constexpr QCalendarLocale locale_data[] = {
{ 1, 0, 0, 0, 0, 83, 83, 130, 153, 83, 83, 47, 47, 23, 26 },// C/AnyScript/AnyTerritory
{ 2, 27, 90, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Abkhazian/Cyrillic/Georgia
{ 3, 66, 77, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Afar/Latin/Ethiopia
+ { 3, 66, 67, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Afar/Latin/Djibouti
+ { 3, 66, 74, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Afar/Latin/Eritrea
{ 4, 66, 216, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Afrikaans/Latin/South Africa
{ 4, 66, 162, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Afrikaans/Latin/Namibia
{ 5, 66, 40, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Aghem/Latin/Cameroon
@@ -75,7 +77,7 @@ static constexpr QCalendarLocale locale_data[] = {
{ 14, 4, 238, 179, 179, 179, 179, 153, 153, 67, 67, 67, 67, 26, 26 },// Arabic/Arabic/Tunisia
{ 14, 4, 245, 179, 179, 179, 179, 153, 153, 67, 67, 67, 67, 26, 26 },// Arabic/Arabic/United Arab Emirates
{ 14, 4, 257, 179, 179, 179, 179, 153, 153, 67, 67, 67, 67, 26, 26 },// Arabic/Arabic/Western Sahara
- { 14, 4, 258, 179, 179, 179, 179, 153, 153, 67, 67, 67, 67, 26, 26 },// Arabic/Arabic/World
+ { 14, 4, 258, 179, 179, 179, 179, 153, 153, 67, 67, 67, 67, 26, 26 },// Arabic/Arabic/world
{ 14, 4, 259, 179, 179, 179, 179, 153, 153, 67, 67, 67, 67, 26, 26 },// Arabic/Arabic/Yemen
{ 15, 66, 220, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Aragonese/Latin/Spain
{ 17, 5, 12, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Armenian/Armenian/Armenia
@@ -83,14 +85,16 @@ static constexpr QCalendarLocale locale_data[] = {
{ 19, 66, 220, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Asturian/Latin/Spain
{ 20, 66, 230, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Asu/Latin/Tanzania
{ 21, 66, 169, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Atsam/Latin/Nigeria
- { 25, 66, 17, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Azerbaijani/Latin/Azerbaijan
+ { 25, 66, 17, 246, 246, 246, 246, 153, 153, 80, 80, 80, 80, 26, 26 },// Azerbaijani/Latin/Azerbaijan
{ 25, 4, 112, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Azerbaijani/Arabic/Iran
+ { 25, 4, 113, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Azerbaijani/Arabic/Iraq
+ { 25, 4, 239, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Azerbaijani/Arabic/Turkey
{ 25, 27, 17, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Azerbaijani/Cyrillic/Azerbaijan
{ 26, 66, 40, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Bafia/Latin/Cameroon
{ 28, 66, 145, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Bambara/Latin/Mali
{ 28, 90, 145, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Bambara/Nko/Mali
- { 30, 9, 20, 246, 246, 334, 334, 421, 421, 88, 88, 87, 87, 26, 26 },// Bangla/Bangla/Bangladesh
- { 30, 9, 110, 246, 246, 334, 334, 421, 421, 88, 88, 87, 87, 26, 26 },// Bangla/Bangla/India
+ { 30, 9, 20, 326, 326, 414, 414, 501, 501, 88, 88, 87, 87, 26, 26 },// Bangla/Bangla/Bangladesh
+ { 30, 9, 110, 326, 326, 414, 414, 501, 501, 88, 88, 87, 87, 26, 26 },// Bangla/Bangla/India
{ 31, 66, 40, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Basaa/Latin/Cameroon
{ 32, 27, 193, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Bashkir/Cyrillic/Russia
{ 33, 66, 220, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Basque/Latin/Spain
@@ -100,44 +104,44 @@ static constexpr QCalendarLocale locale_data[] = {
{ 38, 29, 110, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Bhojpuri/Devanagari/India
{ 40, 33, 74, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Blin/Ethiopic/Eritrea
{ 41, 29, 110, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Bodo/Devanagari/India
- { 42, 66, 29, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Bosnian/Latin/Bosnia And Herzegovina
- { 42, 27, 29, 447, 447, 447, 447, 153, 153, 80, 80, 80, 80, 26, 26 },// Bosnian/Cyrillic/Bosnia And Herzegovina
+ { 42, 66, 29, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Bosnian/Latin/Bosnia and Herzegovina
+ { 42, 27, 29, 527, 527, 527, 527, 153, 153, 80, 80, 80, 80, 26, 26 },// Bosnian/Cyrillic/Bosnia and Herzegovina
{ 43, 66, 84, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Breton/Latin/France
{ 45, 27, 36, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Bulgarian/Cyrillic/Bulgaria
{ 46, 86, 161, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Burmese/Myanmar/Myanmar
- { 47, 137, 107, 527, 527, 527, 527, 153, 153, 38, 38, 38, 38, 26, 26 },// Cantonese/Traditional Han/Hong Kong
- { 47, 118, 50, 527, 527, 527, 527, 153, 153, 38, 38, 38, 38, 26, 26 },// Cantonese/Simplified Han/China
+ { 47, 137, 107, 607, 607, 607, 607, 153, 153, 38, 38, 38, 38, 26, 26 },// Cantonese/Traditional Han/Hong Kong
+ { 47, 118, 50, 607, 607, 607, 607, 153, 153, 38, 38, 38, 38, 26, 26 },// Cantonese/Simplified Han/China
{ 48, 66, 220, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Catalan/Latin/Spain
{ 48, 66, 6, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Catalan/Latin/Andorra
{ 48, 66, 84, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Catalan/Latin/France
{ 48, 66, 117, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Catalan/Latin/Italy
{ 49, 66, 185, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Cebuano/Latin/Philippines
{ 50, 66, 159, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Central Atlas Tamazight/Latin/Morocco
- { 51, 4, 113, 565, 565, 565, 565, 153, 153,101,101,101,101, 26, 26 },// Central Kurdish/Arabic/Iraq
- { 51, 4, 112, 565, 666, 565, 565, 153, 153,101,100,101,101, 26, 26 },// Central Kurdish/Arabic/Iran
+ { 51, 4, 113, 645, 645, 645, 645, 153, 153,101,101,101,101, 26, 26 },// Central Kurdish/Arabic/Iraq
+ { 51, 4, 112, 746, 746, 746, 746, 153, 153,100,100,100,100, 26, 26 },// Central Kurdish/Arabic/Iran
{ 52, 21, 20, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Chakma/Chakma/Bangladesh
{ 52, 21, 110, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Chakma/Chakma/India
{ 54, 27, 193, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Chechen/Cyrillic/Russia
{ 55, 23, 248, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Cherokee/Cherokee/United States
{ 56, 66, 248, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Chickasaw/Latin/United States
{ 57, 66, 243, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Chiga/Latin/Uganda
- { 58, 118, 50, 766, 766, 527, 527, 153, 153, 37, 37, 38, 38, 26, 26 },// Chinese/Simplified Han/China
- { 58, 118, 107, 766, 766, 527, 527, 153, 153, 37, 37, 38, 38, 26, 26 },// Chinese/Simplified Han/Hong Kong
- { 58, 118, 139, 766, 766, 527, 527, 153, 153, 37, 37, 38, 38, 26, 26 },// Chinese/Simplified Han/Macao
- { 58, 118, 210, 766, 766, 527, 527, 153, 153, 37, 37, 38, 38, 26, 26 },// Chinese/Simplified Han/Singapore
- { 58, 137, 107, 527, 527, 527, 527, 153, 153, 38, 38, 38, 38, 26, 26 },// Chinese/Traditional Han/Hong Kong
- { 58, 137, 139, 527, 527, 527, 527, 153, 153, 38, 38, 38, 38, 26, 26 },// Chinese/Traditional Han/Macao
- { 58, 137, 228, 527, 527, 527, 527, 153, 153, 38, 38, 38, 38, 26, 26 },// Chinese/Traditional Han/Taiwan
+ { 58, 118, 50, 846, 846, 607, 607, 153, 153, 37, 37, 38, 38, 26, 26 },// Chinese/Simplified Han/China
+ { 58, 118, 107, 846, 846, 607, 607, 153, 153, 37, 37, 38, 38, 26, 26 },// Chinese/Simplified Han/Hong Kong
+ { 58, 118, 139, 846, 846, 607, 607, 153, 153, 37, 37, 38, 38, 26, 26 },// Chinese/Simplified Han/Macao
+ { 58, 118, 210, 846, 846, 607, 607, 153, 153, 37, 37, 38, 38, 26, 26 },// Chinese/Simplified Han/Singapore
+ { 58, 137, 107, 607, 607, 607, 607, 153, 153, 38, 38, 38, 38, 26, 26 },// Chinese/Traditional Han/Hong Kong
+ { 58, 137, 139, 607, 607, 607, 607, 153, 153, 38, 38, 38, 38, 26, 26 },// Chinese/Traditional Han/Macao
+ { 58, 137, 228, 607, 607, 607, 607, 153, 153, 38, 38, 38, 38, 26, 26 },// Chinese/Traditional Han/Taiwan
{ 59, 27, 193, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Church/Cyrillic/Russia
{ 60, 27, 193, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Chuvash/Cyrillic/Russia
{ 61, 66, 91, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Colognian/Latin/Germany
{ 63, 66, 246, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Cornish/Latin/United Kingdom
{ 64, 66, 84, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Corsican/Latin/France
- { 66, 66, 60, 0, 0, 0, 0, 803, 803, 83, 83, 83, 83, 38, 38 },// Croatian/Latin/Croatia
- { 66, 66, 29, 0, 0, 0, 0, 803, 803, 83, 83, 83, 83, 38, 38 },// Croatian/Latin/Bosnia And Herzegovina
- { 67, 66, 64, 841, 841, 841, 841, 153, 153, 81, 81, 81, 81, 26, 26 },// Czech/Latin/Czechia
- { 68, 66, 65, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Danish/Latin/Denmark
- { 68, 66, 95, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Danish/Latin/Greenland
+ { 66, 66, 60, 0, 0, 0, 0, 883, 883, 83, 83, 83, 83, 38, 38 },// Croatian/Latin/Croatia
+ { 66, 66, 29, 0, 0, 0, 0, 883, 883, 83, 83, 83, 83, 38, 38 },// Croatian/Latin/Bosnia and Herzegovina
+ { 67, 66, 64, 921, 921, 921, 921, 153, 153, 81, 81, 81, 81, 26, 26 },// Czech/Latin/Czechia
+ { 68, 66, 65, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Danish/Latin/Denmark
+ { 68, 66, 95, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Danish/Latin/Greenland
{ 69, 132, 144, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Divehi/Thaana/Maldives
{ 70, 29, 110, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Dogri/Devanagari/India
{ 71, 66, 40, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Duala/Latin/Cameroon
@@ -154,7 +158,7 @@ static constexpr QCalendarLocale locale_data[] = {
{ 75, 28, 248, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Deseret/United States
{ 75, 66, 5, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/American Samoa
{ 75, 66, 8, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Anguilla
- { 75, 66, 10, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Antigua And Barbuda
+ { 75, 66, 10, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Antigua and Barbuda
{ 75, 66, 15, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Australia
{ 75, 66, 16, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Austria
{ 75, 66, 18, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Bahamas
@@ -192,8 +196,9 @@ static constexpr QCalendarLocale locale_data[] = {
{ 75, 66, 103, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Guyana
{ 75, 66, 107, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Hong Kong
{ 75, 66, 110, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/India
+ { 75, 66, 111, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Indonesia
{ 75, 66, 114, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Ireland
- { 75, 66, 115, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Isle Of Man
+ { 75, 66, 115, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Isle of Man
{ 75, 66, 116, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Israel
{ 75, 66, 119, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Jamaica
{ 75, 66, 121, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Jersey
@@ -227,9 +232,9 @@ static constexpr QCalendarLocale locale_data[] = {
{ 75, 66, 189, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Puerto Rico
{ 75, 66, 194, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Rwanda
{ 75, 66, 196, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Saint Helena
- { 75, 66, 197, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Saint Kitts And Nevis
+ { 75, 66, 197, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Saint Kitts and Nevis
{ 75, 66, 198, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Saint Lucia
- { 75, 66, 201, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Saint Vincent And Grenadines
+ { 75, 66, 201, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Saint Vincent and Grenadines
{ 75, 66, 202, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Samoa
{ 75, 66, 208, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Seychelles
{ 75, 66, 209, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Sierra Leone
@@ -245,8 +250,8 @@ static constexpr QCalendarLocale locale_data[] = {
{ 75, 66, 230, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Tanzania
{ 75, 66, 234, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Tokelau
{ 75, 66, 235, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Tonga
- { 75, 66, 236, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Trinidad And Tobago
- { 75, 66, 241, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Turks And Caicos Islands
+ { 75, 66, 236, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Trinidad and Tobago
+ { 75, 66, 241, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Turks and Caicos Islands
{ 75, 66, 242, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Tuvalu
{ 75, 66, 243, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Uganda
{ 75, 66, 245, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/United Arab Emirates
@@ -254,85 +259,85 @@ static constexpr QCalendarLocale locale_data[] = {
{ 75, 66, 247, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/United States Outlying Islands
{ 75, 66, 249, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/United States Virgin Islands
{ 75, 66, 252, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Vanuatu
- { 75, 66, 258, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/World
+ { 75, 66, 258, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/world
{ 75, 66, 260, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Zambia
{ 75, 66, 261, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Latin/Zimbabwe
{ 75, 115, 246, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// English/Shavian/United Kingdom
{ 76, 27, 193, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Erzya/Cyrillic/Russia
- { 77, 66, 258, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Esperanto/Latin/World
+ { 77, 66, 258, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Esperanto/Latin/world
{ 78, 66, 75, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Estonian/Latin/Estonia
- { 79, 66, 92, 1005, 1005, 1091, 1091, 153, 153, 86, 86, 47, 47, 26, 26 },// Ewe/Latin/Ghana
- { 79, 66, 233, 1005, 1005, 1091, 1091, 153, 153, 86, 86, 47, 47, 26, 26 },// Ewe/Latin/Togo
+ { 79, 66, 92, 1085, 1085, 1171, 1171, 153, 153, 86, 86, 47, 47, 26, 26 },// Ewe/Latin/Ghana
+ { 79, 66, 233, 1085, 1085, 1171, 1171, 153, 153, 86, 86, 47, 47, 26, 26 },// Ewe/Latin/Togo
{ 80, 66, 40, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Ewondo/Latin/Cameroon
{ 81, 66, 81, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Faroese/Latin/Faroe Islands
{ 81, 66, 65, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Faroese/Latin/Denmark
{ 83, 66, 185, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Filipino/Latin/Philippines
- { 84, 66, 83, 1138, 1255, 1396, 1255, 153, 153,117,141, 81,141, 26, 26 },// Finnish/Latin/Finland
- { 85, 66, 84, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/France
- { 85, 66, 4, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Algeria
- { 85, 66, 23, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Belgium
- { 85, 66, 25, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Benin
- { 85, 66, 37, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Burkina Faso
- { 85, 66, 38, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Burundi
- { 85, 66, 40, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Cameroon
- { 85, 66, 41, 1615, 1615, 1696, 1696, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Canada
- { 85, 66, 46, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Central African Republic
- { 85, 66, 48, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Chad
- { 85, 66, 55, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Comoros
- { 85, 66, 56, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Congo Brazzaville
- { 85, 66, 57, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Congo Kinshasa
- { 85, 66, 67, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Djibouti
- { 85, 66, 73, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Equatorial Guinea
- { 85, 66, 85, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/French Guiana
- { 85, 66, 86, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/French Polynesia
- { 85, 66, 88, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Gabon
- { 85, 66, 97, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Guadeloupe
- { 85, 66, 102, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Guinea
- { 85, 66, 104, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Haiti
- { 85, 66, 118, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Ivory Coast
- { 85, 66, 138, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Luxembourg
- { 85, 66, 141, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Madagascar
- { 85, 66, 145, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Mali
- { 85, 66, 148, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Martinique
- { 85, 66, 149, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Mauritania
- { 85, 66, 150, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Mauritius
- { 85, 66, 151, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Mayotte
- { 85, 66, 155, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Monaco
- { 85, 66, 159, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Morocco
- { 85, 66, 166, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/New Caledonia
- { 85, 66, 170, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Niger
- { 85, 66, 191, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Reunion
- { 85, 66, 194, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Rwanda
- { 85, 66, 195, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Saint Barthelemy
- { 85, 66, 199, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Saint Martin
- { 85, 66, 200, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Saint Pierre And Miquelon
- { 85, 66, 206, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Senegal
- { 85, 66, 208, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Seychelles
- { 85, 66, 226, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Switzerland
- { 85, 66, 227, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Syria
- { 85, 66, 233, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Togo
- { 85, 66, 238, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Tunisia
- { 85, 66, 252, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Vanuatu
- { 85, 66, 256, 1477, 1477, 1558, 1558, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Wallis And Futuna
+ { 84, 66, 83, 1218, 1335, 1476, 1335, 153, 153,117,141, 81,141, 26, 26 },// Finnish/Latin/Finland
+ { 85, 66, 84, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/France
+ { 85, 66, 4, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Algeria
+ { 85, 66, 23, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Belgium
+ { 85, 66, 25, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Benin
+ { 85, 66, 37, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Burkina Faso
+ { 85, 66, 38, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Burundi
+ { 85, 66, 40, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Cameroon
+ { 85, 66, 41, 1695, 1695, 1776, 1776, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Canada
+ { 85, 66, 46, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Central African Republic
+ { 85, 66, 48, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Chad
+ { 85, 66, 55, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Comoros
+ { 85, 66, 56, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Congo - Brazzaville
+ { 85, 66, 57, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Congo - Kinshasa
+ { 85, 66, 67, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Djibouti
+ { 85, 66, 73, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Equatorial Guinea
+ { 85, 66, 85, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/French Guiana
+ { 85, 66, 86, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/French Polynesia
+ { 85, 66, 88, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Gabon
+ { 85, 66, 97, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Guadeloupe
+ { 85, 66, 102, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Guinea
+ { 85, 66, 104, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Haiti
+ { 85, 66, 118, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Ivory Coast
+ { 85, 66, 138, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Luxembourg
+ { 85, 66, 141, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Madagascar
+ { 85, 66, 145, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Mali
+ { 85, 66, 148, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Martinique
+ { 85, 66, 149, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Mauritania
+ { 85, 66, 150, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Mauritius
+ { 85, 66, 151, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Mayotte
+ { 85, 66, 155, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Monaco
+ { 85, 66, 159, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Morocco
+ { 85, 66, 166, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/New Caledonia
+ { 85, 66, 170, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Niger
+ { 85, 66, 191, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Reunion
+ { 85, 66, 194, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Rwanda
+ { 85, 66, 195, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Saint Barthelemy
+ { 85, 66, 199, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Saint Martin
+ { 85, 66, 200, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Saint Pierre and Miquelon
+ { 85, 66, 206, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Senegal
+ { 85, 66, 208, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Seychelles
+ { 85, 66, 226, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Switzerland
+ { 85, 66, 227, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Syria
+ { 85, 66, 233, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Togo
+ { 85, 66, 238, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Tunisia
+ { 85, 66, 252, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Vanuatu
+ { 85, 66, 256, 1557, 1557, 1638, 1638, 153, 153, 81, 81, 57, 57, 26, 26 },// French/Latin/Wallis and Futuna
{ 86, 66, 117, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Friulian/Latin/Italy
{ 87, 66, 206, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Fulah/Latin/Senegal
- { 87, 1, 37, 1753, 1753, 1753, 1753, 1904, 1904,151,151,151,151, 41, 41 },// Fulah/Adlam/Burkina Faso
- { 87, 1, 40, 1753, 1753, 1753, 1753, 1904, 1904,151,151,151,151, 41, 41 },// Fulah/Adlam/Cameroon
- { 87, 1, 89, 1753, 1753, 1753, 1753, 1904, 1904,151,151,151,151, 41, 41 },// Fulah/Adlam/Gambia
- { 87, 1, 92, 1753, 1753, 1753, 1753, 1904, 1904,151,151,151,151, 41, 41 },// Fulah/Adlam/Ghana
- { 87, 1, 101, 1753, 1753, 1753, 1753, 1904, 1904,151,151,151,151, 41, 41 },// Fulah/Adlam/Guinea Bissau
- { 87, 1, 102, 1753, 1753, 1753, 1753, 1904, 1904,151,151,151,151, 41, 41 },// Fulah/Adlam/Guinea
- { 87, 1, 134, 1753, 1753, 1753, 1753, 1904, 1904,151,151,151,151, 41, 41 },// Fulah/Adlam/Liberia
- { 87, 1, 149, 1753, 1753, 1753, 1753, 1904, 1904,151,151,151,151, 41, 41 },// Fulah/Adlam/Mauritania
- { 87, 1, 169, 1753, 1753, 1753, 1753, 1904, 1904,151,151,151,151, 41, 41 },// Fulah/Adlam/Nigeria
- { 87, 1, 170, 1753, 1753, 1753, 1753, 1904, 1904,151,151,151,151, 41, 41 },// Fulah/Adlam/Niger
- { 87, 1, 206, 1753, 1753, 1753, 1753, 1904, 1904,151,151,151,151, 41, 41 },// Fulah/Adlam/Senegal
- { 87, 1, 209, 1753, 1753, 1753, 1753, 1904, 1904,151,151,151,151, 41, 41 },// Fulah/Adlam/Sierra Leone
+ { 87, 1, 37, 1833, 1833, 1833, 1833, 1984, 1984,151,151,151,151, 41, 41 },// Fulah/Adlam/Burkina Faso
+ { 87, 1, 40, 1833, 1833, 1833, 1833, 1984, 1984,151,151,151,151, 41, 41 },// Fulah/Adlam/Cameroon
+ { 87, 1, 89, 1833, 1833, 1833, 1833, 1984, 1984,151,151,151,151, 41, 41 },// Fulah/Adlam/Gambia
+ { 87, 1, 92, 1833, 1833, 1833, 1833, 1984, 1984,151,151,151,151, 41, 41 },// Fulah/Adlam/Ghana
+ { 87, 1, 101, 1833, 1833, 1833, 1833, 1984, 1984,151,151,151,151, 41, 41 },// Fulah/Adlam/Guinea-Bissau
+ { 87, 1, 102, 1833, 1833, 1833, 1833, 1984, 1984,151,151,151,151, 41, 41 },// Fulah/Adlam/Guinea
+ { 87, 1, 134, 1833, 1833, 1833, 1833, 1984, 1984,151,151,151,151, 41, 41 },// Fulah/Adlam/Liberia
+ { 87, 1, 149, 1833, 1833, 1833, 1833, 1984, 1984,151,151,151,151, 41, 41 },// Fulah/Adlam/Mauritania
+ { 87, 1, 169, 1833, 1833, 1833, 1833, 1984, 1984,151,151,151,151, 41, 41 },// Fulah/Adlam/Nigeria
+ { 87, 1, 170, 1833, 1833, 1833, 1833, 1984, 1984,151,151,151,151, 41, 41 },// Fulah/Adlam/Niger
+ { 87, 1, 206, 1833, 1833, 1833, 1833, 1984, 1984,151,151,151,151, 41, 41 },// Fulah/Adlam/Senegal
+ { 87, 1, 209, 1833, 1833, 1833, 1833, 1984, 1984,151,151,151,151, 41, 41 },// Fulah/Adlam/Sierra Leone
{ 87, 66, 37, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Fulah/Latin/Burkina Faso
{ 87, 66, 40, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Fulah/Latin/Cameroon
{ 87, 66, 89, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Fulah/Latin/Gambia
{ 87, 66, 92, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Fulah/Latin/Ghana
- { 87, 66, 101, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Fulah/Latin/Guinea Bissau
+ { 87, 66, 101, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Fulah/Latin/Guinea-Bissau
{ 87, 66, 102, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Fulah/Latin/Guinea
{ 87, 66, 134, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Fulah/Latin/Liberia
{ 87, 66, 149, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Fulah/Latin/Mauritania
@@ -344,34 +349,37 @@ static constexpr QCalendarLocale locale_data[] = {
{ 90, 66, 220, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Galician/Latin/Spain
{ 91, 66, 243, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Ganda/Latin/Uganda
{ 92, 33, 77, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Geez/Ethiopic/Ethiopia
- { 93, 35, 90, 1945, 1945, 1945, 1945, 153, 153, 91, 91, 91, 91, 26, 26 },// Georgian/Georgian/Georgia
- { 94, 66, 91, 2036, 2036, 2036, 2036, 153, 153, 86, 86, 86, 86, 26, 26 },// German/Latin/Germany
- { 94, 66, 16, 2036, 2036, 2036, 2036, 153, 153, 86, 86, 86, 86, 26, 26 },// German/Latin/Austria
- { 94, 66, 23, 2036, 2036, 2036, 2036, 153, 153, 86, 86, 86, 86, 26, 26 },// German/Latin/Belgium
- { 94, 66, 117, 2036, 2036, 2036, 2036, 153, 153, 86, 86, 86, 86, 26, 26 },// German/Latin/Italy
- { 94, 66, 136, 2036, 2036, 2036, 2036, 153, 153, 86, 86, 86, 86, 26, 26 },// German/Latin/Liechtenstein
- { 94, 66, 138, 2036, 2036, 2036, 2036, 153, 153, 86, 86, 86, 86, 26, 26 },// German/Latin/Luxembourg
- { 94, 66, 226, 2036, 2036, 2036, 2036, 153, 153, 86, 86, 86, 86, 26, 26 },// German/Latin/Switzerland
+ { 92, 33, 74, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Geez/Ethiopic/Eritrea
+ { 93, 35, 90, 2025, 2025, 2025, 2025, 153, 153, 91, 91, 91, 91, 26, 26 },// Georgian/Georgian/Georgia
+ { 94, 66, 91, 2116, 2116, 2116, 2116, 153, 153, 86, 86, 86, 86, 26, 26 },// German/Latin/Germany
+ { 94, 66, 16, 2116, 2116, 2116, 2116, 153, 153, 86, 86, 86, 86, 26, 26 },// German/Latin/Austria
+ { 94, 66, 23, 2116, 2116, 2116, 2116, 153, 153, 86, 86, 86, 86, 26, 26 },// German/Latin/Belgium
+ { 94, 66, 117, 2116, 2116, 2116, 2116, 153, 153, 86, 86, 86, 86, 26, 26 },// German/Latin/Italy
+ { 94, 66, 136, 2116, 2116, 2116, 2116, 153, 153, 86, 86, 86, 86, 26, 26 },// German/Latin/Liechtenstein
+ { 94, 66, 138, 2116, 2116, 2116, 2116, 153, 153, 86, 86, 86, 86, 26, 26 },// German/Latin/Luxembourg
+ { 94, 66, 226, 2116, 2116, 2116, 2116, 153, 153, 86, 86, 86, 86, 26, 26 },// German/Latin/Switzerland
{ 96, 39, 94, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Greek/Greek/Greece
{ 96, 39, 63, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Greek/Greek/Cyprus
{ 97, 66, 183, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Guarani/Latin/Paraguay
- { 98, 40, 110, 2122, 2122, 2122, 2122, 153, 153, 85, 85, 85, 85, 26, 26 },// Gujarati/Gujarati/India
+ { 98, 40, 110, 2202, 2202, 2202, 2202, 153, 153, 85, 85, 85, 85, 26, 26 },// Gujarati/Gujarati/India
{ 99, 66, 124, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Gusii/Latin/Kenya
{ 101, 66, 169, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Hausa/Latin/Nigeria
{ 101, 4, 169, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Hausa/Arabic/Nigeria
+ { 101, 4, 222, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Hausa/Arabic/Sudan
{ 101, 66, 92, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Hausa/Latin/Ghana
{ 101, 66, 170, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Hausa/Latin/Niger
{ 102, 66, 248, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Hawaiian/Latin/United States
- { 103, 47, 116, 2207, 2207, 2207, 2207, 153, 153, 68, 68, 68, 68, 26, 26 },// Hebrew/Hebrew/Israel
- { 105, 29, 110, 2275, 2275, 2275, 2275, 153, 153, 81, 81, 81, 81, 26, 26 },// Hindi/Devanagari/India
+ { 103, 47, 116, 2287, 2287, 2287, 2287, 153, 153, 68, 68, 68, 68, 26, 26 },// Hebrew/Hebrew/Israel
+ { 105, 29, 110, 2355, 2355, 2355, 2355, 153, 153, 81, 81, 81, 81, 26, 26 },// Hindi/Devanagari/India
{ 105, 66, 110, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Hindi/Latin/India
- { 107, 66, 108, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Hungarian/Latin/Hungary
- { 108, 66, 109, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Icelandic/Latin/Iceland
- { 109, 66, 258, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Ido/Latin/World
+ { 107, 66, 108, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Hungarian/Latin/Hungary
+ { 108, 66, 109, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Icelandic/Latin/Iceland
+ { 109, 66, 258, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Ido/Latin/world
{ 110, 66, 169, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Igbo/Latin/Nigeria
{ 111, 66, 83, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Inari Sami/Latin/Finland
{ 112, 66, 111, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Indonesian/Latin/Indonesia
- { 114, 66, 258, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Interlingua/Latin/World
+ { 114, 66, 258, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Interlingua/Latin/world
+ { 115, 66, 75, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Interlingue/Latin/Estonia
{ 116, 18, 41, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Inuktitut/Canadian Aboriginal/Canada
{ 116, 66, 41, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Inuktitut/Latin/Canada
{ 118, 66, 114, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Irish/Latin/Ireland
@@ -380,61 +388,65 @@ static constexpr QCalendarLocale locale_data[] = {
{ 119, 66, 203, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Italian/Latin/San Marino
{ 119, 66, 226, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Italian/Latin/Switzerland
{ 119, 66, 253, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Italian/Latin/Vatican City
- { 120, 53, 120, 2356, 2356, 2356, 2356, 153, 153, 77, 77, 77, 77, 26, 26 },// Japanese/Japanese/Japan
+ { 120, 53, 120, 2436, 2436, 2436, 2436, 153, 153, 77, 77, 77, 77, 26, 26 },// Japanese/Japanese/Japan
{ 121, 66, 111, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Javanese/Latin/Indonesia
{ 122, 66, 169, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Jju/Latin/Nigeria
- { 123, 66, 206, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Jola Fonyi/Latin/Senegal
+ { 123, 66, 206, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Jola-Fonyi/Latin/Senegal
{ 124, 66, 43, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Kabuverdianu/Latin/Cape Verde
{ 125, 66, 4, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Kabyle/Latin/Algeria
{ 126, 66, 40, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Kako/Latin/Cameroon
{ 127, 66, 95, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Kalaallisut/Latin/Greenland
{ 128, 66, 124, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Kalenjin/Latin/Kenya
{ 129, 66, 124, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Kamba/Latin/Kenya
- { 130, 56, 110, 2433, 2433, 2433, 2433, 153, 153, 92, 92, 92, 92, 26, 26 },// Kannada/Kannada/India
+ { 130, 56, 110, 2513, 2513, 2513, 2513, 153, 153, 92, 92, 92, 92, 26, 26 },// Kannada/Kannada/India
{ 132, 4, 110, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Kashmiri/Arabic/India
{ 132, 29, 110, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Kashmiri/Devanagari/India
- { 133, 27, 123, 2525, 2525, 2525, 2525, 153, 153, 80, 80, 80, 80, 26, 26 },// Kazakh/Cyrillic/Kazakhstan
+ { 133, 27, 123, 2605, 2605, 2605, 2605, 153, 153, 80, 80, 80, 80, 26, 26 },// Kazakh/Cyrillic/Kazakhstan
{ 134, 66, 40, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Kenyang/Latin/Cameroon
{ 135, 60, 39, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Khmer/Khmer/Cambodia
{ 136, 66, 99, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Kiche/Latin/Guatemala
{ 137, 66, 124, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Kikuyu/Latin/Kenya
{ 138, 66, 194, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Kinyarwanda/Latin/Rwanda
{ 141, 29, 110, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Konkani/Devanagari/India
- { 142, 63, 218, 2605, 2605, 2605, 2605, 153, 153, 54, 54, 54, 54, 26, 26 },// Korean/Korean/South Korea
- { 142, 63, 174, 2605, 2605, 2605, 2605, 153, 153, 54, 54, 54, 54, 26, 26 },// Korean/Korean/North Korea
+ { 142, 63, 218, 2685, 2685, 2685, 2685, 153, 153, 54, 54, 54, 54, 26, 26 },// Korean/Korean/South Korea
+ { 142, 63, 50, 2685, 2685, 2685, 2685, 153, 153, 54, 54, 54, 54, 26, 26 },// Korean/Korean/China
+ { 142, 63, 174, 2685, 2685, 2685, 2685, 153, 153, 54, 54, 54, 54, 26, 26 },// Korean/Korean/North Korea
{ 144, 66, 145, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Koyraboro Senni/Latin/Mali
{ 145, 66, 145, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Koyra Chiini/Latin/Mali
{ 146, 66, 134, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Kpelle/Latin/Liberia
+ { 146, 66, 102, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Kpelle/Latin/Guinea
{ 148, 66, 239, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Kurdish/Latin/Turkey
{ 149, 66, 40, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Kwasio/Latin/Cameroon
{ 150, 27, 128, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Kyrgyz/Cyrillic/Kyrgyzstan
{ 151, 66, 248, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Lakota/Latin/United States
{ 152, 66, 230, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Langi/Latin/Tanzania
- { 153, 65, 129, 2659, 2659, 2739, 2818, 153, 153, 80, 80, 79, 79, 26, 26 },// Lao/Lao/Laos
+ { 153, 65, 129, 2739, 2739, 2819, 2898, 153, 153, 80, 80, 79, 79, 26, 26 },// Lao/Lao/Laos
{ 154, 66, 253, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Latin/Latin/Vatican City
- { 155, 66, 131, 2897, 2897, 2897, 2897, 153, 153, 92, 92, 92, 92, 26, 26 },// Latvian/Latin/Latvia
- { 158, 66, 57, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Lingala/Latin/Congo Kinshasa
+ { 155, 66, 131, 2977, 2977, 2977, 2977, 153, 153, 92, 92, 92, 92, 26, 26 },// Latvian/Latin/Latvia
+ { 158, 66, 57, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Lingala/Latin/Congo - Kinshasa
{ 158, 66, 7, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Lingala/Latin/Angola
{ 158, 66, 46, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Lingala/Latin/Central African Republic
- { 158, 66, 56, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Lingala/Latin/Congo Brazzaville
+ { 158, 66, 56, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Lingala/Latin/Congo - Brazzaville
{ 160, 66, 137, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Lithuanian/Latin/Lithuania
- { 161, 66, 258, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Lojban/Latin/World
+ { 161, 66, 258, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Lojban/Latin/world
{ 162, 66, 91, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Lower Sorbian/Latin/Germany
{ 163, 66, 91, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Low German/Latin/Germany
{ 163, 66, 165, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Low German/Latin/Netherlands
- { 164, 66, 57, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Luba Katanga/Latin/Congo Kinshasa
+ { 164, 66, 57, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Luba-Katanga/Latin/Congo - Kinshasa
{ 165, 66, 225, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Lule Sami/Latin/Sweden
+ { 165, 66, 175, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Lule Sami/Latin/Norway
{ 166, 66, 124, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Luo/Latin/Kenya
{ 167, 66, 138, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Luxembourgish/Latin/Luxembourg
{ 168, 66, 124, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Luyia/Latin/Kenya
- { 169, 27, 140, 2989, 2989, 2989, 2989, 153, 153, 79, 79, 79, 79, 26, 26 },// Macedonian/Cyrillic/Macedonia
+ { 169, 27, 140, 3069, 3069, 3069, 3069, 153, 153, 79, 79, 79, 79, 26, 26 },// Macedonian/Cyrillic/Macedonia
{ 170, 66, 230, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Machame/Latin/Tanzania
{ 171, 29, 110, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Maithili/Devanagari/India
- { 172, 66, 160, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Makhuwa Meetto/Latin/Mozambique
+ { 172, 66, 160, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Makhuwa-Meetto/Latin/Mozambique
{ 173, 66, 230, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Makonde/Latin/Tanzania
{ 174, 66, 141, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Malagasy/Latin/Madagascar
- { 175, 74, 110, 3068, 3068, 3068, 3068, 3159, 3159, 91, 91, 91, 91, 39, 39 },// Malayalam/Malayalam/India
+ { 175, 74, 110, 3148, 3148, 3148, 3148, 3239, 3239, 91, 91, 91, 91, 39, 39 },// Malayalam/Malayalam/India
{ 176, 66, 143, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Malay/Latin/Malaysia
+ { 176, 4, 35, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Malay/Arabic/Brunei
{ 176, 4, 143, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Malay/Arabic/Malaysia
{ 176, 66, 35, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Malay/Latin/Brunei
{ 176, 66, 111, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Malay/Latin/Indonesia
@@ -442,10 +454,10 @@ static constexpr QCalendarLocale locale_data[] = {
{ 177, 66, 146, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Maltese/Latin/Malta
{ 179, 9, 110, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Manipuri/Bangla/India
{ 179, 78, 110, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Manipuri/Meitei Mayek/India
- { 180, 66, 115, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Manx/Latin/Isle Of Man
+ { 180, 66, 115, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Manx/Latin/Isle of Man
{ 181, 66, 167, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Maori/Latin/New Zealand
{ 182, 66, 49, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Mapuche/Latin/Chile
- { 183, 29, 110, 3198, 3198, 3198, 3198, 3278, 3278, 80, 80, 80, 80, 26, 26 },// Marathi/Devanagari/India
+ { 183, 29, 110, 3278, 3278, 3278, 3278, 3358, 3358, 80, 80, 80, 80, 26, 26 },// Marathi/Devanagari/India
{ 185, 66, 124, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Masai/Latin/Kenya
{ 185, 66, 230, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Masai/Latin/Tanzania
{ 186, 4, 112, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Mazanderani/Arabic/Iran
@@ -454,6 +466,7 @@ static constexpr QCalendarLocale locale_data[] = {
{ 190, 66, 41, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Mohawk/Latin/Canada
{ 191, 27, 156, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Mongolian/Cyrillic/Mongolia
{ 191, 83, 50, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Mongolian/Mongolian/China
+ { 191, 83, 156, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Mongolian/Mongolian/Mongolia
{ 192, 66, 150, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Morisyen/Latin/Mauritius
{ 193, 66, 40, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Mundang/Latin/Cameroon
{ 194, 66, 248, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Muscogee/Latin/United States
@@ -472,9 +485,9 @@ static constexpr QCalendarLocale locale_data[] = {
{ 206, 66, 225, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Northern Sami/Latin/Sweden
{ 207, 66, 216, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Northern Sotho/Latin/South Africa
{ 208, 66, 261, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// North Ndebele/Latin/Zimbabwe
- { 209, 66, 175, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Norwegian Bokmal/Latin/Norway
- { 209, 66, 224, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Norwegian Bokmal/Latin/Svalbard And Jan Mayen
- { 210, 66, 175, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Norwegian Nynorsk/Latin/Norway
+ { 209, 66, 175, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Norwegian Bokmal/Latin/Norway
+ { 209, 66, 224, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Norwegian Bokmal/Latin/Svalbard and Jan Mayen
+ { 210, 66, 175, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Norwegian Nynorsk/Latin/Norway
{ 211, 66, 219, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Nuer/Latin/South Sudan
{ 212, 66, 142, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Nyanja/Latin/Malawi
{ 213, 66, 243, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Nyankole/Latin/Uganda
@@ -486,40 +499,42 @@ static constexpr QCalendarLocale locale_data[] = {
{ 221, 101, 248, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Osage/Osage/United States
{ 222, 27, 90, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Ossetic/Cyrillic/Georgia
{ 222, 27, 193, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Ossetic/Cyrillic/Russia
- { 227, 4, 1, 3304, 3304, 3304, 3304, 3366, 3366, 62, 62, 62, 62, 26, 26 },// Pashto/Arabic/Afghanistan
- { 227, 4, 178, 3304, 3304, 3304, 3304, 3366, 3366, 62, 62, 62, 62, 26, 26 },// Pashto/Arabic/Pakistan
- { 228, 4, 112, 3392, 3392, 3392, 3392, 3458, 3458, 66, 66, 66, 66, 23, 23 },// Persian/Arabic/Iran
- { 228, 4, 1, 3392, 3481, 3392, 3392, 3537, 3458, 66, 56, 66, 66, 23, 23 },// Persian/Arabic/Afghanistan
- { 230, 66, 187, 3560, 3560, 3560, 3560, 153, 153, 83, 83, 83, 83, 26, 26 },// Polish/Latin/Poland
+ { 226, 66, 62, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Papiamento/Latin/Curacao
+ { 226, 66, 13, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Papiamento/Latin/Aruba
+ { 227, 4, 1, 3384, 3384, 3384, 3384, 3446, 3446, 62, 62, 62, 62, 26, 26 },// Pashto/Arabic/Afghanistan
+ { 227, 4, 178, 3384, 3384, 3384, 3384, 3446, 3446, 62, 62, 62, 62, 26, 26 },// Pashto/Arabic/Pakistan
+ { 228, 4, 112, 3472, 3472, 3472, 3472, 3538, 3538, 66, 66, 66, 66, 23, 23 },// Persian/Arabic/Iran
+ { 228, 4, 1, 3561, 3561, 3561, 3561, 3617, 3617, 56, 56, 56, 56, 23, 23 },// Persian/Arabic/Afghanistan
+ { 230, 66, 187, 3640, 3640, 3640, 3640, 153, 153, 83, 83, 83, 83, 26, 26 },// Polish/Latin/Poland
{ 231, 66, 32, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Portuguese/Latin/Brazil
{ 231, 66, 7, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Portuguese/Latin/Angola
{ 231, 66, 43, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Portuguese/Latin/Cape Verde
{ 231, 66, 73, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Portuguese/Latin/Equatorial Guinea
- { 231, 66, 101, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Portuguese/Latin/Guinea Bissau
+ { 231, 66, 101, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Portuguese/Latin/Guinea-Bissau
{ 231, 66, 138, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Portuguese/Latin/Luxembourg
{ 231, 66, 139, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Portuguese/Latin/Macao
{ 231, 66, 160, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Portuguese/Latin/Mozambique
{ 231, 66, 188, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Portuguese/Latin/Portugal
- { 231, 66, 204, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Portuguese/Latin/Sao Tome And Principe
+ { 231, 66, 204, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Portuguese/Latin/Sao Tome and Principe
{ 231, 66, 226, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Portuguese/Latin/Switzerland
{ 231, 66, 232, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Portuguese/Latin/Timor-Leste
- { 232, 66, 258, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Prussian/Latin/World
- { 233, 41, 110, 3643, 3643, 3643, 3643, 153, 153, 77, 77, 77, 77, 26, 26 },// Punjabi/Gurmukhi/India
+ { 232, 66, 187, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Prussian/Latin/Poland
+ { 233, 41, 110, 3723, 3723, 3723, 3723, 153, 153, 77, 77, 77, 77, 26, 26 },// Punjabi/Gurmukhi/India
{ 233, 4, 178, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Punjabi/Arabic/Pakistan
{ 234, 66, 184, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Quechua/Latin/Peru
{ 234, 66, 28, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Quechua/Latin/Bolivia
{ 234, 66, 70, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Quechua/Latin/Ecuador
- { 235, 66, 192, 3720, 3720, 3720, 3720, 153, 153, 85, 85, 85, 85, 26, 26 },// Romanian/Latin/Romania
- { 235, 66, 154, 3720, 3720, 3720, 3720, 153, 153, 85, 85, 85, 85, 26, 26 },// Romanian/Latin/Moldova
+ { 235, 66, 192, 3800, 3800, 3800, 3800, 153, 153, 85, 85, 85, 85, 26, 26 },// Romanian/Latin/Romania
+ { 235, 66, 154, 3800, 3800, 3800, 3800, 153, 153, 85, 85, 85, 85, 26, 26 },// Romanian/Latin/Moldova
{ 236, 66, 226, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Romansh/Latin/Switzerland
{ 237, 66, 230, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Rombo/Latin/Tanzania
{ 238, 66, 38, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Rundi/Latin/Burundi
- { 239, 27, 193, 3805, 3805, 3805, 3805, 153, 153, 80, 80, 80, 80, 26, 26 },// Russian/Cyrillic/Russia
- { 239, 27, 22, 3805, 3805, 3805, 3805, 153, 153, 80, 80, 80, 80, 26, 26 },// Russian/Cyrillic/Belarus
- { 239, 27, 123, 3805, 3805, 3805, 3805, 153, 153, 80, 80, 80, 80, 26, 26 },// Russian/Cyrillic/Kazakhstan
- { 239, 27, 128, 3805, 3805, 3805, 3805, 153, 153, 80, 80, 80, 80, 26, 26 },// Russian/Cyrillic/Kyrgyzstan
- { 239, 27, 154, 3805, 3805, 3805, 3805, 153, 153, 80, 80, 80, 80, 26, 26 },// Russian/Cyrillic/Moldova
- { 239, 27, 244, 3805, 3805, 3805, 3805, 153, 153, 80, 80, 80, 80, 26, 26 },// Russian/Cyrillic/Ukraine
+ { 239, 27, 193, 3885, 3885, 3885, 3885, 153, 153, 80, 80, 80, 80, 26, 26 },// Russian/Cyrillic/Russia
+ { 239, 27, 22, 3885, 3885, 3885, 3885, 153, 153, 80, 80, 80, 80, 26, 26 },// Russian/Cyrillic/Belarus
+ { 239, 27, 123, 3885, 3885, 3885, 3885, 153, 153, 80, 80, 80, 80, 26, 26 },// Russian/Cyrillic/Kazakhstan
+ { 239, 27, 128, 3885, 3885, 3885, 3885, 153, 153, 80, 80, 80, 80, 26, 26 },// Russian/Cyrillic/Kyrgyzstan
+ { 239, 27, 154, 3885, 3885, 3885, 3885, 153, 153, 80, 80, 80, 80, 26, 26 },// Russian/Cyrillic/Moldova
+ { 239, 27, 244, 3885, 3885, 3885, 3885, 153, 153, 80, 80, 80, 80, 26, 26 },// Russian/Cyrillic/Ukraine
{ 240, 66, 230, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Rwa/Latin/Tanzania
{ 241, 66, 74, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Saho/Latin/Eritrea
{ 242, 27, 193, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Sakha/Cyrillic/Russia
@@ -529,16 +544,16 @@ static constexpr QCalendarLocale locale_data[] = {
{ 247, 29, 110, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Sanskrit/Devanagari/India
{ 248, 93, 110, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Santali/Ol Chiki/India
{ 248, 29, 110, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Santali/Devanagari/India
- { 249, 66, 117, 922, 922, 3885, 3885, 153, 153, 83, 83, 57, 57, 26, 26 },// Sardinian/Latin/Italy
+ { 249, 66, 117, 1002, 1002, 3965, 3965, 153, 153, 83, 83, 57, 57, 26, 26 },// Sardinian/Latin/Italy
{ 251, 66, 160, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Sena/Latin/Mozambique
- { 252, 27, 207, 447, 447, 447, 447, 153, 153, 80, 80, 80, 80, 26, 26 },// Serbian/Cyrillic/Serbia
- { 252, 27, 29, 447, 447, 447, 447, 153, 153, 80, 80, 80, 80, 26, 26 },// Serbian/Cyrillic/Bosnia And Herzegovina
- { 252, 27, 126, 447, 447, 447, 447, 153, 153, 80, 80, 80, 80, 26, 26 },// Serbian/Cyrillic/Kosovo
- { 252, 27, 157, 447, 447, 447, 447, 153, 153, 80, 80, 80, 80, 26, 26 },// Serbian/Cyrillic/Montenegro
- { 252, 66, 29, 3942, 3942, 3942, 3942, 153, 153, 80, 80, 80, 80, 26, 26 },// Serbian/Latin/Bosnia And Herzegovina
- { 252, 66, 126, 3942, 3942, 3942, 3942, 153, 153, 80, 80, 80, 80, 26, 26 },// Serbian/Latin/Kosovo
- { 252, 66, 157, 3942, 3942, 3942, 3942, 153, 153, 80, 80, 80, 80, 26, 26 },// Serbian/Latin/Montenegro
- { 252, 66, 207, 3942, 3942, 3942, 3942, 153, 153, 80, 80, 80, 80, 26, 26 },// Serbian/Latin/Serbia
+ { 252, 27, 207, 527, 527, 527, 527, 153, 153, 80, 80, 80, 80, 26, 26 },// Serbian/Cyrillic/Serbia
+ { 252, 27, 29, 527, 527, 527, 527, 153, 153, 80, 80, 80, 80, 26, 26 },// Serbian/Cyrillic/Bosnia and Herzegovina
+ { 252, 27, 126, 527, 527, 527, 527, 153, 153, 80, 80, 80, 80, 26, 26 },// Serbian/Cyrillic/Kosovo
+ { 252, 27, 157, 527, 527, 527, 527, 153, 153, 80, 80, 80, 80, 26, 26 },// Serbian/Cyrillic/Montenegro
+ { 252, 66, 29, 4022, 4022, 4022, 4022, 153, 153, 80, 80, 80, 80, 26, 26 },// Serbian/Latin/Bosnia and Herzegovina
+ { 252, 66, 126, 4022, 4022, 4022, 4022, 153, 153, 80, 80, 80, 80, 26, 26 },// Serbian/Latin/Kosovo
+ { 252, 66, 157, 4022, 4022, 4022, 4022, 153, 153, 80, 80, 80, 80, 26, 26 },// Serbian/Latin/Montenegro
+ { 252, 66, 207, 4022, 4022, 4022, 4022, 153, 153, 80, 80, 80, 80, 26, 26 },// Serbian/Latin/Serbia
{ 253, 66, 230, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Shambala/Latin/Tanzania
{ 254, 66, 261, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Shona/Latin/Zimbabwe
{ 255, 141, 50, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Sichuan Yi/Yi/China
@@ -549,75 +564,80 @@ static constexpr QCalendarLocale locale_data[] = {
{ 259, 29, 110, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Sindhi/Devanagari/India
{ 260, 119, 221, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Sinhala/Sinhala/Sri Lanka
{ 261, 66, 83, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Skolt Sami/Latin/Finland
- { 262, 66, 212, 841, 841, 841, 841, 153, 153, 81, 81, 81, 81, 26, 26 },// Slovak/Latin/Slovakia
+ { 262, 66, 212, 921, 921, 921, 921, 153, 153, 81, 81, 81, 81, 26, 26 },// Slovak/Latin/Slovakia
{ 263, 66, 213, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Slovenian/Latin/Slovenia
{ 264, 66, 243, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Soga/Latin/Uganda
- { 265, 66, 215, 4022, 4022, 4022, 4022, 153, 153, 99, 99, 99, 99, 26, 26 },// Somali/Latin/Somalia
- { 265, 66, 67, 4022, 4022, 4022, 4022, 153, 153, 99, 99, 99, 99, 26, 26 },// Somali/Latin/Djibouti
- { 265, 66, 77, 4022, 4022, 4022, 4022, 153, 153, 99, 99, 99, 99, 26, 26 },// Somali/Latin/Ethiopia
- { 265, 66, 124, 4022, 4022, 4022, 4022, 153, 153, 99, 99, 99, 99, 26, 26 },// Somali/Latin/Kenya
+ { 265, 66, 215, 4102, 4102, 4102, 4102, 153, 153, 99, 99, 99, 99, 26, 26 },// Somali/Latin/Somalia
+ { 265, 66, 67, 4102, 4102, 4102, 4102, 153, 153, 99, 99, 99, 99, 26, 26 },// Somali/Latin/Djibouti
+ { 265, 66, 77, 4102, 4102, 4102, 4102, 153, 153, 99, 99, 99, 99, 26, 26 },// Somali/Latin/Ethiopia
+ { 265, 66, 124, 4102, 4102, 4102, 4102, 153, 153, 99, 99, 99, 99, 26, 26 },// Somali/Latin/Kenya
{ 266, 4, 112, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Southern Kurdish/Arabic/Iran
+ { 266, 4, 113, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Southern Kurdish/Arabic/Iraq
{ 267, 66, 225, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Southern Sami/Latin/Sweden
+ { 267, 66, 175, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Southern Sami/Latin/Norway
{ 268, 66, 216, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Southern Sotho/Latin/South Africa
+ { 268, 66, 133, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Southern Sotho/Latin/Lesotho
{ 269, 66, 216, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// South Ndebele/Latin/South Africa
- { 270, 66, 220, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Spain
- { 270, 66, 11, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Argentina
- { 270, 66, 24, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Belize
- { 270, 66, 28, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Bolivia
- { 270, 66, 32, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Brazil
- { 270, 66, 42, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Canary Islands
- { 270, 66, 47, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Ceuta And Melilla
- { 270, 66, 49, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Chile
- { 270, 66, 54, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Colombia
- { 270, 66, 59, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Costa Rica
- { 270, 66, 61, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Cuba
- { 270, 66, 69, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Dominican Republic
- { 270, 66, 70, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Ecuador
- { 270, 66, 72, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/El Salvador
- { 270, 66, 73, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Equatorial Guinea
- { 270, 66, 99, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Guatemala
- { 270, 66, 106, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Honduras
- { 270, 66, 130, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Latin America
- { 270, 66, 152, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Mexico
- { 270, 66, 168, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Nicaragua
- { 270, 66, 181, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Panama
- { 270, 66, 183, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Paraguay
- { 270, 66, 184, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Peru
- { 270, 66, 185, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Philippines
- { 270, 66, 189, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Puerto Rico
- { 270, 66, 248, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/United States
- { 270, 66, 250, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Uruguay
- { 270, 66, 254, 922, 922, 922, 922, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Venezuela
+ { 270, 66, 220, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Spain
+ { 270, 66, 11, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Argentina
+ { 270, 66, 24, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Belize
+ { 270, 66, 28, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Bolivia
+ { 270, 66, 32, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Brazil
+ { 270, 66, 42, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Canary Islands
+ { 270, 66, 47, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Ceuta and Melilla
+ { 270, 66, 49, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Chile
+ { 270, 66, 54, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Colombia
+ { 270, 66, 59, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Costa Rica
+ { 270, 66, 61, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Cuba
+ { 270, 66, 69, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Dominican Republic
+ { 270, 66, 70, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Ecuador
+ { 270, 66, 72, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/El Salvador
+ { 270, 66, 73, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Equatorial Guinea
+ { 270, 66, 99, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Guatemala
+ { 270, 66, 106, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Honduras
+ { 270, 66, 130, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Latin America
+ { 270, 66, 152, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Mexico
+ { 270, 66, 168, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Nicaragua
+ { 270, 66, 181, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Panama
+ { 270, 66, 183, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Paraguay
+ { 270, 66, 184, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Peru
+ { 270, 66, 185, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Philippines
+ { 270, 66, 189, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Puerto Rico
+ { 270, 66, 248, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/United States
+ { 270, 66, 250, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Uruguay
+ { 270, 66, 254, 1002, 1002, 1002, 1002, 153, 153, 83, 83, 83, 83, 26, 26 },// Spanish/Latin/Venezuela
{ 271, 135, 159, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Standard Moroccan Tamazight/Tifinagh/Morocco
{ 272, 66, 111, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Sundanese/Latin/Indonesia
{ 273, 66, 230, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Swahili/Latin/Tanzania
- { 273, 66, 57, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Swahili/Latin/Congo Kinshasa
+ { 273, 66, 57, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Swahili/Latin/Congo - Kinshasa
{ 273, 66, 124, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Swahili/Latin/Kenya
{ 273, 66, 243, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Swahili/Latin/Uganda
{ 274, 66, 216, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Swati/Latin/South Africa
- { 275, 66, 225, 4121, 4204, 4121, 4204, 153, 153, 83, 83, 83, 83, 26, 26 },// Swedish/Latin/Sweden
- { 275, 66, 2, 4121, 4204, 4121, 4204, 153, 153, 83, 83, 83, 83, 26, 26 },// Swedish/Latin/Aland Islands
- { 275, 66, 83, 4121, 4204, 4121, 4204, 153, 153, 83, 83, 83, 83, 26, 26 },// Swedish/Latin/Finland
+ { 274, 66, 76, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Swati/Latin/Eswatini
+ { 275, 66, 225, 4201, 4284, 4201, 4284, 153, 153, 83, 83, 83, 83, 26, 26 },// Swedish/Latin/Sweden
+ { 275, 66, 2, 4201, 4284, 4201, 4284, 153, 153, 83, 83, 83, 83, 26, 26 },// Swedish/Latin/Aland Islands
+ { 275, 66, 83, 4201, 4284, 4201, 4284, 153, 153, 83, 83, 83, 83, 26, 26 },// Swedish/Latin/Finland
{ 276, 66, 226, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Swiss German/Latin/Switzerland
{ 276, 66, 84, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Swiss German/Latin/France
{ 276, 66, 136, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Swiss German/Latin/Liechtenstein
{ 277, 123, 113, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Syriac/Syriac/Iraq
+ { 277, 123, 227, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Syriac/Syriac/Syria
{ 278, 135, 159, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Tachelhit/Tifinagh/Morocco
{ 278, 66, 159, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Tachelhit/Latin/Morocco
{ 280, 127, 255, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Tai Dam/Tai Viet/Vietnam
{ 281, 66, 124, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Taita/Latin/Kenya
- { 282, 27, 229, 4287, 4287, 4287, 4287, 153, 153, 80, 80, 80, 80, 26, 26 },// Tajik/Cyrillic/Tajikistan
- { 283, 129, 110, 4367, 4367, 4460, 4460, 153, 153, 93, 93, 63, 63, 26, 26 },// Tamil/Tamil/India
- { 283, 129, 143, 4367, 4367, 4460, 4460, 153, 153, 93, 93, 63, 63, 26, 26 },// Tamil/Tamil/Malaysia
- { 283, 129, 210, 4367, 4367, 4460, 4460, 153, 153, 93, 93, 63, 63, 26, 26 },// Tamil/Tamil/Singapore
- { 283, 129, 221, 4367, 4367, 4460, 4460, 153, 153, 93, 93, 63, 63, 26, 26 },// Tamil/Tamil/Sri Lanka
+ { 282, 27, 229, 4367, 4367, 4367, 4367, 153, 153, 80, 80, 80, 80, 26, 26 },// Tajik/Cyrillic/Tajikistan
+ { 283, 129, 110, 4447, 4447, 4540, 4540, 153, 153, 93, 93, 63, 63, 26, 26 },// Tamil/Tamil/India
+ { 283, 129, 143, 4447, 4447, 4540, 4540, 153, 153, 93, 93, 63, 63, 26, 26 },// Tamil/Tamil/Malaysia
+ { 283, 129, 210, 4447, 4447, 4540, 4540, 153, 153, 93, 93, 63, 63, 26, 26 },// Tamil/Tamil/Singapore
+ { 283, 129, 221, 4447, 4447, 4540, 4540, 153, 153, 93, 93, 63, 63, 26, 26 },// Tamil/Tamil/Sri Lanka
{ 284, 66, 228, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Taroko/Latin/Taiwan
{ 285, 66, 170, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Tasawaq/Latin/Niger
{ 286, 27, 193, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Tatar/Cyrillic/Russia
- { 287, 131, 110, 4523, 4523, 4523, 4523, 153, 153, 88, 88, 88, 88, 26, 26 },// Telugu/Telugu/India
+ { 287, 131, 110, 4603, 4603, 4603, 4603, 153, 153, 88, 88, 88, 88, 26, 26 },// Telugu/Telugu/India
{ 288, 66, 243, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Teso/Latin/Uganda
{ 288, 66, 124, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Teso/Latin/Kenya
- { 289, 133, 231, 4611, 4611, 4611, 4611, 153, 153, 98, 98, 98, 98, 26, 26 },// Thai/Thai/Thailand
+ { 289, 133, 231, 4691, 4691, 4691, 4691, 153, 153, 98, 98, 98, 98, 26, 26 },// Thai/Thai/Thailand
{ 290, 134, 50, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Tibetan/Tibetan/China
{ 290, 134, 110, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Tibetan/Tibetan/India
{ 291, 33, 74, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Tigre/Ethiopic/Eritrea
@@ -627,38 +647,44 @@ static constexpr QCalendarLocale locale_data[] = {
{ 295, 66, 235, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Tongan/Latin/Tonga
{ 296, 66, 216, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Tsonga/Latin/South Africa
{ 297, 66, 216, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Tswana/Latin/South Africa
- { 298, 66, 239, 4709, 4709, 4709, 4709, 153, 153, 80, 80, 80, 80, 26, 26 },// Turkish/Latin/Turkey
- { 298, 66, 63, 4709, 4709, 4709, 4709, 153, 153, 80, 80, 80, 80, 26, 26 },// Turkish/Latin/Cyprus
+ { 297, 66, 30, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Tswana/Latin/Botswana
+ { 298, 66, 239, 4789, 4789, 4789, 4789, 153, 153, 80, 80, 80, 80, 26, 26 },// Turkish/Latin/Turkey
+ { 298, 66, 63, 4789, 4789, 4789, 4789, 153, 153, 80, 80, 80, 80, 26, 26 },// Turkish/Latin/Cyprus
{ 299, 66, 240, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Turkmen/Latin/Turkmenistan
{ 301, 66, 169, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Tyap/Latin/Nigeria
- { 303, 27, 244, 4789, 4789, 4869, 4918, 153, 153, 80, 80, 49, 57, 26, 26 },// Ukrainian/Cyrillic/Ukraine
+ { 303, 27, 244, 4869, 4869, 4949, 4998, 153, 153, 80, 80, 49, 57, 26, 26 },// Ukrainian/Cyrillic/Ukraine
{ 304, 66, 91, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Upper Sorbian/Latin/Germany
- { 305, 4, 178, 4975, 4975, 4975, 4975, 153, 153, 66, 66, 66, 66, 26, 26 },// Urdu/Arabic/Pakistan
- { 305, 4, 110, 4975, 4975, 4975, 4975, 153, 153, 66, 66, 66, 66, 26, 26 },// Urdu/Arabic/India
+ { 305, 4, 178, 5055, 5055, 5055, 5055, 153, 153, 66, 66, 66, 66, 26, 26 },// Urdu/Arabic/Pakistan
+ { 305, 4, 110, 5055, 5055, 5055, 5055, 153, 153, 66, 66, 66, 66, 26, 26 },// Urdu/Arabic/India
{ 306, 4, 50, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Uyghur/Arabic/China
- { 307, 66, 251, 5041, 5124, 5206, 5124, 153, 153, 83, 82, 83, 82, 26, 26 },// Uzbek/Latin/Uzbekistan
+ { 307, 66, 251, 5121, 5204, 5286, 5204, 153, 153, 83, 82, 83, 82, 26, 26 },// Uzbek/Latin/Uzbekistan
{ 307, 4, 1, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Uzbek/Arabic/Afghanistan
{ 307, 27, 251, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Uzbek/Cyrillic/Uzbekistan
{ 308, 139, 134, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Vai/Vai/Liberia
{ 308, 66, 134, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Vai/Latin/Liberia
{ 309, 66, 216, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Venda/Latin/South Africa
{ 310, 66, 255, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Vietnamese/Latin/Vietnam
- { 311, 66, 258, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Volapuk/Latin/World
+ { 311, 66, 258, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Volapuk/Latin/world
{ 312, 66, 230, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Vunjo/Latin/Tanzania
{ 313, 66, 23, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Walloon/Latin/Belgium
{ 314, 66, 226, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Walser/Latin/Switzerland
{ 315, 66, 15, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Warlpiri/Latin/Australia
{ 316, 66, 246, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Welsh/Latin/United Kingdom
{ 317, 4, 178, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Western Balochi/Arabic/Pakistan
+ { 317, 4, 1, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Western Balochi/Arabic/Afghanistan
+ { 317, 4, 112, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Western Balochi/Arabic/Iran
+ { 317, 4, 176, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Western Balochi/Arabic/Oman
+ { 317, 4, 245, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Western Balochi/Arabic/United Arab Emirates
{ 318, 66, 165, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Western Frisian/Latin/Netherlands
{ 319, 33, 77, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Wolaytta/Ethiopic/Ethiopia
{ 320, 66, 206, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Wolof/Latin/Senegal
{ 321, 66, 216, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Xhosa/Latin/South Africa
{ 322, 66, 40, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Yangben/Latin/Cameroon
- { 323, 47, 258, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Yiddish/Hebrew/World
+ { 323, 47, 244, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Yiddish/Hebrew/Ukraine
{ 324, 66, 169, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Yoruba/Latin/Nigeria
{ 324, 66, 25, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Yoruba/Latin/Benin
{ 325, 66, 170, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Zarma/Latin/Niger
+ { 326, 66, 50, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Zhuang/Latin/China
{ 327, 66, 216, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Zulu/Latin/South Africa
{ 328, 66, 32, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Kaingang/Latin/Brazil
{ 329, 66, 32, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Nheengatu/Latin/Brazil
@@ -668,278 +694,470 @@ static constexpr QCalendarLocale locale_data[] = {
{ 331, 66, 91, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Northern Frisian/Latin/Germany
{ 332, 29, 110, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Rajasthani/Devanagari/India
{ 333, 27, 193, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Moksha/Cyrillic/Russia
- { 334, 66, 258, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Toki Pona/Latin/World
+ { 334, 66, 258, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Toki Pona/Latin/world
{ 335, 66, 214, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Pijin/Latin/Solomon Islands
{ 336, 66, 169, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Obolo/Latin/Nigeria
+ { 337, 4, 178, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Baluchi/Arabic/Pakistan
+ { 337, 66, 178, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Baluchi/Latin/Pakistan
+ { 338, 66, 117, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Ligurian/Latin/Italy
+ { 339, 142, 161, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Rohingya/Hanifi/Myanmar
+ { 339, 142, 20, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Rohingya/Hanifi/Bangladesh
+ { 340, 4, 178, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Torwali/Arabic/Pakistan
+ { 341, 66, 25, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Anii/Latin/Benin
+ { 342, 29, 110, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Kangri/Devanagari/India
+ { 343, 66, 117, 0, 0, 0, 0, 153, 153, 83, 83, 83, 83, 26, 26 },// Venetian/Latin/Italy
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },// trailing zeros
};
static constexpr char16_t months_data[] = {
-0x46, 0x61, 0x72, 0x76, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x4f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x73, 0x68,
-0x74, 0x3b, 0x4b, 0x68, 0x6f, 0x72, 0x64, 0x61, 0x64, 0x3b, 0x54, 0x69, 0x72, 0x3b, 0x4d, 0x6f, 0x72, 0x64, 0x61, 0x64,
-0x3b, 0x53, 0x68, 0x61, 0x68, 0x72, 0x69, 0x76, 0x61, 0x72, 0x3b, 0x4d, 0x65, 0x68, 0x72, 0x3b, 0x41, 0x62, 0x61, 0x6e,
-0x3b, 0x41, 0x7a, 0x61, 0x72, 0x3b, 0x44, 0x65, 0x79, 0x3b, 0x42, 0x61, 0x68, 0x6d, 0x61, 0x6e, 0x3b, 0x45, 0x73, 0x66,
-0x61, 0x6e, 0x64, 0x46, 0x61, 0x72, 0x3b, 0x4f, 0x72, 0x64, 0x3b, 0x4b, 0x68, 0x6f, 0x3b, 0x54, 0x69, 0x72, 0x3b, 0x4d,
-0x6f, 0x72, 0x3b, 0x53, 0x68, 0x61, 0x3b, 0x4d, 0x65, 0x68, 0x3b, 0x41, 0x62, 0x61, 0x3b, 0x41, 0x7a, 0x61, 0x3b, 0x44,
-0x65, 0x79, 0x3b, 0x42, 0x61, 0x68, 0x3b, 0x45, 0x73, 0x66, 0x46, 0x3b, 0x4f, 0x3b, 0x4b, 0x3b, 0x54, 0x3b, 0x4d, 0x3b,
-0x53, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x44, 0x3b, 0x42, 0x3b, 0x45, 0x31, 0x3b, 0x32, 0x3b, 0x33, 0x3b, 0x34,
-0x3b, 0x35, 0x3b, 0x36, 0x3b, 0x37, 0x3b, 0x38, 0x3b, 0x39, 0x3b, 0x31, 0x30, 0x3b, 0x31, 0x31, 0x3b, 0x31, 0x32, 0x641,
-0x631, 0x641, 0x631, 0x62f, 0x646, 0x3b, 0x623, 0x630, 0x631, 0x628, 0x64a, 0x647, 0x634, 0x62a, 0x3b, 0x62e, 0x631, 0x62f, 0x627, 0x62f,
-0x3b, 0x62a, 0x627, 0x631, 0x3b, 0x645, 0x631, 0x62f, 0x627, 0x62f, 0x3b, 0x634, 0x647, 0x631, 0x641, 0x627, 0x631, 0x3b, 0x645, 0x647,
-0x631, 0x3b, 0x622, 0x64a, 0x627, 0x646, 0x3b, 0x622, 0x630, 0x631, 0x3b, 0x62f, 0x64a, 0x3b, 0x628, 0x647, 0x645, 0x646, 0x3b, 0x627,
-0x633, 0x641, 0x646, 0x62f, 0x627, 0x631, 0x9ab, 0x9cd, 0x9af, 0x9be, 0x9ad, 0x9be, 0x9b0, 0x9cd, 0x9a1, 0x9bf, 0x9a8, 0x3b, 0x985, 0x9b0,
-0x9a1, 0x9bf, 0x9ac, 0x9c7, 0x9b9, 0x9c7, 0x9b6, 0x9cd, 0x9a4, 0x3b, 0x996, 0x9cb, 0x9b0, 0x9cd, 0x9a6, 0x9cd, 0x9a6, 0x3b, 0x9a4, 0x9c0,
-0x9b0, 0x3b, 0x9ae, 0x9b0, 0x9cd, 0x9af, 0x9be, 0x9a6, 0x3b, 0x9b6, 0x9be, 0x9b9, 0x9b0, 0x9bf, 0x9ac, 0x9be, 0x9b0, 0x3b, 0x9ae, 0x9c7,
-0x9b9, 0x9c7, 0x9b0, 0x3b, 0x986, 0x9ac, 0x9be, 0x9a8, 0x3b, 0x9ac, 0x9be, 0x99c, 0x9be, 0x9b0, 0x3b, 0x9a6, 0x9c7, 0x3b, 0x9ac, 0x9be,
-0x9b9, 0x9ae, 0x9be, 0x9a8, 0x3b, 0x98f, 0x9b8, 0x9ab, 0x9cd, 0x9af, 0x9be, 0x9a8, 0x9cd, 0x9a1, 0x9ab, 0x9cd, 0x9af, 0x9be, 0x9ad, 0x9be,
-0x9b0, 0x9cd, 0x9a1, 0x9bf, 0x9a8, 0x3b, 0x985, 0x9b0, 0x9a1, 0x9bf, 0x9ac, 0x9c7, 0x9b9, 0x9c7, 0x9b6, 0x9cd, 0x9a4, 0x3b, 0x996, 0x9cb,
-0x9b0, 0x9cd, 0x9a6, 0x9cd, 0x9a6, 0x3b, 0x9a4, 0x9c0, 0x9b0, 0x3b, 0x9ae, 0x9b0, 0x9cd, 0x9af, 0x9be, 0x9a6, 0x3b, 0x9b6, 0x9be, 0x9b9,
-0x9b0, 0x9bf, 0x9ac, 0x9be, 0x9b0, 0x3b, 0x9ae, 0x9c7, 0x9b9, 0x9c7, 0x9b0, 0x3b, 0x986, 0x9ac, 0x9be, 0x9a8, 0x3b, 0x986, 0x99c, 0x9be,
-0x9b0, 0x3b, 0x9a6, 0x9c7, 0x3b, 0x9ac, 0x9be, 0x9b9, 0x9ae, 0x9be, 0x9a8, 0x3b, 0x98f, 0x9b8, 0x9ab, 0x9cd, 0x9af, 0x9be, 0x9a8, 0x9cd,
-0x9a1, 0x9e7, 0x3b, 0x9e8, 0x3b, 0x9e9, 0x3b, 0x9ea, 0x3b, 0x9eb, 0x3b, 0x9ec, 0x3b, 0x9ed, 0x3b, 0x9ee, 0x3b, 0x9ef, 0x3b, 0x9e7,
-0x9e6, 0x3b, 0x9e7, 0x9e7, 0x3b, 0x9e7, 0x9e8, 0x424, 0x430, 0x440, 0x430, 0x432, 0x430, 0x434, 0x438, 0x43d, 0x3b, 0x41e, 0x440, 0x434,
-0x438, 0x431, 0x435, 0x445, 0x435, 0x448, 0x442, 0x3b, 0x41a, 0x43e, 0x440, 0x434, 0x430, 0x434, 0x3b, 0x422, 0x438, 0x440, 0x3b, 0x41c,
-0x43e, 0x440, 0x434, 0x430, 0x434, 0x3b, 0x428, 0x430, 0x445, 0x440, 0x438, 0x432, 0x430, 0x440, 0x3b, 0x41c, 0x435, 0x445, 0x440, 0x3b,
-0x410, 0x431, 0x430, 0x43d, 0x3b, 0x410, 0x437, 0x430, 0x440, 0x3b, 0x414, 0x435, 0x458, 0x3b, 0x411, 0x430, 0x445, 0x43c, 0x430, 0x43d,
-0x3b, 0x415, 0x441, 0x444, 0x430, 0x43d, 0x434, 0x31, 0x6708, 0x3b, 0x32, 0x6708, 0x3b, 0x33, 0x6708, 0x3b, 0x34, 0x6708, 0x3b, 0x35,
-0x6708, 0x3b, 0x36, 0x6708, 0x3b, 0x37, 0x6708, 0x3b, 0x38, 0x6708, 0x3b, 0x39, 0x6708, 0x3b, 0x31, 0x30, 0x6708, 0x3b, 0x31, 0x31,
-0x6708, 0x3b, 0x31, 0x32, 0x6708, 0x62e, 0x627, 0x6a9, 0x6d5, 0x644, 0x6ce, 0x648, 0x6d5, 0x3b, 0x628, 0x627, 0x646, 0x6d5, 0x645, 0x6d5,
-0x695, 0x3b, 0x62c, 0x6c6, 0x632, 0x6d5, 0x631, 0x62f, 0x627, 0x646, 0x3b, 0x67e, 0x648, 0x648, 0x634, 0x67e, 0x6d5, 0x695, 0x3b, 0x6af,
-0x6d5, 0x644, 0x627, 0x648, 0x6ce, 0x698, 0x3b, 0x62e, 0x6d5, 0x631, 0x645, 0x627, 0x646, 0x627, 0x646, 0x3b, 0x695, 0x6d5, 0x632, 0x628,
-0x6d5, 0x631, 0x3b, 0x62e, 0x6d5, 0x632, 0x6d5, 0x6b5, 0x648, 0x6d5, 0x631, 0x3b, 0x633, 0x6d5, 0x631, 0x645, 0x627, 0x648, 0x6d5, 0x632,
-0x3b, 0x628, 0x6d5, 0x641, 0x631, 0x627, 0x646, 0x628, 0x627, 0x631, 0x3b, 0x695, 0x6ce, 0x628, 0x6d5, 0x646, 0x62f, 0x627, 0x646, 0x3b,
-0x631, 0x6d5, 0x634, 0x6d5, 0x645, 0x6ce, 0x62e, 0x627, 0x6a9, 0x6d5, 0x644, 0x6ce, 0x648, 0x6d5, 0x3b, 0x6af, 0x648, 0x6b5, 0x627, 0x646,
-0x3b, 0x62c, 0x6c6, 0x632, 0x6d5, 0x631, 0x62f, 0x627, 0x646, 0x3b, 0x67e, 0x648, 0x648, 0x634, 0x67e, 0x6d5, 0x695, 0x3b, 0x6af, 0x6d5,
-0x644, 0x627, 0x648, 0x6ce, 0x698, 0x3b, 0x62e, 0x6d5, 0x631, 0x645, 0x627, 0x646, 0x627, 0x646, 0x3b, 0x695, 0x6d5, 0x632, 0x628, 0x6d5,
-0x631, 0x3b, 0x6af, 0x6d5, 0x6b5, 0x627, 0x695, 0x6ce, 0x632, 0x627, 0x646, 0x3b, 0x633, 0x6d5, 0x631, 0x645, 0x627, 0x648, 0x6d5, 0x632,
-0x3b, 0x628, 0x6d5, 0x641, 0x631, 0x627, 0x646, 0x628, 0x627, 0x631, 0x3b, 0x695, 0x6ce, 0x628, 0x6d5, 0x646, 0x62f, 0x627, 0x646, 0x3b,
-0x695, 0x6d5, 0x634, 0x6d5, 0x645, 0x6d5, 0x4e00, 0x6708, 0x3b, 0x4e8c, 0x6708, 0x3b, 0x4e09, 0x6708, 0x3b, 0x56db, 0x6708, 0x3b, 0x4e94, 0x6708,
-0x3b, 0x516d, 0x6708, 0x3b, 0x4e03, 0x6708, 0x3b, 0x516b, 0x6708, 0x3b, 0x4e5d, 0x6708, 0x3b, 0x5341, 0x6708, 0x3b, 0x5341, 0x4e00, 0x6708, 0x3b,
-0x5341, 0x4e8c, 0x6708, 0x31, 0x2e, 0x3b, 0x32, 0x2e, 0x3b, 0x33, 0x2e, 0x3b, 0x34, 0x2e, 0x3b, 0x35, 0x2e, 0x3b, 0x36, 0x2e,
-0x3b, 0x37, 0x2e, 0x3b, 0x38, 0x2e, 0x3b, 0x39, 0x2e, 0x3b, 0x31, 0x30, 0x2e, 0x3b, 0x31, 0x31, 0x2e, 0x3b, 0x31, 0x32,
-0x2e, 0x66, 0x61, 0x72, 0x76, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x6f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x161,
-0x74, 0x3b, 0x63, 0x68, 0x6f, 0x72, 0x64, 0xe1, 0x64, 0x3b, 0x74, 0xed, 0x72, 0x3b, 0x6d, 0x6f, 0x72, 0x64, 0xe1, 0x64,
-0x3b, 0x161, 0x61, 0x68, 0x72, 0xed, 0x76, 0x61, 0x72, 0x3b, 0x6d, 0x65, 0x68, 0x72, 0x3b, 0xe1, 0x62, 0xe1, 0x6e, 0x3b,
-0xe1, 0x7a, 0x61, 0x72, 0x3b, 0x64, 0x65, 0x69, 0x3b, 0x62, 0x61, 0x68, 0x6d, 0x61, 0x6e, 0x3b, 0x65, 0x73, 0x66, 0x61,
-0x6e, 0x64, 0x66, 0x61, 0x72, 0x76, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x6f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65,
-0x73, 0x68, 0x74, 0x3b, 0x6b, 0x68, 0x6f, 0x72, 0x64, 0x61, 0x64, 0x3b, 0x74, 0x69, 0x72, 0x3b, 0x6d, 0x6f, 0x72, 0x64,
-0x61, 0x64, 0x3b, 0x73, 0x68, 0x61, 0x68, 0x72, 0x69, 0x76, 0x61, 0x72, 0x3b, 0x6d, 0x65, 0x68, 0x72, 0x3b, 0x61, 0x62,
-0x61, 0x6e, 0x3b, 0x61, 0x7a, 0x61, 0x72, 0x3b, 0x64, 0x65, 0x79, 0x3b, 0x62, 0x61, 0x68, 0x6d, 0x61, 0x6e, 0x3b, 0x65,
-0x73, 0x66, 0x61, 0x6e, 0x64, 0x64, 0x7a, 0x6f, 0x76, 0x65, 0x3b, 0x64, 0x7a, 0x6f, 0x64, 0x7a, 0x65, 0x3b, 0x74, 0x65,
-0x64, 0x6f, 0x78, 0x65, 0x3b, 0x61, 0x66, 0x254, 0x66, 0x69, 0x1ebd, 0x3b, 0x64, 0x61, 0x6d, 0x25b, 0x3b, 0x6d, 0x61, 0x73,
-0x61, 0x3b, 0x73, 0x69, 0x61, 0x6d, 0x6c, 0x254, 0x6d, 0x3b, 0x64, 0x65, 0x61, 0x73, 0x69, 0x61, 0x6d, 0x69, 0x6d, 0x65,
-0x3b, 0x61, 0x6e, 0x79, 0x254, 0x6e, 0x79, 0x254, 0x3b, 0x6b, 0x65, 0x6c, 0x65, 0x3b, 0x61, 0x64, 0x65, 0x25b, 0x6d, 0x65,
-0x6b, 0x70, 0x254, 0x78, 0x65, 0x3b, 0x64, 0x7a, 0x6f, 0x6d, 0x65, 0x64, 0x7a, 0x76, 0x3b, 0x64, 0x7a, 0x64, 0x3b, 0x74,
-0x65, 0x64, 0x3b, 0x61, 0x66, 0x254, 0x3b, 0x64, 0x61, 0x6d, 0x3b, 0x6d, 0x61, 0x73, 0x3b, 0x73, 0x69, 0x61, 0x3b, 0x64,
-0x65, 0x61, 0x3b, 0x61, 0x6e, 0x79, 0x3b, 0x6b, 0x65, 0x6c, 0x3b, 0x61, 0x64, 0x65, 0x3b, 0x64, 0x7a, 0x6d, 0x66, 0x61,
-0x72, 0x76, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x6b, 0x75, 0x75, 0x3b, 0x6f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x161,
-0x74, 0x6b, 0x75, 0x75, 0x3b, 0x6b, 0x68, 0x6f, 0x72, 0x64, 0x61, 0x64, 0x6b, 0x75, 0x75, 0x3b, 0x74, 0x69, 0x72, 0x6b,
-0x75, 0x75, 0x3b, 0x6d, 0x6f, 0x72, 0x64, 0x61, 0x64, 0x6b, 0x75, 0x75, 0x3b, 0x161, 0x61, 0x68, 0x72, 0x69, 0x76, 0x61,
-0x72, 0x6b, 0x75, 0x75, 0x3b, 0x6d, 0x65, 0x68, 0x72, 0x6b, 0x75, 0x75, 0x3b, 0x61, 0x62, 0x61, 0x6e, 0x6b, 0x75, 0x75,
-0x3b, 0x61, 0x7a, 0x61, 0x72, 0x6b, 0x75, 0x75, 0x3b, 0x64, 0x65, 0x79, 0x6b, 0x75, 0x75, 0x3b, 0x62, 0x61, 0x68, 0x6d,
-0x61, 0x6e, 0x6b, 0x75, 0x75, 0x3b, 0x65, 0x73, 0x66, 0x61, 0x6e, 0x64, 0x6b, 0x75, 0x75, 0x66, 0x61, 0x72, 0x76, 0x61,
-0x72, 0x64, 0x69, 0x6e, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x6f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x161, 0x74,
-0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x6b, 0x68, 0x6f, 0x72, 0x64, 0x61, 0x64, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x74,
-0x69, 0x72, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x6d, 0x6f, 0x72, 0x64, 0x61, 0x64, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b,
-0x161, 0x61, 0x68, 0x72, 0x69, 0x76, 0x61, 0x72, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x6d, 0x65, 0x68, 0x72, 0x6b, 0x75,
-0x75, 0x74, 0x61, 0x3b, 0x61, 0x62, 0x61, 0x6e, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x61, 0x7a, 0x61, 0x72, 0x6b, 0x75,
-0x75, 0x74, 0x61, 0x3b, 0x64, 0x65, 0x79, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x62, 0x61, 0x68, 0x6d, 0x61, 0x6e, 0x6b,
-0x75, 0x75, 0x74, 0x61, 0x3b, 0x65, 0x73, 0x66, 0x61, 0x6e, 0x64, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x66, 0x61, 0x72, 0x76,
-0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x6f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x161, 0x74, 0x3b, 0x6b, 0x68, 0x6f,
-0x72, 0x64, 0x61, 0x64, 0x3b, 0x74, 0x69, 0x72, 0x3b, 0x6d, 0x6f, 0x72, 0x64, 0x61, 0x64, 0x3b, 0x161, 0x61, 0x68, 0x72,
-0x69, 0x76, 0x61, 0x72, 0x3b, 0x6d, 0x65, 0x68, 0x72, 0x3b, 0x61, 0x62, 0x61, 0x6e, 0x3b, 0x61, 0x7a, 0x61, 0x72, 0x3b,
-0x64, 0x65, 0x79, 0x3b, 0x62, 0x61, 0x68, 0x6d, 0x61, 0x6e, 0x3b, 0x65, 0x73, 0x66, 0x61, 0x6e, 0x64, 0x66, 0x61, 0x72,
-0x76, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x6f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x161, 0x74, 0x3b, 0x6b, 0x68,
-0x6f, 0x72, 0x64, 0xe2, 0x64, 0x3b, 0x74, 0x69, 0x72, 0x3b, 0x6d, 0x6f, 0x72, 0x64, 0xe2, 0x64, 0x3b, 0x161, 0x61, 0x68,
-0x72, 0x69, 0x76, 0x61, 0x72, 0x3b, 0x6d, 0x65, 0x68, 0x72, 0x3b, 0xe2, 0x62, 0xe2, 0x6e, 0x3b, 0xe2, 0x7a, 0x61, 0x72,
-0x3b, 0x64, 0x65, 0x79, 0x3b, 0x62, 0x61, 0x68, 0x6d, 0x61, 0x6e, 0x3b, 0x65, 0x73, 0x66, 0x61, 0x6e, 0x64, 0x66, 0x61,
-0x72, 0x2e, 0x3b, 0x6f, 0x72, 0x64, 0x2e, 0x3b, 0x6b, 0x68, 0x6f, 0x2e, 0x3b, 0x74, 0x69, 0x72, 0x3b, 0x6d, 0x6f, 0x72,
-0x2e, 0x3b, 0x161, 0x61, 0x68, 0x2e, 0x3b, 0x6d, 0x65, 0x68, 0x72, 0x3b, 0xe2, 0x62, 0xe2, 0x6e, 0x3b, 0xe2, 0x7a, 0x61,
-0x72, 0x3b, 0x64, 0x65, 0x79, 0x3b, 0x62, 0x61, 0x68, 0x2e, 0x3b, 0x65, 0x73, 0x66, 0x2e, 0x46, 0x61, 0x72, 0x76, 0x61,
-0x72, 0x64, 0x69, 0x6e, 0x3b, 0x4f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x161, 0x74, 0x3b, 0x4b, 0x68, 0x6f, 0x72,
-0x64, 0xe2, 0x64, 0x3b, 0x54, 0x69, 0x72, 0x3b, 0x4d, 0x6f, 0x72, 0x64, 0xe2, 0x64, 0x3b, 0x160, 0x61, 0x68, 0x72, 0x69,
-0x76, 0x61, 0x72, 0x3b, 0x4d, 0x65, 0x68, 0x72, 0x3b, 0xc2, 0x62, 0xe2, 0x6e, 0x3b, 0xc2, 0x7a, 0x61, 0x72, 0x3b, 0x44,
-0x65, 0x79, 0x3b, 0x42, 0x61, 0x68, 0x6d, 0x61, 0x6e, 0x3b, 0x45, 0x73, 0x66, 0x61, 0x6e, 0x64, 0x46, 0x61, 0x72, 0x2e,
-0x3b, 0x4f, 0x72, 0x64, 0x2e, 0x3b, 0x4b, 0x68, 0x6f, 0x2e, 0x3b, 0x54, 0x69, 0x72, 0x3b, 0x4d, 0x6f, 0x72, 0x2e, 0x3b,
-0x160, 0x61, 0x68, 0x2e, 0x3b, 0x4d, 0x65, 0x68, 0x72, 0x3b, 0xc2, 0x62, 0xe2, 0x2e, 0x3b, 0xc2, 0x7a, 0x61, 0x72, 0x3b,
-0x44, 0x65, 0x79, 0x3b, 0x42, 0x61, 0x68, 0x2e, 0x3b, 0x45, 0x73, 0x66, 0x2e, 0xd83a, 0xdd0a, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0xd83a,
-0xdd3e, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd23, 0xd83a, 0xdd2d, 0xd83a, 0xdd32, 0x3b, 0xd83a, 0xdd0c, 0xd83a, 0xdd2a, 0xd83a, 0xdd23, 0xd83a, 0xdd2d,
-0xd83a, 0xdd26, 0xd83a, 0xdd2b, 0xd83a, 0xdd38, 0xd83a, 0xdd2b, 0xd83a, 0xdd43, 0xd83a, 0xdd3c, 0x3b, 0xd83a, 0xdd1d, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0xd83a,
-0xdd23, 0xd83a, 0xdd22, 0xd83a, 0xdd23, 0x3b, 0xd83a, 0xdd1a, 0xd83a, 0xdd2d, 0xd83a, 0xdd2a, 0x3b, 0xd83a, 0xdd03, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0xd83a,
-0xdd23, 0xd83a, 0xdd22, 0xd83a, 0xdd23, 0x3b, 0xd83a, 0xdd21, 0xd83a, 0xdd22, 0xd83a, 0xdd38, 0xd83a, 0xdd2a, 0xd83a, 0xdd2d, 0xd83a, 0xdd3e, 0xd83a, 0xdd22,
-0xd83a, 0xdd2a, 0x3b, 0xd83a, 0xdd03, 0xd83a, 0xdd2b, 0xd83a, 0xdd38, 0xd83a, 0xdd2b, 0xd83a, 0xdd2a, 0x3b, 0xd83a, 0xdd00, 0xd83a, 0xdd26, 0xd83a, 0xdd22,
-0xd83a, 0xdd32, 0x3b, 0xd83a, 0xdd00, 0xd83a, 0xdd41, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0x3b, 0xd83a, 0xdd01, 0xd83a, 0xdd2b, 0xd83a, 0xdd34, 0x3b, 0xd83a,
-0xdd04, 0xd83a, 0xdd22, 0xd83a, 0xdd38, 0xd83a, 0xdd25, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0x3b, 0xd83a, 0xdd09, 0xd83a, 0xdd27, 0xd83a, 0xdd2c, 0xd83a, 0xdd22,
-0xd83a, 0xdd32, 0xd83a, 0xdd23, 0xd83a, 0xdd51, 0x3b, 0xd83a, 0xdd52, 0x3b, 0xd83a, 0xdd53, 0x3b, 0xd83a, 0xdd54, 0x3b, 0xd83a, 0xdd55, 0x3b, 0xd83a,
-0xdd56, 0x3b, 0xd83a, 0xdd57, 0x3b, 0xd83a, 0xdd58, 0x3b, 0xd83a, 0xdd59, 0x3b, 0xd83a, 0xdd51, 0xd83a, 0xdd50, 0x3b, 0xd83a, 0xdd51, 0xd83a, 0xdd51,
-0x3b, 0xd83a, 0xdd51, 0xd83a, 0xdd52, 0x10e4, 0x10d0, 0x10e0, 0x10d5, 0x10d0, 0x10e0, 0x10d3, 0x10d8, 0x10dc, 0x10d8, 0x3b, 0x10dd, 0x10e0, 0x10d3, 0x10d8,
-0x10d1, 0x10d4, 0x10f0, 0x10d4, 0x10e8, 0x10d7, 0x10d8, 0x3b, 0x10ee, 0x10dd, 0x10e0, 0x10d3, 0x10d0, 0x10d3, 0x10d8, 0x3b, 0x10d7, 0x10d8, 0x10e0, 0x10d8,
-0x3b, 0x10db, 0x10dd, 0x10e0, 0x10d3, 0x10d0, 0x10d3, 0x10d8, 0x3b, 0x10e8, 0x10d0, 0x10f0, 0x10e0, 0x10d8, 0x10d5, 0x10d0, 0x10e0, 0x10d8, 0x3b, 0x10db,
-0x10d4, 0x10f0, 0x10e0, 0x10d8, 0x3b, 0x10d0, 0x10d1, 0x10d0, 0x10dc, 0x10d8, 0x3b, 0x10d0, 0x10d6, 0x10d0, 0x10e0, 0x10d8, 0x3b, 0x10d3, 0x10d4, 0x10d8,
-0x3b, 0x10d1, 0x10d0, 0x10f0, 0x10db, 0x10d0, 0x10dc, 0x10d8, 0x3b, 0x10d4, 0x10e1, 0x10e4, 0x10d0, 0x10dc, 0x10d3, 0x10d8, 0x46, 0x61, 0x72, 0x77,
-0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x4f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x73, 0x63, 0x68, 0x74, 0x3b, 0x43,
-0x68, 0x6f, 0x72, 0x64, 0x101, 0x64, 0x3b, 0x54, 0x69, 0x72, 0x3b, 0x4d, 0x6f, 0x72, 0x64, 0x101, 0x64, 0x3b, 0x53, 0x63,
-0x68, 0x61, 0x68, 0x72, 0x69, 0x77, 0x61, 0x72, 0x3b, 0x4d, 0x65, 0x68, 0x72, 0x3b, 0x100, 0x62, 0x101, 0x6e, 0x3b, 0x100,
-0x73, 0x61, 0x72, 0x3b, 0x44, 0xe9, 0x69, 0x3b, 0x42, 0x61, 0x68, 0x6d, 0x61, 0x6e, 0x3b, 0x45, 0x73, 0x73, 0x66, 0x61,
-0x6e, 0x64, 0xaab, 0xabe, 0xab0, 0xacd, 0xab5, 0xabe, 0xab0, 0xacd, 0xaa6, 0xabf, 0xaa8, 0x3b, 0xa93, 0xab0, 0xaa1, 0xac0, 0xaac, 0xac7,
-0xab9, 0xac7, 0xab6, 0xacd, 0xa9f, 0x3b, 0xa96, 0xacb, 0xab0, 0xaa6, 0xabe, 0xaa6, 0x3b, 0xaa4, 0xabf, 0xab0, 0x3b, 0xaae, 0xacb, 0xab0,
-0xacd, 0xaa6, 0xabe, 0xaa6, 0x3b, 0xab6, 0xabe, 0xab9, 0xab0, 0xabf, 0xab5, 0xab0, 0x3b, 0xaae, 0xac7, 0xab9, 0xab0, 0x3b, 0xa85, 0xaac,
-0xabe, 0xaa8, 0x3b, 0xa85, 0xa9d, 0xabe, 0xab0, 0x3b, 0xaa1, 0xac7, 0xaaf, 0x3b, 0xaac, 0xabe, 0xab9, 0xaae, 0xac7, 0xaa8, 0x3b, 0xa8f,
-0xab8, 0xacd, 0xaab, 0xabe, 0xaa8, 0xacd, 0xaa1, 0x5e4, 0x5e8, 0x5d5, 0x5e8, 0x5d3, 0x5d9, 0x5df, 0x3b, 0x5d0, 0x5e8, 0x5d3, 0x5d9, 0x5d1,
-0x5d4, 0x5e9, 0x5ea, 0x3b, 0x5d7, 0x5f3, 0x5e8, 0x5d3, 0x5d0, 0x5d3, 0x3b, 0x5ea, 0x5d9, 0x5e8, 0x3b, 0x5de, 0x5e8, 0x5d3, 0x5d0, 0x5d3,
-0x3b, 0x5e9, 0x5d4, 0x5e8, 0x5d9, 0x5d5, 0x5e8, 0x3b, 0x5de, 0x5d4, 0x5e8, 0x3b, 0x5d0, 0x5d1, 0x5d0, 0x5df, 0x3b, 0x5d0, 0x5d3, 0x5f3,
-0x5e8, 0x3b, 0x5d3, 0x5d9, 0x3b, 0x5d1, 0x5d4, 0x5de, 0x5df, 0x3b, 0x5d0, 0x5e1, 0x5e4, 0x5e0, 0x5d3, 0x92b, 0x930, 0x94d, 0x935, 0x93e,
-0x926, 0x93f, 0x928, 0x3b, 0x913, 0x930, 0x94d, 0x926, 0x93f, 0x935, 0x947, 0x939, 0x947, 0x938, 0x94d, 0x91f, 0x3b, 0x916, 0x94b, 0x930,
-0x930, 0x94d, 0x926, 0x93e, 0x926, 0x3b, 0x91f, 0x93f, 0x930, 0x3b, 0x92e, 0x94b, 0x930, 0x926, 0x93e, 0x926, 0x3b, 0x936, 0x93e, 0x939,
-0x930, 0x940, 0x935, 0x930, 0x94d, 0x3b, 0x92e, 0x947, 0x939, 0x930, 0x3b, 0x905, 0x935, 0x928, 0x3b, 0x905, 0x91c, 0x93c, 0x930, 0x3b,
-0x921, 0x947, 0x3b, 0x92c, 0x939, 0x92e, 0x928, 0x3b, 0x908, 0x938, 0x94d, 0x92b, 0x928, 0x94d, 0x926, 0x94d, 0x30d5, 0x30a1, 0x30eb, 0x30f4,
-0x30a1, 0x30eb, 0x30c7, 0x30a3, 0x30fc, 0x30f3, 0x3b, 0x30aa, 0x30eb, 0x30c7, 0x30a3, 0x30fc, 0x30d9, 0x30d8, 0x30b7, 0x30e5, 0x30c8, 0x3b, 0x30db, 0x30eb,
-0x30c0, 0x30fc, 0x30c9, 0x3b, 0x30c6, 0x30a3, 0x30fc, 0x30eb, 0x3b, 0x30e2, 0x30eb, 0x30c0, 0x30fc, 0x30c9, 0x3b, 0x30b7, 0x30e3, 0x30cf, 0x30ea, 0x30fc,
-0x30f4, 0x30a1, 0x30eb, 0x3b, 0x30e1, 0x30d5, 0x30eb, 0x3b, 0x30a2, 0x30fc, 0x30d0, 0x30fc, 0x30f3, 0x3b, 0x30a2, 0x30fc, 0x30b6, 0x30eb, 0x3b, 0x30c7,
-0x30a4, 0x3b, 0x30d0, 0x30d5, 0x30de, 0x30f3, 0x3b, 0x30a8, 0x30b9, 0x30d5, 0x30a1, 0x30f3, 0x30c9, 0xcab, 0xcb0, 0xccd, 0xcb5, 0xcb0, 0xccd, 0xca6,
-0xcbf, 0xca8, 0xccd, 0x3b, 0xc93, 0xcb0, 0xccd, 0xca6, 0xcbf, 0xcac, 0xcc6, 0xcb9, 0xcc6, 0xcb6, 0xccd, 0xc9f, 0xccd, 0x3b, 0xc96, 0xccb,
-0xcb0, 0xccd, 0xca1, 0xcbe, 0xca6, 0xccd, 0x3b, 0xc9f, 0xcbf, 0xcb0, 0xccd, 0x3b, 0xcae, 0xcca, 0xcb0, 0xccd, 0xca6, 0xcbe, 0xca6, 0xccd,
-0x3b, 0xcb6, 0xcb9, 0xcb0, 0xcbf, 0xcb5, 0xcbe, 0xcb0, 0xccd, 0x3b, 0xcae, 0xcc6, 0xcb9, 0xccd, 0xcb0, 0xccd, 0x3b, 0xc85, 0xcac, 0xca8,
-0xccd, 0x3b, 0xc85, 0xc9d, 0xcb0, 0xccd, 0x3b, 0xca1, 0xcc7, 0x3b, 0xcac, 0xcb9, 0xccd, 0xcae, 0xca8, 0xccd, 0x3b, 0xc8e, 0xcb8, 0xccd,
-0xcab, 0xcbe, 0xc82, 0xca1, 0xccd, 0x424, 0x430, 0x440, 0x432, 0x430, 0x440, 0x434, 0x438, 0x43d, 0x3b, 0x41e, 0x440, 0x434, 0x438, 0x431,
-0x435, 0x445, 0x435, 0x448, 0x442, 0x3b, 0x425, 0x43e, 0x440, 0x434, 0x430, 0x434, 0x3b, 0x422, 0x438, 0x440, 0x3b, 0x41c, 0x43e, 0x440,
-0x434, 0x430, 0x434, 0x3b, 0x428, 0x430, 0x445, 0x440, 0x438, 0x432, 0x430, 0x440, 0x3b, 0x41c, 0x435, 0x445, 0x440, 0x3b, 0x410, 0x431,
-0x430, 0x43d, 0x3b, 0x410, 0x437, 0x430, 0x440, 0x3b, 0x414, 0x435, 0x439, 0x3b, 0x411, 0x430, 0x445, 0x43c, 0x430, 0x43d, 0x3b, 0x42d,
-0x441, 0x444, 0x430, 0x43d, 0x434, 0xd654, 0xb974, 0xbc14, 0xb518, 0x3b, 0xc624, 0xb974, 0xb514, 0xbca0, 0xd5e4, 0xc26c, 0xd2b8, 0x3b, 0xd638, 0xb974,
-0xb2e4, 0xb4dc, 0x3b, 0xd2f0, 0xb974, 0x3b, 0xbaa8, 0xb974, 0xb2e4, 0xb4dc, 0x3b, 0xc0e4, 0xd750, 0xb9ac, 0xbc14, 0xb974, 0x3b, 0xba54, 0xd750, 0xb974,
-0x3b, 0xc544, 0xbc18, 0x3b, 0xc544, 0xc790, 0xb974, 0x3b, 0xb2e4, 0xc774, 0x3b, 0xbc14, 0xd750, 0xb9cc, 0x3b, 0xc5d0, 0xc2a4, 0xd310, 0xb4dc, 0xe9f,
-0xea3, 0xeb2, 0xea7, 0xeb2, 0xe94, 0xeb4, 0xe99, 0x3b, 0xead, 0xecd, 0xea3, 0xe94, 0xeb5, 0xe9a, 0xeb5, 0xec0, 0xeab, 0xea3, 0xe94, 0x3b,
-0xe84, 0xecd, 0xea3, 0xec0, 0xe94, 0xe94, 0x3b, 0xec1, 0xe95, 0xea3, 0x3b, 0xea1, 0xecd, 0xea3, 0xec0, 0xe94, 0xe94, 0x3b, 0xe8a, 0xeb2,
-0xea3, 0xeab, 0xeb4, 0xea7, 0xeb2, 0x3b, 0xec0, 0xea1, 0xeb5, 0x3b, 0xead, 0xeb2, 0xe9a, 0xeb2, 0xe99, 0x3b, 0xead, 0xeb2, 0xe8a, 0xeb2,
-0xea3, 0x3b, 0xe94, 0xeb5, 0xea3, 0x3b, 0xe9a, 0xea3, 0xeb2, 0xec1, 0xea1, 0xe99, 0x3b, 0xec0, 0xead, 0xeaa, 0xe9f, 0xeb2, 0xe99, 0xe9f,
-0xea3, 0xeb2, 0xea7, 0xeb2, 0xe94, 0xeb4, 0xe99, 0x3b, 0xead, 0xecd, 0xea3, 0xe94, 0xeb5, 0xe9a, 0xeb5, 0xec0, 0xeab, 0xeae, 0xe94, 0x3b,
-0xe84, 0xecd, 0xea3, 0xec0, 0xe94, 0xe94, 0x3b, 0xec1, 0xe95, 0xea3, 0x3b, 0xea1, 0xecd, 0xea3, 0xec0, 0xe94, 0xe94, 0x3b, 0xe8a, 0xeb2,
-0xea3, 0xea5, 0xeb4, 0xea7, 0xeb2, 0x3b, 0xec0, 0xea1, 0xeb5, 0x3b, 0xead, 0xeb2, 0xe9a, 0xeb2, 0xe99, 0x3b, 0xead, 0xeb2, 0xe8a, 0xeb2,
-0x3b, 0xe94, 0xeb5, 0xea3, 0x3b, 0xe9a, 0xea3, 0xeb2, 0xea1, 0xeb2, 0xe99, 0x3b, 0xec0, 0xead, 0xeaa, 0xe9f, 0xeb2, 0xe99, 0xe9f, 0xeb2,
-0xea3, 0xea7, 0xeb2, 0xe94, 0xeb4, 0xe99, 0x3b, 0xead, 0xecd, 0xea3, 0xe94, 0xeb5, 0xe9a, 0xeb5, 0xec0, 0xeab, 0xea3, 0xe94, 0x3b, 0xe84,
-0xecd, 0xea3, 0xec0, 0xe94, 0xe94, 0x3b, 0xec1, 0xe95, 0xea3, 0x3b, 0xea1, 0xecd, 0xea3, 0xec0, 0xe94, 0xe94, 0x3b, 0xe8a, 0xeb2, 0xea3,
-0xeab, 0xeb4, 0xea7, 0xeb2, 0x3b, 0xec0, 0xea1, 0xeb5, 0x3b, 0xead, 0xeb2, 0xe9a, 0xeb2, 0xe99, 0x3b, 0xead, 0xeb2, 0xe8a, 0xeb2, 0x3b,
-0xe94, 0xeb5, 0xea3, 0x3b, 0xe9a, 0xea3, 0xeb2, 0xea1, 0xeb2, 0xe99, 0x3b, 0xec0, 0xead, 0xeaa, 0xe9f, 0xeb2, 0xe99, 0x66, 0x61, 0x72,
-0x76, 0x61, 0x72, 0x64, 0x12b, 0x6e, 0x73, 0x3b, 0x6f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x161, 0x74, 0x73, 0x3b,
-0x68, 0x6f, 0x72, 0x64, 0x101, 0x64, 0x73, 0x3b, 0x74, 0x12b, 0x72, 0x73, 0x3b, 0x6d, 0x6f, 0x72, 0x64, 0x101, 0x64, 0x73,
-0x3b, 0x161, 0x61, 0x68, 0x72, 0x69, 0x76, 0x113, 0x72, 0x73, 0x3b, 0x6d, 0x65, 0x68, 0x72, 0x73, 0x3b, 0x61, 0x62, 0x61,
-0x6e, 0x73, 0x3b, 0x61, 0x7a, 0x65, 0x72, 0x73, 0x3b, 0x64, 0x65, 0x6a, 0x73, 0x3b, 0x62, 0x61, 0x68, 0x6d, 0x61, 0x6e,
-0x73, 0x3b, 0x65, 0x73, 0x66, 0x61, 0x6e, 0x64, 0x73, 0x444, 0x430, 0x440, 0x432, 0x430, 0x440, 0x434, 0x438, 0x43d, 0x3b, 0x43e,
-0x440, 0x434, 0x438, 0x431, 0x435, 0x445, 0x435, 0x448, 0x442, 0x3b, 0x43a, 0x43e, 0x440, 0x434, 0x430, 0x434, 0x3b, 0x442, 0x438, 0x440,
-0x3b, 0x43c, 0x43e, 0x440, 0x434, 0x430, 0x434, 0x3b, 0x448, 0x430, 0x445, 0x440, 0x438, 0x432, 0x430, 0x440, 0x3b, 0x43c, 0x435, 0x440,
-0x3b, 0x430, 0x431, 0x430, 0x43d, 0x3b, 0x430, 0x437, 0x430, 0x440, 0x3b, 0x434, 0x435, 0x458, 0x3b, 0x431, 0x430, 0x445, 0x43c, 0x430,
-0x43d, 0x3b, 0x435, 0x441, 0x444, 0x430, 0x43d, 0x434, 0xd2b, 0xd7c, 0xd35, 0xd3e, 0xd7c, 0xd26, 0xd3f, 0xd7b, 0x3b, 0xd13, 0xd7c, 0xd21,
-0xd3f, 0xd2c, 0xd46, 0xd39, 0xd46, 0xd37, 0xd4d, 0x200c, 0xd31, 0xd4d, 0xd31, 0xd4d, 0x3b, 0xd16, 0xd4b, 0xd7c, 0xd26, 0xd3e, 0xd26, 0xd4d,
-0x3b, 0xd1f, 0xd3f, 0xd7c, 0x3b, 0xd2e, 0xd4b, 0xd7c, 0xd26, 0xd3e, 0xd26, 0xd4d, 0x3b, 0xd37, 0xd39, 0xd4d, 0x200c, 0xd30, 0xd3f, 0xd35,
-0xd3e, 0xd7c, 0x3b, 0xd2e, 0xd46, 0xd39, 0xd7c, 0x3b, 0xd05, 0xd2c, 0xd3e, 0xd7b, 0x3b, 0xd05, 0xd38, 0xd7c, 0x3b, 0xd21, 0xd46, 0xd2f,
-0xd4d, 0x3b, 0xd2c, 0xd39, 0xd4d, 0x200c, 0xd2e, 0xd3e, 0xd7b, 0x3b, 0xd0e, 0xd38, 0xd4d, 0x200c, 0xd2b, 0xd3e, 0xd7b, 0xd21, 0xd4d, 0xd2b,
-0x2e, 0x3b, 0xd13, 0x2e, 0x3b, 0xd16, 0xd4b, 0x3b, 0xd1f, 0xd3f, 0x2e, 0x3b, 0xd2e, 0xd4b, 0x2e, 0x3b, 0xd37, 0x2e, 0x3b, 0xd2e,
-0xd46, 0x2e, 0x3b, 0xd05, 0x2e, 0x3b, 0xd05, 0x2e, 0x3b, 0xd21, 0xd46, 0x2e, 0x3b, 0xd2c, 0x2e, 0x3b, 0xd0e, 0x2e, 0x92b, 0x930,
-0x935, 0x930, 0x926, 0x93f, 0x928, 0x3b, 0x913, 0x930, 0x94d, 0x926, 0x93f, 0x92c, 0x947, 0x939, 0x947, 0x936, 0x94d, 0x924, 0x3b, 0x916,
-0x94b, 0x930, 0x926, 0x93e, 0x926, 0x3b, 0x924, 0x93f, 0x930, 0x3b, 0x92e, 0x94b, 0x930, 0x926, 0x93e, 0x926, 0x3b, 0x936, 0x93e, 0x939,
-0x930, 0x940, 0x935, 0x93e, 0x930, 0x3b, 0x92e, 0x947, 0x939, 0x947, 0x930, 0x3b, 0x905, 0x92c, 0x93e, 0x928, 0x3b, 0x905, 0x91d, 0x93e,
-0x930, 0x3b, 0x926, 0x947, 0x3b, 0x92c, 0x93e, 0x939, 0x92e, 0x93e, 0x928, 0x3b, 0x90f, 0x938, 0x92b, 0x93e, 0x902, 0x926, 0x967, 0x3b,
-0x968, 0x3b, 0x969, 0x3b, 0x96a, 0x3b, 0x96b, 0x3b, 0x96c, 0x3b, 0x96d, 0x3b, 0x96e, 0x3b, 0x96f, 0x3b, 0x967, 0x966, 0x3b, 0x967,
-0x967, 0x3b, 0x967, 0x968, 0x648, 0x631, 0x6cc, 0x3b, 0x63a, 0x648, 0x6cc, 0x6cc, 0x3b, 0x63a, 0x628, 0x631, 0x6af, 0x648, 0x644, 0x6cc,
-0x3b, 0x686, 0x646, 0x6af, 0x627, 0x69a, 0x3b, 0x632, 0x645, 0x631, 0x6cc, 0x3b, 0x648, 0x696, 0x6cc, 0x3b, 0x62a, 0x644, 0x647, 0x3b,
-0x644, 0x693, 0x645, 0x3b, 0x644, 0x6cc, 0x646, 0x62f, 0x6cd, 0x3b, 0x645, 0x631, 0x63a, 0x648, 0x645, 0x6cc, 0x3b, 0x633, 0x644, 0x648,
-0x627, 0x63a, 0x647, 0x3b, 0x6a9, 0x628, 0x6f1, 0x3b, 0x6f2, 0x3b, 0x6f3, 0x3b, 0x6f4, 0x3b, 0x6f5, 0x3b, 0x6f6, 0x3b, 0x6f7, 0x3b,
-0x6f8, 0x3b, 0x6f9, 0x3b, 0x6f1, 0x6f0, 0x3b, 0x6f1, 0x6f1, 0x3b, 0x6f1, 0x6f2, 0x641, 0x631, 0x648, 0x631, 0x62f, 0x6cc, 0x646, 0x3b,
-0x627, 0x631, 0x62f, 0x6cc, 0x628, 0x647, 0x634, 0x62a, 0x3b, 0x62e, 0x631, 0x62f, 0x627, 0x62f, 0x3b, 0x62a, 0x6cc, 0x631, 0x3b, 0x645,
-0x631, 0x62f, 0x627, 0x62f, 0x3b, 0x634, 0x647, 0x631, 0x6cc, 0x648, 0x631, 0x3b, 0x645, 0x647, 0x631, 0x3b, 0x622, 0x628, 0x627, 0x646,
-0x3b, 0x622, 0x630, 0x631, 0x3b, 0x62f, 0x6cc, 0x3b, 0x628, 0x647, 0x645, 0x646, 0x3b, 0x627, 0x633, 0x641, 0x646, 0x62f, 0x641, 0x3b,
-0x627, 0x3b, 0x62e, 0x3b, 0x62a, 0x3b, 0x645, 0x3b, 0x634, 0x3b, 0x645, 0x3b, 0x622, 0x3b, 0x622, 0x3b, 0x62f, 0x3b, 0x628, 0x3b,
-0x627, 0x62d, 0x645, 0x644, 0x3b, 0x62b, 0x648, 0x631, 0x3b, 0x62c, 0x648, 0x632, 0x627, 0x3b, 0x633, 0x631, 0x637, 0x627, 0x646, 0x3b,
-0x627, 0x633, 0x62f, 0x3b, 0x633, 0x646, 0x628, 0x644, 0x647, 0x654, 0x3b, 0x645, 0x6cc, 0x632, 0x627, 0x646, 0x3b, 0x639, 0x642, 0x631,
-0x628, 0x3b, 0x642, 0x648, 0x633, 0x3b, 0x62c, 0x62f, 0x6cc, 0x3b, 0x62f, 0x644, 0x648, 0x3b, 0x62d, 0x648, 0x62a, 0x62d, 0x3b, 0x62b,
-0x3b, 0x62c, 0x3b, 0x633, 0x3b, 0x627, 0x3b, 0x633, 0x3b, 0x645, 0x3b, 0x639, 0x3b, 0x642, 0x3b, 0x62c, 0x3b, 0x62f, 0x3b, 0x62d,
-0x46, 0x61, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x4f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x73, 0x7a,
-0x74, 0x3b, 0x43, 0x68, 0x6f, 0x72, 0x64, 0x101, 0x64, 0x3b, 0x54, 0x69, 0x72, 0x3b, 0x4d, 0x6f, 0x72, 0x64, 0x101, 0x64,
-0x3b, 0x53, 0x7a, 0x61, 0x68, 0x72, 0x69, 0x77, 0x61, 0x72, 0x3b, 0x4d, 0x65, 0x68, 0x72, 0x3b, 0x100, 0x62, 0x101, 0x6e,
-0x3b, 0x100, 0x73, 0x61, 0x72, 0x3b, 0x44, 0xe9, 0x69, 0x3b, 0x42, 0x61, 0x68, 0x6d, 0x61, 0x6e, 0x3b, 0x45, 0x73, 0x66,
-0x61, 0x6e, 0x64, 0xa2b, 0xa3e, 0xa30, 0xa35, 0xa30, 0xa21, 0xa40, 0xa28, 0x3b, 0xa14, 0xa30, 0xa21, 0xa3e, 0xa08, 0xa2c, 0xa39, 0xa48,
-0xa38, 0xa3c, 0xa1f, 0x3b, 0xa16, 0xa4b, 0xa21, 0xa30, 0xa21, 0x3b, 0xa1f, 0xa3f, 0xa30, 0x3b, 0xa2e, 0xa4b, 0xa30, 0xa21, 0xa3e, 0xa26,
-0x3b, 0xa38, 0xa3c, 0xa30, 0xa3e, 0xa07, 0xa35, 0xa30, 0x3b, 0xa2e, 0xa47, 0xa39, 0xa30, 0x3b, 0xa05, 0xa2c, 0xa3e, 0xa28, 0x3b, 0xa05,
-0xa1c, 0xa3c, 0xa3e, 0xa30, 0x3b, 0xa21, 0xa47, 0xa05, 0x3b, 0xa2c, 0xa3e, 0xa39, 0xa2e, 0xa28, 0x3b, 0xa10, 0xa38, 0xa2b, 0xa70, 0xa21,
-0x46, 0x61, 0x72, 0x76, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x4f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x73, 0x68,
-0x74, 0x3b, 0x4b, 0x68, 0x6f, 0x72, 0x64, 0x61, 0x64, 0x3b, 0x54, 0x69, 0x72, 0x3b, 0x41, 0x2d, 0x4d, 0x6f, 0x72, 0x64,
-0x61, 0x64, 0x3b, 0x53, 0x68, 0x61, 0x68, 0x72, 0x69, 0x76, 0x61, 0x72, 0x3b, 0x4d, 0x65, 0x68, 0x72, 0x3b, 0x41, 0x62,
-0x61, 0x6e, 0x3b, 0x41, 0x7a, 0x61, 0x72, 0x3b, 0x44, 0x65, 0x79, 0x3b, 0x42, 0x61, 0x68, 0x6d, 0x61, 0x6e, 0x3b, 0x45,
-0x73, 0x66, 0x61, 0x6e, 0x64, 0x444, 0x430, 0x440, 0x432, 0x430, 0x440, 0x434, 0x438, 0x43d, 0x3b, 0x43e, 0x440, 0x434, 0x438, 0x431,
-0x435, 0x445, 0x435, 0x448, 0x442, 0x3b, 0x445, 0x43e, 0x440, 0x434, 0x430, 0x434, 0x3b, 0x442, 0x438, 0x440, 0x3b, 0x43c, 0x43e, 0x440,
-0x434, 0x430, 0x434, 0x3b, 0x448, 0x430, 0x445, 0x440, 0x438, 0x432, 0x435, 0x440, 0x3b, 0x43c, 0x435, 0x445, 0x440, 0x3b, 0x430, 0x431,
-0x430, 0x43d, 0x3b, 0x430, 0x437, 0x435, 0x440, 0x3b, 0x434, 0x435, 0x439, 0x3b, 0x431, 0x430, 0x445, 0x43c, 0x430, 0x43d, 0x3b, 0x44d,
-0x441, 0x444, 0x430, 0x43d, 0x434, 0x66, 0x61, 0x72, 0x2e, 0x3b, 0x6f, 0x72, 0x64, 0x2e, 0x3b, 0x6b, 0x68, 0x6f, 0x2e, 0x3b,
-0x74, 0x69, 0x72, 0x3b, 0x6d, 0x6f, 0x72, 0x2e, 0x3b, 0x73, 0x68, 0x61, 0x2e, 0x3b, 0x6d, 0x65, 0x68, 0x72, 0x3b, 0x61,
-0x62, 0x61, 0x6e, 0x3b, 0x61, 0x7a, 0x61, 0x72, 0x3b, 0x64, 0x65, 0x79, 0x3b, 0x62, 0x61, 0x68, 0x2e, 0x3b, 0x65, 0x73,
-0x66, 0x2e, 0x46, 0x61, 0x72, 0x61, 0x76, 0x61, 0x64, 0x69, 0x6e, 0x3b, 0x4f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65,
-0x161, 0x74, 0x3b, 0x4b, 0x6f, 0x72, 0x64, 0x61, 0x64, 0x3b, 0x54, 0x69, 0x72, 0x3b, 0x4d, 0x6f, 0x72, 0x64, 0x61, 0x64,
-0x3b, 0x160, 0x61, 0x68, 0x72, 0x69, 0x76, 0x61, 0x72, 0x3b, 0x4d, 0x65, 0x68, 0x72, 0x3b, 0x41, 0x62, 0x61, 0x6e, 0x3b,
-0x41, 0x7a, 0x61, 0x72, 0x3b, 0x44, 0x65, 0x6a, 0x3b, 0x42, 0x61, 0x68, 0x6d, 0x61, 0x6e, 0x3b, 0x45, 0x73, 0x66, 0x61,
-0x6e, 0x64, 0x4a, 0x61, 0x6e, 0x61, 0x61, 0x79, 0x6f, 0x3b, 0x46, 0x65, 0x65, 0x62, 0x72, 0x61, 0x61, 0x79, 0x6f, 0x3b,
-0x4d, 0x61, 0x61, 0x72, 0x73, 0x6f, 0x3b, 0x41, 0x62, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x61, 0x61, 0x79, 0x6f, 0x3b, 0x4a,
-0x75, 0x75, 0x6e, 0x3b, 0x4c, 0x75, 0x75, 0x6c, 0x69, 0x79, 0x6f, 0x3b, 0x41, 0x67, 0x6f, 0x6f, 0x73, 0x74, 0x6f, 0x3b,
-0x53, 0x61, 0x62, 0x74, 0x65, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x3b,
-0x4e, 0x6f, 0x6f, 0x66, 0x65, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x44, 0x69, 0x69, 0x73, 0x65, 0x65, 0x6d, 0x62, 0x61,
-0x72, 0x46, 0x61, 0x72, 0x76, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x4f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x73,
-0x68, 0x74, 0x3b, 0x4b, 0x68, 0x6f, 0x72, 0x64, 0x101, 0x64, 0x3b, 0x54, 0x69, 0x72, 0x3b, 0x4d, 0x6f, 0x72, 0x64, 0x101,
-0x64, 0x3b, 0x53, 0x68, 0x61, 0x68, 0x72, 0x69, 0x76, 0x61, 0x72, 0x3b, 0x4d, 0x65, 0x68, 0x72, 0x3b, 0x100, 0x62, 0x101,
-0x6e, 0x3b, 0x100, 0x7a, 0x61, 0x72, 0x3b, 0x44, 0x65, 0x79, 0x3b, 0x42, 0x61, 0x68, 0x6d, 0x61, 0x6e, 0x3b, 0x45, 0x73,
-0x66, 0x61, 0x6e, 0x64, 0x66, 0x61, 0x72, 0x76, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x6f, 0x72, 0x64, 0x69, 0x62, 0x65,
-0x68, 0x65, 0x73, 0x68, 0x74, 0x3b, 0x6b, 0x68, 0x6f, 0x72, 0x64, 0x101, 0x64, 0x3b, 0x74, 0x69, 0x72, 0x3b, 0x6d, 0x6f,
-0x72, 0x64, 0x101, 0x64, 0x3b, 0x73, 0x68, 0x61, 0x68, 0x72, 0x69, 0x76, 0x61, 0x72, 0x3b, 0x6d, 0x65, 0x68, 0x72, 0x3b,
-0x101, 0x62, 0x101, 0x6e, 0x3b, 0x101, 0x7a, 0x61, 0x72, 0x3b, 0x64, 0x65, 0x79, 0x3b, 0x62, 0x61, 0x68, 0x6d, 0x61, 0x6e,
-0x3b, 0x65, 0x73, 0x66, 0x61, 0x6e, 0x64, 0x444, 0x430, 0x440, 0x432, 0x430, 0x440, 0x434, 0x438, 0x43d, 0x3b, 0x443, 0x440, 0x434,
-0x438, 0x431, 0x438, 0x4b3, 0x438, 0x448, 0x442, 0x3b, 0x445, 0x443, 0x440, 0x434, 0x43e, 0x434, 0x3b, 0x442, 0x438, 0x440, 0x3b, 0x43c,
-0x443, 0x440, 0x434, 0x43e, 0x434, 0x3b, 0x448, 0x430, 0x4b3, 0x440, 0x438, 0x432, 0x430, 0x440, 0x3b, 0x43c, 0x435, 0x4b3, 0x440, 0x3b,
-0x43e, 0x431, 0x43e, 0x43d, 0x3b, 0x43e, 0x437, 0x430, 0x440, 0x3b, 0x434, 0x435, 0x439, 0x3b, 0x431, 0x430, 0x4b3, 0x43c, 0x430, 0x43d,
-0x3b, 0x438, 0x441, 0x444, 0x430, 0x43d, 0x434, 0xb83, 0xbaa, 0xbb0, 0xbcd, 0xbb5, 0xbbe, 0xba4, 0xbbf, 0xba9, 0xbcd, 0x3b, 0xb86, 0xbb0,
-0xbcd, 0xb9f, 0xbbf, 0xbaa, 0xbc6, 0xbb9, 0xbc6, 0xbb7, 0xbcd, 0xba4, 0xbcd, 0x3b, 0xb95, 0xbca, 0xbb0, 0xbcd, 0xba4, 0xbbe, 0xba4, 0xbcd,
-0x3b, 0xba4, 0xbbf, 0xbb0, 0xbcd, 0x3b, 0xbae, 0xbca, 0xbb0, 0xbcd, 0xba4, 0xbbe, 0xba4, 0xbcd, 0x3b, 0xbb7, 0xbbe, 0xbb0, 0xbbf, 0xbb5,
-0xbbe, 0xbb0, 0xbcd, 0x3b, 0xbae, 0xbc6, 0xbb9, 0xbcd, 0xbb0, 0xbcd, 0x3b, 0xb85, 0xbaa, 0xbbe, 0xba9, 0xbcd, 0x3b, 0xb85, 0xb9a, 0xbbe,
-0xbb0, 0xbcd, 0x3b, 0xba4, 0xbc7, 0x3b, 0xbaa, 0xbb9, 0xbcd, 0xbae, 0xbbe, 0xba9, 0xbcd, 0x3b, 0xb8e, 0xb83, 0xbaa, 0xbbe, 0xba9, 0xbcd,
-0xb83, 0xbaa, 0xbb0, 0xbcd, 0x2e, 0x3b, 0xb86, 0xbb0, 0xbcd, 0xb9f, 0xbbf, 0x2e, 0x3b, 0xb95, 0xbca, 0xbb0, 0xbcd, 0x2e, 0x3b, 0xba4,
-0xbbf, 0xbb0, 0xbcd, 0x3b, 0xbae, 0xbca, 0xbb0, 0xbcd, 0x2e, 0x3b, 0xbb7, 0xbbe, 0xbb0, 0xbbf, 0x2e, 0x3b, 0xbae, 0xbc6, 0xbb9, 0xbcd,
-0x2e, 0x3b, 0xb85, 0xbaa, 0xbbe, 0x2e, 0x3b, 0xb85, 0xb9a, 0xbbe, 0x2e, 0x3b, 0xba4, 0xbc7, 0x3b, 0xbaa, 0xbb9, 0xbcd, 0x2e, 0x3b,
-0xb8e, 0xb83, 0x2e, 0xc2b, 0xc3e, 0xc35, 0xc30, 0xc4d, 0xc21, 0xc3f, 0xc28, 0xc4d, 0x3b, 0xc0a, 0xc21, 0xc3e, 0xc2c, 0xc39, 0xc37, 0xc4d,
-0xc1f, 0xc4d, 0x3b, 0xc16, 0xc4b, 0xc30, 0xc4d, 0xc21, 0xc3e, 0xc21, 0xc4d, 0x3b, 0xc1f, 0xc3f, 0xc30, 0xc4d, 0x3b, 0xc2e, 0xc46, 0xc30,
-0xc4d, 0xc21, 0xc3e, 0xc21, 0xc4d, 0x3b, 0xc36, 0xc36, 0xc3f, 0xc35, 0xc30, 0xc4d, 0x3b, 0xc2e, 0xc46, 0xc39, 0xc30, 0xc4d, 0x3b, 0xc05,
-0xc2c, 0xc28, 0xc4d, 0x3b, 0xc05, 0xc1c, 0xc30, 0xc4d, 0x3b, 0xc21, 0xc47, 0x3b, 0xc2c, 0xc3e, 0xc39, 0xc4d, 0x200c, 0xc2e, 0xc3e, 0xc28,
-0xc4d, 0x3b, 0xc0e, 0xc38, 0xc4d, 0x200c, 0xc2b, 0xc3e, 0xc02, 0xc21, 0xc4d, 0xe1f, 0xe32, 0xe23, 0xe4c, 0xe27, 0xe32, 0xe23, 0xe4c, 0xe14,
-0xe34, 0xe19, 0x3b, 0xe2d, 0xe2d, 0xe23, 0xe4c, 0xe14, 0xe34, 0xe40, 0xe1a, 0xe40, 0xe2e, 0xe0a, 0xe15, 0xe4c, 0x3b, 0xe04, 0xe2d, 0xe23,
-0xe4c, 0xe41, 0xe14, 0xe14, 0x3b, 0xe40, 0xe15, 0xe2d, 0xe23, 0xe4c, 0x3b, 0xe21, 0xe2d, 0xe23, 0xe4c, 0xe41, 0xe14, 0xe14, 0x3b, 0xe0a,
-0xe32, 0xe2b, 0xe23, 0xe34, 0xe27, 0xe32, 0xe23, 0xe4c, 0x3b, 0xe40, 0xe21, 0xe2e, 0xe23, 0xe4c, 0x3b, 0xe2d, 0xe30, 0xe1a, 0xe32, 0xe19,
-0x3b, 0xe2d, 0xe30, 0xe0b, 0xe32, 0xe23, 0xe4c, 0x3b, 0xe40, 0xe14, 0xe22, 0xe4c, 0x3b, 0xe1a, 0xe32, 0xe2e, 0xe4c, 0xe21, 0xe32, 0xe19,
-0x3b, 0xe40, 0xe2d, 0xe2a, 0xe1f, 0xe32, 0xe19, 0xe14, 0xe4c, 0x46, 0x65, 0x72, 0x76, 0x65, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x4f,
-0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x15f, 0x74, 0x3b, 0x48, 0x6f, 0x72, 0x64, 0x61, 0x64, 0x3b, 0x54, 0x69, 0x72,
-0x3b, 0x4d, 0x6f, 0x72, 0x64, 0x61, 0x64, 0x3b, 0x15e, 0x65, 0x68, 0x72, 0x69, 0x76, 0x65, 0x72, 0x3b, 0x4d, 0x65, 0x68,
-0x72, 0x3b, 0x41, 0x62, 0x61, 0x6e, 0x3b, 0x41, 0x7a, 0x65, 0x72, 0x3b, 0x44, 0x65, 0x79, 0x3b, 0x42, 0x65, 0x68, 0x6d,
-0x65, 0x6e, 0x3b, 0x45, 0x73, 0x66, 0x65, 0x6e, 0x64, 0x444, 0x430, 0x440, 0x432, 0x430, 0x440, 0x434, 0x456, 0x43d, 0x3b, 0x43e,
-0x440, 0x434, 0x456, 0x431, 0x435, 0x445, 0x435, 0x448, 0x442, 0x3b, 0x445, 0x43e, 0x440, 0x434, 0x430, 0x434, 0x3b, 0x442, 0x456, 0x440,
-0x3b, 0x43c, 0x43e, 0x440, 0x434, 0x430, 0x434, 0x3b, 0x448, 0x430, 0x445, 0x440, 0x456, 0x432, 0x435, 0x440, 0x3b, 0x43c, 0x435, 0x445,
-0x440, 0x3b, 0x430, 0x431, 0x430, 0x43d, 0x3b, 0x430, 0x437, 0x435, 0x440, 0x3b, 0x434, 0x435, 0x439, 0x3b, 0x431, 0x430, 0x445, 0x43c,
-0x430, 0x43d, 0x3b, 0x435, 0x441, 0x444, 0x430, 0x43d, 0x434, 0x444, 0x430, 0x440, 0x3b, 0x43e, 0x440, 0x434, 0x3b, 0x445, 0x43e, 0x440,
-0x3b, 0x442, 0x456, 0x440, 0x3b, 0x43c, 0x43e, 0x440, 0x3b, 0x448, 0x430, 0x445, 0x3b, 0x43c, 0x435, 0x445, 0x3b, 0x430, 0x431, 0x430,
-0x43d, 0x3b, 0x430, 0x437, 0x435, 0x440, 0x3b, 0x434, 0x435, 0x439, 0x3b, 0x431, 0x430, 0x445, 0x3b, 0x435, 0x441, 0x444, 0x444, 0x430,
-0x440, 0x2e, 0x3b, 0x43e, 0x440, 0x434, 0x2e, 0x3b, 0x445, 0x43e, 0x440, 0x2e, 0x3b, 0x442, 0x456, 0x440, 0x3b, 0x43c, 0x43e, 0x440,
-0x2e, 0x3b, 0x448, 0x430, 0x445, 0x2e, 0x3b, 0x43c, 0x435, 0x445, 0x2e, 0x3b, 0x430, 0x431, 0x430, 0x43d, 0x3b, 0x430, 0x437, 0x435,
-0x440, 0x3b, 0x434, 0x435, 0x439, 0x3b, 0x431, 0x430, 0x445, 0x2e, 0x3b, 0x435, 0x441, 0x444, 0x2e, 0x641, 0x631, 0x648, 0x631, 0x62f,
-0x646, 0x3b, 0x622, 0x631, 0x688, 0x628, 0x627, 0x626, 0x634, 0x3b, 0x62e, 0x62f, 0x627, 0x62f, 0x627, 0x62f, 0x3b, 0x62a, 0x6cc, 0x631,
-0x3b, 0x645, 0x631, 0x62f, 0x627, 0x62f, 0x3b, 0x634, 0x6c1, 0x631, 0x6cc, 0x648, 0x627, 0x631, 0x3b, 0x645, 0x6c1, 0x631, 0x3b, 0x627,
-0x628, 0x627, 0x646, 0x3b, 0x622, 0x632, 0x631, 0x3b, 0x688, 0x6d2, 0x3b, 0x628, 0x6c1, 0x645, 0x646, 0x3b, 0x627, 0x633, 0x641, 0x646,
-0x62f, 0x66, 0x61, 0x72, 0x76, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x6f, 0x2bb, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x69,
-0x73, 0x68, 0x74, 0x3b, 0x78, 0x75, 0x72, 0x64, 0x6f, 0x64, 0x3b, 0x74, 0x75, 0x72, 0x3b, 0x6d, 0x75, 0x72, 0x64, 0x6f,
-0x64, 0x3b, 0x73, 0x68, 0x61, 0x68, 0x72, 0x69, 0x76, 0x61, 0x72, 0x3b, 0x6d, 0x65, 0x68, 0x72, 0x3b, 0x6f, 0x62, 0x6f,
-0x6e, 0x3b, 0x6f, 0x7a, 0x61, 0x72, 0x3b, 0x64, 0x65, 0x79, 0x3b, 0x62, 0x61, 0x68, 0x6d, 0x61, 0x6e, 0x3b, 0x69, 0x73,
-0x66, 0x61, 0x6e, 0x64, 0x66, 0x61, 0x72, 0x76, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x6f, 0x2bb, 0x72, 0x64, 0x69, 0x62,
-0x65, 0x68, 0x69, 0x73, 0x68, 0x74, 0x3b, 0x78, 0x75, 0x72, 0x64, 0x6f, 0x64, 0x3b, 0x74, 0x69, 0x72, 0x3b, 0x6d, 0x75,
-0x72, 0x64, 0x6f, 0x64, 0x3b, 0x73, 0x68, 0x61, 0x68, 0x72, 0x69, 0x76, 0x61, 0x72, 0x3b, 0x6d, 0x65, 0x68, 0x72, 0x3b,
-0x6f, 0x62, 0x6f, 0x6e, 0x3b, 0x6f, 0x7a, 0x61, 0x72, 0x3b, 0x64, 0x65, 0x79, 0x3b, 0x62, 0x61, 0x68, 0x6d, 0x61, 0x6e,
-0x3b, 0x69, 0x73, 0x66, 0x61, 0x6e, 0x66, 0x61, 0x72, 0x76, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x6f, 0x2bb, 0x72, 0x64,
-0x69, 0x62, 0x65, 0x68, 0x69, 0x73, 0x68, 0x74, 0x3b, 0x78, 0x75, 0x72, 0x64, 0x6f, 0x64, 0x3b, 0x74, 0x69, 0x72, 0x3b,
-0x6d, 0x75, 0x72, 0x64, 0x6f, 0x64, 0x3b, 0x73, 0x68, 0x61, 0x68, 0x72, 0x69, 0x76, 0x61, 0x72, 0x3b, 0x6d, 0x65, 0x68,
-0x72, 0x3b, 0x6f, 0x62, 0x6f, 0x6e, 0x3b, 0x6f, 0x7a, 0x61, 0x72, 0x3b, 0x64, 0x65, 0x79, 0x3b, 0x62, 0x61, 0x68, 0x6d,
-0x61, 0x6e, 0x3b, 0x69, 0x73, 0x66, 0x61, 0x6e, 0x64
+0x46, 0x61, 0x72, 0x76, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x4f, 0x72,
+0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x73, 0x68, 0x74, 0x3b, 0x4b, 0x68,
+0x6f, 0x72, 0x64, 0x61, 0x64, 0x3b, 0x54, 0x69, 0x72, 0x3b, 0x4d, 0x6f,
+0x72, 0x64, 0x61, 0x64, 0x3b, 0x53, 0x68, 0x61, 0x68, 0x72, 0x69, 0x76,
+0x61, 0x72, 0x3b, 0x4d, 0x65, 0x68, 0x72, 0x3b, 0x41, 0x62, 0x61, 0x6e,
+0x3b, 0x41, 0x7a, 0x61, 0x72, 0x3b, 0x44, 0x65, 0x79, 0x3b, 0x42, 0x61,
+0x68, 0x6d, 0x61, 0x6e, 0x3b, 0x45, 0x73, 0x66, 0x61, 0x6e, 0x64, 0x46,
+0x61, 0x72, 0x3b, 0x4f, 0x72, 0x64, 0x3b, 0x4b, 0x68, 0x6f, 0x3b, 0x54,
+0x69, 0x72, 0x3b, 0x4d, 0x6f, 0x72, 0x3b, 0x53, 0x68, 0x61, 0x3b, 0x4d,
+0x65, 0x68, 0x3b, 0x41, 0x62, 0x61, 0x3b, 0x41, 0x7a, 0x61, 0x3b, 0x44,
+0x65, 0x79, 0x3b, 0x42, 0x61, 0x68, 0x3b, 0x45, 0x73, 0x66, 0x46, 0x3b,
+0x4f, 0x3b, 0x4b, 0x3b, 0x54, 0x3b, 0x4d, 0x3b, 0x53, 0x3b, 0x4d, 0x3b,
+0x41, 0x3b, 0x41, 0x3b, 0x44, 0x3b, 0x42, 0x3b, 0x45, 0x31, 0x3b, 0x32,
+0x3b, 0x33, 0x3b, 0x34, 0x3b, 0x35, 0x3b, 0x36, 0x3b, 0x37, 0x3b, 0x38,
+0x3b, 0x39, 0x3b, 0x31, 0x30, 0x3b, 0x31, 0x31, 0x3b, 0x31, 0x32, 0x641,
+0x631, 0x641, 0x631, 0x62f, 0x646, 0x3b, 0x623, 0x630, 0x631, 0x628, 0x64a, 0x647,
+0x634, 0x62a, 0x3b, 0x62e, 0x631, 0x62f, 0x627, 0x62f, 0x3b, 0x62a, 0x627, 0x631,
+0x3b, 0x645, 0x631, 0x62f, 0x627, 0x62f, 0x3b, 0x634, 0x647, 0x631, 0x641, 0x627,
+0x631, 0x3b, 0x645, 0x647, 0x631, 0x3b, 0x622, 0x64a, 0x627, 0x646, 0x3b, 0x622,
+0x630, 0x631, 0x3b, 0x62f, 0x64a, 0x3b, 0x628, 0x647, 0x645, 0x646, 0x3b, 0x627,
+0x633, 0x641, 0x646, 0x62f, 0x627, 0x631, 0x66, 0x259, 0x72, 0x76, 0x259, 0x72,
+0x64, 0x69, 0x6e, 0x3b, 0x6f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65,
+0x15f, 0x74, 0x3b, 0x78, 0x6f, 0x72, 0x64, 0x259, 0x64, 0x3b, 0x74, 0x69,
+0x72, 0x3b, 0x6d, 0x6f, 0x72, 0x64, 0x259, 0x64, 0x3b, 0x15f, 0x259, 0x68,
+0x72, 0x69, 0x76, 0x61, 0x72, 0x3b, 0x6d, 0x65, 0x68, 0x72, 0x3b, 0x61,
+0x62, 0x259, 0x6e, 0x3b, 0x61, 0x7a, 0x259, 0x72, 0x3b, 0x64, 0x65, 0x79,
+0x3b, 0x62, 0x259, 0x68, 0x6d, 0x259, 0x6e, 0x3b, 0x69, 0x73, 0x66, 0x259,
+0x6e, 0x64, 0x9ab, 0x9cd, 0x9af, 0x9be, 0x9ad, 0x9be, 0x9b0, 0x9cd, 0x9a1, 0x9bf,
+0x9a8, 0x3b, 0x985, 0x9b0, 0x9a1, 0x9bf, 0x9ac, 0x9c7, 0x9b9, 0x9c7, 0x9b6, 0x9cd,
+0x9a4, 0x3b, 0x996, 0x9cb, 0x9b0, 0x9cd, 0x9a6, 0x9cd, 0x9a6, 0x3b, 0x9a4, 0x9c0,
+0x9b0, 0x3b, 0x9ae, 0x9b0, 0x9cd, 0x9af, 0x9be, 0x9a6, 0x3b, 0x9b6, 0x9be, 0x9b9,
+0x9b0, 0x9bf, 0x9ac, 0x9be, 0x9b0, 0x3b, 0x9ae, 0x9c7, 0x9b9, 0x9c7, 0x9b0, 0x3b,
+0x986, 0x9ac, 0x9be, 0x9a8, 0x3b, 0x9ac, 0x9be, 0x99c, 0x9be, 0x9b0, 0x3b, 0x9a6,
+0x9c7, 0x3b, 0x9ac, 0x9be, 0x9b9, 0x9ae, 0x9be, 0x9a8, 0x3b, 0x98f, 0x9b8, 0x9ab,
+0x9cd, 0x9af, 0x9be, 0x9a8, 0x9cd, 0x9a1, 0x9ab, 0x9cd, 0x9af, 0x9be, 0x9ad, 0x9be,
+0x9b0, 0x9cd, 0x9a1, 0x9bf, 0x9a8, 0x3b, 0x985, 0x9b0, 0x9a1, 0x9bf, 0x9ac, 0x9c7,
+0x9b9, 0x9c7, 0x9b6, 0x9cd, 0x9a4, 0x3b, 0x996, 0x9cb, 0x9b0, 0x9cd, 0x9a6, 0x9cd,
+0x9a6, 0x3b, 0x9a4, 0x9c0, 0x9b0, 0x3b, 0x9ae, 0x9b0, 0x9cd, 0x9af, 0x9be, 0x9a6,
+0x3b, 0x9b6, 0x9be, 0x9b9, 0x9b0, 0x9bf, 0x9ac, 0x9be, 0x9b0, 0x3b, 0x9ae, 0x9c7,
+0x9b9, 0x9c7, 0x9b0, 0x3b, 0x986, 0x9ac, 0x9be, 0x9a8, 0x3b, 0x986, 0x99c, 0x9be,
+0x9b0, 0x3b, 0x9a6, 0x9c7, 0x3b, 0x9ac, 0x9be, 0x9b9, 0x9ae, 0x9be, 0x9a8, 0x3b,
+0x98f, 0x9b8, 0x9ab, 0x9cd, 0x9af, 0x9be, 0x9a8, 0x9cd, 0x9a1, 0x9e7, 0x3b, 0x9e8,
+0x3b, 0x9e9, 0x3b, 0x9ea, 0x3b, 0x9eb, 0x3b, 0x9ec, 0x3b, 0x9ed, 0x3b, 0x9ee,
+0x3b, 0x9ef, 0x3b, 0x9e7, 0x9e6, 0x3b, 0x9e7, 0x9e7, 0x3b, 0x9e7, 0x9e8, 0x424,
+0x430, 0x440, 0x430, 0x432, 0x430, 0x434, 0x438, 0x43d, 0x3b, 0x41e, 0x440, 0x434,
+0x438, 0x431, 0x435, 0x445, 0x435, 0x448, 0x442, 0x3b, 0x41a, 0x43e, 0x440, 0x434,
+0x430, 0x434, 0x3b, 0x422, 0x438, 0x440, 0x3b, 0x41c, 0x43e, 0x440, 0x434, 0x430,
+0x434, 0x3b, 0x428, 0x430, 0x445, 0x440, 0x438, 0x432, 0x430, 0x440, 0x3b, 0x41c,
+0x435, 0x445, 0x440, 0x3b, 0x410, 0x431, 0x430, 0x43d, 0x3b, 0x410, 0x437, 0x430,
+0x440, 0x3b, 0x414, 0x435, 0x458, 0x3b, 0x411, 0x430, 0x445, 0x43c, 0x430, 0x43d,
+0x3b, 0x415, 0x441, 0x444, 0x430, 0x43d, 0x434, 0x31, 0x6708, 0x3b, 0x32, 0x6708,
+0x3b, 0x33, 0x6708, 0x3b, 0x34, 0x6708, 0x3b, 0x35, 0x6708, 0x3b, 0x36, 0x6708,
+0x3b, 0x37, 0x6708, 0x3b, 0x38, 0x6708, 0x3b, 0x39, 0x6708, 0x3b, 0x31, 0x30,
+0x6708, 0x3b, 0x31, 0x31, 0x6708, 0x3b, 0x31, 0x32, 0x6708, 0x62e, 0x627, 0x6a9,
+0x6d5, 0x644, 0x6ce, 0x648, 0x6d5, 0x3b, 0x628, 0x627, 0x646, 0x6d5, 0x645, 0x6d5,
+0x695, 0x3b, 0x62c, 0x6c6, 0x632, 0x6d5, 0x631, 0x62f, 0x627, 0x646, 0x3b, 0x67e,
+0x648, 0x648, 0x634, 0x67e, 0x6d5, 0x695, 0x3b, 0x6af, 0x6d5, 0x644, 0x627, 0x648,
+0x6ce, 0x698, 0x3b, 0x62e, 0x6d5, 0x631, 0x645, 0x627, 0x646, 0x627, 0x646, 0x3b,
+0x695, 0x6d5, 0x632, 0x628, 0x6d5, 0x631, 0x3b, 0x62e, 0x6d5, 0x632, 0x6d5, 0x6b5,
+0x648, 0x6d5, 0x631, 0x3b, 0x633, 0x6d5, 0x631, 0x645, 0x627, 0x648, 0x6d5, 0x632,
+0x3b, 0x628, 0x6d5, 0x641, 0x631, 0x627, 0x646, 0x628, 0x627, 0x631, 0x3b, 0x695,
+0x6ce, 0x628, 0x6d5, 0x646, 0x62f, 0x627, 0x646, 0x3b, 0x631, 0x6d5, 0x634, 0x6d5,
+0x645, 0x6ce, 0x62e, 0x627, 0x6a9, 0x6d5, 0x644, 0x6ce, 0x648, 0x6d5, 0x3b, 0x6af,
+0x648, 0x6b5, 0x627, 0x646, 0x3b, 0x62c, 0x6c6, 0x632, 0x6d5, 0x631, 0x62f, 0x627,
+0x646, 0x3b, 0x67e, 0x648, 0x648, 0x634, 0x67e, 0x6d5, 0x695, 0x3b, 0x6af, 0x6d5,
+0x644, 0x627, 0x648, 0x6ce, 0x698, 0x3b, 0x62e, 0x6d5, 0x631, 0x645, 0x627, 0x646,
+0x627, 0x646, 0x3b, 0x695, 0x6d5, 0x632, 0x628, 0x6d5, 0x631, 0x3b, 0x6af, 0x6d5,
+0x6b5, 0x627, 0x695, 0x6ce, 0x632, 0x627, 0x646, 0x3b, 0x633, 0x6d5, 0x631, 0x645,
+0x627, 0x648, 0x6d5, 0x632, 0x3b, 0x628, 0x6d5, 0x641, 0x631, 0x627, 0x646, 0x628,
+0x627, 0x631, 0x3b, 0x695, 0x6ce, 0x628, 0x6d5, 0x646, 0x62f, 0x627, 0x646, 0x3b,
+0x695, 0x6d5, 0x634, 0x6d5, 0x645, 0x6d5, 0x4e00, 0x6708, 0x3b, 0x4e8c, 0x6708, 0x3b,
+0x4e09, 0x6708, 0x3b, 0x56db, 0x6708, 0x3b, 0x4e94, 0x6708, 0x3b, 0x516d, 0x6708, 0x3b,
+0x4e03, 0x6708, 0x3b, 0x516b, 0x6708, 0x3b, 0x4e5d, 0x6708, 0x3b, 0x5341, 0x6708, 0x3b,
+0x5341, 0x4e00, 0x6708, 0x3b, 0x5341, 0x4e8c, 0x6708, 0x31, 0x2e, 0x3b, 0x32, 0x2e,
+0x3b, 0x33, 0x2e, 0x3b, 0x34, 0x2e, 0x3b, 0x35, 0x2e, 0x3b, 0x36, 0x2e,
+0x3b, 0x37, 0x2e, 0x3b, 0x38, 0x2e, 0x3b, 0x39, 0x2e, 0x3b, 0x31, 0x30,
+0x2e, 0x3b, 0x31, 0x31, 0x2e, 0x3b, 0x31, 0x32, 0x2e, 0x66, 0x61, 0x72,
+0x76, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x6f, 0x72, 0x64, 0x69, 0x62,
+0x65, 0x68, 0x65, 0x161, 0x74, 0x3b, 0x63, 0x68, 0x6f, 0x72, 0x64, 0xe1,
+0x64, 0x3b, 0x74, 0xed, 0x72, 0x3b, 0x6d, 0x6f, 0x72, 0x64, 0xe1, 0x64,
+0x3b, 0x161, 0x61, 0x68, 0x72, 0xed, 0x76, 0x61, 0x72, 0x3b, 0x6d, 0x65,
+0x68, 0x72, 0x3b, 0xe1, 0x62, 0xe1, 0x6e, 0x3b, 0xe1, 0x7a, 0x61, 0x72,
+0x3b, 0x64, 0x65, 0x69, 0x3b, 0x62, 0x61, 0x68, 0x6d, 0x61, 0x6e, 0x3b,
+0x65, 0x73, 0x66, 0x61, 0x6e, 0x64, 0x66, 0x61, 0x72, 0x76, 0x61, 0x72,
+0x64, 0x69, 0x6e, 0x3b, 0x6f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65,
+0x73, 0x68, 0x74, 0x3b, 0x6b, 0x68, 0x6f, 0x72, 0x64, 0x61, 0x64, 0x3b,
+0x74, 0x69, 0x72, 0x3b, 0x6d, 0x6f, 0x72, 0x64, 0x61, 0x64, 0x3b, 0x73,
+0x68, 0x61, 0x68, 0x72, 0x69, 0x76, 0x61, 0x72, 0x3b, 0x6d, 0x65, 0x68,
+0x72, 0x3b, 0x61, 0x62, 0x61, 0x6e, 0x3b, 0x61, 0x7a, 0x61, 0x72, 0x3b,
+0x64, 0x65, 0x79, 0x3b, 0x62, 0x61, 0x68, 0x6d, 0x61, 0x6e, 0x3b, 0x65,
+0x73, 0x66, 0x61, 0x6e, 0x64, 0x64, 0x7a, 0x6f, 0x76, 0x65, 0x3b, 0x64,
+0x7a, 0x6f, 0x64, 0x7a, 0x65, 0x3b, 0x74, 0x65, 0x64, 0x6f, 0x78, 0x65,
+0x3b, 0x61, 0x66, 0x254, 0x66, 0x69, 0x1ebd, 0x3b, 0x64, 0x61, 0x6d, 0x25b,
+0x3b, 0x6d, 0x61, 0x73, 0x61, 0x3b, 0x73, 0x69, 0x61, 0x6d, 0x6c, 0x254,
+0x6d, 0x3b, 0x64, 0x65, 0x61, 0x73, 0x69, 0x61, 0x6d, 0x69, 0x6d, 0x65,
+0x3b, 0x61, 0x6e, 0x79, 0x254, 0x6e, 0x79, 0x254, 0x3b, 0x6b, 0x65, 0x6c,
+0x65, 0x3b, 0x61, 0x64, 0x65, 0x25b, 0x6d, 0x65, 0x6b, 0x70, 0x254, 0x78,
+0x65, 0x3b, 0x64, 0x7a, 0x6f, 0x6d, 0x65, 0x64, 0x7a, 0x76, 0x3b, 0x64,
+0x7a, 0x64, 0x3b, 0x74, 0x65, 0x64, 0x3b, 0x61, 0x66, 0x254, 0x3b, 0x64,
+0x61, 0x6d, 0x3b, 0x6d, 0x61, 0x73, 0x3b, 0x73, 0x69, 0x61, 0x3b, 0x64,
+0x65, 0x61, 0x3b, 0x61, 0x6e, 0x79, 0x3b, 0x6b, 0x65, 0x6c, 0x3b, 0x61,
+0x64, 0x65, 0x3b, 0x64, 0x7a, 0x6d, 0x66, 0x61, 0x72, 0x76, 0x61, 0x72,
+0x64, 0x69, 0x6e, 0x6b, 0x75, 0x75, 0x3b, 0x6f, 0x72, 0x64, 0x69, 0x62,
+0x65, 0x68, 0x65, 0x161, 0x74, 0x6b, 0x75, 0x75, 0x3b, 0x6b, 0x68, 0x6f,
+0x72, 0x64, 0x61, 0x64, 0x6b, 0x75, 0x75, 0x3b, 0x74, 0x69, 0x72, 0x6b,
+0x75, 0x75, 0x3b, 0x6d, 0x6f, 0x72, 0x64, 0x61, 0x64, 0x6b, 0x75, 0x75,
+0x3b, 0x161, 0x61, 0x68, 0x72, 0x69, 0x76, 0x61, 0x72, 0x6b, 0x75, 0x75,
+0x3b, 0x6d, 0x65, 0x68, 0x72, 0x6b, 0x75, 0x75, 0x3b, 0x61, 0x62, 0x61,
+0x6e, 0x6b, 0x75, 0x75, 0x3b, 0x61, 0x7a, 0x61, 0x72, 0x6b, 0x75, 0x75,
+0x3b, 0x64, 0x65, 0x79, 0x6b, 0x75, 0x75, 0x3b, 0x62, 0x61, 0x68, 0x6d,
+0x61, 0x6e, 0x6b, 0x75, 0x75, 0x3b, 0x65, 0x73, 0x66, 0x61, 0x6e, 0x64,
+0x6b, 0x75, 0x75, 0x66, 0x61, 0x72, 0x76, 0x61, 0x72, 0x64, 0x69, 0x6e,
+0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x6f, 0x72, 0x64, 0x69, 0x62, 0x65,
+0x68, 0x65, 0x161, 0x74, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x6b, 0x68,
+0x6f, 0x72, 0x64, 0x61, 0x64, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x74,
+0x69, 0x72, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x6d, 0x6f, 0x72, 0x64,
+0x61, 0x64, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x161, 0x61, 0x68, 0x72,
+0x69, 0x76, 0x61, 0x72, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x6d, 0x65,
+0x68, 0x72, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x61, 0x62, 0x61, 0x6e,
+0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x61, 0x7a, 0x61, 0x72, 0x6b, 0x75,
+0x75, 0x74, 0x61, 0x3b, 0x64, 0x65, 0x79, 0x6b, 0x75, 0x75, 0x74, 0x61,
+0x3b, 0x62, 0x61, 0x68, 0x6d, 0x61, 0x6e, 0x6b, 0x75, 0x75, 0x74, 0x61,
+0x3b, 0x65, 0x73, 0x66, 0x61, 0x6e, 0x64, 0x6b, 0x75, 0x75, 0x74, 0x61,
+0x66, 0x61, 0x72, 0x76, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x6f, 0x72,
+0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x161, 0x74, 0x3b, 0x6b, 0x68, 0x6f,
+0x72, 0x64, 0x61, 0x64, 0x3b, 0x74, 0x69, 0x72, 0x3b, 0x6d, 0x6f, 0x72,
+0x64, 0x61, 0x64, 0x3b, 0x161, 0x61, 0x68, 0x72, 0x69, 0x76, 0x61, 0x72,
+0x3b, 0x6d, 0x65, 0x68, 0x72, 0x3b, 0x61, 0x62, 0x61, 0x6e, 0x3b, 0x61,
+0x7a, 0x61, 0x72, 0x3b, 0x64, 0x65, 0x79, 0x3b, 0x62, 0x61, 0x68, 0x6d,
+0x61, 0x6e, 0x3b, 0x65, 0x73, 0x66, 0x61, 0x6e, 0x64, 0x66, 0x61, 0x72,
+0x76, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x6f, 0x72, 0x64, 0x69, 0x62,
+0x65, 0x68, 0x65, 0x161, 0x74, 0x3b, 0x6b, 0x68, 0x6f, 0x72, 0x64, 0xe2,
+0x64, 0x3b, 0x74, 0x69, 0x72, 0x3b, 0x6d, 0x6f, 0x72, 0x64, 0xe2, 0x64,
+0x3b, 0x161, 0x61, 0x68, 0x72, 0x69, 0x76, 0x61, 0x72, 0x3b, 0x6d, 0x65,
+0x68, 0x72, 0x3b, 0xe2, 0x62, 0xe2, 0x6e, 0x3b, 0xe2, 0x7a, 0x61, 0x72,
+0x3b, 0x64, 0x65, 0x79, 0x3b, 0x62, 0x61, 0x68, 0x6d, 0x61, 0x6e, 0x3b,
+0x65, 0x73, 0x66, 0x61, 0x6e, 0x64, 0x66, 0x61, 0x72, 0x2e, 0x3b, 0x6f,
+0x72, 0x64, 0x2e, 0x3b, 0x6b, 0x68, 0x6f, 0x2e, 0x3b, 0x74, 0x69, 0x72,
+0x3b, 0x6d, 0x6f, 0x72, 0x2e, 0x3b, 0x161, 0x61, 0x68, 0x2e, 0x3b, 0x6d,
+0x65, 0x68, 0x72, 0x3b, 0xe2, 0x62, 0xe2, 0x6e, 0x3b, 0xe2, 0x7a, 0x61,
+0x72, 0x3b, 0x64, 0x65, 0x79, 0x3b, 0x62, 0x61, 0x68, 0x2e, 0x3b, 0x65,
+0x73, 0x66, 0x2e, 0x46, 0x61, 0x72, 0x76, 0x61, 0x72, 0x64, 0x69, 0x6e,
+0x3b, 0x4f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x161, 0x74, 0x3b,
+0x4b, 0x68, 0x6f, 0x72, 0x64, 0xe2, 0x64, 0x3b, 0x54, 0x69, 0x72, 0x3b,
+0x4d, 0x6f, 0x72, 0x64, 0xe2, 0x64, 0x3b, 0x160, 0x61, 0x68, 0x72, 0x69,
+0x76, 0x61, 0x72, 0x3b, 0x4d, 0x65, 0x68, 0x72, 0x3b, 0xc2, 0x62, 0xe2,
+0x6e, 0x3b, 0xc2, 0x7a, 0x61, 0x72, 0x3b, 0x44, 0x65, 0x79, 0x3b, 0x42,
+0x61, 0x68, 0x6d, 0x61, 0x6e, 0x3b, 0x45, 0x73, 0x66, 0x61, 0x6e, 0x64,
+0x46, 0x61, 0x72, 0x2e, 0x3b, 0x4f, 0x72, 0x64, 0x2e, 0x3b, 0x4b, 0x68,
+0x6f, 0x2e, 0x3b, 0x54, 0x69, 0x72, 0x3b, 0x4d, 0x6f, 0x72, 0x2e, 0x3b,
+0x160, 0x61, 0x68, 0x2e, 0x3b, 0x4d, 0x65, 0x68, 0x72, 0x3b, 0xc2, 0x62,
+0xe2, 0x2e, 0x3b, 0xc2, 0x7a, 0x61, 0x72, 0x3b, 0x44, 0x65, 0x79, 0x3b,
+0x42, 0x61, 0x68, 0x2e, 0x3b, 0x45, 0x73, 0x66, 0x2e, 0xd83a, 0xdd0a, 0xd83a,
+0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd3e, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd23, 0xd83a,
+0xdd2d, 0xd83a, 0xdd32, 0x3b, 0xd83a, 0xdd0c, 0xd83a, 0xdd2a, 0xd83a, 0xdd23, 0xd83a, 0xdd2d,
+0xd83a, 0xdd26, 0xd83a, 0xdd2b, 0xd83a, 0xdd38, 0xd83a, 0xdd2b, 0xd83a, 0xdd43, 0xd83a, 0xdd3c,
+0x3b, 0xd83a, 0xdd1d, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0xd83a, 0xdd23, 0xd83a, 0xdd22, 0xd83a,
+0xdd23, 0x3b, 0xd83a, 0xdd1a, 0xd83a, 0xdd2d, 0xd83a, 0xdd2a, 0x3b, 0xd83a, 0xdd03, 0xd83a,
+0xdd2e, 0xd83a, 0xdd2a, 0xd83a, 0xdd23, 0xd83a, 0xdd22, 0xd83a, 0xdd23, 0x3b, 0xd83a, 0xdd21,
+0xd83a, 0xdd22, 0xd83a, 0xdd38, 0xd83a, 0xdd2a, 0xd83a, 0xdd2d, 0xd83a, 0xdd3e, 0xd83a, 0xdd22,
+0xd83a, 0xdd2a, 0x3b, 0xd83a, 0xdd03, 0xd83a, 0xdd2b, 0xd83a, 0xdd38, 0xd83a, 0xdd2b, 0xd83a,
+0xdd2a, 0x3b, 0xd83a, 0xdd00, 0xd83a, 0xdd26, 0xd83a, 0xdd22, 0xd83a, 0xdd32, 0x3b, 0xd83a,
+0xdd00, 0xd83a, 0xdd41, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0x3b, 0xd83a, 0xdd01, 0xd83a, 0xdd2b,
+0xd83a, 0xdd34, 0x3b, 0xd83a, 0xdd04, 0xd83a, 0xdd22, 0xd83a, 0xdd38, 0xd83a, 0xdd25, 0xd83a,
+0xdd22, 0xd83a, 0xdd32, 0x3b, 0xd83a, 0xdd09, 0xd83a, 0xdd27, 0xd83a, 0xdd2c, 0xd83a, 0xdd22,
+0xd83a, 0xdd32, 0xd83a, 0xdd23, 0xd83a, 0xdd51, 0x3b, 0xd83a, 0xdd52, 0x3b, 0xd83a, 0xdd53,
+0x3b, 0xd83a, 0xdd54, 0x3b, 0xd83a, 0xdd55, 0x3b, 0xd83a, 0xdd56, 0x3b, 0xd83a, 0xdd57,
+0x3b, 0xd83a, 0xdd58, 0x3b, 0xd83a, 0xdd59, 0x3b, 0xd83a, 0xdd51, 0xd83a, 0xdd50, 0x3b,
+0xd83a, 0xdd51, 0xd83a, 0xdd51, 0x3b, 0xd83a, 0xdd51, 0xd83a, 0xdd52, 0x10e4, 0x10d0, 0x10e0,
+0x10d5, 0x10d0, 0x10e0, 0x10d3, 0x10d8, 0x10dc, 0x10d8, 0x3b, 0x10dd, 0x10e0, 0x10d3, 0x10d8,
+0x10d1, 0x10d4, 0x10f0, 0x10d4, 0x10e8, 0x10d7, 0x10d8, 0x3b, 0x10ee, 0x10dd, 0x10e0, 0x10d3,
+0x10d0, 0x10d3, 0x10d8, 0x3b, 0x10d7, 0x10d8, 0x10e0, 0x10d8, 0x3b, 0x10db, 0x10dd, 0x10e0,
+0x10d3, 0x10d0, 0x10d3, 0x10d8, 0x3b, 0x10e8, 0x10d0, 0x10f0, 0x10e0, 0x10d8, 0x10d5, 0x10d0,
+0x10e0, 0x10d8, 0x3b, 0x10db, 0x10d4, 0x10f0, 0x10e0, 0x10d8, 0x3b, 0x10d0, 0x10d1, 0x10d0,
+0x10dc, 0x10d8, 0x3b, 0x10d0, 0x10d6, 0x10d0, 0x10e0, 0x10d8, 0x3b, 0x10d3, 0x10d4, 0x10d8,
+0x3b, 0x10d1, 0x10d0, 0x10f0, 0x10db, 0x10d0, 0x10dc, 0x10d8, 0x3b, 0x10d4, 0x10e1, 0x10e4,
+0x10d0, 0x10dc, 0x10d3, 0x10d8, 0x46, 0x61, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69,
+0x6e, 0x3b, 0x4f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x73, 0x63,
+0x68, 0x74, 0x3b, 0x43, 0x68, 0x6f, 0x72, 0x64, 0x101, 0x64, 0x3b, 0x54,
+0x69, 0x72, 0x3b, 0x4d, 0x6f, 0x72, 0x64, 0x101, 0x64, 0x3b, 0x53, 0x63,
+0x68, 0x61, 0x68, 0x72, 0x69, 0x77, 0x61, 0x72, 0x3b, 0x4d, 0x65, 0x68,
+0x72, 0x3b, 0x100, 0x62, 0x101, 0x6e, 0x3b, 0x100, 0x73, 0x61, 0x72, 0x3b,
+0x44, 0xe9, 0x69, 0x3b, 0x42, 0x61, 0x68, 0x6d, 0x61, 0x6e, 0x3b, 0x45,
+0x73, 0x73, 0x66, 0x61, 0x6e, 0x64, 0xaab, 0xabe, 0xab0, 0xacd, 0xab5, 0xabe,
+0xab0, 0xacd, 0xaa6, 0xabf, 0xaa8, 0x3b, 0xa93, 0xab0, 0xaa1, 0xac0, 0xaac, 0xac7,
+0xab9, 0xac7, 0xab6, 0xacd, 0xa9f, 0x3b, 0xa96, 0xacb, 0xab0, 0xaa6, 0xabe, 0xaa6,
+0x3b, 0xaa4, 0xabf, 0xab0, 0x3b, 0xaae, 0xacb, 0xab0, 0xacd, 0xaa6, 0xabe, 0xaa6,
+0x3b, 0xab6, 0xabe, 0xab9, 0xab0, 0xabf, 0xab5, 0xab0, 0x3b, 0xaae, 0xac7, 0xab9,
+0xab0, 0x3b, 0xa85, 0xaac, 0xabe, 0xaa8, 0x3b, 0xa85, 0xa9d, 0xabe, 0xab0, 0x3b,
+0xaa1, 0xac7, 0xaaf, 0x3b, 0xaac, 0xabe, 0xab9, 0xaae, 0xac7, 0xaa8, 0x3b, 0xa8f,
+0xab8, 0xacd, 0xaab, 0xabe, 0xaa8, 0xacd, 0xaa1, 0x5e4, 0x5e8, 0x5d5, 0x5e8, 0x5d3,
+0x5d9, 0x5df, 0x3b, 0x5d0, 0x5e8, 0x5d3, 0x5d9, 0x5d1, 0x5d4, 0x5e9, 0x5ea, 0x3b,
+0x5d7, 0x5f3, 0x5e8, 0x5d3, 0x5d0, 0x5d3, 0x3b, 0x5ea, 0x5d9, 0x5e8, 0x3b, 0x5de,
+0x5e8, 0x5d3, 0x5d0, 0x5d3, 0x3b, 0x5e9, 0x5d4, 0x5e8, 0x5d9, 0x5d5, 0x5e8, 0x3b,
+0x5de, 0x5d4, 0x5e8, 0x3b, 0x5d0, 0x5d1, 0x5d0, 0x5df, 0x3b, 0x5d0, 0x5d3, 0x5f3,
+0x5e8, 0x3b, 0x5d3, 0x5d9, 0x3b, 0x5d1, 0x5d4, 0x5de, 0x5df, 0x3b, 0x5d0, 0x5e1,
+0x5e4, 0x5e0, 0x5d3, 0x92b, 0x930, 0x94d, 0x935, 0x93e, 0x926, 0x93f, 0x928, 0x3b,
+0x913, 0x930, 0x94d, 0x926, 0x93f, 0x935, 0x947, 0x939, 0x947, 0x938, 0x94d, 0x91f,
+0x3b, 0x916, 0x94b, 0x930, 0x930, 0x94d, 0x926, 0x93e, 0x926, 0x3b, 0x91f, 0x93f,
+0x930, 0x3b, 0x92e, 0x94b, 0x930, 0x926, 0x93e, 0x926, 0x3b, 0x936, 0x93e, 0x939,
+0x930, 0x940, 0x935, 0x930, 0x94d, 0x3b, 0x92e, 0x947, 0x939, 0x930, 0x3b, 0x905,
+0x935, 0x928, 0x3b, 0x905, 0x91c, 0x93c, 0x930, 0x3b, 0x921, 0x947, 0x3b, 0x92c,
+0x939, 0x92e, 0x928, 0x3b, 0x908, 0x938, 0x94d, 0x92b, 0x928, 0x94d, 0x926, 0x94d,
+0x30d5, 0x30a1, 0x30eb, 0x30f4, 0x30a1, 0x30eb, 0x30c7, 0x30a3, 0x30fc, 0x30f3, 0x3b, 0x30aa,
+0x30eb, 0x30c7, 0x30a3, 0x30fc, 0x30d9, 0x30d8, 0x30b7, 0x30e5, 0x30c8, 0x3b, 0x30db, 0x30eb,
+0x30c0, 0x30fc, 0x30c9, 0x3b, 0x30c6, 0x30a3, 0x30fc, 0x30eb, 0x3b, 0x30e2, 0x30eb, 0x30c0,
+0x30fc, 0x30c9, 0x3b, 0x30b7, 0x30e3, 0x30cf, 0x30ea, 0x30fc, 0x30f4, 0x30a1, 0x30eb, 0x3b,
+0x30e1, 0x30d5, 0x30eb, 0x3b, 0x30a2, 0x30fc, 0x30d0, 0x30fc, 0x30f3, 0x3b, 0x30a2, 0x30fc,
+0x30b6, 0x30eb, 0x3b, 0x30c7, 0x30a4, 0x3b, 0x30d0, 0x30d5, 0x30de, 0x30f3, 0x3b, 0x30a8,
+0x30b9, 0x30d5, 0x30a1, 0x30f3, 0x30c9, 0xcab, 0xcb0, 0xccd, 0xcb5, 0xcb0, 0xccd, 0xca6,
+0xcbf, 0xca8, 0xccd, 0x3b, 0xc93, 0xcb0, 0xccd, 0xca6, 0xcbf, 0xcac, 0xcc6, 0xcb9,
+0xcc6, 0xcb6, 0xccd, 0xc9f, 0xccd, 0x3b, 0xc96, 0xccb, 0xcb0, 0xccd, 0xca1, 0xcbe,
+0xca6, 0xccd, 0x3b, 0xc9f, 0xcbf, 0xcb0, 0xccd, 0x3b, 0xcae, 0xcca, 0xcb0, 0xccd,
+0xca6, 0xcbe, 0xca6, 0xccd, 0x3b, 0xcb6, 0xcb9, 0xcb0, 0xcbf, 0xcb5, 0xcbe, 0xcb0,
+0xccd, 0x3b, 0xcae, 0xcc6, 0xcb9, 0xccd, 0xcb0, 0xccd, 0x3b, 0xc85, 0xcac, 0xca8,
+0xccd, 0x3b, 0xc85, 0xc9d, 0xcb0, 0xccd, 0x3b, 0xca1, 0xcc7, 0x3b, 0xcac, 0xcb9,
+0xccd, 0xcae, 0xca8, 0xccd, 0x3b, 0xc8e, 0xcb8, 0xccd, 0xcab, 0xcbe, 0xc82, 0xca1,
+0xccd, 0x424, 0x430, 0x440, 0x432, 0x430, 0x440, 0x434, 0x438, 0x43d, 0x3b, 0x41e,
+0x440, 0x434, 0x438, 0x431, 0x435, 0x445, 0x435, 0x448, 0x442, 0x3b, 0x425, 0x43e,
+0x440, 0x434, 0x430, 0x434, 0x3b, 0x422, 0x438, 0x440, 0x3b, 0x41c, 0x43e, 0x440,
+0x434, 0x430, 0x434, 0x3b, 0x428, 0x430, 0x445, 0x440, 0x438, 0x432, 0x430, 0x440,
+0x3b, 0x41c, 0x435, 0x445, 0x440, 0x3b, 0x410, 0x431, 0x430, 0x43d, 0x3b, 0x410,
+0x437, 0x430, 0x440, 0x3b, 0x414, 0x435, 0x439, 0x3b, 0x411, 0x430, 0x445, 0x43c,
+0x430, 0x43d, 0x3b, 0x42d, 0x441, 0x444, 0x430, 0x43d, 0x434, 0xd654, 0xb974, 0xbc14,
+0xb518, 0x3b, 0xc624, 0xb974, 0xb514, 0xbca0, 0xd5e4, 0xc26c, 0xd2b8, 0x3b, 0xd638, 0xb974,
+0xb2e4, 0xb4dc, 0x3b, 0xd2f0, 0xb974, 0x3b, 0xbaa8, 0xb974, 0xb2e4, 0xb4dc, 0x3b, 0xc0e4,
+0xd750, 0xb9ac, 0xbc14, 0xb974, 0x3b, 0xba54, 0xd750, 0xb974, 0x3b, 0xc544, 0xbc18, 0x3b,
+0xc544, 0xc790, 0xb974, 0x3b, 0xb2e4, 0xc774, 0x3b, 0xbc14, 0xd750, 0xb9cc, 0x3b, 0xc5d0,
+0xc2a4, 0xd310, 0xb4dc, 0xe9f, 0xea3, 0xeb2, 0xea7, 0xeb2, 0xe94, 0xeb4, 0xe99, 0x3b,
+0xead, 0xecd, 0xea3, 0xe94, 0xeb5, 0xe9a, 0xeb5, 0xec0, 0xeab, 0xea3, 0xe94, 0x3b,
+0xe84, 0xecd, 0xea3, 0xec0, 0xe94, 0xe94, 0x3b, 0xec1, 0xe95, 0xea3, 0x3b, 0xea1,
+0xecd, 0xea3, 0xec0, 0xe94, 0xe94, 0x3b, 0xe8a, 0xeb2, 0xea3, 0xeab, 0xeb4, 0xea7,
+0xeb2, 0x3b, 0xec0, 0xea1, 0xeb5, 0x3b, 0xead, 0xeb2, 0xe9a, 0xeb2, 0xe99, 0x3b,
+0xead, 0xeb2, 0xe8a, 0xeb2, 0xea3, 0x3b, 0xe94, 0xeb5, 0xea3, 0x3b, 0xe9a, 0xea3,
+0xeb2, 0xec1, 0xea1, 0xe99, 0x3b, 0xec0, 0xead, 0xeaa, 0xe9f, 0xeb2, 0xe99, 0xe9f,
+0xea3, 0xeb2, 0xea7, 0xeb2, 0xe94, 0xeb4, 0xe99, 0x3b, 0xead, 0xecd, 0xea3, 0xe94,
+0xeb5, 0xe9a, 0xeb5, 0xec0, 0xeab, 0xeae, 0xe94, 0x3b, 0xe84, 0xecd, 0xea3, 0xec0,
+0xe94, 0xe94, 0x3b, 0xec1, 0xe95, 0xea3, 0x3b, 0xea1, 0xecd, 0xea3, 0xec0, 0xe94,
+0xe94, 0x3b, 0xe8a, 0xeb2, 0xea3, 0xea5, 0xeb4, 0xea7, 0xeb2, 0x3b, 0xec0, 0xea1,
+0xeb5, 0x3b, 0xead, 0xeb2, 0xe9a, 0xeb2, 0xe99, 0x3b, 0xead, 0xeb2, 0xe8a, 0xeb2,
+0x3b, 0xe94, 0xeb5, 0xea3, 0x3b, 0xe9a, 0xea3, 0xeb2, 0xea1, 0xeb2, 0xe99, 0x3b,
+0xec0, 0xead, 0xeaa, 0xe9f, 0xeb2, 0xe99, 0xe9f, 0xeb2, 0xea3, 0xea7, 0xeb2, 0xe94,
+0xeb4, 0xe99, 0x3b, 0xead, 0xecd, 0xea3, 0xe94, 0xeb5, 0xe9a, 0xeb5, 0xec0, 0xeab,
+0xea3, 0xe94, 0x3b, 0xe84, 0xecd, 0xea3, 0xec0, 0xe94, 0xe94, 0x3b, 0xec1, 0xe95,
+0xea3, 0x3b, 0xea1, 0xecd, 0xea3, 0xec0, 0xe94, 0xe94, 0x3b, 0xe8a, 0xeb2, 0xea3,
+0xeab, 0xeb4, 0xea7, 0xeb2, 0x3b, 0xec0, 0xea1, 0xeb5, 0x3b, 0xead, 0xeb2, 0xe9a,
+0xeb2, 0xe99, 0x3b, 0xead, 0xeb2, 0xe8a, 0xeb2, 0x3b, 0xe94, 0xeb5, 0xea3, 0x3b,
+0xe9a, 0xea3, 0xeb2, 0xea1, 0xeb2, 0xe99, 0x3b, 0xec0, 0xead, 0xeaa, 0xe9f, 0xeb2,
+0xe99, 0x66, 0x61, 0x72, 0x76, 0x61, 0x72, 0x64, 0x12b, 0x6e, 0x73, 0x3b,
+0x6f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x161, 0x74, 0x73, 0x3b,
+0x68, 0x6f, 0x72, 0x64, 0x101, 0x64, 0x73, 0x3b, 0x74, 0x12b, 0x72, 0x73,
+0x3b, 0x6d, 0x6f, 0x72, 0x64, 0x101, 0x64, 0x73, 0x3b, 0x161, 0x61, 0x68,
+0x72, 0x69, 0x76, 0x113, 0x72, 0x73, 0x3b, 0x6d, 0x65, 0x68, 0x72, 0x73,
+0x3b, 0x61, 0x62, 0x61, 0x6e, 0x73, 0x3b, 0x61, 0x7a, 0x65, 0x72, 0x73,
+0x3b, 0x64, 0x65, 0x6a, 0x73, 0x3b, 0x62, 0x61, 0x68, 0x6d, 0x61, 0x6e,
+0x73, 0x3b, 0x65, 0x73, 0x66, 0x61, 0x6e, 0x64, 0x73, 0x444, 0x430, 0x440,
+0x432, 0x430, 0x440, 0x434, 0x438, 0x43d, 0x3b, 0x43e, 0x440, 0x434, 0x438, 0x431,
+0x435, 0x445, 0x435, 0x448, 0x442, 0x3b, 0x43a, 0x43e, 0x440, 0x434, 0x430, 0x434,
+0x3b, 0x442, 0x438, 0x440, 0x3b, 0x43c, 0x43e, 0x440, 0x434, 0x430, 0x434, 0x3b,
+0x448, 0x430, 0x445, 0x440, 0x438, 0x432, 0x430, 0x440, 0x3b, 0x43c, 0x435, 0x440,
+0x3b, 0x430, 0x431, 0x430, 0x43d, 0x3b, 0x430, 0x437, 0x430, 0x440, 0x3b, 0x434,
+0x435, 0x458, 0x3b, 0x431, 0x430, 0x445, 0x43c, 0x430, 0x43d, 0x3b, 0x435, 0x441,
+0x444, 0x430, 0x43d, 0x434, 0xd2b, 0xd7c, 0xd35, 0xd3e, 0xd7c, 0xd26, 0xd3f, 0xd7b,
+0x3b, 0xd13, 0xd7c, 0xd21, 0xd3f, 0xd2c, 0xd46, 0xd39, 0xd46, 0xd37, 0xd4d, 0x200c,
+0xd31, 0xd4d, 0xd31, 0xd4d, 0x3b, 0xd16, 0xd4b, 0xd7c, 0xd26, 0xd3e, 0xd26, 0xd4d,
+0x3b, 0xd1f, 0xd3f, 0xd7c, 0x3b, 0xd2e, 0xd4b, 0xd7c, 0xd26, 0xd3e, 0xd26, 0xd4d,
+0x3b, 0xd37, 0xd39, 0xd4d, 0x200c, 0xd30, 0xd3f, 0xd35, 0xd3e, 0xd7c, 0x3b, 0xd2e,
+0xd46, 0xd39, 0xd7c, 0x3b, 0xd05, 0xd2c, 0xd3e, 0xd7b, 0x3b, 0xd05, 0xd38, 0xd7c,
+0x3b, 0xd21, 0xd46, 0xd2f, 0xd4d, 0x3b, 0xd2c, 0xd39, 0xd4d, 0x200c, 0xd2e, 0xd3e,
+0xd7b, 0x3b, 0xd0e, 0xd38, 0xd4d, 0x200c, 0xd2b, 0xd3e, 0xd7b, 0xd21, 0xd4d, 0xd2b,
+0x2e, 0x3b, 0xd13, 0x2e, 0x3b, 0xd16, 0xd4b, 0x3b, 0xd1f, 0xd3f, 0x2e, 0x3b,
+0xd2e, 0xd4b, 0x2e, 0x3b, 0xd37, 0x2e, 0x3b, 0xd2e, 0xd46, 0x2e, 0x3b, 0xd05,
+0x2e, 0x3b, 0xd05, 0x2e, 0x3b, 0xd21, 0xd46, 0x2e, 0x3b, 0xd2c, 0x2e, 0x3b,
+0xd0e, 0x2e, 0x92b, 0x930, 0x935, 0x930, 0x926, 0x93f, 0x928, 0x3b, 0x913, 0x930,
+0x94d, 0x926, 0x93f, 0x92c, 0x947, 0x939, 0x947, 0x936, 0x94d, 0x924, 0x3b, 0x916,
+0x94b, 0x930, 0x926, 0x93e, 0x926, 0x3b, 0x924, 0x93f, 0x930, 0x3b, 0x92e, 0x94b,
+0x930, 0x926, 0x93e, 0x926, 0x3b, 0x936, 0x93e, 0x939, 0x930, 0x940, 0x935, 0x93e,
+0x930, 0x3b, 0x92e, 0x947, 0x939, 0x947, 0x930, 0x3b, 0x905, 0x92c, 0x93e, 0x928,
+0x3b, 0x905, 0x91d, 0x93e, 0x930, 0x3b, 0x926, 0x947, 0x3b, 0x92c, 0x93e, 0x939,
+0x92e, 0x93e, 0x928, 0x3b, 0x90f, 0x938, 0x92b, 0x93e, 0x902, 0x926, 0x967, 0x3b,
+0x968, 0x3b, 0x969, 0x3b, 0x96a, 0x3b, 0x96b, 0x3b, 0x96c, 0x3b, 0x96d, 0x3b,
+0x96e, 0x3b, 0x96f, 0x3b, 0x967, 0x966, 0x3b, 0x967, 0x967, 0x3b, 0x967, 0x968,
+0x648, 0x631, 0x6cc, 0x3b, 0x63a, 0x648, 0x6cc, 0x6cc, 0x3b, 0x63a, 0x628, 0x631,
+0x6af, 0x648, 0x644, 0x6cc, 0x3b, 0x686, 0x646, 0x6af, 0x627, 0x69a, 0x3b, 0x632,
+0x645, 0x631, 0x6cc, 0x3b, 0x648, 0x696, 0x6cc, 0x3b, 0x62a, 0x644, 0x647, 0x3b,
+0x644, 0x693, 0x645, 0x3b, 0x644, 0x6cc, 0x646, 0x62f, 0x6cd, 0x3b, 0x645, 0x631,
+0x63a, 0x648, 0x645, 0x6cc, 0x3b, 0x633, 0x644, 0x648, 0x627, 0x63a, 0x647, 0x3b,
+0x6a9, 0x628, 0x6f1, 0x3b, 0x6f2, 0x3b, 0x6f3, 0x3b, 0x6f4, 0x3b, 0x6f5, 0x3b,
+0x6f6, 0x3b, 0x6f7, 0x3b, 0x6f8, 0x3b, 0x6f9, 0x3b, 0x6f1, 0x6f0, 0x3b, 0x6f1,
+0x6f1, 0x3b, 0x6f1, 0x6f2, 0x641, 0x631, 0x648, 0x631, 0x62f, 0x6cc, 0x646, 0x3b,
+0x627, 0x631, 0x62f, 0x6cc, 0x628, 0x647, 0x634, 0x62a, 0x3b, 0x62e, 0x631, 0x62f,
+0x627, 0x62f, 0x3b, 0x62a, 0x6cc, 0x631, 0x3b, 0x645, 0x631, 0x62f, 0x627, 0x62f,
+0x3b, 0x634, 0x647, 0x631, 0x6cc, 0x648, 0x631, 0x3b, 0x645, 0x647, 0x631, 0x3b,
+0x622, 0x628, 0x627, 0x646, 0x3b, 0x622, 0x630, 0x631, 0x3b, 0x62f, 0x6cc, 0x3b,
+0x628, 0x647, 0x645, 0x646, 0x3b, 0x627, 0x633, 0x641, 0x646, 0x62f, 0x641, 0x3b,
+0x627, 0x3b, 0x62e, 0x3b, 0x62a, 0x3b, 0x645, 0x3b, 0x634, 0x3b, 0x645, 0x3b,
+0x622, 0x3b, 0x622, 0x3b, 0x62f, 0x3b, 0x628, 0x3b, 0x627, 0x62d, 0x645, 0x644,
+0x3b, 0x62b, 0x648, 0x631, 0x3b, 0x62c, 0x648, 0x632, 0x627, 0x3b, 0x633, 0x631,
+0x637, 0x627, 0x646, 0x3b, 0x627, 0x633, 0x62f, 0x3b, 0x633, 0x646, 0x628, 0x644,
+0x647, 0x654, 0x3b, 0x645, 0x6cc, 0x632, 0x627, 0x646, 0x3b, 0x639, 0x642, 0x631,
+0x628, 0x3b, 0x642, 0x648, 0x633, 0x3b, 0x62c, 0x62f, 0x6cc, 0x3b, 0x62f, 0x644,
+0x648, 0x3b, 0x62d, 0x648, 0x62a, 0x62d, 0x3b, 0x62b, 0x3b, 0x62c, 0x3b, 0x633,
+0x3b, 0x627, 0x3b, 0x633, 0x3b, 0x645, 0x3b, 0x639, 0x3b, 0x642, 0x3b, 0x62c,
+0x3b, 0x62f, 0x3b, 0x62d, 0x46, 0x61, 0x72, 0x77, 0x61, 0x72, 0x64, 0x69,
+0x6e, 0x3b, 0x4f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x73, 0x7a,
+0x74, 0x3b, 0x43, 0x68, 0x6f, 0x72, 0x64, 0x101, 0x64, 0x3b, 0x54, 0x69,
+0x72, 0x3b, 0x4d, 0x6f, 0x72, 0x64, 0x101, 0x64, 0x3b, 0x53, 0x7a, 0x61,
+0x68, 0x72, 0x69, 0x77, 0x61, 0x72, 0x3b, 0x4d, 0x65, 0x68, 0x72, 0x3b,
+0x100, 0x62, 0x101, 0x6e, 0x3b, 0x100, 0x73, 0x61, 0x72, 0x3b, 0x44, 0xe9,
+0x69, 0x3b, 0x42, 0x61, 0x68, 0x6d, 0x61, 0x6e, 0x3b, 0x45, 0x73, 0x66,
+0x61, 0x6e, 0x64, 0xa2b, 0xa3e, 0xa30, 0xa35, 0xa30, 0xa21, 0xa40, 0xa28, 0x3b,
+0xa14, 0xa30, 0xa21, 0xa3e, 0xa08, 0xa2c, 0xa39, 0xa48, 0xa38, 0xa3c, 0xa1f, 0x3b,
+0xa16, 0xa4b, 0xa21, 0xa30, 0xa21, 0x3b, 0xa1f, 0xa3f, 0xa30, 0x3b, 0xa2e, 0xa4b,
+0xa30, 0xa21, 0xa3e, 0xa26, 0x3b, 0xa38, 0xa3c, 0xa30, 0xa3e, 0xa07, 0xa35, 0xa30,
+0x3b, 0xa2e, 0xa47, 0xa39, 0xa30, 0x3b, 0xa05, 0xa2c, 0xa3e, 0xa28, 0x3b, 0xa05,
+0xa1c, 0xa3c, 0xa3e, 0xa30, 0x3b, 0xa21, 0xa47, 0xa05, 0x3b, 0xa2c, 0xa3e, 0xa39,
+0xa2e, 0xa28, 0x3b, 0xa10, 0xa38, 0xa2b, 0xa70, 0xa21, 0x46, 0x61, 0x72, 0x76,
+0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x4f, 0x72, 0x64, 0x69, 0x62, 0x65,
+0x68, 0x65, 0x73, 0x68, 0x74, 0x3b, 0x4b, 0x68, 0x6f, 0x72, 0x64, 0x61,
+0x64, 0x3b, 0x54, 0x69, 0x72, 0x3b, 0x41, 0x2d, 0x4d, 0x6f, 0x72, 0x64,
+0x61, 0x64, 0x3b, 0x53, 0x68, 0x61, 0x68, 0x72, 0x69, 0x76, 0x61, 0x72,
+0x3b, 0x4d, 0x65, 0x68, 0x72, 0x3b, 0x41, 0x62, 0x61, 0x6e, 0x3b, 0x41,
+0x7a, 0x61, 0x72, 0x3b, 0x44, 0x65, 0x79, 0x3b, 0x42, 0x61, 0x68, 0x6d,
+0x61, 0x6e, 0x3b, 0x45, 0x73, 0x66, 0x61, 0x6e, 0x64, 0x444, 0x430, 0x440,
+0x432, 0x430, 0x440, 0x434, 0x438, 0x43d, 0x3b, 0x43e, 0x440, 0x434, 0x438, 0x431,
+0x435, 0x445, 0x435, 0x448, 0x442, 0x3b, 0x445, 0x43e, 0x440, 0x434, 0x430, 0x434,
+0x3b, 0x442, 0x438, 0x440, 0x3b, 0x43c, 0x43e, 0x440, 0x434, 0x430, 0x434, 0x3b,
+0x448, 0x430, 0x445, 0x440, 0x438, 0x432, 0x435, 0x440, 0x3b, 0x43c, 0x435, 0x445,
+0x440, 0x3b, 0x430, 0x431, 0x430, 0x43d, 0x3b, 0x430, 0x437, 0x435, 0x440, 0x3b,
+0x434, 0x435, 0x439, 0x3b, 0x431, 0x430, 0x445, 0x43c, 0x430, 0x43d, 0x3b, 0x44d,
+0x441, 0x444, 0x430, 0x43d, 0x434, 0x66, 0x61, 0x72, 0x2e, 0x3b, 0x6f, 0x72,
+0x64, 0x2e, 0x3b, 0x6b, 0x68, 0x6f, 0x2e, 0x3b, 0x74, 0x69, 0x72, 0x3b,
+0x6d, 0x6f, 0x72, 0x2e, 0x3b, 0x73, 0x68, 0x61, 0x2e, 0x3b, 0x6d, 0x65,
+0x68, 0x72, 0x3b, 0x61, 0x62, 0x61, 0x6e, 0x3b, 0x61, 0x7a, 0x61, 0x72,
+0x3b, 0x64, 0x65, 0x79, 0x3b, 0x62, 0x61, 0x68, 0x2e, 0x3b, 0x65, 0x73,
+0x66, 0x2e, 0x46, 0x61, 0x72, 0x61, 0x76, 0x61, 0x64, 0x69, 0x6e, 0x3b,
+0x4f, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x161, 0x74, 0x3b, 0x4b,
+0x6f, 0x72, 0x64, 0x61, 0x64, 0x3b, 0x54, 0x69, 0x72, 0x3b, 0x4d, 0x6f,
+0x72, 0x64, 0x61, 0x64, 0x3b, 0x160, 0x61, 0x68, 0x72, 0x69, 0x76, 0x61,
+0x72, 0x3b, 0x4d, 0x65, 0x68, 0x72, 0x3b, 0x41, 0x62, 0x61, 0x6e, 0x3b,
+0x41, 0x7a, 0x61, 0x72, 0x3b, 0x44, 0x65, 0x6a, 0x3b, 0x42, 0x61, 0x68,
+0x6d, 0x61, 0x6e, 0x3b, 0x45, 0x73, 0x66, 0x61, 0x6e, 0x64, 0x4a, 0x61,
+0x6e, 0x61, 0x61, 0x79, 0x6f, 0x3b, 0x46, 0x65, 0x65, 0x62, 0x72, 0x61,
+0x61, 0x79, 0x6f, 0x3b, 0x4d, 0x61, 0x61, 0x72, 0x73, 0x6f, 0x3b, 0x41,
+0x62, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x61, 0x61, 0x79, 0x6f, 0x3b, 0x4a,
+0x75, 0x75, 0x6e, 0x3b, 0x4c, 0x75, 0x75, 0x6c, 0x69, 0x79, 0x6f, 0x3b,
+0x41, 0x67, 0x6f, 0x6f, 0x73, 0x74, 0x6f, 0x3b, 0x53, 0x61, 0x62, 0x74,
+0x65, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x6f,
+0x62, 0x61, 0x72, 0x3b, 0x4e, 0x6f, 0x6f, 0x66, 0x65, 0x65, 0x6d, 0x62,
+0x61, 0x72, 0x3b, 0x44, 0x69, 0x69, 0x73, 0x65, 0x65, 0x6d, 0x62, 0x61,
+0x72, 0x46, 0x61, 0x72, 0x76, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x4f,
+0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x73, 0x68, 0x74, 0x3b, 0x4b,
+0x68, 0x6f, 0x72, 0x64, 0x101, 0x64, 0x3b, 0x54, 0x69, 0x72, 0x3b, 0x4d,
+0x6f, 0x72, 0x64, 0x101, 0x64, 0x3b, 0x53, 0x68, 0x61, 0x68, 0x72, 0x69,
+0x76, 0x61, 0x72, 0x3b, 0x4d, 0x65, 0x68, 0x72, 0x3b, 0x100, 0x62, 0x101,
+0x6e, 0x3b, 0x100, 0x7a, 0x61, 0x72, 0x3b, 0x44, 0x65, 0x79, 0x3b, 0x42,
+0x61, 0x68, 0x6d, 0x61, 0x6e, 0x3b, 0x45, 0x73, 0x66, 0x61, 0x6e, 0x64,
+0x66, 0x61, 0x72, 0x76, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x6f, 0x72,
+0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x73, 0x68, 0x74, 0x3b, 0x6b, 0x68,
+0x6f, 0x72, 0x64, 0x101, 0x64, 0x3b, 0x74, 0x69, 0x72, 0x3b, 0x6d, 0x6f,
+0x72, 0x64, 0x101, 0x64, 0x3b, 0x73, 0x68, 0x61, 0x68, 0x72, 0x69, 0x76,
+0x61, 0x72, 0x3b, 0x6d, 0x65, 0x68, 0x72, 0x3b, 0x101, 0x62, 0x101, 0x6e,
+0x3b, 0x101, 0x7a, 0x61, 0x72, 0x3b, 0x64, 0x65, 0x79, 0x3b, 0x62, 0x61,
+0x68, 0x6d, 0x61, 0x6e, 0x3b, 0x65, 0x73, 0x66, 0x61, 0x6e, 0x64, 0x444,
+0x430, 0x440, 0x432, 0x430, 0x440, 0x434, 0x438, 0x43d, 0x3b, 0x443, 0x440, 0x434,
+0x438, 0x431, 0x438, 0x4b3, 0x438, 0x448, 0x442, 0x3b, 0x445, 0x443, 0x440, 0x434,
+0x43e, 0x434, 0x3b, 0x442, 0x438, 0x440, 0x3b, 0x43c, 0x443, 0x440, 0x434, 0x43e,
+0x434, 0x3b, 0x448, 0x430, 0x4b3, 0x440, 0x438, 0x432, 0x430, 0x440, 0x3b, 0x43c,
+0x435, 0x4b3, 0x440, 0x3b, 0x43e, 0x431, 0x43e, 0x43d, 0x3b, 0x43e, 0x437, 0x430,
+0x440, 0x3b, 0x434, 0x435, 0x439, 0x3b, 0x431, 0x430, 0x4b3, 0x43c, 0x430, 0x43d,
+0x3b, 0x438, 0x441, 0x444, 0x430, 0x43d, 0x434, 0xb83, 0xbaa, 0xbb0, 0xbcd, 0xbb5,
+0xbbe, 0xba4, 0xbbf, 0xba9, 0xbcd, 0x3b, 0xb86, 0xbb0, 0xbcd, 0xb9f, 0xbbf, 0xbaa,
+0xbc6, 0xbb9, 0xbc6, 0xbb7, 0xbcd, 0xba4, 0xbcd, 0x3b, 0xb95, 0xbca, 0xbb0, 0xbcd,
+0xba4, 0xbbe, 0xba4, 0xbcd, 0x3b, 0xba4, 0xbbf, 0xbb0, 0xbcd, 0x3b, 0xbae, 0xbca,
+0xbb0, 0xbcd, 0xba4, 0xbbe, 0xba4, 0xbcd, 0x3b, 0xbb7, 0xbbe, 0xbb0, 0xbbf, 0xbb5,
+0xbbe, 0xbb0, 0xbcd, 0x3b, 0xbae, 0xbc6, 0xbb9, 0xbcd, 0xbb0, 0xbcd, 0x3b, 0xb85,
+0xbaa, 0xbbe, 0xba9, 0xbcd, 0x3b, 0xb85, 0xb9a, 0xbbe, 0xbb0, 0xbcd, 0x3b, 0xba4,
+0xbc7, 0x3b, 0xbaa, 0xbb9, 0xbcd, 0xbae, 0xbbe, 0xba9, 0xbcd, 0x3b, 0xb8e, 0xb83,
+0xbaa, 0xbbe, 0xba9, 0xbcd, 0xb83, 0xbaa, 0xbb0, 0xbcd, 0x2e, 0x3b, 0xb86, 0xbb0,
+0xbcd, 0xb9f, 0xbbf, 0x2e, 0x3b, 0xb95, 0xbca, 0xbb0, 0xbcd, 0x2e, 0x3b, 0xba4,
+0xbbf, 0xbb0, 0xbcd, 0x3b, 0xbae, 0xbca, 0xbb0, 0xbcd, 0x2e, 0x3b, 0xbb7, 0xbbe,
+0xbb0, 0xbbf, 0x2e, 0x3b, 0xbae, 0xbc6, 0xbb9, 0xbcd, 0x2e, 0x3b, 0xb85, 0xbaa,
+0xbbe, 0x2e, 0x3b, 0xb85, 0xb9a, 0xbbe, 0x2e, 0x3b, 0xba4, 0xbc7, 0x3b, 0xbaa,
+0xbb9, 0xbcd, 0x2e, 0x3b, 0xb8e, 0xb83, 0x2e, 0xc2b, 0xc3e, 0xc35, 0xc30, 0xc4d,
+0xc21, 0xc3f, 0xc28, 0xc4d, 0x3b, 0xc0a, 0xc21, 0xc3e, 0xc2c, 0xc39, 0xc37, 0xc4d,
+0xc1f, 0xc4d, 0x3b, 0xc16, 0xc4b, 0xc30, 0xc4d, 0xc21, 0xc3e, 0xc21, 0xc4d, 0x3b,
+0xc1f, 0xc3f, 0xc30, 0xc4d, 0x3b, 0xc2e, 0xc46, 0xc30, 0xc4d, 0xc21, 0xc3e, 0xc21,
+0xc4d, 0x3b, 0xc36, 0xc36, 0xc3f, 0xc35, 0xc30, 0xc4d, 0x3b, 0xc2e, 0xc46, 0xc39,
+0xc30, 0xc4d, 0x3b, 0xc05, 0xc2c, 0xc28, 0xc4d, 0x3b, 0xc05, 0xc1c, 0xc30, 0xc4d,
+0x3b, 0xc21, 0xc47, 0x3b, 0xc2c, 0xc3e, 0xc39, 0xc4d, 0x200c, 0xc2e, 0xc3e, 0xc28,
+0xc4d, 0x3b, 0xc0e, 0xc38, 0xc4d, 0x200c, 0xc2b, 0xc3e, 0xc02, 0xc21, 0xc4d, 0xe1f,
+0xe32, 0xe23, 0xe4c, 0xe27, 0xe32, 0xe23, 0xe4c, 0xe14, 0xe34, 0xe19, 0x3b, 0xe2d,
+0xe2d, 0xe23, 0xe4c, 0xe14, 0xe34, 0xe40, 0xe1a, 0xe40, 0xe2e, 0xe0a, 0xe15, 0xe4c,
+0x3b, 0xe04, 0xe2d, 0xe23, 0xe4c, 0xe41, 0xe14, 0xe14, 0x3b, 0xe40, 0xe15, 0xe2d,
+0xe23, 0xe4c, 0x3b, 0xe21, 0xe2d, 0xe23, 0xe4c, 0xe41, 0xe14, 0xe14, 0x3b, 0xe0a,
+0xe32, 0xe2b, 0xe23, 0xe34, 0xe27, 0xe32, 0xe23, 0xe4c, 0x3b, 0xe40, 0xe21, 0xe2e,
+0xe23, 0xe4c, 0x3b, 0xe2d, 0xe30, 0xe1a, 0xe32, 0xe19, 0x3b, 0xe2d, 0xe30, 0xe0b,
+0xe32, 0xe23, 0xe4c, 0x3b, 0xe40, 0xe14, 0xe22, 0xe4c, 0x3b, 0xe1a, 0xe32, 0xe2e,
+0xe4c, 0xe21, 0xe32, 0xe19, 0x3b, 0xe40, 0xe2d, 0xe2a, 0xe1f, 0xe32, 0xe19, 0xe14,
+0xe4c, 0x46, 0x65, 0x72, 0x76, 0x65, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x4f,
+0x72, 0x64, 0x69, 0x62, 0x65, 0x68, 0x65, 0x15f, 0x74, 0x3b, 0x48, 0x6f,
+0x72, 0x64, 0x61, 0x64, 0x3b, 0x54, 0x69, 0x72, 0x3b, 0x4d, 0x6f, 0x72,
+0x64, 0x61, 0x64, 0x3b, 0x15e, 0x65, 0x68, 0x72, 0x69, 0x76, 0x65, 0x72,
+0x3b, 0x4d, 0x65, 0x68, 0x72, 0x3b, 0x41, 0x62, 0x61, 0x6e, 0x3b, 0x41,
+0x7a, 0x65, 0x72, 0x3b, 0x44, 0x65, 0x79, 0x3b, 0x42, 0x65, 0x68, 0x6d,
+0x65, 0x6e, 0x3b, 0x45, 0x73, 0x66, 0x65, 0x6e, 0x64, 0x444, 0x430, 0x440,
+0x432, 0x430, 0x440, 0x434, 0x456, 0x43d, 0x3b, 0x43e, 0x440, 0x434, 0x456, 0x431,
+0x435, 0x445, 0x435, 0x448, 0x442, 0x3b, 0x445, 0x43e, 0x440, 0x434, 0x430, 0x434,
+0x3b, 0x442, 0x456, 0x440, 0x3b, 0x43c, 0x43e, 0x440, 0x434, 0x430, 0x434, 0x3b,
+0x448, 0x430, 0x445, 0x440, 0x456, 0x432, 0x435, 0x440, 0x3b, 0x43c, 0x435, 0x445,
+0x440, 0x3b, 0x430, 0x431, 0x430, 0x43d, 0x3b, 0x430, 0x437, 0x435, 0x440, 0x3b,
+0x434, 0x435, 0x439, 0x3b, 0x431, 0x430, 0x445, 0x43c, 0x430, 0x43d, 0x3b, 0x435,
+0x441, 0x444, 0x430, 0x43d, 0x434, 0x444, 0x430, 0x440, 0x3b, 0x43e, 0x440, 0x434,
+0x3b, 0x445, 0x43e, 0x440, 0x3b, 0x442, 0x456, 0x440, 0x3b, 0x43c, 0x43e, 0x440,
+0x3b, 0x448, 0x430, 0x445, 0x3b, 0x43c, 0x435, 0x445, 0x3b, 0x430, 0x431, 0x430,
+0x43d, 0x3b, 0x430, 0x437, 0x435, 0x440, 0x3b, 0x434, 0x435, 0x439, 0x3b, 0x431,
+0x430, 0x445, 0x3b, 0x435, 0x441, 0x444, 0x444, 0x430, 0x440, 0x2e, 0x3b, 0x43e,
+0x440, 0x434, 0x2e, 0x3b, 0x445, 0x43e, 0x440, 0x2e, 0x3b, 0x442, 0x456, 0x440,
+0x3b, 0x43c, 0x43e, 0x440, 0x2e, 0x3b, 0x448, 0x430, 0x445, 0x2e, 0x3b, 0x43c,
+0x435, 0x445, 0x2e, 0x3b, 0x430, 0x431, 0x430, 0x43d, 0x3b, 0x430, 0x437, 0x435,
+0x440, 0x3b, 0x434, 0x435, 0x439, 0x3b, 0x431, 0x430, 0x445, 0x2e, 0x3b, 0x435,
+0x441, 0x444, 0x2e, 0x641, 0x631, 0x648, 0x631, 0x62f, 0x646, 0x3b, 0x622, 0x631,
+0x688, 0x628, 0x627, 0x626, 0x634, 0x3b, 0x62e, 0x62f, 0x627, 0x62f, 0x627, 0x62f,
+0x3b, 0x62a, 0x6cc, 0x631, 0x3b, 0x645, 0x631, 0x62f, 0x627, 0x62f, 0x3b, 0x634,
+0x6c1, 0x631, 0x6cc, 0x648, 0x627, 0x631, 0x3b, 0x645, 0x6c1, 0x631, 0x3b, 0x627,
+0x628, 0x627, 0x646, 0x3b, 0x622, 0x632, 0x631, 0x3b, 0x688, 0x6d2, 0x3b, 0x628,
+0x6c1, 0x645, 0x646, 0x3b, 0x627, 0x633, 0x641, 0x646, 0x62f, 0x66, 0x61, 0x72,
+0x76, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x6f, 0x2bb, 0x72, 0x64, 0x69,
+0x62, 0x65, 0x68, 0x69, 0x73, 0x68, 0x74, 0x3b, 0x78, 0x75, 0x72, 0x64,
+0x6f, 0x64, 0x3b, 0x74, 0x75, 0x72, 0x3b, 0x6d, 0x75, 0x72, 0x64, 0x6f,
+0x64, 0x3b, 0x73, 0x68, 0x61, 0x68, 0x72, 0x69, 0x76, 0x61, 0x72, 0x3b,
+0x6d, 0x65, 0x68, 0x72, 0x3b, 0x6f, 0x62, 0x6f, 0x6e, 0x3b, 0x6f, 0x7a,
+0x61, 0x72, 0x3b, 0x64, 0x65, 0x79, 0x3b, 0x62, 0x61, 0x68, 0x6d, 0x61,
+0x6e, 0x3b, 0x69, 0x73, 0x66, 0x61, 0x6e, 0x64, 0x66, 0x61, 0x72, 0x76,
+0x61, 0x72, 0x64, 0x69, 0x6e, 0x3b, 0x6f, 0x2bb, 0x72, 0x64, 0x69, 0x62,
+0x65, 0x68, 0x69, 0x73, 0x68, 0x74, 0x3b, 0x78, 0x75, 0x72, 0x64, 0x6f,
+0x64, 0x3b, 0x74, 0x69, 0x72, 0x3b, 0x6d, 0x75, 0x72, 0x64, 0x6f, 0x64,
+0x3b, 0x73, 0x68, 0x61, 0x68, 0x72, 0x69, 0x76, 0x61, 0x72, 0x3b, 0x6d,
+0x65, 0x68, 0x72, 0x3b, 0x6f, 0x62, 0x6f, 0x6e, 0x3b, 0x6f, 0x7a, 0x61,
+0x72, 0x3b, 0x64, 0x65, 0x79, 0x3b, 0x62, 0x61, 0x68, 0x6d, 0x61, 0x6e,
+0x3b, 0x69, 0x73, 0x66, 0x61, 0x6e, 0x66, 0x61, 0x72, 0x76, 0x61, 0x72,
+0x64, 0x69, 0x6e, 0x3b, 0x6f, 0x2bb, 0x72, 0x64, 0x69, 0x62, 0x65, 0x68,
+0x69, 0x73, 0x68, 0x74, 0x3b, 0x78, 0x75, 0x72, 0x64, 0x6f, 0x64, 0x3b,
+0x74, 0x69, 0x72, 0x3b, 0x6d, 0x75, 0x72, 0x64, 0x6f, 0x64, 0x3b, 0x73,
+0x68, 0x61, 0x68, 0x72, 0x69, 0x76, 0x61, 0x72, 0x3b, 0x6d, 0x65, 0x68,
+0x72, 0x3b, 0x6f, 0x62, 0x6f, 0x6e, 0x3b, 0x6f, 0x7a, 0x61, 0x72, 0x3b,
+0x64, 0x65, 0x79, 0x3b, 0x62, 0x61, 0x68, 0x6d, 0x61, 0x6e, 0x3b, 0x69,
+0x73, 0x66, 0x61, 0x6e, 0x64
};
// GENERATED PART ENDS HERE
diff --git a/src/corelib/time/qlocaltime.cpp b/src/corelib/time/qlocaltime.cpp
index d8c0a3f823..609a5a4b37 100644
--- a/src/corelib/time/qlocaltime.cpp
+++ b/src/corelib/time/qlocaltime.cpp
@@ -20,6 +20,11 @@
# include <qt_windows.h>
#endif
+#ifdef __GLIBC__ // Extends struct tm with some extra fields:
+#define HAVE_TM_GMTOFF // tm_gmtoff is the UTC offset.
+#define HAVE_TM_ZONE // tm_zone is the zone abbreviation.
+#endif
+
QT_BEGIN_NAMESPACE
using namespace QtPrivate::DateTimeConstants;
@@ -38,6 +43,35 @@ constexpr inline qint64 tmSecsWithinDay(const struct tm &when)
return (when.tm_hour * MINS_PER_HOUR + when.tm_min) * SECS_PER_MIN + when.tm_sec;
}
+/* Call mktime() and make sense of the result.
+
+ This packages the call to mktime() with the needed determination of whether
+ that succeeded and whether the call has materially perturbed, including
+ normalizing, the struct tm it was passed (as opposed to merely filling in
+ details).
+*/
+class MkTimeResult
+{
+ // mktime()'s return on error; or last second of 1969 UTC:
+ static constexpr time_t maybeError = -1;
+ inline bool meansEnd1969();
+ bool changed(const struct tm &prior) const;
+
+public:
+ struct tm local = {}; // Describes the local time in familiar form.
+ time_t utcSecs = maybeError; // Seconds since UTC epoch.
+ bool good = false; // Ignore the rest unless this is true.
+ bool adjusted = true; // Is local at odds with prior ?
+ MkTimeResult() { local.tm_isdst = -1; }
+
+ // Note: the calls to qMkTime() and meansEnd1969() potentially modify local.
+ explicit MkTimeResult(const struct tm &prior)
+ : local(prior), utcSecs(qMkTime(&local)),
+ good(utcSecs != maybeError || meansEnd1969()),
+ adjusted(changed(prior))
+ {}
+};
+
/* If mktime() returns -1, is it really an error ?
It might return -1 because we're looking at the last second of 1969 and
@@ -49,110 +83,62 @@ constexpr inline qint64 tmSecsWithinDay(const struct tm &when)
check errno, but we call mktime from within a qt_scoped_lock(QBasicMutex),
whose unlocking and destruction of the locker might frob errno.)
- We can assume the zone offset is a multiple of five minutes and less than a
- day, so this can only arise for the last second of a minute that differs from
- 59 by a multiple of 5 on the last day of 1969 or the first day of 1970. That
- makes for a cheap pre-test; if it holds, we can ask mktime about the first
- second of the same minute; if it gives us -60, then the -1 we originally saw
- is not an error (or was an error, but needn't have been).
+ We can assume time-zone offsets are less than a day, so this can only arise
+ if the struct tm describes either the last day of 1969 or the first day of
+ 1970. When we do know the offset (a glibc extension supplies it as a member
+ of struct tm), we can determine whether we're on the last second of the day,
+ refining that check. That makes for a cheap pre-test; if it holds, we can ask
+ mktime() about the preceding second; if it gives us -2, then the -1 we
+ originally saw is not (or at least didn't need to be) an error. We can then
+ synthesize a corrected value for local using the -2 result.
*/
-inline bool meansEnd1969(tm *local)
+inline bool MkTimeResult::meansEnd1969()
{
#ifdef Q_OS_WIN
- Q_UNUSED(local);
return false;
#else
- if (local->tm_sec < 59 || local->tm_year < 69 || local->tm_year > 70
- || local->tm_min % 5 != 4 // Assume zone offset is a multiple of 5 mins
- || (local->tm_year == 69
- ? local->tm_mon < 11 || local->tm_mday < 31
- : local->tm_mon > 0 || local->tm_mday > 1)) {
+ if (local.tm_year < 69 || local.tm_year > 70
+# ifdef HAVE_TM_GMTOFF
+ // Africa/Monrovia had offset 00:44:30 at the epoch, so (although all
+ // other zones' offsets were round multiples of five minutes) we need
+ // the offset to determine whether the time might match:
+ || (tmSecsWithinDay(local) - local.tm_gmtoff + 1) % SECS_PER_DAY
+# endif
+ || (local.tm_year == 69 // ... and less than a day:
+ ? local.tm_mon < 11 || local.tm_mday < 31
+ : local.tm_mon > 0 || local.tm_mday > 1)) {
return false;
}
- tm copy = *local;
+ struct tm copy = local;
copy.tm_sec--; // Preceding second should get -2, not -1
if (qMkTime(&copy) != -2)
return false;
// The original call to qMkTime() may have returned -1 as failure, not
// updating local, even though it could have; so fake it here. Assumes there
// was no transition in the last minute of the day !
- *local = copy;
- local->tm_sec++; // Advance back to the intended second
+ local = copy;
+ local.tm_sec++; // Advance back to the intended second
return true;
#endif
}
-/*
- Call mktime but bypass its fixing of denormal times.
-
- The POSIX spec says mktime() accepts a struct tm whose fields lie outside
- the usual ranges; the parameter is not const-qualified and will be updated
- to have values in those ranges. However, MS's implementation doesn't do that
- (or hasn't always done it); and the only member we actually want updated is
- the tm_isdst flag. (Aside: MS's implementation also only works for tm_year
- >= 70; this is, in fact, in accordance with the POSIX spec; but all known
- UNIX libc implementations in fact have a signed time_t and Do The Sensible
- Thing, to the best of their ability, at least for 0 <= tm_year < 70; see
- meansEnd1969 for the handling of the last second of UTC's 1969.)
-
- If we thought we knew tm_isdst and mktime() disagrees, it'll let us know
- either by correcting it - in which case it adjusts the struct tm to reflect
- the same time, but represented using the right tm_isdst, so typically an
- hour earlier or later - or by returning -1. When this happens, the way we
- actually use mktime(), we don't want a revised time with corrected DST, we
- want the original time with its corrected DST; so we retry the call, this
- time not claiming to know the DST-ness.
-
- POSIX doesn't actually say what to do if the specified struct tm describes a
- time in a spring-forward gap: read literally, this is an unrepresentable
- time and it could return -1, setting errno to EOVERFLOW. However, actual
- implementations chose a time one side or the other of the gap. For example,
- if we claim to know DST, glibc pushes to the other side of the gap (changing
- tm_isdst), but stays on the indicated branch of a repetition (no change to
- tm_isdst); this matches how QTimeZonePrivate::dataForLocalTime() uses its
- hint; in either case, if we don't claim to know DST, glibc picks the DST
- candidate. (Experiments conducted with glibc 2.31-9.)
-*/
-inline bool callMkTime(tm *local, time_t *secs)
+bool MkTimeResult::changed(const struct tm &prior) const
{
- constexpr time_t maybeError = -1; // mktime()'s return on error; or last second of 1969 UTC.
- const tm copy = *local;
- *secs = qMkTime(local);
- bool good = *secs != maybeError || meansEnd1969(local);
- if (copy.tm_isdst >= 0 && (!good || local->tm_isdst != copy.tm_isdst)) {
- // We thought we knew DST-ness, but were wrong:
- *local = copy;
- local->tm_isdst = -1;
- *secs = qMkTime(local);
- good = *secs != maybeError || meansEnd1969(local);
- }
-#if defined(Q_OS_WIN)
- // Windows mktime for the missing hour backs up 1 hour instead of advancing
- // 1 hour. If time differs and is standard time then this has happened, so
- // add 2 hours to the time and 1 hour to the secs
- if (local->tm_isdst == 0 && local->tm_hour != copy.tm_hour) {
- local->tm_hour += 2;
- if (local->tm_hour > 23) {
- local->tm_hour -= 24;
- if (++local->tm_mday > QGregorianCalendar::monthLength(
- local->tm_mon + 1, qYearFromTmYear(local->tm_year))) {
- local->tm_mday = 1;
- if (++local->tm_mon > 11) {
- local->tm_mon = 0;
- ++local->tm_year;
- }
- }
- }
- *secs += 3600;
- local->tm_isdst = 1;
- }
-#endif // Q_OS_WIN
- return good;
+ // If mktime() has been passed a copy of prior and local is its value on
+ // return, this checks whether mktime() has made a material change
+ // (including normalization) to the value, as opposed to merely filling in
+ // the fields that it's specified to fill in. It returns true if there has
+ // been any material change.
+ return !(prior.tm_year == local.tm_year && prior.tm_mon == local.tm_mon
+ && prior.tm_mday == local.tm_mday && prior.tm_hour == local.tm_hour
+ && prior.tm_min == local.tm_min && prior.tm_sec == local.tm_sec
+ && (prior.tm_isdst == -1
+ ? local.tm_isdst >= 0 : prior.tm_isdst == local.tm_isdst));
}
-struct tm timeToTm(qint64 localDay, int secs, QDateTimePrivate::DaylightStatus dst)
+struct tm timeToTm(qint64 localDay, int secs)
{
- Q_ASSERT(0 <= secs && secs < 3600 * 24);
+ Q_ASSERT(0 <= secs && secs < SECS_PER_DAY);
const auto ymd = QGregorianCalendar::partsFromJulian(JULIAN_DAY_FOR_EPOCH + localDay);
struct tm local = {};
local.tm_year = tmYearFromQYear(ymd.year);
@@ -161,10 +147,318 @@ struct tm timeToTm(qint64 localDay, int secs, QDateTimePrivate::DaylightStatus d
local.tm_hour = secs / 3600;
local.tm_min = (secs % 3600) / 60;
local.tm_sec = (secs % 60);
- local.tm_isdst = int(dst);
+ local.tm_isdst = -1;
return local;
}
+// Transitions account for a small fraction of 1% of the time.
+// So mark functions only used in handling them as cold.
+Q_DECL_COLD_FUNCTION
+struct tm matchYearMonth(struct tm when, const struct tm &base)
+{
+ // Adjust *when to be a denormal representation of the same point in time
+ // but with tm_year and tm_mon the same as base. In practice this will
+ // represent an adjacent month, so don't worry too much about optimising for
+ // any other case; we almost certainly run zero or one iteration of one of
+ // the year loops then zero or one iteration of one of the month loops.
+ while (when.tm_year > base.tm_year) {
+ --when.tm_year;
+ when.tm_mon += 12;
+ }
+ while (when.tm_year < base.tm_year) {
+ ++when.tm_year;
+ when.tm_mon -= 12;
+ }
+ Q_ASSERT(when.tm_year == base.tm_year);
+ while (when.tm_mon > base.tm_mon) {
+ const auto yearMon = QRoundingDown::qDivMod<12>(when.tm_mon);
+ int year = yearMon.quotient;
+ // We want the month before's Qt month number, which is the tm_mon mod 12:
+ int month = yearMon.remainder;
+ if (month == 0) {
+ --year;
+ month = 12;
+ }
+ year += when.tm_year;
+ when.tm_mday += QGregorianCalendar::monthLength(month, qYearFromTmYear(year));
+ --when.tm_mon;
+ }
+ while (when.tm_mon < base.tm_mon) {
+ const auto yearMon = QRoundingDown::qDivMod<12>(when.tm_mon);
+ // Qt month number is offset from tm_mon by one:
+ when.tm_mday -= QGregorianCalendar::monthLength(
+ yearMon.remainder + 1, qYearFromTmYear(yearMon.quotient + when.tm_year));
+ ++when.tm_mon;
+ }
+ Q_ASSERT(when.tm_mon == base.tm_mon);
+ return when;
+}
+
+Q_DECL_COLD_FUNCTION
+struct tm adjacentDay(struct tm when, int dayStep)
+{
+ // Before we adjust it, when is a return from timeToTm(), so in normal form.
+ Q_ASSERT(dayStep * dayStep == 1);
+ when.tm_mday += dayStep;
+ // That may have bumped us across a month boundary or even a year one.
+ // So now we normalize it.
+
+ if (dayStep < 0) {
+ if (when.tm_mday <= 0) {
+ // Month before's day-count; but tm_mon's value is one less than Qt's
+ // month numbering so, before we decrement it, it has the value we need,
+ // unless it's 0.
+ int daysInMonth = when.tm_mon
+ ? QGregorianCalendar::monthLength(when.tm_mon, qYearFromTmYear(when.tm_year))
+ : QGregorianCalendar::monthLength(12, qYearFromTmYear(when.tm_year - 1));
+ when.tm_mday += daysInMonth;
+ if (--when.tm_mon < 0) {
+ --when.tm_year;
+ when.tm_mon = 11;
+ }
+ Q_ASSERT(when.tm_mday >= 1);
+ }
+ } else if (when.tm_mday > 28) {
+ // We have to wind through months one at a time, since their lengths vary.
+ int daysInMonth = QGregorianCalendar::monthLength(
+ when.tm_mon + 1, qYearFromTmYear(when.tm_year));
+ if (when.tm_mday > daysInMonth) {
+ when.tm_mday -= daysInMonth;
+ if (++when.tm_mon > 11) {
+ ++when.tm_year;
+ when.tm_mon = 0;
+ }
+ Q_ASSERT(when.tm_mday <= QGregorianCalendar::monthLength(
+ when.tm_mon + 1, qYearFromTmYear(when.tm_year)));
+ }
+ }
+ return when;
+}
+
+Q_DECL_COLD_FUNCTION
+qint64 secondsBetween(const struct tm &start, const struct tm &stop)
+{
+ // Nominal difference between start and stop, in seconds (negative if start
+ // is after stop); may differ from actual UTC difference if there's a
+ // transition between them.
+ struct tm from = matchYearMonth(start, stop);
+ qint64 diff = stop.tm_mday - from.tm_mday; // in days
+ diff = diff * 24 + stop.tm_hour - from.tm_hour; // in hours
+ diff = diff * 60 + stop.tm_min - from.tm_min; // in minutes
+ return diff * 60 + stop.tm_sec - from.tm_sec; // in seconds
+}
+
+Q_DECL_COLD_FUNCTION
+MkTimeResult hopAcrossGap(const MkTimeResult &outside, const struct tm &base)
+{
+ // base fell in a gap; outside is one resolution
+ // This returns the other resolution, if possible.
+ const qint64 shift = secondsBetween(outside.local, base);
+ struct tm across;
+ // Shift is the nominal time adjustment between outside and base; now obtain
+ // the actual time that far from outside:
+ if (qLocalTime(outside.utcSecs + shift, &across)) {
+ const qint64 wider = secondsBetween(outside.local, across);
+ // That should be bigger than shift (typically by a factor of two), in
+ // the same direction:
+ if (shift > 0 ? wider > shift : wider < shift) {
+ MkTimeResult result(across);
+ if (result.good && !result.adjusted)
+ return result;
+ }
+ }
+ // This can surely only arise if the other resolution lies outside the
+ // time_t-range supported by the system functions.
+ return {};
+}
+
+Q_DECL_COLD_FUNCTION
+MkTimeResult resolveRejected(struct tm base, MkTimeResult result,
+ QDateTimePrivate::TransitionOptions resolve)
+{
+ // May result from a time outside the supported range of system time_t
+ // functions, or from a gap (on a platform where mktime() rejects them).
+ // QDateTime filters on times well outside the supported range, but may
+ // pass values only slightly outside the range.
+
+ // The easy case - no need to find a resolution anyway:
+ if (!resolve.testAnyFlags(QDateTimePrivate::GapMask))
+ return {};
+
+ constexpr time_t twoDaysInSeconds = 2 * 24 * 60 * 60;
+ // Bracket base, one day each side (in case the zone skipped a whole day):
+ MkTimeResult early(adjacentDay(base, -1));
+ MkTimeResult later(adjacentDay(base, +1));
+ if (!early.good || !later.good) // Assume out of range, rather than gap.
+ return {};
+
+ // OK, looks like a gap.
+ Q_ASSERT(twoDaysInSeconds + early.utcSecs > later.utcSecs);
+ result.adjusted = true;
+
+ // Extrapolate backwards from later if this option is set:
+ QDateTimePrivate::TransitionOption beforeLater = QDateTimePrivate::GapUseBefore;
+ if (resolve.testFlag(QDateTimePrivate::FlipForReverseDst)) {
+ // Reverse DST has DST before a gap and not after:
+ if (early.local.tm_isdst == 1 && !later.local.tm_isdst)
+ beforeLater = QDateTimePrivate::GapUseAfter;
+ }
+ if (resolve.testFlag(beforeLater)) // Result will be before the gap:
+ result.utcSecs = later.utcSecs - secondsBetween(base, later.local);
+ else // Result will be after the gap:
+ result.utcSecs = early.utcSecs + secondsBetween(early.local, base);
+
+ if (!qLocalTime(result.utcSecs, &result.local)) // Abandon hope.
+ return {};
+
+ return result;
+}
+
+Q_DECL_COLD_FUNCTION
+bool preferAlternative(QDateTimePrivate::TransitionOptions resolve,
+ // is_dst flags of incumbent and an alternative:
+ int gotDst, int altDst,
+ // True precisely if alternative selects a later UTC time:
+ bool altIsLater,
+ // True for a gap, false for a fold:
+ bool inGap)
+{
+ // If resolve has this option set, prefer the later candidate, else the earlier:
+ QDateTimePrivate::TransitionOption preferLater = inGap ? QDateTimePrivate::GapUseAfter
+ : QDateTimePrivate::FoldUseAfter;
+ if (resolve.testFlag(QDateTimePrivate::FlipForReverseDst)) {
+ // gotDst and altDst are {-1: unknown, 0: standard, 1: daylight-saving}
+ // So gotDst ^ altDst is 1 precisely if exactly one candidate thinks it's DST.
+ if ((altDst ^ gotDst) == 1) {
+ // In this case, we can tell whether we have reversed DST: that's a
+ // gap with DST before it or a fold with DST after it.
+#if 1
+ const bool isReversed = (altDst == 1) != (altIsLater == inGap);
+#else // Pedagogic version of the same thing:
+ bool isReversed;
+ if (altIsLater == inGap) // alt is after a gap or before a fold, so summer-time
+ isReversed = altDst != 1; // flip if summer-time isn't DST
+ else // alt is before a gap or after a fold, so winter-time
+ isReversed = altDst == 1; // flip if winter-time is DST
+#endif
+ if (isReversed) {
+ preferLater = inGap ? QDateTimePrivate::GapUseBefore
+ : QDateTimePrivate::FoldUseBefore;
+ }
+ } // Otherwise, we can't tell, so assume not.
+ }
+ return resolve.testFlag(preferLater) == altIsLater;
+}
+
+/*
+ Determine UTC time and offset, if possible, at a given local time.
+
+ The local time is specified as a number of seconds since the epoch (so, in
+ effect, a time_t, albeit delivered as qint64). If the specified local time
+ falls in a transition, resolve determines what to do.
+
+ If the specified local time is outside what the system time_t APIs will
+ handle, this fails.
+*/
+MkTimeResult resolveLocalTime(qint64 local, QDateTimePrivate::TransitionOptions resolve)
+{
+ const auto localDaySecs = QRoundingDown::qDivMod<SECS_PER_DAY>(local);
+ struct tm base = timeToTm(localDaySecs.quotient, localDaySecs.remainder);
+
+ // Get provisional result (correct > 99.9 % of the time):
+ MkTimeResult result(base);
+
+ // Our callers (mostly) deal with questions of being within the range that
+ // system time_t functions can handle, and timeToTm() gave us data in
+ // normalized form, so the only excuse for !good or a change to the HH:mm:ss
+ // fields (aside from being at the boundary of time_t's supported range) is
+ // that we hit a gap, although we have to handle these cases differently:
+ if (!result.good) {
+ // Rejected. The tricky case: maybe mktime() doesn't resolve gaps.
+ return resolveRejected(base, result, resolve);
+ } else if (result.local.tm_isdst < 0) {
+ // Apparently success without knowledge of whether this is DST or not.
+ // Should not happen, but that means our usual understanding of what the
+ // system is up to has gone out the window. So just let it be.
+ } else if (result.adjusted) {
+ // Shunted out of a gap.
+ if (!resolve.testAnyFlags(QDateTimePrivate::GapMask)) {
+ result = {};
+ return result;
+ }
+
+ // Try to obtain a matching point on the other side of the gap:
+ const MkTimeResult flipped = hopAcrossGap(result, base);
+ // Even if that failed, result may be the correct resolution
+
+ if (preferAlternative(resolve, result.local.tm_isdst, flipped.local.tm_isdst,
+ flipped.utcSecs > result.utcSecs, true)) {
+ // If hopAcrossGap() failed and we do need its answer, give up.
+ if (!flipped.good || flipped.adjusted)
+ return {};
+
+ // As resolution of local, flipped involves adjustment (across gap):
+ result = flipped;
+ result.adjusted = true;
+ }
+ } else if (resolve.testFlag(QDateTimePrivate::FlipForReverseDst)
+ // In fold, DST counts as before and standard as after -
+ // we may not need to check whether we're in a transition:
+ && resolve.testFlag(result.local.tm_isdst ? QDateTimePrivate::FoldUseBefore
+ : QDateTimePrivate::FoldUseAfter)) {
+ // We prefer DST or standard and got what we wanted, so we're good.
+ // As below, but we don't need to check, because we're on the side of
+ // the transition that it would select as valid, if we were near one.
+ // NB: this branch is routinely exercised, when QDT::Data::isShort()
+ // obliges us to rediscover an offsetFromUtc that ShortData has no space
+ // to store, as it does remember the DST status we got before.
+ } else {
+ // What we gave was valid. However, it might have been in a fall-back.
+ // If so, the same input but with tm_isdst flipped should also be valid.
+ struct tm copy = base;
+ copy.tm_isdst = !result.local.tm_isdst;
+ const MkTimeResult flipped(copy);
+ if (flipped.good && !flipped.adjusted) {
+ // We're in a fall-back
+ if (!resolve.testAnyFlags(QDateTimePrivate::FoldMask)) {
+ result = {};
+ return result;
+ }
+
+ // Work out which repeat to use:
+ if (preferAlternative(resolve, result.local.tm_isdst, flipped.local.tm_isdst,
+ flipped.utcSecs > result.utcSecs, false)) {
+ result = flipped;
+ }
+ } // else: not in a transition, nothing to worry about.
+ }
+ return result;
+}
+
+inline std::optional<qint64> tmToJd(const struct tm &date)
+{
+ return QGregorianCalendar::julianFromParts(qYearFromTmYear(date.tm_year),
+ date.tm_mon + 1, date.tm_mday);
+}
+
+#define IC(N) std::integral_constant<qint64, N>()
+
+// True if combining day and seconds overflows qint64; otherwise, sets *epochSeconds
+inline bool daysAndSecondsOverflow(qint64 julianDay, qint64 daySeconds, qint64 *epochSeconds)
+{
+ return qMulOverflow(julianDay - JULIAN_DAY_FOR_EPOCH, IC(SECS_PER_DAY), epochSeconds)
+ || qAddOverflow(*epochSeconds, daySeconds, epochSeconds);
+}
+
+// True if combining seconds and millis overflows; otherwise sets *epochMillis
+inline bool secondsAndMillisOverflow(qint64 epochSeconds, qint64 millis, qint64 *epochMillis)
+{
+ return qMulOverflow(epochSeconds, IC(MSECS_PER_SEC), epochMillis)
+ || qAddOverflow(*epochMillis, millis, epochMillis);
+}
+
+#undef IC
+
} // namespace
namespace QLocalTime {
@@ -232,24 +526,6 @@ int getUtcOffset(qint64 atMSecsSinceEpoch)
}
#endif // QT_BOOTSTRAPPED
-#define IC(N) std::integral_constant<qint64, N>()
-
-// True if combining day and seconds overflows qint64; otherwise, sets *epochSeconds
-inline bool daysAndSecondsOverflow(qint64 julianDay, qint64 daySeconds, qint64 *epochSeconds)
-{
- return mul_overflow(julianDay - JULIAN_DAY_FOR_EPOCH, IC(SECS_PER_DAY), epochSeconds)
- || add_overflow(*epochSeconds, daySeconds, epochSeconds);
-}
-
-// True if combining seconds and millis overflows; otherwise sets *epochMillis
-inline bool secondsAndMillisOverflow(qint64 epochSeconds, qint64 millis, qint64 *epochMillis)
-{
- return mul_overflow(epochSeconds, IC(MSECS_PER_SEC), epochMillis)
- || add_overflow(*epochMillis, millis, epochMillis);
-}
-
-#undef IC
-
// Calls the platform variant of localtime() for the given utcMillis, and
// returns the local milliseconds, offset from UTC and DST status.
QDateTimePrivate::ZoneState utcToLocal(qint64 utcMillis)
@@ -265,15 +541,14 @@ QDateTimePrivate::ZoneState utcToLocal(qint64 utcMillis)
if (!qLocalTime(epochSeconds, &local))
return {utcMillis};
- qint64 jd;
- if (Q_UNLIKELY(!QGregorianCalendar::julianFromParts(qYearFromTmYear(local.tm_year),
- local.tm_mon + 1, local.tm_mday, &jd))) {
+ auto jd = tmToJd(local);
+ if (Q_UNLIKELY(!jd))
return {utcMillis};
- }
+
const qint64 daySeconds = tmSecsWithinDay(local);
Q_ASSERT(0 <= daySeconds && daySeconds < SECS_PER_DAY);
qint64 localSeconds, localMillis;
- if (Q_UNLIKELY(daysAndSecondsOverflow(jd, daySeconds, &localSeconds)
+ if (Q_UNLIKELY(daysAndSecondsOverflow(*jd, daySeconds, &localSeconds)
|| secondsAndMillisOverflow(localSeconds, qint64(msec), &localMillis))) {
return {utcMillis};
}
@@ -282,60 +557,65 @@ QDateTimePrivate::ZoneState utcToLocal(qint64 utcMillis)
return { localMillis, int(localSeconds - epochSeconds), dst };
}
-QString localTimeAbbbreviationAt(qint64 local, QDateTimePrivate::DaylightStatus dst)
+QString localTimeAbbbreviationAt(qint64 local, QDateTimePrivate::TransitionOptions resolve)
{
- const auto localDayMilli = QRoundingDown::qDivMod<MSECS_PER_DAY>(local);
- qint64 millis = localDayMilli.remainder;
- Q_ASSERT(0 <= millis && millis < MSECS_PER_DAY); // Definition of QRD::qDiv.
- struct tm tmLocal = timeToTm(localDayMilli.quotient, int(millis / MSECS_PER_SEC), dst);
- time_t utcSecs;
- if (!callMkTime(&tmLocal, &utcSecs))
+ auto use = resolveLocalTime(QRoundingDown::qDiv<MSECS_PER_SEC>(local), resolve);
+ if (!use.good)
return {};
- return qTzName(tmLocal.tm_isdst > 0 ? 1 : 0);
+#ifdef HAVE_TM_ZONE
+ if (use.local.tm_zone)
+ return QString::fromLocal8Bit(use.local.tm_zone);
+#endif
+ return qTzName(use.local.tm_isdst > 0 ? 1 : 0);
}
-QDateTimePrivate::ZoneState mapLocalTime(qint64 local, QDateTimePrivate::DaylightStatus dst)
+QDateTimePrivate::ZoneState mapLocalTime(qint64 local, QDateTimePrivate::TransitionOptions resolve)
{
+ // Revised later to match what use.local tells us:
qint64 localSecs = local / MSECS_PER_SEC;
- qint64 millis = local - localSecs * MSECS_PER_SEC; // 0 or with same sign as local
- const auto localDaySec = QRoundingDown::qDivMod<SECS_PER_DAY>(localSecs);
- qint64 daySecs = localDaySec.remainder;
- Q_ASSERT(0 <= daySecs && daySecs < SECS_PER_DAY); // Definition of QRD::qDiv.
-
- struct tm tmLocal = timeToTm(localDaySec.quotient, daySecs, dst);
- time_t utcSecs;
- if (!callMkTime(&tmLocal, &utcSecs))
+ auto use = resolveLocalTime(localSecs, resolve);
+ if (!use.good)
return {local};
- // TODO: for glibc, we could use tmLocal.tm_gmtoff
- // That would give us offset directly, hence localSecs = offset + utcSecs
- // Provisional offset, until we have a revised localSeconds:
- int offset = QRoundingDown::qDiv<MSECS_PER_SEC>(local) - utcSecs;
- dst = tmLocal.tm_isdst > 0 ? QDateTimePrivate::DaylightTime : QDateTimePrivate::StandardTime;
- qint64 jd;
- if (Q_UNLIKELY(!QGregorianCalendar::julianFromParts(
- qYearFromTmYear(tmLocal.tm_year), tmLocal.tm_mon + 1, tmLocal.tm_mday,
- &jd))) {
+ qint64 millis = local - localSecs * MSECS_PER_SEC;
+ // Division is defined to round towards zero:
+ Q_ASSERT(local < 0 ? (millis <= 0 && millis > -MSECS_PER_SEC)
+ : (millis >= 0 && millis < MSECS_PER_SEC));
+
+ QDateTimePrivate::DaylightStatus dst =
+ use.local.tm_isdst > 0 ? QDateTimePrivate::DaylightTime : QDateTimePrivate::StandardTime;
+
+#ifdef HAVE_TM_GMTOFF
+ const int offset = use.local.tm_gmtoff;
+ localSecs = offset + use.utcSecs;
+#else
+ // Provisional offset, until we have a revised localSecs:
+ int offset = localSecs - use.utcSecs;
+ auto jd = tmToJd(use.local);
+ if (Q_UNLIKELY(!jd))
return {local, offset, dst, false};
- }
- daySecs = tmSecsWithinDay(tmLocal);
+
+ qint64 daySecs = tmSecsWithinDay(use.local);
Q_ASSERT(0 <= daySecs && daySecs < SECS_PER_DAY);
- if (daySecs > 0 && jd < JULIAN_DAY_FOR_EPOCH) {
- ++jd;
+ if (daySecs > 0 && *jd < JULIAN_DAY_FOR_EPOCH) {
+ jd = *jd + 1;
daySecs -= SECS_PER_DAY;
}
- if (Q_UNLIKELY(daysAndSecondsOverflow(jd, daySecs, &localSecs)))
+ if (Q_UNLIKELY(daysAndSecondsOverflow(*jd, daySecs, &localSecs)))
return {local, offset, dst, false};
- offset = localSecs - utcSecs;
+ // Use revised localSecs to refine offset:
+ offset = localSecs - use.utcSecs;
+#endif // HAVE_TM_GMTOFF
// The only way localSecs and millis can now have opposite sign is for
// resolution of the local time to have kicked us across the epoch, in which
// case there's no danger of overflow. So if overflow is in danger of
// happening, we're already doing the best we can to avoid it.
qint64 revised;
- const bool overflow = secondsAndMillisOverflow(localSecs, millis, &revised);
- return {overflow ? local : revised, offset, dst, !overflow};
+ if (secondsAndMillisOverflow(localSecs, millis, &revised))
+ return {local, offset, QDateTimePrivate::UnknownDaylightTime, false};
+ return {revised, offset, dst, true};
}
/*!
@@ -369,9 +649,7 @@ QDateTimePrivate::ZoneState mapLocalTime(qint64 local, QDateTimePrivate::Dayligh
SystemMillisRange computeSystemMillisRange()
{
// Assert this here, as this is called just once, in a static initialization.
- [[maybe_unused]] qint64 epochJd;
- Q_ASSERT(QGregorianCalendar::julianFromParts(1970, 1, 1, &epochJd)
- && epochJd == JULIAN_DAY_FOR_EPOCH);
+ Q_ASSERT(QGregorianCalendar::julianFromParts(1970, 1, 1) == JULIAN_DAY_FOR_EPOCH);
constexpr qint64 TIME_T_MAX = std::numeric_limits<time_t>::max();
using Bounds = std::numeric_limits<qint64>;
diff --git a/src/corelib/time/qlocaltime_p.h b/src/corelib/time/qlocaltime_p.h
index 027b1bc05b..5e31d5e9cc 100644
--- a/src/corelib/time/qlocaltime_p.h
+++ b/src/corelib/time/qlocaltime_p.h
@@ -34,8 +34,8 @@ Q_CORE_EXPORT int getUtcOffset(qint64 atMSecsSinceEpoch);
// Support for QDateTime
QDateTimePrivate::ZoneState utcToLocal(qint64 utcMillis);
-QString localTimeAbbbreviationAt(qint64 local, QDateTimePrivate::DaylightStatus dst);
-QDateTimePrivate::ZoneState mapLocalTime(qint64 local, QDateTimePrivate::DaylightStatus dst);
+QString localTimeAbbbreviationAt(qint64 local, QDateTimePrivate::TransitionOptions resolve);
+QDateTimePrivate::ZoneState mapLocalTime(qint64 local, QDateTimePrivate::TransitionOptions resolve);
struct SystemMillisRange { qint64 min, max; bool minClip, maxClip; };
SystemMillisRange computeSystemMillisRange();
diff --git a/src/corelib/time/qromancalendar_data_p.h b/src/corelib/time/qromancalendar_data_p.h
index d7e249f52c..320a19ccdc 100644
--- a/src/corelib/time/qromancalendar_data_p.h
+++ b/src/corelib/time/qromancalendar_data_p.h
@@ -1,5 +1,5 @@
// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: Unicode-3.0
#ifndef QROMANCALENDAR_DATA_P_H
#define QROMANCALENDAR_DATA_P_H
@@ -25,8 +25,8 @@ namespace QtPrivate::Roman {
// GENERATED PART STARTS HERE
/*
- This part of the file was generated on 2023-02-02 from the
- Common Locale Data Repository v42
+ This part of the file was generated on 2024-01-09 from the
+ Common Locale Data Repository v44.1
http://www.unicode.org/cldr/
@@ -38,2775 +38,5044 @@ namespace QtPrivate::Roman {
static constexpr QCalendarLocale locale_data[] = {
// lang script terr sLong long sShrt short sNarw narow Sizes...
{ 1, 0, 0, 0, 0, 85, 85, 132, 155, 85, 85, 47, 47, 23, 26 },// C/AnyScript/AnyTerritory
- { 2, 27, 90, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Abkhazian/Cyrillic/Georgia
- { 3, 66, 77, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Afar/Latin/Ethiopia
- { 4, 66, 216, 228, 228, 319, 319, 132, 132, 91, 91, 58, 58, 23, 23 },// Afrikaans/Latin/South Africa
- { 4, 66, 162, 228, 228, 319, 319, 132, 132, 91, 91, 58, 58, 23, 23 },// Afrikaans/Latin/Namibia
- { 5, 66, 40, 377, 377, 571, 571, 618, 618,194,194, 47, 47, 23, 23 },// Aghem/Latin/Cameroon
- { 6, 66, 92, 641, 641, 832, 832, 155, 155,191,191, 47, 47, 26, 26 },// Akan/Latin/Ghana
- { 8, 66, 40, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Akoose/Latin/Cameroon
- { 9, 66, 3, 879, 879, 956, 956, 1005, 1005, 77, 77, 49, 49, 26, 26 },// Albanian/Latin/Albania
- { 9, 66, 126, 879, 879, 956, 956, 1005, 1005, 77, 77, 49, 49, 26, 26 },// Albanian/Latin/Kosovo
- { 9, 66, 140, 879, 879, 956, 956, 1005, 1005, 77, 77, 49, 49, 26, 26 },// Albanian/Latin/Macedonia
- { 11, 33, 77, 1031, 1031, 1091, 1091, 1136, 1136, 60, 60, 45, 45, 23, 23 },// Amharic/Ethiopic/Ethiopia
- { 14, 4, 71, 1159, 1159, 1159, 1159, 1233, 1233, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Egypt
- { 14, 4, 4, 1256, 1256, 1256, 1256, 1326, 1326, 70, 70, 70, 70, 23, 23 },// Arabic/Arabic/Algeria
- { 14, 4, 19, 1159, 1159, 1159, 1159, 1233, 1233, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Bahrain
- { 14, 4, 48, 1159, 1159, 1159, 1159, 1233, 1233, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Chad
- { 14, 4, 55, 1159, 1159, 1159, 1159, 1233, 1233, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Comoros
- { 14, 4, 67, 1159, 1159, 1159, 1159, 1233, 1233, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Djibouti
- { 14, 4, 74, 1159, 1159, 1159, 1159, 1233, 1233, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Eritrea
- { 14, 4, 113, 1349, 1349, 1349, 1440, 1531, 1531, 91, 91, 91, 91, 23, 23 },// Arabic/Arabic/Iraq
- { 14, 4, 116, 1159, 1159, 1159, 1159, 1233, 1233, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Israel
- { 14, 4, 122, 1349, 1349, 1349, 1349, 1531, 1531, 91, 91, 91, 91, 23, 23 },// Arabic/Arabic/Jordan
- { 14, 4, 127, 1159, 1159, 1159, 1159, 1233, 1233, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Kuwait
- { 14, 4, 132, 1349, 1349, 1349, 1349, 1531, 1531, 91, 91, 91, 91, 23, 23 },// Arabic/Arabic/Lebanon
- { 14, 4, 135, 1159, 1159, 1159, 1159, 1233, 1233, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Libya
- { 14, 4, 149, 1554, 1554, 1554, 1554, 1625, 1625, 71, 71, 71, 71, 23, 23 },// Arabic/Arabic/Mauritania
- { 14, 4, 159, 1648, 1648, 1648, 1648, 1717, 1717, 69, 69, 69, 69, 23, 23 },// Arabic/Arabic/Morocco
- { 14, 4, 176, 1159, 1159, 1159, 1159, 1233, 1233, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Oman
- { 14, 4, 180, 1349, 1349, 1349, 1349, 1531, 1531, 91, 91, 91, 91, 23, 23 },// Arabic/Arabic/Palestinian Territories
- { 14, 4, 190, 1159, 1159, 1159, 1159, 1233, 1233, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Qatar
- { 14, 4, 205, 1159, 1159, 1159, 1159, 1233, 1233, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Saudi Arabia
- { 14, 4, 215, 1159, 1159, 1159, 1159, 1233, 1233, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Somalia
- { 14, 4, 219, 1159, 1159, 1159, 1159, 1233, 1233, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/South Sudan
- { 14, 4, 222, 1159, 1159, 1159, 1159, 1233, 1233, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Sudan
- { 14, 4, 227, 1349, 1349, 1349, 1349, 1531, 1531, 91, 91, 91, 91, 23, 23 },// Arabic/Arabic/Syria
- { 14, 4, 238, 1256, 1256, 1256, 1256, 1326, 1326, 70, 70, 70, 70, 23, 23 },// Arabic/Arabic/Tunisia
- { 14, 4, 245, 1159, 1159, 1159, 1159, 1233, 1233, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/United Arab Emirates
- { 14, 4, 257, 1159, 1159, 1159, 1159, 1233, 1233, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Western Sahara
- { 14, 4, 258, 1159, 1159, 1159, 1159, 1233, 1233, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/World
- { 14, 4, 259, 1159, 1159, 1159, 1159, 1233, 1233, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Yemen
- { 15, 66, 220, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Aragonese/Latin/Spain
- { 17, 5, 12, 1740, 1833, 1938, 1938, 1985, 1985, 93,105, 47, 47, 23, 23 },// Armenian/Armenian/Armenia
- { 18, 9, 110, 2008, 2008, 2096, 2096, 2159, 2159, 88, 88, 63, 63, 23, 23 },// Assamese/Bangla/India
- { 19, 66, 220, 2182, 2266, 2382, 2429, 2476, 2476, 84,116, 47, 47, 23, 23 },// Asturian/Latin/Spain
- { 20, 66, 230, 2499, 2499, 2582, 2582, 132, 132, 83, 83, 47, 47, 23, 23 },// Asu/Latin/Tanzania
- { 21, 66, 169, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Atsam/Latin/Nigeria
- { 25, 66, 17, 2629, 2629, 2705, 2705, 155, 155, 76, 76, 47, 47, 26, 26 },// Azerbaijani/Latin/Azerbaijan
- { 25, 4, 112, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Azerbaijani/Arabic/Iran
- { 25, 27, 17, 2752, 2828, 2904, 2904, 155, 155, 76, 76, 47, 47, 26, 26 },// Azerbaijani/Cyrillic/Azerbaijan
- { 26, 66, 40, 2951, 2951, 3141, 3141, 155, 155,190,190, 38, 38, 26, 26 },// Bafia/Latin/Cameroon
- { 28, 66, 145, 3179, 3179, 3270, 3270, 3316, 3316, 91, 91, 46, 46, 23, 23 },// Bambara/Latin/Mali
- { 28, 90, 145, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Bambara/Nko/Mali
- { 30, 9, 20, 3339, 3339, 3428, 3504, 3557, 3557, 89, 89, 76, 53, 32, 32 },// Bangla/Bangla/Bangladesh
- { 30, 9, 110, 3339, 3339, 3589, 3655, 3715, 3715, 89, 89, 66, 60, 33, 33 },// Bangla/Bangla/India
- { 31, 66, 40, 3748, 3748, 3837, 3837, 3884, 3884, 89, 89, 47, 47, 23, 23 },// Basaa/Latin/Cameroon
- { 32, 27, 193, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Bashkir/Cyrillic/Russia
- { 33, 66, 220, 3907, 3907, 3999, 3999, 4058, 4058, 92, 92, 59, 59, 23, 23 },// Basque/Latin/Spain
- { 35, 27, 22, 4081, 4175, 4272, 4319, 4366, 4366, 94, 97, 47, 47, 23, 23 },// Belarusian/Cyrillic/Belarus
- { 36, 66, 260, 4389, 4389, 4471, 4471, 4518, 4518, 82, 82, 47, 47, 23, 23 },// Bemba/Latin/Zambia
- { 37, 66, 230, 4541, 4541, 4794, 4794, 4841, 4841,253,253, 47, 47, 23, 23 },// Bena/Latin/Tanzania
- { 38, 29, 110, 4864, 4864, 4864, 4864, 155, 155, 72, 72, 72, 72, 26, 26 },// Bhojpuri/Devanagari/India
- { 40, 33, 74, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Blin/Ethiopic/Eritrea
- { 41, 29, 110, 4936, 4936, 5023, 5023, 5075, 5075, 87, 87, 52, 52, 23, 23 },// Bodo/Devanagari/India
- { 42, 66, 29, 5098, 5098, 5180, 5180, 5227, 5227, 82, 82, 47, 47, 23, 23 },// Bosnian/Latin/Bosnia And Herzegovina
- { 42, 27, 29, 5250, 5250, 5332, 5332, 5379, 5379, 82, 82, 47, 47, 23, 23 },// Bosnian/Cyrillic/Bosnia And Herzegovina
- { 43, 66, 84, 5402, 5402, 5479, 5479, 5541, 5541, 77, 77, 62, 62, 35, 35 },// Breton/Latin/France
- { 45, 27, 36, 5576, 5576, 5657, 5657, 5705, 5705, 81, 81, 48, 48, 23, 23 },// Bulgarian/Cyrillic/Bulgaria
- { 46, 86, 161, 5728, 5728, 5815, 5815, 5857, 5857, 87, 87, 42, 42, 23, 23 },// Burmese/Myanmar/Myanmar
- { 47, 137, 107, 5880, 5880, 5880, 5880, 155, 155, 38, 38, 38, 38, 26, 26 },// Cantonese/Traditional Han/Hong Kong
- { 47, 118, 50, 5918, 5918, 5880, 5880, 155, 155, 37, 37, 38, 38, 26, 26 },// Cantonese/Simplified Han/China
- { 48, 66, 220, 5955, 6036, 6150, 6209, 6301, 6301, 81,114, 59, 92, 35, 35 },// Catalan/Latin/Spain
- { 48, 66, 6, 5955, 6036, 6150, 6209, 6301, 6301, 81,114, 59, 92, 35, 35 },// Catalan/Latin/Andorra
- { 48, 66, 84, 5955, 6036, 6150, 6209, 6301, 6301, 81,114, 59, 92, 35, 35 },// Catalan/Latin/France
- { 48, 66, 117, 5955, 6036, 6150, 6209, 6301, 6301, 81,114, 59, 92, 35, 35 },// Catalan/Latin/Italy
- { 49, 66, 185, 6336, 6336, 6423, 6423, 6470, 6470, 87, 87, 47, 47, 23, 23 },// Cebuano/Latin/Philippines
- { 50, 66, 159, 6493, 6493, 6578, 6578, 6625, 6625, 85, 85, 47, 47, 23, 23 },// Central Atlas Tamazight/Latin/Morocco
- { 51, 4, 113, 6648, 6648, 6648, 6648, 6752, 6752,104,104,104,104, 23, 23 },// Central Kurdish/Arabic/Iraq
- { 51, 4, 112, 6648, 6648, 6648, 6648, 6752, 6752,104,104,104,104, 23, 23 },// Central Kurdish/Arabic/Iran
- { 52, 21, 20, 6775, 6964, 6775, 7153, 7320, 7320,189,189,189,167, 57, 57 },// Chakma/Chakma/Bangladesh
- { 52, 21, 110, 6775, 6964, 6775, 7153, 7320, 7320,189,189,189,167, 57, 57 },// Chakma/Chakma/India
- { 54, 27, 193, 7377, 7377, 7456, 7456, 7503, 7503, 79, 79, 47, 47, 23, 23 },// Chechen/Cyrillic/Russia
- { 55, 23, 248, 7526, 7526, 7583, 7583, 7618, 7618, 57, 57, 35, 35, 23, 23 },// Cherokee/Cherokee/United States
- { 56, 66, 248, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Chickasaw/Latin/United States
- { 57, 66, 243, 7641, 7641, 7792, 7792, 132, 132,151,151, 47, 47, 23, 23 },// Chiga/Latin/Uganda
- { 58, 118, 50, 5918, 5918, 5880, 5880, 155, 155, 37, 37, 38, 38, 26, 26 },// Chinese/Simplified Han/China
- { 58, 118, 107, 5918, 5918, 5880, 5880, 155, 155, 37, 37, 38, 38, 26, 26 },// Chinese/Simplified Han/Hong Kong
- { 58, 118, 139, 5918, 5918, 5880, 5880, 155, 155, 37, 37, 38, 38, 26, 26 },// Chinese/Simplified Han/Macao
- { 58, 118, 210, 5918, 5918, 5880, 5880, 155, 155, 37, 37, 38, 38, 26, 26 },// Chinese/Simplified Han/Singapore
- { 58, 137, 107, 5880, 5880, 5880, 5880, 155, 155, 38, 38, 38, 38, 26, 26 },// Chinese/Traditional Han/Hong Kong
- { 58, 137, 139, 5880, 5880, 5880, 5880, 155, 155, 38, 38, 38, 38, 26, 26 },// Chinese/Traditional Han/Macao
- { 58, 137, 228, 5880, 5880, 5880, 5880, 155, 155, 38, 38, 38, 38, 26, 26 },// Chinese/Traditional Han/Taiwan
- { 59, 27, 193, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Church/Cyrillic/Russia
- { 60, 27, 193, 7839, 7839, 7899, 7899, 7951, 7951, 60, 60, 52, 52, 23, 23 },// Chuvash/Cyrillic/Russia
- { 61, 66, 91, 7974, 7974, 8060, 8118, 8165, 8165, 86, 86, 58, 47, 23, 23 },// Colognian/Latin/Germany
- { 63, 66, 246, 8188, 8188, 8317, 8317, 155, 155,129,129, 45, 45, 26, 26 },// Cornish/Latin/United Kingdom
- { 64, 66, 84, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Corsican/Latin/France
- { 66, 66, 60, 8362, 8455, 8552, 8552, 8600, 8600, 93, 97, 48, 48, 38, 38 },// Croatian/Latin/Croatia
- { 66, 66, 29, 8362, 8455, 8552, 8552, 8600, 8600, 93, 97, 48, 48, 38, 38 },// Croatian/Latin/Bosnia And Herzegovina
- { 67, 66, 64, 8638, 8719, 8802, 8802, 155, 155, 81, 83, 47, 47, 26, 26 },// Czech/Latin/Czechia
- { 68, 66, 65, 8849, 8849, 8932, 8932, 132, 132, 83, 83, 58, 58, 23, 23 },// Danish/Latin/Denmark
- { 68, 66, 95, 8849, 8849, 8932, 8932, 132, 132, 83, 83, 58, 58, 23, 23 },// Danish/Latin/Greenland
- { 69, 132, 144, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Divehi/Thaana/Maldives
- { 70, 29, 110, 8990, 8990, 9062, 9062, 9121, 9121, 72, 72, 59, 59, 29, 29 },// Dogri/Devanagari/India
- { 71, 66, 40, 9150, 9150, 9248, 9248, 9296, 9296, 98, 98, 48, 48, 23, 23 },// Duala/Latin/Cameroon
- { 72, 66, 165, 9319, 9319, 9406, 9406, 132, 132, 87, 87, 47, 47, 23, 23 },// Dutch/Latin/Netherlands
- { 72, 66, 13, 9319, 9319, 9406, 9406, 132, 132, 87, 87, 47, 47, 23, 23 },// Dutch/Latin/Aruba
- { 72, 66, 23, 9319, 9319, 9406, 9406, 132, 132, 87, 87, 47, 47, 23, 23 },// Dutch/Latin/Belgium
- { 72, 66, 44, 9319, 9319, 9406, 9406, 132, 132, 87, 87, 47, 47, 23, 23 },// Dutch/Latin/Caribbean Netherlands
- { 72, 66, 62, 9319, 9319, 9406, 9406, 132, 132, 87, 87, 47, 47, 23, 23 },// Dutch/Latin/Curacao
- { 72, 66, 211, 9319, 9319, 9406, 9406, 132, 132, 87, 87, 47, 47, 23, 23 },// Dutch/Latin/Sint Maarten
- { 72, 66, 223, 9319, 9319, 9406, 9406, 132, 132, 87, 87, 47, 47, 23, 23 },// Dutch/Latin/Suriname
- { 73, 134, 27, 9453, 9643, 9774, 9836, 9862, 9888,190,131, 62, 26, 26, 26 },// Dzongkha/Tibetan/Bhutan
- { 74, 66, 124, 9914, 9914,10120,10120,10167,10167,206,206, 47, 47, 23, 23 },// Embu/Latin/Kenya
+ { 2, 27, 90, 181, 181, 278, 278, 336, 364, 97, 97, 58, 58, 28, 28 },// Abkhazian/Cyrillic/Georgia
+ { 3, 66, 77, 392, 392, 509, 509, 556, 556,117,117, 47, 47, 23, 23 },// Afar/Latin/Ethiopia
+ { 3, 66, 67, 579, 579, 509, 509, 556, 556,118,118, 47, 47, 23, 23 },// Afar/Latin/Djibouti
+ { 3, 66, 74, 392, 392, 509, 509, 556, 556,117,117, 47, 47, 23, 23 },// Afar/Latin/Eritrea
+ { 4, 66, 216, 697, 697, 788, 788, 132, 132, 91, 91, 58, 58, 23, 23 },// Afrikaans/Latin/South Africa
+ { 4, 66, 162, 697, 697, 788, 788, 132, 132, 91, 91, 58, 58, 23, 23 },// Afrikaans/Latin/Namibia
+ { 5, 66, 40, 846, 846, 1040, 1040, 1087, 1087,194,194, 47, 47, 23, 23 },// Aghem/Latin/Cameroon
+ { 6, 66, 92, 1110, 1110, 1301, 1301, 155, 155,191,191, 47, 47, 26, 26 },// Akan/Latin/Ghana
+ { 8, 66, 40, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Akoose/Latin/Cameroon
+ { 9, 66, 3, 1395, 1395, 1472, 1472, 1521, 1521, 77, 77, 49, 49, 26, 26 },// Albanian/Latin/Albania
+ { 9, 66, 126, 1395, 1395, 1472, 1472, 1521, 1521, 77, 77, 49, 49, 26, 26 },// Albanian/Latin/Kosovo
+ { 9, 66, 140, 1395, 1395, 1472, 1472, 1521, 1521, 77, 77, 49, 49, 26, 26 },// Albanian/Latin/Macedonia
+ { 11, 33, 77, 1547, 1547, 1606, 1606, 1649, 1649, 59, 59, 43, 43, 23, 23 },// Amharic/Ethiopic/Ethiopia
+ { 14, 4, 71, 1672, 1672, 1672, 1672, 1746, 1746, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Egypt
+ { 14, 4, 4, 1769, 1769, 1769, 1769, 1839, 1839, 70, 70, 70, 70, 23, 23 },// Arabic/Arabic/Algeria
+ { 14, 4, 19, 1672, 1672, 1672, 1672, 1746, 1746, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Bahrain
+ { 14, 4, 48, 1672, 1672, 1672, 1672, 1746, 1746, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Chad
+ { 14, 4, 55, 1672, 1672, 1672, 1672, 1746, 1746, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Comoros
+ { 14, 4, 67, 1672, 1672, 1672, 1672, 1746, 1746, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Djibouti
+ { 14, 4, 74, 1672, 1672, 1672, 1672, 1746, 1746, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Eritrea
+ { 14, 4, 113, 1862, 1862, 1862, 1953, 2044, 2044, 91, 91, 91, 91, 23, 23 },// Arabic/Arabic/Iraq
+ { 14, 4, 116, 1672, 1672, 1672, 1672, 1746, 1746, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Israel
+ { 14, 4, 122, 1862, 1862, 1862, 1862, 2044, 2044, 91, 91, 91, 91, 23, 23 },// Arabic/Arabic/Jordan
+ { 14, 4, 127, 1672, 1672, 1672, 1672, 1746, 1746, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Kuwait
+ { 14, 4, 132, 1862, 1862, 1862, 1862, 2044, 2044, 91, 91, 91, 91, 23, 23 },// Arabic/Arabic/Lebanon
+ { 14, 4, 135, 1672, 1672, 1672, 1672, 1746, 1746, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Libya
+ { 14, 4, 149, 2067, 2067, 2067, 2067, 2138, 2138, 71, 71, 71, 71, 23, 23 },// Arabic/Arabic/Mauritania
+ { 14, 4, 159, 2161, 2161, 2161, 2161, 2230, 2230, 69, 69, 69, 69, 23, 23 },// Arabic/Arabic/Morocco
+ { 14, 4, 176, 1672, 1672, 1672, 1672, 1746, 1746, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Oman
+ { 14, 4, 180, 1862, 1862, 1862, 1862, 2044, 2044, 91, 91, 91, 91, 23, 23 },// Arabic/Arabic/Palestinian Territories
+ { 14, 4, 190, 1672, 1672, 1672, 1672, 1746, 1746, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Qatar
+ { 14, 4, 205, 1672, 1672, 1672, 1672, 1746, 1746, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Saudi Arabia
+ { 14, 4, 215, 1672, 1672, 1672, 1672, 1746, 1746, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Somalia
+ { 14, 4, 219, 1672, 1672, 1672, 1672, 1746, 1746, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/South Sudan
+ { 14, 4, 222, 1672, 1672, 1672, 1672, 1746, 1746, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Sudan
+ { 14, 4, 227, 1862, 1862, 1862, 1862, 2044, 2044, 91, 91, 91, 91, 23, 23 },// Arabic/Arabic/Syria
+ { 14, 4, 238, 1769, 1769, 1769, 1769, 1839, 1839, 70, 70, 70, 70, 23, 23 },// Arabic/Arabic/Tunisia
+ { 14, 4, 245, 1672, 1672, 1672, 1672, 1746, 1746, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/United Arab Emirates
+ { 14, 4, 257, 1672, 1672, 1672, 1672, 1746, 1746, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Western Sahara
+ { 14, 4, 258, 1672, 1672, 1672, 1672, 1746, 1746, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/world
+ { 14, 4, 259, 1672, 1672, 1672, 1672, 1746, 1746, 74, 74, 74, 74, 23, 23 },// Arabic/Arabic/Yemen
+ { 15, 66, 220, 2253, 2343, 2465, 2465, 155, 155, 90,122, 59, 59, 26, 26 },// Aragonese/Latin/Spain
+ { 17, 5, 12, 2524, 2617, 2722, 2722, 2769, 2769, 93,105, 47, 47, 23, 23 },// Armenian/Armenian/Armenia
+ { 18, 9, 110, 2792, 2792, 2880, 2880, 2943, 2943, 88, 88, 63, 63, 23, 23 },// Assamese/Bangla/India
+ { 19, 66, 220, 2966, 3050, 3166, 3213, 3260, 3260, 84,116, 47, 47, 23, 23 },// Asturian/Latin/Spain
+ { 20, 66, 230, 3283, 3283, 3366, 3366, 132, 132, 83, 83, 47, 47, 23, 23 },// Asu/Latin/Tanzania
+ { 21, 66, 169, 3413, 3413, 3541, 3541, 155, 155,128,128, 58, 58, 26, 26 },// Atsam/Latin/Nigeria
+ { 25, 66, 17, 3599, 3599, 3675, 3675, 155, 155, 76, 76, 47, 47, 26, 26 },// Azerbaijani/Latin/Azerbaijan
+ { 25, 4, 112, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Azerbaijani/Arabic/Iran
+ { 25, 4, 113, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Azerbaijani/Arabic/Iraq
+ { 25, 4, 239, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Azerbaijani/Arabic/Turkey
+ { 25, 27, 17, 3722, 3798, 3874, 3874, 155, 155, 76, 76, 47, 47, 26, 26 },// Azerbaijani/Cyrillic/Azerbaijan
+ { 26, 66, 40, 3921, 3921, 4111, 4111, 155, 155,190,190, 38, 38, 26, 26 },// Bafia/Latin/Cameroon
+ { 28, 66, 145, 4149, 4149, 4240, 4240, 4286, 4286, 91, 91, 46, 46, 23, 23 },// Bambara/Latin/Mali
+ { 28, 90, 145, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Bambara/Nko/Mali
+ { 30, 9, 20, 4309, 4309, 4398, 4474, 4527, 4527, 89, 89, 76, 53, 32, 32 },// Bangla/Bangla/Bangladesh
+ { 30, 9, 110, 4309, 4309, 4559, 4625, 4685, 4685, 89, 89, 66, 60, 33, 33 },// Bangla/Bangla/India
+ { 31, 66, 40, 4718, 4718, 4807, 4807, 4854, 4854, 89, 89, 47, 47, 23, 23 },// Basaa/Latin/Cameroon
+ { 32, 27, 193, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Bashkir/Cyrillic/Russia
+ { 33, 66, 220, 4877, 4877, 4969, 4969, 5028, 5028, 92, 92, 59, 59, 23, 23 },// Basque/Latin/Spain
+ { 35, 27, 22, 5051, 5145, 5242, 5289, 5336, 5336, 94, 97, 47, 47, 23, 23 },// Belarusian/Cyrillic/Belarus
+ { 36, 66, 260, 5359, 5359, 5441, 5441, 5488, 5488, 82, 82, 47, 47, 23, 23 },// Bemba/Latin/Zambia
+ { 37, 66, 230, 5511, 5511, 5764, 5764, 5811, 5811,253,253, 47, 47, 23, 23 },// Bena/Latin/Tanzania
+ { 38, 29, 110, 5834, 5834, 5834, 5834, 155, 155, 72, 72, 72, 72, 26, 26 },// Bhojpuri/Devanagari/India
+ { 40, 33, 74, 5906, 5906, 5982, 5982, 6028, 6028, 76, 76, 46, 46, 23, 23 },// Blin/Ethiopic/Eritrea
+ { 41, 29, 110, 6051, 6051, 6138, 6138, 6190, 6190, 87, 87, 52, 52, 23, 23 },// Bodo/Devanagari/India
+ { 42, 66, 29, 6213, 6213, 6295, 6295, 6342, 6342, 82, 82, 47, 47, 23, 23 },// Bosnian/Latin/Bosnia and Herzegovina
+ { 42, 27, 29, 6365, 6365, 6447, 6447, 6494, 6494, 82, 82, 47, 47, 23, 23 },// Bosnian/Cyrillic/Bosnia and Herzegovina
+ { 43, 66, 84, 6517, 6517, 6594, 6594, 6656, 6656, 77, 77, 62, 62, 35, 35 },// Breton/Latin/France
+ { 45, 27, 36, 6691, 6691, 6772, 6772, 6820, 6820, 81, 81, 48, 48, 23, 23 },// Bulgarian/Cyrillic/Bulgaria
+ { 46, 86, 161, 6843, 6843, 6930, 6930, 6972, 6972, 87, 87, 42, 42, 23, 23 },// Burmese/Myanmar/Myanmar
+ { 47, 137, 107, 6995, 6995, 6995, 6995, 155, 155, 38, 38, 38, 38, 26, 26 },// Cantonese/Traditional Han/Hong Kong
+ { 47, 118, 50, 7033, 7033, 6995, 6995, 155, 155, 37, 37, 38, 38, 26, 26 },// Cantonese/Simplified Han/China
+ { 48, 66, 220, 7070, 7151, 7265, 7324, 7416, 7416, 81,114, 59, 92, 35, 35 },// Catalan/Latin/Spain
+ { 48, 66, 6, 7070, 7151, 7265, 7324, 7416, 7416, 81,114, 59, 92, 35, 35 },// Catalan/Latin/Andorra
+ { 48, 66, 84, 7070, 7151, 7265, 7324, 7416, 7416, 81,114, 59, 92, 35, 35 },// Catalan/Latin/France
+ { 48, 66, 117, 7070, 7151, 7265, 7324, 7416, 7416, 81,114, 59, 92, 35, 35 },// Catalan/Latin/Italy
+ { 49, 66, 185, 7451, 7451, 7540, 7540, 7587, 7587, 89, 89, 47, 47, 23, 23 },// Cebuano/Latin/Philippines
+ { 50, 66, 159, 7610, 7610, 7695, 7695, 7742, 7742, 85, 85, 47, 47, 23, 23 },// Central Atlas Tamazight/Latin/Morocco
+ { 51, 4, 113, 7765, 7765, 7765, 7765, 7869, 7869,104,104,104,104, 23, 23 },// Central Kurdish/Arabic/Iraq
+ { 51, 4, 112, 7765, 7765, 7765, 7765, 7869, 7869,104,104,104,104, 23, 23 },// Central Kurdish/Arabic/Iran
+ { 52, 21, 20, 7892, 8081, 7892, 8270, 8437, 8437,189,189,189,167, 57, 57 },// Chakma/Chakma/Bangladesh
+ { 52, 21, 110, 7892, 8081, 7892, 8270, 8437, 8437,189,189,189,167, 57, 57 },// Chakma/Chakma/India
+ { 54, 27, 193, 8494, 8494, 8573, 8573, 8620, 8620, 79, 79, 47, 47, 23, 23 },// Chechen/Cyrillic/Russia
+ { 55, 23, 248, 8643, 8643, 8700, 8700, 8735, 8735, 57, 57, 35, 35, 23, 23 },// Cherokee/Cherokee/United States
+ { 56, 66, 248, 8758, 8758, 8758, 8758, 155, 155,118,118,118,118, 26, 26 },// Chickasaw/Latin/United States
+ { 57, 66, 243, 8876, 8876, 9027, 9027, 132, 132,151,151, 47, 47, 23, 23 },// Chiga/Latin/Uganda
+ { 58, 118, 50, 7033, 7033, 6995, 6995, 155, 155, 37, 37, 38, 38, 26, 26 },// Chinese/Simplified Han/China
+ { 58, 118, 107, 7033, 7033, 6995, 6995, 155, 155, 37, 37, 38, 38, 26, 26 },// Chinese/Simplified Han/Hong Kong
+ { 58, 118, 139, 7033, 7033, 6995, 6995, 155, 155, 37, 37, 38, 38, 26, 26 },// Chinese/Simplified Han/Macao
+ { 58, 118, 210, 7033, 7033, 6995, 6995, 155, 155, 37, 37, 38, 38, 26, 26 },// Chinese/Simplified Han/Singapore
+ { 58, 137, 107, 6995, 6995, 6995, 6995, 155, 155, 38, 38, 38, 38, 26, 26 },// Chinese/Traditional Han/Hong Kong
+ { 58, 137, 139, 6995, 6995, 6995, 6995, 155, 155, 38, 38, 38, 38, 26, 26 },// Chinese/Traditional Han/Macao
+ { 58, 137, 228, 6995, 6995, 6995, 6995, 155, 155, 38, 38, 38, 38, 26, 26 },// Chinese/Traditional Han/Taiwan
+ { 59, 27, 193, 9074, 9190, 9306, 9306, 9370, 9370,116,116, 64, 64, 29, 29 },// Church/Cyrillic/Russia
+ { 60, 27, 193, 9399, 9399, 9459, 9459, 9511, 9511, 60, 60, 52, 52, 23, 23 },// Chuvash/Cyrillic/Russia
+ { 61, 66, 91, 9534, 9534, 9620, 9678, 9725, 9725, 86, 86, 58, 47, 23, 23 },// Colognian/Latin/Germany
+ { 63, 66, 246, 9748, 9748, 9877, 9877, 155, 155,129,129, 45, 45, 26, 26 },// Cornish/Latin/United Kingdom
+ { 64, 66, 84, 9922,10020,10151,10151,10211,10211, 98,131, 60, 60, 23, 23 },// Corsican/Latin/France
+ { 66, 66, 60,10234,10327,10424,10424,10472,10472, 93, 97, 48, 48, 38, 38 },// Croatian/Latin/Croatia
+ { 66, 66, 29,10234,10327,10424,10424,10472,10472, 93, 97, 48, 48, 38, 38 },// Croatian/Latin/Bosnia and Herzegovina
+ { 67, 66, 64,10510,10591,10674,10674, 155, 155, 81, 83, 47, 47, 26, 26 },// Czech/Latin/Czechia
+ { 68, 66, 65,10721,10721,10804,10804, 132, 132, 83, 83, 58, 58, 23, 23 },// Danish/Latin/Denmark
+ { 68, 66, 95,10721,10721,10804,10804, 132, 132, 83, 83, 58, 58, 23, 23 },// Danish/Latin/Greenland
+ { 69, 132, 144, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Divehi/Thaana/Maldives
+ { 70, 29, 110,10862,10862,10934,10934,10993,10993, 72, 72, 59, 59, 29, 29 },// Dogri/Devanagari/India
+ { 71, 66, 40,11022,11022,11120,11120,11168,11168, 98, 98, 48, 48, 23, 23 },// Duala/Latin/Cameroon
+ { 72, 66, 165,11191,11191,11278,11278, 132, 132, 87, 87, 47, 47, 23, 23 },// Dutch/Latin/Netherlands
+ { 72, 66, 13,11191,11191,11278,11278, 132, 132, 87, 87, 47, 47, 23, 23 },// Dutch/Latin/Aruba
+ { 72, 66, 23,11191,11191,11278,11278, 132, 132, 87, 87, 47, 47, 23, 23 },// Dutch/Latin/Belgium
+ { 72, 66, 44,11191,11191,11278,11278, 132, 132, 87, 87, 47, 47, 23, 23 },// Dutch/Latin/Caribbean Netherlands
+ { 72, 66, 62,11191,11191,11278,11278, 132, 132, 87, 87, 47, 47, 23, 23 },// Dutch/Latin/Curacao
+ { 72, 66, 211,11191,11191,11278,11278, 132, 132, 87, 87, 47, 47, 23, 23 },// Dutch/Latin/Sint Maarten
+ { 72, 66, 223,11191,11191,11278,11278, 132, 132, 87, 87, 47, 47, 23, 23 },// Dutch/Latin/Suriname
+ { 73, 134, 27,11325,11515,11646,11708,11734,11760,190,131, 62, 26, 26, 26 },// Dzongkha/Tibetan/Bhutan
+ { 74, 66, 124,11786,11786,11992,11992,12039,12039,206,206, 47, 47, 23, 23 },// Embu/Latin/Kenya
{ 75, 66, 248, 0, 0, 85, 85, 132, 132, 85, 85, 47, 47, 23, 23 },// English/Latin/United States
- { 75, 28, 248, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// English/Deseret/United States
+ { 75, 28, 248,12062,12062,12215,12215,12294,12294,153,153, 79, 79, 35, 35 },// English/Deseret/United States
{ 75, 66, 5, 0, 0, 85, 85, 132, 132, 85, 85, 47, 47, 23, 23 },// English/Latin/American Samoa
- { 75, 66, 8, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Anguilla
- { 75, 66, 10, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Antigua And Barbuda
- { 75, 66, 15, 0, 0,10190,10238, 132, 132, 85, 85, 48, 50, 23, 23 },// English/Latin/Australia
- { 75, 66, 16, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Austria
- { 75, 66, 18, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Bahamas
- { 75, 66, 21, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Barbados
- { 75, 66, 23, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Belgium
- { 75, 66, 24, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Belize
- { 75, 66, 26, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Bermuda
- { 75, 66, 30, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Botswana
- { 75, 66, 33, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/British Indian Ocean Territory
- { 75, 66, 34, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/British Virgin Islands
+ { 75, 66, 8, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Anguilla
+ { 75, 66, 10, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Antigua and Barbuda
+ { 75, 66, 15, 0, 0,12377,12377, 132, 132, 85, 85, 50, 50, 23, 23 },// English/Latin/Australia
+ { 75, 66, 16, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Austria
+ { 75, 66, 18, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Bahamas
+ { 75, 66, 21, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Barbados
+ { 75, 66, 23, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Belgium
+ { 75, 66, 24, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Belize
+ { 75, 66, 26, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Bermuda
+ { 75, 66, 30, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Botswana
+ { 75, 66, 33, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/British Indian Ocean Territory
+ { 75, 66, 34, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/British Virgin Islands
{ 75, 66, 38, 0, 0, 85, 85, 132, 132, 85, 85, 47, 47, 23, 23 },// English/Latin/Burundi
- { 75, 66, 40, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Cameroon
+ { 75, 66, 40, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Cameroon
{ 75, 66, 41, 0, 0, 85, 85, 132, 132, 85, 85, 47, 47, 23, 23 },// English/Latin/Canada
- { 75, 66, 45, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Cayman Islands
- { 75, 66, 51, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Christmas Island
- { 75, 66, 53, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Cocos Islands
- { 75, 66, 58, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Cook Islands
- { 75, 66, 63, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Cyprus
- { 75, 66, 65, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Denmark
- { 75, 66, 66, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Diego Garcia
- { 75, 66, 68, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Dominica
- { 75, 66, 74, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Eritrea
- { 75, 66, 76, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Eswatini
- { 75, 66, 78, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Europe
- { 75, 66, 80, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Falkland Islands
- { 75, 66, 82, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Fiji
- { 75, 66, 83, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Finland
- { 75, 66, 89, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Gambia
- { 75, 66, 91, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Germany
- { 75, 66, 92, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Ghana
- { 75, 66, 93, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Gibraltar
- { 75, 66, 96, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Grenada
+ { 75, 66, 45, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Cayman Islands
+ { 75, 66, 51, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Christmas Island
+ { 75, 66, 53, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Cocos Islands
+ { 75, 66, 58, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Cook Islands
+ { 75, 66, 63, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Cyprus
+ { 75, 66, 65, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Denmark
+ { 75, 66, 66, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Diego Garcia
+ { 75, 66, 68, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Dominica
+ { 75, 66, 74, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Eritrea
+ { 75, 66, 76, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Eswatini
+ { 75, 66, 78, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Europe
+ { 75, 66, 80, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Falkland Islands
+ { 75, 66, 82, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Fiji
+ { 75, 66, 83, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Finland
+ { 75, 66, 89, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Gambia
+ { 75, 66, 91, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Germany
+ { 75, 66, 92, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Ghana
+ { 75, 66, 93, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Gibraltar
+ { 75, 66, 96, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Grenada
{ 75, 66, 98, 0, 0, 85, 85, 132, 132, 85, 85, 47, 47, 23, 23 },// English/Latin/Guam
- { 75, 66, 100, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Guernsey
- { 75, 66, 103, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Guyana
- { 75, 66, 107, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Hong Kong
- { 75, 66, 110, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/India
- { 75, 66, 114, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Ireland
- { 75, 66, 115, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Isle Of Man
- { 75, 66, 116, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Israel
- { 75, 66, 119, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Jamaica
- { 75, 66, 121, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Jersey
- { 75, 66, 124, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Kenya
- { 75, 66, 125, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Kiribati
- { 75, 66, 133, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Lesotho
- { 75, 66, 134, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Liberia
- { 75, 66, 139, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Macao
- { 75, 66, 141, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Madagascar
- { 75, 66, 142, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Malawi
- { 75, 66, 143, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Malaysia
- { 75, 66, 144, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Maldives
- { 75, 66, 146, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Malta
+ { 75, 66, 100, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Guernsey
+ { 75, 66, 103, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Guyana
+ { 75, 66, 107, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Hong Kong
+ { 75, 66, 110, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/India
+ { 75, 66, 111, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Indonesia
+ { 75, 66, 114, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Ireland
+ { 75, 66, 115, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Isle of Man
+ { 75, 66, 116, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Israel
+ { 75, 66, 119, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Jamaica
+ { 75, 66, 121, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Jersey
+ { 75, 66, 124, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Kenya
+ { 75, 66, 125, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Kiribati
+ { 75, 66, 133, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Lesotho
+ { 75, 66, 134, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Liberia
+ { 75, 66, 139, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Macao
+ { 75, 66, 141, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Madagascar
+ { 75, 66, 142, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Malawi
+ { 75, 66, 143, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Malaysia
+ { 75, 66, 144, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Maldives
+ { 75, 66, 146, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Malta
{ 75, 66, 147, 0, 0, 85, 85, 132, 132, 85, 85, 47, 47, 23, 23 },// English/Latin/Marshall Islands
- { 75, 66, 150, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Mauritius
- { 75, 66, 153, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Micronesia
- { 75, 66, 158, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Montserrat
- { 75, 66, 162, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Namibia
- { 75, 66, 163, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Nauru
- { 75, 66, 165, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Netherlands
- { 75, 66, 167, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/New Zealand
- { 75, 66, 169, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Nigeria
- { 75, 66, 171, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Niue
- { 75, 66, 172, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Norfolk Island
+ { 75, 66, 150, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Mauritius
+ { 75, 66, 153, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Micronesia
+ { 75, 66, 158, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Montserrat
+ { 75, 66, 162, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Namibia
+ { 75, 66, 163, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Nauru
+ { 75, 66, 165, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Netherlands
+ { 75, 66, 167, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/New Zealand
+ { 75, 66, 169, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Nigeria
+ { 75, 66, 171, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Niue
+ { 75, 66, 172, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Norfolk Island
{ 75, 66, 173, 0, 0, 85, 85, 132, 132, 85, 85, 47, 47, 23, 23 },// English/Latin/Northern Mariana Islands
- { 75, 66, 178, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Pakistan
- { 75, 66, 179, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Palau
- { 75, 66, 182, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Papua New Guinea
+ { 75, 66, 178, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Pakistan
+ { 75, 66, 179, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Palau
+ { 75, 66, 182, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Papua New Guinea
{ 75, 66, 185, 0, 0, 85, 85, 132, 132, 85, 85, 47, 47, 23, 23 },// English/Latin/Philippines
- { 75, 66, 186, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Pitcairn
+ { 75, 66, 186, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Pitcairn
{ 75, 66, 189, 0, 0, 85, 85, 132, 132, 85, 85, 47, 47, 23, 23 },// English/Latin/Puerto Rico
- { 75, 66, 194, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Rwanda
- { 75, 66, 196, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Saint Helena
- { 75, 66, 197, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Saint Kitts And Nevis
- { 75, 66, 198, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Saint Lucia
- { 75, 66, 201, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Saint Vincent And Grenadines
- { 75, 66, 202, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Samoa
- { 75, 66, 208, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Seychelles
- { 75, 66, 209, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Sierra Leone
- { 75, 66, 210, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Singapore
- { 75, 66, 211, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Sint Maarten
- { 75, 66, 213, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Slovenia
- { 75, 66, 214, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Solomon Islands
- { 75, 66, 216, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/South Africa
- { 75, 66, 219, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/South Sudan
- { 75, 66, 222, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Sudan
- { 75, 66, 225, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Sweden
- { 75, 66, 226, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Switzerland
- { 75, 66, 230, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Tanzania
- { 75, 66, 234, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Tokelau
- { 75, 66, 235, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Tonga
- { 75, 66, 236, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Trinidad And Tobago
- { 75, 66, 241, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Turks And Caicos Islands
- { 75, 66, 242, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Tuvalu
- { 75, 66, 243, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Uganda
+ { 75, 66, 194, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Rwanda
+ { 75, 66, 196, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Saint Helena
+ { 75, 66, 197, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Saint Kitts and Nevis
+ { 75, 66, 198, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Saint Lucia
+ { 75, 66, 201, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Saint Vincent and Grenadines
+ { 75, 66, 202, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Samoa
+ { 75, 66, 208, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Seychelles
+ { 75, 66, 209, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Sierra Leone
+ { 75, 66, 210, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Singapore
+ { 75, 66, 211, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Sint Maarten
+ { 75, 66, 213, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Slovenia
+ { 75, 66, 214, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Solomon Islands
+ { 75, 66, 216, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/South Africa
+ { 75, 66, 219, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/South Sudan
+ { 75, 66, 222, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Sudan
+ { 75, 66, 225, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Sweden
+ { 75, 66, 226, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Switzerland
+ { 75, 66, 230, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Tanzania
+ { 75, 66, 234, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Tokelau
+ { 75, 66, 235, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Tonga
+ { 75, 66, 236, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Trinidad and Tobago
+ { 75, 66, 241, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Turks and Caicos Islands
+ { 75, 66, 242, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Tuvalu
+ { 75, 66, 243, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Uganda
{ 75, 66, 245, 0, 0, 85, 85, 132, 132, 85, 85, 47, 47, 23, 23 },// English/Latin/United Arab Emirates
- { 75, 66, 246, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/United Kingdom
+ { 75, 66, 246, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/United Kingdom
{ 75, 66, 247, 0, 0, 85, 85, 132, 132, 85, 85, 47, 47, 23, 23 },// English/Latin/United States Outlying Islands
{ 75, 66, 249, 0, 0, 85, 85, 132, 132, 85, 85, 47, 47, 23, 23 },// English/Latin/United States Virgin Islands
- { 75, 66, 252, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Vanuatu
- { 75, 66, 258, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/World
- { 75, 66, 260, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Zambia
- { 75, 66, 261, 0, 0,10190,10190, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Zimbabwe
- { 75, 115, 246, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// English/Shavian/United Kingdom
- { 76, 27, 193, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Erzya/Cyrillic/Russia
- { 77, 66, 258,10288,10288,10378,10425, 132, 132, 90, 90, 47, 47, 23, 23 },// Esperanto/Latin/World
- { 78, 66, 75,10472,10472,10562,10562,10620,10620, 90, 90, 58, 58, 23, 23 },// Estonian/Latin/Estonia
- { 79, 66, 92,10643,10643,10729,10729,10776,10776, 86, 86, 47, 47, 23, 23 },// Ewe/Latin/Ghana
- { 79, 66, 233,10643,10643,10729,10729,10776,10776, 86, 86, 47, 47, 23, 23 },// Ewe/Latin/Togo
- { 80, 66, 40,10799,10799,10939,10939,10988,10988,140,140, 49, 49, 23, 23 },// Ewondo/Latin/Cameroon
- { 81, 66, 81,11011,11011,11093,11140, 132, 132, 82, 82, 47, 58, 23, 23 },// Faroese/Latin/Faroe Islands
- { 81, 66, 65,11011,11011,11093,11140, 132, 132, 82, 82, 47, 58, 23, 23 },// Faroese/Latin/Denmark
- { 83, 66, 185, 6336, 6336, 6423, 6423,11198, 6423, 87, 87, 47, 47, 37, 47 },// Filipino/Latin/Philippines
- { 84, 66, 83,11235,11339,11467,11535,11627,11627,104,128, 68, 92, 23, 23 },// Finnish/Latin/Finland
- { 85, 66, 84,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/France
- { 85, 66, 4,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Algeria
- { 85, 66, 23,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Belgium
- { 85, 66, 25,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Benin
- { 85, 66, 37,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Burkina Faso
- { 85, 66, 38,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Burundi
- { 85, 66, 40,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Cameroon
- { 85, 66, 41,11650,11650,11796,11796, 132, 132, 84, 84, 63, 63, 23, 23 },// French/Latin/Canada
- { 85, 66, 46,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Central African Republic
- { 85, 66, 48,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Chad
- { 85, 66, 55,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Comoros
- { 85, 66, 56,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Congo Brazzaville
- { 85, 66, 57,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Congo Kinshasa
- { 85, 66, 67,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Djibouti
- { 85, 66, 73,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Equatorial Guinea
- { 85, 66, 85,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/French Guiana
- { 85, 66, 86,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/French Polynesia
- { 85, 66, 88,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Gabon
- { 85, 66, 97,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Guadeloupe
- { 85, 66, 102,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Guinea
- { 85, 66, 104,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Haiti
- { 85, 66, 118,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Ivory Coast
- { 85, 66, 138,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Luxembourg
- { 85, 66, 141,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Madagascar
- { 85, 66, 145,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Mali
- { 85, 66, 148,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Martinique
- { 85, 66, 149,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Mauritania
- { 85, 66, 150,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Mauritius
- { 85, 66, 151,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Mayotte
- { 85, 66, 155,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Monaco
- { 85, 66, 159,11650,11650,11859,11859, 132, 132, 84, 84, 60, 60, 23, 23 },// French/Latin/Morocco
- { 85, 66, 166,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/New Caledonia
- { 85, 66, 170,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Niger
- { 85, 66, 191,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Reunion
- { 85, 66, 194,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Rwanda
- { 85, 66, 195,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Saint Barthelemy
- { 85, 66, 199,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Saint Martin
- { 85, 66, 200,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Saint Pierre And Miquelon
- { 85, 66, 206,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Senegal
- { 85, 66, 208,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Seychelles
- { 85, 66, 226,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Switzerland
- { 85, 66, 227,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Syria
- { 85, 66, 233,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Togo
- { 85, 66, 238,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Tunisia
- { 85, 66, 252,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Vanuatu
- { 85, 66, 256,11650,11650,11734,11734, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Wallis And Futuna
- { 86, 66, 117,11919,11919,11995,11995,12042,12042, 76, 76, 47, 47, 23, 23 },// Friulian/Latin/Italy
- { 87, 66, 206,12065,12065,12141,12141,12188,12188, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Senegal
- { 87, 1, 37,12211,12211,12340,12211,12433,12433,129,129, 93,129, 35, 35 },// Fulah/Adlam/Burkina Faso
- { 87, 1, 40,12211,12211,12340,12211,12433,12433,129,129, 93,129, 35, 35 },// Fulah/Adlam/Cameroon
- { 87, 1, 89,12211,12211,12340,12211,12433,12433,129,129, 93,129, 35, 35 },// Fulah/Adlam/Gambia
- { 87, 1, 92,12211,12211,12340,12211,12433,12433,129,129, 93,129, 35, 35 },// Fulah/Adlam/Ghana
- { 87, 1, 101,12211,12211,12340,12211,12433,12433,129,129, 93,129, 35, 35 },// Fulah/Adlam/Guinea Bissau
- { 87, 1, 102,12211,12211,12340,12211,12433,12433,129,129, 93,129, 35, 35 },// Fulah/Adlam/Guinea
- { 87, 1, 134,12211,12211,12340,12211,12433,12433,129,129, 93,129, 35, 35 },// Fulah/Adlam/Liberia
- { 87, 1, 149,12211,12211,12340,12211,12433,12433,129,129, 93,129, 35, 35 },// Fulah/Adlam/Mauritania
- { 87, 1, 169,12211,12211,12340,12211,12433,12433,129,129, 93,129, 35, 35 },// Fulah/Adlam/Nigeria
- { 87, 1, 170,12211,12211,12340,12211,12433,12433,129,129, 93,129, 35, 35 },// Fulah/Adlam/Niger
- { 87, 1, 206,12211,12211,12340,12211,12433,12433,129,129, 93,129, 35, 35 },// Fulah/Adlam/Senegal
- { 87, 1, 209,12211,12211,12340,12211,12433,12433,129,129, 93,129, 35, 35 },// Fulah/Adlam/Sierra Leone
- { 87, 66, 37,12065,12065,12141,12141,12188,12188, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Burkina Faso
- { 87, 66, 40,12065,12065,12141,12141,12188,12188, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Cameroon
- { 87, 66, 89,12065,12065,12141,12141,12188,12188, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Gambia
- { 87, 66, 92,12065,12065,12141,12141,12188,12188, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Ghana
- { 87, 66, 101,12065,12065,12141,12141,12188,12188, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Guinea Bissau
- { 87, 66, 102,12065,12065,12141,12141,12188,12188, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Guinea
- { 87, 66, 134,12065,12065,12141,12141,12188,12188, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Liberia
- { 87, 66, 149,12065,12065,12141,12141,12188,12188, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Mauritania
- { 87, 66, 169,12065,12065,12141,12141,12188,12188, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Nigeria
- { 87, 66, 170,12065,12065,12141,12141,12188,12188, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Niger
- { 87, 66, 209,12065,12065,12141,12141,12188,12188, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Sierra Leone
- { 88, 66, 246,12468,12609,12775,12775,12835,12835,141,166, 60, 60, 23, 23 },// Gaelic/Latin/United Kingdom
- { 89, 66, 92, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Ga/Latin/Ghana
- { 90, 66, 220,12858,12944,13030,13089,13148,13171, 86, 86, 59, 59, 23, 35 },// Galician/Latin/Spain
- { 91, 66, 243,13206,13206,13302,13302, 132, 132, 96, 96, 47, 47, 23, 23 },// Ganda/Latin/Uganda
- { 92, 33, 77, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Geez/Ethiopic/Ethiopia
- { 93, 35, 90,13349,13349,13447,13447,13494,13494, 98, 98, 47, 47, 23, 23 },// Georgian/Georgian/Georgia
- { 94, 66, 91,13517,13517,13599,13646, 132, 132, 82, 82, 47, 59, 23, 23 },// German/Latin/Germany
- { 94, 66, 16,13705,13705,13787,13834, 132, 132, 82, 82, 47, 58, 23, 23 },// German/Latin/Austria
- { 94, 66, 23,13517,13517,13599,13646, 132, 132, 82, 82, 47, 59, 23, 23 },// German/Latin/Belgium
- { 94, 66, 117,13705,13705,13787,13834, 132, 132, 82, 82, 47, 58, 23, 23 },// German/Latin/Italy
- { 94, 66, 136,13517,13517,13599,13646, 132, 132, 82, 82, 47, 59, 23, 23 },// German/Latin/Liechtenstein
- { 94, 66, 138,13517,13517,13599,13646, 132, 132, 82, 82, 47, 59, 23, 23 },// German/Latin/Luxembourg
- { 94, 66, 226,13517,13517,13599,13646, 132, 132, 82, 82, 47, 59, 23, 23 },// German/Latin/Switzerland
- { 96, 39, 94,13892,14006,14120,14169,14218,14218,114,114, 49, 49, 23, 23 },// Greek/Greek/Greece
- { 96, 39, 63,13892,14006,14120,14169,14218,14218,114,114, 49, 49, 23, 23 },// Greek/Greek/Cyprus
- { 97, 66, 183, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Guarani/Latin/Paraguay
- { 98, 40, 110,14241,14241,14327,14327,14393,14393, 86, 86, 66, 66, 30, 30 },// Gujarati/Gujarati/India
- { 99, 66, 124,14423,14423,14510,14510,14557,14557, 87, 87, 47, 47, 23, 23 },// Gusii/Latin/Kenya
- { 101, 66, 169,14580,14580,14664,14664,14711,14711, 84, 84, 47, 47, 23, 23 },// Hausa/Latin/Nigeria
- { 101, 4, 169, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Hausa/Arabic/Nigeria
- { 101, 66, 92,14580,14580,14664,14664,14711,14711, 84, 84, 47, 47, 23, 23 },// Hausa/Latin/Ghana
- { 101, 66, 170,14580,14580,14664,14664,14711,14711, 84, 84, 47, 47, 23, 23 },// Hausa/Latin/Niger
- { 102, 66, 248,14734,14734,14828,14828, 155, 155, 94, 94, 58, 58, 26, 26 },// Hawaiian/Latin/United States
- { 103, 47, 116,14886,14886,14957,14957, 155, 155, 71, 71, 57, 57, 26, 26 },// Hebrew/Hebrew/Israel
- { 105, 29, 110,15014,15014,15086,15086,15144,15144, 72, 72, 58, 58, 29, 29 },// Hindi/Devanagari/India
- { 105, 66, 110, 0, 0,10190, 85, 132, 132, 85, 85, 48, 47, 23, 23 },// Hindi/Latin/India
- { 107, 66, 108,15173,15173,15270,15270,15333,15333, 97, 97, 63, 63, 24, 24 },// Hungarian/Latin/Hungary
- { 108, 66, 109,15357,15357,15438,15438,15496,15496, 81, 81, 58, 58, 23, 23 },// Icelandic/Latin/Iceland
- { 109, 66, 258, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Ido/Latin/World
- { 110, 66, 169,15519,15519,15605,15605,15652,15652, 86, 86, 47, 47, 23, 23 },// Igbo/Latin/Nigeria
- { 111, 66, 83,15675,15675,15814,15814,15890,15890,139,139, 76, 76, 24, 24 },// Inari Sami/Latin/Finland
- { 112, 66, 111,15914,15914,16000,16000, 132, 132, 86, 86, 47, 47, 23, 23 },// Indonesian/Latin/Indonesia
- { 114, 66, 258,16047,16047,16139,16139, 155, 5227, 92, 92, 47, 47, 26, 23 },// Interlingua/Latin/World
- { 116, 18, 41, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Inuktitut/Canadian Aboriginal/Canada
- { 116, 66, 41, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Inuktitut/Latin/Canada
- { 118, 66, 114,16186,16186,16292,16292,16353,16353,106,106, 61, 61, 23, 23 },// Irish/Latin/Ireland
- { 118, 66, 246,16186,16186,16292,16292,16353,16353,106,106, 61, 61, 23, 23 },// Irish/Latin/United Kingdom
- { 119, 66, 117,16376,16376,16469,16469,16516,16516, 93, 93, 47, 47, 23, 23 },// Italian/Latin/Italy
- { 119, 66, 203,16376,16376,16469,16469,16516,16516, 93, 93, 47, 47, 23, 23 },// Italian/Latin/San Marino
- { 119, 66, 226,16376,16376,16469,16469,16516,16516, 93, 93, 47, 47, 23, 23 },// Italian/Latin/Switzerland
- { 119, 66, 253,16376,16376,16469,16469,16516,16516, 93, 93, 47, 47, 23, 23 },// Italian/Latin/Vatican City
- { 120, 53, 120, 5880, 5880, 5880, 5880, 155, 155, 38, 38, 38, 38, 26, 26 },// Japanese/Japanese/Japan
- { 121, 66, 111,15914,15914,16539,16539, 132, 132, 86, 86, 47, 47, 23, 23 },// Javanese/Latin/Indonesia
- { 122, 66, 169, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Jju/Latin/Nigeria
- { 123, 66, 206,16586,16586,16667,16667,16702,16702, 81, 81, 35, 35, 23, 23 },// Jola Fonyi/Latin/Senegal
- { 124, 66, 43,16725,16725,16809,16809, 132, 132, 84, 84, 47, 47, 23, 23 },// Kabuverdianu/Latin/Cape Verde
- { 125, 66, 4,16856,16856,16939,16939,16986,16986, 83, 83, 47, 47, 23, 23 },// Kabyle/Latin/Algeria
- { 126, 66, 40,17009,17009,17009,17009, 155, 155,102,102,102,102, 26, 26 },// Kako/Latin/Cameroon
- { 127, 66, 95,17111,17209,17319,17319, 132, 132, 98,110, 49, 49, 23, 23 },// Kalaallisut/Latin/Greenland
- { 128, 66, 124,17368,17368,17488,17488,17536,17536,120,120, 48, 48, 23, 23 },// Kalenjin/Latin/Kenya
- { 129, 66, 124,17559,17559,17747,17747,17794,17794,188,188, 47, 47, 23, 23 },// Kamba/Latin/Kenya
- { 130, 56, 110,17817,17817,17903,17965,18037,18037, 86, 86, 62, 72, 30, 30 },// Kannada/Kannada/India
- { 132, 4, 110,18067,18067,18067,18067,18138,18138, 71, 71, 71, 71, 23, 23 },// Kashmiri/Arabic/India
- { 132, 29, 110,18161,18161,18161,18161,18235,18235, 74, 74, 74, 74, 24, 24 },// Kashmiri/Devanagari/India
- { 133, 27, 123,18259,18341,18423,18423,18482,18482, 82, 82, 59, 59, 23, 23 },// Kazakh/Cyrillic/Kazakhstan
- { 134, 66, 40, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Kenyang/Latin/Cameroon
- { 135, 60, 39,18505,18505,18505,18505,18575,18575, 70, 70, 70, 70, 23, 23 },// Khmer/Khmer/Cambodia
- { 136, 66, 99, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Kiche/Latin/Guatemala
- { 137, 66, 124,18598,18598,18782,18782,18829,18829,184,184, 47, 47, 23, 23 },// Kikuyu/Latin/Kenya
- { 138, 66, 194,18852,18852,18951,18951, 155, 155, 99, 99, 59, 59, 26, 26 },// Kinyarwanda/Latin/Rwanda
- { 141, 29, 110,19010,19010,19095,19010, 155, 155, 85, 85, 58, 85, 26, 26 },// Konkani/Devanagari/India
- { 142, 63, 218,19153,19153,19153,19153,19153,19153, 38, 38, 38, 38, 38, 38 },// Korean/Korean/South Korea
- { 142, 63, 174,19153,19153,19153,19153,19153,19153, 38, 38, 38, 38, 38, 38 },// Korean/Korean/North Korea
- { 144, 66, 145,19191,19191,19278,19278,19323,19323, 87, 87, 45, 45, 23, 23 },// Koyraboro Senni/Latin/Mali
- { 145, 66, 145,19191,19191,19278,19278,19323,19323, 87, 87, 45, 45, 23, 23 },// Koyra Chiini/Latin/Mali
- { 146, 66, 134, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Kpelle/Latin/Liberia
- { 148, 66, 239,19346,19433,19533,19533,19580,19580, 87,100, 47, 47, 23, 23 },// Kurdish/Latin/Turkey
- { 149, 66, 40,19603,19603,19745,19745, 155, 155,142,142, 50, 50, 26, 26 },// Kwasio/Latin/Cameroon
- { 150, 27, 128,19795, 7377,19874,19921, 7503, 7503, 79, 79, 47, 58, 23, 23 },// Kyrgyz/Cyrillic/Kyrgyzstan
- { 151, 66, 248,19979,19979,19979,19979, 155, 155,179,179,179,179, 26, 26 },// Lakota/Latin/United States
- { 152, 66, 230,20158,20158,20268,20268,20350,20350,110,110, 82, 82, 23, 23 },// Langi/Latin/Tanzania
- { 153, 65, 129,20373,20373,20447,20447, 155, 155, 74, 74, 60, 60, 26, 26 },// Lao/Lao/Laos
- { 154, 66, 253, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Latin/Latin/Vatican City
- { 155, 66, 131,20507,20507,20607,20607, 132, 132,100,100, 64, 64, 23, 23 },// Latvian/Latin/Latvia
- { 158, 66, 57,20671,20671,20873,20873,20920,20920,202,202, 47, 47, 23, 23 },// Lingala/Latin/Congo Kinshasa
- { 158, 66, 7,20671,20671,20873,20873,20920,20920,202,202, 47, 47, 23, 23 },// Lingala/Latin/Angola
- { 158, 66, 46,20671,20671,20873,20873,20920,20920,202,202, 47, 47, 23, 23 },// Lingala/Latin/Central African Republic
- { 158, 66, 56,20671,20671,20873,20873,20920,20920,202,202, 47, 47, 23, 23 },// Lingala/Latin/Congo Brazzaville
- { 160, 66, 137,20943,21038,21135,21135,21204,21204, 95, 97, 69, 69, 23, 23 },// Lithuanian/Latin/Lithuania
- { 161, 66, 258, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Lojban/Latin/World
- { 162, 66, 91,21227,21311,21403,21450, 5227, 5227, 84, 92, 47, 59, 23, 23 },// Lower Sorbian/Latin/Germany
- { 163, 66, 91,21509,21509,21593,21593, 132, 132, 84, 84, 58, 58, 23, 23 },// Low German/Latin/Germany
- { 163, 66, 165,21509,21509,21593,21593, 132, 132, 84, 84, 58, 58, 23, 23 },// Low German/Latin/Netherlands
- { 164, 66, 57,21651,21651,21749,21749,21797,21797, 98, 98, 48, 48, 23, 23 },// Luba Katanga/Latin/Congo Kinshasa
- { 165, 66, 225, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Lule Sami/Latin/Sweden
- { 166, 66, 124,21820,21820,22005,22005,22052,22052,185,185, 47, 47, 23, 23 },// Luo/Latin/Kenya
- { 167, 66, 138,22075,22075,22159,22206, 132, 132, 84, 84, 47, 58, 23, 23 },// Luxembourgish/Latin/Luxembourg
- { 168, 66, 124, 2499, 2499,22264,22264, 132, 132, 83, 83, 47, 47, 23, 23 },// Luyia/Latin/Kenya
- { 169, 27, 140,22311,22311,22395,22395, 5379, 5379, 84, 84, 60, 60, 23, 23 },// Macedonian/Cyrillic/Macedonia
- { 170, 66, 230,22455,22455,22541,22541, 132, 132, 86, 86, 47, 47, 23, 23 },// Machame/Latin/Tanzania
- { 171, 29, 110,22588,22659,22730,15086,22787,22787, 71, 71, 57, 58, 28, 28 },// Maithili/Devanagari/India
- { 172, 66, 160,22815,22815,23027,23027,23074,23074,212,212, 47, 47, 23, 23 },// Makhuwa Meetto/Latin/Mozambique
- { 173, 66, 230,23097,23097,22541,22541, 132, 132,263,263, 47, 47, 23, 23 },// Makonde/Latin/Tanzania
- { 174, 66, 141,23360,23360,23451,23451, 132, 132, 91, 91, 47, 47, 23, 23 },// Malagasy/Latin/Madagascar
- { 175, 74, 110,23498,23498,23585,23585,23646,23646, 87, 87, 61, 61, 31, 31 },// Malayalam/Malayalam/India
- { 176, 66, 143,23677,23677,23758,23758, 8165, 8165, 81, 81, 47, 47, 23, 23 },// Malay/Latin/Malaysia
- { 176, 4, 143, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Malay/Arabic/Malaysia
- { 176, 66, 35,23677,23677,23758,23758, 8165, 8165, 81, 81, 47, 47, 23, 23 },// Malay/Latin/Brunei
- { 176, 66, 111,23677,23677,23758,23758, 8165, 8165, 81, 81, 47, 47, 23, 23 },// Malay/Latin/Indonesia
- { 176, 66, 210,23677,23677,23758,23758, 8165, 8165, 81, 81, 47, 47, 23, 23 },// Malay/Latin/Singapore
- { 177, 66, 146,23805,23805,23890,23890,23937,23972, 85, 85, 47, 47, 35, 23 },// Maltese/Latin/Malta
- { 179, 9, 110,23995,24082,24169,24082,24226,24262, 87, 87, 57, 87, 36, 37 },// Manipuri/Bangla/India
- { 179, 78, 110, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Manipuri/Meitei Mayek/India
- { 180, 66, 115,24299,24299,24438,24438, 155, 155,139,139,101,101, 26, 26 },// Manx/Latin/Isle Of Man
- { 181, 66, 167,24539,24539,24622,24622,24672,24672, 83, 83, 50, 50, 23, 23 },// Maori/Latin/New Zealand
- { 182, 66, 49, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Mapuche/Latin/Chile
- { 183, 29, 110,24695,24695,24780,24780,24845,24845, 85, 85, 65, 65, 31, 31 },// Marathi/Devanagari/India
- { 185, 66, 124,24876,24876,25007,25007, 155, 155,131,131, 50, 50, 26, 26 },// Masai/Latin/Kenya
- { 185, 66, 230,24876,24876,25007,25007, 155, 155,131,131, 50, 50, 26, 26 },// Masai/Latin/Tanzania
- { 186, 4, 112,25057,25057,25057,25057, 155, 155, 69, 69, 69, 69, 26, 26 },// Mazanderani/Arabic/Iran
- { 188, 66, 124,25126,25126,25211,25211,25258,25258, 85, 85, 47, 47, 23, 23 },// Meru/Latin/Kenya
- { 189, 66, 40,25281,25281,25422,25422,25558,25558,141,141,136,136, 35, 35 },// Meta/Latin/Cameroon
- { 190, 66, 41, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Mohawk/Latin/Canada
- { 191, 27, 156,25593,25784,25975,25975,26073,26073,191,191, 98, 98, 37, 37 },// Mongolian/Cyrillic/Mongolia
- { 191, 83, 50, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Mongolian/Mongolian/China
- { 192, 66, 150,26110,26110,26177,26177,26223,26223, 67, 67, 46, 46, 23, 23 },// Morisyen/Latin/Mauritius
- { 193, 66, 40,26246,26246,26384,26384,26431,26431,138,138, 47, 47, 23, 23 },// Mundang/Latin/Cameroon
- { 194, 66, 248, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Muscogee/Latin/United States
- { 195, 66, 162,26454,26454, 85, 85, 132, 132,135,135, 47, 47, 23, 23 },// Nama/Latin/Namibia
- { 197, 66, 248, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Navajo/Latin/United States
- { 199, 29, 164,26589,26589,26589,26589,26673,26725, 84, 84, 84, 84, 52, 51 },// Nepali/Devanagari/Nepal
- { 199, 29, 110,26589,26589,26589,26589,26673,26725, 84, 84, 84, 84, 52, 51 },// Nepali/Devanagari/India
- { 201, 66, 40,26776,26776,26776,26776, 155, 155,164,164,164,164, 26, 26 },// Ngiemboon/Latin/Cameroon
- { 202, 66, 40,26940,26940,26940,26940, 155, 155,173,173,173,173, 26, 26 },// Ngomba/Latin/Cameroon
- { 203, 66, 169,27113,27113,27195,27245, 132, 132, 82, 82, 50, 49, 23, 23 },// Nigerian Pidgin/Latin/Nigeria
- { 204, 90, 102, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Nko/Nko/Guinea
- { 205, 4, 112,27294,27294,27294,27294, 155, 155, 76, 76, 76, 76, 26, 26 },// Northern Luri/Arabic/Iran
- { 205, 4, 113,27294,27294,27294,27294, 155, 155, 76, 76, 76, 76, 26, 26 },// Northern Luri/Arabic/Iraq
- { 206, 66, 175,27370,27370,27514,27514,27572,27572,144,144, 58, 58, 23, 23 },// Northern Sami/Latin/Norway
- { 206, 66, 83,27370,27370,27595,27595,27572,27572,144,144, 59, 59, 23, 23 },// Northern Sami/Latin/Finland
- { 206, 66, 225,27370,27370,27514,27514,27572,27572,144,144, 58, 58, 23, 23 },// Northern Sami/Latin/Sweden
- { 207, 66, 216, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Northern Sotho/Latin/South Africa
- { 208, 66, 261,27654,27654,27765,27765,27816,27816,111,111, 51, 51, 23, 23 },// North Ndebele/Latin/Zimbabwe
- { 209, 66, 175,27839,27839,11093,11140, 132, 132, 82, 82, 47, 58, 23, 23 },// Norwegian Bokmal/Latin/Norway
- { 209, 66, 224,27839,27839,11093,11140, 132, 132, 82, 82, 47, 58, 23, 23 },// Norwegian Bokmal/Latin/Svalbard And Jan Mayen
- { 210, 66, 175,27839,27839,11093,27921, 132, 132, 82, 82, 47, 58, 23, 23 },// Norwegian Nynorsk/Latin/Norway
- { 211, 66, 219,27979,27979,28074,28074,28127,28127, 95, 95, 53, 53, 23, 23 },// Nuer/Latin/South Sudan
- { 212, 66, 142, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Nyanja/Latin/Malawi
- { 213, 66, 243, 7641, 7641, 7792, 7792, 132, 132,151,151, 47, 47, 23, 23 },// Nyankole/Latin/Uganda
- { 214, 66, 84,28150,28232,28347,28347,28405,28405, 82,115, 58, 58, 23, 23 },// Occitan/Latin/France
- { 214, 66, 220,28428,28428,28501,28501,28405,28548, 73, 73, 47, 47, 23, 23 },// Occitan/Latin/Spain
- { 215, 91, 110,28571,28571,28571,28571,28656,28656, 85, 85, 85, 85, 31, 31 },// Odia/Odia/India
- { 220, 66, 77,28687,28687,28797,28797, 132, 132,110,110, 47, 47, 23, 23 },// Oromo/Latin/Ethiopia
- { 220, 66, 124,28687,28687,28797,28797,28844, 132,110,110, 47, 47, 23, 23 },// Oromo/Latin/Kenya
- { 221, 101, 248, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Osage/Osage/United States
- { 222, 27, 90,28867,28948,29033,29095, 7503, 7503, 81, 85, 62, 59, 23, 23 },// Ossetic/Cyrillic/Georgia
- { 222, 27, 193,28867,28948,29033,29095, 7503, 7503, 81, 85, 62, 59, 23, 23 },// Ossetic/Cyrillic/Russia
- { 227, 4, 1,29154,29222,29290,29222, 155,29357, 68, 68, 67, 68, 26, 23 },// Pashto/Arabic/Afghanistan
- { 227, 4, 178,29154,29222,29290,29222, 155,29357, 68, 68, 67, 68, 26, 23 },// Pashto/Arabic/Pakistan
- { 228, 4, 112,25057,29380,25057,25057,29453,29453, 69, 73, 69, 69, 23, 23 },// Persian/Arabic/Iran
- { 228, 4, 1,29476,29476,29476,29543,29357,29357, 67, 67, 67, 61, 23, 23 },// Persian/Arabic/Afghanistan
- { 230, 66, 187,29604,29700,29798,29798,29845,29868, 96, 98, 47, 47, 23, 23 },// Polish/Latin/Poland
- { 231, 66, 32,29891,29891,29979,29979, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Brazil
- { 231, 66, 7,29891,29891,29979,29979, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Angola
- { 231, 66, 43,29891,29891,29979,29979, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Cape Verde
- { 231, 66, 73,29891,29891,29979,29979, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Equatorial Guinea
- { 231, 66, 101,29891,29891,29979,29979, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Guinea Bissau
- { 231, 66, 138,29891,29891,29979,29979, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Luxembourg
- { 231, 66, 139,29891,29891,29979,29979, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Macao
- { 231, 66, 160,29891,29891,29979,29979, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Mozambique
- { 231, 66, 188,29891,29891,29979,29979, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Portugal
- { 231, 66, 204,29891,29891,29979,29979, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Sao Tome And Principe
- { 231, 66, 226,29891,29891,29979,29979, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Switzerland
- { 231, 66, 232,29891,29891,29979,29979, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Timor-Leste
- { 232, 66, 258, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Prussian/Latin/World
- { 233, 41, 110,30038,30038,30105,30105,30154,30154, 67, 67, 49, 49, 27, 27 },// Punjabi/Gurmukhi/India
- { 233, 4, 178,30181,30181,30181,30181, 155, 155, 66, 66, 66, 66, 26, 26 },// Punjabi/Arabic/Pakistan
- { 234, 66, 184,30247,30247,30334,30334, 155, 155, 87, 87, 47, 47, 26, 26 },// Quechua/Latin/Peru
- { 234, 66, 28,30247,30247,30334,30334, 155, 155, 87, 87, 47, 47, 26, 26 },// Quechua/Latin/Bolivia
- { 234, 66, 70,30247,30247,30334,30334, 155, 155, 87, 87, 47, 47, 26, 26 },// Quechua/Latin/Ecuador
- { 235, 66, 192,30381,30381,30478,30478,30537,30537, 97, 97, 59, 59, 23, 23 },// Romanian/Latin/Romania
- { 235, 66, 154,30381,30381,30478,30478,30537,30537, 97, 97, 59, 59, 23, 23 },// Romanian/Latin/Moldova
- { 236, 66, 226,30560,30651,30775,30775,30841,30841, 91,124, 66, 66, 23, 23 },// Romansh/Latin/Switzerland
- { 237, 66, 230,30864,30864,31057,31057,31095,31095,193,193, 38, 38, 23, 23 },// Rombo/Latin/Tanzania
- { 238, 66, 38,31118,31118,31223,31223, 155, 155,105,105, 59, 59, 26, 26 },// Rundi/Latin/Burundi
- { 239, 27, 193, 7377,31282,31363,31424, 7503, 7503, 79, 81, 61, 61, 23, 23 },// Russian/Cyrillic/Russia
- { 239, 27, 22, 7377,31282,31363,31424, 7503, 7503, 79, 81, 61, 61, 23, 23 },// Russian/Cyrillic/Belarus
- { 239, 27, 123, 7377,31282,31363,31424, 7503, 7503, 79, 81, 61, 61, 23, 23 },// Russian/Cyrillic/Kazakhstan
- { 239, 27, 128, 7377,31282,31363,31424, 7503, 7503, 79, 81, 61, 61, 23, 23 },// Russian/Cyrillic/Kyrgyzstan
- { 239, 27, 154, 7377,31282,31363,31424, 7503, 7503, 79, 81, 61, 61, 23, 23 },// Russian/Cyrillic/Moldova
- { 239, 27, 244, 7377,31282,31363,31424, 7503, 7503, 79, 81, 61, 61, 23, 23 },// Russian/Cyrillic/Ukraine
- { 240, 66, 230,22455,22455,22541,22541, 132, 132, 86, 86, 47, 47, 23, 23 },// Rwa/Latin/Tanzania
- { 241, 66, 74, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Saho/Latin/Eritrea
- { 242, 27, 193,31485,31600,31720,31720,31769,31769,115,120, 49, 49, 23, 23 },// Sakha/Cyrillic/Russia
- { 243, 66, 124,31792,31792,31964,31964,32011,32011,172,172, 47, 47, 23, 23 },// Samburu/Latin/Kenya
- { 245, 66, 46,32034,32034,32124,32124,32171,32171, 90, 90, 47, 47, 23, 23 },// Sango/Latin/Central African Republic
- { 246, 66, 230,32194,32194,32310,32310, 155, 155,116,116, 47, 47, 26, 26 },// Sangu/Latin/Tanzania
- { 247, 29, 110,32357,32357,32476,32476, 155,22787,119,119, 82, 82, 26, 28 },// Sanskrit/Devanagari/India
- { 248, 93, 110,32558,32558,32640,32640,32686,32686, 82, 82, 46, 46, 23, 23 },// Santali/Ol Chiki/India
- { 248, 29, 110, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Santali/Devanagari/India
- { 249, 66, 117,32709,32709,32809,32809,32856,32856,100,100, 47, 47, 23, 23 },// Sardinian/Latin/Italy
- { 251, 66, 160,32879,32879,32966,32966, 132, 132, 87, 87, 47, 47, 23, 23 },// Sena/Latin/Mozambique
- { 252, 27, 207,33013,33013,33093,33093, 5379, 5379, 80, 80, 47, 47, 23, 23 },// Serbian/Cyrillic/Serbia
- { 252, 27, 29,33013,33013,33093,33093, 5379, 5379, 80, 80, 47, 47, 23, 23 },// Serbian/Cyrillic/Bosnia And Herzegovina
- { 252, 27, 126,33013,33013,33140,33140, 5379, 5379, 80, 80, 49, 49, 23, 23 },// Serbian/Cyrillic/Kosovo
- { 252, 27, 157,33013,33013,33140,33140, 5379, 5379, 80, 80, 49, 49, 23, 23 },// Serbian/Cyrillic/Montenegro
- { 252, 66, 29,33189,33189,33269,33269, 5227, 5227, 80, 80, 47, 47, 23, 23 },// Serbian/Latin/Bosnia And Herzegovina
- { 252, 66, 126,33189,33189,33316,33316, 5227, 5227, 80, 80, 49, 49, 23, 23 },// Serbian/Latin/Kosovo
- { 252, 66, 157,33189,33189,33316,33316, 5227, 5227, 80, 80, 49, 49, 23, 23 },// Serbian/Latin/Montenegro
- { 252, 66, 207,33189,33189,33269,33269, 5227, 5227, 80, 80, 47, 47, 23, 23 },// Serbian/Latin/Serbia
- { 253, 66, 230,33365,33365,22541,22541, 132, 132, 83, 83, 47, 47, 23, 23 },// Shambala/Latin/Tanzania
- { 254, 66, 261,33448,33448,33547,33547,33594,33594, 99, 99, 47, 47, 23, 23 },// Shona/Latin/Zimbabwe
- { 255, 141, 50,33617,33617,33617,33617, 155, 155, 37, 37, 37, 37, 26, 26 },// Sichuan Yi/Yi/China
- { 256, 66, 117, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Sicilian/Latin/Italy
- { 257, 66, 77, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Sidamo/Latin/Ethiopia
- { 258, 66, 187, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Silesian/Latin/Poland
- { 259, 4, 178,33654,33654,33654,33654, 132, 132, 71, 71, 71, 71, 23, 23 },// Sindhi/Arabic/Pakistan
- { 259, 29, 110,33725,33799,33873,33926,33977,34006, 74, 74, 53, 51, 29, 30 },// Sindhi/Devanagari/India
- { 260, 119, 221,34036,34036,34131,34189,34249,34249, 95, 95, 58, 60, 31, 31 },// Sinhala/Sinhala/Sri Lanka
- { 261, 66, 83, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Skolt Sami/Latin/Finland
- { 262, 66, 212,34280,34361,34449,34449, 5227, 5227, 81, 88, 47, 47, 23, 23 },// Slovak/Latin/Slovakia
- { 263, 66, 213,34496,34496,34581,34581, 5227, 5227, 85, 85, 58, 58, 23, 23 },// Slovenian/Latin/Slovenia
- { 264, 66, 243,13206,13206,13302,13302, 132, 132, 96, 96, 47, 47, 23, 23 },// Soga/Latin/Uganda
- { 265, 66, 215,34639,34735,34923,34923,34970,34970, 96,188, 47, 47, 23, 23 },// Somali/Latin/Somalia
- { 265, 66, 67,34639,34735,34923,34923,34970,34970, 96,188, 47, 47, 23, 23 },// Somali/Latin/Djibouti
- { 265, 66, 77,34639,34735,34923,34923,34970,34970, 96,188, 47, 47, 23, 23 },// Somali/Latin/Ethiopia
- { 265, 66, 124,34639,34735,34923,34923,34970,34970, 96,188, 47, 47, 23, 23 },// Somali/Latin/Kenya
- { 266, 4, 112, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Southern Kurdish/Arabic/Iran
- { 267, 66, 225, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Southern Sami/Latin/Sweden
- { 268, 66, 216, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Southern Sotho/Latin/South Africa
- { 269, 66, 216, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// South Ndebele/Latin/South Africa
- { 270, 66, 220,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Spain
- { 270, 66, 11,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Argentina
- { 270, 66, 24,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Belize
- { 270, 66, 28,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Bolivia
- { 270, 66, 32,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Brazil
- { 270, 66, 42,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Canary Islands
- { 270, 66, 47,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Ceuta And Melilla
- { 270, 66, 49,34993,34993,35152,35081,35129,35129, 88, 88, 60, 48, 23, 23 },// Spanish/Latin/Chile
- { 270, 66, 54,34993,34993,35152,35081,35129,35129, 88, 88, 60, 48, 23, 23 },// Spanish/Latin/Colombia
- { 270, 66, 59,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Costa Rica
- { 270, 66, 61,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Cuba
- { 270, 66, 69,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Dominican Republic
- { 270, 66, 70,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Ecuador
- { 270, 66, 72,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/El Salvador
- { 270, 66, 73,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Equatorial Guinea
- { 270, 66, 99,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Guatemala
- { 270, 66, 106,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Honduras
- { 270, 66, 130,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Latin America
- { 270, 66, 152,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Mexico
- { 270, 66, 168,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Nicaragua
- { 270, 66, 181,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Panama
- { 270, 66, 183,34993,34993,35152,35152,35129,35129, 88, 88, 60, 60, 23, 23 },// Spanish/Latin/Paraguay
- { 270, 66, 184,30247,35212,35299,35358,35129,35129, 87, 87, 59, 59, 23, 23 },// Spanish/Latin/Peru
- { 270, 66, 185,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Philippines
- { 270, 66, 189,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Puerto Rico
- { 270, 66, 248,34993,34993,35081,35081,35129,35129, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/United States
- { 270, 66, 250,30247,35212,35299,35358,35129,35129, 87, 87, 59, 59, 23, 23 },// Spanish/Latin/Uruguay
- { 270, 66, 254,34993,34993,35152,35152,35129,35129, 88, 88, 60, 60, 23, 23 },// Spanish/Latin/Venezuela
- { 271, 135, 159,35417,35417,35497,35497,35544,35544, 80, 80, 47, 47, 23, 23 },// Standard Moroccan Tamazight/Tifinagh/Morocco
- { 272, 66, 111,35567,35567,35653,35653,35700,35700, 86, 86, 47, 47, 23, 23 },// Sundanese/Latin/Indonesia
- { 273, 66, 230, 2499, 2499,22541,22541, 132, 132, 83, 83, 47, 47, 23, 23 },// Swahili/Latin/Tanzania
- { 273, 66, 57, 2499, 2499,22541,22541, 132, 132, 83, 83, 47, 47, 23, 23 },// Swahili/Latin/Congo Kinshasa
- { 273, 66, 124, 2499, 2499,22541,22541, 132, 132, 83, 83, 47, 47, 23, 23 },// Swahili/Latin/Kenya
- { 273, 66, 243, 2499, 2499,22541,22541, 132, 132, 83, 83, 47, 47, 23, 23 },// Swahili/Latin/Uganda
- { 274, 66, 216, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Swati/Latin/South Africa
- { 275, 66, 225,35723,35723,35808,35808, 132, 132, 85, 85, 58, 58, 23, 23 },// Swedish/Latin/Sweden
- { 275, 66, 2,35723,35723,35808,35808, 132, 132, 85, 85, 58, 58, 23, 23 },// Swedish/Latin/Aland Islands
- { 275, 66, 83,35723,35723,35808,35808, 132, 132, 85, 85, 58, 58, 23, 23 },// Swedish/Latin/Finland
- { 276, 66, 226,35866,35866,13599,13599, 132, 132, 85, 85, 47, 47, 23, 23 },// Swiss German/Latin/Switzerland
- { 276, 66, 84,35866,35866,13599,13599, 132, 132, 85, 85, 47, 47, 23, 23 },// Swiss German/Latin/France
- { 276, 66, 136,35866,35866,13599,13599, 132, 132, 85, 85, 47, 47, 23, 23 },// Swiss German/Latin/Liechtenstein
- { 277, 123, 113, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Syriac/Syriac/Iraq
- { 278, 135, 159,35417,35417,35497,35497,35544,35544, 80, 80, 47, 47, 23, 23 },// Tachelhit/Tifinagh/Morocco
- { 278, 66, 159,35951,35951,36031,36031,36078,36078, 80, 80, 47, 47, 23, 23 },// Tachelhit/Latin/Morocco
- { 280, 127, 255, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Tai Dam/Tai Viet/Vietnam
- { 281, 66, 124,36101,36101,36321,36321,36368,36368,220,220, 47, 47, 23, 23 },// Taita/Latin/Kenya
- { 282, 27, 229,36391,36391,19874,19874, 7503, 7503, 70, 70, 47, 47, 23, 23 },// Tajik/Cyrillic/Tajikistan
- { 283, 129, 110,36461,36461,36546,36546,36603,36603, 85, 85, 57, 57, 30, 30 },// Tamil/Tamil/India
- { 283, 129, 143,36461,36461,36546,36546,36603,36603, 85, 85, 57, 57, 30, 30 },// Tamil/Tamil/Malaysia
- { 283, 129, 210,36461,36461,36546,36546,36603,36603, 85, 85, 57, 57, 30, 30 },// Tamil/Tamil/Singapore
- { 283, 129, 221,36461,36461,36546,36546,36603,36603, 85, 85, 57, 57, 30, 30 },// Tamil/Tamil/Sri Lanka
- { 284, 66, 228, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Taroko/Latin/Taiwan
- { 285, 66, 170,19191,19191,19278,19278,19323,19323, 87, 87, 45, 45, 23, 23 },// Tasawaq/Latin/Niger
- { 286, 27, 193,36633,36633,36713,36713, 155, 155, 80, 80, 61, 61, 26, 26 },// Tatar/Cyrillic/Russia
- { 287, 131, 110,36774,36774,36859,36859,36920,36920, 85, 85, 61, 61, 30, 30 },// Telugu/Telugu/India
- { 288, 66, 243,36950,36950,37043,37043,37090,37090, 93, 93, 47, 47, 23, 23 },// Teso/Latin/Uganda
- { 288, 66, 124,36950,36950,37043,37043,37090,37090, 93, 93, 47, 47, 23, 23 },// Teso/Latin/Kenya
- { 289, 133, 231,37113,37113,37210,37210,37210,37210, 97, 97, 62, 62, 62, 62 },// Thai/Thai/Thailand
- { 290, 134, 50,37272,37430, 9774, 9774, 155, 155,158,146, 62, 62, 26, 26 },// Tibetan/Tibetan/China
- { 290, 134, 110,37272,37430, 9774, 9774, 155, 155,158,146, 62, 62, 26, 26 },// Tibetan/Tibetan/India
- { 291, 33, 74, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Tigre/Ethiopic/Eritrea
- { 292, 33, 77,37576,37576,37629,37629,37664,37664, 53, 53, 35, 35, 23, 23 },// Tigrinya/Ethiopic/Ethiopia
- { 292, 33, 74,37576,37576,37629,37629,37664,37664, 53, 53, 35, 35, 23, 23 },// Tigrinya/Ethiopic/Eritrea
- { 294, 66, 182, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Tok Pisin/Latin/Papua New Guinea
- { 295, 66, 235,37687,37687,37773,37773,37823,37846, 86, 86, 50, 50, 23, 26 },// Tongan/Latin/Tonga
- { 296, 66, 216, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Tsonga/Latin/South Africa
- { 297, 66, 216, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Tswana/Latin/South Africa
- { 298, 66, 239,37872,37872,37946,37946,37993,37993, 74, 74, 47, 47, 23, 23 },// Turkish/Latin/Turkey
- { 298, 66, 63,37872,37872,37946,37946,37993,37993, 74, 74, 47, 47, 23, 23 },// Turkish/Latin/Cyprus
- { 299, 66, 240,38016,38092,38168,38217,38267,38267, 76, 76, 49, 50, 23, 23 },// Turkmen/Latin/Turkmenistan
- { 301, 66, 169, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Tyap/Latin/Nigeria
- { 303, 27, 244,38290,38384,38470,38517,38583,38606, 94, 86, 47, 66, 23, 23 },// Ukrainian/Cyrillic/Ukraine
- { 304, 66, 91,38629,38714,38806,38853, 5227, 5227, 85, 92, 47, 59, 23, 23 },// Upper Sorbian/Latin/Germany
- { 305, 4, 178,38912,38912,38912,38912, 132, 132, 67, 67, 67, 67, 23, 23 },// Urdu/Arabic/Pakistan
- { 305, 4, 110,38912,38912,38912,38912, 132, 132, 67, 67, 67, 67, 23, 23 },// Urdu/Arabic/India
- { 306, 4, 50,38979,38979,38979,38979, 155, 155, 83, 83, 83, 83, 26, 26 },// Uyghur/Arabic/China
- { 307, 66, 251,39062,39136,39210,39257,39304,39304, 74, 74, 47, 47, 23, 23 },// Uzbek/Latin/Uzbekistan
- { 307, 4, 1,29476,29476,39327,39327, 155, 155, 67, 67, 46, 46, 26, 26 },// Uzbek/Arabic/Afghanistan
- { 307, 27, 251,39373,39373, 7456, 7456, 7503, 7503, 70, 70, 47, 47, 23, 23 },// Uzbek/Cyrillic/Uzbekistan
- { 308, 139, 134,39443,39443,39503,39503, 155, 155, 60, 60, 37, 37, 26, 26 },// Vai/Vai/Liberia
- { 308, 66, 134, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Vai/Latin/Liberia
- { 309, 66, 216, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Venda/Latin/South Africa
- { 310, 66, 255,39540,39638,39736,39810, 155, 155, 98, 98, 74, 74, 26, 26 },// Vietnamese/Latin/Vietnam
- { 311, 66, 258, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Volapuk/Latin/World
- { 312, 66, 230,22455,22455,22541,22541, 132, 132, 86, 86, 47, 47, 23, 23 },// Vunjo/Latin/Tanzania
- { 313, 66, 23, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Walloon/Latin/Belgium
- { 314, 66, 226,39884,39884,39982,39982,40029,40029, 98, 98, 47, 47, 23, 23 },// Walser/Latin/Switzerland
- { 315, 66, 15, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Warlpiri/Latin/Australia
- { 316, 66, 246,40052,40052,40138,40189,40244,40244, 86, 86, 51, 55, 25, 25 },// Welsh/Latin/United Kingdom
- { 317, 4, 178, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Western Balochi/Arabic/Pakistan
- { 318, 66, 165,40269,40269,40363,40363, 132, 132, 94, 94, 47, 47, 23, 23 },// Western Frisian/Latin/Netherlands
- { 319, 33, 77, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Wolaytta/Ethiopic/Ethiopia
- { 320, 66, 206,40410,40410,40493,40493, 155, 155, 83, 83, 46, 46, 26, 26 },// Wolof/Latin/Senegal
- { 321, 66, 216,40539,40629,40720,40767, 155, 155, 90, 91, 47, 48, 26, 26 },// Xhosa/Latin/South Africa
- { 322, 66, 40,40815,40815,41005,41005, 155, 155,190,190, 50, 50, 26, 26 },// Yangben/Latin/Cameroon
- { 323, 47, 258,41055,41055,41146,41055, 155, 155, 91, 91, 57, 91, 26, 26 },// Yiddish/Hebrew/World
- { 324, 66, 169,41203,41275,41395,41434,41488,41488, 72,120, 39, 54, 26, 26 },// Yoruba/Latin/Nigeria
- { 324, 66, 25,41514,41587,41720,41760,41815,41815, 73,133, 40, 55, 26, 26 },// Yoruba/Latin/Benin
- { 325, 66, 170,19191,19191,19278,19278,19323,19323, 87, 87, 45, 45, 23, 23 },// Zarma/Latin/Niger
- { 327, 66, 216,41841,41841,41931,41931, 132,41978, 90, 90, 47, 47, 23, 23 },// Zulu/Latin/South Africa
- { 328, 66, 32,42001,42001,42087,42087,42149,42149, 86, 86, 62, 62, 38, 38 },// Kaingang/Latin/Brazil
- { 329, 66, 32,42187,42187,42287,42287,42322,42322,100,100, 35, 35, 23, 23 },// Nheengatu/Latin/Brazil
- { 329, 66, 54,42187,42187,42287,42287,42322,42322,100,100, 35, 35, 23, 23 },// Nheengatu/Latin/Colombia
- { 329, 66, 254,42187,42187,42287,42287,42322,42322,100,100, 35, 35, 23, 23 },// Nheengatu/Latin/Venezuela
- { 330, 29, 110,42345,42345,42345,42345, 155, 155, 73, 73, 73, 73, 26, 26 },// Haryanvi/Devanagari/India
- { 331, 66, 91,42418,42418,42512,42512, 132, 132, 94, 94, 47, 47, 23, 23 },// Northern Frisian/Latin/Germany
- { 332, 29, 110, 4864, 4864, 4864, 4864, 155, 155, 72, 72, 72, 72, 26, 26 },// Rajasthani/Devanagari/India
- { 333, 27, 193, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Moksha/Cyrillic/Russia
- { 334, 66, 258, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Toki Pona/Latin/World
- { 335, 66, 214,42559,42559,42559,42559, 155, 155, 76, 76, 76, 76, 26, 26 },// Pijin/Latin/Solomon Islands
- { 336, 66, 169, 181, 181, 181, 181, 155, 155, 47, 47, 47, 47, 26, 26 },// Obolo/Latin/Nigeria
+ { 75, 66, 252, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Vanuatu
+ { 75, 66, 258, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/world
+ { 75, 66, 260, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Zambia
+ { 75, 66, 261, 0, 0,12329,12329, 132, 132, 85, 85, 48, 48, 23, 23 },// English/Latin/Zimbabwe
+ { 75, 115, 246,12427,12427,12582,12582,12653,12653,155,155, 71, 71, 35, 35 },// English/Shavian/United Kingdom
+ { 76, 27, 193,12688,12688,12793,12688, 155, 155,105,105, 47,105, 26, 26 },// Erzya/Cyrillic/Russia
+ { 77, 66, 258,12840,12840,12930,12930, 132, 132, 90, 90, 47, 47, 23, 23 },// Esperanto/Latin/world
+ { 78, 66, 75,12977,12977,13067,13067,13125,13125, 90, 90, 58, 58, 23, 23 },// Estonian/Latin/Estonia
+ { 79, 66, 92,13148,13148,13234,13234,13281,13281, 86, 86, 47, 47, 23, 23 },// Ewe/Latin/Ghana
+ { 79, 66, 233,13148,13148,13234,13234,13281,13281, 86, 86, 47, 47, 23, 23 },// Ewe/Latin/Togo
+ { 80, 66, 40,13304,13304,13444,13444,13493,13493,140,140, 49, 49, 23, 23 },// Ewondo/Latin/Cameroon
+ { 81, 66, 81,13516,13516,13598,13645, 132, 132, 82, 82, 47, 58, 23, 23 },// Faroese/Latin/Faroe Islands
+ { 81, 66, 65,13516,13516,13598,13645, 132, 132, 82, 82, 47, 58, 23, 23 },// Faroese/Latin/Denmark
+ { 83, 66, 185,13703,13703,13790,13790,13837,13790, 87, 87, 47, 47, 37, 47 },// Filipino/Latin/Philippines
+ { 84, 66, 83,13874,13978,14106,14174,14266,14266,104,128, 68, 92, 23, 23 },// Finnish/Latin/Finland
+ { 85, 66, 84,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/France
+ { 85, 66, 4,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Algeria
+ { 85, 66, 23,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Belgium
+ { 85, 66, 25,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Benin
+ { 85, 66, 37,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Burkina Faso
+ { 85, 66, 38,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Burundi
+ { 85, 66, 40,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Cameroon
+ { 85, 66, 41,14289,14289,14435,14435, 132, 132, 84, 84, 63, 63, 23, 23 },// French/Latin/Canada
+ { 85, 66, 46,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Central African Republic
+ { 85, 66, 48,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Chad
+ { 85, 66, 55,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Comoros
+ { 85, 66, 56,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Congo - Brazzaville
+ { 85, 66, 57,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Congo - Kinshasa
+ { 85, 66, 67,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Djibouti
+ { 85, 66, 73,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Equatorial Guinea
+ { 85, 66, 85,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/French Guiana
+ { 85, 66, 86,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/French Polynesia
+ { 85, 66, 88,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Gabon
+ { 85, 66, 97,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Guadeloupe
+ { 85, 66, 102,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Guinea
+ { 85, 66, 104,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Haiti
+ { 85, 66, 118,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Ivory Coast
+ { 85, 66, 138,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Luxembourg
+ { 85, 66, 141,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Madagascar
+ { 85, 66, 145,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Mali
+ { 85, 66, 148,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Martinique
+ { 85, 66, 149,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Mauritania
+ { 85, 66, 150,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Mauritius
+ { 85, 66, 151,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Mayotte
+ { 85, 66, 155,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Monaco
+ { 85, 66, 159,14289,14289,14498,14498, 132, 132, 84, 84, 60, 60, 23, 23 },// French/Latin/Morocco
+ { 85, 66, 166,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/New Caledonia
+ { 85, 66, 170,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Niger
+ { 85, 66, 191,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Reunion
+ { 85, 66, 194,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Rwanda
+ { 85, 66, 195,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Saint Barthelemy
+ { 85, 66, 199,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Saint Martin
+ { 85, 66, 200,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Saint Pierre and Miquelon
+ { 85, 66, 206,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Senegal
+ { 85, 66, 208,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Seychelles
+ { 85, 66, 226,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Switzerland
+ { 85, 66, 227,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Syria
+ { 85, 66, 233,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Togo
+ { 85, 66, 238,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Tunisia
+ { 85, 66, 252,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Vanuatu
+ { 85, 66, 256,14289,14289,14373,14373, 132, 132, 84, 84, 62, 62, 23, 23 },// French/Latin/Wallis and Futuna
+ { 86, 66, 117,14558,14558,14634,14634,14681,14681, 76, 76, 47, 47, 23, 23 },// Friulian/Latin/Italy
+ { 87, 66, 206,14704,14704,14780,14780,14827,14827, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Senegal
+ { 87, 1, 37,14850,14850,14979,14850,15072,15072,129,129, 93,129, 35, 35 },// Fulah/Adlam/Burkina Faso
+ { 87, 1, 40,14850,14850,14979,14850,15072,15072,129,129, 93,129, 35, 35 },// Fulah/Adlam/Cameroon
+ { 87, 1, 89,14850,14850,14979,14850,15072,15072,129,129, 93,129, 35, 35 },// Fulah/Adlam/Gambia
+ { 87, 1, 92,14850,14850,14979,14850,15072,15072,129,129, 93,129, 35, 35 },// Fulah/Adlam/Ghana
+ { 87, 1, 101,14850,14850,14979,14850,15072,15072,129,129, 93,129, 35, 35 },// Fulah/Adlam/Guinea-Bissau
+ { 87, 1, 102,14850,14850,14979,14850,15072,15072,129,129, 93,129, 35, 35 },// Fulah/Adlam/Guinea
+ { 87, 1, 134,14850,14850,14979,14850,15072,15072,129,129, 93,129, 35, 35 },// Fulah/Adlam/Liberia
+ { 87, 1, 149,14850,14850,14979,14850,15072,15072,129,129, 93,129, 35, 35 },// Fulah/Adlam/Mauritania
+ { 87, 1, 169,14850,14850,14979,14850,15072,15072,129,129, 93,129, 35, 35 },// Fulah/Adlam/Nigeria
+ { 87, 1, 170,14850,14850,14979,14850,15072,15072,129,129, 93,129, 35, 35 },// Fulah/Adlam/Niger
+ { 87, 1, 206,14850,14850,14979,14850,15072,15072,129,129, 93,129, 35, 35 },// Fulah/Adlam/Senegal
+ { 87, 1, 209,14850,14850,14979,14850,15072,15072,129,129, 93,129, 35, 35 },// Fulah/Adlam/Sierra Leone
+ { 87, 66, 37,14704,14704,14780,14780,14827,14827, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Burkina Faso
+ { 87, 66, 40,14704,14704,14780,14780,14827,14827, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Cameroon
+ { 87, 66, 89,14704,14704,14780,14780,14827,14827, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Gambia
+ { 87, 66, 92,14704,14704,14780,14780,14827,14827, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Ghana
+ { 87, 66, 101,14704,14704,14780,14780,14827,14827, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Guinea-Bissau
+ { 87, 66, 102,14704,14704,14780,14780,14827,14827, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Guinea
+ { 87, 66, 134,14704,14704,14780,14780,14827,14827, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Liberia
+ { 87, 66, 149,14704,14704,14780,14780,14827,14827, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Mauritania
+ { 87, 66, 169,14704,14704,14780,14780,14827,14827, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Nigeria
+ { 87, 66, 170,14704,14704,14780,14780,14827,14827, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Niger
+ { 87, 66, 209,14704,14704,14780,14780,14827,14827, 76, 76, 47, 47, 23, 23 },// Fulah/Latin/Sierra Leone
+ { 88, 66, 246,15107,15248,15414,15414,15474,15474,141,166, 60, 60, 23, 23 },// Gaelic/Latin/United Kingdom
+ { 89, 66, 92,15497,15588,15679,15679,15726,15726, 91, 91, 47, 47, 23, 23 },// Ga/Latin/Ghana
+ { 90, 66, 220,15749,15749,15835,15835,15894,15917, 86, 86, 59, 59, 23, 35 },// Galician/Latin/Spain
+ { 91, 66, 243,15952,15952,16048,16048, 132, 132, 96, 96, 47, 47, 23, 23 },// Ganda/Latin/Uganda
+ { 92, 33, 77,16095,16095,16095,16095,16143,16143, 48, 48, 48, 48, 23, 23 },// Geez/Ethiopic/Ethiopia
+ { 92, 33, 74,16095,16095,16095,16095,16143,16143, 48, 48, 48, 48, 23, 23 },// Geez/Ethiopic/Eritrea
+ { 93, 35, 90,16166,16166,16264,16264,16311,16311, 98, 98, 47, 47, 23, 23 },// Georgian/Georgian/Georgia
+ { 94, 66, 91,16334,16334,16416,16463, 132, 132, 82, 82, 47, 59, 23, 23 },// German/Latin/Germany
+ { 94, 66, 16,16522,16522,16604,16651, 132, 132, 82, 82, 47, 58, 23, 23 },// German/Latin/Austria
+ { 94, 66, 23,16334,16334,16416,16463, 132, 132, 82, 82, 47, 59, 23, 23 },// German/Latin/Belgium
+ { 94, 66, 117,16522,16522,16604,16651, 132, 132, 82, 82, 47, 58, 23, 23 },// German/Latin/Italy
+ { 94, 66, 136,16334,16334,16416,16463, 132, 132, 82, 82, 47, 59, 23, 23 },// German/Latin/Liechtenstein
+ { 94, 66, 138,16334,16334,16416,16463, 132, 132, 82, 82, 47, 59, 23, 23 },// German/Latin/Luxembourg
+ { 94, 66, 226,16334,16334,16416,16463, 132, 132, 82, 82, 47, 59, 23, 23 },// German/Latin/Switzerland
+ { 96, 39, 94,16709,16823,16937,16986,17035,17035,114,114, 49, 49, 23, 23 },// Greek/Greek/Greece
+ { 96, 39, 63,16709,16823,16937,16986,17035,17035,114,114, 49, 49, 23, 23 },// Greek/Greek/Cyprus
+ { 97, 66, 183,17058,17058,17058,17058, 155, 155,109,109,109,109, 26, 26 },// Guarani/Latin/Paraguay
+ { 98, 40, 110,17167,17167,17253,17253,17319,17319, 86, 86, 66, 66, 30, 30 },// Gujarati/Gujarati/India
+ { 99, 66, 124,17349,17349,17436,17436,17483,17483, 87, 87, 47, 47, 23, 23 },// Gusii/Latin/Kenya
+ { 101, 66, 169,17506,17506,17590,17590,17637,17637, 84, 84, 47, 47, 23, 23 },// Hausa/Latin/Nigeria
+ { 101, 4, 169,17660,17660,17758,17758, 155, 155, 98, 98, 54, 54, 26, 26 },// Hausa/Arabic/Nigeria
+ { 101, 4, 222,17660,17660,17758,17758, 155, 155, 98, 98, 54, 54, 26, 26 },// Hausa/Arabic/Sudan
+ { 101, 66, 92,17506,17506,17590,17590,17637,17637, 84, 84, 47, 47, 23, 23 },// Hausa/Latin/Ghana
+ { 101, 66, 170,17506,17506,17590,17590,17637,17637, 84, 84, 47, 47, 23, 23 },// Hausa/Latin/Niger
+ { 102, 66, 248,17812,17812,17906,17906, 155, 155, 94, 94, 58, 58, 26, 26 },// Hawaiian/Latin/United States
+ { 103, 47, 116,17964,17964,18035,18035, 155, 155, 71, 71, 57, 57, 26, 26 },// Hebrew/Hebrew/Israel
+ { 105, 29, 110,18092,18092,18164,18164,18222,18222, 72, 72, 58, 58, 29, 29 },// Hindi/Devanagari/India
+ { 105, 66, 110, 0, 0,12329, 85, 132, 132, 85, 85, 48, 47, 23, 23 },// Hindi/Latin/India
+ { 107, 66, 108,18251,18251,18348,18348,18411,18411, 97, 97, 63, 63, 24, 24 },// Hungarian/Latin/Hungary
+ { 108, 66, 109,18435,18435,18516,18516,18574,18574, 81, 81, 58, 58, 23, 23 },// Icelandic/Latin/Iceland
+ { 109, 66, 258, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Ido/Latin/world
+ { 110, 66, 169,18597,18597,18683,18683,18730,18730, 86, 86, 47, 47, 23, 23 },// Igbo/Latin/Nigeria
+ { 111, 66, 83,18753,18753,18892,18892,18968,18968,139,139, 76, 76, 24, 24 },// Inari Sami/Latin/Finland
+ { 112, 66, 111,18992,18992,19078,19078, 132, 132, 86, 86, 47, 47, 23, 23 },// Indonesian/Latin/Indonesia
+ { 114, 66, 258,19125,19125,19217,19217, 155, 6342, 92, 92, 47, 47, 26, 23 },// Interlingua/Latin/world
+ { 115, 66, 75,19264,19264,19348,19348, 132, 132, 84, 84, 60, 60, 23, 23 },// Interlingue/Latin/Estonia
+ { 116, 18, 41,19408,19408,19408,19408, 155, 155, 58, 58, 58, 58, 26, 26 },// Inuktitut/Canadian Aboriginal/Canada
+ { 116, 66, 41, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Inuktitut/Latin/Canada
+ { 118, 66, 114,19466,19466,19572,19572,19633,19633,106,106, 61, 61, 23, 23 },// Irish/Latin/Ireland
+ { 118, 66, 246,19466,19466,19572,19572,19633,19633,106,106, 61, 61, 23, 23 },// Irish/Latin/United Kingdom
+ { 119, 66, 117,19656,19656,19749,19749,10211,10211, 93, 93, 47, 47, 23, 23 },// Italian/Latin/Italy
+ { 119, 66, 203,19656,19656,19749,19749,10211,10211, 93, 93, 47, 47, 23, 23 },// Italian/Latin/San Marino
+ { 119, 66, 226,19656,19656,19749,19749,10211,10211, 93, 93, 47, 47, 23, 23 },// Italian/Latin/Switzerland
+ { 119, 66, 253,19656,19656,19749,19749,10211,10211, 93, 93, 47, 47, 23, 23 },// Italian/Latin/Vatican City
+ { 120, 53, 120, 6995, 6995, 6995, 6995, 155, 155, 38, 38, 38, 38, 26, 26 },// Japanese/Japanese/Japan
+ { 121, 66, 111,18992,18992,19796,19796, 132, 132, 86, 86, 47, 47, 23, 23 },// Javanese/Latin/Indonesia
+ { 122, 66, 169,19843,19843,20020,20020, 155, 155,177,177, 56, 56, 26, 26 },// Jju/Latin/Nigeria
+ { 123, 66, 206,20076,20076,20157,20157,20192,20192, 81, 81, 35, 35, 23, 23 },// Jola-Fonyi/Latin/Senegal
+ { 124, 66, 43,20215,20215,20299,20299, 132, 132, 84, 84, 47, 47, 23, 23 },// Kabuverdianu/Latin/Cape Verde
+ { 125, 66, 4,20346,20346,20429,20476,20523,20546, 83, 83, 47, 47, 23, 23 },// Kabyle/Latin/Algeria
+ { 126, 66, 40,20569,20569,20569,20569, 155, 155,102,102,102,102, 26, 26 },// Kako/Latin/Cameroon
+ { 127, 66, 95,20671,20769,20879,20879, 132, 132, 98,110, 49, 49, 23, 23 },// Kalaallisut/Latin/Greenland
+ { 128, 66, 124,20928,20928,21048,21048,21096,21096,120,120, 48, 48, 23, 23 },// Kalenjin/Latin/Kenya
+ { 129, 66, 124,21119,21119,21307,21307,21354,21354,188,188, 47, 47, 23, 23 },// Kamba/Latin/Kenya
+ { 130, 56, 110,21377,21377,21463,21525,21597,21597, 86, 86, 62, 72, 30, 30 },// Kannada/Kannada/India
+ { 132, 4, 110,21627,21698,21627,21770,21839,21839, 71, 72, 71, 69, 23, 23 },// Kashmiri/Arabic/India
+ { 132, 29, 110,21862,21936,21862,22006,22079,22079, 74, 70, 74, 73, 24, 24 },// Kashmiri/Devanagari/India
+ { 133, 27, 123,22103,22185,22267,22267,22326,22326, 82, 82, 59, 59, 23, 23 },// Kazakh/Cyrillic/Kazakhstan
+ { 134, 66, 40, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Kenyang/Latin/Cameroon
+ { 135, 60, 39,22349,22349,22349,22349,22419,22419, 70, 70, 70, 70, 23, 23 },// Khmer/Khmer/Cambodia
+ { 136, 66, 99, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Kiche/Latin/Guatemala
+ { 137, 66, 124,22442,22442,22626,22626,22673,22673,184,184, 47, 47, 23, 23 },// Kikuyu/Latin/Kenya
+ { 138, 66, 194,22696,22696,22795,22795, 155, 155, 99, 99, 59, 59, 26, 26 },// Kinyarwanda/Latin/Rwanda
+ { 141, 29, 110,22854,22854,22939,22854, 155, 155, 85, 85, 58, 85, 26, 26 },// Konkani/Devanagari/India
+ { 142, 63, 218,22997,22997,22997,22997,22997,22997, 38, 38, 38, 38, 38, 38 },// Korean/Korean/South Korea
+ { 142, 63, 50,22997,22997,22997,22997,22997,22997, 38, 38, 38, 38, 38, 38 },// Korean/Korean/China
+ { 142, 63, 174,22997,22997,22997,22997,22997,22997, 38, 38, 38, 38, 38, 38 },// Korean/Korean/North Korea
+ { 144, 66, 145,23035,23035,23122,23122,23167,23167, 87, 87, 45, 45, 23, 23 },// Koyraboro Senni/Latin/Mali
+ { 145, 66, 145,23035,23035,23122,23122,23167,23167, 87, 87, 45, 45, 23, 23 },// Koyra Chiini/Latin/Mali
+ { 146, 66, 134, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Kpelle/Latin/Liberia
+ { 146, 66, 102, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Kpelle/Latin/Guinea
+ { 148, 66, 239,23190,23190,23271,23271,23318,23318, 81, 81, 47, 47, 23, 23 },// Kurdish/Latin/Turkey
+ { 149, 66, 40,23341,23341,23483,23483, 155, 155,142,142, 50, 50, 26, 26 },// Kwasio/Latin/Cameroon
+ { 150, 27, 128,23533, 8494,23612,23659, 8620, 8620, 79, 79, 47, 58, 23, 23 },// Kyrgyz/Cyrillic/Kyrgyzstan
+ { 151, 66, 248,23717,23717,23717,23717, 155, 155,179,179,179,179, 26, 26 },// Lakota/Latin/United States
+ { 152, 66, 230,23896,23896,24006,24006,24088,24088,110,110, 82, 82, 23, 23 },// Langi/Latin/Tanzania
+ { 153, 65, 129,24111,24111,24185,24185, 155, 155, 74, 74, 60, 60, 26, 26 },// Lao/Lao/Laos
+ { 154, 66, 253,24245,24346,24444,24444, 155, 155,101, 98, 47, 47, 26, 26 },// Latin/Latin/Vatican City
+ { 155, 66, 131,24491,24491,24591,24591, 132, 132,100,100, 64, 64, 23, 23 },// Latvian/Latin/Latvia
+ { 158, 66, 57,24655,24655,24857,24857,24904,24904,202,202, 47, 47, 23, 23 },// Lingala/Latin/Congo - Kinshasa
+ { 158, 66, 7,24655,24655,24857,24857,24904,24904,202,202, 47, 47, 23, 23 },// Lingala/Latin/Angola
+ { 158, 66, 46,24655,24655,24857,24857,24904,24904,202,202, 47, 47, 23, 23 },// Lingala/Latin/Central African Republic
+ { 158, 66, 56,24655,24655,24857,24857,24904,24904,202,202, 47, 47, 23, 23 },// Lingala/Latin/Congo - Brazzaville
+ { 160, 66, 137,24927,25022,25119,25119,25188,25188, 95, 97, 69, 69, 23, 23 },// Lithuanian/Latin/Lithuania
+ { 161, 66, 258, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Lojban/Latin/world
+ { 162, 66, 91,25211,25295,25387,25434, 6342, 6342, 84, 92, 47, 59, 23, 23 },// Lower Sorbian/Latin/Germany
+ { 163, 66, 91,25493,25493,25577,25577, 132, 132, 84, 84, 58, 58, 23, 23 },// Low German/Latin/Germany
+ { 163, 66, 165,25493,25493,25577,25577, 132, 132, 84, 84, 58, 58, 23, 23 },// Low German/Latin/Netherlands
+ { 164, 66, 57,25635,25635,25733,25733,25781,25781, 98, 98, 48, 48, 23, 23 },// Luba-Katanga/Latin/Congo - Kinshasa
+ { 165, 66, 225, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Lule Sami/Latin/Sweden
+ { 165, 66, 175, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Lule Sami/Latin/Norway
+ { 166, 66, 124,25804,25804,25989,25989,26036,26036,185,185, 47, 47, 23, 23 },// Luo/Latin/Kenya
+ { 167, 66, 138,26059,26059,26143,26190, 132, 132, 84, 84, 47, 58, 23, 23 },// Luxembourgish/Latin/Luxembourg
+ { 168, 66, 124, 3283, 3283,26248,26248, 132, 132, 83, 83, 47, 47, 23, 23 },// Luyia/Latin/Kenya
+ { 169, 27, 140,26295,26295,26379,26379, 6494, 6494, 84, 84, 58, 58, 23, 23 },// Macedonian/Cyrillic/Macedonia
+ { 170, 66, 230,26437,26437,26523,26523, 132, 132, 86, 86, 47, 47, 23, 23 },// Machame/Latin/Tanzania
+ { 171, 29, 110,26570,26641,26712,18164,26769,26769, 71, 71, 57, 58, 28, 28 },// Maithili/Devanagari/India
+ { 172, 66, 160,26797,26797,27009,27009,27056,27056,212,212, 47, 47, 23, 23 },// Makhuwa-Meetto/Latin/Mozambique
+ { 173, 66, 230,27079,27079,26523,26523, 132, 132,263,263, 47, 47, 23, 23 },// Makonde/Latin/Tanzania
+ { 174, 66, 141,27342,27342,27433,27433, 132, 132, 91, 91, 47, 47, 23, 23 },// Malagasy/Latin/Madagascar
+ { 175, 74, 110,27480,27480,27567,27567,27628,27628, 87, 87, 61, 61, 31, 31 },// Malayalam/Malayalam/India
+ { 176, 66, 143,27659,27659,27740,27740, 9725, 9725, 81, 81, 47, 47, 23, 23 },// Malay/Latin/Malaysia
+ { 176, 4, 35,27787,27787,27787,27787, 155, 155, 74, 74, 74, 74, 26, 26 },// Malay/Arabic/Brunei
+ { 176, 4, 143,27787,27787,27787,27787, 155, 155, 74, 74, 74, 74, 26, 26 },// Malay/Arabic/Malaysia
+ { 176, 66, 35,27659,27659,27740,27740, 9725, 9725, 81, 81, 47, 47, 23, 23 },// Malay/Latin/Brunei
+ { 176, 66, 111,27659,27659,27740,27740, 9725, 9725, 81, 81, 47, 47, 23, 23 },// Malay/Latin/Indonesia
+ { 176, 66, 210,27659,27659,27740,27740, 9725, 9725, 81, 81, 47, 47, 23, 23 },// Malay/Latin/Singapore
+ { 177, 66, 146,27861,27861,27946,27946,27993,28028, 85, 85, 47, 47, 35, 23 },// Maltese/Latin/Malta
+ { 179, 9, 110,28051,28138,28225,28282,28360,28396, 87, 87, 57, 78, 36, 37 },// Manipuri/Bangla/India
+ { 179, 78, 110, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Manipuri/Meitei Mayek/India
+ { 180, 66, 115,28433,28433,28572,28572, 155, 155,139,139,101,101, 26, 26 },// Manx/Latin/Isle of Man
+ { 181, 66, 167,28673,28755,28838,28838,28885,28885, 82, 83, 47, 47, 23, 23 },// Maori/Latin/New Zealand
+ { 182, 66, 49, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Mapuche/Latin/Chile
+ { 183, 29, 110,28908,28908,28993,28993,29058,29058, 85, 85, 65, 65, 31, 31 },// Marathi/Devanagari/India
+ { 185, 66, 124,29089,29089,29220,29220, 155, 155,131,131, 50, 50, 26, 26 },// Masai/Latin/Kenya
+ { 185, 66, 230,29089,29089,29220,29220, 155, 155,131,131, 50, 50, 26, 26 },// Masai/Latin/Tanzania
+ { 186, 4, 112,29270,29270,29270,29270, 155, 155, 69, 69, 69, 69, 26, 26 },// Mazanderani/Arabic/Iran
+ { 188, 66, 124,29339,29339,29424,29424,29471,29471, 85, 85, 47, 47, 23, 23 },// Meru/Latin/Kenya
+ { 189, 66, 40,29494,29494,29635,29635,29771,29771,141,141,136,136, 35, 35 },// Meta/Latin/Cameroon
+ { 190, 66, 41, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Mohawk/Latin/Canada
+ { 191, 27, 156,29806,29997,30188,30188,30286,30286,191,191, 98, 98, 37, 37 },// Mongolian/Cyrillic/Mongolia
+ { 191, 83, 50, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Mongolian/Mongolian/China
+ { 191, 83, 156,30323,30323,30534,30665,30286,30286,211,211,131,132, 37, 37 },// Mongolian/Mongolian/Mongolia
+ { 192, 66, 150,30797,30797,30864,30864,30910,30910, 67, 67, 46, 46, 23, 23 },// Morisyen/Latin/Mauritius
+ { 193, 66, 40,30933,30933,31071,31071,31118,31118,138,138, 47, 47, 23, 23 },// Mundang/Latin/Cameroon
+ { 194, 66, 248,31141,31141,31141,31141, 155, 155,124,124,124,124, 26, 26 },// Muscogee/Latin/United States
+ { 195, 66, 162,31265,31265, 85, 85, 132, 132,135,135, 47, 47, 23, 23 },// Nama/Latin/Namibia
+ { 197, 66, 248, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Navajo/Latin/United States
+ { 199, 29, 164,31400,31400,31400,31400,31484,31536, 84, 84, 84, 84, 52, 51 },// Nepali/Devanagari/Nepal
+ { 199, 29, 110,31400,31400,31400,31400,31484,31536, 84, 84, 84, 84, 52, 51 },// Nepali/Devanagari/India
+ { 201, 66, 40,31587,31587,31587,31587, 155, 155,164,164,164,164, 26, 26 },// Ngiemboon/Latin/Cameroon
+ { 202, 66, 40,31751,31751,31751,31751, 155, 155,173,173,173,173, 26, 26 },// Ngomba/Latin/Cameroon
+ { 203, 66, 169,31924,31924,32006,32056, 132, 132, 82, 82, 50, 49, 23, 23 },// Nigerian Pidgin/Latin/Nigeria
+ { 204, 90, 102,32105,32105,32210,32210,32271,32271,105,105, 61, 61, 23, 23 },// Nko/Nko/Guinea
+ { 205, 4, 112,32294,32294,32294,32294, 155, 155, 76, 76, 76, 76, 26, 26 },// Northern Luri/Arabic/Iran
+ { 205, 4, 113,32294,32294,32294,32294, 155, 155, 76, 76, 76, 76, 26, 26 },// Northern Luri/Arabic/Iraq
+ { 206, 66, 175,32370,32370,32514,32514,32572,32572,144,144, 58, 58, 23, 23 },// Northern Sami/Latin/Norway
+ { 206, 66, 83,32370,32370,32595,32595,32572,32572,144,144, 59, 59, 23, 23 },// Northern Sami/Latin/Finland
+ { 206, 66, 225,32370,32370,32514,32514,32572,32572,144,144, 58, 58, 23, 23 },// Northern Sami/Latin/Sweden
+ { 207, 66, 216,32654,32654,32759,32759,32823,32823,105,105, 64, 64, 23, 23 },// Northern Sotho/Latin/South Africa
+ { 208, 66, 261,32846,32846,32957,32957,33008,33008,111,111, 51, 51, 23, 23 },// North Ndebele/Latin/Zimbabwe
+ { 209, 66, 175,33031,33031,13598,33113, 132, 132, 82, 82, 47, 58, 23, 23 },// Norwegian Bokmal/Latin/Norway
+ { 209, 66, 224,33031,33031,13598,33113, 132, 132, 82, 82, 47, 58, 23, 23 },// Norwegian Bokmal/Latin/Svalbard and Jan Mayen
+ { 210, 66, 175,33031,33031,13598,33113, 132, 132, 82, 82, 47, 58, 23, 23 },// Norwegian Nynorsk/Latin/Norway
+ { 211, 66, 219,33171,33171,33266,33266,33319,33319, 95, 95, 53, 53, 23, 23 },// Nuer/Latin/South Sudan
+ { 212, 66, 142,33342,33342,33432,33432, 155, 155, 90, 90, 47, 47, 26, 26 },// Nyanja/Latin/Malawi
+ { 213, 66, 243, 8876, 8876, 9027, 9027, 132, 132,151,151, 47, 47, 23, 23 },// Nyankole/Latin/Uganda
+ { 214, 66, 84,33479,33561,33676,33676,33734,33734, 82,115, 58, 58, 23, 23 },// Occitan/Latin/France
+ { 214, 66, 220,33757,33757,33830,33830,33734,33877, 73, 73, 47, 47, 23, 23 },// Occitan/Latin/Spain
+ { 215, 91, 110,33900,33900,33900,33900,33985,33985, 85, 85, 85, 85, 31, 31 },// Odia/Odia/India
+ { 220, 66, 77,34016,34016,34126,34126, 132, 132,110,110, 47, 47, 23, 23 },// Oromo/Latin/Ethiopia
+ { 220, 66, 124,34016,34016,34126,34126,34173,34173,110,110, 47, 47, 23, 23 },// Oromo/Latin/Kenya
+ { 221, 101, 248,34196,34196,34527,34527, 155, 155,331,331,155,155, 26, 26 },// Osage/Osage/United States
+ { 222, 27, 90,34682,34763,34848,34910, 8620, 8620, 81, 85, 62, 59, 23, 23 },// Ossetic/Cyrillic/Georgia
+ { 222, 27, 193,34682,34763,34848,34910, 8620, 8620, 81, 85, 62, 59, 23, 23 },// Ossetic/Cyrillic/Russia
+ { 226, 66, 62,34969,34969,35055,35102, 155, 155, 86, 86, 47, 47, 26, 26 },// Papiamento/Latin/Curacao
+ { 226, 66, 13,34969,34969,35055,35102, 155, 155, 86, 86, 47, 47, 26, 26 },// Papiamento/Latin/Aruba
+ { 227, 4, 1,35149,35217,35285,35217, 155,35352, 68, 68, 67, 68, 26, 23 },// Pashto/Arabic/Afghanistan
+ { 227, 4, 178,35149,35217,35285,35217, 155,35352, 68, 68, 67, 68, 26, 23 },// Pashto/Arabic/Pakistan
+ { 228, 4, 112,29270,35375,29270,29270,35448,35448, 69, 73, 69, 69, 23, 23 },// Persian/Arabic/Iran
+ { 228, 4, 1,35471,35471,35471,35538,35352,35352, 67, 67, 67, 61, 23, 23 },// Persian/Arabic/Afghanistan
+ { 230, 66, 187,35599,35695,35793,35793,35840,35863, 96, 98, 47, 47, 23, 23 },// Polish/Latin/Poland
+ { 231, 66, 32,35886,35886,35974,35974, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Brazil
+ { 231, 66, 7,35886,35886,35974,35974, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Angola
+ { 231, 66, 43,35886,35886,35974,35974, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Cape Verde
+ { 231, 66, 73,35886,35886,35974,35974, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Equatorial Guinea
+ { 231, 66, 101,35886,35886,35974,35974, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Guinea-Bissau
+ { 231, 66, 138,35886,35886,35974,35974, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Luxembourg
+ { 231, 66, 139,35886,35886,35974,35974, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Macao
+ { 231, 66, 160,35886,35886,35974,35974, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Mozambique
+ { 231, 66, 188,35886,35886,35974,35974, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Portugal
+ { 231, 66, 204,35886,35886,35974,35974, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Sao Tome and Principe
+ { 231, 66, 226,35886,35886,35974,35974, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Switzerland
+ { 231, 66, 232,35886,35886,35974,35974, 132, 132, 88, 88, 59, 59, 23, 23 },// Portuguese/Latin/Timor-Leste
+ { 232, 66, 187,36033,36033,36123,36123,36170,36170, 90, 90, 47, 47, 23, 23 },// Prussian/Latin/Poland
+ { 233, 41, 110,36193,36193,36260,36260,36309,36309, 67, 67, 49, 49, 27, 27 },// Punjabi/Gurmukhi/India
+ { 233, 4, 178,36336,36336,36336,36336, 155, 155, 66, 66, 66, 66, 26, 26 },// Punjabi/Arabic/Pakistan
+ { 234, 66, 184,36402,36402,36489,36489, 155, 155, 87, 87, 47, 47, 26, 26 },// Quechua/Latin/Peru
+ { 234, 66, 28,36402,36402,36489,36489, 155, 155, 87, 87, 47, 47, 26, 26 },// Quechua/Latin/Bolivia
+ { 234, 66, 70,36402,36402,36489,36489, 155, 155, 87, 87, 47, 47, 26, 26 },// Quechua/Latin/Ecuador
+ { 235, 66, 192,36536,36536,36633,36633,36692,36692, 97, 97, 59, 59, 23, 23 },// Romanian/Latin/Romania
+ { 235, 66, 154,36536,36536,36633,36633,36692,36692, 97, 97, 59, 59, 23, 23 },// Romanian/Latin/Moldova
+ { 236, 66, 226,36715,36806,36930,36930,36996,36996, 91,124, 66, 66, 23, 23 },// Romansh/Latin/Switzerland
+ { 237, 66, 230,37019,37019,37212,37212,37250,37250,193,193, 38, 38, 23, 23 },// Rombo/Latin/Tanzania
+ { 238, 66, 38,37273,37273,37378,37378, 155, 155,105,105, 59, 59, 26, 26 },// Rundi/Latin/Burundi
+ { 239, 27, 193, 8494,37437,37518,37579, 8620, 8620, 79, 81, 61, 61, 23, 23 },// Russian/Cyrillic/Russia
+ { 239, 27, 22, 8494,37437,37518,37579, 8620, 8620, 79, 81, 61, 61, 23, 23 },// Russian/Cyrillic/Belarus
+ { 239, 27, 123, 8494,37437,37518,37579, 8620, 8620, 79, 81, 61, 61, 23, 23 },// Russian/Cyrillic/Kazakhstan
+ { 239, 27, 128, 8494,37437,37518,37579, 8620, 8620, 79, 81, 61, 61, 23, 23 },// Russian/Cyrillic/Kyrgyzstan
+ { 239, 27, 154, 8494,37437,37518,37579, 8620, 8620, 79, 81, 61, 61, 23, 23 },// Russian/Cyrillic/Moldova
+ { 239, 27, 244, 8494,37437,37518,37579, 8620, 8620, 79, 81, 61, 61, 23, 23 },// Russian/Cyrillic/Ukraine
+ { 240, 66, 230,26437,26437,26523,26523, 132, 132, 86, 86, 47, 47, 23, 23 },// Rwa/Latin/Tanzania
+ { 241, 66, 74, 392, 392, 509, 509, 556, 556,117,117, 47, 47, 23, 23 },// Saho/Latin/Eritrea
+ { 242, 27, 193,37640,37755,37875,37875,37924,37924,115,120, 49, 49, 23, 23 },// Sakha/Cyrillic/Russia
+ { 243, 66, 124,37947,37947,38119,38119,38166,38166,172,172, 47, 47, 23, 23 },// Samburu/Latin/Kenya
+ { 245, 66, 46,38189,38189,38279,38279,38326,38326, 90, 90, 47, 47, 23, 23 },// Sango/Latin/Central African Republic
+ { 246, 66, 230,38349,38349,38465,38465, 155, 155,116,116, 47, 47, 26, 26 },// Sangu/Latin/Tanzania
+ { 247, 29, 110,38512,38512,38631,38631, 155,26769,119,119, 82, 82, 26, 28 },// Sanskrit/Devanagari/India
+ { 248, 93, 110,38713,38713,38795,38795,38841,38841, 82, 82, 46, 46, 23, 23 },// Santali/Ol Chiki/India
+ { 248, 29, 110, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Santali/Devanagari/India
+ { 249, 66, 117,38864,38864,38964,38964,39011,39011,100,100, 47, 47, 23, 23 },// Sardinian/Latin/Italy
+ { 251, 66, 160,39034,39034,39121,39121, 132, 132, 87, 87, 47, 47, 23, 23 },// Sena/Latin/Mozambique
+ { 252, 27, 207,39168,39168,39248,39248, 6494, 6494, 80, 80, 47, 47, 23, 23 },// Serbian/Cyrillic/Serbia
+ { 252, 27, 29,39168,39168,39248,39248, 6494, 6494, 80, 80, 47, 47, 23, 23 },// Serbian/Cyrillic/Bosnia and Herzegovina
+ { 252, 27, 126,39168,39168,39295,39295, 6494, 6494, 80, 80, 49, 49, 23, 23 },// Serbian/Cyrillic/Kosovo
+ { 252, 27, 157,39168,39168,39295,39295, 6494, 6494, 80, 80, 49, 49, 23, 23 },// Serbian/Cyrillic/Montenegro
+ { 252, 66, 29,39344,39344,39424,39424, 6342, 6342, 80, 80, 47, 47, 23, 23 },// Serbian/Latin/Bosnia and Herzegovina
+ { 252, 66, 126,39344,39344,39471,39471, 6342, 6342, 80, 80, 49, 49, 23, 23 },// Serbian/Latin/Kosovo
+ { 252, 66, 157,39344,39344,39471,39471, 6342, 6342, 80, 80, 49, 49, 23, 23 },// Serbian/Latin/Montenegro
+ { 252, 66, 207,39344,39344,39424,39424, 6342, 6342, 80, 80, 47, 47, 23, 23 },// Serbian/Latin/Serbia
+ { 253, 66, 230,39520,39520,26523,26523, 132, 132, 83, 83, 47, 47, 23, 23 },// Shambala/Latin/Tanzania
+ { 254, 66, 261,39603,39603,39702,39702,39749,39749, 99, 99, 47, 47, 23, 23 },// Shona/Latin/Zimbabwe
+ { 255, 141, 50,39772,39772,39772,39772, 155, 155, 37, 37, 37, 37, 26, 26 },// Sichuan Yi/Yi/China
+ { 256, 66, 117,39809,39809,39906,39906,39953,39953, 97, 97, 47, 47, 23, 23 },// Sicilian/Latin/Italy
+ { 257, 66, 77, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Sidamo/Latin/Ethiopia
+ { 258, 66, 187,39976,40072,40170,40170,35840,35840, 96, 98, 47, 47, 23, 23 },// Silesian/Latin/Poland
+ { 259, 4, 178,40217,40217,40217,40217, 132, 132, 71, 71, 71, 71, 23, 23 },// Sindhi/Arabic/Pakistan
+ { 259, 29, 110,40288,40362,40436,40489,40540,40569, 74, 74, 53, 51, 29, 30 },// Sindhi/Devanagari/India
+ { 260, 119, 221,40599,40599,40694,40752,40812,40812, 95, 95, 58, 60, 31, 31 },// Sinhala/Sinhala/Sri Lanka
+ { 261, 66, 83, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Skolt Sami/Latin/Finland
+ { 262, 66, 212,40843,40924,41012,41012, 6342, 6342, 81, 88, 47, 47, 23, 23 },// Slovak/Latin/Slovakia
+ { 263, 66, 213,41059,41059,41144,41144, 6342, 6342, 85, 85, 58, 58, 23, 23 },// Slovenian/Latin/Slovenia
+ { 264, 66, 243,15952,15952,16048,16048, 132, 132, 96, 96, 47, 47, 23, 23 },// Soga/Latin/Uganda
+ { 265, 66, 215,41202,41298,41486,41486,41533,41533, 96,188, 47, 47, 23, 23 },// Somali/Latin/Somalia
+ { 265, 66, 67,41202,41298,41486,41486,41533,41533, 96,188, 47, 47, 23, 23 },// Somali/Latin/Djibouti
+ { 265, 66, 77,41202,41298,41486,41486,41533,41533, 96,188, 47, 47, 23, 23 },// Somali/Latin/Ethiopia
+ { 265, 66, 124,41202,41298,41486,41486,41533,41533, 96,188, 47, 47, 23, 23 },// Somali/Latin/Kenya
+ { 266, 4, 112, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Southern Kurdish/Arabic/Iran
+ { 266, 4, 113, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Southern Kurdish/Arabic/Iraq
+ { 267, 66, 225, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Southern Sami/Latin/Sweden
+ { 267, 66, 175, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Southern Sami/Latin/Norway
+ { 268, 66, 216,41556,41556,41660,41660, 155, 155,104,104, 47, 47, 26, 26 },// Southern Sotho/Latin/South Africa
+ { 268, 66, 133,41556,41556,41660,41660, 155, 155,104,104, 47, 47, 26, 26 },// Southern Sotho/Latin/Lesotho
+ { 269, 66, 216,41707,41707,41806,41806, 155, 155, 99, 99, 47, 47, 26, 26 },// South Ndebele/Latin/South Africa
+ { 270, 66, 220,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Spain
+ { 270, 66, 11,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Argentina
+ { 270, 66, 24,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Belize
+ { 270, 66, 28,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Bolivia
+ { 270, 66, 32,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Brazil
+ { 270, 66, 42,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Canary Islands
+ { 270, 66, 47,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Ceuta and Melilla
+ { 270, 66, 49,41853,41853,42012,41941,41989,41989, 88, 88, 60, 48, 23, 23 },// Spanish/Latin/Chile
+ { 270, 66, 54,41853,41853,42012,41941,41989,41989, 88, 88, 60, 48, 23, 23 },// Spanish/Latin/Colombia
+ { 270, 66, 59,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Costa Rica
+ { 270, 66, 61,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Cuba
+ { 270, 66, 69,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Dominican Republic
+ { 270, 66, 70,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Ecuador
+ { 270, 66, 72,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/El Salvador
+ { 270, 66, 73,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Equatorial Guinea
+ { 270, 66, 99,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Guatemala
+ { 270, 66, 106,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Honduras
+ { 270, 66, 130,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Latin America
+ { 270, 66, 152,41853,41853,42072,42072,41989,41989, 88, 88, 47, 47, 23, 23 },// Spanish/Latin/Mexico
+ { 270, 66, 168,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Nicaragua
+ { 270, 66, 181,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Panama
+ { 270, 66, 183,41853,41853,42012,42012,41989,41989, 88, 88, 60, 60, 23, 23 },// Spanish/Latin/Paraguay
+ { 270, 66, 184,36402,42119,42206,42265,41989,41989, 87, 87, 59, 59, 23, 23 },// Spanish/Latin/Peru
+ { 270, 66, 185,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Philippines
+ { 270, 66, 189,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/Puerto Rico
+ { 270, 66, 248,41853,41853,41941,41941,41989,41989, 88, 88, 48, 48, 23, 23 },// Spanish/Latin/United States
+ { 270, 66, 250,36402,42119,42206,42265,41989,41989, 87, 87, 59, 59, 23, 23 },// Spanish/Latin/Uruguay
+ { 270, 66, 254,41853,41853,42012,42012,41989,41989, 88, 88, 60, 60, 23, 23 },// Spanish/Latin/Venezuela
+ { 271, 135, 159,42324,42324,42404,42404,42451,42451, 80, 80, 47, 47, 23, 23 },// Standard Moroccan Tamazight/Tifinagh/Morocco
+ { 272, 66, 111,42474,42474,42560,42560,42607,42607, 86, 86, 47, 47, 23, 23 },// Sundanese/Latin/Indonesia
+ { 273, 66, 230, 3283, 3283,26523,26523, 132, 132, 83, 83, 47, 47, 23, 23 },// Swahili/Latin/Tanzania
+ { 273, 66, 57, 3283, 3283,26523,26523, 132, 132, 83, 83, 47, 47, 23, 23 },// Swahili/Latin/Congo - Kinshasa
+ { 273, 66, 124, 3283, 3283,26523,26523, 132, 132, 83, 83, 47, 47, 23, 23 },// Swahili/Latin/Kenya
+ { 273, 66, 243, 3283, 3283,26523,26523, 132, 132, 83, 83, 47, 47, 23, 23 },// Swahili/Latin/Uganda
+ { 274, 66, 216,42630,42630,42743,42743, 155, 155,113,113, 47, 47, 26, 26 },// Swati/Latin/South Africa
+ { 274, 66, 76,42630,42630,42743,42743, 155, 155,113,113, 47, 47, 26, 26 },// Swati/Latin/Eswatini
+ { 275, 66, 225,42790,42790,42875,42875, 132, 132, 85, 85, 58, 58, 23, 23 },// Swedish/Latin/Sweden
+ { 275, 66, 2,42790,42790,42875,42875, 132, 132, 85, 85, 58, 58, 23, 23 },// Swedish/Latin/Aland Islands
+ { 275, 66, 83,42790,42790,42875,42875, 132, 132, 85, 85, 58, 58, 23, 23 },// Swedish/Latin/Finland
+ { 276, 66, 226,42933,42933,16416,16416, 132, 132, 85, 85, 47, 47, 23, 23 },// Swiss German/Latin/Switzerland
+ { 276, 66, 84,42933,42933,16416,16416, 132, 132, 85, 85, 47, 47, 23, 23 },// Swiss German/Latin/France
+ { 276, 66, 136,42933,42933,16416,16416, 132, 132, 85, 85, 47, 47, 23, 23 },// Swiss German/Latin/Liechtenstein
+ { 277, 123, 113,43018,43018,43100,43100,43166,43189, 82, 82, 66, 66, 23, 23 },// Syriac/Syriac/Iraq
+ { 277, 123, 227,43018,43018,43100,43100,43166,43189, 82, 82, 66, 66, 23, 23 },// Syriac/Syriac/Syria
+ { 278, 135, 159,42324,42324,42404,42404,42451,42451, 80, 80, 47, 47, 23, 23 },// Tachelhit/Tifinagh/Morocco
+ { 278, 66, 159,43212,43212,43292,43292,43339,43339, 80, 80, 47, 47, 23, 23 },// Tachelhit/Latin/Morocco
+ { 280, 127, 255, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Tai Dam/Tai Viet/Vietnam
+ { 281, 66, 124,43362,43362,43582,43582,43629,43629,220,220, 47, 47, 23, 23 },// Taita/Latin/Kenya
+ { 282, 27, 229,43652,43652,23612,23612, 8620, 8620, 70, 70, 47, 47, 23, 23 },// Tajik/Cyrillic/Tajikistan
+ { 283, 129, 110,43722,43722,43807,43807,43864,43864, 85, 85, 57, 57, 30, 30 },// Tamil/Tamil/India
+ { 283, 129, 143,43722,43722,43807,43807,43864,43864, 85, 85, 57, 57, 30, 30 },// Tamil/Tamil/Malaysia
+ { 283, 129, 210,43722,43722,43807,43807,43864,43864, 85, 85, 57, 57, 30, 30 },// Tamil/Tamil/Singapore
+ { 283, 129, 221,43722,43722,43807,43807,43864,43864, 85, 85, 57, 57, 30, 30 },// Tamil/Tamil/Sri Lanka
+ { 284, 66, 228,43894,43894,44035,44035,44082,44082,141,141, 47, 47, 23, 23 },// Taroko/Latin/Taiwan
+ { 285, 66, 170,23035,23035,23122,23122,23167,23167, 87, 87, 45, 45, 23, 23 },// Tasawaq/Latin/Niger
+ { 286, 27, 193,44105,44105,44185,44185, 155, 155, 80, 80, 61, 61, 26, 26 },// Tatar/Cyrillic/Russia
+ { 287, 131, 110,44246,44246,44331,44331,44392,44392, 85, 85, 61, 61, 30, 30 },// Telugu/Telugu/India
+ { 288, 66, 243,44422,44422,44515,44515,44562,44562, 93, 93, 47, 47, 23, 23 },// Teso/Latin/Uganda
+ { 288, 66, 124,44422,44422,44515,44515,44562,44562, 93, 93, 47, 47, 23, 23 },// Teso/Latin/Kenya
+ { 289, 133, 231,44585,44585,44682,44682,44682,44682, 97, 97, 62, 62, 62, 62 },// Thai/Thai/Thailand
+ { 290, 134, 50,44744,44902,11646,11646, 155, 155,158,146, 62, 62, 26, 26 },// Tibetan/Tibetan/China
+ { 290, 134, 110,44744,44902,11646,11646, 155, 155,158,146, 62, 62, 26, 26 },// Tibetan/Tibetan/India
+ { 291, 33, 74,45048,45048,45109,45109, 1649, 1649, 61, 61, 45, 45, 23, 23 },// Tigre/Ethiopic/Eritrea
+ { 292, 33, 77,45154,45154,45207,45207,45242,45242, 53, 53, 35, 35, 23, 23 },// Tigrinya/Ethiopic/Ethiopia
+ { 292, 33, 74,45154,45154,45207,45207,45242,45242, 53, 53, 35, 35, 23, 23 },// Tigrinya/Ethiopic/Eritrea
+ { 294, 66, 182,45265,45265,45341,45341, 155, 155, 76, 76, 46, 46, 26, 26 },// Tok Pisin/Latin/Papua New Guinea
+ { 295, 66, 235,45387,45473,45559,45559,45609,45609, 86, 86, 50, 50, 26, 26 },// Tongan/Latin/Tonga
+ { 296, 66, 216,45635,45635,45756,45756, 155, 155,121,121, 47, 47, 26, 26 },// Tsonga/Latin/South Africa
+ { 297, 66, 216,45803,45803,45919,45919, 155, 155,116,116, 47, 47, 26, 26 },// Tswana/Latin/South Africa
+ { 297, 66, 30,45803,45803,45919,45919, 155, 155,116,116, 47, 47, 26, 26 },// Tswana/Latin/Botswana
+ { 298, 66, 239,45966,45966,46040,46040,46087,46087, 74, 74, 47, 47, 23, 23 },// Turkish/Latin/Turkey
+ { 298, 66, 63,45966,45966,46040,46040,46087,46087, 74, 74, 47, 47, 23, 23 },// Turkish/Latin/Cyprus
+ { 299, 66, 240,46110,46186,46262,46311,46361,46361, 76, 76, 49, 50, 23, 23 },// Turkmen/Latin/Turkmenistan
+ { 301, 66, 169,46384,46384,46536,46536, 155, 155,152,152, 47, 47, 26, 26 },// Tyap/Latin/Nigeria
+ { 303, 27, 244,46583,46677,46763,46763,46829,46852, 94, 86, 66, 66, 23, 23 },// Ukrainian/Cyrillic/Ukraine
+ { 304, 66, 91,46875,46960,47052,47099, 6342, 6342, 85, 92, 47, 59, 23, 23 },// Upper Sorbian/Latin/Germany
+ { 305, 4, 178,47158,47158,47158,47158, 132, 132, 67, 67, 67, 67, 23, 23 },// Urdu/Arabic/Pakistan
+ { 305, 4, 110,47158,47158,47158,47158, 132, 132, 67, 67, 67, 67, 23, 23 },// Urdu/Arabic/India
+ { 306, 4, 50,47225,47225,47225,47225, 155, 155, 83, 83, 83, 83, 26, 26 },// Uyghur/Arabic/China
+ { 307, 66, 251,47308,47382,47456,47503,47550,47550, 74, 74, 47, 47, 23, 23 },// Uzbek/Latin/Uzbekistan
+ { 307, 4, 1,35471,35471,47573,47573, 155, 155, 67, 67, 46, 46, 26, 26 },// Uzbek/Arabic/Afghanistan
+ { 307, 27, 251,47619,47619, 8573, 8573, 8620, 8620, 70, 70, 47, 47, 23, 23 },// Uzbek/Cyrillic/Uzbekistan
+ { 308, 139, 134,47689,47689,47749,47749, 155, 155, 60, 60, 37, 37, 26, 26 },// Vai/Vai/Liberia
+ { 308, 66, 134, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Vai/Latin/Liberia
+ { 309, 66, 216,47786,47786,47896,47896, 155, 155,110,110, 47, 47, 26, 26 },// Venda/Latin/South Africa
+ { 310, 66, 255,47943,48041,47943,48139, 155, 155, 98, 98, 98, 74, 26, 26 },// Vietnamese/Latin/Vietnam
+ { 311, 66, 258,48213,48213,48286,48333,48380,48380, 73, 73, 47, 47, 23, 23 },// Volapuk/Latin/world
+ { 312, 66, 230,26437,26437,26523,26523, 132, 132, 86, 86, 47, 47, 23, 23 },// Vunjo/Latin/Tanzania
+ { 313, 66, 23, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Walloon/Latin/Belgium
+ { 314, 66, 226,48403,48403,48501,48501,48548,48548, 98, 98, 47, 47, 23, 23 },// Walser/Latin/Switzerland
+ { 315, 66, 15, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Warlpiri/Latin/Australia
+ { 316, 66, 246,48571,48571,48657,48708,48763,48763, 86, 86, 51, 55, 25, 25 },// Welsh/Latin/United Kingdom
+ { 317, 4, 178, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Western Balochi/Arabic/Pakistan
+ { 317, 4, 1, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Western Balochi/Arabic/Afghanistan
+ { 317, 4, 112, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Western Balochi/Arabic/Iran
+ { 317, 4, 176, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Western Balochi/Arabic/Oman
+ { 317, 4, 245, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Western Balochi/Arabic/United Arab Emirates
+ { 318, 66, 165,48788,48788,48882,48882, 132, 132, 94, 94, 47, 47, 23, 23 },// Western Frisian/Latin/Netherlands
+ { 319, 33, 77,45048,45048,45109,45109, 1649, 1649, 61, 61, 45, 45, 23, 23 },// Wolaytta/Ethiopic/Ethiopia
+ { 320, 66, 206,48929,48929,49012,49012, 155, 155, 83, 83, 46, 46, 26, 26 },// Wolof/Latin/Senegal
+ { 321, 66, 216,49058,49148,49239,49286, 155, 155, 90, 91, 47, 48, 26, 26 },// Xhosa/Latin/South Africa
+ { 322, 66, 40,49334,49334,49524,49524, 155, 155,190,190, 50, 50, 26, 26 },// Yangben/Latin/Cameroon
+ { 323, 47, 244,49574,49574,49665,49574, 155, 155, 91, 91, 57, 91, 26, 26 },// Yiddish/Hebrew/Ukraine
+ { 324, 66, 169,49722,49794,49914,49953,50007,50007, 72,120, 39, 54, 26, 26 },// Yoruba/Latin/Nigeria
+ { 324, 66, 25,50033,50106,50239,50279,50334,50334, 73,133, 40, 55, 26, 26 },// Yoruba/Latin/Benin
+ { 325, 66, 170,23035,23035,23122,23122,23167,23167, 87, 87, 45, 45, 23, 23 },// Zarma/Latin/Niger
+ { 326, 66, 50,50360,50360,50360,50360, 155, 155,121,121,121,121, 26, 26 },// Zhuang/Latin/China
+ { 327, 66, 216,50481,50481,50571,50571, 132,50618, 90, 90, 47, 47, 23, 23 },// Zulu/Latin/South Africa
+ { 328, 66, 32,50641,50641,50727,50727,50789,50789, 86, 86, 62, 62, 38, 38 },// Kaingang/Latin/Brazil
+ { 329, 66, 32,50827,50827,50927,50927,50962,50962,100,100, 35, 35, 23, 23 },// Nheengatu/Latin/Brazil
+ { 329, 66, 54,50827,50827,50927,50927,50962,50962,100,100, 35, 35, 23, 23 },// Nheengatu/Latin/Colombia
+ { 329, 66, 254,50827,50827,50927,50927,50962,50962,100,100, 35, 35, 23, 23 },// Nheengatu/Latin/Venezuela
+ { 330, 29, 110,50985,50985,50985,50985, 155, 155, 73, 73, 73, 73, 26, 26 },// Haryanvi/Devanagari/India
+ { 331, 66, 91,51058,51058,51152,51152, 132, 132, 94, 94, 47, 47, 23, 23 },// Northern Frisian/Latin/Germany
+ { 332, 29, 110, 5834, 5834, 5834, 5834, 155, 155, 72, 72, 72, 72, 26, 26 },// Rajasthani/Devanagari/India
+ { 333, 27, 193, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Moksha/Cyrillic/Russia
+ { 334, 66, 258,51199,51199,51199,51199, 155, 155, 86, 86, 86, 86, 26, 26 },// Toki Pona/Latin/world
+ { 335, 66, 214,51285,51285,51285,51285, 155, 155, 76, 76, 76, 76, 26, 26 },// Pijin/Latin/Solomon Islands
+ { 336, 66, 169, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Obolo/Latin/Nigeria
+ { 337, 4, 178,51361,51361,51430,51430, 155, 155, 69, 69, 48, 48, 26, 26 },// Baluchi/Arabic/Pakistan
+ { 337, 66, 178,51478,51478,51560,51560, 155, 155, 82, 82, 47, 47, 26, 26 },// Baluchi/Latin/Pakistan
+ { 338, 66, 117,51607,51690,51806,51865,51957,51957, 83,116, 59, 92, 35, 35 },// Ligurian/Latin/Italy
+ { 339, 142, 161, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Rohingya/Hanifi/Myanmar
+ { 339, 142, 20, 1348, 1348, 1348, 1348, 155, 155, 47, 47, 47, 47, 26, 26 },// Rohingya/Hanifi/Bangladesh
+ { 340, 4, 178,36336,36336,36336,36336,35352,35352, 66, 66, 66, 66, 23, 23 },// Torwali/Arabic/Pakistan
+ { 341, 66, 25,51992,51992,52190,52190, 155, 155,198,198, 44, 44, 26, 26 },// Anii/Latin/Benin
+ { 342, 29, 110,18092,18092,18164,18164,18222,18222, 72, 72, 58, 58, 29, 29 },// Kangri/Devanagari/India
+ { 343, 66, 117,52234,52234,52318,52318,52365,52365, 84, 84, 47, 47, 23, 23 },// Venetian/Latin/Italy
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },// trailing zeros
};
static constexpr char16_t months_data[] = {
-0x4a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x79, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x79, 0x3b, 0x4d, 0x61, 0x72,
-0x63, 0x68, 0x3b, 0x41, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x4a, 0x75, 0x6e, 0x65, 0x3b, 0x4a, 0x75,
-0x6c, 0x79, 0x3b, 0x41, 0x75, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b,
-0x4f, 0x63, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x44, 0x65, 0x63,
-0x65, 0x6d, 0x62, 0x65, 0x72, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x70, 0x72,
-0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x75, 0x67, 0x3b, 0x53, 0x65, 0x70,
-0x3b, 0x4f, 0x63, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x63, 0x4a, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b,
-0x4d, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x31, 0x3b, 0x32, 0x3b, 0x33,
-0x3b, 0x34, 0x3b, 0x35, 0x3b, 0x36, 0x3b, 0x37, 0x3b, 0x38, 0x3b, 0x39, 0x3b, 0x31, 0x30, 0x3b, 0x31, 0x31, 0x3b, 0x31,
-0x32, 0x4d, 0x30, 0x31, 0x3b, 0x4d, 0x30, 0x32, 0x3b, 0x4d, 0x30, 0x33, 0x3b, 0x4d, 0x30, 0x34, 0x3b, 0x4d, 0x30, 0x35,
-0x3b, 0x4d, 0x30, 0x36, 0x3b, 0x4d, 0x30, 0x37, 0x3b, 0x4d, 0x30, 0x38, 0x3b, 0x4d, 0x30, 0x39, 0x3b, 0x4d, 0x31, 0x30,
-0x3b, 0x4d, 0x31, 0x31, 0x3b, 0x4d, 0x31, 0x32, 0x4a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x69, 0x65, 0x3b, 0x46, 0x65, 0x62,
-0x72, 0x75, 0x61, 0x72, 0x69, 0x65, 0x3b, 0x4d, 0x61, 0x61, 0x72, 0x74, 0x3b, 0x41, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x4d,
-0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x65, 0x3b, 0x4a, 0x75, 0x6c, 0x69, 0x65, 0x3b, 0x41, 0x75, 0x67, 0x75, 0x73,
-0x74, 0x75, 0x73, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x65,
-0x72, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x44, 0x65, 0x73, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4a,
-0x61, 0x6e, 0x2e, 0x3b, 0x46, 0x65, 0x62, 0x2e, 0x3b, 0x4d, 0x72, 0x74, 0x2e, 0x3b, 0x41, 0x70, 0x72, 0x2e, 0x3b, 0x4d,
-0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x2e, 0x3b, 0x4a, 0x75, 0x6c, 0x2e, 0x3b, 0x41, 0x75, 0x67, 0x2e, 0x3b, 0x53, 0x65,
-0x70, 0x2e, 0x3b, 0x4f, 0x6b, 0x74, 0x2e, 0x3b, 0x4e, 0x6f, 0x76, 0x2e, 0x3b, 0x44, 0x65, 0x73, 0x2e, 0x6e, 0x64, 0x7a,
-0x254, 0x300, 0x14b, 0x254, 0x300, 0x6e, 0xf9, 0x6d, 0x3b, 0x6e, 0x64, 0x7a, 0x254, 0x300, 0x14b, 0x254, 0x300, 0x6b, 0x197, 0x300,
-0x7a, 0xf9, 0x294, 0x3b, 0x6e, 0x64, 0x7a, 0x254, 0x300, 0x14b, 0x254, 0x300, 0x74, 0x197, 0x300, 0x64, 0x289, 0x300, 0x67, 0x68,
-0xe0, 0x3b, 0x6e, 0x64, 0x7a, 0x254, 0x300, 0x14b, 0x254, 0x300, 0x74, 0x1ce, 0x61, 0x66, 0x289, 0x304, 0x67, 0x68, 0x101, 0x3b,
-0x6e, 0x64, 0x7a, 0x254, 0x300, 0x14b, 0xe8, 0x73, 0xe8, 0x65, 0x3b, 0x6e, 0x64, 0x7a, 0x254, 0x300, 0x14b, 0x254, 0x300, 0x6e,
-0x7a, 0xf9, 0x67, 0x68, 0xf2, 0x3b, 0x6e, 0x64, 0x7a, 0x254, 0x300, 0x14b, 0x254, 0x300, 0x64, 0xf9, 0x6d, 0x6c, 0x6f, 0x3b,
-0x6e, 0x64, 0x7a, 0x254, 0x300, 0x14b, 0x254, 0x300, 0x6b, 0x77, 0xee, 0x66, 0x254, 0x300, 0x65, 0x3b, 0x6e, 0x64, 0x7a, 0x254,
-0x300, 0x14b, 0x254, 0x300, 0x74, 0x197, 0x300, 0x66, 0x289, 0x300, 0x67, 0x68, 0xe0, 0x64, 0x7a, 0x75, 0x67, 0x68, 0xf9, 0x3b,
-0x6e, 0x64, 0x7a, 0x254, 0x300, 0x14b, 0x254, 0x300, 0x67, 0x68, 0x1d4, 0x75, 0x77, 0x65, 0x6c, 0x254, 0x300, 0x6d, 0x3b, 0x6e,
-0x64, 0x7a, 0x254, 0x300, 0x14b, 0x254, 0x300, 0x63, 0x68, 0x77, 0x61, 0x294, 0xe0, 0x6b, 0x61, 0x61, 0x20, 0x77, 0x6f, 0x3b,
-0x6e, 0x64, 0x7a, 0x254, 0x300, 0x14b, 0xe8, 0x66, 0x77, 0xf2, 0x6f, 0x6e, 0xf9, 0x6d, 0x3b, 0x6b, 0x268, 0x7a, 0x3b, 0x74,
-0x268, 0x64, 0x3b, 0x74, 0x61, 0x61, 0x3b, 0x73, 0x65, 0x65, 0x3b, 0x6e, 0x7a, 0x75, 0x3b, 0x64, 0x75, 0x6d, 0x3b, 0x66,
-0x254, 0x65, 0x3b, 0x64, 0x7a, 0x75, 0x3b, 0x6c, 0x254, 0x6d, 0x3b, 0x6b, 0x61, 0x61, 0x3b, 0x66, 0x77, 0x6f, 0x6e, 0x3b,
-0x6b, 0x3b, 0x74, 0x3b, 0x74, 0x3b, 0x73, 0x3b, 0x7a, 0x3b, 0x6b, 0x3b, 0x66, 0x3b, 0x64, 0x3b, 0x6c, 0x3b, 0x63, 0x3b,
-0x66, 0x53, 0x61, 0x6e, 0x64, 0x61, 0x2d, 0x186, 0x70, 0x25b, 0x70, 0x254, 0x6e, 0x3b, 0x4b, 0x77, 0x61, 0x6b, 0x77, 0x61,
-0x72, 0x2d, 0x186, 0x67, 0x79, 0x65, 0x66, 0x75, 0x6f, 0x3b, 0x45, 0x62, 0x254, 0x77, 0x2d, 0x186, 0x62, 0x65, 0x6e, 0x65,
-0x6d, 0x3b, 0x45, 0x62, 0x254, 0x62, 0x69, 0x72, 0x61, 0x2d, 0x4f, 0x66, 0x6f, 0x72, 0x69, 0x73, 0x75, 0x6f, 0x3b, 0x45,
-0x73, 0x75, 0x73, 0x6f, 0x77, 0x20, 0x41, 0x6b, 0x65, 0x74, 0x73, 0x65, 0x61, 0x62, 0x61, 0x2d, 0x4b, 0x254, 0x74, 0x254,
-0x6e, 0x69, 0x6d, 0x62, 0x61, 0x3b, 0x4f, 0x62, 0x69, 0x72, 0x61, 0x64, 0x65, 0x2d, 0x41, 0x79, 0x25b, 0x77, 0x6f, 0x68,
-0x6f, 0x6d, 0x75, 0x6d, 0x75, 0x3b, 0x41, 0x79, 0x25b, 0x77, 0x6f, 0x68, 0x6f, 0x2d, 0x4b, 0x69, 0x74, 0x61, 0x77, 0x6f,
-0x6e, 0x73, 0x61, 0x3b, 0x44, 0x69, 0x66, 0x75, 0x75, 0x2d, 0x186, 0x73, 0x61, 0x6e, 0x64, 0x61, 0x61, 0x3b, 0x46, 0x61,
-0x6e, 0x6b, 0x77, 0x61, 0x2d, 0x190, 0x62, 0x254, 0x3b, 0x186, 0x62, 0x25b, 0x73, 0x25b, 0x2d, 0x41, 0x68, 0x69, 0x6e, 0x69,
-0x6d, 0x65, 0x3b, 0x186, 0x62, 0x65, 0x72, 0x25b, 0x66, 0x25b, 0x77, 0x2d, 0x4f, 0x62, 0x75, 0x62, 0x75, 0x6f, 0x3b, 0x4d,
-0x75, 0x6d, 0x75, 0x2d, 0x186, 0x70, 0x25b, 0x6e, 0x69, 0x6d, 0x62, 0x61, 0x53, 0x2d, 0x186, 0x3b, 0x4b, 0x2d, 0x186, 0x3b,
-0x45, 0x2d, 0x186, 0x3b, 0x45, 0x2d, 0x4f, 0x3b, 0x45, 0x2d, 0x4b, 0x3b, 0x4f, 0x2d, 0x41, 0x3b, 0x41, 0x2d, 0x4b, 0x3b,
-0x44, 0x2d, 0x186, 0x3b, 0x46, 0x2d, 0x190, 0x3b, 0x186, 0x2d, 0x41, 0x3b, 0x186, 0x2d, 0x4f, 0x3b, 0x4d, 0x2d, 0x186, 0x6a,
-0x61, 0x6e, 0x61, 0x72, 0x3b, 0x73, 0x68, 0x6b, 0x75, 0x72, 0x74, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x3b, 0x70, 0x72, 0x69,
-0x6c, 0x6c, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x71, 0x65, 0x72, 0x73, 0x68, 0x6f, 0x72, 0x3b, 0x6b, 0x6f, 0x72, 0x72, 0x69,
-0x6b, 0x3b, 0x67, 0x75, 0x73, 0x68, 0x74, 0x3b, 0x73, 0x68, 0x74, 0x61, 0x74, 0x6f, 0x72, 0x3b, 0x74, 0x65, 0x74, 0x6f,
-0x72, 0x3b, 0x6e, 0xeb, 0x6e, 0x74, 0x6f, 0x72, 0x3b, 0x64, 0x68, 0x6a, 0x65, 0x74, 0x6f, 0x72, 0x6a, 0x61, 0x6e, 0x3b,
-0x73, 0x68, 0x6b, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x70, 0x72, 0x69, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x71, 0x65, 0x72, 0x3b,
-0x6b, 0x6f, 0x72, 0x72, 0x3b, 0x67, 0x75, 0x73, 0x68, 0x3b, 0x73, 0x68, 0x74, 0x3b, 0x74, 0x65, 0x74, 0x3b, 0x6e, 0xeb,
-0x6e, 0x3b, 0x64, 0x68, 0x6a, 0x6a, 0x3b, 0x73, 0x68, 0x3b, 0x6d, 0x3b, 0x70, 0x3b, 0x6d, 0x3b, 0x71, 0x3b, 0x6b, 0x3b,
-0x67, 0x3b, 0x73, 0x68, 0x3b, 0x74, 0x3b, 0x6e, 0x3b, 0x64, 0x68, 0x1303, 0x1295, 0x12e9, 0x12c8, 0x122a, 0x3b, 0x134c, 0x1265, 0x1229,
-0x12c8, 0x122a, 0x3b, 0x121b, 0x122d, 0x127d, 0x3b, 0x12a4, 0x1355, 0x122a, 0x120d, 0x3b, 0x121c, 0x12ed, 0x3b, 0x1301, 0x1295, 0x3b, 0x1301, 0x120b,
-0x12ed, 0x3b, 0x12a6, 0x1308, 0x1235, 0x1275, 0x3b, 0x1234, 0x1355, 0x1274, 0x121d, 0x1260, 0x122d, 0x3b, 0x12a6, 0x12ad, 0x1276, 0x1260, 0x122d, 0x3b,
-0x1296, 0x126c, 0x121d, 0x1260, 0x122d, 0x3b, 0x12f2, 0x1234, 0x121d, 0x1260, 0x122d, 0x1303, 0x1295, 0x12e9, 0x3b, 0x134c, 0x1265, 0x1229, 0x3b, 0x121b,
-0x122d, 0x127d, 0x3b, 0x12a4, 0x1355, 0x122a, 0x3b, 0x121c, 0x12ed, 0x3b, 0x1301, 0x1295, 0x3b, 0x1301, 0x120b, 0x12ed, 0x3b, 0x12a6, 0x1308, 0x1235,
-0x3b, 0x1234, 0x1355, 0x1274, 0x3b, 0x12a6, 0x12ad, 0x1276, 0x3b, 0x1296, 0x126c, 0x121d, 0x3b, 0x12f2, 0x1234, 0x121d, 0x1303, 0x3b, 0x134c, 0x3b,
-0x121b, 0x3b, 0x12a4, 0x3b, 0x121c, 0x3b, 0x1301, 0x3b, 0x1301, 0x3b, 0x12a6, 0x3b, 0x1234, 0x3b, 0x12a6, 0x3b, 0x1296, 0x3b, 0x12f2, 0x64a,
-0x646, 0x627, 0x64a, 0x631, 0x3b, 0x641, 0x628, 0x631, 0x627, 0x64a, 0x631, 0x3b, 0x645, 0x627, 0x631, 0x633, 0x3b, 0x623, 0x628, 0x631,
-0x64a, 0x644, 0x3b, 0x645, 0x627, 0x64a, 0x648, 0x3b, 0x64a, 0x648, 0x646, 0x64a, 0x648, 0x3b, 0x64a, 0x648, 0x644, 0x64a, 0x648, 0x3b,
-0x623, 0x63a, 0x633, 0x637, 0x633, 0x3b, 0x633, 0x628, 0x62a, 0x645, 0x628, 0x631, 0x3b, 0x623, 0x643, 0x62a, 0x648, 0x628, 0x631, 0x3b,
-0x646, 0x648, 0x641, 0x645, 0x628, 0x631, 0x3b, 0x62f, 0x64a, 0x633, 0x645, 0x628, 0x631, 0x64a, 0x3b, 0x641, 0x3b, 0x645, 0x3b, 0x623,
-0x3b, 0x648, 0x3b, 0x646, 0x3b, 0x644, 0x3b, 0x63a, 0x3b, 0x633, 0x3b, 0x643, 0x3b, 0x628, 0x3b, 0x62f, 0x62c, 0x627, 0x646, 0x641,
-0x64a, 0x3b, 0x641, 0x64a, 0x641, 0x631, 0x64a, 0x3b, 0x645, 0x627, 0x631, 0x633, 0x3b, 0x623, 0x641, 0x631, 0x64a, 0x644, 0x3b, 0x645,
-0x627, 0x64a, 0x3b, 0x62c, 0x648, 0x627, 0x646, 0x3b, 0x62c, 0x648, 0x64a, 0x644, 0x64a, 0x629, 0x3b, 0x623, 0x648, 0x62a, 0x3b, 0x633,
-0x628, 0x62a, 0x645, 0x628, 0x631, 0x3b, 0x623, 0x643, 0x62a, 0x648, 0x628, 0x631, 0x3b, 0x646, 0x648, 0x641, 0x645, 0x628, 0x631, 0x3b,
-0x62f, 0x64a, 0x633, 0x645, 0x628, 0x631, 0x62c, 0x3b, 0x641, 0x3b, 0x645, 0x3b, 0x623, 0x3b, 0x645, 0x3b, 0x62c, 0x3b, 0x62c, 0x3b,
-0x623, 0x3b, 0x633, 0x3b, 0x623, 0x3b, 0x646, 0x3b, 0x62f, 0x643, 0x627, 0x646, 0x648, 0x646, 0x20, 0x627, 0x644, 0x62b, 0x627, 0x646,
-0x64a, 0x3b, 0x634, 0x628, 0x627, 0x637, 0x3b, 0x622, 0x630, 0x627, 0x631, 0x3b, 0x646, 0x64a, 0x633, 0x627, 0x646, 0x3b, 0x623, 0x64a,
-0x627, 0x631, 0x3b, 0x62d, 0x632, 0x64a, 0x631, 0x627, 0x646, 0x3b, 0x62a, 0x645, 0x648, 0x632, 0x3b, 0x622, 0x628, 0x3b, 0x623, 0x64a,
-0x644, 0x648, 0x644, 0x3b, 0x62a, 0x634, 0x631, 0x64a, 0x646, 0x20, 0x627, 0x644, 0x623, 0x648, 0x644, 0x3b, 0x62a, 0x634, 0x631, 0x64a,
-0x646, 0x20, 0x627, 0x644, 0x62b, 0x627, 0x646, 0x64a, 0x3b, 0x643, 0x627, 0x646, 0x648, 0x646, 0x20, 0x627, 0x644, 0x623, 0x648, 0x644,
-0x643, 0x627, 0x646, 0x648, 0x646, 0x20, 0x627, 0x644, 0x62b, 0x627, 0x646, 0x64a, 0x3b, 0x634, 0x628, 0x627, 0x637, 0x3b, 0x622, 0x630,
-0x627, 0x631, 0x3b, 0x646, 0x64a, 0x633, 0x627, 0x646, 0x3b, 0x623, 0x64a, 0x627, 0x631, 0x3b, 0x62d, 0x632, 0x64a, 0x631, 0x627, 0x646,
-0x3b, 0x62a, 0x645, 0x648, 0x632, 0x3b, 0x622, 0x628, 0x3b, 0x623, 0x64a, 0x644, 0x648, 0x644, 0x3b, 0x62a, 0x634, 0x631, 0x64a, 0x646,
-0xa0, 0x627, 0x644, 0x623, 0x648, 0x644, 0x3b, 0x62a, 0x634, 0x631, 0x64a, 0x646, 0x20, 0x627, 0x644, 0x62b, 0x627, 0x646, 0x64a, 0x3b,
-0x643, 0x627, 0x646, 0x648, 0x646, 0x20, 0x627, 0x644, 0x623, 0x648, 0x644, 0x643, 0x3b, 0x634, 0x3b, 0x622, 0x3b, 0x646, 0x3b, 0x623,
-0x3b, 0x62d, 0x3b, 0x62a, 0x3b, 0x622, 0x3b, 0x623, 0x3b, 0x62a, 0x3b, 0x62a, 0x3b, 0x643, 0x64a, 0x646, 0x627, 0x64a, 0x631, 0x3b,
-0x641, 0x628, 0x631, 0x627, 0x64a, 0x631, 0x3b, 0x645, 0x627, 0x631, 0x633, 0x3b, 0x625, 0x628, 0x631, 0x64a, 0x644, 0x3b, 0x645, 0x627,
-0x64a, 0x648, 0x3b, 0x64a, 0x648, 0x646, 0x64a, 0x648, 0x3b, 0x64a, 0x648, 0x644, 0x64a, 0x648, 0x3b, 0x623, 0x63a, 0x634, 0x62a, 0x3b,
-0x634, 0x62a, 0x645, 0x628, 0x631, 0x3b, 0x623, 0x643, 0x62a, 0x648, 0x628, 0x631, 0x3b, 0x646, 0x648, 0x641, 0x645, 0x628, 0x631, 0x3b,
-0x62f, 0x62c, 0x645, 0x628, 0x631, 0x64a, 0x3b, 0x641, 0x3b, 0x645, 0x3b, 0x625, 0x3b, 0x648, 0x3b, 0x646, 0x3b, 0x644, 0x3b, 0x63a,
-0x3b, 0x634, 0x3b, 0x643, 0x3b, 0x628, 0x3b, 0x62f, 0x64a, 0x646, 0x627, 0x64a, 0x631, 0x3b, 0x641, 0x628, 0x631, 0x627, 0x64a, 0x631,
-0x3b, 0x645, 0x627, 0x631, 0x633, 0x3b, 0x623, 0x628, 0x631, 0x64a, 0x644, 0x3b, 0x645, 0x627, 0x64a, 0x3b, 0x64a, 0x648, 0x646, 0x64a,
-0x648, 0x3b, 0x64a, 0x648, 0x644, 0x64a, 0x648, 0x632, 0x3b, 0x63a, 0x634, 0x62a, 0x3b, 0x634, 0x62a, 0x646, 0x628, 0x631, 0x3b, 0x623,
-0x643, 0x62a, 0x648, 0x628, 0x631, 0x3b, 0x646, 0x648, 0x646, 0x628, 0x631, 0x3b, 0x62f, 0x62c, 0x646, 0x628, 0x631, 0x64a, 0x3b, 0x641,
-0x3b, 0x645, 0x3b, 0x623, 0x3b, 0x645, 0x3b, 0x646, 0x3b, 0x644, 0x3b, 0x63a, 0x3b, 0x634, 0x3b, 0x643, 0x3b, 0x628, 0x3b, 0x62f,
-0x570, 0x578, 0x582, 0x576, 0x57e, 0x561, 0x580, 0x3b, 0x583, 0x565, 0x57f, 0x580, 0x57e, 0x561, 0x580, 0x3b, 0x574, 0x561, 0x580, 0x57f,
-0x3b, 0x561, 0x57a, 0x580, 0x56b, 0x56c, 0x3b, 0x574, 0x561, 0x575, 0x56b, 0x57d, 0x3b, 0x570, 0x578, 0x582, 0x576, 0x56b, 0x57d, 0x3b,
-0x570, 0x578, 0x582, 0x56c, 0x56b, 0x57d, 0x3b, 0x585, 0x563, 0x578, 0x57d, 0x57f, 0x578, 0x57d, 0x3b, 0x57d, 0x565, 0x57a, 0x57f, 0x565,
-0x574, 0x562, 0x565, 0x580, 0x3b, 0x570, 0x578, 0x56f, 0x57f, 0x565, 0x574, 0x562, 0x565, 0x580, 0x3b, 0x576, 0x578, 0x575, 0x565, 0x574,
-0x562, 0x565, 0x580, 0x3b, 0x564, 0x565, 0x56f, 0x57f, 0x565, 0x574, 0x562, 0x565, 0x580, 0x570, 0x578, 0x582, 0x576, 0x57e, 0x561, 0x580,
-0x56b, 0x3b, 0x583, 0x565, 0x57f, 0x580, 0x57e, 0x561, 0x580, 0x56b, 0x3b, 0x574, 0x561, 0x580, 0x57f, 0x56b, 0x3b, 0x561, 0x57a, 0x580,
-0x56b, 0x56c, 0x56b, 0x3b, 0x574, 0x561, 0x575, 0x56b, 0x57d, 0x56b, 0x3b, 0x570, 0x578, 0x582, 0x576, 0x56b, 0x57d, 0x56b, 0x3b, 0x570,
-0x578, 0x582, 0x56c, 0x56b, 0x57d, 0x56b, 0x3b, 0x585, 0x563, 0x578, 0x57d, 0x57f, 0x578, 0x57d, 0x56b, 0x3b, 0x57d, 0x565, 0x57a, 0x57f,
-0x565, 0x574, 0x562, 0x565, 0x580, 0x56b, 0x3b, 0x570, 0x578, 0x56f, 0x57f, 0x565, 0x574, 0x562, 0x565, 0x580, 0x56b, 0x3b, 0x576, 0x578,
-0x575, 0x565, 0x574, 0x562, 0x565, 0x580, 0x56b, 0x3b, 0x564, 0x565, 0x56f, 0x57f, 0x565, 0x574, 0x562, 0x565, 0x580, 0x56b, 0x570, 0x576,
-0x57e, 0x3b, 0x583, 0x57f, 0x57e, 0x3b, 0x574, 0x580, 0x57f, 0x3b, 0x561, 0x57a, 0x580, 0x3b, 0x574, 0x575, 0x57d, 0x3b, 0x570, 0x576,
-0x57d, 0x3b, 0x570, 0x56c, 0x57d, 0x3b, 0x585, 0x563, 0x57d, 0x3b, 0x57d, 0x565, 0x57a, 0x3b, 0x570, 0x578, 0x56f, 0x3b, 0x576, 0x578,
-0x575, 0x3b, 0x564, 0x565, 0x56f, 0x540, 0x3b, 0x553, 0x3b, 0x544, 0x3b, 0x531, 0x3b, 0x544, 0x3b, 0x540, 0x3b, 0x540, 0x3b, 0x555,
-0x3b, 0x54d, 0x3b, 0x540, 0x3b, 0x546, 0x3b, 0x534, 0x99c, 0x9be, 0x9a8, 0x9c1, 0x9f1, 0x9be, 0x9f0, 0x9c0, 0x3b, 0x9ab, 0x9c7, 0x9ac,
-0x9cd, 0x9f0, 0x9c1, 0x9f1, 0x9be, 0x9f0, 0x9c0, 0x3b, 0x9ae, 0x9be, 0x9f0, 0x9cd, 0x99a, 0x3b, 0x98f, 0x9aa, 0x9cd, 0x9f0, 0x9bf, 0x9b2,
-0x3b, 0x9ae, 0x9c7, 0x2019, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b, 0x99c, 0x9c1, 0x9b2, 0x9be, 0x987, 0x3b, 0x986, 0x997, 0x9b7, 0x9cd, 0x99f,
-0x3b, 0x99b, 0x9c7, 0x9aa, 0x9cd, 0x9a4, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9f0, 0x3b, 0x985, 0x995, 0x9cd, 0x99f, 0x9cb, 0x9ac, 0x9f0, 0x3b,
-0x9a8, 0x9f1, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9f0, 0x3b, 0x9a1, 0x9bf, 0x99a, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9f0, 0x99c, 0x9be, 0x9a8, 0x9c1,
-0x3b, 0x9ab, 0x9c7, 0x9ac, 0x9cd, 0x9f0, 0x9c1, 0x3b, 0x9ae, 0x9be, 0x9f0, 0x9cd, 0x99a, 0x3b, 0x98f, 0x9aa, 0x9cd, 0x9f0, 0x9bf, 0x9b2,
-0x3b, 0x9ae, 0x9c7, 0x2019, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b, 0x99c, 0x9c1, 0x9b2, 0x9be, 0x987, 0x3b, 0x986, 0x997, 0x3b, 0x99b, 0x9c7,
-0x9aa, 0x9cd, 0x9a4, 0x9c7, 0x3b, 0x985, 0x995, 0x9cd, 0x99f, 0x9cb, 0x3b, 0x9a8, 0x9f1, 0x9c7, 0x3b, 0x9a1, 0x9bf, 0x99a, 0x9c7, 0x99c,
-0x3b, 0x9ab, 0x3b, 0x9ae, 0x3b, 0x98f, 0x3b, 0x9ae, 0x3b, 0x99c, 0x3b, 0x99c, 0x3b, 0x986, 0x3b, 0x99b, 0x3b, 0x985, 0x3b, 0x9a8,
-0x3b, 0x9a1, 0x78, 0x69, 0x6e, 0x65, 0x72, 0x75, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x65, 0x72, 0x75, 0x3b, 0x6d, 0x61, 0x72,
-0x7a, 0x75, 0x3b, 0x61, 0x62, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x61, 0x79, 0x75, 0x3b, 0x78, 0x75, 0x6e, 0x75, 0x3b, 0x78,
-0x75, 0x6e, 0x65, 0x74, 0x75, 0x3b, 0x61, 0x67, 0x6f, 0x73, 0x74, 0x75, 0x3b, 0x73, 0x65, 0x74, 0x69, 0x65, 0x6d, 0x62,
-0x72, 0x65, 0x3b, 0x6f, 0x63, 0x68, 0x6f, 0x62, 0x72, 0x65, 0x3b, 0x70, 0x61, 0x79, 0x61, 0x72, 0x65, 0x73, 0x3b, 0x61,
-0x76, 0x69, 0x65, 0x6e, 0x74, 0x75, 0x64, 0x65, 0x20, 0x78, 0x69, 0x6e, 0x65, 0x72, 0x75, 0x3b, 0x64, 0x65, 0x20, 0x66,
-0x65, 0x62, 0x72, 0x65, 0x72, 0x75, 0x3b, 0x64, 0x65, 0x20, 0x6d, 0x61, 0x72, 0x7a, 0x75, 0x3b, 0x64, 0x2019, 0x61, 0x62,
-0x72, 0x69, 0x6c, 0x3b, 0x64, 0x65, 0x20, 0x6d, 0x61, 0x79, 0x75, 0x3b, 0x64, 0x65, 0x20, 0x78, 0x75, 0x6e, 0x75, 0x3b,
-0x64, 0x65, 0x20, 0x78, 0x75, 0x6e, 0x65, 0x74, 0x75, 0x3b, 0x64, 0x2019, 0x61, 0x67, 0x6f, 0x73, 0x74, 0x75, 0x3b, 0x64,
-0x65, 0x20, 0x73, 0x65, 0x74, 0x69, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x2019, 0x6f, 0x63, 0x68, 0x6f, 0x62, 0x72,
-0x65, 0x3b, 0x64, 0x65, 0x20, 0x70, 0x61, 0x79, 0x61, 0x72, 0x65, 0x73, 0x3b, 0x64, 0x2019, 0x61, 0x76, 0x69, 0x65, 0x6e,
-0x74, 0x75, 0x58, 0x69, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x62, 0x72, 0x3b, 0x4d, 0x61,
-0x79, 0x3b, 0x58, 0x75, 0x6e, 0x3b, 0x58, 0x6e, 0x74, 0x3b, 0x41, 0x67, 0x6f, 0x3b, 0x53, 0x65, 0x74, 0x3b, 0x4f, 0x63,
-0x68, 0x3b, 0x50, 0x61, 0x79, 0x3b, 0x41, 0x76, 0x69, 0x78, 0x69, 0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0x61, 0x72,
-0x3b, 0x61, 0x62, 0x72, 0x3b, 0x6d, 0x61, 0x79, 0x3b, 0x78, 0x75, 0x6e, 0x3b, 0x78, 0x6e, 0x74, 0x3b, 0x61, 0x67, 0x6f,
-0x3b, 0x73, 0x65, 0x74, 0x3b, 0x6f, 0x63, 0x68, 0x3b, 0x70, 0x61, 0x79, 0x3b, 0x61, 0x76, 0x69, 0x58, 0x3b, 0x46, 0x3b,
-0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x58, 0x3b, 0x58, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x50, 0x3b, 0x41, 0x4a,
-0x61, 0x6e, 0x75, 0x61, 0x72, 0x69, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x69, 0x3b, 0x4d, 0x61, 0x63, 0x68,
-0x69, 0x3b, 0x41, 0x70, 0x72, 0x69, 0x6c, 0x69, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75,
-0x6c, 0x61, 0x69, 0x3b, 0x41, 0x67, 0x6f, 0x73, 0x74, 0x69, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x61, 0x3b,
-0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x61, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x44, 0x65, 0x73, 0x65, 0x6d,
-0x62, 0x61, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x63, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x65,
-0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x6f, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b,
-0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x63, 0x79, 0x61, 0x6e, 0x76, 0x61, 0x72, 0x3b, 0x66, 0x65, 0x76, 0x72,
-0x61, 0x6c, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x3b, 0x61, 0x70, 0x72, 0x65, 0x6c, 0x3b, 0x6d, 0x61, 0x79, 0x3b, 0x69, 0x79,
-0x75, 0x6e, 0x3b, 0x69, 0x79, 0x75, 0x6c, 0x3b, 0x61, 0x76, 0x71, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x6e, 0x74, 0x79,
-0x61, 0x62, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x79, 0x61, 0x62, 0x72, 0x3b, 0x6e, 0x6f, 0x79, 0x61, 0x62, 0x72, 0x3b, 0x64,
-0x65, 0x6b, 0x61, 0x62, 0x72, 0x79, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x76, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x61, 0x70, 0x72,
-0x3b, 0x6d, 0x61, 0x79, 0x3b, 0x69, 0x79, 0x6e, 0x3b, 0x69, 0x79, 0x6c, 0x3b, 0x61, 0x76, 0x71, 0x3b, 0x73, 0x65, 0x6e,
-0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x79, 0x3b, 0x64, 0x65, 0x6b, 0x408, 0x430, 0x43d, 0x432, 0x430, 0x440, 0x3b, 0x424,
-0x435, 0x432, 0x440, 0x430, 0x43b, 0x3b, 0x41c, 0x430, 0x440, 0x442, 0x3b, 0x410, 0x43f, 0x440, 0x435, 0x43b, 0x3b, 0x41c, 0x430, 0x439,
-0x3b, 0x418, 0x458, 0x443, 0x43d, 0x3b, 0x418, 0x458, 0x443, 0x43b, 0x3b, 0x410, 0x432, 0x433, 0x443, 0x441, 0x442, 0x3b, 0x421, 0x435,
-0x43d, 0x442, 0x458, 0x430, 0x431, 0x440, 0x3b, 0x41e, 0x43a, 0x442, 0x458, 0x430, 0x431, 0x440, 0x3b, 0x41d, 0x43e, 0x458, 0x430, 0x431,
-0x440, 0x3b, 0x414, 0x435, 0x43a, 0x430, 0x431, 0x440, 0x458, 0x430, 0x43d, 0x432, 0x430, 0x440, 0x3b, 0x444, 0x435, 0x432, 0x440, 0x430,
-0x43b, 0x3b, 0x43c, 0x430, 0x440, 0x442, 0x3b, 0x430, 0x43f, 0x440, 0x435, 0x43b, 0x3b, 0x43c, 0x430, 0x439, 0x3b, 0x438, 0x458, 0x443,
-0x43d, 0x3b, 0x438, 0x458, 0x443, 0x43b, 0x3b, 0x430, 0x432, 0x433, 0x443, 0x441, 0x442, 0x3b, 0x441, 0x435, 0x43d, 0x442, 0x458, 0x430,
-0x431, 0x440, 0x3b, 0x43e, 0x43a, 0x442, 0x458, 0x430, 0x431, 0x440, 0x3b, 0x43d, 0x43e, 0x458, 0x430, 0x431, 0x440, 0x3b, 0x434, 0x435,
-0x43a, 0x430, 0x431, 0x440, 0x458, 0x430, 0x43d, 0x3b, 0x444, 0x435, 0x432, 0x3b, 0x43c, 0x430, 0x440, 0x3b, 0x430, 0x43f, 0x440, 0x3b,
-0x43c, 0x430, 0x439, 0x3b, 0x438, 0x458, 0x43d, 0x3b, 0x438, 0x458, 0x43b, 0x3b, 0x430, 0x432, 0x433, 0x3b, 0x441, 0x435, 0x43d, 0x3b,
-0x43e, 0x43a, 0x442, 0x3b, 0x43d, 0x43e, 0x458, 0x3b, 0x434, 0x435, 0x43a, 0x14b, 0x77, 0xed, 0xed, 0x20, 0x61, 0x20, 0x6e, 0x74,
-0x254, 0x301, 0x6e, 0x74, 0x254, 0x3b, 0x14b, 0x77, 0xed, 0xed, 0x20, 0x61, 0x6b, 0x1dd, 0x20, 0x62, 0x25b, 0x301, 0x25b, 0x3b,
-0x14b, 0x77, 0xed, 0xed, 0x20, 0x61, 0x6b, 0x1dd, 0x20, 0x72, 0xe1, 0xe1, 0x3b, 0x14b, 0x77, 0xed, 0xed, 0x20, 0x61, 0x6b,
-0x1dd, 0x20, 0x6e, 0x69, 0x6e, 0x3b, 0x14b, 0x77, 0xed, 0xed, 0x20, 0x61, 0x6b, 0x1dd, 0x20, 0x74, 0xe1, 0x61, 0x6e, 0x3b,
-0x14b, 0x77, 0xed, 0xed, 0x20, 0x61, 0x6b, 0x1dd, 0x20, 0x74, 0xe1, 0x61, 0x66, 0x254, 0x6b, 0x3b, 0x14b, 0x77, 0xed, 0xed,
-0x20, 0x61, 0x6b, 0x1dd, 0x20, 0x74, 0xe1, 0x61, 0x62, 0x25b, 0x25b, 0x3b, 0x14b, 0x77, 0xed, 0xed, 0x20, 0x61, 0x6b, 0x1dd,
-0x20, 0x74, 0xe1, 0x61, 0x72, 0x61, 0x61, 0x3b, 0x14b, 0x77, 0xed, 0xed, 0x20, 0x61, 0x6b, 0x1dd, 0x20, 0x74, 0xe1, 0x61,
-0x6e, 0x69, 0x6e, 0x3b, 0x14b, 0x77, 0xed, 0xed, 0x20, 0x61, 0x6b, 0x1dd, 0x20, 0x6e, 0x74, 0x25b, 0x6b, 0x3b, 0x14b, 0x77,
-0xed, 0xed, 0x20, 0x61, 0x6b, 0x1dd, 0x20, 0x6e, 0x74, 0x25b, 0x6b, 0x20, 0x64, 0x69, 0x20, 0x62, 0x254, 0x301, 0x6b, 0x3b,
-0x14b, 0x77, 0xed, 0xed, 0x20, 0x61, 0x6b, 0x1dd, 0x20, 0x6e, 0x74, 0x25b, 0x6b, 0x20, 0x64, 0x69, 0x20, 0x62, 0x25b, 0x301,
-0x25b, 0x14b, 0x31, 0x3b, 0x14b, 0x32, 0x3b, 0x14b, 0x33, 0x3b, 0x14b, 0x34, 0x3b, 0x14b, 0x35, 0x3b, 0x14b, 0x36, 0x3b, 0x14b,
-0x37, 0x3b, 0x14b, 0x38, 0x3b, 0x14b, 0x39, 0x3b, 0x14b, 0x31, 0x30, 0x3b, 0x14b, 0x31, 0x31, 0x3b, 0x14b, 0x31, 0x32, 0x7a,
-0x61, 0x6e, 0x77, 0x75, 0x79, 0x65, 0x3b, 0x66, 0x65, 0x62, 0x75, 0x72, 0x75, 0x79, 0x65, 0x3b, 0x6d, 0x61, 0x72, 0x69,
-0x73, 0x69, 0x3b, 0x61, 0x77, 0x69, 0x72, 0x69, 0x6c, 0x69, 0x3b, 0x6d, 0x25b, 0x3b, 0x7a, 0x75, 0x77, 0x25b, 0x6e, 0x3b,
-0x7a, 0x75, 0x6c, 0x75, 0x79, 0x65, 0x3b, 0x75, 0x74, 0x69, 0x3b, 0x73, 0x25b, 0x74, 0x61, 0x6e, 0x62, 0x75, 0x72, 0x75,
-0x3b, 0x254, 0x6b, 0x75, 0x74, 0x254, 0x62, 0x75, 0x72, 0x75, 0x3b, 0x6e, 0x6f, 0x77, 0x61, 0x6e, 0x62, 0x75, 0x72, 0x75,
-0x3b, 0x64, 0x65, 0x73, 0x61, 0x6e, 0x62, 0x75, 0x72, 0x75, 0x7a, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0x61,
-0x72, 0x3b, 0x61, 0x77, 0x69, 0x3b, 0x6d, 0x25b, 0x3b, 0x7a, 0x75, 0x77, 0x3b, 0x7a, 0x75, 0x6c, 0x3b, 0x75, 0x74, 0x69,
-0x3b, 0x73, 0x25b, 0x74, 0x3b, 0x254, 0x6b, 0x75, 0x3b, 0x6e, 0x6f, 0x77, 0x3b, 0x64, 0x65, 0x73, 0x5a, 0x3b, 0x46, 0x3b,
-0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x5a, 0x3b, 0x5a, 0x3b, 0x55, 0x3b, 0x53, 0x3b, 0x186, 0x3b, 0x4e, 0x3b, 0x44, 0x99c,
-0x9be, 0x9a8, 0x9c1, 0x9af, 0x9bc, 0x9be, 0x9b0, 0x9c0, 0x3b, 0x9ab, 0x9c7, 0x9ac, 0x9cd, 0x9b0, 0x9c1, 0x9af, 0x9bc, 0x9be, 0x9b0, 0x9c0,
-0x3b, 0x9ae, 0x9be, 0x9b0, 0x9cd, 0x99a, 0x3b, 0x98f, 0x9aa, 0x9cd, 0x9b0, 0x9bf, 0x9b2, 0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1, 0x9a8,
-0x3b, 0x99c, 0x9c1, 0x9b2, 0x9be, 0x987, 0x3b, 0x986, 0x997, 0x9b8, 0x9cd, 0x99f, 0x3b, 0x9b8, 0x9c7, 0x9aa, 0x9cd, 0x99f, 0x9c7, 0x9ae,
-0x9cd, 0x9ac, 0x9b0, 0x3b, 0x985, 0x995, 0x9cd, 0x99f, 0x9cb, 0x9ac, 0x9b0, 0x3b, 0x9a8, 0x9ad, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9b0, 0x3b,
-0x9a1, 0x9bf, 0x9b8, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9b0, 0x99c, 0x9be, 0x9a8, 0x9c1, 0x3b, 0x9ab, 0x9c7, 0x9ac, 0x3b, 0x9ae, 0x9be, 0x9b0,
-0x9cd, 0x99a, 0x3b, 0x98f, 0x9aa, 0x9cd, 0x9b0, 0x9bf, 0x9b2, 0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b, 0x99c, 0x9c1, 0x9b2,
-0x9be, 0x987, 0x3b, 0x986, 0x997, 0x9b8, 0x9cd, 0x99f, 0x3b, 0x9b8, 0x9c7, 0x9aa, 0x9cd, 0x99f, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9b0, 0x3b,
-0x985, 0x995, 0x9cd, 0x99f, 0x9cb, 0x9ac, 0x9b0, 0x3b, 0x9a8, 0x9ad, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9b0, 0x3b, 0x9a1, 0x9bf, 0x9b8, 0x9c7,
-0x9ae, 0x9cd, 0x9ac, 0x9b0, 0x99c, 0x9be, 0x9a8, 0x9c1, 0x3b, 0x9ab, 0x9c7, 0x9ac, 0x3b, 0x9ae, 0x9be, 0x9b0, 0x9cd, 0x99a, 0x3b, 0x98f,
-0x9aa, 0x9cd, 0x9b0, 0x9bf, 0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b, 0x99c, 0x9c1, 0x9b2, 0x3b, 0x986, 0x997, 0x3b, 0x9b8,
-0x9c7, 0x9aa, 0x3b, 0x985, 0x995, 0x9cd, 0x99f, 0x9cb, 0x3b, 0x9a8, 0x9ad, 0x9c7, 0x3b, 0x9a1, 0x9bf, 0x9b8, 0x9c7, 0x99c, 0x9be, 0x3b,
-0x9ab, 0x9c7, 0x3b, 0x9ae, 0x9be, 0x3b, 0x98f, 0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b, 0x99c, 0x9c1, 0x3b, 0x986, 0x3b,
-0x9b8, 0x9c7, 0x3b, 0x985, 0x3b, 0x9a8, 0x3b, 0x9a1, 0x9bf, 0x99c, 0x9be, 0x9a8, 0x9c1, 0x3b, 0x9ab, 0x9c7, 0x9ac, 0x3b, 0x9ae, 0x9be,
-0x9b0, 0x9cd, 0x99a, 0x3b, 0x98f, 0x9aa, 0x9cd, 0x9b0, 0x9bf, 0x9b2, 0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b, 0x99c, 0x9c1,
-0x9b2, 0x9be, 0x987, 0x3b, 0x986, 0x997, 0x9b8, 0x9cd, 0x99f, 0x3b, 0x9b8, 0x9c7, 0x9aa, 0x9cd, 0x99f, 0x9c7, 0x983, 0x3b, 0x985, 0x995,
-0x9cd, 0x99f, 0x9cb, 0x983, 0x3b, 0x9a8, 0x9ad, 0x9c7, 0x983, 0x3b, 0x9a1, 0x9bf, 0x9b8, 0x9c7, 0x983, 0x99c, 0x9be, 0x9a8, 0x9c1, 0x3b,
-0x9ab, 0x9c7, 0x9ac, 0x3b, 0x9ae, 0x9be, 0x9b0, 0x9cd, 0x99a, 0x3b, 0x98f, 0x9aa, 0x9cd, 0x9b0, 0x9bf, 0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c,
-0x9c1, 0x9a8, 0x3b, 0x99c, 0x9c1, 0x9b2, 0x3b, 0x986, 0x997, 0x3b, 0x9b8, 0x9c7, 0x9aa, 0x9cd, 0x99f, 0x9c7, 0x983, 0x3b, 0x985, 0x995,
-0x9cd, 0x99f, 0x9cb, 0x983, 0x3b, 0x9a8, 0x9ad, 0x9c7, 0x983, 0x3b, 0x9a1, 0x9bf, 0x9b8, 0x9c7, 0x983, 0x99c, 0x9be, 0x3b, 0x9ab, 0x9c7,
-0x3b, 0x9ae, 0x9be, 0x3b, 0x98f, 0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b, 0x99c, 0x9c1, 0x9b2, 0x3b, 0x986, 0x3b, 0x9b8,
-0x9c7, 0x3b, 0x985, 0x3b, 0x9a8, 0x3b, 0x9a1, 0x9bf, 0x4b, 0x254, 0x6e, 0x64, 0x254, 0x14b, 0x3b, 0x4d, 0xe0, 0x63, 0x25b, 0x302,
-0x6c, 0x3b, 0x4d, 0xe0, 0x74, 0xf9, 0x6d, 0x62, 0x3b, 0x4d, 0xe0, 0x74, 0x6f, 0x70, 0x3b, 0x4d, 0x300, 0x70, 0x75, 0x79,
-0x25b, 0x3b, 0x48, 0xec, 0x6c, 0xf2, 0x6e, 0x64, 0x25b, 0x300, 0x3b, 0x4e, 0x6a, 0xe8, 0x62, 0xe0, 0x3b, 0x48, 0xec, 0x6b,
-0x61, 0x14b, 0x3b, 0x44, 0xec, 0x70, 0x254, 0x300, 0x73, 0x3b, 0x42, 0xec, 0xf2, 0xf4, 0x6d, 0x3b, 0x4d, 0xe0, 0x79, 0x25b,
-0x73, 0xe8, 0x70, 0x3b, 0x4c, 0xec, 0x62, 0x75, 0x79, 0x20, 0x6c, 0x69, 0x20, 0x144, 0x79, 0xe8, 0x65, 0x6b, 0x254, 0x6e,
-0x3b, 0x6d, 0x61, 0x63, 0x3b, 0x6d, 0x61, 0x74, 0x3b, 0x6d, 0x74, 0x6f, 0x3b, 0x6d, 0x70, 0x75, 0x3b, 0x68, 0x69, 0x6c,
-0x3b, 0x6e, 0x6a, 0x65, 0x3b, 0x68, 0x69, 0x6b, 0x3b, 0x64, 0x69, 0x70, 0x3b, 0x62, 0x69, 0x6f, 0x3b, 0x6d, 0x61, 0x79,
-0x3b, 0x6c, 0x69, 0x253, 0x6b, 0x3b, 0x6d, 0x3b, 0x6d, 0x3b, 0x6d, 0x3b, 0x6d, 0x3b, 0x68, 0x3b, 0x6e, 0x3b, 0x68, 0x3b,
-0x64, 0x3b, 0x62, 0x3b, 0x6d, 0x3b, 0x6c, 0x75, 0x72, 0x74, 0x61, 0x72, 0x72, 0x69, 0x6c, 0x61, 0x3b, 0x6f, 0x74, 0x73,
-0x61, 0x69, 0x6c, 0x61, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x78, 0x6f, 0x61, 0x3b, 0x61, 0x70, 0x69, 0x72, 0x69, 0x6c, 0x61,
-0x3b, 0x6d, 0x61, 0x69, 0x61, 0x74, 0x7a, 0x61, 0x3b, 0x65, 0x6b, 0x61, 0x69, 0x6e, 0x61, 0x3b, 0x75, 0x7a, 0x74, 0x61,
-0x69, 0x6c, 0x61, 0x3b, 0x61, 0x62, 0x75, 0x7a, 0x74, 0x75, 0x61, 0x3b, 0x69, 0x72, 0x61, 0x69, 0x6c, 0x61, 0x3b, 0x75,
-0x72, 0x72, 0x69, 0x61, 0x3b, 0x61, 0x7a, 0x61, 0x72, 0x6f, 0x61, 0x3b, 0x61, 0x62, 0x65, 0x6e, 0x64, 0x75, 0x61, 0x75,
-0x72, 0x74, 0x2e, 0x3b, 0x6f, 0x74, 0x73, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x61, 0x70, 0x69, 0x2e, 0x3b, 0x6d,
-0x61, 0x69, 0x2e, 0x3b, 0x65, 0x6b, 0x61, 0x2e, 0x3b, 0x75, 0x7a, 0x74, 0x2e, 0x3b, 0x61, 0x62, 0x75, 0x2e, 0x3b, 0x69,
-0x72, 0x61, 0x2e, 0x3b, 0x75, 0x72, 0x72, 0x2e, 0x3b, 0x61, 0x7a, 0x61, 0x2e, 0x3b, 0x61, 0x62, 0x65, 0x2e, 0x55, 0x3b,
-0x4f, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x45, 0x3b, 0x55, 0x3b, 0x41, 0x3b, 0x49, 0x3b, 0x55, 0x3b, 0x41, 0x3b,
-0x41, 0x441, 0x442, 0x443, 0x434, 0x437, 0x435, 0x43d, 0x44c, 0x3b, 0x43b, 0x44e, 0x442, 0x44b, 0x3b, 0x441, 0x430, 0x43a, 0x430, 0x432,
-0x456, 0x43a, 0x3b, 0x43a, 0x440, 0x430, 0x441, 0x430, 0x432, 0x456, 0x43a, 0x3b, 0x43c, 0x430, 0x439, 0x3b, 0x447, 0x44d, 0x440, 0x432,
-0x435, 0x43d, 0x44c, 0x3b, 0x43b, 0x456, 0x43f, 0x435, 0x43d, 0x44c, 0x3b, 0x436, 0x43d, 0x456, 0x432, 0x435, 0x43d, 0x44c, 0x3b, 0x432,
-0x435, 0x440, 0x430, 0x441, 0x435, 0x43d, 0x44c, 0x3b, 0x43a, 0x430, 0x441, 0x442, 0x440, 0x44b, 0x447, 0x43d, 0x456, 0x43a, 0x3b, 0x43b,
-0x456, 0x441, 0x442, 0x430, 0x43f, 0x430, 0x434, 0x3b, 0x441, 0x43d, 0x435, 0x436, 0x430, 0x43d, 0x44c, 0x441, 0x442, 0x443, 0x434, 0x437,
-0x435, 0x43d, 0x44f, 0x3b, 0x43b, 0x44e, 0x442, 0x430, 0x433, 0x430, 0x3b, 0x441, 0x430, 0x43a, 0x430, 0x432, 0x456, 0x43a, 0x430, 0x3b,
-0x43a, 0x440, 0x430, 0x441, 0x430, 0x432, 0x456, 0x43a, 0x430, 0x3b, 0x43c, 0x430, 0x44f, 0x3b, 0x447, 0x44d, 0x440, 0x432, 0x435, 0x43d,
-0x44f, 0x3b, 0x43b, 0x456, 0x43f, 0x435, 0x43d, 0x44f, 0x3b, 0x436, 0x43d, 0x456, 0x45e, 0x43d, 0x44f, 0x3b, 0x432, 0x435, 0x440, 0x430,
-0x441, 0x43d, 0x44f, 0x3b, 0x43a, 0x430, 0x441, 0x442, 0x440, 0x44b, 0x447, 0x43d, 0x456, 0x43a, 0x430, 0x3b, 0x43b, 0x456, 0x441, 0x442,
-0x430, 0x43f, 0x430, 0x434, 0x430, 0x3b, 0x441, 0x43d, 0x435, 0x436, 0x43d, 0x44f, 0x441, 0x442, 0x443, 0x3b, 0x43b, 0x44e, 0x442, 0x3b,
-0x441, 0x430, 0x43a, 0x3b, 0x43a, 0x440, 0x430, 0x3b, 0x43c, 0x430, 0x439, 0x3b, 0x447, 0x44d, 0x440, 0x3b, 0x43b, 0x456, 0x43f, 0x3b,
-0x436, 0x43d, 0x456, 0x3b, 0x432, 0x435, 0x440, 0x3b, 0x43a, 0x430, 0x441, 0x3b, 0x43b, 0x456, 0x441, 0x3b, 0x441, 0x43d, 0x435, 0x441,
-0x442, 0x443, 0x3b, 0x43b, 0x44e, 0x442, 0x3b, 0x441, 0x430, 0x43a, 0x3b, 0x43a, 0x440, 0x430, 0x3b, 0x43c, 0x430, 0x44f, 0x3b, 0x447,
-0x44d, 0x440, 0x3b, 0x43b, 0x456, 0x43f, 0x3b, 0x436, 0x43d, 0x456, 0x3b, 0x432, 0x435, 0x440, 0x3b, 0x43a, 0x430, 0x441, 0x3b, 0x43b,
-0x456, 0x441, 0x3b, 0x441, 0x43d, 0x435, 0x441, 0x3b, 0x43b, 0x3b, 0x441, 0x3b, 0x43a, 0x3b, 0x43c, 0x3b, 0x447, 0x3b, 0x43b, 0x3b,
-0x436, 0x3b, 0x432, 0x3b, 0x43a, 0x3b, 0x43b, 0x3b, 0x441, 0x4a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x69, 0x3b, 0x46, 0x65, 0x62,
-0x72, 0x75, 0x61, 0x72, 0x69, 0x3b, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x3b, 0x45, 0x70, 0x72, 0x65, 0x6f, 0x3b, 0x4d, 0x65,
-0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x61, 0x69, 0x3b, 0x4f, 0x67, 0x61, 0x73, 0x74, 0x69, 0x3b,
-0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x61, 0x3b, 0x4e, 0x6f, 0x76, 0x65,
-0x6d, 0x62, 0x61, 0x3b, 0x44, 0x69, 0x73, 0x65, 0x6d, 0x62, 0x61, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d,
-0x61, 0x63, 0x3b, 0x45, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x4f,
-0x67, 0x61, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x69, 0x73, 0x4a, 0x3b,
-0x46, 0x3b, 0x4d, 0x3b, 0x45, 0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x4f, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b,
-0x44, 0x70, 0x61, 0x20, 0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69, 0x20, 0x67, 0x77, 0x61, 0x20, 0x68, 0x75, 0x74, 0x61, 0x6c,
-0x61, 0x3b, 0x70, 0x61, 0x20, 0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69, 0x20, 0x67, 0x77, 0x61, 0x20, 0x77, 0x75, 0x76, 0x69,
-0x6c, 0x69, 0x3b, 0x70, 0x61, 0x20, 0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69, 0x20, 0x67, 0x77, 0x61, 0x20, 0x77, 0x75, 0x64,
-0x61, 0x74, 0x75, 0x3b, 0x70, 0x61, 0x20, 0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69, 0x20, 0x67, 0x77, 0x61, 0x20, 0x77, 0x75,
-0x74, 0x61, 0x69, 0x3b, 0x70, 0x61, 0x20, 0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69, 0x20, 0x67, 0x77, 0x61, 0x20, 0x77, 0x75,
-0x68, 0x61, 0x6e, 0x75, 0x3b, 0x70, 0x61, 0x20, 0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69, 0x20, 0x67, 0x77, 0x61, 0x20, 0x73,
-0x69, 0x74, 0x61, 0x3b, 0x70, 0x61, 0x20, 0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69, 0x20, 0x67, 0x77, 0x61, 0x20, 0x73, 0x61,
-0x62, 0x61, 0x3b, 0x70, 0x61, 0x20, 0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69, 0x20, 0x67, 0x77, 0x61, 0x20, 0x6e, 0x61, 0x6e,
-0x65, 0x3b, 0x70, 0x61, 0x20, 0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69, 0x20, 0x67, 0x77, 0x61, 0x20, 0x74, 0x69, 0x73, 0x61,
-0x3b, 0x70, 0x61, 0x20, 0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69, 0x20, 0x67, 0x77, 0x61, 0x20, 0x6b, 0x75, 0x6d, 0x69, 0x3b,
-0x70, 0x61, 0x20, 0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69, 0x20, 0x67, 0x77, 0x61, 0x20, 0x6b, 0x75, 0x6d, 0x69, 0x20, 0x6e,
-0x61, 0x20, 0x6d, 0x6f, 0x6a, 0x61, 0x3b, 0x70, 0x61, 0x20, 0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69, 0x20, 0x67, 0x77, 0x61,
-0x20, 0x6b, 0x75, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x6d, 0x62, 0x69, 0x6c, 0x69, 0x48, 0x75, 0x74, 0x3b, 0x56, 0x69,
-0x6c, 0x3b, 0x44, 0x61, 0x74, 0x3b, 0x54, 0x61, 0x69, 0x3b, 0x48, 0x61, 0x6e, 0x3b, 0x53, 0x69, 0x74, 0x3b, 0x53, 0x61,
-0x62, 0x3b, 0x4e, 0x61, 0x6e, 0x3b, 0x54, 0x69, 0x73, 0x3b, 0x4b, 0x75, 0x6d, 0x3b, 0x4b, 0x6d, 0x6a, 0x3b, 0x4b, 0x6d,
-0x62, 0x48, 0x3b, 0x56, 0x3b, 0x44, 0x3b, 0x54, 0x3b, 0x48, 0x3b, 0x53, 0x3b, 0x53, 0x3b, 0x4e, 0x3b, 0x54, 0x3b, 0x4b,
-0x3b, 0x4b, 0x3b, 0x4b, 0x91c, 0x928, 0x935, 0x930, 0x940, 0x3b, 0x92b, 0x930, 0x935, 0x930, 0x940, 0x3b, 0x92e, 0x93e, 0x930, 0x94d,
-0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x948, 0x932, 0x3b, 0x92e, 0x908, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x93e,
-0x908, 0x3b, 0x905, 0x917, 0x938, 0x94d, 0x924, 0x3b, 0x938, 0x93f, 0x924, 0x92e, 0x94d, 0x92c, 0x930, 0x3b, 0x905, 0x915, 0x94d, 0x91f,
-0x942, 0x92c, 0x930, 0x3b, 0x928, 0x935, 0x902, 0x92c, 0x930, 0x3b, 0x926, 0x93f, 0x938, 0x902, 0x92c, 0x930, 0x91c, 0x93e, 0x928, 0x941,
-0x935, 0x93e, 0x930, 0x940, 0x3b, 0x92b, 0x947, 0x92c, 0x94d, 0x930, 0x942, 0x935, 0x93e, 0x930, 0x940, 0x3b, 0x92e, 0x93e, 0x930, 0x94d,
-0x91a, 0x3b, 0x90f, 0x92a, 0x94d, 0x930, 0x93f, 0x932, 0x3b, 0x92e, 0x947, 0x3b, 0x91c, 0x941, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x93e,
-0x908, 0x3b, 0x906, 0x917, 0x937, 0x94d, 0x91f, 0x3b, 0x938, 0x947, 0x92a, 0x94d, 0x925, 0x947, 0x92e, 0x94d, 0x92c, 0x930, 0x3b, 0x905,
-0x915, 0x94d, 0x91f, 0x2019, 0x92c, 0x930, 0x3b, 0x928, 0x935, 0x947, 0x92e, 0x94d, 0x92c, 0x930, 0x3b, 0x921, 0x93f, 0x938, 0x947, 0x92e,
-0x94d, 0x92c, 0x930, 0x91c, 0x93e, 0x928, 0x3b, 0x92b, 0x947, 0x92c, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x90f, 0x92a, 0x94d,
-0x930, 0x93f, 0x3b, 0x92e, 0x947, 0x3b, 0x91c, 0x941, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x3b, 0x906, 0x917, 0x3b, 0x938, 0x947, 0x92a,
-0x3b, 0x905, 0x915, 0x94d, 0x91f, 0x2019, 0x3b, 0x928, 0x935, 0x947, 0x3b, 0x921, 0x93f, 0x938, 0x947, 0x91c, 0x3b, 0x92b, 0x3b, 0x92e,
-0x3b, 0x90f, 0x3b, 0x92e, 0x3b, 0x91c, 0x3b, 0x91c, 0x3b, 0x906, 0x3b, 0x938, 0x3b, 0x905, 0x3b, 0x928, 0x3b, 0x921, 0x6a, 0x61,
-0x6e, 0x75, 0x61, 0x72, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x3b, 0x61, 0x70,
-0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x3b, 0x61, 0x75,
-0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62,
-0x61, 0x72, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x61, 0x72,
-0x6a, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0x61, 0x6a, 0x3b,
-0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x75, 0x67, 0x3b, 0x73, 0x65, 0x70, 0x3b, 0x6f, 0x6b, 0x74, 0x3b,
-0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65, 0x63, 0x6a, 0x3b, 0x66, 0x3b, 0x6d, 0x3b, 0x61, 0x3b, 0x6d, 0x3b, 0x6a, 0x3b, 0x6a,
-0x3b, 0x61, 0x3b, 0x73, 0x3b, 0x6f, 0x3b, 0x6e, 0x3b, 0x64, 0x458, 0x430, 0x43d, 0x443, 0x430, 0x440, 0x3b, 0x444, 0x435, 0x431,
-0x440, 0x443, 0x430, 0x440, 0x3b, 0x43c, 0x430, 0x440, 0x442, 0x3b, 0x430, 0x43f, 0x440, 0x438, 0x43b, 0x3b, 0x43c, 0x430, 0x458, 0x3b,
-0x458, 0x443, 0x43d, 0x438, 0x3b, 0x458, 0x443, 0x43b, 0x438, 0x3b, 0x430, 0x443, 0x433, 0x443, 0x441, 0x442, 0x3b, 0x441, 0x435, 0x43f,
-0x442, 0x435, 0x43c, 0x431, 0x430, 0x440, 0x3b, 0x43e, 0x43a, 0x442, 0x43e, 0x431, 0x430, 0x440, 0x3b, 0x43d, 0x43e, 0x432, 0x435, 0x43c,
-0x431, 0x430, 0x440, 0x3b, 0x434, 0x435, 0x446, 0x435, 0x43c, 0x431, 0x430, 0x440, 0x458, 0x430, 0x43d, 0x3b, 0x444, 0x435, 0x431, 0x3b,
-0x43c, 0x430, 0x440, 0x3b, 0x430, 0x43f, 0x440, 0x3b, 0x43c, 0x430, 0x458, 0x3b, 0x458, 0x443, 0x43d, 0x3b, 0x458, 0x443, 0x43b, 0x3b,
-0x430, 0x443, 0x433, 0x3b, 0x441, 0x435, 0x43f, 0x3b, 0x43e, 0x43a, 0x442, 0x3b, 0x43d, 0x43e, 0x432, 0x3b, 0x434, 0x435, 0x446, 0x458,
-0x3b, 0x444, 0x3b, 0x43c, 0x3b, 0x430, 0x3b, 0x43c, 0x3b, 0x458, 0x3b, 0x458, 0x3b, 0x430, 0x3b, 0x441, 0x3b, 0x43e, 0x3b, 0x43d,
-0x3b, 0x434, 0x47, 0x65, 0x6e, 0x76, 0x65, 0x72, 0x3b, 0x43, 0x2bc, 0x68, 0x77, 0x65, 0x76, 0x72, 0x65, 0x72, 0x3b, 0x4d,
-0x65, 0x75, 0x72, 0x7a, 0x68, 0x3b, 0x45, 0x62, 0x72, 0x65, 0x6c, 0x3b, 0x4d, 0x61, 0x65, 0x3b, 0x4d, 0x65, 0x7a, 0x68,
-0x65, 0x76, 0x65, 0x6e, 0x3b, 0x47, 0x6f, 0x75, 0x65, 0x72, 0x65, 0x3b, 0x45, 0x6f, 0x73, 0x74, 0x3b, 0x47, 0x77, 0x65,
-0x6e, 0x67, 0x6f, 0x6c, 0x6f, 0x3b, 0x48, 0x65, 0x72, 0x65, 0x3b, 0x44, 0x75, 0x3b, 0x4b, 0x65, 0x72, 0x7a, 0x75, 0x47,
-0x65, 0x6e, 0x2e, 0x3b, 0x43, 0x2bc, 0x68, 0x77, 0x65, 0x2e, 0x3b, 0x4d, 0x65, 0x75, 0x72, 0x2e, 0x3b, 0x45, 0x62, 0x72,
-0x2e, 0x3b, 0x4d, 0x61, 0x65, 0x3b, 0x4d, 0x65, 0x7a, 0x68, 0x2e, 0x3b, 0x47, 0x6f, 0x75, 0x65, 0x2e, 0x3b, 0x45, 0x6f,
-0x73, 0x74, 0x3b, 0x47, 0x77, 0x65, 0x6e, 0x2e, 0x3b, 0x48, 0x65, 0x72, 0x65, 0x3b, 0x44, 0x75, 0x3b, 0x4b, 0x7a, 0x75,
-0x2e, 0x30, 0x31, 0x3b, 0x30, 0x32, 0x3b, 0x30, 0x33, 0x3b, 0x30, 0x34, 0x3b, 0x30, 0x35, 0x3b, 0x30, 0x36, 0x3b, 0x30,
-0x37, 0x3b, 0x30, 0x38, 0x3b, 0x30, 0x39, 0x3b, 0x31, 0x30, 0x3b, 0x31, 0x31, 0x3b, 0x31, 0x32, 0x44f, 0x43d, 0x443, 0x430,
-0x440, 0x438, 0x3b, 0x444, 0x435, 0x432, 0x440, 0x443, 0x430, 0x440, 0x438, 0x3b, 0x43c, 0x430, 0x440, 0x442, 0x3b, 0x430, 0x43f, 0x440,
-0x438, 0x43b, 0x3b, 0x43c, 0x430, 0x439, 0x3b, 0x44e, 0x43d, 0x438, 0x3b, 0x44e, 0x43b, 0x438, 0x3b, 0x430, 0x432, 0x433, 0x443, 0x441,
-0x442, 0x3b, 0x441, 0x435, 0x43f, 0x442, 0x435, 0x43c, 0x432, 0x440, 0x438, 0x3b, 0x43e, 0x43a, 0x442, 0x43e, 0x43c, 0x432, 0x440, 0x438,
-0x3b, 0x43d, 0x43e, 0x435, 0x43c, 0x432, 0x440, 0x438, 0x3b, 0x434, 0x435, 0x43a, 0x435, 0x43c, 0x432, 0x440, 0x438, 0x44f, 0x43d, 0x443,
-0x3b, 0x444, 0x435, 0x432, 0x3b, 0x43c, 0x430, 0x440, 0x442, 0x3b, 0x430, 0x43f, 0x440, 0x3b, 0x43c, 0x430, 0x439, 0x3b, 0x44e, 0x43d,
-0x438, 0x3b, 0x44e, 0x43b, 0x438, 0x3b, 0x430, 0x432, 0x433, 0x3b, 0x441, 0x435, 0x43f, 0x3b, 0x43e, 0x43a, 0x442, 0x3b, 0x43d, 0x43e,
-0x435, 0x3b, 0x434, 0x435, 0x43a, 0x44f, 0x3b, 0x444, 0x3b, 0x43c, 0x3b, 0x430, 0x3b, 0x43c, 0x3b, 0x44e, 0x3b, 0x44e, 0x3b, 0x430,
-0x3b, 0x441, 0x3b, 0x43e, 0x3b, 0x43d, 0x3b, 0x434, 0x1007, 0x1014, 0x103a, 0x1014, 0x101d, 0x102b, 0x101b, 0x102e, 0x3b, 0x1016, 0x1031, 0x1016,
-0x1031, 0x102c, 0x103a, 0x101d, 0x102b, 0x101b, 0x102e, 0x3b, 0x1019, 0x1010, 0x103a, 0x3b, 0x1027, 0x1015, 0x103c, 0x102e, 0x3b, 0x1019, 0x1031, 0x3b,
-0x1007, 0x103d, 0x1014, 0x103a, 0x3b, 0x1007, 0x1030, 0x101c, 0x102d, 0x102f, 0x1004, 0x103a, 0x3b, 0x1029, 0x1002, 0x102f, 0x1010, 0x103a, 0x3b, 0x1005,
-0x1000, 0x103a, 0x1010, 0x1004, 0x103a, 0x1018, 0x102c, 0x3b, 0x1021, 0x1031, 0x102c, 0x1000, 0x103a, 0x1010, 0x102d, 0x102f, 0x1018, 0x102c, 0x3b, 0x1014,
-0x102d, 0x102f, 0x101d, 0x1004, 0x103a, 0x1018, 0x102c, 0x3b, 0x1012, 0x102e, 0x1007, 0x1004, 0x103a, 0x1018, 0x102c, 0x1007, 0x1014, 0x103a, 0x3b, 0x1016,
-0x1031, 0x3b, 0x1019, 0x1010, 0x103a, 0x3b, 0x1027, 0x3b, 0x1019, 0x1031, 0x3b, 0x1007, 0x103d, 0x1014, 0x103a, 0x3b, 0x1007, 0x1030, 0x3b, 0x1029,
-0x3b, 0x1005, 0x1000, 0x103a, 0x3b, 0x1021, 0x1031, 0x102c, 0x1000, 0x103a, 0x3b, 0x1014, 0x102d, 0x102f, 0x3b, 0x1012, 0x102e, 0x1007, 0x3b, 0x1016,
-0x3b, 0x1019, 0x3b, 0x1027, 0x3b, 0x1019, 0x3b, 0x1007, 0x3b, 0x1007, 0x3b, 0x1029, 0x3b, 0x1005, 0x3b, 0x1021, 0x3b, 0x1014, 0x3b, 0x1012,
-0x31, 0x6708, 0x3b, 0x32, 0x6708, 0x3b, 0x33, 0x6708, 0x3b, 0x34, 0x6708, 0x3b, 0x35, 0x6708, 0x3b, 0x36, 0x6708, 0x3b, 0x37, 0x6708,
-0x3b, 0x38, 0x6708, 0x3b, 0x39, 0x6708, 0x3b, 0x31, 0x30, 0x6708, 0x3b, 0x31, 0x31, 0x6708, 0x3b, 0x31, 0x32, 0x6708, 0x4e00, 0x6708,
-0x3b, 0x4e8c, 0x6708, 0x3b, 0x4e09, 0x6708, 0x3b, 0x56db, 0x6708, 0x3b, 0x4e94, 0x6708, 0x3b, 0x516d, 0x6708, 0x3b, 0x4e03, 0x6708, 0x3b, 0x516b,
-0x6708, 0x3b, 0x4e5d, 0x6708, 0x3b, 0x5341, 0x6708, 0x3b, 0x5341, 0x4e00, 0x6708, 0x3b, 0x5341, 0x4e8c, 0x6708, 0x67, 0x65, 0x6e, 0x65, 0x72,
-0x3b, 0x66, 0x65, 0x62, 0x72, 0x65, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0xe7, 0x3b, 0x61, 0x62, 0x72, 0x69, 0x6c, 0x3b, 0x6d,
-0x61, 0x69, 0x67, 0x3b, 0x6a, 0x75, 0x6e, 0x79, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x6f, 0x6c, 0x3b, 0x61, 0x67, 0x6f, 0x73,
-0x74, 0x3b, 0x73, 0x65, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x6f, 0x63, 0x74, 0x75, 0x62, 0x72, 0x65, 0x3b, 0x6e,
-0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x65, 0x73, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x64, 0x65, 0x20, 0x67,
-0x65, 0x6e, 0x65, 0x72, 0x3b, 0x64, 0x65, 0x20, 0x66, 0x65, 0x62, 0x72, 0x65, 0x72, 0x3b, 0x64, 0x65, 0x20, 0x6d, 0x61,
-0x72, 0xe7, 0x3b, 0x64, 0x2019, 0x61, 0x62, 0x72, 0x69, 0x6c, 0x3b, 0x64, 0x65, 0x20, 0x6d, 0x61, 0x69, 0x67, 0x3b, 0x64,
-0x65, 0x20, 0x6a, 0x75, 0x6e, 0x79, 0x3b, 0x64, 0x65, 0x20, 0x6a, 0x75, 0x6c, 0x69, 0x6f, 0x6c, 0x3b, 0x64, 0x2019, 0x61,
-0x67, 0x6f, 0x73, 0x74, 0x3b, 0x64, 0x65, 0x20, 0x73, 0x65, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x2019, 0x6f,
-0x63, 0x74, 0x75, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x65, 0x20, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64,
-0x65, 0x20, 0x64, 0x65, 0x73, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x67, 0x65, 0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x2e,
-0x3b, 0x6d, 0x61, 0x72, 0xe7, 0x3b, 0x61, 0x62, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x69, 0x67, 0x3b, 0x6a, 0x75, 0x6e, 0x79,
-0x3b, 0x6a, 0x75, 0x6c, 0x2e, 0x3b, 0x61, 0x67, 0x2e, 0x3b, 0x73, 0x65, 0x74, 0x2e, 0x3b, 0x6f, 0x63, 0x74, 0x2e, 0x3b,
-0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x73, 0x2e, 0x64, 0x65, 0x20, 0x67, 0x65, 0x6e, 0x2e, 0x3b, 0x64, 0x65, 0x20,
-0x66, 0x65, 0x62, 0x72, 0x2e, 0x3b, 0x64, 0x65, 0x20, 0x6d, 0x61, 0x72, 0xe7, 0x3b, 0x64, 0x2019, 0x61, 0x62, 0x72, 0x2e,
-0x3b, 0x64, 0x65, 0x20, 0x6d, 0x61, 0x69, 0x67, 0x3b, 0x64, 0x65, 0x20, 0x6a, 0x75, 0x6e, 0x79, 0x3b, 0x64, 0x65, 0x20,
-0x6a, 0x75, 0x6c, 0x2e, 0x3b, 0x64, 0x2019, 0x61, 0x67, 0x2e, 0x3b, 0x64, 0x65, 0x20, 0x73, 0x65, 0x74, 0x2e, 0x3b, 0x64,
-0x2019, 0x6f, 0x63, 0x74, 0x2e, 0x3b, 0x64, 0x65, 0x20, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x20, 0x64, 0x65, 0x73,
-0x2e, 0x47, 0x4e, 0x3b, 0x46, 0x42, 0x3b, 0x4d, 0xc7, 0x3b, 0x41, 0x42, 0x3b, 0x4d, 0x47, 0x3b, 0x4a, 0x4e, 0x3b, 0x4a,
-0x4c, 0x3b, 0x41, 0x47, 0x3b, 0x53, 0x54, 0x3b, 0x4f, 0x43, 0x3b, 0x4e, 0x56, 0x3b, 0x44, 0x53, 0x45, 0x6e, 0x65, 0x72,
-0x6f, 0x3b, 0x50, 0x65, 0x62, 0x72, 0x65, 0x72, 0x6f, 0x3b, 0x4d, 0x61, 0x72, 0x73, 0x6f, 0x3b, 0x41, 0x62, 0x72, 0x69,
-0x6c, 0x3b, 0x4d, 0x61, 0x79, 0x6f, 0x3b, 0x48, 0x75, 0x6e, 0x79, 0x6f, 0x3b, 0x48, 0x75, 0x6c, 0x79, 0x6f, 0x3b, 0x41,
-0x67, 0x6f, 0x73, 0x74, 0x6f, 0x3b, 0x53, 0x65, 0x74, 0x79, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x4f, 0x6b, 0x74, 0x75,
-0x62, 0x72, 0x65, 0x3b, 0x4e, 0x6f, 0x62, 0x79, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x44, 0x69, 0x73, 0x79, 0x65, 0x6d,
-0x62, 0x72, 0x65, 0x45, 0x6e, 0x65, 0x3b, 0x50, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x62, 0x72, 0x3b, 0x4d,
-0x61, 0x79, 0x3b, 0x48, 0x75, 0x6e, 0x3b, 0x48, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x6f, 0x3b, 0x53, 0x65, 0x74, 0x3b, 0x4f,
-0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x62, 0x3b, 0x44, 0x69, 0x73, 0x45, 0x3b, 0x50, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b,
-0x48, 0x3b, 0x48, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x59, 0x65, 0x6e, 0x6e, 0x61, 0x79, 0x65,
-0x72, 0x3b, 0x59, 0x65, 0x62, 0x72, 0x61, 0x79, 0x65, 0x72, 0x3b, 0x4d, 0x61, 0x72, 0x73, 0x3b, 0x49, 0x62, 0x72, 0x69,
-0x72, 0x3b, 0x4d, 0x61, 0x79, 0x79, 0x75, 0x3b, 0x59, 0x75, 0x6e, 0x79, 0x75, 0x3b, 0x59, 0x75, 0x6c, 0x79, 0x75, 0x7a,
-0x3b, 0x194, 0x75, 0x63, 0x74, 0x3b, 0x43, 0x75, 0x74, 0x61, 0x6e, 0x62, 0x69, 0x72, 0x3b, 0x4b, 0x1e6d, 0x75, 0x62, 0x65,
-0x72, 0x3b, 0x4e, 0x77, 0x61, 0x6e, 0x62, 0x69, 0x72, 0x3b, 0x44, 0x75, 0x6a, 0x61, 0x6e, 0x62, 0x69, 0x72, 0x59, 0x65,
-0x6e, 0x3b, 0x59, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x49, 0x62, 0x72, 0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x59, 0x75,
-0x6e, 0x3b, 0x59, 0x75, 0x6c, 0x3b, 0x194, 0x75, 0x63, 0x3b, 0x43, 0x75, 0x74, 0x3b, 0x4b, 0x1e6d, 0x75, 0x3b, 0x4e, 0x77,
-0x61, 0x3b, 0x44, 0x75, 0x6a, 0x59, 0x3b, 0x59, 0x3b, 0x4d, 0x3b, 0x49, 0x3b, 0x4d, 0x3b, 0x59, 0x3b, 0x59, 0x3b, 0x194,
-0x3b, 0x43, 0x3b, 0x4b, 0x3b, 0x4e, 0x3b, 0x44, 0x6a9, 0x627, 0x646, 0x648, 0x648, 0x646, 0x6cc, 0x20, 0x62f, 0x648, 0x648, 0x6d5,
-0x645, 0x3b, 0x634, 0x648, 0x628, 0x627, 0x62a, 0x3b, 0x626, 0x627, 0x632, 0x627, 0x631, 0x3b, 0x646, 0x6cc, 0x633, 0x627, 0x646, 0x3b,
-0x626, 0x627, 0x6cc, 0x627, 0x631, 0x3b, 0x62d, 0x648, 0x632, 0x6d5, 0x6cc, 0x631, 0x627, 0x646, 0x3b, 0x62a, 0x6d5, 0x645, 0x648, 0x648,
-0x632, 0x3b, 0x626, 0x627, 0x628, 0x3b, 0x626, 0x6d5, 0x6cc, 0x644, 0x648, 0x648, 0x644, 0x3b, 0x62a, 0x634, 0x631, 0x6cc, 0x646, 0x6cc,
-0x20, 0x6cc, 0x6d5, 0x6a9, 0x6d5, 0x645, 0x3b, 0x62a, 0x634, 0x631, 0x6cc, 0x646, 0x6cc, 0x20, 0x62f, 0x648, 0x648, 0x6d5, 0x645, 0x3b,
-0x6a9, 0x627, 0x646, 0x648, 0x646, 0x6cc, 0x20, 0x6cc, 0x6d5, 0x6a9, 0x6d5, 0x645, 0x6a9, 0x3b, 0x634, 0x3b, 0x626, 0x3b, 0x646, 0x3b,
-0x626, 0x3b, 0x62d, 0x3b, 0x62a, 0x3b, 0x626, 0x3b, 0x626, 0x3b, 0x62a, 0x3b, 0x62a, 0x3b, 0x6a9, 0xd804, 0xdd0e, 0xd804, 0xdd1a, 0xd804,
-0xdd2a, 0xd804, 0xdd20, 0xd804, 0xdd22, 0xd804, 0xdd28, 0x3b, 0xd804, 0xdd1c, 0xd804, 0xdd2c, 0xd804, 0xdd1b, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd33,
-0xd804, 0xdd22, 0xd804, 0xdd2a, 0xd804, 0xdd20, 0xd804, 0xdd22, 0xd804, 0xdd28, 0x3b, 0xd804, 0xdd1f, 0xd804, 0xdd22, 0xd804, 0xdd34, 0xd804, 0xdd0c, 0xd804,
-0xdd27, 0x3b, 0xd804, 0xdd03, 0xd804, 0xdd2c, 0xd804, 0xdd1b, 0xd804, 0xdd33, 0xd804, 0xdd22, 0xd804, 0xdd28, 0xd804, 0xdd23, 0xd804, 0xdd34, 0x3b, 0xd804,
-0xdd1f, 0xd804, 0xdd2c, 0x3b, 0xd804, 0xdd0e, 0xd804, 0xdd2a, 0xd804, 0xdd1a, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd0e, 0xd804, 0xdd2a, 0xd804, 0xdd23, 0xd804,
-0xdd2d, 0x3b, 0xd804, 0xdd03, 0xd804, 0xdd09, 0xd804, 0xdd27, 0xd804, 0xdd0c, 0xd804, 0xdd34, 0xd804, 0xdd11, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd25, 0xd804,
-0xdd2c, 0xd804, 0xdd1b, 0xd804, 0xdd34, 0xd804, 0xdd11, 0xd804, 0xdd2c, 0xd804, 0xdd1f, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd27, 0xd804, 0xdd22, 0xd804,
-0xdd34, 0x3b, 0xd804, 0xdd03, 0xd804, 0xdd27, 0xd804, 0xdd07, 0xd804, 0xdd34, 0xd804, 0xdd11, 0xd804, 0xdd2e, 0xd804, 0xdd1d, 0xd804, 0xdd27, 0xd804, 0xdd22,
-0xd804, 0xdd34, 0x3b, 0xd804, 0xdd1a, 0xd804, 0xdd27, 0xd804, 0xdd1e, 0xd804, 0xdd2c, 0xd804, 0xdd1f, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd27, 0xd804,
-0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd13, 0xd804, 0xdd28, 0xd804, 0xdd25, 0xd804, 0xdd2c, 0xd804, 0xdd1f, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd27,
-0xd804, 0xdd22, 0xd804, 0xdd34, 0xd804, 0xdd0e, 0xd804, 0xdd1a, 0xd804, 0xdd2a, 0xd804, 0xdd20, 0xd804, 0xdd22, 0xd804, 0xdd28, 0x3b, 0xd804, 0xdd1c, 0xd804,
-0xdd2c, 0xd804, 0xdd1b, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd33, 0xd804, 0xdd22, 0xd804, 0xdd2a, 0xd804, 0xdd20, 0xd804, 0xdd22, 0xd804, 0xdd28, 0x3b,
-0xd804, 0xdd1f, 0xd804, 0xdd22, 0xd804, 0xdd34, 0xd804, 0xdd0c, 0xd804, 0xdd27, 0x3b, 0xd804, 0xdd03, 0xd804, 0xdd2c, 0xd804, 0xdd1b, 0xd804, 0xdd33, 0xd804,
-0xdd22, 0xd804, 0xdd28, 0xd804, 0xdd23, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd1f, 0xd804, 0xdd2c, 0x3b, 0xd804, 0xdd0e, 0xd804, 0xdd2a, 0xd804, 0xdd1a, 0xd804,
-0xdd34, 0x3b, 0xd804, 0xdd0e, 0xd804, 0xdd2a, 0xd804, 0xdd23, 0xd804, 0xdd2d, 0x3b, 0xd804, 0xdd03, 0xd804, 0xdd09, 0xd804, 0xdd27, 0xd804, 0xdd0c, 0xd804,
-0xdd34, 0xd804, 0xdd11, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd25, 0xd804, 0xdd2c, 0xd804, 0xdd1b, 0xd804, 0xdd34, 0xd804, 0xdd11, 0xd804, 0xdd2c, 0xd804, 0xdd1f,
-0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd27, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd03, 0xd804, 0xdd27, 0xd804, 0xdd07, 0xd804, 0xdd34, 0xd804,
-0xdd11, 0xd804, 0xdd2c, 0xd804, 0xdd1d, 0xd804, 0xdd27, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd1a, 0xd804, 0xdd27, 0xd804, 0xdd1e, 0xd804, 0xdd2c,
-0xd804, 0xdd1f, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd27, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd13, 0xd804, 0xdd28, 0xd804, 0xdd25, 0xd804,
-0xdd2c, 0xd804, 0xdd1f, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd27, 0xd804, 0xdd22, 0xd804, 0xdd34, 0xd804, 0xdd0e, 0xd804, 0xdd1a, 0xd804, 0xdd2a, 0x3b,
-0xd804, 0xdd1c, 0xd804, 0xdd2c, 0xd804, 0xdd1b, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd1f, 0xd804, 0xdd22, 0xd804, 0xdd34, 0xd804, 0xdd0c, 0xd804, 0xdd27, 0x3b,
-0xd804, 0xdd03, 0xd804, 0xdd2c, 0xd804, 0xdd1b, 0xd804, 0xdd33, 0xd804, 0xdd22, 0xd804, 0xdd28, 0xd804, 0xdd23, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd1f, 0xd804,
-0xdd2c, 0x3b, 0xd804, 0xdd0e, 0xd804, 0xdd2a, 0xd804, 0xdd1a, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd0e, 0xd804, 0xdd2a, 0xd804, 0xdd23, 0xd804, 0xdd2d, 0x3b,
-0xd804, 0xdd03, 0xd804, 0xdd09, 0xd804, 0xdd27, 0xd804, 0xdd0c, 0xd804, 0xdd34, 0xd804, 0xdd11, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd25, 0xd804, 0xdd2c, 0xd804,
-0xdd1b, 0xd804, 0xdd34, 0xd804, 0xdd11, 0xd804, 0xdd2c, 0xd804, 0xdd1f, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd27, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b,
-0xd804, 0xdd03, 0xd804, 0xdd27, 0xd804, 0xdd07, 0xd804, 0xdd34, 0xd804, 0xdd11, 0xd804, 0xdd2e, 0xd804, 0xdd1d, 0xd804, 0xdd27, 0xd804, 0xdd22, 0xd804, 0xdd34,
-0x3b, 0xd804, 0xdd1a, 0xd804, 0xdd27, 0xd804, 0xdd1e, 0xd804, 0xdd2c, 0xd804, 0xdd1f, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd27, 0xd804, 0xdd22, 0xd804,
-0xdd34, 0x3b, 0xd804, 0xdd13, 0xd804, 0xdd28, 0xd804, 0xdd25, 0xd804, 0xdd2c, 0xd804, 0xdd1f, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd22, 0xd804, 0xdd34,
-0xd804, 0xdd0e, 0x3b, 0xd804, 0xdd1c, 0xd804, 0xdd2c, 0x3b, 0xd804, 0xdd1f, 0x3b, 0xd804, 0xdd03, 0xd804, 0xdd2c, 0x3b, 0xd804, 0xdd1f, 0xd804, 0xdd2c,
-0x3b, 0xd804, 0xdd0e, 0xd804, 0xdd2a, 0xd804, 0xdd1a, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd0e, 0xd804, 0xdd2a, 0x3b, 0xd804, 0xdd03, 0x3b, 0xd804, 0xdd25,
-0xd804, 0xdd2c, 0x3b, 0xd804, 0xdd03, 0xd804, 0xdd27, 0x3b, 0xd804, 0xdd1a, 0xd804, 0xdd27, 0x3b, 0xd804, 0xdd13, 0xd804, 0xdd28, 0x44f, 0x43d, 0x432,
-0x430, 0x440, 0x44c, 0x3b, 0x444, 0x435, 0x432, 0x440, 0x430, 0x43b, 0x44c, 0x3b, 0x43c, 0x430, 0x440, 0x442, 0x3b, 0x430, 0x43f, 0x440,
-0x435, 0x43b, 0x44c, 0x3b, 0x43c, 0x430, 0x439, 0x3b, 0x438, 0x44e, 0x43d, 0x44c, 0x3b, 0x438, 0x44e, 0x43b, 0x44c, 0x3b, 0x430, 0x432,
-0x433, 0x443, 0x441, 0x442, 0x3b, 0x441, 0x435, 0x43d, 0x442, 0x44f, 0x431, 0x440, 0x44c, 0x3b, 0x43e, 0x43a, 0x442, 0x44f, 0x431, 0x440,
-0x44c, 0x3b, 0x43d, 0x43e, 0x44f, 0x431, 0x440, 0x44c, 0x3b, 0x434, 0x435, 0x43a, 0x430, 0x431, 0x440, 0x44c, 0x44f, 0x43d, 0x432, 0x3b,
-0x444, 0x435, 0x432, 0x3b, 0x43c, 0x430, 0x440, 0x3b, 0x430, 0x43f, 0x440, 0x3b, 0x43c, 0x430, 0x439, 0x3b, 0x438, 0x44e, 0x43d, 0x3b,
-0x438, 0x44e, 0x43b, 0x3b, 0x430, 0x432, 0x433, 0x3b, 0x441, 0x435, 0x43d, 0x3b, 0x43e, 0x43a, 0x442, 0x3b, 0x43d, 0x43e, 0x44f, 0x3b,
-0x434, 0x435, 0x43a, 0x42f, 0x3b, 0x424, 0x3b, 0x41c, 0x3b, 0x410, 0x3b, 0x41c, 0x3b, 0x418, 0x3b, 0x418, 0x3b, 0x410, 0x3b, 0x421,
-0x3b, 0x41e, 0x3b, 0x41d, 0x3b, 0x414, 0x13a4, 0x13c3, 0x13b8, 0x13d4, 0x13c5, 0x3b, 0x13a7, 0x13a6, 0x13b5, 0x3b, 0x13a0, 0x13c5, 0x13f1, 0x3b,
-0x13a7, 0x13ec, 0x13c2, 0x3b, 0x13a0, 0x13c2, 0x13cd, 0x13ac, 0x13d8, 0x3b, 0x13d5, 0x13ad, 0x13b7, 0x13f1, 0x3b, 0x13ab, 0x13f0, 0x13c9, 0x13c2, 0x3b,
-0x13a6, 0x13b6, 0x13c2, 0x3b, 0x13da, 0x13b5, 0x13cd, 0x13d7, 0x3b, 0x13da, 0x13c2, 0x13c5, 0x13d7, 0x3b, 0x13c5, 0x13d3, 0x13d5, 0x13c6, 0x3b, 0x13a5,
-0x13cd, 0x13a9, 0x13f1, 0x13a4, 0x13c3, 0x3b, 0x13a7, 0x13a6, 0x3b, 0x13a0, 0x13c5, 0x3b, 0x13a7, 0x13ec, 0x3b, 0x13a0, 0x13c2, 0x3b, 0x13d5, 0x13ad,
-0x3b, 0x13ab, 0x13f0, 0x3b, 0x13a6, 0x13b6, 0x3b, 0x13da, 0x13b5, 0x3b, 0x13da, 0x13c2, 0x3b, 0x13c5, 0x13d3, 0x3b, 0x13a5, 0x13cd, 0x13a4, 0x3b,
-0x13a7, 0x3b, 0x13a0, 0x3b, 0x13a7, 0x3b, 0x13a0, 0x3b, 0x13d5, 0x3b, 0x13ab, 0x3b, 0x13a6, 0x3b, 0x13da, 0x3b, 0x13da, 0x3b, 0x13c5, 0x3b,
-0x13a5, 0x4f, 0x6b, 0x77, 0x6f, 0x6b, 0x75, 0x62, 0x61, 0x6e, 0x7a, 0x61, 0x3b, 0x4f, 0x6b, 0x77, 0x61, 0x6b, 0x61, 0x62,
-0x69, 0x72, 0x69, 0x3b, 0x4f, 0x6b, 0x77, 0x61, 0x6b, 0x61, 0x73, 0x68, 0x61, 0x74, 0x75, 0x3b, 0x4f, 0x6b, 0x77, 0x61,
-0x6b, 0x61, 0x6e, 0x61, 0x3b, 0x4f, 0x6b, 0x77, 0x61, 0x6b, 0x61, 0x74, 0x61, 0x61, 0x6e, 0x61, 0x3b, 0x4f, 0x6b, 0x77,
-0x61, 0x6d, 0x75, 0x6b, 0x61, 0x61, 0x67, 0x61, 0x3b, 0x4f, 0x6b, 0x77, 0x61, 0x6d, 0x75, 0x73, 0x68, 0x61, 0x6e, 0x6a,
-0x75, 0x3b, 0x4f, 0x6b, 0x77, 0x61, 0x6d, 0x75, 0x6e, 0x61, 0x61, 0x6e, 0x61, 0x3b, 0x4f, 0x6b, 0x77, 0x61, 0x6d, 0x77,
-0x65, 0x6e, 0x64, 0x61, 0x3b, 0x4f, 0x6b, 0x77, 0x61, 0x69, 0x6b, 0x75, 0x6d, 0x69, 0x3b, 0x4f, 0x6b, 0x77, 0x61, 0x69,
-0x6b, 0x75, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x6b, 0x75, 0x6d, 0x77, 0x65, 0x3b, 0x4f, 0x6b, 0x77, 0x61, 0x69, 0x6b,
-0x75, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x69, 0x62, 0x69, 0x72, 0x69, 0x4b, 0x42, 0x5a, 0x3b, 0x4b, 0x42, 0x52, 0x3b,
-0x4b, 0x53, 0x54, 0x3b, 0x4b, 0x4b, 0x4e, 0x3b, 0x4b, 0x54, 0x4e, 0x3b, 0x4b, 0x4d, 0x4b, 0x3b, 0x4b, 0x4d, 0x53, 0x3b,
-0x4b, 0x4d, 0x4e, 0x3b, 0x4b, 0x4d, 0x57, 0x3b, 0x4b, 0x4b, 0x4d, 0x3b, 0x4b, 0x4e, 0x4b, 0x3b, 0x4b, 0x4e, 0x42, 0x43a,
-0x4d1, 0x440, 0x43b, 0x430, 0x447, 0x3b, 0x43d, 0x430, 0x440, 0x4d1, 0x441, 0x3b, 0x43f, 0x443, 0x448, 0x3b, 0x430, 0x43a, 0x430, 0x3b,
-0x4ab, 0x443, 0x3b, 0x4ab, 0x4d7, 0x440, 0x442, 0x43c, 0x435, 0x3b, 0x443, 0x442, 0x4d1, 0x3b, 0x4ab, 0x443, 0x440, 0x43b, 0x430, 0x3b,
-0x430, 0x432, 0x4d1, 0x43d, 0x3b, 0x44e, 0x43f, 0x430, 0x3b, 0x447, 0x4f3, 0x43a, 0x3b, 0x440, 0x430, 0x448, 0x442, 0x430, 0x432, 0x43a,
-0x4d1, 0x440, 0x2e, 0x3b, 0x43d, 0x430, 0x440, 0x2e, 0x3b, 0x43f, 0x443, 0x448, 0x3b, 0x430, 0x43a, 0x430, 0x3b, 0x4ab, 0x443, 0x3b,
-0x4ab, 0x4d7, 0x440, 0x2e, 0x3b, 0x443, 0x442, 0x4d1, 0x3b, 0x4ab, 0x443, 0x440, 0x2e, 0x3b, 0x430, 0x432, 0x4d1, 0x43d, 0x3b, 0x44e,
-0x43f, 0x430, 0x3b, 0x447, 0x4f3, 0x43a, 0x3b, 0x440, 0x430, 0x448, 0x2e, 0x41a, 0x3b, 0x41d, 0x3b, 0x41f, 0x3b, 0x410, 0x3b, 0x4aa,
-0x3b, 0x4aa, 0x3b, 0x423, 0x3b, 0x4aa, 0x3b, 0x410, 0x3b, 0x42e, 0x3b, 0x427, 0x3b, 0x420, 0x4a, 0x61, 0x6e, 0x6e, 0x65, 0x77,
-0x61, 0x3b, 0x46, 0xe4, 0x62, 0x72, 0x6f, 0x77, 0x61, 0x3b, 0x4d, 0xe4, 0xe4, 0x7a, 0x3b, 0x41, 0x70, 0x72, 0x65, 0x6c,
-0x6c, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x75, 0x6c, 0x69, 0x3b, 0x4f, 0x75,
-0x6a, 0x6f, 0xdf, 0x3b, 0x53, 0x65, 0x70, 0x74, 0xe4, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x68, 0x62,
-0x65, 0x72, 0x3b, 0x4e, 0x6f, 0x76, 0xe4, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x44, 0x65, 0x7a, 0xe4, 0x6d, 0x62, 0x65, 0x72,
-0x4a, 0x61, 0x6e, 0x2e, 0x3b, 0x46, 0xe4, 0x62, 0x2e, 0x3b, 0x4d, 0xe4, 0x7a, 0x2e, 0x3b, 0x41, 0x70, 0x72, 0x2e, 0x3b,
-0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x2e, 0x3b, 0x4a, 0x75, 0x6c, 0x2e, 0x3b, 0x4f, 0x75, 0x6a, 0x2e, 0x3b, 0x53,
-0xe4, 0x70, 0x2e, 0x3b, 0x4f, 0x6b, 0x74, 0x2e, 0x3b, 0x4e, 0x6f, 0x76, 0x2e, 0x3b, 0x44, 0x65, 0x7a, 0x2e, 0x4a, 0x61,
-0x6e, 0x3b, 0x46, 0xe4, 0x62, 0x3b, 0x4d, 0xe4, 0x7a, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75,
-0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x4f, 0x75, 0x6a, 0x3b, 0x53, 0xe4, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f,
-0x76, 0x3b, 0x44, 0x65, 0x7a, 0x4a, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x4f,
-0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x6d, 0x69, 0x73, 0x20, 0x47, 0x65, 0x6e, 0x76, 0x65, 0x72, 0x3b, 0x6d,
-0x69, 0x73, 0x20, 0x48, 0x77, 0x65, 0x76, 0x72, 0x65, 0x72, 0x3b, 0x6d, 0x69, 0x73, 0x20, 0x4d, 0x65, 0x75, 0x72, 0x74,
-0x68, 0x3b, 0x6d, 0x69, 0x73, 0x20, 0x45, 0x62, 0x72, 0x65, 0x6c, 0x3b, 0x6d, 0x69, 0x73, 0x20, 0x4d, 0x65, 0x3b, 0x6d,
-0x69, 0x73, 0x20, 0x4d, 0x65, 0x74, 0x68, 0x65, 0x76, 0x65, 0x6e, 0x3b, 0x6d, 0x69, 0x73, 0x20, 0x47, 0x6f, 0x72, 0x74,
-0x68, 0x65, 0x72, 0x65, 0x6e, 0x3b, 0x6d, 0x69, 0x73, 0x20, 0x45, 0x73, 0x74, 0x3b, 0x6d, 0x69, 0x73, 0x20, 0x47, 0x77,
-0x79, 0x6e, 0x6e, 0x67, 0x61, 0x6c, 0x61, 0x3b, 0x6d, 0x69, 0x73, 0x20, 0x48, 0x65, 0x64, 0x72, 0x61, 0x3b, 0x6d, 0x69,
-0x73, 0x20, 0x44, 0x75, 0x3b, 0x6d, 0x69, 0x73, 0x20, 0x4b, 0x65, 0x76, 0x61, 0x72, 0x64, 0x68, 0x75, 0x47, 0x65, 0x6e,
-0x3b, 0x48, 0x77, 0x65, 0x3b, 0x4d, 0x65, 0x75, 0x3b, 0x45, 0x62, 0x72, 0x3b, 0x4d, 0x65, 0x3b, 0x4d, 0x65, 0x74, 0x3b,
-0x47, 0x6f, 0x72, 0x3b, 0x45, 0x73, 0x74, 0x3b, 0x47, 0x77, 0x6e, 0x3b, 0x48, 0x65, 0x64, 0x3b, 0x44, 0x75, 0x3b, 0x4b,
-0x65, 0x76, 0x73, 0x69, 0x6a, 0x65, 0x10d, 0x61, 0x6e, 0x6a, 0x3b, 0x76, 0x65, 0x6c, 0x6a, 0x61, 0x10d, 0x61, 0x3b, 0x6f,
-0x17e, 0x75, 0x6a, 0x61, 0x6b, 0x3b, 0x74, 0x72, 0x61, 0x76, 0x61, 0x6e, 0x6a, 0x3b, 0x73, 0x76, 0x69, 0x62, 0x61, 0x6e,
-0x6a, 0x3b, 0x6c, 0x69, 0x70, 0x61, 0x6e, 0x6a, 0x3b, 0x73, 0x72, 0x70, 0x61, 0x6e, 0x6a, 0x3b, 0x6b, 0x6f, 0x6c, 0x6f,
-0x76, 0x6f, 0x7a, 0x3b, 0x72, 0x75, 0x6a, 0x61, 0x6e, 0x3b, 0x6c, 0x69, 0x73, 0x74, 0x6f, 0x70, 0x61, 0x64, 0x3b, 0x73,
-0x74, 0x75, 0x64, 0x65, 0x6e, 0x69, 0x3b, 0x70, 0x72, 0x6f, 0x73, 0x69, 0x6e, 0x61, 0x63, 0x73, 0x69, 0x6a, 0x65, 0x10d,
-0x6e, 0x6a, 0x61, 0x3b, 0x76, 0x65, 0x6c, 0x6a, 0x61, 0x10d, 0x65, 0x3b, 0x6f, 0x17e, 0x75, 0x6a, 0x6b, 0x61, 0x3b, 0x74,
-0x72, 0x61, 0x76, 0x6e, 0x6a, 0x61, 0x3b, 0x73, 0x76, 0x69, 0x62, 0x6e, 0x6a, 0x61, 0x3b, 0x6c, 0x69, 0x70, 0x6e, 0x6a,
-0x61, 0x3b, 0x73, 0x72, 0x70, 0x6e, 0x6a, 0x61, 0x3b, 0x6b, 0x6f, 0x6c, 0x6f, 0x76, 0x6f, 0x7a, 0x61, 0x3b, 0x72, 0x75,
-0x6a, 0x6e, 0x61, 0x3b, 0x6c, 0x69, 0x73, 0x74, 0x6f, 0x70, 0x61, 0x64, 0x61, 0x3b, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e,
-0x6f, 0x67, 0x61, 0x3b, 0x70, 0x72, 0x6f, 0x73, 0x69, 0x6e, 0x63, 0x61, 0x73, 0x69, 0x6a, 0x3b, 0x76, 0x65, 0x6c, 0x6a,
-0x3b, 0x6f, 0x17e, 0x75, 0x3b, 0x74, 0x72, 0x61, 0x3b, 0x73, 0x76, 0x69, 0x3b, 0x6c, 0x69, 0x70, 0x3b, 0x73, 0x72, 0x70,
-0x3b, 0x6b, 0x6f, 0x6c, 0x3b, 0x72, 0x75, 0x6a, 0x3b, 0x6c, 0x69, 0x73, 0x3b, 0x73, 0x74, 0x75, 0x3b, 0x70, 0x72, 0x6f,
-0x31, 0x2e, 0x3b, 0x32, 0x2e, 0x3b, 0x33, 0x2e, 0x3b, 0x34, 0x2e, 0x3b, 0x35, 0x2e, 0x3b, 0x36, 0x2e, 0x3b, 0x37, 0x2e,
-0x3b, 0x38, 0x2e, 0x3b, 0x39, 0x2e, 0x3b, 0x31, 0x30, 0x2e, 0x3b, 0x31, 0x31, 0x2e, 0x3b, 0x31, 0x32, 0x2e, 0x6c, 0x65,
-0x64, 0x65, 0x6e, 0x3b, 0xfa, 0x6e, 0x6f, 0x72, 0x3b, 0x62, 0x159, 0x65, 0x7a, 0x65, 0x6e, 0x3b, 0x64, 0x75, 0x62, 0x65,
-0x6e, 0x3b, 0x6b, 0x76, 0x11b, 0x74, 0x65, 0x6e, 0x3b, 0x10d, 0x65, 0x72, 0x76, 0x65, 0x6e, 0x3b, 0x10d, 0x65, 0x72, 0x76,
-0x65, 0x6e, 0x65, 0x63, 0x3b, 0x73, 0x72, 0x70, 0x65, 0x6e, 0x3b, 0x7a, 0xe1, 0x159, 0xed, 0x3b, 0x159, 0xed, 0x6a, 0x65,
-0x6e, 0x3b, 0x6c, 0x69, 0x73, 0x74, 0x6f, 0x70, 0x61, 0x64, 0x3b, 0x70, 0x72, 0x6f, 0x73, 0x69, 0x6e, 0x65, 0x63, 0x6c,
-0x65, 0x64, 0x6e, 0x61, 0x3b, 0xfa, 0x6e, 0x6f, 0x72, 0x61, 0x3b, 0x62, 0x159, 0x65, 0x7a, 0x6e, 0x61, 0x3b, 0x64, 0x75,
-0x62, 0x6e, 0x61, 0x3b, 0x6b, 0x76, 0x11b, 0x74, 0x6e, 0x61, 0x3b, 0x10d, 0x65, 0x72, 0x76, 0x6e, 0x61, 0x3b, 0x10d, 0x65,
-0x72, 0x76, 0x65, 0x6e, 0x63, 0x65, 0x3b, 0x73, 0x72, 0x70, 0x6e, 0x61, 0x3b, 0x7a, 0xe1, 0x159, 0xed, 0x3b, 0x159, 0xed,
-0x6a, 0x6e, 0x61, 0x3b, 0x6c, 0x69, 0x73, 0x74, 0x6f, 0x70, 0x61, 0x64, 0x75, 0x3b, 0x70, 0x72, 0x6f, 0x73, 0x69, 0x6e,
-0x63, 0x65, 0x6c, 0x65, 0x64, 0x3b, 0xfa, 0x6e, 0x6f, 0x3b, 0x62, 0x159, 0x65, 0x3b, 0x64, 0x75, 0x62, 0x3b, 0x6b, 0x76,
-0x11b, 0x3b, 0x10d, 0x76, 0x6e, 0x3b, 0x10d, 0x76, 0x63, 0x3b, 0x73, 0x72, 0x70, 0x3b, 0x7a, 0xe1, 0x159, 0x3b, 0x159, 0xed,
-0x6a, 0x3b, 0x6c, 0x69, 0x73, 0x3b, 0x70, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x3b, 0x66, 0x65, 0x62, 0x72,
-0x75, 0x61, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x73, 0x3b, 0x61, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x61, 0x6a, 0x3b,
-0x6a, 0x75, 0x6e, 0x69, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x3b, 0x61, 0x75, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x70,
-0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d,
-0x62, 0x65, 0x72, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x6a, 0x61, 0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x62,
-0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x61, 0x70, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x2e,
-0x3b, 0x6a, 0x75, 0x6c, 0x2e, 0x3b, 0x61, 0x75, 0x67, 0x2e, 0x3b, 0x73, 0x65, 0x70, 0x2e, 0x3b, 0x6f, 0x6b, 0x74, 0x2e,
-0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x63, 0x2e, 0x91c, 0x928, 0x935, 0x930, 0x940, 0x3b, 0x92b, 0x930, 0x935, 0x930,
-0x940, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x948, 0x932, 0x3b, 0x92e, 0x947, 0x908, 0x3b, 0x91c,
-0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x93e, 0x908, 0x3b, 0x905, 0x917, 0x938, 0x94d, 0x924, 0x3b, 0x938, 0x93f, 0x924, 0x902, 0x92c,
-0x930, 0x3b, 0x905, 0x915, 0x94d, 0x924, 0x942, 0x92c, 0x930, 0x3b, 0x928, 0x935, 0x902, 0x92c, 0x930, 0x3b, 0x926, 0x93f, 0x938, 0x902,
-0x92c, 0x930, 0x91c, 0x928, 0x2e, 0x3b, 0x92b, 0x930, 0x2e, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930,
-0x948, 0x932, 0x3b, 0x92e, 0x947, 0x908, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x93e, 0x908, 0x3b, 0x905, 0x917, 0x2e,
-0x3b, 0x938, 0x93f, 0x924, 0x2e, 0x3b, 0x905, 0x915, 0x94d, 0x924, 0x942, 0x2e, 0x3b, 0x928, 0x935, 0x2e, 0x3b, 0x926, 0x93f, 0x938,
-0x2e, 0x91c, 0x3b, 0x92b, 0x3b, 0x92e, 0x93e, 0x3b, 0x905, 0x3b, 0x92e, 0x947, 0x3b, 0x91c, 0x942, 0x3b, 0x91c, 0x941, 0x3b, 0x905,
-0x3b, 0x938, 0x93f, 0x3b, 0x905, 0x3b, 0x928, 0x3b, 0x926, 0x93f, 0x64, 0x69, 0x6d, 0x254, 0x301, 0x64, 0x69, 0x3b, 0x14b, 0x67,
-0x254, 0x6e, 0x64, 0x25b, 0x3b, 0x73, 0x254, 0x14b, 0x25b, 0x3b, 0x64, 0x69, 0x253, 0xe1, 0x253, 0xe1, 0x3b, 0x65, 0x6d, 0x69,
-0x61, 0x73, 0x65, 0x6c, 0x65, 0x3b, 0x65, 0x73, 0x254, 0x70, 0x25b, 0x73, 0x254, 0x70, 0x25b, 0x3b, 0x6d, 0x61, 0x64, 0x69,
-0x253, 0x25b, 0x301, 0x64, 0xed, 0x253, 0x25b, 0x301, 0x3b, 0x64, 0x69, 0x14b, 0x67, 0x69, 0x6e, 0x64, 0x69, 0x3b, 0x6e, 0x79,
-0x25b, 0x74, 0x25b, 0x6b, 0x69, 0x3b, 0x6d, 0x61, 0x79, 0xe9, 0x73, 0x25b, 0x301, 0x3b, 0x74, 0x69, 0x6e, 0xed, 0x6e, 0xed,
-0x3b, 0x65, 0x6c, 0xe1, 0x14b, 0x67, 0x25b, 0x301, 0x64, 0x69, 0x3b, 0x14b, 0x67, 0x254, 0x6e, 0x3b, 0x73, 0x254, 0x14b, 0x3b,
-0x64, 0x69, 0x253, 0x3b, 0x65, 0x6d, 0x69, 0x3b, 0x65, 0x73, 0x254, 0x3b, 0x6d, 0x61, 0x64, 0x3b, 0x64, 0x69, 0x14b, 0x3b,
-0x6e, 0x79, 0x25b, 0x74, 0x3b, 0x6d, 0x61, 0x79, 0x3b, 0x74, 0x69, 0x6e, 0x3b, 0x65, 0x6c, 0xe1, 0x64, 0x3b, 0x14b, 0x3b,
-0x73, 0x3b, 0x64, 0x3b, 0x65, 0x3b, 0x65, 0x3b, 0x6d, 0x3b, 0x64, 0x3b, 0x6e, 0x3b, 0x6d, 0x3b, 0x74, 0x3b, 0x65, 0x6a,
-0x61, 0x6e, 0x75, 0x61, 0x72, 0x69, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x69, 0x3b, 0x6d, 0x61, 0x61, 0x72,
-0x74, 0x3b, 0x61, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x65, 0x69, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x3b, 0x6a, 0x75, 0x6c,
-0x69, 0x3b, 0x61, 0x75, 0x67, 0x75, 0x73, 0x74, 0x75, 0x73, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72,
-0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x64, 0x65,
-0x63, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x6a, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0x72, 0x74, 0x3b, 0x61, 0x70,
-0x72, 0x3b, 0x6d, 0x65, 0x69, 0x3b, 0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x75, 0x67, 0x3b, 0x73, 0x65,
-0x70, 0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65, 0x63, 0xf66, 0xfa4, 0xfb1, 0xf72, 0xf0b, 0xf5f, 0xfb3,
-0xf0b, 0xf51, 0xf44, 0xf54, 0xf0b, 0x3b, 0xf66, 0xfa4, 0xfb1, 0xf72, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf42, 0xf49, 0xf72, 0xf66, 0xf0b, 0xf54,
-0xf0b, 0x3b, 0xf66, 0xfa4, 0xfb1, 0xf72, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf42, 0xf66, 0xf74, 0xf58, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf66, 0xfa4,
-0xfb1, 0xf72, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf5e, 0xf72, 0xf0b, 0xf54, 0x3b, 0xf66, 0xfa4, 0xfb1, 0xf72, 0xf0b, 0xf5f, 0xfb3, 0xf0b,
-0xf63, 0xf94, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf66, 0xfa4, 0xfb1, 0xf72, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf51, 0xfb2, 0xf74, 0xf42, 0xf0b, 0xf54,
-0x3b, 0xf66, 0xfa4, 0xfb1, 0xf72, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf51, 0xf74, 0xf53, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf66, 0xfa4, 0xfb1,
-0xf72, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf62, 0xf92, 0xfb1, 0xf51, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf66, 0xfa4, 0xfb1, 0xf72, 0xf0b, 0xf5f,
-0xfb3, 0xf0b, 0xf51, 0xf42, 0xf74, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf66, 0xfa4, 0xfb1, 0xf72, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf45, 0xf74,
-0xf0b, 0xf54, 0xf0b, 0x3b, 0xf66, 0xfa4, 0xfb1, 0xf72, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf45, 0xf74, 0xf0b, 0xf42, 0xf45, 0xf72, 0xf42,
-0xf0b, 0xf54, 0xf0b, 0x3b, 0xf66, 0xfa4, 0xfb1, 0xf72, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf45, 0xf74, 0xf0b, 0xf42, 0xf49, 0xf72, 0xf66,
-0xf0b, 0xf54, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf51, 0xf44, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf42, 0xf49, 0xf72, 0xf66, 0xf0b, 0xf54,
-0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf42, 0xf66, 0xf74, 0xf58, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf5e, 0xf72, 0xf0b,
-0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf63, 0xf94, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf51, 0xfb2, 0xf74, 0xf42, 0xf0b,
-0xf54, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf51, 0xf74, 0xf53, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf62, 0xf92, 0xfb1,
-0xf51, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf51, 0xf42, 0xf74, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf45,
-0xf74, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf45, 0xf74, 0xf0b, 0xf42, 0xf45, 0xf72, 0xf42, 0xf0b, 0xf54, 0xf0b, 0x3b,
-0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf45, 0xf74, 0xf0b, 0xf42, 0xf49, 0xf72, 0xf66, 0xf0b, 0xf54, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf21, 0x3b, 0xf5f,
-0xfb3, 0xf0b, 0xf22, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf23, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf24, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf25, 0x3b, 0xf5f,
-0xfb3, 0xf0b, 0xf26, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf27, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf28, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf29, 0x3b, 0xf5f,
-0xfb3, 0xf0b, 0xf21, 0xf20, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf21, 0xf21, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf21, 0xf22, 0xf21, 0x3b, 0xf22, 0x3b,
-0xf23, 0x3b, 0xf24, 0x3b, 0xf25, 0x3b, 0xf26, 0x3b, 0xf27, 0x3b, 0xf28, 0x3b, 0xf29, 0x3b, 0xf21, 0xf20, 0x3b, 0xf21, 0xf21, 0x3b,
-0x31, 0x32, 0xf21, 0x3b, 0xf22, 0x3b, 0xf23, 0x3b, 0xf24, 0x3b, 0xf25, 0x3b, 0xf26, 0x3b, 0xf27, 0x3b, 0xf28, 0x3b, 0xf29, 0x3b,
-0xf21, 0xf20, 0x3b, 0xf21, 0xf21, 0x3b, 0xf21, 0xf22, 0xf21, 0x3b, 0xf22, 0x3b, 0xf23, 0x3b, 0x34, 0x3b, 0xf25, 0x3b, 0xf26, 0x3b,
-0xf27, 0x3b, 0xf28, 0x3b, 0x39, 0x3b, 0xf21, 0xf20, 0x3b, 0xf21, 0xf21, 0x3b, 0xf21, 0xf22, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20,
-0x77, 0x61, 0x20, 0x6d, 0x62, 0x65, 0x72, 0x65, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x61,
-0x129, 0x72, 0x69, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x74, 0x68, 0x61, 0x74, 0x169,
-0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x6e, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69,
-0x20, 0x77, 0x61, 0x20, 0x67, 0x61, 0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20,
-0x67, 0x61, 0x74, 0x61, 0x6e, 0x74, 0x61, 0x74, 0x169, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6d,
-0x169, 0x67, 0x77, 0x61, 0x6e, 0x6a, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x6e,
-0x61, 0x6e, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x65, 0x6e, 0x64, 0x61, 0x3b, 0x4d,
-0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x69, 0x6b, 0x169, 0x6d, 0x69, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20,
-0x77, 0x61, 0x20, 0x69, 0x6b, 0x169, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x169, 0x6d, 0x77, 0x65, 0x3b, 0x4d, 0x77, 0x65,
-0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x69, 0x6b, 0x169, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x4b, 0x61, 0x129, 0x72, 0x129,
-0x4d, 0x62, 0x65, 0x3b, 0x4b, 0x61, 0x69, 0x3b, 0x4b, 0x61, 0x74, 0x3b, 0x4b, 0x61, 0x6e, 0x3b, 0x47, 0x61, 0x74, 0x3b,
-0x47, 0x61, 0x6e, 0x3b, 0x4d, 0x75, 0x67, 0x3b, 0x4b, 0x6e, 0x6e, 0x3b, 0x4b, 0x65, 0x6e, 0x3b, 0x49, 0x6b, 0x75, 0x3b,
-0x49, 0x6d, 0x77, 0x3b, 0x49, 0x67, 0x69, 0x4d, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x47, 0x3b, 0x47, 0x3b, 0x4d,
-0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x49, 0x3b, 0x49, 0x3b, 0x49, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61,
-0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x75,
-0x67, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x3b, 0x4f, 0x63, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x63, 0x4a, 0x61,
-0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x4a, 0x75,
-0x6e, 0x65, 0x3b, 0x4a, 0x75, 0x6c, 0x79, 0x3b, 0x41, 0x75, 0x67, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x3b, 0x4f, 0x63, 0x74,
-0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x63, 0x6a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x6f, 0x3b, 0x66, 0x65, 0x62, 0x72,
-0x75, 0x61, 0x72, 0x6f, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x6f, 0x3b, 0x61, 0x70, 0x72, 0x69, 0x6c, 0x6f, 0x3b, 0x6d, 0x61,
-0x6a, 0x6f, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x6f, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x6f, 0x3b, 0x61, 0x16d, 0x67, 0x75, 0x73,
-0x74, 0x6f, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x6f, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x72, 0x6f,
-0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x6f, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x72, 0x6f, 0x4a, 0x61,
-0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x61, 0x6a, 0x3b, 0x4a, 0x75,
-0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x16d, 0x67, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f,
-0x76, 0x3b, 0x44, 0x65, 0x63, 0x6a, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x61, 0x70, 0x72,
-0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x16d, 0x67, 0x3b, 0x73, 0x65, 0x70,
-0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65, 0x63, 0x6a, 0x61, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x3b,
-0x76, 0x65, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x3b, 0x6d, 0xe4, 0x72, 0x74, 0x73, 0x3b, 0x61, 0x70, 0x72, 0x69, 0x6c,
-0x6c, 0x3b, 0x6d, 0x61, 0x69, 0x3b, 0x6a, 0x75, 0x75, 0x6e, 0x69, 0x3b, 0x6a, 0x75, 0x75, 0x6c, 0x69, 0x3b, 0x61, 0x75,
-0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x6f,
-0x62, 0x65, 0x72, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x64, 0x65, 0x74, 0x73, 0x65, 0x6d, 0x62,
-0x65, 0x72, 0x6a, 0x61, 0x61, 0x6e, 0x3b, 0x76, 0x65, 0x65, 0x62, 0x72, 0x3b, 0x6d, 0xe4, 0x72, 0x74, 0x73, 0x3b, 0x61,
-0x70, 0x72, 0x3b, 0x6d, 0x61, 0x69, 0x3b, 0x6a, 0x75, 0x75, 0x6e, 0x69, 0x3b, 0x6a, 0x75, 0x75, 0x6c, 0x69, 0x3b, 0x61,
-0x75, 0x67, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65, 0x74, 0x73,
-0x4a, 0x3b, 0x56, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b,
-0x4e, 0x3b, 0x44, 0x64, 0x7a, 0x6f, 0x76, 0x65, 0x3b, 0x64, 0x7a, 0x6f, 0x64, 0x7a, 0x65, 0x3b, 0x74, 0x65, 0x64, 0x6f,
-0x78, 0x65, 0x3b, 0x61, 0x66, 0x254, 0x66, 0x129, 0x65, 0x3b, 0x64, 0x61, 0x6d, 0x61, 0x3b, 0x6d, 0x61, 0x73, 0x61, 0x3b,
-0x73, 0x69, 0x61, 0x6d, 0x6c, 0x254, 0x6d, 0x3b, 0x64, 0x65, 0x61, 0x73, 0x69, 0x61, 0x6d, 0x69, 0x6d, 0x65, 0x3b, 0x61,
-0x6e, 0x79, 0x254, 0x6e, 0x79, 0x254, 0x3b, 0x6b, 0x65, 0x6c, 0x65, 0x3b, 0x61, 0x64, 0x65, 0x25b, 0x6d, 0x65, 0x6b, 0x70,
-0x254, 0x78, 0x65, 0x3b, 0x64, 0x7a, 0x6f, 0x6d, 0x65, 0x64, 0x7a, 0x76, 0x3b, 0x64, 0x7a, 0x64, 0x3b, 0x74, 0x65, 0x64,
-0x3b, 0x61, 0x66, 0x254, 0x3b, 0x64, 0x61, 0x6d, 0x3b, 0x6d, 0x61, 0x73, 0x3b, 0x73, 0x69, 0x61, 0x3b, 0x64, 0x65, 0x61,
-0x3b, 0x61, 0x6e, 0x79, 0x3b, 0x6b, 0x65, 0x6c, 0x3b, 0x61, 0x64, 0x65, 0x3b, 0x64, 0x7a, 0x6d, 0x64, 0x3b, 0x64, 0x3b,
-0x74, 0x3b, 0x61, 0x3b, 0x64, 0x3b, 0x6d, 0x3b, 0x73, 0x3b, 0x64, 0x3b, 0x61, 0x3b, 0x6b, 0x3b, 0x61, 0x3b, 0x64, 0x6e,
-0x67, 0x254, 0x6e, 0x20, 0x6f, 0x73, 0xfa, 0x3b, 0x6e, 0x67, 0x254, 0x6e, 0x20, 0x62, 0x25b, 0x30c, 0x3b, 0x6e, 0x67, 0x254,
-0x6e, 0x20, 0x6c, 0xe1, 0x6c, 0x61, 0x3b, 0x6e, 0x67, 0x254, 0x6e, 0x20, 0x6e, 0x79, 0x69, 0x6e, 0x61, 0x3b, 0x6e, 0x67,
-0x254, 0x6e, 0x20, 0x74, 0xe1, 0x6e, 0x61, 0x3b, 0x6e, 0x67, 0x254, 0x6e, 0x20, 0x73, 0x61, 0x6d, 0x259, 0x6e, 0x61, 0x3b,
-0x6e, 0x67, 0x254, 0x6e, 0x20, 0x7a, 0x61, 0x6d, 0x67, 0x62, 0xe1, 0x6c, 0x61, 0x3b, 0x6e, 0x67, 0x254, 0x6e, 0x20, 0x6d,
-0x77, 0x6f, 0x6d, 0x3b, 0x6e, 0x67, 0x254, 0x6e, 0x20, 0x65, 0x62, 0x75, 0x6c, 0xfa, 0x3b, 0x6e, 0x67, 0x254, 0x6e, 0x20,
-0x61, 0x77, 0xf3, 0x6d, 0x3b, 0x6e, 0x67, 0x254, 0x6e, 0x20, 0x61, 0x77, 0xf3, 0x6d, 0x20, 0x61, 0x69, 0x20, 0x64, 0x7a,
-0x69, 0xe1, 0x3b, 0x6e, 0x67, 0x254, 0x6e, 0x20, 0x61, 0x77, 0xf3, 0x6d, 0x20, 0x61, 0x69, 0x20, 0x62, 0x25b, 0x30c, 0x6e,
-0x67, 0x6f, 0x3b, 0x6e, 0x67, 0x62, 0x3b, 0x6e, 0x67, 0x6c, 0x3b, 0x6e, 0x67, 0x6e, 0x3b, 0x6e, 0x67, 0x74, 0x3b, 0x6e,
-0x67, 0x73, 0x3b, 0x6e, 0x67, 0x7a, 0x3b, 0x6e, 0x67, 0x6d, 0x3b, 0x6e, 0x67, 0x65, 0x3b, 0x6e, 0x67, 0x61, 0x3b, 0x6e,
-0x67, 0x61, 0x64, 0x3b, 0x6e, 0x67, 0x61, 0x62, 0x6f, 0x3b, 0x62, 0x3b, 0x6c, 0x3b, 0x6e, 0x3b, 0x74, 0x3b, 0x73, 0x3b,
-0x7a, 0x3b, 0x6d, 0x3b, 0x65, 0x3b, 0x61, 0x3b, 0x64, 0x3b, 0x62, 0x6a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x3b, 0x66, 0x65,
-0x62, 0x72, 0x75, 0x61, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x3b, 0x61, 0x70, 0x72, 0xed, 0x6c, 0x3b, 0x6d, 0x61, 0x69,
-0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x3b, 0x61, 0x75, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65,
-0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x6e, 0x6f, 0x76, 0x65,
-0x6d, 0x62, 0x65, 0x72, 0x3b, 0x64, 0x65, 0x73, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x6a, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x62,
-0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0x61, 0x69, 0x3b, 0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x6c,
-0x3b, 0x61, 0x75, 0x67, 0x3b, 0x73, 0x65, 0x70, 0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65, 0x73,
-0x6a, 0x61, 0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x62, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x61, 0x70, 0x72, 0x2e, 0x3b,
-0x6d, 0x61, 0x69, 0x3b, 0x6a, 0x75, 0x6e, 0x2e, 0x3b, 0x6a, 0x75, 0x6c, 0x2e, 0x3b, 0x61, 0x75, 0x67, 0x2e, 0x3b, 0x73,
-0x65, 0x70, 0x2e, 0x3b, 0x6f, 0x6b, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x73, 0x2e, 0x45, 0x3b,
-0x50, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x48, 0x75, 0x6e, 0x3b, 0x48, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x6f, 0x3b,
-0x53, 0x65, 0x74, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x62, 0x3b, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6d, 0x6d, 0x69,
-0x6b, 0x75, 0x75, 0x3b, 0x68, 0x65, 0x6c, 0x6d, 0x69, 0x6b, 0x75, 0x75, 0x3b, 0x6d, 0x61, 0x61, 0x6c, 0x69, 0x73, 0x6b,
-0x75, 0x75, 0x3b, 0x68, 0x75, 0x68, 0x74, 0x69, 0x6b, 0x75, 0x75, 0x3b, 0x74, 0x6f, 0x75, 0x6b, 0x6f, 0x6b, 0x75, 0x75,
-0x3b, 0x6b, 0x65, 0x73, 0xe4, 0x6b, 0x75, 0x75, 0x3b, 0x68, 0x65, 0x69, 0x6e, 0xe4, 0x6b, 0x75, 0x75, 0x3b, 0x65, 0x6c,
-0x6f, 0x6b, 0x75, 0x75, 0x3b, 0x73, 0x79, 0x79, 0x73, 0x6b, 0x75, 0x75, 0x3b, 0x6c, 0x6f, 0x6b, 0x61, 0x6b, 0x75, 0x75,
-0x3b, 0x6d, 0x61, 0x72, 0x72, 0x61, 0x73, 0x6b, 0x75, 0x75, 0x3b, 0x6a, 0x6f, 0x75, 0x6c, 0x75, 0x6b, 0x75, 0x75, 0x74,
-0x61, 0x6d, 0x6d, 0x69, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x68, 0x65, 0x6c, 0x6d, 0x69, 0x6b, 0x75, 0x75, 0x74, 0x61,
-0x3b, 0x6d, 0x61, 0x61, 0x6c, 0x69, 0x73, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x68, 0x75, 0x68, 0x74, 0x69, 0x6b, 0x75,
-0x75, 0x74, 0x61, 0x3b, 0x74, 0x6f, 0x75, 0x6b, 0x6f, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x6b, 0x65, 0x73, 0xe4, 0x6b,
-0x75, 0x75, 0x74, 0x61, 0x3b, 0x68, 0x65, 0x69, 0x6e, 0xe4, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x65, 0x6c, 0x6f, 0x6b,
-0x75, 0x75, 0x74, 0x61, 0x3b, 0x73, 0x79, 0x79, 0x73, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x6c, 0x6f, 0x6b, 0x61, 0x6b,
-0x75, 0x75, 0x74, 0x61, 0x3b, 0x6d, 0x61, 0x72, 0x72, 0x61, 0x73, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x6a, 0x6f, 0x75,
-0x6c, 0x75, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x74, 0x61, 0x6d, 0x6d, 0x69, 0x3b, 0x68, 0x65, 0x6c, 0x6d, 0x69, 0x3b, 0x6d,
-0x61, 0x61, 0x6c, 0x69, 0x73, 0x3b, 0x68, 0x75, 0x68, 0x74, 0x69, 0x3b, 0x74, 0x6f, 0x75, 0x6b, 0x6f, 0x3b, 0x6b, 0x65,
-0x73, 0xe4, 0x3b, 0x68, 0x65, 0x69, 0x6e, 0xe4, 0x3b, 0x65, 0x6c, 0x6f, 0x3b, 0x73, 0x79, 0x79, 0x73, 0x3b, 0x6c, 0x6f,
-0x6b, 0x61, 0x3b, 0x6d, 0x61, 0x72, 0x72, 0x61, 0x73, 0x3b, 0x6a, 0x6f, 0x75, 0x6c, 0x75, 0x74, 0x61, 0x6d, 0x6d, 0x69,
-0x6b, 0x2e, 0x3b, 0x68, 0x65, 0x6c, 0x6d, 0x69, 0x6b, 0x2e, 0x3b, 0x6d, 0x61, 0x61, 0x6c, 0x69, 0x73, 0x6b, 0x2e, 0x3b,
-0x68, 0x75, 0x68, 0x74, 0x69, 0x6b, 0x2e, 0x3b, 0x74, 0x6f, 0x75, 0x6b, 0x6f, 0x6b, 0x2e, 0x3b, 0x6b, 0x65, 0x73, 0xe4,
-0x6b, 0x2e, 0x3b, 0x68, 0x65, 0x69, 0x6e, 0xe4, 0x6b, 0x2e, 0x3b, 0x65, 0x6c, 0x6f, 0x6b, 0x2e, 0x3b, 0x73, 0x79, 0x79,
-0x73, 0x6b, 0x2e, 0x3b, 0x6c, 0x6f, 0x6b, 0x61, 0x6b, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x72, 0x61, 0x73, 0x6b, 0x2e, 0x3b,
-0x6a, 0x6f, 0x75, 0x6c, 0x75, 0x6b, 0x2e, 0x54, 0x3b, 0x48, 0x3b, 0x4d, 0x3b, 0x48, 0x3b, 0x54, 0x3b, 0x4b, 0x3b, 0x48,
-0x3b, 0x45, 0x3b, 0x53, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x4a, 0x6a, 0x61, 0x6e, 0x76, 0x69, 0x65, 0x72, 0x3b, 0x66, 0xe9,
-0x76, 0x72, 0x69, 0x65, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x3b, 0x61, 0x76, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x61, 0x69,
-0x3b, 0x6a, 0x75, 0x69, 0x6e, 0x3b, 0x6a, 0x75, 0x69, 0x6c, 0x6c, 0x65, 0x74, 0x3b, 0x61, 0x6f, 0xfb, 0x74, 0x3b, 0x73,
-0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x6f, 0x63, 0x74, 0x6f, 0x62, 0x72, 0x65, 0x3b, 0x6e, 0x6f, 0x76,
-0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64, 0xe9, 0x63, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x6a, 0x61, 0x6e, 0x76, 0x2e, 0x3b,
-0x66, 0xe9, 0x76, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x3b, 0x61, 0x76, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x69, 0x3b,
-0x6a, 0x75, 0x69, 0x6e, 0x3b, 0x6a, 0x75, 0x69, 0x6c, 0x2e, 0x3b, 0x61, 0x6f, 0xfb, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74,
-0x2e, 0x3b, 0x6f, 0x63, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0xe9, 0x63, 0x2e, 0x6a, 0x61, 0x6e, 0x76,
-0x2e, 0x3b, 0x66, 0xe9, 0x76, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x3b, 0x61, 0x76, 0x72, 0x2e, 0x3b, 0x6d, 0x61,
-0x69, 0x3b, 0x6a, 0x75, 0x69, 0x6e, 0x3b, 0x6a, 0x75, 0x69, 0x6c, 0x6c, 0x2e, 0x3b, 0x61, 0x6f, 0xfb, 0x74, 0x3b, 0x73,
-0x65, 0x70, 0x74, 0x2e, 0x3b, 0x6f, 0x63, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0xe9, 0x63, 0x2e, 0x6a,
-0x61, 0x6e, 0x2e, 0x3b, 0x66, 0xe9, 0x76, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x61, 0x76, 0x72, 0x2e, 0x3b, 0x6d,
-0x61, 0x69, 0x3b, 0x6a, 0x75, 0x69, 0x2e, 0x3b, 0x6a, 0x75, 0x69, 0x6c, 0x2e, 0x3b, 0x61, 0x6f, 0xfb, 0x74, 0x3b, 0x73,
-0x65, 0x70, 0x74, 0x2e, 0x3b, 0x6f, 0x63, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0xe9, 0x63, 0x2e, 0x5a,
-0x65, 0x6e, 0xe2, 0x72, 0x3b, 0x46, 0x65, 0x76, 0x72, 0xe2, 0x72, 0x3b, 0x4d, 0x61, 0x72, 0xe7, 0x3b, 0x41, 0x76, 0x72,
-0xee, 0x6c, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x67, 0x6e, 0x3b, 0x4c, 0x75, 0x69, 0x3b, 0x41, 0x76, 0x6f, 0x73,
-0x74, 0x3b, 0x53, 0x65, 0x74, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x4f, 0x74, 0x75, 0x62, 0x61, 0x72, 0x3b, 0x4e, 0x6f,
-0x76, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x44, 0x69, 0x63, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x5a, 0x65, 0x6e, 0x3b, 0x46,
-0x65, 0x76, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x76, 0x72, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x67, 0x3b, 0x4c,
-0x75, 0x69, 0x3b, 0x41, 0x76, 0x6f, 0x3b, 0x53, 0x65, 0x74, 0x3b, 0x4f, 0x74, 0x75, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44,
-0x69, 0x63, 0x5a, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x4c, 0x3b, 0x41, 0x3b, 0x53, 0x3b,
-0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x73, 0x69, 0x69, 0x6c, 0x6f, 0x3b, 0x63, 0x6f, 0x6c, 0x74, 0x65, 0x3b, 0x6d, 0x62, 0x6f,
-0x6f, 0x79, 0x3b, 0x73, 0x65, 0x65, 0x257, 0x74, 0x6f, 0x3b, 0x64, 0x75, 0x75, 0x6a, 0x61, 0x6c, 0x3b, 0x6b, 0x6f, 0x72,
-0x73, 0x65, 0x3b, 0x6d, 0x6f, 0x72, 0x73, 0x6f, 0x3b, 0x6a, 0x75, 0x6b, 0x6f, 0x3b, 0x73, 0x69, 0x69, 0x6c, 0x74, 0x6f,
-0x3b, 0x79, 0x61, 0x72, 0x6b, 0x6f, 0x6d, 0x61, 0x61, 0x3b, 0x6a, 0x6f, 0x6c, 0x61, 0x6c, 0x3b, 0x62, 0x6f, 0x77, 0x74,
-0x65, 0x73, 0x69, 0x69, 0x3b, 0x63, 0x6f, 0x6c, 0x3b, 0x6d, 0x62, 0x6f, 0x3b, 0x73, 0x65, 0x65, 0x3b, 0x64, 0x75, 0x75,
-0x3b, 0x6b, 0x6f, 0x72, 0x3b, 0x6d, 0x6f, 0x72, 0x3b, 0x6a, 0x75, 0x6b, 0x3b, 0x73, 0x6c, 0x74, 0x3b, 0x79, 0x61, 0x72,
-0x3b, 0x6a, 0x6f, 0x6c, 0x3b, 0x62, 0x6f, 0x77, 0x73, 0x3b, 0x63, 0x3b, 0x6d, 0x3b, 0x73, 0x3b, 0x64, 0x3b, 0x6b, 0x3b,
-0x6d, 0x3b, 0x6a, 0x3b, 0x73, 0x3b, 0x79, 0x3b, 0x6a, 0x3b, 0x62, 0xd83a, 0xdd05, 0xd83a, 0xdd2d, 0xd83a, 0xdd45, 0xd83a, 0xdd24, 0xd83a,
-0xdd2e, 0x3b, 0xd83a, 0xdd15, 0xd83a, 0xdd2e, 0xd83a, 0xdd24, 0xd83a, 0xdd3c, 0xd83a, 0xdd2e, 0x3b, 0xd83a, 0xdd10, 0xd83a, 0xdd26, 0xd83a, 0xdd2e, 0xd83a,
-0xdd45, 0xd83a, 0xdd34, 0xd83a, 0xdd2e, 0x3b, 0xd83a, 0xdd05, 0xd83a, 0xdd2b, 0xd83a, 0xdd45, 0xd83a, 0xdd3c, 0xd83a, 0xdd2e, 0x3b, 0xd83a, 0xdd01, 0xd83a,
-0xdd35, 0xd83a, 0xdd45, 0xd83a, 0xdd36, 0xd83a, 0xdd2e, 0x3b, 0xd83a, 0xdd11, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0xd83a, 0xdd27, 0xd83a, 0xdd2e, 0x3b, 0xd83a,
-0xdd03, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0xd83a, 0xdd27, 0xd83a, 0xdd2e, 0x3b, 0xd83a, 0xdd14, 0xd83a, 0xdd35, 0xd83a, 0xdd33, 0xd83a, 0xdd2e, 0x3b, 0xd83a,
-0xdd05, 0xd83a, 0xdd2d, 0xd83a, 0xdd24, 0xd83a, 0xdd3c, 0xd83a, 0xdd2e, 0x3b, 0xd83a, 0xdd12, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd33, 0xd83a, 0xdd2e,
-0x3b, 0xd83a, 0xdd14, 0xd83a, 0xdd2e, 0xd83a, 0xdd24, 0xd83a, 0xdd2e, 0x3b, 0xd83a, 0xdd04, 0xd83a, 0xdd2e, 0xd83a, 0xdd31, 0xd83a, 0xdd3c, 0xd83a, 0xdd2e,
-0xd83a, 0xdd05, 0xd83a, 0xdd2d, 0xd83a, 0xdd45, 0xd83a, 0xdd24, 0x3b, 0xd83a, 0xdd15, 0xd83a, 0xdd2e, 0xd83a, 0xdd24, 0x3b, 0xd83a, 0xdd10, 0xd83a, 0xdd26,
-0xd83a, 0xdd2e, 0xd83a, 0xdd45, 0xd83a, 0xdd34, 0x3b, 0xd83a, 0xdd05, 0xd83a, 0xdd2b, 0xd83a, 0xdd45, 0xd83a, 0xdd3c, 0x3b, 0xd83a, 0xdd01, 0xd83a, 0xdd35,
-0xd83a, 0xdd45, 0xd83a, 0xdd36, 0x3b, 0xd83a, 0xdd11, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0x3b, 0xd83a, 0xdd03, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0x3b, 0xd83a,
-0xdd14, 0xd83a, 0xdd35, 0xd83a, 0xdd33, 0x3b, 0xd83a, 0xdd05, 0xd83a, 0xdd2d, 0xd83a, 0xdd24, 0x3b, 0xd83a, 0xdd12, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0x3b,
-0xd83a, 0xdd14, 0xd83a, 0xdd2e, 0xd83a, 0xdd24, 0x3b, 0xd83a, 0xdd04, 0xd83a, 0xdd2e, 0xd83a, 0xdd31, 0xd83a, 0xdd05, 0x3b, 0xd83a, 0xdd15, 0x3b, 0xd83a,
-0xdd04, 0x3b, 0xd83a, 0xdd05, 0x3b, 0xd83a, 0xdd01, 0x3b, 0xd83a, 0xdd11, 0x3b, 0xd83a, 0xdd03, 0x3b, 0xd83a, 0xdd14, 0x3b, 0xd83a, 0xdd05, 0x3b,
-0xd83a, 0xdd12, 0x3b, 0xd83a, 0xdd14, 0x3b, 0xd83a, 0xdd04, 0x41, 0x6d, 0x20, 0x46, 0x61, 0x6f, 0x69, 0x6c, 0x6c, 0x65, 0x61, 0x63,
-0x68, 0x3b, 0x41, 0x6e, 0x20, 0x47, 0x65, 0x61, 0x72, 0x72, 0x61, 0x6e, 0x3b, 0x41, 0x6d, 0x20, 0x4d, 0xe0, 0x72, 0x74,
-0x3b, 0x41, 0x6e, 0x20, 0x47, 0x69, 0x62, 0x6c, 0x65, 0x61, 0x6e, 0x3b, 0x41, 0x6e, 0x20, 0x43, 0xe8, 0x69, 0x74, 0x65,
-0x61, 0x6e, 0x3b, 0x41, 0x6e, 0x20, 0x74, 0x2d, 0xd2, 0x67, 0x6d, 0x68, 0x69, 0x6f, 0x73, 0x3b, 0x41, 0x6e, 0x20, 0x74,
-0x2d, 0x49, 0x75, 0x63, 0x68, 0x61, 0x72, 0x3b, 0x41, 0x6e, 0x20, 0x4c, 0xf9, 0x6e, 0x61, 0x73, 0x74, 0x61, 0x6c, 0x3b,
-0x41, 0x6e, 0x20, 0x74, 0x2d, 0x53, 0x75, 0x6c, 0x74, 0x61, 0x69, 0x6e, 0x3b, 0x41, 0x6e, 0x20, 0x44, 0xe0, 0x6d, 0x68,
-0x61, 0x69, 0x72, 0x3b, 0x41, 0x6e, 0x20, 0x74, 0x2d, 0x53, 0x61, 0x6d, 0x68, 0x61, 0x69, 0x6e, 0x3b, 0x41, 0x6e, 0x20,
-0x44, 0xf9, 0x62, 0x68, 0x6c, 0x61, 0x63, 0x68, 0x64, 0x64, 0x68, 0x65, 0x6e, 0x20, 0x46, 0x68, 0x61, 0x6f, 0x69, 0x6c,
-0x6c, 0x65, 0x61, 0x63, 0x68, 0x3b, 0x64, 0x68, 0x65, 0x6e, 0x20, 0x47, 0x68, 0x65, 0x61, 0x72, 0x72, 0x61, 0x6e, 0x3b,
-0x64, 0x68, 0x65, 0x6e, 0x20, 0x4d, 0x68, 0xe0, 0x72, 0x74, 0x3b, 0x64, 0x68, 0x65, 0x6e, 0x20, 0x47, 0x68, 0x69, 0x62,
-0x6c, 0x65, 0x61, 0x6e, 0x3b, 0x64, 0x68, 0x65, 0x6e, 0x20, 0x43, 0x68, 0xe8, 0x69, 0x74, 0x65, 0x61, 0x6e, 0x3b, 0x64,
-0x68, 0x65, 0x6e, 0x20, 0xd2, 0x67, 0x6d, 0x68, 0x69, 0x6f, 0x73, 0x3b, 0x64, 0x68, 0x65, 0x6e, 0x20, 0x49, 0x75, 0x63,
-0x68, 0x61, 0x72, 0x3b, 0x64, 0x68, 0x65, 0x6e, 0x20, 0x4c, 0xf9, 0x6e, 0x61, 0x73, 0x74, 0x61, 0x6c, 0x3b, 0x64, 0x68,
-0x65, 0x6e, 0x20, 0x74, 0x2d, 0x53, 0x75, 0x6c, 0x74, 0x61, 0x69, 0x6e, 0x3b, 0x64, 0x68, 0x65, 0x6e, 0x20, 0x44, 0xe0,
-0x6d, 0x68, 0x61, 0x69, 0x72, 0x3b, 0x64, 0x68, 0x65, 0x6e, 0x20, 0x74, 0x2d, 0x53, 0x61, 0x6d, 0x68, 0x61, 0x69, 0x6e,
-0x3b, 0x64, 0x68, 0x65, 0x6e, 0x20, 0x44, 0xf9, 0x62, 0x68, 0x6c, 0x61, 0x63, 0x68, 0x64, 0x46, 0x61, 0x6f, 0x69, 0x3b,
-0x47, 0x65, 0x61, 0x72, 0x72, 0x3b, 0x4d, 0xe0, 0x72, 0x74, 0x3b, 0x47, 0x69, 0x62, 0x6c, 0x3b, 0x43, 0xe8, 0x69, 0x74,
-0x3b, 0xd2, 0x67, 0x6d, 0x68, 0x3b, 0x49, 0x75, 0x63, 0x68, 0x3b, 0x4c, 0xf9, 0x6e, 0x61, 0x3b, 0x53, 0x75, 0x6c, 0x74,
-0x3b, 0x44, 0xe0, 0x6d, 0x68, 0x3b, 0x53, 0x61, 0x6d, 0x68, 0x3b, 0x44, 0xf9, 0x62, 0x68, 0x46, 0x3b, 0x47, 0x3b, 0x4d,
-0x3b, 0x47, 0x3b, 0x43, 0x3b, 0xd2, 0x3b, 0x49, 0x3b, 0x4c, 0x3b, 0x53, 0x3b, 0x44, 0x3b, 0x53, 0x3b, 0x44, 0x58, 0x61,
-0x6e, 0x65, 0x69, 0x72, 0x6f, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x65, 0x69, 0x72, 0x6f, 0x3b, 0x4d, 0x61, 0x72, 0x7a, 0x6f,
-0x3b, 0x41, 0x62, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x61, 0x69, 0x6f, 0x3b, 0x58, 0x75, 0xf1, 0x6f, 0x3b, 0x58, 0x75, 0x6c,
-0x6c, 0x6f, 0x3b, 0x41, 0x67, 0x6f, 0x73, 0x74, 0x6f, 0x3b, 0x53, 0x65, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x6f, 0x3b, 0x4f,
-0x75, 0x74, 0x75, 0x62, 0x72, 0x6f, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x6f, 0x3b, 0x44, 0x65, 0x63, 0x65,
-0x6d, 0x62, 0x72, 0x6f, 0x78, 0x61, 0x6e, 0x65, 0x69, 0x72, 0x6f, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x65, 0x69, 0x72, 0x6f,
-0x3b, 0x6d, 0x61, 0x72, 0x7a, 0x6f, 0x3b, 0x61, 0x62, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x61, 0x69, 0x6f, 0x3b, 0x78, 0x75,
-0xf1, 0x6f, 0x3b, 0x78, 0x75, 0x6c, 0x6c, 0x6f, 0x3b, 0x61, 0x67, 0x6f, 0x73, 0x74, 0x6f, 0x3b, 0x73, 0x65, 0x74, 0x65,
-0x6d, 0x62, 0x72, 0x6f, 0x3b, 0x6f, 0x75, 0x74, 0x75, 0x62, 0x72, 0x6f, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72,
-0x6f, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x72, 0x6f, 0x58, 0x61, 0x6e, 0x2e, 0x3b, 0x46, 0x65, 0x62, 0x2e, 0x3b,
-0x4d, 0x61, 0x72, 0x2e, 0x3b, 0x41, 0x62, 0x72, 0x2e, 0x3b, 0x4d, 0x61, 0x69, 0x6f, 0x3b, 0x58, 0x75, 0xf1, 0x6f, 0x3b,
-0x58, 0x75, 0x6c, 0x2e, 0x3b, 0x41, 0x67, 0x6f, 0x2e, 0x3b, 0x53, 0x65, 0x74, 0x2e, 0x3b, 0x4f, 0x75, 0x74, 0x2e, 0x3b,
-0x4e, 0x6f, 0x76, 0x2e, 0x3b, 0x44, 0x65, 0x63, 0x2e, 0x78, 0x61, 0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x62, 0x2e, 0x3b, 0x6d,
-0x61, 0x72, 0x2e, 0x3b, 0x61, 0x62, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x69, 0x6f, 0x3b, 0x78, 0x75, 0xf1, 0x6f, 0x3b, 0x78,
-0x75, 0x6c, 0x2e, 0x3b, 0x61, 0x67, 0x6f, 0x2e, 0x3b, 0x73, 0x65, 0x74, 0x2e, 0x3b, 0x6f, 0x75, 0x74, 0x2e, 0x3b, 0x6e,
-0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x63, 0x2e, 0x58, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x58, 0x3b,
-0x58, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x78, 0x2e, 0x3b, 0x66, 0x2e, 0x3b, 0x6d, 0x2e, 0x3b,
-0x61, 0x2e, 0x3b, 0x6d, 0x2e, 0x3b, 0x78, 0x2e, 0x3b, 0x78, 0x2e, 0x3b, 0x61, 0x2e, 0x3b, 0x73, 0x2e, 0x3b, 0x6f, 0x2e,
-0x3b, 0x6e, 0x2e, 0x3b, 0x64, 0x2e, 0x4a, 0x61, 0x6e, 0x77, 0x61, 0x6c, 0x69, 0x79, 0x6f, 0x3b, 0x46, 0x65, 0x62, 0x77,
-0x61, 0x6c, 0x69, 0x79, 0x6f, 0x3b, 0x4d, 0x61, 0x72, 0x69, 0x73, 0x69, 0x3b, 0x41, 0x70, 0x75, 0x6c, 0x69, 0x3b, 0x4d,
-0x61, 0x61, 0x79, 0x69, 0x3b, 0x4a, 0x75, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x61, 0x61, 0x79, 0x69, 0x3b, 0x41,
-0x67, 0x75, 0x73, 0x69, 0x74, 0x6f, 0x3b, 0x53, 0x65, 0x62, 0x75, 0x74, 0x74, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x4f, 0x6b,
-0x69, 0x74, 0x6f, 0x62, 0x62, 0x61, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x44, 0x65, 0x73, 0x65, 0x6d,
-0x62, 0x61, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x70, 0x75, 0x3b, 0x4d, 0x61,
-0x61, 0x3b, 0x4a, 0x75, 0x75, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x75, 0x3b, 0x53, 0x65, 0x62, 0x3b, 0x4f, 0x6b,
-0x69, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x73, 0x10d8, 0x10d0, 0x10dc, 0x10d5, 0x10d0, 0x10e0, 0x10d8, 0x3b, 0x10d7, 0x10d4, 0x10d1,
-0x10d4, 0x10e0, 0x10d5, 0x10d0, 0x10da, 0x10d8, 0x3b, 0x10db, 0x10d0, 0x10e0, 0x10e2, 0x10d8, 0x3b, 0x10d0, 0x10de, 0x10e0, 0x10d8, 0x10da, 0x10d8, 0x3b,
-0x10db, 0x10d0, 0x10d8, 0x10e1, 0x10d8, 0x3b, 0x10d8, 0x10d5, 0x10dc, 0x10d8, 0x10e1, 0x10d8, 0x3b, 0x10d8, 0x10d5, 0x10da, 0x10d8, 0x10e1, 0x10d8, 0x3b,
-0x10d0, 0x10d2, 0x10d5, 0x10d8, 0x10e1, 0x10e2, 0x10dd, 0x3b, 0x10e1, 0x10d4, 0x10e5, 0x10e2, 0x10d4, 0x10db, 0x10d1, 0x10d4, 0x10e0, 0x10d8, 0x3b, 0x10dd,
-0x10e5, 0x10e2, 0x10dd, 0x10db, 0x10d1, 0x10d4, 0x10e0, 0x10d8, 0x3b, 0x10dc, 0x10dd, 0x10d4, 0x10db, 0x10d1, 0x10d4, 0x10e0, 0x10d8, 0x3b, 0x10d3, 0x10d4,
-0x10d9, 0x10d4, 0x10db, 0x10d1, 0x10d4, 0x10e0, 0x10d8, 0x10d8, 0x10d0, 0x10dc, 0x3b, 0x10d7, 0x10d4, 0x10d1, 0x3b, 0x10db, 0x10d0, 0x10e0, 0x3b, 0x10d0,
-0x10de, 0x10e0, 0x3b, 0x10db, 0x10d0, 0x10d8, 0x3b, 0x10d8, 0x10d5, 0x10dc, 0x3b, 0x10d8, 0x10d5, 0x10da, 0x3b, 0x10d0, 0x10d2, 0x10d5, 0x3b, 0x10e1,
-0x10d4, 0x10e5, 0x3b, 0x10dd, 0x10e5, 0x10e2, 0x3b, 0x10dc, 0x10dd, 0x10d4, 0x3b, 0x10d3, 0x10d4, 0x10d9, 0x10d8, 0x3b, 0x10d7, 0x3b, 0x10db, 0x3b,
-0x10d0, 0x3b, 0x10db, 0x3b, 0x10d8, 0x3b, 0x10d8, 0x3b, 0x10d0, 0x3b, 0x10e1, 0x3b, 0x10dd, 0x3b, 0x10dc, 0x3b, 0x10d3, 0x4a, 0x61, 0x6e,
-0x75, 0x61, 0x72, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x3b, 0x4d, 0xe4, 0x72, 0x7a, 0x3b, 0x41, 0x70, 0x72,
-0x69, 0x6c, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x69, 0x3b, 0x41, 0x75, 0x67,
-0x75, 0x73, 0x74, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x65,
-0x72, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x44, 0x65, 0x7a, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4a,
-0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0xe4, 0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a,
-0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x75, 0x67, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e,
-0x6f, 0x76, 0x3b, 0x44, 0x65, 0x7a, 0x4a, 0x61, 0x6e, 0x2e, 0x3b, 0x46, 0x65, 0x62, 0x2e, 0x3b, 0x4d, 0xe4, 0x72, 0x7a,
-0x3b, 0x41, 0x70, 0x72, 0x2e, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x69, 0x3b,
-0x41, 0x75, 0x67, 0x2e, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x2e, 0x3b, 0x4f, 0x6b, 0x74, 0x2e, 0x3b, 0x4e, 0x6f, 0x76, 0x2e,
-0x3b, 0x44, 0x65, 0x7a, 0x2e, 0x4a, 0xe4, 0x6e, 0x6e, 0x65, 0x72, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x3b,
-0x4d, 0xe4, 0x72, 0x7a, 0x3b, 0x41, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b,
-0x4a, 0x75, 0x6c, 0x69, 0x3b, 0x41, 0x75, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65,
-0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x44,
-0x65, 0x7a, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4a, 0xe4, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0xe4, 0x72, 0x3b, 0x41,
-0x70, 0x72, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x75, 0x67, 0x3b, 0x53,
-0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x7a, 0x4a, 0xe4, 0x6e, 0x2e, 0x3b, 0x46,
-0x65, 0x62, 0x2e, 0x3b, 0x4d, 0xe4, 0x72, 0x7a, 0x3b, 0x41, 0x70, 0x72, 0x2e, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75,
-0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x69, 0x3b, 0x41, 0x75, 0x67, 0x2e, 0x3b, 0x53, 0x65, 0x70, 0x2e, 0x3b, 0x4f, 0x6b,
-0x74, 0x2e, 0x3b, 0x4e, 0x6f, 0x76, 0x2e, 0x3b, 0x44, 0x65, 0x7a, 0x2e, 0x399, 0x3b1, 0x3bd, 0x3bf, 0x3c5, 0x3ac, 0x3c1, 0x3b9,
-0x3bf, 0x3c2, 0x3b, 0x3a6, 0x3b5, 0x3b2, 0x3c1, 0x3bf, 0x3c5, 0x3ac, 0x3c1, 0x3b9, 0x3bf, 0x3c2, 0x3b, 0x39c, 0x3ac, 0x3c1, 0x3c4, 0x3b9,
-0x3bf, 0x3c2, 0x3b, 0x391, 0x3c0, 0x3c1, 0x3af, 0x3bb, 0x3b9, 0x3bf, 0x3c2, 0x3b, 0x39c, 0x3ac, 0x3b9, 0x3bf, 0x3c2, 0x3b, 0x399, 0x3bf,
-0x3cd, 0x3bd, 0x3b9, 0x3bf, 0x3c2, 0x3b, 0x399, 0x3bf, 0x3cd, 0x3bb, 0x3b9, 0x3bf, 0x3c2, 0x3b, 0x391, 0x3cd, 0x3b3, 0x3bf, 0x3c5, 0x3c3,
-0x3c4, 0x3bf, 0x3c2, 0x3b, 0x3a3, 0x3b5, 0x3c0, 0x3c4, 0x3ad, 0x3bc, 0x3b2, 0x3c1, 0x3b9, 0x3bf, 0x3c2, 0x3b, 0x39f, 0x3ba, 0x3c4, 0x3ce,
-0x3b2, 0x3c1, 0x3b9, 0x3bf, 0x3c2, 0x3b, 0x39d, 0x3bf, 0x3ad, 0x3bc, 0x3b2, 0x3c1, 0x3b9, 0x3bf, 0x3c2, 0x3b, 0x394, 0x3b5, 0x3ba, 0x3ad,
-0x3bc, 0x3b2, 0x3c1, 0x3b9, 0x3bf, 0x3c2, 0x399, 0x3b1, 0x3bd, 0x3bf, 0x3c5, 0x3b1, 0x3c1, 0x3af, 0x3bf, 0x3c5, 0x3b, 0x3a6, 0x3b5, 0x3b2,
-0x3c1, 0x3bf, 0x3c5, 0x3b1, 0x3c1, 0x3af, 0x3bf, 0x3c5, 0x3b, 0x39c, 0x3b1, 0x3c1, 0x3c4, 0x3af, 0x3bf, 0x3c5, 0x3b, 0x391, 0x3c0, 0x3c1,
-0x3b9, 0x3bb, 0x3af, 0x3bf, 0x3c5, 0x3b, 0x39c, 0x3b1, 0x390, 0x3bf, 0x3c5, 0x3b, 0x399, 0x3bf, 0x3c5, 0x3bd, 0x3af, 0x3bf, 0x3c5, 0x3b,
-0x399, 0x3bf, 0x3c5, 0x3bb, 0x3af, 0x3bf, 0x3c5, 0x3b, 0x391, 0x3c5, 0x3b3, 0x3bf, 0x3cd, 0x3c3, 0x3c4, 0x3bf, 0x3c5, 0x3b, 0x3a3, 0x3b5,
-0x3c0, 0x3c4, 0x3b5, 0x3bc, 0x3b2, 0x3c1, 0x3af, 0x3bf, 0x3c5, 0x3b, 0x39f, 0x3ba, 0x3c4, 0x3c9, 0x3b2, 0x3c1, 0x3af, 0x3bf, 0x3c5, 0x3b,
-0x39d, 0x3bf, 0x3b5, 0x3bc, 0x3b2, 0x3c1, 0x3af, 0x3bf, 0x3c5, 0x3b, 0x394, 0x3b5, 0x3ba, 0x3b5, 0x3bc, 0x3b2, 0x3c1, 0x3af, 0x3bf, 0x3c5,
-0x399, 0x3b1, 0x3bd, 0x3b, 0x3a6, 0x3b5, 0x3b2, 0x3b, 0x39c, 0x3ac, 0x3c1, 0x3b, 0x391, 0x3c0, 0x3c1, 0x3b, 0x39c, 0x3ac, 0x3b9, 0x3b,
-0x399, 0x3bf, 0x3cd, 0x3bd, 0x3b, 0x399, 0x3bf, 0x3cd, 0x3bb, 0x3b, 0x391, 0x3cd, 0x3b3, 0x3b, 0x3a3, 0x3b5, 0x3c0, 0x3b, 0x39f, 0x3ba,
-0x3c4, 0x3b, 0x39d, 0x3bf, 0x3ad, 0x3b, 0x394, 0x3b5, 0x3ba, 0x399, 0x3b1, 0x3bd, 0x3b, 0x3a6, 0x3b5, 0x3b2, 0x3b, 0x39c, 0x3b1, 0x3c1,
-0x3b, 0x391, 0x3c0, 0x3c1, 0x3b, 0x39c, 0x3b1, 0x390, 0x3b, 0x399, 0x3bf, 0x3c5, 0x3bd, 0x3b, 0x399, 0x3bf, 0x3c5, 0x3bb, 0x3b, 0x391,
-0x3c5, 0x3b3, 0x3b, 0x3a3, 0x3b5, 0x3c0, 0x3b, 0x39f, 0x3ba, 0x3c4, 0x3b, 0x39d, 0x3bf, 0x3b5, 0x3b, 0x394, 0x3b5, 0x3ba, 0x399, 0x3b,
-0x3a6, 0x3b, 0x39c, 0x3b, 0x391, 0x3b, 0x39c, 0x3b, 0x399, 0x3b, 0x399, 0x3b, 0x391, 0x3b, 0x3a3, 0x3b, 0x39f, 0x3b, 0x39d, 0x3b,
-0x394, 0xa9c, 0xabe, 0xaa8, 0xacd, 0xaaf, 0xac1, 0xa86, 0xab0, 0xac0, 0x3b, 0xaab, 0xac7, 0xaac, 0xacd, 0xab0, 0xac1, 0xa86, 0xab0, 0xac0,
-0x3b, 0xaae, 0xabe, 0xab0, 0xacd, 0xa9a, 0x3b, 0xa8f, 0xaaa, 0xacd, 0xab0, 0xabf, 0xab2, 0x3b, 0xaae, 0xac7, 0x3b, 0xa9c, 0xac2, 0xaa8,
-0x3b, 0xa9c, 0xac1, 0xab2, 0xabe, 0xa88, 0x3b, 0xa91, 0xa97, 0xab8, 0xacd, 0xa9f, 0x3b, 0xab8, 0xaaa, 0xacd, 0xa9f, 0xac7, 0xaae, 0xacd,
-0xaac, 0xab0, 0x3b, 0xa91, 0xa95, 0xacd, 0xa9f, 0xacb, 0xaac, 0xab0, 0x3b, 0xaa8, 0xab5, 0xac7, 0xaae, 0xacd, 0xaac, 0xab0, 0x3b, 0xaa1,
-0xabf, 0xab8, 0xac7, 0xaae, 0xacd, 0xaac, 0xab0, 0xa9c, 0xabe, 0xaa8, 0xacd, 0xaaf, 0xac1, 0x3b, 0xaab, 0xac7, 0xaac, 0xacd, 0xab0, 0xac1,
-0x3b, 0xaae, 0xabe, 0xab0, 0xacd, 0xa9a, 0x3b, 0xa8f, 0xaaa, 0xacd, 0xab0, 0xabf, 0xab2, 0x3b, 0xaae, 0xac7, 0x3b, 0xa9c, 0xac2, 0xaa8,
-0x3b, 0xa9c, 0xac1, 0xab2, 0xabe, 0xa88, 0x3b, 0xa91, 0xa97, 0xab8, 0xacd, 0xa9f, 0x3b, 0xab8, 0xaaa, 0xacd, 0xa9f, 0xac7, 0x3b, 0xa91,
-0xa95, 0xacd, 0xa9f, 0xacb, 0x3b, 0xaa8, 0xab5, 0xac7, 0x3b, 0xaa1, 0xabf, 0xab8, 0xac7, 0xa9c, 0xabe, 0x3b, 0xaab, 0xac7, 0x3b, 0xaae,
-0xabe, 0x3b, 0xa8f, 0x3b, 0xaae, 0xac7, 0x3b, 0xa9c, 0xac2, 0x3b, 0xa9c, 0xac1, 0x3b, 0xa91, 0x3b, 0xab8, 0x3b, 0xa91, 0x3b, 0xaa8,
-0x3b, 0xaa1, 0xabf, 0x43, 0x68, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x69, 0x3b, 0x46, 0x65, 0x62, 0x75, 0x72, 0x61, 0x72, 0x69,
-0x3b, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x3b, 0x41, 0x70, 0x69, 0x72, 0x69, 0x72, 0x69, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a,
-0x75, 0x6e, 0x69, 0x3b, 0x43, 0x68, 0x75, 0x6c, 0x61, 0x69, 0x3b, 0x41, 0x67, 0x6f, 0x73, 0x74, 0x69, 0x3b, 0x53, 0x65,
-0x70, 0x74, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x4f, 0x6b, 0x69, 0x74, 0x6f, 0x62, 0x61, 0x3b, 0x4e, 0x6f, 0x62, 0x65, 0x6d,
-0x62, 0x61, 0x3b, 0x44, 0x69, 0x73, 0x65, 0x6d, 0x62, 0x61, 0x43, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61,
-0x63, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x43, 0x75, 0x6c, 0x3b, 0x41, 0x67,
-0x74, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x62, 0x3b, 0x44, 0x69, 0x73, 0x43, 0x3b, 0x46,
-0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x43, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44,
-0x4a, 0x61, 0x6e, 0x61, 0x69, 0x72, 0x75, 0x3b, 0x46, 0x61, 0x62, 0x75, 0x72, 0x61, 0x69, 0x72, 0x75, 0x3b, 0x4d, 0x61,
-0x72, 0x69, 0x73, 0x3b, 0x41, 0x66, 0x69, 0x72, 0x69, 0x6c, 0x75, 0x3b, 0x4d, 0x61, 0x79, 0x75, 0x3b, 0x59, 0x75, 0x6e,
-0x69, 0x3b, 0x59, 0x75, 0x6c, 0x69, 0x3b, 0x41, 0x67, 0x75, 0x73, 0x74, 0x61, 0x3b, 0x53, 0x61, 0x74, 0x75, 0x6d, 0x62,
-0x61, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x61, 0x3b, 0x4e, 0x75, 0x77, 0x61, 0x6d, 0x62, 0x61, 0x3b, 0x44, 0x69, 0x73,
-0x61, 0x6d, 0x62, 0x61, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x61, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x66, 0x69, 0x3b,
-0x4d, 0x61, 0x79, 0x3b, 0x59, 0x75, 0x6e, 0x3b, 0x59, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x75, 0x3b, 0x53, 0x61, 0x74, 0x3b,
-0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x75, 0x77, 0x3b, 0x44, 0x69, 0x73, 0x4a, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d,
-0x3b, 0x59, 0x3b, 0x59, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x49, 0x61, 0x6e, 0x75, 0x61, 0x6c,
-0x69, 0x3b, 0x50, 0x65, 0x70, 0x65, 0x6c, 0x75, 0x61, 0x6c, 0x69, 0x3b, 0x4d, 0x61, 0x6c, 0x61, 0x6b, 0x69, 0x3b, 0x2bb,
-0x41, 0x70, 0x65, 0x6c, 0x69, 0x6c, 0x61, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x49, 0x75, 0x6e, 0x65, 0x3b, 0x49, 0x75, 0x6c,
-0x61, 0x69, 0x3b, 0x2bb, 0x41, 0x75, 0x6b, 0x61, 0x6b, 0x65, 0x3b, 0x4b, 0x65, 0x70, 0x61, 0x6b, 0x65, 0x6d, 0x61, 0x70,
-0x61, 0x3b, 0x2bb, 0x4f, 0x6b, 0x61, 0x6b, 0x6f, 0x70, 0x61, 0x3b, 0x4e, 0x6f, 0x77, 0x65, 0x6d, 0x61, 0x70, 0x61, 0x3b,
-0x4b, 0x65, 0x6b, 0x65, 0x6d, 0x61, 0x70, 0x61, 0x49, 0x61, 0x6e, 0x2e, 0x3b, 0x50, 0x65, 0x70, 0x2e, 0x3b, 0x4d, 0x61,
-0x6c, 0x2e, 0x3b, 0x2bb, 0x41, 0x70, 0x2e, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x49, 0x75, 0x6e, 0x2e, 0x3b, 0x49, 0x75, 0x6c,
-0x2e, 0x3b, 0x2bb, 0x41, 0x75, 0x2e, 0x3b, 0x4b, 0x65, 0x70, 0x2e, 0x3b, 0x2bb, 0x4f, 0x6b, 0x2e, 0x3b, 0x4e, 0x6f, 0x77,
-0x2e, 0x3b, 0x4b, 0x65, 0x6b, 0x2e, 0x5d9, 0x5e0, 0x5d5, 0x5d0, 0x5e8, 0x3b, 0x5e4, 0x5d1, 0x5e8, 0x5d5, 0x5d0, 0x5e8, 0x3b, 0x5de,
-0x5e8, 0x5e5, 0x3b, 0x5d0, 0x5e4, 0x5e8, 0x5d9, 0x5dc, 0x3b, 0x5de, 0x5d0, 0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5e0, 0x5d9, 0x3b, 0x5d9, 0x5d5,
-0x5dc, 0x5d9, 0x3b, 0x5d0, 0x5d5, 0x5d2, 0x5d5, 0x5e1, 0x5d8, 0x3b, 0x5e1, 0x5e4, 0x5d8, 0x5de, 0x5d1, 0x5e8, 0x3b, 0x5d0, 0x5d5, 0x5e7,
-0x5d8, 0x5d5, 0x5d1, 0x5e8, 0x3b, 0x5e0, 0x5d5, 0x5d1, 0x5de, 0x5d1, 0x5e8, 0x3b, 0x5d3, 0x5e6, 0x5de, 0x5d1, 0x5e8, 0x5d9, 0x5e0, 0x5d5,
-0x5f3, 0x3b, 0x5e4, 0x5d1, 0x5e8, 0x5f3, 0x3b, 0x5de, 0x5e8, 0x5e5, 0x3b, 0x5d0, 0x5e4, 0x5e8, 0x5f3, 0x3b, 0x5de, 0x5d0, 0x5d9, 0x3b,
-0x5d9, 0x5d5, 0x5e0, 0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5dc, 0x5d9, 0x3b, 0x5d0, 0x5d5, 0x5d2, 0x5f3, 0x3b, 0x5e1, 0x5e4, 0x5d8, 0x5f3, 0x3b,
-0x5d0, 0x5d5, 0x5e7, 0x5f3, 0x3b, 0x5e0, 0x5d5, 0x5d1, 0x5f3, 0x3b, 0x5d3, 0x5e6, 0x5de, 0x5f3, 0x91c, 0x928, 0x935, 0x930, 0x940, 0x3b,
-0x92b, 0x93c, 0x930, 0x935, 0x930, 0x940, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x948, 0x932, 0x3b,
-0x92e, 0x908, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x93e, 0x908, 0x3b, 0x905, 0x917, 0x938, 0x94d, 0x924, 0x3b, 0x938,
-0x93f, 0x924, 0x902, 0x92c, 0x930, 0x3b, 0x905, 0x915, 0x94d, 0x924, 0x942, 0x92c, 0x930, 0x3b, 0x928, 0x935, 0x902, 0x92c, 0x930, 0x3b,
-0x926, 0x93f, 0x938, 0x902, 0x92c, 0x930, 0x91c, 0x928, 0x970, 0x3b, 0x92b, 0x93c, 0x930, 0x970, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a,
-0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x948, 0x932, 0x3b, 0x92e, 0x908, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x970, 0x3b,
-0x905, 0x917, 0x970, 0x3b, 0x938, 0x93f, 0x924, 0x970, 0x3b, 0x905, 0x915, 0x94d, 0x924, 0x942, 0x970, 0x3b, 0x928, 0x935, 0x970, 0x3b,
-0x926, 0x93f, 0x938, 0x970, 0x91c, 0x3b, 0x92b, 0x93c, 0x3b, 0x92e, 0x93e, 0x3b, 0x905, 0x3b, 0x92e, 0x3b, 0x91c, 0x942, 0x3b, 0x91c,
-0x941, 0x3b, 0x905, 0x3b, 0x938, 0x93f, 0x3b, 0x905, 0x3b, 0x928, 0x3b, 0x926, 0x93f, 0x6a, 0x61, 0x6e, 0x75, 0xe1, 0x72, 0x3b,
-0x66, 0x65, 0x62, 0x72, 0x75, 0xe1, 0x72, 0x3b, 0x6d, 0xe1, 0x72, 0x63, 0x69, 0x75, 0x73, 0x3b, 0xe1, 0x70, 0x72, 0x69,
-0x6c, 0x69, 0x73, 0x3b, 0x6d, 0xe1, 0x6a, 0x75, 0x73, 0x3b, 0x6a, 0xfa, 0x6e, 0x69, 0x75, 0x73, 0x3b, 0x6a, 0xfa, 0x6c,
-0x69, 0x75, 0x73, 0x3b, 0x61, 0x75, 0x67, 0x75, 0x73, 0x7a, 0x74, 0x75, 0x73, 0x3b, 0x73, 0x7a, 0x65, 0x70, 0x74, 0x65,
-0x6d, 0x62, 0x65, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0xf3, 0x62, 0x65, 0x72, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65,
-0x72, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x6a, 0x61, 0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x2e,
-0x3b, 0x6d, 0xe1, 0x72, 0x63, 0x2e, 0x3b, 0xe1, 0x70, 0x72, 0x2e, 0x3b, 0x6d, 0xe1, 0x6a, 0x2e, 0x3b, 0x6a, 0xfa, 0x6e,
-0x2e, 0x3b, 0x6a, 0xfa, 0x6c, 0x2e, 0x3b, 0x61, 0x75, 0x67, 0x2e, 0x3b, 0x73, 0x7a, 0x65, 0x70, 0x74, 0x2e, 0x3b, 0x6f,
-0x6b, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x63, 0x2e, 0x4a, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0xc1,
-0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x41, 0x3b, 0x53, 0x7a, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x6a, 0x61, 0x6e,
-0xfa, 0x61, 0x72, 0x3b, 0x66, 0x65, 0x62, 0x72, 0xfa, 0x61, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x3b, 0x61, 0x70, 0x72,
-0xed, 0x6c, 0x3b, 0x6d, 0x61, 0xed, 0x3b, 0x6a, 0xfa, 0x6e, 0xed, 0x3b, 0x6a, 0xfa, 0x6c, 0xed, 0x3b, 0xe1, 0x67, 0xfa,
-0x73, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0xf3, 0x62, 0x65, 0x72,
-0x3b, 0x6e, 0xf3, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x64, 0x65, 0x73, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x6a, 0x61,
-0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x62, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x61, 0x70, 0x72, 0x2e, 0x3b, 0x6d, 0x61,
-0xed, 0x3b, 0x6a, 0xfa, 0x6e, 0x2e, 0x3b, 0x6a, 0xfa, 0x6c, 0x2e, 0x3b, 0xe1, 0x67, 0xfa, 0x2e, 0x3b, 0x73, 0x65, 0x70,
-0x2e, 0x3b, 0x6f, 0x6b, 0x74, 0x2e, 0x3b, 0x6e, 0xf3, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x73, 0x2e, 0x4a, 0x3b, 0x46, 0x3b,
-0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0xc1, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x4a,
-0x65, 0x6e, 0x1ee5, 0x77, 0x61, 0x72, 0x1ecb, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x1ee5, 0x77, 0x61, 0x72, 0x1ecb, 0x3b, 0x4d, 0x61,
-0x61, 0x63, 0x68, 0x1ecb, 0x3b, 0x45, 0x70, 0x72, 0x65, 0x65, 0x6c, 0x3b, 0x4d, 0x65, 0x65, 0x3b, 0x4a, 0x75, 0x75, 0x6e,
-0x3b, 0x4a, 0x75, 0x6c, 0x61, 0x1ecb, 0x3b, 0x1ecc, 0x67, 0x1ecd, 0x1ecd, 0x73, 0x74, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d,
-0x62, 0x61, 0x3b, 0x1ecc, 0x6b, 0x74, 0x6f, 0x62, 0x61, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x44, 0x69,
-0x73, 0x65, 0x6d, 0x62, 0x61, 0x4a, 0x65, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x61, 0x3b, 0x45, 0x70, 0x72,
-0x3b, 0x4d, 0x65, 0x65, 0x3b, 0x4a, 0x75, 0x75, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x1ecc, 0x67, 0x1ecd, 0x3b, 0x53, 0x65, 0x70,
-0x3b, 0x1ecc, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x69, 0x73, 0x4a, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x45, 0x3b,
-0x4d, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x1ecc, 0x3b, 0x53, 0x3b, 0x1ecc, 0x3b, 0x4e, 0x3b, 0x44, 0x75, 0x111, 0x111, 0xe2, 0x69,
-0x76, 0x65, 0x6d, 0xe1, 0xe1, 0x6e, 0x75, 0x3b, 0x6b, 0x75, 0x6f, 0x76, 0xe2, 0x6d, 0xe1, 0xe1, 0x6e, 0x75, 0x3b, 0x6e,
-0x6a, 0x75, 0x68, 0x10d, 0xe2, 0x6d, 0xe1, 0xe1, 0x6e, 0x75, 0x3b, 0x63, 0x75, 0xe1, 0x14b, 0x75, 0x69, 0x6d, 0xe1, 0xe1,
-0x6e, 0x75, 0x3b, 0x76, 0x79, 0x65, 0x73, 0x69, 0x6d, 0xe1, 0xe1, 0x6e, 0x75, 0x3b, 0x6b, 0x65, 0x73, 0x69, 0x6d, 0xe1,
-0xe1, 0x6e, 0x75, 0x3b, 0x73, 0x79, 0x65, 0x69, 0x6e, 0x69, 0x6d, 0xe1, 0xe1, 0x6e, 0x75, 0x3b, 0x70, 0x6f, 0x72, 0x67,
-0x65, 0x6d, 0xe1, 0xe1, 0x6e, 0x75, 0x3b, 0x10d, 0x6f, 0x68, 0x10d, 0xe2, 0x6d, 0xe1, 0xe1, 0x6e, 0x75, 0x3b, 0x72, 0x6f,
-0x6f, 0x76, 0x76, 0xe2, 0x64, 0x6d, 0xe1, 0xe1, 0x6e, 0x75, 0x3b, 0x73, 0x6b, 0x61, 0x6d, 0x6d, 0xe2, 0x6d, 0xe1, 0xe1,
-0x6e, 0x75, 0x3b, 0x6a, 0x75, 0x6f, 0x76, 0x6c, 0xe2, 0x6d, 0xe1, 0xe1, 0x6e, 0x75, 0x75, 0x111, 0x69, 0x76, 0x3b, 0x6b,
-0x75, 0x6f, 0x76, 0xe2, 0x3b, 0x6e, 0x6a, 0x75, 0x68, 0x10d, 0xe2, 0x3b, 0x63, 0x75, 0xe1, 0x14b, 0x75, 0x69, 0x3b, 0x76,
-0x79, 0x65, 0x73, 0x69, 0x3b, 0x6b, 0x65, 0x73, 0x69, 0x3b, 0x73, 0x79, 0x65, 0x69, 0x6e, 0x69, 0x3b, 0x70, 0x6f, 0x72,
-0x67, 0x65, 0x3b, 0x10d, 0x6f, 0x68, 0x10d, 0xe2, 0x3b, 0x72, 0x6f, 0x6f, 0x76, 0x76, 0xe2, 0x64, 0x3b, 0x73, 0x6b, 0x61,
-0x6d, 0x6d, 0xe2, 0x3b, 0x6a, 0x75, 0x6f, 0x76, 0x6c, 0xe2, 0x55, 0x3b, 0x4b, 0x3b, 0x4e, 0x4a, 0x3b, 0x43, 0x3b, 0x56,
-0x3b, 0x4b, 0x3b, 0x53, 0x3b, 0x50, 0x3b, 0x10c, 0x3b, 0x52, 0x3b, 0x53, 0x3b, 0x4a, 0x4a, 0x61, 0x6e, 0x75, 0x61, 0x72,
-0x69, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x69, 0x3b, 0x4d, 0x61, 0x72, 0x65, 0x74, 0x3b, 0x41, 0x70, 0x72,
-0x69, 0x6c, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x69, 0x3b, 0x41, 0x67, 0x75,
-0x73, 0x74, 0x75, 0x73, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62,
-0x65, 0x72, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x44, 0x65, 0x73, 0x65, 0x6d, 0x62, 0x65, 0x72,
-0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x69, 0x3b,
-0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x75, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b,
-0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x73, 0x6a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x69, 0x6f, 0x3b, 0x66, 0x65, 0x62, 0x72,
-0x75, 0x61, 0x72, 0x69, 0x6f, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x69, 0x6f, 0x3b, 0x61, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x6d,
-0x61, 0x69, 0x6f, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x6f, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x6f, 0x3b, 0x61, 0x75, 0x67, 0x75,
-0x73, 0x74, 0x6f, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x6f, 0x63, 0x74, 0x6f, 0x62, 0x72,
-0x65, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x6a,
-0x61, 0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0x61, 0x69, 0x3b, 0x6a,
-0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x75, 0x67, 0x3b, 0x73, 0x65, 0x70, 0x3b, 0x6f, 0x63, 0x74, 0x3b, 0x6e,
-0x6f, 0x76, 0x3b, 0x64, 0x65, 0x63, 0x45, 0x61, 0x6e, 0xe1, 0x69, 0x72, 0x3b, 0x46, 0x65, 0x61, 0x62, 0x68, 0x72, 0x61,
-0x3b, 0x4d, 0xe1, 0x72, 0x74, 0x61, 0x3b, 0x41, 0x69, 0x62, 0x72, 0x65, 0xe1, 0x6e, 0x3b, 0x42, 0x65, 0x61, 0x6c, 0x74,
-0x61, 0x69, 0x6e, 0x65, 0x3b, 0x4d, 0x65, 0x69, 0x74, 0x68, 0x65, 0x61, 0x6d, 0x68, 0x3b, 0x49, 0xfa, 0x69, 0x6c, 0x3b,
-0x4c, 0xfa, 0x6e, 0x61, 0x73, 0x61, 0x3b, 0x4d, 0x65, 0xe1, 0x6e, 0x20, 0x46, 0xf3, 0x6d, 0x68, 0x61, 0x69, 0x72, 0x3b,
-0x44, 0x65, 0x69, 0x72, 0x65, 0x61, 0x64, 0x68, 0x20, 0x46, 0xf3, 0x6d, 0x68, 0x61, 0x69, 0x72, 0x3b, 0x53, 0x61, 0x6d,
-0x68, 0x61, 0x69, 0x6e, 0x3b, 0x4e, 0x6f, 0x6c, 0x6c, 0x61, 0x69, 0x67, 0x45, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x61, 0x62,
-0x68, 0x3b, 0x4d, 0xe1, 0x72, 0x74, 0x61, 0x3b, 0x41, 0x69, 0x62, 0x3b, 0x42, 0x65, 0x61, 0x6c, 0x3b, 0x4d, 0x65, 0x69,
-0x74, 0x68, 0x3b, 0x49, 0xfa, 0x69, 0x6c, 0x3b, 0x4c, 0xfa, 0x6e, 0x3b, 0x4d, 0x46, 0xf3, 0x6d, 0x68, 0x3b, 0x44, 0x46,
-0xf3, 0x6d, 0x68, 0x3b, 0x53, 0x61, 0x6d, 0x68, 0x3b, 0x4e, 0x6f, 0x6c, 0x6c, 0x45, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41,
-0x3b, 0x42, 0x3b, 0x4d, 0x3b, 0x49, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x44, 0x3b, 0x53, 0x3b, 0x4e, 0x67, 0x65, 0x6e, 0x6e,
-0x61, 0x69, 0x6f, 0x3b, 0x66, 0x65, 0x62, 0x62, 0x72, 0x61, 0x69, 0x6f, 0x3b, 0x6d, 0x61, 0x72, 0x7a, 0x6f, 0x3b, 0x61,
-0x70, 0x72, 0x69, 0x6c, 0x65, 0x3b, 0x6d, 0x61, 0x67, 0x67, 0x69, 0x6f, 0x3b, 0x67, 0x69, 0x75, 0x67, 0x6e, 0x6f, 0x3b,
-0x6c, 0x75, 0x67, 0x6c, 0x69, 0x6f, 0x3b, 0x61, 0x67, 0x6f, 0x73, 0x74, 0x6f, 0x3b, 0x73, 0x65, 0x74, 0x74, 0x65, 0x6d,
-0x62, 0x72, 0x65, 0x3b, 0x6f, 0x74, 0x74, 0x6f, 0x62, 0x72, 0x65, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x65,
-0x3b, 0x64, 0x69, 0x63, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x67, 0x65, 0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0x61, 0x72,
-0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0x61, 0x67, 0x3b, 0x67, 0x69, 0x75, 0x3b, 0x6c, 0x75, 0x67, 0x3b, 0x61, 0x67, 0x6f,
-0x3b, 0x73, 0x65, 0x74, 0x3b, 0x6f, 0x74, 0x74, 0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x69, 0x63, 0x47, 0x3b, 0x46, 0x3b,
-0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x47, 0x3b, 0x4c, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x4a,
-0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a,
-0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x74, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e,
-0x6f, 0x76, 0x3b, 0x44, 0x65, 0x73, 0x53, 0x61, 0x6e, 0x76, 0x69, 0x65, 0x3b, 0x46, 0xe9, 0x62, 0x69, 0x72, 0x69, 0x65,
-0x3b, 0x4d, 0x61, 0x72, 0x73, 0x3b, 0x41, 0x62, 0x75, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x65, 0x65, 0x3b, 0x53, 0x75, 0x65,
-0x14b, 0x3b, 0x53, 0xfa, 0x75, 0x79, 0x65, 0x65, 0x3b, 0x55, 0x74, 0x3b, 0x53, 0x65, 0x74, 0x74, 0x65, 0x6d, 0x62, 0x61,
-0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x61, 0x72, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x44,
-0x69, 0x73, 0x61, 0x6d, 0x62, 0x61, 0x72, 0x53, 0x61, 0x3b, 0x46, 0x65, 0x3b, 0x4d, 0x61, 0x3b, 0x41, 0x62, 0x3b, 0x4d,
-0x65, 0x3b, 0x53, 0x75, 0x3b, 0x53, 0xfa, 0x3b, 0x55, 0x74, 0x3b, 0x53, 0x65, 0x3b, 0x4f, 0x6b, 0x3b, 0x4e, 0x6f, 0x3b,
-0x44, 0x65, 0x53, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x53, 0x3b, 0x53, 0x3b, 0x55, 0x3b, 0x53, 0x3b,
-0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x4a, 0x61, 0x6e, 0x65, 0x72, 0x75, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x65, 0x72, 0x75, 0x3b,
-0x4d, 0x61, 0x72, 0x73, 0x75, 0x3b, 0x41, 0x62, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x61, 0x69, 0x75, 0x3b, 0x4a, 0x75, 0x6e,
-0x68, 0x75, 0x3b, 0x4a, 0x75, 0x6c, 0x68, 0x75, 0x3b, 0x41, 0x67, 0x6f, 0x73, 0x74, 0x75, 0x3b, 0x53, 0x65, 0x74, 0x65,
-0x6e, 0x62, 0x72, 0x75, 0x3b, 0x4f, 0x74, 0x75, 0x62, 0x72, 0x75, 0x3b, 0x4e, 0x75, 0x76, 0x65, 0x6e, 0x62, 0x72, 0x75,
-0x3b, 0x44, 0x69, 0x7a, 0x65, 0x6e, 0x62, 0x72, 0x75, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72,
-0x3b, 0x41, 0x62, 0x72, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x6f,
-0x3b, 0x53, 0x65, 0x74, 0x3b, 0x4f, 0x74, 0x75, 0x3b, 0x4e, 0x75, 0x76, 0x3b, 0x44, 0x69, 0x7a, 0x59, 0x65, 0x6e, 0x6e,
-0x61, 0x79, 0x65, 0x72, 0x3b, 0x46, 0x75, 0x1e5b, 0x61, 0x72, 0x3b, 0x4d, 0x65, 0x263, 0x72, 0x65, 0x73, 0x3b, 0x59, 0x65,
-0x62, 0x72, 0x69, 0x72, 0x3b, 0x4d, 0x61, 0x79, 0x79, 0x75, 0x3b, 0x59, 0x75, 0x6e, 0x79, 0x75, 0x3b, 0x59, 0x75, 0x6c,
-0x79, 0x75, 0x3b, 0x194, 0x75, 0x63, 0x74, 0x3b, 0x43, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x1e5b, 0x3b, 0x54, 0x75, 0x62, 0x65,
-0x1e5b, 0x3b, 0x4e, 0x75, 0x6e, 0x65, 0x6d, 0x62, 0x65, 0x1e5b, 0x3b, 0x44, 0x75, 0x1e7, 0x65, 0x6d, 0x62, 0x65, 0x1e5b, 0x59,
-0x65, 0x6e, 0x3b, 0x46, 0x75, 0x72, 0x3b, 0x4d, 0x65, 0x263, 0x3b, 0x59, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x59,
-0x75, 0x6e, 0x3b, 0x59, 0x75, 0x6c, 0x3b, 0x194, 0x75, 0x63, 0x3b, 0x43, 0x74, 0x65, 0x3b, 0x54, 0x75, 0x62, 0x3b, 0x4e,
-0x75, 0x6e, 0x3b, 0x44, 0x75, 0x1e7, 0x59, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x59, 0x3b, 0x4d, 0x3b, 0x59, 0x3b, 0x59, 0x3b,
-0x194, 0x3b, 0x43, 0x3b, 0x54, 0x3b, 0x4e, 0x3b, 0x44, 0x70, 0x61, 0x6d, 0x62, 0x61, 0x3b, 0x77, 0x61, 0x6e, 0x6a, 0x61,
-0x3b, 0x6d, 0x62, 0x69, 0x79, 0x254, 0x20, 0x6d, 0x25b, 0x6e, 0x64, 0x6f, 0x14b, 0x67, 0x254, 0x3b, 0x4e, 0x79, 0x254, 0x6c,
-0x254, 0x6d, 0x62, 0x254, 0x14b, 0x67, 0x254, 0x3b, 0x4d, 0x254, 0x6e, 0x254, 0x20, 0x14b, 0x67, 0x62, 0x61, 0x6e, 0x6a, 0x61,
-0x3b, 0x4e, 0x79, 0x61, 0x14b, 0x67, 0x77, 0x25b, 0x20, 0x14b, 0x67, 0x62, 0x61, 0x6e, 0x6a, 0x61, 0x3b, 0x6b, 0x75, 0x14b,
-0x67, 0x77, 0x25b, 0x3b, 0x66, 0x25b, 0x3b, 0x6e, 0x6a, 0x61, 0x70, 0x69, 0x3b, 0x6e, 0x79, 0x75, 0x6b, 0x75, 0x6c, 0x3b,
-0x4d, 0x31, 0x31, 0x3b, 0x253, 0x75, 0x6c, 0x253, 0x75, 0x73, 0x25b, 0x6a, 0x61, 0x6e, 0x75, 0x61, 0x61, 0x72, 0x69, 0x3b,
-0x66, 0x65, 0x62, 0x72, 0x75, 0x61, 0x61, 0x72, 0x69, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x69, 0x3b, 0x61, 0x70, 0x72, 0x69,
-0x69, 0x6c, 0x69, 0x3b, 0x6d, 0x61, 0x61, 0x6a, 0x69, 0x3b, 0x6a, 0x75, 0x75, 0x6e, 0x69, 0x3b, 0x6a, 0x75, 0x75, 0x6c,
-0x69, 0x3b, 0x61, 0x67, 0x67, 0x75, 0x73, 0x74, 0x69, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x69,
-0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x61, 0x72, 0x69, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x69, 0x3b,
-0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x69, 0x6a, 0x61, 0x6e, 0x75, 0x61, 0x61, 0x72, 0x69, 0x70, 0x3b, 0x66,
-0x65, 0x62, 0x72, 0x75, 0x61, 0x61, 0x72, 0x69, 0x70, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x69, 0x70, 0x3b, 0x61, 0x70, 0x72,
-0x69, 0x69, 0x6c, 0x69, 0x70, 0x3b, 0x6d, 0x61, 0x61, 0x6a, 0x69, 0x70, 0x3b, 0x6a, 0x75, 0x75, 0x6e, 0x69, 0x70, 0x3b,
-0x6a, 0x75, 0x75, 0x6c, 0x69, 0x70, 0x3b, 0x61, 0x67, 0x67, 0x75, 0x73, 0x74, 0x69, 0x70, 0x3b, 0x73, 0x65, 0x70, 0x74,
-0x65, 0x6d, 0x62, 0x61, 0x72, 0x69, 0x70, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x61, 0x72, 0x69, 0x70, 0x3b, 0x6e, 0x6f,
-0x76, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x69, 0x70, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x69, 0x70, 0x6a,
-0x61, 0x6e, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0x61, 0x6a, 0x3b,
-0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x75, 0x67, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x3b, 0x6f, 0x6b, 0x74,
-0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65, 0x63, 0x4d, 0x75, 0x6c, 0x67, 0x75, 0x6c, 0x3b, 0x4e, 0x67, 0x2019, 0x61, 0x74,
-0x79, 0x61, 0x61, 0x74, 0x6f, 0x3b, 0x4b, 0x69, 0x70, 0x74, 0x61, 0x61, 0x6d, 0x6f, 0x3b, 0x49, 0x77, 0x6f, 0x6f, 0x74,
-0x6b, 0x75, 0x75, 0x74, 0x3b, 0x4d, 0x61, 0x6d, 0x75, 0x75, 0x74, 0x3b, 0x50, 0x61, 0x61, 0x67, 0x69, 0x3b, 0x4e, 0x67,
-0x2019, 0x65, 0x69, 0x79, 0x65, 0x65, 0x74, 0x3b, 0x52, 0x6f, 0x6f, 0x70, 0x74, 0x75, 0x69, 0x3b, 0x42, 0x75, 0x72, 0x65,
-0x65, 0x74, 0x3b, 0x45, 0x70, 0x65, 0x65, 0x73, 0x6f, 0x3b, 0x4b, 0x69, 0x70, 0x73, 0x75, 0x75, 0x6e, 0x64, 0x65, 0x20,
-0x6e, 0x65, 0x20, 0x74, 0x61, 0x61, 0x69, 0x3b, 0x4b, 0x69, 0x70, 0x73, 0x75, 0x75, 0x6e, 0x64, 0x65, 0x20, 0x6e, 0x65,
-0x62, 0x6f, 0x20, 0x61, 0x65, 0x6e, 0x67, 0x2019, 0x4d, 0x75, 0x6c, 0x3b, 0x4e, 0x67, 0x61, 0x74, 0x3b, 0x54, 0x61, 0x61,
-0x3b, 0x49, 0x77, 0x6f, 0x3b, 0x4d, 0x61, 0x6d, 0x3b, 0x50, 0x61, 0x61, 0x3b, 0x4e, 0x67, 0x65, 0x3b, 0x52, 0x6f, 0x6f,
-0x3b, 0x42, 0x75, 0x72, 0x3b, 0x45, 0x70, 0x65, 0x3b, 0x4b, 0x70, 0x74, 0x3b, 0x4b, 0x70, 0x61, 0x4d, 0x3b, 0x4e, 0x3b,
-0x54, 0x3b, 0x49, 0x3b, 0x4d, 0x3b, 0x50, 0x3b, 0x4e, 0x3b, 0x52, 0x3b, 0x42, 0x3b, 0x45, 0x3b, 0x4b, 0x3b, 0x4b, 0x4d,
-0x77, 0x61, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6d, 0x62, 0x65, 0x65, 0x3b, 0x4d, 0x77, 0x61, 0x69, 0x20, 0x77, 0x61, 0x20,
-0x6b, 0x65, 0x6c, 0x129, 0x3b, 0x4d, 0x77, 0x61, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x74, 0x61, 0x74, 0x169, 0x3b,
-0x4d, 0x77, 0x61, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x6e, 0x61, 0x3b, 0x4d, 0x77, 0x61, 0x69, 0x20, 0x77, 0x61,
-0x20, 0x6b, 0x61, 0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x4d, 0x77, 0x61, 0x69, 0x20, 0x77, 0x61, 0x20, 0x74, 0x68, 0x61, 0x6e,
-0x74, 0x68, 0x61, 0x74, 0x169, 0x3b, 0x4d, 0x77, 0x61, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6d, 0x75, 0x6f, 0x6e, 0x7a, 0x61,
-0x3b, 0x4d, 0x77, 0x61, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6e, 0x79, 0x61, 0x61, 0x6e, 0x79, 0x61, 0x3b, 0x4d, 0x77, 0x61,
-0x69, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x65, 0x6e, 0x64, 0x61, 0x3b, 0x4d, 0x77, 0x61, 0x69, 0x20, 0x77, 0x61, 0x20, 0x129,
-0x6b, 0x75, 0x6d, 0x69, 0x3b, 0x4d, 0x77, 0x61, 0x69, 0x20, 0x77, 0x61, 0x20, 0x129, 0x6b, 0x75, 0x6d, 0x69, 0x20, 0x6e,
-0x61, 0x20, 0x129, 0x6d, 0x77, 0x65, 0x3b, 0x4d, 0x77, 0x61, 0x69, 0x20, 0x77, 0x61, 0x20, 0x129, 0x6b, 0x75, 0x6d, 0x69,
-0x20, 0x6e, 0x61, 0x20, 0x69, 0x6c, 0x129, 0x4d, 0x62, 0x65, 0x3b, 0x4b, 0x65, 0x6c, 0x3b, 0x4b, 0x74, 0x169, 0x3b, 0x4b,
-0x61, 0x6e, 0x3b, 0x4b, 0x74, 0x6e, 0x3b, 0x54, 0x68, 0x61, 0x3b, 0x4d, 0x6f, 0x6f, 0x3b, 0x4e, 0x79, 0x61, 0x3b, 0x4b,
-0x6e, 0x64, 0x3b, 0x128, 0x6b, 0x75, 0x3b, 0x128, 0x6b, 0x6d, 0x3b, 0x128, 0x6b, 0x6c, 0x4d, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b,
-0x4b, 0x3b, 0x4b, 0x3b, 0x54, 0x3b, 0x4d, 0x3b, 0x4e, 0x3b, 0x4b, 0x3b, 0x128, 0x3b, 0x128, 0x3b, 0x128, 0xc9c, 0xca8, 0xcb5,
-0xcb0, 0xcbf, 0x3b, 0xcab, 0xcc6, 0xcac, 0xccd, 0xcb0, 0xcb5, 0xcb0, 0xcbf, 0x3b, 0xcae, 0xcbe, 0xcb0, 0xccd, 0xc9a, 0xccd, 0x3b, 0xc8f,
-0xcaa, 0xccd, 0xcb0, 0xcbf, 0xcb2, 0xccd, 0x3b, 0xcae, 0xcc7, 0x3b, 0xc9c, 0xcc2, 0xca8, 0xccd, 0x3b, 0xc9c, 0xcc1, 0xcb2, 0xcc8, 0x3b,
-0xc86, 0xc97, 0xcb8, 0xccd, 0xc9f, 0xccd, 0x3b, 0xcb8, 0xcc6, 0xcaa, 0xccd, 0xc9f, 0xcc6, 0xc82, 0xcac, 0xcb0, 0xccd, 0x3b, 0xc85, 0xc95,
-0xccd, 0xc9f, 0xccb, 0xcac, 0xcb0, 0xccd, 0x3b, 0xca8, 0xcb5, 0xcc6, 0xc82, 0xcac, 0xcb0, 0xccd, 0x3b, 0xca1, 0xcbf, 0xcb8, 0xcc6, 0xc82,
-0xcac, 0xcb0, 0xccd, 0xc9c, 0xca8, 0x3b, 0xcab, 0xcc6, 0xcac, 0xccd, 0xcb0, 0x3b, 0xcae, 0xcbe, 0xcb0, 0xccd, 0xc9a, 0xccd, 0x3b, 0xc8f,
-0xcaa, 0xccd, 0xcb0, 0xcbf, 0x3b, 0xcae, 0xcc7, 0x3b, 0xc9c, 0xcc2, 0xca8, 0xccd, 0x3b, 0xc9c, 0xcc1, 0xcb2, 0xcc8, 0x3b, 0xc86, 0xc97,
-0x3b, 0xcb8, 0xcc6, 0xcaa, 0xccd, 0xc9f, 0xcc6, 0xc82, 0x3b, 0xc85, 0xc95, 0xccd, 0xc9f, 0xccb, 0x3b, 0xca8, 0xcb5, 0xcc6, 0xc82, 0x3b,
-0xca1, 0xcbf, 0xcb8, 0xcc6, 0xc82, 0xc9c, 0xca8, 0xcb5, 0xcb0, 0xcbf, 0x3b, 0xcab, 0xcc6, 0xcac, 0xccd, 0xcb0, 0xcb5, 0xcb0, 0xcbf, 0x3b,
-0xcae, 0xcbe, 0xcb0, 0xccd, 0xc9a, 0xccd, 0x3b, 0xc8f, 0xcaa, 0xccd, 0xcb0, 0xcbf, 0x3b, 0xcae, 0xcc7, 0x3b, 0xc9c, 0xcc2, 0xca8, 0xccd,
-0x3b, 0xc9c, 0xcc1, 0xcb2, 0xcc8, 0x3b, 0xc86, 0xc97, 0xcb8, 0xccd, 0xc9f, 0xccd, 0x3b, 0xcb8, 0xcc6, 0xcaa, 0xccd, 0xc9f, 0xcc6, 0xc82,
-0x3b, 0xc85, 0xc95, 0xccd, 0xc9f, 0xccb, 0x3b, 0xca8, 0xcb5, 0xcc6, 0xc82, 0x3b, 0xca1, 0xcbf, 0xcb8, 0xcc6, 0xc82, 0xc9c, 0x3b, 0xcab,
-0xcc6, 0x3b, 0xcae, 0xcbe, 0x3b, 0xc8f, 0x3b, 0xcae, 0xcc7, 0x3b, 0xc9c, 0xcc2, 0x3b, 0xc9c, 0xcc1, 0x3b, 0xc86, 0x3b, 0xcb8, 0xcc6,
-0x3b, 0xc85, 0x3b, 0xca8, 0x3b, 0xca1, 0xcbf, 0x62c, 0x646, 0x624, 0x631, 0x6cc, 0x3b, 0x641, 0x631, 0x624, 0x631, 0x6cc, 0x3b, 0x645,
-0x627, 0x631, 0x655, 0x686, 0x3b, 0x627, 0x67e, 0x631, 0x6cc, 0x644, 0x3b, 0x645, 0x626, 0x6cc, 0x3b, 0x62c, 0x648, 0x657, 0x646, 0x3b,
-0x62c, 0x648, 0x657, 0x644, 0x627, 0x6cc, 0x6cc, 0x3b, 0x627, 0x6af, 0x633, 0x62a, 0x3b, 0x633, 0x62a, 0x645, 0x628, 0x631, 0x3b, 0x627,
-0x6a9, 0x62a, 0x648, 0x657, 0x628, 0x631, 0x3b, 0x646, 0x648, 0x645, 0x628, 0x631, 0x3b, 0x62f, 0x633, 0x645, 0x628, 0x631, 0x62c, 0x3b,
-0x641, 0x3b, 0x645, 0x3b, 0x627, 0x3b, 0x645, 0x3b, 0x62c, 0x3b, 0x62c, 0x3b, 0x627, 0x3b, 0x633, 0x3b, 0x633, 0x3b, 0x627, 0x3b,
-0x646, 0x91c, 0x928, 0x935, 0x930, 0x940, 0x3b, 0x92b, 0x93c, 0x930, 0x935, 0x930, 0x940, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b,
-0x905, 0x92a, 0x94d, 0x930, 0x948, 0x932, 0x3b, 0x92e, 0x947, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x93e, 0x908, 0x3b,
-0x905, 0x917, 0x938, 0x94d, 0x924, 0x3b, 0x938, 0x924, 0x941, 0x902, 0x92c, 0x930, 0x3b, 0x905, 0x915, 0x924, 0x941, 0x92e, 0x94d, 0x92c,
-0x930, 0x3b, 0x928, 0x935, 0x942, 0x92e, 0x92c, 0x930, 0x3b, 0x926, 0x938, 0x942, 0x92e, 0x92c, 0x930, 0x91c, 0x3b, 0x92b, 0x93c, 0x3b,
-0x92e, 0x3b, 0x905, 0x3b, 0x92e, 0x3b, 0x91c, 0x3b, 0x91c, 0x3b, 0x905, 0x3b, 0x938, 0x3b, 0x913, 0x3b, 0x928, 0x3b, 0x926, 0x49a,
-0x430, 0x4a3, 0x442, 0x430, 0x440, 0x3b, 0x410, 0x49b, 0x43f, 0x430, 0x43d, 0x3b, 0x41d, 0x430, 0x443, 0x440, 0x44b, 0x437, 0x3b, 0x421,
-0x4d9, 0x443, 0x456, 0x440, 0x3b, 0x41c, 0x430, 0x43c, 0x44b, 0x440, 0x3b, 0x41c, 0x430, 0x443, 0x441, 0x44b, 0x43c, 0x3b, 0x428, 0x456,
-0x43b, 0x434, 0x435, 0x3b, 0x422, 0x430, 0x43c, 0x44b, 0x437, 0x3b, 0x49a, 0x44b, 0x440, 0x43a, 0x4af, 0x439, 0x435, 0x43a, 0x3b, 0x49a,
-0x430, 0x437, 0x430, 0x43d, 0x3b, 0x49a, 0x430, 0x440, 0x430, 0x448, 0x430, 0x3b, 0x416, 0x435, 0x43b, 0x442, 0x43e, 0x49b, 0x441, 0x430,
-0x43d, 0x49b, 0x430, 0x4a3, 0x442, 0x430, 0x440, 0x3b, 0x430, 0x49b, 0x43f, 0x430, 0x43d, 0x3b, 0x43d, 0x430, 0x443, 0x440, 0x44b, 0x437,
-0x3b, 0x441, 0x4d9, 0x443, 0x456, 0x440, 0x3b, 0x43c, 0x430, 0x43c, 0x44b, 0x440, 0x3b, 0x43c, 0x430, 0x443, 0x441, 0x44b, 0x43c, 0x3b,
-0x448, 0x456, 0x43b, 0x434, 0x435, 0x3b, 0x442, 0x430, 0x43c, 0x44b, 0x437, 0x3b, 0x49b, 0x44b, 0x440, 0x43a, 0x4af, 0x439, 0x435, 0x43a,
-0x3b, 0x49b, 0x430, 0x437, 0x430, 0x43d, 0x3b, 0x49b, 0x430, 0x440, 0x430, 0x448, 0x430, 0x3b, 0x436, 0x435, 0x43b, 0x442, 0x43e, 0x49b,
-0x441, 0x430, 0x43d, 0x49b, 0x430, 0x4a3, 0x2e, 0x3b, 0x430, 0x49b, 0x43f, 0x2e, 0x3b, 0x43d, 0x430, 0x443, 0x2e, 0x3b, 0x441, 0x4d9,
-0x443, 0x2e, 0x3b, 0x43c, 0x430, 0x43c, 0x2e, 0x3b, 0x43c, 0x430, 0x443, 0x2e, 0x3b, 0x448, 0x456, 0x43b, 0x2e, 0x3b, 0x442, 0x430,
-0x43c, 0x2e, 0x3b, 0x49b, 0x44b, 0x440, 0x2e, 0x3b, 0x49b, 0x430, 0x437, 0x2e, 0x3b, 0x49b, 0x430, 0x440, 0x2e, 0x3b, 0x436, 0x435,
-0x43b, 0x2e, 0x49a, 0x3b, 0x410, 0x3b, 0x41d, 0x3b, 0x421, 0x3b, 0x41c, 0x3b, 0x41c, 0x3b, 0x428, 0x3b, 0x422, 0x3b, 0x49a, 0x3b,
-0x49a, 0x3b, 0x49a, 0x3b, 0x416, 0x1798, 0x1780, 0x179a, 0x17b6, 0x3b, 0x1780, 0x17bb, 0x1798, 0x17d2, 0x1797, 0x17c8, 0x3b, 0x1798, 0x17b8, 0x1793,
-0x17b6, 0x3b, 0x1798, 0x17c1, 0x179f, 0x17b6, 0x3b, 0x17a7, 0x179f, 0x1797, 0x17b6, 0x3b, 0x1798, 0x17b7, 0x1790, 0x17bb, 0x1793, 0x17b6, 0x3b, 0x1780,
-0x1780, 0x17d2, 0x1780, 0x178a, 0x17b6, 0x3b, 0x179f, 0x17b8, 0x17a0, 0x17b6, 0x3b, 0x1780, 0x1789, 0x17d2, 0x1789, 0x17b6, 0x3b, 0x178f, 0x17bb, 0x179b,
-0x17b6, 0x3b, 0x179c, 0x17b7, 0x1785, 0x17d2, 0x1786, 0x17b7, 0x1780, 0x17b6, 0x3b, 0x1792, 0x17d2, 0x1793, 0x17bc, 0x1798, 0x3b, 0x1780, 0x3b, 0x1798,
-0x3b, 0x1798, 0x3b, 0x17a7, 0x3b, 0x1798, 0x3b, 0x1780, 0x3b, 0x179f, 0x3b, 0x1780, 0x3b, 0x178f, 0x3b, 0x179c, 0x3b, 0x1792, 0x4e, 0x6a,
-0x65, 0x6e, 0x75, 0x61, 0x72, 0x129, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x65, 0x72, 0x129,
-0x3b, 0x4d, 0x77, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x20, 0x67, 0x61, 0x74, 0x61, 0x74, 0x169, 0x3b, 0x4d, 0x77, 0x65,
-0x72, 0x65, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x6e, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x20,
-0x67, 0x61, 0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x20, 0x67, 0x61, 0x74, 0x61,
-0x6e, 0x64, 0x61, 0x74, 0x169, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x20, 0x6d, 0x169, 0x67, 0x77, 0x61,
-0x6e, 0x6a, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x3b,
-0x4d, 0x77, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x65, 0x6e, 0x64, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x65,
-0x20, 0x77, 0x61, 0x20, 0x69, 0x6b, 0x169, 0x6d, 0x69, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x20, 0x69,
-0x6b, 0x169, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x169, 0x6d, 0x77, 0x65, 0x3b, 0x4e, 0x64, 0x69, 0x74, 0x68, 0x65, 0x6d,
-0x62, 0x61, 0x4a, 0x45, 0x4e, 0x3b, 0x57, 0x4b, 0x52, 0x3b, 0x57, 0x47, 0x54, 0x3b, 0x57, 0x4b, 0x4e, 0x3b, 0x57, 0x54,
-0x4e, 0x3b, 0x57, 0x54, 0x44, 0x3b, 0x57, 0x4d, 0x4a, 0x3b, 0x57, 0x4e, 0x4e, 0x3b, 0x57, 0x4b, 0x44, 0x3b, 0x57, 0x49,
-0x4b, 0x3b, 0x57, 0x4d, 0x57, 0x3b, 0x44, 0x49, 0x54, 0x4a, 0x3b, 0x4b, 0x3b, 0x47, 0x3b, 0x4b, 0x3b, 0x47, 0x3b, 0x47,
-0x3b, 0x4d, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x49, 0x3b, 0x49, 0x3b, 0x44, 0x4d, 0x75, 0x74, 0x61, 0x72, 0x61, 0x6d, 0x61,
-0x3b, 0x47, 0x61, 0x73, 0x68, 0x79, 0x61, 0x6e, 0x74, 0x61, 0x72, 0x65, 0x3b, 0x57, 0x65, 0x72, 0x75, 0x72, 0x77, 0x65,
-0x3b, 0x4d, 0x61, 0x74, 0x61, 0x3b, 0x47, 0x69, 0x63, 0x75, 0x72, 0x61, 0x73, 0x69, 0x3b, 0x4b, 0x61, 0x6d, 0x65, 0x6e,
-0x61, 0x3b, 0x4e, 0x79, 0x61, 0x6b, 0x61, 0x6e, 0x67, 0x61, 0x3b, 0x4b, 0x61, 0x6e, 0x61, 0x6d, 0x61, 0x3b, 0x4e, 0x7a,
-0x65, 0x6c, 0x69, 0x3b, 0x55, 0x6b, 0x77, 0x61, 0x6b, 0x69, 0x72, 0x61, 0x3b, 0x55, 0x67, 0x75, 0x73, 0x68, 0x79, 0x69,
-0x6e, 0x67, 0x6f, 0x3b, 0x55, 0x6b, 0x75, 0x62, 0x6f, 0x7a, 0x61, 0x6d, 0x75, 0x74, 0x2e, 0x3b, 0x67, 0x61, 0x73, 0x2e,
-0x3b, 0x77, 0x65, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x74, 0x2e, 0x3b, 0x67, 0x69, 0x63, 0x2e, 0x3b, 0x6b, 0x61, 0x6d, 0x2e,
-0x3b, 0x6e, 0x79, 0x61, 0x2e, 0x3b, 0x6b, 0x61, 0x6e, 0x2e, 0x3b, 0x6e, 0x7a, 0x65, 0x2e, 0x3b, 0x75, 0x6b, 0x77, 0x2e,
-0x3b, 0x75, 0x67, 0x75, 0x2e, 0x3b, 0x75, 0x6b, 0x75, 0x2e, 0x91c, 0x93e, 0x928, 0x947, 0x935, 0x93e, 0x930, 0x940, 0x3b, 0x92b,
-0x947, 0x92c, 0x94d, 0x930, 0x941, 0x935, 0x93e, 0x930, 0x940, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x90f, 0x92a, 0x94d, 0x930,
-0x940, 0x932, 0x3b, 0x92e, 0x947, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x92f, 0x3b, 0x911, 0x917, 0x938, 0x94d, 0x91f,
-0x3b, 0x938, 0x92a, 0x94d, 0x91f, 0x947, 0x902, 0x92c, 0x930, 0x3b, 0x911, 0x915, 0x94d, 0x91f, 0x94b, 0x92c, 0x930, 0x3b, 0x928, 0x94b,
-0x935, 0x94d, 0x939, 0x947, 0x902, 0x92c, 0x930, 0x3b, 0x921, 0x93f, 0x938, 0x947, 0x902, 0x92c, 0x930, 0x91c, 0x93e, 0x928, 0x947, 0x3b,
-0x92b, 0x947, 0x92c, 0x94d, 0x930, 0x941, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x90f, 0x92a, 0x94d, 0x930, 0x940, 0x3b, 0x92e,
-0x947, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x3b, 0x911, 0x917, 0x3b, 0x938, 0x92a, 0x94d, 0x91f, 0x947, 0x902, 0x3b,
-0x911, 0x915, 0x94d, 0x91f, 0x94b, 0x3b, 0x928, 0x94b, 0x3b, 0x921, 0x93f, 0x938, 0x947, 0x31, 0xc6d4, 0x3b, 0x32, 0xc6d4, 0x3b, 0x33,
-0xc6d4, 0x3b, 0x34, 0xc6d4, 0x3b, 0x35, 0xc6d4, 0x3b, 0x36, 0xc6d4, 0x3b, 0x37, 0xc6d4, 0x3b, 0x38, 0xc6d4, 0x3b, 0x39, 0xc6d4, 0x3b,
-0x31, 0x30, 0xc6d4, 0x3b, 0x31, 0x31, 0xc6d4, 0x3b, 0x31, 0x32, 0xc6d4, 0x17d, 0x61, 0x6e, 0x77, 0x69, 0x79, 0x65, 0x3b, 0x46,
-0x65, 0x65, 0x77, 0x69, 0x72, 0x69, 0x79, 0x65, 0x3b, 0x4d, 0x61, 0x72, 0x73, 0x69, 0x3b, 0x41, 0x77, 0x69, 0x72, 0x69,
-0x6c, 0x3b, 0x4d, 0x65, 0x3b, 0x17d, 0x75, 0x77, 0x65, 0x14b, 0x3b, 0x17d, 0x75, 0x79, 0x79, 0x65, 0x3b, 0x55, 0x74, 0x3b,
-0x53, 0x65, 0x6b, 0x74, 0x61, 0x6e, 0x62, 0x75, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x6f, 0x62, 0x75, 0x72, 0x3b, 0x4e,
-0x6f, 0x6f, 0x77, 0x61, 0x6e, 0x62, 0x75, 0x72, 0x3b, 0x44, 0x65, 0x65, 0x73, 0x61, 0x6e, 0x62, 0x75, 0x72, 0x17d, 0x61,
-0x6e, 0x3b, 0x46, 0x65, 0x65, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x77, 0x69, 0x3b, 0x4d, 0x65, 0x3b, 0x17d, 0x75, 0x77,
-0x3b, 0x17d, 0x75, 0x79, 0x3b, 0x55, 0x74, 0x3b, 0x53, 0x65, 0x6b, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x6f, 0x3b,
-0x44, 0x65, 0x65, 0x17d, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x17d, 0x3b, 0x17d, 0x3b, 0x55, 0x3b, 0x53,
-0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x72, 0xea, 0x62, 0x65, 0x6e, 0x64, 0x61, 0x6e, 0x3b, 0x72, 0x65, 0x15f, 0x65, 0x6d,
-0xee, 0x3b, 0x61, 0x64, 0x61, 0x72, 0x3b, 0x61, 0x76, 0x72, 0xea, 0x6c, 0x3b, 0x67, 0x75, 0x6c, 0x61, 0x6e, 0x3b, 0x70,
-0xfb, 0x15f, 0x70, 0x65, 0x72, 0x3b, 0x74, 0xee, 0x72, 0x6d, 0x65, 0x68, 0x3b, 0x67, 0x65, 0x6c, 0x61, 0x77, 0xea, 0x6a,
-0x3b, 0x72, 0x65, 0x7a, 0x62, 0x65, 0x72, 0x3b, 0x6b, 0x65, 0x77, 0xe7, 0xea, 0x72, 0x3b, 0x73, 0x65, 0x72, 0x6d, 0x61,
-0x77, 0x65, 0x7a, 0x3b, 0x62, 0x65, 0x72, 0x66, 0x61, 0x6e, 0x62, 0x61, 0x72, 0x72, 0xea, 0x62, 0x65, 0x6e, 0x64, 0x61,
-0x6e, 0xea, 0x3b, 0x72, 0x65, 0x15f, 0x65, 0x6d, 0x69, 0x79, 0xea, 0x3b, 0x61, 0x64, 0x61, 0x72, 0xea, 0x3b, 0x61, 0x76,
-0x72, 0xea, 0x6c, 0xea, 0x3b, 0x67, 0x75, 0x6c, 0x61, 0x6e, 0xea, 0x3b, 0x70, 0xfb, 0x15f, 0x70, 0x65, 0x72, 0xea, 0x3b,
-0x74, 0xee, 0x72, 0x6d, 0x65, 0x68, 0xea, 0x3b, 0x67, 0x65, 0x6c, 0x61, 0x77, 0xea, 0x6a, 0xea, 0x3b, 0x72, 0x65, 0x7a,
-0x62, 0x65, 0x72, 0xea, 0x3b, 0x6b, 0x65, 0x77, 0xe7, 0xea, 0x72, 0xea, 0x3b, 0x73, 0x65, 0x72, 0x6d, 0x61, 0x77, 0x65,
-0x7a, 0xea, 0x3b, 0x62, 0x65, 0x72, 0x66, 0x61, 0x6e, 0x62, 0x61, 0x72, 0xea, 0x72, 0xea, 0x62, 0x3b, 0x72, 0x65, 0x15f,
-0x3b, 0x61, 0x64, 0x61, 0x3b, 0x61, 0x76, 0x72, 0x3b, 0x67, 0x75, 0x6c, 0x3b, 0x70, 0xfb, 0x15f, 0x3b, 0x74, 0xee, 0x72,
-0x3b, 0x67, 0x65, 0x6c, 0x3b, 0x72, 0x65, 0x7a, 0x3b, 0x6b, 0x65, 0x77, 0x3b, 0x73, 0x65, 0x72, 0x3b, 0x62, 0x65, 0x72,
-0x52, 0x3b, 0x52, 0x3b, 0x41, 0x3b, 0x41, 0x3b, 0x47, 0x3b, 0x50, 0x3b, 0x54, 0x3b, 0x47, 0x3b, 0x52, 0x3b, 0x4b, 0x3b,
-0x53, 0x3b, 0x42, 0x6e, 0x67, 0x77, 0x25b, 0x6e, 0x20, 0x6d, 0x61, 0x74, 0xe1, 0x68, 0x72, 0x61, 0x3b, 0x6e, 0x67, 0x77,
-0x25b, 0x6e, 0x20, 0x144, 0x6d, 0x62, 0x61, 0x3b, 0x6e, 0x67, 0x77, 0x25b, 0x6e, 0x20, 0x144, 0x6c, 0x61, 0x6c, 0x3b, 0x6e,
-0x67, 0x77, 0x25b, 0x6e, 0x20, 0x144, 0x6e, 0x61, 0x3b, 0x6e, 0x67, 0x77, 0x25b, 0x6e, 0x20, 0x144, 0x74, 0x61, 0x6e, 0x3b,
-0x6e, 0x67, 0x77, 0x25b, 0x6e, 0x20, 0x144, 0x74, 0x75, 0xf3, 0x3b, 0x6e, 0x67, 0x77, 0x25b, 0x6e, 0x20, 0x68, 0x25b, 0x6d,
-0x62, 0x75, 0x25b, 0x72, 0xed, 0x3b, 0x6e, 0x67, 0x77, 0x25b, 0x6e, 0x20, 0x6c, 0x254, 0x6d, 0x62, 0x69, 0x3b, 0x6e, 0x67,
-0x77, 0x25b, 0x6e, 0x20, 0x72, 0x25b, 0x62, 0x76, 0x75, 0xe2, 0x3b, 0x6e, 0x67, 0x77, 0x25b, 0x6e, 0x20, 0x77, 0x75, 0x6d,
-0x3b, 0x6e, 0x67, 0x77, 0x25b, 0x6e, 0x20, 0x77, 0x75, 0x6d, 0x20, 0x6e, 0x61, 0x76, 0x1d4, 0x72, 0x3b, 0x6b, 0x72, 0xed,
-0x73, 0x69, 0x6d, 0x69, 0x6e, 0x6e, 0x67, 0x31, 0x3b, 0x6e, 0x67, 0x32, 0x3b, 0x6e, 0x67, 0x33, 0x3b, 0x6e, 0x67, 0x34,
-0x3b, 0x6e, 0x67, 0x35, 0x3b, 0x6e, 0x67, 0x36, 0x3b, 0x6e, 0x67, 0x37, 0x3b, 0x6e, 0x67, 0x38, 0x3b, 0x6e, 0x67, 0x39,
-0x3b, 0x6e, 0x67, 0x31, 0x30, 0x3b, 0x6e, 0x67, 0x31, 0x31, 0x3b, 0x6b, 0x72, 0x69, 0x73, 0x42f, 0x43d, 0x432, 0x430, 0x440,
-0x44c, 0x3b, 0x424, 0x435, 0x432, 0x440, 0x430, 0x43b, 0x44c, 0x3b, 0x41c, 0x430, 0x440, 0x442, 0x3b, 0x410, 0x43f, 0x440, 0x435, 0x43b,
-0x44c, 0x3b, 0x41c, 0x430, 0x439, 0x3b, 0x418, 0x44e, 0x43d, 0x44c, 0x3b, 0x418, 0x44e, 0x43b, 0x44c, 0x3b, 0x410, 0x432, 0x433, 0x443,
-0x441, 0x442, 0x3b, 0x421, 0x435, 0x43d, 0x442, 0x44f, 0x431, 0x440, 0x44c, 0x3b, 0x41e, 0x43a, 0x442, 0x44f, 0x431, 0x440, 0x44c, 0x3b,
-0x41d, 0x43e, 0x44f, 0x431, 0x440, 0x44c, 0x3b, 0x414, 0x435, 0x43a, 0x430, 0x431, 0x440, 0x44c, 0x42f, 0x43d, 0x432, 0x3b, 0x424, 0x435,
-0x432, 0x3b, 0x41c, 0x430, 0x440, 0x3b, 0x410, 0x43f, 0x440, 0x3b, 0x41c, 0x430, 0x439, 0x3b, 0x418, 0x44e, 0x43d, 0x3b, 0x418, 0x44e,
-0x43b, 0x3b, 0x410, 0x432, 0x433, 0x3b, 0x421, 0x435, 0x43d, 0x3b, 0x41e, 0x43a, 0x442, 0x3b, 0x41d, 0x43e, 0x44f, 0x3b, 0x414, 0x435,
-0x43a, 0x44f, 0x43d, 0x432, 0x2e, 0x3b, 0x444, 0x435, 0x432, 0x2e, 0x3b, 0x43c, 0x430, 0x440, 0x2e, 0x3b, 0x430, 0x43f, 0x440, 0x2e,
-0x3b, 0x43c, 0x430, 0x439, 0x3b, 0x438, 0x44e, 0x43d, 0x2e, 0x3b, 0x438, 0x44e, 0x43b, 0x2e, 0x3b, 0x430, 0x432, 0x433, 0x2e, 0x3b,
-0x441, 0x435, 0x43d, 0x2e, 0x3b, 0x43e, 0x43a, 0x442, 0x2e, 0x3b, 0x43d, 0x43e, 0x44f, 0x2e, 0x3b, 0x434, 0x435, 0x43a, 0x2e, 0x57,
-0x69, 0xf3, 0x74, 0x68, 0x65, 0x21f, 0x69, 0x6b, 0x61, 0x20, 0x57, 0xed, 0x3b, 0x54, 0x68, 0x69, 0x79, 0xf3, 0x21f, 0x65,
-0x79, 0x75, 0x14b, 0x6b, 0x61, 0x20, 0x57, 0xed, 0x3b, 0x49, 0x161, 0x74, 0xe1, 0x77, 0x69, 0x10d, 0x68, 0x61, 0x79, 0x61,
-0x7a, 0x61, 0x14b, 0x20, 0x57, 0xed, 0x3b, 0x50, 0x21f, 0x65, 0x17e, 0xed, 0x74, 0x21f, 0x6f, 0x20, 0x57, 0xed, 0x3b, 0x10c,
-0x68, 0x61, 0x14b, 0x77, 0xe1, 0x70, 0x65, 0x74, 0x21f, 0x6f, 0x20, 0x57, 0xed, 0x3b, 0x57, 0xed, 0x70, 0x61, 0x7a, 0x75,
-0x6b, 0x21f, 0x61, 0x2d, 0x77, 0x61, 0x161, 0x74, 0xe9, 0x20, 0x57, 0xed, 0x3b, 0x10c, 0x68, 0x61, 0x14b, 0x70, 0x21f, 0xe1,
-0x73, 0x61, 0x70, 0x61, 0x20, 0x57, 0xed, 0x3b, 0x57, 0x61, 0x73, 0xfa, 0x74, 0x21f, 0x75, 0x14b, 0x20, 0x57, 0xed, 0x3b,
-0x10c, 0x68, 0x61, 0x14b, 0x77, 0xe1, 0x70, 0x65, 0x1e7, 0x69, 0x20, 0x57, 0xed, 0x3b, 0x10c, 0x68, 0x61, 0x14b, 0x77, 0xe1,
-0x70, 0x65, 0x2d, 0x6b, 0x61, 0x73, 0x6e, 0xe1, 0x20, 0x57, 0xed, 0x3b, 0x57, 0x61, 0x6e, 0xed, 0x79, 0x65, 0x74, 0x75,
-0x20, 0x57, 0xed, 0x3b, 0x54, 0x21f, 0x61, 0x68, 0xe9, 0x6b, 0x61, 0x70, 0x161, 0x75, 0x14b, 0x20, 0x57, 0xed, 0x4b, 0x289,
-0x66, 0xfa, 0x6e, 0x67, 0x61, 0x74, 0x268, 0x3b, 0x4b, 0x289, 0x6e, 0x61, 0x61, 0x6e, 0x268, 0x3b, 0x4b, 0x289, 0x6b, 0x65,
-0x65, 0x6e, 0x64, 0x61, 0x3b, 0x4b, 0x77, 0x69, 0x69, 0x6b, 0x75, 0x6d, 0x69, 0x3b, 0x4b, 0x77, 0x69, 0x69, 0x6e, 0x79,
-0x61, 0x6d, 0x62, 0xe1, 0x6c, 0x61, 0x3b, 0x4b, 0x77, 0x69, 0x69, 0x64, 0x77, 0x61, 0x61, 0x74, 0x61, 0x3b, 0x4b, 0x289,
-0x6d, 0x289, 0x289, 0x6e, 0x63, 0x68, 0x268, 0x3b, 0x4b, 0x289, 0x76, 0x268, 0x268, 0x72, 0x268, 0x3b, 0x4b, 0x289, 0x73, 0x61,
-0x61, 0x74, 0x289, 0x3b, 0x4b, 0x77, 0x69, 0x69, 0x6e, 0x79, 0x69, 0x3b, 0x4b, 0x289, 0x73, 0x61, 0x61, 0x6e, 0x6f, 0x3b,
-0x4b, 0x289, 0x73, 0x61, 0x73, 0x61, 0x74, 0x289, 0x46, 0xfa, 0x6e, 0x67, 0x61, 0x74, 0x268, 0x3b, 0x4e, 0x61, 0x61, 0x6e,
-0x268, 0x3b, 0x4b, 0x65, 0x65, 0x6e, 0x64, 0x61, 0x3b, 0x49, 0x6b, 0xfa, 0x6d, 0x69, 0x3b, 0x49, 0x6e, 0x79, 0x61, 0x6d,
-0x62, 0x61, 0x6c, 0x61, 0x3b, 0x49, 0x64, 0x77, 0x61, 0x61, 0x74, 0x61, 0x3b, 0x4d, 0x289, 0x289, 0x6e, 0x63, 0x68, 0x268,
-0x3b, 0x56, 0x268, 0x268, 0x72, 0x268, 0x3b, 0x53, 0x61, 0x61, 0x74, 0x289, 0x3b, 0x49, 0x6e, 0x79, 0x69, 0x3b, 0x53, 0x61,
-0x61, 0x6e, 0x6f, 0x3b, 0x53, 0x61, 0x73, 0x61, 0x74, 0x289, 0x46, 0x3b, 0x4e, 0x3b, 0x4b, 0x3b, 0x49, 0x3b, 0x49, 0x3b,
-0x49, 0x3b, 0x4d, 0x3b, 0x56, 0x3b, 0x53, 0x3b, 0x49, 0x3b, 0x53, 0x3b, 0x53, 0xea1, 0xeb1, 0xe87, 0xe81, 0xead, 0xe99, 0x3b,
-0xe81, 0xeb8, 0xea1, 0xe9e, 0xeb2, 0x3b, 0xea1, 0xeb5, 0xe99, 0xeb2, 0x3b, 0xec0, 0xea1, 0xeaa, 0xeb2, 0x3b, 0xe9e, 0xeb6, 0xe94, 0xeaa,
-0xeb0, 0xe9e, 0xeb2, 0x3b, 0xea1, 0xeb4, 0xe96, 0xeb8, 0xe99, 0xeb2, 0x3b, 0xe81, 0xecd, 0xea5, 0xeb0, 0xe81, 0xebb, 0xe94, 0x3b, 0xeaa,
-0xeb4, 0xe87, 0xeab, 0xeb2, 0x3b, 0xe81, 0xeb1, 0xe99, 0xe8d, 0xeb2, 0x3b, 0xe95, 0xeb8, 0xea5, 0xeb2, 0x3b, 0xe9e, 0xeb0, 0xe88, 0xeb4,
-0xe81, 0x3b, 0xe97, 0xeb1, 0xe99, 0xea7, 0xeb2, 0xea1, 0x2e, 0xe81, 0x2e, 0x3b, 0xe81, 0x2e, 0xe9e, 0x2e, 0x3b, 0xea1, 0x2e, 0xe99,
-0x2e, 0x3b, 0xea1, 0x2e, 0xeaa, 0x2e, 0x3b, 0xe9e, 0x2e, 0xe9e, 0x2e, 0x3b, 0xea1, 0xeb4, 0x2e, 0xe96, 0x2e, 0x3b, 0xe81, 0x2e,
-0xea5, 0x2e, 0x3b, 0xeaa, 0x2e, 0xeab, 0x2e, 0x3b, 0xe81, 0x2e, 0xe8d, 0x2e, 0x3b, 0xe95, 0x2e, 0xea5, 0x2e, 0x3b, 0xe9e, 0x2e,
-0xe88, 0x2e, 0x3b, 0xe97, 0x2e, 0xea7, 0x2e, 0x6a, 0x61, 0x6e, 0x76, 0x101, 0x72, 0x69, 0x73, 0x3b, 0x66, 0x65, 0x62, 0x72,
-0x75, 0x101, 0x72, 0x69, 0x73, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x73, 0x3b, 0x61, 0x70, 0x72, 0x12b, 0x6c, 0x69, 0x73, 0x3b,
-0x6d, 0x61, 0x69, 0x6a, 0x73, 0x3b, 0x6a, 0x16b, 0x6e, 0x69, 0x6a, 0x73, 0x3b, 0x6a, 0x16b, 0x6c, 0x69, 0x6a, 0x73, 0x3b,
-0x61, 0x75, 0x67, 0x75, 0x73, 0x74, 0x73, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x69, 0x73, 0x3b, 0x6f,
-0x6b, 0x74, 0x6f, 0x62, 0x72, 0x69, 0x73, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x69, 0x73, 0x3b, 0x64, 0x65,
-0x63, 0x65, 0x6d, 0x62, 0x72, 0x69, 0x73, 0x6a, 0x61, 0x6e, 0x76, 0x2e, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x2e, 0x3b, 0x6d,
-0x61, 0x72, 0x74, 0x73, 0x3b, 0x61, 0x70, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x69, 0x6a, 0x73, 0x3b, 0x6a, 0x16b, 0x6e, 0x2e,
-0x3b, 0x6a, 0x16b, 0x6c, 0x2e, 0x3b, 0x61, 0x75, 0x67, 0x2e, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x2e, 0x3b, 0x6f, 0x6b, 0x74,
-0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x63, 0x2e, 0x73, 0xe1, 0x6e, 0x7a, 0xe1, 0x20, 0x79, 0x61, 0x20,
-0x79, 0x61, 0x6d, 0x62, 0x6f, 0x3b, 0x73, 0xe1, 0x6e, 0x7a, 0xe1, 0x20, 0x79, 0x61, 0x20, 0x6d, 0xed, 0x62, 0x61, 0x6c,
-0xe9, 0x3b, 0x73, 0xe1, 0x6e, 0x7a, 0xe1, 0x20, 0x79, 0x61, 0x20, 0x6d, 0xed, 0x73, 0xe1, 0x74, 0x6f, 0x3b, 0x73, 0xe1,
-0x6e, 0x7a, 0xe1, 0x20, 0x79, 0x61, 0x20, 0x6d, 0xed, 0x6e, 0x65, 0x69, 0x3b, 0x73, 0xe1, 0x6e, 0x7a, 0xe1, 0x20, 0x79,
-0x61, 0x20, 0x6d, 0xed, 0x74, 0xe1, 0x6e, 0x6f, 0x3b, 0x73, 0xe1, 0x6e, 0x7a, 0xe1, 0x20, 0x79, 0x61, 0x20, 0x6d, 0x6f,
-0x74, 0xf3, 0x62, 0xe1, 0x3b, 0x73, 0xe1, 0x6e, 0x7a, 0xe1, 0x20, 0x79, 0x61, 0x20, 0x6e, 0x73, 0x61, 0x6d, 0x62, 0x6f,
-0x3b, 0x73, 0xe1, 0x6e, 0x7a, 0xe1, 0x20, 0x79, 0x61, 0x20, 0x6d, 0x77, 0x61, 0x6d, 0x62, 0x65, 0x3b, 0x73, 0xe1, 0x6e,
-0x7a, 0xe1, 0x20, 0x79, 0x61, 0x20, 0x6c, 0x69, 0x62, 0x77, 0x61, 0x3b, 0x73, 0xe1, 0x6e, 0x7a, 0xe1, 0x20, 0x79, 0x61,
-0x20, 0x7a, 0xf3, 0x6d, 0x69, 0x3b, 0x73, 0xe1, 0x6e, 0x7a, 0xe1, 0x20, 0x79, 0x61, 0x20, 0x7a, 0xf3, 0x6d, 0x69, 0x20,
-0x6e, 0x61, 0x20, 0x6d, 0x254, 0x30c, 0x6b, 0x254, 0x301, 0x3b, 0x73, 0xe1, 0x6e, 0x7a, 0xe1, 0x20, 0x79, 0x61, 0x20, 0x7a,
-0xf3, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x6d, 0xed, 0x62, 0x61, 0x6c, 0xe9, 0x79, 0x61, 0x6e, 0x3b, 0x66, 0x62, 0x6c,
-0x3b, 0x6d, 0x73, 0x69, 0x3b, 0x61, 0x70, 0x6c, 0x3b, 0x6d, 0x61, 0x69, 0x3b, 0x79, 0x75, 0x6e, 0x3b, 0x79, 0x75, 0x6c,
-0x3b, 0x61, 0x67, 0x74, 0x3b, 0x73, 0x74, 0x62, 0x3b, 0x254, 0x74, 0x62, 0x3b, 0x6e, 0x76, 0x62, 0x3b, 0x64, 0x73, 0x62,
-0x79, 0x3b, 0x66, 0x3b, 0x6d, 0x3b, 0x61, 0x3b, 0x6d, 0x3b, 0x79, 0x3b, 0x79, 0x3b, 0x61, 0x3b, 0x73, 0x3b, 0x254, 0x3b,
-0x6e, 0x3b, 0x64, 0x73, 0x61, 0x75, 0x73, 0x69, 0x73, 0x3b, 0x76, 0x61, 0x73, 0x61, 0x72, 0x69, 0x73, 0x3b, 0x6b, 0x6f,
-0x76, 0x61, 0x73, 0x3b, 0x62, 0x61, 0x6c, 0x61, 0x6e, 0x64, 0x69, 0x73, 0x3b, 0x67, 0x65, 0x67, 0x75, 0x17e, 0x117, 0x3b,
-0x62, 0x69, 0x72, 0x17e, 0x65, 0x6c, 0x69, 0x73, 0x3b, 0x6c, 0x69, 0x65, 0x70, 0x61, 0x3b, 0x72, 0x75, 0x67, 0x70, 0x6a,
-0x16b, 0x74, 0x69, 0x73, 0x3b, 0x72, 0x75, 0x67, 0x73, 0x117, 0x6a, 0x69, 0x73, 0x3b, 0x73, 0x70, 0x61, 0x6c, 0x69, 0x73,
-0x3b, 0x6c, 0x61, 0x70, 0x6b, 0x72, 0x69, 0x74, 0x69, 0x73, 0x3b, 0x67, 0x72, 0x75, 0x6f, 0x64, 0x69, 0x73, 0x73, 0x61,
-0x75, 0x73, 0x69, 0x6f, 0x3b, 0x76, 0x61, 0x73, 0x61, 0x72, 0x69, 0x6f, 0x3b, 0x6b, 0x6f, 0x76, 0x6f, 0x3b, 0x62, 0x61,
-0x6c, 0x61, 0x6e, 0x64, 0x17e, 0x69, 0x6f, 0x3b, 0x67, 0x65, 0x67, 0x75, 0x17e, 0x117, 0x73, 0x3b, 0x62, 0x69, 0x72, 0x17e,
-0x65, 0x6c, 0x69, 0x6f, 0x3b, 0x6c, 0x69, 0x65, 0x70, 0x6f, 0x73, 0x3b, 0x72, 0x75, 0x67, 0x70, 0x6a, 0x16b, 0x10d, 0x69,
-0x6f, 0x3b, 0x72, 0x75, 0x67, 0x73, 0x117, 0x6a, 0x6f, 0x3b, 0x73, 0x70, 0x61, 0x6c, 0x69, 0x6f, 0x3b, 0x6c, 0x61, 0x70,
-0x6b, 0x72, 0x69, 0x10d, 0x69, 0x6f, 0x3b, 0x67, 0x72, 0x75, 0x6f, 0x64, 0x17e, 0x69, 0x6f, 0x73, 0x61, 0x75, 0x73, 0x2e,
-0x3b, 0x76, 0x61, 0x73, 0x2e, 0x3b, 0x6b, 0x6f, 0x76, 0x2e, 0x3b, 0x62, 0x61, 0x6c, 0x2e, 0x3b, 0x67, 0x65, 0x67, 0x2e,
-0x3b, 0x62, 0x69, 0x72, 0x17e, 0x2e, 0x3b, 0x6c, 0x69, 0x65, 0x70, 0x2e, 0x3b, 0x72, 0x75, 0x67, 0x70, 0x2e, 0x3b, 0x72,
-0x75, 0x67, 0x73, 0x2e, 0x3b, 0x73, 0x70, 0x61, 0x6c, 0x2e, 0x3b, 0x6c, 0x61, 0x70, 0x6b, 0x72, 0x2e, 0x3b, 0x67, 0x72,
-0x75, 0x6f, 0x64, 0x2e, 0x53, 0x3b, 0x56, 0x3b, 0x4b, 0x3b, 0x42, 0x3b, 0x47, 0x3b, 0x42, 0x3b, 0x4c, 0x3b, 0x52, 0x3b,
-0x52, 0x3b, 0x53, 0x3b, 0x4c, 0x3b, 0x47, 0x6a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0x61,
-0x72, 0x3b, 0x6d, 0x11b, 0x72, 0x63, 0x3b, 0x61, 0x70, 0x72, 0x79, 0x6c, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e,
-0x69, 0x6a, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x6a, 0x3b, 0x61, 0x77, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74,
-0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x6e, 0x6f, 0x77, 0x65, 0x6d, 0x62,
-0x65, 0x72, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x6a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x61, 0x3b, 0x66,
-0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x61, 0x3b, 0x6d, 0x11b, 0x72, 0x63, 0x61, 0x3b, 0x61, 0x70, 0x72, 0x79, 0x6c, 0x61,
-0x3b, 0x6d, 0x61, 0x6a, 0x61, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x6a, 0x61, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x6a, 0x61, 0x3b,
-0x61, 0x77, 0x67, 0x75, 0x73, 0x74, 0x61, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x61, 0x3b, 0x6f, 0x6b,
-0x74, 0x6f, 0x62, 0x72, 0x61, 0x3b, 0x6e, 0x6f, 0x77, 0x65, 0x6d, 0x62, 0x72, 0x61, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d,
-0x62, 0x72, 0x61, 0x6a, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0x11b, 0x72, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d,
-0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x77, 0x67, 0x3b, 0x73, 0x65, 0x70, 0x3b, 0x6f,
-0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x77, 0x3b, 0x64, 0x65, 0x63, 0x6a, 0x61, 0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x62, 0x2e, 0x3b,
-0x6d, 0x11b, 0x72, 0x2e, 0x3b, 0x61, 0x70, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x6a, 0x2e, 0x3b, 0x6a, 0x75, 0x6e, 0x2e, 0x3b,
-0x6a, 0x75, 0x6c, 0x2e, 0x3b, 0x61, 0x77, 0x67, 0x2e, 0x3b, 0x73, 0x65, 0x70, 0x2e, 0x3b, 0x6f, 0x6b, 0x74, 0x2e, 0x3b,
-0x6e, 0x6f, 0x77, 0x2e, 0x3b, 0x64, 0x65, 0x63, 0x2e, 0x4a, 0x61, 0x6e, 0x75, 0x61, 0x61, 0x72, 0x3b, 0x46, 0x65, 0x62,
-0x72, 0x75, 0x61, 0x61, 0x72, 0x3b, 0x4d, 0xe4, 0x72, 0x7a, 0x3b, 0x41, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x61, 0x69,
-0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x69, 0x3b, 0x41, 0x75, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x53, 0x65,
-0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x76, 0x65, 0x72, 0x3b, 0x4e, 0x6f, 0x76, 0x65,
-0x6d, 0x62, 0x65, 0x72, 0x3b, 0x44, 0x65, 0x7a, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4a, 0x61, 0x6e, 0x2e, 0x3b, 0x46, 0x65,
-0x62, 0x2e, 0x3b, 0x4d, 0xe4, 0x72, 0x7a, 0x3b, 0x41, 0x70, 0x72, 0x2e, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e,
-0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x69, 0x3b, 0x41, 0x75, 0x67, 0x2e, 0x3b, 0x53, 0x65, 0x70, 0x2e, 0x3b, 0x4f, 0x6b, 0x74,
-0x2e, 0x3b, 0x4e, 0x6f, 0x76, 0x2e, 0x3b, 0x44, 0x65, 0x7a, 0x2e, 0x43, 0x69, 0x6f, 0x6e, 0x67, 0x6f, 0x3b, 0x4c, 0xf9,
-0x69, 0x73, 0x68, 0x69, 0x3b, 0x4c, 0x75, 0x73, 0xf2, 0x6c, 0x6f, 0x3b, 0x4d, 0xf9, 0x75, 0x79, 0xe0, 0x3b, 0x4c, 0x75,
-0x6d, 0xf9, 0x6e, 0x67, 0xf9, 0x6c, 0xf9, 0x3b, 0x4c, 0x75, 0x66, 0x75, 0x69, 0x6d, 0x69, 0x3b, 0x4b, 0x61, 0x62, 0xe0,
-0x6c, 0xe0, 0x73, 0x68, 0xec, 0x70, 0xf9, 0x3b, 0x4c, 0xf9, 0x73, 0x68, 0xec, 0x6b, 0xe0, 0x3b, 0x4c, 0x75, 0x74, 0x6f,
-0x6e, 0x67, 0x6f, 0x6c, 0x6f, 0x3b, 0x4c, 0x75, 0x6e, 0x67, 0xf9, 0x64, 0x69, 0x3b, 0x4b, 0x61, 0x73, 0x77, 0xe8, 0x6b,
-0xe8, 0x73, 0xe8, 0x3b, 0x43, 0x69, 0x73, 0x77, 0xe0, 0x43, 0x69, 0x6f, 0x3b, 0x4c, 0x75, 0x69, 0x3b, 0x4c, 0x75, 0x73,
-0x3b, 0x4d, 0x75, 0x75, 0x3b, 0x4c, 0x75, 0x6d, 0x3b, 0x4c, 0x75, 0x66, 0x3b, 0x4b, 0x61, 0x62, 0x3b, 0x4c, 0x75, 0x73,
-0x68, 0x3b, 0x4c, 0x75, 0x74, 0x3b, 0x4c, 0x75, 0x6e, 0x3b, 0x4b, 0x61, 0x73, 0x3b, 0x43, 0x69, 0x73, 0x43, 0x3b, 0x4c,
-0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x4c, 0x3b, 0x4c, 0x3b, 0x4b, 0x3b, 0x4c, 0x3b, 0x4c, 0x3b, 0x4c, 0x3b, 0x4b, 0x3b, 0x43,
-0x44, 0x77, 0x65, 0x20, 0x6d, 0x61, 0x72, 0x20, 0x41, 0x63, 0x68, 0x69, 0x65, 0x6c, 0x3b, 0x44, 0x77, 0x65, 0x20, 0x6d,
-0x61, 0x72, 0x20, 0x41, 0x72, 0x69, 0x79, 0x6f, 0x3b, 0x44, 0x77, 0x65, 0x20, 0x6d, 0x61, 0x72, 0x20, 0x41, 0x64, 0x65,
-0x6b, 0x3b, 0x44, 0x77, 0x65, 0x20, 0x6d, 0x61, 0x72, 0x20, 0x41, 0x6e, 0x67, 0x2019, 0x77, 0x65, 0x6e, 0x3b, 0x44, 0x77,
-0x65, 0x20, 0x6d, 0x61, 0x72, 0x20, 0x41, 0x62, 0x69, 0x63, 0x68, 0x3b, 0x44, 0x77, 0x65, 0x20, 0x6d, 0x61, 0x72, 0x20,
-0x41, 0x75, 0x63, 0x68, 0x69, 0x65, 0x6c, 0x3b, 0x44, 0x77, 0x65, 0x20, 0x6d, 0x61, 0x72, 0x20, 0x41, 0x62, 0x69, 0x72,
-0x69, 0x79, 0x6f, 0x3b, 0x44, 0x77, 0x65, 0x20, 0x6d, 0x61, 0x72, 0x20, 0x41, 0x62, 0x6f, 0x72, 0x6f, 0x3b, 0x44, 0x77,
-0x65, 0x20, 0x6d, 0x61, 0x72, 0x20, 0x4f, 0x63, 0x68, 0x69, 0x6b, 0x6f, 0x3b, 0x44, 0x77, 0x65, 0x20, 0x6d, 0x61, 0x72,
-0x20, 0x41, 0x70, 0x61, 0x72, 0x3b, 0x44, 0x77, 0x65, 0x20, 0x6d, 0x61, 0x72, 0x20, 0x67, 0x69, 0x20, 0x61, 0x63, 0x68,
-0x69, 0x65, 0x6c, 0x3b, 0x44, 0x77, 0x65, 0x20, 0x6d, 0x61, 0x72, 0x20, 0x41, 0x70, 0x61, 0x72, 0x20, 0x67, 0x69, 0x20,
-0x61, 0x72, 0x69, 0x79, 0x6f, 0x44, 0x41, 0x43, 0x3b, 0x44, 0x41, 0x52, 0x3b, 0x44, 0x41, 0x44, 0x3b, 0x44, 0x41, 0x4e,
-0x3b, 0x44, 0x41, 0x48, 0x3b, 0x44, 0x41, 0x55, 0x3b, 0x44, 0x41, 0x4f, 0x3b, 0x44, 0x41, 0x42, 0x3b, 0x44, 0x4f, 0x43,
-0x3b, 0x44, 0x41, 0x50, 0x3b, 0x44, 0x47, 0x49, 0x3b, 0x44, 0x41, 0x47, 0x43, 0x3b, 0x52, 0x3b, 0x44, 0x3b, 0x4e, 0x3b,
-0x42, 0x3b, 0x55, 0x3b, 0x42, 0x3b, 0x42, 0x3b, 0x43, 0x3b, 0x50, 0x3b, 0x43, 0x3b, 0x50, 0x4a, 0x61, 0x6e, 0x75, 0x61,
-0x72, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x3b, 0x4d, 0xe4, 0x65, 0x72, 0x7a, 0x3b, 0x41, 0x62, 0x72, 0xeb,
-0x6c, 0x6c, 0x3b, 0x4d, 0x65, 0x65, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x69, 0x3b, 0x41, 0x75, 0x67,
-0x75, 0x73, 0x74, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x65,
-0x72, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x44, 0x65, 0x7a, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4a,
-0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0xe4, 0x65, 0x3b, 0x41, 0x62, 0x72, 0x3b, 0x4d, 0x65, 0x65, 0x3b, 0x4a,
-0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x75, 0x67, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e,
-0x6f, 0x76, 0x3b, 0x44, 0x65, 0x7a, 0x4a, 0x61, 0x6e, 0x2e, 0x3b, 0x46, 0x65, 0x62, 0x2e, 0x3b, 0x4d, 0xe4, 0x65, 0x2e,
-0x3b, 0x41, 0x62, 0x72, 0x2e, 0x3b, 0x4d, 0x65, 0x65, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x69, 0x3b,
-0x41, 0x75, 0x67, 0x2e, 0x3b, 0x53, 0x65, 0x70, 0x2e, 0x3b, 0x4f, 0x6b, 0x74, 0x2e, 0x3b, 0x4e, 0x6f, 0x76, 0x2e, 0x3b,
-0x44, 0x65, 0x7a, 0x2e, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b,
-0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x6f, 0x3b, 0x53, 0x65, 0x70, 0x3b,
-0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x73, 0x458, 0x430, 0x43d, 0x443, 0x430, 0x440, 0x438, 0x3b, 0x444,
-0x435, 0x432, 0x440, 0x443, 0x430, 0x440, 0x438, 0x3b, 0x43c, 0x430, 0x440, 0x442, 0x3b, 0x430, 0x43f, 0x440, 0x438, 0x43b, 0x3b, 0x43c,
-0x430, 0x458, 0x3b, 0x458, 0x443, 0x43d, 0x438, 0x3b, 0x458, 0x443, 0x43b, 0x438, 0x3b, 0x430, 0x432, 0x433, 0x443, 0x441, 0x442, 0x3b,
-0x441, 0x435, 0x43f, 0x442, 0x435, 0x43c, 0x432, 0x440, 0x438, 0x3b, 0x43e, 0x43a, 0x442, 0x43e, 0x43c, 0x432, 0x440, 0x438, 0x3b, 0x43d,
-0x43e, 0x435, 0x43c, 0x432, 0x440, 0x438, 0x3b, 0x434, 0x435, 0x43a, 0x435, 0x43c, 0x432, 0x440, 0x438, 0x458, 0x430, 0x43d, 0x2e, 0x3b,
-0x444, 0x435, 0x432, 0x2e, 0x3b, 0x43c, 0x430, 0x440, 0x2e, 0x3b, 0x430, 0x43f, 0x440, 0x2e, 0x3b, 0x43c, 0x430, 0x458, 0x3b, 0x458,
-0x443, 0x43d, 0x2e, 0x3b, 0x458, 0x443, 0x43b, 0x2e, 0x3b, 0x430, 0x432, 0x433, 0x2e, 0x3b, 0x441, 0x435, 0x43f, 0x442, 0x2e, 0x3b,
-0x43e, 0x43a, 0x442, 0x2e, 0x3b, 0x43d, 0x43e, 0x435, 0x43c, 0x2e, 0x3b, 0x434, 0x435, 0x43a, 0x2e, 0x4a, 0x61, 0x6e, 0x75, 0x61,
-0x72, 0x69, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x69, 0x3b, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x3b, 0x41, 0x70,
-0x72, 0x69, 0x6c, 0x79, 0x69, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x79, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x79,
-0x61, 0x69, 0x3b, 0x41, 0x67, 0x75, 0x73, 0x74, 0x69, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x4f,
-0x6b, 0x74, 0x6f, 0x62, 0x61, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x44, 0x65, 0x73, 0x65, 0x6d, 0x62,
-0x61, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x63, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x69,
-0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x6f, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74,
-0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x73, 0x91c, 0x928, 0x935, 0x930, 0x940, 0x3b, 0x92b, 0x930, 0x935, 0x930, 0x940, 0x3b,
-0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x948, 0x932, 0x3b, 0x92e, 0x908, 0x3b, 0x91c, 0x942, 0x928, 0x3b,
-0x91c, 0x941, 0x932, 0x93e, 0x908, 0x3b, 0x905, 0x917, 0x938, 0x94d, 0x924, 0x3b, 0x938, 0x93f, 0x924, 0x902, 0x92c, 0x930, 0x3b, 0x905,
-0x915, 0x94d, 0x91f, 0x942, 0x92c, 0x930, 0x3b, 0x928, 0x935, 0x902, 0x92c, 0x930, 0x3b, 0x926, 0x93f, 0x938, 0x902, 0x92c, 0x930, 0x91c,
-0x928, 0x935, 0x930, 0x940, 0x3b, 0x92b, 0x930, 0x935, 0x930, 0x940, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d,
-0x930, 0x948, 0x932, 0x3b, 0x92e, 0x908, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x93e, 0x908, 0x3b, 0x905, 0x917, 0x938,
-0x94d, 0x924, 0x3b, 0x938, 0x93f, 0x924, 0x902, 0x92c, 0x930, 0x3b, 0x905, 0x915, 0x94d, 0x924, 0x942, 0x92c, 0x930, 0x3b, 0x928, 0x935,
-0x902, 0x92c, 0x930, 0x3b, 0x926, 0x93f, 0x938, 0x902, 0x92c, 0x930, 0x91c, 0x928, 0x970, 0x3b, 0x92b, 0x930, 0x970, 0x3b, 0x92e, 0x93e,
-0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x948, 0x932, 0x3b, 0x92e, 0x908, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941,
-0x932, 0x970, 0x3b, 0x905, 0x917, 0x970, 0x3b, 0x938, 0x93f, 0x924, 0x970, 0x3b, 0x905, 0x915, 0x94d, 0x924, 0x942, 0x970, 0x3b, 0x928,
-0x935, 0x970, 0x3b, 0x926, 0x93f, 0x938, 0x970, 0x91c, 0x3b, 0x92b, 0x3b, 0x92e, 0x93e, 0x3b, 0x905, 0x3b, 0x92e, 0x3b, 0x91c, 0x942,
-0x3b, 0x91c, 0x941, 0x3b, 0x905, 0x3b, 0x938, 0x93f, 0x3b, 0x905, 0x3b, 0x928, 0x3b, 0x926, 0x93f, 0x4d, 0x77, 0x65, 0x72, 0x69,
-0x20, 0x77, 0x6f, 0x20, 0x6b, 0x77, 0x61, 0x6e, 0x7a, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x6f, 0x20,
-0x75, 0x6e, 0x61, 0x79, 0x65, 0x6c, 0x69, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x6f, 0x20, 0x75, 0x6e, 0x65,
-0x72, 0x61, 0x72, 0x75, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x6f, 0x20, 0x75, 0x6e, 0x65, 0x63, 0x68, 0x65,
-0x73, 0x68, 0x65, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x6f, 0x20, 0x75, 0x6e, 0x65, 0x74, 0x68, 0x61, 0x6e,
-0x75, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x6f, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x75, 0x20, 0x6e, 0x61, 0x20,
-0x6d, 0x6f, 0x63, 0x68, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x6f, 0x20, 0x73, 0x61, 0x62, 0x61, 0x3b,
-0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x6f, 0x20, 0x6e, 0x61, 0x6e, 0x65, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20,
-0x77, 0x6f, 0x20, 0x74, 0x69, 0x73, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x6f, 0x20, 0x6b, 0x75, 0x6d,
-0x69, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x6f, 0x20, 0x6b, 0x75, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x6d,
-0x6f, 0x6a, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x6f, 0x20, 0x6b, 0x75, 0x6d, 0x69, 0x20, 0x6e, 0x61,
-0x20, 0x79, 0x65, 0x6c, 0x2019, 0x6c, 0x69, 0x4b, 0x77, 0x61, 0x3b, 0x55, 0x6e, 0x61, 0x3b, 0x52, 0x61, 0x72, 0x3b, 0x43,
-0x68, 0x65, 0x3b, 0x54, 0x68, 0x61, 0x3b, 0x4d, 0x6f, 0x63, 0x3b, 0x53, 0x61, 0x62, 0x3b, 0x4e, 0x61, 0x6e, 0x3b, 0x54,
-0x69, 0x73, 0x3b, 0x4b, 0x75, 0x6d, 0x3b, 0x4d, 0x6f, 0x6a, 0x3b, 0x59, 0x65, 0x6c, 0x4b, 0x3b, 0x55, 0x3b, 0x52, 0x3b,
-0x43, 0x3b, 0x54, 0x3b, 0x4d, 0x3b, 0x53, 0x3b, 0x4e, 0x3b, 0x54, 0x3b, 0x4b, 0x3b, 0x4d, 0x3b, 0x59, 0x4d, 0x77, 0x65,
-0x64, 0x69, 0x20, 0x4e, 0x74, 0x61, 0x6e, 0x64, 0x69, 0x3b, 0x4d, 0x77, 0x65, 0x64, 0x69, 0x20, 0x77, 0x61, 0x20, 0x50,
-0x69, 0x6c, 0x69, 0x3b, 0x4d, 0x77, 0x65, 0x64, 0x69, 0x20, 0x77, 0x61, 0x20, 0x54, 0x61, 0x74, 0x75, 0x3b, 0x4d, 0x77,
-0x65, 0x64, 0x69, 0x20, 0x77, 0x61, 0x20, 0x4e, 0x63, 0x68, 0x65, 0x63, 0x68, 0x69, 0x3b, 0x4d, 0x77, 0x65, 0x64, 0x69,
-0x20, 0x77, 0x61, 0x20, 0x4e, 0x6e, 0x79, 0x61, 0x6e, 0x6f, 0x3b, 0x4d, 0x77, 0x65, 0x64, 0x69, 0x20, 0x77, 0x61, 0x20,
-0x4e, 0x6e, 0x79, 0x61, 0x6e, 0x6f, 0x20, 0x6e, 0x61, 0x20, 0x55, 0x6d, 0x6f, 0x3b, 0x4d, 0x77, 0x65, 0x64, 0x69, 0x20,
-0x77, 0x61, 0x20, 0x4e, 0x6e, 0x79, 0x61, 0x6e, 0x6f, 0x20, 0x6e, 0x61, 0x20, 0x4d, 0x69, 0x76, 0x69, 0x6c, 0x69, 0x3b,
-0x4d, 0x77, 0x65, 0x64, 0x69, 0x20, 0x77, 0x61, 0x20, 0x4e, 0x6e, 0x79, 0x61, 0x6e, 0x6f, 0x20, 0x6e, 0x61, 0x20, 0x4d,
-0x69, 0x74, 0x61, 0x74, 0x75, 0x3b, 0x4d, 0x77, 0x65, 0x64, 0x69, 0x20, 0x77, 0x61, 0x20, 0x4e, 0x6e, 0x79, 0x61, 0x6e,
-0x6f, 0x20, 0x6e, 0x61, 0x20, 0x4e, 0x63, 0x68, 0x65, 0x63, 0x68, 0x69, 0x3b, 0x4d, 0x77, 0x65, 0x64, 0x69, 0x20, 0x77,
-0x61, 0x20, 0x4e, 0x6e, 0x79, 0x61, 0x6e, 0x6f, 0x20, 0x6e, 0x61, 0x20, 0x4e, 0x6e, 0x79, 0x61, 0x6e, 0x6f, 0x3b, 0x4d,
-0x77, 0x65, 0x64, 0x69, 0x20, 0x77, 0x61, 0x20, 0x4e, 0x6e, 0x79, 0x61, 0x6e, 0x6f, 0x20, 0x6e, 0x61, 0x20, 0x4e, 0x6e,
-0x79, 0x61, 0x6e, 0x6f, 0x20, 0x6e, 0x61, 0x20, 0x55, 0x3b, 0x4d, 0x77, 0x65, 0x64, 0x69, 0x20, 0x77, 0x61, 0x20, 0x4e,
-0x6e, 0x79, 0x61, 0x6e, 0x6f, 0x20, 0x6e, 0x61, 0x20, 0x4e, 0x6e, 0x79, 0x61, 0x6e, 0x6f, 0x20, 0x6e, 0x61, 0x20, 0x4d,
-0x4a, 0x61, 0x6e, 0x6f, 0x61, 0x72, 0x79, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x6f, 0x61, 0x72, 0x79, 0x3b, 0x4d, 0x61, 0x72,
-0x74, 0x73, 0x61, 0x3b, 0x41, 0x70, 0x72, 0x69, 0x6c, 0x79, 0x3b, 0x4d, 0x65, 0x79, 0x3b, 0x4a, 0x6f, 0x6e, 0x61, 0x3b,
-0x4a, 0x6f, 0x6c, 0x61, 0x79, 0x3b, 0x41, 0x6f, 0x67, 0x6f, 0x73, 0x69, 0x74, 0x72, 0x61, 0x3b, 0x53, 0x65, 0x70, 0x74,
-0x61, 0x6d, 0x62, 0x72, 0x61, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x72, 0x61, 0x3b, 0x4e, 0x6f, 0x76, 0x61, 0x6d, 0x62,
-0x72, 0x61, 0x3b, 0x44, 0x65, 0x73, 0x61, 0x6d, 0x62, 0x72, 0x61, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d,
-0x61, 0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x79, 0x3b, 0x4a, 0x6f, 0x6e, 0x3b, 0x4a, 0x6f, 0x6c, 0x3b, 0x41,
-0x6f, 0x67, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x73, 0xd1c, 0xd28,
-0xd41, 0xd35, 0xd30, 0xd3f, 0x3b, 0xd2b, 0xd46, 0xd2c, 0xd4d, 0xd30, 0xd41, 0xd35, 0xd30, 0xd3f, 0x3b, 0xd2e, 0xd3e, 0xd7c, 0xd1a, 0xd4d,
-0xd1a, 0xd4d, 0x3b, 0xd0f, 0xd2a, 0xd4d, 0xd30, 0xd3f, 0xd7d, 0x3b, 0xd2e, 0xd47, 0xd2f, 0xd4d, 0x3b, 0xd1c, 0xd42, 0xd7a, 0x3b, 0xd1c,
-0xd42, 0xd32, 0xd48, 0x3b, 0xd13, 0xd17, 0xd38, 0xd4d, 0xd31, 0xd4d, 0xd31, 0xd4d, 0x3b, 0xd38, 0xd46, 0xd2a, 0xd4d, 0xd31, 0xd4d, 0xd31,
-0xd02, 0xd2c, 0xd7c, 0x3b, 0xd12, 0xd15, 0xd4d, 0x200c, 0xd1f, 0xd4b, 0xd2c, 0xd7c, 0x3b, 0xd28, 0xd35, 0xd02, 0xd2c, 0xd7c, 0x3b, 0xd21,
-0xd3f, 0xd38, 0xd02, 0xd2c, 0xd7c, 0xd1c, 0xd28, 0xd41, 0x3b, 0xd2b, 0xd46, 0xd2c, 0xd4d, 0xd30, 0xd41, 0x3b, 0xd2e, 0xd3e, 0xd7c, 0x3b,
-0xd0f, 0xd2a, 0xd4d, 0xd30, 0xd3f, 0x3b, 0xd2e, 0xd47, 0xd2f, 0xd4d, 0x3b, 0xd1c, 0xd42, 0xd7a, 0x3b, 0xd1c, 0xd42, 0xd32, 0xd48, 0x3b,
-0xd13, 0xd17, 0x3b, 0xd38, 0xd46, 0xd2a, 0xd4d, 0xd31, 0xd4d, 0xd31, 0xd02, 0x3b, 0xd12, 0xd15, 0xd4d, 0xd1f, 0xd4b, 0x3b, 0xd28, 0xd35,
-0xd02, 0x3b, 0xd21, 0xd3f, 0xd38, 0xd02, 0xd1c, 0x3b, 0xd2b, 0xd46, 0x3b, 0xd2e, 0xd3e, 0x3b, 0xd0f, 0x3b, 0xd2e, 0xd46, 0x3b, 0xd1c,
-0xd42, 0xd7a, 0x3b, 0xd1c, 0xd42, 0x3b, 0xd13, 0x3b, 0xd38, 0xd46, 0x3b, 0xd12, 0x3b, 0xd28, 0x3b, 0xd21, 0xd3f, 0x4a, 0x61, 0x6e,
-0x75, 0x61, 0x72, 0x69, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x69, 0x3b, 0x4d, 0x61, 0x63, 0x3b, 0x41, 0x70,
-0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x61, 0x69, 0x3b, 0x4f, 0x67,
-0x6f, 0x73, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x65, 0x72,
-0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x44, 0x69, 0x73, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4a, 0x61,
-0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x63, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75,
-0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x4f, 0x67, 0x6f, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f,
-0x76, 0x3b, 0x44, 0x69, 0x73, 0x4a, 0x61, 0x6e, 0x6e, 0x61, 0x72, 0x3b, 0x46, 0x72, 0x61, 0x72, 0x3b, 0x4d, 0x61, 0x72,
-0x7a, 0x75, 0x3b, 0x41, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x65, 0x6a, 0x6a, 0x75, 0x3b, 0x120, 0x75, 0x6e, 0x6a, 0x75,
-0x3b, 0x4c, 0x75, 0x6c, 0x6a, 0x75, 0x3b, 0x41, 0x77, 0x77, 0x69, 0x73, 0x73, 0x75, 0x3b, 0x53, 0x65, 0x74, 0x74, 0x65,
-0x6d, 0x62, 0x72, 0x75, 0x3b, 0x4f, 0x74, 0x74, 0x75, 0x62, 0x72, 0x75, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72,
-0x75, 0x3b, 0x44, 0x69, 0x10b, 0x65, 0x6d, 0x62, 0x72, 0x75, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x72, 0x61, 0x3b, 0x4d, 0x61,
-0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x6a, 0x3b, 0x120, 0x75, 0x6e, 0x3b, 0x4c, 0x75, 0x6c, 0x3b, 0x41, 0x77,
-0x77, 0x3b, 0x53, 0x65, 0x74, 0x3b, 0x4f, 0x74, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x69, 0x10b, 0x4a, 0x6e, 0x3b,
-0x46, 0x72, 0x3b, 0x4d, 0x7a, 0x3b, 0x41, 0x70, 0x3b, 0x4d, 0x6a, 0x3b, 0x120, 0x6e, 0x3b, 0x4c, 0x6a, 0x3b, 0x41, 0x77,
-0x3b, 0x53, 0x74, 0x3b, 0x4f, 0x62, 0x3b, 0x4e, 0x76, 0x3b, 0x44, 0x10b, 0x4a, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b,
-0x4d, 0x3b, 0x120, 0x3b, 0x4c, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x99c, 0x9be, 0x9a8, 0x9c1, 0x9f1,
-0x9be, 0x9b0, 0x9bf, 0x3b, 0x9ab, 0x9c7, 0x9ac, 0x9cd, 0x9b0, 0x9c1, 0x9f1, 0x9be, 0x9b0, 0x9bf, 0x3b, 0x9ae, 0x9be, 0x9b0, 0x9cd, 0x99a,
-0x3b, 0x98f, 0x9aa, 0x9cd, 0x9b0, 0x9bf, 0x9b2, 0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b, 0x99c, 0x9c1, 0x9b2, 0x9be, 0x987,
-0x3b, 0x993, 0x997, 0x9b7, 0x9cd, 0x99f, 0x3b, 0x9b8, 0x9c7, 0x9aa, 0x9cd, 0x99f, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9b0, 0x3b, 0x993, 0x995,
-0x9cd, 0x99f, 0x9cb, 0x9ac, 0x9b0, 0x3b, 0x9a8, 0x9ac, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9b0, 0x3b, 0x9a1, 0x9bf, 0x9b8, 0x9c7, 0x9ae, 0x9cd,
-0x9ac, 0x9b0, 0x99c, 0x9be, 0x9a8, 0x9c1, 0x9f1, 0x9be, 0x9b0, 0x9bf, 0x3b, 0x9ab, 0x9c7, 0x9ac, 0x9cd, 0x9b0, 0x9c1, 0x9f1, 0x9be, 0x9b0,
-0x9bf, 0x3b, 0x9ae, 0x9be, 0x9b0, 0x9cd, 0x99a, 0x3b, 0x98f, 0x9aa, 0x9cd, 0x9b0, 0x9bf, 0x9b2, 0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1,
-0x9a8, 0x3b, 0x99c, 0x9c1, 0x9b2, 0x9be, 0x987, 0x3b, 0x986, 0x997, 0x9b8, 0x9cd, 0x99f, 0x3b, 0x9b8, 0x9c7, 0x9aa, 0x9cd, 0x99f, 0x9c7,
-0x9ae, 0x9cd, 0x9ac, 0x9b0, 0x3b, 0x993, 0x995, 0x9cd, 0x99f, 0x9cb, 0x9ac, 0x9b0, 0x3b, 0x9a8, 0x9ad, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9b0,
-0x3b, 0x9a1, 0x9bf, 0x9b8, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9b0, 0x99c, 0x9be, 0x9a8, 0x9c1, 0x3b, 0x9ab, 0x9c7, 0x9ac, 0x9cd, 0x9b0, 0x9c1,
-0x3b, 0x9ae, 0x9be, 0x9b0, 0x3b, 0x98f, 0x9aa, 0x9cd, 0x9b0, 0x9bf, 0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b, 0x99c, 0x9c1,
-0x9b2, 0x9be, 0x3b, 0x986, 0x997, 0x3b, 0x9b8, 0x9c7, 0x9aa, 0x9cd, 0x99f, 0x3b, 0x993, 0x995, 0x9cd, 0x99f, 0x9cb, 0x3b, 0x9a8, 0x9ad,
-0x9c7, 0x3b, 0x9a1, 0x9bf, 0x9b8, 0x9c7, 0x99c, 0x9be, 0x3b, 0x9ab, 0x9c7, 0x3b, 0x9ae, 0x9be, 0x9b0, 0x3b, 0x98f, 0x9aa, 0x3b, 0x9ae,
-0x9c7, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b, 0x99c, 0x9c1, 0x9b2, 0x3b, 0x986, 0x3b, 0x9b8, 0x9c7, 0x3b, 0x993, 0x3b, 0x9a8, 0x9ac, 0x3b,
-0x9a1, 0x9bf, 0x99c, 0x9be, 0x3b, 0x9ab, 0x9c7, 0x3b, 0x9ae, 0x9be, 0x9b0, 0x3b, 0x98f, 0x9aa, 0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1,
-0x9a8, 0x3b, 0x99c, 0x9c1, 0x9b2, 0x3b, 0x986, 0x3b, 0x9b8, 0x9c7, 0x3b, 0x993, 0x995, 0x3b, 0x9a8, 0x9ac, 0x3b, 0x9a1, 0x9bf, 0x4a,
-0x65, 0x72, 0x72, 0x65, 0x79, 0x2d, 0x67, 0x65, 0x75, 0x72, 0x65, 0x65, 0x3b, 0x54, 0x6f, 0x73, 0x68, 0x69, 0x61, 0x67,
-0x68, 0x74, 0x2d, 0x61, 0x72, 0x72, 0x65, 0x65, 0x3b, 0x4d, 0x61, 0x79, 0x72, 0x6e, 0x74, 0x3b, 0x41, 0x76, 0x65, 0x72,
-0x69, 0x6c, 0x3b, 0x42, 0x6f, 0x61, 0x6c, 0x64, 0x79, 0x6e, 0x3b, 0x4d, 0x65, 0x61, 0x6e, 0x2d, 0x73, 0x6f, 0x75, 0x72,
-0x65, 0x65, 0x3b, 0x4a, 0x65, 0x72, 0x72, 0x65, 0x79, 0x2d, 0x73, 0x6f, 0x75, 0x72, 0x65, 0x65, 0x3b, 0x4c, 0x75, 0x61,
-0x6e, 0x69, 0x73, 0x74, 0x79, 0x6e, 0x3b, 0x4d, 0x65, 0x61, 0x6e, 0x2d, 0x66, 0x6f, 0x75, 0x79, 0x69, 0x72, 0x3b, 0x4a,
-0x65, 0x72, 0x72, 0x65, 0x79, 0x2d, 0x66, 0x6f, 0x75, 0x79, 0x69, 0x72, 0x3b, 0x4d, 0x65, 0x65, 0x20, 0x48, 0x6f, 0x75,
-0x6e, 0x65, 0x79, 0x3b, 0x4d, 0x65, 0x65, 0x20, 0x6e, 0x79, 0x20, 0x4e, 0x6f, 0x6c, 0x6c, 0x69, 0x63, 0x6b, 0x4a, 0x2d,
-0x67, 0x75, 0x65, 0x72, 0x3b, 0x54, 0x2d, 0x61, 0x72, 0x72, 0x65, 0x65, 0x3b, 0x4d, 0x61, 0x79, 0x72, 0x6e, 0x74, 0x3b,
-0x41, 0x76, 0x72, 0x72, 0x69, 0x6c, 0x3b, 0x42, 0x6f, 0x61, 0x6c, 0x64, 0x79, 0x6e, 0x3b, 0x4d, 0x2d, 0x73, 0x6f, 0x75,
-0x72, 0x65, 0x65, 0x3b, 0x4a, 0x2d, 0x73, 0x6f, 0x75, 0x72, 0x65, 0x65, 0x3b, 0x4c, 0x75, 0x61, 0x6e, 0x69, 0x73, 0x74,
-0x79, 0x6e, 0x3b, 0x4d, 0x2d, 0x66, 0x6f, 0x75, 0x79, 0x69, 0x72, 0x3b, 0x4a, 0x2d, 0x66, 0x6f, 0x75, 0x79, 0x69, 0x72,
-0x3b, 0x4d, 0x2d, 0x48, 0x6f, 0x75, 0x6e, 0x65, 0x79, 0x3b, 0x4d, 0x2d, 0x4e, 0x6f, 0x6c, 0x6c, 0x69, 0x63, 0x6b, 0x48,
-0x101, 0x6e, 0x75, 0x65, 0x72, 0x65, 0x3b, 0x50, 0x113, 0x70, 0x75, 0x65, 0x72, 0x65, 0x3b, 0x4d, 0x101, 0x65, 0x68, 0x65,
-0x3b, 0x100, 0x70, 0x65, 0x72, 0x65, 0x69, 0x72, 0x61, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x48, 0x75, 0x6e, 0x65, 0x3b, 0x48,
-0x16b, 0x72, 0x61, 0x65, 0x3b, 0x100, 0x6b, 0x75, 0x68, 0x61, 0x74, 0x61, 0x3b, 0x48, 0x65, 0x70, 0x65, 0x74, 0x65, 0x6d,
-0x61, 0x3b, 0x4f, 0x6b, 0x65, 0x74, 0x6f, 0x70, 0x61, 0x3b, 0x4e, 0x6f, 0x65, 0x6d, 0x61, 0x3b, 0x54, 0x12b, 0x68, 0x65,
-0x6d, 0x61, 0x48, 0x101, 0x6e, 0x3b, 0x50, 0x113, 0x70, 0x3b, 0x4d, 0x101, 0x65, 0x3b, 0x100, 0x70, 0x65, 0x3b, 0x4d, 0x65,
-0x69, 0x3b, 0x48, 0x75, 0x6e, 0x65, 0x3b, 0x48, 0x16b, 0x72, 0x3b, 0x100, 0x6b, 0x75, 0x3b, 0x48, 0x65, 0x70, 0x3b, 0x4f,
-0x6b, 0x65, 0x3b, 0x4e, 0x6f, 0x65, 0x6d, 0x3b, 0x54, 0x12b, 0x68, 0x65, 0x48, 0x3b, 0x50, 0x3b, 0x4d, 0x3b, 0x100, 0x3b,
-0x4d, 0x3b, 0x48, 0x3b, 0x48, 0x3b, 0x100, 0x3b, 0x48, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x54, 0x91c, 0x93e, 0x928, 0x947, 0x935,
-0x93e, 0x930, 0x940, 0x3b, 0x92b, 0x947, 0x92c, 0x94d, 0x930, 0x941, 0x935, 0x93e, 0x930, 0x940, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a,
-0x3b, 0x90f, 0x92a, 0x94d, 0x930, 0x93f, 0x932, 0x3b, 0x92e, 0x947, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x948, 0x3b,
-0x911, 0x917, 0x938, 0x94d, 0x91f, 0x3b, 0x938, 0x92a, 0x94d, 0x91f, 0x947, 0x902, 0x92c, 0x930, 0x3b, 0x911, 0x915, 0x94d, 0x91f, 0x94b,
-0x92c, 0x930, 0x3b, 0x928, 0x94b, 0x935, 0x94d, 0x939, 0x947, 0x902, 0x92c, 0x930, 0x3b, 0x921, 0x93f, 0x938, 0x947, 0x902, 0x92c, 0x930,
-0x91c, 0x93e, 0x928, 0x947, 0x3b, 0x92b, 0x947, 0x92c, 0x94d, 0x930, 0x941, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x90f, 0x92a,
-0x94d, 0x930, 0x93f, 0x3b, 0x92e, 0x947, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x948, 0x3b, 0x911, 0x917, 0x3b, 0x938,
-0x92a, 0x94d, 0x91f, 0x947, 0x902, 0x3b, 0x911, 0x915, 0x94d, 0x91f, 0x94b, 0x3b, 0x928, 0x94b, 0x935, 0x94d, 0x939, 0x947, 0x902, 0x3b,
-0x921, 0x93f, 0x938, 0x947, 0x902, 0x91c, 0x93e, 0x3b, 0x92b, 0x947, 0x3b, 0x92e, 0x93e, 0x3b, 0x90f, 0x3b, 0x92e, 0x947, 0x3b, 0x91c,
-0x942, 0x3b, 0x91c, 0x941, 0x3b, 0x911, 0x3b, 0x938, 0x3b, 0x911, 0x3b, 0x928, 0x94b, 0x3b, 0x921, 0x93f, 0x4f, 0x6c, 0x61, 0x64,
-0x61, 0x6c, 0x289, 0x301, 0x3b, 0x41, 0x72, 0xe1, 0x74, 0x3b, 0x186, 0x25b, 0x6e, 0x268, 0x301, 0x254, 0x268, 0x14b, 0x254, 0x6b,
-0x3b, 0x4f, 0x6c, 0x6f, 0x64, 0x6f, 0x79, 0xed, 0xf3, 0x72, 0xed, 0xea, 0x20, 0x69, 0x6e, 0x6b, 0xf3, 0x6b, 0xfa, 0xe2,
-0x3b, 0x4f, 0x6c, 0x6f, 0x69, 0x6c, 0xe9, 0x70, 0x16b, 0x6e, 0x79, 0x12b, 0x113, 0x20, 0x69, 0x6e, 0x6b, 0xf3, 0x6b, 0xfa,
-0xe2, 0x3b, 0x4b, 0xfa, 0x6a, 0xfa, 0x254, 0x72, 0x254, 0x6b, 0x3b, 0x4d, 0xf3, 0x72, 0x75, 0x73, 0xe1, 0x73, 0x69, 0x6e,
-0x3b, 0x186, 0x6c, 0x254, 0x301, 0x268, 0x301, 0x62, 0x254, 0x301, 0x72, 0xe1, 0x72, 0x25b, 0x3b, 0x4b, 0xfa, 0x73, 0x68, 0xee,
-0x6e, 0x3b, 0x4f, 0x6c, 0x67, 0xed, 0x73, 0x61, 0x6e, 0x3b, 0x50, 0x289, 0x73, 0x68, 0x289, 0x301, 0x6b, 0x61, 0x3b, 0x4e,
-0x74, 0x289, 0x301, 0x14b, 0x289, 0x301, 0x73, 0x44, 0x61, 0x6c, 0x3b, 0x41, 0x72, 0xe1, 0x3b, 0x186, 0x25b, 0x6e, 0x3b, 0x44,
-0x6f, 0x79, 0x3b, 0x4c, 0xe9, 0x70, 0x3b, 0x52, 0x6f, 0x6b, 0x3b, 0x53, 0xe1, 0x73, 0x3b, 0x42, 0x254, 0x301, 0x72, 0x3b,
-0x4b, 0xfa, 0x73, 0x3b, 0x47, 0xed, 0x73, 0x3b, 0x53, 0x68, 0x289, 0x301, 0x3b, 0x4e, 0x74, 0x289, 0x301, 0x698, 0x627, 0x646,
-0x648, 0x6cc, 0x647, 0x3b, 0x641, 0x648, 0x631, 0x6cc, 0x647, 0x3b, 0x645, 0x627, 0x631, 0x633, 0x3b, 0x622, 0x648, 0x631, 0x6cc, 0x644,
-0x3b, 0x645, 0x647, 0x3b, 0x698, 0x648, 0x626, 0x646, 0x3b, 0x698, 0x648, 0x626, 0x6cc, 0x647, 0x3b, 0x627, 0x648, 0x62a, 0x3b, 0x633,
-0x67e, 0x62a, 0x627, 0x645, 0x628, 0x631, 0x3b, 0x627, 0x6a9, 0x62a, 0x628, 0x631, 0x3b, 0x646, 0x648, 0x627, 0x645, 0x628, 0x631, 0x3b,
-0x62f, 0x633, 0x627, 0x645, 0x628, 0x631, 0x4a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x129, 0x3b, 0x46, 0x65, 0x62, 0x75, 0x72, 0x75,
-0x61, 0x72, 0x129, 0x3b, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x3b, 0x128, 0x70, 0x75, 0x72, 0x169, 0x3b, 0x4d, 0x129, 0x129, 0x3b,
-0x4e, 0x6a, 0x75, 0x6e, 0x69, 0x3b, 0x4e, 0x6a, 0x75, 0x72, 0x61, 0x129, 0x3b, 0x41, 0x67, 0x61, 0x73, 0x74, 0x69, 0x3b,
-0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x4f, 0x6b, 0x74, 0x169, 0x62, 0x61, 0x3b, 0x4e, 0x6f, 0x76, 0x65,
-0x6d, 0x62, 0x61, 0x3b, 0x44, 0x69, 0x63, 0x65, 0x6d, 0x62, 0x61, 0x4a, 0x41, 0x4e, 0x3b, 0x46, 0x45, 0x42, 0x3b, 0x4d,
-0x41, 0x43, 0x3b, 0x128, 0x50, 0x55, 0x3b, 0x4d, 0x128, 0x128, 0x3b, 0x4e, 0x4a, 0x55, 0x3b, 0x4e, 0x4a, 0x52, 0x3b, 0x41,
-0x47, 0x41, 0x3b, 0x53, 0x50, 0x54, 0x3b, 0x4f, 0x4b, 0x54, 0x3b, 0x4e, 0x4f, 0x56, 0x3b, 0x44, 0x45, 0x43, 0x4a, 0x3b,
-0x46, 0x3b, 0x4d, 0x3b, 0x128, 0x3b, 0x4d, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b,
-0x44, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x6d, 0x62, 0x65, 0x67, 0x74, 0x75, 0x67, 0x3b, 0x69, 0x6d, 0x65, 0x67, 0x20, 0xe0,
-0x62, 0xf9, 0x62, 0xec, 0x3b, 0x69, 0x6d, 0x65, 0x67, 0x20, 0x6d, 0x62, 0x259, 0x14b, 0x63, 0x68, 0x75, 0x62, 0x69, 0x3b,
-0x69, 0x6d, 0x259, 0x67, 0x20, 0x6e, 0x67, 0x77, 0x259, 0x300, 0x74, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x66, 0x6f, 0x67,
-0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x69, 0x63, 0x68, 0x69, 0x69, 0x62, 0x254, 0x64, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20,
-0xe0, 0x64, 0xf9, 0x6d, 0x62, 0x259, 0x300, 0x14b, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x69, 0x63, 0x68, 0x69, 0x6b, 0x61,
-0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x6b, 0x75, 0x64, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x74, 0xe8, 0x73, 0x69, 0x2bc,
-0x65, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x7a, 0xf2, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x6b, 0x72, 0x69, 0x7a, 0x6d,
-0x65, 0x64, 0x6d, 0x62, 0x65, 0x67, 0x74, 0x75, 0x67, 0x3b, 0x69, 0x6d, 0x65, 0x67, 0x20, 0xe0, 0x62, 0xf9, 0x62, 0xec,
-0x3b, 0x69, 0x6d, 0x65, 0x67, 0x20, 0x6d, 0x62, 0x259, 0x14b, 0x63, 0x68, 0x75, 0x62, 0x69, 0x3b, 0x69, 0x6d, 0x259, 0x67,
-0x20, 0x6e, 0x67, 0x77, 0x259, 0x300, 0x74, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x66, 0x6f, 0x67, 0x3b, 0x69, 0x6d, 0x259,
-0x67, 0x20, 0x69, 0x63, 0x68, 0x69, 0x69, 0x62, 0x254, 0x64, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0xe0, 0x64, 0xf9, 0x6d,
-0x62, 0x259, 0x300, 0x14b, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x69, 0x63, 0x68, 0x69, 0x6b, 0x61, 0x3b, 0x69, 0x6d, 0x259,
-0x67, 0x20, 0x6b, 0x75, 0x64, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x74, 0xe8, 0x73, 0x69, 0x2bc, 0x65, 0x3b, 0x69, 0x6d,
-0x259, 0x67, 0x20, 0x7a, 0xf2, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x6b, 0x72, 0x69, 0x7a, 0x6d, 0x65, 0x64, 0x4d, 0x31,
-0x3b, 0x41, 0x32, 0x3b, 0x4d, 0x33, 0x3b, 0x4e, 0x34, 0x3b, 0x46, 0x35, 0x3b, 0x49, 0x36, 0x3b, 0x41, 0x37, 0x3b, 0x49,
-0x38, 0x3b, 0x4b, 0x39, 0x3b, 0x31, 0x30, 0x3b, 0x31, 0x31, 0x3b, 0x31, 0x32, 0x41d, 0x44d, 0x433, 0x434, 0x4af, 0x433, 0x44d,
-0x44d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x425, 0x43e, 0x451, 0x440, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440, 0x20, 0x441, 0x430,
-0x440, 0x3b, 0x413, 0x443, 0x440, 0x430, 0x432, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x414, 0x4e9,
-0x440, 0x4e9, 0x432, 0x434, 0x4af, 0x433, 0x44d, 0x44d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x422, 0x430, 0x432, 0x434, 0x443, 0x433,
-0x430, 0x430, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x417, 0x443, 0x440, 0x433, 0x430, 0x430, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440,
-0x20, 0x441, 0x430, 0x440, 0x3b, 0x414, 0x43e, 0x43b, 0x43e, 0x43e, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440, 0x20, 0x441, 0x430, 0x440,
-0x3b, 0x41d, 0x430, 0x439, 0x43c, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x415, 0x441, 0x434, 0x4af,
-0x433, 0x44d, 0x44d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x410, 0x440, 0x430, 0x432, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440, 0x20,
-0x441, 0x430, 0x440, 0x3b, 0x410, 0x440, 0x432, 0x430, 0x43d, 0x20, 0x43d, 0x44d, 0x433, 0x434, 0x4af, 0x433, 0x44d, 0x44d, 0x440, 0x20,
-0x441, 0x430, 0x440, 0x3b, 0x410, 0x440, 0x432, 0x430, 0x43d, 0x20, 0x445, 0x43e, 0x451, 0x440, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440,
-0x20, 0x441, 0x430, 0x440, 0x43d, 0x44d, 0x433, 0x434, 0x4af, 0x433, 0x44d, 0x44d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x445, 0x43e,
-0x451, 0x440, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x433, 0x443, 0x440, 0x430, 0x432, 0x434, 0x443,
-0x433, 0x430, 0x430, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x434, 0x4e9, 0x440, 0x4e9, 0x432, 0x434, 0x4af, 0x433, 0x44d, 0x44d, 0x440,
-0x20, 0x441, 0x430, 0x440, 0x3b, 0x442, 0x430, 0x432, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x437,
-0x443, 0x440, 0x433, 0x430, 0x430, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x434, 0x43e, 0x43b, 0x43e,
-0x43e, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x43d, 0x430, 0x439, 0x43c, 0x434, 0x443, 0x433, 0x430,
-0x430, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x435, 0x441, 0x434, 0x4af, 0x433, 0x44d, 0x44d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b,
-0x430, 0x440, 0x430, 0x432, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x430, 0x440, 0x432, 0x430, 0x43d,
-0x20, 0x43d, 0x44d, 0x433, 0x434, 0x4af, 0x433, 0x44d, 0x44d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x430, 0x440, 0x432, 0x430, 0x43d,
-0x20, 0x445, 0x43e, 0x451, 0x440, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440, 0x20, 0x441, 0x430, 0x440, 0x31, 0x2d, 0x440, 0x20, 0x441,
-0x430, 0x440, 0x3b, 0x32, 0x2d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x33, 0x2d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x34,
-0x2d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x35, 0x2d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x36, 0x2d, 0x440, 0x20, 0x441,
-0x430, 0x440, 0x3b, 0x37, 0x2d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x38, 0x2d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x39,
-0x2d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x31, 0x30, 0x2d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x31, 0x31, 0x2d, 0x440,
-0x20, 0x441, 0x430, 0x440, 0x3b, 0x31, 0x32, 0x2d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x49, 0x3b, 0x49, 0x49, 0x3b, 0x49, 0x49,
-0x49, 0x3b, 0x49, 0x56, 0x3b, 0x56, 0x3b, 0x56, 0x49, 0x3b, 0x56, 0x49, 0x49, 0x3b, 0x56, 0x49, 0x49, 0x49, 0x3b, 0x49,
-0x58, 0x3b, 0x58, 0x3b, 0x58, 0x49, 0x3b, 0x58, 0x49, 0x49, 0x7a, 0x61, 0x6e, 0x76, 0x69, 0x65, 0x3b, 0x66, 0x65, 0x76,
-0x72, 0x69, 0x79, 0x65, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x3b, 0x61, 0x76, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x65, 0x3b, 0x7a,
-0x69, 0x6e, 0x3b, 0x7a, 0x69, 0x6c, 0x79, 0x65, 0x3b, 0x6f, 0x75, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x61, 0x6d, 0x3b,
-0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x3b, 0x6e, 0x6f, 0x76, 0x61, 0x6d, 0x3b, 0x64, 0x65, 0x73, 0x61, 0x6d, 0x7a, 0x61, 0x6e,
-0x3b, 0x66, 0x65, 0x76, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x61, 0x76, 0x72, 0x3b, 0x6d, 0x65, 0x3b, 0x7a, 0x69, 0x6e, 0x3b,
-0x7a, 0x69, 0x6c, 0x3b, 0x6f, 0x75, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x76, 0x3b,
-0x64, 0x65, 0x73, 0x7a, 0x3b, 0x66, 0x3b, 0x6d, 0x3b, 0x61, 0x3b, 0x6d, 0x3b, 0x7a, 0x3b, 0x7a, 0x3b, 0x6f, 0x3b, 0x73,
-0x3b, 0x6f, 0x3b, 0x6e, 0x3b, 0x64, 0x46, 0x129, 0x69, 0x20, 0x4c, 0x6f, 0x6f, 0x3b, 0x43, 0x6f, 0x6b, 0x63, 0x77, 0x61,
-0x6b, 0x6c, 0x61, 0x14b, 0x6e, 0x65, 0x3b, 0x43, 0x6f, 0x6b, 0x63, 0x77, 0x61, 0x6b, 0x6c, 0x69, 0x69, 0x3b, 0x46, 0x129,
-0x69, 0x20, 0x4d, 0x61, 0x72, 0x66, 0x6f, 0x6f, 0x3b, 0x4d, 0x61, 0x64, 0x1dd, 0x1dd, 0x75, 0x75, 0x74, 0x1dd, 0x62, 0x69,
-0x6a, 0x61, 0x14b, 0x3b, 0x4d, 0x61, 0x6d, 0x1dd, 0x14b, 0x67, 0x77, 0xe3, 0x61, 0x66, 0x61, 0x68, 0x62, 0x69, 0x69, 0x3b,
-0x4d, 0x61, 0x6d, 0x1dd, 0x14b, 0x67, 0x77, 0xe3, 0x61, 0x6c, 0x69, 0x69, 0x3b, 0x4d, 0x61, 0x64, 0x1dd, 0x6d, 0x62, 0x69,
-0x69, 0x3b, 0x46, 0x129, 0x69, 0x20, 0x44, 0x1dd, 0x253, 0x6c, 0x69, 0x69, 0x3b, 0x46, 0x129, 0x69, 0x20, 0x4d, 0x75, 0x6e,
-0x64, 0x61, 0x14b, 0x3b, 0x46, 0x129, 0x69, 0x20, 0x47, 0x77, 0x61, 0x68, 0x6c, 0x6c, 0x65, 0x3b, 0x46, 0x129, 0x69, 0x20,
-0x59, 0x75, 0x72, 0x75, 0x46, 0x4c, 0x4f, 0x3b, 0x43, 0x4c, 0x41, 0x3b, 0x43, 0x4b, 0x49, 0x3b, 0x46, 0x4d, 0x46, 0x3b,
-0x4d, 0x41, 0x44, 0x3b, 0x4d, 0x42, 0x49, 0x3b, 0x4d, 0x4c, 0x49, 0x3b, 0x4d, 0x41, 0x4d, 0x3b, 0x46, 0x44, 0x45, 0x3b,
-0x46, 0x4d, 0x55, 0x3b, 0x46, 0x47, 0x57, 0x3b, 0x46, 0x59, 0x55, 0x4f, 0x3b, 0x41, 0x3b, 0x49, 0x3b, 0x46, 0x3b, 0x44,
-0x3b, 0x42, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x45, 0x3b, 0x55, 0x3b, 0x57, 0x3b, 0x59, 0x1c3, 0x4b, 0x68, 0x61, 0x6e, 0x6e,
-0x69, 0x3b, 0x1c3, 0x4b, 0x68, 0x61, 0x6e, 0x1c0, 0x67, 0xf4, 0x61, 0x62, 0x3b, 0x1c0, 0x4b, 0x68, 0x75, 0x75, 0x1c1, 0x6b,
-0x68, 0xe2, 0x62, 0x3b, 0x1c3, 0x48, 0xf4, 0x61, 0x1c2, 0x6b, 0x68, 0x61, 0x69, 0x62, 0x3b, 0x1c3, 0x4b, 0x68, 0x61, 0x69,
-0x74, 0x73, 0xe2, 0x62, 0x3b, 0x47, 0x61, 0x6d, 0x61, 0x1c0, 0x61, 0x65, 0x62, 0x3b, 0x1c2, 0x4b, 0x68, 0x6f, 0x65, 0x73,
-0x61, 0x6f, 0x62, 0x3b, 0x41, 0x6f, 0x1c1, 0x6b, 0x68, 0x75, 0x75, 0x6d, 0xfb, 0x1c1, 0x6b, 0x68, 0xe2, 0x62, 0x3b, 0x54,
-0x61, 0x72, 0x61, 0x1c0, 0x6b, 0x68, 0x75, 0x75, 0x6d, 0xfb, 0x1c1, 0x6b, 0x68, 0xe2, 0x62, 0x3b, 0x1c2, 0x4e, 0xfb, 0x1c1,
-0x6e, 0xe2, 0x69, 0x73, 0x65, 0x62, 0x3b, 0x1c0, 0x48, 0x6f, 0x6f, 0x1c2, 0x67, 0x61, 0x65, 0x62, 0x3b, 0x48, 0xf4, 0x61,
-0x73, 0x6f, 0x72, 0x65, 0x1c1, 0x6b, 0x68, 0xe2, 0x62, 0x91c, 0x928, 0x935, 0x930, 0x940, 0x3b, 0x92b, 0x947, 0x92c, 0x94d, 0x930,
-0x941, 0x905, 0x930, 0x940, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x93f, 0x932, 0x3b, 0x92e, 0x947,
-0x3b, 0x91c, 0x941, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x93e, 0x908, 0x3b, 0x905, 0x917, 0x938, 0x94d, 0x91f, 0x3b, 0x938, 0x947, 0x92a,
-0x94d, 0x91f, 0x947, 0x92e, 0x94d, 0x92c, 0x930, 0x3b, 0x905, 0x915, 0x94d, 0x91f, 0x94b, 0x92c, 0x930, 0x3b, 0x928, 0x94b, 0x92d, 0x947,
-0x92e, 0x94d, 0x92c, 0x930, 0x3b, 0x921, 0x93f, 0x938, 0x947, 0x92e, 0x94d, 0x92c, 0x930, 0x91c, 0x928, 0x3b, 0x92b, 0x947, 0x947, 0x92c,
-0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x3b, 0x92e, 0x947, 0x3b, 0x91c, 0x941, 0x928, 0x3b, 0x91c,
-0x941, 0x932, 0x3b, 0x905, 0x917, 0x3b, 0x938, 0x947, 0x92a, 0x3b, 0x905, 0x915, 0x94d, 0x91f, 0x94b, 0x3b, 0x928, 0x94b, 0x92d, 0x947,
-0x3b, 0x921, 0x93f, 0x938, 0x947, 0x91c, 0x928, 0x3b, 0x92b, 0x947, 0x92c, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a,
-0x94d, 0x930, 0x3b, 0x92e, 0x947, 0x3b, 0x91c, 0x941, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x3b, 0x905, 0x917, 0x3b, 0x938, 0x947, 0x92a,
-0x3b, 0x905, 0x915, 0x94d, 0x91f, 0x94b, 0x3b, 0x928, 0x94b, 0x92d, 0x947, 0x3b, 0x921, 0x93f, 0x938, 0x947, 0x73, 0x61, 0x14b, 0x20,
-0x74, 0x73, 0x65, 0x74, 0x73, 0x25b, 0x300, 0x25b, 0x20, 0x6c, 0xf9, 0x6d, 0x3b, 0x73, 0x61, 0x14b, 0x20, 0x6b, 0xe0, 0x67,
-0x20, 0x6e, 0x67, 0x77, 0xf3, 0x14b, 0x3b, 0x73, 0x61, 0x14b, 0x20, 0x6c, 0x65, 0x70, 0x79, 0xe8, 0x20, 0x73, 0x68, 0xfa,
-0x6d, 0x3b, 0x73, 0x61, 0x14b, 0x20, 0x63, 0xff, 0xf3, 0x3b, 0x73, 0x61, 0x14b, 0x20, 0x74, 0x73, 0x25b, 0x300, 0x25b, 0x20,
-0x63, 0xff, 0xf3, 0x3b, 0x73, 0x61, 0x14b, 0x20, 0x6e, 0x6a, 0xff, 0x6f, 0x6c, 0xe1, 0x2bc, 0x3b, 0x73, 0x61, 0x14b, 0x20,
-0x74, 0x79, 0x25b, 0x300, 0x62, 0x20, 0x74, 0x79, 0x25b, 0x300, 0x62, 0x20, 0x6d, 0x62, 0x289, 0x300, 0x14b, 0x3b, 0x73, 0x61,
-0x14b, 0x20, 0x6d, 0x62, 0x289, 0x300, 0x14b, 0x3b, 0x73, 0x61, 0x14b, 0x20, 0x6e, 0x67, 0x77, 0x254, 0x300, 0x2bc, 0x20, 0x6d,
-0x62, 0xff, 0x25b, 0x3b, 0x73, 0x61, 0x14b, 0x20, 0x74, 0xe0, 0x14b, 0x61, 0x20, 0x74, 0x73, 0x65, 0x74, 0x73, 0xe1, 0x2bc,
-0x3b, 0x73, 0x61, 0x14b, 0x20, 0x6d, 0x65, 0x6a, 0x77, 0x6f, 0x14b, 0xf3, 0x3b, 0x73, 0x61, 0x14b, 0x20, 0x6c, 0xf9, 0x6d,
-0x4e, 0x64, 0x75, 0x14b, 0x6d, 0x62, 0x69, 0x20, 0x53, 0x61, 0x14b, 0x3b, 0x50, 0x25b, 0x73, 0x61, 0x14b, 0x20, 0x50, 0x25b,
-0x301, 0x70, 0xe1, 0x3b, 0x50, 0x25b, 0x73, 0x61, 0x14b, 0x20, 0x50, 0x25b, 0x301, 0x74, 0xe1, 0x74, 0x3b, 0x50, 0x25b, 0x73,
-0x61, 0x14b, 0x20, 0x50, 0x25b, 0x301, 0x6e, 0x25b, 0x301, 0x6b, 0x77, 0x61, 0x3b, 0x50, 0x25b, 0x73, 0x61, 0x14b, 0x20, 0x50,
-0x61, 0x74, 0x61, 0x61, 0x3b, 0x50, 0x25b, 0x73, 0x61, 0x14b, 0x20, 0x50, 0x25b, 0x301, 0x6e, 0x25b, 0x301, 0x6e, 0x74, 0xfa,
-0x6b, 0xfa, 0x3b, 0x50, 0x25b, 0x73, 0x61, 0x14b, 0x20, 0x53, 0x61, 0x61, 0x6d, 0x62, 0xe1, 0x3b, 0x50, 0x25b, 0x73, 0x61,
-0x14b, 0x20, 0x50, 0x25b, 0x301, 0x6e, 0x25b, 0x301, 0x66, 0x254, 0x6d, 0x3b, 0x50, 0x25b, 0x73, 0x61, 0x14b, 0x20, 0x50, 0x25b,
-0x301, 0x6e, 0x25b, 0x301, 0x70, 0x66, 0xfa, 0xa78b, 0xfa, 0x3b, 0x50, 0x25b, 0x73, 0x61, 0x14b, 0x20, 0x4e, 0x25b, 0x67, 0x25b,
-0x301, 0x6d, 0x3b, 0x50, 0x25b, 0x73, 0x61, 0x14b, 0x20, 0x4e, 0x74, 0x73, 0x254, 0x30c, 0x70, 0x6d, 0x254, 0x301, 0x3b, 0x50,
-0x25b, 0x73, 0x61, 0x14b, 0x20, 0x4e, 0x74, 0x73, 0x254, 0x30c, 0x70, 0x70, 0xe1, 0x4a, 0xe9, 0x6e, 0xfa, 0xe1, 0x72, 0x69,
-0x3b, 0x46, 0x1eb9, 0x301, 0x62, 0xfa, 0xe1, 0x72, 0x69, 0x3b, 0x4d, 0x61, 0x63, 0x68, 0x3b, 0xc9, 0x70, 0x72, 0x65, 0x6c,
-0x3b, 0x4d, 0x65, 0x65, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x61, 0x69, 0x3b, 0x1ecc, 0x67, 0x1ecd, 0x73, 0x74,
-0x3b, 0x53, 0x1eb9, 0x70, 0x74, 0x1eb9, 0x301, 0x6d, 0x62, 0x61, 0x3b, 0x1ecc, 0x6b, 0x74, 0xf3, 0x62, 0x61, 0x3b, 0x4e, 0x1ecd,
-0x76, 0x1eb9, 0x301, 0x6d, 0x62, 0x61, 0x3b, 0x44, 0x69, 0x73, 0x1eb9, 0x301, 0x6d, 0x62, 0x61, 0x4a, 0xe9, 0x6e, 0x3b, 0x46,
-0x1eb9, 0x301, 0x62, 0x3b, 0x4d, 0x61, 0x63, 0x68, 0x3b, 0xc9, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x65, 0x3b, 0x4a, 0x75, 0x6e,
-0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x1ecc, 0x301, 0x67, 0x1ecd, 0x3b, 0x53, 0x1eb9, 0x70, 0x3b, 0x1ecc, 0x6b, 0x74, 0x3b, 0x4e, 0x1ecd,
-0x76, 0x3b, 0x44, 0x69, 0x73, 0x4a, 0xe9, 0x6e, 0x3b, 0x46, 0x1eb9, 0x301, 0x62, 0x3b, 0x4d, 0x61, 0x63, 0x68, 0x3b, 0xc9,
-0x70, 0x72, 0x3b, 0x4d, 0x65, 0x65, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x1ecc, 0x67, 0x1ecd, 0x3b, 0x53,
-0x1eb9, 0x70, 0x3b, 0x1ecc, 0x6b, 0x74, 0x3b, 0x4e, 0x1ecd, 0x76, 0x3b, 0x44, 0x69, 0x73, 0x62c, 0x627, 0x646, 0x6a4, 0x6cc, 0x6d5,
-0x3b, 0x641, 0x626, 0x6a4, 0x631, 0x6cc, 0x6d5, 0x3b, 0x645, 0x627, 0x631, 0x633, 0x3b, 0x622, 0x6a4, 0x631, 0x6cc, 0x644, 0x3b, 0x645,
-0x626, 0x6cc, 0x3b, 0x62c, 0x648, 0x659, 0x623, 0x646, 0x3b, 0x62c, 0x648, 0x659, 0x644, 0x627, 0x3b, 0x622, 0x6af, 0x648, 0x633, 0x62a,
-0x3b, 0x633, 0x626, 0x67e, 0x62a, 0x627, 0x645, 0x631, 0x3b, 0x626, 0x648, 0x6a9, 0x62a, 0x648, 0x6a4, 0x631, 0x3b, 0x646, 0x648, 0x6a4,
-0x627, 0x645, 0x631, 0x3b, 0x62f, 0x626, 0x633, 0x627, 0x645, 0x631, 0x6f, 0x111, 0x111, 0x61, 0x6a, 0x61, 0x67, 0x65, 0x6d, 0xe1,
-0x6e, 0x6e, 0x75, 0x3b, 0x67, 0x75, 0x6f, 0x76, 0x76, 0x61, 0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x3b, 0x6e, 0x6a, 0x75, 0x6b,
-0x10d, 0x61, 0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x3b, 0x63, 0x75, 0x6f, 0x14b, 0x6f, 0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x3b, 0x6d,
-0x69, 0x65, 0x73, 0x73, 0x65, 0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x3b, 0x67, 0x65, 0x61, 0x73, 0x73, 0x65, 0x6d, 0xe1, 0x6e,
-0x6e, 0x75, 0x3b, 0x73, 0x75, 0x6f, 0x69, 0x64, 0x6e, 0x65, 0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x3b, 0x62, 0x6f, 0x72, 0x67,
-0x65, 0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x3b, 0x10d, 0x61, 0x6b, 0x10d, 0x61, 0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x3b, 0x67, 0x6f,
-0x6c, 0x67, 0x67, 0x6f, 0x74, 0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x3b, 0x73, 0x6b, 0xe1, 0x62, 0x6d, 0x61, 0x6d, 0xe1, 0x6e,
-0x6e, 0x75, 0x3b, 0x6a, 0x75, 0x6f, 0x76, 0x6c, 0x61, 0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x6f, 0x111, 0x111, 0x6a, 0x3b, 0x67,
-0x75, 0x6f, 0x76, 0x3b, 0x6e, 0x6a, 0x75, 0x6b, 0x3b, 0x63, 0x75, 0x6f, 0x3b, 0x6d, 0x69, 0x65, 0x73, 0x3b, 0x67, 0x65,
-0x61, 0x73, 0x3b, 0x73, 0x75, 0x6f, 0x69, 0x3b, 0x62, 0x6f, 0x72, 0x67, 0x3b, 0x10d, 0x61, 0x6b, 0x10d, 0x3b, 0x67, 0x6f,
-0x6c, 0x67, 0x3b, 0x73, 0x6b, 0xe1, 0x62, 0x3b, 0x6a, 0x75, 0x6f, 0x76, 0x4f, 0x3b, 0x47, 0x3b, 0x4e, 0x3b, 0x43, 0x3b,
-0x4d, 0x3b, 0x47, 0x3b, 0x53, 0x3b, 0x42, 0x3b, 0x10c, 0x3b, 0x47, 0x3b, 0x53, 0x3b, 0x4a, 0x6f, 0x111, 0x111, 0x6a, 0x3b,
-0x67, 0x75, 0x6f, 0x76, 0x3b, 0x6e, 0x6a, 0x75, 0x6b, 0x3b, 0x63, 0x75, 0x6f, 0x14b, 0x3b, 0x6d, 0x69, 0x65, 0x73, 0x3b,
-0x67, 0x65, 0x61, 0x73, 0x3b, 0x73, 0x75, 0x6f, 0x69, 0x3b, 0x62, 0x6f, 0x72, 0x67, 0x3b, 0x10d, 0x61, 0x6b, 0x10d, 0x3b,
-0x67, 0x6f, 0x6c, 0x67, 0x3b, 0x73, 0x6b, 0xe1, 0x62, 0x3b, 0x6a, 0x75, 0x6f, 0x76, 0x5a, 0x69, 0x62, 0x61, 0x6e, 0x64,
-0x6c, 0x65, 0x6c, 0x61, 0x3b, 0x4e, 0x68, 0x6c, 0x6f, 0x6c, 0x61, 0x6e, 0x6a, 0x61, 0x3b, 0x4d, 0x62, 0x69, 0x6d, 0x62,
-0x69, 0x74, 0x68, 0x6f, 0x3b, 0x4d, 0x61, 0x62, 0x61, 0x73, 0x61, 0x3b, 0x4e, 0x6b, 0x77, 0x65, 0x6e, 0x6b, 0x77, 0x65,
-0x7a, 0x69, 0x3b, 0x4e, 0x68, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x6c, 0x61, 0x3b, 0x4e, 0x74, 0x75, 0x6c, 0x69, 0x6b, 0x61,
-0x7a, 0x69, 0x3b, 0x4e, 0x63, 0x77, 0x61, 0x62, 0x61, 0x6b, 0x61, 0x7a, 0x69, 0x3b, 0x4d, 0x70, 0x61, 0x6e, 0x64, 0x75,
-0x6c, 0x61, 0x3b, 0x4d, 0x66, 0x75, 0x6d, 0x66, 0x75, 0x3b, 0x4c, 0x77, 0x65, 0x7a, 0x69, 0x3b, 0x4d, 0x70, 0x61, 0x6c,
-0x61, 0x6b, 0x61, 0x7a, 0x69, 0x5a, 0x69, 0x62, 0x3b, 0x4e, 0x68, 0x6c, 0x6f, 0x3b, 0x4d, 0x62, 0x69, 0x3b, 0x4d, 0x61,
-0x62, 0x3b, 0x4e, 0x6b, 0x77, 0x3b, 0x4e, 0x68, 0x6c, 0x61, 0x3b, 0x4e, 0x74, 0x75, 0x3b, 0x4e, 0x63, 0x77, 0x3b, 0x4d,
-0x70, 0x61, 0x6e, 0x3b, 0x4d, 0x66, 0x75, 0x3b, 0x4c, 0x77, 0x65, 0x3b, 0x4d, 0x70, 0x61, 0x6c, 0x5a, 0x3b, 0x4e, 0x3b,
-0x4d, 0x3b, 0x4d, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x4c, 0x3b, 0x4d, 0x6a,
-0x61, 0x6e, 0x75, 0x61, 0x72, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x3b, 0x61,
-0x70, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x61, 0x69, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x3b, 0x61,
-0x75, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x6f,
-0x62, 0x65, 0x72, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x64, 0x65, 0x73, 0x65, 0x6d, 0x62, 0x65,
-0x72, 0x6a, 0x61, 0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x62, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x3b, 0x61, 0x70, 0x72, 0x2e,
-0x3b, 0x6d, 0x61, 0x69, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x3b, 0x61, 0x75, 0x67, 0x2e, 0x3b,
-0x73, 0x65, 0x70, 0x2e, 0x3b, 0x6f, 0x6b, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x73, 0x2e, 0x54,
-0x69, 0x6f, 0x70, 0x20, 0x74, 0x68, 0x61, 0x72, 0x20, 0x70, 0x25b, 0x74, 0x3b, 0x50, 0x25b, 0x74, 0x3b, 0x44, 0x75, 0x254,
-0x331, 0x254, 0x331, 0x14b, 0x3b, 0x47, 0x75, 0x61, 0x6b, 0x3b, 0x44, 0x75, 0xe4, 0x74, 0x3b, 0x4b, 0x6f, 0x72, 0x6e, 0x79,
-0x6f, 0x6f, 0x74, 0x3b, 0x50, 0x61, 0x79, 0x20, 0x79, 0x69, 0x65, 0x331, 0x74, 0x6e, 0x69, 0x3b, 0x54, 0x68, 0x6f, 0x331,
-0x6f, 0x331, 0x72, 0x3b, 0x54, 0x25b, 0x25b, 0x72, 0x3b, 0x4c, 0x61, 0x61, 0x74, 0x68, 0x3b, 0x4b, 0x75, 0x72, 0x3b, 0x54,
-0x69, 0x6f, 0x331, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x64, 0x69, 0x331, 0x69, 0x331, 0x74, 0x54, 0x69, 0x6f, 0x70, 0x3b, 0x50,
-0x25b, 0x74, 0x3b, 0x44, 0x75, 0x254, 0x331, 0x254, 0x331, 0x3b, 0x47, 0x75, 0x61, 0x6b, 0x3b, 0x44, 0x75, 0xe4, 0x3b, 0x4b,
-0x6f, 0x72, 0x3b, 0x50, 0x61, 0x79, 0x3b, 0x54, 0x68, 0x6f, 0x6f, 0x3b, 0x54, 0x25b, 0x25b, 0x3b, 0x4c, 0x61, 0x61, 0x3b,
-0x4b, 0x75, 0x72, 0x3b, 0x54, 0x69, 0x64, 0x54, 0x3b, 0x50, 0x3b, 0x44, 0x3b, 0x47, 0x3b, 0x44, 0x3b, 0x4b, 0x3b, 0x50,
-0x3b, 0x54, 0x3b, 0x54, 0x3b, 0x4c, 0x3b, 0x4b, 0x3b, 0x54, 0x67, 0x65, 0x6e, 0x69, 0xe8, 0x72, 0x3b, 0x66, 0x65, 0x62,
-0x72, 0x69, 0xe8, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0xe7, 0x3b, 0x61, 0x62, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x61, 0x69, 0x3b,
-0x6a, 0x75, 0x6e, 0x68, 0x3b, 0x6a, 0x75, 0x6c, 0x68, 0x65, 0x74, 0x3b, 0x61, 0x67, 0x6f, 0x73, 0x74, 0x3b, 0x73, 0x65,
-0x74, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x6f, 0x63, 0x74, 0xf2, 0x62, 0x72, 0x65, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d,
-0x62, 0x72, 0x65, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x64, 0x65, 0x20, 0x67, 0x65, 0x6e, 0x69, 0xe8,
-0x72, 0x3b, 0x64, 0x65, 0x20, 0x66, 0x65, 0x62, 0x72, 0x69, 0xe8, 0x72, 0x3b, 0x64, 0x65, 0x20, 0x6d, 0x61, 0x72, 0xe7,
-0x3b, 0x64, 0x2019, 0x61, 0x62, 0x72, 0x69, 0x6c, 0x3b, 0x64, 0x65, 0x20, 0x6d, 0x61, 0x69, 0x3b, 0x64, 0x65, 0x20, 0x6a,
-0x75, 0x6e, 0x68, 0x3b, 0x64, 0x65, 0x20, 0x6a, 0x75, 0x6c, 0x68, 0x65, 0x74, 0x3b, 0x64, 0x2019, 0x61, 0x67, 0x6f, 0x73,
-0x74, 0x3b, 0x64, 0x65, 0x20, 0x73, 0x65, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x2019, 0x6f, 0x63, 0x74, 0xf2,
-0x62, 0x72, 0x65, 0x3b, 0x64, 0x65, 0x20, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x65, 0x20, 0x64,
-0x65, 0x63, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x67, 0x65, 0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x62, 0x2e, 0x3b, 0x6d, 0x61, 0x72,
-0xe7, 0x3b, 0x61, 0x62, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x69, 0x3b, 0x6a, 0x75, 0x6e, 0x68, 0x3b, 0x6a, 0x75, 0x6c, 0x2e,
-0x3b, 0x61, 0x67, 0x6f, 0x2e, 0x3b, 0x73, 0x65, 0x74, 0x2e, 0x3b, 0x6f, 0x63, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e,
-0x3b, 0x64, 0x65, 0x63, 0x2e, 0x47, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x41,
-0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x67, 0xe8, 0x72, 0x3b, 0x68, 0x65, 0x72, 0x65, 0x75, 0xe8, 0x72, 0x3b,
-0x6d, 0x61, 0x72, 0xe7, 0x3b, 0x61, 0x62, 0x72, 0x69, 0x75, 0x3b, 0x6d, 0x61, 0x69, 0x3b, 0x6a, 0x75, 0x6e, 0x68, 0x3b,
-0x6a, 0x75, 0x72, 0x69, 0xf2, 0x6c, 0x3b, 0x61, 0x67, 0x6f, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x74, 0x65, 0x6d, 0x65, 0x3b,
-0x6f, 0x63, 0x74, 0x6f, 0x62, 0x72, 0x65, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x65, 0x3b, 0x64, 0x65, 0x73, 0x65, 0x6d,
-0x65, 0x67, 0xe8, 0x72, 0x3b, 0x68, 0x65, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x61, 0x62, 0x72, 0x3b, 0x6d, 0x61, 0x69,
-0x3b, 0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x72, 0x3b, 0x61, 0x67, 0x6f, 0x3b, 0x73, 0x65, 0x74, 0x3b, 0x6f, 0x63, 0x74,
-0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65, 0x63, 0x47, 0x3b, 0x48, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4a, 0x3b,
-0x4a, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0xb1c, 0xb3e, 0xb28, 0xb41, 0xb06, 0xb30, 0xb40, 0x3b, 0xb2b,
-0xb47, 0xb2c, 0xb43, 0xb06, 0xb30, 0xb40, 0x3b, 0xb2e, 0xb3e, 0xb30, 0xb4d, 0xb1a, 0xb4d, 0xb1a, 0x3b, 0xb05, 0xb2a, 0xb4d, 0xb30, 0xb47,
-0xb32, 0x3b, 0xb2e, 0xb07, 0x3b, 0xb1c, 0xb41, 0xb28, 0x3b, 0xb1c, 0xb41, 0xb32, 0xb3e, 0xb07, 0x3b, 0xb05, 0xb17, 0xb37, 0xb4d, 0xb1f,
-0x3b, 0xb38, 0xb47, 0xb2a, 0xb4d, 0xb1f, 0xb47, 0xb2e, 0xb4d, 0xb2c, 0xb30, 0x3b, 0xb05, 0xb15, 0xb4d, 0xb1f, 0xb4b, 0xb2c, 0xb30, 0x3b,
-0xb28, 0xb2d, 0xb47, 0xb2e, 0xb4d, 0xb2c, 0xb30, 0x3b, 0xb21, 0xb3f, 0xb38, 0xb47, 0xb2e, 0xb4d, 0xb2c, 0xb30, 0xb1c, 0xb3e, 0x3b, 0xb2b,
-0xb47, 0x3b, 0xb2e, 0xb3e, 0x3b, 0xb05, 0x3b, 0xb2e, 0xb07, 0x3b, 0xb1c, 0xb41, 0x3b, 0xb1c, 0xb41, 0x3b, 0xb05, 0x3b, 0xb38, 0xb47,
-0x3b, 0xb05, 0x3b, 0xb28, 0x3b, 0xb21, 0xb3f, 0x41, 0x6d, 0x61, 0x6a, 0x6a, 0x69, 0x69, 0x3b, 0x47, 0x75, 0x72, 0x61, 0x61,
-0x6e, 0x64, 0x68, 0x61, 0x6c, 0x61, 0x3b, 0x42, 0x69, 0x74, 0x6f, 0x6f, 0x74, 0x65, 0x65, 0x73, 0x73, 0x61, 0x3b, 0x45,
-0x6c, 0x62, 0x61, 0x3b, 0x43, 0x61, 0x61, 0x6d, 0x73, 0x61, 0x3b, 0x57, 0x61, 0x78, 0x61, 0x62, 0x61, 0x6a, 0x6a, 0x69,
-0x69, 0x3b, 0x41, 0x64, 0x6f, 0x6f, 0x6c, 0x65, 0x65, 0x73, 0x73, 0x61, 0x3b, 0x48, 0x61, 0x67, 0x61, 0x79, 0x79, 0x61,
-0x3b, 0x46, 0x75, 0x75, 0x6c, 0x62, 0x61, 0x6e, 0x61, 0x3b, 0x4f, 0x6e, 0x6b, 0x6f, 0x6c, 0x6f, 0x6c, 0x65, 0x65, 0x73,
-0x73, 0x61, 0x3b, 0x53, 0x61, 0x64, 0x61, 0x61, 0x73, 0x61, 0x3b, 0x4d, 0x75, 0x64, 0x64, 0x65, 0x65, 0x41, 0x6d, 0x61,
-0x3b, 0x47, 0x75, 0x72, 0x3b, 0x42, 0x69, 0x74, 0x3b, 0x45, 0x6c, 0x62, 0x3b, 0x43, 0x61, 0x6d, 0x3b, 0x57, 0x61, 0x78,
-0x3b, 0x41, 0x64, 0x6f, 0x3b, 0x48, 0x61, 0x67, 0x3b, 0x46, 0x75, 0x6c, 0x3b, 0x4f, 0x6e, 0x6b, 0x3b, 0x53, 0x61, 0x64,
-0x3b, 0x4d, 0x75, 0x64, 0x41, 0x3b, 0x47, 0x3b, 0x42, 0x3b, 0x45, 0x3b, 0x43, 0x3b, 0x57, 0x3b, 0x41, 0x3b, 0x48, 0x3b,
-0x46, 0x3b, 0x4f, 0x3b, 0x53, 0x3b, 0x4d, 0x42f, 0x43d, 0x432, 0x430, 0x440, 0x44c, 0x3b, 0x424, 0x435, 0x432, 0x440, 0x430, 0x43b,
-0x44c, 0x3b, 0x41c, 0x430, 0x440, 0x442, 0x44a, 0x438, 0x3b, 0x410, 0x43f, 0x440, 0x435, 0x43b, 0x44c, 0x3b, 0x41c, 0x430, 0x439, 0x3b,
-0x418, 0x44e, 0x43d, 0x44c, 0x3b, 0x418, 0x44e, 0x43b, 0x44c, 0x3b, 0x410, 0x432, 0x433, 0x443, 0x441, 0x442, 0x3b, 0x421, 0x435, 0x43d,
-0x442, 0x44f, 0x431, 0x440, 0x44c, 0x3b, 0x41e, 0x43a, 0x442, 0x44f, 0x431, 0x440, 0x44c, 0x3b, 0x41d, 0x43e, 0x44f, 0x431, 0x440, 0x44c,
-0x3b, 0x414, 0x435, 0x43a, 0x430, 0x431, 0x440, 0x44c, 0x44f, 0x43d, 0x432, 0x430, 0x440, 0x44b, 0x3b, 0x444, 0x435, 0x432, 0x440, 0x430,
-0x43b, 0x44b, 0x3b, 0x43c, 0x430, 0x440, 0x442, 0x44a, 0x438, 0x439, 0x44b, 0x3b, 0x430, 0x43f, 0x440, 0x435, 0x43b, 0x44b, 0x3b, 0x43c,
-0x430, 0x439, 0x44b, 0x3b, 0x438, 0x44e, 0x43d, 0x44b, 0x3b, 0x438, 0x44e, 0x43b, 0x44b, 0x3b, 0x430, 0x432, 0x433, 0x443, 0x441, 0x442,
-0x44b, 0x3b, 0x441, 0x435, 0x43d, 0x442, 0x44f, 0x431, 0x440, 0x44b, 0x3b, 0x43e, 0x43a, 0x442, 0x44f, 0x431, 0x440, 0x44b, 0x3b, 0x43d,
-0x43e, 0x44f, 0x431, 0x440, 0x44b, 0x3b, 0x434, 0x435, 0x43a, 0x430, 0x431, 0x440, 0x44b, 0x42f, 0x43d, 0x432, 0x2e, 0x3b, 0x424, 0x435,
-0x432, 0x440, 0x2e, 0x3b, 0x41c, 0x430, 0x440, 0x442, 0x2e, 0x3b, 0x410, 0x43f, 0x440, 0x2e, 0x3b, 0x41c, 0x430, 0x439, 0x3b, 0x418,
-0x44e, 0x43d, 0x44c, 0x3b, 0x418, 0x44e, 0x43b, 0x44c, 0x3b, 0x410, 0x432, 0x433, 0x2e, 0x3b, 0x421, 0x435, 0x43d, 0x442, 0x2e, 0x3b,
-0x41e, 0x43a, 0x442, 0x2e, 0x3b, 0x41d, 0x43e, 0x44f, 0x431, 0x2e, 0x3b, 0x414, 0x435, 0x43a, 0x2e, 0x44f, 0x43d, 0x432, 0x2e, 0x3b,
-0x444, 0x435, 0x432, 0x2e, 0x3b, 0x43c, 0x430, 0x440, 0x2e, 0x3b, 0x430, 0x43f, 0x440, 0x2e, 0x3b, 0x43c, 0x430, 0x439, 0x44b, 0x3b,
-0x438, 0x44e, 0x43d, 0x44b, 0x3b, 0x438, 0x44e, 0x43b, 0x44b, 0x3b, 0x430, 0x432, 0x433, 0x2e, 0x3b, 0x441, 0x435, 0x43d, 0x2e, 0x3b,
-0x43e, 0x43a, 0x442, 0x2e, 0x3b, 0x43d, 0x43e, 0x44f, 0x2e, 0x3b, 0x434, 0x435, 0x43a, 0x2e, 0x62c, 0x646, 0x648, 0x631, 0x64a, 0x3b,
-0x641, 0x6d0, 0x628, 0x631, 0x648, 0x631, 0x64a, 0x3b, 0x645, 0x627, 0x631, 0x686, 0x3b, 0x627, 0x67e, 0x631, 0x6cc, 0x644, 0x3b, 0x645,
-0x6cd, 0x3b, 0x62c, 0x648, 0x646, 0x3b, 0x62c, 0x648, 0x644, 0x627, 0x6cc, 0x3b, 0x627, 0x6ab, 0x633, 0x62a, 0x3b, 0x633, 0x67e, 0x62a,
-0x645, 0x628, 0x631, 0x3b, 0x627, 0x6a9, 0x62a, 0x648, 0x628, 0x631, 0x3b, 0x646, 0x648, 0x645, 0x628, 0x631, 0x3b, 0x62f, 0x633, 0x645,
-0x628, 0x631, 0x62c, 0x646, 0x648, 0x631, 0x64a, 0x3b, 0x641, 0x628, 0x631, 0x648, 0x631, 0x64a, 0x3b, 0x645, 0x627, 0x631, 0x686, 0x3b,
-0x627, 0x67e, 0x631, 0x6cc, 0x644, 0x3b, 0x645, 0x6cd, 0x3b, 0x62c, 0x648, 0x646, 0x3b, 0x62c, 0x648, 0x644, 0x627, 0x6cc, 0x3b, 0x627,
-0x6ab, 0x633, 0x62a, 0x3b, 0x633, 0x6d0, 0x67e, 0x62a, 0x645, 0x628, 0x631, 0x3b, 0x627, 0x6a9, 0x62a, 0x648, 0x628, 0x631, 0x3b, 0x646,
-0x648, 0x645, 0x628, 0x631, 0x3b, 0x62f, 0x633, 0x645, 0x628, 0x631, 0x62c, 0x646, 0x648, 0x631, 0x64a, 0x3b, 0x641, 0x628, 0x631, 0x648,
-0x631, 0x64a, 0x3b, 0x645, 0x627, 0x631, 0x686, 0x3b, 0x627, 0x67e, 0x631, 0x6cc, 0x644, 0x3b, 0x645, 0x6cd, 0x3b, 0x62c, 0x648, 0x646,
-0x3b, 0x62c, 0x648, 0x644, 0x627, 0x6cc, 0x3b, 0x627, 0x6ab, 0x633, 0x62a, 0x3b, 0x633, 0x67e, 0x62a, 0x645, 0x628, 0x631, 0x3b, 0x627,
-0x6a9, 0x62a, 0x648, 0x628, 0x631, 0x3b, 0x646, 0x648, 0x645, 0x628, 0x631, 0x3b, 0x62f, 0x633, 0x645, 0x628, 0x631, 0x62c, 0x3b, 0x641,
-0x3b, 0x645, 0x3b, 0x627, 0x3b, 0x645, 0x3b, 0x62c, 0x3b, 0x62c, 0x3b, 0x627, 0x3b, 0x633, 0x3b, 0x627, 0x3b, 0x646, 0x3b, 0x62f,
-0x698, 0x627, 0x646, 0x648, 0x6cc, 0x647, 0x654, 0x3b, 0x641, 0x648, 0x631, 0x6cc, 0x647, 0x654, 0x3b, 0x645, 0x627, 0x631, 0x633, 0x3b,
-0x622, 0x648, 0x631, 0x6cc, 0x644, 0x3b, 0x645, 0x647, 0x654, 0x3b, 0x698, 0x648, 0x626, 0x646, 0x3b, 0x698, 0x648, 0x626, 0x6cc, 0x647,
-0x654, 0x3b, 0x627, 0x648, 0x62a, 0x3b, 0x633, 0x67e, 0x62a, 0x627, 0x645, 0x628, 0x631, 0x3b, 0x627, 0x6a9, 0x62a, 0x628, 0x631, 0x3b,
-0x646, 0x648, 0x627, 0x645, 0x628, 0x631, 0x3b, 0x62f, 0x633, 0x627, 0x645, 0x628, 0x631, 0x698, 0x3b, 0x641, 0x3b, 0x645, 0x3b, 0x622,
-0x3b, 0x645, 0x3b, 0x698, 0x3b, 0x698, 0x3b, 0x627, 0x3b, 0x633, 0x3b, 0x627, 0x3b, 0x646, 0x3b, 0x62f, 0x62c, 0x646, 0x648, 0x631,
-0x6cc, 0x3b, 0x641, 0x628, 0x631, 0x648, 0x631, 0x6cc, 0x3b, 0x645, 0x627, 0x631, 0x686, 0x3b, 0x627, 0x67e, 0x631, 0x6cc, 0x644, 0x3b,
-0x645, 0x6cc, 0x3b, 0x62c, 0x648, 0x646, 0x3b, 0x62c, 0x648, 0x644, 0x627, 0x6cc, 0x3b, 0x627, 0x6af, 0x633, 0x62a, 0x3b, 0x633, 0x67e,
-0x62a, 0x645, 0x628, 0x631, 0x3b, 0x627, 0x6a9, 0x62a, 0x648, 0x628, 0x631, 0x3b, 0x646, 0x648, 0x645, 0x628, 0x631, 0x3b, 0x62f, 0x633,
-0x645, 0x628, 0x631, 0x62c, 0x646, 0x648, 0x3b, 0x641, 0x628, 0x631, 0x648, 0x631, 0x6cc, 0x3b, 0x645, 0x627, 0x631, 0x686, 0x3b, 0x627,
-0x67e, 0x631, 0x6cc, 0x644, 0x3b, 0x645, 0x6cc, 0x3b, 0x62c, 0x648, 0x646, 0x3b, 0x62c, 0x648, 0x644, 0x3b, 0x627, 0x6af, 0x633, 0x62a,
-0x3b, 0x633, 0x67e, 0x62a, 0x645, 0x628, 0x631, 0x3b, 0x627, 0x6a9, 0x62a, 0x648, 0x628, 0x631, 0x3b, 0x646, 0x648, 0x645, 0x628, 0x631,
-0x3b, 0x62f, 0x633, 0x645, 0x73, 0x74, 0x79, 0x63, 0x7a, 0x65, 0x144, 0x3b, 0x6c, 0x75, 0x74, 0x79, 0x3b, 0x6d, 0x61, 0x72,
-0x7a, 0x65, 0x63, 0x3b, 0x6b, 0x77, 0x69, 0x65, 0x63, 0x69, 0x65, 0x144, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x63, 0x7a, 0x65,
-0x72, 0x77, 0x69, 0x65, 0x63, 0x3b, 0x6c, 0x69, 0x70, 0x69, 0x65, 0x63, 0x3b, 0x73, 0x69, 0x65, 0x72, 0x70, 0x69, 0x65,
-0x144, 0x3b, 0x77, 0x72, 0x7a, 0x65, 0x73, 0x69, 0x65, 0x144, 0x3b, 0x70, 0x61, 0x17a, 0x64, 0x7a, 0x69, 0x65, 0x72, 0x6e,
-0x69, 0x6b, 0x3b, 0x6c, 0x69, 0x73, 0x74, 0x6f, 0x70, 0x61, 0x64, 0x3b, 0x67, 0x72, 0x75, 0x64, 0x7a, 0x69, 0x65, 0x144,
-0x73, 0x74, 0x79, 0x63, 0x7a, 0x6e, 0x69, 0x61, 0x3b, 0x6c, 0x75, 0x74, 0x65, 0x67, 0x6f, 0x3b, 0x6d, 0x61, 0x72, 0x63,
-0x61, 0x3b, 0x6b, 0x77, 0x69, 0x65, 0x74, 0x6e, 0x69, 0x61, 0x3b, 0x6d, 0x61, 0x6a, 0x61, 0x3b, 0x63, 0x7a, 0x65, 0x72,
-0x77, 0x63, 0x61, 0x3b, 0x6c, 0x69, 0x70, 0x63, 0x61, 0x3b, 0x73, 0x69, 0x65, 0x72, 0x70, 0x6e, 0x69, 0x61, 0x3b, 0x77,
-0x72, 0x7a, 0x65, 0x15b, 0x6e, 0x69, 0x61, 0x3b, 0x70, 0x61, 0x17a, 0x64, 0x7a, 0x69, 0x65, 0x72, 0x6e, 0x69, 0x6b, 0x61,
-0x3b, 0x6c, 0x69, 0x73, 0x74, 0x6f, 0x70, 0x61, 0x64, 0x61, 0x3b, 0x67, 0x72, 0x75, 0x64, 0x6e, 0x69, 0x61, 0x73, 0x74,
-0x79, 0x3b, 0x6c, 0x75, 0x74, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x6b, 0x77, 0x69, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x63, 0x7a,
-0x65, 0x3b, 0x6c, 0x69, 0x70, 0x3b, 0x73, 0x69, 0x65, 0x3b, 0x77, 0x72, 0x7a, 0x3b, 0x70, 0x61, 0x17a, 0x3b, 0x6c, 0x69,
-0x73, 0x3b, 0x67, 0x72, 0x75, 0x53, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x4b, 0x3b, 0x4d, 0x3b, 0x43, 0x3b, 0x4c, 0x3b, 0x53,
-0x3b, 0x57, 0x3b, 0x50, 0x3b, 0x4c, 0x3b, 0x47, 0x73, 0x3b, 0x6c, 0x3b, 0x6d, 0x3b, 0x6b, 0x3b, 0x6d, 0x3b, 0x63, 0x3b,
-0x6c, 0x3b, 0x73, 0x3b, 0x77, 0x3b, 0x70, 0x3b, 0x6c, 0x3b, 0x67, 0x6a, 0x61, 0x6e, 0x65, 0x69, 0x72, 0x6f, 0x3b, 0x66,
-0x65, 0x76, 0x65, 0x72, 0x65, 0x69, 0x72, 0x6f, 0x3b, 0x6d, 0x61, 0x72, 0xe7, 0x6f, 0x3b, 0x61, 0x62, 0x72, 0x69, 0x6c,
-0x3b, 0x6d, 0x61, 0x69, 0x6f, 0x3b, 0x6a, 0x75, 0x6e, 0x68, 0x6f, 0x3b, 0x6a, 0x75, 0x6c, 0x68, 0x6f, 0x3b, 0x61, 0x67,
-0x6f, 0x73, 0x74, 0x6f, 0x3b, 0x73, 0x65, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x6f, 0x3b, 0x6f, 0x75, 0x74, 0x75, 0x62, 0x72,
-0x6f, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x6f, 0x3b, 0x64, 0x65, 0x7a, 0x65, 0x6d, 0x62, 0x72, 0x6f, 0x6a,
-0x61, 0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x76, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x61, 0x62, 0x72, 0x2e, 0x3b, 0x6d,
-0x61, 0x69, 0x2e, 0x3b, 0x6a, 0x75, 0x6e, 0x2e, 0x3b, 0x6a, 0x75, 0x6c, 0x2e, 0x3b, 0x61, 0x67, 0x6f, 0x2e, 0x3b, 0x73,
-0x65, 0x74, 0x2e, 0x3b, 0x6f, 0x75, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x7a, 0x2e, 0xa1c, 0xa28,
-0xa35, 0xa30, 0xa40, 0x3b, 0xa2b, 0xa3c, 0xa30, 0xa35, 0xa30, 0xa40, 0x3b, 0xa2e, 0xa3e, 0xa30, 0xa1a, 0x3b, 0xa05, 0xa2a, 0xa4d, 0xa30,
-0xa48, 0xa32, 0x3b, 0xa2e, 0xa08, 0x3b, 0xa1c, 0xa42, 0xa28, 0x3b, 0xa1c, 0xa41, 0xa32, 0xa3e, 0xa08, 0x3b, 0xa05, 0xa17, 0xa38, 0xa24,
-0x3b, 0xa38, 0xa24, 0xa70, 0xa2c, 0xa30, 0x3b, 0xa05, 0xa15, 0xa24, 0xa42, 0xa2c, 0xa30, 0x3b, 0xa28, 0xa35, 0xa70, 0xa2c, 0xa30, 0x3b,
-0xa26, 0xa38, 0xa70, 0xa2c, 0xa30, 0xa1c, 0xa28, 0x3b, 0xa2b, 0xa3c, 0xa30, 0x3b, 0xa2e, 0xa3e, 0xa30, 0xa1a, 0x3b, 0xa05, 0xa2a, 0xa4d,
-0xa30, 0xa48, 0x3b, 0xa2e, 0xa08, 0x3b, 0xa1c, 0xa42, 0xa28, 0x3b, 0xa1c, 0xa41, 0xa32, 0xa3e, 0x3b, 0xa05, 0xa17, 0x3b, 0xa38, 0xa24,
-0xa70, 0x3b, 0xa05, 0xa15, 0xa24, 0xa42, 0x3b, 0xa28, 0xa35, 0xa70, 0x3b, 0xa26, 0xa38, 0xa70, 0xa1c, 0x3b, 0xa2b, 0xa3c, 0x3b, 0xa2e,
-0xa3e, 0x3b, 0xa05, 0x3b, 0xa2e, 0x3b, 0xa1c, 0xa42, 0x3b, 0xa1c, 0xa41, 0x3b, 0xa05, 0x3b, 0xa38, 0x3b, 0xa05, 0x3b, 0xa28, 0x3b,
-0xa26, 0x62c, 0x646, 0x648, 0x631, 0x6cc, 0x3b, 0x641, 0x631, 0x648, 0x631, 0x6cc, 0x3b, 0x645, 0x627, 0x631, 0x686, 0x3b, 0x627, 0x67e,
-0x631, 0x6cc, 0x644, 0x3b, 0x645, 0x626, 0x3b, 0x62c, 0x648, 0x646, 0x3b, 0x62c, 0x648, 0x644, 0x627, 0x626, 0x6cc, 0x3b, 0x627, 0x6af,
-0x633, 0x62a, 0x3b, 0x633, 0x62a, 0x645, 0x628, 0x631, 0x3b, 0x627, 0x6a9, 0x62a, 0x648, 0x628, 0x631, 0x3b, 0x646, 0x648, 0x645, 0x628,
-0x631, 0x3b, 0x62f, 0x633, 0x645, 0x628, 0x631, 0x45, 0x6e, 0x65, 0x72, 0x6f, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x65, 0x72, 0x6f,
-0x3b, 0x4d, 0x61, 0x72, 0x7a, 0x6f, 0x3b, 0x41, 0x62, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x61, 0x79, 0x6f, 0x3b, 0x4a, 0x75,
-0x6e, 0x69, 0x6f, 0x3b, 0x4a, 0x75, 0x6c, 0x69, 0x6f, 0x3b, 0x41, 0x67, 0x6f, 0x73, 0x74, 0x6f, 0x3b, 0x53, 0x65, 0x74,
-0x69, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x4f, 0x63, 0x74, 0x75, 0x62, 0x72, 0x65, 0x3b, 0x4e, 0x6f, 0x76, 0x69, 0x65,
-0x6d, 0x62, 0x72, 0x65, 0x3b, 0x44, 0x69, 0x63, 0x69, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x45, 0x6e, 0x65, 0x3b, 0x46, 0x65,
-0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x62, 0x72, 0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75,
-0x6c, 0x3b, 0x41, 0x67, 0x6f, 0x3b, 0x53, 0x65, 0x74, 0x3b, 0x4f, 0x63, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x69,
-0x63, 0x69, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x69, 0x65, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x69, 0x65, 0x3b,
-0x6d, 0x61, 0x72, 0x74, 0x69, 0x65, 0x3b, 0x61, 0x70, 0x72, 0x69, 0x6c, 0x69, 0x65, 0x3b, 0x6d, 0x61, 0x69, 0x3b, 0x69,
-0x75, 0x6e, 0x69, 0x65, 0x3b, 0x69, 0x75, 0x6c, 0x69, 0x65, 0x3b, 0x61, 0x75, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65,
-0x70, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x69, 0x65, 0x3b, 0x6f, 0x63, 0x74, 0x6f, 0x6d, 0x62, 0x72, 0x69, 0x65, 0x3b, 0x6e,
-0x6f, 0x69, 0x65, 0x6d, 0x62, 0x72, 0x69, 0x65, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x72, 0x69, 0x65, 0x69, 0x61,
-0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x62, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x61, 0x70, 0x72, 0x2e, 0x3b, 0x6d, 0x61,
-0x69, 0x3b, 0x69, 0x75, 0x6e, 0x2e, 0x3b, 0x69, 0x75, 0x6c, 0x2e, 0x3b, 0x61, 0x75, 0x67, 0x2e, 0x3b, 0x73, 0x65, 0x70,
-0x74, 0x2e, 0x3b, 0x6f, 0x63, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x63, 0x2e, 0x49, 0x3b, 0x46,
-0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x49, 0x3b, 0x49, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44,
-0x73, 0x63, 0x68, 0x61, 0x6e, 0x65, 0x72, 0x3b, 0x66, 0x61, 0x76, 0x72, 0x65, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x3b,
-0x61, 0x76, 0x72, 0x69, 0x67, 0x6c, 0x3b, 0x6d, 0x61, 0x74, 0x67, 0x3b, 0x7a, 0x65, 0x72, 0x63, 0x6c, 0x61, 0x64, 0x75,
-0x72, 0x3b, 0x66, 0x61, 0x6e, 0x61, 0x64, 0x75, 0x72, 0x3b, 0x61, 0x76, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x74, 0x74,
-0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x6f, 0x63, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62,
-0x65, 0x72, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x64, 0x61, 0x20, 0x73, 0x63, 0x68, 0x61, 0x6e, 0x65,
-0x72, 0x3b, 0x64, 0x61, 0x20, 0x66, 0x61, 0x76, 0x72, 0x65, 0x72, 0x3b, 0x64, 0x61, 0x20, 0x6d, 0x61, 0x72, 0x73, 0x3b,
-0x64, 0x2019, 0x61, 0x76, 0x72, 0x69, 0x67, 0x6c, 0x3b, 0x64, 0x61, 0x20, 0x6d, 0x61, 0x74, 0x67, 0x3b, 0x64, 0x61, 0x20,
-0x7a, 0x65, 0x72, 0x63, 0x6c, 0x61, 0x64, 0x75, 0x72, 0x3b, 0x64, 0x61, 0x20, 0x66, 0x61, 0x6e, 0x61, 0x64, 0x75, 0x72,
-0x3b, 0x64, 0x2019, 0x61, 0x76, 0x75, 0x73, 0x74, 0x3b, 0x64, 0x61, 0x20, 0x73, 0x65, 0x74, 0x74, 0x65, 0x6d, 0x62, 0x65,
-0x72, 0x3b, 0x64, 0x2019, 0x6f, 0x63, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x64, 0x61, 0x20, 0x6e, 0x6f, 0x76, 0x65, 0x6d,
-0x62, 0x65, 0x72, 0x3b, 0x64, 0x61, 0x20, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x63, 0x68, 0x61, 0x6e,
-0x2e, 0x3b, 0x66, 0x61, 0x76, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x3b, 0x61, 0x76, 0x72, 0x2e, 0x3b, 0x6d, 0x61,
-0x74, 0x67, 0x3b, 0x7a, 0x65, 0x72, 0x63, 0x6c, 0x2e, 0x3b, 0x66, 0x61, 0x6e, 0x2e, 0x3b, 0x61, 0x76, 0x75, 0x73, 0x74,
-0x3b, 0x73, 0x65, 0x74, 0x74, 0x2e, 0x3b, 0x6f, 0x63, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x63,
-0x2e, 0x53, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x5a, 0x3b, 0x46, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f,
-0x3b, 0x4e, 0x3b, 0x44, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x77, 0x61, 0x6e, 0x7a, 0x61, 0x3b,
-0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x69, 0x6c, 0x69, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69,
-0x20, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x74, 0x61, 0x74, 0x75, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20,
-0x6b, 0x61, 0x61, 0x6e, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x74, 0x61, 0x6e, 0x75, 0x3b,
-0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x73, 0x69, 0x74, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20,
-0x77, 0x61, 0x20, 0x73, 0x61, 0x62, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6e, 0x61, 0x6e,
-0x65, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x74, 0x69, 0x73, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72,
-0x69, 0x20, 0x77, 0x61, 0x20, 0x69, 0x6b, 0x75, 0x6d, 0x69, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20,
-0x69, 0x6b, 0x75, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x6d, 0x6f, 0x6a, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20,
-0x77, 0x61, 0x20, 0x69, 0x6b, 0x75, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x6d, 0x62, 0x69, 0x6c, 0x69, 0x4d, 0x31, 0x3b,
-0x4d, 0x32, 0x3b, 0x4d, 0x33, 0x3b, 0x4d, 0x34, 0x3b, 0x4d, 0x35, 0x3b, 0x4d, 0x36, 0x3b, 0x4d, 0x37, 0x3b, 0x4d, 0x38,
-0x3b, 0x4d, 0x39, 0x3b, 0x4d, 0x31, 0x30, 0x3b, 0x4d, 0x31, 0x31, 0x3b, 0x4d, 0x31, 0x32, 0x4b, 0x3b, 0x4b, 0x3b, 0x4b,
-0x3b, 0x4b, 0x3b, 0x54, 0x3b, 0x53, 0x3b, 0x53, 0x3b, 0x4e, 0x3b, 0x54, 0x3b, 0x49, 0x3b, 0x49, 0x3b, 0x49, 0x4e, 0x7a,
-0x65, 0x72, 0x6f, 0x3b, 0x52, 0x75, 0x68, 0x75, 0x68, 0x75, 0x6d, 0x61, 0x3b, 0x4e, 0x74, 0x77, 0x61, 0x72, 0x61, 0x6e,
-0x74, 0x65, 0x3b, 0x4e, 0x64, 0x61, 0x6d, 0x75, 0x6b, 0x69, 0x7a, 0x61, 0x3b, 0x52, 0x75, 0x73, 0x61, 0x6d, 0x61, 0x3b,
-0x52, 0x75, 0x68, 0x65, 0x73, 0x68, 0x69, 0x3b, 0x4d, 0x75, 0x6b, 0x61, 0x6b, 0x61, 0x72, 0x6f, 0x3b, 0x4e, 0x79, 0x61,
-0x6e, 0x64, 0x61, 0x67, 0x61, 0x72, 0x6f, 0x3b, 0x4e, 0x79, 0x61, 0x6b, 0x61, 0x6e, 0x67, 0x61, 0x3b, 0x47, 0x69, 0x74,
-0x75, 0x67, 0x75, 0x74, 0x75, 0x3b, 0x4d, 0x75, 0x6e, 0x79, 0x6f, 0x6e, 0x79, 0x6f, 0x3b, 0x4b, 0x69, 0x67, 0x61, 0x72,
-0x61, 0x6d, 0x61, 0x4d, 0x75, 0x74, 0x2e, 0x3b, 0x47, 0x61, 0x73, 0x2e, 0x3b, 0x57, 0x65, 0x72, 0x2e, 0x3b, 0x4d, 0x61,
-0x74, 0x2e, 0x3b, 0x47, 0x69, 0x63, 0x2e, 0x3b, 0x4b, 0x61, 0x6d, 0x2e, 0x3b, 0x4e, 0x79, 0x61, 0x2e, 0x3b, 0x4b, 0x61,
-0x6e, 0x2e, 0x3b, 0x4e, 0x7a, 0x65, 0x2e, 0x3b, 0x55, 0x6b, 0x77, 0x2e, 0x3b, 0x55, 0x67, 0x75, 0x2e, 0x3b, 0x55, 0x6b,
-0x75, 0x2e, 0x44f, 0x43d, 0x432, 0x430, 0x440, 0x44f, 0x3b, 0x444, 0x435, 0x432, 0x440, 0x430, 0x43b, 0x44f, 0x3b, 0x43c, 0x430, 0x440,
-0x442, 0x430, 0x3b, 0x430, 0x43f, 0x440, 0x435, 0x43b, 0x44f, 0x3b, 0x43c, 0x430, 0x44f, 0x3b, 0x438, 0x44e, 0x43d, 0x44f, 0x3b, 0x438,
-0x44e, 0x43b, 0x44f, 0x3b, 0x430, 0x432, 0x433, 0x443, 0x441, 0x442, 0x430, 0x3b, 0x441, 0x435, 0x43d, 0x442, 0x44f, 0x431, 0x440, 0x44f,
-0x3b, 0x43e, 0x43a, 0x442, 0x44f, 0x431, 0x440, 0x44f, 0x3b, 0x43d, 0x43e, 0x44f, 0x431, 0x440, 0x44f, 0x3b, 0x434, 0x435, 0x43a, 0x430,
-0x431, 0x440, 0x44f, 0x44f, 0x43d, 0x432, 0x2e, 0x3b, 0x444, 0x435, 0x432, 0x440, 0x2e, 0x3b, 0x43c, 0x430, 0x440, 0x442, 0x3b, 0x430,
-0x43f, 0x440, 0x2e, 0x3b, 0x43c, 0x430, 0x439, 0x3b, 0x438, 0x44e, 0x43d, 0x44c, 0x3b, 0x438, 0x44e, 0x43b, 0x44c, 0x3b, 0x430, 0x432,
-0x433, 0x2e, 0x3b, 0x441, 0x435, 0x43d, 0x442, 0x2e, 0x3b, 0x43e, 0x43a, 0x442, 0x2e, 0x3b, 0x43d, 0x43e, 0x44f, 0x431, 0x2e, 0x3b,
-0x434, 0x435, 0x43a, 0x2e, 0x44f, 0x43d, 0x432, 0x2e, 0x3b, 0x444, 0x435, 0x432, 0x440, 0x2e, 0x3b, 0x43c, 0x430, 0x440, 0x2e, 0x3b,
-0x430, 0x43f, 0x440, 0x2e, 0x3b, 0x43c, 0x430, 0x44f, 0x3b, 0x438, 0x44e, 0x43d, 0x2e, 0x3b, 0x438, 0x44e, 0x43b, 0x2e, 0x3b, 0x430,
-0x432, 0x433, 0x2e, 0x3b, 0x441, 0x435, 0x43d, 0x442, 0x2e, 0x3b, 0x43e, 0x43a, 0x442, 0x2e, 0x3b, 0x43d, 0x43e, 0x44f, 0x431, 0x2e,
-0x3b, 0x434, 0x435, 0x43a, 0x2e, 0x442, 0x43e, 0x445, 0x441, 0x443, 0x43d, 0x43d, 0x44c, 0x443, 0x3b, 0x43e, 0x43b, 0x443, 0x43d, 0x43d,
-0x44c, 0x443, 0x3b, 0x43a, 0x443, 0x43b, 0x443, 0x43d, 0x20, 0x442, 0x443, 0x442, 0x430, 0x440, 0x3b, 0x43c, 0x443, 0x443, 0x441, 0x20,
-0x443, 0x441, 0x442, 0x430, 0x440, 0x3b, 0x44b, 0x430, 0x43c, 0x20, 0x44b, 0x439, 0x430, 0x3b, 0x431, 0x44d, 0x441, 0x20, 0x44b, 0x439,
-0x430, 0x3b, 0x43e, 0x442, 0x20, 0x44b, 0x439, 0x430, 0x3b, 0x430, 0x442, 0x44b, 0x440, 0x434, 0x44c, 0x44b, 0x445, 0x20, 0x44b, 0x439,
-0x430, 0x3b, 0x431, 0x430, 0x43b, 0x430, 0x495, 0x430, 0x43d, 0x20, 0x44b, 0x439, 0x430, 0x3b, 0x430, 0x43b, 0x442, 0x44b, 0x43d, 0x43d,
-0x44c, 0x44b, 0x3b, 0x441, 0x44d, 0x442, 0x438, 0x43d, 0x43d, 0x44c, 0x438, 0x3b, 0x430, 0x445, 0x441, 0x44b, 0x43d, 0x43d, 0x44c, 0x44b,
-0x422, 0x43e, 0x445, 0x441, 0x443, 0x43d, 0x43d, 0x44c, 0x443, 0x3b, 0x41e, 0x43b, 0x443, 0x43d, 0x43d, 0x44c, 0x443, 0x3b, 0x41a, 0x443,
-0x43b, 0x443, 0x43d, 0x20, 0x442, 0x443, 0x442, 0x430, 0x440, 0x3b, 0x41c, 0x443, 0x443, 0x441, 0x20, 0x443, 0x441, 0x442, 0x430, 0x440,
-0x3b, 0x42b, 0x430, 0x43c, 0x20, 0x44b, 0x439, 0x44b, 0x43d, 0x3b, 0x411, 0x44d, 0x441, 0x20, 0x44b, 0x439, 0x44b, 0x43d, 0x3b, 0x41e,
-0x442, 0x20, 0x44b, 0x439, 0x44b, 0x43d, 0x3b, 0x410, 0x442, 0x44b, 0x440, 0x434, 0x44c, 0x44b, 0x445, 0x20, 0x44b, 0x439, 0x44b, 0x43d,
-0x3b, 0x411, 0x430, 0x43b, 0x430, 0x495, 0x430, 0x43d, 0x20, 0x44b, 0x439, 0x44b, 0x43d, 0x3b, 0x410, 0x43b, 0x442, 0x44b, 0x43d, 0x43d,
-0x44c, 0x44b, 0x3b, 0x421, 0x44d, 0x442, 0x438, 0x43d, 0x43d, 0x44c, 0x438, 0x3b, 0x430, 0x445, 0x441, 0x44b, 0x43d, 0x43d, 0x44c, 0x44b,
-0x422, 0x43e, 0x445, 0x441, 0x3b, 0x41e, 0x43b, 0x443, 0x43d, 0x3b, 0x41a, 0x43b, 0x43d, 0x3b, 0x41c, 0x441, 0x443, 0x3b, 0x42b, 0x430,
-0x43c, 0x3b, 0x411, 0x44d, 0x441, 0x3b, 0x41e, 0x442, 0x439, 0x3b, 0x410, 0x442, 0x440, 0x3b, 0x411, 0x43b, 0x495, 0x3b, 0x410, 0x43b,
-0x442, 0x3b, 0x421, 0x44d, 0x442, 0x3b, 0x410, 0x445, 0x441, 0x422, 0x3b, 0x41e, 0x3b, 0x41a, 0x3b, 0x41c, 0x3b, 0x42b, 0x3b, 0x411,
-0x3b, 0x41e, 0x3b, 0x410, 0x3b, 0x411, 0x3b, 0x410, 0x3b, 0x421, 0x3b, 0x410, 0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c, 0x65, 0x20,
-0x6f, 0x62, 0x6f, 0x3b, 0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c, 0x65, 0x20, 0x77, 0x61, 0x61, 0x72, 0x65, 0x3b, 0x4c, 0x61,
-0x70, 0x61, 0x20, 0x6c, 0x65, 0x20, 0x6f, 0x6b, 0x75, 0x6e, 0x69, 0x3b, 0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c, 0x65, 0x20,
-0x6f, 0x6e, 0x67, 0x2019, 0x77, 0x61, 0x6e, 0x3b, 0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c, 0x65, 0x20, 0x69, 0x6d, 0x65, 0x74,
-0x3b, 0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c, 0x65, 0x20, 0x69, 0x6c, 0x65, 0x3b, 0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c, 0x65,
-0x20, 0x73, 0x61, 0x70, 0x61, 0x3b, 0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c, 0x65, 0x20, 0x69, 0x73, 0x69, 0x65, 0x74, 0x3b,
-0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c, 0x65, 0x20, 0x73, 0x61, 0x61, 0x6c, 0x3b, 0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c, 0x65,
-0x20, 0x74, 0x6f, 0x6d, 0x6f, 0x6e, 0x3b, 0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x6d, 0x6f, 0x6e,
-0x20, 0x6f, 0x62, 0x6f, 0x3b, 0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x6d, 0x6f, 0x6e, 0x20, 0x77,
-0x61, 0x61, 0x72, 0x65, 0x4f, 0x62, 0x6f, 0x3b, 0x57, 0x61, 0x61, 0x3b, 0x4f, 0x6b, 0x75, 0x3b, 0x4f, 0x6e, 0x67, 0x3b,
-0x49, 0x6d, 0x65, 0x3b, 0x49, 0x6c, 0x65, 0x3b, 0x53, 0x61, 0x70, 0x3b, 0x49, 0x73, 0x69, 0x3b, 0x53, 0x61, 0x61, 0x3b,
-0x54, 0x6f, 0x6d, 0x3b, 0x54, 0x6f, 0x62, 0x3b, 0x54, 0x6f, 0x77, 0x4f, 0x3b, 0x57, 0x3b, 0x4f, 0x3b, 0x4f, 0x3b, 0x49,
-0x3b, 0x49, 0x3b, 0x53, 0x3b, 0x49, 0x3b, 0x53, 0x3b, 0x54, 0x3b, 0x54, 0x3b, 0x54, 0x4e, 0x79, 0x65, 0x6e, 0x79, 0x65,
-0x3b, 0x46, 0x75, 0x6c, 0x75, 0x6e, 0x64, 0xef, 0x67, 0x69, 0x3b, 0x4d, 0x62, 0xe4, 0x6e, 0x67, 0xfc, 0x3b, 0x4e, 0x67,
-0x75, 0x62, 0xf9, 0x65, 0x3b, 0x42, 0xea, 0x6c, 0xe4, 0x77, 0xfc, 0x3b, 0x46, 0xf6, 0x6e, 0x64, 0x6f, 0x3b, 0x4c, 0x65,
-0x6e, 0x67, 0x75, 0x61, 0x3b, 0x4b, 0xfc, 0x6b, 0xfc, 0x72, 0xfc, 0x3b, 0x4d, 0x76, 0x75, 0x6b, 0x61, 0x3b, 0x4e, 0x67,
-0x62, 0x65, 0x72, 0x65, 0x72, 0x65, 0x3b, 0x4e, 0x61, 0x62, 0xe4, 0x6e, 0x64, 0xfc, 0x72, 0x75, 0x3b, 0x4b, 0x61, 0x6b,
-0x61, 0x75, 0x6b, 0x61, 0x4e, 0x79, 0x65, 0x3b, 0x46, 0x75, 0x6c, 0x3b, 0x4d, 0x62, 0xe4, 0x3b, 0x4e, 0x67, 0x75, 0x3b,
-0x42, 0xea, 0x6c, 0x3b, 0x46, 0xf6, 0x6e, 0x3b, 0x4c, 0x65, 0x6e, 0x3b, 0x4b, 0xfc, 0x6b, 0x3b, 0x4d, 0x76, 0x75, 0x3b,
-0x4e, 0x67, 0x62, 0x3b, 0x4e, 0x61, 0x62, 0x3b, 0x4b, 0x61, 0x6b, 0x4e, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x4e, 0x3b, 0x42,
-0x3b, 0x46, 0x3b, 0x4c, 0x3b, 0x4b, 0x3b, 0x4d, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b, 0x4b, 0x4d, 0x75, 0x70, 0x61, 0x6c, 0x61,
-0x6e, 0x67, 0x75, 0x6c, 0x77, 0x61, 0x3b, 0x4d, 0x77, 0x69, 0x74, 0x6f, 0x70, 0x65, 0x3b, 0x4d, 0x75, 0x73, 0x68, 0x65,
-0x6e, 0x64, 0x65, 0x3b, 0x4d, 0x75, 0x6e, 0x79, 0x69, 0x3b, 0x4d, 0x75, 0x73, 0x68, 0x65, 0x6e, 0x64, 0x65, 0x20, 0x4d,
-0x61, 0x67, 0x61, 0x6c, 0x69, 0x3b, 0x4d, 0x75, 0x6a, 0x69, 0x6d, 0x62, 0x69, 0x3b, 0x4d, 0x75, 0x73, 0x68, 0x69, 0x70,
-0x65, 0x70, 0x6f, 0x3b, 0x4d, 0x75, 0x70, 0x75, 0x67, 0x75, 0x74, 0x6f, 0x3b, 0x4d, 0x75, 0x6e, 0x79, 0x65, 0x6e, 0x73,
-0x65, 0x3b, 0x4d, 0x6f, 0x6b, 0x68, 0x75, 0x3b, 0x4d, 0x75, 0x73, 0x6f, 0x6e, 0x67, 0x61, 0x6e, 0x64, 0x65, 0x6d, 0x62,
-0x77, 0x65, 0x3b, 0x4d, 0x75, 0x68, 0x61, 0x61, 0x6e, 0x6f, 0x4d, 0x75, 0x70, 0x3b, 0x4d, 0x77, 0x69, 0x3b, 0x4d, 0x73,
-0x68, 0x3b, 0x4d, 0x75, 0x6e, 0x3b, 0x4d, 0x61, 0x67, 0x3b, 0x4d, 0x75, 0x6a, 0x3b, 0x4d, 0x73, 0x70, 0x3b, 0x4d, 0x70,
-0x67, 0x3b, 0x4d, 0x79, 0x65, 0x3b, 0x4d, 0x6f, 0x6b, 0x3b, 0x4d, 0x75, 0x73, 0x3b, 0x4d, 0x75, 0x68, 0x91c, 0x928, 0x935,
-0x930, 0x940, 0x92e, 0x93e, 0x938, 0x903, 0x3b, 0x92b, 0x930, 0x935, 0x930, 0x940, 0x92e, 0x93e, 0x938, 0x903, 0x3b, 0x92e, 0x93e, 0x930,
-0x94d, 0x91a, 0x92e, 0x93e, 0x938, 0x903, 0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x948, 0x932, 0x92e, 0x93e, 0x938, 0x903, 0x3b, 0x92e, 0x908,
-0x92e, 0x93e, 0x938, 0x903, 0x3b, 0x91c, 0x942, 0x928, 0x92e, 0x93e, 0x938, 0x903, 0x3b, 0x91c, 0x941, 0x932, 0x93e, 0x908, 0x92e, 0x93e,
-0x938, 0x903, 0x3b, 0x905, 0x917, 0x938, 0x94d, 0x924, 0x92e, 0x93e, 0x938, 0x903, 0x3b, 0x938, 0x93f, 0x924, 0x902, 0x92c, 0x930, 0x92e,
-0x93e, 0x938, 0x903, 0x3b, 0x905, 0x915, 0x94d, 0x924, 0x942, 0x92c, 0x930, 0x92e, 0x93e, 0x938, 0x903, 0x3b, 0x928, 0x935, 0x902, 0x92c,
-0x930, 0x92e, 0x93e, 0x938, 0x903, 0x3b, 0x926, 0x93f, 0x938, 0x902, 0x92c, 0x930, 0x92e, 0x93e, 0x938, 0x903, 0x91c, 0x928, 0x935, 0x930,
-0x940, 0x3a, 0x3b, 0x92b, 0x930, 0x935, 0x930, 0x940, 0x3a, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3a, 0x3b, 0x905, 0x92a, 0x94d,
-0x930, 0x948, 0x932, 0x3a, 0x3b, 0x92e, 0x908, 0x3b, 0x91c, 0x942, 0x928, 0x3a, 0x3b, 0x91c, 0x941, 0x932, 0x93e, 0x908, 0x3a, 0x3b,
-0x905, 0x917, 0x938, 0x94d, 0x924, 0x3a, 0x3b, 0x938, 0x93f, 0x924, 0x902, 0x92c, 0x930, 0x3a, 0x3b, 0x905, 0x915, 0x94d, 0x924, 0x942,
-0x92c, 0x930, 0x3a, 0x3b, 0x928, 0x935, 0x902, 0x92c, 0x930, 0x3a, 0x3b, 0x926, 0x93f, 0x938, 0x902, 0x92c, 0x930, 0x3a, 0x1c61, 0x1c5f,
-0x1c71, 0x1c63, 0x1c5f, 0x1c68, 0x1c64, 0x3b, 0x1c6f, 0x1c77, 0x1c5f, 0x1c68, 0x1c63, 0x1c5f, 0x1c68, 0x1c64, 0x3b, 0x1c62, 0x1c5f, 0x1c68, 0x1c6a, 0x3b,
-0x1c5f, 0x1c6f, 0x1c68, 0x1c6e, 0x1c5e, 0x3b, 0x1c62, 0x1c6e, 0x3b, 0x1c61, 0x1c69, 0x1c71, 0x3b, 0x1c61, 0x1c69, 0x1c5e, 0x1c5f, 0x1c6d, 0x3b, 0x1c5f,
-0x1c5c, 0x1c5f, 0x1c65, 0x1c5b, 0x3b, 0x1c65, 0x1c6e, 0x1c6f, 0x1c74, 0x1c6e, 0x1c62, 0x1c75, 0x1c5f, 0x1c68, 0x3b, 0x1c5a, 0x1c60, 0x1c74, 0x1c5a, 0x1c75,
-0x1c5f, 0x1c68, 0x3b, 0x1c71, 0x1c5f, 0x1c63, 0x1c5f, 0x1c62, 0x1c75, 0x1c5f, 0x1c68, 0x3b, 0x1c6b, 0x1c64, 0x1c65, 0x1c5f, 0x1c62, 0x1c75, 0x1c5f, 0x1c68,
-0x1c61, 0x1c5f, 0x1c71, 0x3b, 0x1c6f, 0x1c77, 0x1c5f, 0x3b, 0x1c62, 0x1c5f, 0x1c68, 0x3b, 0x1c5f, 0x1c6f, 0x1c68, 0x3b, 0x1c62, 0x1c6e, 0x3b, 0x1c61,
-0x1c69, 0x1c71, 0x3b, 0x1c61, 0x1c69, 0x1c5e, 0x3b, 0x1c5f, 0x1c5c, 0x1c5f, 0x3b, 0x1c65, 0x1c6e, 0x1c6f, 0x3b, 0x1c5a, 0x1c60, 0x1c74, 0x3b, 0x1c71,
-0x1c5f, 0x1c63, 0x3b, 0x1c6b, 0x1c64, 0x1c65, 0x1c61, 0x3b, 0x1c6f, 0x3b, 0x1c62, 0x3b, 0x1c5f, 0x3b, 0x1c62, 0x3b, 0x1c61, 0x3b, 0x1c61, 0x3b,
-0x1c5f, 0x3b, 0x1c65, 0x3b, 0x1c5a, 0x3b, 0x1c71, 0x3b, 0x1c6b, 0x67, 0x68, 0x65, 0x6e, 0x6e, 0xe0, 0x72, 0x67, 0x69, 0x75, 0x3b,
-0x66, 0x72, 0x65, 0xe0, 0x72, 0x67, 0x69, 0x75, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x7a, 0x75, 0x3b, 0x61, 0x62, 0x72, 0x69,
-0x6c, 0x65, 0x3b, 0x6d, 0x61, 0x6a, 0x75, 0x3b, 0x6c, 0xe0, 0x6d, 0x70, 0x61, 0x64, 0x61, 0x73, 0x3b, 0x74, 0x72, 0xec,
-0x75, 0x6c, 0x61, 0x73, 0x3b, 0x61, 0x75, 0x73, 0x74, 0x75, 0x3b, 0x63, 0x61, 0x62, 0x75, 0x64, 0x61, 0x6e, 0x6e, 0x69,
-0x3b, 0x73, 0x61, 0x6e, 0x74, 0x75, 0x67, 0x61, 0x69, 0x6e, 0x65, 0x3b, 0x73, 0x61, 0x6e, 0x74, 0x61, 0x6e, 0x64, 0x72,
-0x69, 0x61, 0x3b, 0x6e, 0x61, 0x64, 0x61, 0x6c, 0x65, 0x67, 0x68, 0x65, 0x3b, 0x66, 0x72, 0x65, 0x3b, 0x6d, 0x61, 0x72,
-0x3b, 0x61, 0x62, 0x72, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6c, 0xe0, 0x6d, 0x3b, 0x74, 0x72, 0xec, 0x3b, 0x61, 0x75, 0x73,
-0x3b, 0x63, 0x61, 0x62, 0x3b, 0x73, 0x74, 0x47, 0x3b, 0x73, 0x74, 0x41, 0x3b, 0x6e, 0x61, 0x64, 0x47, 0x3b, 0x46, 0x3b,
-0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4c, 0x3b, 0x54, 0x3b, 0x41, 0x3b, 0x43, 0x3b, 0x53, 0x3b, 0x53, 0x3b, 0x4e, 0x4a,
-0x61, 0x6e, 0x65, 0x69, 0x72, 0x6f, 0x3b, 0x46, 0x65, 0x76, 0x72, 0x65, 0x69, 0x72, 0x6f, 0x3b, 0x4d, 0x61, 0x72, 0x63,
-0x6f, 0x3b, 0x41, 0x62, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x61, 0x69, 0x6f, 0x3b, 0x4a, 0x75, 0x6e, 0x68, 0x6f, 0x3b, 0x4a,
-0x75, 0x6c, 0x68, 0x6f, 0x3b, 0x41, 0x75, 0x67, 0x75, 0x73, 0x74, 0x6f, 0x3b, 0x53, 0x65, 0x74, 0x65, 0x6d, 0x62, 0x72,
-0x6f, 0x3b, 0x4f, 0x74, 0x75, 0x62, 0x72, 0x6f, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x6f, 0x3b, 0x44, 0x65,
-0x63, 0x65, 0x6d, 0x62, 0x72, 0x6f, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x76, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x62,
-0x72, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x75, 0x67, 0x3b, 0x53, 0x65,
-0x74, 0x3b, 0x4f, 0x74, 0x75, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x63, 0x458, 0x430, 0x43d, 0x443, 0x430, 0x440, 0x3b,
-0x444, 0x435, 0x431, 0x440, 0x443, 0x430, 0x440, 0x3b, 0x43c, 0x430, 0x440, 0x442, 0x3b, 0x430, 0x43f, 0x440, 0x438, 0x43b, 0x3b, 0x43c,
-0x430, 0x458, 0x3b, 0x458, 0x443, 0x43d, 0x3b, 0x458, 0x443, 0x43b, 0x3b, 0x430, 0x432, 0x433, 0x443, 0x441, 0x442, 0x3b, 0x441, 0x435,
-0x43f, 0x442, 0x435, 0x43c, 0x431, 0x430, 0x440, 0x3b, 0x43e, 0x43a, 0x442, 0x43e, 0x431, 0x430, 0x440, 0x3b, 0x43d, 0x43e, 0x432, 0x435,
-0x43c, 0x431, 0x430, 0x440, 0x3b, 0x434, 0x435, 0x446, 0x435, 0x43c, 0x431, 0x430, 0x440, 0x458, 0x430, 0x43d, 0x3b, 0x444, 0x435, 0x431,
-0x3b, 0x43c, 0x430, 0x440, 0x3b, 0x430, 0x43f, 0x440, 0x3b, 0x43c, 0x430, 0x458, 0x3b, 0x458, 0x443, 0x43d, 0x3b, 0x458, 0x443, 0x43b,
-0x3b, 0x430, 0x432, 0x433, 0x3b, 0x441, 0x435, 0x43f, 0x3b, 0x43e, 0x43a, 0x442, 0x3b, 0x43d, 0x43e, 0x432, 0x3b, 0x434, 0x435, 0x446,
-0x458, 0x430, 0x43d, 0x3b, 0x444, 0x435, 0x431, 0x3b, 0x43c, 0x430, 0x440, 0x442, 0x3b, 0x430, 0x43f, 0x440, 0x3b, 0x43c, 0x430, 0x458,
-0x3b, 0x458, 0x443, 0x43d, 0x3b, 0x458, 0x443, 0x43b, 0x3b, 0x430, 0x432, 0x433, 0x3b, 0x441, 0x435, 0x43f, 0x442, 0x3b, 0x43e, 0x43a,
-0x442, 0x3b, 0x43d, 0x43e, 0x432, 0x3b, 0x434, 0x435, 0x446, 0x6a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x3b, 0x66, 0x65, 0x62, 0x72,
-0x75, 0x61, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x3b, 0x61, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a,
-0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x76, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d,
-0x62, 0x61, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x61, 0x72, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x72,
-0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x6a, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0x61, 0x72,
-0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x76, 0x67,
-0x3b, 0x73, 0x65, 0x70, 0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65, 0x63, 0x6a, 0x61, 0x6e, 0x3b,
-0x66, 0x65, 0x62, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e,
-0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x76, 0x67, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e, 0x6f,
-0x76, 0x3b, 0x64, 0x65, 0x63, 0x4a, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x69, 0x3b, 0x46, 0x65, 0x62, 0x6c, 0x75, 0x61, 0x6c,
-0x69, 0x3b, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x3b, 0x41, 0x70, 0x6c, 0x69, 0x6c, 0x69, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a,
-0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x61, 0x69, 0x3b, 0x41, 0x67, 0x6f, 0x73, 0x74, 0x69, 0x3b, 0x53, 0x65, 0x70,
-0x74, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x61, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61,
-0x3b, 0x44, 0x65, 0x73, 0x65, 0x6d, 0x62, 0x61, 0x4e, 0x64, 0x69, 0x72, 0x61, 0x3b, 0x4b, 0x75, 0x6b, 0x61, 0x64, 0x7a,
-0x69, 0x3b, 0x4b, 0x75, 0x72, 0x75, 0x6d, 0x65, 0x3b, 0x4b, 0x75, 0x62, 0x76, 0x75, 0x6d, 0x62, 0x69, 0x3b, 0x43, 0x68,
-0x69, 0x76, 0x61, 0x62, 0x76, 0x75, 0x3b, 0x43, 0x68, 0x69, 0x6b, 0x75, 0x6d, 0x69, 0x3b, 0x43, 0x68, 0x69, 0x6b, 0x75,
-0x6e, 0x67, 0x75, 0x72, 0x75, 0x3b, 0x4e, 0x79, 0x61, 0x6d, 0x61, 0x76, 0x68, 0x75, 0x76, 0x68, 0x75, 0x3b, 0x47, 0x75,
-0x6e, 0x79, 0x61, 0x6e, 0x61, 0x3b, 0x47, 0x75, 0x6d, 0x69, 0x67, 0x75, 0x72, 0x75, 0x3b, 0x4d, 0x62, 0x75, 0x64, 0x7a,
-0x69, 0x3b, 0x5a, 0x76, 0x69, 0x74, 0x61, 0x4e, 0x64, 0x69, 0x3b, 0x4b, 0x75, 0x6b, 0x3b, 0x4b, 0x75, 0x72, 0x3b, 0x4b,
-0x75, 0x62, 0x3b, 0x43, 0x68, 0x76, 0x3b, 0x43, 0x68, 0x6b, 0x3b, 0x43, 0x68, 0x67, 0x3b, 0x4e, 0x79, 0x61, 0x3b, 0x47,
-0x75, 0x6e, 0x3b, 0x47, 0x75, 0x6d, 0x3b, 0x4d, 0x62, 0x75, 0x3b, 0x5a, 0x76, 0x69, 0x4e, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b,
-0x4b, 0x3b, 0x43, 0x3b, 0x43, 0x3b, 0x43, 0x3b, 0x4e, 0x3b, 0x47, 0x3b, 0x47, 0x3b, 0x4d, 0x3b, 0x5a, 0xa2cd, 0xa1aa, 0x3b,
-0xa44d, 0xa1aa, 0x3b, 0xa315, 0xa1aa, 0x3b, 0xa1d6, 0xa1aa, 0x3b, 0xa26c, 0xa1aa, 0x3b, 0xa0d8, 0xa1aa, 0x3b, 0xa3c3, 0xa1aa, 0x3b, 0xa246, 0xa1aa,
-0x3b, 0xa22c, 0xa1aa, 0x3b, 0xa2b0, 0xa1aa, 0x3b, 0xa2b0, 0xa2aa, 0xa1aa, 0x3b, 0xa2b0, 0xa44b, 0xa1aa, 0x62c, 0x646, 0x648, 0x631, 0x64a, 0x3b,
-0x641, 0x64a, 0x628, 0x631, 0x648, 0x631, 0x64a, 0x3b, 0x645, 0x627, 0x631, 0x686, 0x3b, 0x627, 0x67e, 0x631, 0x64a, 0x644, 0x3b, 0x645,
-0x626, 0x64a, 0x3b, 0x62c, 0x648, 0x646, 0x3b, 0x62c, 0x648, 0x644, 0x627, 0x621, 0x650, 0x3b, 0x622, 0x6af, 0x633, 0x67d, 0x3b, 0x633,
-0x64a, 0x67e, 0x67d, 0x645, 0x628, 0x631, 0x3b, 0x622, 0x6aa, 0x67d, 0x648, 0x628, 0x631, 0x3b, 0x646, 0x648, 0x645, 0x628, 0x631, 0x3b,
-0x68a, 0x633, 0x645, 0x628, 0x631, 0x91c, 0x928, 0x935, 0x930, 0x940, 0x3b, 0x92b, 0x930, 0x935, 0x930, 0x940, 0x3b, 0x92e, 0x93e, 0x930,
-0x94d, 0x91a, 0x941, 0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x948, 0x932, 0x3b, 0x92e, 0x908, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941,
-0x932, 0x93e, 0x908, 0x3b, 0x905, 0x917, 0x938, 0x94d, 0x91f, 0x3b, 0x938, 0x92a, 0x94d, 0x91f, 0x947, 0x902, 0x92c, 0x930, 0x3b, 0x911,
-0x915, 0x94d, 0x91f, 0x94b, 0x92c, 0x930, 0x3b, 0x928, 0x935, 0x902, 0x92c, 0x930, 0x3b, 0x921, 0x93f, 0x938, 0x902, 0x92c, 0x930, 0x91c,
-0x928, 0x935, 0x930, 0x940, 0x3b, 0x92b, 0x930, 0x935, 0x930, 0x940, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x941, 0x3b, 0x905, 0x92a,
-0x94d, 0x930, 0x948, 0x932, 0x3b, 0x92e, 0x908, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x93e, 0x908, 0x3b, 0x905, 0x917,
-0x938, 0x94d, 0x91f, 0x3b, 0x938, 0x92a, 0x94d, 0x91f, 0x947, 0x902, 0x92c, 0x930, 0x3b, 0x913, 0x915, 0x94d, 0x91f, 0x94b, 0x92c, 0x930,
-0x3b, 0x928, 0x935, 0x902, 0x92c, 0x930, 0x3b, 0x921, 0x93f, 0x938, 0x902, 0x92c, 0x930, 0x91c, 0x928, 0x3b, 0x92b, 0x930, 0x3b, 0x92e,
-0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x948, 0x3b, 0x92e, 0x908, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941,
-0x932, 0x93e, 0x3b, 0x905, 0x917, 0x3b, 0x938, 0x92a, 0x94d, 0x91f, 0x947, 0x3b, 0x911, 0x915, 0x94d, 0x91f, 0x94b, 0x3b, 0x928, 0x935,
-0x902, 0x3b, 0x921, 0x93f, 0x938, 0x902, 0x91c, 0x928, 0x3b, 0x92b, 0x930, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a,
-0x94d, 0x930, 0x948, 0x3b, 0x92e, 0x908, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x3b, 0x905, 0x917, 0x3b, 0x938, 0x92a, 0x94d,
-0x91f, 0x947, 0x3b, 0x911, 0x915, 0x94d, 0x91f, 0x94b, 0x3b, 0x928, 0x935, 0x902, 0x3b, 0x921, 0x93f, 0x938, 0x902, 0x91c, 0x3b, 0x92b,
-0x93c, 0x3b, 0x92e, 0x3b, 0x905, 0x3b, 0x92e, 0x93e, 0x3b, 0x91c, 0x942, 0x3b, 0x91c, 0x941, 0x3b, 0x905, 0x917, 0x3b, 0x938, 0x3b,
-0x911, 0x3b, 0x928, 0x3b, 0x921, 0x93f, 0x91c, 0x3b, 0x92b, 0x93c, 0x3b, 0x92e, 0x93e, 0x3b, 0x905, 0x3b, 0x92e, 0x93e, 0x3b, 0x91c,
-0x942, 0x3b, 0x91c, 0x941, 0x3b, 0x905, 0x917, 0x3b, 0x938, 0x3b, 0x911, 0x3b, 0x928, 0x3b, 0x921, 0x93f, 0xda2, 0xdb1, 0xdc0, 0xdcf,
-0xdbb, 0xdd2, 0x3b, 0xdb4, 0xdd9, 0xdb6, 0xdbb, 0xdc0, 0xdcf, 0xdbb, 0xdd2, 0x3b, 0xdb8, 0xdcf, 0xdbb, 0xdca, 0xdad, 0xdd4, 0x3b, 0xd85,
-0xdb4, 0xdca, 0x200d, 0xdbb, 0xdda, 0xdbd, 0xdca, 0x3b, 0xdb8, 0xdd0, 0xdba, 0xdd2, 0x3b, 0xda2, 0xdd6, 0xdb1, 0xdd2, 0x3b, 0xda2, 0xdd6,
-0xdbd, 0xdd2, 0x3b, 0xd85, 0xd9c, 0xddd, 0xdc3, 0xdca, 0xdad, 0xdd4, 0x3b, 0xdc3, 0xdd0, 0xdb4, 0xdca, 0xdad, 0xdd0, 0xdb8, 0xdca, 0xdb6,
-0xdbb, 0xdca, 0x3b, 0xd94, 0xd9a, 0xdca, 0xdad, 0xddd, 0xdb6, 0xdbb, 0xdca, 0x3b, 0xdb1, 0xddc, 0xdc0, 0xdd0, 0xdb8, 0xdca, 0xdb6, 0xdbb,
-0xdca, 0x3b, 0xdaf, 0xdd9, 0xdc3, 0xdd0, 0xdb8, 0xdca, 0xdb6, 0xdbb, 0xdca, 0xda2, 0xdb1, 0x3b, 0xdb4, 0xdd9, 0xdb6, 0x3b, 0xdb8, 0xdcf,
-0xdbb, 0xdca, 0x3b, 0xd85, 0xdb4, 0xdca, 0x200d, 0xdbb, 0xdda, 0xdbd, 0xdca, 0x3b, 0xdb8, 0xdd0, 0xdba, 0xdd2, 0x3b, 0xda2, 0xdd6, 0xdb1,
-0xdd2, 0x3b, 0xda2, 0xdd6, 0xdbd, 0xdd2, 0x3b, 0xd85, 0xd9c, 0xddd, 0x3b, 0xdc3, 0xdd0, 0xdb4, 0xdca, 0x3b, 0xd94, 0xd9a, 0xdca, 0x3b,
-0xdb1, 0xddc, 0xdc0, 0xdd0, 0x3b, 0xdaf, 0xdd9, 0xdc3, 0xdd0, 0xda2, 0xdb1, 0x3b, 0xdb4, 0xdd9, 0xdb6, 0x3b, 0xdb8, 0xdcf, 0xdbb, 0xdca,
-0xdad, 0xdd4, 0x3b, 0xd85, 0xdb4, 0xdca, 0x200d, 0xdbb, 0xdda, 0xdbd, 0xdca, 0x3b, 0xdb8, 0xdd0, 0xdba, 0xdd2, 0x3b, 0xda2, 0xdd6, 0xdb1,
-0xdd2, 0x3b, 0xda2, 0xdd6, 0xdbd, 0xdd2, 0x3b, 0xd85, 0xd9c, 0xddd, 0x3b, 0xdc3, 0xdd0, 0xdb4, 0xdca, 0x3b, 0xd94, 0xd9a, 0xdca, 0x3b,
-0xdb1, 0xddc, 0xdc0, 0xdd0, 0x3b, 0xdaf, 0xdd9, 0xdc3, 0xdd0, 0xda2, 0x3b, 0xdb4, 0xdd9, 0x3b, 0xdb8, 0xdcf, 0x3b, 0xd85, 0x3b, 0xdb8,
-0xdd0, 0x3b, 0xda2, 0xdd6, 0x3b, 0xda2, 0xdd6, 0x3b, 0xd85, 0x3b, 0xdc3, 0xdd0, 0x3b, 0xd94, 0x3b, 0xdb1, 0xdd9, 0x3b, 0xdaf, 0xdd9,
-0x6a, 0x61, 0x6e, 0x75, 0xe1, 0x72, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0xe1, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0x65, 0x63,
-0x3b, 0x61, 0x70, 0x72, 0xed, 0x6c, 0x3b, 0x6d, 0xe1, 0x6a, 0x3b, 0x6a, 0xfa, 0x6e, 0x3b, 0x6a, 0xfa, 0x6c, 0x3b, 0x61,
-0x75, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0xf3,
-0x62, 0x65, 0x72, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x65,
-0x72, 0x6a, 0x61, 0x6e, 0x75, 0xe1, 0x72, 0x61, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0xe1, 0x72, 0x61, 0x3b, 0x6d, 0x61,
-0x72, 0x63, 0x61, 0x3b, 0x61, 0x70, 0x72, 0xed, 0x6c, 0x61, 0x3b, 0x6d, 0xe1, 0x6a, 0x61, 0x3b, 0x6a, 0xfa, 0x6e, 0x61,
-0x3b, 0x6a, 0xfa, 0x6c, 0x61, 0x3b, 0x61, 0x75, 0x67, 0x75, 0x73, 0x74, 0x61, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d,
-0x62, 0x72, 0x61, 0x3b, 0x6f, 0x6b, 0x74, 0xf3, 0x62, 0x72, 0x61, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x61,
-0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x72, 0x61, 0x6a, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0x61, 0x72,
-0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0xe1, 0x6a, 0x3b, 0x6a, 0xfa, 0x6e, 0x3b, 0x6a, 0xfa, 0x6c, 0x3b, 0x61, 0x75, 0x67,
-0x3b, 0x73, 0x65, 0x70, 0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65, 0x63, 0x6a, 0x61, 0x6e, 0x75,
-0x61, 0x72, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0x65, 0x63, 0x3b, 0x61, 0x70, 0x72,
-0x69, 0x6c, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x6a, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x6a, 0x3b, 0x61,
-0x76, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x6f,
-0x62, 0x65, 0x72, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x65,
-0x72, 0x6a, 0x61, 0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x62, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x61, 0x70, 0x72, 0x2e,
-0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x2e, 0x3b, 0x6a, 0x75, 0x6c, 0x2e, 0x3b, 0x61, 0x76, 0x67, 0x2e, 0x3b,
-0x73, 0x65, 0x70, 0x2e, 0x3b, 0x6f, 0x6b, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x63, 0x2e, 0x4a,
-0x61, 0x6e, 0x6e, 0x61, 0x61, 0x79, 0x6f, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x61, 0x61, 0x79, 0x6f, 0x3b, 0x4d, 0x61, 0x61,
-0x72, 0x73, 0x6f, 0x3b, 0x41, 0x62, 0x72, 0x69, 0x69, 0x6c, 0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x4a, 0x75, 0x75, 0x6e, 0x3b,
-0x4c, 0x75, 0x75, 0x6c, 0x69, 0x79, 0x6f, 0x3b, 0x4f, 0x67, 0x6f, 0x73, 0x74, 0x6f, 0x3b, 0x53, 0x65, 0x62, 0x74, 0x65,
-0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x3b, 0x4e, 0x6f, 0x6f, 0x66, 0x65,
-0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x44, 0x69, 0x73, 0x65, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x42, 0x69, 0x73, 0x68, 0x61,
-0x20, 0x4b, 0x6f, 0x6f, 0x62, 0x61, 0x61, 0x64, 0x3b, 0x42, 0x69, 0x73, 0x68, 0x61, 0x20, 0x4c, 0x61, 0x62, 0x61, 0x61,
-0x64, 0x3b, 0x42, 0x69, 0x73, 0x68, 0x61, 0x20, 0x53, 0x61, 0x64, 0x64, 0x65, 0x78, 0x61, 0x61, 0x64, 0x3b, 0x42, 0x69,
-0x73, 0x68, 0x61, 0x20, 0x41, 0x66, 0x72, 0x61, 0x61, 0x64, 0x3b, 0x42, 0x69, 0x73, 0x68, 0x61, 0x20, 0x53, 0x68, 0x61,
-0x6e, 0x61, 0x61, 0x64, 0x3b, 0x42, 0x69, 0x73, 0x68, 0x61, 0x20, 0x4c, 0x69, 0x78, 0x61, 0x61, 0x64, 0x3b, 0x42, 0x69,
-0x73, 0x68, 0x61, 0x20, 0x54, 0x6f, 0x64, 0x6f, 0x62, 0x61, 0x61, 0x64, 0x3b, 0x42, 0x69, 0x73, 0x68, 0x61, 0x20, 0x53,
-0x69, 0x64, 0x65, 0x65, 0x64, 0x61, 0x61, 0x64, 0x3b, 0x42, 0x69, 0x73, 0x68, 0x61, 0x20, 0x53, 0x61, 0x67, 0x61, 0x61,
-0x6c, 0x61, 0x61, 0x64, 0x3b, 0x42, 0x69, 0x73, 0x68, 0x61, 0x20, 0x54, 0x6f, 0x62, 0x6e, 0x61, 0x61, 0x64, 0x3b, 0x42,
-0x69, 0x73, 0x68, 0x61, 0x20, 0x4b, 0x6f, 0x77, 0x20, 0x69, 0x79, 0x6f, 0x20, 0x54, 0x6f, 0x62, 0x6e, 0x61, 0x61, 0x64,
-0x3b, 0x42, 0x69, 0x73, 0x68, 0x61, 0x20, 0x4c, 0x61, 0x62, 0x61, 0x20, 0x69, 0x79, 0x6f, 0x20, 0x54, 0x6f, 0x62, 0x6e,
-0x61, 0x61, 0x64, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x62, 0x72, 0x3b, 0x4d,
-0x61, 0x79, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4c, 0x75, 0x6c, 0x3b, 0x4f, 0x67, 0x73, 0x3b, 0x53, 0x65, 0x62, 0x3b, 0x4f,
-0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x66, 0x3b, 0x44, 0x69, 0x73, 0x4a, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b,
-0x4a, 0x3b, 0x4c, 0x3b, 0x4f, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x65, 0x6e, 0x65, 0x72, 0x6f, 0x3b, 0x66,
-0x65, 0x62, 0x72, 0x65, 0x72, 0x6f, 0x3b, 0x6d, 0x61, 0x72, 0x7a, 0x6f, 0x3b, 0x61, 0x62, 0x72, 0x69, 0x6c, 0x3b, 0x6d,
-0x61, 0x79, 0x6f, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x6f, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x6f, 0x3b, 0x61, 0x67, 0x6f, 0x73,
-0x74, 0x6f, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x69, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x6f, 0x63, 0x74, 0x75, 0x62, 0x72,
-0x65, 0x3b, 0x6e, 0x6f, 0x76, 0x69, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x69, 0x63, 0x69, 0x65, 0x6d, 0x62, 0x72,
-0x65, 0x65, 0x6e, 0x65, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x61, 0x62, 0x72, 0x3b, 0x6d, 0x61, 0x79,
-0x3b, 0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x67, 0x6f, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x3b, 0x6f, 0x63,
-0x74, 0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x69, 0x63, 0x45, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4a,
-0x3b, 0x4a, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x65, 0x6e, 0x65, 0x2e, 0x3b, 0x66, 0x65, 0x62,
-0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x61, 0x62, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x79, 0x2e, 0x3b, 0x6a, 0x75, 0x6e,
-0x2e, 0x3b, 0x6a, 0x75, 0x6c, 0x2e, 0x3b, 0x61, 0x67, 0x6f, 0x2e, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x2e, 0x3b, 0x6f, 0x63,
-0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x69, 0x63, 0x2e, 0x65, 0x6e, 0x65, 0x72, 0x6f, 0x3b, 0x66, 0x65,
-0x62, 0x72, 0x65, 0x72, 0x6f, 0x3b, 0x6d, 0x61, 0x72, 0x7a, 0x6f, 0x3b, 0x61, 0x62, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x61,
-0x79, 0x6f, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x6f, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x6f, 0x3b, 0x61, 0x67, 0x6f, 0x73, 0x74,
-0x6f, 0x3b, 0x73, 0x65, 0x74, 0x69, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x6f, 0x63, 0x74, 0x75, 0x62, 0x72, 0x65, 0x3b,
-0x6e, 0x6f, 0x76, 0x69, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x69, 0x63, 0x69, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x45,
-0x6e, 0x65, 0x2e, 0x3b, 0x46, 0x65, 0x62, 0x2e, 0x3b, 0x4d, 0x61, 0x72, 0x2e, 0x3b, 0x41, 0x62, 0x72, 0x2e, 0x3b, 0x4d,
-0x61, 0x79, 0x2e, 0x3b, 0x4a, 0x75, 0x6e, 0x2e, 0x3b, 0x4a, 0x75, 0x6c, 0x2e, 0x3b, 0x41, 0x67, 0x6f, 0x2e, 0x3b, 0x53,
-0x65, 0x74, 0x2e, 0x3b, 0x4f, 0x63, 0x74, 0x2e, 0x3b, 0x4e, 0x6f, 0x76, 0x2e, 0x3b, 0x44, 0x69, 0x63, 0x2e, 0x65, 0x6e,
-0x65, 0x2e, 0x3b, 0x66, 0x65, 0x62, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x61, 0x62, 0x72, 0x2e, 0x3b, 0x6d, 0x61,
-0x79, 0x2e, 0x3b, 0x6a, 0x75, 0x6e, 0x2e, 0x3b, 0x6a, 0x75, 0x6c, 0x2e, 0x3b, 0x61, 0x67, 0x6f, 0x2e, 0x3b, 0x73, 0x65,
-0x74, 0x2e, 0x3b, 0x6f, 0x63, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x69, 0x63, 0x2e, 0x2d49, 0x2d4f, 0x2d4f,
-0x2d30, 0x2d62, 0x2d54, 0x3b, 0x2d31, 0x2d55, 0x2d30, 0x2d62, 0x2d55, 0x3b, 0x2d4e, 0x2d30, 0x2d55, 0x2d5a, 0x3b, 0x2d49, 0x2d31, 0x2d54, 0x2d49, 0x2d54,
-0x3b, 0x2d4e, 0x2d30, 0x2d62, 0x2d62, 0x2d53, 0x3b, 0x2d62, 0x2d53, 0x2d4f, 0x2d62, 0x2d53, 0x3b, 0x2d62, 0x2d53, 0x2d4d, 0x2d62, 0x2d53, 0x2d63, 0x3b,
-0x2d56, 0x2d53, 0x2d5b, 0x2d5c, 0x3b, 0x2d5b, 0x2d53, 0x2d5c, 0x2d30, 0x2d4f, 0x2d31, 0x2d49, 0x2d54, 0x3b, 0x2d3d, 0x2d5c, 0x2d53, 0x2d31, 0x2d54, 0x3b,
-0x2d4f, 0x2d53, 0x2d61, 0x2d30, 0x2d4f, 0x2d31, 0x2d49, 0x2d54, 0x3b, 0x2d37, 0x2d53, 0x2d4a, 0x2d30, 0x2d4f, 0x2d31, 0x2d49, 0x2d54, 0x2d49, 0x2d4f, 0x2d4f,
-0x3b, 0x2d31, 0x2d55, 0x2d30, 0x3b, 0x2d4e, 0x2d30, 0x2d55, 0x3b, 0x2d49, 0x2d31, 0x2d54, 0x3b, 0x2d4e, 0x2d30, 0x2d62, 0x3b, 0x2d62, 0x2d53, 0x2d4f,
-0x3b, 0x2d62, 0x2d53, 0x2d4d, 0x3b, 0x2d56, 0x2d53, 0x2d5b, 0x3b, 0x2d5b, 0x2d53, 0x2d5c, 0x3b, 0x2d3d, 0x2d5c, 0x2d53, 0x3b, 0x2d4f, 0x2d53, 0x2d61,
-0x3b, 0x2d37, 0x2d53, 0x2d4a, 0x2d49, 0x3b, 0x2d31, 0x3b, 0x2d4e, 0x3b, 0x2d49, 0x3b, 0x2d4e, 0x3b, 0x2d62, 0x3b, 0x2d62, 0x3b, 0x2d56, 0x3b,
-0x2d5b, 0x3b, 0x2d3d, 0x3b, 0x2d4f, 0x3b, 0x2d37, 0x4a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x69, 0x3b, 0x50, 0xe9, 0x62, 0x72, 0x75,
-0x61, 0x72, 0x69, 0x3b, 0x4d, 0x61, 0x72, 0x65, 0x74, 0x3b, 0x41, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0xe9, 0x69, 0x3b,
-0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x69, 0x3b, 0x41, 0x67, 0x75, 0x73, 0x74, 0x75, 0x73, 0x3b, 0x53, 0xe9,
-0x70, 0x74, 0xe9, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x4e, 0x6f, 0x70, 0xe9,
-0x6d, 0x62, 0x65, 0x72, 0x3b, 0x44, 0xe9, 0x73, 0xe9, 0x6d, 0x62, 0x65, 0x72, 0x4a, 0x61, 0x6e, 0x3b, 0x50, 0xe9, 0x62,
-0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0xe9, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c,
-0x3b, 0x41, 0x67, 0x73, 0x3b, 0x53, 0xe9, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x70, 0x3b, 0x44, 0xe9, 0x73,
-0x4a, 0x3b, 0x50, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b,
-0x4e, 0x3b, 0x44, 0x6a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x69, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x69, 0x3b,
-0x6d, 0x61, 0x72, 0x73, 0x3b, 0x61, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x3b,
-0x6a, 0x75, 0x6c, 0x69, 0x3b, 0x61, 0x75, 0x67, 0x75, 0x73, 0x74, 0x69, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62,
-0x65, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b,
-0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x6a, 0x61, 0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x62, 0x2e, 0x3b, 0x6d, 0x61,
-0x72, 0x73, 0x3b, 0x61, 0x70, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x3b, 0x6a, 0x75, 0x6c,
-0x69, 0x3b, 0x61, 0x75, 0x67, 0x2e, 0x3b, 0x73, 0x65, 0x70, 0x2e, 0x3b, 0x6f, 0x6b, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76,
-0x2e, 0x3b, 0x64, 0x65, 0x63, 0x2e, 0x4a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72,
-0x3b, 0x4d, 0xe4, 0x72, 0x7a, 0x3b, 0x41, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69,
-0x3b, 0x4a, 0x75, 0x6c, 0x69, 0x3b, 0x41, 0x75, 0x67, 0x75, 0x73, 0x63, 0x68, 0x74, 0x3b, 0x53, 0x65, 0x70, 0x74, 0xe4,
-0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x4e, 0x6f, 0x76, 0xe4, 0x6d, 0x62,
-0x65, 0x72, 0x3b, 0x44, 0x65, 0x7a, 0xe4, 0x6d, 0x62, 0x65, 0x72, 0x69, 0x6e, 0x6e, 0x61, 0x79, 0x72, 0x3b, 0x62, 0x1e5b,
-0x61, 0x79, 0x1e5b, 0x3b, 0x6d, 0x61, 0x1e5b, 0x1e63, 0x3b, 0x69, 0x62, 0x72, 0x69, 0x72, 0x3b, 0x6d, 0x61, 0x79, 0x79, 0x75,
-0x3b, 0x79, 0x75, 0x6e, 0x79, 0x75, 0x3b, 0x79, 0x75, 0x6c, 0x79, 0x75, 0x7a, 0x3b, 0x263, 0x75, 0x63, 0x74, 0x3b, 0x63,
-0x75, 0x74, 0x61, 0x6e, 0x62, 0x69, 0x72, 0x3b, 0x6b, 0x74, 0x75, 0x62, 0x72, 0x3b, 0x6e, 0x75, 0x77, 0x61, 0x6e, 0x62,
-0x69, 0x72, 0x3b, 0x64, 0x75, 0x6a, 0x61, 0x6e, 0x62, 0x69, 0x72, 0x69, 0x6e, 0x6e, 0x3b, 0x62, 0x1e5b, 0x61, 0x3b, 0x6d,
-0x61, 0x1e5b, 0x3b, 0x69, 0x62, 0x72, 0x3b, 0x6d, 0x61, 0x79, 0x3b, 0x79, 0x75, 0x6e, 0x3b, 0x79, 0x75, 0x6c, 0x3b, 0x263,
-0x75, 0x63, 0x3b, 0x63, 0x75, 0x74, 0x3b, 0x6b, 0x74, 0x75, 0x3b, 0x6e, 0x75, 0x77, 0x3b, 0x64, 0x75, 0x6a, 0x69, 0x3b,
-0x62, 0x3b, 0x6d, 0x3b, 0x69, 0x3b, 0x6d, 0x3b, 0x79, 0x3b, 0x79, 0x3b, 0x263, 0x3b, 0x63, 0x3b, 0x6b, 0x3b, 0x6e, 0x3b,
-0x64, 0x4d, 0x6f, 0x72, 0x69, 0x20, 0x67, 0x68, 0x77, 0x61, 0x20, 0x69, 0x6d, 0x62, 0x69, 0x72, 0x69, 0x3b, 0x4d, 0x6f,
-0x72, 0x69, 0x20, 0x67, 0x68, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x77, 0x69, 0x3b, 0x4d, 0x6f, 0x72, 0x69, 0x20, 0x67, 0x68,
-0x77, 0x61, 0x20, 0x6b, 0x61, 0x64, 0x61, 0x64, 0x75, 0x3b, 0x4d, 0x6f, 0x72, 0x69, 0x20, 0x67, 0x68, 0x77, 0x61, 0x20,
-0x6b, 0x61, 0x6e, 0x61, 0x3b, 0x4d, 0x6f, 0x72, 0x69, 0x20, 0x67, 0x68, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x73, 0x61, 0x6e,
-0x75, 0x3b, 0x4d, 0x6f, 0x72, 0x69, 0x20, 0x67, 0x68, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x72, 0x61, 0x6e, 0x64, 0x61, 0x64,
-0x75, 0x3b, 0x4d, 0x6f, 0x72, 0x69, 0x20, 0x67, 0x68, 0x77, 0x61, 0x20, 0x6d, 0x66, 0x75, 0x6e, 0x67, 0x61, 0x64, 0x65,
-0x3b, 0x4d, 0x6f, 0x72, 0x69, 0x20, 0x67, 0x68, 0x77, 0x61, 0x20, 0x77, 0x75, 0x6e, 0x79, 0x61, 0x6e, 0x79, 0x61, 0x3b,
-0x4d, 0x6f, 0x72, 0x69, 0x20, 0x67, 0x68, 0x77, 0x61, 0x20, 0x69, 0x6b, 0x65, 0x6e, 0x64, 0x61, 0x3b, 0x4d, 0x6f, 0x72,
-0x69, 0x20, 0x67, 0x68, 0x77, 0x61, 0x20, 0x69, 0x6b, 0x75, 0x6d, 0x69, 0x3b, 0x4d, 0x6f, 0x72, 0x69, 0x20, 0x67, 0x68,
-0x77, 0x61, 0x20, 0x69, 0x6b, 0x75, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x69, 0x6d, 0x77, 0x65, 0x72, 0x69, 0x3b, 0x4d,
-0x6f, 0x72, 0x69, 0x20, 0x67, 0x68, 0x77, 0x61, 0x20, 0x69, 0x6b, 0x75, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x69, 0x77,
-0x69, 0x49, 0x6d, 0x62, 0x3b, 0x4b, 0x61, 0x77, 0x3b, 0x4b, 0x61, 0x64, 0x3b, 0x4b, 0x61, 0x6e, 0x3b, 0x4b, 0x61, 0x73,
-0x3b, 0x4b, 0x61, 0x72, 0x3b, 0x4d, 0x66, 0x75, 0x3b, 0x57, 0x75, 0x6e, 0x3b, 0x49, 0x6b, 0x65, 0x3b, 0x49, 0x6b, 0x75,
-0x3b, 0x49, 0x6d, 0x77, 0x3b, 0x49, 0x77, 0x69, 0x49, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b,
-0x4d, 0x3b, 0x57, 0x3b, 0x49, 0x3b, 0x49, 0x3b, 0x49, 0x3b, 0x49, 0x42f, 0x43d, 0x432, 0x430, 0x440, 0x3b, 0x424, 0x435, 0x432,
-0x440, 0x430, 0x43b, 0x3b, 0x41c, 0x430, 0x440, 0x442, 0x3b, 0x410, 0x43f, 0x440, 0x435, 0x43b, 0x3b, 0x41c, 0x430, 0x439, 0x3b, 0x418,
-0x44e, 0x43d, 0x3b, 0x418, 0x44e, 0x43b, 0x3b, 0x410, 0x432, 0x433, 0x443, 0x441, 0x442, 0x3b, 0x421, 0x435, 0x43d, 0x442, 0x44f, 0x431,
-0x440, 0x3b, 0x41e, 0x43a, 0x442, 0x44f, 0x431, 0x440, 0x3b, 0x41d, 0x43e, 0x44f, 0x431, 0x440, 0x3b, 0x414, 0x435, 0x43a, 0x430, 0x431,
-0x440, 0xb9c, 0xba9, 0xbb5, 0xbb0, 0xbbf, 0x3b, 0xbaa, 0xbbf, 0xbaa, 0xbcd, 0xbb0, 0xbb5, 0xbb0, 0xbbf, 0x3b, 0xbae, 0xbbe, 0xbb0, 0xbcd,
-0xb9a, 0xbcd, 0x3b, 0xb8f, 0xbaa, 0xbcd, 0xbb0, 0xbb2, 0xbcd, 0x3b, 0xbae, 0xbc7, 0x3b, 0xb9c, 0xbc2, 0xba9, 0xbcd, 0x3b, 0xb9c, 0xbc2,
-0xbb2, 0xbc8, 0x3b, 0xb86, 0xb95, 0xbb8, 0xbcd, 0xb9f, 0xbcd, 0x3b, 0xb9a, 0xbc6, 0xbaa, 0xbcd, 0xb9f, 0xbae, 0xbcd, 0xbaa, 0xbb0, 0xbcd,
-0x3b, 0xb85, 0xb95, 0xbcd, 0xb9f, 0xbcb, 0xbaa, 0xbb0, 0xbcd, 0x3b, 0xba8, 0xbb5, 0xbae, 0xbcd, 0xbaa, 0xbb0, 0xbcd, 0x3b, 0xb9f, 0xbbf,
-0xb9a, 0xbae, 0xbcd, 0xbaa, 0xbb0, 0xbcd, 0xb9c, 0xba9, 0x2e, 0x3b, 0xbaa, 0xbbf, 0xbaa, 0xbcd, 0x2e, 0x3b, 0xbae, 0xbbe, 0xbb0, 0xbcd,
-0x2e, 0x3b, 0xb8f, 0xbaa, 0xbcd, 0x2e, 0x3b, 0xbae, 0xbc7, 0x3b, 0xb9c, 0xbc2, 0xba9, 0xbcd, 0x3b, 0xb9c, 0xbc2, 0xbb2, 0xbc8, 0x3b,
-0xb86, 0xb95, 0x2e, 0x3b, 0xb9a, 0xbc6, 0xbaa, 0xbcd, 0x2e, 0x3b, 0xb85, 0xb95, 0xbcd, 0x2e, 0x3b, 0xba8, 0xbb5, 0x2e, 0x3b, 0xb9f,
-0xbbf, 0xb9a, 0x2e, 0xb9c, 0x3b, 0xbaa, 0xbbf, 0x3b, 0xbae, 0xbbe, 0x3b, 0xb8f, 0x3b, 0xbae, 0xbc7, 0x3b, 0xb9c, 0xbc2, 0x3b, 0xb9c,
-0xbc2, 0x3b, 0xb86, 0x3b, 0xb9a, 0xbc6, 0x3b, 0xb85, 0x3b, 0xba8, 0x3b, 0xb9f, 0xbbf, 0x433, 0x44b, 0x439, 0x43d, 0x432, 0x430, 0x440,
-0x3b, 0x444, 0x435, 0x432, 0x440, 0x430, 0x43b, 0x44c, 0x3b, 0x43c, 0x430, 0x440, 0x442, 0x3b, 0x430, 0x43f, 0x440, 0x435, 0x43b, 0x44c,
-0x3b, 0x43c, 0x430, 0x439, 0x3b, 0x438, 0x44e, 0x43d, 0x44c, 0x3b, 0x438, 0x44e, 0x43b, 0x44c, 0x3b, 0x430, 0x432, 0x433, 0x443, 0x441,
-0x442, 0x3b, 0x441, 0x435, 0x43d, 0x442, 0x44f, 0x431, 0x440, 0x44c, 0x3b, 0x43e, 0x43a, 0x442, 0x44f, 0x431, 0x440, 0x44c, 0x3b, 0x43d,
-0x43e, 0x44f, 0x431, 0x440, 0x44c, 0x3b, 0x434, 0x435, 0x43a, 0x430, 0x431, 0x440, 0x44c, 0x433, 0x44b, 0x439, 0x43d, 0x2e, 0x3b, 0x444,
-0x435, 0x432, 0x2e, 0x3b, 0x43c, 0x430, 0x440, 0x2e, 0x3b, 0x430, 0x43f, 0x440, 0x2e, 0x3b, 0x43c, 0x430, 0x439, 0x3b, 0x438, 0x44e,
-0x43d, 0x44c, 0x3b, 0x438, 0x44e, 0x43b, 0x44c, 0x3b, 0x430, 0x432, 0x433, 0x2e, 0x3b, 0x441, 0x435, 0x43d, 0x442, 0x2e, 0x3b, 0x43e,
-0x43a, 0x442, 0x2e, 0x3b, 0x43d, 0x43e, 0x44f, 0x431, 0x2e, 0x3b, 0x434, 0x435, 0x43a, 0x2e, 0xc1c, 0xc28, 0xc35, 0xc30, 0xc3f, 0x3b,
-0xc2b, 0xc3f, 0xc2c, 0xc4d, 0xc30, 0xc35, 0xc30, 0xc3f, 0x3b, 0xc2e, 0xc3e, 0xc30, 0xc4d, 0xc1a, 0xc3f, 0x3b, 0xc0f, 0xc2a, 0xc4d, 0xc30,
-0xc3f, 0xc32, 0xc4d, 0x3b, 0xc2e, 0xc47, 0x3b, 0xc1c, 0xc42, 0xc28, 0xc4d, 0x3b, 0xc1c, 0xc41, 0xc32, 0xc48, 0x3b, 0xc06, 0xc17, 0xc38,
-0xc4d, 0xc1f, 0xc41, 0x3b, 0xc38, 0xc46, 0xc2a, 0xc4d, 0xc1f, 0xc46, 0xc02, 0xc2c, 0xc30, 0xc4d, 0x3b, 0xc05, 0xc15, 0xc4d, 0xc1f, 0xc4b,
-0xc2c, 0xc30, 0xc4d, 0x3b, 0xc28, 0xc35, 0xc02, 0xc2c, 0xc30, 0xc4d, 0x3b, 0xc21, 0xc3f, 0xc38, 0xc46, 0xc02, 0xc2c, 0xc30, 0xc4d, 0xc1c,
-0xc28, 0x3b, 0xc2b, 0xc3f, 0xc2c, 0xc4d, 0xc30, 0x3b, 0xc2e, 0xc3e, 0xc30, 0xc4d, 0xc1a, 0xc3f, 0x3b, 0xc0f, 0xc2a, 0xc4d, 0xc30, 0xc3f,
-0x3b, 0xc2e, 0xc47, 0x3b, 0xc1c, 0xc42, 0xc28, 0xc4d, 0x3b, 0xc1c, 0xc41, 0xc32, 0xc48, 0x3b, 0xc06, 0xc17, 0x3b, 0xc38, 0xc46, 0xc2a,
-0xc4d, 0xc1f, 0xc46, 0xc02, 0x3b, 0xc05, 0xc15, 0xc4d, 0xc1f, 0xc4b, 0x3b, 0xc28, 0xc35, 0xc02, 0x3b, 0xc21, 0xc3f, 0xc38, 0xc46, 0xc02,
-0xc1c, 0x3b, 0xc2b, 0xc3f, 0x3b, 0xc2e, 0xc3e, 0x3b, 0xc0f, 0x3b, 0xc2e, 0xc47, 0x3b, 0xc1c, 0xc42, 0x3b, 0xc1c, 0xc41, 0x3b, 0xc06,
-0x3b, 0xc38, 0xc46, 0x3b, 0xc05, 0x3b, 0xc28, 0x3b, 0xc21, 0xc3f, 0x4f, 0x72, 0x61, 0x72, 0x61, 0x3b, 0x4f, 0x6d, 0x75, 0x6b,
-0x3b, 0x4f, 0x6b, 0x77, 0x61, 0x6d, 0x67, 0x2019, 0x3b, 0x4f, 0x64, 0x75, 0x6e, 0x67, 0x2019, 0x65, 0x6c, 0x3b, 0x4f, 0x6d,
-0x61, 0x72, 0x75, 0x6b, 0x3b, 0x4f, 0x6d, 0x6f, 0x64, 0x6f, 0x6b, 0x2019, 0x6b, 0x69, 0x6e, 0x67, 0x2019, 0x6f, 0x6c, 0x3b,
-0x4f, 0x6a, 0x6f, 0x6c, 0x61, 0x3b, 0x4f, 0x70, 0x65, 0x64, 0x65, 0x6c, 0x3b, 0x4f, 0x73, 0x6f, 0x6b, 0x6f, 0x73, 0x6f,
-0x6b, 0x6f, 0x6d, 0x61, 0x3b, 0x4f, 0x74, 0x69, 0x62, 0x61, 0x72, 0x3b, 0x4f, 0x6c, 0x61, 0x62, 0x6f, 0x72, 0x3b, 0x4f,
-0x70, 0x6f, 0x6f, 0x52, 0x61, 0x72, 0x3b, 0x4d, 0x75, 0x6b, 0x3b, 0x4b, 0x77, 0x61, 0x3b, 0x44, 0x75, 0x6e, 0x3b, 0x4d,
-0x61, 0x72, 0x3b, 0x4d, 0x6f, 0x64, 0x3b, 0x4a, 0x6f, 0x6c, 0x3b, 0x50, 0x65, 0x64, 0x3b, 0x53, 0x6f, 0x6b, 0x3b, 0x54,
-0x69, 0x62, 0x3b, 0x4c, 0x61, 0x62, 0x3b, 0x50, 0x6f, 0x6f, 0x52, 0x3b, 0x4d, 0x3b, 0x4b, 0x3b, 0x44, 0x3b, 0x4d, 0x3b,
-0x4d, 0x3b, 0x4a, 0x3b, 0x50, 0x3b, 0x53, 0x3b, 0x54, 0x3b, 0x4c, 0x3b, 0x50, 0xe21, 0xe01, 0xe23, 0xe32, 0xe04, 0xe21, 0x3b,
-0xe01, 0xe38, 0xe21, 0xe20, 0xe32, 0xe1e, 0xe31, 0xe19, 0xe18, 0xe4c, 0x3b, 0xe21, 0xe35, 0xe19, 0xe32, 0xe04, 0xe21, 0x3b, 0xe40, 0xe21,
-0xe29, 0xe32, 0xe22, 0xe19, 0x3b, 0xe1e, 0xe24, 0xe29, 0xe20, 0xe32, 0xe04, 0xe21, 0x3b, 0xe21, 0xe34, 0xe16, 0xe38, 0xe19, 0xe32, 0xe22,
-0xe19, 0x3b, 0xe01, 0xe23, 0xe01, 0xe0e, 0xe32, 0xe04, 0xe21, 0x3b, 0xe2a, 0xe34, 0xe07, 0xe2b, 0xe32, 0xe04, 0xe21, 0x3b, 0xe01, 0xe31,
-0xe19, 0xe22, 0xe32, 0xe22, 0xe19, 0x3b, 0xe15, 0xe38, 0xe25, 0xe32, 0xe04, 0xe21, 0x3b, 0xe1e, 0xe24, 0xe28, 0xe08, 0xe34, 0xe01, 0xe32,
-0xe22, 0xe19, 0x3b, 0xe18, 0xe31, 0xe19, 0xe27, 0xe32, 0xe04, 0xe21, 0xe21, 0x2e, 0xe04, 0x2e, 0x3b, 0xe01, 0x2e, 0xe1e, 0x2e, 0x3b,
-0xe21, 0xe35, 0x2e, 0xe04, 0x2e, 0x3b, 0xe40, 0xe21, 0x2e, 0xe22, 0x2e, 0x3b, 0xe1e, 0x2e, 0xe04, 0x2e, 0x3b, 0xe21, 0xe34, 0x2e,
-0xe22, 0x2e, 0x3b, 0xe01, 0x2e, 0xe04, 0x2e, 0x3b, 0xe2a, 0x2e, 0xe04, 0x2e, 0x3b, 0xe01, 0x2e, 0xe22, 0x2e, 0x3b, 0xe15, 0x2e,
-0xe04, 0x2e, 0x3b, 0xe1e, 0x2e, 0xe22, 0x2e, 0x3b, 0xe18, 0x2e, 0xe04, 0x2e, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf51, 0xf44, 0xf0b,
-0xf54, 0xf7c, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf42, 0xf49, 0xf72, 0xf66, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b,
-0xf56, 0xf0b, 0xf42, 0xf66, 0xf74, 0xf58, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf56, 0xf5e, 0xf72, 0xf0b, 0xf54,
-0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf63, 0xf94, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf51, 0xfb2,
-0xf74, 0xf42, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf56, 0xf51, 0xf74, 0xf53, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f,
-0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf56, 0xf62, 0xf92, 0xfb1, 0xf51, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf51, 0xf42,
-0xf74, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf56, 0xf45, 0xf74, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b,
-0xf56, 0xf0b, 0xf56, 0xf45, 0xf74, 0xf0b, 0xf42, 0xf45, 0xf72, 0xf42, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf56,
-0xf45, 0xf74, 0xf0b, 0xf42, 0xf49, 0xf72, 0xf66, 0xf0b, 0xf54, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf51, 0xf44, 0xf0b, 0xf54, 0xf7c,
-0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf42, 0xf49, 0xf72, 0xf66, 0xf0b, 0xf54, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf42, 0xf66,
-0xf74, 0xf58, 0xf0b, 0xf54, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf56, 0xf5e, 0xf72, 0xf0b, 0xf54, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56,
-0xf0b, 0xf63, 0xf94, 0xf0b, 0xf54, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf51, 0xfb2, 0xf74, 0xf42, 0xf0b, 0xf54, 0x3b, 0xf5f, 0xfb3,
-0xf0b, 0xf56, 0xf0b, 0xf56, 0xf51, 0xf74, 0xf53, 0xf0b, 0xf54, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf56, 0xf62, 0xf92, 0xfb1, 0xf51,
-0xf0b, 0xf54, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf51, 0xf42, 0xf74, 0xf0b, 0xf54, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf56,
-0xf45, 0xf74, 0xf0b, 0xf54, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf56, 0xf45, 0xf74, 0xf0b, 0xf42, 0xf45, 0xf72, 0xf42, 0xf0b, 0xf54,
-0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf56, 0xf45, 0xf74, 0xf0b, 0xf42, 0xf49, 0xf72, 0xf66, 0xf0b, 0xf54, 0x1325, 0x122a, 0x3b, 0x1208,
-0x12ab, 0x1272, 0x1275, 0x3b, 0x1218, 0x130b, 0x1262, 0x1275, 0x3b, 0x121a, 0x12eb, 0x12dd, 0x12eb, 0x3b, 0x130d, 0x1295, 0x1266, 0x1275, 0x3b, 0x1230,
-0x1290, 0x3b, 0x1213, 0x121d, 0x1208, 0x3b, 0x1290, 0x1213, 0x1230, 0x3b, 0x1218, 0x1235, 0x12a8, 0x1228, 0x121d, 0x3b, 0x1325, 0x1245, 0x121d, 0x1272,
-0x3b, 0x1215, 0x12f3, 0x122d, 0x3b, 0x1273, 0x1215, 0x1233, 0x1235, 0x1325, 0x122a, 0x3b, 0x1208, 0x12ab, 0x3b, 0x1218, 0x130b, 0x3b, 0x121a, 0x12eb,
-0x3b, 0x130d, 0x1295, 0x3b, 0x1230, 0x1290, 0x3b, 0x1213, 0x121d, 0x3b, 0x1290, 0x1213, 0x3b, 0x1218, 0x1235, 0x3b, 0x1325, 0x1245, 0x3b, 0x1215,
-0x12f3, 0x3b, 0x1273, 0x1215, 0x1325, 0x3b, 0x1208, 0x3b, 0x1218, 0x3b, 0x121a, 0x3b, 0x130d, 0x3b, 0x1230, 0x3b, 0x1213, 0x3b, 0x1290, 0x3b,
-0x1218, 0x3b, 0x1325, 0x3b, 0x1215, 0x3b, 0x1273, 0x53, 0x101, 0x6e, 0x75, 0x61, 0x6c, 0x69, 0x3b, 0x46, 0x113, 0x70, 0x75, 0x65,
-0x6c, 0x69, 0x3b, 0x4d, 0x61, 0x2bb, 0x61, 0x73, 0x69, 0x3b, 0x2bb, 0x45, 0x70, 0x65, 0x6c, 0x65, 0x6c, 0x69, 0x3b, 0x4d,
-0x113, 0x3b, 0x53, 0x75, 0x6e, 0x65, 0x3b, 0x53, 0x69, 0x75, 0x6c, 0x61, 0x69, 0x3b, 0x2bb, 0x41, 0x6f, 0x6b, 0x6f, 0x73,
-0x69, 0x3b, 0x53, 0x65, 0x70, 0x69, 0x74, 0x65, 0x6d, 0x61, 0x3b, 0x2bb, 0x4f, 0x6b, 0x61, 0x74, 0x6f, 0x70, 0x61, 0x3b,
-0x4e, 0x14d, 0x76, 0x65, 0x6d, 0x61, 0x3b, 0x54, 0x12b, 0x73, 0x65, 0x6d, 0x61, 0x53, 0x101, 0x6e, 0x3b, 0x46, 0x113, 0x70,
-0x3b, 0x4d, 0x61, 0x2bb, 0x61, 0x3b, 0x2bb, 0x45, 0x70, 0x65, 0x3b, 0x4d, 0x113, 0x3b, 0x53, 0x75, 0x6e, 0x3b, 0x53, 0x69,
-0x75, 0x3b, 0x2bb, 0x41, 0x6f, 0x6b, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x2bb, 0x4f, 0x6b, 0x61, 0x3b, 0x4e, 0x14d, 0x76, 0x3b,
-0x54, 0x12b, 0x73, 0x53, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x45, 0x3b, 0x4d, 0x3b, 0x53, 0x3b, 0x53, 0x3b, 0x41, 0x3b, 0x53,
-0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x54, 0x53, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x2bb, 0x45, 0x3b, 0x4d, 0x3b, 0x53, 0x3b, 0x53,
-0x3b, 0x2bb, 0x41, 0x3b, 0x53, 0x3b, 0x2bb, 0x4f, 0x3b, 0x4e, 0x3b, 0x54, 0x4f, 0x63, 0x61, 0x6b, 0x3b, 0x15e, 0x75, 0x62,
-0x61, 0x74, 0x3b, 0x4d, 0x61, 0x72, 0x74, 0x3b, 0x4e, 0x69, 0x73, 0x61, 0x6e, 0x3b, 0x4d, 0x61, 0x79, 0x131, 0x73, 0x3b,
-0x48, 0x61, 0x7a, 0x69, 0x72, 0x61, 0x6e, 0x3b, 0x54, 0x65, 0x6d, 0x6d, 0x75, 0x7a, 0x3b, 0x41, 0x11f, 0x75, 0x73, 0x74,
-0x6f, 0x73, 0x3b, 0x45, 0x79, 0x6c, 0xfc, 0x6c, 0x3b, 0x45, 0x6b, 0x69, 0x6d, 0x3b, 0x4b, 0x61, 0x73, 0x131, 0x6d, 0x3b,
-0x41, 0x72, 0x61, 0x6c, 0x131, 0x6b, 0x4f, 0x63, 0x61, 0x3b, 0x15e, 0x75, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x4e, 0x69,
-0x73, 0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x48, 0x61, 0x7a, 0x3b, 0x54, 0x65, 0x6d, 0x3b, 0x41, 0x11f, 0x75, 0x3b, 0x45, 0x79,
-0x6c, 0x3b, 0x45, 0x6b, 0x69, 0x3b, 0x4b, 0x61, 0x73, 0x3b, 0x41, 0x72, 0x61, 0x4f, 0x3b, 0x15e, 0x3b, 0x4d, 0x3b, 0x4e,
-0x3b, 0x4d, 0x3b, 0x48, 0x3b, 0x54, 0x3b, 0x41, 0x3b, 0x45, 0x3b, 0x45, 0x3b, 0x4b, 0x3b, 0x41, 0xdd, 0x61, 0x6e, 0x77,
-0x61, 0x72, 0x3b, 0x46, 0x65, 0x77, 0x72, 0x61, 0x6c, 0x3b, 0x4d, 0x61, 0x72, 0x74, 0x3b, 0x41, 0x70, 0x72, 0x65, 0x6c,
-0x3b, 0x4d, 0x61, 0xfd, 0x3b, 0x49, 0xfd, 0x75, 0x6e, 0x3b, 0x49, 0xfd, 0x75, 0x6c, 0x3b, 0x41, 0x77, 0x67, 0x75, 0x73,
-0x74, 0x3b, 0x53, 0x65, 0x6e, 0x74, 0xfd, 0x61, 0x62, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0xfd, 0x61, 0x62, 0x72, 0x3b, 0x4e,
-0x6f, 0xfd, 0x61, 0x62, 0x72, 0x3b, 0x44, 0x65, 0x6b, 0x61, 0x62, 0x72, 0xfd, 0x61, 0x6e, 0x77, 0x61, 0x72, 0x3b, 0x66,
-0x65, 0x77, 0x72, 0x61, 0x6c, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x3b, 0x61, 0x70, 0x72, 0x65, 0x6c, 0x3b, 0x6d, 0x61, 0xfd,
-0x3b, 0x69, 0xfd, 0x75, 0x6e, 0x3b, 0x69, 0xfd, 0x75, 0x6c, 0x3b, 0x61, 0x77, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65,
-0x6e, 0x74, 0xfd, 0x61, 0x62, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0xfd, 0x61, 0x62, 0x72, 0x3b, 0x6e, 0x6f, 0xfd, 0x61, 0x62,
-0x72, 0x3b, 0x64, 0x65, 0x6b, 0x61, 0x62, 0x72, 0xdd, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x77, 0x3b, 0x4d, 0x61, 0x72, 0x3b,
-0x41, 0x70, 0x72, 0x3b, 0x4d, 0x61, 0xfd, 0x3b, 0x49, 0xfd, 0x75, 0x6e, 0x3b, 0x49, 0xfd, 0x75, 0x6c, 0x3b, 0x41, 0x77,
-0x67, 0x3b, 0x53, 0x65, 0x6e, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0xfd, 0x3b, 0x44, 0x65, 0x6b, 0xfd, 0x61, 0x6e,
-0x3b, 0x66, 0x65, 0x77, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0x61, 0xfd, 0x3b, 0x69, 0xfd,
-0x75, 0x6e, 0x3b, 0x69, 0xfd, 0x75, 0x6c, 0x3b, 0x61, 0x77, 0x67, 0x3b, 0x73, 0x65, 0x6e, 0x3b, 0x6f, 0x6b, 0x74, 0x3b,
-0x6e, 0x6f, 0xfd, 0x3b, 0x64, 0x65, 0x6b, 0xdd, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x49, 0x3b, 0x49,
-0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x441, 0x456, 0x447, 0x435, 0x43d, 0x44c, 0x3b, 0x43b, 0x44e, 0x442,
-0x438, 0x439, 0x3b, 0x431, 0x435, 0x440, 0x435, 0x437, 0x435, 0x43d, 0x44c, 0x3b, 0x43a, 0x432, 0x456, 0x442, 0x435, 0x43d, 0x44c, 0x3b,
-0x442, 0x440, 0x430, 0x432, 0x435, 0x43d, 0x44c, 0x3b, 0x447, 0x435, 0x440, 0x432, 0x435, 0x43d, 0x44c, 0x3b, 0x43b, 0x438, 0x43f, 0x435,
-0x43d, 0x44c, 0x3b, 0x441, 0x435, 0x440, 0x43f, 0x435, 0x43d, 0x44c, 0x3b, 0x432, 0x435, 0x440, 0x435, 0x441, 0x435, 0x43d, 0x44c, 0x3b,
-0x436, 0x43e, 0x432, 0x442, 0x435, 0x43d, 0x44c, 0x3b, 0x43b, 0x438, 0x441, 0x442, 0x43e, 0x43f, 0x430, 0x434, 0x3b, 0x433, 0x440, 0x443,
-0x434, 0x435, 0x43d, 0x44c, 0x441, 0x456, 0x447, 0x43d, 0x44f, 0x3b, 0x43b, 0x44e, 0x442, 0x43e, 0x433, 0x43e, 0x3b, 0x431, 0x435, 0x440,
-0x435, 0x437, 0x43d, 0x44f, 0x3b, 0x43a, 0x432, 0x456, 0x442, 0x43d, 0x44f, 0x3b, 0x442, 0x440, 0x430, 0x432, 0x43d, 0x44f, 0x3b, 0x447,
-0x435, 0x440, 0x432, 0x43d, 0x44f, 0x3b, 0x43b, 0x438, 0x43f, 0x43d, 0x44f, 0x3b, 0x441, 0x435, 0x440, 0x43f, 0x43d, 0x44f, 0x3b, 0x432,
-0x435, 0x440, 0x435, 0x441, 0x43d, 0x44f, 0x3b, 0x436, 0x43e, 0x432, 0x442, 0x43d, 0x44f, 0x3b, 0x43b, 0x438, 0x441, 0x442, 0x43e, 0x43f,
-0x430, 0x434, 0x430, 0x3b, 0x433, 0x440, 0x443, 0x434, 0x43d, 0x44f, 0x441, 0x456, 0x447, 0x3b, 0x43b, 0x44e, 0x442, 0x3b, 0x431, 0x435,
-0x440, 0x3b, 0x43a, 0x432, 0x456, 0x3b, 0x442, 0x440, 0x430, 0x3b, 0x447, 0x435, 0x440, 0x3b, 0x43b, 0x438, 0x43f, 0x3b, 0x441, 0x435,
-0x440, 0x3b, 0x432, 0x435, 0x440, 0x3b, 0x436, 0x43e, 0x432, 0x3b, 0x43b, 0x438, 0x441, 0x3b, 0x433, 0x440, 0x443, 0x441, 0x456, 0x447,
-0x2e, 0x3b, 0x43b, 0x44e, 0x442, 0x2e, 0x3b, 0x431, 0x435, 0x440, 0x2e, 0x3b, 0x43a, 0x432, 0x456, 0x442, 0x2e, 0x3b, 0x442, 0x440,
-0x430, 0x432, 0x2e, 0x3b, 0x447, 0x435, 0x440, 0x432, 0x2e, 0x3b, 0x43b, 0x438, 0x43f, 0x2e, 0x3b, 0x441, 0x435, 0x440, 0x43f, 0x2e,
-0x3b, 0x432, 0x435, 0x440, 0x2e, 0x3b, 0x436, 0x43e, 0x432, 0x442, 0x2e, 0x3b, 0x43b, 0x438, 0x441, 0x442, 0x2e, 0x3b, 0x433, 0x440,
-0x443, 0x434, 0x2e, 0x421, 0x3b, 0x41b, 0x3b, 0x411, 0x3b, 0x41a, 0x3b, 0x422, 0x3b, 0x427, 0x3b, 0x41b, 0x3b, 0x421, 0x3b, 0x412,
-0x3b, 0x416, 0x3b, 0x41b, 0x3b, 0x413, 0x441, 0x3b, 0x43b, 0x3b, 0x431, 0x3b, 0x43a, 0x3b, 0x442, 0x3b, 0x447, 0x3b, 0x43b, 0x3b,
-0x441, 0x3b, 0x432, 0x3b, 0x436, 0x3b, 0x43b, 0x3b, 0x433, 0x6a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x3b, 0x66, 0x65, 0x62, 0x72,
-0x75, 0x61, 0x72, 0x3b, 0x6d, 0x11b, 0x72, 0x63, 0x3b, 0x61, 0x70, 0x72, 0x79, 0x6c, 0x3b, 0x6d, 0x65, 0x6a, 0x61, 0x3b,
-0x6a, 0x75, 0x6e, 0x69, 0x6a, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x6a, 0x3b, 0x61, 0x77, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x73,
-0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x6e, 0x6f, 0x77,
-0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x6a, 0x61, 0x6e, 0x75, 0x61, 0x72,
-0x61, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x61, 0x3b, 0x6d, 0x11b, 0x72, 0x63, 0x61, 0x3b, 0x61, 0x70, 0x72,
-0x79, 0x6c, 0x61, 0x3b, 0x6d, 0x65, 0x6a, 0x65, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x6a, 0x61, 0x3b, 0x6a, 0x75, 0x6c, 0x69,
-0x6a, 0x61, 0x3b, 0x61, 0x77, 0x67, 0x75, 0x73, 0x74, 0x61, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x61,
-0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x72, 0x61, 0x3b, 0x6e, 0x6f, 0x77, 0x65, 0x6d, 0x62, 0x72, 0x61, 0x3b, 0x64, 0x65,
-0x63, 0x65, 0x6d, 0x62, 0x72, 0x61, 0x6a, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0x11b, 0x72, 0x3b, 0x61, 0x70,
-0x72, 0x3b, 0x6d, 0x65, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x77, 0x67, 0x3b, 0x73, 0x65,
-0x70, 0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x77, 0x3b, 0x64, 0x65, 0x63, 0x6a, 0x61, 0x6e, 0x2e, 0x3b, 0x66, 0x65,
-0x62, 0x2e, 0x3b, 0x6d, 0x11b, 0x72, 0x2e, 0x3b, 0x61, 0x70, 0x72, 0x2e, 0x3b, 0x6d, 0x65, 0x6a, 0x2e, 0x3b, 0x6a, 0x75,
-0x6e, 0x2e, 0x3b, 0x6a, 0x75, 0x6c, 0x2e, 0x3b, 0x61, 0x77, 0x67, 0x2e, 0x3b, 0x73, 0x65, 0x70, 0x2e, 0x3b, 0x6f, 0x6b,
-0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x77, 0x2e, 0x3b, 0x64, 0x65, 0x63, 0x2e, 0x62c, 0x646, 0x648, 0x631, 0x6cc, 0x3b, 0x641, 0x631,
-0x648, 0x631, 0x6cc, 0x3b, 0x645, 0x627, 0x631, 0x686, 0x3b, 0x627, 0x67e, 0x631, 0x6cc, 0x644, 0x3b, 0x645, 0x626, 0x6cc, 0x3b, 0x62c,
-0x648, 0x646, 0x3b, 0x62c, 0x648, 0x644, 0x627, 0x626, 0x6cc, 0x3b, 0x627, 0x6af, 0x633, 0x62a, 0x3b, 0x633, 0x62a, 0x645, 0x628, 0x631,
-0x3b, 0x627, 0x6a9, 0x62a, 0x648, 0x628, 0x631, 0x3b, 0x646, 0x648, 0x645, 0x628, 0x631, 0x3b, 0x62f, 0x633, 0x645, 0x628, 0x631, 0x64a,
-0x627, 0x646, 0x6cb, 0x627, 0x631, 0x3b, 0x641, 0x6d0, 0x6cb, 0x631, 0x627, 0x644, 0x3b, 0x645, 0x627, 0x631, 0x62a, 0x3b, 0x626, 0x627,
-0x67e, 0x631, 0x6d0, 0x644, 0x3b, 0x645, 0x627, 0x64a, 0x3b, 0x626, 0x649, 0x64a, 0x6c7, 0x646, 0x3b, 0x626, 0x649, 0x64a, 0x6c7, 0x644,
-0x3b, 0x626, 0x627, 0x6cb, 0x63a, 0x6c7, 0x633, 0x62a, 0x3b, 0x633, 0x6d0, 0x646, 0x62a, 0x6d5, 0x628, 0x649, 0x631, 0x3b, 0x626, 0x6c6,
-0x643, 0x62a, 0x6d5, 0x628, 0x649, 0x631, 0x3b, 0x646, 0x648, 0x64a, 0x627, 0x628, 0x649, 0x631, 0x3b, 0x62f, 0x6d0, 0x643, 0x627, 0x628,
-0x649, 0x631, 0x59, 0x61, 0x6e, 0x76, 0x61, 0x72, 0x3b, 0x46, 0x65, 0x76, 0x72, 0x61, 0x6c, 0x3b, 0x4d, 0x61, 0x72, 0x74,
-0x3b, 0x41, 0x70, 0x72, 0x65, 0x6c, 0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x49, 0x79, 0x75, 0x6e, 0x3b, 0x49, 0x79, 0x75, 0x6c,
-0x3b, 0x41, 0x76, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x53, 0x65, 0x6e, 0x74, 0x61, 0x62, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x61,
-0x62, 0x72, 0x3b, 0x4e, 0x6f, 0x79, 0x61, 0x62, 0x72, 0x3b, 0x44, 0x65, 0x6b, 0x61, 0x62, 0x72, 0x79, 0x61, 0x6e, 0x76,
-0x61, 0x72, 0x3b, 0x66, 0x65, 0x76, 0x72, 0x61, 0x6c, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x3b, 0x61, 0x70, 0x72, 0x65, 0x6c,
-0x3b, 0x6d, 0x61, 0x79, 0x3b, 0x69, 0x79, 0x75, 0x6e, 0x3b, 0x69, 0x79, 0x75, 0x6c, 0x3b, 0x61, 0x76, 0x67, 0x75, 0x73,
-0x74, 0x3b, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x62, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x61, 0x62, 0x72, 0x3b, 0x6e, 0x6f, 0x79,
-0x61, 0x62, 0x72, 0x3b, 0x64, 0x65, 0x6b, 0x61, 0x62, 0x72, 0x59, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x76, 0x3b, 0x4d, 0x61,
-0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x49, 0x79, 0x6e, 0x3b, 0x49, 0x79, 0x6c, 0x3b, 0x41, 0x76,
-0x67, 0x3b, 0x53, 0x65, 0x6e, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x79, 0x3b, 0x44, 0x65, 0x6b, 0x79, 0x61, 0x6e,
-0x3b, 0x66, 0x65, 0x76, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0x61, 0x79, 0x3b, 0x69, 0x79, 0x6e,
-0x3b, 0x69, 0x79, 0x6c, 0x3b, 0x61, 0x76, 0x67, 0x3b, 0x73, 0x65, 0x6e, 0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x79,
-0x3b, 0x64, 0x65, 0x6b, 0x59, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x49, 0x3b, 0x49, 0x3b, 0x41, 0x3b,
-0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x62c, 0x646, 0x648, 0x3b, 0x641, 0x628, 0x631, 0x3b, 0x645, 0x627, 0x631, 0x3b, 0x627,
-0x67e, 0x631, 0x3b, 0x645, 0x6cc, 0x3b, 0x62c, 0x648, 0x646, 0x3b, 0x62c, 0x648, 0x644, 0x3b, 0x627, 0x6af, 0x633, 0x3b, 0x633, 0x67e,
-0x62a, 0x3b, 0x627, 0x6a9, 0x62a, 0x3b, 0x646, 0x648, 0x645, 0x3b, 0x62f, 0x633, 0x645, 0x44f, 0x43d, 0x432, 0x430, 0x440, 0x3b, 0x444,
-0x435, 0x432, 0x440, 0x430, 0x43b, 0x3b, 0x43c, 0x430, 0x440, 0x442, 0x3b, 0x430, 0x43f, 0x440, 0x435, 0x43b, 0x3b, 0x43c, 0x430, 0x439,
-0x3b, 0x438, 0x44e, 0x43d, 0x3b, 0x438, 0x44e, 0x43b, 0x3b, 0x430, 0x432, 0x433, 0x443, 0x441, 0x442, 0x3b, 0x441, 0x435, 0x43d, 0x442,
-0x44f, 0x431, 0x440, 0x3b, 0x43e, 0x43a, 0x442, 0x44f, 0x431, 0x440, 0x3b, 0x43d, 0x43e, 0x44f, 0x431, 0x440, 0x3b, 0x434, 0x435, 0x43a,
-0x430, 0x431, 0x440, 0xa5a8, 0xa595, 0x20, 0xa56a, 0xa574, 0x20, 0xa51e, 0xa500, 0xa56e, 0xa54a, 0x3b, 0xa552, 0xa561, 0xa59d, 0xa595, 0x3b, 0xa57e,
-0xa5ba, 0x3b, 0xa5a2, 0xa595, 0x3b, 0xa591, 0xa571, 0x3b, 0xa5b1, 0xa60b, 0x3b, 0xa5b1, 0xa55e, 0xa524, 0x3b, 0xa5db, 0xa515, 0x3b, 0xa562, 0xa54c,
-0x3b, 0xa56d, 0xa583, 0x3b, 0xa51e, 0xa60b, 0xa554, 0xa57f, 0x20, 0xa578, 0xa583, 0xa5cf, 0x3b, 0xa5a8, 0xa595, 0x20, 0xa56a, 0xa574, 0x20, 0xa5cf,
-0xa5ba, 0xa56e, 0xa54a, 0xa5a8, 0xa595, 0xa51e, 0x3b, 0xa552, 0xa561, 0x3b, 0xa57e, 0xa5ba, 0x3b, 0xa5a2, 0xa595, 0x3b, 0xa591, 0xa571, 0x3b, 0xa5b1,
-0xa60b, 0x3b, 0xa5b1, 0xa55e, 0x3b, 0xa5db, 0xa515, 0x3b, 0xa562, 0xa54c, 0x3b, 0xa56d, 0xa583, 0x3b, 0xa51e, 0xa60b, 0x3b, 0xa5a8, 0xa595, 0xa5cf,
-0x54, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x31, 0x3b, 0x54, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x32, 0x3b, 0x54, 0x68, 0xe1, 0x6e,
-0x67, 0x20, 0x33, 0x3b, 0x54, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x34, 0x3b, 0x54, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x35, 0x3b,
-0x54, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x36, 0x3b, 0x54, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x37, 0x3b, 0x54, 0x68, 0xe1, 0x6e,
-0x67, 0x20, 0x38, 0x3b, 0x54, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x39, 0x3b, 0x54, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x31, 0x30,
-0x3b, 0x54, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x31, 0x31, 0x3b, 0x54, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x31, 0x32, 0x74, 0x68,
-0xe1, 0x6e, 0x67, 0x20, 0x31, 0x3b, 0x74, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x32, 0x3b, 0x74, 0x68, 0xe1, 0x6e, 0x67, 0x20,
-0x33, 0x3b, 0x74, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x34, 0x3b, 0x74, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x35, 0x3b, 0x74, 0x68,
-0xe1, 0x6e, 0x67, 0x20, 0x36, 0x3b, 0x74, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x37, 0x3b, 0x74, 0x68, 0xe1, 0x6e, 0x67, 0x20,
-0x38, 0x3b, 0x74, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x39, 0x3b, 0x74, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x31, 0x30, 0x3b, 0x74,
-0x68, 0xe1, 0x6e, 0x67, 0x20, 0x31, 0x31, 0x3b, 0x74, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x31, 0x32, 0x54, 0x68, 0x67, 0x20,
-0x31, 0x3b, 0x54, 0x68, 0x67, 0x20, 0x32, 0x3b, 0x54, 0x68, 0x67, 0x20, 0x33, 0x3b, 0x54, 0x68, 0x67, 0x20, 0x34, 0x3b,
-0x54, 0x68, 0x67, 0x20, 0x35, 0x3b, 0x54, 0x68, 0x67, 0x20, 0x36, 0x3b, 0x54, 0x68, 0x67, 0x20, 0x37, 0x3b, 0x54, 0x68,
-0x67, 0x20, 0x38, 0x3b, 0x54, 0x68, 0x67, 0x20, 0x39, 0x3b, 0x54, 0x68, 0x67, 0x20, 0x31, 0x30, 0x3b, 0x54, 0x68, 0x67,
-0x20, 0x31, 0x31, 0x3b, 0x54, 0x68, 0x67, 0x20, 0x31, 0x32, 0x74, 0x68, 0x67, 0x20, 0x31, 0x3b, 0x74, 0x68, 0x67, 0x20,
-0x32, 0x3b, 0x74, 0x68, 0x67, 0x20, 0x33, 0x3b, 0x74, 0x68, 0x67, 0x20, 0x34, 0x3b, 0x74, 0x68, 0x67, 0x20, 0x35, 0x3b,
-0x74, 0x68, 0x67, 0x20, 0x36, 0x3b, 0x74, 0x68, 0x67, 0x20, 0x37, 0x3b, 0x74, 0x68, 0x67, 0x20, 0x38, 0x3b, 0x74, 0x68,
-0x67, 0x20, 0x39, 0x3b, 0x74, 0x68, 0x67, 0x20, 0x31, 0x30, 0x3b, 0x74, 0x68, 0x67, 0x20, 0x31, 0x31, 0x3b, 0x74, 0x68,
-0x67, 0x20, 0x31, 0x32, 0x4a, 0x65, 0x6e, 0x6e, 0x65, 0x72, 0x3b, 0x48, 0x6f, 0x72, 0x6e, 0x69, 0x67, 0x3b, 0x4d, 0xe4,
-0x72, 0x7a, 0x65, 0x3b, 0x41, 0x62, 0x72, 0x69, 0x6c, 0x6c, 0x65, 0x3b, 0x4d, 0x65, 0x69, 0x6a, 0x65, 0x3b, 0x42, 0x72,
-0xe1, 0x10d, 0x65, 0x74, 0x3b, 0x48, 0x65, 0x69, 0x77, 0x65, 0x74, 0x3b, 0xd6, 0x69, 0x67, 0x161, 0x74, 0x65, 0x3b, 0x48,
-0x65, 0x72, 0x62, 0x161, 0x74, 0x6d, 0xe1, 0x6e, 0x65, 0x74, 0x3b, 0x57, 0xed, 0x6d, 0xe1, 0x6e, 0x65, 0x74, 0x3b, 0x57,
-0x69, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0xe1, 0x6e, 0x65, 0x74, 0x3b, 0x43, 0x68, 0x72, 0x69, 0x161, 0x74, 0x6d, 0xe1, 0x6e,
-0x65, 0x74, 0x4a, 0x65, 0x6e, 0x3b, 0x48, 0x6f, 0x72, 0x3b, 0x4d, 0xe4, 0x72, 0x3b, 0x41, 0x62, 0x72, 0x3b, 0x4d, 0x65,
-0x69, 0x3b, 0x42, 0x72, 0xe1, 0x3b, 0x48, 0x65, 0x69, 0x3b, 0xd6, 0x69, 0x67, 0x3b, 0x48, 0x65, 0x72, 0x3b, 0x57, 0xed,
-0x6d, 0x3b, 0x57, 0x69, 0x6e, 0x3b, 0x43, 0x68, 0x72, 0x4a, 0x3b, 0x48, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x42,
-0x3b, 0x48, 0x3b, 0xd6, 0x3b, 0x48, 0x3b, 0x57, 0x3b, 0x57, 0x3b, 0x43, 0x49, 0x6f, 0x6e, 0x61, 0x77, 0x72, 0x3b, 0x43,
-0x68, 0x77, 0x65, 0x66, 0x72, 0x6f, 0x72, 0x3b, 0x4d, 0x61, 0x77, 0x72, 0x74, 0x68, 0x3b, 0x45, 0x62, 0x72, 0x69, 0x6c,
-0x6c, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4d, 0x65, 0x68, 0x65, 0x66, 0x69, 0x6e, 0x3b, 0x47, 0x6f, 0x72, 0x66, 0x66, 0x65,
-0x6e, 0x6e, 0x61, 0x66, 0x3b, 0x41, 0x77, 0x73, 0x74, 0x3b, 0x4d, 0x65, 0x64, 0x69, 0x3b, 0x48, 0x79, 0x64, 0x72, 0x65,
-0x66, 0x3b, 0x54, 0x61, 0x63, 0x68, 0x77, 0x65, 0x64, 0x64, 0x3b, 0x52, 0x68, 0x61, 0x67, 0x66, 0x79, 0x72, 0x49, 0x6f,
-0x6e, 0x3b, 0x43, 0x68, 0x77, 0x3b, 0x4d, 0x61, 0x77, 0x3b, 0x45, 0x62, 0x72, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4d, 0x65,
-0x68, 0x3b, 0x47, 0x6f, 0x72, 0x3b, 0x41, 0x77, 0x73, 0x74, 0x3b, 0x4d, 0x65, 0x64, 0x69, 0x3b, 0x48, 0x79, 0x64, 0x3b,
-0x54, 0x61, 0x63, 0x68, 0x3b, 0x52, 0x68, 0x61, 0x67, 0x49, 0x6f, 0x6e, 0x3b, 0x43, 0x68, 0x77, 0x65, 0x66, 0x3b, 0x4d,
-0x61, 0x77, 0x3b, 0x45, 0x62, 0x72, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4d, 0x65, 0x68, 0x3b, 0x47, 0x6f, 0x72, 0x66, 0x66,
-0x3b, 0x41, 0x77, 0x73, 0x74, 0x3b, 0x4d, 0x65, 0x64, 0x69, 0x3b, 0x48, 0x79, 0x64, 0x3b, 0x54, 0x61, 0x63, 0x68, 0x3b,
-0x52, 0x68, 0x61, 0x67, 0x49, 0x3b, 0x43, 0x68, 0x3b, 0x4d, 0x3b, 0x45, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x47, 0x3b, 0x41,
-0x3b, 0x4d, 0x3b, 0x48, 0x3b, 0x54, 0x3b, 0x52, 0x68, 0x4a, 0x61, 0x6e, 0x6e, 0x65, 0x77, 0x61, 0x72, 0x69, 0x73, 0x3b,
-0x46, 0x65, 0x62, 0x72, 0x65, 0x77, 0x61, 0x72, 0x69, 0x73, 0x3b, 0x4d, 0x61, 0x61, 0x72, 0x74, 0x3b, 0x41, 0x70, 0x72,
-0x69, 0x6c, 0x3b, 0x4d, 0x61, 0x61, 0x69, 0x65, 0x3b, 0x4a, 0x75, 0x6e, 0x79, 0x3b, 0x4a, 0x75, 0x6c, 0x79, 0x3b, 0x41,
-0x75, 0x67, 0x75, 0x73, 0x74, 0x75, 0x73, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x69, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b,
-0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x4e, 0x6f, 0x76, 0x69, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x44, 0x65, 0x73, 0x69, 0x6d,
-0x62, 0x65, 0x72, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x72, 0x74, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d,
-0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x75, 0x67, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f,
-0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x73, 0x53, 0x61, 0x6d, 0x77, 0x69, 0x79, 0x65, 0x65, 0x3b, 0x46,
-0x65, 0x77, 0x72, 0x69, 0x79, 0x65, 0x65, 0x3b, 0x4d, 0x61, 0x72, 0x73, 0x3b, 0x41, 0x77, 0x72, 0x69, 0x6c, 0x3b, 0x4d,
-0x65, 0x65, 0x3b, 0x53, 0x75, 0x77, 0x65, 0x3b, 0x53, 0x75, 0x6c, 0x65, 0x74, 0x3b, 0x55, 0x74, 0x3b, 0x53, 0xe0, 0x74,
-0x74, 0x75, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x3b, 0x4e, 0x6f, 0x77, 0xe0,
-0x6d, 0x62, 0x61, 0x72, 0x3b, 0x44, 0x65, 0x73, 0xe0, 0x6d, 0x62, 0x61, 0x72, 0x53, 0x61, 0x6d, 0x3b, 0x46, 0x65, 0x77,
-0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x77, 0x72, 0x3b, 0x4d, 0x65, 0x65, 0x3b, 0x53, 0x75, 0x77, 0x3b, 0x53, 0x75, 0x6c,
-0x3b, 0x55, 0x74, 0x3b, 0x53, 0xe0, 0x74, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x77, 0x3b, 0x44, 0x65, 0x73, 0x4a,
-0x61, 0x6e, 0x79, 0x75, 0x77, 0x61, 0x72, 0x69, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x77, 0x61, 0x72, 0x69, 0x3b, 0x4d,
-0x61, 0x74, 0x73, 0x68, 0x69, 0x3b, 0x45, 0x70, 0x72, 0x65, 0x6c, 0x69, 0x3b, 0x4d, 0x65, 0x79, 0x69, 0x3b, 0x4a, 0x75,
-0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x61, 0x79, 0x69, 0x3b, 0x41, 0x67, 0x61, 0x73, 0x74, 0x69, 0x3b, 0x53, 0x65, 0x70,
-0x74, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x4f, 0x6b, 0x74, 0x68, 0x6f, 0x62, 0x61, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62,
-0x61, 0x3b, 0x44, 0x69, 0x73, 0x65, 0x6d, 0x62, 0x61, 0x4a, 0x61, 0x6e, 0x79, 0x75, 0x77, 0x61, 0x72, 0x69, 0x3b, 0x46,
-0x65, 0x62, 0x72, 0x75, 0x77, 0x61, 0x72, 0x69, 0x3b, 0x4d, 0x61, 0x74, 0x73, 0x68, 0x69, 0x3b, 0x45, 0x70, 0x72, 0x65,
-0x6c, 0x69, 0x3b, 0x4d, 0x65, 0x79, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x61, 0x79, 0x69, 0x3b,
-0x41, 0x67, 0x61, 0x73, 0x74, 0x69, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x4f, 0x6b, 0x74, 0x68,
-0x6f, 0x62, 0x68, 0x61, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x44, 0x69, 0x73, 0x65, 0x6d, 0x62, 0x61,
-0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x74, 0x3b, 0x45, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x79, 0x3b,
-0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x61, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b,
-0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x69, 0x73, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x74, 0x3b, 0x45,
-0x70, 0x72, 0x3b, 0x4d, 0x65, 0x79, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x61, 0x3b, 0x53,
-0x65, 0x70, 0x74, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x69, 0x73, 0x70, 0x69, 0x6b, 0xed, 0x74,
-0xed, 0x6b, 0xed, 0x74, 0x69, 0x65, 0x2c, 0x20, 0x6f, 0xf3, 0x6c, 0xed, 0x20, 0xfa, 0x20, 0x6b, 0x75, 0x74, 0xfa, 0x61,
-0x6e, 0x3b, 0x73, 0x69, 0x25b, 0x79, 0x25b, 0x301, 0x2c, 0x20, 0x6f, 0xf3, 0x6c, 0x69, 0x20, 0xfa, 0x20, 0x6b, 0xe1, 0x6e,
-0x64, 0xed, 0x25b, 0x3b, 0x254, 0x6e, 0x73, 0xfa, 0x6d, 0x62, 0x254, 0x6c, 0x2c, 0x20, 0x6f, 0xf3, 0x6c, 0x69, 0x20, 0xfa,
-0x20, 0x6b, 0xe1, 0x74, 0xe1, 0x74, 0xfa, 0x25b, 0x3b, 0x6d, 0x65, 0x73, 0x69, 0x14b, 0x2c, 0x20, 0x6f, 0xf3, 0x6c, 0x69,
-0x20, 0xfa, 0x20, 0x6b, 0xe9, 0x6e, 0x69, 0x65, 0x3b, 0x65, 0x6e, 0x73, 0x69, 0x6c, 0x2c, 0x20, 0x6f, 0xf3, 0x6c, 0x69,
-0x20, 0xfa, 0x20, 0x6b, 0xe1, 0x74, 0xe1, 0x6e, 0x75, 0x25b, 0x3b, 0x254, 0x73, 0x254, 0x6e, 0x3b, 0x65, 0x66, 0x75, 0x74,
-0x65, 0x3b, 0x70, 0x69, 0x73, 0x75, 0x79, 0xfa, 0x3b, 0x69, 0x6d, 0x25b, 0x14b, 0x20, 0x69, 0x20, 0x70, 0x75, 0x254, 0x73,
-0x3b, 0x69, 0x6d, 0x25b, 0x14b, 0x20, 0x69, 0x20, 0x70, 0x75, 0x74, 0xfa, 0x6b, 0x2c, 0x6f, 0xf3, 0x6c, 0x69, 0x20, 0xfa,
-0x20, 0x6b, 0xe1, 0x74, 0xed, 0x25b, 0x3b, 0x6d, 0x61, 0x6b, 0x61, 0x6e, 0x64, 0x69, 0x6b, 0x25b, 0x3b, 0x70, 0x69, 0x6c,
-0x254, 0x6e, 0x64, 0x254, 0x301, 0x6f, 0x2e, 0x31, 0x3b, 0x6f, 0x2e, 0x32, 0x3b, 0x6f, 0x2e, 0x33, 0x3b, 0x6f, 0x2e, 0x34,
-0x3b, 0x6f, 0x2e, 0x35, 0x3b, 0x6f, 0x2e, 0x36, 0x3b, 0x6f, 0x2e, 0x37, 0x3b, 0x6f, 0x2e, 0x38, 0x3b, 0x6f, 0x2e, 0x39,
-0x3b, 0x6f, 0x2e, 0x31, 0x30, 0x3b, 0x6f, 0x2e, 0x31, 0x31, 0x3b, 0x6f, 0x2e, 0x31, 0x32, 0x5d9, 0x5d0, 0x5b7, 0x5e0, 0x5d5,
-0x5d0, 0x5b7, 0x5e8, 0x3b, 0x5e4, 0x5bf, 0x5e2, 0x5d1, 0x5e8, 0x5d5, 0x5d0, 0x5b7, 0x5e8, 0x3b, 0x5de, 0x5e2, 0x5e8, 0x5e5, 0x3b, 0x5d0,
-0x5b7, 0x5e4, 0x5bc, 0x5e8, 0x5d9, 0x5dc, 0x3b, 0x5de, 0x5d9, 0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5e0, 0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5dc, 0x5d9,
-0x3b, 0x5d0, 0x5d5, 0x5d9, 0x5d2, 0x5d5, 0x5e1, 0x5d8, 0x3b, 0x5e1, 0x5e2, 0x5e4, 0x5bc, 0x5d8, 0x5e2, 0x5de, 0x5d1, 0x5e2, 0x5e8, 0x3b,
-0x5d0, 0x5e7, 0x5d8, 0x5d0, 0x5d1, 0x5e2, 0x5e8, 0x3b, 0x5e0, 0x5d0, 0x5d5, 0x5d5, 0x5e2, 0x5de, 0x5d1, 0x5e2, 0x5e8, 0x3b, 0x5d3, 0x5e2,
-0x5e6, 0x5e2, 0x5de, 0x5d1, 0x5e2, 0x5e8, 0x5d9, 0x5d0, 0x5b7, 0x5e0, 0x3b, 0x5e4, 0x5bf, 0x5e2, 0x5d1, 0x3b, 0x5de, 0x5e2, 0x5e8, 0x5e5,
-0x3b, 0x5d0, 0x5b7, 0x5e4, 0x5bc, 0x5e8, 0x3b, 0x5de, 0x5d9, 0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5e0, 0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5dc, 0x5d9,
-0x3b, 0x5d0, 0x5d5, 0x5d9, 0x5d2, 0x3b, 0x5e1, 0x5e2, 0x5e4, 0x5bc, 0x3b, 0x5d0, 0x5e7, 0x5d8, 0x3b, 0x5e0, 0x5d0, 0x5d5, 0x5d5, 0x3b,
-0x5d3, 0x5e2, 0x5e6, 0x1e62, 0x1eb9, 0x301, 0x72, 0x1eb9, 0x301, 0x3b, 0xc8, 0x72, 0xe8, 0x6c, 0xe8, 0x3b, 0x1eb8, 0x72, 0x1eb9, 0x300,
-0x6e, 0xe0, 0x3b, 0xcc, 0x67, 0x62, 0xe9, 0x3b, 0x1eb8, 0x300, 0x62, 0x69, 0x62, 0x69, 0x3b, 0xd2, 0x6b, 0xfa, 0x64, 0x75,
-0x3b, 0x41, 0x67, 0x1eb9, 0x6d, 0x1ecd, 0x3b, 0xd2, 0x67, 0xfa, 0x6e, 0x3b, 0x4f, 0x77, 0x65, 0x77, 0x65, 0x3b, 0x1ecc, 0x300,
-0x77, 0xe0, 0x72, 0xe0, 0x3b, 0x42, 0xe9, 0x6c, 0xfa, 0x3b, 0x1ecc, 0x300, 0x70, 0x1eb9, 0x300, 0x4f, 0x1e63, 0xf9, 0x20, 0x1e62,
-0x1eb9, 0x301, 0x72, 0x1eb9, 0x301, 0x3b, 0x4f, 0x1e63, 0xf9, 0x20, 0xc8, 0x72, 0xe8, 0x6c, 0xe8, 0x3b, 0x4f, 0x1e63, 0xf9, 0x20,
-0x1eb8, 0x72, 0x1eb9, 0x300, 0x6e, 0xe0, 0x3b, 0x4f, 0x1e63, 0xf9, 0x20, 0xcc, 0x67, 0x62, 0xe9, 0x3b, 0x4f, 0x1e63, 0xf9, 0x20,
-0x1eb8, 0x300, 0x62, 0x69, 0x62, 0x69, 0x3b, 0x4f, 0x1e63, 0xf9, 0x20, 0xd2, 0x6b, 0xfa, 0x64, 0x75, 0x3b, 0x4f, 0x1e63, 0xf9,
-0x20, 0x41, 0x67, 0x1eb9, 0x6d, 0x1ecd, 0x3b, 0x4f, 0x1e63, 0xf9, 0x20, 0xd2, 0x67, 0xfa, 0x6e, 0x3b, 0x4f, 0x1e63, 0xf9, 0x20,
-0x4f, 0x77, 0x65, 0x77, 0x65, 0x3b, 0x4f, 0x1e63, 0xf9, 0x20, 0x1ecc, 0x300, 0x77, 0xe0, 0x72, 0xe0, 0x3b, 0x4f, 0x1e63, 0xf9,
-0x20, 0x42, 0xe9, 0x6c, 0xfa, 0x3b, 0x4f, 0x1e63, 0xf9, 0x20, 0x1ecc, 0x300, 0x70, 0x1eb9, 0x300, 0x1e62, 0x1eb9, 0x301, 0x3b, 0xc8,
-0x72, 0x3b, 0x1eb8, 0x72, 0x3b, 0xcc, 0x67, 0x3b, 0x1eb8, 0x300, 0x62, 0x3b, 0xd2, 0x6b, 0x3b, 0x41, 0x67, 0x3b, 0xd2, 0x67,
-0x3b, 0x4f, 0x77, 0x3b, 0x1ecc, 0x300, 0x77, 0x3b, 0x42, 0xe9, 0x3b, 0x1ecc, 0x300, 0x70, 0x1e62, 0x1eb9, 0x301, 0x72, 0x3b, 0xc8,
-0x72, 0xe8, 0x6c, 0x3b, 0x1eb8, 0x72, 0x1eb9, 0x300, 0x6e, 0x3b, 0xcc, 0x67, 0x62, 0x3b, 0x1eb8, 0x300, 0x62, 0x69, 0x3b, 0xd2,
-0x6b, 0xfa, 0x3b, 0x41, 0x67, 0x1eb9, 0x3b, 0xd2, 0x67, 0xfa, 0x3b, 0x4f, 0x77, 0x65, 0x3b, 0x1ecc, 0x300, 0x77, 0xe0, 0x3b,
-0x42, 0xe9, 0x6c, 0x3b, 0x1ecc, 0x300, 0x70, 0x1eb9, 0x53, 0x3b, 0xc8, 0x3b, 0x1eb8, 0x3b, 0xcc, 0x3b, 0x1eb8, 0x300, 0x3b, 0xd2,
-0x3b, 0x41, 0x3b, 0xd2, 0x3b, 0x4f, 0x3b, 0x1ecc, 0x300, 0x3b, 0x42, 0x3b, 0x1ecc, 0x300, 0x53, 0x68, 0x25b, 0x301, 0x72, 0x25b,
-0x301, 0x3b, 0xc8, 0x72, 0xe8, 0x6c, 0xe8, 0x3b, 0x190, 0x72, 0x25b, 0x300, 0x6e, 0xe0, 0x3b, 0xcc, 0x67, 0x62, 0xe9, 0x3b,
-0x190, 0x300, 0x62, 0x69, 0x62, 0x69, 0x3b, 0xd2, 0x6b, 0xfa, 0x64, 0x75, 0x3b, 0x41, 0x67, 0x25b, 0x6d, 0x254, 0x3b, 0xd2,
-0x67, 0xfa, 0x6e, 0x3b, 0x4f, 0x77, 0x65, 0x77, 0x65, 0x3b, 0x186, 0x300, 0x77, 0xe0, 0x72, 0xe0, 0x3b, 0x42, 0xe9, 0x6c,
-0xfa, 0x3b, 0x186, 0x300, 0x70, 0x25b, 0x300, 0x4f, 0x73, 0x68, 0xf9, 0x20, 0x53, 0x68, 0x25b, 0x301, 0x72, 0x25b, 0x301, 0x3b,
-0x4f, 0x73, 0x68, 0xf9, 0x20, 0xc8, 0x72, 0xe8, 0x6c, 0xe8, 0x3b, 0x4f, 0x73, 0x68, 0xf9, 0x20, 0x190, 0x72, 0x25b, 0x300,
-0x6e, 0xe0, 0x3b, 0x4f, 0x73, 0x68, 0xf9, 0x20, 0xcc, 0x67, 0x62, 0xe9, 0x3b, 0x4f, 0x73, 0x68, 0xf9, 0x20, 0x190, 0x300,
-0x62, 0x69, 0x62, 0x69, 0x3b, 0x4f, 0x73, 0x68, 0xf9, 0x20, 0xd2, 0x6b, 0xfa, 0x64, 0x75, 0x3b, 0x4f, 0x73, 0x68, 0xf9,
-0x20, 0x41, 0x67, 0x25b, 0x6d, 0x254, 0x3b, 0x4f, 0x73, 0x68, 0xf9, 0x20, 0xd2, 0x67, 0xfa, 0x6e, 0x3b, 0x4f, 0x73, 0x68,
-0xf9, 0x20, 0x4f, 0x77, 0x65, 0x77, 0x65, 0x3b, 0x4f, 0x73, 0x68, 0xf9, 0x20, 0x186, 0x300, 0x77, 0xe0, 0x72, 0xe0, 0x3b,
-0x4f, 0x73, 0x68, 0xf9, 0x20, 0x42, 0xe9, 0x6c, 0xfa, 0x3b, 0x4f, 0x73, 0x68, 0xf9, 0x20, 0x186, 0x300, 0x70, 0x25b, 0x300,
-0x53, 0x68, 0x25b, 0x301, 0x3b, 0xc8, 0x72, 0x3b, 0x190, 0x72, 0x3b, 0xcc, 0x67, 0x3b, 0x190, 0x300, 0x62, 0x3b, 0xd2, 0x6b,
-0x3b, 0x41, 0x67, 0x3b, 0xd2, 0x67, 0x3b, 0x4f, 0x77, 0x3b, 0x186, 0x300, 0x77, 0x3b, 0x42, 0xe9, 0x3b, 0x186, 0x300, 0x70,
-0x53, 0x68, 0x25b, 0x301, 0x72, 0x3b, 0xc8, 0x72, 0xe8, 0x6c, 0x3b, 0x190, 0x72, 0x25b, 0x300, 0x6e, 0x3b, 0xcc, 0x67, 0x62,
-0x3b, 0x190, 0x300, 0x62, 0x69, 0x3b, 0xd2, 0x6b, 0xfa, 0x3b, 0x41, 0x67, 0x25b, 0x3b, 0xd2, 0x67, 0xfa, 0x3b, 0x4f, 0x77,
-0x65, 0x3b, 0x186, 0x300, 0x77, 0xe0, 0x3b, 0x42, 0xe9, 0x6c, 0x3b, 0x186, 0x300, 0x70, 0x25b, 0x53, 0x3b, 0xc8, 0x3b, 0x190,
-0x3b, 0xcc, 0x3b, 0x190, 0x300, 0x3b, 0xd2, 0x3b, 0x41, 0x3b, 0xd2, 0x3b, 0x4f, 0x3b, 0x186, 0x300, 0x3b, 0x42, 0x3b, 0x186,
-0x300, 0x4a, 0x61, 0x6e, 0x75, 0x77, 0x61, 0x72, 0x69, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x77, 0x61, 0x72, 0x69, 0x3b,
-0x4d, 0x61, 0x73, 0x68, 0x69, 0x3b, 0x45, 0x70, 0x68, 0x72, 0x65, 0x6c, 0x69, 0x3b, 0x4d, 0x65, 0x79, 0x69, 0x3b, 0x4a,
-0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x61, 0x79, 0x69, 0x3b, 0x41, 0x67, 0x61, 0x73, 0x74, 0x69, 0x3b, 0x53, 0x65,
-0x70, 0x74, 0x68, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x4f, 0x6b, 0x74, 0x68, 0x6f, 0x62, 0x61, 0x3b, 0x4e, 0x6f, 0x76, 0x65,
-0x6d, 0x62, 0x61, 0x3b, 0x44, 0x69, 0x73, 0x65, 0x6d, 0x62, 0x61, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d,
-0x61, 0x73, 0x3b, 0x45, 0x70, 0x68, 0x3b, 0x4d, 0x65, 0x79, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41,
-0x67, 0x61, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x69, 0x73, 0x4a, 0x3b,
-0x46, 0x3b, 0x4d, 0x3b, 0x45, 0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b,
-0x44, 0x31, 0x2d, 0x4b, 0x79, 0x73, 0xe3, 0x3b, 0x32, 0x2d, 0x4b, 0x79, 0x73, 0xe3, 0x3b, 0x33, 0x2d, 0x4b, 0x79, 0x73,
-0xe3, 0x3b, 0x34, 0x2d, 0x4b, 0x79, 0x73, 0xe3, 0x3b, 0x35, 0x2d, 0x4b, 0x79, 0x73, 0xe3, 0x3b, 0x36, 0x2d, 0x4b, 0x79,
-0x73, 0xe3, 0x3b, 0x37, 0x2d, 0x4b, 0x79, 0x73, 0xe3, 0x3b, 0x38, 0x2d, 0x4b, 0x79, 0x73, 0xe3, 0x3b, 0x39, 0x2d, 0x4b,
-0x79, 0x73, 0xe3, 0x3b, 0x31, 0x30, 0x2d, 0x4b, 0x79, 0x73, 0xe3, 0x3b, 0x31, 0x31, 0x2d, 0x4b, 0x79, 0x73, 0xe3, 0x3b,
-0x31, 0x32, 0x2d, 0x4b, 0x79, 0x73, 0xe3, 0x31, 0x4b, 0x79, 0x2e, 0x3b, 0x32, 0x4b, 0x79, 0x2e, 0x3b, 0x33, 0x4b, 0x79,
-0x2e, 0x3b, 0x34, 0x4b, 0x79, 0x2e, 0x3b, 0x35, 0x4b, 0x79, 0x2e, 0x3b, 0x36, 0x4b, 0x79, 0x2e, 0x3b, 0x37, 0x4b, 0x79,
-0x2e, 0x3b, 0x38, 0x4b, 0x79, 0x2e, 0x3b, 0x39, 0x4b, 0x79, 0x2e, 0x3b, 0x31, 0x30, 0x4b, 0x79, 0x2e, 0x3b, 0x31, 0x31,
-0x4b, 0x79, 0x2e, 0x3b, 0x31, 0x32, 0x4b, 0x79, 0x2e, 0x31, 0x4b, 0x3b, 0x32, 0x4b, 0x3b, 0x33, 0x4b, 0x3b, 0x34, 0x4b,
-0x3b, 0x35, 0x4b, 0x3b, 0x36, 0x4b, 0x3b, 0x37, 0x4b, 0x3b, 0x38, 0x4b, 0x3b, 0x39, 0x4b, 0x3b, 0x31, 0x30, 0x4b, 0x3b,
-0x31, 0x31, 0x4b, 0x3b, 0x31, 0x32, 0x4b, 0x79, 0x65, 0x70, 0xe9, 0x3b, 0x6d, 0x75, 0x6b, 0x169, 0x69, 0x3b, 0x6d, 0x75,
-0x73, 0x61, 0x70, 0xed, 0x72, 0x69, 0x3b, 0x69, 0x72, 0x169, 0x64, 0xed, 0x3b, 0x70, 0xfa, 0x3b, 0x70, 0xfa, 0x2d, 0x79,
-0x65, 0x70, 0xe9, 0x3b, 0x70, 0xfa, 0x2d, 0x6d, 0x75, 0x6b, 0x169, 0x69, 0x3b, 0x70, 0xfa, 0x2d, 0x6d, 0x75, 0x73, 0x61,
-0x70, 0xed, 0x72, 0x69, 0x3b, 0x70, 0xfa, 0x2d, 0x69, 0x72, 0x169, 0x64, 0xed, 0x3b, 0x79, 0x65, 0x70, 0xe9, 0x2d, 0x70,
-0x75, 0x74, 0x69, 0x6d, 0x61, 0xe3, 0x3b, 0x79, 0x65, 0x70, 0xe9, 0x2d, 0x79, 0x65, 0x70, 0xe9, 0x3b, 0x79, 0x65, 0x70,
-0xe9, 0x2d, 0x6d, 0x75, 0x6b, 0x169, 0x69, 0x79, 0x65, 0x3b, 0x6d, 0x6b, 0x3b, 0x6d, 0x73, 0x3b, 0x69, 0x64, 0x3b, 0x70,
-0x75, 0x3b, 0x70, 0x79, 0x3b, 0x70, 0x6d, 0x3b, 0x70, 0x73, 0x3b, 0x70, 0x69, 0x3b, 0x79, 0x70, 0x3b, 0x79, 0x79, 0x3b,
-0x79, 0x6d, 0x59, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x49, 0x3b, 0x50, 0x3b, 0x50, 0x3b, 0x50, 0x3b, 0x50, 0x3b, 0x50, 0x3b,
-0x59, 0x3b, 0x59, 0x3b, 0x59, 0x91c, 0x928, 0x935, 0x930, 0x940, 0x3b, 0x92b, 0x930, 0x935, 0x930, 0x940, 0x3b, 0x92e, 0x93e, 0x930,
-0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x948, 0x932, 0x3b, 0x92e, 0x908, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932,
-0x93e, 0x908, 0x3b, 0x905, 0x917, 0x938, 0x94d, 0x924, 0x3b, 0x938, 0x93f, 0x924, 0x92e, 0x94d, 0x92c, 0x930, 0x3b, 0x905, 0x915, 0x94d,
-0x91f, 0x942, 0x92c, 0x930, 0x3b, 0x928, 0x935, 0x92e, 0x94d, 0x92c, 0x930, 0x3b, 0x926, 0x93f, 0x938, 0x902, 0x92c, 0x930, 0x4a, 0x61,
-0x6e, 0x65, 0x77, 0x6f, 0x6f, 0x72, 0x65, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x65, 0x77, 0x6f, 0x6f, 0x72, 0x65, 0x3b, 0x4d,
-0x61, 0x61, 0x72, 0x74, 0x73, 0x3b, 0x41, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a, 0xfc, 0xfc, 0x6e,
-0x65, 0x3b, 0x4a, 0xfc, 0xfc, 0x6c, 0x65, 0x3b, 0x41, 0x75, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65,
-0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x75, 0x75, 0x62, 0x65, 0x72, 0x3b, 0x4e, 0x6f, 0x66, 0x65, 0x6d, 0x62,
-0x65, 0x72, 0x3b, 0x44, 0x65, 0x74, 0x73, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b,
-0x4d, 0x61, 0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a, 0xfc, 0x6e, 0x3b, 0x4a, 0xfc, 0x6c, 0x3b,
-0x41, 0x75, 0x67, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x66, 0x3b, 0x44, 0x65, 0x74, 0x4a,
-0x61, 0x6e, 0x75, 0x61, 0x72, 0x65, 0x3b, 0x46, 0x65, 0x62, 0x75, 0x61, 0x72, 0x65, 0x3b, 0x4d, 0x61, 0x73, 0x3b, 0x45,
-0x70, 0x72, 0x65, 0x6c, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x61, 0x65, 0x3b, 0x4f,
-0x67, 0x75, 0x73, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x61, 0x3b,
-0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x44, 0x69, 0x73, 0x65, 0x6d, 0x62, 0x61
+0x4a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x79, 0x3b, 0x46, 0x65, 0x62, 0x72,
+0x75, 0x61, 0x72, 0x79, 0x3b, 0x4d, 0x61, 0x72, 0x63, 0x68, 0x3b, 0x41,
+0x70, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x4a, 0x75, 0x6e,
+0x65, 0x3b, 0x4a, 0x75, 0x6c, 0x79, 0x3b, 0x41, 0x75, 0x67, 0x75, 0x73,
+0x74, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b,
+0x4f, 0x63, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x4e, 0x6f, 0x76, 0x65,
+0x6d, 0x62, 0x65, 0x72, 0x3b, 0x44, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x65,
+0x72, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72,
+0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x4a, 0x75, 0x6e,
+0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x75, 0x67, 0x3b, 0x53, 0x65, 0x70,
+0x3b, 0x4f, 0x63, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x63,
+0x4a, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4a, 0x3b,
+0x4a, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x31,
+0x3b, 0x32, 0x3b, 0x33, 0x3b, 0x34, 0x3b, 0x35, 0x3b, 0x36, 0x3b, 0x37,
+0x3b, 0x38, 0x3b, 0x39, 0x3b, 0x31, 0x30, 0x3b, 0x31, 0x31, 0x3b, 0x31,
+0x32, 0x410, 0x436, 0x44c, 0x44b, 0x440, 0x43d, 0x44b, 0x4b3, 0x259, 0x430, 0x3b,
+0x416, 0x259, 0x430, 0x431, 0x440, 0x430, 0x43d, 0x3b, 0x425, 0x259, 0x430, 0x436,
+0x259, 0x43a, 0x44b, 0x440, 0x430, 0x3b, 0x41c, 0x448, 0x430, 0x525, 0x44b, 0x3b,
+0x41b, 0x430, 0x4b5, 0x430, 0x440, 0x430, 0x3b, 0x420, 0x430, 0x448, 0x259, 0x430,
+0x440, 0x430, 0x3b, 0x524, 0x445, 0x44b, 0x43d, 0x433, 0x259, 0x44b, 0x3b, 0x41d,
+0x430, 0x43d, 0x4b3, 0x259, 0x430, 0x3b, 0x426, 0x259, 0x44b, 0x431, 0x431, 0x440,
+0x430, 0x3b, 0x416, 0x44c, 0x4ad, 0x430, 0x430, 0x440, 0x430, 0x3b, 0x410, 0x431,
+0x4b5, 0x430, 0x440, 0x430, 0x3b, 0x524, 0x445, 0x44b, 0x43d, 0x4b7, 0x43a, 0x4d9,
+0x44b, 0x43d, 0x410, 0x436, 0x44c, 0x3b, 0x416, 0x259, 0x430, 0x431, 0x3b, 0x425,
+0x259, 0x430, 0x436, 0x4d9, 0x3b, 0x41c, 0x448, 0x3b, 0x41b, 0x430, 0x4b5, 0x3b,
+0x420, 0x430, 0x448, 0x4d9, 0x3b, 0x524, 0x445, 0x44b, 0x43d, 0x433, 0x4d9, 0x3b,
+0x41d, 0x430, 0x43d, 0x4b3, 0x4d9, 0x3b, 0x426, 0x259, 0x44b, 0x431, 0x3b, 0x416,
+0x44c, 0x4ad, 0x3b, 0x410, 0x431, 0x4b5, 0x3b, 0x524, 0x445, 0x44b, 0x43d, 0x4b7,
+0x416, 0x44c, 0x3b, 0x416, 0x259, 0x3b, 0x425, 0x259, 0x3b, 0x41c, 0x3b, 0x41b,
+0x3b, 0x420, 0x3b, 0x413, 0x4d9, 0x3b, 0x41d, 0x3b, 0x426, 0x4d9, 0x3b, 0x4ac,
+0x3b, 0x411, 0x3b, 0x4b6, 0x416, 0x44c, 0x3b, 0x416, 0x259, 0x3b, 0x425, 0x259,
+0x3b, 0x41c, 0x3b, 0x41b, 0x3b, 0x420, 0x3b, 0x413, 0x4d9, 0x3b, 0x41d, 0x3b,
+0x426, 0x259, 0x3b, 0x4ac, 0x3b, 0x411, 0x3b, 0x4b6, 0x51, 0x75, 0x6e, 0x78,
+0x61, 0x20, 0x47, 0x61, 0x72, 0x61, 0x62, 0x6c, 0x75, 0x3b, 0x4b, 0x75,
+0x64, 0x6f, 0x3b, 0x43, 0x69, 0x67, 0x67, 0x69, 0x6c, 0x74, 0x61, 0x20,
+0x4b, 0x75, 0x64, 0x6f, 0x3b, 0x41, 0x67, 0x64, 0x61, 0x20, 0x42, 0x61,
+0x78, 0x69, 0x73, 0x3b, 0x43, 0x61, 0x78, 0x61, 0x68, 0x20, 0x41, 0x6c,
+0x73, 0x61, 0x3b, 0x51, 0x61, 0x73, 0x61, 0x20, 0x44, 0x69, 0x72, 0x72,
+0x69, 0x3b, 0x51, 0x61, 0x64, 0x6f, 0x20, 0x44, 0x69, 0x72, 0x72, 0x69,
+0x3b, 0x4c, 0x69, 0x69, 0x71, 0x65, 0x6e, 0x3b, 0x57, 0x61, 0x79, 0x73,
+0x75, 0x3b, 0x44, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x3b, 0x58, 0x69, 0x6d,
+0x6f, 0x6c, 0x69, 0x3b, 0x4b, 0x61, 0x78, 0x78, 0x61, 0x20, 0x47, 0x61,
+0x72, 0x61, 0x62, 0x6c, 0x75, 0x51, 0x75, 0x6e, 0x3b, 0x4e, 0x61, 0x68,
+0x3b, 0x43, 0x69, 0x67, 0x3b, 0x41, 0x67, 0x64, 0x3b, 0x43, 0x61, 0x78,
+0x3b, 0x51, 0x61, 0x73, 0x3b, 0x51, 0x61, 0x64, 0x3b, 0x4c, 0x65, 0x71,
+0x3b, 0x57, 0x61, 0x79, 0x3b, 0x44, 0x69, 0x74, 0x3b, 0x58, 0x69, 0x6d,
+0x3b, 0x4b, 0x61, 0x78, 0x51, 0x3b, 0x4e, 0x3b, 0x43, 0x3b, 0x41, 0x3b,
+0x43, 0x3b, 0x51, 0x3b, 0x51, 0x3b, 0x4c, 0x3b, 0x57, 0x3b, 0x44, 0x3b,
+0x58, 0x3b, 0x4b, 0x51, 0x75, 0x6e, 0x78, 0x61, 0x20, 0x47, 0x61, 0x72,
+0x61, 0x62, 0x6c, 0x75, 0x3b, 0x4b, 0x75, 0x64, 0x6f, 0x3b, 0x43, 0x69,
+0x67, 0x67, 0x69, 0x6c, 0x74, 0x61, 0x20, 0x4b, 0x75, 0x64, 0x6f, 0x3b,
+0x41, 0x67, 0x64, 0x61, 0x20, 0x42, 0x61, 0x78, 0x69, 0x73, 0x3b, 0x43,
+0x61, 0x78, 0x61, 0x68, 0x20, 0x41, 0x6c, 0x73, 0x61, 0x3b, 0x51, 0x61,
+0x73, 0x61, 0x20, 0x44, 0x69, 0x72, 0x72, 0x69, 0x3b, 0x51, 0x61, 0x64,
+0x6f, 0x20, 0x44, 0x69, 0x72, 0x72, 0x69, 0x3b, 0x4c, 0x65, 0x71, 0x65,
+0x65, 0x6e, 0x69, 0x3b, 0x57, 0x61, 0x79, 0x73, 0x75, 0x3b, 0x44, 0x69,
+0x74, 0x65, 0x6c, 0x69, 0x3b, 0x58, 0x69, 0x6d, 0x6f, 0x6c, 0x69, 0x3b,
+0x4b, 0x61, 0x78, 0x78, 0x61, 0x20, 0x47, 0x61, 0x72, 0x61, 0x62, 0x6c,
+0x75, 0x4a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x69, 0x65, 0x3b, 0x46, 0x65,
+0x62, 0x72, 0x75, 0x61, 0x72, 0x69, 0x65, 0x3b, 0x4d, 0x61, 0x61, 0x72,
+0x74, 0x3b, 0x41, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x65, 0x69, 0x3b,
+0x4a, 0x75, 0x6e, 0x69, 0x65, 0x3b, 0x4a, 0x75, 0x6c, 0x69, 0x65, 0x3b,
+0x41, 0x75, 0x67, 0x75, 0x73, 0x74, 0x75, 0x73, 0x3b, 0x53, 0x65, 0x70,
+0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62,
+0x65, 0x72, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b,
+0x44, 0x65, 0x73, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4a, 0x61, 0x6e, 0x2e,
+0x3b, 0x46, 0x65, 0x62, 0x2e, 0x3b, 0x4d, 0x72, 0x74, 0x2e, 0x3b, 0x41,
+0x70, 0x72, 0x2e, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x2e,
+0x3b, 0x4a, 0x75, 0x6c, 0x2e, 0x3b, 0x41, 0x75, 0x67, 0x2e, 0x3b, 0x53,
+0x65, 0x70, 0x2e, 0x3b, 0x4f, 0x6b, 0x74, 0x2e, 0x3b, 0x4e, 0x6f, 0x76,
+0x2e, 0x3b, 0x44, 0x65, 0x73, 0x2e, 0x6e, 0x64, 0x7a, 0x254, 0x300, 0x14b,
+0x254, 0x300, 0x6e, 0xf9, 0x6d, 0x3b, 0x6e, 0x64, 0x7a, 0x254, 0x300, 0x14b,
+0x254, 0x300, 0x6b, 0x197, 0x300, 0x7a, 0xf9, 0x294, 0x3b, 0x6e, 0x64, 0x7a,
+0x254, 0x300, 0x14b, 0x254, 0x300, 0x74, 0x197, 0x300, 0x64, 0x289, 0x300, 0x67,
+0x68, 0xe0, 0x3b, 0x6e, 0x64, 0x7a, 0x254, 0x300, 0x14b, 0x254, 0x300, 0x74,
+0x1ce, 0x61, 0x66, 0x289, 0x304, 0x67, 0x68, 0x101, 0x3b, 0x6e, 0x64, 0x7a,
+0x254, 0x300, 0x14b, 0xe8, 0x73, 0xe8, 0x65, 0x3b, 0x6e, 0x64, 0x7a, 0x254,
+0x300, 0x14b, 0x254, 0x300, 0x6e, 0x7a, 0xf9, 0x67, 0x68, 0xf2, 0x3b, 0x6e,
+0x64, 0x7a, 0x254, 0x300, 0x14b, 0x254, 0x300, 0x64, 0xf9, 0x6d, 0x6c, 0x6f,
+0x3b, 0x6e, 0x64, 0x7a, 0x254, 0x300, 0x14b, 0x254, 0x300, 0x6b, 0x77, 0xee,
+0x66, 0x254, 0x300, 0x65, 0x3b, 0x6e, 0x64, 0x7a, 0x254, 0x300, 0x14b, 0x254,
+0x300, 0x74, 0x197, 0x300, 0x66, 0x289, 0x300, 0x67, 0x68, 0xe0, 0x64, 0x7a,
+0x75, 0x67, 0x68, 0xf9, 0x3b, 0x6e, 0x64, 0x7a, 0x254, 0x300, 0x14b, 0x254,
+0x300, 0x67, 0x68, 0x1d4, 0x75, 0x77, 0x65, 0x6c, 0x254, 0x300, 0x6d, 0x3b,
+0x6e, 0x64, 0x7a, 0x254, 0x300, 0x14b, 0x254, 0x300, 0x63, 0x68, 0x77, 0x61,
+0x294, 0xe0, 0x6b, 0x61, 0x61, 0x20, 0x77, 0x6f, 0x3b, 0x6e, 0x64, 0x7a,
+0x254, 0x300, 0x14b, 0xe8, 0x66, 0x77, 0xf2, 0x6f, 0x6e, 0xf9, 0x6d, 0x3b,
+0x6b, 0x268, 0x7a, 0x3b, 0x74, 0x268, 0x64, 0x3b, 0x74, 0x61, 0x61, 0x3b,
+0x73, 0x65, 0x65, 0x3b, 0x6e, 0x7a, 0x75, 0x3b, 0x64, 0x75, 0x6d, 0x3b,
+0x66, 0x254, 0x65, 0x3b, 0x64, 0x7a, 0x75, 0x3b, 0x6c, 0x254, 0x6d, 0x3b,
+0x6b, 0x61, 0x61, 0x3b, 0x66, 0x77, 0x6f, 0x6e, 0x3b, 0x6b, 0x3b, 0x74,
+0x3b, 0x74, 0x3b, 0x73, 0x3b, 0x7a, 0x3b, 0x6b, 0x3b, 0x66, 0x3b, 0x64,
+0x3b, 0x6c, 0x3b, 0x63, 0x3b, 0x66, 0x53, 0x61, 0x6e, 0x64, 0x61, 0x2d,
+0x186, 0x70, 0x25b, 0x70, 0x254, 0x6e, 0x3b, 0x4b, 0x77, 0x61, 0x6b, 0x77,
+0x61, 0x72, 0x2d, 0x186, 0x67, 0x79, 0x65, 0x66, 0x75, 0x6f, 0x3b, 0x45,
+0x62, 0x254, 0x77, 0x2d, 0x186, 0x62, 0x65, 0x6e, 0x65, 0x6d, 0x3b, 0x45,
+0x62, 0x254, 0x62, 0x69, 0x72, 0x61, 0x2d, 0x4f, 0x66, 0x6f, 0x72, 0x69,
+0x73, 0x75, 0x6f, 0x3b, 0x45, 0x73, 0x75, 0x73, 0x6f, 0x77, 0x20, 0x41,
+0x6b, 0x65, 0x74, 0x73, 0x65, 0x61, 0x62, 0x61, 0x2d, 0x4b, 0x254, 0x74,
+0x254, 0x6e, 0x69, 0x6d, 0x62, 0x61, 0x3b, 0x4f, 0x62, 0x69, 0x72, 0x61,
+0x64, 0x65, 0x2d, 0x41, 0x79, 0x25b, 0x77, 0x6f, 0x68, 0x6f, 0x6d, 0x75,
+0x6d, 0x75, 0x3b, 0x41, 0x79, 0x25b, 0x77, 0x6f, 0x68, 0x6f, 0x2d, 0x4b,
+0x69, 0x74, 0x61, 0x77, 0x6f, 0x6e, 0x73, 0x61, 0x3b, 0x44, 0x69, 0x66,
+0x75, 0x75, 0x2d, 0x186, 0x73, 0x61, 0x6e, 0x64, 0x61, 0x61, 0x3b, 0x46,
+0x61, 0x6e, 0x6b, 0x77, 0x61, 0x2d, 0x190, 0x62, 0x254, 0x3b, 0x186, 0x62,
+0x25b, 0x73, 0x25b, 0x2d, 0x41, 0x68, 0x69, 0x6e, 0x69, 0x6d, 0x65, 0x3b,
+0x186, 0x62, 0x65, 0x72, 0x25b, 0x66, 0x25b, 0x77, 0x2d, 0x4f, 0x62, 0x75,
+0x62, 0x75, 0x6f, 0x3b, 0x4d, 0x75, 0x6d, 0x75, 0x2d, 0x186, 0x70, 0x25b,
+0x6e, 0x69, 0x6d, 0x62, 0x61, 0x53, 0x2d, 0x186, 0x3b, 0x4b, 0x2d, 0x186,
+0x3b, 0x45, 0x2d, 0x186, 0x3b, 0x45, 0x2d, 0x4f, 0x3b, 0x45, 0x2d, 0x4b,
+0x3b, 0x4f, 0x2d, 0x41, 0x3b, 0x41, 0x2d, 0x4b, 0x3b, 0x44, 0x2d, 0x186,
+0x3b, 0x46, 0x2d, 0x190, 0x3b, 0x186, 0x2d, 0x41, 0x3b, 0x186, 0x2d, 0x4f,
+0x3b, 0x4d, 0x2d, 0x186, 0x4d, 0x30, 0x31, 0x3b, 0x4d, 0x30, 0x32, 0x3b,
+0x4d, 0x30, 0x33, 0x3b, 0x4d, 0x30, 0x34, 0x3b, 0x4d, 0x30, 0x35, 0x3b,
+0x4d, 0x30, 0x36, 0x3b, 0x4d, 0x30, 0x37, 0x3b, 0x4d, 0x30, 0x38, 0x3b,
+0x4d, 0x30, 0x39, 0x3b, 0x4d, 0x31, 0x30, 0x3b, 0x4d, 0x31, 0x31, 0x3b,
+0x4d, 0x31, 0x32, 0x6a, 0x61, 0x6e, 0x61, 0x72, 0x3b, 0x73, 0x68, 0x6b,
+0x75, 0x72, 0x74, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x3b, 0x70, 0x72, 0x69,
+0x6c, 0x6c, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x71, 0x65, 0x72, 0x73, 0x68,
+0x6f, 0x72, 0x3b, 0x6b, 0x6f, 0x72, 0x72, 0x69, 0x6b, 0x3b, 0x67, 0x75,
+0x73, 0x68, 0x74, 0x3b, 0x73, 0x68, 0x74, 0x61, 0x74, 0x6f, 0x72, 0x3b,
+0x74, 0x65, 0x74, 0x6f, 0x72, 0x3b, 0x6e, 0xeb, 0x6e, 0x74, 0x6f, 0x72,
+0x3b, 0x64, 0x68, 0x6a, 0x65, 0x74, 0x6f, 0x72, 0x6a, 0x61, 0x6e, 0x3b,
+0x73, 0x68, 0x6b, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x70, 0x72, 0x69, 0x3b,
+0x6d, 0x61, 0x6a, 0x3b, 0x71, 0x65, 0x72, 0x3b, 0x6b, 0x6f, 0x72, 0x72,
+0x3b, 0x67, 0x75, 0x73, 0x68, 0x3b, 0x73, 0x68, 0x74, 0x3b, 0x74, 0x65,
+0x74, 0x3b, 0x6e, 0xeb, 0x6e, 0x3b, 0x64, 0x68, 0x6a, 0x6a, 0x3b, 0x73,
+0x68, 0x3b, 0x6d, 0x3b, 0x70, 0x3b, 0x6d, 0x3b, 0x71, 0x3b, 0x6b, 0x3b,
+0x67, 0x3b, 0x73, 0x68, 0x3b, 0x74, 0x3b, 0x6e, 0x3b, 0x64, 0x68, 0x1303,
+0x1295, 0x12cb, 0x122a, 0x3b, 0x134c, 0x1265, 0x1229, 0x12cb, 0x122a, 0x3b, 0x121b, 0x122d,
+0x127d, 0x3b, 0x12a4, 0x1355, 0x122a, 0x120d, 0x3b, 0x121c, 0x12ed, 0x3b, 0x1301, 0x1295,
+0x3b, 0x1301, 0x120b, 0x12ed, 0x3b, 0x12a6, 0x1308, 0x1235, 0x1275, 0x3b, 0x1234, 0x1355,
+0x1274, 0x121d, 0x1260, 0x122d, 0x3b, 0x12a6, 0x12ad, 0x1276, 0x1260, 0x122d, 0x3b, 0x1296,
+0x126c, 0x121d, 0x1260, 0x122d, 0x3b, 0x12f2, 0x1234, 0x121d, 0x1260, 0x122d, 0x1303, 0x1295,
+0x3b, 0x134c, 0x1265, 0x3b, 0x121b, 0x122d, 0x127d, 0x3b, 0x12a4, 0x1355, 0x122a, 0x3b,
+0x121c, 0x12ed, 0x3b, 0x1301, 0x1295, 0x3b, 0x1301, 0x120b, 0x12ed, 0x3b, 0x12a6, 0x1308,
+0x1235, 0x3b, 0x1234, 0x1355, 0x1274, 0x3b, 0x12a6, 0x12ad, 0x1276, 0x3b, 0x1296, 0x126c,
+0x121d, 0x3b, 0x12f2, 0x1234, 0x121d, 0x1303, 0x3b, 0x134c, 0x3b, 0x121b, 0x3b, 0x12a4,
+0x3b, 0x121c, 0x3b, 0x1301, 0x3b, 0x1301, 0x3b, 0x12a6, 0x3b, 0x1234, 0x3b, 0x12a6,
+0x3b, 0x1296, 0x3b, 0x12f2, 0x64a, 0x646, 0x627, 0x64a, 0x631, 0x3b, 0x641, 0x628,
+0x631, 0x627, 0x64a, 0x631, 0x3b, 0x645, 0x627, 0x631, 0x633, 0x3b, 0x623, 0x628,
+0x631, 0x64a, 0x644, 0x3b, 0x645, 0x627, 0x64a, 0x648, 0x3b, 0x64a, 0x648, 0x646,
+0x64a, 0x648, 0x3b, 0x64a, 0x648, 0x644, 0x64a, 0x648, 0x3b, 0x623, 0x63a, 0x633,
+0x637, 0x633, 0x3b, 0x633, 0x628, 0x62a, 0x645, 0x628, 0x631, 0x3b, 0x623, 0x643,
+0x62a, 0x648, 0x628, 0x631, 0x3b, 0x646, 0x648, 0x641, 0x645, 0x628, 0x631, 0x3b,
+0x62f, 0x64a, 0x633, 0x645, 0x628, 0x631, 0x64a, 0x3b, 0x641, 0x3b, 0x645, 0x3b,
+0x623, 0x3b, 0x648, 0x3b, 0x646, 0x3b, 0x644, 0x3b, 0x63a, 0x3b, 0x633, 0x3b,
+0x643, 0x3b, 0x628, 0x3b, 0x62f, 0x62c, 0x627, 0x646, 0x641, 0x64a, 0x3b, 0x641,
+0x64a, 0x641, 0x631, 0x64a, 0x3b, 0x645, 0x627, 0x631, 0x633, 0x3b, 0x623, 0x641,
+0x631, 0x64a, 0x644, 0x3b, 0x645, 0x627, 0x64a, 0x3b, 0x62c, 0x648, 0x627, 0x646,
+0x3b, 0x62c, 0x648, 0x64a, 0x644, 0x64a, 0x629, 0x3b, 0x623, 0x648, 0x62a, 0x3b,
+0x633, 0x628, 0x62a, 0x645, 0x628, 0x631, 0x3b, 0x623, 0x643, 0x62a, 0x648, 0x628,
+0x631, 0x3b, 0x646, 0x648, 0x641, 0x645, 0x628, 0x631, 0x3b, 0x62f, 0x64a, 0x633,
+0x645, 0x628, 0x631, 0x62c, 0x3b, 0x641, 0x3b, 0x645, 0x3b, 0x623, 0x3b, 0x645,
+0x3b, 0x62c, 0x3b, 0x62c, 0x3b, 0x623, 0x3b, 0x633, 0x3b, 0x623, 0x3b, 0x646,
+0x3b, 0x62f, 0x643, 0x627, 0x646, 0x648, 0x646, 0x20, 0x627, 0x644, 0x62b, 0x627,
+0x646, 0x64a, 0x3b, 0x634, 0x628, 0x627, 0x637, 0x3b, 0x622, 0x630, 0x627, 0x631,
+0x3b, 0x646, 0x64a, 0x633, 0x627, 0x646, 0x3b, 0x623, 0x64a, 0x627, 0x631, 0x3b,
+0x62d, 0x632, 0x64a, 0x631, 0x627, 0x646, 0x3b, 0x62a, 0x645, 0x648, 0x632, 0x3b,
+0x622, 0x628, 0x3b, 0x623, 0x64a, 0x644, 0x648, 0x644, 0x3b, 0x62a, 0x634, 0x631,
+0x64a, 0x646, 0x20, 0x627, 0x644, 0x623, 0x648, 0x644, 0x3b, 0x62a, 0x634, 0x631,
+0x64a, 0x646, 0x20, 0x627, 0x644, 0x62b, 0x627, 0x646, 0x64a, 0x3b, 0x643, 0x627,
+0x646, 0x648, 0x646, 0x20, 0x627, 0x644, 0x623, 0x648, 0x644, 0x643, 0x627, 0x646,
+0x648, 0x646, 0x20, 0x627, 0x644, 0x62b, 0x627, 0x646, 0x64a, 0x3b, 0x634, 0x628,
+0x627, 0x637, 0x3b, 0x622, 0x630, 0x627, 0x631, 0x3b, 0x646, 0x64a, 0x633, 0x627,
+0x646, 0x3b, 0x623, 0x64a, 0x627, 0x631, 0x3b, 0x62d, 0x632, 0x64a, 0x631, 0x627,
+0x646, 0x3b, 0x62a, 0x645, 0x648, 0x632, 0x3b, 0x622, 0x628, 0x3b, 0x623, 0x64a,
+0x644, 0x648, 0x644, 0x3b, 0x62a, 0x634, 0x631, 0x64a, 0x646, 0xa0, 0x627, 0x644,
+0x623, 0x648, 0x644, 0x3b, 0x62a, 0x634, 0x631, 0x64a, 0x646, 0x20, 0x627, 0x644,
+0x62b, 0x627, 0x646, 0x64a, 0x3b, 0x643, 0x627, 0x646, 0x648, 0x646, 0x20, 0x627,
+0x644, 0x623, 0x648, 0x644, 0x643, 0x3b, 0x634, 0x3b, 0x622, 0x3b, 0x646, 0x3b,
+0x623, 0x3b, 0x62d, 0x3b, 0x62a, 0x3b, 0x622, 0x3b, 0x623, 0x3b, 0x62a, 0x3b,
+0x62a, 0x3b, 0x643, 0x64a, 0x646, 0x627, 0x64a, 0x631, 0x3b, 0x641, 0x628, 0x631,
+0x627, 0x64a, 0x631, 0x3b, 0x645, 0x627, 0x631, 0x633, 0x3b, 0x625, 0x628, 0x631,
+0x64a, 0x644, 0x3b, 0x645, 0x627, 0x64a, 0x648, 0x3b, 0x64a, 0x648, 0x646, 0x64a,
+0x648, 0x3b, 0x64a, 0x648, 0x644, 0x64a, 0x648, 0x3b, 0x623, 0x63a, 0x634, 0x62a,
+0x3b, 0x634, 0x62a, 0x645, 0x628, 0x631, 0x3b, 0x623, 0x643, 0x62a, 0x648, 0x628,
+0x631, 0x3b, 0x646, 0x648, 0x641, 0x645, 0x628, 0x631, 0x3b, 0x62f, 0x62c, 0x645,
+0x628, 0x631, 0x64a, 0x3b, 0x641, 0x3b, 0x645, 0x3b, 0x625, 0x3b, 0x648, 0x3b,
+0x646, 0x3b, 0x644, 0x3b, 0x63a, 0x3b, 0x634, 0x3b, 0x643, 0x3b, 0x628, 0x3b,
+0x62f, 0x64a, 0x646, 0x627, 0x64a, 0x631, 0x3b, 0x641, 0x628, 0x631, 0x627, 0x64a,
+0x631, 0x3b, 0x645, 0x627, 0x631, 0x633, 0x3b, 0x623, 0x628, 0x631, 0x64a, 0x644,
+0x3b, 0x645, 0x627, 0x64a, 0x3b, 0x64a, 0x648, 0x646, 0x64a, 0x648, 0x3b, 0x64a,
+0x648, 0x644, 0x64a, 0x648, 0x632, 0x3b, 0x63a, 0x634, 0x62a, 0x3b, 0x634, 0x62a,
+0x646, 0x628, 0x631, 0x3b, 0x623, 0x643, 0x62a, 0x648, 0x628, 0x631, 0x3b, 0x646,
+0x648, 0x646, 0x628, 0x631, 0x3b, 0x62f, 0x62c, 0x646, 0x628, 0x631, 0x64a, 0x3b,
+0x641, 0x3b, 0x645, 0x3b, 0x623, 0x3b, 0x645, 0x3b, 0x646, 0x3b, 0x644, 0x3b,
+0x63a, 0x3b, 0x634, 0x3b, 0x643, 0x3b, 0x628, 0x3b, 0x62f, 0x63, 0x68, 0x69,
+0x6e, 0x65, 0x72, 0x6f, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x65, 0x72, 0x6f,
+0x3b, 0x6d, 0x61, 0x72, 0x7a, 0x6f, 0x3b, 0x61, 0x62, 0x72, 0x69, 0x6c,
+0x3b, 0x6d, 0x61, 0x79, 0x6f, 0x3b, 0x63, 0x68, 0x75, 0x6e, 0x79, 0x6f,
+0x3b, 0x63, 0x68, 0x75, 0x6c, 0x69, 0x6f, 0x6c, 0x3b, 0x61, 0x67, 0x6f,
+0x73, 0x74, 0x6f, 0x3b, 0x73, 0x65, 0x74, 0x69, 0x65, 0x6d, 0x62, 0x72,
+0x65, 0x3b, 0x6f, 0x63, 0x74, 0x75, 0x62, 0x72, 0x65, 0x3b, 0x6e, 0x6f,
+0x76, 0x69, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x61, 0x76, 0x69, 0x65,
+0x6e, 0x74, 0x6f, 0x64, 0x65, 0x20, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72,
+0x6f, 0x3b, 0x64, 0x65, 0x20, 0x66, 0x65, 0x62, 0x72, 0x65, 0x72, 0x6f,
+0x3b, 0x64, 0x65, 0x20, 0x6d, 0x61, 0x72, 0x7a, 0x6f, 0x3b, 0x64, 0x2019,
+0x61, 0x62, 0x72, 0x69, 0x6c, 0x3b, 0x64, 0x65, 0x20, 0x6d, 0x61, 0x79,
+0x6f, 0x3b, 0x64, 0x65, 0x20, 0x63, 0x68, 0x75, 0x6e, 0x79, 0x6f, 0x3b,
+0x64, 0x65, 0x20, 0x63, 0x68, 0x75, 0x6c, 0x69, 0x6f, 0x6c, 0x3b, 0x64,
+0x2019, 0x61, 0x67, 0x6f, 0x73, 0x74, 0x6f, 0x3b, 0x64, 0x65, 0x20, 0x73,
+0x65, 0x74, 0x69, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x2019, 0x6f,
+0x63, 0x74, 0x75, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x65, 0x20, 0x6e, 0x6f,
+0x76, 0x69, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x2019, 0x61, 0x76,
+0x69, 0x65, 0x6e, 0x74, 0x6f, 0x63, 0x68, 0x69, 0x2e, 0x3b, 0x66, 0x65,
+0x62, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x61, 0x62, 0x72, 0x2e,
+0x3b, 0x6d, 0x61, 0x79, 0x2e, 0x3b, 0x63, 0x68, 0x6e, 0x2e, 0x3b, 0x63,
+0x68, 0x6c, 0x2e, 0x3b, 0x61, 0x67, 0x6f, 0x2e, 0x3b, 0x73, 0x65, 0x74,
+0x2e, 0x3b, 0x6f, 0x63, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b,
+0x61, 0x76, 0x69, 0x2e, 0x570, 0x578, 0x582, 0x576, 0x57e, 0x561, 0x580, 0x3b,
+0x583, 0x565, 0x57f, 0x580, 0x57e, 0x561, 0x580, 0x3b, 0x574, 0x561, 0x580, 0x57f,
+0x3b, 0x561, 0x57a, 0x580, 0x56b, 0x56c, 0x3b, 0x574, 0x561, 0x575, 0x56b, 0x57d,
+0x3b, 0x570, 0x578, 0x582, 0x576, 0x56b, 0x57d, 0x3b, 0x570, 0x578, 0x582, 0x56c,
+0x56b, 0x57d, 0x3b, 0x585, 0x563, 0x578, 0x57d, 0x57f, 0x578, 0x57d, 0x3b, 0x57d,
+0x565, 0x57a, 0x57f, 0x565, 0x574, 0x562, 0x565, 0x580, 0x3b, 0x570, 0x578, 0x56f,
+0x57f, 0x565, 0x574, 0x562, 0x565, 0x580, 0x3b, 0x576, 0x578, 0x575, 0x565, 0x574,
+0x562, 0x565, 0x580, 0x3b, 0x564, 0x565, 0x56f, 0x57f, 0x565, 0x574, 0x562, 0x565,
+0x580, 0x570, 0x578, 0x582, 0x576, 0x57e, 0x561, 0x580, 0x56b, 0x3b, 0x583, 0x565,
+0x57f, 0x580, 0x57e, 0x561, 0x580, 0x56b, 0x3b, 0x574, 0x561, 0x580, 0x57f, 0x56b,
+0x3b, 0x561, 0x57a, 0x580, 0x56b, 0x56c, 0x56b, 0x3b, 0x574, 0x561, 0x575, 0x56b,
+0x57d, 0x56b, 0x3b, 0x570, 0x578, 0x582, 0x576, 0x56b, 0x57d, 0x56b, 0x3b, 0x570,
+0x578, 0x582, 0x56c, 0x56b, 0x57d, 0x56b, 0x3b, 0x585, 0x563, 0x578, 0x57d, 0x57f,
+0x578, 0x57d, 0x56b, 0x3b, 0x57d, 0x565, 0x57a, 0x57f, 0x565, 0x574, 0x562, 0x565,
+0x580, 0x56b, 0x3b, 0x570, 0x578, 0x56f, 0x57f, 0x565, 0x574, 0x562, 0x565, 0x580,
+0x56b, 0x3b, 0x576, 0x578, 0x575, 0x565, 0x574, 0x562, 0x565, 0x580, 0x56b, 0x3b,
+0x564, 0x565, 0x56f, 0x57f, 0x565, 0x574, 0x562, 0x565, 0x580, 0x56b, 0x570, 0x576,
+0x57e, 0x3b, 0x583, 0x57f, 0x57e, 0x3b, 0x574, 0x580, 0x57f, 0x3b, 0x561, 0x57a,
+0x580, 0x3b, 0x574, 0x575, 0x57d, 0x3b, 0x570, 0x576, 0x57d, 0x3b, 0x570, 0x56c,
+0x57d, 0x3b, 0x585, 0x563, 0x57d, 0x3b, 0x57d, 0x565, 0x57a, 0x3b, 0x570, 0x578,
+0x56f, 0x3b, 0x576, 0x578, 0x575, 0x3b, 0x564, 0x565, 0x56f, 0x540, 0x3b, 0x553,
+0x3b, 0x544, 0x3b, 0x531, 0x3b, 0x544, 0x3b, 0x540, 0x3b, 0x540, 0x3b, 0x555,
+0x3b, 0x54d, 0x3b, 0x540, 0x3b, 0x546, 0x3b, 0x534, 0x99c, 0x9be, 0x9a8, 0x9c1,
+0x9f1, 0x9be, 0x9f0, 0x9c0, 0x3b, 0x9ab, 0x9c7, 0x9ac, 0x9cd, 0x9f0, 0x9c1, 0x9f1,
+0x9be, 0x9f0, 0x9c0, 0x3b, 0x9ae, 0x9be, 0x9f0, 0x9cd, 0x99a, 0x3b, 0x98f, 0x9aa,
+0x9cd, 0x9f0, 0x9bf, 0x9b2, 0x3b, 0x9ae, 0x9c7, 0x2019, 0x3b, 0x99c, 0x9c1, 0x9a8,
+0x3b, 0x99c, 0x9c1, 0x9b2, 0x9be, 0x987, 0x3b, 0x986, 0x997, 0x9b7, 0x9cd, 0x99f,
+0x3b, 0x99b, 0x9c7, 0x9aa, 0x9cd, 0x9a4, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9f0, 0x3b,
+0x985, 0x995, 0x9cd, 0x99f, 0x9cb, 0x9ac, 0x9f0, 0x3b, 0x9a8, 0x9f1, 0x9c7, 0x9ae,
+0x9cd, 0x9ac, 0x9f0, 0x3b, 0x9a1, 0x9bf, 0x99a, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9f0,
+0x99c, 0x9be, 0x9a8, 0x9c1, 0x3b, 0x9ab, 0x9c7, 0x9ac, 0x9cd, 0x9f0, 0x9c1, 0x3b,
+0x9ae, 0x9be, 0x9f0, 0x9cd, 0x99a, 0x3b, 0x98f, 0x9aa, 0x9cd, 0x9f0, 0x9bf, 0x9b2,
+0x3b, 0x9ae, 0x9c7, 0x2019, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b, 0x99c, 0x9c1, 0x9b2,
+0x9be, 0x987, 0x3b, 0x986, 0x997, 0x3b, 0x99b, 0x9c7, 0x9aa, 0x9cd, 0x9a4, 0x9c7,
+0x3b, 0x985, 0x995, 0x9cd, 0x99f, 0x9cb, 0x3b, 0x9a8, 0x9f1, 0x9c7, 0x3b, 0x9a1,
+0x9bf, 0x99a, 0x9c7, 0x99c, 0x3b, 0x9ab, 0x3b, 0x9ae, 0x3b, 0x98f, 0x3b, 0x9ae,
+0x3b, 0x99c, 0x3b, 0x99c, 0x3b, 0x986, 0x3b, 0x99b, 0x3b, 0x985, 0x3b, 0x9a8,
+0x3b, 0x9a1, 0x78, 0x69, 0x6e, 0x65, 0x72, 0x75, 0x3b, 0x66, 0x65, 0x62,
+0x72, 0x65, 0x72, 0x75, 0x3b, 0x6d, 0x61, 0x72, 0x7a, 0x75, 0x3b, 0x61,
+0x62, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x61, 0x79, 0x75, 0x3b, 0x78, 0x75,
+0x6e, 0x75, 0x3b, 0x78, 0x75, 0x6e, 0x65, 0x74, 0x75, 0x3b, 0x61, 0x67,
+0x6f, 0x73, 0x74, 0x75, 0x3b, 0x73, 0x65, 0x74, 0x69, 0x65, 0x6d, 0x62,
+0x72, 0x65, 0x3b, 0x6f, 0x63, 0x68, 0x6f, 0x62, 0x72, 0x65, 0x3b, 0x70,
+0x61, 0x79, 0x61, 0x72, 0x65, 0x73, 0x3b, 0x61, 0x76, 0x69, 0x65, 0x6e,
+0x74, 0x75, 0x64, 0x65, 0x20, 0x78, 0x69, 0x6e, 0x65, 0x72, 0x75, 0x3b,
+0x64, 0x65, 0x20, 0x66, 0x65, 0x62, 0x72, 0x65, 0x72, 0x75, 0x3b, 0x64,
+0x65, 0x20, 0x6d, 0x61, 0x72, 0x7a, 0x75, 0x3b, 0x64, 0x2019, 0x61, 0x62,
+0x72, 0x69, 0x6c, 0x3b, 0x64, 0x65, 0x20, 0x6d, 0x61, 0x79, 0x75, 0x3b,
+0x64, 0x65, 0x20, 0x78, 0x75, 0x6e, 0x75, 0x3b, 0x64, 0x65, 0x20, 0x78,
+0x75, 0x6e, 0x65, 0x74, 0x75, 0x3b, 0x64, 0x2019, 0x61, 0x67, 0x6f, 0x73,
+0x74, 0x75, 0x3b, 0x64, 0x65, 0x20, 0x73, 0x65, 0x74, 0x69, 0x65, 0x6d,
+0x62, 0x72, 0x65, 0x3b, 0x64, 0x2019, 0x6f, 0x63, 0x68, 0x6f, 0x62, 0x72,
+0x65, 0x3b, 0x64, 0x65, 0x20, 0x70, 0x61, 0x79, 0x61, 0x72, 0x65, 0x73,
+0x3b, 0x64, 0x2019, 0x61, 0x76, 0x69, 0x65, 0x6e, 0x74, 0x75, 0x58, 0x69,
+0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x62,
+0x72, 0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x58, 0x75, 0x6e, 0x3b, 0x58, 0x6e,
+0x74, 0x3b, 0x41, 0x67, 0x6f, 0x3b, 0x53, 0x65, 0x74, 0x3b, 0x4f, 0x63,
+0x68, 0x3b, 0x50, 0x61, 0x79, 0x3b, 0x41, 0x76, 0x69, 0x78, 0x69, 0x6e,
+0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x61, 0x62, 0x72,
+0x3b, 0x6d, 0x61, 0x79, 0x3b, 0x78, 0x75, 0x6e, 0x3b, 0x78, 0x6e, 0x74,
+0x3b, 0x61, 0x67, 0x6f, 0x3b, 0x73, 0x65, 0x74, 0x3b, 0x6f, 0x63, 0x68,
+0x3b, 0x70, 0x61, 0x79, 0x3b, 0x61, 0x76, 0x69, 0x58, 0x3b, 0x46, 0x3b,
+0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x58, 0x3b, 0x58, 0x3b, 0x41, 0x3b,
+0x53, 0x3b, 0x4f, 0x3b, 0x50, 0x3b, 0x41, 0x4a, 0x61, 0x6e, 0x75, 0x61,
+0x72, 0x69, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x69, 0x3b,
+0x4d, 0x61, 0x63, 0x68, 0x69, 0x3b, 0x41, 0x70, 0x72, 0x69, 0x6c, 0x69,
+0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75,
+0x6c, 0x61, 0x69, 0x3b, 0x41, 0x67, 0x6f, 0x73, 0x74, 0x69, 0x3b, 0x53,
+0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x4f, 0x6b, 0x74, 0x6f,
+0x62, 0x61, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x44,
+0x65, 0x73, 0x65, 0x6d, 0x62, 0x61, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65,
+0x62, 0x3b, 0x4d, 0x61, 0x63, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x65,
+0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x67,
+0x6f, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f,
+0x76, 0x3b, 0x44, 0x65, 0x63, 0x50, 0x65, 0x6e, 0x20, 0x44, 0x79, 0x6f,
+0x6e, 0x3b, 0x50, 0x65, 0x6e, 0x20, 0x42, 0x61, 0x2bc, 0x61, 0x3b, 0x50,
+0x65, 0x6e, 0x20, 0x41, 0x74, 0x61, 0x74, 0x3b, 0x50, 0x65, 0x6e, 0x20,
+0x41, 0x6e, 0x61, 0x73, 0x3b, 0x50, 0x65, 0x6e, 0x20, 0x41, 0x74, 0x79,
+0x6f, 0x6e, 0x3b, 0x50, 0x65, 0x6e, 0x20, 0x41, 0x63, 0x68, 0x69, 0x72,
+0x69, 0x6d, 0x3b, 0x50, 0x65, 0x6e, 0x20, 0x41, 0x74, 0x61, 0x72, 0x69,
+0x62, 0x61, 0x3b, 0x50, 0x65, 0x6e, 0x20, 0x41, 0x77, 0x75, 0x72, 0x72,
+0x3b, 0x50, 0x65, 0x6e, 0x20, 0x53, 0x68, 0x61, 0x64, 0x6f, 0x6e, 0x3b,
+0x50, 0x65, 0x6e, 0x20, 0x53, 0x68, 0x61, 0x6b, 0x75, 0x72, 0x3b, 0x50,
+0x65, 0x6e, 0x20, 0x4b, 0x75, 0x72, 0x20, 0x4e, 0x61, 0x62, 0x61, 0x3b,
+0x50, 0x65, 0x6e, 0x20, 0x4b, 0x75, 0x72, 0x20, 0x4e, 0x61, 0x74, 0x61,
+0x74, 0x44, 0x79, 0x6f, 0x6e, 0x3b, 0x42, 0x61, 0x61, 0x3b, 0x41, 0x74,
+0x61, 0x74, 0x3b, 0x41, 0x6e, 0x61, 0x73, 0x3b, 0x41, 0x74, 0x79, 0x6f,
+0x3b, 0x41, 0x63, 0x68, 0x69, 0x3b, 0x41, 0x74, 0x61, 0x72, 0x3b, 0x41,
+0x77, 0x75, 0x72, 0x3b, 0x53, 0x68, 0x61, 0x64, 0x3b, 0x53, 0x68, 0x61,
+0x6b, 0x3b, 0x4e, 0x61, 0x62, 0x61, 0x3b, 0x4e, 0x61, 0x74, 0x61, 0x79,
+0x61, 0x6e, 0x76, 0x61, 0x72, 0x3b, 0x66, 0x65, 0x76, 0x72, 0x61, 0x6c,
+0x3b, 0x6d, 0x61, 0x72, 0x74, 0x3b, 0x61, 0x70, 0x72, 0x65, 0x6c, 0x3b,
+0x6d, 0x61, 0x79, 0x3b, 0x69, 0x79, 0x75, 0x6e, 0x3b, 0x69, 0x79, 0x75,
+0x6c, 0x3b, 0x61, 0x76, 0x71, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x6e,
+0x74, 0x79, 0x61, 0x62, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x79, 0x61, 0x62,
+0x72, 0x3b, 0x6e, 0x6f, 0x79, 0x61, 0x62, 0x72, 0x3b, 0x64, 0x65, 0x6b,
+0x61, 0x62, 0x72, 0x79, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x76, 0x3b, 0x6d,
+0x61, 0x72, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0x61, 0x79, 0x3b, 0x69,
+0x79, 0x6e, 0x3b, 0x69, 0x79, 0x6c, 0x3b, 0x61, 0x76, 0x71, 0x3b, 0x73,
+0x65, 0x6e, 0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x79, 0x3b, 0x64,
+0x65, 0x6b, 0x408, 0x430, 0x43d, 0x432, 0x430, 0x440, 0x3b, 0x424, 0x435, 0x432,
+0x440, 0x430, 0x43b, 0x3b, 0x41c, 0x430, 0x440, 0x442, 0x3b, 0x410, 0x43f, 0x440,
+0x435, 0x43b, 0x3b, 0x41c, 0x430, 0x439, 0x3b, 0x418, 0x458, 0x443, 0x43d, 0x3b,
+0x418, 0x458, 0x443, 0x43b, 0x3b, 0x410, 0x432, 0x433, 0x443, 0x441, 0x442, 0x3b,
+0x421, 0x435, 0x43d, 0x442, 0x458, 0x430, 0x431, 0x440, 0x3b, 0x41e, 0x43a, 0x442,
+0x458, 0x430, 0x431, 0x440, 0x3b, 0x41d, 0x43e, 0x458, 0x430, 0x431, 0x440, 0x3b,
+0x414, 0x435, 0x43a, 0x430, 0x431, 0x440, 0x458, 0x430, 0x43d, 0x432, 0x430, 0x440,
+0x3b, 0x444, 0x435, 0x432, 0x440, 0x430, 0x43b, 0x3b, 0x43c, 0x430, 0x440, 0x442,
+0x3b, 0x430, 0x43f, 0x440, 0x435, 0x43b, 0x3b, 0x43c, 0x430, 0x439, 0x3b, 0x438,
+0x458, 0x443, 0x43d, 0x3b, 0x438, 0x458, 0x443, 0x43b, 0x3b, 0x430, 0x432, 0x433,
+0x443, 0x441, 0x442, 0x3b, 0x441, 0x435, 0x43d, 0x442, 0x458, 0x430, 0x431, 0x440,
+0x3b, 0x43e, 0x43a, 0x442, 0x458, 0x430, 0x431, 0x440, 0x3b, 0x43d, 0x43e, 0x458,
+0x430, 0x431, 0x440, 0x3b, 0x434, 0x435, 0x43a, 0x430, 0x431, 0x440, 0x458, 0x430,
+0x43d, 0x3b, 0x444, 0x435, 0x432, 0x3b, 0x43c, 0x430, 0x440, 0x3b, 0x430, 0x43f,
+0x440, 0x3b, 0x43c, 0x430, 0x439, 0x3b, 0x438, 0x458, 0x43d, 0x3b, 0x438, 0x458,
+0x43b, 0x3b, 0x430, 0x432, 0x433, 0x3b, 0x441, 0x435, 0x43d, 0x3b, 0x43e, 0x43a,
+0x442, 0x3b, 0x43d, 0x43e, 0x458, 0x3b, 0x434, 0x435, 0x43a, 0x14b, 0x77, 0xed,
+0xed, 0x20, 0x61, 0x20, 0x6e, 0x74, 0x254, 0x301, 0x6e, 0x74, 0x254, 0x3b,
+0x14b, 0x77, 0xed, 0xed, 0x20, 0x61, 0x6b, 0x1dd, 0x20, 0x62, 0x25b, 0x301,
+0x25b, 0x3b, 0x14b, 0x77, 0xed, 0xed, 0x20, 0x61, 0x6b, 0x1dd, 0x20, 0x72,
+0xe1, 0xe1, 0x3b, 0x14b, 0x77, 0xed, 0xed, 0x20, 0x61, 0x6b, 0x1dd, 0x20,
+0x6e, 0x69, 0x6e, 0x3b, 0x14b, 0x77, 0xed, 0xed, 0x20, 0x61, 0x6b, 0x1dd,
+0x20, 0x74, 0xe1, 0x61, 0x6e, 0x3b, 0x14b, 0x77, 0xed, 0xed, 0x20, 0x61,
+0x6b, 0x1dd, 0x20, 0x74, 0xe1, 0x61, 0x66, 0x254, 0x6b, 0x3b, 0x14b, 0x77,
+0xed, 0xed, 0x20, 0x61, 0x6b, 0x1dd, 0x20, 0x74, 0xe1, 0x61, 0x62, 0x25b,
+0x25b, 0x3b, 0x14b, 0x77, 0xed, 0xed, 0x20, 0x61, 0x6b, 0x1dd, 0x20, 0x74,
+0xe1, 0x61, 0x72, 0x61, 0x61, 0x3b, 0x14b, 0x77, 0xed, 0xed, 0x20, 0x61,
+0x6b, 0x1dd, 0x20, 0x74, 0xe1, 0x61, 0x6e, 0x69, 0x6e, 0x3b, 0x14b, 0x77,
+0xed, 0xed, 0x20, 0x61, 0x6b, 0x1dd, 0x20, 0x6e, 0x74, 0x25b, 0x6b, 0x3b,
+0x14b, 0x77, 0xed, 0xed, 0x20, 0x61, 0x6b, 0x1dd, 0x20, 0x6e, 0x74, 0x25b,
+0x6b, 0x20, 0x64, 0x69, 0x20, 0x62, 0x254, 0x301, 0x6b, 0x3b, 0x14b, 0x77,
+0xed, 0xed, 0x20, 0x61, 0x6b, 0x1dd, 0x20, 0x6e, 0x74, 0x25b, 0x6b, 0x20,
+0x64, 0x69, 0x20, 0x62, 0x25b, 0x301, 0x25b, 0x14b, 0x31, 0x3b, 0x14b, 0x32,
+0x3b, 0x14b, 0x33, 0x3b, 0x14b, 0x34, 0x3b, 0x14b, 0x35, 0x3b, 0x14b, 0x36,
+0x3b, 0x14b, 0x37, 0x3b, 0x14b, 0x38, 0x3b, 0x14b, 0x39, 0x3b, 0x14b, 0x31,
+0x30, 0x3b, 0x14b, 0x31, 0x31, 0x3b, 0x14b, 0x31, 0x32, 0x7a, 0x61, 0x6e,
+0x77, 0x75, 0x79, 0x65, 0x3b, 0x66, 0x65, 0x62, 0x75, 0x72, 0x75, 0x79,
+0x65, 0x3b, 0x6d, 0x61, 0x72, 0x69, 0x73, 0x69, 0x3b, 0x61, 0x77, 0x69,
+0x72, 0x69, 0x6c, 0x69, 0x3b, 0x6d, 0x25b, 0x3b, 0x7a, 0x75, 0x77, 0x25b,
+0x6e, 0x3b, 0x7a, 0x75, 0x6c, 0x75, 0x79, 0x65, 0x3b, 0x75, 0x74, 0x69,
+0x3b, 0x73, 0x25b, 0x74, 0x61, 0x6e, 0x62, 0x75, 0x72, 0x75, 0x3b, 0x254,
+0x6b, 0x75, 0x74, 0x254, 0x62, 0x75, 0x72, 0x75, 0x3b, 0x6e, 0x6f, 0x77,
+0x61, 0x6e, 0x62, 0x75, 0x72, 0x75, 0x3b, 0x64, 0x65, 0x73, 0x61, 0x6e,
+0x62, 0x75, 0x72, 0x75, 0x7a, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b,
+0x6d, 0x61, 0x72, 0x3b, 0x61, 0x77, 0x69, 0x3b, 0x6d, 0x25b, 0x3b, 0x7a,
+0x75, 0x77, 0x3b, 0x7a, 0x75, 0x6c, 0x3b, 0x75, 0x74, 0x69, 0x3b, 0x73,
+0x25b, 0x74, 0x3b, 0x254, 0x6b, 0x75, 0x3b, 0x6e, 0x6f, 0x77, 0x3b, 0x64,
+0x65, 0x73, 0x5a, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b,
+0x5a, 0x3b, 0x5a, 0x3b, 0x55, 0x3b, 0x53, 0x3b, 0x186, 0x3b, 0x4e, 0x3b,
+0x44, 0x99c, 0x9be, 0x9a8, 0x9c1, 0x9af, 0x9bc, 0x9be, 0x9b0, 0x9c0, 0x3b, 0x9ab,
+0x9c7, 0x9ac, 0x9cd, 0x9b0, 0x9c1, 0x9af, 0x9bc, 0x9be, 0x9b0, 0x9c0, 0x3b, 0x9ae,
+0x9be, 0x9b0, 0x9cd, 0x99a, 0x3b, 0x98f, 0x9aa, 0x9cd, 0x9b0, 0x9bf, 0x9b2, 0x3b,
+0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b, 0x99c, 0x9c1, 0x9b2, 0x9be, 0x987,
+0x3b, 0x986, 0x997, 0x9b8, 0x9cd, 0x99f, 0x3b, 0x9b8, 0x9c7, 0x9aa, 0x9cd, 0x99f,
+0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9b0, 0x3b, 0x985, 0x995, 0x9cd, 0x99f, 0x9cb, 0x9ac,
+0x9b0, 0x3b, 0x9a8, 0x9ad, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9b0, 0x3b, 0x9a1, 0x9bf,
+0x9b8, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9b0, 0x99c, 0x9be, 0x9a8, 0x9c1, 0x3b, 0x9ab,
+0x9c7, 0x9ac, 0x3b, 0x9ae, 0x9be, 0x9b0, 0x9cd, 0x99a, 0x3b, 0x98f, 0x9aa, 0x9cd,
+0x9b0, 0x9bf, 0x9b2, 0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b, 0x99c,
+0x9c1, 0x9b2, 0x9be, 0x987, 0x3b, 0x986, 0x997, 0x9b8, 0x9cd, 0x99f, 0x3b, 0x9b8,
+0x9c7, 0x9aa, 0x9cd, 0x99f, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9b0, 0x3b, 0x985, 0x995,
+0x9cd, 0x99f, 0x9cb, 0x9ac, 0x9b0, 0x3b, 0x9a8, 0x9ad, 0x9c7, 0x9ae, 0x9cd, 0x9ac,
+0x9b0, 0x3b, 0x9a1, 0x9bf, 0x9b8, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9b0, 0x99c, 0x9be,
+0x9a8, 0x9c1, 0x3b, 0x9ab, 0x9c7, 0x9ac, 0x3b, 0x9ae, 0x9be, 0x9b0, 0x9cd, 0x99a,
+0x3b, 0x98f, 0x9aa, 0x9cd, 0x9b0, 0x9bf, 0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1,
+0x9a8, 0x3b, 0x99c, 0x9c1, 0x9b2, 0x3b, 0x986, 0x997, 0x3b, 0x9b8, 0x9c7, 0x9aa,
+0x3b, 0x985, 0x995, 0x9cd, 0x99f, 0x9cb, 0x3b, 0x9a8, 0x9ad, 0x9c7, 0x3b, 0x9a1,
+0x9bf, 0x9b8, 0x9c7, 0x99c, 0x9be, 0x3b, 0x9ab, 0x9c7, 0x3b, 0x9ae, 0x9be, 0x3b,
+0x98f, 0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b, 0x99c, 0x9c1, 0x3b,
+0x986, 0x3b, 0x9b8, 0x9c7, 0x3b, 0x985, 0x3b, 0x9a8, 0x3b, 0x9a1, 0x9bf, 0x99c,
+0x9be, 0x9a8, 0x9c1, 0x3b, 0x9ab, 0x9c7, 0x9ac, 0x3b, 0x9ae, 0x9be, 0x9b0, 0x9cd,
+0x99a, 0x3b, 0x98f, 0x9aa, 0x9cd, 0x9b0, 0x9bf, 0x9b2, 0x3b, 0x9ae, 0x9c7, 0x3b,
+0x99c, 0x9c1, 0x9a8, 0x3b, 0x99c, 0x9c1, 0x9b2, 0x9be, 0x987, 0x3b, 0x986, 0x997,
+0x9b8, 0x9cd, 0x99f, 0x3b, 0x9b8, 0x9c7, 0x9aa, 0x9cd, 0x99f, 0x9c7, 0x983, 0x3b,
+0x985, 0x995, 0x9cd, 0x99f, 0x9cb, 0x983, 0x3b, 0x9a8, 0x9ad, 0x9c7, 0x983, 0x3b,
+0x9a1, 0x9bf, 0x9b8, 0x9c7, 0x983, 0x99c, 0x9be, 0x9a8, 0x9c1, 0x3b, 0x9ab, 0x9c7,
+0x9ac, 0x3b, 0x9ae, 0x9be, 0x9b0, 0x9cd, 0x99a, 0x3b, 0x98f, 0x9aa, 0x9cd, 0x9b0,
+0x9bf, 0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b, 0x99c, 0x9c1, 0x9b2,
+0x3b, 0x986, 0x997, 0x3b, 0x9b8, 0x9c7, 0x9aa, 0x9cd, 0x99f, 0x9c7, 0x983, 0x3b,
+0x985, 0x995, 0x9cd, 0x99f, 0x9cb, 0x983, 0x3b, 0x9a8, 0x9ad, 0x9c7, 0x983, 0x3b,
+0x9a1, 0x9bf, 0x9b8, 0x9c7, 0x983, 0x99c, 0x9be, 0x3b, 0x9ab, 0x9c7, 0x3b, 0x9ae,
+0x9be, 0x3b, 0x98f, 0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b, 0x99c,
+0x9c1, 0x9b2, 0x3b, 0x986, 0x3b, 0x9b8, 0x9c7, 0x3b, 0x985, 0x3b, 0x9a8, 0x3b,
+0x9a1, 0x9bf, 0x4b, 0x254, 0x6e, 0x64, 0x254, 0x14b, 0x3b, 0x4d, 0xe0, 0x63,
+0x25b, 0x302, 0x6c, 0x3b, 0x4d, 0xe0, 0x74, 0xf9, 0x6d, 0x62, 0x3b, 0x4d,
+0xe0, 0x74, 0x6f, 0x70, 0x3b, 0x4d, 0x300, 0x70, 0x75, 0x79, 0x25b, 0x3b,
+0x48, 0xec, 0x6c, 0xf2, 0x6e, 0x64, 0x25b, 0x300, 0x3b, 0x4e, 0x6a, 0xe8,
+0x62, 0xe0, 0x3b, 0x48, 0xec, 0x6b, 0x61, 0x14b, 0x3b, 0x44, 0xec, 0x70,
+0x254, 0x300, 0x73, 0x3b, 0x42, 0xec, 0xf2, 0xf4, 0x6d, 0x3b, 0x4d, 0xe0,
+0x79, 0x25b, 0x73, 0xe8, 0x70, 0x3b, 0x4c, 0xec, 0x62, 0x75, 0x79, 0x20,
+0x6c, 0x69, 0x20, 0x144, 0x79, 0xe8, 0x65, 0x6b, 0x254, 0x6e, 0x3b, 0x6d,
+0x61, 0x63, 0x3b, 0x6d, 0x61, 0x74, 0x3b, 0x6d, 0x74, 0x6f, 0x3b, 0x6d,
+0x70, 0x75, 0x3b, 0x68, 0x69, 0x6c, 0x3b, 0x6e, 0x6a, 0x65, 0x3b, 0x68,
+0x69, 0x6b, 0x3b, 0x64, 0x69, 0x70, 0x3b, 0x62, 0x69, 0x6f, 0x3b, 0x6d,
+0x61, 0x79, 0x3b, 0x6c, 0x69, 0x253, 0x6b, 0x3b, 0x6d, 0x3b, 0x6d, 0x3b,
+0x6d, 0x3b, 0x6d, 0x3b, 0x68, 0x3b, 0x6e, 0x3b, 0x68, 0x3b, 0x64, 0x3b,
+0x62, 0x3b, 0x6d, 0x3b, 0x6c, 0x75, 0x72, 0x74, 0x61, 0x72, 0x72, 0x69,
+0x6c, 0x61, 0x3b, 0x6f, 0x74, 0x73, 0x61, 0x69, 0x6c, 0x61, 0x3b, 0x6d,
+0x61, 0x72, 0x74, 0x78, 0x6f, 0x61, 0x3b, 0x61, 0x70, 0x69, 0x72, 0x69,
+0x6c, 0x61, 0x3b, 0x6d, 0x61, 0x69, 0x61, 0x74, 0x7a, 0x61, 0x3b, 0x65,
+0x6b, 0x61, 0x69, 0x6e, 0x61, 0x3b, 0x75, 0x7a, 0x74, 0x61, 0x69, 0x6c,
+0x61, 0x3b, 0x61, 0x62, 0x75, 0x7a, 0x74, 0x75, 0x61, 0x3b, 0x69, 0x72,
+0x61, 0x69, 0x6c, 0x61, 0x3b, 0x75, 0x72, 0x72, 0x69, 0x61, 0x3b, 0x61,
+0x7a, 0x61, 0x72, 0x6f, 0x61, 0x3b, 0x61, 0x62, 0x65, 0x6e, 0x64, 0x75,
+0x61, 0x75, 0x72, 0x74, 0x2e, 0x3b, 0x6f, 0x74, 0x73, 0x2e, 0x3b, 0x6d,
+0x61, 0x72, 0x2e, 0x3b, 0x61, 0x70, 0x69, 0x2e, 0x3b, 0x6d, 0x61, 0x69,
+0x2e, 0x3b, 0x65, 0x6b, 0x61, 0x2e, 0x3b, 0x75, 0x7a, 0x74, 0x2e, 0x3b,
+0x61, 0x62, 0x75, 0x2e, 0x3b, 0x69, 0x72, 0x61, 0x2e, 0x3b, 0x75, 0x72,
+0x72, 0x2e, 0x3b, 0x61, 0x7a, 0x61, 0x2e, 0x3b, 0x61, 0x62, 0x65, 0x2e,
+0x55, 0x3b, 0x4f, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x45, 0x3b,
+0x55, 0x3b, 0x41, 0x3b, 0x49, 0x3b, 0x55, 0x3b, 0x41, 0x3b, 0x41, 0x441,
+0x442, 0x443, 0x434, 0x437, 0x435, 0x43d, 0x44c, 0x3b, 0x43b, 0x44e, 0x442, 0x44b,
+0x3b, 0x441, 0x430, 0x43a, 0x430, 0x432, 0x456, 0x43a, 0x3b, 0x43a, 0x440, 0x430,
+0x441, 0x430, 0x432, 0x456, 0x43a, 0x3b, 0x43c, 0x430, 0x439, 0x3b, 0x447, 0x44d,
+0x440, 0x432, 0x435, 0x43d, 0x44c, 0x3b, 0x43b, 0x456, 0x43f, 0x435, 0x43d, 0x44c,
+0x3b, 0x436, 0x43d, 0x456, 0x432, 0x435, 0x43d, 0x44c, 0x3b, 0x432, 0x435, 0x440,
+0x430, 0x441, 0x435, 0x43d, 0x44c, 0x3b, 0x43a, 0x430, 0x441, 0x442, 0x440, 0x44b,
+0x447, 0x43d, 0x456, 0x43a, 0x3b, 0x43b, 0x456, 0x441, 0x442, 0x430, 0x43f, 0x430,
+0x434, 0x3b, 0x441, 0x43d, 0x435, 0x436, 0x430, 0x43d, 0x44c, 0x441, 0x442, 0x443,
+0x434, 0x437, 0x435, 0x43d, 0x44f, 0x3b, 0x43b, 0x44e, 0x442, 0x430, 0x433, 0x430,
+0x3b, 0x441, 0x430, 0x43a, 0x430, 0x432, 0x456, 0x43a, 0x430, 0x3b, 0x43a, 0x440,
+0x430, 0x441, 0x430, 0x432, 0x456, 0x43a, 0x430, 0x3b, 0x43c, 0x430, 0x44f, 0x3b,
+0x447, 0x44d, 0x440, 0x432, 0x435, 0x43d, 0x44f, 0x3b, 0x43b, 0x456, 0x43f, 0x435,
+0x43d, 0x44f, 0x3b, 0x436, 0x43d, 0x456, 0x45e, 0x43d, 0x44f, 0x3b, 0x432, 0x435,
+0x440, 0x430, 0x441, 0x43d, 0x44f, 0x3b, 0x43a, 0x430, 0x441, 0x442, 0x440, 0x44b,
+0x447, 0x43d, 0x456, 0x43a, 0x430, 0x3b, 0x43b, 0x456, 0x441, 0x442, 0x430, 0x43f,
+0x430, 0x434, 0x430, 0x3b, 0x441, 0x43d, 0x435, 0x436, 0x43d, 0x44f, 0x441, 0x442,
+0x443, 0x3b, 0x43b, 0x44e, 0x442, 0x3b, 0x441, 0x430, 0x43a, 0x3b, 0x43a, 0x440,
+0x430, 0x3b, 0x43c, 0x430, 0x439, 0x3b, 0x447, 0x44d, 0x440, 0x3b, 0x43b, 0x456,
+0x43f, 0x3b, 0x436, 0x43d, 0x456, 0x3b, 0x432, 0x435, 0x440, 0x3b, 0x43a, 0x430,
+0x441, 0x3b, 0x43b, 0x456, 0x441, 0x3b, 0x441, 0x43d, 0x435, 0x441, 0x442, 0x443,
+0x3b, 0x43b, 0x44e, 0x442, 0x3b, 0x441, 0x430, 0x43a, 0x3b, 0x43a, 0x440, 0x430,
+0x3b, 0x43c, 0x430, 0x44f, 0x3b, 0x447, 0x44d, 0x440, 0x3b, 0x43b, 0x456, 0x43f,
+0x3b, 0x436, 0x43d, 0x456, 0x3b, 0x432, 0x435, 0x440, 0x3b, 0x43a, 0x430, 0x441,
+0x3b, 0x43b, 0x456, 0x441, 0x3b, 0x441, 0x43d, 0x435, 0x441, 0x3b, 0x43b, 0x3b,
+0x441, 0x3b, 0x43a, 0x3b, 0x43c, 0x3b, 0x447, 0x3b, 0x43b, 0x3b, 0x436, 0x3b,
+0x432, 0x3b, 0x43a, 0x3b, 0x43b, 0x3b, 0x441, 0x4a, 0x61, 0x6e, 0x75, 0x61,
+0x72, 0x69, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x69, 0x3b,
+0x4d, 0x61, 0x63, 0x68, 0x69, 0x3b, 0x45, 0x70, 0x72, 0x65, 0x6f, 0x3b,
+0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c,
+0x61, 0x69, 0x3b, 0x4f, 0x67, 0x61, 0x73, 0x74, 0x69, 0x3b, 0x53, 0x65,
+0x70, 0x74, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62,
+0x61, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x44, 0x69,
+0x73, 0x65, 0x6d, 0x62, 0x61, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62,
+0x3b, 0x4d, 0x61, 0x63, 0x3b, 0x45, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x69,
+0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x4f, 0x67, 0x61,
+0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x76,
+0x3b, 0x44, 0x69, 0x73, 0x4a, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x45, 0x3b,
+0x4d, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x4f, 0x3b, 0x53, 0x3b, 0x4f, 0x3b,
+0x4e, 0x3b, 0x44, 0x70, 0x61, 0x20, 0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69,
+0x20, 0x67, 0x77, 0x61, 0x20, 0x68, 0x75, 0x74, 0x61, 0x6c, 0x61, 0x3b,
+0x70, 0x61, 0x20, 0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69, 0x20, 0x67, 0x77,
+0x61, 0x20, 0x77, 0x75, 0x76, 0x69, 0x6c, 0x69, 0x3b, 0x70, 0x61, 0x20,
+0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69, 0x20, 0x67, 0x77, 0x61, 0x20, 0x77,
+0x75, 0x64, 0x61, 0x74, 0x75, 0x3b, 0x70, 0x61, 0x20, 0x6d, 0x77, 0x65,
+0x64, 0x7a, 0x69, 0x20, 0x67, 0x77, 0x61, 0x20, 0x77, 0x75, 0x74, 0x61,
+0x69, 0x3b, 0x70, 0x61, 0x20, 0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69, 0x20,
+0x67, 0x77, 0x61, 0x20, 0x77, 0x75, 0x68, 0x61, 0x6e, 0x75, 0x3b, 0x70,
+0x61, 0x20, 0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69, 0x20, 0x67, 0x77, 0x61,
+0x20, 0x73, 0x69, 0x74, 0x61, 0x3b, 0x70, 0x61, 0x20, 0x6d, 0x77, 0x65,
+0x64, 0x7a, 0x69, 0x20, 0x67, 0x77, 0x61, 0x20, 0x73, 0x61, 0x62, 0x61,
+0x3b, 0x70, 0x61, 0x20, 0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69, 0x20, 0x67,
+0x77, 0x61, 0x20, 0x6e, 0x61, 0x6e, 0x65, 0x3b, 0x70, 0x61, 0x20, 0x6d,
+0x77, 0x65, 0x64, 0x7a, 0x69, 0x20, 0x67, 0x77, 0x61, 0x20, 0x74, 0x69,
+0x73, 0x61, 0x3b, 0x70, 0x61, 0x20, 0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69,
+0x20, 0x67, 0x77, 0x61, 0x20, 0x6b, 0x75, 0x6d, 0x69, 0x3b, 0x70, 0x61,
+0x20, 0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69, 0x20, 0x67, 0x77, 0x61, 0x20,
+0x6b, 0x75, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x6d, 0x6f, 0x6a, 0x61,
+0x3b, 0x70, 0x61, 0x20, 0x6d, 0x77, 0x65, 0x64, 0x7a, 0x69, 0x20, 0x67,
+0x77, 0x61, 0x20, 0x6b, 0x75, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x6d,
+0x62, 0x69, 0x6c, 0x69, 0x48, 0x75, 0x74, 0x3b, 0x56, 0x69, 0x6c, 0x3b,
+0x44, 0x61, 0x74, 0x3b, 0x54, 0x61, 0x69, 0x3b, 0x48, 0x61, 0x6e, 0x3b,
+0x53, 0x69, 0x74, 0x3b, 0x53, 0x61, 0x62, 0x3b, 0x4e, 0x61, 0x6e, 0x3b,
+0x54, 0x69, 0x73, 0x3b, 0x4b, 0x75, 0x6d, 0x3b, 0x4b, 0x6d, 0x6a, 0x3b,
+0x4b, 0x6d, 0x62, 0x48, 0x3b, 0x56, 0x3b, 0x44, 0x3b, 0x54, 0x3b, 0x48,
+0x3b, 0x53, 0x3b, 0x53, 0x3b, 0x4e, 0x3b, 0x54, 0x3b, 0x4b, 0x3b, 0x4b,
+0x3b, 0x4b, 0x91c, 0x928, 0x935, 0x930, 0x940, 0x3b, 0x92b, 0x930, 0x935, 0x930,
+0x940, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930,
+0x948, 0x932, 0x3b, 0x92e, 0x908, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941,
+0x932, 0x93e, 0x908, 0x3b, 0x905, 0x917, 0x938, 0x94d, 0x924, 0x3b, 0x938, 0x93f,
+0x924, 0x92e, 0x94d, 0x92c, 0x930, 0x3b, 0x905, 0x915, 0x94d, 0x91f, 0x942, 0x92c,
+0x930, 0x3b, 0x928, 0x935, 0x902, 0x92c, 0x930, 0x3b, 0x926, 0x93f, 0x938, 0x902,
+0x92c, 0x930, 0x120d, 0x12f0, 0x1275, 0x122a, 0x3b, 0x12ab, 0x1265, 0x12bd, 0x1265, 0x1272,
+0x3b, 0x12ad, 0x1265, 0x120b, 0x3b, 0x134b, 0x1305, 0x12ba, 0x122a, 0x3b, 0x12ad, 0x1262,
+0x1245, 0x122a, 0x3b, 0x121d, 0x12aa, 0x12a4, 0x120d, 0x20, 0x1275, 0x131f, 0x1292, 0x122a,
+0x3b, 0x12b0, 0x122d, 0x12a9, 0x3b, 0x121b, 0x122d, 0x12eb, 0x121d, 0x20, 0x1275, 0x122a,
+0x3b, 0x12eb, 0x12b8, 0x1292, 0x20, 0x1218, 0x1233, 0x1245, 0x1208, 0x122a, 0x3b, 0x1218,
+0x1270, 0x1209, 0x3b, 0x121d, 0x12aa, 0x12a4, 0x120d, 0x20, 0x1218, 0x123d, 0x12c8, 0x122a,
+0x3b, 0x1270, 0x1215, 0x1233, 0x1235, 0x122a, 0x120d, 0x12f0, 0x1275, 0x3b, 0x12ab, 0x1265,
+0x12bd, 0x3b, 0x12ad, 0x1265, 0x120b, 0x3b, 0x134b, 0x1305, 0x12ba, 0x3b, 0x12ad, 0x1262,
+0x1245, 0x3b, 0x121d, 0x2f, 0x1275, 0x3b, 0x12b0, 0x122d, 0x3b, 0x121b, 0x122d, 0x12eb,
+0x3b, 0x12eb, 0x12b8, 0x1292, 0x3b, 0x1218, 0x1270, 0x1209, 0x3b, 0x121d, 0x2f, 0x121d,
+0x3b, 0x1270, 0x1215, 0x1233, 0x120d, 0x3b, 0x12ab, 0x3b, 0x12ad, 0x3b, 0x134b, 0x3b,
+0x12ad, 0x3b, 0x121d, 0x3b, 0x12b0, 0x3b, 0x121b, 0x3b, 0x12eb, 0x3b, 0x1218, 0x3b,
+0x121d, 0x3b, 0x1270, 0x91c, 0x93e, 0x928, 0x941, 0x935, 0x93e, 0x930, 0x940, 0x3b,
+0x92b, 0x947, 0x92c, 0x94d, 0x930, 0x942, 0x935, 0x93e, 0x930, 0x940, 0x3b, 0x92e,
+0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x90f, 0x92a, 0x94d, 0x930, 0x93f, 0x932, 0x3b,
+0x92e, 0x947, 0x3b, 0x91c, 0x941, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x93e, 0x908,
+0x3b, 0x906, 0x917, 0x937, 0x94d, 0x91f, 0x3b, 0x938, 0x947, 0x92a, 0x94d, 0x925,
+0x947, 0x92e, 0x94d, 0x92c, 0x930, 0x3b, 0x905, 0x915, 0x94d, 0x91f, 0x2019, 0x92c,
+0x930, 0x3b, 0x928, 0x935, 0x947, 0x92e, 0x94d, 0x92c, 0x930, 0x3b, 0x921, 0x93f,
+0x938, 0x947, 0x92e, 0x94d, 0x92c, 0x930, 0x91c, 0x93e, 0x928, 0x3b, 0x92b, 0x947,
+0x92c, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x90f, 0x92a, 0x94d, 0x930,
+0x93f, 0x3b, 0x92e, 0x947, 0x3b, 0x91c, 0x941, 0x928, 0x3b, 0x91c, 0x941, 0x932,
+0x3b, 0x906, 0x917, 0x3b, 0x938, 0x947, 0x92a, 0x3b, 0x905, 0x915, 0x94d, 0x91f,
+0x2019, 0x3b, 0x928, 0x935, 0x947, 0x3b, 0x921, 0x93f, 0x938, 0x947, 0x91c, 0x3b,
+0x92b, 0x3b, 0x92e, 0x3b, 0x90f, 0x3b, 0x92e, 0x3b, 0x91c, 0x3b, 0x91c, 0x3b,
+0x906, 0x3b, 0x938, 0x3b, 0x905, 0x3b, 0x928, 0x3b, 0x921, 0x6a, 0x61, 0x6e,
+0x75, 0x61, 0x72, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x3b,
+0x6d, 0x61, 0x72, 0x74, 0x3b, 0x61, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x6d,
+0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x3b, 0x6a, 0x75, 0x6c, 0x69,
+0x3b, 0x61, 0x75, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74,
+0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x61,
+0x72, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x64,
+0x65, 0x63, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x6a, 0x61, 0x6e, 0x3b, 0x66,
+0x65, 0x62, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d,
+0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61,
+0x75, 0x67, 0x3b, 0x73, 0x65, 0x70, 0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e,
+0x6f, 0x76, 0x3b, 0x64, 0x65, 0x63, 0x6a, 0x3b, 0x66, 0x3b, 0x6d, 0x3b,
+0x61, 0x3b, 0x6d, 0x3b, 0x6a, 0x3b, 0x6a, 0x3b, 0x61, 0x3b, 0x73, 0x3b,
+0x6f, 0x3b, 0x6e, 0x3b, 0x64, 0x458, 0x430, 0x43d, 0x443, 0x430, 0x440, 0x3b,
+0x444, 0x435, 0x431, 0x440, 0x443, 0x430, 0x440, 0x3b, 0x43c, 0x430, 0x440, 0x442,
+0x3b, 0x430, 0x43f, 0x440, 0x438, 0x43b, 0x3b, 0x43c, 0x430, 0x458, 0x3b, 0x458,
+0x443, 0x43d, 0x438, 0x3b, 0x458, 0x443, 0x43b, 0x438, 0x3b, 0x430, 0x443, 0x433,
+0x443, 0x441, 0x442, 0x3b, 0x441, 0x435, 0x43f, 0x442, 0x435, 0x43c, 0x431, 0x430,
+0x440, 0x3b, 0x43e, 0x43a, 0x442, 0x43e, 0x431, 0x430, 0x440, 0x3b, 0x43d, 0x43e,
+0x432, 0x435, 0x43c, 0x431, 0x430, 0x440, 0x3b, 0x434, 0x435, 0x446, 0x435, 0x43c,
+0x431, 0x430, 0x440, 0x458, 0x430, 0x43d, 0x3b, 0x444, 0x435, 0x431, 0x3b, 0x43c,
+0x430, 0x440, 0x3b, 0x430, 0x43f, 0x440, 0x3b, 0x43c, 0x430, 0x458, 0x3b, 0x458,
+0x443, 0x43d, 0x3b, 0x458, 0x443, 0x43b, 0x3b, 0x430, 0x443, 0x433, 0x3b, 0x441,
+0x435, 0x43f, 0x3b, 0x43e, 0x43a, 0x442, 0x3b, 0x43d, 0x43e, 0x432, 0x3b, 0x434,
+0x435, 0x446, 0x458, 0x3b, 0x444, 0x3b, 0x43c, 0x3b, 0x430, 0x3b, 0x43c, 0x3b,
+0x458, 0x3b, 0x458, 0x3b, 0x430, 0x3b, 0x441, 0x3b, 0x43e, 0x3b, 0x43d, 0x3b,
+0x434, 0x47, 0x65, 0x6e, 0x76, 0x65, 0x72, 0x3b, 0x43, 0x2bc, 0x68, 0x77,
+0x65, 0x76, 0x72, 0x65, 0x72, 0x3b, 0x4d, 0x65, 0x75, 0x72, 0x7a, 0x68,
+0x3b, 0x45, 0x62, 0x72, 0x65, 0x6c, 0x3b, 0x4d, 0x61, 0x65, 0x3b, 0x4d,
+0x65, 0x7a, 0x68, 0x65, 0x76, 0x65, 0x6e, 0x3b, 0x47, 0x6f, 0x75, 0x65,
+0x72, 0x65, 0x3b, 0x45, 0x6f, 0x73, 0x74, 0x3b, 0x47, 0x77, 0x65, 0x6e,
+0x67, 0x6f, 0x6c, 0x6f, 0x3b, 0x48, 0x65, 0x72, 0x65, 0x3b, 0x44, 0x75,
+0x3b, 0x4b, 0x65, 0x72, 0x7a, 0x75, 0x47, 0x65, 0x6e, 0x2e, 0x3b, 0x43,
+0x2bc, 0x68, 0x77, 0x65, 0x2e, 0x3b, 0x4d, 0x65, 0x75, 0x72, 0x2e, 0x3b,
+0x45, 0x62, 0x72, 0x2e, 0x3b, 0x4d, 0x61, 0x65, 0x3b, 0x4d, 0x65, 0x7a,
+0x68, 0x2e, 0x3b, 0x47, 0x6f, 0x75, 0x65, 0x2e, 0x3b, 0x45, 0x6f, 0x73,
+0x74, 0x3b, 0x47, 0x77, 0x65, 0x6e, 0x2e, 0x3b, 0x48, 0x65, 0x72, 0x65,
+0x3b, 0x44, 0x75, 0x3b, 0x4b, 0x7a, 0x75, 0x2e, 0x30, 0x31, 0x3b, 0x30,
+0x32, 0x3b, 0x30, 0x33, 0x3b, 0x30, 0x34, 0x3b, 0x30, 0x35, 0x3b, 0x30,
+0x36, 0x3b, 0x30, 0x37, 0x3b, 0x30, 0x38, 0x3b, 0x30, 0x39, 0x3b, 0x31,
+0x30, 0x3b, 0x31, 0x31, 0x3b, 0x31, 0x32, 0x44f, 0x43d, 0x443, 0x430, 0x440,
+0x438, 0x3b, 0x444, 0x435, 0x432, 0x440, 0x443, 0x430, 0x440, 0x438, 0x3b, 0x43c,
+0x430, 0x440, 0x442, 0x3b, 0x430, 0x43f, 0x440, 0x438, 0x43b, 0x3b, 0x43c, 0x430,
+0x439, 0x3b, 0x44e, 0x43d, 0x438, 0x3b, 0x44e, 0x43b, 0x438, 0x3b, 0x430, 0x432,
+0x433, 0x443, 0x441, 0x442, 0x3b, 0x441, 0x435, 0x43f, 0x442, 0x435, 0x43c, 0x432,
+0x440, 0x438, 0x3b, 0x43e, 0x43a, 0x442, 0x43e, 0x43c, 0x432, 0x440, 0x438, 0x3b,
+0x43d, 0x43e, 0x435, 0x43c, 0x432, 0x440, 0x438, 0x3b, 0x434, 0x435, 0x43a, 0x435,
+0x43c, 0x432, 0x440, 0x438, 0x44f, 0x43d, 0x443, 0x3b, 0x444, 0x435, 0x432, 0x3b,
+0x43c, 0x430, 0x440, 0x442, 0x3b, 0x430, 0x43f, 0x440, 0x3b, 0x43c, 0x430, 0x439,
+0x3b, 0x44e, 0x43d, 0x438, 0x3b, 0x44e, 0x43b, 0x438, 0x3b, 0x430, 0x432, 0x433,
+0x3b, 0x441, 0x435, 0x43f, 0x3b, 0x43e, 0x43a, 0x442, 0x3b, 0x43d, 0x43e, 0x435,
+0x3b, 0x434, 0x435, 0x43a, 0x44f, 0x3b, 0x444, 0x3b, 0x43c, 0x3b, 0x430, 0x3b,
+0x43c, 0x3b, 0x44e, 0x3b, 0x44e, 0x3b, 0x430, 0x3b, 0x441, 0x3b, 0x43e, 0x3b,
+0x43d, 0x3b, 0x434, 0x1007, 0x1014, 0x103a, 0x1014, 0x101d, 0x102b, 0x101b, 0x102e, 0x3b,
+0x1016, 0x1031, 0x1016, 0x1031, 0x102c, 0x103a, 0x101d, 0x102b, 0x101b, 0x102e, 0x3b, 0x1019,
+0x1010, 0x103a, 0x3b, 0x1027, 0x1015, 0x103c, 0x102e, 0x3b, 0x1019, 0x1031, 0x3b, 0x1007,
+0x103d, 0x1014, 0x103a, 0x3b, 0x1007, 0x1030, 0x101c, 0x102d, 0x102f, 0x1004, 0x103a, 0x3b,
+0x1029, 0x1002, 0x102f, 0x1010, 0x103a, 0x3b, 0x1005, 0x1000, 0x103a, 0x1010, 0x1004, 0x103a,
+0x1018, 0x102c, 0x3b, 0x1021, 0x1031, 0x102c, 0x1000, 0x103a, 0x1010, 0x102d, 0x102f, 0x1018,
+0x102c, 0x3b, 0x1014, 0x102d, 0x102f, 0x101d, 0x1004, 0x103a, 0x1018, 0x102c, 0x3b, 0x1012,
+0x102e, 0x1007, 0x1004, 0x103a, 0x1018, 0x102c, 0x1007, 0x1014, 0x103a, 0x3b, 0x1016, 0x1031,
+0x3b, 0x1019, 0x1010, 0x103a, 0x3b, 0x1027, 0x3b, 0x1019, 0x1031, 0x3b, 0x1007, 0x103d,
+0x1014, 0x103a, 0x3b, 0x1007, 0x1030, 0x3b, 0x1029, 0x3b, 0x1005, 0x1000, 0x103a, 0x3b,
+0x1021, 0x1031, 0x102c, 0x1000, 0x103a, 0x3b, 0x1014, 0x102d, 0x102f, 0x3b, 0x1012, 0x102e,
+0x1007, 0x3b, 0x1016, 0x3b, 0x1019, 0x3b, 0x1027, 0x3b, 0x1019, 0x3b, 0x1007, 0x3b,
+0x1007, 0x3b, 0x1029, 0x3b, 0x1005, 0x3b, 0x1021, 0x3b, 0x1014, 0x3b, 0x1012, 0x31,
+0x6708, 0x3b, 0x32, 0x6708, 0x3b, 0x33, 0x6708, 0x3b, 0x34, 0x6708, 0x3b, 0x35,
+0x6708, 0x3b, 0x36, 0x6708, 0x3b, 0x37, 0x6708, 0x3b, 0x38, 0x6708, 0x3b, 0x39,
+0x6708, 0x3b, 0x31, 0x30, 0x6708, 0x3b, 0x31, 0x31, 0x6708, 0x3b, 0x31, 0x32,
+0x6708, 0x4e00, 0x6708, 0x3b, 0x4e8c, 0x6708, 0x3b, 0x4e09, 0x6708, 0x3b, 0x56db, 0x6708,
+0x3b, 0x4e94, 0x6708, 0x3b, 0x516d, 0x6708, 0x3b, 0x4e03, 0x6708, 0x3b, 0x516b, 0x6708,
+0x3b, 0x4e5d, 0x6708, 0x3b, 0x5341, 0x6708, 0x3b, 0x5341, 0x4e00, 0x6708, 0x3b, 0x5341,
+0x4e8c, 0x6708, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x3b, 0x66, 0x65, 0x62, 0x72,
+0x65, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0xe7, 0x3b, 0x61, 0x62, 0x72, 0x69,
+0x6c, 0x3b, 0x6d, 0x61, 0x69, 0x67, 0x3b, 0x6a, 0x75, 0x6e, 0x79, 0x3b,
+0x6a, 0x75, 0x6c, 0x69, 0x6f, 0x6c, 0x3b, 0x61, 0x67, 0x6f, 0x73, 0x74,
+0x3b, 0x73, 0x65, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x6f, 0x63,
+0x74, 0x75, 0x62, 0x72, 0x65, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62,
+0x72, 0x65, 0x3b, 0x64, 0x65, 0x73, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x64,
+0x65, 0x20, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x3b, 0x64, 0x65, 0x20, 0x66,
+0x65, 0x62, 0x72, 0x65, 0x72, 0x3b, 0x64, 0x65, 0x20, 0x6d, 0x61, 0x72,
+0xe7, 0x3b, 0x64, 0x2019, 0x61, 0x62, 0x72, 0x69, 0x6c, 0x3b, 0x64, 0x65,
+0x20, 0x6d, 0x61, 0x69, 0x67, 0x3b, 0x64, 0x65, 0x20, 0x6a, 0x75, 0x6e,
+0x79, 0x3b, 0x64, 0x65, 0x20, 0x6a, 0x75, 0x6c, 0x69, 0x6f, 0x6c, 0x3b,
+0x64, 0x2019, 0x61, 0x67, 0x6f, 0x73, 0x74, 0x3b, 0x64, 0x65, 0x20, 0x73,
+0x65, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x2019, 0x6f, 0x63,
+0x74, 0x75, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x65, 0x20, 0x6e, 0x6f, 0x76,
+0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x65, 0x20, 0x64, 0x65, 0x73,
+0x65, 0x6d, 0x62, 0x72, 0x65, 0x67, 0x65, 0x6e, 0x2e, 0x3b, 0x66, 0x65,
+0x62, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0xe7, 0x3b, 0x61, 0x62, 0x72,
+0x2e, 0x3b, 0x6d, 0x61, 0x69, 0x67, 0x3b, 0x6a, 0x75, 0x6e, 0x79, 0x3b,
+0x6a, 0x75, 0x6c, 0x2e, 0x3b, 0x61, 0x67, 0x2e, 0x3b, 0x73, 0x65, 0x74,
+0x2e, 0x3b, 0x6f, 0x63, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b,
+0x64, 0x65, 0x73, 0x2e, 0x64, 0x65, 0x20, 0x67, 0x65, 0x6e, 0x2e, 0x3b,
+0x64, 0x65, 0x20, 0x66, 0x65, 0x62, 0x72, 0x2e, 0x3b, 0x64, 0x65, 0x20,
+0x6d, 0x61, 0x72, 0xe7, 0x3b, 0x64, 0x2019, 0x61, 0x62, 0x72, 0x2e, 0x3b,
+0x64, 0x65, 0x20, 0x6d, 0x61, 0x69, 0x67, 0x3b, 0x64, 0x65, 0x20, 0x6a,
+0x75, 0x6e, 0x79, 0x3b, 0x64, 0x65, 0x20, 0x6a, 0x75, 0x6c, 0x2e, 0x3b,
+0x64, 0x2019, 0x61, 0x67, 0x2e, 0x3b, 0x64, 0x65, 0x20, 0x73, 0x65, 0x74,
+0x2e, 0x3b, 0x64, 0x2019, 0x6f, 0x63, 0x74, 0x2e, 0x3b, 0x64, 0x65, 0x20,
+0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x20, 0x64, 0x65, 0x73, 0x2e,
+0x47, 0x4e, 0x3b, 0x46, 0x42, 0x3b, 0x4d, 0xc7, 0x3b, 0x41, 0x42, 0x3b,
+0x4d, 0x47, 0x3b, 0x4a, 0x4e, 0x3b, 0x4a, 0x4c, 0x3b, 0x41, 0x47, 0x3b,
+0x53, 0x54, 0x3b, 0x4f, 0x43, 0x3b, 0x4e, 0x56, 0x3b, 0x44, 0x53, 0x45,
+0x6e, 0x65, 0x72, 0x6f, 0x3b, 0x50, 0x65, 0x62, 0x72, 0x65, 0x72, 0x6f,
+0x3b, 0x4d, 0x61, 0x72, 0x73, 0x6f, 0x3b, 0x41, 0x62, 0x72, 0x69, 0x6c,
+0x3b, 0x4d, 0x61, 0x79, 0x6f, 0x3b, 0x48, 0x75, 0x6e, 0x79, 0x6f, 0x3b,
+0x48, 0x75, 0x6c, 0x79, 0x6f, 0x3b, 0x41, 0x67, 0x6f, 0x73, 0x74, 0x6f,
+0x3b, 0x53, 0x65, 0x70, 0x74, 0x69, 0x79, 0x65, 0x6d, 0x62, 0x72, 0x65,
+0x3b, 0x4f, 0x6b, 0x74, 0x75, 0x62, 0x72, 0x65, 0x3b, 0x4e, 0x6f, 0x62,
+0x79, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x44, 0x69, 0x73, 0x79, 0x65,
+0x6d, 0x62, 0x72, 0x65, 0x45, 0x6e, 0x65, 0x3b, 0x50, 0x65, 0x62, 0x3b,
+0x4d, 0x61, 0x72, 0x3b, 0x41, 0x62, 0x72, 0x3b, 0x4d, 0x61, 0x79, 0x3b,
+0x48, 0x75, 0x6e, 0x3b, 0x48, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x6f, 0x3b,
+0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x62, 0x3b,
+0x44, 0x69, 0x73, 0x45, 0x3b, 0x50, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d,
+0x3b, 0x48, 0x3b, 0x48, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e,
+0x3b, 0x44, 0x59, 0x65, 0x6e, 0x6e, 0x61, 0x79, 0x65, 0x72, 0x3b, 0x59,
+0x65, 0x62, 0x72, 0x61, 0x79, 0x65, 0x72, 0x3b, 0x4d, 0x61, 0x72, 0x73,
+0x3b, 0x49, 0x62, 0x72, 0x69, 0x72, 0x3b, 0x4d, 0x61, 0x79, 0x79, 0x75,
+0x3b, 0x59, 0x75, 0x6e, 0x79, 0x75, 0x3b, 0x59, 0x75, 0x6c, 0x79, 0x75,
+0x7a, 0x3b, 0x194, 0x75, 0x63, 0x74, 0x3b, 0x43, 0x75, 0x74, 0x61, 0x6e,
+0x62, 0x69, 0x72, 0x3b, 0x4b, 0x1e6d, 0x75, 0x62, 0x65, 0x72, 0x3b, 0x4e,
+0x77, 0x61, 0x6e, 0x62, 0x69, 0x72, 0x3b, 0x44, 0x75, 0x6a, 0x61, 0x6e,
+0x62, 0x69, 0x72, 0x59, 0x65, 0x6e, 0x3b, 0x59, 0x65, 0x62, 0x3b, 0x4d,
+0x61, 0x72, 0x3b, 0x49, 0x62, 0x72, 0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x59,
+0x75, 0x6e, 0x3b, 0x59, 0x75, 0x6c, 0x3b, 0x194, 0x75, 0x63, 0x3b, 0x43,
+0x75, 0x74, 0x3b, 0x4b, 0x1e6d, 0x75, 0x3b, 0x4e, 0x77, 0x61, 0x3b, 0x44,
+0x75, 0x6a, 0x59, 0x3b, 0x59, 0x3b, 0x4d, 0x3b, 0x49, 0x3b, 0x4d, 0x3b,
+0x59, 0x3b, 0x59, 0x3b, 0x194, 0x3b, 0x43, 0x3b, 0x4b, 0x3b, 0x4e, 0x3b,
+0x44, 0x6a9, 0x627, 0x646, 0x648, 0x648, 0x646, 0x6cc, 0x20, 0x62f, 0x648, 0x648,
+0x6d5, 0x645, 0x3b, 0x634, 0x648, 0x628, 0x627, 0x62a, 0x3b, 0x626, 0x627, 0x632,
+0x627, 0x631, 0x3b, 0x646, 0x6cc, 0x633, 0x627, 0x646, 0x3b, 0x626, 0x627, 0x6cc,
+0x627, 0x631, 0x3b, 0x62d, 0x648, 0x632, 0x6d5, 0x6cc, 0x631, 0x627, 0x646, 0x3b,
+0x62a, 0x6d5, 0x645, 0x648, 0x648, 0x632, 0x3b, 0x626, 0x627, 0x628, 0x3b, 0x626,
+0x6d5, 0x6cc, 0x644, 0x648, 0x648, 0x644, 0x3b, 0x62a, 0x634, 0x631, 0x6cc, 0x646,
+0x6cc, 0x20, 0x6cc, 0x6d5, 0x6a9, 0x6d5, 0x645, 0x3b, 0x62a, 0x634, 0x631, 0x6cc,
+0x646, 0x6cc, 0x20, 0x62f, 0x648, 0x648, 0x6d5, 0x645, 0x3b, 0x6a9, 0x627, 0x646,
+0x648, 0x646, 0x6cc, 0x20, 0x6cc, 0x6d5, 0x6a9, 0x6d5, 0x645, 0x6a9, 0x3b, 0x634,
+0x3b, 0x626, 0x3b, 0x646, 0x3b, 0x626, 0x3b, 0x62d, 0x3b, 0x62a, 0x3b, 0x626,
+0x3b, 0x626, 0x3b, 0x62a, 0x3b, 0x62a, 0x3b, 0x6a9, 0xd804, 0xdd0e, 0xd804, 0xdd1a,
+0xd804, 0xdd2a, 0xd804, 0xdd20, 0xd804, 0xdd22, 0xd804, 0xdd28, 0x3b, 0xd804, 0xdd1c, 0xd804,
+0xdd2c, 0xd804, 0xdd1b, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd33, 0xd804, 0xdd22, 0xd804,
+0xdd2a, 0xd804, 0xdd20, 0xd804, 0xdd22, 0xd804, 0xdd28, 0x3b, 0xd804, 0xdd1f, 0xd804, 0xdd22,
+0xd804, 0xdd34, 0xd804, 0xdd0c, 0xd804, 0xdd27, 0x3b, 0xd804, 0xdd03, 0xd804, 0xdd2c, 0xd804,
+0xdd1b, 0xd804, 0xdd33, 0xd804, 0xdd22, 0xd804, 0xdd28, 0xd804, 0xdd23, 0xd804, 0xdd34, 0x3b,
+0xd804, 0xdd1f, 0xd804, 0xdd2c, 0x3b, 0xd804, 0xdd0e, 0xd804, 0xdd2a, 0xd804, 0xdd1a, 0xd804,
+0xdd34, 0x3b, 0xd804, 0xdd0e, 0xd804, 0xdd2a, 0xd804, 0xdd23, 0xd804, 0xdd2d, 0x3b, 0xd804,
+0xdd03, 0xd804, 0xdd09, 0xd804, 0xdd27, 0xd804, 0xdd0c, 0xd804, 0xdd34, 0xd804, 0xdd11, 0xd804,
+0xdd34, 0x3b, 0xd804, 0xdd25, 0xd804, 0xdd2c, 0xd804, 0xdd1b, 0xd804, 0xdd34, 0xd804, 0xdd11,
+0xd804, 0xdd2c, 0xd804, 0xdd1f, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd27, 0xd804, 0xdd22,
+0xd804, 0xdd34, 0x3b, 0xd804, 0xdd03, 0xd804, 0xdd27, 0xd804, 0xdd07, 0xd804, 0xdd34, 0xd804,
+0xdd11, 0xd804, 0xdd2e, 0xd804, 0xdd1d, 0xd804, 0xdd27, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b,
+0xd804, 0xdd1a, 0xd804, 0xdd27, 0xd804, 0xdd1e, 0xd804, 0xdd2c, 0xd804, 0xdd1f, 0xd804, 0xdd34,
+0xd804, 0xdd1d, 0xd804, 0xdd27, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd13, 0xd804,
+0xdd28, 0xd804, 0xdd25, 0xd804, 0xdd2c, 0xd804, 0xdd1f, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804,
+0xdd27, 0xd804, 0xdd22, 0xd804, 0xdd34, 0xd804, 0xdd0e, 0xd804, 0xdd1a, 0xd804, 0xdd2a, 0xd804,
+0xdd20, 0xd804, 0xdd22, 0xd804, 0xdd28, 0x3b, 0xd804, 0xdd1c, 0xd804, 0xdd2c, 0xd804, 0xdd1b,
+0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd33, 0xd804, 0xdd22, 0xd804, 0xdd2a, 0xd804, 0xdd20,
+0xd804, 0xdd22, 0xd804, 0xdd28, 0x3b, 0xd804, 0xdd1f, 0xd804, 0xdd22, 0xd804, 0xdd34, 0xd804,
+0xdd0c, 0xd804, 0xdd27, 0x3b, 0xd804, 0xdd03, 0xd804, 0xdd2c, 0xd804, 0xdd1b, 0xd804, 0xdd33,
+0xd804, 0xdd22, 0xd804, 0xdd28, 0xd804, 0xdd23, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd1f, 0xd804,
+0xdd2c, 0x3b, 0xd804, 0xdd0e, 0xd804, 0xdd2a, 0xd804, 0xdd1a, 0xd804, 0xdd34, 0x3b, 0xd804,
+0xdd0e, 0xd804, 0xdd2a, 0xd804, 0xdd23, 0xd804, 0xdd2d, 0x3b, 0xd804, 0xdd03, 0xd804, 0xdd09,
+0xd804, 0xdd27, 0xd804, 0xdd0c, 0xd804, 0xdd34, 0xd804, 0xdd11, 0xd804, 0xdd34, 0x3b, 0xd804,
+0xdd25, 0xd804, 0xdd2c, 0xd804, 0xdd1b, 0xd804, 0xdd34, 0xd804, 0xdd11, 0xd804, 0xdd2c, 0xd804,
+0xdd1f, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd27, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b,
+0xd804, 0xdd03, 0xd804, 0xdd27, 0xd804, 0xdd07, 0xd804, 0xdd34, 0xd804, 0xdd11, 0xd804, 0xdd2c,
+0xd804, 0xdd1d, 0xd804, 0xdd27, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd1a, 0xd804,
+0xdd27, 0xd804, 0xdd1e, 0xd804, 0xdd2c, 0xd804, 0xdd1f, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804,
+0xdd27, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd13, 0xd804, 0xdd28, 0xd804, 0xdd25,
+0xd804, 0xdd2c, 0xd804, 0xdd1f, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd27, 0xd804, 0xdd22,
+0xd804, 0xdd34, 0xd804, 0xdd0e, 0xd804, 0xdd1a, 0xd804, 0xdd2a, 0x3b, 0xd804, 0xdd1c, 0xd804,
+0xdd2c, 0xd804, 0xdd1b, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd1f, 0xd804, 0xdd22, 0xd804, 0xdd34,
+0xd804, 0xdd0c, 0xd804, 0xdd27, 0x3b, 0xd804, 0xdd03, 0xd804, 0xdd2c, 0xd804, 0xdd1b, 0xd804,
+0xdd33, 0xd804, 0xdd22, 0xd804, 0xdd28, 0xd804, 0xdd23, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd1f,
+0xd804, 0xdd2c, 0x3b, 0xd804, 0xdd0e, 0xd804, 0xdd2a, 0xd804, 0xdd1a, 0xd804, 0xdd34, 0x3b,
+0xd804, 0xdd0e, 0xd804, 0xdd2a, 0xd804, 0xdd23, 0xd804, 0xdd2d, 0x3b, 0xd804, 0xdd03, 0xd804,
+0xdd09, 0xd804, 0xdd27, 0xd804, 0xdd0c, 0xd804, 0xdd34, 0xd804, 0xdd11, 0xd804, 0xdd34, 0x3b,
+0xd804, 0xdd25, 0xd804, 0xdd2c, 0xd804, 0xdd1b, 0xd804, 0xdd34, 0xd804, 0xdd11, 0xd804, 0xdd2c,
+0xd804, 0xdd1f, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd27, 0xd804, 0xdd22, 0xd804, 0xdd34,
+0x3b, 0xd804, 0xdd03, 0xd804, 0xdd27, 0xd804, 0xdd07, 0xd804, 0xdd34, 0xd804, 0xdd11, 0xd804,
+0xdd2e, 0xd804, 0xdd1d, 0xd804, 0xdd27, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd1a,
+0xd804, 0xdd27, 0xd804, 0xdd1e, 0xd804, 0xdd2c, 0xd804, 0xdd1f, 0xd804, 0xdd34, 0xd804, 0xdd1d,
+0xd804, 0xdd27, 0xd804, 0xdd22, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd13, 0xd804, 0xdd28, 0xd804,
+0xdd25, 0xd804, 0xdd2c, 0xd804, 0xdd1f, 0xd804, 0xdd34, 0xd804, 0xdd1d, 0xd804, 0xdd22, 0xd804,
+0xdd34, 0xd804, 0xdd0e, 0x3b, 0xd804, 0xdd1c, 0xd804, 0xdd2c, 0x3b, 0xd804, 0xdd1f, 0x3b,
+0xd804, 0xdd03, 0xd804, 0xdd2c, 0x3b, 0xd804, 0xdd1f, 0xd804, 0xdd2c, 0x3b, 0xd804, 0xdd0e,
+0xd804, 0xdd2a, 0xd804, 0xdd1a, 0xd804, 0xdd34, 0x3b, 0xd804, 0xdd0e, 0xd804, 0xdd2a, 0x3b,
+0xd804, 0xdd03, 0x3b, 0xd804, 0xdd25, 0xd804, 0xdd2c, 0x3b, 0xd804, 0xdd03, 0xd804, 0xdd27,
+0x3b, 0xd804, 0xdd1a, 0xd804, 0xdd27, 0x3b, 0xd804, 0xdd13, 0xd804, 0xdd28, 0x44f, 0x43d,
+0x432, 0x430, 0x440, 0x44c, 0x3b, 0x444, 0x435, 0x432, 0x440, 0x430, 0x43b, 0x44c,
+0x3b, 0x43c, 0x430, 0x440, 0x442, 0x3b, 0x430, 0x43f, 0x440, 0x435, 0x43b, 0x44c,
+0x3b, 0x43c, 0x430, 0x439, 0x3b, 0x438, 0x44e, 0x43d, 0x44c, 0x3b, 0x438, 0x44e,
+0x43b, 0x44c, 0x3b, 0x430, 0x432, 0x433, 0x443, 0x441, 0x442, 0x3b, 0x441, 0x435,
+0x43d, 0x442, 0x44f, 0x431, 0x440, 0x44c, 0x3b, 0x43e, 0x43a, 0x442, 0x44f, 0x431,
+0x440, 0x44c, 0x3b, 0x43d, 0x43e, 0x44f, 0x431, 0x440, 0x44c, 0x3b, 0x434, 0x435,
+0x43a, 0x430, 0x431, 0x440, 0x44c, 0x44f, 0x43d, 0x432, 0x3b, 0x444, 0x435, 0x432,
+0x3b, 0x43c, 0x430, 0x440, 0x3b, 0x430, 0x43f, 0x440, 0x3b, 0x43c, 0x430, 0x439,
+0x3b, 0x438, 0x44e, 0x43d, 0x3b, 0x438, 0x44e, 0x43b, 0x3b, 0x430, 0x432, 0x433,
+0x3b, 0x441, 0x435, 0x43d, 0x3b, 0x43e, 0x43a, 0x442, 0x3b, 0x43d, 0x43e, 0x44f,
+0x3b, 0x434, 0x435, 0x43a, 0x42f, 0x3b, 0x424, 0x3b, 0x41c, 0x3b, 0x410, 0x3b,
+0x41c, 0x3b, 0x418, 0x3b, 0x418, 0x3b, 0x410, 0x3b, 0x421, 0x3b, 0x41e, 0x3b,
+0x41d, 0x3b, 0x414, 0x13a4, 0x13c3, 0x13b8, 0x13d4, 0x13c5, 0x3b, 0x13a7, 0x13a6, 0x13b5,
+0x3b, 0x13a0, 0x13c5, 0x13f1, 0x3b, 0x13a7, 0x13ec, 0x13c2, 0x3b, 0x13a0, 0x13c2, 0x13cd,
+0x13ac, 0x13d8, 0x3b, 0x13d5, 0x13ad, 0x13b7, 0x13f1, 0x3b, 0x13ab, 0x13f0, 0x13c9, 0x13c2,
+0x3b, 0x13a6, 0x13b6, 0x13c2, 0x3b, 0x13da, 0x13b5, 0x13cd, 0x13d7, 0x3b, 0x13da, 0x13c2,
+0x13c5, 0x13d7, 0x3b, 0x13c5, 0x13d3, 0x13d5, 0x13c6, 0x3b, 0x13a5, 0x13cd, 0x13a9, 0x13f1,
+0x13a4, 0x13c3, 0x3b, 0x13a7, 0x13a6, 0x3b, 0x13a0, 0x13c5, 0x3b, 0x13a7, 0x13ec, 0x3b,
+0x13a0, 0x13c2, 0x3b, 0x13d5, 0x13ad, 0x3b, 0x13ab, 0x13f0, 0x3b, 0x13a6, 0x13b6, 0x3b,
+0x13da, 0x13b5, 0x3b, 0x13da, 0x13c2, 0x3b, 0x13c5, 0x13d3, 0x3b, 0x13a5, 0x13cd, 0x13a4,
+0x3b, 0x13a7, 0x3b, 0x13a0, 0x3b, 0x13a7, 0x3b, 0x13a0, 0x3b, 0x13d5, 0x3b, 0x13ab,
+0x3b, 0x13a6, 0x3b, 0x13da, 0x3b, 0x13da, 0x3b, 0x13c5, 0x3b, 0x13a5, 0x48, 0x61,
+0x73, 0x68, 0x69, 0x2bc, 0x20, 0x41, 0x6d, 0x6d, 0x6f, 0x2bc, 0x6e, 0x61,
+0x2bc, 0x3b, 0x48, 0x61, 0x73, 0x68, 0x69, 0x2bc, 0x20, 0x41, 0x74, 0x6f,
+0x6b, 0x6c, 0x6f, 0x2bc, 0x3b, 0x48, 0x61, 0x73, 0x68, 0x69, 0x2bc, 0x20,
+0x41, 0x74, 0x6f, 0x63, 0x68, 0x63, 0x68, 0xed, 0x2bc, 0x6e, 0x61, 0x2bc,
+0x3b, 0x49, 0x69, 0x70, 0x6c, 0x61, 0x6c, 0x3b, 0x4d, 0x69, 0x68, 0x3b,
+0x43, 0x68, 0x6f, 0x6f, 0x6e, 0x3b, 0x43, 0x68, 0x6f, 0x6f, 0x6c, 0x61,
+0x3b, 0x41, 0x6b, 0x61, 0x61, 0x73, 0x3b, 0x53, 0x69, 0x70, 0x74, 0x69,
+0x6d, 0x70, 0x61, 0x2bc, 0x3b, 0x41, 0x61, 0x6b, 0x74, 0x6f, 0x70, 0x61,
+0x2bc, 0x3b, 0x4e, 0x6f, 0x66, 0x69, 0x6d, 0x70, 0x61, 0x2bc, 0x3b, 0x54,
+0x69, 0x69, 0x73, 0x69, 0x6d, 0x70, 0x61, 0x2bc, 0x4f, 0x6b, 0x77, 0x6f,
+0x6b, 0x75, 0x62, 0x61, 0x6e, 0x7a, 0x61, 0x3b, 0x4f, 0x6b, 0x77, 0x61,
+0x6b, 0x61, 0x62, 0x69, 0x72, 0x69, 0x3b, 0x4f, 0x6b, 0x77, 0x61, 0x6b,
+0x61, 0x73, 0x68, 0x61, 0x74, 0x75, 0x3b, 0x4f, 0x6b, 0x77, 0x61, 0x6b,
+0x61, 0x6e, 0x61, 0x3b, 0x4f, 0x6b, 0x77, 0x61, 0x6b, 0x61, 0x74, 0x61,
+0x61, 0x6e, 0x61, 0x3b, 0x4f, 0x6b, 0x77, 0x61, 0x6d, 0x75, 0x6b, 0x61,
+0x61, 0x67, 0x61, 0x3b, 0x4f, 0x6b, 0x77, 0x61, 0x6d, 0x75, 0x73, 0x68,
+0x61, 0x6e, 0x6a, 0x75, 0x3b, 0x4f, 0x6b, 0x77, 0x61, 0x6d, 0x75, 0x6e,
+0x61, 0x61, 0x6e, 0x61, 0x3b, 0x4f, 0x6b, 0x77, 0x61, 0x6d, 0x77, 0x65,
+0x6e, 0x64, 0x61, 0x3b, 0x4f, 0x6b, 0x77, 0x61, 0x69, 0x6b, 0x75, 0x6d,
+0x69, 0x3b, 0x4f, 0x6b, 0x77, 0x61, 0x69, 0x6b, 0x75, 0x6d, 0x69, 0x20,
+0x6e, 0x61, 0x20, 0x6b, 0x75, 0x6d, 0x77, 0x65, 0x3b, 0x4f, 0x6b, 0x77,
+0x61, 0x69, 0x6b, 0x75, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x69, 0x62,
+0x69, 0x72, 0x69, 0x4b, 0x42, 0x5a, 0x3b, 0x4b, 0x42, 0x52, 0x3b, 0x4b,
+0x53, 0x54, 0x3b, 0x4b, 0x4b, 0x4e, 0x3b, 0x4b, 0x54, 0x4e, 0x3b, 0x4b,
+0x4d, 0x4b, 0x3b, 0x4b, 0x4d, 0x53, 0x3b, 0x4b, 0x4d, 0x4e, 0x3b, 0x4b,
+0x4d, 0x57, 0x3b, 0x4b, 0x4b, 0x4d, 0x3b, 0x4b, 0x4e, 0x4b, 0x3b, 0x4b,
+0x4e, 0x42, 0x456, 0x486, 0x430, 0x43d, 0x43d, 0xa64b, 0x430, 0x301, 0x440, 0x457,
+0x439, 0x3b, 0x444, 0x435, 0x432, 0x440, 0xa64b, 0x430, 0x301, 0x440, 0x457, 0x439,
+0x3b, 0x43c, 0x430, 0x301, 0x440, 0x442, 0x44a, 0x3b, 0x430, 0x486, 0x43f, 0x440,
+0x456, 0x301, 0x43b, 0x43b, 0x457, 0x439, 0x3b, 0x43c, 0x430, 0x301, 0x457, 0x439,
+0x3b, 0x456, 0x486, 0xa64b, 0x301, 0x43d, 0x457, 0x439, 0x3b, 0x456, 0x486, 0xa64b,
+0x301, 0x43b, 0x457, 0x439, 0x3b, 0x430, 0x486, 0x301, 0x475, 0x433, 0xa64b, 0x441,
+0x442, 0x44a, 0x3b, 0x441, 0x435, 0x43f, 0x442, 0x435, 0x301, 0x43c, 0x432, 0x440,
+0x457, 0x439, 0x3b, 0x47b, 0x486, 0x43a, 0x442, 0x461, 0x301, 0x432, 0x440, 0x457,
+0x439, 0x3b, 0x43d, 0x43e, 0x435, 0x301, 0x43c, 0x432, 0x440, 0x457, 0x439, 0x3b,
+0x434, 0x435, 0x43a, 0x435, 0x301, 0x43c, 0x432, 0x440, 0x457, 0x439, 0x456, 0x486,
+0x430, 0x43d, 0x43d, 0xa64b, 0x430, 0x301, 0x440, 0x457, 0x430, 0x3b, 0x444, 0x435,
+0x432, 0x440, 0xa64b, 0x430, 0x301, 0x440, 0x457, 0x430, 0x3b, 0x43c, 0x430, 0x301,
+0x440, 0x442, 0x430, 0x3b, 0x430, 0x486, 0x43f, 0x440, 0x456, 0x301, 0x43b, 0x43b,
+0x457, 0x430, 0x3b, 0x43c, 0x430, 0x301, 0x457, 0x430, 0x3b, 0x456, 0x486, 0xa64b,
+0x301, 0x43d, 0x457, 0x430, 0x3b, 0x456, 0x486, 0xa64b, 0x301, 0x43b, 0x457, 0x430,
+0x3b, 0x430, 0x486, 0x301, 0x475, 0x433, 0xa64b, 0x441, 0x442, 0x430, 0x3b, 0x441,
+0x435, 0x43f, 0x442, 0x435, 0x301, 0x43c, 0x432, 0x440, 0x457, 0x430, 0x3b, 0x47b,
+0x486, 0x43a, 0x442, 0x461, 0x301, 0x432, 0x440, 0x457, 0x430, 0x3b, 0x43d, 0x43e,
+0x435, 0x301, 0x43c, 0x432, 0x440, 0x457, 0x430, 0x3b, 0x434, 0x435, 0x43a, 0x435,
+0x301, 0x43c, 0x432, 0x440, 0x457, 0x430, 0x456, 0x486, 0x430, 0x2de9, 0x487, 0x3b,
+0x444, 0x435, 0x2de1, 0x487, 0x3b, 0x43c, 0x430, 0x2dec, 0x487, 0x3b, 0x430, 0x486,
+0x43f, 0x2dec, 0x487, 0x3b, 0x43c, 0x430, 0xa675, 0x3b, 0x456, 0x486, 0xa64b, 0x2de9,
+0x487, 0x3b, 0x456, 0x486, 0xa64b, 0x2de7, 0x487, 0x3b, 0x430, 0x486, 0x301, 0x475,
+0x2de2, 0x487, 0x3b, 0x441, 0x435, 0x2deb, 0x487, 0x3b, 0x47b, 0x486, 0x43a, 0x2dee,
+0x3b, 0x43d, 0x43e, 0x435, 0x2de8, 0x3b, 0x434, 0x435, 0x2de6, 0x487, 0x406, 0x486,
+0x3b, 0x424, 0x3b, 0x41c, 0x3b, 0x410, 0x486, 0x3b, 0x41c, 0x3b, 0x406, 0x486,
+0x3b, 0x406, 0x486, 0x3b, 0x410, 0x486, 0x3b, 0x421, 0x3b, 0x47a, 0x486, 0x3b,
+0x41d, 0x3b, 0x414, 0x43a, 0x4d1, 0x440, 0x43b, 0x430, 0x447, 0x3b, 0x43d, 0x430,
+0x440, 0x4d1, 0x441, 0x3b, 0x43f, 0x443, 0x448, 0x3b, 0x430, 0x43a, 0x430, 0x3b,
+0x4ab, 0x443, 0x3b, 0x4ab, 0x4d7, 0x440, 0x442, 0x43c, 0x435, 0x3b, 0x443, 0x442,
+0x4d1, 0x3b, 0x4ab, 0x443, 0x440, 0x43b, 0x430, 0x3b, 0x430, 0x432, 0x4d1, 0x43d,
+0x3b, 0x44e, 0x43f, 0x430, 0x3b, 0x447, 0x4f3, 0x43a, 0x3b, 0x440, 0x430, 0x448,
+0x442, 0x430, 0x432, 0x43a, 0x4d1, 0x440, 0x2e, 0x3b, 0x43d, 0x430, 0x440, 0x2e,
+0x3b, 0x43f, 0x443, 0x448, 0x3b, 0x430, 0x43a, 0x430, 0x3b, 0x4ab, 0x443, 0x3b,
+0x4ab, 0x4d7, 0x440, 0x2e, 0x3b, 0x443, 0x442, 0x4d1, 0x3b, 0x4ab, 0x443, 0x440,
+0x2e, 0x3b, 0x430, 0x432, 0x4d1, 0x43d, 0x3b, 0x44e, 0x43f, 0x430, 0x3b, 0x447,
+0x4f3, 0x43a, 0x3b, 0x440, 0x430, 0x448, 0x2e, 0x41a, 0x3b, 0x41d, 0x3b, 0x41f,
+0x3b, 0x410, 0x3b, 0x4aa, 0x3b, 0x4aa, 0x3b, 0x423, 0x3b, 0x4aa, 0x3b, 0x410,
+0x3b, 0x42e, 0x3b, 0x427, 0x3b, 0x420, 0x4a, 0x61, 0x6e, 0x6e, 0x65, 0x77,
+0x61, 0x3b, 0x46, 0xe4, 0x62, 0x72, 0x6f, 0x77, 0x61, 0x3b, 0x4d, 0xe4,
+0xe4, 0x7a, 0x3b, 0x41, 0x70, 0x72, 0x65, 0x6c, 0x6c, 0x3b, 0x4d, 0x61,
+0x69, 0x3b, 0x4a, 0x75, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x75, 0x6c,
+0x69, 0x3b, 0x4f, 0x75, 0x6a, 0x6f, 0xdf, 0x3b, 0x53, 0x65, 0x70, 0x74,
+0xe4, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x68, 0x62,
+0x65, 0x72, 0x3b, 0x4e, 0x6f, 0x76, 0xe4, 0x6d, 0x62, 0x65, 0x72, 0x3b,
+0x44, 0x65, 0x7a, 0xe4, 0x6d, 0x62, 0x65, 0x72, 0x4a, 0x61, 0x6e, 0x2e,
+0x3b, 0x46, 0xe4, 0x62, 0x2e, 0x3b, 0x4d, 0xe4, 0x7a, 0x2e, 0x3b, 0x41,
+0x70, 0x72, 0x2e, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x2e,
+0x3b, 0x4a, 0x75, 0x6c, 0x2e, 0x3b, 0x4f, 0x75, 0x6a, 0x2e, 0x3b, 0x53,
+0xe4, 0x70, 0x2e, 0x3b, 0x4f, 0x6b, 0x74, 0x2e, 0x3b, 0x4e, 0x6f, 0x76,
+0x2e, 0x3b, 0x44, 0x65, 0x7a, 0x2e, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0xe4,
+0x62, 0x3b, 0x4d, 0xe4, 0x7a, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x61,
+0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x4f, 0x75,
+0x6a, 0x3b, 0x53, 0xe4, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f,
+0x76, 0x3b, 0x44, 0x65, 0x7a, 0x4a, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41,
+0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x4f, 0x3b, 0x53, 0x3b, 0x4f,
+0x3b, 0x4e, 0x3b, 0x44, 0x6d, 0x69, 0x73, 0x20, 0x47, 0x65, 0x6e, 0x76,
+0x65, 0x72, 0x3b, 0x6d, 0x69, 0x73, 0x20, 0x48, 0x77, 0x65, 0x76, 0x72,
+0x65, 0x72, 0x3b, 0x6d, 0x69, 0x73, 0x20, 0x4d, 0x65, 0x75, 0x72, 0x74,
+0x68, 0x3b, 0x6d, 0x69, 0x73, 0x20, 0x45, 0x62, 0x72, 0x65, 0x6c, 0x3b,
+0x6d, 0x69, 0x73, 0x20, 0x4d, 0x65, 0x3b, 0x6d, 0x69, 0x73, 0x20, 0x4d,
+0x65, 0x74, 0x68, 0x65, 0x76, 0x65, 0x6e, 0x3b, 0x6d, 0x69, 0x73, 0x20,
+0x47, 0x6f, 0x72, 0x74, 0x68, 0x65, 0x72, 0x65, 0x6e, 0x3b, 0x6d, 0x69,
+0x73, 0x20, 0x45, 0x73, 0x74, 0x3b, 0x6d, 0x69, 0x73, 0x20, 0x47, 0x77,
+0x79, 0x6e, 0x6e, 0x67, 0x61, 0x6c, 0x61, 0x3b, 0x6d, 0x69, 0x73, 0x20,
+0x48, 0x65, 0x64, 0x72, 0x61, 0x3b, 0x6d, 0x69, 0x73, 0x20, 0x44, 0x75,
+0x3b, 0x6d, 0x69, 0x73, 0x20, 0x4b, 0x65, 0x76, 0x61, 0x72, 0x64, 0x68,
+0x75, 0x47, 0x65, 0x6e, 0x3b, 0x48, 0x77, 0x65, 0x3b, 0x4d, 0x65, 0x75,
+0x3b, 0x45, 0x62, 0x72, 0x3b, 0x4d, 0x65, 0x3b, 0x4d, 0x65, 0x74, 0x3b,
+0x47, 0x6f, 0x72, 0x3b, 0x45, 0x73, 0x74, 0x3b, 0x47, 0x77, 0x6e, 0x3b,
+0x48, 0x65, 0x64, 0x3b, 0x44, 0x75, 0x3b, 0x4b, 0x65, 0x76, 0x67, 0x68,
+0x6a, 0x65, 0x6e, 0x6e, 0x61, 0x67, 0x68, 0x6a, 0x75, 0x3b, 0x66, 0x65,
+0x72, 0x72, 0x61, 0x67, 0x68, 0x6a, 0x75, 0x3b, 0x6d, 0x61, 0x72, 0x7a,
+0x75, 0x3b, 0x61, 0x70, 0x72, 0x69, 0x6c, 0x65, 0x3b, 0x6d, 0x61, 0x67,
+0x68, 0x6a, 0x75, 0x3b, 0x67, 0x68, 0x6a, 0x75, 0x67, 0x6e, 0x75, 0x3b,
+0x6c, 0x75, 0x67, 0x6c, 0x69, 0x75, 0x3b, 0x61, 0x6f, 0x73, 0x74, 0x75,
+0x3b, 0x73, 0x69, 0x74, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x6f,
+0x74, 0x74, 0x6f, 0x62, 0x72, 0x65, 0x3b, 0x6e, 0x75, 0x76, 0x65, 0x6d,
+0x62, 0x72, 0x65, 0x3b, 0x64, 0x69, 0x63, 0x65, 0x6d, 0x62, 0x72, 0x65,
+0x64, 0x69, 0x20, 0x67, 0x68, 0x6a, 0x65, 0x6e, 0x6e, 0x61, 0x67, 0x68,
+0x6a, 0x75, 0x3b, 0x64, 0x69, 0x20, 0x66, 0x65, 0x72, 0x72, 0x61, 0x67,
+0x68, 0x6a, 0x75, 0x3b, 0x64, 0x69, 0x20, 0x6d, 0x61, 0x72, 0x7a, 0x75,
+0x3b, 0x64, 0x2019, 0x61, 0x70, 0x72, 0x69, 0x6c, 0x65, 0x3b, 0x64, 0x69,
+0x20, 0x6d, 0x61, 0x67, 0x68, 0x6a, 0x75, 0x3b, 0x64, 0x69, 0x20, 0x67,
+0x68, 0x6a, 0x75, 0x67, 0x6e, 0x75, 0x3b, 0x64, 0x69, 0x20, 0x6c, 0x75,
+0x67, 0x6c, 0x69, 0x75, 0x3b, 0x64, 0x2019, 0x61, 0x6f, 0x73, 0x74, 0x75,
+0x3b, 0x64, 0x69, 0x20, 0x73, 0x69, 0x74, 0x74, 0x65, 0x6d, 0x62, 0x72,
+0x65, 0x3b, 0x64, 0x2019, 0x6f, 0x74, 0x74, 0x6f, 0x62, 0x72, 0x65, 0x3b,
+0x64, 0x69, 0x20, 0x6e, 0x75, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b,
+0x64, 0x69, 0x20, 0x64, 0x69, 0x63, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x67,
+0x68, 0x6a, 0x2e, 0x3b, 0x66, 0x65, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x72,
+0x2e, 0x3b, 0x61, 0x70, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x67, 0x2e, 0x3b,
+0x67, 0x68, 0x6a, 0x75, 0x2e, 0x3b, 0x6c, 0x75, 0x67, 0x2e, 0x3b, 0x61,
+0x6f, 0x73, 0x2e, 0x3b, 0x73, 0x69, 0x74, 0x2e, 0x3b, 0x6f, 0x74, 0x74,
+0x2e, 0x3b, 0x6e, 0x75, 0x76, 0x2e, 0x3b, 0x64, 0x69, 0x63, 0x2e, 0x47,
+0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x47, 0x3b, 0x4c,
+0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x73, 0x69,
+0x6a, 0x65, 0x10d, 0x61, 0x6e, 0x6a, 0x3b, 0x76, 0x65, 0x6c, 0x6a, 0x61,
+0x10d, 0x61, 0x3b, 0x6f, 0x17e, 0x75, 0x6a, 0x61, 0x6b, 0x3b, 0x74, 0x72,
+0x61, 0x76, 0x61, 0x6e, 0x6a, 0x3b, 0x73, 0x76, 0x69, 0x62, 0x61, 0x6e,
+0x6a, 0x3b, 0x6c, 0x69, 0x70, 0x61, 0x6e, 0x6a, 0x3b, 0x73, 0x72, 0x70,
+0x61, 0x6e, 0x6a, 0x3b, 0x6b, 0x6f, 0x6c, 0x6f, 0x76, 0x6f, 0x7a, 0x3b,
+0x72, 0x75, 0x6a, 0x61, 0x6e, 0x3b, 0x6c, 0x69, 0x73, 0x74, 0x6f, 0x70,
+0x61, 0x64, 0x3b, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x69, 0x3b, 0x70,
+0x72, 0x6f, 0x73, 0x69, 0x6e, 0x61, 0x63, 0x73, 0x69, 0x6a, 0x65, 0x10d,
+0x6e, 0x6a, 0x61, 0x3b, 0x76, 0x65, 0x6c, 0x6a, 0x61, 0x10d, 0x65, 0x3b,
+0x6f, 0x17e, 0x75, 0x6a, 0x6b, 0x61, 0x3b, 0x74, 0x72, 0x61, 0x76, 0x6e,
+0x6a, 0x61, 0x3b, 0x73, 0x76, 0x69, 0x62, 0x6e, 0x6a, 0x61, 0x3b, 0x6c,
+0x69, 0x70, 0x6e, 0x6a, 0x61, 0x3b, 0x73, 0x72, 0x70, 0x6e, 0x6a, 0x61,
+0x3b, 0x6b, 0x6f, 0x6c, 0x6f, 0x76, 0x6f, 0x7a, 0x61, 0x3b, 0x72, 0x75,
+0x6a, 0x6e, 0x61, 0x3b, 0x6c, 0x69, 0x73, 0x74, 0x6f, 0x70, 0x61, 0x64,
+0x61, 0x3b, 0x73, 0x74, 0x75, 0x64, 0x65, 0x6e, 0x6f, 0x67, 0x61, 0x3b,
+0x70, 0x72, 0x6f, 0x73, 0x69, 0x6e, 0x63, 0x61, 0x73, 0x69, 0x6a, 0x3b,
+0x76, 0x65, 0x6c, 0x6a, 0x3b, 0x6f, 0x17e, 0x75, 0x3b, 0x74, 0x72, 0x61,
+0x3b, 0x73, 0x76, 0x69, 0x3b, 0x6c, 0x69, 0x70, 0x3b, 0x73, 0x72, 0x70,
+0x3b, 0x6b, 0x6f, 0x6c, 0x3b, 0x72, 0x75, 0x6a, 0x3b, 0x6c, 0x69, 0x73,
+0x3b, 0x73, 0x74, 0x75, 0x3b, 0x70, 0x72, 0x6f, 0x31, 0x2e, 0x3b, 0x32,
+0x2e, 0x3b, 0x33, 0x2e, 0x3b, 0x34, 0x2e, 0x3b, 0x35, 0x2e, 0x3b, 0x36,
+0x2e, 0x3b, 0x37, 0x2e, 0x3b, 0x38, 0x2e, 0x3b, 0x39, 0x2e, 0x3b, 0x31,
+0x30, 0x2e, 0x3b, 0x31, 0x31, 0x2e, 0x3b, 0x31, 0x32, 0x2e, 0x6c, 0x65,
+0x64, 0x65, 0x6e, 0x3b, 0xfa, 0x6e, 0x6f, 0x72, 0x3b, 0x62, 0x159, 0x65,
+0x7a, 0x65, 0x6e, 0x3b, 0x64, 0x75, 0x62, 0x65, 0x6e, 0x3b, 0x6b, 0x76,
+0x11b, 0x74, 0x65, 0x6e, 0x3b, 0x10d, 0x65, 0x72, 0x76, 0x65, 0x6e, 0x3b,
+0x10d, 0x65, 0x72, 0x76, 0x65, 0x6e, 0x65, 0x63, 0x3b, 0x73, 0x72, 0x70,
+0x65, 0x6e, 0x3b, 0x7a, 0xe1, 0x159, 0xed, 0x3b, 0x159, 0xed, 0x6a, 0x65,
+0x6e, 0x3b, 0x6c, 0x69, 0x73, 0x74, 0x6f, 0x70, 0x61, 0x64, 0x3b, 0x70,
+0x72, 0x6f, 0x73, 0x69, 0x6e, 0x65, 0x63, 0x6c, 0x65, 0x64, 0x6e, 0x61,
+0x3b, 0xfa, 0x6e, 0x6f, 0x72, 0x61, 0x3b, 0x62, 0x159, 0x65, 0x7a, 0x6e,
+0x61, 0x3b, 0x64, 0x75, 0x62, 0x6e, 0x61, 0x3b, 0x6b, 0x76, 0x11b, 0x74,
+0x6e, 0x61, 0x3b, 0x10d, 0x65, 0x72, 0x76, 0x6e, 0x61, 0x3b, 0x10d, 0x65,
+0x72, 0x76, 0x65, 0x6e, 0x63, 0x65, 0x3b, 0x73, 0x72, 0x70, 0x6e, 0x61,
+0x3b, 0x7a, 0xe1, 0x159, 0xed, 0x3b, 0x159, 0xed, 0x6a, 0x6e, 0x61, 0x3b,
+0x6c, 0x69, 0x73, 0x74, 0x6f, 0x70, 0x61, 0x64, 0x75, 0x3b, 0x70, 0x72,
+0x6f, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x3b, 0xfa, 0x6e,
+0x6f, 0x3b, 0x62, 0x159, 0x65, 0x3b, 0x64, 0x75, 0x62, 0x3b, 0x6b, 0x76,
+0x11b, 0x3b, 0x10d, 0x76, 0x6e, 0x3b, 0x10d, 0x76, 0x63, 0x3b, 0x73, 0x72,
+0x70, 0x3b, 0x7a, 0xe1, 0x159, 0x3b, 0x159, 0xed, 0x6a, 0x3b, 0x6c, 0x69,
+0x73, 0x3b, 0x70, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x3b,
+0x66, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0x74,
+0x73, 0x3b, 0x61, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x61, 0x6a, 0x3b,
+0x6a, 0x75, 0x6e, 0x69, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x3b, 0x61, 0x75,
+0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62,
+0x65, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x6e,
+0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x64, 0x65, 0x63, 0x65,
+0x6d, 0x62, 0x65, 0x72, 0x6a, 0x61, 0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x62,
+0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x61, 0x70, 0x72, 0x2e, 0x3b,
+0x6d, 0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x2e, 0x3b, 0x6a, 0x75, 0x6c,
+0x2e, 0x3b, 0x61, 0x75, 0x67, 0x2e, 0x3b, 0x73, 0x65, 0x70, 0x2e, 0x3b,
+0x6f, 0x6b, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65,
+0x63, 0x2e, 0x91c, 0x928, 0x935, 0x930, 0x940, 0x3b, 0x92b, 0x930, 0x935, 0x930,
+0x940, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930,
+0x948, 0x932, 0x3b, 0x92e, 0x947, 0x908, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c,
+0x941, 0x932, 0x93e, 0x908, 0x3b, 0x905, 0x917, 0x938, 0x94d, 0x924, 0x3b, 0x938,
+0x93f, 0x924, 0x902, 0x92c, 0x930, 0x3b, 0x905, 0x915, 0x94d, 0x924, 0x942, 0x92c,
+0x930, 0x3b, 0x928, 0x935, 0x902, 0x92c, 0x930, 0x3b, 0x926, 0x93f, 0x938, 0x902,
+0x92c, 0x930, 0x91c, 0x928, 0x2e, 0x3b, 0x92b, 0x930, 0x2e, 0x3b, 0x92e, 0x93e,
+0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x948, 0x932, 0x3b, 0x92e,
+0x947, 0x908, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x93e, 0x908,
+0x3b, 0x905, 0x917, 0x2e, 0x3b, 0x938, 0x93f, 0x924, 0x2e, 0x3b, 0x905, 0x915,
+0x94d, 0x924, 0x942, 0x2e, 0x3b, 0x928, 0x935, 0x2e, 0x3b, 0x926, 0x93f, 0x938,
+0x2e, 0x91c, 0x3b, 0x92b, 0x3b, 0x92e, 0x93e, 0x3b, 0x905, 0x3b, 0x92e, 0x947,
+0x3b, 0x91c, 0x942, 0x3b, 0x91c, 0x941, 0x3b, 0x905, 0x3b, 0x938, 0x93f, 0x3b,
+0x905, 0x3b, 0x928, 0x3b, 0x926, 0x93f, 0x64, 0x69, 0x6d, 0x254, 0x301, 0x64,
+0x69, 0x3b, 0x14b, 0x67, 0x254, 0x6e, 0x64, 0x25b, 0x3b, 0x73, 0x254, 0x14b,
+0x25b, 0x3b, 0x64, 0x69, 0x253, 0xe1, 0x253, 0xe1, 0x3b, 0x65, 0x6d, 0x69,
+0x61, 0x73, 0x65, 0x6c, 0x65, 0x3b, 0x65, 0x73, 0x254, 0x70, 0x25b, 0x73,
+0x254, 0x70, 0x25b, 0x3b, 0x6d, 0x61, 0x64, 0x69, 0x253, 0x25b, 0x301, 0x64,
+0xed, 0x253, 0x25b, 0x301, 0x3b, 0x64, 0x69, 0x14b, 0x67, 0x69, 0x6e, 0x64,
+0x69, 0x3b, 0x6e, 0x79, 0x25b, 0x74, 0x25b, 0x6b, 0x69, 0x3b, 0x6d, 0x61,
+0x79, 0xe9, 0x73, 0x25b, 0x301, 0x3b, 0x74, 0x69, 0x6e, 0xed, 0x6e, 0xed,
+0x3b, 0x65, 0x6c, 0xe1, 0x14b, 0x67, 0x25b, 0x301, 0x64, 0x69, 0x3b, 0x14b,
+0x67, 0x254, 0x6e, 0x3b, 0x73, 0x254, 0x14b, 0x3b, 0x64, 0x69, 0x253, 0x3b,
+0x65, 0x6d, 0x69, 0x3b, 0x65, 0x73, 0x254, 0x3b, 0x6d, 0x61, 0x64, 0x3b,
+0x64, 0x69, 0x14b, 0x3b, 0x6e, 0x79, 0x25b, 0x74, 0x3b, 0x6d, 0x61, 0x79,
+0x3b, 0x74, 0x69, 0x6e, 0x3b, 0x65, 0x6c, 0xe1, 0x64, 0x3b, 0x14b, 0x3b,
+0x73, 0x3b, 0x64, 0x3b, 0x65, 0x3b, 0x65, 0x3b, 0x6d, 0x3b, 0x64, 0x3b,
+0x6e, 0x3b, 0x6d, 0x3b, 0x74, 0x3b, 0x65, 0x6a, 0x61, 0x6e, 0x75, 0x61,
+0x72, 0x69, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x69, 0x3b,
+0x6d, 0x61, 0x61, 0x72, 0x74, 0x3b, 0x61, 0x70, 0x72, 0x69, 0x6c, 0x3b,
+0x6d, 0x65, 0x69, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x3b, 0x6a, 0x75, 0x6c,
+0x69, 0x3b, 0x61, 0x75, 0x67, 0x75, 0x73, 0x74, 0x75, 0x73, 0x3b, 0x73,
+0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x6f, 0x6b, 0x74,
+0x6f, 0x62, 0x65, 0x72, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65,
+0x72, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x6a, 0x61,
+0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0x72, 0x74, 0x3b, 0x61, 0x70,
+0x72, 0x3b, 0x6d, 0x65, 0x69, 0x3b, 0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75,
+0x6c, 0x3b, 0x61, 0x75, 0x67, 0x3b, 0x73, 0x65, 0x70, 0x3b, 0x6f, 0x6b,
+0x74, 0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65, 0x63, 0xf66, 0xfa4, 0xfb1,
+0xf72, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf51, 0xf44, 0xf54, 0xf0b, 0x3b, 0xf66, 0xfa4,
+0xfb1, 0xf72, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf42, 0xf49, 0xf72, 0xf66, 0xf0b, 0xf54,
+0xf0b, 0x3b, 0xf66, 0xfa4, 0xfb1, 0xf72, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf42, 0xf66,
+0xf74, 0xf58, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf66, 0xfa4, 0xfb1, 0xf72, 0xf0b, 0xf5f,
+0xfb3, 0xf0b, 0xf56, 0xf5e, 0xf72, 0xf0b, 0xf54, 0x3b, 0xf66, 0xfa4, 0xfb1, 0xf72,
+0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf63, 0xf94, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf66, 0xfa4,
+0xfb1, 0xf72, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf51, 0xfb2, 0xf74, 0xf42, 0xf0b, 0xf54,
+0x3b, 0xf66, 0xfa4, 0xfb1, 0xf72, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf51, 0xf74,
+0xf53, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf66, 0xfa4, 0xfb1, 0xf72, 0xf0b, 0xf5f, 0xfb3,
+0xf0b, 0xf56, 0xf62, 0xf92, 0xfb1, 0xf51, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf66, 0xfa4,
+0xfb1, 0xf72, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf51, 0xf42, 0xf74, 0xf0b, 0xf54, 0xf0b,
+0x3b, 0xf66, 0xfa4, 0xfb1, 0xf72, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf45, 0xf74,
+0xf0b, 0xf54, 0xf0b, 0x3b, 0xf66, 0xfa4, 0xfb1, 0xf72, 0xf0b, 0xf5f, 0xfb3, 0xf0b,
+0xf56, 0xf45, 0xf74, 0xf0b, 0xf42, 0xf45, 0xf72, 0xf42, 0xf0b, 0xf54, 0xf0b, 0x3b,
+0xf66, 0xfa4, 0xfb1, 0xf72, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf45, 0xf74, 0xf0b,
+0xf42, 0xf49, 0xf72, 0xf66, 0xf0b, 0xf54, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf51, 0xf44,
+0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf42, 0xf49, 0xf72, 0xf66, 0xf0b, 0xf54,
+0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf42, 0xf66, 0xf74, 0xf58, 0xf0b, 0xf54, 0xf0b,
+0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf5e, 0xf72, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f,
+0xfb3, 0xf0b, 0xf63, 0xf94, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf51,
+0xfb2, 0xf74, 0xf42, 0xf0b, 0xf54, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf51, 0xf74,
+0xf53, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf62, 0xf92, 0xfb1,
+0xf51, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf51, 0xf42, 0xf74, 0xf0b,
+0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf45, 0xf74, 0xf0b, 0xf54, 0xf0b,
+0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf45, 0xf74, 0xf0b, 0xf42, 0xf45, 0xf72, 0xf42,
+0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf45, 0xf74, 0xf0b, 0xf42,
+0xf49, 0xf72, 0xf66, 0xf0b, 0xf54, 0xf0b, 0xf5f, 0xfb3, 0xf0b, 0xf21, 0x3b, 0xf5f,
+0xfb3, 0xf0b, 0xf22, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf23, 0x3b, 0xf5f, 0xfb3, 0xf0b,
+0xf24, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf25, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf26, 0x3b,
+0xf5f, 0xfb3, 0xf0b, 0xf27, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf28, 0x3b, 0xf5f, 0xfb3,
+0xf0b, 0xf29, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf21, 0xf20, 0x3b, 0xf5f, 0xfb3, 0xf0b,
+0xf21, 0xf21, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf21, 0xf22, 0xf21, 0x3b, 0xf22, 0x3b,
+0xf23, 0x3b, 0xf24, 0x3b, 0xf25, 0x3b, 0xf26, 0x3b, 0xf27, 0x3b, 0xf28, 0x3b,
+0xf29, 0x3b, 0xf21, 0xf20, 0x3b, 0xf21, 0xf21, 0x3b, 0x31, 0x32, 0xf21, 0x3b,
+0xf22, 0x3b, 0xf23, 0x3b, 0xf24, 0x3b, 0xf25, 0x3b, 0xf26, 0x3b, 0xf27, 0x3b,
+0xf28, 0x3b, 0xf29, 0x3b, 0xf21, 0xf20, 0x3b, 0xf21, 0xf21, 0x3b, 0xf21, 0xf22,
+0xf21, 0x3b, 0xf22, 0x3b, 0xf23, 0x3b, 0x34, 0x3b, 0xf25, 0x3b, 0xf26, 0x3b,
+0xf27, 0x3b, 0xf28, 0x3b, 0x39, 0x3b, 0xf21, 0xf20, 0x3b, 0xf21, 0xf21, 0x3b,
+0xf21, 0xf22, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6d,
+0x62, 0x65, 0x72, 0x65, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77,
+0x61, 0x20, 0x6b, 0x61, 0x129, 0x72, 0x69, 0x3b, 0x4d, 0x77, 0x65, 0x72,
+0x69, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x74, 0x68, 0x61, 0x74, 0x169,
+0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x61,
+0x6e, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20,
+0x67, 0x61, 0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69,
+0x20, 0x77, 0x61, 0x20, 0x67, 0x61, 0x74, 0x61, 0x6e, 0x74, 0x61, 0x74,
+0x169, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6d,
+0x169, 0x67, 0x77, 0x61, 0x6e, 0x6a, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72,
+0x69, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x3b,
+0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x65, 0x6e,
+0x64, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20,
+0x69, 0x6b, 0x169, 0x6d, 0x69, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20,
+0x77, 0x61, 0x20, 0x69, 0x6b, 0x169, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20,
+0x169, 0x6d, 0x77, 0x65, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77,
+0x61, 0x20, 0x69, 0x6b, 0x169, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x4b,
+0x61, 0x129, 0x72, 0x129, 0x4d, 0x62, 0x65, 0x3b, 0x4b, 0x61, 0x69, 0x3b,
+0x4b, 0x61, 0x74, 0x3b, 0x4b, 0x61, 0x6e, 0x3b, 0x47, 0x61, 0x74, 0x3b,
+0x47, 0x61, 0x6e, 0x3b, 0x4d, 0x75, 0x67, 0x3b, 0x4b, 0x6e, 0x6e, 0x3b,
+0x4b, 0x65, 0x6e, 0x3b, 0x49, 0x6b, 0x75, 0x3b, 0x49, 0x6d, 0x77, 0x3b,
+0x49, 0x67, 0x69, 0x4d, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x47,
+0x3b, 0x47, 0x3b, 0x4d, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x49, 0x3b, 0x49,
+0x3b, 0x49, 0xd801, 0xdc16, 0xd801, 0xdc30, 0xd801, 0xdc4c, 0xd801, 0xdc37, 0xd801, 0xdc2d,
+0xd801, 0xdc2f, 0xd801, 0xdc49, 0xd801, 0xdc28, 0x3b, 0xd801, 0xdc19, 0xd801, 0xdc2f, 0xd801,
+0xdc3a, 0xd801, 0xdc49, 0xd801, 0xdc2d, 0xd801, 0xdc2f, 0xd801, 0xdc49, 0xd801, 0xdc28, 0x3b,
+0xd801, 0xdc23, 0xd801, 0xdc2a, 0xd801, 0xdc49, 0xd801, 0xdc3d, 0x3b, 0xd801, 0xdc01, 0xd801,
+0xdc39, 0xd801, 0xdc49, 0xd801, 0xdc2e, 0xd801, 0xdc4a, 0x3b, 0xd801, 0xdc23, 0xd801, 0xdc29,
+0x3b, 0xd801, 0xdc16, 0xd801, 0xdc2d, 0xd801, 0xdc4c, 0x3b, 0xd801, 0xdc16, 0xd801, 0xdc2d,
+0xd801, 0xdc4a, 0xd801, 0xdc34, 0x3b, 0xd801, 0xdc02, 0xd801, 0xdc40, 0xd801, 0xdc32, 0xd801,
+0xdc45, 0xd801, 0xdc3b, 0x3b, 0xd801, 0xdc1d, 0xd801, 0xdc2f, 0xd801, 0xdc39, 0xd801, 0xdc3b,
+0xd801, 0xdc2f, 0xd801, 0xdc4b, 0xd801, 0xdc3a, 0xd801, 0xdc32, 0xd801, 0xdc49, 0x3b, 0xd801,
+0xdc09, 0xd801, 0xdc3f, 0xd801, 0xdc3b, 0xd801, 0xdc2c, 0xd801, 0xdc3a, 0xd801, 0xdc32, 0xd801,
+0xdc49, 0x3b, 0xd801, 0xdc24, 0xd801, 0xdc2c, 0xd801, 0xdc42, 0xd801, 0xdc2f, 0xd801, 0xdc4b,
+0xd801, 0xdc3a, 0xd801, 0xdc32, 0xd801, 0xdc49, 0x3b, 0xd801, 0xdc14, 0xd801, 0xdc28, 0xd801,
+0xdc45, 0xd801, 0xdc2f, 0xd801, 0xdc4b, 0xd801, 0xdc3a, 0xd801, 0xdc32, 0xd801, 0xdc49, 0xd801,
+0xdc16, 0xd801, 0xdc30, 0xd801, 0xdc4c, 0x3b, 0xd801, 0xdc19, 0xd801, 0xdc2f, 0xd801, 0xdc3a,
+0x3b, 0xd801, 0xdc23, 0xd801, 0xdc2a, 0xd801, 0xdc49, 0x3b, 0xd801, 0xdc01, 0xd801, 0xdc39,
+0xd801, 0xdc49, 0x3b, 0xd801, 0xdc23, 0xd801, 0xdc29, 0x3b, 0xd801, 0xdc16, 0xd801, 0xdc2d,
+0xd801, 0xdc4c, 0x3b, 0xd801, 0xdc16, 0xd801, 0xdc2d, 0xd801, 0xdc4a, 0x3b, 0xd801, 0xdc02,
+0xd801, 0xdc40, 0x3b, 0xd801, 0xdc1d, 0xd801, 0xdc2f, 0xd801, 0xdc39, 0x3b, 0xd801, 0xdc09,
+0xd801, 0xdc3f, 0xd801, 0xdc3b, 0x3b, 0xd801, 0xdc24, 0xd801, 0xdc2c, 0xd801, 0xdc42, 0x3b,
+0xd801, 0xdc14, 0xd801, 0xdc28, 0xd801, 0xdc45, 0xd801, 0xdc16, 0x3b, 0xd801, 0xdc19, 0x3b,
+0xd801, 0xdc23, 0x3b, 0xd801, 0xdc01, 0x3b, 0xd801, 0xdc23, 0x3b, 0xd801, 0xdc16, 0x3b,
+0xd801, 0xdc16, 0x3b, 0xd801, 0xdc02, 0x3b, 0xd801, 0xdc1d, 0x3b, 0xd801, 0xdc09, 0x3b,
+0xd801, 0xdc24, 0x3b, 0xd801, 0xdc14, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62,
+0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x61, 0x79,
+0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x75, 0x67,
+0x3b, 0x53, 0x65, 0x70, 0x74, 0x3b, 0x4f, 0x63, 0x74, 0x3b, 0x4e, 0x6f,
+0x76, 0x3b, 0x44, 0x65, 0x63, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62,
+0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x61, 0x79,
+0x3b, 0x4a, 0x75, 0x6e, 0x65, 0x3b, 0x4a, 0x75, 0x6c, 0x79, 0x3b, 0x41,
+0x75, 0x67, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x3b, 0x4f, 0x63, 0x74, 0x3b,
+0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x63, 0xb7, 0xd801, 0xdc61, 0xd801, 0xdc68,
+0xd801, 0xdc59, 0xd801, 0xdc58, 0xd801, 0xdc6d, 0xd801, 0xdc62, 0xd801, 0xdc7a, 0xd801, 0xdc70,
+0x3b, 0xb7, 0xd801, 0xdc53, 0xd801, 0xdc67, 0xd801, 0xdc5a, 0xd801, 0xdc58, 0xd801, 0xdc75,
+0xd801, 0xdc62, 0xd801, 0xdc7a, 0xd801, 0xdc70, 0x3b, 0xb7, 0xd801, 0xdc65, 0xd801, 0xdc78,
+0xd801, 0xdc57, 0x3b, 0xb7, 0xd801, 0xdc71, 0xd801, 0xdc50, 0xd801, 0xdc6e, 0xd801, 0xdc6d,
+0xd801, 0xdc64, 0x3b, 0xb7, 0xd801, 0xdc65, 0xd801, 0xdc71, 0x3b, 0xb7, 0xd801, 0xdc61,
+0xd801, 0xdc75, 0xd801, 0xdc6f, 0x3b, 0xb7, 0xd801, 0xdc61, 0xd801, 0xdc6b, 0xd801, 0xdc64,
+0xd801, 0xdc72, 0x3b, 0xb7, 0xd801, 0xdc6a, 0xd801, 0xdc5c, 0xd801, 0xdc6d, 0xd801, 0xdc55,
+0xd801, 0xdc51, 0x3b, 0xb7, 0xd801, 0xdc55, 0xd801, 0xdc67, 0xd801, 0xdc50, 0xd801, 0xdc51,
+0xd801, 0xdc67, 0xd801, 0xdc65, 0xd801, 0xdc5a, 0xd801, 0xdc78, 0x3b, 0xb7, 0xd801, 0xdc77,
+0xd801, 0xdc52, 0xd801, 0xdc51, 0xd801, 0xdc74, 0xd801, 0xdc5a, 0xd801, 0xdc78, 0x3b, 0xb7,
+0xd801, 0xdc6f, 0xd801, 0xdc74, 0xd801, 0xdc5d, 0xd801, 0xdc67, 0xd801, 0xdc65, 0xd801, 0xdc5a,
+0xd801, 0xdc78, 0x3b, 0xb7, 0xd801, 0xdc5b, 0xd801, 0xdc6d, 0xd801, 0xdc55, 0xd801, 0xdc67,
+0xd801, 0xdc65, 0xd801, 0xdc5a, 0xd801, 0xdc78, 0xb7, 0xd801, 0xdc61, 0xd801, 0xdc68, 0x3b,
+0xb7, 0xd801, 0xdc53, 0xd801, 0xdc67, 0x3b, 0xb7, 0xd801, 0xdc65, 0xd801, 0xdc78, 0x3b,
+0xb7, 0xd801, 0xdc71, 0xd801, 0xdc50, 0x3b, 0xb7, 0xd801, 0xdc65, 0xd801, 0xdc71, 0x3b,
+0xb7, 0xd801, 0xdc61, 0xd801, 0xdc75, 0x3b, 0xb7, 0xd801, 0xdc61, 0xd801, 0xdc6b, 0x3b,
+0xb7, 0xd801, 0xdc6a, 0xd801, 0xdc5c, 0x3b, 0xb7, 0xd801, 0xdc55, 0xd801, 0xdc67, 0x3b,
+0xb7, 0xd801, 0xdc77, 0xd801, 0xdc52, 0x3b, 0xb7, 0xd801, 0xdc6f, 0xd801, 0xdc74, 0x3b,
+0xb7, 0xd801, 0xdc5b, 0xd801, 0xdc6d, 0xd801, 0xdc61, 0x3b, 0xd801, 0xdc53, 0x3b, 0xd801,
+0xdc65, 0x3b, 0xd801, 0xdc71, 0x3b, 0xd801, 0xdc65, 0x3b, 0xd801, 0xdc61, 0x3b, 0xd801,
+0xdc61, 0x3b, 0xd801, 0xdc6a, 0x3b, 0xd801, 0xdc55, 0x3b, 0xd801, 0xdc77, 0x3b, 0xd801,
+0xdc6f, 0x3b, 0xd801, 0xdc5b, 0x44f, 0x43a, 0x448, 0x430, 0x43c, 0x43a, 0x43e, 0x432,
+0x3b, 0x434, 0x430, 0x432, 0x43e, 0x43b, 0x43a, 0x43e, 0x432, 0x3b, 0x44d, 0x439,
+0x437, 0x44e, 0x440, 0x43a, 0x43e, 0x432, 0x3b, 0x447, 0x430, 0x434, 0x44b, 0x43a,
+0x43e, 0x432, 0x3b, 0x43f, 0x430, 0x43d, 0x436, 0x438, 0x43a, 0x43e, 0x432, 0x3b,
+0x430, 0x448, 0x442, 0x435, 0x43c, 0x43a, 0x43e, 0x432, 0x3b, 0x43c, 0x435, 0x434,
+0x44c, 0x43a, 0x43e, 0x432, 0x3b, 0x443, 0x43c, 0x430, 0x440, 0x44c, 0x43a, 0x43e,
+0x432, 0x3b, 0x442, 0x430, 0x448, 0x442, 0x430, 0x43c, 0x43a, 0x43e, 0x432, 0x3b,
+0x43e, 0x436, 0x43e, 0x43a, 0x43e, 0x432, 0x3b, 0x441, 0x443, 0x43d, 0x434, 0x435,
+0x440, 0x44c, 0x43a, 0x43e, 0x432, 0x3b, 0x430, 0x446, 0x430, 0x43c, 0x43a, 0x43e,
+0x432, 0x44f, 0x43a, 0x448, 0x3b, 0x434, 0x430, 0x432, 0x3b, 0x44d, 0x439, 0x437,
+0x3b, 0x447, 0x430, 0x434, 0x3b, 0x43f, 0x430, 0x43d, 0x3b, 0x430, 0x448, 0x442,
+0x3b, 0x43c, 0x435, 0x434, 0x3b, 0x443, 0x43c, 0x430, 0x3b, 0x442, 0x430, 0x448,
+0x3b, 0x43e, 0x436, 0x43e, 0x3b, 0x441, 0x443, 0x43d, 0x3b, 0x430, 0x446, 0x430,
+0x4a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x6f, 0x3b, 0x46, 0x65, 0x62, 0x72,
+0x75, 0x61, 0x72, 0x6f, 0x3b, 0x4d, 0x61, 0x72, 0x74, 0x6f, 0x3b, 0x41,
+0x70, 0x72, 0x69, 0x6c, 0x6f, 0x3b, 0x4d, 0x61, 0x6a, 0x6f, 0x3b, 0x4a,
+0x75, 0x6e, 0x69, 0x6f, 0x3b, 0x4a, 0x75, 0x6c, 0x69, 0x6f, 0x3b, 0x41,
+0x16d, 0x67, 0x75, 0x73, 0x74, 0x6f, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65,
+0x6d, 0x62, 0x72, 0x6f, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x72, 0x6f,
+0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x6f, 0x3b, 0x44, 0x65,
+0x63, 0x65, 0x6d, 0x62, 0x72, 0x6f, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65,
+0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x61,
+0x6a, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x16d,
+0x67, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f,
+0x76, 0x3b, 0x44, 0x65, 0x63, 0x6a, 0x61, 0x61, 0x6e, 0x75, 0x61, 0x72,
+0x3b, 0x76, 0x65, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x3b, 0x6d, 0xe4,
+0x72, 0x74, 0x73, 0x3b, 0x61, 0x70, 0x72, 0x69, 0x6c, 0x6c, 0x3b, 0x6d,
+0x61, 0x69, 0x3b, 0x6a, 0x75, 0x75, 0x6e, 0x69, 0x3b, 0x6a, 0x75, 0x75,
+0x6c, 0x69, 0x3b, 0x61, 0x75, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65,
+0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x6f,
+0x6f, 0x62, 0x65, 0x72, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65,
+0x72, 0x3b, 0x64, 0x65, 0x74, 0x73, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x6a,
+0x61, 0x61, 0x6e, 0x3b, 0x76, 0x65, 0x65, 0x62, 0x72, 0x3b, 0x6d, 0xe4,
+0x72, 0x74, 0x73, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0x61, 0x69, 0x3b,
+0x6a, 0x75, 0x75, 0x6e, 0x69, 0x3b, 0x6a, 0x75, 0x75, 0x6c, 0x69, 0x3b,
+0x61, 0x75, 0x67, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x3b, 0x6f, 0x6b, 0x74,
+0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65, 0x74, 0x73, 0x4a, 0x3b, 0x56,
+0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x41,
+0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x64, 0x7a, 0x6f, 0x76,
+0x65, 0x3b, 0x64, 0x7a, 0x6f, 0x64, 0x7a, 0x65, 0x3b, 0x74, 0x65, 0x64,
+0x6f, 0x78, 0x65, 0x3b, 0x61, 0x66, 0x254, 0x66, 0x129, 0x65, 0x3b, 0x64,
+0x61, 0x6d, 0x61, 0x3b, 0x6d, 0x61, 0x73, 0x61, 0x3b, 0x73, 0x69, 0x61,
+0x6d, 0x6c, 0x254, 0x6d, 0x3b, 0x64, 0x65, 0x61, 0x73, 0x69, 0x61, 0x6d,
+0x69, 0x6d, 0x65, 0x3b, 0x61, 0x6e, 0x79, 0x254, 0x6e, 0x79, 0x254, 0x3b,
+0x6b, 0x65, 0x6c, 0x65, 0x3b, 0x61, 0x64, 0x65, 0x25b, 0x6d, 0x65, 0x6b,
+0x70, 0x254, 0x78, 0x65, 0x3b, 0x64, 0x7a, 0x6f, 0x6d, 0x65, 0x64, 0x7a,
+0x76, 0x3b, 0x64, 0x7a, 0x64, 0x3b, 0x74, 0x65, 0x64, 0x3b, 0x61, 0x66,
+0x254, 0x3b, 0x64, 0x61, 0x6d, 0x3b, 0x6d, 0x61, 0x73, 0x3b, 0x73, 0x69,
+0x61, 0x3b, 0x64, 0x65, 0x61, 0x3b, 0x61, 0x6e, 0x79, 0x3b, 0x6b, 0x65,
+0x6c, 0x3b, 0x61, 0x64, 0x65, 0x3b, 0x64, 0x7a, 0x6d, 0x64, 0x3b, 0x64,
+0x3b, 0x74, 0x3b, 0x61, 0x3b, 0x64, 0x3b, 0x6d, 0x3b, 0x73, 0x3b, 0x64,
+0x3b, 0x61, 0x3b, 0x6b, 0x3b, 0x61, 0x3b, 0x64, 0x6e, 0x67, 0x254, 0x6e,
+0x20, 0x6f, 0x73, 0xfa, 0x3b, 0x6e, 0x67, 0x254, 0x6e, 0x20, 0x62, 0x25b,
+0x30c, 0x3b, 0x6e, 0x67, 0x254, 0x6e, 0x20, 0x6c, 0xe1, 0x6c, 0x61, 0x3b,
+0x6e, 0x67, 0x254, 0x6e, 0x20, 0x6e, 0x79, 0x69, 0x6e, 0x61, 0x3b, 0x6e,
+0x67, 0x254, 0x6e, 0x20, 0x74, 0xe1, 0x6e, 0x61, 0x3b, 0x6e, 0x67, 0x254,
+0x6e, 0x20, 0x73, 0x61, 0x6d, 0x259, 0x6e, 0x61, 0x3b, 0x6e, 0x67, 0x254,
+0x6e, 0x20, 0x7a, 0x61, 0x6d, 0x67, 0x62, 0xe1, 0x6c, 0x61, 0x3b, 0x6e,
+0x67, 0x254, 0x6e, 0x20, 0x6d, 0x77, 0x6f, 0x6d, 0x3b, 0x6e, 0x67, 0x254,
+0x6e, 0x20, 0x65, 0x62, 0x75, 0x6c, 0xfa, 0x3b, 0x6e, 0x67, 0x254, 0x6e,
+0x20, 0x61, 0x77, 0xf3, 0x6d, 0x3b, 0x6e, 0x67, 0x254, 0x6e, 0x20, 0x61,
+0x77, 0xf3, 0x6d, 0x20, 0x61, 0x69, 0x20, 0x64, 0x7a, 0x69, 0xe1, 0x3b,
+0x6e, 0x67, 0x254, 0x6e, 0x20, 0x61, 0x77, 0xf3, 0x6d, 0x20, 0x61, 0x69,
+0x20, 0x62, 0x25b, 0x30c, 0x6e, 0x67, 0x6f, 0x3b, 0x6e, 0x67, 0x62, 0x3b,
+0x6e, 0x67, 0x6c, 0x3b, 0x6e, 0x67, 0x6e, 0x3b, 0x6e, 0x67, 0x74, 0x3b,
+0x6e, 0x67, 0x73, 0x3b, 0x6e, 0x67, 0x7a, 0x3b, 0x6e, 0x67, 0x6d, 0x3b,
+0x6e, 0x67, 0x65, 0x3b, 0x6e, 0x67, 0x61, 0x3b, 0x6e, 0x67, 0x61, 0x64,
+0x3b, 0x6e, 0x67, 0x61, 0x62, 0x6f, 0x3b, 0x62, 0x3b, 0x6c, 0x3b, 0x6e,
+0x3b, 0x74, 0x3b, 0x73, 0x3b, 0x7a, 0x3b, 0x6d, 0x3b, 0x65, 0x3b, 0x61,
+0x3b, 0x64, 0x3b, 0x62, 0x6a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x3b, 0x66,
+0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x3b,
+0x61, 0x70, 0x72, 0xed, 0x6c, 0x3b, 0x6d, 0x61, 0x69, 0x3b, 0x6a, 0x75,
+0x6e, 0x69, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x3b, 0x61, 0x75, 0x67, 0x75,
+0x73, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72,
+0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x6e, 0x6f, 0x76,
+0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x64, 0x65, 0x73, 0x65, 0x6d, 0x62,
+0x65, 0x72, 0x6a, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0x61,
+0x72, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0x61, 0x69, 0x3b, 0x6a, 0x75,
+0x6e, 0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x75, 0x67, 0x3b, 0x73, 0x65,
+0x70, 0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65,
+0x73, 0x6a, 0x61, 0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x62, 0x2e, 0x3b, 0x6d,
+0x61, 0x72, 0x2e, 0x3b, 0x61, 0x70, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x69,
+0x3b, 0x6a, 0x75, 0x6e, 0x2e, 0x3b, 0x6a, 0x75, 0x6c, 0x2e, 0x3b, 0x61,
+0x75, 0x67, 0x2e, 0x3b, 0x73, 0x65, 0x70, 0x2e, 0x3b, 0x6f, 0x6b, 0x74,
+0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x73, 0x2e, 0x45,
+0x6e, 0x65, 0x72, 0x6f, 0x3b, 0x50, 0x65, 0x62, 0x72, 0x65, 0x72, 0x6f,
+0x3b, 0x4d, 0x61, 0x72, 0x73, 0x6f, 0x3b, 0x41, 0x62, 0x72, 0x69, 0x6c,
+0x3b, 0x4d, 0x61, 0x79, 0x6f, 0x3b, 0x48, 0x75, 0x6e, 0x79, 0x6f, 0x3b,
+0x48, 0x75, 0x6c, 0x79, 0x6f, 0x3b, 0x41, 0x67, 0x6f, 0x73, 0x74, 0x6f,
+0x3b, 0x53, 0x65, 0x74, 0x79, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x4f,
+0x6b, 0x74, 0x75, 0x62, 0x72, 0x65, 0x3b, 0x4e, 0x6f, 0x62, 0x79, 0x65,
+0x6d, 0x62, 0x72, 0x65, 0x3b, 0x44, 0x69, 0x73, 0x79, 0x65, 0x6d, 0x62,
+0x72, 0x65, 0x45, 0x6e, 0x65, 0x3b, 0x50, 0x65, 0x62, 0x3b, 0x4d, 0x61,
+0x72, 0x3b, 0x41, 0x62, 0x72, 0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x48, 0x75,
+0x6e, 0x3b, 0x48, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x6f, 0x3b, 0x53, 0x65,
+0x74, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x62, 0x3b, 0x44, 0x69,
+0x73, 0x45, 0x3b, 0x50, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x48,
+0x75, 0x6e, 0x3b, 0x48, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x6f, 0x3b, 0x53,
+0x65, 0x74, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x62, 0x3b, 0x44,
+0x69, 0x73, 0x74, 0x61, 0x6d, 0x6d, 0x69, 0x6b, 0x75, 0x75, 0x3b, 0x68,
+0x65, 0x6c, 0x6d, 0x69, 0x6b, 0x75, 0x75, 0x3b, 0x6d, 0x61, 0x61, 0x6c,
+0x69, 0x73, 0x6b, 0x75, 0x75, 0x3b, 0x68, 0x75, 0x68, 0x74, 0x69, 0x6b,
+0x75, 0x75, 0x3b, 0x74, 0x6f, 0x75, 0x6b, 0x6f, 0x6b, 0x75, 0x75, 0x3b,
+0x6b, 0x65, 0x73, 0xe4, 0x6b, 0x75, 0x75, 0x3b, 0x68, 0x65, 0x69, 0x6e,
+0xe4, 0x6b, 0x75, 0x75, 0x3b, 0x65, 0x6c, 0x6f, 0x6b, 0x75, 0x75, 0x3b,
+0x73, 0x79, 0x79, 0x73, 0x6b, 0x75, 0x75, 0x3b, 0x6c, 0x6f, 0x6b, 0x61,
+0x6b, 0x75, 0x75, 0x3b, 0x6d, 0x61, 0x72, 0x72, 0x61, 0x73, 0x6b, 0x75,
+0x75, 0x3b, 0x6a, 0x6f, 0x75, 0x6c, 0x75, 0x6b, 0x75, 0x75, 0x74, 0x61,
+0x6d, 0x6d, 0x69, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x68, 0x65, 0x6c,
+0x6d, 0x69, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x6d, 0x61, 0x61, 0x6c,
+0x69, 0x73, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x68, 0x75, 0x68, 0x74,
+0x69, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x74, 0x6f, 0x75, 0x6b, 0x6f,
+0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x6b, 0x65, 0x73, 0xe4, 0x6b, 0x75,
+0x75, 0x74, 0x61, 0x3b, 0x68, 0x65, 0x69, 0x6e, 0xe4, 0x6b, 0x75, 0x75,
+0x74, 0x61, 0x3b, 0x65, 0x6c, 0x6f, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b,
+0x73, 0x79, 0x79, 0x73, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x6c, 0x6f,
+0x6b, 0x61, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x6d, 0x61, 0x72, 0x72,
+0x61, 0x73, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x3b, 0x6a, 0x6f, 0x75, 0x6c,
+0x75, 0x6b, 0x75, 0x75, 0x74, 0x61, 0x74, 0x61, 0x6d, 0x6d, 0x69, 0x3b,
+0x68, 0x65, 0x6c, 0x6d, 0x69, 0x3b, 0x6d, 0x61, 0x61, 0x6c, 0x69, 0x73,
+0x3b, 0x68, 0x75, 0x68, 0x74, 0x69, 0x3b, 0x74, 0x6f, 0x75, 0x6b, 0x6f,
+0x3b, 0x6b, 0x65, 0x73, 0xe4, 0x3b, 0x68, 0x65, 0x69, 0x6e, 0xe4, 0x3b,
+0x65, 0x6c, 0x6f, 0x3b, 0x73, 0x79, 0x79, 0x73, 0x3b, 0x6c, 0x6f, 0x6b,
+0x61, 0x3b, 0x6d, 0x61, 0x72, 0x72, 0x61, 0x73, 0x3b, 0x6a, 0x6f, 0x75,
+0x6c, 0x75, 0x74, 0x61, 0x6d, 0x6d, 0x69, 0x6b, 0x2e, 0x3b, 0x68, 0x65,
+0x6c, 0x6d, 0x69, 0x6b, 0x2e, 0x3b, 0x6d, 0x61, 0x61, 0x6c, 0x69, 0x73,
+0x6b, 0x2e, 0x3b, 0x68, 0x75, 0x68, 0x74, 0x69, 0x6b, 0x2e, 0x3b, 0x74,
+0x6f, 0x75, 0x6b, 0x6f, 0x6b, 0x2e, 0x3b, 0x6b, 0x65, 0x73, 0xe4, 0x6b,
+0x2e, 0x3b, 0x68, 0x65, 0x69, 0x6e, 0xe4, 0x6b, 0x2e, 0x3b, 0x65, 0x6c,
+0x6f, 0x6b, 0x2e, 0x3b, 0x73, 0x79, 0x79, 0x73, 0x6b, 0x2e, 0x3b, 0x6c,
+0x6f, 0x6b, 0x61, 0x6b, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x72, 0x61, 0x73,
+0x6b, 0x2e, 0x3b, 0x6a, 0x6f, 0x75, 0x6c, 0x75, 0x6b, 0x2e, 0x54, 0x3b,
+0x48, 0x3b, 0x4d, 0x3b, 0x48, 0x3b, 0x54, 0x3b, 0x4b, 0x3b, 0x48, 0x3b,
+0x45, 0x3b, 0x53, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x4a, 0x6a, 0x61, 0x6e,
+0x76, 0x69, 0x65, 0x72, 0x3b, 0x66, 0xe9, 0x76, 0x72, 0x69, 0x65, 0x72,
+0x3b, 0x6d, 0x61, 0x72, 0x73, 0x3b, 0x61, 0x76, 0x72, 0x69, 0x6c, 0x3b,
+0x6d, 0x61, 0x69, 0x3b, 0x6a, 0x75, 0x69, 0x6e, 0x3b, 0x6a, 0x75, 0x69,
+0x6c, 0x6c, 0x65, 0x74, 0x3b, 0x61, 0x6f, 0xfb, 0x74, 0x3b, 0x73, 0x65,
+0x70, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x6f, 0x63, 0x74, 0x6f,
+0x62, 0x72, 0x65, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x65,
+0x3b, 0x64, 0xe9, 0x63, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x6a, 0x61, 0x6e,
+0x76, 0x2e, 0x3b, 0x66, 0xe9, 0x76, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x72,
+0x73, 0x3b, 0x61, 0x76, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x69, 0x3b, 0x6a,
+0x75, 0x69, 0x6e, 0x3b, 0x6a, 0x75, 0x69, 0x6c, 0x2e, 0x3b, 0x61, 0x6f,
+0xfb, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x2e, 0x3b, 0x6f, 0x63, 0x74,
+0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0xe9, 0x63, 0x2e, 0x6a,
+0x61, 0x6e, 0x76, 0x2e, 0x3b, 0x66, 0xe9, 0x76, 0x72, 0x2e, 0x3b, 0x6d,
+0x61, 0x72, 0x73, 0x3b, 0x61, 0x76, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x69,
+0x3b, 0x6a, 0x75, 0x69, 0x6e, 0x3b, 0x6a, 0x75, 0x69, 0x6c, 0x6c, 0x2e,
+0x3b, 0x61, 0x6f, 0xfb, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x2e, 0x3b,
+0x6f, 0x63, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0xe9,
+0x63, 0x2e, 0x6a, 0x61, 0x6e, 0x2e, 0x3b, 0x66, 0xe9, 0x76, 0x2e, 0x3b,
+0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x61, 0x76, 0x72, 0x2e, 0x3b, 0x6d, 0x61,
+0x69, 0x3b, 0x6a, 0x75, 0x69, 0x2e, 0x3b, 0x6a, 0x75, 0x69, 0x6c, 0x2e,
+0x3b, 0x61, 0x6f, 0xfb, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x2e, 0x3b,
+0x6f, 0x63, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0xe9,
+0x63, 0x2e, 0x5a, 0x65, 0x6e, 0xe2, 0x72, 0x3b, 0x46, 0x65, 0x76, 0x72,
+0xe2, 0x72, 0x3b, 0x4d, 0x61, 0x72, 0xe7, 0x3b, 0x41, 0x76, 0x72, 0xee,
+0x6c, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x67, 0x6e, 0x3b, 0x4c,
+0x75, 0x69, 0x3b, 0x41, 0x76, 0x6f, 0x73, 0x74, 0x3b, 0x53, 0x65, 0x74,
+0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x4f, 0x74, 0x75, 0x62, 0x61, 0x72,
+0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x44, 0x69,
+0x63, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x5a, 0x65, 0x6e, 0x3b, 0x46, 0x65,
+0x76, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x76, 0x72, 0x3b, 0x4d, 0x61,
+0x69, 0x3b, 0x4a, 0x75, 0x67, 0x3b, 0x4c, 0x75, 0x69, 0x3b, 0x41, 0x76,
+0x6f, 0x3b, 0x53, 0x65, 0x74, 0x3b, 0x4f, 0x74, 0x75, 0x3b, 0x4e, 0x6f,
+0x76, 0x3b, 0x44, 0x69, 0x63, 0x5a, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41,
+0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x4c, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f,
+0x3b, 0x4e, 0x3b, 0x44, 0x73, 0x69, 0x69, 0x6c, 0x6f, 0x3b, 0x63, 0x6f,
+0x6c, 0x74, 0x65, 0x3b, 0x6d, 0x62, 0x6f, 0x6f, 0x79, 0x3b, 0x73, 0x65,
+0x65, 0x257, 0x74, 0x6f, 0x3b, 0x64, 0x75, 0x75, 0x6a, 0x61, 0x6c, 0x3b,
+0x6b, 0x6f, 0x72, 0x73, 0x65, 0x3b, 0x6d, 0x6f, 0x72, 0x73, 0x6f, 0x3b,
+0x6a, 0x75, 0x6b, 0x6f, 0x3b, 0x73, 0x69, 0x69, 0x6c, 0x74, 0x6f, 0x3b,
+0x79, 0x61, 0x72, 0x6b, 0x6f, 0x6d, 0x61, 0x61, 0x3b, 0x6a, 0x6f, 0x6c,
+0x61, 0x6c, 0x3b, 0x62, 0x6f, 0x77, 0x74, 0x65, 0x73, 0x69, 0x69, 0x3b,
+0x63, 0x6f, 0x6c, 0x3b, 0x6d, 0x62, 0x6f, 0x3b, 0x73, 0x65, 0x65, 0x3b,
+0x64, 0x75, 0x75, 0x3b, 0x6b, 0x6f, 0x72, 0x3b, 0x6d, 0x6f, 0x72, 0x3b,
+0x6a, 0x75, 0x6b, 0x3b, 0x73, 0x6c, 0x74, 0x3b, 0x79, 0x61, 0x72, 0x3b,
+0x6a, 0x6f, 0x6c, 0x3b, 0x62, 0x6f, 0x77, 0x73, 0x3b, 0x63, 0x3b, 0x6d,
+0x3b, 0x73, 0x3b, 0x64, 0x3b, 0x6b, 0x3b, 0x6d, 0x3b, 0x6a, 0x3b, 0x73,
+0x3b, 0x79, 0x3b, 0x6a, 0x3b, 0x62, 0xd83a, 0xdd05, 0xd83a, 0xdd2d, 0xd83a, 0xdd45,
+0xd83a, 0xdd24, 0xd83a, 0xdd2e, 0x3b, 0xd83a, 0xdd15, 0xd83a, 0xdd2e, 0xd83a, 0xdd24, 0xd83a,
+0xdd3c, 0xd83a, 0xdd2e, 0x3b, 0xd83a, 0xdd10, 0xd83a, 0xdd26, 0xd83a, 0xdd2e, 0xd83a, 0xdd45,
+0xd83a, 0xdd34, 0xd83a, 0xdd2e, 0x3b, 0xd83a, 0xdd05, 0xd83a, 0xdd2b, 0xd83a, 0xdd45, 0xd83a,
+0xdd3c, 0xd83a, 0xdd2e, 0x3b, 0xd83a, 0xdd01, 0xd83a, 0xdd35, 0xd83a, 0xdd45, 0xd83a, 0xdd36,
+0xd83a, 0xdd2e, 0x3b, 0xd83a, 0xdd11, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0xd83a, 0xdd27, 0xd83a,
+0xdd2e, 0x3b, 0xd83a, 0xdd03, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0xd83a, 0xdd27, 0xd83a, 0xdd2e,
+0x3b, 0xd83a, 0xdd14, 0xd83a, 0xdd35, 0xd83a, 0xdd33, 0xd83a, 0xdd2e, 0x3b, 0xd83a, 0xdd05,
+0xd83a, 0xdd2d, 0xd83a, 0xdd24, 0xd83a, 0xdd3c, 0xd83a, 0xdd2e, 0x3b, 0xd83a, 0xdd12, 0xd83a,
+0xdd22, 0xd83a, 0xdd2a, 0xd83a, 0xdd33, 0xd83a, 0xdd2e, 0x3b, 0xd83a, 0xdd14, 0xd83a, 0xdd2e,
+0xd83a, 0xdd24, 0xd83a, 0xdd2e, 0x3b, 0xd83a, 0xdd04, 0xd83a, 0xdd2e, 0xd83a, 0xdd31, 0xd83a,
+0xdd3c, 0xd83a, 0xdd2e, 0xd83a, 0xdd05, 0xd83a, 0xdd2d, 0xd83a, 0xdd45, 0xd83a, 0xdd24, 0x3b,
+0xd83a, 0xdd15, 0xd83a, 0xdd2e, 0xd83a, 0xdd24, 0x3b, 0xd83a, 0xdd10, 0xd83a, 0xdd26, 0xd83a,
+0xdd2e, 0xd83a, 0xdd45, 0xd83a, 0xdd34, 0x3b, 0xd83a, 0xdd05, 0xd83a, 0xdd2b, 0xd83a, 0xdd45,
+0xd83a, 0xdd3c, 0x3b, 0xd83a, 0xdd01, 0xd83a, 0xdd35, 0xd83a, 0xdd45, 0xd83a, 0xdd36, 0x3b,
+0xd83a, 0xdd11, 0xd83a, 0xdd2e, 0xd83a, 0xdd2a, 0x3b, 0xd83a, 0xdd03, 0xd83a, 0xdd2e, 0xd83a,
+0xdd2a, 0x3b, 0xd83a, 0xdd14, 0xd83a, 0xdd35, 0xd83a, 0xdd33, 0x3b, 0xd83a, 0xdd05, 0xd83a,
+0xdd2d, 0xd83a, 0xdd24, 0x3b, 0xd83a, 0xdd12, 0xd83a, 0xdd22, 0xd83a, 0xdd2a, 0x3b, 0xd83a,
+0xdd14, 0xd83a, 0xdd2e, 0xd83a, 0xdd24, 0x3b, 0xd83a, 0xdd04, 0xd83a, 0xdd2e, 0xd83a, 0xdd31,
+0xd83a, 0xdd05, 0x3b, 0xd83a, 0xdd15, 0x3b, 0xd83a, 0xdd04, 0x3b, 0xd83a, 0xdd05, 0x3b,
+0xd83a, 0xdd01, 0x3b, 0xd83a, 0xdd11, 0x3b, 0xd83a, 0xdd03, 0x3b, 0xd83a, 0xdd14, 0x3b,
+0xd83a, 0xdd05, 0x3b, 0xd83a, 0xdd12, 0x3b, 0xd83a, 0xdd14, 0x3b, 0xd83a, 0xdd04, 0x41,
+0x6d, 0x20, 0x46, 0x61, 0x6f, 0x69, 0x6c, 0x6c, 0x65, 0x61, 0x63, 0x68,
+0x3b, 0x41, 0x6e, 0x20, 0x47, 0x65, 0x61, 0x72, 0x72, 0x61, 0x6e, 0x3b,
+0x41, 0x6d, 0x20, 0x4d, 0xe0, 0x72, 0x74, 0x3b, 0x41, 0x6e, 0x20, 0x47,
+0x69, 0x62, 0x6c, 0x65, 0x61, 0x6e, 0x3b, 0x41, 0x6e, 0x20, 0x43, 0xe8,
+0x69, 0x74, 0x65, 0x61, 0x6e, 0x3b, 0x41, 0x6e, 0x20, 0x74, 0x2d, 0xd2,
+0x67, 0x6d, 0x68, 0x69, 0x6f, 0x73, 0x3b, 0x41, 0x6e, 0x20, 0x74, 0x2d,
+0x49, 0x75, 0x63, 0x68, 0x61, 0x72, 0x3b, 0x41, 0x6e, 0x20, 0x4c, 0xf9,
+0x6e, 0x61, 0x73, 0x74, 0x61, 0x6c, 0x3b, 0x41, 0x6e, 0x20, 0x74, 0x2d,
+0x53, 0x75, 0x6c, 0x74, 0x61, 0x69, 0x6e, 0x3b, 0x41, 0x6e, 0x20, 0x44,
+0xe0, 0x6d, 0x68, 0x61, 0x69, 0x72, 0x3b, 0x41, 0x6e, 0x20, 0x74, 0x2d,
+0x53, 0x61, 0x6d, 0x68, 0x61, 0x69, 0x6e, 0x3b, 0x41, 0x6e, 0x20, 0x44,
+0xf9, 0x62, 0x68, 0x6c, 0x61, 0x63, 0x68, 0x64, 0x64, 0x68, 0x65, 0x6e,
+0x20, 0x46, 0x68, 0x61, 0x6f, 0x69, 0x6c, 0x6c, 0x65, 0x61, 0x63, 0x68,
+0x3b, 0x64, 0x68, 0x65, 0x6e, 0x20, 0x47, 0x68, 0x65, 0x61, 0x72, 0x72,
+0x61, 0x6e, 0x3b, 0x64, 0x68, 0x65, 0x6e, 0x20, 0x4d, 0x68, 0xe0, 0x72,
+0x74, 0x3b, 0x64, 0x68, 0x65, 0x6e, 0x20, 0x47, 0x68, 0x69, 0x62, 0x6c,
+0x65, 0x61, 0x6e, 0x3b, 0x64, 0x68, 0x65, 0x6e, 0x20, 0x43, 0x68, 0xe8,
+0x69, 0x74, 0x65, 0x61, 0x6e, 0x3b, 0x64, 0x68, 0x65, 0x6e, 0x20, 0xd2,
+0x67, 0x6d, 0x68, 0x69, 0x6f, 0x73, 0x3b, 0x64, 0x68, 0x65, 0x6e, 0x20,
+0x49, 0x75, 0x63, 0x68, 0x61, 0x72, 0x3b, 0x64, 0x68, 0x65, 0x6e, 0x20,
+0x4c, 0xf9, 0x6e, 0x61, 0x73, 0x74, 0x61, 0x6c, 0x3b, 0x64, 0x68, 0x65,
+0x6e, 0x20, 0x74, 0x2d, 0x53, 0x75, 0x6c, 0x74, 0x61, 0x69, 0x6e, 0x3b,
+0x64, 0x68, 0x65, 0x6e, 0x20, 0x44, 0xe0, 0x6d, 0x68, 0x61, 0x69, 0x72,
+0x3b, 0x64, 0x68, 0x65, 0x6e, 0x20, 0x74, 0x2d, 0x53, 0x61, 0x6d, 0x68,
+0x61, 0x69, 0x6e, 0x3b, 0x64, 0x68, 0x65, 0x6e, 0x20, 0x44, 0xf9, 0x62,
+0x68, 0x6c, 0x61, 0x63, 0x68, 0x64, 0x46, 0x61, 0x6f, 0x69, 0x3b, 0x47,
+0x65, 0x61, 0x72, 0x72, 0x3b, 0x4d, 0xe0, 0x72, 0x74, 0x3b, 0x47, 0x69,
+0x62, 0x6c, 0x3b, 0x43, 0xe8, 0x69, 0x74, 0x3b, 0xd2, 0x67, 0x6d, 0x68,
+0x3b, 0x49, 0x75, 0x63, 0x68, 0x3b, 0x4c, 0xf9, 0x6e, 0x61, 0x3b, 0x53,
+0x75, 0x6c, 0x74, 0x3b, 0x44, 0xe0, 0x6d, 0x68, 0x3b, 0x53, 0x61, 0x6d,
+0x68, 0x3b, 0x44, 0xf9, 0x62, 0x68, 0x46, 0x3b, 0x47, 0x3b, 0x4d, 0x3b,
+0x47, 0x3b, 0x43, 0x3b, 0xd2, 0x3b, 0x49, 0x3b, 0x4c, 0x3b, 0x53, 0x3b,
+0x44, 0x3b, 0x53, 0x3b, 0x44, 0x41, 0x68, 0x61, 0x72, 0x61, 0x62, 0x61,
+0x74, 0x61, 0x3b, 0x4f, 0x66, 0x6c, 0x254, 0x3b, 0x4f, 0x74, 0x73, 0x6f,
+0x6b, 0x72, 0x69, 0x6b, 0x72, 0x69, 0x3b, 0x41, 0x62, 0x65, 0x69, 0x62,
+0x65, 0x3b, 0x41, 0x67, 0x62, 0x69, 0x25b, 0x6e, 0x61, 0x61, 0x3b, 0x4f,
+0x74, 0x75, 0x6b, 0x77, 0x61, 0x6a, 0x61, 0x6e, 0x3b, 0x4d, 0x61, 0x61,
+0x77, 0x25b, 0x3b, 0x4d, 0x61, 0x6e, 0x79, 0x61, 0x77, 0x61, 0x6c, 0x65,
+0x3b, 0x47, 0x62, 0x6f, 0x3b, 0x41, 0x6e, 0x74, 0x254, 0x14b, 0x3b, 0x41,
+0x6c, 0x65, 0x6d, 0x6c, 0x65, 0x3b, 0x41, 0x66, 0x75, 0x61, 0x62, 0x65,
+0x41, 0x68, 0x61, 0x72, 0x61, 0x62, 0x61, 0x74, 0x61, 0x3b, 0x4f, 0x66,
+0x6c, 0x254, 0x3b, 0x4f, 0x74, 0x73, 0x6f, 0x6b, 0x72, 0x69, 0x6b, 0x72,
+0x69, 0x3b, 0x41, 0x62, 0x65, 0x69, 0x62, 0x65, 0x3b, 0x41, 0x67, 0x62,
+0x69, 0x25b, 0x6e, 0x61, 0x61, 0x3b, 0x4f, 0x74, 0x75, 0x6b, 0x77, 0x61,
+0x6a, 0x61, 0x14b, 0x3b, 0x4d, 0x61, 0x61, 0x77, 0x25b, 0x3b, 0x4d, 0x61,
+0x6e, 0x79, 0x61, 0x77, 0x61, 0x6c, 0x65, 0x3b, 0x47, 0x62, 0x6f, 0x3b,
+0x41, 0x6e, 0x74, 0x254, 0x14b, 0x3b, 0x41, 0x6c, 0x65, 0x6d, 0x6c, 0x65,
+0x3b, 0x41, 0x66, 0x75, 0x61, 0x62, 0x65, 0x41, 0x68, 0x61, 0x3b, 0x4f,
+0x66, 0x6c, 0x3b, 0x4f, 0x74, 0x73, 0x3b, 0x41, 0x62, 0x65, 0x3b, 0x41,
+0x67, 0x62, 0x3b, 0x4f, 0x74, 0x75, 0x3b, 0x4d, 0x61, 0x61, 0x3b, 0x4d,
+0x61, 0x6e, 0x3b, 0x47, 0x62, 0x6f, 0x3b, 0x41, 0x6e, 0x74, 0x3b, 0x41,
+0x6c, 0x65, 0x3b, 0x41, 0x66, 0x75, 0x41, 0x3b, 0x4f, 0x3b, 0x4f, 0x3b,
+0x41, 0x3b, 0x41, 0x3b, 0x4f, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x47, 0x3b,
+0x41, 0x3b, 0x41, 0x3b, 0x41, 0x78, 0x61, 0x6e, 0x65, 0x69, 0x72, 0x6f,
+0x3b, 0x66, 0x65, 0x62, 0x72, 0x65, 0x69, 0x72, 0x6f, 0x3b, 0x6d, 0x61,
+0x72, 0x7a, 0x6f, 0x3b, 0x61, 0x62, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x61,
+0x69, 0x6f, 0x3b, 0x78, 0x75, 0xf1, 0x6f, 0x3b, 0x78, 0x75, 0x6c, 0x6c,
+0x6f, 0x3b, 0x61, 0x67, 0x6f, 0x73, 0x74, 0x6f, 0x3b, 0x73, 0x65, 0x74,
+0x65, 0x6d, 0x62, 0x72, 0x6f, 0x3b, 0x6f, 0x75, 0x74, 0x75, 0x62, 0x72,
+0x6f, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x6f, 0x3b, 0x64,
+0x65, 0x63, 0x65, 0x6d, 0x62, 0x72, 0x6f, 0x78, 0x61, 0x6e, 0x2e, 0x3b,
+0x66, 0x65, 0x62, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x61, 0x62,
+0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x69, 0x6f, 0x3b, 0x78, 0x75, 0xf1, 0x6f,
+0x3b, 0x78, 0x75, 0x6c, 0x2e, 0x3b, 0x61, 0x67, 0x6f, 0x2e, 0x3b, 0x73,
+0x65, 0x74, 0x2e, 0x3b, 0x6f, 0x75, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76,
+0x2e, 0x3b, 0x64, 0x65, 0x63, 0x2e, 0x58, 0x3b, 0x46, 0x3b, 0x4d, 0x3b,
+0x41, 0x3b, 0x4d, 0x3b, 0x58, 0x3b, 0x58, 0x3b, 0x41, 0x3b, 0x53, 0x3b,
+0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x78, 0x2e, 0x3b, 0x66, 0x2e, 0x3b, 0x6d,
+0x2e, 0x3b, 0x61, 0x2e, 0x3b, 0x6d, 0x2e, 0x3b, 0x78, 0x2e, 0x3b, 0x78,
+0x2e, 0x3b, 0x61, 0x2e, 0x3b, 0x73, 0x2e, 0x3b, 0x6f, 0x2e, 0x3b, 0x6e,
+0x2e, 0x3b, 0x64, 0x2e, 0x4a, 0x61, 0x6e, 0x77, 0x61, 0x6c, 0x69, 0x79,
+0x6f, 0x3b, 0x46, 0x65, 0x62, 0x77, 0x61, 0x6c, 0x69, 0x79, 0x6f, 0x3b,
+0x4d, 0x61, 0x72, 0x69, 0x73, 0x69, 0x3b, 0x41, 0x70, 0x75, 0x6c, 0x69,
+0x3b, 0x4d, 0x61, 0x61, 0x79, 0x69, 0x3b, 0x4a, 0x75, 0x75, 0x6e, 0x69,
+0x3b, 0x4a, 0x75, 0x6c, 0x61, 0x61, 0x79, 0x69, 0x3b, 0x41, 0x67, 0x75,
+0x73, 0x69, 0x74, 0x6f, 0x3b, 0x53, 0x65, 0x62, 0x75, 0x74, 0x74, 0x65,
+0x6d, 0x62, 0x61, 0x3b, 0x4f, 0x6b, 0x69, 0x74, 0x6f, 0x62, 0x62, 0x61,
+0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x44, 0x65, 0x73,
+0x65, 0x6d, 0x62, 0x61, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b,
+0x4d, 0x61, 0x72, 0x3b, 0x41, 0x70, 0x75, 0x3b, 0x4d, 0x61, 0x61, 0x3b,
+0x4a, 0x75, 0x75, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x75, 0x3b,
+0x53, 0x65, 0x62, 0x3b, 0x4f, 0x6b, 0x69, 0x3b, 0x4e, 0x6f, 0x76, 0x3b,
+0x44, 0x65, 0x73, 0x1320, 0x1210, 0x1228, 0x3b, 0x12a8, 0x1270, 0x1270, 0x3b, 0x1218,
+0x1308, 0x1260, 0x3b, 0x12a0, 0x1280, 0x12d8, 0x3b, 0x130d, 0x1295, 0x1263, 0x1275, 0x3b,
+0x1220, 0x1295, 0x12e8, 0x3b, 0x1210, 0x1218, 0x1208, 0x3b, 0x1290, 0x1210, 0x1230, 0x3b,
+0x12a8, 0x1228, 0x1218, 0x3b, 0x1320, 0x1240, 0x1218, 0x3b, 0x1280, 0x12f0, 0x1228, 0x3b,
+0x1280, 0x1220, 0x1220, 0x1320, 0x3b, 0x12a8, 0x3b, 0x1218, 0x3b, 0x12a0, 0x3b, 0x130d,
+0x3b, 0x1220, 0x3b, 0x1210, 0x3b, 0x1290, 0x3b, 0x12a8, 0x3b, 0x1320, 0x3b, 0x1280,
+0x3b, 0x1280, 0x10d8, 0x10d0, 0x10dc, 0x10d5, 0x10d0, 0x10e0, 0x10d8, 0x3b, 0x10d7, 0x10d4,
+0x10d1, 0x10d4, 0x10e0, 0x10d5, 0x10d0, 0x10da, 0x10d8, 0x3b, 0x10db, 0x10d0, 0x10e0, 0x10e2,
+0x10d8, 0x3b, 0x10d0, 0x10de, 0x10e0, 0x10d8, 0x10da, 0x10d8, 0x3b, 0x10db, 0x10d0, 0x10d8,
+0x10e1, 0x10d8, 0x3b, 0x10d8, 0x10d5, 0x10dc, 0x10d8, 0x10e1, 0x10d8, 0x3b, 0x10d8, 0x10d5,
+0x10da, 0x10d8, 0x10e1, 0x10d8, 0x3b, 0x10d0, 0x10d2, 0x10d5, 0x10d8, 0x10e1, 0x10e2, 0x10dd,
+0x3b, 0x10e1, 0x10d4, 0x10e5, 0x10e2, 0x10d4, 0x10db, 0x10d1, 0x10d4, 0x10e0, 0x10d8, 0x3b,
+0x10dd, 0x10e5, 0x10e2, 0x10dd, 0x10db, 0x10d1, 0x10d4, 0x10e0, 0x10d8, 0x3b, 0x10dc, 0x10dd,
+0x10d4, 0x10db, 0x10d1, 0x10d4, 0x10e0, 0x10d8, 0x3b, 0x10d3, 0x10d4, 0x10d9, 0x10d4, 0x10db,
+0x10d1, 0x10d4, 0x10e0, 0x10d8, 0x10d8, 0x10d0, 0x10dc, 0x3b, 0x10d7, 0x10d4, 0x10d1, 0x3b,
+0x10db, 0x10d0, 0x10e0, 0x3b, 0x10d0, 0x10de, 0x10e0, 0x3b, 0x10db, 0x10d0, 0x10d8, 0x3b,
+0x10d8, 0x10d5, 0x10dc, 0x3b, 0x10d8, 0x10d5, 0x10da, 0x3b, 0x10d0, 0x10d2, 0x10d5, 0x3b,
+0x10e1, 0x10d4, 0x10e5, 0x3b, 0x10dd, 0x10e5, 0x10e2, 0x3b, 0x10dc, 0x10dd, 0x10d4, 0x3b,
+0x10d3, 0x10d4, 0x10d9, 0x10d8, 0x3b, 0x10d7, 0x3b, 0x10db, 0x3b, 0x10d0, 0x3b, 0x10db,
+0x3b, 0x10d8, 0x3b, 0x10d8, 0x3b, 0x10d0, 0x3b, 0x10e1, 0x3b, 0x10dd, 0x3b, 0x10dc,
+0x3b, 0x10d3, 0x4a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x3b, 0x46, 0x65, 0x62,
+0x72, 0x75, 0x61, 0x72, 0x3b, 0x4d, 0xe4, 0x72, 0x7a, 0x3b, 0x41, 0x70,
+0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69,
+0x3b, 0x4a, 0x75, 0x6c, 0x69, 0x3b, 0x41, 0x75, 0x67, 0x75, 0x73, 0x74,
+0x3b, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f,
+0x6b, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d,
+0x62, 0x65, 0x72, 0x3b, 0x44, 0x65, 0x7a, 0x65, 0x6d, 0x62, 0x65, 0x72,
+0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0xe4, 0x72, 0x3b,
+0x41, 0x70, 0x72, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b,
+0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x75, 0x67, 0x3b, 0x53, 0x65, 0x70, 0x3b,
+0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x7a, 0x4a,
+0x61, 0x6e, 0x2e, 0x3b, 0x46, 0x65, 0x62, 0x2e, 0x3b, 0x4d, 0xe4, 0x72,
+0x7a, 0x3b, 0x41, 0x70, 0x72, 0x2e, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a,
+0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x69, 0x3b, 0x41, 0x75, 0x67,
+0x2e, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x2e, 0x3b, 0x4f, 0x6b, 0x74, 0x2e,
+0x3b, 0x4e, 0x6f, 0x76, 0x2e, 0x3b, 0x44, 0x65, 0x7a, 0x2e, 0x4a, 0xe4,
+0x6e, 0x6e, 0x65, 0x72, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72,
+0x3b, 0x4d, 0xe4, 0x72, 0x7a, 0x3b, 0x41, 0x70, 0x72, 0x69, 0x6c, 0x3b,
+0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c,
+0x69, 0x3b, 0x41, 0x75, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x53, 0x65, 0x70,
+0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62,
+0x65, 0x72, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b,
+0x44, 0x65, 0x7a, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4a, 0xe4, 0x6e, 0x3b,
+0x46, 0x65, 0x62, 0x3b, 0x4d, 0xe4, 0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b,
+0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b,
+0x41, 0x75, 0x67, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b,
+0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x7a, 0x4a, 0xe4, 0x6e, 0x2e, 0x3b,
+0x46, 0x65, 0x62, 0x2e, 0x3b, 0x4d, 0xe4, 0x72, 0x7a, 0x3b, 0x41, 0x70,
+0x72, 0x2e, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b,
+0x4a, 0x75, 0x6c, 0x69, 0x3b, 0x41, 0x75, 0x67, 0x2e, 0x3b, 0x53, 0x65,
+0x70, 0x2e, 0x3b, 0x4f, 0x6b, 0x74, 0x2e, 0x3b, 0x4e, 0x6f, 0x76, 0x2e,
+0x3b, 0x44, 0x65, 0x7a, 0x2e, 0x399, 0x3b1, 0x3bd, 0x3bf, 0x3c5, 0x3ac, 0x3c1,
+0x3b9, 0x3bf, 0x3c2, 0x3b, 0x3a6, 0x3b5, 0x3b2, 0x3c1, 0x3bf, 0x3c5, 0x3ac, 0x3c1,
+0x3b9, 0x3bf, 0x3c2, 0x3b, 0x39c, 0x3ac, 0x3c1, 0x3c4, 0x3b9, 0x3bf, 0x3c2, 0x3b,
+0x391, 0x3c0, 0x3c1, 0x3af, 0x3bb, 0x3b9, 0x3bf, 0x3c2, 0x3b, 0x39c, 0x3ac, 0x3b9,
+0x3bf, 0x3c2, 0x3b, 0x399, 0x3bf, 0x3cd, 0x3bd, 0x3b9, 0x3bf, 0x3c2, 0x3b, 0x399,
+0x3bf, 0x3cd, 0x3bb, 0x3b9, 0x3bf, 0x3c2, 0x3b, 0x391, 0x3cd, 0x3b3, 0x3bf, 0x3c5,
+0x3c3, 0x3c4, 0x3bf, 0x3c2, 0x3b, 0x3a3, 0x3b5, 0x3c0, 0x3c4, 0x3ad, 0x3bc, 0x3b2,
+0x3c1, 0x3b9, 0x3bf, 0x3c2, 0x3b, 0x39f, 0x3ba, 0x3c4, 0x3ce, 0x3b2, 0x3c1, 0x3b9,
+0x3bf, 0x3c2, 0x3b, 0x39d, 0x3bf, 0x3ad, 0x3bc, 0x3b2, 0x3c1, 0x3b9, 0x3bf, 0x3c2,
+0x3b, 0x394, 0x3b5, 0x3ba, 0x3ad, 0x3bc, 0x3b2, 0x3c1, 0x3b9, 0x3bf, 0x3c2, 0x399,
+0x3b1, 0x3bd, 0x3bf, 0x3c5, 0x3b1, 0x3c1, 0x3af, 0x3bf, 0x3c5, 0x3b, 0x3a6, 0x3b5,
+0x3b2, 0x3c1, 0x3bf, 0x3c5, 0x3b1, 0x3c1, 0x3af, 0x3bf, 0x3c5, 0x3b, 0x39c, 0x3b1,
+0x3c1, 0x3c4, 0x3af, 0x3bf, 0x3c5, 0x3b, 0x391, 0x3c0, 0x3c1, 0x3b9, 0x3bb, 0x3af,
+0x3bf, 0x3c5, 0x3b, 0x39c, 0x3b1, 0x390, 0x3bf, 0x3c5, 0x3b, 0x399, 0x3bf, 0x3c5,
+0x3bd, 0x3af, 0x3bf, 0x3c5, 0x3b, 0x399, 0x3bf, 0x3c5, 0x3bb, 0x3af, 0x3bf, 0x3c5,
+0x3b, 0x391, 0x3c5, 0x3b3, 0x3bf, 0x3cd, 0x3c3, 0x3c4, 0x3bf, 0x3c5, 0x3b, 0x3a3,
+0x3b5, 0x3c0, 0x3c4, 0x3b5, 0x3bc, 0x3b2, 0x3c1, 0x3af, 0x3bf, 0x3c5, 0x3b, 0x39f,
+0x3ba, 0x3c4, 0x3c9, 0x3b2, 0x3c1, 0x3af, 0x3bf, 0x3c5, 0x3b, 0x39d, 0x3bf, 0x3b5,
+0x3bc, 0x3b2, 0x3c1, 0x3af, 0x3bf, 0x3c5, 0x3b, 0x394, 0x3b5, 0x3ba, 0x3b5, 0x3bc,
+0x3b2, 0x3c1, 0x3af, 0x3bf, 0x3c5, 0x399, 0x3b1, 0x3bd, 0x3b, 0x3a6, 0x3b5, 0x3b2,
+0x3b, 0x39c, 0x3ac, 0x3c1, 0x3b, 0x391, 0x3c0, 0x3c1, 0x3b, 0x39c, 0x3ac, 0x3b9,
+0x3b, 0x399, 0x3bf, 0x3cd, 0x3bd, 0x3b, 0x399, 0x3bf, 0x3cd, 0x3bb, 0x3b, 0x391,
+0x3cd, 0x3b3, 0x3b, 0x3a3, 0x3b5, 0x3c0, 0x3b, 0x39f, 0x3ba, 0x3c4, 0x3b, 0x39d,
+0x3bf, 0x3ad, 0x3b, 0x394, 0x3b5, 0x3ba, 0x399, 0x3b1, 0x3bd, 0x3b, 0x3a6, 0x3b5,
+0x3b2, 0x3b, 0x39c, 0x3b1, 0x3c1, 0x3b, 0x391, 0x3c0, 0x3c1, 0x3b, 0x39c, 0x3b1,
+0x390, 0x3b, 0x399, 0x3bf, 0x3c5, 0x3bd, 0x3b, 0x399, 0x3bf, 0x3c5, 0x3bb, 0x3b,
+0x391, 0x3c5, 0x3b3, 0x3b, 0x3a3, 0x3b5, 0x3c0, 0x3b, 0x39f, 0x3ba, 0x3c4, 0x3b,
+0x39d, 0x3bf, 0x3b5, 0x3b, 0x394, 0x3b5, 0x3ba, 0x399, 0x3b, 0x3a6, 0x3b, 0x39c,
+0x3b, 0x391, 0x3b, 0x39c, 0x3b, 0x399, 0x3b, 0x399, 0x3b, 0x391, 0x3b, 0x3a3,
+0x3b, 0x39f, 0x3b, 0x39d, 0x3b, 0x394, 0x4a, 0x61, 0x73, 0x79, 0x74, 0x65,
+0x129, 0x3b, 0x4a, 0x61, 0x73, 0x79, 0x6b, 0xf5, 0x69, 0x3b, 0x4a, 0x61,
+0x73, 0x79, 0x61, 0x70, 0x79, 0x3b, 0x4a, 0x61, 0x73, 0x79, 0x72, 0x75,
+0x6e, 0x64, 0x79, 0x3b, 0x4a, 0x61, 0x73, 0x79, 0x70, 0x6f, 0x3b, 0x4a,
+0x61, 0x73, 0x79, 0x70, 0x6f, 0x74, 0x65, 0x129, 0x3b, 0x4a, 0x61, 0x73,
+0x79, 0x70, 0x6f, 0x6b, 0xf5, 0x69, 0x3b, 0x4a, 0x61, 0x73, 0x79, 0x70,
+0x6f, 0x61, 0x70, 0x79, 0x3b, 0x4a, 0x61, 0x73, 0x79, 0x70, 0x6f, 0x72,
+0x75, 0x6e, 0x64, 0x79, 0x3b, 0x4a, 0x61, 0x73, 0x79, 0x70, 0x61, 0x3b,
+0x4a, 0x61, 0x73, 0x79, 0x70, 0x61, 0x74, 0x65, 0x129, 0x3b, 0x4a, 0x61,
+0x73, 0x79, 0x70, 0x61, 0x6b, 0xf5, 0x69, 0xa9c, 0xabe, 0xaa8, 0xacd, 0xaaf,
+0xac1, 0xa86, 0xab0, 0xac0, 0x3b, 0xaab, 0xac7, 0xaac, 0xacd, 0xab0, 0xac1, 0xa86,
+0xab0, 0xac0, 0x3b, 0xaae, 0xabe, 0xab0, 0xacd, 0xa9a, 0x3b, 0xa8f, 0xaaa, 0xacd,
+0xab0, 0xabf, 0xab2, 0x3b, 0xaae, 0xac7, 0x3b, 0xa9c, 0xac2, 0xaa8, 0x3b, 0xa9c,
+0xac1, 0xab2, 0xabe, 0xa88, 0x3b, 0xa91, 0xa97, 0xab8, 0xacd, 0xa9f, 0x3b, 0xab8,
+0xaaa, 0xacd, 0xa9f, 0xac7, 0xaae, 0xacd, 0xaac, 0xab0, 0x3b, 0xa91, 0xa95, 0xacd,
+0xa9f, 0xacb, 0xaac, 0xab0, 0x3b, 0xaa8, 0xab5, 0xac7, 0xaae, 0xacd, 0xaac, 0xab0,
+0x3b, 0xaa1, 0xabf, 0xab8, 0xac7, 0xaae, 0xacd, 0xaac, 0xab0, 0xa9c, 0xabe, 0xaa8,
+0xacd, 0xaaf, 0xac1, 0x3b, 0xaab, 0xac7, 0xaac, 0xacd, 0xab0, 0xac1, 0x3b, 0xaae,
+0xabe, 0xab0, 0xacd, 0xa9a, 0x3b, 0xa8f, 0xaaa, 0xacd, 0xab0, 0xabf, 0xab2, 0x3b,
+0xaae, 0xac7, 0x3b, 0xa9c, 0xac2, 0xaa8, 0x3b, 0xa9c, 0xac1, 0xab2, 0xabe, 0xa88,
+0x3b, 0xa91, 0xa97, 0xab8, 0xacd, 0xa9f, 0x3b, 0xab8, 0xaaa, 0xacd, 0xa9f, 0xac7,
+0x3b, 0xa91, 0xa95, 0xacd, 0xa9f, 0xacb, 0x3b, 0xaa8, 0xab5, 0xac7, 0x3b, 0xaa1,
+0xabf, 0xab8, 0xac7, 0xa9c, 0xabe, 0x3b, 0xaab, 0xac7, 0x3b, 0xaae, 0xabe, 0x3b,
+0xa8f, 0x3b, 0xaae, 0xac7, 0x3b, 0xa9c, 0xac2, 0x3b, 0xa9c, 0xac1, 0x3b, 0xa91,
+0x3b, 0xab8, 0x3b, 0xa91, 0x3b, 0xaa8, 0x3b, 0xaa1, 0xabf, 0x43, 0x68, 0x61,
+0x6e, 0x75, 0x61, 0x72, 0x69, 0x3b, 0x46, 0x65, 0x62, 0x75, 0x72, 0x61,
+0x72, 0x69, 0x3b, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x3b, 0x41, 0x70, 0x69,
+0x72, 0x69, 0x72, 0x69, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e,
+0x69, 0x3b, 0x43, 0x68, 0x75, 0x6c, 0x61, 0x69, 0x3b, 0x41, 0x67, 0x6f,
+0x73, 0x74, 0x69, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x61,
+0x3b, 0x4f, 0x6b, 0x69, 0x74, 0x6f, 0x62, 0x61, 0x3b, 0x4e, 0x6f, 0x62,
+0x65, 0x6d, 0x62, 0x61, 0x3b, 0x44, 0x69, 0x73, 0x65, 0x6d, 0x62, 0x61,
+0x43, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x63, 0x3b,
+0x41, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b,
+0x43, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x74, 0x3b, 0x53, 0x65, 0x70, 0x3b,
+0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x62, 0x3b, 0x44, 0x69, 0x73, 0x43,
+0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x43,
+0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x4a, 0x61,
+0x6e, 0x61, 0x69, 0x72, 0x75, 0x3b, 0x46, 0x61, 0x62, 0x75, 0x72, 0x61,
+0x69, 0x72, 0x75, 0x3b, 0x4d, 0x61, 0x72, 0x69, 0x73, 0x3b, 0x41, 0x66,
+0x69, 0x72, 0x69, 0x6c, 0x75, 0x3b, 0x4d, 0x61, 0x79, 0x75, 0x3b, 0x59,
+0x75, 0x6e, 0x69, 0x3b, 0x59, 0x75, 0x6c, 0x69, 0x3b, 0x41, 0x67, 0x75,
+0x73, 0x74, 0x61, 0x3b, 0x53, 0x61, 0x74, 0x75, 0x6d, 0x62, 0x61, 0x3b,
+0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x61, 0x3b, 0x4e, 0x75, 0x77, 0x61, 0x6d,
+0x62, 0x61, 0x3b, 0x44, 0x69, 0x73, 0x61, 0x6d, 0x62, 0x61, 0x4a, 0x61,
+0x6e, 0x3b, 0x46, 0x61, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x66,
+0x69, 0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x59, 0x75, 0x6e, 0x3b, 0x59, 0x75,
+0x6c, 0x3b, 0x41, 0x67, 0x75, 0x3b, 0x53, 0x61, 0x74, 0x3b, 0x4f, 0x6b,
+0x74, 0x3b, 0x4e, 0x75, 0x77, 0x3b, 0x44, 0x69, 0x73, 0x4a, 0x3b, 0x46,
+0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x59, 0x3b, 0x59, 0x3b, 0x41,
+0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x62c, 0x64e, 0x646, 0x64e,
+0x64a, 0x652, 0x631, 0x64f, 0x3b, 0x6a2, 0x64e, 0x628, 0x652, 0x631, 0x64e, 0x64a,
+0x652, 0x631, 0x64f, 0x3b, 0x645, 0x64e, 0x631, 0x650, 0x633, 0x652, 0x3b, 0x623,
+0x64e, 0x6a2, 0x652, 0x631, 0x650, 0x644, 0x64f, 0x3b, 0x645, 0x64e, 0x64a, 0x64f,
+0x3b, 0x64a, 0x64f, 0x648, 0x646, 0x650, 0x3b, 0x64a, 0x64f, 0x648, 0x644, 0x650,
+0x3b, 0x623, 0x64e, 0x63a, 0x64f, 0x633, 0x652, 0x62a, 0x64e, 0x3b, 0x633, 0x64e,
+0x62a, 0x64f, 0x645, 0x652, 0x628, 0x64e, 0x3b, 0x623, 0x64f, 0x643, 0x652, 0x62a,
+0x648, 0x64f, 0x628, 0x64e, 0x3b, 0x646, 0x64f, 0x648, 0x64e, 0x645, 0x652, 0x628,
+0x64e, 0x3b, 0x62f, 0x650, 0x633, 0x64e, 0x645, 0x652, 0x628, 0x64e, 0x62c, 0x64e,
+0x646, 0x3b, 0x6a2, 0x64e, 0x628, 0x3b, 0x645, 0x64e, 0x631, 0x3b, 0x623, 0x64e,
+0x6a2, 0x652, 0x631, 0x3b, 0x645, 0x64e, 0x64a, 0x3b, 0x64a, 0x64f, 0x648, 0x646,
+0x3b, 0x64a, 0x64f, 0x648, 0x644, 0x3b, 0x623, 0x64e, 0x63a, 0x64f, 0x3b, 0x633,
+0x64e, 0x62a, 0x3b, 0x623, 0x64f, 0x643, 0x652, 0x62a, 0x3b, 0x646, 0x64f, 0x648,
+0x3b, 0x62f, 0x650, 0x633, 0x49, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x69, 0x3b,
+0x50, 0x65, 0x70, 0x65, 0x6c, 0x75, 0x61, 0x6c, 0x69, 0x3b, 0x4d, 0x61,
+0x6c, 0x61, 0x6b, 0x69, 0x3b, 0x2bb, 0x41, 0x70, 0x65, 0x6c, 0x69, 0x6c,
+0x61, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x49, 0x75, 0x6e, 0x65, 0x3b, 0x49,
+0x75, 0x6c, 0x61, 0x69, 0x3b, 0x2bb, 0x41, 0x75, 0x6b, 0x61, 0x6b, 0x65,
+0x3b, 0x4b, 0x65, 0x70, 0x61, 0x6b, 0x65, 0x6d, 0x61, 0x70, 0x61, 0x3b,
+0x2bb, 0x4f, 0x6b, 0x61, 0x6b, 0x6f, 0x70, 0x61, 0x3b, 0x4e, 0x6f, 0x77,
+0x65, 0x6d, 0x61, 0x70, 0x61, 0x3b, 0x4b, 0x65, 0x6b, 0x65, 0x6d, 0x61,
+0x70, 0x61, 0x49, 0x61, 0x6e, 0x2e, 0x3b, 0x50, 0x65, 0x70, 0x2e, 0x3b,
+0x4d, 0x61, 0x6c, 0x2e, 0x3b, 0x2bb, 0x41, 0x70, 0x2e, 0x3b, 0x4d, 0x65,
+0x69, 0x3b, 0x49, 0x75, 0x6e, 0x2e, 0x3b, 0x49, 0x75, 0x6c, 0x2e, 0x3b,
+0x2bb, 0x41, 0x75, 0x2e, 0x3b, 0x4b, 0x65, 0x70, 0x2e, 0x3b, 0x2bb, 0x4f,
+0x6b, 0x2e, 0x3b, 0x4e, 0x6f, 0x77, 0x2e, 0x3b, 0x4b, 0x65, 0x6b, 0x2e,
+0x5d9, 0x5e0, 0x5d5, 0x5d0, 0x5e8, 0x3b, 0x5e4, 0x5d1, 0x5e8, 0x5d5, 0x5d0, 0x5e8,
+0x3b, 0x5de, 0x5e8, 0x5e5, 0x3b, 0x5d0, 0x5e4, 0x5e8, 0x5d9, 0x5dc, 0x3b, 0x5de,
+0x5d0, 0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5e0, 0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5dc, 0x5d9,
+0x3b, 0x5d0, 0x5d5, 0x5d2, 0x5d5, 0x5e1, 0x5d8, 0x3b, 0x5e1, 0x5e4, 0x5d8, 0x5de,
+0x5d1, 0x5e8, 0x3b, 0x5d0, 0x5d5, 0x5e7, 0x5d8, 0x5d5, 0x5d1, 0x5e8, 0x3b, 0x5e0,
+0x5d5, 0x5d1, 0x5de, 0x5d1, 0x5e8, 0x3b, 0x5d3, 0x5e6, 0x5de, 0x5d1, 0x5e8, 0x5d9,
+0x5e0, 0x5d5, 0x5f3, 0x3b, 0x5e4, 0x5d1, 0x5e8, 0x5f3, 0x3b, 0x5de, 0x5e8, 0x5e5,
+0x3b, 0x5d0, 0x5e4, 0x5e8, 0x5f3, 0x3b, 0x5de, 0x5d0, 0x5d9, 0x3b, 0x5d9, 0x5d5,
+0x5e0, 0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5dc, 0x5d9, 0x3b, 0x5d0, 0x5d5, 0x5d2, 0x5f3,
+0x3b, 0x5e1, 0x5e4, 0x5d8, 0x5f3, 0x3b, 0x5d0, 0x5d5, 0x5e7, 0x5f3, 0x3b, 0x5e0,
+0x5d5, 0x5d1, 0x5f3, 0x3b, 0x5d3, 0x5e6, 0x5de, 0x5f3, 0x91c, 0x928, 0x935, 0x930,
+0x940, 0x3b, 0x92b, 0x93c, 0x930, 0x935, 0x930, 0x940, 0x3b, 0x92e, 0x93e, 0x930,
+0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x948, 0x932, 0x3b, 0x92e, 0x908,
+0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x93e, 0x908, 0x3b, 0x905,
+0x917, 0x938, 0x94d, 0x924, 0x3b, 0x938, 0x93f, 0x924, 0x902, 0x92c, 0x930, 0x3b,
+0x905, 0x915, 0x94d, 0x924, 0x942, 0x92c, 0x930, 0x3b, 0x928, 0x935, 0x902, 0x92c,
+0x930, 0x3b, 0x926, 0x93f, 0x938, 0x902, 0x92c, 0x930, 0x91c, 0x928, 0x970, 0x3b,
+0x92b, 0x93c, 0x930, 0x970, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905,
+0x92a, 0x94d, 0x930, 0x948, 0x932, 0x3b, 0x92e, 0x908, 0x3b, 0x91c, 0x942, 0x928,
+0x3b, 0x91c, 0x941, 0x932, 0x970, 0x3b, 0x905, 0x917, 0x970, 0x3b, 0x938, 0x93f,
+0x924, 0x970, 0x3b, 0x905, 0x915, 0x94d, 0x924, 0x942, 0x970, 0x3b, 0x928, 0x935,
+0x970, 0x3b, 0x926, 0x93f, 0x938, 0x970, 0x91c, 0x3b, 0x92b, 0x93c, 0x3b, 0x92e,
+0x93e, 0x3b, 0x905, 0x3b, 0x92e, 0x3b, 0x91c, 0x942, 0x3b, 0x91c, 0x941, 0x3b,
+0x905, 0x3b, 0x938, 0x93f, 0x3b, 0x905, 0x3b, 0x928, 0x3b, 0x926, 0x93f, 0x6a,
+0x61, 0x6e, 0x75, 0xe1, 0x72, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0xe1,
+0x72, 0x3b, 0x6d, 0xe1, 0x72, 0x63, 0x69, 0x75, 0x73, 0x3b, 0xe1, 0x70,
+0x72, 0x69, 0x6c, 0x69, 0x73, 0x3b, 0x6d, 0xe1, 0x6a, 0x75, 0x73, 0x3b,
+0x6a, 0xfa, 0x6e, 0x69, 0x75, 0x73, 0x3b, 0x6a, 0xfa, 0x6c, 0x69, 0x75,
+0x73, 0x3b, 0x61, 0x75, 0x67, 0x75, 0x73, 0x7a, 0x74, 0x75, 0x73, 0x3b,
+0x73, 0x7a, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x6f,
+0x6b, 0x74, 0xf3, 0x62, 0x65, 0x72, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d,
+0x62, 0x65, 0x72, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x65, 0x72,
+0x6a, 0x61, 0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x2e, 0x3b, 0x6d,
+0xe1, 0x72, 0x63, 0x2e, 0x3b, 0xe1, 0x70, 0x72, 0x2e, 0x3b, 0x6d, 0xe1,
+0x6a, 0x2e, 0x3b, 0x6a, 0xfa, 0x6e, 0x2e, 0x3b, 0x6a, 0xfa, 0x6c, 0x2e,
+0x3b, 0x61, 0x75, 0x67, 0x2e, 0x3b, 0x73, 0x7a, 0x65, 0x70, 0x74, 0x2e,
+0x3b, 0x6f, 0x6b, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64,
+0x65, 0x63, 0x2e, 0x4a, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0xc1, 0x3b, 0x4d,
+0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x41, 0x3b, 0x53, 0x7a, 0x3b, 0x4f, 0x3b,
+0x4e, 0x3b, 0x44, 0x6a, 0x61, 0x6e, 0xfa, 0x61, 0x72, 0x3b, 0x66, 0x65,
+0x62, 0x72, 0xfa, 0x61, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x3b, 0x61,
+0x70, 0x72, 0xed, 0x6c, 0x3b, 0x6d, 0x61, 0xed, 0x3b, 0x6a, 0xfa, 0x6e,
+0xed, 0x3b, 0x6a, 0xfa, 0x6c, 0xed, 0x3b, 0xe1, 0x67, 0xfa, 0x73, 0x74,
+0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x6f,
+0x6b, 0x74, 0xf3, 0x62, 0x65, 0x72, 0x3b, 0x6e, 0xf3, 0x76, 0x65, 0x6d,
+0x62, 0x65, 0x72, 0x3b, 0x64, 0x65, 0x73, 0x65, 0x6d, 0x62, 0x65, 0x72,
+0x6a, 0x61, 0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x62, 0x2e, 0x3b, 0x6d, 0x61,
+0x72, 0x2e, 0x3b, 0x61, 0x70, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0xed, 0x3b,
+0x6a, 0xfa, 0x6e, 0x2e, 0x3b, 0x6a, 0xfa, 0x6c, 0x2e, 0x3b, 0xe1, 0x67,
+0xfa, 0x2e, 0x3b, 0x73, 0x65, 0x70, 0x2e, 0x3b, 0x6f, 0x6b, 0x74, 0x2e,
+0x3b, 0x6e, 0xf3, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x73, 0x2e, 0x4a, 0x3b,
+0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b,
+0xc1, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x4a, 0x65, 0x6e,
+0x1ee5, 0x77, 0x61, 0x72, 0x1ecb, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x1ee5, 0x77,
+0x61, 0x72, 0x1ecb, 0x3b, 0x4d, 0x61, 0x61, 0x63, 0x68, 0x1ecb, 0x3b, 0x45,
+0x70, 0x72, 0x65, 0x65, 0x6c, 0x3b, 0x4d, 0x65, 0x65, 0x3b, 0x4a, 0x75,
+0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x61, 0x1ecb, 0x3b, 0x1ecc, 0x67, 0x1ecd,
+0x1ecd, 0x73, 0x74, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x61,
+0x3b, 0x1ecc, 0x6b, 0x74, 0x6f, 0x62, 0x61, 0x3b, 0x4e, 0x6f, 0x76, 0x65,
+0x6d, 0x62, 0x61, 0x3b, 0x44, 0x69, 0x73, 0x65, 0x6d, 0x62, 0x61, 0x4a,
+0x65, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x61, 0x3b, 0x45,
+0x70, 0x72, 0x3b, 0x4d, 0x65, 0x65, 0x3b, 0x4a, 0x75, 0x75, 0x3b, 0x4a,
+0x75, 0x6c, 0x3b, 0x1ecc, 0x67, 0x1ecd, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x1ecc,
+0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x69, 0x73, 0x4a, 0x3b,
+0x46, 0x3b, 0x4d, 0x3b, 0x45, 0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b,
+0x1ecc, 0x3b, 0x53, 0x3b, 0x1ecc, 0x3b, 0x4e, 0x3b, 0x44, 0x75, 0x111, 0x111,
+0xe2, 0x69, 0x76, 0x65, 0x6d, 0xe1, 0xe1, 0x6e, 0x75, 0x3b, 0x6b, 0x75,
+0x6f, 0x76, 0xe2, 0x6d, 0xe1, 0xe1, 0x6e, 0x75, 0x3b, 0x6e, 0x6a, 0x75,
+0x68, 0x10d, 0xe2, 0x6d, 0xe1, 0xe1, 0x6e, 0x75, 0x3b, 0x63, 0x75, 0xe1,
+0x14b, 0x75, 0x69, 0x6d, 0xe1, 0xe1, 0x6e, 0x75, 0x3b, 0x76, 0x79, 0x65,
+0x73, 0x69, 0x6d, 0xe1, 0xe1, 0x6e, 0x75, 0x3b, 0x6b, 0x65, 0x73, 0x69,
+0x6d, 0xe1, 0xe1, 0x6e, 0x75, 0x3b, 0x73, 0x79, 0x65, 0x69, 0x6e, 0x69,
+0x6d, 0xe1, 0xe1, 0x6e, 0x75, 0x3b, 0x70, 0x6f, 0x72, 0x67, 0x65, 0x6d,
+0xe1, 0xe1, 0x6e, 0x75, 0x3b, 0x10d, 0x6f, 0x68, 0x10d, 0xe2, 0x6d, 0xe1,
+0xe1, 0x6e, 0x75, 0x3b, 0x72, 0x6f, 0x6f, 0x76, 0x76, 0xe2, 0x64, 0x6d,
+0xe1, 0xe1, 0x6e, 0x75, 0x3b, 0x73, 0x6b, 0x61, 0x6d, 0x6d, 0xe2, 0x6d,
+0xe1, 0xe1, 0x6e, 0x75, 0x3b, 0x6a, 0x75, 0x6f, 0x76, 0x6c, 0xe2, 0x6d,
+0xe1, 0xe1, 0x6e, 0x75, 0x75, 0x111, 0x69, 0x76, 0x3b, 0x6b, 0x75, 0x6f,
+0x76, 0xe2, 0x3b, 0x6e, 0x6a, 0x75, 0x68, 0x10d, 0xe2, 0x3b, 0x63, 0x75,
+0xe1, 0x14b, 0x75, 0x69, 0x3b, 0x76, 0x79, 0x65, 0x73, 0x69, 0x3b, 0x6b,
+0x65, 0x73, 0x69, 0x3b, 0x73, 0x79, 0x65, 0x69, 0x6e, 0x69, 0x3b, 0x70,
+0x6f, 0x72, 0x67, 0x65, 0x3b, 0x10d, 0x6f, 0x68, 0x10d, 0xe2, 0x3b, 0x72,
+0x6f, 0x6f, 0x76, 0x76, 0xe2, 0x64, 0x3b, 0x73, 0x6b, 0x61, 0x6d, 0x6d,
+0xe2, 0x3b, 0x6a, 0x75, 0x6f, 0x76, 0x6c, 0xe2, 0x55, 0x3b, 0x4b, 0x3b,
+0x4e, 0x4a, 0x3b, 0x43, 0x3b, 0x56, 0x3b, 0x4b, 0x3b, 0x53, 0x3b, 0x50,
+0x3b, 0x10c, 0x3b, 0x52, 0x3b, 0x53, 0x3b, 0x4a, 0x4a, 0x61, 0x6e, 0x75,
+0x61, 0x72, 0x69, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x69,
+0x3b, 0x4d, 0x61, 0x72, 0x65, 0x74, 0x3b, 0x41, 0x70, 0x72, 0x69, 0x6c,
+0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75,
+0x6c, 0x69, 0x3b, 0x41, 0x67, 0x75, 0x73, 0x74, 0x75, 0x73, 0x3b, 0x53,
+0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74,
+0x6f, 0x62, 0x65, 0x72, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65,
+0x72, 0x3b, 0x44, 0x65, 0x73, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4a, 0x61,
+0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x70,
+0x72, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75,
+0x6c, 0x3b, 0x41, 0x67, 0x75, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b,
+0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x73, 0x6a, 0x61, 0x6e,
+0x75, 0x61, 0x72, 0x69, 0x6f, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0x61,
+0x72, 0x69, 0x6f, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x69, 0x6f, 0x3b, 0x61,
+0x70, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x61, 0x69, 0x6f, 0x3b, 0x6a, 0x75,
+0x6e, 0x69, 0x6f, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x6f, 0x3b, 0x61, 0x75,
+0x67, 0x75, 0x73, 0x74, 0x6f, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d,
+0x62, 0x72, 0x65, 0x3b, 0x6f, 0x63, 0x74, 0x6f, 0x62, 0x72, 0x65, 0x3b,
+0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x65, 0x63,
+0x65, 0x6d, 0x62, 0x72, 0x65, 0x6a, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x62,
+0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0x61, 0x69,
+0x3b, 0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x75, 0x67,
+0x3b, 0x73, 0x65, 0x70, 0x3b, 0x6f, 0x63, 0x74, 0x3b, 0x6e, 0x6f, 0x76,
+0x3b, 0x64, 0x65, 0x63, 0x6a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x3b, 0x66,
+0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x65,
+0x3b, 0x61, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x61, 0x79, 0x3b, 0x6a,
+0x75, 0x6e, 0x69, 0x6f, 0x3b, 0x6a, 0x75, 0x6c, 0xed, 0x3b, 0x61, 0x75,
+0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62,
+0x72, 0x65, 0x3b, 0x6f, 0x63, 0x74, 0x6f, 0x62, 0x72, 0x65, 0x3b, 0x6e,
+0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x65, 0x63, 0x65,
+0x6d, 0x62, 0x72, 0x65, 0x6a, 0x61, 0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x62,
+0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x61, 0x70, 0x72, 0x2e,
+0x3b, 0x6d, 0x61, 0x79, 0x3b, 0x6a, 0x75, 0x6e, 0x2e, 0x3b, 0x6a, 0x75,
+0x6c, 0xed, 0x3b, 0x61, 0x75, 0x67, 0x2e, 0x3b, 0x73, 0x65, 0x70, 0x74,
+0x2e, 0x3b, 0x6f, 0x63, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b,
+0x64, 0x65, 0x63, 0x2e, 0x152d, 0x14d0, 0x14c4, 0x140a, 0x14d5, 0x3b, 0x1555, 0x155d,
+0x1557, 0x140a, 0x14d5, 0x3b, 0x14ab, 0x1466, 0x14ef, 0x3b, 0x140a, 0x1403, 0x1449, 0x1433,
+0x14d7, 0x3b, 0x14aa, 0x1403, 0x3b, 0x152b, 0x14c2, 0x3b, 0x152a, 0x14da, 0x1403, 0x3b,
+0x140a, 0x1405, 0x14a1, 0x148d, 0x14ef, 0x3b, 0x14ef, 0x144e, 0x1431, 0x1546, 0x3b, 0x1406,
+0x1466, 0x1451, 0x155d, 0x1559, 0x3b, 0x14c4, 0x1555, 0x1431, 0x1546, 0x3b, 0x144e, 0x14ef,
+0x1431, 0x1546, 0x45, 0x61, 0x6e, 0xe1, 0x69, 0x72, 0x3b, 0x46, 0x65, 0x61,
+0x62, 0x68, 0x72, 0x61, 0x3b, 0x4d, 0xe1, 0x72, 0x74, 0x61, 0x3b, 0x41,
+0x69, 0x62, 0x72, 0x65, 0xe1, 0x6e, 0x3b, 0x42, 0x65, 0x61, 0x6c, 0x74,
+0x61, 0x69, 0x6e, 0x65, 0x3b, 0x4d, 0x65, 0x69, 0x74, 0x68, 0x65, 0x61,
+0x6d, 0x68, 0x3b, 0x49, 0xfa, 0x69, 0x6c, 0x3b, 0x4c, 0xfa, 0x6e, 0x61,
+0x73, 0x61, 0x3b, 0x4d, 0x65, 0xe1, 0x6e, 0x20, 0x46, 0xf3, 0x6d, 0x68,
+0x61, 0x69, 0x72, 0x3b, 0x44, 0x65, 0x69, 0x72, 0x65, 0x61, 0x64, 0x68,
+0x20, 0x46, 0xf3, 0x6d, 0x68, 0x61, 0x69, 0x72, 0x3b, 0x53, 0x61, 0x6d,
+0x68, 0x61, 0x69, 0x6e, 0x3b, 0x4e, 0x6f, 0x6c, 0x6c, 0x61, 0x69, 0x67,
+0x45, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x61, 0x62, 0x68, 0x3b, 0x4d, 0xe1,
+0x72, 0x74, 0x61, 0x3b, 0x41, 0x69, 0x62, 0x3b, 0x42, 0x65, 0x61, 0x6c,
+0x3b, 0x4d, 0x65, 0x69, 0x74, 0x68, 0x3b, 0x49, 0xfa, 0x69, 0x6c, 0x3b,
+0x4c, 0xfa, 0x6e, 0x3b, 0x4d, 0x46, 0xf3, 0x6d, 0x68, 0x3b, 0x44, 0x46,
+0xf3, 0x6d, 0x68, 0x3b, 0x53, 0x61, 0x6d, 0x68, 0x3b, 0x4e, 0x6f, 0x6c,
+0x6c, 0x45, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x42, 0x3b, 0x4d,
+0x3b, 0x49, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x44, 0x3b, 0x53, 0x3b, 0x4e,
+0x67, 0x65, 0x6e, 0x6e, 0x61, 0x69, 0x6f, 0x3b, 0x66, 0x65, 0x62, 0x62,
+0x72, 0x61, 0x69, 0x6f, 0x3b, 0x6d, 0x61, 0x72, 0x7a, 0x6f, 0x3b, 0x61,
+0x70, 0x72, 0x69, 0x6c, 0x65, 0x3b, 0x6d, 0x61, 0x67, 0x67, 0x69, 0x6f,
+0x3b, 0x67, 0x69, 0x75, 0x67, 0x6e, 0x6f, 0x3b, 0x6c, 0x75, 0x67, 0x6c,
+0x69, 0x6f, 0x3b, 0x61, 0x67, 0x6f, 0x73, 0x74, 0x6f, 0x3b, 0x73, 0x65,
+0x74, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x6f, 0x74, 0x74, 0x6f,
+0x62, 0x72, 0x65, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x65,
+0x3b, 0x64, 0x69, 0x63, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x67, 0x65, 0x6e,
+0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x61, 0x70, 0x72,
+0x3b, 0x6d, 0x61, 0x67, 0x3b, 0x67, 0x69, 0x75, 0x3b, 0x6c, 0x75, 0x67,
+0x3b, 0x61, 0x67, 0x6f, 0x3b, 0x73, 0x65, 0x74, 0x3b, 0x6f, 0x74, 0x74,
+0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x69, 0x63, 0x4a, 0x61, 0x6e, 0x3b,
+0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b,
+0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b,
+0x41, 0x67, 0x74, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b,
+0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x73, 0x48, 0x79, 0x77, 0x61, 0x6e,
+0x20, 0x41, 0x331, 0x79, 0x72, 0x6e, 0x69, 0x67, 0x3b, 0x48, 0x79, 0x77,
+0x61, 0x6e, 0x20, 0x41, 0x331, 0x68, 0x77, 0x61, 0x3b, 0x48, 0x79, 0x77,
+0x61, 0x6e, 0x20, 0x41, 0x331, 0x74, 0x61, 0x74, 0x3b, 0x48, 0x79, 0x77,
+0x61, 0x6e, 0x20, 0x41, 0x331, 0x6e, 0x61, 0x61, 0x69, 0x3b, 0x48, 0x79,
+0x77, 0x61, 0x6e, 0x20, 0x41, 0x331, 0x70, 0x66, 0x77, 0x6f, 0x6e, 0x3b,
+0x48, 0x79, 0x77, 0x61, 0x6e, 0x20, 0x41, 0x331, 0x6b, 0x69, 0x74, 0x61,
+0x74, 0x3b, 0x48, 0x79, 0x77, 0x61, 0x6e, 0x20, 0x41, 0x331, 0x74, 0x79,
+0x69, 0x72, 0x69, 0x6e, 0x3b, 0x48, 0x79, 0x77, 0x61, 0x6e, 0x20, 0x41,
+0x331, 0x6e, 0x69, 0x6e, 0x61, 0x69, 0x3b, 0x48, 0x79, 0x77, 0x61, 0x6e,
+0x20, 0x41, 0x331, 0x6b, 0x75, 0x6d, 0x76, 0x69, 0x72, 0x69, 0x79, 0x69,
+0x6e, 0x3b, 0x48, 0x79, 0x77, 0x61, 0x6e, 0x20, 0x53, 0x77, 0x61, 0x6b,
+0x3b, 0x48, 0x79, 0x77, 0x61, 0x6e, 0x20, 0x53, 0x77, 0x61, 0x6b, 0x20,
+0x42, 0x2019, 0x61, 0x331, 0x79, 0x72, 0x6e, 0x69, 0x67, 0x3b, 0x48, 0x79,
+0x77, 0x61, 0x6e, 0x20, 0x53, 0x77, 0x61, 0x6b, 0x20, 0x42, 0x2019, 0x61,
+0x331, 0x68, 0x77, 0x61, 0x41, 0x331, 0x79, 0x72, 0x3b, 0x41, 0x331, 0x68,
+0x77, 0x3b, 0x41, 0x331, 0x74, 0x61, 0x3b, 0x41, 0x331, 0x6e, 0x61, 0x3b,
+0x41, 0x331, 0x70, 0x66, 0x3b, 0x41, 0x331, 0x6b, 0x69, 0x3b, 0x41, 0x331,
+0x74, 0x79, 0x3b, 0x41, 0x331, 0x6e, 0x69, 0x3b, 0x41, 0x331, 0x6b, 0x75,
+0x3b, 0x53, 0x77, 0x61, 0x3b, 0x53, 0x62, 0x79, 0x3b, 0x53, 0x62, 0x68,
+0x53, 0x61, 0x6e, 0x76, 0x69, 0x65, 0x3b, 0x46, 0xe9, 0x62, 0x69, 0x72,
+0x69, 0x65, 0x3b, 0x4d, 0x61, 0x72, 0x73, 0x3b, 0x41, 0x62, 0x75, 0x72,
+0x69, 0x6c, 0x3b, 0x4d, 0x65, 0x65, 0x3b, 0x53, 0x75, 0x65, 0x14b, 0x3b,
+0x53, 0xfa, 0x75, 0x79, 0x65, 0x65, 0x3b, 0x55, 0x74, 0x3b, 0x53, 0x65,
+0x74, 0x74, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f,
+0x62, 0x61, 0x72, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x72,
+0x3b, 0x44, 0x69, 0x73, 0x61, 0x6d, 0x62, 0x61, 0x72, 0x53, 0x61, 0x3b,
+0x46, 0x65, 0x3b, 0x4d, 0x61, 0x3b, 0x41, 0x62, 0x3b, 0x4d, 0x65, 0x3b,
+0x53, 0x75, 0x3b, 0x53, 0xfa, 0x3b, 0x55, 0x74, 0x3b, 0x53, 0x65, 0x3b,
+0x4f, 0x6b, 0x3b, 0x4e, 0x6f, 0x3b, 0x44, 0x65, 0x53, 0x3b, 0x46, 0x3b,
+0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x53, 0x3b, 0x53, 0x3b, 0x55, 0x3b,
+0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x4a, 0x61, 0x6e, 0x65, 0x72,
+0x75, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x65, 0x72, 0x75, 0x3b, 0x4d, 0x61,
+0x72, 0x73, 0x75, 0x3b, 0x41, 0x62, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x61,
+0x69, 0x75, 0x3b, 0x4a, 0x75, 0x6e, 0x68, 0x75, 0x3b, 0x4a, 0x75, 0x6c,
+0x68, 0x75, 0x3b, 0x41, 0x67, 0x6f, 0x73, 0x74, 0x75, 0x3b, 0x53, 0x65,
+0x74, 0x65, 0x6e, 0x62, 0x72, 0x75, 0x3b, 0x4f, 0x74, 0x75, 0x62, 0x72,
+0x75, 0x3b, 0x4e, 0x75, 0x76, 0x65, 0x6e, 0x62, 0x72, 0x75, 0x3b, 0x44,
+0x69, 0x7a, 0x65, 0x6e, 0x62, 0x72, 0x75, 0x4a, 0x61, 0x6e, 0x3b, 0x46,
+0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x62, 0x72, 0x3b, 0x4d,
+0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41,
+0x67, 0x6f, 0x3b, 0x53, 0x65, 0x74, 0x3b, 0x4f, 0x74, 0x75, 0x3b, 0x4e,
+0x75, 0x76, 0x3b, 0x44, 0x69, 0x7a, 0x59, 0x65, 0x6e, 0x6e, 0x61, 0x79,
+0x65, 0x72, 0x3b, 0x46, 0x75, 0x1e5b, 0x61, 0x72, 0x3b, 0x4d, 0x65, 0x263,
+0x72, 0x65, 0x73, 0x3b, 0x59, 0x65, 0x62, 0x72, 0x69, 0x72, 0x3b, 0x4d,
+0x61, 0x79, 0x79, 0x75, 0x3b, 0x59, 0x75, 0x6e, 0x79, 0x75, 0x3b, 0x59,
+0x75, 0x6c, 0x79, 0x75, 0x3b, 0x194, 0x75, 0x63, 0x74, 0x3b, 0x43, 0x74,
+0x65, 0x6d, 0x62, 0x65, 0x1e5b, 0x3b, 0x54, 0x75, 0x62, 0x65, 0x1e5b, 0x3b,
+0x4e, 0x75, 0x6e, 0x65, 0x6d, 0x62, 0x65, 0x1e5b, 0x3b, 0x44, 0x75, 0x1e7,
+0x65, 0x6d, 0x62, 0x65, 0x1e5b, 0x59, 0x65, 0x6e, 0x3b, 0x46, 0x75, 0x72,
+0x3b, 0x4d, 0x65, 0x263, 0x3b, 0x59, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x79,
+0x3b, 0x59, 0x75, 0x6e, 0x3b, 0x59, 0x75, 0x6c, 0x3b, 0x194, 0x75, 0x63,
+0x3b, 0x43, 0x74, 0x65, 0x3b, 0x54, 0x75, 0x62, 0x3b, 0x57, 0x61, 0x6d,
+0x3b, 0x44, 0x75, 0x1e7, 0x59, 0x65, 0x6e, 0x3b, 0x46, 0x75, 0x72, 0x3b,
+0x4d, 0x65, 0x263, 0x3b, 0x59, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x79, 0x3b,
+0x59, 0x75, 0x6e, 0x3b, 0x59, 0x75, 0x6c, 0x3b, 0x194, 0x75, 0x63, 0x3b,
+0x43, 0x74, 0x65, 0x3b, 0x54, 0x75, 0x62, 0x3b, 0x4e, 0x75, 0x6e, 0x3b,
+0x44, 0x75, 0x1e7, 0x59, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x59, 0x3b, 0x4d,
+0x3b, 0x59, 0x3b, 0x59, 0x3b, 0x194, 0x3b, 0x43, 0x3b, 0x54, 0x3b, 0x4e,
+0x3b, 0x44, 0x59, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x59, 0x3b, 0x4d, 0x3b,
+0x59, 0x3b, 0x59, 0x3b, 0x194, 0x3b, 0x43, 0x3b, 0x54, 0x3b, 0x57, 0x3b,
+0x44, 0x70, 0x61, 0x6d, 0x62, 0x61, 0x3b, 0x77, 0x61, 0x6e, 0x6a, 0x61,
+0x3b, 0x6d, 0x62, 0x69, 0x79, 0x254, 0x20, 0x6d, 0x25b, 0x6e, 0x64, 0x6f,
+0x14b, 0x67, 0x254, 0x3b, 0x4e, 0x79, 0x254, 0x6c, 0x254, 0x6d, 0x62, 0x254,
+0x14b, 0x67, 0x254, 0x3b, 0x4d, 0x254, 0x6e, 0x254, 0x20, 0x14b, 0x67, 0x62,
+0x61, 0x6e, 0x6a, 0x61, 0x3b, 0x4e, 0x79, 0x61, 0x14b, 0x67, 0x77, 0x25b,
+0x20, 0x14b, 0x67, 0x62, 0x61, 0x6e, 0x6a, 0x61, 0x3b, 0x6b, 0x75, 0x14b,
+0x67, 0x77, 0x25b, 0x3b, 0x66, 0x25b, 0x3b, 0x6e, 0x6a, 0x61, 0x70, 0x69,
+0x3b, 0x6e, 0x79, 0x75, 0x6b, 0x75, 0x6c, 0x3b, 0x4d, 0x31, 0x31, 0x3b,
+0x253, 0x75, 0x6c, 0x253, 0x75, 0x73, 0x25b, 0x6a, 0x61, 0x6e, 0x75, 0x61,
+0x61, 0x72, 0x69, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0x61, 0x61, 0x72,
+0x69, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x69, 0x3b, 0x61, 0x70, 0x72, 0x69,
+0x69, 0x6c, 0x69, 0x3b, 0x6d, 0x61, 0x61, 0x6a, 0x69, 0x3b, 0x6a, 0x75,
+0x75, 0x6e, 0x69, 0x3b, 0x6a, 0x75, 0x75, 0x6c, 0x69, 0x3b, 0x61, 0x67,
+0x67, 0x75, 0x73, 0x74, 0x69, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d,
+0x62, 0x61, 0x72, 0x69, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x61, 0x72,
+0x69, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x69, 0x3b,
+0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x69, 0x6a, 0x61, 0x6e,
+0x75, 0x61, 0x61, 0x72, 0x69, 0x70, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75,
+0x61, 0x61, 0x72, 0x69, 0x70, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x69, 0x70,
+0x3b, 0x61, 0x70, 0x72, 0x69, 0x69, 0x6c, 0x69, 0x70, 0x3b, 0x6d, 0x61,
+0x61, 0x6a, 0x69, 0x70, 0x3b, 0x6a, 0x75, 0x75, 0x6e, 0x69, 0x70, 0x3b,
+0x6a, 0x75, 0x75, 0x6c, 0x69, 0x70, 0x3b, 0x61, 0x67, 0x67, 0x75, 0x73,
+0x74, 0x69, 0x70, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x61,
+0x72, 0x69, 0x70, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x61, 0x72, 0x69,
+0x70, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x69, 0x70,
+0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x69, 0x70, 0x6a,
+0x61, 0x6e, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x3b, 0x6d, 0x61, 0x72, 0x3b,
+0x61, 0x70, 0x72, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x3b,
+0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x75, 0x67, 0x3b, 0x73, 0x65, 0x70, 0x74,
+0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65, 0x63,
+0x4d, 0x75, 0x6c, 0x67, 0x75, 0x6c, 0x3b, 0x4e, 0x67, 0x2019, 0x61, 0x74,
+0x79, 0x61, 0x61, 0x74, 0x6f, 0x3b, 0x4b, 0x69, 0x70, 0x74, 0x61, 0x61,
+0x6d, 0x6f, 0x3b, 0x49, 0x77, 0x6f, 0x6f, 0x74, 0x6b, 0x75, 0x75, 0x74,
+0x3b, 0x4d, 0x61, 0x6d, 0x75, 0x75, 0x74, 0x3b, 0x50, 0x61, 0x61, 0x67,
+0x69, 0x3b, 0x4e, 0x67, 0x2019, 0x65, 0x69, 0x79, 0x65, 0x65, 0x74, 0x3b,
+0x52, 0x6f, 0x6f, 0x70, 0x74, 0x75, 0x69, 0x3b, 0x42, 0x75, 0x72, 0x65,
+0x65, 0x74, 0x3b, 0x45, 0x70, 0x65, 0x65, 0x73, 0x6f, 0x3b, 0x4b, 0x69,
+0x70, 0x73, 0x75, 0x75, 0x6e, 0x64, 0x65, 0x20, 0x6e, 0x65, 0x20, 0x74,
+0x61, 0x61, 0x69, 0x3b, 0x4b, 0x69, 0x70, 0x73, 0x75, 0x75, 0x6e, 0x64,
+0x65, 0x20, 0x6e, 0x65, 0x62, 0x6f, 0x20, 0x61, 0x65, 0x6e, 0x67, 0x2019,
+0x4d, 0x75, 0x6c, 0x3b, 0x4e, 0x67, 0x61, 0x74, 0x3b, 0x54, 0x61, 0x61,
+0x3b, 0x49, 0x77, 0x6f, 0x3b, 0x4d, 0x61, 0x6d, 0x3b, 0x50, 0x61, 0x61,
+0x3b, 0x4e, 0x67, 0x65, 0x3b, 0x52, 0x6f, 0x6f, 0x3b, 0x42, 0x75, 0x72,
+0x3b, 0x45, 0x70, 0x65, 0x3b, 0x4b, 0x70, 0x74, 0x3b, 0x4b, 0x70, 0x61,
+0x4d, 0x3b, 0x4e, 0x3b, 0x54, 0x3b, 0x49, 0x3b, 0x4d, 0x3b, 0x50, 0x3b,
+0x4e, 0x3b, 0x52, 0x3b, 0x42, 0x3b, 0x45, 0x3b, 0x4b, 0x3b, 0x4b, 0x4d,
+0x77, 0x61, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6d, 0x62, 0x65, 0x65, 0x3b,
+0x4d, 0x77, 0x61, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x65, 0x6c, 0x129,
+0x3b, 0x4d, 0x77, 0x61, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x74,
+0x61, 0x74, 0x169, 0x3b, 0x4d, 0x77, 0x61, 0x69, 0x20, 0x77, 0x61, 0x20,
+0x6b, 0x61, 0x6e, 0x61, 0x3b, 0x4d, 0x77, 0x61, 0x69, 0x20, 0x77, 0x61,
+0x20, 0x6b, 0x61, 0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x4d, 0x77, 0x61, 0x69,
+0x20, 0x77, 0x61, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x74, 0x68, 0x61, 0x74,
+0x169, 0x3b, 0x4d, 0x77, 0x61, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6d, 0x75,
+0x6f, 0x6e, 0x7a, 0x61, 0x3b, 0x4d, 0x77, 0x61, 0x69, 0x20, 0x77, 0x61,
+0x20, 0x6e, 0x79, 0x61, 0x61, 0x6e, 0x79, 0x61, 0x3b, 0x4d, 0x77, 0x61,
+0x69, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x65, 0x6e, 0x64, 0x61, 0x3b, 0x4d,
+0x77, 0x61, 0x69, 0x20, 0x77, 0x61, 0x20, 0x129, 0x6b, 0x75, 0x6d, 0x69,
+0x3b, 0x4d, 0x77, 0x61, 0x69, 0x20, 0x77, 0x61, 0x20, 0x129, 0x6b, 0x75,
+0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x129, 0x6d, 0x77, 0x65, 0x3b, 0x4d,
+0x77, 0x61, 0x69, 0x20, 0x77, 0x61, 0x20, 0x129, 0x6b, 0x75, 0x6d, 0x69,
+0x20, 0x6e, 0x61, 0x20, 0x69, 0x6c, 0x129, 0x4d, 0x62, 0x65, 0x3b, 0x4b,
+0x65, 0x6c, 0x3b, 0x4b, 0x74, 0x169, 0x3b, 0x4b, 0x61, 0x6e, 0x3b, 0x4b,
+0x74, 0x6e, 0x3b, 0x54, 0x68, 0x61, 0x3b, 0x4d, 0x6f, 0x6f, 0x3b, 0x4e,
+0x79, 0x61, 0x3b, 0x4b, 0x6e, 0x64, 0x3b, 0x128, 0x6b, 0x75, 0x3b, 0x128,
+0x6b, 0x6d, 0x3b, 0x128, 0x6b, 0x6c, 0x4d, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b,
+0x4b, 0x3b, 0x4b, 0x3b, 0x54, 0x3b, 0x4d, 0x3b, 0x4e, 0x3b, 0x4b, 0x3b,
+0x128, 0x3b, 0x128, 0x3b, 0x128, 0xc9c, 0xca8, 0xcb5, 0xcb0, 0xcbf, 0x3b, 0xcab,
+0xcc6, 0xcac, 0xccd, 0xcb0, 0xcb5, 0xcb0, 0xcbf, 0x3b, 0xcae, 0xcbe, 0xcb0, 0xccd,
+0xc9a, 0xccd, 0x3b, 0xc8f, 0xcaa, 0xccd, 0xcb0, 0xcbf, 0xcb2, 0xccd, 0x3b, 0xcae,
+0xcc7, 0x3b, 0xc9c, 0xcc2, 0xca8, 0xccd, 0x3b, 0xc9c, 0xcc1, 0xcb2, 0xcc8, 0x3b,
+0xc86, 0xc97, 0xcb8, 0xccd, 0xc9f, 0xccd, 0x3b, 0xcb8, 0xcc6, 0xcaa, 0xccd, 0xc9f,
+0xcc6, 0xc82, 0xcac, 0xcb0, 0xccd, 0x3b, 0xc85, 0xc95, 0xccd, 0xc9f, 0xccb, 0xcac,
+0xcb0, 0xccd, 0x3b, 0xca8, 0xcb5, 0xcc6, 0xc82, 0xcac, 0xcb0, 0xccd, 0x3b, 0xca1,
+0xcbf, 0xcb8, 0xcc6, 0xc82, 0xcac, 0xcb0, 0xccd, 0xc9c, 0xca8, 0x3b, 0xcab, 0xcc6,
+0xcac, 0xccd, 0xcb0, 0x3b, 0xcae, 0xcbe, 0xcb0, 0xccd, 0xc9a, 0xccd, 0x3b, 0xc8f,
+0xcaa, 0xccd, 0xcb0, 0xcbf, 0x3b, 0xcae, 0xcc7, 0x3b, 0xc9c, 0xcc2, 0xca8, 0xccd,
+0x3b, 0xc9c, 0xcc1, 0xcb2, 0xcc8, 0x3b, 0xc86, 0xc97, 0x3b, 0xcb8, 0xcc6, 0xcaa,
+0xccd, 0xc9f, 0xcc6, 0xc82, 0x3b, 0xc85, 0xc95, 0xccd, 0xc9f, 0xccb, 0x3b, 0xca8,
+0xcb5, 0xcc6, 0xc82, 0x3b, 0xca1, 0xcbf, 0xcb8, 0xcc6, 0xc82, 0xc9c, 0xca8, 0xcb5,
+0xcb0, 0xcbf, 0x3b, 0xcab, 0xcc6, 0xcac, 0xccd, 0xcb0, 0xcb5, 0xcb0, 0xcbf, 0x3b,
+0xcae, 0xcbe, 0xcb0, 0xccd, 0xc9a, 0xccd, 0x3b, 0xc8f, 0xcaa, 0xccd, 0xcb0, 0xcbf,
+0x3b, 0xcae, 0xcc7, 0x3b, 0xc9c, 0xcc2, 0xca8, 0xccd, 0x3b, 0xc9c, 0xcc1, 0xcb2,
+0xcc8, 0x3b, 0xc86, 0xc97, 0xcb8, 0xccd, 0xc9f, 0xccd, 0x3b, 0xcb8, 0xcc6, 0xcaa,
+0xccd, 0xc9f, 0xcc6, 0xc82, 0x3b, 0xc85, 0xc95, 0xccd, 0xc9f, 0xccb, 0x3b, 0xca8,
+0xcb5, 0xcc6, 0xc82, 0x3b, 0xca1, 0xcbf, 0xcb8, 0xcc6, 0xc82, 0xc9c, 0x3b, 0xcab,
+0xcc6, 0x3b, 0xcae, 0xcbe, 0x3b, 0xc8f, 0x3b, 0xcae, 0xcc7, 0x3b, 0xc9c, 0xcc2,
+0x3b, 0xc9c, 0xcc1, 0x3b, 0xc86, 0x3b, 0xcb8, 0xcc6, 0x3b, 0xc85, 0x3b, 0xca8,
+0x3b, 0xca1, 0xcbf, 0x62c, 0x646, 0x624, 0x631, 0x6cc, 0x3b, 0x641, 0x631, 0x624,
+0x631, 0x6cc, 0x3b, 0x645, 0x627, 0x631, 0x655, 0x686, 0x3b, 0x627, 0x67e, 0x631,
+0x6cc, 0x644, 0x3b, 0x645, 0x626, 0x6cc, 0x3b, 0x62c, 0x648, 0x657, 0x646, 0x3b,
+0x62c, 0x648, 0x657, 0x644, 0x627, 0x6cc, 0x6cc, 0x3b, 0x627, 0x6af, 0x633, 0x62a,
+0x3b, 0x633, 0x62a, 0x645, 0x628, 0x631, 0x3b, 0x627, 0x6a9, 0x62a, 0x648, 0x657,
+0x628, 0x631, 0x3b, 0x646, 0x648, 0x645, 0x628, 0x631, 0x3b, 0x62f, 0x633, 0x645,
+0x628, 0x631, 0x62c, 0x646, 0x624, 0x631, 0x6cc, 0x3b, 0x641, 0x631, 0x624, 0x631,
+0x6cc, 0x3b, 0x645, 0x627, 0x631, 0x655, 0x686, 0x3b, 0x627, 0x67e, 0x631, 0x6cc,
+0x644, 0x3b, 0x645, 0x626, 0x6cc, 0x3b, 0x62c, 0x648, 0x657, 0x646, 0x3b, 0x62c,
+0x64f, 0x644, 0x64e, 0x6d2, 0x3b, 0x627, 0x6af, 0x633, 0x62a, 0x3b, 0x633, 0x62a,
+0x645, 0x628, 0x631, 0x3b, 0x627, 0x6a9, 0x62a, 0x648, 0x657, 0x628, 0x631, 0x3b,
+0x646, 0x648, 0x645, 0x628, 0x631, 0x3b, 0x62f, 0x64e, 0x633, 0x64e, 0x645, 0x628,
+0x64e, 0x631, 0x62c, 0x646, 0x624, 0x631, 0x6cc, 0x3b, 0x641, 0x631, 0x624, 0x631,
+0x6cc, 0x3b, 0x645, 0x627, 0x631, 0x655, 0x686, 0x3b, 0x627, 0x67e, 0x631, 0x6cc,
+0x644, 0x3b, 0x645, 0x626, 0x6cc, 0x3b, 0x62c, 0x648, 0x657, 0x646, 0x3b, 0x62c,
+0x64f, 0x644, 0x64e, 0x6d2, 0x3b, 0x627, 0x6af, 0x633, 0x62a, 0x3b, 0x633, 0x62a,
+0x645, 0x628, 0x631, 0x3b, 0x627, 0x6a9, 0x62a, 0x648, 0x657, 0x628, 0x631, 0x3b,
+0x646, 0x648, 0x645, 0x628, 0x631, 0x3b, 0x62f, 0x633, 0x645, 0x628, 0x631, 0x62c,
+0x3b, 0x641, 0x3b, 0x645, 0x3b, 0x627, 0x3b, 0x645, 0x3b, 0x62c, 0x3b, 0x62c,
+0x3b, 0x627, 0x3b, 0x633, 0x3b, 0x633, 0x3b, 0x627, 0x3b, 0x646, 0x91c, 0x928,
+0x935, 0x930, 0x940, 0x3b, 0x92b, 0x93c, 0x930, 0x935, 0x930, 0x940, 0x3b, 0x92e,
+0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x948, 0x932, 0x3b,
+0x92e, 0x947, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x93e, 0x908,
+0x3b, 0x905, 0x917, 0x938, 0x94d, 0x924, 0x3b, 0x938, 0x924, 0x941, 0x902, 0x92c,
+0x930, 0x3b, 0x905, 0x915, 0x924, 0x941, 0x92e, 0x94d, 0x92c, 0x930, 0x3b, 0x928,
+0x935, 0x942, 0x92e, 0x92c, 0x930, 0x3b, 0x926, 0x938, 0x942, 0x92e, 0x92c, 0x930,
+0x91c, 0x928, 0x935, 0x930, 0x940, 0x3b, 0x92b, 0x93c, 0x930, 0x935, 0x930, 0x940,
+0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x948,
+0x932, 0x3b, 0x92e, 0x947, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932,
+0x93e, 0x908, 0x3b, 0x905, 0x917, 0x938, 0x94d, 0x924, 0x3b, 0x938, 0x924, 0x92e,
+0x92c, 0x930, 0x3b, 0x905, 0x915, 0x94d, 0x924, 0x942, 0x92c, 0x930, 0x3b, 0x928,
+0x935, 0x92e, 0x92c, 0x930, 0x3b, 0x926, 0x938, 0x92e, 0x92c, 0x930, 0x91c, 0x928,
+0x935, 0x930, 0x940, 0x3b, 0x92b, 0x93c, 0x930, 0x935, 0x930, 0x940, 0x3b, 0x92e,
+0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x948, 0x932, 0x3b,
+0x92e, 0x947, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x93e, 0x908,
+0x3b, 0x905, 0x917, 0x938, 0x94d, 0x924, 0x3b, 0x938, 0x924, 0x941, 0x902, 0x92c,
+0x930, 0x3b, 0x905, 0x915, 0x94d, 0x924, 0x942, 0x92c, 0x930, 0x3b, 0x928, 0x935,
+0x942, 0x92e, 0x92c, 0x930, 0x3b, 0x926, 0x938, 0x942, 0x92e, 0x92c, 0x930, 0x91c,
+0x3b, 0x92b, 0x93c, 0x3b, 0x92e, 0x3b, 0x905, 0x3b, 0x92e, 0x3b, 0x91c, 0x3b,
+0x91c, 0x3b, 0x905, 0x3b, 0x938, 0x3b, 0x913, 0x3b, 0x928, 0x3b, 0x926, 0x49a,
+0x430, 0x4a3, 0x442, 0x430, 0x440, 0x3b, 0x410, 0x49b, 0x43f, 0x430, 0x43d, 0x3b,
+0x41d, 0x430, 0x443, 0x440, 0x44b, 0x437, 0x3b, 0x421, 0x4d9, 0x443, 0x456, 0x440,
+0x3b, 0x41c, 0x430, 0x43c, 0x44b, 0x440, 0x3b, 0x41c, 0x430, 0x443, 0x441, 0x44b,
+0x43c, 0x3b, 0x428, 0x456, 0x43b, 0x434, 0x435, 0x3b, 0x422, 0x430, 0x43c, 0x44b,
+0x437, 0x3b, 0x49a, 0x44b, 0x440, 0x43a, 0x4af, 0x439, 0x435, 0x43a, 0x3b, 0x49a,
+0x430, 0x437, 0x430, 0x43d, 0x3b, 0x49a, 0x430, 0x440, 0x430, 0x448, 0x430, 0x3b,
+0x416, 0x435, 0x43b, 0x442, 0x43e, 0x49b, 0x441, 0x430, 0x43d, 0x49b, 0x430, 0x4a3,
+0x442, 0x430, 0x440, 0x3b, 0x430, 0x49b, 0x43f, 0x430, 0x43d, 0x3b, 0x43d, 0x430,
+0x443, 0x440, 0x44b, 0x437, 0x3b, 0x441, 0x4d9, 0x443, 0x456, 0x440, 0x3b, 0x43c,
+0x430, 0x43c, 0x44b, 0x440, 0x3b, 0x43c, 0x430, 0x443, 0x441, 0x44b, 0x43c, 0x3b,
+0x448, 0x456, 0x43b, 0x434, 0x435, 0x3b, 0x442, 0x430, 0x43c, 0x44b, 0x437, 0x3b,
+0x49b, 0x44b, 0x440, 0x43a, 0x4af, 0x439, 0x435, 0x43a, 0x3b, 0x49b, 0x430, 0x437,
+0x430, 0x43d, 0x3b, 0x49b, 0x430, 0x440, 0x430, 0x448, 0x430, 0x3b, 0x436, 0x435,
+0x43b, 0x442, 0x43e, 0x49b, 0x441, 0x430, 0x43d, 0x49b, 0x430, 0x4a3, 0x2e, 0x3b,
+0x430, 0x49b, 0x43f, 0x2e, 0x3b, 0x43d, 0x430, 0x443, 0x2e, 0x3b, 0x441, 0x4d9,
+0x443, 0x2e, 0x3b, 0x43c, 0x430, 0x43c, 0x2e, 0x3b, 0x43c, 0x430, 0x443, 0x2e,
+0x3b, 0x448, 0x456, 0x43b, 0x2e, 0x3b, 0x442, 0x430, 0x43c, 0x2e, 0x3b, 0x49b,
+0x44b, 0x440, 0x2e, 0x3b, 0x49b, 0x430, 0x437, 0x2e, 0x3b, 0x49b, 0x430, 0x440,
+0x2e, 0x3b, 0x436, 0x435, 0x43b, 0x2e, 0x49a, 0x3b, 0x410, 0x3b, 0x41d, 0x3b,
+0x421, 0x3b, 0x41c, 0x3b, 0x41c, 0x3b, 0x428, 0x3b, 0x422, 0x3b, 0x49a, 0x3b,
+0x49a, 0x3b, 0x49a, 0x3b, 0x416, 0x1798, 0x1780, 0x179a, 0x17b6, 0x3b, 0x1780, 0x17bb,
+0x1798, 0x17d2, 0x1797, 0x17c8, 0x3b, 0x1798, 0x17b8, 0x1793, 0x17b6, 0x3b, 0x1798, 0x17c1,
+0x179f, 0x17b6, 0x3b, 0x17a7, 0x179f, 0x1797, 0x17b6, 0x3b, 0x1798, 0x17b7, 0x1790, 0x17bb,
+0x1793, 0x17b6, 0x3b, 0x1780, 0x1780, 0x17d2, 0x1780, 0x178a, 0x17b6, 0x3b, 0x179f, 0x17b8,
+0x17a0, 0x17b6, 0x3b, 0x1780, 0x1789, 0x17d2, 0x1789, 0x17b6, 0x3b, 0x178f, 0x17bb, 0x179b,
+0x17b6, 0x3b, 0x179c, 0x17b7, 0x1785, 0x17d2, 0x1786, 0x17b7, 0x1780, 0x17b6, 0x3b, 0x1792,
+0x17d2, 0x1793, 0x17bc, 0x1798, 0x3b, 0x1780, 0x3b, 0x1798, 0x3b, 0x1798, 0x3b, 0x17a7,
+0x3b, 0x1798, 0x3b, 0x1780, 0x3b, 0x179f, 0x3b, 0x1780, 0x3b, 0x178f, 0x3b, 0x179c,
+0x3b, 0x1792, 0x4e, 0x6a, 0x65, 0x6e, 0x75, 0x61, 0x72, 0x129, 0x3b, 0x4d,
+0x77, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x65, 0x72, 0x129,
+0x3b, 0x4d, 0x77, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x20, 0x67, 0x61,
+0x74, 0x61, 0x74, 0x169, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x65, 0x20, 0x77,
+0x61, 0x20, 0x6b, 0x61, 0x6e, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x65,
+0x20, 0x77, 0x61, 0x20, 0x67, 0x61, 0x74, 0x61, 0x6e, 0x6f, 0x3b, 0x4d,
+0x77, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x20, 0x67, 0x61, 0x74, 0x61,
+0x6e, 0x64, 0x61, 0x74, 0x169, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x65, 0x20,
+0x77, 0x61, 0x20, 0x6d, 0x169, 0x67, 0x77, 0x61, 0x6e, 0x6a, 0x61, 0x3b,
+0x4d, 0x77, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x6e,
+0x61, 0x6e, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x65, 0x20, 0x77, 0x61,
+0x20, 0x6b, 0x65, 0x6e, 0x64, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x65,
+0x20, 0x77, 0x61, 0x20, 0x69, 0x6b, 0x169, 0x6d, 0x69, 0x3b, 0x4d, 0x77,
+0x65, 0x72, 0x65, 0x20, 0x77, 0x61, 0x20, 0x69, 0x6b, 0x169, 0x6d, 0x69,
+0x20, 0x6e, 0x61, 0x20, 0x169, 0x6d, 0x77, 0x65, 0x3b, 0x4e, 0x64, 0x69,
+0x74, 0x68, 0x65, 0x6d, 0x62, 0x61, 0x4a, 0x45, 0x4e, 0x3b, 0x57, 0x4b,
+0x52, 0x3b, 0x57, 0x47, 0x54, 0x3b, 0x57, 0x4b, 0x4e, 0x3b, 0x57, 0x54,
+0x4e, 0x3b, 0x57, 0x54, 0x44, 0x3b, 0x57, 0x4d, 0x4a, 0x3b, 0x57, 0x4e,
+0x4e, 0x3b, 0x57, 0x4b, 0x44, 0x3b, 0x57, 0x49, 0x4b, 0x3b, 0x57, 0x4d,
+0x57, 0x3b, 0x44, 0x49, 0x54, 0x4a, 0x3b, 0x4b, 0x3b, 0x47, 0x3b, 0x4b,
+0x3b, 0x47, 0x3b, 0x47, 0x3b, 0x4d, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x49,
+0x3b, 0x49, 0x3b, 0x44, 0x4d, 0x75, 0x74, 0x61, 0x72, 0x61, 0x6d, 0x61,
+0x3b, 0x47, 0x61, 0x73, 0x68, 0x79, 0x61, 0x6e, 0x74, 0x61, 0x72, 0x65,
+0x3b, 0x57, 0x65, 0x72, 0x75, 0x72, 0x77, 0x65, 0x3b, 0x4d, 0x61, 0x74,
+0x61, 0x3b, 0x47, 0x69, 0x63, 0x75, 0x72, 0x61, 0x73, 0x69, 0x3b, 0x4b,
+0x61, 0x6d, 0x65, 0x6e, 0x61, 0x3b, 0x4e, 0x79, 0x61, 0x6b, 0x61, 0x6e,
+0x67, 0x61, 0x3b, 0x4b, 0x61, 0x6e, 0x61, 0x6d, 0x61, 0x3b, 0x4e, 0x7a,
+0x65, 0x6c, 0x69, 0x3b, 0x55, 0x6b, 0x77, 0x61, 0x6b, 0x69, 0x72, 0x61,
+0x3b, 0x55, 0x67, 0x75, 0x73, 0x68, 0x79, 0x69, 0x6e, 0x67, 0x6f, 0x3b,
+0x55, 0x6b, 0x75, 0x62, 0x6f, 0x7a, 0x61, 0x6d, 0x75, 0x74, 0x2e, 0x3b,
+0x67, 0x61, 0x73, 0x2e, 0x3b, 0x77, 0x65, 0x72, 0x2e, 0x3b, 0x6d, 0x61,
+0x74, 0x2e, 0x3b, 0x67, 0x69, 0x63, 0x2e, 0x3b, 0x6b, 0x61, 0x6d, 0x2e,
+0x3b, 0x6e, 0x79, 0x61, 0x2e, 0x3b, 0x6b, 0x61, 0x6e, 0x2e, 0x3b, 0x6e,
+0x7a, 0x65, 0x2e, 0x3b, 0x75, 0x6b, 0x77, 0x2e, 0x3b, 0x75, 0x67, 0x75,
+0x2e, 0x3b, 0x75, 0x6b, 0x75, 0x2e, 0x91c, 0x93e, 0x928, 0x947, 0x935, 0x93e,
+0x930, 0x940, 0x3b, 0x92b, 0x947, 0x92c, 0x94d, 0x930, 0x941, 0x935, 0x93e, 0x930,
+0x940, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x90f, 0x92a, 0x94d, 0x930,
+0x940, 0x932, 0x3b, 0x92e, 0x947, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941,
+0x932, 0x92f, 0x3b, 0x911, 0x917, 0x938, 0x94d, 0x91f, 0x3b, 0x938, 0x92a, 0x94d,
+0x91f, 0x947, 0x902, 0x92c, 0x930, 0x3b, 0x911, 0x915, 0x94d, 0x91f, 0x94b, 0x92c,
+0x930, 0x3b, 0x928, 0x94b, 0x935, 0x94d, 0x939, 0x947, 0x902, 0x92c, 0x930, 0x3b,
+0x921, 0x93f, 0x938, 0x947, 0x902, 0x92c, 0x930, 0x91c, 0x93e, 0x928, 0x947, 0x3b,
+0x92b, 0x947, 0x92c, 0x94d, 0x930, 0x941, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a,
+0x3b, 0x90f, 0x92a, 0x94d, 0x930, 0x940, 0x3b, 0x92e, 0x947, 0x3b, 0x91c, 0x942,
+0x928, 0x3b, 0x91c, 0x941, 0x932, 0x3b, 0x911, 0x917, 0x3b, 0x938, 0x92a, 0x94d,
+0x91f, 0x947, 0x902, 0x3b, 0x911, 0x915, 0x94d, 0x91f, 0x94b, 0x3b, 0x928, 0x94b,
+0x3b, 0x921, 0x93f, 0x938, 0x947, 0x31, 0xc6d4, 0x3b, 0x32, 0xc6d4, 0x3b, 0x33,
+0xc6d4, 0x3b, 0x34, 0xc6d4, 0x3b, 0x35, 0xc6d4, 0x3b, 0x36, 0xc6d4, 0x3b, 0x37,
+0xc6d4, 0x3b, 0x38, 0xc6d4, 0x3b, 0x39, 0xc6d4, 0x3b, 0x31, 0x30, 0xc6d4, 0x3b,
+0x31, 0x31, 0xc6d4, 0x3b, 0x31, 0x32, 0xc6d4, 0x17d, 0x61, 0x6e, 0x77, 0x69,
+0x79, 0x65, 0x3b, 0x46, 0x65, 0x65, 0x77, 0x69, 0x72, 0x69, 0x79, 0x65,
+0x3b, 0x4d, 0x61, 0x72, 0x73, 0x69, 0x3b, 0x41, 0x77, 0x69, 0x72, 0x69,
+0x6c, 0x3b, 0x4d, 0x65, 0x3b, 0x17d, 0x75, 0x77, 0x65, 0x14b, 0x3b, 0x17d,
+0x75, 0x79, 0x79, 0x65, 0x3b, 0x55, 0x74, 0x3b, 0x53, 0x65, 0x6b, 0x74,
+0x61, 0x6e, 0x62, 0x75, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x6f, 0x62,
+0x75, 0x72, 0x3b, 0x4e, 0x6f, 0x6f, 0x77, 0x61, 0x6e, 0x62, 0x75, 0x72,
+0x3b, 0x44, 0x65, 0x65, 0x73, 0x61, 0x6e, 0x62, 0x75, 0x72, 0x17d, 0x61,
+0x6e, 0x3b, 0x46, 0x65, 0x65, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x77,
+0x69, 0x3b, 0x4d, 0x65, 0x3b, 0x17d, 0x75, 0x77, 0x3b, 0x17d, 0x75, 0x79,
+0x3b, 0x55, 0x74, 0x3b, 0x53, 0x65, 0x6b, 0x3b, 0x4f, 0x6b, 0x74, 0x3b,
+0x4e, 0x6f, 0x6f, 0x3b, 0x44, 0x65, 0x65, 0x17d, 0x3b, 0x46, 0x3b, 0x4d,
+0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x17d, 0x3b, 0x17d, 0x3b, 0x55, 0x3b, 0x53,
+0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x72, 0xea, 0x62, 0x65, 0x6e, 0x64,
+0x61, 0x6e, 0x3b, 0x73, 0x69, 0x62, 0x61, 0x74, 0x3b, 0x61, 0x64, 0x61,
+0x72, 0x3b, 0x6e, 0xee, 0x73, 0x61, 0x6e, 0x3b, 0x67, 0x75, 0x6c, 0x61,
+0x6e, 0x3b, 0x68, 0x65, 0x7a, 0xee, 0x72, 0x61, 0x6e, 0x3b, 0x74, 0xee,
+0x72, 0x6d, 0x65, 0x68, 0x3b, 0x74, 0x65, 0x62, 0x61, 0x78, 0x3b, 0xee,
+0x6c, 0x6f, 0x6e, 0x3b, 0x63, 0x6f, 0x74, 0x6d, 0x65, 0x68, 0x3b, 0x6d,
+0x69, 0x6a, 0x64, 0x61, 0x72, 0x3b, 0x62, 0x65, 0x72, 0x66, 0x61, 0x6e,
+0x62, 0x61, 0x72, 0x72, 0x62, 0x6e, 0x3b, 0x73, 0x62, 0x74, 0x3b, 0x61,
+0x64, 0x72, 0x3b, 0x6e, 0x73, 0x6e, 0x3b, 0x67, 0x6c, 0x6e, 0x3b, 0x68,
+0x7a, 0x72, 0x3b, 0x74, 0x72, 0x6d, 0x3b, 0x74, 0x62, 0x78, 0x3b, 0xee,
+0x6c, 0x6e, 0x3b, 0x63, 0x6f, 0x74, 0x3b, 0x6d, 0x6a, 0x64, 0x3b, 0x62,
+0x72, 0x66, 0x52, 0x3b, 0x53, 0x3b, 0x41, 0x3b, 0x4e, 0x3b, 0x47, 0x3b,
+0x48, 0x3b, 0x54, 0x3b, 0x54, 0x3b, 0xce, 0x3b, 0x43, 0x3b, 0x4d, 0x3b,
+0x42, 0x6e, 0x67, 0x77, 0x25b, 0x6e, 0x20, 0x6d, 0x61, 0x74, 0xe1, 0x68,
+0x72, 0x61, 0x3b, 0x6e, 0x67, 0x77, 0x25b, 0x6e, 0x20, 0x144, 0x6d, 0x62,
+0x61, 0x3b, 0x6e, 0x67, 0x77, 0x25b, 0x6e, 0x20, 0x144, 0x6c, 0x61, 0x6c,
+0x3b, 0x6e, 0x67, 0x77, 0x25b, 0x6e, 0x20, 0x144, 0x6e, 0x61, 0x3b, 0x6e,
+0x67, 0x77, 0x25b, 0x6e, 0x20, 0x144, 0x74, 0x61, 0x6e, 0x3b, 0x6e, 0x67,
+0x77, 0x25b, 0x6e, 0x20, 0x144, 0x74, 0x75, 0xf3, 0x3b, 0x6e, 0x67, 0x77,
+0x25b, 0x6e, 0x20, 0x68, 0x25b, 0x6d, 0x62, 0x75, 0x25b, 0x72, 0xed, 0x3b,
+0x6e, 0x67, 0x77, 0x25b, 0x6e, 0x20, 0x6c, 0x254, 0x6d, 0x62, 0x69, 0x3b,
+0x6e, 0x67, 0x77, 0x25b, 0x6e, 0x20, 0x72, 0x25b, 0x62, 0x76, 0x75, 0xe2,
+0x3b, 0x6e, 0x67, 0x77, 0x25b, 0x6e, 0x20, 0x77, 0x75, 0x6d, 0x3b, 0x6e,
+0x67, 0x77, 0x25b, 0x6e, 0x20, 0x77, 0x75, 0x6d, 0x20, 0x6e, 0x61, 0x76,
+0x1d4, 0x72, 0x3b, 0x6b, 0x72, 0xed, 0x73, 0x69, 0x6d, 0x69, 0x6e, 0x6e,
+0x67, 0x31, 0x3b, 0x6e, 0x67, 0x32, 0x3b, 0x6e, 0x67, 0x33, 0x3b, 0x6e,
+0x67, 0x34, 0x3b, 0x6e, 0x67, 0x35, 0x3b, 0x6e, 0x67, 0x36, 0x3b, 0x6e,
+0x67, 0x37, 0x3b, 0x6e, 0x67, 0x38, 0x3b, 0x6e, 0x67, 0x39, 0x3b, 0x6e,
+0x67, 0x31, 0x30, 0x3b, 0x6e, 0x67, 0x31, 0x31, 0x3b, 0x6b, 0x72, 0x69,
+0x73, 0x42f, 0x43d, 0x432, 0x430, 0x440, 0x44c, 0x3b, 0x424, 0x435, 0x432, 0x440,
+0x430, 0x43b, 0x44c, 0x3b, 0x41c, 0x430, 0x440, 0x442, 0x3b, 0x410, 0x43f, 0x440,
+0x435, 0x43b, 0x44c, 0x3b, 0x41c, 0x430, 0x439, 0x3b, 0x418, 0x44e, 0x43d, 0x44c,
+0x3b, 0x418, 0x44e, 0x43b, 0x44c, 0x3b, 0x410, 0x432, 0x433, 0x443, 0x441, 0x442,
+0x3b, 0x421, 0x435, 0x43d, 0x442, 0x44f, 0x431, 0x440, 0x44c, 0x3b, 0x41e, 0x43a,
+0x442, 0x44f, 0x431, 0x440, 0x44c, 0x3b, 0x41d, 0x43e, 0x44f, 0x431, 0x440, 0x44c,
+0x3b, 0x414, 0x435, 0x43a, 0x430, 0x431, 0x440, 0x44c, 0x42f, 0x43d, 0x432, 0x3b,
+0x424, 0x435, 0x432, 0x3b, 0x41c, 0x430, 0x440, 0x3b, 0x410, 0x43f, 0x440, 0x3b,
+0x41c, 0x430, 0x439, 0x3b, 0x418, 0x44e, 0x43d, 0x3b, 0x418, 0x44e, 0x43b, 0x3b,
+0x410, 0x432, 0x433, 0x3b, 0x421, 0x435, 0x43d, 0x3b, 0x41e, 0x43a, 0x442, 0x3b,
+0x41d, 0x43e, 0x44f, 0x3b, 0x414, 0x435, 0x43a, 0x44f, 0x43d, 0x432, 0x2e, 0x3b,
+0x444, 0x435, 0x432, 0x2e, 0x3b, 0x43c, 0x430, 0x440, 0x2e, 0x3b, 0x430, 0x43f,
+0x440, 0x2e, 0x3b, 0x43c, 0x430, 0x439, 0x3b, 0x438, 0x44e, 0x43d, 0x2e, 0x3b,
+0x438, 0x44e, 0x43b, 0x2e, 0x3b, 0x430, 0x432, 0x433, 0x2e, 0x3b, 0x441, 0x435,
+0x43d, 0x2e, 0x3b, 0x43e, 0x43a, 0x442, 0x2e, 0x3b, 0x43d, 0x43e, 0x44f, 0x2e,
+0x3b, 0x434, 0x435, 0x43a, 0x2e, 0x57, 0x69, 0xf3, 0x74, 0x68, 0x65, 0x21f,
+0x69, 0x6b, 0x61, 0x20, 0x57, 0xed, 0x3b, 0x54, 0x68, 0x69, 0x79, 0xf3,
+0x21f, 0x65, 0x79, 0x75, 0x14b, 0x6b, 0x61, 0x20, 0x57, 0xed, 0x3b, 0x49,
+0x161, 0x74, 0xe1, 0x77, 0x69, 0x10d, 0x68, 0x61, 0x79, 0x61, 0x7a, 0x61,
+0x14b, 0x20, 0x57, 0xed, 0x3b, 0x50, 0x21f, 0x65, 0x17e, 0xed, 0x74, 0x21f,
+0x6f, 0x20, 0x57, 0xed, 0x3b, 0x10c, 0x68, 0x61, 0x14b, 0x77, 0xe1, 0x70,
+0x65, 0x74, 0x21f, 0x6f, 0x20, 0x57, 0xed, 0x3b, 0x57, 0xed, 0x70, 0x61,
+0x7a, 0x75, 0x6b, 0x21f, 0x61, 0x2d, 0x77, 0x61, 0x161, 0x74, 0xe9, 0x20,
+0x57, 0xed, 0x3b, 0x10c, 0x68, 0x61, 0x14b, 0x70, 0x21f, 0xe1, 0x73, 0x61,
+0x70, 0x61, 0x20, 0x57, 0xed, 0x3b, 0x57, 0x61, 0x73, 0xfa, 0x74, 0x21f,
+0x75, 0x14b, 0x20, 0x57, 0xed, 0x3b, 0x10c, 0x68, 0x61, 0x14b, 0x77, 0xe1,
+0x70, 0x65, 0x1e7, 0x69, 0x20, 0x57, 0xed, 0x3b, 0x10c, 0x68, 0x61, 0x14b,
+0x77, 0xe1, 0x70, 0x65, 0x2d, 0x6b, 0x61, 0x73, 0x6e, 0xe1, 0x20, 0x57,
+0xed, 0x3b, 0x57, 0x61, 0x6e, 0xed, 0x79, 0x65, 0x74, 0x75, 0x20, 0x57,
+0xed, 0x3b, 0x54, 0x21f, 0x61, 0x68, 0xe9, 0x6b, 0x61, 0x70, 0x161, 0x75,
+0x14b, 0x20, 0x57, 0xed, 0x4b, 0x289, 0x66, 0xfa, 0x6e, 0x67, 0x61, 0x74,
+0x268, 0x3b, 0x4b, 0x289, 0x6e, 0x61, 0x61, 0x6e, 0x268, 0x3b, 0x4b, 0x289,
+0x6b, 0x65, 0x65, 0x6e, 0x64, 0x61, 0x3b, 0x4b, 0x77, 0x69, 0x69, 0x6b,
+0x75, 0x6d, 0x69, 0x3b, 0x4b, 0x77, 0x69, 0x69, 0x6e, 0x79, 0x61, 0x6d,
+0x62, 0xe1, 0x6c, 0x61, 0x3b, 0x4b, 0x77, 0x69, 0x69, 0x64, 0x77, 0x61,
+0x61, 0x74, 0x61, 0x3b, 0x4b, 0x289, 0x6d, 0x289, 0x289, 0x6e, 0x63, 0x68,
+0x268, 0x3b, 0x4b, 0x289, 0x76, 0x268, 0x268, 0x72, 0x268, 0x3b, 0x4b, 0x289,
+0x73, 0x61, 0x61, 0x74, 0x289, 0x3b, 0x4b, 0x77, 0x69, 0x69, 0x6e, 0x79,
+0x69, 0x3b, 0x4b, 0x289, 0x73, 0x61, 0x61, 0x6e, 0x6f, 0x3b, 0x4b, 0x289,
+0x73, 0x61, 0x73, 0x61, 0x74, 0x289, 0x46, 0xfa, 0x6e, 0x67, 0x61, 0x74,
+0x268, 0x3b, 0x4e, 0x61, 0x61, 0x6e, 0x268, 0x3b, 0x4b, 0x65, 0x65, 0x6e,
+0x64, 0x61, 0x3b, 0x49, 0x6b, 0xfa, 0x6d, 0x69, 0x3b, 0x49, 0x6e, 0x79,
+0x61, 0x6d, 0x62, 0x61, 0x6c, 0x61, 0x3b, 0x49, 0x64, 0x77, 0x61, 0x61,
+0x74, 0x61, 0x3b, 0x4d, 0x289, 0x289, 0x6e, 0x63, 0x68, 0x268, 0x3b, 0x56,
+0x268, 0x268, 0x72, 0x268, 0x3b, 0x53, 0x61, 0x61, 0x74, 0x289, 0x3b, 0x49,
+0x6e, 0x79, 0x69, 0x3b, 0x53, 0x61, 0x61, 0x6e, 0x6f, 0x3b, 0x53, 0x61,
+0x73, 0x61, 0x74, 0x289, 0x46, 0x3b, 0x4e, 0x3b, 0x4b, 0x3b, 0x49, 0x3b,
+0x49, 0x3b, 0x49, 0x3b, 0x4d, 0x3b, 0x56, 0x3b, 0x53, 0x3b, 0x49, 0x3b,
+0x53, 0x3b, 0x53, 0xea1, 0xeb1, 0xe87, 0xe81, 0xead, 0xe99, 0x3b, 0xe81, 0xeb8,
+0xea1, 0xe9e, 0xeb2, 0x3b, 0xea1, 0xeb5, 0xe99, 0xeb2, 0x3b, 0xec0, 0xea1, 0xeaa,
+0xeb2, 0x3b, 0xe9e, 0xeb6, 0xe94, 0xeaa, 0xeb0, 0xe9e, 0xeb2, 0x3b, 0xea1, 0xeb4,
+0xe96, 0xeb8, 0xe99, 0xeb2, 0x3b, 0xe81, 0xecd, 0xea5, 0xeb0, 0xe81, 0xebb, 0xe94,
+0x3b, 0xeaa, 0xeb4, 0xe87, 0xeab, 0xeb2, 0x3b, 0xe81, 0xeb1, 0xe99, 0xe8d, 0xeb2,
+0x3b, 0xe95, 0xeb8, 0xea5, 0xeb2, 0x3b, 0xe9e, 0xeb0, 0xe88, 0xeb4, 0xe81, 0x3b,
+0xe97, 0xeb1, 0xe99, 0xea7, 0xeb2, 0xea1, 0x2e, 0xe81, 0x2e, 0x3b, 0xe81, 0x2e,
+0xe9e, 0x2e, 0x3b, 0xea1, 0x2e, 0xe99, 0x2e, 0x3b, 0xea1, 0x2e, 0xeaa, 0x2e,
+0x3b, 0xe9e, 0x2e, 0xe9e, 0x2e, 0x3b, 0xea1, 0xeb4, 0x2e, 0xe96, 0x2e, 0x3b,
+0xe81, 0x2e, 0xea5, 0x2e, 0x3b, 0xeaa, 0x2e, 0xeab, 0x2e, 0x3b, 0xe81, 0x2e,
+0xe8d, 0x2e, 0x3b, 0xe95, 0x2e, 0xea5, 0x2e, 0x3b, 0xe9e, 0x2e, 0xe88, 0x2e,
+0x3b, 0xe97, 0x2e, 0xea7, 0x2e, 0x49, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x69,
+0x75, 0x73, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x69, 0x75,
+0x73, 0x3b, 0x4d, 0x61, 0x72, 0x74, 0x69, 0x75, 0x73, 0x3b, 0x41, 0x70,
+0x72, 0x69, 0x6c, 0x69, 0x73, 0x3b, 0x4d, 0x61, 0x69, 0x75, 0x73, 0x3b,
+0x49, 0x75, 0x6e, 0x69, 0x75, 0x73, 0x3b, 0x49, 0x75, 0x6c, 0x69, 0x75,
+0x73, 0x3b, 0x41, 0x75, 0x67, 0x75, 0x73, 0x74, 0x75, 0x73, 0x3b, 0x53,
+0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x63, 0x74,
+0x6f, 0x62, 0x65, 0x72, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65,
+0x72, 0x3b, 0x44, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x49, 0x61,
+0x6e, 0x75, 0x61, 0x72, 0x69, 0x69, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75,
+0x61, 0x72, 0x69, 0x69, 0x3b, 0x4d, 0x61, 0x72, 0x74, 0x69, 0x69, 0x3b,
+0x41, 0x70, 0x72, 0x69, 0x6c, 0x69, 0x73, 0x3b, 0x4d, 0x61, 0x69, 0x69,
+0x3b, 0x49, 0x75, 0x6e, 0x69, 0x69, 0x3b, 0x49, 0x75, 0x6c, 0x69, 0x69,
+0x3b, 0x41, 0x75, 0x67, 0x75, 0x73, 0x74, 0x69, 0x3b, 0x53, 0x65, 0x70,
+0x74, 0x65, 0x6d, 0x62, 0x72, 0x69, 0x73, 0x3b, 0x4f, 0x63, 0x74, 0x6f,
+0x62, 0x72, 0x69, 0x73, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72,
+0x69, 0x73, 0x3b, 0x44, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x72, 0x69, 0x73,
+0x49, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b,
+0x41, 0x70, 0x72, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x49, 0x75, 0x6e, 0x3b,
+0x49, 0x75, 0x6c, 0x3b, 0x41, 0x75, 0x67, 0x3b, 0x53, 0x65, 0x70, 0x3b,
+0x4f, 0x63, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x63, 0x6a,
+0x61, 0x6e, 0x76, 0x101, 0x72, 0x69, 0x73, 0x3b, 0x66, 0x65, 0x62, 0x72,
+0x75, 0x101, 0x72, 0x69, 0x73, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x73, 0x3b,
+0x61, 0x70, 0x72, 0x12b, 0x6c, 0x69, 0x73, 0x3b, 0x6d, 0x61, 0x69, 0x6a,
+0x73, 0x3b, 0x6a, 0x16b, 0x6e, 0x69, 0x6a, 0x73, 0x3b, 0x6a, 0x16b, 0x6c,
+0x69, 0x6a, 0x73, 0x3b, 0x61, 0x75, 0x67, 0x75, 0x73, 0x74, 0x73, 0x3b,
+0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x69, 0x73, 0x3b, 0x6f,
+0x6b, 0x74, 0x6f, 0x62, 0x72, 0x69, 0x73, 0x3b, 0x6e, 0x6f, 0x76, 0x65,
+0x6d, 0x62, 0x72, 0x69, 0x73, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62,
+0x72, 0x69, 0x73, 0x6a, 0x61, 0x6e, 0x76, 0x2e, 0x3b, 0x66, 0x65, 0x62,
+0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x73, 0x3b, 0x61, 0x70, 0x72,
+0x2e, 0x3b, 0x6d, 0x61, 0x69, 0x6a, 0x73, 0x3b, 0x6a, 0x16b, 0x6e, 0x2e,
+0x3b, 0x6a, 0x16b, 0x6c, 0x2e, 0x3b, 0x61, 0x75, 0x67, 0x2e, 0x3b, 0x73,
+0x65, 0x70, 0x74, 0x2e, 0x3b, 0x6f, 0x6b, 0x74, 0x2e, 0x3b, 0x6e, 0x6f,
+0x76, 0x2e, 0x3b, 0x64, 0x65, 0x63, 0x2e, 0x73, 0xe1, 0x6e, 0x7a, 0xe1,
+0x20, 0x79, 0x61, 0x20, 0x79, 0x61, 0x6d, 0x62, 0x6f, 0x3b, 0x73, 0xe1,
+0x6e, 0x7a, 0xe1, 0x20, 0x79, 0x61, 0x20, 0x6d, 0xed, 0x62, 0x61, 0x6c,
+0xe9, 0x3b, 0x73, 0xe1, 0x6e, 0x7a, 0xe1, 0x20, 0x79, 0x61, 0x20, 0x6d,
+0xed, 0x73, 0xe1, 0x74, 0x6f, 0x3b, 0x73, 0xe1, 0x6e, 0x7a, 0xe1, 0x20,
+0x79, 0x61, 0x20, 0x6d, 0xed, 0x6e, 0x65, 0x69, 0x3b, 0x73, 0xe1, 0x6e,
+0x7a, 0xe1, 0x20, 0x79, 0x61, 0x20, 0x6d, 0xed, 0x74, 0xe1, 0x6e, 0x6f,
+0x3b, 0x73, 0xe1, 0x6e, 0x7a, 0xe1, 0x20, 0x79, 0x61, 0x20, 0x6d, 0x6f,
+0x74, 0xf3, 0x62, 0xe1, 0x3b, 0x73, 0xe1, 0x6e, 0x7a, 0xe1, 0x20, 0x79,
+0x61, 0x20, 0x6e, 0x73, 0x61, 0x6d, 0x62, 0x6f, 0x3b, 0x73, 0xe1, 0x6e,
+0x7a, 0xe1, 0x20, 0x79, 0x61, 0x20, 0x6d, 0x77, 0x61, 0x6d, 0x62, 0x65,
+0x3b, 0x73, 0xe1, 0x6e, 0x7a, 0xe1, 0x20, 0x79, 0x61, 0x20, 0x6c, 0x69,
+0x62, 0x77, 0x61, 0x3b, 0x73, 0xe1, 0x6e, 0x7a, 0xe1, 0x20, 0x79, 0x61,
+0x20, 0x7a, 0xf3, 0x6d, 0x69, 0x3b, 0x73, 0xe1, 0x6e, 0x7a, 0xe1, 0x20,
+0x79, 0x61, 0x20, 0x7a, 0xf3, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x6d,
+0x254, 0x30c, 0x6b, 0x254, 0x301, 0x3b, 0x73, 0xe1, 0x6e, 0x7a, 0xe1, 0x20,
+0x79, 0x61, 0x20, 0x7a, 0xf3, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x6d,
+0xed, 0x62, 0x61, 0x6c, 0xe9, 0x79, 0x61, 0x6e, 0x3b, 0x66, 0x62, 0x6c,
+0x3b, 0x6d, 0x73, 0x69, 0x3b, 0x61, 0x70, 0x6c, 0x3b, 0x6d, 0x61, 0x69,
+0x3b, 0x79, 0x75, 0x6e, 0x3b, 0x79, 0x75, 0x6c, 0x3b, 0x61, 0x67, 0x74,
+0x3b, 0x73, 0x74, 0x62, 0x3b, 0x254, 0x74, 0x62, 0x3b, 0x6e, 0x76, 0x62,
+0x3b, 0x64, 0x73, 0x62, 0x79, 0x3b, 0x66, 0x3b, 0x6d, 0x3b, 0x61, 0x3b,
+0x6d, 0x3b, 0x79, 0x3b, 0x79, 0x3b, 0x61, 0x3b, 0x73, 0x3b, 0x254, 0x3b,
+0x6e, 0x3b, 0x64, 0x73, 0x61, 0x75, 0x73, 0x69, 0x73, 0x3b, 0x76, 0x61,
+0x73, 0x61, 0x72, 0x69, 0x73, 0x3b, 0x6b, 0x6f, 0x76, 0x61, 0x73, 0x3b,
+0x62, 0x61, 0x6c, 0x61, 0x6e, 0x64, 0x69, 0x73, 0x3b, 0x67, 0x65, 0x67,
+0x75, 0x17e, 0x117, 0x3b, 0x62, 0x69, 0x72, 0x17e, 0x65, 0x6c, 0x69, 0x73,
+0x3b, 0x6c, 0x69, 0x65, 0x70, 0x61, 0x3b, 0x72, 0x75, 0x67, 0x70, 0x6a,
+0x16b, 0x74, 0x69, 0x73, 0x3b, 0x72, 0x75, 0x67, 0x73, 0x117, 0x6a, 0x69,
+0x73, 0x3b, 0x73, 0x70, 0x61, 0x6c, 0x69, 0x73, 0x3b, 0x6c, 0x61, 0x70,
+0x6b, 0x72, 0x69, 0x74, 0x69, 0x73, 0x3b, 0x67, 0x72, 0x75, 0x6f, 0x64,
+0x69, 0x73, 0x73, 0x61, 0x75, 0x73, 0x69, 0x6f, 0x3b, 0x76, 0x61, 0x73,
+0x61, 0x72, 0x69, 0x6f, 0x3b, 0x6b, 0x6f, 0x76, 0x6f, 0x3b, 0x62, 0x61,
+0x6c, 0x61, 0x6e, 0x64, 0x17e, 0x69, 0x6f, 0x3b, 0x67, 0x65, 0x67, 0x75,
+0x17e, 0x117, 0x73, 0x3b, 0x62, 0x69, 0x72, 0x17e, 0x65, 0x6c, 0x69, 0x6f,
+0x3b, 0x6c, 0x69, 0x65, 0x70, 0x6f, 0x73, 0x3b, 0x72, 0x75, 0x67, 0x70,
+0x6a, 0x16b, 0x10d, 0x69, 0x6f, 0x3b, 0x72, 0x75, 0x67, 0x73, 0x117, 0x6a,
+0x6f, 0x3b, 0x73, 0x70, 0x61, 0x6c, 0x69, 0x6f, 0x3b, 0x6c, 0x61, 0x70,
+0x6b, 0x72, 0x69, 0x10d, 0x69, 0x6f, 0x3b, 0x67, 0x72, 0x75, 0x6f, 0x64,
+0x17e, 0x69, 0x6f, 0x73, 0x61, 0x75, 0x73, 0x2e, 0x3b, 0x76, 0x61, 0x73,
+0x2e, 0x3b, 0x6b, 0x6f, 0x76, 0x2e, 0x3b, 0x62, 0x61, 0x6c, 0x2e, 0x3b,
+0x67, 0x65, 0x67, 0x2e, 0x3b, 0x62, 0x69, 0x72, 0x17e, 0x2e, 0x3b, 0x6c,
+0x69, 0x65, 0x70, 0x2e, 0x3b, 0x72, 0x75, 0x67, 0x70, 0x2e, 0x3b, 0x72,
+0x75, 0x67, 0x73, 0x2e, 0x3b, 0x73, 0x70, 0x61, 0x6c, 0x2e, 0x3b, 0x6c,
+0x61, 0x70, 0x6b, 0x72, 0x2e, 0x3b, 0x67, 0x72, 0x75, 0x6f, 0x64, 0x2e,
+0x53, 0x3b, 0x56, 0x3b, 0x4b, 0x3b, 0x42, 0x3b, 0x47, 0x3b, 0x42, 0x3b,
+0x4c, 0x3b, 0x52, 0x3b, 0x52, 0x3b, 0x53, 0x3b, 0x4c, 0x3b, 0x47, 0x6a,
+0x61, 0x6e, 0x75, 0x61, 0x72, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0x61,
+0x72, 0x3b, 0x6d, 0x11b, 0x72, 0x63, 0x3b, 0x61, 0x70, 0x72, 0x79, 0x6c,
+0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x6a, 0x3b, 0x6a,
+0x75, 0x6c, 0x69, 0x6a, 0x3b, 0x61, 0x77, 0x67, 0x75, 0x73, 0x74, 0x3b,
+0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x6f, 0x6b,
+0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x6e, 0x6f, 0x77, 0x65, 0x6d, 0x62,
+0x65, 0x72, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x6a,
+0x61, 0x6e, 0x75, 0x61, 0x72, 0x61, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75,
+0x61, 0x72, 0x61, 0x3b, 0x6d, 0x11b, 0x72, 0x63, 0x61, 0x3b, 0x61, 0x70,
+0x72, 0x79, 0x6c, 0x61, 0x3b, 0x6d, 0x61, 0x6a, 0x61, 0x3b, 0x6a, 0x75,
+0x6e, 0x69, 0x6a, 0x61, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x6a, 0x61, 0x3b,
+0x61, 0x77, 0x67, 0x75, 0x73, 0x74, 0x61, 0x3b, 0x73, 0x65, 0x70, 0x74,
+0x65, 0x6d, 0x62, 0x72, 0x61, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x72,
+0x61, 0x3b, 0x6e, 0x6f, 0x77, 0x65, 0x6d, 0x62, 0x72, 0x61, 0x3b, 0x64,
+0x65, 0x63, 0x65, 0x6d, 0x62, 0x72, 0x61, 0x6a, 0x61, 0x6e, 0x3b, 0x66,
+0x65, 0x62, 0x3b, 0x6d, 0x11b, 0x72, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d,
+0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61,
+0x77, 0x67, 0x3b, 0x73, 0x65, 0x70, 0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e,
+0x6f, 0x77, 0x3b, 0x64, 0x65, 0x63, 0x6a, 0x61, 0x6e, 0x2e, 0x3b, 0x66,
+0x65, 0x62, 0x2e, 0x3b, 0x6d, 0x11b, 0x72, 0x2e, 0x3b, 0x61, 0x70, 0x72,
+0x2e, 0x3b, 0x6d, 0x61, 0x6a, 0x2e, 0x3b, 0x6a, 0x75, 0x6e, 0x2e, 0x3b,
+0x6a, 0x75, 0x6c, 0x2e, 0x3b, 0x61, 0x77, 0x67, 0x2e, 0x3b, 0x73, 0x65,
+0x70, 0x2e, 0x3b, 0x6f, 0x6b, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x77, 0x2e,
+0x3b, 0x64, 0x65, 0x63, 0x2e, 0x4a, 0x61, 0x6e, 0x75, 0x61, 0x61, 0x72,
+0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x61, 0x61, 0x72, 0x3b, 0x4d, 0xe4,
+0x72, 0x7a, 0x3b, 0x41, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x61, 0x69,
+0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x69, 0x3b, 0x41,
+0x75, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d,
+0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x76, 0x65, 0x72, 0x3b,
+0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x44, 0x65, 0x7a,
+0x65, 0x6d, 0x62, 0x65, 0x72, 0x4a, 0x61, 0x6e, 0x2e, 0x3b, 0x46, 0x65,
+0x62, 0x2e, 0x3b, 0x4d, 0xe4, 0x72, 0x7a, 0x3b, 0x41, 0x70, 0x72, 0x2e,
+0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75,
+0x6c, 0x69, 0x3b, 0x41, 0x75, 0x67, 0x2e, 0x3b, 0x53, 0x65, 0x70, 0x2e,
+0x3b, 0x4f, 0x6b, 0x74, 0x2e, 0x3b, 0x4e, 0x6f, 0x76, 0x2e, 0x3b, 0x44,
+0x65, 0x7a, 0x2e, 0x43, 0x69, 0x6f, 0x6e, 0x67, 0x6f, 0x3b, 0x4c, 0xf9,
+0x69, 0x73, 0x68, 0x69, 0x3b, 0x4c, 0x75, 0x73, 0xf2, 0x6c, 0x6f, 0x3b,
+0x4d, 0xf9, 0x75, 0x79, 0xe0, 0x3b, 0x4c, 0x75, 0x6d, 0xf9, 0x6e, 0x67,
+0xf9, 0x6c, 0xf9, 0x3b, 0x4c, 0x75, 0x66, 0x75, 0x69, 0x6d, 0x69, 0x3b,
+0x4b, 0x61, 0x62, 0xe0, 0x6c, 0xe0, 0x73, 0x68, 0xec, 0x70, 0xf9, 0x3b,
+0x4c, 0xf9, 0x73, 0x68, 0xec, 0x6b, 0xe0, 0x3b, 0x4c, 0x75, 0x74, 0x6f,
+0x6e, 0x67, 0x6f, 0x6c, 0x6f, 0x3b, 0x4c, 0x75, 0x6e, 0x67, 0xf9, 0x64,
+0x69, 0x3b, 0x4b, 0x61, 0x73, 0x77, 0xe8, 0x6b, 0xe8, 0x73, 0xe8, 0x3b,
+0x43, 0x69, 0x73, 0x77, 0xe0, 0x43, 0x69, 0x6f, 0x3b, 0x4c, 0x75, 0x69,
+0x3b, 0x4c, 0x75, 0x73, 0x3b, 0x4d, 0x75, 0x75, 0x3b, 0x4c, 0x75, 0x6d,
+0x3b, 0x4c, 0x75, 0x66, 0x3b, 0x4b, 0x61, 0x62, 0x3b, 0x4c, 0x75, 0x73,
+0x68, 0x3b, 0x4c, 0x75, 0x74, 0x3b, 0x4c, 0x75, 0x6e, 0x3b, 0x4b, 0x61,
+0x73, 0x3b, 0x43, 0x69, 0x73, 0x43, 0x3b, 0x4c, 0x3b, 0x4c, 0x3b, 0x4d,
+0x3b, 0x4c, 0x3b, 0x4c, 0x3b, 0x4b, 0x3b, 0x4c, 0x3b, 0x4c, 0x3b, 0x4c,
+0x3b, 0x4b, 0x3b, 0x43, 0x44, 0x77, 0x65, 0x20, 0x6d, 0x61, 0x72, 0x20,
+0x41, 0x63, 0x68, 0x69, 0x65, 0x6c, 0x3b, 0x44, 0x77, 0x65, 0x20, 0x6d,
+0x61, 0x72, 0x20, 0x41, 0x72, 0x69, 0x79, 0x6f, 0x3b, 0x44, 0x77, 0x65,
+0x20, 0x6d, 0x61, 0x72, 0x20, 0x41, 0x64, 0x65, 0x6b, 0x3b, 0x44, 0x77,
+0x65, 0x20, 0x6d, 0x61, 0x72, 0x20, 0x41, 0x6e, 0x67, 0x2019, 0x77, 0x65,
+0x6e, 0x3b, 0x44, 0x77, 0x65, 0x20, 0x6d, 0x61, 0x72, 0x20, 0x41, 0x62,
+0x69, 0x63, 0x68, 0x3b, 0x44, 0x77, 0x65, 0x20, 0x6d, 0x61, 0x72, 0x20,
+0x41, 0x75, 0x63, 0x68, 0x69, 0x65, 0x6c, 0x3b, 0x44, 0x77, 0x65, 0x20,
+0x6d, 0x61, 0x72, 0x20, 0x41, 0x62, 0x69, 0x72, 0x69, 0x79, 0x6f, 0x3b,
+0x44, 0x77, 0x65, 0x20, 0x6d, 0x61, 0x72, 0x20, 0x41, 0x62, 0x6f, 0x72,
+0x6f, 0x3b, 0x44, 0x77, 0x65, 0x20, 0x6d, 0x61, 0x72, 0x20, 0x4f, 0x63,
+0x68, 0x69, 0x6b, 0x6f, 0x3b, 0x44, 0x77, 0x65, 0x20, 0x6d, 0x61, 0x72,
+0x20, 0x41, 0x70, 0x61, 0x72, 0x3b, 0x44, 0x77, 0x65, 0x20, 0x6d, 0x61,
+0x72, 0x20, 0x67, 0x69, 0x20, 0x61, 0x63, 0x68, 0x69, 0x65, 0x6c, 0x3b,
+0x44, 0x77, 0x65, 0x20, 0x6d, 0x61, 0x72, 0x20, 0x41, 0x70, 0x61, 0x72,
+0x20, 0x67, 0x69, 0x20, 0x61, 0x72, 0x69, 0x79, 0x6f, 0x44, 0x41, 0x43,
+0x3b, 0x44, 0x41, 0x52, 0x3b, 0x44, 0x41, 0x44, 0x3b, 0x44, 0x41, 0x4e,
+0x3b, 0x44, 0x41, 0x48, 0x3b, 0x44, 0x41, 0x55, 0x3b, 0x44, 0x41, 0x4f,
+0x3b, 0x44, 0x41, 0x42, 0x3b, 0x44, 0x4f, 0x43, 0x3b, 0x44, 0x41, 0x50,
+0x3b, 0x44, 0x47, 0x49, 0x3b, 0x44, 0x41, 0x47, 0x43, 0x3b, 0x52, 0x3b,
+0x44, 0x3b, 0x4e, 0x3b, 0x42, 0x3b, 0x55, 0x3b, 0x42, 0x3b, 0x42, 0x3b,
+0x43, 0x3b, 0x50, 0x3b, 0x43, 0x3b, 0x50, 0x4a, 0x61, 0x6e, 0x75, 0x61,
+0x72, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x3b, 0x4d, 0xe4,
+0x65, 0x72, 0x7a, 0x3b, 0x41, 0x62, 0x72, 0xeb, 0x6c, 0x6c, 0x3b, 0x4d,
+0x65, 0x65, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x69,
+0x3b, 0x41, 0x75, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x53, 0x65, 0x70, 0x74,
+0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x65,
+0x72, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x44,
+0x65, 0x7a, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4a, 0x61, 0x6e, 0x3b, 0x46,
+0x65, 0x62, 0x3b, 0x4d, 0xe4, 0x65, 0x3b, 0x41, 0x62, 0x72, 0x3b, 0x4d,
+0x65, 0x65, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41,
+0x75, 0x67, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e,
+0x6f, 0x76, 0x3b, 0x44, 0x65, 0x7a, 0x4a, 0x61, 0x6e, 0x2e, 0x3b, 0x46,
+0x65, 0x62, 0x2e, 0x3b, 0x4d, 0xe4, 0x65, 0x2e, 0x3b, 0x41, 0x62, 0x72,
+0x2e, 0x3b, 0x4d, 0x65, 0x65, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a,
+0x75, 0x6c, 0x69, 0x3b, 0x41, 0x75, 0x67, 0x2e, 0x3b, 0x53, 0x65, 0x70,
+0x2e, 0x3b, 0x4f, 0x6b, 0x74, 0x2e, 0x3b, 0x4e, 0x6f, 0x76, 0x2e, 0x3b,
+0x44, 0x65, 0x7a, 0x2e, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b,
+0x4d, 0x61, 0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x69, 0x3b,
+0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x6f, 0x3b,
+0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b,
+0x44, 0x65, 0x73, 0x458, 0x430, 0x43d, 0x443, 0x430, 0x440, 0x438, 0x3b, 0x444,
+0x435, 0x432, 0x440, 0x443, 0x430, 0x440, 0x438, 0x3b, 0x43c, 0x430, 0x440, 0x442,
+0x3b, 0x430, 0x43f, 0x440, 0x438, 0x43b, 0x3b, 0x43c, 0x430, 0x458, 0x3b, 0x458,
+0x443, 0x43d, 0x438, 0x3b, 0x458, 0x443, 0x43b, 0x438, 0x3b, 0x430, 0x432, 0x433,
+0x443, 0x441, 0x442, 0x3b, 0x441, 0x435, 0x43f, 0x442, 0x435, 0x43c, 0x432, 0x440,
+0x438, 0x3b, 0x43e, 0x43a, 0x442, 0x43e, 0x43c, 0x432, 0x440, 0x438, 0x3b, 0x43d,
+0x43e, 0x435, 0x43c, 0x432, 0x440, 0x438, 0x3b, 0x434, 0x435, 0x43a, 0x435, 0x43c,
+0x432, 0x440, 0x438, 0x458, 0x430, 0x43d, 0x2e, 0x3b, 0x444, 0x435, 0x432, 0x2e,
+0x3b, 0x43c, 0x430, 0x440, 0x2e, 0x3b, 0x430, 0x43f, 0x440, 0x2e, 0x3b, 0x43c,
+0x430, 0x458, 0x3b, 0x458, 0x443, 0x43d, 0x2e, 0x3b, 0x458, 0x443, 0x43b, 0x2e,
+0x3b, 0x430, 0x432, 0x433, 0x2e, 0x3b, 0x441, 0x435, 0x43f, 0x2e, 0x3b, 0x43e,
+0x43a, 0x442, 0x2e, 0x3b, 0x43d, 0x43e, 0x435, 0x2e, 0x3b, 0x434, 0x435, 0x43a,
+0x2e, 0x4a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x69, 0x3b, 0x46, 0x65, 0x62,
+0x72, 0x75, 0x61, 0x72, 0x69, 0x3b, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x3b,
+0x41, 0x70, 0x72, 0x69, 0x6c, 0x79, 0x69, 0x3b, 0x4d, 0x65, 0x69, 0x3b,
+0x4a, 0x75, 0x6e, 0x79, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x79, 0x61, 0x69,
+0x3b, 0x41, 0x67, 0x75, 0x73, 0x74, 0x69, 0x3b, 0x53, 0x65, 0x70, 0x74,
+0x65, 0x6d, 0x62, 0x61, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x61, 0x3b,
+0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x44, 0x65, 0x73, 0x65,
+0x6d, 0x62, 0x61, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d,
+0x61, 0x63, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a,
+0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x6f, 0x3b, 0x53,
+0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44,
+0x65, 0x73, 0x91c, 0x928, 0x935, 0x930, 0x940, 0x3b, 0x92b, 0x930, 0x935, 0x930,
+0x940, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930,
+0x948, 0x932, 0x3b, 0x92e, 0x908, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941,
+0x932, 0x93e, 0x908, 0x3b, 0x905, 0x917, 0x938, 0x94d, 0x924, 0x3b, 0x938, 0x93f,
+0x924, 0x902, 0x92c, 0x930, 0x3b, 0x905, 0x915, 0x94d, 0x91f, 0x942, 0x92c, 0x930,
+0x3b, 0x928, 0x935, 0x902, 0x92c, 0x930, 0x3b, 0x926, 0x93f, 0x938, 0x902, 0x92c,
+0x930, 0x91c, 0x928, 0x935, 0x930, 0x940, 0x3b, 0x92b, 0x930, 0x935, 0x930, 0x940,
+0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x948,
+0x932, 0x3b, 0x92e, 0x908, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932,
+0x93e, 0x908, 0x3b, 0x905, 0x917, 0x938, 0x94d, 0x924, 0x3b, 0x938, 0x93f, 0x924,
+0x902, 0x92c, 0x930, 0x3b, 0x905, 0x915, 0x94d, 0x924, 0x942, 0x92c, 0x930, 0x3b,
+0x928, 0x935, 0x902, 0x92c, 0x930, 0x3b, 0x926, 0x93f, 0x938, 0x902, 0x92c, 0x930,
+0x91c, 0x928, 0x970, 0x3b, 0x92b, 0x930, 0x970, 0x3b, 0x92e, 0x93e, 0x930, 0x94d,
+0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x948, 0x932, 0x3b, 0x92e, 0x908, 0x3b,
+0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x970, 0x3b, 0x905, 0x917, 0x970,
+0x3b, 0x938, 0x93f, 0x924, 0x970, 0x3b, 0x905, 0x915, 0x94d, 0x924, 0x942, 0x970,
+0x3b, 0x928, 0x935, 0x970, 0x3b, 0x926, 0x93f, 0x938, 0x970, 0x91c, 0x3b, 0x92b,
+0x3b, 0x92e, 0x93e, 0x3b, 0x905, 0x3b, 0x92e, 0x3b, 0x91c, 0x942, 0x3b, 0x91c,
+0x941, 0x3b, 0x905, 0x3b, 0x938, 0x93f, 0x3b, 0x905, 0x3b, 0x928, 0x3b, 0x926,
+0x93f, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x6f, 0x20, 0x6b, 0x77,
+0x61, 0x6e, 0x7a, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77,
+0x6f, 0x20, 0x75, 0x6e, 0x61, 0x79, 0x65, 0x6c, 0x69, 0x3b, 0x4d, 0x77,
+0x65, 0x72, 0x69, 0x20, 0x77, 0x6f, 0x20, 0x75, 0x6e, 0x65, 0x72, 0x61,
+0x72, 0x75, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x6f, 0x20,
+0x75, 0x6e, 0x65, 0x63, 0x68, 0x65, 0x73, 0x68, 0x65, 0x3b, 0x4d, 0x77,
+0x65, 0x72, 0x69, 0x20, 0x77, 0x6f, 0x20, 0x75, 0x6e, 0x65, 0x74, 0x68,
+0x61, 0x6e, 0x75, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x6f,
+0x20, 0x74, 0x68, 0x61, 0x6e, 0x75, 0x20, 0x6e, 0x61, 0x20, 0x6d, 0x6f,
+0x63, 0x68, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x6f,
+0x20, 0x73, 0x61, 0x62, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20,
+0x77, 0x6f, 0x20, 0x6e, 0x61, 0x6e, 0x65, 0x3b, 0x4d, 0x77, 0x65, 0x72,
+0x69, 0x20, 0x77, 0x6f, 0x20, 0x74, 0x69, 0x73, 0x61, 0x3b, 0x4d, 0x77,
+0x65, 0x72, 0x69, 0x20, 0x77, 0x6f, 0x20, 0x6b, 0x75, 0x6d, 0x69, 0x3b,
+0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x6f, 0x20, 0x6b, 0x75, 0x6d,
+0x69, 0x20, 0x6e, 0x61, 0x20, 0x6d, 0x6f, 0x6a, 0x61, 0x3b, 0x4d, 0x77,
+0x65, 0x72, 0x69, 0x20, 0x77, 0x6f, 0x20, 0x6b, 0x75, 0x6d, 0x69, 0x20,
+0x6e, 0x61, 0x20, 0x79, 0x65, 0x6c, 0x2019, 0x6c, 0x69, 0x4b, 0x77, 0x61,
+0x3b, 0x55, 0x6e, 0x61, 0x3b, 0x52, 0x61, 0x72, 0x3b, 0x43, 0x68, 0x65,
+0x3b, 0x54, 0x68, 0x61, 0x3b, 0x4d, 0x6f, 0x63, 0x3b, 0x53, 0x61, 0x62,
+0x3b, 0x4e, 0x61, 0x6e, 0x3b, 0x54, 0x69, 0x73, 0x3b, 0x4b, 0x75, 0x6d,
+0x3b, 0x4d, 0x6f, 0x6a, 0x3b, 0x59, 0x65, 0x6c, 0x4b, 0x3b, 0x55, 0x3b,
+0x52, 0x3b, 0x43, 0x3b, 0x54, 0x3b, 0x4d, 0x3b, 0x53, 0x3b, 0x4e, 0x3b,
+0x54, 0x3b, 0x4b, 0x3b, 0x4d, 0x3b, 0x59, 0x4d, 0x77, 0x65, 0x64, 0x69,
+0x20, 0x4e, 0x74, 0x61, 0x6e, 0x64, 0x69, 0x3b, 0x4d, 0x77, 0x65, 0x64,
+0x69, 0x20, 0x77, 0x61, 0x20, 0x50, 0x69, 0x6c, 0x69, 0x3b, 0x4d, 0x77,
+0x65, 0x64, 0x69, 0x20, 0x77, 0x61, 0x20, 0x54, 0x61, 0x74, 0x75, 0x3b,
+0x4d, 0x77, 0x65, 0x64, 0x69, 0x20, 0x77, 0x61, 0x20, 0x4e, 0x63, 0x68,
+0x65, 0x63, 0x68, 0x69, 0x3b, 0x4d, 0x77, 0x65, 0x64, 0x69, 0x20, 0x77,
+0x61, 0x20, 0x4e, 0x6e, 0x79, 0x61, 0x6e, 0x6f, 0x3b, 0x4d, 0x77, 0x65,
+0x64, 0x69, 0x20, 0x77, 0x61, 0x20, 0x4e, 0x6e, 0x79, 0x61, 0x6e, 0x6f,
+0x20, 0x6e, 0x61, 0x20, 0x55, 0x6d, 0x6f, 0x3b, 0x4d, 0x77, 0x65, 0x64,
+0x69, 0x20, 0x77, 0x61, 0x20, 0x4e, 0x6e, 0x79, 0x61, 0x6e, 0x6f, 0x20,
+0x6e, 0x61, 0x20, 0x4d, 0x69, 0x76, 0x69, 0x6c, 0x69, 0x3b, 0x4d, 0x77,
+0x65, 0x64, 0x69, 0x20, 0x77, 0x61, 0x20, 0x4e, 0x6e, 0x79, 0x61, 0x6e,
+0x6f, 0x20, 0x6e, 0x61, 0x20, 0x4d, 0x69, 0x74, 0x61, 0x74, 0x75, 0x3b,
+0x4d, 0x77, 0x65, 0x64, 0x69, 0x20, 0x77, 0x61, 0x20, 0x4e, 0x6e, 0x79,
+0x61, 0x6e, 0x6f, 0x20, 0x6e, 0x61, 0x20, 0x4e, 0x63, 0x68, 0x65, 0x63,
+0x68, 0x69, 0x3b, 0x4d, 0x77, 0x65, 0x64, 0x69, 0x20, 0x77, 0x61, 0x20,
+0x4e, 0x6e, 0x79, 0x61, 0x6e, 0x6f, 0x20, 0x6e, 0x61, 0x20, 0x4e, 0x6e,
+0x79, 0x61, 0x6e, 0x6f, 0x3b, 0x4d, 0x77, 0x65, 0x64, 0x69, 0x20, 0x77,
+0x61, 0x20, 0x4e, 0x6e, 0x79, 0x61, 0x6e, 0x6f, 0x20, 0x6e, 0x61, 0x20,
+0x4e, 0x6e, 0x79, 0x61, 0x6e, 0x6f, 0x20, 0x6e, 0x61, 0x20, 0x55, 0x3b,
+0x4d, 0x77, 0x65, 0x64, 0x69, 0x20, 0x77, 0x61, 0x20, 0x4e, 0x6e, 0x79,
+0x61, 0x6e, 0x6f, 0x20, 0x6e, 0x61, 0x20, 0x4e, 0x6e, 0x79, 0x61, 0x6e,
+0x6f, 0x20, 0x6e, 0x61, 0x20, 0x4d, 0x4a, 0x61, 0x6e, 0x6f, 0x61, 0x72,
+0x79, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x6f, 0x61, 0x72, 0x79, 0x3b, 0x4d,
+0x61, 0x72, 0x74, 0x73, 0x61, 0x3b, 0x41, 0x70, 0x72, 0x69, 0x6c, 0x79,
+0x3b, 0x4d, 0x65, 0x79, 0x3b, 0x4a, 0x6f, 0x6e, 0x61, 0x3b, 0x4a, 0x6f,
+0x6c, 0x61, 0x79, 0x3b, 0x41, 0x6f, 0x67, 0x6f, 0x73, 0x69, 0x74, 0x72,
+0x61, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x61, 0x6d, 0x62, 0x72, 0x61, 0x3b,
+0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x72, 0x61, 0x3b, 0x4e, 0x6f, 0x76, 0x61,
+0x6d, 0x62, 0x72, 0x61, 0x3b, 0x44, 0x65, 0x73, 0x61, 0x6d, 0x62, 0x72,
+0x61, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72,
+0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x79, 0x3b, 0x4a, 0x6f, 0x6e,
+0x3b, 0x4a, 0x6f, 0x6c, 0x3b, 0x41, 0x6f, 0x67, 0x3b, 0x53, 0x65, 0x70,
+0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x73,
+0xd1c, 0xd28, 0xd41, 0xd35, 0xd30, 0xd3f, 0x3b, 0xd2b, 0xd46, 0xd2c, 0xd4d, 0xd30,
+0xd41, 0xd35, 0xd30, 0xd3f, 0x3b, 0xd2e, 0xd3e, 0xd7c, 0xd1a, 0xd4d, 0xd1a, 0xd4d,
+0x3b, 0xd0f, 0xd2a, 0xd4d, 0xd30, 0xd3f, 0xd7d, 0x3b, 0xd2e, 0xd47, 0xd2f, 0xd4d,
+0x3b, 0xd1c, 0xd42, 0xd7a, 0x3b, 0xd1c, 0xd42, 0xd32, 0xd48, 0x3b, 0xd13, 0xd17,
+0xd38, 0xd4d, 0xd31, 0xd4d, 0xd31, 0xd4d, 0x3b, 0xd38, 0xd46, 0xd2a, 0xd4d, 0xd31,
+0xd4d, 0xd31, 0xd02, 0xd2c, 0xd7c, 0x3b, 0xd12, 0xd15, 0xd4d, 0x200c, 0xd1f, 0xd4b,
+0xd2c, 0xd7c, 0x3b, 0xd28, 0xd35, 0xd02, 0xd2c, 0xd7c, 0x3b, 0xd21, 0xd3f, 0xd38,
+0xd02, 0xd2c, 0xd7c, 0xd1c, 0xd28, 0xd41, 0x3b, 0xd2b, 0xd46, 0xd2c, 0xd4d, 0xd30,
+0xd41, 0x3b, 0xd2e, 0xd3e, 0xd7c, 0x3b, 0xd0f, 0xd2a, 0xd4d, 0xd30, 0xd3f, 0x3b,
+0xd2e, 0xd47, 0xd2f, 0xd4d, 0x3b, 0xd1c, 0xd42, 0xd7a, 0x3b, 0xd1c, 0xd42, 0xd32,
+0xd48, 0x3b, 0xd13, 0xd17, 0x3b, 0xd38, 0xd46, 0xd2a, 0xd4d, 0xd31, 0xd4d, 0xd31,
+0xd02, 0x3b, 0xd12, 0xd15, 0xd4d, 0xd1f, 0xd4b, 0x3b, 0xd28, 0xd35, 0xd02, 0x3b,
+0xd21, 0xd3f, 0xd38, 0xd02, 0xd1c, 0x3b, 0xd2b, 0xd46, 0x3b, 0xd2e, 0xd3e, 0x3b,
+0xd0f, 0x3b, 0xd2e, 0xd46, 0x3b, 0xd1c, 0xd42, 0xd7a, 0x3b, 0xd1c, 0xd42, 0x3b,
+0xd13, 0x3b, 0xd38, 0xd46, 0x3b, 0xd12, 0x3b, 0xd28, 0x3b, 0xd21, 0xd3f, 0x4a,
+0x61, 0x6e, 0x75, 0x61, 0x72, 0x69, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75,
+0x61, 0x72, 0x69, 0x3b, 0x4d, 0x61, 0x63, 0x3b, 0x41, 0x70, 0x72, 0x69,
+0x6c, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75,
+0x6c, 0x61, 0x69, 0x3b, 0x4f, 0x67, 0x6f, 0x73, 0x3b, 0x53, 0x65, 0x70,
+0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62,
+0x65, 0x72, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b,
+0x44, 0x69, 0x73, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4a, 0x61, 0x6e, 0x3b,
+0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x63, 0x3b, 0x41, 0x70, 0x72, 0x3b,
+0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b,
+0x4f, 0x67, 0x6f, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b,
+0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x69, 0x73, 0x62c, 0x627, 0x646, 0x648, 0x627,
+0x631, 0x64a, 0x3b, 0x641, 0x64a, 0x628, 0x648, 0x627, 0x631, 0x64a, 0x3b, 0x645,
+0x686, 0x3b, 0x627, 0x6a4, 0x631, 0x64a, 0x644, 0x3b, 0x645, 0x64a, 0x3b, 0x62c,
+0x648, 0x646, 0x3b, 0x62c, 0x648, 0x644, 0x627, 0x64a, 0x3b, 0x762, 0x648, 0x633,
+0x3b, 0x633, 0x64a, 0x6a4, 0x62a, 0x64a, 0x645, 0x628, 0x631, 0x3b, 0x627, 0x648,
+0x6a9, 0x62a, 0x648, 0x628, 0x631, 0x3b, 0x646, 0x648, 0x6cf, 0x64a, 0x645, 0x628,
+0x631, 0x3b, 0x62f, 0x64a, 0x633, 0x64a, 0x645, 0x628, 0x631, 0x4a, 0x61, 0x6e,
+0x6e, 0x61, 0x72, 0x3b, 0x46, 0x72, 0x61, 0x72, 0x3b, 0x4d, 0x61, 0x72,
+0x7a, 0x75, 0x3b, 0x41, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x65, 0x6a,
+0x6a, 0x75, 0x3b, 0x120, 0x75, 0x6e, 0x6a, 0x75, 0x3b, 0x4c, 0x75, 0x6c,
+0x6a, 0x75, 0x3b, 0x41, 0x77, 0x77, 0x69, 0x73, 0x73, 0x75, 0x3b, 0x53,
+0x65, 0x74, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x75, 0x3b, 0x4f, 0x74, 0x74,
+0x75, 0x62, 0x72, 0x75, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72,
+0x75, 0x3b, 0x44, 0x69, 0x10b, 0x65, 0x6d, 0x62, 0x72, 0x75, 0x4a, 0x61,
+0x6e, 0x3b, 0x46, 0x72, 0x61, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x70,
+0x72, 0x3b, 0x4d, 0x65, 0x6a, 0x3b, 0x120, 0x75, 0x6e, 0x3b, 0x4c, 0x75,
+0x6c, 0x3b, 0x41, 0x77, 0x77, 0x3b, 0x53, 0x65, 0x74, 0x3b, 0x4f, 0x74,
+0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x69, 0x10b, 0x4a, 0x6e, 0x3b,
+0x46, 0x72, 0x3b, 0x4d, 0x7a, 0x3b, 0x41, 0x70, 0x3b, 0x4d, 0x6a, 0x3b,
+0x120, 0x6e, 0x3b, 0x4c, 0x6a, 0x3b, 0x41, 0x77, 0x3b, 0x53, 0x74, 0x3b,
+0x4f, 0x62, 0x3b, 0x4e, 0x76, 0x3b, 0x44, 0x10b, 0x4a, 0x3b, 0x46, 0x3b,
+0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x120, 0x3b, 0x4c, 0x3b, 0x41, 0x3b,
+0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x99c, 0x9be, 0x9a8, 0x9c1, 0x9f1,
+0x9be, 0x9b0, 0x9bf, 0x3b, 0x9ab, 0x9c7, 0x9ac, 0x9cd, 0x9b0, 0x9c1, 0x9f1, 0x9be,
+0x9b0, 0x9bf, 0x3b, 0x9ae, 0x9be, 0x9b0, 0x9cd, 0x99a, 0x3b, 0x98f, 0x9aa, 0x9cd,
+0x9b0, 0x9bf, 0x9b2, 0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b, 0x99c,
+0x9c1, 0x9b2, 0x9be, 0x987, 0x3b, 0x993, 0x997, 0x9b7, 0x9cd, 0x99f, 0x3b, 0x9b8,
+0x9c7, 0x9aa, 0x9cd, 0x99f, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9b0, 0x3b, 0x993, 0x995,
+0x9cd, 0x99f, 0x9cb, 0x9ac, 0x9b0, 0x3b, 0x9a8, 0x9ac, 0x9c7, 0x9ae, 0x9cd, 0x9ac,
+0x9b0, 0x3b, 0x9a1, 0x9bf, 0x9b8, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9b0, 0x99c, 0x9a8,
+0x9c1, 0x9f1, 0x9be, 0x9b0, 0x9c0, 0x3b, 0x9ab, 0x9c7, 0x9ac, 0x9cd, 0x9b0, 0x9c1,
+0x9f1, 0x9be, 0x9b0, 0x9bf, 0x3b, 0x9ae, 0x9be, 0x9b0, 0x9cd, 0x99a, 0x3b, 0x98f,
+0x9aa, 0x9cd, 0x9b0, 0x9bf, 0x9b2, 0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1, 0x9a8,
+0x3b, 0x99c, 0x9c1, 0x9b2, 0x9be, 0x987, 0x3b, 0x200c, 0x993, 0x997, 0x9b7, 0x9cd,
+0x99f, 0x3b, 0x9b8, 0x9c7, 0x9aa, 0x9cd, 0x99f, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9b0,
+0x3b, 0x993, 0x995, 0x9cd, 0x99f, 0x9cb, 0x9ac, 0x9b0, 0x3b, 0x9a8, 0x9ad, 0x9c7,
+0x9ae, 0x9cd, 0x9ac, 0x9b0, 0x3b, 0x9a1, 0x9bf, 0x9b8, 0x9c7, 0x9ae, 0x9cd, 0x9ac,
+0x9b0, 0x99c, 0x9be, 0x9a8, 0x9c1, 0x3b, 0x9ab, 0x9c7, 0x9ac, 0x9cd, 0x9b0, 0x9c1,
+0x3b, 0x9ae, 0x9be, 0x9b0, 0x3b, 0x98f, 0x9aa, 0x9cd, 0x9b0, 0x9bf, 0x3b, 0x9ae,
+0x9c7, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b, 0x99c, 0x9c1, 0x9b2, 0x9be, 0x3b, 0x986,
+0x997, 0x3b, 0x9b8, 0x9c7, 0x9aa, 0x9cd, 0x99f, 0x3b, 0x993, 0x995, 0x9cd, 0x99f,
+0x9cb, 0x3b, 0x9a8, 0x9ad, 0x9c7, 0x3b, 0x9a1, 0x9bf, 0x9b8, 0x9c7, 0x99c, 0x9a8,
+0x3b, 0x9ab, 0x9c7, 0x9ac, 0x9cd, 0x9b0, 0x9c1, 0x9f1, 0x9be, 0x9b0, 0x9bf, 0x3b,
+0x9ae, 0x9be, 0x9b0, 0x9cd, 0x99a, 0x3b, 0x98f, 0x9aa, 0x9cd, 0x9b0, 0x9bf, 0x9b2,
+0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b, 0x99c, 0x9c1, 0x9b2, 0x9be,
+0x987, 0x3b, 0x993, 0x997, 0x3b, 0x9b8, 0x9c7, 0x9aa, 0x9cd, 0x99f, 0x9c7, 0x9ae,
+0x9cd, 0x9ac, 0x9b0, 0x3b, 0x993, 0x995, 0x9cd, 0x99f, 0x9cb, 0x9ac, 0x9b0, 0x3b,
+0x9a8, 0x9ad, 0x9c7, 0x9ae, 0x9cd, 0x9ac, 0x9b0, 0x3b, 0x9a1, 0x9bf, 0x9b8, 0x9c7,
+0x9ae, 0x9cd, 0x9ac, 0x9b0, 0x99c, 0x9be, 0x3b, 0x9ab, 0x9c7, 0x3b, 0x9ae, 0x9be,
+0x9b0, 0x3b, 0x98f, 0x9aa, 0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b,
+0x99c, 0x9c1, 0x9b2, 0x3b, 0x986, 0x3b, 0x9b8, 0x9c7, 0x3b, 0x993, 0x3b, 0x9a8,
+0x9ac, 0x3b, 0x9a1, 0x9bf, 0x99c, 0x9be, 0x3b, 0x9ab, 0x9c7, 0x3b, 0x9ae, 0x9be,
+0x9b0, 0x3b, 0x98f, 0x9aa, 0x3b, 0x9ae, 0x9c7, 0x3b, 0x99c, 0x9c1, 0x9a8, 0x3b,
+0x99c, 0x9c1, 0x9b2, 0x3b, 0x986, 0x3b, 0x9b8, 0x9c7, 0x3b, 0x993, 0x995, 0x3b,
+0x9a8, 0x9ac, 0x3b, 0x9a1, 0x9bf, 0x4a, 0x65, 0x72, 0x72, 0x65, 0x79, 0x2d,
+0x67, 0x65, 0x75, 0x72, 0x65, 0x65, 0x3b, 0x54, 0x6f, 0x73, 0x68, 0x69,
+0x61, 0x67, 0x68, 0x74, 0x2d, 0x61, 0x72, 0x72, 0x65, 0x65, 0x3b, 0x4d,
+0x61, 0x79, 0x72, 0x6e, 0x74, 0x3b, 0x41, 0x76, 0x65, 0x72, 0x69, 0x6c,
+0x3b, 0x42, 0x6f, 0x61, 0x6c, 0x64, 0x79, 0x6e, 0x3b, 0x4d, 0x65, 0x61,
+0x6e, 0x2d, 0x73, 0x6f, 0x75, 0x72, 0x65, 0x65, 0x3b, 0x4a, 0x65, 0x72,
+0x72, 0x65, 0x79, 0x2d, 0x73, 0x6f, 0x75, 0x72, 0x65, 0x65, 0x3b, 0x4c,
+0x75, 0x61, 0x6e, 0x69, 0x73, 0x74, 0x79, 0x6e, 0x3b, 0x4d, 0x65, 0x61,
+0x6e, 0x2d, 0x66, 0x6f, 0x75, 0x79, 0x69, 0x72, 0x3b, 0x4a, 0x65, 0x72,
+0x72, 0x65, 0x79, 0x2d, 0x66, 0x6f, 0x75, 0x79, 0x69, 0x72, 0x3b, 0x4d,
+0x65, 0x65, 0x20, 0x48, 0x6f, 0x75, 0x6e, 0x65, 0x79, 0x3b, 0x4d, 0x65,
+0x65, 0x20, 0x6e, 0x79, 0x20, 0x4e, 0x6f, 0x6c, 0x6c, 0x69, 0x63, 0x6b,
+0x4a, 0x2d, 0x67, 0x75, 0x65, 0x72, 0x3b, 0x54, 0x2d, 0x61, 0x72, 0x72,
+0x65, 0x65, 0x3b, 0x4d, 0x61, 0x79, 0x72, 0x6e, 0x74, 0x3b, 0x41, 0x76,
+0x72, 0x72, 0x69, 0x6c, 0x3b, 0x42, 0x6f, 0x61, 0x6c, 0x64, 0x79, 0x6e,
+0x3b, 0x4d, 0x2d, 0x73, 0x6f, 0x75, 0x72, 0x65, 0x65, 0x3b, 0x4a, 0x2d,
+0x73, 0x6f, 0x75, 0x72, 0x65, 0x65, 0x3b, 0x4c, 0x75, 0x61, 0x6e, 0x69,
+0x73, 0x74, 0x79, 0x6e, 0x3b, 0x4d, 0x2d, 0x66, 0x6f, 0x75, 0x79, 0x69,
+0x72, 0x3b, 0x4a, 0x2d, 0x66, 0x6f, 0x75, 0x79, 0x69, 0x72, 0x3b, 0x4d,
+0x2d, 0x48, 0x6f, 0x75, 0x6e, 0x65, 0x79, 0x3b, 0x4d, 0x2d, 0x4e, 0x6f,
+0x6c, 0x6c, 0x69, 0x63, 0x6b, 0x48, 0x101, 0x6e, 0x75, 0x65, 0x72, 0x65,
+0x3b, 0x50, 0x113, 0x70, 0x75, 0x65, 0x72, 0x65, 0x3b, 0x4d, 0x101, 0x65,
+0x68, 0x65, 0x3b, 0x100, 0x70, 0x65, 0x72, 0x69, 0x72, 0x61, 0x3b, 0x4d,
+0x65, 0x69, 0x3b, 0x48, 0x75, 0x6e, 0x65, 0x3b, 0x48, 0x16b, 0x72, 0x61,
+0x65, 0x3b, 0x100, 0x6b, 0x75, 0x68, 0x61, 0x74, 0x61, 0x3b, 0x48, 0x65,
+0x70, 0x65, 0x74, 0x65, 0x6d, 0x61, 0x3b, 0x4f, 0x6b, 0x65, 0x74, 0x6f,
+0x70, 0x61, 0x3b, 0x4e, 0x6f, 0x65, 0x6d, 0x61, 0x3b, 0x54, 0x12b, 0x68,
+0x65, 0x6d, 0x61, 0x48, 0x101, 0x6e, 0x75, 0x65, 0x72, 0x65, 0x3b, 0x50,
+0x113, 0x70, 0x75, 0x65, 0x72, 0x65, 0x3b, 0x4d, 0x101, 0x65, 0x68, 0x65,
+0x3b, 0x100, 0x70, 0x65, 0x72, 0x65, 0x69, 0x72, 0x61, 0x3b, 0x4d, 0x65,
+0x69, 0x3b, 0x48, 0x75, 0x6e, 0x65, 0x3b, 0x48, 0x16b, 0x72, 0x61, 0x65,
+0x3b, 0x100, 0x6b, 0x75, 0x68, 0x61, 0x74, 0x61, 0x3b, 0x48, 0x65, 0x70,
+0x65, 0x74, 0x65, 0x6d, 0x61, 0x3b, 0x4f, 0x6b, 0x65, 0x74, 0x6f, 0x70,
+0x61, 0x3b, 0x4e, 0x6f, 0x65, 0x6d, 0x61, 0x3b, 0x54, 0x12b, 0x68, 0x65,
+0x6d, 0x61, 0x48, 0x101, 0x6e, 0x3b, 0x50, 0x113, 0x70, 0x3b, 0x4d, 0x101,
+0x65, 0x3b, 0x100, 0x70, 0x65, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x48, 0x75,
+0x6e, 0x3b, 0x48, 0x16b, 0x72, 0x3b, 0x100, 0x6b, 0x75, 0x3b, 0x48, 0x65,
+0x70, 0x3b, 0x4f, 0x6b, 0x65, 0x3b, 0x4e, 0x6f, 0x65, 0x3b, 0x54, 0x12b,
+0x68, 0x48, 0x3b, 0x50, 0x3b, 0x4d, 0x3b, 0x100, 0x3b, 0x4d, 0x3b, 0x48,
+0x3b, 0x48, 0x3b, 0x100, 0x3b, 0x48, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x54,
+0x91c, 0x93e, 0x928, 0x947, 0x935, 0x93e, 0x930, 0x940, 0x3b, 0x92b, 0x947, 0x92c,
+0x94d, 0x930, 0x941, 0x935, 0x93e, 0x930, 0x940, 0x3b, 0x92e, 0x93e, 0x930, 0x94d,
+0x91a, 0x3b, 0x90f, 0x92a, 0x94d, 0x930, 0x93f, 0x932, 0x3b, 0x92e, 0x947, 0x3b,
+0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x948, 0x3b, 0x911, 0x917, 0x938,
+0x94d, 0x91f, 0x3b, 0x938, 0x92a, 0x94d, 0x91f, 0x947, 0x902, 0x92c, 0x930, 0x3b,
+0x911, 0x915, 0x94d, 0x91f, 0x94b, 0x92c, 0x930, 0x3b, 0x928, 0x94b, 0x935, 0x94d,
+0x939, 0x947, 0x902, 0x92c, 0x930, 0x3b, 0x921, 0x93f, 0x938, 0x947, 0x902, 0x92c,
+0x930, 0x91c, 0x93e, 0x928, 0x947, 0x3b, 0x92b, 0x947, 0x92c, 0x94d, 0x930, 0x941,
+0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x90f, 0x92a, 0x94d, 0x930, 0x93f,
+0x3b, 0x92e, 0x947, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x948,
+0x3b, 0x911, 0x917, 0x3b, 0x938, 0x92a, 0x94d, 0x91f, 0x947, 0x902, 0x3b, 0x911,
+0x915, 0x94d, 0x91f, 0x94b, 0x3b, 0x928, 0x94b, 0x935, 0x94d, 0x939, 0x947, 0x902,
+0x3b, 0x921, 0x93f, 0x938, 0x947, 0x902, 0x91c, 0x93e, 0x3b, 0x92b, 0x947, 0x3b,
+0x92e, 0x93e, 0x3b, 0x90f, 0x3b, 0x92e, 0x947, 0x3b, 0x91c, 0x942, 0x3b, 0x91c,
+0x941, 0x3b, 0x911, 0x3b, 0x938, 0x3b, 0x911, 0x3b, 0x928, 0x94b, 0x3b, 0x921,
+0x93f, 0x4f, 0x6c, 0x61, 0x64, 0x61, 0x6c, 0x289, 0x301, 0x3b, 0x41, 0x72,
+0xe1, 0x74, 0x3b, 0x186, 0x25b, 0x6e, 0x268, 0x301, 0x254, 0x268, 0x14b, 0x254,
+0x6b, 0x3b, 0x4f, 0x6c, 0x6f, 0x64, 0x6f, 0x79, 0xed, 0xf3, 0x72, 0xed,
+0xea, 0x20, 0x69, 0x6e, 0x6b, 0xf3, 0x6b, 0xfa, 0xe2, 0x3b, 0x4f, 0x6c,
+0x6f, 0x69, 0x6c, 0xe9, 0x70, 0x16b, 0x6e, 0x79, 0x12b, 0x113, 0x20, 0x69,
+0x6e, 0x6b, 0xf3, 0x6b, 0xfa, 0xe2, 0x3b, 0x4b, 0xfa, 0x6a, 0xfa, 0x254,
+0x72, 0x254, 0x6b, 0x3b, 0x4d, 0xf3, 0x72, 0x75, 0x73, 0xe1, 0x73, 0x69,
+0x6e, 0x3b, 0x186, 0x6c, 0x254, 0x301, 0x268, 0x301, 0x62, 0x254, 0x301, 0x72,
+0xe1, 0x72, 0x25b, 0x3b, 0x4b, 0xfa, 0x73, 0x68, 0xee, 0x6e, 0x3b, 0x4f,
+0x6c, 0x67, 0xed, 0x73, 0x61, 0x6e, 0x3b, 0x50, 0x289, 0x73, 0x68, 0x289,
+0x301, 0x6b, 0x61, 0x3b, 0x4e, 0x74, 0x289, 0x301, 0x14b, 0x289, 0x301, 0x73,
+0x44, 0x61, 0x6c, 0x3b, 0x41, 0x72, 0xe1, 0x3b, 0x186, 0x25b, 0x6e, 0x3b,
+0x44, 0x6f, 0x79, 0x3b, 0x4c, 0xe9, 0x70, 0x3b, 0x52, 0x6f, 0x6b, 0x3b,
+0x53, 0xe1, 0x73, 0x3b, 0x42, 0x254, 0x301, 0x72, 0x3b, 0x4b, 0xfa, 0x73,
+0x3b, 0x47, 0xed, 0x73, 0x3b, 0x53, 0x68, 0x289, 0x301, 0x3b, 0x4e, 0x74,
+0x289, 0x301, 0x698, 0x627, 0x646, 0x648, 0x6cc, 0x647, 0x3b, 0x641, 0x648, 0x631,
+0x6cc, 0x647, 0x3b, 0x645, 0x627, 0x631, 0x633, 0x3b, 0x622, 0x648, 0x631, 0x6cc,
+0x644, 0x3b, 0x645, 0x647, 0x3b, 0x698, 0x648, 0x626, 0x646, 0x3b, 0x698, 0x648,
+0x626, 0x6cc, 0x647, 0x3b, 0x627, 0x648, 0x62a, 0x3b, 0x633, 0x67e, 0x62a, 0x627,
+0x645, 0x628, 0x631, 0x3b, 0x627, 0x6a9, 0x62a, 0x628, 0x631, 0x3b, 0x646, 0x648,
+0x627, 0x645, 0x628, 0x631, 0x3b, 0x62f, 0x633, 0x627, 0x645, 0x628, 0x631, 0x4a,
+0x61, 0x6e, 0x75, 0x61, 0x72, 0x129, 0x3b, 0x46, 0x65, 0x62, 0x75, 0x72,
+0x75, 0x61, 0x72, 0x129, 0x3b, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x3b, 0x128,
+0x70, 0x75, 0x72, 0x169, 0x3b, 0x4d, 0x129, 0x129, 0x3b, 0x4e, 0x6a, 0x75,
+0x6e, 0x69, 0x3b, 0x4e, 0x6a, 0x75, 0x72, 0x61, 0x129, 0x3b, 0x41, 0x67,
+0x61, 0x73, 0x74, 0x69, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62,
+0x61, 0x3b, 0x4f, 0x6b, 0x74, 0x169, 0x62, 0x61, 0x3b, 0x4e, 0x6f, 0x76,
+0x65, 0x6d, 0x62, 0x61, 0x3b, 0x44, 0x69, 0x63, 0x65, 0x6d, 0x62, 0x61,
+0x4a, 0x41, 0x4e, 0x3b, 0x46, 0x45, 0x42, 0x3b, 0x4d, 0x41, 0x43, 0x3b,
+0x128, 0x50, 0x55, 0x3b, 0x4d, 0x128, 0x128, 0x3b, 0x4e, 0x4a, 0x55, 0x3b,
+0x4e, 0x4a, 0x52, 0x3b, 0x41, 0x47, 0x41, 0x3b, 0x53, 0x50, 0x54, 0x3b,
+0x4f, 0x4b, 0x54, 0x3b, 0x4e, 0x4f, 0x56, 0x3b, 0x44, 0x45, 0x43, 0x4a,
+0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x128, 0x3b, 0x4d, 0x3b, 0x4e, 0x3b, 0x4e,
+0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x69, 0x6d,
+0x259, 0x67, 0x20, 0x6d, 0x62, 0x65, 0x67, 0x74, 0x75, 0x67, 0x3b, 0x69,
+0x6d, 0x65, 0x67, 0x20, 0xe0, 0x62, 0xf9, 0x62, 0xec, 0x3b, 0x69, 0x6d,
+0x65, 0x67, 0x20, 0x6d, 0x62, 0x259, 0x14b, 0x63, 0x68, 0x75, 0x62, 0x69,
+0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x6e, 0x67, 0x77, 0x259, 0x300, 0x74,
+0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x66, 0x6f, 0x67, 0x3b, 0x69, 0x6d,
+0x259, 0x67, 0x20, 0x69, 0x63, 0x68, 0x69, 0x69, 0x62, 0x254, 0x64, 0x3b,
+0x69, 0x6d, 0x259, 0x67, 0x20, 0xe0, 0x64, 0xf9, 0x6d, 0x62, 0x259, 0x300,
+0x14b, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x69, 0x63, 0x68, 0x69, 0x6b,
+0x61, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x6b, 0x75, 0x64, 0x3b, 0x69,
+0x6d, 0x259, 0x67, 0x20, 0x74, 0xe8, 0x73, 0x69, 0x2bc, 0x65, 0x3b, 0x69,
+0x6d, 0x259, 0x67, 0x20, 0x7a, 0xf2, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20,
+0x6b, 0x72, 0x69, 0x7a, 0x6d, 0x65, 0x64, 0x6d, 0x62, 0x65, 0x67, 0x74,
+0x75, 0x67, 0x3b, 0x69, 0x6d, 0x65, 0x67, 0x20, 0xe0, 0x62, 0xf9, 0x62,
+0xec, 0x3b, 0x69, 0x6d, 0x65, 0x67, 0x20, 0x6d, 0x62, 0x259, 0x14b, 0x63,
+0x68, 0x75, 0x62, 0x69, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x6e, 0x67,
+0x77, 0x259, 0x300, 0x74, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x66, 0x6f,
+0x67, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x69, 0x63, 0x68, 0x69, 0x69,
+0x62, 0x254, 0x64, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0xe0, 0x64, 0xf9,
+0x6d, 0x62, 0x259, 0x300, 0x14b, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x69,
+0x63, 0x68, 0x69, 0x6b, 0x61, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x6b,
+0x75, 0x64, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x74, 0xe8, 0x73, 0x69,
+0x2bc, 0x65, 0x3b, 0x69, 0x6d, 0x259, 0x67, 0x20, 0x7a, 0xf2, 0x3b, 0x69,
+0x6d, 0x259, 0x67, 0x20, 0x6b, 0x72, 0x69, 0x7a, 0x6d, 0x65, 0x64, 0x4d,
+0x31, 0x3b, 0x41, 0x32, 0x3b, 0x4d, 0x33, 0x3b, 0x4e, 0x34, 0x3b, 0x46,
+0x35, 0x3b, 0x49, 0x36, 0x3b, 0x41, 0x37, 0x3b, 0x49, 0x38, 0x3b, 0x4b,
+0x39, 0x3b, 0x31, 0x30, 0x3b, 0x31, 0x31, 0x3b, 0x31, 0x32, 0x41d, 0x44d,
+0x433, 0x434, 0x4af, 0x433, 0x44d, 0x44d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b,
+0x425, 0x43e, 0x451, 0x440, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440, 0x20, 0x441,
+0x430, 0x440, 0x3b, 0x413, 0x443, 0x440, 0x430, 0x432, 0x434, 0x443, 0x433, 0x430,
+0x430, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x414, 0x4e9, 0x440, 0x4e9, 0x432,
+0x434, 0x4af, 0x433, 0x44d, 0x44d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x422,
+0x430, 0x432, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440, 0x20, 0x441, 0x430, 0x440,
+0x3b, 0x417, 0x443, 0x440, 0x433, 0x430, 0x430, 0x434, 0x443, 0x433, 0x430, 0x430,
+0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x414, 0x43e, 0x43b, 0x43e, 0x43e, 0x434,
+0x443, 0x433, 0x430, 0x430, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x41d, 0x430,
+0x439, 0x43c, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440, 0x20, 0x441, 0x430, 0x440,
+0x3b, 0x415, 0x441, 0x434, 0x4af, 0x433, 0x44d, 0x44d, 0x440, 0x20, 0x441, 0x430,
+0x440, 0x3b, 0x410, 0x440, 0x430, 0x432, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440,
+0x20, 0x441, 0x430, 0x440, 0x3b, 0x410, 0x440, 0x432, 0x430, 0x43d, 0x20, 0x43d,
+0x44d, 0x433, 0x434, 0x4af, 0x433, 0x44d, 0x44d, 0x440, 0x20, 0x441, 0x430, 0x440,
+0x3b, 0x410, 0x440, 0x432, 0x430, 0x43d, 0x20, 0x445, 0x43e, 0x451, 0x440, 0x434,
+0x443, 0x433, 0x430, 0x430, 0x440, 0x20, 0x441, 0x430, 0x440, 0x43d, 0x44d, 0x433,
+0x434, 0x4af, 0x433, 0x44d, 0x44d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x445,
+0x43e, 0x451, 0x440, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440, 0x20, 0x441, 0x430,
+0x440, 0x3b, 0x433, 0x443, 0x440, 0x430, 0x432, 0x434, 0x443, 0x433, 0x430, 0x430,
+0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x434, 0x4e9, 0x440, 0x4e9, 0x432, 0x434,
+0x4af, 0x433, 0x44d, 0x44d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x442, 0x430,
+0x432, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b,
+0x437, 0x443, 0x440, 0x433, 0x430, 0x430, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440,
+0x20, 0x441, 0x430, 0x440, 0x3b, 0x434, 0x43e, 0x43b, 0x43e, 0x43e, 0x434, 0x443,
+0x433, 0x430, 0x430, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x43d, 0x430, 0x439,
+0x43c, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b,
+0x435, 0x441, 0x434, 0x4af, 0x433, 0x44d, 0x44d, 0x440, 0x20, 0x441, 0x430, 0x440,
+0x3b, 0x430, 0x440, 0x430, 0x432, 0x434, 0x443, 0x433, 0x430, 0x430, 0x440, 0x20,
+0x441, 0x430, 0x440, 0x3b, 0x430, 0x440, 0x432, 0x430, 0x43d, 0x20, 0x43d, 0x44d,
+0x433, 0x434, 0x4af, 0x433, 0x44d, 0x44d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b,
+0x430, 0x440, 0x432, 0x430, 0x43d, 0x20, 0x445, 0x43e, 0x451, 0x440, 0x434, 0x443,
+0x433, 0x430, 0x430, 0x440, 0x20, 0x441, 0x430, 0x440, 0x31, 0x2d, 0x440, 0x20,
+0x441, 0x430, 0x440, 0x3b, 0x32, 0x2d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b,
+0x33, 0x2d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x34, 0x2d, 0x440, 0x20,
+0x441, 0x430, 0x440, 0x3b, 0x35, 0x2d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b,
+0x36, 0x2d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x37, 0x2d, 0x440, 0x20,
+0x441, 0x430, 0x440, 0x3b, 0x38, 0x2d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b,
+0x39, 0x2d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x3b, 0x31, 0x30, 0x2d, 0x440,
+0x20, 0x441, 0x430, 0x440, 0x3b, 0x31, 0x31, 0x2d, 0x440, 0x20, 0x441, 0x430,
+0x440, 0x3b, 0x31, 0x32, 0x2d, 0x440, 0x20, 0x441, 0x430, 0x440, 0x49, 0x3b,
+0x49, 0x49, 0x3b, 0x49, 0x49, 0x49, 0x3b, 0x49, 0x56, 0x3b, 0x56, 0x3b,
+0x56, 0x49, 0x3b, 0x56, 0x49, 0x49, 0x3b, 0x56, 0x49, 0x49, 0x49, 0x3b,
+0x49, 0x58, 0x3b, 0x58, 0x3b, 0x58, 0x49, 0x3b, 0x58, 0x49, 0x49, 0x1828,
+0x1822, 0x182d, 0x1821, 0x1833, 0x1825, 0x182d, 0x1821, 0x1837, 0x20, 0x1830, 0x1820, 0x1837,
+0x180e, 0x1820, 0x3b, 0x182c, 0x1823, 0x1836, 0x1820, 0x1833, 0x1823, 0x182d, 0x1820, 0x1837,
+0x20, 0x1830, 0x1820, 0x1837, 0x202f, 0x1820, 0x3b, 0x182d, 0x1823, 0x1837, 0x182a, 0x1821,
+0x1833, 0x1823, 0x182d, 0x1820, 0x1837, 0x20, 0x1830, 0x1820, 0x1837, 0x202f, 0x1820, 0x3b,
+0x1833, 0x1825, 0x1837, 0x182a, 0x1821, 0x1833, 0x1825, 0x182d, 0x1821, 0x1837, 0x20, 0x1830,
+0x1820, 0x1837, 0x180e, 0x1820, 0x3b, 0x1832, 0x1820, 0x182a, 0x1823, 0x1833, 0x1823, 0x182d,
+0x1820, 0x1837, 0x20, 0x1830, 0x1820, 0x1837, 0x202f, 0x1820, 0x3b, 0x1835, 0x1822, 0x1837,
+0x182d, 0x1823, 0x182d, 0x1820, 0x1833, 0x1823, 0x182d, 0x1820, 0x1837, 0x20, 0x1830, 0x1820,
+0x1837, 0x180e, 0x1820, 0x3b, 0x1832, 0x1823, 0x182f, 0x1823, 0x182d, 0x1820, 0x1833, 0x1823,
+0x182d, 0x1820, 0x1837, 0x20, 0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x3b, 0x1828, 0x1820,
+0x1822, 0x182e, 0x1820, 0x1833, 0x1825, 0x182d, 0x1820, 0x1837, 0x20, 0x1830, 0x1820, 0x1837,
+0x180e, 0x1820, 0x3b, 0x1836, 0x1822, 0x1830, 0x1825, 0x1833, 0x1825, 0x182d, 0x1821, 0x1837,
+0x20, 0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x3b, 0x1820, 0x1837, 0x182a, 0x1820, 0x1833,
+0x1823, 0x182d, 0x1820, 0x1837, 0x20, 0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x3b, 0x1820,
+0x1837, 0x182a, 0x1820, 0x1828, 0x20, 0x1828, 0x1822, 0x182d, 0x1821, 0x1833, 0x1825, 0x182d,
+0x1821, 0x1837, 0x20, 0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x3b, 0x1820, 0x1837, 0x182a,
+0x1820, 0x1828, 0x20, 0x182c, 0x1823, 0x1836, 0x1820, 0x1833, 0x1823, 0x182d, 0x1820, 0x1837,
+0x20, 0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x31, 0x202f, 0x180a, 0x1837, 0x20, 0x1830,
+0x1820, 0x1837, 0x180e, 0x1820, 0x3b, 0x32, 0x202f, 0x180a, 0x1837, 0x20, 0x1830, 0x1820,
+0x1837, 0x180e, 0x1820, 0x3b, 0x33, 0x180a, 0x1837, 0x20, 0x1830, 0x1820, 0x1837, 0x180e,
+0x1820, 0x3b, 0x34, 0x202f, 0x180a, 0x1837, 0x20, 0x1830, 0x1820, 0x1837, 0x180e, 0x1820,
+0x3b, 0x35, 0x202f, 0x180a, 0x1837, 0x20, 0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x3b,
+0x36, 0x202f, 0x180a, 0x1837, 0x20, 0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x3b, 0x37,
+0x202f, 0x180a, 0x1837, 0x20, 0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x3b, 0x38, 0x202f,
+0x180a, 0x1837, 0x20, 0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x3b, 0x39, 0x202f, 0x180a,
+0x1837, 0x20, 0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x3b, 0x31, 0x30, 0x20, 0x180a,
+0x1837, 0x20, 0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x3b, 0x31, 0x31, 0x180a, 0x1837,
+0x20, 0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x3b, 0x31, 0x32, 0x180a, 0x1837, 0x20,
+0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x31, 0x202f, 0x180a, 0x1837, 0x20, 0x1830, 0x1820,
+0x1837, 0x180e, 0x1820, 0x3b, 0x32, 0x202f, 0x180a, 0x1837, 0x20, 0x1830, 0x1820, 0x1837,
+0x180e, 0x1820, 0x3b, 0x33, 0x180a, 0x1837, 0x20, 0x1830, 0x1820, 0x1837, 0x180e, 0x1820,
+0x3b, 0x34, 0x202f, 0x180a, 0x1837, 0x20, 0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x3b,
+0x35, 0x202f, 0x180a, 0x1837, 0x20, 0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x3b, 0x36,
+0x202f, 0x180a, 0x1837, 0x20, 0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x3b, 0x37, 0x202f,
+0x180a, 0x1837, 0x20, 0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x3b, 0x38, 0x180a, 0x1837,
+0x20, 0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x3b, 0x39, 0x20, 0x180a, 0x1837, 0x20,
+0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x3b, 0x31, 0x30, 0x20, 0x180a, 0x1837, 0x20,
+0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x3b, 0x31, 0x31, 0x20, 0x180a, 0x1837, 0x20,
+0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x3b, 0x31, 0x32, 0x20, 0x180a, 0x1837, 0x20,
+0x1830, 0x1820, 0x1837, 0x180e, 0x1820, 0x7a, 0x61, 0x6e, 0x76, 0x69, 0x65, 0x3b,
+0x66, 0x65, 0x76, 0x72, 0x69, 0x79, 0x65, 0x3b, 0x6d, 0x61, 0x72, 0x73,
+0x3b, 0x61, 0x76, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x65, 0x3b, 0x7a, 0x69,
+0x6e, 0x3b, 0x7a, 0x69, 0x6c, 0x79, 0x65, 0x3b, 0x6f, 0x75, 0x74, 0x3b,
+0x73, 0x65, 0x70, 0x74, 0x61, 0x6d, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62,
+0x3b, 0x6e, 0x6f, 0x76, 0x61, 0x6d, 0x3b, 0x64, 0x65, 0x73, 0x61, 0x6d,
+0x7a, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x76, 0x3b, 0x6d, 0x61, 0x72, 0x3b,
+0x61, 0x76, 0x72, 0x3b, 0x6d, 0x65, 0x3b, 0x7a, 0x69, 0x6e, 0x3b, 0x7a,
+0x69, 0x6c, 0x3b, 0x6f, 0x75, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x3b, 0x6f,
+0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65, 0x73, 0x7a, 0x3b,
+0x66, 0x3b, 0x6d, 0x3b, 0x61, 0x3b, 0x6d, 0x3b, 0x7a, 0x3b, 0x7a, 0x3b,
+0x6f, 0x3b, 0x73, 0x3b, 0x6f, 0x3b, 0x6e, 0x3b, 0x64, 0x46, 0x129, 0x69,
+0x20, 0x4c, 0x6f, 0x6f, 0x3b, 0x43, 0x6f, 0x6b, 0x63, 0x77, 0x61, 0x6b,
+0x6c, 0x61, 0x14b, 0x6e, 0x65, 0x3b, 0x43, 0x6f, 0x6b, 0x63, 0x77, 0x61,
+0x6b, 0x6c, 0x69, 0x69, 0x3b, 0x46, 0x129, 0x69, 0x20, 0x4d, 0x61, 0x72,
+0x66, 0x6f, 0x6f, 0x3b, 0x4d, 0x61, 0x64, 0x1dd, 0x1dd, 0x75, 0x75, 0x74,
+0x1dd, 0x62, 0x69, 0x6a, 0x61, 0x14b, 0x3b, 0x4d, 0x61, 0x6d, 0x1dd, 0x14b,
+0x67, 0x77, 0xe3, 0x61, 0x66, 0x61, 0x68, 0x62, 0x69, 0x69, 0x3b, 0x4d,
+0x61, 0x6d, 0x1dd, 0x14b, 0x67, 0x77, 0xe3, 0x61, 0x6c, 0x69, 0x69, 0x3b,
+0x4d, 0x61, 0x64, 0x1dd, 0x6d, 0x62, 0x69, 0x69, 0x3b, 0x46, 0x129, 0x69,
+0x20, 0x44, 0x1dd, 0x253, 0x6c, 0x69, 0x69, 0x3b, 0x46, 0x129, 0x69, 0x20,
+0x4d, 0x75, 0x6e, 0x64, 0x61, 0x14b, 0x3b, 0x46, 0x129, 0x69, 0x20, 0x47,
+0x77, 0x61, 0x68, 0x6c, 0x6c, 0x65, 0x3b, 0x46, 0x129, 0x69, 0x20, 0x59,
+0x75, 0x72, 0x75, 0x46, 0x4c, 0x4f, 0x3b, 0x43, 0x4c, 0x41, 0x3b, 0x43,
+0x4b, 0x49, 0x3b, 0x46, 0x4d, 0x46, 0x3b, 0x4d, 0x41, 0x44, 0x3b, 0x4d,
+0x42, 0x49, 0x3b, 0x4d, 0x4c, 0x49, 0x3b, 0x4d, 0x41, 0x4d, 0x3b, 0x46,
+0x44, 0x45, 0x3b, 0x46, 0x4d, 0x55, 0x3b, 0x46, 0x47, 0x57, 0x3b, 0x46,
+0x59, 0x55, 0x4f, 0x3b, 0x41, 0x3b, 0x49, 0x3b, 0x46, 0x3b, 0x44, 0x3b,
+0x42, 0x3b, 0x4c, 0x3b, 0x4d, 0x3b, 0x45, 0x3b, 0x55, 0x3b, 0x57, 0x3b,
+0x59, 0x52, 0x76, 0x66, 0x6f, 0x20, 0x43, 0x75, 0x73, 0x65, 0x3b, 0x48,
+0x6f, 0x74, 0x76, 0x6c, 0x65, 0x20, 0x48, 0x76, 0x73, 0x65, 0x3b, 0x54,
+0x61, 0x73, 0x61, 0x68, 0x63, 0x75, 0x63, 0x65, 0x3b, 0x54, 0x61, 0x73,
+0x61, 0x68, 0x63, 0x65, 0x20, 0x52, 0x61, 0x6b, 0x6b, 0x6f, 0x3b, 0x4b,
+0x65, 0x20, 0x48, 0x76, 0x73, 0x65, 0x3b, 0x4b, 0x76, 0x63, 0x6f, 0x20,
+0x48, 0x76, 0x73, 0x65, 0x3b, 0x48, 0x69, 0x79, 0x75, 0x63, 0x65, 0x3b,
+0x48, 0x69, 0x79, 0x6f, 0x20, 0x52, 0x61, 0x6b, 0x6b, 0x6f, 0x3b, 0x4f,
+0x74, 0x6f, 0x77, 0x6f, 0x73, 0x6b, 0x75, 0x63, 0x65, 0x3b, 0x4f, 0x74,
+0x6f, 0x77, 0x6f, 0x73, 0x6b, 0x76, 0x20, 0x52, 0x61, 0x6b, 0x6b, 0x6f,
+0x3b, 0x45, 0x68, 0x6f, 0x6c, 0x65, 0x3b, 0x52, 0x76, 0x66, 0x6f, 0x20,
+0x52, 0x61, 0x6b, 0x6b, 0x6f, 0x1c3, 0x4b, 0x68, 0x61, 0x6e, 0x6e, 0x69,
+0x3b, 0x1c3, 0x4b, 0x68, 0x61, 0x6e, 0x1c0, 0x67, 0xf4, 0x61, 0x62, 0x3b,
+0x1c0, 0x4b, 0x68, 0x75, 0x75, 0x1c1, 0x6b, 0x68, 0xe2, 0x62, 0x3b, 0x1c3,
+0x48, 0xf4, 0x61, 0x1c2, 0x6b, 0x68, 0x61, 0x69, 0x62, 0x3b, 0x1c3, 0x4b,
+0x68, 0x61, 0x69, 0x74, 0x73, 0xe2, 0x62, 0x3b, 0x47, 0x61, 0x6d, 0x61,
+0x1c0, 0x61, 0x65, 0x62, 0x3b, 0x1c2, 0x4b, 0x68, 0x6f, 0x65, 0x73, 0x61,
+0x6f, 0x62, 0x3b, 0x41, 0x6f, 0x1c1, 0x6b, 0x68, 0x75, 0x75, 0x6d, 0xfb,
+0x1c1, 0x6b, 0x68, 0xe2, 0x62, 0x3b, 0x54, 0x61, 0x72, 0x61, 0x1c0, 0x6b,
+0x68, 0x75, 0x75, 0x6d, 0xfb, 0x1c1, 0x6b, 0x68, 0xe2, 0x62, 0x3b, 0x1c2,
+0x4e, 0xfb, 0x1c1, 0x6e, 0xe2, 0x69, 0x73, 0x65, 0x62, 0x3b, 0x1c0, 0x48,
+0x6f, 0x6f, 0x1c2, 0x67, 0x61, 0x65, 0x62, 0x3b, 0x48, 0xf4, 0x61, 0x73,
+0x6f, 0x72, 0x65, 0x1c1, 0x6b, 0x68, 0xe2, 0x62, 0x91c, 0x928, 0x935, 0x930,
+0x940, 0x3b, 0x92b, 0x947, 0x92c, 0x94d, 0x930, 0x941, 0x905, 0x930, 0x940, 0x3b,
+0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x93f, 0x932,
+0x3b, 0x92e, 0x947, 0x3b, 0x91c, 0x941, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x93e,
+0x908, 0x3b, 0x905, 0x917, 0x938, 0x94d, 0x91f, 0x3b, 0x938, 0x947, 0x92a, 0x94d,
+0x91f, 0x947, 0x92e, 0x94d, 0x92c, 0x930, 0x3b, 0x905, 0x915, 0x94d, 0x91f, 0x94b,
+0x92c, 0x930, 0x3b, 0x928, 0x94b, 0x92d, 0x947, 0x92e, 0x94d, 0x92c, 0x930, 0x3b,
+0x921, 0x93f, 0x938, 0x947, 0x92e, 0x94d, 0x92c, 0x930, 0x91c, 0x928, 0x3b, 0x92b,
+0x947, 0x947, 0x92c, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a,
+0x94d, 0x930, 0x3b, 0x92e, 0x947, 0x3b, 0x91c, 0x941, 0x928, 0x3b, 0x91c, 0x941,
+0x932, 0x3b, 0x905, 0x917, 0x3b, 0x938, 0x947, 0x92a, 0x3b, 0x905, 0x915, 0x94d,
+0x91f, 0x94b, 0x3b, 0x928, 0x94b, 0x92d, 0x947, 0x3b, 0x921, 0x93f, 0x938, 0x947,
+0x91c, 0x928, 0x3b, 0x92b, 0x947, 0x92c, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a,
+0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x3b, 0x92e, 0x947, 0x3b, 0x91c, 0x941, 0x928,
+0x3b, 0x91c, 0x941, 0x932, 0x3b, 0x905, 0x917, 0x3b, 0x938, 0x947, 0x92a, 0x3b,
+0x905, 0x915, 0x94d, 0x91f, 0x94b, 0x3b, 0x928, 0x94b, 0x92d, 0x947, 0x3b, 0x921,
+0x93f, 0x938, 0x947, 0x73, 0x61, 0x14b, 0x20, 0x74, 0x73, 0x65, 0x74, 0x73,
+0x25b, 0x300, 0x25b, 0x20, 0x6c, 0xf9, 0x6d, 0x3b, 0x73, 0x61, 0x14b, 0x20,
+0x6b, 0xe0, 0x67, 0x20, 0x6e, 0x67, 0x77, 0xf3, 0x14b, 0x3b, 0x73, 0x61,
+0x14b, 0x20, 0x6c, 0x65, 0x70, 0x79, 0xe8, 0x20, 0x73, 0x68, 0xfa, 0x6d,
+0x3b, 0x73, 0x61, 0x14b, 0x20, 0x63, 0xff, 0xf3, 0x3b, 0x73, 0x61, 0x14b,
+0x20, 0x74, 0x73, 0x25b, 0x300, 0x25b, 0x20, 0x63, 0xff, 0xf3, 0x3b, 0x73,
+0x61, 0x14b, 0x20, 0x6e, 0x6a, 0xff, 0x6f, 0x6c, 0xe1, 0x2bc, 0x3b, 0x73,
+0x61, 0x14b, 0x20, 0x74, 0x79, 0x25b, 0x300, 0x62, 0x20, 0x74, 0x79, 0x25b,
+0x300, 0x62, 0x20, 0x6d, 0x62, 0x289, 0x300, 0x14b, 0x3b, 0x73, 0x61, 0x14b,
+0x20, 0x6d, 0x62, 0x289, 0x300, 0x14b, 0x3b, 0x73, 0x61, 0x14b, 0x20, 0x6e,
+0x67, 0x77, 0x254, 0x300, 0x2bc, 0x20, 0x6d, 0x62, 0xff, 0x25b, 0x3b, 0x73,
+0x61, 0x14b, 0x20, 0x74, 0xe0, 0x14b, 0x61, 0x20, 0x74, 0x73, 0x65, 0x74,
+0x73, 0xe1, 0x2bc, 0x3b, 0x73, 0x61, 0x14b, 0x20, 0x6d, 0x65, 0x6a, 0x77,
+0x6f, 0x14b, 0xf3, 0x3b, 0x73, 0x61, 0x14b, 0x20, 0x6c, 0xf9, 0x6d, 0x4e,
+0x64, 0x75, 0x14b, 0x6d, 0x62, 0x69, 0x20, 0x53, 0x61, 0x14b, 0x3b, 0x50,
+0x25b, 0x73, 0x61, 0x14b, 0x20, 0x50, 0x25b, 0x301, 0x70, 0xe1, 0x3b, 0x50,
+0x25b, 0x73, 0x61, 0x14b, 0x20, 0x50, 0x25b, 0x301, 0x74, 0xe1, 0x74, 0x3b,
+0x50, 0x25b, 0x73, 0x61, 0x14b, 0x20, 0x50, 0x25b, 0x301, 0x6e, 0x25b, 0x301,
+0x6b, 0x77, 0x61, 0x3b, 0x50, 0x25b, 0x73, 0x61, 0x14b, 0x20, 0x50, 0x61,
+0x74, 0x61, 0x61, 0x3b, 0x50, 0x25b, 0x73, 0x61, 0x14b, 0x20, 0x50, 0x25b,
+0x301, 0x6e, 0x25b, 0x301, 0x6e, 0x74, 0xfa, 0x6b, 0xfa, 0x3b, 0x50, 0x25b,
+0x73, 0x61, 0x14b, 0x20, 0x53, 0x61, 0x61, 0x6d, 0x62, 0xe1, 0x3b, 0x50,
+0x25b, 0x73, 0x61, 0x14b, 0x20, 0x50, 0x25b, 0x301, 0x6e, 0x25b, 0x301, 0x66,
+0x254, 0x6d, 0x3b, 0x50, 0x25b, 0x73, 0x61, 0x14b, 0x20, 0x50, 0x25b, 0x301,
+0x6e, 0x25b, 0x301, 0x70, 0x66, 0xfa, 0xa78b, 0xfa, 0x3b, 0x50, 0x25b, 0x73,
+0x61, 0x14b, 0x20, 0x4e, 0x25b, 0x67, 0x25b, 0x301, 0x6d, 0x3b, 0x50, 0x25b,
+0x73, 0x61, 0x14b, 0x20, 0x4e, 0x74, 0x73, 0x254, 0x30c, 0x70, 0x6d, 0x254,
+0x301, 0x3b, 0x50, 0x25b, 0x73, 0x61, 0x14b, 0x20, 0x4e, 0x74, 0x73, 0x254,
+0x30c, 0x70, 0x70, 0xe1, 0x4a, 0xe9, 0x6e, 0xfa, 0xe1, 0x72, 0x69, 0x3b,
+0x46, 0x1eb9, 0x301, 0x62, 0xfa, 0xe1, 0x72, 0x69, 0x3b, 0x4d, 0x61, 0x63,
+0x68, 0x3b, 0xc9, 0x70, 0x72, 0x65, 0x6c, 0x3b, 0x4d, 0x65, 0x65, 0x3b,
+0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x61, 0x69, 0x3b, 0x1ecc, 0x67,
+0x1ecd, 0x73, 0x74, 0x3b, 0x53, 0x1eb9, 0x70, 0x74, 0x1eb9, 0x301, 0x6d, 0x62,
+0x61, 0x3b, 0x1ecc, 0x6b, 0x74, 0xf3, 0x62, 0x61, 0x3b, 0x4e, 0x1ecd, 0x76,
+0x1eb9, 0x301, 0x6d, 0x62, 0x61, 0x3b, 0x44, 0x69, 0x73, 0x1eb9, 0x301, 0x6d,
+0x62, 0x61, 0x4a, 0xe9, 0x6e, 0x3b, 0x46, 0x1eb9, 0x301, 0x62, 0x3b, 0x4d,
+0x61, 0x63, 0x68, 0x3b, 0xc9, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x65, 0x3b,
+0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x1ecc, 0x301, 0x67, 0x1ecd,
+0x3b, 0x53, 0x1eb9, 0x70, 0x3b, 0x1ecc, 0x6b, 0x74, 0x3b, 0x4e, 0x1ecd, 0x76,
+0x3b, 0x44, 0x69, 0x73, 0x4a, 0xe9, 0x6e, 0x3b, 0x46, 0x1eb9, 0x301, 0x62,
+0x3b, 0x4d, 0x61, 0x63, 0x68, 0x3b, 0xc9, 0x70, 0x72, 0x3b, 0x4d, 0x65,
+0x65, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x1ecc, 0x67,
+0x1ecd, 0x3b, 0x53, 0x1eb9, 0x70, 0x3b, 0x1ecc, 0x6b, 0x74, 0x3b, 0x4e, 0x1ecd,
+0x76, 0x3b, 0x44, 0x69, 0x73, 0x7d3, 0x7cc, 0x7f2, 0x7e0, 0x7ca, 0x7e5, 0x7ce,
+0x7df, 0x7cb, 0x7f2, 0x3b, 0x7de, 0x7cf, 0x7f2, 0x7de, 0x7cf, 0x7dc, 0x7cd, 0x3b,
+0x7d5, 0x7d9, 0x7ca, 0x7d3, 0x7ca, 0x3b, 0x7de, 0x7cf, 0x7f2, 0x7de, 0x7cf, 0x7d8,
+0x7cc, 0x7ec, 0x7d3, 0x7cc, 0x3b, 0x7d8, 0x7d3, 0x7ca, 0x7ec, 0x7d5, 0x7ca, 0x3b,
+0x7e5, 0x7ca, 0x7ec, 0x7db, 0x7cc, 0x7ec, 0x7e5, 0x7d9, 0x7ca, 0x3b, 0x7de, 0x7ca,
+0x7ec, 0x7d9, 0x7cc, 0x7dd, 0x7d0, 0x7ed, 0x3b, 0x7d8, 0x7d3, 0x7ca, 0x7ec, 0x7d3,
+0x7cc, 0x7df, 0x7ca, 0x3b, 0x7d5, 0x7ce, 0x7df, 0x7ca, 0x7dd, 0x7cc, 0x7f2, 0x3b,
+0x7de, 0x7cf, 0x7f2, 0x7d3, 0x7cc, 0x7d5, 0x7cc, 0x7ee, 0x3b, 0x7e3, 0x7cd, 0x7e3,
+0x7cd, 0x7d3, 0x7ca, 0x3b, 0x7de, 0x7cf, 0x7df, 0x7cc, 0x7f2, 0x7de, 0x7cf, 0x7df,
+0x7cc, 0x7f2, 0x7d3, 0x7cc, 0x7f2, 0x7e0, 0x3b, 0x7de, 0x7cf, 0x7f2, 0x7de, 0x3b,
+0x7d5, 0x7d9, 0x7ca, 0x3b, 0x7de, 0x7cf, 0x7f2, 0x7d8, 0x3b, 0x7d8, 0x7d3, 0x7ca,
+0x7ec, 0x7d5, 0x3b, 0x7e5, 0x7ca, 0x7ec, 0x7db, 0x3b, 0x7de, 0x7ca, 0x7ec, 0x7d9,
+0x3b, 0x7d8, 0x7d3, 0x7ca, 0x7ec, 0x7d3, 0x3b, 0x7d5, 0x7ce, 0x7df, 0x7ca, 0x7dd,
+0x7cc, 0x7f2, 0x3b, 0x7de, 0x7cf, 0x7f2, 0x7d3, 0x3b, 0x7e3, 0x7cd, 0x7e3, 0x3b,
+0x7de, 0x7cf, 0x7df, 0x7d3, 0x3b, 0x7de, 0x3b, 0x7d5, 0x3b, 0x7de, 0x3b, 0x7d8,
+0x3b, 0x7e5, 0x3b, 0x7de, 0x3b, 0x7d8, 0x3b, 0x7d5, 0x3b, 0x7de, 0x3b, 0x7e3,
+0x3b, 0x7de, 0x62c, 0x627, 0x646, 0x6a4, 0x6cc, 0x6d5, 0x3b, 0x641, 0x626, 0x6a4,
+0x631, 0x6cc, 0x6d5, 0x3b, 0x645, 0x627, 0x631, 0x633, 0x3b, 0x622, 0x6a4, 0x631,
+0x6cc, 0x644, 0x3b, 0x645, 0x626, 0x6cc, 0x3b, 0x62c, 0x648, 0x659, 0x623, 0x646,
+0x3b, 0x62c, 0x648, 0x659, 0x644, 0x627, 0x3b, 0x622, 0x6af, 0x648, 0x633, 0x62a,
+0x3b, 0x633, 0x626, 0x67e, 0x62a, 0x627, 0x645, 0x631, 0x3b, 0x626, 0x648, 0x6a9,
+0x62a, 0x648, 0x6a4, 0x631, 0x3b, 0x646, 0x648, 0x6a4, 0x627, 0x645, 0x631, 0x3b,
+0x62f, 0x626, 0x633, 0x627, 0x645, 0x631, 0x6f, 0x111, 0x111, 0x61, 0x6a, 0x61,
+0x67, 0x65, 0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x3b, 0x67, 0x75, 0x6f, 0x76,
+0x76, 0x61, 0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x3b, 0x6e, 0x6a, 0x75, 0x6b,
+0x10d, 0x61, 0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x3b, 0x63, 0x75, 0x6f, 0x14b,
+0x6f, 0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x3b, 0x6d, 0x69, 0x65, 0x73, 0x73,
+0x65, 0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x3b, 0x67, 0x65, 0x61, 0x73, 0x73,
+0x65, 0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x3b, 0x73, 0x75, 0x6f, 0x69, 0x64,
+0x6e, 0x65, 0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x3b, 0x62, 0x6f, 0x72, 0x67,
+0x65, 0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x3b, 0x10d, 0x61, 0x6b, 0x10d, 0x61,
+0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x3b, 0x67, 0x6f, 0x6c, 0x67, 0x67, 0x6f,
+0x74, 0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x3b, 0x73, 0x6b, 0xe1, 0x62, 0x6d,
+0x61, 0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x3b, 0x6a, 0x75, 0x6f, 0x76, 0x6c,
+0x61, 0x6d, 0xe1, 0x6e, 0x6e, 0x75, 0x6f, 0x111, 0x111, 0x6a, 0x3b, 0x67,
+0x75, 0x6f, 0x76, 0x3b, 0x6e, 0x6a, 0x75, 0x6b, 0x3b, 0x63, 0x75, 0x6f,
+0x3b, 0x6d, 0x69, 0x65, 0x73, 0x3b, 0x67, 0x65, 0x61, 0x73, 0x3b, 0x73,
+0x75, 0x6f, 0x69, 0x3b, 0x62, 0x6f, 0x72, 0x67, 0x3b, 0x10d, 0x61, 0x6b,
+0x10d, 0x3b, 0x67, 0x6f, 0x6c, 0x67, 0x3b, 0x73, 0x6b, 0xe1, 0x62, 0x3b,
+0x6a, 0x75, 0x6f, 0x76, 0x4f, 0x3b, 0x47, 0x3b, 0x4e, 0x3b, 0x43, 0x3b,
+0x4d, 0x3b, 0x47, 0x3b, 0x53, 0x3b, 0x42, 0x3b, 0x10c, 0x3b, 0x47, 0x3b,
+0x53, 0x3b, 0x4a, 0x6f, 0x111, 0x111, 0x6a, 0x3b, 0x67, 0x75, 0x6f, 0x76,
+0x3b, 0x6e, 0x6a, 0x75, 0x6b, 0x3b, 0x63, 0x75, 0x6f, 0x14b, 0x3b, 0x6d,
+0x69, 0x65, 0x73, 0x3b, 0x67, 0x65, 0x61, 0x73, 0x3b, 0x73, 0x75, 0x6f,
+0x69, 0x3b, 0x62, 0x6f, 0x72, 0x67, 0x3b, 0x10d, 0x61, 0x6b, 0x10d, 0x3b,
+0x67, 0x6f, 0x6c, 0x67, 0x3b, 0x73, 0x6b, 0xe1, 0x62, 0x3b, 0x6a, 0x75,
+0x6f, 0x76, 0x50, 0x68, 0x65, 0x72, 0x65, 0x6b, 0x67, 0x6f, 0x6e, 0x67,
+0x3b, 0x44, 0x69, 0x62, 0x6f, 0x6b, 0x77, 0x61, 0x6e, 0x65, 0x3b, 0x48,
+0x6c, 0x61, 0x6b, 0x6f, 0x6c, 0x61, 0x3b, 0x4d, 0x6f, 0x72, 0x61, 0x6e,
+0x61, 0x6e, 0x67, 0x3b, 0x4d, 0x6f, 0x70, 0x69, 0x74, 0x6c, 0x6f, 0x3b,
+0x50, 0x68, 0x75, 0x70, 0x75, 0x3b, 0x4d, 0x6f, 0x73, 0x65, 0x67, 0x65,
+0x6d, 0x61, 0x6e, 0x79, 0x65, 0x3b, 0x50, 0x68, 0x61, 0x74, 0x6f, 0x3b,
+0x4c, 0x65, 0x77, 0x65, 0x64, 0x69, 0x3b, 0x44, 0x69, 0x70, 0x68, 0x61,
+0x6c, 0x61, 0x6e, 0x65, 0x3b, 0x44, 0x69, 0x62, 0x61, 0x74, 0x73, 0x65,
+0x6c, 0x61, 0x3b, 0x4d, 0x61, 0x6e, 0x74, 0x68, 0x6f, 0x6c, 0x65, 0x50,
+0x68, 0x65, 0x72, 0x65, 0x3b, 0x44, 0x69, 0x62, 0x6f, 0x3b, 0x48, 0x6c,
+0x61, 0x6b, 0x3b, 0x4d, 0x6f, 0x72, 0x61, 0x3b, 0x4d, 0x6f, 0x70, 0x69,
+0x3b, 0x50, 0x68, 0x75, 0x70, 0x75, 0x3b, 0x4d, 0x6f, 0x73, 0x65, 0x3b,
+0x50, 0x68, 0x61, 0x74, 0x6f, 0x3b, 0x4c, 0x65, 0x77, 0x65, 0x3b, 0x44,
+0x69, 0x70, 0x68, 0x61, 0x3b, 0x44, 0x69, 0x62, 0x61, 0x3b, 0x4d, 0x61,
+0x6e, 0x74, 0x68, 0x50, 0x3b, 0x44, 0x3b, 0x48, 0x3b, 0x4d, 0x3b, 0x4d,
+0x3b, 0x50, 0x3b, 0x4d, 0x3b, 0x50, 0x3b, 0x4c, 0x3b, 0x44, 0x3b, 0x44,
+0x3b, 0x4d, 0x5a, 0x69, 0x62, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x6c, 0x61,
+0x3b, 0x4e, 0x68, 0x6c, 0x6f, 0x6c, 0x61, 0x6e, 0x6a, 0x61, 0x3b, 0x4d,
+0x62, 0x69, 0x6d, 0x62, 0x69, 0x74, 0x68, 0x6f, 0x3b, 0x4d, 0x61, 0x62,
+0x61, 0x73, 0x61, 0x3b, 0x4e, 0x6b, 0x77, 0x65, 0x6e, 0x6b, 0x77, 0x65,
+0x7a, 0x69, 0x3b, 0x4e, 0x68, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x6c, 0x61,
+0x3b, 0x4e, 0x74, 0x75, 0x6c, 0x69, 0x6b, 0x61, 0x7a, 0x69, 0x3b, 0x4e,
+0x63, 0x77, 0x61, 0x62, 0x61, 0x6b, 0x61, 0x7a, 0x69, 0x3b, 0x4d, 0x70,
+0x61, 0x6e, 0x64, 0x75, 0x6c, 0x61, 0x3b, 0x4d, 0x66, 0x75, 0x6d, 0x66,
+0x75, 0x3b, 0x4c, 0x77, 0x65, 0x7a, 0x69, 0x3b, 0x4d, 0x70, 0x61, 0x6c,
+0x61, 0x6b, 0x61, 0x7a, 0x69, 0x5a, 0x69, 0x62, 0x3b, 0x4e, 0x68, 0x6c,
+0x6f, 0x3b, 0x4d, 0x62, 0x69, 0x3b, 0x4d, 0x61, 0x62, 0x3b, 0x4e, 0x6b,
+0x77, 0x3b, 0x4e, 0x68, 0x6c, 0x61, 0x3b, 0x4e, 0x74, 0x75, 0x3b, 0x4e,
+0x63, 0x77, 0x3b, 0x4d, 0x70, 0x61, 0x6e, 0x3b, 0x4d, 0x66, 0x75, 0x3b,
+0x4c, 0x77, 0x65, 0x3b, 0x4d, 0x70, 0x61, 0x6c, 0x5a, 0x3b, 0x4e, 0x3b,
+0x4d, 0x3b, 0x4d, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b,
+0x4d, 0x3b, 0x4d, 0x3b, 0x4c, 0x3b, 0x4d, 0x6a, 0x61, 0x6e, 0x75, 0x61,
+0x72, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x3b, 0x6d, 0x61,
+0x72, 0x73, 0x3b, 0x61, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x61, 0x69,
+0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x3b, 0x61,
+0x75, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d,
+0x62, 0x65, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b,
+0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x64, 0x65, 0x73,
+0x65, 0x6d, 0x62, 0x65, 0x72, 0x6a, 0x61, 0x6e, 0x2e, 0x3b, 0x66, 0x65,
+0x62, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x3b, 0x61, 0x70, 0x72, 0x2e,
+0x3b, 0x6d, 0x61, 0x69, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x3b, 0x6a, 0x75,
+0x6c, 0x69, 0x3b, 0x61, 0x75, 0x67, 0x2e, 0x3b, 0x73, 0x65, 0x70, 0x2e,
+0x3b, 0x6f, 0x6b, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64,
+0x65, 0x73, 0x2e, 0x54, 0x69, 0x6f, 0x70, 0x20, 0x74, 0x68, 0x61, 0x72,
+0x20, 0x70, 0x25b, 0x74, 0x3b, 0x50, 0x25b, 0x74, 0x3b, 0x44, 0x75, 0x254,
+0x331, 0x254, 0x331, 0x14b, 0x3b, 0x47, 0x75, 0x61, 0x6b, 0x3b, 0x44, 0x75,
+0xe4, 0x74, 0x3b, 0x4b, 0x6f, 0x72, 0x6e, 0x79, 0x6f, 0x6f, 0x74, 0x3b,
+0x50, 0x61, 0x79, 0x20, 0x79, 0x69, 0x65, 0x331, 0x74, 0x6e, 0x69, 0x3b,
+0x54, 0x68, 0x6f, 0x331, 0x6f, 0x331, 0x72, 0x3b, 0x54, 0x25b, 0x25b, 0x72,
+0x3b, 0x4c, 0x61, 0x61, 0x74, 0x68, 0x3b, 0x4b, 0x75, 0x72, 0x3b, 0x54,
+0x69, 0x6f, 0x331, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x64, 0x69, 0x331, 0x69,
+0x331, 0x74, 0x54, 0x69, 0x6f, 0x70, 0x3b, 0x50, 0x25b, 0x74, 0x3b, 0x44,
+0x75, 0x254, 0x331, 0x254, 0x331, 0x3b, 0x47, 0x75, 0x61, 0x6b, 0x3b, 0x44,
+0x75, 0xe4, 0x3b, 0x4b, 0x6f, 0x72, 0x3b, 0x50, 0x61, 0x79, 0x3b, 0x54,
+0x68, 0x6f, 0x6f, 0x3b, 0x54, 0x25b, 0x25b, 0x3b, 0x4c, 0x61, 0x61, 0x3b,
+0x4b, 0x75, 0x72, 0x3b, 0x54, 0x69, 0x64, 0x54, 0x3b, 0x50, 0x3b, 0x44,
+0x3b, 0x47, 0x3b, 0x44, 0x3b, 0x4b, 0x3b, 0x50, 0x3b, 0x54, 0x3b, 0x54,
+0x3b, 0x4c, 0x3b, 0x4b, 0x3b, 0x54, 0x4a, 0x61, 0x6e, 0x75, 0x77, 0x61,
+0x6c, 0x65, 0x3b, 0x46, 0x65, 0x62, 0x75, 0x6c, 0x75, 0x77, 0x61, 0x6c,
+0x65, 0x3b, 0x4d, 0x61, 0x6c, 0x69, 0x63, 0x68, 0x69, 0x3b, 0x45, 0x70,
+0x75, 0x6c, 0x6f, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69,
+0x3b, 0x4a, 0x75, 0x6c, 0x61, 0x69, 0x3b, 0x4f, 0x67, 0x61, 0x73, 0x69,
+0x74, 0x69, 0x3b, 0x53, 0x65, 0x70, 0x75, 0x74, 0x65, 0x6d, 0x62, 0x61,
+0x3b, 0x4f, 0x6b, 0x75, 0x74, 0x6f, 0x62, 0x61, 0x3b, 0x4e, 0x6f, 0x76,
+0x65, 0x6d, 0x62, 0x61, 0x3b, 0x44, 0x69, 0x73, 0x65, 0x6d, 0x62, 0x61,
+0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x6c, 0x3b,
+0x45, 0x70, 0x75, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b,
+0x4a, 0x75, 0x6c, 0x3b, 0x4f, 0x67, 0x61, 0x3b, 0x53, 0x65, 0x70, 0x3b,
+0x4f, 0x6b, 0x75, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x69, 0x73, 0x67,
+0x65, 0x6e, 0x69, 0xe8, 0x72, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x69, 0xe8,
+0x72, 0x3b, 0x6d, 0x61, 0x72, 0xe7, 0x3b, 0x61, 0x62, 0x72, 0x69, 0x6c,
+0x3b, 0x6d, 0x61, 0x69, 0x3b, 0x6a, 0x75, 0x6e, 0x68, 0x3b, 0x6a, 0x75,
+0x6c, 0x68, 0x65, 0x74, 0x3b, 0x61, 0x67, 0x6f, 0x73, 0x74, 0x3b, 0x73,
+0x65, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x6f, 0x63, 0x74, 0xf2,
+0x62, 0x72, 0x65, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x65,
+0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x64, 0x65, 0x20,
+0x67, 0x65, 0x6e, 0x69, 0xe8, 0x72, 0x3b, 0x64, 0x65, 0x20, 0x66, 0x65,
+0x62, 0x72, 0x69, 0xe8, 0x72, 0x3b, 0x64, 0x65, 0x20, 0x6d, 0x61, 0x72,
+0xe7, 0x3b, 0x64, 0x2019, 0x61, 0x62, 0x72, 0x69, 0x6c, 0x3b, 0x64, 0x65,
+0x20, 0x6d, 0x61, 0x69, 0x3b, 0x64, 0x65, 0x20, 0x6a, 0x75, 0x6e, 0x68,
+0x3b, 0x64, 0x65, 0x20, 0x6a, 0x75, 0x6c, 0x68, 0x65, 0x74, 0x3b, 0x64,
+0x2019, 0x61, 0x67, 0x6f, 0x73, 0x74, 0x3b, 0x64, 0x65, 0x20, 0x73, 0x65,
+0x74, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x2019, 0x6f, 0x63, 0x74,
+0xf2, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x65, 0x20, 0x6e, 0x6f, 0x76, 0x65,
+0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x65, 0x20, 0x64, 0x65, 0x63, 0x65,
+0x6d, 0x62, 0x72, 0x65, 0x67, 0x65, 0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x62,
+0x2e, 0x3b, 0x6d, 0x61, 0x72, 0xe7, 0x3b, 0x61, 0x62, 0x72, 0x2e, 0x3b,
+0x6d, 0x61, 0x69, 0x3b, 0x6a, 0x75, 0x6e, 0x68, 0x3b, 0x6a, 0x75, 0x6c,
+0x2e, 0x3b, 0x61, 0x67, 0x6f, 0x2e, 0x3b, 0x73, 0x65, 0x74, 0x2e, 0x3b,
+0x6f, 0x63, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65,
+0x63, 0x2e, 0x47, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b,
+0x4a, 0x3b, 0x4a, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b,
+0x44, 0x67, 0xe8, 0x72, 0x3b, 0x68, 0x65, 0x72, 0x65, 0x75, 0xe8, 0x72,
+0x3b, 0x6d, 0x61, 0x72, 0xe7, 0x3b, 0x61, 0x62, 0x72, 0x69, 0x75, 0x3b,
+0x6d, 0x61, 0x69, 0x3b, 0x6a, 0x75, 0x6e, 0x68, 0x3b, 0x6a, 0x75, 0x72,
+0x69, 0xf2, 0x6c, 0x3b, 0x61, 0x67, 0x6f, 0x73, 0x74, 0x3b, 0x73, 0x65,
+0x74, 0x65, 0x6d, 0x65, 0x3b, 0x6f, 0x63, 0x74, 0x6f, 0x62, 0x72, 0x65,
+0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x65, 0x3b, 0x64, 0x65, 0x73, 0x65,
+0x6d, 0x65, 0x67, 0xe8, 0x72, 0x3b, 0x68, 0x65, 0x72, 0x3b, 0x6d, 0x61,
+0x72, 0x3b, 0x61, 0x62, 0x72, 0x3b, 0x6d, 0x61, 0x69, 0x3b, 0x6a, 0x75,
+0x6e, 0x3b, 0x6a, 0x75, 0x72, 0x3b, 0x61, 0x67, 0x6f, 0x3b, 0x73, 0x65,
+0x74, 0x3b, 0x6f, 0x63, 0x74, 0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65,
+0x63, 0x47, 0x3b, 0x48, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4a,
+0x3b, 0x4a, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44,
+0xb1c, 0xb3e, 0xb28, 0xb41, 0xb06, 0xb30, 0xb40, 0x3b, 0xb2b, 0xb47, 0xb2c, 0xb43,
+0xb06, 0xb30, 0xb40, 0x3b, 0xb2e, 0xb3e, 0xb30, 0xb4d, 0xb1a, 0xb4d, 0xb1a, 0x3b,
+0xb05, 0xb2a, 0xb4d, 0xb30, 0xb47, 0xb32, 0x3b, 0xb2e, 0xb07, 0x3b, 0xb1c, 0xb41,
+0xb28, 0x3b, 0xb1c, 0xb41, 0xb32, 0xb3e, 0xb07, 0x3b, 0xb05, 0xb17, 0xb37, 0xb4d,
+0xb1f, 0x3b, 0xb38, 0xb47, 0xb2a, 0xb4d, 0xb1f, 0xb47, 0xb2e, 0xb4d, 0xb2c, 0xb30,
+0x3b, 0xb05, 0xb15, 0xb4d, 0xb1f, 0xb4b, 0xb2c, 0xb30, 0x3b, 0xb28, 0xb2d, 0xb47,
+0xb2e, 0xb4d, 0xb2c, 0xb30, 0x3b, 0xb21, 0xb3f, 0xb38, 0xb47, 0xb2e, 0xb4d, 0xb2c,
+0xb30, 0xb1c, 0xb3e, 0x3b, 0xb2b, 0xb47, 0x3b, 0xb2e, 0xb3e, 0x3b, 0xb05, 0x3b,
+0xb2e, 0xb07, 0x3b, 0xb1c, 0xb41, 0x3b, 0xb1c, 0xb41, 0x3b, 0xb05, 0x3b, 0xb38,
+0xb47, 0x3b, 0xb05, 0x3b, 0xb28, 0x3b, 0xb21, 0xb3f, 0x41, 0x6d, 0x61, 0x6a,
+0x6a, 0x69, 0x69, 0x3b, 0x47, 0x75, 0x72, 0x61, 0x61, 0x6e, 0x64, 0x68,
+0x61, 0x6c, 0x61, 0x3b, 0x42, 0x69, 0x74, 0x6f, 0x6f, 0x74, 0x65, 0x65,
+0x73, 0x73, 0x61, 0x3b, 0x45, 0x6c, 0x62, 0x61, 0x3b, 0x43, 0x61, 0x61,
+0x6d, 0x73, 0x61, 0x3b, 0x57, 0x61, 0x78, 0x61, 0x62, 0x61, 0x6a, 0x6a,
+0x69, 0x69, 0x3b, 0x41, 0x64, 0x6f, 0x6f, 0x6c, 0x65, 0x65, 0x73, 0x73,
+0x61, 0x3b, 0x48, 0x61, 0x67, 0x61, 0x79, 0x79, 0x61, 0x3b, 0x46, 0x75,
+0x75, 0x6c, 0x62, 0x61, 0x6e, 0x61, 0x3b, 0x4f, 0x6e, 0x6b, 0x6f, 0x6c,
+0x6f, 0x6c, 0x65, 0x65, 0x73, 0x73, 0x61, 0x3b, 0x53, 0x61, 0x64, 0x61,
+0x61, 0x73, 0x61, 0x3b, 0x4d, 0x75, 0x64, 0x64, 0x65, 0x65, 0x41, 0x6d,
+0x61, 0x3b, 0x47, 0x75, 0x72, 0x3b, 0x42, 0x69, 0x74, 0x3b, 0x45, 0x6c,
+0x62, 0x3b, 0x43, 0x61, 0x6d, 0x3b, 0x57, 0x61, 0x78, 0x3b, 0x41, 0x64,
+0x6f, 0x3b, 0x48, 0x61, 0x67, 0x3b, 0x46, 0x75, 0x6c, 0x3b, 0x4f, 0x6e,
+0x6b, 0x3b, 0x53, 0x61, 0x64, 0x3b, 0x4d, 0x75, 0x64, 0x41, 0x3b, 0x47,
+0x3b, 0x42, 0x3b, 0x45, 0x3b, 0x43, 0x3b, 0x57, 0x3b, 0x41, 0x3b, 0x48,
+0x3b, 0x46, 0x3b, 0x4f, 0x3b, 0x53, 0x3b, 0x4d, 0xd801, 0xdcc0, 0xd801, 0xdce3,
+0x358, 0xd801, 0xdcea, 0x358, 0xd801, 0xdcec, 0xd801, 0xdcd8, 0x20, 0xd801, 0xdcc4, 0xd801,
+0xdcd8, 0xd801, 0xdce1, 0xd801, 0xdcdb, 0x358, 0xd801, 0xdce7, 0xd801, 0xdcdf, 0x3b, 0xd801,
+0xdcc0, 0xd801, 0xdce3, 0x358, 0xd801, 0xdcea, 0x358, 0xd801, 0xdcec, 0xd801, 0xdcd8, 0x20,
+0xd801, 0xdccf, 0xd801, 0xdcdf, 0xd801, 0xdcf5, 0xd801, 0xdcea, 0x358, 0xd801, 0xdcec, 0xd801,
+0xdcd8, 0x3b, 0xd801, 0xdcc0, 0xd801, 0xdce3, 0x358, 0xd801, 0xdcea, 0x358, 0xd801, 0xdcec,
+0xd801, 0xdcd8, 0x20, 0xd801, 0xdccf, 0xd801, 0xdcdf, 0xd801, 0xdcf5, 0xd801, 0xdcd8, 0xd801,
+0xdcdc, 0xd801, 0xdce3, 0x3b, 0xd801, 0xdcc0, 0xd801, 0xdce3, 0x358, 0xd801, 0xdcea, 0x358,
+0xd801, 0xdcec, 0xd801, 0xdcd8, 0x20, 0xd801, 0xdccf, 0xd801, 0xdcdf, 0xd801, 0xdcf0, 0xd801,
+0xdcea, 0xd801, 0xdcec, 0xd801, 0xdcd8, 0x3b, 0xd801, 0xdcc0, 0xd801, 0xdce3, 0x358, 0xd801,
+0xdcea, 0x358, 0xd801, 0xdcec, 0xd801, 0xdcd8, 0x20, 0xd801, 0xdccf, 0xd801, 0xdcdf, 0xd801,
+0xdcee, 0xd801, 0xdcd8, 0xd801, 0xdcf0, 0xd801, 0xdcd8, 0x3b, 0xd801, 0xdcc0, 0xd801, 0xdce3,
+0x358, 0xd801, 0xdcea, 0x358, 0xd801, 0xdcec, 0xd801, 0xdcd8, 0x20, 0xd801, 0xdccf, 0xd801,
+0xdcdf, 0xd801, 0xdcef, 0xd801, 0xdcd8, 0xd801, 0xdcec, 0xd801, 0xdcdf, 0x3b, 0xd801, 0xdcc0,
+0xd801, 0xdce3, 0x358, 0xd801, 0xdcea, 0x358, 0xd801, 0xdcec, 0xd801, 0xdcd8, 0x20, 0xd801,
+0xdcc4, 0xd801, 0xdcdf, 0xd801, 0xdcf5, 0xd801, 0xdcea, 0x358, 0xd801, 0xdcec, 0xd801, 0xdcd8,
+0x3b, 0xd801, 0xdcc0, 0xd801, 0xdce3, 0x358, 0xd801, 0xdcea, 0x358, 0xd801, 0xdcec, 0xd801,
+0xdcd8, 0x20, 0xd801, 0xdcbc, 0xd801, 0xdce3, 0xd801, 0xdcdf, 0xd801, 0xdcf0, 0xd801, 0xdcea,
+0xd801, 0xdcec, 0xd801, 0xdcd8, 0x3b, 0xd801, 0xdcc0, 0xd801, 0xdce3, 0x358, 0xd801, 0xdcea,
+0x358, 0xd801, 0xdcec, 0xd801, 0xdcd8, 0x20, 0xd801, 0xdcbf, 0xd801, 0xdcdf, 0xd801, 0xdcdc,
+0xd801, 0xdcdb, 0xd801, 0xdcf2, 0xd801, 0xdcdf, 0xd801, 0xdcf7, 0xd801, 0xdce3, 0x358, 0xd801,
+0xdce4, 0xd801, 0xdcdf, 0x3b, 0xd801, 0xdcc0, 0xd801, 0xdce3, 0x358, 0xd801, 0xdcea, 0x358,
+0xd801, 0xdcec, 0xd801, 0xdcd8, 0x20, 0xd801, 0xdcbf, 0xd801, 0xdcdf, 0xd801, 0xdcdc, 0xd801,
+0xdcdb, 0x3b, 0xd801, 0xdcc0, 0xd801, 0xdce3, 0x358, 0xd801, 0xdcea, 0x358, 0xd801, 0xdcec,
+0xd801, 0xdcd8, 0x20, 0xd801, 0xdcb0, 0xd801, 0xdce7, 0xd801, 0xdce3, 0x20, 0xd801, 0xdccf,
+0xd801, 0xdce3, 0x358, 0xd801, 0xdcf8, 0xd801, 0xdcf2, 0xd801, 0xdce3, 0x3b, 0xd801, 0xdcc0,
+0xd801, 0xdce3, 0x358, 0xd801, 0xdcea, 0x358, 0xd801, 0xdcec, 0xd801, 0xdcd8, 0x20, 0xd801,
+0xdcb0, 0xd801, 0xdce7, 0xd801, 0xdce3, 0x20, 0xd801, 0xdccd, 0xd801, 0xdcea, 0x358, 0xd801,
+0xdcec, 0xd801, 0xdcd8, 0xd801, 0xdcc4, 0xd801, 0xdcd8, 0xd801, 0xdce1, 0xd801, 0xdcdb, 0x358,
+0xd801, 0xdce7, 0xd801, 0xdcdf, 0x3b, 0xd801, 0xdcf5, 0xd801, 0xdcea, 0x358, 0xd801, 0xdcec,
+0xd801, 0xdcd8, 0x3b, 0xd801, 0xdcf5, 0xd801, 0xdcd8, 0xd801, 0xdcdc, 0xd801, 0xdce3, 0x3b,
+0xd801, 0xdcf0, 0xd801, 0xdcea, 0xd801, 0xdcec, 0xd801, 0xdcd8, 0x3b, 0xd801, 0xdcee, 0xd801,
+0xdcd8, 0xd801, 0xdcf0, 0xd801, 0xdcd8, 0x3b, 0xd801, 0xdcef, 0xd801, 0xdcd8, 0xd801, 0xdcec,
+0xd801, 0xdcdf, 0x3b, 0xd801, 0xdcc4, 0xd801, 0xdcdf, 0xd801, 0xdcf5, 0xd801, 0xdcea, 0x358,
+0xd801, 0xdcec, 0xd801, 0xdcd8, 0x3b, 0xd801, 0xdcbc, 0xd801, 0xdce3, 0xd801, 0xdcdf, 0xd801,
+0xdcf0, 0xd801, 0xdcea, 0xd801, 0xdcec, 0xd801, 0xdcd8, 0x3b, 0xd801, 0xdcbf, 0xd801, 0xdcdf,
+0xd801, 0xdcdc, 0xd801, 0xdcdb, 0xd801, 0xdcf2, 0xd801, 0xdcdf, 0xd801, 0xdcf7, 0xd801, 0xdce3,
+0x358, 0xd801, 0xdce4, 0xd801, 0xdcdf, 0x3b, 0xd801, 0xdcbf, 0xd801, 0xdcdf, 0xd801, 0xdcdc,
+0xd801, 0xdcdb, 0x3b, 0xd801, 0xdcb0, 0xd801, 0xdce7, 0xd801, 0xdce3, 0x20, 0xd801, 0xdccf,
+0xd801, 0xdce3, 0x358, 0xd801, 0xdcf8, 0xd801, 0xdcf2, 0xd801, 0xdce3, 0x3b, 0xd801, 0xdcb0,
+0xd801, 0xdce7, 0xd801, 0xdce3, 0x20, 0xd801, 0xdccd, 0xd801, 0xdcea, 0x358, 0xd801, 0xdcec,
+0xd801, 0xdcd8, 0x42f, 0x43d, 0x432, 0x430, 0x440, 0x44c, 0x3b, 0x424, 0x435, 0x432,
+0x440, 0x430, 0x43b, 0x44c, 0x3b, 0x41c, 0x430, 0x440, 0x442, 0x44a, 0x438, 0x3b,
+0x410, 0x43f, 0x440, 0x435, 0x43b, 0x44c, 0x3b, 0x41c, 0x430, 0x439, 0x3b, 0x418,
+0x44e, 0x43d, 0x44c, 0x3b, 0x418, 0x44e, 0x43b, 0x44c, 0x3b, 0x410, 0x432, 0x433,
+0x443, 0x441, 0x442, 0x3b, 0x421, 0x435, 0x43d, 0x442, 0x44f, 0x431, 0x440, 0x44c,
+0x3b, 0x41e, 0x43a, 0x442, 0x44f, 0x431, 0x440, 0x44c, 0x3b, 0x41d, 0x43e, 0x44f,
+0x431, 0x440, 0x44c, 0x3b, 0x414, 0x435, 0x43a, 0x430, 0x431, 0x440, 0x44c, 0x44f,
+0x43d, 0x432, 0x430, 0x440, 0x44b, 0x3b, 0x444, 0x435, 0x432, 0x440, 0x430, 0x43b,
+0x44b, 0x3b, 0x43c, 0x430, 0x440, 0x442, 0x44a, 0x438, 0x439, 0x44b, 0x3b, 0x430,
+0x43f, 0x440, 0x435, 0x43b, 0x44b, 0x3b, 0x43c, 0x430, 0x439, 0x44b, 0x3b, 0x438,
+0x44e, 0x43d, 0x44b, 0x3b, 0x438, 0x44e, 0x43b, 0x44b, 0x3b, 0x430, 0x432, 0x433,
+0x443, 0x441, 0x442, 0x44b, 0x3b, 0x441, 0x435, 0x43d, 0x442, 0x44f, 0x431, 0x440,
+0x44b, 0x3b, 0x43e, 0x43a, 0x442, 0x44f, 0x431, 0x440, 0x44b, 0x3b, 0x43d, 0x43e,
+0x44f, 0x431, 0x440, 0x44b, 0x3b, 0x434, 0x435, 0x43a, 0x430, 0x431, 0x440, 0x44b,
+0x42f, 0x43d, 0x432, 0x2e, 0x3b, 0x424, 0x435, 0x432, 0x440, 0x2e, 0x3b, 0x41c,
+0x430, 0x440, 0x442, 0x2e, 0x3b, 0x410, 0x43f, 0x440, 0x2e, 0x3b, 0x41c, 0x430,
+0x439, 0x3b, 0x418, 0x44e, 0x43d, 0x44c, 0x3b, 0x418, 0x44e, 0x43b, 0x44c, 0x3b,
+0x410, 0x432, 0x433, 0x2e, 0x3b, 0x421, 0x435, 0x43d, 0x442, 0x2e, 0x3b, 0x41e,
+0x43a, 0x442, 0x2e, 0x3b, 0x41d, 0x43e, 0x44f, 0x431, 0x2e, 0x3b, 0x414, 0x435,
+0x43a, 0x2e, 0x44f, 0x43d, 0x432, 0x2e, 0x3b, 0x444, 0x435, 0x432, 0x2e, 0x3b,
+0x43c, 0x430, 0x440, 0x2e, 0x3b, 0x430, 0x43f, 0x440, 0x2e, 0x3b, 0x43c, 0x430,
+0x439, 0x44b, 0x3b, 0x438, 0x44e, 0x43d, 0x44b, 0x3b, 0x438, 0x44e, 0x43b, 0x44b,
+0x3b, 0x430, 0x432, 0x433, 0x2e, 0x3b, 0x441, 0x435, 0x43d, 0x2e, 0x3b, 0x43e,
+0x43a, 0x442, 0x2e, 0x3b, 0x43d, 0x43e, 0x44f, 0x2e, 0x3b, 0x434, 0x435, 0x43a,
+0x2e, 0x59, 0x61, 0x6e, 0xfc, 0x61, 0x72, 0x69, 0x3b, 0x46, 0x65, 0x62,
+0x72, 0xfc, 0x61, 0x72, 0x69, 0x3b, 0x4d, 0x61, 0x72, 0x74, 0x3b, 0x41,
+0x70, 0x72, 0x65, 0x6c, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x59, 0xfc, 0x6e,
+0x69, 0x3b, 0x59, 0xfc, 0x6c, 0x69, 0x3b, 0x4f, 0x75, 0x67, 0xf9, 0x73,
+0x74, 0xf9, 0x73, 0x3b, 0x53, 0xe8, 0x70, 0x74, 0xe8, 0x6d, 0x62, 0x65,
+0x72, 0x3b, 0xd2, 0x6b, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x4e, 0x6f,
+0x76, 0xe8, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x44, 0x65, 0x73, 0xe8, 0x6d,
+0x62, 0x65, 0x72, 0x6a, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d,
+0x61, 0x72, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0x65, 0x69, 0x3b, 0x79,
+0xfc, 0x6e, 0x3b, 0x79, 0xfc, 0x6c, 0x3b, 0x6f, 0x75, 0x67, 0x3b, 0x73,
+0xe8, 0x70, 0x3b, 0xf2, 0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64,
+0x65, 0x73, 0x59, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61,
+0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x59, 0xfc,
+0x6e, 0x3b, 0x59, 0xfc, 0x6c, 0x3b, 0x4f, 0x75, 0x67, 0x3b, 0x53, 0xe8,
+0x70, 0x3b, 0xd2, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65,
+0x73, 0x62c, 0x646, 0x648, 0x631, 0x64a, 0x3b, 0x641, 0x6d0, 0x628, 0x631, 0x648,
+0x631, 0x64a, 0x3b, 0x645, 0x627, 0x631, 0x686, 0x3b, 0x627, 0x67e, 0x631, 0x6cc,
+0x644, 0x3b, 0x645, 0x6cd, 0x3b, 0x62c, 0x648, 0x646, 0x3b, 0x62c, 0x648, 0x644,
+0x627, 0x6cc, 0x3b, 0x627, 0x6ab, 0x633, 0x62a, 0x3b, 0x633, 0x67e, 0x62a, 0x645,
+0x628, 0x631, 0x3b, 0x627, 0x6a9, 0x62a, 0x648, 0x628, 0x631, 0x3b, 0x646, 0x648,
+0x645, 0x628, 0x631, 0x3b, 0x62f, 0x633, 0x645, 0x628, 0x631, 0x62c, 0x646, 0x648,
+0x631, 0x64a, 0x3b, 0x641, 0x628, 0x631, 0x648, 0x631, 0x64a, 0x3b, 0x645, 0x627,
+0x631, 0x686, 0x3b, 0x627, 0x67e, 0x631, 0x6cc, 0x644, 0x3b, 0x645, 0x6cd, 0x3b,
+0x62c, 0x648, 0x646, 0x3b, 0x62c, 0x648, 0x644, 0x627, 0x6cc, 0x3b, 0x627, 0x6ab,
+0x633, 0x62a, 0x3b, 0x633, 0x6d0, 0x67e, 0x62a, 0x645, 0x628, 0x631, 0x3b, 0x627,
+0x6a9, 0x62a, 0x648, 0x628, 0x631, 0x3b, 0x646, 0x648, 0x645, 0x628, 0x631, 0x3b,
+0x62f, 0x633, 0x645, 0x628, 0x631, 0x62c, 0x646, 0x648, 0x631, 0x64a, 0x3b, 0x641,
+0x628, 0x631, 0x648, 0x631, 0x64a, 0x3b, 0x645, 0x627, 0x631, 0x686, 0x3b, 0x627,
+0x67e, 0x631, 0x6cc, 0x644, 0x3b, 0x645, 0x6cd, 0x3b, 0x62c, 0x648, 0x646, 0x3b,
+0x62c, 0x648, 0x644, 0x627, 0x6cc, 0x3b, 0x627, 0x6ab, 0x633, 0x62a, 0x3b, 0x633,
+0x67e, 0x62a, 0x645, 0x628, 0x631, 0x3b, 0x627, 0x6a9, 0x62a, 0x648, 0x628, 0x631,
+0x3b, 0x646, 0x648, 0x645, 0x628, 0x631, 0x3b, 0x62f, 0x633, 0x645, 0x628, 0x631,
+0x62c, 0x3b, 0x641, 0x3b, 0x645, 0x3b, 0x627, 0x3b, 0x645, 0x3b, 0x62c, 0x3b,
+0x62c, 0x3b, 0x627, 0x3b, 0x633, 0x3b, 0x627, 0x3b, 0x646, 0x3b, 0x62f, 0x698,
+0x627, 0x646, 0x648, 0x6cc, 0x647, 0x654, 0x3b, 0x641, 0x648, 0x631, 0x6cc, 0x647,
+0x654, 0x3b, 0x645, 0x627, 0x631, 0x633, 0x3b, 0x622, 0x648, 0x631, 0x6cc, 0x644,
+0x3b, 0x645, 0x647, 0x654, 0x3b, 0x698, 0x648, 0x626, 0x646, 0x3b, 0x698, 0x648,
+0x626, 0x6cc, 0x647, 0x654, 0x3b, 0x627, 0x648, 0x62a, 0x3b, 0x633, 0x67e, 0x62a,
+0x627, 0x645, 0x628, 0x631, 0x3b, 0x627, 0x6a9, 0x62a, 0x628, 0x631, 0x3b, 0x646,
+0x648, 0x627, 0x645, 0x628, 0x631, 0x3b, 0x62f, 0x633, 0x627, 0x645, 0x628, 0x631,
+0x698, 0x3b, 0x641, 0x3b, 0x645, 0x3b, 0x622, 0x3b, 0x645, 0x3b, 0x698, 0x3b,
+0x698, 0x3b, 0x627, 0x3b, 0x633, 0x3b, 0x627, 0x3b, 0x646, 0x3b, 0x62f, 0x62c,
+0x646, 0x648, 0x631, 0x6cc, 0x3b, 0x641, 0x628, 0x631, 0x648, 0x631, 0x6cc, 0x3b,
+0x645, 0x627, 0x631, 0x686, 0x3b, 0x627, 0x67e, 0x631, 0x6cc, 0x644, 0x3b, 0x645,
+0x6cc, 0x3b, 0x62c, 0x648, 0x646, 0x3b, 0x62c, 0x648, 0x644, 0x627, 0x6cc, 0x3b,
+0x627, 0x6af, 0x633, 0x62a, 0x3b, 0x633, 0x67e, 0x62a, 0x645, 0x628, 0x631, 0x3b,
+0x627, 0x6a9, 0x62a, 0x648, 0x628, 0x631, 0x3b, 0x646, 0x648, 0x645, 0x628, 0x631,
+0x3b, 0x62f, 0x633, 0x645, 0x628, 0x631, 0x62c, 0x646, 0x648, 0x3b, 0x641, 0x628,
+0x631, 0x648, 0x631, 0x6cc, 0x3b, 0x645, 0x627, 0x631, 0x686, 0x3b, 0x627, 0x67e,
+0x631, 0x6cc, 0x644, 0x3b, 0x645, 0x6cc, 0x3b, 0x62c, 0x648, 0x646, 0x3b, 0x62c,
+0x648, 0x644, 0x3b, 0x627, 0x6af, 0x633, 0x62a, 0x3b, 0x633, 0x67e, 0x62a, 0x645,
+0x628, 0x631, 0x3b, 0x627, 0x6a9, 0x62a, 0x648, 0x628, 0x631, 0x3b, 0x646, 0x648,
+0x645, 0x628, 0x631, 0x3b, 0x62f, 0x633, 0x645, 0x73, 0x74, 0x79, 0x63, 0x7a,
+0x65, 0x144, 0x3b, 0x6c, 0x75, 0x74, 0x79, 0x3b, 0x6d, 0x61, 0x72, 0x7a,
+0x65, 0x63, 0x3b, 0x6b, 0x77, 0x69, 0x65, 0x63, 0x69, 0x65, 0x144, 0x3b,
+0x6d, 0x61, 0x6a, 0x3b, 0x63, 0x7a, 0x65, 0x72, 0x77, 0x69, 0x65, 0x63,
+0x3b, 0x6c, 0x69, 0x70, 0x69, 0x65, 0x63, 0x3b, 0x73, 0x69, 0x65, 0x72,
+0x70, 0x69, 0x65, 0x144, 0x3b, 0x77, 0x72, 0x7a, 0x65, 0x73, 0x69, 0x65,
+0x144, 0x3b, 0x70, 0x61, 0x17a, 0x64, 0x7a, 0x69, 0x65, 0x72, 0x6e, 0x69,
+0x6b, 0x3b, 0x6c, 0x69, 0x73, 0x74, 0x6f, 0x70, 0x61, 0x64, 0x3b, 0x67,
+0x72, 0x75, 0x64, 0x7a, 0x69, 0x65, 0x144, 0x73, 0x74, 0x79, 0x63, 0x7a,
+0x6e, 0x69, 0x61, 0x3b, 0x6c, 0x75, 0x74, 0x65, 0x67, 0x6f, 0x3b, 0x6d,
+0x61, 0x72, 0x63, 0x61, 0x3b, 0x6b, 0x77, 0x69, 0x65, 0x74, 0x6e, 0x69,
+0x61, 0x3b, 0x6d, 0x61, 0x6a, 0x61, 0x3b, 0x63, 0x7a, 0x65, 0x72, 0x77,
+0x63, 0x61, 0x3b, 0x6c, 0x69, 0x70, 0x63, 0x61, 0x3b, 0x73, 0x69, 0x65,
+0x72, 0x70, 0x6e, 0x69, 0x61, 0x3b, 0x77, 0x72, 0x7a, 0x65, 0x15b, 0x6e,
+0x69, 0x61, 0x3b, 0x70, 0x61, 0x17a, 0x64, 0x7a, 0x69, 0x65, 0x72, 0x6e,
+0x69, 0x6b, 0x61, 0x3b, 0x6c, 0x69, 0x73, 0x74, 0x6f, 0x70, 0x61, 0x64,
+0x61, 0x3b, 0x67, 0x72, 0x75, 0x64, 0x6e, 0x69, 0x61, 0x73, 0x74, 0x79,
+0x3b, 0x6c, 0x75, 0x74, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x6b, 0x77, 0x69,
+0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x63, 0x7a, 0x65, 0x3b, 0x6c, 0x69, 0x70,
+0x3b, 0x73, 0x69, 0x65, 0x3b, 0x77, 0x72, 0x7a, 0x3b, 0x70, 0x61, 0x17a,
+0x3b, 0x6c, 0x69, 0x73, 0x3b, 0x67, 0x72, 0x75, 0x53, 0x3b, 0x4c, 0x3b,
+0x4d, 0x3b, 0x4b, 0x3b, 0x4d, 0x3b, 0x43, 0x3b, 0x4c, 0x3b, 0x53, 0x3b,
+0x57, 0x3b, 0x50, 0x3b, 0x4c, 0x3b, 0x47, 0x73, 0x3b, 0x6c, 0x3b, 0x6d,
+0x3b, 0x6b, 0x3b, 0x6d, 0x3b, 0x63, 0x3b, 0x6c, 0x3b, 0x73, 0x3b, 0x77,
+0x3b, 0x70, 0x3b, 0x6c, 0x3b, 0x67, 0x6a, 0x61, 0x6e, 0x65, 0x69, 0x72,
+0x6f, 0x3b, 0x66, 0x65, 0x76, 0x65, 0x72, 0x65, 0x69, 0x72, 0x6f, 0x3b,
+0x6d, 0x61, 0x72, 0xe7, 0x6f, 0x3b, 0x61, 0x62, 0x72, 0x69, 0x6c, 0x3b,
+0x6d, 0x61, 0x69, 0x6f, 0x3b, 0x6a, 0x75, 0x6e, 0x68, 0x6f, 0x3b, 0x6a,
+0x75, 0x6c, 0x68, 0x6f, 0x3b, 0x61, 0x67, 0x6f, 0x73, 0x74, 0x6f, 0x3b,
+0x73, 0x65, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x6f, 0x3b, 0x6f, 0x75, 0x74,
+0x75, 0x62, 0x72, 0x6f, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72,
+0x6f, 0x3b, 0x64, 0x65, 0x7a, 0x65, 0x6d, 0x62, 0x72, 0x6f, 0x6a, 0x61,
+0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x76, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e,
+0x3b, 0x61, 0x62, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x69, 0x2e, 0x3b, 0x6a,
+0x75, 0x6e, 0x2e, 0x3b, 0x6a, 0x75, 0x6c, 0x2e, 0x3b, 0x61, 0x67, 0x6f,
+0x2e, 0x3b, 0x73, 0x65, 0x74, 0x2e, 0x3b, 0x6f, 0x75, 0x74, 0x2e, 0x3b,
+0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x7a, 0x2e, 0x72, 0x61, 0x67,
+0x73, 0x3b, 0x77, 0x61, 0x73, 0x73, 0x61, 0x72, 0x69, 0x6e, 0x73, 0x3b,
+0x70, 0x16b, 0x6c, 0x69, 0x73, 0x3b, 0x73, 0x61, 0x6b, 0x6b, 0x69, 0x73,
+0x3b, 0x7a, 0x61, 0x6c, 0x6c, 0x61, 0x77, 0x73, 0x3b, 0x73, 0x12b, 0x6d,
+0x65, 0x6e, 0x69, 0x73, 0x3b, 0x6c, 0x12b, 0x70, 0x61, 0x3b, 0x64, 0x61,
+0x67, 0x67, 0x69, 0x73, 0x3b, 0x73, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x73,
+0x3b, 0x73, 0x70, 0x61, 0x6c, 0x6c, 0x69, 0x6e, 0x73, 0x3b, 0x6c, 0x61,
+0x70, 0x6b, 0x72, 0x16b, 0x74, 0x69, 0x73, 0x3b, 0x73, 0x61, 0x6c, 0x6c,
+0x61, 0x77, 0x73, 0x72, 0x61, 0x67, 0x3b, 0x77, 0x61, 0x73, 0x3b, 0x70,
+0x16b, 0x6c, 0x3b, 0x73, 0x61, 0x6b, 0x3b, 0x7a, 0x61, 0x6c, 0x3b, 0x73,
+0x12b, 0x6d, 0x3b, 0x6c, 0x12b, 0x70, 0x3b, 0x64, 0x61, 0x67, 0x3b, 0x73,
+0x69, 0x6c, 0x3b, 0x73, 0x70, 0x61, 0x3b, 0x6c, 0x61, 0x70, 0x3b, 0x73,
+0x61, 0x6c, 0x52, 0x3b, 0x57, 0x3b, 0x50, 0x3b, 0x53, 0x3b, 0x5a, 0x3b,
+0x53, 0x3b, 0x4c, 0x3b, 0x44, 0x3b, 0x53, 0x3b, 0x53, 0x3b, 0x4c, 0x3b,
+0x53, 0xa1c, 0xa28, 0xa35, 0xa30, 0xa40, 0x3b, 0xa2b, 0xa3c, 0xa30, 0xa35, 0xa30,
+0xa40, 0x3b, 0xa2e, 0xa3e, 0xa30, 0xa1a, 0x3b, 0xa05, 0xa2a, 0xa4d, 0xa30, 0xa48,
+0xa32, 0x3b, 0xa2e, 0xa08, 0x3b, 0xa1c, 0xa42, 0xa28, 0x3b, 0xa1c, 0xa41, 0xa32,
+0xa3e, 0xa08, 0x3b, 0xa05, 0xa17, 0xa38, 0xa24, 0x3b, 0xa38, 0xa24, 0xa70, 0xa2c,
+0xa30, 0x3b, 0xa05, 0xa15, 0xa24, 0xa42, 0xa2c, 0xa30, 0x3b, 0xa28, 0xa35, 0xa70,
+0xa2c, 0xa30, 0x3b, 0xa26, 0xa38, 0xa70, 0xa2c, 0xa30, 0xa1c, 0xa28, 0x3b, 0xa2b,
+0xa3c, 0xa30, 0x3b, 0xa2e, 0xa3e, 0xa30, 0xa1a, 0x3b, 0xa05, 0xa2a, 0xa4d, 0xa30,
+0xa48, 0x3b, 0xa2e, 0xa08, 0x3b, 0xa1c, 0xa42, 0xa28, 0x3b, 0xa1c, 0xa41, 0xa32,
+0xa3e, 0x3b, 0xa05, 0xa17, 0x3b, 0xa38, 0xa24, 0xa70, 0x3b, 0xa05, 0xa15, 0xa24,
+0xa42, 0x3b, 0xa28, 0xa35, 0xa70, 0x3b, 0xa26, 0xa38, 0xa70, 0xa1c, 0x3b, 0xa2b,
+0xa3c, 0x3b, 0xa2e, 0xa3e, 0x3b, 0xa05, 0x3b, 0xa2e, 0x3b, 0xa1c, 0xa42, 0x3b,
+0xa1c, 0xa41, 0x3b, 0xa05, 0x3b, 0xa38, 0x3b, 0xa05, 0x3b, 0xa28, 0x3b, 0xa26,
+0x62c, 0x646, 0x648, 0x631, 0x6cc, 0x3b, 0x641, 0x631, 0x648, 0x631, 0x6cc, 0x3b,
+0x645, 0x627, 0x631, 0x686, 0x3b, 0x627, 0x67e, 0x631, 0x6cc, 0x644, 0x3b, 0x645,
+0x626, 0x3b, 0x62c, 0x648, 0x646, 0x3b, 0x62c, 0x648, 0x644, 0x627, 0x626, 0x6cc,
+0x3b, 0x627, 0x6af, 0x633, 0x62a, 0x3b, 0x633, 0x62a, 0x645, 0x628, 0x631, 0x3b,
+0x627, 0x6a9, 0x62a, 0x648, 0x628, 0x631, 0x3b, 0x646, 0x648, 0x645, 0x628, 0x631,
+0x3b, 0x62f, 0x633, 0x645, 0x628, 0x631, 0x45, 0x6e, 0x65, 0x72, 0x6f, 0x3b,
+0x46, 0x65, 0x62, 0x72, 0x65, 0x72, 0x6f, 0x3b, 0x4d, 0x61, 0x72, 0x7a,
+0x6f, 0x3b, 0x41, 0x62, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x61, 0x79, 0x6f,
+0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x6f, 0x3b, 0x4a, 0x75, 0x6c, 0x69, 0x6f,
+0x3b, 0x41, 0x67, 0x6f, 0x73, 0x74, 0x6f, 0x3b, 0x53, 0x65, 0x74, 0x69,
+0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x4f, 0x63, 0x74, 0x75, 0x62, 0x72,
+0x65, 0x3b, 0x4e, 0x6f, 0x76, 0x69, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b,
+0x44, 0x69, 0x63, 0x69, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x45, 0x6e, 0x65,
+0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x62, 0x72,
+0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c,
+0x3b, 0x41, 0x67, 0x6f, 0x3b, 0x53, 0x65, 0x74, 0x3b, 0x4f, 0x63, 0x74,
+0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x69, 0x63, 0x69, 0x61, 0x6e, 0x75,
+0x61, 0x72, 0x69, 0x65, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72,
+0x69, 0x65, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x69, 0x65, 0x3b, 0x61, 0x70,
+0x72, 0x69, 0x6c, 0x69, 0x65, 0x3b, 0x6d, 0x61, 0x69, 0x3b, 0x69, 0x75,
+0x6e, 0x69, 0x65, 0x3b, 0x69, 0x75, 0x6c, 0x69, 0x65, 0x3b, 0x61, 0x75,
+0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62,
+0x72, 0x69, 0x65, 0x3b, 0x6f, 0x63, 0x74, 0x6f, 0x6d, 0x62, 0x72, 0x69,
+0x65, 0x3b, 0x6e, 0x6f, 0x69, 0x65, 0x6d, 0x62, 0x72, 0x69, 0x65, 0x3b,
+0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x72, 0x69, 0x65, 0x69, 0x61, 0x6e,
+0x2e, 0x3b, 0x66, 0x65, 0x62, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b,
+0x61, 0x70, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x69, 0x3b, 0x69, 0x75, 0x6e,
+0x2e, 0x3b, 0x69, 0x75, 0x6c, 0x2e, 0x3b, 0x61, 0x75, 0x67, 0x2e, 0x3b,
+0x73, 0x65, 0x70, 0x74, 0x2e, 0x3b, 0x6f, 0x63, 0x74, 0x2e, 0x3b, 0x6e,
+0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x63, 0x2e, 0x49, 0x3b, 0x46, 0x3b,
+0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x49, 0x3b, 0x49, 0x3b, 0x41, 0x3b,
+0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x73, 0x63, 0x68, 0x61, 0x6e,
+0x65, 0x72, 0x3b, 0x66, 0x61, 0x76, 0x72, 0x65, 0x72, 0x3b, 0x6d, 0x61,
+0x72, 0x73, 0x3b, 0x61, 0x76, 0x72, 0x69, 0x67, 0x6c, 0x3b, 0x6d, 0x61,
+0x74, 0x67, 0x3b, 0x7a, 0x65, 0x72, 0x63, 0x6c, 0x61, 0x64, 0x75, 0x72,
+0x3b, 0x66, 0x61, 0x6e, 0x61, 0x64, 0x75, 0x72, 0x3b, 0x61, 0x76, 0x75,
+0x73, 0x74, 0x3b, 0x73, 0x65, 0x74, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72,
+0x3b, 0x6f, 0x63, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x6e, 0x6f, 0x76,
+0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62,
+0x65, 0x72, 0x64, 0x61, 0x20, 0x73, 0x63, 0x68, 0x61, 0x6e, 0x65, 0x72,
+0x3b, 0x64, 0x61, 0x20, 0x66, 0x61, 0x76, 0x72, 0x65, 0x72, 0x3b, 0x64,
+0x61, 0x20, 0x6d, 0x61, 0x72, 0x73, 0x3b, 0x64, 0x2019, 0x61, 0x76, 0x72,
+0x69, 0x67, 0x6c, 0x3b, 0x64, 0x61, 0x20, 0x6d, 0x61, 0x74, 0x67, 0x3b,
+0x64, 0x61, 0x20, 0x7a, 0x65, 0x72, 0x63, 0x6c, 0x61, 0x64, 0x75, 0x72,
+0x3b, 0x64, 0x61, 0x20, 0x66, 0x61, 0x6e, 0x61, 0x64, 0x75, 0x72, 0x3b,
+0x64, 0x2019, 0x61, 0x76, 0x75, 0x73, 0x74, 0x3b, 0x64, 0x61, 0x20, 0x73,
+0x65, 0x74, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x64, 0x2019, 0x6f,
+0x63, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x64, 0x61, 0x20, 0x6e, 0x6f,
+0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x64, 0x61, 0x20, 0x64, 0x65,
+0x63, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x63, 0x68, 0x61, 0x6e, 0x2e,
+0x3b, 0x66, 0x61, 0x76, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x3b,
+0x61, 0x76, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x74, 0x67, 0x3b, 0x7a, 0x65,
+0x72, 0x63, 0x6c, 0x2e, 0x3b, 0x66, 0x61, 0x6e, 0x2e, 0x3b, 0x61, 0x76,
+0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x74, 0x74, 0x2e, 0x3b, 0x6f, 0x63,
+0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x63, 0x2e,
+0x53, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x5a, 0x3b,
+0x46, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x4d,
+0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x77, 0x61, 0x6e,
+0x7a, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20,
+0x6b, 0x61, 0x69, 0x6c, 0x69, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20,
+0x77, 0x61, 0x20, 0x6b, 0x61, 0x74, 0x61, 0x74, 0x75, 0x3b, 0x4d, 0x77,
+0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x61, 0x6e, 0x61,
+0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x74, 0x61,
+0x6e, 0x75, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20,
+0x73, 0x69, 0x74, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77,
+0x61, 0x20, 0x73, 0x61, 0x62, 0x61, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69,
+0x20, 0x77, 0x61, 0x20, 0x6e, 0x61, 0x6e, 0x65, 0x3b, 0x4d, 0x77, 0x65,
+0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x74, 0x69, 0x73, 0x61, 0x3b, 0x4d,
+0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x69, 0x6b, 0x75, 0x6d,
+0x69, 0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x69,
+0x6b, 0x75, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x6d, 0x6f, 0x6a, 0x61,
+0x3b, 0x4d, 0x77, 0x65, 0x72, 0x69, 0x20, 0x77, 0x61, 0x20, 0x69, 0x6b,
+0x75, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x6d, 0x62, 0x69, 0x6c, 0x69,
+0x4d, 0x31, 0x3b, 0x4d, 0x32, 0x3b, 0x4d, 0x33, 0x3b, 0x4d, 0x34, 0x3b,
+0x4d, 0x35, 0x3b, 0x4d, 0x36, 0x3b, 0x4d, 0x37, 0x3b, 0x4d, 0x38, 0x3b,
+0x4d, 0x39, 0x3b, 0x4d, 0x31, 0x30, 0x3b, 0x4d, 0x31, 0x31, 0x3b, 0x4d,
+0x31, 0x32, 0x4b, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x54, 0x3b,
+0x53, 0x3b, 0x53, 0x3b, 0x4e, 0x3b, 0x54, 0x3b, 0x49, 0x3b, 0x49, 0x3b,
+0x49, 0x4e, 0x7a, 0x65, 0x72, 0x6f, 0x3b, 0x52, 0x75, 0x68, 0x75, 0x68,
+0x75, 0x6d, 0x61, 0x3b, 0x4e, 0x74, 0x77, 0x61, 0x72, 0x61, 0x6e, 0x74,
+0x65, 0x3b, 0x4e, 0x64, 0x61, 0x6d, 0x75, 0x6b, 0x69, 0x7a, 0x61, 0x3b,
+0x52, 0x75, 0x73, 0x61, 0x6d, 0x61, 0x3b, 0x52, 0x75, 0x68, 0x65, 0x73,
+0x68, 0x69, 0x3b, 0x4d, 0x75, 0x6b, 0x61, 0x6b, 0x61, 0x72, 0x6f, 0x3b,
+0x4e, 0x79, 0x61, 0x6e, 0x64, 0x61, 0x67, 0x61, 0x72, 0x6f, 0x3b, 0x4e,
+0x79, 0x61, 0x6b, 0x61, 0x6e, 0x67, 0x61, 0x3b, 0x47, 0x69, 0x74, 0x75,
+0x67, 0x75, 0x74, 0x75, 0x3b, 0x4d, 0x75, 0x6e, 0x79, 0x6f, 0x6e, 0x79,
+0x6f, 0x3b, 0x4b, 0x69, 0x67, 0x61, 0x72, 0x61, 0x6d, 0x61, 0x4d, 0x75,
+0x74, 0x2e, 0x3b, 0x47, 0x61, 0x73, 0x2e, 0x3b, 0x57, 0x65, 0x72, 0x2e,
+0x3b, 0x4d, 0x61, 0x74, 0x2e, 0x3b, 0x47, 0x69, 0x63, 0x2e, 0x3b, 0x4b,
+0x61, 0x6d, 0x2e, 0x3b, 0x4e, 0x79, 0x61, 0x2e, 0x3b, 0x4b, 0x61, 0x6e,
+0x2e, 0x3b, 0x4e, 0x7a, 0x65, 0x2e, 0x3b, 0x55, 0x6b, 0x77, 0x2e, 0x3b,
+0x55, 0x67, 0x75, 0x2e, 0x3b, 0x55, 0x6b, 0x75, 0x2e, 0x44f, 0x43d, 0x432,
+0x430, 0x440, 0x44f, 0x3b, 0x444, 0x435, 0x432, 0x440, 0x430, 0x43b, 0x44f, 0x3b,
+0x43c, 0x430, 0x440, 0x442, 0x430, 0x3b, 0x430, 0x43f, 0x440, 0x435, 0x43b, 0x44f,
+0x3b, 0x43c, 0x430, 0x44f, 0x3b, 0x438, 0x44e, 0x43d, 0x44f, 0x3b, 0x438, 0x44e,
+0x43b, 0x44f, 0x3b, 0x430, 0x432, 0x433, 0x443, 0x441, 0x442, 0x430, 0x3b, 0x441,
+0x435, 0x43d, 0x442, 0x44f, 0x431, 0x440, 0x44f, 0x3b, 0x43e, 0x43a, 0x442, 0x44f,
+0x431, 0x440, 0x44f, 0x3b, 0x43d, 0x43e, 0x44f, 0x431, 0x440, 0x44f, 0x3b, 0x434,
+0x435, 0x43a, 0x430, 0x431, 0x440, 0x44f, 0x44f, 0x43d, 0x432, 0x2e, 0x3b, 0x444,
+0x435, 0x432, 0x440, 0x2e, 0x3b, 0x43c, 0x430, 0x440, 0x442, 0x3b, 0x430, 0x43f,
+0x440, 0x2e, 0x3b, 0x43c, 0x430, 0x439, 0x3b, 0x438, 0x44e, 0x43d, 0x44c, 0x3b,
+0x438, 0x44e, 0x43b, 0x44c, 0x3b, 0x430, 0x432, 0x433, 0x2e, 0x3b, 0x441, 0x435,
+0x43d, 0x442, 0x2e, 0x3b, 0x43e, 0x43a, 0x442, 0x2e, 0x3b, 0x43d, 0x43e, 0x44f,
+0x431, 0x2e, 0x3b, 0x434, 0x435, 0x43a, 0x2e, 0x44f, 0x43d, 0x432, 0x2e, 0x3b,
+0x444, 0x435, 0x432, 0x440, 0x2e, 0x3b, 0x43c, 0x430, 0x440, 0x2e, 0x3b, 0x430,
+0x43f, 0x440, 0x2e, 0x3b, 0x43c, 0x430, 0x44f, 0x3b, 0x438, 0x44e, 0x43d, 0x2e,
+0x3b, 0x438, 0x44e, 0x43b, 0x2e, 0x3b, 0x430, 0x432, 0x433, 0x2e, 0x3b, 0x441,
+0x435, 0x43d, 0x442, 0x2e, 0x3b, 0x43e, 0x43a, 0x442, 0x2e, 0x3b, 0x43d, 0x43e,
+0x44f, 0x431, 0x2e, 0x3b, 0x434, 0x435, 0x43a, 0x2e, 0x442, 0x43e, 0x445, 0x441,
+0x443, 0x43d, 0x43d, 0x44c, 0x443, 0x3b, 0x43e, 0x43b, 0x443, 0x43d, 0x43d, 0x44c,
+0x443, 0x3b, 0x43a, 0x443, 0x43b, 0x443, 0x43d, 0x20, 0x442, 0x443, 0x442, 0x430,
+0x440, 0x3b, 0x43c, 0x443, 0x443, 0x441, 0x20, 0x443, 0x441, 0x442, 0x430, 0x440,
+0x3b, 0x44b, 0x430, 0x43c, 0x20, 0x44b, 0x439, 0x430, 0x3b, 0x431, 0x44d, 0x441,
+0x20, 0x44b, 0x439, 0x430, 0x3b, 0x43e, 0x442, 0x20, 0x44b, 0x439, 0x430, 0x3b,
+0x430, 0x442, 0x44b, 0x440, 0x434, 0x44c, 0x44b, 0x445, 0x20, 0x44b, 0x439, 0x430,
+0x3b, 0x431, 0x430, 0x43b, 0x430, 0x495, 0x430, 0x43d, 0x20, 0x44b, 0x439, 0x430,
+0x3b, 0x430, 0x43b, 0x442, 0x44b, 0x43d, 0x43d, 0x44c, 0x44b, 0x3b, 0x441, 0x44d,
+0x442, 0x438, 0x43d, 0x43d, 0x44c, 0x438, 0x3b, 0x430, 0x445, 0x441, 0x44b, 0x43d,
+0x43d, 0x44c, 0x44b, 0x422, 0x43e, 0x445, 0x441, 0x443, 0x43d, 0x43d, 0x44c, 0x443,
+0x3b, 0x41e, 0x43b, 0x443, 0x43d, 0x43d, 0x44c, 0x443, 0x3b, 0x41a, 0x443, 0x43b,
+0x443, 0x43d, 0x20, 0x442, 0x443, 0x442, 0x430, 0x440, 0x3b, 0x41c, 0x443, 0x443,
+0x441, 0x20, 0x443, 0x441, 0x442, 0x430, 0x440, 0x3b, 0x42b, 0x430, 0x43c, 0x20,
+0x44b, 0x439, 0x44b, 0x43d, 0x3b, 0x411, 0x44d, 0x441, 0x20, 0x44b, 0x439, 0x44b,
+0x43d, 0x3b, 0x41e, 0x442, 0x20, 0x44b, 0x439, 0x44b, 0x43d, 0x3b, 0x410, 0x442,
+0x44b, 0x440, 0x434, 0x44c, 0x44b, 0x445, 0x20, 0x44b, 0x439, 0x44b, 0x43d, 0x3b,
+0x411, 0x430, 0x43b, 0x430, 0x495, 0x430, 0x43d, 0x20, 0x44b, 0x439, 0x44b, 0x43d,
+0x3b, 0x410, 0x43b, 0x442, 0x44b, 0x43d, 0x43d, 0x44c, 0x44b, 0x3b, 0x421, 0x44d,
+0x442, 0x438, 0x43d, 0x43d, 0x44c, 0x438, 0x3b, 0x430, 0x445, 0x441, 0x44b, 0x43d,
+0x43d, 0x44c, 0x44b, 0x422, 0x43e, 0x445, 0x441, 0x3b, 0x41e, 0x43b, 0x443, 0x43d,
+0x3b, 0x41a, 0x43b, 0x43d, 0x3b, 0x41c, 0x441, 0x443, 0x3b, 0x42b, 0x430, 0x43c,
+0x3b, 0x411, 0x44d, 0x441, 0x3b, 0x41e, 0x442, 0x439, 0x3b, 0x410, 0x442, 0x440,
+0x3b, 0x411, 0x43b, 0x495, 0x3b, 0x410, 0x43b, 0x442, 0x3b, 0x421, 0x44d, 0x442,
+0x3b, 0x410, 0x445, 0x441, 0x422, 0x3b, 0x41e, 0x3b, 0x41a, 0x3b, 0x41c, 0x3b,
+0x42b, 0x3b, 0x411, 0x3b, 0x41e, 0x3b, 0x410, 0x3b, 0x411, 0x3b, 0x410, 0x3b,
+0x421, 0x3b, 0x410, 0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c, 0x65, 0x20, 0x6f,
+0x62, 0x6f, 0x3b, 0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c, 0x65, 0x20, 0x77,
+0x61, 0x61, 0x72, 0x65, 0x3b, 0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c, 0x65,
+0x20, 0x6f, 0x6b, 0x75, 0x6e, 0x69, 0x3b, 0x4c, 0x61, 0x70, 0x61, 0x20,
+0x6c, 0x65, 0x20, 0x6f, 0x6e, 0x67, 0x2019, 0x77, 0x61, 0x6e, 0x3b, 0x4c,
+0x61, 0x70, 0x61, 0x20, 0x6c, 0x65, 0x20, 0x69, 0x6d, 0x65, 0x74, 0x3b,
+0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c, 0x65, 0x20, 0x69, 0x6c, 0x65, 0x3b,
+0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c, 0x65, 0x20, 0x73, 0x61, 0x70, 0x61,
+0x3b, 0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c, 0x65, 0x20, 0x69, 0x73, 0x69,
+0x65, 0x74, 0x3b, 0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c, 0x65, 0x20, 0x73,
+0x61, 0x61, 0x6c, 0x3b, 0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c, 0x65, 0x20,
+0x74, 0x6f, 0x6d, 0x6f, 0x6e, 0x3b, 0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c,
+0x65, 0x20, 0x74, 0x6f, 0x6d, 0x6f, 0x6e, 0x20, 0x6f, 0x62, 0x6f, 0x3b,
+0x4c, 0x61, 0x70, 0x61, 0x20, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x6d, 0x6f,
+0x6e, 0x20, 0x77, 0x61, 0x61, 0x72, 0x65, 0x4f, 0x62, 0x6f, 0x3b, 0x57,
+0x61, 0x61, 0x3b, 0x4f, 0x6b, 0x75, 0x3b, 0x4f, 0x6e, 0x67, 0x3b, 0x49,
+0x6d, 0x65, 0x3b, 0x49, 0x6c, 0x65, 0x3b, 0x53, 0x61, 0x70, 0x3b, 0x49,
+0x73, 0x69, 0x3b, 0x53, 0x61, 0x61, 0x3b, 0x54, 0x6f, 0x6d, 0x3b, 0x54,
+0x6f, 0x62, 0x3b, 0x54, 0x6f, 0x77, 0x4f, 0x3b, 0x57, 0x3b, 0x4f, 0x3b,
+0x4f, 0x3b, 0x49, 0x3b, 0x49, 0x3b, 0x53, 0x3b, 0x49, 0x3b, 0x53, 0x3b,
+0x54, 0x3b, 0x54, 0x3b, 0x54, 0x4e, 0x79, 0x65, 0x6e, 0x79, 0x65, 0x3b,
+0x46, 0x75, 0x6c, 0x75, 0x6e, 0x64, 0xef, 0x67, 0x69, 0x3b, 0x4d, 0x62,
+0xe4, 0x6e, 0x67, 0xfc, 0x3b, 0x4e, 0x67, 0x75, 0x62, 0xf9, 0x65, 0x3b,
+0x42, 0xea, 0x6c, 0xe4, 0x77, 0xfc, 0x3b, 0x46, 0xf6, 0x6e, 0x64, 0x6f,
+0x3b, 0x4c, 0x65, 0x6e, 0x67, 0x75, 0x61, 0x3b, 0x4b, 0xfc, 0x6b, 0xfc,
+0x72, 0xfc, 0x3b, 0x4d, 0x76, 0x75, 0x6b, 0x61, 0x3b, 0x4e, 0x67, 0x62,
+0x65, 0x72, 0x65, 0x72, 0x65, 0x3b, 0x4e, 0x61, 0x62, 0xe4, 0x6e, 0x64,
+0xfc, 0x72, 0x75, 0x3b, 0x4b, 0x61, 0x6b, 0x61, 0x75, 0x6b, 0x61, 0x4e,
+0x79, 0x65, 0x3b, 0x46, 0x75, 0x6c, 0x3b, 0x4d, 0x62, 0xe4, 0x3b, 0x4e,
+0x67, 0x75, 0x3b, 0x42, 0xea, 0x6c, 0x3b, 0x46, 0xf6, 0x6e, 0x3b, 0x4c,
+0x65, 0x6e, 0x3b, 0x4b, 0xfc, 0x6b, 0x3b, 0x4d, 0x76, 0x75, 0x3b, 0x4e,
+0x67, 0x62, 0x3b, 0x4e, 0x61, 0x62, 0x3b, 0x4b, 0x61, 0x6b, 0x4e, 0x3b,
+0x46, 0x3b, 0x4d, 0x3b, 0x4e, 0x3b, 0x42, 0x3b, 0x46, 0x3b, 0x4c, 0x3b,
+0x4b, 0x3b, 0x4d, 0x3b, 0x4e, 0x3b, 0x4e, 0x3b, 0x4b, 0x4d, 0x75, 0x70,
+0x61, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x6c, 0x77, 0x61, 0x3b, 0x4d, 0x77,
+0x69, 0x74, 0x6f, 0x70, 0x65, 0x3b, 0x4d, 0x75, 0x73, 0x68, 0x65, 0x6e,
+0x64, 0x65, 0x3b, 0x4d, 0x75, 0x6e, 0x79, 0x69, 0x3b, 0x4d, 0x75, 0x73,
+0x68, 0x65, 0x6e, 0x64, 0x65, 0x20, 0x4d, 0x61, 0x67, 0x61, 0x6c, 0x69,
+0x3b, 0x4d, 0x75, 0x6a, 0x69, 0x6d, 0x62, 0x69, 0x3b, 0x4d, 0x75, 0x73,
+0x68, 0x69, 0x70, 0x65, 0x70, 0x6f, 0x3b, 0x4d, 0x75, 0x70, 0x75, 0x67,
+0x75, 0x74, 0x6f, 0x3b, 0x4d, 0x75, 0x6e, 0x79, 0x65, 0x6e, 0x73, 0x65,
+0x3b, 0x4d, 0x6f, 0x6b, 0x68, 0x75, 0x3b, 0x4d, 0x75, 0x73, 0x6f, 0x6e,
+0x67, 0x61, 0x6e, 0x64, 0x65, 0x6d, 0x62, 0x77, 0x65, 0x3b, 0x4d, 0x75,
+0x68, 0x61, 0x61, 0x6e, 0x6f, 0x4d, 0x75, 0x70, 0x3b, 0x4d, 0x77, 0x69,
+0x3b, 0x4d, 0x73, 0x68, 0x3b, 0x4d, 0x75, 0x6e, 0x3b, 0x4d, 0x61, 0x67,
+0x3b, 0x4d, 0x75, 0x6a, 0x3b, 0x4d, 0x73, 0x70, 0x3b, 0x4d, 0x70, 0x67,
+0x3b, 0x4d, 0x79, 0x65, 0x3b, 0x4d, 0x6f, 0x6b, 0x3b, 0x4d, 0x75, 0x73,
+0x3b, 0x4d, 0x75, 0x68, 0x91c, 0x928, 0x935, 0x930, 0x940, 0x92e, 0x93e, 0x938,
+0x903, 0x3b, 0x92b, 0x930, 0x935, 0x930, 0x940, 0x92e, 0x93e, 0x938, 0x903, 0x3b,
+0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x92e, 0x93e, 0x938, 0x903, 0x3b, 0x905, 0x92a,
+0x94d, 0x930, 0x948, 0x932, 0x92e, 0x93e, 0x938, 0x903, 0x3b, 0x92e, 0x908, 0x92e,
+0x93e, 0x938, 0x903, 0x3b, 0x91c, 0x942, 0x928, 0x92e, 0x93e, 0x938, 0x903, 0x3b,
+0x91c, 0x941, 0x932, 0x93e, 0x908, 0x92e, 0x93e, 0x938, 0x903, 0x3b, 0x905, 0x917,
+0x938, 0x94d, 0x924, 0x92e, 0x93e, 0x938, 0x903, 0x3b, 0x938, 0x93f, 0x924, 0x902,
+0x92c, 0x930, 0x92e, 0x93e, 0x938, 0x903, 0x3b, 0x905, 0x915, 0x94d, 0x924, 0x942,
+0x92c, 0x930, 0x92e, 0x93e, 0x938, 0x903, 0x3b, 0x928, 0x935, 0x902, 0x92c, 0x930,
+0x92e, 0x93e, 0x938, 0x903, 0x3b, 0x926, 0x93f, 0x938, 0x902, 0x92c, 0x930, 0x92e,
+0x93e, 0x938, 0x903, 0x91c, 0x928, 0x935, 0x930, 0x940, 0x3a, 0x3b, 0x92b, 0x930,
+0x935, 0x930, 0x940, 0x3a, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3a, 0x3b,
+0x905, 0x92a, 0x94d, 0x930, 0x948, 0x932, 0x3a, 0x3b, 0x92e, 0x908, 0x3b, 0x91c,
+0x942, 0x928, 0x3a, 0x3b, 0x91c, 0x941, 0x932, 0x93e, 0x908, 0x3a, 0x3b, 0x905,
+0x917, 0x938, 0x94d, 0x924, 0x3a, 0x3b, 0x938, 0x93f, 0x924, 0x902, 0x92c, 0x930,
+0x3a, 0x3b, 0x905, 0x915, 0x94d, 0x924, 0x942, 0x92c, 0x930, 0x3a, 0x3b, 0x928,
+0x935, 0x902, 0x92c, 0x930, 0x3a, 0x3b, 0x926, 0x93f, 0x938, 0x902, 0x92c, 0x930,
+0x3a, 0x1c61, 0x1c5f, 0x1c71, 0x1c63, 0x1c5f, 0x1c68, 0x1c64, 0x3b, 0x1c6f, 0x1c77, 0x1c5f,
+0x1c68, 0x1c63, 0x1c5f, 0x1c68, 0x1c64, 0x3b, 0x1c62, 0x1c5f, 0x1c68, 0x1c6a, 0x3b, 0x1c5f,
+0x1c6f, 0x1c68, 0x1c6e, 0x1c5e, 0x3b, 0x1c62, 0x1c6e, 0x3b, 0x1c61, 0x1c69, 0x1c71, 0x3b,
+0x1c61, 0x1c69, 0x1c5e, 0x1c5f, 0x1c6d, 0x3b, 0x1c5f, 0x1c5c, 0x1c5f, 0x1c65, 0x1c5b, 0x3b,
+0x1c65, 0x1c6e, 0x1c6f, 0x1c74, 0x1c6e, 0x1c62, 0x1c75, 0x1c5f, 0x1c68, 0x3b, 0x1c5a, 0x1c60,
+0x1c74, 0x1c5a, 0x1c75, 0x1c5f, 0x1c68, 0x3b, 0x1c71, 0x1c5f, 0x1c63, 0x1c5f, 0x1c62, 0x1c75,
+0x1c5f, 0x1c68, 0x3b, 0x1c6b, 0x1c64, 0x1c65, 0x1c5f, 0x1c62, 0x1c75, 0x1c5f, 0x1c68, 0x1c61,
+0x1c5f, 0x1c71, 0x3b, 0x1c6f, 0x1c77, 0x1c5f, 0x3b, 0x1c62, 0x1c5f, 0x1c68, 0x3b, 0x1c5f,
+0x1c6f, 0x1c68, 0x3b, 0x1c62, 0x1c6e, 0x3b, 0x1c61, 0x1c69, 0x1c71, 0x3b, 0x1c61, 0x1c69,
+0x1c5e, 0x3b, 0x1c5f, 0x1c5c, 0x1c5f, 0x3b, 0x1c65, 0x1c6e, 0x1c6f, 0x3b, 0x1c5a, 0x1c60,
+0x1c74, 0x3b, 0x1c71, 0x1c5f, 0x1c63, 0x3b, 0x1c6b, 0x1c64, 0x1c65, 0x1c61, 0x3b, 0x1c6f,
+0x3b, 0x1c62, 0x3b, 0x1c5f, 0x3b, 0x1c62, 0x3b, 0x1c61, 0x3b, 0x1c61, 0x3b, 0x1c5f,
+0x3b, 0x1c65, 0x3b, 0x1c5a, 0x3b, 0x1c71, 0x3b, 0x1c6b, 0x67, 0x68, 0x65, 0x6e,
+0x6e, 0xe0, 0x72, 0x67, 0x69, 0x75, 0x3b, 0x66, 0x72, 0x65, 0xe0, 0x72,
+0x67, 0x69, 0x75, 0x3b, 0x6d, 0x61, 0x72, 0x74, 0x7a, 0x75, 0x3b, 0x61,
+0x62, 0x72, 0x69, 0x6c, 0x65, 0x3b, 0x6d, 0x61, 0x6a, 0x75, 0x3b, 0x6c,
+0xe0, 0x6d, 0x70, 0x61, 0x64, 0x61, 0x73, 0x3b, 0x74, 0x72, 0xec, 0x75,
+0x6c, 0x61, 0x73, 0x3b, 0x61, 0x75, 0x73, 0x74, 0x75, 0x3b, 0x63, 0x61,
+0x62, 0x75, 0x64, 0x61, 0x6e, 0x6e, 0x69, 0x3b, 0x73, 0x61, 0x6e, 0x74,
+0x75, 0x67, 0x61, 0x69, 0x6e, 0x65, 0x3b, 0x73, 0x61, 0x6e, 0x74, 0x61,
+0x6e, 0x64, 0x72, 0x69, 0x61, 0x3b, 0x6e, 0x61, 0x64, 0x61, 0x6c, 0x65,
+0x67, 0x68, 0x65, 0x3b, 0x66, 0x72, 0x65, 0x3b, 0x6d, 0x61, 0x72, 0x3b,
+0x61, 0x62, 0x72, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6c, 0xe0, 0x6d, 0x3b,
+0x74, 0x72, 0xec, 0x3b, 0x61, 0x75, 0x73, 0x3b, 0x63, 0x61, 0x62, 0x3b,
+0x73, 0x74, 0x47, 0x3b, 0x73, 0x74, 0x41, 0x3b, 0x6e, 0x61, 0x64, 0x47,
+0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4c, 0x3b, 0x54,
+0x3b, 0x41, 0x3b, 0x43, 0x3b, 0x53, 0x3b, 0x53, 0x3b, 0x4e, 0x4a, 0x61,
+0x6e, 0x65, 0x69, 0x72, 0x6f, 0x3b, 0x46, 0x65, 0x76, 0x72, 0x65, 0x69,
+0x72, 0x6f, 0x3b, 0x4d, 0x61, 0x72, 0x63, 0x6f, 0x3b, 0x41, 0x62, 0x72,
+0x69, 0x6c, 0x3b, 0x4d, 0x61, 0x69, 0x6f, 0x3b, 0x4a, 0x75, 0x6e, 0x68,
+0x6f, 0x3b, 0x4a, 0x75, 0x6c, 0x68, 0x6f, 0x3b, 0x41, 0x75, 0x67, 0x75,
+0x73, 0x74, 0x6f, 0x3b, 0x53, 0x65, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x6f,
+0x3b, 0x4f, 0x74, 0x75, 0x62, 0x72, 0x6f, 0x3b, 0x4e, 0x6f, 0x76, 0x65,
+0x6d, 0x62, 0x72, 0x6f, 0x3b, 0x44, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x72,
+0x6f, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x76, 0x3b, 0x4d, 0x61, 0x72,
+0x3b, 0x41, 0x62, 0x72, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e,
+0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x75, 0x67, 0x3b, 0x53, 0x65, 0x74,
+0x3b, 0x4f, 0x74, 0x75, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44, 0x65, 0x63,
+0x458, 0x430, 0x43d, 0x443, 0x430, 0x440, 0x3b, 0x444, 0x435, 0x431, 0x440, 0x443,
+0x430, 0x440, 0x3b, 0x43c, 0x430, 0x440, 0x442, 0x3b, 0x430, 0x43f, 0x440, 0x438,
+0x43b, 0x3b, 0x43c, 0x430, 0x458, 0x3b, 0x458, 0x443, 0x43d, 0x3b, 0x458, 0x443,
+0x43b, 0x3b, 0x430, 0x432, 0x433, 0x443, 0x441, 0x442, 0x3b, 0x441, 0x435, 0x43f,
+0x442, 0x435, 0x43c, 0x431, 0x430, 0x440, 0x3b, 0x43e, 0x43a, 0x442, 0x43e, 0x431,
+0x430, 0x440, 0x3b, 0x43d, 0x43e, 0x432, 0x435, 0x43c, 0x431, 0x430, 0x440, 0x3b,
+0x434, 0x435, 0x446, 0x435, 0x43c, 0x431, 0x430, 0x440, 0x458, 0x430, 0x43d, 0x3b,
+0x444, 0x435, 0x431, 0x3b, 0x43c, 0x430, 0x440, 0x3b, 0x430, 0x43f, 0x440, 0x3b,
+0x43c, 0x430, 0x458, 0x3b, 0x458, 0x443, 0x43d, 0x3b, 0x458, 0x443, 0x43b, 0x3b,
+0x430, 0x432, 0x433, 0x3b, 0x441, 0x435, 0x43f, 0x3b, 0x43e, 0x43a, 0x442, 0x3b,
+0x43d, 0x43e, 0x432, 0x3b, 0x434, 0x435, 0x446, 0x458, 0x430, 0x43d, 0x3b, 0x444,
+0x435, 0x431, 0x3b, 0x43c, 0x430, 0x440, 0x442, 0x3b, 0x430, 0x43f, 0x440, 0x3b,
+0x43c, 0x430, 0x458, 0x3b, 0x458, 0x443, 0x43d, 0x3b, 0x458, 0x443, 0x43b, 0x3b,
+0x430, 0x432, 0x433, 0x3b, 0x441, 0x435, 0x43f, 0x442, 0x3b, 0x43e, 0x43a, 0x442,
+0x3b, 0x43d, 0x43e, 0x432, 0x3b, 0x434, 0x435, 0x446, 0x6a, 0x61, 0x6e, 0x75,
+0x61, 0x72, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x3b, 0x6d,
+0x61, 0x72, 0x74, 0x3b, 0x61, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x61,
+0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x76,
+0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62,
+0x61, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x61, 0x72, 0x3b, 0x6e,
+0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x64, 0x65, 0x63, 0x65,
+0x6d, 0x62, 0x61, 0x72, 0x6a, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b,
+0x6d, 0x61, 0x72, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0x61, 0x6a, 0x3b,
+0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x76, 0x67, 0x3b,
+0x73, 0x65, 0x70, 0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x76, 0x3b,
+0x64, 0x65, 0x63, 0x6a, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d,
+0x61, 0x72, 0x74, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0x61, 0x6a, 0x3b,
+0x6a, 0x75, 0x6e, 0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x76, 0x67, 0x3b,
+0x73, 0x65, 0x70, 0x74, 0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x76,
+0x3b, 0x64, 0x65, 0x63, 0x4a, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x69, 0x3b,
+0x46, 0x65, 0x62, 0x6c, 0x75, 0x61, 0x6c, 0x69, 0x3b, 0x4d, 0x61, 0x63,
+0x68, 0x69, 0x3b, 0x41, 0x70, 0x6c, 0x69, 0x6c, 0x69, 0x3b, 0x4d, 0x65,
+0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x61, 0x69,
+0x3b, 0x41, 0x67, 0x6f, 0x73, 0x74, 0x69, 0x3b, 0x53, 0x65, 0x70, 0x74,
+0x65, 0x6d, 0x62, 0x61, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x61, 0x3b,
+0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x44, 0x65, 0x73, 0x65,
+0x6d, 0x62, 0x61, 0x4e, 0x64, 0x69, 0x72, 0x61, 0x3b, 0x4b, 0x75, 0x6b,
+0x61, 0x64, 0x7a, 0x69, 0x3b, 0x4b, 0x75, 0x72, 0x75, 0x6d, 0x65, 0x3b,
+0x4b, 0x75, 0x62, 0x76, 0x75, 0x6d, 0x62, 0x69, 0x3b, 0x43, 0x68, 0x69,
+0x76, 0x61, 0x62, 0x76, 0x75, 0x3b, 0x43, 0x68, 0x69, 0x6b, 0x75, 0x6d,
+0x69, 0x3b, 0x43, 0x68, 0x69, 0x6b, 0x75, 0x6e, 0x67, 0x75, 0x72, 0x75,
+0x3b, 0x4e, 0x79, 0x61, 0x6d, 0x61, 0x76, 0x68, 0x75, 0x76, 0x68, 0x75,
+0x3b, 0x47, 0x75, 0x6e, 0x79, 0x61, 0x6e, 0x61, 0x3b, 0x47, 0x75, 0x6d,
+0x69, 0x67, 0x75, 0x72, 0x75, 0x3b, 0x4d, 0x62, 0x75, 0x64, 0x7a, 0x69,
+0x3b, 0x5a, 0x76, 0x69, 0x74, 0x61, 0x4e, 0x64, 0x69, 0x3b, 0x4b, 0x75,
+0x6b, 0x3b, 0x4b, 0x75, 0x72, 0x3b, 0x4b, 0x75, 0x62, 0x3b, 0x43, 0x68,
+0x76, 0x3b, 0x43, 0x68, 0x6b, 0x3b, 0x43, 0x68, 0x67, 0x3b, 0x4e, 0x79,
+0x61, 0x3b, 0x47, 0x75, 0x6e, 0x3b, 0x47, 0x75, 0x6d, 0x3b, 0x4d, 0x62,
+0x75, 0x3b, 0x5a, 0x76, 0x69, 0x4e, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x4b,
+0x3b, 0x43, 0x3b, 0x43, 0x3b, 0x43, 0x3b, 0x4e, 0x3b, 0x47, 0x3b, 0x47,
+0x3b, 0x4d, 0x3b, 0x5a, 0xa2cd, 0xa1aa, 0x3b, 0xa44d, 0xa1aa, 0x3b, 0xa315, 0xa1aa,
+0x3b, 0xa1d6, 0xa1aa, 0x3b, 0xa26c, 0xa1aa, 0x3b, 0xa0d8, 0xa1aa, 0x3b, 0xa3c3, 0xa1aa,
+0x3b, 0xa246, 0xa1aa, 0x3b, 0xa22c, 0xa1aa, 0x3b, 0xa2b0, 0xa1aa, 0x3b, 0xa2b0, 0xa2aa,
+0xa1aa, 0x3b, 0xa2b0, 0xa44b, 0xa1aa, 0x6a, 0x69, 0x6e, 0x6e, 0x61, 0x72, 0x75,
+0x3b, 0x66, 0x72, 0x69, 0x76, 0x61, 0x72, 0x75, 0x3b, 0x6d, 0x61, 0x72,
+0x7a, 0x75, 0x3b, 0x61, 0x70, 0x72, 0x69, 0x6c, 0x69, 0x3b, 0x6d, 0x61,
+0x6a, 0x75, 0x3b, 0x67, 0x69, 0x75, 0x67, 0x6e, 0x75, 0x3b, 0x67, 0x69,
+0x75, 0x67, 0x6e, 0x65, 0x74, 0x74, 0x75, 0x3b, 0x61, 0x67, 0x75, 0x73,
+0x74, 0x75, 0x3b, 0x73, 0x69, 0x74, 0x74, 0xe8, 0x6d, 0x6d, 0x69, 0x72,
+0x75, 0x3b, 0x75, 0x74, 0x74, 0xf2, 0x76, 0x69, 0x72, 0x75, 0x3b, 0x6e,
+0x75, 0x76, 0xe8, 0x6d, 0x6d, 0x69, 0x72, 0x75, 0x3b, 0x64, 0x69, 0x63,
+0xe8, 0x6d, 0x6d, 0x69, 0x72, 0x75, 0x6a, 0x69, 0x6e, 0x3b, 0x66, 0x72,
+0x69, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0x61,
+0x6a, 0x3b, 0x67, 0x69, 0x75, 0x3b, 0x67, 0x6e, 0x74, 0x3b, 0x61, 0x67,
+0x75, 0x3b, 0x73, 0x69, 0x74, 0x3b, 0x75, 0x74, 0x74, 0x3b, 0x6e, 0x75,
+0x76, 0x3b, 0x64, 0x69, 0x63, 0x4a, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41,
+0x3b, 0x4d, 0x3b, 0x47, 0x3b, 0x47, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x55,
+0x3b, 0x4e, 0x3b, 0x44, 0x73, 0x74, 0x79, 0x63, 0x7a, 0x79, 0x144, 0x3b,
+0x6c, 0x75, 0x74, 0x79, 0x3b, 0x6d, 0x61, 0x72, 0x7a, 0x65, 0x63, 0x3b,
+0x6b, 0x77, 0x69, 0x65, 0x63, 0x69, 0x79, 0x144, 0x3b, 0x6d, 0x6f, 0x6a,
+0x3b, 0x63, 0x7a, 0x79, 0x72, 0x77, 0x69, 0x65, 0x63, 0x3b, 0x6c, 0x69,
+0x70, 0x69, 0x65, 0x63, 0x3b, 0x73, 0x69, 0x79, 0x72, 0x70, 0x69, 0x79,
+0x144, 0x3b, 0x77, 0x72, 0x7a, 0x65, 0x73, 0x69, 0x79, 0x144, 0x3b, 0x70,
+0x61, 0x17a, 0x64, 0x7a, 0x69, 0x65, 0x72, 0x6e, 0x69, 0x6b, 0x3b, 0x6c,
+0x69, 0x73, 0x74, 0x6f, 0x70, 0x61, 0x64, 0x3b, 0x67, 0x72, 0x75, 0x64,
+0x7a, 0x69, 0x79, 0x144, 0x73, 0x74, 0x79, 0x63, 0x7a, 0x6e, 0x69, 0x61,
+0x3b, 0x6c, 0x75, 0x74, 0x65, 0x67, 0x6f, 0x3b, 0x6d, 0x61, 0x72, 0x63,
+0x61, 0x3b, 0x6b, 0x77, 0x69, 0x65, 0x74, 0x6e, 0x69, 0x61, 0x3b, 0x6d,
+0x6f, 0x6a, 0x61, 0x3b, 0x63, 0x7a, 0x79, 0x72, 0x77, 0x63, 0x61, 0x3b,
+0x6c, 0x69, 0x70, 0x63, 0x61, 0x3b, 0x73, 0x69, 0x79, 0x72, 0x70, 0x6e,
+0x69, 0x61, 0x3b, 0x77, 0x72, 0x7a, 0x65, 0x15b, 0x6e, 0x69, 0x61, 0x3b,
+0x70, 0x61, 0x17a, 0x64, 0x7a, 0x69, 0x65, 0x72, 0x6e, 0x69, 0x6b, 0x61,
+0x3b, 0x6c, 0x69, 0x73, 0x74, 0x6f, 0x70, 0x61, 0x64, 0x61, 0x3b, 0x67,
+0x72, 0x75, 0x64, 0x6e, 0x69, 0x61, 0x73, 0x74, 0x79, 0x3b, 0x6c, 0x75,
+0x74, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x6b, 0x77, 0x69, 0x3b, 0x6d, 0x6f,
+0x6a, 0x3b, 0x63, 0x7a, 0x79, 0x3b, 0x6c, 0x69, 0x70, 0x3b, 0x73, 0x69,
+0x79, 0x3b, 0x77, 0x72, 0x7a, 0x3b, 0x70, 0x61, 0x17a, 0x3b, 0x6c, 0x69,
+0x73, 0x3b, 0x67, 0x72, 0x75, 0x62c, 0x646, 0x648, 0x631, 0x64a, 0x3b, 0x641,
+0x64a, 0x628, 0x631, 0x648, 0x631, 0x64a, 0x3b, 0x645, 0x627, 0x631, 0x686, 0x3b,
+0x627, 0x67e, 0x631, 0x64a, 0x644, 0x3b, 0x645, 0x626, 0x64a, 0x3b, 0x62c, 0x648,
+0x646, 0x3b, 0x62c, 0x648, 0x644, 0x627, 0x621, 0x650, 0x3b, 0x622, 0x6af, 0x633,
+0x67d, 0x3b, 0x633, 0x64a, 0x67e, 0x67d, 0x645, 0x628, 0x631, 0x3b, 0x622, 0x6aa,
+0x67d, 0x648, 0x628, 0x631, 0x3b, 0x646, 0x648, 0x645, 0x628, 0x631, 0x3b, 0x68a,
+0x633, 0x645, 0x628, 0x631, 0x91c, 0x928, 0x935, 0x930, 0x940, 0x3b, 0x92b, 0x930,
+0x935, 0x930, 0x940, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x941, 0x3b, 0x905,
+0x92a, 0x94d, 0x930, 0x948, 0x932, 0x3b, 0x92e, 0x908, 0x3b, 0x91c, 0x942, 0x928,
+0x3b, 0x91c, 0x941, 0x932, 0x93e, 0x908, 0x3b, 0x905, 0x917, 0x938, 0x94d, 0x91f,
+0x3b, 0x938, 0x92a, 0x94d, 0x91f, 0x947, 0x902, 0x92c, 0x930, 0x3b, 0x911, 0x915,
+0x94d, 0x91f, 0x94b, 0x92c, 0x930, 0x3b, 0x928, 0x935, 0x902, 0x92c, 0x930, 0x3b,
+0x921, 0x93f, 0x938, 0x902, 0x92c, 0x930, 0x91c, 0x928, 0x935, 0x930, 0x940, 0x3b,
+0x92b, 0x930, 0x935, 0x930, 0x940, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x941,
+0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x948, 0x932, 0x3b, 0x92e, 0x908, 0x3b, 0x91c,
+0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x93e, 0x908, 0x3b, 0x905, 0x917, 0x938,
+0x94d, 0x91f, 0x3b, 0x938, 0x92a, 0x94d, 0x91f, 0x947, 0x902, 0x92c, 0x930, 0x3b,
+0x913, 0x915, 0x94d, 0x91f, 0x94b, 0x92c, 0x930, 0x3b, 0x928, 0x935, 0x902, 0x92c,
+0x930, 0x3b, 0x921, 0x93f, 0x938, 0x902, 0x92c, 0x930, 0x91c, 0x928, 0x3b, 0x92b,
+0x930, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930,
+0x948, 0x3b, 0x92e, 0x908, 0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932,
+0x93e, 0x3b, 0x905, 0x917, 0x3b, 0x938, 0x92a, 0x94d, 0x91f, 0x947, 0x3b, 0x911,
+0x915, 0x94d, 0x91f, 0x94b, 0x3b, 0x928, 0x935, 0x902, 0x3b, 0x921, 0x93f, 0x938,
+0x902, 0x91c, 0x928, 0x3b, 0x92b, 0x930, 0x3b, 0x92e, 0x93e, 0x930, 0x94d, 0x91a,
+0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x948, 0x3b, 0x92e, 0x908, 0x3b, 0x91c, 0x942,
+0x928, 0x3b, 0x91c, 0x941, 0x3b, 0x905, 0x917, 0x3b, 0x938, 0x92a, 0x94d, 0x91f,
+0x947, 0x3b, 0x911, 0x915, 0x94d, 0x91f, 0x94b, 0x3b, 0x928, 0x935, 0x902, 0x3b,
+0x921, 0x93f, 0x938, 0x902, 0x91c, 0x3b, 0x92b, 0x93c, 0x3b, 0x92e, 0x3b, 0x905,
+0x3b, 0x92e, 0x93e, 0x3b, 0x91c, 0x942, 0x3b, 0x91c, 0x941, 0x3b, 0x905, 0x917,
+0x3b, 0x938, 0x3b, 0x911, 0x3b, 0x928, 0x3b, 0x921, 0x93f, 0x91c, 0x3b, 0x92b,
+0x93c, 0x3b, 0x92e, 0x93e, 0x3b, 0x905, 0x3b, 0x92e, 0x93e, 0x3b, 0x91c, 0x942,
+0x3b, 0x91c, 0x941, 0x3b, 0x905, 0x917, 0x3b, 0x938, 0x3b, 0x911, 0x3b, 0x928,
+0x3b, 0x921, 0x93f, 0xda2, 0xdb1, 0xdc0, 0xdcf, 0xdbb, 0xdd2, 0x3b, 0xdb4, 0xdd9,
+0xdb6, 0xdbb, 0xdc0, 0xdcf, 0xdbb, 0xdd2, 0x3b, 0xdb8, 0xdcf, 0xdbb, 0xdca, 0xdad,
+0xdd4, 0x3b, 0xd85, 0xdb4, 0xdca, 0x200d, 0xdbb, 0xdda, 0xdbd, 0xdca, 0x3b, 0xdb8,
+0xdd0, 0xdba, 0xdd2, 0x3b, 0xda2, 0xdd6, 0xdb1, 0xdd2, 0x3b, 0xda2, 0xdd6, 0xdbd,
+0xdd2, 0x3b, 0xd85, 0xd9c, 0xddd, 0xdc3, 0xdca, 0xdad, 0xdd4, 0x3b, 0xdc3, 0xdd0,
+0xdb4, 0xdca, 0xdad, 0xdd0, 0xdb8, 0xdca, 0xdb6, 0xdbb, 0xdca, 0x3b, 0xd94, 0xd9a,
+0xdca, 0xdad, 0xddd, 0xdb6, 0xdbb, 0xdca, 0x3b, 0xdb1, 0xddc, 0xdc0, 0xdd0, 0xdb8,
+0xdca, 0xdb6, 0xdbb, 0xdca, 0x3b, 0xdaf, 0xdd9, 0xdc3, 0xdd0, 0xdb8, 0xdca, 0xdb6,
+0xdbb, 0xdca, 0xda2, 0xdb1, 0x3b, 0xdb4, 0xdd9, 0xdb6, 0x3b, 0xdb8, 0xdcf, 0xdbb,
+0xdca, 0x3b, 0xd85, 0xdb4, 0xdca, 0x200d, 0xdbb, 0xdda, 0xdbd, 0xdca, 0x3b, 0xdb8,
+0xdd0, 0xdba, 0xdd2, 0x3b, 0xda2, 0xdd6, 0xdb1, 0xdd2, 0x3b, 0xda2, 0xdd6, 0xdbd,
+0xdd2, 0x3b, 0xd85, 0xd9c, 0xddd, 0x3b, 0xdc3, 0xdd0, 0xdb4, 0xdca, 0x3b, 0xd94,
+0xd9a, 0xdca, 0x3b, 0xdb1, 0xddc, 0xdc0, 0xdd0, 0x3b, 0xdaf, 0xdd9, 0xdc3, 0xdd0,
+0xda2, 0xdb1, 0x3b, 0xdb4, 0xdd9, 0xdb6, 0x3b, 0xdb8, 0xdcf, 0xdbb, 0xdca, 0xdad,
+0xdd4, 0x3b, 0xd85, 0xdb4, 0xdca, 0x200d, 0xdbb, 0xdda, 0xdbd, 0xdca, 0x3b, 0xdb8,
+0xdd0, 0xdba, 0xdd2, 0x3b, 0xda2, 0xdd6, 0xdb1, 0xdd2, 0x3b, 0xda2, 0xdd6, 0xdbd,
+0xdd2, 0x3b, 0xd85, 0xd9c, 0xddd, 0x3b, 0xdc3, 0xdd0, 0xdb4, 0xdca, 0x3b, 0xd94,
+0xd9a, 0xdca, 0x3b, 0xdb1, 0xddc, 0xdc0, 0xdd0, 0x3b, 0xdaf, 0xdd9, 0xdc3, 0xdd0,
+0xda2, 0x3b, 0xdb4, 0xdd9, 0x3b, 0xdb8, 0xdcf, 0x3b, 0xd85, 0x3b, 0xdb8, 0xdd0,
+0x3b, 0xda2, 0xdd6, 0x3b, 0xda2, 0xdd6, 0x3b, 0xd85, 0x3b, 0xdc3, 0xdd0, 0x3b,
+0xd94, 0x3b, 0xdb1, 0xdd9, 0x3b, 0xdaf, 0xdd9, 0x6a, 0x61, 0x6e, 0x75, 0xe1,
+0x72, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0xe1, 0x72, 0x3b, 0x6d, 0x61,
+0x72, 0x65, 0x63, 0x3b, 0x61, 0x70, 0x72, 0xed, 0x6c, 0x3b, 0x6d, 0xe1,
+0x6a, 0x3b, 0x6a, 0xfa, 0x6e, 0x3b, 0x6a, 0xfa, 0x6c, 0x3b, 0x61, 0x75,
+0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62,
+0x65, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0xf3, 0x62, 0x65, 0x72, 0x3b, 0x6e,
+0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x64, 0x65, 0x63, 0x65,
+0x6d, 0x62, 0x65, 0x72, 0x6a, 0x61, 0x6e, 0x75, 0xe1, 0x72, 0x61, 0x3b,
+0x66, 0x65, 0x62, 0x72, 0x75, 0xe1, 0x72, 0x61, 0x3b, 0x6d, 0x61, 0x72,
+0x63, 0x61, 0x3b, 0x61, 0x70, 0x72, 0xed, 0x6c, 0x61, 0x3b, 0x6d, 0xe1,
+0x6a, 0x61, 0x3b, 0x6a, 0xfa, 0x6e, 0x61, 0x3b, 0x6a, 0xfa, 0x6c, 0x61,
+0x3b, 0x61, 0x75, 0x67, 0x75, 0x73, 0x74, 0x61, 0x3b, 0x73, 0x65, 0x70,
+0x74, 0x65, 0x6d, 0x62, 0x72, 0x61, 0x3b, 0x6f, 0x6b, 0x74, 0xf3, 0x62,
+0x72, 0x61, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x61, 0x3b,
+0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x72, 0x61, 0x6a, 0x61, 0x6e, 0x3b,
+0x66, 0x65, 0x62, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x61, 0x70, 0x72, 0x3b,
+0x6d, 0xe1, 0x6a, 0x3b, 0x6a, 0xfa, 0x6e, 0x3b, 0x6a, 0xfa, 0x6c, 0x3b,
+0x61, 0x75, 0x67, 0x3b, 0x73, 0x65, 0x70, 0x3b, 0x6f, 0x6b, 0x74, 0x3b,
+0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65, 0x63, 0x6a, 0x61, 0x6e, 0x75, 0x61,
+0x72, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x3b, 0x6d, 0x61,
+0x72, 0x65, 0x63, 0x3b, 0x61, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x6d, 0x61,
+0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x6a, 0x3b, 0x6a, 0x75, 0x6c, 0x69,
+0x6a, 0x3b, 0x61, 0x76, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x70,
+0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62,
+0x65, 0x72, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b,
+0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x6a, 0x61, 0x6e, 0x2e,
+0x3b, 0x66, 0x65, 0x62, 0x2e, 0x3b, 0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x61,
+0x70, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x2e,
+0x3b, 0x6a, 0x75, 0x6c, 0x2e, 0x3b, 0x61, 0x76, 0x67, 0x2e, 0x3b, 0x73,
+0x65, 0x70, 0x2e, 0x3b, 0x6f, 0x6b, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76,
+0x2e, 0x3b, 0x64, 0x65, 0x63, 0x2e, 0x4a, 0x61, 0x6e, 0x6e, 0x61, 0x61,
+0x79, 0x6f, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x61, 0x61, 0x79, 0x6f, 0x3b,
+0x4d, 0x61, 0x61, 0x72, 0x73, 0x6f, 0x3b, 0x41, 0x62, 0x72, 0x69, 0x69,
+0x6c, 0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x4a, 0x75, 0x75, 0x6e, 0x3b, 0x4c,
+0x75, 0x75, 0x6c, 0x69, 0x79, 0x6f, 0x3b, 0x4f, 0x67, 0x6f, 0x73, 0x74,
+0x6f, 0x3b, 0x53, 0x65, 0x62, 0x74, 0x65, 0x65, 0x6d, 0x62, 0x61, 0x72,
+0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x3b, 0x4e, 0x6f,
+0x6f, 0x66, 0x65, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x44, 0x69, 0x73,
+0x65, 0x65, 0x6d, 0x62, 0x61, 0x72, 0x42, 0x69, 0x73, 0x68, 0x61, 0x20,
+0x4b, 0x6f, 0x6f, 0x62, 0x61, 0x61, 0x64, 0x3b, 0x42, 0x69, 0x73, 0x68,
+0x61, 0x20, 0x4c, 0x61, 0x62, 0x61, 0x61, 0x64, 0x3b, 0x42, 0x69, 0x73,
+0x68, 0x61, 0x20, 0x53, 0x61, 0x64, 0x64, 0x65, 0x78, 0x61, 0x61, 0x64,
+0x3b, 0x42, 0x69, 0x73, 0x68, 0x61, 0x20, 0x41, 0x66, 0x72, 0x61, 0x61,
+0x64, 0x3b, 0x42, 0x69, 0x73, 0x68, 0x61, 0x20, 0x53, 0x68, 0x61, 0x6e,
+0x61, 0x61, 0x64, 0x3b, 0x42, 0x69, 0x73, 0x68, 0x61, 0x20, 0x4c, 0x69,
+0x78, 0x61, 0x61, 0x64, 0x3b, 0x42, 0x69, 0x73, 0x68, 0x61, 0x20, 0x54,
+0x6f, 0x64, 0x6f, 0x62, 0x61, 0x61, 0x64, 0x3b, 0x42, 0x69, 0x73, 0x68,
+0x61, 0x20, 0x53, 0x69, 0x64, 0x65, 0x65, 0x64, 0x61, 0x61, 0x64, 0x3b,
+0x42, 0x69, 0x73, 0x68, 0x61, 0x20, 0x53, 0x61, 0x67, 0x61, 0x61, 0x6c,
+0x61, 0x61, 0x64, 0x3b, 0x42, 0x69, 0x73, 0x68, 0x61, 0x20, 0x54, 0x6f,
+0x62, 0x6e, 0x61, 0x61, 0x64, 0x3b, 0x42, 0x69, 0x73, 0x68, 0x61, 0x20,
+0x4b, 0x6f, 0x77, 0x20, 0x69, 0x79, 0x6f, 0x20, 0x54, 0x6f, 0x62, 0x6e,
+0x61, 0x61, 0x64, 0x3b, 0x42, 0x69, 0x73, 0x68, 0x61, 0x20, 0x4c, 0x61,
+0x62, 0x61, 0x20, 0x69, 0x79, 0x6f, 0x20, 0x54, 0x6f, 0x62, 0x6e, 0x61,
+0x61, 0x64, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61,
+0x72, 0x3b, 0x41, 0x62, 0x72, 0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x4a, 0x75,
+0x6e, 0x3b, 0x4c, 0x75, 0x6c, 0x3b, 0x4f, 0x67, 0x73, 0x3b, 0x53, 0x65,
+0x62, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x66, 0x3b, 0x44, 0x69,
+0x73, 0x4a, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4a,
+0x3b, 0x4c, 0x3b, 0x4f, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44,
+0x50, 0x68, 0x65, 0x73, 0x65, 0x6b, 0x67, 0x6f, 0x6e, 0x67, 0x3b, 0x48,
+0x6c, 0x61, 0x6b, 0x6f, 0x6c, 0x61, 0x3b, 0x48, 0x6c, 0x61, 0x6b, 0x75,
+0x62, 0x65, 0x6c, 0x65, 0x3b, 0x4d, 0x6d, 0x65, 0x73, 0x65, 0x3b, 0x4d,
+0x6f, 0x74, 0x73, 0x68, 0x65, 0x61, 0x6e, 0x6f, 0x6e, 0x67, 0x3b, 0x50,
+0x68, 0x75, 0x70, 0x6a, 0x61, 0x6e, 0x65, 0x3b, 0x50, 0x68, 0x75, 0x70,
+0x75, 0x3b, 0x50, 0x68, 0x61, 0x74, 0x61, 0x3b, 0x4c, 0x65, 0x6f, 0x74,
+0x73, 0x68, 0x65, 0x3b, 0x4d, 0x70, 0x68, 0x61, 0x6c, 0x61, 0x6e, 0x65,
+0x3b, 0x50, 0x75, 0x6e, 0x64, 0x75, 0x6e, 0x67, 0x77, 0x61, 0x6e, 0x65,
+0x3b, 0x54, 0x73, 0x68, 0x69, 0x74, 0x77, 0x65, 0x50, 0x68, 0x65, 0x3b,
+0x4b, 0x6f, 0x6c, 0x3b, 0x55, 0x62, 0x65, 0x3b, 0x4d, 0x6d, 0x65, 0x3b,
+0x4d, 0x6f, 0x74, 0x3b, 0x4a, 0x61, 0x6e, 0x3b, 0x55, 0x70, 0x75, 0x3b,
+0x50, 0x68, 0x61, 0x3b, 0x4c, 0x65, 0x6f, 0x3b, 0x4d, 0x70, 0x68, 0x3b,
+0x50, 0x75, 0x6e, 0x3b, 0x54, 0x73, 0x68, 0x4a, 0x61, 0x6e, 0x61, 0x62,
+0x61, 0x72, 0x69, 0x3b, 0x75, 0x46, 0x65, 0x62, 0x65, 0x72, 0x62, 0x61,
+0x72, 0x69, 0x3b, 0x75, 0x4d, 0x61, 0x74, 0x6a, 0x68, 0x69, 0x3b, 0x75,
+0x2d, 0x41, 0x70, 0x72, 0x65, 0x6c, 0x69, 0x3b, 0x4d, 0x65, 0x79, 0x69,
+0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x61, 0x79, 0x69,
+0x3b, 0x41, 0x72, 0x68, 0x6f, 0x73, 0x74, 0x6f, 0x73, 0x69, 0x3b, 0x53,
+0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x4f, 0x6b, 0x74, 0x6f,
+0x62, 0x61, 0x3b, 0x55, 0x73, 0x69, 0x6e, 0x79, 0x69, 0x6b, 0x68, 0x61,
+0x62, 0x61, 0x3b, 0x44, 0x69, 0x73, 0x65, 0x6d, 0x62, 0x61, 0x4a, 0x61,
+0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x74, 0x3b, 0x41, 0x70,
+0x72, 0x3b, 0x4d, 0x65, 0x79, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75,
+0x6c, 0x3b, 0x41, 0x72, 0x68, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b,
+0x74, 0x3b, 0x55, 0x73, 0x69, 0x3b, 0x44, 0x69, 0x73, 0x65, 0x6e, 0x65,
+0x72, 0x6f, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x65, 0x72, 0x6f, 0x3b, 0x6d,
+0x61, 0x72, 0x7a, 0x6f, 0x3b, 0x61, 0x62, 0x72, 0x69, 0x6c, 0x3b, 0x6d,
+0x61, 0x79, 0x6f, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x6f, 0x3b, 0x6a, 0x75,
+0x6c, 0x69, 0x6f, 0x3b, 0x61, 0x67, 0x6f, 0x73, 0x74, 0x6f, 0x3b, 0x73,
+0x65, 0x70, 0x74, 0x69, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x6f, 0x63,
+0x74, 0x75, 0x62, 0x72, 0x65, 0x3b, 0x6e, 0x6f, 0x76, 0x69, 0x65, 0x6d,
+0x62, 0x72, 0x65, 0x3b, 0x64, 0x69, 0x63, 0x69, 0x65, 0x6d, 0x62, 0x72,
+0x65, 0x65, 0x6e, 0x65, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0x61, 0x72,
+0x3b, 0x61, 0x62, 0x72, 0x3b, 0x6d, 0x61, 0x79, 0x3b, 0x6a, 0x75, 0x6e,
+0x3b, 0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x67, 0x6f, 0x3b, 0x73, 0x65, 0x70,
+0x74, 0x3b, 0x6f, 0x63, 0x74, 0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x69,
+0x63, 0x45, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4a,
+0x3b, 0x4a, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44,
+0x65, 0x6e, 0x65, 0x2e, 0x3b, 0x66, 0x65, 0x62, 0x2e, 0x3b, 0x6d, 0x61,
+0x72, 0x2e, 0x3b, 0x61, 0x62, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x79, 0x2e,
+0x3b, 0x6a, 0x75, 0x6e, 0x2e, 0x3b, 0x6a, 0x75, 0x6c, 0x2e, 0x3b, 0x61,
+0x67, 0x6f, 0x2e, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x2e, 0x3b, 0x6f, 0x63,
+0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x69, 0x63, 0x2e,
+0x65, 0x6e, 0x65, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0x61, 0x72, 0x3b,
+0x61, 0x62, 0x72, 0x3b, 0x6d, 0x61, 0x79, 0x3b, 0x6a, 0x75, 0x6e, 0x3b,
+0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x67, 0x6f, 0x3b, 0x73, 0x65, 0x70, 0x3b,
+0x6f, 0x63, 0x74, 0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x69, 0x63, 0x65,
+0x6e, 0x65, 0x72, 0x6f, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x65, 0x72, 0x6f,
+0x3b, 0x6d, 0x61, 0x72, 0x7a, 0x6f, 0x3b, 0x61, 0x62, 0x72, 0x69, 0x6c,
+0x3b, 0x6d, 0x61, 0x79, 0x6f, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x6f, 0x3b,
+0x6a, 0x75, 0x6c, 0x69, 0x6f, 0x3b, 0x61, 0x67, 0x6f, 0x73, 0x74, 0x6f,
+0x3b, 0x73, 0x65, 0x74, 0x69, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x6f,
+0x63, 0x74, 0x75, 0x62, 0x72, 0x65, 0x3b, 0x6e, 0x6f, 0x76, 0x69, 0x65,
+0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x69, 0x63, 0x69, 0x65, 0x6d, 0x62,
+0x72, 0x65, 0x45, 0x6e, 0x65, 0x2e, 0x3b, 0x46, 0x65, 0x62, 0x2e, 0x3b,
+0x4d, 0x61, 0x72, 0x2e, 0x3b, 0x41, 0x62, 0x72, 0x2e, 0x3b, 0x4d, 0x61,
+0x79, 0x2e, 0x3b, 0x4a, 0x75, 0x6e, 0x2e, 0x3b, 0x4a, 0x75, 0x6c, 0x2e,
+0x3b, 0x41, 0x67, 0x6f, 0x2e, 0x3b, 0x53, 0x65, 0x74, 0x2e, 0x3b, 0x4f,
+0x63, 0x74, 0x2e, 0x3b, 0x4e, 0x6f, 0x76, 0x2e, 0x3b, 0x44, 0x69, 0x63,
+0x2e, 0x65, 0x6e, 0x65, 0x2e, 0x3b, 0x66, 0x65, 0x62, 0x2e, 0x3b, 0x6d,
+0x61, 0x72, 0x2e, 0x3b, 0x61, 0x62, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x79,
+0x2e, 0x3b, 0x6a, 0x75, 0x6e, 0x2e, 0x3b, 0x6a, 0x75, 0x6c, 0x2e, 0x3b,
+0x61, 0x67, 0x6f, 0x2e, 0x3b, 0x73, 0x65, 0x74, 0x2e, 0x3b, 0x6f, 0x63,
+0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x69, 0x63, 0x2e,
+0x2d49, 0x2d4f, 0x2d4f, 0x2d30, 0x2d62, 0x2d54, 0x3b, 0x2d31, 0x2d55, 0x2d30, 0x2d62, 0x2d55,
+0x3b, 0x2d4e, 0x2d30, 0x2d55, 0x2d5a, 0x3b, 0x2d49, 0x2d31, 0x2d54, 0x2d49, 0x2d54, 0x3b,
+0x2d4e, 0x2d30, 0x2d62, 0x2d62, 0x2d53, 0x3b, 0x2d62, 0x2d53, 0x2d4f, 0x2d62, 0x2d53, 0x3b,
+0x2d62, 0x2d53, 0x2d4d, 0x2d62, 0x2d53, 0x2d63, 0x3b, 0x2d56, 0x2d53, 0x2d5b, 0x2d5c, 0x3b,
+0x2d5b, 0x2d53, 0x2d5c, 0x2d30, 0x2d4f, 0x2d31, 0x2d49, 0x2d54, 0x3b, 0x2d3d, 0x2d5c, 0x2d53,
+0x2d31, 0x2d54, 0x3b, 0x2d4f, 0x2d53, 0x2d61, 0x2d30, 0x2d4f, 0x2d31, 0x2d49, 0x2d54, 0x3b,
+0x2d37, 0x2d53, 0x2d4a, 0x2d30, 0x2d4f, 0x2d31, 0x2d49, 0x2d54, 0x2d49, 0x2d4f, 0x2d4f, 0x3b,
+0x2d31, 0x2d55, 0x2d30, 0x3b, 0x2d4e, 0x2d30, 0x2d55, 0x3b, 0x2d49, 0x2d31, 0x2d54, 0x3b,
+0x2d4e, 0x2d30, 0x2d62, 0x3b, 0x2d62, 0x2d53, 0x2d4f, 0x3b, 0x2d62, 0x2d53, 0x2d4d, 0x3b,
+0x2d56, 0x2d53, 0x2d5b, 0x3b, 0x2d5b, 0x2d53, 0x2d5c, 0x3b, 0x2d3d, 0x2d5c, 0x2d53, 0x3b,
+0x2d4f, 0x2d53, 0x2d61, 0x3b, 0x2d37, 0x2d53, 0x2d4a, 0x2d49, 0x3b, 0x2d31, 0x3b, 0x2d4e,
+0x3b, 0x2d49, 0x3b, 0x2d4e, 0x3b, 0x2d62, 0x3b, 0x2d62, 0x3b, 0x2d56, 0x3b, 0x2d5b,
+0x3b, 0x2d3d, 0x3b, 0x2d4f, 0x3b, 0x2d37, 0x4a, 0x61, 0x6e, 0x75, 0x61, 0x72,
+0x69, 0x3b, 0x50, 0xe9, 0x62, 0x72, 0x75, 0x61, 0x72, 0x69, 0x3b, 0x4d,
+0x61, 0x72, 0x65, 0x74, 0x3b, 0x41, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x4d,
+0xe9, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x69,
+0x3b, 0x41, 0x67, 0x75, 0x73, 0x74, 0x75, 0x73, 0x3b, 0x53, 0xe9, 0x70,
+0x74, 0xe9, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62,
+0x65, 0x72, 0x3b, 0x4e, 0x6f, 0x70, 0xe9, 0x6d, 0x62, 0x65, 0x72, 0x3b,
+0x44, 0xe9, 0x73, 0xe9, 0x6d, 0x62, 0x65, 0x72, 0x4a, 0x61, 0x6e, 0x3b,
+0x50, 0xe9, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b,
+0x4d, 0xe9, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b,
+0x41, 0x67, 0x73, 0x3b, 0x53, 0xe9, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b,
+0x4e, 0x6f, 0x70, 0x3b, 0x44, 0xe9, 0x73, 0x4a, 0x3b, 0x50, 0x3b, 0x4d,
+0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x4a, 0x3b, 0x41, 0x3b, 0x53,
+0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x42, 0x68, 0x69, 0x6d, 0x62, 0x69,
+0x64, 0x76, 0x77, 0x61, 0x6e, 0x65, 0x3b, 0x69, 0x4e, 0x64, 0x6c, 0x6f,
+0x76, 0x61, 0x6e, 0x61, 0x3b, 0x69, 0x4e, 0x64, 0x6c, 0x6f, 0x76, 0x75,
+0x2d, 0x6c, 0x65, 0x6e, 0x6b, 0x68, 0x75, 0x6c, 0x75, 0x3b, 0x4d, 0x61,
+0x62, 0x61, 0x73, 0x61, 0x3b, 0x69, 0x4e, 0x6b, 0x68, 0x77, 0x65, 0x6b,
+0x68, 0x77, 0x65, 0x74, 0x69, 0x3b, 0x69, 0x4e, 0x68, 0x6c, 0x61, 0x62,
+0x61, 0x3b, 0x4b, 0x68, 0x6f, 0x6c, 0x77, 0x61, 0x6e, 0x65, 0x3b, 0x69,
+0x4e, 0x67, 0x63, 0x69, 0x3b, 0x69, 0x4e, 0x79, 0x6f, 0x6e, 0x69, 0x3b,
+0x69, 0x4d, 0x70, 0x68, 0x61, 0x6c, 0x61, 0x3b, 0x4c, 0x77, 0x65, 0x74,
+0x69, 0x3b, 0x69, 0x4e, 0x67, 0x6f, 0x6e, 0x67, 0x6f, 0x6e, 0x69, 0x42,
+0x68, 0x69, 0x3b, 0x56, 0x61, 0x6e, 0x3b, 0x56, 0x6f, 0x6c, 0x3b, 0x4d,
+0x61, 0x62, 0x3b, 0x4e, 0x6b, 0x68, 0x3b, 0x4e, 0x68, 0x6c, 0x3b, 0x4b,
+0x68, 0x6f, 0x3b, 0x4e, 0x67, 0x63, 0x3b, 0x4e, 0x79, 0x6f, 0x3b, 0x4d,
+0x70, 0x68, 0x3b, 0x4c, 0x77, 0x65, 0x3b, 0x4e, 0x67, 0x6f, 0x6a, 0x61,
+0x6e, 0x75, 0x61, 0x72, 0x69, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x75, 0x61,
+0x72, 0x69, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x3b, 0x61, 0x70, 0x72, 0x69,
+0x6c, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x3b, 0x6a,
+0x75, 0x6c, 0x69, 0x3b, 0x61, 0x75, 0x67, 0x75, 0x73, 0x74, 0x69, 0x3b,
+0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x6f, 0x6b,
+0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62,
+0x65, 0x72, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x6a,
+0x61, 0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x62, 0x2e, 0x3b, 0x6d, 0x61, 0x72,
+0x73, 0x3b, 0x61, 0x70, 0x72, 0x2e, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a,
+0x75, 0x6e, 0x69, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x3b, 0x61, 0x75, 0x67,
+0x2e, 0x3b, 0x73, 0x65, 0x70, 0x2e, 0x3b, 0x6f, 0x6b, 0x74, 0x2e, 0x3b,
+0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x63, 0x2e, 0x4a, 0x61, 0x6e,
+0x75, 0x61, 0x72, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x3b,
+0x4d, 0xe4, 0x72, 0x7a, 0x3b, 0x41, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x4d,
+0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x69,
+0x3b, 0x41, 0x75, 0x67, 0x75, 0x73, 0x63, 0x68, 0x74, 0x3b, 0x53, 0x65,
+0x70, 0x74, 0xe4, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f,
+0x6f, 0x62, 0x65, 0x72, 0x3b, 0x4e, 0x6f, 0x76, 0xe4, 0x6d, 0x62, 0x65,
+0x72, 0x3b, 0x44, 0x65, 0x7a, 0xe4, 0x6d, 0x62, 0x65, 0x72, 0x71f, 0x722,
+0x718, 0x722, 0x20, 0x710, 0x71a, 0x72a, 0x71d, 0x710, 0x3b, 0x72b, 0x712, 0x71b,
+0x3b, 0x710, 0x715, 0x72a, 0x3b, 0x722, 0x71d, 0x723, 0x722, 0x3b, 0x710, 0x71d,
+0x72a, 0x3b, 0x71a, 0x719, 0x71d, 0x72a, 0x722, 0x3b, 0x72c, 0x721, 0x718, 0x719,
+0x3b, 0x710, 0x712, 0x3b, 0x710, 0x71d, 0x720, 0x718, 0x720, 0x3b, 0x72c, 0x72b,
+0x72a, 0x71d, 0x722, 0x20, 0x729, 0x715, 0x721, 0x71d, 0x710, 0x3b, 0x72c, 0x72b,
+0x72a, 0x71d, 0x722, 0x20, 0x710, 0x71a, 0x72a, 0x71d, 0x710, 0x3b, 0x71f, 0x722,
+0x718, 0x722, 0x20, 0x729, 0x715, 0x721, 0x71d, 0x710, 0x71f, 0x722, 0x718, 0x722,
+0x20, 0x712, 0x3b, 0x72b, 0x712, 0x71b, 0x3b, 0x710, 0x715, 0x72a, 0x3b, 0x722,
+0x71d, 0x723, 0x722, 0x3b, 0x710, 0x71d, 0x72a, 0x3b, 0x71a, 0x719, 0x71d, 0x72a,
+0x722, 0x3b, 0x72c, 0x721, 0x718, 0x719, 0x3b, 0x710, 0x712, 0x3b, 0x710, 0x71d,
+0x720, 0x718, 0x720, 0x3b, 0x72c, 0x72b, 0x72a, 0x71d, 0x722, 0x20, 0x710, 0x3b,
+0x72c, 0x72b, 0x72a, 0x71d, 0x722, 0x20, 0x712, 0x3b, 0x71f, 0x722, 0x718, 0x722,
+0x20, 0x710, 0x71f, 0x3b, 0x72b, 0x3b, 0x710, 0x3b, 0x722, 0x3b, 0x710, 0x3b,
+0x72c, 0x3b, 0x71a, 0x3b, 0x710, 0x3b, 0x710, 0x3b, 0x72c, 0x3b, 0x72c, 0x3b,
+0x71f, 0x71f, 0x3b, 0x72b, 0x3b, 0x710, 0x3b, 0x722, 0x3b, 0x710, 0x3b, 0x71a,
+0x3b, 0x72c, 0x3b, 0x710, 0x3b, 0x710, 0x3b, 0x72c, 0x3b, 0x72c, 0x3b, 0x71f,
+0x69, 0x6e, 0x6e, 0x61, 0x79, 0x72, 0x3b, 0x62, 0x1e5b, 0x61, 0x79, 0x1e5b,
+0x3b, 0x6d, 0x61, 0x1e5b, 0x1e63, 0x3b, 0x69, 0x62, 0x72, 0x69, 0x72, 0x3b,
+0x6d, 0x61, 0x79, 0x79, 0x75, 0x3b, 0x79, 0x75, 0x6e, 0x79, 0x75, 0x3b,
+0x79, 0x75, 0x6c, 0x79, 0x75, 0x7a, 0x3b, 0x263, 0x75, 0x63, 0x74, 0x3b,
+0x63, 0x75, 0x74, 0x61, 0x6e, 0x62, 0x69, 0x72, 0x3b, 0x6b, 0x74, 0x75,
+0x62, 0x72, 0x3b, 0x6e, 0x75, 0x77, 0x61, 0x6e, 0x62, 0x69, 0x72, 0x3b,
+0x64, 0x75, 0x6a, 0x61, 0x6e, 0x62, 0x69, 0x72, 0x69, 0x6e, 0x6e, 0x3b,
+0x62, 0x1e5b, 0x61, 0x3b, 0x6d, 0x61, 0x1e5b, 0x3b, 0x69, 0x62, 0x72, 0x3b,
+0x6d, 0x61, 0x79, 0x3b, 0x79, 0x75, 0x6e, 0x3b, 0x79, 0x75, 0x6c, 0x3b,
+0x263, 0x75, 0x63, 0x3b, 0x63, 0x75, 0x74, 0x3b, 0x6b, 0x74, 0x75, 0x3b,
+0x6e, 0x75, 0x77, 0x3b, 0x64, 0x75, 0x6a, 0x69, 0x3b, 0x62, 0x3b, 0x6d,
+0x3b, 0x69, 0x3b, 0x6d, 0x3b, 0x79, 0x3b, 0x79, 0x3b, 0x263, 0x3b, 0x63,
+0x3b, 0x6b, 0x3b, 0x6e, 0x3b, 0x64, 0x4d, 0x6f, 0x72, 0x69, 0x20, 0x67,
+0x68, 0x77, 0x61, 0x20, 0x69, 0x6d, 0x62, 0x69, 0x72, 0x69, 0x3b, 0x4d,
+0x6f, 0x72, 0x69, 0x20, 0x67, 0x68, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x77,
+0x69, 0x3b, 0x4d, 0x6f, 0x72, 0x69, 0x20, 0x67, 0x68, 0x77, 0x61, 0x20,
+0x6b, 0x61, 0x64, 0x61, 0x64, 0x75, 0x3b, 0x4d, 0x6f, 0x72, 0x69, 0x20,
+0x67, 0x68, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x6e, 0x61, 0x3b, 0x4d, 0x6f,
+0x72, 0x69, 0x20, 0x67, 0x68, 0x77, 0x61, 0x20, 0x6b, 0x61, 0x73, 0x61,
+0x6e, 0x75, 0x3b, 0x4d, 0x6f, 0x72, 0x69, 0x20, 0x67, 0x68, 0x77, 0x61,
+0x20, 0x6b, 0x61, 0x72, 0x61, 0x6e, 0x64, 0x61, 0x64, 0x75, 0x3b, 0x4d,
+0x6f, 0x72, 0x69, 0x20, 0x67, 0x68, 0x77, 0x61, 0x20, 0x6d, 0x66, 0x75,
+0x6e, 0x67, 0x61, 0x64, 0x65, 0x3b, 0x4d, 0x6f, 0x72, 0x69, 0x20, 0x67,
+0x68, 0x77, 0x61, 0x20, 0x77, 0x75, 0x6e, 0x79, 0x61, 0x6e, 0x79, 0x61,
+0x3b, 0x4d, 0x6f, 0x72, 0x69, 0x20, 0x67, 0x68, 0x77, 0x61, 0x20, 0x69,
+0x6b, 0x65, 0x6e, 0x64, 0x61, 0x3b, 0x4d, 0x6f, 0x72, 0x69, 0x20, 0x67,
+0x68, 0x77, 0x61, 0x20, 0x69, 0x6b, 0x75, 0x6d, 0x69, 0x3b, 0x4d, 0x6f,
+0x72, 0x69, 0x20, 0x67, 0x68, 0x77, 0x61, 0x20, 0x69, 0x6b, 0x75, 0x6d,
+0x69, 0x20, 0x6e, 0x61, 0x20, 0x69, 0x6d, 0x77, 0x65, 0x72, 0x69, 0x3b,
+0x4d, 0x6f, 0x72, 0x69, 0x20, 0x67, 0x68, 0x77, 0x61, 0x20, 0x69, 0x6b,
+0x75, 0x6d, 0x69, 0x20, 0x6e, 0x61, 0x20, 0x69, 0x77, 0x69, 0x49, 0x6d,
+0x62, 0x3b, 0x4b, 0x61, 0x77, 0x3b, 0x4b, 0x61, 0x64, 0x3b, 0x4b, 0x61,
+0x6e, 0x3b, 0x4b, 0x61, 0x73, 0x3b, 0x4b, 0x61, 0x72, 0x3b, 0x4d, 0x66,
+0x75, 0x3b, 0x57, 0x75, 0x6e, 0x3b, 0x49, 0x6b, 0x65, 0x3b, 0x49, 0x6b,
+0x75, 0x3b, 0x49, 0x6d, 0x77, 0x3b, 0x49, 0x77, 0x69, 0x49, 0x3b, 0x4b,
+0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x4b, 0x3b, 0x4d, 0x3b, 0x57,
+0x3b, 0x49, 0x3b, 0x49, 0x3b, 0x49, 0x3b, 0x49, 0x42f, 0x43d, 0x432, 0x430,
+0x440, 0x3b, 0x424, 0x435, 0x432, 0x440, 0x430, 0x43b, 0x3b, 0x41c, 0x430, 0x440,
+0x442, 0x3b, 0x410, 0x43f, 0x440, 0x435, 0x43b, 0x3b, 0x41c, 0x430, 0x439, 0x3b,
+0x418, 0x44e, 0x43d, 0x3b, 0x418, 0x44e, 0x43b, 0x3b, 0x410, 0x432, 0x433, 0x443,
+0x441, 0x442, 0x3b, 0x421, 0x435, 0x43d, 0x442, 0x44f, 0x431, 0x440, 0x3b, 0x41e,
+0x43a, 0x442, 0x44f, 0x431, 0x440, 0x3b, 0x41d, 0x43e, 0x44f, 0x431, 0x440, 0x3b,
+0x414, 0x435, 0x43a, 0x430, 0x431, 0x440, 0xb9c, 0xba9, 0xbb5, 0xbb0, 0xbbf, 0x3b,
+0xbaa, 0xbbf, 0xbaa, 0xbcd, 0xbb0, 0xbb5, 0xbb0, 0xbbf, 0x3b, 0xbae, 0xbbe, 0xbb0,
+0xbcd, 0xb9a, 0xbcd, 0x3b, 0xb8f, 0xbaa, 0xbcd, 0xbb0, 0xbb2, 0xbcd, 0x3b, 0xbae,
+0xbc7, 0x3b, 0xb9c, 0xbc2, 0xba9, 0xbcd, 0x3b, 0xb9c, 0xbc2, 0xbb2, 0xbc8, 0x3b,
+0xb86, 0xb95, 0xbb8, 0xbcd, 0xb9f, 0xbcd, 0x3b, 0xb9a, 0xbc6, 0xbaa, 0xbcd, 0xb9f,
+0xbae, 0xbcd, 0xbaa, 0xbb0, 0xbcd, 0x3b, 0xb85, 0xb95, 0xbcd, 0xb9f, 0xbcb, 0xbaa,
+0xbb0, 0xbcd, 0x3b, 0xba8, 0xbb5, 0xbae, 0xbcd, 0xbaa, 0xbb0, 0xbcd, 0x3b, 0xb9f,
+0xbbf, 0xb9a, 0xbae, 0xbcd, 0xbaa, 0xbb0, 0xbcd, 0xb9c, 0xba9, 0x2e, 0x3b, 0xbaa,
+0xbbf, 0xbaa, 0xbcd, 0x2e, 0x3b, 0xbae, 0xbbe, 0xbb0, 0xbcd, 0x2e, 0x3b, 0xb8f,
+0xbaa, 0xbcd, 0x2e, 0x3b, 0xbae, 0xbc7, 0x3b, 0xb9c, 0xbc2, 0xba9, 0xbcd, 0x3b,
+0xb9c, 0xbc2, 0xbb2, 0xbc8, 0x3b, 0xb86, 0xb95, 0x2e, 0x3b, 0xb9a, 0xbc6, 0xbaa,
+0xbcd, 0x2e, 0x3b, 0xb85, 0xb95, 0xbcd, 0x2e, 0x3b, 0xba8, 0xbb5, 0x2e, 0x3b,
+0xb9f, 0xbbf, 0xb9a, 0x2e, 0xb9c, 0x3b, 0xbaa, 0xbbf, 0x3b, 0xbae, 0xbbe, 0x3b,
+0xb8f, 0x3b, 0xbae, 0xbc7, 0x3b, 0xb9c, 0xbc2, 0x3b, 0xb9c, 0xbc2, 0x3b, 0xb86,
+0x3b, 0xb9a, 0xbc6, 0x3b, 0xb85, 0x3b, 0xba8, 0x3b, 0xb9f, 0xbbf, 0x4b, 0x69,
+0x6e, 0x67, 0x61, 0x6c, 0x20, 0x69, 0x64, 0x61, 0x73, 0x3b, 0x44, 0x68,
+0x61, 0x20, 0x69, 0x64, 0x61, 0x73, 0x3b, 0x54, 0x72, 0x75, 0x20, 0x69,
+0x64, 0x61, 0x73, 0x3b, 0x53, 0x70, 0x61, 0x74, 0x20, 0x69, 0x64, 0x61,
+0x73, 0x3b, 0x52, 0x69, 0x6d, 0x61, 0x20, 0x69, 0x64, 0x61, 0x73, 0x3b,
+0x4d, 0x61, 0x74, 0x61, 0x72, 0x75, 0x20, 0x69, 0x64, 0x61, 0x73, 0x3b,
+0x45, 0x6d, 0x70, 0x69, 0x74, 0x75, 0x20, 0x69, 0x64, 0x61, 0x73, 0x3b,
+0x4d, 0x61, 0x73, 0x70, 0x61, 0x74, 0x20, 0x69, 0x64, 0x61, 0x73, 0x3b,
+0x4d, 0x6e, 0x67, 0x61, 0x72, 0x69, 0x20, 0x69, 0x64, 0x61, 0x73, 0x3b,
+0x4d, 0x61, 0x78, 0x61, 0x6c, 0x20, 0x69, 0x64, 0x61, 0x73, 0x3b, 0x4d,
+0x61, 0x78, 0x61, 0x6c, 0x20, 0x6b, 0x69, 0x6e, 0x67, 0x61, 0x6c, 0x20,
+0x69, 0x64, 0x61, 0x73, 0x3b, 0x4d, 0x61, 0x78, 0x61, 0x6c, 0x20, 0x64,
+0x68, 0x61, 0x20, 0x69, 0x64, 0x61, 0x73, 0x4b, 0x69, 0x69, 0x3b, 0x44,
+0x68, 0x69, 0x3b, 0x54, 0x72, 0x69, 0x3b, 0x53, 0x70, 0x69, 0x3b, 0x52,
+0x69, 0x69, 0x3b, 0x4d, 0x74, 0x69, 0x3b, 0x45, 0x6d, 0x69, 0x3b, 0x4d,
+0x61, 0x69, 0x3b, 0x4d, 0x6e, 0x69, 0x3b, 0x4d, 0x78, 0x69, 0x3b, 0x4d,
+0x78, 0x6b, 0x3b, 0x4d, 0x78, 0x64, 0x4b, 0x3b, 0x44, 0x3b, 0x54, 0x3b,
+0x53, 0x3b, 0x52, 0x3b, 0x4d, 0x3b, 0x45, 0x3b, 0x50, 0x3b, 0x41, 0x3b,
+0x4d, 0x3b, 0x4b, 0x3b, 0x44, 0x433, 0x44b, 0x439, 0x43d, 0x432, 0x430, 0x440,
+0x3b, 0x444, 0x435, 0x432, 0x440, 0x430, 0x43b, 0x44c, 0x3b, 0x43c, 0x430, 0x440,
+0x442, 0x3b, 0x430, 0x43f, 0x440, 0x435, 0x43b, 0x44c, 0x3b, 0x43c, 0x430, 0x439,
+0x3b, 0x438, 0x44e, 0x43d, 0x44c, 0x3b, 0x438, 0x44e, 0x43b, 0x44c, 0x3b, 0x430,
+0x432, 0x433, 0x443, 0x441, 0x442, 0x3b, 0x441, 0x435, 0x43d, 0x442, 0x44f, 0x431,
+0x440, 0x44c, 0x3b, 0x43e, 0x43a, 0x442, 0x44f, 0x431, 0x440, 0x44c, 0x3b, 0x43d,
+0x43e, 0x44f, 0x431, 0x440, 0x44c, 0x3b, 0x434, 0x435, 0x43a, 0x430, 0x431, 0x440,
+0x44c, 0x433, 0x44b, 0x439, 0x43d, 0x2e, 0x3b, 0x444, 0x435, 0x432, 0x2e, 0x3b,
+0x43c, 0x430, 0x440, 0x2e, 0x3b, 0x430, 0x43f, 0x440, 0x2e, 0x3b, 0x43c, 0x430,
+0x439, 0x3b, 0x438, 0x44e, 0x43d, 0x44c, 0x3b, 0x438, 0x44e, 0x43b, 0x44c, 0x3b,
+0x430, 0x432, 0x433, 0x2e, 0x3b, 0x441, 0x435, 0x43d, 0x442, 0x2e, 0x3b, 0x43e,
+0x43a, 0x442, 0x2e, 0x3b, 0x43d, 0x43e, 0x44f, 0x431, 0x2e, 0x3b, 0x434, 0x435,
+0x43a, 0x2e, 0xc1c, 0xc28, 0xc35, 0xc30, 0xc3f, 0x3b, 0xc2b, 0xc3f, 0xc2c, 0xc4d,
+0xc30, 0xc35, 0xc30, 0xc3f, 0x3b, 0xc2e, 0xc3e, 0xc30, 0xc4d, 0xc1a, 0xc3f, 0x3b,
+0xc0f, 0xc2a, 0xc4d, 0xc30, 0xc3f, 0xc32, 0xc4d, 0x3b, 0xc2e, 0xc47, 0x3b, 0xc1c,
+0xc42, 0xc28, 0xc4d, 0x3b, 0xc1c, 0xc41, 0xc32, 0xc48, 0x3b, 0xc06, 0xc17, 0xc38,
+0xc4d, 0xc1f, 0xc41, 0x3b, 0xc38, 0xc46, 0xc2a, 0xc4d, 0xc1f, 0xc46, 0xc02, 0xc2c,
+0xc30, 0xc4d, 0x3b, 0xc05, 0xc15, 0xc4d, 0xc1f, 0xc4b, 0xc2c, 0xc30, 0xc4d, 0x3b,
+0xc28, 0xc35, 0xc02, 0xc2c, 0xc30, 0xc4d, 0x3b, 0xc21, 0xc3f, 0xc38, 0xc46, 0xc02,
+0xc2c, 0xc30, 0xc4d, 0xc1c, 0xc28, 0x3b, 0xc2b, 0xc3f, 0xc2c, 0xc4d, 0xc30, 0x3b,
+0xc2e, 0xc3e, 0xc30, 0xc4d, 0xc1a, 0xc3f, 0x3b, 0xc0f, 0xc2a, 0xc4d, 0xc30, 0xc3f,
+0x3b, 0xc2e, 0xc47, 0x3b, 0xc1c, 0xc42, 0xc28, 0xc4d, 0x3b, 0xc1c, 0xc41, 0xc32,
+0xc48, 0x3b, 0xc06, 0xc17, 0x3b, 0xc38, 0xc46, 0xc2a, 0xc4d, 0xc1f, 0xc46, 0xc02,
+0x3b, 0xc05, 0xc15, 0xc4d, 0xc1f, 0xc4b, 0x3b, 0xc28, 0xc35, 0xc02, 0x3b, 0xc21,
+0xc3f, 0xc38, 0xc46, 0xc02, 0xc1c, 0x3b, 0xc2b, 0xc3f, 0x3b, 0xc2e, 0xc3e, 0x3b,
+0xc0f, 0x3b, 0xc2e, 0xc47, 0x3b, 0xc1c, 0xc42, 0x3b, 0xc1c, 0xc41, 0x3b, 0xc06,
+0x3b, 0xc38, 0xc46, 0x3b, 0xc05, 0x3b, 0xc28, 0x3b, 0xc21, 0xc3f, 0x4f, 0x72,
+0x61, 0x72, 0x61, 0x3b, 0x4f, 0x6d, 0x75, 0x6b, 0x3b, 0x4f, 0x6b, 0x77,
+0x61, 0x6d, 0x67, 0x2019, 0x3b, 0x4f, 0x64, 0x75, 0x6e, 0x67, 0x2019, 0x65,
+0x6c, 0x3b, 0x4f, 0x6d, 0x61, 0x72, 0x75, 0x6b, 0x3b, 0x4f, 0x6d, 0x6f,
+0x64, 0x6f, 0x6b, 0x2019, 0x6b, 0x69, 0x6e, 0x67, 0x2019, 0x6f, 0x6c, 0x3b,
+0x4f, 0x6a, 0x6f, 0x6c, 0x61, 0x3b, 0x4f, 0x70, 0x65, 0x64, 0x65, 0x6c,
+0x3b, 0x4f, 0x73, 0x6f, 0x6b, 0x6f, 0x73, 0x6f, 0x6b, 0x6f, 0x6d, 0x61,
+0x3b, 0x4f, 0x74, 0x69, 0x62, 0x61, 0x72, 0x3b, 0x4f, 0x6c, 0x61, 0x62,
+0x6f, 0x72, 0x3b, 0x4f, 0x70, 0x6f, 0x6f, 0x52, 0x61, 0x72, 0x3b, 0x4d,
+0x75, 0x6b, 0x3b, 0x4b, 0x77, 0x61, 0x3b, 0x44, 0x75, 0x6e, 0x3b, 0x4d,
+0x61, 0x72, 0x3b, 0x4d, 0x6f, 0x64, 0x3b, 0x4a, 0x6f, 0x6c, 0x3b, 0x50,
+0x65, 0x64, 0x3b, 0x53, 0x6f, 0x6b, 0x3b, 0x54, 0x69, 0x62, 0x3b, 0x4c,
+0x61, 0x62, 0x3b, 0x50, 0x6f, 0x6f, 0x52, 0x3b, 0x4d, 0x3b, 0x4b, 0x3b,
+0x44, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x50, 0x3b, 0x53, 0x3b,
+0x54, 0x3b, 0x4c, 0x3b, 0x50, 0xe21, 0xe01, 0xe23, 0xe32, 0xe04, 0xe21, 0x3b,
+0xe01, 0xe38, 0xe21, 0xe20, 0xe32, 0xe1e, 0xe31, 0xe19, 0xe18, 0xe4c, 0x3b, 0xe21,
+0xe35, 0xe19, 0xe32, 0xe04, 0xe21, 0x3b, 0xe40, 0xe21, 0xe29, 0xe32, 0xe22, 0xe19,
+0x3b, 0xe1e, 0xe24, 0xe29, 0xe20, 0xe32, 0xe04, 0xe21, 0x3b, 0xe21, 0xe34, 0xe16,
+0xe38, 0xe19, 0xe32, 0xe22, 0xe19, 0x3b, 0xe01, 0xe23, 0xe01, 0xe0e, 0xe32, 0xe04,
+0xe21, 0x3b, 0xe2a, 0xe34, 0xe07, 0xe2b, 0xe32, 0xe04, 0xe21, 0x3b, 0xe01, 0xe31,
+0xe19, 0xe22, 0xe32, 0xe22, 0xe19, 0x3b, 0xe15, 0xe38, 0xe25, 0xe32, 0xe04, 0xe21,
+0x3b, 0xe1e, 0xe24, 0xe28, 0xe08, 0xe34, 0xe01, 0xe32, 0xe22, 0xe19, 0x3b, 0xe18,
+0xe31, 0xe19, 0xe27, 0xe32, 0xe04, 0xe21, 0xe21, 0x2e, 0xe04, 0x2e, 0x3b, 0xe01,
+0x2e, 0xe1e, 0x2e, 0x3b, 0xe21, 0xe35, 0x2e, 0xe04, 0x2e, 0x3b, 0xe40, 0xe21,
+0x2e, 0xe22, 0x2e, 0x3b, 0xe1e, 0x2e, 0xe04, 0x2e, 0x3b, 0xe21, 0xe34, 0x2e,
+0xe22, 0x2e, 0x3b, 0xe01, 0x2e, 0xe04, 0x2e, 0x3b, 0xe2a, 0x2e, 0xe04, 0x2e,
+0x3b, 0xe01, 0x2e, 0xe22, 0x2e, 0x3b, 0xe15, 0x2e, 0xe04, 0x2e, 0x3b, 0xe1e,
+0x2e, 0xe22, 0x2e, 0x3b, 0xe18, 0x2e, 0xe04, 0x2e, 0xf5f, 0xfb3, 0xf0b, 0xf56,
+0xf0b, 0xf51, 0xf44, 0xf0b, 0xf54, 0xf7c, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56,
+0xf0b, 0xf42, 0xf49, 0xf72, 0xf66, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b,
+0xf56, 0xf0b, 0xf42, 0xf66, 0xf74, 0xf58, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3,
+0xf0b, 0xf56, 0xf0b, 0xf56, 0xf5e, 0xf72, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3,
+0xf0b, 0xf56, 0xf0b, 0xf63, 0xf94, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b,
+0xf56, 0xf0b, 0xf51, 0xfb2, 0xf74, 0xf42, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3,
+0xf0b, 0xf56, 0xf0b, 0xf56, 0xf51, 0xf74, 0xf53, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f,
+0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf56, 0xf62, 0xf92, 0xfb1, 0xf51, 0xf0b, 0xf54, 0xf0b,
+0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf51, 0xf42, 0xf74, 0xf0b, 0xf54, 0xf0b,
+0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf56, 0xf45, 0xf74, 0xf0b, 0xf54, 0xf0b,
+0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf56, 0xf45, 0xf74, 0xf0b, 0xf42, 0xf45,
+0xf72, 0xf42, 0xf0b, 0xf54, 0xf0b, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf56,
+0xf45, 0xf74, 0xf0b, 0xf42, 0xf49, 0xf72, 0xf66, 0xf0b, 0xf54, 0xf0b, 0xf5f, 0xfb3,
+0xf0b, 0xf56, 0xf0b, 0xf51, 0xf44, 0xf0b, 0xf54, 0xf7c, 0x3b, 0xf5f, 0xfb3, 0xf0b,
+0xf56, 0xf0b, 0xf42, 0xf49, 0xf72, 0xf66, 0xf0b, 0xf54, 0x3b, 0xf5f, 0xfb3, 0xf0b,
+0xf56, 0xf0b, 0xf42, 0xf66, 0xf74, 0xf58, 0xf0b, 0xf54, 0x3b, 0xf5f, 0xfb3, 0xf0b,
+0xf56, 0xf0b, 0xf56, 0xf5e, 0xf72, 0xf0b, 0xf54, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56,
+0xf0b, 0xf63, 0xf94, 0xf0b, 0xf54, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf51,
+0xfb2, 0xf74, 0xf42, 0xf0b, 0xf54, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf56,
+0xf51, 0xf74, 0xf53, 0xf0b, 0xf54, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf56,
+0xf62, 0xf92, 0xfb1, 0xf51, 0xf0b, 0xf54, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b,
+0xf51, 0xf42, 0xf74, 0xf0b, 0xf54, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf56,
+0xf45, 0xf74, 0xf0b, 0xf54, 0x3b, 0xf5f, 0xfb3, 0xf0b, 0xf56, 0xf0b, 0xf56, 0xf45,
+0xf74, 0xf0b, 0xf42, 0xf45, 0xf72, 0xf42, 0xf0b, 0xf54, 0x3b, 0xf5f, 0xfb3, 0xf0b,
+0xf56, 0xf0b, 0xf56, 0xf45, 0xf74, 0xf0b, 0xf42, 0xf49, 0xf72, 0xf66, 0xf0b, 0xf54,
+0x1303, 0x1295, 0x12e9, 0x12c8, 0x122a, 0x3b, 0x134c, 0x1265, 0x1229, 0x12c8, 0x122a, 0x3b,
+0x121b, 0x122d, 0x127d, 0x3b, 0x12a4, 0x1355, 0x1228, 0x120d, 0x3b, 0x121c, 0x12ed, 0x3b,
+0x1301, 0x1295, 0x3b, 0x1301, 0x120b, 0x12ed, 0x3b, 0x12a6, 0x1308, 0x1235, 0x1275, 0x3b,
+0x1234, 0x1355, 0x1274, 0x121d, 0x1260, 0x122d, 0x3b, 0x12a6, 0x12ad, 0x1270, 0x12cd, 0x1260,
+0x122d, 0x3b, 0x1296, 0x126c, 0x121d, 0x1260, 0x122d, 0x3b, 0x12f2, 0x1234, 0x121d, 0x1260,
+0x122d, 0x1303, 0x1295, 0x12e9, 0x3b, 0x134c, 0x1265, 0x1229, 0x3b, 0x121b, 0x122d, 0x127d,
+0x3b, 0x12a4, 0x1355, 0x1228, 0x3b, 0x121c, 0x12ed, 0x3b, 0x1301, 0x1295, 0x3b, 0x1301,
+0x120b, 0x12ed, 0x3b, 0x12a6, 0x1308, 0x1235, 0x3b, 0x1234, 0x1355, 0x1274, 0x3b, 0x12a6,
+0x12ad, 0x1270, 0x3b, 0x1296, 0x126c, 0x121d, 0x3b, 0x12f2, 0x1234, 0x121d, 0x1325, 0x122a,
+0x3b, 0x1208, 0x12ab, 0x1272, 0x1275, 0x3b, 0x1218, 0x130b, 0x1262, 0x1275, 0x3b, 0x121a,
+0x12eb, 0x12dd, 0x12eb, 0x3b, 0x130d, 0x1295, 0x1266, 0x1275, 0x3b, 0x1230, 0x1290, 0x3b,
+0x1213, 0x121d, 0x1208, 0x3b, 0x1290, 0x1213, 0x1230, 0x3b, 0x1218, 0x1235, 0x12a8, 0x1228,
+0x121d, 0x3b, 0x1325, 0x1245, 0x121d, 0x1272, 0x3b, 0x1215, 0x12f3, 0x122d, 0x3b, 0x1273,
+0x1215, 0x1233, 0x1235, 0x1325, 0x122a, 0x3b, 0x1208, 0x12ab, 0x3b, 0x1218, 0x130b, 0x3b,
+0x121a, 0x12eb, 0x3b, 0x130d, 0x1295, 0x3b, 0x1230, 0x1290, 0x3b, 0x1213, 0x121d, 0x3b,
+0x1290, 0x1213, 0x3b, 0x1218, 0x1235, 0x3b, 0x1325, 0x1245, 0x3b, 0x1215, 0x12f3, 0x3b,
+0x1273, 0x1215, 0x1325, 0x3b, 0x1208, 0x3b, 0x1218, 0x3b, 0x121a, 0x3b, 0x130d, 0x3b,
+0x1230, 0x3b, 0x1213, 0x3b, 0x1290, 0x3b, 0x1218, 0x3b, 0x1325, 0x3b, 0x1215, 0x3b,
+0x1273, 0x4a, 0x61, 0x6e, 0x75, 0x65, 0x72, 0x69, 0x3b, 0x46, 0x65, 0x62,
+0x72, 0x75, 0x65, 0x72, 0x69, 0x3b, 0x4d, 0x61, 0x73, 0x3b, 0x45, 0x70,
+0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x65, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a,
+0x75, 0x6c, 0x61, 0x69, 0x3b, 0x4f, 0x67, 0x61, 0x73, 0x3b, 0x53, 0x65,
+0x70, 0x74, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62,
+0x61, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x44, 0x65,
+0x73, 0x65, 0x6d, 0x62, 0x61, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62,
+0x3b, 0x4d, 0x61, 0x73, 0x3b, 0x45, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x3b,
+0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x4f, 0x67, 0x61, 0x3b,
+0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b,
+0x44, 0x65, 0x73, 0x53, 0x101, 0x6e, 0x75, 0x61, 0x6c, 0x69, 0x3b, 0x46,
+0x113, 0x70, 0x75, 0x65, 0x6c, 0x69, 0x3b, 0x4d, 0x61, 0x2bb, 0x61, 0x73,
+0x69, 0x3b, 0x2bb, 0x45, 0x70, 0x65, 0x6c, 0x65, 0x6c, 0x69, 0x3b, 0x4d,
+0x113, 0x3b, 0x53, 0x75, 0x6e, 0x65, 0x3b, 0x53, 0x69, 0x75, 0x6c, 0x61,
+0x69, 0x3b, 0x2bb, 0x41, 0x6f, 0x6b, 0x6f, 0x73, 0x69, 0x3b, 0x53, 0x65,
+0x70, 0x69, 0x74, 0x65, 0x6d, 0x61, 0x3b, 0x2bb, 0x4f, 0x6b, 0x61, 0x74,
+0x6f, 0x70, 0x61, 0x3b, 0x4e, 0x14d, 0x76, 0x65, 0x6d, 0x61, 0x3b, 0x54,
+0x12b, 0x73, 0x65, 0x6d, 0x61, 0x53, 0x101, 0x6e, 0x75, 0x61, 0x6c, 0x69,
+0x3b, 0x46, 0x113, 0x70, 0x75, 0x65, 0x6c, 0x69, 0x3b, 0x4d, 0x61, 0x2bb,
+0x61, 0x73, 0x69, 0x3b, 0x2bb, 0x45, 0x70, 0x65, 0x6c, 0x65, 0x6c, 0x69,
+0x3b, 0x4d, 0x113, 0x3b, 0x53, 0x75, 0x6e, 0x65, 0x3b, 0x53, 0x69, 0x75,
+0x6c, 0x61, 0x69, 0x3b, 0x2bb, 0x41, 0x6f, 0x6b, 0x6f, 0x73, 0x69, 0x3b,
+0x53, 0x113, 0x70, 0x69, 0x74, 0x65, 0x6d, 0x61, 0x3b, 0x2bb, 0x4f, 0x6b,
+0x61, 0x74, 0x6f, 0x70, 0x61, 0x3b, 0x4e, 0x14d, 0x76, 0x65, 0x6d, 0x61,
+0x3b, 0x54, 0x12b, 0x73, 0x65, 0x6d, 0x61, 0x53, 0x101, 0x6e, 0x3b, 0x46,
+0x113, 0x70, 0x3b, 0x4d, 0x61, 0x2bb, 0x61, 0x3b, 0x2bb, 0x45, 0x70, 0x65,
+0x3b, 0x4d, 0x113, 0x3b, 0x53, 0x75, 0x6e, 0x3b, 0x53, 0x69, 0x75, 0x3b,
+0x2bb, 0x41, 0x6f, 0x6b, 0x3b, 0x53, 0x113, 0x70, 0x3b, 0x2bb, 0x4f, 0x6b,
+0x61, 0x3b, 0x4e, 0x14d, 0x76, 0x3b, 0x54, 0x12b, 0x73, 0x53, 0x3b, 0x46,
+0x3b, 0x4d, 0x3b, 0x2bb, 0x45, 0x3b, 0x4d, 0x3b, 0x53, 0x3b, 0x53, 0x3b,
+0x2bb, 0x41, 0x3b, 0x53, 0x3b, 0x2bb, 0x4f, 0x3b, 0x4e, 0x3b, 0x54, 0x53,
+0x75, 0x6e, 0x67, 0x75, 0x74, 0x69, 0x3b, 0x4e, 0x79, 0x65, 0x6e, 0x79,
+0x65, 0x6e, 0x79, 0x61, 0x6e, 0x69, 0x3b, 0x4e, 0x79, 0x65, 0x6e, 0x79,
+0x61, 0x6e, 0x6b, 0x75, 0x6c, 0x75, 0x3b, 0x44, 0x7a, 0x69, 0x76, 0x61,
+0x6d, 0x69, 0x73, 0x6f, 0x6b, 0x6f, 0x3b, 0x4d, 0x75, 0x64, 0x79, 0x61,
+0x78, 0x69, 0x68, 0x69, 0x3b, 0x4b, 0x68, 0x6f, 0x74, 0x61, 0x76, 0x75,
+0x78, 0x69, 0x6b, 0x61, 0x3b, 0x4d, 0x61, 0x77, 0x75, 0x77, 0x61, 0x6e,
+0x69, 0x3b, 0x4d, 0x68, 0x61, 0x77, 0x75, 0x72, 0x69, 0x3b, 0x4e, 0x64,
+0x7a, 0x68, 0x61, 0x74, 0x69, 0x3b, 0x4e, 0x68, 0x6c, 0x61, 0x6e, 0x67,
+0x75, 0x6c, 0x61, 0x3b, 0x48, 0x75, 0x6b, 0x75, 0x72, 0x69, 0x3b, 0x4e,
+0x2019, 0x77, 0x65, 0x6e, 0x64, 0x7a, 0x61, 0x6d, 0x68, 0x61, 0x6c, 0x61,
+0x53, 0x75, 0x6e, 0x3b, 0x59, 0x61, 0x6e, 0x3b, 0x4b, 0x75, 0x6c, 0x3b,
+0x44, 0x7a, 0x69, 0x3b, 0x4d, 0x75, 0x64, 0x3b, 0x4b, 0x68, 0x6f, 0x3b,
+0x4d, 0x61, 0x77, 0x3b, 0x4d, 0x68, 0x61, 0x3b, 0x4e, 0x64, 0x7a, 0x3b,
+0x4e, 0x68, 0x6c, 0x3b, 0x48, 0x75, 0x6b, 0x3b, 0x4e, 0x2019, 0x77, 0x46,
+0x65, 0x72, 0x69, 0x6b, 0x67, 0x6f, 0x6e, 0x67, 0x3b, 0x54, 0x6c, 0x68,
+0x61, 0x6b, 0x6f, 0x6c, 0x65, 0x3b, 0x4d, 0x6f, 0x70, 0x69, 0x74, 0x6c,
+0x6f, 0x3b, 0x4d, 0x6f, 0x72, 0x61, 0x6e, 0x61, 0x6e, 0x67, 0x3b, 0x4d,
+0x6f, 0x74, 0x73, 0x68, 0x65, 0x67, 0x61, 0x6e, 0x61, 0x6e, 0x67, 0x3b,
+0x53, 0x65, 0x65, 0x74, 0x65, 0x62, 0x6f, 0x73, 0x69, 0x67, 0x6f, 0x3b,
+0x50, 0x68, 0x75, 0x6b, 0x77, 0x69, 0x3b, 0x50, 0x68, 0x61, 0x74, 0x77,
+0x65, 0x3b, 0x4c, 0x77, 0x65, 0x74, 0x73, 0x65, 0x3b, 0x44, 0x69, 0x70,
+0x68, 0x61, 0x6c, 0x61, 0x6e, 0x65, 0x3b, 0x4e, 0x67, 0x77, 0x61, 0x6e,
+0x61, 0x74, 0x73, 0x65, 0x6c, 0x65, 0x3b, 0x53, 0x65, 0x64, 0x69, 0x6d,
+0x6f, 0x6e, 0x74, 0x68, 0x6f, 0x6c, 0x65, 0x46, 0x65, 0x72, 0x3b, 0x54,
+0x6c, 0x68, 0x3b, 0x4d, 0x6f, 0x70, 0x3b, 0x4d, 0x6f, 0x72, 0x3b, 0x4d,
+0x6f, 0x74, 0x3b, 0x53, 0x65, 0x65, 0x3b, 0x50, 0x68, 0x75, 0x3b, 0x50,
+0x68, 0x61, 0x3b, 0x4c, 0x77, 0x65, 0x3b, 0x44, 0x69, 0x70, 0x3b, 0x4e,
+0x67, 0x77, 0x3b, 0x53, 0x65, 0x64, 0x4f, 0x63, 0x61, 0x6b, 0x3b, 0x15e,
+0x75, 0x62, 0x61, 0x74, 0x3b, 0x4d, 0x61, 0x72, 0x74, 0x3b, 0x4e, 0x69,
+0x73, 0x61, 0x6e, 0x3b, 0x4d, 0x61, 0x79, 0x131, 0x73, 0x3b, 0x48, 0x61,
+0x7a, 0x69, 0x72, 0x61, 0x6e, 0x3b, 0x54, 0x65, 0x6d, 0x6d, 0x75, 0x7a,
+0x3b, 0x41, 0x11f, 0x75, 0x73, 0x74, 0x6f, 0x73, 0x3b, 0x45, 0x79, 0x6c,
+0xfc, 0x6c, 0x3b, 0x45, 0x6b, 0x69, 0x6d, 0x3b, 0x4b, 0x61, 0x73, 0x131,
+0x6d, 0x3b, 0x41, 0x72, 0x61, 0x6c, 0x131, 0x6b, 0x4f, 0x63, 0x61, 0x3b,
+0x15e, 0x75, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x4e, 0x69, 0x73, 0x3b,
+0x4d, 0x61, 0x79, 0x3b, 0x48, 0x61, 0x7a, 0x3b, 0x54, 0x65, 0x6d, 0x3b,
+0x41, 0x11f, 0x75, 0x3b, 0x45, 0x79, 0x6c, 0x3b, 0x45, 0x6b, 0x69, 0x3b,
+0x4b, 0x61, 0x73, 0x3b, 0x41, 0x72, 0x61, 0x4f, 0x3b, 0x15e, 0x3b, 0x4d,
+0x3b, 0x4e, 0x3b, 0x4d, 0x3b, 0x48, 0x3b, 0x54, 0x3b, 0x41, 0x3b, 0x45,
+0x3b, 0x45, 0x3b, 0x4b, 0x3b, 0x41, 0xdd, 0x61, 0x6e, 0x77, 0x61, 0x72,
+0x3b, 0x46, 0x65, 0x77, 0x72, 0x61, 0x6c, 0x3b, 0x4d, 0x61, 0x72, 0x74,
+0x3b, 0x41, 0x70, 0x72, 0x65, 0x6c, 0x3b, 0x4d, 0x61, 0xfd, 0x3b, 0x49,
+0xfd, 0x75, 0x6e, 0x3b, 0x49, 0xfd, 0x75, 0x6c, 0x3b, 0x41, 0x77, 0x67,
+0x75, 0x73, 0x74, 0x3b, 0x53, 0x65, 0x6e, 0x74, 0xfd, 0x61, 0x62, 0x72,
+0x3b, 0x4f, 0x6b, 0x74, 0xfd, 0x61, 0x62, 0x72, 0x3b, 0x4e, 0x6f, 0xfd,
+0x61, 0x62, 0x72, 0x3b, 0x44, 0x65, 0x6b, 0x61, 0x62, 0x72, 0xfd, 0x61,
+0x6e, 0x77, 0x61, 0x72, 0x3b, 0x66, 0x65, 0x77, 0x72, 0x61, 0x6c, 0x3b,
+0x6d, 0x61, 0x72, 0x74, 0x3b, 0x61, 0x70, 0x72, 0x65, 0x6c, 0x3b, 0x6d,
+0x61, 0xfd, 0x3b, 0x69, 0xfd, 0x75, 0x6e, 0x3b, 0x69, 0xfd, 0x75, 0x6c,
+0x3b, 0x61, 0x77, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x6e, 0x74,
+0xfd, 0x61, 0x62, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0xfd, 0x61, 0x62, 0x72,
+0x3b, 0x6e, 0x6f, 0xfd, 0x61, 0x62, 0x72, 0x3b, 0x64, 0x65, 0x6b, 0x61,
+0x62, 0x72, 0xdd, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x77, 0x3b, 0x4d, 0x61,
+0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x61, 0xfd, 0x3b, 0x49, 0xfd,
+0x75, 0x6e, 0x3b, 0x49, 0xfd, 0x75, 0x6c, 0x3b, 0x41, 0x77, 0x67, 0x3b,
+0x53, 0x65, 0x6e, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0xfd, 0x3b,
+0x44, 0x65, 0x6b, 0xfd, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x77, 0x3b, 0x6d,
+0x61, 0x72, 0x74, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d, 0x61, 0xfd, 0x3b,
+0x69, 0xfd, 0x75, 0x6e, 0x3b, 0x69, 0xfd, 0x75, 0x6c, 0x3b, 0x61, 0x77,
+0x67, 0x3b, 0x73, 0x65, 0x6e, 0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e, 0x6f,
+0xfd, 0x3b, 0x64, 0x65, 0x6b, 0xdd, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x41,
+0x3b, 0x4d, 0x3b, 0x49, 0x3b, 0x49, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f,
+0x3b, 0x4e, 0x3b, 0x44, 0x5a, 0x77, 0x61, 0x74, 0x20, 0x4a, 0x75, 0x77,
+0x75, 0x6e, 0x67, 0x3b, 0x5a, 0x77, 0x61, 0x74, 0x20, 0x53, 0x77, 0x69,
+0x79, 0x61, 0x6e, 0x67, 0x3b, 0x5a, 0x77, 0x61, 0x74, 0x20, 0x54, 0x73,
+0x61, 0x74, 0x3b, 0x5a, 0x77, 0x61, 0x74, 0x20, 0x4e, 0x79, 0x61, 0x69,
+0x3b, 0x5a, 0x77, 0x61, 0x74, 0x20, 0x54, 0x73, 0x77, 0x6f, 0x6e, 0x3b,
+0x5a, 0x77, 0x61, 0x74, 0x20, 0x41, 0x74, 0x61, 0x61, 0x68, 0x3b, 0x5a,
+0x77, 0x61, 0x74, 0x20, 0x41, 0x6e, 0x61, 0x74, 0x61, 0x74, 0x3b, 0x5a,
+0x77, 0x61, 0x74, 0x20, 0x41, 0x72, 0x69, 0x6e, 0x61, 0x69, 0x3b, 0x5a,
+0x77, 0x61, 0x74, 0x20, 0x41, 0x6b, 0x75, 0x62, 0x75, 0x6e, 0x79, 0x75,
+0x6e, 0x67, 0x3b, 0x5a, 0x77, 0x61, 0x74, 0x20, 0x53, 0x77, 0x61, 0x67,
+0x3b, 0x5a, 0x77, 0x61, 0x74, 0x20, 0x4d, 0x61, 0x6e, 0x67, 0x6a, 0x75,
+0x77, 0x61, 0x6e, 0x67, 0x3b, 0x5a, 0x77, 0x61, 0x74, 0x20, 0x53, 0x77,
+0x61, 0x67, 0x2d, 0x4d, 0x61, 0x2d, 0x53, 0x75, 0x79, 0x61, 0x6e, 0x67,
+0x4a, 0x75, 0x77, 0x3b, 0x53, 0x77, 0x69, 0x3b, 0x54, 0x73, 0x61, 0x3b,
+0x4e, 0x79, 0x61, 0x3b, 0x54, 0x73, 0x77, 0x3b, 0x41, 0x74, 0x61, 0x3b,
+0x41, 0x6e, 0x61, 0x3b, 0x41, 0x72, 0x69, 0x3b, 0x41, 0x6b, 0x75, 0x3b,
+0x53, 0x77, 0x61, 0x3b, 0x4d, 0x61, 0x6e, 0x3b, 0x4d, 0x61, 0x73, 0x441,
+0x456, 0x447, 0x435, 0x43d, 0x44c, 0x3b, 0x43b, 0x44e, 0x442, 0x438, 0x439, 0x3b,
+0x431, 0x435, 0x440, 0x435, 0x437, 0x435, 0x43d, 0x44c, 0x3b, 0x43a, 0x432, 0x456,
+0x442, 0x435, 0x43d, 0x44c, 0x3b, 0x442, 0x440, 0x430, 0x432, 0x435, 0x43d, 0x44c,
+0x3b, 0x447, 0x435, 0x440, 0x432, 0x435, 0x43d, 0x44c, 0x3b, 0x43b, 0x438, 0x43f,
+0x435, 0x43d, 0x44c, 0x3b, 0x441, 0x435, 0x440, 0x43f, 0x435, 0x43d, 0x44c, 0x3b,
+0x432, 0x435, 0x440, 0x435, 0x441, 0x435, 0x43d, 0x44c, 0x3b, 0x436, 0x43e, 0x432,
+0x442, 0x435, 0x43d, 0x44c, 0x3b, 0x43b, 0x438, 0x441, 0x442, 0x43e, 0x43f, 0x430,
+0x434, 0x3b, 0x433, 0x440, 0x443, 0x434, 0x435, 0x43d, 0x44c, 0x441, 0x456, 0x447,
+0x43d, 0x44f, 0x3b, 0x43b, 0x44e, 0x442, 0x43e, 0x433, 0x43e, 0x3b, 0x431, 0x435,
+0x440, 0x435, 0x437, 0x43d, 0x44f, 0x3b, 0x43a, 0x432, 0x456, 0x442, 0x43d, 0x44f,
+0x3b, 0x442, 0x440, 0x430, 0x432, 0x43d, 0x44f, 0x3b, 0x447, 0x435, 0x440, 0x432,
+0x43d, 0x44f, 0x3b, 0x43b, 0x438, 0x43f, 0x43d, 0x44f, 0x3b, 0x441, 0x435, 0x440,
+0x43f, 0x43d, 0x44f, 0x3b, 0x432, 0x435, 0x440, 0x435, 0x441, 0x43d, 0x44f, 0x3b,
+0x436, 0x43e, 0x432, 0x442, 0x43d, 0x44f, 0x3b, 0x43b, 0x438, 0x441, 0x442, 0x43e,
+0x43f, 0x430, 0x434, 0x430, 0x3b, 0x433, 0x440, 0x443, 0x434, 0x43d, 0x44f, 0x441,
+0x456, 0x447, 0x2e, 0x3b, 0x43b, 0x44e, 0x442, 0x2e, 0x3b, 0x431, 0x435, 0x440,
+0x2e, 0x3b, 0x43a, 0x432, 0x456, 0x442, 0x2e, 0x3b, 0x442, 0x440, 0x430, 0x432,
+0x2e, 0x3b, 0x447, 0x435, 0x440, 0x432, 0x2e, 0x3b, 0x43b, 0x438, 0x43f, 0x2e,
+0x3b, 0x441, 0x435, 0x440, 0x43f, 0x2e, 0x3b, 0x432, 0x435, 0x440, 0x2e, 0x3b,
+0x436, 0x43e, 0x432, 0x442, 0x2e, 0x3b, 0x43b, 0x438, 0x441, 0x442, 0x2e, 0x3b,
+0x433, 0x440, 0x443, 0x434, 0x2e, 0x421, 0x3b, 0x41b, 0x3b, 0x411, 0x3b, 0x41a,
+0x3b, 0x422, 0x3b, 0x427, 0x3b, 0x41b, 0x3b, 0x421, 0x3b, 0x412, 0x3b, 0x416,
+0x3b, 0x41b, 0x3b, 0x413, 0x441, 0x3b, 0x43b, 0x3b, 0x431, 0x3b, 0x43a, 0x3b,
+0x442, 0x3b, 0x447, 0x3b, 0x43b, 0x3b, 0x441, 0x3b, 0x432, 0x3b, 0x436, 0x3b,
+0x43b, 0x3b, 0x433, 0x6a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x3b, 0x66, 0x65,
+0x62, 0x72, 0x75, 0x61, 0x72, 0x3b, 0x6d, 0x11b, 0x72, 0x63, 0x3b, 0x61,
+0x70, 0x72, 0x79, 0x6c, 0x3b, 0x6d, 0x65, 0x6a, 0x61, 0x3b, 0x6a, 0x75,
+0x6e, 0x69, 0x6a, 0x3b, 0x6a, 0x75, 0x6c, 0x69, 0x6a, 0x3b, 0x61, 0x77,
+0x67, 0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62,
+0x65, 0x72, 0x3b, 0x6f, 0x6b, 0x74, 0x6f, 0x62, 0x65, 0x72, 0x3b, 0x6e,
+0x6f, 0x77, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x64, 0x65, 0x63, 0x65,
+0x6d, 0x62, 0x65, 0x72, 0x6a, 0x61, 0x6e, 0x75, 0x61, 0x72, 0x61, 0x3b,
+0x66, 0x65, 0x62, 0x72, 0x75, 0x61, 0x72, 0x61, 0x3b, 0x6d, 0x11b, 0x72,
+0x63, 0x61, 0x3b, 0x61, 0x70, 0x72, 0x79, 0x6c, 0x61, 0x3b, 0x6d, 0x65,
+0x6a, 0x65, 0x3b, 0x6a, 0x75, 0x6e, 0x69, 0x6a, 0x61, 0x3b, 0x6a, 0x75,
+0x6c, 0x69, 0x6a, 0x61, 0x3b, 0x61, 0x77, 0x67, 0x75, 0x73, 0x74, 0x61,
+0x3b, 0x73, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x72, 0x61, 0x3b, 0x6f,
+0x6b, 0x74, 0x6f, 0x62, 0x72, 0x61, 0x3b, 0x6e, 0x6f, 0x77, 0x65, 0x6d,
+0x62, 0x72, 0x61, 0x3b, 0x64, 0x65, 0x63, 0x65, 0x6d, 0x62, 0x72, 0x61,
+0x6a, 0x61, 0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0x11b, 0x72, 0x3b,
+0x61, 0x70, 0x72, 0x3b, 0x6d, 0x65, 0x6a, 0x3b, 0x6a, 0x75, 0x6e, 0x3b,
+0x6a, 0x75, 0x6c, 0x3b, 0x61, 0x77, 0x67, 0x3b, 0x73, 0x65, 0x70, 0x3b,
+0x6f, 0x6b, 0x74, 0x3b, 0x6e, 0x6f, 0x77, 0x3b, 0x64, 0x65, 0x63, 0x6a,
+0x61, 0x6e, 0x2e, 0x3b, 0x66, 0x65, 0x62, 0x2e, 0x3b, 0x6d, 0x11b, 0x72,
+0x2e, 0x3b, 0x61, 0x70, 0x72, 0x2e, 0x3b, 0x6d, 0x65, 0x6a, 0x2e, 0x3b,
+0x6a, 0x75, 0x6e, 0x2e, 0x3b, 0x6a, 0x75, 0x6c, 0x2e, 0x3b, 0x61, 0x77,
+0x67, 0x2e, 0x3b, 0x73, 0x65, 0x70, 0x2e, 0x3b, 0x6f, 0x6b, 0x74, 0x2e,
+0x3b, 0x6e, 0x6f, 0x77, 0x2e, 0x3b, 0x64, 0x65, 0x63, 0x2e, 0x62c, 0x646,
+0x648, 0x631, 0x6cc, 0x3b, 0x641, 0x631, 0x648, 0x631, 0x6cc, 0x3b, 0x645, 0x627,
+0x631, 0x686, 0x3b, 0x627, 0x67e, 0x631, 0x6cc, 0x644, 0x3b, 0x645, 0x626, 0x6cc,
+0x3b, 0x62c, 0x648, 0x646, 0x3b, 0x62c, 0x648, 0x644, 0x627, 0x626, 0x6cc, 0x3b,
+0x627, 0x6af, 0x633, 0x62a, 0x3b, 0x633, 0x62a, 0x645, 0x628, 0x631, 0x3b, 0x627,
+0x6a9, 0x62a, 0x648, 0x628, 0x631, 0x3b, 0x646, 0x648, 0x645, 0x628, 0x631, 0x3b,
+0x62f, 0x633, 0x645, 0x628, 0x631, 0x64a, 0x627, 0x646, 0x6cb, 0x627, 0x631, 0x3b,
+0x641, 0x6d0, 0x6cb, 0x631, 0x627, 0x644, 0x3b, 0x645, 0x627, 0x631, 0x62a, 0x3b,
+0x626, 0x627, 0x67e, 0x631, 0x6d0, 0x644, 0x3b, 0x645, 0x627, 0x64a, 0x3b, 0x626,
+0x649, 0x64a, 0x6c7, 0x646, 0x3b, 0x626, 0x649, 0x64a, 0x6c7, 0x644, 0x3b, 0x626,
+0x627, 0x6cb, 0x63a, 0x6c7, 0x633, 0x62a, 0x3b, 0x633, 0x6d0, 0x646, 0x62a, 0x6d5,
+0x628, 0x649, 0x631, 0x3b, 0x626, 0x6c6, 0x643, 0x62a, 0x6d5, 0x628, 0x649, 0x631,
+0x3b, 0x646, 0x648, 0x64a, 0x627, 0x628, 0x649, 0x631, 0x3b, 0x62f, 0x6d0, 0x643,
+0x627, 0x628, 0x649, 0x631, 0x59, 0x61, 0x6e, 0x76, 0x61, 0x72, 0x3b, 0x46,
+0x65, 0x76, 0x72, 0x61, 0x6c, 0x3b, 0x4d, 0x61, 0x72, 0x74, 0x3b, 0x41,
+0x70, 0x72, 0x65, 0x6c, 0x3b, 0x4d, 0x61, 0x79, 0x3b, 0x49, 0x79, 0x75,
+0x6e, 0x3b, 0x49, 0x79, 0x75, 0x6c, 0x3b, 0x41, 0x76, 0x67, 0x75, 0x73,
+0x74, 0x3b, 0x53, 0x65, 0x6e, 0x74, 0x61, 0x62, 0x72, 0x3b, 0x4f, 0x6b,
+0x74, 0x61, 0x62, 0x72, 0x3b, 0x4e, 0x6f, 0x79, 0x61, 0x62, 0x72, 0x3b,
+0x44, 0x65, 0x6b, 0x61, 0x62, 0x72, 0x79, 0x61, 0x6e, 0x76, 0x61, 0x72,
+0x3b, 0x66, 0x65, 0x76, 0x72, 0x61, 0x6c, 0x3b, 0x6d, 0x61, 0x72, 0x74,
+0x3b, 0x61, 0x70, 0x72, 0x65, 0x6c, 0x3b, 0x6d, 0x61, 0x79, 0x3b, 0x69,
+0x79, 0x75, 0x6e, 0x3b, 0x69, 0x79, 0x75, 0x6c, 0x3b, 0x61, 0x76, 0x67,
+0x75, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x6e, 0x74, 0x61, 0x62, 0x72, 0x3b,
+0x6f, 0x6b, 0x74, 0x61, 0x62, 0x72, 0x3b, 0x6e, 0x6f, 0x79, 0x61, 0x62,
+0x72, 0x3b, 0x64, 0x65, 0x6b, 0x61, 0x62, 0x72, 0x59, 0x61, 0x6e, 0x3b,
+0x46, 0x65, 0x76, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b,
+0x4d, 0x61, 0x79, 0x3b, 0x49, 0x79, 0x6e, 0x3b, 0x49, 0x79, 0x6c, 0x3b,
+0x41, 0x76, 0x67, 0x3b, 0x53, 0x65, 0x6e, 0x3b, 0x4f, 0x6b, 0x74, 0x3b,
+0x4e, 0x6f, 0x79, 0x3b, 0x44, 0x65, 0x6b, 0x79, 0x61, 0x6e, 0x3b, 0x66,
+0x65, 0x76, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x61, 0x70, 0x72, 0x3b, 0x6d,
+0x61, 0x79, 0x3b, 0x69, 0x79, 0x6e, 0x3b, 0x69, 0x79, 0x6c, 0x3b, 0x61,
+0x76, 0x67, 0x3b, 0x73, 0x65, 0x6e, 0x3b, 0x6f, 0x6b, 0x74, 0x3b, 0x6e,
+0x6f, 0x79, 0x3b, 0x64, 0x65, 0x6b, 0x59, 0x3b, 0x46, 0x3b, 0x4d, 0x3b,
+0x41, 0x3b, 0x4d, 0x3b, 0x49, 0x3b, 0x49, 0x3b, 0x41, 0x3b, 0x53, 0x3b,
+0x4f, 0x3b, 0x4e, 0x3b, 0x44, 0x62c, 0x646, 0x648, 0x3b, 0x641, 0x628, 0x631,
+0x3b, 0x645, 0x627, 0x631, 0x3b, 0x627, 0x67e, 0x631, 0x3b, 0x645, 0x6cc, 0x3b,
+0x62c, 0x648, 0x646, 0x3b, 0x62c, 0x648, 0x644, 0x3b, 0x627, 0x6af, 0x633, 0x3b,
+0x633, 0x67e, 0x62a, 0x3b, 0x627, 0x6a9, 0x62a, 0x3b, 0x646, 0x648, 0x645, 0x3b,
+0x62f, 0x633, 0x645, 0x44f, 0x43d, 0x432, 0x430, 0x440, 0x3b, 0x444, 0x435, 0x432,
+0x440, 0x430, 0x43b, 0x3b, 0x43c, 0x430, 0x440, 0x442, 0x3b, 0x430, 0x43f, 0x440,
+0x435, 0x43b, 0x3b, 0x43c, 0x430, 0x439, 0x3b, 0x438, 0x44e, 0x43d, 0x3b, 0x438,
+0x44e, 0x43b, 0x3b, 0x430, 0x432, 0x433, 0x443, 0x441, 0x442, 0x3b, 0x441, 0x435,
+0x43d, 0x442, 0x44f, 0x431, 0x440, 0x3b, 0x43e, 0x43a, 0x442, 0x44f, 0x431, 0x440,
+0x3b, 0x43d, 0x43e, 0x44f, 0x431, 0x440, 0x3b, 0x434, 0x435, 0x43a, 0x430, 0x431,
+0x440, 0xa5a8, 0xa595, 0x20, 0xa56a, 0xa574, 0x20, 0xa51e, 0xa500, 0xa56e, 0xa54a, 0x3b,
+0xa552, 0xa561, 0xa59d, 0xa595, 0x3b, 0xa57e, 0xa5ba, 0x3b, 0xa5a2, 0xa595, 0x3b, 0xa591,
+0xa571, 0x3b, 0xa5b1, 0xa60b, 0x3b, 0xa5b1, 0xa55e, 0xa524, 0x3b, 0xa5db, 0xa515, 0x3b,
+0xa562, 0xa54c, 0x3b, 0xa56d, 0xa583, 0x3b, 0xa51e, 0xa60b, 0xa554, 0xa57f, 0x20, 0xa578,
+0xa583, 0xa5cf, 0x3b, 0xa5a8, 0xa595, 0x20, 0xa56a, 0xa574, 0x20, 0xa5cf, 0xa5ba, 0xa56e,
+0xa54a, 0xa5a8, 0xa595, 0xa51e, 0x3b, 0xa552, 0xa561, 0x3b, 0xa57e, 0xa5ba, 0x3b, 0xa5a2,
+0xa595, 0x3b, 0xa591, 0xa571, 0x3b, 0xa5b1, 0xa60b, 0x3b, 0xa5b1, 0xa55e, 0x3b, 0xa5db,
+0xa515, 0x3b, 0xa562, 0xa54c, 0x3b, 0xa56d, 0xa583, 0x3b, 0xa51e, 0xa60b, 0x3b, 0xa5a8,
+0xa595, 0xa5cf, 0x50, 0x68, 0x61, 0x6e, 0x64, 0x6f, 0x3b, 0x4c, 0x75, 0x68,
+0x75, 0x68, 0x69, 0x3b, 0x1e70, 0x68, 0x61, 0x66, 0x61, 0x6d, 0x75, 0x68,
+0x77, 0x65, 0x3b, 0x4c, 0x61, 0x6d, 0x62, 0x61, 0x6d, 0x61, 0x69, 0x3b,
+0x53, 0x68, 0x75, 0x6e, 0x64, 0x75, 0x6e, 0x74, 0x68, 0x75, 0x6c, 0x65,
+0x3b, 0x46, 0x75, 0x6c, 0x77, 0x69, 0x3b, 0x46, 0x75, 0x6c, 0x77, 0x61,
+0x6e, 0x61, 0x3b, 0x1e70, 0x68, 0x61, 0x6e, 0x67, 0x75, 0x6c, 0x65, 0x3b,
+0x4b, 0x68, 0x75, 0x62, 0x76, 0x75, 0x6d, 0x65, 0x64, 0x7a, 0x69, 0x3b,
+0x54, 0x73, 0x68, 0x69, 0x6d, 0x65, 0x64, 0x7a, 0x69, 0x3b, 0x1e3c, 0x61,
+0x72, 0x61, 0x3b, 0x4e, 0x79, 0x65, 0x6e, 0x64, 0x61, 0x76, 0x68, 0x75,
+0x73, 0x69, 0x6b, 0x75, 0x50, 0x68, 0x61, 0x3b, 0x4c, 0x75, 0x68, 0x3b,
+0x1e70, 0x68, 0x66, 0x3b, 0x4c, 0x61, 0x6d, 0x3b, 0x53, 0x68, 0x75, 0x3b,
+0x4c, 0x77, 0x69, 0x3b, 0x4c, 0x77, 0x61, 0x3b, 0x1e70, 0x68, 0x61, 0x3b,
+0x4b, 0x68, 0x75, 0x3b, 0x54, 0x73, 0x68, 0x3b, 0x1e3c, 0x61, 0x72, 0x3b,
+0x4e, 0x79, 0x65, 0x54, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x31, 0x3b, 0x54,
+0x68, 0xe1, 0x6e, 0x67, 0x20, 0x32, 0x3b, 0x54, 0x68, 0xe1, 0x6e, 0x67,
+0x20, 0x33, 0x3b, 0x54, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x34, 0x3b, 0x54,
+0x68, 0xe1, 0x6e, 0x67, 0x20, 0x35, 0x3b, 0x54, 0x68, 0xe1, 0x6e, 0x67,
+0x20, 0x36, 0x3b, 0x54, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x37, 0x3b, 0x54,
+0x68, 0xe1, 0x6e, 0x67, 0x20, 0x38, 0x3b, 0x54, 0x68, 0xe1, 0x6e, 0x67,
+0x20, 0x39, 0x3b, 0x54, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x31, 0x30, 0x3b,
+0x54, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x31, 0x31, 0x3b, 0x54, 0x68, 0xe1,
+0x6e, 0x67, 0x20, 0x31, 0x32, 0x74, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x31,
+0x3b, 0x74, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x32, 0x3b, 0x74, 0x68, 0xe1,
+0x6e, 0x67, 0x20, 0x33, 0x3b, 0x74, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x34,
+0x3b, 0x74, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x35, 0x3b, 0x74, 0x68, 0xe1,
+0x6e, 0x67, 0x20, 0x36, 0x3b, 0x74, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x37,
+0x3b, 0x74, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x38, 0x3b, 0x74, 0x68, 0xe1,
+0x6e, 0x67, 0x20, 0x39, 0x3b, 0x74, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x31,
+0x30, 0x3b, 0x74, 0x68, 0xe1, 0x6e, 0x67, 0x20, 0x31, 0x31, 0x3b, 0x74,
+0x68, 0xe1, 0x6e, 0x67, 0x20, 0x31, 0x32, 0x74, 0x68, 0x67, 0x20, 0x31,
+0x3b, 0x74, 0x68, 0x67, 0x20, 0x32, 0x3b, 0x74, 0x68, 0x67, 0x20, 0x33,
+0x3b, 0x74, 0x68, 0x67, 0x20, 0x34, 0x3b, 0x74, 0x68, 0x67, 0x20, 0x35,
+0x3b, 0x74, 0x68, 0x67, 0x20, 0x36, 0x3b, 0x74, 0x68, 0x67, 0x20, 0x37,
+0x3b, 0x74, 0x68, 0x67, 0x20, 0x38, 0x3b, 0x74, 0x68, 0x67, 0x20, 0x39,
+0x3b, 0x74, 0x68, 0x67, 0x20, 0x31, 0x30, 0x3b, 0x74, 0x68, 0x67, 0x20,
+0x31, 0x31, 0x3b, 0x74, 0x68, 0x67, 0x20, 0x31, 0x32, 0x79, 0x61, 0x6e,
+0x75, 0x6c, 0x3b, 0x66, 0x65, 0x62, 0x75, 0x6c, 0x3b, 0x6d, 0xe4, 0x7a,
+0x75, 0x6c, 0x3b, 0x70, 0x72, 0x69, 0x6c, 0x75, 0x6c, 0x3b, 0x6d, 0x61,
+0x79, 0x75, 0x6c, 0x3b, 0x79, 0x75, 0x6e, 0x75, 0x6c, 0x3b, 0x79, 0x75,
+0x6c, 0x75, 0x6c, 0x3b, 0x67, 0x75, 0x73, 0x74, 0x75, 0x6c, 0x3b, 0x73,
+0x65, 0x74, 0x75, 0x6c, 0x3b, 0x74, 0x6f, 0x62, 0x75, 0x6c, 0x3b, 0x6e,
+0x6f, 0x76, 0x75, 0x6c, 0x3b, 0x64, 0x65, 0x6b, 0x75, 0x6c, 0x79, 0x61,
+0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0xe4, 0x7a, 0x3b, 0x70, 0x72,
+0x6c, 0x3b, 0x6d, 0x61, 0x79, 0x3b, 0x79, 0x75, 0x6e, 0x3b, 0x79, 0x75,
+0x6c, 0x3b, 0x67, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x74, 0x3b, 0x74, 0x6f,
+0x62, 0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65, 0x6b, 0x79, 0x61, 0x6e,
+0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0xe4, 0x7a, 0x3b, 0x70, 0x72, 0x6c,
+0x3b, 0x6d, 0x61, 0x79, 0x3b, 0x79, 0x75, 0x6e, 0x3b, 0x79, 0x75, 0x6c,
+0x3b, 0x67, 0x73, 0x74, 0x3b, 0x73, 0x65, 0x74, 0x3b, 0x74, 0x6f, 0x6e,
+0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65, 0x6b, 0x59, 0x3b, 0x46, 0x3b,
+0x4d, 0x3b, 0x50, 0x3b, 0x4d, 0x3b, 0x59, 0x3b, 0x59, 0x3b, 0x47, 0x3b,
+0x53, 0x3b, 0x54, 0x3b, 0x4e, 0x3b, 0x44, 0x4a, 0x65, 0x6e, 0x6e, 0x65,
+0x72, 0x3b, 0x48, 0x6f, 0x72, 0x6e, 0x69, 0x67, 0x3b, 0x4d, 0xe4, 0x72,
+0x7a, 0x65, 0x3b, 0x41, 0x62, 0x72, 0x69, 0x6c, 0x6c, 0x65, 0x3b, 0x4d,
+0x65, 0x69, 0x6a, 0x65, 0x3b, 0x42, 0x72, 0xe1, 0x10d, 0x65, 0x74, 0x3b,
+0x48, 0x65, 0x69, 0x77, 0x65, 0x74, 0x3b, 0xd6, 0x69, 0x67, 0x161, 0x74,
+0x65, 0x3b, 0x48, 0x65, 0x72, 0x62, 0x161, 0x74, 0x6d, 0xe1, 0x6e, 0x65,
+0x74, 0x3b, 0x57, 0xed, 0x6d, 0xe1, 0x6e, 0x65, 0x74, 0x3b, 0x57, 0x69,
+0x6e, 0x74, 0x65, 0x72, 0x6d, 0xe1, 0x6e, 0x65, 0x74, 0x3b, 0x43, 0x68,
+0x72, 0x69, 0x161, 0x74, 0x6d, 0xe1, 0x6e, 0x65, 0x74, 0x4a, 0x65, 0x6e,
+0x3b, 0x48, 0x6f, 0x72, 0x3b, 0x4d, 0xe4, 0x72, 0x3b, 0x41, 0x62, 0x72,
+0x3b, 0x4d, 0x65, 0x69, 0x3b, 0x42, 0x72, 0xe1, 0x3b, 0x48, 0x65, 0x69,
+0x3b, 0xd6, 0x69, 0x67, 0x3b, 0x48, 0x65, 0x72, 0x3b, 0x57, 0xed, 0x6d,
+0x3b, 0x57, 0x69, 0x6e, 0x3b, 0x43, 0x68, 0x72, 0x4a, 0x3b, 0x48, 0x3b,
+0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x42, 0x3b, 0x48, 0x3b, 0xd6, 0x3b,
+0x48, 0x3b, 0x57, 0x3b, 0x57, 0x3b, 0x43, 0x49, 0x6f, 0x6e, 0x61, 0x77,
+0x72, 0x3b, 0x43, 0x68, 0x77, 0x65, 0x66, 0x72, 0x6f, 0x72, 0x3b, 0x4d,
+0x61, 0x77, 0x72, 0x74, 0x68, 0x3b, 0x45, 0x62, 0x72, 0x69, 0x6c, 0x6c,
+0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4d, 0x65, 0x68, 0x65, 0x66, 0x69, 0x6e,
+0x3b, 0x47, 0x6f, 0x72, 0x66, 0x66, 0x65, 0x6e, 0x6e, 0x61, 0x66, 0x3b,
+0x41, 0x77, 0x73, 0x74, 0x3b, 0x4d, 0x65, 0x64, 0x69, 0x3b, 0x48, 0x79,
+0x64, 0x72, 0x65, 0x66, 0x3b, 0x54, 0x61, 0x63, 0x68, 0x77, 0x65, 0x64,
+0x64, 0x3b, 0x52, 0x68, 0x61, 0x67, 0x66, 0x79, 0x72, 0x49, 0x6f, 0x6e,
+0x3b, 0x43, 0x68, 0x77, 0x3b, 0x4d, 0x61, 0x77, 0x3b, 0x45, 0x62, 0x72,
+0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4d, 0x65, 0x68, 0x3b, 0x47, 0x6f, 0x72,
+0x3b, 0x41, 0x77, 0x73, 0x74, 0x3b, 0x4d, 0x65, 0x64, 0x69, 0x3b, 0x48,
+0x79, 0x64, 0x3b, 0x54, 0x61, 0x63, 0x68, 0x3b, 0x52, 0x68, 0x61, 0x67,
+0x49, 0x6f, 0x6e, 0x3b, 0x43, 0x68, 0x77, 0x65, 0x66, 0x3b, 0x4d, 0x61,
+0x77, 0x3b, 0x45, 0x62, 0x72, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4d, 0x65,
+0x68, 0x3b, 0x47, 0x6f, 0x72, 0x66, 0x66, 0x3b, 0x41, 0x77, 0x73, 0x74,
+0x3b, 0x4d, 0x65, 0x64, 0x69, 0x3b, 0x48, 0x79, 0x64, 0x3b, 0x54, 0x61,
+0x63, 0x68, 0x3b, 0x52, 0x68, 0x61, 0x67, 0x49, 0x3b, 0x43, 0x68, 0x3b,
+0x4d, 0x3b, 0x45, 0x3b, 0x4d, 0x3b, 0x4d, 0x3b, 0x47, 0x3b, 0x41, 0x3b,
+0x4d, 0x3b, 0x48, 0x3b, 0x54, 0x3b, 0x52, 0x68, 0x4a, 0x61, 0x6e, 0x6e,
+0x65, 0x77, 0x61, 0x72, 0x69, 0x73, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x65,
+0x77, 0x61, 0x72, 0x69, 0x73, 0x3b, 0x4d, 0x61, 0x61, 0x72, 0x74, 0x3b,
+0x41, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x61, 0x61, 0x69, 0x65, 0x3b,
+0x4a, 0x75, 0x6e, 0x79, 0x3b, 0x4a, 0x75, 0x6c, 0x79, 0x3b, 0x41, 0x75,
+0x67, 0x75, 0x73, 0x74, 0x75, 0x73, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x69,
+0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x65, 0x72,
+0x3b, 0x4e, 0x6f, 0x76, 0x69, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x44, 0x65,
+0x73, 0x69, 0x6d, 0x62, 0x65, 0x72, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65,
+0x62, 0x3b, 0x4d, 0x72, 0x74, 0x3b, 0x41, 0x70, 0x72, 0x3b, 0x4d, 0x61,
+0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x75,
+0x67, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f,
+0x76, 0x3b, 0x44, 0x65, 0x73, 0x53, 0x61, 0x6d, 0x77, 0x69, 0x79, 0x65,
+0x65, 0x3b, 0x46, 0x65, 0x77, 0x72, 0x69, 0x79, 0x65, 0x65, 0x3b, 0x4d,
+0x61, 0x72, 0x73, 0x3b, 0x41, 0x77, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x65,
+0x65, 0x3b, 0x53, 0x75, 0x77, 0x65, 0x3b, 0x53, 0x75, 0x6c, 0x65, 0x74,
+0x3b, 0x55, 0x74, 0x3b, 0x53, 0xe0, 0x74, 0x74, 0x75, 0x6d, 0x62, 0x61,
+0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x6f, 0x62, 0x61, 0x72, 0x3b, 0x4e,
+0x6f, 0x77, 0xe0, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x44, 0x65, 0x73, 0xe0,
+0x6d, 0x62, 0x61, 0x72, 0x53, 0x61, 0x6d, 0x3b, 0x46, 0x65, 0x77, 0x3b,
+0x4d, 0x61, 0x72, 0x3b, 0x41, 0x77, 0x72, 0x3b, 0x4d, 0x65, 0x65, 0x3b,
+0x53, 0x75, 0x77, 0x3b, 0x53, 0x75, 0x6c, 0x3b, 0x55, 0x74, 0x3b, 0x53,
+0xe0, 0x74, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x77, 0x3b, 0x44,
+0x65, 0x73, 0x4a, 0x61, 0x6e, 0x79, 0x75, 0x77, 0x61, 0x72, 0x69, 0x3b,
+0x46, 0x65, 0x62, 0x72, 0x75, 0x77, 0x61, 0x72, 0x69, 0x3b, 0x4d, 0x61,
+0x74, 0x73, 0x68, 0x69, 0x3b, 0x45, 0x70, 0x72, 0x65, 0x6c, 0x69, 0x3b,
+0x4d, 0x65, 0x79, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75,
+0x6c, 0x61, 0x79, 0x69, 0x3b, 0x41, 0x67, 0x61, 0x73, 0x74, 0x69, 0x3b,
+0x53, 0x65, 0x70, 0x74, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x4f, 0x6b, 0x74,
+0x68, 0x6f, 0x62, 0x61, 0x3b, 0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61,
+0x3b, 0x44, 0x69, 0x73, 0x65, 0x6d, 0x62, 0x61, 0x4a, 0x61, 0x6e, 0x79,
+0x75, 0x77, 0x61, 0x72, 0x69, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x77,
+0x61, 0x72, 0x69, 0x3b, 0x4d, 0x61, 0x74, 0x73, 0x68, 0x69, 0x3b, 0x45,
+0x70, 0x72, 0x65, 0x6c, 0x69, 0x3b, 0x4d, 0x65, 0x79, 0x69, 0x3b, 0x4a,
+0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x61, 0x79, 0x69, 0x3b, 0x41,
+0x67, 0x61, 0x73, 0x74, 0x69, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d,
+0x62, 0x61, 0x3b, 0x4f, 0x6b, 0x74, 0x68, 0x6f, 0x62, 0x68, 0x61, 0x3b,
+0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x44, 0x69, 0x73, 0x65,
+0x6d, 0x62, 0x61, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d,
+0x61, 0x74, 0x3b, 0x45, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x79, 0x3b, 0x4a,
+0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x61, 0x3b, 0x53,
+0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44,
+0x69, 0x73, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61,
+0x74, 0x3b, 0x45, 0x70, 0x72, 0x3b, 0x4d, 0x65, 0x79, 0x3b, 0x4a, 0x75,
+0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x61, 0x3b, 0x53, 0x65,
+0x70, 0x74, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44,
+0x69, 0x73, 0x70, 0x69, 0x6b, 0xed, 0x74, 0xed, 0x6b, 0xed, 0x74, 0x69,
+0x65, 0x2c, 0x20, 0x6f, 0xf3, 0x6c, 0xed, 0x20, 0xfa, 0x20, 0x6b, 0x75,
+0x74, 0xfa, 0x61, 0x6e, 0x3b, 0x73, 0x69, 0x25b, 0x79, 0x25b, 0x301, 0x2c,
+0x20, 0x6f, 0xf3, 0x6c, 0x69, 0x20, 0xfa, 0x20, 0x6b, 0xe1, 0x6e, 0x64,
+0xed, 0x25b, 0x3b, 0x254, 0x6e, 0x73, 0xfa, 0x6d, 0x62, 0x254, 0x6c, 0x2c,
+0x20, 0x6f, 0xf3, 0x6c, 0x69, 0x20, 0xfa, 0x20, 0x6b, 0xe1, 0x74, 0xe1,
+0x74, 0xfa, 0x25b, 0x3b, 0x6d, 0x65, 0x73, 0x69, 0x14b, 0x2c, 0x20, 0x6f,
+0xf3, 0x6c, 0x69, 0x20, 0xfa, 0x20, 0x6b, 0xe9, 0x6e, 0x69, 0x65, 0x3b,
+0x65, 0x6e, 0x73, 0x69, 0x6c, 0x2c, 0x20, 0x6f, 0xf3, 0x6c, 0x69, 0x20,
+0xfa, 0x20, 0x6b, 0xe1, 0x74, 0xe1, 0x6e, 0x75, 0x25b, 0x3b, 0x254, 0x73,
+0x254, 0x6e, 0x3b, 0x65, 0x66, 0x75, 0x74, 0x65, 0x3b, 0x70, 0x69, 0x73,
+0x75, 0x79, 0xfa, 0x3b, 0x69, 0x6d, 0x25b, 0x14b, 0x20, 0x69, 0x20, 0x70,
+0x75, 0x254, 0x73, 0x3b, 0x69, 0x6d, 0x25b, 0x14b, 0x20, 0x69, 0x20, 0x70,
+0x75, 0x74, 0xfa, 0x6b, 0x2c, 0x6f, 0xf3, 0x6c, 0x69, 0x20, 0xfa, 0x20,
+0x6b, 0xe1, 0x74, 0xed, 0x25b, 0x3b, 0x6d, 0x61, 0x6b, 0x61, 0x6e, 0x64,
+0x69, 0x6b, 0x25b, 0x3b, 0x70, 0x69, 0x6c, 0x254, 0x6e, 0x64, 0x254, 0x301,
+0x6f, 0x2e, 0x31, 0x3b, 0x6f, 0x2e, 0x32, 0x3b, 0x6f, 0x2e, 0x33, 0x3b,
+0x6f, 0x2e, 0x34, 0x3b, 0x6f, 0x2e, 0x35, 0x3b, 0x6f, 0x2e, 0x36, 0x3b,
+0x6f, 0x2e, 0x37, 0x3b, 0x6f, 0x2e, 0x38, 0x3b, 0x6f, 0x2e, 0x39, 0x3b,
+0x6f, 0x2e, 0x31, 0x30, 0x3b, 0x6f, 0x2e, 0x31, 0x31, 0x3b, 0x6f, 0x2e,
+0x31, 0x32, 0x5d9, 0x5d0, 0x5b7, 0x5e0, 0x5d5, 0x5d0, 0x5b7, 0x5e8, 0x3b, 0x5e4,
+0x5bf, 0x5e2, 0x5d1, 0x5e8, 0x5d5, 0x5d0, 0x5b7, 0x5e8, 0x3b, 0x5de, 0x5e2, 0x5e8,
+0x5e5, 0x3b, 0x5d0, 0x5b7, 0x5e4, 0x5bc, 0x5e8, 0x5d9, 0x5dc, 0x3b, 0x5de, 0x5d9,
+0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5e0, 0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5dc, 0x5d9, 0x3b,
+0x5d0, 0x5d5, 0x5d9, 0x5d2, 0x5d5, 0x5e1, 0x5d8, 0x3b, 0x5e1, 0x5e2, 0x5e4, 0x5bc,
+0x5d8, 0x5e2, 0x5de, 0x5d1, 0x5e2, 0x5e8, 0x3b, 0x5d0, 0x5e7, 0x5d8, 0x5d0, 0x5d1,
+0x5e2, 0x5e8, 0x3b, 0x5e0, 0x5d0, 0x5d5, 0x5d5, 0x5e2, 0x5de, 0x5d1, 0x5e2, 0x5e8,
+0x3b, 0x5d3, 0x5e2, 0x5e6, 0x5e2, 0x5de, 0x5d1, 0x5e2, 0x5e8, 0x5d9, 0x5d0, 0x5b7,
+0x5e0, 0x3b, 0x5e4, 0x5bf, 0x5e2, 0x5d1, 0x3b, 0x5de, 0x5e2, 0x5e8, 0x5e5, 0x3b,
+0x5d0, 0x5b7, 0x5e4, 0x5bc, 0x5e8, 0x3b, 0x5de, 0x5d9, 0x5d9, 0x3b, 0x5d9, 0x5d5,
+0x5e0, 0x5d9, 0x3b, 0x5d9, 0x5d5, 0x5dc, 0x5d9, 0x3b, 0x5d0, 0x5d5, 0x5d9, 0x5d2,
+0x3b, 0x5e1, 0x5e2, 0x5e4, 0x5bc, 0x3b, 0x5d0, 0x5e7, 0x5d8, 0x3b, 0x5e0, 0x5d0,
+0x5d5, 0x5d5, 0x3b, 0x5d3, 0x5e2, 0x5e6, 0x1e62, 0x1eb9, 0x301, 0x72, 0x1eb9, 0x301,
+0x3b, 0xc8, 0x72, 0xe8, 0x6c, 0xe8, 0x3b, 0x1eb8, 0x72, 0x1eb9, 0x300, 0x6e,
+0xe0, 0x3b, 0xcc, 0x67, 0x62, 0xe9, 0x3b, 0x1eb8, 0x300, 0x62, 0x69, 0x62,
+0x69, 0x3b, 0xd2, 0x6b, 0xfa, 0x64, 0x75, 0x3b, 0x41, 0x67, 0x1eb9, 0x6d,
+0x1ecd, 0x3b, 0xd2, 0x67, 0xfa, 0x6e, 0x3b, 0x4f, 0x77, 0x65, 0x77, 0x65,
+0x3b, 0x1ecc, 0x300, 0x77, 0xe0, 0x72, 0xe0, 0x3b, 0x42, 0xe9, 0x6c, 0xfa,
+0x3b, 0x1ecc, 0x300, 0x70, 0x1eb9, 0x300, 0x4f, 0x1e63, 0xf9, 0x20, 0x1e62, 0x1eb9,
+0x301, 0x72, 0x1eb9, 0x301, 0x3b, 0x4f, 0x1e63, 0xf9, 0x20, 0xc8, 0x72, 0xe8,
+0x6c, 0xe8, 0x3b, 0x4f, 0x1e63, 0xf9, 0x20, 0x1eb8, 0x72, 0x1eb9, 0x300, 0x6e,
+0xe0, 0x3b, 0x4f, 0x1e63, 0xf9, 0x20, 0xcc, 0x67, 0x62, 0xe9, 0x3b, 0x4f,
+0x1e63, 0xf9, 0x20, 0x1eb8, 0x300, 0x62, 0x69, 0x62, 0x69, 0x3b, 0x4f, 0x1e63,
+0xf9, 0x20, 0xd2, 0x6b, 0xfa, 0x64, 0x75, 0x3b, 0x4f, 0x1e63, 0xf9, 0x20,
+0x41, 0x67, 0x1eb9, 0x6d, 0x1ecd, 0x3b, 0x4f, 0x1e63, 0xf9, 0x20, 0xd2, 0x67,
+0xfa, 0x6e, 0x3b, 0x4f, 0x1e63, 0xf9, 0x20, 0x4f, 0x77, 0x65, 0x77, 0x65,
+0x3b, 0x4f, 0x1e63, 0xf9, 0x20, 0x1ecc, 0x300, 0x77, 0xe0, 0x72, 0xe0, 0x3b,
+0x4f, 0x1e63, 0xf9, 0x20, 0x42, 0xe9, 0x6c, 0xfa, 0x3b, 0x4f, 0x1e63, 0xf9,
+0x20, 0x1ecc, 0x300, 0x70, 0x1eb9, 0x300, 0x1e62, 0x1eb9, 0x301, 0x3b, 0xc8, 0x72,
+0x3b, 0x1eb8, 0x72, 0x3b, 0xcc, 0x67, 0x3b, 0x1eb8, 0x300, 0x62, 0x3b, 0xd2,
+0x6b, 0x3b, 0x41, 0x67, 0x3b, 0xd2, 0x67, 0x3b, 0x4f, 0x77, 0x3b, 0x1ecc,
+0x300, 0x77, 0x3b, 0x42, 0xe9, 0x3b, 0x1ecc, 0x300, 0x70, 0x1e62, 0x1eb9, 0x301,
+0x72, 0x3b, 0xc8, 0x72, 0xe8, 0x6c, 0x3b, 0x1eb8, 0x72, 0x1eb9, 0x300, 0x6e,
+0x3b, 0xcc, 0x67, 0x62, 0x3b, 0x1eb8, 0x300, 0x62, 0x69, 0x3b, 0xd2, 0x6b,
+0xfa, 0x3b, 0x41, 0x67, 0x1eb9, 0x3b, 0xd2, 0x67, 0xfa, 0x3b, 0x4f, 0x77,
+0x65, 0x3b, 0x1ecc, 0x300, 0x77, 0xe0, 0x3b, 0x42, 0xe9, 0x6c, 0x3b, 0x1ecc,
+0x300, 0x70, 0x1eb9, 0x53, 0x3b, 0xc8, 0x3b, 0x1eb8, 0x3b, 0xcc, 0x3b, 0x1eb8,
+0x300, 0x3b, 0xd2, 0x3b, 0x41, 0x3b, 0xd2, 0x3b, 0x4f, 0x3b, 0x1ecc, 0x300,
+0x3b, 0x42, 0x3b, 0x1ecc, 0x300, 0x53, 0x68, 0x25b, 0x301, 0x72, 0x25b, 0x301,
+0x3b, 0xc8, 0x72, 0xe8, 0x6c, 0xe8, 0x3b, 0x190, 0x72, 0x25b, 0x300, 0x6e,
+0xe0, 0x3b, 0xcc, 0x67, 0x62, 0xe9, 0x3b, 0x190, 0x300, 0x62, 0x69, 0x62,
+0x69, 0x3b, 0xd2, 0x6b, 0xfa, 0x64, 0x75, 0x3b, 0x41, 0x67, 0x25b, 0x6d,
+0x254, 0x3b, 0xd2, 0x67, 0xfa, 0x6e, 0x3b, 0x4f, 0x77, 0x65, 0x77, 0x65,
+0x3b, 0x186, 0x300, 0x77, 0xe0, 0x72, 0xe0, 0x3b, 0x42, 0xe9, 0x6c, 0xfa,
+0x3b, 0x186, 0x300, 0x70, 0x25b, 0x300, 0x4f, 0x73, 0x68, 0xf9, 0x20, 0x53,
+0x68, 0x25b, 0x301, 0x72, 0x25b, 0x301, 0x3b, 0x4f, 0x73, 0x68, 0xf9, 0x20,
+0xc8, 0x72, 0xe8, 0x6c, 0xe8, 0x3b, 0x4f, 0x73, 0x68, 0xf9, 0x20, 0x190,
+0x72, 0x25b, 0x300, 0x6e, 0xe0, 0x3b, 0x4f, 0x73, 0x68, 0xf9, 0x20, 0xcc,
+0x67, 0x62, 0xe9, 0x3b, 0x4f, 0x73, 0x68, 0xf9, 0x20, 0x190, 0x300, 0x62,
+0x69, 0x62, 0x69, 0x3b, 0x4f, 0x73, 0x68, 0xf9, 0x20, 0xd2, 0x6b, 0xfa,
+0x64, 0x75, 0x3b, 0x4f, 0x73, 0x68, 0xf9, 0x20, 0x41, 0x67, 0x25b, 0x6d,
+0x254, 0x3b, 0x4f, 0x73, 0x68, 0xf9, 0x20, 0xd2, 0x67, 0xfa, 0x6e, 0x3b,
+0x4f, 0x73, 0x68, 0xf9, 0x20, 0x4f, 0x77, 0x65, 0x77, 0x65, 0x3b, 0x4f,
+0x73, 0x68, 0xf9, 0x20, 0x186, 0x300, 0x77, 0xe0, 0x72, 0xe0, 0x3b, 0x4f,
+0x73, 0x68, 0xf9, 0x20, 0x42, 0xe9, 0x6c, 0xfa, 0x3b, 0x4f, 0x73, 0x68,
+0xf9, 0x20, 0x186, 0x300, 0x70, 0x25b, 0x300, 0x53, 0x68, 0x25b, 0x301, 0x3b,
+0xc8, 0x72, 0x3b, 0x190, 0x72, 0x3b, 0xcc, 0x67, 0x3b, 0x190, 0x300, 0x62,
+0x3b, 0xd2, 0x6b, 0x3b, 0x41, 0x67, 0x3b, 0xd2, 0x67, 0x3b, 0x4f, 0x77,
+0x3b, 0x186, 0x300, 0x77, 0x3b, 0x42, 0xe9, 0x3b, 0x186, 0x300, 0x70, 0x53,
+0x68, 0x25b, 0x301, 0x72, 0x3b, 0xc8, 0x72, 0xe8, 0x6c, 0x3b, 0x190, 0x72,
+0x25b, 0x300, 0x6e, 0x3b, 0xcc, 0x67, 0x62, 0x3b, 0x190, 0x300, 0x62, 0x69,
+0x3b, 0xd2, 0x6b, 0xfa, 0x3b, 0x41, 0x67, 0x25b, 0x3b, 0xd2, 0x67, 0xfa,
+0x3b, 0x4f, 0x77, 0x65, 0x3b, 0x186, 0x300, 0x77, 0xe0, 0x3b, 0x42, 0xe9,
+0x6c, 0x3b, 0x186, 0x300, 0x70, 0x25b, 0x53, 0x3b, 0xc8, 0x3b, 0x190, 0x3b,
+0xcc, 0x3b, 0x190, 0x300, 0x3b, 0xd2, 0x3b, 0x41, 0x3b, 0xd2, 0x3b, 0x4f,
+0x3b, 0x186, 0x300, 0x3b, 0x42, 0x3b, 0x186, 0x300, 0x6e, 0x64, 0x77, 0x65,
+0x6e, 0x69, 0x74, 0x3b, 0x6e, 0x64, 0x77, 0x65, 0x6e, 0x6e, 0x67, 0x65,
+0x69, 0x68, 0x3b, 0x6e, 0x64, 0x77, 0x65, 0x6e, 0x73, 0x61, 0x6d, 0x3b,
+0x6e, 0x64, 0x77, 0x65, 0x6e, 0x73, 0x65, 0x69, 0x71, 0x3b, 0x6e, 0x64,
+0x77, 0x65, 0x6e, 0x6e, 0x67, 0x75, 0x78, 0x3b, 0x6e, 0x64, 0x77, 0x65,
+0x6e, 0x6c, 0x6f, 0x65, 0x67, 0x3b, 0x6e, 0x64, 0x77, 0x65, 0x6e, 0x63,
+0x61, 0x65, 0x74, 0x3b, 0x6e, 0x64, 0x77, 0x65, 0x6e, 0x62, 0x65, 0x74,
+0x3b, 0x6e, 0x64, 0x77, 0x65, 0x6e, 0x67, 0x6f, 0x75, 0x6a, 0x3b, 0x6e,
+0x64, 0x77, 0x65, 0x6e, 0x63, 0x69, 0x62, 0x3b, 0x6e, 0x64, 0x77, 0x65,
+0x6e, 0x63, 0x69, 0x62, 0x2019, 0x69, 0x74, 0x3b, 0x6e, 0x64, 0x77, 0x65,
+0x6e, 0x63, 0x69, 0x62, 0x6e, 0x67, 0x65, 0x69, 0x68, 0x4a, 0x61, 0x6e,
+0x75, 0x77, 0x61, 0x72, 0x69, 0x3b, 0x46, 0x65, 0x62, 0x72, 0x75, 0x77,
+0x61, 0x72, 0x69, 0x3b, 0x4d, 0x61, 0x73, 0x68, 0x69, 0x3b, 0x45, 0x70,
+0x68, 0x72, 0x65, 0x6c, 0x69, 0x3b, 0x4d, 0x65, 0x79, 0x69, 0x3b, 0x4a,
+0x75, 0x6e, 0x69, 0x3b, 0x4a, 0x75, 0x6c, 0x61, 0x79, 0x69, 0x3b, 0x41,
+0x67, 0x61, 0x73, 0x74, 0x69, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x68, 0x65,
+0x6d, 0x62, 0x61, 0x3b, 0x4f, 0x6b, 0x74, 0x68, 0x6f, 0x62, 0x61, 0x3b,
+0x4e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x44, 0x69, 0x73, 0x65,
+0x6d, 0x62, 0x61, 0x4a, 0x61, 0x6e, 0x3b, 0x46, 0x65, 0x62, 0x3b, 0x4d,
+0x61, 0x73, 0x3b, 0x45, 0x70, 0x68, 0x3b, 0x4d, 0x65, 0x79, 0x3b, 0x4a,
+0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x3b, 0x41, 0x67, 0x61, 0x3b, 0x53,
+0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b, 0x4e, 0x6f, 0x76, 0x3b, 0x44,
+0x69, 0x73, 0x4a, 0x3b, 0x46, 0x3b, 0x4d, 0x3b, 0x45, 0x3b, 0x4d, 0x3b,
+0x4a, 0x3b, 0x4a, 0x3b, 0x41, 0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b,
+0x44, 0x31, 0x2d, 0x4b, 0x79, 0x73, 0xe3, 0x3b, 0x32, 0x2d, 0x4b, 0x79,
+0x73, 0xe3, 0x3b, 0x33, 0x2d, 0x4b, 0x79, 0x73, 0xe3, 0x3b, 0x34, 0x2d,
+0x4b, 0x79, 0x73, 0xe3, 0x3b, 0x35, 0x2d, 0x4b, 0x79, 0x73, 0xe3, 0x3b,
+0x36, 0x2d, 0x4b, 0x79, 0x73, 0xe3, 0x3b, 0x37, 0x2d, 0x4b, 0x79, 0x73,
+0xe3, 0x3b, 0x38, 0x2d, 0x4b, 0x79, 0x73, 0xe3, 0x3b, 0x39, 0x2d, 0x4b,
+0x79, 0x73, 0xe3, 0x3b, 0x31, 0x30, 0x2d, 0x4b, 0x79, 0x73, 0xe3, 0x3b,
+0x31, 0x31, 0x2d, 0x4b, 0x79, 0x73, 0xe3, 0x3b, 0x31, 0x32, 0x2d, 0x4b,
+0x79, 0x73, 0xe3, 0x31, 0x4b, 0x79, 0x2e, 0x3b, 0x32, 0x4b, 0x79, 0x2e,
+0x3b, 0x33, 0x4b, 0x79, 0x2e, 0x3b, 0x34, 0x4b, 0x79, 0x2e, 0x3b, 0x35,
+0x4b, 0x79, 0x2e, 0x3b, 0x36, 0x4b, 0x79, 0x2e, 0x3b, 0x37, 0x4b, 0x79,
+0x2e, 0x3b, 0x38, 0x4b, 0x79, 0x2e, 0x3b, 0x39, 0x4b, 0x79, 0x2e, 0x3b,
+0x31, 0x30, 0x4b, 0x79, 0x2e, 0x3b, 0x31, 0x31, 0x4b, 0x79, 0x2e, 0x3b,
+0x31, 0x32, 0x4b, 0x79, 0x2e, 0x31, 0x4b, 0x3b, 0x32, 0x4b, 0x3b, 0x33,
+0x4b, 0x3b, 0x34, 0x4b, 0x3b, 0x35, 0x4b, 0x3b, 0x36, 0x4b, 0x3b, 0x37,
+0x4b, 0x3b, 0x38, 0x4b, 0x3b, 0x39, 0x4b, 0x3b, 0x31, 0x30, 0x4b, 0x3b,
+0x31, 0x31, 0x4b, 0x3b, 0x31, 0x32, 0x4b, 0x79, 0x65, 0x70, 0xe9, 0x3b,
+0x6d, 0x75, 0x6b, 0x169, 0x69, 0x3b, 0x6d, 0x75, 0x73, 0x61, 0x70, 0xed,
+0x72, 0x69, 0x3b, 0x69, 0x72, 0x169, 0x64, 0xed, 0x3b, 0x70, 0xfa, 0x3b,
+0x70, 0xfa, 0x2d, 0x79, 0x65, 0x70, 0xe9, 0x3b, 0x70, 0xfa, 0x2d, 0x6d,
+0x75, 0x6b, 0x169, 0x69, 0x3b, 0x70, 0xfa, 0x2d, 0x6d, 0x75, 0x73, 0x61,
+0x70, 0xed, 0x72, 0x69, 0x3b, 0x70, 0xfa, 0x2d, 0x69, 0x72, 0x169, 0x64,
+0xed, 0x3b, 0x79, 0x65, 0x70, 0xe9, 0x2d, 0x70, 0x75, 0x74, 0x69, 0x6d,
+0x61, 0xe3, 0x3b, 0x79, 0x65, 0x70, 0xe9, 0x2d, 0x79, 0x65, 0x70, 0xe9,
+0x3b, 0x79, 0x65, 0x70, 0xe9, 0x2d, 0x6d, 0x75, 0x6b, 0x169, 0x69, 0x79,
+0x65, 0x3b, 0x6d, 0x6b, 0x3b, 0x6d, 0x73, 0x3b, 0x69, 0x64, 0x3b, 0x70,
+0x75, 0x3b, 0x70, 0x79, 0x3b, 0x70, 0x6d, 0x3b, 0x70, 0x73, 0x3b, 0x70,
+0x69, 0x3b, 0x79, 0x70, 0x3b, 0x79, 0x79, 0x3b, 0x79, 0x6d, 0x59, 0x3b,
+0x4d, 0x3b, 0x4d, 0x3b, 0x49, 0x3b, 0x50, 0x3b, 0x50, 0x3b, 0x50, 0x3b,
+0x50, 0x3b, 0x50, 0x3b, 0x59, 0x3b, 0x59, 0x3b, 0x59, 0x91c, 0x928, 0x935,
+0x930, 0x940, 0x3b, 0x92b, 0x930, 0x935, 0x930, 0x940, 0x3b, 0x92e, 0x93e, 0x930,
+0x94d, 0x91a, 0x3b, 0x905, 0x92a, 0x94d, 0x930, 0x948, 0x932, 0x3b, 0x92e, 0x908,
+0x3b, 0x91c, 0x942, 0x928, 0x3b, 0x91c, 0x941, 0x932, 0x93e, 0x908, 0x3b, 0x905,
+0x917, 0x938, 0x94d, 0x924, 0x3b, 0x938, 0x93f, 0x924, 0x92e, 0x94d, 0x92c, 0x930,
+0x3b, 0x905, 0x915, 0x94d, 0x91f, 0x942, 0x92c, 0x930, 0x3b, 0x928, 0x935, 0x92e,
+0x94d, 0x92c, 0x930, 0x3b, 0x926, 0x93f, 0x938, 0x902, 0x92c, 0x930, 0x4a, 0x61,
+0x6e, 0x65, 0x77, 0x6f, 0x6f, 0x72, 0x65, 0x3b, 0x46, 0x65, 0x62, 0x72,
+0x65, 0x77, 0x6f, 0x6f, 0x72, 0x65, 0x3b, 0x4d, 0x61, 0x61, 0x72, 0x74,
+0x73, 0x3b, 0x41, 0x70, 0x72, 0x69, 0x6c, 0x3b, 0x4d, 0x65, 0x69, 0x3b,
+0x4a, 0xfc, 0xfc, 0x6e, 0x65, 0x3b, 0x4a, 0xfc, 0xfc, 0x6c, 0x65, 0x3b,
+0x41, 0x75, 0x67, 0x75, 0x73, 0x74, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65,
+0x6d, 0x62, 0x65, 0x72, 0x3b, 0x4f, 0x6b, 0x74, 0x75, 0x75, 0x62, 0x65,
+0x72, 0x3b, 0x4e, 0x6f, 0x66, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x3b, 0x44,
+0x65, 0x74, 0x73, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x4a, 0x61, 0x6e, 0x3b,
+0x46, 0x65, 0x62, 0x3b, 0x4d, 0x61, 0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b,
+0x4d, 0x65, 0x69, 0x3b, 0x4a, 0xfc, 0x6e, 0x3b, 0x4a, 0xfc, 0x6c, 0x3b,
+0x41, 0x75, 0x67, 0x3b, 0x53, 0x65, 0x70, 0x3b, 0x4f, 0x6b, 0x74, 0x3b,
+0x4e, 0x6f, 0x66, 0x3b, 0x44, 0x65, 0x74, 0x6d, 0x75, 0x6e, 0x20, 0x23,
+0x31, 0x3b, 0x6d, 0x75, 0x6e, 0x20, 0x23, 0x32, 0x3b, 0x6d, 0x75, 0x6e,
+0x20, 0x23, 0x33, 0x3b, 0x6d, 0x75, 0x6e, 0x20, 0x23, 0x34, 0x3b, 0x6d,
+0x75, 0x6e, 0x20, 0x23, 0x35, 0x3b, 0x6d, 0x75, 0x6e, 0x20, 0x23, 0x36,
+0x3b, 0x6d, 0x75, 0x6e, 0x20, 0x23, 0x37, 0x3b, 0x6d, 0x75, 0x6e, 0x20,
+0x23, 0x38, 0x3b, 0x6d, 0x75, 0x6e, 0x20, 0x23, 0x39, 0x3b, 0x6d, 0x75,
+0x6e, 0x20, 0x23, 0x31, 0x30, 0x3b, 0x6d, 0x75, 0x6e, 0x20, 0x23, 0x31,
+0x31, 0x3b, 0x6d, 0x75, 0x6e, 0x20, 0x23, 0x31, 0x32, 0x4a, 0x61, 0x6e,
+0x75, 0x61, 0x72, 0x65, 0x3b, 0x46, 0x65, 0x62, 0x75, 0x61, 0x72, 0x65,
+0x3b, 0x4d, 0x61, 0x73, 0x3b, 0x45, 0x70, 0x72, 0x65, 0x6c, 0x3b, 0x4d,
+0x65, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0x75, 0x6c, 0x61, 0x65,
+0x3b, 0x4f, 0x67, 0x75, 0x73, 0x3b, 0x53, 0x65, 0x70, 0x74, 0x65, 0x6d,
+0x62, 0x61, 0x3b, 0x4f, 0x6b, 0x74, 0x6f, 0x62, 0x61, 0x3b, 0x4e, 0x6f,
+0x76, 0x65, 0x6d, 0x62, 0x61, 0x3b, 0x44, 0x69, 0x73, 0x65, 0x6d, 0x62,
+0x61, 0x62c, 0x646, 0x648, 0x631, 0x6cc, 0x3b, 0x67e, 0x631, 0x648, 0x631, 0x6cc,
+0x3b, 0x645, 0x627, 0x631, 0x686, 0x3b, 0x627, 0x67e, 0x631, 0x6ce, 0x644, 0x3b,
+0x645, 0x626, 0x6cc, 0x6cc, 0x3b, 0x62c, 0x648, 0x646, 0x3b, 0x62c, 0x6c6, 0x644,
+0x627, 0x6cc, 0x6cc, 0x3b, 0x627, 0x6af, 0x633, 0x62a, 0x3b, 0x633, 0x62a, 0x645,
+0x628, 0x631, 0x3b, 0x627, 0x6a9, 0x62a, 0x648, 0x628, 0x631, 0x3b, 0x646, 0x626,
+0x648, 0x645, 0x628, 0x631, 0x3b, 0x62f, 0x633, 0x645, 0x628, 0x631, 0x62c, 0x646,
+0x3b, 0x67e, 0x631, 0x3b, 0x645, 0x627, 0x631, 0x3b, 0x627, 0x67e, 0x631, 0x3b,
+0x645, 0x626, 0x6cc, 0x6cc, 0x3b, 0x62c, 0x648, 0x646, 0x3b, 0x62c, 0x6c6, 0x644,
+0x3b, 0x627, 0x6af, 0x633, 0x62a, 0x3b, 0x633, 0x62a, 0x645, 0x3b, 0x627, 0x6a9,
+0x62a, 0x3b, 0x646, 0x626, 0x648, 0x645, 0x3b, 0x62f, 0x633, 0x645, 0x4a, 0x61,
+0x6e, 0x77, 0x61, 0x72, 0x69, 0x3b, 0x50, 0x61, 0x72, 0x77, 0x61, 0x72,
+0x69, 0x3b, 0x4d, 0xe1, 0x72, 0x63, 0x68, 0x3b, 0x41, 0x70, 0x72, 0xe9,
+0x6c, 0x3b, 0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0xf3,
+0x6c, 0xe1, 0x69, 0x3b, 0x41, 0x67, 0x61, 0x73, 0x74, 0x3b, 0x53, 0x61,
+0x74, 0x61, 0x6d, 0x62, 0x61, 0x72, 0x3b, 0x41, 0x6b, 0x74, 0x75, 0x62,
+0x61, 0x72, 0x3b, 0x4e, 0x61, 0x77, 0x61, 0x6d, 0x62, 0x61, 0x72, 0x3b,
+0x44, 0x61, 0x73, 0x61, 0x6d, 0x62, 0x61, 0x72, 0x4a, 0x61, 0x6e, 0x3b,
+0x50, 0x61, 0x72, 0x3b, 0x4d, 0xe1, 0x72, 0x3b, 0x41, 0x70, 0x72, 0x3b,
+0x4d, 0x61, 0x69, 0x3b, 0x4a, 0x75, 0x6e, 0x3b, 0x4a, 0xf3, 0x6c, 0x3b,
+0x41, 0x67, 0x61, 0x3b, 0x53, 0x61, 0x74, 0x3b, 0x41, 0x6b, 0x74, 0x3b,
+0x4e, 0x61, 0x77, 0x3b, 0x44, 0x61, 0x73, 0x7a, 0x65, 0x6e, 0xe2, 0x3b,
+0x66, 0x72, 0x65, 0x76, 0xe2, 0x3b, 0x6d, 0x61, 0x72, 0x73, 0x6f, 0x3b,
+0x61, 0x72, 0x76, 0xee, 0x3b, 0x6d, 0x61, 0x7a, 0x7a, 0x6f, 0x3b, 0x7a,
+0x75, 0x67, 0x6e, 0x6f, 0x3b, 0x6c, 0x75, 0x67, 0x67, 0x69, 0x6f, 0x3b,
+0x61, 0x67, 0x6f, 0x73, 0x74, 0x6f, 0x3b, 0x73, 0x65, 0x74, 0x74, 0x65,
+0x6d, 0x62, 0x72, 0x65, 0x3b, 0x6f, 0x74, 0x74, 0x6f, 0x62, 0x72, 0x65,
+0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x65,
+0x78, 0x65, 0x6d, 0x62, 0x72, 0x65, 0x64, 0x65, 0x20, 0x7a, 0x65, 0x6e,
+0xe2, 0x3b, 0x64, 0x65, 0x20, 0x66, 0x72, 0x65, 0x76, 0xe2, 0x3b, 0x64,
+0x65, 0x20, 0x6d, 0x61, 0x72, 0x73, 0x6f, 0x3b, 0x64, 0x2019, 0x61, 0x72,
+0x76, 0xee, 0x3b, 0x64, 0x65, 0x20, 0x6d, 0x61, 0x7a, 0x7a, 0x6f, 0x3b,
+0x64, 0x65, 0x20, 0x7a, 0x75, 0x67, 0x6e, 0x6f, 0x3b, 0x64, 0x65, 0x20,
+0x6c, 0x75, 0x67, 0x67, 0x69, 0x6f, 0x3b, 0x64, 0x2019, 0x61, 0x67, 0x6f,
+0x73, 0x74, 0x6f, 0x3b, 0x64, 0x65, 0x20, 0x73, 0x65, 0x74, 0x74, 0x65,
+0x6d, 0x62, 0x72, 0x65, 0x3b, 0x64, 0x2019, 0x6f, 0x74, 0x74, 0x6f, 0x62,
+0x72, 0x65, 0x3b, 0x64, 0x65, 0x20, 0x6e, 0x6f, 0x76, 0x65, 0x6d, 0x62,
+0x72, 0x65, 0x3b, 0x64, 0x65, 0x20, 0x64, 0x65, 0x78, 0x65, 0x6d, 0x62,
+0x72, 0x65, 0x7a, 0x65, 0x6e, 0x2e, 0x3b, 0x66, 0x72, 0x65, 0x2e, 0x3b,
+0x6d, 0x61, 0x72, 0x2e, 0x3b, 0x61, 0x72, 0x76, 0x2e, 0x3b, 0x6d, 0x61,
+0x7a, 0x2e, 0x3b, 0x7a, 0x75, 0x67, 0x2e, 0x3b, 0x6c, 0x75, 0x67, 0x2e,
+0x3b, 0x61, 0x67, 0x6f, 0x2e, 0x3b, 0x73, 0x65, 0x74, 0x2e, 0x3b, 0x6f,
+0x74, 0x74, 0x2e, 0x3b, 0x6e, 0x6f, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x78,
+0x2e, 0x64, 0x65, 0x20, 0x7a, 0x65, 0x6e, 0x2e, 0x3b, 0x64, 0x65, 0x20,
+0x66, 0x72, 0x65, 0x2e, 0x3b, 0x64, 0x65, 0x20, 0x6d, 0x61, 0x72, 0x2e,
+0x3b, 0x64, 0x2019, 0x61, 0x72, 0x76, 0x2e, 0x3b, 0x64, 0x65, 0x20, 0x6d,
+0x61, 0x7a, 0x2e, 0x3b, 0x64, 0x65, 0x20, 0x7a, 0x75, 0x67, 0x2e, 0x3b,
+0x64, 0x65, 0x20, 0x6c, 0x75, 0x67, 0x2e, 0x3b, 0x64, 0x2019, 0x61, 0x67,
+0x6f, 0x2e, 0x3b, 0x64, 0x65, 0x20, 0x73, 0x65, 0x74, 0x2e, 0x3b, 0x64,
+0x2019, 0x6f, 0x74, 0x74, 0x2e, 0x3b, 0x64, 0x65, 0x20, 0x6e, 0x6f, 0x76,
+0x2e, 0x3b, 0x64, 0x65, 0x20, 0x64, 0x65, 0x78, 0x2e, 0x5a, 0x4e, 0x3b,
+0x46, 0x52, 0x3b, 0x4d, 0x52, 0x3b, 0x41, 0x52, 0x3b, 0x4d, 0x5a, 0x3b,
+0x5a, 0x47, 0x3b, 0x4c, 0x47, 0x3b, 0x41, 0x47, 0x3b, 0x53, 0x54, 0x3b,
+0x4f, 0x54, 0x3b, 0x4e, 0x56, 0x3b, 0x44, 0x58, 0x269, 0x6a, 0x69, 0x6b,
+0x61, 0x77, 0x1dd, 0x72, 0x6b, 0x61, 0x20, 0x6b, 0x61, 0x14b, 0x254, 0x72,
+0x254, 0x3b, 0x269, 0x6a, 0x69, 0x6b, 0x70, 0x61, 0x6b, 0x61, 0x20, 0x6b,
+0x61, 0x14b, 0x254, 0x72, 0x254, 0x3b, 0x61, 0x72, 0x25b, 0x301, 0x63, 0x69,
+0x6b, 0x61, 0x20, 0x6b, 0x61, 0x14b, 0x254, 0x72, 0x254, 0x3b, 0x6e, 0x6a,
+0x269, 0x62, 0x254, 0x20, 0x6e, 0x256, 0x28a, 0x6b, 0x61, 0x20, 0x6b, 0x61,
+0x14b, 0x254, 0x72, 0x254, 0x3b, 0x61, 0x63, 0x61, 0x66, 0x28a, 0x6e, 0x256,
+0x75, 0x6b, 0x61, 0x20, 0x6b, 0x61, 0x14b, 0x254, 0x72, 0x254, 0x3b, 0x61,
+0x6e, 0x254, 0x254, 0x256, 0x75, 0x6b, 0x61, 0x20, 0x6b, 0x61, 0x14b, 0x254,
+0x72, 0x254, 0x3b, 0x61, 0x6c, 0xe0, 0x6c, 0x61, 0x6b, 0x61, 0x20, 0x6b,
+0x61, 0x14b, 0x254, 0x72, 0x254, 0x3b, 0x269, 0x6a, 0x69, 0x6b, 0x1dd, 0x75,
+0x6b, 0x61, 0x20, 0x6b, 0x61, 0x14b, 0x254, 0x72, 0x254, 0x3b, 0x61, 0x62,
+0x6f, 0x66, 0x28a, 0x6d, 0x6b, 0x61, 0x20, 0x6b, 0x61, 0x14b, 0x254, 0x72,
+0x254, 0x3b, 0x269, 0x6a, 0x69, 0x63, 0x69, 0x6d, 0x6b, 0x61, 0x20, 0x6b,
+0x61, 0x14b, 0x254, 0x72, 0x254, 0x3b, 0x61, 0x63, 0x61, 0x70, 0x6f, 0x6d,
+0x6b, 0x61, 0x20, 0x6b, 0x61, 0x14b, 0x254, 0x72, 0x254, 0x3b, 0x61, 0x6e,
+0x254, 0x254, 0x62, 0x28a, 0x6e, 0x6b, 0x61, 0x20, 0x6b, 0x61, 0x14b, 0x254,
+0x72, 0x254, 0x6b, 0x61, 0x77, 0x3b, 0x6b, 0x70, 0x61, 0x3b, 0x63, 0x69,
+0x3b, 0x256, 0x28a, 0x3b, 0x256, 0x75, 0x35, 0x3b, 0x256, 0x75, 0x36, 0x3b,
+0x6c, 0x61, 0x3b, 0x6b, 0x1dd, 0x75, 0x3b, 0x66, 0x28a, 0x6d, 0x3b, 0x63,
+0x69, 0x6d, 0x3b, 0x70, 0x6f, 0x6d, 0x3b, 0x62, 0x28a, 0x6e, 0x6a, 0x65,
+0x6e, 0x61, 0x72, 0x6f, 0x3b, 0x66, 0x65, 0x62, 0x72, 0x61, 0x72, 0x6f,
+0x3b, 0x6d, 0x61, 0x72, 0x73, 0x6f, 0x3b, 0x61, 0x70, 0x72, 0x69, 0x6c,
+0x65, 0x3b, 0x6d, 0x61, 0x6a, 0x6f, 0x3b, 0x6a, 0x75, 0x67, 0x6e, 0x6f,
+0x3b, 0x6c, 0x75, 0x6a, 0x6f, 0x3b, 0x61, 0x67, 0x6f, 0x73, 0x74, 0x6f,
+0x3b, 0x73, 0x65, 0x74, 0x65, 0x6e, 0x62, 0x72, 0x65, 0x3b, 0x6f, 0x74,
+0x6f, 0x62, 0x72, 0x65, 0x3b, 0x6e, 0x6f, 0x76, 0x65, 0x6e, 0x62, 0x72,
+0x65, 0x3b, 0x64, 0x65, 0x73, 0x65, 0x6e, 0x62, 0x72, 0x65, 0x6a, 0x65,
+0x6e, 0x3b, 0x66, 0x65, 0x62, 0x3b, 0x6d, 0x61, 0x72, 0x3b, 0x61, 0x70,
+0x72, 0x3b, 0x6d, 0x61, 0x6a, 0x3b, 0x6a, 0x75, 0x67, 0x3b, 0x6c, 0x75,
+0x6a, 0x3b, 0x61, 0x67, 0x6f, 0x3b, 0x73, 0x65, 0x74, 0x3b, 0x6f, 0x74,
+0x6f, 0x3b, 0x6e, 0x6f, 0x76, 0x3b, 0x64, 0x65, 0x73, 0x4a, 0x3b, 0x46,
+0x3b, 0x4d, 0x3b, 0x41, 0x3b, 0x4d, 0x3b, 0x4a, 0x3b, 0x4c, 0x3b, 0x41,
+0x3b, 0x53, 0x3b, 0x4f, 0x3b, 0x4e, 0x3b, 0x44
};
// GENERATED PART ENDS HERE
diff --git a/src/corelib/time/qromancalendar_p.h b/src/corelib/time/qromancalendar_p.h
index 9b5e7afd0c..96501ce701 100644
--- a/src/corelib/time/qromancalendar_p.h
+++ b/src/corelib/time/qromancalendar_p.h
@@ -29,6 +29,12 @@ public:
bool isLunar() const override;
bool isLuniSolar() const override;
bool isSolar() const override;
+
+ // Names of months (implemented in qlocale.cpp):
+ QString monthName(const QLocale &locale, int month, int year,
+ QLocale::FormatType format) const override;
+ QString standaloneMonthName(const QLocale &locale, int month, int year,
+ QLocale::FormatType format) const override;
protected:
// locale support:
const QCalendarLocale *localeMonthIndexData() const override;
diff --git a/src/corelib/time/qtimezone.cpp b/src/corelib/time/qtimezone.cpp
index c5fc6e20a5..3a68277a6c 100644
--- a/src/corelib/time/qtimezone.cpp
+++ b/src/corelib/time/qtimezone.cpp
@@ -22,13 +22,6 @@ using namespace Qt::StringLiterals;
// Create default time zone using appropriate backend
static QTimeZonePrivate *newBackendTimeZone()
{
-#ifdef QT_NO_SYSTEMLOCALE
-#if QT_CONFIG(icu)
- return new QIcuTimeZonePrivate();
-#else
- return new QUtcTimeZonePrivate();
-#endif
-#else
#if defined(Q_OS_DARWIN)
return new QMacTimeZonePrivate();
#elif defined(Q_OS_ANDROID)
@@ -41,21 +34,13 @@ static QTimeZonePrivate *newBackendTimeZone()
return new QWinTimeZonePrivate();
#else
return new QUtcTimeZonePrivate();
-#endif // System Locales
-#endif // QT_NO_SYSTEMLOCALE
+#endif // Backend selection
}
// Create named time zone using appropriate backend
static QTimeZonePrivate *newBackendTimeZone(const QByteArray &ianaId)
{
Q_ASSERT(!ianaId.isEmpty());
-#ifdef QT_NO_SYSTEMLOCALE
-#if QT_CONFIG(icu)
- return new QIcuTimeZonePrivate(ianaId);
-#else
- return new QUtcTimeZonePrivate(ianaId);
-#endif
-#else
#if defined(Q_OS_DARWIN)
return new QMacTimeZonePrivate(ianaId);
#elif defined(Q_OS_ANDROID)
@@ -68,8 +53,7 @@ static QTimeZonePrivate *newBackendTimeZone(const QByteArray &ianaId)
return new QWinTimeZonePrivate(ianaId);
#else
return new QUtcTimeZonePrivate(ianaId);
-#endif // System Locales
-#endif // QT_NO_SYSTEMLOCALE
+#endif // Backend selection
}
class QTimeZoneSingleton
@@ -77,10 +61,11 @@ class QTimeZoneSingleton
public:
QTimeZoneSingleton() : backend(newBackendTimeZone()) {}
- // The global_tz is the tz to use in static methods such as availableTimeZoneIds() and
- // isTimeZoneIdAvailable() and to create named IANA time zones. This is usually the host
- // system, but may be different if the host resources are insufficient or if
- // QT_NO_SYSTEMLOCALE is set. A simple UTC backend is used if no alternative is available.
+ // The global_tz is the tz to use in static methods such as
+ // availableTimeZoneIds() and isTimeZoneIdAvailable() and to create named
+ // IANA time zones. This is usually the host system, but may be different if
+ // the host resources are insufficient. A simple UTC backend is used if no
+ // alternative is available.
QExplicitlySharedDataPointer<QTimeZonePrivate> backend;
};
@@ -95,6 +80,8 @@ Q_GLOBAL_STATIC(QTimeZoneSingleton, global_tz);
\brief QTimeZone identifies how a time representation relates to UTC.
+ \compares equality
+
When dates and times are combined, the meaning of the result depends on how
time is being represented. There are various international standards for
representing time; one of these, UTC, corresponds to the traditional
@@ -177,7 +164,7 @@ Q_GLOBAL_STATIC(QTimeZoneSingleton, global_tz);
A default UTC time zone backend is provided which is always available when
feature \c timezone is enabled. This provides a set of generic Offset From
- UTC time zones in the range UTC-14:00 to UTC+14:00. These time zones can be
+ UTC time zones in the range UTC-16:00 to UTC+16:00. These time zones can be
created using either the standard ISO format names, such as "UTC+00:00", as
listed by availableTimeZoneIds(), or using a name of similar form in
combination with the number of offset seconds.
@@ -254,17 +241,34 @@ Q_GLOBAL_STATIC(QTimeZoneSingleton, global_tz);
*/
/*!
- \enum QTimeZone::anonymous
+ \variable QTimeZone::MinUtcOffsetSecs
+ \brief Timezone offsets from UTC are expected to be no lower than this.
+
+ The lowest UTC offset of any early 21st century timezone is -12 hours (Baker
+ Island, USA), or 12 hours west of Greenwich.
+
+ Historically, until 1844, The Philippines (then controlled by Spain) used
+ the same date as Spain's American holdings, so had offsets close to 16 hours
+ west of Greenwich. As The Philippines was using local solar mean time, it is
+ possible some outlying territory of it may have been operating at more than
+ 16 hours west of Greenwich, but no early 21st century timezone traces its
+ history back to such an extreme.
+
+ \sa MaxUtcOffsetSecs
+*/
+/*!
+ \variable QTimeZone::MaxUtcOffsetSecs
+ \brief Timezone offsets from UTC are expected to be no higher than this.
+
+ The highest UTC offset of any early 21st century timezone is +14 hours
+ (Christmas Island, Kiribati, Kiritimati), or 14 hours east of Greenwich.
- This enumeration provides constants bounding the range of plausible timezone
- offsets from UTC, measured in seconds.
- Sane UTC offsets range from -14 to +14 hours.
- No known zone has offset > 12 hrs West of Greenwich (Baker Island, USA).
- No known zone has offset > 14 hrs East of Greenwich (Kiritimati, Christmas Island, Kiribati).
- Note that there are zones whose offsets differ by more than a day.
+ Historically, before 1867, when Russia sold Alaska to America, Alaska used
+ the same date as Russia, so had offsets over 15 hours east of Greenwich. As
+ Alaska was using local solar mean time, its offsets varied, but all were
+ less than 16 hours east of Greenwich.
- \value MinUtcOffsetSecs -14 * 3600,
- \value MaxUtcOffsetSecs +14 * 3600
+ \sa MinUtcOffsetSecs
*/
#if QT_CONFIG(timezone)
@@ -435,22 +439,27 @@ QTimeZone::Data &QTimeZone::Data::operator=(QTimeZonePrivate *dptr) noexcept
Creates a time zone instance with the requested IANA ID \a ianaId.
The ID must be one of the available system IDs or a valid UTC-with-offset
- ID, otherwise an invalid time zone will be returned.
+ ID, otherwise an invalid time zone will be returned. For UTC-with-offset
+ IDs, when they are not in fact IANA IDs, the \c{id()} of the resulting
+ instance may differ from the ID passed to the constructor.
This constructor is only available when feature \c timezone is enabled.
- \sa availableTimeZoneIds()
+ \sa availableTimeZoneIds(), id()
*/
QTimeZone::QTimeZone(const QByteArray &ianaId)
{
- // Try and see if it's a CLDR UTC offset ID - just as quick by creating as
- // by looking up.
+ // Try and see if it's a recognized UTC offset ID - just as quick by
+ // creating as by looking up.
d = new QUtcTimeZonePrivate(ianaId);
- // If not a CLDR UTC offset ID then try creating it with the system backend.
- // Relies on backend not creating valid TZ with invalid name.
- if (!d->isValid())
- d = ianaId.isEmpty() ? newBackendTimeZone() : newBackendTimeZone(ianaId);
+ // If not recognized, try creating it with the system backend.
+ if (!d->isValid()) {
+ if (ianaId.isEmpty())
+ d = newBackendTimeZone();
+ else // Constructor MUST produce invalid for unsupported ID.
+ d = newBackendTimeZone(ianaId);
+ }
// Can also handle UTC with arbitrary (valid) offset, but only do so as
// fall-back, since either of the above may handle it more informatively.
if (!d->isValid()) {
@@ -468,13 +477,15 @@ QTimeZone::QTimeZone(const QByteArray &ianaId)
/*!
Creates a time zone instance with the given offset, \a offsetSeconds, from UTC.
- The \a offsetSeconds from UTC must be in the range -14 hours to +14 hours
+ The \a offsetSeconds from UTC must be in the range -16 hours to +16 hours
otherwise an invalid time zone will be returned.
This constructor is only available when feature \c timezone is enabled. The
returned instance is equivalent to the lightweight time representation
\c{QTimeZone::fromSecondsAfterUtc(offsetSeconds)}, albeit implemented as a
time zone.
+
+ \sa MinUtcOffsetSecs, MaxUtcOffsetSecs, id()
*/
QTimeZone::QTimeZone(int offsetSeconds)
@@ -486,27 +497,32 @@ QTimeZone::QTimeZone(int offsetSeconds)
/*!
Creates a custom time zone instance at fixed offset from UTC.
- The returned time zone has an ID of \a ianaId and an offset from UTC of \a
+ The returned time zone has an ID of \a zoneId and an offset from UTC of \a
offsetSeconds. The \a name will be the name used by displayName() for the
LongName, the \a abbreviation will be used by displayName() for the
ShortName and by abbreviation(), and the optional \a territory will be used
by territory(). The \a comment is an optional note that may be displayed in
a GUI to assist users in selecting a time zone.
- The \a ianaId must not be one of the available system IDs returned by
- availableTimeZoneIds(). The \a offsetSeconds from UTC must be in the range
- -14 hours to +14 hours.
+ The \a zoneId \e{must not} be one of the available system IDs returned by
+ availableTimeZoneIds(). The \a offsetSeconds from UTC must be in the range
+ -16 hours to +16 hours.
If the custom time zone does not have a specific territory then set it to the
default value of QLocale::AnyTerritory.
This constructor is only available when feature \c timezone is enabled.
+
+ \sa id(), offsetFromUtc(), displayName(), abbreviation(), territory(), comment(),
+ MinUtcOffsetSecs, MaxUtcOffsetSecs
*/
-QTimeZone::QTimeZone(const QByteArray &ianaId, int offsetSeconds, const QString &name,
+QTimeZone::QTimeZone(const QByteArray &zoneId, int offsetSeconds, const QString &name,
const QString &abbreviation, QLocale::Territory territory, const QString &comment)
- : d(isTimeZoneIdAvailable(ianaId) ? nullptr // Don't let client code hijack a real zone name.
- : new QUtcTimeZonePrivate(ianaId, offsetSeconds, name, abbreviation, territory, comment))
+ : d(QUtcTimeZonePrivate().isTimeZoneIdAvailable(zoneId)
+ || global_tz->backend->isTimeZoneIdAvailable(zoneId)
+ ? nullptr // Don't let client code hijack a real zone name.
+ : new QUtcTimeZonePrivate(zoneId, offsetSeconds, name, abbreviation, territory, comment))
{
}
@@ -529,16 +545,12 @@ QTimeZone::QTimeZone(QTimeZonePrivate &dd)
In all cases, the result's \l timeSpec() is Qt::TimeZone. When this
QTimeZone's timeSpec() is Qt::TimeZone, this QTimeZone itself is returned.
+ If timeSpec() is Qt::LocalTime then systemTimeZone() is returned.
If timeSpec() is Qt::UTC, QTimeZone::utc() is returned. If it is
Qt::OffsetFromUTC then QTimeZone(int) is passed its offset and the result is
returned.
- If timeSpec() is Qt::LocalTime then an instance of the current system time
- zone will be returned. This will not change to reflect any subsequent change
- to the system time zone. It represents the local time that was in effect
- when asBackendZone() was called.
-
When using a lightweight time representation - local time, UTC time or time
at a fixed offset from UTC - using methods only supported when feature \c
timezone is enabled may be more expensive than using a corresponding time
@@ -603,17 +615,18 @@ QTimeZone QTimeZone::asBackendZone() const
Returns a time representation at a fixed \a offset, in seconds, ahead of
UTC.
- The \a offset from UTC must be in the range -14 hours to +14 hours otherwise an
- invalid time zone will be returned. The returned QTimeZone is a lightweight
- time representation, not a time zone (backed by system-supplied or standard
- data).
+ The \a offset from UTC must be in the range -16 hours to +16 hours otherwise
+ an invalid time zone will be returned. The returned QTimeZone is a
+ lightweight time representation, not a time zone (backed by system-supplied
+ or standard data).
If the offset is 0, the \l timeSpec() of the returned instance will be
Qt::UTC. Otherwise, if \a offset is valid, timeSpec() is
Qt::OffsetFromUTC. An invalid time zone, when returned, has Qt::TimeZone as
its timeSpec().
- \sa QTimeZone(int), asBackendZone(), fixedSecondsAheadOfUtc()
+ \sa QTimeZone(int), asBackendZone(), fixedSecondsAheadOfUtc(),
+ MinUtcOffsetSecs, MaxUtcOffsetSecs
*/
/*!
@@ -707,7 +720,9 @@ QTimeZone &QTimeZone::operator=(const QTimeZone &other)
*/
/*!
- Returns \c true if this time representation is equal to the \a other.
+ \fn bool QTimeZone::operator==(const QTimeZone &lhs, const QTimeZone &rhs)
+
+ Returns \c true if \a lhs time zone is equal to the \a rhs time zone.
Two representations are different if they are internally described
differently, even if they agree in their representation of all moments of
@@ -715,33 +730,31 @@ QTimeZone &QTimeZone::operator=(const QTimeZone &other)
time zone but the two will not be equal.
*/
-bool QTimeZone::operator==(const QTimeZone &other) const
-{
- if (d.isShort())
- return other.d.isShort() && d.s == other.d.s;
-
- if (!other.d.isShort()) {
- if (d.d == other.d.d)
- return true;
-#if QT_CONFIG(timezone)
- return d.d && other.d.d && *d.d == *other.d.d;
-#endif
- }
-
- return false;
-}
-
/*!
- Returns \c true if this time zone is not equal to the \a other time zone.
+ \fn bool QTimeZone::operator!=(const QTimeZone &lhs, const QTimeZone &rhs)
+
+ Returns \c true if \a lhs time zone is not equal to the \a rhs time zone.
Two representations are different if they are internally described
differently, even if they agree in their representation of all moments of
time. In particular, a lightweight time representation may coincide with a
time zone but the two will not be equal.
*/
-bool QTimeZone::operator!=(const QTimeZone &other) const // ### Qt 7: inline
+
+bool comparesEqual(const QTimeZone &lhs, const QTimeZone &rhs) noexcept
{
- return !(*this == other);
+ if (lhs.d.isShort())
+ return rhs.d.isShort() && lhs.d.s == rhs.d.s;
+
+ if (!rhs.d.isShort()) {
+ if (lhs.d.d == rhs.d.d)
+ return true;
+#if QT_CONFIG(timezone)
+ return lhs.d.d && rhs.d.d && *lhs.d.d == *rhs.d.d;
+#endif
+ }
+
+ return false;
}
/*!
@@ -764,6 +777,28 @@ bool QTimeZone::isValid() const
IANA IDs are used on all platforms. On Windows these are translated from
the Windows ID into the best match IANA ID for the time zone and territory.
+ If this timezone instance was not constructed from an IANA ID, its ID is
+ determined by how it was constructed. In most cases, the ID passed when
+ constructing the instance is used. (The constructor for a custom zone uses
+ the ID it is passed, which must not be an IANA ID.) There are two
+ exceptions.
+ \list
+ \li Instances constructed by passing only a UTC offset in seconds have no ID
+ passed when constructing.
+ \li The constructor taking only an IANA ID will also accept some UTC-offset
+ IDs that are not in fact IANA IDs: its handling of these is equivalent
+ to passing the corresponding offset in seconds, as for the first
+ exception.
+ \endlist
+
+ In the two exceptional cases, if there is an IANA UTC-offset zone with the
+ specified offset, the instance constructed uses that IANA zone's ID, even
+ though this may differ from the (non-IANA) UTC-offset ID passed to the
+ constructor. Otherwise, the instance uses an ID synthesized from its offset,
+ with the form UTC±hh:mm:ss, omitting any trailing :00 for zero seconds or
+ minutes. Again, this may differ from the UTC-offset ID passed to the
+ constructor.
+
This method is only available when feature \c timezone is enabled.
*/
@@ -792,6 +827,14 @@ QByteArray QTimeZone::id() const
Returns the territory for the time zone.
+ A return of \l {QLocale::}{AnyTerritory} means the zone has no known
+ territorial association. In some cases this may be because the zone has no
+ associated territory - for example, UTC - or because the zone is used in
+ several territories - for example, CET. In other cases, the QTimeZone
+ backend may not know which territory the zone is associated with - for
+ example, because it is not the primary zone of the territory in which it is
+ used.
+
This method is only available when feature \c timezone is enabled.
*/
QLocale::Territory QTimeZone::territory() const
@@ -865,7 +908,7 @@ QString QTimeZone::displayName(const QDateTime &atDateTime, NameType nameType,
return systemTimeZone().displayName(atDateTime, nameType, locale);
case Qt::UTC:
case Qt::OffsetFromUTC:
- return QUtcTimeZonePrivate(d.s.offset).QTimeZonePrivate::displayName(
+ return QUtcTimeZonePrivate(d.s.offset).displayName(
atDateTime.toMSecsSinceEpoch(), nameType, locale);
case Qt::TimeZone:
Q_UNREACHABLE();
@@ -1110,9 +1153,12 @@ bool QTimeZone::isDaylightTime(const QDateTime &atDateTime) const
}
/*!
- Returns the effective offset details at the given \a forDateTime. This is
- the equivalent of calling offsetFromUtc(), abbreviation(), etc individually but is
- more efficient.
+ Returns the effective offset details at the given \a forDateTime.
+
+ This is the equivalent of calling abbreviation() and all three offset
+ functions individually but is more efficient. If this data is not available
+ for the given datetime, an invalid OffsetData will be returned with an
+ invalid QDateTime as its \c atUtc.
This method is only available when feature \c timezone is enabled.
@@ -1132,9 +1178,9 @@ QTimeZone::OffsetData QTimeZone::offsetData(const QDateTime &forDateTime) const
Q_UNREACHABLE();
break;
}
- } else if (hasTransitions()) {
- return QTimeZonePrivate::toOffsetData(d->data(forDateTime.toMSecsSinceEpoch()));
}
+ if (isValid())
+ return QTimeZonePrivate::toOffsetData(d->data(forDateTime.toMSecsSinceEpoch()));
return QTimeZonePrivate::invalidOffsetData();
}
@@ -1175,7 +1221,7 @@ bool QTimeZone::hasTransitions() const
Transition after it.
If there is no transition after the given \a afterDateTime then an invalid
- OffsetData will be returned with an invalid QDateTime.
+ OffsetData will be returned with an invalid QDateTime as its \c atUtc.
The given \a afterDateTime is exclusive.
@@ -1210,7 +1256,7 @@ QTimeZone::OffsetData QTimeZone::nextTransition(const QDateTime &afterDateTime)
Transition before it.
If there is no transition before the given \a beforeDateTime then an invalid
- OffsetData will be returned with an invalid QDateTime.
+ OffsetData will be returned with an invalid QDateTime as its \c atUtc.
The given \a beforeDateTime is exclusive.
@@ -1243,7 +1289,9 @@ QTimeZone::OffsetData QTimeZone::previousTransition(const QDateTime &beforeDateT
/*!
Returns a list of all time zone transitions between the given datetimes.
- The given \a fromDateTime and \a toDateTime are inclusive.
+ The given \a fromDateTime and \a toDateTime are inclusive. The \c atUtc
+ member of each entry describes the moment of the transition, at which the
+ offsets and abbreviation given by other members take effect.
This method is only available when feature \c timezone is enabled.
@@ -1280,13 +1328,25 @@ QTimeZone::OffsetDataList QTimeZone::transitions(const QDateTime &fromDateTime,
/*!
Returns the current system time zone IANA ID.
- On Windows this ID is translated from the Windows ID using an internal
- translation table and the user's selected country. As a consequence there
- is a small chance any Windows install may have IDs not known by Qt, in
- which case "UTC" will be returned.
+ Equivalent to calling systemTimeZone().id(), but may bypass some computation
+ to obtain it. Constructing a QTimeZone from the returned byte array will
+ produce the same result as systemTimeZone().
+
+ If the backend is unable to determine the correct system zone, the result is
+ empty. In this case, systemTimeZone().isValid() is false and a warning is
+ output if either this method of systemTimeZone() is called.
+
+ If the backend is able to determine the correct system zone but not its
+ name, an empty byte array is returned. For example, on Windows, the system
+ native ID is converted to an IANA ID - if the system ID isn't known to the
+ internal translation code, the result shall be empty. In this case,
+ systemTimeZone().isValid() shall be true.
This method is only available when feature \c timezone is enabled.
+ \note Prior to Qt 6.7, when the result could not be determined, the
+ misleading result "UTC" was returned.
+
\sa systemTimeZone()
*/
@@ -1296,12 +1356,7 @@ QByteArray QTimeZone::systemTimeZoneId()
if (!sys.isEmpty())
return sys;
// The system zone, despite the empty ID, may know its real ID anyway:
- auto zone = systemTimeZone();
- if (zone.isValid() && !zone.id().isEmpty())
- return zone.id();
- // TODO: "-00:00", meaning "unspecified local zone" in some RFC, may be more apt.
- // If all else fails, guess UTC.
- return QTimeZonePrivate::utcQByteArray();
+ return systemTimeZone().id();
}
/*!
@@ -1314,11 +1369,29 @@ QByteArray QTimeZone::systemTimeZoneId()
representation \c {QTimeZone(QTimeZone::LocalTime)}, albeit implemented as a
time zone.
- \sa utc(), Initialization, asBackendZone()
+ The returned object will not change to reflect any subsequent change to the
+ system time zone. It represents the local time that was in effect when
+ asBackendZone() was called. On misconfigured systems, such as those that
+ lack the timezone data relied on by the backend for which Qt was compiled,
+ it may be invalid. In such a case, a warning is output.
+
+ \sa utc(), Initialization, asBackendZone(), systemTimeZoneId()
*/
QTimeZone QTimeZone::systemTimeZone()
{
- return QTimeZone(global_tz->backend->systemTimeZoneId());
+ // Use ID even if empty, as default constructor is invalid but empty-ID
+ // constructor goes to backend's default constructor, which may succeed.
+ const auto sys = QTimeZone(global_tz->backend->systemTimeZoneId());
+ if (!sys.isValid()) {
+ static bool neverWarned = true;
+ if (neverWarned) {
+ // Racey but, at worst, merely repeats the warning.
+ neverWarned = false;
+ qWarning("Unable to determine system time zone: "
+ "please check your system configuration.");
+ }
+ }
+ return sys;
}
/*!
@@ -1340,6 +1413,9 @@ QTimeZone QTimeZone::utc()
/*!
Returns \c true if a given time zone \a ianaId is available on this system.
+ This may include some non-IANA IDs, notably UTC-offset IDs, that are not
+ listed in \l availableTimeZoneIds().
+
This method is only available when feature \c timezone is enabled.
\sa availableTimeZoneIds()
@@ -1350,7 +1426,7 @@ bool QTimeZone::isTimeZoneIdAvailable(const QByteArray &ianaId)
#if defined(Q_OS_UNIX) && !(defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN))
// Keep #if-ery consistent with selection of QTzTimeZonePrivate in
// newBackendTimeZone(). Skip the pre-check, as the TZ backend accepts POSIX
- // zone IDs, which need not be valid IANA IDs.
+ // zone IDs, which need not be valid IANA IDs. See also QTBUG-112006.
#else
// isValidId is not strictly required, but faster to weed out invalid
// IDs as availableTimeZoneIds() may be slow
@@ -1358,6 +1434,7 @@ bool QTimeZone::isTimeZoneIdAvailable(const QByteArray &ianaId)
return false;
#endif
return QUtcTimeZonePrivate().isTimeZoneIdAvailable(ianaId)
+ || QUtcTimeZonePrivate::offsetFromUtcString(ianaId) != QTimeZonePrivate::invalidSeconds()
|| global_tz->backend->isTimeZoneIdAvailable(ianaId);
}
@@ -1376,6 +1453,10 @@ static QList<QByteArray> set_union(const QList<QByteArray> &l1, const QList<QByt
This method is only available when feature \c timezone is enabled.
+ \note the QTimeZone constructor will also accept some UTC-offset IDs that
+ are not in the list returned - it would be impractical to list all possible
+ UTC-offset IDs.
+
\sa isTimeZoneIdAvailable()
*/
@@ -1388,14 +1469,14 @@ QList<QByteArray> QTimeZone::availableTimeZoneIds()
/*!
Returns a list of all available IANA time zone IDs for a given \a territory.
- As a special case, a \a territory of Qt::AnyTerritory returns those time zones
- that do not have any territory related to them, such as UTC. If you require
- a list of all time zone IDs for all countries then use the standard
- availableTimeZoneIds() method.
+ As a special case, a \a territory of \l {QLocale::}{AnyTerritory} selects
+ those time zones that have no known territorial association, such as UTC. If
+ you require a list of all time zone IDs for all territories then use the
+ standard availableTimeZoneIds() method.
This method is only available when feature \c timezone is enabled.
- \sa isTimeZoneIdAvailable()
+ \sa isTimeZoneIdAvailable(), territory()
*/
QList<QByteArray> QTimeZone::availableTimeZoneIds(QLocale::Territory territory)
@@ -1408,9 +1489,13 @@ QList<QByteArray> QTimeZone::availableTimeZoneIds(QLocale::Territory territory)
Returns a list of all available IANA time zone IDs with a given standard
time offset of \a offsetSeconds.
+ Where the given offset is supported, \c{QTimeZone(offsetSeconds).id()} is
+ included in the list, even if it is not an IANA ID. This only arises when
+ there is no IANA UTC-offset ID with the given offset.
+
This method is only available when feature \c timezone is enabled.
- \sa isTimeZoneIdAvailable()
+ \sa isTimeZoneIdAvailable(), QTimeZone(int)
*/
QList<QByteArray> QTimeZone::availableTimeZoneIds(int offsetSeconds)
@@ -1436,9 +1521,9 @@ QByteArray QTimeZone::ianaIdToWindowsId(const QByteArray &ianaId)
Returns the default IANA ID for a given \a windowsId.
Because a Windows ID can cover several IANA IDs in several different
- countries, this function returns the most frequently used IANA ID with no
- regard for the country and should thus be used with care. It is usually
- best to request the default for a specific country.
+ territories, this function returns the most frequently used IANA ID with no
+ regard for the territory and should thus be used with care. It is usually
+ best to request the default for a specific territory.
This method is only available when feature \c timezone is enabled.
@@ -1456,15 +1541,16 @@ QByteArray QTimeZone::windowsIdToDefaultIanaId(const QByteArray &windowsId)
Because a Windows ID can cover several IANA IDs within a given territory,
the most frequently used IANA ID in that territory is returned.
- As a special case, QLocale::AnyTerritory returns the default of those IANA IDs
- that do not have any specific territory.
+ As a special case, \l{QLocale::}{AnyTerritory} returns the default of those
+ IANA IDs that have no known territorial association.
This method is only available when feature \c timezone is enabled.
- \sa ianaIdToWindowsId(), windowsIdToIanaIds()
+ \sa ianaIdToWindowsId(), windowsIdToIanaIds(), territory()
*/
-QByteArray QTimeZone::windowsIdToDefaultIanaId(const QByteArray &windowsId, QLocale::Territory territory)
+QByteArray QTimeZone::windowsIdToDefaultIanaId(const QByteArray &windowsId,
+ QLocale::Territory territory)
{
return QTimeZonePrivate::windowsIdToDefaultIanaId(windowsId, territory);
}
@@ -1487,18 +1573,19 @@ QList<QByteArray> QTimeZone::windowsIdToIanaIds(const QByteArray &windowsId)
/*!
Returns all the IANA IDs for a given \a windowsId and \a territory.
- As a special case QLocale::AnyTerritory returns those IANA IDs that do
- not have any specific territory.
+ As a special case, \l{QLocale::}{AnyTerritory} selects those IANA IDs that
+ have no known territorial association.
The returned list is in order of frequency of usage, i.e. larger zones
within a territory are listed first.
This method is only available when feature \c timezone is enabled.
- \sa ianaIdToWindowsId(), windowsIdToDefaultIanaId()
+ \sa ianaIdToWindowsId(), windowsIdToDefaultIanaId(), territory()
*/
-QList<QByteArray> QTimeZone::windowsIdToIanaIds(const QByteArray &windowsId, QLocale::Territory territory)
+QList<QByteArray> QTimeZone::windowsIdToIanaIds(const QByteArray &windowsId,
+ QLocale::Territory territory)
{
return QTimeZonePrivate::windowsIdToIanaIds(windowsId, territory);
}
diff --git a/src/corelib/time/qtimezone.h b/src/corelib/time/qtimezone.h
index 273bcc7b1c..46c7d6312b 100644
--- a/src/corelib/time/qtimezone.h
+++ b/src/corelib/time/qtimezone.h
@@ -5,6 +5,7 @@
#ifndef QTIMEZONE_H
#define QTIMEZONE_H
+#include <QtCore/qcompare.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qlocale.h>
#include <QtCore/qswap.h>
@@ -12,7 +13,7 @@
#include <chrono>
-#if QT_CONFIG(timezone) && (defined(Q_OS_DARWIN) || defined(Q_QDOC)) && !defined(QT_NO_SYSTEMLOCALE)
+#if QT_CONFIG(timezone) && (defined(Q_OS_DARWIN) || defined(Q_QDOC))
Q_FORWARD_DECLARE_CF_TYPE(CFTimeZone);
Q_FORWARD_DECLARE_OBJC_CLASS(NSTimeZone);
#endif
@@ -48,7 +49,7 @@ class Q_CORE_EXPORT QTimeZone
#endif
{
}
- friend constexpr bool operator==(const ShortData &lhs, const ShortData &rhs)
+ friend constexpr bool operator==(ShortData lhs, ShortData rhs)
{ return lhs.mode == rhs.mode && lhs.offset == rhs.offset; }
constexpr Qt::TimeSpec spec() const { return Qt::TimeSpec((mode + 3) & 3); }
};
@@ -82,13 +83,13 @@ class Q_CORE_EXPORT QTimeZone
QTimeZone(ShortData sd) : d(sd) {}
public:
- // Sane UTC offsets range from -14 to +14 hours:
- enum {
- // No known zone > 12 hrs West of Greenwich (Baker Island, USA)
- MinUtcOffsetSecs = -14 * 3600,
- // No known zone > 14 hrs East of Greenwich (Kiritimati, Christmas Island, Kiribati)
- MaxUtcOffsetSecs = +14 * 3600
- };
+ // Sane UTC offsets range from -16 to +16 hours:
+ static constexpr int MinUtcOffsetSecs = -16 * 3600;
+ // No known modern zone > 12 hrs West of Greenwich.
+ // Until 1844, Asia/Manila (in The Philippines) was at 15:56 West.
+ static constexpr int MaxUtcOffsetSecs = +16 * 3600;
+ // No known modern zone > 14 hrs East of Greenwich.
+ // Until 1867, America/Metlakatla (in Alaska) was at 15:13:42 East.
enum Initialization { LocalTime, UTC };
@@ -114,8 +115,10 @@ public:
void swap(QTimeZone &other) noexcept
{ d.swap(other.d); }
+#if QT_CORE_REMOVED_SINCE(6, 7)
bool operator==(const QTimeZone &other) const;
bool operator!=(const QTimeZone &other) const;
+#endif
bool isValid() const;
@@ -128,7 +131,7 @@ public:
}
static QTimeZone fromSecondsAheadOfUtc(int offset)
{
- return fromDurationAheadOfUtc(std::chrono::seconds{offset});;
+ return fromDurationAheadOfUtc(std::chrono::seconds{offset});
}
constexpr Qt::TimeSpec timeSpec() const noexcept { return d.s.spec(); }
constexpr int fixedSecondsAheadOfUtc() const noexcept
@@ -211,7 +214,7 @@ public:
static QList<QByteArray> windowsIdToIanaIds(const QByteArray &windowsId,
QLocale::Territory territory);
-# if (defined(Q_OS_DARWIN) || defined(Q_QDOC)) && !defined(QT_NO_SYSTEMLOCALE)
+# if defined(Q_OS_DARWIN) || defined(Q_QDOC)
static QTimeZone fromCFTimeZone(CFTimeZoneRef timeZone);
CFTimeZoneRef toCFTimeZone() const Q_DECL_CF_RETURNS_RETAINED;
static QTimeZone fromNSTimeZone(const NSTimeZone *timeZone);
@@ -230,6 +233,9 @@ public:
# endif
#endif // feature timezone
private:
+ friend Q_CORE_EXPORT bool comparesEqual(const QTimeZone &lhs, const QTimeZone &rhs) noexcept;
+ Q_DECLARE_EQUALITY_COMPARABLE(QTimeZone)
+
#ifndef QT_NO_DATASTREAM
friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &ds, const QTimeZone &tz);
#endif
diff --git a/src/corelib/time/qtimezonelocale.cpp b/src/corelib/time/qtimezonelocale.cpp
new file mode 100644
index 0000000000..5757e55d28
--- /dev/null
+++ b/src/corelib/time/qtimezonelocale.cpp
@@ -0,0 +1,29 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <private/qtimezonelocale_p.h>
+#include <private/qtimezoneprivate_p.h>
+
+#if !QT_CONFIG(icu) // Use data generated from CLDR:
+# include <private/qtimezonelocale_data_p.h>
+# include <private/qtimezoneprivate_data_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#if QT_CONFIG(icu) // Get data from ICU:
+namespace QtTimeZoneLocale {
+
+} // QtTimeZoneLocale
+#else // No ICU, use QTZ[LP}_data_p.h data for feature timezone_locale.
+namespace {
+using namespace QtTimeZoneLocale; // QTZL_data_p.h
+using namespace QtTimeZoneCldr; // QTZP_data_p.h
+// Accessors for the QTZL_data_p.h
+
+// Accessors for the QTZP_data_p.h
+
+} // nameless namespace
+#endif // ICU
+
+QT_END_NAMESPACE
diff --git a/src/corelib/time/qtimezonelocale_data_p.h b/src/corelib/time/qtimezonelocale_data_p.h
new file mode 100644
index 0000000000..1cdbbaa952
--- /dev/null
+++ b/src/corelib/time/qtimezonelocale_data_p.h
@@ -0,0 +1,39 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: Unicode-3.0
+
+#ifndef QTIMEZONELOCALE_DATA_P_H
+#define QTIMEZONELOCALE_DATA_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of internal files. This header file may change from version to version
+// without notice, or even be removed.
+//
+// We mean it.
+//
+
+// Only qtimezonelocale.cpp should #include this (after other things it needs),
+// and even that only when feature icu is disabled.
+#include "qtimezonelocale_p.h"
+
+QT_REQUIRE_CONFIG(timezone_locale);
+#if QT_CONFIG(icu)
+# error "This file should only be needed (or seen) when ICU is not in use"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace QtTimeZoneLocale {
+
+// GENERATED PART STARTS HERE
+
+// GENERATED PART ENDS HERE
+
+} // QtTimeZoneLocale
+
+QT_END_NAMESPACE
+
+#endif // QTIMEZONELOCALE_DATA_P_H
diff --git a/src/corelib/time/qtimezonelocale_p.h b/src/corelib/time/qtimezonelocale_p.h
new file mode 100644
index 0000000000..adc8e83b35
--- /dev/null
+++ b/src/corelib/time/qtimezonelocale_p.h
@@ -0,0 +1,31 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTIMEZONELOCALE_P_H
+#define QTIMEZONELOCALE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of internal files. This header file may change from version to version
+// without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qtimezone.h>
+
+QT_REQUIRE_CONFIG(timezone);
+QT_REQUIRE_CONFIG(timezone_locale);
+
+namespace QtTimeZoneLocale {
+#if QT_CONFIG(icu)
+#else
+// Define data types for QTZL_data_p.h
+
+#endif
+}
+
+#endif // QTIMEZONELOCALE_P_H
diff --git a/src/corelib/time/qtimezoneprivate.cpp b/src/corelib/time/qtimezoneprivate.cpp
index 43f1fea935..2ad0d874b6 100644
--- a/src/corelib/time/qtimezoneprivate.cpp
+++ b/src/corelib/time/qtimezoneprivate.cpp
@@ -7,45 +7,110 @@
#include "qtimezoneprivate_p.h"
#include "qtimezoneprivate_data_p.h"
-#include <private/qnumeric_p.h>
-#include <private/qtools_p.h>
#include <qdatastream.h>
#include <qdebug.h>
+#include <qstring.h>
+
+#include <private/qcalendarmath_p.h>
+#include <private/qnumeric_p.h>
+#include <private/qtools_p.h>
#include <algorithm>
QT_BEGIN_NAMESPACE
using namespace QtMiscUtils;
+using namespace QtTimeZoneCldr;
+using namespace Qt::StringLiterals;
-/*
- Static utilities for looking up Windows ID tables
-*/
+// For use with std::is_sorted() in assertions:
+[[maybe_unused]]
+constexpr bool earlierZoneData(const ZoneData &less, const ZoneData &more) noexcept
+{
+ return less.windowsIdKey < more.windowsIdKey
+ || (less.windowsIdKey == more.windowsIdKey && less.territory < more.territory);
+}
+
+[[maybe_unused]]
+static bool earlierWinData(const WindowsData &less, const WindowsData &more) noexcept
+{
+ // Actually only tested in the negative, to check more < less never happens,
+ // so should be true if more < less in either part; hence || not && combines.
+ return less.windowsIdKey < more.windowsIdKey
+ || less.windowsId().compare(more.windowsId(), Qt::CaseInsensitive) < 0;
+}
+
+// For use with std::lower_bound():
+constexpr bool atLowerUtcOffset(const UtcData &entry, qint32 offsetSeconds) noexcept
+{
+ return entry.offsetFromUtc < offsetSeconds;
+}
+
+constexpr bool atLowerWindowsKey(const WindowsData &entry, qint16 winIdKey) noexcept
+{
+ return entry.windowsIdKey < winIdKey;
+}
+
+static bool earlierWindowsId(const WindowsData &entry, QByteArrayView winId) noexcept
+{
+ return entry.windowsId().compare(winId, Qt::CaseInsensitive) < 0;
+}
+constexpr bool zoneAtLowerWindowsKey(const ZoneData &entry, qint16 winIdKey) noexcept
+{
+ return entry.windowsIdKey < winIdKey;
+}
+
+// Static table-lookup helpers
static quint16 toWindowsIdKey(const QByteArray &winId)
{
- for (const QWindowsData &data : windowsDataTable) {
- if (data.windowsId() == winId)
- return data.windowsIdKey;
- }
+ // Key and winId are monotonic, table is sorted on them.
+ const auto data = std::lower_bound(std::begin(windowsDataTable), std::end(windowsDataTable),
+ winId, earlierWindowsId);
+ if (data != std::end(windowsDataTable) && data->windowsId() == winId)
+ return data->windowsIdKey;
return 0;
}
static QByteArray toWindowsIdLiteral(quint16 windowsIdKey)
{
- for (const QWindowsData &data : windowsDataTable) {
- if (data.windowsIdKey == windowsIdKey)
+ // Caller should be passing a valid (in range) key; and table is sorted in
+ // increasing order, with no gaps in numbering, starting with key = 1 at
+ // index [0]. So this should normally work:
+ if (Q_LIKELY(windowsIdKey > 0 && windowsIdKey <= std::size(windowsDataTable))) {
+ const auto &data = windowsDataTable[windowsIdKey - 1];
+ if (Q_LIKELY(data.windowsIdKey == windowsIdKey))
return data.windowsId().toByteArray();
}
+ // Fall back on binary chop - key and winId are monotonic, table is sorted on them:
+ const auto data = std::lower_bound(std::begin(windowsDataTable), std::end(windowsDataTable),
+ windowsIdKey, atLowerWindowsKey);
+ if (data != std::end(windowsDataTable) && data->windowsIdKey == windowsIdKey)
+ return data->windowsId().toByteArray();
+
return QByteArray();
}
+static auto zoneStartForWindowsId(quint16 windowsIdKey) noexcept
+{
+ // Caller must check the resulting iterator isn't std::end(zoneDataTable)
+ // and does match windowsIdKey, since this is just the lower bound.
+ return std::lower_bound(std::begin(zoneDataTable), std::end(zoneDataTable),
+ windowsIdKey, zoneAtLowerWindowsKey);
+}
+
/*
Base class implementing common utility routines, only instantiate for a null tz.
*/
QTimeZonePrivate::QTimeZonePrivate()
{
+ // If std::is_sorted() were constexpr, the first could be a static_assert().
+ // From C++20, we should be able to rework it in terms of std::all_of().
+ Q_ASSERT(std::is_sorted(std::begin(zoneDataTable), std::end(zoneDataTable),
+ earlierZoneData));
+ Q_ASSERT(std::is_sorted(std::begin(windowsDataTable), std::end(windowsDataTable),
+ earlierWinData));
}
QTimeZonePrivate::QTimeZonePrivate(const QTimeZonePrivate &other)
@@ -89,7 +154,7 @@ QLocale::Territory QTimeZonePrivate::territory() const
{
// Default fall-back mode, use the zoneTable to find Region of known Zones
const QLatin1StringView sought(m_id.data(), m_id.size());
- for (const QZoneData &data : zoneDataTable) {
+ for (const ZoneData &data : zoneDataTable) {
for (QLatin1StringView token : data.ids()) {
if (token == sought)
return QLocale::Territory(data.territory);
@@ -128,8 +193,7 @@ QString QTimeZonePrivate::displayName(QTimeZone::TimeType timeType,
QString QTimeZonePrivate::abbreviation(qint64 atMSecsSinceEpoch) const
{
- Q_UNUSED(atMSecsSinceEpoch);
- return QString();
+ return displayName(atMSecsSinceEpoch, QTimeZone::ShortName, QLocale::c());
}
int QTimeZonePrivate::offsetFromUtc(qint64 atMSecsSinceEpoch) const
@@ -166,49 +230,60 @@ bool QTimeZonePrivate::isDaylightTime(qint64 atMSecsSinceEpoch) const
QTimeZonePrivate::Data QTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const
{
Q_UNUSED(forMSecsSinceEpoch);
- return invalidData();
+ return {};
}
// Private only method for use by QDateTime to convert local msecs to epoch msecs
-QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs, int hint) const
-{
-#ifndef Q_OS_ANDROID
- // The Android back-end's hasDaylightTime() is only true for zones with
- // transitions in the future; we need it to mean "has ever had a transition"
- // though, so can't trust it here.
- if (!hasDaylightTime()) // No DST means same offset for all local msecs
- return data(forLocalMSecs - standardTimeOffset(forLocalMSecs) * 1000);
-#endif
+QDateTimePrivate::ZoneState QTimeZonePrivate::stateAtZoneTime(
+ qint64 forLocalMSecs, QDateTimePrivate::TransitionOptions resolve) const
+{
+ auto dataToState = [](const QTimeZonePrivate::Data &d) {
+ return QDateTimePrivate::ZoneState(d.atMSecsSinceEpoch + d.offsetFromUtc * 1000,
+ d.offsetFromUtc,
+ d.daylightTimeOffset ? QDateTimePrivate::DaylightTime
+ : QDateTimePrivate::StandardTime);
+ };
/*
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
+ add that offset to forLocalMSecs, to get the UTC time we need.
+ Fortunately, all time-zone offsets have been less than 17 hours; and DST
+ transitions happen (much) more than thirty-four hours apart. So sampling
+ offset seventeen hours each side gives us information we can be sure
brackets the correct time and at most one DST transition.
*/
- std::integral_constant<qint64, 16 * 3600 * 1000> sixteenHoursInMSecs;
- static_assert(-sixteenHoursInMSecs / 1000 < QTimeZone::MinUtcOffsetSecs
- && sixteenHoursInMSecs / 1000 > QTimeZone::MaxUtcOffsetSecs);
+ std::integral_constant<qint64, 17 * 3600 * 1000> seventeenHoursInMSecs;
+ static_assert(-seventeenHoursInMSecs / 1000 < QTimeZone::MinUtcOffsetSecs
+ && seventeenHoursInMSecs / 1000 > QTimeZone::MaxUtcOffsetSecs);
qint64 millis;
- // Clip the bracketing times to the bounds of the supported range. Exclude
- // minMSecs(), because at least one backend (Windows) uses it for a
- // start-of-time fake transition, that we want previousTransition() to find.
+ // Clip the bracketing times to the bounds of the supported range.
const qint64 recent =
- sub_overflow(forLocalMSecs, sixteenHoursInMSecs, &millis) || millis <= minMSecs()
- ? minMSecs() + 1 : millis; // Necessarily <= forLocalMSecs + 2.
+ qSubOverflow(forLocalMSecs, seventeenHoursInMSecs, &millis) || millis < minMSecs()
+ ? minMSecs() : millis; // Necessarily <= forLocalMSecs + 1.
// (Given that minMSecs() is std::numeric_limits<qint64>::min() + 1.)
const qint64 imminent =
- add_overflow(forLocalMSecs, sixteenHoursInMSecs, &millis)
+ qAddOverflow(forLocalMSecs, seventeenHoursInMSecs, &millis)
? maxMSecs() : millis; // Necessarily >= forLocalMSecs
// At most one of those was clipped to its boundary value:
- Q_ASSERT(recent < imminent && sixteenHoursInMSecs < imminent - recent + 2);
+ Q_ASSERT(recent < imminent && seventeenHoursInMSecs < imminent - recent + 1);
+
+ const Data past = data(recent), future = data(imminent);
+ // > 99% of the time, past and future will agree:
+ if (Q_LIKELY(past.offsetFromUtc == future.offsetFromUtc
+ && past.standardTimeOffset == future.standardTimeOffset
+ // Those two imply same daylightTimeOffset.
+ && past.abbreviation == future.abbreviation)) {
+ Data data = future;
+ data.atMSecsSinceEpoch = forLocalMSecs - future.offsetFromUtc * 1000;
+ return dataToState(data);
+ }
+
/*
Offsets are Local - UTC, positive to the east of Greenwich, negative to
- the west; DST offset always exceeds standard offset, when DST applies.
+ the west; DST offset normally 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.
+ standard, the higher is DST, unless we have data telling us it's the other
+ way round.
Non-DST transitions (jurisdictions changing time-zone and time-zones
changing their standard offset, typically) are described below as if they
@@ -220,60 +295,34 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs,
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.)
- */
-
+ reasoning that applies to DST applies just the same.
+
+ The resolution of transitions, specified by \a resolve, may be lead astray
+ if (as happens on Windows) the backend has been obliged to guess whether a
+ transition is in fact a DST one or a change to standard offset; or to
+ guess that the higher-offset side is the DST one (the reverse of this is
+ true for Ireland, using negative DST). There's not much we can do about
+ that, though.
+ */
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.
+ 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 resolve 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(recent);
+ Data tran = past; // Data after last transition before our window.
Q_ASSERT(forLocalMSecs < 0 || // Pre-epoch TZ info may be unavailable
forLocalMSecs - tran.offsetFromUtc * 1000 >= tran.atMSecsSinceEpoch);
+ // If offset actually exceeds 17 hours, that assert may trigger.
Data nextTran = nextTransition(tran.atMSecsSinceEpoch);
/*
Now walk those forward until they bracket forLocalMSecs with transitions.
@@ -281,7 +330,7 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs,
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.
+ nextTran is (invalid or) that transition.
*/
while (nextTran.atMSecsSinceEpoch != invalidMSecs()
&& forLocalMSecs > nextTran.atMSecsSinceEpoch + nextTran.offsetFromUtc * 1000) {
@@ -305,50 +354,75 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs,
// If we know of no transition after it, the answer is easy:
const qint64 nextStart = nextTran.atMSecsSinceEpoch;
if (nextStart == invalidMSecs())
- return tran;
+ return dataToState(tran); // Last valid transition.
/*
... and nextTran is either after or only slightly before. We're
going to interpret one as standard time, the other as DST
(although the transition might in fact be a change in standard
- offset, or a change in DST offset, e.g. to/from double-DST). 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.
+ offset, or a change in DST offset, e.g. to/from double-DST).
+
+ Usually exactly one of those shall be relevant and we'll use it;
+ but if we're close to nextTran we may be in a transition, to be
+ settled according to resolve's rules.
*/
// Work out the UTC value it would make sense to return if using nextTran:
nextTran.atMSecsSinceEpoch = forLocalMSecs - nextTran.offsetFromUtc * 1000;
- // If both or neither have zero DST, treat the one with lower offset as standard:
- const bool nextIsDst = !nextTran.daylightTimeOffset == !tran.daylightTimeOffset
- ? tran.offsetFromUtc < nextTran.offsetFromUtc : nextTran.daylightTimeOffset;
- // If that agrees with hint > 0, our first guess is to use nextTran; else tran.
- const bool nextFirst = nextIsDst == (hint > 0);
- 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 (nextFirst ? i == 0 : i) {
- if (nextStart <= nextTran.atMSecsSinceEpoch)
- return nextTran;
- } else {
- // If next is invalid, nextFirst is false, to route us here first:
- if (nextStart > tran.atMSecsSinceEpoch)
- return tran;
+ bool fallBack = false;
+ if (nextStart > nextTran.atMSecsSinceEpoch) {
+ // If both UTC values are before nextTran's offset applies, use tran:
+ if (nextStart > tran.atMSecsSinceEpoch)
+ return dataToState(tran);
+
+ Q_ASSERT(tran.offsetFromUtc < nextTran.offsetFromUtc);
+ // We're in a spring-forward.
+ } else if (nextStart <= tran.atMSecsSinceEpoch) {
+ // Both UTC values say we should be using nextTran:
+ return dataToState(nextTran);
+ } else {
+ Q_ASSERT(nextTran.offsetFromUtc < tran.offsetFromUtc);
+ fallBack = true; // We're in a fall-back.
+ }
+ // (forLocalMSecs - nextStart) / 1000 lies between the two offsets.
+
+ // Apply resolve:
+ // Determine whether FlipForReverseDst affects the outcome:
+ const bool flipped
+ = resolve.testFlag(QDateTimePrivate::FlipForReverseDst)
+ && (fallBack ? !tran.daylightTimeOffset && nextTran.daylightTimeOffset
+ : tran.daylightTimeOffset && !nextTran.daylightTimeOffset);
+
+ if (fallBack) {
+ if (resolve.testFlag(flipped
+ ? QDateTimePrivate::FoldUseBefore
+ : QDateTimePrivate::FoldUseAfter)) {
+ return dataToState(nextTran);
+ }
+ if (resolve.testFlag(flipped
+ ? QDateTimePrivate::FoldUseAfter
+ : QDateTimePrivate::FoldUseBefore)) {
+ return dataToState(tran);
}
+ } else {
+ /* Neither is valid (e.g. in a spring-forward's gap) and
+ nextTran.atMSecsSinceEpoch < nextStart <= tran.atMSecsSinceEpoch.
+ So swap their atMSecsSinceEpoch to give each a moment on the
+ side of the transition that it describes, then select the one
+ after or before according to the option set:
+ */
+ std::swap(tran.atMSecsSinceEpoch, nextTran.atMSecsSinceEpoch);
+ if (resolve.testFlag(flipped
+ ? QDateTimePrivate::GapUseBefore
+ : QDateTimePrivate::GapUseAfter))
+ return dataToState(nextTran);
+ if (resolve.testFlag(flipped
+ ? QDateTimePrivate::GapUseAfter
+ : QDateTimePrivate::GapUseBefore))
+ return dataToState(tran);
}
-
- /*
- Neither is valid (e.g. in a spring-forward's gap) and
- nextTran.atMSecsSinceEpoch < nextStart <= tran.atMSecsSinceEpoch;
- swap their atMSecsSinceEpoch to give each a moment on its side of
- the transition; and pick the reverse of what hint asked for:
- */
- std::swap(tran.atMSecsSinceEpoch, nextTran.atMSecsSinceEpoch);
- return nextFirst ? tran : nextTran;
+ // Reject
+ return {forLocalMSecs};
}
// Before first transition, or system has transitions but not for this zone.
// Try falling back to offsetFromUtc (works for before first transition, at least).
@@ -357,41 +431,54 @@ QTimeZonePrivate::Data QTimeZonePrivate::dataForLocalTime(qint64 forLocalMSecs,
/* Bracket and refine to discover offset. */
qint64 utcEpochMSecs;
- int early = offsetFromUtc(recent);
- int late = offsetFromUtc(imminent);
- if (early == late // > 99% of the time
- || late == invalidSeconds()) {
+ // We don't have true data on DST-ness, so can't apply FlipForReverseDst.
+ int early = past.offsetFromUtc;
+ int late = future.offsetFromUtc;
+ if (early == late || late == invalidSeconds()) {
if (early == invalidSeconds()
- || sub_overflow(forLocalMSecs, early * qint64(1000), &utcEpochMSecs)) {
- return invalidData(); // Outside representable range
+ || qSubOverflow(forLocalMSecs, early * qint64(1000), &utcEpochMSecs)) {
+ return {forLocalMSecs}; // Outside representable range
}
} 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 (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;
+ const qint64 forEarly = forLocalMSecs - early * 1000;
+ const qint64 forLate = forLocalMSecs - late * 1000;
+ // If either of those doesn't have the offset we got it from, it's on
+ // the wrong side of the transition (and both may be, for a gap):
+ const bool earlyOk = offsetFromUtc(forEarly) == early;
+ const bool lateOk = offsetFromUtc(forLate) == late;
+
+ if (earlyOk) {
+ if (lateOk) {
+ Q_ASSERT(early > late);
+ // fall-back's repeated interval
+ if (resolve.testFlag(QDateTimePrivate::FoldUseBefore))
+ utcEpochMSecs = forEarly;
+ else if (resolve.testFlag(QDateTimePrivate::FoldUseAfter))
+ utcEpochMSecs = forLate;
+ else
+ return {forLocalMSecs};
+ } else {
+ // Before and clear of the transition:
+ utcEpochMSecs = forEarly;
+ }
+ } else if (lateOk) {
+ // After and clear of the transition:
+ utcEpochMSecs = forLate;
} else {
- // Invalid forLocalMSecs: in spring-forward gap.
- const int dstStep = (offsetInDst - offsetInStd) * 1000;
- // That'll typically be the DST offset at imminent, but changes to
- // standard time have zero DST offset both before and after.
- Q_ASSERT(dstStep > 0); // There can't be a gap without it !
- utcEpochMSecs = (hint > 0) ? forStd - dstStep : forDst + dstStep;
+ // forLate <= gap < forEarly
+ Q_ASSERT(late > early);
+ const int dstStep = (late - early) * 1000;
+ if (resolve.testFlag(QDateTimePrivate::GapUseBefore))
+ utcEpochMSecs = forEarly - dstStep;
+ else if (resolve.testFlag(QDateTimePrivate::GapUseAfter))
+ utcEpochMSecs = forLate + dstStep;
+ else
+ return {forLocalMSecs};
}
}
- return data(utcEpochMSecs);
+ return dataToState(data(utcEpochMSecs));
}
bool QTimeZonePrivate::hasTransitions() const
@@ -402,13 +489,13 @@ bool QTimeZonePrivate::hasTransitions() const
QTimeZonePrivate::Data QTimeZonePrivate::nextTransition(qint64 afterMSecsSinceEpoch) const
{
Q_UNUSED(afterMSecsSinceEpoch);
- return invalidData();
+ return {};
}
QTimeZonePrivate::Data QTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch) const
{
Q_UNUSED(beforeMSecsSinceEpoch);
- return invalidData();
+ return {};
}
QTimeZonePrivate::DataList QTimeZonePrivate::transitions(qint64 fromMSecsSinceEpoch,
@@ -434,7 +521,8 @@ QByteArray QTimeZonePrivate::systemTimeZoneId() const
bool QTimeZonePrivate::isTimeZoneIdAvailable(const QByteArray& ianaId) const
{
- // Fall-back implementation, can be made faster in subclasses
+ // Fall-back implementation, can be made faster in subclasses.
+ // Backends that don't cache the available list SHOULD override this.
const QList<QByteArray> tzIds = availableTimeZoneIds();
return std::binary_search(tzIds.begin(), tzIds.end(), ianaId);
}
@@ -444,29 +532,31 @@ QList<QByteArray> QTimeZonePrivate::availableTimeZoneIds() const
return QList<QByteArray>();
}
+static QList<QByteArray> selectAvailable(QList<QByteArray>&& desired, const QList<QByteArray>& all)
+{
+ std::sort(desired.begin(), desired.end());
+ const auto newEnd = std::unique(desired.begin(), desired.end());
+ const auto newSize = std::distance(desired.begin(), newEnd);
+ QList<QByteArray> result;
+ result.reserve(qMin(all.size(), newSize));
+ std::set_intersection(all.begin(), all.end(), desired.cbegin(),
+ std::next(desired.cbegin(), newSize), std::back_inserter(result));
+ return result;
+}
+
QList<QByteArray> QTimeZonePrivate::availableTimeZoneIds(QLocale::Territory territory) const
{
// Default fall-back mode, use the zoneTable to find Region of know Zones
QList<QByteArray> regions;
// First get all Zones in the Zones table belonging to the Region
- for (const QZoneData &data : zoneDataTable) {
+ for (const ZoneData &data : zoneDataTable) {
if (data.territory == territory) {
for (auto l1 : data.ids())
regions << QByteArray(l1.data(), l1.size());
}
}
-
- std::sort(regions.begin(), regions.end());
- regions.erase(std::unique(regions.begin(), regions.end()), regions.end());
-
- // Then select just those that are available
- const QList<QByteArray> all = availableTimeZoneIds();
- QList<QByteArray> result;
- result.reserve(qMin(all.size(), regions.size()));
- std::set_intersection(all.begin(), all.end(), regions.cbegin(), regions.cend(),
- std::back_inserter(result));
- return result;
+ return selectAvailable(std::move(regions), availableTimeZoneIds());
}
QList<QByteArray> QTimeZonePrivate::availableTimeZoneIds(int offsetFromUtc) const
@@ -474,27 +564,17 @@ QList<QByteArray> QTimeZonePrivate::availableTimeZoneIds(int offsetFromUtc) cons
// Default fall-back mode, use the zoneTable to find Offset of know Zones
QList<QByteArray> offsets;
// First get all Zones in the table using the Offset
- for (const QWindowsData &winData : windowsDataTable) {
+ for (const WindowsData &winData : windowsDataTable) {
if (winData.offsetFromUtc == offsetFromUtc) {
- for (const QZoneData &data : zoneDataTable) {
- if (data.windowsIdKey == winData.windowsIdKey) {
- for (auto l1 : data.ids())
- offsets << QByteArray(l1.data(), l1.size());
- }
+ for (auto data = zoneStartForWindowsId(winData.windowsIdKey);
+ data != std::end(zoneDataTable) && data->windowsIdKey == winData.windowsIdKey;
+ ++data) {
+ for (auto l1 : data->ids())
+ offsets << QByteArray(l1.data(), l1.size());
}
}
}
-
- std::sort(offsets.begin(), offsets.end());
- offsets.erase(std::unique(offsets.begin(), offsets.end()), offsets.end());
-
- // Then select just those that are available
- const QList<QByteArray> all = availableTimeZoneIds();
- QList<QByteArray> result;
- result.reserve(qMin(all.size(), offsets.size()));
- std::set_intersection(all.begin(), all.end(), offsets.cbegin(), offsets.cend(),
- std::back_inserter(result));
- return result;
+ return selectAvailable(std::move(offsets), availableTimeZoneIds());
}
#ifndef QT_NO_DATASTREAM
@@ -506,37 +586,21 @@ void QTimeZonePrivate::serialize(QDataStream &ds) const
// Static Utility Methods
-QTimeZonePrivate::Data QTimeZonePrivate::invalidData()
-{
- Data data;
- data.atMSecsSinceEpoch = invalidMSecs();
- data.offsetFromUtc = invalidSeconds();
- data.standardTimeOffset = invalidSeconds();
- data.daylightTimeOffset = invalidSeconds();
- return data;
-}
-
QTimeZone::OffsetData QTimeZonePrivate::invalidOffsetData()
{
- QTimeZone::OffsetData offsetData;
- offsetData.atUtc = QDateTime();
- offsetData.offsetFromUtc = invalidSeconds();
- offsetData.standardTimeOffset = invalidSeconds();
- offsetData.daylightTimeOffset = invalidSeconds();
- return offsetData;
+ return { QString(), QDateTime(),
+ invalidSeconds(), invalidSeconds(), invalidSeconds() };
}
QTimeZone::OffsetData QTimeZonePrivate::toOffsetData(const QTimeZonePrivate::Data &data)
{
- QTimeZone::OffsetData offsetData = invalidOffsetData();
- if (data.atMSecsSinceEpoch != invalidMSecs()) {
- offsetData.atUtc = QDateTime::fromMSecsSinceEpoch(data.atMSecsSinceEpoch, QTimeZone::UTC);
- offsetData.offsetFromUtc = data.offsetFromUtc;
- offsetData.standardTimeOffset = data.standardTimeOffset;
- offsetData.daylightTimeOffset = data.daylightTimeOffset;
- offsetData.abbreviation = data.abbreviation;
- }
- return offsetData;
+ if (data.atMSecsSinceEpoch == invalidMSecs())
+ return invalidOffsetData();
+
+ return {
+ data.abbreviation,
+ QDateTime::fromMSecsSinceEpoch(data.atMSecsSinceEpoch, QTimeZone::UTC),
+ data.offsetFromUtc, data.standardTimeOffset, data.daylightTimeOffset };
}
// Is the format of the ID valid ?
@@ -639,11 +703,9 @@ QString QTimeZonePrivate::isoOffsetFormat(int offsetFromUtc, QTimeZone::NameType
QByteArray QTimeZonePrivate::ianaIdToWindowsId(const QByteArray &id)
{
- // We don't have a Latin1/UTF-8 mixed comparator (QTBUG-100234),
- // so we have to allocate here...
- const auto idUtf8 = QString::fromUtf8(id);
+ const auto idUtf8 = QUtf8StringView(id);
- for (const QZoneData &data : zoneDataTable) {
+ for (const ZoneData &data : zoneDataTable) {
for (auto l1 : data.ids()) {
if (l1 == idUtf8)
return toWindowsIdLiteral(data.windowsIdKey);
@@ -654,13 +716,13 @@ QByteArray QTimeZonePrivate::ianaIdToWindowsId(const QByteArray &id)
QByteArray QTimeZonePrivate::windowsIdToDefaultIanaId(const QByteArray &windowsId)
{
- for (const QWindowsData &data : windowsDataTable) {
- if (data.windowsId() == windowsId) {
- QByteArrayView id = data.ianaId();
- if (qsizetype cut = id.indexOf(' '); cut >= 0)
- id = id.first(cut);
- return id.toByteArray();
- }
+ const auto data = std::lower_bound(std::begin(windowsDataTable), std::end(windowsDataTable),
+ windowsId, earlierWindowsId);
+ if (data != std::end(windowsDataTable) && data->windowsId() == windowsId) {
+ QByteArrayView id = data->ianaId();
+ if (qsizetype cut = id.indexOf(' '); cut >= 0)
+ id = id.first(cut);
+ return id.toByteArray();
}
return QByteArray();
}
@@ -677,11 +739,11 @@ QList<QByteArray> QTimeZonePrivate::windowsIdToIanaIds(const QByteArray &windows
const quint16 windowsIdKey = toWindowsIdKey(windowsId);
QList<QByteArray> list;
- for (const QZoneData &data : zoneDataTable) {
- if (data.windowsIdKey == windowsIdKey) {
- for (auto l1 : data.ids())
- list << QByteArray(l1.data(), l1.size());
- }
+ for (auto data = zoneStartForWindowsId(windowsIdKey);
+ data != std::end(zoneDataTable) && data->windowsIdKey == windowsIdKey;
+ ++data) {
+ for (auto l1 : data->ids())
+ list << QByteArray(l1.data(), l1.size());
}
// Return the full list in alpha order
@@ -695,10 +757,12 @@ QList<QByteArray> QTimeZonePrivate::windowsIdToIanaIds(const QByteArray &windows
QList<QByteArray> list;
const quint16 windowsIdKey = toWindowsIdKey(windowsId);
const qint16 land = static_cast<quint16>(territory);
- for (const QZoneData &data : zoneDataTable) {
+ for (auto data = zoneStartForWindowsId(windowsIdKey);
+ data != std::end(zoneDataTable) && data->windowsIdKey == windowsIdKey;
+ ++data) {
// Return the region matches in preference order
- if (data.windowsIdKey == windowsIdKey && data.territory == land) {
- for (auto l1 : data.ids())
+ if (data->territory == land) {
+ for (auto l1 : data->ids())
list << QByteArray(l1.data(), l1.size());
break;
}
@@ -719,14 +783,17 @@ static bool isEntryInIanaList(QByteArrayView id, QByteArrayView ianaIds)
while ((cut = ianaIds.indexOf(' ')) >= 0) {
if (id == ianaIds.first(cut))
return true;
- ianaIds = ianaIds.sliced(cut);
+ ianaIds = ianaIds.sliced(cut + 1);
}
return id == ianaIds;
}
/*
- UTC Offset implementation, used when QT_NO_SYSTEMLOCALE set and ICU is not being used,
- or for QDateTimes with a Qt:Spec of Qt::OffsetFromUtc.
+ UTC Offset backend.
+
+ Always present, based on UTC-offset zones.
+ Complements platform-specific backends.
+ Equivalent to Qt::OffsetFromUtc lightweight time representations.
*/
// Create default UTC time zone
@@ -740,7 +807,7 @@ QUtcTimeZonePrivate::QUtcTimeZonePrivate()
QUtcTimeZonePrivate::QUtcTimeZonePrivate(const QByteArray &id)
{
// Look for the name in the UTC list, if found set the values
- for (const QUtcData &data : utcDataTable) {
+ for (const UtcData &data : utcDataTable) {
if (isEntryInIanaList(id, data.id())) {
QString name = QString::fromUtf8(id);
init(id, data.offsetFromUtc, name, name, QLocale::AnyTerritory, name);
@@ -749,7 +816,7 @@ QUtcTimeZonePrivate::QUtcTimeZonePrivate(const QByteArray &id)
}
}
-qint64 QUtcTimeZonePrivate::offsetFromUtcString(const QByteArray &id)
+qint64 QUtcTimeZonePrivate::offsetFromUtcString(QByteArrayView id)
{
// Convert reasonable UTC[+-]\d+(:\d+){,2} to offset in seconds.
// Assumption: id has already been tried as a CLDR UTC offset ID (notably
@@ -761,32 +828,47 @@ qint64 QUtcTimeZonePrivate::offsetFromUtcString(const QByteArray &id)
return invalidSeconds(); // No sign
const int sign = signChar == '-' ? -1 : 1;
- const auto offsets = id.mid(4).split(':');
- if (offsets.isEmpty() || offsets.size() > 3)
- return invalidSeconds(); // No numbers, or too many.
-
qint32 seconds = 0;
int prior = 0; // Number of fields parsed thus far
- for (const auto &offset : offsets) {
+ for (auto offset : QLatin1StringView(id.mid(4)).tokenize(':'_L1)) {
bool ok = false;
unsigned short field = offset.toUShort(&ok);
// Bound hour above at 24, minutes and seconds at 60:
if (!ok || field >= (prior ? 60 : 24))
return invalidSeconds();
seconds = seconds * 60 + field;
- ++prior;
+ if (++prior > 3)
+ return invalidSeconds(); // Too many numbers
}
+
+ if (!prior)
+ return invalidSeconds(); // No numbers
+
while (prior++ < 3)
seconds *= 60;
return seconds * sign;
}
-// Create offset from UTC
+// Create from UTC offset:
QUtcTimeZonePrivate::QUtcTimeZonePrivate(qint32 offsetSeconds)
{
- QString utcId = isoOffsetFormat(offsetSeconds, QTimeZone::ShortName);
- init(utcId.toUtf8(), offsetSeconds, utcId, utcId, QLocale::AnyTerritory, utcId);
+ QString name;
+ QByteArray id;
+ // If there's an IANA ID for this offset, use it:
+ const auto data = std::lower_bound(std::begin(utcDataTable), std::end(utcDataTable),
+ offsetSeconds, atLowerUtcOffset);
+ if (data != std::end(utcDataTable) && data->offsetFromUtc == offsetSeconds) {
+ QByteArrayView ianaId = data->id();
+ qsizetype cut = ianaId.indexOf(' ');
+ id = (cut < 0 ? ianaId : ianaId.first(cut)).toByteArray();
+ name = QString::fromUtf8(id);
+ Q_ASSERT(!name.isEmpty());
+ } else { // Fall back to a UTC-offset name:
+ name = isoOffsetFormat(offsetSeconds, QTimeZone::ShortName);
+ id = name.toUtf8();
+ }
+ init(id, offsetSeconds, name, name, QLocale::AnyTerritory, name);
}
QUtcTimeZonePrivate::QUtcTimeZonePrivate(const QByteArray &zoneId, int offsetSeconds,
@@ -890,11 +972,13 @@ QByteArray QUtcTimeZonePrivate::systemTimeZoneId() const
bool QUtcTimeZonePrivate::isTimeZoneIdAvailable(const QByteArray &ianaId) const
{
// Only the zone IDs supplied by CLDR and recognized by constructor.
- for (const QUtcData &data : utcDataTable) {
+ for (const UtcData &data : utcDataTable) {
if (isEntryInIanaList(ianaId, data.id()))
return true;
}
- // But see offsetFromUtcString(), which lets us accept some "unavailable" IDs.
+ // Callers may want to || offsetFromUtcString(ianaId) != invalidSeconds(),
+ // but those are technically not IANA IDs and the custom QTimeZone
+ // constructor needs the return here to reflect that.
return false;
}
@@ -903,12 +987,12 @@ QList<QByteArray> QUtcTimeZonePrivate::availableTimeZoneIds() const
// Only the zone IDs supplied by CLDR and recognized by constructor.
QList<QByteArray> result;
result.reserve(std::size(utcDataTable));
- for (const QUtcData &data : utcDataTable) {
+ for (const UtcData &data : utcDataTable) {
QByteArrayView id = data.id();
qsizetype cut;
while ((cut = id.indexOf(' ')) >= 0) {
result << id.first(cut).toByteArray();
- id = id.sliced(cut);
+ id = id.sliced(cut + 1);
}
result << id.toByteArray();
}
@@ -931,17 +1015,23 @@ QList<QByteArray> QUtcTimeZonePrivate::availableTimeZoneIds(qint32 offsetSeconds
// Only if it's present in CLDR. (May get more than one ID: UTC, UTC+00:00
// and UTC-00:00 all have the same offset.)
QList<QByteArray> result;
- for (const QUtcData &data : utcDataTable) {
- if (data.offsetFromUtc == offsetSeconds) {
- QByteArrayView id = data.id();
- qsizetype cut;
- while ((cut = id.indexOf(' ')) >= 0) {
- result << id.first(cut).toByteArray();
- id = id.sliced(cut);
- }
- result << id.toByteArray();
+ const auto data = std::lower_bound(std::begin(utcDataTable), std::end(utcDataTable),
+ offsetSeconds, atLowerUtcOffset);
+ if (data != std::end(utcDataTable) && data->offsetFromUtc == offsetSeconds) {
+ QByteArrayView id = data->id();
+ qsizetype cut;
+ while ((cut = id.indexOf(' ')) >= 0) {
+ result << id.first(cut).toByteArray();
+ id = id.sliced(cut + 1);
}
+ result << id.toByteArray();
}
+ // CLDR only has round multiples of a quarter hour, and only some of
+ // those. For anything else, throw in the ID we would use for this offset
+ // (if we'd accept that ID).
+ QByteArray isoName = isoOffsetFormat(offsetSeconds, QTimeZone::ShortName).toUtf8();
+ if (offsetFromUtcString(isoName) == qint64(offsetSeconds) && !result.contains(isoName))
+ result << isoName;
// Not guaranteed to be sorted, so sort:
std::sort(result.begin(), result.end());
// ### assuming no duplicates
diff --git a/src/corelib/time/qtimezoneprivate_android.cpp b/src/corelib/time/qtimezoneprivate_android.cpp
index c4ca0e4214..47fc68b1ac 100644
--- a/src/corelib/time/qtimezoneprivate_android.cpp
+++ b/src/corelib/time/qtimezoneprivate_android.cpp
@@ -7,6 +7,7 @@
#include <QtCore/QJniEnvironment>
#include <QtCore/QSet>
+#include <QtCore/qjnitypes.h>
QT_BEGIN_NAMESPACE
@@ -31,7 +32,7 @@ QAndroidTimeZonePrivate::QAndroidTimeZonePrivate()
{
// Keep in sync with systemTimeZoneId():
androidTimeZone = QJniObject::callStaticMethod<QtJniTypes::TimeZone>(
- QtJniTypes::className<QtJniTypes::TimeZone>(), "getDefault");
+ QtJniTypes::Traits<QtJniTypes::TimeZone>::className(), "getDefault");
const QJniObject id = androidTimeZone.callMethod<jstring>("getID");
m_id = id.toString().toUtf8();
}
@@ -59,7 +60,7 @@ static QString getDisplayName(QJniObject zone, jint style, jboolean dst,
{
QJniObject jbcpTag = QJniObject::fromString(locale.bcp47Name());
QJniObject jlocale = QJniObject::callStaticMethod<QtJniTypes::Locale>(
- QtJniTypes::className<QtJniTypes::Locale>(), "forLanguageTag",
+ QtJniTypes::Traits<QtJniTypes::Locale>::className(), "forLanguageTag",
jbcpTag.object<jstring>());
return zone.callMethod<jstring>("getDisplayName", dst, style,
@@ -70,7 +71,7 @@ void QAndroidTimeZonePrivate::init(const QByteArray &ianaId)
{
const QString iana = QString::fromUtf8(ianaId);
androidTimeZone = QJniObject::callStaticMethod<QtJniTypes::TimeZone>(
- QtJniTypes::className<QtJniTypes::TimeZone>(), "getTimeZone",
+ QtJniTypes::Traits<QtJniTypes::TimeZone>::className(), "getTimeZone",
QJniObject::fromString(iana).object<jstring>());
// The ID or display name of the zone we've got, if it looks like what we asked for:
@@ -181,16 +182,11 @@ bool QAndroidTimeZonePrivate::isDaylightTime(qint64 atMSecsSinceEpoch) const
QTimeZonePrivate::Data QAndroidTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const
{
if (androidTimeZone.isValid()) {
- Data data;
- data.atMSecsSinceEpoch = forMSecsSinceEpoch;
- data.standardTimeOffset = standardTimeOffset(forMSecsSinceEpoch);
- data.offsetFromUtc = offsetFromUtc(forMSecsSinceEpoch);
- data.daylightTimeOffset = data.offsetFromUtc - data.standardTimeOffset;
- data.abbreviation = abbreviation(forMSecsSinceEpoch);
- return data;
- } else {
- return invalidData();
+ return Data(abbreviation(forMSecsSinceEpoch), forMSecsSinceEpoch,
+ offsetFromUtc(forMSecsSinceEpoch),
+ standardTimeOffset(forMSecsSinceEpoch));
}
+ return {};
}
// java.util.TimeZone does not directly provide transitions,
@@ -200,16 +196,22 @@ QByteArray QAndroidTimeZonePrivate::systemTimeZoneId() const
{
// Keep in sync with default constructor:
QJniObject androidSystemTimeZone = QJniObject::callStaticMethod<QtJniTypes::TimeZone>(
- QtJniTypes::className<QtJniTypes::TimeZone>(), "getDefault");
+ QtJniTypes::Traits<QtJniTypes::TimeZone>::className(), "getDefault");
const QJniObject id = androidSystemTimeZone.callMethod<jstring>("getID");
return id.toString().toUtf8();
}
+bool QAndroidTimeZonePrivate::isTimeZoneIdAvailable(const QByteArray &ianaId) const
+{
+ QAndroidTimeZonePrivate probe(ianaId);
+ return probe.isValid();
+}
+
QList<QByteArray> QAndroidTimeZonePrivate::availableTimeZoneIds() const
{
QList<QByteArray> availableTimeZoneIdList;
QJniObject androidAvailableIdList = QJniObject::callStaticMethod<QtJniTypes::StringArray>(
- QtJniTypes::className<QtJniTypes::TimeZone>(), "getAvailableIDs");
+ QtJniTypes::Traits<QtJniTypes::TimeZone>::className(), "getAvailableIDs");
QJniEnvironment jniEnv;
int androidTZcount = jniEnv->GetArrayLength(androidAvailableIdList.object<jarray>());
diff --git a/src/corelib/time/qtimezoneprivate_data_p.h b/src/corelib/time/qtimezoneprivate_data_p.h
index 2bfa3c884b..5174f06a0d 100644
--- a/src/corelib/time/qtimezoneprivate_data_p.h
+++ b/src/corelib/time/qtimezoneprivate_data_p.h
@@ -1,7 +1,6 @@
// Copyright (C) 2021 The Qt Company Ltd.
// Copyright (C) 2013 John Layt <jlayt@kde.org>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
+// SPDX-License-Identifier: Unicode-3.0
#ifndef QTIMEZONEPRIVATE_DATA_P_H
#define QTIMEZONEPRIVATE_DATA_P_H
@@ -21,76 +20,65 @@
#include "qbytearrayview.h"
#include "qstring.h"
+QT_REQUIRE_CONFIG(timezone);
QT_BEGIN_NAMESPACE
+namespace QtTimeZoneCldr {
/*
- Windows Zone ID support, included in default base class build so can be used on all platforms,
- e.g. an app running on Linux may need to communicate with a Windows Outlook server. These
- tables can also be used to look-up Region Codes and UTC Offsets on platforms that don't directly
- support them., e.g. Mac does not support availableTimeZones() filtering by region or offset.
+ Recognized UTC-offset zones and CLDR-derived data on Windows IDs.
+
+ The UTC-offset zone table is provided for generic UTC±HH:mm format time
+ zones. The UTC backend can support arbitrary offsets in seconds, but only
+ advertises a limited repertoire of offsets as "available" in the normal
+ sense.
- Another data table is provided for generic UTC+00:00 format time zones to be used as a
- fall-back if no system time zones are available (QT_NO_SYSTEMLOCALE is set) or for QDateTimes
- with a QT:Spec of OffsetFromUTC
+ Windows Zone ID support is included in the default base class, QTZP, so can
+ be used on all platforms, since an app running on Linux may need to
+ communicate with a Windows Outlook server. These tables can also be used to
+ look up Region Codes and UTC Offsets on platforms whose backends don't
+ directly support them. For example, Darwin does not support
+ availableTimeZones() filtering by region or offset. This table is
+ auto-generated from the CLDR supplemental/windowsZones.xml data file.
- These tables are automatically adapted from the CLDR supplemental/windowsZones.xml data file
- using a script in qtbase/util/locale_database. Please do not edit this data directly. In the
- future if ICU is made a hard dependency then the ICU resource can be used directly and this
- table removed
+ Please do not edit this data directly. See the generated section for details
+ of its last update and how to update it.
*/
-struct QZoneData
+struct ZoneData
{
- quint16 windowsIdKey; // Windows ID Key
- quint16 territory; // Territory of IANA ID's, AnyTerritory means No Territory
- quint16 ianaIdIndex; // All IANA ID's for the Windows ID and Country, space separated
- inline QLatin1StringView id() const; // Space-joined list of IANA IDs
- inline auto ids() const { return id().tokenize(u' '); }
+ // Keys (table is sorted in Windows ID, then on territory enum value):
+ quint16 windowsIdKey; // Windows ID sequence number
+ quint16 territory; // QLocale::Territory, AnyTerritory means No Territory
+ // Values for this Windows zone and territory:
+ quint16 ianaIdIndex; // Index in ianaIdData of space-joined IANA IDs
+ constexpr QLatin1StringView id() const; // Space-joined list of IANA IDs
+ constexpr auto ids() const { return id().tokenize(u' '); } // Iterate IANA IDs
};
-struct QWindowsData
+struct WindowsData
{
- quint16 windowsIdKey; // Windows ID Key
- quint16 windowsIdIndex; // Windows ID Literal
- quint16 ianaIdIndex; // IANA IDs for the Windows ID
+ // Table is sorted on key and this puts the windowsId()s in ascending order.
+ quint16 windowsIdKey; // Windows ID sequence number
+ quint16 windowsIdIndex; // Index of Windows ID in windowsIdData
+ // Values for this Windows zone:
+ quint16 ianaIdIndex; // Index in ianaIdData of space-joined IANA IDs
qint32 offsetFromUtc; // Standard Time Offset from UTC, used for quick look-ups
- inline QByteArrayView windowsId() const;
- inline QByteArrayView ianaId() const; // Space-joined list of IANA IDs
+ constexpr QByteArrayView windowsId() const;
+ constexpr QByteArrayView ianaId() const; // Space-joined list of IANA IDs
};
-struct QUtcData
+struct UtcData
{
- quint16 ianaIdIndex; // IANA IDs
- qint32 offsetFromUtc; // Offset form UTC is seconds
- inline QByteArrayView id() const; // Space-joined list of IANA IDs
+ quint16 ianaIdIndex; // Index in ianaIdData of space-joined IANA IDs
+ qint32 offsetFromUtc; // Offset form UTC in seconds
+ constexpr QByteArrayView id() const; // Space-joined list of IANA IDs
};
-/*
- COPYRIGHT AND PERMISSION NOTICE
-
- Copyright © 1991-2012 Unicode, Inc. All rights reserved. Distributed under
- the Terms of Use in http://www.unicode.org/copyright.html.
-
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of the Unicode data files and any associated documentation (the "Data
- Files") or Unicode software and any associated documentation (the "Software")
- to deal in the Data Files or Software without restriction, including without
- limitation the rights to use, copy, modify, merge, publish, distribute, and/or
- sell copies of the Data Files or Software, and to permit persons to whom the
- Data Files or Software are furnished to do so, provided that (a) the above
- copyright notice(s) and this permission notice appear with all copies of the
- Data Files or Software, (b) both the above copyright notice(s) and this
- permission notice appear in associated documentation, and (c) there is clear
- notice in each modified Data File or in the Software as well as in the
- documentation associated with the Data File(s) or Software that the data or
- software has been modified.
-*/
-
// GENERATED PART STARTS HERE
/*
- This part of the file was generated on 2022-04-07 from the
- Common Locale Data Repository v41 file supplemental/windowsZones.xml
+ This part of the file was generated on 2024-01-29 from the
+ Common Locale Data Repository v43 file supplemental/windowsZones.xml
http://www.unicode.org/cldr/
@@ -99,7 +87,7 @@ struct QUtcData
*/
// Windows ID Key, Territory Enum, IANA ID Index
-static constexpr QZoneData zoneDataTable[] = {
+static constexpr ZoneData zoneDataTable[] = {
{ 1, 1, 0 }, // Afghanistan Standard Time / Afghanistan
{ 2, 248, 11 }, // Alaskan Standard Time / United States
{ 3, 248, 106 }, // Aleutian Standard Time / United States
@@ -156,7 +144,7 @@ static constexpr QZoneData zoneDataTable[] = {
{ 27, 207, 1278 }, // Central Europe Standard Time / Serbia
{ 27, 212, 1294 }, // Central Europe Standard Time / Slovakia
{ 27, 213, 1312 }, // Central Europe Standard Time / Slovenia
- { 28, 29, 1329 }, // Central European Standard Time / Bosnia And Herzegovina
+ { 28, 29, 1329 }, // Central European Standard Time / Bosnia and Herzegovina
{ 28, 60, 1345 }, // Central European Standard Time / Croatia
{ 28, 140, 1359 }, // Central European Standard Time / Macedonia
{ 28, 187, 1373 }, // Central European Standard Time / Poland
@@ -166,455 +154,454 @@ static constexpr QZoneData zoneDataTable[] = {
{ 29, 166, 1445 }, // Central Pacific Standard Time / New Caledonia
{ 29, 214, 1460 }, // Central Pacific Standard Time / Solomon Islands
{ 29, 252, 1480 }, // Central Pacific Standard Time / Vanuatu
- { 30, 152, 1494 }, // Central Standard Time (Mexico) / Mexico
- { 31, 0, 1570 }, // Central Standard Time / AnyTerritory
- { 31, 41, 1578 }, // Central Standard Time / Canada
- { 31, 152, 1653 }, // Central Standard Time / Mexico
- { 31, 248, 1671 }, // Central Standard Time / United States
- { 32, 50, 1839 }, // China Standard Time / China
- { 32, 107, 1853 }, // China Standard Time / Hong Kong
- { 32, 139, 1868 }, // China Standard Time / Macao
- { 33, 167, 1879 }, // Chatham Islands Standard Time / New Zealand
- { 34, 61, 1895 }, // Cuba Standard Time / Cuba
- { 35, 0, 1910 }, // Dateline Standard Time / AnyTerritory
- { 36, 0, 1921 }, // E. Africa Standard Time / AnyTerritory
- { 36, 9, 1931 }, // E. Africa Standard Time / Antarctica
- { 36, 55, 1948 }, // E. Africa Standard Time / Comoros
- { 36, 67, 1962 }, // E. Africa Standard Time / Djibouti
- { 36, 74, 1978 }, // E. Africa Standard Time / Eritrea
- { 36, 77, 1992 }, // E. Africa Standard Time / Ethiopia
- { 36, 124, 2011 }, // E. Africa Standard Time / Kenya
- { 36, 141, 2026 }, // E. Africa Standard Time / Madagascar
- { 36, 151, 2046 }, // E. Africa Standard Time / Mayotte
- { 36, 215, 2061 }, // E. Africa Standard Time / Somalia
- { 36, 230, 2078 }, // E. Africa Standard Time / Tanzania
- { 36, 243, 2099 }, // E. Africa Standard Time / Uganda
- { 37, 15, 2114 }, // E. Australia Standard Time / Australia
- { 38, 154, 2152 }, // E. Europe Standard Time / Moldova
- { 39, 32, 2168 }, // E. South America Standard Time / Brazil
- { 40, 49, 2186 }, // Easter Island Standard Time / Chile
- { 41, 0, 2201 }, // Eastern Standard Time / AnyTerritory
- { 41, 18, 2209 }, // Eastern Standard Time / Bahamas
- { 41, 41, 2224 }, // Eastern Standard Time / Canada
- { 41, 248, 2329 }, // Eastern Standard Time / United States
- { 42, 152, 2486 }, // Eastern Standard Time (Mexico) / Mexico
- { 43, 71, 2501 }, // Egypt Standard Time / Egypt
- { 44, 193, 2514 }, // Ekaterinburg Standard Time / Russia
- { 45, 82, 2533 }, // Fiji Standard Time / Fiji
- { 46, 2, 2546 }, // FLE Standard Time / Aland Islands
- { 46, 36, 2563 }, // FLE Standard Time / Bulgaria
- { 46, 75, 2576 }, // FLE Standard Time / Estonia
- { 46, 83, 2591 }, // FLE Standard Time / Finland
- { 46, 131, 2607 }, // FLE Standard Time / Latvia
- { 46, 137, 2619 }, // FLE Standard Time / Lithuania
- { 46, 244, 2634 }, // FLE Standard Time / Ukraine
- { 47, 90, 2680 }, // Georgian Standard Time / Georgia
- { 48, 81, 2693 }, // GMT Standard Time / Faroe Islands
- { 48, 100, 2709 }, // GMT Standard Time / Guernsey
- { 48, 114, 2725 }, // GMT Standard Time / Ireland
- { 48, 115, 2739 }, // GMT Standard Time / Isle Of Man
- { 48, 121, 2758 }, // GMT Standard Time / Jersey
- { 48, 188, 2772 }, // GMT Standard Time / Portugal
- { 48, 220, 2803 }, // GMT Standard Time / Spain
- { 48, 246, 2819 }, // GMT Standard Time / United Kingdom
- { 49, 95, 2833 }, // Greenland Standard Time / Greenland
- { 50, 37, 2849 }, // Greenwich Standard Time / Burkina Faso
- { 50, 89, 2868 }, // Greenwich Standard Time / Gambia
- { 50, 92, 2882 }, // Greenwich Standard Time / Ghana
- { 50, 95, 2895 }, // Greenwich Standard Time / Greenland
- { 50, 101, 2916 }, // Greenwich Standard Time / Guinea Bissau
- { 50, 102, 2930 }, // Greenwich Standard Time / Guinea
- { 50, 109, 2945 }, // Greenwich Standard Time / Iceland
- { 50, 118, 2964 }, // Greenwich Standard Time / Ivory Coast
- { 50, 134, 2979 }, // Greenwich Standard Time / Liberia
- { 50, 145, 2995 }, // Greenwich Standard Time / Mali
- { 50, 149, 3009 }, // Greenwich Standard Time / Mauritania
- { 50, 196, 3027 }, // Greenwich Standard Time / Saint Helena
- { 50, 206, 3046 }, // Greenwich Standard Time / Senegal
- { 50, 209, 3059 }, // Greenwich Standard Time / Sierra Leone
- { 50, 233, 3075 }, // Greenwich Standard Time / Togo
- { 51, 63, 3087 }, // GTB Standard Time / Cyprus
- { 51, 94, 3115 }, // GTB Standard Time / Greece
- { 51, 192, 3129 }, // GTB Standard Time / Romania
- { 52, 104, 3146 }, // Haiti Standard Time / Haiti
- { 53, 0, 3169 }, // Hawaiian Standard Time / AnyTerritory
- { 53, 58, 3180 }, // Hawaiian Standard Time / Cook Islands
- { 53, 86, 3198 }, // Hawaiian Standard Time / French Polynesia
- { 53, 247, 3213 }, // Hawaiian Standard Time / United States Outlying Islands
- { 53, 248, 3230 }, // Hawaiian Standard Time / United States
- { 54, 110, 3247 }, // India Standard Time / India
- { 55, 112, 3261 }, // Iran Standard Time / Iran
- { 56, 116, 3273 }, // Israel Standard Time / Israel
- { 57, 122, 3288 }, // Jordan Standard Time / Jordan
- { 58, 193, 3299 }, // Kaliningrad Standard Time / Russia
- { 59, 218, 3318 }, // Korea Standard Time / South Korea
- { 60, 135, 3329 }, // Libya Standard Time / Libya
- { 61, 0, 3344 }, // Line Islands Standard Time / AnyTerritory
- { 61, 125, 3355 }, // Line Islands Standard Time / Kiribati
- { 62, 15, 3374 }, // Lord Howe Standard Time / Australia
- { 63, 193, 3394 }, // Magadan Standard Time / Russia
- { 64, 49, 3407 }, // Magallanes Standard Time / Chile
- { 65, 86, 3428 }, // Marquesas Standard Time / French Polynesia
- { 66, 150, 3446 }, // Mauritius Standard Time / Mauritius
- { 66, 191, 3463 }, // Mauritius Standard Time / Reunion
- { 66, 208, 3478 }, // Mauritius Standard Time / Seychelles
- { 67, 132, 3490 }, // Middle East Standard Time / Lebanon
- { 68, 250, 3502 }, // Montevideo Standard Time / Uruguay
- { 69, 159, 3521 }, // Morocco Standard Time / Morocco
- { 69, 257, 3539 }, // Morocco Standard Time / Western Sahara
- { 70, 152, 3555 }, // Mountain Standard Time (Mexico) / Mexico
- { 71, 0, 3590 }, // Mountain Standard Time / AnyTerritory
- { 71, 41, 3598 }, // Mountain Standard Time / Canada
- { 71, 152, 3672 }, // Mountain Standard Time / Mexico
- { 71, 248, 3688 }, // Mountain Standard Time / United States
- { 72, 53, 3717 }, // Myanmar Standard Time / Cocos Islands
- { 72, 161, 3730 }, // Myanmar Standard Time / Myanmar
- { 73, 193, 3743 }, // N. Central Asia Standard Time / Russia
- { 74, 162, 3760 }, // Namibia Standard Time / Namibia
- { 75, 164, 3776 }, // Nepal Standard Time / Nepal
- { 76, 9, 3790 }, // New Zealand Standard Time / Antarctica
- { 76, 167, 3809 }, // New Zealand Standard Time / New Zealand
- { 77, 41, 3826 }, // Newfoundland Standard Time / Canada
- { 78, 172, 3843 }, // Norfolk Standard Time / Norfolk Island
- { 79, 193, 3859 }, // North Asia East Standard Time / Russia
- { 80, 193, 3872 }, // North Asia Standard Time / Russia
- { 81, 174, 3907 }, // North Korea Standard Time / North Korea
- { 82, 193, 3922 }, // Omsk Standard Time / Russia
- { 83, 49, 3932 }, // Pacific SA Standard Time / Chile
- { 84, 0, 3949 }, // Pacific Standard Time / AnyTerritory
- { 84, 41, 3957 }, // Pacific Standard Time / Canada
- { 84, 248, 3975 }, // Pacific Standard Time / United States
- { 85, 152, 3995 }, // Pacific Standard Time (Mexico) / Mexico
- { 86, 178, 4032 }, // Pakistan Standard Time / Pakistan
- { 87, 183, 4045 }, // Paraguay Standard Time / Paraguay
- { 88, 123, 4062 }, // Qyzylorda Standard Time / Kazakhstan
- { 89, 23, 4077 }, // Romance Standard Time / Belgium
- { 89, 65, 4093 }, // Romance Standard Time / Denmark
- { 89, 84, 4111 }, // Romance Standard Time / France
- { 89, 220, 4124 }, // Romance Standard Time / Spain
- { 90, 193, 4151 }, // Russia Time Zone 3 / Russia
- { 91, 193, 4165 }, // Russia Time Zone 10 / Russia
- { 92, 193, 4184 }, // Russia Time Zone 11 / Russia
- { 93, 193, 4211 }, // Russian Standard Time / Russia
- { 93, 244, 4238 }, // Russian Standard Time / Ukraine
- { 94, 0, 4256 }, // SA Eastern Standard Time / AnyTerritory
- { 94, 9, 4266 }, // SA Eastern Standard Time / Antarctica
- { 94, 32, 4303 }, // SA Eastern Standard Time / Brazil
- { 94, 80, 4382 }, // SA Eastern Standard Time / Falkland Islands
- { 94, 85, 4399 }, // SA Eastern Standard Time / French Guiana
- { 94, 223, 4415 }, // SA Eastern Standard Time / Suriname
- { 95, 0, 4434 }, // SA Pacific Standard Time / AnyTerritory
- { 95, 32, 4444 }, // SA Pacific Standard Time / Brazil
- { 95, 41, 4480 }, // SA Pacific Standard Time / Canada
- { 95, 45, 4502 }, // SA Pacific Standard Time / Cayman Islands
- { 95, 54, 4517 }, // SA Pacific Standard Time / Colombia
- { 95, 70, 4532 }, // SA Pacific Standard Time / Ecuador
- { 95, 119, 4550 }, // SA Pacific Standard Time / Jamaica
- { 95, 181, 4566 }, // SA Pacific Standard Time / Panama
- { 95, 184, 4581 }, // SA Pacific Standard Time / Peru
- { 96, 0, 4594 }, // SA Western Standard Time / AnyTerritory
- { 96, 8, 4604 }, // SA Western Standard Time / Anguilla
- { 96, 10, 4621 }, // SA Western Standard Time / Antigua And Barbuda
- { 96, 13, 4637 }, // SA Western Standard Time / Aruba
- { 96, 21, 4651 }, // SA Western Standard Time / Barbados
- { 96, 28, 4668 }, // SA Western Standard Time / Bolivia
- { 96, 32, 4683 }, // SA Western Standard Time / Brazil
- { 96, 34, 4736 }, // SA Western Standard Time / British Virgin Islands
- { 96, 41, 4752 }, // SA Western Standard Time / Canada
- { 96, 44, 4773 }, // SA Western Standard Time / Caribbean Netherlands
- { 96, 62, 4792 }, // SA Western Standard Time / Curacao
- { 96, 68, 4808 }, // SA Western Standard Time / Dominica
- { 96, 69, 4825 }, // SA Western Standard Time / Dominican Republic
- { 96, 96, 4847 }, // SA Western Standard Time / Grenada
- { 96, 97, 4863 }, // SA Western Standard Time / Guadeloupe
- { 96, 103, 4882 }, // SA Western Standard Time / Guyana
- { 96, 148, 4897 }, // SA Western Standard Time / Martinique
- { 96, 158, 4916 }, // SA Western Standard Time / Montserrat
- { 96, 189, 4935 }, // SA Western Standard Time / Puerto Rico
- { 96, 195, 4955 }, // SA Western Standard Time / Saint Barthelemy
- { 96, 197, 4977 }, // SA Western Standard Time / Saint Kitts And Nevis
- { 96, 198, 4994 }, // SA Western Standard Time / Saint Lucia
- { 96, 199, 5011 }, // SA Western Standard Time / Saint Martin
- { 96, 201, 5027 }, // SA Western Standard Time / Saint Vincent And Grenadines
- { 96, 211, 5046 }, // SA Western Standard Time / Sint Maarten
- { 96, 236, 5068 }, // SA Western Standard Time / Trinidad And Tobago
- { 96, 249, 5090 }, // SA Western Standard Time / United States Virgin Islands
- { 97, 200, 5108 }, // Saint Pierre Standard Time / Saint Pierre And Miquelon
- { 98, 193, 5125 }, // Sakhalin Standard Time / Russia
- { 99, 202, 5139 }, // Samoa Standard Time / Samoa
- { 100, 204, 5152 }, // Sao Tome Standard Time / Sao Tome And Principe
- { 101, 193, 5168 }, // Saratov Standard Time / Russia
- { 102, 0, 5183 }, // SE Asia Standard Time / AnyTerritory
- { 102, 9, 5193 }, // SE Asia Standard Time / Antarctica
- { 102, 39, 5210 }, // SE Asia Standard Time / Cambodia
- { 102, 51, 5226 }, // SE Asia Standard Time / Christmas Island
- { 102, 111, 5243 }, // SE Asia Standard Time / Indonesia
- { 102, 129, 5271 }, // SE Asia Standard Time / Laos
- { 102, 231, 5286 }, // SE Asia Standard Time / Thailand
- { 102, 255, 5299 }, // SE Asia Standard Time / Vietnam
- { 103, 0, 5311 }, // Singapore Standard Time / AnyTerritory
- { 103, 35, 5321 }, // Singapore Standard Time / Brunei
- { 103, 111, 5333 }, // Singapore Standard Time / Indonesia
- { 103, 143, 5347 }, // Singapore Standard Time / Malaysia
- { 103, 185, 5378 }, // Singapore Standard Time / Philippines
- { 103, 210, 5390 }, // Singapore Standard Time / Singapore
- { 104, 0, 5405 }, // South Africa Standard Time / AnyTerritory
- { 104, 30, 5415 }, // South Africa Standard Time / Botswana
- { 104, 38, 5431 }, // South Africa Standard Time / Burundi
- { 104, 57, 5448 }, // South Africa Standard Time / Congo Kinshasa
- { 104, 76, 5466 }, // South Africa Standard Time / Eswatini
- { 104, 133, 5481 }, // South Africa Standard Time / Lesotho
- { 104, 142, 5495 }, // South Africa Standard Time / Malawi
- { 104, 160, 5511 }, // South Africa Standard Time / Mozambique
- { 104, 194, 5525 }, // South Africa Standard Time / Rwanda
- { 104, 216, 5539 }, // South Africa Standard Time / South Africa
- { 104, 260, 5559 }, // South Africa Standard Time / Zambia
- { 104, 261, 5573 }, // South Africa Standard Time / Zimbabwe
- { 105, 219, 5587 }, // South Sudan Standard Time / South Sudan
- { 106, 221, 5599 }, // Sri Lanka Standard Time / Sri Lanka
- { 107, 222, 5612 }, // Sudan Standard Time / Sudan
- { 108, 227, 5628 }, // Syria Standard Time / Syria
- { 109, 228, 5642 }, // Taipei Standard Time / Taiwan
- { 110, 15, 5654 }, // Tasmania Standard Time / Australia
- { 111, 32, 5709 }, // Tocantins Standard Time / Brazil
- { 112, 0, 5727 }, // Tokyo Standard Time / AnyTerritory
- { 112, 111, 5737 }, // Tokyo Standard Time / Indonesia
- { 112, 120, 5751 }, // Tokyo Standard Time / Japan
- { 112, 179, 5762 }, // Tokyo Standard Time / Palau
- { 112, 232, 5776 }, // Tokyo Standard Time / Timor-Leste
- { 113, 193, 5786 }, // Tomsk Standard Time / Russia
- { 114, 235, 5797 }, // Tonga Standard Time / Tonga
- { 115, 193, 5815 }, // Transbaikal Standard Time / Russia
- { 116, 239, 5826 }, // Turkey Standard Time / Turkey
- { 117, 241, 5842 }, // Turks And Caicos Standard Time / Turks And Caicos Islands
- { 118, 156, 5861 }, // Ulaanbaatar Standard Time / Mongolia
- { 119, 248, 5894 }, // US Eastern Standard Time / United States
- { 120, 0, 5961 }, // US Mountain Standard Time / AnyTerritory
- { 120, 41, 5971 }, // US Mountain Standard Time / Canada
- { 120, 152, 6028 }, // US Mountain Standard Time / Mexico
- { 120, 248, 6047 }, // US Mountain Standard Time / United States
- { 121, 0, 6063 }, // UTC-11 / AnyTerritory
- { 121, 5, 6074 }, // UTC-11 / American Samoa
- { 121, 171, 6092 }, // UTC-11 / Niue
- { 121, 247, 6105 }, // UTC-11 / United States Outlying Islands
- { 122, 0, 6120 }, // UTC-09 / AnyTerritory
- { 122, 86, 6130 }, // UTC-09 / French Polynesia
- { 123, 0, 6146 }, // UTC-08 / AnyTerritory
- { 123, 186, 6156 }, // UTC-08 / Pitcairn
- { 124, 0, 6173 }, // UTC-02 / AnyTerritory
- { 124, 32, 6183 }, // UTC-02 / Brazil
- { 124, 217, 6199 }, // UTC-02 / South Georgia And South Sandwich Islands
- { 125, 0, 6222 }, // UTC / AnyTerritory
- { 126, 0, 6238 }, // UTC+12 / AnyTerritory
- { 126, 125, 6249 }, // UTC+12 / Kiribati
- { 126, 147, 6264 }, // UTC+12 / Marshall Islands
- { 126, 163, 6297 }, // UTC+12 / Nauru
- { 126, 242, 6311 }, // UTC+12 / Tuvalu
- { 126, 247, 6328 }, // UTC+12 / United States Outlying Islands
- { 126, 256, 6341 }, // UTC+12 / Wallis And Futuna
- { 127, 0, 6356 }, // UTC+13 / AnyTerritory
- { 127, 125, 6367 }, // UTC+13 / Kiribati
- { 127, 234, 6385 }, // UTC+13 / Tokelau
- { 128, 254, 6401 }, // Venezuela Standard Time / Venezuela
- { 129, 193, 6417 }, // Vladivostok Standard Time / Russia
- { 130, 193, 6448 }, // Volgograd Standard Time / Russia
- { 131, 15, 6465 }, // W. Australia Standard Time / Australia
- { 132, 0, 6481 }, // W. Central Africa Standard Time / AnyTerritory
- { 132, 4, 6491 }, // W. Central Africa Standard Time / Algeria
- { 132, 7, 6506 }, // W. Central Africa Standard Time / Angola
- { 132, 25, 6520 }, // W. Central Africa Standard Time / Benin
- { 132, 40, 6538 }, // W. Central Africa Standard Time / Cameroon
- { 132, 46, 6552 }, // W. Central Africa Standard Time / Central African Republic
- { 132, 48, 6566 }, // W. Central Africa Standard Time / Chad
- { 132, 56, 6582 }, // W. Central Africa Standard Time / Congo Brazzaville
- { 132, 57, 6601 }, // W. Central Africa Standard Time / Congo Kinshasa
- { 132, 73, 6617 }, // W. Central Africa Standard Time / Equatorial Guinea
- { 132, 88, 6631 }, // W. Central Africa Standard Time / Gabon
- { 132, 169, 6649 }, // W. Central Africa Standard Time / Nigeria
- { 132, 170, 6662 }, // W. Central Africa Standard Time / Niger
- { 132, 238, 6676 }, // W. Central Africa Standard Time / Tunisia
- { 133, 6, 6689 }, // W. Europe Standard Time / Andorra
- { 133, 16, 6704 }, // W. Europe Standard Time / Austria
- { 133, 91, 6718 }, // W. Europe Standard Time / Germany
- { 133, 93, 6748 }, // W. Europe Standard Time / Gibraltar
- { 133, 117, 6765 }, // W. Europe Standard Time / Italy
- { 133, 136, 6777 }, // W. Europe Standard Time / Liechtenstein
- { 133, 138, 6790 }, // W. Europe Standard Time / Luxembourg
- { 133, 146, 6808 }, // W. Europe Standard Time / Malta
- { 133, 155, 6821 }, // W. Europe Standard Time / Monaco
- { 133, 165, 6835 }, // W. Europe Standard Time / Netherlands
- { 133, 175, 6852 }, // W. Europe Standard Time / Norway
- { 133, 203, 6864 }, // W. Europe Standard Time / San Marino
- { 133, 224, 6882 }, // W. Europe Standard Time / Svalbard And Jan Mayen
- { 133, 225, 6902 }, // W. Europe Standard Time / Sweden
- { 133, 226, 6919 }, // W. Europe Standard Time / Switzerland
- { 133, 253, 6933 }, // W. Europe Standard Time / Vatican City
- { 134, 156, 6948 }, // W. Mongolia Standard Time / Mongolia
- { 135, 0, 6958 }, // West Asia Standard Time / AnyTerritory
- { 135, 9, 6968 }, // West Asia Standard Time / Antarctica
- { 135, 87, 6986 }, // West Asia Standard Time / French Southern Territories
- { 135, 123, 7003 }, // West Asia Standard Time / Kazakhstan
- { 135, 144, 7048 }, // West Asia Standard Time / Maldives
- { 135, 229, 7064 }, // West Asia Standard Time / Tajikistan
- { 135, 240, 7078 }, // West Asia Standard Time / Turkmenistan
- { 135, 251, 7092 }, // West Asia Standard Time / Uzbekistan
- { 136, 180, 7121 }, // West Bank Standard Time / Palestinian Territories
- { 137, 0, 7143 }, // West Pacific Standard Time / AnyTerritory
- { 137, 9, 7154 }, // West Pacific Standard Time / Antarctica
- { 137, 98, 7180 }, // West Pacific Standard Time / Guam
- { 137, 153, 7193 }, // West Pacific Standard Time / Micronesia
- { 137, 173, 7206 }, // West Pacific Standard Time / Northern Mariana Islands
- { 137, 182, 7221 }, // West Pacific Standard Time / Papua New Guinea
- { 138, 193, 7242 }, // Yakutsk Standard Time / Russia
- { 139, 41, 7269 }, // Yukon Standard Time / Canada
+ { 30, 0, 1494 }, // Central Standard Time / AnyTerritory
+ { 30, 41, 1502 }, // Central Standard Time / Canada
+ { 30, 152, 1577 }, // Central Standard Time / Mexico
+ { 30, 248, 1611 }, // Central Standard Time / United States
+ { 31, 152, 1779 }, // Central Standard Time (Mexico) / Mexico
+ { 32, 167, 1873 }, // Chatham Islands Standard Time / New Zealand
+ { 33, 50, 1889 }, // China Standard Time / China
+ { 33, 107, 1903 }, // China Standard Time / Hong Kong
+ { 33, 139, 1918 }, // China Standard Time / Macao
+ { 34, 61, 1929 }, // Cuba Standard Time / Cuba
+ { 35, 0, 1944 }, // Dateline Standard Time / AnyTerritory
+ { 36, 0, 1955 }, // E. Africa Standard Time / AnyTerritory
+ { 36, 9, 1965 }, // E. Africa Standard Time / Antarctica
+ { 36, 55, 1982 }, // E. Africa Standard Time / Comoros
+ { 36, 67, 1996 }, // E. Africa Standard Time / Djibouti
+ { 36, 74, 2012 }, // E. Africa Standard Time / Eritrea
+ { 36, 77, 2026 }, // E. Africa Standard Time / Ethiopia
+ { 36, 124, 2045 }, // E. Africa Standard Time / Kenya
+ { 36, 141, 2060 }, // E. Africa Standard Time / Madagascar
+ { 36, 151, 2080 }, // E. Africa Standard Time / Mayotte
+ { 36, 215, 2095 }, // E. Africa Standard Time / Somalia
+ { 36, 230, 2112 }, // E. Africa Standard Time / Tanzania
+ { 36, 243, 2133 }, // E. Africa Standard Time / Uganda
+ { 37, 15, 2148 }, // E. Australia Standard Time / Australia
+ { 38, 154, 2186 }, // E. Europe Standard Time / Moldova
+ { 39, 32, 2202 }, // E. South America Standard Time / Brazil
+ { 40, 49, 2220 }, // Easter Island Standard Time / Chile
+ { 41, 0, 2235 }, // Eastern Standard Time / AnyTerritory
+ { 41, 18, 2243 }, // Eastern Standard Time / Bahamas
+ { 41, 41, 2258 }, // Eastern Standard Time / Canada
+ { 41, 248, 2363 }, // Eastern Standard Time / United States
+ { 42, 152, 2520 }, // Eastern Standard Time (Mexico) / Mexico
+ { 43, 71, 2535 }, // Egypt Standard Time / Egypt
+ { 44, 193, 2548 }, // Ekaterinburg Standard Time / Russia
+ { 45, 82, 2567 }, // Fiji Standard Time / Fiji
+ { 46, 2, 2580 }, // FLE Standard Time / Aland Islands
+ { 46, 36, 2597 }, // FLE Standard Time / Bulgaria
+ { 46, 75, 2610 }, // FLE Standard Time / Estonia
+ { 46, 83, 2625 }, // FLE Standard Time / Finland
+ { 46, 131, 2641 }, // FLE Standard Time / Latvia
+ { 46, 137, 2653 }, // FLE Standard Time / Lithuania
+ { 46, 244, 2668 }, // FLE Standard Time / Ukraine
+ { 47, 90, 2714 }, // Georgian Standard Time / Georgia
+ { 48, 81, 2727 }, // GMT Standard Time / Faroe Islands
+ { 48, 100, 2743 }, // GMT Standard Time / Guernsey
+ { 48, 114, 2759 }, // GMT Standard Time / Ireland
+ { 48, 115, 2773 }, // GMT Standard Time / Isle of Man
+ { 48, 121, 2792 }, // GMT Standard Time / Jersey
+ { 48, 188, 2806 }, // GMT Standard Time / Portugal
+ { 48, 220, 2837 }, // GMT Standard Time / Spain
+ { 48, 246, 2853 }, // GMT Standard Time / United Kingdom
+ { 49, 95, 2867 }, // Greenland Standard Time / Greenland
+ { 50, 37, 2883 }, // Greenwich Standard Time / Burkina Faso
+ { 50, 89, 2902 }, // Greenwich Standard Time / Gambia
+ { 50, 92, 2916 }, // Greenwich Standard Time / Ghana
+ { 50, 95, 2929 }, // Greenwich Standard Time / Greenland
+ { 50, 101, 2950 }, // Greenwich Standard Time / Guinea-Bissau
+ { 50, 102, 2964 }, // Greenwich Standard Time / Guinea
+ { 50, 109, 2979 }, // Greenwich Standard Time / Iceland
+ { 50, 118, 2998 }, // Greenwich Standard Time / Ivory Coast
+ { 50, 134, 3013 }, // Greenwich Standard Time / Liberia
+ { 50, 145, 3029 }, // Greenwich Standard Time / Mali
+ { 50, 149, 3043 }, // Greenwich Standard Time / Mauritania
+ { 50, 196, 3061 }, // Greenwich Standard Time / Saint Helena
+ { 50, 206, 3080 }, // Greenwich Standard Time / Senegal
+ { 50, 209, 3093 }, // Greenwich Standard Time / Sierra Leone
+ { 50, 233, 3109 }, // Greenwich Standard Time / Togo
+ { 51, 63, 3121 }, // GTB Standard Time / Cyprus
+ { 51, 94, 3149 }, // GTB Standard Time / Greece
+ { 51, 192, 3163 }, // GTB Standard Time / Romania
+ { 52, 104, 3180 }, // Haiti Standard Time / Haiti
+ { 53, 0, 3203 }, // Hawaiian Standard Time / AnyTerritory
+ { 53, 58, 3214 }, // Hawaiian Standard Time / Cook Islands
+ { 53, 86, 3232 }, // Hawaiian Standard Time / French Polynesia
+ { 53, 247, 3247 }, // Hawaiian Standard Time / United States Outlying Islands
+ { 53, 248, 3264 }, // Hawaiian Standard Time / United States
+ { 54, 110, 3281 }, // India Standard Time / India
+ { 55, 112, 3295 }, // Iran Standard Time / Iran
+ { 56, 116, 3307 }, // Israel Standard Time / Israel
+ { 57, 122, 3322 }, // Jordan Standard Time / Jordan
+ { 58, 193, 3333 }, // Kaliningrad Standard Time / Russia
+ { 59, 218, 3352 }, // Korea Standard Time / South Korea
+ { 60, 135, 3363 }, // Libya Standard Time / Libya
+ { 61, 0, 3378 }, // Line Islands Standard Time / AnyTerritory
+ { 61, 125, 3389 }, // Line Islands Standard Time / Kiribati
+ { 62, 15, 3408 }, // Lord Howe Standard Time / Australia
+ { 63, 193, 3428 }, // Magadan Standard Time / Russia
+ { 64, 49, 3441 }, // Magallanes Standard Time / Chile
+ { 65, 86, 3462 }, // Marquesas Standard Time / French Polynesia
+ { 66, 150, 3480 }, // Mauritius Standard Time / Mauritius
+ { 66, 191, 3497 }, // Mauritius Standard Time / Reunion
+ { 66, 208, 3512 }, // Mauritius Standard Time / Seychelles
+ { 67, 132, 3524 }, // Middle East Standard Time / Lebanon
+ { 68, 250, 3536 }, // Montevideo Standard Time / Uruguay
+ { 69, 159, 3555 }, // Morocco Standard Time / Morocco
+ { 69, 257, 3573 }, // Morocco Standard Time / Western Sahara
+ { 70, 0, 3589 }, // Mountain Standard Time / AnyTerritory
+ { 70, 41, 3597 }, // Mountain Standard Time / Canada
+ { 70, 152, 3671 }, // Mountain Standard Time / Mexico
+ { 70, 248, 3693 }, // Mountain Standard Time / United States
+ { 71, 152, 3722 }, // Mountain Standard Time (Mexico) / Mexico
+ { 72, 53, 3739 }, // Myanmar Standard Time / Cocos Islands
+ { 72, 161, 3752 }, // Myanmar Standard Time / Myanmar
+ { 73, 193, 3765 }, // N. Central Asia Standard Time / Russia
+ { 74, 162, 3782 }, // Namibia Standard Time / Namibia
+ { 75, 164, 3798 }, // Nepal Standard Time / Nepal
+ { 76, 9, 3812 }, // New Zealand Standard Time / Antarctica
+ { 76, 167, 3831 }, // New Zealand Standard Time / New Zealand
+ { 77, 41, 3848 }, // Newfoundland Standard Time / Canada
+ { 78, 172, 3865 }, // Norfolk Standard Time / Norfolk Island
+ { 79, 193, 3881 }, // North Asia East Standard Time / Russia
+ { 80, 193, 3894 }, // North Asia Standard Time / Russia
+ { 81, 174, 3929 }, // North Korea Standard Time / North Korea
+ { 82, 193, 3944 }, // Omsk Standard Time / Russia
+ { 83, 49, 3954 }, // Pacific SA Standard Time / Chile
+ { 84, 0, 3971 }, // Pacific Standard Time / AnyTerritory
+ { 84, 41, 3979 }, // Pacific Standard Time / Canada
+ { 84, 248, 3997 }, // Pacific Standard Time / United States
+ { 85, 152, 4017 }, // Pacific Standard Time (Mexico) / Mexico
+ { 86, 178, 4054 }, // Pakistan Standard Time / Pakistan
+ { 87, 183, 4067 }, // Paraguay Standard Time / Paraguay
+ { 88, 123, 4084 }, // Qyzylorda Standard Time / Kazakhstan
+ { 89, 23, 4099 }, // Romance Standard Time / Belgium
+ { 89, 65, 4115 }, // Romance Standard Time / Denmark
+ { 89, 84, 4133 }, // Romance Standard Time / France
+ { 89, 220, 4146 }, // Romance Standard Time / Spain
+ { 90, 193, 4173 }, // Russia Time Zone 10 / Russia
+ { 91, 193, 4192 }, // Russia Time Zone 11 / Russia
+ { 92, 193, 4219 }, // Russia Time Zone 3 / Russia
+ { 93, 193, 4233 }, // Russian Standard Time / Russia
+ { 93, 244, 4260 }, // Russian Standard Time / Ukraine
+ { 94, 0, 4278 }, // SA Eastern Standard Time / AnyTerritory
+ { 94, 9, 4288 }, // SA Eastern Standard Time / Antarctica
+ { 94, 32, 4325 }, // SA Eastern Standard Time / Brazil
+ { 94, 80, 4404 }, // SA Eastern Standard Time / Falkland Islands
+ { 94, 85, 4421 }, // SA Eastern Standard Time / French Guiana
+ { 94, 223, 4437 }, // SA Eastern Standard Time / Suriname
+ { 95, 0, 4456 }, // SA Pacific Standard Time / AnyTerritory
+ { 95, 32, 4466 }, // SA Pacific Standard Time / Brazil
+ { 95, 41, 4502 }, // SA Pacific Standard Time / Canada
+ { 95, 45, 4524 }, // SA Pacific Standard Time / Cayman Islands
+ { 95, 54, 4539 }, // SA Pacific Standard Time / Colombia
+ { 95, 70, 4554 }, // SA Pacific Standard Time / Ecuador
+ { 95, 119, 4572 }, // SA Pacific Standard Time / Jamaica
+ { 95, 181, 4588 }, // SA Pacific Standard Time / Panama
+ { 95, 184, 4603 }, // SA Pacific Standard Time / Peru
+ { 96, 0, 4616 }, // SA Western Standard Time / AnyTerritory
+ { 96, 8, 4626 }, // SA Western Standard Time / Anguilla
+ { 96, 10, 4643 }, // SA Western Standard Time / Antigua and Barbuda
+ { 96, 13, 4659 }, // SA Western Standard Time / Aruba
+ { 96, 21, 4673 }, // SA Western Standard Time / Barbados
+ { 96, 28, 4690 }, // SA Western Standard Time / Bolivia
+ { 96, 32, 4705 }, // SA Western Standard Time / Brazil
+ { 96, 34, 4758 }, // SA Western Standard Time / British Virgin Islands
+ { 96, 41, 4774 }, // SA Western Standard Time / Canada
+ { 96, 44, 4795 }, // SA Western Standard Time / Caribbean Netherlands
+ { 96, 62, 4814 }, // SA Western Standard Time / Curacao
+ { 96, 68, 4830 }, // SA Western Standard Time / Dominica
+ { 96, 69, 4847 }, // SA Western Standard Time / Dominican Republic
+ { 96, 96, 4869 }, // SA Western Standard Time / Grenada
+ { 96, 97, 4885 }, // SA Western Standard Time / Guadeloupe
+ { 96, 103, 4904 }, // SA Western Standard Time / Guyana
+ { 96, 148, 4919 }, // SA Western Standard Time / Martinique
+ { 96, 158, 4938 }, // SA Western Standard Time / Montserrat
+ { 96, 189, 4957 }, // SA Western Standard Time / Puerto Rico
+ { 96, 195, 4977 }, // SA Western Standard Time / Saint Barthelemy
+ { 96, 197, 4999 }, // SA Western Standard Time / Saint Kitts and Nevis
+ { 96, 198, 5016 }, // SA Western Standard Time / Saint Lucia
+ { 96, 199, 5033 }, // SA Western Standard Time / Saint Martin
+ { 96, 201, 5049 }, // SA Western Standard Time / Saint Vincent and Grenadines
+ { 96, 211, 5068 }, // SA Western Standard Time / Sint Maarten
+ { 96, 236, 5090 }, // SA Western Standard Time / Trinidad and Tobago
+ { 96, 249, 5112 }, // SA Western Standard Time / United States Virgin Islands
+ { 97, 200, 5130 }, // Saint Pierre Standard Time / Saint Pierre and Miquelon
+ { 98, 193, 5147 }, // Sakhalin Standard Time / Russia
+ { 99, 202, 5161 }, // Samoa Standard Time / Samoa
+ { 100, 204, 5174 }, // Sao Tome Standard Time / Sao Tome and Principe
+ { 101, 193, 5190 }, // Saratov Standard Time / Russia
+ { 102, 0, 5205 }, // SE Asia Standard Time / AnyTerritory
+ { 102, 9, 5215 }, // SE Asia Standard Time / Antarctica
+ { 102, 39, 5232 }, // SE Asia Standard Time / Cambodia
+ { 102, 51, 5248 }, // SE Asia Standard Time / Christmas Island
+ { 102, 111, 5265 }, // SE Asia Standard Time / Indonesia
+ { 102, 129, 5293 }, // SE Asia Standard Time / Laos
+ { 102, 231, 5308 }, // SE Asia Standard Time / Thailand
+ { 102, 255, 5321 }, // SE Asia Standard Time / Vietnam
+ { 103, 0, 5333 }, // Singapore Standard Time / AnyTerritory
+ { 103, 35, 5343 }, // Singapore Standard Time / Brunei
+ { 103, 111, 5355 }, // Singapore Standard Time / Indonesia
+ { 103, 143, 5369 }, // Singapore Standard Time / Malaysia
+ { 103, 185, 5400 }, // Singapore Standard Time / Philippines
+ { 103, 210, 5412 }, // Singapore Standard Time / Singapore
+ { 104, 0, 5427 }, // South Africa Standard Time / AnyTerritory
+ { 104, 30, 5437 }, // South Africa Standard Time / Botswana
+ { 104, 38, 5453 }, // South Africa Standard Time / Burundi
+ { 104, 57, 5470 }, // South Africa Standard Time / Congo - Kinshasa
+ { 104, 76, 5488 }, // South Africa Standard Time / Eswatini
+ { 104, 133, 5503 }, // South Africa Standard Time / Lesotho
+ { 104, 142, 5517 }, // South Africa Standard Time / Malawi
+ { 104, 160, 5533 }, // South Africa Standard Time / Mozambique
+ { 104, 194, 5547 }, // South Africa Standard Time / Rwanda
+ { 104, 216, 5561 }, // South Africa Standard Time / South Africa
+ { 104, 260, 5581 }, // South Africa Standard Time / Zambia
+ { 104, 261, 5595 }, // South Africa Standard Time / Zimbabwe
+ { 105, 219, 5609 }, // South Sudan Standard Time / South Sudan
+ { 106, 221, 5621 }, // Sri Lanka Standard Time / Sri Lanka
+ { 107, 222, 5634 }, // Sudan Standard Time / Sudan
+ { 108, 227, 5650 }, // Syria Standard Time / Syria
+ { 109, 228, 5664 }, // Taipei Standard Time / Taiwan
+ { 110, 15, 5676 }, // Tasmania Standard Time / Australia
+ { 111, 32, 5731 }, // Tocantins Standard Time / Brazil
+ { 112, 0, 5749 }, // Tokyo Standard Time / AnyTerritory
+ { 112, 111, 5759 }, // Tokyo Standard Time / Indonesia
+ { 112, 120, 5773 }, // Tokyo Standard Time / Japan
+ { 112, 179, 5784 }, // Tokyo Standard Time / Palau
+ { 112, 232, 5798 }, // Tokyo Standard Time / Timor-Leste
+ { 113, 193, 5808 }, // Tomsk Standard Time / Russia
+ { 114, 235, 5819 }, // Tonga Standard Time / Tonga
+ { 115, 193, 5837 }, // Transbaikal Standard Time / Russia
+ { 116, 239, 5848 }, // Turkey Standard Time / Turkey
+ { 117, 241, 5864 }, // Turks And Caicos Standard Time / Turks and Caicos Islands
+ { 118, 156, 5883 }, // Ulaanbaatar Standard Time / Mongolia
+ { 119, 248, 5916 }, // US Eastern Standard Time / United States
+ { 120, 0, 5983 }, // US Mountain Standard Time / AnyTerritory
+ { 120, 41, 5993 }, // US Mountain Standard Time / Canada
+ { 120, 152, 6050 }, // US Mountain Standard Time / Mexico
+ { 120, 248, 6069 }, // US Mountain Standard Time / United States
+ { 121, 0, 6085 }, // UTC / AnyTerritory
+ { 122, 0, 6101 }, // UTC+12 / AnyTerritory
+ { 122, 125, 6112 }, // UTC+12 / Kiribati
+ { 122, 147, 6127 }, // UTC+12 / Marshall Islands
+ { 122, 163, 6160 }, // UTC+12 / Nauru
+ { 122, 242, 6174 }, // UTC+12 / Tuvalu
+ { 122, 247, 6191 }, // UTC+12 / United States Outlying Islands
+ { 122, 256, 6204 }, // UTC+12 / Wallis and Futuna
+ { 123, 0, 6219 }, // UTC+13 / AnyTerritory
+ { 123, 125, 6230 }, // UTC+13 / Kiribati
+ { 123, 234, 6248 }, // UTC+13 / Tokelau
+ { 124, 0, 6264 }, // UTC-02 / AnyTerritory
+ { 124, 32, 6274 }, // UTC-02 / Brazil
+ { 124, 217, 6290 }, // UTC-02 / South Georgia and South Sandwich Islands
+ { 125, 0, 6313 }, // UTC-08 / AnyTerritory
+ { 125, 186, 6323 }, // UTC-08 / Pitcairn
+ { 126, 0, 6340 }, // UTC-09 / AnyTerritory
+ { 126, 86, 6350 }, // UTC-09 / French Polynesia
+ { 127, 0, 6366 }, // UTC-11 / AnyTerritory
+ { 127, 5, 6377 }, // UTC-11 / American Samoa
+ { 127, 171, 6395 }, // UTC-11 / Niue
+ { 127, 247, 6408 }, // UTC-11 / United States Outlying Islands
+ { 128, 254, 6423 }, // Venezuela Standard Time / Venezuela
+ { 129, 193, 6439 }, // Vladivostok Standard Time / Russia
+ { 130, 193, 6470 }, // Volgograd Standard Time / Russia
+ { 131, 15, 6487 }, // W. Australia Standard Time / Australia
+ { 132, 0, 6503 }, // W. Central Africa Standard Time / AnyTerritory
+ { 132, 4, 6513 }, // W. Central Africa Standard Time / Algeria
+ { 132, 7, 6528 }, // W. Central Africa Standard Time / Angola
+ { 132, 25, 6542 }, // W. Central Africa Standard Time / Benin
+ { 132, 40, 6560 }, // W. Central Africa Standard Time / Cameroon
+ { 132, 46, 6574 }, // W. Central Africa Standard Time / Central African Republic
+ { 132, 48, 6588 }, // W. Central Africa Standard Time / Chad
+ { 132, 56, 6604 }, // W. Central Africa Standard Time / Congo - Brazzaville
+ { 132, 57, 6623 }, // W. Central Africa Standard Time / Congo - Kinshasa
+ { 132, 73, 6639 }, // W. Central Africa Standard Time / Equatorial Guinea
+ { 132, 88, 6653 }, // W. Central Africa Standard Time / Gabon
+ { 132, 169, 6671 }, // W. Central Africa Standard Time / Nigeria
+ { 132, 170, 6684 }, // W. Central Africa Standard Time / Niger
+ { 132, 238, 6698 }, // W. Central Africa Standard Time / Tunisia
+ { 133, 6, 6711 }, // W. Europe Standard Time / Andorra
+ { 133, 16, 6726 }, // W. Europe Standard Time / Austria
+ { 133, 91, 6740 }, // W. Europe Standard Time / Germany
+ { 133, 93, 6770 }, // W. Europe Standard Time / Gibraltar
+ { 133, 117, 6787 }, // W. Europe Standard Time / Italy
+ { 133, 136, 6799 }, // W. Europe Standard Time / Liechtenstein
+ { 133, 138, 6812 }, // W. Europe Standard Time / Luxembourg
+ { 133, 146, 6830 }, // W. Europe Standard Time / Malta
+ { 133, 155, 6843 }, // W. Europe Standard Time / Monaco
+ { 133, 165, 6857 }, // W. Europe Standard Time / Netherlands
+ { 133, 175, 6874 }, // W. Europe Standard Time / Norway
+ { 133, 203, 6886 }, // W. Europe Standard Time / San Marino
+ { 133, 224, 6904 }, // W. Europe Standard Time / Svalbard and Jan Mayen
+ { 133, 225, 6924 }, // W. Europe Standard Time / Sweden
+ { 133, 226, 6941 }, // W. Europe Standard Time / Switzerland
+ { 133, 253, 6955 }, // W. Europe Standard Time / Vatican City
+ { 134, 156, 6970 }, // W. Mongolia Standard Time / Mongolia
+ { 135, 0, 6980 }, // West Asia Standard Time / AnyTerritory
+ { 135, 9, 6990 }, // West Asia Standard Time / Antarctica
+ { 135, 87, 7008 }, // West Asia Standard Time / French Southern Territories
+ { 135, 123, 7025 }, // West Asia Standard Time / Kazakhstan
+ { 135, 144, 7070 }, // West Asia Standard Time / Maldives
+ { 135, 229, 7086 }, // West Asia Standard Time / Tajikistan
+ { 135, 240, 7100 }, // West Asia Standard Time / Turkmenistan
+ { 135, 251, 7114 }, // West Asia Standard Time / Uzbekistan
+ { 136, 180, 7143 }, // West Bank Standard Time / Palestinian Territories
+ { 137, 0, 7165 }, // West Pacific Standard Time / AnyTerritory
+ { 137, 9, 7176 }, // West Pacific Standard Time / Antarctica
+ { 137, 98, 7202 }, // West Pacific Standard Time / Guam
+ { 137, 153, 7215 }, // West Pacific Standard Time / Micronesia
+ { 137, 173, 7228 }, // West Pacific Standard Time / Northern Mariana Islands
+ { 137, 182, 7243 }, // West Pacific Standard Time / Papua New Guinea
+ { 138, 193, 7264 }, // Yakutsk Standard Time / Russia
+ { 139, 41, 7291 }, // Yukon Standard Time / Canada
};
// Windows ID Key, Windows ID Index, IANA ID Index, UTC Offset
-static constexpr QWindowsData windowsDataTable[] = {
+static constexpr WindowsData windowsDataTable[] = {
{ 1, 0, 0, 16200 }, // Afghanistan Standard Time
- { 2, 26, 7303,-32400 }, // Alaskan Standard Time
+ { 2, 26, 7325,-32400 }, // Alaskan Standard Time
{ 3, 48, 106,-36000 }, // Aleutian Standard Time
{ 4, 71, 119, 25200 }, // Altai Standard Time
{ 5, 91, 168, 10800 }, // Arab Standard Time
{ 6, 110, 212, 14400 }, // Arabian Standard Time
{ 7, 132, 223, 10800 }, // Arabic Standard Time
- { 8, 153, 7321,-10800 }, // Argentina Standard Time
- { 9, 177, 7342, 14400 }, // Astrakhan Standard Time
- { 10, 201, 7359,-14400 }, // Atlantic Standard Time
+ { 8, 153, 7343,-10800 }, // Argentina Standard Time
+ { 9, 177, 7364, 14400 }, // Astrakhan Standard Time
+ { 10, 201, 7381,-14400 }, // Atlantic Standard Time
{ 11, 224, 642, 34200 }, // AUS Central Standard Time
{ 12, 250, 659, 31500 }, // Aus Central W. Standard Time
- { 13, 279, 7375, 36000 }, // AUS Eastern Standard Time
+ { 13, 279, 7397, 36000 }, // AUS Eastern Standard Time
{ 14, 305, 712, 14400 }, // Azerbaijan Standard Time
{ 15, 330, 743, -3600 }, // Azores Standard Time
{ 16, 351, 759,-10800 }, // Bahia Standard Time
{ 17, 371, 773, 21600 }, // Bangladesh Standard Time
{ 18, 396, 797, 10800 }, // Belarus Standard Time
{ 19, 418, 810, 39600 }, // Bougainville Standard Time
- { 20, 445, 7392,-21600 }, // Canada Central Standard Time
+ { 20, 445, 7414,-21600 }, // Canada Central Standard Time
{ 21, 474, 878, -3600 }, // Cape Verde Standard Time
{ 22, 499, 898, 14400 }, // Caucasus Standard Time
- { 23, 522, 7407, 34200 }, // Cen. Australia Standard Time
+ { 23, 522, 7429, 34200 }, // Cen. Australia Standard Time
{ 24, 551, 1034,-21600 }, // Central America Standard Time
- { 25, 581, 7426, 21600 }, // Central Asia Standard Time
- { 26, 608, 7438,-14400 }, // Central Brazilian Standard Time
+ { 25, 581, 7448, 21600 }, // Central Asia Standard Time
+ { 26, 608, 7460,-14400 }, // Central Brazilian Standard Time
{ 27, 640, 1245, 3600 }, // Central Europe Standard Time
{ 28, 669, 1373, 3600 }, // Central European Standard Time
{ 29, 700, 1460, 39600 }, // Central Pacific Standard Time
- { 30, 730, 7453,-21600 }, // Central Standard Time (Mexico)
- { 31, 761, 7473,-21600 }, // Central Standard Time
- { 32, 783, 1839, 28800 }, // China Standard Time
- { 33, 803, 1879, 45900 }, // Chatham Islands Standard Time
- { 34, 833, 1895,-18000 }, // Cuba Standard Time
- { 35, 852, 1910,-43200 }, // Dateline Standard Time
- { 36, 875, 2011, 10800 }, // E. Africa Standard Time
- { 37, 899, 7489, 36000 }, // E. Australia Standard Time
- { 38, 926, 2152, 7200 }, // E. Europe Standard Time
- { 39, 950, 2168,-10800 }, // E. South America Standard Time
- { 40, 981, 2186,-21600 }, // Easter Island Standard Time
- { 41, 1009, 7508,-18000 }, // Eastern Standard Time
- { 42, 1031, 2486,-18000 }, // Eastern Standard Time (Mexico)
- { 43, 1062, 2501, 7200 }, // Egypt Standard Time
- { 44, 1082, 2514, 18000 }, // Ekaterinburg Standard Time
- { 45, 1109, 2533, 43200 }, // Fiji Standard Time
- { 46, 1128, 7525, 7200 }, // FLE Standard Time
- { 47, 1146, 2680, 14400 }, // Georgian Standard Time
- { 48, 1169, 2819, 0 }, // GMT Standard Time
- { 49, 1187, 2833,-10800 }, // Greenland Standard Time
- { 50, 1211, 2945, 0 }, // Greenwich Standard Time
- { 51, 1235, 3129, 7200 }, // GTB Standard Time
- { 52, 1253, 3146,-18000 }, // Haiti Standard Time
- { 53, 1273, 3230,-36000 }, // Hawaiian Standard Time
- { 54, 1296, 3247, 19800 }, // India Standard Time
- { 55, 1316, 3261, 12600 }, // Iran Standard Time
- { 56, 1335, 3273, 7200 }, // Israel Standard Time
- { 57, 1356, 3288, 7200 }, // Jordan Standard Time
- { 58, 1377, 3299, 7200 }, // Kaliningrad Standard Time
- { 59, 1403, 3318, 32400 }, // Korea Standard Time
- { 60, 1423, 3329, 7200 }, // Libya Standard Time
- { 61, 1443, 3355, 50400 }, // Line Islands Standard Time
- { 62, 1470, 3374, 37800 }, // Lord Howe Standard Time
- { 63, 1494, 3394, 36000 }, // Magadan Standard Time
- { 64, 1516, 3407,-10800 }, // Magallanes Standard Time
- { 65, 1541, 3428,-34200 }, // Marquesas Standard Time
- { 66, 1565, 3446, 14400 }, // Mauritius Standard Time
- { 67, 1589, 3490, 7200 }, // Middle East Standard Time
- { 68, 1615, 3502,-10800 }, // Montevideo Standard Time
- { 69, 1640, 3521, 0 }, // Morocco Standard Time
- { 70, 1662, 7537,-25200 }, // Mountain Standard Time (Mexico)
- { 71, 1694, 7555,-25200 }, // Mountain Standard Time
- { 72, 1717, 3730, 23400 }, // Myanmar Standard Time
- { 73, 1739, 3743, 21600 }, // N. Central Asia Standard Time
- { 74, 1769, 3760, 3600 }, // Namibia Standard Time
- { 75, 1791, 3776, 20700 }, // Nepal Standard Time
- { 76, 1811, 3809, 43200 }, // New Zealand Standard Time
- { 77, 1837, 3826,-12600 }, // Newfoundland Standard Time
- { 78, 1864, 3843, 39600 }, // Norfolk Standard Time
- { 79, 1886, 3859, 28800 }, // North Asia East Standard Time
- { 80, 1916, 7570, 25200 }, // North Asia Standard Time
- { 81, 1941, 3907, 30600 }, // North Korea Standard Time
- { 82, 1967, 3922, 21600 }, // Omsk Standard Time
- { 83, 1986, 3932,-10800 }, // Pacific SA Standard Time
- { 84, 2011, 3975,-28800 }, // Pacific Standard Time
- { 85, 2033, 7587,-28800 }, // Pacific Standard Time (Mexico)
- { 86, 2064, 4032, 18000 }, // Pakistan Standard Time
- { 87, 2087, 4045,-14400 }, // Paraguay Standard Time
- { 88, 2110, 4062, 18000 }, // Qyzylorda Standard Time
- { 89, 2134, 4111, 3600 }, // Romance Standard Time
- { 90, 2156, 4151, 14400 }, // Russia Time Zone 3
- { 91, 2175, 4165, 39600 }, // Russia Time Zone 10
- { 92, 2195, 7603, 43200 }, // Russia Time Zone 11
- { 93, 2215, 7618, 10800 }, // Russian Standard Time
- { 94, 2237, 4399,-10800 }, // SA Eastern Standard Time
- { 95, 2262, 4517,-18000 }, // SA Pacific Standard Time
- { 96, 2287, 4668,-14400 }, // SA Western Standard Time
- { 97, 2312, 5108,-10800 }, // Saint Pierre Standard Time
- { 98, 2339, 5125, 39600 }, // Sakhalin Standard Time
- { 99, 2362, 5139, 46800 }, // Samoa Standard Time
- { 100, 2382, 5152, 0 }, // Sao Tome Standard Time
- { 101, 2405, 5168, 14400 }, // Saratov Standard Time
- { 102, 2427, 5286, 25200 }, // SE Asia Standard Time
- { 103, 2449, 5390, 28800 }, // Singapore Standard Time
- { 104, 2473, 5539, 7200 }, // South Africa Standard Time
- { 105, 2500, 5587, 7200 }, // South Sudan Standard Time
- { 106, 2526, 5599, 19800 }, // Sri Lanka Standard Time
- { 107, 2550, 5612, 7200 }, // Sudan Standard Time
- { 108, 2570, 5628, 7200 }, // Syria Standard Time
- { 109, 2590, 5642, 28800 }, // Taipei Standard Time
- { 110, 2611, 7632, 36000 }, // Tasmania Standard Time
- { 111, 2634, 5709,-10800 }, // Tocantins Standard Time
- { 112, 2658, 5751, 32400 }, // Tokyo Standard Time
- { 113, 2678, 5786, 25200 }, // Tomsk Standard Time
- { 114, 2698, 5797, 46800 }, // Tonga Standard Time
- { 115, 2718, 5815, 32400 }, // Transbaikal Standard Time
- { 116, 2744, 5826, 7200 }, // Turkey Standard Time
- { 117, 2765, 5842,-14400 }, // Turks And Caicos Standard Time
- { 118, 2796, 7649, 28800 }, // Ulaanbaatar Standard Time
- { 119, 2822, 7666,-18000 }, // US Eastern Standard Time
- { 120, 2847, 6047,-25200 }, // US Mountain Standard Time
- { 121, 2873, 6063,-39600 }, // UTC-11
- { 122, 2880, 6120,-32400 }, // UTC-09
- { 123, 2887, 6146,-28800 }, // UTC-08
- { 124, 2894, 6173, -7200 }, // UTC-02
- { 125, 2901, 7687, 0 }, // UTC
- { 126, 2905, 6238, 43200 }, // UTC+12
- { 127, 2912, 6356, 46800 }, // UTC+13
- { 128, 2919, 6401,-16200 }, // Venezuela Standard Time
- { 129, 2943, 7695, 36000 }, // Vladivostok Standard Time
- { 130, 2969, 6448, 14400 }, // Volgograd Standard Time
- { 131, 2993, 6465, 28800 }, // W. Australia Standard Time
- { 132, 3020, 6649, 3600 }, // W. Central Africa Standard Time
- { 133, 3052, 7712, 3600 }, // W. Europe Standard Time
- { 134, 3076, 6948, 25200 }, // W. Mongolia Standard Time
- { 135, 3102, 7726, 18000 }, // West Asia Standard Time
- { 136, 3126, 7740, 7200 }, // West Bank Standard Time
- { 137, 3150, 7221, 36000 }, // West Pacific Standard Time
- { 138, 3177, 7752, 32400 }, // Yakutsk Standard Time
- { 139, 3199, 7765,-25200 }, // Yukon Standard Time
+ { 30, 730, 7475,-21600 }, // Central Standard Time
+ { 31, 752, 7491,-21600 }, // Central Standard Time (Mexico)
+ { 32, 783, 1873, 45900 }, // Chatham Islands Standard Time
+ { 33, 813, 1889, 28800 }, // China Standard Time
+ { 34, 833, 1929,-18000 }, // Cuba Standard Time
+ { 35, 852, 1944,-43200 }, // Dateline Standard Time
+ { 36, 875, 2045, 10800 }, // E. Africa Standard Time
+ { 37, 899, 7511, 36000 }, // E. Australia Standard Time
+ { 38, 926, 2186, 7200 }, // E. Europe Standard Time
+ { 39, 950, 2202,-10800 }, // E. South America Standard Time
+ { 40, 981, 2220,-21600 }, // Easter Island Standard Time
+ { 41, 1009, 7530,-18000 }, // Eastern Standard Time
+ { 42, 1031, 2520,-18000 }, // Eastern Standard Time (Mexico)
+ { 43, 1062, 2535, 7200 }, // Egypt Standard Time
+ { 44, 1082, 2548, 18000 }, // Ekaterinburg Standard Time
+ { 45, 1109, 2567, 43200 }, // Fiji Standard Time
+ { 46, 1128, 7547, 7200 }, // FLE Standard Time
+ { 47, 1146, 2714, 14400 }, // Georgian Standard Time
+ { 48, 1169, 2853, 0 }, // GMT Standard Time
+ { 49, 1187, 2867,-10800 }, // Greenland Standard Time
+ { 50, 1211, 2979, 0 }, // Greenwich Standard Time
+ { 51, 1235, 3163, 7200 }, // GTB Standard Time
+ { 52, 1253, 3180,-18000 }, // Haiti Standard Time
+ { 53, 1273, 3264,-36000 }, // Hawaiian Standard Time
+ { 54, 1296, 3281, 19800 }, // India Standard Time
+ { 55, 1316, 3295, 12600 }, // Iran Standard Time
+ { 56, 1335, 3307, 7200 }, // Israel Standard Time
+ { 57, 1356, 3322, 7200 }, // Jordan Standard Time
+ { 58, 1377, 3333, 7200 }, // Kaliningrad Standard Time
+ { 59, 1403, 3352, 32400 }, // Korea Standard Time
+ { 60, 1423, 3363, 7200 }, // Libya Standard Time
+ { 61, 1443, 3389, 50400 }, // Line Islands Standard Time
+ { 62, 1470, 3408, 37800 }, // Lord Howe Standard Time
+ { 63, 1494, 3428, 36000 }, // Magadan Standard Time
+ { 64, 1516, 3441,-10800 }, // Magallanes Standard Time
+ { 65, 1541, 3462,-34200 }, // Marquesas Standard Time
+ { 66, 1565, 3480, 14400 }, // Mauritius Standard Time
+ { 67, 1589, 3524, 7200 }, // Middle East Standard Time
+ { 68, 1615, 3536,-10800 }, // Montevideo Standard Time
+ { 69, 1640, 3555, 0 }, // Morocco Standard Time
+ { 70, 1662, 7559,-25200 }, // Mountain Standard Time
+ { 71, 1685, 3722,-25200 }, // Mountain Standard Time (Mexico)
+ { 72, 1717, 3752, 23400 }, // Myanmar Standard Time
+ { 73, 1739, 3765, 21600 }, // N. Central Asia Standard Time
+ { 74, 1769, 3782, 3600 }, // Namibia Standard Time
+ { 75, 1791, 3798, 20700 }, // Nepal Standard Time
+ { 76, 1811, 3831, 43200 }, // New Zealand Standard Time
+ { 77, 1837, 3848,-12600 }, // Newfoundland Standard Time
+ { 78, 1864, 3865, 39600 }, // Norfolk Standard Time
+ { 79, 1886, 3881, 28800 }, // North Asia East Standard Time
+ { 80, 1916, 7574, 25200 }, // North Asia Standard Time
+ { 81, 1941, 3929, 30600 }, // North Korea Standard Time
+ { 82, 1967, 3944, 21600 }, // Omsk Standard Time
+ { 83, 1986, 3954,-10800 }, // Pacific SA Standard Time
+ { 84, 2011, 3997,-28800 }, // Pacific Standard Time
+ { 85, 2033, 7591,-28800 }, // Pacific Standard Time (Mexico)
+ { 86, 2064, 4054, 18000 }, // Pakistan Standard Time
+ { 87, 2087, 4067,-14400 }, // Paraguay Standard Time
+ { 88, 2110, 4084, 18000 }, // Qyzylorda Standard Time
+ { 89, 2134, 4133, 3600 }, // Romance Standard Time
+ { 90, 2156, 4173, 39600 }, // Russia Time Zone 10
+ { 91, 2176, 7607, 43200 }, // Russia Time Zone 11
+ { 92, 2196, 4219, 14400 }, // Russia Time Zone 3
+ { 93, 2215, 7622, 10800 }, // Russian Standard Time
+ { 94, 2237, 4421,-10800 }, // SA Eastern Standard Time
+ { 95, 2262, 4539,-18000 }, // SA Pacific Standard Time
+ { 96, 2287, 4690,-14400 }, // SA Western Standard Time
+ { 97, 2312, 5130,-10800 }, // Saint Pierre Standard Time
+ { 98, 2339, 5147, 39600 }, // Sakhalin Standard Time
+ { 99, 2362, 5161, 46800 }, // Samoa Standard Time
+ { 100, 2382, 5174, 0 }, // Sao Tome Standard Time
+ { 101, 2405, 5190, 14400 }, // Saratov Standard Time
+ { 102, 2427, 5308, 25200 }, // SE Asia Standard Time
+ { 103, 2449, 5412, 28800 }, // Singapore Standard Time
+ { 104, 2473, 5561, 7200 }, // South Africa Standard Time
+ { 105, 2500, 5609, 7200 }, // South Sudan Standard Time
+ { 106, 2526, 5621, 19800 }, // Sri Lanka Standard Time
+ { 107, 2550, 5634, 7200 }, // Sudan Standard Time
+ { 108, 2570, 5650, 7200 }, // Syria Standard Time
+ { 109, 2590, 5664, 28800 }, // Taipei Standard Time
+ { 110, 2611, 7636, 36000 }, // Tasmania Standard Time
+ { 111, 2634, 5731,-10800 }, // Tocantins Standard Time
+ { 112, 2658, 5773, 32400 }, // Tokyo Standard Time
+ { 113, 2678, 5808, 25200 }, // Tomsk Standard Time
+ { 114, 2698, 5819, 46800 }, // Tonga Standard Time
+ { 115, 2718, 5837, 32400 }, // Transbaikal Standard Time
+ { 116, 2744, 5848, 7200 }, // Turkey Standard Time
+ { 117, 2765, 5864,-14400 }, // Turks And Caicos Standard Time
+ { 118, 2796, 7653, 28800 }, // Ulaanbaatar Standard Time
+ { 119, 2822, 7670,-18000 }, // US Eastern Standard Time
+ { 120, 2847, 6069,-25200 }, // US Mountain Standard Time
+ { 121, 2873, 7691, 0 }, // UTC
+ { 122, 2877, 6101, 43200 }, // UTC+12
+ { 123, 2884, 6219, 46800 }, // UTC+13
+ { 124, 2891, 6264, -7200 }, // UTC-02
+ { 125, 2898, 6313,-28800 }, // UTC-08
+ { 126, 2905, 6340,-32400 }, // UTC-09
+ { 127, 2912, 6366,-39600 }, // UTC-11
+ { 128, 2919, 6423,-16200 }, // Venezuela Standard Time
+ { 129, 2943, 7699, 36000 }, // Vladivostok Standard Time
+ { 130, 2969, 6470, 14400 }, // Volgograd Standard Time
+ { 131, 2993, 6487, 28800 }, // W. Australia Standard Time
+ { 132, 3020, 6671, 3600 }, // W. Central Africa Standard Time
+ { 133, 3052, 7716, 3600 }, // W. Europe Standard Time
+ { 134, 3076, 6970, 25200 }, // W. Mongolia Standard Time
+ { 135, 3102, 7730, 18000 }, // West Asia Standard Time
+ { 136, 3126, 7744, 7200 }, // West Bank Standard Time
+ { 137, 3150, 7243, 36000 }, // West Pacific Standard Time
+ { 138, 3177, 7756, 32400 }, // Yakutsk Standard Time
+ { 139, 3199, 7769,-25200 }, // Yukon Standard Time
};
// IANA ID Index, UTC Offset
-static constexpr QUtcData utcDataTable[] = {
- { 7784, 0 }, // UTC
+static constexpr UtcData utcDataTable[] = {
{ 7788,-50400 }, // UTC-14:00
{ 7798,-46800 }, // UTC-13:00
{ 7808,-43200 }, // UTC-12:00
@@ -631,615 +618,760 @@ static constexpr QUtcData utcDataTable[] = {
{ 7918,-10800 }, // UTC-03:00
{ 7928, -7200 }, // UTC-02:00
{ 7938, -3600 }, // UTC-01:00
- { 7948, 0 }, // UTC-00:00
- { 7958, 0 }, // UTC+00:00
- { 7968, 3600 }, // UTC+01:00
- { 7978, 7200 }, // UTC+02:00
- { 7988, 10800 }, // UTC+03:00
- { 7998, 12600 }, // UTC+03:30
- { 8008, 14400 }, // UTC+04:00
- { 8018, 16200 }, // UTC+04:30
- { 8028, 18000 }, // UTC+05:00
- { 8038, 19800 }, // UTC+05:30
- { 8048, 20700 }, // UTC+05:45
- { 8058, 21600 }, // UTC+06:00
- { 8068, 23400 }, // UTC+06:30
- { 8078, 25200 }, // UTC+07:00
- { 8088, 28800 }, // UTC+08:00
- { 8098, 30600 }, // UTC+08:30
- { 8108, 32400 }, // UTC+09:00
- { 8118, 34200 }, // UTC+09:30
- { 8128, 36000 }, // UTC+10:00
- { 8138, 39600 }, // UTC+11:00
- { 8148, 43200 }, // UTC+12:00
- { 8158, 46800 }, // UTC+13:00
- { 8168, 50400 }, // UTC+14:00
+ { 7948, 0 }, // UTC
+ { 7972, 3600 }, // UTC+01:00
+ { 7982, 7200 }, // UTC+02:00
+ { 7992, 10800 }, // UTC+03:00
+ { 8002, 12600 }, // UTC+03:30
+ { 8012, 14400 }, // UTC+04:00
+ { 8022, 16200 }, // UTC+04:30
+ { 8032, 18000 }, // UTC+05:00
+ { 8042, 19800 }, // UTC+05:30
+ { 8052, 20700 }, // UTC+05:45
+ { 8062, 21600 }, // UTC+06:00
+ { 8072, 23400 }, // UTC+06:30
+ { 8082, 25200 }, // UTC+07:00
+ { 8092, 28800 }, // UTC+08:00
+ { 8102, 30600 }, // UTC+08:30
+ { 8112, 32400 }, // UTC+09:00
+ { 8122, 34200 }, // UTC+09:30
+ { 8132, 36000 }, // UTC+10:00
+ { 8142, 39600 }, // UTC+11:00
+ { 8152, 43200 }, // UTC+12:00
+ { 8162, 46800 }, // UTC+13:00
+ { 8172, 50400 }, // UTC+14:00
};
static constexpr char windowsIdData[] = {
-0x41, 0x66, 0x67, 0x68, 0x61, 0x6e, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64,
-0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x41, 0x6c, 0x61, 0x73, 0x6b, 0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61,
-0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x41, 0x6c, 0x65, 0x75, 0x74, 0x69, 0x61, 0x6e, 0x20, 0x53, 0x74, 0x61,
-0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x41, 0x6c, 0x74, 0x61, 0x69, 0x20, 0x53, 0x74, 0x61,
-0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x41, 0x72, 0x61, 0x62, 0x20, 0x53, 0x74, 0x61, 0x6e,
-0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x41, 0x72, 0x61, 0x62, 0x69, 0x61, 0x6e, 0x20, 0x53, 0x74,
-0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x41, 0x72, 0x61, 0x62, 0x69, 0x63, 0x20, 0x53,
-0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69,
-0x6e, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x41, 0x73, 0x74,
-0x72, 0x61, 0x6b, 0x68, 0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65,
-0x0, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54,
-0x69, 0x6d, 0x65, 0x0, 0x41, 0x55, 0x53, 0x20, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x53, 0x74, 0x61, 0x6e,
-0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x41, 0x75, 0x73, 0x20, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61,
-0x6c, 0x20, 0x57, 0x2e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x41,
-0x55, 0x53, 0x20, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20,
-0x54, 0x69, 0x6d, 0x65, 0x0, 0x41, 0x7a, 0x65, 0x72, 0x62, 0x61, 0x69, 0x6a, 0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e,
-0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x41, 0x7a, 0x6f, 0x72, 0x65, 0x73, 0x20, 0x53, 0x74, 0x61,
-0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x42, 0x61, 0x68, 0x69, 0x61, 0x20, 0x53, 0x74, 0x61,
-0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x42, 0x61, 0x6e, 0x67, 0x6c, 0x61, 0x64, 0x65, 0x73,
-0x68, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x42, 0x65, 0x6c, 0x61,
-0x72, 0x75, 0x73, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x42, 0x6f,
-0x75, 0x67, 0x61, 0x69, 0x6e, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20,
-0x54, 0x69, 0x6d, 0x65, 0x0, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x20, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20,
-0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x43, 0x61, 0x70, 0x65, 0x20, 0x56,
-0x65, 0x72, 0x64, 0x65, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x43,
-0x61, 0x75, 0x63, 0x61, 0x73, 0x75, 0x73, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d,
-0x65, 0x0, 0x43, 0x65, 0x6e, 0x2e, 0x20, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x20, 0x53, 0x74, 0x61,
-0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x41,
-0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65,
-0x0, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x41, 0x73, 0x69, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61,
-0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x42, 0x72, 0x61, 0x7a,
-0x69, 0x6c, 0x69, 0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0,
-0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64,
-0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x45, 0x75, 0x72,
-0x6f, 0x70, 0x65, 0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0,
-0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x20, 0x53, 0x74, 0x61, 0x6e,
-0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x53, 0x74,
-0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x20, 0x28, 0x4d, 0x65, 0x78, 0x69, 0x63, 0x6f, 0x29,
-0x0, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69,
-0x6d, 0x65, 0x0, 0x43, 0x68, 0x69, 0x6e, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69,
-0x6d, 0x65, 0x0, 0x43, 0x68, 0x61, 0x74, 0x68, 0x61, 0x6d, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x53,
-0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x43, 0x75, 0x62, 0x61, 0x20, 0x53, 0x74,
-0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x44, 0x61, 0x74, 0x65, 0x6c, 0x69, 0x6e, 0x65,
-0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x45, 0x2e, 0x20, 0x41, 0x66,
-0x72, 0x69, 0x63, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x45,
-0x2e, 0x20, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64,
-0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x45, 0x2e, 0x20, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x20, 0x53, 0x74, 0x61, 0x6e,
-0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x45, 0x2e, 0x20, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x41,
-0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65,
-0x0, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64,
-0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x53, 0x74, 0x61,
-0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x53,
-0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x20, 0x28, 0x4d, 0x65, 0x78, 0x69, 0x63, 0x6f,
-0x29, 0x0, 0x45, 0x67, 0x79, 0x70, 0x74, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d,
-0x65, 0x0, 0x45, 0x6b, 0x61, 0x74, 0x65, 0x72, 0x69, 0x6e, 0x62, 0x75, 0x72, 0x67, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64,
-0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x46, 0x69, 0x6a, 0x69, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61,
-0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x46, 0x4c, 0x45, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64,
-0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x47, 0x65, 0x6f, 0x72, 0x67, 0x69, 0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64,
-0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x47, 0x4d, 0x54, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72,
-0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x47, 0x72, 0x65, 0x65, 0x6e, 0x6c, 0x61, 0x6e, 0x64, 0x20, 0x53, 0x74, 0x61,
-0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x47, 0x72, 0x65, 0x65, 0x6e, 0x77, 0x69, 0x63, 0x68,
-0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x47, 0x54, 0x42, 0x20, 0x53,
-0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x48, 0x61, 0x69, 0x74, 0x69, 0x20, 0x53,
-0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x48, 0x61, 0x77, 0x61, 0x69, 0x69, 0x61,
-0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x49, 0x6e, 0x64, 0x69,
-0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x49, 0x72, 0x61, 0x6e,
-0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x49, 0x73, 0x72, 0x61, 0x65,
-0x6c, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4a, 0x6f, 0x72, 0x64,
-0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4b, 0x61, 0x6c,
-0x69, 0x6e, 0x69, 0x6e, 0x67, 0x72, 0x61, 0x64, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69,
-0x6d, 0x65, 0x0, 0x4b, 0x6f, 0x72, 0x65, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69,
-0x6d, 0x65, 0x0, 0x4c, 0x69, 0x62, 0x79, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69,
-0x6d, 0x65, 0x0, 0x4c, 0x69, 0x6e, 0x65, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x53, 0x74, 0x61, 0x6e,
-0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4c, 0x6f, 0x72, 0x64, 0x20, 0x48, 0x6f, 0x77, 0x65, 0x20,
-0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4d, 0x61, 0x67, 0x61, 0x64, 0x61,
-0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4d, 0x61, 0x67, 0x61,
-0x6c, 0x6c, 0x61, 0x6e, 0x65, 0x73, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65,
-0x0, 0x4d, 0x61, 0x72, 0x71, 0x75, 0x65, 0x73, 0x61, 0x73, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20,
-0x54, 0x69, 0x6d, 0x65, 0x0, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x69, 0x75, 0x73, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64,
-0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x20, 0x45, 0x61, 0x73, 0x74,
-0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4d, 0x6f, 0x6e, 0x74, 0x65,
-0x76, 0x69, 0x64, 0x65, 0x6f, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0,
-0x4d, 0x6f, 0x72, 0x6f, 0x63, 0x63, 0x6f, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d,
-0x65, 0x0, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20,
-0x54, 0x69, 0x6d, 0x65, 0x20, 0x28, 0x4d, 0x65, 0x78, 0x69, 0x63, 0x6f, 0x29, 0x0, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61,
-0x69, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4d, 0x79, 0x61,
-0x6e, 0x6d, 0x61, 0x72, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4e,
-0x2e, 0x20, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x41, 0x73, 0x69, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64,
-0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4e, 0x61, 0x6d, 0x69, 0x62, 0x69, 0x61, 0x20, 0x53, 0x74, 0x61,
-0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4e, 0x65, 0x70, 0x61, 0x6c, 0x20, 0x53, 0x74, 0x61,
-0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4e, 0x65, 0x77, 0x20, 0x5a, 0x65, 0x61, 0x6c, 0x61,
-0x6e, 0x64, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4e, 0x65, 0x77,
-0x66, 0x6f, 0x75, 0x6e, 0x64, 0x6c, 0x61, 0x6e, 0x64, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54,
-0x69, 0x6d, 0x65, 0x0, 0x4e, 0x6f, 0x72, 0x66, 0x6f, 0x6c, 0x6b, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64,
-0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x20, 0x41, 0x73, 0x69, 0x61, 0x20, 0x45, 0x61, 0x73,
-0x74, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4e, 0x6f, 0x72, 0x74,
-0x68, 0x20, 0x41, 0x73, 0x69, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65,
-0x0, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x20, 0x4b, 0x6f, 0x72, 0x65, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72,
-0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4f, 0x6d, 0x73, 0x6b, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64,
-0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x20, 0x53, 0x41, 0x20, 0x53, 0x74, 0x61,
-0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x20, 0x53,
-0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
-0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x20, 0x28, 0x4d, 0x65, 0x78, 0x69,
-0x63, 0x6f, 0x29, 0x0, 0x50, 0x61, 0x6b, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72,
-0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x50, 0x61, 0x72, 0x61, 0x67, 0x75, 0x61, 0x79, 0x20, 0x53, 0x74, 0x61, 0x6e,
-0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x51, 0x79, 0x7a, 0x79, 0x6c, 0x6f, 0x72, 0x64, 0x61, 0x20,
-0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x52, 0x6f, 0x6d, 0x61, 0x6e, 0x63,
-0x65, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x52, 0x75, 0x73, 0x73,
-0x69, 0x61, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x20, 0x5a, 0x6f, 0x6e, 0x65, 0x20, 0x33, 0x0, 0x52, 0x75, 0x73, 0x73, 0x69,
-0x61, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x20, 0x5a, 0x6f, 0x6e, 0x65, 0x20, 0x31, 0x30, 0x0, 0x52, 0x75, 0x73, 0x73, 0x69,
-0x61, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x20, 0x5a, 0x6f, 0x6e, 0x65, 0x20, 0x31, 0x31, 0x0, 0x52, 0x75, 0x73, 0x73, 0x69,
-0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x41, 0x20,
-0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d,
-0x65, 0x0, 0x53, 0x41, 0x20, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72,
-0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x41, 0x20, 0x57, 0x65, 0x73, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x53, 0x74,
-0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x61, 0x69, 0x6e, 0x74, 0x20, 0x50, 0x69,
-0x65, 0x72, 0x72, 0x65, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53,
-0x61, 0x6b, 0x68, 0x61, 0x6c, 0x69, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d,
-0x65, 0x0, 0x53, 0x61, 0x6d, 0x6f, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d,
-0x65, 0x0, 0x53, 0x61, 0x6f, 0x20, 0x54, 0x6f, 0x6d, 0x65, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20,
-0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x76, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72,
-0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x45, 0x20, 0x41, 0x73, 0x69, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64,
-0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x69, 0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, 0x20, 0x53,
-0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x41,
-0x66, 0x72, 0x69, 0x63, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0,
-0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x53, 0x75, 0x64, 0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64,
-0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x72, 0x69, 0x20, 0x4c, 0x61, 0x6e, 0x6b, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e,
-0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x75, 0x64, 0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e,
-0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x79, 0x72, 0x69, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e,
-0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x54, 0x61, 0x69, 0x70, 0x65, 0x69, 0x20, 0x53, 0x74, 0x61,
-0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x54, 0x61, 0x73, 0x6d, 0x61, 0x6e, 0x69, 0x61, 0x20,
-0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x54, 0x6f, 0x63, 0x61, 0x6e, 0x74,
-0x69, 0x6e, 0x73, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x54, 0x6f,
-0x6b, 0x79, 0x6f, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x54, 0x6f,
-0x6d, 0x73, 0x6b, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x54, 0x6f,
-0x6e, 0x67, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x54, 0x72,
-0x61, 0x6e, 0x73, 0x62, 0x61, 0x69, 0x6b, 0x61, 0x6c, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54,
-0x69, 0x6d, 0x65, 0x0, 0x54, 0x75, 0x72, 0x6b, 0x65, 0x79, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20,
-0x54, 0x69, 0x6d, 0x65, 0x0, 0x54, 0x75, 0x72, 0x6b, 0x73, 0x20, 0x41, 0x6e, 0x64, 0x20, 0x43, 0x61, 0x69, 0x63, 0x6f,
-0x73, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x55, 0x6c, 0x61, 0x61,
-0x6e, 0x62, 0x61, 0x61, 0x74, 0x61, 0x72, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d,
-0x65, 0x0, 0x55, 0x53, 0x20, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72,
-0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x55, 0x53, 0x20, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x53,
-0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x31, 0x31, 0x0,
-0x55, 0x54, 0x43, 0x2d, 0x30, 0x39, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x30, 0x38, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x30, 0x32,
-0x0, 0x55, 0x54, 0x43, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x31, 0x32, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x31, 0x33, 0x0, 0x56,
-0x65, 0x6e, 0x65, 0x7a, 0x75, 0x65, 0x6c, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69,
-0x6d, 0x65, 0x0, 0x56, 0x6c, 0x61, 0x64, 0x69, 0x76, 0x6f, 0x73, 0x74, 0x6f, 0x6b, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64,
-0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x56, 0x6f, 0x6c, 0x67, 0x6f, 0x67, 0x72, 0x61, 0x64, 0x20, 0x53,
-0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x57, 0x2e, 0x20, 0x41, 0x75, 0x73, 0x74,
-0x72, 0x61, 0x6c, 0x69, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0,
-0x57, 0x2e, 0x20, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x20, 0x53, 0x74,
-0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x57, 0x2e, 0x20, 0x45, 0x75, 0x72, 0x6f, 0x70,
-0x65, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x57, 0x2e, 0x20, 0x4d,
-0x6f, 0x6e, 0x67, 0x6f, 0x6c, 0x69, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d,
-0x65, 0x0, 0x57, 0x65, 0x73, 0x74, 0x20, 0x41, 0x73, 0x69, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64,
-0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x57, 0x65, 0x73, 0x74, 0x20, 0x42, 0x61, 0x6e, 0x6b, 0x20, 0x53, 0x74, 0x61, 0x6e,
-0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x57, 0x65, 0x73, 0x74, 0x20, 0x50, 0x61, 0x63, 0x69, 0x66,
-0x69, 0x63, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x59, 0x61, 0x6b,
-0x75, 0x74, 0x73, 0x6b, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x59,
-0x75, 0x6b, 0x6f, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0
+0x41, 0x66, 0x67, 0x68, 0x61, 0x6e, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e,
+0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x41, 0x6c, 0x61, 0x73, 0x6b, 0x61,
+0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0,
+0x41, 0x6c, 0x65, 0x75, 0x74, 0x69, 0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72,
+0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x41, 0x6c, 0x74, 0x61, 0x69, 0x20, 0x53, 0x74, 0x61,
+0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x41, 0x72, 0x61, 0x62, 0x20,
+0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x41, 0x72,
+0x61, 0x62, 0x69, 0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54,
+0x69, 0x6d, 0x65, 0x0, 0x41, 0x72, 0x61, 0x62, 0x69, 0x63, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64,
+0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69,
+0x6e, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65,
+0x0, 0x41, 0x73, 0x74, 0x72, 0x61, 0x6b, 0x68, 0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64,
+0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69,
+0x63, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0,
+0x41, 0x55, 0x53, 0x20, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x53, 0x74, 0x61, 0x6e,
+0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x41, 0x75, 0x73, 0x20, 0x43, 0x65,
+0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x57, 0x2e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72,
+0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x41, 0x55, 0x53, 0x20, 0x45, 0x61, 0x73, 0x74, 0x65,
+0x72, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65,
+0x0, 0x41, 0x7a, 0x65, 0x72, 0x62, 0x61, 0x69, 0x6a, 0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e,
+0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x41, 0x7a, 0x6f, 0x72, 0x65, 0x73,
+0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x42,
+0x61, 0x68, 0x69, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69,
+0x6d, 0x65, 0x0, 0x42, 0x61, 0x6e, 0x67, 0x6c, 0x61, 0x64, 0x65, 0x73, 0x68, 0x20, 0x53, 0x74,
+0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x42, 0x65, 0x6c, 0x61,
+0x72, 0x75, 0x73, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d,
+0x65, 0x0, 0x42, 0x6f, 0x75, 0x67, 0x61, 0x69, 0x6e, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x20, 0x53,
+0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x43, 0x61, 0x6e,
+0x61, 0x64, 0x61, 0x20, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x53, 0x74, 0x61, 0x6e,
+0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x43, 0x61, 0x70, 0x65, 0x20, 0x56,
+0x65, 0x72, 0x64, 0x65, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69,
+0x6d, 0x65, 0x0, 0x43, 0x61, 0x75, 0x63, 0x61, 0x73, 0x75, 0x73, 0x20, 0x53, 0x74, 0x61, 0x6e,
+0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x43, 0x65, 0x6e, 0x2e, 0x20, 0x41,
+0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72,
+0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x41,
+0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20,
+0x54, 0x69, 0x6d, 0x65, 0x0, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x41, 0x73, 0x69,
+0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0,
+0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x42, 0x72, 0x61, 0x7a, 0x69, 0x6c, 0x69, 0x61,
+0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0,
+0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x20, 0x53,
+0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x43, 0x65, 0x6e,
+0x74, 0x72, 0x61, 0x6c, 0x20, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x61, 0x6e, 0x20, 0x53, 0x74,
+0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x43, 0x65, 0x6e, 0x74,
+0x72, 0x61, 0x6c, 0x20, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x20, 0x53, 0x74, 0x61, 0x6e,
+0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x43, 0x65, 0x6e, 0x74, 0x72, 0x61,
+0x6c, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0,
+0x43, 0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64,
+0x20, 0x54, 0x69, 0x6d, 0x65, 0x20, 0x28, 0x4d, 0x65, 0x78, 0x69, 0x63, 0x6f, 0x29, 0x0, 0x43,
+0x68, 0x61, 0x74, 0x68, 0x61, 0x6d, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x20, 0x53,
+0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x43, 0x68, 0x69,
+0x6e, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65,
+0x0, 0x43, 0x75, 0x62, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54,
+0x69, 0x6d, 0x65, 0x0, 0x44, 0x61, 0x74, 0x65, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x53, 0x74, 0x61,
+0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x45, 0x2e, 0x20, 0x41, 0x66,
+0x72, 0x69, 0x63, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69,
+0x6d, 0x65, 0x0, 0x45, 0x2e, 0x20, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x20,
+0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x45, 0x2e,
+0x20, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64,
+0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x45, 0x2e, 0x20, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x41,
+0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20,
+0x54, 0x69, 0x6d, 0x65, 0x0, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x49, 0x73, 0x6c, 0x61,
+0x6e, 0x64, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65,
+0x0, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72,
+0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x53,
+0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x20, 0x28, 0x4d, 0x65,
+0x78, 0x69, 0x63, 0x6f, 0x29, 0x0, 0x45, 0x67, 0x79, 0x70, 0x74, 0x20, 0x53, 0x74, 0x61, 0x6e,
+0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x45, 0x6b, 0x61, 0x74, 0x65, 0x72,
+0x69, 0x6e, 0x62, 0x75, 0x72, 0x67, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20,
+0x54, 0x69, 0x6d, 0x65, 0x0, 0x46, 0x69, 0x6a, 0x69, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61,
+0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x46, 0x4c, 0x45, 0x20, 0x53, 0x74, 0x61, 0x6e,
+0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x47, 0x65, 0x6f, 0x72, 0x67, 0x69,
+0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65,
+0x0, 0x47, 0x4d, 0x54, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69,
+0x6d, 0x65, 0x0, 0x47, 0x72, 0x65, 0x65, 0x6e, 0x6c, 0x61, 0x6e, 0x64, 0x20, 0x53, 0x74, 0x61,
+0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x47, 0x72, 0x65, 0x65, 0x6e,
+0x77, 0x69, 0x63, 0x68, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69,
+0x6d, 0x65, 0x0, 0x47, 0x54, 0x42, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20,
+0x54, 0x69, 0x6d, 0x65, 0x0, 0x48, 0x61, 0x69, 0x74, 0x69, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64,
+0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x48, 0x61, 0x77, 0x61, 0x69, 0x69, 0x61,
+0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0,
+0x49, 0x6e, 0x64, 0x69, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54,
+0x69, 0x6d, 0x65, 0x0, 0x49, 0x72, 0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72,
+0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x49, 0x73, 0x72, 0x61, 0x65, 0x6c, 0x20, 0x53, 0x74,
+0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4a, 0x6f, 0x72, 0x64,
+0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65,
+0x0, 0x4b, 0x61, 0x6c, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x72, 0x61, 0x64, 0x20, 0x53, 0x74, 0x61,
+0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4b, 0x6f, 0x72, 0x65, 0x61,
+0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4c,
+0x69, 0x62, 0x79, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69,
+0x6d, 0x65, 0x0, 0x4c, 0x69, 0x6e, 0x65, 0x20, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x73, 0x20,
+0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4c, 0x6f,
+0x72, 0x64, 0x20, 0x48, 0x6f, 0x77, 0x65, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64,
+0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4d, 0x61, 0x67, 0x61, 0x64, 0x61, 0x6e, 0x20, 0x53, 0x74,
+0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4d, 0x61, 0x67, 0x61,
+0x6c, 0x6c, 0x61, 0x6e, 0x65, 0x73, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20,
+0x54, 0x69, 0x6d, 0x65, 0x0, 0x4d, 0x61, 0x72, 0x71, 0x75, 0x65, 0x73, 0x61, 0x73, 0x20, 0x53,
+0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4d, 0x61, 0x75,
+0x72, 0x69, 0x74, 0x69, 0x75, 0x73, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20,
+0x54, 0x69, 0x6d, 0x65, 0x0, 0x4d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x20, 0x45, 0x61, 0x73, 0x74,
+0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4d,
+0x6f, 0x6e, 0x74, 0x65, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61,
+0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4d, 0x6f, 0x72, 0x6f, 0x63, 0x63, 0x6f, 0x20,
+0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4d, 0x6f,
+0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20,
+0x54, 0x69, 0x6d, 0x65, 0x0, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x53, 0x74,
+0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x20, 0x28, 0x4d, 0x65, 0x78,
+0x69, 0x63, 0x6f, 0x29, 0x0, 0x4d, 0x79, 0x61, 0x6e, 0x6d, 0x61, 0x72, 0x20, 0x53, 0x74, 0x61,
+0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4e, 0x2e, 0x20, 0x43, 0x65,
+0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x41, 0x73, 0x69, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64,
+0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4e, 0x61, 0x6d, 0x69, 0x62, 0x69, 0x61,
+0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4e,
+0x65, 0x70, 0x61, 0x6c, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69,
+0x6d, 0x65, 0x0, 0x4e, 0x65, 0x77, 0x20, 0x5a, 0x65, 0x61, 0x6c, 0x61, 0x6e, 0x64, 0x20, 0x53,
+0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4e, 0x65, 0x77,
+0x66, 0x6f, 0x75, 0x6e, 0x64, 0x6c, 0x61, 0x6e, 0x64, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61,
+0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4e, 0x6f, 0x72, 0x66, 0x6f, 0x6c, 0x6b, 0x20,
+0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4e, 0x6f,
+0x72, 0x74, 0x68, 0x20, 0x41, 0x73, 0x69, 0x61, 0x20, 0x45, 0x61, 0x73, 0x74, 0x20, 0x53, 0x74,
+0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4e, 0x6f, 0x72, 0x74,
+0x68, 0x20, 0x41, 0x73, 0x69, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20,
+0x54, 0x69, 0x6d, 0x65, 0x0, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x20, 0x4b, 0x6f, 0x72, 0x65, 0x61,
+0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x4f,
+0x6d, 0x73, 0x6b, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d,
+0x65, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x20, 0x53, 0x41, 0x20, 0x53, 0x74, 0x61,
+0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66,
+0x69, 0x63, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65,
+0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72,
+0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x20, 0x28, 0x4d, 0x65, 0x78, 0x69, 0x63, 0x6f, 0x29, 0x0,
+0x50, 0x61, 0x6b, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72,
+0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x50, 0x61, 0x72, 0x61, 0x67, 0x75, 0x61, 0x79, 0x20,
+0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x51, 0x79,
+0x7a, 0x79, 0x6c, 0x6f, 0x72, 0x64, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64,
+0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x52, 0x6f, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x53, 0x74,
+0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x52, 0x75, 0x73, 0x73,
+0x69, 0x61, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x20, 0x5a, 0x6f, 0x6e, 0x65, 0x20, 0x31, 0x30, 0x0,
+0x52, 0x75, 0x73, 0x73, 0x69, 0x61, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x20, 0x5a, 0x6f, 0x6e, 0x65,
+0x20, 0x31, 0x31, 0x0, 0x52, 0x75, 0x73, 0x73, 0x69, 0x61, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x20,
+0x5a, 0x6f, 0x6e, 0x65, 0x20, 0x33, 0x0, 0x52, 0x75, 0x73, 0x73, 0x69, 0x61, 0x6e, 0x20, 0x53,
+0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x41, 0x20,
+0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64,
+0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x41, 0x20, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
+0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53,
+0x41, 0x20, 0x57, 0x65, 0x73, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61,
+0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x61, 0x69, 0x6e, 0x74, 0x20, 0x50, 0x69,
+0x65, 0x72, 0x72, 0x65, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69,
+0x6d, 0x65, 0x0, 0x53, 0x61, 0x6b, 0x68, 0x61, 0x6c, 0x69, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e,
+0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x61, 0x6d, 0x6f, 0x61, 0x20,
+0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x61,
+0x6f, 0x20, 0x54, 0x6f, 0x6d, 0x65, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20,
+0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x61, 0x72, 0x61, 0x74, 0x6f, 0x76, 0x20, 0x53, 0x74, 0x61,
+0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x45, 0x20, 0x41, 0x73,
+0x69, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65,
+0x0, 0x53, 0x69, 0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64,
+0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x41,
+0x66, 0x72, 0x69, 0x63, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54,
+0x69, 0x6d, 0x65, 0x0, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x20, 0x53, 0x75, 0x64, 0x61, 0x6e, 0x20,
+0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x72,
+0x69, 0x20, 0x4c, 0x61, 0x6e, 0x6b, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64,
+0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x75, 0x64, 0x61, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e,
+0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x53, 0x79, 0x72, 0x69, 0x61, 0x20,
+0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x54, 0x61,
+0x69, 0x70, 0x65, 0x69, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69,
+0x6d, 0x65, 0x0, 0x54, 0x61, 0x73, 0x6d, 0x61, 0x6e, 0x69, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e,
+0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x54, 0x6f, 0x63, 0x61, 0x6e, 0x74,
+0x69, 0x6e, 0x73, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d,
+0x65, 0x0, 0x54, 0x6f, 0x6b, 0x79, 0x6f, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64,
+0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x54, 0x6f, 0x6d, 0x73, 0x6b, 0x20, 0x53, 0x74, 0x61, 0x6e,
+0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x54, 0x6f, 0x6e, 0x67, 0x61, 0x20,
+0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x54, 0x72,
+0x61, 0x6e, 0x73, 0x62, 0x61, 0x69, 0x6b, 0x61, 0x6c, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61,
+0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x54, 0x75, 0x72, 0x6b, 0x65, 0x79, 0x20, 0x53,
+0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x54, 0x75, 0x72,
+0x6b, 0x73, 0x20, 0x41, 0x6e, 0x64, 0x20, 0x43, 0x61, 0x69, 0x63, 0x6f, 0x73, 0x20, 0x53, 0x74,
+0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x55, 0x6c, 0x61, 0x61,
+0x6e, 0x62, 0x61, 0x61, 0x74, 0x61, 0x72, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64,
+0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x55, 0x53, 0x20, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x6e,
+0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x55,
+0x53, 0x20, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64,
+0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x55, 0x54, 0x43, 0x0, 0x55, 0x54, 0x43,
+0x2b, 0x31, 0x32, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x31, 0x33, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x30,
+0x32, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x30, 0x38, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x30, 0x39, 0x0,
+0x55, 0x54, 0x43, 0x2d, 0x31, 0x31, 0x0, 0x56, 0x65, 0x6e, 0x65, 0x7a, 0x75, 0x65, 0x6c, 0x61,
+0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x56,
+0x6c, 0x61, 0x64, 0x69, 0x76, 0x6f, 0x73, 0x74, 0x6f, 0x6b, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64,
+0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x56, 0x6f, 0x6c, 0x67, 0x6f, 0x67, 0x72,
+0x61, 0x64, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65,
+0x0, 0x57, 0x2e, 0x20, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x20, 0x53, 0x74,
+0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x57, 0x2e, 0x20, 0x43,
+0x65, 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x20, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x20, 0x53, 0x74,
+0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x57, 0x2e, 0x20, 0x45,
+0x75, 0x72, 0x6f, 0x70, 0x65, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54,
+0x69, 0x6d, 0x65, 0x0, 0x57, 0x2e, 0x20, 0x4d, 0x6f, 0x6e, 0x67, 0x6f, 0x6c, 0x69, 0x61, 0x20,
+0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x57, 0x65,
+0x73, 0x74, 0x20, 0x41, 0x73, 0x69, 0x61, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64,
+0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x57, 0x65, 0x73, 0x74, 0x20, 0x42, 0x61, 0x6e, 0x6b, 0x20,
+0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x57, 0x65,
+0x73, 0x74, 0x20, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64,
+0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x59, 0x61, 0x6b, 0x75, 0x74, 0x73, 0x6b,
+0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x0, 0x59,
+0x75, 0x6b, 0x6f, 0x6e, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69,
+0x6d, 0x65, 0x0
};
static constexpr char ianaIdData[] = {
-0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x62, 0x75, 0x6c, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41,
-0x6e, 0x63, 0x68, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a, 0x75, 0x6e,
-0x65, 0x61, 0x75, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x65, 0x74, 0x6c, 0x61, 0x6b, 0x61, 0x74,
-0x6c, 0x61, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x6d, 0x65, 0x20, 0x41, 0x6d, 0x65, 0x72,
-0x69, 0x63, 0x61, 0x2f, 0x53, 0x69, 0x74, 0x6b, 0x61, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x59, 0x61,
-0x6b, 0x75, 0x74, 0x61, 0x74, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x64, 0x61, 0x6b, 0x0, 0x41,
-0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x72, 0x6e, 0x61, 0x75, 0x6c, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x68,
-0x72, 0x61, 0x69, 0x6e, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x75, 0x77, 0x61, 0x69, 0x74, 0x0, 0x41, 0x73, 0x69,
-0x61, 0x2f, 0x51, 0x61, 0x74, 0x61, 0x72, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x52, 0x69, 0x79, 0x61, 0x64, 0x68, 0x0,
-0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x64, 0x65, 0x6e, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x34, 0x0,
-0x41, 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x75, 0x73, 0x63, 0x61, 0x74, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x75, 0x62,
-0x61, 0x69, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x67, 0x68, 0x64, 0x61, 0x64, 0x0, 0x41, 0x6d, 0x65, 0x72,
-0x69, 0x63, 0x61, 0x2f, 0x42, 0x75, 0x65, 0x6e, 0x6f, 0x73, 0x5f, 0x41, 0x69, 0x72, 0x65, 0x73, 0x20, 0x41, 0x6d, 0x65,
-0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x4c, 0x61, 0x5f, 0x52, 0x69,
-0x6f, 0x6a, 0x61, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e,
-0x61, 0x2f, 0x52, 0x69, 0x6f, 0x5f, 0x47, 0x61, 0x6c, 0x6c, 0x65, 0x67, 0x6f, 0x73, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69,
-0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x53, 0x61, 0x6c, 0x74, 0x61, 0x20, 0x41,
-0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x53, 0x61, 0x6e,
-0x5f, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74,
-0x69, 0x6e, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x5f, 0x4c, 0x75, 0x69, 0x73, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
-0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x54, 0x75, 0x63, 0x75, 0x6d, 0x61, 0x6e, 0x20, 0x41,
-0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x55, 0x73, 0x68,
-0x75, 0x61, 0x69, 0x61, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x74, 0x61, 0x6d, 0x61, 0x72,
-0x63, 0x61, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x6f, 0x72, 0x64, 0x6f, 0x62, 0x61, 0x20, 0x41,
-0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a, 0x75, 0x6a, 0x75, 0x79, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
-0x2f, 0x4d, 0x65, 0x6e, 0x64, 0x6f, 0x7a, 0x61, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x41, 0x73, 0x74, 0x72,
-0x61, 0x6b, 0x68, 0x61, 0x6e, 0x20, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x55, 0x6c, 0x79, 0x61, 0x6e, 0x6f, 0x76,
-0x73, 0x6b, 0x0, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x42, 0x65, 0x72, 0x6d, 0x75, 0x64, 0x61, 0x0,
-0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x48, 0x61, 0x6c, 0x69, 0x66, 0x61, 0x78, 0x20, 0x41, 0x6d, 0x65, 0x72,
-0x69, 0x63, 0x61, 0x2f, 0x47, 0x6c, 0x61, 0x63, 0x65, 0x5f, 0x42, 0x61, 0x79, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
-0x61, 0x2f, 0x47, 0x6f, 0x6f, 0x73, 0x65, 0x5f, 0x42, 0x61, 0x79, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
-0x4d, 0x6f, 0x6e, 0x63, 0x74, 0x6f, 0x6e, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x68, 0x75, 0x6c,
-0x65, 0x0, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x44, 0x61, 0x72, 0x77, 0x69, 0x6e, 0x0, 0x41,
-0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x45, 0x75, 0x63, 0x6c, 0x61, 0x0, 0x41, 0x75, 0x73, 0x74, 0x72,
-0x61, 0x6c, 0x69, 0x61, 0x2f, 0x53, 0x79, 0x64, 0x6e, 0x65, 0x79, 0x20, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69,
-0x61, 0x2f, 0x4d, 0x65, 0x6c, 0x62, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x6b,
-0x75, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x62, 0x79, 0x73, 0x75,
-0x6e, 0x64, 0x0, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x41, 0x7a, 0x6f, 0x72, 0x65, 0x73, 0x0, 0x41,
-0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x68, 0x69, 0x61, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x68,
-0x61, 0x6b, 0x61, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x68, 0x69, 0x6d, 0x70, 0x68, 0x75, 0x0, 0x45, 0x75, 0x72,
-0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x69, 0x6e, 0x73, 0x6b, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x42, 0x6f,
-0x75, 0x67, 0x61, 0x69, 0x6e, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52,
-0x65, 0x67, 0x69, 0x6e, 0x61, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x77, 0x69, 0x66, 0x74, 0x5f,
-0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x31, 0x0, 0x41, 0x74,
-0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x43, 0x61, 0x70, 0x65, 0x5f, 0x56, 0x65, 0x72, 0x64, 0x65, 0x0, 0x41, 0x73,
-0x69, 0x61, 0x2f, 0x59, 0x65, 0x72, 0x65, 0x76, 0x61, 0x6e, 0x0, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61,
-0x2f, 0x41, 0x64, 0x65, 0x6c, 0x61, 0x69, 0x64, 0x65, 0x20, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f,
-0x42, 0x72, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x48, 0x69, 0x6c, 0x6c, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b,
-0x36, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x65, 0x6c, 0x69, 0x7a, 0x65, 0x0, 0x41, 0x6d, 0x65,
-0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x6f, 0x73, 0x74, 0x61, 0x5f, 0x52, 0x69, 0x63, 0x61, 0x0, 0x50, 0x61, 0x63, 0x69,
-0x66, 0x69, 0x63, 0x2f, 0x47, 0x61, 0x6c, 0x61, 0x70, 0x61, 0x67, 0x6f, 0x73, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
-0x61, 0x2f, 0x45, 0x6c, 0x5f, 0x53, 0x61, 0x6c, 0x76, 0x61, 0x64, 0x6f, 0x72, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
-0x61, 0x2f, 0x47, 0x75, 0x61, 0x74, 0x65, 0x6d, 0x61, 0x6c, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
-0x54, 0x65, 0x67, 0x75, 0x63, 0x69, 0x67, 0x61, 0x6c, 0x70, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
-0x4d, 0x61, 0x6e, 0x61, 0x67, 0x75, 0x61, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x36, 0x0, 0x41, 0x6e,
-0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x56, 0x6f, 0x73, 0x74, 0x6f, 0x6b, 0x0, 0x49, 0x6e, 0x64, 0x69,
-0x61, 0x6e, 0x2f, 0x43, 0x68, 0x61, 0x67, 0x6f, 0x73, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x55, 0x72, 0x75, 0x6d, 0x71,
-0x69, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x6c, 0x6d, 0x61, 0x74, 0x79, 0x20, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x51,
-0x6f, 0x73, 0x74, 0x61, 0x6e, 0x61, 0x79, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x69, 0x73, 0x68, 0x6b, 0x65, 0x6b,
-0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x75, 0x69, 0x61, 0x62, 0x61, 0x20, 0x41, 0x6d, 0x65, 0x72,
-0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x6d, 0x70, 0x6f, 0x5f, 0x47, 0x72, 0x61, 0x6e, 0x64, 0x65, 0x0, 0x45, 0x75, 0x72,
-0x6f, 0x70, 0x65, 0x2f, 0x54, 0x69, 0x72, 0x61, 0x6e, 0x65, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x50, 0x72,
-0x61, 0x67, 0x75, 0x65, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x75, 0x64, 0x61, 0x70, 0x65, 0x73, 0x74,
-0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x50, 0x6f, 0x64, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x0, 0x45, 0x75,
-0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x65, 0x6c, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
-0x2f, 0x42, 0x72, 0x61, 0x74, 0x69, 0x73, 0x6c, 0x61, 0x76, 0x61, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c,
-0x6a, 0x75, 0x62, 0x6c, 0x6a, 0x61, 0x6e, 0x61, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x72, 0x61,
-0x6a, 0x65, 0x76, 0x6f, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x5a, 0x61, 0x67, 0x72, 0x65, 0x62, 0x0, 0x45,
-0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x6b, 0x6f, 0x70, 0x6a, 0x65, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
-0x57, 0x61, 0x72, 0x73, 0x61, 0x77, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x31, 0x0, 0x41, 0x6e,
-0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x73, 0x65, 0x79, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66,
-0x69, 0x63, 0x2f, 0x50, 0x6f, 0x6e, 0x61, 0x70, 0x65, 0x20, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4b, 0x6f,
-0x73, 0x72, 0x61, 0x65, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4e, 0x6f, 0x75, 0x6d, 0x65, 0x61, 0x0,
-0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x47, 0x75, 0x61, 0x64, 0x61, 0x6c, 0x63, 0x61, 0x6e, 0x61, 0x6c, 0x0,
-0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x45, 0x66, 0x61, 0x74, 0x65, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
-0x61, 0x2f, 0x4d, 0x65, 0x78, 0x69, 0x63, 0x6f, 0x5f, 0x43, 0x69, 0x74, 0x79, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
-0x61, 0x2f, 0x42, 0x61, 0x68, 0x69, 0x61, 0x5f, 0x42, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x61, 0x73, 0x20, 0x41, 0x6d, 0x65,
-0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x65, 0x72, 0x69, 0x64, 0x61, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
-0x4d, 0x6f, 0x6e, 0x74, 0x65, 0x72, 0x72, 0x65, 0x79, 0x0, 0x43, 0x53, 0x54, 0x36, 0x43, 0x44, 0x54, 0x0, 0x41, 0x6d,
-0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x57, 0x69, 0x6e, 0x6e, 0x69, 0x70, 0x65, 0x67, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69,
-0x63, 0x61, 0x2f, 0x52, 0x61, 0x69, 0x6e, 0x79, 0x5f, 0x52, 0x69, 0x76, 0x65, 0x72, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69,
-0x63, 0x61, 0x2f, 0x52, 0x61, 0x6e, 0x6b, 0x69, 0x6e, 0x5f, 0x49, 0x6e, 0x6c, 0x65, 0x74, 0x20, 0x41, 0x6d, 0x65, 0x72,
-0x69, 0x63, 0x61, 0x2f, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
-0x2f, 0x4d, 0x61, 0x74, 0x61, 0x6d, 0x6f, 0x72, 0x6f, 0x73, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43,
-0x68, 0x69, 0x63, 0x61, 0x67, 0x6f, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61,
-0x6e, 0x61, 0x2f, 0x4b, 0x6e, 0x6f, 0x78, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69,
-0x61, 0x6e, 0x61, 0x2f, 0x54, 0x65, 0x6c, 0x6c, 0x5f, 0x43, 0x69, 0x74, 0x79, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
-0x61, 0x2f, 0x4d, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x6e, 0x65, 0x65, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
-0x4e, 0x6f, 0x72, 0x74, 0x68, 0x5f, 0x44, 0x61, 0x6b, 0x6f, 0x74, 0x61, 0x2f, 0x42, 0x65, 0x75, 0x6c, 0x61, 0x68, 0x20,
-0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x5f, 0x44, 0x61, 0x6b, 0x6f, 0x74, 0x61,
-0x2f, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x72, 0x74,
-0x68, 0x5f, 0x44, 0x61, 0x6b, 0x6f, 0x74, 0x61, 0x2f, 0x4e, 0x65, 0x77, 0x5f, 0x53, 0x61, 0x6c, 0x65, 0x6d, 0x0, 0x41,
-0x73, 0x69, 0x61, 0x2f, 0x53, 0x68, 0x61, 0x6e, 0x67, 0x68, 0x61, 0x69, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x48, 0x6f,
-0x6e, 0x67, 0x5f, 0x4b, 0x6f, 0x6e, 0x67, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x61, 0x63, 0x61, 0x75, 0x0, 0x50,
-0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x43, 0x68, 0x61, 0x74, 0x68, 0x61, 0x6d, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69,
-0x63, 0x61, 0x2f, 0x48, 0x61, 0x76, 0x61, 0x6e, 0x61, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x31, 0x32,
-0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x33, 0x0, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63,
-0x61, 0x2f, 0x53, 0x79, 0x6f, 0x77, 0x61, 0x0, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x43, 0x6f, 0x6d, 0x6f, 0x72,
-0x6f, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x6a, 0x69, 0x62, 0x6f, 0x75, 0x74, 0x69, 0x0, 0x41, 0x66,
-0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x73, 0x6d, 0x65, 0x72, 0x61, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41,
-0x64, 0x64, 0x69, 0x73, 0x5f, 0x41, 0x62, 0x61, 0x62, 0x61, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x61,
-0x69, 0x72, 0x6f, 0x62, 0x69, 0x0, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x41, 0x6e, 0x74, 0x61, 0x6e, 0x61, 0x6e,
-0x61, 0x72, 0x69, 0x76, 0x6f, 0x0, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x79, 0x6f, 0x74, 0x74, 0x65,
-0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x67, 0x61, 0x64, 0x69, 0x73, 0x68, 0x75, 0x0, 0x41, 0x66,
-0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x72, 0x5f, 0x65, 0x73, 0x5f, 0x53, 0x61, 0x6c, 0x61, 0x61, 0x6d, 0x0, 0x41,
-0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x61, 0x6d, 0x70, 0x61, 0x6c, 0x61, 0x0, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61,
-0x6c, 0x69, 0x61, 0x2f, 0x42, 0x72, 0x69, 0x73, 0x62, 0x61, 0x6e, 0x65, 0x20, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c,
-0x69, 0x61, 0x2f, 0x4c, 0x69, 0x6e, 0x64, 0x65, 0x6d, 0x61, 0x6e, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x43,
-0x68, 0x69, 0x73, 0x69, 0x6e, 0x61, 0x75, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6f, 0x5f,
-0x50, 0x61, 0x75, 0x6c, 0x6f, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72,
-0x0, 0x45, 0x53, 0x54, 0x35, 0x45, 0x44, 0x54, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x61, 0x73,
-0x73, 0x61, 0x75, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x6f, 0x72, 0x6f, 0x6e, 0x74, 0x6f, 0x20,
-0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x71, 0x61, 0x6c, 0x75, 0x69, 0x74, 0x20, 0x41, 0x6d, 0x65, 0x72,
-0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x74, 0x72, 0x65, 0x61, 0x6c, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
-0x2f, 0x4e, 0x69, 0x70, 0x69, 0x67, 0x6f, 0x6e, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x61, 0x6e,
-0x67, 0x6e, 0x69, 0x72, 0x74, 0x75, 0x6e, 0x67, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x68, 0x75,
-0x6e, 0x64, 0x65, 0x72, 0x5f, 0x42, 0x61, 0x79, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x65, 0x77,
-0x5f, 0x59, 0x6f, 0x72, 0x6b, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x65, 0x74, 0x72, 0x6f, 0x69,
-0x74, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x50, 0x65,
-0x74, 0x65, 0x72, 0x73, 0x62, 0x75, 0x72, 0x67, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64,
-0x69, 0x61, 0x6e, 0x61, 0x2f, 0x56, 0x69, 0x6e, 0x63, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69,
-0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x57, 0x69, 0x6e, 0x61, 0x6d, 0x61, 0x63, 0x20, 0x41,
-0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x65, 0x6e, 0x74, 0x75, 0x63, 0x6b, 0x79, 0x2f, 0x4d, 0x6f, 0x6e, 0x74,
-0x69, 0x63, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x6f, 0x75, 0x69, 0x73,
-0x76, 0x69, 0x6c, 0x6c, 0x65, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x6e, 0x63, 0x75, 0x6e,
-0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x69, 0x72, 0x6f, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x59,
-0x65, 0x6b, 0x61, 0x74, 0x65, 0x72, 0x69, 0x6e, 0x62, 0x75, 0x72, 0x67, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
-0x2f, 0x46, 0x69, 0x6a, 0x69, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x61, 0x72, 0x69, 0x65, 0x68, 0x61,
-0x6d, 0x6e, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x6f, 0x66, 0x69, 0x61, 0x0, 0x45, 0x75, 0x72, 0x6f,
-0x70, 0x65, 0x2f, 0x54, 0x61, 0x6c, 0x6c, 0x69, 0x6e, 0x6e, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x48, 0x65,
-0x6c, 0x73, 0x69, 0x6e, 0x6b, 0x69, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x52, 0x69, 0x67, 0x61, 0x0, 0x45,
-0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x56, 0x69, 0x6c, 0x6e, 0x69, 0x75, 0x73, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
-0x2f, 0x4b, 0x69, 0x65, 0x76, 0x20, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x55, 0x7a, 0x68, 0x67, 0x6f, 0x72, 0x6f,
-0x64, 0x20, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x5a, 0x61, 0x70, 0x6f, 0x72, 0x6f, 0x7a, 0x68, 0x79, 0x65, 0x0,
-0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x62, 0x69, 0x6c, 0x69, 0x73, 0x69, 0x0, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69,
-0x63, 0x2f, 0x46, 0x61, 0x65, 0x72, 0x6f, 0x65, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x47, 0x75, 0x65, 0x72,
-0x6e, 0x73, 0x65, 0x79, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x44, 0x75, 0x62, 0x6c, 0x69, 0x6e, 0x0, 0x45,
-0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x49, 0x73, 0x6c, 0x65, 0x5f, 0x6f, 0x66, 0x5f, 0x4d, 0x61, 0x6e, 0x0, 0x45, 0x75,
-0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4a, 0x65, 0x72, 0x73, 0x65, 0x79, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c,
-0x69, 0x73, 0x62, 0x6f, 0x6e, 0x20, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x4d, 0x61, 0x64, 0x65, 0x69,
-0x72, 0x61, 0x0, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x79, 0x0, 0x45,
-0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x6f, 0x6e, 0x64, 0x6f, 0x6e, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
-0x2f, 0x47, 0x6f, 0x64, 0x74, 0x68, 0x61, 0x62, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4f, 0x75, 0x61, 0x67,
-0x61, 0x64, 0x6f, 0x75, 0x67, 0x6f, 0x75, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x6e, 0x6a, 0x75,
-0x6c, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x63, 0x63, 0x72, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69,
-0x63, 0x61, 0x2f, 0x44, 0x61, 0x6e, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x68, 0x61, 0x76, 0x6e, 0x0, 0x41, 0x66, 0x72, 0x69,
-0x63, 0x61, 0x2f, 0x42, 0x69, 0x73, 0x73, 0x61, 0x75, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x6f, 0x6e,
-0x61, 0x6b, 0x72, 0x79, 0x0, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x52, 0x65, 0x79, 0x6b, 0x6a, 0x61,
-0x76, 0x69, 0x6b, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x62, 0x69, 0x64, 0x6a, 0x61, 0x6e, 0x0, 0x41,
-0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x72, 0x6f, 0x76, 0x69, 0x61, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63,
-0x61, 0x2f, 0x42, 0x61, 0x6d, 0x61, 0x6b, 0x6f, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x75, 0x61,
-0x6b, 0x63, 0x68, 0x6f, 0x74, 0x74, 0x0, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x53, 0x74, 0x5f, 0x48,
-0x65, 0x6c, 0x65, 0x6e, 0x61, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x6b, 0x61, 0x72, 0x0, 0x41,
-0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x46, 0x72, 0x65, 0x65, 0x74, 0x6f, 0x77, 0x6e, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63,
-0x61, 0x2f, 0x4c, 0x6f, 0x6d, 0x65, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4e, 0x69, 0x63, 0x6f, 0x73, 0x69, 0x61, 0x20,
-0x41, 0x73, 0x69, 0x61, 0x2f, 0x46, 0x61, 0x6d, 0x61, 0x67, 0x75, 0x73, 0x74, 0x61, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70,
-0x65, 0x2f, 0x41, 0x74, 0x68, 0x65, 0x6e, 0x73, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x75, 0x63, 0x68,
-0x61, 0x72, 0x65, 0x73, 0x74, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x2d, 0x61,
-0x75, 0x2d, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x65, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x31, 0x30, 0x0,
-0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x52, 0x61, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x67, 0x61, 0x0, 0x50, 0x61,
-0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x54, 0x61, 0x68, 0x69, 0x74, 0x69, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
-0x2f, 0x4a, 0x6f, 0x68, 0x6e, 0x73, 0x74, 0x6f, 0x6e, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x48, 0x6f,
-0x6e, 0x6f, 0x6c, 0x75, 0x6c, 0x75, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x43, 0x61, 0x6c, 0x63, 0x75, 0x74, 0x74, 0x61,
-0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x65, 0x68, 0x72, 0x61, 0x6e, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4a, 0x65,
-0x72, 0x75, 0x73, 0x61, 0x6c, 0x65, 0x6d, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x6d, 0x6d, 0x61, 0x6e, 0x0, 0x45,
-0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4b, 0x61, 0x6c, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x72, 0x61, 0x64, 0x0, 0x41, 0x73,
-0x69, 0x61, 0x2f, 0x53, 0x65, 0x6f, 0x75, 0x6c, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x72, 0x69, 0x70,
-0x6f, 0x6c, 0x69, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x34, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66,
-0x69, 0x63, 0x2f, 0x4b, 0x69, 0x72, 0x69, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x69, 0x0, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61,
-0x6c, 0x69, 0x61, 0x2f, 0x4c, 0x6f, 0x72, 0x64, 0x5f, 0x48, 0x6f, 0x77, 0x65, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4d,
-0x61, 0x67, 0x61, 0x64, 0x61, 0x6e, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x75, 0x6e, 0x74, 0x61,
-0x5f, 0x41, 0x72, 0x65, 0x6e, 0x61, 0x73, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4d, 0x61, 0x72, 0x71,
-0x75, 0x65, 0x73, 0x61, 0x73, 0x0, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x69,
-0x75, 0x73, 0x0, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x52, 0x65, 0x75, 0x6e, 0x69, 0x6f, 0x6e, 0x0, 0x49, 0x6e,
-0x64, 0x69, 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x68, 0x65, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x65, 0x69, 0x72, 0x75,
-0x74, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x74, 0x65, 0x76, 0x69, 0x64, 0x65, 0x6f,
-0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x73, 0x61, 0x62, 0x6c, 0x61, 0x6e, 0x63, 0x61, 0x0, 0x41,
-0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x6c, 0x5f, 0x41, 0x61, 0x69, 0x75, 0x6e, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69,
-0x63, 0x61, 0x2f, 0x43, 0x68, 0x69, 0x68, 0x75, 0x61, 0x68, 0x75, 0x61, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
-0x2f, 0x4d, 0x61, 0x7a, 0x61, 0x74, 0x6c, 0x61, 0x6e, 0x0, 0x4d, 0x53, 0x54, 0x37, 0x4d, 0x44, 0x54, 0x0, 0x41, 0x6d,
-0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x64, 0x6d, 0x6f, 0x6e, 0x74, 0x6f, 0x6e, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69,
-0x63, 0x61, 0x2f, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x5f, 0x42, 0x61, 0x79, 0x20, 0x41, 0x6d, 0x65,
-0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x75, 0x76, 0x69, 0x6b, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
-0x59, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6b, 0x6e, 0x69, 0x66, 0x65, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
-0x4f, 0x6a, 0x69, 0x6e, 0x61, 0x67, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x65, 0x6e, 0x76,
-0x65, 0x72, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6f, 0x69, 0x73, 0x65, 0x0, 0x49, 0x6e, 0x64,
-0x69, 0x61, 0x6e, 0x2f, 0x43, 0x6f, 0x63, 0x6f, 0x73, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x52, 0x61, 0x6e, 0x67, 0x6f,
-0x6f, 0x6e, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4e, 0x6f, 0x76, 0x6f, 0x73, 0x69, 0x62, 0x69, 0x72, 0x73, 0x6b, 0x0,
-0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x57, 0x69, 0x6e, 0x64, 0x68, 0x6f, 0x65, 0x6b, 0x0, 0x41, 0x73, 0x69, 0x61,
-0x2f, 0x4b, 0x61, 0x74, 0x6d, 0x61, 0x6e, 0x64, 0x75, 0x0, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61,
-0x2f, 0x4d, 0x63, 0x4d, 0x75, 0x72, 0x64, 0x6f, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x41, 0x75, 0x63,
-0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x74, 0x5f, 0x4a, 0x6f, 0x68,
-0x6e, 0x73, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4e, 0x6f, 0x72, 0x66, 0x6f, 0x6c, 0x6b, 0x0, 0x41,
-0x73, 0x69, 0x61, 0x2f, 0x49, 0x72, 0x6b, 0x75, 0x74, 0x73, 0x6b, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x72, 0x61,
-0x73, 0x6e, 0x6f, 0x79, 0x61, 0x72, 0x73, 0x6b, 0x20, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4e, 0x6f, 0x76, 0x6f, 0x6b, 0x75,
-0x7a, 0x6e, 0x65, 0x74, 0x73, 0x6b, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x50, 0x79, 0x6f, 0x6e, 0x67, 0x79, 0x61, 0x6e,
-0x67, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4f, 0x6d, 0x73, 0x6b, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
-0x53, 0x61, 0x6e, 0x74, 0x69, 0x61, 0x67, 0x6f, 0x0, 0x50, 0x53, 0x54, 0x38, 0x50, 0x44, 0x54, 0x0, 0x41, 0x6d, 0x65,
-0x72, 0x69, 0x63, 0x61, 0x2f, 0x56, 0x61, 0x6e, 0x63, 0x6f, 0x75, 0x76, 0x65, 0x72, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69,
-0x63, 0x61, 0x2f, 0x4c, 0x6f, 0x73, 0x5f, 0x41, 0x6e, 0x67, 0x65, 0x6c, 0x65, 0x73, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69,
-0x63, 0x61, 0x2f, 0x54, 0x69, 0x6a, 0x75, 0x61, 0x6e, 0x61, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53,
-0x61, 0x6e, 0x74, 0x61, 0x5f, 0x49, 0x73, 0x61, 0x62, 0x65, 0x6c, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x72,
-0x61, 0x63, 0x68, 0x69, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x73, 0x75, 0x6e, 0x63, 0x69, 0x6f,
-0x6e, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x51, 0x79, 0x7a, 0x79, 0x6c, 0x6f, 0x72, 0x64, 0x61, 0x0, 0x45, 0x75, 0x72,
-0x6f, 0x70, 0x65, 0x2f, 0x42, 0x72, 0x75, 0x73, 0x73, 0x65, 0x6c, 0x73, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
-0x43, 0x6f, 0x70, 0x65, 0x6e, 0x68, 0x61, 0x67, 0x65, 0x6e, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x50, 0x61,
-0x72, 0x69, 0x73, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x61, 0x64, 0x72, 0x69, 0x64, 0x20, 0x41, 0x66,
-0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x65, 0x75, 0x74, 0x61, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61,
-0x6d, 0x61, 0x72, 0x61, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x72, 0x65, 0x64, 0x6e, 0x65, 0x6b, 0x6f, 0x6c, 0x79,
-0x6d, 0x73, 0x6b, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x6d, 0x63, 0x68, 0x61, 0x74, 0x6b, 0x61, 0x20, 0x41,
-0x73, 0x69, 0x61, 0x2f, 0x41, 0x6e, 0x61, 0x64, 0x79, 0x72, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x6f,
-0x73, 0x63, 0x6f, 0x77, 0x20, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4b, 0x69, 0x72, 0x6f, 0x76, 0x0, 0x45, 0x75,
-0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x69, 0x6d, 0x66, 0x65, 0x72, 0x6f, 0x70, 0x6f, 0x6c, 0x0, 0x45, 0x74, 0x63, 0x2f,
-0x47, 0x4d, 0x54, 0x2b, 0x33, 0x0, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x6f, 0x74,
-0x68, 0x65, 0x72, 0x61, 0x20, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x61, 0x6c, 0x6d,
-0x65, 0x72, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x46, 0x6f, 0x72, 0x74, 0x61, 0x6c, 0x65, 0x7a, 0x61,
-0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x65, 0x6c, 0x65, 0x6d, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69,
-0x63, 0x61, 0x2f, 0x4d, 0x61, 0x63, 0x65, 0x69, 0x6f, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x65,
-0x63, 0x69, 0x66, 0x65, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x74, 0x61, 0x72, 0x65,
-0x6d, 0x0, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x53, 0x74, 0x61, 0x6e, 0x6c, 0x65, 0x79, 0x0, 0x41,
-0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x79, 0x65, 0x6e, 0x6e, 0x65, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69,
-0x63, 0x61, 0x2f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x61, 0x72, 0x69, 0x62, 0x6f, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d,
-0x54, 0x2b, 0x35, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x69, 0x6f, 0x5f, 0x42, 0x72, 0x61, 0x6e,
-0x63, 0x6f, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x69, 0x72, 0x75, 0x6e, 0x65, 0x70, 0x65, 0x0,
-0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x6f, 0x72, 0x61, 0x6c, 0x5f, 0x48, 0x61, 0x72, 0x62, 0x6f, 0x75,
-0x72, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x79, 0x6d, 0x61, 0x6e, 0x0, 0x41, 0x6d, 0x65,
-0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6f, 0x67, 0x6f, 0x74, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
-0x47, 0x75, 0x61, 0x79, 0x61, 0x71, 0x75, 0x69, 0x6c, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a, 0x61,
-0x6d, 0x61, 0x69, 0x63, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x61, 0x6e, 0x61, 0x6d, 0x61,
-0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x69, 0x6d, 0x61, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d,
-0x54, 0x2b, 0x34, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x6e, 0x67, 0x75, 0x69, 0x6c, 0x6c, 0x61,
-0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x6e, 0x74, 0x69, 0x67, 0x75, 0x61, 0x0, 0x41, 0x6d, 0x65,
-0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x75, 0x62, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42,
-0x61, 0x72, 0x62, 0x61, 0x64, 0x6f, 0x73, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x61, 0x5f, 0x50,
-0x61, 0x7a, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x6e, 0x61, 0x75, 0x73, 0x20, 0x41, 0x6d,
-0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6f, 0x61, 0x5f, 0x56, 0x69, 0x73, 0x74, 0x61, 0x20, 0x41, 0x6d, 0x65, 0x72,
-0x69, 0x63, 0x61, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x6f, 0x5f, 0x56, 0x65, 0x6c, 0x68, 0x6f, 0x0, 0x41, 0x6d, 0x65, 0x72,
-0x69, 0x63, 0x61, 0x2f, 0x54, 0x6f, 0x72, 0x74, 0x6f, 0x6c, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
-0x42, 0x6c, 0x61, 0x6e, 0x63, 0x2d, 0x53, 0x61, 0x62, 0x6c, 0x6f, 0x6e, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
-0x2f, 0x4b, 0x72, 0x61, 0x6c, 0x65, 0x6e, 0x64, 0x69, 0x6a, 0x6b, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
-0x43, 0x75, 0x72, 0x61, 0x63, 0x61, 0x6f, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x6f, 0x6d, 0x69,
-0x6e, 0x69, 0x63, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x74, 0x6f, 0x5f, 0x44,
-0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x6f, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x72, 0x65, 0x6e, 0x61,
-0x64, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x75, 0x61, 0x64, 0x65, 0x6c, 0x6f, 0x75, 0x70,
-0x65, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x75, 0x79, 0x61, 0x6e, 0x61, 0x0, 0x41, 0x6d, 0x65,
-0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x0, 0x41, 0x6d, 0x65, 0x72,
-0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x72, 0x61, 0x74, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69,
-0x63, 0x61, 0x2f, 0x50, 0x75, 0x65, 0x72, 0x74, 0x6f, 0x5f, 0x52, 0x69, 0x63, 0x6f, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69,
-0x63, 0x61, 0x2f, 0x53, 0x74, 0x5f, 0x42, 0x61, 0x72, 0x74, 0x68, 0x65, 0x6c, 0x65, 0x6d, 0x79, 0x0, 0x41, 0x6d, 0x65,
-0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x74, 0x5f, 0x4b, 0x69, 0x74, 0x74, 0x73, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
-0x61, 0x2f, 0x53, 0x74, 0x5f, 0x4c, 0x75, 0x63, 0x69, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d,
-0x61, 0x72, 0x69, 0x67, 0x6f, 0x74, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x74, 0x5f, 0x56, 0x69,
-0x6e, 0x63, 0x65, 0x6e, 0x74, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x6f, 0x77, 0x65, 0x72, 0x5f,
-0x50, 0x72, 0x69, 0x6e, 0x63, 0x65, 0x73, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x6f, 0x72, 0x74,
-0x5f, 0x6f, 0x66, 0x5f, 0x53, 0x70, 0x61, 0x69, 0x6e, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x74,
-0x5f, 0x54, 0x68, 0x6f, 0x6d, 0x61, 0x73, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x69, 0x71, 0x75,
-0x65, 0x6c, 0x6f, 0x6e, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x61, 0x6b, 0x68, 0x61, 0x6c, 0x69, 0x6e, 0x0, 0x50,
-0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x41, 0x70, 0x69, 0x61, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53,
-0x61, 0x6f, 0x5f, 0x54, 0x6f, 0x6d, 0x65, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x72, 0x61, 0x74,
-0x6f, 0x76, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x37, 0x0, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74,
-0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x76, 0x69, 0x73, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x50, 0x68, 0x6e, 0x6f, 0x6d,
-0x5f, 0x50, 0x65, 0x6e, 0x68, 0x0, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x43, 0x68, 0x72, 0x69, 0x73, 0x74, 0x6d,
-0x61, 0x73, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4a, 0x61, 0x6b, 0x61, 0x72, 0x74, 0x61, 0x20, 0x41, 0x73, 0x69, 0x61,
-0x2f, 0x50, 0x6f, 0x6e, 0x74, 0x69, 0x61, 0x6e, 0x61, 0x6b, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x56, 0x69, 0x65, 0x6e,
-0x74, 0x69, 0x61, 0x6e, 0x65, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x6e, 0x67, 0x6b, 0x6f, 0x6b, 0x0, 0x41,
-0x73, 0x69, 0x61, 0x2f, 0x53, 0x61, 0x69, 0x67, 0x6f, 0x6e, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x38,
-0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x72, 0x75, 0x6e, 0x65, 0x69, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x61,
-0x6b, 0x61, 0x73, 0x73, 0x61, 0x72, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x75, 0x61, 0x6c, 0x61, 0x5f, 0x4c, 0x75,
-0x6d, 0x70, 0x75, 0x72, 0x20, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x75, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x0, 0x41, 0x73,
-0x69, 0x61, 0x2f, 0x4d, 0x61, 0x6e, 0x69, 0x6c, 0x61, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x69, 0x6e, 0x67, 0x61,
-0x70, 0x6f, 0x72, 0x65, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x32, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63,
-0x61, 0x2f, 0x47, 0x61, 0x62, 0x6f, 0x72, 0x6f, 0x6e, 0x65, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x75,
-0x6a, 0x75, 0x6d, 0x62, 0x75, 0x72, 0x61, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x75, 0x62, 0x75, 0x6d,
-0x62, 0x61, 0x73, 0x68, 0x69, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x62, 0x61, 0x62, 0x61, 0x6e, 0x65,
-0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x73, 0x65, 0x72, 0x75, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63,
-0x61, 0x2f, 0x42, 0x6c, 0x61, 0x6e, 0x74, 0x79, 0x72, 0x65, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61,
-0x70, 0x75, 0x74, 0x6f, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x69, 0x67, 0x61, 0x6c, 0x69, 0x0, 0x41,
-0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a, 0x6f, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x73, 0x62, 0x75, 0x72, 0x67, 0x0, 0x41,
-0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x75, 0x73, 0x61, 0x6b, 0x61, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f,
-0x48, 0x61, 0x72, 0x61, 0x72, 0x65, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a, 0x75, 0x62, 0x61, 0x0, 0x41,
-0x73, 0x69, 0x61, 0x2f, 0x43, 0x6f, 0x6c, 0x6f, 0x6d, 0x62, 0x6f, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b,
-0x68, 0x61, 0x72, 0x74, 0x6f, 0x75, 0x6d, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x61, 0x6d, 0x61, 0x73, 0x63, 0x75,
-0x73, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x61, 0x69, 0x70, 0x65, 0x69, 0x0, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61,
-0x6c, 0x69, 0x61, 0x2f, 0x48, 0x6f, 0x62, 0x61, 0x72, 0x74, 0x20, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61,
-0x2f, 0x43, 0x75, 0x72, 0x72, 0x69, 0x65, 0x20, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x4d,
-0x61, 0x63, 0x71, 0x75, 0x61, 0x72, 0x69, 0x65, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x61,
-0x67, 0x75, 0x61, 0x69, 0x6e, 0x61, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x39, 0x0, 0x41, 0x73, 0x69,
-0x61, 0x2f, 0x4a, 0x61, 0x79, 0x61, 0x70, 0x75, 0x72, 0x61, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x6f, 0x6b, 0x79,
-0x6f, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x61, 0x6c, 0x61, 0x75, 0x0, 0x41, 0x73, 0x69, 0x61,
-0x2f, 0x44, 0x69, 0x6c, 0x69, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x6f, 0x6d, 0x73, 0x6b, 0x0, 0x50, 0x61, 0x63,
-0x69, 0x66, 0x69, 0x63, 0x2f, 0x54, 0x6f, 0x6e, 0x67, 0x61, 0x74, 0x61, 0x70, 0x75, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f,
-0x43, 0x68, 0x69, 0x74, 0x61, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x49, 0x73, 0x74, 0x61, 0x6e, 0x62, 0x75,
-0x6c, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x72, 0x61, 0x6e, 0x64, 0x5f, 0x54, 0x75, 0x72, 0x6b,
-0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x55, 0x6c, 0x61, 0x61, 0x6e, 0x62, 0x61, 0x61, 0x74, 0x61, 0x72, 0x20, 0x41, 0x73,
-0x69, 0x61, 0x2f, 0x43, 0x68, 0x6f, 0x69, 0x62, 0x61, 0x6c, 0x73, 0x61, 0x6e, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
-0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x70, 0x6f, 0x6c, 0x69, 0x73, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69,
-0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x4d, 0x61, 0x72, 0x65, 0x6e, 0x67, 0x6f, 0x20, 0x41,
-0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x56, 0x65, 0x76, 0x61, 0x79,
-0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x37, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43,
-0x72, 0x65, 0x73, 0x74, 0x6f, 0x6e, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x77, 0x73, 0x6f,
-0x6e, 0x5f, 0x43, 0x72, 0x65, 0x65, 0x6b, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x46, 0x6f, 0x72, 0x74,
-0x5f, 0x4e, 0x65, 0x6c, 0x73, 0x6f, 0x6e, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x48, 0x65, 0x72, 0x6d,
-0x6f, 0x73, 0x69, 0x6c, 0x6c, 0x6f, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x68, 0x6f, 0x65, 0x6e,
-0x69, 0x78, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x31, 0x31, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69,
-0x63, 0x2f, 0x50, 0x61, 0x67, 0x6f, 0x5f, 0x50, 0x61, 0x67, 0x6f, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f,
-0x4e, 0x69, 0x75, 0x65, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4d, 0x69, 0x64, 0x77, 0x61, 0x79, 0x0,
-0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x39, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x47, 0x61,
-0x6d, 0x62, 0x69, 0x65, 0x72, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x38, 0x0, 0x50, 0x61, 0x63, 0x69,
-0x66, 0x69, 0x63, 0x2f, 0x50, 0x69, 0x74, 0x63, 0x61, 0x69, 0x72, 0x6e, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54,
-0x2b, 0x32, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x72, 0x6f, 0x6e, 0x68, 0x61, 0x0, 0x41,
-0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x5f, 0x47, 0x65, 0x6f, 0x72, 0x67, 0x69,
-0x61, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x55, 0x54, 0x43, 0x20, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x0, 0x45, 0x74,
-0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x32, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x54, 0x61, 0x72,
-0x61, 0x77, 0x61, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4d, 0x61, 0x6a, 0x75, 0x72, 0x6f, 0x20, 0x50,
-0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4b, 0x77, 0x61, 0x6a, 0x61, 0x6c, 0x65, 0x69, 0x6e, 0x0, 0x50, 0x61, 0x63,
-0x69, 0x66, 0x69, 0x63, 0x2f, 0x4e, 0x61, 0x75, 0x72, 0x75, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x46,
-0x75, 0x6e, 0x61, 0x66, 0x75, 0x74, 0x69, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x57, 0x61, 0x6b, 0x65,
-0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x57, 0x61, 0x6c, 0x6c, 0x69, 0x73, 0x0, 0x45, 0x74, 0x63, 0x2f,
-0x47, 0x4d, 0x54, 0x2d, 0x31, 0x33, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x45, 0x6e, 0x64, 0x65, 0x72,
-0x62, 0x75, 0x72, 0x79, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x46, 0x61, 0x6b, 0x61, 0x6f, 0x66, 0x6f,
-0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x72, 0x61, 0x63, 0x61, 0x73, 0x0, 0x41, 0x73, 0x69,
-0x61, 0x2f, 0x56, 0x6c, 0x61, 0x64, 0x69, 0x76, 0x6f, 0x73, 0x74, 0x6f, 0x6b, 0x20, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x55,
-0x73, 0x74, 0x2d, 0x4e, 0x65, 0x72, 0x61, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x56, 0x6f, 0x6c, 0x67, 0x6f,
-0x67, 0x72, 0x61, 0x64, 0x0, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x50, 0x65, 0x72, 0x74, 0x68,
-0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x6c,
-0x67, 0x69, 0x65, 0x72, 0x73, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x75, 0x61, 0x6e, 0x64, 0x61, 0x0,
-0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x6f, 0x2d, 0x4e, 0x6f, 0x76, 0x6f, 0x0, 0x41, 0x66,
-0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x6f, 0x75, 0x61, 0x6c, 0x61, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42,
-0x61, 0x6e, 0x67, 0x75, 0x69, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x64, 0x6a, 0x61, 0x6d, 0x65, 0x6e,
-0x61, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x72, 0x61, 0x7a, 0x7a, 0x61, 0x76, 0x69, 0x6c, 0x6c, 0x65,
-0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x69, 0x6e, 0x73, 0x68, 0x61, 0x73, 0x61, 0x0, 0x41, 0x66, 0x72,
-0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x6c, 0x61, 0x62, 0x6f, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x69,
-0x62, 0x72, 0x65, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x61, 0x67, 0x6f,
-0x73, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x69, 0x61, 0x6d, 0x65, 0x79, 0x0, 0x41, 0x66, 0x72, 0x69,
-0x63, 0x61, 0x2f, 0x54, 0x75, 0x6e, 0x69, 0x73, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x41, 0x6e, 0x64, 0x6f,
-0x72, 0x72, 0x61, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x56, 0x69, 0x65, 0x6e, 0x6e, 0x61, 0x0, 0x45, 0x75,
-0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x20, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42,
-0x75, 0x73, 0x69, 0x6e, 0x67, 0x65, 0x6e, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x47, 0x69, 0x62, 0x72, 0x61,
-0x6c, 0x74, 0x61, 0x72, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x52, 0x6f, 0x6d, 0x65, 0x0, 0x45, 0x75, 0x72,
-0x6f, 0x70, 0x65, 0x2f, 0x56, 0x61, 0x64, 0x75, 0x7a, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x75, 0x78,
-0x65, 0x6d, 0x62, 0x6f, 0x75, 0x72, 0x67, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x61, 0x6c, 0x74, 0x61,
-0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x6f, 0x6e, 0x61, 0x63, 0x6f, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70,
-0x65, 0x2f, 0x41, 0x6d, 0x73, 0x74, 0x65, 0x72, 0x64, 0x61, 0x6d, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4f,
-0x73, 0x6c, 0x6f, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x6e, 0x5f, 0x4d, 0x61, 0x72, 0x69, 0x6e,
-0x6f, 0x0, 0x41, 0x72, 0x63, 0x74, 0x69, 0x63, 0x2f, 0x4c, 0x6f, 0x6e, 0x67, 0x79, 0x65, 0x61, 0x72, 0x62, 0x79, 0x65,
-0x6e, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x74, 0x6f, 0x63, 0x6b, 0x68, 0x6f, 0x6c, 0x6d, 0x0, 0x45,
-0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x5a, 0x75, 0x72, 0x69, 0x63, 0x68, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
-0x56, 0x61, 0x74, 0x69, 0x63, 0x61, 0x6e, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x48, 0x6f, 0x76, 0x64, 0x0, 0x45, 0x74,
-0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x35, 0x0, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x4d,
-0x61, 0x77, 0x73, 0x6f, 0x6e, 0x0, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x4b, 0x65, 0x72, 0x67, 0x75, 0x65, 0x6c,
-0x65, 0x6e, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4f, 0x72, 0x61, 0x6c, 0x20, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x71,
-0x74, 0x61, 0x75, 0x20, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x71, 0x74, 0x6f, 0x62, 0x65, 0x20, 0x41, 0x73, 0x69, 0x61,
-0x2f, 0x41, 0x74, 0x79, 0x72, 0x61, 0x75, 0x0, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x6c, 0x64, 0x69,
-0x76, 0x65, 0x73, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x75, 0x73, 0x68, 0x61, 0x6e, 0x62, 0x65, 0x0, 0x41, 0x73,
-0x69, 0x61, 0x2f, 0x41, 0x73, 0x68, 0x67, 0x61, 0x62, 0x61, 0x74, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x61, 0x73,
-0x68, 0x6b, 0x65, 0x6e, 0x74, 0x20, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x61, 0x6d, 0x61, 0x72, 0x6b, 0x61, 0x6e, 0x64,
-0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x48, 0x65, 0x62, 0x72, 0x6f, 0x6e, 0x20, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x47, 0x61,
-0x7a, 0x61, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x30, 0x0, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63,
-0x74, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x75, 0x6d, 0x6f, 0x6e, 0x74, 0x44, 0x55, 0x72, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x0,
-0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x47, 0x75, 0x61, 0x6d, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
-0x2f, 0x54, 0x72, 0x75, 0x6b, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x53, 0x61, 0x69, 0x70, 0x61, 0x6e,
-0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x5f, 0x4d, 0x6f, 0x72, 0x65, 0x73, 0x62,
-0x79, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x59, 0x61, 0x6b, 0x75, 0x74, 0x73, 0x6b, 0x20, 0x41, 0x73, 0x69, 0x61, 0x2f,
-0x4b, 0x68, 0x61, 0x6e, 0x64, 0x79, 0x67, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x57, 0x68, 0x69,
-0x74, 0x65, 0x68, 0x6f, 0x72, 0x73, 0x65, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x77, 0x73,
-0x6f, 0x6e, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x61, 0x67, 0x65,
-0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x75, 0x65, 0x6e, 0x6f, 0x73, 0x5f, 0x41, 0x69, 0x72, 0x65,
-0x73, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x41, 0x73, 0x74, 0x72, 0x61, 0x6b, 0x68, 0x61, 0x6e, 0x0, 0x41,
-0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x48, 0x61, 0x6c, 0x69, 0x66, 0x61, 0x78, 0x0, 0x41, 0x75, 0x73, 0x74, 0x72,
-0x61, 0x6c, 0x69, 0x61, 0x2f, 0x53, 0x79, 0x64, 0x6e, 0x65, 0x79, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
-0x52, 0x65, 0x67, 0x69, 0x6e, 0x61, 0x0, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x41, 0x64, 0x65,
-0x6c, 0x61, 0x69, 0x64, 0x65, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x6c, 0x6d, 0x61, 0x74, 0x79, 0x0, 0x41, 0x6d,
-0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x75, 0x69, 0x61, 0x62, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
-0x2f, 0x4d, 0x65, 0x78, 0x69, 0x63, 0x6f, 0x5f, 0x43, 0x69, 0x74, 0x79, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
-0x2f, 0x43, 0x68, 0x69, 0x63, 0x61, 0x67, 0x6f, 0x0, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x42,
-0x72, 0x69, 0x73, 0x62, 0x61, 0x6e, 0x65, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x65, 0x77, 0x5f,
-0x59, 0x6f, 0x72, 0x6b, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4b, 0x69, 0x65, 0x76, 0x0, 0x41, 0x6d, 0x65,
-0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x68, 0x69, 0x68, 0x75, 0x61, 0x68, 0x75, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69,
-0x63, 0x61, 0x2f, 0x44, 0x65, 0x6e, 0x76, 0x65, 0x72, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x72, 0x61, 0x73, 0x6e,
-0x6f, 0x79, 0x61, 0x72, 0x73, 0x6b, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x69, 0x6a, 0x75, 0x61,
-0x6e, 0x61, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x6d, 0x63, 0x68, 0x61, 0x74, 0x6b, 0x61, 0x0, 0x45, 0x75,
-0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x6f, 0x73, 0x63, 0x6f, 0x77, 0x0, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69,
-0x61, 0x2f, 0x48, 0x6f, 0x62, 0x61, 0x72, 0x74, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x55, 0x6c, 0x61, 0x61, 0x6e, 0x62,
-0x61, 0x61, 0x74, 0x61, 0x72, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e,
-0x61, 0x70, 0x6f, 0x6c, 0x69, 0x73, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x55, 0x54, 0x43, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f,
-0x56, 0x6c, 0x61, 0x64, 0x69, 0x76, 0x6f, 0x73, 0x74, 0x6f, 0x6b, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42,
-0x65, 0x72, 0x6c, 0x69, 0x6e, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x61, 0x73, 0x68, 0x6b, 0x65, 0x6e, 0x74, 0x0,
-0x41, 0x73, 0x69, 0x61, 0x2f, 0x48, 0x65, 0x62, 0x72, 0x6f, 0x6e, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x59, 0x61, 0x6b,
-0x75, 0x74, 0x73, 0x6b, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x57, 0x68, 0x69, 0x74, 0x65, 0x68, 0x6f,
-0x72, 0x73, 0x65, 0x0, 0x55, 0x54, 0x43, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x31, 0x34, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54,
-0x43, 0x2d, 0x31, 0x33, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x31, 0x32, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54,
-0x43, 0x2d, 0x31, 0x31, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x31, 0x30, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54,
-0x43, 0x2d, 0x30, 0x39, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x30, 0x38, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54,
-0x43, 0x2d, 0x30, 0x37, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x30, 0x36, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54,
-0x43, 0x2d, 0x30, 0x35, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x30, 0x34, 0x3a, 0x33, 0x30, 0x0, 0x55, 0x54,
-0x43, 0x2d, 0x30, 0x34, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x30, 0x33, 0x3a, 0x33, 0x30, 0x0, 0x55, 0x54,
-0x43, 0x2d, 0x30, 0x33, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x30, 0x32, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54,
-0x43, 0x2d, 0x30, 0x31, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54,
-0x43, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54,
-0x43, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x30, 0x33, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54,
-0x43, 0x2b, 0x30, 0x33, 0x3a, 0x33, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x30, 0x34, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54,
-0x43, 0x2b, 0x30, 0x34, 0x3a, 0x33, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x30, 0x35, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54,
-0x43, 0x2b, 0x30, 0x35, 0x3a, 0x33, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x30, 0x35, 0x3a, 0x34, 0x35, 0x0, 0x55, 0x54,
-0x43, 0x2b, 0x30, 0x36, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x30, 0x36, 0x3a, 0x33, 0x30, 0x0, 0x55, 0x54,
-0x43, 0x2b, 0x30, 0x37, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x30, 0x38, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54,
-0x43, 0x2b, 0x30, 0x38, 0x3a, 0x33, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x30, 0x39, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54,
-0x43, 0x2b, 0x30, 0x39, 0x3a, 0x33, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x31, 0x30, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54,
-0x43, 0x2b, 0x31, 0x31, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x31, 0x32, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54,
-0x43, 0x2b, 0x31, 0x33, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x31, 0x34, 0x3a, 0x30, 0x30, 0x0
+0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x62, 0x75, 0x6c, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69,
+0x63, 0x61, 0x2f, 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x20, 0x41, 0x6d, 0x65,
+0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a, 0x75, 0x6e, 0x65, 0x61, 0x75, 0x20, 0x41, 0x6d, 0x65, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x4d, 0x65, 0x74, 0x6c, 0x61, 0x6b, 0x61, 0x74, 0x6c, 0x61, 0x20, 0x41,
+0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x6d, 0x65, 0x20, 0x41, 0x6d, 0x65, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x53, 0x69, 0x74, 0x6b, 0x61, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
+0x61, 0x2f, 0x59, 0x61, 0x6b, 0x75, 0x74, 0x61, 0x74, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
+0x61, 0x2f, 0x41, 0x64, 0x61, 0x6b, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x72, 0x6e,
+0x61, 0x75, 0x6c, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x68, 0x72, 0x61, 0x69, 0x6e,
+0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x75, 0x77, 0x61, 0x69, 0x74, 0x0, 0x41, 0x73, 0x69,
+0x61, 0x2f, 0x51, 0x61, 0x74, 0x61, 0x72, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x52, 0x69, 0x79,
+0x61, 0x64, 0x68, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x64, 0x65, 0x6e, 0x0, 0x45, 0x74,
+0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x34, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x75, 0x73,
+0x63, 0x61, 0x74, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x75, 0x62, 0x61, 0x69, 0x0, 0x41,
+0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x67, 0x68, 0x64, 0x61, 0x64, 0x0, 0x41, 0x6d, 0x65, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x42, 0x75, 0x65, 0x6e, 0x6f, 0x73, 0x5f, 0x41, 0x69, 0x72, 0x65, 0x73,
+0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69,
+0x6e, 0x61, 0x2f, 0x4c, 0x61, 0x5f, 0x52, 0x69, 0x6f, 0x6a, 0x61, 0x20, 0x41, 0x6d, 0x65, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x52, 0x69,
+0x6f, 0x5f, 0x47, 0x61, 0x6c, 0x6c, 0x65, 0x67, 0x6f, 0x73, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69,
+0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x53, 0x61, 0x6c,
+0x74, 0x61, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e,
+0x74, 0x69, 0x6e, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x5f, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x41, 0x6d,
+0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f,
+0x53, 0x61, 0x6e, 0x5f, 0x4c, 0x75, 0x69, 0x73, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
+0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x54, 0x75, 0x63, 0x75, 0x6d,
+0x61, 0x6e, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e,
+0x74, 0x69, 0x6e, 0x61, 0x2f, 0x55, 0x73, 0x68, 0x75, 0x61, 0x69, 0x61, 0x20, 0x41, 0x6d, 0x65,
+0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x74, 0x61, 0x6d, 0x61, 0x72, 0x63, 0x61, 0x20, 0x41,
+0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x6f, 0x72, 0x64, 0x6f, 0x62, 0x61, 0x20, 0x41,
+0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a, 0x75, 0x6a, 0x75, 0x79, 0x20, 0x41, 0x6d, 0x65,
+0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x65, 0x6e, 0x64, 0x6f, 0x7a, 0x61, 0x0, 0x45, 0x75, 0x72,
+0x6f, 0x70, 0x65, 0x2f, 0x41, 0x73, 0x74, 0x72, 0x61, 0x6b, 0x68, 0x61, 0x6e, 0x20, 0x45, 0x75,
+0x72, 0x6f, 0x70, 0x65, 0x2f, 0x55, 0x6c, 0x79, 0x61, 0x6e, 0x6f, 0x76, 0x73, 0x6b, 0x0, 0x41,
+0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x42, 0x65, 0x72, 0x6d, 0x75, 0x64, 0x61, 0x0,
+0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x48, 0x61, 0x6c, 0x69, 0x66, 0x61, 0x78, 0x20,
+0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x6c, 0x61, 0x63, 0x65, 0x5f, 0x42, 0x61,
+0x79, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x6f, 0x6f, 0x73, 0x65, 0x5f,
+0x42, 0x61, 0x79, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x63,
+0x74, 0x6f, 0x6e, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x68, 0x75, 0x6c,
+0x65, 0x0, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x44, 0x61, 0x72, 0x77,
+0x69, 0x6e, 0x0, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x45, 0x75, 0x63,
+0x6c, 0x61, 0x0, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x53, 0x79, 0x64,
+0x6e, 0x65, 0x79, 0x20, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x4d, 0x65,
+0x6c, 0x62, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x6b,
+0x75, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x73,
+0x62, 0x79, 0x73, 0x75, 0x6e, 0x64, 0x0, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f,
+0x41, 0x7a, 0x6f, 0x72, 0x65, 0x73, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42,
+0x61, 0x68, 0x69, 0x61, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x68, 0x61, 0x6b, 0x61, 0x0,
+0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x68, 0x69, 0x6d, 0x70, 0x68, 0x75, 0x0, 0x45, 0x75, 0x72,
+0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x69, 0x6e, 0x73, 0x6b, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69,
+0x63, 0x2f, 0x42, 0x6f, 0x75, 0x67, 0x61, 0x69, 0x6e, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x0, 0x41,
+0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x65, 0x67, 0x69, 0x6e, 0x61, 0x20, 0x41, 0x6d,
+0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x77, 0x69, 0x66, 0x74, 0x5f, 0x43, 0x75, 0x72, 0x72,
+0x65, 0x6e, 0x74, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x31, 0x0, 0x41, 0x74,
+0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x43, 0x61, 0x70, 0x65, 0x5f, 0x56, 0x65, 0x72, 0x64,
+0x65, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x59, 0x65, 0x72, 0x65, 0x76, 0x61, 0x6e, 0x0, 0x41,
+0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x41, 0x64, 0x65, 0x6c, 0x61, 0x69, 0x64,
+0x65, 0x20, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x42, 0x72, 0x6f, 0x6b,
+0x65, 0x6e, 0x5f, 0x48, 0x69, 0x6c, 0x6c, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b,
+0x36, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x65, 0x6c, 0x69, 0x7a, 0x65,
+0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x6f, 0x73, 0x74, 0x61, 0x5f, 0x52,
+0x69, 0x63, 0x61, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x47, 0x61, 0x6c, 0x61,
+0x70, 0x61, 0x67, 0x6f, 0x73, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x6c,
+0x5f, 0x53, 0x61, 0x6c, 0x76, 0x61, 0x64, 0x6f, 0x72, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
+0x61, 0x2f, 0x47, 0x75, 0x61, 0x74, 0x65, 0x6d, 0x61, 0x6c, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x54, 0x65, 0x67, 0x75, 0x63, 0x69, 0x67, 0x61, 0x6c, 0x70, 0x61, 0x0,
+0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x75, 0x61, 0x0,
+0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x36, 0x0, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63,
+0x74, 0x69, 0x63, 0x61, 0x2f, 0x56, 0x6f, 0x73, 0x74, 0x6f, 0x6b, 0x0, 0x49, 0x6e, 0x64, 0x69,
+0x61, 0x6e, 0x2f, 0x43, 0x68, 0x61, 0x67, 0x6f, 0x73, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x55,
+0x72, 0x75, 0x6d, 0x71, 0x69, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x6c, 0x6d, 0x61, 0x74,
+0x79, 0x20, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x51, 0x6f, 0x73, 0x74, 0x61, 0x6e, 0x61, 0x79, 0x0,
+0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x69, 0x73, 0x68, 0x6b, 0x65, 0x6b, 0x0, 0x41, 0x6d, 0x65,
+0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x75, 0x69, 0x61, 0x62, 0x61, 0x20, 0x41, 0x6d, 0x65, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x6d, 0x70, 0x6f, 0x5f, 0x47, 0x72, 0x61, 0x6e, 0x64, 0x65,
+0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x54, 0x69, 0x72, 0x61, 0x6e, 0x65, 0x0, 0x45,
+0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x50, 0x72, 0x61, 0x67, 0x75, 0x65, 0x0, 0x45, 0x75, 0x72,
+0x6f, 0x70, 0x65, 0x2f, 0x42, 0x75, 0x64, 0x61, 0x70, 0x65, 0x73, 0x74, 0x0, 0x45, 0x75, 0x72,
+0x6f, 0x70, 0x65, 0x2f, 0x50, 0x6f, 0x64, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x0, 0x45, 0x75,
+0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x65, 0x6c, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0, 0x45, 0x75,
+0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x72, 0x61, 0x74, 0x69, 0x73, 0x6c, 0x61, 0x76, 0x61, 0x0,
+0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x6a, 0x75, 0x62, 0x6c, 0x6a, 0x61, 0x6e, 0x61,
+0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x72, 0x61, 0x6a, 0x65, 0x76, 0x6f,
+0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x5a, 0x61, 0x67, 0x72, 0x65, 0x62, 0x0, 0x45,
+0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x6b, 0x6f, 0x70, 0x6a, 0x65, 0x0, 0x45, 0x75, 0x72,
+0x6f, 0x70, 0x65, 0x2f, 0x57, 0x61, 0x72, 0x73, 0x61, 0x77, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47,
+0x4d, 0x54, 0x2d, 0x31, 0x31, 0x0, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61,
+0x2f, 0x43, 0x61, 0x73, 0x65, 0x79, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50,
+0x6f, 0x6e, 0x61, 0x70, 0x65, 0x20, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4b, 0x6f,
+0x73, 0x72, 0x61, 0x65, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4e, 0x6f, 0x75,
+0x6d, 0x65, 0x61, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x47, 0x75, 0x61, 0x64,
+0x61, 0x6c, 0x63, 0x61, 0x6e, 0x61, 0x6c, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f,
+0x45, 0x66, 0x61, 0x74, 0x65, 0x0, 0x43, 0x53, 0x54, 0x36, 0x43, 0x44, 0x54, 0x0, 0x41, 0x6d,
+0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x57, 0x69, 0x6e, 0x6e, 0x69, 0x70, 0x65, 0x67, 0x20, 0x41,
+0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x61, 0x69, 0x6e, 0x79, 0x5f, 0x52, 0x69, 0x76,
+0x65, 0x72, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x61, 0x6e, 0x6b, 0x69,
+0x6e, 0x5f, 0x49, 0x6e, 0x6c, 0x65, 0x74, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
+0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
+0x2f, 0x4d, 0x61, 0x74, 0x61, 0x6d, 0x6f, 0x72, 0x6f, 0x73, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69,
+0x63, 0x61, 0x2f, 0x4f, 0x6a, 0x69, 0x6e, 0x61, 0x67, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69,
+0x63, 0x61, 0x2f, 0x43, 0x68, 0x69, 0x63, 0x61, 0x67, 0x6f, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69,
+0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x4b, 0x6e, 0x6f, 0x78, 0x20,
+0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f,
+0x54, 0x65, 0x6c, 0x6c, 0x5f, 0x43, 0x69, 0x74, 0x79, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
+0x61, 0x2f, 0x4d, 0x65, 0x6e, 0x6f, 0x6d, 0x69, 0x6e, 0x65, 0x65, 0x20, 0x41, 0x6d, 0x65, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x5f, 0x44, 0x61, 0x6b, 0x6f, 0x74, 0x61,
+0x2f, 0x42, 0x65, 0x75, 0x6c, 0x61, 0x68, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
+0x4e, 0x6f, 0x72, 0x74, 0x68, 0x5f, 0x44, 0x61, 0x6b, 0x6f, 0x74, 0x61, 0x2f, 0x43, 0x65, 0x6e,
+0x74, 0x65, 0x72, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x72, 0x74,
+0x68, 0x5f, 0x44, 0x61, 0x6b, 0x6f, 0x74, 0x61, 0x2f, 0x4e, 0x65, 0x77, 0x5f, 0x53, 0x61, 0x6c,
+0x65, 0x6d, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x65, 0x78, 0x69, 0x63,
+0x6f, 0x5f, 0x43, 0x69, 0x74, 0x79, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42,
+0x61, 0x68, 0x69, 0x61, 0x5f, 0x42, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x61, 0x73, 0x20, 0x41, 0x6d,
+0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x65, 0x72, 0x69, 0x64, 0x61, 0x20, 0x41, 0x6d, 0x65,
+0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x74, 0x65, 0x72, 0x72, 0x65, 0x79, 0x20, 0x41,
+0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x68, 0x69, 0x68, 0x75, 0x61, 0x68, 0x75, 0x61,
+0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x43, 0x68, 0x61, 0x74, 0x68, 0x61, 0x6d,
+0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x68, 0x61, 0x6e, 0x67, 0x68, 0x61, 0x69, 0x0, 0x41,
+0x73, 0x69, 0x61, 0x2f, 0x48, 0x6f, 0x6e, 0x67, 0x5f, 0x4b, 0x6f, 0x6e, 0x67, 0x0, 0x41, 0x73,
+0x69, 0x61, 0x2f, 0x4d, 0x61, 0x63, 0x61, 0x75, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
+0x2f, 0x48, 0x61, 0x76, 0x61, 0x6e, 0x61, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b,
+0x31, 0x32, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x33, 0x0, 0x41, 0x6e, 0x74,
+0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x79, 0x6f, 0x77, 0x61, 0x0, 0x49, 0x6e,
+0x64, 0x69, 0x61, 0x6e, 0x2f, 0x43, 0x6f, 0x6d, 0x6f, 0x72, 0x6f, 0x0, 0x41, 0x66, 0x72, 0x69,
+0x63, 0x61, 0x2f, 0x44, 0x6a, 0x69, 0x62, 0x6f, 0x75, 0x74, 0x69, 0x0, 0x41, 0x66, 0x72, 0x69,
+0x63, 0x61, 0x2f, 0x41, 0x73, 0x6d, 0x65, 0x72, 0x61, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61,
+0x2f, 0x41, 0x64, 0x64, 0x69, 0x73, 0x5f, 0x41, 0x62, 0x61, 0x62, 0x61, 0x0, 0x41, 0x66, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x4e, 0x61, 0x69, 0x72, 0x6f, 0x62, 0x69, 0x0, 0x49, 0x6e, 0x64, 0x69,
+0x61, 0x6e, 0x2f, 0x41, 0x6e, 0x74, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x76, 0x6f, 0x0,
+0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x79, 0x6f, 0x74, 0x74, 0x65, 0x0, 0x41,
+0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x67, 0x61, 0x64, 0x69, 0x73, 0x68, 0x75, 0x0,
+0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x72, 0x5f, 0x65, 0x73, 0x5f, 0x53, 0x61,
+0x6c, 0x61, 0x61, 0x6d, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x61, 0x6d, 0x70,
+0x61, 0x6c, 0x61, 0x0, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x42, 0x72,
+0x69, 0x73, 0x62, 0x61, 0x6e, 0x65, 0x20, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61,
+0x2f, 0x4c, 0x69, 0x6e, 0x64, 0x65, 0x6d, 0x61, 0x6e, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
+0x2f, 0x43, 0x68, 0x69, 0x73, 0x69, 0x6e, 0x61, 0x75, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
+0x61, 0x2f, 0x53, 0x61, 0x6f, 0x5f, 0x50, 0x61, 0x75, 0x6c, 0x6f, 0x0, 0x50, 0x61, 0x63, 0x69,
+0x66, 0x69, 0x63, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x0, 0x45, 0x53, 0x54, 0x35, 0x45,
+0x44, 0x54, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x61, 0x73, 0x73, 0x61,
+0x75, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x6f, 0x72, 0x6f, 0x6e, 0x74,
+0x6f, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x71, 0x61, 0x6c, 0x75, 0x69,
+0x74, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x74, 0x72, 0x65,
+0x61, 0x6c, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x69, 0x70, 0x69, 0x67,
+0x6f, 0x6e, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x61, 0x6e, 0x67, 0x6e,
+0x69, 0x72, 0x74, 0x75, 0x6e, 0x67, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54,
+0x68, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x42, 0x61, 0x79, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69,
+0x63, 0x61, 0x2f, 0x4e, 0x65, 0x77, 0x5f, 0x59, 0x6f, 0x72, 0x6b, 0x20, 0x41, 0x6d, 0x65, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x44, 0x65, 0x74, 0x72, 0x6f, 0x69, 0x74, 0x20, 0x41, 0x6d, 0x65, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x50, 0x65, 0x74, 0x65,
+0x72, 0x73, 0x62, 0x75, 0x72, 0x67, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49,
+0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x56, 0x69, 0x6e, 0x63, 0x65, 0x6e, 0x6e, 0x65, 0x73,
+0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61,
+0x2f, 0x57, 0x69, 0x6e, 0x61, 0x6d, 0x61, 0x63, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
+0x2f, 0x4b, 0x65, 0x6e, 0x74, 0x75, 0x63, 0x6b, 0x79, 0x2f, 0x4d, 0x6f, 0x6e, 0x74, 0x69, 0x63,
+0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x6f, 0x75,
+0x69, 0x73, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
+0x43, 0x61, 0x6e, 0x63, 0x75, 0x6e, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61,
+0x69, 0x72, 0x6f, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x59, 0x65, 0x6b, 0x61, 0x74, 0x65, 0x72,
+0x69, 0x6e, 0x62, 0x75, 0x72, 0x67, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x46,
+0x69, 0x6a, 0x69, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x61, 0x72, 0x69, 0x65,
+0x68, 0x61, 0x6d, 0x6e, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x6f, 0x66, 0x69,
+0x61, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x54, 0x61, 0x6c, 0x6c, 0x69, 0x6e, 0x6e,
+0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x48, 0x65, 0x6c, 0x73, 0x69, 0x6e, 0x6b, 0x69,
+0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x52, 0x69, 0x67, 0x61, 0x0, 0x45, 0x75, 0x72,
+0x6f, 0x70, 0x65, 0x2f, 0x56, 0x69, 0x6c, 0x6e, 0x69, 0x75, 0x73, 0x0, 0x45, 0x75, 0x72, 0x6f,
+0x70, 0x65, 0x2f, 0x4b, 0x69, 0x65, 0x76, 0x20, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x55,
+0x7a, 0x68, 0x67, 0x6f, 0x72, 0x6f, 0x64, 0x20, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x5a,
+0x61, 0x70, 0x6f, 0x72, 0x6f, 0x7a, 0x68, 0x79, 0x65, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54,
+0x62, 0x69, 0x6c, 0x69, 0x73, 0x69, 0x0, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f,
+0x46, 0x61, 0x65, 0x72, 0x6f, 0x65, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x47, 0x75,
+0x65, 0x72, 0x6e, 0x73, 0x65, 0x79, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x44, 0x75,
+0x62, 0x6c, 0x69, 0x6e, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x49, 0x73, 0x6c, 0x65,
+0x5f, 0x6f, 0x66, 0x5f, 0x4d, 0x61, 0x6e, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4a,
+0x65, 0x72, 0x73, 0x65, 0x79, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x69, 0x73,
+0x62, 0x6f, 0x6e, 0x20, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x4d, 0x61, 0x64,
+0x65, 0x69, 0x72, 0x61, 0x0, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x43, 0x61,
+0x6e, 0x61, 0x72, 0x79, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x6f, 0x6e, 0x64,
+0x6f, 0x6e, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x6f, 0x64, 0x74, 0x68,
+0x61, 0x62, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4f, 0x75, 0x61, 0x67, 0x61, 0x64,
+0x6f, 0x75, 0x67, 0x6f, 0x75, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x6e,
+0x6a, 0x75, 0x6c, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x63, 0x63, 0x72, 0x61,
+0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x6e, 0x6d, 0x61, 0x72, 0x6b,
+0x73, 0x68, 0x61, 0x76, 0x6e, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x69, 0x73,
+0x73, 0x61, 0x75, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x6f, 0x6e, 0x61, 0x6b,
+0x72, 0x79, 0x0, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x52, 0x65, 0x79, 0x6b,
+0x6a, 0x61, 0x76, 0x69, 0x6b, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x62, 0x69,
+0x64, 0x6a, 0x61, 0x6e, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x72,
+0x6f, 0x76, 0x69, 0x61, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x6d, 0x61,
+0x6b, 0x6f, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x75, 0x61, 0x6b, 0x63,
+0x68, 0x6f, 0x74, 0x74, 0x0, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x53, 0x74,
+0x5f, 0x48, 0x65, 0x6c, 0x65, 0x6e, 0x61, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44,
+0x61, 0x6b, 0x61, 0x72, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x46, 0x72, 0x65, 0x65,
+0x74, 0x6f, 0x77, 0x6e, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x6f, 0x6d, 0x65,
+0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4e, 0x69, 0x63, 0x6f, 0x73, 0x69, 0x61, 0x20, 0x41, 0x73,
+0x69, 0x61, 0x2f, 0x46, 0x61, 0x6d, 0x61, 0x67, 0x75, 0x73, 0x74, 0x61, 0x0, 0x45, 0x75, 0x72,
+0x6f, 0x70, 0x65, 0x2f, 0x41, 0x74, 0x68, 0x65, 0x6e, 0x73, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70,
+0x65, 0x2f, 0x42, 0x75, 0x63, 0x68, 0x61, 0x72, 0x65, 0x73, 0x74, 0x0, 0x41, 0x6d, 0x65, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x2d, 0x61, 0x75, 0x2d, 0x50, 0x72, 0x69, 0x6e,
+0x63, 0x65, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x31, 0x30, 0x0, 0x50, 0x61,
+0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x52, 0x61, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x67, 0x61, 0x0,
+0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x54, 0x61, 0x68, 0x69, 0x74, 0x69, 0x0, 0x50,
+0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4a, 0x6f, 0x68, 0x6e, 0x73, 0x74, 0x6f, 0x6e, 0x0,
+0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x48, 0x6f, 0x6e, 0x6f, 0x6c, 0x75, 0x6c, 0x75,
+0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x43, 0x61, 0x6c, 0x63, 0x75, 0x74, 0x74, 0x61, 0x0, 0x41,
+0x73, 0x69, 0x61, 0x2f, 0x54, 0x65, 0x68, 0x72, 0x61, 0x6e, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f,
+0x4a, 0x65, 0x72, 0x75, 0x73, 0x61, 0x6c, 0x65, 0x6d, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41,
+0x6d, 0x6d, 0x61, 0x6e, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4b, 0x61, 0x6c, 0x69,
+0x6e, 0x69, 0x6e, 0x67, 0x72, 0x61, 0x64, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x65, 0x6f,
+0x75, 0x6c, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x72, 0x69, 0x70, 0x6f, 0x6c,
+0x69, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x34, 0x0, 0x50, 0x61, 0x63,
+0x69, 0x66, 0x69, 0x63, 0x2f, 0x4b, 0x69, 0x72, 0x69, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x69, 0x0,
+0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x4c, 0x6f, 0x72, 0x64, 0x5f, 0x48,
+0x6f, 0x77, 0x65, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x61, 0x67, 0x61, 0x64, 0x61, 0x6e,
+0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x75, 0x6e, 0x74, 0x61, 0x5f, 0x41,
+0x72, 0x65, 0x6e, 0x61, 0x73, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4d, 0x61,
+0x72, 0x71, 0x75, 0x65, 0x73, 0x61, 0x73, 0x0, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x4d,
+0x61, 0x75, 0x72, 0x69, 0x74, 0x69, 0x75, 0x73, 0x0, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f,
+0x52, 0x65, 0x75, 0x6e, 0x69, 0x6f, 0x6e, 0x0, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x4d,
+0x61, 0x68, 0x65, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x65, 0x69, 0x72, 0x75, 0x74, 0x0,
+0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x74, 0x65, 0x76, 0x69, 0x64,
+0x65, 0x6f, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x73, 0x61, 0x62, 0x6c,
+0x61, 0x6e, 0x63, 0x61, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x6c, 0x5f, 0x41,
+0x61, 0x69, 0x75, 0x6e, 0x0, 0x4d, 0x53, 0x54, 0x37, 0x4d, 0x44, 0x54, 0x0, 0x41, 0x6d, 0x65,
+0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x64, 0x6d, 0x6f, 0x6e, 0x74, 0x6f, 0x6e, 0x20, 0x41, 0x6d,
+0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x5f,
+0x42, 0x61, 0x79, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x75, 0x76,
+0x69, 0x6b, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x59, 0x65, 0x6c, 0x6c, 0x6f,
+0x77, 0x6b, 0x6e, 0x69, 0x66, 0x65, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43,
+0x69, 0x75, 0x64, 0x61, 0x64, 0x5f, 0x4a, 0x75, 0x61, 0x72, 0x65, 0x7a, 0x0, 0x41, 0x6d, 0x65,
+0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x65, 0x6e, 0x76, 0x65, 0x72, 0x20, 0x41, 0x6d, 0x65, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x42, 0x6f, 0x69, 0x73, 0x65, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
+0x61, 0x2f, 0x4d, 0x61, 0x7a, 0x61, 0x74, 0x6c, 0x61, 0x6e, 0x0, 0x49, 0x6e, 0x64, 0x69, 0x61,
+0x6e, 0x2f, 0x43, 0x6f, 0x63, 0x6f, 0x73, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x52, 0x61, 0x6e,
+0x67, 0x6f, 0x6f, 0x6e, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4e, 0x6f, 0x76, 0x6f, 0x73, 0x69,
+0x62, 0x69, 0x72, 0x73, 0x6b, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x57, 0x69, 0x6e,
+0x64, 0x68, 0x6f, 0x65, 0x6b, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x74, 0x6d, 0x61,
+0x6e, 0x64, 0x75, 0x0, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x4d,
+0x63, 0x4d, 0x75, 0x72, 0x64, 0x6f, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x41,
+0x75, 0x63, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
+0x53, 0x74, 0x5f, 0x4a, 0x6f, 0x68, 0x6e, 0x73, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
+0x2f, 0x4e, 0x6f, 0x72, 0x66, 0x6f, 0x6c, 0x6b, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x49, 0x72,
+0x6b, 0x75, 0x74, 0x73, 0x6b, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x72, 0x61, 0x73, 0x6e,
+0x6f, 0x79, 0x61, 0x72, 0x73, 0x6b, 0x20, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4e, 0x6f, 0x76, 0x6f,
+0x6b, 0x75, 0x7a, 0x6e, 0x65, 0x74, 0x73, 0x6b, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x50, 0x79,
+0x6f, 0x6e, 0x67, 0x79, 0x61, 0x6e, 0x67, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4f, 0x6d, 0x73,
+0x6b, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x74, 0x69, 0x61,
+0x67, 0x6f, 0x0, 0x50, 0x53, 0x54, 0x38, 0x50, 0x44, 0x54, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69,
+0x63, 0x61, 0x2f, 0x56, 0x61, 0x6e, 0x63, 0x6f, 0x75, 0x76, 0x65, 0x72, 0x0, 0x41, 0x6d, 0x65,
+0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x6f, 0x73, 0x5f, 0x41, 0x6e, 0x67, 0x65, 0x6c, 0x65, 0x73,
+0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x69, 0x6a, 0x75, 0x61, 0x6e, 0x61,
+0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x74, 0x61, 0x5f, 0x49,
+0x73, 0x61, 0x62, 0x65, 0x6c, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x72, 0x61, 0x63,
+0x68, 0x69, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x73, 0x75, 0x6e, 0x63,
+0x69, 0x6f, 0x6e, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x51, 0x79, 0x7a, 0x79, 0x6c, 0x6f, 0x72,
+0x64, 0x61, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x72, 0x75, 0x73, 0x73, 0x65,
+0x6c, 0x73, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x43, 0x6f, 0x70, 0x65, 0x6e, 0x68,
+0x61, 0x67, 0x65, 0x6e, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x50, 0x61, 0x72, 0x69,
+0x73, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x61, 0x64, 0x72, 0x69, 0x64, 0x20,
+0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x65, 0x75, 0x74, 0x61, 0x0, 0x41, 0x73, 0x69,
+0x61, 0x2f, 0x53, 0x72, 0x65, 0x64, 0x6e, 0x65, 0x6b, 0x6f, 0x6c, 0x79, 0x6d, 0x73, 0x6b, 0x0,
+0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x6d, 0x63, 0x68, 0x61, 0x74, 0x6b, 0x61, 0x20, 0x41,
+0x73, 0x69, 0x61, 0x2f, 0x41, 0x6e, 0x61, 0x64, 0x79, 0x72, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70,
+0x65, 0x2f, 0x53, 0x61, 0x6d, 0x61, 0x72, 0x61, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
+0x4d, 0x6f, 0x73, 0x63, 0x6f, 0x77, 0x20, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4b, 0x69,
+0x72, 0x6f, 0x76, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x69, 0x6d, 0x66, 0x65,
+0x72, 0x6f, 0x70, 0x6f, 0x6c, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x33, 0x0,
+0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x6f, 0x74, 0x68, 0x65,
+0x72, 0x61, 0x20, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x61,
+0x6c, 0x6d, 0x65, 0x72, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x46, 0x6f, 0x72,
+0x74, 0x61, 0x6c, 0x65, 0x7a, 0x61, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42,
+0x65, 0x6c, 0x65, 0x6d, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x63,
+0x65, 0x69, 0x6f, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x65, 0x63, 0x69,
+0x66, 0x65, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x74, 0x61,
+0x72, 0x65, 0x6d, 0x0, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x53, 0x74, 0x61,
+0x6e, 0x6c, 0x65, 0x79, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x79,
+0x65, 0x6e, 0x6e, 0x65, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x61, 0x72,
+0x61, 0x6d, 0x61, 0x72, 0x69, 0x62, 0x6f, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b,
+0x35, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x69, 0x6f, 0x5f, 0x42, 0x72,
+0x61, 0x6e, 0x63, 0x6f, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x69, 0x72,
+0x75, 0x6e, 0x65, 0x70, 0x65, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x6f,
+0x72, 0x61, 0x6c, 0x5f, 0x48, 0x61, 0x72, 0x62, 0x6f, 0x75, 0x72, 0x0, 0x41, 0x6d, 0x65, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x79, 0x6d, 0x61, 0x6e, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69,
+0x63, 0x61, 0x2f, 0x42, 0x6f, 0x67, 0x6f, 0x74, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
+0x61, 0x2f, 0x47, 0x75, 0x61, 0x79, 0x61, 0x71, 0x75, 0x69, 0x6c, 0x0, 0x41, 0x6d, 0x65, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x4a, 0x61, 0x6d, 0x61, 0x69, 0x63, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x50, 0x61, 0x6e, 0x61, 0x6d, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69,
+0x63, 0x61, 0x2f, 0x4c, 0x69, 0x6d, 0x61, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b,
+0x34, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x6e, 0x67, 0x75, 0x69, 0x6c,
+0x6c, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x6e, 0x74, 0x69, 0x67,
+0x75, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x75, 0x62, 0x61,
+0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x72, 0x62, 0x61, 0x64, 0x6f,
+0x73, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x61, 0x5f, 0x50, 0x61, 0x7a,
+0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x6e, 0x61, 0x75, 0x73, 0x20,
+0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6f, 0x61, 0x5f, 0x56, 0x69, 0x73, 0x74,
+0x61, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x6f, 0x5f,
+0x56, 0x65, 0x6c, 0x68, 0x6f, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x6f,
+0x72, 0x74, 0x6f, 0x6c, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6c,
+0x61, 0x6e, 0x63, 0x2d, 0x53, 0x61, 0x62, 0x6c, 0x6f, 0x6e, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69,
+0x63, 0x61, 0x2f, 0x4b, 0x72, 0x61, 0x6c, 0x65, 0x6e, 0x64, 0x69, 0x6a, 0x6b, 0x0, 0x41, 0x6d,
+0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x75, 0x72, 0x61, 0x63, 0x61, 0x6f, 0x0, 0x41, 0x6d,
+0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x6f, 0x6d, 0x69, 0x6e, 0x69, 0x63, 0x61, 0x0, 0x41,
+0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x74, 0x6f, 0x5f, 0x44, 0x6f, 0x6d,
+0x69, 0x6e, 0x67, 0x6f, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x72, 0x65,
+0x6e, 0x61, 0x64, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x75, 0x61,
+0x64, 0x65, 0x6c, 0x6f, 0x75, 0x70, 0x65, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
+0x47, 0x75, 0x79, 0x61, 0x6e, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d,
+0x61, 0x72, 0x74, 0x69, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
+0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x72, 0x61, 0x74, 0x0, 0x41, 0x6d, 0x65,
+0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x75, 0x65, 0x72, 0x74, 0x6f, 0x5f, 0x52, 0x69, 0x63, 0x6f,
+0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x74, 0x5f, 0x42, 0x61, 0x72, 0x74,
+0x68, 0x65, 0x6c, 0x65, 0x6d, 0x79, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53,
+0x74, 0x5f, 0x4b, 0x69, 0x74, 0x74, 0x73, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
+0x53, 0x74, 0x5f, 0x4c, 0x75, 0x63, 0x69, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
+0x2f, 0x4d, 0x61, 0x72, 0x69, 0x67, 0x6f, 0x74, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
+0x2f, 0x53, 0x74, 0x5f, 0x56, 0x69, 0x6e, 0x63, 0x65, 0x6e, 0x74, 0x0, 0x41, 0x6d, 0x65, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x4c, 0x6f, 0x77, 0x65, 0x72, 0x5f, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x65,
+0x73, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x5f, 0x6f,
+0x66, 0x5f, 0x53, 0x70, 0x61, 0x69, 0x6e, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
+0x53, 0x74, 0x5f, 0x54, 0x68, 0x6f, 0x6d, 0x61, 0x73, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
+0x61, 0x2f, 0x4d, 0x69, 0x71, 0x75, 0x65, 0x6c, 0x6f, 0x6e, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f,
+0x53, 0x61, 0x6b, 0x68, 0x61, 0x6c, 0x69, 0x6e, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
+0x2f, 0x41, 0x70, 0x69, 0x61, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6f,
+0x5f, 0x54, 0x6f, 0x6d, 0x65, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x72,
+0x61, 0x74, 0x6f, 0x76, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x37, 0x0, 0x41,
+0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x76, 0x69, 0x73, 0x0,
+0x41, 0x73, 0x69, 0x61, 0x2f, 0x50, 0x68, 0x6e, 0x6f, 0x6d, 0x5f, 0x50, 0x65, 0x6e, 0x68, 0x0,
+0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x43, 0x68, 0x72, 0x69, 0x73, 0x74, 0x6d, 0x61, 0x73,
+0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4a, 0x61, 0x6b, 0x61, 0x72, 0x74, 0x61, 0x20, 0x41, 0x73,
+0x69, 0x61, 0x2f, 0x50, 0x6f, 0x6e, 0x74, 0x69, 0x61, 0x6e, 0x61, 0x6b, 0x0, 0x41, 0x73, 0x69,
+0x61, 0x2f, 0x56, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6e, 0x65, 0x0, 0x41, 0x73, 0x69, 0x61,
+0x2f, 0x42, 0x61, 0x6e, 0x67, 0x6b, 0x6f, 0x6b, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x61,
+0x69, 0x67, 0x6f, 0x6e, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x38, 0x0, 0x41,
+0x73, 0x69, 0x61, 0x2f, 0x42, 0x72, 0x75, 0x6e, 0x65, 0x69, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f,
+0x4d, 0x61, 0x6b, 0x61, 0x73, 0x73, 0x61, 0x72, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x75,
+0x61, 0x6c, 0x61, 0x5f, 0x4c, 0x75, 0x6d, 0x70, 0x75, 0x72, 0x20, 0x41, 0x73, 0x69, 0x61, 0x2f,
+0x4b, 0x75, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x61, 0x6e,
+0x69, 0x6c, 0x61, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x69, 0x6e, 0x67, 0x61, 0x70, 0x6f,
+0x72, 0x65, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x32, 0x0, 0x41, 0x66, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x47, 0x61, 0x62, 0x6f, 0x72, 0x6f, 0x6e, 0x65, 0x0, 0x41, 0x66, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x42, 0x75, 0x6a, 0x75, 0x6d, 0x62, 0x75, 0x72, 0x61, 0x0, 0x41, 0x66,
+0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x75, 0x62, 0x75, 0x6d, 0x62, 0x61, 0x73, 0x68, 0x69, 0x0,
+0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x62, 0x61, 0x62, 0x61, 0x6e, 0x65, 0x0, 0x41,
+0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x73, 0x65, 0x72, 0x75, 0x0, 0x41, 0x66, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x42, 0x6c, 0x61, 0x6e, 0x74, 0x79, 0x72, 0x65, 0x0, 0x41, 0x66, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x70, 0x75, 0x74, 0x6f, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63,
+0x61, 0x2f, 0x4b, 0x69, 0x67, 0x61, 0x6c, 0x69, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f,
+0x4a, 0x6f, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x73, 0x62, 0x75, 0x72, 0x67, 0x0, 0x41, 0x66, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x4c, 0x75, 0x73, 0x61, 0x6b, 0x61, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63,
+0x61, 0x2f, 0x48, 0x61, 0x72, 0x61, 0x72, 0x65, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f,
+0x4a, 0x75, 0x62, 0x61, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x43, 0x6f, 0x6c, 0x6f, 0x6d, 0x62,
+0x6f, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x68, 0x61, 0x72, 0x74, 0x6f, 0x75,
+0x6d, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x61, 0x6d, 0x61, 0x73, 0x63, 0x75, 0x73, 0x0,
+0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x61, 0x69, 0x70, 0x65, 0x69, 0x0, 0x41, 0x75, 0x73, 0x74,
+0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x48, 0x6f, 0x62, 0x61, 0x72, 0x74, 0x20, 0x41, 0x75, 0x73,
+0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x43, 0x75, 0x72, 0x72, 0x69, 0x65, 0x20, 0x41, 0x6e,
+0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x63, 0x71, 0x75, 0x61, 0x72,
+0x69, 0x65, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x61, 0x67, 0x75,
+0x61, 0x69, 0x6e, 0x61, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x39, 0x0, 0x41,
+0x73, 0x69, 0x61, 0x2f, 0x4a, 0x61, 0x79, 0x61, 0x70, 0x75, 0x72, 0x61, 0x0, 0x41, 0x73, 0x69,
+0x61, 0x2f, 0x54, 0x6f, 0x6b, 0x79, 0x6f, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f,
+0x50, 0x61, 0x6c, 0x61, 0x75, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x69, 0x6c, 0x69, 0x0,
+0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x6f, 0x6d, 0x73, 0x6b, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66,
+0x69, 0x63, 0x2f, 0x54, 0x6f, 0x6e, 0x67, 0x61, 0x74, 0x61, 0x70, 0x75, 0x0, 0x41, 0x73, 0x69,
+0x61, 0x2f, 0x43, 0x68, 0x69, 0x74, 0x61, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x49,
+0x73, 0x74, 0x61, 0x6e, 0x62, 0x75, 0x6c, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
+0x47, 0x72, 0x61, 0x6e, 0x64, 0x5f, 0x54, 0x75, 0x72, 0x6b, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f,
+0x55, 0x6c, 0x61, 0x61, 0x6e, 0x62, 0x61, 0x61, 0x74, 0x61, 0x72, 0x20, 0x41, 0x73, 0x69, 0x61,
+0x2f, 0x43, 0x68, 0x6f, 0x69, 0x62, 0x61, 0x6c, 0x73, 0x61, 0x6e, 0x0, 0x41, 0x6d, 0x65, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x70, 0x6f, 0x6c, 0x69, 0x73,
+0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61,
+0x2f, 0x4d, 0x61, 0x72, 0x65, 0x6e, 0x67, 0x6f, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
+0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x56, 0x65, 0x76, 0x61, 0x79, 0x0, 0x45,
+0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x37, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
+0x2f, 0x43, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x6e, 0x20, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
+0x2f, 0x44, 0x61, 0x77, 0x73, 0x6f, 0x6e, 0x5f, 0x43, 0x72, 0x65, 0x65, 0x6b, 0x20, 0x41, 0x6d,
+0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x46, 0x6f, 0x72, 0x74, 0x5f, 0x4e, 0x65, 0x6c, 0x73, 0x6f,
+0x6e, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x48, 0x65, 0x72, 0x6d, 0x6f, 0x73,
+0x69, 0x6c, 0x6c, 0x6f, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x68, 0x6f,
+0x65, 0x6e, 0x69, 0x78, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x55, 0x54, 0x43, 0x20, 0x45, 0x74, 0x63,
+0x2f, 0x47, 0x4d, 0x54, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x32, 0x0,
+0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x54, 0x61, 0x72, 0x61, 0x77, 0x61, 0x0, 0x50,
+0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4d, 0x61, 0x6a, 0x75, 0x72, 0x6f, 0x20, 0x50, 0x61,
+0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4b, 0x77, 0x61, 0x6a, 0x61, 0x6c, 0x65, 0x69, 0x6e, 0x0,
+0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4e, 0x61, 0x75, 0x72, 0x75, 0x0, 0x50, 0x61,
+0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x46, 0x75, 0x6e, 0x61, 0x66, 0x75, 0x74, 0x69, 0x0, 0x50,
+0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x57, 0x61, 0x6b, 0x65, 0x0, 0x50, 0x61, 0x63, 0x69,
+0x66, 0x69, 0x63, 0x2f, 0x57, 0x61, 0x6c, 0x6c, 0x69, 0x73, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47,
+0x4d, 0x54, 0x2d, 0x31, 0x33, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x45, 0x6e,
+0x64, 0x65, 0x72, 0x62, 0x75, 0x72, 0x79, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f,
+0x46, 0x61, 0x6b, 0x61, 0x6f, 0x66, 0x6f, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b,
+0x32, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x72, 0x6f, 0x6e, 0x68,
+0x61, 0x0, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x53, 0x6f, 0x75, 0x74, 0x68,
+0x5f, 0x47, 0x65, 0x6f, 0x72, 0x67, 0x69, 0x61, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54,
+0x2b, 0x38, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x69, 0x74, 0x63, 0x61,
+0x69, 0x72, 0x6e, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x39, 0x0, 0x50, 0x61,
+0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x47, 0x61, 0x6d, 0x62, 0x69, 0x65, 0x72, 0x0, 0x45, 0x74,
+0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x31, 0x31, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
+0x2f, 0x50, 0x61, 0x67, 0x6f, 0x5f, 0x50, 0x61, 0x67, 0x6f, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66,
+0x69, 0x63, 0x2f, 0x4e, 0x69, 0x75, 0x65, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f,
+0x4d, 0x69, 0x64, 0x77, 0x61, 0x79, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43,
+0x61, 0x72, 0x61, 0x63, 0x61, 0x73, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x56, 0x6c, 0x61, 0x64,
+0x69, 0x76, 0x6f, 0x73, 0x74, 0x6f, 0x6b, 0x20, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x55, 0x73, 0x74,
+0x2d, 0x4e, 0x65, 0x72, 0x61, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x56, 0x6f, 0x6c,
+0x67, 0x6f, 0x67, 0x72, 0x61, 0x64, 0x0, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61,
+0x2f, 0x50, 0x65, 0x72, 0x74, 0x68, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31,
+0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x6c, 0x67, 0x69, 0x65, 0x72, 0x73, 0x0,
+0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x75, 0x61, 0x6e, 0x64, 0x61, 0x0, 0x41, 0x66,
+0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x6f, 0x2d, 0x4e, 0x6f, 0x76, 0x6f, 0x0,
+0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x6f, 0x75, 0x61, 0x6c, 0x61, 0x0, 0x41, 0x66,
+0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x6e, 0x67, 0x75, 0x69, 0x0, 0x41, 0x66, 0x72, 0x69,
+0x63, 0x61, 0x2f, 0x4e, 0x64, 0x6a, 0x61, 0x6d, 0x65, 0x6e, 0x61, 0x0, 0x41, 0x66, 0x72, 0x69,
+0x63, 0x61, 0x2f, 0x42, 0x72, 0x61, 0x7a, 0x7a, 0x61, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x0, 0x41,
+0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x69, 0x6e, 0x73, 0x68, 0x61, 0x73, 0x61, 0x0, 0x41,
+0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x6c, 0x61, 0x62, 0x6f, 0x0, 0x41, 0x66, 0x72,
+0x69, 0x63, 0x61, 0x2f, 0x4c, 0x69, 0x62, 0x72, 0x65, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x0, 0x41,
+0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x61, 0x67, 0x6f, 0x73, 0x0, 0x41, 0x66, 0x72, 0x69,
+0x63, 0x61, 0x2f, 0x4e, 0x69, 0x61, 0x6d, 0x65, 0x79, 0x0, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61,
+0x2f, 0x54, 0x75, 0x6e, 0x69, 0x73, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x41, 0x6e,
+0x64, 0x6f, 0x72, 0x72, 0x61, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x56, 0x69, 0x65,
+0x6e, 0x6e, 0x61, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x65, 0x72, 0x6c, 0x69,
+0x6e, 0x20, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x65,
+0x6e, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x47, 0x69, 0x62, 0x72, 0x61, 0x6c, 0x74,
+0x61, 0x72, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x52, 0x6f, 0x6d, 0x65, 0x0, 0x45,
+0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x56, 0x61, 0x64, 0x75, 0x7a, 0x0, 0x45, 0x75, 0x72, 0x6f,
+0x70, 0x65, 0x2f, 0x4c, 0x75, 0x78, 0x65, 0x6d, 0x62, 0x6f, 0x75, 0x72, 0x67, 0x0, 0x45, 0x75,
+0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x61, 0x6c, 0x74, 0x61, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70,
+0x65, 0x2f, 0x4d, 0x6f, 0x6e, 0x61, 0x63, 0x6f, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
+0x41, 0x6d, 0x73, 0x74, 0x65, 0x72, 0x64, 0x61, 0x6d, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
+0x2f, 0x4f, 0x73, 0x6c, 0x6f, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x6e,
+0x5f, 0x4d, 0x61, 0x72, 0x69, 0x6e, 0x6f, 0x0, 0x41, 0x72, 0x63, 0x74, 0x69, 0x63, 0x2f, 0x4c,
+0x6f, 0x6e, 0x67, 0x79, 0x65, 0x61, 0x72, 0x62, 0x79, 0x65, 0x6e, 0x0, 0x45, 0x75, 0x72, 0x6f,
+0x70, 0x65, 0x2f, 0x53, 0x74, 0x6f, 0x63, 0x6b, 0x68, 0x6f, 0x6c, 0x6d, 0x0, 0x45, 0x75, 0x72,
+0x6f, 0x70, 0x65, 0x2f, 0x5a, 0x75, 0x72, 0x69, 0x63, 0x68, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70,
+0x65, 0x2f, 0x56, 0x61, 0x74, 0x69, 0x63, 0x61, 0x6e, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x48,
+0x6f, 0x76, 0x64, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x35, 0x0, 0x41, 0x6e,
+0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x77, 0x73, 0x6f, 0x6e, 0x0,
+0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x4b, 0x65, 0x72, 0x67, 0x75, 0x65, 0x6c, 0x65, 0x6e,
+0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4f, 0x72, 0x61, 0x6c, 0x20, 0x41, 0x73, 0x69, 0x61, 0x2f,
+0x41, 0x71, 0x74, 0x61, 0x75, 0x20, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x71, 0x74, 0x6f, 0x62,
+0x65, 0x20, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x74, 0x79, 0x72, 0x61, 0x75, 0x0, 0x49, 0x6e,
+0x64, 0x69, 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x6c, 0x64, 0x69, 0x76, 0x65, 0x73, 0x0, 0x41, 0x73,
+0x69, 0x61, 0x2f, 0x44, 0x75, 0x73, 0x68, 0x61, 0x6e, 0x62, 0x65, 0x0, 0x41, 0x73, 0x69, 0x61,
+0x2f, 0x41, 0x73, 0x68, 0x67, 0x61, 0x62, 0x61, 0x74, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54,
+0x61, 0x73, 0x68, 0x6b, 0x65, 0x6e, 0x74, 0x20, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x61, 0x6d,
+0x61, 0x72, 0x6b, 0x61, 0x6e, 0x64, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x48, 0x65, 0x62, 0x72,
+0x6f, 0x6e, 0x20, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x47, 0x61, 0x7a, 0x61, 0x0, 0x45, 0x74, 0x63,
+0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x30, 0x0, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69,
+0x63, 0x61, 0x2f, 0x44, 0x75, 0x6d, 0x6f, 0x6e, 0x74, 0x44, 0x55, 0x72, 0x76, 0x69, 0x6c, 0x6c,
+0x65, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x47, 0x75, 0x61, 0x6d, 0x0, 0x50,
+0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x54, 0x72, 0x75, 0x6b, 0x0, 0x50, 0x61, 0x63, 0x69,
+0x66, 0x69, 0x63, 0x2f, 0x53, 0x61, 0x69, 0x70, 0x61, 0x6e, 0x0, 0x50, 0x61, 0x63, 0x69, 0x66,
+0x69, 0x63, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x5f, 0x4d, 0x6f, 0x72, 0x65, 0x73, 0x62, 0x79, 0x0,
+0x41, 0x73, 0x69, 0x61, 0x2f, 0x59, 0x61, 0x6b, 0x75, 0x74, 0x73, 0x6b, 0x20, 0x41, 0x73, 0x69,
+0x61, 0x2f, 0x4b, 0x68, 0x61, 0x6e, 0x64, 0x79, 0x67, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69,
+0x63, 0x61, 0x2f, 0x57, 0x68, 0x69, 0x74, 0x65, 0x68, 0x6f, 0x72, 0x73, 0x65, 0x20, 0x41, 0x6d,
+0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x77, 0x73, 0x6f, 0x6e, 0x0, 0x41, 0x6d, 0x65,
+0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x0, 0x41,
+0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x75, 0x65, 0x6e, 0x6f, 0x73, 0x5f, 0x41, 0x69,
+0x72, 0x65, 0x73, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x41, 0x73, 0x74, 0x72, 0x61,
+0x6b, 0x68, 0x61, 0x6e, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x48, 0x61, 0x6c,
+0x69, 0x66, 0x61, 0x78, 0x0, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x53,
+0x79, 0x64, 0x6e, 0x65, 0x79, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x65,
+0x67, 0x69, 0x6e, 0x61, 0x0, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x41,
+0x64, 0x65, 0x6c, 0x61, 0x69, 0x64, 0x65, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x6c, 0x6d,
+0x61, 0x74, 0x79, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x75, 0x69, 0x61,
+0x62, 0x61, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x68, 0x69, 0x63, 0x61,
+0x67, 0x6f, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x65, 0x78, 0x69, 0x63,
+0x6f, 0x5f, 0x43, 0x69, 0x74, 0x79, 0x0, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61,
+0x2f, 0x42, 0x72, 0x69, 0x73, 0x62, 0x61, 0x6e, 0x65, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
+0x61, 0x2f, 0x4e, 0x65, 0x77, 0x5f, 0x59, 0x6f, 0x72, 0x6b, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70,
+0x65, 0x2f, 0x4b, 0x69, 0x65, 0x76, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44,
+0x65, 0x6e, 0x76, 0x65, 0x72, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x72, 0x61, 0x73, 0x6e,
+0x6f, 0x79, 0x61, 0x72, 0x73, 0x6b, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54,
+0x69, 0x6a, 0x75, 0x61, 0x6e, 0x61, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x6d, 0x63,
+0x68, 0x61, 0x74, 0x6b, 0x61, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x6f, 0x73,
+0x63, 0x6f, 0x77, 0x0, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x48, 0x6f,
+0x62, 0x61, 0x72, 0x74, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x55, 0x6c, 0x61, 0x61, 0x6e, 0x62,
+0x61, 0x61, 0x74, 0x61, 0x72, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e,
+0x64, 0x69, 0x61, 0x6e, 0x61, 0x70, 0x6f, 0x6c, 0x69, 0x73, 0x0, 0x45, 0x74, 0x63, 0x2f, 0x55,
+0x54, 0x43, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x56, 0x6c, 0x61, 0x64, 0x69, 0x76, 0x6f, 0x73,
+0x74, 0x6f, 0x6b, 0x0, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x65, 0x72, 0x6c, 0x69,
+0x6e, 0x0, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x61, 0x73, 0x68, 0x6b, 0x65, 0x6e, 0x74, 0x0,
+0x41, 0x73, 0x69, 0x61, 0x2f, 0x48, 0x65, 0x62, 0x72, 0x6f, 0x6e, 0x0, 0x41, 0x73, 0x69, 0x61,
+0x2f, 0x59, 0x61, 0x6b, 0x75, 0x74, 0x73, 0x6b, 0x0, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
+0x2f, 0x57, 0x68, 0x69, 0x74, 0x65, 0x68, 0x6f, 0x72, 0x73, 0x65, 0x0, 0x55, 0x54, 0x43, 0x2d,
+0x31, 0x34, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x31, 0x33, 0x3a, 0x30, 0x30, 0x0,
+0x55, 0x54, 0x43, 0x2d, 0x31, 0x32, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x31, 0x31,
+0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x31, 0x30, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54,
+0x43, 0x2d, 0x30, 0x39, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x30, 0x38, 0x3a, 0x30,
+0x30, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x30, 0x37, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2d,
+0x30, 0x36, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x30, 0x35, 0x3a, 0x30, 0x30, 0x0,
+0x55, 0x54, 0x43, 0x2d, 0x30, 0x34, 0x3a, 0x33, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x30, 0x34,
+0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x30, 0x33, 0x3a, 0x33, 0x30, 0x0, 0x55, 0x54,
+0x43, 0x2d, 0x30, 0x33, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x30, 0x32, 0x3a, 0x30,
+0x30, 0x0, 0x55, 0x54, 0x43, 0x2d, 0x30, 0x31, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x20,
+0x55, 0x54, 0x43, 0x2b, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x20, 0x55, 0x54, 0x43, 0x2d, 0x30, 0x30,
+0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x30, 0x31, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54,
+0x43, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x30, 0x33, 0x3a, 0x30,
+0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x30, 0x33, 0x3a, 0x33, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b,
+0x30, 0x34, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x30, 0x34, 0x3a, 0x33, 0x30, 0x0,
+0x55, 0x54, 0x43, 0x2b, 0x30, 0x35, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x30, 0x35,
+0x3a, 0x33, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x30, 0x35, 0x3a, 0x34, 0x35, 0x0, 0x55, 0x54,
+0x43, 0x2b, 0x30, 0x36, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x30, 0x36, 0x3a, 0x33,
+0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x30, 0x37, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b,
+0x30, 0x38, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x30, 0x38, 0x3a, 0x33, 0x30, 0x0,
+0x55, 0x54, 0x43, 0x2b, 0x30, 0x39, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x30, 0x39,
+0x3a, 0x33, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x31, 0x30, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54,
+0x43, 0x2b, 0x31, 0x31, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x31, 0x32, 0x3a, 0x30,
+0x30, 0x0, 0x55, 0x54, 0x43, 0x2b, 0x31, 0x33, 0x3a, 0x30, 0x30, 0x0, 0x55, 0x54, 0x43, 0x2b,
+0x31, 0x34, 0x3a, 0x30, 0x30, 0x0
};
// GENERATED PART ENDS HERE
-inline QByteArrayView QWindowsData::windowsId() const { return windowsIdData + windowsIdIndex; }
+constexpr QByteArrayView WindowsData::windowsId() const { return windowsIdData + windowsIdIndex; }
// Each of the following returns a space-joined sequence of IANA IDs:
-inline QByteArrayView QWindowsData::ianaId() const { return ianaIdData + ianaIdIndex; }
-inline QByteArrayView QUtcData::id() const { return ianaIdData + ianaIdIndex; }
-inline QLatin1StringView QZoneData::id() const
+constexpr QByteArrayView WindowsData::ianaId() const { return ianaIdData + ianaIdIndex; }
+constexpr QByteArrayView UtcData::id() const { return ianaIdData + ianaIdIndex; }
+constexpr QLatin1StringView ZoneData::id() const
{ return QLatin1StringView(ianaIdData + ianaIdIndex); }
+} // namespace QtTimeZoneCldr
+
QT_END_NAMESPACE
#endif // QTIMEZONEPRIVATE_DATA_P_H
diff --git a/src/corelib/time/qtimezoneprivate_icu.cpp b/src/corelib/time/qtimezoneprivate_icu.cpp
index c071e7d549..1a3baa70d0 100644
--- a/src/corelib/time/qtimezoneprivate_icu.cpp
+++ b/src/corelib/time/qtimezoneprivate_icu.cpp
@@ -153,7 +153,7 @@ static QTimeZonePrivate::Data ucalTimeZoneTransition(UCalendar *m_ucal,
UTimeZoneTransitionType type,
qint64 atMSecsSinceEpoch)
{
- QTimeZonePrivate::Data tran = QTimeZonePrivate::invalidData();
+ QTimeZonePrivate::Data tran;
// Clone the ucal so we don't change the shared object
UErrorCode status = U_ZERO_ERROR;
@@ -254,8 +254,8 @@ QIcuTimeZonePrivate::QIcuTimeZonePrivate()
QIcuTimeZonePrivate::QIcuTimeZonePrivate(const QByteArray &ianaId)
: m_ucal(nullptr)
{
- // Need to check validity here as ICu will create a GMT tz if name is invalid
- if (availableTimeZoneIds().contains(ianaId))
+ // ICU misleadingly maps invalid IDs to GMT.
+ if (isTimeZoneIdAvailable(ianaId))
init(ianaId);
}
@@ -301,28 +301,25 @@ QString QIcuTimeZonePrivate::displayName(QTimeZone::TimeType timeType,
QTimeZone::NameType nameType,
const QLocale &locale) const
{
- // Return standard offset format name as ICU C api doesn't support it yet
+ // Base class has handled OffsetName if we came via the other overload.
if (nameType == QTimeZone::OffsetName) {
- const Data nowData = data(QDateTime::currentMSecsSinceEpoch());
- // We can't use transitions reliably to find out right dst offset
- // Instead use dst offset api to try get it if needed
+ int offset = standardTimeOffset(QDateTime::currentMSecsSinceEpoch());
+ // We can't use transitions reliably to find out right DST offset.
+ // Instead use DST offset API to try to get it, when needed:
if (timeType == QTimeZone::DaylightTime)
- return isoOffsetFormat(nowData.standardTimeOffset + ucalDaylightOffset(m_id));
- else
- return isoOffsetFormat(nowData.standardTimeOffset);
+ offset += ucalDaylightOffset(m_id);
+ // This is only valid for times since the most recent standard offset
+ // change; for earlier times, caller must use the other overload.
+
+ // Use our own formating for offset names (ICU C API doesn't support it
+ // and we may as well be self-consistent anyway).
+ return isoOffsetFormat(offset);
}
+ // Technically this may be suspect, if locale isn't QLocale(), since that's
+ // what we used when constructing m_ucal; does ICU cope with inconsistency ?
return ucalTimeZoneDisplayName(m_ucal, timeType, nameType, locale.name());
}
-QString QIcuTimeZonePrivate::abbreviation(qint64 atMSecsSinceEpoch) const
-{
- // TODO No ICU API, use short name instead
- if (isDaylightTime(atMSecsSinceEpoch))
- return displayName(QTimeZone::DaylightTime, QTimeZone::ShortName, QLocale());
- else
- return displayName(QTimeZone::StandardTime, QTimeZone::ShortName, QLocale());
-}
-
int QIcuTimeZonePrivate::offsetFromUtc(qint64 atMSecsSinceEpoch) const
{
int stdOffset = 0;
@@ -387,7 +384,7 @@ bool QIcuTimeZonePrivate::isDaylightTime(qint64 atMSecsSinceEpoch) const
QTimeZonePrivate::Data QIcuTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const
{
// Available in ICU C++ api, and draft C api in v50
- QTimeZonePrivate::Data data = invalidData();
+ QTimeZonePrivate::Data data;
#if U_ICU_VERSION_MAJOR_NUM >= 50
data = ucalTimeZoneTransition(m_ucal, UCAL_TZ_TRANSITION_PREVIOUS_INCLUSIVE,
forMSecsSinceEpoch);
@@ -420,7 +417,7 @@ QTimeZonePrivate::Data QIcuTimeZonePrivate::nextTransition(qint64 afterMSecsSinc
return ucalTimeZoneTransition(m_ucal, UCAL_TZ_TRANSITION_NEXT, afterMSecsSinceEpoch);
#else
Q_UNUSED(afterMSecsSinceEpoch);
- return invalidData();
+ return {};
#endif
}
@@ -431,7 +428,7 @@ QTimeZonePrivate::Data QIcuTimeZonePrivate::previousTransition(qint64 beforeMSec
return ucalTimeZoneTransition(m_ucal, UCAL_TZ_TRANSITION_PREVIOUS, beforeMSecsSinceEpoch);
#else
Q_UNUSED(beforeMSecsSinceEpoch);
- return invalidData();
+ return {};
#endif
}
@@ -442,6 +439,25 @@ QByteArray QIcuTimeZonePrivate::systemTimeZoneId() const
return ucalDefaultTimeZoneId();
}
+bool QIcuTimeZonePrivate::isTimeZoneIdAvailable(const QByteArray &ianaId) const
+{
+ const QString ianaStr = QString::fromUtf8(ianaId);
+ const UChar *const name = reinterpret_cast<const UChar *>(ianaStr.constData());
+ // We are not interested in the value, but we have to pass something.
+ // No known IANA zone name is (up to 2023) longer than 30 characters.
+ constexpr size_t size = 64;
+ UChar buffer[size];
+
+ // TODO: convert to ucal_getIanaTimeZoneID(), new draft in ICU 74, once we
+ // can rely on its availability, assuming it works the same once not draft.
+ UErrorCode status = U_ZERO_ERROR;
+ UBool isSys = false;
+ // Returns the length of the IANA zone name (but we don't care):
+ ucal_getCanonicalTimeZoneID(name, ianaStr.size(), buffer, size, &isSys, &status);
+ // We're only interested if the result is a "system" (i.e. IANA) ID:
+ return isSys;
+}
+
QList<QByteArray> QIcuTimeZonePrivate::availableTimeZoneIds() const
{
UErrorCode status = U_ZERO_ERROR;
diff --git a/src/corelib/time/qtimezoneprivate_mac.mm b/src/corelib/time/qtimezoneprivate_mac.mm
index b051b08ec7..da7e24d614 100644
--- a/src/corelib/time/qtimezoneprivate_mac.mm
+++ b/src/corelib/time/qtimezoneprivate_mac.mm
@@ -19,7 +19,8 @@ QT_BEGIN_NAMESPACE
/*
Private
- OS X system implementation
+ Darwin system implementation
+ https://developer.apple.com/documentation/foundation/nstimezone
*/
// Create the system default time zone
@@ -56,12 +57,10 @@ QMacTimeZonePrivate *QMacTimeZonePrivate::clone() const
void QMacTimeZonePrivate::init(const QByteArray &ianaId)
{
- if (availableTimeZoneIds().contains(ianaId)) {
- m_nstz = [[NSTimeZone timeZoneWithName:QString::fromUtf8(ianaId).toNSString()] retain];
- if (m_nstz)
- m_id = ianaId;
- }
- if (!m_nstz) {
+ m_nstz = [[NSTimeZone timeZoneWithName:QString::fromUtf8(ianaId).toNSString()] retain];
+ if (m_nstz) {
+ m_id = ianaId;
+ } else {
// macOS has been seen returning a systemTimeZone which reports its name
// as Asia/Kolkata, which doesn't appear in knownTimeZoneNames (which
// calls the zone Asia/Calcutta). So explicitly check for the name
@@ -113,7 +112,7 @@ QString QMacTimeZonePrivate::displayName(QTimeZone::TimeType timeType,
style = NSTimeZoneNameStyleStandard;
break;
case QTimeZone::OffsetName :
- // Unreachable
+ Q_UNREACHABLE();
break;
}
@@ -149,7 +148,7 @@ int QMacTimeZonePrivate::daylightTimeOffset(qint64 atMSecsSinceEpoch) const
bool QMacTimeZonePrivate::hasDaylightTime() const
{
- // TODO No Mac API, assume if has transitions
+ // TODO Scan transitions for one after which isDaylightSavingTimeForDate is true.
return hasTransitions();
}
@@ -191,7 +190,7 @@ QTimeZonePrivate::Data QMacTimeZonePrivate::nextTransition(qint64 afterMSecsSinc
const NSTimeInterval nextSecs = nextDate.timeIntervalSince1970;
if (nextDate == nil || nextSecs <= seconds) {
[nextDate release];
- return invalidData();
+ return {};
}
tran.atMSecsSinceEpoch = nextSecs * 1000;
tran.offsetFromUtc = [m_nstz secondsFromGMTForDate:nextDate];
@@ -204,7 +203,7 @@ QTimeZonePrivate::Data QMacTimeZonePrivate::nextTransition(qint64 afterMSecsSinc
QTimeZonePrivate::Data QMacTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch) const
{
// The native API only lets us search forward, so we need to find an early-enough start:
- const NSTimeInterval lowerBound = std::numeric_limits<NSTimeInterval>::lowest();
+ constexpr NSTimeInterval lowerBound = std::numeric_limits<NSTimeInterval>::lowest();
const qint64 endSecs = beforeMSecsSinceEpoch / 1000;
const int year = 366 * 24 * 3600; // a (long) year, in seconds
NSTimeInterval prevSecs = endSecs; // sentinel for later check
@@ -274,7 +273,7 @@ QTimeZonePrivate::Data QMacTimeZonePrivate::previousTransition(qint64 beforeMSec
return data(qint64(prevSecs * 1e3));
// No transition data; or first transition later than requested time.
- return invalidData();
+ return {};
}
QByteArray QMacTimeZonePrivate::systemTimeZoneId() const
@@ -285,6 +284,12 @@ QByteArray QMacTimeZonePrivate::systemTimeZoneId() const
return QString::fromNSString(NSTimeZone.systemTimeZone.name).toUtf8();
}
+bool QMacTimeZonePrivate::isTimeZoneIdAvailable(const QByteArray& ianaId) const
+{
+ QMacAutoReleasePool pool;
+ return [NSTimeZone timeZoneWithName:QString::fromUtf8(ianaId).toNSString()] != nil;
+}
+
QList<QByteArray> QMacTimeZonePrivate::availableTimeZoneIds() const
{
NSEnumerator *enumerator = NSTimeZone.knownTimeZoneNames.objectEnumerator;
diff --git a/src/corelib/time/qtimezoneprivate_p.h b/src/corelib/time/qtimezoneprivate_p.h
index 3cc9fcbcba..506acaa1f7 100644
--- a/src/corelib/time/qtimezoneprivate_p.h
+++ b/src/corelib/time/qtimezoneprivate_p.h
@@ -20,6 +20,7 @@
#include "qlist.h"
#include "qtimezone.h"
#include "private/qlocale_p.h"
+#include "private/qdatetime_p.h"
#if QT_CONFIG(icu)
#include <unicode/ucal.h>
@@ -37,18 +38,32 @@ Q_FORWARD_DECLARE_OBJC_CLASS(NSTimeZone);
#include <QJniObject>
#endif
+QT_REQUIRE_CONFIG(timezone);
QT_BEGIN_NAMESPACE
class Q_AUTOTEST_EXPORT QTimeZonePrivate : public QSharedData
{
public:
- //Version of QTimeZone::OffsetData struct using msecs for efficiency
+ // Version of QTimeZone::OffsetData struct using msecs for efficiency
struct Data {
QString abbreviation;
qint64 atMSecsSinceEpoch;
int offsetFromUtc;
int standardTimeOffset;
int daylightTimeOffset;
+ Data()
+ : atMSecsSinceEpoch(QTimeZonePrivate::invalidMSecs()),
+ offsetFromUtc(QTimeZonePrivate::invalidSeconds()),
+ standardTimeOffset(QTimeZonePrivate::invalidSeconds()),
+ daylightTimeOffset(QTimeZonePrivate::invalidSeconds())
+ {}
+ Data(const QString &name, qint64 when, int offset, int standard)
+ : abbreviation(name),
+ atMSecsSinceEpoch(when),
+ offsetFromUtc(offset),
+ standardTimeOffset(standard),
+ daylightTimeOffset(offset - standard)
+ {}
};
typedef QList<Data> DataList;
@@ -84,7 +99,8 @@ public:
virtual bool isDaylightTime(qint64 atMSecsSinceEpoch) const;
virtual Data data(qint64 forMSecsSinceEpoch) const;
- Data dataForLocalTime(qint64 forLocalMSecs, int hint) const;
+ QDateTimePrivate::ZoneState stateAtZoneTime(qint64 forLocalMSecs,
+ QDateTimePrivate::TransitionOptions resolve) const;
virtual bool hasTransitions() const;
virtual Data nextTransition(qint64 afterMSecsSinceEpoch) const;
@@ -109,7 +125,6 @@ public:
{ return (std::numeric_limits<qint64>::min)(); }
[[nodiscard]] static constexpr qint64 invalidSeconds()
{ return (std::numeric_limits<int>::min)(); }
- static Data invalidData();
static QTimeZone::OffsetData invalidOffsetData();
static QTimeZone::OffsetData toOffsetData(const Data &data);
static bool isValidId(const QByteArray &ianaId);
@@ -159,7 +174,7 @@ public:
virtual ~QUtcTimeZonePrivate();
// Fall-back for UTC[+-]\d+(:\d+){,2} IDs.
- static qint64 offsetFromUtcString(const QByteArray &id);
+ static qint64 offsetFromUtcString(QByteArrayView id);
QUtcTimeZonePrivate *clone() const override;
@@ -168,6 +183,7 @@ public:
QLocale::Territory territory() const override;
QString comment() const override;
+ using QTimeZonePrivate::displayName;
QString displayName(QTimeZone::TimeType timeType,
QTimeZone::NameType nameType,
const QLocale &locale) const override;
@@ -198,6 +214,9 @@ private:
int m_offsetFromUtc;
};
+// TODO: shuffle (almost reverse) order of and rework #if-ery here to use #elif
+// and match the #if-ery in each of QTZ's newBackendTimeZone() cascades for
+// backend selection.
#if QT_CONFIG(icu)
class Q_AUTOTEST_EXPORT QIcuTimeZonePrivate final : public QTimeZonePrivate
{
@@ -214,7 +233,6 @@ public:
using QTimeZonePrivate::displayName;
QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
const QLocale &locale) const override;
- QString abbreviation(qint64 atMSecsSinceEpoch) const override;
int offsetFromUtc(qint64 atMSecsSinceEpoch) const override;
int standardTimeOffset(qint64 atMSecsSinceEpoch) const override;
@@ -231,6 +249,7 @@ public:
QByteArray systemTimeZoneId() const override;
+ bool isTimeZoneIdAvailable(const QByteArray &ianaId) const override;
QList<QByteArray> availableTimeZoneIds() const override;
QList<QByteArray> availableTimeZoneIds(QLocale::Territory territory) const override;
QList<QByteArray> availableTimeZoneIds(int offsetFromUtc) const override;
@@ -240,7 +259,7 @@ private:
UCalendar *m_ucal;
};
-#endif
+#endif // ICU
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && !defined(Q_OS_ANDROID)
struct QTzTransitionTime
@@ -251,9 +270,9 @@ struct QTzTransitionTime
Q_DECLARE_TYPEINFO(QTzTransitionTime, Q_PRIMITIVE_TYPE);
struct QTzTransitionRule
{
- int stdOffset;
- int dstOffset;
- quint8 abbreviationIndex;
+ int stdOffset = 0;
+ int dstOffset = 0;
+ quint8 abbreviationIndex = 0;
};
Q_DECLARE_TYPEINFO(QTzTransitionRule, Q_PRIMITIVE_TYPE);
constexpr inline bool operator==(const QTzTransitionRule &lhs, const QTzTransitionRule &rhs) noexcept
@@ -270,7 +289,7 @@ struct QTzTimeZoneCacheEntry
QList<QByteArray> m_abbreviations;
QByteArray m_posixRule;
QTzTransitionRule m_preZoneRule;
- bool m_hasDst;
+ bool m_hasDst = false;
};
class Q_AUTOTEST_EXPORT QTzTimeZonePrivate final : public QTimeZonePrivate
@@ -288,9 +307,7 @@ public:
QLocale::Territory territory() const override;
QString comment() const override;
- QString displayName(qint64 atMSecsSinceEpoch,
- QTimeZone::NameType nameType,
- const QLocale &locale) const override;
+ using QTimeZonePrivate::displayName;
QString displayName(QTimeZone::TimeType timeType,
QTimeZone::NameType nameType,
const QLocale &locale) const override;
@@ -330,7 +347,7 @@ private:
mutable QExplicitlySharedDataPointer<const QIcuTimeZonePrivate> m_icu;
#endif
QTzTimeZoneCacheEntry cached_data;
- QList<QTzTransitionTime> tranCache() const { return cached_data.m_tranTimes; }
+ const QList<QTzTransitionTime> &tranCache() const { return cached_data.m_tranTimes; }
};
#endif // Q_OS_UNIX
@@ -349,6 +366,7 @@ public:
QString comment() const override;
+ using QTimeZonePrivate::displayName;
QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
const QLocale &locale) const override;
QString abbreviation(qint64 atMSecsSinceEpoch) const override;
@@ -367,7 +385,7 @@ public:
Data previousTransition(qint64 beforeMSecsSinceEpoch) const override;
QByteArray systemTimeZoneId() const override;
-
+ bool isTimeZoneIdAvailable(const QByteArray &ianaId) const override;
QList<QByteArray> availableTimeZoneIds() const override;
NSTimeZone *nsTimeZone() const;
@@ -379,7 +397,7 @@ private:
};
#endif // Q_OS_DARWIN
-#ifdef Q_OS_WIN
+#if defined(Q_OS_WIN) && !QT_CONFIG(icu)
class Q_AUTOTEST_EXPORT QWinTimeZonePrivate final : public QTimeZonePrivate
{
public:
@@ -402,6 +420,7 @@ public:
QString comment() const override;
+ using QTimeZonePrivate::displayName;
QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
const QLocale &locale) const override;
QString abbreviation(qint64 atMSecsSinceEpoch) const override;
@@ -435,7 +454,7 @@ private:
QString m_daylightName;
QList<QWinTransitionRule> m_tranRules;
};
-#endif // Q_OS_WIN
+#endif // Q_OS_WIN && !icu
#ifdef Q_OS_ANDROID
class QAndroidTimeZonePrivate final : public QTimeZonePrivate
@@ -450,6 +469,7 @@ public:
QAndroidTimeZonePrivate *clone() const override;
+ using QTimeZonePrivate::displayName;
QString displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType,
const QLocale &locale) const override;
QString abbreviation(qint64 atMSecsSinceEpoch) const override;
@@ -464,7 +484,7 @@ public:
Data data(qint64 forMSecsSinceEpoch) const override;
QByteArray systemTimeZoneId() const override;
-
+ bool isTimeZoneIdAvailable(const QByteArray &ianaId) const override;
QList<QByteArray> availableTimeZoneIds() const override;
private:
diff --git a/src/corelib/time/qtimezoneprivate_tz.cpp b/src/corelib/time/qtimezoneprivate_tz.cpp
index 95b5894c3f..f6156fe93e 100644
--- a/src/corelib/time/qtimezoneprivate_tz.cpp
+++ b/src/corelib/time/qtimezoneprivate_tz.cpp
@@ -10,6 +10,7 @@
#include <QtCore/QDataStream>
#include <QtCore/QDateTime>
+#include <QtCore/QDirListing>
#include <QtCore/QFile>
#include <QtCore/QCache>
#include <QtCore/QMap>
@@ -19,6 +20,8 @@
#include <qplatformdefs.h>
#include <algorithm>
+#include <memory>
+
#include <errno.h>
#include <limits.h>
#ifndef Q_OS_INTEGRITY
@@ -41,22 +44,50 @@ Q_CONSTINIT static QBasicMutex s_icu_mutex;
*/
struct QTzTimeZone {
- QLocale::Territory territory;
+ QLocale::Territory territory = QLocale::AnyTerritory;
QByteArray comment;
};
// Define as a type as Q_GLOBAL_STATIC doesn't like it
typedef QHash<QByteArray, QTzTimeZone> QTzTimeZoneHash;
-// Parse zone.tab table, assume lists all installed zones, if not will need to read directories
-static QTzTimeZoneHash loadTzTimeZones()
+static bool isTzFile(const QString &name);
+
+// Open a named file under the zone info directory:
+static bool openZoneInfo(const QString &name, QFile *file)
{
- QString path = QStringLiteral("/usr/share/zoneinfo/zone.tab");
- if (!QFile::exists(path))
- path = QStringLiteral("/usr/lib/zoneinfo/zone.tab");
+ // At least on Linux / glibc (see man 3 tzset), $TZDIR overrides the system
+ // default location for zone info:
+ const QString tzdir = qEnvironmentVariable("TZDIR");
+ if (!tzdir.isEmpty()) {
+ file->setFileName(QDir(tzdir).filePath(name));
+ if (file->open(QIODevice::ReadOnly))
+ return true;
+ }
+ // Try modern system path first:
+ constexpr auto zoneShare = "/usr/share/zoneinfo/"_L1;
+ if (tzdir != zoneShare && tzdir != zoneShare.chopped(1)) {
+ file->setFileName(zoneShare + name);
+ if (file->open(QIODevice::ReadOnly))
+ return true;
+ }
+ // Fall back to legacy system path:
+ constexpr auto zoneLib = "/usr/lib/zoneinfo/"_L1;
+ if (tzdir != zoneLib && tzdir != zoneLib.chopped(1)) {
+ file->setFileName(zoneShare + name);
+ if (file->open(QIODevice::ReadOnly))
+ return true;
+ }
+ return false;
+}
- QFile tzif(path);
- if (!tzif.open(QIODevice::ReadOnly))
+// Parse zone.tab table for territory information, read directories to ensure we
+// find all installed zones (many are omitted from zone.tab; even more from
+// zone1970.tab).
+static QTzTimeZoneHash loadTzTimeZones()
+{
+ QFile tzif;
+ if (!openZoneInfo("zone.tab"_L1, &tzif))
return QTzTimeZoneHash();
QTzTimeZoneHash zonesHash;
@@ -85,6 +116,27 @@ static QTzTimeZoneHash loadTzTimeZones()
}
}
}
+
+ const QString path = tzif.fileName();
+ const qsizetype cut = path.lastIndexOf(u'/');
+ Q_ASSERT(cut > 0);
+ const QDir zoneDir = QDir(path.first(cut));
+ for (const auto &info : QDirListing(zoneDir, QDirListing::IteratorFlag::Recursive)) {
+ if (!(info.isFile() || info.isSymLink()))
+ continue;
+ const QString name = zoneDir.relativeFilePath(info.filePath());
+ // Two sub-directories containing (more or less) copies of the zoneinfo tree.
+ if (info.isDir() ? name == "posix"_L1 || name == "right"_L1
+ : name.startsWith("posix/"_L1) || name.startsWith("right/"_L1)) {
+ continue;
+ }
+ // We could filter out *.* and leapseconds instead of doing the
+ // isTzFile() check; in practice current (2023) zoneinfo/ contains only
+ // actual zone files and matches to that filter.
+ const QByteArray id = QFile::encodeName(name);
+ if (!zonesHash.contains(id) && isTzFile(zoneDir.absoluteFilePath(name)))
+ zonesHash.insert(id, QTzTimeZone());
+ }
return zonesHash;
}
@@ -128,6 +180,11 @@ struct QTzType {
};
Q_DECLARE_TYPEINFO(QTzType, Q_PRIMITIVE_TYPE);
+static bool isTzFile(const QString &name)
+{
+ QFile file(name);
+ return file.open(QFile::ReadOnly) && file.read(strlen(TZ_MAGIC)) == TZ_MAGIC;
+}
// TZ File parsing
@@ -352,13 +409,15 @@ static QDate calculateDowDate(int year, int month, int dayOfWeek, int week)
static QDate calculatePosixDate(const QByteArray &dateRule, int year)
{
+ Q_ASSERT(!dateRule.isEmpty());
bool ok;
// Can start with M, J, or a digit
if (dateRule.at(0) == 'M') {
// nth week in month format "Mmonth.week.dow"
QList<QByteArray> dateParts = dateRule.split('.');
if (dateParts.size() > 2) {
- int month = dateParts.at(0).mid(1).toInt(&ok);
+ Q_ASSERT(!dateParts.at(0).isEmpty()); // the 'M' is its [0].
+ int month = QByteArrayView{ dateParts.at(0) }.sliced(1).toInt(&ok);
int week = ok ? dateParts.at(1).toInt(&ok) : 0;
int dow = ok ? dateParts.at(2).toInt(&ok) : 0;
if (ok)
@@ -367,7 +426,7 @@ static QDate calculatePosixDate(const QByteArray &dateRule, int year)
} else if (dateRule.at(0) == 'J') {
// Day of Year 1...365, ignores Feb 29.
// So March always starts on day 60.
- int doy = dateRule.mid(1).toInt(&ok);
+ int doy = QByteArrayView{ dateRule }.sliced(1).toInt(&ok);
if (ok && doy > 0 && doy < 366) {
// Subtract 1 because we're adding days *after* the first of
// January, unless it's after February in a leap year, when the leap
@@ -462,12 +521,20 @@ struct PosixZone
};
QString name;
- int offset;
+ int offset = InvalidOffset;
+ bool hasValidOffset() const noexcept { return offset != InvalidOffset; }
+ QTimeZonePrivate::Data dataAt(qint64 when)
+ {
+ Q_ASSERT(hasValidOffset());
+ return QTimeZonePrivate::Data(name, when, offset, offset);
+ }
+ QTimeZonePrivate::Data dataAtOffset(qint64 when, int standard)
+ {
+ Q_ASSERT(hasValidOffset());
+ return QTimeZonePrivate::Data(name, when, offset, standard);
+ }
- static PosixZone invalid() { return {QString(), InvalidOffset}; }
static PosixZone parse(const char *&pos, const char *end);
-
- bool hasValidOffset() const noexcept { return offset != InvalidOffset; }
};
} // unnamed namespace
@@ -498,7 +565,7 @@ PosixZone PosixZone::parse(const char *&pos, const char *end)
pos = nameEnd;
}
if (nameEnd - nameBegin < 3)
- return invalid(); // name must be at least 3 characters long
+ return {}; // name must be at least 3 characters long
// zone offset, form [+-]hh:mm:ss
const char *zoneBegin = pos;
@@ -517,7 +584,7 @@ PosixZone PosixZone::parse(const char *&pos, const char *end)
// UTC+hh:mm:ss or GMT+hh:mm:ss should be read as offsets from UTC, not as a
// POSIX rule naming a zone as UTC or GMT and specifying a non-zero offset.
if (offset != 0 && (name =="UTC"_L1 || name == "GMT"_L1))
- return invalid();
+ return {};
return {std::move(name), offset};
}
@@ -587,7 +654,7 @@ static QList<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArray
// and the link in validatePosixRule(), above.
QList<QByteArray> parts = posixRule.split(',');
- PosixZone stdZone, dstZone = PosixZone::invalid();
+ PosixZone stdZone, dstZone;
{
const QByteArray &zoneinfo = parts.at(0);
const char *begin = zoneinfo.constBegin();
@@ -606,13 +673,9 @@ static QList<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArray
// If only the name part, or no DST specified, then no transitions
if (parts.size() == 1 || !dstZone.hasValidOffset()) {
- QTimeZonePrivate::Data data;
- data.atMSecsSinceEpoch = lastTranMSecs;
- data.offsetFromUtc = stdZone.offset;
- data.standardTimeOffset = stdZone.offset;
- data.daylightTimeOffset = 0;
- data.abbreviation = stdZone.name.isEmpty() ? QString::fromUtf8(parts.at(0)) : stdZone.name;
- result << data;
+ result.emplaceBack(
+ stdZone.name.isEmpty() ? QString::fromUtf8(parts.at(0)) : stdZone.name,
+ lastTranMSecs, stdZone.offset, stdZone.offset);
return result;
}
if (parts.size() < 3 || parts.at(1).isEmpty() || parts.at(2).isEmpty())
@@ -645,40 +708,33 @@ static QList<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArray
// moments; the atMSecsSinceEpoch values computed from them are
// correctly offse to be UTC-based.
- QTimeZonePrivate::Data dstData; // Transition to DST
+ // Transition to daylight-saving time:
QDateTime dst(calculatePosixDate(dstDateRule, year)
.startOfDay(QTimeZone::UTC).addSecs(dstTime));
- 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; // Transition to standard time
+ auto saving = dstZone.dataAtOffset(dst.toMSecsSinceEpoch() - stdZone.offset * 1000,
+ stdZone.offset);
+ // Transition to standard time:
QDateTime std(calculatePosixDate(stdDateRule, year)
.startOfDay(QTimeZone::UTC).addSecs(stdTime));
- stdData.atMSecsSinceEpoch = std.toMSecsSinceEpoch() - dstZone.offset * 1000;
- stdData.offsetFromUtc = stdZone.offset;
- stdData.standardTimeOffset = stdZone.offset;
- stdData.daylightTimeOffset = 0;
- stdData.abbreviation = stdZone.name;
+ auto standard = stdZone.dataAt(std.toMSecsSinceEpoch() - dstZone.offset * 1000);
if (year == startYear) {
// Handle the special case of fixed state, which may be represented
// by fake transitions at start and end of each year:
- if (dstData.atMSecsSinceEpoch < stdData.atMSecsSinceEpoch) {
+ if (saving.atMSecsSinceEpoch < standard.atMSecsSinceEpoch) {
if (dst <= QDate(year, 1, 1).startOfDay(QTimeZone::UTC)
&& std >= QDate(year, 12, 31).endOfDay(QTimeZone::UTC)) {
// Permanent DST:
- dstData.atMSecsSinceEpoch = lastTranMSecs;
- result << dstData;
+ saving.atMSecsSinceEpoch = lastTranMSecs;
+ result.emplaceBack(std::move(saving));
return result;
}
} else {
if (std <= QDate(year, 1, 1).startOfDay(QTimeZone::UTC)
&& dst >= QDate(year, 12, 31).endOfDay(QTimeZone::UTC)) {
// Permanent Standard time, perversely described:
- stdData.atMSecsSinceEpoch = lastTranMSecs;
- result << stdData;
+ standard.atMSecsSinceEpoch = lastTranMSecs;
+ result.emplaceBack(std::move(standard));
return result;
}
}
@@ -687,14 +743,17 @@ static QList<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArray
const bool useStd = std.isValid() && std.date().year() == year && !stdZone.name.isEmpty();
const bool useDst = dst.isValid() && dst.date().year() == year && !dstZone.name.isEmpty();
if (useStd && useDst) {
- if (dst < std)
- result << dstData << stdData;
- else
- result << stdData << dstData;
+ if (dst < std) {
+ result.emplaceBack(std::move(saving));
+ result.emplaceBack(std::move(standard));
+ } else {
+ result.emplaceBack(std::move(standard));
+ result.emplaceBack(std::move(saving));
+ }
} else if (useStd) {
- result << stdData;
+ result.emplaceBack(std::move(standard));
} else if (useDst) {
- result << dstData;
+ result.emplaceBack(std::move(saving));
}
}
return result;
@@ -724,7 +783,7 @@ public:
QTzTimeZoneCacheEntry fetchEntry(const QByteArray &ianaId);
private:
- QTzTimeZoneCacheEntry findEntry(const QByteArray &ianaId);
+ static QTzTimeZoneCacheEntry findEntry(const QByteArray &ianaId);
QCache<QByteArray, QTzTimeZoneCacheEntry> m_cache;
QMutex m_mutex;
};
@@ -738,21 +797,14 @@ QTzTimeZoneCacheEntry QTzTimeZoneCache::findEntry(const QByteArray &ianaId)
tzif.setFileName(QStringLiteral("/etc/localtime"));
if (!tzif.open(QIODevice::ReadOnly))
return ret;
- } else {
- // Open named tz, try modern path first, if fails try legacy path
- tzif.setFileName("/usr/share/zoneinfo/"_L1 + QString::fromLocal8Bit(ianaId));
- if (!tzif.open(QIODevice::ReadOnly)) {
- tzif.setFileName("/usr/lib/zoneinfo/"_L1 + QString::fromLocal8Bit(ianaId));
- if (!tzif.open(QIODevice::ReadOnly)) {
- // ianaId may be a POSIX rule, taken from $TZ or /etc/TZ
- auto check = validatePosixRule(ianaId);
- if (check.isValid) {
- ret.m_hasDst = check.hasDst;
- ret.m_posixRule = ianaId;
- }
- return ret;
- }
+ } else if (!openZoneInfo(QString::fromLocal8Bit(ianaId), &tzif)) {
+ // ianaId may be a POSIX rule, taken from $TZ or /etc/TZ
+ auto check = validatePosixRule(ianaId);
+ if (check.isValid) {
+ ret.m_hasDst = check.hasDst;
+ ret.m_posixRule = ianaId;
}
+ return ret;
}
QDataStream ds(&tzif);
@@ -832,8 +884,6 @@ QTzTimeZoneCacheEntry QTzTimeZoneCache::findEntry(const QByteArray &ianaId)
// TODO: is typeList[0] always the "before zones" data ? It seems to be ...
if (typeList.size())
ret.m_preZoneRule = { typeList.at(0).tz_gmtoff, 0, typeList.at(0).tz_abbrind };
- else
- ret.m_preZoneRule = { 0, 0, 0 };
// Offsets are stored as total offset, want to know separate UTC and DST offsets
// so find the first non-dst transition to use as base UTC Offset
@@ -846,7 +896,7 @@ QTzTimeZoneCacheEntry QTzTimeZoneCache::findEntry(const QByteArray &ianaId)
}
// Now for each transition time calculate and store our rule:
- const int tranCount = tranList.size();;
+ const int tranCount = tranList.size();
ret.m_tranTimes.reserve(tranCount);
// The DST offset when in effect: usually stable, usually an hour:
int lastDstOff = 3600;
@@ -905,8 +955,8 @@ QTzTimeZoneCacheEntry QTzTimeZoneCache::findEntry(const QByteArray &ianaId)
if (ruleIndex == -1) {
if (rule.dstOffset != 0)
ret.m_hasDst = true;
+ tran.ruleIndex = ret.m_tranRules.size();
ret.m_tranRules.append(rule);
- tran.ruleIndex = ret.m_tranRules.size() - 1;
} else {
tran.ruleIndex = ruleIndex;
}
@@ -928,14 +978,24 @@ QTzTimeZoneCacheEntry QTzTimeZoneCache::fetchEntry(const QByteArray &ianaId)
return *obj;
// ... or build a new entry from scratch
+
+ locker.unlock(); // don't parse files under mutex lock
+
QTzTimeZoneCacheEntry ret = findEntry(ianaId);
- m_cache.insert(ianaId, new QTzTimeZoneCacheEntry(ret));
+ auto ptr = std::make_unique<QTzTimeZoneCacheEntry>(ret);
+
+ locker.relock();
+ m_cache.insert(ianaId, ptr.release()); // may overwrite if another thread was faster
+ locker.unlock();
+
return ret;
}
// Create a named time zone
QTzTimeZonePrivate::QTzTimeZonePrivate(const QByteArray &ianaId)
{
+ if (!isTimeZoneIdAvailable(ianaId)) // Avoid pointlessly creating cache entries
+ return;
static QTzTimeZoneCache tzCache;
auto entry = tzCache.fetchEntry(ianaId);
if (entry.m_tranTimes.isEmpty() && entry.m_posixRule.isEmpty())
@@ -970,46 +1030,27 @@ QString QTzTimeZonePrivate::comment() const
return QString::fromUtf8(tzZones->value(m_id).comment);
}
-QString QTzTimeZonePrivate::displayName(qint64 atMSecsSinceEpoch,
- QTimeZone::NameType nameType,
- const QLocale &locale) const
-{
-#if QT_CONFIG(icu)
- auto lock = qt_unique_lock(s_icu_mutex);
- if (!m_icu)
- m_icu = new QIcuTimeZonePrivate(m_id);
- // TODO small risk may not match if tran times differ due to outdated files
- // TODO Some valid TZ names are not valid ICU names, use translation table?
- if (m_icu->isValid())
- return m_icu->displayName(atMSecsSinceEpoch, nameType, locale);
- lock.unlock();
-#else
- Q_UNUSED(nameType);
- Q_UNUSED(locale);
-#endif
- // Fall back to base-class:
- return QTimeZonePrivate::displayName(atMSecsSinceEpoch, nameType, locale);
-}
-
QString QTzTimeZonePrivate::displayName(QTimeZone::TimeType timeType,
QTimeZone::NameType nameType,
const QLocale &locale) const
{
+ // TZ DB lacks localized names (it only has IANA IDs), so delegate to ICU
+ // for those, when available.
#if QT_CONFIG(icu)
- auto lock = qt_unique_lock(s_icu_mutex);
- if (!m_icu)
- m_icu = new QIcuTimeZonePrivate(m_id);
- // TODO small risk may not match if tran times differ due to outdated files
- // TODO Some valid TZ names are not valid ICU names, use translation table?
- if (m_icu->isValid())
- return m_icu->displayName(timeType, nameType, locale);
- lock.unlock();
+ {
+ auto lock = qt_scoped_lock(s_icu_mutex);
+ // TODO Some valid TZ names are not valid ICU names, use translation table?
+ if (!m_icu)
+ m_icu = new QIcuTimeZonePrivate(m_id);
+ if (m_icu->isValid())
+ return m_icu->displayName(timeType, nameType, locale);
+ }
#else
Q_UNUSED(timeType);
Q_UNUSED(nameType);
Q_UNUSED(locale);
#endif
- // If no ICU available then have to use abbreviations instead
+ // If ICU is unavailable, fall back to abbreviations.
// Abbreviations don't have GenericTime
if (timeType == QTimeZone::GenericTime)
timeType = QTimeZone::StandardTime;
@@ -1098,8 +1139,8 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::dataForTzTransition(QTzTransitionTime
QTimeZonePrivate::Data QTzTimeZonePrivate::dataFromRule(QTzTransitionRule rule,
qint64 msecsSinceEpoch) const
{
- return { QString::fromUtf8(cached_data.m_abbreviations.at(rule.abbreviationIndex)),
- msecsSinceEpoch, rule.stdOffset + rule.dstOffset, rule.stdOffset, rule.dstOffset };
+ return Data(QString::fromUtf8(cached_data.m_abbreviations.at(rule.abbreviationIndex)),
+ msecsSinceEpoch, rule.stdOffset + rule.dstOffset, rule.stdOffset);
}
QList<QTimeZonePrivate::Data> QTzTimeZonePrivate::getPosixTransitions(qint64 msNear) const
@@ -1129,7 +1170,7 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const
}
}
if (tranCache().isEmpty()) // Only possible if !isValid()
- return invalidData();
+ return {};
// Otherwise, use the rule for the most recent or first transition:
auto last = std::partition_point(tranCache().cbegin(), tranCache().cend(),
@@ -1160,7 +1201,7 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::nextTransition(qint64 afterMSecsSince
return at.atMSecsSinceEpoch <= afterMSecsSinceEpoch;
});
- return it == posixTrans.cend() ? invalidData() : *it;
+ return it == posixTrans.cend() ? Data{} : *it;
}
// Otherwise, if we can find a valid tran, use its rule:
@@ -1168,7 +1209,7 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::nextTransition(qint64 afterMSecsSince
[afterMSecsSinceEpoch] (const QTzTransitionTime &at) {
return at.atMSecsSinceEpoch <= afterMSecsSinceEpoch;
});
- return last != tranCache().cend() ? dataForTzTransition(*last) : invalidData();
+ return last != tranCache().cend() ? dataForTzTransition(*last) : Data{};
}
QTimeZonePrivate::Data QTzTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch) const
@@ -1185,7 +1226,7 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::previousTransition(qint64 beforeMSecs
if (it > posixTrans.cbegin())
return *--it;
// It fell between the last transition (if any) and the first of the POSIX rule:
- return tranCache().isEmpty() ? invalidData() : dataForTzTransition(tranCache().last());
+ return tranCache().isEmpty() ? Data{} : dataForTzTransition(tranCache().last());
}
// Otherwise if we can find a valid tran then use its rule
@@ -1193,7 +1234,7 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::previousTransition(qint64 beforeMSecs
[beforeMSecsSinceEpoch] (const QTzTransitionTime &at) {
return at.atMSecsSinceEpoch < beforeMSecsSinceEpoch;
});
- return last > tranCache().cbegin() ? dataForTzTransition(*--last) : invalidData();
+ return last > tranCache().cbegin() ? dataForTzTransition(*--last) : Data{};
}
bool QTzTimeZonePrivate::isTimeZoneIdAvailable(const QByteArray &ianaId) const
@@ -1298,7 +1339,8 @@ private:
{
// On most distros /etc/localtime is a symlink to a real file so extract
// name from the path
- const auto zoneinfo = "/zoneinfo/"_L1;
+ const QString tzdir = qEnvironmentVariable("TZDIR");
+ constexpr auto zoneinfo = "/zoneinfo/"_L1;
QString path = QStringLiteral("/etc/localtime");
long iteration = getSymloopMax();
// Symlink may point to another symlink etc. before being under zoneinfo/
@@ -1306,9 +1348,15 @@ private:
// symlink, like America/Montreal pointing to America/Toronto
do {
path = QFile::symLinkTarget(path);
- int index = path.indexOf(zoneinfo);
- if (index >= 0) // Found zoneinfo file; extract zone name from path:
- return QStringView{ path }.mid(index + zoneinfo.size()).toUtf8();
+ // If it's a zoneinfo file, extract the zone name from its path:
+ int index = tzdir.isEmpty() ? -1 : path.indexOf(tzdir);
+ if (index >= 0) {
+ const auto tail = QStringView{ path }.sliced(index + tzdir.size()).toUtf8();
+ return tail.startsWith(u'/') ? tail.sliced(1) : tail;
+ }
+ index = path.indexOf(zoneinfo);
+ if (index >= 0)
+ return QStringView{ path }.sliced(index + zoneinfo.size()).toUtf8();
} while (!path.isEmpty() && --iteration > 0);
return QByteArray();
@@ -1365,7 +1413,7 @@ QByteArray QTzTimeZonePrivate::staticSystemTimeZoneId()
if (ianaId == ":/etc/localtime")
ianaId.clear();
else if (ianaId.startsWith(':'))
- ianaId = ianaId.mid(1);
+ ianaId = ianaId.sliced(1);
if (ianaId.isEmpty()) {
Q_CONSTINIT thread_local static ZoneNameReader reader;
diff --git a/src/corelib/time/qtimezoneprivate_win.cpp b/src/corelib/time/qtimezoneprivate_win.cpp
index 7c5249ef5b..7874c22174 100644
--- a/src/corelib/time/qtimezoneprivate_win.cpp
+++ b/src/corelib/time/qtimezoneprivate_win.cpp
@@ -186,22 +186,24 @@ bool isSameRule(const QWinTimeZonePrivate::QWinTransitionRule &last,
QList<QByteArray> availableWindowsIds()
{
- // TODO Consider caching results in a global static, very unlikely to change.
- QList<QByteArray> list;
- QWinRegistryKey key(HKEY_LOCAL_MACHINE, tzRegPath);
- if (key.isValid()) {
- DWORD idCount = 0;
- if (RegQueryInfoKey(key, 0, 0, 0, &idCount, 0, 0, 0, 0, 0, 0, 0) == ERROR_SUCCESS
- && idCount > 0) {
- for (DWORD i = 0; i < idCount; ++i) {
- DWORD maxLen = MAX_KEY_LENGTH;
- TCHAR buffer[MAX_KEY_LENGTH];
- if (RegEnumKeyEx(key, i, buffer, &maxLen, 0, 0, 0, 0) == ERROR_SUCCESS)
- list.append(QString::fromWCharArray(buffer).toUtf8());
+ static const QList<QByteArray> cache = [] {
+ QList<QByteArray> list;
+ QWinRegistryKey key(HKEY_LOCAL_MACHINE, tzRegPath);
+ if (key.isValid()) {
+ DWORD idCount = 0;
+ if (RegQueryInfoKey(key, 0, 0, 0, &idCount, 0, 0, 0, 0, 0, 0, 0) == ERROR_SUCCESS
+ && idCount > 0) {
+ for (DWORD i = 0; i < idCount; ++i) {
+ DWORD maxLen = MAX_KEY_LENGTH;
+ TCHAR buffer[MAX_KEY_LENGTH];
+ if (RegEnumKeyEx(key, i, buffer, &maxLen, 0, 0, 0, 0) == ERROR_SUCCESS)
+ list.append(QString::fromWCharArray(buffer).toUtf8());
+ }
}
}
- }
- return list;
+ return list;
+ }();
+ return cache;
}
QByteArray windowsSystemZoneId()
@@ -275,8 +277,8 @@ inline bool timeToMSecs(QDate date, QTime time, qint64 *msecs)
++daySinceEpoch;
msInDay -= MSECS_PER_DAY;
}
- return mul_overflow(daySinceEpoch, std::integral_constant<qint64, MSECS_PER_DAY>(), &dayms)
- || add_overflow(dayms, msInDay, msecs);
+ return qMulOverflow(daySinceEpoch, std::integral_constant<qint64, MSECS_PER_DAY>(), &dayms)
+ || qAddOverflow(dayms, msInDay, msecs);
}
qint64 calculateTransitionForYear(const SYSTEMTIME &rule, int year, int bias)
@@ -291,7 +293,7 @@ qint64 calculateTransitionForYear(const SYSTEMTIME &rule, int year, int bias)
// If bias pushes us outside the representable range, clip to range
// (overflow went past the end bias pushed us towards; and
// invalidMSecs() is a representable value less than minMSecs()):
- return bias && add_overflow(msecs, qint64(bias) * 60000, &msecs)
+ return bias && qAddOverflow(msecs, qint64(bias) * 60000, &msecs)
? (bias < 0 ? QTimeZonePrivate::minMSecs() : QTimeZonePrivate::maxMSecs())
: qMax(QTimeZonePrivate::minMSecs(), msecs);
}
@@ -690,7 +692,7 @@ QTimeZonePrivate::Data QWinTimeZonePrivate::data(qint64 forMSecsSinceEpoch) cons
// Fell off start of rule, try previous rule.
}
// We don't have relevant data :-(
- return invalidData();
+ return {};
}
bool QWinTimeZonePrivate::hasTransitions() const
@@ -772,13 +774,13 @@ QTimeZonePrivate::Data QWinTimeZonePrivate::nextTransition(qint64 afterMSecsSinc
}
}
// Apparently no transition after the given time:
- return invalidData();
+ return {};
}
QTimeZonePrivate::Data QWinTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch) const
{
if (beforeMSecsSinceEpoch <= minMSecs())
- return invalidData();
+ return {};
int year = msecsToDate(beforeMSecsSinceEpoch).year();
for (int ruleIndex = ruleIndexForYear(m_tranRules, year);
@@ -828,7 +830,7 @@ QTimeZonePrivate::Data QWinTimeZonePrivate::previousTransition(qint64 beforeMSec
}
}
// Apparently no transition before the given time:
- return invalidData();
+ return {};
}
QByteArray QWinTimeZonePrivate::systemTimeZoneId() const
@@ -847,13 +849,16 @@ QByteArray QWinTimeZonePrivate::systemTimeZoneId() const
QList<QByteArray> QWinTimeZonePrivate::availableTimeZoneIds() const
{
- QList<QByteArray> result;
- const auto winIds = availableWindowsIds();
- for (const QByteArray &winId : winIds)
- result += windowsIdToIanaIds(winId);
- std::sort(result.begin(), result.end());
- result.erase(std::unique(result.begin(), result.end()), result.end());
- return result;
+ static const QList<QByteArray> cache = [] {
+ QList<QByteArray> result;
+ const auto winIds = availableWindowsIds();
+ for (const QByteArray &winId : winIds)
+ result += windowsIdToIanaIds(winId);
+ std::sort(result.begin(), result.end());
+ result.erase(std::unique(result.begin(), result.end()), result.end());
+ return result;
+ }();
+ return cache;
}
QTimeZonePrivate::Data QWinTimeZonePrivate::ruleToData(const QWinTransitionRule &rule,
@@ -861,7 +866,7 @@ QTimeZonePrivate::Data QWinTimeZonePrivate::ruleToData(const QWinTransitionRule
QTimeZone::TimeType type,
bool fakeDst) const
{
- Data tran = invalidData();
+ Data tran;
tran.atMSecsSinceEpoch = atMSecsSinceEpoch;
tran.standardTimeOffset = rule.standardTimeBias * -60;
if (fakeDst) {
diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp
index b1634d61b5..6aebd4306a 100644
--- a/src/corelib/tools/qarraydata.cpp
+++ b/src/corelib/tools/qarraydata.cpp
@@ -54,8 +54,8 @@ qsizetype qCalculateBlockSize(qsizetype elementCount, qsizetype elementSize, qsi
Q_ASSERT(elementSize);
size_t bytes;
- if (Q_UNLIKELY(mul_overflow(size_t(elementSize), size_t(elementCount), &bytes)) ||
- Q_UNLIKELY(add_overflow(bytes, size_t(headerSize), &bytes)))
+ if (Q_UNLIKELY(qMulOverflow(size_t(elementSize), size_t(elementCount), &bytes)) ||
+ Q_UNLIKELY(qAddOverflow(bytes, size_t(headerSize), &bytes)))
return -1;
if (Q_UNLIKELY(qsizetype(bytes) < 0))
return -1;
@@ -107,33 +107,30 @@ qCalculateGrowingBlockSize(qsizetype elementCount, qsizetype elementSize, qsizet
return result;
}
-/*!
- \internal
+/*
+ Calculate the byte size for a block of \a capacity objects of size \a
+ objectSize, with a header of size \a headerSize. If the \a option is
+ QArrayData::Grow, the capacity itself adjusted up, preallocating room for
+ more elements to be added later; otherwise, it is an exact calculation.
- Returns \a allocSize plus extra reserved bytes necessary to store '\0'.
- */
-static inline qsizetype reserveExtraBytes(qsizetype allocSize)
+ Returns a structure containing the size in bytes and elements available.
+*/
+static inline CalculateGrowingBlockSizeResult
+calculateBlockSize(qsizetype capacity, qsizetype objectSize, qsizetype headerSize, QArrayData::AllocationOption option)
{
- // We deal with QByteArray and QString only
- constexpr qsizetype extra = qMax(sizeof(QByteArray::value_type), sizeof(QString::value_type));
- if (Q_UNLIKELY(allocSize < 0))
- return -1;
- if (Q_UNLIKELY(add_overflow(allocSize, extra, &allocSize)))
- return -1;
- return allocSize;
-}
+ // Adjust the header size up to account for the trailing null for QString
+ // and QByteArray. This is not checked for overflow because headers sizes
+ // should not be anywhere near the overflow limit.
+ constexpr qsizetype FooterSize = qMax(sizeof(QString::value_type), sizeof(QByteArray::value_type));
+ if (objectSize <= FooterSize)
+ headerSize += FooterSize;
-static inline qsizetype calculateBlockSize(qsizetype &capacity, qsizetype objectSize, qsizetype headerSize, QArrayData::AllocationOption option)
-{
- // Calculate the byte size
// allocSize = objectSize * capacity + headerSize, but checked for overflow
// plus padded to grow in size
if (option == QArrayData::Grow) {
- auto r = qCalculateGrowingBlockSize(capacity, objectSize, headerSize);
- capacity = r.elementCount;
- return r.size;
+ return qCalculateGrowingBlockSize(capacity, objectSize, headerSize);
} else {
- return qCalculateBlockSize(capacity, objectSize, headerSize);
+ return { qCalculateBlockSize(capacity, objectSize, headerSize), capacity };
}
}
@@ -148,27 +145,20 @@ static QArrayData *allocateData(qsizetype allocSize)
return header;
}
-
namespace {
-// QArrayData with strictest alignment requirements supported by malloc()
-struct alignas(std::max_align_t) AlignedQArrayData : QArrayData
-{
+struct AllocationResult {
+ void *data;
+ QArrayData *header;
};
}
+using QtPrivate::AlignedQArrayData;
-
-void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype alignment,
- qsizetype capacity, QArrayData::AllocationOption option) noexcept
+static inline AllocationResult
+allocateHelper(qsizetype objectSize, qsizetype alignment, qsizetype capacity,
+ QArrayData::AllocationOption option) noexcept
{
- Q_ASSERT(dptr);
- // Alignment is a power of two
- Q_ASSERT(alignment >= qsizetype(alignof(QArrayData))
- && !(alignment & (alignment - 1)));
-
- if (capacity == 0) {
- *dptr = nullptr;
- return nullptr;
- }
+ if (capacity == 0)
+ return {};
qsizetype headerSize = sizeof(AlignedQArrayData);
const qsizetype headerAlignment = alignof(AlignedQArrayData);
@@ -177,16 +167,16 @@ void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype al
// Allocate extra (alignment - Q_ALIGNOF(AlignedQArrayData)) padding
// bytes so we can properly align the data array. This assumes malloc is
// able to provide appropriate alignment for the header -- as it should!
+ // Effectively, we allocate one QTypedArrayData<T>::AlignmentDummy.
headerSize += alignment - headerAlignment;
}
Q_ASSERT(headerSize > 0);
- qsizetype allocSize = calculateBlockSize(capacity, objectSize, headerSize, option);
- allocSize = reserveExtraBytes(allocSize);
- if (Q_UNLIKELY(allocSize < 0)) { // handle overflow. cannot allocate reliably
- *dptr = nullptr;
- return nullptr;
- }
+ auto blockSize = calculateBlockSize(capacity, objectSize, headerSize, option);
+ capacity = blockSize.elementCount;
+ qsizetype allocSize = blockSize.size;
+ if (Q_UNLIKELY(allocSize < 0)) // handle overflow. cannot allocate reliably
+ return {};
QArrayData *header = allocateData(allocSize);
void *data = nullptr;
@@ -196,20 +186,54 @@ void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype al
header->alloc = qsizetype(capacity);
}
- *dptr = header;
- return data;
+ return { data, header };
}
-QPair<QArrayData *, void *>
+// Generic size and alignment allocation function
+void *QArrayData::allocate(QArrayData **dptr, qsizetype objectSize, qsizetype alignment,
+ qsizetype capacity, AllocationOption option) noexcept
+{
+ Q_ASSERT(dptr);
+ // Alignment is a power of two
+ Q_ASSERT(alignment >= qsizetype(alignof(QArrayData))
+ && !(alignment & (alignment - 1)));
+
+ auto r = allocateHelper(objectSize, alignment, capacity, option);
+ *dptr = r.header;
+ return r.data;
+}
+
+// Fixed size and alignment allocation functions
+void *QArrayData::allocate1(QArrayData **dptr, qsizetype capacity, AllocationOption option) noexcept
+{
+ Q_ASSERT(dptr);
+
+ auto r = allocateHelper(1, alignof(AlignedQArrayData), capacity, option);
+ *dptr = r.header;
+ return r.data;
+}
+
+void *QArrayData::allocate2(QArrayData **dptr, qsizetype capacity, AllocationOption option) noexcept
+{
+ Q_ASSERT(dptr);
+
+ auto r = allocateHelper(2, alignof(AlignedQArrayData), capacity, option);
+ *dptr = r.header;
+ return r.data;
+}
+
+std::pair<QArrayData *, void *>
QArrayData::reallocateUnaligned(QArrayData *data, void *dataPointer,
qsizetype objectSize, qsizetype capacity, AllocationOption option) noexcept
{
Q_ASSERT(!data || !data->isShared());
const qsizetype headerSize = sizeof(AlignedQArrayData);
- qsizetype allocSize = calculateBlockSize(capacity, objectSize, headerSize, option);
+ auto r = calculateBlockSize(capacity, objectSize, headerSize, option);
+ qsizetype allocSize = r.size;
+ capacity = r.elementCount;
if (Q_UNLIKELY(allocSize < 0))
- return qMakePair<QArrayData *, void *>(nullptr, nullptr);
+ return {};
const qptrdiff offset = dataPointer
? reinterpret_cast<char *>(dataPointer) - reinterpret_cast<char *>(data)
@@ -217,10 +241,6 @@ QArrayData::reallocateUnaligned(QArrayData *data, void *dataPointer,
Q_ASSERT(offset > 0);
Q_ASSERT(offset <= allocSize); // equals when all free space is at the beginning
- allocSize = reserveExtraBytes(allocSize);
- if (Q_UNLIKELY(allocSize < 0)) // handle overflow. cannot reallocate reliably
- return qMakePair(data, dataPointer);
-
QArrayData *header = static_cast<QArrayData *>(::realloc(data, size_t(allocSize)));
if (header) {
header->alloc = capacity;
@@ -228,7 +248,7 @@ QArrayData::reallocateUnaligned(QArrayData *data, void *dataPointer,
} else {
dataPointer = nullptr;
}
- return qMakePair(static_cast<QArrayData *>(header), dataPointer);
+ return {header, dataPointer};
}
void QArrayData::deallocate(QArrayData *data, qsizetype objectSize,
diff --git a/src/corelib/tools/qarraydata.h b/src/corelib/tools/qarraydata.h
index 766596fe18..da83fc1a21 100644
--- a/src/corelib/tools/qarraydata.h
+++ b/src/corelib/tools/qarraydata.h
@@ -7,10 +7,18 @@
#include <QtCore/qpair.h>
#include <QtCore/qatomic.h>
+#include <QtCore/qflags.h>
+#include <QtCore/qcontainerfwd.h>
#include <string.h>
QT_BEGIN_NAMESPACE
+#if __has_cpp_attribute(gnu::malloc)
+# define Q_DECL_MALLOCLIKE [[nodiscard, gnu::malloc]]
+#else
+# define Q_DECL_MALLOCLIKE [[nodiscard]]
+#endif
+
template <class T> struct QTypedArrayData;
struct QArrayData
@@ -66,7 +74,7 @@ struct QArrayData
// Returns true if a detach is necessary before modifying the data
// This method is intentionally not const: if you want to know whether
// detaching is necessary, you should be in a non-const function already
- bool needsDetach() const noexcept
+ bool needsDetach() noexcept
{
return ref_.loadRelaxed() > 1;
}
@@ -78,13 +86,17 @@ struct QArrayData
return newSize;
}
- [[nodiscard]]
-#if defined(Q_CC_GNU)
- __attribute__((__malloc__))
-#endif
+ Q_DECL_MALLOCLIKE
static Q_CORE_EXPORT void *allocate(QArrayData **pdata, qsizetype objectSize, qsizetype alignment,
qsizetype capacity, AllocationOption option = QArrayData::KeepSize) noexcept;
- [[nodiscard]] static Q_CORE_EXPORT QPair<QArrayData *, void *> reallocateUnaligned(QArrayData *data, void *dataPointer,
+ Q_DECL_MALLOCLIKE
+ static Q_CORE_EXPORT void *allocate1(QArrayData **pdata, qsizetype capacity,
+ AllocationOption option = QArrayData::KeepSize) noexcept;
+ Q_DECL_MALLOCLIKE
+ static Q_CORE_EXPORT void *allocate2(QArrayData **pdata, qsizetype capacity,
+ AllocationOption option = QArrayData::KeepSize) noexcept;
+
+ [[nodiscard]] static Q_CORE_EXPORT std::pair<QArrayData *, void *> reallocateUnaligned(QArrayData *data, void *dataPointer,
qsizetype objectSize, qsizetype newCapacity, AllocationOption option) noexcept;
static Q_CORE_EXPORT void deallocate(QArrayData *data, qsizetype objectSize,
qsizetype alignment) noexcept;
@@ -92,30 +104,56 @@ struct QArrayData
Q_DECLARE_OPERATORS_FOR_FLAGS(QArrayData::ArrayOptions)
+namespace QtPrivate {
+// QArrayData with strictest alignment requirements supported by malloc()
+#if defined(Q_PROCESSOR_X86_32) && defined(Q_CC_GNU)
+// GCC's definition is incorrect since GCC 8 (commit r240248 in SVN; commit
+// 63012d9a57edc950c5f30242d1e19318b5708060 in Git). This is applied to all
+// GCC-like compilers in case they decide to follow GCC's lead in being wrong.
+constexpr size_t MaxPrimitiveAlignment = 2 * sizeof(void *);
+#else
+constexpr size_t MaxPrimitiveAlignment = alignof(std::max_align_t);
+#endif
+
+struct alignas(MaxPrimitiveAlignment) AlignedQArrayData : QArrayData
+{
+};
+}
+
template <class T>
struct QTypedArrayData
: QArrayData
{
- struct AlignmentDummy { QArrayData header; T data; };
+ struct AlignmentDummy { QtPrivate::AlignedQArrayData header; T data; };
- [[nodiscard]] static QPair<QTypedArrayData *, T *> allocate(qsizetype capacity, AllocationOption option = QArrayData::KeepSize)
+ [[nodiscard]] static std::pair<QTypedArrayData *, T *> allocate(qsizetype capacity, AllocationOption option = QArrayData::KeepSize)
{
static_assert(sizeof(QTypedArrayData) == sizeof(QArrayData));
QArrayData *d;
- void *result = QArrayData::allocate(&d, sizeof(T), alignof(AlignmentDummy), capacity, option);
+ void *result;
+ if constexpr (sizeof(T) == 1) {
+ // necessarily, alignof(T) == 1
+ result = allocate1(&d, capacity, option);
+ } else if constexpr (sizeof(T) == 2) {
+ // alignof(T) may be 1, but that makes no difference
+ result = allocate2(&d, capacity, option);
+ } else {
+ result = QArrayData::allocate(&d, sizeof(T), alignof(AlignmentDummy), capacity, option);
+ }
#if __has_builtin(__builtin_assume_aligned)
+ // and yet we do offer results that have stricter alignment
result = __builtin_assume_aligned(result, Q_ALIGNOF(AlignmentDummy));
#endif
- return qMakePair(static_cast<QTypedArrayData *>(d), static_cast<T *>(result));
+ return {static_cast<QTypedArrayData *>(d), static_cast<T *>(result)};
}
- static QPair<QTypedArrayData *, T *>
+ static std::pair<QTypedArrayData *, T *>
reallocateUnaligned(QTypedArrayData *data, T *dataPointer, qsizetype capacity, AllocationOption option)
{
static_assert(sizeof(QTypedArrayData) == sizeof(QArrayData));
- QPair<QArrayData *, void *> pair =
+ std::pair<QArrayData *, void *> pair =
QArrayData::reallocateUnaligned(data, dataPointer, sizeof(T), capacity, option);
- return qMakePair(static_cast<QTypedArrayData *>(pair.first), static_cast<T *>(pair.second));
+ return {static_cast<QTypedArrayData *>(pair.first), static_cast<T *>(pair.second)};
}
static void deallocate(QArrayData *data) noexcept
@@ -132,6 +170,12 @@ struct QTypedArrayData
(quintptr(data) + sizeof(QArrayData) + alignment - 1) & ~(alignment - 1));
return static_cast<T *>(start);
}
+
+ constexpr static qsizetype max_size() noexcept
+ {
+ // -1 to deal with the pointer one-past-the-end
+ return (QtPrivate::MaxAllocSize - sizeof(QtPrivate::AlignedQArrayData) - 1) / sizeof(T);
+ }
};
namespace QtPrivate {
@@ -172,6 +216,8 @@ struct Q_CORE_EXPORT QContainerImplHelper
};
}
+#undef Q_DECL_MALLOCLIKE
+
QT_END_NAMESPACE
#endif // include guard
diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h
index bd8ead0a80..c3e9821e81 100644
--- a/src/corelib/tools/qarraydataops.h
+++ b/src/corelib/tools/qarraydataops.h
@@ -7,6 +7,7 @@
#include <QtCore/qarraydata.h>
#include <QtCore/qcontainertools_impl.h>
+#include <QtCore/qnamespace.h>
#include <memory>
#include <new>
@@ -236,7 +237,7 @@ public:
if (it == end)
return result;
- QPodArrayOps<T> other{ Data::allocate(this->size), this->size };
+ QPodArrayOps<T> other(this->size);
Q_CHECK_PTR(other.data());
auto dest = other.begin();
// std::uninitialized_copy will fallback to ::memcpy/memmove()
@@ -960,6 +961,24 @@ public:
// b might be updated so use [b, n)
this->copyAppend(b, b + n);
}
+
+ void appendUninitialized(qsizetype newSize)
+ {
+ Q_ASSERT(this->isMutable());
+ Q_ASSERT(!this->isShared());
+ Q_ASSERT(newSize > this->size);
+ Q_ASSERT(newSize - this->size <= this->freeSpaceAtEnd());
+
+ T *const b = this->begin();
+ do {
+ auto ptr = b + this->size;
+
+ if constexpr (std::is_constructible_v<T, Qt::Initialization>)
+ new (ptr) T(Qt::Uninitialized);
+ else
+ new (ptr) T; // not T() -- default-construct
+ } while (++this->size != newSize);
+ }
};
} // namespace QtPrivate
diff --git a/src/corelib/tools/qarraydatapointer.h b/src/corelib/tools/qarraydatapointer.h
index 5e89fd0026..6657d40cf9 100644
--- a/src/corelib/tools/qarraydatapointer.h
+++ b/src/corelib/tools/qarraydatapointer.h
@@ -7,6 +7,9 @@
#include <QtCore/qarraydataops.h>
#include <QtCore/qcontainertools_impl.h>
+#include <QtCore/q20functional.h>
+#include <QtCore/q20memory.h>
+
QT_BEGIN_NAMESPACE
template <class T>
@@ -24,27 +27,39 @@ public:
typedef typename std::conditional<pass_parameter_by_value, T, const T &>::type parameter_type;
+ Q_NODISCARD_CTOR
constexpr QArrayDataPointer() noexcept
: d(nullptr), ptr(nullptr), size(0)
{
}
+ Q_NODISCARD_CTOR
QArrayDataPointer(const QArrayDataPointer &other) noexcept
: d(other.d), ptr(other.ptr), size(other.size)
{
ref();
}
+ Q_NODISCARD_CTOR
constexpr QArrayDataPointer(Data *header, T *adata, qsizetype n = 0) noexcept
: d(header), ptr(adata), size(n)
{
}
- explicit QArrayDataPointer(QPair<QTypedArrayData<T> *, T *> adata, qsizetype n = 0) noexcept
+ Q_NODISCARD_CTOR
+ explicit QArrayDataPointer(std::pair<QTypedArrayData<T> *, T *> adata, qsizetype n = 0) noexcept
: d(adata.first), ptr(adata.second), size(n)
{
}
+ Q_NODISCARD_CTOR explicit
+ QArrayDataPointer(qsizetype alloc, qsizetype n = 0,
+ QArrayData::AllocationOption option = QArrayData::KeepSize)
+ : QArrayDataPointer(Data::allocate(alloc, option), n)
+ {
+ }
+
+ Q_NODISCARD_CTOR
static QArrayDataPointer fromRawData(const T *rawData, qsizetype length) noexcept
{
Q_ASSERT(rawData || !length);
@@ -58,12 +73,12 @@ public:
return *this;
}
+ Q_NODISCARD_CTOR
QArrayDataPointer(QArrayDataPointer &&other) noexcept
- : d(other.d), ptr(other.ptr), size(other.size)
+ : d(std::exchange(other.d, nullptr)),
+ ptr(std::exchange(other.ptr, nullptr)),
+ size(std::exchange(other.size, 0))
{
- other.d = nullptr;
- other.ptr = nullptr;
- other.size = 0;
}
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QArrayDataPointer)
@@ -305,6 +320,118 @@ public:
this->ptr = res;
}
+ template <typename InputIterator, typename Projection = q20::identity>
+ void assign(InputIterator first, InputIterator last, Projection proj = {})
+ {
+ // This function only provides the basic exception guarantee.
+ constexpr bool IsFwdIt = std::is_convertible_v<
+ typename std::iterator_traits<InputIterator>::iterator_category,
+ std::forward_iterator_tag>;
+ constexpr bool IsIdentity = std::is_same_v<Projection, q20::identity>;
+
+ if constexpr (IsFwdIt) {
+ const qsizetype n = std::distance(first, last);
+ if (needsDetach() || n > constAllocatedCapacity()) {
+ QArrayDataPointer allocated(detachCapacity(n));
+ swap(allocated);
+ }
+ } else if (needsDetach()) {
+ QArrayDataPointer allocated(allocatedCapacity());
+ swap(allocated);
+ // We don't want to copy data that we know we'll overwrite
+ }
+
+ auto offset = freeSpaceAtBegin();
+ const auto capacityBegin = begin() - offset;
+ const auto prependBufferEnd = begin();
+
+ if constexpr (!std::is_nothrow_constructible_v<T, decltype(std::invoke(proj, *first))>) {
+ // If construction can throw, and we have freeSpaceAtBegin(),
+ // it's easiest to just clear the container and start fresh.
+ // The alternative would be to keep track of two active, disjoint ranges.
+ if (offset) {
+ (*this)->truncate(0);
+ setBegin(capacityBegin);
+ offset = 0;
+ }
+ }
+
+ auto dst = capacityBegin;
+ const auto dend = end();
+ if (offset) { // avoids dead stores
+ setBegin(capacityBegin); // undo prepend optimization
+
+ // By construction, the following loop is nothrow!
+ // (otherwise, we can't reach here)
+ // Assumes InputIterator operations don't throw.
+ // (but we can't statically assert that, as these operations
+ // have preconditons, so typically aren't noexcept)
+ while (true) {
+ if (dst == prependBufferEnd) { // ran out of prepend buffer space
+ size += offset;
+ // we now have a contiguous buffer, continue with the main loop:
+ break;
+ }
+ if (first == last) { // ran out of elements to assign
+ std::destroy(prependBufferEnd, dend);
+ size = dst - begin();
+ return;
+ }
+ // construct element in prepend buffer
+ q20::construct_at(dst, std::invoke(proj, *first));
+ ++dst;
+ ++first;
+ }
+ }
+
+ while (true) {
+ if (first == last) { // ran out of elements to assign
+ std::destroy(dst, dend);
+ break;
+ }
+ if (dst == dend) { // ran out of existing elements to overwrite
+ if constexpr (IsFwdIt && IsIdentity) {
+ dst = std::uninitialized_copy(first, last, dst);
+ break;
+ } else if constexpr (IsFwdIt && !IsIdentity
+ && std::is_nothrow_constructible_v<T, decltype(std::invoke(proj, *first))>) {
+ for (; first != last; ++dst, ++first) // uninitialized_copy with projection
+ q20::construct_at(dst, std::invoke(proj, *first));
+ break;
+ } else {
+ do {
+ (*this)->emplace(size, std::invoke(proj, *first));
+ } while (++first != last);
+ return; // size() is already correct (and dst invalidated)!
+ }
+ }
+ *dst = std::invoke(proj, *first); // overwrite existing element
+ ++dst;
+ ++first;
+ }
+ size = dst - begin();
+ }
+
+ QArrayDataPointer sliced(qsizetype pos, qsizetype n) const &
+ {
+ QArrayDataPointer result(n);
+ std::uninitialized_copy_n(begin() + pos, n, result.begin());
+ result.size = n;
+ return result;
+ }
+
+ QArrayDataPointer sliced(qsizetype pos, qsizetype n) &&
+ {
+ if (needsDetach())
+ return sliced(pos, n);
+ T *newBeginning = begin() + pos;
+ std::destroy(begin(), newBeginning);
+ std::destroy(newBeginning + n, end());
+ setBegin(newBeginning);
+ size = n;
+ return std::move(*this);
+ }
+
// forwards from QArrayData
qsizetype allocatedCapacity() noexcept { return d ? d->allocatedCapacity() : 0; }
qsizetype constAllocatedCapacity() const noexcept { return d ? d->constAllocatedCapacity() : 0; }
diff --git a/src/corelib/tools/qatomicscopedvaluerollback_p.h b/src/corelib/tools/qatomicscopedvaluerollback.h
index 147156d585..8f653acba5 100644
--- a/src/corelib/tools/qatomicscopedvaluerollback_p.h
+++ b/src/corelib/tools/qatomicscopedvaluerollback.h
@@ -1,29 +1,21 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QATOMICSCOPEDVALUEROLLBACK_P_H
-#define QATOMICSCOPEDVALUEROLLBACK_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
-// file may change from version to version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include <QtCore/qglobal.h>
+#ifndef QATOMICSCOPEDVALUEROLLBACK_H
+#define QATOMICSCOPEDVALUEROLLBACK_H
+
+#include <QtCore/qassert.h>
#include <QtCore/qatomic.h>
+#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qtclasshelpermacros.h>
+#include <QtCore/qtconfigmacros.h>
#include <atomic>
QT_BEGIN_NAMESPACE
template <typename T>
-class [[nodiscard]] QAtomicScopedValueRollback
+class QAtomicScopedValueRollback
{
std::atomic<T> &m_atomic;
T m_value;
@@ -31,7 +23,7 @@ class [[nodiscard]] QAtomicScopedValueRollback
Q_DISABLE_COPY_MOVE(QAtomicScopedValueRollback)
- constexpr std::memory_order store_part(std::memory_order mo) noexcept
+ static constexpr std::memory_order store_part(std::memory_order mo) noexcept
{
switch (mo) {
case std::memory_order_relaxed:
@@ -41,7 +33,25 @@ class [[nodiscard]] QAtomicScopedValueRollback
case std::memory_order_acq_rel: return std::memory_order_release;
case std::memory_order_seq_cst: return std::memory_order_seq_cst;
}
- // GCC 8.x does not tread __builtin_unreachable() as constexpr
+ // GCC 8.x does not treat __builtin_unreachable() as constexpr
+#if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
+ // NOLINTNEXTLINE(qt-use-unreachable-return): Triggers on Clang, breaking GCC 8
+ Q_UNREACHABLE();
+#endif
+ return std::memory_order_seq_cst;
+ }
+
+ static constexpr std::memory_order load_part(std::memory_order mo) noexcept
+ {
+ switch (mo) {
+ case std::memory_order_relaxed:
+ case std::memory_order_release: return std::memory_order_relaxed;
+ case std::memory_order_consume: return std::memory_order_consume;
+ case std::memory_order_acquire:
+ case std::memory_order_acq_rel: return std::memory_order_acquire;
+ case std::memory_order_seq_cst: return std::memory_order_seq_cst;
+ }
+ // GCC 8.x does not treat __builtin_unreachable() as constexpr
#if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
// NOLINTNEXTLINE(qt-use-unreachable-return): Triggers on Clang, breaking GCC 8
Q_UNREACHABLE();
@@ -52,11 +62,13 @@ public:
//
// std::atomic:
//
+ Q_NODISCARD_CTOR
explicit constexpr
QAtomicScopedValueRollback(std::atomic<T> &var,
std::memory_order mo = std::memory_order_seq_cst)
- : m_atomic(var), m_value(var.load(mo)), m_mo(mo) {}
+ : m_atomic(var), m_value(var.load(load_part(mo))), m_mo(mo) {}
+ Q_NODISCARD_CTOR
explicit constexpr
QAtomicScopedValueRollback(std::atomic<T> &var, T value,
std::memory_order mo = std::memory_order_seq_cst)
@@ -65,11 +77,13 @@ public:
//
// Q(Basic)AtomicInteger:
//
+ Q_NODISCARD_CTOR
explicit constexpr
QAtomicScopedValueRollback(QBasicAtomicInteger<T> &var,
std::memory_order mo = std::memory_order_seq_cst)
: QAtomicScopedValueRollback(var._q_value, mo) {}
+ Q_NODISCARD_CTOR
explicit constexpr
QAtomicScopedValueRollback(QBasicAtomicInteger<T> &var, T value,
std::memory_order mo = std::memory_order_seq_cst)
@@ -78,30 +92,36 @@ public:
//
// Q(Basic)AtomicPointer:
//
+ Q_NODISCARD_CTOR
explicit constexpr
QAtomicScopedValueRollback(QBasicAtomicPointer<std::remove_pointer_t<T>> &var,
std::memory_order mo = std::memory_order_seq_cst)
: QAtomicScopedValueRollback(var._q_value, mo) {}
+ Q_NODISCARD_CTOR
explicit constexpr
QAtomicScopedValueRollback(QBasicAtomicPointer<std::remove_pointer_t<T>> &var, T value,
std::memory_order mo = std::memory_order_seq_cst)
: QAtomicScopedValueRollback(var._q_value, value, mo) {}
-#if __cpp_constexpr >= 201907L
- constexpr
-#endif
~QAtomicScopedValueRollback()
{
m_atomic.store(m_value, store_part(m_mo));
}
- constexpr void commit()
+ void commit()
{
- m_value = m_atomic.load(m_mo);
+ m_value = m_atomic.load(load_part(m_mo));
}
};
+template <typename T>
+QAtomicScopedValueRollback(QBasicAtomicPointer<T> &)
+ -> QAtomicScopedValueRollback<T*>;
+template <typename T>
+QAtomicScopedValueRollback(QBasicAtomicPointer<T> &, std::memory_order)
+ -> QAtomicScopedValueRollback<T*>;
+
QT_END_NAMESPACE
-#endif // QATOMICASCOPEDVALUEROLLBACK_P_H
+#endif // QATOMICASCOPEDVALUEROLLBACK_H
diff --git a/src/corelib/tools/qatomicscopedvaluerollback.qdoc b/src/corelib/tools/qatomicscopedvaluerollback.qdoc
new file mode 100644
index 0000000000..8c8161cb35
--- /dev/null
+++ b/src/corelib/tools/qatomicscopedvaluerollback.qdoc
@@ -0,0 +1,123 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAtomicScopedValueRollback
+ \inmodule QtCore
+ \brief Provides a QScopedValueRollback for atomic variables.
+ \ingroup misc
+ \ingroup tools
+ \since 6.7
+
+ The QAtomicScopedValueRollback class resets an atomic variable to its
+ prior value on destruction. It can be used to revert state when an
+ exception is thrown without the need to write try-catch blocks.
+
+ It can also be used to manage variables that are temporarily set, such as
+ reentrancy guards. By using this class, the variable will be reset whether the
+ function is exited normally, exited early by a return statement, or exited by
+ an exception.
+
+ The class works on std::atomic and the Qt atomic classes: QBasicAtomicInteger,
+ \l QAtomicInteger, \l QAtomicInt, QBasicAtomicPointer and \l QAtomicPointer.
+
+ \target Memory Order
+ The memory accesses to the atomic variable \a var are specified using the value
+ of \c mo. The memory order follows this mapping:
+ \br
+ \list
+ \li When writing to the atomic variable:
+ \list
+ \li An acquire ordering performs a relaxed operation instead.
+ \li A hybrid acquire-release ordering performs a release operation instead.
+ \endlist
+ \li When reading from the atomic variable:
+ \list
+ \li A release ordering performs a relaxed operation instead.
+ \li A consume ordering performs a consume operation.
+ \li A hybrid acquire-release ordering performs an acquire operation instead.
+ \endlist
+ \endlist
+ \br
+ Otherwise, the default memory order is sequential consistent ordering.
+
+ \note You should never name the template arguments explicitly, but exclusively
+ use Class Template Argument Deduction (CTAD) and let the compiler pick the
+ template argument.
+
+ \note There is a chance that other threads modify the variable too, which means
+ you may lose updates performed by other threads between the call to the
+ QAtomicScopedValueRollback constructor and commit() or between commit() and the
+ destructor.
+
+ \sa QScopedValueRollback
+*/
+
+/*!
+ \fn template <typename T> QAtomicScopedValueRollback<T>::QAtomicScopedValueRollback(std::atomic<T> &var, std::memory_order mo = std::memory_order_seq_cst)
+ \fn template <typename T> QAtomicScopedValueRollback<T>::QAtomicScopedValueRollback(QBasicAtomicInteger<T> &var, std::memory_order mo = std::memory_order_seq_cst)
+ \fn template <typename T> QAtomicScopedValueRollback<T>::QAtomicScopedValueRollback(QBasicAtomicPointer<std::remove_pointer_t<T>> &var, std::memory_order mo = std::memory_order_seq_cst)
+
+ Records the value of \a var in order to restore it on destruction.
+
+ This is equivalent to:
+ \code
+ T old_value = var.load(mo);
+ // And in the destructor: var.store(old_value, mo);
+ \endcode
+ The \c{mo} adjustment for the load is described in the \l {Memory Order} section.
+*/
+
+/*!
+ \fn template <typename T> QAtomicScopedValueRollback<T>::QAtomicScopedValueRollback(std::atomic<T> &var, T value, std::memory_order mo = std::memory_order_seq_cst)
+ \fn template <typename T> QAtomicScopedValueRollback<T>::QAtomicScopedValueRollback(QBasicAtomicInteger<T> &var, T value, std::memory_order mo = std::memory_order_seq_cst)
+ \fn template <typename T> QAtomicScopedValueRollback<T>::QAtomicScopedValueRollback(QBasicAtomicPointer<std::remove_pointer_t<T>> &var, T value, std::memory_order mo = std::memory_order_seq_cst)
+
+ Assigns \a value to \a var and stores the prior value of \a var internally for
+ reverting on destruction.
+
+ This is equivalent to:
+ \code
+ T old_value = var.exchange(new_value, mo);
+ // And in the destructor: var.store(old_value, mo);
+ \endcode
+*/
+
+/*!
+ \fn template <typename T> QAtomicScopedValueRollback<T>::~QAtomicScopedValueRollback()
+
+ Restores the stored value that was current at construction time, or
+ at the last call to commit(), to the managed variable.
+
+ This is equivalent to:
+ \code
+ // In the constructor: T old_value = var.load(mo);
+ // or: T old_value = exchange(new_value, mo);
+ var.store(old_value, mo);
+ \endcode
+ Where \c{mo} is the same as the one initially passed to the constructor.
+ See \l{Memory Order} for the meaning of \c{mo}.
+*/
+
+/*!
+ \fn template <typename T> void QAtomicScopedValueRollback<T>::commit()
+
+ Updates the stored value to the managed variable's current value, loaded
+ with the same memory order as on construction.
+
+ This updated value will be restored on destruction, instead of the original
+ prior value.
+
+ This is equivalent to:
+ \code
+ // Given constructor: T old_value = var.load(mo);
+ old_value = var.load(mo); // referesh it
+ // And, in the destructor: var.store(old_value, mo);
+ \endcode
+ Where \c{mo} is the same as the one initially passed to the constructor.
+ See \l{Memory Order} for the meaning of \c{mo}.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/corelib/tools/qbitarray.cpp b/src/corelib/tools/qbitarray.cpp
index 5c48b3b608..e4276d383d 100644
--- a/src/corelib/tools/qbitarray.cpp
+++ b/src/corelib/tools/qbitarray.cpp
@@ -7,6 +7,9 @@
#include <qdatastream.h>
#include <qdebug.h>
#include <qendian.h>
+
+#include <limits>
+
#include <string.h>
QT_BEGIN_NAMESPACE
@@ -20,6 +23,8 @@ QT_BEGIN_NAMESPACE
\ingroup shared
\reentrant
+ \compares equality
+
A QBitArray is an array that gives access to individual bits and
provides operators (\l{operator&()}{AND}, \l{operator|()}{OR},
\l{operator^()}{XOR}, and \l{operator~()}{NOT}) that work on
@@ -74,6 +79,7 @@ QT_BEGIN_NAMESPACE
\sa QByteArray, QList
*/
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
/*!
\fn QBitArray::QBitArray(QBitArray &&other)
@@ -82,6 +88,7 @@ QT_BEGIN_NAMESPACE
\since 5.2
*/
+#endif
/*! \fn QBitArray::QBitArray()
@@ -104,22 +111,39 @@ QT_BEGIN_NAMESPACE
* inline qsizetype size() const { return (d.size() << 3) - *d.constData(); }
*/
+static constexpr qsizetype storage_size(qsizetype size)
+{
+ // avoid overflow when adding 7, by doing the arithmetic in unsigned space:
+ return qsizetype((size_t(size) + 7) / 8);
+}
+
+static constexpr qsizetype allocation_size(qsizetype size)
+{
+ return size <= 0 ? 0 : storage_size(size) + 1;
+}
+
+static void adjust_head_and_tail(char *data, qsizetype storageSize, qsizetype logicalSize)
+{
+ quint8 *c = reinterpret_cast<quint8 *>(data);
+ // store the difference between storage and logical size in d[0]:
+ *c = quint8(size_t(storageSize) * 8 - logicalSize);
+ // reset unallocated bits to 0:
+ if (logicalSize & 7)
+ *(c + 1 + logicalSize / 8) &= (1 << (logicalSize & 7)) - 1;
+}
+
/*!
Constructs a bit array containing \a size bits. The bits are
initialized with \a value, which defaults to false (0).
*/
QBitArray::QBitArray(qsizetype size, bool value)
- : d(size <= 0 ? 0 : 1 + (size + 7) / 8, Qt::Uninitialized)
+ : d(allocation_size(size), value ? 0xFF : 0x00)
{
Q_ASSERT_X(size >= 0, "QBitArray::QBitArray", "Size must be greater than or equal to 0.");
if (size <= 0)
return;
- uchar *c = reinterpret_cast<uchar *>(d.data());
- memset(c + 1, value ? 0xff : 0, d.size() - 1);
- *c = d.size() * 8 - size;
- if (value && size && size & 7)
- *(c + 1 + size / 8) &= (1 << (size & 7)) - 1;
+ adjust_head_and_tail(d.data(), d.size(), size);
}
/*! \fn qsizetype QBitArray::size() const
@@ -183,17 +207,12 @@ qsizetype QBitArray::count(bool on) const
*/
void QBitArray::resize(qsizetype size)
{
- if (!size) {
+ Q_ASSERT_X(size >= 0, "QBitArray::resize", "Size must be greater than or equal to 0.");
+ if (size <= 0) {
d.resize(0);
} else {
- qsizetype s = d.size();
- d.resize(1 + (size + 7) / 8);
- uchar *c = reinterpret_cast<uchar *>(d.data());
- if (size > (s << 3))
- memset(c + s, 0, d.size() - s);
- else if (size & 7)
- *(c + 1 + size / 8) &= (1 << (size & 7)) - 1;
- *c = d.size() * 8 - size;
+ d.resize(allocation_size(size), 0x00);
+ adjust_head_and_tail(d.data(), d.size(), size);
}
}
@@ -289,20 +308,15 @@ void QBitArray::fill(bool value, qsizetype begin, qsizetype end)
*/
QBitArray QBitArray::fromBits(const char *data, qsizetype size)
{
+ Q_ASSERT_X(size >= 0, "QBitArray::fromBits", "Size must be greater than or equal to 0.");
QBitArray result;
- if (size == 0)
+ if (size <= 0)
return result;
- qsizetype nbytes = (size + 7) / 8;
-
- result.d = QByteArray(nbytes + 1, Qt::Uninitialized);
- char *bits = result.d.data();
- memcpy(bits + 1, data, nbytes);
-
- // clear any unused bits from the last byte
- if (size & 7)
- bits[nbytes] &= 0xffU >> (8 - (size & 7));
- *bits = result.d.size() * 8 - size;
+ auto &d = result.d;
+ d.resize(allocation_size(size));
+ memcpy(d.data() + 1, data, d.size() - 1);
+ adjust_head_and_tail(d.data(), d.size(), size);
return result;
}
@@ -453,6 +467,7 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
\overload
*/
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
/*! \fn QBitArray::QBitArray(const QBitArray &other) noexcept
Constructs a copy of \a other.
@@ -477,6 +492,7 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
Moves \a other to this bit array and returns a reference to
this bit array.
*/
+#endif // Qt 6
/*! \fn void QBitArray::swap(QBitArray &other)
\since 4.8
@@ -485,23 +501,145 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
fast and never fails.
*/
-/*! \fn bool QBitArray::operator==(const QBitArray &other) const
+/*! \fn bool QBitArray::operator==(const QBitArray &lhs, const QBitArray &rhs)
- Returns \c true if \a other is equal to this bit array; otherwise
+ Returns \c true if \a lhs is equal to \a rhs bit array; otherwise
returns \c false.
\sa operator!=()
*/
-/*! \fn bool QBitArray::operator!=(const QBitArray &other) const
+/*! \fn bool QBitArray::operator!=(const QBitArray &lhs, const QBitArray &rhs)
- Returns \c true if \a other is not equal to this bit array;
+ Returns \c true if \a lhs is not equal to \a rhs bit array;
otherwise returns \c false.
\sa operator==()
*/
+// Returns a new QBitArray that has the same size as the bigger of \a a1 and
+// \a a2, but whose contents are uninitialized.
+static QBitArray sizedForOverwrite(const QBitArray &a1, const QBitArray &a2)
+{
+ QBitArray result;
+ const QByteArrayData &d1 = a1.data_ptr();
+ const QByteArrayData &d2 = a2.data_ptr();
+ qsizetype n1 = d1.size;
+ qsizetype n2 = d2.size;
+ qsizetype n = qMax(n1, n2);
+
+ QByteArrayData bytes(n, n);
+
+ // initialize the count of bits in the last byte (see construction note)
+ if (n1 > n2)
+ *bytes.ptr = *d1.ptr;
+ else if (n2 > n1)
+ *bytes.ptr = *d2.ptr;
+ else if (n1) // n1 == n2
+ *bytes.ptr = qMin(*d1.ptr, *d2.ptr);
+
+ result.data_ptr() = std::move(bytes);
+ return result;
+}
+
+template <typename BitwiseOp> static Q_NEVER_INLINE
+QBitArray &performBitwiseOperationHelper(QBitArray &out, const QBitArray &a1,
+ const QBitArray &a2, BitwiseOp op)
+{
+ const QByteArrayData &d1 = a1.data_ptr();
+ const QByteArrayData &d2 = a2.data_ptr();
+
+ // Sizes in bytes (including the initial bit difference counter)
+ qsizetype n1 = d1.size;
+ qsizetype n2 = d2.size;
+ Q_ASSERT(out.data_ptr().size == qMax(n1, n2));
+ Q_ASSERT(out.data_ptr().size == 0 || !out.data_ptr().needsDetach());
+
+ // Bypass QByteArray's emptiness verification; we won't dereference
+ // these pointers if their size is zero.
+ auto dst = reinterpret_cast<uchar *>(out.data_ptr().data());
+ auto p1 = reinterpret_cast<const uchar *>(d1.data());
+ auto p2 = reinterpret_cast<const uchar *>(d2.data());
+
+ // Main: perform the operation in the range where both arrays have data
+ if (n1 < n2) {
+ std::swap(n1, n2);
+ std::swap(p1, p2);
+ }
+ for (qsizetype i = 1; i < n2; ++i)
+ dst[i] = op(p1[i], p2[i]);
+
+ // Tail: operate as if both arrays had the same data by padding zeroes to
+ // the end of the shorter of the two (for std::bit_or and std::bit_xor, this is
+ // a memmove; for std::bit_and, it's memset to 0).
+ for (qsizetype i = qMax(n2, qsizetype(1)); i < n1; ++i)
+ dst[i] = op(p1[i], uchar(0));
+
+ return out;
+}
+
+template <typename BitwiseOp> static Q_NEVER_INLINE
+QBitArray &performBitwiseOperationInCopy(QBitArray &self, const QBitArray &other, BitwiseOp op)
+{
+ QBitArray tmp(std::move(self));
+ self = sizedForOverwrite(tmp, other);
+ return performBitwiseOperationHelper(self, tmp, other, op);
+}
+
+template <typename BitwiseOp> static Q_NEVER_INLINE
+QBitArray &performBitwiseOperationInPlace(QBitArray &self, const QBitArray &other, BitwiseOp op)
+{
+ if (self.size() < other.size())
+ self.resize(other.size());
+ return performBitwiseOperationHelper(self, self, other, op);
+}
+
+template <typename BitwiseOp> static
+QBitArray &performBitwiseOperation(QBitArray &self, const QBitArray &other, BitwiseOp op)
+{
+ if (self.data_ptr().needsDetach())
+ return performBitwiseOperationInCopy(self, other, op);
+ return performBitwiseOperationInPlace(self, other, op);
+}
+
+// SCARY helper
+enum { InCopy, InPlace };
+static auto prepareForBitwiseOperation(QBitArray &self, QBitArray &other)
+{
+ QByteArrayData &d1 = self.data_ptr();
+ QByteArrayData &d2 = other.data_ptr();
+ bool detached1 = !d1.needsDetach();
+ bool detached2 = !d2.needsDetach();
+ if (!detached1 && !detached2)
+ return InCopy;
+
+ // at least one of the two is detached, we'll reuse its buffer
+ bool swap = false;
+ if (detached1 && detached2) {
+ // both are detached, so choose the larger of the two
+ swap = d1.allocatedCapacity() < d2.allocatedCapacity();
+ } else if (detached2) {
+ // we can re-use other's buffer but not self's, so swap the two
+ swap = true;
+ }
+ if (swap)
+ self.swap(other);
+ return InPlace;
+}
+
+template <typename BitwiseOp> static
+QBitArray &performBitwiseOperation(QBitArray &self, QBitArray &other, BitwiseOp op)
+{
+ auto choice = prepareForBitwiseOperation(self, other);
+ if (choice == InCopy)
+ return performBitwiseOperationInCopy(self, other, std::move(op));
+ return performBitwiseOperationInPlace(self, other, std::move(op));
+}
+
/*!
+ \fn QBitArray &QBitArray::operator&=(const QBitArray &other)
+ \fn QBitArray &QBitArray::operator&=(QBitArray &&other)
+
Performs the AND operation between all bits in this bit array and
\a other. Assigns the result to this bit array, and returns a
reference to it.
@@ -516,21 +654,20 @@ quint32 QBitArray::toUInt32(QSysInfo::Endian endianness, bool *ok) const noexcep
\sa operator&(), operator|=(), operator^=(), operator~()
*/
+QBitArray &QBitArray::operator&=(QBitArray &&other)
+{
+ return performBitwiseOperation(*this, other, std::bit_and<uchar>());
+}
+
QBitArray &QBitArray::operator&=(const QBitArray &other)
{
- resize(qMax(size(), other.size()));
- uchar *a1 = reinterpret_cast<uchar *>(d.data()) + 1;
- const uchar *a2 = reinterpret_cast<const uchar *>(other.d.constData()) + 1;
- qsizetype n = other.d.size() - 1;
- qsizetype p = d.size() - 1 - n;
- while (n-- > 0)
- *a1++ &= *a2++;
- while (p-- > 0)
- *a1++ = 0;
- return *this;
+ return performBitwiseOperation(*this, other, std::bit_and<uchar>());
}
/*!
+ \fn QBitArray &QBitArray::operator|=(const QBitArray &other)
+ \fn QBitArray &QBitArray::operator|=(QBitArray &&other)
+
Performs the OR operation between all bits in this bit array and
\a other. Assigns the result to this bit array, and returns a
reference to it.
@@ -545,18 +682,20 @@ QBitArray &QBitArray::operator&=(const QBitArray &other)
\sa operator|(), operator&=(), operator^=(), operator~()
*/
+QBitArray &QBitArray::operator|=(QBitArray &&other)
+{
+ return performBitwiseOperation(*this, other, std::bit_or<uchar>());
+}
+
QBitArray &QBitArray::operator|=(const QBitArray &other)
{
- resize(qMax(size(), other.size()));
- uchar *a1 = reinterpret_cast<uchar *>(d.data()) + 1;
- const uchar *a2 = reinterpret_cast<const uchar *>(other.d.constData()) + 1;
- qsizetype n = other.d.size() - 1;
- while (n-- > 0)
- *a1++ |= *a2++;
- return *this;
+ return performBitwiseOperation(*this, other, std::bit_or<uchar>());
}
/*!
+ \fn QBitArray &QBitArray::operator^=(const QBitArray &other)
+ \fn QBitArray &QBitArray::operator^=(QBitArray &&other)
+
Performs the XOR operation between all bits in this bit array and
\a other. Assigns the result to this bit array, and returns a
reference to it.
@@ -571,20 +710,20 @@ QBitArray &QBitArray::operator|=(const QBitArray &other)
\sa operator^(), operator&=(), operator|=(), operator~()
*/
+QBitArray &QBitArray::operator^=(QBitArray &&other)
+{
+ return performBitwiseOperation(*this, other, std::bit_xor<uchar>());
+}
+
QBitArray &QBitArray::operator^=(const QBitArray &other)
{
- resize(qMax(size(), other.size()));
- uchar *a1 = reinterpret_cast<uchar *>(d.data()) + 1;
- const uchar *a2 = reinterpret_cast<const uchar *>(other.d.constData()) + 1;
- qsizetype n = other.d.size() - 1;
- while (n-- > 0)
- *a1++ ^= *a2++;
- return *this;
+ return performBitwiseOperation(*this, other, std::bit_xor<uchar>());
}
/*!
- Returns a bit array that contains the inverted bits of this bit
- array.
+ \fn QBitArray QBitArray::operator~(QBitArray a)
+ Returns a bit array that contains the inverted bits of the bit
+ array \a a.
Example:
\snippet code/src_corelib_tools_qbitarray.cpp 11
@@ -592,24 +731,42 @@ QBitArray &QBitArray::operator^=(const QBitArray &other)
\sa operator&(), operator|(), operator^()
*/
-QBitArray QBitArray::operator~() const
+Q_NEVER_INLINE QBitArray QBitArray::inverted_inplace() &&
{
- qsizetype sz = size();
- QBitArray a(sz);
- const uchar *a1 = reinterpret_cast<const uchar *>(d.constData()) + 1;
- uchar *a2 = reinterpret_cast<uchar *>(a.d.data()) + 1;
- qsizetype n = d.size() - 1;
-
- while (n-- > 0)
- *a2++ = ~*a1++;
-
- if (sz && sz % 8)
- *(a2 - 1) &= (1 << (sz % 8)) - 1;
- return a;
+ qsizetype n = d.size();
+ uchar *dst = reinterpret_cast<uchar *>(data_ptr().data());
+ const uchar *src = dst;
+ QBitArray result([&] {
+ if (d.isDetached() || n == 0)
+ return std::move(d.data_ptr()); // invert in-place
+
+ QByteArrayData tmp(n, n);
+ dst = reinterpret_cast<uchar *>(tmp.data());
+ return tmp;
+ }());
+
+ uchar bitdiff = 8;
+ if (n)
+ bitdiff = dst[0] = src[0]; // copy the count of bits in the last byte
+
+ for (qsizetype i = 1; i < n; ++i)
+ dst[i] = ~src[i];
+
+ if (int tailCount = 16 - bitdiff; tailCount != 8) {
+ // zero the bits beyond our size in the last byte
+ Q_ASSERT(n > 1);
+ uchar tailMask = (1U << tailCount) - 1;
+ dst[n - 1] &= tailMask;
+ }
+
+ return result;
}
/*!
- \relates QBitArray
+ \fn QBitArray QBitArray::operator&(const QBitArray &a1, const QBitArray &a2)
+ \fn QBitArray QBitArray::operator&(QBitArray &&a1, const QBitArray &a2)
+ \fn QBitArray QBitArray::operator&(const QBitArray &a1, QBitArray &&a2)
+ \fn QBitArray QBitArray::operator&(QBitArray &&a1, QBitArray &&a2)
Returns a bit array that is the AND of the bit arrays \a a1 and \a
a2.
@@ -626,13 +783,16 @@ QBitArray QBitArray::operator~() const
QBitArray operator&(const QBitArray &a1, const QBitArray &a2)
{
- QBitArray tmp = a1;
- tmp &= a2;
+ QBitArray tmp = sizedForOverwrite(a1, a2);
+ performBitwiseOperationHelper(tmp, a1, a2, std::bit_and<uchar>());
return tmp;
}
/*!
- \relates QBitArray
+ \fn QBitArray QBitArray::operator|(const QBitArray &a1, const QBitArray &a2)
+ \fn QBitArray QBitArray::operator|(QBitArray &&a1, const QBitArray &a2)
+ \fn QBitArray QBitArray::operator|(const QBitArray &a1, QBitArray &&a2)
+ \fn QBitArray QBitArray::operator|(QBitArray &&a1, QBitArray &&a2)
Returns a bit array that is the OR of the bit arrays \a a1 and \a
a2.
@@ -649,13 +809,16 @@ QBitArray operator&(const QBitArray &a1, const QBitArray &a2)
QBitArray operator|(const QBitArray &a1, const QBitArray &a2)
{
- QBitArray tmp = a1;
- tmp |= a2;
+ QBitArray tmp = sizedForOverwrite(a1, a2);
+ performBitwiseOperationHelper(tmp, a1, a2, std::bit_or<uchar>());
return tmp;
}
/*!
- \relates QBitArray
+ \fn QBitArray QBitArray::operator^(const QBitArray &a1, const QBitArray &a2)
+ \fn QBitArray QBitArray::operator^(QBitArray &&a1, const QBitArray &a2)
+ \fn QBitArray QBitArray::operator^(const QBitArray &a1, QBitArray &&a2)
+ \fn QBitArray QBitArray::operator^(QBitArray &&a1, QBitArray &&a2)
Returns a bit array that is the XOR of the bit arrays \a a1 and \a
a2.
@@ -672,8 +835,8 @@ QBitArray operator|(const QBitArray &a1, const QBitArray &a2)
QBitArray operator^(const QBitArray &a1, const QBitArray &a2)
{
- QBitArray tmp = a1;
- tmp ^= a2;
+ QBitArray tmp = sizedForOverwrite(a1, a2);
+ performBitwiseOperationHelper(tmp, a1, a2, std::bit_xor<uchar>());
return tmp;
}
@@ -733,19 +896,19 @@ QBitArray operator^(const QBitArray &a1, const QBitArray &a2)
QDataStream &operator<<(QDataStream &out, const QBitArray &ba)
{
+ const qsizetype len = ba.size();
if (out.version() < QDataStream::Qt_6_0) {
- quint32 len = ba.size();
- out << len;
- if (len > 0)
- out.writeRawData(ba.d.constData() + 1, ba.d.size() - 1);
- return out;
+ if (Q_UNLIKELY(len > qsizetype{(std::numeric_limits<qint32>::max)()})) {
+ out.setStatus(QDataStream::Status::SizeLimitExceeded);
+ return out;
+ }
+ out << quint32(len);
} else {
- quint64 len = ba.size();
- out << len;
- if (len > 0)
- out.writeRawData(ba.d.constData() + 1, ba.d.size() - 1);
- return out;
+ out << quint64(len);
}
+ if (len > 0)
+ out.writeRawData(ba.d.data() + 1, ba.d.size() - 1);
+ return out;
}
/*!
@@ -763,10 +926,18 @@ QDataStream &operator>>(QDataStream &in, QBitArray &ba)
if (in.version() < QDataStream::Qt_6_0) {
quint32 tmp;
in >> tmp;
+ if (Q_UNLIKELY(tmp > quint32((std::numeric_limits<qint32>::max)()))) {
+ in.setStatus(QDataStream::ReadCorruptData);
+ return in;
+ }
len = tmp;
} else {
quint64 tmp;
in >> tmp;
+ if (Q_UNLIKELY(tmp > quint64((std::numeric_limits<qsizetype>::max)()))) {
+ in.setStatus(QDataStream::Status::SizeLimitExceeded);
+ return in;
+ }
len = tmp;
}
if (len == 0) {
@@ -775,7 +946,7 @@ QDataStream &operator>>(QDataStream &in, QBitArray &ba)
}
const qsizetype Step = 8 * 1024 * 1024;
- qsizetype totalBytes = (len + 7) / 8;
+ const qsizetype totalBytes = storage_size(len);
qsizetype allocated = 0;
while (allocated < totalBytes) {
@@ -789,14 +960,13 @@ QDataStream &operator>>(QDataStream &in, QBitArray &ba)
allocated += blockSize;
}
- qsizetype paddingMask = ~((0x1 << (len & 0x7)) - 1);
- if (paddingMask != ~0x0 && (ba.d.constData()[ba.d.size() - 1] & paddingMask)) {
+ const auto fromStream = ba.d.back();
+ adjust_head_and_tail(ba.d.data(), ba.d.size(), len);
+ if (ba.d.back() != fromStream) {
ba.clear();
in.setStatus(QDataStream::ReadCorruptData);
return in;
}
-
- *ba.d.data() = ba.d.size() * 8 - len;
return in;
}
#endif // QT_NO_DATASTREAM
diff --git a/src/corelib/tools/qbitarray.h b/src/corelib/tools/qbitarray.h
index e724aea598..b9c36b5320 100644
--- a/src/corelib/tools/qbitarray.h
+++ b/src/corelib/tools/qbitarray.h
@@ -11,25 +11,70 @@ QT_BEGIN_NAMESPACE
class QBitRef;
class Q_CORE_EXPORT QBitArray
{
+ Q_CORE_EXPORT friend QBitArray operator&(const QBitArray &a1, const QBitArray &a2);
+ friend QBitArray operator&(QBitArray &&a1, const QBitArray &a2)
+ { return a1 &= a2; }
+ friend QBitArray operator&(const QBitArray &a1, QBitArray &&a2)
+ { return a2 &= a1; }
+ friend QBitArray operator&(QBitArray &&a1, QBitArray &&a2)
+ { return a1 &= a2; }
+
+ Q_CORE_EXPORT friend QBitArray operator|(const QBitArray &a1, const QBitArray &a2);
+ friend QBitArray operator|(QBitArray &&a1, const QBitArray &a2)
+ { return a1 |= a2; }
+ friend QBitArray operator|(const QBitArray &a1, QBitArray &&a2)
+ { return a2 |= a1; }
+ friend QBitArray operator|(QBitArray &&a1, QBitArray &&a2)
+ { return a1 |= a2; }
+
+ Q_CORE_EXPORT friend QBitArray operator^(const QBitArray &a1, const QBitArray &a2);
+ friend QBitArray operator^(QBitArray &&a1, const QBitArray &a2)
+ { return a1 ^= a2; }
+ friend QBitArray operator^(const QBitArray &a1, QBitArray &&a2)
+ { return a2 ^= a1; }
+ friend QBitArray operator^(QBitArray &&a1, QBitArray &&a2)
+ { return a1 ^= a2; }
+
#ifndef QT_NO_DATASTREAM
friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QBitArray &);
friend Q_CORE_EXPORT QDataStream &operator>>(QDataStream &, QBitArray &);
#endif
friend Q_CORE_EXPORT size_t qHash(const QBitArray &key, size_t seed) noexcept;
+ friend QBitArray operator~(QBitArray a)
+ { return std::move(a).inverted_inplace(); }
QByteArray d;
+ QBitArray(QByteArrayData &&dd) : d(std::move(dd)) {}
+
+ template <typename BitArray> static auto bitLocation(BitArray &ba, qsizetype i)
+ {
+ Q_ASSERT(size_t(i) < size_t(ba.size()));
+ struct R {
+ decltype(ba.d[1]) byte;
+ uchar bitMask;
+ };
+ qsizetype byteIdx = i >> 3;
+ qsizetype bitIdx = i & 7;
+ return R{ ba.d[1 + byteIdx], uchar(1U << bitIdx) };
+ }
+
+ QBitArray inverted_inplace() &&;
+
public:
inline QBitArray() noexcept {}
explicit QBitArray(qsizetype size, bool val = false);
+ // Rule Of Zero applies
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
QBitArray(const QBitArray &other) noexcept : d(other.d) {}
inline QBitArray &operator=(const QBitArray &other) noexcept { d = other.d; return *this; }
inline QBitArray(QBitArray &&other) noexcept : d(std::move(other.d)) {}
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QBitArray)
+#endif // Qt 6
void swap(QBitArray &other) noexcept { d.swap(other.d); }
- inline qsizetype size() const { return (d.size() << 3) - *d.constData(); }
- inline qsizetype count() const { return (d.size() << 3) - *d.constData(); }
+ qsizetype size() const { return qsizetype((size_t(d.size()) << 3) - *d.constData()); }
+ qsizetype count() const { return size(); }
qsizetype count(bool on) const;
inline bool isEmpty() const { return d.isEmpty(); }
@@ -41,25 +86,43 @@ public:
inline bool isDetached() const { return d.isDetached(); }
inline void clear() { d.clear(); }
- bool testBit(qsizetype i) const;
- void setBit(qsizetype i);
- void setBit(qsizetype i, bool val);
- void clearBit(qsizetype i);
- bool toggleBit(qsizetype i);
-
- bool at(qsizetype i) const;
- QBitRef operator[](qsizetype i);
- bool operator[](qsizetype i) const;
-
+ bool testBit(qsizetype i) const
+ { auto r = bitLocation(*this, i); return r.byte & r.bitMask; }
+ void setBit(qsizetype i)
+ { auto r = bitLocation(*this, i); r.byte |= r.bitMask; }
+ void setBit(qsizetype i, bool val)
+ { if (val) setBit(i); else clearBit(i); }
+ void clearBit(qsizetype i)
+ { auto r = bitLocation(*this, i); r.byte &= ~r.bitMask; }
+ bool toggleBit(qsizetype i)
+ {
+ auto r = bitLocation(*this, i);
+ bool cl = r.byte & r.bitMask;
+ r.byte ^= r.bitMask;
+ return cl;
+ }
+
+ bool at(qsizetype i) const { return testBit(i); }
+ inline QBitRef operator[](qsizetype i);
+ bool operator[](qsizetype i) const { return testBit(i); }
+
+ QBitArray &operator&=(QBitArray &&);
+ QBitArray &operator|=(QBitArray &&);
+ QBitArray &operator^=(QBitArray &&);
QBitArray &operator&=(const QBitArray &);
QBitArray &operator|=(const QBitArray &);
QBitArray &operator^=(const QBitArray &);
+#if QT_CORE_REMOVED_SINCE(6, 7)
QBitArray operator~() const;
+#endif
- inline bool operator==(const QBitArray &other) const { return d == other.d; }
- inline bool operator!=(const QBitArray &other) const { return d != other.d; }
+#if QT_CORE_REMOVED_SINCE(6, 8)
+ inline bool operator==(const QBitArray &other) const { return comparesEqual(d, other.d); }
+ inline bool operator!=(const QBitArray &other) const { return !operator==(other); }
+#endif
- inline bool fill(bool val, qsizetype size = -1);
+ bool fill(bool aval, qsizetype asize = -1)
+ { *this = QBitArray((asize < 0 ? this->size() : asize), aval); return true; }
void fill(bool val, qsizetype first, qsizetype last);
inline void truncate(qsizetype pos) { if (pos < size()) resize(pos); }
@@ -72,39 +135,17 @@ public:
public:
typedef QByteArray::DataPointer DataPtr;
inline DataPtr &data_ptr() { return d.data_ptr(); }
-};
+ inline const DataPtr &data_ptr() const { return d.data_ptr(); }
-inline bool QBitArray::fill(bool aval, qsizetype asize)
-{ *this = QBitArray((asize < 0 ? this->size() : asize), aval); return true; }
-
-Q_CORE_EXPORT QBitArray operator&(const QBitArray &, const QBitArray &);
-Q_CORE_EXPORT QBitArray operator|(const QBitArray &, const QBitArray &);
-Q_CORE_EXPORT QBitArray operator^(const QBitArray &, const QBitArray &);
-
-inline bool QBitArray::testBit(qsizetype i) const
-{ Q_ASSERT(size_t(i) < size_t(size()));
- return (*(reinterpret_cast<const uchar*>(d.constData())+1+(i>>3)) & (1 << (i & 7))) != 0; }
-
-inline void QBitArray::setBit(qsizetype i)
-{ Q_ASSERT(size_t(i) < size_t(size()));
- *(reinterpret_cast<uchar*>(d.data())+1+(i>>3)) |= uchar(1 << (i & 7)); }
-
-inline void QBitArray::clearBit(qsizetype i)
-{ Q_ASSERT(size_t(i) < size_t(size()));
- *(reinterpret_cast<uchar*>(d.data())+1+(i>>3)) &= ~uchar(1 << (i & 7)); }
-
-inline void QBitArray::setBit(qsizetype i, bool val)
-{ if (val) setBit(i); else clearBit(i); }
-
-inline bool QBitArray::toggleBit(qsizetype i)
-{ Q_ASSERT(size_t(i) < size_t(size()));
- uchar b = uchar(1<<(i&7)); uchar* p = reinterpret_cast<uchar*>(d.data())+1+(i>>3);
- uchar c = uchar(*p&b); *p^=b; return c!=0; }
-
-inline bool QBitArray::operator[](qsizetype i) const { return testBit(i); }
-inline bool QBitArray::at(qsizetype i) const { return testBit(i); }
+private:
+ friend bool comparesEqual(const QBitArray &lhs, const QBitArray &rhs) noexcept
+ {
+ return lhs.d == rhs.d;
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(QBitArray)
+};
-class Q_CORE_EXPORT QBitRef
+class QT6_ONLY(Q_CORE_EXPORT) QBitRef
{
private:
QBitArray &a;
@@ -119,7 +160,7 @@ public:
QBitRef &operator=(bool val) { a.setBit(i, val); return *this; }
};
-inline QBitRef QBitArray::operator[](qsizetype i)
+QBitRef QBitArray::operator[](qsizetype i)
{ Q_ASSERT(i >= 0); return QBitRef(*this, i); }
#ifndef QT_NO_DATASTREAM
diff --git a/src/corelib/tools/qcommandlineoption.cpp b/src/corelib/tools/qcommandlineoption.cpp
index f1816753e6..6b990cecf1 100644
--- a/src/corelib/tools/qcommandlineoption.cpp
+++ b/src/corelib/tools/qcommandlineoption.cpp
@@ -116,8 +116,7 @@ QCommandLineOption::QCommandLineOption(const QStringList &names)
The default value for the option is set to \a defaultValue.
In Qt versions before 5.4, this constructor was \c explicit. In Qt 5.4
- and later, it no longer is and can be used for C++11-style uniform
- initialization:
+ and later, it no longer is and can be used for uniform initialization:
\snippet code/src_corelib_tools_qcommandlineoption.cpp cxx11-init
@@ -152,8 +151,7 @@ QCommandLineOption::QCommandLineOption(const QString &name, const QString &descr
The default value for the option is set to \a defaultValue.
In Qt versions before 5.4, this constructor was \c explicit. In Qt 5.4
- and later, it no longer is and can be used for C++11-style uniform
- initialization:
+ and later, it no longer is and can be used for uniform initialization:
\snippet code/src_corelib_tools_qcommandlineoption.cpp cxx11-init-list
diff --git a/src/corelib/tools/qcommandlineparser.cpp b/src/corelib/tools/qcommandlineparser.cpp
index c0a073085d..2880eedf77 100644
--- a/src/corelib/tools/qcommandlineparser.cpp
+++ b/src/corelib/tools/qcommandlineparser.cpp
@@ -22,7 +22,7 @@ using namespace Qt::StringLiterals;
extern void Q_CORE_EXPORT qt_call_post_routines();
-typedef QHash<QString, int> NameHash_t;
+typedef QHash<QString, qsizetype> NameHash_t;
class QCommandLineParserPrivate
{
@@ -55,7 +55,7 @@ public:
NameHash_t nameHash;
//! Option values found (only for options with a value)
- QHash<int, QStringList> optionValuesHash;
+ QHash<qsizetype, QStringList> optionValuesHash;
//! Names of options found on the command line.
QStringList optionNames;
@@ -125,24 +125,24 @@ QStringList QCommandLineParserPrivate::aliases(const QString &optionName) const
The parser handles short names, long names, more than one name for the same
option, and option values.
- Options on the command line are recognized as starting with a single or
- double \c{-} character(s).
+ Options on the command line are recognized as starting with one or two
+ \c{-} characters, followed by the option name.
The option \c{-} (single dash alone) is a special case, often meaning standard
- input, and not treated as an option. The parser will treat everything after the
+ input, and is not treated as an option. The parser will treat everything after the
option \c{--} (double dash) as positional arguments.
Short options are single letters. The option \c{v} would be specified by
passing \c{-v} on the command line. In the default parsing mode, short options
can be written in a compact form, for instance \c{-abc} is equivalent to \c{-a -b -c}.
- The parsing mode for can be set to ParseAsLongOptions, in which case \c{-abc}
+ The parsing mode can be changed to ParseAsLongOptions, in which case \c{-abc}
will be parsed as the long option \c{abc}.
Long options are more than one letter long and cannot be compacted together.
The long option \c{verbose} would be passed as \c{--verbose} or \c{-verbose}.
- Passing values to options can be done using the assignment operator: \c{-v=value}
- \c{--verbose=value}, or a space: \c{-v value} \c{--verbose value}, i.e. the next
- argument is used as value (even if it starts with a \c{-}).
+ Passing values to options can be done by using the assignment operator (\c{-v=value},
+ \c{--verbose=value}), or with a space (\c{-v value}, \c{--verbose value}). This
+ works even if the the value starts with a \c{-}.
The parser does not support optional values - if an option is set to
require a value, one must be present. If such an option is placed last
@@ -157,13 +157,13 @@ QStringList QCommandLineParserPrivate::aliases(const QString &optionName) const
Example:
\snippet code/src_corelib_tools_qcommandlineparser_main.cpp 0
- If your compiler supports the C++11 standard, the three addOption() calls in
- the above example can be simplified:
+ The three addOption() calls in the above example can be made more compact
+ by using addOptions():
\snippet code/src_corelib_tools_qcommandlineparser_main.cpp cxx11
Known limitation: the parsing of Qt options inside QCoreApplication and subclasses
happens before QCommandLineParser exists, so it can't take it into account. This
- means any option value that looks like a builtin Qt option, will be treated by
+ means any option value that looks like a builtin Qt option will be treated by
QCoreApplication as a builtin Qt option. Example: \c{--profile -reverse} will
lead to QGuiApplication seeing the -reverse option set, and removing it from
QCoreApplication::arguments() before QCommandLineParser defines the \c{profile}
@@ -341,7 +341,7 @@ bool QCommandLineParser::addOption(const QCommandLineOption &option)
d->commandLineOptionList.append(option);
- const int offset = d->commandLineOptionList.size() - 1;
+ const qsizetype offset = d->commandLineOptionList.size() - 1;
for (const QString &name : optionNames)
d->nameHash.insert(name, offset);
@@ -389,13 +389,17 @@ QCommandLineOption QCommandLineParser::addVersionOption()
}
/*!
- Adds the help option (\c{-h}, \c{--help} and \c{-?} on Windows)
- as well as an option \c{--help-all} to include Qt-specific options in the output.
+ Adds help options to the command-line parser.
+
+ The options specified for this command-line are described by \c{-h} or
+ \c{--help}. On Windows, the alternative \c{-?} is also supported. The option
+ \c{--help-all} extends that to include generic Qt options, not defined by
+ this command, in the output.
These options are handled automatically by QCommandLineParser.
- Remember to use setApplicationDescription to set the application description,
- which will be displayed when this option is used.
+ Remember to use setApplicationDescription() to set the application
+ description, which will be displayed when this option is used.
Example:
\snippet code/src_corelib_tools_qcommandlineparser_main.cpp 0
@@ -411,7 +415,8 @@ QCommandLineOption QCommandLineParser::addHelpOption()
<< QStringLiteral("h")
<< QStringLiteral("help"), tr("Displays help on commandline options."));
addOption(opt);
- QCommandLineOption optHelpAll(QStringLiteral("help-all"), tr("Displays help including Qt specific options."));
+ QCommandLineOption optHelpAll(QStringLiteral("help-all"),
+ tr("Displays help, including generic Qt options."));
addOption(optHelpAll);
d->builtinHelpOption = true;
return opt;
@@ -503,7 +508,7 @@ QString QCommandLineParser::errorText() const
if (!d->errorText.isEmpty())
return d->errorText;
if (d->unknownOptionNames.size() == 1)
- return tr("Unknown option '%1'.").arg(d->unknownOptionNames.first());
+ return tr("Unknown option '%1'.").arg(d->unknownOptionNames.constFirst());
if (d->unknownOptionNames.size() > 1)
return tr("Unknown options: %1.").arg(d->unknownOptionNames.join(QStringLiteral(", ")));
return QString();
@@ -516,7 +521,8 @@ enum MessageType { UsageMessage, ErrorMessage };
// or we are run with redirected handles (for example, by QProcess).
static inline bool displayMessageBox()
{
- if (GetConsoleWindow())
+ if (GetConsoleWindow()
+ || qEnvironmentVariableIsSet("QT_COMMAND_LINE_PARSER_NO_GUI_MESSAGE_BOXES"))
return false;
STARTUPINFO startupInfo;
startupInfo.cb = sizeof(STARTUPINFO);
@@ -628,7 +634,7 @@ bool QCommandLineParserPrivate::parseOptionValue(const QString &optionName, cons
const QLatin1Char assignChar('=');
const NameHash_t::const_iterator nameHashIt = nameHash.constFind(optionName);
if (nameHashIt != nameHash.constEnd()) {
- const int assignPos = argument.indexOf(assignChar);
+ const qsizetype assignPos = argument.indexOf(assignChar);
const NameHash_t::mapped_type optionOffset = *nameHashIt;
const bool withValue = !commandLineOptionList.at(optionOffset).valueName().isEmpty();
if (withValue) {
@@ -668,7 +674,6 @@ bool QCommandLineParserPrivate::parse(const QStringList &args)
needsParsing = false;
bool error = false;
- const QString doubleDashString(QStringLiteral("--"));
const QLatin1Char dashChar('-');
const QLatin1Char assignChar('=');
@@ -692,7 +697,7 @@ bool QCommandLineParserPrivate::parse(const QStringList &args)
if (forcePositional) {
positionalArgumentList.append(argument);
- } else if (argument.startsWith(doubleDashString)) {
+ } else if (argument.startsWith("--"_L1)) {
if (argument.size() > 2) {
QString optionName = argument.mid(2).section(assignChar, 0, 0);
if (registerFoundOption(optionName)) {
@@ -781,7 +786,7 @@ bool QCommandLineParserPrivate::parse(const QStringList &args)
Returns \c true if the option \a name was set, false otherwise.
The name provided can be any long or short name of any option that was
- added with \c addOption(). All the options names are treated as being
+ added with addOption(). All the options names are treated as being
equivalent. If the name is not recognized or that option was not present,
false is returned.
@@ -807,7 +812,7 @@ bool QCommandLineParser::isSet(const QString &name) const
an empty string if not found.
The name provided can be any long or short name of any option that was
- added with \c addOption(). All the option names are treated as being
+ added with addOption(). All the option names are treated as being
equivalent. If the name is not recognized or that option was not present, an
empty string is returned.
@@ -815,7 +820,7 @@ bool QCommandLineParser::isSet(const QString &name) const
that option is returned. If the option wasn't specified on the command line,
the default value is returned.
- An empty string is returned if the option does not take a value.
+ If the option does not take a value, a warning is printed, and an empty string is returned.
\sa values(), QCommandLineOption::setDefaultValue(), QCommandLineOption::setDefaultValues()
*/
@@ -836,7 +841,7 @@ QString QCommandLineParser::value(const QString &optionName) const
optionName, or an empty list if not found.
The name provided can be any long or short name of any option that was
- added with \c addOption(). All the options names are treated as being
+ added with addOption(). All the options names are treated as being
equivalent. If the name is not recognized or that option was not present, an
empty list is returned.
@@ -852,12 +857,18 @@ QString QCommandLineParser::value(const QString &optionName) const
QStringList QCommandLineParser::values(const QString &optionName) const
{
d->checkParsed("values");
- const NameHash_t::const_iterator it = d->nameHash.constFind(optionName);
+ auto it = d->nameHash.constFind(optionName);
if (it != d->nameHash.cend()) {
- const int optionOffset = *it;
+ const qsizetype optionOffset = *it;
QStringList values = d->optionValuesHash.value(optionOffset);
- if (values.isEmpty())
- values = d->commandLineOptionList.at(optionOffset).defaultValues();
+ if (values.isEmpty()) {
+ const auto &option = d->commandLineOptionList.at(optionOffset);
+ if (option.valueName().isEmpty()) {
+ qWarning("QCommandLineParser: option not expecting values: \"%ls\"",
+ qUtf16Printable(optionName));
+ }
+ values = option.defaultValues();
+ }
return values;
}
@@ -944,8 +955,8 @@ QStringList QCommandLineParser::positionalArguments() const
Names may appear more than once in this list if they were encountered
more than once by the parser.
- Any entry in the list can be used with \c value() or with
- \c values() to get any relevant option values.
+ Any entry in the list can be used with value() or with
+ values() to get any relevant option values.
*/
QStringList QCommandLineParser::optionNames() const
@@ -1040,20 +1051,20 @@ static QString wrapText(const QString &names, int optionNameMaxWidth, const QStr
};
QString text;
- int lineStart = 0;
- int lastBreakable = -1;
+ qsizetype lineStart = 0;
+ qsizetype lastBreakable = -1;
const int max = 79 - (indentation.size() + optionNameMaxWidth + 1);
int x = 0;
- const int len = description.size();
+ const qsizetype len = description.size();
- for (int i = 0; i < len; ++i) {
+ for (qsizetype i = 0; i < len; ++i) {
++x;
const QChar c = description.at(i);
if (c.isSpace())
lastBreakable = i;
- int breakAt = -1;
- int nextLineStart = -1;
+ qsizetype breakAt = -1;
+ qsizetype nextLineStart = -1;
if (x > max && lastBreakable != -1) {
// time to break and we know where
breakAt = lastBreakable;
@@ -1069,7 +1080,7 @@ static QString wrapText(const QString &names, int optionNameMaxWidth, const QStr
}
if (breakAt != -1) {
- const int numChars = breakAt - lineStart;
+ const qsizetype numChars = breakAt - lineStart;
//qDebug() << "breakAt=" << description.at(breakAt) << "breakAtSpace=" << breakAtSpace << lineStart << "to" << breakAt << description.mid(lineStart, numChars);
text += indentation + nextNameSection().leftJustified(optionNameMaxWidth) + u' ';
text += QStringView{description}.mid(lineStart, numChars) + nl;
@@ -1095,7 +1106,8 @@ QString QCommandLineParserPrivate::helpText(bool includeQtOptions) const
QString text;
QString usage;
// executable name
- usage += qApp ? QCoreApplication::arguments().constFirst() : QStringLiteral("<executable_name>");
+ usage += qApp ? QStringView(QCoreApplication::arguments().constFirst())
+ : QStringView(u"<executable_name>");
QList<QCommandLineOption> options = commandLineOptionList;
if (includeQtOptions && qApp)
qApp->d_func()->addQtOptions(&options);
@@ -1111,7 +1123,7 @@ QString QCommandLineParserPrivate::helpText(bool includeQtOptions) const
text += QCommandLineParser::tr("Options:") + nl;
QStringList optionNameList;
optionNameList.reserve(options.size());
- int longestOptionNameString = 0;
+ qsizetype longestOptionNameString = 0;
for (const QCommandLineOption &option : std::as_const(options)) {
if (option.flags() & QCommandLineOption::HiddenFromHelp)
continue;
@@ -1130,7 +1142,7 @@ QString QCommandLineParserPrivate::helpText(bool includeQtOptions) const
longestOptionNameString = qMax(longestOptionNameString, optionNamesString.size());
}
++longestOptionNameString;
- const int optionNameMaxWidth = qMin(50, longestOptionNameString);
+ const int optionNameMaxWidth = qMin(50, int(longestOptionNameString));
auto optionNameIterator = optionNameList.cbegin();
for (const QCommandLineOption &option : std::as_const(options)) {
if (option.flags() & QCommandLineOption::HiddenFromHelp)
diff --git a/src/corelib/tools/qcontainerfwd.h b/src/corelib/tools/qcontainerfwd.h
index b876c4648f..d5590553fa 100644
--- a/src/corelib/tools/qcontainerfwd.h
+++ b/src/corelib/tools/qcontainerfwd.h
@@ -1,17 +1,20 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <QtCore/qglobal.h>
-
#ifndef QCONTAINERFWD_H
#define QCONTAINERFWD_H
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qtypes.h>
+
#if 0
#pragma qt_class(QtContainerFwd)
#endif
// std headers can unfortunately not be forward declared
+#include <cstddef> // std::size_t
#include <utility>
+#include <limits>
QT_BEGIN_NAMESPACE
@@ -20,12 +23,16 @@ template <typename Key, typename T> class QHash;
template <typename Key, typename T> class QMap;
template <typename Key, typename T> class QMultiHash;
template <typename Key, typename T> class QMultiMap;
+#ifndef QT_NO_QPAIR
template <typename T1, typename T2>
using QPair = std::pair<T1, T2>;
+#endif
template <typename T> class QQueue;
template <typename T> class QSet;
+template <typename T, std::size_t E = std::size_t(-1) /* = std::dynamic_extent*/> class QSpan;
template <typename T> class QStack;
-template <typename T, qsizetype Prealloc = 256> class QVarLengthArray;
+constexpr qsizetype QVarLengthArrayDefaultPrealloc = 256;
+template <typename T, qsizetype Prealloc = QVarLengthArrayDefaultPrealloc> class QVarLengthArray;
template <typename T> class QList;
class QString;
#ifndef Q_QDOC
@@ -44,7 +51,13 @@ class QVariant;
using QVariantList = QList<QVariant>;
using QVariantMap = QMap<QString, QVariant>;
using QVariantHash = QHash<QString, QVariant>;
-using QVariantPair = QPair<QVariant, QVariant>;
+using QVariantPair = std::pair<QVariant, QVariant>;
+
+namespace QtPrivate
+{
+[[maybe_unused]]
+constexpr qsizetype MaxAllocSize = (std::numeric_limits<qsizetype>::max)();
+}
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qcontainertools_impl.h b/src/corelib/tools/qcontainertools_impl.h
index dec60aa076..998bc292d4 100644
--- a/src/corelib/tools/qcontainertools_impl.h
+++ b/src/corelib/tools/qcontainertools_impl.h
@@ -72,6 +72,8 @@ template <typename T, typename N>
void q_uninitialized_relocate_n(T* first, N n, T* out)
{
if constexpr (QTypeInfo<T>::isRelocatable) {
+ static_assert(std::is_copy_constructible_v<T> || std::is_move_constructible_v<T>,
+ "Refusing to relocate this non-copy/non-move-constructible type.");
if (n != N(0)) { // even if N == 0, out == nullptr or first == nullptr are UB for memcpy()
std::memcpy(static_cast<void *>(out),
static_cast<const void *>(first),
@@ -252,6 +254,13 @@ void q_relocate_overlap_n(T *first, N n, T *d_first)
}
}
+template <typename T>
+struct ArrowProxy
+{
+ T t;
+ T *operator->() noexcept { return &t; }
+};
+
template <typename Iterator>
using IfIsInputIterator = typename std::enable_if<
std::is_convertible<typename std::iterator_traits<Iterator>::iterator_category, std::input_iterator_tag>::value,
@@ -300,7 +309,20 @@ using IfAssociativeIteratorHasKeyAndValue =
template <typename Iterator>
using IfAssociativeIteratorHasFirstAndSecond =
- std::enable_if_t<qxp::is_detected_v<FirstAndSecondTest, Iterator>, bool>;
+ std::enable_if_t<
+ std::conjunction_v<
+ std::negation<qxp::is_detected<KeyAndValueTest, Iterator>>,
+ qxp::is_detected<FirstAndSecondTest, Iterator>
+ >, bool>;
+
+template <typename Iterator>
+using MoveBackwardsTest = decltype(
+ std::declval<Iterator &>().operator--()
+);
+
+template <typename Iterator>
+using IfIteratorCanMoveBackwards =
+ std::enable_if_t<qxp::is_detected_v<MoveBackwardsTest, Iterator>, bool>;
template <typename T, typename U>
using IfIsNotSame =
@@ -358,8 +380,7 @@ template <typename Container, typename T>
auto sequential_erase_with_copy(Container &c, const T &t)
{
using CopyProxy = std::conditional_t<std::is_copy_constructible_v<T>, T, const T &>;
- const T &tCopy = CopyProxy(t);
- return sequential_erase(c, tCopy);
+ return sequential_erase(c, CopyProxy(t));
}
template <typename Container, typename T>
diff --git a/src/corelib/tools/qcontiguouscache.cpp b/src/corelib/tools/qcontiguouscache.cpp
index 73cfed97f2..d28d1e7153 100644
--- a/src/corelib/tools/qcontiguouscache.cpp
+++ b/src/corelib/tools/qcontiguouscache.cpp
@@ -6,6 +6,8 @@
#include <QDebug>
#endif
+#include <QtCore/qmalloc.h>
+
QT_BEGIN_NAMESPACE
#ifdef QT_QCONTIGUOUSCACHE_DEBUG
diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h
index 98fa82fda9..c01dbb9390 100644
--- a/src/corelib/tools/qcontiguouscache.h
+++ b/src/corelib/tools/qcontiguouscache.h
@@ -5,7 +5,13 @@
#define QCONTIGUOUSCACHE_H
#include <QtCore/qatomic.h>
-#include <limits.h>
+#include <QtCore/qassert.h>
+#include <QtCore/qtclasshelpermacros.h>
+#include <QtCore/qtcoreexports.h>
+#include <QtCore/qtypeinfo.h>
+
+#include <climits>
+#include <limits>
#include <new>
QT_BEGIN_NAMESPACE
diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp
index 2c4a2b276b..2e82a394ee 100644
--- a/src/corelib/tools/qcryptographichash.cpp
+++ b/src/corelib/tools/qcryptographichash.cpp
@@ -25,12 +25,13 @@
#include "../../3rdparty/rfc6234/sha.h"
#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
-#if !QT_CONFIG(opensslv30) || !QT_CONFIG(openssl_linked)
+#if !QT_CONFIG(openssl_hash)
// qdoc and qmake only need SHA-1
#include "../../3rdparty/md5/md5.h"
#include "../../3rdparty/md5/md5.cpp"
#include "../../3rdparty/md4/md4.h"
#include "../../3rdparty/md4/md4.cpp"
+#endif // !QT_CONFIG(openssl_hash)
typedef unsigned char BitSequence;
typedef unsigned long long DataLength;
@@ -71,6 +72,7 @@ Q_CONSTINIT static SHA3Final * const sha3Final = Final;
#endif
+#if !QT_CONFIG(openssl_hash)
/*
These 2 functions replace macros of the same name in sha224-256.c and
sha384-512.c. Originally, these macros relied on a global static 'addTemp'
@@ -114,7 +116,7 @@ static inline int SHA384_512AddLength(SHA512Context *context, unsigned int lengt
#endif
#endif // QT_CRYPTOGRAPHICHASH_ONLY_SHA1
-#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(opensslv30) && QT_CONFIG(openssl_linked)
+#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(openssl_hash)
#define USING_OPENSSL30
#include <openssl/evp.h>
#include <openssl/provider.h>
@@ -266,10 +268,6 @@ static constexpr const char * methodToName(QCryptographicHash::Algorithm method)
CASE(RealSha3_256, "SHA3-256");
CASE(RealSha3_384, "SHA3-384");
CASE(RealSha3_512, "SHA3-512");
- CASE(Keccak_224, "SHA3-224");
- CASE(Keccak_256, "SHA3-256");
- CASE(Keccak_384, "SHA3-384");
- CASE(Keccak_512, "SHA3-512");
CASE(Blake2b_512, "BLAKE2B512");
CASE(Blake2s_256, "BLAKE2S256");
#undef CASE
@@ -283,7 +281,9 @@ static constexpr const char * methodToName(QCryptographicHash::Algorithm method)
*/
static constexpr bool useNonOpenSSLFallback(QCryptographicHash::Algorithm method) noexcept
{
- if (method == QCryptographicHash::Blake2b_160 || method == QCryptographicHash::Blake2b_256 ||
+ if (method == QCryptographicHash::Keccak_224 || method == QCryptographicHash::Keccak_256 ||
+ method == QCryptographicHash::Keccak_384 || method == QCryptographicHash::Keccak_512 ||
+ method == QCryptographicHash::Blake2b_160 || method == QCryptographicHash::Blake2b_256 ||
method == QCryptographicHash::Blake2b_384 || method == QCryptographicHash::Blake2s_128 ||
method == QCryptographicHash::Blake2s_160 || method == QCryptographicHash::Blake2s_224)
return true;
@@ -326,11 +326,20 @@ public:
EVP_MD_free(md);
}
};
+ struct OSSL_PROVIDER_deleter {
+ void operator()(OSSL_PROVIDER *provider) const noexcept {
+ OSSL_PROVIDER_unload(provider);
+ }
+ };
+
using EVP_MD_CTX_ptr = std::unique_ptr<EVP_MD_CTX, EVP_MD_CTX_deleter>;
using EVP_MD_ptr = std::unique_ptr<EVP_MD, EVP_MD_deleter>;
+ using OSSL_PROVIDER_ptr = std::unique_ptr<OSSL_PROVIDER, OSSL_PROVIDER_deleter>;
struct EVP {
EVP_MD_ptr algorithm;
EVP_MD_CTX_ptr context;
+ OSSL_PROVIDER_ptr defaultProvider;
+ OSSL_PROVIDER_ptr legacyProvider;
bool initializationFailed;
explicit EVP(QCryptographicHash::Algorithm method);
@@ -361,11 +370,11 @@ public:
SHA256Context sha256Context;
SHA384Context sha384Context;
SHA512Context sha512Context;
+#endif
SHA3Context sha3Context;
enum class Sha3Variant { Sha3, Keccak };
void sha3Finish(HashResult &result, int bitCount, Sha3Variant sha3Variant);
-#endif
blake2b_state blake2bContext;
blake2s_state blake2sContext;
#endif
@@ -378,7 +387,6 @@ public:
};
#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
-#ifndef USING_OPENSSL30
void QCryptographicHashPrivate::State::sha3Finish(HashResult &result, int bitCount,
Sha3Variant sha3Variant)
{
@@ -418,7 +426,6 @@ void QCryptographicHashPrivate::State::sha3Finish(HashResult &result, int bitCou
sha3Final(&copy, result.data());
}
-#endif // !QT_CONFIG(opensslv30)
#endif
/*!
@@ -548,9 +555,15 @@ QCryptographicHash::Algorithm QCryptographicHash::algorithm() const noexcept
QCryptographicHashPrivate::State::State(QCryptographicHash::Algorithm method)
{
- if (method == QCryptographicHash::Blake2b_160 ||
- method == QCryptographicHash::Blake2b_256 ||
- method == QCryptographicHash::Blake2b_384) {
+ if (method == QCryptographicHash::Keccak_224 ||
+ method == QCryptographicHash::Keccak_256 ||
+ method == QCryptographicHash::Keccak_384 ||
+ method == QCryptographicHash::Keccak_512) {
+ new (&sha3Context) SHA3Context;
+ reset(method);
+ } else if (method == QCryptographicHash::Blake2b_160 ||
+ method == QCryptographicHash::Blake2b_256 ||
+ method == QCryptographicHash::Blake2b_384) {
new (&blake2bContext) blake2b_state;
reset(method);
} else if (method == QCryptographicHash::Blake2s_128 ||
@@ -565,7 +578,11 @@ QCryptographicHashPrivate::State::State(QCryptographicHash::Algorithm method)
void QCryptographicHashPrivate::State::destroy(QCryptographicHash::Algorithm method)
{
- if (method != QCryptographicHash::Blake2b_160 &&
+ if (method != QCryptographicHash::Keccak_224 &&
+ method != QCryptographicHash::Keccak_256 &&
+ method != QCryptographicHash::Keccak_384 &&
+ method != QCryptographicHash::Keccak_512 &&
+ method != QCryptographicHash::Blake2b_160 &&
method != QCryptographicHash::Blake2b_256 &&
method != QCryptographicHash::Blake2b_384 &&
method != QCryptographicHash::Blake2s_128 &&
@@ -583,12 +600,16 @@ QCryptographicHashPrivate::EVP::EVP(QCryptographicHash::Algorithm method)
* We need to load the legacy provider in order to have the MD4
* algorithm available.
*/
- if (!OSSL_PROVIDER_load(nullptr, "legacy"))
- return;
- if (!OSSL_PROVIDER_load(nullptr, "default"))
+ legacyProvider = OSSL_PROVIDER_ptr(OSSL_PROVIDER_load(nullptr, "legacy"));
+
+ if (!legacyProvider)
return;
}
+ defaultProvider = OSSL_PROVIDER_ptr(OSSL_PROVIDER_load(nullptr, "default"));
+ if (!defaultProvider)
+ return;
+
context = EVP_MD_CTX_ptr(EVP_MD_CTX_new());
if (!context) {
@@ -685,9 +706,14 @@ void QCryptographicHashPrivate::reset() noexcept
void QCryptographicHashPrivate::State::reset(QCryptographicHash::Algorithm method) noexcept
{
- if (method == QCryptographicHash::Blake2b_160 ||
- method == QCryptographicHash::Blake2b_256 ||
- method == QCryptographicHash::Blake2b_384) {
+ if (method == QCryptographicHash::Keccak_224 ||
+ method == QCryptographicHash::Keccak_256 ||
+ method == QCryptographicHash::Keccak_384 ||
+ method == QCryptographicHash::Keccak_512) {
+ sha3Init(&sha3Context, hashLengthInternal(method) * 8);
+ } else if (method == QCryptographicHash::Blake2b_160 ||
+ method == QCryptographicHash::Blake2b_256 ||
+ method == QCryptographicHash::Blake2b_384) {
blake2b_init(&blake2bContext, hashLengthInternal(method));
} else if (method == QCryptographicHash::Blake2s_128 ||
method == QCryptographicHash::Blake2s_160 ||
@@ -813,9 +839,14 @@ void QCryptographicHashPrivate::State::addData(QCryptographicHash::Algorithm met
auto length = bytes.size();
// all functions take size_t length, so we don't need to loop around them:
{
- if (method == QCryptographicHash::Blake2b_160 ||
- method == QCryptographicHash::Blake2b_256 ||
- method == QCryptographicHash::Blake2b_384) {
+ if (method == QCryptographicHash::Keccak_224 ||
+ method == QCryptographicHash::Keccak_256 ||
+ method == QCryptographicHash::Keccak_384 ||
+ method == QCryptographicHash::Keccak_512) {
+ sha3Update(&sha3Context, reinterpret_cast<const BitSequence *>(data), uint64_t(length) * 8);
+ } else if (method == QCryptographicHash::Blake2b_160 ||
+ method == QCryptographicHash::Blake2b_256 ||
+ method == QCryptographicHash::Blake2b_384) {
blake2b_update(&blake2bContext, reinterpret_cast<const uint8_t *>(data), length);
} else if (method == QCryptographicHash::Blake2s_128 ||
method == QCryptographicHash::Blake2s_160 ||
@@ -987,9 +1018,14 @@ void QCryptographicHashPrivate::finalizeUnchecked() noexcept
void QCryptographicHashPrivate::State::finalizeUnchecked(QCryptographicHash::Algorithm method,
HashResult &result) noexcept
{
- if (method == QCryptographicHash::Blake2b_160 ||
- method == QCryptographicHash::Blake2b_256 ||
- method == QCryptographicHash::Blake2b_384) {
+ if (method == QCryptographicHash::Keccak_224 ||
+ method == QCryptographicHash::Keccak_256 ||
+ method == QCryptographicHash::Keccak_384 ||
+ method == QCryptographicHash::Keccak_512) {
+ sha3Finish(result, 8 * hashLengthInternal(method), Sha3Variant::Keccak);
+ } else if (method == QCryptographicHash::Blake2b_160 ||
+ method == QCryptographicHash::Blake2b_256 ||
+ method == QCryptographicHash::Blake2b_384) {
const auto length = hashLengthInternal(method);
blake2b_state copy = blake2bContext;
result.resizeForOverwrite(length);
@@ -1163,8 +1199,8 @@ bool QCryptographicHashPrivate::supportsAlgorithm(QCryptographicHash::Algorithm
if (useNonOpenSSLFallback(method))
return true;
- OSSL_PROVIDER_load(nullptr, "legacy");
- OSSL_PROVIDER_load(nullptr, "default");
+ auto legacyProvider = OSSL_PROVIDER_ptr(OSSL_PROVIDER_load(nullptr, "legacy"));
+ auto defaultProvider = OSSL_PROVIDER_ptr(OSSL_PROVIDER_load(nullptr, "default"));
const char *restriction = "-fips";
EVP_MD_ptr algorithm = EVP_MD_ptr(EVP_MD_fetch(nullptr, methodToName(method), restriction));
@@ -1246,7 +1282,7 @@ static constexpr int qt_hash_block_size(QCryptographicHash::Algorithm method)
return BLAKE2S_BLOCKBYTES;
#endif // QT_CRYPTOGRAPHICHASH_ONLY_SHA1
case QCryptographicHash::NumAlgorithms:
-#if !defined(Q_GCC_ONLY) || Q_CC_GCC >= 900
+#if !defined(Q_CC_GNU_ONLY) || Q_CC_GNU >= 900
// GCC 8 has trouble with Q_UNREACHABLE() in constexpr functions
Q_UNREACHABLE();
#endif
@@ -1289,9 +1325,9 @@ using HashBlock = QSmallByteArray<maxHashBlockSize()>;
static HashBlock xored(const HashBlock &block, quint8 val) noexcept
{
// some hints for the optimizer:
- Q_ASSUME(block.size() >= minHashBlockSize());
- Q_ASSUME(block.size() <= maxHashBlockSize());
- Q_ASSUME(block.size() % gcdHashBlockSize() == 0);
+ Q_ASSERT(block.size() >= minHashBlockSize());
+ Q_ASSERT(block.size() <= maxHashBlockSize());
+ Q_ASSERT(block.size() % gcdHashBlockSize() == 0);
HashBlock result;
result.resizeForOverwrite(block.size());
for (qsizetype i = 0; i < block.size(); ++i)
@@ -1381,21 +1417,32 @@ void QMessageAuthenticationCodePrivate::initMessageHash() noexcept
\ingroup tools
\reentrant
- QMessageAuthenticationCode supports all cryptographic hashes which are supported by
- QCryptographicHash.
+ Use the QMessageAuthenticationCode class to generate hash-based message
+ authentication codes (HMACs). The class supports all cryptographic
+ hash algorithms from \l QCryptographicHash (see also
+ \l{QCryptographicHash::Algorithm}).
+
+ To generate a message authentication code, pass a suitable hash
+ algorithm and secret key to the constructor. Then process the message
+ data by calling \l addData() one or more times. After the full
+ message has been processed, get the final authentication code
+ via the \l result() function:
- To generate message authentication code, pass hash algorithm QCryptographicHash::Algorithm
- to constructor, then set key and message by setKey() and addData() functions. Result
- can be acquired by result() function.
\snippet qmessageauthenticationcode/main.cpp 0
\dots
\snippet qmessageauthenticationcode/main.cpp 1
- Alternatively, this effect can be achieved by providing message,
- key and method to hash() method.
+ For simple cases like above, you can also use the static
+ \l hash() function:
+
\snippet qmessageauthenticationcode/main.cpp 2
- \sa QCryptographicHash
+
+ \note The cryptographic strength of the HMAC depends upon the
+ size of the secret key, and the security of the
+ underlying hash function.
+
+ \sa QCryptographicHash, QCryptographicHash::Algorithm
*/
/*!
@@ -1460,7 +1507,7 @@ QMessageAuthenticationCode::~QMessageAuthenticationCode()
*/
/*!
- Resets message data. Calling this method doesn't affect the key.
+ Resets message data. Calling this function doesn't affect the key.
*/
void QMessageAuthenticationCode::reset() noexcept
{
@@ -1469,9 +1516,9 @@ void QMessageAuthenticationCode::reset() noexcept
}
/*!
- Sets secret \a key. Calling this method automatically resets the object state.
+ Sets secret \a key. Calling this function automatically resets the object state.
- For optimal performance, call this method only to \e change the active key,
+ For optimal performance, call this function only to \e change the active key,
not to set an \e initial key, as in
\code
diff --git a/src/corelib/tools/qduplicatetracker_p.h b/src/corelib/tools/qduplicatetracker_p.h
index 950220184f..23465ecffe 100644
--- a/src/corelib/tools/qduplicatetracker_p.h
+++ b/src/corelib/tools/qduplicatetracker_p.h
@@ -16,7 +16,7 @@
#include <private/qglobal_p.h>
-#if __has_include(<memory_resource>)
+#ifdef __cpp_lib_memory_resource
# include <unordered_set>
# include <memory_resource>
# include <qhash.h> // for the hashing helpers
diff --git a/src/corelib/tools/qflatmap_p.h b/src/corelib/tools/qflatmap_p.h
index 68ab567439..d2c0d45b79 100644
--- a/src/corelib/tools/qflatmap_p.h
+++ b/src/corelib/tools/qflatmap_p.h
@@ -83,6 +83,7 @@ public:
}
};
+namespace qflatmap {
namespace detail {
template <class T>
class QFlatMapMockPointer
@@ -100,6 +101,7 @@ public:
}
};
} // namespace detail
+} // namespace qflatmap
template<class Key, class T, class Compare = std::less<Key>, class KeyContainer = QList<Key>,
class MappedContainer = QList<T>>
@@ -107,8 +109,9 @@ class QFlatMap : private QFlatMapValueCompare<Key, T, Compare>
{
static_assert(std::is_nothrow_destructible_v<T>, "Types with throwing destructors are not supported in Qt containers.");
- template <class U>
- using mock_pointer = detail::QFlatMapMockPointer<U>;
+ template<class U>
+ using mock_pointer = qflatmap::detail::QFlatMapMockPointer<U>;
+
public:
using key_type = Key;
using mapped_type = T;
@@ -1096,7 +1099,9 @@ private:
containers c;
};
-template<class Key, class T, qsizetype N = 256, class Compare = std::less<Key>>
+template <class Key, class T,
+ qsizetype N = QVarLengthArrayDefaultPrealloc,
+ class Compare = std::less<Key>>
using QVarLengthFlatMap = QFlatMap<Key, T, Compare, QVarLengthArray<Key, N>, QVarLengthArray<T, N>>;
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qfreelist.cpp b/src/corelib/tools/qfreelist.cpp
index 45bd3ba8ae..db15fac5d6 100644
--- a/src/corelib/tools/qfreelist.cpp
+++ b/src/corelib/tools/qfreelist.cpp
@@ -6,6 +6,7 @@
QT_BEGIN_NAMESPACE
// default sizes and offsets (no need to define these when customizing)
+namespace QFreeListDefaultConstantsPrivate {
enum {
Offset0 = 0x00000000,
Offset1 = 0x00008000,
@@ -17,12 +18,13 @@ enum {
Size2 = Offset3 - Offset2,
Size3 = QFreeListDefaultConstants::MaxIndex - Offset3
};
+}
Q_CONSTINIT const int QFreeListDefaultConstants::Sizes[QFreeListDefaultConstants::BlockCount] = {
- Size0,
- Size1,
- Size2,
- Size3
+ QFreeListDefaultConstantsPrivate::Size0,
+ QFreeListDefaultConstantsPrivate::Size1,
+ QFreeListDefaultConstantsPrivate::Size2,
+ QFreeListDefaultConstantsPrivate::Size3
};
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qfunctionaltools_impl.cpp b/src/corelib/tools/qfunctionaltools_impl.cpp
new file mode 100644
index 0000000000..28148c39a2
--- /dev/null
+++ b/src/corelib/tools/qfunctionaltools_impl.cpp
@@ -0,0 +1,47 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtCore/qfunctionaltools_impl.h>
+
+// Remove this file once we have tests that implicitly test all aspects of
+// CompactStorage
+
+QT_BEGIN_NAMESPACE
+
+namespace QtPrivate {
+
+#define FOR_EACH_CVREF(op) \
+ op(&) \
+ op(const &) \
+ op(&&) \
+ op(const &&) \
+ /* end */
+
+namespace _testing {
+ struct empty {};
+ struct final final {};
+ static_assert(std::is_same_v<CompactStorage<empty>,
+ detail::StorageEmptyBaseClassOptimization<empty>>);
+ static_assert(std::is_same_v<CompactStorage<final>,
+ detail::StorageByValue<final>>);
+ static_assert(std::is_same_v<CompactStorage<int>,
+ detail::StorageByValue<int>>);
+#define CHECK1(Obj, cvref) \
+ static_assert(std::is_same_v<decltype(std::declval<CompactStorage< Obj > cvref>().object()), \
+ Obj cvref>);
+#define CHECK(cvref) \
+ CHECK1(empty, cvref) \
+ CHECK1(final, cvref) \
+ CHECK1(int, cvref) \
+ /* end */
+
+ FOR_EACH_CVREF(CHECK)
+#undef CHECK
+#undef CHECK1
+} // namespace _testing
+
+} // namespace QtPrivate
+
+#undef FOR_EACH_CVREF
+
+QT_END_NAMESPACE
diff --git a/src/corelib/tools/qfunctionaltools_impl.h b/src/corelib/tools/qfunctionaltools_impl.h
new file mode 100644
index 0000000000..0942d5fe7d
--- /dev/null
+++ b/src/corelib/tools/qfunctionaltools_impl.h
@@ -0,0 +1,77 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#if 0
+#pragma qt_sync_skip_header_check
+#pragma qt_sync_stop_processing
+#endif
+
+#ifndef QFUNCTIONALTOOLS_IMPL_H
+#define QFUNCTIONALTOOLS_IMPL_H
+
+#include <QtCore/qtconfigmacros.h>
+
+#include <type_traits>
+#include <utility>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtPrivate {
+
+namespace detail {
+
+#define FOR_EACH_CVREF(op) \
+ op(&) \
+ op(const &) \
+ op(&&) \
+ op(const &&) \
+ /* end */
+
+
+template <typename Object, typename = void>
+struct StorageByValue
+{
+ Object o;
+#define MAKE_GETTER(cvref) \
+ constexpr Object cvref object() cvref noexcept \
+ { return static_cast<Object cvref>(o); }
+ FOR_EACH_CVREF(MAKE_GETTER)
+#undef MAKE_GETTER
+};
+
+template <typename Object, typename Tag = void>
+struct StorageEmptyBaseClassOptimization : Object
+{
+ StorageEmptyBaseClassOptimization() = default;
+ StorageEmptyBaseClassOptimization(Object &&o)
+ : Object(std::move(o))
+ {}
+ StorageEmptyBaseClassOptimization(const Object &o)
+ : Object(o)
+ {}
+
+#define MAKE_GETTER(cvref) \
+ constexpr Object cvref object() cvref noexcept \
+ { return static_cast<Object cvref>(*this); }
+ FOR_EACH_CVREF(MAKE_GETTER)
+#undef MAKE_GETTER
+};
+} // namespace detail
+
+template <typename Object, typename Tag = void>
+using CompactStorage = typename std::conditional_t<
+ std::conjunction_v<
+ std::is_empty<Object>,
+ std::negation<std::is_final<Object>>
+ >,
+ detail::StorageEmptyBaseClassOptimization<Object, Tag>,
+ detail::StorageByValue<Object, Tag>
+ >;
+
+} // namespace QtPrivate
+
+#undef FOR_EACH_CVREF
+
+QT_END_NAMESPACE
+
+#endif // QFUNCTIONALTOOLS_IMPL_H
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index db52852dc8..12e90daecf 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -49,6 +49,8 @@
QT_BEGIN_NAMESPACE
+void qt_from_latin1(char16_t *dst, const char *str, size_t size) noexcept; // qstring.cpp
+
// We assume that pointers and size_t have the same size. If that assumption should fail
// on a platform the code selecting the different methods below needs to be fixed.
static_assert(sizeof(size_t) == QT_POINTER_SIZE, "size_t and pointers have different size.");
@@ -83,6 +85,7 @@ struct HashSeedStorage
void resetSeed()
{
+#ifndef QT_BOOTSTRAPPED
if (state().state < AlreadyInitialized)
return;
@@ -90,6 +93,7 @@ struct HashSeedStorage
QRandomGenerator *generator = QRandomGenerator::system();
seeds[0].storeRelaxed(sizeof(size_t) > sizeof(quint32)
? generator->generate64() : generator->generate());
+#endif
}
void clearSeed()
@@ -281,17 +285,11 @@ static inline uint64_t murmurhash(const void *key, uint64_t len, uint64_t seed)
#endif
-#if QT_POINTER_SIZE == 8
+namespace {
// This is an inlined version of the SipHash implementation that is
// trying to avoid some memcpy's from uint64 to uint8[] and back.
-//
-
-// Use SipHash-1-2, which has similar performance characteristics as
-// stablehash() above, instead of the SipHash-2-4 default
-#define cROUNDS 1
-#define dROUNDS 2
-#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
+#define ROTL(x, b) (((x) << (b)) | ((x) >> (sizeof(x) * 8 - (b))))
#define SIPROUND \
do { \
@@ -311,8 +309,7 @@ static inline uint64_t murmurhash(const void *key, uint64_t len, uint64_t seed)
v2 = ROTL(v2, 32); \
} while (0)
-Q_NEVER_INLINE Q_DECL_HOT_FUNCTION
-static uint64_t siphash(const uint8_t *in, uint64_t inlen, uint64_t seed, uint64_t seed2)
+template <int cROUNDS = 2, int dROUNDS = 4> struct SipHash64
{
/* "somepseudorandomlygeneratedbytes" */
uint64_t v0 = 0x736f6d6570736575ULL;
@@ -320,17 +317,32 @@ static uint64_t siphash(const uint8_t *in, uint64_t inlen, uint64_t seed, uint64
uint64_t v2 = 0x6c7967656e657261ULL;
uint64_t v3 = 0x7465646279746573ULL;
uint64_t b;
- uint64_t k0 = seed;
- uint64_t k1 = seed2;
- int i;
- const uint8_t *end = in + (inlen & ~7ULL);
- const int left = inlen & 7;
+ uint64_t k0;
+ uint64_t k1;
+
+ inline SipHash64(uint64_t fulllen, uint64_t seed, uint64_t seed2);
+ inline void addBlock(const uint8_t *in, size_t inlen);
+ inline uint64_t finalize(const uint8_t *in, size_t left);
+};
+
+template <int cROUNDS, int dROUNDS>
+SipHash64<cROUNDS, dROUNDS>::SipHash64(uint64_t inlen, uint64_t seed, uint64_t seed2)
+{
b = inlen << 56;
+ k0 = seed;
+ k1 = seed2;
v3 ^= k1;
v2 ^= k0;
v1 ^= k1;
v0 ^= k0;
+}
+template <int cROUNDS, int dROUNDS> Q_DECL_HOT_FUNCTION void
+SipHash64<cROUNDS, dROUNDS>::addBlock(const uint8_t *in, size_t inlen)
+{
+ Q_ASSERT((inlen & 7ULL) == 0);
+ int i;
+ const uint8_t *end = in + inlen;
for (; in != end; in += 8) {
uint64_t m = qFromUnaligned<uint64_t>(in);
v3 ^= m;
@@ -340,24 +352,31 @@ static uint64_t siphash(const uint8_t *in, uint64_t inlen, uint64_t seed, uint64
v0 ^= m;
}
+}
-
-#if defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 700
- QT_WARNING_DISABLE_GCC("-Wimplicit-fallthrough")
-#endif
+template <int cROUNDS, int dROUNDS> Q_DECL_HOT_FUNCTION uint64_t
+SipHash64<cROUNDS, dROUNDS>::finalize(const uint8_t *in, size_t left)
+{
+ int i;
switch (left) {
case 7:
b |= ((uint64_t)in[6]) << 48;
+ Q_FALLTHROUGH();
case 6:
b |= ((uint64_t)in[5]) << 40;
+ Q_FALLTHROUGH();
case 5:
b |= ((uint64_t)in[4]) << 32;
+ Q_FALLTHROUGH();
case 4:
b |= ((uint64_t)in[3]) << 24;
+ Q_FALLTHROUGH();
case 3:
b |= ((uint64_t)in[2]) << 16;
+ Q_FALLTHROUGH();
case 2:
b |= ((uint64_t)in[1]) << 8;
+ Q_FALLTHROUGH();
case 1:
b |= ((uint64_t)in[0]);
break;
@@ -380,7 +399,8 @@ static uint64_t siphash(const uint8_t *in, uint64_t inlen, uint64_t seed, uint64
b = v0 ^ v1 ^ v2 ^ v3;
return b;
}
-#else
+#undef SIPROUND
+
// This is a "SipHash" implementation adopted for 32bit platforms. It performs
// basically the same operations as the 64bit version using 4 byte at a time
// instead of 8.
@@ -391,12 +411,6 @@ static uint64_t siphash(const uint8_t *in, uint64_t inlen, uint64_t seed, uint64
//
// For the v0-v4 constants, simply use the first four bytes of the 64 bit versions.
//
-// Use SipHash-1-2, which has similar performance characteristics as
-// stablehash() above, instead of the SipHash-2-4 default
-#define cROUNDS 1
-#define dROUNDS 2
-
-#define ROTL(x, b) (uint32_t)(((x) << (b)) | ((x) >> (32 - (b))))
#define SIPROUND \
do { \
@@ -416,8 +430,7 @@ static uint64_t siphash(const uint8_t *in, uint64_t inlen, uint64_t seed, uint64
v2 = ROTL(v2, 16); \
} while (0)
-Q_NEVER_INLINE Q_DECL_HOT_FUNCTION
-static uint siphash(const uint8_t *in, uint inlen, uint seed, uint seed2)
+template <int cROUNDS = 2, int dROUNDS = 4> struct SipHash32
{
/* "somepseudorandomlygeneratedbytes" */
uint v0 = 0x736f6d65U;
@@ -425,17 +438,32 @@ static uint siphash(const uint8_t *in, uint inlen, uint seed, uint seed2)
uint v2 = 0x6c796765U;
uint v3 = 0x74656462U;
uint b;
+ uint k0;
+ uint k1;
+
+ inline SipHash32(size_t fulllen, uint seed, uint seed2);
+ inline void addBlock(const uint8_t *in, size_t inlen);
+ inline uint finalize(const uint8_t *in, size_t left);
+};
+
+template <int cROUNDS, int dROUNDS> inline
+SipHash32<cROUNDS, dROUNDS>::SipHash32(size_t inlen, uint seed, uint seed2)
+{
uint k0 = seed;
uint k1 = seed2;
- int i;
- const uint8_t *end = in + (inlen & ~3ULL);
- const int left = inlen & 3;
b = inlen << 24;
v3 ^= k1;
v2 ^= k0;
v1 ^= k1;
v0 ^= k0;
+}
+template <int cROUNDS, int dROUNDS> inline Q_DECL_HOT_FUNCTION void
+SipHash32<cROUNDS, dROUNDS>::addBlock(const uint8_t *in, size_t inlen)
+{
+ Q_ASSERT((inlen & 3ULL) == 0);
+ int i;
+ const uint8_t *end = in + inlen;
for (; in != end; in += 4) {
uint m = qFromUnaligned<uint>(in);
v3 ^= m;
@@ -445,15 +473,19 @@ static uint siphash(const uint8_t *in, uint inlen, uint seed, uint seed2)
v0 ^= m;
}
+}
-#if defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 700
- QT_WARNING_DISABLE_GCC("-Wimplicit-fallthrough")
-#endif
+template <int cROUNDS, int dROUNDS> inline Q_DECL_HOT_FUNCTION uint
+SipHash32<cROUNDS, dROUNDS>::finalize(const uint8_t *in, size_t left)
+{
+ int i;
switch (left) {
case 3:
b |= ((uint)in[2]) << 16;
+ Q_FALLTHROUGH();
case 2:
b |= ((uint)in[1]) << 8;
+ Q_FALLTHROUGH();
case 1:
b |= ((uint)in[0]);
break;
@@ -476,7 +508,70 @@ static uint siphash(const uint8_t *in, uint inlen, uint seed, uint seed2)
b = v0 ^ v1 ^ v2 ^ v3;
return b;
}
-#endif
+#undef SIPROUND
+#undef ROTL
+
+// Use SipHash-1-2, which has similar performance characteristics as
+// stablehash() above, instead of the SipHash-2-4 default
+template <int cROUNDS = 1, int dROUNDS = 2>
+using SipHash = std::conditional_t<sizeof(void *) == 8,
+ SipHash64<cROUNDS, dROUNDS>, SipHash32<cROUNDS, dROUNDS>>;
+} // unnamed namespace
+
+Q_NEVER_INLINE Q_DECL_HOT_FUNCTION
+static size_t siphash(const uint8_t *in, size_t inlen, size_t seed, size_t seed2)
+{
+ constexpr size_t TailSizeMask = sizeof(void *) - 1;
+ SipHash<> hasher(inlen, seed, seed2);
+ hasher.addBlock(in, inlen & ~TailSizeMask);
+ return hasher.finalize(in + (inlen & ~TailSizeMask), inlen & TailSizeMask);
+}
+
+enum ZeroExtension {
+ None = 0,
+ ByteToWord = 1,
+};
+
+template <ZeroExtension = None> static size_t
+qHashBits_fallback(const uchar *p, size_t size, size_t seed, size_t seed2) noexcept;
+template <> size_t qHashBits_fallback<None>(const uchar *p, size_t size, size_t seed, size_t seed2) noexcept
+{
+ if (size <= QT_POINTER_SIZE)
+ return murmurhash(p, size, seed);
+
+ return siphash(reinterpret_cast<const uchar *>(p), size, seed, seed2);
+}
+
+template <> size_t qHashBits_fallback<ByteToWord>(const uchar *data, size_t size, size_t seed, size_t seed2) noexcept
+{
+ auto quick_from_latin1 = [](char16_t *dest, const uchar *data, size_t size) {
+ // Quick, "inlined" version for very short blocks
+ std::copy_n(data, size, dest);
+ };
+ if (size <= QT_POINTER_SIZE / 2) {
+ std::array<char16_t, QT_POINTER_SIZE / 2> buf;
+ quick_from_latin1(buf.data(), data, size);
+ return murmurhash(buf.data(), size * 2, seed);
+ }
+
+ constexpr size_t TailSizeMask = sizeof(void *) / 2 - 1;
+ std::array<char16_t, 256> buf;
+ SipHash<> siphash(size * 2, seed, seed2);
+ ptrdiff_t offset = 0;
+ for ( ; offset + buf.size() < size; offset += buf.size()) {
+ qt_from_latin1(buf.data(), reinterpret_cast<const char *>(data) + offset, buf.size());
+ siphash.addBlock(reinterpret_cast<uint8_t *>(buf.data()), sizeof(buf));
+ }
+ if (size_t n = size - offset; n > TailSizeMask) {
+ n &= ~TailSizeMask;
+ qt_from_latin1(buf.data(), reinterpret_cast<const char *>(data) + offset, n);
+ siphash.addBlock(reinterpret_cast<uint8_t *>(buf.data()), n * 2);
+ offset += n;
+ }
+
+ quick_from_latin1(buf.data(), data + offset, size - offset);
+ return siphash.finalize(reinterpret_cast<uint8_t *>(buf.data()), (size - offset) * 2);
+}
#if defined(__SANITIZE_ADDRESS__) || defined(__SANITIZE_THREAD__) // GCC
# define QHASH_AES_SANITIZER_BUILD
@@ -523,10 +618,41 @@ namespace {
// the scrambling round (step 3 in [1]) because it's just very good at
// spreading the bits around.
//
+ // Note on Latin-1 hashing (ZX == ByteToWord): for simplicity of the
+ // algorithm, we pass sizes equivalent to the UTF-16 content (ZX == None).
+ // That means we must multiply by 2 on entry, divide by 2 on pointer
+ // advancing, and load half as much data from memory (though we produce
+ // exactly as much data in registers). The compilers appear to optimize
+ // this out.
+ //
// [1] https://en.wikipedia.org/wiki/Advanced_Encryption_Standard#High-level_description_of_the_algorithm
+ template <ZeroExtension ZX, typename T> static const T *advance(const T *ptr, ptrdiff_t n)
+ {
+ if constexpr (ZX == None)
+ return ptr + n;
+
+ // see note above on ZX == ByteToWord hashing
+ auto p = reinterpret_cast<const uchar *>(ptr);
+ n *= sizeof(T);
+ return reinterpret_cast<const T *>(p + n/2);
+ }
+
+ template <ZeroExtension> static __m128i loadu128(const void *ptr);
+ template <> Q_ALWAYS_INLINE QT_FUNCTION_TARGET(AES) __m128i loadu128<None>(const void *ptr)
+ {
+ return _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
+ }
+ template <> Q_ALWAYS_INLINE QT_FUNCTION_TARGET(AES) __m128i loadu128<ByteToWord>(const void *ptr)
+ {
+ // use a MOVQ followed by PMOVZXBW
+ // the compiler usually combines them as a single, loading PMOVZXBW
+ __m128i data = _mm_loadl_epi64(static_cast<const __m128i *>(ptr));
+ return _mm_cvtepu8_epi16(data);
+ }
+
// hash 16 bytes, running 3 scramble rounds of AES on itself (like label "final1")
- static void QT_FUNCTION_TARGET(AES) QT_VECTORCALL
+ static void Q_ALWAYS_INLINE QT_FUNCTION_TARGET(AES) QT_VECTORCALL
hash16bytes(__m128i &state0, __m128i data)
{
state0 = _mm_xor_si128(state0, data);
@@ -536,11 +662,12 @@ namespace {
}
// hash twice 16 bytes, running 2 scramble rounds of AES on itself
+ template <ZeroExtension ZX>
static void QT_FUNCTION_TARGET(AES) QT_VECTORCALL
hash2x16bytes(__m128i &state0, __m128i &state1, const __m128i *src0, const __m128i *src1)
{
- __m128i data0 = _mm_loadu_si128(src0);
- __m128i data1 = _mm_loadu_si128(src1);
+ __m128i data0 = loadu128<ZX>(src0);
+ __m128i data1 = loadu128<ZX>(src1);
state0 = _mm_xor_si128(data0, state0);
state1 = _mm_xor_si128(data1, state1);
state0 = _mm_aesenc_si128(state0, state0);
@@ -587,16 +714,18 @@ Q_ALWAYS_INLINE __m128i AESHashSeed::state1() const
}
}
+template <ZeroExtension ZX>
static size_t QT_FUNCTION_TARGET(AES) QT_VECTORCALL
aeshash128_16to32(__m128i state0, __m128i state1, const __m128i *src, const __m128i *srcend)
{
{
- if (src + 1 < srcend) {
+ const __m128i *src2 = advance<ZX>(srcend, -1);
+ if (advance<ZX>(src, 1) < srcend) {
// epilogue: between 16 and 31 bytes
- hash2x16bytes(state0, state1, src, srcend - 1);
+ hash2x16bytes<ZX>(state0, state1, src, src2);
} else if (src != srcend) {
// epilogue: between 1 and 16 bytes, overlap with the end
- __m128i data = _mm_loadu_si128(srcend - 1);
+ __m128i data = loadu128<ZX>(src2);
hash16bytes(state0, data);
}
@@ -607,8 +736,21 @@ aeshash128_16to32(__m128i state0, __m128i state1, const __m128i *src, const __m1
return mm_cvtsi128_sz(state0);
}
+// load all 16 bytes and mask off the bytes past the end of the source
+static const qint8 maskarray[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+// load 16 bytes ending at the data end, then shuffle them to the beginning
+static const qint8 shufflecontrol[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+template <ZeroExtension ZX>
static size_t QT_FUNCTION_TARGET(AES) QT_VECTORCALL
-aeshash128_lt16(__m128i state0, const uchar *p, size_t len)
+aeshash128_lt16(__m128i state0, const __m128i *src, const __m128i *srcend, size_t len)
{
if (len) {
// We're going to load 16 bytes and mask zero the part we don't care
@@ -616,28 +758,18 @@ aeshash128_lt16(__m128i state0, const uchar *p, size_t len)
// including NULLs at the end because the length is in the key)
// WARNING: this may produce valgrind warnings, but it's safe
- constexpr quintptr PageSize = 4096;
+ constexpr quintptr CachelineSize = 64;
__m128i data;
- if ((quintptr(p) & (PageSize / 2)) == 0) {
- // lower half of the page:
- // load all 16 bytes and mask off the bytes past the end of the source
- static const qint8 maskarray[] = {
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- };
+ if ((quintptr(src) & (CachelineSize / 2)) == 0) {
+ // lower half of the cacheline:
__m128i mask = _mm_loadu_si128(reinterpret_cast<const __m128i *>(maskarray + 15 - len));
- data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));
+ data = loadu128<ZX>(src);
data = _mm_and_si128(data, mask);
} else {
- // upper half of the page:
- // load 16 bytes ending at the data end, then shuffle them to the beginning
- static const qint8 shufflecontrol[] = {
- 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
- };
+ // upper half of the cacheline:
__m128i control = _mm_loadu_si128(reinterpret_cast<const __m128i *>(shufflecontrol + 15 - len));
- data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p + len) - 1);
+ data = loadu128<ZX>(advance<ZX>(srcend, -1));
data = _mm_shuffle_epi8(data, control);
}
@@ -646,24 +778,45 @@ aeshash128_lt16(__m128i state0, const uchar *p, size_t len)
return mm_cvtsi128_sz(state0);
}
+template <ZeroExtension ZX>
static size_t QT_FUNCTION_TARGET(AES) QT_VECTORCALL
aeshash128_ge32(__m128i state0, __m128i state1, const __m128i *src, const __m128i *srcend)
{
// main loop: scramble two 16-byte blocks
- for ( ; src + 2 < srcend; src += 2)
- hash2x16bytes(state0, state1, src, src + 1);
+ for ( ; advance<ZX>(src, 2) < srcend; src = advance<ZX>(src, 2))
+ hash2x16bytes<ZX>(state0, state1, src, advance<ZX>(src, 1));
- return aeshash128_16to32(state0, state1, src, srcend);
+ return aeshash128_16to32<ZX>(state0, state1, src, srcend);
}
# if QT_COMPILER_SUPPORTS_HERE(VAES)
-static size_t QT_FUNCTION_TARGET(ARCH_ICL) QT_VECTORCALL
+template <ZeroExtension> static __m256i loadu256(const void *ptr);
+template <> Q_ALWAYS_INLINE QT_FUNCTION_TARGET(VAES) __m256i loadu256<None>(const void *ptr)
+{
+ return _mm256_loadu_si256(reinterpret_cast<const __m256i *>(ptr));
+}
+template <> Q_ALWAYS_INLINE QT_FUNCTION_TARGET(VAES) __m256i loadu256<ByteToWord>(const void *ptr)
+{
+ // VPMOVZXBW xmm, ymm
+ __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(ptr));
+ return _mm256_cvtepu8_epi16(data);
+}
+
+template <ZeroExtension ZX>
+static size_t QT_FUNCTION_TARGET(VAES_AVX512) QT_VECTORCALL
aeshash256_lt32_avx256(__m256i state0, const uchar *p, size_t len)
{
__m128i state0_128 = _mm256_castsi256_si128(state0);
if (len) {
- __mmask32 mask = _bzhi_u32(-1, unsigned(len));
- __m256i data = _mm256_maskz_loadu_epi8(mask, p);
+ __m256i data;
+ if constexpr (ZX == None) {
+ __mmask32 mask = _bzhi_u32(-1, unsigned(len));
+ data = _mm256_maskz_loadu_epi8(mask, p);
+ } else {
+ __mmask16 mask = _bzhi_u32(-1, unsigned(len) / 2);
+ __m128i data0 = _mm_maskz_loadu_epi8(mask, p);
+ data = _mm256_cvtepu8_epi16(data0);
+ }
__m128i data0 = _mm256_castsi256_si128(data);
if (len >= sizeof(__m128i)) {
state0 = _mm256_xor_si256(state0, data);
@@ -683,8 +836,9 @@ aeshash256_lt32_avx256(__m256i state0, const uchar *p, size_t len)
return mm_cvtsi128_sz(state0_128);
}
+template <ZeroExtension ZX>
static size_t QT_FUNCTION_TARGET(VAES) QT_VECTORCALL
-aeshash256_ge32(__m256i state0, const uchar *p, size_t len)
+aeshash256_ge32(__m256i state0, const __m128i *s, const __m128i *end, size_t len)
{
static const auto hash32bytes = [](__m256i &state0, __m256i data) QT_FUNCTION_TARGET(VAES) {
state0 = _mm256_xor_si256(state0, data);
@@ -694,10 +848,10 @@ aeshash256_ge32(__m256i state0, const uchar *p, size_t len)
};
// hash twice 32 bytes, running 2 scramble rounds of AES on itself
- const auto hash2x32bytes = [](__m256i &state0, __m256i &state1, const __m256i *src0,
- const __m256i *src1) QT_FUNCTION_TARGET(VAES) {
- __m256i data0 = _mm256_loadu_si256(src0);
- __m256i data1 = _mm256_loadu_si256(src1);
+ const auto hash2x32bytes = [](__m256i &state0, __m256i &state1, const void *src0,
+ const void *src1) QT_FUNCTION_TARGET(VAES) {
+ __m256i data0 = loadu256<ZX>(src0);
+ __m256i data1 = loadu256<ZX>(src1);
state0 = _mm256_xor_si256(data0, state0);
state1 = _mm256_xor_si256(data1, state1);
state0 = _mm256_aesenc_epi128(state0, state0);
@@ -706,21 +860,22 @@ aeshash256_ge32(__m256i state0, const uchar *p, size_t len)
state1 = _mm256_aesenc_epi128(state1, state1);
};
- const __m256i *src = reinterpret_cast<const __m256i *>(p);
- const __m256i *srcend = reinterpret_cast<const __m256i *>(p + len);
+ const __m256i *src = reinterpret_cast<const __m256i *>(s);
+ const __m256i *srcend = reinterpret_cast<const __m256i *>(end);
__m256i state1 = _mm256_aesenc_epi128(state0, mm256_set1_epz(len));
// main loop: scramble two 32-byte blocks
- for ( ; src + 2 < srcend; src += 2)
- hash2x32bytes(state0, state1, src, src + 1);
+ for ( ; advance<ZX>(src, 2) < srcend; src = advance<ZX>(src, 2))
+ hash2x32bytes(state0, state1, src, advance<ZX>(src, 1));
- if (src + 1 < srcend) {
+ const __m256i *src2 = advance<ZX>(srcend, -1);
+ if (advance<ZX>(src, 1) < srcend) {
// epilogue: between 32 and 31 bytes
- hash2x32bytes(state0, state1, src, srcend - 1);
+ hash2x32bytes(state0, state1, src, src2);
} else if (src != srcend) {
// epilogue: between 1 and 32 bytes, overlap with the end
- __m256i data = _mm256_loadu_si256(srcend - 1);
+ __m256i data = loadu256<ZX>(src2);
hash32bytes(state0, data);
}
@@ -733,59 +888,69 @@ aeshash256_ge32(__m256i state0, const uchar *p, size_t len)
return mm_cvtsi128_sz(_mm_xor_si128(low, high));
}
+template <ZeroExtension ZX>
static size_t QT_FUNCTION_TARGET(VAES)
aeshash256(const uchar *p, size_t len, size_t seed, size_t seed2) noexcept
{
AESHashSeed state(seed, seed2);
auto src = reinterpret_cast<const __m128i *>(p);
- const auto srcend = reinterpret_cast<const __m128i *>(p + len);
+ const auto srcend = reinterpret_cast<const __m128i *>(advance<ZX>(p, len));
if (len < sizeof(__m128i))
- return aeshash128_lt16(state.state0, p, len);
+ return aeshash128_lt16<ZX>(state.state0, src, srcend, len);
if (len <= sizeof(__m256i))
- return aeshash128_16to32(state.state0, state.state1(), src, srcend);
+ return aeshash128_16to32<ZX>(state.state0, state.state1(), src, srcend);
- return aeshash256_ge32(state.state0_256(), p, len);
+ return aeshash256_ge32<ZX>(state.state0_256(), src, srcend, len);
}
+template <ZeroExtension ZX>
static size_t QT_FUNCTION_TARGET(VAES_AVX512)
aeshash256_avx256(const uchar *p, size_t len, size_t seed, size_t seed2) noexcept
{
AESHashSeed state(seed, seed2);
+ auto src = reinterpret_cast<const __m128i *>(p);
+ const auto srcend = reinterpret_cast<const __m128i *>(advance<ZX>(p, len));
+
if (len <= sizeof(__m256i))
- return aeshash256_lt32_avx256(state.state0_256(), p, len);
+ return aeshash256_lt32_avx256<ZX>(state.state0_256(), p, len);
- return aeshash256_ge32(state.state0_256(), p, len);
+ return aeshash256_ge32<ZX>(state.state0_256(), src, srcend, len);
}
# endif // VAES
+template <ZeroExtension ZX>
static size_t QT_FUNCTION_TARGET(AES)
aeshash128(const uchar *p, size_t len, size_t seed, size_t seed2) noexcept
{
AESHashSeed state(seed, seed2);
auto src = reinterpret_cast<const __m128i *>(p);
- const auto srcend = reinterpret_cast<const __m128i *>(p + len);
+ const auto srcend = reinterpret_cast<const __m128i *>(advance<ZX>(p, len));
if (len < sizeof(__m128i))
- return aeshash128_lt16(state.state0, p, len);
+ return aeshash128_lt16<ZX>(state.state0, src, srcend, len);
if (len <= sizeof(__m256i))
- return aeshash128_16to32(state.state0, state.state1(), src, srcend);
+ return aeshash128_16to32<ZX>(state.state0, state.state1(), src, srcend);
- return aeshash128_ge32(state.state0, state.state1(), src, srcend);
+ return aeshash128_ge32<ZX>(state.state0, state.state1(), src, srcend);
}
+template <ZeroExtension ZX = None>
static size_t aeshash(const uchar *p, size_t len, size_t seed, size_t seed2) noexcept
{
+ if constexpr (ZX == ByteToWord)
+ len *= 2; // see note above on ZX == ByteToWord hashing
+
# if QT_COMPILER_SUPPORTS_HERE(VAES)
if (qCpuHasFeature(VAES)) {
if (qCpuHasFeature(AVX512VL))
- return aeshash256_avx256(p, len, seed, seed2);
- return aeshash256(p, len, seed, seed2);
+ return aeshash256_avx256<ZX>(p, len, seed, seed2);
+ return aeshash256<ZX>(p, len, seed, seed2);
}
# endif
- return aeshash128(p, len, seed, seed2);
+ return aeshash128<ZX>(p, len, seed, seed2);
}
#endif // x86 AESNI
@@ -933,24 +1098,17 @@ size_t qHashBits(const void *p, size_t size, size_t seed) noexcept
size_t seed2 = size;
if (seed)
seed2 = qt_qhash_seed.currentSeed(1);
+
+ auto data = reinterpret_cast<const uchar *>(p);
#ifdef AESHASH
if (seed && qCpuHasFeature(AES) && qCpuHasFeature(SSE4_2))
- return aeshash(reinterpret_cast<const uchar *>(p), size, seed, seed2);
+ return aeshash(data, size, seed, seed2);
#elif defined(Q_PROCESSOR_ARM) && QT_COMPILER_SUPPORTS_HERE(AES) && !defined(QHASH_AES_SANITIZER_BUILD) && !defined(QT_BOOTSTRAPPED)
-# if defined(Q_OS_LINUX)
- // Do specific runtime-only check as Yocto hard enables Crypto extension for
- // all armv8 configs
- if (seed && (qCpuFeatures() & CpuFeatureAES))
-# else
if (seed && qCpuHasFeature(AES))
-# endif
- return aeshash(reinterpret_cast<const uchar *>(p), size, seed, seed2);
+ return aeshash(data, size, seed, seed2);
#endif
- if (size <= QT_POINTER_SIZE)
- return murmurhash(p, size, seed);
-
- return siphash(reinterpret_cast<const uchar *>(p), size, seed, seed2);
+ return qHashBits_fallback<>(data, size, seed, seed2);
}
size_t qHash(QByteArrayView key, size_t seed) noexcept
@@ -963,6 +1121,7 @@ size_t qHash(QStringView key, size_t seed) noexcept
return qHashBits(key.data(), key.size()*sizeof(QChar), seed);
}
+#ifndef QT_BOOTSTRAPPED
size_t qHash(const QBitArray &bitArray, size_t seed) noexcept
{
qsizetype m = bitArray.d.size() - 1;
@@ -975,10 +1134,30 @@ size_t qHash(const QBitArray &bitArray, size_t seed) noexcept
result = ((result << 4) + bitArray.d.at(m)) & ((1 << n) - 1);
return result;
}
+#endif
size_t qHash(QLatin1StringView key, size_t seed) noexcept
{
- return qHashBits(reinterpret_cast<const uchar *>(key.data()), size_t(key.size()), seed);
+#ifdef QT_BOOTSTRAPPED
+ // the seed is always 0 in bootstrapped mode (no seed generation code),
+ // so help the compiler do dead code elimination
+ seed = 0;
+#endif
+
+ auto data = reinterpret_cast<const uchar *>(key.data());
+ size_t size = key.size();
+
+ // Mix in the length as a secondary seed.
+ // Multiplied by 2 to match the byte size of the equiavlent UTF-16 string.
+ size_t seed2 = size * 2;
+ if (seed)
+ seed2 = qt_qhash_seed.currentSeed(1);
+
+#if defined(AESHASH)
+ if (seed && qCpuHasFeature(AES) && qCpuHasFeature(SSE4_2))
+ return aeshash<ByteToWord>(data, size, seed, seed2);
+#endif
+ return qHashBits_fallback<ByteToWord>(data, size, seed, seed2);
}
/*!
@@ -1383,6 +1562,26 @@ uint qt_hash(QStringView key, uint chained) noexcept
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
+/*! \fn size_t qHash(quint128 key, size_t seed = 0)
+ \relates QHash
+ \since 6.8
+
+ Returns the hash value for the \a key, using \a seed to seed the calculation.
+
+ \note This function is only available on platforms that support a native
+ 128-bit integer type.
+*/
+
+/*! \fn size_t qHash(qint128 key, size_t seed = 0)
+ \relates QHash
+ \since 6.8
+
+ Returns the hash value for the \a key, using \a seed to seed the calculation.
+
+ \note This function is only available on platforms that support a native
+ 128-bit integer type.
+ */
+
/*! \fn size_t qHash(char8_t key, size_t seed = 0)
\relates QHash
\since 6.0
@@ -1436,7 +1635,6 @@ size_t qHash(double key, size_t seed) noexcept
}
}
-#if !defined(Q_OS_DARWIN) || defined(Q_QDOC)
/*! \relates QHash
\since 5.3
@@ -1454,7 +1652,6 @@ size_t qHash(long double key, size_t seed) noexcept
return murmurhash(&key, sizeof(key), seed);
}
}
-#endif
/*! \fn size_t qHash(const QChar key, size_t seed = 0)
\relates QHash
@@ -1512,7 +1709,7 @@ size_t qHash(long double key, size_t seed) noexcept
Returns the hash value for the \a key, using \a seed to seed the calculation.
*/
-/*! \fn template <class T> size_t qHash(std::nullptr_t key, size_t seed = 0)
+/*! \fn size_t qHash(std::nullptr_t key, size_t seed = 0)
\relates QHash
\since 6.0
@@ -1640,7 +1837,7 @@ size_t qHash(long double key, size_t seed) noexcept
hash table, use \l{QMultiHash}.
If you only need to extract the values from a hash (not the keys),
- you can also use \l{foreach}:
+ you can also use range-based for:
\snippet code/src_corelib_tools_qhash.cpp 12
@@ -1783,8 +1980,8 @@ size_t qHash(long double key, size_t seed) noexcept
Constructs a hash with a copy of each of the elements in the iterator range
[\a begin, \a end). Either the elements iterated by the range must be
- objects with \c{first} and \c{second} data members (like \c{QPair},
- \c{std::pair}, etc.) convertible to \c Key and to \c T respectively; or the
+ objects with \c{first} and \c{second} data members (like \c{std::pair}),
+ convertible to \c Key and to \c T respectively; or the
iterators must have \c{key()} and \c{value()} member functions, returning a
key convertible to \c Key and a value convertible to \c T respectively.
*/
@@ -2019,7 +2216,7 @@ size_t qHash(long double key, size_t seed) noexcept
Returns \c true if the hash contains an item with the \a key;
otherwise returns \c false.
- \sa count(), QMultiHash::contains()
+ \sa count()
*/
/*! \fn template <class Key, class T> T QHash<Key, T>::value(const Key &key) const
@@ -2042,6 +2239,12 @@ size_t qHash(long double key, size_t seed) noexcept
a \l{default-constructed value} into the hash with the \a key, and
returns a reference to it.
+//! [qhash-iterator-invalidation-func-desc]
+ \warning Returned iterators/references should be considered invalidated
+ the next time you call a non-const function on the hash, or when the
+ hash is destroyed.
+//! [qhash-iterator-invalidation-func-desc]
+
\sa insert(), value()
*/
@@ -2125,12 +2328,16 @@ size_t qHash(long double key, size_t seed) noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in
the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa constBegin(), end()
*/
/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::begin() const
\overload
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::cbegin() const
@@ -2139,6 +2346,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa begin(), cend()
*/
@@ -2147,6 +2356,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa begin(), constEnd()
*/
@@ -2156,6 +2367,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first key
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyEnd()
*/
@@ -2164,12 +2377,16 @@ size_t qHash(long double key, size_t seed) noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item
after the last item in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa begin(), constEnd()
*/
/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::end() const
\overload
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::constEnd() const
@@ -2177,6 +2394,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
item after the last item in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa constBegin(), end()
*/
@@ -2186,6 +2405,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
item after the last item in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa cbegin(), end()
*/
@@ -2195,6 +2416,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
item after the last key in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyBegin()
*/
@@ -2204,6 +2427,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first entry
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyValueEnd()
*/
@@ -2213,6 +2438,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
entry after the last entry in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyValueBegin()
*/
@@ -2222,6 +2449,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyValueEnd()
*/
@@ -2231,6 +2460,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyValueBegin()
*/
@@ -2240,6 +2471,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
entry after the last entry in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyValueBegin()
*/
@@ -2249,6 +2482,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
entry after the last entry in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa constKeyValueBegin()
*/
@@ -2268,6 +2503,8 @@ size_t qHash(long double key, size_t seed) noexcept
references to the ones in the hash. Specifically, mutating the value
will modify the hash itself.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa QKeyValueIterator
*/
@@ -2285,6 +2522,8 @@ size_t qHash(long double key, size_t seed) noexcept
\snippet code/src_corelib_tools_qhash.cpp 15
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa remove(), take(), find()
*/
@@ -2304,12 +2543,16 @@ size_t qHash(long double key, size_t seed) noexcept
\snippet code/src_corelib_tools_qhash.cpp 16
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa value(), values()
*/
/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::find(const Key &key) const
\overload
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator QHash<Key, T>::constFind(const Key &key) const
@@ -2321,6 +2564,8 @@ size_t qHash(long double key, size_t seed) noexcept
If the hash contains no item with the \a key, the function
returns constEnd().
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa find()
*/
@@ -2330,6 +2575,10 @@ size_t qHash(long double key, size_t seed) noexcept
If there is already an item with the \a key, that item's value
is replaced with \a value.
+
+ Returns an iterator pointing to the new/updated element.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*!
@@ -2341,6 +2590,8 @@ size_t qHash(long double key, size_t seed) noexcept
construction.
Returns an iterator pointing to the new element.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
@@ -2360,17 +2611,21 @@ size_t qHash(long double key, size_t seed) noexcept
returns \c false.
*/
-/*! \fn template <class Key, class T> QPair<iterator, iterator> QMultiHash<Key, T>::equal_range(const Key &key)
+/*! \fn template <class Key, class T> std::pair<iterator, iterator> QMultiHash<Key, T>::equal_range(const Key &key)
\since 5.7
Returns a pair of iterators delimiting the range of values \c{[first, second)}, that
are stored under \a key. If the range is empty then both iterators will be equal to end().
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*!
- \fn template <class Key, class T> QPair<const_iterator, const_iterator> QMultiHash<Key, T>::equal_range(const Key &key) const
+ \fn template <class Key, class T> std::pair<const_iterator, const_iterator> QMultiHash<Key, T>::equal_range(const Key &key) const
\overload
\since 5.7
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*! \typedef QHash::ConstIterator
@@ -2467,12 +2722,6 @@ size_t qHash(long double key, size_t seed) noexcept
\inmodule QtCore
\brief The QHash::iterator class provides an STL-style non-const iterator for QHash.
- QHash features both \l{STL-style iterators} and \l{Java-style
- iterators}. The STL-style iterators are more low-level and more
- cumbersome to use; on the other hand, they are slightly faster
- and, for developers who already know STL, have the advantage of
- familiarity.
-
QHash\<Key, T\>::iterator allows you to iterate over a QHash
and to modify the value (but not the key) associated
with a particular key. If you want to iterate over a const QHash,
@@ -2493,31 +2742,15 @@ size_t qHash(long double key, size_t seed) noexcept
Unlike QMap, which orders its items by key, QHash stores its
items in an arbitrary order.
- Let's see a few examples of things we can do with a
- QHash::iterator that we cannot do with a QHash::const_iterator.
Here's an example that increments every value stored in the QHash
by 2:
\snippet code/src_corelib_tools_qhash.cpp 18
- Here's an example that removes all the items whose key is a
- string that starts with an underscore character:
-
- \snippet code/src_corelib_tools_qhash.cpp 19
-
- The call to QHash::erase() removes the item pointed to by the
- iterator from the hash, and returns an iterator to the next item.
- Here's another way of removing an item while iterating:
-
- \snippet code/src_corelib_tools_qhash.cpp 20
-
- It might be tempting to write code like this:
+ To remove elements from a QHash you can use erase_if(QHash\<Key, T\> &map, Predicate pred):
\snippet code/src_corelib_tools_qhash.cpp 21
- However, this will potentially crash in \c{++i}, because \c i is
- a dangling iterator after the call to erase().
-
Multiple iterators can be used on the same hash. However, be aware
that any modification performed directly on the QHash (inserting and
removing items) can cause the iterators to become invalid.
@@ -2528,10 +2761,6 @@ size_t qHash(long double key, size_t seed) noexcept
to grow/shrink its internal hash table.
Using any iterator after a rehashing operation has occurred will lead to undefined behavior.
- You can however safely use iterators to remove entries from the hash
- using the QHash::erase() method. This function can safely be called while
- iterating, and won't affect the order of items in the hash.
-
If you need to keep iterators over a long period of time, we recommend
that you use QMap rather than QHash.
@@ -2540,7 +2769,7 @@ size_t qHash(long double key, size_t seed) noexcept
while iterators are active on that container. For more information,
read \l{Implicit sharing iterator problem}.
- \sa QHash::const_iterator, QHash::key_iterator, QMutableHashIterator
+ \sa QHash::const_iterator, QHash::key_iterator, QHash::key_value_iterator
*/
/*! \fn template <class Key, class T> QHash<Key, T>::iterator::iterator()
@@ -2636,12 +2865,6 @@ size_t qHash(long double key, size_t seed) noexcept
\inmodule QtCore
\brief The QHash::const_iterator class provides an STL-style const iterator for QHash.
- QHash features both \l{STL-style iterators} and \l{Java-style
- iterators}. The STL-style iterators are more low-level and more
- cumbersome to use; on the other hand, they are slightly faster
- and, for developers who already know STL, have the advantage of
- familiarity.
-
QHash\<Key, T\>::const_iterator allows you to iterate over a
QHash. If you want to modify the QHash as you
iterate over it, you must use QHash::iterator instead. It is
@@ -2652,8 +2875,8 @@ size_t qHash(long double key, size_t seed) noexcept
The default QHash::const_iterator constructor creates an
uninitialized iterator. You must initialize it using a QHash
- function like QHash::constBegin(), QHash::constEnd(), or
- QHash::find() before you can start iterating. Here's a typical
+ function like QHash::cbegin(), QHash::cend(), or
+ QHash::constFind() before you can start iterating. Here's a typical
loop that prints all the (key, value) pairs stored in a hash:
\snippet code/src_corelib_tools_qhash.cpp 23
@@ -2674,12 +2897,16 @@ size_t qHash(long double key, size_t seed) noexcept
to grow/shrink its internal hash table.
Using any iterator after a rehashing operation has occurred will lead to undefined behavior.
+ You can however safely use iterators to remove entries from the hash
+ using the QHash::erase() method. This function can safely be called while
+ iterating, and won't affect the order of items in the hash.
+
\warning Iterators on implicitly shared containers do not work
exactly like STL-iterators. You should avoid copying a container
while iterators are active on that container. For more information,
read \l{Implicit sharing iterator problem}.
- \sa QHash::iterator, QHashIterator
+ \sa QHash::iterator, QHash::key_iterator, QHash::const_key_value_iterator
*/
/*! \fn template <class Key, class T> QHash<Key, T>::const_iterator::const_iterator()
@@ -2965,9 +3192,6 @@ size_t qHash(long double key, size_t seed) noexcept
Constructs a multi-hash with a copy of each of the elements in the
initializer list \a list.
-
- This function is only available if the program is being
- compiled in C++11 mode.
*/
/*! \fn template <class Key, class T> QMultiHash<Key, T>::QMultiHash(const QHash<Key, T> &other)
@@ -2981,8 +3205,8 @@ size_t qHash(long double key, size_t seed) noexcept
Constructs a multi-hash with a copy of each of the elements in the iterator range
[\a begin, \a end). Either the elements iterated by the range must be
- objects with \c{first} and \c{second} data members (like \c{QPair},
- \c{std::pair}, etc.) convertible to \c Key and to \c T respectively; or the
+ objects with \c{first} and \c{second} data members (like \c{std::pair}),
+ convertible to \c Key and to \c T respectively; or the
iterators must have \c{key()} and \c{value()} member functions, returning a
key convertible to \c Key and a value convertible to \c T respectively.
*/
@@ -2997,6 +3221,10 @@ size_t qHash(long double key, size_t seed) noexcept
If there are multiple items with the \a key, the most
recently inserted item's value is replaced with \a value.
+ Returns an iterator pointing to the new/updated element.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa insert()
*/
@@ -3009,6 +3237,10 @@ size_t qHash(long double key, size_t seed) noexcept
different from replace(), which overwrites the value of an
existing item.)
+ Returns an iterator pointing to the new element.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa replace()
*/
@@ -3027,6 +3259,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns an iterator pointing to the new element.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa insert
*/
@@ -3043,6 +3277,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns an iterator pointing to the new element.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa replace, emplace
*/
@@ -3109,6 +3345,8 @@ size_t qHash(long double key, size_t seed) noexcept
If the hash contains multiple items with the \a key, this function returns
a reference to the most recently inserted value.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa insert(), value()
*/
@@ -3261,12 +3499,16 @@ size_t qHash(long double key, size_t seed) noexcept
If the hash contains multiple items with the \a key and \a value, the
iterator returned points to the most recently inserted item.
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*!
\fn template <class Key, class T> typename QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::find(const Key &key, const T &value) const
\since 4.3
\overload
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*!
@@ -3278,6 +3520,8 @@ size_t qHash(long double key, size_t seed) noexcept
If the hash contains no such item, the function returns
constEnd().
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*! \fn template <class Key, class T> QMultiHash<Key, T>::iterator QMultiHash<Key, T>::begin()
@@ -3285,12 +3529,16 @@ size_t qHash(long double key, size_t seed) noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in
the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa constBegin(), end()
*/
/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::begin() const
\overload
+
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
*/
/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator QMultiHash<Key, T>::cbegin() const
@@ -3299,6 +3547,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa begin(), cend()
*/
@@ -3307,6 +3557,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa begin(), constEnd()
*/
@@ -3316,6 +3568,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first key
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyEnd()
*/
@@ -3324,6 +3578,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item
after the last item in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa begin(), constEnd()
*/
@@ -3337,6 +3593,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
item after the last item in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa constBegin(), end()
*/
@@ -3346,6 +3604,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
item after the last item in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa cbegin(), end()
*/
@@ -3355,6 +3615,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
item after the last key in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyBegin()
*/
@@ -3364,6 +3626,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first entry
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyValueEnd()
*/
@@ -3373,6 +3637,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
entry after the last entry in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyValueBegin()
*/
@@ -3382,6 +3648,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyValueEnd()
*/
@@ -3391,6 +3659,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first entry
in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyValueBegin()
*/
@@ -3400,6 +3670,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
entry after the last entry in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa keyValueBegin()
*/
@@ -3409,6 +3681,8 @@ size_t qHash(long double key, size_t seed) noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary
entry after the last entry in the hash.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa constKeyValueBegin()
*/
@@ -3428,6 +3702,8 @@ size_t qHash(long double key, size_t seed) noexcept
references to the ones in the hash. Specifically, mutating the value
will modify the hash itself.
+ \include qhash.cpp qhash-iterator-invalidation-func-desc
+
\sa QKeyValueIterator
*/
@@ -3435,12 +3711,6 @@ size_t qHash(long double key, size_t seed) noexcept
\inmodule QtCore
\brief The QMultiHash::iterator class provides an STL-style non-const iterator for QMultiHash.
- QMultiHash features both \l{STL-style iterators} and \l{Java-style
- iterators}. The STL-style iterators are more low-level and more
- cumbersome to use; on the other hand, they are slightly faster
- and, for developers who already know STL, have the advantage of
- familiarity.
-
QMultiHash\<Key, T\>::iterator allows you to iterate over a QMultiHash
and to modify the value (but not the key) associated
with a particular key. If you want to iterate over a const QMultiHash,
@@ -3461,31 +3731,15 @@ size_t qHash(long double key, size_t seed) noexcept
Unlike QMap, which orders its items by key, QMultiHash stores its
items in an arbitrary order.
- Let's see a few examples of things we can do with a
- QMultiHash::iterator that we cannot do with a QMultiHash::const_iterator.
Here's an example that increments every value stored in the QMultiHash
by 2:
\snippet code/src_corelib_tools_qhash.cpp 18
- Here's an example that removes all the items whose key is a
- string that starts with an underscore character:
-
- \snippet code/src_corelib_tools_qhash.cpp 19
-
- The call to QMultiHash::erase() removes the item pointed to by the
- iterator from the hash, and returns an iterator to the next item.
- Here's another way of removing an item while iterating:
-
- \snippet code/src_corelib_tools_qhash.cpp 20
-
- It might be tempting to write code like this:
+ To remove elements from a QMultiHash you can use erase_if(QMultiHash\<Key, T\> &map, Predicate pred):
\snippet code/src_corelib_tools_qhash.cpp 21
- However, this will potentially crash in \c{++i}, because \c i is
- a dangling iterator after the call to erase().
-
Multiple iterators can be used on the same hash. However, be aware
that any modification performed directly on the QHash (inserting and
removing items) can cause the iterators to become invalid.
@@ -3496,10 +3750,6 @@ size_t qHash(long double key, size_t seed) noexcept
to grow/shrink its internal hash table.
Using any iterator after a rehashing operation has occurred will lead to undefined behavior.
- You can however safely use iterators to remove entries from the hash
- using the QHash::erase() method. This function can safely be called while
- iterating, and won't affect the order of items in the hash.
-
If you need to keep iterators over a long period of time, we recommend
that you use QMultiMap rather than QHash.
@@ -3508,7 +3758,7 @@ size_t qHash(long double key, size_t seed) noexcept
while iterators are active on that container. For more information,
read \l{Implicit sharing iterator problem}.
- \sa QMultiHash::const_iterator, QMultiHash::key_iterator, QMutableHashIterator
+ \sa QMultiHash::const_iterator, QMultiHash::key_iterator, QMultiHash::key_value_iterator
*/
/*! \fn template <class Key, class T> QMultiHash<Key, T>::iterator::iterator()
@@ -3604,12 +3854,6 @@ size_t qHash(long double key, size_t seed) noexcept
\inmodule QtCore
\brief The QMultiHash::const_iterator class provides an STL-style const iterator for QMultiHash.
- QMultiHash features both \l{STL-style iterators} and \l{Java-style
- iterators}. The STL-style iterators are more low-level and more
- cumbersome to use; on the other hand, they are slightly faster
- and, for developers who already know STL, have the advantage of
- familiarity.
-
QMultiHash\<Key, T\>::const_iterator allows you to iterate over a
QMultiHash. If you want to modify the QMultiHash as you
iterate over it, you must use QMultiHash::iterator instead. It is
@@ -3620,8 +3864,8 @@ size_t qHash(long double key, size_t seed) noexcept
The default QMultiHash::const_iterator constructor creates an
uninitialized iterator. You must initialize it using a QMultiHash
- function like QMultiHash::constBegin(), QMultiHash::constEnd(), or
- QMultiHash::find() before you can start iterating. Here's a typical
+ function like QMultiHash::cbegin(), QMultiHash::cend(), or
+ QMultiHash::constFind() before you can start iterating. Here's a typical
loop that prints all the (key, value) pairs stored in a hash:
\snippet code/src_corelib_tools_qhash.cpp 23
@@ -3633,28 +3877,24 @@ size_t qHash(long double key, size_t seed) noexcept
recently to the least recently inserted value.
Multiple iterators can be used on the same hash. However, be aware
- that any modification performed directly on the QHash (inserting and
+ that any modification performed directly on the QMultiHash (inserting and
removing items) can cause the iterators to become invalid.
- Inserting items into the hash or calling methods such as QHash::reserve()
- or QHash::squeeze() can invalidate all iterators pointing into the hash.
- Iterators are guaranteed to stay valid only as long as the QHash doesn't have
+ Inserting items into the hash or calling methods such as QMultiHash::reserve()
+ or QMultiHash::squeeze() can invalidate all iterators pointing into the hash.
+ Iterators are guaranteed to stay valid only as long as the QMultiHash doesn't have
to grow/shrink it's internal hash table.
Using any iterator after a rehashing operation ahs occurred will lead to undefined behavior.
- You can however safely use iterators to remove entries from the hash
- using the QHash::erase() method. This function can safely be called while
- iterating, and won't affect the order of items in the hash.
-
If you need to keep iterators over a long period of time, we recommend
- that you use QMap rather than QHash.
+ that you use QMultiMap rather than QMultiHash.
\warning Iterators on implicitly shared containers do not work
exactly like STL-iterators. You should avoid copying a container
while iterators are active on that container. For more information,
read \l{Implicit sharing iterator problem}.
- \sa QMultiHash::iterator
+ \sa QMultiHash::iterator, QMultiHash::key_iterator, QMultiHash::const_key_value_iterator
*/
/*! \fn template <class Key, class T> QMultiHash<Key, T>::const_iterator::const_iterator()
diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h
index 09766859a9..e7cd4123fb 100644
--- a/src/corelib/tools/qhash.h
+++ b/src/corelib/tools/qhash.h
@@ -531,11 +531,29 @@ struct Data
}
};
+ static auto allocateSpans(size_t numBuckets)
+ {
+ struct R {
+ Span *spans;
+ size_t nSpans;
+ };
+
+ constexpr qptrdiff MaxSpanCount = (std::numeric_limits<qptrdiff>::max)() / sizeof(Span);
+ constexpr size_t MaxBucketCount = MaxSpanCount << SpanConstants::SpanShift;
+
+ if (numBuckets > MaxBucketCount) {
+ Q_CHECK_PTR(false);
+ Q_UNREACHABLE(); // no exceptions and no assertions -> no error reporting
+ }
+
+ size_t nSpans = numBuckets >> SpanConstants::SpanShift;
+ return R{ new Span[nSpans], nSpans };
+ }
+
Data(size_t reserve = 0)
{
numBuckets = GrowthPolicy::bucketsForCapacity(reserve);
- size_t nSpans = numBuckets >> SpanConstants::SpanShift;
- spans = new Span[nSpans];
+ spans = allocateSpans(numBuckets).spans;
seed = QHashSeed::globalSeed();
}
@@ -557,17 +575,16 @@ struct Data
Data(const Data &other) : size(other.size), numBuckets(other.numBuckets), seed(other.seed)
{
- size_t nSpans = numBuckets >> SpanConstants::SpanShift;
- spans = new Span[nSpans];
- reallocationHelper(other, nSpans, false);
+ auto r = allocateSpans(numBuckets);
+ spans = r.spans;
+ reallocationHelper(other, r.nSpans, false);
}
Data(const Data &other, size_t reserved) : size(other.size), seed(other.seed)
{
numBuckets = GrowthPolicy::bucketsForCapacity(qMax(size, reserved));
- size_t nSpans = numBuckets >> SpanConstants::SpanShift;
- spans = new Span[nSpans];
+ spans = allocateSpans(numBuckets).spans;
size_t otherNSpans = other.numBuckets >> SpanConstants::SpanShift;
- reallocationHelper(other, otherNSpans, true);
+ reallocationHelper(other, otherNSpans, numBuckets != other.numBuckets);
}
static Data *detached(Data *d)
@@ -623,8 +640,7 @@ struct Data
Span *oldSpans = spans;
size_t oldBucketCount = numBuckets;
- size_t nSpans = newBucketCount >> SpanConstants::SpanShift;
- spans = new Span[nSpans];
+ spans = allocateSpans(newBucketCount).spans;
numBuckets = newBucketCount;
size_t oldNSpans = oldBucketCount >> SpanConstants::SpanShift;
@@ -661,8 +677,10 @@ struct Data
return size >= (numBuckets >> 1);
}
- Bucket findBucket(const Key &key) const noexcept
+ template <typename K> Bucket findBucket(const K &key) const noexcept
{
+ static_assert(std::is_same_v<std::remove_cv_t<Key>, K> ||
+ QHashHeterogeneousSearch<std::remove_cv_t<Key>, K>::value);
Q_ASSERT(numBuckets > 0);
size_t hash = QHashPrivate::calculateHash(key, seed);
Bucket bucket(this, GrowthPolicy::bucketForHash(numBuckets, hash));
@@ -681,24 +699,12 @@ struct Data
}
}
- Node *findNode(const Key &key) const noexcept
+ template <typename K> Node *findNode(const K &key) const noexcept
{
- Q_ASSERT(numBuckets > 0);
- size_t hash = QHashPrivate::calculateHash(key, seed);
- Bucket bucket(this, GrowthPolicy::bucketForHash(numBuckets, hash));
- // loop over the buckets until we find the entry we search for
- // or an empty slot, in which case we know the entry doesn't exist
- while (true) {
- size_t offset = bucket.offset();
- if (offset == SpanConstants::UnusedEntry) {
- return nullptr;
- } else {
- Node &n = bucket.nodeAtOffset(offset);
- if (qHashEquals(n.key, key))
- return &n;
- }
- bucket.advanceWrapped(this);
- }
+ auto bucket = findBucket(key);
+ if (bucket.isUnused())
+ return nullptr;
+ return bucket.node();
}
struct InsertionResult
@@ -707,7 +713,7 @@ struct Data
bool initialized;
};
- InsertionResult findOrInsert(const Key &key) noexcept
+ template <typename K> InsertionResult findOrInsert(const K &key) noexcept
{
Bucket it(static_cast<Span *>(nullptr), 0);
if (numBuckets > 0) {
@@ -951,6 +957,11 @@ public:
bool remove(const Key &key)
{
+ return removeImpl(key);
+ }
+private:
+ template <typename K> bool removeImpl(const K &key)
+ {
if (isEmpty()) // prevents detaching shared null
return false;
auto it = d->findBucket(key);
@@ -963,13 +974,21 @@ public:
d->erase(it);
return true;
}
+
+public:
template <typename Predicate>
qsizetype removeIf(Predicate pred)
{
return QtPrivate::associative_erase_if(*this, pred);
}
+
T take(const Key &key)
{
+ return takeImpl(key);
+ }
+private:
+ template <typename K> T takeImpl(const K &key)
+ {
if (isEmpty()) // prevents detaching shared null
return T();
auto it = d->findBucket(key);
@@ -984,6 +1003,7 @@ public:
return value;
}
+public:
bool contains(const Key &key) const noexcept
{
if (!d)
@@ -996,74 +1016,68 @@ public:
}
private:
- const Key *keyImpl(const T &value) const noexcept
+ template <typename Fn> Key keyImpl(const T &value, Fn &&defaultFn) const noexcept
{
if (d) {
const_iterator i = begin();
while (i != end()) {
if (i.value() == value)
- return &i.key();
+ return i.key();
++i;
}
}
- return nullptr;
+ return defaultFn();
}
public:
Key key(const T &value) const noexcept
{
- if (auto *k = keyImpl(value))
- return *k;
- else
- return Key();
+ return keyImpl(value, [] { return Key(); });
}
Key key(const T &value, const Key &defaultKey) const noexcept
{
- if (auto *k = keyImpl(value))
- return *k;
- else
- return defaultKey;
+ return keyImpl(value, [&] { return defaultKey; });
}
private:
- T *valueImpl(const Key &key) const noexcept
+ template <typename K, typename Fn> T valueImpl(const K &key, Fn &&defaultValue) const noexcept
{
if (d) {
Node *n = d->findNode(key);
if (n)
- return &n->value;
+ return n->value;
}
- return nullptr;
+ return defaultValue();
}
public:
T value(const Key &key) const noexcept
{
- if (T *v = valueImpl(key))
- return *v;
- else
- return T();
+ return valueImpl(key, [] { return T(); });
}
T value(const Key &key, const T &defaultValue) const noexcept
{
- if (T *v = valueImpl(key))
- return *v;
- else
- return defaultValue;
+ return valueImpl(key, [&] { return defaultValue; });
}
T &operator[](const Key &key)
{
+ return operatorIndexImpl(key);
+ }
+private:
+ template <typename K> T &operatorIndexImpl(const K &key)
+ {
const auto copy = isDetached() ? QHash() : *this; // keep 'key' alive across the detach
detach();
auto result = d->findOrInsert(key);
Q_ASSERT(!result.it.atEnd());
if (!result.initialized)
- Node::createInPlace(result.it.node(), key, T());
+ Node::createInPlace(result.it.node(), Key(key), T());
return result.it.node()->value;
}
+public:
const T operator[](const Key &key) const noexcept
{
return value(key);
@@ -1230,28 +1244,25 @@ public:
return i;
}
- QPair<iterator, iterator> equal_range(const Key &key)
+ std::pair<iterator, iterator> equal_range(const Key &key)
{
- auto first = find(key);
- auto second = first;
- if (second != iterator())
- ++second;
- return qMakePair(first, second);
+ return equal_range_impl(*this, key);
}
-
- QPair<const_iterator, const_iterator> equal_range(const Key &key) const noexcept
+ std::pair<const_iterator, const_iterator> equal_range(const Key &key) const noexcept
{
- auto first = find(key);
+ return equal_range_impl(*this, key);
+ }
+private:
+ template <typename Hash, typename K> static auto equal_range_impl(Hash &self, const K &key)
+ {
+ auto first = self.find(key);
auto second = first;
- if (second != iterator())
+ if (second != decltype(first){})
++second;
- return qMakePair(first, second);
+ return std::make_pair(first, second);
}
- typedef iterator Iterator;
- typedef const_iterator ConstIterator;
- inline qsizetype count() const noexcept { return d ? qsizetype(d->size) : 0; }
- iterator find(const Key &key)
+ template <typename K> iterator findImpl(const K &key)
{
if (isEmpty()) // prevents detaching shared null
return end();
@@ -1263,7 +1274,7 @@ public:
return end();
return iterator(it.toIterator(d));
}
- const_iterator find(const Key &key) const noexcept
+ template <typename K> const_iterator constFindImpl(const K &key) const noexcept
{
if (isEmpty())
return end();
@@ -1272,6 +1283,19 @@ public:
return end();
return const_iterator({d, it.toBucketIndex(d)});
}
+
+public:
+ typedef iterator Iterator;
+ typedef const_iterator ConstIterator;
+ inline qsizetype count() const noexcept { return d ? qsizetype(d->size) : 0; }
+ iterator find(const Key &key)
+ {
+ return findImpl(key);
+ }
+ const_iterator find(const Key &key) const noexcept
+ {
+ return constFindImpl(key);
+ }
const_iterator constFind(const Key &key) const noexcept
{
return find(key);
@@ -1335,8 +1359,65 @@ private:
result.it.node()->emplaceValue(std::forward<Args>(args)...);
return iterator(result.it);
}
-};
+public:
+#ifdef __cpp_concepts
+ bool remove(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return removeImpl(key);
+ }
+ T take(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return takeImpl(key);
+ }
+ bool contains(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return d ? d->findNode(key) != nullptr : false;
+ }
+ qsizetype count(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return contains(key) ? 1 : 0;
+ }
+ T value(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return valueImpl(key, [] { return T(); });
+ }
+ T value(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &defaultValue) const noexcept
+ {
+ return valueImpl(key, [&] { return defaultValue; });
+ }
+ T &operator[](const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return operatorIndexImpl(key);
+ }
+ const T operator[](const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return value(key);
+ }
+ std::pair<iterator, iterator>
+ equal_range(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return equal_range_impl(*this, key);
+ }
+ std::pair<const_iterator, const_iterator>
+ equal_range(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return equal_range_impl(*this, key);
+ }
+ iterator find(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return findImpl(key);
+ }
+ const_iterator find(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return constFindImpl(key);
+ }
+ const_iterator constFind(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return find(key);
+ }
+#endif // __cpp_concepts
+};
template <typename Key, typename T>
@@ -1514,6 +1595,11 @@ public:
qsizetype remove(const Key &key)
{
+ return removeImpl(key);
+ }
+private:
+ template <typename K> qsizetype removeImpl(const K &key)
+ {
if (isEmpty()) // prevents detaching shared null
return 0;
auto it = d->findBucket(key);
@@ -1529,13 +1615,21 @@ public:
d->erase(it);
return n;
}
+
+public:
template <typename Predicate>
qsizetype removeIf(Predicate pred)
{
return QtPrivate::associative_erase_if(*this, pred);
}
+
T take(const Key &key)
{
+ return takeImpl(key);
+ }
+private:
+ template <typename K> T takeImpl(const K &key)
+ {
if (isEmpty()) // prevents detaching shared null
return T();
auto it = d->findBucket(key);
@@ -1560,6 +1654,7 @@ public:
return t;
}
+public:
bool contains(const Key &key) const noexcept
{
if (!d)
@@ -1568,75 +1663,71 @@ public:
}
private:
- const Key *keyImpl(const T &value) const noexcept
+ template <typename Fn> Key keyImpl(const T &value, Fn &&defaultValue) const noexcept
{
if (d) {
auto i = d->begin();
while (i != d->end()) {
Chain *e = i.node()->value;
if (e->contains(value))
- return &i.node()->key;
+ return i.node()->key;
++i;
}
}
- return nullptr;
+ return defaultValue();
}
public:
Key key(const T &value) const noexcept
{
- if (auto *k = keyImpl(value))
- return *k;
- else
- return Key();
+ return keyImpl(value, [] { return Key(); });
}
Key key(const T &value, const Key &defaultKey) const noexcept
{
- if (auto *k = keyImpl(value))
- return *k;
- else
- return defaultKey;
+ return keyImpl(value, [&] { return defaultKey; });
}
private:
- T *valueImpl(const Key &key) const noexcept
+ template <typename K, typename Fn> T valueImpl(const K &key, Fn &&defaultValue) const noexcept
{
if (d) {
Node *n = d->findNode(key);
if (n) {
Q_ASSERT(n->value);
- return &n->value->value;
+ return n->value->value;
}
}
- return nullptr;
+ return defaultValue();
}
public:
T value(const Key &key) const noexcept
{
- if (auto *v = valueImpl(key))
- return *v;
- else
- return T();
+ return valueImpl(key, [] { return T(); });
}
T value(const Key &key, const T &defaultValue) const noexcept
{
- if (auto *v = valueImpl(key))
- return *v;
- else
- return defaultValue;
+ return valueImpl(key, [&] { return defaultValue; });
}
T &operator[](const Key &key)
{
+ return operatorIndexImpl(key);
+ }
+private:
+ template <typename K> T &operatorIndexImpl(const K &key)
+ {
const auto copy = isDetached() ? QMultiHash() : *this; // keep 'key' alive across the detach
detach();
auto result = d->findOrInsert(key);
Q_ASSERT(!result.it.atEnd());
- if (!result.initialized)
- Node::createInPlace(result.it.node(), key, T());
+ if (!result.initialized) {
+ Node::createInPlace(result.it.node(), Key(key), T());
+ ++m_size;
+ }
return result.it.node()->value->value;
}
+public:
const T operator[](const Key &key) const noexcept
{
return value(key);
@@ -1667,9 +1758,15 @@ public:
}
return res;
}
+
QList<T> values() const { return QList<T>(begin(), end()); }
QList<T> values(const Key &key) const
{
+ return valuesImpl(key);
+ }
+private:
+ template <typename K> QList<T> valuesImpl(const K &key) const
+ {
QList<T> values;
if (d) {
Node *n = d->findNode(key);
@@ -1684,6 +1781,7 @@ public:
return values;
}
+public:
class const_iterator;
class iterator
@@ -1895,7 +1993,9 @@ public:
typedef iterator Iterator;
typedef const_iterator ConstIterator;
inline qsizetype count() const noexcept { return size(); }
- iterator find(const Key &key)
+
+private:
+ template <typename K> iterator findImpl(const K &key)
{
if (isEmpty())
return end();
@@ -1908,11 +2008,7 @@ public:
return end();
return iterator(it.toIterator(d));
}
- const_iterator find(const Key &key) const noexcept
- {
- return constFind(key);
- }
- const_iterator constFind(const Key &key) const noexcept
+ template <typename K> const_iterator constFindImpl(const K &key) const noexcept
{
if (isEmpty())
return end();
@@ -1921,6 +2017,20 @@ public:
return constEnd();
return const_iterator(it.toIterator(d));
}
+public:
+ iterator find(const Key &key)
+ {
+ return findImpl(key);
+ }
+ const_iterator constFind(const Key &key) const noexcept
+ {
+ return constFindImpl(key);
+ }
+ const_iterator find(const Key &key) const noexcept
+ {
+ return constFindImpl(key);
+ }
+
iterator insert(const Key &key, const T &value)
{
return emplace(key, value);
@@ -1986,6 +2096,11 @@ public:
bool contains(const Key &key, const T &value) const noexcept
{
+ return containsImpl(key, value);
+ }
+private:
+ template <typename K> bool containsImpl(const K &key, const T &value) const noexcept
+ {
if (isEmpty())
return false;
auto n = d->findNode(key);
@@ -1994,8 +2109,14 @@ public:
return n->value->contains(value);
}
+public:
qsizetype remove(const Key &key, const T &value)
{
+ return removeImpl(key, value);
+ }
+private:
+ template <typename K> qsizetype removeImpl(const K &key, const T &value)
+ {
if (isEmpty()) // prevents detaching shared null
return 0;
auto it = d->findBucket(key);
@@ -2024,8 +2145,14 @@ public:
return n;
}
+public:
qsizetype count(const Key &key) const noexcept
{
+ return countImpl(key);
+ }
+private:
+ template <typename K> qsizetype countImpl(const K &key) const noexcept
+ {
if (!d)
return 0;
auto it = d->findBucket(key);
@@ -2041,8 +2168,14 @@ public:
return n;
}
+public:
qsizetype count(const Key &key, const T &value) const noexcept
{
+ return countImpl(key, value);
+ }
+private:
+ template <typename K> qsizetype countImpl(const K &key, const T &value) const noexcept
+ {
if (!d)
return 0;
auto it = d->findBucket(key);
@@ -2059,7 +2192,7 @@ public:
return n;
}
- iterator find(const Key &key, const T &value)
+ template <typename K> iterator findImpl(const K &key, const T &value)
{
if (isEmpty())
return end();
@@ -2068,11 +2201,7 @@ public:
auto it = constFind(key, value);
return iterator(it.i, it.e);
}
- const_iterator find(const Key &key, const T &value) const noexcept
- {
- return constFind(key, value);
- }
- const_iterator constFind(const Key &key, const T &value) const noexcept
+ template <typename K> const_iterator constFindImpl(const K &key, const T &value) const noexcept
{
const_iterator i(constFind(key));
const_iterator end(constEnd());
@@ -2084,6 +2213,21 @@ public:
return end;
}
+public:
+ iterator find(const Key &key, const T &value)
+ {
+ return findImpl(key, value);
+ }
+
+ const_iterator constFind(const Key &key, const T &value) const noexcept
+ {
+ return constFindImpl(key, value);
+ }
+ const_iterator find(const Key &key, const T &value) const noexcept
+ {
+ return constFind(key, value);
+ }
+
QMultiHash &unite(const QMultiHash &other)
{
if (isEmpty()) {
@@ -2119,29 +2263,39 @@ public:
return *this;
}
- QPair<iterator, iterator> equal_range(const Key &key)
+ std::pair<iterator, iterator> equal_range(const Key &key)
+ {
+ return equal_range_impl(key);
+ }
+private:
+ template <typename K> std::pair<iterator, iterator> equal_range_impl(const K &key)
{
const auto copy = isDetached() ? QMultiHash() : *this; // keep 'key' alive across the detach
detach();
auto pair = std::as_const(*this).equal_range(key);
- return qMakePair(iterator(pair.first.i), iterator(pair.second.i));
+ return {iterator(pair.first.i), iterator(pair.second.i)};
}
- QPair<const_iterator, const_iterator> equal_range(const Key &key) const noexcept
+public:
+ std::pair<const_iterator, const_iterator> equal_range(const Key &key) const noexcept
+ {
+ return equal_range_impl(key);
+ }
+private:
+ template <typename K> std::pair<const_iterator, const_iterator> equal_range_impl(const K &key) const noexcept
{
if (!d)
- return qMakePair(end(), end());
+ return {end(), end()};
auto bucket = d->findBucket(key);
if (bucket.isUnused())
- return qMakePair(end(), end());
+ return {end(), end()};
auto it = bucket.toIterator(d);
auto end = it;
++end;
- return qMakePair(const_iterator(it), const_iterator(end));
+ return {const_iterator(it), const_iterator(end)};
}
-private:
void detach_helper()
{
if (!d) {
@@ -2178,6 +2332,94 @@ private:
}
return iterator(result.it);
}
+
+public:
+#ifdef __cpp_concepts
+ qsizetype remove(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return removeImpl(key);
+ }
+ T take(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return takeImpl(key);
+ }
+ bool contains(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ if (!d)
+ return false;
+ return d->findNode(key) != nullptr;
+ }
+ T value(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return valueImpl(key, [] { return T(); });
+ }
+ T value(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &defaultValue) const noexcept
+ {
+ return valueImpl(key, [&] { return defaultValue; });
+ }
+ T &operator[](const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return operatorIndexImpl(key);
+ }
+ const T operator[](const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return value(key);
+ }
+ QList<T> values(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return valuesImpl(key);
+ }
+ iterator find(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return findImpl(key);
+ }
+ const_iterator constFind(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return constFindImpl(key);
+ }
+ const_iterator find(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return constFindImpl(key);
+ }
+ bool contains(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value) const noexcept
+ {
+ return containsImpl(key, value);
+ }
+ qsizetype remove(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value)
+ {
+ return removeImpl(key, value);
+ }
+ qsizetype count(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return countImpl(key);
+ }
+ qsizetype count(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value) const noexcept
+ {
+ return countImpl(key, value);
+ }
+ iterator find(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value)
+ {
+ return findImpl(key, value);
+ }
+ const_iterator constFind(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value) const noexcept
+ {
+ return constFindImpl(key, value);
+ }
+ const_iterator find(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key, const T &value) const noexcept
+ {
+ return constFind(key, value);
+ }
+ std::pair<iterator, iterator>
+ equal_range(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key)
+ {
+ return equal_range_impl(key);
+ }
+ std::pair<const_iterator, const_iterator>
+ equal_range(const QHashPrivate::HeterogeneouslySearchableWith<Key> auto &key) const noexcept
+ {
+ return equal_range_impl(key);
+ }
+#endif // __cpp_concepts
};
Q_DECLARE_ASSOCIATIVE_FORWARD_ITERATOR(Hash)
diff --git a/src/corelib/tools/qhashfunctions.h b/src/corelib/tools/qhashfunctions.h
index bcb8caf1f7..90a269deaa 100644
--- a/src/corelib/tools/qhashfunctions.h
+++ b/src/corelib/tools/qhashfunctions.h
@@ -1,5 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
+// Copyright (C) 2024 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QHASHFUNCTIONS_H
@@ -7,10 +8,14 @@
#include <QtCore/qstring.h>
#include <QtCore/qstringfwd.h>
-#include <QtCore/qpair.h>
#include <numeric> // for std::accumulate
#include <functional> // for std::hash
+#include <utility> // For std::pair
+
+#ifdef __cpp_concepts
+# include <concepts>
+#endif
#if 0
#pragma qt_class(QHashFunctions)
@@ -45,6 +50,21 @@ private:
size_t data;
};
+// Whether, ∀ t of type T && ∀ seed, qHash(Key(t), seed) == qHash(t, seed)
+template <typename Key, typename T> struct QHashHeterogeneousSearch : std::false_type {};
+
+// Specializations
+template <> struct QHashHeterogeneousSearch<QString, QStringView> : std::true_type {};
+template <> struct QHashHeterogeneousSearch<QStringView, QString> : std::true_type {};
+template <> struct QHashHeterogeneousSearch<QByteArray, QByteArrayView> : std::true_type {};
+template <> struct QHashHeterogeneousSearch<QByteArrayView, QByteArray> : std::true_type {};
+#ifndef Q_PROCESSOR_ARM
+template <> struct QHashHeterogeneousSearch<QString, QLatin1StringView> : std::true_type {};
+template <> struct QHashHeterogeneousSearch<QStringView, QLatin1StringView> : std::true_type {};
+template <> struct QHashHeterogeneousSearch<QLatin1StringView, QString> : std::true_type {};
+template <> struct QHashHeterogeneousSearch<QLatin1StringView, QStringView> : std::true_type {};
+#endif
+
namespace QHashPrivate {
Q_DECL_CONST_FUNCTION constexpr size_t hash(size_t key, size_t seed) noexcept
@@ -102,7 +122,39 @@ Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(quint64 key, size_t seed = 0
key ^= (key >> 32);
return QHashPrivate::hash(size_t(key), seed);
}
-Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(qint64 key, size_t seed = 0) noexcept { return qHash(quint64(key), seed); }
+Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(qint64 key, size_t seed = 0) noexcept
+{
+ if constexpr (sizeof(qint64) > sizeof(size_t)) {
+ // Avoid QTBUG-116080: we XOR the top half with its own sign bit:
+ // - if the qint64 is in range of qint32, then signmask ^ high == 0
+ // (for Qt 7 only)
+ // - if the qint64 is in range of quint32, then signmask == 0 and we
+ // do the same as the quint64 overload above
+ quint32 high = quint32(quint64(key) >> 32);
+ quint32 low = quint32(quint64(key));
+ quint32 signmask = qint32(high) >> 31; // all zeroes or all ones
+ signmask = QT_VERSION_MAJOR > 6 ? signmask : 0;
+ low ^= signmask ^ high;
+ return qHash(low, seed);
+ }
+ return qHash(quint64(key), seed);
+}
+#if QT_SUPPORTS_INT128
+constexpr size_t qHash(quint128 key, size_t seed = 0) noexcept
+{
+ return qHash(quint64(key + (key >> 64)), seed);
+}
+constexpr size_t qHash(qint128 key, size_t seed = 0) noexcept
+{
+ // Avoid QTBUG-116080: same as above, but with double the sizes and without
+ // the need for compatibility
+ quint64 high = quint64(quint128(key) >> 64);
+ quint64 low = quint64(quint128(key));
+ quint64 signmask = qint64(high) >> 63; // all zeroes or all ones
+ low += signmask ^ high;
+ return qHash(low, seed);
+}
+#endif // QT_SUPPORTS_INT128
Q_DECL_CONST_FUNCTION inline size_t qHash(float key, size_t seed = 0) noexcept
{
// ensure -0 gets mapped to 0
@@ -112,9 +164,7 @@ Q_DECL_CONST_FUNCTION inline size_t qHash(float key, size_t seed = 0) noexcept
return QHashPrivate::hash(k, seed);
}
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION size_t qHash(double key, size_t seed = 0) noexcept;
-#if !defined(Q_OS_DARWIN) || defined(Q_QDOC)
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION size_t qHash(long double key, size_t seed = 0) noexcept;
-#endif
Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(wchar_t key, size_t seed = 0) noexcept
{ return QHashPrivate::hash(size_t(key), seed); }
Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(char16_t key, size_t seed = 0) noexcept
@@ -153,7 +203,9 @@ inline Q_DECL_PURE_FUNCTION size_t qHash(const QByteArray &key, size_t seed = 0
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(QStringView key, size_t seed = 0) noexcept;
inline Q_DECL_PURE_FUNCTION size_t qHash(const QString &key, size_t seed = 0) noexcept
{ return qHash(QStringView{key}, seed); }
+#ifndef QT_BOOTSTRAPPED
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(const QBitArray &key, size_t seed = 0) noexcept;
+#endif
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION size_t qHash(QLatin1StringView key, size_t seed = 0) noexcept;
Q_DECL_CONST_FUNCTION constexpr inline size_t qHash(QKeyCombination key, size_t seed = 0) noexcept
{ return qHash(key.toCombined(), seed); }
@@ -184,12 +236,35 @@ size_t qHash(const T &t, size_t seed) noexcept(noexcept(qHash(t)))
{ return qHash(t) ^ seed; }
#endif // < Qt 7
+namespace QHashPrivate {
+#ifdef __cpp_concepts
+template <typename Key, typename T> concept HeterogeneouslySearchableWithHelper =
+ // if Key and T are not the same (member already exists)
+ !std::is_same_v<Key, T>
+ // but are comparable amongst each other
+ && std::equality_comparable_with<Key, T>
+ // and supports heteregenous hashing
+ && QHashHeterogeneousSearch<Key, T>::value;
+template <typename Key, typename T> concept HeterogeneouslySearchableWith =
+ HeterogeneouslySearchableWithHelper<q20::remove_cvref_t<Key>, q20::remove_cvref_t<T>>;
+#else
+template <typename Key, typename T> constexpr bool HeterogeneouslySearchableWith = false;
+#endif
+}
+
template<typename T>
bool qHashEquals(const T &a, const T &b)
{
return a == b;
}
+template <typename T1, typename T2>
+std::enable_if_t<QHashPrivate::HeterogeneouslySearchableWith<T1, T2>, bool>
+qHashEquals(const T1 &a, const T2 &b)
+{
+ return a == b;
+}
+
namespace QtPrivate {
struct QHashCombine
@@ -326,7 +401,9 @@ QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_VALUE(QStringView)
QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_VALUE(QLatin1StringView)
QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_VALUE(QByteArrayView)
QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(QByteArray)
+#ifndef QT_BOOTSTRAPPED
QT_SPECIALIZE_STD_HASH_TO_CALL_QHASH_BY_CREF(QBitArray)
+#endif
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qiterator.h b/src/corelib/tools/qiterator.h
index cff535d030..8a2b493ef4 100644
--- a/src/corelib/tools/qiterator.h
+++ b/src/corelib/tools/qiterator.h
@@ -5,11 +5,19 @@
#define QITERATOR_H
#include <QtCore/qglobal.h>
+#include <QtCore/qcontainertools_impl.h>
QT_BEGIN_NAMESPACE
#if !defined(QT_NO_JAVA_STYLE_ITERATORS)
+#ifdef Q_QDOC
+#define Q_DISABLE_BACKWARD_ITERATOR
+#else
+#define Q_DISABLE_BACKWARD_ITERATOR \
+ template<typename It = decltype(i), QtPrivate::IfIteratorCanMoveBackwards<It> = true>
+#endif
+
#define Q_DECLARE_SEQUENTIAL_ITERATOR(C) \
\
template <class T> \
@@ -28,11 +36,15 @@ public: \
inline bool hasNext() const { return i != c.constEnd(); } \
inline const T &next() { return *i++; } \
inline const T &peekNext() const { return *i; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline bool hasPrevious() const { return i != c.constBegin(); } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline const T &previous() { return *--i; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline const T &peekPrevious() const { const_iterator p = i; return *--p; } \
inline bool findNext(const T &t) \
{ while (i != c.constEnd()) if (*i++ == t) return true; return false; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline bool findPrevious(const T &t) \
{ while (i != c.constBegin()) if (*(--i) == t) return true; \
return false; } \
@@ -59,8 +71,11 @@ public: \
inline bool hasNext() const { return c->constEnd() != const_iterator(i); } \
inline T &next() { n = i++; return *n; } \
inline T &peekNext() const { return *i; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline bool hasPrevious() const { return c->constBegin() != const_iterator(i); } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline T &previous() { n = --i; return *n; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline T &peekPrevious() const { iterator p = i; return *--p; } \
inline void remove() \
{ if (c->constEnd() != const_iterator(n)) { i = c->erase(n); n = c->end(); } } \
@@ -70,6 +85,7 @@ public: \
inline void insert(const T &t) { n = i = c->insert(i, t); ++i; } \
inline bool findNext(const T &t) \
{ while (c->constEnd() != const_iterator(n = i)) if (*i++ == t) return true; return false; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline bool findPrevious(const T &t) \
{ while (c->constBegin() != const_iterator(i)) if (*(n = --i) == t) return true; \
n = c->end(); return false; } \
@@ -95,13 +111,17 @@ public: \
inline bool hasNext() const { return i != c.constEnd(); } \
inline Item next() { n = i++; return n; } \
inline Item peekNext() const { return i; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline bool hasPrevious() const { return i != c.constBegin(); } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline Item previous() { n = --i; return n; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline Item peekPrevious() const { const_iterator p = i; return --p; } \
inline const T &value() const { Q_ASSERT(item_exists()); return *n; } \
inline const Key &key() const { Q_ASSERT(item_exists()); return n.key(); } \
inline bool findNext(const T &t) \
{ while ((n = i) != c.constEnd()) if (*i++ == t) return true; return false; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline bool findPrevious(const T &t) \
{ while (i != c.constBegin()) if (*(n = --i) == t) return true; \
n = c.constEnd(); return false; } \
@@ -129,8 +149,11 @@ public: \
inline bool hasNext() const { return const_iterator(i) != c->constEnd(); } \
inline Item next() { n = i++; return n; } \
inline Item peekNext() const { return i; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline bool hasPrevious() const { return const_iterator(i) != c->constBegin(); } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline Item previous() { n = --i; return n; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline Item peekPrevious() const { iterator p = i; return --p; } \
inline void remove() \
{ if (const_iterator(n) != c->constEnd()) { i = c->erase(n); n = c->end(); } } \
@@ -140,6 +163,7 @@ public: \
inline const Key &key() const { Q_ASSERT(item_exists()); return n.key(); } \
inline bool findNext(const T &t) \
{ while (const_iterator(n = i) != c->constEnd()) if (*i++ == t) return true; return false; } \
+ Q_DISABLE_BACKWARD_ITERATOR \
inline bool findPrevious(const T &t) \
{ while (const_iterator(i) != c->constBegin()) if (*(n = --i) == t) return true; \
n = c->end(); return false; } \
@@ -230,26 +254,10 @@ public:
return std::pair<Key, T>(i.key(), i.value());
}
- struct pointer
- {
- pointer(value_type &&r_) : r(std::move(r_)) { }
-
- pointer() = default;
- pointer(const pointer &other) = default;
- pointer(pointer &&other) = default;
- pointer &operator=(const pointer &other) = default;
- pointer &operator=(pointer &&other) = default;
-
- value_type &operator*() const { return r; }
-
- value_type r;
- const value_type *operator->() const {
- return &r;
- }
- };
+ using pointer = QtPrivate::ArrowProxy<value_type>;
pointer operator->() const {
- return pointer(std::pair<Key, T>(i.key(), i.value()));
+ return pointer{std::pair<Key, T>(i.key(), i.value())};
}
friend bool operator==(QKeyValueIterator lhs, QKeyValueIterator rhs) noexcept { return lhs.i == rhs.i; }
diff --git a/src/corelib/tools/qiterator.qdoc b/src/corelib/tools/qiterator.qdoc
index 3fc68e0874..041fb0701d 100644
--- a/src/corelib/tools/qiterator.qdoc
+++ b/src/corelib/tools/qiterator.qdoc
@@ -213,12 +213,8 @@
\image javaiterators1.png
- Here's how to iterate over the elements in reverse order:
-
- \snippet code/doc_src_qiterator.cpp 7
-
If you want to find all occurrences of a particular value, use
- findNext() or findPrevious() in a loop.
+ findNext() in a loop.
Multiple iterators can be used on the same set. If the set
is modified while a QSetIterator is active, the QSetIterator
@@ -389,15 +385,21 @@
*/
/*! \fn template <class T> void QListIterator<T>::toBack()
- \fn template <class T> void QSetIterator<T>::toBack()
\fn template <class T> void QMutableListIterator<T>::toBack()
+//! [toBack]
Moves the iterator to the back of the container (after the last
item).
+//! [toBack]
\sa toFront(), previous()
*/
+/*! \fn template <class T> void QSetIterator<T>::toBack()
+ \include qiterator.qdoc toBack
+ \sa toFront()
+*/
+
/*! \fn template <class T> void QMutableSetIterator<T>::toBack()
Moves the iterator to the back of the container (after the last
@@ -407,16 +409,22 @@
*/
/*! \fn template <class T> bool QListIterator<T>::hasNext() const
- \fn template <class T> bool QSetIterator<T>::hasNext() const
\fn template <class T> bool QMutableListIterator<T>::hasNext() const
+//! [hasNext]
Returns \c true if there is at least one item ahead of the iterator,
i.e. the iterator is \e not at the back of the container;
otherwise returns \c false.
+//! [hasNext]
\sa hasPrevious(), next()
*/
+/*! \fn template <class T> bool QSetIterator<T>::hasNext() const
+ \include qiterator.qdoc hasNext
+ \sa next()
+*/
+
/*! \fn template <class T> bool QMutableSetIterator<T>::hasNext() const
Returns \c true if there is at least one item ahead of the iterator,
@@ -427,16 +435,23 @@
*/
/*! \fn template <class T> const T &QListIterator<T>::next()
- \fn template <class T> const T &QSetIterator<T>::next()
+//! [next]
Returns the next item and advances the iterator by one position.
Calling this function on an iterator located at the back of the
container leads to undefined results.
+//! [next]
\sa hasNext(), peekNext(), previous()
*/
+/*!
+ \fn template <class T> const T &QSetIterator<T>::next()
+ \include qiterator.qdoc next
+ \sa hasNext(), peekNext()
+*/
+
/* \fn template <class T> const T &QMutableSetIterator<T>::next()
Returns the next item and advances the iterator by one position.
@@ -468,17 +483,24 @@
*/
/*! \fn template <class T> const T &QListIterator<T>::peekNext() const
- \fn template <class T> const T &QSetIterator<T>::peekNext() const
+//! [peekNext]
Returns the next item without moving the iterator.
Calling this function on an iterator located at the back of the
container leads to undefined results.
+//! [peekNext]
\sa hasNext(), next(), peekPrevious()
*/
/*!
+ \fn template <class T> const T &QSetIterator<T>::peekNext() const
+ \include qiterator.qdoc peekNext
+ \sa hasNext(), next()
+*/
+
+/*!
\fn template <class T> const T &QMutableSetIterator<T>::peekNext() const
Returns the next item without moving the iterator.
@@ -500,7 +522,6 @@
*/
/*! \fn template <class T> bool QListIterator<T>::hasPrevious() const
- \fn template <class T> bool QSetIterator<T>::hasPrevious() const
\fn template <class T> bool QMutableListIterator<T>::hasPrevious() const
Returns \c true if there is at least one item behind the iterator,
@@ -511,7 +532,6 @@
*/
/*! \fn template <class T> const T &QListIterator<T>::previous()
- \fn template <class T> const T &QSetIterator<T>::previous()
Returns the previous item and moves the iterator back by one
position.
@@ -534,7 +554,6 @@
*/
/*! \fn template <class T> const T &QListIterator<T>::peekPrevious() const
- \fn template <class T> const T &QSetIterator<T>::peekPrevious() const
Returns the previous item without moving the iterator.
@@ -566,21 +585,25 @@
*/
/*! \fn template <class T> bool QListIterator<T>::findNext(const T &value)
- \fn template <class T> bool QSetIterator<T>::findNext(const T &value)
\fn template <class T> bool QMutableListIterator<T>::findNext(const T &value)
+//! [findNext]
Searches for \a value starting from the current iterator position
forward. Returns \c true if \a value is found; otherwise returns \c false.
After the call, if \a value was found, the iterator is positioned
just after the matching item; otherwise, the iterator is
positioned at the back of the container.
+//! [findNext]
\sa findPrevious()
*/
+/*! \fn template <class T> bool QSetIterator<T>::findNext(const T &value)
+ \include qiterator.qdoc findNext
+*/
+
/*! \fn template <class T> bool QListIterator<T>::findPrevious(const T &value)
- \fn template <class T> bool QSetIterator<T>::findPrevious(const T &value)
\fn template <class T> bool QMutableListIterator<T>::findPrevious(const T &value)
Searches for \a value starting from the current iterator position
@@ -950,9 +973,8 @@
be preferred.
QMutableHashIterator\<Key, T\> allows you to iterate over a QHash
- (or a QMultiHash) and modify the hash. If you don't want to modify
- the hash (or have a const QHash), use the slightly faster
- QHashIterator instead.
+ and modify the hash. If you don't want to modify the hash (or have
+ a const QHash), use the slightly faster QHashIterator instead.
The QMutableHashIterator constructor takes a QHash as argument.
After construction, the iterator is located at the very beginning
diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h
index cc65039941..89e0e3f380 100644
--- a/src/corelib/tools/qlist.h
+++ b/src/corelib/tools/qlist.h
@@ -10,12 +10,15 @@
#include <QtCore/qhashfunctions.h>
#include <QtCore/qiterator.h>
#include <QtCore/qcontainertools_impl.h>
+#include <QtCore/qnamespace.h>
#include <functional>
#include <limits>
#include <initializer_list>
#include <type_traits>
+class tst_QList;
+
QT_BEGIN_NAMESPACE
namespace QtPrivate {
@@ -75,10 +78,15 @@ class QList
using DataPointer = QArrayDataPointer<T>;
class DisableRValueRefs {};
+ friend class ::tst_QList;
+
DataPointer d;
template <typename V, typename U> friend qsizetype QtPrivate::indexOf(const QList<V> &list, const U &u, qsizetype from) noexcept;
template <typename V, typename U> friend qsizetype QtPrivate::lastIndexOf(const QList<V> &list, const U &u, qsizetype from) noexcept;
+ // This alias prevents the QtPrivate namespace from being exposed into the docs.
+ template <typename InputIterator>
+ using if_input_iterator = QtPrivate::IfIsInputIterator<InputIterator>;
public:
using Type = T;
@@ -109,8 +117,7 @@ public:
public:
using difference_type = qsizetype;
using value_type = T;
- // libstdc++ shipped with gcc < 11 does not have a fix for defect LWG 3346
-#if __cplusplus >= 202002L && (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE >= 11)
+#ifdef QT_COMPILER_HAS_LWG3346
using iterator_concept = std::contiguous_iterator_tag;
using element_type = value_type;
#endif
@@ -180,8 +187,7 @@ public:
public:
using difference_type = qsizetype;
using value_type = T;
- // libstdc++ shipped with gcc < 11 does not have a fix for defect LWG 3346
-#if __cplusplus >= 202002L && (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE >= 11)
+#ifdef QT_COMPILER_HAS_LWG3346
using iterator_concept = std::contiguous_iterator_tag;
using element_type = const value_type;
#endif
@@ -252,6 +258,14 @@ private:
const std::less<const T*> less = {};
return !less(d->end(), i.i) && !less(i.i, d->begin());
}
+
+ void verify([[maybe_unused]] qsizetype pos = 0, [[maybe_unused]] qsizetype n = 1) const
+ {
+ Q_ASSERT(pos >= 0);
+ Q_ASSERT(pos <= size());
+ Q_ASSERT(n >= 0);
+ Q_ASSERT(n <= size() - pos);
+ }
public:
QList(DataPointer dd) noexcept
: d(dd)
@@ -261,20 +275,20 @@ public:
public:
QList() = default;
explicit QList(qsizetype size)
- : d(Data::allocate(size))
+ : d(size)
{
if (size)
d->appendInitialize(size);
}
QList(qsizetype size, parameter_type t)
- : d(Data::allocate(size))
+ : d(size)
{
if (size)
d->copyAppend(size, t);
}
inline QList(std::initializer_list<T> args)
- : d(Data::allocate(args.size()))
+ : d(qsizetype(args.size()))
{
if (args.size())
d->copyAppend(args.begin(), args.end());
@@ -282,12 +296,10 @@ public:
QList<T> &operator=(std::initializer_list<T> args)
{
- d = DataPointer(Data::allocate(args.size()));
- if (args.size())
- d->copyAppend(args.begin(), args.end());
- return *this;
+ return assign(args);
}
- template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true>
+
+ template <typename InputIterator, if_input_iterator<InputIterator> = true>
QList(InputIterator i1, InputIterator i2)
{
if constexpr (!std::is_convertible_v<typename std::iterator_traits<InputIterator>::iterator_category, std::forward_iterator_tag>) {
@@ -295,7 +307,7 @@ public:
} else {
const auto distance = std::distance(i1, i2);
if (distance) {
- d = DataPointer(Data::allocate(distance));
+ d = DataPointer(qsizetype(distance));
// appendIteratorRange can deal with contiguous iterators on its own,
// this is an optimization for C++17 code.
if constexpr (std::is_same_v<std::decay_t<InputIterator>, iterator> ||
@@ -313,6 +325,13 @@ public:
inline explicit QList(const String &str)
{ append(str); }
+ QList(qsizetype size, Qt::Initialization)
+ : d(size)
+ {
+ if (size)
+ d->appendUninitialized(size);
+ }
+
// compiler-generated special member functions are fine!
void swap(QList &other) noexcept { d.swap(other.d); }
@@ -393,6 +412,12 @@ public:
if (size > this->size())
d->copyAppend(size - this->size(), c);
}
+ void resizeForOverwrite(qsizetype size)
+ {
+ resize_internal(size);
+ if (size > this->size())
+ d->appendUninitialized(size);
+ }
inline qsizetype capacity() const { return qsizetype(d->constAllocatedCapacity()); }
void reserve(qsizetype size);
@@ -411,7 +436,7 @@ public:
return;
if (d->needsDetach()) {
// must allocate memory
- DataPointer detached(Data::allocate(d.allocatedCapacity()));
+ DataPointer detached(d.allocatedCapacity());
d.swap(detached);
} else {
d->truncate(0);
@@ -488,6 +513,19 @@ public:
}
}
+ QList &assign(qsizetype n, parameter_type t)
+ {
+ Q_ASSERT(n >= 0);
+ return fill(t, n);
+ }
+
+ template <typename InputIterator, if_input_iterator<InputIterator> = true>
+ QList &assign(InputIterator first, InputIterator last)
+ { d.assign(first, last); return *this; }
+
+ QList &assign(std::initializer_list<T> l)
+ { return assign(l.begin(), l.end()); }
+
template <typename ...Args>
iterator emplace(const_iterator before, Args&&... args)
{
@@ -615,27 +653,13 @@ public:
QList<T> mid(qsizetype pos, qsizetype len = -1) const;
QList<T> first(qsizetype n) const
- {
- Q_ASSERT(size_t(n) <= size_t(size()));
- return QList<T>(begin(), begin() + n);
- }
+ { verify(0, n); return QList<T>(begin(), begin() + n); }
QList<T> last(qsizetype n) const
- {
- Q_ASSERT(size_t(n) <= size_t(size()));
- return QList<T>(end() - n, end());
- }
+ { verify(0, n); return QList<T>(end() - n, end()); }
QList<T> sliced(qsizetype pos) const
- {
- Q_ASSERT(size_t(pos) <= size_t(size()));
- return QList<T>(begin() + pos, end());
- }
+ { verify(pos, 0); return QList<T>(begin() + pos, end()); }
QList<T> sliced(qsizetype pos, qsizetype n) const
- {
- Q_ASSERT(size_t(pos) <= size_t(size()));
- Q_ASSERT(n >= 0);
- Q_ASSERT(pos + n <= size());
- return QList<T>(begin() + pos, begin() + pos + n);
- }
+ { verify(pos, n); return QList<T>(begin() + pos, begin() + pos + n); }
T value(qsizetype i) const { return value(i, T()); }
T value(qsizetype i, parameter_type defaultValue) const;
@@ -665,6 +689,10 @@ public:
inline reference back() { return last(); }
inline const_reference back() const noexcept { return last(); }
void shrink_to_fit() { squeeze(); }
+ static qsizetype max_size() noexcept
+ {
+ return Data::max_size();
+ }
// comfort
QList<T> &operator+=(const QList<T> &l) { append(l); return *this; }
@@ -735,7 +763,7 @@ void QList<T>::reserve(qsizetype asize)
}
}
- DataPointer detached(Data::allocate(qMax(asize, size())));
+ DataPointer detached(qMax(asize, size()));
detached->copyAppend(d->begin(), d->end());
if (detached.d_ptr())
detached->setFlag(Data::CapacityReserved);
@@ -749,7 +777,7 @@ inline void QList<T>::squeeze()
return;
if (d->needsDetach() || size() < capacity()) {
// must allocate memory
- DataPointer detached(Data::allocate(size()));
+ DataPointer detached(size());
if (size()) {
if (d.needsDetach())
detached->copyAppend(d.data(), d.data() + d.size);
@@ -878,7 +906,7 @@ inline QList<T> &QList<T>::fill(parameter_type t, qsizetype newSize)
newSize = size();
if (d->needsDetach() || newSize > capacity()) {
// must allocate memory
- DataPointer detached(Data::allocate(d->detachCapacity(newSize)));
+ DataPointer detached(d->detachCapacity(newSize));
detached->copyAppend(newSize, t);
d.swap(detached);
} else {
@@ -960,7 +988,7 @@ inline QList<T> QList<T>::mid(qsizetype pos, qsizetype len) const
}
// Allocate memory
- DataPointer copied(Data::allocate(l));
+ DataPointer copied(l);
copied->copyAppend(data() + p, data() + p + l);
return copied;
}
diff --git a/src/corelib/tools/qlist.qdoc b/src/corelib/tools/qlist.qdoc
index 28aa1f271f..e07b74cd53 100644
--- a/src/corelib/tools/qlist.qdoc
+++ b/src/corelib/tools/qlist.qdoc
@@ -247,6 +247,31 @@
\sa resize()
*/
+/*! \fn template <typename T> QList<T>::QList(qsizetype size, Qt::Initialization)
+ \since 6.8
+
+ Constructs a list with an initial size of \a size elements.
+
+ QList will make an attempt at \b{not initializing} the elements.
+
+//! [qlist-uninitialized-strategy]
+ Specifically:
+
+ \list
+
+ \li if \c{T} has a constructor that accepts \c{Qt::Uninitialized},
+ that constructor will be used to initialize the elements;
+
+ \li otherwise, each element is default constructed. For
+ trivially constructible types (such as \c{int}, \c{float}, etc.)
+ this is equivalent to not initializing them.
+
+ \endlist
+//! [qlist-uninitialized-strategy]
+
+ \sa resizeForOverwrite()
+*/
+
/*! \fn template <typename T> QList<T>::QList(qsizetype size, parameter_type value)
Constructs a list with an initial size of \a size elements.
@@ -274,11 +299,15 @@
Constructs a list from the std::initializer_list given by \a args.
*/
-/*! \fn template <typename T> template<typename InputIterator> QList<T>::QList(InputIterator first, InputIterator last)
+/*! \fn template<typename T> template <typename InputIterator, QList<T>::if_input_iterator<InputIterator> = true> QList<T>::QList(InputIterator first, InputIterator last)
\since 5.14
Constructs a list with the contents in the iterator range [\a first, \a last).
+ \note This constructor only participates in overload resolution if
+ \c InputIterator meets the requirements of a
+ \l {https://en.cppreference.com/w/cpp/named_req/InputIterator} {LegacyInputIterator}.
+
The value type of \c InputIterator must be convertible to \c T.
*/
@@ -422,18 +451,35 @@
*/
/*! \fn template <typename T> void QList<T>::resize(qsizetype size)
+ \fn template <typename T> void QList<T>::resize(qsizetype size, parameter_type c)
+ \since 6.0
Sets the size of the list to \a size. If \a size is greater than the
current size, elements are added to the end; the new elements are
- initialized with a \l{default-constructed value}. If \a size is less
- than the current size, elements are removed from the end.
+ initialized with either a \l{default-constructed value} or \a c. If \a size
+ is less than the current size, elements are removed from the end.
- Since Qt 5.6, resize() doesn't shrink the capacity anymore.
- To shed excess capacity, use squeeze().
+ If this list is not shared, the capacity() is preserved. Use squeeze()
+ to shed excess capacity.
+
+ \note In Qt versions prior to 5.7 (for QVector; QList lacked a resize()
+ until 6.0), this function released the memory used by the list instead of
+ preserving the capacity.
\sa size()
*/
+/*! \fn template <typename T> void QList<T>::resizeForOverwrite(qsizetype size)
+ \since 6.8
+
+ Sets the size of the list to \a size. If \a size is less than the
+ current size, elements are removed from the end. If \a size is
+ greater than the current size, elements are added to the end; QList
+ will make an attempt at \b{not initializing} these new elements.
+
+ \include qlist.qdoc qlist-uninitialized-strategy
+*/
+
/*! \fn template <typename T> qsizetype QList<T>::capacity() const
Returns the maximum number of items that can be stored in the
@@ -1283,6 +1329,15 @@
returns \c false.
*/
+/*! \fn template <typename T> qsizetype QList<T>::max_size()
+ \since 6.8
+
+ This function is provided for STL compatibility.
+ It returns the maximum number of elements that the list can
+ theoretically hold. In practice, the number can be much smaller,
+ limited by the amount of memory available to the system.
+*/
+
/*! \fn template <typename T> QList<T> &QList<T>::operator+=(const QList<T> &other)
Appends the items of the \a other list to this list and
@@ -1528,3 +1583,47 @@
\sa erase
*/
+
+/*! \fn template <typename T> QList<T>& QList<T>::assign(qsizetype n, parameter_type t)
+ \since 6.6
+
+ Replaces the contents of this list with \a n copies of \a t.
+
+ The size of this list will be equal to \a n.
+
+ This function will only allocate memory if \a n exceeds the capacity of the
+ list or this list is shared.
+*/
+
+/*! \fn template <typename T> template <typename InputIterator, QList<T>::if_input_iterator<InputIterator>> QList<T>& QList<T>::assign(InputIterator first, InputIterator last)
+ \since 6.6
+
+ Replaces the contents of this list with a copy of the elements in the
+ iterator range [\a first, \a last).
+
+ The size of this list will be equal to the number of elements in the
+ range [\a first, \a last).
+
+ This function will only allocate memory if the number of elements in the
+ range exceeds the capacity of this list or this list is shared.
+
+ \note This function overload only participates in overload resolution if
+ \c InputIterator meets the requirements of a
+ \l {https://en.cppreference.com/w/cpp/named_req/InputIterator} {LegacyInputIterator}.
+
+ \note The behavior is undefined if either argument is an iterator into
+ *this.
+*/
+
+/*! \fn template <typename T> QList<T>& QList<T>::assign(std::initializer_list<T> l)
+ \since 6.6
+
+ Replaces the contents of this list with a copy of the elements of
+ \a l.
+
+ The size of this list will be equal to the number of elements in
+ \a l.
+
+ This function only allocates memory if the number of elements in \a l
+ exceeds the capacity of this list or this list is shared.
+*/
diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h
index 1a6506348f..7ee0be1e51 100644
--- a/src/corelib/tools/qmap.h
+++ b/src/corelib/tools/qmap.h
@@ -5,6 +5,7 @@
#ifndef QMAP_H
#define QMAP_H
+#include <QtCore/qhashfunctions.h>
#include <QtCore/qiterator.h>
#include <QtCore/qlist.h>
#include <QtCore/qrefcount.h>
@@ -762,7 +763,7 @@ public:
return isEmpty();
}
- QPair<iterator, iterator> equal_range(const Key &akey)
+ std::pair<iterator, iterator> equal_range(const Key &akey)
{
const auto copy = d.isShared() ? *this : QMap(); // keep `key` alive across the detach
detach();
@@ -770,13 +771,38 @@ public:
return {iterator(result.first), iterator(result.second)};
}
- QPair<const_iterator, const_iterator> equal_range(const Key &akey) const
+ std::pair<const_iterator, const_iterator> equal_range(const Key &akey) const
{
if (!d)
return {};
auto result = d->m.equal_range(akey);
return {const_iterator(result.first), const_iterator(result.second)};
}
+
+private:
+#ifdef Q_QDOC
+ friend size_t qHash(const QMap &key, size_t seed = 0);
+#else
+# if defined(Q_CC_GHS) || defined (Q_CC_MSVC)
+ // GHS and MSVC tries to intantiate qHash() for the noexcept running into a
+ // non-SFINAE'ed hard error... Create an artificial SFINAE context as a
+ // work-around:
+ template <typename M, std::enable_if_t<std::is_same_v<M, QMap>, bool> = true>
+ friend QtPrivate::QHashMultiReturnType<typename M::key_type, typename M::mapped_type>
+# else
+ using M = QMap;
+ friend size_t
+# endif
+ qHash(const M &key, size_t seed = 0)
+ noexcept(QHashPrivate::noexceptPairHash<typename M::key_type, typename M::mapped_type>())
+ {
+ if (!key.d)
+ return seed;
+ // don't use qHashRange to avoid its compile-time overhead:
+ return std::accumulate(key.d->m.begin(), key.d->m.end(), seed,
+ QtPrivate::QHashCombine{});
+ }
+#endif // !Q_QDOC
};
Q_DECLARE_ASSOCIATIVE_ITERATOR(Map)
@@ -788,6 +814,7 @@ qsizetype erase_if(QMap<Key, T> &map, Predicate pred)
return QtPrivate::associative_erase_if(map, pred);
}
+
//
// QMultiMap
//
@@ -1492,7 +1519,7 @@ public:
// STL compatibility
inline bool empty() const { return isEmpty(); }
- QPair<iterator, iterator> equal_range(const Key &akey)
+ std::pair<iterator, iterator> equal_range(const Key &akey)
{
const auto copy = d.isShared() ? *this : QMultiMap(); // keep `key` alive across the detach
detach();
@@ -1500,7 +1527,7 @@ public:
return {iterator(result.first), iterator(result.second)};
}
- QPair<const_iterator, const_iterator> equal_range(const Key &akey) const
+ std::pair<const_iterator, const_iterator> equal_range(const Key &akey) const
{
if (!d)
return {};
diff --git a/src/corelib/tools/qmap.qdoc b/src/corelib/tools/qmap.qdoc
index b8ce4224a3..0cabf3df38 100644
--- a/src/corelib/tools/qmap.qdoc
+++ b/src/corelib/tools/qmap.qdoc
@@ -1,6 +1,6 @@
// Copyright (C) 2020 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.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\class QMap
@@ -97,7 +97,7 @@
QMultiMap.
If you only need to extract the values from a map (not the keys),
- you can also use \l{foreach}:
+ you can also use range-based for:
\snippet code/src_corelib_tools_qmap.cpp 12
@@ -390,7 +390,7 @@
use that entails can be avoided by iterating from \l keyBegin() to
\l keyEnd().
- \sa QMultiMap::uniqueKeys(), values(), key()
+ \sa values(), key()
*/
/*! \fn template <class Key, class T> QList<Key> QMap<Key, T>::keys(const T &value) const
@@ -730,7 +730,7 @@
If there is already an item with the key \a key, that item's value
is replaced with \a value.
- \sa QMultiMap::insert()
+ Returns an iterator pointing to the new/updated element.
*/
/*! \fn template <class Key, class T> QMap<Key, T>::iterator QMap<Key, T>::insert(const_iterator pos, const Key &key, const T &value)
@@ -756,7 +756,7 @@
\b {Note:} Be careful with the hint. Providing an iterator from an older shared instance might
crash but there is also a risk that it will silently corrupt both the map and the \a pos map.
- \sa QMultiMap::insert()
+ Returns an iterator pointing to the new/updated element.
*/
/*! \fn template <class Key, class T> void QMap<Key, T>::insert(const QMap<Key, T> &map)
@@ -766,8 +766,6 @@
If a key is common to both maps, its value will be replaced with
the value stored in \a map.
-
- \sa QMultiMap::insert()
*/
/*! \fn template <class Key, class T> void QMap<Key, T>::insert(QMap<Key, T> &&map)
@@ -783,12 +781,12 @@
/*! \typedef QMap::Iterator
- Qt-style synonym for QMap<Key, T>::iterator.
+ Qt-style synonym for QMap::iterator.
*/
/*! \typedef QMap::ConstIterator
- Qt-style synonym for QMap<Key, T>::const_iterator.
+ Qt-style synonym for QMap::const_iterator.
*/
/*! \typedef QMap::difference_type
@@ -820,14 +818,14 @@
*/
/*!
- \fn template <class Key, class T> QPair<typename QMap<Key, T>::iterator, typename QMap<Key, T>::iterator> QMap<Key, T>::equal_range(const Key &key)
+ \fn template <class Key, class T> std::pair<typename QMap<Key, T>::iterator, typename QMap<Key, T>::iterator> QMap<Key, T>::equal_range(const Key &key)
Returns a pair of iterators delimiting the range of values \c{[first, second)}, that
are stored under \a key.
*/
/*!
- \fn template <class Key, class T> QPair<typename QMap<Key, T>::const_iterator, typename QMap<Key, T>::const_iterator> QMap<Key, T>::equal_range(const Key &key) const
+ \fn template <class Key, class T> std::pair<typename QMap<Key, T>::const_iterator, typename QMap<Key, T>::const_iterator> QMap<Key, T>::equal_range(const Key &key) const
\overload
\since 5.6
*/
@@ -837,12 +835,6 @@
\inmodule QtCore
\brief The QMap::iterator class provides an STL-style non-const iterator for QMap.
- QMap features both \l{STL-style iterators} and \l{Java-style
- iterators}. The STL-style iterators are more low-level and more
- cumbersome to use; on the other hand, they are slightly faster
- and, for developers who already know STL, have the advantage of
- familiarity.
-
QMap\<Key, T\>::iterator allows you to iterate over a QMap
and to modify the value (but not the key) stored under
a particular key. If you want to iterate over a const QMap, you
@@ -862,31 +854,15 @@
Unlike QHash, which stores its items in an arbitrary order, QMap
stores its items ordered by key.
- Let's see a few examples of things we can do with a
- QMap::iterator that we cannot do with a QMap::const_iterator.
Here's an example that increments every value stored in the QMap
by 2:
\snippet code/src_corelib_tools_qmap.cpp 19
- Here's an example that removes all the items whose key is a
- string that starts with an underscore character:
-
- \snippet code/src_corelib_tools_qmap.cpp 20
-
- The call to QMap::erase() removes the item pointed to by the
- iterator from the map, and returns an iterator to the next item.
- Here's another way of removing an item while iterating:
+ To remove elements from a QMap you can use erase_if(QMap\<Key, T\> &map, Predicate pred):
\snippet code/src_corelib_tools_qmap.cpp 21
- It might be tempting to write code like this:
-
- \snippet code/src_corelib_tools_qmap.cpp 22
-
- However, this will potentially crash in \c{++i}, because \c i is
- a dangling iterator after the call to erase().
-
Multiple iterators can be used on the same map. If you add items
to the map, existing iterators will remain valid. If you remove
items from the map, iterators that point to the removed items
@@ -897,7 +873,7 @@
while iterators are active on that container. For more information,
read \l{Implicit sharing iterator problem}.
- \sa QMap::const_iterator, QMap::key_iterator, QMutableMapIterator
+ \sa QMap::const_iterator, QMap::key_iterator, QMap::key_value_iterator
*/
/*! \typedef QMap::iterator::difference_type
@@ -1057,12 +1033,6 @@
\inmodule QtCore
\brief The QMap::const_iterator class provides an STL-style const iterator for QMap.
- QMap features both \l{STL-style iterators} and \l{Java-style
- iterators}. The STL-style iterators are more low-level and more
- cumbersome to use; on the other hand, they are slightly faster
- and, for developers who already know STL, have the advantage of
- familiarity.
-
QMap\<Key, T\>::const_iterator allows you to iterate over a QMap.
If you want to modify the QMap as you iterate
over it, you must use QMap::iterator instead. It is generally
@@ -1073,12 +1043,20 @@
The default QMap::const_iterator constructor creates an
uninitialized iterator. You must initialize it using a QMap
- function like QMap::constBegin(), QMap::constEnd(), or
- QMap::find() before you can start iterating. Here's a typical
+ function like QMap::cbegin(), QMap::cend(), or
+ QMap::constFind() before you can start iterating. Here's a typical
loop that prints all the (key, value) pairs stored in a map:
\snippet code/src_corelib_tools_qmap.cpp 24
+ Here's an example that removes all the items whose value is greater than 10:
+
+ \snippet code/src_corelib_tools_qmap.cpp 20
+
+ And here the same behavior with erase_if()
+
+ \snippet code/src_corelib_tools_qmap.cpp 21
+
Unlike QHash, which stores its items in an arbitrary order, QMap
stores its items ordered by key.
@@ -1092,7 +1070,7 @@
while iterators are active on that container. For more information,
read \l{Implicit sharing iterator problem}.
- \sa QMap::iterator, QMap::key_iterator, QMapIterator
+ \sa QMap::iterator, QMap::key_iterator, QMap::const_key_value_iterator
*/
/*! \typedef QMap::const_iterator::difference_type
@@ -1411,3 +1389,12 @@
Returns the number of elements removed, if any.
*/
+
+/*!
+ \fn template <class Key, class T> size_t QMap<Key, T>::qHash(const QMap &key, size_t seed) noexcept
+ \since 6.8
+
+ Returns the hash value for \a key, using \a seed to seed the calculation.
+
+ Types \c Key and \c T must be supported by qHash().
+*/
diff --git a/src/corelib/tools/qminimalflatset_p.h b/src/corelib/tools/qminimalflatset_p.h
new file mode 100644
index 0000000000..6074688f6e
--- /dev/null
+++ b/src/corelib/tools/qminimalflatset_p.h
@@ -0,0 +1,156 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTCORE_QMINIMALFLATSET_P_H
+#define QTCORE_QMINIMALFLATSET_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/qcontainerfwd.h>
+#include <QtCore/qfunctionaltools_impl.h> // CompactStorage
+#include <QtCore/private/qglobal_p.h>
+
+//#define QMINIMAL_FLAT_SET_DEBUG
+#ifdef QMINIMAL_FLAT_SET_DEBUG
+# include <QtCore/qscopeguard.h>
+# include <QtCore/qdebug.h>
+# define QMINIMAL_FLAT_SET_PRINT_AT_END \
+ const auto sg = qScopeGuard([&] { qDebug() << this << *this; });
+#else
+# define QMINIMAL_FLAT_SET_PRINT_AT_END
+#endif
+
+#include <algorithm> // for std::lower_bound
+#include <functional> // for std::less, std::ref
+
+QT_BEGIN_NAMESPACE
+
+/*
+ This is a minimal version of a QFlatSet, the std::set version of QFlatMap.
+ Like QFlatMap, it has linear insertion and removal, not logarithmic, like
+ real QMap and std::set, so it's only a good container if you either have
+ very few entries or lots, but with separate setup and lookup stages.
+ Because a full QFlatSet would be 10x the work on writing this minimal one,
+ we keep it here for now. When more users pop up and the class has matured a
+ bit, we can consider moving it as QFlatSet alongside QFlatMap.
+*/
+
+template <typename T, typename Container = QList<T>, typename Compare = std::less<T>>
+class QMinimalFlatSet : QtPrivate::CompactStorage<Compare>
+{
+ Container c;
+ using CompareStorage = QtPrivate::CompactStorage<Compare>;
+public:
+ QMinimalFlatSet() = default;
+ explicit QMinimalFlatSet(const Compare &cmp) : CompareStorage{cmp} {}
+ // Rule Of Zero applies
+
+ using const_iterator = typename Container::const_iterator;
+ using iterator = const_iterator;
+ using const_reverse_iterator = typename Container::const_reverse_iterator;
+ using reverse_iterator = const_reverse_iterator;
+ using value_type = T;
+ using key_compare = Compare;
+ using value_compare = Compare;
+
+ key_compare key_comp() const { return this->object(); }
+ value_compare value_comp() const { return key_comp(); }
+
+ iterator begin() const { return c.cbegin(); }
+ iterator end() const { return c.cend(); }
+ iterator cbegin() const { return begin(); }
+ iterator cend() const { return cend(); }
+
+ reverse_iterator rbegin() const { return c.crbegin(); }
+ reverse_iterator rend() const { return c.crend(); }
+ reverse_iterator crbegin() const { return rbegin(); }
+ reverse_iterator crend() const { return rend(); }
+
+ void clear() {
+ QMINIMAL_FLAT_SET_PRINT_AT_END
+ c.clear();
+ }
+ auto size() const { return c.size(); }
+ auto count() const { return size(); }
+ bool isEmpty() const { return size() == 0; }
+
+ std::pair<iterator, bool> insert(value_type &&v)
+ {
+ QMINIMAL_FLAT_SET_PRINT_AT_END
+ const auto r = lookup(v);
+ if (r.exists)
+ return {r.it, false};
+ else
+ return {c.insert(r.it, std::move(v)), true};
+ }
+
+ std::pair<iterator, bool> insert(const value_type &v)
+ {
+ QMINIMAL_FLAT_SET_PRINT_AT_END
+ const auto r = lookup(v);
+ if (r.exists)
+ return {r.it, false};
+ else
+ return {c.insert(r.it, v), true};
+ }
+
+ void erase(const value_type &v)
+ {
+ QMINIMAL_FLAT_SET_PRINT_AT_END
+ const auto r = lookup(v);
+ if (r.exists)
+ c.erase(r.it);
+ }
+ void remove(const value_type &v) { erase(v); }
+
+ bool contains(const value_type &v) const
+ {
+ return lookup(v).exists;
+ }
+
+ const Container &values() const & { return c; }
+ Container values() && { return std::move(c); }
+
+private:
+ auto lookup(const value_type &v) const
+ {
+ struct R {
+ iterator it;
+ bool exists;
+ };
+
+ auto cmp = std::ref(this->object()); // don't let std::lower_bound copy it
+
+ const auto it = std::lower_bound(c.cbegin(), c.cend(), v, cmp);
+ return R{it, it != c.cend() && !cmp(v, *it)};
+ }
+
+#ifdef QMINIMAL_FLAT_SET_DEBUG
+ friend QDebug operator<<(QDebug dbg, const QMinimalFlatSet &set)
+ {
+ const QDebugStateSaver saver(dbg);
+ dbg.nospace() << "QMinimalFlatSet{";
+ for (auto &e : set)
+ dbg << e << ", ";
+ return dbg << "}";
+ }
+#endif
+};
+
+#undef QMINIMAL_FLAT_SET_PRINT_AT_END
+
+template <typename T, qsizetype N = QVarLengthArrayDefaultPrealloc>
+using QMinimalVarLengthFlatSet = QMinimalFlatSet<T, QVarLengthArray<T, N>>;
+
+QT_END_NAMESPACE
+
+#endif // QTCORE_QMINIMALFLATSET_P_H
diff --git a/src/corelib/tools/qmultimap.qdoc b/src/corelib/tools/qmultimap.qdoc
index c4b073bd94..0b05192817 100644
--- a/src/corelib/tools/qmultimap.qdoc
+++ b/src/corelib/tools/qmultimap.qdoc
@@ -1,6 +1,6 @@
// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
// Copyright (C) 2020 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\class QMultiMap
@@ -92,7 +92,7 @@
\snippet code/src_corelib_tools_qmultimap.cpp 11
If you only need to extract the values from a map (not the keys),
- you can also use \l{foreach}:
+ you can also use range-based for:
\snippet code/src_corelib_tools_qmultimap.cpp 12
@@ -817,6 +817,8 @@
different from replace(), which overwrites the value of an
existing item.)
+ Returns an iterator pointing to the new element.
+
\sa replace()
*/
@@ -839,6 +841,8 @@
is faster than inserting in sorted order with constEnd(), since constEnd() - 1 (which is needed
to check if the hint is valid) needs \l{logarithmic time}.
+ Returns an iterator pointing to the new element.
+
\b {Note:} Be careful with the hint. Providing an iterator from an older shared instance might
crash but there is also a risk that it will silently corrupt both the multi map and the \a pos multi map.
*/
@@ -886,17 +890,19 @@
If there are multiple items with the key \a key, the most
recently inserted item's value is replaced with \a value.
+ Returns an iterator pointing to the new/updated element.
+
\sa insert()
*/
/*! \typedef QMultiMap::Iterator
- Qt-style synonym for QMultiMap<Key, T>::iterator.
+ Qt-style synonym for QMultiMap::iterator.
*/
/*! \typedef QMultiMap::ConstIterator
- Qt-style synonym for QMultiMap<Key, T>::const_iterator.
+ Qt-style synonym for QMultiMap::const_iterator.
*/
/*! \typedef QMultiMap::difference_type
@@ -928,14 +934,14 @@
*/
/*!
- \fn template <class Key, class T> QPair<typename QMultiMap<Key, T>::iterator, typename QMultiMap<Key, T>::iterator> QMultiMap<Key, T>::equal_range(const Key &key)
+ \fn template <class Key, class T> std::pair<typename QMultiMap<Key, T>::iterator, typename QMultiMap<Key, T>::iterator> QMultiMap<Key, T>::equal_range(const Key &key)
Returns a pair of iterators delimiting the range of values \c{[first, second)}, that
are stored under \a key.
*/
/*!
- \fn template <class Key, class T> QPair<typename QMultiMap<Key, T>::const_iterator, typename QMultiMap<Key, T>::const_iterator> QMultiMap<Key, T>::equal_range(const Key &key) const
+ \fn template <class Key, class T> std::pair<typename QMultiMap<Key, T>::const_iterator, typename QMultiMap<Key, T>::const_iterator> QMultiMap<Key, T>::equal_range(const Key &key) const
\overload
\since 5.6
*/
@@ -959,6 +965,7 @@
*/
/*! \fn template <class Key, class T> QMultiMap<Key, T> operator+=(QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs)
+ \relates QMultiMap
Inserts all the items in the \a rhs map into the \a lhs map and
returns the resulting map.
@@ -967,6 +974,7 @@
*/
/*! \fn template <class Key, class T> QMultiMap<Key, T> operator+(const QMultiMap<Key, T> &lhs, const QMultiMap<Key, T> &rhs)
+ \relates QMultiMap
Returns a map that contains all the items in the \a lhs map in
addition to all the items in \a rhs. If a key is common to both
@@ -979,12 +987,6 @@
\inmodule QtCore
\brief The QMultiMap::iterator class provides an STL-style non-const iterator for QMultiMap.
- QMultiMap features both \l{STL-style iterators} and \l{Java-style
- iterators}. The STL-style iterators are more low-level and more
- cumbersome to use; on the other hand, they are slightly faster
- and, for developers who already know STL, have the advantage of
- familiarity.
-
QMultiMap\<Key, T\>::iterator allows you to iterate over a QMultiMap
and to modify the value (but not the key) stored under
a particular key. If you want to iterate over a const QMultiMap, you
@@ -999,38 +1001,20 @@
start iterating. Here's a typical loop that prints all the (key,
value) pairs stored in a map:
- \snippet code/src_corelib_tools_qmultimap.cpp 18
-
Unlike QMultiHash, which stores its items in an arbitrary order, QMultiMap
stores its items ordered by key. Items that share the same key
will appear consecutively,
from the most recently to the least recently inserted value.
- Let's see a few examples of things we can do with a
- QMultiMap::iterator that we cannot do with a QMultiMap::const_iterator.
Here's an example that increments every value stored in the QMultiMap
by 2:
\snippet code/src_corelib_tools_qmultimap.cpp 19
- Here's an example that removes all the items whose key is a
- string that starts with an underscore character:
-
- \snippet code/src_corelib_tools_qmultimap.cpp 20
-
- The call to QMultiMap::erase() removes the item pointed to by the
- iterator from the map, and returns an iterator to the next item.
- Here's another way of removing an item while iterating:
+ To remove elements from a QMultiMap you can use erase_if(QMultiMap\<Key, T\> &map, Predicate pred):
\snippet code/src_corelib_tools_qmultimap.cpp 21
- It might be tempting to write code like this:
-
- \snippet code/src_corelib_tools_qmultimap.cpp 22
-
- However, this will potentially crash in \c{++i}, because \c i is
- a dangling iterator after the call to erase().
-
Multiple iterators can be used on the same map. If you add items
to the map, existing iterators will remain valid. If you remove
items from the map, iterators that point to the removed items
@@ -1041,7 +1025,7 @@
while iterators are active on that container. For more information,
read \l{Implicit sharing iterator problem}.
- \sa QMultiMap::const_iterator, QMultiMap::key_iterator, QMutableMultiMapIterator
+ \sa QMultiMap::const_iterator, QMultiMap::key_iterator, QMultiMap::key_value_iterator
*/
/*! \typedef QMultiMap::iterator::difference_type
@@ -1202,12 +1186,6 @@
\inmodule QtCore
\brief The QMultiMap::const_iterator class provides an STL-style const iterator for QMultiMap.
- QMultiMap features both \l{STL-style iterators} and \l{Java-style
- iterators}. The STL-style iterators are more low-level and more
- cumbersome to use; on the other hand, they are slightly faster
- and, for developers who already know STL, have the advantage of
- familiarity.
-
QMultiMap\<Key, T\>::const_iterator allows you to iterate over a QMultiMap.
If you want to modify the QMultiMap as you iterate
over it, you must use QMultiMap::iterator instead. It is generally
@@ -1218,12 +1196,16 @@
The default QMultiMap::const_iterator constructor creates an
uninitialized iterator. You must initialize it using a QMultiMap
- function like QMultiMap::constBegin(), QMultiMap::constEnd(), or
- QMultiMap::find() before you can start iterating. Here's a typical
+ function like QMultiMap::cbegin(), QMultiMap::cend(), or
+ QMultiMap::constFind() before you can start iterating. Here's a typical
loop that prints all the (key, value) pairs stored in a map:
\snippet code/src_corelib_tools_qmultimap.cpp 24
+ Here's an example that removes all the items whose value is greater than 10:
+
+ \snippet code/src_corelib_tools_qmultimap.cpp 20
+
Unlike QMultiHash, which stores its items in an arbitrary order, QMultiMap
stores its items ordered by key. Items that share the same key
will appear consecutively,
@@ -1239,7 +1221,7 @@
while iterators are active on that container. For more information,
read \l{Implicit sharing iterator problem}.
- \sa QMultiMap::iterator, QMultiMap::key_iterator, QMultiMapIterator
+ \sa QMultiMap::iterator, QMultiMap::key_iterator, QMultiMap::const_key_value_iterator
*/
/*! \typedef QMultiMap::const_iterator::difference_type
diff --git a/src/corelib/tools/qpair.h b/src/corelib/tools/qpair.h
index 8070ca0175..84f99075e1 100644
--- a/src/corelib/tools/qpair.h
+++ b/src/corelib/tools/qpair.h
@@ -4,6 +4,7 @@
#ifndef QPAIR_H
#define QPAIR_H
+#include <QtCore/qcontainerfwd.h>
#include <QtCore/qglobal.h>
QT_BEGIN_NAMESPACE
@@ -12,8 +13,7 @@ QT_BEGIN_NAMESPACE
#pragma qt_class(QPair)
#endif
-template <typename T1, typename T2>
-using QPair = std::pair<T1, T2>;
+#ifndef QT_NO_QPAIR
template <typename T1, typename T2>
constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2)
@@ -22,6 +22,8 @@ constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2)
return std::make_pair(std::forward<T1>(value1), std::forward<T2>(value2));
}
+#endif // QT_NO_QPAIR
+
QT_END_NAMESPACE
#endif // QPAIR_H
diff --git a/src/corelib/tools/qringbuffer.cpp b/src/corelib/tools/qringbuffer.cpp
index ea4224eefe..0645759118 100644
--- a/src/corelib/tools/qringbuffer.cpp
+++ b/src/corelib/tools/qringbuffer.cpp
@@ -3,7 +3,6 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "private/qringbuffer_p.h"
-#include "private/qbytearray_p.h"
#include <type_traits>
@@ -91,7 +90,7 @@ void QRingBuffer::free(qint64 bytes)
clear(); // try to minify/squeeze us
}
} else {
- Q_ASSERT(bytes < MaxByteArraySize);
+ Q_ASSERT(bytes < QByteArray::max_size());
chunk.advance(bytes);
bufferSize -= bytes;
}
@@ -106,7 +105,7 @@ void QRingBuffer::free(qint64 bytes)
char *QRingBuffer::reserve(qint64 bytes)
{
- Q_ASSERT(bytes > 0 && bytes < MaxByteArraySize);
+ Q_ASSERT(bytes > 0 && bytes < QByteArray::max_size());
const qsizetype chunkSize = qMax(qint64(basicBlockSize), bytes);
qsizetype tail = 0;
@@ -136,7 +135,7 @@ char *QRingBuffer::reserve(qint64 bytes)
*/
char *QRingBuffer::reserveFront(qint64 bytes)
{
- Q_ASSERT(bytes > 0 && bytes < MaxByteArraySize);
+ Q_ASSERT(bytes > 0 && bytes < QByteArray::max_size());
const qsizetype chunkSize = qMax(qint64(basicBlockSize), bytes);
if (bufferSize == 0) {
@@ -182,7 +181,7 @@ void QRingBuffer::chop(qint64 bytes)
clear(); // try to minify/squeeze us
}
} else {
- Q_ASSERT(bytes < MaxByteArraySize);
+ Q_ASSERT(bytes < QByteArray::max_size());
chunk.grow(-bytes);
bufferSize -= bytes;
}
diff --git a/src/corelib/tools/qscopedpointer.cpp b/src/corelib/tools/qscopedpointer.cpp
index 28cc39ae5d..515eb9dc75 100644
--- a/src/corelib/tools/qscopedpointer.cpp
+++ b/src/corelib/tools/qscopedpointer.cpp
@@ -269,7 +269,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn template <typename T, typename Cleanup> template <typename D> QScopedArrayPointer<T, Cleanup>::QScopedArrayPointer(D * p)
+ \fn template <typename T, typename Cleanup> template <typename D, QScopedArrayPointer<T, Cleanup>::if_same_type<D> = true> QScopedArrayPointer<T, Cleanup>::QScopedArrayPointer(D * p)
Constructs a QScopedArrayPointer and stores the array of objects
pointed to by \a p.
diff --git a/src/corelib/tools/qscopedpointer.h b/src/corelib/tools/qscopedpointer.h
index 1637bb40a5..59bae9b967 100644
--- a/src/corelib/tools/qscopedpointer.h
+++ b/src/corelib/tools/qscopedpointer.h
@@ -67,9 +67,10 @@ typedef QScopedPointerObjectDeleteLater<QObject> QScopedPointerDeleteLater;
#endif
template <typename T, typename Cleanup = QScopedPointerDeleter<T> >
-class [[nodiscard]] QScopedPointer
+class QScopedPointer
{
public:
+ Q_NODISCARD_CTOR
explicit QScopedPointer(T *p = nullptr) noexcept : d(p)
{
}
@@ -187,15 +188,17 @@ private:
};
template <typename T, typename Cleanup = QScopedPointerArrayDeleter<T> >
-class [[nodiscard]] QScopedArrayPointer : public QScopedPointer<T, Cleanup>
+class QScopedArrayPointer : public QScopedPointer<T, Cleanup>
{
template <typename Ptr>
using if_same_type = typename std::enable_if<std::is_same<typename std::remove_cv<T>::type, Ptr>::value, bool>::type;
public:
+ Q_NODISCARD_CTOR
inline QScopedArrayPointer() : QScopedPointer<T, Cleanup>(nullptr) {}
inline ~QScopedArrayPointer() = default;
template <typename D, if_same_type<D> = true>
+ Q_NODISCARD_CTOR
explicit QScopedArrayPointer(D *p)
: QScopedPointer<T, Cleanup>(p)
{
diff --git a/src/corelib/tools/qscopedvaluerollback.h b/src/corelib/tools/qscopedvaluerollback.h
index 53a31e4675..0ae3efd0c0 100644
--- a/src/corelib/tools/qscopedvaluerollback.h
+++ b/src/corelib/tools/qscopedvaluerollback.h
@@ -9,14 +9,16 @@
QT_BEGIN_NAMESPACE
template <typename T>
-class [[nodiscard]] QScopedValueRollback
+class QScopedValueRollback
{
public:
+ Q_NODISCARD_CTOR
explicit constexpr QScopedValueRollback(T &var)
: varRef(var), oldValue(var)
{
}
+ Q_NODISCARD_CTOR
explicit constexpr QScopedValueRollback(T &var, T value)
: varRef(var), oldValue(std::move(var)) // ### C++20: std::exchange(var, std::move(value))
{
diff --git a/src/corelib/tools/qscopeguard.h b/src/corelib/tools/qscopeguard.h
index 5bd202ce33..9be6634cc8 100644
--- a/src/corelib/tools/qscopeguard.h
+++ b/src/corelib/tools/qscopeguard.h
@@ -13,19 +13,22 @@
QT_BEGIN_NAMESPACE
template <typename F>
-class [[nodiscard]] QScopeGuard
+class QScopeGuard
{
public:
+ Q_NODISCARD_CTOR
explicit QScopeGuard(F &&f) noexcept
: m_func(std::move(f))
{
}
+ Q_NODISCARD_CTOR
explicit QScopeGuard(const F &f) noexcept
: m_func(f)
{
}
+ Q_NODISCARD_CTOR
QScopeGuard(QScopeGuard &&other) noexcept
: m_func(std::move(other.m_func))
, m_invoke(std::exchange(other.m_invoke, false))
diff --git a/src/corelib/tools/qset.h b/src/corelib/tools/qset.h
index cdd9ceda20..7330b5e91c 100644
--- a/src/corelib/tools/qset.h
+++ b/src/corelib/tools/qset.h
@@ -189,14 +189,18 @@ public:
inline QSet<T> &operator+=(const T &value) { insert(value); return *this; }
inline QSet<T> &operator-=(const QSet<T> &other) { subtract(other); return *this; }
inline QSet<T> &operator-=(const T &value) { remove(value); return *this; }
- inline QSet<T> operator|(const QSet<T> &other) const
- { QSet<T> result = *this; result |= other; return result; }
- inline QSet<T> operator&(const QSet<T> &other) const
- { QSet<T> result = *this; result &= other; return result; }
- inline QSet<T> operator+(const QSet<T> &other) const
- { QSet<T> result = *this; result += other; return result; }
- inline QSet<T> operator-(const QSet<T> &other) const
- { QSet<T> result = *this; result -= other; return result; }
+
+ friend QSet operator|(const QSet &lhs, const QSet &rhs) { return QSet(lhs) |= rhs; }
+ friend QSet operator|(QSet &&lhs, const QSet &rhs) { lhs |= rhs; return std::move(lhs); }
+
+ friend QSet operator&(const QSet &lhs, const QSet &rhs) { return QSet(lhs) &= rhs; }
+ friend QSet operator&(QSet &&lhs, const QSet &rhs) { lhs &= rhs; return std::move(lhs); }
+
+ friend QSet operator+(const QSet &lhs, const QSet &rhs) { return QSet(lhs) += rhs; }
+ friend QSet operator+(QSet &&lhs, const QSet &rhs) { lhs += rhs; return std::move(lhs); }
+
+ friend QSet operator-(const QSet &lhs, const QSet &rhs) { return QSet(lhs) -= rhs; }
+ friend QSet operator-(QSet &&lhs, const QSet &rhs) { lhs -= rhs; return std::move(lhs); }
QList<T> values() const;
@@ -224,10 +228,13 @@ Q_INLINE_TEMPLATE void QSet<T>::reserve(qsizetype asize) { q_hash.reserve(asize)
template <class T>
Q_INLINE_TEMPLATE QSet<T> &QSet<T>::unite(const QSet<T> &other)
{
- if (!q_hash.isSharedWith(other.q_hash)) {
- for (const T &e : other)
- insert(e);
- }
+ if (q_hash.isSharedWith(other.q_hash))
+ return *this;
+ QSet<T> tmp = other;
+ if (size() < other.size())
+ swap(tmp);
+ for (const auto &e : std::as_const(tmp))
+ insert(e);
return *this;
}
diff --git a/src/corelib/tools/qset.qdoc b/src/corelib/tools/qset.qdoc
index 47153e1349..4ef7a80a52 100644
--- a/src/corelib/tools/qset.qdoc
+++ b/src/corelib/tools/qset.qdoc
@@ -46,7 +46,7 @@
QSet is unordered, so an iterator's sequence cannot be assumed to
be predictable. If ordering by key is required, use a QMap.
- To navigate through a QSet, you can also use \l{foreach}:
+ To navigate through a QSet, you can also use range-based for:
\snippet code/doc_src_qset.cpp 6
@@ -86,7 +86,7 @@
initializer list \a list.
*/
-/*! \fn template <class T> template<typename InputIterator> QSet<T>::QSet(InputIterator first, InputIterator last)
+/*! \fn template <class T> template <typename InputIterator, QtPrivate::IfIsInputIterator<InputIterator> = true> QSet<T>::QSet(InputIterator first, InputIterator last)
\since 5.14
Constructs a set with the contents in the iterator range [\a first, \a last).
@@ -435,7 +435,7 @@
*/
/*!
- \fn template <class T> QSet<T>::insert(const T &value)
+ \fn template <class T> QSet<T>::iterator QSet<T>::insert(const T &value)
Inserts item \a value into the set, if \a value isn't already
in the set, and returns an iterator pointing at the inserted
@@ -567,29 +567,30 @@
*/
/*!
- \fn template <class T> QSet<T> QSet<T>::operator|(const QSet<T> &other) const
- \fn template <class T> QSet<T> QSet<T>::operator+(const QSet<T> &other) const
+ \fn template <class T> QSet<T> QSet<T>::operator|(const QSet &lhs, const QSet &rhs)
+ \fn template <class T> QSet<T> QSet<T>::operator|(QSet &&lhs, const QSet &rhs)
+ \fn template <class T> QSet<T> QSet<T>::operator+(const QSet &lhs, const QSet &rhs)
+ \fn template <class T> QSet<T> QSet<T>::operator+(QSet &&lhs, const QSet &rhs)
- Returns a new QSet that is the union of this set and the
- \a other set.
+ Returns a new QSet that is the union of sets \a lhs and \a rhs.
\sa unite(), operator|=(), operator&(), operator-()
*/
/*!
- \fn template <class T> QSet<T> QSet<T>::operator&(const QSet<T> &other) const
+ \fn template <class T> QSet<T> QSet<T>::operator&(const QSet &lhs, const QSet &rhs)
+ \fn template <class T> QSet<T> QSet<T>::operator&(QSet &&lhs, const QSet &rhs)
- Returns a new QSet that is the intersection of this set and the
- \a other set.
+ Returns a new QSet that is the intersection of sets \a lhs and \a rhs.
\sa intersect(), operator&=(), operator|(), operator-()
*/
/*!
- \fn template <class T> QSet<T> QSet<T>::operator-(const QSet<T> &other) const
+ \fn template <class T> QSet<T> QSet<T>::operator-(const QSet &lhs, const QSet &rhs)
+ \fn template <class T> QSet<T> QSet<T>::operator-(QSet &&lhs, const QSet &rhs)
- Returns a new QSet that is the set difference of this set and
- the \a other set, i.e., this set - \a other set.
+ Returns a new QSet that is the set difference of sets \a lhs and \a rhs.
\sa subtract(), operator-=(), operator|(), operator&()
*/
@@ -886,3 +887,10 @@
from the set \a set. Returns the number of elements removed, if
any.
*/
+
+/*! \fn template <class T> template <class Pred> qsizetype QSet<T>::removeIf(Pred pred)
+ \since 6.1
+
+ Removes, from this set, all elements for which the predicate \a pred
+ returns \c true. Returns the number of elements removed, if any.
+*/
diff --git a/src/corelib/tools/qshareddata.h b/src/corelib/tools/qshareddata.h
index 826152b63a..4c4153a506 100644
--- a/src/corelib/tools/qshareddata.h
+++ b/src/corelib/tools/qshareddata.h
@@ -51,13 +51,17 @@ public:
const T *constData() const noexcept { return d; }
T *take() noexcept { return std::exchange(d, nullptr); }
+ Q_NODISCARD_CTOR
QSharedDataPointer() noexcept : d(nullptr) { }
~QSharedDataPointer() { if (d && !d->ref.deref()) delete d; }
+ Q_NODISCARD_CTOR
explicit QSharedDataPointer(T *data) noexcept : d(data)
{ if (d) d->ref.ref(); }
+ Q_NODISCARD_CTOR
QSharedDataPointer(T *data, QAdoptSharedDataTag) noexcept : d(data)
{}
+ Q_NODISCARD_CTOR
QSharedDataPointer(const QSharedDataPointer &o) noexcept : d(o.d)
{ if (d) d->ref.ref(); }
@@ -82,6 +86,7 @@ public:
reset(o);
return *this;
}
+ Q_NODISCARD_CTOR
QSharedDataPointer(QSharedDataPointer &&o) noexcept : d(std::exchange(o.d, nullptr)) {}
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QSharedDataPointer)
@@ -139,17 +144,22 @@ public:
void detach() { if (d && d->ref.loadRelaxed() != 1) detach_helper(); }
+ Q_NODISCARD_CTOR
QExplicitlySharedDataPointer() noexcept : d(nullptr) { }
~QExplicitlySharedDataPointer() { if (d && !d->ref.deref()) delete d; }
+ Q_NODISCARD_CTOR
explicit QExplicitlySharedDataPointer(T *data) noexcept : d(data)
{ if (d) d->ref.ref(); }
+ Q_NODISCARD_CTOR
QExplicitlySharedDataPointer(T *data, QAdoptSharedDataTag) noexcept : d(data)
{}
+ Q_NODISCARD_CTOR
QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer &o) noexcept : d(o.d)
{ if (d) d->ref.ref(); }
template<typename X>
+ Q_NODISCARD_CTOR
QExplicitlySharedDataPointer(const QExplicitlySharedDataPointer<X> &o) noexcept
#ifdef QT_ENABLE_QEXPLICITLYSHAREDDATAPOINTER_STATICCAST
: d(static_cast<T *>(o.data()))
@@ -179,6 +189,7 @@ public:
reset(o);
return *this;
}
+ Q_NODISCARD_CTOR
QExplicitlySharedDataPointer(QExplicitlySharedDataPointer &&o) noexcept : d(std::exchange(o.d, nullptr)) {}
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QExplicitlySharedDataPointer)
diff --git a/src/corelib/tools/qsharedpointer.cpp b/src/corelib/tools/qsharedpointer.cpp
index 7ed3847182..217a3a4ff4 100644
--- a/src/corelib/tools/qsharedpointer.cpp
+++ b/src/corelib/tools/qsharedpointer.cpp
@@ -139,8 +139,7 @@
can also exceptionally be -1, indicating that there are no QSharedPointers
attached to an object, which is tracked too. The only case where this is
possible is that of QWeakPointers and QPointers tracking a QObject. Note
- that QWeakPointers tracking a QObject is a deprecated feature as of Qt 5.0,
- kept only for compatibility with Qt 4.x.
+ that QWeakPointers tracking a QObject is deprecated.
The weak reference count controls the lifetime of the d-pointer itself.
It can be thought of as an internal/intrusive reference count for
@@ -175,7 +174,7 @@
last QSharedPointer instance had.
This class is never instantiated directly: the constructors and
- destructor are private and, in C++11, deleted. Only the create() function
+ destructor are deleted. Only the create() function
may be called to return an object of this type. See below for construction
details.
@@ -214,8 +213,7 @@
Like ExternalRefCountWithCustomDeleter, this class is never instantiated
directly. This class also provides a create() member that returns the
- pointer, and hides its constructors and destructor. With C++11, they're
- deleted.
+ pointer, and deletes its constructors and destructor.
The size of this class depends on the size of \tt T.
@@ -711,6 +709,49 @@
*/
/*!
+ \fn template <class T> template <class X> bool QSharedPointer<T>::owner_before(const QSharedPointer<X> &other) const noexcept
+ \fn template <class T> template <class X> bool QSharedPointer<T>::owner_before(const QWeakPointer<X> &other) const noexcept
+ \fn template <class T> template <class X> bool QWeakPointer<T>::owner_before(const QSharedPointer<X> &other) const noexcept
+ \fn template <class T> template <class X> bool QWeakPointer<T>::owner_before(const QWeakPointer<X> &other) const noexcept
+ \since 6.7
+
+ Returns \c true if and only if this smart pointer precedes \a other
+ in an implementation-defined owner-based ordering. The ordering is such
+ that two smart pointers are considered equivalent if they are both
+ empty or if they both own the same object (even if their apparent type
+ and pointer are different).
+
+ \sa owner_equal
+*/
+
+/*!
+ \fn template <class T> template <class X> bool QSharedPointer<T>::owner_equal(const QSharedPointer<X> &other) const noexcept
+ \fn template <class T> template <class X> bool QSharedPointer<T>::owner_equal(const QWeakPointer<X> &other) const noexcept
+ \fn template <class T> template <class X> bool QWeakPointer<T>::owner_equal(const QSharedPointer<X> &other) const noexcept
+ \fn template <class T> template <class X> bool QWeakPointer<T>::owner_equal(const QWeakPointer<X> &other) const noexcept
+
+ \since 6.7
+
+ Returns \c true if and only if this smart pointer and \a other
+ share ownership.
+
+ \sa owner_before, owner_hash
+*/
+
+/*!
+ \fn template <class T> size_t QSharedPointer<T>::owner_hash() const noexcept
+ \fn template <class T> size_t QWeakPointer<T>::owner_hash() const noexcept
+
+ \since 6.7
+
+ Returns a owner-based hash value for this smart pointer object.
+ Smart pointers that compare equal (as per \c{owner_equal}) will
+ have an identical owner-based hash.
+
+ \sa owner_equal
+*/
+
+/*!
\fn template <class T> QWeakPointer<T>::QWeakPointer()
Creates a QWeakPointer that points to nothing.
@@ -945,7 +986,7 @@
*/
/*!
- \fn template <class T> template <class X> bool operator==(const QSharedPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
+ \fn template<class T, class X> bool operator==(const QSharedPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
\relates QSharedPointer
Returns \c true if \a ptr1 and \a ptr2 refer to the same pointer.
@@ -958,7 +999,7 @@
*/
/*!
- \fn template <class T> template <class X> bool operator!=(const QSharedPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
+ \fn template<class T, class X> bool operator!=(const QSharedPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
\relates QSharedPointer
Returns \c true if \a ptr1 and \a ptr2 refer to distinct pointers.
@@ -971,7 +1012,7 @@
*/
/*!
- \fn template <class T> template <class X> bool operator==(const QSharedPointer<T> &ptr1, const X *ptr2)
+ \fn template<class T, class X> bool operator==(const QSharedPointer<T> &ptr1, const X *ptr2)
\relates QSharedPointer
Returns \c true if \a ptr1 and \a ptr2 refer to the same pointer.
@@ -984,7 +1025,7 @@
*/
/*!
- \fn template <class T> template <class X> bool operator!=(const QSharedPointer<T> &ptr1, const X *ptr2)
+ \fn template<class T, class X> bool operator!=(const QSharedPointer<T> &ptr1, const X *ptr2)
\relates QSharedPointer
Returns \c true if \a ptr1 and \a ptr2 refer to distinct pointers.
@@ -997,7 +1038,7 @@
*/
/*!
- \fn template <class T> template <class X> bool operator==(const T *ptr1, const QSharedPointer<X> &ptr2)
+ \fn template<class T, class X> bool operator==(const T *ptr1, const QSharedPointer<X> &ptr2)
\relates QSharedPointer
Returns \c true if the pointer \a ptr1 is the
@@ -1011,7 +1052,7 @@
*/
/*!
- \fn template <class T> template <class X> bool operator!=(const T *ptr1, const QSharedPointer<X> &ptr2)
+ \fn template<class T, class X> bool operator!=(const T *ptr1, const QSharedPointer<X> &ptr2)
\relates QSharedPointer
Returns \c true if the pointer \a ptr1 is not the
@@ -1025,7 +1066,7 @@
*/
/*!
- \fn template <class T> template <class X> bool operator==(const QSharedPointer<T> &ptr1, const QWeakPointer<X> &ptr2)
+ \fn template<class T, class X> bool operator==(const QSharedPointer<T> &ptr1, const QWeakPointer<X> &ptr2)
\relates QWeakPointer
Returns \c true if \a ptr1 and \a ptr2 refer to the same pointer.
@@ -1038,7 +1079,7 @@
*/
/*!
- \fn template <class T> template <class X> bool operator!=(const QSharedPointer<T> &ptr1, const QWeakPointer<X> &ptr2)
+ \fn template<class T, class X> bool operator!=(const QSharedPointer<T> &ptr1, const QWeakPointer<X> &ptr2)
\relates QWeakPointer
Returns \c true if \a ptr1 and \a ptr2 refer to distinct pointers.
@@ -1051,7 +1092,7 @@
*/
/*!
- \fn template <class T> template <class X> bool operator==(const QWeakPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
+ \fn template<class T, class X> bool operator==(const QWeakPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
\relates QWeakPointer
Returns \c true if \a ptr1 and \a ptr2 refer to the same pointer.
@@ -1144,7 +1185,7 @@
*/
/*!
- \fn template <class T> template <class X> bool operator!=(const QWeakPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
+ \fn template<class T, class X> bool operator!=(const QWeakPointer<T> &ptr1, const QSharedPointer<X> &ptr2)
\relates QWeakPointer
Returns \c true if \a ptr1 and \a ptr2 refer to distinct pointers.
@@ -1157,7 +1198,7 @@
*/
/*!
- \fn template <class X> template <class T> QSharedPointer<X> qSharedPointerCast(const QSharedPointer<T> &other)
+ \fn template <class X, class T> QSharedPointer<X> qSharedPointerCast(const QSharedPointer<T> &other)
\relates QSharedPointer
Returns a shared pointer to the pointer held by \a other, cast to
@@ -1172,7 +1213,7 @@
*/
/*!
- \fn template <class X> template <class T> QSharedPointer<X> qSharedPointerCast(const QWeakPointer<T> &other)
+ \fn template <class X, class T> QSharedPointer<X> qSharedPointerCast(const QWeakPointer<T> &other)
\relates QSharedPointer
\relates QWeakPointer
@@ -1193,7 +1234,7 @@
*/
/*!
- \fn template <class X> template <class T> QSharedPointer<X> qSharedPointerDynamicCast(const QSharedPointer<T> &src)
+ \fn template <class X, class T> QSharedPointer<X> qSharedPointerDynamicCast(const QSharedPointer<T> &src)
\relates QSharedPointer
Returns a shared pointer to the pointer held by \a src, using a
@@ -1209,7 +1250,7 @@
*/
/*!
- \fn template <class X> template <class T> QSharedPointer<X> qSharedPointerDynamicCast(const QWeakPointer<T> &src)
+ \fn template <class X, class T> QSharedPointer<X> qSharedPointerDynamicCast(const QWeakPointer<T> &src)
\relates QSharedPointer
\relates QWeakPointer
@@ -1231,7 +1272,7 @@
*/
/*!
- \fn template <class X> template <class T> QSharedPointer<X> qSharedPointerConstCast(const QSharedPointer<T> &src)
+ \fn template <class X, class T> QSharedPointer<X> qSharedPointerConstCast(const QSharedPointer<T> &src)
\relates QSharedPointer
Returns a shared pointer to the pointer held by \a src, cast to
@@ -1243,7 +1284,7 @@
*/
/*!
- \fn template <class X> template <class T> QSharedPointer<X> qSharedPointerConstCast(const QWeakPointer<T> &src)
+ \fn template <class X, class T> QSharedPointer<X> qSharedPointerConstCast(const QWeakPointer<T> &src)
\relates QSharedPointer
\relates QWeakPointer
@@ -1261,7 +1302,7 @@
*/
/*!
- \fn template <class X> template <class T> QSharedPointer<X> qSharedPointerObjectCast(const QSharedPointer<T> &src)
+ \fn template <class X, class T> QSharedPointer<X> qSharedPointerObjectCast(const QSharedPointer<T> &src)
\relates QSharedPointer
\since 4.6
@@ -1333,7 +1374,7 @@
*/
/*!
- \fn template <class X> template <class T> QSharedPointer<X> qSharedPointerObjectCast(const QWeakPointer<T> &src)
+ \fn template <class X, class T> QSharedPointer<X> qSharedPointerObjectCast(const QWeakPointer<T> &src)
\relates QSharedPointer
\relates QWeakPointer
\since 4.6
@@ -1359,7 +1400,7 @@
/*!
- \fn template <class X> template <class T> QWeakPointer<X> qWeakPointerCast(const QWeakPointer<T> &src)
+ \fn template <class X, class T> QWeakPointer<X> qWeakPointerCast(const QWeakPointer<T> &src)
\relates QWeakPointer
Returns a weak pointer to the pointer held by \a src, cast to
@@ -1379,6 +1420,7 @@
QT_BEGIN_NAMESPACE
+QT6_ONLY(
/*!
\internal
This function is called for a just-created QObject \a obj, to enable
@@ -1386,7 +1428,9 @@ QT_BEGIN_NAMESPACE
*/
void QtSharedPointer::ExternalRefCountData::setQObjectShared(const QObject *, bool)
{}
+)
+QT6_ONLY(
/*!
\internal
This function is called when a QSharedPointer is created from a QWeakPointer
@@ -1399,6 +1443,7 @@ void QtSharedPointer::ExternalRefCountData::checkQObjectShared(const QObject *)
if (strongref.loadRelaxed() < 0)
qWarning("QSharedPointer: cannot create a QSharedPointer from a QObject-tracking QWeakPointer");
}
+)
QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::getAndRef(const QObject *obj)
{
diff --git a/src/corelib/tools/qsharedpointer.h b/src/corelib/tools/qsharedpointer.h
index 2a60f3ca5e..116c9afa00 100644
--- a/src/corelib/tools/qsharedpointer.h
+++ b/src/corelib/tools/qsharedpointer.h
@@ -72,6 +72,19 @@ public:
template <typename... Args>
static inline QSharedPointer<T> create(Args &&... args);
+
+ // owner-based comparisons
+ template <typename X>
+ bool owner_before(const QSharedPointer<X> &other) const noexcept;
+ template <typename X>
+ bool owner_before(const QWeakPointer<X> &other) const noexcept;
+
+ template <typename X>
+ bool owner_equal(const QSharedPointer<X> &other) const noexcept;
+ template <typename X>
+ bool owner_equal(const QWeakPointer<X> &other) const noexcept;
+
+ size_t owner_hash() const noexcept;
};
template <class T>
@@ -108,6 +121,19 @@ public:
QSharedPointer<T> toStrongRef() const;
QSharedPointer<T> lock() const;
+
+ // owner-based comparisons
+ template <typename X>
+ bool owner_before(const QWeakPointer<X> &other) const noexcept;
+ template <typename X>
+ bool owner_before(const QSharedPointer<X> &other) const noexcept;
+
+ template <typename X>
+ bool owner_equal(const QWeakPointer<X> &other) const noexcept;
+ template <typename X>
+ bool owner_equal(const QSharedPointer<X> &other) const noexcept;
+
+ size_t owner_hash() const noexcept;
};
template <class T>
diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h
index dd6bd22fca..456be91d03 100644
--- a/src/corelib/tools/qsharedpointer_impl.h
+++ b/src/corelib/tools/qsharedpointer_impl.h
@@ -28,6 +28,7 @@ QT_END_NAMESPACE
#include <QtCore/qatomic.h>
#include <QtCore/qhashfunctions.h>
#include <QtCore/qmetatype.h> // for IsPointerToTypeDerivedFromQObject
+#include <QtCore/qxptype_traits.h>
#include <memory>
@@ -115,8 +116,10 @@ namespace QtSharedPointer {
#ifndef QT_NO_QOBJECT
Q_CORE_EXPORT static ExternalRefCountData *getAndRef(const QObject *);
+ QT6_ONLY(
Q_CORE_EXPORT void setQObjectShared(const QObject *, bool enable);
- Q_CORE_EXPORT void checkQObjectShared(const QObject *);
+ )
+ QT6_ONLY(Q_CORE_EXPORT void checkQObjectShared(const QObject *);)
#endif
inline void checkQObjectShared(...) { }
inline void setQObjectShared(...) { }
@@ -276,23 +279,29 @@ public:
T &operator*() const { return *data(); }
T *operator->() const noexcept { return data(); }
+ Q_NODISCARD_CTOR
constexpr QSharedPointer() noexcept : value(nullptr), d(nullptr) { }
~QSharedPointer() { deref(); }
+ Q_NODISCARD_CTOR
constexpr QSharedPointer(std::nullptr_t) noexcept : value(nullptr), d(nullptr) { }
template <class X, IfCompatible<X> = true>
+ Q_NODISCARD_CTOR
inline explicit QSharedPointer(X *ptr) : value(ptr) // noexcept
{ internalConstruct(ptr, QtSharedPointer::NormalDeleter()); }
template <class X, typename Deleter, IfCompatible<X> = true>
+ Q_NODISCARD_CTOR
inline QSharedPointer(X *ptr, Deleter deleter) : value(ptr) // throws
{ internalConstruct(ptr, deleter); }
template <typename Deleter>
+ Q_NODISCARD_CTOR
QSharedPointer(std::nullptr_t, Deleter deleter) : value(nullptr)
{ internalConstruct(static_cast<T *>(nullptr), deleter); }
+ Q_NODISCARD_CTOR
QSharedPointer(const QSharedPointer &other) noexcept : value(other.value), d(other.d)
{ if (d) ref(); }
QSharedPointer &operator=(const QSharedPointer &other) noexcept
@@ -301,6 +310,7 @@ public:
swap(copy);
return *this;
}
+ Q_NODISCARD_CTOR
QSharedPointer(QSharedPointer &&other) noexcept
: value(other.value), d(other.d)
{
@@ -310,6 +320,7 @@ public:
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QSharedPointer)
template <class X, IfCompatible<X> = true>
+ Q_NODISCARD_CTOR
QSharedPointer(QSharedPointer<X> &&other) noexcept
: value(other.value), d(other.d)
{
@@ -326,6 +337,7 @@ public:
}
template <class X, IfCompatible<X> = true>
+ Q_NODISCARD_CTOR
QSharedPointer(const QSharedPointer<X> &other) noexcept : value(other.value), d(other.d)
{ if (d) ref(); }
@@ -338,6 +350,7 @@ public:
}
template <class X, IfCompatible<X> = true>
+ Q_NODISCARD_CTOR
inline QSharedPointer(const QWeakPointer<X> &other) : value(nullptr), d(nullptr)
{ *this = other; }
@@ -383,10 +396,10 @@ public:
inline void clear() { QSharedPointer copy; swap(copy); }
- QWeakPointer<T> toWeakRef() const;
+ [[nodiscard]] QWeakPointer<T> toWeakRef() const;
template <typename... Args>
- static QSharedPointer create(Args && ...arguments)
+ [[nodiscard]] static QSharedPointer create(Args && ...arguments)
{
typedef QtSharedPointer::ExternalRefCountWithContiguousData<T> Private;
# ifdef QT_SHAREDPOINTER_TRACK_POINTERS
@@ -433,7 +446,25 @@ public:
#undef DECLARE_TEMPLATE_COMPARE_SET
#undef DECLARE_COMPARE_SET
+ template <typename X>
+ bool owner_before(const QSharedPointer<X> &other) const noexcept
+ { return std::less<>()(d, other.d); }
+ template <typename X>
+ bool owner_before(const QWeakPointer<X> &other) const noexcept
+ { return std::less<>()(d, other.d); }
+
+ template <typename X>
+ bool owner_equal(const QSharedPointer<X> &other) const noexcept
+ { return d == other.d; }
+ template <typename X>
+ bool owner_equal(const QWeakPointer<X> &other) const noexcept
+ { return d == other.d; }
+
+ size_t owner_hash() const noexcept
+ { return std::hash<Data *>()(d); }
+
private:
+ Q_NODISCARD_CTOR
explicit QSharedPointer(Qt::Initialization) {}
void deref() noexcept
@@ -470,7 +501,6 @@ private:
#ifdef QT_SHAREDPOINTER_TRACK_POINTERS
internalSafetyCheckAdd(d, ptr);
#endif
- d->setQObjectShared(ptr, true);
enableSharedFromThis(ptr);
}
@@ -498,12 +528,10 @@ private:
tmp = o->strongref.loadRelaxed(); // failed, try again
}
- if (tmp > 0) {
+ if (tmp > 0)
o->weakref.ref();
- } else {
- o->checkQObjectShared(actual);
+ else
o = nullptr;
- }
}
qt_ptr_swap(d, o);
@@ -526,6 +554,12 @@ class QWeakPointer
template <typename X>
using IfCompatible = typename std::enable_if<std::is_convertible<X*, T*>::value, bool>::type;
+ template <typename X>
+ using IfVirtualBase = typename std::enable_if<qxp::is_virtual_base_of_v<T, X>, bool>::type;
+
+ template <typename X>
+ using IfNotVirtualBase = typename std::enable_if<!qxp::is_virtual_base_of_v<T, X>, bool>::type;
+
public:
typedef T element_type;
typedef T value_type;
@@ -539,11 +573,14 @@ public:
explicit operator bool() const noexcept { return !isNull(); }
bool operator !() const noexcept { return isNull(); }
+ Q_NODISCARD_CTOR
constexpr QWeakPointer() noexcept : d(nullptr), value(nullptr) { }
inline ~QWeakPointer() { if (d && !d->weakref.deref()) delete d; }
+ Q_NODISCARD_CTOR
QWeakPointer(const QWeakPointer &other) noexcept : d(other.d), value(other.value)
{ if (d) d->weakref.ref(); }
+ Q_NODISCARD_CTOR
QWeakPointer(QWeakPointer &&other) noexcept
: d(other.d), value(other.value)
{
@@ -552,9 +589,18 @@ public:
}
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QWeakPointer)
- template <class X, IfCompatible<X> = true>
+ template <class X, IfCompatible<X> = true, IfNotVirtualBase<X> = true>
+ Q_NODISCARD_CTOR
QWeakPointer(QWeakPointer<X> &&other) noexcept
- : d(other.d), value(other.value)
+ : d(std::exchange(other.d, nullptr)),
+ value(std::exchange(other.value, nullptr))
+ {
+ }
+
+ template <class X, IfCompatible<X> = true, IfVirtualBase<X> = true>
+ Q_NODISCARD_CTOR
+ QWeakPointer(QWeakPointer<X> &&other) noexcept
+ : d(other.d), value(other.toStrongRef().get()) // must go through QSharedPointer, see below
{
other.d = nullptr;
other.value = nullptr;
@@ -581,6 +627,7 @@ public:
qt_ptr_swap(this->value, other.value);
}
+ Q_NODISCARD_CTOR
inline QWeakPointer(const QSharedPointer<T> &o) : d(o.d), value(o.data())
{ if (d) d->weakref.ref();}
inline QWeakPointer &operator=(const QSharedPointer<T> &o)
@@ -590,6 +637,7 @@ public:
}
template <class X, IfCompatible<X> = true>
+ Q_NODISCARD_CTOR
inline QWeakPointer(const QWeakPointer<X> &o) : d(nullptr), value(nullptr)
{ *this = o; }
@@ -603,6 +651,7 @@ public:
}
template <class X, IfCompatible<X> = true>
+ Q_NODISCARD_CTOR
inline QWeakPointer(const QSharedPointer<X> &o) : d(nullptr), value(nullptr)
{ *this = o; }
@@ -615,9 +664,9 @@ public:
inline void clear() { *this = QWeakPointer(); }
- inline QSharedPointer<T> toStrongRef() const { return QSharedPointer<T>(*this); }
+ [[nodiscard]] QSharedPointer<T> toStrongRef() const { return QSharedPointer<T>(*this); }
// std::weak_ptr compatibility:
- inline QSharedPointer<T> lock() const { return toStrongRef(); }
+ [[nodiscard]] QSharedPointer<T> lock() const { return toStrongRef(); }
template <class X>
bool operator==(const QWeakPointer<X> &o) const noexcept
@@ -651,6 +700,23 @@ public:
friend bool operator!=(std::nullptr_t, const QWeakPointer &p)
{ return !p.isNull(); }
+ template <typename X>
+ bool owner_before(const QWeakPointer<X> &other) const noexcept
+ { return std::less<>()(d, other.d); }
+ template <typename X>
+ bool owner_before(const QSharedPointer<X> &other) const noexcept
+ { return std::less<>()(d, other.d); }
+
+ template <typename X>
+ bool owner_equal(const QWeakPointer<X> &other) const noexcept
+ { return d == other.d; }
+ template <typename X>
+ bool owner_equal(const QSharedPointer<X> &other) const noexcept
+ { return d == other.d; }
+
+ size_t owner_hash() const noexcept
+ { return std::hash<Data *>()(d); }
+
private:
friend struct QtPrivate::EnableInternalData;
template <class X> friend class QSharedPointer;
@@ -659,10 +725,11 @@ private:
template <class X>
inline QWeakPointer &assign(X *ptr)
- { return *this = QWeakPointer<X>(ptr, true); }
+ { return *this = QWeakPointer<T>(ptr, true); }
#ifndef QT_NO_QOBJECT
template <class X, IfCompatible<X> = true>
+ Q_NODISCARD_CTOR
inline QWeakPointer(X *ptr, bool) : d(ptr ? Data::getAndRef(ptr) : nullptr), value(ptr)
{ }
#endif
diff --git a/src/corelib/tools/qspan.h b/src/corelib/tools/qspan.h
new file mode 100644
index 0000000000..d6ae2570ae
--- /dev/null
+++ b/src/corelib/tools/qspan.h
@@ -0,0 +1,452 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSPAN_H
+#define QSPAN_H
+
+#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qtypes.h>
+#include <QtCore/qcontainerfwd.h>
+
+#include <array>
+#include <cstddef>
+#include <cassert>
+#include <initializer_list>
+#include <QtCore/q20iterator.h>
+#include <QtCore/q20memory.h>
+#ifdef __cpp_lib_span
+#include <span>
+#endif
+#include <QtCore/q20type_traits.h>
+
+QT_BEGIN_NAMESPACE
+
+// like std::dynamic_extent
+namespace q20 {
+ inline constexpr auto dynamic_extent = std::size_t(-1);
+} // namespace q20
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#ifdef __cpp_lib_span
+#ifdef __cpp_lib_concepts
+namespace std::ranges {
+// Officially, these are defined in <ranges>, but that is a heavy-hitter header.
+// OTOH, <span> must specialize these variable templates, too, so we assume that
+// <span> includes some meaningful subset of <ranges> and just go ahead and use them:
+template <typename T, std::size_t E>
+constexpr inline bool enable_borrowed_range<QT_PREPEND_NAMESPACE(QSpan)<T, E>> = true;
+template <typename T, std::size_t E>
+constexpr inline bool enable_view<QT_PREPEND_NAMESPACE(QSpan)<T, E>> = true;
+} // namespace std::ranges
+#endif // __cpp_lib_concepts
+#endif // __cpp_lib_span
+QT_END_INCLUDE_NAMESPACE
+
+namespace QSpanPrivate {
+
+template <typename T, std::size_t E> class QSpanBase;
+
+template <typename T>
+struct is_qspan_helper : std::false_type {};
+template <typename T, std::size_t E>
+struct is_qspan_helper<QSpan<T, E>> : std::true_type {};
+template <typename T, std::size_t E>
+struct is_qspan_helper<QSpanBase<T, E>> : std::true_type {};
+template <typename T>
+using is_qspan = is_qspan_helper<q20::remove_cvref_t<T>>;
+
+template <typename T>
+struct is_std_span_helper : std::false_type {};
+#ifdef __cpp_lib_span
+template <typename T, std::size_t E>
+struct is_std_span_helper<std::span<T, E>> : std::true_type {};
+#endif // __cpp_lib_span
+template <typename T>
+using is_std_span = is_std_span_helper<q20::remove_cvref_t<T>>;
+
+template <typename T>
+struct is_std_array_helper : std::false_type {};
+template <typename T, std::size_t N>
+struct is_std_array_helper<std::array<T, N>> : std::true_type {};
+template <typename T>
+using is_std_array = is_std_array_helper<q20::remove_cvref_t<T>>;
+
+template <typename From, typename To>
+using is_qualification_conversion =
+ std::is_convertible<From(*)[], To(*)[]>; // https://eel.is/c++draft/span.cons#note-1
+template <typename From, typename To>
+constexpr inline bool is_qualification_conversion_v = is_qualification_conversion<From, To>::value;
+
+namespace AdlTester {
+#define MAKE_ADL_TEST(what) \
+ using std:: what; /* bring into scope */ \
+ template <typename T> using what ## _result = decltype( what (std::declval<T&&>())); \
+ /* end */
+MAKE_ADL_TEST(begin)
+MAKE_ADL_TEST(data)
+MAKE_ADL_TEST(size)
+#undef MAKE_ADL_TEST
+}
+
+// Replacements for std::ranges::XXX(), but only bringing in ADL XXX()s,
+// not doing the extra work C++20 requires
+template <typename Range>
+AdlTester::begin_result<Range> adl_begin(Range &&r) { using std::begin; return begin(r); }
+template <typename Range>
+AdlTester::data_result<Range> adl_data(Range &&r) { using std::data; return data(r); }
+template <typename Range>
+AdlTester::size_result<Range> adl_size(Range &&r) { using std::size; return size(r); }
+
+// Replacement for std::ranges::iterator_t (which depends on C++20 std::ranges::begin)
+// This one uses adl_begin() instead.
+template <typename Range>
+using iterator_t = decltype(QSpanPrivate::adl_begin(std::declval<Range&>()));
+template <typename Range>
+using range_reference_t = q20::iter_reference_t<QSpanPrivate::iterator_t<Range>>;
+
+template <typename T>
+class QSpanCommon {
+protected:
+ template <typename Iterator>
+ using is_compatible_iterator = std::conjunction<
+ // ### C++20: extend to contiguous_iteratorss
+ std::is_base_of<
+ std::random_access_iterator_tag,
+ typename std::iterator_traits<Iterator>::iterator_category
+ >,
+ is_qualification_conversion<
+ std::remove_reference_t<q20::iter_reference_t<Iterator>>,
+ T
+ >
+ >;
+ template <typename Iterator, typename End>
+ using is_compatible_iterator_and_sentinel = std::conjunction<
+ // ### C++20: extend to contiguous_iterators and real sentinels
+ is_compatible_iterator<Iterator>,
+ std::negation<std::is_convertible<End, std::size_t>>
+ >;
+ template <typename Range, typename = void> // wrap use of SFINAE-unfriendly iterator_t:
+ struct is_compatible_range_helper : std::false_type {};
+ template <typename Range>
+ struct is_compatible_range_helper<Range, std::void_t<QSpanPrivate::iterator_t<Range>>>
+ : is_compatible_iterator<QSpanPrivate::iterator_t<Range>> {};
+ template <typename Range>
+ using is_compatible_range = std::conjunction<
+ // ### C++20: extend to contiguous_iterators
+ std::negation<is_qspan<Range>>,
+ std::negation<is_std_span<Range>>,
+ std::negation<is_std_array<Range>>,
+ std::negation<std::is_array<q20::remove_cvref_t<Range>>>,
+ is_compatible_range_helper<Range>
+ >;
+
+ // constraints
+ template <typename Iterator>
+ using if_compatible_iterator = std::enable_if_t<
+ is_compatible_iterator<Iterator>::value
+ , bool>;
+ template <typename Iterator, typename End>
+ using if_compatible_iterator_and_sentinel = std::enable_if_t<
+ is_compatible_iterator_and_sentinel<Iterator, End>::value
+ , bool>;
+ template <typename Range>
+ using if_compatible_range = std::enable_if_t<is_compatible_range<Range>::value, bool>;
+}; // class QSpanCommon
+
+template <typename T, std::size_t E>
+class QSpanBase : protected QSpanCommon<T>
+{
+ static_assert(E < size_t{(std::numeric_limits<qsizetype>::max)()},
+ "QSpan only supports extents that fit into the signed size type (qsizetype).");
+
+ struct Enabled_t { explicit Enabled_t() = default; };
+ static inline constexpr Enabled_t Enable{};
+
+ template <typename S, std::size_t N>
+ using if_compatible_array = std::enable_if_t<
+ N == E && is_qualification_conversion_v<S, T>
+ , bool>;
+
+ template <typename S>
+ using if_qualification_conversion = std::enable_if_t<
+ is_qualification_conversion_v<S, T>
+ , bool>;
+protected:
+ using Base = QSpanCommon<T>;
+
+ // data members:
+ T *m_data;
+ static constexpr qsizetype m_size = qsizetype(E);
+
+ // types and constants:
+ // (in QSpan only)
+
+ // constructors (need to be public d/t the way ctor inheriting works):
+public:
+ template <std::size_t E2 = E, std::enable_if_t<E2 == 0, bool> = true>
+ Q_IMPLICIT constexpr QSpanBase() noexcept : m_data{nullptr} {}
+
+ template <typename It, typename Base::template if_compatible_iterator<It> = true>
+ explicit constexpr QSpanBase(It first, qsizetype count)
+ : m_data{q20::to_address(first)}
+ {
+ Q_ASSERT(count == m_size);
+ }
+
+ template <typename It, typename End, typename Base::template if_compatible_iterator_and_sentinel<It, End> = true>
+ explicit constexpr QSpanBase(It first, End last)
+ : QSpanBase(first, last - first) {}
+
+ template <size_t N, std::enable_if_t<N == E, bool> = true>
+ Q_IMPLICIT constexpr QSpanBase(q20::type_identity_t<T> (&arr)[N]) noexcept
+ : QSpanBase(arr, N) {}
+
+ template <typename S, size_t N, if_compatible_array<S, N> = true>
+ Q_IMPLICIT constexpr QSpanBase(std::array<S, N> &arr) noexcept
+ : QSpanBase(arr.data(), N) {}
+
+ template <typename S, size_t N, if_compatible_array<S, N> = true>
+ Q_IMPLICIT constexpr QSpanBase(const std::array<S, N> &arr) noexcept
+ : QSpanBase(arr.data(), N) {}
+
+ template <typename Range, typename Base::template if_compatible_range<Range> = true>
+ Q_IMPLICIT constexpr QSpanBase(Range &&r)
+ : QSpanBase(QSpanPrivate::adl_data(r), // no forward<>() here (std doesn't have it, either)
+ qsizetype(QSpanPrivate::adl_size(r))) // ditto, no forward<>()
+ {}
+
+ template <typename S, if_qualification_conversion<S> = true>
+ Q_IMPLICIT constexpr QSpanBase(QSpan<S, E> other) noexcept
+ : QSpanBase(other.data(), other.size())
+ {}
+
+ template <typename S, if_qualification_conversion<S> = true>
+ Q_IMPLICIT constexpr QSpanBase(QSpan<S> other)
+ : QSpanBase(other.data(), other.size())
+ {}
+
+ template <typename U = T, std::enable_if_t<std::is_const_v<U>, bool> = true>
+ Q_IMPLICIT constexpr QSpanBase(std::initializer_list<std::remove_cv_t<T>> il)
+ : QSpanBase(il.begin(), il.size())
+ {}
+
+#ifdef __cpp_lib_span
+ template <typename S, if_qualification_conversion<S> = true>
+ Q_IMPLICIT constexpr QSpanBase(std::span<S, E> other) noexcept
+ : QSpanBase(other.data(), other.size())
+ {}
+
+ template <typename S, if_qualification_conversion<S> = true>
+ Q_IMPLICIT constexpr QSpanBase(std::span<S> other)
+ : QSpanBase(other.data(), other.size())
+ {}
+#endif // __cpp_lib_span
+}; // class QSpanBase (fixed extent)
+
+template <typename T>
+class QSpanBase<T, q20::dynamic_extent> : protected QSpanCommon<T>
+{
+ template <typename S>
+ using if_qualification_conversion = std::enable_if_t<
+ is_qualification_conversion_v<S, T>
+ , bool>;
+protected:
+ using Base = QSpanCommon<T>;
+
+ // data members:
+ T *m_data;
+ qsizetype m_size;
+
+ // constructors (need to be public d/t the way ctor inheriting works):
+public:
+ Q_IMPLICIT constexpr QSpanBase() noexcept : m_data{nullptr}, m_size{0} {}
+
+ template <typename It, typename Base::template if_compatible_iterator<It> = true>
+ Q_IMPLICIT constexpr QSpanBase(It first, qsizetype count)
+ : m_data{q20::to_address(first)}, m_size{count} {}
+
+ template <typename It, typename End, typename Base::template if_compatible_iterator_and_sentinel<It, End> = true>
+ Q_IMPLICIT constexpr QSpanBase(It first, End last)
+ : QSpanBase(first, last - first) {}
+
+ template <size_t N>
+ Q_IMPLICIT constexpr QSpanBase(q20::type_identity_t<T> (&arr)[N]) noexcept
+ : QSpanBase(arr, N) {}
+
+ template <typename S, size_t N, if_qualification_conversion<S> = true>
+ Q_IMPLICIT constexpr QSpanBase(std::array<S, N> &arr) noexcept
+ : QSpanBase(arr.data(), N) {}
+
+ template <typename S, size_t N, if_qualification_conversion<S> = true>
+ Q_IMPLICIT constexpr QSpanBase(const std::array<S, N> &arr) noexcept
+ : QSpanBase(arr.data(), N) {}
+
+ template <typename Range, typename Base::template if_compatible_range<Range> = true>
+ Q_IMPLICIT constexpr QSpanBase(Range &&r)
+ : QSpanBase(QSpanPrivate::adl_data(r), // no forward<>() here (std doesn't have it, either)
+ qsizetype(QSpanPrivate::adl_size(r))) // ditto, no forward<>()
+ {}
+
+ template <typename S, size_t N, if_qualification_conversion<S> = true>
+ Q_IMPLICIT constexpr QSpanBase(QSpan<S, N> other) noexcept
+ : QSpanBase(other.data(), other.size())
+ {}
+
+ template <typename U = T, std::enable_if_t<std::is_const_v<U>, bool> = true>
+ Q_IMPLICIT constexpr QSpanBase(std::initializer_list<std::remove_cv_t<T>> il) noexcept
+ : QSpanBase(il.begin(), il.size())
+ {}
+
+#ifdef __cpp_lib_span
+ template <typename S, size_t N, if_qualification_conversion<S> = true>
+ Q_IMPLICIT constexpr QSpanBase(std::span<S, N> other) noexcept
+ : QSpanBase(other.data(), other.size())
+ {}
+#endif // __cpp_lib_span
+}; // class QSpanBase (dynamic extent)
+
+} // namespace QSpanPrivate
+
+template <typename T, std::size_t E>
+class QSpan
+#ifndef Q_QDOC
+ : private QSpanPrivate::QSpanBase<T, E>
+#endif
+{
+ using Base = QSpanPrivate::QSpanBase<T, E>;
+ Q_ALWAYS_INLINE constexpr void verify([[maybe_unused]] qsizetype pos = 0,
+ [[maybe_unused]] qsizetype n = 1) const
+ {
+ Q_ASSERT(pos >= 0);
+ Q_ASSERT(pos <= size());
+ Q_ASSERT(n >= 0);
+ Q_ASSERT(n <= size() - pos);
+ }
+
+ template <std::size_t N>
+ static constexpr bool subspan_always_succeeds_v = N <= E && E != q20::dynamic_extent;
+public:
+ // constants and types
+ using value_type = std::remove_cv_t<T>;
+#ifdef QT_COMPILER_HAS_LWG3346
+ using iterator_concept = std::contiguous_iterator_tag;
+ using element_type = T;
+#endif
+ using size_type = qsizetype; // difference to std::span
+ using difference_type = qptrdiff; // difference to std::span
+ using pointer = T*;
+ using const_pointer = const T*;
+ using reference = T&;
+ using const_reference = const T&;
+ using iterator = pointer; // implementation-defined choice
+ using const_iterator = const_pointer; // implementation-defined choice
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ static constexpr std::size_t extent = E;
+
+ // [span.cons], constructors, copy, and assignment
+ using Base::Base;
+#ifdef Q_QDOC
+ template <typename It> using if_compatible_iterator = bool;
+ template <typename S> using if_qualification_conversion = bool;
+ template <typename Range> using if_compatible_range = bool;
+ template <typename It, if_compatible_iterator<It> = true> constexpr QSpan(It first, qsizetype count);
+ template <typename It, if_compatible_iterator<It> = true> constexpr QSpan(It first, It last);
+ template <size_t N> constexpr QSpan(q20::type_identity_t<T> (&arr)[N]) noexcept;
+ template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(std::array<S, N> &arr) noexcept;
+ template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(const std::array<S, N> &arr) noexcept;
+ template <typename Range, if_compatible_range<Range> = true> constexpr QSpan(Range &&r);
+ template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(QSpan<S, N> other) noexcept;
+ template <typename S, size_t N, if_qualification_conversion<S> = true> constexpr QSpan(std::span<S, N> other) noexcept;
+ constexpr QSpan(std::initializer_list<value_type> il);
+#endif // Q_QDOC
+
+ // [span.obs]
+ [[nodiscard]] constexpr size_type size() const noexcept { return this->m_size; }
+ [[nodiscard]] constexpr size_type size_bytes() const noexcept { return size() * sizeof(T); }
+ [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; }
+
+ // [span.elem]
+ [[nodiscard]] constexpr reference operator[](size_type idx) const
+ { verify(idx); return data()[idx]; }
+ [[nodiscard]] constexpr reference front() const { verify(); return *data(); }
+ [[nodiscard]] constexpr reference back() const { verify(); return data()[size() - 1]; }
+ [[nodiscard]] constexpr pointer data() const noexcept { return this->m_data; }
+
+ // [span.iterators]
+ [[nodiscard]] constexpr iterator begin() const noexcept { return data(); }
+ [[nodiscard]] constexpr iterator end() const noexcept { return data() + size(); }
+ [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return begin(); }
+ [[nodiscard]] constexpr const_iterator cend() const noexcept { return end(); }
+ [[nodiscard]] constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
+ [[nodiscard]] constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
+ [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); }
+ [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return rend(); }
+
+ // [span.sub]
+ template <std::size_t Count>
+ [[nodiscard]] constexpr QSpan<T, Count> first() const
+ noexcept(subspan_always_succeeds_v<Count>)
+ {
+ static_assert(Count <= E,
+ "Count cannot be larger than the span's extent.");
+ verify(0, Count);
+ return QSpan<T, Count>{data(), Count};
+ }
+
+ template <std::size_t Count>
+ [[nodiscard]] constexpr QSpan<T, Count> last() const
+ noexcept(subspan_always_succeeds_v<Count>)
+ {
+ static_assert(Count <= E,
+ "Count cannot be larger than the span's extent.");
+ verify(0, Count);
+ return QSpan<T, Count>{data() + (size() - Count), Count};
+ }
+
+ template <std::size_t Offset>
+ [[nodiscard]] constexpr auto subspan() const
+ noexcept(subspan_always_succeeds_v<Offset>)
+ {
+ static_assert(Offset <= E,
+ "Offset cannot be larger than the span's extent.");
+ verify(Offset, 0);
+ if constexpr (E == q20::dynamic_extent)
+ return QSpan<T>{data() + Offset, qsizetype(size() - Offset)};
+ else
+ return QSpan<T, E - Offset>{data() + Offset, qsizetype(E - Offset)};
+ }
+
+ template <std::size_t Offset, std::size_t Count>
+ [[nodiscard]] constexpr auto subspan() const
+ noexcept(subspan_always_succeeds_v<Offset + Count>)
+ { return subspan<Offset>().template first<Count>(); }
+
+ [[nodiscard]] constexpr QSpan<T> first(size_type n) const { verify(0, n); return {data(), n}; }
+ [[nodiscard]] constexpr QSpan<T> last(size_type n) const { verify(0, n); return {data() + (size() - n), n}; }
+ [[nodiscard]] constexpr QSpan<T> subspan(size_type pos) const { verify(pos, 0); return {data() + pos, size() - pos}; }
+ [[nodiscard]] constexpr QSpan<T> subspan(size_type pos, size_type n) const { return subspan(pos).first(n); }
+
+ // Qt-compatibility API:
+ [[nodiscard]] bool isEmpty() const noexcept { return empty(); }
+ // nullary first()/last() clash with first<>() and last<>(), so they're not provided for QSpan
+ [[nodiscard]] constexpr QSpan<T> sliced(size_type pos) const { return subspan(pos); }
+ [[nodiscard]] constexpr QSpan<T> sliced(size_type pos, size_type n) const { return subspan(pos, n); }
+
+}; // class QSpan
+
+// [span.deduct]
+template <class It, class EndOrSize>
+QSpan(It, EndOrSize) -> QSpan<std::remove_reference_t<q20::iter_reference_t<It>>>;
+template <class T, std::size_t N>
+QSpan(T (&)[N]) -> QSpan<T, N>;
+template <class T, std::size_t N>
+QSpan(std::array<T, N> &) -> QSpan<T, N>;
+template <class T, std::size_t N>
+QSpan(const std::array<T, N> &) -> QSpan<const T, N>;
+template <class R>
+QSpan(R&&) -> QSpan<std::remove_reference_t<QSpanPrivate::range_reference_t<R>>>;
+
+QT_END_NAMESPACE
+
+#endif // QSPAN_H
diff --git a/src/corelib/tools/qspan.qdoc b/src/corelib/tools/qspan.qdoc
new file mode 100644
index 0000000000..472f122877
--- /dev/null
+++ b/src/corelib/tools/qspan.qdoc
@@ -0,0 +1,651 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \class QSpan
+ \inmodule QtCore
+ \since 6.7
+ \brief A non-owning container over contiguous data.
+ \ingroup tools
+ \reentrant
+
+ A QSpan references a contiguous portion of another contiguous container.
+ It acts as an interface type for all kinds of contiguous containers,
+ without the need to construct an owning container such as QList or
+ std::vector first.
+
+ The data referenced by a QSpan may be represented as an array (or
+ array-compatible data-structure such as QList, std::vector,
+ QVarLengthArray, etc.). QSpan itself merely stores a pointer to the data,
+ so users must ensure that QSpan objects do not outlive the data they
+ reference.
+
+ Unlike views such as QStringView, QLatin1StringView and QUtf8StringView,
+ referenced data can be modified through a QSpan object. To prevent this,
+ construct a QSpan over a \c{const T}:
+
+ \code
+ int numbers[] = {0, 1, 2};
+ QSpan<int> span = numbers;
+ span[0] = 42;
+ // numbers == {42, 1, 2};
+ QSpan<const int> cspan = numbers;
+ cspan[0] = 0; // ERROR: cspan[0] is read-only
+ \endcode
+
+ A QSpan can be \e{fixed-size} or \e{variable-sized}.
+
+ A variable-sized span is formed by omitting the second template argument
+ (or setting it to \c{std::dynamic_extent}, which is, however, only
+ available in C++20 builds), as seen in the example above.
+
+ A fixed-size span is formed by passing a number as the second template
+ argument:
+
+ \code
+ int numbers[] = {0, 1, 2};
+ QSpan<int, 3> span = numbers;
+ QSpan<const int, 3> = numbers; // also OK
+ \endcode
+
+ As the name suggests, a fixed-size span's size() is fixed at compile-time
+ whereas the size() of a variable-sized span is determined only at run-time.
+
+ A fixed-size span is not default-constructible (unless its \l extent is zero
+ (0)). A variable-sized span \e{is} default-constructible and will have
+ \c{data() == nullptr} and \c{size() == 0}.
+
+ A fixed-size span can be implicitly converted into a variable-sized one.
+ The opposite direction (variable-length into fixed-length) has the
+ precondition that both span's sizes must match.
+
+ Unlike with owning containers, \c{const} is \e{shallow} in QSpan: you can
+ still modify the data through a const QSpan (but not through a
+ \c{QSpan<const T>}), and begin() and end() are not overloaded on
+ \c{const}/non-\c{const}. There are cbegin() and cend(), though, that return
+ const_iterators which prevent modification of the data even though \c{T} is
+ not const:
+ \code
+ int numbers[] = {0, 1, 2};
+ const QSpan<int> span = numbers;
+ span.front() = 42; // OK, numbers[0] == 42 now
+ *span.begin() = 31; // OK, numbers[0] == 31 now
+ *span.cbegin() = -1; // ERROR: cannot assign through a const_iterator
+ \endcode
+
+ QSpan should be passed by value, not by reference-to-const:
+
+ \code
+ void consume(QSpan<const int> data); // OK
+ void consume(const QSpan<const int> &data); // works, but is non-idiomatic and less efficient
+ \endcode
+
+ \c{QSpan<T,N>} is a \e{Literal Type}, regardless of whether \c{T} is a
+ Literal Type or not.
+
+ \section2 QSpan vs. std::span
+ \target span-STL
+
+ QSpan is closely modelled after
+ \l{https://en.cppreference.com/w/cpp/container/span}{std::span}, but has a
+ few differences which we'll discuss here. Since they both implicitly
+ convert into each other, you're free to choose whichever one you like best
+ in your own code.
+
+ \list
+ \li QSpan is using the signed qsizetype as \c{size_type}
+ whereas \c{std::span} uses \c{size_t}.
+ \li All QSpan constructors are implicit;
+ many \c{std::span} ones are \c{explicit}.
+ \li QSpan can be constructed from rvalue owning containers, \c{std::span} can not.
+ \endlist
+
+ The last two are required for source-compatibility when functions that took
+ owning containers are converted to take QSpan instead, which is a
+ vitally-important use-case in Qt. The use of qsizetype is for consistency
+ with the rest of Qt containers. QSpan template arguments still use size_t
+ to avoid introducing unnecessary error conditions (negative sizes).
+
+ \section2 Compatible Iterators
+ \target span-compatible-iterators
+
+ QSpan can be constructed from an iterator and size or from an
+ iterator pair, provided the iterators are \e{compatible} ones.
+ Eventually, this should mean C++20 \c{std::contiguous_iterator} and
+ \c{std::sentinel_for}, but while Qt still supports C++17, only raw pointers
+ are considered contiguous iterators.
+
+ \section2 Compatible Ranges
+ \target span-compatible-ranges
+
+ QSpan can also be constructed from a \e{compatible} range. A range is
+ compatible if it has \l{span-compatible-iterators}{compatible iterators}.
+
+ \sa QList, QStringView, QLatin1StringView, QUtf8StringView
+*/
+
+//
+// Nested types and constants
+//
+
+/*!
+ \typedef QSpan::element_type
+
+ An alias for \c{T}. Includes the \c{const}, if any.
+
+ This alias is provided for compatbility with the STL.
+
+ \sa value_type, pointer
+*/
+
+/*!
+ \typedef QSpan::value_type
+
+ An alias for \c{T}. Excludes the \c{const}, if any.
+
+ This alias is provided for compatbility with the STL.
+
+ \sa element_type
+*/
+
+/*!
+ \typedef QSpan::size_type
+
+ An alias for qsizetype. This \l{span-STL}{differs from \c{std::span}}.
+
+ This alias is provided for compatbility with the STL.
+*/
+
+/*!
+ \typedef QSpan::difference_type
+
+ An alias for qptrdiff. This \l{span-STL}{differs from \c{std::span}}.
+
+ This alias is provided for compatbility with the STL.
+*/
+
+/*!
+ \typedef QSpan::pointer
+
+ An alias for \c{T*} and \c{element_type*}, respectively. Includes the \c{const}, if any.
+
+ This alias is provided for compatbility with the STL.
+
+ \sa element_type, const_pointer, reference, iterator
+*/
+
+/*!
+ \typedef QSpan::const_pointer
+
+ An alias for \c{const T*} and \c{const element_type*}, respectively.
+
+ This alias is provided for compatbility with the STL.
+
+ \sa element_type, pointer, const_reference, const_iterator
+*/
+
+/*!
+ \typedef QSpan::reference
+
+ An alias for \c{T&} and \c{element_type&}, respectively. Includes the \c{const}, if any.
+
+ This alias is provided for compatbility with the STL.
+
+ \sa element_type, const_reference, pointer
+*/
+
+/*!
+ \typedef QSpan::const_reference
+
+ An alias for \c{const T&} and \c{const element_type&}, respectively.
+
+ This alias is provided for compatbility with the STL.
+
+ \sa element_type, reference, const_pointer
+*/
+
+/*!
+ \typedef QSpan::iterator
+
+ An alias for \c{T*} and \c{pointer}, respectively. Includes the \c{const}, if any.
+
+ \sa pointer, const_iterator, reverse_iterator
+*/
+
+/*!
+ \typedef QSpan::const_iterator
+
+ An alias for \c{const T*} and \c{const_pointer}, respectively.
+
+ \sa const_pointer, iterator, const_reverse_iterator
+*/
+
+/*!
+ \typedef QSpan::reverse_iterator
+
+ An alias for \c{std::reverse_iterator<iterator>}. Includes the \c{const}, if any.
+
+ \sa iterator, const_reverse_iterator
+*/
+
+/*!
+ \typedef QSpan::const_reverse_iterator
+
+ An alias for \c{std::reverse_iterator<const_iterator>}.
+
+ \sa const_iterator, reverse_iterator
+*/
+
+/*!
+ \variable QSpan::extent
+
+ The second template argument of \c{QSpan<T, E>}, that is, \c{E}. This is
+ \c{std::dynamic_extent} for variable-sized spans.
+
+ \note While all other sizes and indexes in QSpan use qsizetype, this
+ variable, like \c{E}, is actually of type \c{size_t}, for compatibility with
+ \c{std::span} and \c{std::dynamic_extent}.
+
+ \sa size()
+*/
+
+//
+// Constructors and SMFs
+//
+
+/*!
+ \fn template <typename T, size_t E> QSpan<T,E>::QSpan()
+
+ Default constructor.
+
+ This constructor is only present if \c{E} is either zero (0) or
+ \c{std::dynamic_extent}. In other words: only fixed-zero-sized or variable-sized spans
+ are default-constructible.
+
+ \sa extent
+*/
+
+/*!
+ \fn template <typename T, size_t E> QSpan<T,E>::QSpan(const QSpan &other)
+ \fn template <typename T, size_t E> QSpan<T,E>::QSpan(QSpan &&other)
+ \fn template <typename T, size_t E> QSpan<T,E> &QSpan<T,E>::operator=(const QSpan &other)
+ \fn template <typename T, size_t E> QSpan<T,E> &QSpan<T,E>::operator=(QSpan &&other)
+ \fn template <typename T, size_t E> QSpan<T,E>::~QSpan()
+
+ These Special Member Functions are implicitly-defined.
+
+ \note Moves are equivalent to copies. Only data() and size() are copied
+ from span to span, not the referenced data.
+*/
+
+/*!
+ \fn template <typename T, size_t E> template <typename It, QSpan<T, E>::if_compatible_iterator<It>> QSpan<T,E>::QSpan(It first, qsizetype count)
+
+ Constructs a QSpan referencing the data starting at \a first and having length
+ \a count.
+
+ \c{[first, count)} must be a valid range.
+
+ \note This constructor participates in overload resolution only if \c{It}
+ is \l{span-compatible-iterators}{a compatible iterator}.
+*/
+
+/*!
+ \fn template <typename T, size_t E> template <typename It, QSpan<T, E>::if_compatible_iterator<It>> QSpan<T,E>::QSpan(It first, It last)
+
+ Constructs a QSpan referencing the data starting at \a first and having length
+ (\a last - \a first).
+
+ \c{[first, last)} must be a valid range.
+
+ \note This constructor participates in overload resolution only if \c{It}
+ is \l{span-compatible-iterators}{a compatible iterator}.
+*/
+
+/*!
+ \fn template <typename T, size_t E> template <size_t N> QSpan<T,E>::QSpan(q20::type_identity_t<T> (&arr)[N]);
+ \fn template <typename T, size_t E> template <typename S, size_t N, QSpan<T, E>::if_qualification_conversion<S> = true> QSpan<T,E>::QSpan(std::array<S, N> &arr);
+ \fn template <typename T, size_t E> template <typename S, size_t N, QSpan<T, E>::if_qualification_conversion<S> = true> QSpan<T,E>::QSpan(const std::array<S, N> &arr);
+
+ Constructs a QSpan referencing the data in the supplied array \a arr.
+
+ \note This constructor participates in overload resolution only if
+ \list
+ \li either \c{N} or \l{extent} are \c{std::dynamic_extent} or otherwise \l{extent} \c{==} \c{N}
+ \li and either \c{S} or \c{const S} are the same as \c{T}.
+ \endlist
+
+ \note \c{q20::type_identity_t} is a C++17 backport of C++20's
+ \l{https://en.cppreference.com/w/cpp/types/type_identity}{\c{std::type_identity_t}}.
+*/
+
+/*!
+ \fn template <typename T, size_t E> template <typename Range, QSpan<T, E>::if_compatible_range<Range> = true> QSpan<T,E>::QSpan(Range &&r)
+
+ Constructs a QSpan referencing the data in the supplied range \a r.
+
+ \note This constructor participates in overload resolution only if \c{Range}
+ is \l{span-compatible-ranges}{a compatible range}.
+*/
+
+/*!
+ \fn template <typename T, size_t E> template <typename S, size_t N, QSpan<T, E>::if_qualification_conversion<S> = true> QSpan<T,E>::QSpan(QSpan<S, N> other);
+ \fn template <typename T, size_t E> template <typename S, size_t N, QSpan<T, E>::if_qualification_conversion<S> = true> QSpan<T,E>::QSpan(std::span<S, N> other);
+
+ Constructs a QSpan referencing the data in the supplied span \a other.
+
+ \note This constructor participates in overload resolution only if
+ \list
+ \li either \c{N} or \l{extent} are \c{std::dynamic_extent} or \l{extent} \c{==} \c{N}
+ \li and either \c{S} or \c{const S} are the same as \c{T}.
+ \endlist
+*/
+
+/*!
+ \fn template <typename T, size_t E> QSpan<T, E>::QSpan(std::initializer_list<value_type> il);
+
+ Constructs a QSpan referencing the data in the supplied initializer list \a il.
+
+ \note This constructor participates in overload resolution only if \c{T} is \c{const}-qualified.
+
+ \note This constructor is \c{noexcept} only if \c{E} is \c{std::dynamic_extent}.
+
+ \note If \c{E} is not \c{std::dynamic_extent} and the size of \a il is not \c{E}, the behavior is undefined.
+*/
+
+//
+// Member functions: sizes
+//
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::size() const
+
+ Returns the size of the span, that is, the number of elements it references.
+
+ \sa size_bytes(), empty(), isEmpty()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::size_bytes() const
+
+ Returns the size of the span in bytes, that is, the number of elements
+ multiplied by \c{sizeof(T)}.
+
+ \sa size(), empty(), isEmpty()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::empty() const
+ \fn template <typename T, size_t E> auto QSpan<T, E>::isEmpty() const
+
+ Returns whether the span is empty, that is, whether \c{size() == 0}.
+
+ These functions do the same thing: empty() is provided for STL
+ compatibility and isEmpty() is provided for Qt compatibility.
+
+ \sa size(), size_bytes()
+*/
+
+//
+// element access
+//
+
+/*!
+ \fn template <typename T, size_t E> QSpan<T, E>::operator[](size_type idx) const
+
+ Returns a reference to the element at index \a idx in the span.
+
+ The index must be in range, that is, \a idx >= 0 and \a idx < size(),
+ otherwise the behavior is undefined.
+
+ \sa front(), back(), size(), empty()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::front() const
+
+ Returns a reference to the first element in the span.
+
+ The span must not be empty, otherwise the behavior is undefined.
+
+ \sa operator[](), back(), size(), empty()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::back() const
+
+ Returns a reference to the last element in the span.
+
+ The span must not be empty, otherwise the behavior is undefined.
+
+ \sa operator[](), front(), size(), empty()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::data() const
+
+ Returns a pointer to the beginning of the span.
+
+ The same as calling begin().
+
+ \sa begin(), front()
+*/
+
+//
+// iterators
+//
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::begin() const
+
+ Returns an interator pointing at the beginning of the span.
+
+ Because QSpan iterators are just pointers, this is the same as calling
+ data().
+
+ \sa end(), cbegin(), rbegin(), crbegin(), data()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::end() const
+
+ Returns an iterator pointing to one past the end of the span.
+
+ Because QSpan iterators are just pointers, this it the same as calling
+ \c{data() + size()}.
+
+ \sa begin(), cend(), rend(), crend(), data(), size()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::cbegin() const
+
+ Returns a const_iterator pointing to the beginning of the span.
+
+ This will return a read-only iterator even if \c{T} is not \c{const}:
+ \code
+ QSpan<int> span = ~~~;
+ *span.begin() = 42; // OK
+ *span.cbegin() = 42; // ERROR: cannot assign through a const_iterator
+ \endcode
+
+ \sa cend(), begin(), crbegin(), rbegin(), data()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::cend() const
+
+ Returns a const_iterator pointing to one past the end of the span.
+
+ \sa cbegin(), end(), crend(), rend(), data(), size()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::rbegin() const
+
+ Returns a reverse_iterator pointing to the beginning of the reversed span.
+
+ \sa rend(), crbegin(), begin(), cbegin()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::rend() const
+
+ Returns a reverse_iterator pointing to one past the end of the reversed span.
+
+ \sa rbegin(), crend(), end(), cend()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::crbegin() const
+
+ Returns a const_reverse_iterator pointing to the beginning of the reversed span.
+
+ \sa crend(), rbegin(), cbegin(), begin()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::crend() const
+
+ Returns a const_reverse_iterator pointing to one past the end of the reversed span.
+
+ \sa crbegin(), rend(), cend(), end()
+*/
+
+//
+// compile-time subspans:
+//
+
+/*!
+ \fn template <typename T, size_t E> template <std::size_t Count> auto QSpan<T, E>::first() const
+ \keyword first-t
+
+ Returns a fixed-sized span of size \c{Count} referencing the first \c{Count} elements of \c{*this}.
+
+ The span must hold at least \c{Count} elements (\c{E} >= \c{Count} \e{and}
+ size() >= \c{Count}), otherwise the behavior is undefined.
+
+ \sa first(QSpan<T,E>::size_type), last(), subspan()
+*/
+
+/*!
+ \fn template <typename T, size_t E> template <std::size_t Count> auto QSpan<T, E>::last() const
+ \keyword last-t
+
+ Returns a fixed-sized span of size \c{Count} referencing the last \c{Count} elements of \c{*this}.
+
+ The span must hold at least \c{Count} elements (\c{E} >= \c{Count} \e{and}
+ size() >= \c{Count}), otherwise the behavior is undefined.
+
+ \sa last(QSpan<T,E>::size_type), first(), subspan()
+*/
+
+/*!
+ \fn template <typename T, size_t E> template <std::size_t Offset> auto QSpan<T, E>::subspan() const
+ \keyword subspan-t1
+
+ Returns a span of size \c{E - Offset} referencing the remainder of this span
+ after dropping the first \c{Offset} elements.
+
+ If \c{*this} is a variable-sized span, the return type is a variable-sized
+ span, otherwise it is a fixed-sized span.
+
+ This span must hold at least \c{Offset} elements (\c{E} >= \c{Offset} \e{and}
+ size() >= \c{Offset}), otherwise the behavior is undefined.
+
+ \sa subspan(QSpan<T,E>::size_type), subspan(), first(), last()
+*/
+
+#if 0 // needs fix for QTBUG-118080 integrated into qt5.git
+/*!
+ \fn template <typename T, size_t E> template <std::size_t Offset, std::size_t Count> auto QSpan<T, E>::subspan() const
+ \keyword subspan-t2
+
+ Returns a span of size \c{Count} referencing the \c{Count} elements of this
+ span starting at \c{Offset}.
+
+ If \c{*this} is a variable-sized span, the return type is a variable-sized
+ span, otherwise it is a fixed-sized span.
+
+ This span must hold at least \c{Offset + Count} elements (\c{E} >=
+ \c{Offset + Count} \e{and} size() >= \c{Offset + Count}), otherwise the
+ behavior is undefined.
+
+ \sa subspan(QSpan<T,E>::size_type, QSpan<T,E>::size_type), subspan(), first(), last()
+*/
+#endif
+
+//
+// runtime subspans:
+//
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::first(qsizetype n) const
+ \keyword first-n
+
+ Returns a variable-sized span of size \a n referencing the first \a n elements of \c{*this}.
+
+ \a n must be non-negative.
+
+ The span must hold at least \a n elements (\c{E} >= \a n \e{and} size() >=
+ \a n), otherwise the behavior is undefined.
+
+ \sa {first-t}{first<N>()}, last(QSpan<T,E>::size_type), subspan(QSpan<T,E>::size_type),
+ subspan(QSpan<T,E>::size_type, QSpan<T,E>::size_type)
+ \sa sliced()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::last(qsizetype n) const
+ \keyword last-n
+
+ Returns a variable-sized span of size \a n referencing the last \a n elements of \c{*this}.
+
+ \a n must be non-negative.
+
+ The span must hold at least \a n elements (\c{E} >= \a n \e{and}
+ size() >= \a n), otherwise the behavior is undefined.
+
+ \sa last(), first(QSpan<T,E>::size_type), subspan(QSpan<T,E>::size_type),
+ subspan(QSpan<T,E>::size_type, QSpan<T,E>::size_type), sliced()
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::subspan(qsizetype pos) const
+ \fn template <typename T, size_t E> auto QSpan<T, E>::sliced(qsizetype pos) const
+ \keyword subspan-n1
+
+ Returns a variable-sized span of size \c{size() - pos} referencing the
+ remainder of this span after dropping the first \a pos elements.
+
+ \a pos must be non-negative.
+
+ This span must hold at least \a pos elements (\c{E} >= \a pos \e{and}
+ size() >= \a pos), otherwise the behavior is undefined.
+
+ These functions do the same thing: subspan() is provided for STL
+ compatibility and sliced() is provided for Qt compatibility.
+
+ \sa subspan(), first(QSpan<T,E>::size_type), last(QSpan<T,E>::size_type)
+*/
+
+/*!
+ \fn template <typename T, size_t E> auto QSpan<T, E>::subspan(qsizetype pos, qsizetype n) const
+ \fn template <typename T, size_t E> auto QSpan<T, E>::sliced(qsizetype pos, qsizetype n) const
+ \keyword subspan-n2
+
+ Returns a variable-sized span of size \a n referencing the \a n elements of
+ this span starting at \a pos.
+
+ Both \a pos and \a n must be non-negative.
+
+ This span must hold at least \c{pos + n} elements (\c{E} >=
+ \c{pos + n} \e{and} size() >= \c{pos + n}), otherwise the
+ behavior is undefined.
+
+ These functions do the same thing: subspan() is provided for STL
+ compatibility and sliced() is provided for Qt compatibility.
+
+ \sa subspan(), first(QSpan<T,E>::size_type), last(QSpan<T,E>::size_type)
+*/
+
diff --git a/src/corelib/tools/qspan_p.h b/src/corelib/tools/qspan_p.h
new file mode 100644
index 0000000000..0072e3ef64
--- /dev/null
+++ b/src/corelib/tools/qspan_p.h
@@ -0,0 +1,24 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSPAN_P_H
+#define QSPAN_P_H
+
+#include <QtCore/qspan.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
+
+QT_END_NAMESPACE
+
+#endif // QSPAN_P_H
diff --git a/src/corelib/tools/qtaggedpointer.h b/src/corelib/tools/qtaggedpointer.h
index bc43f765aa..6c467d59f8 100644
--- a/src/corelib/tools/qtaggedpointer.h
+++ b/src/corelib/tools/qtaggedpointer.h
@@ -43,10 +43,10 @@ public:
static constexpr quintptr tagMask() { return QtPrivate::TagInfo<T>::alignment - 1; }
static constexpr quintptr pointerMask() { return ~tagMask(); }
- constexpr QTaggedPointer() noexcept : d(0) {}
- constexpr QTaggedPointer(std::nullptr_t) noexcept : QTaggedPointer() {}
+ Q_NODISCARD_CTOR constexpr QTaggedPointer() noexcept : d(0) {}
+ Q_NODISCARD_CTOR constexpr QTaggedPointer(std::nullptr_t) noexcept : QTaggedPointer() {}
- explicit QTaggedPointer(T *pointer, Tag tag = Tag()) noexcept
+ Q_NODISCARD_CTOR explicit QTaggedPointer(T *pointer, Tag tag = Tag()) noexcept
: d(quintptr(pointer) | quintptr(tag))
{
static_assert(sizeof(Type*) == sizeof(QTaggedPointer));
diff --git a/src/corelib/tools/qtimeline.cpp b/src/corelib/tools/qtimeline.cpp
index 3bfe000bca..5512da867f 100644
--- a/src/corelib/tools/qtimeline.cpp
+++ b/src/corelib/tools/qtimeline.cpp
@@ -55,16 +55,16 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
{
Q_Q(QTimeLine);
currentTime.removeBindingUnlessInWrapper();
- auto previousCurrentTime = currentTime.value();
+ const auto previousCurrentTime = currentTime.valueBypassingBindings();
- qreal lastValue = q->currentValue();
- int lastFrame = q->currentFrame();
+ const qreal lastValue = q->valueForTime(previousCurrentTime);
+ const int lastFrame = q->frameForTime(previousCurrentTime);
// Determine if we are looping.
- int elapsed = (direction == QTimeLine::Backward) ? (-msecs + duration) : msecs;
- int loopCountNow = elapsed / duration;
+ const int elapsed = (direction == QTimeLine::Backward) ? (-msecs + duration) : msecs;
+ const int loopCountNow = elapsed / duration;
- bool looping = (loopCountNow != currentLoopCount);
+ const bool looping = (loopCountNow != currentLoopCount);
#ifdef QTIMELINE_DEBUG
qDebug() << "QTimeLinePrivate::setCurrentTime:" << msecs << duration << "with loopCountNow"
<< loopCountNow << "currentLoopCount" << currentLoopCount << "looping" << looping;
@@ -75,7 +75,7 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
// Normalize msecs to be between 0 and duration, inclusive.
currentTime.setValueBypassingBindings(elapsed % duration);
if (direction.value() == QTimeLine::Backward)
- currentTime.setValueBypassingBindings(duration - currentTime);
+ currentTime.setValueBypassingBindings(duration - currentTime.valueBypassingBindings());
// Check if we have reached the end of loopcount.
bool finished = false;
@@ -85,12 +85,14 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
currentLoopCount = loopCount - 1;
}
- int currentFrame = q->frameForTime(currentTime);
+ const int currentFrame = q->frameForTime(currentTime.valueBypassingBindings());
#ifdef QTIMELINE_DEBUG
- qDebug() << "QTimeLinePrivate::setCurrentTime: frameForTime" << currentTime << currentFrame;
+ qDebug() << "QTimeLinePrivate::setCurrentTime: frameForTime"
+ << currentTime.valueBypassingBindings() << currentFrame;
#endif
- if (!qFuzzyCompare(lastValue, q->currentValue()))
- emit q->valueChanged(q->currentValue(), QTimeLine::QPrivateSignal());
+ const qreal currentValue = q->valueForTime(currentTime.valueBypassingBindings());
+ if (!qFuzzyCompare(lastValue, currentValue))
+ emit q->valueChanged(currentValue, QTimeLine::QPrivateSignal());
if (lastFrame != currentFrame) {
const int transitionframe = (direction == QTimeLine::Forward ? endFrame : startFrame);
if (looping && !finished && transitionframe != currentFrame) {
@@ -123,7 +125,7 @@ void QTimeLinePrivate::setCurrentTime(int msecs)
q->stop();
emit q->finished(QTimeLine::QPrivateSignal());
}
- if (currentTime.value() != previousCurrentTime)
+ if (currentTime.valueBypassingBindings() != previousCurrentTime)
currentTime.notify();
}
QBindable<int> QTimeLine::bindableCurrentTime()
@@ -334,11 +336,12 @@ QTimeLine::Direction QTimeLine::direction() const
void QTimeLine::setDirection(Direction direction)
{
Q_D(QTimeLine);
- auto previousDirection = d->direction.value();
- d->direction.setValue(direction);
+ d->direction.removeBindingUnlessInWrapper();
+ const auto previousDirection = d->direction.valueBypassingBindings();
+ d->direction.setValueBypassingBindings(direction);
d->startTime = d->currentTime;
d->timer.start();
- if (previousDirection != d->direction.value())
+ if (previousDirection != d->direction.valueBypassingBindings())
d->direction.notify();
}
@@ -372,12 +375,11 @@ void QTimeLine::setDuration(int duration)
qWarning("QTimeLine::setDuration: cannot set duration <= 0");
return;
}
- if (duration == d->duration) {
- d->duration.removeBindingUnlessInWrapper();
- return;
+ d->duration.removeBindingUnlessInWrapper();
+ if (duration != d->duration.valueBypassingBindings()) {
+ d->duration.setValueBypassingBindings(duration);
+ d->duration.notify();
}
- d->duration.setValue(duration);
- d->duration.notify();
}
QBindable<int> QTimeLine::bindableDuration()
diff --git a/src/corelib/tools/qtools_p.h b/src/corelib/tools/qtools_p.h
index 93432a9524..105aa40c02 100644
--- a/src/corelib/tools/qtools_p.h
+++ b/src/corelib/tools/qtools_p.h
@@ -115,9 +115,6 @@ constexpr inline int qt_lencmp(qsizetype lhs, qsizetype rhs) noexcept
} // namespace QtMiscUtils
-// We typically need an extra bit for qNextPowerOfTwo when determining the next allocation size.
-constexpr qsizetype MaxAllocSize = (std::numeric_limits<qsizetype>::max)();
-
struct CalculateGrowingBlockSizeResult
{
qsizetype size;
diff --git a/src/corelib/tools/qtyperevision.cpp b/src/corelib/tools/qtyperevision.cpp
new file mode 100644
index 0000000000..6426236288
--- /dev/null
+++ b/src/corelib/tools/qtyperevision.cpp
@@ -0,0 +1,217 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtCore/qtyperevision.h>
+#include <QtCore/qhashfunctions.h>
+
+#ifndef QT_NO_DATASTREAM
+# include <QtCore/qdatastream.h>
+#endif
+
+#ifndef QT_NO_DEBUG_STREAM
+# include <QtCore/qdebug.h>
+#endif
+
+#include <algorithm>
+#include <limits>
+
+QT_BEGIN_NAMESPACE
+
+QT_IMPL_METATYPE_EXTERN(QTypeRevision)
+
+/*!
+ \class QTypeRevision
+ \inmodule QtCore
+ \since 6.0
+ \brief The QTypeRevision class contains a lightweight representation of
+ a version number with two 8-bit segments, major and minor, either
+ of which can be unknown.
+ \compares strong
+
+ Use this class to describe revisions of a type. Compatible revisions can be
+ expressed as increments of the minor version. Breaking changes can be
+ expressed as increments of the major version. The return values of
+ \l QMetaMethod::revision() and \l QMetaProperty::revision() can be passed to
+ \l QTypeRevision::fromEncodedVersion(). The resulting major and minor versions
+ specify in which Qt versions the properties and methods were added.
+
+ \sa QMetaMethod::revision(), QMetaProperty::revision()
+*/
+
+/*!
+ \fn template<typename Integer, QTypeRevision::if_valid_segment_type<Integer> = true> static bool QTypeRevision::isValidSegment(Integer segment)
+
+ Returns true if the given number can be used as either major or minor
+ version in a QTypeRevision. The valid range for \a segment is \c {>= 0} and \c {< 255}.
+*/
+
+/*!
+ \fn QTypeRevision::QTypeRevision()
+
+ Produces an invalid revision.
+
+ \sa isValid()
+*/
+
+/*!
+ \fn template<typename Major, typename Minor, QTypeRevision::if_valid_segment_type<Major> = true, QTypeRevision::if_valid_segment_type<Minor> = true> static QTypeRevision QTypeRevision::fromVersion(Major majorVersion, Minor minorVersion)
+
+ Produces a QTypeRevision from the given \a majorVersion and \a minorVersion,
+ both of which need to be a valid segments.
+
+ \sa isValidSegment()
+*/
+
+/*!
+ \fn template<typename Major, QTypeRevision::if_valid_segment_type<Major> = true> static QTypeRevision QTypeRevision::fromMajorVersion(Major majorVersion)
+
+ Produces a QTypeRevision from the given \a majorVersion with an invalid minor
+ version. \a majorVersion needs to be a valid segment.
+
+ \sa isValidSegment()
+*/
+
+/*!
+ \fn template<typename Minor, QTypeRevision::if_valid_segment_type<Minor> = true> static QTypeRevision QTypeRevision::fromMinorVersion(Minor minorVersion)
+
+ Produces a QTypeRevision from the given \a minorVersion with an invalid major
+ version. \a minorVersion needs to be a valid segment.
+
+ \sa isValidSegment()
+*/
+
+/*!
+ \fn template<typename Integer, QTypeRevision::if_valid_value_type<Integer> = true> static QTypeRevision QTypeRevision::fromEncodedVersion(Integer value)
+
+ Produces a QTypeRevision from the given \a value. \a value encodes both the
+ minor and major versions in the least significant and second least
+ significant byte, respectively.
+
+ \a value must not have any bits outside the least significant two bytes set.
+ \c Integer needs to be at least 16 bits wide, and must not have a sign bit
+ in the least significant 16 bits.
+
+ \sa toEncodedVersion()
+*/
+
+/*!
+ \fn static QTypeRevision QTypeRevision::zero()
+
+ Produces a QTypeRevision with major and minor version \c{0}.
+*/
+
+/*!
+ \fn bool QTypeRevision::hasMajorVersion() const
+
+ Returns true if the major version is known, otherwise false.
+
+ \sa majorVersion(), hasMinorVersion()
+*/
+
+/*!
+ \fn quint8 QTypeRevision::majorVersion() const
+
+ Returns the major version encoded in the revision.
+
+ \sa hasMajorVersion(), minorVersion()
+*/
+
+/*!
+ \fn bool QTypeRevision::hasMinorVersion() const
+
+ Returns true if the minor version is known, otherwise false.
+
+ \sa minorVersion(), hasMajorVersion()
+*/
+
+/*!
+ \fn quint8 QTypeRevision::minorVersion() const
+
+ Returns the minor version encoded in the revision.
+
+ \sa hasMinorVersion(), majorVersion()
+*/
+
+/*!
+ \fn bool QTypeRevision::isValid() const
+
+ Returns true if the major version or the minor version is known,
+ otherwise false.
+
+ \sa hasMajorVersion(), hasMinorVersion()
+*/
+
+/*!
+ \fn template<typename Integer, QTypeRevision::if_valid_value_type<Integer> = true> Integer QTypeRevision::toEncodedVersion() const
+
+ Transforms the revision into an integer value, encoding the minor
+ version into the least significant byte, and the major version into
+ the second least significant byte.
+
+ \c Integer needs to be at least 16 bits wide, and must not have a sign bit
+ in the least significant 16 bits.
+
+ \sa fromEncodedVersion()
+*/
+
+#ifndef QT_NO_DATASTREAM
+/*!
+ \fn QDataStream& operator<<(QDataStream &out, const QTypeRevision &revision)
+ \relates QTypeRevision
+ \since 6.0
+
+ Writes the revision \a revision to stream \a out.
+ */
+QDataStream &operator<<(QDataStream &out, const QTypeRevision &revision)
+{
+ return out << revision.toEncodedVersion<quint16>();
+}
+
+/*!
+ \fn QDataStream& operator>>(QDataStream &in, QTypeRevision &revision)
+ \relates QTypeRevision
+ \since 6.0
+
+ Reads a revision from stream \a in and stores it in \a revision.
+ */
+QDataStream &operator>>(QDataStream &in, QTypeRevision &revision)
+{
+ quint16 value;
+ in >> value;
+ revision = QTypeRevision::fromEncodedVersion(value);
+ return in;
+}
+#endif
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QTypeRevision &revision)
+{
+ QDebugStateSaver saver(debug);
+ if (revision.hasMajorVersion()) {
+ if (revision.hasMinorVersion())
+ debug.nospace() << revision.majorVersion() << '.' << revision.minorVersion();
+ else
+ debug.nospace().noquote() << revision.majorVersion() << ".x";
+ } else {
+ if (revision.hasMinorVersion())
+ debug << revision.minorVersion();
+ else
+ debug.noquote() << "invalid";
+ }
+ return debug;
+}
+#endif
+
+/*!
+ \relates QHash
+ \since 6.0
+
+ Returns the hash value for the \a key, using \a seed to seed the
+ calculation.
+*/
+size_t qHash(const QTypeRevision &key, size_t seed)
+{
+ return qHash(key.toEncodedVersion<quint16>(), seed);
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/tools/qtyperevision.h b/src/corelib/tools/qtyperevision.h
new file mode 100644
index 0000000000..8f255a77e8
--- /dev/null
+++ b/src/corelib/tools/qtyperevision.h
@@ -0,0 +1,167 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2022 Intel Corporation.
+// Copyright (C) 2015 Keith Gardner <kreios4004@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTYPEREVISION_H
+#define QTYPEREVISION_H
+
+#include <QtCore/qassert.h>
+#include <QtCore/qcompare.h>
+#include <QtCore/qcontainertools_impl.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qtypeinfo.h>
+
+#include <limits>
+
+QT_BEGIN_NAMESPACE
+
+class QDataStream;
+class QDebug;
+
+class QTypeRevision;
+Q_CORE_EXPORT size_t qHash(const QTypeRevision &key, size_t seed = 0);
+
+#ifndef QT_NO_DATASTREAM
+Q_CORE_EXPORT QDataStream& operator<<(QDataStream &out, const QTypeRevision &revision);
+Q_CORE_EXPORT QDataStream& operator>>(QDataStream &in, QTypeRevision &revision);
+#endif
+
+class QTypeRevision
+{
+public:
+ template<typename Integer>
+ using if_valid_segment_type = typename std::enable_if<
+ std::is_integral<Integer>::value, bool>::type;
+
+ template<typename Integer>
+ using if_valid_value_type = typename std::enable_if<
+ std::is_integral<Integer>::value
+ && (sizeof(Integer) > sizeof(quint16)
+ || (sizeof(Integer) == sizeof(quint16)
+ && !std::is_signed<Integer>::value)), bool>::type;
+
+ template<typename Integer, if_valid_segment_type<Integer> = true>
+ static constexpr bool isValidSegment(Integer segment)
+ {
+ // using extra parentheses around max to avoid expanding it if it is a macro
+ return segment >= Integer(0)
+ && ((std::numeric_limits<Integer>::max)() < Integer(SegmentUnknown)
+ || segment < Integer(SegmentUnknown));
+ }
+
+ template<typename Major, typename Minor,
+ if_valid_segment_type<Major> = true,
+ if_valid_segment_type<Minor> = true>
+ static constexpr QTypeRevision fromVersion(Major majorVersion, Minor minorVersion)
+ {
+ return Q_ASSERT(isValidSegment(majorVersion)),
+ Q_ASSERT(isValidSegment(minorVersion)),
+ QTypeRevision(quint8(majorVersion), quint8(minorVersion));
+ }
+
+ template<typename Major, if_valid_segment_type<Major> = true>
+ static constexpr QTypeRevision fromMajorVersion(Major majorVersion)
+ {
+ return Q_ASSERT(isValidSegment(majorVersion)),
+ QTypeRevision(quint8(majorVersion), SegmentUnknown);
+ }
+
+ template<typename Minor, if_valid_segment_type<Minor> = true>
+ static constexpr QTypeRevision fromMinorVersion(Minor minorVersion)
+ {
+ return Q_ASSERT(isValidSegment(minorVersion)),
+ QTypeRevision(SegmentUnknown, quint8(minorVersion));
+ }
+
+ template<typename Integer, if_valid_value_type<Integer> = true>
+ static constexpr QTypeRevision fromEncodedVersion(Integer value)
+ {
+ return Q_ASSERT((value & ~Integer(0xffff)) == Integer(0)),
+ QTypeRevision((value & Integer(0xff00)) >> 8, value & Integer(0xff));
+ }
+
+ static constexpr QTypeRevision zero() { return QTypeRevision(0, 0); }
+
+ constexpr QTypeRevision() = default;
+
+ constexpr bool hasMajorVersion() const { return m_majorVersion != SegmentUnknown; }
+ constexpr quint8 majorVersion() const { return m_majorVersion; }
+
+ constexpr bool hasMinorVersion() const { return m_minorVersion != SegmentUnknown; }
+ constexpr quint8 minorVersion() const { return m_minorVersion; }
+
+ constexpr bool isValid() const { return hasMajorVersion() || hasMinorVersion(); }
+
+ template<typename Integer, if_valid_value_type<Integer> = true>
+ constexpr Integer toEncodedVersion() const
+ {
+ return Integer(m_majorVersion << 8) | Integer(m_minorVersion);
+ }
+
+private:
+ friend constexpr bool
+ comparesEqual(const QTypeRevision &lhs, const QTypeRevision &rhs) noexcept
+ { return lhs.toEncodedVersion<quint16>() == rhs.toEncodedVersion<quint16>(); }
+ friend constexpr Qt::strong_ordering
+ compareThreeWay(const QTypeRevision &lhs, const QTypeRevision &rhs) noexcept
+ {
+ // For both major and minor the following rule applies:
+ // non-0 ver > unspecified ver > 0 ver
+ auto cmpUnspecified = [](quint8 leftVer, quint8 rightVer) {
+ Q_ASSERT(leftVer != rightVer
+ && (leftVer == QTypeRevision::SegmentUnknown
+ || rightVer == QTypeRevision::SegmentUnknown));
+ if (leftVer != QTypeRevision::SegmentUnknown)
+ return leftVer > 0 ? Qt::strong_ordering::greater : Qt::strong_ordering::less;
+ return rightVer > 0 ? Qt::strong_ordering::less : Qt::strong_ordering::greater;
+ };
+
+ if (lhs.hasMajorVersion() != rhs.hasMajorVersion()) {
+ return cmpUnspecified(lhs.majorVersion(), rhs.majorVersion());
+ } else {
+ const auto majorRes = Qt::compareThreeWay(lhs.majorVersion(), rhs.majorVersion());
+ if (is_eq(majorRes)) {
+ if (lhs.hasMinorVersion() != rhs.hasMinorVersion())
+ return cmpUnspecified(lhs.minorVersion(), rhs.minorVersion());
+ return Qt::compareThreeWay(lhs.minorVersion(), rhs.minorVersion());
+ }
+ return majorRes;
+ }
+ }
+ Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(QTypeRevision)
+
+ enum { SegmentUnknown = 0xff };
+
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ constexpr QTypeRevision(quint8 major, quint8 minor)
+ : m_minorVersion(minor), m_majorVersion(major) {}
+
+ quint8 m_minorVersion = SegmentUnknown;
+ quint8 m_majorVersion = SegmentUnknown;
+#else
+ constexpr QTypeRevision(quint8 major, quint8 minor)
+ : m_majorVersion(major), m_minorVersion(minor) {}
+
+ quint8 m_majorVersion = SegmentUnknown;
+ quint8 m_minorVersion = SegmentUnknown;
+#endif
+};
+
+static_assert(sizeof(QTypeRevision) == 2);
+Q_DECLARE_TYPEINFO(QTypeRevision, Q_RELOCATABLE_TYPE);
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_CORE_EXPORT QDebug operator<<(QDebug, const QTypeRevision &revision);
+#endif
+
+QT_END_NAMESPACE
+
+QT_DECL_METATYPE_EXTERN(QTypeRevision, Q_CORE_EXPORT)
+
+#endif // QTYPEREVISION_H
+
+#if !defined(QT_LEAN_HEADERS) || QT_LEAN_HEADERS < 2
+// make QVersionNumber available from <QTypeRevision>
+#include <QtCore/qversionnumber.h>
+#endif
diff --git a/src/corelib/tools/quniquehandle_p.h b/src/corelib/tools/quniquehandle_p.h
new file mode 100644
index 0000000000..7af1536c2e
--- /dev/null
+++ b/src/corelib/tools/quniquehandle_p.h
@@ -0,0 +1,225 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QUNIQUEHANDLE_P_H
+#define QUNIQUEHANDLE_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/qtconfigmacros.h>
+#include <QtCore/qassert.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+/*! \internal QUniqueHandle is a general purpose RAII wrapper intended
+ for interfacing with resource-allocating C-style APIs, for example
+ operating system APIs, database engine APIs, or any other scenario
+ where resources are allocated and released, and where pointer
+ semantics does not seem a perfect fit.
+
+ QUniqueHandle does not support copying, because it is intended to
+ maintain ownership of resources that can not be copied. This makes
+ it safer to use than naked handle types, since ownership is
+ maintained by design.
+
+ The underlying handle object is described using a client supplied
+ HandleTraits object that is implemented per resource type. The
+ traits struct must describe two properties of a handle:
+
+ 1) What value is considered invalid
+ 2) How to close a resource.
+
+ Example 1:
+
+ struct InvalidHandleTraits {
+ using Type = HANDLE;
+
+ static Type invalidValue() {
+ return INVALID_HANDLE_VALUE;
+ }
+
+ static bool close(Type handle) {
+ return CloseHandle(handle) != 0;
+ }
+ }
+
+ using FileHandle = QUniqueHandle<InvalidHandleTraits>;
+
+ Usage:
+
+ // Takes ownership of returned handle.
+ FileHandle handle{ CreateFile(...) };
+
+ if (!handle.isValid()) {
+ qDebug() << GetLastError()
+ return;
+ }
+
+ ...
+
+ Example 2:
+
+ struct SqLiteTraits {
+ using Type = sqlite3*;
+
+ static Type invalidValue() {
+ return nullptr;
+ }
+
+ static bool close(Type handle) {
+ sqlite3_close(handle);
+ return true;
+ }
+ }
+
+ using DbHandle = QUniqueHandle<SqLiteTraits>;
+
+ Usage:
+
+ DbHandle h;
+
+ // Take ownership of returned handle.
+ int result = sqlite3_open(":memory:", &h);
+
+ ...
+
+ NOTE: The QUniqueHandle assumes that closing a resource is
+ guaranteed to succeed, and provides no support for handling failure
+ to close a resource. It is therefore only recommended for use cases
+ where failure to close a resource is either not an error, or an
+ unrecoverable error.
+*/
+
+// clang-format off
+
+template <typename HandleTraits>
+class QUniqueHandle
+{
+public:
+ using Type = typename HandleTraits::Type;
+
+ QUniqueHandle() = default;
+
+ explicit QUniqueHandle(const Type &handle) noexcept
+ : m_handle{ handle }
+ {}
+
+ QUniqueHandle(QUniqueHandle &&other) noexcept
+ : m_handle{ other.release() }
+ {}
+
+ ~QUniqueHandle() noexcept
+ {
+ close();
+ }
+
+ QUniqueHandle& operator=(QUniqueHandle &&rhs) noexcept
+ {
+ if (this != std::addressof(rhs))
+ reset(rhs.release());
+
+ return *this;
+ }
+
+ QUniqueHandle(const QUniqueHandle &) = delete;
+ QUniqueHandle &operator=(const QUniqueHandle &) = delete;
+
+
+ [[nodiscard]] bool isValid() const noexcept
+ {
+ return m_handle != HandleTraits::invalidValue();
+ }
+
+ [[nodiscard]] explicit operator bool() const noexcept
+ {
+ return isValid();
+ }
+
+ [[nodiscard]] Type get() const noexcept
+ {
+ return m_handle;
+ }
+
+ void reset(const Type& handle) noexcept
+ {
+ if (handle == m_handle)
+ return;
+
+ close();
+ m_handle = handle;
+ }
+
+ [[nodiscard]] Type release() noexcept
+ {
+ Type handle = m_handle;
+ m_handle = HandleTraits::invalidValue();
+ return handle;
+ }
+
+ [[nodiscard]] Type *operator&() noexcept // NOLINT(google-runtime-operator)
+ {
+ Q_ASSERT(!isValid());
+ return &m_handle;
+ }
+
+ void close() noexcept
+ {
+ if (!isValid())
+ return;
+
+ const bool success = HandleTraits::close(m_handle);
+ Q_ASSERT(success);
+
+ m_handle = HandleTraits::invalidValue();
+ }
+
+ [[nodiscard]] friend bool operator==(const QUniqueHandle &lhs, const QUniqueHandle &rhs) noexcept
+ {
+ return lhs.get() == rhs.get();
+ }
+
+ [[nodiscard]] friend bool operator!=(const QUniqueHandle &lhs, const QUniqueHandle &rhs) noexcept
+ {
+ return lhs.get() != rhs.get();
+ }
+
+ [[nodiscard]] friend bool operator<(const QUniqueHandle &lhs, const QUniqueHandle &rhs) noexcept
+ {
+ return lhs.get() < rhs.get();
+ }
+
+ [[nodiscard]] friend bool operator<=(const QUniqueHandle &lhs, const QUniqueHandle &rhs) noexcept
+ {
+ return lhs.get() <= rhs.get();
+ }
+
+ [[nodiscard]] friend bool operator>(const QUniqueHandle &lhs, const QUniqueHandle &rhs) noexcept
+ {
+ return lhs.get() > rhs.get();
+ }
+
+ [[nodiscard]] friend bool operator>=(const QUniqueHandle &lhs, const QUniqueHandle &rhs) noexcept
+ {
+ return lhs.get() >= rhs.get();
+ }
+
+private:
+ Type m_handle{ HandleTraits::invalidValue() };
+};
+
+// clang-format on
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h
index 44c5d8beac..0a579bf487 100644
--- a/src/corelib/tools/qvarlengtharray.h
+++ b/src/corelib/tools/qvarlengtharray.h
@@ -183,6 +183,12 @@ public:
iterator erase(const_iterator begin, const_iterator end);
iterator erase(const_iterator pos) { return erase(pos, pos + 1); }
+ static constexpr qsizetype max_size() noexcept
+ {
+ // -1 to deal with the pointer one-past-the-end
+ return (QtPrivate::MaxAllocSize / sizeof(T)) - 1;
+ }
+
size_t hash(size_t seed) const noexcept(QtPrivate::QNothrowHashable_v<T>)
{
return qHashRange(begin(), end(), seed);
@@ -278,6 +284,8 @@ class QVarLengthArray
template <typename InputIterator>
using if_input_iterator = QtPrivate::IfIsInputIterator<InputIterator>;
public:
+ static constexpr qsizetype PreallocatedSize = Prealloc;
+
using size_type = typename Base::size_type;
using value_type = typename Base::value_type;
using pointer = typename Base::pointer;
@@ -395,6 +403,7 @@ public:
}
#ifdef Q_QDOC
inline qsizetype size() const { return this->s; }
+ static constexpr qsizetype max_size() noexcept { return QVLABase<T>::max_size(); }
#endif
using Base::size;
inline qsizetype count() const { return size(); }
@@ -501,13 +510,13 @@ public:
void insert(qsizetype i, const T &t);
void insert(qsizetype i, qsizetype n, const T &t);
- void assign(qsizetype n, const T &t)
- { Base::assign_impl(Prealloc, this->array, n, t); }
+ QVarLengthArray &assign(qsizetype n, const T &t)
+ { Base::assign_impl(Prealloc, this->array, n, t); return *this; }
template <typename InputIterator, if_input_iterator<InputIterator> = true>
- void assign(InputIterator first, InputIterator last)
- { Base::assign_impl(Prealloc, this->array, first, last); }
- void assign(std::initializer_list<T> list)
- { assign(list.begin(), list.end()); }
+ QVarLengthArray &assign(InputIterator first, InputIterator last)
+ { Base::assign_impl(Prealloc, this->array, first, last); return *this; }
+ QVarLengthArray &assign(std::initializer_list<T> list)
+ { assign(list.begin(), list.end()); return *this; }
#ifdef Q_QDOC
void replace(qsizetype i, const T &t);
@@ -790,27 +799,28 @@ Q_OUTOFLINE_TEMPLATE void QVLABase<T>::assign_impl(qsizetype prealloc, void *arr
}
auto dst = begin();
- while (first != last && dst != end()) {
- *dst = *first; // reuse initialized buffer
+ const auto dend = end();
+ while (true) {
+ if (first == last) { // ran out of elements to assign
+ std::destroy(dst, dend);
+ break;
+ }
+ if (dst == dend) { // ran out of existing elements to overwrite
+ if constexpr (IsFwdIt) {
+ dst = std::uninitialized_copy(first, last, dst);
+ break;
+ } else {
+ do {
+ emplace_back_impl(prealloc, array, *first);
+ } while (++first != last);
+ return; // size() is already correct (and dst invalidated)!
+ }
+ }
+ *dst = *first; // overwrite existing element
++dst;
++first;
}
-
- qsizetype n = 0;
- if constexpr (IsFwdIt && noexcept(T(*first))) {
- dst = std::uninitialized_copy(first, last, dst);
- n = dst - begin();
- if (n > s) // otherwise: readjust 's' in erase() later
- s = n;
- } else {
- n = dst - begin();
- while (first != last) {
- emplace_back_impl(prealloc, array, *first);
- ++first;
- ++n;
- }
- }
- erase(data() + n, data() + size());
+ this->s = dst - begin();
}
template <class T>
@@ -822,7 +832,7 @@ Q_OUTOFLINE_TEMPLATE void QVLABase<T>::reallocate_impl(qsizetype prealloc, void
qsizetype osize = size();
const qsizetype copySize = qMin(asize, osize);
- Q_ASSUME(copySize >= 0);
+ Q_ASSERT(copySize >= 0);
if (aalloc != capacity()) {
QVLABaseBase::malloced_ptr guard;
@@ -946,8 +956,8 @@ Q_OUTOFLINE_TEMPLATE auto QVLABase<T>::insert_impl(qsizetype prealloc, void *arr
template <class T>
Q_OUTOFLINE_TEMPLATE auto QVLABase<T>::erase(const_iterator abegin, const_iterator aend) -> iterator
{
- Q_ASSERT_X(isValidIterator(abegin), "QVarLengthArray::insert", "The specified const_iterator argument 'abegin' is invalid");
- Q_ASSERT_X(isValidIterator(aend), "QVarLengthArray::insert", "The specified const_iterator argument 'aend' is invalid");
+ Q_ASSERT_X(isValidIterator(abegin), "QVarLengthArray::erase", "The specified const_iterator argument 'abegin' is invalid");
+ Q_ASSERT_X(isValidIterator(aend), "QVarLengthArray::erase", "The specified const_iterator argument 'aend' is invalid");
qsizetype f = qsizetype(abegin - cbegin());
qsizetype l = qsizetype(aend - cbegin());
@@ -958,10 +968,11 @@ Q_OUTOFLINE_TEMPLATE auto QVLABase<T>::erase(const_iterator abegin, const_iterat
Q_ASSERT(n > 0); // aend must be reachable from abegin
- if constexpr (QTypeInfo<T>::isComplex) {
+ if constexpr (!QTypeInfo<T>::isRelocatable) {
std::move(begin() + l, end(), QT_MAKE_CHECKED_ARRAY_ITERATOR(begin() + f, size() - f));
std::destroy(end() - n, end());
} else {
+ std::destroy(abegin, aend);
memmove(static_cast<void *>(data() + f), static_cast<const void *>(data() + l), (size() - l) * sizeof(T));
}
this->s -= n;
diff --git a/src/corelib/tools/qvarlengtharray.qdoc b/src/corelib/tools/qvarlengtharray.qdoc
index 3ad8a82857..4467e0c65a 100644
--- a/src/corelib/tools/qvarlengtharray.qdoc
+++ b/src/corelib/tools/qvarlengtharray.qdoc
@@ -98,18 +98,16 @@
\since 5.5
Constructs an array from the std::initializer_list given by \a args.
-
- This constructor is only enabled if the compiler supports C++11 initializer
- lists.
*/
-/*! \fn template<class T, qsizetype Prealloc> template<typename InputIterator, if_input_iterator<InputIterator>> QVarLengthArray<T, Prealloc>::QVarLengthArray(InputIterator first, InputIterator last)
+/*! \fn template<class T, qsizetype Prealloc> template<typename InputIterator, QVarLengthArray<T, Prealloc>::if_input_iterator<InputIterator>> QVarLengthArray<T, Prealloc>::QVarLengthArray(InputIterator first, InputIterator last)
\since 5.14
Constructs an array with the contents in the iterator range [\a first, \a last).
This constructor only participates in overload resolution if
- \c InputIterator models the \c std::input_iterator concept.
+ \c InputIterator meets the requirements of an
+ \l {https://en.cppreference.com/w/cpp/named_req/InputIterator} {LegacyInputIterator}.
The value type of \c InputIterator must be convertible to \c T.
*/
@@ -142,6 +140,15 @@
\sa isEmpty(), resize()
*/
+/*! \fn template<class T, qsizetype Prealloc> qsizetype QVarLengthArray<T, Prealloc>::max_size()
+ \since 6.8
+
+ This function is provided for STL compatibility.
+ It returns the maximum number of elements that the array can
+ theoretically hold. In practice, the number can be much smaller,
+ limited by the amount of memory available to the system.
+*/
+
/*! \fn template<class T, qsizetype Prealloc> T& QVarLengthArray<T, Prealloc>::first()
Returns a reference to the first item in the array. The array must
@@ -423,9 +430,6 @@
\since 5.5
Assigns the values of \a list to this array, and returns a reference to this array.
-
- This constructor is only enabled if the compiler supports C++11 initializer
- lists.
*/
/*! \fn template<class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>::QVarLengthArray(const QVarLengthArray<T, Prealloc> &other)
@@ -467,6 +471,15 @@
\a defaultValue.
*/
+/*
+ \var QVarLengthArray::PreallocatedSize
+ \since 6.8
+
+ The same value as the \c{Prealloc} template argument. Provided for easier
+ access compared to manually extracting the value from the template
+ argument.
+*/
+
/*!
\typedef QVarLengthArray::size_type
\since 4.7
@@ -996,7 +1009,7 @@
\sa erase()
*/
-/*! \fn template <class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::assign(qsizetype n, const T &t)
+/*! \fn template <class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>& QVarLengthArray<T, Prealloc>::assign(qsizetype n, const T &t)
\since 6.6
Replaces the contents of this container with \a n copies of \a t.
@@ -1005,7 +1018,7 @@
allocate memory if \a n exceeds the capacity of the container.
*/
-/*! \fn template <class T, qsizetype Prealloc> template <typename InputIterator, if_input_iterator<InputIterator>> void QVarLengthArray<T, Prealloc>::assign(InputIterator first, InputIterator last)
+/*! \fn template <class T, qsizetype Prealloc> template <typename InputIterator, QVarLengthArray<T, Prealloc>::if_input_iterator<InputIterator>> QVarLengthArray<T, Prealloc>& QVarLengthArray<T, Prealloc>::assign(InputIterator first, InputIterator last)
\since 6.6
Replaces the contents of this container with a copy of the elements in the
@@ -1016,11 +1029,13 @@
number of elements in the range exceeds the capacity of the container.
This function overload only participates in overload resolution if
- \c InputIterator models the \c std::input_iterator concept.
+ \c InputIterator meets the requirements of an
+ \l {https://en.cppreference.com/w/cpp/named_req/InputIterator} {LegacyInputIterator}.
+
The behavior is undefined if either argument is an iterator into *this.
*/
-/*! \fn template <class T, qsizetype Prealloc> void QVarLengthArray<T, Prealloc>::assign(std::initializer_list<T> list)
+/*! \fn template <class T, qsizetype Prealloc> QVarLengthArray<T, Prealloc>& QVarLengthArray<T, Prealloc>::assign(std::initializer_list<T> list)
\since 6.6
Replaces the contents of this container with a copy of the elements of \a list.
diff --git a/src/corelib/tools/qversionnumber.cpp b/src/corelib/tools/qversionnumber.cpp
index dcb2a3ad64..4b8ace71cc 100644
--- a/src/corelib/tools/qversionnumber.cpp
+++ b/src/corelib/tools/qversionnumber.cpp
@@ -22,7 +22,6 @@
QT_BEGIN_NAMESPACE
QT_IMPL_METATYPE_EXTERN(QVersionNumber)
-QT_IMPL_METATYPE_EXTERN(QTypeRevision)
/*!
\class QVersionNumber
@@ -72,25 +71,23 @@ QT_IMPL_METATYPE_EXTERN(QTypeRevision)
\fn QVersionNumber::QVersionNumber(QList<int> &&seg)
Move-constructs a version number from the list of numbers contained in \a seg.
-
- This constructor is only enabled if the compiler supports C++11 move semantics.
*/
/*!
\fn QVersionNumber::QVersionNumber(std::initializer_list<int> args)
- Construct a version number from the std::initializer_list specified by
+ Constructs a version number from the std::initializer_list specified by
\a args.
-
- This constructor is only enabled if the compiler supports C++11 initializer
- lists.
*/
/*!
- \fn template <qsizetype N> QVersionNumber::QVersionNumber(const QVarLengthArray<int, N> &seg)
- \since 6.4
+ \fn QVersionNumber::QVersionNumber(QSpan<const int> args)
+ \since 6.8
- Constructs a version number from the list of numbers contained in \a seg.
+ Constructs a version number from the span specified by \a args.
+
+ \note In Qt versions prior to 6.8, QVersionNumber could only be constructed
+ from QList, QVarLenthArray or std::initializer_list.
*/
/*!
@@ -178,6 +175,55 @@ QList<int> QVersionNumber::segments() const
*/
/*!
+ \typedef QVersionNumber::const_iterator
+ \typedef QVersionNumber::const_reverse_iterator
+ \since 6.8
+
+ Typedefs for an opaque class that implements a (reverse) random-access
+ iterator over QVersionNumber segments.
+
+ \note QVersionNumber does not support modifying segments in-place, so
+ there is no mutable iterator.
+*/
+
+/*!
+ \typedef QVersionNumber::value_type
+ \typedef QVersionNumber::difference_type
+ \typedef QVersionNumber::size_type
+ \typedef QVersionNumber::reference
+ \typedef QVersionNumber::const_reference
+ \typedef QVersionNumber::pointer
+ \typedef QVersionNumber::const_pointer
+ \since 6.8
+
+ Provided for STL-compatibility.
+
+ \note QVersionNumber does not support modifying segments in-place, so
+ reference and const_reference, as well as pointer and const_pointer are
+ pairwise the same types.
+*/
+
+/*!
+ \fn QVersionNumber::begin() const
+ \fn QVersionNumber::end() const;
+ \fn QVersionNumber::rbegin() const
+ \fn QVersionNumber::rend() const;
+ \fn QVersionNumber::cbegin() const
+ \fn QVersionNumber::cend() const;
+ \fn QVersionNumber::crbegin() const
+ \fn QVersionNumber::crend() const;
+ \fn QVersionNumber::constBegin() const;
+ \fn QVersionNumber::constEnd() const;
+ \since 6.8
+
+ Returns a const_iterator or const_reverse_iterator, respectively, pointing
+ to the first or one past the last segment of this version number.
+
+ \note QVersionNumber does not support modifying segments in-place, so
+ there is no mutable iterator.
+*/
+
+/*!
\fn QVersionNumber QVersionNumber::normalized() const
Returns an equivalent version number but with all trailing zeros removed.
@@ -538,198 +584,4 @@ size_t qHash(const QVersionNumber &key, size_t seed)
return seed;
}
-/*!
- \class QTypeRevision
- \inmodule QtCore
- \since 6.0
- \brief The QTypeRevision class contains a lightweight representation of
- a version number with two 8-bit segments, major and minor, either
- of which can be unknown.
-
- Use this class to describe revisions of a type. Compatible revisions can be
- expressed as increments of the minor version. Breaking changes can be
- expressed as increments of the major version. The return values of
- \l QMetaMethod::revision() and \l QMetaProperty::revision() can be passed to
- \l QTypeRevision::fromEncodedVersion(). The resulting major and minor versions
- specify in which Qt versions the properties and methods were added.
-
- \sa QMetaMethod::revision(), QMetaProperty::revision()
-*/
-
-/*!
- \fn template<typename Integer> static bool QTypeRevision::isValidSegment(Integer segment)
-
- Returns true if the given number can be used as either major or minor
- version in a QTypeRevision. The valid range for \a segment is \c {>= 0} and \c {< 255}.
-*/
-
-/*!
- \fn QTypeRevision::QTypeRevision()
-
- Produces an invalid revision.
-
- \sa isValid()
-*/
-
-/*!
- \fn template <typename Major, typename Minor> static QTypeRevision QTypeRevision::fromVersion(Major majorVersion, Minor minorVersion)
-
- Produces a QTypeRevision from the given \a majorVersion and \a minorVersion,
- both of which need to be a valid segments.
-
- \sa isValidSegment()
-*/
-
-/*!
- \fn template <typename Major> static QTypeRevision QTypeRevision::fromMajorVersion(Major majorVersion)
-
- Produces a QTypeRevision from the given \a majorVersion with an invalid minor
- version. \a majorVersion needs to be a valid segment.
-
- \sa isValidSegment()
-*/
-
-/*!
- \fn template <typename Minor> static QTypeRevision QTypeRevision::fromMinorVersion(Minor minorVersion)
-
- Produces a QTypeRevision from the given \a minorVersion with an invalid major
- version. \a minorVersion needs to be a valid segment.
-
- \sa isValidSegment()
-*/
-
-/*!
- \fn template <typename Integer> static QTypeRevision QTypeRevision::fromEncodedVersion(Integer value)
-
- Produces a QTypeRevision from the given \a value. \a value encodes both the
- minor and major versions in the least significant and second least
- significant byte, respectively.
-
- \a value must not have any bits outside the least significant two bytes set.
- \c Integer needs to be at least 16 bits wide, and must not have a sign bit
- in the least significant 16 bits.
-
- \sa toEncodedVersion()
-*/
-
-/*!
- \fn static QTypeRevision QTypeRevision::zero()
-
- Produces a QTypeRevision with major and minor version \c{0}.
-*/
-
-/*!
- \fn bool QTypeRevision::hasMajorVersion() const
-
- Returns true if the major version is known, otherwise false.
-
- \sa majorVersion(), hasMinorVersion()
-*/
-
-/*!
- \fn quint8 QTypeRevision::majorVersion() const
-
- Returns the major version encoded in the revision.
-
- \sa hasMajorVersion(), minorVersion()
-*/
-
-/*!
- \fn bool QTypeRevision::hasMinorVersion() const
-
- Returns true if the minor version is known, otherwise false.
-
- \sa minorVersion(), hasMajorVersion()
-*/
-
-/*!
- \fn quint8 QTypeRevision::minorVersion() const
-
- Returns the minor version encoded in the revision.
-
- \sa hasMinorVersion(), majorVersion()
-*/
-
-/*!
- \fn bool QTypeRevision::isValid() const
-
- Returns true if the major version or the minor version is known,
- otherwise false.
-
- \sa hasMajorVersion(), hasMinorVersion()
-*/
-
-/*!
- \fn template<typename Integer> Integer QTypeRevision::toEncodedVersion() const
-
- Transforms the revision into an integer value, encoding the minor
- version into the least significant byte, and the major version into
- the second least significant byte.
-
- \c Integer needs to be at least 16 bits wide, and must not have a sign bit
- in the least significant 16 bits.
-
- \sa fromEncodedVersion()
-*/
-
-#ifndef QT_NO_DATASTREAM
-/*!
- \fn QDataStream& operator<<(QDataStream &out, const QTypeRevision &revision)
- \relates QTypeRevision
- \since 6.0
-
- Writes the revision \a revision to stream \a out.
- */
-QDataStream &operator<<(QDataStream &out, const QTypeRevision &revision)
-{
- return out << revision.toEncodedVersion<quint16>();
-}
-
-/*!
- \fn QDataStream& operator>>(QDataStream &in, QTypeRevision &revision)
- \relates QTypeRevision
- \since 6.0
-
- Reads a revision from stream \a in and stores it in \a revision.
- */
-QDataStream &operator>>(QDataStream &in, QTypeRevision &revision)
-{
- quint16 value;
- in >> value;
- revision = QTypeRevision::fromEncodedVersion(value);
- return in;
-}
-#endif
-
-#ifndef QT_NO_DEBUG_STREAM
-QDebug operator<<(QDebug debug, const QTypeRevision &revision)
-{
- QDebugStateSaver saver(debug);
- if (revision.hasMajorVersion()) {
- if (revision.hasMinorVersion())
- debug.nospace() << revision.majorVersion() << '.' << revision.minorVersion();
- else
- debug.nospace().noquote() << revision.majorVersion() << ".x";
- } else {
- if (revision.hasMinorVersion())
- debug << revision.minorVersion();
- else
- debug.noquote() << "invalid";
- }
- return debug;
-}
-#endif
-
-/*!
- \relates QHash
- \since 6.0
-
- Returns the hash value for the \a key, using \a seed to seed the
- calculation.
-*/
-size_t qHash(const QTypeRevision &key, size_t seed)
-{
- return qHash(key.toEncodedVersion<quint16>(), seed);
-}
-
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qversionnumber.h b/src/corelib/tools/qversionnumber.h
index a7c2b44a7e..95217a6eff 100644
--- a/src/corelib/tools/qversionnumber.h
+++ b/src/corelib/tools/qversionnumber.h
@@ -6,12 +6,16 @@
#ifndef QVERSIONNUMBER_H
#define QVERSIONNUMBER_H
+#include <QtCore/qcontainertools_impl.h>
#include <QtCore/qlist.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qnamespace.h>
+#include <QtCore/qspan.h>
#include <QtCore/qstring.h>
#include <QtCore/qtypeinfo.h>
-#include <limits>
+#if !defined(QT_LEAN_HEADERS) || QT_LEAN_HEADERS < 2
+#include <QtCore/qtyperevision.h>
+#endif // lean headers level 2
QT_BEGIN_NAMESPACE
@@ -110,7 +114,7 @@ class QVersionNumber
Q_CORE_EXPORT void setListData(QList<int> &&seg);
- explicit SegmentStorage(std::initializer_list<int> args)
+ explicit SegmentStorage(QSpan<const int> args)
: SegmentStorage(args.begin(), args.end()) {}
explicit SegmentStorage(const int *first, const int *last)
@@ -188,23 +192,85 @@ class QVersionNumber
Q_CORE_EXPORT void setVector(int len, int maj, int min, int mic);
} m_segments;
+ class It
+ {
+ const QVersionNumber *v;
+ qsizetype i;
+
+ friend class QVersionNumber;
+ explicit constexpr It(const QVersionNumber *vn, qsizetype idx) noexcept : v(vn), i(idx) {}
+
+ friend constexpr bool comparesEqual(const It &lhs, const It &rhs)
+ { Q_ASSERT(lhs.v == rhs.v); return lhs.i == rhs.i; }
+ friend constexpr Qt::strong_ordering compareThreeWay(const It &lhs, const It &rhs)
+ { Q_ASSERT(lhs.v == rhs.v); return Qt::compareThreeWay(lhs.i, rhs.i); }
+ Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(It)
+
+ public:
+ // Rule Of Zero applies
+ It() = default;
+
+ using iterator_category = std::random_access_iterator_tag;
+ using value_type = int;
+#ifdef QT_COMPILER_HAS_LWG3346
+ using element_type = const int;
+#endif
+ using difference_type = qptrdiff; // difference to container requirements
+ using size_type = qsizetype; // difference to container requirements
+ using reference = value_type; // difference to container requirements
+ using pointer = QtPrivate::ArrowProxy<reference>;
+
+ reference operator*() const { return v->segmentAt(i); }
+ pointer operator->() const { return {**this}; }
+
+ It &operator++() { ++i; return *this; }
+ It operator++(int) { auto copy = *this; ++*this; return copy; }
+
+ It &operator--() { --i; return *this; }
+ It operator--(int) { auto copy = *this; --*this; return copy; }
+
+ It &operator+=(difference_type n) { i += n; return *this; }
+ friend It operator+(It it, difference_type n) { it += n; return it; }
+ friend It operator+(difference_type n, It it) { return it + n; }
+
+ It &operator-=(difference_type n) { i -= n; return *this; }
+ friend It operator-(It it, difference_type n) { it -= n; return it; }
+
+ friend difference_type operator-(It lhs, It rhs)
+ { Q_ASSERT(lhs.v == rhs.v); return lhs.i - rhs.i; }
+
+ reference operator[](difference_type n) const { return *(*this + n); }
+ };
+
public:
+ using const_iterator = It;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ using value_type = It::value_type;
+ using difference_type = It::difference_type;
+ using size_type = It::size_type;
+ using reference = It::reference;
+ using const_reference = reference;
+ using pointer = It::pointer;
+ using const_pointer = pointer;
+
inline QVersionNumber() noexcept
: m_segments()
{}
+ Q_WEAK_OVERLOAD
inline explicit QVersionNumber(const QList<int> &seg) : m_segments(seg) { }
// compiler-generated copy/move ctor/assignment operators and the destructor are ok
+ Q_WEAK_OVERLOAD
explicit QVersionNumber(QList<int> &&seg) : m_segments(std::move(seg)) { }
inline QVersionNumber(std::initializer_list<int> args)
- : m_segments(args)
+ : m_segments(QSpan{args})
{}
- template <qsizetype N>
- explicit QVersionNumber(const QVarLengthArray<int, N> &sec)
- : m_segments(sec.begin(), sec.end())
+ explicit QVersionNumber(QSpan<const int> args)
+ : m_segments(args)
{}
inline explicit QVersionNumber(int maj)
@@ -241,6 +307,19 @@ public:
[[nodiscard]] inline qsizetype segmentCount() const noexcept
{ return m_segments.size(); }
+ [[nodiscard]] const_iterator begin() const noexcept { return const_iterator{this, 0}; }
+ [[nodiscard]] const_iterator end() const noexcept { return begin() + segmentCount(); }
+ [[nodiscard]] const_iterator cbegin() const noexcept { return begin(); }
+ [[nodiscard]] const_iterator cend() const noexcept { return end(); }
+
+ [[nodiscard]] const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator{end()}; }
+ [[nodiscard]] const_reverse_iterator rend() const noexcept { return const_reverse_iterator{begin()}; }
+ [[nodiscard]] const_reverse_iterator crbegin() const noexcept { return rbegin(); }
+ [[nodiscard]] const_reverse_iterator crend() const noexcept { return rend(); }
+
+ [[nodiscard]] const_iterator constBegin() const noexcept { return begin(); }
+ [[nodiscard]] const_iterator constEnd() const noexcept { return end(); }
+
[[nodiscard]] Q_CORE_EXPORT bool isPrefixOf(const QVersionNumber &other) const noexcept;
[[nodiscard]] Q_CORE_EXPORT static int compare(const QVersionNumber &v1, const QVersionNumber &v2) noexcept;
@@ -307,160 +386,8 @@ Q_DECLARE_TYPEINFO(QVersionNumber, Q_RELOCATABLE_TYPE);
Q_CORE_EXPORT QDebug operator<<(QDebug, const QVersionNumber &version);
#endif
-class QTypeRevision;
-Q_CORE_EXPORT size_t qHash(const QTypeRevision &key, size_t seed = 0);
-
-#ifndef QT_NO_DATASTREAM
-Q_CORE_EXPORT QDataStream& operator<<(QDataStream &out, const QTypeRevision &revision);
-Q_CORE_EXPORT QDataStream& operator>>(QDataStream &in, QTypeRevision &revision);
-#endif
-
-class QTypeRevision
-{
-public:
- template<typename Integer>
- using if_valid_segment_type = typename std::enable_if<
- std::is_integral<Integer>::value, bool>::type;
-
- template<typename Integer>
- using if_valid_value_type = typename std::enable_if<
- std::is_integral<Integer>::value
- && (sizeof(Integer) > sizeof(quint16)
- || (sizeof(Integer) == sizeof(quint16)
- && !std::is_signed<Integer>::value)), bool>::type;
-
- template<typename Integer, if_valid_segment_type<Integer> = true>
- static constexpr bool isValidSegment(Integer segment)
- {
- // using extra parentheses around max to avoid expanding it if it is a macro
- return segment >= Integer(0)
- && ((std::numeric_limits<Integer>::max)() < Integer(SegmentUnknown)
- || segment < Integer(SegmentUnknown));
- }
-
- template<typename Major, typename Minor,
- if_valid_segment_type<Major> = true,
- if_valid_segment_type<Minor> = true>
- static constexpr QTypeRevision fromVersion(Major majorVersion, Minor minorVersion)
- {
- return Q_ASSERT(isValidSegment(majorVersion)),
- Q_ASSERT(isValidSegment(minorVersion)),
- QTypeRevision(quint8(majorVersion), quint8(minorVersion));
- }
-
- template<typename Major, if_valid_segment_type<Major> = true>
- static constexpr QTypeRevision fromMajorVersion(Major majorVersion)
- {
- return Q_ASSERT(isValidSegment(majorVersion)),
- QTypeRevision(quint8(majorVersion), SegmentUnknown);
- }
-
- template<typename Minor, if_valid_segment_type<Minor> = true>
- static constexpr QTypeRevision fromMinorVersion(Minor minorVersion)
- {
- return Q_ASSERT(isValidSegment(minorVersion)),
- QTypeRevision(SegmentUnknown, quint8(minorVersion));
- }
-
- template<typename Integer, if_valid_value_type<Integer> = true>
- static constexpr QTypeRevision fromEncodedVersion(Integer value)
- {
- return Q_ASSERT((value & ~Integer(0xffff)) == Integer(0)),
- QTypeRevision((value & Integer(0xff00)) >> 8, value & Integer(0xff));
- }
-
- static constexpr QTypeRevision zero() { return QTypeRevision(0, 0); }
-
- constexpr QTypeRevision() = default;
-
- constexpr bool hasMajorVersion() const { return m_majorVersion != SegmentUnknown; }
- constexpr quint8 majorVersion() const { return m_majorVersion; }
-
- constexpr bool hasMinorVersion() const { return m_minorVersion != SegmentUnknown; }
- constexpr quint8 minorVersion() const { return m_minorVersion; }
-
- constexpr bool isValid() const { return hasMajorVersion() || hasMinorVersion(); }
-
- template<typename Integer, if_valid_value_type<Integer> = true>
- constexpr Integer toEncodedVersion() const
- {
- return Integer(m_majorVersion << 8) | Integer(m_minorVersion);
- }
-
- [[nodiscard]] friend constexpr bool operator==(QTypeRevision lhs, QTypeRevision rhs)
- {
- return lhs.toEncodedVersion<quint16>() == rhs.toEncodedVersion<quint16>();
- }
-
- [[nodiscard]] friend constexpr bool operator!=(QTypeRevision lhs, QTypeRevision rhs)
- {
- return lhs.toEncodedVersion<quint16>() != rhs.toEncodedVersion<quint16>();
- }
-
- [[nodiscard]] friend constexpr bool operator<(QTypeRevision lhs, QTypeRevision rhs)
- {
- return (!lhs.hasMajorVersion() && rhs.hasMajorVersion())
- // non-0 major > unspecified major > major 0
- ? rhs.majorVersion() != 0
- : ((lhs.hasMajorVersion() && !rhs.hasMajorVersion())
- // major 0 < unspecified major < non-0 major
- ? lhs.majorVersion() == 0
- : (lhs.majorVersion() != rhs.majorVersion()
- // both majors specified and non-0
- ? lhs.majorVersion() < rhs.majorVersion()
- : ((!lhs.hasMinorVersion() && rhs.hasMinorVersion())
- // non-0 minor > unspecified minor > minor 0
- ? rhs.minorVersion() != 0
- : ((lhs.hasMinorVersion() && !rhs.hasMinorVersion())
- // minor 0 < unspecified minor < non-0 minor
- ? lhs.minorVersion() == 0
- // both minors specified and non-0
- : lhs.minorVersion() < rhs.minorVersion()))));
- }
-
- [[nodiscard]] friend constexpr bool operator>(QTypeRevision lhs, QTypeRevision rhs)
- {
- return lhs != rhs && !(lhs < rhs);
- }
-
- [[nodiscard]] friend constexpr bool operator<=(QTypeRevision lhs, QTypeRevision rhs)
- {
- return lhs == rhs || lhs < rhs;
- }
-
- [[nodiscard]] friend constexpr bool operator>=(QTypeRevision lhs, QTypeRevision rhs)
- {
- return lhs == rhs || !(lhs < rhs);
- }
-
-private:
- enum { SegmentUnknown = 0xff };
-
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- constexpr QTypeRevision(quint8 major, quint8 minor)
- : m_minorVersion(minor), m_majorVersion(major) {}
-
- quint8 m_minorVersion = SegmentUnknown;
- quint8 m_majorVersion = SegmentUnknown;
-#else
- constexpr QTypeRevision(quint8 major, quint8 minor)
- : m_majorVersion(major), m_minorVersion(minor) {}
-
- quint8 m_majorVersion = SegmentUnknown;
- quint8 m_minorVersion = SegmentUnknown;
-#endif
-};
-
-static_assert(sizeof(QTypeRevision) == 2);
-Q_DECLARE_TYPEINFO(QTypeRevision, Q_RELOCATABLE_TYPE);
-
-#ifndef QT_NO_DEBUG_STREAM
-Q_CORE_EXPORT QDebug operator<<(QDebug, const QTypeRevision &revision);
-#endif
-
QT_END_NAMESPACE
QT_DECL_METATYPE_EXTERN(QVersionNumber, Q_CORE_EXPORT)
-QT_DECL_METATYPE_EXTERN(QTypeRevision, Q_CORE_EXPORT)
#endif // QVERSIONNUMBER_H
diff --git a/src/corelib/tracing/qctf.cpp b/src/corelib/tracing/qctf.cpp
index 1dafa582d9..ff81d0a678 100644
--- a/src/corelib/tracing/qctf.cpp
+++ b/src/corelib/tracing/qctf.cpp
@@ -7,6 +7,7 @@
#include <qpluginloader.h>
#include <qfileinfo.h>
#include <qdir.h>
+#include <qjsonarray.h>
#include "qctf_p.h"
@@ -15,8 +16,11 @@ QT_BEGIN_NAMESPACE
static bool s_initialized = false;
static bool s_triedLoading = false;
static bool s_prevent_recursion = false;
+static bool s_shutdown = false;
static QCtfLib* s_plugin = nullptr;
+#if QT_CONFIG(library) && defined(QT_SHARED)
+
#if defined(Q_OS_ANDROID)
static QString findPlugin(const QString &plugin)
{
@@ -59,18 +63,37 @@ static bool loadPlugin(bool &retry)
s_plugin = qobject_cast<QCtfLib *>(loader.instance());
if (!s_plugin)
return false;
- QObject *obj = loader.instance();
- if (obj) {
- QObject::connect(obj, &QObject::destroyed, []() {
- s_plugin = nullptr;
- });
- }
+ s_plugin->shutdown(&s_shutdown);
return true;
}
+#else
+
+#define QCtfPluginIID QStringLiteral("org.qt-project.Qt.QCtfLib")
+
+static bool loadPlugin(bool &retry)
+{
+ retry = false;
+ const auto &plugins = QPluginLoader::staticPlugins();
+ for (const auto &plugin : plugins) {
+ const auto json = plugin.metaData();
+ const auto IID = json[QStringLiteral("IID")];
+ if (IID.toString() == QCtfPluginIID) {
+ s_plugin = qobject_cast<QCtfLib *>(plugin.instance());
+ if (!s_plugin)
+ return false;
+ s_plugin->shutdown(&s_shutdown);
+ return true;
+ }
+ }
+ return false;
+}
+
+#endif
+
static bool initialize()
{
- if (s_prevent_recursion)
+ if (s_shutdown || s_prevent_recursion)
return false;
if (s_initialized || s_triedLoading)
return s_initialized;
@@ -117,3 +140,5 @@ QCtfTracePointPrivate *_initialize_tracepoint(const QCtfTracePointEvent &point)
}
QT_END_NAMESPACE
+
+#include "moc_qctf_p.cpp"
diff --git a/src/corelib/tracing/qctf_p.h b/src/corelib/tracing/qctf_p.h
index 8bd4a218c0..70d00d018c 100644
--- a/src/corelib/tracing/qctf_p.h
+++ b/src/corelib/tracing/qctf_p.h
@@ -19,8 +19,6 @@
#include <qtcoreexports.h>
#include <qobject.h>
-QT_REQUIRE_CONFIG(library);
-
QT_BEGIN_NAMESPACE
struct QCtfTraceMetadata;
@@ -224,12 +222,15 @@ inline QByteArray toByteArrayFromFlags(QFlags<T> value)
class Q_CORE_EXPORT QCtfLib : public QObject
{
Q_OBJECT
+ Q_DISABLE_COPY(QCtfLib)
public:
+ explicit QCtfLib(QObject *parent = nullptr) : QObject(parent) {}
virtual ~QCtfLib() = default;
virtual bool tracepointEnabled(const QCtfTracePointEvent &point) = 0;
virtual void doTracepoint(const QCtfTracePointEvent &point, const QByteArray &arr) = 0;
virtual bool sessionEnabled() = 0;
virtual QCtfTracePointPrivate *initializeTracepoint(const QCtfTracePointEvent &point) = 0;
+ virtual void shutdown(bool *shutdown) = 0;
};
QT_END_NAMESPACE
diff --git a/src/dbus/CMakeLists.txt b/src/dbus/CMakeLists.txt
index 8022f265b2..9c3f6d23d2 100644
--- a/src/dbus/CMakeLists.txt
+++ b/src/dbus/CMakeLists.txt
@@ -15,7 +15,7 @@ qt_internal_add_module(DBus
qdbusargument.cpp qdbusargument.h qdbusargument_p.h
qdbusconnection.cpp qdbusconnection.h qdbusconnection_p.h
qdbusconnectioninterface.cpp qdbusconnectioninterface.h
- qdbusconnectionmanager_p.h
+ qdbusconnectionmanager.cpp qdbusconnectionmanager_p.h
qdbuscontext.cpp qdbuscontext.h qdbuscontext_p.h
qdbuserror.cpp qdbuserror.h
qdbusextratypes.cpp qdbusextratypes.h
@@ -40,9 +40,14 @@ qt_internal_add_module(DBus
qdbusxmlgenerator.cpp
qdbusxmlparser.cpp qdbusxmlparser_p.h
qtdbusglobal.h qtdbusglobal_p.h
+ NO_UNITY_BUILD_SOURCES
+ qdbusconnectionmanager.cpp # qt_windows.h clashing with "interface"
DEFINES
DBUS_API_SUBJECT_TO_CHANGE
+ QT_NO_CONTEXTLESS_CONNECT
QT_NO_FOREACH
+ QT_NO_QPAIR
+ QT_USE_NODISCARD_FILE_OPEN
LIBRARIES
Qt::CorePrivate
PUBLIC_LIBRARIES
@@ -52,8 +57,9 @@ qt_internal_add_module(DBus
GENERATE_CPP_EXPORTS
)
+# This file is included by qdbusargument.cpp
set_source_files_properties(qdbusmarshaller.cpp
- PROPERTIES HEADER_FILE_ONLY ON) # special case: This file is included by qdbusargument.cpp
+ PROPERTIES HEADER_FILE_ONLY ON)
## Scopes:
#####################################################################
diff --git a/src/dbus/doc/qtdbus.qdocconf b/src/dbus/doc/qtdbus.qdocconf
index 7befc5b9e7..90ee5743ff 100644
--- a/src/dbus/doc/qtdbus.qdocconf
+++ b/src/dbus/doc/qtdbus.qdocconf
@@ -66,5 +66,5 @@ navigation.cppclassespage = "Qt D-Bus C++ Classes"
manifestmeta.thumbnail.names = "QtDBus/D-Bus Ping Pong" \
"QtDBus/D-Bus Complex Ping Pong"
-# Fail the documentation build if there are more warnings than the limit
+# Enforce zero documentation warnings
warninglimit = 0
diff --git a/src/dbus/doc/snippets/CMakeLists.txt b/src/dbus/doc/snippets/CMakeLists.txt
index 81f53ade30..4b4751d4fa 100644
--- a/src/dbus/doc/snippets/CMakeLists.txt
+++ b/src/dbus/doc/snippets/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#! [cmake_use]
find_package(Qt6 REQUIRED COMPONENTS DBus)
diff --git a/src/dbus/doc/snippets/cmake/examples.cmake b/src/dbus/doc/snippets/cmake/examples.cmake
index f49e8e6535..2bb6b63abb 100644
--- a/src/dbus/doc/snippets/cmake/examples.cmake
+++ b/src/dbus/doc/snippets/cmake/examples.cmake
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#! [qt_add_dbus_adaptor]
qt_add_dbus_adaptor(GENERATED_SOURCES org.example.chat.xml chat.h ChatMainWindow)
diff --git a/src/dbus/doc/snippets/code/doc_src_introtodbus.qdoc b/src/dbus/doc/snippets/code/doc_src_introtodbus.qdoc
index d39151354a..61afa69790 100644
--- a/src/dbus/doc/snippets/code/doc_src_introtodbus.qdoc
+++ b/src/dbus/doc/snippets/code/doc_src_introtodbus.qdoc
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
//! [0]
org.freedesktop.DBus
diff --git a/src/dbus/doc/snippets/code/src_qdbus_qdbusabstractinterface.cpp b/src/dbus/doc/snippets/code/src_qdbus_qdbusabstractinterface.cpp
index 5348d18ba3..92b9dea909 100644
--- a/src/dbus/doc/snippets/code/src_qdbus_qdbusabstractinterface.cpp
+++ b/src/dbus/doc/snippets/code/src_qdbus_qdbusabstractinterface.cpp
@@ -47,12 +47,22 @@ else
void Abstract_DBus_Interface::asyncCall()
{
//! [1]
-QString value = retrieveValue();
-QDBusPendingCall pcall = interface->asyncCall("Process"_L1, value);
+QDBusPendingCall pcall = interface->asyncCall("GetAPIVersion"_L1);
+auto watcher = new QDBusPendingCallWatcher(pcall, this);
-QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pcall);
+QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this,
+ [&](QDBusPendingCallWatcher *w) {
+ QString value = retrieveValue();
+ QDBusPendingReply<int> reply(*w);
+ QDBusPendingCall pcall;
+ if (reply.argumentAt<0>() >= 14)
+ pcall = interface->asyncCall("ProcessWorkUnicode"_L1, value);
+ else
+ pcall = interface->asyncCall("ProcessWork"_L1, "UTF-8"_L1, value.toUtf8());
-QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
- this, SLOT(callFinishedSlot(QDBusPendingCallWatcher*)));
+ w = new QDBusPendingCallWatcher(pcall);
+ QObject::connect(w, &QDBusPendingCallWatcher::finished, this,
+ &Abstract_DBus_Interface::callFinishedSlot);
+});
//! [1]
}
diff --git a/src/dbus/doc/snippets/code/src_qdbus_qdbuscontext.cpp b/src/dbus/doc/snippets/code/src_qdbus_qdbuscontext.cpp
index 9e4e26cb4e..75b4394595 100644
--- a/src/dbus/doc/snippets/code/src_qdbus_qdbuscontext.cpp
+++ b/src/dbus/doc/snippets/code/src_qdbus_qdbuscontext.cpp
@@ -37,7 +37,7 @@ QString MyObject::methodWithDelayedReply()
conn = connection();
msg = message();
setDelayedReply(true);
- QMetaObject::invokeMethod(this, "process", Qt::QueuedConnection);
+ QMetaObject::invokeMethod(this, &MyObject::process, Qt::QueuedConnection);
return QString();
}
//! [0]
diff --git a/src/dbus/doc/snippets/code/src_qdbus_qdbuspendingcall.cpp b/src/dbus/doc/snippets/code/src_qdbus_qdbuspendingcall.cpp
index c44337ade2..67b019a67d 100644
--- a/src/dbus/doc/snippets/code/src_qdbus_qdbuspendingcall.cpp
+++ b/src/dbus/doc/snippets/code/src_qdbus_qdbuspendingcall.cpp
@@ -33,8 +33,8 @@ void DBus_PendingCall_Interface::callInterfaceMain()
QDBusPendingCall async = iface->asyncCall("RemoteMethod", value1, value2);
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(async, this);
- QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
- this, SLOT(callFinishedSlot(QDBusPendingCallWatcher*)));
+ QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this,
+ &DBus_PendingCall_Interface::callFinishedSlot);
//! [0]
}
diff --git a/src/dbus/doc/src/dbus-adaptors.qdoc b/src/dbus/doc/src/dbus-adaptors.qdoc
index 3dbedbbcce..e57cc095b9 100644
--- a/src/dbus/doc/src/dbus-adaptors.qdoc
+++ b/src/dbus/doc/src/dbus-adaptors.qdoc
@@ -6,7 +6,7 @@
\title Using Qt D-Bus Adaptors
\brief How to create and use DBus adaptors in Qt.
- \ingroup best-practices
+ \ingroup how-to
Adaptors are special classes that are attached to any QObject-derived class
and provide the interface to the external world using D-Bus. Adaptors are
@@ -44,7 +44,7 @@
\li \l{Declaring Slots in D-Bus Adaptors}
\li \l{Declaring Signals in D-Bus Adaptors}
\li \l{The Qt D-Bus Type System}
- \li In the \l{D-Bus Complex Ping Pong Example}, \c complexpong.h and
+ \li In the \l{D-Bus Complex Ping Pong} example, \c complexpong.h and
\c complexpong.cpp show an implementation of QDBusAbstractAdaptor.
\endlist
@@ -87,15 +87,15 @@
Asynchronous slots are marked by the keyword \l Q_NOREPLY in the method
signature, before the \c void return type and the slot name. The \c quit()
- slot in the \l {D-Bus Complex Ping Pong Example} is an example of this.
+ slot in the \l {D-Bus Complex Ping Pong} example is an example of this.
\section1 Input-Only Slots
Input-only slots are normal slots that take parameters passed by value or
by constant reference. However, unlike asynchronous slots, the caller is
usually waiting for completion of the callee before resuming operation.
- Therefore, non-asynchronous slots should not block or should state it its
- documentation that they may do so.
+ Therefore, non-asynchronous slots should not block or should explicitly
+ state it will block in its documentation that they may do so.
Input-only slots have no special marking in their signature, except that
they take only parameters passed by value or by constant reference.
@@ -193,8 +193,8 @@
However, signals must still be emitted. The easiest way to emit an adaptor
signal is to connect another signal to it, so that Qt's signals and slots
mechanism automatically emits the adaptor signal, too. This can be done in
- the adaptor's constructor, as you can see in the \l {D-Bus Complex Ping
- Pong Example}.
+ the adaptor's constructor, as you can see in the \l {D-Bus Complex Ping Pong}
+ example.
The QDBusAbstractAdaptor::setAutoRelaySignals() convenience function can also
be used to make and break connections between signals in the real object and
diff --git a/src/dbus/doc/src/qt6-changes.qdoc b/src/dbus/doc/src/qt6-changes.qdoc
index c9e73a187a..80cd56c627 100644
--- a/src/dbus/doc/src/qt6-changes.qdoc
+++ b/src/dbus/doc/src/qt6-changes.qdoc
@@ -5,7 +5,7 @@
\page dbus-changes-qt6.html
\title Changes to Qt D-Bus
\ingroup changes-qt-5-to-6
- \brief Migrate Qt DBus to Qt 6.
+ \brief Minimal porting effort to be able to switch to Qt 6.
Qt 6 is a result of the conscious effort to make the framework more
efficient and easy to use.
diff --git a/src/dbus/doc/src/qtdbus-cmake.qdoc b/src/dbus/doc/src/qtdbus-cmake.qdoc
index d64b315796..86807af6e5 100644
--- a/src/dbus/doc/src/qtdbus-cmake.qdoc
+++ b/src/dbus/doc/src/qtdbus-cmake.qdoc
@@ -172,7 +172,7 @@ qt_generate_dbus_interface(header
\section1 Description
Parses the C++ source or header file containing a QObject-derived class
-declaration and generates a file containing the D-BUS Introspection XML.
+declaration and generates a file containing the D-Bus Introspection XML.
By default, the generated XML file is stored in the current binary directory,
and has the same base name as the header. You can specify a different name or
diff --git a/src/dbus/doc/src/qtdbus-overview.qdoc b/src/dbus/doc/src/qtdbus-overview.qdoc
index b40caf24a6..6342e674fd 100644
--- a/src/dbus/doc/src/qtdbus-overview.qdoc
+++ b/src/dbus/doc/src/qtdbus-overview.qdoc
@@ -5,6 +5,7 @@
\page qtdbus-overview.html
\title Qt D-Bus Overview
\brief Provides insight into the Qt Qt D-Bus module.
+ \ingroup explanations-networkingandconnectivity
D-Bus is an Inter-Process Communication (IPC) and Remote Procedure
Calling (RPC) mechanism originally developed for Linux to replace
@@ -164,7 +165,7 @@
This feature can be enabled on a per-application basis by setting the
\c QDBUS_DEBUG environment variable before running each application.
For example, we can enable debugging only for the car in the
- \l{D-Bus Remote Controlled Car Example} by running the controller and the
+ \l{D-Bus Remote Controlled Car} example by running the controller and the
car in the following way:
\snippet code/doc_src_introtodbus.qdoc QDBUS_DEBUG
diff --git a/src/dbus/qdbus_symbols.cpp b/src/dbus/qdbus_symbols.cpp
index 676bc3d4be..9788bb98bc 100644
--- a/src/dbus/qdbus_symbols.cpp
+++ b/src/dbus/qdbus_symbols.cpp
@@ -2,7 +2,7 @@
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <QtCore/qglobal.h>
+#include "qdbus_symbols_p.h"
#include <QtCore/qlatin1stringview.h>
#if QT_CONFIG(library)
#include <QtCore/qlibrary.h>
@@ -12,14 +12,10 @@
#ifndef QT_NO_DBUS
-extern "C" void dbus_shutdown();
-
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-void (*qdbus_resolve_me(const char *name))();
-
#if !defined QT_LINKED_LIBDBUS
#if QT_CONFIG(library)
@@ -58,7 +54,7 @@ bool qdbus_loadLibDBus()
lib->setLoadHints(QLibrary::ExportExternalSymbolsHint); // make libdbus symbols available for apps that need more advanced control over the dbus
triedToLoadLibrary = true;
- static int majorversions[] = { 3, 2, -1 };
+ static constexpr int majorversions[] = { 3, 2, -1 };
const QString baseNames[] = {
#ifdef Q_OS_WIN
"dbus-1"_L1,
@@ -92,7 +88,7 @@ bool qdbus_loadLibDBus()
#endif
}
-void (*qdbus_resolve_conditionally(const char *name))()
+QFunctionPointer qdbus_resolve_conditionally(const char *name)
{
#if QT_CONFIG(library)
if (qdbus_loadLibDBus())
@@ -103,7 +99,7 @@ void (*qdbus_resolve_conditionally(const char *name))()
return nullptr;
}
-void (*qdbus_resolve_me(const char *name))()
+QFunctionPointer qdbus_resolve_me(const char *name)
{
#if QT_CONFIG(library)
if (Q_UNLIKELY(!qdbus_loadLibDBus()))
diff --git a/src/dbus/qdbus_symbols_p.h b/src/dbus/qdbus_symbols_p.h
index e3008be761..78b7e049ef 100644
--- a/src/dbus/qdbus_symbols_p.h
+++ b/src/dbus/qdbus_symbols_p.h
@@ -27,6 +27,8 @@
# include "dbus_minimal_p.h"
#endif
+#include <atomic>
+
#ifdef interface
# undef interface
#endif
@@ -35,8 +37,8 @@ QT_BEGIN_NAMESPACE
#if !defined QT_LINKED_LIBDBUS
-void (*qdbus_resolve_conditionally(const char *name))(); // doesn't print a warning
-void (*qdbus_resolve_me(const char *name))(); // prints a warning
+QFunctionPointer qdbus_resolve_conditionally(const char *name); // doesn't print a warning
+QFunctionPointer qdbus_resolve_me(const char *name); // prints a warning
bool qdbus_loadLibDBus();
//# define TRACE_DBUS_CALLS
@@ -114,28 +116,34 @@ template <> struct TraceReturn<void> { typedef void Type; };
# define DEBUGRET(ret)
# endif
-# define DEFINEFUNC(ret, func, args, argcall, funcret) \
- typedef ret (* _q_PTR_##func) args; \
- static inline ret q_##func args \
- { \
- static _q_PTR_##func ptr; \
- DEBUGCALL(#func, argcall); \
- if (!ptr) \
- ptr = (_q_PTR_##func) qdbus_resolve_me(#func); \
- funcret DEBUGRET(ret) ptr argcall; \
+# define DEFINEFUNC(ret, func, args, argcall, funcret) \
+ static inline ret q_##func args \
+ { \
+ using func_ptr = ret (*) args; \
+ static std::atomic<func_ptr> atomic_ptr; \
+ func_ptr ptr = atomic_ptr.load(std::memory_order_relaxed); \
+ DEBUGCALL(#func, argcall); \
+ if (!ptr) { \
+ ptr = reinterpret_cast<func_ptr>(qdbus_resolve_me(#func)); \
+ atomic_ptr.store(ptr, std::memory_order_relaxed); \
+ } \
+ funcret DEBUGRET(ret) ptr argcall; \
}
-# define DEFINEFUNC_CONDITIONALLY(ret, func, args, argcall, funcret, failret) \
- typedef ret (* _q_PTR_##func) args; \
- static inline ret q_##func args \
- { \
- static _q_PTR_##func ptr; \
- DEBUGCALL(#func, argcall); \
- if (!ptr) \
- ptr = (_q_PTR_##func) qdbus_resolve_conditionally(#func); \
- if (!ptr) \
- failret; \
- funcret DEBUGRET(ret) ptr argcall; \
+# define DEFINEFUNC_CONDITIONALLY(ret, func, args, argcall, funcret, failret) \
+ static inline ret q_##func args \
+ { \
+ using func_ptr = ret (*) args; \
+ static std::atomic<func_ptr> atomic_ptr; \
+ func_ptr ptr = atomic_ptr.load(std::memory_order_relaxed); \
+ DEBUGCALL(#func, argcall); \
+ if (!ptr) { \
+ ptr = reinterpret_cast<func_ptr>(qdbus_resolve_conditionally(#func)); \
+ atomic_ptr.store(ptr, std::memory_order_relaxed); \
+ } \
+ if (!ptr) \
+ failret; \
+ funcret DEBUGRET(ret) ptr argcall; \
}
#else // defined QT_LINKED_LIBDBUS
diff --git a/src/dbus/qdbusabstractadaptor.cpp b/src/dbus/qdbusabstractadaptor.cpp
index a53ba41683..afe769fcd0 100644
--- a/src/dbus/qdbusabstractadaptor.cpp
+++ b/src/dbus/qdbusabstractadaptor.cpp
@@ -22,14 +22,10 @@
QT_BEGIN_NAMESPACE
-static int cachedRelaySlotMethodIndex = 0;
-
int QDBusAdaptorConnector::relaySlotMethodIndex()
{
- if (cachedRelaySlotMethodIndex == 0) {
- cachedRelaySlotMethodIndex = staticMetaObject.indexOfMethod("relaySlot()");
- Q_ASSERT(cachedRelaySlotMethodIndex != 0); // 0 should be deleteLater() or destroyed()
- }
+ static const int cachedRelaySlotMethodIndex = staticMetaObject.indexOfMethod("relaySlot()");
+ Q_ASSERT(cachedRelaySlotMethodIndex != 0); // 0 should be deleteLater() or destroyed()
return cachedRelaySlotMethodIndex;
}
@@ -37,11 +33,9 @@ QDBusAdaptorConnector *qDBusFindAdaptorConnector(QObject *obj)
{
if (!obj)
return nullptr;
- const QObjectList &children = obj->children();
- QObjectList::ConstIterator it = children.constBegin();
- QObjectList::ConstIterator end = children.constEnd();
- for ( ; it != end; ++it) {
- QDBusAdaptorConnector *connector = qobject_cast<QDBusAdaptorConnector *>(*it);
+
+ for (QObject *child : std::as_const(obj->children())) {
+ QDBusAdaptorConnector *connector = qobject_cast<QDBusAdaptorConnector *>(child);
if (connector) {
connector->polish();
return connector;
@@ -110,10 +104,13 @@ void QDBusAbstractAdaptorPrivate::saveIntrospectionXml(QDBusAbstractAdaptor *ada
QDBusAbstractAdaptor::QDBusAbstractAdaptor(QObject* obj)
: QObject(*new QDBusAbstractAdaptorPrivate, obj)
{
+
+ Q_ASSERT_X(obj, Q_FUNC_INFO, "Expected non-null parent");
+
QDBusAdaptorConnector *connector = qDBusCreateAdaptorConnector(obj);
connector->waitingForPolish = true;
- QMetaObject::invokeMethod(connector, "polish", Qt::QueuedConnection);
+ QMetaObject::invokeMethod(connector, &QDBusAdaptorConnector::polish, Qt::QueuedConnection);
}
/*!
@@ -227,11 +224,8 @@ void QDBusAdaptorConnector::polish()
return; // avoid working multiple times if multiple adaptors were added
waitingForPolish = false;
- const QObjectList &objs = parent()->children();
- QObjectList::ConstIterator it = objs.constBegin();
- QObjectList::ConstIterator end = objs.constEnd();
- for ( ; it != end; ++it) {
- QDBusAbstractAdaptor *adaptor = qobject_cast<QDBusAbstractAdaptor *>(*it);
+ for (QObject *child : std::as_const(parent()->children())) {
+ QDBusAbstractAdaptor *adaptor = qobject_cast<QDBusAbstractAdaptor *>(child);
if (adaptor)
addAdaptor(adaptor);
}
@@ -260,8 +254,8 @@ void QDBusAdaptorConnector::relay(QObject *senderObj, int lastSignalIdx, void **
// QObject signal (destroyed(QObject *)) -- ignore
return;
- const QMetaObject *senderMetaObject = senderObj->metaObject();
- QMetaMethod mm = senderMetaObject->method(lastSignalIdx);
+ QMetaMethod mm = senderObj->metaObject()->method(lastSignalIdx);
+ const QMetaObject *senderMetaObject = mm.enclosingMetaObject();
QObject *realObject = senderObj;
if (qobject_cast<QDBusAbstractAdaptor *>(senderObj))
diff --git a/src/dbus/qdbusabstractinterface.cpp b/src/dbus/qdbusabstractinterface.cpp
index 60984c99a0..0c6dbf1b3b 100644
--- a/src/dbus/qdbusabstractinterface.cpp
+++ b/src/dbus/qdbusabstractinterface.cpp
@@ -79,6 +79,7 @@ QDBusAbstractInterfacePrivate::QDBusAbstractInterfacePrivate(const QString &serv
lastError(checkIfValid(serv, p, iface, isDynamic, (connectionPrivate() &&
connectionPrivate()->mode == QDBusConnectionPrivate::PeerMode))),
timeout(-1),
+ interactiveAuthorizationAllowed(false),
isValid(!lastError.isValid())
{
if (!isValid)
@@ -222,7 +223,6 @@ void QDBusAbstractInterfacePrivate::_q_serviceOwnerChanged(const QString &name,
const QString &newOwner)
{
Q_UNUSED(oldOwner);
- Q_UNUSED(name);
//qDebug() << "QDBusAbstractInterfacePrivate serviceOwnerChanged" << name << oldOwner << newOwner;
Q_ASSERT(name == service);
currentOwner = newOwner;
@@ -398,6 +398,43 @@ int QDBusAbstractInterface::timeout() const
}
/*!
+ Configures whether, for asynchronous calls, the caller
+ is prepared to wait for interactive authorization.
+
+ If \a enable is set to \c true, the D-Bus messages generated for
+ asynchronous calls via this interface will set the
+ \c ALLOW_INTERACTIVE_AUTHORIZATION flag.
+
+ This flag is only useful when unprivileged code calls a more privileged
+ method call, and an authorization framework is deployed that allows
+ possibly interactive authorization.
+
+ The default is \c false.
+
+ \since 6.7
+ \sa QDBusMessage::setInteractiveAuthorizationAllowed()
+*/
+void QDBusAbstractInterface::setInteractiveAuthorizationAllowed(bool enable)
+{
+ d_func()->interactiveAuthorizationAllowed = enable;
+}
+
+/*!
+ Returns whether, for asynchronous calls, the caller
+ is prepared to wait for interactive authorization.
+
+ The default is \c false.
+
+ \since 6.7
+ \sa setInteractiveAuthorizationAllowed(),
+ QDBusMessage::setInteractiveAuthorizationAllowed()
+*/
+bool QDBusAbstractInterface::isInteractiveAuthorizationAllowed() const
+{
+ return d_func()->interactiveAuthorizationAllowed;
+}
+
+/*!
Places a call to the remote method specified by \a method on this interface, using \a args as
arguments. This function returns the message that was received as a reply, which can be a normal
QDBusMessage::ReplyMessage (indicating success) or QDBusMessage::ErrorMessage (if the call
@@ -476,6 +513,9 @@ QDBusMessage QDBusAbstractInterface::callWithArgumentList(QDBus::CallMode mode,
Normally, you should place calls using asyncCall().
+ \note Method calls to objects registered by the application itself are never
+ asynchronous due to implementation limitations.
+
\threadsafe
*/
QDBusPendingCall QDBusAbstractInterface::asyncCallWithArgumentList(const QString& method,
@@ -489,6 +529,8 @@ QDBusPendingCall QDBusAbstractInterface::asyncCallWithArgumentList(const QString
QDBusMessage msg = QDBusMessage::createMethodCall(service(), path(), interface(), method);
QDBusMessagePrivate::setParametersValidated(msg, true);
msg.setArguments(args);
+ if (d->interactiveAuthorizationAllowed)
+ msg.setInteractiveAuthorizationAllowed(true);
return d->connection.asyncCall(msg, d->timeout);
}
@@ -510,6 +552,9 @@ QDBusPendingCall QDBusAbstractInterface::asyncCallWithArgumentList(const QString
parameter as its last or only parameter. The \a errorMethod must
have a QDBusError as its only parameter.
+ \note Method calls to objects registered by the application itself are never
+ asynchronous due to implementation limitations.
+
\since 4.3
\sa QDBusError, QDBusMessage
*/
@@ -677,6 +722,7 @@ void QDBusAbstractInterface::internalPropSet(const char *propname, const QVarian
This example illustrates function calling with 0, 1 and 2 parameters and illustrates different
parameter types passed in each (the first call to \c "ProcessWorkUnicode" will contain one
Unicode string, the second call to \c "ProcessWork" will contain one string and one byte array).
+ See asyncCall() for the same example in non-blocking (asynchronous) calls.
\note Before Qt 5.14, this function accepted a maximum of just eight (8) arguments.
@@ -734,9 +780,13 @@ void QDBusAbstractInterface::internalPropSet(const char *propname, const QVarian
This example illustrates function calling with 0, 1 and 2 parameters and illustrates different
parameter types passed in each (the first call to \c "ProcessWorkUnicode" will contain one
Unicode string, the second call to \c "ProcessWork" will contain one string and one byte array).
+ See call() for the same example in blocking (synchronous) calls.
\note Before Qt 5.14, this function accepted a maximum of just eight (8) arguments.
+ \note Method calls to local \c{QDBusServer}'s are never asynchronous
+ due to implementation limitations.
+
\sa asyncCallWithArgumentList()
*/
diff --git a/src/dbus/qdbusabstractinterface.h b/src/dbus/qdbusabstractinterface.h
index a87b377b0c..8d36fb3728 100644
--- a/src/dbus/qdbusabstractinterface.h
+++ b/src/dbus/qdbusabstractinterface.h
@@ -63,6 +63,9 @@ public:
void setTimeout(int timeout);
int timeout() const;
+ void setInteractiveAuthorizationAllowed(bool enable);
+ bool isInteractiveAuthorizationAllowed() const;
+
QDBusMessage call(const QString &method)
{
return doCall(QDBus::AutoDetect, method, nullptr, 0);
diff --git a/src/dbus/qdbusabstractinterface_p.h b/src/dbus/qdbusabstractinterface_p.h
index 531be7471c..1bd5e96f2d 100644
--- a/src/dbus/qdbusabstractinterface_p.h
+++ b/src/dbus/qdbusabstractinterface_p.h
@@ -42,6 +42,7 @@ public:
QString interface;
mutable QDBusError lastError;
int timeout;
+ bool interactiveAuthorizationAllowed;
// this is set during creation and never changed
// it can't be const because QDBusInterfacePrivate has one more check
diff --git a/src/dbus/qdbusargument.cpp b/src/dbus/qdbusargument.cpp
index 5187d579cf..99e60244da 100644
--- a/src/dbus/qdbusargument.cpp
+++ b/src/dbus/qdbusargument.cpp
@@ -31,17 +31,17 @@ QDBusArgumentPrivate::~QDBusArgumentPrivate()
q_dbus_message_unref(message);
}
-QByteArray QDBusArgumentPrivate::createSignature(int id)
+QByteArray QDBusArgumentPrivate::createSignature(QMetaType type)
{
if (!qdbus_loadLibDBus())
return "";
QByteArray signature;
- QDBusMarshaller *marshaller = new QDBusMarshaller(0);
+ QDBusMarshaller *marshaller = new QDBusMarshaller;
marshaller->ba = &signature;
// run it
- QVariant v{QMetaType(id)};
+ QVariant v{type};
QDBusArgument arg(marshaller);
QDBusMetaType::marshall(arg, v.metaType(), v.constData());
arg.d = nullptr;
@@ -51,16 +51,16 @@ QByteArray QDBusArgumentPrivate::createSignature(int id)
delete marshaller;
if (signature.isEmpty() || !ok || !QDBusUtil::isValidSingleSignature(QString::fromLatin1(signature))) {
- qWarning("QDBusMarshaller: type '%s' produces invalid D-BUS signature '%s' "
+ qWarning("QDBusMarshaller: type '%s' produces invalid D-Bus signature '%s' "
"(Did you forget to call beginStructure() ?)",
- QMetaType(id).name(), signature.isEmpty() ? "<empty>" : signature.constData());
+ type.name(), signature.isEmpty() ? "<empty>" : signature.constData());
return "";
} else if ((signature.at(0) != DBUS_TYPE_ARRAY && signature.at(0) != DBUS_STRUCT_BEGIN_CHAR) ||
(signature.at(0) == DBUS_TYPE_ARRAY && (signature.at(1) == DBUS_TYPE_BYTE ||
signature.at(1) == DBUS_TYPE_STRING))) {
- qWarning("QDBusMarshaller: type '%s' attempts to redefine basic D-BUS type '%s' (%s) "
+ qWarning("QDBusMarshaller: type '%s' attempts to redefine basic D-Bus type '%s' (%s) "
"(Did you forget to call beginStructure() ?)",
- QMetaType(id).name(), signature.constData(),
+ type.name(), signature.constData(),
QDBusMetaType::signatureToMetaType(signature).name());
return "";
}
@@ -71,7 +71,7 @@ bool QDBusArgumentPrivate::checkWrite(QDBusArgumentPrivate *&d)
{
if (!d)
return false;
- if (d->direction == Marshalling) {
+ if (d->direction == Direction::Marshalling) {
if (!d->marshaller()->ok)
return false;
@@ -99,7 +99,7 @@ bool QDBusArgumentPrivate::checkRead(QDBusArgumentPrivate *d)
{
if (!d)
return false;
- if (d->direction == Demarshalling)
+ if (d->direction == Direction::Demarshalling)
return true;
#ifdef QT_DEBUG
@@ -260,7 +260,7 @@ QDBusArgument::QDBusArgument()
return;
}
- QDBusMarshaller *dd = new QDBusMarshaller(0);
+ QDBusMarshaller *dd = new QDBusMarshaller;
d = dd;
// create a new message with any type, we won't sent it anyways
@@ -537,7 +537,7 @@ QString QDBusArgument::currentSignature() const
{
if (!d)
return QString();
- if (d->direction == QDBusArgumentPrivate::Demarshalling)
+ if (d->direction == QDBusArgumentPrivate::Direction::Demarshalling)
return d->demarshaller()->currentSignature();
else
return d->marshaller()->currentSignature();
@@ -556,14 +556,14 @@ QDBusArgument::ElementType QDBusArgument::currentType() const
{
if (!d)
return UnknownType;
- if (d->direction == QDBusArgumentPrivate::Demarshalling)
+ if (d->direction == QDBusArgumentPrivate::Direction::Demarshalling)
return d->demarshaller()->currentType();
return UnknownType;
}
/*!
- Extracts one D-BUS primitive argument of type \c{BYTE} from the
- D-BUS stream and puts it into \a arg.
+ Extracts one D-Bus primitive argument of type \c{BYTE} from the
+ D-Bus stream and puts it into \a arg.
*/
const QDBusArgument &QDBusArgument::operator>>(uchar &arg) const
{
diff --git a/src/dbus/qdbusargument.h b/src/dbus/qdbusargument.h
index 475c47f442..70f6703d2f 100644
--- a/src/dbus/qdbusargument.h
+++ b/src/dbus/qdbusargument.h
@@ -47,7 +47,7 @@ public:
void swap(QDBusArgument &other) noexcept { qt_ptr_swap(d, other.d); }
- // used for marshalling (Qt -> D-BUS)
+ // used for marshalling (Qt -> D-Bus)
QDBusArgument &operator<<(uchar arg);
QDBusArgument &operator<<(bool arg);
QDBusArgument &operator<<(short arg);
@@ -80,7 +80,7 @@ public:
void appendVariant(const QVariant &v);
- // used for de-marshalling (D-BUS -> Qt)
+ // used for de-marshalling (D-Bus -> Qt)
QString currentSignature() const;
ElementType currentType() const;
@@ -222,10 +222,8 @@ inline const QDBusArgument &operator>>(const QDBusArgument &arg, Container<T> &l
inline QDBusArgument &operator<<(QDBusArgument &arg, const QVariantList &list)
{
arg.beginArray(QMetaType::fromType<QDBusVariant>());
- QVariantList::ConstIterator it = list.constBegin();
- QVariantList::ConstIterator end = list.constEnd();
- for ( ; it != end; ++it)
- arg << QDBusVariant(*it);
+ for (const QVariant &value : list)
+ arg << QDBusVariant(value);
arg.endArray();
return arg;
}
@@ -284,11 +282,9 @@ inline const QDBusArgument &operator>>(const QDBusArgument &arg, Container<Key,
inline QDBusArgument &operator<<(QDBusArgument &arg, const QVariantMap &map)
{
arg.beginMap(QMetaType::fromType<QString>(), QMetaType::fromType<QDBusVariant>());
- QVariantMap::ConstIterator it = map.constBegin();
- QVariantMap::ConstIterator end = map.constEnd();
- for ( ; it != end; ++it) {
+ for (const auto &[key, value] : map.asKeyValueRange()) {
arg.beginMapEntry();
- arg << it.key() << QDBusVariant(it.value());
+ arg << key << QDBusVariant(value);
arg.endMapEntry();
}
arg.endMap();
@@ -298,11 +294,9 @@ inline QDBusArgument &operator<<(QDBusArgument &arg, const QVariantMap &map)
inline QDBusArgument &operator<<(QDBusArgument &arg, const QVariantHash &map)
{
arg.beginMap(QMetaType::fromType<QString>(), QMetaType::fromType<QDBusVariant>());
- QVariantHash::ConstIterator it = map.constBegin();
- QVariantHash::ConstIterator end = map.constEnd();
- for ( ; it != end; ++it) {
+ for (const auto &[key, value] : map.asKeyValueRange()) {
arg.beginMapEntry();
- arg << it.key() << QDBusVariant(it.value());
+ arg << key << QDBusVariant(value);
arg.endMapEntry();
}
arg.endMap();
@@ -310,7 +304,7 @@ inline QDBusArgument &operator<<(QDBusArgument &arg, const QVariantHash &map)
}
template <typename T1, typename T2>
-inline QDBusArgument &operator<<(QDBusArgument &arg, const QPair<T1, T2> &pair)
+inline QDBusArgument &operator<<(QDBusArgument &arg, const std::pair<T1, T2> &pair)
{
arg.beginStructure();
arg << pair.first << pair.second;
@@ -319,7 +313,7 @@ inline QDBusArgument &operator<<(QDBusArgument &arg, const QPair<T1, T2> &pair)
}
template <typename T1, typename T2>
-inline const QDBusArgument &operator>>(const QDBusArgument &arg, QPair<T1, T2> &pair)
+inline const QDBusArgument &operator>>(const QDBusArgument &arg, std::pair<T1, T2> &pair)
{
arg.beginStructure();
arg >> pair.first >> pair.second;
diff --git a/src/dbus/qdbusargument_p.h b/src/dbus/qdbusargument_p.h
index 540692cb9e..d9a7382742 100644
--- a/src/dbus/qdbusargument_p.h
+++ b/src/dbus/qdbusargument_p.h
@@ -17,6 +17,7 @@
#include <QtDBus/private/qtdbusglobal_p.h>
#include <qdbusargument.h>
+#include "qdbusconnection.h"
#include "qdbusunixfiledescriptor.h"
#include "qdbus_symbols_p.h"
@@ -33,10 +34,10 @@ class QDBusMarshaller;
class QDBusDemarshaller;
class QDBusArgumentPrivate
{
+ Q_DISABLE_COPY_MOVE(QDBusArgumentPrivate)
public:
- inline QDBusArgumentPrivate(int flags = 0)
- : message(nullptr), ref(1), capabilities(flags)
- { }
+ enum class Direction { Marshalling, Demarshalling };
+
virtual ~QDBusArgumentPrivate();
static bool checkRead(QDBusArgumentPrivate *d);
@@ -46,7 +47,7 @@ public:
QDBusMarshaller *marshaller();
QDBusDemarshaller *demarshaller();
- static QByteArray createSignature(int id);
+ static QByteArray createSignature(QMetaType type);
static inline QDBusArgument create(QDBusArgumentPrivate *d)
{
QDBusArgument q(d);
@@ -55,21 +56,26 @@ public:
static inline QDBusArgumentPrivate *d(QDBusArgument &q)
{ return q.d; }
-public:
- DBusMessage *message;
- QAtomicInt ref;
- int capabilities;
- enum Direction {
- Marshalling,
- Demarshalling
- } direction;
+ DBusMessage *message = nullptr;
+ QAtomicInt ref = 1;
+ QDBusConnection::ConnectionCapabilities capabilities;
+ Direction direction;
+
+protected:
+ explicit QDBusArgumentPrivate(Direction direction,
+ QDBusConnection::ConnectionCapabilities flags = {})
+ : capabilities(flags), direction(direction)
+ {
+ }
};
-class QDBusMarshaller: public QDBusArgumentPrivate
+class QDBusMarshaller final : public QDBusArgumentPrivate
{
public:
- QDBusMarshaller(int flags) : QDBusArgumentPrivate(flags), parent(nullptr), ba(nullptr), closeCode(0), ok(true), skipSignature(false)
- { direction = Marshalling; }
+ explicit QDBusMarshaller(QDBusConnection::ConnectionCapabilities flags = {})
+ : QDBusArgumentPrivate(Direction::Marshalling, flags)
+ {
+ }
~QDBusMarshaller();
QString currentSignature();
@@ -109,25 +115,26 @@ public:
bool appendRegisteredType(const QVariant &arg);
bool appendCrossMarshalling(QDBusDemarshaller *arg);
-public:
DBusMessageIter iterator;
- QDBusMarshaller *parent;
- QByteArray *ba;
+ QDBusMarshaller *parent = nullptr;
+ QByteArray *ba = nullptr;
QString errorString;
- char closeCode;
- bool ok;
- bool skipSignature;
+ char closeCode = 0;
+ bool ok = true;
+ bool skipSignature = false;
private:
Q_DECL_COLD_FUNCTION void unregisteredTypeError(QMetaType t);
Q_DISABLE_COPY_MOVE(QDBusMarshaller)
};
-class QDBusDemarshaller: public QDBusArgumentPrivate
+class QDBusDemarshaller final : public QDBusArgumentPrivate
{
public:
- inline QDBusDemarshaller(int flags) : QDBusArgumentPrivate(flags), parent(nullptr)
- { direction = Demarshalling; }
+ explicit QDBusDemarshaller(QDBusConnection::ConnectionCapabilities flags = {})
+ : QDBusArgumentPrivate(Direction::Demarshalling, flags)
+ {
+ }
~QDBusDemarshaller();
QString currentSignature();
@@ -168,9 +175,8 @@ public:
QDBusArgument::ElementType currentType();
bool isCurrentTypeStringLike();
-public:
DBusMessageIter iterator;
- QDBusDemarshaller *parent;
+ QDBusDemarshaller *parent = nullptr;
private:
Q_DISABLE_COPY_MOVE(QDBusDemarshaller)
diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp
index af6604bf0f..f6918b70b0 100644
--- a/src/dbus/qdbusconnection.cpp
+++ b/src/dbus/qdbusconnection.cpp
@@ -6,21 +6,14 @@
#include "qdbusconnection_p.h"
#include <qdebug.h>
-#include <qcoreapplication.h>
#include <qstringlist.h>
-#include <qtimer.h>
-#include <qthread.h>
-#include <QtCore/private/qlocking_p.h>
#include "qdbusconnectioninterface.h"
#include "qdbuserror.h"
#include "qdbusmessage.h"
-#include "qdbusmessage_p.h"
-#include "qdbusinterface_p.h"
#include "qdbusutil_p.h"
#include "qdbusconnectionmanager_p.h"
#include "qdbuspendingcall_p.h"
-
#include "qdbusthreaddebug_p.h"
#include <algorithm>
@@ -33,219 +26,6 @@
QT_BEGIN_NAMESPACE
-#ifdef Q_OS_WIN
-static void preventDllUnload();
-#endif
-
-Q_GLOBAL_STATIC(QDBusConnectionManager, _q_manager)
-
-QDBusConnectionPrivate *QDBusConnectionManager::busConnection(QDBusConnection::BusType type)
-{
- static_assert(int(QDBusConnection::SessionBus) + int(QDBusConnection::SystemBus) == 1);
- Q_ASSERT(type == QDBusConnection::SessionBus || type == QDBusConnection::SystemBus);
-
- if (!qdbus_loadLibDBus())
- return nullptr;
-
- // we'll start in suspended delivery mode if we're in the main thread
- // (the event loop will resume delivery)
- bool suspendedDelivery = qApp && qApp->thread() == QThread::currentThread();
-
- const auto locker = qt_scoped_lock(defaultBusMutex);
- if (defaultBuses[type])
- return defaultBuses[type];
-
- QString name = QStringLiteral("qt_default_session_bus");
- if (type == QDBusConnection::SystemBus)
- name = QStringLiteral("qt_default_system_bus");
- return defaultBuses[type] = connectToBus(type, name, suspendedDelivery);
-}
-
-QDBusConnectionPrivate *QDBusConnectionManager::connection(const QString &name) const
-{
- return connectionHash.value(name, nullptr);
-}
-
-void QDBusConnectionManager::removeConnection(const QString &name)
-{
- QDBusConnectionPrivate *d = nullptr;
- d = connectionHash.take(name);
- if (d && !d->ref.deref())
- d->deleteLater();
-
- // Static objects may be keeping the connection open.
- // However, it is harmless to have outstanding references to a connection that is
- // closing as long as those references will be soon dropped without being used.
-
- // ### Output a warning if connections are being used after they have been removed.
-}
-
-QDBusConnectionManager::QDBusConnectionManager()
-{
- connect(this, &QDBusConnectionManager::connectionRequested,
- this, &QDBusConnectionManager::executeConnectionRequest, Qt::BlockingQueuedConnection);
- connect(this, &QDBusConnectionManager::serverRequested,
- this, &QDBusConnectionManager::createServer, Qt::BlockingQueuedConnection);
- moveToThread(this); // ugly, don't do this in other projects
-
-#ifdef Q_OS_WIN
- // prevent the library from being unloaded on Windows. See comments in the function.
- preventDllUnload();
-#endif
- defaultBuses[0] = defaultBuses[1] = nullptr;
- start();
-}
-
-QDBusConnectionManager::~QDBusConnectionManager()
-{
- quit();
- wait();
-}
-
-QDBusConnectionManager* QDBusConnectionManager::instance()
-{
- return _q_manager();
-}
-
-Q_DBUS_EXPORT void qDBusBindToApplication();
-void qDBusBindToApplication()
-{
-}
-
-void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionPrivate *c)
-{
- connectionHash[name] = c;
- c->name = name;
-}
-
-void QDBusConnectionManager::run()
-{
- exec();
-
- // cleanup:
- const auto locker = qt_scoped_lock(mutex);
- for (QHash<QString, QDBusConnectionPrivate *>::const_iterator it = connectionHash.constBegin();
- it != connectionHash.constEnd(); ++it) {
- QDBusConnectionPrivate *d = it.value();
- if (!d->ref.deref()) {
- delete d;
- } else {
- d->closeConnection();
- d->moveToThread(nullptr); // allow it to be deleted in another thread
- }
- }
- connectionHash.clear();
-
- // allow deletion from any thread without warning
- moveToThread(nullptr);
-}
-
-QDBusConnectionPrivate *QDBusConnectionManager::connectToBus(QDBusConnection::BusType type, const QString &name,
- bool suspendedDelivery)
-{
- ConnectionRequestData data;
- data.type = ConnectionRequestData::ConnectToStandardBus;
- data.busType = type;
- data.name = &name;
- data.suspendedDelivery = suspendedDelivery;
-
- emit connectionRequested(&data);
- if (suspendedDelivery && data.result->connection) {
- data.result->ref.ref();
- QDBusConnectionDispatchEnabler *o = new QDBusConnectionDispatchEnabler(data.result);
- QTimer::singleShot(0, o, SLOT(execute()));
- o->moveToThread(qApp->thread()); // qApp was checked in the caller
- }
- return data.result;
-}
-
-QDBusConnectionPrivate *QDBusConnectionManager::connectToBus(const QString &address, const QString &name)
-{
- ConnectionRequestData data;
- data.type = ConnectionRequestData::ConnectToBusByAddress;
- data.busAddress = &address;
- data.name = &name;
- data.suspendedDelivery = false;
-
- emit connectionRequested(&data);
- return data.result;
-}
-
-QDBusConnectionPrivate *QDBusConnectionManager::connectToPeer(const QString &address, const QString &name)
-{
- ConnectionRequestData data;
- data.type = ConnectionRequestData::ConnectToPeerByAddress;
- data.busAddress = &address;
- data.name = &name;
- data.suspendedDelivery = false;
-
- emit connectionRequested(&data);
- return data.result;
-}
-
-void QDBusConnectionManager::executeConnectionRequest(QDBusConnectionManager::ConnectionRequestData *data)
-{
- const auto locker = qt_scoped_lock(mutex);
- const QString &name = *data->name;
- QDBusConnectionPrivate *&d = data->result;
-
- // check if the connection exists by name
- d = connection(name);
- if (d || name.isEmpty())
- return;
-
- d = new QDBusConnectionPrivate;
- DBusConnection *c = nullptr;
- QDBusErrorInternal error;
- switch (data->type) {
- case ConnectionRequestData::ConnectToStandardBus:
- switch (data->busType) {
- case QDBusConnection::SystemBus:
- c = q_dbus_bus_get_private(DBUS_BUS_SYSTEM, error);
- break;
- case QDBusConnection::SessionBus:
- c = q_dbus_bus_get_private(DBUS_BUS_SESSION, error);
- break;
- case QDBusConnection::ActivationBus:
- c = q_dbus_bus_get_private(DBUS_BUS_STARTER, error);
- break;
- }
- break;
-
- case ConnectionRequestData::ConnectToBusByAddress:
- case ConnectionRequestData::ConnectToPeerByAddress:
- c = q_dbus_connection_open_private(data->busAddress->toUtf8().constData(), error);
- if (c && data->type == ConnectionRequestData::ConnectToBusByAddress) {
- // register on the bus
- if (!q_dbus_bus_register(c, error)) {
- q_dbus_connection_unref(c);
- c = nullptr;
- }
- }
- break;
- }
-
- setConnection(name, d);
- if (data->type == ConnectionRequestData::ConnectToPeerByAddress) {
- d->setPeer(c, error);
- } else {
- // create the bus service
- // will lock in QDBusConnectionPrivate::connectRelay()
- d->setConnection(c, error);
- d->createBusService();
- if (c && data->suspendedDelivery)
- d->setDispatchEnabled(false);
- }
-}
-
-void QDBusConnectionManager::createServer(const QString &address, void *server)
-{
- QDBusErrorInternal error;
- QDBusConnectionPrivate *d = new QDBusConnectionPrivate;
- d->setServer(static_cast<QDBusServer *>(server),
- q_dbus_server_listen(address.toUtf8().constData(), error), error);
-}
-
/*!
\class QDBusConnection
\inmodule QtDBus
@@ -370,13 +150,17 @@ void QDBusConnectionManager::createServer(const QString &address, void *server)
*/
QDBusConnection::QDBusConnection(const QString &name)
{
- if (name.isEmpty() || _q_manager.isDestroyed()) {
+ if (name.isEmpty()) {
+ d = nullptr;
+ return;
+ }
+
+ auto *manager = QDBusConnectionManager::instance();
+
+ if (!manager) {
d = nullptr;
} else {
- const auto locker = qt_scoped_lock(_q_manager()->mutex);
- d = _q_manager()->connection(name);
- if (d)
- d->ref.ref();
+ d = manager->existingConnection(name);
}
}
@@ -435,11 +219,13 @@ QDBusConnection &QDBusConnection::operator=(const QDBusConnection &other)
*/
QDBusConnection QDBusConnection::connectToBus(BusType type, const QString &name)
{
- if (_q_manager.isDestroyed() || !qdbus_loadLibDBus()) {
+ auto *manager = QDBusConnectionManager::instance();
+
+ if (!manager || !qdbus_loadLibDBus()) {
QDBusConnectionPrivate *d = nullptr;
return QDBusConnection(d);
}
- return QDBusConnection(_q_manager()->connectToBus(type, name, false));
+ return QDBusConnection(manager->connectToBus(type, name, false));
}
/*!
@@ -449,11 +235,13 @@ QDBusConnection QDBusConnection::connectToBus(BusType type, const QString &name)
QDBusConnection QDBusConnection::connectToBus(const QString &address,
const QString &name)
{
- if (_q_manager.isDestroyed() || !qdbus_loadLibDBus()) {
+ auto *manager = QDBusConnectionManager::instance();
+
+ if (!manager || !qdbus_loadLibDBus()) {
QDBusConnectionPrivate *d = nullptr;
return QDBusConnection(d);
}
- return QDBusConnection(_q_manager()->connectToBus(address, name));
+ return QDBusConnection(manager->connectToBus(address, name));
}
/*!
\since 4.8
@@ -464,11 +252,13 @@ QDBusConnection QDBusConnection::connectToBus(const QString &address,
QDBusConnection QDBusConnection::connectToPeer(const QString &address,
const QString &name)
{
- if (_q_manager.isDestroyed() || !qdbus_loadLibDBus()) {
+ auto *manager = QDBusConnectionManager::instance();
+
+ if (!manager || !qdbus_loadLibDBus()) {
QDBusConnectionPrivate *d = nullptr;
return QDBusConnection(d);
}
- return QDBusConnection(_q_manager()->connectToPeer(address, name));
+ return QDBusConnection(manager->connectToPeer(address, name));
}
/*!
@@ -481,13 +271,11 @@ QDBusConnection QDBusConnection::connectToPeer(const QString &address,
*/
void QDBusConnection::disconnectFromBus(const QString &name)
{
- if (_q_manager()) {
- const auto locker = qt_scoped_lock(_q_manager()->mutex);
- QDBusConnectionPrivate *d = _q_manager()->connection(name);
- if (d && d->mode != QDBusConnectionPrivate::ClientMode)
- return;
- _q_manager()->removeConnection(name);
- }
+ auto *manager = QDBusConnectionManager::instance();
+ if (!manager)
+ return;
+
+ manager->disconnectFrom(name, QDBusConnectionPrivate::ClientMode);
}
/*!
@@ -502,13 +290,11 @@ void QDBusConnection::disconnectFromBus(const QString &name)
*/
void QDBusConnection::disconnectFromPeer(const QString &name)
{
- if (_q_manager()) {
- const auto locker = qt_scoped_lock(_q_manager()->mutex);
- QDBusConnectionPrivate *d = _q_manager()->connection(name);
- if (d && d->mode != QDBusConnectionPrivate::PeerMode)
- return;
- _q_manager()->removeConnection(name);
- }
+ auto *manager = QDBusConnectionManager::instance();
+ if (!manager)
+ return;
+
+ manager->disconnectFrom(name, QDBusConnectionPrivate::PeerMode);
}
/*!
@@ -645,6 +431,9 @@ QDBusMessage QDBusConnection::call(const QDBusMessage &message, QDBus::CallMode
See the QDBusInterface::asyncCall() function for a more friendly way
of placing calls.
+
+ \note Method calls to objects registered by the application itself are never
+ asynchronous due to implementation limitations.
*/
QDBusPendingCall QDBusConnection::asyncCall(const QDBusMessage &message, int timeout) const
{
@@ -1128,9 +917,11 @@ bool QDBusConnection::unregisterService(const QString &serviceName)
*/
QDBusConnection QDBusConnection::sessionBus()
{
- if (_q_manager.isDestroyed())
+ auto *manager = QDBusConnectionManager::instance();
+
+ if (!manager)
return QDBusConnection(nullptr);
- return QDBusConnection(_q_manager()->busConnection(SessionBus));
+ return QDBusConnection(manager->busConnection(SessionBus));
}
/*!
@@ -1142,9 +933,11 @@ QDBusConnection QDBusConnection::sessionBus()
*/
QDBusConnection QDBusConnection::systemBus()
{
- if (_q_manager.isDestroyed())
+ auto *manager = QDBusConnectionManager::instance();
+
+ if (!manager)
return QDBusConnection(nullptr);
- return QDBusConnection(_q_manager()->busConnection(SystemBus));
+ return QDBusConnection(manager->busConnection(SystemBus));
}
/*!
@@ -1221,33 +1014,5 @@ QT_END_NAMESPACE
#include "moc_qdbusconnection_p.cpp"
#include "moc_qdbusconnection.cpp"
-#include "moc_qdbusconnectionmanager_p.cpp"
-
-#ifdef Q_OS_WIN
-# include <qt_windows.h>
-
-QT_BEGIN_NAMESPACE
-static void preventDllUnload()
-{
- // Thread termination is really wacky on Windows. For some reason we don't
- // understand, exiting from the thread may try to unload the DLL. Since the
- // QDBusConnectionManager thread runs until the DLL is unloaded, we've got
- // a deadlock: the main thread is waiting for the manager thread to exit,
- // but the manager thread is attempting to acquire a lock to unload the DLL.
- //
- // We work around the issue by preventing the unload from happening in the
- // first place.
- //
- // For this trick, see
- // https://blogs.msdn.microsoft.com/oldnewthing/20131105-00/?p=2733
-
- static HMODULE self;
- GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
- GET_MODULE_HANDLE_EX_FLAG_PIN,
- reinterpret_cast<const wchar_t *>(&self), // any address in this DLL
- &self);
-}
-QT_END_NAMESPACE
-#endif
#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h
index 3431992eac..53e6874818 100644
--- a/src/dbus/qdbusconnection_p.h
+++ b/src/dbus/qdbusconnection_p.h
@@ -115,9 +115,11 @@ public:
{
typedef QList<ObjectTreeNode> DataList;
- inline ObjectTreeNode() : obj(nullptr), flags(0) { }
+ inline ObjectTreeNode() : obj(nullptr) { }
inline ObjectTreeNode(const QString &n) // intentionally implicit
- : name(n), obj(nullptr), flags(0) { }
+ : name(n), obj(nullptr)
+ {
+ }
inline bool operator<(const QString &other) const
{ return name < other; }
inline bool operator<(QStringView other) const
@@ -131,12 +133,11 @@ public:
QObject *obj;
QDBusVirtualObject *treeNode;
};
- int flags;
+ QDBusConnection::RegisterOptions flags;
DataList children;
};
-public:
// typedefs
typedef QMultiHash<qintptr, Watcher> WatcherHash;
typedef QHash<int, DBusTimeout *> TimeoutHash;
@@ -157,9 +158,8 @@ public:
};
typedef QHash<QString, WatchedServiceData> WatchedServicesHash;
-public:
// public methods are entry points from other objects
- explicit QDBusConnectionPrivate(QObject *parent = nullptr);
+ QDBusConnectionPrivate();
~QDBusConnectionPrivate();
void createBusService();
@@ -177,7 +177,7 @@ public:
QObject *obj, const char *member);
bool send(const QDBusMessage &message);
- QDBusMessage sendWithReply(const QDBusMessage &message, int mode, int timeout = -1);
+ QDBusMessage sendWithReply(const QDBusMessage &message, QDBus::CallMode mode, int timeout = -1);
QDBusMessage sendWithReplyLocal(const QDBusMessage &message);
QDBusPendingCallPrivate *sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
const char *returnMethod, const char *errorMethod,int timeout = -1);
@@ -212,6 +212,8 @@ public:
void postEventToThread(int action, QObject *target, QEvent *event);
+ void enableDispatchDelayed(QObject *context);
+
private:
void checkThread();
bool handleError(const QDBusErrorInternal &error);
@@ -223,12 +225,13 @@ private:
void activateSignal(const SignalHook& hook, const QDBusMessage &msg);
void activateObject(ObjectTreeNode &node, const QDBusMessage &msg, int pathStartPos);
bool activateInternalFilters(const ObjectTreeNode &node, const QDBusMessage &msg);
- bool activateCall(QObject *object, int flags, const QDBusMessage &msg);
+ bool activateCall(QObject *object, QDBusConnection::RegisterOptions flags,
+ const QDBusMessage &msg);
void sendInternal(QDBusPendingCallPrivate *pcall, void *msg, int timeout);
void sendError(const QDBusMessage &msg, QDBusError::ErrorType code);
- void deliverCall(QObject *object, int flags, const QDBusMessage &msg,
- const QList<QMetaType> &metaTypes, int slotIdx);
+ void deliverCall(QObject *object, const QDBusMessage &msg, const QList<QMetaType> &metaTypes,
+ int slotIdx);
SignalHookHash::Iterator removeSignalHookNoLock(SignalHookHash::Iterator it);
void collectAllObjects(ObjectTreeNode &node, QSet<QObject *> &set);
@@ -239,10 +242,14 @@ private:
void watchForDBusDisconnection();
- void _q_newConnection(QDBusConnectionPrivate *newConnection);
-
void handleAuthentication();
+ bool addSignalHook(const QString &key, const SignalHook &hook);
+ bool removeSignalHook(const QString &key, const SignalHook &hook);
+
+ bool addSignalHookImpl(const QString &key, const SignalHook &hook);
+ bool removeSignalHookImpl(const QString &key, const SignalHook &hook);
+
protected:
void timerEvent(QTimerEvent *e) override;
@@ -254,8 +261,6 @@ public slots:
void socketWrite(qintptr);
void objectDestroyed(QObject *o);
void relaySignal(QObject *obj, const QMetaObject *, int signalId, const QVariantList &args);
- bool addSignalHook(const QString &key, const SignalHook &hook);
- bool removeSignalHook(const QString &key, const SignalHook &hook);
private slots:
void serviceOwnerChangedNoLock(const QString &name, const QString &oldOwner, const QString &newOwner);
@@ -267,11 +272,8 @@ signals:
void dispatchStatusChanged();
void spyHooksFinished(const QDBusMessage &msg);
void messageNeedsSending(QDBusPendingCallPrivate *pcall, void *msg, int timeout = -1);
- bool signalNeedsConnecting(const QString &key, const QDBusConnectionPrivate::SignalHook &hook);
- bool signalNeedsDisconnecting(const QString &key, const QDBusConnectionPrivate::SignalHook &hook);
void serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner);
void callWithCallbackFailed(const QDBusError &error, const QDBusMessage &message);
- void newServerConnection(QDBusConnectionPrivate *newConnection);
public:
QAtomicInt ref;
@@ -314,17 +316,14 @@ public:
bool dispatchEnabled; // protected by the dispatch lock, not the main lock
bool isAuthenticated;
-public:
// static methods
static int findSlot(QObject *obj, const QByteArray &normalizedName, QList<QMetaType> &params,
QString &errorMsg);
static bool prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key,
- const QString &service,
- const QString &path, const QString &interface, const QString &name,
- const ArgMatchRules &argMatch,
- QObject *receiver, const char *signal, int minMIdx,
- bool buildSignature);
- static DBusHandlerResult messageFilter(DBusConnection *, DBusMessage *, void *);
+ const QString &service, const QString &path, const QString &interface,
+ const QString &name, const ArgMatchRules &argMatch, QObject *receiver,
+ const char *signal, int minMIdx, bool buildSignature,
+ QString &errorMsg);
static QDBusCallDeliveryEvent *prepareReply(QDBusConnectionPrivate *target, QObject *object,
int idx, const QList<QMetaType> &metaTypes,
const QDBusMessage &msg);
@@ -357,26 +356,6 @@ extern QDBusMessage qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNod
extern QDBusMessage qDBusPropertyGetAll(const QDBusConnectionPrivate::ObjectTreeNode &node,
const QDBusMessage &msg);
-// can be replaced with a lambda in Qt 5.7
-class QDBusConnectionDispatchEnabler : public QObject
-{
- Q_OBJECT
- QDBusConnectionPrivate *con;
-public:
- QDBusConnectionDispatchEnabler(QDBusConnectionPrivate *con) : con(con) {}
-
-public slots:
- void execute()
- {
- // This call cannot race with something disabling dispatch only because dispatch is
- // never re-disabled from Qt code on an in-use connection once it has been enabled.
- QMetaObject::invokeMethod(con, "setDispatchEnabled", Qt::QueuedConnection, Q_ARG(bool, true));
- if (!con->ref.deref())
- con->deleteLater();
- deleteLater();
- }
-};
-
#endif // QT_BOOTSTRAPPED
QT_END_NAMESPACE
diff --git a/src/dbus/qdbusconnectionmanager.cpp b/src/dbus/qdbusconnectionmanager.cpp
new file mode 100644
index 0000000000..ce52c9fa63
--- /dev/null
+++ b/src/dbus/qdbusconnectionmanager.cpp
@@ -0,0 +1,334 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qdbusconnectionmanager_p.h"
+
+#include <qcoreapplication.h>
+#include <qthread.h>
+#include <qstringlist.h>
+#include <QtCore/private/qlocking_p.h>
+
+#include "qdbuserror.h"
+#include "qdbuspendingcall_p.h"
+#include "qdbusmetatype_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_OS_WIN
+static void preventDllUnload();
+#endif
+
+Q_GLOBAL_STATIC(QDBusConnectionManager, _q_manager)
+
+QDBusConnectionPrivate *QDBusConnectionManager::busConnection(QDBusConnection::BusType type)
+{
+ static_assert(int(QDBusConnection::SessionBus) + int(QDBusConnection::SystemBus) == 1);
+ Q_ASSERT(type == QDBusConnection::SessionBus || type == QDBusConnection::SystemBus);
+
+ if (!qdbus_loadLibDBus())
+ return nullptr;
+
+ // we'll start in suspended delivery mode if we're in the main thread
+ // (the event loop will resume delivery)
+ bool suspendedDelivery = qApp && qApp->thread() == QThread::currentThread();
+
+ const auto locker = qt_scoped_lock(defaultBusMutex);
+ if (defaultBuses[type])
+ return defaultBuses[type];
+
+ QString name = QStringLiteral("qt_default_session_bus");
+ if (type == QDBusConnection::SystemBus)
+ name = QStringLiteral("qt_default_system_bus");
+ return defaultBuses[type] = connectToBus(type, name, suspendedDelivery);
+}
+
+QDBusConnectionPrivate *QDBusConnectionManager::connection(const QString &name) const
+{
+ return connectionHash.value(name, nullptr);
+}
+
+QDBusConnectionPrivate *QDBusConnectionManager::existingConnection(const QString &name) const
+{
+ const auto locker = qt_scoped_lock(mutex);
+ auto *conn = connection(name);
+ if (conn)
+ conn->ref.ref();
+ return conn;
+}
+
+void QDBusConnectionManager::removeConnection(const QString &name)
+{
+ QDBusConnectionPrivate *d = nullptr;
+ d = connectionHash.take(name);
+ if (d && !d->ref.deref())
+ d->deleteLater();
+
+ // Static objects may be keeping the connection open.
+ // However, it is harmless to have outstanding references to a connection that is
+ // closing as long as those references will be soon dropped without being used.
+
+ // ### Output a warning if connections are being used after they have been removed.
+}
+
+void QDBusConnectionManager::removeConnections(const QStringList &names)
+{
+ const auto locker = qt_scoped_lock(mutex);
+
+ for (const auto &name : names)
+ removeConnection(name);
+}
+
+void QDBusConnectionManager::disconnectFrom(const QString &name,
+ QDBusConnectionPrivate::ConnectionMode mode)
+{
+ const auto locker = qt_scoped_lock(mutex);
+
+ QDBusConnectionPrivate *d = connection(name);
+ if (d && d->mode != mode)
+ return;
+ removeConnection(name);
+}
+
+QDBusConnectionManager::QDBusConnectionManager()
+{
+ // Ensure that the custom metatype registry is created before the instance
+ // of this class. This will ensure that the registry is not destroyed before
+ // the connection manager at application exit (see also QTBUG-58732). This
+ // works with compilers that use mechanism similar to atexit() to call
+ // destructurs for global statics.
+ QDBusMetaTypeId::init();
+
+ moveToThread(this); // ugly, don't do this in other projects
+
+#ifdef Q_OS_WIN
+ // prevent the library from being unloaded on Windows. See comments in the function.
+ preventDllUnload();
+#endif
+ defaultBuses[0] = defaultBuses[1] = nullptr;
+ start();
+}
+
+QDBusConnectionManager::~QDBusConnectionManager()
+{
+ quit();
+ wait();
+}
+
+QDBusConnectionManager* QDBusConnectionManager::instance()
+{
+ return _q_manager();
+}
+
+Q_DBUS_EXPORT void qDBusBindToApplication();
+void qDBusBindToApplication()
+{
+}
+
+void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionPrivate *c)
+{
+ connectionHash[name] = c;
+ c->name = name;
+}
+
+void QDBusConnectionManager::addConnection(const QString &name, QDBusConnectionPrivate *c)
+{
+ const auto locker = qt_scoped_lock(mutex);
+ setConnection(name, c);
+}
+
+void QDBusConnectionManager::run()
+{
+ exec();
+
+ // cleanup:
+ const auto locker = qt_scoped_lock(mutex);
+ for (QDBusConnectionPrivate *d : std::as_const(connectionHash)) {
+ if (!d->ref.deref()) {
+ delete d;
+ } else {
+ d->closeConnection();
+ d->moveToThread(nullptr); // allow it to be deleted in another thread
+ }
+ }
+ connectionHash.clear();
+
+ // allow deletion from any thread without warning
+ moveToThread(nullptr);
+}
+
+QDBusConnectionPrivate *QDBusConnectionManager::connectToBus(QDBusConnection::BusType type, const QString &name,
+ bool suspendedDelivery)
+{
+ QDBusConnectionPrivate *result = nullptr;
+
+ QMetaObject::invokeMethod(this, &QDBusConnectionManager::doConnectToStandardBus,
+ Qt::BlockingQueuedConnection, qReturnArg(result), type, name,
+ suspendedDelivery);
+
+ if (suspendedDelivery && result && result->connection)
+ result->enableDispatchDelayed(qApp); // qApp was checked in the caller
+
+ return result;
+}
+
+QDBusConnectionPrivate *QDBusConnectionManager::connectToBus(const QString &address, const QString &name)
+{
+ QDBusConnectionPrivate *result = nullptr;
+
+ QMetaObject::invokeMethod(this, &QDBusConnectionManager::doConnectToBus,
+ Qt::BlockingQueuedConnection, qReturnArg(result), address, name);
+
+ return result;
+}
+
+QDBusConnectionPrivate *QDBusConnectionManager::connectToPeer(const QString &address, const QString &name)
+{
+ QDBusConnectionPrivate *result = nullptr;
+
+ QMetaObject::invokeMethod(this, &QDBusConnectionManager::doConnectToPeer,
+ Qt::BlockingQueuedConnection, qReturnArg(result), address, name);
+
+ return result;
+}
+
+QDBusConnectionPrivate *
+QDBusConnectionManager::doConnectToStandardBus(QDBusConnection::BusType type, const QString &name,
+ bool suspendedDelivery)
+{
+ const auto locker = qt_scoped_lock(mutex);
+
+ // check if the connection exists by name
+ QDBusConnectionPrivate *d = connection(name);
+ if (d || name.isEmpty())
+ return d;
+
+ d = new QDBusConnectionPrivate;
+ DBusConnection *c = nullptr;
+ QDBusErrorInternal error;
+
+ switch (type) {
+ case QDBusConnection::SystemBus:
+ c = q_dbus_bus_get_private(DBUS_BUS_SYSTEM, error);
+ break;
+ case QDBusConnection::SessionBus:
+ c = q_dbus_bus_get_private(DBUS_BUS_SESSION, error);
+ break;
+ case QDBusConnection::ActivationBus:
+ c = q_dbus_bus_get_private(DBUS_BUS_STARTER, error);
+ break;
+ }
+
+ setConnection(name, d);
+
+ // create the bus service
+ // will lock in QDBusConnectionPrivate::connectRelay()
+ d->setConnection(c, error);
+ d->createBusService();
+ if (c && suspendedDelivery)
+ d->setDispatchEnabled(false);
+
+ return d;
+}
+
+QDBusConnectionPrivate *QDBusConnectionManager::doConnectToBus(const QString &address,
+ const QString &name)
+{
+ const auto locker = qt_scoped_lock(mutex);
+
+ // check if the connection exists by name
+ QDBusConnectionPrivate *d = connection(name);
+ if (d || name.isEmpty())
+ return d;
+
+ d = new QDBusConnectionPrivate;
+ QDBusErrorInternal error;
+
+ DBusConnection *c = q_dbus_connection_open_private(address.toUtf8().constData(), error);
+ if (c) {
+ // register on the bus
+ if (!q_dbus_bus_register(c, error)) {
+ q_dbus_connection_close(c);
+ q_dbus_connection_unref(c);
+ c = nullptr;
+ }
+ }
+
+ setConnection(name, d);
+
+ // create the bus service
+ // will lock in QDBusConnectionPrivate::connectRelay()
+ d->setConnection(c, error);
+ d->createBusService();
+
+ return d;
+}
+
+QDBusConnectionPrivate *QDBusConnectionManager::doConnectToPeer(const QString &address,
+ const QString &name)
+{
+ const auto locker = qt_scoped_lock(mutex);
+
+ // check if the connection exists by name
+ QDBusConnectionPrivate *d = connection(name);
+ if (d || name.isEmpty())
+ return d;
+
+ d = new QDBusConnectionPrivate;
+ QDBusErrorInternal error;
+
+ DBusConnection *c = q_dbus_connection_open_private(address.toUtf8().constData(), error);
+
+ setConnection(name, d);
+ d->setPeer(c, error);
+
+ return d;
+}
+
+void QDBusConnectionManager::createServer(const QString &address, QDBusServer *server)
+{
+ QMetaObject::invokeMethod(
+ this,
+ [&address, server] {
+ QDBusErrorInternal error;
+ QDBusConnectionPrivate *d = new QDBusConnectionPrivate;
+ d->setServer(server, q_dbus_server_listen(address.toUtf8().constData(), error),
+ error);
+ },
+ Qt::BlockingQueuedConnection);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qdbusconnectionmanager_p.cpp"
+
+#ifdef Q_OS_WIN
+# include <qt_windows.h>
+
+QT_BEGIN_NAMESPACE
+static void preventDllUnload()
+{
+ // Thread termination is really wacky on Windows. For some reason we don't
+ // understand, exiting from the thread may try to unload the DLL. Since the
+ // QDBusConnectionManager thread runs until the DLL is unloaded, we've got
+ // a deadlock: the main thread is waiting for the manager thread to exit,
+ // but the manager thread is attempting to acquire a lock to unload the DLL.
+ //
+ // We work around the issue by preventing the unload from happening in the
+ // first place.
+ //
+ // For this trick, see the blog post titled "What is the point of FreeLibraryAndExitThread?"
+ // https://devblogs.microsoft.com/oldnewthing/20131105-00/?p=2733
+
+ static HMODULE self;
+ GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+ GET_MODULE_HANDLE_EX_FLAG_PIN,
+ reinterpret_cast<const wchar_t *>(&self), // any address in this DLL
+ &self);
+}
+QT_END_NAMESPACE
+#endif
+
+#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusconnectionmanager_p.h b/src/dbus/qdbusconnectionmanager_p.h
index f6a153945a..644c3c8fb1 100644
--- a/src/dbus/qdbusconnectionmanager_p.h
+++ b/src/dbus/qdbusconnectionmanager_p.h
@@ -25,63 +25,46 @@
QT_BEGIN_NAMESPACE
+class QDBusServer;
+
class QDBusConnectionManager : public QDaemonThread
{
Q_OBJECT
- struct ConnectionRequestData;
public:
QDBusConnectionManager();
~QDBusConnectionManager();
static QDBusConnectionManager* instance();
QDBusConnectionPrivate *busConnection(QDBusConnection::BusType type);
- QDBusConnectionPrivate *connection(const QString &name) const;
- void removeConnection(const QString &name);
- void setConnection(const QString &name, QDBusConnectionPrivate *c);
+ QDBusConnectionPrivate *existingConnection(const QString &name) const;
+
+ void removeConnections(const QStringList &names);
+ void disconnectFrom(const QString &name, QDBusConnectionPrivate::ConnectionMode mode);
+ void addConnection(const QString &name, QDBusConnectionPrivate *c);
+
QDBusConnectionPrivate *connectToBus(QDBusConnection::BusType type, const QString &name, bool suspendedDelivery);
QDBusConnectionPrivate *connectToBus(const QString &address, const QString &name);
QDBusConnectionPrivate *connectToPeer(const QString &address, const QString &name);
- mutable QMutex mutex;
-
-signals:
- void connectionRequested(ConnectionRequestData *);
- void serverRequested(const QString &address, void *server);
+ void createServer(const QString &address, QDBusServer *server);
protected:
void run() override;
private:
- void executeConnectionRequest(ConnectionRequestData *data);
- void createServer(const QString &address, void *server);
+ QDBusConnectionPrivate *doConnectToStandardBus(QDBusConnection::BusType type,
+ const QString &name, bool suspendedDelivery);
+ QDBusConnectionPrivate *doConnectToBus(const QString &address, const QString &name);
+ QDBusConnectionPrivate *doConnectToPeer(const QString &address, const QString &name);
+ mutable QMutex mutex;
QHash<QString, QDBusConnectionPrivate *> connectionHash;
+ QDBusConnectionPrivate *connection(const QString &name) const;
+ void removeConnection(const QString &name);
+ void setConnection(const QString &name, QDBusConnectionPrivate *c);
QMutex defaultBusMutex;
QDBusConnectionPrivate *defaultBuses[2];
-
- mutable QMutex senderMutex;
- QString senderName; // internal; will probably change
-};
-
-// TODO: move into own header and use Q_MOC_INCLUDE
-struct QDBusConnectionManager::ConnectionRequestData
-{
- enum RequestType {
- ConnectToStandardBus,
- ConnectToBusByAddress,
- ConnectToPeerByAddress
- } type;
-
- union {
- QDBusConnection::BusType busType;
- const QString *busAddress;
- };
- const QString *name;
-
- QDBusConnectionPrivate *result;
-
- bool suspendedDelivery;
};
QT_END_NAMESPACE
diff --git a/src/dbus/qdbusextratypes.cpp b/src/dbus/qdbusextratypes.cpp
index 3f8ed34548..61f2075443 100644
--- a/src/dbus/qdbusextratypes.cpp
+++ b/src/dbus/qdbusextratypes.cpp
@@ -12,6 +12,15 @@ QT_IMPL_METATYPE_EXTERN(QDBusVariant)
QT_IMPL_METATYPE_EXTERN(QDBusObjectPath)
QT_IMPL_METATYPE_EXTERN(QDBusSignature)
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QDBusObjectPath &path)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace() << "QDBusObjectPath(" << path.path() << ')';
+ return dbg;
+}
+#endif
+
void QDBusObjectPath::doCheck()
{
if (!QDBusUtil::isValidObjectPath(m_path)) {
diff --git a/src/dbus/qdbusextratypes.h b/src/dbus/qdbusextratypes.h
index 03d151f16d..1bc0f3086d 100644
--- a/src/dbus/qdbusextratypes.h
+++ b/src/dbus/qdbusextratypes.h
@@ -4,7 +4,7 @@
#ifndef QDBUSEXTRATYPES_H
#define QDBUSEXTRATYPES_H
-// define some useful types for D-BUS
+// define some useful types for D-Bus
#include <QtDBus/qtdbusglobal.h>
#include <QtCore/qvariant.h>
@@ -69,6 +69,9 @@ inline bool operator<(const QDBusObjectPath &lhs, const QDBusObjectPath &rhs)
inline size_t qHash(const QDBusObjectPath &objectPath, size_t seed = 0)
{ return qHash(objectPath.path(), seed); }
+#ifndef QT_NO_DEBUG_STREAM
+Q_DBUS_EXPORT QDebug operator<<(QDebug, const QDBusObjectPath &);
+#endif
class Q_DBUS_EXPORT QDBusSignature
{
diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp
index 28fb32c531..836562f496 100644
--- a/src/dbus/qdbusintegrator.cpp
+++ b/src/dbus/qdbusintegrator.cpp
@@ -101,7 +101,34 @@ void qdbusDefaultThreadDebug(int action, int condition, QDBusConnectionPrivate *
qdbusThreadDebugFunc qdbusThreadDebug = nullptr;
#endif
-typedef QVarLengthArray<QDBusSpyCallEvent::Hook, 4> QDBusSpyHookList;
+class QDBusSpyHookList
+{
+public:
+ void add(QDBusSpyCallEvent::Hook hook)
+ {
+ const auto locker = qt_scoped_lock(lock);
+ list.append(hook);
+ }
+
+ void invoke(const QDBusMessage &msg)
+ {
+ // Create a copy of the hook list here, so that the hooks can be called
+ // without holding the lock.
+ QList<QDBusSpyCallEvent::Hook> hookListCopy;
+ {
+ const auto locker = qt_scoped_lock(lock);
+ hookListCopy = list;
+ }
+
+ for (auto hook : std::as_const(hookListCopy))
+ hook(msg);
+ }
+
+private:
+ QBasicMutex lock;
+ QList<QDBusSpyCallEvent::Hook> list;
+};
+
Q_GLOBAL_STATIC(QDBusSpyHookList, qDBusSpyHookList)
extern "C" {
@@ -124,8 +151,8 @@ static dbus_bool_t qDBusAddTimeout(DBusTimeout *timeout, void *data)
Q_ASSERT(d->timeouts.key(timeout, 0) == 0);
- int timerId = d->startTimer(std::chrono::milliseconds{q_dbus_timeout_get_interval(timeout)});
- Q_ASSERT_X(timerId, "QDBusConnection", "Failed to start a timer");
+ using namespace std::chrono_literals;
+ int timerId = d->startTimer(q_dbus_timeout_get_interval(timeout) * 1ms); // no overflow possible
if (!timerId)
return false;
@@ -251,7 +278,6 @@ static void qDBusToggleWatch(DBusWatch *watch, void *data)
static void qDBusUpdateDispatchStatus(DBusConnection *connection, DBusDispatchStatus new_status, void *data)
{
Q_ASSERT(connection);
- Q_UNUSED(connection);
QDBusConnectionPrivate *d = static_cast<QDBusConnectionPrivate *>(data);
if (new_status == DBUS_DISPATCH_DATA_REMAINS)
emit d->dispatchStatusChanged();
@@ -261,11 +287,11 @@ static void qDBusNewConnection(DBusServer *server, DBusConnection *connection, v
{
// ### We may want to separate the server from the QDBusConnectionPrivate
Q_ASSERT(server);
- Q_UNUSED(server);
Q_ASSERT(connection);
Q_ASSERT(data);
- if (!QDBusConnectionManager::instance())
+ auto *manager = QDBusConnectionManager::instance();
+ if (!manager)
return;
// keep the connection alive
@@ -276,35 +302,35 @@ static void qDBusNewConnection(DBusServer *server, DBusConnection *connection, v
if (serverConnection->anonymousAuthenticationAllowed)
q_dbus_connection_set_allow_anonymous(connection, true);
- QDBusConnectionPrivate *newConnection = new QDBusConnectionPrivate(serverConnection->parent());
- const auto locker = qt_scoped_lock(QDBusConnectionManager::instance()->mutex);
- QDBusConnectionManager::instance()->setConnection("QDBusServer-"_L1 + QString::number(reinterpret_cast<qulonglong>(newConnection), 16), newConnection);
- serverConnection->serverConnectionNames << newConnection->name;
+ QDBusConnectionPrivate *newConnection = new QDBusConnectionPrivate;
+
+ manager->addConnection(
+ "QDBusServer-"_L1 + QString::number(reinterpret_cast<qulonglong>(newConnection), 16),
+ newConnection);
+ {
+ QWriteLocker locker(&serverConnection->lock);
+ serverConnection->serverConnectionNames << newConnection->name;
+ }
// setPeer does the error handling for us
QDBusErrorInternal error;
newConnection->setPeer(connection, error);
newConnection->setDispatchEnabled(false);
+ QReadLocker serverLock(&serverConnection->lock);
+ if (!serverConnection->serverObject)
+ return;
+
// this is a queued connection and will resume in the QDBusServer's thread
- emit serverConnection->newServerConnection(newConnection);
+ QMetaObject::invokeMethod(serverConnection->serverObject, &QDBusServer::newConnection,
+ Qt::QueuedConnection, QDBusConnectionPrivate::q(newConnection));
// we've disabled dispatching of events, so now we post an event to the
// QDBusServer's thread in order to enable it after the
// QDBusServer::newConnection() signal has been received by the
// application's code
- newConnection->ref.ref();
- QReadLocker serverLock(&serverConnection->lock);
- QDBusConnectionDispatchEnabler *o = new QDBusConnectionDispatchEnabler(newConnection);
- QTimer::singleShot(0, o, SLOT(execute()));
- if (serverConnection->serverObject)
- o->moveToThread(serverConnection->serverObject->thread());
-}
-void QDBusConnectionPrivate::_q_newConnection(QDBusConnectionPrivate *newConnection)
-{
- Q_ASSERT(mode == ServerMode);
- emit serverObject->newConnection(QDBusConnectionPrivate::q(newConnection));
+ newConnection->enableDispatchDelayed(serverConnection->serverObject);
}
} // extern "C"
@@ -409,17 +435,14 @@ static QObject *findChildObject(const QDBusConnectionPrivate::ObjectTreeNode *ro
pos = (pos == -1 ? length : pos);
auto pathComponent = QStringView{fullpath}.mid(start, pos - start);
- const QObjectList children = obj->children();
-
// find a child with the proper name
QObject *next = nullptr;
- QObjectList::ConstIterator it = children.constBegin();
- QObjectList::ConstIterator end = children.constEnd();
- for ( ; it != end; ++it)
- if ((*it)->objectName() == pathComponent) {
- next = *it;
+ for (QObject *child : std::as_const(obj->children())) {
+ if (child->objectName() == pathComponent) {
+ next = child;
break;
}
+ }
if (!next)
break;
@@ -462,7 +485,11 @@ static QDBusConnectionPrivate::ArgMatchRules matchArgsForService(const QString &
extern Q_DBUS_EXPORT void qDBusAddSpyHook(QDBusSpyCallEvent::Hook);
void qDBusAddSpyHook(QDBusSpyCallEvent::Hook hook)
{
- qDBusSpyHookList()->append(hook);
+ auto *hooks = qDBusSpyHookList();
+ if (!hooks)
+ return;
+
+ hooks->add(hook);
}
QDBusSpyCallEvent::~QDBusSpyCallEvent()
@@ -477,14 +504,15 @@ QDBusSpyCallEvent::~QDBusSpyCallEvent()
void QDBusSpyCallEvent::placeMetaCall(QObject *)
{
- invokeSpyHooks(msg, hooks, hookCount);
+ invokeSpyHooks(msg);
}
-inline void QDBusSpyCallEvent::invokeSpyHooks(const QDBusMessage &msg, const Hook *hooks, int hookCount)
+inline void QDBusSpyCallEvent::invokeSpyHooks(const QDBusMessage &msg)
{
- // call the spy hook list
- for (int i = 0; i < hookCount; ++i)
- hooks[i](msg);
+ if (!qDBusSpyHookList.exists())
+ return;
+
+ qDBusSpyHookList->invoke(msg);
}
extern "C" {
@@ -533,15 +561,14 @@ bool QDBusConnectionPrivate::handleMessage(const QDBusMessage &amsg)
// a) if it's a local message, we're in the caller's thread, so invoke the filter directly
// b) if it's an external message, post to the main thread
if (Q_UNLIKELY(qDBusSpyHookList.exists()) && qApp) {
- const QDBusSpyHookList &list = *qDBusSpyHookList;
if (isLocal) {
Q_ASSERT(QThread::currentThread() != thread());
qDBusDebug() << this << "invoking message spies directly";
- QDBusSpyCallEvent::invokeSpyHooks(amsg, list.constData(), list.size());
+ QDBusSpyCallEvent::invokeSpyHooks(amsg);
} else {
qDBusDebug() << this << "invoking message spies via event";
- QCoreApplication::postEvent(qApp, new QDBusSpyCallEvent(this, QDBusConnection(this),
- amsg, list.constData(), list.size()));
+ QCoreApplication::postEvent(
+ qApp, new QDBusSpyCallEvent(this, QDBusConnection(this), amsg));
// we'll be called back, so return
return true;
@@ -561,7 +588,7 @@ bool QDBusConnectionPrivate::handleMessage(const QDBusMessage &amsg)
static void huntAndDestroy(QObject *needle, QDBusConnectionPrivate::ObjectTreeNode &haystack)
{
- for (auto &node : haystack.children)
+ for (QDBusConnectionPrivate::ObjectTreeNode &node : haystack.children)
huntAndDestroy(needle, node);
auto isInactive = [](const QDBusConnectionPrivate::ObjectTreeNode &node) { return !node.isActive(); };
@@ -569,7 +596,7 @@ static void huntAndDestroy(QObject *needle, QDBusConnectionPrivate::ObjectTreeNo
if (needle == haystack.obj) {
haystack.obj = nullptr;
- haystack.flags = 0;
+ haystack.flags = {};
}
}
@@ -580,7 +607,7 @@ static void huntAndUnregister(const QList<QStringView> &pathComponents, int i,
if (pathComponents.size() == i) {
// found it
node->obj = nullptr;
- node->flags = 0;
+ node->flags = {};
if (mode == QDBusConnection::UnregisterTree) {
// clear the sub-tree as well
@@ -605,11 +632,11 @@ static void huntAndEmit(DBusConnection *connection, DBusMessage *msg,
QObject *needle, const QDBusConnectionPrivate::ObjectTreeNode &haystack,
bool isScriptable, bool isAdaptor, const QString &path = QString())
{
- QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator it = haystack.children.constBegin();
- QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator end = haystack.children.constEnd();
- for ( ; it != end; ++it) {
- if (it->isActive())
- huntAndEmit(connection, msg, needle, *it, isScriptable, isAdaptor, path + u'/' + it->name);
+ for (const QDBusConnectionPrivate::ObjectTreeNode &node : std::as_const(haystack.children)) {
+ if (node.isActive()) {
+ huntAndEmit(connection, msg, needle, node, isScriptable, isAdaptor,
+ path + u'/' + node.name);
+ }
}
if (needle == haystack.obj) {
@@ -639,6 +666,7 @@ static int findSlot(const QMetaObject *mo, const QByteArray &name, int flags,
const QString &signature_, QList<QMetaType> &metaTypes)
{
QByteArray msgSignature = signature_.toLatin1();
+ QString parametersErrorMsg;
for (int idx = mo->methodCount() - 1 ; idx >= QObject::staticMetaObject.methodCount(); --idx) {
QMetaMethod mm = mo->method(idx);
@@ -665,8 +693,10 @@ static int findSlot(const QMetaObject *mo, const QByteArray &name, int flags,
QString errorMsg;
int inputCount = qDBusParametersForMethod(mm, metaTypes, errorMsg);
- if (inputCount == -1)
+ if (inputCount == -1) {
+ parametersErrorMsg = errorMsg;
continue; // problem parsing
+ }
metaTypes[0] = returnType;
bool hasMessage = false;
@@ -728,6 +758,13 @@ static int findSlot(const QMetaObject *mo, const QByteArray &name, int flags,
}
// no slot matched
+ if (!parametersErrorMsg.isEmpty()) {
+ qCWarning(dbusIntegration, "QDBusConnection: couldn't handle call to %s: %ls",
+ name.constData(), qUtf16Printable(parametersErrorMsg));
+ } else {
+ qCWarning(dbusIntegration, "QDBusConnection: couldn't handle call to %s, no slot matched",
+ name.constData());
+ }
return -1;
}
@@ -753,7 +790,6 @@ QDBusCallDeliveryEvent *QDBusConnectionPrivate::prepareReply(QDBusConnectionPriv
const QDBusMessage &msg)
{
Q_ASSERT(object);
- Q_UNUSED(object);
int n = metaTypes.size() - 1;
if (metaTypes[n] == QDBusMetaTypeId::message())
@@ -789,14 +825,15 @@ void QDBusConnectionPrivate::activateSignal(const QDBusConnectionPrivate::Signal
if (call == DIRECT_DELIVERY) {
// short-circuit delivery
Q_ASSERT(this == hook.obj);
- deliverCall(this, 0, msg, hook.params, hook.midx);
+ deliverCall(this, msg, hook.params, hook.midx);
return;
}
if (call)
postEventToThread(ActivateSignalAction, hook.obj, call);
}
-bool QDBusConnectionPrivate::activateCall(QObject* object, int flags, const QDBusMessage &msg)
+bool QDBusConnectionPrivate::activateCall(QObject *object, QDBusConnection::RegisterOptions flags,
+ const QDBusMessage &msg)
{
// This is called by QDBusConnectionPrivate::handleObjectCall to place a call
// to a slot on the object.
@@ -836,19 +873,15 @@ bool QDBusConnectionPrivate::activateCall(QObject* object, int flags, const QDBu
cacheKey += signature;
}
- QDBusSlotCache::Hash::ConstIterator cacheIt = slotCache.hash.constFind(cacheKey);
- while (cacheIt != slotCache.hash.constEnd() && cacheIt->flags != flags &&
- cacheIt.key() == cacheKey)
- ++cacheIt;
- if (cacheIt == slotCache.hash.constEnd() || cacheIt.key() != cacheKey)
- {
+ QDBusSlotCache::Key compoundKey{ std::move(cacheKey), flags };
+ QDBusSlotCache::Hash::ConstIterator cacheIt = slotCache.hash.constFind(compoundKey);
+ if (cacheIt == slotCache.hash.constEnd()) {
// not cached, analyze the meta object
const QMetaObject *mo = object->metaObject();
QByteArray memberName = msg.member().toUtf8();
// find a slot that matches according to the rules above
QDBusSlotCache::Data slotData;
- slotData.flags = flags;
slotData.slotIdx = ::findSlot(mo, memberName, flags, msg.signature(), slotData.metaTypes);
if (slotData.slotIdx == -1) {
// ### this is where we want to add the connection as an arg too
@@ -860,7 +893,7 @@ bool QDBusConnectionPrivate::activateCall(QObject* object, int flags, const QDBu
// save the negative lookup
slotData.slotIdx = -1;
slotData.metaTypes.clear();
- slotCache.hash.insert(cacheKey, slotData);
+ slotCache.hash.insert(compoundKey, slotData);
object->setProperty(cachePropertyName, QVariant::fromValue(slotCache));
qCWarning(dbusIntegration).nospace() << "Could not find slot " << mo->className()
@@ -870,24 +903,24 @@ bool QDBusConnectionPrivate::activateCall(QObject* object, int flags, const QDBu
}
// save to the cache
- slotCache.hash.insert(cacheKey, slotData);
+ slotCache.hash.insert(compoundKey, slotData);
object->setProperty(cachePropertyName, QVariant::fromValue(slotCache));
// found the slot to be called
- deliverCall(object, flags, msg, slotData.metaTypes, slotData.slotIdx);
+ deliverCall(object, msg, slotData.metaTypes, slotData.slotIdx);
return true;
} else if (cacheIt->slotIdx == -1) {
// negative cache
return false;
} else {
// use the cache
- deliverCall(object, flags, msg, cacheIt->metaTypes, cacheIt->slotIdx);
+ deliverCall(object, msg, cacheIt->metaTypes, cacheIt->slotIdx);
return true;
}
return false;
}
-void QDBusConnectionPrivate::deliverCall(QObject *object, int /*flags*/, const QDBusMessage &msg,
+void QDBusConnectionPrivate::deliverCall(QObject *object, const QDBusMessage &msg,
const QList<QMetaType> &metaTypes, int slotIdx)
{
Q_ASSERT_X(!object || QThread::currentThread() == object->thread(),
@@ -996,11 +1029,8 @@ void QDBusConnectionPrivate::deliverCall(QObject *object, int /*flags*/, const Q
return;
}
-extern bool qDBusInitThreads();
-
-QDBusConnectionPrivate::QDBusConnectionPrivate(QObject *p)
- : QObject(p),
- ref(1),
+QDBusConnectionPrivate::QDBusConnectionPrivate()
+ : ref(1),
mode(InvalidMode),
busService(nullptr),
connection(nullptr),
@@ -1026,12 +1056,8 @@ QDBusConnectionPrivate::QDBusConnectionPrivate(QObject *p)
this, &QDBusConnectionPrivate::handleObjectCall, Qt::QueuedConnection);
connect(this, &QDBusConnectionPrivate::messageNeedsSending,
this, &QDBusConnectionPrivate::sendInternal);
- connect(this, &QDBusConnectionPrivate::signalNeedsConnecting,
- this, &QDBusConnectionPrivate::addSignalHook, Qt::BlockingQueuedConnection);
- connect(this, &QDBusConnectionPrivate::signalNeedsDisconnecting,
- this, &QDBusConnectionPrivate::removeSignalHook, Qt::BlockingQueuedConnection);
- rootNode.flags = 0;
+ rootNode.flags = {};
// prepopulate watchedServices:
// we know that the owner of org.freedesktop.DBus is itself
@@ -1076,12 +1102,8 @@ QDBusConnectionPrivate::~QDBusConnectionPrivate()
void QDBusConnectionPrivate::collectAllObjects(QDBusConnectionPrivate::ObjectTreeNode &haystack,
QSet<QObject *> &set)
{
- QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it = haystack.children.begin();
-
- while (it != haystack.children.end()) {
- collectAllObjects(*it, set);
- it++;
- }
+ for (ObjectTreeNode &child : haystack.children)
+ collectAllObjects(child, set);
if (haystack.obj)
set.insert(haystack.obj);
@@ -1109,11 +1131,9 @@ void QDBusConnectionPrivate::closeConnection()
}
}
- for (auto it = pendingCalls.begin(); it != pendingCalls.end(); ++it) {
- auto call = *it;
- if (!call->ref.deref()) {
+ for (QDBusPendingCallPrivate *call : pendingCalls) {
+ if (!call->ref.deref())
delete call;
- }
}
pendingCalls.clear();
@@ -1124,18 +1144,12 @@ void QDBusConnectionPrivate::closeConnection()
// dangling pointer.
QSet<QObject *> allObjects;
collectAllObjects(rootNode, allObjects);
- SignalHookHash::const_iterator sit = signalHooks.constBegin();
- while (sit != signalHooks.constEnd()) {
- allObjects.insert(sit.value().obj);
- ++sit;
- }
+ for (const SignalHook &signalHook : std::as_const(signalHooks))
+ allObjects.insert(signalHook.obj);
// now disconnect ourselves
- QSet<QObject *>::const_iterator oit = allObjects.constBegin();
- while (oit != allObjects.constEnd()) {
- (*oit)->disconnect(this);
- ++oit;
- }
+ for (QObject *obj : std::as_const(allObjects))
+ obj->disconnect(this);
}
void QDBusConnectionPrivate::handleDBusDisconnection()
@@ -1175,17 +1189,15 @@ void QDBusConnectionPrivate::timerEvent(QTimerEvent *e)
void QDBusConnectionPrivate::doDispatch()
{
if (mode == ClientMode || mode == PeerMode) {
- while (q_dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS) ;
if (dispatchEnabled && !pendingMessages.isEmpty()) {
// dispatch previously queued messages
- PendingMessageList::Iterator it = pendingMessages.begin();
- PendingMessageList::Iterator end = pendingMessages.end();
- for ( ; it != end; ++it) {
- qDBusDebug() << this << "dequeueing message" << *it;
- handleMessage(std::move(*it));
+ for (QDBusMessage &message : pendingMessages) {
+ qDBusDebug() << this << "dequeueing message" << message;
+ handleMessage(std::move(message));
}
pendingMessages.clear();
}
+ while (q_dbus_connection_dispatch(connection) == DBUS_DISPATCH_DATA_REMAINS) ;
}
}
@@ -1281,7 +1293,6 @@ void QDBusConnectionPrivate::relaySignal(QObject *obj, const QMetaObject *mo, in
void QDBusConnectionPrivate::serviceOwnerChangedNoLock(const QString &name,
const QString &oldOwner, const QString &newOwner)
{
- Q_UNUSED(oldOwner);
// QDBusWriteLocker locker(UpdateSignalHookOwnerAction, this);
WatchedServicesHash::Iterator it = watchedServices.find(name);
if (it == watchedServices.end())
@@ -1311,14 +1322,13 @@ int QDBusConnectionPrivate::findSlot(QObject *obj, const QByteArray &normalizedN
}
bool QDBusConnectionPrivate::prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key,
- const QString &service,
- const QString &path, const QString &interface, const QString &name,
- const ArgMatchRules &argMatch,
- QObject *receiver, const char *signal, int minMIdx,
- bool buildSignature)
+ const QString &service, const QString &path,
+ const QString &interface, const QString &name,
+ const ArgMatchRules &argMatch, QObject *receiver,
+ const char *signal, int minMIdx, bool buildSignature,
+ QString &errorMsg)
{
QByteArray normalizedName = signal + 1;
- QString errorMsg;
hook.midx = findSlot(receiver, signal + 1, hook.params, errorMsg);
if (hook.midx == -1) {
normalizedName = QMetaObject::normalizedSignature(signal + 1);
@@ -1456,19 +1466,16 @@ void QDBusConnectionPrivate::activateObject(ObjectTreeNode &node, const QDBusMes
QDBusAdaptorConnector *connector;
if (node.flags & QDBusConnection::ExportAdaptors &&
(connector = qDBusFindAdaptorConnector(node.obj))) {
- int newflags = node.flags | QDBusConnection::ExportAllSlots;
+ auto newflags = node.flags | QDBusConnection::ExportAllSlots;
if (msg.interface().isEmpty()) {
// place the call in all interfaces
// let the first one that handles it to work
- QDBusAdaptorConnector::AdaptorMap::ConstIterator it =
- connector->adaptors.constBegin();
- QDBusAdaptorConnector::AdaptorMap::ConstIterator end =
- connector->adaptors.constEnd();
-
- for ( ; it != end; ++it)
- if (activateCall(it->adaptor, newflags, msg))
+ for (const QDBusAdaptorConnector::AdaptorData &adaptorData :
+ std::as_const(connector->adaptors)) {
+ if (activateCall(adaptorData.adaptor, newflags, msg))
return;
+ }
} else {
// check if we have an interface matching the name that was asked:
QDBusAdaptorConnector::AdaptorMap::ConstIterator it;
@@ -1666,7 +1673,7 @@ void QDBusConnectionPrivate::handleSignal(const QDBusMessage& msg)
key += u':';
key += msg.interface();
- QDBusReadLocker locker(HandleSignalAction, this);
+ QDBusWriteLocker locker(HandleSignalAction, this);
handleSignal(key, msg); // one try
key.truncate(msg.member().size() + 1); // keep the ':'
@@ -1757,10 +1764,10 @@ void QDBusConnectionPrivate::setPeer(DBusConnection *c, const QDBusErrorInternal
watchForDBusDisconnection();
- QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection);
+ QMetaObject::invokeMethod(this, &QDBusConnectionPrivate::doDispatch, Qt::QueuedConnection);
}
-static QDBusConnection::ConnectionCapabilities connectionCapabilies(DBusConnection *connection)
+static QDBusConnection::ConnectionCapabilities connectionCapabilities(DBusConnection *connection)
{
QDBusConnection::ConnectionCapabilities result;
typedef dbus_bool_t (*can_send_type_t)(DBusConnection *, int);
@@ -1786,7 +1793,7 @@ static QDBusConnection::ConnectionCapabilities connectionCapabilies(DBusConnecti
void QDBusConnectionPrivate::handleAuthentication()
{
- capabilities.storeRelaxed(connectionCapabilies(connection));
+ capabilities.storeRelaxed(::connectionCapabilities(connection));
isAuthenticated = true;
}
@@ -1845,7 +1852,7 @@ void QDBusConnectionPrivate::setConnection(DBusConnection *dbc, const QDBusError
qDBusDebug() << this << ": connected successfully";
// schedule a dispatch:
- QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection);
+ QMetaObject::invokeMethod(this, &QDBusConnectionPrivate::doDispatch, Qt::QueuedConnection);
}
extern "C"{
@@ -1853,7 +1860,6 @@ static void qDBusResultReceived(DBusPendingCall *pending, void *user_data)
{
QDBusPendingCallPrivate *call = reinterpret_cast<QDBusPendingCallPrivate *>(user_data);
Q_ASSERT(call->pending == pending);
- Q_UNUSED(pending);
QDBusConnectionPrivate::processFinishedCall(call);
}
}
@@ -1970,7 +1976,7 @@ bool QDBusConnectionPrivate::send(const QDBusMessage& message)
class QDBusBlockingCallWatcher
{
public:
- QDBusBlockingCallWatcher(const QDBusMessage &message)
+ Q_NODISCARD_CTOR QDBusBlockingCallWatcher(const QDBusMessage &message)
: m_message(message), m_maxCallTimeoutMs(0)
{
#if defined(QT_NO_DEBUG)
@@ -2053,29 +2059,18 @@ private:
QElapsedTimer m_callTimer;
};
-
QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message,
- int sendMode, int timeout)
+ QDBus::CallMode mode, int timeout)
{
QDBusBlockingCallWatcher watcher(message);
QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, nullptr, nullptr, nullptr, timeout);
Q_ASSERT(pcall);
- if (pcall->replyMessage.type() == QDBusMessage::InvalidMessage) {
- // need to wait for the reply
- if (sendMode == QDBus::BlockWithGui) {
- pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
- QEventLoop loop;
- loop.connect(pcall->watcherHelper, &QDBusPendingCallWatcherHelper::reply, &loop, &QEventLoop::quit);
- loop.connect(pcall->watcherHelper, &QDBusPendingCallWatcherHelper::error, &loop, &QEventLoop::quit);
-
- // enter the event loop and wait for a reply
- loop.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents);
- } else {
- pcall->waitForFinished();
- }
- }
+ if (mode == QDBus::BlockWithGui)
+ pcall->waitForFinishedWithGui();
+ else
+ pcall->waitForFinished();
QDBusMessage reply = pcall->replyMessage;
lastError = QDBusError(reply); // set or clear error
@@ -2136,6 +2131,7 @@ QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusM
pcall->setReplyCallback(receiver, returnMethod);
if (errorMethod) {
+ Q_ASSERT(!pcall->watcherHelper);
pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), receiver, errorMethod,
Qt::QueuedConnection);
@@ -2237,18 +2233,30 @@ bool QDBusConnectionPrivate::connectSignal(const QString &service,
QString key;
hook.signature = signature;
+ QString errorMsg;
if (!prepareHook(hook, key, service, path, interface, name, argumentMatch, receiver, slot, 0,
- false)) {
- qCWarning(dbusIntegration) << "Could not connect" << interface << "to" << slot + 1;
+ false, errorMsg)) {
+ qCWarning(dbusIntegration)
+ << "Could not connect" << interface << "to" << slot + 1 << ":" << qPrintable(errorMsg);
return false; // don't connect
}
Q_ASSERT(thread() != QThread::currentThread());
- return emit signalNeedsConnecting(key, hook);
+ return addSignalHook(key, hook);
}
bool QDBusConnectionPrivate::addSignalHook(const QString &key, const SignalHook &hook)
{
+ bool result = false;
+
+ QMetaObject::invokeMethod(this, &QDBusConnectionPrivate::addSignalHookImpl,
+ Qt::BlockingQueuedConnection, qReturnArg(result), key, hook);
+
+ return result;
+}
+
+bool QDBusConnectionPrivate::addSignalHookImpl(const QString &key, const SignalHook &hook)
+{
QDBusWriteLocker locker(ConnectAction, this);
// avoid duplicating:
@@ -2330,18 +2338,30 @@ bool QDBusConnectionPrivate::disconnectSignal(const QString &service,
name2.detach();
hook.signature = signature;
+ QString errorMsg;
if (!prepareHook(hook, key, service, path, interface, name, argumentMatch, receiver, slot, 0,
- false)) {
- qCWarning(dbusIntegration) << "Could not disconnect" << interface << "to" << slot + 1;
+ false, errorMsg)) {
+ qCWarning(dbusIntegration)
+ << "Could not disconnect" << interface << "to" << slot + 1 << ":" << qPrintable(errorMsg);
return false; // don't disconnect
}
Q_ASSERT(thread() != QThread::currentThread());
- return emit signalNeedsDisconnecting(key, hook);
+ return removeSignalHook(key, hook);
}
bool QDBusConnectionPrivate::removeSignalHook(const QString &key, const SignalHook &hook)
{
+ bool result = false;
+
+ QMetaObject::invokeMethod(this, &QDBusConnectionPrivate::removeSignalHookImpl,
+ Qt::BlockingQueuedConnection, qReturnArg(result), key, hook);
+
+ return result;
+}
+
+bool QDBusConnectionPrivate::removeSignalHookImpl(const QString &key, const SignalHook &hook)
+{
// remove it from our list:
QDBusWriteLocker locker(ConnectAction, this);
QDBusConnectionPrivate::SignalHookHash::Iterator it = signalHooks.find(key);
@@ -2428,8 +2448,8 @@ void QDBusConnectionPrivate::registerObject(const ObjectTreeNode *node)
connector->connectAllSignals(node->obj);
}
- connect(connector, SIGNAL(relaySignal(QObject*,const QMetaObject*,int,QVariantList)),
- this, SLOT(relaySignal(QObject*,const QMetaObject*,int,QVariantList)),
+ connect(connector, &QDBusAdaptorConnector::relaySignal, this,
+ &QDBusConnectionPrivate::relaySignal,
Qt::ConnectionType(Qt::QueuedConnection | Qt::UniqueConnection));
}
}
@@ -2462,14 +2482,16 @@ void QDBusConnectionPrivate::connectRelay(const QString &service,
QByteArray sig;
sig.append(QSIGNAL_CODE + '0');
sig.append(signal.methodSignature());
+ QString errorMsg;
if (!prepareHook(hook, key, service, path, interface, QString(), ArgMatchRules(), receiver, sig,
- QDBusAbstractInterface::staticMetaObject.methodCount(), true)) {
- qCWarning(dbusIntegration) << "Could not connect" << interface << "to" << signal.name();
+ QDBusAbstractInterface::staticMetaObject.methodCount(), true, errorMsg)) {
+ qCWarning(dbusIntegration)
+ << "Could not connect" << interface << "to" << signal.name() << ":" << qPrintable(errorMsg);
return; // don't connect
}
Q_ASSERT(thread() != QThread::currentThread());
- emit signalNeedsConnecting(key, hook);
+ addSignalHook(key, hook);
}
void QDBusConnectionPrivate::disconnectRelay(const QString &service,
@@ -2485,15 +2507,16 @@ void QDBusConnectionPrivate::disconnectRelay(const QString &service,
QByteArray sig;
sig.append(QSIGNAL_CODE + '0');
sig.append(signal.methodSignature());
+ QString errorMsg;
if (!prepareHook(hook, key, service, path, interface, QString(), ArgMatchRules(), receiver, sig,
- QDBusAbstractInterface::staticMetaObject.methodCount(), true)) {
- qCWarning(dbusIntegration)
- << "Could not disconnect" << interface << "to" << signal.methodSignature();
+ QDBusAbstractInterface::staticMetaObject.methodCount(), true, errorMsg)) {
+ qCWarning(dbusIntegration) << "Could not disconnect" << interface << "to"
+ << signal.methodSignature() << ":" << qPrintable(errorMsg);
return; // don't disconnect
}
Q_ASSERT(thread() != QThread::currentThread());
- emit signalNeedsDisconnecting(key, hook);
+ removeSignalHook(key, hook);
}
bool QDBusConnectionPrivate::shouldWatchService(const QString &service)
@@ -2678,6 +2701,28 @@ void QDBusConnectionPrivate::postEventToThread(int action, QObject *object, QEve
QDBusLockerBase::reportThreadAction(action, QDBusLockerBase::AfterPost, this);
}
+/*
+ * Enable dispatch of D-Bus events for this connection, but only after
+ * context's thread's event loop has started and processed any already
+ * pending events. The event dispatch is then enabled in the DBus aux thread.
+ */
+void QDBusConnectionPrivate::enableDispatchDelayed(QObject *context)
+{
+ ref.ref();
+ QMetaObject::invokeMethod(
+ context,
+ [this]() {
+ // This call cannot race with something disabling dispatch only
+ // because dispatch is never re-disabled from Qt code on an
+ // in-use connection once it has been enabled.
+ QMetaObject::invokeMethod(this, &QDBusConnectionPrivate::setDispatchEnabled,
+ Qt::QueuedConnection, true);
+ if (!ref.deref())
+ deleteLater();
+ },
+ Qt::QueuedConnection);
+}
+
QT_END_NAMESPACE
#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusintegrator_p.h b/src/dbus/qdbusintegrator_p.h
index 275735b5d5..b0c349799a 100644
--- a/src/dbus/qdbusintegrator_p.h
+++ b/src/dbus/qdbusintegrator_p.h
@@ -46,18 +46,34 @@ struct QDBusSlotCache
{
struct Data
{
- int flags;
int slotIdx;
QList<QMetaType> metaTypes;
void swap(Data &other) noexcept
{
- qSwap(flags, other.flags);
qSwap(slotIdx, other.slotIdx);
qSwap(metaTypes, other.metaTypes);
}
};
- typedef QMultiHash<QString, Data> Hash;
+
+ struct Key
+ {
+ QString memberWithSignature;
+ QDBusConnection::RegisterOptions flags;
+
+ friend bool operator==(const Key &lhs, const Key &rhs) noexcept
+ {
+ return lhs.memberWithSignature == rhs.memberWithSignature && lhs.flags == rhs.flags;
+ }
+
+ friend size_t qHash(const QDBusSlotCache::Key &key, size_t seed = 0) noexcept
+ {
+ return qHashMulti(seed, key.memberWithSignature, key.flags);
+ }
+ };
+
+ using Hash = QHash<Key, Data>;
+
Hash hash;
void swap(QDBusSlotCache &other) noexcept { qSwap(hash, other.hash); }
@@ -69,19 +85,14 @@ class QDBusCallDeliveryEvent: public QAbstractMetaCallEvent
{
public:
QDBusCallDeliveryEvent(const QDBusConnection &c, int id, QObject *sender,
- const QDBusMessage &msg, const QList<QMetaType> &types, int f = 0)
- : QAbstractMetaCallEvent(sender, -1),
- connection(c),
- message(msg),
- metaTypes(types),
- id(id),
- flags(f)
+ const QDBusMessage &msg, const QList<QMetaType> &types)
+ : QAbstractMetaCallEvent(sender, -1), connection(c), message(msg), metaTypes(types), id(id)
{
}
void placeMetaCall(QObject *object) override
{
- QDBusConnectionPrivate::d(connection)->deliverCall(object, flags, message, metaTypes, id);
+ QDBusConnectionPrivate::d(connection)->deliverCall(object, message, metaTypes, id);
}
private:
@@ -89,7 +100,6 @@ private:
QDBusMessage message;
QList<QMetaType> metaTypes;
int id;
- int flags;
};
class QDBusActivateObjectEvent: public QAbstractMetaCallEvent
@@ -117,18 +127,15 @@ class QDBusSpyCallEvent : public QAbstractMetaCallEvent
{
public:
typedef void (*Hook)(const QDBusMessage&);
- QDBusSpyCallEvent(QDBusConnectionPrivate *cp, const QDBusConnection &c, const QDBusMessage &msg,
- const Hook *hooks, int count)
- : QAbstractMetaCallEvent(cp, 0), conn(c), msg(msg), hooks(hooks), hookCount(count)
+ QDBusSpyCallEvent(QDBusConnectionPrivate *cp, const QDBusConnection &c, const QDBusMessage &msg)
+ : QAbstractMetaCallEvent(cp, 0), conn(c), msg(msg)
{}
~QDBusSpyCallEvent() override;
void placeMetaCall(QObject *) override;
- static inline void invokeSpyHooks(const QDBusMessage &msg, const Hook *hooks, int hookCount);
+ static inline void invokeSpyHooks(const QDBusMessage &msg);
QDBusConnection conn; // keeps the refcount in QDBusConnectionPrivate up
QDBusMessage msg;
- const Hook *hooks;
- int hookCount;
};
QT_END_NAMESPACE
diff --git a/src/dbus/qdbusinternalfilters.cpp b/src/dbus/qdbusinternalfilters.cpp
index d963903dc6..721564ed3c 100644
--- a/src/dbus/qdbusinternalfilters.cpp
+++ b/src/dbus/qdbusinternalfilters.cpp
@@ -73,14 +73,11 @@ static const char peerInterfaceXml[] =
" </method>\n"
" </interface>\n";
-static QString generateSubObjectXml(QObject *object)
+static QString generateSubObjectXml(const QObject *object)
{
QString retval;
- const QObjectList &objs = object->children();
- QObjectList::ConstIterator it = objs.constBegin();
- QObjectList::ConstIterator end = objs.constEnd();
- for ( ; it != end; ++it) {
- QString name = (*it)->objectName();
+ for (const QObject *child : object->children()) {
+ QString name = child->objectName();
if (!name.isEmpty() && QDBusUtil::isValidPartOfObjectPath(name))
retval += " <node name=\""_L1 + name + "\"/>\n"_L1;
}
@@ -116,20 +113,22 @@ QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode &node
(connector = qDBusFindAdaptorConnector(node.obj))) {
// trasverse every adaptor in this object
- QDBusAdaptorConnector::AdaptorMap::ConstIterator it = connector->adaptors.constBegin();
- QDBusAdaptorConnector::AdaptorMap::ConstIterator end = connector->adaptors.constEnd();
- for ( ; it != end; ++it) {
+ for (const QDBusAdaptorConnector::AdaptorData &adaptorData :
+ std::as_const(connector->adaptors)) {
// add the interface:
- QString ifaceXml = QDBusAbstractAdaptorPrivate::retrieveIntrospectionXml(it->adaptor);
+ QString ifaceXml =
+ QDBusAbstractAdaptorPrivate::retrieveIntrospectionXml(adaptorData.adaptor);
if (ifaceXml.isEmpty()) {
// add the interface's contents:
- ifaceXml += qDBusGenerateMetaObjectXml(QString::fromLatin1(it->interface),
- it->adaptor->metaObject(),
- &QDBusAbstractAdaptor::staticMetaObject,
- QDBusConnection::ExportScriptableContents
- | QDBusConnection::ExportNonScriptableContents);
-
- QDBusAbstractAdaptorPrivate::saveIntrospectionXml(it->adaptor, ifaceXml);
+ ifaceXml += qDBusGenerateMetaObjectXml(
+ QString::fromLatin1(adaptorData.interface),
+ adaptorData.adaptor->metaObject(),
+ &QDBusAbstractAdaptor::staticMetaObject,
+ QDBusConnection::ExportScriptableContents
+ | QDBusConnection::ExportNonScriptableContents);
+
+ QDBusAbstractAdaptorPrivate::saveIntrospectionXml(adaptorData.adaptor,
+ ifaceXml);
}
xml_data += ifaceXml;
@@ -151,13 +150,10 @@ QString qDBusIntrospectObject(const QDBusConnectionPrivate::ObjectTreeNode &node
xml_data += generateSubObjectXml(node.obj);
} else {
// generate from the object tree
- QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator it =
- node.children.constBegin();
- QDBusConnectionPrivate::ObjectTreeNode::DataList::ConstIterator end =
- node.children.constEnd();
- for ( ; it != end; ++it)
- if (it->obj || !it->children.isEmpty())
- xml_data += " <node name=\""_L1 + it->name + "\"/>\n"_L1;
+ for (const QDBusConnectionPrivate::ObjectTreeNode &node : node.children) {
+ if (node.obj || !node.children.isEmpty())
+ xml_data += " <node name=\""_L1 + node.name + "\"/>\n"_L1;
+ }
}
xml_data += "</node>\n"_L1;
@@ -195,7 +191,7 @@ QDBusMessage qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode &node
QString interface_name = msg.arguments().at(0).toString();
QByteArray property_name = msg.arguments().at(1).toString().toUtf8();
- QDBusAdaptorConnector *connector;
+ const QDBusAdaptorConnector *connector;
QVariant value;
bool interfaceFound = false;
if (node.flags & QDBusConnection::ExportAdaptors &&
@@ -204,12 +200,11 @@ QDBusMessage qDBusPropertyGet(const QDBusConnectionPrivate::ObjectTreeNode &node
// find the class that implements interface_name or try until we've found the property
// in case of an empty interface
if (interface_name.isEmpty()) {
- for (QDBusAdaptorConnector::AdaptorMap::ConstIterator it = connector->adaptors.constBegin(),
- end = connector->adaptors.constEnd(); it != end; ++it) {
- const QMetaObject *mo = it->adaptor->metaObject();
+ for (const QDBusAdaptorConnector::AdaptorData &adaptorData : connector->adaptors) {
+ const QMetaObject *mo = adaptorData.adaptor->metaObject();
int pidx = mo->indexOfProperty(property_name);
if (pidx != -1) {
- value = mo->property(pidx).read(it->adaptor);
+ value = mo->property(pidx).read(adaptorData.adaptor);
break;
}
}
@@ -332,14 +327,14 @@ static int writeProperty(QObject *obj, const QByteArray &property_name, QVariant
return PropertyWriteFailed;
}
- value = other;
+ value = std::move(other);
}
if (mp.metaType() == QMetaType::fromType<QDBusVariant>())
value = QVariant::fromValue(QDBusVariant(value));
// the property type here should match
- return mp.write(obj, value) ? PropertyWriteSuccess : PropertyWriteFailed;
+ return mp.write(obj, std::move(value)) ? PropertyWriteSuccess : PropertyWriteFailed;
}
QDBusMessage qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode &node,
@@ -361,9 +356,9 @@ QDBusMessage qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode &node
// find the class that implements interface_name or try until we've found the property
// in case of an empty interface
if (interface_name.isEmpty()) {
- for (QDBusAdaptorConnector::AdaptorMap::ConstIterator it = connector->adaptors.constBegin(),
- end = connector->adaptors.constEnd(); it != end; ++it) {
- int status = writeProperty(it->adaptor, property_name, value);
+ for (const QDBusAdaptorConnector::AdaptorData &adaptorData :
+ std::as_const(connector->adaptors)) {
+ int status = writeProperty(adaptorData.adaptor, property_name, value);
if (status == PropertyNotFound)
continue;
return propertyWriteReply(msg, interface_name, property_name, status);
@@ -401,10 +396,8 @@ QDBusMessage qDBusPropertySet(const QDBusConnectionPrivate::ObjectTreeNode &node
// unite two QVariantMaps, but don't generate duplicate keys
static QVariantMap &operator+=(QVariantMap &lhs, const QVariantMap &rhs)
{
- QVariantMap::ConstIterator it = rhs.constBegin(),
- end = rhs.constEnd();
- for ( ; it != end; ++it)
- lhs.insert(it.key(), it.value());
+ for (const auto &[key, value] : rhs.asKeyValueRange())
+ lhs.insert(key, value);
return lhs;
}
@@ -461,9 +454,10 @@ QDBusMessage qDBusPropertyGetAll(const QDBusConnectionPrivate::ObjectTreeNode &n
if (interface_name.isEmpty()) {
// iterate over all interfaces
- for (QDBusAdaptorConnector::AdaptorMap::ConstIterator it = connector->adaptors.constBegin(),
- end = connector->adaptors.constEnd(); it != end; ++it) {
- result += readAllProperties(it->adaptor, QDBusConnection::ExportAllProperties);
+ for (const QDBusAdaptorConnector::AdaptorData &adaptorData :
+ std::as_const(connector->adaptors)) {
+ result += readAllProperties(adaptorData.adaptor,
+ QDBusConnection::ExportAllProperties);
}
} else {
// find the class that implements interface_name
diff --git a/src/dbus/qdbusintrospection.cpp b/src/dbus/qdbusintrospection.cpp
index 3f8766636f..04b5ab7751 100644
--- a/src/dbus/qdbusintrospection.cpp
+++ b/src/dbus/qdbusintrospection.cpp
@@ -21,6 +21,9 @@ QT_BEGIN_NAMESPACE
But they may prove useful if the XML data was obtained through other means (like parsing a file).
*/
+QDBusIntrospection::DiagnosticsReporter::~DiagnosticsReporter()
+ = default;
+
/*!
\class QDBusIntrospection::Argument
\inmodule QtDBus
@@ -297,11 +300,11 @@ QT_BEGIN_NAMESPACE
If there are multiple interfaces in this XML data, it is undefined which one will be
returned.
*/
-QDBusIntrospection::Interface
-QDBusIntrospection::parseInterface(const QString &xml)
+QDBusIntrospection::Interface QDBusIntrospection::parseInterface(const QString &xml,
+ DiagnosticsReporter *reporter)
{
// be lazy
- Interfaces ifs = parseInterfaces(xml);
+ Interfaces ifs = parseInterfaces(xml, reporter);
if (ifs.isEmpty())
return Interface();
@@ -315,11 +318,11 @@ QDBusIntrospection::parseInterface(const QString &xml)
If the first element tag in this document fragment is \<node\>, the interfaces parsed will
be those found as child elements of the \<node\> tag.
*/
-QDBusIntrospection::Interfaces
-QDBusIntrospection::parseInterfaces(const QString &xml)
+QDBusIntrospection::Interfaces QDBusIntrospection::parseInterfaces(const QString &xml,
+ DiagnosticsReporter *reporter)
{
QString null;
- QDBusXmlParser parser(null, null, xml);
+ QDBusXmlParser parser(null, null, xml, reporter);
return parser.interfaces();
}
@@ -334,10 +337,12 @@ QDBusIntrospection::parseInterfaces(const QString &xml)
This function does not parse the interfaces contained in the node, nor sub-object's contents.
It will only list their names.
*/
-QDBusIntrospection::Object
-QDBusIntrospection::parseObject(const QString &xml, const QString &service, const QString &path)
+QDBusIntrospection::Object QDBusIntrospection::parseObject(const QString &xml,
+ const QString &service,
+ const QString &path,
+ DiagnosticsReporter *reporter)
{
- QDBusXmlParser parser(service, path, xml);
+ QDBusXmlParser parser(service, path, xml, reporter);
QSharedDataPointer<QDBusIntrospection::Object> retval = parser.object();
if (!retval)
return QDBusIntrospection::Object();
diff --git a/src/dbus/qdbusintrospection_p.h b/src/dbus/qdbusintrospection_p.h
index 0dd7f70579..766cdffb62 100644
--- a/src/dbus/qdbusintrospection_p.h
+++ b/src/dbus/qdbusintrospection_p.h
@@ -18,7 +18,6 @@
#include <QtDBus/private/qtdbusglobal_p.h>
#include <QtCore/qlist.h>
#include <QtCore/qmap.h>
-#include <QtCore/qpair.h>
#include <QtCore/qshareddata.h>
#include <QtCore/qstring.h>
#include <QtCore/qstringlist.h>
@@ -38,9 +37,10 @@ public:
struct Interface;
struct Object;
struct ObjectTree;
+ struct Annotation;
// typedefs
- typedef QMap<QString, QString> Annotations;
+ typedef QMap<QString, Annotation> Annotations;
typedef QList<Argument> Arguments;
typedef QMultiMap<QString, Method> Methods;
typedef QMultiMap<QString, Signal> Signals;
@@ -51,8 +51,40 @@ public:
public:
// the structs
+ // Line and column numbers have the same meaning as in QXmlStreamReader.
+ struct SourceLocation
+ {
+ qint64 lineNumber = 1;
+ qint64 columnNumber = 0;
+ };
+
+ class Q_DBUS_EXPORT DiagnosticsReporter
+ {
+ Q_DISABLE_COPY_MOVE(DiagnosticsReporter)
+ public:
+ DiagnosticsReporter() = default;
+ virtual ~DiagnosticsReporter();
+ virtual void warning(const SourceLocation &location, const char *msg, ...)
+ Q_ATTRIBUTE_FORMAT_PRINTF(3, 4) = 0;
+ virtual void error(const SourceLocation &location, const char *msg, ...)
+ Q_ATTRIBUTE_FORMAT_PRINTF(3, 4) = 0;
+ };
+
+ struct Annotation
+ {
+ SourceLocation location;
+ QString name;
+ QString value;
+
+ inline bool operator==(const Annotation &other) const
+ {
+ return name == other.name && value == other.value;
+ }
+ };
+
struct Argument
{
+ SourceLocation location;
QString type;
QString name;
@@ -62,6 +94,7 @@ public:
struct Method
{
+ SourceLocation location;
QString name;
Arguments inputArgs;
Arguments outputArgs;
@@ -74,6 +107,7 @@ public:
struct Signal
{
+ SourceLocation location;
QString name;
Arguments outputArgs;
Annotations annotations;
@@ -86,6 +120,7 @@ public:
struct Property
{
enum Access { Read, Write, ReadWrite };
+ SourceLocation location;
QString name;
QString type;
Access access;
@@ -98,6 +133,7 @@ public:
struct Interface: public QSharedData
{
+ SourceLocation location;
QString name;
QString introspection;
@@ -112,6 +148,7 @@ public:
struct Object: public QSharedData
{
+ SourceLocation location;
QString service;
QString path;
@@ -120,10 +157,11 @@ public:
};
public:
- static Interface parseInterface(const QString &xml);
- static Interfaces parseInterfaces(const QString &xml);
+ static Interface parseInterface(const QString &xml, DiagnosticsReporter *reporter = nullptr);
+ static Interfaces parseInterfaces(const QString &xml, DiagnosticsReporter *reporter = nullptr);
static Object parseObject(const QString &xml, const QString &service = QString(),
- const QString &path = QString());
+ const QString &path = QString(),
+ DiagnosticsReporter *reporter = nullptr);
private:
QDBusIntrospection();
diff --git a/src/dbus/qdbusmarshaller.cpp b/src/dbus/qdbusmarshaller.cpp
index e3fb298fbe..b2ed2586fb 100644
--- a/src/dbus/qdbusmarshaller.cpp
+++ b/src/dbus/qdbusmarshaller.cpp
@@ -28,7 +28,7 @@ QDBusMarshaller::~QDBusMarshaller()
void QDBusMarshaller::unregisteredTypeError(QMetaType id)
{
const char *name = id.name();
- qWarning("QDBusMarshaller: type '%s' (%d) is not registered with D-BUS. "
+ qWarning("QDBusMarshaller: type '%s' (%d) is not registered with D-Bus. "
"Use qDBusRegisterMetaType to register it",
name ? name : "", id.id());
error("Unregistered type %1 passed in arguments"_L1
@@ -206,10 +206,8 @@ inline void QDBusMarshaller::append(const QStringList &arg)
QDBusMarshaller sub(capabilities);
open(sub, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING);
- QStringList::ConstIterator it = arg.constBegin();
- QStringList::ConstIterator end = arg.constEnd();
- for ( ; it != end; ++it)
- sub.append(*it);
+ for (const QString &s : arg)
+ sub.append(s);
// don't call sub.close(): it auto-closes
}
@@ -239,7 +237,7 @@ inline QDBusMarshaller *QDBusMarshaller::beginMap(QMetaType kid, QMetaType vid)
if (ksignature[1] != 0 || !QDBusUtil::isValidBasicType(*ksignature)) {
QT_WARNING_PUSH
QT_WARNING_DISABLE_GCC("-Wformat-overflow")
- qWarning("QDBusMarshaller: type '%s' (%d) cannot be used as the key type in a D-BUS map.",
+ qWarning("QDBusMarshaller: type '%s' (%d) cannot be used as the key type in a D-Bus map.",
kid.name(), kid.id());
QT_WARNING_POP
error("Type %1 passed in arguments cannot be used as a key in a map"_L1
@@ -362,7 +360,7 @@ bool QDBusMarshaller::appendVariantInternal(const QVariant &arg)
QDBusDemarshaller demarshaller(capabilities);
demarshaller.message = q_dbus_message_ref(d->message);
- if (d->direction == Demarshalling) {
+ if (d->direction == Direction::Demarshalling) {
// it's demarshalling; just copy
demarshaller.iterator = static_cast<QDBusDemarshaller *>(d)->iterator;
} else {
@@ -474,7 +472,7 @@ bool QDBusMarshaller::appendVariantInternal(const QVariant &arg)
Q_FALLTHROUGH();
default:
- qWarning("QDBusMarshaller::appendVariantInternal: Found unknown D-BUS type '%s'",
+ qWarning("QDBusMarshaller::appendVariantInternal: Found unknown D-Bus type '%s'",
signature);
return false;
}
@@ -494,7 +492,7 @@ bool QDBusMarshaller::appendCrossMarshalling(QDBusDemarshaller *demarshaller)
int code = q_dbus_message_iter_get_arg_type(&demarshaller->iterator);
if (QDBusUtil::isValidBasicType(code)) {
// easy: just append
- // do exactly like the D-BUS docs suggest
+ // do exactly like the D-Bus docs suggest
// (see apidocs for q_dbus_message_iter_get_basic)
qlonglong value;
diff --git a/src/dbus/qdbusmessage.cpp b/src/dbus/qdbusmessage.cpp
index fb3f8600e1..6ef762f225 100644
--- a/src/dbus/qdbusmessage.cpp
+++ b/src/dbus/qdbusmessage.cpp
@@ -36,22 +36,37 @@ static inline const char *data(const QByteArray &arr)
}
QDBusMessagePrivate::QDBusMessagePrivate()
- : msg(nullptr), reply(nullptr), localReply(nullptr), ref(1), type(QDBusMessage::InvalidMessage),
- delayedReply(false), localMessage(false),
- parametersValidated(false), autoStartService(true),
- interactiveAuthorizationAllowed(false)
+ : localReply(nullptr), ref(1), type(QDBusMessage::InvalidMessage),
+ delayedReply(false), parametersValidated(false),
+ localMessage(false), autoStartService(true),
+ interactiveAuthorizationAllowed(false), isReplyRequired(false)
{
}
QDBusMessagePrivate::~QDBusMessagePrivate()
{
- if (msg)
- q_dbus_message_unref(msg);
- if (reply)
- q_dbus_message_unref(reply);
delete localReply;
}
+void QDBusMessagePrivate::createResponseLink(const QDBusMessagePrivate *call)
+{
+ if (Q_UNLIKELY(call->type != QDBusMessage::MethodCallMessage)) {
+ qWarning("QDBusMessage: replying to a message that isn't a method call");
+ return;
+ }
+
+ if (call->localMessage) {
+ localMessage = true;
+ call->localReply = new QDBusMessage(*this); // keep an internal copy
+ } else {
+ serial = call->serial;
+ service = call->service;
+ }
+
+ // the reply must have a serial or be a local-loop optimization
+ Q_ASSERT(serial || localMessage);
+}
+
/*!
\since 4.3
Returns the human-readable message associated with the error that was received.
@@ -113,8 +128,8 @@ DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message, QDB
case QDBusMessage::ReplyMessage:
msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
if (!d_ptr->localMessage) {
- q_dbus_message_set_destination(msg, q_dbus_message_get_sender(d_ptr->reply));
- q_dbus_message_set_reply_serial(msg, q_dbus_message_get_serial(d_ptr->reply));
+ q_dbus_message_set_destination(msg, data(d_ptr->service.toUtf8()));
+ q_dbus_message_set_reply_serial(msg, d_ptr->serial);
}
break;
case QDBusMessage::ErrorMessage:
@@ -126,8 +141,8 @@ DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message, QDB
msg = q_dbus_message_new(DBUS_MESSAGE_TYPE_ERROR);
q_dbus_message_set_error_name(msg, d_ptr->name.toUtf8());
if (!d_ptr->localMessage) {
- q_dbus_message_set_destination(msg, q_dbus_message_get_sender(d_ptr->reply));
- q_dbus_message_set_reply_serial(msg, q_dbus_message_get_serial(d_ptr->reply));
+ q_dbus_message_set_destination(msg, data(d_ptr->service.toUtf8()));
+ q_dbus_message_set_reply_serial(msg, d_ptr->serial);
}
break;
case QDBusMessage::SignalMessage:
@@ -155,14 +170,12 @@ DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message, QDB
d_ptr->parametersValidated = true;
QDBusMarshaller marshaller(capabilities);
- QVariantList::ConstIterator it = d_ptr->arguments.constBegin();
- QVariantList::ConstIterator cend = d_ptr->arguments.constEnd();
q_dbus_message_iter_init_append(msg, &marshaller.iterator);
if (!d_ptr->message.isEmpty())
// prepend the error message
marshaller.append(d_ptr->message);
- for ( ; it != cend; ++it)
- marshaller.appendVariantInternal(*it);
+ for (const QVariant &argument : std::as_const(d_ptr->arguments))
+ marshaller.appendVariantInternal(argument);
// check if everything is ok
if (marshaller.ok)
@@ -206,6 +219,7 @@ QDBusMessage QDBusMessagePrivate::fromDBusMessage(DBusMessage *dmsg, QDBusConnec
return message;
message.d_ptr->type = QDBusMessage::MessageType(q_dbus_message_get_type(dmsg));
+ message.d_ptr->serial = q_dbus_message_get_serial(dmsg);
message.d_ptr->path = QString::fromUtf8(q_dbus_message_get_path(dmsg));
message.d_ptr->interface = QString::fromUtf8(q_dbus_message_get_interface(dmsg));
message.d_ptr->name = message.d_ptr->type == DBUS_MESSAGE_TYPE_ERROR ?
@@ -214,7 +228,7 @@ QDBusMessage QDBusMessagePrivate::fromDBusMessage(DBusMessage *dmsg, QDBusConnec
message.d_ptr->service = QString::fromUtf8(q_dbus_message_get_sender(dmsg));
message.d_ptr->signature = QString::fromUtf8(q_dbus_message_get_signature(dmsg));
message.d_ptr->interactiveAuthorizationAllowed = q_dbus_message_get_allow_interactive_authorization(dmsg);
- message.d_ptr->msg = q_dbus_message_ref(dmsg);
+ message.d_ptr->isReplyRequired = !q_dbus_message_get_no_reply(dmsg);
QDBusDemarshaller demarshaller(capabilities);
demarshaller.message = q_dbus_message_ref(dmsg);
@@ -239,10 +253,8 @@ QDBusMessage QDBusMessagePrivate::makeLocal(const QDBusConnectionPrivate &conn,
// determine if we are carrying any complex types
QString computedSignature;
- QVariantList::ConstIterator it = asSent.d_ptr->arguments.constBegin();
- QVariantList::ConstIterator end = asSent.d_ptr->arguments.constEnd();
- for ( ; it != end; ++it) {
- QMetaType id = it->metaType();
+ for (const QVariant &argument : std::as_const(asSent.d_ptr->arguments)) {
+ QMetaType id = argument.metaType();
const char *signature = QDBusMetaType::typeToSignature(id);
if ((id.id() != QMetaType::QStringList && id.id() != QMetaType::QByteArray &&
qstrlen(signature) != 1) || id == QMetaType::fromType<QDBusVariant>()) {
@@ -406,6 +418,7 @@ QDBusMessage QDBusMessage::createMethodCall(const QString &service, const QStrin
message.d_ptr->path = path;
message.d_ptr->interface = interface;
message.d_ptr->name = method;
+ message.d_ptr->isReplyRequired = true;
return message;
}
@@ -448,15 +461,7 @@ QDBusMessage QDBusMessage::createReply(const QVariantList &arguments) const
QDBusMessage reply;
reply.setArguments(arguments);
reply.d_ptr->type = ReplyMessage;
- if (d_ptr->msg)
- reply.d_ptr->reply = q_dbus_message_ref(d_ptr->msg);
- if (d_ptr->localMessage) {
- reply.d_ptr->localMessage = true;
- d_ptr->localReply = new QDBusMessage(reply); // keep an internal copy
- }
-
- // the reply must have a msg or be a local-loop optimization
- Q_ASSERT(reply.d_ptr->reply || reply.d_ptr->localMessage);
+ reply.d_ptr->createResponseLink(d_ptr);
return reply;
}
@@ -467,15 +472,7 @@ QDBusMessage QDBusMessage::createReply(const QVariantList &arguments) const
QDBusMessage QDBusMessage::createErrorReply(const QString &name, const QString &msg) const
{
QDBusMessage reply = QDBusMessage::createError(name, msg);
- if (d_ptr->msg)
- reply.d_ptr->reply = q_dbus_message_ref(d_ptr->msg);
- if (d_ptr->localMessage) {
- reply.d_ptr->localMessage = true;
- d_ptr->localReply = new QDBusMessage(reply); // keep an internal copy
- }
-
- // the reply must have a msg or be a local-loop optimization
- Q_ASSERT(reply.d_ptr->reply || reply.d_ptr->localMessage);
+ reply.d_ptr->createResponseLink(d_ptr);
return reply;
}
@@ -559,6 +556,8 @@ QDBusMessage &QDBusMessage::operator=(const QDBusMessage &other)
*/
QString QDBusMessage::service() const
{
+ if (d_ptr->type == ErrorMessage || d_ptr->type == ReplyMessage)
+ return QString(); // d_ptr->service holds the destination
return d_ptr->service;
}
@@ -621,9 +620,9 @@ bool QDBusMessage::isReplyRequired() const
if (d_ptr->type != QDBusMessage::MethodCallMessage)
return false;
- if (!d_ptr->msg)
- return d_ptr->localMessage; // if it's a local message, reply is required
- return !q_dbus_message_get_no_reply(d_ptr->msg);
+ if (d_ptr->localMessage) // if it's a local message, reply is required
+ return true;
+ return d_ptr->isReplyRequired;
}
/*!
@@ -695,20 +694,26 @@ bool QDBusMessage::autoStartService() const
}
/*!
- Sets the interactive authorization flag to \a enable.
- This flag only makes sense for method call messages, where it
- tells the D-Bus server that the caller of the method is prepared
- to wait for interactive authorization to take place (for instance
- via Polkit) before the actual method is processed.
+ Enables or disables the \c ALLOW_INTERACTIVE_AUTHORIZATION flag
+ in a message.
+
+ This flag only makes sense for method call messages
+ (\l QDBusMessage::MethodCallMessage). If \a enable
+ is set to \c true, the flag indicates to the callee that the
+ caller of the method is prepared to wait for interactive authorization
+ to take place (for instance via Polkit) before the actual method
+ is processed.
- By default this flag is false and the other end is expected to
- make any authorization decisions non-interactively and promptly.
+ If \a enable is set to \c false, the flag is not
+ set, meaning that the other end is expected to make any authorization
+ decisions non-interactively and promptly. This is the default.
The \c org.freedesktop.DBus.Error.InteractiveAuthorizationRequired
error indicates that authorization failed, but could have succeeded
if this flag had been set.
- \sa isInteractiveAuthorizationAllowed()
+ \sa isInteractiveAuthorizationAllowed(),
+ QDBusAbstractInterface::setInteractiveAuthorizationAllowed()
\since 5.12
*/
@@ -718,12 +723,11 @@ void QDBusMessage::setInteractiveAuthorizationAllowed(bool enable)
}
/*!
- Returns the interactive authorization allowed flag, as set by
- setInteractiveAuthorizationAllowed(). By default this flag
- is false and the other end is expected to make any authorization
- decisions non-interactively and promptly.
+ Returns whether the message has the
+ \c ALLOW_INTERACTIVE_AUTHORIZATION flag set.
- \sa setInteractiveAuthorizationAllowed()
+ \sa setInteractiveAuthorizationAllowed(),
+ QDBusAbstractInterface::isInteractiveAuthorizationAllowed()
\since 5.12
*/
@@ -763,6 +767,12 @@ QDBusMessage &QDBusMessage::operator<<(const QVariant &arg)
return *this;
}
+QDBusMessage::QDBusMessage(QDBusMessagePrivate &dd)
+ : d_ptr(&dd)
+{
+ d_ptr->ref.ref();
+}
+
/*!
Returns the message type.
*/
@@ -804,12 +814,10 @@ static QDebug operator<<(QDebug dbg, QDBusMessage::MessageType t)
static void debugVariantList(QDebug dbg, const QVariantList &list)
{
bool first = true;
- QVariantList::ConstIterator it = list.constBegin();
- QVariantList::ConstIterator end = list.constEnd();
- for ( ; it != end; ++it) {
+ for (const QVariant &elem : list) {
if (!first)
dbg.nospace() << ", ";
- dbg.nospace() << qPrintable(QDBusUtil::argumentToString(*it));
+ dbg.nospace() << qPrintable(QDBusUtil::argumentToString(elem));
first = false;
}
}
diff --git a/src/dbus/qdbusmessage.h b/src/dbus/qdbusmessage.h
index 644a1170e3..f6db3bc21e 100644
--- a/src/dbus/qdbusmessage.h
+++ b/src/dbus/qdbusmessage.h
@@ -84,6 +84,7 @@ public:
QDBusMessage &operator<<(const QVariant &arg);
private:
+ explicit QDBusMessage(QDBusMessagePrivate &dd);
friend class QDBusMessagePrivate;
QDBusMessagePrivate *d_ptr;
};
diff --git a/src/dbus/qdbusmessage_p.h b/src/dbus/qdbusmessage_p.h
index cca1b4bd19..88ba78025e 100644
--- a/src/dbus/qdbusmessage_p.h
+++ b/src/dbus/qdbusmessage_p.h
@@ -39,20 +39,22 @@ public:
// the following parameters are "const": they are not changed after the constructors
// the parametersValidated member below controls whether they've been validated already
+ // (service is also used to store the destination of reply-type messages)
QString service, path, interface, name, message, signature;
- DBusMessage *msg;
- DBusMessage *reply;
mutable QDBusMessage *localReply;
QAtomicInt ref;
QDBusMessage::MessageType type;
+ uint32_t serial; // if type == MethodCall; the incoming serial; if type == Reply or Error, the serial we're replying to
mutable uint delayedReply : 1;
- uint localMessage : 1;
mutable uint parametersValidated : 1;
+ uint localMessage : 1;
uint autoStartService : 1;
uint interactiveAuthorizationAllowed : 1;
+ uint isReplyRequired : 1;
+ void createResponseLink(const QDBusMessagePrivate *call);
static void setParametersValidated(QDBusMessage &msg, bool enable)
{ msg.d_ptr->parametersValidated = enable; }
diff --git a/src/dbus/qdbusmetaobject.cpp b/src/dbus/qdbusmetaobject.cpp
index 054bc448e6..543b185df9 100644
--- a/src/dbus/qdbusmetaobject.cpp
+++ b/src/dbus/qdbusmetaobject.cpp
@@ -55,8 +55,9 @@ private:
QByteArray name;
};
- QMap<QByteArray, Method> signals_;
- QMap<QByteArray, Method> methods;
+ using MethodMap = QMap<QByteArray, Method>;
+ MethodMap signals_;
+ MethodMap methods;
QMap<QByteArray, Property> properties;
const QDBusIntrospection::Interface *data;
@@ -70,7 +71,7 @@ private:
void parseSignals();
void parseProperties();
- static qsizetype aggregateParameterCount(const QMap<QByteArray, Method> &map);
+ static qsizetype aggregateParameterCount(const MethodMap &map);
};
static const qsizetype intsPerProperty = 2;
@@ -147,7 +148,8 @@ QDBusMetaObjectGenerator::findType(const QByteArray &signature,
.arg(id);
// extract from annotations:
- QByteArray typeName = annotations.value(annotationName).toLatin1();
+ auto annotation = annotations.value(annotationName);
+ QByteArray typeName = annotation.value.toLatin1();
// verify that it's a valid one
if (typeName.isEmpty()) {
@@ -157,7 +159,8 @@ QDBusMetaObjectGenerator::findType(const QByteArray &signature,
annotationName += QString::fromLatin1(".%1%2")
.arg(QLatin1StringView(direction))
.arg(id);
- typeName = annotations.value(annotationName).toLatin1();
+ annotation = annotations.value(annotationName);
+ typeName = annotation.value.toLatin1();
}
if (!typeName.isEmpty()) {
@@ -208,10 +211,7 @@ void QDBusMetaObjectGenerator::parseMethods()
// Add cloned methods when the remote object has return types
//
- QDBusIntrospection::Methods::ConstIterator method_it = data->methods.constBegin();
- QDBusIntrospection::Methods::ConstIterator method_end = data->methods.constEnd();
- for ( ; method_it != method_end; ++method_it) {
- const QDBusIntrospection::Method &m = *method_it;
+ for (const QDBusIntrospection::Method &m : std::as_const(data->methods)) {
Method mm;
mm.name = m.name.toLatin1();
@@ -271,7 +271,7 @@ void QDBusMetaObjectGenerator::parseMethods()
prototype.append(')');
// check the async tag
- if (m.annotations.value(ANNOTATION_NO_WAIT ""_L1) == "true"_L1)
+ if (m.annotations.value(ANNOTATION_NO_WAIT ""_L1).value == "true"_L1)
mm.tag = "Q_NOREPLY";
// meta method flags
@@ -284,10 +284,7 @@ void QDBusMetaObjectGenerator::parseMethods()
void QDBusMetaObjectGenerator::parseSignals()
{
- QDBusIntrospection::Signals::ConstIterator signal_it = data->signals_.constBegin();
- QDBusIntrospection::Signals::ConstIterator signal_end = data->signals_.constEnd();
- for ( ; signal_it != signal_end; ++signal_it) {
- const QDBusIntrospection::Signal &s = *signal_it;
+ for (const QDBusIntrospection::Signal &s : std::as_const(data->signals_)) {
Method mm;
mm.name = s.name.toLatin1();
@@ -331,10 +328,7 @@ void QDBusMetaObjectGenerator::parseSignals()
void QDBusMetaObjectGenerator::parseProperties()
{
- QDBusIntrospection::Properties::ConstIterator prop_it = data->properties.constBegin();
- QDBusIntrospection::Properties::ConstIterator prop_end = data->properties.constEnd();
- for ( ; prop_it != prop_end; ++prop_it) {
- const QDBusIntrospection::Property &p = *prop_it;
+ for (const QDBusIntrospection::Property &p : std::as_const(data->properties)) {
Property mp;
Type type = findType(p.type.toLatin1(), p.annotations);
if (type.id == QMetaType::UnknownType)
@@ -360,14 +354,11 @@ void QDBusMetaObjectGenerator::parseProperties()
// Returns the sum of all parameters (including return type) for the given
// \a map of methods. This is needed for calculating the size of the methods'
// parameter type/name meta-data.
-qsizetype QDBusMetaObjectGenerator::aggregateParameterCount(const QMap<QByteArray, Method> &map)
+qsizetype QDBusMetaObjectGenerator::aggregateParameterCount(const MethodMap &map)
{
qsizetype sum = 0;
- QMap<QByteArray, Method>::const_iterator it;
- for (it = map.constBegin(); it != map.constEnd(); ++it) {
- const Method &m = it.value();
+ for (const Method &m : map)
sum += m.inputTypes.size() + qMax(qsizetype(1), m.outputTypes.size());
- }
return sum;
}
@@ -391,7 +382,7 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
- methods.size(); // ditto
QDBusMetaObjectPrivate *header = reinterpret_cast<QDBusMetaObjectPrivate *>(idata.data());
- static_assert(QMetaObjectPrivate::OutputRevision == 11, "QtDBus meta-object generator should generate the same version as moc");
+ static_assert(QMetaObjectPrivate::OutputRevision == 12, "QtDBus meta-object generator should generate the same version as moc");
header->revision = QMetaObjectPrivate::OutputRevision;
header->className = 0;
header->classInfoCount = 0;
@@ -415,10 +406,14 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
qsizetype data_size = idata.size() +
(header->methodCount * (QMetaObjectPrivate::IntsPerMethod+intsPerMethod)) + methodParametersDataSize +
(header->propertyCount * (QMetaObjectPrivate::IntsPerProperty+intsPerProperty));
- for (const Method &mm : std::as_const(signals_))
- data_size += 2 + mm.inputTypes.size() + mm.outputTypes.size();
- for (const Method &mm : std::as_const(methods))
- data_size += 2 + mm.inputTypes.size() + mm.outputTypes.size();
+
+ // Signals must be added before other methods, to match moc.
+ std::array<std::reference_wrapper<const MethodMap>, 2> methodMaps = { signals_, methods };
+
+ for (const auto &methodMap : methodMaps) {
+ for (const Method &mm : methodMap.get())
+ data_size += 2 + mm.inputTypes.size() + mm.outputTypes.size();
+ }
idata.resize(data_size + 1);
QMetaStringTable strings(className.toLatin1());
@@ -431,9 +426,9 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
qsizetype totalMetaTypeCount = properties.size();
++totalMetaTypeCount; // + 1 for metatype of dynamic metaobject
- for (const auto& methodContainer: {signals_, methods}) {
- for (const auto& method: methodContainer) {
- qsizetype argc = method.inputTypes.size() + qMax(qsizetype(0), method.outputTypes.size() - 1);
+ for (const auto &methodMap : methodMaps) {
+ for (const Method &mm : methodMap.get()) {
+ qsizetype argc = mm.inputTypes.size() + qMax(qsizetype(0), mm.outputTypes.size() - 1);
totalMetaTypeCount += argc + 1;
}
}
@@ -442,13 +437,9 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
// add each method:
qsizetype currentMethodMetaTypeOffset = properties.size() + 1;
- for (int x = 0; x < 2; ++x) {
- // Signals must be added before other methods, to match moc.
- QMap<QByteArray, Method> &map = (x == 0) ? signals_ : methods;
- for (QMap<QByteArray, Method>::ConstIterator it = map.constBegin();
- it != map.constEnd(); ++it) {
- const Method &mm = it.value();
+ for (const auto &methodMap : methodMaps) {
+ for (const Method &mm : methodMap.get()) {
qsizetype argc = mm.inputTypes.size() + qMax(qsizetype(0), mm.outputTypes.size() - 1);
idata[offset++] = strings.enter(mm.name);
@@ -514,12 +505,9 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj)
// add each property
signatureOffset = header->propertyDBusData;
- for (QMap<QByteArray, Property>::ConstIterator it = properties.constBegin();
- it != properties.constEnd(); ++it) {
- const Property &mp = it.value();
-
+ for (const auto &[name, mp] : std::as_const(properties).asKeyValueRange()) {
// form is name, typeinfo, flags
- idata[offset++] = strings.enter(it.key()); // name
+ idata[offset++] = strings.enter(name);
Q_ASSERT(mp.type != QMetaType::UnknownType);
idata[offset++] = mp.type;
idata[offset++] = mp.flags;
diff --git a/src/dbus/qdbusmetatype.cpp b/src/dbus/qdbusmetatype.cpp
index a70190995d..3ae7589480 100644
--- a/src/dbus/qdbusmetatype.cpp
+++ b/src/dbus/qdbusmetatype.cpp
@@ -53,14 +53,14 @@ void QDBusMetaTypeId::init()
// reentrancy is not a problem since everything else is locked on their own
// set the guard variable at the end
if (!initialized.loadRelaxed()) {
- // register our types with Qt Core (calling qMetaTypeId<T>() does this implicitly)
- (void)message();
- (void)argument();
- (void)variant();
- (void)objectpath();
- (void)signature();
- (void)error();
- (void)unixfd();
+ // register our types with Qt Core
+ message().registerType();
+ argument().registerType();
+ variant().registerType();
+ objectpath().registerType();
+ signature().registerType();
+ error().registerType();
+ unixfd().registerType();
#ifndef QDBUS_NO_SPECIALTYPES
// and register Qt Core's with us
@@ -78,7 +78,6 @@ void QDBusMetaTypeId::init()
qDBusRegisterMetaType<QVariantList>();
qDBusRegisterMetaType<QVariantMap>();
qDBusRegisterMetaType<QVariantHash>();
- qDBusRegisterMetaType<QDBusObjectPath>();
qDBusRegisterMetaType<QList<bool> >();
qDBusRegisterMetaType<QList<short> >();
@@ -88,6 +87,9 @@ void QDBusMetaTypeId::init()
qDBusRegisterMetaType<QList<qlonglong> >();
qDBusRegisterMetaType<QList<qulonglong> >();
qDBusRegisterMetaType<QList<double> >();
+
+ // plus lists of our own types
+ qDBusRegisterMetaType<QList<QDBusVariant> >();
qDBusRegisterMetaType<QList<QDBusObjectPath> >();
qDBusRegisterMetaType<QList<QDBusSignature> >();
qDBusRegisterMetaType<QList<QDBusUnixFileDescriptor> >();
@@ -97,9 +99,13 @@ void QDBusMetaTypeId::init()
}
}
-using QDBusCustomTypeHash = QHash<int, QDBusCustomTypeInfo>;
-Q_GLOBAL_STATIC(QDBusCustomTypeHash, customTypes)
-Q_GLOBAL_STATIC(QReadWriteLock, customTypesLock)
+struct QDBusCustomTypes
+{
+ QReadWriteLock lock;
+ QHash<int, QDBusCustomTypeInfo> hash;
+};
+
+Q_GLOBAL_STATIC(QDBusCustomTypes, customTypes)
/*!
\class QDBusMetaType
@@ -123,7 +129,7 @@ Q_GLOBAL_STATIC(QReadWriteLock, customTypesLock)
*/
/*!
- \fn int qDBusRegisterMetaType()
+ \fn template<typename T> QMetaType qDBusRegisterMetaType()
\relates QDBusArgument
\threadsafe
\since 4.2
@@ -180,12 +186,15 @@ void QDBusMetaType::registerMarshallOperators(QMetaType metaType, MarshallFuncti
DemarshallFunction df)
{
int id = metaType.id();
- auto *ct = customTypes();
- if (id < 0 || !mf || !df || !ct)
+ if (id < 0 || !mf || !df)
return; // error!
- QWriteLocker locker(customTypesLock());
- QDBusCustomTypeInfo &info = (*ct)[id];
+ auto *ct = customTypes();
+ if (!ct)
+ return;
+
+ QWriteLocker locker(&ct->lock);
+ QDBusCustomTypeInfo &info = ct->hash[id];
info.marshall = mf;
info.demarshall = df;
}
@@ -198,15 +207,19 @@ void QDBusMetaType::registerMarshallOperators(QMetaType metaType, MarshallFuncti
*/
bool QDBusMetaType::marshall(QDBusArgument &arg, QMetaType metaType, const void *data)
{
+ auto *ct = customTypes();
+ if (!ct)
+ return false;
+
int id = metaType.id();
QDBusMetaTypeId::init();
MarshallFunction mf;
{
- QReadLocker locker(customTypesLock());
- auto *ct = customTypes();
- auto it = ct->constFind(id);
- if (it == ct->cend())
+ QReadLocker locker(&ct->lock);
+
+ auto it = ct->hash.constFind(id);
+ if (it == ct->hash.cend())
return false; // non-existent
const QDBusCustomTypeInfo &info = *it;
@@ -229,15 +242,19 @@ bool QDBusMetaType::marshall(QDBusArgument &arg, QMetaType metaType, const void
*/
bool QDBusMetaType::demarshall(const QDBusArgument &arg, QMetaType metaType, void *data)
{
+ auto *ct = customTypes();
+ if (!ct)
+ return false;
+
int id = metaType.id();
QDBusMetaTypeId::init();
DemarshallFunction df;
{
- QReadLocker locker(customTypesLock());
- auto *ct = customTypes();
- auto it = ct->constFind(id);
- if (it == ct->cend())
+ QReadLocker locker(&ct->lock);
+
+ auto it = ct->hash.constFind(id);
+ if (it == ct->hash.cend())
return false; // non-existent
const QDBusCustomTypeInfo &info = *it;
@@ -355,8 +372,11 @@ QMetaType QDBusMetaType::signatureToMetaType(const char *signature)
void QDBusMetaType::registerCustomType(QMetaType type, const QByteArray &signature)
{
auto *ct = customTypes();
- QWriteLocker locker(customTypesLock());
- auto &info = (*ct)[type.id()];
+ if (!ct)
+ return;
+
+ QWriteLocker locker(&ct->lock);
+ auto &info = ct->hash[type.id()];
info.signature = signature;
// note how marshall/demarshall are not set, the type is never used at runtime
}
@@ -428,10 +448,13 @@ const char *QDBusMetaType::typeToSignature(QMetaType type)
// try the database
auto *ct = customTypes();
+ if (!ct)
+ return nullptr;
+
{
- QReadLocker locker(customTypesLock());
- auto it = ct->constFind(type.id());
- if (it == ct->end())
+ QReadLocker locker(&ct->lock);
+ auto it = ct->hash.constFind(type.id());
+ if (it == ct->hash.end())
return nullptr;
const QDBusCustomTypeInfo &info = *it;
@@ -448,11 +471,11 @@ const char *QDBusMetaType::typeToSignature(QMetaType type)
{
// createSignature will never return a null QByteArray
// if there was an error, it'll return ""
- QByteArray signature = QDBusArgumentPrivate::createSignature(type.id());
+ QByteArray signature = QDBusArgumentPrivate::createSignature(type);
// re-acquire lock
- QWriteLocker locker(customTypesLock());
- info = &(*ct)[type.id()];
+ QWriteLocker locker(&ct->lock);
+ info = &ct->hash[type.id()];
info->signature = signature;
}
return info->signature;
diff --git a/src/dbus/qdbusmetatype_p.h b/src/dbus/qdbusmetatype_p.h
index fdae803553..86a59f587d 100644
--- a/src/dbus/qdbusmetatype_p.h
+++ b/src/dbus/qdbusmetatype_p.h
@@ -28,18 +28,17 @@
QT_BEGIN_NAMESPACE
-struct QDBusMetaTypeId
-{
- static QMetaType message(); // QDBusMessage
- static QMetaType argument(); // QDBusArgument
- static QMetaType variant(); // QDBusVariant
- static QMetaType objectpath(); // QDBusObjectPath
- static QMetaType signature(); // QDBusSignature
- static QMetaType error(); // QDBusError
- static QMetaType unixfd(); // QDBusUnixFileDescriptor
-
- static void init();
-};
+namespace QDBusMetaTypeId {
+QMetaType message(); // QDBusMessage
+QMetaType argument(); // QDBusArgument
+QMetaType variant(); // QDBusVariant
+QMetaType objectpath(); // QDBusObjectPath
+QMetaType signature(); // QDBusSignature
+QMetaType error(); // QDBusError
+QMetaType unixfd(); // QDBusUnixFileDescriptor
+
+Q_DBUS_EXPORT void init();
+}; // namespace QDBusMetaTypeId
inline QMetaType QDBusMetaTypeId::message()
{ return QMetaType::fromType<QDBusMessage>(); }
diff --git a/src/dbus/qdbusmisc.cpp b/src/dbus/qdbusmisc.cpp
index b1da47111e..635258c86d 100644
--- a/src/dbus/qdbusmisc.cpp
+++ b/src/dbus/qdbusmisc.cpp
@@ -8,6 +8,7 @@
#include <QtCore/qlist.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qvariant.h>
+#include <private/qurl_p.h>
#include "qdbusutil_p.h"
#include "qdbusconnection_p.h"
@@ -58,23 +59,42 @@ QString qDBusInterfaceFromMetaObject(const QMetaObject *mo)
} else if (!QCoreApplication::instance()||
QCoreApplication::instance()->applicationName().isEmpty()) {
interface.prepend("local."_L1);
- } else {
- interface.prepend(u'.').prepend(QCoreApplication::instance()->applicationName());
+ } else {
+ QString domainName = QCoreApplication::instance()->applicationName();
const QString organizationDomain = QCoreApplication::instance()->organizationDomain();
- const auto domainName = QStringView{organizationDomain}.split(u'.', Qt::SkipEmptyParts);
- if (domainName.isEmpty()) {
- interface.prepend("local."_L1);
- } else {
- QString composedDomain;
- // + 1 for additional dot, e.g. organizationDomain equals "example.com",
- // then composedDomain will be equal "com.example."
- composedDomain.reserve(organizationDomain.size() + 1);
- for (auto it = domainName.rbegin(), end = domainName.rend(); it != end; ++it)
- composedDomain += *it + u'.';
-
- interface.prepend(composedDomain);
+ if (organizationDomain.isEmpty())
+ domainName.append(".local"_L1);
+ else
+ domainName.append(u'.').append(organizationDomain);
+
+ // Domain names used to produce interface names should be IDN-encoded.
+ QString encodedDomainName = qt_ACE_do(domainName, ToAceOnly, ForbidLeadingDot);
+ if (encodedDomainName.isEmpty()) {
+ interface.prepend("local."_L1);
+ return interface;
}
- }
+
+ // Hyphens are not allowed in interface names and should be replaced
+ // by underscores.
+ encodedDomainName.replace(u'-', u'_');
+
+ auto nameParts = QStringView{ encodedDomainName }.split(u'.', Qt::SkipEmptyParts);
+
+ QString composedDomain;
+ // + 1 for additional dot, e.g. domainName equals "App.example.com",
+ // then composedDomain will be equal "com.example.App."
+ composedDomain.reserve(encodedDomainName.size() + nameParts.size() + 1);
+ for (auto it = nameParts.rbegin(), end = nameParts.rend(); it != end; ++it) {
+ // An interface name cannot start with a digit, and cannot
+ // contain digits immediately following a period. Prefix such
+ // digits with underscores.
+ if (it->first().isDigit())
+ composedDomain += u'_';
+ composedDomain += *it + u'.';
+ }
+
+ interface.prepend(composedDomain);
+ }
}
return interface;
@@ -103,7 +123,19 @@ bool qDBusInterfaceInObject(QObject *obj, const QString &interface_name)
// sig must be the normalised signature for the method
int qDBusParametersForMethod(const QMetaMethod &mm, QList<QMetaType> &metaTypes, QString &errorMsg)
{
- return qDBusParametersForMethod(mm.parameterTypes(), metaTypes, errorMsg);
+ QList<QByteArray> parameterTypes;
+ parameterTypes.reserve(mm.parameterCount());
+
+ // Not using QMetaMethod::parameterTypes() since we call QMetaType::fromName below
+ // where we need any typedefs resolved already.
+ for (int i = 0; i < mm.parameterCount(); ++i) {
+ QByteArray typeName = mm.parameterMetaType(i).name();
+ if (typeName.isEmpty())
+ typeName = mm.parameterTypeName(i);
+ parameterTypes.append(typeName);
+ }
+
+ return qDBusParametersForMethod(parameterTypes, metaTypes, errorMsg);
}
#endif // QT_BOOTSTRAPPED
@@ -117,10 +149,7 @@ int qDBusParametersForMethod(const QList<QByteArray> &parameterTypes, QList<QMet
metaTypes.append(QMetaType()); // return type
int inputCount = 0;
bool seenMessage = false;
- QList<QByteArray>::ConstIterator it = parameterTypes.constBegin();
- QList<QByteArray>::ConstIterator end = parameterTypes.constEnd();
- for ( ; it != end; ++it) {
- QByteArray type = *it;
+ for (QByteArray type : parameterTypes) {
if (type.endsWith('*')) {
errorMsg = "Pointers are not supported: "_L1 + QLatin1StringView(type);
return -1;
diff --git a/src/dbus/qdbuspendingcall.cpp b/src/dbus/qdbuspendingcall.cpp
index ff5dfc8967..f9d414d1bd 100644
--- a/src/dbus/qdbuspendingcall.cpp
+++ b/src/dbus/qdbuspendingcall.cpp
@@ -94,7 +94,8 @@ using namespace Qt::StringLiterals;
void QDBusPendingCallWatcherHelper::add(QDBusPendingCallWatcher *watcher)
{
- connect(this, SIGNAL(finished()), watcher, SLOT(_q_finished()), Qt::QueuedConnection);
+ connect(this, &QDBusPendingCallWatcherHelper::finished, watcher,
+ [watcher] { Q_EMIT watcher->finished(watcher); }, Qt::QueuedConnection);
}
QDBusPendingCallPrivate::~QDBusPendingCallPrivate()
@@ -205,6 +206,26 @@ void QDBusPendingCallPrivate::waitForFinished()
waitForFinishedCondition.wait(&mutex);
}
+void QDBusPendingCallPrivate::waitForFinishedWithGui()
+{
+ QEventLoop loop;
+
+ {
+ const auto locker = qt_scoped_lock(mutex);
+ if (replyMessage.type() != QDBusMessage::InvalidMessage)
+ return; // already finished
+
+ Q_ASSERT(!watcherHelper);
+ watcherHelper = new QDBusPendingCallWatcherHelper;
+ loop.connect(watcherHelper, &QDBusPendingCallWatcherHelper::reply, &loop,
+ &QEventLoop::quit);
+ loop.connect(watcherHelper, &QDBusPendingCallWatcherHelper::error, &loop,
+ &QEventLoop::quit);
+ }
+
+ loop.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents);
+}
+
/*!
Creates a copy of the \a other pending asynchronous call. Note
that both objects will refer to the same pending call.
@@ -223,7 +244,6 @@ QDBusPendingCall::QDBusPendingCall(QDBusPendingCallPrivate *dd)
if (dd) {
bool r = dd->ref.deref();
Q_ASSERT(r);
- Q_UNUSED(r);
}
}
@@ -445,28 +465,13 @@ QDBusPendingCall QDBusPendingCall::fromCompletedCall(const QDBusMessage &msg)
return QDBusPendingCall(d);
}
-
-class QDBusPendingCallWatcherPrivate: public QObjectPrivate
-{
-public:
- void _q_finished();
-
- Q_DECLARE_PUBLIC(QDBusPendingCallWatcher)
-};
-
-inline void QDBusPendingCallWatcherPrivate::_q_finished()
-{
- Q_Q(QDBusPendingCallWatcher);
- emit q->finished(q);
-}
-
/*!
Creates a QDBusPendingCallWatcher object to watch for replies on the
asynchronous pending call \a call and sets this object's parent
to \a parent.
*/
QDBusPendingCallWatcher::QDBusPendingCallWatcher(const QDBusPendingCall &call, QObject *parent)
- : QObject(*new QDBusPendingCallWatcherPrivate, parent), QDBusPendingCall(call)
+ : QObject(parent), QDBusPendingCall(call)
{
if (d) { // QDBusPendingCall::d
const auto locker = qt_scoped_lock(d->mutex);
@@ -474,7 +479,9 @@ QDBusPendingCallWatcher::QDBusPendingCallWatcher(const QDBusPendingCall &call, Q
d->watcherHelper = new QDBusPendingCallWatcherHelper;
if (d->replyMessage.type() != QDBusMessage::InvalidMessage) {
// cause a signal emission anyways
- QMetaObject::invokeMethod(d->watcherHelper, "finished", Qt::QueuedConnection);
+ QMetaObject::invokeMethod(d->watcherHelper,
+ &QDBusPendingCallWatcherHelper::finished,
+ Qt::QueuedConnection);
}
}
d->watcherHelper->add(this);
diff --git a/src/dbus/qdbuspendingcall.h b/src/dbus/qdbuspendingcall.h
index eae68144fe..c276376223 100644
--- a/src/dbus/qdbuspendingcall.h
+++ b/src/dbus/qdbuspendingcall.h
@@ -57,7 +57,6 @@ private:
Q_DECLARE_SHARED(QDBusPendingCall)
-class QDBusPendingCallWatcherPrivate;
class Q_DBUS_EXPORT QDBusPendingCallWatcher: public QObject, public QDBusPendingCall
{
Q_OBJECT
@@ -73,10 +72,6 @@ public:
Q_SIGNALS:
void finished(QDBusPendingCallWatcher *self = nullptr);
-
-private:
- Q_DECLARE_PRIVATE(QDBusPendingCallWatcher)
- Q_PRIVATE_SLOT(d_func(), void _q_finished())
};
QT_END_NAMESPACE
diff --git a/src/dbus/qdbuspendingcall_p.h b/src/dbus/qdbuspendingcall_p.h
index 2ba802ad85..2795cc3ecf 100644
--- a/src/dbus/qdbuspendingcall_p.h
+++ b/src/dbus/qdbuspendingcall_p.h
@@ -68,10 +68,9 @@ public:
~QDBusPendingCallPrivate();
bool setReplyCallback(QObject *target, const char *member);
void waitForFinished();
+ void waitForFinishedWithGui();
void setMetaTypes(int count, const QMetaType *types);
void checkReceivedSignature();
-
- static QDBusPendingCall fromMessage(const QDBusMessage &msg);
};
class QDBusPendingCallWatcherHelper: public QObject
diff --git a/src/dbus/qdbusreply.cpp b/src/dbus/qdbusreply.cpp
index 3b9e24eaf8..5b26250b10 100644
--- a/src/dbus/qdbusreply.cpp
+++ b/src/dbus/qdbusreply.cpp
@@ -141,7 +141,7 @@ using namespace Qt::StringLiterals;
*/
/*!
- \fn template <typename T> QDBusReply<T>::value() const
+ \fn template <typename T> Type QDBusReply<T>::value() const
Returns the remote function's calls return value. If the remote call returned with an error,
the return value of this function is undefined and may be undistinguishable from a valid return
value.
diff --git a/src/dbus/qdbusserver.cpp b/src/dbus/qdbusserver.cpp
index 21d422ac9e..e9131a14c4 100644
--- a/src/dbus/qdbusserver.cpp
+++ b/src/dbus/qdbusserver.cpp
@@ -38,9 +38,8 @@ QDBusServer::QDBusServer(const QString &address, QObject *parent)
if (!instance)
return;
- emit instance->serverRequested(address, this);
- QObject::connect(d, SIGNAL(newServerConnection(QDBusConnectionPrivate*)),
- this, SLOT(_q_newConnection(QDBusConnectionPrivate*)), Qt::QueuedConnection);
+ instance->createServer(address, this);
+ Q_ASSERT(d != nullptr);
}
/*!
@@ -49,25 +48,15 @@ QDBusServer::QDBusServer(const QString &address, QObject *parent)
localhost (elsewhere).
*/
QDBusServer::QDBusServer(QObject *parent)
- : QObject(parent), d(nullptr)
-{
+ : QDBusServer(
#ifdef Q_OS_UNIX
- // Use Unix sockets on Unix systems only
- const QString address = QStringLiteral("unix:tmpdir=/tmp");
+ // Use Unix sockets on Unix systems only
+ QStringLiteral("unix:tmpdir=/tmp"),
#else
- const QString address = QStringLiteral("tcp:");
+ QStringLiteral("tcp:"),
#endif
-
- if (!qdbus_loadLibDBus())
- return;
-
- QDBusConnectionManager *instance = QDBusConnectionManager::instance();
- if (!instance)
- return;
-
- emit instance->serverRequested(address, this);
- QObject::connect(d, SIGNAL(newServerConnection(QDBusConnectionPrivate*)),
- this, SLOT(_q_newConnection(QDBusConnectionPrivate*)), Qt::QueuedConnection);
+ parent)
+{
}
/*!
@@ -75,17 +64,17 @@ QDBusServer::QDBusServer(QObject *parent)
*/
QDBusServer::~QDBusServer()
{
- QMutex *managerMutex = nullptr;
- if (QDBusConnectionManager::instance())
- managerMutex = &QDBusConnectionManager::instance()->mutex;
- QMutexLocker locker(managerMutex);
+ if (!d)
+ return;
+
+ auto manager = QDBusConnectionManager::instance();
+ if (!manager)
+ return;
+
QWriteLocker writeLocker(&d->lock);
- if (QDBusConnectionManager::instance()) {
- for (const QString &name : std::as_const(d->serverConnectionNames))
- QDBusConnectionManager::instance()->removeConnection(name);
- d->serverConnectionNames.clear();
- locker.unlock();
- }
+ manager->removeConnections(d->serverConnectionNames);
+ d->serverConnectionNames.clear();
+
d->serverObject = nullptr;
d->ref.storeRelaxed(0);
d->deleteLater();
@@ -138,6 +127,9 @@ QString QDBusServer::address() const
*/
void QDBusServer::setAnonymousAuthenticationAllowed(bool value)
{
+ if (!d)
+ return;
+
d->anonymousAuthenticationAllowed = value;
}
@@ -150,6 +142,9 @@ void QDBusServer::setAnonymousAuthenticationAllowed(bool value)
*/
bool QDBusServer::isAnonymousAuthenticationAllowed() const
{
+ if (!d)
+ return false;
+
return d->anonymousAuthenticationAllowed;
}
diff --git a/src/dbus/qdbusserver.h b/src/dbus/qdbusserver.h
index b482314319..34985cc055 100644
--- a/src/dbus/qdbusserver.h
+++ b/src/dbus/qdbusserver.h
@@ -37,7 +37,6 @@ Q_SIGNALS:
private:
Q_DISABLE_COPY(QDBusServer)
- Q_PRIVATE_SLOT(d, void _q_newConnection(QDBusConnectionPrivate*))
QDBusConnectionPrivate *d;
friend class QDBusConnectionPrivate;
};
diff --git a/src/dbus/qdbusservicewatcher.cpp b/src/dbus/qdbusservicewatcher.cpp
index 4d180e2124..bf94f54f56 100644
--- a/src/dbus/qdbusservicewatcher.cpp
+++ b/src/dbus/qdbusservicewatcher.cpp
@@ -40,10 +40,11 @@ public:
&QDBusServiceWatcherPrivate::setWatchModeForwardToQ)
void _q_serviceOwnerChanged(const QString &, const QString &, const QString &);
- void setConnection(const QStringList &services, const QDBusConnection &c, QDBusServiceWatcher::WatchMode watchMode);
+ void setConnection(const QStringList &newServices, const QDBusConnection &newConnection,
+ QDBusServiceWatcher::WatchMode newMode);
- void addService(const QString &service);
- void removeService(const QString &service);
+ void addService(const QString &service, QDBusServiceWatcher::WatchMode mode);
+ void removeService(const QString &service, QDBusServiceWatcher::WatchMode mode);
};
void QDBusServiceWatcherPrivate::_q_serviceOwnerChanged(const QString &service, const QString &oldOwner, const QString &newOwner)
@@ -56,39 +57,43 @@ void QDBusServiceWatcherPrivate::_q_serviceOwnerChanged(const QString &service,
emit q->serviceUnregistered(service);
}
-void QDBusServiceWatcherPrivate::setConnection(const QStringList &services,
- const QDBusConnection &c,
- QDBusServiceWatcher::WatchMode wm)
+void QDBusServiceWatcherPrivate::setConnection(const QStringList &newServices,
+ const QDBusConnection &newConnection,
+ QDBusServiceWatcher::WatchMode newMode)
{
+ const QStringList oldServices = watchedServicesData.valueBypassingBindings();
+ const QDBusServiceWatcher::WatchMode oldMode = watchMode.valueBypassingBindings();
if (connection.isConnected()) {
// remove older rules
- for (const QString &s : std::as_const(watchedServicesData.value()))
- removeService(s);
+ for (const QString &s : oldServices)
+ removeService(s, oldMode);
}
- connection = c;
- watchMode.setValueBypassingBindings(wm); // caller has to call notify()
- watchedServicesData.setValueBypassingBindings(services); // caller has to call notify()
+ connection = newConnection;
+ watchMode.setValueBypassingBindings(newMode); // caller has to call notify()
+ watchedServicesData.setValueBypassingBindings(newServices); // caller has to call notify()
if (connection.isConnected()) {
// add new rules
- for (const QString &s : std::as_const(watchedServicesData.value()))
- addService(s);
+ for (const QString &s : newServices)
+ addService(s, newMode);
}
}
-void QDBusServiceWatcherPrivate::addService(const QString &service)
+void QDBusServiceWatcherPrivate::addService(const QString &service,
+ QDBusServiceWatcher::WatchMode mode)
{
QDBusConnectionPrivate *d = QDBusConnectionPrivate::d(connection);
if (d && d->shouldWatchService(service))
- d->watchService(service, watchMode, q_func(), SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
+ d->watchService(service, mode, q_func(), SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
}
-void QDBusServiceWatcherPrivate::removeService(const QString &service)
+void QDBusServiceWatcherPrivate::removeService(const QString &service,
+ QDBusServiceWatcher::WatchMode mode)
{
QDBusConnectionPrivate *d = QDBusConnectionPrivate::d(connection);
if (d && d->shouldWatchService(service))
- d->unwatchService(service, watchMode, q_func(), SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
+ d->unwatchService(service, mode, q_func(), SLOT(_q_serviceOwnerChanged(QString,QString,QString)));
}
/*!
@@ -260,8 +265,9 @@ void QDBusServiceWatcher::setWatchedServices(const QStringList &services)
{
Q_D(QDBusServiceWatcher);
d->watchedServicesData.removeBindingUnlessInWrapper();
- if (services == d->watchedServicesData)
+ if (services == d->watchedServicesData.valueBypassingBindings())
return;
+ // trigger watchMode re-evaluation, but only once for the setter
d->setConnection(services, d->connection, d->watchMode);
d->watchedServicesData.notify();
}
@@ -283,13 +289,14 @@ void QDBusServiceWatcher::addWatchedService(const QString &newService)
{
Q_D(QDBusServiceWatcher);
d->watchedServicesData.removeBindingUnlessInWrapper();
- if (d->watchedServicesData.value().contains(newService))
+ auto services = d->watchedServicesData.valueBypassingBindings();
+ if (services.contains(newService))
return;
- d->addService(newService);
+ // re-evaluate watch mode
+ d->addService(newService, d->watchMode);
- auto templist = d->watchedServicesData.valueBypassingBindings();
- templist << newService;
- d->watchedServicesData.setValueBypassingBindings(templist);
+ services << newService;
+ d->watchedServicesData.setValueBypassingBindings(services);
d->watchedServicesData.notify();
}
@@ -308,17 +315,16 @@ bool QDBusServiceWatcher::removeWatchedService(const QString &service)
{
Q_D(QDBusServiceWatcher);
d->watchedServicesData.removeBindingUnlessInWrapper();
- d->removeService(service);
- auto tempList = d->watchedServicesData.value();
- bool result = tempList.removeOne(service);
- if (result) {
- d->watchedServicesData.setValueBypassingBindings(tempList);
- d->watchedServicesData.notify();
- return true;
- } else {
- // nothing changed
- return false;
- }
+ auto tempList = d->watchedServicesData.valueBypassingBindings();
+ const bool result = tempList.removeOne(service);
+ if (!result)
+ return false; // nothing changed
+
+ // re-evaluate watch mode
+ d->removeService(service, d->watchMode);
+ d->watchedServicesData.setValueBypassingBindings(tempList);
+ d->watchedServicesData.notify();
+ return true;
}
QDBusServiceWatcher::WatchMode QDBusServiceWatcher::watchMode() const
@@ -335,8 +341,9 @@ void QDBusServiceWatcher::setWatchMode(WatchMode mode)
{
Q_D(QDBusServiceWatcher);
d->watchMode.removeBindingUnlessInWrapper();
- if (mode == d->watchMode.value())
+ if (mode == d->watchMode.valueBypassingBindings())
return;
+ // trigger watchedServicesData re-evaluation, but only once for the setter
d->setConnection(d->watchedServicesData, d->connection, mode);
d->watchMode.notify();
}
diff --git a/src/dbus/qdbusthreaddebug_p.h b/src/dbus/qdbusthreaddebug_p.h
index 73be3d7517..a1d3a420ec 100644
--- a/src/dbus/qdbusthreaddebug_p.h
+++ b/src/dbus/qdbusthreaddebug_p.h
@@ -93,7 +93,7 @@ struct QDBusReadLocker: QDBusLockerBase
{
QDBusConnectionPrivate *self;
ThreadAction action;
- inline QDBusReadLocker(ThreadAction a, QDBusConnectionPrivate *s)
+ Q_NODISCARD_CTOR QDBusReadLocker(ThreadAction a, QDBusConnectionPrivate *s)
: self(s), action(a)
{
reportThreadAction(action, BeforeLock, self);
@@ -113,7 +113,7 @@ struct QDBusWriteLocker: QDBusLockerBase
{
QDBusConnectionPrivate *self;
ThreadAction action;
- inline QDBusWriteLocker(ThreadAction a, QDBusConnectionPrivate *s)
+ Q_NODISCARD_CTOR QDBusWriteLocker(ThreadAction a, QDBusConnectionPrivate *s)
: self(s), action(a)
{
reportThreadAction(action, BeforeLock, self);
diff --git a/src/dbus/qdbusutil.cpp b/src/dbus/qdbusutil.cpp
index 00f05b3dd3..827418c487 100644
--- a/src/dbus/qdbusutil.cpp
+++ b/src/dbus/qdbusutil.cpp
@@ -206,6 +206,21 @@ static const char oneLetterTypes[] = "vsogybnqiuxtdh";
static const char basicTypes[] = "sogybnqiuxtdh";
static const char fixedTypes[] = "ybnqiuxtdh";
+/*
+ D-Bus signature grammar (in ABNF), as of 0.42 (2023-08-21):
+ https://dbus.freedesktop.org/doc/dbus-specification.html#type-system
+
+ <signature> = *<single-complete-type>
+ <single-complete-type> = <basic-type> / <variant> / <struct> / <array>
+ <fixed-type> = "y" / "b" / "n" / "q" / "i" / "u" / "x" / "t" / "d" / "h"
+ <variable-length-type> = "s" / "o" / "g"
+ <basic-type> = <variable-length-type> / <fixed-type>
+ <variant> = "v"
+ <struct> = "(" 1*<single-complete-type> ")"
+ <array> = "a" ( <single-complete-type> / <dict-entry> )
+ <dict-entry> = "{" <basic-type> <single-complete-type> "}"
+*/
+
static bool isBasicType(int c)
{
return c != DBUS_TYPE_INVALID && strchr(basicTypes, c) != nullptr;
@@ -310,13 +325,6 @@ namespace QDBusUtil
}
/*!
- \internal
- \fn bool isValidPartOfObjectPath(const QString &part)
-
- \overload
- */
-
- /*!
\fn bool isValidInterfaceName(const QString &ifaceName)
Returns \c true if this is \a ifaceName is a valid interface name.
@@ -376,12 +384,6 @@ namespace QDBusUtil
}
/*!
- \fn bool isValidUniqueConnectionName(const QString &connName)
-
- \overload
- */
-
- /*!
\fn bool isValidBusName(const QString &busName)
Returns \c true if \a busName is a valid bus name.
@@ -405,9 +407,6 @@ namespace QDBusUtil
return isValidUniqueConnectionName(busName);
const auto parts = QStringView{busName}.split(u'.');
- if (parts.size() < 1)
- return false;
-
for (QStringView part : parts) {
if (part.isEmpty())
return false;
@@ -444,12 +443,6 @@ namespace QDBusUtil
}
/*!
- \fn bool isValidMemberName(const QString &memberName)
-
- \overload
- */
-
- /*!
\fn bool isValidErrorName(const QString &errorName)
Returns \c true if \a errorName is a valid error name. Valid error names are valid interface
names and vice-versa, so this function is actually an alias for isValidInterfaceName.
@@ -467,9 +460,8 @@ namespace QDBusUtil
\list
\li start with the slash character ("/")
\li do not end in a slash, unless the path is just the initial slash
- \li do not contain any two slashes in sequence
- \li contain slash-separated parts, each of which is composed of ASCII letters, digits and
- underscores ("_")
+ \li contain slash-separated parts, each of which is not empty, and composed
+ only of ASCII letters, digits and underscores ("_").
\endlist
*/
bool isValidObjectPath(const QString &path)
diff --git a/src/dbus/qdbusxmlgenerator.cpp b/src/dbus/qdbusxmlgenerator.cpp
index 662a96e53b..412ac18095 100644
--- a/src/dbus/qdbusxmlgenerator.cpp
+++ b/src/dbus/qdbusxmlgenerator.cpp
@@ -228,56 +228,6 @@ QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo,
return " <interface name=\"%1\">\n%2 </interface>\n"_L1
.arg(interface, xml);
}
-#if 0
-QString qDBusGenerateMetaObjectXml(QString interface, const QMetaObject *mo, const QMetaObject *base,
- int flags)
-{
- if (interface.isEmpty()) {
- // generate the interface name from the meta object
- int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTERFACE);
- if (idx >= mo->classInfoOffset()) {
- interface = QLatin1StringView(mo->classInfo(idx).value());
- } else {
- interface = QLatin1StringView(mo->className());
- interface.replace("::"_L1, "."_L1);
-
- if (interface.startsWith("QDBus"_L1)) {
- interface.prepend("org.qtproject.QtDBus."_L1);
- } else if (interface.startsWith(u'Q') &&
- interface.length() >= 2 && interface.at(1).isUpper()) {
- // assume it's Qt
- interface.prepend("org.qtproject.Qt."_L1);
- } else if (!QCoreApplication::instance()||
- QCoreApplication::instance()->applicationName().isEmpty()) {
- interface.prepend("local."_L1);
- } else {
- interface.prepend(u'.').prepend(QCoreApplication::instance()->applicationName());
- QStringList domainName =
- QCoreApplication::instance()->organizationDomain().split(u'.',
- Qt::SkipEmptyParts);
- if (domainName.isEmpty())
- interface.prepend("local."_L1);
- else
- for (int i = 0; i < domainName.count(); ++i)
- interface.prepend(u'.').prepend(domainName.at(i));
- }
- }
- }
-
- QString xml;
- int idx = mo->indexOfClassInfo(QCLASSINFO_DBUS_INTROSPECTION);
- if (idx >= mo->classInfoOffset())
- return QString::fromUtf8(mo->classInfo(idx).value());
- else
- xml = generateInterfaceXml(mo, flags, base->methodCount(), base->propertyCount());
-
- if (xml.isEmpty())
- return QString(); // don't add an empty interface
- return QString::fromLatin1(" <interface name=\"%1\">\n%2 </interface>\n")
- .arg(interface, xml);
-}
-
-#endif
QT_END_NAMESPACE
diff --git a/src/dbus/qdbusxmlparser.cpp b/src/dbus/qdbusxmlparser.cpp
index 509ca6e77c..c2e8df8be7 100644
--- a/src/dbus/qdbusxmlparser.cpp
+++ b/src/dbus/qdbusxmlparser.cpp
@@ -7,7 +7,6 @@
#include <QtCore/qmap.h>
#include <QtCore/qvariant.h>
#include <QtCore/qtextstream.h>
-#include <QtCore/qxmlstream.h>
#include <QtCore/qdebug.h>
#ifndef QT_NO_DBUS
@@ -18,67 +17,89 @@ using namespace Qt::StringLiterals;
Q_LOGGING_CATEGORY(dbusParser, "dbus.parser", QtWarningMsg)
-#define qDBusParserError(...) qCDebug(dbusParser, ##__VA_ARGS__)
-
-static bool parseArg(const QXmlStreamAttributes &attributes, QDBusIntrospection::Argument &argData,
- QDBusIntrospection::Interface *ifaceData)
+#define qDBusParserWarning(format, ...) \
+ do { \
+ if (m_reporter) \
+ m_reporter->warning(m_currentLocation, format "\n", ##__VA_ARGS__); \
+ else \
+ qCDebug(dbusParser, "Warning: " format, ##__VA_ARGS__); \
+ } while (0)
+
+#define qDBusParserError(format, ...) \
+ do { \
+ if (m_reporter) \
+ m_reporter->error(m_currentLocation, format "\n", ##__VA_ARGS__); \
+ else \
+ qCDebug(dbusParser, "Error: " format, ##__VA_ARGS__); \
+ } while (0)
+
+bool QDBusXmlParser::parseArg(const QXmlStreamAttributes &attributes,
+ QDBusIntrospection::Argument &argData)
{
+ Q_ASSERT(m_currentInterface);
+
const QString argType = attributes.value("type"_L1).toString();
bool ok = QDBusUtil::isValidSingleSignature(argType);
if (!ok) {
- qDBusParserError("Invalid D-BUS type signature '%s' found while parsing introspection",
- qPrintable(argType));
+ qDBusParserError("Invalid D-Bus type signature '%s' found while parsing introspection",
+ qPrintable(argType));
}
argData.name = attributes.value("name"_L1).toString();
argData.type = argType;
- ifaceData->introspection += " <arg"_L1;
+ m_currentInterface->introspection += " <arg"_L1;
if (attributes.hasAttribute("direction"_L1)) {
const QString direction = attributes.value("direction"_L1).toString();
- ifaceData->introspection += " direction=\""_L1 + direction + u'"';
+ m_currentInterface->introspection += " direction=\""_L1 + direction + u'"';
}
- ifaceData->introspection += " type=\""_L1 + argData.type + u'"';
+ m_currentInterface->introspection += " type=\""_L1 + argData.type + u'"';
if (!argData.name.isEmpty())
- ifaceData->introspection += " name=\""_L1 + argData.name + u'"';
- ifaceData->introspection += "/>\n"_L1;
+ m_currentInterface->introspection += " name=\""_L1 + argData.name + u'"';
+ m_currentInterface->introspection += "/>\n"_L1;
return ok;
}
-static bool parseAnnotation(const QXmlStreamReader &xml, QDBusIntrospection::Annotations &annotations,
- QDBusIntrospection::Interface *ifaceData, bool interfaceAnnotation = false)
+bool QDBusXmlParser::parseAnnotation(QDBusIntrospection::Annotations &annotations,
+ bool interfaceAnnotation)
{
- Q_ASSERT(xml.isStartElement() && xml.name() == "annotation"_L1);
+ Q_ASSERT(m_currentInterface);
+ Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "annotation"_L1);
- const QXmlStreamAttributes attributes = xml.attributes();
- const QString name = attributes.value("name"_L1).toString();
+ QDBusIntrospection::Annotation annotation;
+ annotation.location = m_currentLocation;
- if (!QDBusUtil::isValidInterfaceName(name)) {
- qDBusParserError("Invalid D-BUS annotation '%s' found while parsing introspection",
- qPrintable(name));
+ const QXmlStreamAttributes attributes = m_xml.attributes();
+ annotation.name = attributes.value("name"_L1).toString();
+
+ if (!QDBusUtil::isValidInterfaceName(annotation.name)) {
+ qDBusParserError("Invalid D-Bus annotation '%s' found while parsing introspection",
+ qPrintable(annotation.name));
return false;
}
- const QString value = attributes.value("value"_L1).toString();
- annotations.insert(name, value);
+ annotation.value = attributes.value("value"_L1).toString();
+ annotations.insert(annotation.name, annotation);
if (!interfaceAnnotation)
- ifaceData->introspection += " "_L1;
- ifaceData->introspection += " <annotation value=\""_L1 + value.toHtmlEscaped() + "\" name=\""_L1 + name + "\"/>\n"_L1;
+ m_currentInterface->introspection += " "_L1;
+ m_currentInterface->introspection += " <annotation value=\""_L1
+ + annotation.value.toHtmlEscaped() + "\" name=\""_L1 + annotation.name + "\"/>\n"_L1;
return true;
}
-static bool parseProperty(QXmlStreamReader &xml, QDBusIntrospection::Property &propertyData,
- QDBusIntrospection::Interface *ifaceData)
+bool QDBusXmlParser::parseProperty(QDBusIntrospection::Property &propertyData)
{
- Q_ASSERT(xml.isStartElement() && xml.name() == "property"_L1);
+ Q_ASSERT(m_currentInterface);
+ Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "property"_L1);
- QXmlStreamAttributes attributes = xml.attributes();
+ QXmlStreamAttributes attributes = m_xml.attributes();
const QString propertyName = attributes.value("name"_L1).toString();
if (!QDBusUtil::isValidMemberName(propertyName)) {
- qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection",
- qPrintable(propertyName), qPrintable(ifaceData->name));
- xml.skipCurrentElement();
+ qDBusParserWarning("Invalid D-Bus member name '%s' found in interface '%s' while parsing "
+ "introspection",
+ qPrintable(propertyName), qPrintable(m_currentInterface->name));
+ m_xml.skipCurrentElement();
return false;
}
@@ -88,9 +109,10 @@ static bool parseProperty(QXmlStreamReader &xml, QDBusIntrospection::Property &p
if (!QDBusUtil::isValidSingleSignature(propertyData.type)) {
// cannot be!
- qDBusParserError("Invalid D-BUS type signature '%s' found in property '%s.%s' while parsing introspection",
- qPrintable(propertyData.type), qPrintable(ifaceData->name),
- qPrintable(propertyName));
+ qDBusParserError("Invalid D-Bus type signature '%s' found in property '%s.%s' while "
+ "parsing introspection",
+ qPrintable(propertyData.type), qPrintable(m_currentInterface->name),
+ qPrintable(propertyName));
}
const QString access = attributes.value("access"_L1).toString();
@@ -101,85 +123,90 @@ static bool parseProperty(QXmlStreamReader &xml, QDBusIntrospection::Property &p
else if (access == "readwrite"_L1)
propertyData.access = QDBusIntrospection::Property::ReadWrite;
else {
- qDBusParserError("Invalid D-BUS property access '%s' found in property '%s.%s' while parsing introspection",
- qPrintable(access), qPrintable(ifaceData->name),
- qPrintable(propertyName));
+ qDBusParserError("Invalid D-Bus property access '%s' found in property '%s.%s' while "
+ "parsing introspection",
+ qPrintable(access), qPrintable(m_currentInterface->name),
+ qPrintable(propertyName));
return false; // invalid one!
}
- ifaceData->introspection += " <property access=\""_L1 + access + "\" type=\""_L1 + propertyData.type + "\" name=\""_L1 + propertyName + u'"';
+ m_currentInterface->introspection += " <property access=\""_L1 + access + "\" type=\""_L1 + propertyData.type + "\" name=\""_L1 + propertyName + u'"';
- if (!xml.readNextStartElement()) {
- ifaceData->introspection += "/>\n"_L1;
+ if (!readNextStartElement()) {
+ m_currentInterface->introspection += "/>\n"_L1;
} else {
- ifaceData->introspection += ">\n"_L1;
+ m_currentInterface->introspection += ">\n"_L1;
do {
- if (xml.name() == "annotation"_L1) {
- parseAnnotation(xml, propertyData.annotations, ifaceData);
- } else if (xml.prefix().isEmpty()) {
- qDBusParserError() << "Unknown element" << xml.name() << "while checking for annotations";
+ if (m_xml.name() == "annotation"_L1) {
+ parseAnnotation(propertyData.annotations);
+ } else if (m_xml.prefix().isEmpty()) {
+ qDBusParserWarning("Unknown element '%s' while checking for annotations",
+ qPrintable(m_xml.name().toString()));
}
- xml.skipCurrentElement();
- } while (xml.readNextStartElement());
+ m_xml.skipCurrentElement();
+ } while (readNextStartElement());
- ifaceData->introspection += " </property>\n"_L1;
+ m_currentInterface->introspection += " </property>\n"_L1;
}
- if (!xml.isEndElement() || xml.name() != "property"_L1) {
- qDBusParserError() << "Invalid property specification" << xml.tokenString() << xml.name();
+ if (!m_xml.isEndElement() || m_xml.name() != "property"_L1) {
+ qDBusParserError("Invalid property specification: '%s'", qPrintable(m_xml.tokenString()));
return false;
}
return true;
}
-static bool parseMethod(QXmlStreamReader &xml, QDBusIntrospection::Method &methodData,
- QDBusIntrospection::Interface *ifaceData)
+bool QDBusXmlParser::parseMethod(QDBusIntrospection::Method &methodData)
{
- Q_ASSERT(xml.isStartElement() && xml.name() == "method"_L1);
+ Q_ASSERT(m_currentInterface);
+ Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "method"_L1);
- const QXmlStreamAttributes attributes = xml.attributes();
+ const QXmlStreamAttributes attributes = m_xml.attributes();
const QString methodName = attributes.value("name"_L1).toString();
if (!QDBusUtil::isValidMemberName(methodName)) {
- qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection",
- qPrintable(methodName), qPrintable(ifaceData->name));
+ qDBusParserError("Invalid D-Bus member name '%s' found in interface '%s' while parsing "
+ "introspection",
+ qPrintable(methodName), qPrintable(m_currentInterface->name));
return false;
}
methodData.name = methodName;
- ifaceData->introspection += " <method name=\""_L1 + methodName + u'"';
+ m_currentInterface->introspection += " <method name=\""_L1 + methodName + u'"';
QDBusIntrospection::Arguments outArguments;
QDBusIntrospection::Arguments inArguments;
QDBusIntrospection::Annotations annotations;
- if (!xml.readNextStartElement()) {
- ifaceData->introspection += "/>\n"_L1;
+ if (!readNextStartElement()) {
+ m_currentInterface->introspection += "/>\n"_L1;
} else {
- ifaceData->introspection += ">\n"_L1;
+ m_currentInterface->introspection += ">\n"_L1;
do {
- if (xml.name() == "annotation"_L1) {
- parseAnnotation(xml, annotations, ifaceData);
- } else if (xml.name() == "arg"_L1) {
- const QXmlStreamAttributes attributes = xml.attributes();
+ if (m_xml.name() == "annotation"_L1) {
+ parseAnnotation(annotations);
+ } else if (m_xml.name() == "arg"_L1) {
+ const QXmlStreamAttributes attributes = m_xml.attributes();
const QString direction = attributes.value("direction"_L1).toString();
QDBusIntrospection::Argument argument;
+ argument.location = m_currentLocation;
if (!attributes.hasAttribute("direction"_L1) || direction == "in"_L1) {
- parseArg(attributes, argument, ifaceData);
+ parseArg(attributes, argument);
inArguments << argument;
} else if (direction == "out"_L1) {
- parseArg(attributes, argument, ifaceData);
+ parseArg(attributes, argument);
outArguments << argument;
}
- } else if (xml.prefix().isEmpty()) {
- qDBusParserError() << "Unknown element" << xml.name() << "while checking for method arguments";
+ } else if (m_xml.prefix().isEmpty()) {
+ qDBusParserWarning("Unknown element '%s' while checking for method arguments",
+ qPrintable(m_xml.name().toString()));
}
- xml.skipCurrentElement();
- } while (xml.readNextStartElement());
+ m_xml.skipCurrentElement();
+ } while (readNextStartElement());
- ifaceData->introspection += " </method>\n"_L1;
+ m_currentInterface->introspection += " </method>\n"_L1;
}
methodData.inputArgs = inArguments;
@@ -189,50 +216,52 @@ static bool parseMethod(QXmlStreamReader &xml, QDBusIntrospection::Method &metho
return true;
}
-
-static bool parseSignal(QXmlStreamReader &xml, QDBusIntrospection::Signal &signalData,
- QDBusIntrospection::Interface *ifaceData)
+bool QDBusXmlParser::parseSignal(QDBusIntrospection::Signal &signalData)
{
- Q_ASSERT(xml.isStartElement() && xml.name() == "signal"_L1);
+ Q_ASSERT(m_currentInterface);
+ Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "signal"_L1);
- const QXmlStreamAttributes attributes = xml.attributes();
+ const QXmlStreamAttributes attributes = m_xml.attributes();
const QString signalName = attributes.value("name"_L1).toString();
if (!QDBusUtil::isValidMemberName(signalName)) {
- qDBusParserError("Invalid D-BUS member name '%s' found in interface '%s' while parsing introspection",
- qPrintable(signalName), qPrintable(ifaceData->name));
+ qDBusParserError("Invalid D-Bus member name '%s' found in interface '%s' while parsing "
+ "introspection",
+ qPrintable(signalName), qPrintable(m_currentInterface->name));
return false;
}
signalData.name = signalName;
- ifaceData->introspection += " <signal name=\""_L1 + signalName + u'"';
+ m_currentInterface->introspection += " <signal name=\""_L1 + signalName + u'"';
QDBusIntrospection::Arguments arguments;
QDBusIntrospection::Annotations annotations;
- if (!xml.readNextStartElement()) {
- ifaceData->introspection += "/>\n"_L1;
+ if (!readNextStartElement()) {
+ m_currentInterface->introspection += "/>\n"_L1;
} else {
- ifaceData->introspection += ">\n"_L1;
+ m_currentInterface->introspection += ">\n"_L1;
do {
- if (xml.name() == "annotation"_L1) {
- parseAnnotation(xml, annotations, ifaceData);
- } else if (xml.name() == "arg"_L1) {
- const QXmlStreamAttributes attributes = xml.attributes();
+ if (m_xml.name() == "annotation"_L1) {
+ parseAnnotation(annotations);
+ } else if (m_xml.name() == "arg"_L1) {
+ const QXmlStreamAttributes attributes = m_xml.attributes();
QDBusIntrospection::Argument argument;
+ argument.location = m_currentLocation;
if (!attributes.hasAttribute("direction"_L1) ||
attributes.value("direction"_L1) == "out"_L1) {
- parseArg(attributes, argument, ifaceData);
+ parseArg(attributes, argument);
arguments << argument;
}
} else {
- qDBusParserError() << "Unknown element" << xml.name() << "while checking for signal arguments";
+ qDBusParserWarning("Unknown element '%s' while checking for signal arguments",
+ qPrintable(m_xml.name().toString()));
}
- xml.skipCurrentElement();
- } while (xml.readNextStartElement());
+ m_xml.skipCurrentElement();
+ } while (readNextStartElement());
- ifaceData->introspection += " </signal>\n"_L1;
+ m_currentInterface->introspection += " </signal>\n"_L1;
}
signalData.outputArgs = arguments;
@@ -241,105 +270,142 @@ static bool parseSignal(QXmlStreamReader &xml, QDBusIntrospection::Signal &signa
return true;
}
-static void readInterface(QXmlStreamReader &xml, QDBusIntrospection::Object *objData,
- QDBusIntrospection::Interfaces *interfaces)
+void QDBusXmlParser::readInterface()
{
- const QString ifaceName = xml.attributes().value("name"_L1).toString();
+ Q_ASSERT(!m_currentInterface);
+
+ const QString ifaceName = m_xml.attributes().value("name"_L1).toString();
if (!QDBusUtil::isValidInterfaceName(ifaceName)) {
- qDBusParserError("Invalid D-BUS interface name '%s' found while parsing introspection",
- qPrintable(ifaceName));
+ qDBusParserError("Invalid D-Bus interface name '%s' found while parsing introspection",
+ qPrintable(ifaceName));
return;
}
- objData->interfaces.append(ifaceName);
+ m_object->interfaces.append(ifaceName);
- QDBusIntrospection::Interface *ifaceData = new QDBusIntrospection::Interface;
- ifaceData->name = ifaceName;
- ifaceData->introspection += " <interface name=\""_L1 + ifaceName + "\">\n"_L1;
+ m_currentInterface = std::make_unique<QDBusIntrospection::Interface>();
+ m_currentInterface->location = m_currentLocation;
+ m_currentInterface->name = ifaceName;
+ m_currentInterface->introspection += " <interface name=\""_L1 + ifaceName + "\">\n"_L1;
- while (xml.readNextStartElement()) {
- if (xml.name() == "method"_L1) {
+ while (readNextStartElement()) {
+ if (m_xml.name() == "method"_L1) {
QDBusIntrospection::Method methodData;
- if (parseMethod(xml, methodData, ifaceData))
- ifaceData->methods.insert(methodData.name, methodData);
- } else if (xml.name() == "signal"_L1) {
+ methodData.location = m_currentLocation;
+ if (parseMethod(methodData))
+ m_currentInterface->methods.insert(methodData.name, methodData);
+ } else if (m_xml.name() == "signal"_L1) {
QDBusIntrospection::Signal signalData;
- if (parseSignal(xml, signalData, ifaceData))
- ifaceData->signals_.insert(signalData.name, signalData);
- } else if (xml.name() == "property"_L1) {
+ signalData.location = m_currentLocation;
+ if (parseSignal(signalData))
+ m_currentInterface->signals_.insert(signalData.name, signalData);
+ } else if (m_xml.name() == "property"_L1) {
QDBusIntrospection::Property propertyData;
- if (parseProperty(xml, propertyData, ifaceData))
- ifaceData->properties.insert(propertyData.name, propertyData);
- } else if (xml.name() == "annotation"_L1) {
- parseAnnotation(xml, ifaceData->annotations, ifaceData, true);
- xml.skipCurrentElement(); // skip over annotation object
+ propertyData.location = m_currentLocation;
+ if (parseProperty(propertyData))
+ m_currentInterface->properties.insert(propertyData.name, propertyData);
+ } else if (m_xml.name() == "annotation"_L1) {
+ parseAnnotation(m_currentInterface->annotations, true);
+ m_xml.skipCurrentElement(); // skip over annotation object
} else {
- if (xml.prefix().isEmpty()) {
- qDBusParserError() << "Unknown element while parsing interface" << xml.name();
+ if (m_xml.prefix().isEmpty()) {
+ qDBusParserWarning("Unknown element '%s' while parsing interface",
+ qPrintable(m_xml.name().toString()));
}
- xml.skipCurrentElement();
+ m_xml.skipCurrentElement();
}
}
- ifaceData->introspection += " </interface>"_L1;
+ m_currentInterface->introspection += " </interface>"_L1;
- interfaces->insert(ifaceName, QSharedDataPointer<QDBusIntrospection::Interface>(ifaceData));
+ m_interfaces.insert(
+ ifaceName,
+ QSharedDataPointer<QDBusIntrospection::Interface>(m_currentInterface.release()));
- if (!xml.isEndElement() || xml.name() != "interface"_L1) {
- qDBusParserError() << "Invalid Interface specification";
+ if (!m_xml.isEndElement() || m_xml.name() != "interface"_L1) {
+ qDBusParserError("Invalid Interface specification");
}
}
-static void readNode(const QXmlStreamReader &xml, QDBusIntrospection::Object *objData, int nodeLevel)
+void QDBusXmlParser::readNode(int nodeLevel)
{
- const QString objName = xml.attributes().value("name"_L1).toString();
- const QString fullName = objData->path.endsWith(u'/')
- ? (objData->path + objName)
- : QString(objData->path + u'/' + objName);
+ const QString objName = m_xml.attributes().value("name"_L1).toString();
+ QString fullName = m_object->path;
+ if (!(fullName.endsWith(u'/') || (nodeLevel == 0 && objName.startsWith(u'/'))))
+ fullName.append(u'/');
+ fullName += objName;
+
if (!QDBusUtil::isValidObjectPath(fullName)) {
- qDBusParserError("Invalid D-BUS object path '%s' found while parsing introspection",
- qPrintable(fullName));
+ qDBusParserError("Invalid D-Bus object path '%s' found while parsing introspection",
+ qPrintable(fullName));
return;
}
if (nodeLevel > 0)
- objData->childObjects.append(objName);
+ m_object->childObjects.append(objName);
+ else
+ m_object->location = m_currentLocation;
+}
+
+void QDBusXmlParser::updateCurrentLocation()
+{
+ m_currentLocation =
+ QDBusIntrospection::SourceLocation{ m_xml.lineNumber(), m_xml.columnNumber() };
}
-QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path,
- const QString& xmlData)
- : m_service(service), m_path(path), m_object(new QDBusIntrospection::Object)
+// Similar to m_xml.readNextElement() but sets current location to point
+// to the start element.
+bool QDBusXmlParser::readNextStartElement()
{
-// qDBusParserError() << "parsing" << xmlData;
+ updateCurrentLocation();
+
+ while (m_xml.readNext() != QXmlStreamReader::Invalid) {
+ if (m_xml.isEndElement())
+ return false;
+ else if (m_xml.isStartElement())
+ return true;
+ updateCurrentLocation();
+ }
+ return false;
+}
+QDBusXmlParser::QDBusXmlParser(const QString &service, const QString &path, const QString &xmlData,
+ QDBusIntrospection::DiagnosticsReporter *reporter)
+ : m_service(service),
+ m_path(path),
+ m_object(new QDBusIntrospection::Object),
+ m_xml(xmlData),
+ m_reporter(reporter)
+{
m_object->service = m_service;
m_object->path = m_path;
- QXmlStreamReader xml(xmlData);
-
int nodeLevel = -1;
- while (!xml.atEnd()) {
- xml.readNext();
+ while (!m_xml.atEnd()) {
+ updateCurrentLocation();
+ m_xml.readNext();
- switch (xml.tokenType()) {
+ switch (m_xml.tokenType()) {
case QXmlStreamReader::StartElement:
- if (xml.name() == "node"_L1) {
- readNode(xml, m_object, ++nodeLevel);
- } else if (xml.name() == "interface"_L1) {
- readInterface(xml, m_object, &m_interfaces);
+ if (m_xml.name() == "node"_L1) {
+ readNode(++nodeLevel);
+ } else if (m_xml.name() == "interface"_L1) {
+ readInterface();
} else {
- if (xml.prefix().isEmpty()) {
- qDBusParserError() << "skipping unknown element" << xml.name();
+ if (m_xml.prefix().isEmpty()) {
+ qDBusParserWarning("Skipping unknown element '%s'",
+ qPrintable(m_xml.name().toString()));
}
- xml.skipCurrentElement();
+ m_xml.skipCurrentElement();
}
break;
case QXmlStreamReader::EndElement:
- if (xml.name() == "node"_L1) {
+ if (m_xml.name() == "node"_L1) {
--nodeLevel;
} else {
- qDBusParserError() << "Invalid Node declaration" << xml.name();
+ qDBusParserError("Invalid node declaration '%s'",
+ qPrintable(m_xml.name().toString()));
}
break;
case QXmlStreamReader::StartDocument:
@@ -352,18 +418,17 @@ QDBusXmlParser::QDBusXmlParser(const QString& service, const QString& path,
break;
case QXmlStreamReader::Characters:
// ignore whitespace
- if (xml.isWhitespace())
+ if (m_xml.isWhitespace())
break;
Q_FALLTHROUGH();
default:
- qDBusParserError() << "unknown token" << xml.name() << xml.tokenString();
+ qDBusParserError("Unknown token: '%s'", qPrintable(m_xml.tokenString()));
break;
}
}
- if (xml.hasError()) {
- qDBusParserError() << "xml error" << xml.errorString() << "doc" << xmlData;
- }
+ if (m_xml.hasError())
+ qDBusParserError("XML error: %s", qPrintable(m_xml.errorString()));
}
QT_END_NAMESPACE
diff --git a/src/dbus/qdbusxmlparser_p.h b/src/dbus/qdbusxmlparser_p.h
index db3b289a2a..0476ba3628 100644
--- a/src/dbus/qdbusxmlparser_p.h
+++ b/src/dbus/qdbusxmlparser_p.h
@@ -18,6 +18,7 @@
#include <QtDBus/private/qtdbusglobal_p.h>
#include <QtCore/qloggingcategory.h>
#include <QtCore/qmap.h>
+#include <QtCore/qxmlstream.h>
#include "qdbusintrospection_p.h"
#ifndef QT_NO_DBUS
@@ -34,14 +35,30 @@ class QDBusXmlParser
QString m_service;
QString m_path;
QSharedDataPointer<QDBusIntrospection::Object> m_object;
+ std::unique_ptr<QDBusIntrospection::Interface> m_currentInterface;
QDBusIntrospection::Interfaces m_interfaces;
+ QXmlStreamReader m_xml;
+ QDBusIntrospection::SourceLocation m_currentLocation;
+ QDBusIntrospection::DiagnosticsReporter *m_reporter;
public:
- QDBusXmlParser(const QString& service, const QString& path,
- const QString& xmlData);
+ QDBusXmlParser(const QString &service, const QString &path, const QString &xmlData,
+ QDBusIntrospection::DiagnosticsReporter *reporter = nullptr);
inline QDBusIntrospection::Interfaces interfaces() const { return m_interfaces; }
inline QSharedDataPointer<QDBusIntrospection::Object> object() const { return m_object; }
+
+private:
+ void readNode(int nodeLevel);
+ void readInterface();
+ bool parseSignal(QDBusIntrospection::Signal &signalData);
+ bool parseMethod(QDBusIntrospection::Method &methodData);
+ bool parseProperty(QDBusIntrospection::Property &propertyData);
+ bool parseAnnotation(QDBusIntrospection::Annotations &annotations,
+ bool interfaceAnnotation = false);
+ bool parseArg(const QXmlStreamAttributes &attributes, QDBusIntrospection::Argument &argData);
+ bool readNextStartElement();
+ void updateCurrentLocation();
};
QT_END_NAMESPACE
diff --git a/src/dbus/qt_attribution.json b/src/dbus/qt_attribution.json
index 6cfe6ab2af..a4c4446862 100644
--- a/src/dbus/qt_attribution.json
+++ b/src/dbus/qt_attribution.json
@@ -11,8 +11,8 @@
"LicenseId": "AFL-2.1 OR GPL-2.0-or-later",
"License": "Academic Free License v2.1, or GNU General Public License v2.0 or later",
"LicenseFile": "LIBDBUS-1-LICENSE.txt",
- "Files": "Fragments from various upstream files, see comments in ...",
+ "Comment": "Fragments from various upstream files, see comments in ...",
"Files": "dbus_minimal_p.h",
- "Copyright": "Copyright (C) 2002, 2003 CodeFactory AB
-Copyright (C) 2004, 2005 Red Hat, Inc."
+ "Copyright": ["Copyright (C) 2002, 2003 CodeFactory AB",
+ "Copyright (C) 2004, 2005 Red Hat, Inc."]
}
diff --git a/src/dbus/qtdbusglobal.h b/src/dbus/qtdbusglobal.h
index 3c2268c8c3..9724c066f6 100644
--- a/src/dbus/qtdbusglobal.h
+++ b/src/dbus/qtdbusglobal.h
@@ -4,10 +4,6 @@
#ifndef QTDBUSGLOBAL_H
#define QTDBUSGLOBAL_H
-#if 0
-#pragma qt_deprecates(qdbusmacros.h)
-#endif
-
#include <QtCore/qglobal.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qvariant.h>
diff --git a/src/entrypoint/CMakeLists.txt b/src/entrypoint/CMakeLists.txt
index 21385eaba0..ba8342e41a 100644
--- a/src/entrypoint/CMakeLists.txt
+++ b/src/entrypoint/CMakeLists.txt
@@ -1,7 +1,7 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
-if (NOT WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "iOS")
+if (NOT (WIN32 OR UIKIT))
return()
endif()
@@ -111,7 +111,7 @@ if(WIN32)
qt_internal_add_sync_header_dependencies(EntryPointImplementation Core)
endif()
-if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
+if(UIKIT)
set_target_properties(EntryPointPrivate PROPERTIES
INTERFACE_LINK_OPTIONS "-Wl,-e,_qt_main_wrapper"
)
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt
index 3fd28d2a01..cef71318d8 100644
--- a/src/gui/CMakeLists.txt
+++ b/src/gui/CMakeLists.txt
@@ -13,7 +13,7 @@ if (QT_FEATURE_gui)
set(_default_platform "android")
elseif(MACOS)
set(_default_platform "cocoa")
- elseif(TVOS OR IOS)
+ elseif(UIKIT)
set(_default_platform "ios")
elseif(WATCHOS)
set(_default_platform "minimal")
@@ -56,12 +56,13 @@ qt_internal_add_module(Gui
Qt::Network
QMAKE_MODULE_CONFIG "${qmake_module_config}"
SOURCES
+ compat/removed_api.cpp
image/qabstractfileiconengine.cpp image/qabstractfileiconengine_p.h
image/qabstractfileiconprovider.cpp image/qabstractfileiconprovider.h image/qabstractfileiconprovider_p.h
image/qbitmap.cpp image/qbitmap.h
image/qbmphandler.cpp image/qbmphandler_p.h
image/qicon.cpp image/qicon.h image/qicon_p.h
- image/qiconengine.cpp image/qiconengine.h
+ image/qiconengine.cpp image/qiconengine.h image/qiconengine_p.h
image/qiconengineplugin.cpp image/qiconengineplugin.h
image/qiconloader.cpp image/qiconloader_p.h
image/qimage.cpp image/qimage.h image/qimage_p.h
@@ -100,7 +101,7 @@ qt_internal_add_module(Gui
kernel/qoffscreensurface_platform.h
kernel/qopenglcontext.h
kernel/qpaintdevicewindow.cpp kernel/qpaintdevicewindow.h kernel/qpaintdevicewindow_p.h
- kernel/qpalette.cpp kernel/qpalette.h
+ kernel/qpalette.cpp kernel/qpalette.h kernel/qpalette_p.h
kernel/qpixelformat.cpp kernel/qpixelformat.h
kernel/qplatformclipboard.cpp kernel/qplatformclipboard.h
kernel/qplatformcursor.cpp kernel/qplatformcursor.h
@@ -113,6 +114,7 @@ qt_internal_add_module(Gui
kernel/qplatformintegration.cpp kernel/qplatformintegration.h
kernel/qplatformintegrationfactory.cpp kernel/qplatformintegrationfactory_p.h
kernel/qplatformintegrationplugin.cpp kernel/qplatformintegrationplugin.h
+ kernel/qplatformkeymapper.cpp kernel/qplatformkeymapper.h
kernel/qplatformmenu.cpp kernel/qplatformmenu.h kernel/qplatformmenu_p.h
kernel/qplatformnativeinterface.cpp kernel/qplatformnativeinterface.h
kernel/qplatformoffscreensurface.cpp kernel/qplatformoffscreensurface.h
@@ -129,7 +131,7 @@ qt_internal_add_module(Gui
kernel/qplatformwindow.cpp kernel/qplatformwindow.h kernel/qplatformwindow_p.h
kernel/qpointingdevice.cpp kernel/qpointingdevice.h kernel/qpointingdevice_p.h
kernel/qrasterwindow.cpp kernel/qrasterwindow.h
- kernel/qscreen.cpp kernel/qscreen.h kernel/qscreen_p.h
+ kernel/qscreen.cpp kernel/qscreen.h kernel/qscreen_p.h kernel/qscreen_platform.h
kernel/qsessionmanager.cpp kernel/qsessionmanager.h kernel/qsessionmanager_p.h
kernel/qstylehints.cpp kernel/qstylehints.h kernel/qstylehints_p.h
kernel/qsurface.cpp kernel/qsurface.h
@@ -158,6 +160,7 @@ qt_internal_add_module(Gui
painting/qblittable.cpp painting/qblittable_p.h
painting/qbrush.cpp painting/qbrush.h
painting/qcolor.cpp painting/qcolor.h painting/qcolor_p.h
+ painting/qcolorclut_p.h
painting/qcolormatrix_p.h
painting/qcolorspace.cpp painting/qcolorspace.h painting/qcolorspace_p.h
painting/qcolortransferfunction_p.h
@@ -167,6 +170,7 @@ qt_internal_add_module(Gui
painting/qcolortrclut.cpp painting/qcolortrclut_p.h
painting/qcompositionfunctions.cpp
painting/qcosmeticstroker.cpp painting/qcosmeticstroker_p.h
+ painting/qcmyk_p.h
painting/qdatabuffer_p.h
painting/qdrawhelper_p.h
painting/qdrawhelper_x86_p.h
@@ -175,6 +179,7 @@ qt_internal_add_module(Gui
painting/qfixed_p.h
painting/qgrayraster.c painting/qgrayraster_p.h
painting/qicc.cpp painting/qicc_p.h
+ painting/qimageeffects.cpp
painting/qimagescale.cpp painting/qimagescale_p.h
painting/qmath_p.h
painting/qmemrotate.cpp painting/qmemrotate_p.h
@@ -211,14 +216,10 @@ qt_internal_add_module(Gui
painting/qtriangulatingstroker.cpp painting/qtriangulatingstroker_p.h
painting/qtriangulator.cpp painting/qtriangulator_p.h
painting/qvectorpath_p.h
- rhi/qrhi.cpp rhi/qrhi_p.h
- rhi/qrhi_p_p.h
+ rhi/qrhi.cpp rhi/qrhi.h rhi/qrhi_platform.h rhi/qrhi_p.h
rhi/qrhinull.cpp rhi/qrhinull_p.h
- rhi/qrhinull_p_p.h
- rhi/qshader.cpp rhi/qshader_p.h
- rhi/qshader_p_p.h
- rhi/qshaderdescription.cpp rhi/qshaderdescription_p.h
- rhi/qshaderdescription_p_p.h
+ rhi/qshader.cpp rhi/qshader.h rhi/qshader_p.h
+ rhi/qshaderdescription.cpp rhi/qshaderdescription.h rhi/qshaderdescription_p.h
text/qabstracttextdocumentlayout.cpp text/qabstracttextdocumentlayout.h text/qabstracttextdocumentlayout_p.h
text/qdistancefield.cpp text/qdistancefield_p.h
text/qfont.cpp text/qfont.h text/qfont_p.h
@@ -262,8 +263,10 @@ qt_internal_add_module(Gui
util/qtexturefilereader.cpp util/qtexturefilereader_p.h
util/qvalidator.cpp util/qvalidator.h
DEFINES
+ QT_NO_CONTEXTLESS_CONNECT
QT_NO_FOREACH
QT_NO_USING_NAMESPACE
+ QT_USE_NODISCARD_FILE_OPEN
QT_QPA_DEFAULT_PLATFORM_NAME="${QT_QPA_DEFAULT_PLATFORM}"
INCLUDE_DIRECTORIES
../3rdparty/VulkanMemoryAllocator
@@ -275,39 +278,40 @@ qt_internal_add_module(Gui
PRIVATE_MODULE_INTERFACE
Qt::CorePrivate
NO_PCH_SOURCES
- "painting/qdrawhelper.cpp"
+ compat/removed_api.cpp
+ painting/qdrawhelper.cpp
PRECOMPILED_HEADER
"kernel/qt_gui_pch.h"
GENERATE_CPP_EXPORTS
QPA_HEADER_FILTERS
"(^|/)qplatform.+\\.h$|(^|/)qwindowsystem.+\\.h$"
+ RHI_HEADER_FILTERS
+ "(^|/)qrhi\\.h$|(^|/)qrhi_platform\\.h$|(^|/)qshader\\.h$|(^|/)qshaderdescription\\.h$"
)
# Resources:
-set_source_files_properties("../3rdparty/icc/sRGB2014.icc"
- PROPERTIES QT_RESOURCE_ALIAS "sRGB2014.icc"
-)
-set(qpdf_resource_files
- "../3rdparty/icc/sRGB2014.icc"
- "painting/qpdfa_metadata.xml"
-)
-
-set_source_files_properties(painting/qdrawhelper.cpp # NO_PCH_SOURCES
- PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
+if(QT_FEATURE_pdf)
+ set_source_files_properties("../3rdparty/icc/sRGB2014.icc"
+ PROPERTIES QT_RESOURCE_ALIAS "sRGB2014.icc"
+ )
+ set(qpdf_resource_files
+ "../3rdparty/icc/sRGB2014.icc"
+ "painting/qpdfa_metadata.xml"
+ )
+ qt_internal_add_resource(Gui "qpdf"
+ PREFIX
+ "/qpdf/"
+ BASE
+ "painting"
+ FILES
+ ${qpdf_resource_files}
+ )
+endif()
if(WIN32 OR (UNIX AND NOT APPLE))
set_target_properties(Gui PROPERTIES UNITY_BUILD OFF) # X11 define clashes/Windows oddities.
endif()
-qt_internal_add_resource(Gui "qpdf"
- PREFIX
- "/qpdf/"
- BASE
- "painting"
- FILES
- ${qpdf_resource_files}
-)
-
qt_internal_add_resource(Gui "gui_shaders"
PREFIX
"/qt-project.org/gui"
@@ -339,9 +343,10 @@ if(QT_FEATURE_opengl)
target_link_libraries(Gui PUBLIC GLESv2::GLESv2)
if(INTEGRITY AND _qt_igy_gui_libs)
- find_package(IntegrityPlatformGraphics)
- target_link_libraries(Gui
- INTERFACE $<LINK_ONLY:IntegrityPlatformGraphics::IntegrityPlatformGraphics>)
+ qt_internal_extend_target(Gui
+ LIBRARIES
+ IntegrityPlatformGraphics::IntegrityPlatformGraphics
+ )
endif()
elseif(NOT QT_FEATURE_opengl_dynamic)
@@ -359,7 +364,6 @@ qt_internal_extend_target(Gui CONDITION QT_FEATURE_opengl
opengl/qopenglfunctions.cpp
opengl/qopenglprogrambinarycache.cpp opengl/qopenglprogrambinarycache_p.h
rhi/qrhigles2.cpp rhi/qrhigles2_p.h
- rhi/qrhigles2_p_p.h
)
qt_internal_extend_target(Gui CONDITION MACOS
@@ -372,6 +376,11 @@ qt_internal_extend_target(Gui CONDITION MACOS
${FWAppKit}
)
+qt_internal_extend_target(Gui CONDITION WASM
+ SOURCES
+ platform/wasm/qwasmnativeinterface.cpp
+)
+
qt_internal_extend_target(Gui CONDITION APPLE
SOURCES
image/qimage_darwin.mm
@@ -381,6 +390,7 @@ qt_internal_extend_target(Gui CONDITION APPLE
platform/darwin/qmacmimeregistry.mm platform/darwin/qmacmimeregistry_p.h
platform/darwin/qutimimeconverter.mm platform/darwin/qutimimeconverter.h
platform/darwin/qapplekeymapper.mm platform/darwin/qapplekeymapper_p.h
+ platform/darwin/qappleiconengine.mm platform/darwin/qappleiconengine_p.h
text/coretext/qcoretextfontdatabase.mm text/coretext/qcoretextfontdatabase_p.h
text/coretext/qfontengine_coretext.mm text/coretext/qfontengine_coretext_p.h
LIBRARIES
@@ -404,11 +414,11 @@ qt_internal_extend_target(Gui CONDITION WIN32
platform/windows/qwindowsguieventdispatcher.cpp platform/windows/qwindowsguieventdispatcher_p.h
platform/windows/qwindowsmimeconverter.h platform/windows/qwindowsmimeconverter.cpp
platform/windows/qwindowsnativeinterface.cpp
+ platform/windows/qwindowsthemecache.cpp platform/windows/qwindowsthemecache_p.h
rhi/qrhid3d11.cpp rhi/qrhid3d11_p.h
- rhi/qrhid3d11_p_p.h
+ rhi/qrhid3dhelpers.cpp rhi/qrhid3dhelpers_p.h
rhi/vs_test_p.h
rhi/qrhid3d12.cpp rhi/qrhid3d12_p.h
- rhi/qrhid3d12_p_p.h
rhi/cs_mipmap_p.h
../3rdparty/D3D12MemoryAllocator/D3D12MemAlloc.h
../3rdparty/D3D12MemoryAllocator/D3D12MemAlloc.cpp
@@ -422,14 +432,36 @@ qt_internal_extend_target(Gui CONDITION WIN32
ole32
shell32
user32
+ uxtheme
PUBLIC_LIBRARIES
d3d11
dxgi
dxguid
- dcomp
d3d12
)
+if(QT_FEATURE_graphicsframecapture)
+ qt_internal_extend_target(Gui
+ SOURCES
+ util/qgraphicsframecapture_p.h util/qgraphicsframecapture.cpp
+ util/qgraphicsframecapture_p_p.h
+ )
+
+ qt_internal_extend_target(Gui CONDITION (WIN32 OR (UNIX AND NOT APPLE)) AND QT_FEATURE_library
+ LIBRARIES
+ RenderDoc::RenderDoc
+ SOURCES
+ util/qgraphicsframecapturerenderdoc_p_p.h util/qgraphicsframecapturerenderdoc.cpp
+ )
+
+ qt_internal_extend_target(Gui CONDITION IOS OR MACOS
+ SOURCES
+ util/qgraphicsframecapturemetal_p_p.h util/qgraphicsframecapturemetal.mm
+ PUBLIC_LIBRARIES
+ ${FWMetal}
+ )
+endif()
+
if(QT_FEATURE_egl)
qt_find_package(EGL)
endif()
@@ -443,9 +475,15 @@ qt_internal_extend_target(Gui CONDITION QT_FEATURE_egl
EGL::EGL
)
-qt_internal_extend_target(Gui CONDITION QT_FEATURE_accessibility
- CONDITION_INDEPENDENT_SOURCES
+# These two headers are always installed, their contents are guarded with
+# "#if QT_CONFIG(accessibility)", so if QT_FEATURE_accessibility is not
+# enabled, they are just duds.
+qt_internal_extend_target(Gui
+ SOURCES
accessible/qaccessible.h accessible/qplatformaccessibility.h
+)
+
+qt_internal_extend_target(Gui CONDITION QT_FEATURE_accessibility
SOURCES
accessible/qaccessible.cpp accessible/qaccessible_base.h
accessible/qaccessiblebridge.cpp accessible/qaccessiblebridge.h
@@ -463,21 +501,6 @@ qt_internal_extend_target(Gui CONDITION APPLE AND QT_FEATURE_accessibility
${FWFoundation}
)
-qt_internal_extend_target(Gui CONDITION QT_FEATURE_accessibility AND WIN32
- SOURCES
- accessible/windows/apisupport/qwindowsuiawrapper.cpp accessible/windows/apisupport/qwindowsuiawrapper_p.h
- accessible/windows/apisupport/uiaattributeids_p.h
- accessible/windows/apisupport/uiaclientinterfaces_p.h
- accessible/windows/apisupport/uiacontroltypeids_p.h
- accessible/windows/apisupport/uiaerrorids_p.h
- accessible/windows/apisupport/uiaeventids_p.h
- accessible/windows/apisupport/uiageneralids_p.h
- accessible/windows/apisupport/uiapatternids_p.h
- accessible/windows/apisupport/uiapropertyids_p.h
- accessible/windows/apisupport/uiaserverinterfaces_p.h
- accessible/windows/apisupport/uiatypes_p.h
-)
-
if(QT_FEATURE_accessibility AND QT_FEATURE_accessibility_atspi_bridge)
set(atspi_accessibility ON)
else()
@@ -543,7 +566,10 @@ qt_internal_extend_target(Gui CONDITION QT_FEATURE_png
WrapPNG::WrapPNG
)
-qt_internal_extend_target(Gui CONDITION ((QT_FEATURE_png) AND (WIN32 AND MINGW)) AND (GCC_VERSION___equals___8.1.0)
+qt_internal_extend_target(Gui
+ CONDITION
+ QT_FEATURE_png AND WIN32 AND MINGW AND
+ (CMAKE_CXX_COMPILER_VESION VERSION_EQUAL "8.1.0")
COMPILE_OPTIONS
-fno-reorder-blocks-and-partition
)
@@ -605,6 +631,8 @@ endif()
qt_internal_extend_target(Gui CONDITION ANDROID
SOURCES
platform/android/qandroidnativeinterface.cpp
+ painting/qrasterbackingstore.cpp painting/qrasterbackingstore_p.h
+ painting/qrhibackingstore.cpp painting/qrhibackingstore_p.h
)
qt_internal_extend_target(Gui CONDITION ANDROID AND (TEST_architecture_arch STREQUAL arm64 OR TEST_architecture_arch STREQUAL arm)
@@ -647,9 +675,6 @@ qt_internal_extend_target(Gui CONDITION QT_FEATURE_harfbuzz AND UIKIT
qt_internal_extend_target(Gui CONDITION QT_FEATURE_textodfwriter
SOURCES
text/qtextodfwriter.cpp text/qtextodfwriter_p.h
- text/qzip.cpp
- text/qzipreader_p.h
- text/qzipwriter_p.h
)
qt_internal_extend_target(Gui CONDITION QT_FEATURE_textmarkdownreader
@@ -832,7 +857,6 @@ qt_internal_extend_target(Gui CONDITION QT_FEATURE_filesystemmodel
qt_internal_extend_target(Gui CONDITION QT_FEATURE_vulkan
SOURCES
rhi/qrhivulkan.cpp rhi/qrhivulkan_p.h
- rhi/qrhivulkanext_p.h
vulkan/qbasicvulkanplatforminstance.cpp vulkan/qbasicvulkanplatforminstance_p.h
vulkan/qplatformvulkaninstance.cpp vulkan/qplatformvulkaninstance.h
vulkan/qvulkandefaultinstance.cpp vulkan/qvulkandefaultinstance_p.h
@@ -871,7 +895,7 @@ if (QT_FEATURE_vulkan)
list(APPEND vulkan_fun_command_content
COMMAND "${qvkgen}"
"${CMAKE_CURRENT_SOURCE_DIR}/vulkan/vk.xml"
- "${CMAKE_CURRENT_SOURCE_DIR}/vulkan/generated_header.txt"
+ "${CMAKE_CURRENT_SOURCE_DIR}/vulkan/licenseheader.h.in"
"${CMAKE_CURRENT_BINARY_DIR}/vulkan/qvulkanfunctions"
DEPENDS vulkan/vk.xml ${qvkgen}
COMMENT "Generating vulkan data"
@@ -904,10 +928,14 @@ qt_internal_extend_target(Gui CONDITION WASM
qt_internal_extend_target(Gui CONDITION UNIX
SOURCES
+ platform/unix/qunixnativeinterface.cpp
+)
+
+qt_internal_extend_target(Gui CONDITION UNIX AND NOT WASM
+ SOURCES
platform/unix/qgenericunixeventdispatcher.cpp platform/unix/qgenericunixeventdispatcher_p.h
platform/unix/qunixeventdispatcher.cpp
platform/unix/qunixeventdispatcher_qpa_p.h
- platform/unix/qunixnativeinterface.cpp
)
qt_internal_extend_target(Gui CONDITION QT_FEATURE_glib AND UNIX
@@ -965,10 +993,9 @@ qt_internal_extend_target(Gui CONDITION QT_FEATURE_xkbcommon AND UNIX
XKB::XKB
)
-qt_internal_extend_target(Gui CONDITION IOS OR MACOS
+qt_internal_extend_target(Gui CONDITION QT_FEATURE_metal
SOURCES
rhi/qrhimetal.mm rhi/qrhimetal_p.h
- rhi/qrhimetal_p_p.h
PUBLIC_LIBRARIES
${FWMetal}
)
@@ -980,7 +1007,7 @@ qt_internal_extend_target(Gui
"painting/qdrawhelper.cpp"
)
-qt_internal_extend_target(Gui CONDITION (QT_FEATURE_eglfs OR QT_FEATURE_xcb)
+qt_internal_extend_target(Gui CONDITION (QT_FEATURE_eglfs OR QT_FEATURE_xcb OR QT_FEATURE_direct2d OR WIN32)
SOURCES
util/qedidparser.cpp util/qedidparser_p.h
util/qedidvendortable_p.h
@@ -995,4 +1022,9 @@ qt_internal_add_docs(Gui
doc/qtgui.qdocconf
)
+if(IOS)
+ qt_internal_set_apple_privacy_manifest(Gui
+ "${CMAKE_CURRENT_SOURCE_DIR}/platform/ios/PrivacyInfo.xcprivacy")
+endif()
+
qt_internal_add_optimize_full_flags()
diff --git a/src/gui/accessible/linux/atspiadaptor.cpp b/src/gui/accessible/linux/atspiadaptor.cpp
index e6ada2c240..b3269a2a95 100644
--- a/src/gui/accessible/linux/atspiadaptor.cpp
+++ b/src/gui/accessible/linux/atspiadaptor.cpp
@@ -16,6 +16,7 @@
#if QT_CONFIG(accessibility)
#include "socket_interface.h"
#include "qspi_constant_mappings_p.h"
+#include <QtCore/private/qstringiterator_p.h>
#include <QtGui/private/qaccessiblebridgeutils_p.h>
#include "qspiapplicationadaptor_p.h"
@@ -468,6 +469,14 @@ QString AtSpiAdaptor::introspect(const QString &path) const
" <arg direction=\"out\" name=\"row_extents\" type=\"i\" />\n"
" <arg direction=\"out\" name=\"col_extents\" type=\"i\" />\n"
" </method>\n"
+ " <method name=\"GetColumnHeaderCells\">\n"
+ " <arg direction=\"out\" type=\"a(so)\"/>\n"
+ " <annotation value=\"QSpiObjectReferenceArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
+ " <method name=\"GetRowHeaderCells\">\n"
+ " <arg direction=\"out\" type=\"a(so)\"/>\n"
+ " <annotation value=\"QSpiObjectReferenceArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
+ " </method>\n"
" </interface>\n"
);
@@ -1741,15 +1750,14 @@ bool AtSpiAdaptor::inheritsQAction(QObject *object)
// Component
static QAccessibleInterface * getWindow(QAccessibleInterface * interface)
{
- if (interface->role() == QAccessible::Dialog || interface->role() == QAccessible::Window)
- return interface;
-
- QAccessibleInterface * parent = interface->parent();
- while (parent && parent->role() != QAccessible::Dialog
- && parent->role() != QAccessible::Window)
- parent = parent->parent();
-
- return parent;
+ // find top-level window in a11y hierarchy (either has a
+ // corresponding role or is a direct child of the application object)
+ QAccessibleInterface* app = QAccessible::queryAccessibleInterface(qApp);
+ while (interface && interface->role() != QAccessible::Dialog
+ && interface->role() != QAccessible::Window && interface->parent() != app)
+ interface = interface->parent();
+
+ return interface;
}
bool AtSpiAdaptor::componentInterface(QAccessibleInterface *interface, const QString &function, const QDBusMessage &message, const QDBusConnection &connection)
@@ -1980,8 +1988,13 @@ bool AtSpiAdaptor::textInterface(QAccessibleInterface *interface, const QString
int offset = message.arguments().at(0).toInt();
int start;
int end;
- QString result = interface->textInterface()->textAtOffset(offset, QAccessible::CharBoundary, &start, &end);
- sendReply(connection, message, (int) *(qPrintable (result)));
+ const QString charString = interface->textInterface()
+ ->textAtOffset(offset, QAccessible::CharBoundary, &start, &end);
+ int codePoint = 0;
+ QStringIterator stringIt(charString);
+ if (stringIt.hasNext())
+ codePoint = static_cast<int>(stringIt.peekNext());
+ sendReply(connection, message, codePoint);
} else if (function == "GetCharacterExtents"_L1) {
int offset = message.arguments().at(0).toInt();
int coordType = message.arguments().at(1).toUInt();
@@ -2147,7 +2160,7 @@ namespace
QString atspiColor(const QString &ia2Color)
{
// "rgb(%u,%u,%u)" -> "%u,%u,%u"
- return ia2Color.mid(4, ia2Color.size() - (4+1));
+ return ia2Color.mid(4, ia2Color.size() - (4+1)).replace(u"\\,"_s, u","_s);
}
QString atspiSize(const QString &ia2Size)
@@ -2161,9 +2174,9 @@ namespace
QString name = ia2Name;
QString value = ia2Value;
- // IAccessible2: http://www.linuxfoundation.org/collaborate/workgroups/accessibility/iaccessible2/textattributes
- // ATK attribute names: https://git.gnome.org/browse/orca/tree/src/orca/text_attribute_names.py
- // ATK attribute values: https://developer.gnome.org/atk/unstable/AtkText.html#AtkTextAttribute
+ // IAccessible2: https://wiki.linuxfoundation.org/accessibility/iaccessible2/textattributes
+ // ATK attribute names: https://gitlab.gnome.org/GNOME/orca/-/blob/master/src/orca/text_attribute_names.py
+ // ATK attribute values: https://gnome.pages.gitlab.gnome.org/atk/AtkText.html#AtkTextAttribute
// https://bugzilla.gnome.org/show_bug.cgi?id=744553 "ATK docs provide no guidance for allowed values of some text attributes"
// specifically for "weight", "invalid", "language" and value range for colors
@@ -2209,6 +2222,13 @@ namespace
// (on which it produces traceback and fails to read any following text attributes),
// but that is the default value, so omit it anyway
value = QString();
+ } else if (((ia2Name == "text-line-through-style"_L1 || ia2Name == "text-line-through-type"_L1) && (ia2Value != "none"_L1))
+ || (ia2Name == "text-line-through-text"_L1 && !ia2Value.isEmpty())) {
+ // if any of the above is set, set "strikethrough" to true, but don't explicitly set
+ // to false otherwise, since any of the others might still be set to indicate strikethrough
+ // and no strikethrough is assumed anyway when nothing is explicitly set
+ name = QStringLiteral("strikethrough");
+ value = QStringLiteral("true");
} else if (ia2Name == "text-position"_L1) {
name = QStringLiteral("vertical-align");
if (value != "baseline"_L1 && value != "super"_L1 && value != "sub"_L1) {
@@ -2256,11 +2276,13 @@ QVariantList AtSpiAdaptor::getAttributes(QAccessibleInterface *interface, int of
QString joined = interface->textInterface()->attributes(offset, &startOffset, &endOffset);
const QStringList attributes = joined.split(u';', Qt::SkipEmptyParts, Qt::CaseSensitive);
for (const QString &attr : attributes) {
- QStringList items;
- items = attr.split(u':', Qt::SkipEmptyParts, Qt::CaseSensitive);
- AtSpiAttribute attribute = atspiTextAttribute(items[0], items[1]);
- if (!attribute.isNull())
- set[attribute.name] = attribute.value;
+ QStringList items = attr.split(u':', Qt::SkipEmptyParts, Qt::CaseSensitive);
+ if (items.count() == 2)
+ {
+ AtSpiAttribute attribute = atspiTextAttribute(items[0], items[1]);
+ if (!attribute.isNull())
+ set[attribute.name] = attribute.value;
+ }
}
QVariantList list;
@@ -2672,14 +2694,15 @@ bool AtSpiAdaptor::tableInterface(QAccessibleInterface *interface, const QString
if (cols > 0) {
row = index / cols;
col = index % cols;
- QAccessibleTableCellInterface *cell = interface->tableInterface()->cellAt(row, col)->tableCellInterface();
- if (cell) {
- row = cell->rowIndex();
- col = cell->columnIndex();
- rowExtents = cell->rowExtent();
- colExtents = cell->columnExtent();
- isSelected = cell->isSelected();
- success = true;
+ if (QAccessibleInterface *cell = interface->tableInterface()->cellAt(row, col)) {
+ if (QAccessibleTableCellInterface *cellIface = cell->tableCellInterface()) {
+ row = cellIface->rowIndex();
+ col = cellIface->columnIndex();
+ rowExtents = cellIface->rowExtent();
+ colExtents = cellIface->columnExtent();
+ isSelected = cellIface->isSelected();
+ success = true;
+ }
}
}
QVariantList list;
@@ -2689,12 +2712,22 @@ bool AtSpiAdaptor::tableInterface(QAccessibleInterface *interface, const QString
} else if (function == "GetColumnExtentAt"_L1) {
int row = message.arguments().at(0).toInt();
int column = message.arguments().at(1).toInt();
- connection.send(message.createReply(interface->tableInterface()->cellAt(row, column)->tableCellInterface()->columnExtent()));
+ int columnExtent = 0;
+ if (QAccessibleInterface *cell = interface->tableInterface()->cellAt(row, column)) {
+ if (QAccessibleTableCellInterface *cellIface = cell->tableCellInterface())
+ columnExtent = cellIface->columnExtent();
+ }
+ connection.send(message.createReply(columnExtent));
} else if (function == "GetRowExtentAt"_L1) {
int row = message.arguments().at(0).toInt();
int column = message.arguments().at(1).toInt();
- connection.send(message.createReply(interface->tableInterface()->cellAt(row, column)->tableCellInterface()->rowExtent()));
+ int rowExtent = 0;
+ if (QAccessibleInterface *cell = interface->tableInterface()->cellAt(row, column)) {
+ if (QAccessibleTableCellInterface *cellIface = cell->tableCellInterface())
+ rowExtent = cellIface->rowExtent();
+ }
+ connection.send(message.createReply(rowExtent));
} else if (function == "GetColumnHeader"_L1) {
int column = message.arguments().at(0).toInt();
@@ -2734,8 +2767,12 @@ bool AtSpiAdaptor::tableInterface(QAccessibleInterface *interface, const QString
} else if (function == "IsSelected"_L1) {
int row = message.arguments().at(0).toInt();
int column = message.arguments().at(1).toInt();
- QAccessibleTableCellInterface* cell = interface->tableInterface()->cellAt(row, column)->tableCellInterface();
- connection.send(message.createReply(cell->isSelected()));
+ bool selected = false;
+ if (QAccessibleInterface* cell = interface->tableInterface()->cellAt(row, column)) {
+ if (QAccessibleTableCellInterface *cellIface = cell->tableCellInterface())
+ selected = cellIface->isSelected();
+ }
+ connection.send(message.createReply(selected));
} else if (function == "AddColumnSelection"_L1) {
int column = message.arguments().at(0).toInt();
connection.send(message.createReply(interface->tableInterface()->selectColumn(column)));
@@ -2764,7 +2801,17 @@ bool AtSpiAdaptor::tableCellInterface(QAccessibleInterface *interface, const QSt
return false;
}
- if (function == "GetColumnSpan"_L1) {
+ if (function == "GetColumnHeaderCells"_L1) {
+ QSpiObjectReferenceArray headerCells;
+ const auto headerCellInterfaces = cellInterface->columnHeaderCells();
+ headerCells.reserve(headerCellInterfaces.size());
+ for (QAccessibleInterface *cell : headerCellInterfaces) {
+ const QString childPath = pathForInterface(cell);
+ const QSpiObjectReference ref(connection, QDBusObjectPath(childPath));
+ headerCells << ref;
+ }
+ connection.send(message.createReply(QVariant::fromValue(headerCells)));
+ } else if (function == "GetColumnSpan"_L1) {
connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
QVariant::fromValue(cellInterface->columnExtent())))));
} else if (function == "GetPosition"_L1) {
@@ -2772,6 +2819,16 @@ bool AtSpiAdaptor::tableCellInterface(QAccessibleInterface *interface, const QSt
const int column = cellInterface->columnIndex();
connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
QVariant::fromValue(QPoint(row, column))))));
+ } else if (function == "GetRowHeaderCells"_L1) {
+ QSpiObjectReferenceArray headerCells;
+ const auto headerCellInterfaces = cellInterface->rowHeaderCells();
+ headerCells.reserve(headerCellInterfaces.size());
+ for (QAccessibleInterface *cell : headerCellInterfaces) {
+ const QString childPath = pathForInterface(cell);
+ const QSpiObjectReference ref(connection, QDBusObjectPath(childPath));
+ headerCells << ref;
+ }
+ connection.send(message.createReply(QVariant::fromValue(headerCells)));
} else if (function == "GetRowSpan"_L1) {
connection.send(message.createReply(QVariant::fromValue(QDBusVariant(
QVariant::fromValue(cellInterface->rowExtent())))));
@@ -2785,6 +2842,9 @@ bool AtSpiAdaptor::tableCellInterface(QAccessibleInterface *interface, const QSt
if (table && table->tableInterface())
ref = QSpiObjectReference(connection, QDBusObjectPath(pathForInterface(table)));
connection.send(message.createReply(QVariant::fromValue(QDBusVariant(QVariant::fromValue(ref)))));
+ } else {
+ qCWarning(lcAccessibilityAtspi) << "AtSpiAdaptor::tableCellInterface does not implement" << function << message.path();
+ return false;
}
return true;
diff --git a/src/gui/accessible/linux/dbusconnection.cpp b/src/gui/accessible/linux/dbusconnection.cpp
index 9105768fcf..10bd10927e 100644
--- a/src/gui/accessible/linux/dbusconnection.cpp
+++ b/src/gui/accessible/linux/dbusconnection.cpp
@@ -38,15 +38,8 @@ DBusConnection::DBusConnection(QObject *parent)
// If the bus is explicitly set via env var it overrides everything else.
QByteArray addressEnv = qgetenv("AT_SPI_BUS_ADDRESS");
if (!addressEnv.isEmpty()) {
- // Only connect on next loop run, connections to our enabled signal are
- // only established after the ctor returns.
- QMetaObject::invokeMethod(
- this,
- [this, addressEnv] {
- m_enabled = true;
- connectA11yBus(QString::fromLocal8Bit(addressEnv));
- },
- Qt::QueuedConnection);
+ m_enabled = true;
+ connectA11yBus(QString::fromLocal8Bit(addressEnv));
return;
}
@@ -63,11 +56,13 @@ DBusConnection::DBusConnection(QObject *parent)
if (c.interface()->isServiceRegistered(A11Y_SERVICE))
serviceRegistered();
- // In addition try if there is an xatom exposing the bus address, this allows applications run as root to work
- QString address = getAddressFromXCB();
- if (!address.isEmpty()) {
- m_enabled = true;
- connectA11yBus(address);
+ if (QGuiApplication::platformName().startsWith("xcb"_L1)) {
+ // In addition try if there is an xatom exposing the bus address, this allows applications run as root to work
+ QString address = getAddressFromXCB();
+ if (!address.isEmpty()) {
+ m_enabled = true;
+ connectA11yBus(address);
+ }
}
}
diff --git a/src/gui/accessible/linux/dbusxml/Socket.xml b/src/gui/accessible/linux/dbusxml/Socket.xml
index 75ec99f994..f9ac76d2c8 100644
--- a/src/gui/accessible/linux/dbusxml/Socket.xml
+++ b/src/gui/accessible/linux/dbusxml/Socket.xml
@@ -17,7 +17,7 @@
<signal name="Available">
<arg direction="in" name="socket" type="(so)"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QSpiObjectReference"/>
- </method>
+ </signal>
</interface>
</node>
diff --git a/src/gui/accessible/linux/qspi_constant_mappings.cpp b/src/gui/accessible/linux/qspi_constant_mappings.cpp
index 4fc7bdf83c..e5b6e3f634 100644
--- a/src/gui/accessible/linux/qspi_constant_mappings.cpp
+++ b/src/gui/accessible/linux/qspi_constant_mappings.cpp
@@ -36,6 +36,8 @@ quint64 spiStatesFromQState(QAccessible::State state)
setSpiStateBit(&spiState, ATSPI_STATE_FOCUSED);
if (state.pressed)
setSpiStateBit(&spiState, ATSPI_STATE_PRESSED);
+ if (state.checkable)
+ setSpiStateBit(&spiState, ATSPI_STATE_CHECKABLE);
if (state.checked)
setSpiStateBit(&spiState, ATSPI_STATE_CHECKED);
if (state.checkStateMixed)
@@ -75,7 +77,8 @@ quint64 spiStatesFromQState(QAccessible::State state)
if (state.extSelectable)
setSpiStateBit(&spiState, ATSPI_STATE_SELECTABLE);
// if (state.Protected)
- // if (state.HasPopup)
+ if (state.hasPopup)
+ setSpiStateBit(&spiState, ATSPI_STATE_HAS_POPUP);
if (state.modal)
setSpiStateBit(&spiState, ATSPI_STATE_MODAL);
if (state.multiLine)
diff --git a/src/gui/accessible/linux/qspiaccessiblebridge.cpp b/src/gui/accessible/linux/qspiaccessiblebridge.cpp
index 8961055f1b..de2e7d5fc0 100644
--- a/src/gui/accessible/linux/qspiaccessiblebridge.cpp
+++ b/src/gui/accessible/linux/qspiaccessiblebridge.cpp
@@ -33,6 +33,14 @@ QSpiAccessibleBridge::QSpiAccessibleBridge()
{
dbusConnection = new DBusConnection();
connect(dbusConnection, SIGNAL(enabledChanged(bool)), this, SLOT(enabledChanged(bool)));
+ // Now that we have connected the signal, make sure we didn't miss a change,
+ // e.g. when running as root or when AT_SPI_BUS_ADDRESS is set by hand.
+ // But do that only on next loop, once dbus is really settled.
+ QTimer::singleShot(
+ 0, this, [this]{
+ if (dbusConnection->isEnabled() && dbusConnection->connection().isConnected())
+ enabledChanged(true);
+ });
}
void QSpiAccessibleBridge::enabledChanged(bool enabled)
@@ -197,7 +205,11 @@ static RoleMapping map[] = {
//: Role of an accessible object
{ QAccessible::ButtonDropDown, ATSPI_ROLE_PUSH_BUTTON, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "button with drop down") },
//: Role of an accessible object
+#if ATSPI_ROLE_COUNT > 130
+ { QAccessible::ButtonMenu, ATSPI_ROLE_PUSH_BUTTON_MENU, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "button menu") },
+#else
{ QAccessible::ButtonMenu, ATSPI_ROLE_PUSH_BUTTON, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "button menu") },
+#endif
//: Role of an accessible object - a button that expands a grid.
{ QAccessible::ButtonDropGrid, ATSPI_ROLE_PUSH_BUTTON, QT_TRANSLATE_NOOP("QSpiAccessibleBridge", "button with drop down grid") },
//: Role of an accessible object - blank space between other objects.
diff --git a/src/gui/accessible/linux/qspiapplicationadaptor.cpp b/src/gui/accessible/linux/qspiapplicationadaptor.cpp
index 963490d056..37d7648984 100644
--- a/src/gui/accessible/linux/qspiapplicationadaptor.cpp
+++ b/src/gui/accessible/linux/qspiapplicationadaptor.cpp
@@ -12,12 +12,16 @@
#include "deviceeventcontroller_adaptor.h"
#include "atspi/atspi-constants.h"
+#if __has_include(<xcb/xproto.h>)
#include <xcb/xproto.h>
+#endif
//#define KEYBOARD_DEBUG
QT_BEGIN_NAMESPACE
+using namespace Qt::Literals::StringLiterals;
+
/*!
\class QSpiApplicationAdaptor
\internal
@@ -125,9 +129,13 @@ bool QSpiApplicationAdaptor::eventFilter(QObject *target, QEvent *event)
de.modifiers = 0;
if ((keyEvent->modifiers() & Qt::ShiftModifier) && (keyEvent->key() != Qt::Key_Shift))
de.modifiers |= 1 << ATSPI_MODIFIER_SHIFT;
- // TODO rather introduce Qt::CapslockModifier into KeyboardModifier
- if (keyEvent->nativeModifiers() & XCB_MOD_MASK_LOCK )
- de.modifiers |= 1 << ATSPI_MODIFIER_SHIFTLOCK;
+#ifdef XCB_MOD_MASK_LOCK
+ if (QGuiApplication::platformName().startsWith("xcb"_L1)) {
+ // TODO rather introduce Qt::CapslockModifier into KeyboardModifier
+ if (keyEvent->nativeModifiers() & XCB_MOD_MASK_LOCK )
+ de.modifiers |= 1 << ATSPI_MODIFIER_SHIFTLOCK;
+ }
+#endif
if ((keyEvent->modifiers() & Qt::ControlModifier) && (keyEvent->key() != Qt::Key_Control))
de.modifiers |= 1 << ATSPI_MODIFIER_CONTROL;
if ((keyEvent->modifiers() & Qt::AltModifier) && (keyEvent->key() != Qt::Key_Alt))
diff --git a/src/gui/accessible/qaccessible.cpp b/src/gui/accessible/qaccessible.cpp
index b382f20037..46bca16dad 100644
--- a/src/gui/accessible/qaccessible.cpp
+++ b/src/gui/accessible/qaccessible.cpp
@@ -412,6 +412,43 @@ Q_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core");
\sa QAccessibleTextInterface
*/
+/*! \enum QAccessible::Attribute
+ This enum describes different types of attributes used by the
+ \l QAccessibleAttributesInterface.
+ \since 6.8
+
+ These attributes are comparable to the concept of properties/(object)
+ attributes found in ARIA, AT-SPI2, IAccessible, UIA and NSAccessibility
+ and are mapped to their platform counterpart where applicable.
+
+ Each attribute is handled as a key-value pair, with the values of this
+ enumeration being used as keys.
+
+ Attribute values are represented in a \l QVariant. The type of the value
+ stored in the \l QVariant is fixed and specified below for each of the
+ attribute types.
+
+ \value Custom value type: \a QHash<QString, QString>
+ The \a Custom attribute is special in that
+ it can effectively represent multiple attributes at
+ once, since it itself is a \l QHash used to represent
+ key-value pairs.
+ For platforms supporting custom key-value pairs for
+ attributes, those set in the \a Custom attribute
+ are bridged to the platform layer without applying any
+ translation to platform-specific attributes. In general,
+ the other, more strongly typed attributes should be used.
+ This attribute can e.g. be used for prototyping
+ before officially adding an official new enumeration value
+ for a specific feature.
+ \value Level value type: \a int
+ Defines the hierarchical level of an element within a structure,
+ e.g. the heading level of a heading. This attribute conceptually
+ matches the "aria-level" property in ARIA.
+
+ \sa QAccessibleAttributesInterface
+*/
+
/*!
\enum QAccessible::InterfaceType
@@ -431,8 +468,9 @@ Q_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core");
\value TableCellInterface For cells in a TableInterface object.
\value HyperlinkInterface For hyperlink nodes (usually embedded as children of text nodes)
\value [since 6.5] SelectionInterface For non-text objects that support selection of child objects.
+ \value [since 6.8] AttributesInterface For objects that support object-specific attributes.
- \sa QAccessibleInterface::interface_cast(), QAccessibleTextInterface, QAccessibleValueInterface, QAccessibleActionInterface, QAccessibleTableInterface, QAccessibleTableCellInterface, QAccessibleSelectionInterface
+ \sa QAccessibleInterface::interface_cast(), QAccessibleTextInterface, QAccessibleValueInterface, QAccessibleActionInterface, QAccessibleTableInterface, QAccessibleTableCellInterface, QAccessibleSelectionInterface, QAccessibleAttributesInterface
*/
#if QT_CONFIG(accessibility)
@@ -866,11 +904,11 @@ void QAccessible::updateAccessibility(QAccessibleEvent *event)
if (iface->tableInterface())
iface->tableInterface()->modelChange(static_cast<QAccessibleTableModelChangeEvent*>(event));
}
+ }
- if (updateHandler) {
- updateHandler(event);
- return;
- }
+ if (updateHandler) {
+ updateHandler(event);
+ return;
}
if (QPlatformAccessibility *pfAccessibility = platformAccessibility())
@@ -1655,8 +1693,8 @@ QAccessibleTextRemoveEvent::~QAccessibleTextRemoveEvent()
/*!
\fn QAccessibleTextInsertEvent::QAccessibleTextInsertEvent(QAccessibleInterface *iface, int position, const QString &text)
- Constructs a new QAccessibleTextInsertEvent event for \a iface. The text has been inserted at
- \a position.
+ Constructs a new QAccessibleTextInsertEvent event for \a iface. The \a text has been inserted
+ at \a position.
*/
/*!
@@ -2968,7 +3006,6 @@ QString QAccessibleActionInterface::nextPageAction()
\class QAccessibleSelectionInterface
\inmodule QtGui
\ingroup accessibility
- \preliminary
\brief The QAccessibleSelectionInterface class implements support for
selection handling.
@@ -3070,6 +3107,54 @@ bool QAccessibleSelectionInterface::isSelected(QAccessibleInterface *childItem)
*/
+/*!
+ \since 6.8
+ \class QAccessibleAttributesInterface
+ \inmodule QtGui
+ \ingroup accessibility
+
+ \brief The QAccessibleAttributesInterface class implements support for
+ reporting attributes for an accessible object.
+
+ Attributes are key-value pairs. Values are stored in \l QVariant.
+
+ The \a QAccessible::Attributes enumeration describes the available keys and
+ documents which type to use for the value of each key.
+
+ While the text-specific attributes handled by \l QAccessibleTextInterface::attributes
+ are specific to objects implementing text and are specific to a specific text
+ position/offset, the attributes handled by the \l QAccessibleAttributesInterface
+ can be used for objects of any role and apply for the whole object.
+
+ Classes already implementing \l QAccessibleTextInterface for text-specific attrtibutes
+ may want to implement \l QAccessibleAttributesInterface in addition for object-specific
+ attributes.
+*/
+
+/*!
+
+ Destroys the QAccessibleAttributesInterface.
+*/
+QAccessibleAttributesInterface::~QAccessibleAttributesInterface()
+{
+}
+
+/*!
+ \fn QList<QAccessible::Attribute> QAccessibleAttributesInterface::attributeKeys() const
+
+ Returns the keys of all attributes the object supports. The \l QAccessible::Attribute
+ enumeration describes available keys.
+*/
+
+/*!
+ \fn QVariant QAccessibleAttributesInterface::attributeValue(QAccessible::Attribute key) const
+
+ Returns the value of the attribute \a key of this object.
+
+ If the specificed attribute is not set for this object, an invalid
+ \l QVariant is returned.
+*/
+
/*! \internal */
QString qAccessibleLocalizedActionDescription(const QString &actionName)
{
diff --git a/src/gui/accessible/qaccessible.h b/src/gui/accessible/qaccessible.h
index 3fdc4eb7d9..0a92e76c73 100644
--- a/src/gui/accessible/qaccessible.h
+++ b/src/gui/accessible/qaccessible.h
@@ -43,6 +43,7 @@ class QAccessibleTableInterface;
class QAccessibleTableCellInterface;
class QAccessibleHyperlinkInterface;
class QAccessibleSelectionInterface;
+class QAccessibleAttributesInterface;
class QAccessibleTableModelChangeEvent;
class Q_GUI_EXPORT QAccessibleInterface
@@ -106,6 +107,9 @@ public:
inline QAccessibleSelectionInterface *selectionInterface()
{ return reinterpret_cast<QAccessibleSelectionInterface *>(interface_cast(QAccessible::SelectionInterface)); }
+ inline QAccessibleAttributesInterface *attributesInterface()
+ { return reinterpret_cast<QAccessibleAttributesInterface *>(interface_cast(QAccessible::AttributesInterface)); }
+
virtual void virtual_hook(int id, void *data);
virtual void *interface_cast(QAccessible::InterfaceType)
@@ -284,6 +288,15 @@ public:
virtual bool clear() = 0;
};
+class Q_GUI_EXPORT QAccessibleAttributesInterface
+{
+public:
+ virtual ~QAccessibleAttributesInterface();
+ virtual QList<QAccessible::Attribute> attributeKeys() const = 0;
+ virtual QVariant attributeValue(QAccessible::Attribute key) const = 0;
+};
+
+
class Q_GUI_EXPORT QAccessibleEvent
{
Q_DISABLE_COPY(QAccessibleEvent)
diff --git a/src/gui/accessible/qaccessible_base.h b/src/gui/accessible/qaccessible_base.h
index 74926a3565..2d2b1de316 100644
--- a/src/gui/accessible/qaccessible_base.h
+++ b/src/gui/accessible/qaccessible_base.h
@@ -349,7 +349,8 @@ public:
TableInterface,
TableCellInterface,
HyperlinkInterface,
- SelectionInterface
+ SelectionInterface,
+ AttributesInterface,
};
enum TextBoundaryType {
@@ -361,6 +362,11 @@ public:
NoBoundary
};
+ enum class Attribute {
+ Custom,
+ Level,
+ };
+
typedef QAccessibleInterface*(*InterfaceFactory)(const QString &key, QObject*);
typedef void(*UpdateHandler)(QAccessibleEvent *event);
typedef void(*RootObjectHandler)(QObject*);
diff --git a/src/gui/accessible/windows/apisupport/qwindowsuiawrapper.cpp b/src/gui/accessible/windows/apisupport/qwindowsuiawrapper.cpp
deleted file mode 100644
index d9ff723a61..0000000000
--- a/src/gui/accessible/windows/apisupport/qwindowsuiawrapper.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include <initguid.h>
-
-#include "qwindowsuiawrapper_p.h"
-#include <QtCore/private/qsystemlibrary_p.h>
-
-QT_BEGIN_NAMESPACE
-
-// private constructor
-QWindowsUiaWrapper::QWindowsUiaWrapper()
-{
- QSystemLibrary uiaLib(QStringLiteral("UIAutomationCore"));
- if (uiaLib.load()) {
- m_pUiaReturnRawElementProvider = reinterpret_cast<PtrUiaReturnRawElementProvider>(uiaLib.resolve("UiaReturnRawElementProvider"));
- m_pUiaHostProviderFromHwnd = reinterpret_cast<PtrUiaHostProviderFromHwnd>(uiaLib.resolve("UiaHostProviderFromHwnd"));
- m_pUiaRaiseAutomationPropertyChangedEvent = reinterpret_cast<PtrUiaRaiseAutomationPropertyChangedEvent>(uiaLib.resolve("UiaRaiseAutomationPropertyChangedEvent"));
- m_pUiaRaiseAutomationEvent = reinterpret_cast<PtrUiaRaiseAutomationEvent>(uiaLib.resolve("UiaRaiseAutomationEvent"));
- m_pUiaRaiseNotificationEvent = reinterpret_cast<PtrUiaRaiseNotificationEvent>(uiaLib.resolve("UiaRaiseNotificationEvent"));
- m_pUiaClientsAreListening = reinterpret_cast<PtrUiaClientsAreListening>(uiaLib.resolve("UiaClientsAreListening"));
- }
-}
-
-QWindowsUiaWrapper::~QWindowsUiaWrapper()
-{
-}
-
-// shared instance
-QWindowsUiaWrapper *QWindowsUiaWrapper::instance()
-{
- static QWindowsUiaWrapper wrapper;
- return &wrapper;
-}
-
-// True if most symbols resolved (UiaRaiseNotificationEvent is optional).
-BOOL QWindowsUiaWrapper::ready()
-{
- return m_pUiaReturnRawElementProvider
- && m_pUiaHostProviderFromHwnd
- && m_pUiaRaiseAutomationPropertyChangedEvent
- && m_pUiaRaiseAutomationEvent
- && m_pUiaClientsAreListening;
-}
-
-BOOL QWindowsUiaWrapper::clientsAreListening()
-{
- if (!m_pUiaClientsAreListening)
- return FALSE;
- return m_pUiaClientsAreListening();
-}
-
-LRESULT QWindowsUiaWrapper::returnRawElementProvider(HWND hwnd, WPARAM wParam, LPARAM lParam, IRawElementProviderSimple *el)
-{
- if (!m_pUiaReturnRawElementProvider)
- return static_cast<LRESULT>(NULL);
- return m_pUiaReturnRawElementProvider(hwnd, wParam, lParam, el);
-}
-
-HRESULT QWindowsUiaWrapper::hostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **ppProvider)
-{
- if (!m_pUiaHostProviderFromHwnd)
- return UIA_E_NOTSUPPORTED;
- return m_pUiaHostProviderFromHwnd(hwnd, ppProvider);
-}
-
-HRESULT QWindowsUiaWrapper::raiseAutomationPropertyChangedEvent(IRawElementProviderSimple *pProvider, PROPERTYID id, VARIANT oldValue, VARIANT newValue)
-{
- if (!m_pUiaRaiseAutomationPropertyChangedEvent)
- return UIA_E_NOTSUPPORTED;
- return m_pUiaRaiseAutomationPropertyChangedEvent(pProvider, id, oldValue, newValue);
-}
-
-HRESULT QWindowsUiaWrapper::raiseAutomationEvent(IRawElementProviderSimple *pProvider, EVENTID id)
-{
- if (!m_pUiaRaiseAutomationEvent)
- return UIA_E_NOTSUPPORTED;
- return m_pUiaRaiseAutomationEvent(pProvider, id);
-}
-
-HRESULT QWindowsUiaWrapper::raiseNotificationEvent(IRawElementProviderSimple *provider, NotificationKind notificationKind, NotificationProcessing notificationProcessing, BSTR displayString, BSTR activityId)
-{
- if (!m_pUiaRaiseNotificationEvent)
- return UIA_E_NOTSUPPORTED;
- return m_pUiaRaiseNotificationEvent(provider, notificationKind, notificationProcessing, displayString, activityId);
-}
-
-QT_END_NAMESPACE
-
diff --git a/src/gui/accessible/windows/apisupport/qwindowsuiawrapper_p.h b/src/gui/accessible/windows/apisupport/qwindowsuiawrapper_p.h
deleted file mode 100644
index 05b93f8393..0000000000
--- a/src/gui/accessible/windows/apisupport/qwindowsuiawrapper_p.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QWINDOWSUIAWRAPPER_H
-#define QWINDOWSUIAWRAPPER_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of other Qt classes. 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 "uiatypes_p.h"
-#include "uiaattributeids_p.h"
-#include "uiacontroltypeids_p.h"
-#include "uiaerrorids_p.h"
-#include "uiaeventids_p.h"
-#include "uiageneralids_p.h"
-#include "uiapatternids_p.h"
-#include "uiapropertyids_p.h"
-#include "uiaserverinterfaces_p.h"
-#include "uiaclientinterfaces_p.h"
-
-QT_REQUIRE_CONFIG(accessibility);
-
-QT_BEGIN_NAMESPACE
-
-class Q_GUI_EXPORT QWindowsUiaWrapper
-{
- QWindowsUiaWrapper();
- virtual ~QWindowsUiaWrapper();
-public:
- static QWindowsUiaWrapper *instance();
- BOOL ready();
- BOOL clientsAreListening();
- LRESULT returnRawElementProvider(HWND hwnd, WPARAM wParam, LPARAM lParam, IRawElementProviderSimple *el);
- HRESULT hostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **ppProvider);
- HRESULT raiseAutomationPropertyChangedEvent(IRawElementProviderSimple *pProvider, PROPERTYID id, VARIANT oldValue, VARIANT newValue);
- HRESULT raiseAutomationEvent(IRawElementProviderSimple *pProvider, EVENTID id);
- HRESULT raiseNotificationEvent(IRawElementProviderSimple *provider, NotificationKind notificationKind, NotificationProcessing notificationProcessing, BSTR displayString, BSTR activityId);
-
-private:
- typedef LRESULT (WINAPI *PtrUiaReturnRawElementProvider)(HWND, WPARAM, LPARAM, IRawElementProviderSimple *);
- typedef HRESULT (WINAPI *PtrUiaHostProviderFromHwnd)(HWND, IRawElementProviderSimple **);
- typedef HRESULT (WINAPI *PtrUiaRaiseAutomationPropertyChangedEvent)(IRawElementProviderSimple *, PROPERTYID, VARIANT, VARIANT);
- typedef HRESULT (WINAPI *PtrUiaRaiseAutomationEvent)(IRawElementProviderSimple *, EVENTID);
- typedef HRESULT (WINAPI *PtrUiaRaiseNotificationEvent)(IRawElementProviderSimple *, NotificationKind, NotificationProcessing, BSTR, BSTR);
- typedef BOOL (WINAPI *PtrUiaClientsAreListening)();
- PtrUiaReturnRawElementProvider m_pUiaReturnRawElementProvider = nullptr;
- PtrUiaHostProviderFromHwnd m_pUiaHostProviderFromHwnd = nullptr;
- PtrUiaRaiseAutomationPropertyChangedEvent m_pUiaRaiseAutomationPropertyChangedEvent = nullptr;
- PtrUiaRaiseAutomationEvent m_pUiaRaiseAutomationEvent = nullptr;
- PtrUiaRaiseNotificationEvent m_pUiaRaiseNotificationEvent = nullptr;
- PtrUiaClientsAreListening m_pUiaClientsAreListening = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif //QWINDOWSUIAWRAPPER_H
-
diff --git a/src/gui/accessible/windows/apisupport/uiaattributeids_p.h b/src/gui/accessible/windows/apisupport/uiaattributeids_p.h
deleted file mode 100644
index 2078351a98..0000000000
--- a/src/gui/accessible/windows/apisupport/uiaattributeids_p.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef UIAATTRIBUTEIDS_H
-#define UIAATTRIBUTEIDS_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.
-//
-
-#define UIA_AnimationStyleAttributeId 40000
-#define UIA_BackgroundColorAttributeId 40001
-#define UIA_BulletStyleAttributeId 40002
-#define UIA_CapStyleAttributeId 40003
-#define UIA_CultureAttributeId 40004
-#define UIA_FontNameAttributeId 40005
-#define UIA_FontSizeAttributeId 40006
-#define UIA_FontWeightAttributeId 40007
-#define UIA_ForegroundColorAttributeId 40008
-#define UIA_HorizontalTextAlignmentAttributeId 40009
-#define UIA_IndentationFirstLineAttributeId 40010
-#define UIA_IndentationLeadingAttributeId 40011
-#define UIA_IndentationTrailingAttributeId 40012
-#define UIA_IsHiddenAttributeId 40013
-#define UIA_IsItalicAttributeId 40014
-#define UIA_IsReadOnlyAttributeId 40015
-#define UIA_IsSubscriptAttributeId 40016
-#define UIA_IsSuperscriptAttributeId 40017
-#define UIA_MarginBottomAttributeId 40018
-#define UIA_MarginLeadingAttributeId 40019
-#define UIA_MarginTopAttributeId 40020
-#define UIA_MarginTrailingAttributeId 40021
-#define UIA_OutlineStylesAttributeId 40022
-#define UIA_OverlineColorAttributeId 40023
-#define UIA_OverlineStyleAttributeId 40024
-#define UIA_StrikethroughColorAttributeId 40025
-#define UIA_StrikethroughStyleAttributeId 40026
-#define UIA_TabsAttributeId 40027
-#define UIA_TextFlowDirectionsAttributeId 40028
-#define UIA_UnderlineColorAttributeId 40029
-#define UIA_UnderlineStyleAttributeId 40030
-#define UIA_AnnotationTypesAttributeId 40031
-#define UIA_AnnotationObjectsAttributeId 40032
-#define UIA_StyleNameAttributeId 40033
-#define UIA_StyleIdAttributeId 40034
-#define UIA_LinkAttributeId 40035
-#define UIA_IsActiveAttributeId 40036
-#define UIA_SelectionActiveEndAttributeId 40037
-#define UIA_CaretPositionAttributeId 40038
-#define UIA_CaretBidiModeAttributeId 40039
-#define UIA_LineSpacingAttributeId 40040
-#define UIA_BeforeParagraphSpacingAttributeId 40041
-#define UIA_AfterParagraphSpacingAttributeId 40042
-#define UIA_SayAsInterpretAsAttributeId 40043
-
-#endif
diff --git a/src/gui/accessible/windows/apisupport/uiaclientinterfaces_p.h b/src/gui/accessible/windows/apisupport/uiaclientinterfaces_p.h
deleted file mode 100644
index fb74042bfa..0000000000
--- a/src/gui/accessible/windows/apisupport/uiaclientinterfaces_p.h
+++ /dev/null
@@ -1,230 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef UIACLIENTINTERFACES_H
-#define UIACLIENTINTERFACES_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 <unknwn.h>
-
-#ifndef __IUIAutomationElement_INTERFACE_DEFINED__
-
-struct IUIAutomationCondition;
-struct IUIAutomationCacheRequest;
-struct IUIAutomationElementArray;
-struct IUIAutomationTreeWalker;
-struct IUIAutomationEventHandler;
-struct IUIAutomationPropertyChangedEventHandler;
-struct IUIAutomationStructureChangedEventHandler;
-struct IUIAutomationFocusChangedEventHandler;
-struct IUIAutomationProxyFactory;
-struct IUIAutomationProxyFactoryEntry;
-struct IUIAutomationProxyFactoryMapping;
-#ifndef __IAccessible_FWD_DEFINED__
-#define __IAccessible_FWD_DEFINED__
-struct IAccessible;
-#endif /* __IAccessible_FWD_DEFINED__ */
-
-#define __IUIAutomationElement_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IUIAutomationElement, 0xd22108aa, 0x8ac5, 0x49a5, 0x83,0x7b, 0x37,0xbb,0xb3,0xd7,0x59,0x1e);
-MIDL_INTERFACE("d22108aa-8ac5-49a5-837b-37bbb3d7591e")
-IUIAutomationElement : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE SetFocus() = 0;
- virtual HRESULT STDMETHODCALLTYPE GetRuntimeId(__RPC__deref_out_opt SAFEARRAY **runtimeId) = 0;
- virtual HRESULT STDMETHODCALLTYPE FindFirst(enum TreeScope scope, __RPC__in_opt IUIAutomationCondition *condition, __RPC__deref_out_opt IUIAutomationElement **found) = 0;
- virtual HRESULT STDMETHODCALLTYPE FindAll(enum TreeScope scope, __RPC__in_opt IUIAutomationCondition *condition, __RPC__deref_out_opt IUIAutomationElementArray **found) = 0;
- virtual HRESULT STDMETHODCALLTYPE FindFirstBuildCache(enum TreeScope scope, __RPC__in_opt IUIAutomationCondition *condition, __RPC__in_opt IUIAutomationCacheRequest *cacheRequest, __RPC__deref_out_opt IUIAutomationElement **found) = 0;
- virtual HRESULT STDMETHODCALLTYPE FindAllBuildCache(enum TreeScope scope, __RPC__in_opt IUIAutomationCondition *condition, __RPC__in_opt IUIAutomationCacheRequest *cacheRequest, __RPC__deref_out_opt IUIAutomationElementArray **found) = 0;
- virtual HRESULT STDMETHODCALLTYPE BuildUpdatedCache(__RPC__in_opt IUIAutomationCacheRequest *cacheRequest, __RPC__deref_out_opt IUIAutomationElement **updatedElement) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetCurrentPropertyValue(PROPERTYID propertyId, __RPC__out VARIANT *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetCurrentPropertyValueEx(PROPERTYID propertyId, BOOL ignoreDefaultValue, __RPC__out VARIANT *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetCachedPropertyValue(PROPERTYID propertyId, __RPC__out VARIANT *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetCachedPropertyValueEx(PROPERTYID propertyId, BOOL ignoreDefaultValue, __RPC__out VARIANT *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetCurrentPatternAs(PATTERNID patternId, __RPC__in REFIID riid, __RPC__deref_out_opt void **patternObject) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetCachedPatternAs(PATTERNID patternId, __RPC__in REFIID riid, __RPC__deref_out_opt void **patternObject) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetCurrentPattern(PATTERNID patternId, __RPC__deref_out_opt IUnknown **patternObject) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetCachedPattern(PATTERNID patternId, __RPC__deref_out_opt IUnknown **patternObject) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetCachedParent(__RPC__deref_out_opt IUIAutomationElement **parent) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetCachedChildren(__RPC__deref_out_opt IUIAutomationElementArray **children) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentProcessId(__RPC__out int *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentControlType(__RPC__out CONTROLTYPEID *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentLocalizedControlType(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentName(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentAcceleratorKey(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentAccessKey(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentHasKeyboardFocus(__RPC__out BOOL *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentIsKeyboardFocusable(__RPC__out BOOL *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentIsEnabled(__RPC__out BOOL *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentAutomationId(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentClassName(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentHelpText(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentCulture(__RPC__out int *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentIsControlElement(__RPC__out BOOL *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentIsContentElement(__RPC__out BOOL *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentIsPassword(__RPC__out BOOL *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentNativeWindowHandle(__RPC__deref_out_opt UIA_HWND *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentItemType(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentIsOffscreen(__RPC__out BOOL *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentOrientation(__RPC__out enum OrientationType *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentFrameworkId(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentIsRequiredForForm(__RPC__out BOOL *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentItemStatus(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentBoundingRectangle(__RPC__out RECT *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentLabeledBy(__RPC__deref_out_opt IUIAutomationElement **retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentAriaRole(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentAriaProperties(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentIsDataValidForForm(__RPC__out BOOL *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentControllerFor(__RPC__deref_out_opt IUIAutomationElementArray **retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentDescribedBy(__RPC__deref_out_opt IUIAutomationElementArray **retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentFlowsTo(__RPC__deref_out_opt IUIAutomationElementArray **retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CurrentProviderDescription(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedProcessId(__RPC__out int *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedControlType(__RPC__out CONTROLTYPEID *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedLocalizedControlType(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedName(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedAcceleratorKey(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedAccessKey(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedHasKeyboardFocus(__RPC__out BOOL *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedIsKeyboardFocusable(__RPC__out BOOL *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedIsEnabled(__RPC__out BOOL *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedAutomationId(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedClassName(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedHelpText(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedCulture(__RPC__out int *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedIsControlElement(__RPC__out BOOL *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedIsContentElement(__RPC__out BOOL *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedIsPassword(__RPC__out BOOL *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedNativeWindowHandle(__RPC__deref_out_opt UIA_HWND *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedItemType(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedIsOffscreen(__RPC__out BOOL *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedOrientation(__RPC__out enum OrientationType *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedFrameworkId(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedIsRequiredForForm(__RPC__out BOOL *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedItemStatus(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedBoundingRectangle(__RPC__out RECT *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedLabeledBy(__RPC__deref_out_opt IUIAutomationElement **retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedAriaRole(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedAriaProperties(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedIsDataValidForForm(__RPC__out BOOL *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedControllerFor(__RPC__deref_out_opt IUIAutomationElementArray **retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedDescribedBy(__RPC__deref_out_opt IUIAutomationElementArray **retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedFlowsTo(__RPC__deref_out_opt IUIAutomationElementArray **retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CachedProviderDescription(__RPC__deref_out_opt BSTR *retVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetClickablePoint(__RPC__out POINT *clickable, __RPC__out BOOL *gotClickable) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IUIAutomationElement, 0xd22108aa, 0x8ac5, 0x49a5, 0x83,0x7b, 0x37,0xbb,0xb3,0xd7,0x59,0x1e)
-#endif
-#endif
-
-
-#ifndef __IUIAutomation_INTERFACE_DEFINED__
-#define __IUIAutomation_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IUIAutomation, 0x30cbe57d, 0xd9d0, 0x452a, 0xab,0x13, 0x7a,0xc5,0xac,0x48,0x25,0xee);
-MIDL_INTERFACE("30cbe57d-d9d0-452a-ab13-7ac5ac4825ee")
-IUIAutomation : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE CompareElements(__RPC__in_opt IUIAutomationElement *el1, __RPC__in_opt IUIAutomationElement *el2, __RPC__out BOOL *areSame) = 0;
- virtual HRESULT STDMETHODCALLTYPE CompareRuntimeIds(__RPC__in SAFEARRAY * runtimeId1, __RPC__in SAFEARRAY * runtimeId2, __RPC__out BOOL *areSame) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetRootElement(__RPC__deref_out_opt IUIAutomationElement **root) = 0;
- virtual HRESULT STDMETHODCALLTYPE ElementFromHandle(__RPC__in UIA_HWND hwnd, __RPC__deref_out_opt IUIAutomationElement **element) = 0;
- virtual HRESULT STDMETHODCALLTYPE ElementFromPoint(POINT pt, __RPC__deref_out_opt IUIAutomationElement **element) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetFocusedElement(__RPC__deref_out_opt IUIAutomationElement **element) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetRootElementBuildCache(__RPC__in_opt IUIAutomationCacheRequest *cacheRequest, __RPC__deref_out_opt IUIAutomationElement **root) = 0;
- virtual HRESULT STDMETHODCALLTYPE ElementFromHandleBuildCache(__RPC__in UIA_HWND hwnd, __RPC__in_opt IUIAutomationCacheRequest *cacheRequest, __RPC__deref_out_opt IUIAutomationElement **element) = 0;
- virtual HRESULT STDMETHODCALLTYPE ElementFromPointBuildCache(POINT pt, __RPC__in_opt IUIAutomationCacheRequest *cacheRequest, __RPC__deref_out_opt IUIAutomationElement **element) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetFocusedElementBuildCache(__RPC__in_opt IUIAutomationCacheRequest *cacheRequest, __RPC__deref_out_opt IUIAutomationElement **element) = 0;
- virtual HRESULT STDMETHODCALLTYPE CreateTreeWalker(__RPC__in_opt IUIAutomationCondition *pCondition, __RPC__deref_out_opt IUIAutomationTreeWalker **walker) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_ControlViewWalker(__RPC__deref_out_opt IUIAutomationTreeWalker **walker) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_ContentViewWalker(__RPC__deref_out_opt IUIAutomationTreeWalker **walker) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_RawViewWalker(__RPC__deref_out_opt IUIAutomationTreeWalker **walker) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_RawViewCondition(__RPC__deref_out_opt IUIAutomationCondition **condition) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_ControlViewCondition(__RPC__deref_out_opt IUIAutomationCondition **condition) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_ContentViewCondition(__RPC__deref_out_opt IUIAutomationCondition **condition) = 0;
- virtual HRESULT STDMETHODCALLTYPE CreateCacheRequest(__RPC__deref_out_opt IUIAutomationCacheRequest **cacheRequest) = 0;
- virtual HRESULT STDMETHODCALLTYPE CreateTrueCondition(__RPC__deref_out_opt IUIAutomationCondition **newCondition) = 0;
- virtual HRESULT STDMETHODCALLTYPE CreateFalseCondition(__RPC__deref_out_opt IUIAutomationCondition **newCondition) = 0;
- virtual HRESULT STDMETHODCALLTYPE CreatePropertyCondition(PROPERTYID propertyId, VARIANT value, __RPC__deref_out_opt IUIAutomationCondition **newCondition) = 0;
- virtual HRESULT STDMETHODCALLTYPE CreatePropertyConditionEx(PROPERTYID propertyId, VARIANT value, enum PropertyConditionFlags flags, __RPC__deref_out_opt IUIAutomationCondition **newCondition) = 0;
- virtual HRESULT STDMETHODCALLTYPE CreateAndCondition(__RPC__in_opt IUIAutomationCondition *condition1, __RPC__in_opt IUIAutomationCondition *condition2, __RPC__deref_out_opt IUIAutomationCondition **newCondition) = 0;
- virtual HRESULT STDMETHODCALLTYPE CreateAndConditionFromArray(__RPC__in_opt SAFEARRAY * conditions, __RPC__deref_out_opt IUIAutomationCondition **newCondition) = 0;
- virtual HRESULT STDMETHODCALLTYPE CreateAndConditionFromNativeArray(__RPC__in_ecount_full(conditionCount) IUIAutomationCondition **conditions, int conditionCount, __RPC__deref_out_opt IUIAutomationCondition **newCondition) = 0;
- virtual HRESULT STDMETHODCALLTYPE CreateOrCondition(__RPC__in_opt IUIAutomationCondition *condition1, __RPC__in_opt IUIAutomationCondition *condition2, __RPC__deref_out_opt IUIAutomationCondition **newCondition) = 0;
- virtual HRESULT STDMETHODCALLTYPE CreateOrConditionFromArray(__RPC__in_opt SAFEARRAY * conditions, __RPC__deref_out_opt IUIAutomationCondition **newCondition) = 0;
- virtual HRESULT STDMETHODCALLTYPE CreateOrConditionFromNativeArray(__RPC__in_ecount_full(conditionCount) IUIAutomationCondition **conditions, int conditionCount, __RPC__deref_out_opt IUIAutomationCondition **newCondition) = 0;
- virtual HRESULT STDMETHODCALLTYPE CreateNotCondition(__RPC__in_opt IUIAutomationCondition *condition, __RPC__deref_out_opt IUIAutomationCondition **newCondition) = 0;
- virtual HRESULT STDMETHODCALLTYPE AddAutomationEventHandler(EVENTID eventId, __RPC__in_opt IUIAutomationElement *element, enum TreeScope scope, __RPC__in_opt IUIAutomationCacheRequest *cacheRequest, __RPC__in_opt IUIAutomationEventHandler *handler) = 0;
- virtual HRESULT STDMETHODCALLTYPE RemoveAutomationEventHandler(EVENTID eventId, __RPC__in_opt IUIAutomationElement *element, __RPC__in_opt IUIAutomationEventHandler *handler) = 0;
- virtual HRESULT STDMETHODCALLTYPE AddPropertyChangedEventHandlerNativeArray(__RPC__in_opt IUIAutomationElement *element, enum TreeScope scope, __RPC__in_opt IUIAutomationCacheRequest *cacheRequest, __RPC__in_opt IUIAutomationPropertyChangedEventHandler *handler, __RPC__in_ecount_full(propertyCount) PROPERTYID *propertyArray, int propertyCount) = 0;
- virtual HRESULT STDMETHODCALLTYPE AddPropertyChangedEventHandler(__RPC__in_opt IUIAutomationElement *element, enum TreeScope scope, __RPC__in_opt IUIAutomationCacheRequest *cacheRequest, __RPC__in_opt IUIAutomationPropertyChangedEventHandler *handler, __RPC__in SAFEARRAY * propertyArray) = 0;
- virtual HRESULT STDMETHODCALLTYPE RemovePropertyChangedEventHandler(__RPC__in_opt IUIAutomationElement *element, __RPC__in_opt IUIAutomationPropertyChangedEventHandler *handler) = 0;
- virtual HRESULT STDMETHODCALLTYPE AddStructureChangedEventHandler(__RPC__in_opt IUIAutomationElement *element, enum TreeScope scope, __RPC__in_opt IUIAutomationCacheRequest *cacheRequest, __RPC__in_opt IUIAutomationStructureChangedEventHandler *handler) = 0;
- virtual HRESULT STDMETHODCALLTYPE RemoveStructureChangedEventHandler(__RPC__in_opt IUIAutomationElement *element, __RPC__in_opt IUIAutomationStructureChangedEventHandler *handler) = 0;
- virtual HRESULT STDMETHODCALLTYPE AddFocusChangedEventHandler(__RPC__in_opt IUIAutomationCacheRequest *cacheRequest, __RPC__in_opt IUIAutomationFocusChangedEventHandler *handler) = 0;
- virtual HRESULT STDMETHODCALLTYPE RemoveFocusChangedEventHandler(__RPC__in_opt IUIAutomationFocusChangedEventHandler *handler) = 0;
- virtual HRESULT STDMETHODCALLTYPE RemoveAllEventHandlers() = 0;
- virtual HRESULT STDMETHODCALLTYPE IntNativeArrayToSafeArray(__RPC__in_ecount_full(arrayCount) int *array, int arrayCount, __RPC__deref_out_opt SAFEARRAY **safeArray) = 0;
- virtual HRESULT STDMETHODCALLTYPE IntSafeArrayToNativeArray(__RPC__in SAFEARRAY * intArray, __RPC__deref_out_ecount_full_opt(*arrayCount) int **array, __RPC__out int *arrayCount) = 0;
- virtual HRESULT STDMETHODCALLTYPE RectToVariant(RECT rc, __RPC__out VARIANT *var) = 0;
- virtual HRESULT STDMETHODCALLTYPE VariantToRect(VARIANT var, __RPC__out RECT *rc) = 0;
- virtual HRESULT STDMETHODCALLTYPE SafeArrayToRectNativeArray(__RPC__in SAFEARRAY * rects, __RPC__deref_out_ecount_full_opt(*rectArrayCount) RECT **rectArray, __RPC__out int *rectArrayCount) = 0;
- virtual HRESULT STDMETHODCALLTYPE CreateProxyFactoryEntry(__RPC__in_opt IUIAutomationProxyFactory *factory, __RPC__deref_out_opt IUIAutomationProxyFactoryEntry **factoryEntry) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_ProxyFactoryMapping(__RPC__deref_out_opt IUIAutomationProxyFactoryMapping **factoryMapping) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetPropertyProgrammaticName(PROPERTYID property, __RPC__deref_out_opt BSTR *name) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetPatternProgrammaticName(PATTERNID pattern, __RPC__deref_out_opt BSTR *name) = 0;
- virtual HRESULT STDMETHODCALLTYPE PollForPotentialSupportedPatterns(__RPC__in_opt IUIAutomationElement *pElement, __RPC__deref_out_opt SAFEARRAY **patternIds, __RPC__deref_out_opt SAFEARRAY **patternNames) = 0;
- virtual HRESULT STDMETHODCALLTYPE PollForPotentialSupportedProperties(__RPC__in_opt IUIAutomationElement *pElement, __RPC__deref_out_opt SAFEARRAY **propertyIds, __RPC__deref_out_opt SAFEARRAY **propertyNames) = 0;
- virtual HRESULT STDMETHODCALLTYPE CheckNotSupported(VARIANT value, __RPC__out BOOL *isNotSupported) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_ReservedNotSupportedValue(__RPC__deref_out_opt IUnknown **notSupportedValue) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_ReservedMixedAttributeValue(__RPC__deref_out_opt IUnknown **mixedAttributeValue) = 0;
- virtual HRESULT STDMETHODCALLTYPE ElementFromIAccessible(__RPC__in_opt IAccessible *accessible, int childId, __RPC__deref_out_opt IUIAutomationElement **element) = 0;
- virtual HRESULT STDMETHODCALLTYPE ElementFromIAccessibleBuildCache(__RPC__in_opt IAccessible *accessible, int childId, __RPC__in_opt IUIAutomationCacheRequest *cacheRequest, __RPC__deref_out_opt IUIAutomationElement **element) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IUIAutomation, 0x30cbe57d, 0xd9d0, 0x452a, 0xab,0x13, 0x7a,0xc5,0xac,0x48,0x25,0xee)
-#endif
-#endif
-
-
-#ifndef __IUIAutomationTreeWalker_INTERFACE_DEFINED__
-#define __IUIAutomationTreeWalker_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IUIAutomationTreeWalker, 0x4042c624, 0x389c, 0x4afc, 0xa6,0x30, 0x9d,0xf8,0x54,0xa5,0x41,0xfc);
-MIDL_INTERFACE("4042c624-389c-4afc-a630-9df854a541fc")
-IUIAutomationTreeWalker : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE GetParentElement(__RPC__in_opt IUIAutomationElement *element, __RPC__deref_out_opt IUIAutomationElement **parent) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetFirstChildElement(__RPC__in_opt IUIAutomationElement *element, __RPC__deref_out_opt IUIAutomationElement **first) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetLastChildElement(__RPC__in_opt IUIAutomationElement *element, __RPC__deref_out_opt IUIAutomationElement **last) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetNextSiblingElement(__RPC__in_opt IUIAutomationElement *element, __RPC__deref_out_opt IUIAutomationElement **next) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetPreviousSiblingElement(__RPC__in_opt IUIAutomationElement *element, __RPC__deref_out_opt IUIAutomationElement **previous) = 0;
- virtual HRESULT STDMETHODCALLTYPE NormalizeElement(__RPC__in_opt IUIAutomationElement *element, __RPC__deref_out_opt IUIAutomationElement **normalized) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetParentElementBuildCache(__RPC__in_opt IUIAutomationElement *element, __RPC__in_opt IUIAutomationCacheRequest *cacheRequest, __RPC__deref_out_opt IUIAutomationElement **parent) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetFirstChildElementBuildCache(__RPC__in_opt IUIAutomationElement *element, __RPC__in_opt IUIAutomationCacheRequest *cacheRequest, __RPC__deref_out_opt IUIAutomationElement **first) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetLastChildElementBuildCache(__RPC__in_opt IUIAutomationElement *element, __RPC__in_opt IUIAutomationCacheRequest *cacheRequest, __RPC__deref_out_opt IUIAutomationElement **last) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetNextSiblingElementBuildCache(__RPC__in_opt IUIAutomationElement *element, __RPC__in_opt IUIAutomationCacheRequest *cacheRequest, __RPC__deref_out_opt IUIAutomationElement **next) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetPreviousSiblingElementBuildCache(__RPC__in_opt IUIAutomationElement *element, __RPC__in_opt IUIAutomationCacheRequest *cacheRequest, __RPC__deref_out_opt IUIAutomationElement **previous) = 0;
- virtual HRESULT STDMETHODCALLTYPE NormalizeElementBuildCache(__RPC__in_opt IUIAutomationElement *element, __RPC__in_opt IUIAutomationCacheRequest *cacheRequest, __RPC__deref_out_opt IUIAutomationElement **normalized) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_Condition(__RPC__deref_out_opt IUIAutomationCondition **condition) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IUIAutomationTreeWalker, 0x4042c624, 0x389c, 0x4afc, 0xa6,0x30, 0x9d,0xf8,0x54,0xa5,0x41,0xfc)
-#endif
-#endif
-
-DEFINE_GUID(CLSID_CUIAutomation, 0xff48dba4, 0x60ef, 0x4201, 0xaa,0x87, 0x54,0x10,0x3e,0xef,0x59,0x4e);
-
-#endif
diff --git a/src/gui/accessible/windows/apisupport/uiacontroltypeids_p.h b/src/gui/accessible/windows/apisupport/uiacontroltypeids_p.h
deleted file mode 100644
index 21d8080bc2..0000000000
--- a/src/gui/accessible/windows/apisupport/uiacontroltypeids_p.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef UIACONTROLTYPEIDS_H
-#define UIACONTROLTYPEIDS_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.
-//
-
-#define UIA_ButtonControlTypeId 50000
-#define UIA_CalendarControlTypeId 50001
-#define UIA_CheckBoxControlTypeId 50002
-#define UIA_ComboBoxControlTypeId 50003
-#define UIA_EditControlTypeId 50004
-#define UIA_HyperlinkControlTypeId 50005
-#define UIA_ImageControlTypeId 50006
-#define UIA_ListItemControlTypeId 50007
-#define UIA_ListControlTypeId 50008
-#define UIA_MenuControlTypeId 50009
-#define UIA_MenuBarControlTypeId 50010
-#define UIA_MenuItemControlTypeId 50011
-#define UIA_ProgressBarControlTypeId 50012
-#define UIA_RadioButtonControlTypeId 50013
-#define UIA_ScrollBarControlTypeId 50014
-#define UIA_SliderControlTypeId 50015
-#define UIA_SpinnerControlTypeId 50016
-#define UIA_StatusBarControlTypeId 50017
-#define UIA_TabControlTypeId 50018
-#define UIA_TabItemControlTypeId 50019
-#define UIA_TextControlTypeId 50020
-#define UIA_ToolBarControlTypeId 50021
-#define UIA_ToolTipControlTypeId 50022
-#define UIA_TreeControlTypeId 50023
-#define UIA_TreeItemControlTypeId 50024
-#define UIA_CustomControlTypeId 50025
-#define UIA_GroupControlTypeId 50026
-#define UIA_ThumbControlTypeId 50027
-#define UIA_DataGridControlTypeId 50028
-#define UIA_DataItemControlTypeId 50029
-#define UIA_DocumentControlTypeId 50030
-#define UIA_SplitButtonControlTypeId 50031
-#define UIA_WindowControlTypeId 50032
-#define UIA_PaneControlTypeId 50033
-#define UIA_HeaderControlTypeId 50034
-#define UIA_HeaderItemControlTypeId 50035
-#define UIA_TableControlTypeId 50036
-#define UIA_TitleBarControlTypeId 50037
-#define UIA_SeparatorControlTypeId 50038
-#define UIA_SemanticZoomControlTypeId 50039
-#define UIA_AppBarControlTypeId 50040
-
-#endif
diff --git a/src/gui/accessible/windows/apisupport/uiaerrorids_p.h b/src/gui/accessible/windows/apisupport/uiaerrorids_p.h
deleted file mode 100644
index b965fe5c30..0000000000
--- a/src/gui/accessible/windows/apisupport/uiaerrorids_p.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef UIAERRORIDS_H
-#define UIAERRORIDS_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.
-//
-
-#define UIA_E_ELEMENTNOTENABLED 0x80040200
-#define UIA_E_ELEMENTNOTAVAILABLE 0x80040201
-#define UIA_E_NOCLICKABLEPOINT 0x80040202
-#define UIA_E_PROXYASSEMBLYNOTLOADED 0x80040203
-#define UIA_E_NOTSUPPORTED 0x80040204
-#define UIA_E_INVALIDOPERATION 0x80131509
-#define UIA_E_TIMEOUT 0x80131505
-
-#endif
diff --git a/src/gui/accessible/windows/apisupport/uiaeventids_p.h b/src/gui/accessible/windows/apisupport/uiaeventids_p.h
deleted file mode 100644
index 7ac6d85ec5..0000000000
--- a/src/gui/accessible/windows/apisupport/uiaeventids_p.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef UIAEVENTIDS_H
-#define UIAEVENTIDS_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.
-//
-
-#define UIA_ToolTipOpenedEventId 20000
-#define UIA_ToolTipClosedEventId 20001
-#define UIA_StructureChangedEventId 20002
-#define UIA_MenuOpenedEventId 20003
-#define UIA_AutomationPropertyChangedEventId 20004
-#define UIA_AutomationFocusChangedEventId 20005
-#define UIA_AsyncContentLoadedEventId 20006
-#define UIA_MenuClosedEventId 20007
-#define UIA_LayoutInvalidatedEventId 20008
-#define UIA_Invoke_InvokedEventId 20009
-#define UIA_SelectionItem_ElementAddedToSelectionEventId 20010
-#define UIA_SelectionItem_ElementRemovedFromSelectionEventId 20011
-#define UIA_SelectionItem_ElementSelectedEventId 20012
-#define UIA_Selection_InvalidatedEventId 20013
-#define UIA_Text_TextSelectionChangedEventId 20014
-#define UIA_Text_TextChangedEventId 20015
-#define UIA_Window_WindowOpenedEventId 20016
-#define UIA_Window_WindowClosedEventId 20017
-#define UIA_MenuModeStartEventId 20018
-#define UIA_MenuModeEndEventId 20019
-#define UIA_InputReachedTargetEventId 20020
-#define UIA_InputReachedOtherElementEventId 20021
-#define UIA_InputDiscardedEventId 20022
-#define UIA_SystemAlertEventId 20023
-#define UIA_LiveRegionChangedEventId 20024
-#define UIA_HostedFragmentRootsInvalidatedEventId 20025
-#define UIA_Drag_DragStartEventId 20026
-#define UIA_Drag_DragCancelEventId 20027
-#define UIA_Drag_DragCompleteEventId 20028
-#define UIA_DropTarget_DragEnterEventId 20029
-#define UIA_DropTarget_DragLeaveEventId 20030
-#define UIA_DropTarget_DroppedEventId 20031
-#define UIA_TextEdit_TextChangedEventId 20032
-#define UIA_TextEdit_ConversionTargetChangedEventId 20033
-#define UIA_ChangesEventId 20034
-
-#endif
diff --git a/src/gui/accessible/windows/apisupport/uiageneralids_p.h b/src/gui/accessible/windows/apisupport/uiageneralids_p.h
deleted file mode 100644
index a6fdeceee3..0000000000
--- a/src/gui/accessible/windows/apisupport/uiageneralids_p.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef UIAGENERALIDS_H
-#define UIAGENERALIDS_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.
-//
-
-#define UiaAppendRuntimeId 3
-#define UiaRootObjectId -25
-
-#endif
diff --git a/src/gui/accessible/windows/apisupport/uiapatternids_p.h b/src/gui/accessible/windows/apisupport/uiapatternids_p.h
deleted file mode 100644
index 0ff463cd36..0000000000
--- a/src/gui/accessible/windows/apisupport/uiapatternids_p.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef UIAPATTERNIDS_H
-#define UIAPATTERNIDS_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.
-//
-
-#define UIA_InvokePatternId 10000
-#define UIA_SelectionPatternId 10001
-#define UIA_ValuePatternId 10002
-#define UIA_RangeValuePatternId 10003
-#define UIA_ScrollPatternId 10004
-#define UIA_ExpandCollapsePatternId 10005
-#define UIA_GridPatternId 10006
-#define UIA_GridItemPatternId 10007
-#define UIA_MultipleViewPatternId 10008
-#define UIA_WindowPatternId 10009
-#define UIA_SelectionItemPatternId 10010
-#define UIA_DockPatternId 10011
-#define UIA_TablePatternId 10012
-#define UIA_TableItemPatternId 10013
-#define UIA_TextPatternId 10014
-#define UIA_TogglePatternId 10015
-#define UIA_TransformPatternId 10016
-#define UIA_ScrollItemPatternId 10017
-#define UIA_LegacyIAccessiblePatternId 10018
-#define UIA_ItemContainerPatternId 10019
-#define UIA_VirtualizedItemPatternId 10020
-#define UIA_SynchronizedInputPatternId 10021
-#define UIA_ObjectModelPatternId 10022
-#define UIA_AnnotationPatternId 10023
-#define UIA_TextPattern2Id 10024
-#define UIA_StylesPatternId 10025
-#define UIA_SpreadsheetPatternId 10026
-#define UIA_SpreadsheetItemPatternId 10027
-#define UIA_TransformPattern2Id 10028
-#define UIA_TextChildPatternId 10029
-#define UIA_DragPatternId 10030
-#define UIA_DropTargetPatternId 10031
-#define UIA_TextEditPatternId 10032
-#define UIA_CustomNavigationPatternId 10033
-
-#endif
diff --git a/src/gui/accessible/windows/apisupport/uiapropertyids_p.h b/src/gui/accessible/windows/apisupport/uiapropertyids_p.h
deleted file mode 100644
index 77fc454e0f..0000000000
--- a/src/gui/accessible/windows/apisupport/uiapropertyids_p.h
+++ /dev/null
@@ -1,188 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef UIAPROPERTYIDS_H
-#define UIAPROPERTYIDS_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.
-//
-
-#define UIA_RuntimeIdPropertyId 30000
-#define UIA_BoundingRectanglePropertyId 30001
-#define UIA_ProcessIdPropertyId 30002
-#define UIA_ControlTypePropertyId 30003
-#define UIA_LocalizedControlTypePropertyId 30004
-#define UIA_NamePropertyId 30005
-#define UIA_AcceleratorKeyPropertyId 30006
-#define UIA_AccessKeyPropertyId 30007
-#define UIA_HasKeyboardFocusPropertyId 30008
-#define UIA_IsKeyboardFocusablePropertyId 30009
-#define UIA_IsEnabledPropertyId 30010
-#define UIA_AutomationIdPropertyId 30011
-#define UIA_ClassNamePropertyId 30012
-#define UIA_HelpTextPropertyId 30013
-#define UIA_ClickablePointPropertyId 30014
-#define UIA_CulturePropertyId 30015
-#define UIA_IsControlElementPropertyId 30016
-#define UIA_IsContentElementPropertyId 30017
-#define UIA_LabeledByPropertyId 30018
-#define UIA_IsPasswordPropertyId 30019
-#define UIA_NativeWindowHandlePropertyId 30020
-#define UIA_ItemTypePropertyId 30021
-#define UIA_IsOffscreenPropertyId 30022
-#define UIA_OrientationPropertyId 30023
-#define UIA_FrameworkIdPropertyId 30024
-#define UIA_IsRequiredForFormPropertyId 30025
-#define UIA_ItemStatusPropertyId 30026
-#define UIA_IsDockPatternAvailablePropertyId 30027
-#define UIA_IsExpandCollapsePatternAvailablePropertyId 30028
-#define UIA_IsGridItemPatternAvailablePropertyId 30029
-#define UIA_IsGridPatternAvailablePropertyId 30030
-#define UIA_IsInvokePatternAvailablePropertyId 30031
-#define UIA_IsMultipleViewPatternAvailablePropertyId 30032
-#define UIA_IsRangeValuePatternAvailablePropertyId 30033
-#define UIA_IsScrollPatternAvailablePropertyId 30034
-#define UIA_IsScrollItemPatternAvailablePropertyId 30035
-#define UIA_IsSelectionItemPatternAvailablePropertyId 30036
-#define UIA_IsSelectionPatternAvailablePropertyId 30037
-#define UIA_IsTablePatternAvailablePropertyId 30038
-#define UIA_IsTableItemPatternAvailablePropertyId 30039
-#define UIA_IsTextPatternAvailablePropertyId 30040
-#define UIA_IsTogglePatternAvailablePropertyId 30041
-#define UIA_IsTransformPatternAvailablePropertyId 30042
-#define UIA_IsValuePatternAvailablePropertyId 30043
-#define UIA_IsWindowPatternAvailablePropertyId 30044
-#define UIA_ValueValuePropertyId 30045
-#define UIA_ValueIsReadOnlyPropertyId 30046
-#define UIA_RangeValueValuePropertyId 30047
-#define UIA_RangeValueIsReadOnlyPropertyId 30048
-#define UIA_RangeValueMinimumPropertyId 30049
-#define UIA_RangeValueMaximumPropertyId 30050
-#define UIA_RangeValueLargeChangePropertyId 30051
-#define UIA_RangeValueSmallChangePropertyId 30052
-#define UIA_ScrollHorizontalScrollPercentPropertyId 30053
-#define UIA_ScrollHorizontalViewSizePropertyId 30054
-#define UIA_ScrollVerticalScrollPercentPropertyId 30055
-#define UIA_ScrollVerticalViewSizePropertyId 30056
-#define UIA_ScrollHorizontallyScrollablePropertyId 30057
-#define UIA_ScrollVerticallyScrollablePropertyId 30058
-#define UIA_SelectionSelectionPropertyId 30059
-#define UIA_SelectionCanSelectMultiplePropertyId 30060
-#define UIA_SelectionIsSelectionRequiredPropertyId 30061
-#define UIA_GridRowCountPropertyId 30062
-#define UIA_GridColumnCountPropertyId 30063
-#define UIA_GridItemRowPropertyId 30064
-#define UIA_GridItemColumnPropertyId 30065
-#define UIA_GridItemRowSpanPropertyId 30066
-#define UIA_GridItemColumnSpanPropertyId 30067
-#define UIA_GridItemContainingGridPropertyId 30068
-#define UIA_DockDockPositionPropertyId 30069
-#define UIA_ExpandCollapseExpandCollapseStatePropertyId 30070
-#define UIA_MultipleViewCurrentViewPropertyId 30071
-#define UIA_MultipleViewSupportedViewsPropertyId 30072
-#define UIA_WindowCanMaximizePropertyId 30073
-#define UIA_WindowCanMinimizePropertyId 30074
-#define UIA_WindowWindowVisualStatePropertyId 30075
-#define UIA_WindowWindowInteractionStatePropertyId 30076
-#define UIA_WindowIsModalPropertyId 30077
-#define UIA_WindowIsTopmostPropertyId 30078
-#define UIA_SelectionItemIsSelectedPropertyId 30079
-#define UIA_SelectionItemSelectionContainerPropertyId 30080
-#define UIA_TableRowHeadersPropertyId 30081
-#define UIA_TableColumnHeadersPropertyId 30082
-#define UIA_TableRowOrColumnMajorPropertyId 30083
-#define UIA_TableItemRowHeaderItemsPropertyId 30084
-#define UIA_TableItemColumnHeaderItemsPropertyId 30085
-#define UIA_ToggleToggleStatePropertyId 30086
-#define UIA_TransformCanMovePropertyId 30087
-#define UIA_TransformCanResizePropertyId 30088
-#define UIA_TransformCanRotatePropertyId 30089
-#define UIA_IsLegacyIAccessiblePatternAvailablePropertyId 30090
-#define UIA_LegacyIAccessibleChildIdPropertyId 30091
-#define UIA_LegacyIAccessibleNamePropertyId 30092
-#define UIA_LegacyIAccessibleValuePropertyId 30093
-#define UIA_LegacyIAccessibleDescriptionPropertyId 30094
-#define UIA_LegacyIAccessibleRolePropertyId 30095
-#define UIA_LegacyIAccessibleStatePropertyId 30096
-#define UIA_LegacyIAccessibleHelpPropertyId 30097
-#define UIA_LegacyIAccessibleKeyboardShortcutPropertyId 30098
-#define UIA_LegacyIAccessibleSelectionPropertyId 30099
-#define UIA_LegacyIAccessibleDefaultActionPropertyId 30100
-#define UIA_AriaRolePropertyId 30101
-#define UIA_AriaPropertiesPropertyId 30102
-#define UIA_IsDataValidForFormPropertyId 30103
-#define UIA_ControllerForPropertyId 30104
-#define UIA_DescribedByPropertyId 30105
-#define UIA_FlowsToPropertyId 30106
-#define UIA_ProviderDescriptionPropertyId 30107
-#define UIA_IsItemContainerPatternAvailablePropertyId 30108
-#define UIA_IsVirtualizedItemPatternAvailablePropertyId 30109
-#define UIA_IsSynchronizedInputPatternAvailablePropertyId 30110
-#define UIA_OptimizeForVisualContentPropertyId 30111
-#define UIA_IsObjectModelPatternAvailablePropertyId 30112
-#define UIA_AnnotationAnnotationTypeIdPropertyId 30113
-#define UIA_AnnotationAnnotationTypeNamePropertyId 30114
-#define UIA_AnnotationAuthorPropertyId 30115
-#define UIA_AnnotationDateTimePropertyId 30116
-#define UIA_AnnotationTargetPropertyId 30117
-#define UIA_IsAnnotationPatternAvailablePropertyId 30118
-#define UIA_IsTextPattern2AvailablePropertyId 30119
-#define UIA_StylesStyleIdPropertyId 30120
-#define UIA_StylesStyleNamePropertyId 30121
-#define UIA_StylesFillColorPropertyId 30122
-#define UIA_StylesFillPatternStylePropertyId 30123
-#define UIA_StylesShapePropertyId 30124
-#define UIA_StylesFillPatternColorPropertyId 30125
-#define UIA_StylesExtendedPropertiesPropertyId 30126
-#define UIA_IsStylesPatternAvailablePropertyId 30127
-#define UIA_IsSpreadsheetPatternAvailablePropertyId 30128
-#define UIA_SpreadsheetItemFormulaPropertyId 30129
-#define UIA_SpreadsheetItemAnnotationObjectsPropertyId 30130
-#define UIA_SpreadsheetItemAnnotationTypesPropertyId 30131
-#define UIA_IsSpreadsheetItemPatternAvailablePropertyId 30132
-#define UIA_Transform2CanZoomPropertyId 30133
-#define UIA_IsTransformPattern2AvailablePropertyId 30134
-#define UIA_LiveSettingPropertyId 30135
-#define UIA_IsTextChildPatternAvailablePropertyId 30136
-#define UIA_IsDragPatternAvailablePropertyId 30137
-#define UIA_DragIsGrabbedPropertyId 30138
-#define UIA_DragDropEffectPropertyId 30139
-#define UIA_DragDropEffectsPropertyId 30140
-#define UIA_IsDropTargetPatternAvailablePropertyId 30141
-#define UIA_DropTargetDropTargetEffectPropertyId 30142
-#define UIA_DropTargetDropTargetEffectsPropertyId 30143
-#define UIA_DragGrabbedItemsPropertyId 30144
-#define UIA_Transform2ZoomLevelPropertyId 30145
-#define UIA_Transform2ZoomMinimumPropertyId 30146
-#define UIA_Transform2ZoomMaximumPropertyId 30147
-#define UIA_FlowsFromPropertyId 30148
-#define UIA_IsTextEditPatternAvailablePropertyId 30149
-#define UIA_IsPeripheralPropertyId 30150
-#define UIA_IsCustomNavigationPatternAvailablePropertyId 30151
-#define UIA_PositionInSetPropertyId 30152
-#define UIA_SizeOfSetPropertyId 30153
-#define UIA_LevelPropertyId 30154
-#define UIA_AnnotationTypesPropertyId 30155
-#define UIA_AnnotationObjectsPropertyId 30156
-#define UIA_LandmarkTypePropertyId 30157
-#define UIA_LocalizedLandmarkTypePropertyId 30158
-#define UIA_FullDescriptionPropertyId 30159
-#define UIA_FillColorPropertyId 30160
-#define UIA_OutlineColorPropertyId 30161
-#define UIA_FillTypePropertyId 30162
-#define UIA_VisualEffectsPropertyId 30163
-#define UIA_OutlineThicknessPropertyId 30164
-#define UIA_CenterPointPropertyId 30165
-#define UIA_RotationPropertyId 30166
-#define UIA_SizePropertyId 30167
-#define UIA_IsDialogPropertyId 30174
-
-#endif
diff --git a/src/gui/accessible/windows/apisupport/uiaserverinterfaces_p.h b/src/gui/accessible/windows/apisupport/uiaserverinterfaces_p.h
deleted file mode 100644
index 6cf15cacb0..0000000000
--- a/src/gui/accessible/windows/apisupport/uiaserverinterfaces_p.h
+++ /dev/null
@@ -1,367 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef UIASERVERINTERFACES_H
-#define UIASERVERINTERFACES_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 <unknwn.h>
-
-#ifndef __IRawElementProviderSimple_INTERFACE_DEFINED__
-#define __IRawElementProviderSimple_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IRawElementProviderSimple, 0xd6dd68d1, 0x86fd, 0x4332, 0x86,0x66, 0x9a,0xbe,0xde,0xa2,0xd2,0x4c);
-MIDL_INTERFACE("d6dd68d1-86fd-4332-8666-9abedea2d24c")
-IRawElementProviderSimple : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE get_ProviderOptions(__RPC__out enum ProviderOptions *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetPatternProvider(PATTERNID patternId, __RPC__deref_out_opt IUnknown **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetPropertyValue(PROPERTYID propertyId, __RPC__out VARIANT *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_HostRawElementProvider(__RPC__deref_out_opt IRawElementProviderSimple **pRetVal) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IRawElementProviderSimple, 0xd6dd68d1, 0x86fd, 0x4332, 0x86,0x66, 0x9a,0xbe,0xde,0xa2,0xd2,0x4c)
-#endif
-#endif
-
-
-#ifndef __IRawElementProviderFragmentRoot_FWD_DEFINED__
-#define __IRawElementProviderFragmentRoot_FWD_DEFINED__
-typedef interface IRawElementProviderFragmentRoot IRawElementProviderFragmentRoot;
-#endif
-
-
-#ifndef __IRawElementProviderFragment_FWD_DEFINED__
-#define __IRawElementProviderFragment_FWD_DEFINED__
-typedef interface IRawElementProviderFragment IRawElementProviderFragment;
-#endif
-
-
-#ifndef __IRawElementProviderFragment_INTERFACE_DEFINED__
-#define __IRawElementProviderFragment_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IRawElementProviderFragment, 0xf7063da8, 0x8359, 0x439c, 0x92,0x97, 0xbb,0xc5,0x29,0x9a,0x7d,0x87);
-MIDL_INTERFACE("f7063da8-8359-439c-9297-bbc5299a7d87")
-IRawElementProviderFragment : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE Navigate(enum NavigateDirection direction, __RPC__deref_out_opt IRawElementProviderFragment **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetRuntimeId(__RPC__deref_out_opt SAFEARRAY **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_BoundingRectangle(__RPC__out struct UiaRect *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetEmbeddedFragmentRoots(__RPC__deref_out_opt SAFEARRAY **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE SetFocus() = 0;
- virtual HRESULT STDMETHODCALLTYPE get_FragmentRoot(__RPC__deref_out_opt IRawElementProviderFragmentRoot **pRetVal) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IRawElementProviderFragment, 0xf7063da8, 0x8359, 0x439c, 0x92,0x97, 0xbb,0xc5,0x29,0x9a,0x7d,0x87)
-#endif
-#endif
-
-
-#ifndef __IRawElementProviderFragmentRoot_INTERFACE_DEFINED__
-#define __IRawElementProviderFragmentRoot_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IRawElementProviderFragmentRoot, 0x620ce2a5, 0xab8f, 0x40a9, 0x86,0xcb, 0xde,0x3c,0x75,0x59,0x9b,0x58);
-MIDL_INTERFACE("620ce2a5-ab8f-40a9-86cb-de3c75599b58")
-IRawElementProviderFragmentRoot : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE ElementProviderFromPoint(double x, double y, __RPC__deref_out_opt IRawElementProviderFragment **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetFocus(__RPC__deref_out_opt IRawElementProviderFragment **pRetVal) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IRawElementProviderFragmentRoot, 0x620ce2a5, 0xab8f, 0x40a9, 0x86,0xcb, 0xde,0x3c,0x75,0x59,0x9b,0x58)
-#endif
-#endif
-
-
-#ifndef __IValueProvider_INTERFACE_DEFINED__
-#define __IValueProvider_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IValueProvider, 0xc7935180, 0x6fb3, 0x4201, 0xb1,0x74, 0x7d,0xf7,0x3a,0xdb,0xf6,0x4a);
-MIDL_INTERFACE("c7935180-6fb3-4201-b174-7df73adbf64a")
-IValueProvider : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE SetValue(__RPC__in LPCWSTR val) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_Value(__RPC__deref_out_opt BSTR *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_IsReadOnly(__RPC__out BOOL *pRetVal) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IValueProvider, 0xc7935180, 0x6fb3, 0x4201, 0xb1,0x74, 0x7d,0xf7,0x3a,0xdb,0xf6,0x4a)
-#endif
-#endif
-
-
-#ifndef __IRangeValueProvider_INTERFACE_DEFINED__
-#define __IRangeValueProvider_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IRangeValueProvider, 0x36dc7aef, 0x33e6, 0x4691, 0xaf,0xe1, 0x2b,0xe7,0x27,0x4b,0x3d,0x33);
-MIDL_INTERFACE("36dc7aef-33e6-4691-afe1-2be7274b3d33")
-IRangeValueProvider : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE SetValue(double val) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_Value(__RPC__out double *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_IsReadOnly(__RPC__out BOOL *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_Maximum(__RPC__out double *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_Minimum(__RPC__out double *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_LargeChange(__RPC__out double *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_SmallChange(__RPC__out double *pRetVal) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IRangeValueProvider, 0x36dc7aef, 0x33e6, 0x4691, 0xaf,0xe1, 0x2b,0xe7,0x27,0x4b,0x3d,0x33)
-#endif
-#endif
-
-
-#ifndef __ITextRangeProvider_INTERFACE_DEFINED__
-#define __ITextRangeProvider_INTERFACE_DEFINED__
-DEFINE_GUID(IID_ITextRangeProvider, 0x5347ad7b, 0xc355, 0x46f8, 0xaf,0xf5, 0x90,0x90,0x33,0x58,0x2f,0x63);
-MIDL_INTERFACE("5347ad7b-c355-46f8-aff5-909033582f63")
-ITextRangeProvider : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE Clone(__RPC__deref_out_opt ITextRangeProvider **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE Compare(__RPC__in_opt ITextRangeProvider *range, __RPC__out BOOL *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE CompareEndpoints(enum TextPatternRangeEndpoint endpoint, __RPC__in_opt ITextRangeProvider *targetRange, enum TextPatternRangeEndpoint targetEndpoint, __RPC__out int *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE ExpandToEnclosingUnit(enum TextUnit unit) = 0;
- virtual HRESULT STDMETHODCALLTYPE FindAttribute(TEXTATTRIBUTEID attributeId, VARIANT val, BOOL backward, __RPC__deref_out_opt ITextRangeProvider **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE FindText(__RPC__in BSTR text, BOOL backward, BOOL ignoreCase, __RPC__deref_out_opt ITextRangeProvider **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetAttributeValue(TEXTATTRIBUTEID attributeId, __RPC__out VARIANT *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetBoundingRectangles(__RPC__deref_out_opt SAFEARRAY **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetEnclosingElement(__RPC__deref_out_opt IRawElementProviderSimple **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetText(int maxLength, __RPC__deref_out_opt BSTR *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE Move(enum TextUnit unit, int count, __RPC__out int *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE MoveEndpointByUnit(enum TextPatternRangeEndpoint endpoint, enum TextUnit unit, int count, __RPC__out int *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE MoveEndpointByRange(enum TextPatternRangeEndpoint endpoint, __RPC__in_opt ITextRangeProvider *targetRange, enum TextPatternRangeEndpoint targetEndpoint) = 0;
- virtual HRESULT STDMETHODCALLTYPE Select() = 0;
- virtual HRESULT STDMETHODCALLTYPE AddToSelection() = 0;
- virtual HRESULT STDMETHODCALLTYPE RemoveFromSelection() = 0;
- virtual HRESULT STDMETHODCALLTYPE ScrollIntoView(BOOL alignToTop) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetChildren(__RPC__deref_out_opt SAFEARRAY **pRetVal) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(ITextRangeProvider, 0x5347ad7b, 0xc355, 0x46f8, 0xaf,0xf5, 0x90,0x90,0x33,0x58,0x2f,0x63)
-#endif
-#endif
-
-
-#ifndef __ITextProvider_INTERFACE_DEFINED__
-#define __ITextProvider_INTERFACE_DEFINED__
-DEFINE_GUID(IID_ITextProvider, 0x3589c92c, 0x63f3, 0x4367, 0x99,0xbb, 0xad,0xa6,0x53,0xb7,0x7c,0xf2);
-MIDL_INTERFACE("3589c92c-63f3-4367-99bb-ada653b77cf2")
-ITextProvider : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE GetSelection(__RPC__deref_out_opt SAFEARRAY **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetVisibleRanges(__RPC__deref_out_opt SAFEARRAY **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE RangeFromChild(__RPC__in_opt IRawElementProviderSimple *childElement, __RPC__deref_out_opt ITextRangeProvider **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE RangeFromPoint(struct UiaPoint point, __RPC__deref_out_opt ITextRangeProvider **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_DocumentRange(__RPC__deref_out_opt ITextRangeProvider **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_SupportedTextSelection(__RPC__out enum SupportedTextSelection *pRetVal) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(ITextProvider, 0x3589c92c, 0x63f3, 0x4367, 0x99,0xbb, 0xad,0xa6,0x53,0xb7,0x7c,0xf2)
-#endif
-#endif
-
-
-#ifndef __ITextProvider2_INTERFACE_DEFINED__
-#define __ITextProvider2_INTERFACE_DEFINED__
-DEFINE_GUID(IID_ITextProvider2, 0x0dc5e6ed, 0x3e16, 0x4bf1, 0x8f,0x9a, 0xa9,0x79,0x87,0x8b,0xc1,0x95);
-MIDL_INTERFACE("0dc5e6ed-3e16-4bf1-8f9a-a979878bc195")
-ITextProvider2 : public ITextProvider
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE RangeFromAnnotation(__RPC__in_opt IRawElementProviderSimple *annotationElement, __RPC__deref_out_opt ITextRangeProvider **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetCaretRange(__RPC__out BOOL *isActive, __RPC__deref_out_opt ITextRangeProvider **pRetVal) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(ITextProvider2, 0x0dc5e6ed, 0x3e16, 0x4bf1, 0x8f,0x9a, 0xa9,0x79,0x87,0x8b,0xc1,0x95)
-#endif
-#endif
-
-
-#ifndef __IToggleProvider_INTERFACE_DEFINED__
-#define __IToggleProvider_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IToggleProvider, 0x56d00bd0, 0xc4f4, 0x433c, 0xa8,0x36, 0x1a,0x52,0xa5,0x7e,0x08,0x92);
-MIDL_INTERFACE("56d00bd0-c4f4-433c-a836-1a52a57e0892")
-IToggleProvider : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE Toggle() = 0;
- virtual HRESULT STDMETHODCALLTYPE get_ToggleState(__RPC__out enum ToggleState *pRetVal) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IToggleProvider, 0x56d00bd0, 0xc4f4, 0x433c, 0xa8,0x36, 0x1a,0x52,0xa5,0x7e,0x08,0x92)
-#endif
-#endif
-
-
-#ifndef __IInvokeProvider_INTERFACE_DEFINED__
-#define __IInvokeProvider_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IInvokeProvider, 0x54fcb24b, 0xe18e, 0x47a2, 0xb4,0xd3, 0xec,0xcb,0xe7,0x75,0x99,0xa2);
-MIDL_INTERFACE("54fcb24b-e18e-47a2-b4d3-eccbe77599a2")
-IInvokeProvider : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE Invoke() = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IInvokeProvider, 0x54fcb24b, 0xe18e, 0x47a2, 0xb4,0xd3, 0xec,0xcb,0xe7,0x75,0x99,0xa2)
-#endif
-#endif
-
-
-#ifndef __ISelectionProvider_INTERFACE_DEFINED__
-#define __ISelectionProvider_INTERFACE_DEFINED__
-DEFINE_GUID(IID_ISelectionProvider, 0xfb8b03af, 0x3bdf, 0x48d4, 0xbd,0x36, 0x1a,0x65,0x79,0x3b,0xe1,0x68);
-MIDL_INTERFACE("fb8b03af-3bdf-48d4-bd36-1a65793be168")
-ISelectionProvider : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE GetSelection(__RPC__deref_out_opt SAFEARRAY **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CanSelectMultiple(__RPC__out BOOL *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_IsSelectionRequired(__RPC__out BOOL *pRetVal) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(ISelectionProvider, 0xfb8b03af, 0x3bdf, 0x48d4, 0xbd,0x36, 0x1a,0x65,0x79,0x3b,0xe1,0x68)
-#endif
-#endif
-
-
-#ifndef __ISelectionItemProvider_INTERFACE_DEFINED__
-#define __ISelectionItemProvider_INTERFACE_DEFINED__
-DEFINE_GUID(IID_ISelectionItemProvider, 0x2acad808, 0xb2d4, 0x452d, 0xa4,0x07, 0x91,0xff,0x1a,0xd1,0x67,0xb2);
-MIDL_INTERFACE("2acad808-b2d4-452d-a407-91ff1ad167b2")
-ISelectionItemProvider : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE Select() = 0;
- virtual HRESULT STDMETHODCALLTYPE AddToSelection() = 0;
- virtual HRESULT STDMETHODCALLTYPE RemoveFromSelection() = 0;
- virtual HRESULT STDMETHODCALLTYPE get_IsSelected(__RPC__out BOOL *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_SelectionContainer(__RPC__deref_out_opt IRawElementProviderSimple **pRetVal) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(ISelectionItemProvider, 0x2acad808, 0xb2d4, 0x452d, 0xa4,0x07, 0x91,0xff,0x1a,0xd1,0x67,0xb2)
-#endif
-#endif
-
-
-#ifndef __ITableProvider_INTERFACE_DEFINED__
-#define __ITableProvider_INTERFACE_DEFINED__
-DEFINE_GUID(IID_ITableProvider, 0x9c860395, 0x97b3, 0x490a, 0xb5,0x2a, 0x85,0x8c,0xc2,0x2a,0xf1,0x66);
-MIDL_INTERFACE("9c860395-97b3-490a-b52a-858cc22af166")
-ITableProvider : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE GetRowHeaders(__RPC__deref_out_opt SAFEARRAY **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetColumnHeaders(__RPC__deref_out_opt SAFEARRAY **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_RowOrColumnMajor(__RPC__out enum RowOrColumnMajor *pRetVal) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(ITableProvider, 0x9c860395, 0x97b3, 0x490a, 0xb5,0x2a, 0x85,0x8c,0xc2,0x2a,0xf1,0x66)
-#endif
-#endif
-
-
-#ifndef __ITableItemProvider_INTERFACE_DEFINED__
-#define __ITableItemProvider_INTERFACE_DEFINED__
-DEFINE_GUID(IID_ITableItemProvider, 0xb9734fa6, 0x771f, 0x4d78, 0x9c,0x90, 0x25,0x17,0x99,0x93,0x49,0xcd);
-MIDL_INTERFACE("b9734fa6-771f-4d78-9c90-2517999349cd")
-ITableItemProvider : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE GetRowHeaderItems(__RPC__deref_out_opt SAFEARRAY **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE GetColumnHeaderItems(__RPC__deref_out_opt SAFEARRAY **pRetVal) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(ITableItemProvider, 0xb9734fa6, 0x771f, 0x4d78, 0x9c,0x90, 0x25,0x17,0x99,0x93,0x49,0xcd)
-#endif
-#endif
-
-
-#ifndef __IGridProvider_INTERFACE_DEFINED__
-#define __IGridProvider_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IGridProvider, 0xb17d6187, 0x0907, 0x464b, 0xa1,0x68, 0x0e,0xf1,0x7a,0x15,0x72,0xb1);
-MIDL_INTERFACE("b17d6187-0907-464b-a168-0ef17a1572b1")
-IGridProvider : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE GetItem(int row, int column, __RPC__deref_out_opt IRawElementProviderSimple **pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_RowCount(__RPC__out int *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_ColumnCount(__RPC__out int *pRetVal) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IGridProvider, 0xb17d6187, 0x0907, 0x464b, 0xa1,0x68, 0x0e,0xf1,0x7a,0x15,0x72,0xb1)
-#endif
-#endif
-
-
-#ifndef __IGridItemProvider_INTERFACE_DEFINED__
-#define __IGridItemProvider_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IGridItemProvider, 0xd02541f1, 0xfb81, 0x4d64, 0xae,0x32, 0xf5,0x20,0xf8,0xa6,0xdb,0xd1);
-MIDL_INTERFACE("d02541f1-fb81-4d64-ae32-f520f8a6dbd1")
-IGridItemProvider : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE get_Row(__RPC__out int *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_Column(__RPC__out int *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_RowSpan(__RPC__out int *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_ColumnSpan(__RPC__out int *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_ContainingGrid(__RPC__deref_out_opt IRawElementProviderSimple **pRetVal) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IGridItemProvider, 0xd02541f1, 0xfb81, 0x4d64, 0xae,0x32, 0xf5,0x20,0xf8,0xa6,0xdb,0xd1)
-#endif
-#endif
-
-
-#ifndef __IWindowProvider_INTERFACE_DEFINED__
-#define __IWindowProvider_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IWindowProvider, 0x987df77b, 0xdb06, 0x4d77, 0x8f,0x8a, 0x86,0xa9,0xc3,0xbb,0x90,0xb9);
-MIDL_INTERFACE("987df77b-db06-4d77-8f8a-86a9c3bb90b9")
-IWindowProvider : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE SetVisualState(enum WindowVisualState state) = 0;
- virtual HRESULT STDMETHODCALLTYPE Close( void) = 0;
- virtual HRESULT STDMETHODCALLTYPE WaitForInputIdle(int milliseconds, __RPC__out BOOL *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CanMaximize(__RPC__out BOOL *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_CanMinimize(__RPC__out BOOL *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_IsModal(__RPC__out BOOL *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_WindowVisualState(__RPC__out enum WindowVisualState *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_WindowInteractionState(__RPC__out enum WindowInteractionState *pRetVal) = 0;
- virtual HRESULT STDMETHODCALLTYPE get_IsTopmost(__RPC__out BOOL *pRetVal) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IWindowProvider, 0x987df77b, 0xdb06, 0x4d77, 0x8f,0x8a, 0x86,0xa9,0xc3,0xbb,0x90,0xb9)
-#endif
-#endif
-
-
-#ifndef __IExpandCollapseProvider_INTERFACE_DEFINED__
-#define __IExpandCollapseProvider_INTERFACE_DEFINED__
-DEFINE_GUID(IID_IExpandCollapseProvider, 0xd847d3a5, 0xcab0, 0x4a98, 0x8c,0x32, 0xec,0xb4,0x5c,0x59,0xad,0x24);
-MIDL_INTERFACE("d847d3a5-cab0-4a98-8c32-ecb45c59ad24")
-IExpandCollapseProvider : public IUnknown
-{
-public:
- virtual HRESULT STDMETHODCALLTYPE Expand() = 0;
- virtual HRESULT STDMETHODCALLTYPE Collapse() = 0;
- virtual HRESULT STDMETHODCALLTYPE get_ExpandCollapseState(__RPC__out enum ExpandCollapseState *pRetVal) = 0;
-};
-#ifdef __CRT_UUID_DECL
-__CRT_UUID_DECL(IExpandCollapseProvider, 0xd847d3a5, 0xcab0, 0x4a98, 0x8c,0x32, 0xec,0xb4,0x5c,0x59,0xad,0x24)
-#endif
-#endif
-
-#endif
diff --git a/src/gui/accessible/windows/apisupport/uiatypes_p.h b/src/gui/accessible/windows/apisupport/uiatypes_p.h
deleted file mode 100644
index 465bd07a07..0000000000
--- a/src/gui/accessible/windows/apisupport/uiatypes_p.h
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef UIATYPES_H
-#define UIATYPES_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.
-//
-
-typedef int PROPERTYID;
-typedef int PATTERNID;
-typedef int EVENTID;
-typedef int TEXTATTRIBUTEID;
-typedef int CONTROLTYPEID;
-typedef int LANDMARKTYPEID;
-typedef int METADATAID;
-
-typedef void *UIA_HWND;
-
-enum NavigateDirection {
- NavigateDirection_Parent = 0,
- NavigateDirection_NextSibling = 1,
- NavigateDirection_PreviousSibling = 2,
- NavigateDirection_FirstChild = 3,
- NavigateDirection_LastChild = 4
-};
-
-enum ProviderOptions {
- ProviderOptions_ClientSideProvider = 0x1,
- ProviderOptions_ServerSideProvider = 0x2,
- ProviderOptions_NonClientAreaProvider = 0x4,
- ProviderOptions_OverrideProvider = 0x8,
- ProviderOptions_ProviderOwnsSetFocus = 0x10,
- ProviderOptions_UseComThreading = 0x20,
- ProviderOptions_RefuseNonClientSupport = 0x40,
- ProviderOptions_HasNativeIAccessible = 0x80,
- ProviderOptions_UseClientCoordinates = 0x100
-};
-
-enum SupportedTextSelection {
- SupportedTextSelection_None = 0,
- SupportedTextSelection_Single = 1,
- SupportedTextSelection_Multiple = 2
-};
-
-enum TextUnit {
- TextUnit_Character = 0,
- TextUnit_Format = 1,
- TextUnit_Word = 2,
- TextUnit_Line = 3,
- TextUnit_Paragraph = 4,
- TextUnit_Page = 5,
- TextUnit_Document = 6
-};
-
-enum TextPatternRangeEndpoint {
- TextPatternRangeEndpoint_Start = 0,
- TextPatternRangeEndpoint_End = 1
-};
-
-enum CaretPosition {
- CaretPosition_Unknown = 0,
- CaretPosition_EndOfLine = 1,
- CaretPosition_BeginningOfLine = 2
-};
-
-enum ToggleState {
- ToggleState_Off = 0,
- ToggleState_On = 1,
- ToggleState_Indeterminate = 2
-};
-
-enum RowOrColumnMajor {
- RowOrColumnMajor_RowMajor = 0,
- RowOrColumnMajor_ColumnMajor = 1,
- RowOrColumnMajor_Indeterminate = 2
-};
-
-enum TreeScope {
- TreeScope_None = 0,
- TreeScope_Element = 0x1,
- TreeScope_Children = 0x2,
- TreeScope_Descendants = 0x4,
- TreeScope_Parent = 0x8,
- TreeScope_Ancestors = 0x10,
- TreeScope_Subtree = TreeScope_Element | TreeScope_Children | TreeScope_Descendants
-};
-
-enum OrientationType {
- OrientationType_None = 0,
- OrientationType_Horizontal = 1,
- OrientationType_Vertical = 2
-};
-
-enum PropertyConditionFlags {
- PropertyConditionFlags_None = 0,
- PropertyConditionFlags_IgnoreCase = 1
-};
-
-enum WindowVisualState {
- WindowVisualState_Normal = 0,
- WindowVisualState_Maximized = 1,
- WindowVisualState_Minimized = 2
-};
-
-enum WindowInteractionState {
- WindowInteractionState_Running = 0,
- WindowInteractionState_Closing = 1,
- WindowInteractionState_ReadyForUserInteraction = 2,
- WindowInteractionState_BlockedByModalWindow = 3,
- WindowInteractionState_NotResponding = 4
-};
-
-enum ExpandCollapseState {
- ExpandCollapseState_Collapsed = 0,
- ExpandCollapseState_Expanded = 1,
- ExpandCollapseState_PartiallyExpanded = 2,
- ExpandCollapseState_LeafNode = 3
-};
-
-enum NotificationKind {
- NotificationKind_ItemAdded = 0,
- NotificationKind_ItemRemoved = 1,
- NotificationKind_ActionCompleted = 2,
- NotificationKind_ActionAborted = 3,
- NotificationKind_Other = 4
-};
-
-enum NotificationProcessing {
- NotificationProcessing_ImportantAll = 0,
- NotificationProcessing_ImportantMostRecent = 1,
- NotificationProcessing_All = 2,
- NotificationProcessing_MostRecent = 3,
- NotificationProcessing_CurrentThenMostRecent = 4
-};
-
-struct UiaRect {
- double left;
- double top;
- double width;
- double height;
-};
-
-struct UiaPoint {
- double x;
- double y;
-};
-
-#endif
diff --git a/src/gui/compat/removed_api.cpp b/src/gui/compat/removed_api.cpp
new file mode 100644
index 0000000000..a642c33c42
--- /dev/null
+++ b/src/gui/compat/removed_api.cpp
@@ -0,0 +1,70 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#define QT_GUI_BUILD_REMOVED_API
+
+#include "qtguiglobal.h"
+
+QT_USE_NAMESPACE
+
+#if QT_GUI_REMOVED_SINCE(6, 4)
+
+#include "qpagesize.h" // removed duplicate declaration of op==
+ // (still caused an symbol on some platforms)
+
+// #include "qotherheader.h"
+// // implement removed functions from qotherheader.h
+// order sections alphabetically
+
+#endif // QT_GUI_REMOVED_SINCE(6, 4)
+
+#if QT_GUI_REMOVED_SINCE(6, 6)
+
+#include "qpixmapcache.h" // inlined API
+
+// #include "qotherheader.h"
+// // implement removed functions from qotherheader.h
+// order sections alphabetically
+
+#endif // QT_GUI_REMOVED_SINCE(6, 6)
+
+#if QT_GUI_REMOVED_SINCE(6, 7)
+
+#include "qtextdocument.h"
+
+bool Qt::mightBeRichText(const QString& text)
+{
+ return Qt::mightBeRichText(qToStringViewIgnoringNull(text));
+}
+
+#endif // QT_GUI_REMOVED_SINCE(6, 7)
+
+#if QT_GUI_REMOVED_SINCE(6, 8)
+
+#include "qpagelayout.h"
+
+bool QPageLayout::setMargins(const QMarginsF &margins)
+{
+ return setMargins(margins, OutOfBoundsPolicy::Reject);
+}
+
+bool QPageLayout::setLeftMargin(qreal leftMargin)
+{
+ return setLeftMargin(leftMargin, OutOfBoundsPolicy::Reject);
+}
+
+bool QPageLayout::setRightMargin(qreal rightMargin)
+{
+ return setRightMargin(rightMargin, OutOfBoundsPolicy::Reject);
+}
+
+bool QPageLayout::setTopMargin(qreal topMargin)
+{
+ return setTopMargin(topMargin, OutOfBoundsPolicy::Reject);
+}
+
+// #include "qotherheader.h"
+// // implement removed functions from qotherheader.h
+// order sections alphabetically
+
+#endif // QT_GUI_REMOVED_SINCE(6, 8)
diff --git a/src/gui/configure.cmake b/src/gui/configure.cmake
index d8319c120b..e1d8efb292 100644
--- a/src/gui/configure.cmake
+++ b/src/gui/configure.cmake
@@ -28,7 +28,8 @@ set_property(CACHE INPUT_libpng PROPERTY STRINGS undefined no qt system)
#### Libraries
-qt_set01(X11_SUPPORTED LINUX OR HPUX OR FREEBSD OR NETBSD OR OPENBSD OR SOLARIS OR HURD) # special case
+qt_set01(X11_SUPPORTED LINUX OR HPUX OR FREEBSD OR NETBSD OR OPENBSD OR SOLARIS OR
+ HURD)
qt_find_package(ATSPI2 PROVIDED_TARGETS PkgConfig::ATSPI2 MODULE_NAME gui QMAKE_LIB atspi)
qt_find_package(DirectFB PROVIDED_TARGETS PkgConfig::DirectFB MODULE_NAME gui QMAKE_LIB directfb)
qt_find_package(Libdrm PROVIDED_TARGETS Libdrm::Libdrm MODULE_NAME gui QMAKE_LIB drm)
@@ -57,9 +58,11 @@ qt_find_package(Mtdev PROVIDED_TARGETS PkgConfig::Mtdev MODULE_NAME gui QMAKE_LI
qt_find_package(WrapOpenGL PROVIDED_TARGETS WrapOpenGL::WrapOpenGL MODULE_NAME gui QMAKE_LIB opengl)
qt_find_package(GLESv2 PROVIDED_TARGETS GLESv2::GLESv2 MODULE_NAME gui QMAKE_LIB opengl_es2)
qt_find_package(Tslib PROVIDED_TARGETS PkgConfig::Tslib MODULE_NAME gui QMAKE_LIB tslib)
-qt_find_package(WrapVulkanHeaders PROVIDED_TARGETS WrapVulkanHeaders::WrapVulkanHeaders MODULE_NAME gui QMAKE_LIB vulkan MARK_OPTIONAL) # special case
+qt_find_package(WrapVulkanHeaders PROVIDED_TARGETS WrapVulkanHeaders::WrapVulkanHeaders
+ MODULE_NAME gui QMAKE_LIB vulkan MARK_OPTIONAL)
if((LINUX) OR QT_FIND_ALL_PACKAGES_ALWAYS)
qt_find_package(Wayland PROVIDED_TARGETS Wayland::Server MODULE_NAME gui QMAKE_LIB wayland_server)
+ qt_find_package(Wayland PROVIDED_TARGETS Wayland::Client MODULE_NAME gui QMAKE_LIB wayland_client)
endif()
if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS)
qt_find_package(X11 PROVIDED_TARGETS X11::X11 MODULE_NAME gui QMAKE_LIB xlib)
@@ -140,6 +143,7 @@ if((X11_SUPPORTED) OR QT_FIND_ALL_PACKAGES_ALWAYS)
endif()
qt_add_qmake_lib_dependency(xrender xlib)
+qt_find_package(RenderDoc PROVIDED_TARGETS RenderDoc::RenderDoc)
#### Tests
@@ -230,6 +234,7 @@ EGLDeviceEXT device = 0;
EGLStreamKHR stream = 0;
EGLOutputLayerEXT layer = 0;
(void) EGL_DRM_CRTC_EXT;
+(void) EGL_DRM_MASTER_FD_EXT;
/* END TEST: */
return 0;
}
@@ -277,8 +282,8 @@ qt_config_compile_test(egl_viv
LABEL "i.Mx6 EGL"
LIBRARIES
EGL::EGL
- COMPILE_OPTIONS # special case
- "-DEGL_API_FB=1" # special case
+ COMPILE_OPTIONS
+ "-DEGL_API_FB=1"
CODE
"#include <EGL/egl.h>
#include <EGL/eglvivante.h>
@@ -406,11 +411,9 @@ ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);
")
# opengles3
-# special case begin
if(WASM)
set(extra_compiler_options "-s FULL_ES3=1")
endif()
-# special case end
set(test_libs GLESv2::GLESv2)
if(INTEGRITY AND _qt_igy_gui_libs)
@@ -421,9 +424,7 @@ qt_config_compile_test(opengles3
LABEL "OpenGL ES 3.0"
LIBRARIES
${test_libs}
-# special case begin
COMPILE_OPTIONS ${extra_compiler_options}
-# special case end
CODE
"#ifdef __APPLE__
# include <OpenGLES/ES3/gl.h>
@@ -553,7 +554,6 @@ libinput_event_pointer_get_scroll_value_v120(nullptr, LIBINPUT_POINTER_AXIS_SCRO
}
")
-# special case begin
# directwrite (assumes DirectWrite2)
qt_config_compile_test(directwrite
LABEL "WINDOWS directwrite"
@@ -580,7 +580,7 @@ qt_config_compile_test(directwrite3
int main(int, char **)
{
IUnknown *factory = nullptr;
- DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3),
+ DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory6),
&factory);
return 0;
}
@@ -615,14 +615,27 @@ int main(int, char **)
return 0;
}
")
-# special case end
+
+qt_config_compile_test(renderdoc
+ LIBRARIES
+ RenderDoc::RenderDoc
+ LABEL "RenderDoc header check"
+ CODE
+"#include <renderdoc_app.h>
+int main(int, char **)
+{
+ if (RENDERDOC_Version::eRENDERDOC_API_Version_1_6_0)
+ return 0;
+ return 0;
+}
+")
#### Features
qt_feature("accessibility-atspi-bridge" PUBLIC PRIVATE
LABEL "ATSPI Bridge"
- CONDITION QT_FEATURE_accessibility AND QT_FEATURE_xcb AND QT_FEATURE_dbus AND ATSPI2_FOUND
+ CONDITION QT_FEATURE_accessibility AND QT_FEATURE_dbus AND ATSPI2_FOUND
)
qt_feature_definition("accessibility-atspi-bridge" "QT_NO_ACCESSIBILITY_ATSPI_BRIDGE" NEGATE VALUE "1")
qt_feature("directfb" PRIVATE
@@ -633,21 +646,21 @@ qt_feature("directfb" PRIVATE
)
qt_feature("directwrite" PRIVATE
LABEL "DirectWrite"
- CONDITION TEST_directwrite # special case
+ CONDITION TEST_directwrite
EMIT_IF WIN32
)
qt_feature("directwrite3" PRIVATE
LABEL "DirectWrite 3"
- CONDITION QT_FEATURE_directwrite AND TEST_directwrite3 # special case
+ CONDITION QT_FEATURE_directwrite AND TEST_directwrite3
EMIT_IF WIN32
)
qt_feature("direct2d" PRIVATE
LABEL "Direct 2D"
- CONDITION WIN32 AND NOT WINRT AND TEST_d2d1 # special case
+ CONDITION WIN32 AND NOT WINRT AND TEST_d2d1
)
qt_feature("direct2d1_1" PRIVATE
LABEL "Direct 2D 1.1"
- CONDITION QT_FEATURE_direct2d AND TEST_d2d1_1 # special case
+ CONDITION QT_FEATURE_direct2d AND TEST_d2d1_1
)
qt_feature("evdev" PRIVATE
LABEL "evdev"
@@ -798,6 +811,10 @@ qt_feature("vulkan" PUBLIC
LABEL "Vulkan"
CONDITION QT_FEATURE_library AND QT_FEATURE_vkgen AND WrapVulkanHeaders_FOUND
)
+qt_feature("metal" PUBLIC
+ LABEL "Metal"
+ CONDITION MACOS OR IOS OR VISIONOS
+)
qt_feature("vkkhrdisplay" PRIVATE
SECTION "Platform plugins"
LABEL "VK_KHR_display"
@@ -851,7 +868,7 @@ qt_feature("eglfs_rcar" PRIVATE
)
qt_feature("eglfs_viv_wl" PRIVATE
LABEL "EGLFS i.Mx6 Wayland"
- CONDITION QT_FEATURE_eglfs_viv AND Wayland_FOUND
+ CONDITION QT_FEATURE_eglfs_viv AND TARGET Wayland::Server
)
qt_feature("eglfs_openwfd" PRIVATE
LABEL "EGLFS OpenWFD"
@@ -999,7 +1016,8 @@ qt_feature("system-textmarkdownreader" PUBLIC
qt_feature("textmarkdownwriter" PUBLIC
SECTION "Kernel"
LABEL "MarkdownWriter"
- PURPOSE "Provides a Markdown (CommonMark) writer"
+ CONDITION QT_FEATURE_regularexpression
+ PURPOSE "Provides a Markdown (CommonMark and GitHub) writer"
)
qt_feature("textodfwriter" PUBLIC
SECTION "Kernel"
@@ -1204,6 +1222,7 @@ qt_feature("raster-fp" PRIVATE
SECTION "Painting"
LABEL "QPainter - floating point raster"
PURPOSE "Internal painting support for floating point rasterization."
+ CONDITION NOT VXWORKS # QTBUG-115777
)
qt_feature("undocommand" PUBLIC
SECTION "Utilities"
@@ -1224,7 +1243,19 @@ qt_feature("undogroup" PUBLIC
PURPOSE "Provides the ability to cluster QUndoCommands."
CONDITION QT_FEATURE_undostack
)
+qt_feature("graphicsframecapture" PRIVATE
+ SECTION "Utilities"
+ LABEL "QGraphicsFrameCapture"
+ PURPOSE "Provides a way to capture 3D graphics API calls for a rendered frame."
+ CONDITION TEST_renderdoc OR (MACOS OR IOS)
+)
qt_feature_definition("undogroup" "QT_NO_UNDOGROUP" NEGATE VALUE "1")
+qt_feature("wayland" PUBLIC
+ SECTION "Platform plugins"
+ LABEL "Wayland"
+ CONDITION TARGET Wayland::Client
+)
+
qt_configure_add_summary_section(NAME "Qt Gui")
qt_configure_add_summary_entry(ARGS "accessibility")
qt_configure_add_summary_entry(ARGS "freetype")
@@ -1262,6 +1293,8 @@ qt_configure_add_summary_entry(ARGS "opengles31")
qt_configure_add_summary_entry(ARGS "opengles32")
qt_configure_end_summary_section() # end of "OpenGL" section
qt_configure_add_summary_entry(ARGS "vulkan")
+qt_configure_add_summary_entry(ARGS "metal")
+qt_configure_add_summary_entry(ARGS "graphicsframecapture")
qt_configure_add_summary_entry(ARGS "sessionmanager")
qt_configure_end_summary_section() # end of "Qt Gui" section
qt_configure_add_summary_section(NAME "Features used by QPA backends")
@@ -1316,7 +1349,7 @@ qt_configure_end_summary_section() # end of "GL integrations" section
qt_configure_end_summary_section() # end of "XCB" section
qt_configure_add_summary_section(NAME "Windows")
qt_configure_add_summary_entry(ARGS "direct2d")
-qt_configure_add_summary_entry(ARGS "direct2d1_1") ### special case
+qt_configure_add_summary_entry(ARGS "direct2d1_1")
qt_configure_add_summary_entry(ARGS "directwrite")
qt_configure_add_summary_entry(ARGS "directwrite3")
qt_configure_end_summary_section() # end of "Windows" section
@@ -1339,7 +1372,7 @@ qt_configure_add_report_entry(
qt_configure_add_report_entry(
TYPE ERROR
MESSAGE "The OpenGL functionality tests failed! You might need to modify the OpenGL package search path by setting the OpenGL_DIR CMake variable to the OpenGL library's installation directory."
- CONDITION QT_FEATURE_gui AND NOT WATCHOS AND ( NOT INPUT_opengl STREQUAL 'no' ) AND NOT QT_FEATURE_opengl_desktop AND NOT QT_FEATURE_opengles2 AND NOT QT_FEATURE_opengl_dynamic
+ CONDITION QT_FEATURE_gui AND NOT WATCHOS AND NOT VISIONOS AND ( NOT INPUT_opengl STREQUAL 'no' ) AND NOT QT_FEATURE_opengl_desktop AND NOT QT_FEATURE_opengles2 AND NOT QT_FEATURE_opengl_dynamic
)
qt_configure_add_report_entry(
TYPE WARNING
diff --git a/src/gui/doc/images/qpainter-concentriccircles.png b/src/gui/doc/images/qpainter-concentriccircles.png
index 4889dcd76d..d9489a4162 100644
--- a/src/gui/doc/images/qpainter-concentriccircles.png
+++ b/src/gui/doc/images/qpainter-concentriccircles.png
Binary files differ
diff --git a/src/gui/doc/includes/QtGuiDoc b/src/gui/doc/includes/QtGuiDoc
index 80292141e2..e8fa73786e 100644
--- a/src/gui/doc/includes/QtGuiDoc
+++ b/src/gui/doc/includes/QtGuiDoc
@@ -16,3 +16,8 @@
#include <QtGui/qpa/qplatformscreen_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qkeymapper_p.h>
+
+// rhi
+#include <QtGui/rhi/qrhi.h>
+#include <QtGui/rhi/qshader.h>
+#include <QtGui/rhi/qshaderdescription.h>
diff --git a/src/gui/doc/qtgui.qdocconf b/src/gui/doc/qtgui.qdocconf
index 00dc548d93..b94f11849c 100644
--- a/src/gui/doc/qtgui.qdocconf
+++ b/src/gui/doc/qtgui.qdocconf
@@ -39,6 +39,7 @@ depends += \
qtdoc \
qmake \
qtcmake \
+ qtshadertools \
qttestlib \
qtplatformintegration \
qthelp
@@ -62,6 +63,8 @@ imagedirs += images \
excludefiles += ../kernel/qtestsupport_gui.cpp \
../painting/qdrawhelper_ssse3.cpp
+manifestmeta.highlighted.names = "QtGui/Hello Vulkan Cubes Example"
+
navigation.landingpage = "Qt GUI"
navigation.cppclassespage = "Qt GUI C++ Classes"
@@ -72,5 +75,5 @@ spurious += "Undocumented enum item '.*' in QGradient::Preset"
macro.svgcolor.HTML = "<div style=\"padding:10px;color:#fff;background:\1;\"></div>"
macro.svgcolor.DocBook = "<db:phrase role=\"color:\1\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</db:phrase>"
-# Fail the documentation build if there are more warnings than the limit
+# Enforce zero documentation warnings
warninglimit = 0
diff --git a/src/gui/doc/snippets/code/doc_src_richtext.qdoc b/src/gui/doc/snippets/code/doc_src_richtext.qdoc
index 39e29caa8d..0c69514210 100644
--- a/src/gui/doc/snippets/code/doc_src_richtext.qdoc
+++ b/src/gui/doc/snippets/code/doc_src_richtext.qdoc
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
//! [7]
<meta http-equiv="Content-Type" content="text/html; charset=EUC-JP" />
diff --git a/src/gui/doc/snippets/code/src_gui_image_qicon.cpp b/src/gui/doc/snippets/code/src_gui_image_qicon.cpp
index d446f16c3c..a7f27a7fdd 100644
--- a/src/gui/doc/snippets/code/src_gui_image_qicon.cpp
+++ b/src/gui/doc/snippets/code/src_gui_image_qicon.cpp
@@ -8,7 +8,7 @@ namespace src_gui_image_qicon {
struct MyWidget : public QWidget
{
- void drawIcon(QPainter *painter, QPoint pos);
+ void drawIcon(QPainter *painter, const QRect &rect);
bool isChecked() { return true; }
QIcon icon;
};
@@ -17,9 +17,13 @@ void wrapper0() {
//! [0]
QToolButton *button = new QToolButton;
-button->setIcon(QIcon("open.xpm"));
+button->setIcon(QIcon("open.png"));
//! [0]
+//! [addFile]
+QIcon openIcon("open.png");
+openIcon.addFile("open-disabled.png", QIcon::Disabled);
+//! [addFile]
//! [1]
button->setIcon(QIcon());
@@ -29,29 +33,27 @@ button->setIcon(QIcon());
//! [2]
-void MyWidget::drawIcon(QPainter *painter, QPoint pos)
+void MyWidget::drawIcon(QPainter *painter, const QRect &rect)
{
- QPixmap pixmap = icon.pixmap(QSize(22, 22),
- isEnabled() ? QIcon::Normal
- : QIcon::Disabled,
- isChecked() ? QIcon::On
- : QIcon::Off);
- painter->drawPixmap(pos, pixmap);
+ icon.paint(painter, rect, Qt::AlignCenter, isEnabled() ? QIcon::Normal
+ : QIcon::Disabled,
+ isChecked() ? QIcon::On
+ : QIcon::Off);
}
//! [2]
void wrapper1() {
-//! [3]
-QIcon undoicon = QIcon::fromTheme("edit-undo");
-//! [3]
+//! [fromTheme]
+QIcon undoicon = QIcon::fromTheme(QIcon::ThemeIcon::EditUndo);
+//! [fromTheme]
} // wrapper1
//! [4]
-QIcon undoicon = QIcon::fromTheme("edit-undo", QIcon(":/undo.png"));
+QIcon undoicon = QIcon::fromTheme(QIcon::ThemeIcon::EditUndo, QIcon(":/undo.png"));
//! [4]
diff --git a/src/gui/doc/snippets/code/src_gui_kernel_qapplication.cpp b/src/gui/doc/snippets/code/src_gui_kernel_qapplication.cpp
index ab8521b465..9455cacf1c 100644
--- a/src/gui/doc/snippets/code/src_gui_kernel_qapplication.cpp
+++ b/src/gui/doc/snippets/code/src_gui_kernel_qapplication.cpp
@@ -19,70 +19,6 @@ struct MyWidget
int manhattanLength() { return 0; }
};
-
-//! [0]
-QCoreApplication *createApplication(int &argc, char *argv[])
-{
- for (int i = 1; i < argc; ++i)
- if (!qstrcmp(argv[i], "-no-gui"))
- return new QCoreApplication(argc, argv);
- return new QApplication(argc, argv);
-}
-
-int main(int argc, char *argv[])
-{
- QScopedPointer<QCoreApplication> app(createApplication(argc, argv));
-
- if (qobject_cast<QApplication *>(app.data())) {
- // start GUI version...
- } else {
- // start non-GUI version...
- }
-
- return app->exec();
-}
-//! [0]
-
-
-void wrapper0() {
-
-//! [1]
-QApplication::setStyle(QStyleFactory::create("fusion"));
-//! [1]
-
-} // wrapper0
-
-
-//! [3]
-QSize MyWidget::sizeHint() const
-{
- return QSize(80, 25);
-}
-//! [3]
-
-
-//! [4]
-void showAllHiddenTopLevelWidgets()
-{
- const auto topLevelWidgets = QApplication::topLevelWidgets();
- for (QWidget *widget : topLevelWidgets) {
- if (widget->isHidden())
- widget->show();
- }
-}
-//! [4]
-
-
-//! [5]
-void updateAllWidgets()
-{
- const auto topLevelWidgets = QApplication::topLevelWidgets();
- for (QWidget *widget : topLevelWidgets)
- widget->update();
-}
-//! [5]
-
-
void startTheDrag() {};
void wrapper1() {
MyWidget startPos;
@@ -96,25 +32,6 @@ if ((startPos - currentPos).manhattanLength() >=
startTheDrag();
//! [6]
-
-//! [7]
-QWidget *widget = qApp->widgetAt(x, y);
-if (widget)
- widget = widget->window();
-//! [7]
-
} // wrapper1
-
-void wrapper2() {
-QPoint point;
-
-//! [8]
-QWidget *widget = qApp->widgetAt(point);
-if (widget)
- widget = widget->window();
-//! [8]
-
-
-} // wrapper2
} // src_gui_kernel_qapplication
diff --git a/src/gui/doc/snippets/code/src_gui_kernel_qguiapplication.cpp b/src/gui/doc/snippets/code/src_gui_kernel_qguiapplication.cpp
index e9a2446b91..347b47403e 100644
--- a/src/gui/doc/snippets/code/src_gui_kernel_qguiapplication.cpp
+++ b/src/gui/doc/snippets/code/src_gui_kernel_qguiapplication.cpp
@@ -74,26 +74,4 @@ appname -session id
*/ // wrap snippet 2
-
-void wrapper0() {
-
-
-//! [3]
-const QStringList commands = mySession.restartCommand();
-for (const QString &command : commands)
- do_something(command);
-//! [3]
-
-} // wrapper0
-
-
-void wrapper1() {
-//! [4]
-const QStringList commands = mySession.discardCommand();
-for (const QString &command : mySession.discardCommand())
- do_something(command);
-//! [4]
-
-
-} // wrapper1
} // src_gui_kernel_qguiapplication
diff --git a/src/gui/doc/snippets/code/src_gui_painting_qpainter.cpp b/src/gui/doc/snippets/code/src_gui_painting_qpainter.cpp
index 17436c9de5..cfbf3e44a2 100644
--- a/src/gui/doc/snippets/code/src_gui_painting_qpainter.cpp
+++ b/src/gui/doc/snippets/code/src_gui_painting_qpainter.cpp
@@ -63,6 +63,7 @@ struct MyWidget : public QWidget
void wrapper13();
void wrapper14();
void wrapper15();
+ void concentricCircles();
};
QLine drawingCode;
@@ -97,15 +98,6 @@ struct QPainter {
void setWorldTransform(QTransform matrix, bool);
};
-//! [4]
-void QPainter::rotate(qreal angle)
-{
- QTransform matrix;
- matrix.rotate(angle);
- setWorldTransform(matrix, true);
-}
-//! [4]
-
} // QPainterWrapper
void MyWidget::wrapper1() {
@@ -123,7 +115,7 @@ painter.drawPath(path);
//! [6]
QLineF line(10.0, 80.0, 90.0, 20.0);
-QPainter(this);
+QPainter painter(this);
painter.drawLine(line);
//! [6]
} // MyWidget::wrapper1()
@@ -260,7 +252,7 @@ QRectF target(10.0, 20.0, 80.0, 60.0);
QRectF source(0.0, 0.0, 70.0, 40.0);
QPixmap pixmap(":myPixmap.png");
-QPainter(this);
+QPainter painter(this);
painter.drawPixmap(target, pixmap, source);
//! [16]
@@ -364,4 +356,21 @@ painter.drawRect(rectangle.adjusted(0, 0, -pen.width(), -pen.width()));
} // MyWidget::wrapper15
-} // src_gui_painting_qpainter2
+
+void MyWidget::concentricCircles()
+{
+//! [renderHint]
+ QPainter painter(this);
+ painter.setRenderHint(QPainter::Antialiasing, true);
+//! [renderHint]
+ int diameter = 50;
+//! [floatBased]
+ painter.drawEllipse(QRectF(-diameter / 2.0, -diameter / 2.0, diameter, diameter));
+//! [floatBased]
+//! [intBased]
+ painter.drawEllipse(QRect(-diameter / 2, -diameter / 2, diameter, diameter));
+//! [intBased]
+
+} // MyWidget::concentricCircles
+
+} // src_gui_painting_qpainter2 \ No newline at end of file
diff --git a/src/gui/doc/snippets/code/src_gui_text_qtextdocument.cpp b/src/gui/doc/snippets/code/src_gui_text_qtextdocument.cpp
deleted file mode 100644
index 570728f41d..0000000000
--- a/src/gui/doc/snippets/code/src_gui_text_qtextdocument.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-namespace src_gui_text_qtextdocument {
-
-/* wrap non-code snippet
-
-//! [0]
-<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body>...
-//! [0]
-
-*/ // wrap non-code snippet
-} // src_gui_text_qtextdocument
diff --git a/src/gui/doc/snippets/code/src_gui_util_qdesktopservices.cpp b/src/gui/doc/snippets/code/src_gui_util_qdesktopservices.cpp
index 96c8040eb2..13deb88bc8 100644
--- a/src/gui/doc/snippets/code/src_gui_util_qdesktopservices.cpp
+++ b/src/gui/doc/snippets/code/src_gui_util_qdesktopservices.cpp
@@ -65,15 +65,6 @@ QDesktopServices::openUrl(QUrl("file:///C:/Program Files", QUrl::TolerantMode));
*/ // comment wrapper 2
-
-void wrapper3() {
-//! [6]
-QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) +
- "/data/organization/application";
-//! [6]
-} // wrapper3
-
-
/* comment wrapper 3
//! [7]
<key>com.apple.developer.associated-domains</key>
diff --git a/src/gui/doc/snippets/code/src_gui_vulkan_qvulkanfunctions.cpp b/src/gui/doc/snippets/code/src_gui_vulkan_qvulkanfunctions.cpp
index a83c6eb7f9..700d933f43 100644
--- a/src/gui/doc/snippets/code/src_gui_vulkan_qvulkanfunctions.cpp
+++ b/src/gui/doc/snippets/code/src_gui_vulkan_qvulkanfunctions.cpp
@@ -8,20 +8,18 @@
namespace src_gui_vulkan_qvulkanfunctions {
struct Window {
- void render();
+ void init();
QVulkanInstance *vulkanInstance() { return nullptr; }
};
-VkDevice_T *device = nullptr;
-VkCommandBufferAllocateInfo cmdBufInfo;
-VkCommandBuffer cmdBuf;
//! [0]
-void Window::render()
+void Window::init()
{
QVulkanInstance *inst = vulkanInstance();
QVulkanFunctions *f = inst->functions();
// ...
- VkResult err = f->vkAllocateCommandBuffers(device, &cmdBufInfo, &cmdBuf);
+ uint32_t count = 0;
+ VkResult err = f->vkEnumeratePhysicalDevices(inst->vkInstance(), &count, nullptr);
// ...
}
//! [0]
diff --git a/src/gui/doc/snippets/image/image.cpp b/src/gui/doc/snippets/image/image.cpp
index b1c42d62da..82703c5c0f 100644
--- a/src/gui/doc/snippets/image/image.cpp
+++ b/src/gui/doc/snippets/image/image.cpp
@@ -25,13 +25,6 @@ buffer.open(QIODevice::WriteOnly);
pixmap.save(&buffer, "PNG"); // writes pixmap into bytes in PNG format
//! [1]
-
-//! [2]
-QPixmap alpha("image-with-alpha.png");
-QPixmap alphacopy = alpha;
-alphacopy.setMask(alphacopy.mask());
-//! [2]
-
} // wrapper1
} // image
diff --git a/src/gui/doc/snippets/rhioffscreen/color.frag b/src/gui/doc/snippets/rhioffscreen/color.frag
new file mode 100644
index 0000000000..ad9d953d02
--- /dev/null
+++ b/src/gui/doc/snippets/rhioffscreen/color.frag
@@ -0,0 +1,16 @@
+//! [0]
+#version 440
+
+layout(location = 0) in vec3 v_color;
+layout(location = 0) out vec4 fragColor;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 mvp;
+ float opacity;
+};
+
+void main()
+{
+ fragColor = vec4(v_color * opacity, opacity);
+}
+//! [0]
diff --git a/src/gui/doc/snippets/rhioffscreen/color.vert b/src/gui/doc/snippets/rhioffscreen/color.vert
new file mode 100644
index 0000000000..0010e55561
--- /dev/null
+++ b/src/gui/doc/snippets/rhioffscreen/color.vert
@@ -0,0 +1,18 @@
+//! [0]
+#version 440
+
+layout(location = 0) in vec4 position;
+layout(location = 1) in vec3 color;
+layout(location = 0) out vec3 v_color;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 mvp;
+ float opacity;
+};
+
+void main()
+{
+ v_color = color;
+ gl_Position = mvp * position;
+}
+//! [0]
diff --git a/src/gui/doc/snippets/rhioffscreen/main.cpp b/src/gui/doc/snippets/rhioffscreen/main.cpp
new file mode 100644
index 0000000000..c2c6f74dc1
--- /dev/null
+++ b/src/gui/doc/snippets/rhioffscreen/main.cpp
@@ -0,0 +1,151 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [0]
+#include <QGuiApplication>
+#include <QImage>
+#include <QFile>
+#include <rhi/qrhi.h>
+
+int main(int argc, char **argv)
+{
+ QGuiApplication app(argc, argv);
+
+#if QT_CONFIG(vulkan)
+ QVulkanInstance inst;
+#endif
+ std::unique_ptr<QRhi> rhi;
+#if defined(Q_OS_WIN)
+ QRhiD3D12InitParams params;
+ rhi.reset(QRhi::create(QRhi::D3D12, &params));
+#elif QT_CONFIG(metal)
+ QRhiMetalInitParams params;
+ rhi.reset(QRhi::create(QRhi::Metal, &params));
+#elif QT_CONFIG(vulkan)
+ inst.setExtensions(QRhiVulkanInitParams::preferredInstanceExtensions());
+ if (inst.create()) {
+ QRhiVulkanInitParams params;
+ params.inst = &inst;
+ rhi.reset(QRhi::create(QRhi::Vulkan, &params));
+ } else {
+ qFatal("Failed to create Vulkan instance");
+ }
+#endif
+ if (rhi)
+ qDebug() << rhi->backendName() << rhi->driverInfo();
+ else
+ qFatal("Failed to initialize RHI");
+
+ float rotation = 0.0f;
+ float opacity = 1.0f;
+ int opacityDir = 1;
+
+ std::unique_ptr<QRhiTexture> tex(rhi->newTexture(QRhiTexture::RGBA8,
+ QSize(1280, 720),
+ 1,
+ QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
+ tex->create();
+ std::unique_ptr<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ tex.get() }));
+ std::unique_ptr<QRhiRenderPassDescriptor> rp(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rp.get());
+ rt->create();
+
+ QMatrix4x4 viewProjection = rhi->clipSpaceCorrMatrix();
+ viewProjection.perspective(45.0f, 1280 / 720.f, 0.01f, 1000.0f);
+ viewProjection.translate(0, 0, -4);
+
+ static float vertexData[] = { // Y up, CCW
+ 0.0f, 0.5f, 1.0f, 0.0f, 0.0f,
+ -0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
+ 0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
+ };
+
+ std::unique_ptr<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable,
+ QRhiBuffer::VertexBuffer,
+ sizeof(vertexData)));
+ vbuf->create();
+
+ std::unique_ptr<QRhiBuffer> ubuf(rhi->newBuffer(QRhiBuffer::Dynamic,
+ QRhiBuffer::UniformBuffer,
+ 64 + 4));
+ ubuf->create();
+
+ std::unique_ptr<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings());
+ srb->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0,
+ QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage,
+ ubuf.get())
+ });
+ srb->create();
+
+ std::unique_ptr<QRhiGraphicsPipeline> ps(rhi->newGraphicsPipeline());
+ QRhiGraphicsPipeline::TargetBlend premulAlphaBlend;
+ premulAlphaBlend.enable = true;
+ ps->setTargetBlends({ premulAlphaBlend });
+ static auto getShader = [](const QString &name) {
+ QFile f(name);
+ return f.open(QIODevice::ReadOnly) ? QShader::fromSerialized(f.readAll()) : QShader();
+ };
+ ps->setShaderStages({
+ { QRhiShaderStage::Vertex, getShader(QLatin1String("color.vert.qsb")) },
+ { QRhiShaderStage::Fragment, getShader(QLatin1String("color.frag.qsb")) }
+ });
+ QRhiVertexInputLayout inputLayout;
+ inputLayout.setBindings({
+ { 5 * sizeof(float) }
+ });
+ inputLayout.setAttributes({
+ { 0, 0, QRhiVertexInputAttribute::Float2, 0 },
+ { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) }
+ });
+ ps->setVertexInputLayout(inputLayout);
+ ps->setShaderResourceBindings(srb.get());
+ ps->setRenderPassDescriptor(rp.get());
+ ps->create();
+
+ QRhiCommandBuffer *cb;
+ for (int frame = 0; frame < 20; ++frame) {
+ rhi->beginOffscreenFrame(&cb);
+
+ QRhiResourceUpdateBatch *u = rhi->nextResourceUpdateBatch();
+ if (frame == 0)
+ u->uploadStaticBuffer(vbuf.get(), vertexData);
+
+ QMatrix4x4 mvp = viewProjection;
+ mvp.rotate(rotation, 0, 1, 0);
+ u->updateDynamicBuffer(ubuf.get(), 0, 64, mvp.constData());
+ rotation += 5.0f;
+
+ u->updateDynamicBuffer(ubuf.get(), 64, 4, &opacity);
+ opacity += opacityDir * 0.2f;
+ if (opacity < 0.0f || opacity > 1.0f) {
+ opacityDir *= -1;
+ opacity = qBound(0.0f, opacity, 1.0f);
+ }
+
+ cb->beginPass(rt.get(), Qt::green, { 1.0f, 0 }, u);
+ cb->setGraphicsPipeline(ps.get());
+ cb->setViewport({ 0, 0, 1280, 720 });
+ cb->setShaderResources();
+ const QRhiCommandBuffer::VertexInput vbufBinding(vbuf.get(), 0);
+ cb->setVertexInput(0, 1, &vbufBinding);
+ cb->draw(3);
+ QRhiReadbackResult readbackResult;
+ u = rhi->nextResourceUpdateBatch();
+ u->readBackTexture({ tex.get() }, &readbackResult);
+ cb->endPass(u);
+
+ rhi->endOffscreenFrame();
+
+ QImage image(reinterpret_cast<const uchar *>(readbackResult.data.constData()),
+ readbackResult.pixelSize.width(),
+ readbackResult.pixelSize.height(),
+ QImage::Format_RGBA8888_Premultiplied);
+ if (rhi->isYUpInFramebuffer())
+ image = image.mirrored();
+ image.save(QString::asprintf("frame%d.png", frame));
+ }
+
+ return 0;
+}
+//! [0]
diff --git a/src/gui/doc/snippets/separations/separations.qdoc b/src/gui/doc/snippets/separations/separations.qdoc
index ad670f305a..ee567030bb 100644
--- a/src/gui/doc/snippets/separations/separations.qdoc
+++ b/src/gui/doc/snippets/separations/separations.qdoc
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*
\example painting/separations
diff --git a/src/gui/doc/src/dnd.qdoc b/src/gui/doc/src/dnd.qdoc
index e8276f3465..7a756b304e 100644
--- a/src/gui/doc/src/dnd.qdoc
+++ b/src/gui/doc/src/dnd.qdoc
@@ -335,7 +335,9 @@
For example, we can copy the contents of a QLineEdit to the clipboard
with the following code:
- \snippet ../widgets/widgets/charactermap/mainwindow.cpp 11
+ \code
+ QGuiApplication::clipboard()->setText(lineEdit->text(), QClipboard::Clipboard);
+ \endcode
Data with different MIME types can also be put on the clipboard.
Construct a QMimeData object and set data with setData() function in
@@ -364,8 +366,6 @@
\li \l{draganddrop/draggableicons}{Draggable Icons}
\li \l{draganddrop/draggabletext}{Draggable Text}
\li \l{draganddrop/dropsite}{Drop Site}
- \li \l{draganddrop/fridgemagnets}{Fridge Magnets}
- \li \l{draganddrop/puzzle}{Drag and Drop Puzzle}
\endlist
\section1 Interoperating with Other Applications
diff --git a/src/gui/doc/src/external-resources.qdoc b/src/gui/doc/src/external-resources.qdoc
index 67ba9f3013..16bca2475d 100644
--- a/src/gui/doc/src/external-resources.qdoc
+++ b/src/gui/doc/src/external-resources.qdoc
@@ -29,15 +29,24 @@
/*!
\externalpage https://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
- \title Icon Theme Specification
+ \title Freedesktop Icon Theme Specification
*/
/*!
+ \externalpage https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html
+ \title Freedesktop Icon Naming Specification
+*/
+/*!
\externalpage https://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html#directory_layout
\title Icon Theme Specification - Directory Layout
*/
/*!
+ \externalpage https://freedesktop.org/
+ \title Freedesktop
+*/
+
+/*!
\externalpage https://www.khronos.org/vulkan/
\title Vulkan
*/
diff --git a/src/gui/doc/src/qt6-changes.qdoc b/src/gui/doc/src/qt6-changes.qdoc
index 109a7f1750..60e1bffba8 100644
--- a/src/gui/doc/src/qt6-changes.qdoc
+++ b/src/gui/doc/src/qt6-changes.qdoc
@@ -5,7 +5,7 @@
\page gui-changes-qt6.html
\title Changes to Qt GUI
\ingroup changes-qt-5-to-6
- \brief Migrate Qt GUI to Qt 6.
+ \brief Kernel, Text, Painting, and Utility classes are modified.
Qt 6 is a result of the conscious effort to make the framework more
efficient and easy to use.
@@ -114,4 +114,38 @@
Metal, in addition to OpenGL. On Windows the default choice is Direct 3D,
therefore the removal of ANGLE is alleviated by having support for graphics
APIs other than OpenGL as well.
+
+ \section2 Native clipboard integration
+
+ Qt 5 provided interfaces for integrating platform specific or custom
+ clipboard formats into Qt through \c QMacPasteboardMime in \c QtMacExtras,
+ and \c QWindowsMime from the Windows QPA API. Since Qt 6.6, the
+ equivalent functionality is provided by the classes QUtiMimeConverter for
+ \macos, and the QWindowsMimeConverter for Windows.
+
+ Porting from QWindowsMime to QWindowsMimeConverter requires practically no
+ changes, as the virtual interface is identical. However, in Qt 6 it is no
+ longer needed to register a QWindowsMimeConverter implementation;
+ instantiating the type implicitly registers the converter.
+
+ Porting a QMacPasteboardMime to QUtiMimeConverter requires renaming some of
+ the virtual functions. Note that the \c{QMacPasteboardMime} API used the
+ outdated term \c{flavor} for the native clipboard format on \macos, whereas
+ the platform now uses \c{Uniform Type Identifiers}, i.e. \c{UTI}s, which Qt
+ has adapted for function and parameter names.
+
+ The \c{mimeFor} and \c{flavorFor} functions are replaced by the
+ \l{QUtiMimeConverter::}{mimeForUti} and \l{QUtiMimeConverter::}{utiForMime}
+ implementations, respectively. Those should return the name of the mime
+ type or \c{UTI} that the converter can convert the input format to, so a
+ port usually just involves renaming existing overrides. The
+ \c{convertToMime}, \c{convertFromMime}, and \c{count} functions in
+ QUtiMimeConverter are identical to their QMacPasteboardMime versions.
+
+ The \c{canConvert}, \c{converterName} functions are no longer needed, they
+ are implied by implementation of the above functions, so overrides of those
+ functions can be removed.
+
+ As with the the QWindowsMimeConverter, registration is done by instantiating
+ the type.
*/
diff --git a/src/gui/doc/src/qtgui-overview.qdoc b/src/gui/doc/src/qtgui-overview.qdoc
index ecd34f0e9e..446479c9be 100644
--- a/src/gui/doc/src/qtgui-overview.qdoc
+++ b/src/gui/doc/src/qtgui-overview.qdoc
@@ -51,6 +51,68 @@
that prefer more low-level APIs to text and font handling can use classes
like QRawFont and QGlyphRun.
+ \section1 RHI Graphics
+
+ The Qt Rendering Hardware Interface is an abstraction for hardware accelerated
+ graphics APIs, such as, \l{https://www.khronos.org/opengl/}{OpenGL},
+ \l{https://www.khronos.org/opengles/}{OpenGL ES},
+ \l{https://docs.microsoft.com/en-us/windows/desktop/direct3d}{Direct3D},
+ \l{https://developer.apple.com/metal/}{Metal}, and
+ \l{https://www.khronos.org/vulkan/}{Vulkan}.
+
+ As an alternative to using OpenGL or Vulkan directly to render to a
+ QWindow, \l QRhi and the related classes provide a portable, cross-platform
+ 3D graphics and compute API complemented by a shader conditioning and
+ transpiling pipeline. This way applications can avoid directly depending on
+ a single, and, in some cases, vendor or platform-specific 3D API.
+
+ Below is a list of the main RHI-related classes. These are complemented by
+ a number of additional classes and structs.
+
+ \list
+ \li QRhi
+ \li QShader
+ \li QShaderDescription
+ \li QRhiCommandBuffer
+ \li QRhiResourceUpdateBatch
+ \li QRhiBuffer
+ \li QRhiRenderBuffer
+ \li QRhiTexture
+ \li QRhiSampler
+ \li QRhiTextureRenderTarget
+ \li QRhiShaderResourceBindings
+ \li QRhiGraphicsPipeline
+ \li QRhiComputePipeline
+ \li QRhiSwapChain
+ \endlist
+
+ See the \l{RHI Window Example} for an introductory example of creating a
+ portable, cross-platform application that performs accelerated 3D rendering
+ onto a QWindow using QRhi.
+
+ Working directly with QWindow is the most advanced and often the most
+ flexible way of rendering with the QRhi API. It is the most low-level
+ approach, however, and limited in the sense that Qt's UI technologies,
+ widgets and Qt Quick, are not utilized at all. In many cases applications
+ will rather want to integrate QRhi-based rendering into a widget or Qt
+ Quick-based user interface. QWidget-based applications may choose to embed
+ the window as a native child into the widget hierarchy via
+ QWidget::createWindowContainer(), but in many cases \l QRhiWidget will
+ offer a more convenient enabler to integrate QRhi-based rendering into a
+ widget UI. Qt Quick provides its own set of enablers for extending the
+ 2D/3D scene with QRhi-based custom rendering.
+
+ \note The RHI family of APIs are currently offered with a limited
+ compatibility guarantee, as opposed to regular Qt public APIs. See \l QRhi
+ for details.
+
+ \section1 3D Matrix and Vector Math
+
+ The Qt GUI module also contains a few math classes to aid with the most
+ common mathematical operations related to 3D graphics. These classes
+ include \l {QMatrix4x4}, \l {QVector2D}, \l {QVector3D}, \l {QVector4D},
+ and \l {QQuaternion}.
+
\section1 OpenGL and OpenGL ES Integration
QWindow supports rendering using OpenGL and OpenGL ES, depending on what the
@@ -86,10 +148,6 @@
For more information, see the \l {OpenGL Window Example}.
- The Qt GUI module also contains a few math classes to aid with the most
- common mathematical operations related to 3D graphics. These classes include
- \l {QMatrix4x4}, \l {QVector4D}, and \l {QQuaternion}.
-
A \l {QWindow} created with the \l {QSurface::OpenGLSurface} can be used in
combination with \l QPainter and \l QOpenGLPaintDevice to have OpenGL
hardware-accelerated 2D graphics by sacrificing some of the visual quality.
@@ -104,20 +162,23 @@
On Android, Vulkan headers were added in API level 24 of the NDK.
- Relevant classes:
+ The main relevant classes for low-level Vulkan support are:
\list
- \li QVulkanDeviceFunctions
- \li QVulkanExtension
- \li QVulkanFunctions
- \li QVulkanInfoVector
\li QVulkanInstance
- \li QVulkanWindow
- \li QVulkanWindowRenderer
+ \li QVulkanFunctions
+ \li QVulkanDeviceFunctions
\endlist
+ In addition, \l QVulkanWindow provides a convenience subclass of QWindow
+ that makes it easier to get started with implementing Vulkan-based
+ rendering targeting a QWindow. Using this helper class is completely
+ optional; applications with more advanced Vulkan-based renderers may
+ instead want to use a QWindow with the \l {QSurface::VulkanSurface} type
+ directly.
+
For more information, see the \l{Hello Vulkan Widget Example}
- and the \l {Hello Vulkan Window Example}.
+ and the \l {Hello Vulkan Triangle Example}.
\section1 Drag and Drop
diff --git a/src/gui/doc/src/qtgui.qdoc b/src/gui/doc/src/qtgui.qdoc
index d39fa72221..2a1d69d4d3 100644
--- a/src/gui/doc/src/qtgui.qdoc
+++ b/src/gui/doc/src/qtgui.qdoc
@@ -15,6 +15,23 @@
*/
/*!
+ \module QtGuiPrivate
+ \title Qt GUI Private C++ Classes
+ \qtcmakepackage Gui
+ \qtvariable gui-private
+
+ \brief Provides access to private GUI functionality.
+
+ Use the following CMake commands in your \c {CMakeLists.txt} to access
+ private Qt GUI APIs:
+
+ \badcode
+ find_package(Qt6 REQUIRED COMPONENTS Gui)
+ target_link_libraries(mytarget PRIVATE Qt6::GuiPrivate)
+ \endcode
+*/
+
+/*!
\page qtgui-index.html
\title Qt GUI
@@ -54,6 +71,8 @@
\list
\li \l {Application Windows} {Qt GUI Application Windows}
\li \l {2D Graphics} {Qt GUI 2D Graphics}
+ \li \l {RHI Graphics} {Qt GUI Accelerated 2D and 3D Graphics using the Qt RHI}
+ \li \l {3D Matrix and Vector Math} {Qt GUI Matrix and Vector Math}
\li \l {OpenGL and OpenGL ES Integration}
{Qt GUI OpenGL and OpenGL ES Integration}
\li \l {Vulkan Integration} {Qt GUI Vulkan Integration}
diff --git a/src/gui/doc/src/richtext.qdoc b/src/gui/doc/src/richtext.qdoc
index 5ae7739481..10d9962850 100644
--- a/src/gui/doc/src/richtext.qdoc
+++ b/src/gui/doc/src/richtext.qdoc
@@ -11,10 +11,9 @@
\page richtext.html
\title Rich Text Processing
\brief An overview of Qt's rich text processing, editing and display features.
-
+ \ingroup explanations-ui
\ingroup frameworks-technologies
\ingroup qt-basic-concepts
- \ingroup best-practices
\nextpage Rich Text Document Structure
@@ -839,7 +838,11 @@
\section1 Supported Tags
The following table lists the HTML tags supported by Qt's
- \l{Rich Text Processing}{rich text} engine:
+ \l{Rich Text Processing}{rich text} engine.
+
+ \note The functionality implemented for tags listed below is a subset of
+ the full HTML 4 specification. Not all attributes are supported,
+ see comments for each tag.
\table 70%
\header \li Tag
diff --git a/src/gui/image/qabstractfileiconengine_p.h b/src/gui/image/qabstractfileiconengine_p.h
index cdabdc7b77..99d16d3224 100644
--- a/src/gui/image/qabstractfileiconengine_p.h
+++ b/src/gui/image/qabstractfileiconengine_p.h
@@ -30,6 +30,7 @@ public:
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State) override;
QPixmap scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State, qreal scale) override;
QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
+ bool isNull() override { return false; }
QFileInfo fileInfo() const { return m_fileInfo; }
QPlatformTheme::IconOptions options() const { return m_options; }
diff --git a/src/gui/image/qabstractfileiconprovider.cpp b/src/gui/image/qabstractfileiconprovider.cpp
index c5a51001af..71b6a0b03d 100644
--- a/src/gui/image/qabstractfileiconprovider.cpp
+++ b/src/gui/image/qabstractfileiconprovider.cpp
@@ -229,21 +229,16 @@ QIcon QAbstractFileIconProvider::icon(const QFileInfo &info) const
return result.isNull() ? d->getPlatformThemeIcon(info) : result;
}
-/*!
- Returns the type of the file described by \a info.
-*/
-QString QAbstractFileIconProvider::type(const QFileInfo &info) const
+QString QAbstractFileIconProviderPrivate::getFileType(const QFileInfo &info)
{
- Q_D(const QAbstractFileIconProvider);
if (QFileSystemEntry::isRootPath(info.absoluteFilePath()))
return QGuiApplication::translate("QAbstractFileIconProvider", "Drive");
if (info.isFile()) {
#if QT_CONFIG(mimetype)
- const QMimeType mimeType = d->mimeDatabase.mimeTypeForFile(info);
+ const QMimeType mimeType = QMimeDatabase().mimeTypeForFile(info);
return mimeType.comment().isEmpty() ? mimeType.name() : mimeType.comment();
#else
- Q_UNUSED(d);
return QGuiApplication::translate("QAbstractFileIconProvider", "File");
#endif
}
@@ -273,4 +268,13 @@ QString QAbstractFileIconProvider::type(const QFileInfo &info) const
return QGuiApplication::translate("QAbstractFileIconProvider", "Unknown");
}
+/*!
+ Returns the type of the file described by \a info.
+*/
+
+QString QAbstractFileIconProvider::type(const QFileInfo &info) const
+{
+ return QAbstractFileIconProviderPrivate::getFileType(info);
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/image/qabstractfileiconprovider_p.h b/src/gui/image/qabstractfileiconprovider_p.h
index d2caf05440..f53be0f06c 100644
--- a/src/gui/image/qabstractfileiconprovider_p.h
+++ b/src/gui/image/qabstractfileiconprovider_p.h
@@ -37,6 +37,7 @@ public:
QIcon getIconThemeIcon(const QFileInfo &info) const;
static void clearIconTypeCache();
+ static QString getFileType(const QFileInfo &info);
QAbstractFileIconProvider *q_ptr = nullptr;
QAbstractFileIconProvider::Options options = {};
diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp
index b65ca923e5..798ba7f4b3 100644
--- a/src/gui/image/qbmphandler.cpp
+++ b/src/gui/image/qbmphandler.cpp
@@ -608,7 +608,7 @@ bool qt_write_dib(QDataStream &s, const QImage &image, int bpl, int bpl_bmp, int
if (image.depth() != 32) { // write color table
uchar *color_table = new uchar[4*image.colorCount()];
uchar *rgb = color_table;
- QList<QRgb> c = image.colorTable();
+ const QList<QRgb> c = image.colorTable();
for (int i = 0; i < image.colorCount(); i++) {
*rgb++ = qBlue (c[i]);
*rgb++ = qGreen(c[i]);
diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp
index a46c0ad009..086ac37a07 100644
--- a/src/gui/image/qicon.cpp
+++ b/src/gui/image/qicon.cpp
@@ -25,6 +25,7 @@
#include "private/qhexstring_p.h"
#include "private/qguiapplication_p.h"
+#include "private/qoffsetstringarray_p.h"
#include "qpa/qplatformtheme.h"
#ifndef QT_NO_ICON
@@ -98,6 +99,11 @@ QIconPrivate::QIconPrivate(QIconEngine *e)
{
}
+void QIconPrivate::clearIconCache()
+{
+ qt_cleanup_icon_cache();
+}
+
/*! \internal
Computes the displayDevicePixelRatio for a pixmap.
@@ -164,6 +170,9 @@ static QPixmapIconEngineEntry *bestSizeScaleMatch(const QSize &size, qreal scale
qreal ascore = pa->scale - scale;
qreal bscore = pb->scale - scale;
+ // always prefer positive scores to prevent upscaling
+ if ((ascore < 0) != (bscore < 0))
+ return bscore < 0 ? pa : pb;
// Take the one closest to 0
return (qAbs(ascore) < qAbs(bscore)) ? pa : pb;
}
@@ -343,15 +352,16 @@ QSize QPixmapIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::
QList<QSize> QPixmapIconEngine::availableSizes(QIcon::Mode mode, QIcon::State state)
{
QList<QSize> sizes;
- for (int i = 0; i < pixmaps.size(); ++i) {
- QPixmapIconEngineEntry &pe = pixmaps[i];
- if (pe.size == QSize() && pe.pixmap.isNull()) {
+ for (QPixmapIconEngineEntry &pe : pixmaps) {
+ if (pe.mode != mode || pe.state != state)
+ continue;
+ if (pe.size.isEmpty() && pe.pixmap.isNull()) {
pe.pixmap = QPixmap(pe.fileName);
pe.size = pe.pixmap.size();
}
- if (pe.mode == mode && pe.state == state && !pe.size.isEmpty())
+ if (!pe.size.isEmpty() && !sizes.contains(pe.size))
sizes.push_back(pe.size);
- }
+ }
return sizes;
}
@@ -457,6 +467,11 @@ void QPixmapIconEngine::addFile(const QString &fileName, const QSize &size, QIco
pixmaps += QPixmapIconEngineEntry(abs, size, mode, state);
}
+bool QPixmapIconEngine::isNull()
+{
+ return pixmaps.isEmpty();
+}
+
QString QPixmapIconEngine::key() const
{
return "QPixmapIconEngine"_L1;
@@ -536,15 +551,26 @@ QFactoryLoader *qt_iconEngineFactoryLoader()
A QIcon can generate smaller, larger, active, and disabled pixmaps
from the set of pixmaps it is given. Such pixmaps are used by Qt
- widgets to show an icon representing a particular action.
+ UI components to show an icon representing a particular action.
- The simplest use of QIcon is to create one from a QPixmap file or
- resource, and then use it, allowing Qt to work out all the required
- icon styles and sizes. For example:
+ \section1 Creating an icon from image files
+
+ The simplest way to construct a QIcon is to create one from one or
+ several image files or resources. For example:
\snippet code/src_gui_image_qicon.cpp 0
- To undo a QIcon, simply set a null icon in its place:
+ QIcon can store several images for different states, and Qt will
+ select the image that is the closest match for the action's current
+ state.
+
+ \snippet code/src_gui_image_qicon.cpp addFile
+
+ Qt will generate the required icon styles and sizes when needed,
+ e.g. the pixmap for the QIcon::Disabled state might be generated by
+ graying out one of the provided pixmaps.
+
+ To clear the icon, simply set a null icon in its place:
\snippet code/src_gui_image_qicon.cpp 1
@@ -552,31 +578,54 @@ QFactoryLoader *qt_iconEngineFactoryLoader()
QImageWriter::supportedImageFormats() functions to retrieve a
complete list of the supported file formats.
- When you retrieve a pixmap using pixmap(QSize, Mode, State), and no
- pixmap for this given size, mode and state has been added with
- addFile() or addPixmap(), then QIcon will generate one on the
- fly. This pixmap generation happens in a QIconEngine. The default
- engine scales pixmaps down if required, but never up, and it uses
- the current style to calculate a disabled appearance. By using
- custom icon engines, you can customize every aspect of generated
- icons. With QIconEnginePlugin it is possible to register different
- icon engines for different file suffixes, making it possible for
- third parties to provide additional icon engines to those included
+ \section1 Creating an icon from a theme or icon library
+
+ The most convenient way to construct an icon is by using the
+ \l{QIcon::}{fromTheme()} factory function. Qt implements access to
+ the native icon library on platforms that support the
+ \l {Freedesktop Icon Theme Specification}. Since Qt 6.7, Qt also
+ provides access to the native icon library on macOS, iOS, and
+ Windows 10 and 11. On Android, Qt can access icons from the Material
+ design system as long as the
+ \l{https://github.com/google/material-design-icons/tree/master/font}
+ {MaterialIcons-Regular} font is available on the system, or bundled
+ as a resource at \c{:/qt-project.org/icons/MaterialIcons-Regular.ttf}
+ with the application.
+
+ \snippet code/src_gui_image_qicon.cpp fromTheme
+
+ Applications can use the same theming specification to provide
+ their own icon library. See below for an example theme description
+ and the corresponding directory structure for the image files.
+ Icons from an application-provided theme take precedence over the
+ native icon library.
+
+ In addition, it is possible to provide custom \l {QIconEngine}
+ {icon engines}. This allows applications to customize every aspect
+ of generated icons. With QIconEnginePlugin it is possible to register
+ different icon engines for different file suffixes, making it possible
+ for third parties to provide additional icon engines to those included
with Qt.
- \note Since Qt 4.2, an icon engine that supports SVG is included.
-
\section1 Making Classes that Use QIcon
If you write your own widgets that have an option to set a small
pixmap, consider allowing a QIcon to be set for that pixmap. The
Qt class QToolButton is an example of such a widget.
- Provide a method to set a QIcon, and when you draw the icon, choose
- whichever pixmap is appropriate for the current state of your widget.
- For example:
+ Provide a method to set a QIcon, and paint the QIcon with
+ \l{QIcon::}{paint}, choosing the appropriate parameters based
+ on the current state of your widget. For example:
+
\snippet code/src_gui_image_qicon.cpp 2
+ When you retrieve a pixmap using pixmap(QSize, Mode, State), and no
+ pixmap for this given size, mode and state has been added with
+ addFile() or addPixmap(), then QIcon will generate one on the
+ fly. This pixmap generation happens in a QIconEngine. The default
+ engine scales pixmaps down if required, but never up, and it uses
+ the current style to calculate a disabled appearance.
+
You might also make use of the \c Active mode, perhaps making your
widget \c Active when the mouse is over the widget (see \l
QWidget::enterEvent()), while the mouse is pressed pending the
@@ -590,17 +639,19 @@ QFactoryLoader *qt_iconEngineFactoryLoader()
\section1 High DPI Icons
- There are two ways that QIcon supports \l {High DPI}{high DPI}
- icons: via \l addFile() and \l fromTheme().
+ Icons that are provided by the native icon library are usually based
+ on vector graphics, and will automatically be rendered in the appropriate
+ resolution.
- \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}.
+ When providing your own image files via \l addFile(), then QIcon will
+ use Qt's \l {High Resolution Versions of Images}{"@nx" high DPI syntax}.
+ This is useful if you have your own custom directory structure and do not
+ use follow \l {Freedesktop Icon Theme Specification}.
- 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:
+ When providing an application theme, then you need to follow the Icon Theme
+ Specification to specify which files to use for different resolutions.
+ 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]
@@ -632,8 +683,6 @@ QFactoryLoader *qt_iconEngineFactoryLoader()
│ └── appointment-new.png
└── index.theme
\endcode
-
- \sa {Icons Example}
*/
@@ -1118,6 +1167,10 @@ QString QIcon::name() const
\since 4.6
Sets the search paths for icon themes to \a paths.
+
+ The content of \a paths should follow the theme format
+ documented by setThemeName().
+
\sa themeSearchPaths(), fromTheme(), setThemeName()
*/
void QIcon::setThemeSearchPaths(const QStringList &paths)
@@ -1126,20 +1179,14 @@ void QIcon::setThemeSearchPaths(const QStringList &paths)
}
/*!
- \since 4.6
-
- Returns the search paths for icon themes.
-
- The default value will depend on the platform:
+ \since 4.6
- On X11, the search path will use the XDG_DATA_DIRS environment
- variable if available.
+ Returns the search paths for icon themes.
- By default all platforms will have the resource directory
- \c{:\icons} as a fallback. You can use "rcc -project" to generate a
- resource file from your icon theme.
+ The default search paths will be defined by the platform.
+ All platforms will also have the resource directory \c{:\icons} as a fallback.
- \sa setThemeSearchPaths(), fromTheme(), setThemeName()
+ \sa setThemeSearchPaths(), fromTheme(), setThemeName()
*/
QStringList QIcon::themeSearchPaths()
{
@@ -1151,7 +1198,13 @@ QStringList QIcon::themeSearchPaths()
Returns the fallback search paths for icons.
- The default value will depend on the platform.
+ The fallback search paths are consulted for standalone
+ icon files if the \l{themeName()}{current icon theme}
+ or \l{fallbackThemeName()}{fallback icon theme} do
+ not provide results for an icon lookup.
+
+ If not set, the fallback search paths will be defined
+ by the platform.
\sa setFallbackSearchPaths(), themeSearchPaths()
*/
@@ -1165,7 +1218,12 @@ QStringList QIcon::fallbackSearchPaths()
Sets the fallback search paths for icons to \a paths.
- \note To add some path without replacing existing ones:
+ The fallback search paths are consulted for standalone
+ icon files if the \l{themeName()}{current icon theme}
+ or \l{fallbackThemeName()}{fallback icon theme} do
+ not provide results for an icon lookup.
+
+ For example:
\snippet code/src_gui_image_qicon.cpp 5
@@ -1181,11 +1239,15 @@ void QIcon::setFallbackSearchPaths(const QStringList &paths)
Sets the current icon theme to \a name.
- The \a name should correspond to a directory name in the
- themeSearchPath() containing an index.theme
- file describing its contents.
+ The theme will be will be looked up in themeSearchPaths().
- \sa themeSearchPaths(), themeName()
+ At the moment the only supported icon theme format is the
+ \l{Freedesktop Icon Theme Specification}. The \a name should
+ correspond to a directory name in the themeSearchPath()
+ containing an \c index.theme file describing its contents.
+
+ \sa themeSearchPaths(), themeName(),
+ {Freedesktop Icon Theme Specification}
*/
void QIcon::setThemeName(const QString &name)
{
@@ -1197,8 +1259,12 @@ void QIcon::setThemeName(const QString &name)
Returns the name of the current icon theme.
- On X11, the current icon theme depends on your desktop
- settings. On other platforms it is not set by default.
+ If not set, the current icon theme will be defined by the
+ platform.
+
+ \note Platform icon themes are only implemented on
+ \l{Freedesktop} based systems at the moment, and the
+ icon theme depends on your desktop settings.
\sa setThemeName(), themeSearchPaths(), fromTheme(),
hasThemeIcon()
@@ -1213,8 +1279,12 @@ QString QIcon::themeName()
Returns the name of the fallback icon theme.
- On X11, if not set, the fallback icon theme depends on your desktop
- settings. On other platforms it is not set by default.
+ If not set, the fallback icon theme will be defined by the
+ platform.
+
+ \note Platform fallback icon themes are only implemented on
+ \l{Freedesktop} based systems at the moment, and the
+ icon theme depends on your desktop settings.
\sa setFallbackThemeName(), themeName()
*/
@@ -1228,12 +1298,16 @@ QString QIcon::fallbackThemeName()
Sets the fallback icon theme to \a name.
- The \a name should correspond to a directory name in the
- themeSearchPath() containing an index.theme
- file describing its contents.
+ The fallback icon theme is consulted for icons not provided by
+ the \l{themeName()}{current icon theme}, or if the \l{themeName()}
+ {current icon theme} does not exist.
+
+ The \a name should correspond to theme in the same format
+ as documented by setThemeName(), and will be looked up
+ in themeSearchPaths().
- \note This should be done before creating \l QGuiApplication, to ensure
- correct initialization.
+ \note Fallback icon themes should be set before creating
+ QGuiApplication, to ensure correct initialization.
\sa fallbackThemeName(), themeSearchPaths(), themeName()
*/
@@ -1245,71 +1319,63 @@ void QIcon::setFallbackThemeName(const QString &name)
/*!
\since 4.6
- Returns the QIcon corresponding to \a name in the current
- icon theme.
+ Returns the QIcon corresponding to \a name in the
+ \l{themeName()}{current icon theme}.
- The latest version of the freedesktop icon specification and naming
- specification can be obtained here:
-
- \list
- \li \l{http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html}
- \li \l{http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html}
- \endlist
+ If the current theme does not provide an icon for \a name,
+ the \l{fallbackThemeName()}{fallback icon theme} is consulted,
+ before falling back to looking up standalone icon files in the
+ \l{QIcon::fallbackSearchPaths()}{fallback icon search path}.
+ Finally, the platform's native icon library is consulted.
To fetch an icon from the current icon theme:
- \snippet code/src_gui_image_qicon.cpp 3
-
- \note By default, only X11 will support themed icons. In order to
- use themed icons on Mac and Windows, you will have to bundle a
- compliant theme in one of your themeSearchPaths() and set the
- appropriate themeName().
-
- \note Qt will make use of GTK's icon-theme.cache if present to speed up
- the lookup. These caches can be generated using gtk-update-icon-cache:
- \l{https://developer.gnome.org/gtk3/stable/gtk-update-icon-cache.html}.
+ \snippet code/src_gui_image_qicon.cpp fromTheme
- \note If an icon can't be found in the current theme, then it will be
- searched in fallbackSearchPaths() as an unthemed icon.
+ If an \l{themeName()}{icon theme} has not been explicitly
+ set via setThemeName() a platform defined icon theme will
+ be used.
- \sa themeName(), setThemeName(), themeSearchPaths(), fallbackSearchPaths()
+ \sa themeName(), fallbackThemeName(), setThemeName(), themeSearchPaths(), fallbackSearchPaths(),
+ {Freedesktop Icon Naming Specification}
*/
QIcon QIcon::fromTheme(const QString &name)
{
- if (QIcon *cachedIcon = qtIconCache()->object(name)) {
- if (!cachedIcon->isNull())
- return *cachedIcon;
- qtIconCache()->remove(name);
- }
+ if (QIcon *cachedIcon = qtIconCache()->object(name))
+ return *cachedIcon;
- QIcon icon;
- if (QDir::isAbsolutePath(name)) {
+ if (QDir::isAbsolutePath(name))
return QIcon(name);
- } else {
- QPlatformTheme * const platformTheme = QGuiApplicationPrivate::platformTheme();
- bool hasUserTheme = QIconLoader::instance()->hasUserTheme();
- QIconEngine * const engine = (platformTheme && !hasUserTheme) ? platformTheme->createIconEngine(name)
- : new QIconLoaderEngine(name);
- icon = QIcon(engine);
- if (!icon.isNull())
- qtIconCache()->insert(name, new QIcon(icon));
- }
+ QIcon icon(new QThemeIconEngine(name));
+ qtIconCache()->insert(name, new QIcon(icon));
return icon;
}
/*!
\overload
- Returns the QIcon corresponding to \a name in the current
- icon theme. If no such icon is found in the current theme
- \a fallback is returned instead.
+ Returns the QIcon corresponding to \a name in the
+ \l{themeName()}{current icon theme}.
+
+ If the current theme does not provide an icon for \a name,
+ the \l{fallbackThemeName()}{fallback icon theme} is consulted,
+ before falling back to looking up standalone icon files in the
+ \l{QIcon::fallbackSearchPaths()}{fallback icon search path}.
+ Finally, the platform's native icon library is consulted.
+
+ If no icon is found \a fallback is returned.
+
+ This is useful to provide a guaranteed fallback, regardless of
+ whether the current set of icon themes and fallbacks paths
+ support the requested icon.
- If you want to provide a guaranteed fallback for platforms that
- do not support theme icons, you can use the second argument:
+ For example:
\snippet code/src_gui_image_qicon.cpp 4
+
+ \sa fallbackThemeName(), fallbackSearchPaths()
*/
QIcon QIcon::fromTheme(const QString &name, const QIcon &fallback)
{
@@ -1325,7 +1391,8 @@ QIcon QIcon::fromTheme(const QString &name, const QIcon &fallback)
\since 4.6
Returns \c true if there is an icon available for \a name in the
- current icon theme, otherwise returns \c false.
+ current icon theme or any of the fallbacks, as described by
+ fromTheme(), otherwise returns \c false.
\sa themeSearchPaths(), fromTheme(), setThemeName()
*/
@@ -1336,6 +1403,401 @@ bool QIcon::hasThemeIcon(const QString &name)
return icon.name() == name;
}
+static constexpr auto themeIconMapping = qOffsetStringArray(
+ "address-book-new",
+ "application-exit",
+ "appointment-new",
+ "call-start",
+ "call-stop",
+ "contact-new",
+ "document-new",
+ "document-open",
+ "document-open-recent",
+ "document-page-setup",
+ "document-print",
+ "document-print-preview",
+ "document-properties",
+ "document-revert",
+ "document-save",
+ "document-save-as",
+ "document-send",
+ "edit-clear",
+ "edit-copy",
+ "edit-cut",
+ "edit-delete",
+ "edit-find",
+ "edit-paste",
+ "edit-redo",
+ "edit-select-all",
+ "edit-undo",
+ "folder-new",
+ "format-indent-less",
+ "format-indent-more",
+ "format-justify-center",
+ "format-justify-fill",
+ "format-justify-left",
+ "format-justify-right",
+ "format-text-direction-ltr",
+ "format-text-direction-rtl",
+ "format-text-bold",
+ "format-text-italic",
+ "format-text-underline",
+ "format-text-strikethrough",
+ "go-down",
+ "go-home",
+ "go-next",
+ "go-previous",
+ "go-up",
+ "help-about",
+ "help-faq",
+ "insert-image",
+ "insert-link",
+ "insert-text",
+ "list-add",
+ "list-remove",
+ "mail-forward",
+ "mail-mark-important",
+ "mail-mark-read",
+ "mail-mark-unread",
+ "mail-message-new",
+ "mail-reply-all",
+ "mail-reply-sender",
+ "mail-send",
+ "media-eject",
+ "media-playback-pause",
+ "media-playback-start",
+ "media-playback-stop",
+ "media-record",
+ "media-seek-backward",
+ "media-seek-forward",
+ "media-skip-backward",
+ "media-skip-forward",
+ "object-rotate-left",
+ "object-rotate-right",
+ "process-stop",
+ "system-lock-screen",
+ "system-log-out",
+ "system-search",
+ "system-reboot",
+ "system-shutdown",
+ "tools-check-spelling",
+ "view-fullscreen",
+ "view-refresh",
+ "view-restore",
+ "window-close",
+ "window-new",
+ "zoom-fit-best",
+ "zoom-in",
+ "zoom-out",
+
+ "audio-card",
+ "audio-input-microphone",
+ "battery",
+ "camera-photo",
+ "camera-video",
+ "camera-web",
+ "computer",
+ "drive-harddisk",
+ "drive-optical",
+ "input-gaming",
+ "input-keyboard",
+ "input-mouse",
+ "input-tablet",
+ "media-flash",
+ "media-optical",
+ "media-tape",
+ "multimedia-player",
+ "network-wired",
+ "network-wireless",
+ "phone",
+ "printer",
+ "scanner",
+ "video-display",
+
+ "appointment-missed",
+ "appointment-soon",
+ "audio-volume-high",
+ "audio-volume-low",
+ "audio-volume-medium",
+ "audio-volume-muted",
+ "battery-caution",
+ "battery-low",
+ "dialog-error",
+ "dialog-information",
+ "dialog-password",
+ "dialog-question",
+ "dialog-warning",
+ "folder-drag-accept",
+ "folder-open",
+ "folder-visiting",
+ "image-loading",
+ "image-missing",
+ "mail-attachment",
+ "mail-unread",
+ "mail-read",
+ "mail-replied",
+ "media-playlist-repeat",
+ "media-playlist-shuffle",
+ "network-offline",
+ "printer-printing",
+ "security-high",
+ "security-low",
+ "software-update-available",
+ "software-update-urgent",
+ "sync-error",
+ "sync-synchronizing",
+ "user-available",
+ "user-offline",
+ "weather-clear",
+ "weather-clear-night",
+ "weather-few-clouds",
+ "weather-few-clouds-night",
+ "weather-fog",
+ "weather-showers",
+ "weather-snow",
+ "weather-storm"
+);
+static_assert(QIcon::ThemeIcon::NThemeIcons == QIcon::ThemeIcon(themeIconMapping.count()));
+
+static constexpr QLatin1StringView themeIconName(QIcon::ThemeIcon icon)
+{
+ using ThemeIconIndex = std::underlying_type_t<QIcon::ThemeIcon>;
+ const auto index = static_cast<ThemeIconIndex>(icon);
+ Q_ASSERT(index < themeIconMapping.count());
+ return QLatin1StringView(themeIconMapping.viewAt(index));
+}
+
+/*!
+ \enum QIcon::ThemeIcon
+ \since 6.7
+
+ This enum provides access to icons that are provided by most
+ icon theme implementations.
+
+ \value AddressBookNew The icon for the action to create a new address book.
+ \value ApplicationExit The icon for exiting an application.
+ \value AppointmentNew The icon for the action to create a new appointment.
+ \value CallStart The icon for initiating or accepting a call.
+ \value CallStop The icon for stopping a current call.
+ \value ContactNew The icon for the action to create a new contact.
+ \value DocumentNew The icon for the action to create a new document.
+ \value DocumentOpen The icon for the action to open a document.
+ \value DocumentOpenRecent The icon for the action to open a document that was recently opened.
+ \value DocumentPageSetup The icon for the \e{page setup} action.
+ \value DocumentPrint The icon for the \e{print} action.
+ \value DocumentPrintPreview The icon for the \e{print preview} action.
+ \value DocumentProperties The icon for the action to view the properties of a document.
+ \value DocumentRevert The icon for the action of reverting to a previous version of a document.
+ \value DocumentSave The icon for the \e{save} action.
+ \value DocumentSaveAs The icon for the \e{save as} action.
+ \value DocumentSend The icon for the \e{send} action.
+ \value EditClear The icon for the \e{clear} action.
+ \value EditCopy The icon for the \e{copy} action.
+ \value EditCut The icon for the \e{cut} action.
+ \value EditDelete The icon for the \e{delete} action.
+ \value EditFind The icon for the \e{find} action.
+ \value EditPaste The icon for the \e{paste} action.
+ \value EditRedo The icon for the \e{redo} action.
+ \value EditSelectAll The icon for the \e{select all} action.
+ \value EditUndo The icon for the \e{undo} action.
+ \value FolderNew The icon for creating a new folder.
+ \value FormatIndentLess The icon for the \e{decrease indent formatting} action.
+ \value FormatIndentMore The icon for the \e{increase indent formatting} action.
+ \value FormatJustifyCenter The icon for the \e{center justification formatting} action.
+ \value FormatJustifyFill The icon for the \e{fill justification formatting} action.
+ \value FormatJustifyLeft The icon for the \e{left justification formatting} action.
+ \value FormatJustifyRight The icon for the \e{right justification} action.
+ \value FormatTextDirectionLtr The icon for the \e{left-to-right text formatting} action.
+ \value FormatTextDirectionRtl The icon for the \e{right-to-left formatting} action.
+ \value FormatTextBold The icon for the \e{bold text formatting} action.
+ \value FormatTextItalic The icon for the \e{italic text formatting} action.
+ \value FormatTextUnderline The icon for the \e{underlined text formatting} action.
+ \value FormatTextStrikethrough The icon for the \e{strikethrough text formatting} action.
+ \value GoDown The icon for the \e{go down in a list} action.
+ \value GoHome The icon for the \e{go to home location} action.
+ \value GoNext The icon for the \e{go to the next item in a list} action.
+ \value GoPrevious The icon for the \e{go to the previous item in a list} action.
+ \value GoUp The icon for the \e{go up in a list} action.
+ \value HelpAbout The icon for the \e{About} item in the Help menu.
+ \value HelpFaq The icon for the \e{FAQ} item in the Help menu.
+ \value InsertImage The icon for the \e{insert image} action of an application.
+ \value InsertLink The icon for the \e{insert link} action of an application.
+ \value InsertText The icon for the \e{insert text} action of an application.
+ \value ListAdd The icon for the \e{add to list} action.
+ \value ListRemove The icon for the \e{remove from list} action.
+ \value MailForward The icon for the \e{forward} action.
+ \value MailMarkImportant The icon for the \e{mark as important} action.
+ \value MailMarkRead The icon for the \e{mark as read} action.
+ \value MailMarkUnread The icon for the \e{mark as unread} action.
+ \value MailMessageNew The icon for the \e{compose new mail} action.
+ \value MailReplyAll The icon for the \e{reply to all} action.
+ \value MailReplySender The icon for the \e{reply to sender} action.
+ \value MailSend The icon for the \e{send} action.
+ \value MediaEject The icon for the \e{eject} action of a media player or file manager.
+ \value MediaPlaybackPause The icon for the \e{pause} action of a media player.
+ \value MediaPlaybackStart The icon for the \e{start playback} action of a media player.
+ \value MediaPlaybackStop The icon for the \e{stop} action of a media player.
+ \value MediaRecord The icon for the \e{record} action of a media application.
+ \value MediaSeekBackward The icon for the \e{seek backward} action of a media player.
+ \value MediaSeekForward The icon for the \e{seek forward} action of a media player.
+ \value MediaSkipBackward The icon for the \e{skip backward} action of a media player.
+ \value MediaSkipForward The icon for the \e{skip forward} action of a media player.
+ \value ObjectRotateLeft The icon for the \e{rotate left} action performed on an object.
+ \value ObjectRotateRight The icon for the \e{rotate right} action performed on an object.
+ \value ProcessStop The icon for the \e{stop action in applications with} actions that
+ may take a while to process, such as web page loading in a browser.
+ \value SystemLockScreen The icon for the \e{lock screen} action.
+ \value SystemLogOut The icon for the \e{log out} action.
+ \value SystemSearch The icon for the \e{search} action.
+ \value SystemReboot The icon for the \e{reboot} action.
+ \value SystemShutdown The icon for the \e{shutdown} action.
+ \value ToolsCheckSpelling The icon for the \e{check spelling} action.
+ \value ViewFullscreen The icon for the \e{fullscreen} action.
+ \value ViewRefresh The icon for the \e{refresh} action.
+ \value ViewRestore The icon for leaving the fullscreen view.
+ \value WindowClose The icon for the \e{close window} action.
+ \value WindowNew The icon for the \e{new window} action.
+ \value ZoomFitBest The icon for the \e{best fit} action.
+ \value ZoomIn The icon for the \e{zoom in} action.
+ \value ZoomOut The icon for the \e{zoom out} action.
+
+ \value AudioCard The icon for the audio rendering device.
+ \value AudioInputMicrophone The icon for the microphone audio input device.
+ \value Battery The icon for the system battery device.
+ \value CameraPhoto The icon for a digital still camera devices.
+ \value CameraVideo The icon for a video camera device.
+ \value CameraWeb The icon for a web camera device.
+ \value Computer The icon for the computing device as a whole.
+ \value DriveHarddisk The icon for hard disk drives.
+ \value DriveOptical The icon for optical media drives such as CD and DVD.
+ \value InputGaming The icon for the gaming input device.
+ \value InputKeyboard The icon for the keyboard input device.
+ \value InputMouse The icon for the mousing input device.
+ \value InputTablet The icon for graphics tablet input devices.
+ \value MediaFlash The icon for flash media, such as a memory stick.
+ \value MediaOptical The icon for physical optical media such as CD and DVD.
+ \value MediaTape The icon for generic physical tape media.
+ \value MultimediaPlayer The icon for generic multimedia playing devices.
+ \value NetworkWired The icon for wired network connections.
+ \value NetworkWireless The icon for wireless network connections.
+ \value Phone The icon for phone devices.
+ \value Printer The icon for a printer device.
+ \value Scanner The icon for a scanner device.
+ \value VideoDisplay The icon for the monitor that video gets displayed on.
+
+ \value AppointmentMissed The icon for when an appointment was missed.
+ \value AppointmentSoon The icon for when an appointment will occur soon.
+ \value AudioVolumeHigh The icon used to indicate high audio volume.
+ \value AudioVolumeLow The icon used to indicate low audio volume.
+ \value AudioVolumeMedium The icon used to indicate medium audio volume.
+ \value AudioVolumeMuted The icon used to indicate the muted state for audio playback.
+ \value BatteryCaution The icon used when the battery is below 40%.
+ \value BatteryLow The icon used when the battery is below 20%.
+ \value DialogError The icon used when a dialog is opened to explain an error
+ condition to the user.
+ \value DialogInformation The icon used when a dialog is opened to give information to the
+ user that may be pertinent to the requested action.
+ \value DialogPassword The icon used when a dialog requesting the authentication
+ credentials for a user is opened.
+ \value DialogQuestion The icon used when a dialog is opened to ask a simple question
+ to the user.
+ \value DialogWarning The icon used when a dialog is opened to warn the user of
+ impending issues with the requested action.
+ \value FolderDragAccept The icon used for a folder while an acceptable object is being
+ dragged onto it.
+ \value FolderOpen The icon used for folders, while their contents are being displayed
+ within the same window.
+ \value FolderVisiting The icon used for folders, while their contents are being displayed
+ in another window.
+ \value ImageLoading The icon used while another image is being loaded.
+ \value ImageMissing The icon used when another image could not be loaded.
+ \value MailAttachment The icon for a message that contains attachments.
+ \value MailUnread The icon for an unread message.
+ \value MailRead The icon for a read message.
+ \value MailReplied The icon for a message that has been replied to.
+ \value MediaPlaylistRepeat The icon for the repeat mode of a media player.
+ \value MediaPlaylistShuffle The icon for the shuffle mode of a media player.
+ \value NetworkOffline The icon used to indicate that the device is not connected to the
+ network.
+ \value PrinterPrinting The icon used while a print job is successfully being spooled to a
+ printing device.
+ \value SecurityHigh The icon used to indicate that the security level of an item is
+ known to be high.
+ \value SecurityLow The icon used to indicate that the security level of an item is
+ known to be low.
+ \value SoftwareUpdateAvailable The icon used to indicate that an update is available.
+ \value SoftwareUpdateUrgent The icon used to indicate that an urgent update is available.
+ \value SyncError The icon used when an error occurs while attempting to synchronize
+ data across devices.
+ \value SyncSynchronizing The icon used while data is successfully synchronizing across
+ devices.
+ \value UserAvailable The icon used to indicate that a user is available.
+ \value UserOffline The icon used to indicate that a user is not available.
+ \value WeatherClear The icon used to indicate that the sky is clear.
+ \value WeatherClearNight The icon used to indicate that the sky is clear
+ during the night.
+ \value WeatherFewClouds The icon used to indicate that the sky is partly cloudy.
+ \value WeatherFewCloudsNight The icon used to indicate that the sky is partly cloudy
+ during the night.
+ \value WeatherFog The icon used to indicate that the weather is foggy.
+ \value WeatherShowers The icon used to indicate that rain showers are occurring.
+ \value WeatherSnow The icon used to indicate that snow is falling.
+ \value WeatherStorm The icon used to indicate that the weather is stormy.
+
+ \omitvalue NThemeIcons
+
+ \sa {QIcon#Creating an icon from a theme or icon library},
+ fromTheme()
+*/
+
+/*!
+ \since 6.7
+ \overload
+
+ Returns \c true if there is an icon available for \a icon in the
+ current icon theme or any of the fallbacks, as described by
+ fromTheme(), otherwise returns \c false.
+
+ \sa fromTheme()
+*/
+bool QIcon::hasThemeIcon(QIcon::ThemeIcon icon)
+{
+ return hasThemeIcon(themeIconName(icon));
+}
+
+/*!
+ \fn QIcon QIcon::fromTheme(QIcon::ThemeIcon icon)
+ \fn QIcon QIcon::fromTheme(QIcon::ThemeIcon icon, const QIcon &fallback)
+ \since 6.7
+ \overload
+
+ Returns the QIcon corresponding to \a icon in the
+ \l{themeName()}{current icon theme}.
+
+ If the current theme does not provide an icon for \a icon,
+ the \l{fallbackThemeName()}{fallback icon theme} is consulted,
+ before falling back to looking up standalone icon files in the
+ \l{QIcon::fallbackSearchPaths()}{fallback icon search path}.
+ Finally, the platform's native icon library is consulted.
+
+ If no icon is found and a \a fallback is provided, \a fallback is
+ returned. This is useful to provide a guaranteed fallback, regardless
+ of whether the current set of icon themes and fallbacks paths
+ support the requested icon.
+
+ If no icon is found and no \a fallback is provided, a default
+ constructed, empty QIcon is returned.
+*/
+QIcon QIcon::fromTheme(QIcon::ThemeIcon icon)
+{
+ return fromTheme(themeIconName(icon));
+}
+
+QIcon QIcon::fromTheme(QIcon::ThemeIcon icon, const QIcon &fallback)
+{
+ return fromTheme(themeIconName(icon), fallback);
+}
+
/*!
\since 5.6
@@ -1430,8 +1892,8 @@ QDataStream &operator>>(QDataStream &s, QIcon &icon)
if (key == "QPixmapIconEngine"_L1) {
icon.d = new QIconPrivate(new QPixmapIconEngine);
icon.d->engine->read(s);
- } else if (key == "QIconLoaderEngine"_L1) {
- icon.d = new QIconPrivate(new QIconLoaderEngine());
+ } else if (key == "QIconLoaderEngine"_L1 || key == "QThemeIconEngine"_L1) {
+ icon.d = new QIconPrivate(new QThemeIconEngine);
icon.d->engine->read(s);
} else {
const int index = iceLoader()->indexOf(key);
diff --git a/src/gui/image/qicon.h b/src/gui/image/qicon.h
index 22f63b1ecb..5100ada548 100644
--- a/src/gui/image/qicon.h
+++ b/src/gui/image/qicon.h
@@ -22,6 +22,163 @@ public:
enum Mode { Normal, Disabled, Active, Selected };
enum State { On, Off };
+ enum class ThemeIcon {
+ AddressBookNew,
+ ApplicationExit,
+ AppointmentNew,
+ CallStart,
+ CallStop,
+ ContactNew,
+ DocumentNew,
+ DocumentOpen,
+ DocumentOpenRecent,
+ DocumentPageSetup,
+ DocumentPrint,
+ DocumentPrintPreview,
+ DocumentProperties,
+ DocumentRevert,
+ DocumentSave,
+ DocumentSaveAs,
+ DocumentSend,
+ EditClear,
+ EditCopy,
+ EditCut,
+ EditDelete,
+ EditFind,
+ EditPaste,
+ EditRedo,
+ EditSelectAll,
+ EditUndo,
+ FolderNew,
+ FormatIndentLess,
+ FormatIndentMore,
+ FormatJustifyCenter,
+ FormatJustifyFill,
+ FormatJustifyLeft,
+ FormatJustifyRight,
+ FormatTextDirectionLtr,
+ FormatTextDirectionRtl,
+ FormatTextBold,
+ FormatTextItalic,
+ FormatTextUnderline,
+ FormatTextStrikethrough,
+ GoDown,
+ GoHome,
+ GoNext,
+ GoPrevious,
+ GoUp,
+ HelpAbout,
+ HelpFaq,
+ InsertImage,
+ InsertLink,
+ InsertText,
+ ListAdd,
+ ListRemove,
+ MailForward,
+ MailMarkImportant,
+ MailMarkRead,
+ MailMarkUnread,
+ MailMessageNew,
+ MailReplyAll,
+ MailReplySender,
+ MailSend,
+ MediaEject,
+ MediaPlaybackPause,
+ MediaPlaybackStart,
+ MediaPlaybackStop,
+ MediaRecord,
+ MediaSeekBackward,
+ MediaSeekForward,
+ MediaSkipBackward,
+ MediaSkipForward,
+ ObjectRotateLeft,
+ ObjectRotateRight,
+ ProcessStop,
+ SystemLockScreen,
+ SystemLogOut,
+ SystemSearch,
+ SystemReboot,
+ SystemShutdown,
+ ToolsCheckSpelling,
+ ViewFullscreen,
+ ViewRefresh,
+ ViewRestore,
+ WindowClose,
+ WindowNew,
+ ZoomFitBest,
+ ZoomIn,
+ ZoomOut,
+
+ AudioCard,
+ AudioInputMicrophone,
+ Battery,
+ CameraPhoto,
+ CameraVideo,
+ CameraWeb,
+ Computer,
+ DriveHarddisk,
+ DriveOptical,
+ InputGaming,
+ InputKeyboard,
+ InputMouse,
+ InputTablet,
+ MediaFlash,
+ MediaOptical,
+ MediaTape,
+ MultimediaPlayer,
+ NetworkWired,
+ NetworkWireless,
+ Phone,
+ Printer,
+ Scanner,
+ VideoDisplay,
+
+ AppointmentMissed,
+ AppointmentSoon,
+ AudioVolumeHigh,
+ AudioVolumeLow,
+ AudioVolumeMedium,
+ AudioVolumeMuted,
+ BatteryCaution,
+ BatteryLow,
+ DialogError,
+ DialogInformation,
+ DialogPassword,
+ DialogQuestion,
+ DialogWarning,
+ FolderDragAccept,
+ FolderOpen,
+ FolderVisiting,
+ ImageLoading,
+ ImageMissing,
+ MailAttachment,
+ MailUnread,
+ MailRead,
+ MailReplied,
+ MediaPlaylistRepeat,
+ MediaPlaylistShuffle,
+ NetworkOffline,
+ PrinterPrinting,
+ SecurityHigh,
+ SecurityLow,
+ SoftwareUpdateAvailable,
+ SoftwareUpdateUrgent,
+ SyncError,
+ SyncSynchronizing,
+ UserAvailable,
+ UserOffline,
+ WeatherClear,
+ WeatherClearNight,
+ WeatherFewClouds,
+ WeatherFewCloudsNight,
+ WeatherFog,
+ WeatherShowers,
+ WeatherSnow,
+ WeatherStorm,
+
+ NThemeIcons
+ };
+
QIcon() noexcept;
QIcon(const QPixmap &pixmap);
QIcon(const QIcon &other);
@@ -81,6 +238,10 @@ public:
static QIcon fromTheme(const QString &name, const QIcon &fallback);
static bool hasThemeIcon(const QString &name);
+ static QIcon fromTheme(ThemeIcon icon);
+ static QIcon fromTheme(ThemeIcon icon, const QIcon &fallback);
+ static bool hasThemeIcon(ThemeIcon icon);
+
static QStringList themeSearchPaths();
static void setThemeSearchPaths(const QStringList &searchpath);
diff --git a/src/gui/image/qicon_p.h b/src/gui/image/qicon_p.h
index ab144e61ff..c5bf120620 100644
--- a/src/gui/image/qicon_p.h
+++ b/src/gui/image/qicon_p.h
@@ -42,6 +42,8 @@ public:
int serialNum;
int detach_no;
bool is_mask;
+
+ static void clearIconCache();
};
@@ -82,7 +84,7 @@ public:
QList<QSize> availableSizes(QIcon::Mode mode, QIcon::State state) override;
void addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state) override;
void addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state) override;
-
+ bool isNull() override;
QString key() const override;
QIconEngine *clone() const override;
diff --git a/src/gui/image/qiconengine.cpp b/src/gui/image/qiconengine.cpp
index 49528c7034..78273bdeb3 100644
--- a/src/gui/image/qiconengine.cpp
+++ b/src/gui/image/qiconengine.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qiconengine.h"
+#include "qiconengine_p.h"
#include "qpainter.h"
QT_BEGIN_NAMESPACE
@@ -307,4 +308,78 @@ QPixmap QIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::St
return arg.pixmap;
}
+
+// ------- QProxyIconEngine -----
+
+void QProxyIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
+{
+ proxiedEngine()->paint(painter, rect, mode, state);
+}
+
+QSize QProxyIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state)
+{
+ return proxiedEngine()->actualSize(size, mode, state);
+}
+
+QPixmap QProxyIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
+{
+ return proxiedEngine()->pixmap(size, mode, state);
+}
+
+void QProxyIconEngine::addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state)
+{
+ proxiedEngine()->addPixmap(pixmap, mode, state);
+}
+
+void QProxyIconEngine::addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state)
+{
+ proxiedEngine()->addFile(fileName, size, mode, state);
+}
+
+QString QProxyIconEngine::key() const
+{
+ return proxiedEngine()->key();
+}
+
+QIconEngine *QProxyIconEngine::clone() const
+{
+ return proxiedEngine()->clone();
+}
+
+bool QProxyIconEngine::read(QDataStream &in)
+{
+ return proxiedEngine()->read(in);
+}
+
+bool QProxyIconEngine::write(QDataStream &out) const
+{
+ return proxiedEngine()->write(out);
+}
+
+QList<QSize> QProxyIconEngine::availableSizes(QIcon::Mode mode, QIcon::State state)
+{
+ return proxiedEngine()->availableSizes(mode, state);
+}
+
+QString QProxyIconEngine::iconName()
+{
+ return proxiedEngine()->iconName();
+}
+
+bool QProxyIconEngine::isNull()
+{
+ return proxiedEngine()->isNull();
+}
+
+QPixmap QProxyIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
+{
+ return proxiedEngine()->scaledPixmap(size, mode, state, scale);
+}
+
+void QProxyIconEngine::virtual_hook(int id, void *data)
+{
+ proxiedEngine()->virtual_hook(id, data);
+}
+
+
QT_END_NAMESPACE
diff --git a/src/gui/image/qiconengine_p.h b/src/gui/image/qiconengine_p.h
new file mode 100644
index 0000000000..3cf0998429
--- /dev/null
+++ b/src/gui/image/qiconengine_p.h
@@ -0,0 +1,59 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QICONENGINE_P_H
+#define QICONENGINE_P_H
+
+#include <QtGui/private/qtguiglobal_p.h>
+
+#ifndef QT_NO_ICON
+//
+// 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/QIcon>
+#include <QtGui/QIconEngine>
+
+QT_BEGIN_NAMESPACE
+
+class QIconEngine;
+
+class QProxyIconEngine : public QIconEngine
+{
+public:
+ void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override;
+ QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
+ QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
+
+ void addPixmap(const QPixmap &pixmap, QIcon::Mode mode, QIcon::State state) override;
+ void addFile(const QString &fileName, const QSize &size, QIcon::Mode mode, QIcon::State state) override;
+
+ QString key() const override;
+ QIconEngine *clone() const override;
+ bool read(QDataStream &in) override;
+ bool write(QDataStream &out) const override;
+
+ QList<QSize> availableSizes(QIcon::Mode mode = QIcon::Normal,
+ QIcon::State state = QIcon::Off) override;
+
+ QString iconName() override;
+ bool isNull() override;
+ QPixmap scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale) override;
+
+ void virtual_hook(int id, void *data) override;
+protected:
+ virtual QIconEngine *proxiedEngine() const = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_ICON
+
+#endif // QICONENGINE_P_H
diff --git a/src/gui/image/qiconloader.cpp b/src/gui/image/qiconloader.cpp
index f5ae864746..982b9a26b4 100644
--- a/src/gui/image/qiconloader.cpp
+++ b/src/gui/image/qiconloader.cpp
@@ -14,6 +14,7 @@
#include <QtCore/qmath.h>
#include <QtCore/QList>
#include <QtCore/QDir>
+#include <QtCore/qloggingcategory.h>
#if QT_CONFIG(settings)
#include <QtCore/QSettings>
#endif
@@ -23,6 +24,8 @@
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcIconLoader, "qt.gui.icon.loader")
+
using namespace Qt::StringLiterals;
Q_GLOBAL_STATIC(QIconLoader, iconLoaderInstance)
@@ -90,6 +93,9 @@ void QIconLoader::ensureInitialized()
m_systemTheme = systemFallbackThemeName();
if (qt_iconEngineFactoryLoader()->keyMap().key("svg"_L1, -1) != -1)
m_supportsSvg = true;
+
+ qCDebug(lcIconLoader) << "Initialized icon loader with system theme"
+ << m_systemTheme << "and SVG support" << m_supportsSvg;
}
}
@@ -113,21 +119,45 @@ QIconLoader *QIconLoader::instance()
// icons if the theme has changed.
void QIconLoader::updateSystemTheme()
{
- // Only change if this is not explicitly set by the user
- if (m_userTheme.isEmpty()) {
- QString theme = systemThemeName();
- if (theme.isEmpty())
- theme = fallbackThemeName();
- if (theme != m_systemTheme) {
- m_systemTheme = theme;
- invalidateKey();
- }
- }
+ const QString currentSystemTheme = m_systemTheme;
+ m_systemTheme = systemThemeName();
+ if (m_systemTheme.isEmpty())
+ m_systemTheme = systemFallbackThemeName();
+ if (m_systemTheme != currentSystemTheme)
+ qCDebug(lcIconLoader) << "Updated system theme to" << m_systemTheme;
+ // Invalidate even if the system theme name hasn't changed, as the
+ // theme itself may have changed its underlying icon lookup logic.
+ if (!hasUserTheme())
+ invalidateKey();
+}
+
+void QIconLoader::invalidateKey()
+{
+ // Invalidating the key here will result in QThemeIconEngine
+ // recreating the actual engine the next time the icon is used.
+ // We don't need to clear the QIcon cache itself.
+ m_themeKey++;
+}
+
+QString QIconLoader::themeName() const
+{
+ return m_userTheme.isEmpty() ? m_systemTheme : m_userTheme;
}
void QIconLoader::setThemeName(const QString &themeName)
{
+ if (m_userTheme == themeName)
+ return;
+
+ qCDebug(lcIconLoader) << "Setting user theme name to" << themeName;
+
+ const bool hadUserTheme = hasUserTheme();
m_userTheme = themeName;
+ // if we cleared the user theme, then reset search paths as well,
+ // otherwise we'll keep looking in the user-defined search paths for
+ // a system-provide theme, which will never work.
+ if (!hasUserTheme() && hadUserTheme)
+ setThemeSearchPath(systemIconSearchPaths());
invalidateKey();
}
@@ -138,11 +168,14 @@ QString QIconLoader::fallbackThemeName() const
void QIconLoader::setFallbackThemeName(const QString &themeName)
{
+ qCDebug(lcIconLoader) << "Setting fallback theme name to" << themeName;
m_userFallbackTheme = themeName;
+ invalidateKey();
}
void QIconLoader::setThemeSearchPath(const QStringList &searchPaths)
{
+ qCDebug(lcIconLoader) << "Setting theme search path to" << searchPaths;
m_iconDirs = searchPaths;
themeList.clear();
invalidateKey();
@@ -160,6 +193,7 @@ QStringList QIconLoader::themeSearchPaths() const
void QIconLoader::setFallbackSearchPaths(const QStringList &searchPaths)
{
+ qCDebug(lcIconLoader) << "Setting fallback search path to" << searchPaths;
m_fallbackDirs = searchPaths;
invalidateKey();
}
@@ -324,12 +358,12 @@ QIconTheme::QIconTheme(const QString &themeName)
if (!m_valid) {
themeIndex.setFileName(themeDir + "/index.theme"_L1);
- if (themeIndex.exists())
- m_valid = true;
+ m_valid = themeIndex.exists();
+ qCDebug(lcIconLoader) << "Probing theme file at" << themeIndex.fileName() << m_valid;
}
}
#if QT_CONFIG(settings)
- if (themeIndex.exists()) {
+ if (m_valid) {
const QSettings indexReader(themeIndex.fileName(), QSettings::IniFormat);
const QStringList keys = indexReader.allKeys();
for (const QString &key : keys) {
@@ -358,6 +392,17 @@ QIconTheme::QIconTheme(const QString &themeName)
dirInfo.maxSize = indexReader.value(directoryKey + "/MaxSize"_L1, size).toInt();
dirInfo.scale = indexReader.value(directoryKey + "/Scale"_L1, 1).toInt();
+
+ const QString context = indexReader.value(directoryKey + "/Context"_L1).toString();
+ dirInfo.context = [context]() {
+ if (context == "Applications"_L1)
+ return QIconDirInfo::Applications;
+ else if (context == "MimeTypes"_L1)
+ return QIconDirInfo::MimeTypes;
+ else
+ return QIconDirInfo::UnknownContext;
+ }();
+
m_keyList.append(dirInfo);
}
}
@@ -366,25 +411,42 @@ QIconTheme::QIconTheme(const QString &themeName)
// Parent themes provide fallbacks for missing icons
m_parents = indexReader.value("Icon Theme/Inherits"_L1).toStringList();
m_parents.removeAll(QString());
-
- // Ensure a default platform fallback for all themes
- if (m_parents.isEmpty()) {
- const QString fallback = QIconLoader::instance()->fallbackThemeName();
- if (!fallback.isEmpty())
- m_parents.append(fallback);
- }
-
- // Ensure that all themes fall back to hicolor
- if (!m_parents.contains("hicolor"_L1))
- m_parents.append("hicolor"_L1);
}
#endif // settings
}
+QStringList QIconTheme::parents() const
+{
+ // Respect explicitly declared parents
+ QStringList result = m_parents;
+
+ // Ensure a default fallback for all themes
+ const QString fallback = QIconLoader::instance()->fallbackThemeName();
+ if (!fallback.isEmpty())
+ result.append(fallback);
+
+ // Ensure that all themes fall back to hicolor as the last theme
+ result.removeAll("hicolor"_L1);
+ result.append("hicolor"_L1);
+
+ return result;
+}
+
+QDebug operator<<(QDebug debug, const std::unique_ptr<QIconLoaderEngineEntry> &entry)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote() << entry->filename;
+ return debug;
+}
+
QThemeIconInfo QIconLoader::findIconHelper(const QString &themeName,
const QString &iconName,
- QStringList &visited) const
+ QStringList &visited,
+ DashRule rule) const
{
+ qCDebug(lcIconLoader) << "Finding icon" << iconName << "in theme" << themeName
+ << "skipping" << visited;
+
QThemeIconInfo info;
Q_ASSERT(!themeName.isEmpty());
@@ -394,16 +456,19 @@ QThemeIconInfo QIconLoader::findIconHelper(const QString &themeName,
QIconTheme &theme = themeList[themeName];
if (!theme.isValid()) {
theme = QIconTheme(themeName);
- if (!theme.isValid())
- theme = QIconTheme(fallbackThemeName());
+ if (!theme.isValid()) {
+ qCDebug(lcIconLoader) << "Theme" << themeName << "not found";
+ return info;
+ }
}
const QStringList contentDirs = theme.contentDirs();
QStringView iconNameFallback(iconName);
+ bool searchingGenericFallback = m_iconName.length() > iconName.length();
// Iterate through all icon's fallbacks in current theme
- while (info.entries.empty()) {
+ if (info.entries.empty()) {
const QString svgIconName = iconNameFallback + ".svg"_L1;
const QString pngIconName = iconNameFallback + ".png"_L1;
@@ -435,6 +500,11 @@ QThemeIconInfo QIconLoader::findIconHelper(const QString &themeName,
QString contentDir = contentDirs.at(i) + u'/';
for (int j = 0; j < subDirs.size() ; ++j) {
const QIconDirInfo &dirInfo = subDirs.at(j);
+ if (searchingGenericFallback &&
+ (dirInfo.context == QIconDirInfo::Applications ||
+ dirInfo.context == QIconDirInfo::MimeTypes))
+ continue;
+
const QString subDir = contentDir + dirInfo.path + u'/';
const QString pngPath = subDir + pngIconName;
if (QFile::exists(pngPath)) {
@@ -458,36 +528,47 @@ QThemeIconInfo QIconLoader::findIconHelper(const QString &themeName,
if (!info.entries.empty()) {
info.iconName = iconNameFallback.toString();
- break;
}
-
- // If it's possible - find next fallback for the icon
- const int indexOfDash = iconNameFallback.lastIndexOf(u'-');
- if (indexOfDash == -1)
- break;
-
- iconNameFallback.truncate(indexOfDash);
}
if (info.entries.empty()) {
const QStringList parents = theme.parents();
+ qCDebug(lcIconLoader) << "Did not find matching icons in theme;"
+ << "trying parent themes" << parents
+ << "skipping visited" << visited;
+
// Search recursively through inherited themes
for (int i = 0 ; i < parents.size() ; ++i) {
const QString parentTheme = parents.at(i).trimmed();
if (!visited.contains(parentTheme)) // guard against recursion
- info = findIconHelper(parentTheme, iconName, visited);
+ info = findIconHelper(parentTheme, iconName, visited, QIconLoader::NoFallBack);
if (!info.entries.empty()) // success
break;
}
}
+
+ if (rule == QIconLoader::FallBack && info.entries.empty()) {
+ // If it's possible - find next fallback for the icon
+ const int indexOfDash = iconNameFallback.lastIndexOf(u'-');
+ if (indexOfDash != -1) {
+ qCDebug(lcIconLoader) << "Did not find matching icons in all themes;"
+ << "trying dash fallback";
+ iconNameFallback.truncate(indexOfDash);
+ QStringList _visited;
+ info = findIconHelper(themeName, iconNameFallback.toString(), _visited, QIconLoader::FallBack);
+ }
+ }
+
return info;
}
QThemeIconInfo QIconLoader::lookupFallbackIcon(const QString &iconName) const
{
+ qCDebug(lcIconLoader) << "Looking up fallback icon" << iconName;
+
QThemeIconInfo info;
const QString pngIconName = iconName + ".png"_L1;
@@ -526,64 +607,162 @@ QThemeIconInfo QIconLoader::lookupFallbackIcon(const QString &iconName) const
QThemeIconInfo QIconLoader::loadIcon(const QString &name) const
{
- if (!themeName().isEmpty()) {
- QStringList visited;
- QThemeIconInfo iconInfo = findIconHelper(themeName(), name, visited);
- if (!iconInfo.entries.empty())
- return iconInfo;
+ qCDebug(lcIconLoader) << "Loading icon" << name;
+
+ m_iconName = name;
+ QThemeIconInfo iconInfo;
+ QStringList visitedThemes;
+ if (!themeName().isEmpty())
+ iconInfo = findIconHelper(themeName(), name, visitedThemes, QIconLoader::FallBack);
+
+ if (iconInfo.entries.empty() && !fallbackThemeName().isEmpty())
+ iconInfo = findIconHelper(fallbackThemeName(), name, visitedThemes, QIconLoader::FallBack);
+
+ if (iconInfo.entries.empty())
+ iconInfo = lookupFallbackIcon(name);
+
+ qCDebug(lcIconLoader) << "Resulting icon entries" << iconInfo.entries;
+ return iconInfo;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, QIconEngine *engine)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ if (engine) {
+ debug.noquote() << engine->key() << "(";
+ debug << static_cast<const void *>(engine);
+ if (!engine->isNull())
+ debug.quote() << ", " << engine->iconName();
+ else
+ debug << ", null";
+ debug << ")";
+ } else {
+ debug << "QIconEngine(nullptr)";
+ }
+ return debug;
+}
+#endif
- return lookupFallbackIcon(name);
+QIconEngine *QIconLoader::iconEngine(const QString &iconName) const
+{
+ qCDebug(lcIconLoader) << "Resolving icon engine for icon" << iconName;
+
+ std::unique_ptr<QIconEngine> iconEngine;
+ if (hasUserTheme())
+ iconEngine.reset(new QIconLoaderEngine(iconName));
+ if (!iconEngine || iconEngine->isNull()) {
+ qCDebug(lcIconLoader) << "Icon is not available from theme or fallback theme.";
+ if (auto *platformTheme = QGuiApplicationPrivate::platformTheme()) {
+ qCDebug(lcIconLoader) << "Trying platform engine.";
+ std::unique_ptr<QIconEngine> themeEngine(platformTheme->createIconEngine(iconName));
+ if (themeEngine && !themeEngine->isNull()) {
+ iconEngine = std::move(themeEngine);
+ qCDebug(lcIconLoader) << "Icon provided by platform engine.";
+ }
+ }
}
+ // We need to maintain the invariant that the QIcon has a valid engine
+ if (!iconEngine)
+ iconEngine.reset(new QIconLoaderEngine(iconName));
- return QThemeIconInfo();
+ qCDebug(lcIconLoader) << "Resulting engine" << iconEngine.get();
+ return iconEngine.release();
}
+/*!
+ \internal
+ \class QThemeIconEngine
+ \inmodule QtGui
+
+ \brief A named-based icon engine for providing theme icons.
-// -------- Icon Loader Engine -------- //
+ The engine supports invalidation of prior lookups, e.g. when
+ the platform theme changes or the user sets an explicit icon
+ theme.
+ The actual icon lookup is handed over to an engine provided
+ by QIconLoader::iconEngine().
+*/
-QIconLoaderEngine::QIconLoaderEngine(const QString& iconName)
- : m_iconName(iconName), m_key(0)
+QThemeIconEngine::QThemeIconEngine(const QString& iconName)
+ : QProxyIconEngine()
+ , m_iconName(iconName)
{
}
-QIconLoaderEngine::~QIconLoaderEngine() = default;
+QThemeIconEngine::QThemeIconEngine(const QThemeIconEngine &other)
+ : QProxyIconEngine()
+ , m_iconName(other.m_iconName)
+{
+}
-QIconLoaderEngine::QIconLoaderEngine(const QIconLoaderEngine &other)
- : QIconEngine(other),
- m_iconName(other.m_iconName),
- m_key(0)
+QString QThemeIconEngine::key() const
{
+ // Although we proxy the underlying engine, that's an implementation
+ // detail, so from the point of view of QIcon, and in terms of
+ // serialization, we are the one and only theme icon engine.
+ return u"QThemeIconEngine"_s;
}
-QIconEngine *QIconLoaderEngine::clone() const
+QIconEngine *QThemeIconEngine::clone() const
{
- return new QIconLoaderEngine(*this);
+ return new QThemeIconEngine(*this);
}
-bool QIconLoaderEngine::read(QDataStream &in) {
+bool QThemeIconEngine::read(QDataStream &in) {
in >> m_iconName;
return true;
}
-bool QIconLoaderEngine::write(QDataStream &out) const
+bool QThemeIconEngine::write(QDataStream &out) const
{
out << m_iconName;
return true;
}
-bool QIconLoaderEngine::hasIcon() const
+QIconEngine *QThemeIconEngine::proxiedEngine() const
{
- return !(m_info.entries.empty());
+ const auto *iconLoader = QIconLoader::instance();
+ auto mostRecentThemeKey = iconLoader->themeKey();
+ if (mostRecentThemeKey != m_themeKey) {
+ qCDebug(lcIconLoader) << "Theme key" << mostRecentThemeKey << "is different"
+ << "than cached key" << m_themeKey << "for icon" << m_iconName;
+ m_proxiedEngine.reset(iconLoader->iconEngine(m_iconName));
+ m_themeKey = mostRecentThemeKey;
+ }
+ return m_proxiedEngine.get();
}
-// Lazily load the icon
-void QIconLoaderEngine::ensureLoaded()
+/*!
+ \internal
+ \class QIconLoaderEngine
+ \inmodule QtGui
+
+ \brief An icon engine based on icon entries collected by QIconLoader.
+
+ The design and implementation of QIconLoader is based on
+ the XDG icon specification.
+*/
+
+QIconLoaderEngine::QIconLoaderEngine(const QString& iconName)
+ : m_iconName(iconName)
+ , m_info(QIconLoader::instance()->loadIcon(m_iconName))
{
- if (QIconLoader::instance()->themeKey() != m_key) {
- m_info = QIconLoader::instance()->loadIcon(m_iconName);
- m_key = QIconLoader::instance()->themeKey();
- }
+}
+
+QIconLoaderEngine::~QIconLoaderEngine() = default;
+
+QIconEngine *QIconLoaderEngine::clone() const
+{
+ Q_UNREACHABLE();
+ return nullptr; // Cannot be cloned
+}
+
+bool QIconLoaderEngine::hasIcon() const
+{
+ return !(m_info.entries.empty());
}
void QIconLoaderEngine::paint(QPainter *painter, const QRect &rect,
@@ -691,8 +870,6 @@ QSize QIconLoaderEngine::actualSize(const QSize &size, QIcon::Mode mode,
Q_UNUSED(mode);
Q_UNUSED(state);
- ensureLoaded();
-
QIconLoaderEngineEntry *entry = entryForSize(m_info, size);
if (entry) {
const QIconDirInfo &dir = entry->dir;
@@ -701,7 +878,7 @@ QSize QIconLoaderEngine::actualSize(const QSize &size, QIcon::Mode mode,
} else if (dir.type == QIconDirInfo::Fallback) {
return QIcon(entry->filename).actualSize(size, mode, state);
} else {
- int result = qMin<int>(dir.size, qMin(size.width(), size.height()));
+ int result = qMin<int>(dir.size * dir.scale, qMin(size.width(), size.height()));
return QSize(result, result);
}
}
@@ -761,8 +938,6 @@ QPixmap ScalableEntry::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State
QPixmap QIconLoaderEngine::pixmap(const QSize &size, QIcon::Mode mode,
QIcon::State state)
{
- ensureLoaded();
-
QIconLoaderEngineEntry *entry = entryForSize(m_info, size);
if (entry)
return entry->pixmap(size, mode, state);
@@ -777,19 +952,16 @@ QString QIconLoaderEngine::key() const
QString QIconLoaderEngine::iconName()
{
- ensureLoaded();
return m_info.iconName;
}
bool QIconLoaderEngine::isNull()
{
- ensureLoaded();
return m_info.entries.empty();
}
QPixmap QIconLoaderEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
{
- ensureLoaded();
const int integerScale = qCeil(scale);
QIconLoaderEngineEntry *entry = entryForSize(m_info, size / integerScale, integerScale);
return entry ? entry->pixmap(size, mode, state) : QPixmap();
@@ -799,7 +971,7 @@ QList<QSize> QIconLoaderEngine::availableSizes(QIcon::Mode mode, QIcon::State st
{
Q_UNUSED(mode);
Q_UNUSED(state);
- ensureLoaded();
+
const qsizetype N = qsizetype(m_info.entries.size());
QList<QSize> sizes;
sizes.reserve(N);
diff --git a/src/gui/image/qiconloader_p.h b/src/gui/image/qiconloader_p.h
index cd3227c207..3cfa9381d1 100644
--- a/src/gui/image/qiconloader_p.h
+++ b/src/gui/image/qiconloader_p.h
@@ -22,6 +22,7 @@
#include <QtGui/QIconEngine>
#include <QtGui/QPixmapCache>
#include <private/qicon_p.h>
+#include <private/qiconengine_p.h>
#include <private/qfactoryloader_p.h>
#include <QtCore/QHash>
#include <QtCore/QList>
@@ -37,6 +38,7 @@ class QIconLoader;
struct QIconDirInfo
{
enum Type { Fixed, Scalable, Threshold, Fallback };
+ enum Context { UnknownContext, Applications, MimeTypes };
QIconDirInfo(const QString &_path = QString()) :
path(_path),
size(0),
@@ -44,7 +46,8 @@ struct QIconDirInfo
minSize(0),
threshold(0),
scale(1),
- type(Threshold) {}
+ type(Threshold),
+ context(UnknownContext) {}
QString path;
short size;
short maxSize;
@@ -52,6 +55,7 @@ struct QIconDirInfo
short threshold;
short scale;
Type type;
+ Context context;
};
Q_DECLARE_TYPEINFO(QIconDirInfo, Q_RELOCATABLE_TYPE);
@@ -86,6 +90,27 @@ struct QThemeIconInfo
QString iconName;
};
+class QThemeIconEngine : public QProxyIconEngine
+{
+public:
+ QThemeIconEngine(const QString& iconName = QString());
+ QIconEngine *clone() const override;
+ bool read(QDataStream &in) override;
+ bool write(QDataStream &out) const override;
+
+protected:
+ QIconEngine *proxiedEngine() const override;
+
+private:
+ QThemeIconEngine(const QThemeIconEngine &other);
+ QString key() const override;
+
+ QString m_iconName;
+ mutable uint m_themeKey = 0;
+
+ mutable std::unique_ptr<QIconEngine> m_proxiedEngine;
+};
+
class QIconLoaderEngine : public QIconEngine
{
public:
@@ -96,8 +121,6 @@ public:
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
QIconEngine *clone() const override;
- bool read(QDataStream &in) override;
- bool write(QDataStream &out) const override;
QString iconName() override;
bool isNull() override;
@@ -107,14 +130,13 @@ public:
Q_GUI_EXPORT static QIconLoaderEngineEntry *entryForSize(const QThemeIconInfo &info, const QSize &size, int scale = 1);
private:
+ Q_DISABLE_COPY(QIconLoaderEngine)
+
QString key() const override;
bool hasIcon() const;
- void ensureLoaded();
- QIconLoaderEngine(const QIconLoaderEngine &other);
- QThemeIconInfo m_info;
QString m_iconName;
- uint m_key;
+ QThemeIconInfo m_info;
friend class QIconLoader;
};
@@ -126,7 +148,7 @@ class QIconTheme
public:
QIconTheme(const QString &name);
QIconTheme() : m_valid(false) {}
- QStringList parents() { return m_parents; }
+ QStringList parents() const;
QList<QIconDirInfo> keyList() { return m_keyList; }
QStringList contentDirs() { return m_contentDirs; }
bool isValid() { return m_valid; }
@@ -146,7 +168,7 @@ public:
QThemeIconInfo loadIcon(const QString &iconName) const;
uint themeKey() const { return m_themeKey; }
- QString themeName() const { return m_userTheme.isEmpty() ? m_systemTheme : m_userTheme; }
+ QString themeName() const;
void setThemeName(const QString &themeName);
QString fallbackThemeName() const;
void setFallbackThemeName(const QString &themeName);
@@ -158,14 +180,18 @@ public:
QIconDirInfo dirInfo(int dirindex);
static QIconLoader *instance();
void updateSystemTheme();
- void invalidateKey() { m_themeKey++; }
+ void invalidateKey();
void ensureInitialized();
bool hasUserTheme() const { return !m_userTheme.isEmpty(); }
+ QIconEngine *iconEngine(const QString &iconName) const;
+
private:
+ enum DashRule { FallBack, NoFallBack };
QThemeIconInfo findIconHelper(const QString &themeName,
const QString &iconName,
- QStringList &visited) const;
+ QStringList &visited,
+ DashRule rule) const;
QThemeIconInfo lookupFallbackIcon(const QString &iconName) const;
uint m_themeKey;
@@ -178,6 +204,7 @@ private:
mutable QStringList m_iconDirs;
mutable QHash <QString, QIconTheme> themeList;
mutable QStringList m_fallbackDirs;
+ mutable QString m_iconName;
};
QT_END_NAMESPACE
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index dc2d936fda..3bbf21320e 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <limits.h>
#include <qpa/qplatformpixmap.h>
+#include <private/qcolorspace_p.h>
#include <private/qcolortransform_p.h>
#include <private/qmemrotate_p.h>
#include <private/qimagescale_p.h>
@@ -45,6 +46,7 @@
#include <memory>
QT_BEGIN_NAMESPACE
+class QCmyk32;
using namespace Qt::StringLiterals;
@@ -304,6 +306,7 @@ bool QImageData::checkForAlphaPixels() const
case QImage::Format_RGBX64:
case QImage::Format_RGBX16FPx4:
case QImage::Format_RGBX32FPx4:
+ case QImage::Format_CMYK8888:
break;
case QImage::Format_Invalid:
case QImage::NImageFormats:
@@ -360,7 +363,7 @@ bool QImageData::checkForAlphaPixels() const
refer to the \l{How to Create Qt Plugins}{Plugin HowTo}.
\warning Painting on a QImage with the format
- QImage::Format_Indexed8 is not supported.
+ QImage::Format_Indexed8 or QImage::Format_CMYK8888 is not supported.
\tableofcontents
@@ -616,8 +619,8 @@ bool QImageData::checkForAlphaPixels() const
\endtable
- \sa QImageReader, QImageWriter, QPixmap, QSvgRenderer, {Image Composition Example},
- {Image Viewer Example}, {Scribble Example}, {Pixelator Example}
+ \sa QImageReader, QImageWriter, QPixmap, QSvgRenderer,
+ {Image Composition Example}, {Scribble Example}
*/
/*!
@@ -710,40 +713,62 @@ bool QImageData::checkForAlphaPixels() const
The unused bits are always zero.
\value Format_ARGB4444_Premultiplied The image is stored using a
premultiplied 16-bit ARGB format (4-4-4-4).
- \value Format_RGBX8888 The image is stored using a 32-bit byte-ordered RGB(x) format (8-8-8-8).
- This is the same as the Format_RGBA8888 except alpha must always be 255. (added in Qt 5.2)
- \value Format_RGBA8888 The image is stored using a 32-bit byte-ordered RGBA format (8-8-8-8).
+ \value [since 5.2]
+ Format_RGBX8888 The image is stored using a 32-bit byte-ordered RGB(x) format (8-8-8-8).
+ This is the same as the Format_RGBA8888 except alpha must always be 255.
+ \value [since 5.2]
+ Format_RGBA8888 The image is stored using a 32-bit byte-ordered RGBA format (8-8-8-8).
Unlike ARGB32 this is a byte-ordered format, which means the 32bit
encoding differs between big endian and little endian architectures,
being respectively (0xRRGGBBAA) and (0xAABBGGRR). The order of the colors
- is the same on any architecture if read as bytes 0xRR,0xGG,0xBB,0xAA. (added in Qt 5.2)
- \value Format_RGBA8888_Premultiplied The image is stored using a
- premultiplied 32-bit byte-ordered RGBA format (8-8-8-8). (added in Qt 5.2)
- \value Format_BGR30 The image is stored using a 32-bit BGR format (x-10-10-10). (added in Qt 5.4)
- \value Format_A2BGR30_Premultiplied The image is stored using a 32-bit premultiplied ABGR format (2-10-10-10). (added in Qt 5.4)
- \value Format_RGB30 The image is stored using a 32-bit RGB format (x-10-10-10). (added in Qt 5.4)
- \value Format_A2RGB30_Premultiplied The image is stored using a 32-bit premultiplied ARGB format (2-10-10-10). (added in Qt 5.4)
- \value Format_Alpha8 The image is stored using an 8-bit alpha only format. (added in Qt 5.5)
- \value Format_Grayscale8 The image is stored using an 8-bit grayscale format. (added in Qt 5.5)
- \value Format_Grayscale16 The image is stored using an 16-bit grayscale format. (added in Qt 5.13)
- \value Format_RGBX64 The image is stored using a 64-bit halfword-ordered RGB(x) format (16-16-16-16).
- This is the same as the Format_RGBA64 except alpha must always be 65535. (added in Qt 5.12)
- \value Format_RGBA64 The image is stored using a 64-bit halfword-ordered RGBA format (16-16-16-16). (added in Qt 5.12)
- \value Format_RGBA64_Premultiplied The image is stored using a premultiplied 64-bit halfword-ordered
- RGBA format (16-16-16-16). (added in Qt 5.12)
- \value Format_BGR888 The image is stored using a 24-bit BGR format. (added in Qt 5.14)
- \value Format_RGBX16FPx4 The image is stored using a 4 16-bit halfword floating point RGBx format (16FP-16FP-16FP-16FP).
- This is the same as the Format_RGBA16FPx4 except alpha must always be 1.0. (added in Qt 6.2)
- \value Format_RGBA16FPx4 The image is stored using a 4 16-bit halfword floating point RGBA format (16FP-16FP-16FP-16FP). (added in Qt 6.2)
- \value Format_RGBA16FPx4_Premultiplied The image is stored using a premultiplied 4 16-bit halfword floating point
- RGBA format (16FP-16FP-16FP-16FP). (added in Qt 6.2)
- \value Format_RGBX32FPx4 The image is stored using a 4 32-bit floating point RGBx format (32FP-32FP-32FP-32FP).
- This is the same as the Format_RGBA32FPx4 except alpha must always be 1.0. (added in Qt 6.2)
- \value Format_RGBA32FPx4 The image is stored using a 4 32-bit floating point RGBA format (32FP-32FP-32FP-32FP). (added in Qt 6.2)
- \value Format_RGBA32FPx4_Premultiplied The image is stored using a premultiplied 4 32-bit floating point
- RGBA format (32FP-32FP-32FP-32FP). (added in Qt 6.2)
-
- \note Drawing into a QImage with QImage::Format_Indexed8 is not
+ is the same on any architecture if read as bytes 0xRR,0xGG,0xBB,0xAA.
+ \value [since 5.2]
+ Format_RGBA8888_Premultiplied The image is stored using a
+ premultiplied 32-bit byte-ordered RGBA format (8-8-8-8).
+ \value [since 5.4]
+ Format_BGR30 The image is stored using a 32-bit BGR format (x-10-10-10).
+ \value [since 5.4]
+ Format_A2BGR30_Premultiplied The image is stored using a 32-bit premultiplied ABGR format (2-10-10-10).
+ \value [since 5.4]
+ Format_RGB30 The image is stored using a 32-bit RGB format (x-10-10-10).
+ \value [since 5.4]
+ Format_A2RGB30_Premultiplied The image is stored using a 32-bit premultiplied ARGB format (2-10-10-10).
+ \value [since 5.5]
+ Format_Alpha8 The image is stored using an 8-bit alpha only format.
+ \value [since 5.5]
+ Format_Grayscale8 The image is stored using an 8-bit grayscale format.
+ \value [since 5.13]
+ Format_Grayscale16 The image is stored using an 16-bit grayscale format.
+ \value [since 5.12]
+ Format_RGBX64 The image is stored using a 64-bit halfword-ordered RGB(x) format (16-16-16-16).
+ This is the same as the Format_RGBA64 except alpha must always be 65535.
+ \value [since 5.12]
+ Format_RGBA64 The image is stored using a 64-bit halfword-ordered RGBA format (16-16-16-16).
+ \value [since 5.12]
+ Format_RGBA64_Premultiplied The image is stored using a premultiplied 64-bit halfword-ordered
+ RGBA format (16-16-16-16).
+ \value [since 5.14]
+ Format_BGR888 The image is stored using a 24-bit BGR format.
+ \value [since 6.2]
+ Format_RGBX16FPx4 The image is stored using a four 16-bit halfword floating point RGBx format (16FP-16FP-16FP-16FP).
+ This is the same as the Format_RGBA16FPx4 except alpha must always be 1.0.
+ \value [since 6.2]
+ Format_RGBA16FPx4 The image is stored using a four 16-bit halfword floating point RGBA format (16FP-16FP-16FP-16FP).
+ \value [since 6.2]
+ Format_RGBA16FPx4_Premultiplied The image is stored using a premultiplied four 16-bit halfword floating point
+ RGBA format (16FP-16FP-16FP-16FP).
+ \value [since 6.2]
+ Format_RGBX32FPx4 The image is stored using a four 32-bit floating point RGBx format (32FP-32FP-32FP-32FP).
+ This is the same as the Format_RGBA32FPx4 except alpha must always be 1.0.
+ \value [since 6.2]
+ Format_RGBA32FPx4 The image is stored using a four 32-bit floating point RGBA format (32FP-32FP-32FP-32FP).
+ \value [since 6.2]
+ Format_RGBA32FPx4_Premultiplied The image is stored using a premultiplied four 32-bit floating point
+ RGBA format (32FP-32FP-32FP-32FP).
+ \value [since 6.8]
+ Format_CMYK8888 The image is stored using a 32-bit byte-ordered CMYK format.
+
+ \note Drawing into a QImage with format QImage::Format_Indexed8 or QImage::Format_CMYK8888 is not
supported.
\note Avoid most rendering directly to most of these formats using QPainter. Rendering
@@ -819,7 +844,7 @@ QImageData *QImageData::create(uchar *data, int width, int height, qsizetype bp
// recalculate the total with this value
params.bytesPerLine = bpl;
- if (mul_overflow<qsizetype>(bpl, height, &params.totalSize))
+ if (qMulOverflow<qsizetype>(bpl, height, &params.totalSize))
return nullptr;
}
@@ -1147,9 +1172,10 @@ static void copyPhysicalMetadata(QImageData *dst, const QImageData *src)
static void copyMetadata(QImageData *dst, const QImageData *src)
{
- // Doesn't copy colortable and alpha_clut, or offset.
+ // Doesn't copy colortable and alpha_clut.
copyPhysicalMetadata(dst, src);
dst->text = src->text;
+ dst->offset = src->offset;
dst->colorSpace = src->colorSpace;
}
@@ -1214,7 +1240,6 @@ QImage Q_TRACE_INSTRUMENT(qtgui) QImage::copy(const QRect& r) const
} else
memcpy(image.bits(), bits(), d->nbytes);
image.d->colortable = d->colortable;
- image.d->offset = d->offset;
image.d->has_alpha_clut = d->has_alpha_clut;
copyMetadata(image.d, d);
return image;
@@ -1303,7 +1328,6 @@ QImage Q_TRACE_INSTRUMENT(qtgui) QImage::copy(const QRect& r) const
}
copyMetadata(image.d, d);
- image.d->offset = offset();
image.d->has_alpha_clut = d->has_alpha_clut;
return image;
}
@@ -2203,7 +2227,6 @@ QImage QImage::convertToFormat_helper(Format format, Qt::ImageConversionFlags fl
QIMAGE_SANITYCHECK_MEMORY(image);
- image.d->offset = offset();
copyMetadata(image.d, d);
converter(image.d, d, flags);
@@ -2633,6 +2656,9 @@ void QImage::setPixel(int x, int y, uint index_or_rgb)
case Format_A2RGB30_Premultiplied:
((uint *)s)[x] = qConvertArgb32ToA2rgb30<PixelOrderRGB>(index_or_rgb);
return;
+ case Format_RGBX64:
+ ((QRgba64 *)s)[x] = QRgba64::fromArgb32(index_or_rgb | 0xff000000);
+ return;
case Format_RGBA64:
case Format_RGBA64_Premultiplied:
((QRgba64 *)s)[x] = QRgba64::fromArgb32(index_or_rgb);
@@ -3900,10 +3926,15 @@ bool QImage::save(QIODevice* device, const char* format, int quality) const
bool QImageData::doImageIO(const QImage *image, QImageWriter *writer, int quality) const
{
if (quality > 100 || quality < -1)
- qWarning("QPixmap::save: Quality out of range [-1, 100]");
+ qWarning("QImage::save: Quality out of range [-1, 100]");
if (quality >= 0)
writer->setQuality(qMin(quality,100));
- return writer->write(*image);
+ const bool result = writer->write(*image);
+#ifdef QT_DEBUG
+ if (!result)
+ qWarning("QImage::save: failed to write image - %s", qPrintable(writer->errorString()));
+#endif
+ return result;
}
/*****************************************************************************
@@ -4857,14 +4888,24 @@ QImage Q_TRACE_INSTRUMENT(qtgui) QImage::transformed(const QTransform &matrix, Q
|| (ws * hs) >= (1<<20)
#endif
) {
+ QImage scaledImage;
if (mat.m11() < 0.0F && mat.m22() < 0.0F) { // horizontal/vertical flip
- return smoothScaled(wd, hd).mirrored(true, true).convertToFormat(format());
+ scaledImage = smoothScaled(wd, hd).mirrored(true, true);
} else if (mat.m11() < 0.0F) { // horizontal flip
- return smoothScaled(wd, hd).mirrored(true, false).convertToFormat(format());
+ scaledImage = smoothScaled(wd, hd).mirrored(true, false);
} else if (mat.m22() < 0.0F) { // vertical flip
- return smoothScaled(wd, hd).mirrored(false, true).convertToFormat(format());
+ scaledImage = smoothScaled(wd, hd).mirrored(false, true);
} else { // no flipping
- return smoothScaled(wd, hd).convertToFormat(format());
+ scaledImage = smoothScaled(wd, hd);
+ }
+
+ switch (format()) {
+ case QImage::Format_Mono:
+ case QImage::Format_MonoLSB:
+ case QImage::Format_Indexed8:
+ return scaledImage;
+ default:
+ return scaledImage.convertToFormat(format());
}
}
}
@@ -4906,7 +4947,14 @@ QImage Q_TRACE_INSTRUMENT(qtgui) QImage::transformed(const QTransform &matrix, Q
if (target_format >= QImage::Format_RGB32) {
// Prevent QPainter from applying devicePixelRatio corrections
- const QImage sImage = (devicePixelRatio() != 1) ? QImage(constBits(), width(), height(), format()) : *this;
+ QImage sImage = (devicePixelRatio() != 1) ? QImage(constBits(), width(), height(), format()) : *this;
+ if (sImage.d != d
+ && (d->format == QImage::Format_MonoLSB
+ || d->format == QImage::Format_Mono
+ || d->format == QImage::Format_Indexed8)) {
+ sImage.d->colortable = d->colortable;
+ sImage.d->has_alpha_clut = d->has_alpha_clut;
+ }
Q_ASSERT(sImage.devicePixelRatio() == 1);
Q_ASSERT(sImage.devicePixelRatio() == dImage.devicePixelRatio());
@@ -4976,6 +5024,9 @@ void QImage::setColorSpace(const QColorSpace &colorSpace)
return;
if (d->colorSpace == colorSpace)
return;
+ if (colorSpace.isValid() && !qt_compatibleColorModel(pixelFormat().colorModel(), colorSpace.colorModel()))
+ return;
+
detachMetadata(false);
if (d)
d->colorSpace = colorSpace;
@@ -4988,21 +5039,60 @@ void QImage::setColorSpace(const QColorSpace &colorSpace)
If the image has no valid color space, the method does nothing.
+ \note If \a colorSpace is not compatible with the current format, the image
+ will be converted to one that is.
+
\sa convertedToColorSpace(), setColorSpace()
*/
void QImage::convertToColorSpace(const QColorSpace &colorSpace)
{
- if (!d)
- return;
- if (!d->colorSpace.isValid())
+ if (!d || !d->colorSpace.isValid())
return;
- if (!colorSpace.isValid()) {
+ if (!colorSpace.isValidTarget()) {
qWarning() << "QImage::convertToColorSpace: Output colorspace is not valid";
return;
}
if (d->colorSpace == colorSpace)
return;
+ if (!qt_compatibleColorModel(pixelFormat().colorModel(), colorSpace.colorModel())) {
+ *this = convertedToColorSpace(colorSpace);
+ return;
+ }
applyColorTransform(d->colorSpace.transformationToColorSpace(colorSpace));
+ if (d->ref.loadRelaxed() != 1)
+ detachMetadata(false);
+ d->colorSpace = colorSpace;
+}
+
+/*!
+ \since 6.8
+
+ Converts the image to \a colorSpace and \a format.
+
+ If the image has no valid color space, the method does nothing,
+ nor if the color space is not compatible with with the format.
+
+ The specified image conversion \a flags control how the image data
+ is handled during the format conversion process.
+
+ \sa convertedToColorSpace(), setColorSpace()
+*/
+void QImage::convertToColorSpace(const QColorSpace &colorSpace, QImage::Format format, Qt::ImageConversionFlags flags)
+{
+ if (!d || !d->colorSpace.isValid())
+ return;
+ if (!colorSpace.isValidTarget()) {
+ qWarning() << "QImage::convertToColorSpace: Output colorspace is not valid";
+ return;
+ }
+ if (!qt_compatibleColorModel(toPixelFormat(format).colorModel(), colorSpace.colorModel())) {
+ qWarning() << "QImage::convertToColorSpace: Color space is not compatible with format";
+ return;
+ }
+
+ if (d->colorSpace == colorSpace)
+ return convertTo(format, flags);
+ applyColorTransform(d->colorSpace.transformationToColorSpace(colorSpace), format, flags);
d->colorSpace = colorSpace;
}
@@ -5013,16 +5103,56 @@ void QImage::convertToColorSpace(const QColorSpace &colorSpace)
If the image has no valid color space, a null QImage is returned.
- \sa convertToColorSpace()
+ \note If \a colorSpace is not compatible with the current format,
+ the returned image will also be converted to a format this is.
+ For more control over returned image format, see the three argument
+ overload of this method.
+
+ \sa convertToColorSpace(), colorTransformed()
*/
QImage QImage::convertedToColorSpace(const QColorSpace &colorSpace) const
{
- if (!d || !d->colorSpace.isValid() || !colorSpace.isValid())
+ if (!d || !d->colorSpace.isValid())
return QImage();
+ if (!colorSpace.isValidTarget()) {
+ qWarning() << "QImage::convertedToColorSpace: Output colorspace is not valid";
+ return QImage();
+ }
if (d->colorSpace == colorSpace)
return *this;
- QImage image = copy();
- image.convertToColorSpace(colorSpace);
+ QImage image = colorTransformed(d->colorSpace.transformationToColorSpace(colorSpace));
+ image.setColorSpace(colorSpace);
+ return image;
+}
+
+/*!
+ \since 6.8
+
+ Returns the image converted to \a colorSpace and \a format.
+
+ If the image has no valid color space, a null QImage is returned.
+
+ The specified image conversion \a flags control how the image data
+ is handled during the format conversion process.
+
+ \sa colorTransformed()
+*/
+QImage QImage::convertedToColorSpace(const QColorSpace &colorSpace, QImage::Format format, Qt::ImageConversionFlags flags) const
+{
+ if (!d || !d->colorSpace.isValid())
+ return QImage();
+ if (!colorSpace.isValidTarget()) {
+ qWarning() << "QImage::convertedToColorSpace: Output colorspace is not valid";
+ return QImage();
+ }
+ if (!qt_compatibleColorModel(toPixelFormat(format).colorModel(), colorSpace.colorModel())) {
+ qWarning() << "QImage::convertedToColorSpace: Color space is not compatible with format";
+ return QImage();
+ }
+ if (d->colorSpace == colorSpace)
+ return convertedTo(format, flags);
+ QImage image = colorTransformed(d->colorSpace.transformationToColorSpace(colorSpace), format, flags);
+ image.setColorSpace(colorSpace);
return image;
}
@@ -5047,6 +5177,13 @@ void QImage::applyColorTransform(const QColorTransform &transform)
{
if (transform.isIdentity())
return;
+
+ if (!qt_compatibleColorModel(pixelFormat().colorModel(), QColorTransformPrivate::get(transform)->colorSpaceIn->colorModel) ||
+ !qt_compatibleColorModel(pixelFormat().colorModel(), QColorTransformPrivate::get(transform)->colorSpaceOut->colorModel)) {
+ qWarning() << "QImage::applyColorTransform can not apply format switching transform without switching format";
+ return;
+ }
+
detach();
if (!d)
return;
@@ -5065,7 +5202,8 @@ void QImage::applyColorTransform(const QColorTransform &transform)
&& oldFormat != QImage::Format_RGBA64_Premultiplied)
convertTo(QImage::Format_RGBA64);
} else if (oldFormat != QImage::Format_ARGB32 && oldFormat != QImage::Format_RGB32
- && oldFormat != QImage::Format_ARGB32_Premultiplied) {
+ && oldFormat != QImage::Format_ARGB32_Premultiplied && oldFormat != QImage::Format_CMYK8888
+ && oldFormat != QImage::Format_Grayscale8 && oldFormat != QImage::Format_Grayscale16) {
if (hasAlphaChannel())
convertTo(QImage::Format_ARGB32);
else
@@ -5079,7 +5217,10 @@ void QImage::applyColorTransform(const QColorTransform &transform)
case Format_RGBA32FPx4_Premultiplied:
flags = QColorTransformPrivate::Premultiplied;
break;
+ case Format_Grayscale8:
+ case Format_Grayscale16:
case Format_RGB32:
+ case Format_CMYK8888:
case Format_RGBX64:
case Format_RGBX32FPx4:
flags = QColorTransformPrivate::InputOpaque;
@@ -5094,7 +5235,21 @@ void QImage::applyColorTransform(const QColorTransform &transform)
std::function<void(int,int)> transformSegment;
- if (qt_fpColorPrecision(format())) {
+ if (format() == Format_Grayscale8) {
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ uint8_t *scanline = reinterpret_cast<uint8_t *>(d->data + y * d->bytes_per_line);
+ QColorTransformPrivate::get(transform)->applyGray(scanline, scanline, width(), flags);
+ }
+ };
+ } else if (format() == Format_Grayscale16) {
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ uint16_t *scanline = reinterpret_cast<uint16_t *>(d->data + y * d->bytes_per_line);
+ QColorTransformPrivate::get(transform)->applyGray(scanline, scanline, width(), flags);
+ }
+ };
+ } else if (qt_fpColorPrecision(format())) {
transformSegment = [&](int yStart, int yEnd) {
for (int y = yStart; y < yEnd; ++y) {
QRgbaFloat32 *scanline = reinterpret_cast<QRgbaFloat32 *>(d->data + y * d->bytes_per_line);
@@ -5108,6 +5263,13 @@ void QImage::applyColorTransform(const QColorTransform &transform)
QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
}
};
+ } else if (oldFormat == QImage::Format_CMYK8888) {
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ QCmyk32 *scanline = reinterpret_cast<QCmyk32 *>(d->data + y * d->bytes_per_line);
+ QColorTransformPrivate::get(transform)->apply(scanline, scanline, width(), flags);
+ }
+ };
} else {
transformSegment = [&](int yStart, int yEnd) {
for (int y = yStart; y < yEnd; ++y) {
@@ -5142,23 +5304,497 @@ void QImage::applyColorTransform(const QColorTransform &transform)
}
/*!
+ \since 6.8
+
+ Applies the color transformation \a transform to all pixels in the image, and converts the format of the image to \a toFormat.
+
+ The specified image conversion \a flags control how the image data
+ is handled during the format conversion process.
+*/
+void QImage::applyColorTransform(const QColorTransform &transform, QImage::Format toFormat, Qt::ImageConversionFlags flags)
+{
+ if (!d)
+ return;
+ if (transform.isIdentity())
+ return convertTo(toFormat, flags);
+
+ *this = colorTransformed(transform, toFormat, flags);
+}
+
+/*!
\since 6.4
Returns the image color transformed using \a transform on all pixels in the image.
+ \note If \a transform has a source color space which is incompatible with the format of this image,
+ returns a null QImage. If \a transform has a target color space which is incompatible with the format
+ of this image, the image will also be converted to a compatible format. For more control about the
+ choice of the target pixel format, see the three argument overload of this method.
+
\sa applyColorTransform()
*/
QImage QImage::colorTransformed(const QColorTransform &transform) const &
{
- if (!d || !d->colorSpace.isValid())
+ if (!d)
return QImage();
if (transform.isIdentity())
return *this;
+
+ QColorSpace::ColorModel inColorModel = QColorTransformPrivate::get(transform)->colorSpaceIn->colorModel;
+ QColorSpace::ColorModel outColorModel = QColorTransformPrivate::get(transform)->colorSpaceOut->colorModel;
+ if (!qt_compatibleColorModel(pixelFormat().colorModel(), inColorModel)) {
+ qWarning() << "QImage::colorTransformed: Invalid input color space for transform";
+ return QImage();
+ }
+ if (!qt_compatibleColorModel(pixelFormat().colorModel(), outColorModel)) {
+ // All model switching transforms are opaque in at least one end.
+ switch (outColorModel) {
+ case QColorSpace::ColorModel::Rgb:
+ return colorTransformed(transform, qt_highColorPrecision(format(), true) ? QImage::Format_RGBX64 : QImage::Format_RGB32);
+ case QColorSpace::ColorModel::Gray:
+ return colorTransformed(transform, qt_highColorPrecision(format(), true) ? QImage::Format_Grayscale16 : QImage::Format_Grayscale8);
+ case QColorSpace::ColorModel::Cmyk:
+ return colorTransformed(transform, QImage::Format_CMYK8888);
+ case QColorSpace::ColorModel::Undefined:
+ break;
+ }
+ return QImage();
+ }
+
QImage image = copy();
image.applyColorTransform(transform);
return image;
}
+static bool isRgb32Data(QImage::Format f)
+{
+ switch (f) {
+ case QImage::Format_RGB32:
+ case QImage::Format_ARGB32:
+ case QImage::Format_ARGB32_Premultiplied:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+static bool isRgb64Data(QImage::Format f)
+{
+ switch (f) {
+ case QImage::Format_RGBX64:
+ case QImage::Format_RGBA64:
+ case QImage::Format_RGBA64_Premultiplied:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+static bool isRgb32fpx4Data(QImage::Format f)
+{
+ switch (f) {
+ case QImage::Format_RGBX32FPx4:
+ case QImage::Format_RGBA32FPx4:
+ case QImage::Format_RGBA32FPx4_Premultiplied:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+/*!
+ \since 6.8
+
+ Returns the image color transformed using \a transform on all pixels in the image, returning an image of format \a toFormat.
+
+ The specified image conversion \a flags control how the image data
+ is handled during the format conversion process.
+
+ \note If \a transform has a source color space which is incompatible with the format of this image,
+ or a target color space that is incompatible with \a toFormat, returns a null QImage.
+
+ \sa applyColorTransform()
+*/
+QImage QImage::colorTransformed(const QColorTransform &transform, QImage::Format toFormat, Qt::ImageConversionFlags flags) const &
+{
+ if (!d)
+ return QImage();
+ if (toFormat == QImage::Format_Invalid)
+ toFormat = format();
+ if (transform.isIdentity())
+ return convertedTo(toFormat, flags);
+
+ QColorSpace::ColorModel inColorModel = QColorTransformPrivate::get(transform)->colorSpaceIn->colorModel;
+ QColorSpace::ColorModel outColorModel = QColorTransformPrivate::get(transform)->colorSpaceOut->colorModel;
+ if (!qt_compatibleColorModel(pixelFormat().colorModel(), inColorModel)) {
+ qWarning() << "QImage::colorTransformed: Invalid input color space for transform";
+ return QImage();
+ }
+ if (!qt_compatibleColorModel(toPixelFormat(toFormat).colorModel(), outColorModel)) {
+ qWarning() << "QImage::colorTransformed: Invalid output color space for transform";
+ return QImage();
+ }
+
+ QImage fromImage = *this;
+
+ QImage::Format tmpFormat = toFormat;
+ switch (toFormat) {
+ case QImage::Format_RGB32:
+ case QImage::Format_ARGB32:
+ case QImage::Format_ARGB32_Premultiplied:
+ case QImage::Format_RGBX32FPx4:
+ case QImage::Format_RGBA32FPx4:
+ case QImage::Format_RGBA32FPx4_Premultiplied:
+ case QImage::Format_RGBX64:
+ case QImage::Format_RGBA64:
+ case QImage::Format_RGBA64_Premultiplied:
+ case QImage::Format_Grayscale8:
+ case QImage::Format_Grayscale16:
+ case QImage::Format_CMYK8888:
+ // can be output natively
+ break;
+ case QImage::Format_RGB16:
+ case QImage::Format_RGB444:
+ case QImage::Format_RGB555:
+ case QImage::Format_RGB666:
+ case QImage::Format_RGB888:
+ case QImage::Format_BGR888:
+ case QImage::Format_RGBX8888:
+ tmpFormat = QImage::Format_RGB32;
+ break;
+ case QImage::Format_Mono:
+ case QImage::Format_MonoLSB:
+ case QImage::Format_Indexed8:
+ case QImage::Format_ARGB8565_Premultiplied:
+ case QImage::Format_ARGB6666_Premultiplied:
+ case QImage::Format_ARGB8555_Premultiplied:
+ case QImage::Format_ARGB4444_Premultiplied:
+ case QImage::Format_RGBA8888:
+ case QImage::Format_RGBA8888_Premultiplied:
+ tmpFormat = QImage::Format_ARGB32;
+ break;
+ case QImage::Format_BGR30:
+ case QImage::Format_RGB30:
+ tmpFormat = QImage::Format_RGBX64;
+ break;
+ case QImage::Format_A2BGR30_Premultiplied:
+ case QImage::Format_A2RGB30_Premultiplied:
+ tmpFormat = QImage::Format_RGBA64;
+ break;
+ case QImage::Format_RGBX16FPx4:
+ case QImage::Format_RGBA16FPx4:
+ case QImage::Format_RGBA16FPx4_Premultiplied:
+ tmpFormat = QImage::Format_RGBA32FPx4;
+ break;
+ case QImage::Format_Alpha8:
+ return convertedTo(QImage::Format_Alpha8);
+ case QImage::Format_Invalid:
+ case QImage::NImageFormats:
+ Q_UNREACHABLE();
+ break;
+ }
+ QColorSpace::ColorModel inColorData = qt_csColorData(pixelFormat().colorModel());
+ QColorSpace::ColorModel outColorData = qt_csColorData(toPixelFormat(toFormat).colorModel());
+ // Ensure only precision increasing transforms
+ if (inColorData != outColorData) {
+ if (fromImage.format() == QImage::Format_Grayscale8 && outColorData == QColorSpace::ColorModel::Rgb)
+ tmpFormat = QImage::Format_RGB32;
+ else if (tmpFormat == QImage::Format_Grayscale8 && qt_highColorPrecision(fromImage.format()))
+ tmpFormat = QImage::Format_Grayscale16;
+ else if (fromImage.format() == QImage::Format_Grayscale16 && outColorData == QColorSpace::ColorModel::Rgb)
+ tmpFormat = QImage::Format_RGBX64;
+ } else {
+ if (tmpFormat == QImage::Format_Grayscale8 && fromImage.format() == QImage::Format_Grayscale16)
+ tmpFormat = QImage::Format_Grayscale16;
+ else if (qt_fpColorPrecision(fromImage.format()) && !qt_fpColorPrecision(tmpFormat))
+ tmpFormat = QImage::Format_RGBA32FPx4;
+ else if (isRgb32Data(tmpFormat) && qt_highColorPrecision(fromImage.format(), true))
+ tmpFormat = QImage::Format_RGBA64;
+ }
+
+ QImage toImage(size(), tmpFormat);
+ copyMetadata(&toImage, *this);
+
+ std::function<void(int, int)> transformSegment;
+ QColorTransformPrivate::TransformFlags transFlags = QColorTransformPrivate::Unpremultiplied;
+
+ if (inColorData != outColorData) {
+ // Needs color model switching transform
+ if (inColorData == QColorSpace::ColorModel::Gray && outColorData == QColorSpace::ColorModel::Rgb) {
+ // Gray -> RGB
+ if (format() == QImage::Format_Grayscale8) {
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const quint8 *in_scanline = reinterpret_cast<const quint8 *>(d->data + y * d->bytes_per_line);
+ QRgb *out_scanline = reinterpret_cast<QRgb *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->applyGray(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
+ }
+ };
+ } else {
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const quint16 *in_scanline = reinterpret_cast<const quint16 *>(d->data + y * d->bytes_per_line);
+ QRgba64 *out_scanline = reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->applyGray(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
+ }
+ };
+ }
+ } else if (inColorData == QColorSpace::ColorModel::Gray && outColorData == QColorSpace::ColorModel::Cmyk) {
+ // Gray -> CMYK
+ if (format() == QImage::Format_Grayscale8) {
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const quint8 *in_scanline = reinterpret_cast<const quint8 *>(d->data + y * d->bytes_per_line);
+ QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->applyGray(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
+ }
+ };
+ } else {
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const quint16 *in_scanline = reinterpret_cast<const quint16 *>(d->data + y * d->bytes_per_line);
+ QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->applyGray(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
+ }
+ };
+ }
+ } else if (inColorData == QColorSpace::ColorModel::Rgb && outColorData == QColorSpace::ColorModel::Gray) {
+ // RGB -> Gray
+ if (tmpFormat == QImage::Format_Grayscale8) {
+ fromImage.convertTo(QImage::Format_RGB32);
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const QRgb *in_scanline = reinterpret_cast<const QRgb *>(fromImage.constBits() + y * fromImage.bytesPerLine());
+ quint8 *out_scanline = reinterpret_cast<quint8 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->applyReturnGray(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
+ }
+ };
+ } else {
+ fromImage.convertTo(QImage::Format_RGBX64);
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const QRgba64 *in_scanline = reinterpret_cast<const QRgba64 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
+ quint16 *out_scanline = reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->applyReturnGray(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
+ }
+ };
+ }
+ } else if (inColorData == QColorSpace::ColorModel::Cmyk && outColorData == QColorSpace::ColorModel::Gray) {
+ // CMYK -> Gray
+ if (tmpFormat == QImage::Format_Grayscale8) {
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
+ quint8 *out_scanline = reinterpret_cast<quint8 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->applyReturnGray(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
+ }
+ };
+ } else {
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
+ quint16 *out_scanline = reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->applyReturnGray(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
+ }
+ };
+ }
+ } else if (inColorData == QColorSpace::ColorModel::Cmyk && outColorData == QColorSpace::ColorModel::Rgb) {
+ // CMYK -> RGB
+ if (isRgb32Data(tmpFormat) ) {
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
+ QRgb *out_scanline = reinterpret_cast<QRgb *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
+ }
+ };
+ } else if (isRgb64Data(tmpFormat)) {
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
+ QRgba64 *out_scanline = reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
+ }
+ };
+ } else {
+ Q_ASSERT(isRgb32fpx4Data(tmpFormat));
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
+ QRgbaFloat32 *out_scanline = reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), QColorTransformPrivate::InputOpaque);
+ }
+ };
+ }
+ } else if (inColorData == QColorSpace::ColorModel::Rgb && outColorData == QColorSpace::ColorModel::Cmyk) {
+ // RGB -> CMYK
+ if (!fromImage.hasAlphaChannel())
+ transFlags = QColorTransformPrivate::InputOpaque;
+ else if (qPixelLayouts[fromImage.format()].premultiplied)
+ transFlags = QColorTransformPrivate::Premultiplied;
+ if (isRgb32Data(fromImage.format()) ) {
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const QRgb *in_scanline = reinterpret_cast<const QRgb *>(fromImage.constBits() + y * fromImage.bytesPerLine());
+ QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
+ }
+ };
+ } else if (isRgb64Data(fromImage.format())) {
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const QRgba64 *in_scanline = reinterpret_cast<const QRgba64 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
+ QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
+ }
+ };
+ } else {
+ Q_ASSERT(isRgb32fpx4Data(fromImage.format()));
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const QRgbaFloat32 *in_scanline = reinterpret_cast<const QRgbaFloat32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
+ QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
+ }
+ };
+ }
+ } else {
+ Q_UNREACHABLE();
+ }
+ } else {
+ // Conversion on same color model
+ if (pixelFormat().colorModel() == QPixelFormat::Indexed) {
+ for (int i = 0; i < d->colortable.size(); ++i)
+ fromImage.d->colortable[i] = transform.map(d->colortable[i]);
+ return fromImage.convertedTo(toFormat, flags);
+ }
+
+ QImage::Format oldFormat = format();
+ if (qt_fpColorPrecision(oldFormat)) {
+ if (oldFormat != QImage::Format_RGBX32FPx4 && oldFormat != QImage::Format_RGBA32FPx4
+ && oldFormat != QImage::Format_RGBA32FPx4_Premultiplied)
+ fromImage.convertTo(QImage::Format_RGBA32FPx4);
+ } else if (qt_highColorPrecision(oldFormat, true)) {
+ if (oldFormat != QImage::Format_RGBX64 && oldFormat != QImage::Format_RGBA64
+ && oldFormat != QImage::Format_RGBA64_Premultiplied && oldFormat != QImage::Format_Grayscale16)
+ fromImage.convertTo(QImage::Format_RGBA64);
+ } else if (oldFormat != QImage::Format_ARGB32 && oldFormat != QImage::Format_RGB32
+ && oldFormat != QImage::Format_ARGB32_Premultiplied && oldFormat != QImage::Format_CMYK8888
+ && oldFormat != QImage::Format_Grayscale8 && oldFormat != QImage::Format_Grayscale16) {
+ if (hasAlphaChannel())
+ fromImage.convertTo(QImage::Format_ARGB32);
+ else
+ fromImage.convertTo(QImage::Format_RGB32);
+ }
+
+ if (!fromImage.hasAlphaChannel())
+ transFlags = QColorTransformPrivate::InputOpaque;
+ else if (qPixelLayouts[fromImage.format()].premultiplied)
+ transFlags = QColorTransformPrivate::Premultiplied;
+
+ if (fromImage.format() == Format_Grayscale8) {
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const quint8 *in_scanline = reinterpret_cast<const quint8 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
+ if (tmpFormat == Format_Grayscale8) {
+ quint8 *out_scanline = reinterpret_cast<quint8 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->applyGray(out_scanline, in_scanline, width(), transFlags);
+ } else {
+ Q_ASSERT(tmpFormat == Format_Grayscale16);
+ quint16 *out_scanline = reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->applyGray(out_scanline, in_scanline, width(), transFlags);
+ }
+ }
+ };
+ } else if (fromImage.format() == Format_Grayscale16) {
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const quint16 *in_scanline = reinterpret_cast<const quint16 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
+ quint16 *out_scanline = reinterpret_cast<quint16 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->applyGray(out_scanline, in_scanline, width(), transFlags);
+ }
+ };
+ } else if (fromImage.format() == Format_CMYK8888) {
+ Q_ASSERT(tmpFormat == Format_CMYK8888);
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const QCmyk32 *in_scanline = reinterpret_cast<const QCmyk32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
+ QCmyk32 *out_scanline = reinterpret_cast<QCmyk32 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
+ }
+ };
+ } else if (isRgb32fpx4Data(fromImage.format())) {
+ Q_ASSERT(isRgb32fpx4Data(tmpFormat));
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const QRgbaFloat32 *in_scanline = reinterpret_cast<const QRgbaFloat32 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
+ QRgbaFloat32 *out_scanline = reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
+ }
+ };
+ } else if (isRgb64Data(fromImage.format())) {
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const QRgba64 *in_scanline = reinterpret_cast<const QRgba64 *>(fromImage.constBits() + y * fromImage.bytesPerLine());
+ if (isRgb32fpx4Data(tmpFormat)) {
+ QRgbaFloat32 *out_scanline = reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
+ } else {
+ Q_ASSERT(isRgb64Data(tmpFormat));
+ QRgba64 *out_scanline = reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
+ }
+ }
+ };
+ } else {
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const QRgb *in_scanline = reinterpret_cast<const QRgb *>(fromImage.constBits() + y * fromImage.bytesPerLine());
+ if (isRgb32fpx4Data(tmpFormat)) {
+ QRgbaFloat32 *out_scanline = reinterpret_cast<QRgbaFloat32 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
+ } else if (isRgb64Data(tmpFormat)) {
+ QRgba64 *out_scanline = reinterpret_cast<QRgba64 *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
+ } else {
+ Q_ASSERT(isRgb32Data(tmpFormat));
+ QRgb *out_scanline = reinterpret_cast<QRgb *>(toImage.d->data + y * toImage.bytesPerLine());
+ QColorTransformPrivate::get(transform)->apply(out_scanline, in_scanline, width(), transFlags);
+ }
+ }
+ };
+ }
+ }
+
+#if QT_CONFIG(thread) && !defined(Q_OS_WASM)
+ int segments = (qsizetype(width()) * height()) >> 16;
+ segments = std::min(segments, height());
+ QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance();
+ if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (height() - y) / (segments - i);
+ threadPool->start([&, y, yn]() {
+ transformSegment(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ } else
+#endif
+ transformSegment(0, height());
+
+ if (tmpFormat != toFormat)
+ toImage.convertTo(toFormat);
+
+ return toImage;
+}
+
/*!
\since 6.4
\overload
@@ -5169,12 +5805,48 @@ QImage QImage::colorTransformed(const QColorTransform &transform) const &
*/
QImage QImage::colorTransformed(const QColorTransform &transform) &&
{
- if (!d || !d->colorSpace.isValid())
+ if (!d)
return QImage();
+
+ QColorSpace::ColorModel inColorModel = QColorTransformPrivate::get(transform)->colorSpaceIn->colorModel;
+ QColorSpace::ColorModel outColorModel = QColorTransformPrivate::get(transform)->colorSpaceOut->colorModel;
+ if (!qt_compatibleColorModel(pixelFormat().colorModel(), inColorModel)) {
+ qWarning() << "QImage::colorTransformed: Invalid input color space for transform";
+ return QImage();
+ }
+ if (!qt_compatibleColorModel(pixelFormat().colorModel(), outColorModel)) {
+ // There is currently no inplace conversion of both colorspace and format, so just use the normal version.
+ switch (outColorModel) {
+ case QColorSpace::ColorModel::Rgb:
+ return colorTransformed(transform, qt_highColorPrecision(format(), true) ? QImage::Format_RGBX64 : QImage::Format_RGB32);
+ case QColorSpace::ColorModel::Gray:
+ return colorTransformed(transform, qt_highColorPrecision(format(), true) ? QImage::Format_Grayscale16 : QImage::Format_Grayscale8);
+ case QColorSpace::ColorModel::Cmyk:
+ return colorTransformed(transform, QImage::Format_CMYK8888);
+ case QColorSpace::ColorModel::Undefined:
+ break;
+ }
+ return QImage();
+ }
+
applyColorTransform(transform);
return std::move(*this);
}
+/*!
+ \since 6.8
+ \overload
+
+ Returns the image color transformed using \a transform on all pixels in the image.
+
+ \sa applyColorTransform()
+*/
+QImage QImage::colorTransformed(const QColorTransform &transform, QImage::Format format, Qt::ImageConversionFlags flags) &&
+{
+ // There is currently no inplace conversion of both colorspace and format, so just use the normal version.
+ return colorTransformed(transform, format, flags);
+}
+
bool QImageData::convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags flags)
{
if (format == newFormat)
@@ -5699,6 +6371,19 @@ static constexpr QPixelFormat pixelformats[] = {
/*PREMULTIPLIED*/ QPixelFormat::Premultiplied,
/*INTERPRETATION*/ QPixelFormat::FloatingPoint,
/*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
+ //QImage::Format_CMYK8888:
+ QPixelFormat(QPixelFormat::CMYK,
+ /*RED*/ 8,
+ /*GREEN*/ 8,
+ /*BLUE*/ 8,
+ /*FOURTH*/ 8,
+ /*FIFTH*/ 0,
+ /*ALPHA*/ 0,
+ /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
+ /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
+ /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
+ /*INTERPRETATION*/ QPixelFormat::UnsignedInteger,
+ /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
};
static_assert(sizeof(pixelformats) / sizeof(*pixelformats) == QImage::NImageFormats);
@@ -5759,8 +6444,7 @@ QMap<QString, QString> qt_getImageText(const QImage &image, const QString &descr
QMap<QString, QString> qt_getImageTextFromDescription(const QString &description)
{
QMap<QString, QString> text;
- const auto pairs = QStringView{description}.split(u"\n\n");
- for (const auto &pair : pairs) {
+ for (const auto &pair : QStringView{description}.tokenize(u"\n\n")) {
int index = pair.indexOf(u':');
if (index >= 0 && pair.indexOf(u' ') < index) {
if (!pair.trimmed().isEmpty())
diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h
index 86c49ac28a..cba50e5e4c 100644
--- a/src/gui/image/qimage.h
+++ b/src/gui/image/qimage.h
@@ -75,6 +75,7 @@ public:
Format_RGBX32FPx4,
Format_RGBA32FPx4,
Format_RGBA32FPx4_Premultiplied,
+ Format_CMYK8888,
#ifndef Q_QDOC
NImageFormats
#endif
@@ -230,13 +231,18 @@ public:
void invertPixels(InvertMode = InvertRgb);
QColorSpace colorSpace() const;
- [[nodiscard]] QImage convertedToColorSpace(const QColorSpace &) const;
- void convertToColorSpace(const QColorSpace &);
- void setColorSpace(const QColorSpace &);
+ [[nodiscard]] QImage convertedToColorSpace(const QColorSpace &colorSpace) const;
+ [[nodiscard]] QImage convertedToColorSpace(const QColorSpace &colorSpace, QImage::Format format, Qt::ImageConversionFlags flags = Qt::AutoColor) const;
+ void convertToColorSpace(const QColorSpace &colorSpace);
+ void convertToColorSpace(const QColorSpace &colorSpace, QImage::Format format, Qt::ImageConversionFlags flags = Qt::AutoColor);
+ void setColorSpace(const QColorSpace &colorSpace);
QImage colorTransformed(const QColorTransform &transform) const &;
+ QImage colorTransformed(const QColorTransform &transform, QImage::Format format, Qt::ImageConversionFlags flags = Qt::AutoColor) const &;
QImage colorTransformed(const QColorTransform &transform) &&;
+ QImage colorTransformed(const QColorTransform &transform, QImage::Format format, Qt::ImageConversionFlags flags = Qt::AutoColor) &&;
void applyColorTransform(const QColorTransform &transform);
+ void applyColorTransform(const QColorTransform &transform, QImage::Format format, Qt::ImageConversionFlags flags = Qt::AutoColor);
bool load(QIODevice *device, const char *format);
bool load(const QString &fileName, const char *format = nullptr);
diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp
index 2e1eb5e5e4..a806954df2 100644
--- a/src/gui/image/qimage_conversions.cpp
+++ b/src/gui/image/qimage_conversions.cpp
@@ -4,6 +4,7 @@
#include <private/qguiapplication_p.h>
#include <private/qcolortransform_p.h>
#include <private/qcolortrclut_p.h>
+#include <private/qcmyk_p.h>
#include <private/qdrawhelper_p.h>
#include <private/qendian_p.h>
#include <private/qpixellayout_p.h>
@@ -165,7 +166,7 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
if (srcLayout->hasAlphaChannel && !srcLayout->premultiplied &&
!destLayout->hasAlphaChannel && destLayout->storeFromRGB32) {
// Avoid unnecessary premultiply and unpremultiply when converting from unpremultiplied src format.
- fetch = qPixelLayouts[src->format + 1].fetchToARGB32PM;
+ fetch = qPixelLayouts[qt_toPremultipliedFormat(src->format)].fetchToARGB32PM;
if (dest->format == QImage::Format_RGB32)
store = storeRGB32FromARGB32;
else
@@ -383,7 +384,7 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
if (srcLayout->hasAlphaChannel && !srcLayout->premultiplied &&
!destLayout->hasAlphaChannel && destLayout->storeFromRGB32) {
// Avoid unnecessary premultiply and unpremultiply when converting from unpremultiplied src format.
- fetch = qPixelLayouts[data->format + 1].fetchToARGB32PM;
+ fetch = qPixelLayouts[qt_toPremultipliedFormat(data->format)].fetchToARGB32PM;
if (data->format == QImage::Format_RGB32)
store = storeRGB32FromARGB32;
else
@@ -485,9 +486,8 @@ bool convert_generic_inplace_over_rgb64(QImageData *data, QImage::Format dst_for
if (srcLayout->hasAlphaChannel && !srcLayout->premultiplied &&
destLayout->hasAlphaChannel && !destLayout->premultiplied) {
// Avoid unnecessary premultiply and unpremultiply when converting between two unpremultiplied formats.
- // This abuses the fact unpremultiplied formats are always before their premultiplied counterparts.
- fetch = qPixelLayouts[data->format + 1].fetchToRGBA64PM;
- store = qStoreFromRGBA64PM[dst_format + 1];
+ fetch = qPixelLayouts[qt_toPremultipliedFormat(data->format)].fetchToRGBA64PM;
+ store = qStoreFromRGBA64PM[qt_toPremultipliedFormat(dst_format)];
}
auto convertSegment = [=](int yStart, int yEnd) {
@@ -580,9 +580,8 @@ bool convert_generic_inplace_over_rgba32f(QImageData *data, QImage::Format dst_f
if (srcLayout->hasAlphaChannel && !srcLayout->premultiplied &&
destLayout->hasAlphaChannel && !destLayout->premultiplied) {
// Avoid unnecessary premultiply and unpremultiply when converting between two unpremultiplied formats.
- // This abuses the fact unpremultiplied formats are always before their premultiplied counterparts.
- fetch = qFetchToRGBA32F[data->format + 1];
- store = qStoreFromRGBA32F[dst_format + 1];
+ fetch = qFetchToRGBA32F[qt_toPremultipliedFormat(data->format)];
+ store = qStoreFromRGBA32F[qt_toPremultipliedFormat(dst_format)];
}
auto convertSegment = [=](int yStart, int yEnd) {
@@ -1323,11 +1322,11 @@ static void convert_ARGB32_to_RGBA64(QImageData *dest, const QImageData *src, Qt
const uchar *src_data = src->data;
uchar *dest_data = dest->data;
- const FetchAndConvertPixelsFunc64 fetch = qPixelLayouts[src->format + 1].fetchToRGBA64PM;
+ const FetchAndConvertPixelsFunc64 fetch = qPixelLayouts[qt_toPremultipliedFormat(src->format)].fetchToRGBA64PM;
for (int i = 0; i < src->height; ++i) {
fetch(reinterpret_cast<QRgba64 *>(dest_data), src_data, 0, src->width, nullptr, nullptr);
- src_data += src->bytes_per_line;;
+ src_data += src->bytes_per_line;
dest_data += dest->bytes_per_line;
}
}
@@ -1425,7 +1424,7 @@ static void convert_ARGB_to_gray8(QImageData *dest, const QImageData *src, Qt::I
for (int i = 0; i < src->height; ++i) {
const QRgb *src_line = reinterpret_cast<const QRgb *>(src_data);
- tfd->apply(dest_data, src_line, src->width, flags);
+ tfd->applyReturnGray(dest_data, src_line, src->width, flags);
src_data += sbpl;
dest_data += dbpl;
}
@@ -1462,7 +1461,7 @@ static void convert_ARGB_to_gray16(QImageData *dest, const QImageData *src, Qt::
const int len = std::min(src->width - j, BufferSize);
for (int k = 0; k < len; ++k)
tmp_line[k] = QRgba64::fromArgb32(src_line[j + k]);
- tfd->apply(dest_line + j, tmp_line, len, flags);
+ tfd->applyReturnGray(dest_line + j, tmp_line, len, flags);
j += len;
}
src_data += sbpl;
@@ -1499,7 +1498,7 @@ static void convert_RGBA64_to_gray8(QImageData *dest, const QImageData *src, Qt:
int j = 0;
while (j < src->width) {
const int len = std::min(src->width - j, BufferSize);
- tfd->apply(gray_line, src_line + j, len, flags);
+ tfd->applyReturnGray(gray_line, src_line + j, len, flags);
for (int k = 0; k < len; ++k)
dest_line[j + k] = qt_div_257(gray_line[k]);
j += len;
@@ -1534,7 +1533,7 @@ static void convert_RGBA64_to_gray16(QImageData *dest, const QImageData *src, Qt
for (int i = 0; i < src->height; ++i) {
const QRgba64 *src_line = reinterpret_cast<const QRgba64 *>(src_data);
quint16 *dest_line = reinterpret_cast<quint16 *>(dest_data);
- tfd->apply(dest_line, src_line, src->width, flags);
+ tfd->applyReturnGray(dest_line, src_line, src->width, flags);
src_data += sbpl;
dest_data += dbpl;
}
@@ -2456,6 +2455,34 @@ static bool convert_Grayscale8_to_Indexed8_inplace(QImageData *data, Qt::ImageCo
return true;
}
+template <bool SourceIsPremultiplied>
+static void convert_ARGB32_to_CMYK8888(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(src->format == QImage::Format_RGB32 ||
+ src->format == QImage::Format_ARGB32 ||
+ src->format == QImage::Format_ARGB32_Premultiplied);
+ Q_ASSERT(dest->format == QImage::Format_CMYK8888);
+ Q_ASSERT(src->width == dest->width);
+ Q_ASSERT(src->height == dest->height);
+
+ const uchar *src_data = src->data;
+ uchar *dest_data = dest->data;
+ for (int y = 0; y < src->height; ++y) {
+ const QRgb *srcRgba = reinterpret_cast<const QRgb *>(src_data);
+ uint *destCmyk = reinterpret_cast<uint *>(dest_data);
+
+ for (int x = 0; x < src->width; ++x) {
+ QRgb sourcePixel = srcRgba[x];
+ if constexpr (SourceIsPremultiplied)
+ sourcePixel = qUnpremultiply(sourcePixel);
+
+ destCmyk[x] = QCmyk32::fromRgba(sourcePixel).toUint();
+ }
+
+ src_data += src->bytes_per_line;;
+ dest_data += dest->bytes_per_line;
+ }
+}
// first index source, second dest
Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats] = {};
@@ -2592,6 +2619,11 @@ static void qInitImageConversions()
qimage_converter_map[QImage::Format_RGBX32FPx4][QImage::Format_RGBA32FPx4] = convert_passthrough;
qimage_converter_map[QImage::Format_RGBX32FPx4][QImage::Format_RGBA32FPx4_Premultiplied] = convert_passthrough;
+ qimage_converter_map[QImage::Format_CMYK8888][QImage::Format_CMYK8888] = convert_passthrough;
+ qimage_converter_map[QImage::Format_RGB32][QImage::Format_CMYK8888] = convert_ARGB32_to_CMYK8888<false>;
+ qimage_converter_map[QImage::Format_ARGB32][QImage::Format_CMYK8888] = convert_ARGB32_to_CMYK8888<false>;
+ qimage_converter_map[QImage::Format_ARGB32_Premultiplied][QImage::Format_CMYK8888] = convert_ARGB32_to_CMYK8888<true>;
+
// Inline converters:
qimage_inplace_converter_map[QImage::Format_Indexed8][QImage::Format_Grayscale8] =
convert_Indexed8_to_Grayscale8_inplace;
diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h
index ba22c99ed7..0d42f94253 100644
--- a/src/gui/image/qimage_p.h
+++ b/src/gui/image/qimage_p.h
@@ -21,6 +21,8 @@
#include <QtCore/private/qnumeric_p.h>
#include <QtCore/qlist.h>
#include <QtCore/qmap.h>
+#include <QtCore/qttypetraits.h>
+
QT_BEGIN_NAMESPACE
@@ -92,18 +94,18 @@ QImageData::calculateImageParameters(qsizetype width, qsizetype height, qsizetyp
// calculate the size, taking care of overflows
qsizetype bytes_per_line;
- if (mul_overflow(width, depth, &bytes_per_line))
+ if (qMulOverflow(width, depth, &bytes_per_line))
return invalid;
- if (add_overflow(bytes_per_line, qsizetype(31), &bytes_per_line))
+ if (qAddOverflow(bytes_per_line, qsizetype(31), &bytes_per_line))
return invalid;
// bytes per scanline (must be multiple of 4)
bytes_per_line = (bytes_per_line >> 5) << 2; // can't overflow
qsizetype total_size;
- if (mul_overflow(height, bytes_per_line, &total_size))
+ if (qMulOverflow(height, bytes_per_line, &total_size))
return invalid;
qsizetype dummy;
- if (mul_overflow(height, qsizetype(sizeof(uchar *)), &dummy))
+ if (qMulOverflow(height, qsizetype(sizeof(uchar *)), &dummy))
return invalid; // why is this here?
#if 1 || QT_VERSION < QT_VERSION_CHECK(6,0,0) // ### can only fix this if QImage dimensions are not int anymore
// Disallow images where width * depth calculations might overflow
@@ -193,6 +195,9 @@ inline int qt_depthForFormat(QImage::Format format)
case QImage::Format_RGBA32FPx4_Premultiplied:
depth = 128;
break;
+ case QImage::Format_CMYK8888:
+ depth = 32;
+ break;
}
return depth;
}
@@ -246,6 +251,7 @@ inline QImage::Format qt_opaqueVersion(QImage::Format format)
case QImage::Format_RGBX32FPx4:
case QImage::Format_Grayscale8:
case QImage::Format_Grayscale16:
+ case QImage::Format_CMYK8888:
return format;
case QImage::Format_Mono:
case QImage::Format_MonoLSB:
@@ -309,12 +315,84 @@ inline QImage::Format qt_alphaVersion(QImage::Format format)
case QImage::Format_Alpha8:
case QImage::Format_Grayscale8:
case QImage::Format_Invalid:
+ case QImage::Format_CMYK8888:
case QImage::NImageFormats:
break;
}
return QImage::Format_ARGB32_Premultiplied;
}
+// Returns an opaque version that is compatible with format
+inline QImage::Format qt_maybeDataCompatibleOpaqueVersion(QImage::Format format)
+{
+ switch (format) {
+ case QImage::Format_ARGB6666_Premultiplied:
+ return QImage::Format_RGB666;
+ case QImage::Format_ARGB4444_Premultiplied:
+ return QImage::Format_RGB444;
+ case QImage::Format_RGBA8888:
+ case QImage::Format_RGBA8888_Premultiplied:
+ return QImage::Format_RGBX8888;
+ case QImage::Format_A2BGR30_Premultiplied:
+ return QImage::Format_BGR30;
+ case QImage::Format_A2RGB30_Premultiplied:
+ return QImage::Format_RGB30;
+ case QImage::Format_RGBA64:
+ case QImage::Format_RGBA64_Premultiplied:
+ return QImage::Format_RGBX64;
+ case QImage::Format_RGBA16FPx4:
+ case QImage::Format_RGBA16FPx4_Premultiplied:
+ return QImage::Format_RGBX16FPx4;
+ case QImage::Format_RGBA32FPx4:
+ case QImage::Format_RGBA32FPx4_Premultiplied:
+ return QImage::Format_RGBX32FPx4;
+ case QImage::Format_ARGB32_Premultiplied:
+ case QImage::Format_ARGB32:
+ return QImage::Format_RGB32;
+ case QImage::Format_RGB16:
+ case QImage::Format_RGB32:
+ case QImage::Format_RGB444:
+ case QImage::Format_RGB555:
+ case QImage::Format_RGB666:
+ case QImage::Format_RGB888:
+ case QImage::Format_BGR888:
+ case QImage::Format_RGBX8888:
+ case QImage::Format_BGR30:
+ case QImage::Format_RGB30:
+ case QImage::Format_RGBX64:
+ case QImage::Format_RGBX16FPx4:
+ case QImage::Format_RGBX32FPx4:
+ case QImage::Format_Grayscale8:
+ case QImage::Format_Grayscale16:
+ case QImage::Format_CMYK8888:
+ return format; // Already opaque
+ case QImage::Format_Mono:
+ case QImage::Format_MonoLSB:
+ case QImage::Format_Indexed8:
+ case QImage::Format_ARGB8565_Premultiplied:
+ case QImage::Format_ARGB8555_Premultiplied:
+ case QImage::Format_Alpha8:
+ case QImage::Format_Invalid:
+ case QImage::NImageFormats:
+ break;
+ }
+ return format; // No compatible opaque versions
+}
+
+constexpr QImage::Format qt_toUnpremultipliedFormat(QImage::Format format)
+{
+ // Assumes input is already a premultiplied format with an unpremultiplied counterpart
+ // This abuses the fact unpremultiplied formats are always before their premultiplied counterparts.
+ return static_cast<QImage::Format>(qToUnderlying(format) - 1);
+}
+
+constexpr QImage::Format qt_toPremultipliedFormat(QImage::Format format)
+{
+ // Assumes input is already an unpremultiplied format
+ // This abuses the fact unpremultiplied formats are always before their premultiplied counterparts.
+ return static_cast<QImage::Format>(qToUnderlying(format) + 1);
+}
+
inline bool qt_highColorPrecision(QImage::Format format, bool opaque = false)
{
// Formats with higher color precision than ARGB32_Premultiplied.
@@ -359,10 +437,98 @@ inline bool qt_fpColorPrecision(QImage::Format format)
return false;
}
-inline QImage::Format qt_maybeAlphaVersionWithSameDepth(QImage::Format format)
+inline QColorSpace::ColorModel qt_csColorData(QPixelFormat::ColorModel format)
{
- const QImage::Format toFormat = qt_alphaVersion(format);
- return qt_depthForFormat(format) == qt_depthForFormat(toFormat) ? toFormat : format;
+ switch (format) {
+ case QPixelFormat::ColorModel::RGB:
+ case QPixelFormat::ColorModel::BGR:
+ case QPixelFormat::ColorModel::Indexed:
+ return QColorSpace::ColorModel::Rgb;
+ case QPixelFormat::ColorModel::Alpha:
+ return QColorSpace::ColorModel::Undefined; // No valid colors
+ case QPixelFormat::ColorModel::Grayscale:
+ return QColorSpace::ColorModel::Gray;
+ case QPixelFormat::ColorModel::CMYK:
+ return QColorSpace::ColorModel::Cmyk;
+ default:
+ break;
+ }
+ return QColorSpace::ColorModel::Undefined;
+}
+
+inline bool qt_compatibleColorModel(QPixelFormat::ColorModel data, QColorSpace::ColorModel cs)
+{
+ QColorSpace::ColorModel dataCs = qt_csColorData(data);
+
+ if (data == QPixelFormat::ColorModel::Alpha)
+ return true; // Alpha data has no colors and can be handled by any color space
+
+ if (cs == QColorSpace::ColorModel::Undefined || dataCs == QColorSpace::ColorModel::Undefined)
+ return false;
+
+ if (dataCs == cs)
+ return true; // Matching color models
+
+ if (dataCs == QColorSpace::ColorModel::Gray)
+ return true; // Can apply any CS with white point to Gray data
+
+ return false;
+}
+
+inline QImage::Format qt_maybeDataCompatibleAlphaVersion(QImage::Format format)
+{
+ switch (format) {
+ case QImage::Format_RGB32:
+ return QImage::Format_ARGB32_Premultiplied;
+ case QImage::Format_RGB666:
+ return QImage::Format_ARGB6666_Premultiplied;
+ case QImage::Format_RGB444:
+ return QImage::Format_ARGB4444_Premultiplied;
+ case QImage::Format_RGBX8888:
+ return QImage::Format_RGBA8888_Premultiplied;
+ case QImage::Format_BGR30:
+ return QImage::Format_A2BGR30_Premultiplied;
+ case QImage::Format_RGB30:
+ return QImage::Format_A2RGB30_Premultiplied;
+ case QImage::Format_RGBX64:
+ return QImage::Format_RGBA64_Premultiplied;
+ case QImage::Format_RGBX16FPx4:
+ return QImage::Format_RGBA16FPx4_Premultiplied;
+ case QImage::Format_RGBX32FPx4:
+ return QImage::Format_RGBA32FPx4_Premultiplied;
+ case QImage::Format_ARGB32:
+ case QImage::Format_ARGB32_Premultiplied:
+ case QImage::Format_ARGB8565_Premultiplied:
+ case QImage::Format_ARGB8555_Premultiplied:
+ case QImage::Format_ARGB6666_Premultiplied:
+ case QImage::Format_ARGB4444_Premultiplied:
+ case QImage::Format_RGBA8888:
+ case QImage::Format_RGBA8888_Premultiplied:
+ case QImage::Format_A2BGR30_Premultiplied:
+ case QImage::Format_A2RGB30_Premultiplied:
+ case QImage::Format_Alpha8:
+ case QImage::Format_RGBA64:
+ case QImage::Format_RGBA64_Premultiplied:
+ case QImage::Format_RGBA16FPx4:
+ case QImage::Format_RGBA16FPx4_Premultiplied:
+ case QImage::Format_RGBA32FPx4:
+ case QImage::Format_RGBA32FPx4_Premultiplied:
+ return format; // Already alpha versions
+ case QImage::Format_Mono:
+ case QImage::Format_MonoLSB:
+ case QImage::Format_Indexed8:
+ case QImage::Format_RGB16:
+ case QImage::Format_RGB555:
+ case QImage::Format_RGB888:
+ case QImage::Format_BGR888:
+ case QImage::Format_Grayscale8:
+ case QImage::Format_Grayscale16:
+ case QImage::Format_CMYK8888:
+ case QImage::Format_Invalid:
+ case QImage::NImageFormats:
+ break;
+ }
+ return format; // No data-compatible alpha version
}
inline QImage::Format qt_opaqueVersionForPainting(QImage::Format format)
diff --git a/src/gui/image/qimageiohandler.cpp b/src/gui/image/qimageiohandler.cpp
index 264b720b5e..1dcfd9a074 100644
--- a/src/gui/image/qimageiohandler.cpp
+++ b/src/gui/image/qimageiohandler.cpp
@@ -124,13 +124,13 @@
variants should return a list of supported variant names
(QList<QByteArray>) in this option.
- \value OptimizedWrite. A handler which supports this option
+ \value OptimizedWrite A handler which supports this option
is expected to turn on optimization flags when writing.
- \value ProgressiveScanWrite. A handler which supports
+ \value ProgressiveScanWrite A handler which supports
this option is expected to write the image as a progressive scan image.
- \value ImageTransformation. A handler which supports this option can read
+ \value ImageTransformation A handler which supports this option can read
the transformation metadata of an image. A handler that supports this option
should not apply the transformation itself.
*/
diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp
index 6208ae52c7..9366e9cbb1 100644
--- a/src/gui/image/qimagereader.cpp
+++ b/src/gui/image/qimagereader.cpp
@@ -463,7 +463,7 @@ public:
static int maxAlloc;
};
-int QImageReaderPrivate::maxAlloc = 128; // 128 MB is enough for an 8K 32bpp image
+int QImageReaderPrivate::maxAlloc = 256; // 256 MB is enough for an 8K 64bpp image
/*!
\internal
@@ -529,14 +529,15 @@ bool QImageReaderPrivate::initHandler()
int currentExtension = 0;
QString fileName = file->fileName();
+ bool fileIsOpen;
do {
file->setFileName(fileName + u'.'
+ QLatin1StringView(extensions.at(currentExtension++).constData()));
- file->open(QIODevice::ReadOnly);
- } while (!file->isOpen() && currentExtension < extensions.size());
+ fileIsOpen = file->open(QIODevice::ReadOnly);
+ } while (!fileIsOpen && currentExtension < extensions.size());
- if (!device->isOpen()) {
+ if (!fileIsOpen) {
imageReaderError = QImageReader::FileNotFoundError;
errorString = QImageReader::tr("File not found");
file->setFileName(fileName); // restore the old file name
@@ -558,7 +559,7 @@ bool QImageReaderPrivate::initHandler()
*/
void QImageReaderPrivate::getText()
{
- if (text.isEmpty() && initHandler() && handler->supportsOption(QImageIOHandler::Description))
+ if (text.isEmpty() && q->supportsOption(QImageIOHandler::Description))
text = qt_getImageTextFromDescription(handler->option(QImageIOHandler::Description).toString());
}
@@ -848,10 +849,7 @@ int QImageReader::quality() const
*/
QSize QImageReader::size() const
{
- if (!d->initHandler())
- return QSize();
-
- if (d->handler->supportsOption(QImageIOHandler::Size))
+ if (supportsOption(QImageIOHandler::Size))
return d->handler->option(QImageIOHandler::Size).toSize();
return QSize();
@@ -871,10 +869,7 @@ QSize QImageReader::size() const
*/
QImage::Format QImageReader::imageFormat() const
{
- if (!d->initHandler())
- return QImage::Format_Invalid;
-
- if (d->handler->supportsOption(QImageIOHandler::ImageFormat))
+ if (supportsOption(QImageIOHandler::ImageFormat))
return (QImage::Format)d->handler->option(QImageIOHandler::ImageFormat).toInt();
return QImage::Format_Invalid;
@@ -946,6 +941,10 @@ QRect QImageReader::clipRect() const
support scaling), QImageReader will use QImage::scale() with
Qt::SmoothScaling.
+ If only one dimension is set in \a size, the other one will be
+ computed from the image's \l {size()} {natural size} so as to
+ maintain the aspect ratio.
+
\sa scaledSize(), setClipRect(), setScaledClipRect()
*/
void QImageReader::setScaledSize(const QSize &size)
@@ -996,9 +995,7 @@ QRect QImageReader::scaledClipRect() const
*/
void QImageReader::setBackgroundColor(const QColor &color)
{
- if (!d->initHandler())
- return;
- if (d->handler->supportsOption(QImageIOHandler::BackgroundColor))
+ if (supportsOption(QImageIOHandler::BackgroundColor))
d->handler->setOption(QImageIOHandler::BackgroundColor, color);
}
@@ -1013,9 +1010,7 @@ void QImageReader::setBackgroundColor(const QColor &color)
*/
QColor QImageReader::backgroundColor() const
{
- if (!d->initHandler())
- return QColor();
- if (d->handler->supportsOption(QImageIOHandler::BackgroundColor))
+ if (supportsOption(QImageIOHandler::BackgroundColor))
return qvariant_cast<QColor>(d->handler->option(QImageIOHandler::BackgroundColor));
return QColor();
}
@@ -1030,9 +1025,7 @@ QColor QImageReader::backgroundColor() const
*/
bool QImageReader::supportsAnimation() const
{
- if (!d->initHandler())
- return false;
- if (d->handler->supportsOption(QImageIOHandler::Animation))
+ if (supportsOption(QImageIOHandler::Animation))
return d->handler->option(QImageIOHandler::Animation).toBool();
return false;
}
@@ -1044,10 +1037,7 @@ bool QImageReader::supportsAnimation() const
*/
QByteArray QImageReader::subType() const
{
- if (!d->initHandler())
- return QByteArray();
-
- if (d->handler->supportsOption(QImageIOHandler::SubType))
+ if (supportsOption(QImageIOHandler::SubType))
return d->handler->option(QImageIOHandler::SubType).toByteArray();
return QByteArray();
}
@@ -1059,10 +1049,7 @@ QByteArray QImageReader::subType() const
*/
QList<QByteArray> QImageReader::supportedSubTypes() const
{
- if (!d->initHandler())
- return QList<QByteArray>();
-
- if (d->handler->supportsOption(QImageIOHandler::SupportedSubTypes))
+ if (supportsOption(QImageIOHandler::SupportedSubTypes))
return qvariant_cast<QList<QByteArray> >(d->handler->option(QImageIOHandler::SupportedSubTypes));
return QList<QByteArray>();
}
@@ -1078,7 +1065,7 @@ QList<QByteArray> QImageReader::supportedSubTypes() const
QImageIOHandler::Transformations QImageReader::transformation() const
{
int option = QImageIOHandler::TransformationNone;
- if (d->initHandler() && d->handler->supportsOption(QImageIOHandler::ImageTransformation))
+ if (supportsOption(QImageIOHandler::ImageTransformation))
option = d->handler->option(QImageIOHandler::ImageTransformation).toInt();
return QImageIOHandler::Transformations(option);
}
@@ -1196,20 +1183,39 @@ bool QImageReader::read(QImage *image)
if (!d->initHandler())
return false;
+ QSize scaledSize = d->scaledSize;
+ if ((scaledSize.width() <= 0 && scaledSize.height() > 0) ||
+ (scaledSize.height() <= 0 && scaledSize.width() > 0)) {
+ // if only one dimension is given, let's try to calculate the second one
+ // based on the original image size and maintaining the aspect ratio
+ if (const QSize originalSize = size(); !originalSize.isEmpty()) {
+ if (scaledSize.width() <= 0) {
+ const auto ratio = qreal(scaledSize.height()) / originalSize.height();
+ scaledSize.setWidth(qRound(originalSize.width() * ratio));
+ } else {
+ const auto ratio = qreal(scaledSize.width()) / originalSize.width();
+ scaledSize.setHeight(qRound(originalSize.height() * ratio));
+ }
+ }
+ }
+
+ const bool supportScaledSize = supportsOption(QImageIOHandler::ScaledSize) && scaledSize.isValid();
+ const bool supportClipRect = supportsOption(QImageIOHandler::ClipRect) && !d->clipRect.isNull();
+ const bool supportScaledClipRect = supportsOption(QImageIOHandler::ScaledClipRect) && !d->scaledClipRect.isNull();
+
// set the handler specific options.
- if (d->handler->supportsOption(QImageIOHandler::ScaledSize) && d->scaledSize.isValid()) {
- if ((d->handler->supportsOption(QImageIOHandler::ClipRect) && !d->clipRect.isNull())
- || d->clipRect.isNull()) {
+ if (supportScaledSize) {
+ if (supportClipRect || d->clipRect.isNull()) {
// Only enable the ScaledSize option if there is no clip rect, or
// if the handler also supports ClipRect.
- d->handler->setOption(QImageIOHandler::ScaledSize, d->scaledSize);
+ d->handler->setOption(QImageIOHandler::ScaledSize, scaledSize);
}
}
- if (d->handler->supportsOption(QImageIOHandler::ClipRect) && !d->clipRect.isNull())
+ if (supportClipRect)
d->handler->setOption(QImageIOHandler::ClipRect, d->clipRect);
- if (d->handler->supportsOption(QImageIOHandler::ScaledClipRect) && !d->scaledClipRect.isNull())
+ if (supportScaledClipRect)
d->handler->setOption(QImageIOHandler::ScaledClipRect, d->scaledClipRect);
- if (d->handler->supportsOption(QImageIOHandler::Quality))
+ if (supportsOption(QImageIOHandler::Quality))
d->handler->setOption(QImageIOHandler::Quality, d->quality);
// read the image
@@ -1230,9 +1236,9 @@ bool QImageReader::read(QImage *image)
// provide default implementations for any unsupported image
// options
- if (d->handler->supportsOption(QImageIOHandler::ClipRect) && !d->clipRect.isNull()) {
- if (d->handler->supportsOption(QImageIOHandler::ScaledSize) && d->scaledSize.isValid()) {
- if (d->handler->supportsOption(QImageIOHandler::ScaledClipRect) && !d->scaledClipRect.isNull()) {
+ if (supportClipRect) {
+ if (supportScaledSize) {
+ if (supportScaledClipRect) {
// all features are supported by the handler; nothing to do.
} else {
// the image is already scaled, so apply scaled clipping.
@@ -1240,12 +1246,12 @@ bool QImageReader::read(QImage *image)
*image = image->copy(d->scaledClipRect);
}
} else {
- if (d->handler->supportsOption(QImageIOHandler::ScaledClipRect) && !d->scaledClipRect.isNull()) {
+ if (supportScaledClipRect) {
// supports scaled clipping but not scaling, most
// likely a broken handler.
} else {
- if (d->scaledSize.isValid()) {
- *image = image->scaled(d->scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ if (scaledSize.isValid()) {
+ *image = image->scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}
if (d->scaledClipRect.isValid()) {
*image = image->copy(d->scaledClipRect);
@@ -1253,8 +1259,8 @@ bool QImageReader::read(QImage *image)
}
}
} else {
- if (d->handler->supportsOption(QImageIOHandler::ScaledSize) && d->scaledSize.isValid() && d->clipRect.isNull()) {
- if (d->handler->supportsOption(QImageIOHandler::ScaledClipRect) && !d->scaledClipRect.isNull()) {
+ if (supportScaledSize && d->clipRect.isNull()) {
+ if (supportScaledClipRect) {
// nothing to do (ClipRect is ignored!)
} else {
// provide all workarounds.
@@ -1263,7 +1269,7 @@ bool QImageReader::read(QImage *image)
}
}
} else {
- if (d->handler->supportsOption(QImageIOHandler::ScaledClipRect) && !d->scaledClipRect.isNull()) {
+ if (supportScaledClipRect) {
// this makes no sense; a handler that supports
// ScaledClipRect but not ScaledSize is broken, and we
// can't work around it.
@@ -1271,8 +1277,8 @@ bool QImageReader::read(QImage *image)
// provide all workarounds.
if (d->clipRect.isValid())
*image = image->copy(d->clipRect);
- if (d->scaledSize.isValid())
- *image = image->scaled(d->scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ if (scaledSize.isValid())
+ *image = image->scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
if (d->scaledClipRect.isValid())
*image = image->copy(d->scaledClipRect);
}
@@ -1572,6 +1578,8 @@ int QImageReader::allocationLimit()
loading corrupt image files. It is normally not needed to change it. The
default limit is large enough for all commonly used image sizes.
+ At runtime, this value may be overridden by the environment variable \c QT_IMAGEIO_MAXALLOC.
+
\note The memory requirements are calculated for a minimum of 32 bits per pixel, since Qt will
typically convert an image to that depth when it is used in GUI. This means that the effective
allocation limit is significantly smaller than \a mbLimit when reading 1 bpp and 8 bpp images.
diff --git a/src/gui/image/qimagereaderwriterhelpers.cpp b/src/gui/image/qimagereaderwriterhelpers.cpp
index 1255cd827a..502b0f95f0 100644
--- a/src/gui/image/qimagereaderwriterhelpers.cpp
+++ b/src/gui/image/qimagereaderwriterhelpers.cpp
@@ -97,12 +97,14 @@ QList<QByteArray> supportedImageFormats(Capability cap)
return formats;
}
+static constexpr QByteArrayView imagePrefix() noexcept { return "image/"; }
+
QList<QByteArray> supportedMimeTypes(Capability cap)
{
QList<QByteArray> mimeTypes;
mimeTypes.reserve(_qt_NumFormats);
for (const auto &fmt : _qt_BuiltInFormats)
- mimeTypes.append(QByteArrayLiteral("image/") + fmt.mimeType);
+ mimeTypes.emplace_back(imagePrefix() + fmt.mimeType);
#ifndef QT_NO_IMAGEFORMATPLUGIN
appendImagePluginMimeTypes(irhLoader(), pluginCapability(cap), &mimeTypes);
@@ -113,11 +115,11 @@ QList<QByteArray> supportedMimeTypes(Capability cap)
return mimeTypes;
}
-QList<QByteArray> imageFormatsForMimeType(const QByteArray &mimeType, Capability cap)
+QList<QByteArray> imageFormatsForMimeType(QByteArrayView mimeType, Capability cap)
{
QList<QByteArray> formats;
- if (mimeType.startsWith("image/")) {
- const QByteArray type = mimeType.mid(sizeof("image/") - 1);
+ if (mimeType.startsWith(imagePrefix())) {
+ const QByteArrayView type = mimeType.mid(imagePrefix().size());
for (const auto &fmt : _qt_BuiltInFormats) {
if (fmt.mimeType == type && !formats.contains(fmt.extension))
formats << fmt.extension;
diff --git a/src/gui/image/qimagereaderwriterhelpers_p.h b/src/gui/image/qimagereaderwriterhelpers_p.h
index 8e999db5b9..930a57b536 100644
--- a/src/gui/image/qimagereaderwriterhelpers_p.h
+++ b/src/gui/image/qimagereaderwriterhelpers_p.h
@@ -94,7 +94,7 @@ enum Capability {
};
QList<QByteArray> supportedImageFormats(Capability cap);
QList<QByteArray> supportedMimeTypes(Capability cap);
-QList<QByteArray> imageFormatsForMimeType(const QByteArray &mimeType, Capability cap);
+QList<QByteArray> imageFormatsForMimeType(QByteArrayView mimeType, Capability cap);
}
diff --git a/src/gui/image/qmovie.cpp b/src/gui/image/qmovie.cpp
index 875d88225f..0d13639d35 100644
--- a/src/gui/image/qmovie.cpp
+++ b/src/gui/image/qmovie.cpp
@@ -53,7 +53,7 @@
Call supportedFormats() for a list of formats that QMovie supports.
- \sa QLabel, QImageReader, {Movie Example}
+ \sa QLabel, QImageReader
*/
/*! \enum QMovie::MovieState
@@ -144,11 +144,11 @@
#include "qrect.h"
#include "qelapsedtimer.h"
#include "qtimer.h"
-#include "qpair.h"
#include "qmap.h"
#include "qlist.h"
#include "qbuffer.h"
#include "qdir.h"
+#include "qloggingcategory.h"
#include "private/qobject_p.h"
#include "private/qproperty_p.h"
@@ -156,6 +156,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcImageIo)
+
class QFrameInfo
{
public:
@@ -306,6 +308,19 @@ QFrameInfo QMoviePrivate::infoForFrame(int frameNumber)
return QFrameInfo(); // Invalid
}
+ // For an animated image format, the tradition is that QMovie calls read()
+ // until canRead() == false, because the number of frames may not be known
+ // in advance; but if we're abusing a multi-frame format as an animation,
+ // canRead() may remain true, and we need to stop after reading the maximum
+ // number of frames that the image provides.
+ const bool supportsAnimation = reader->supportsOption(QImageIOHandler::Animation);
+ const int stopAtFrame = supportsAnimation ? -1 : frameCount();
+
+ // For an animated image format, QImageIOHandler::nextImageDelay() should
+ // provide the time to wait until showing the next frame; but multi-frame
+ // formats are not expected to provide this value, so use 1000 ms by default.
+ const auto nextFrameDelay = [&]() { return supportsAnimation ? reader->nextImageDelay() : 1000; };
+
if (cacheMode == QMovie::CacheNone) {
if (frameNumber != currentFrameNumber+1) {
// Non-sequential frame access
@@ -335,8 +350,12 @@ QFrameInfo QMoviePrivate::infoForFrame(int frameNumber)
}
}
}
- if (reader->canRead()) {
+ qCDebug(lcImageIo, "CacheNone: read frame %d of %d", frameNumber, stopAtFrame);
+ if (stopAtFrame > 0 ? (frameNumber < stopAtFrame) : reader->canRead()) {
// reader says we can read. Attempt to actually read image
+ // But if it's a non-animated multi-frame format and we know the frame count, stop there.
+ if (stopAtFrame > 0)
+ reader->jumpToImage(frameNumber);
QImage anImage = reader->read();
if (anImage.isNull()) {
// Reading image failed.
@@ -344,7 +363,7 @@ QFrameInfo QMoviePrivate::infoForFrame(int frameNumber)
}
if (frameNumber > greatestFrameNumber)
greatestFrameNumber = frameNumber;
- return QFrameInfo(QPixmap::fromImage(std::move(anImage)), reader->nextImageDelay());
+ return QFrameInfo(QPixmap::fromImage(std::move(anImage)), nextFrameDelay());
} else if (frameNumber != 0) {
// We've read all frames now. Return an end marker
haveReadAll = true;
@@ -360,15 +379,19 @@ QFrameInfo QMoviePrivate::infoForFrame(int frameNumber)
if (frameNumber > greatestFrameNumber) {
// Frame hasn't been read from file yet. Try to do it
for (int i = greatestFrameNumber + 1; i <= frameNumber; ++i) {
- if (reader->canRead()) {
+ qCDebug(lcImageIo, "CacheAll: read frame %d of %d", frameNumber, stopAtFrame);
+ if (stopAtFrame > 0 ? (frameNumber < stopAtFrame) : reader->canRead()) {
// reader says we can read. Attempt to actually read image
+ // But if it's a non-animated multi-frame format and we know the frame count, stop there.
+ if (stopAtFrame > 0)
+ reader->jumpToImage(frameNumber);
QImage anImage = reader->read();
if (anImage.isNull()) {
// Reading image failed.
return QFrameInfo(); // Invalid
}
greatestFrameNumber = i;
- QFrameInfo info(QPixmap::fromImage(std::move(anImage)), reader->nextImageDelay());
+ QFrameInfo info(QPixmap::fromImage(std::move(anImage)), nextFrameDelay());
// Cache it!
frameMap.insert(i, info);
if (i == frameNumber) {
@@ -426,11 +449,7 @@ bool QMoviePrivate::next()
}
// Image and delay OK, update internal state
currentFrameNumber = nextFrameNumber++;
- QSize scaledSize = reader->scaledSize();
- if (scaledSize.isValid() && (scaledSize != info.pixmap.size()))
- currentPixmap = QPixmap::fromImage( info.pixmap.toImage().scaled(scaledSize) );
- else
- currentPixmap = info.pixmap;
+ currentPixmap = info.pixmap;
if (!speed)
return true;
diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp
index 8b7de7ac23..89b8d5303b 100644
--- a/src/gui/image/qpixmap.cpp
+++ b/src/gui/image/qpixmap.cpp
@@ -1280,8 +1280,9 @@ QPixmap QPixmap::transformed(const QTransform &transform,
QPixmap using the fromImage(). If this is too expensive an
operation, you can use QBitmap::fromImage() instead.
- To convert a QPixmap to and from HICON you can use the QtWinExtras
- functions QtWin::toHICON() and QtWin::fromHICON() respectively.
+ To convert a QPixmap to and from HICON you can use the
+ QImage::toHICON() and QImage::fromHICON() functions respectively
+ (after converting the QPixmap to a QImage, as explained above).
\section1 Pixmap Transformations
diff --git a/src/gui/image/qpixmap_win.cpp b/src/gui/image/qpixmap_win.cpp
index 24af7636ce..fc601bccfc 100644
--- a/src/gui/image/qpixmap_win.cpp
+++ b/src/gui/image/qpixmap_win.cpp
@@ -164,7 +164,7 @@ static QImage copyImageData(const BITMAPINFOHEADER &header, const RGBQUAD *color
Q_ASSERT(DWORD(image.sizeInBytes()) == header.biSizeImage);
memcpy(image.bits(), data, header.biSizeImage);
if (format == QImage::Format_RGB888)
- image = image.rgbSwapped();
+ image = std::move(image).rgbSwapped();
break;
default:
Q_UNREACHABLE();
@@ -305,6 +305,7 @@ HBITMAP qt_imageToWinHBITMAP(const QImage &imageIn, int hbitmapFormat)
return nullptr;
}
if (!pixels) {
+ DeleteObject(bitmap);
qErrnoWarning("%s, did not allocate pixel data", __FUNCTION__);
return nullptr;
}
diff --git a/src/gui/image/qpixmapcache.cpp b/src/gui/image/qpixmapcache.cpp
index 016cd1a987..45c9743f93 100644
--- a/src/gui/image/qpixmapcache.cpp
+++ b/src/gui/image/qpixmapcache.cpp
@@ -184,7 +184,6 @@ public:
void timerEvent(QTimerEvent *) override;
bool insert(const QString& key, const QPixmap &pixmap, int cost);
QPixmapCache::Key insert(const QPixmap &pixmap, int cost);
- bool replace(const QPixmapCache::Key &key, const QPixmap &pixmap, int cost);
bool remove(const QString &key);
bool remove(const QPixmapCache::Key &key);
@@ -219,10 +218,15 @@ QT_BEGIN_INCLUDE_NAMESPACE
#include "qpixmapcache.moc"
QT_END_INCLUDE_NAMESPACE
-size_t qHash(const QPixmapCache::Key &k, size_t seed)
+/*!
+ size_t QPixmapCache::qHash(const Key &key, size_t seed = 0);
+ \since 6.6
+
+ Returns the hash value for the \a key, using \a seed to seed the calculation.
+*/
+size_t QPixmapCache::Key::hash(size_t seed) const noexcept
{
- const auto *keyData = QPMCache::get(k);
- return qHash(keyData ? keyData->key : 0, seed);
+ return qHash(this->d ? this->d->key : 0, seed);
}
QPMCache::QPMCache()
@@ -255,25 +259,12 @@ bool QPMCache::flushDetachedPixmaps(bool nt)
{
auto mc = maxCost();
const qsizetype currentTotal = totalCost();
+ const qsizetype oldSize = size();
if (currentTotal)
setMaxCost(nt ? currentTotal * 3 / 4 : currentTotal - 1);
setMaxCost(mc);
ps = totalCost();
-
- bool any = false;
- QHash<QString, QPixmapCache::Key>::iterator it = cacheKeys.begin();
- while (it != cacheKeys.end()) {
- const auto value = it.value();
- if (value.isValid() && !contains(value)) {
- releaseKey(value);
- it = cacheKeys.erase(it);
- any = true;
- } else {
- ++it;
- }
- }
-
- return any;
+ return size() != oldSize;
}
void QPMCache::timerEvent(QTimerEvent *)
@@ -292,17 +283,9 @@ void QPMCache::timerEvent(QTimerEvent *)
QPixmap *QPMCache::object(const QString &key) const
{
- QPixmapCache::Key cacheKey = cacheKeys.value(key);
- if (!cacheKey.d || !cacheKey.d->isValid) {
- const_cast<QPMCache *>(this)->cacheKeys.remove(key);
- return nullptr;
- }
- QPixmap *ptr = QCache<QPixmapCache::Key, QPixmapCacheEntry>::object(cacheKey);
- //We didn't find the pixmap in the cache, the key is not valid anymore
- if (!ptr) {
- const_cast<QPMCache *>(this)->cacheKeys.remove(key);
- }
- return ptr;
+ if (const auto it = cacheKeys.find(key); it != cacheKeys.cend())
+ return object(it.value());
+ return nullptr;
}
QPixmap *QPMCache::object(const QPixmapCache::Key &key) const
@@ -317,31 +300,24 @@ QPixmap *QPMCache::object(const QPixmapCache::Key &key) const
bool QPMCache::insert(const QString& key, const QPixmap &pixmap, int cost)
{
- QPixmapCache::Key &cacheKey = cacheKeys[key];
//If for the same key we add already a pixmap we should delete it
- if (cacheKey.d)
- QCache<QPixmapCache::Key, QPixmapCacheEntry>::remove(cacheKey);
-
- //we create a new key the old one has been removed
- cacheKey = createKey();
+ remove(key);
- bool success = QCache<QPixmapCache::Key, QPixmapCacheEntry>::insert(cacheKey, new QPixmapCacheEntry(cacheKey, pixmap), cost);
- if (success) {
- if (!theid) {
- theid = startTimer(flush_time);
- t = false;
- }
- } else {
- //Insertion failed we released the new allocated key
- cacheKeys.remove(key);
+ // this will create a new key; the old one has been removed
+ auto k = insert(pixmap, cost);
+ if (k.isValid()) {
+ k.d->stringKey = key;
+ cacheKeys[key] = std::move(k);
+ return true;
}
- return success;
+ return false;
}
QPixmapCache::Key QPMCache::insert(const QPixmap &pixmap, int cost)
{
- QPixmapCache::Key cacheKey = createKey();
+ QPixmapCache::Key cacheKey = createKey(); // invalidated by ~QPixmapCacheEntry on failed insert
bool success = QCache<QPixmapCache::Key, QPixmapCacheEntry>::insert(cacheKey, new QPixmapCacheEntry(cacheKey, pixmap), cost);
+ Q_ASSERT(success || !cacheKey.isValid());
if (success) {
if (!theid) {
theid = startTimer(flush_time);
@@ -351,34 +327,10 @@ QPixmapCache::Key QPMCache::insert(const QPixmap &pixmap, int cost)
return cacheKey;
}
-bool QPMCache::replace(const QPixmapCache::Key &key, const QPixmap &pixmap, int cost)
-{
- Q_ASSERT(key.isValid());
- //If for the same key we had already an entry so we should delete the pixmap and use the new one
- QCache<QPixmapCache::Key, QPixmapCacheEntry>::remove(key);
-
- QPixmapCache::Key cacheKey = createKey();
-
- bool success = QCache<QPixmapCache::Key, QPixmapCacheEntry>::insert(cacheKey, new QPixmapCacheEntry(cacheKey, pixmap), cost);
- if (success) {
- if (!theid) {
- theid = startTimer(flush_time);
- t = false;
- }
- const_cast<QPixmapCache::Key&>(key) = cacheKey;
- }
- return success;
-}
-
bool QPMCache::remove(const QString &key)
{
- auto cacheKey = cacheKeys.constFind(key);
- //The key was not in the cache
- if (cacheKey == cacheKeys.constEnd())
- return false;
- const bool result = QCache<QPixmapCache::Key, QPixmapCacheEntry>::remove(cacheKey.value());
- cacheKeys.erase(cacheKey);
- return result;
+ const auto cacheKey = cacheKeys.take(key);
+ return cacheKey.isValid() && remove(cacheKey);
}
bool QPMCache::remove(const QPixmapCache::Key &key)
@@ -412,7 +364,11 @@ QPixmapCache::Key QPMCache::createKey()
void QPMCache::releaseKey(const QPixmapCache::Key &key)
{
QPixmapCache::KeyData *keyData = key.d;
- if (!keyData || keyData->key > keyArraySize || keyData->key <= 0)
+ if (!keyData)
+ return;
+ if (!keyData->stringKey.isNull())
+ cacheKeys.remove(keyData->stringKey);
+ if (keyData->key > keyArraySize || keyData->key <= 0)
return;
keyData->key--;
keyArray[keyData->key] = freeKey;
@@ -473,7 +429,7 @@ QPixmapCacheEntry::~QPixmapCacheEntry()
bool QPixmapCache::find(const QString &key, QPixmap *pixmap)
{
- if (!qt_pixmapcache_thread_test())
+ if (key.isEmpty() || !qt_pixmapcache_thread_test())
return false;
QPixmap *ptr = pm_cache()->object(key);
if (ptr && pixmap)
@@ -525,7 +481,7 @@ bool QPixmapCache::find(const Key &key, QPixmap *pixmap)
bool QPixmapCache::insert(const QString &key, const QPixmap &pixmap)
{
- if (!qt_pixmapcache_thread_test())
+ if (key.isEmpty() || !qt_pixmapcache_thread_test())
return false;
return pm_cache()->insert(key, pixmap, cost(pixmap));
}
@@ -552,24 +508,25 @@ QPixmapCache::Key QPixmapCache::insert(const QPixmap &pixmap)
return pm_cache()->insert(pixmap, cost(pixmap));
}
+#if QT_DEPRECATED_SINCE(6, 6)
/*!
+ \fn bool QPixmapCache::replace(const Key &key, const QPixmap &pixmap)
+
+ \deprecated [6.6] Use \c{remove(key); key = insert(pixmap);} instead.
+
Replaces the pixmap associated with the given \a key with the \a pixmap
specified. Returns \c true if the \a pixmap has been correctly inserted into
the cache; otherwise returns \c false.
+ The passed \a key is updated to reference \a pixmap now. Other copies of \a
+ key, if any, still refer to the old pixmap, which is, however, removed from
+ the cache by this function.
+
\sa setCacheLimit(), insert()
\since 4.6
*/
-bool QPixmapCache::replace(const Key &key, const QPixmap &pixmap)
-{
- if (!qt_pixmapcache_thread_test())
- return false;
- //The key is not valid anymore, a flush happened before probably
- if (!key.d || !key.d->isValid)
- return false;
- return pm_cache()->replace(key, pixmap, cost(pixmap));
-}
+#endif // QT_DEPRECATED_SINCE(6, 6)
/*!
Returns the cache limit (in kilobytes).
@@ -606,7 +563,7 @@ void QPixmapCache::setCacheLimit(int n)
*/
void QPixmapCache::remove(const QString &key)
{
- if (!qt_pixmapcache_thread_test())
+ if (key.isEmpty() || !qt_pixmapcache_thread_test())
return;
pm_cache()->remove(key);
}
diff --git a/src/gui/image/qpixmapcache.h b/src/gui/image/qpixmapcache.h
index 433890c68f..72ee1b797f 100644
--- a/src/gui/image/qpixmapcache.h
+++ b/src/gui/image/qpixmapcache.h
@@ -31,6 +31,10 @@ public:
bool isValid() const noexcept;
private:
+ friend size_t qHash(const QPixmapCache::Key &k, size_t seed = 0) noexcept
+ { return k.hash(seed); }
+ size_t hash(size_t seed) const noexcept;
+
KeyData *d;
friend class QPMCache;
friend class QPixmapCache;
@@ -42,13 +46,30 @@ public:
static bool find(const Key &key, QPixmap *pixmap);
static bool insert(const QString &key, const QPixmap &pixmap);
static Key insert(const QPixmap &pixmap);
+#if QT_DEPRECATED_SINCE(6, 6)
+ QT_DEPRECATED_VERSION_X_6_6("Use remove(key), followed by key = insert(pixmap).")
+ QT_GUI_INLINE_SINCE(6, 6)
static bool replace(const Key &key, const QPixmap &pixmap);
+#endif
static void remove(const QString &key);
static void remove(const Key &key);
static void clear();
};
Q_DECLARE_SHARED(QPixmapCache::Key)
+#if QT_DEPRECATED_SINCE(6, 6)
+#if QT_GUI_INLINE_IMPL_SINCE(6, 6)
+bool QPixmapCache::replace(const Key &key, const QPixmap &pixmap)
+{
+ if (!key.isValid())
+ return false;
+ remove(key);
+ const_cast<Key&>(key) = insert(pixmap);
+ return key.isValid();
+}
+#endif // QT_GUI_INLINE_IMPL_SINCE(6, 6)
+#endif // QT_DEPRECATED_SINCE(6, 6)
+
QT_END_NAMESPACE
#endif // QPIXMAPCACHE_H
diff --git a/src/gui/image/qpixmapcache_p.h b/src/gui/image/qpixmapcache_p.h
index 6418296f56..43c4d9784c 100644
--- a/src/gui/image/qpixmapcache_p.h
+++ b/src/gui/image/qpixmapcache_p.h
@@ -23,8 +23,6 @@
QT_BEGIN_NAMESPACE
-size_t qHash(const QPixmapCache::Key &k, size_t seed = 0);
-
class QPixmapCache::KeyData
{
public:
@@ -33,6 +31,7 @@ public:
: isValid(other.isValid), key(other.key), ref(1) {}
~KeyData() {}
+ QString stringKey;
bool isValid;
int key;
int ref;
diff --git a/src/gui/image/qplatformpixmap.cpp b/src/gui/image/qplatformpixmap.cpp
index 2e622723ee..a297736095 100644
--- a/src/gui/image/qplatformpixmap.cpp
+++ b/src/gui/image/qplatformpixmap.cpp
@@ -65,10 +65,10 @@ QPlatformPixmap *QPlatformPixmap::createCompatiblePlatformPixmap() const
return d;
}
-static QImage makeBitmapCompliantIfNeeded(QPlatformPixmap *d, const QImage &image, Qt::ImageConversionFlags flags)
+static QImage makeBitmapCompliantIfNeeded(QPlatformPixmap *d, QImage image, Qt::ImageConversionFlags flags)
{
if (d->pixelType() == QPlatformPixmap::BitmapType) {
- QImage img = image.convertToFormat(QImage::Format_MonoLSB, flags);
+ QImage img = std::move(image).convertToFormat(QImage::Format_MonoLSB, flags);
// make sure image.color(0) == Qt::color0 (white)
// and image.color(1) == Qt::color1 (black)
@@ -98,7 +98,7 @@ bool QPlatformPixmap::fromFile(const QString &fileName, const char *format,
QImage image = QImageReader(fileName, format).read();
if (image.isNull())
return false;
- fromImage(makeBitmapCompliantIfNeeded(this, image, flags), flags);
+ fromImage(makeBitmapCompliantIfNeeded(this, std::move(image), flags), flags);
return !isNull();
}
@@ -110,7 +110,7 @@ bool QPlatformPixmap::fromData(const uchar *buf, uint len, const char *format, Q
QImage image = QImageReader(&b, format).read();
if (image.isNull())
return false;
- fromImage(makeBitmapCompliantIfNeeded(this, image, flags), flags);
+ fromImage(makeBitmapCompliantIfNeeded(this, std::move(image), flags), flags);
return !isNull();
}
@@ -132,9 +132,9 @@ QBitmap QPlatformPixmap::mask() const
if (!hasAlphaChannel())
return QBitmap();
- const QImage img = toImage();
+ QImage img = toImage();
bool shouldConvert = (img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_ARGB32_Premultiplied);
- const QImage image = (shouldConvert ? img.convertToFormat(QImage::Format_ARGB32_Premultiplied) : img);
+ const QImage image = (shouldConvert ? std::move(img).convertToFormat(QImage::Format_ARGB32_Premultiplied) : img);
const int w = image.width();
const int h = image.height();
@@ -160,7 +160,7 @@ QBitmap QPlatformPixmap::mask() const
}
}
- return QBitmap::fromImage(mask);
+ return QBitmap::fromImage(std::move(mask));
}
void QPlatformPixmap::setMask(const QBitmap &mask)
@@ -168,7 +168,7 @@ void QPlatformPixmap::setMask(const QBitmap &mask)
QImage image = toImage();
if (mask.size().isEmpty()) {
if (image.depth() != 1) { // hw: ????
- image = image.convertToFormat(QImage::Format_RGB32);
+ image = std::move(image).convertToFormat(QImage::Format_RGB32);
}
} else {
const int w = image.width();
@@ -188,7 +188,7 @@ void QPlatformPixmap::setMask(const QBitmap &mask)
}
default: {
const QImage imageMask = mask.toImage().convertToFormat(QImage::Format_MonoLSB);
- image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ image = std::move(image).convertToFormat(QImage::Format_ARGB32_Premultiplied);
for (int y = 0; y < h; ++y) {
const uchar *mscan = imageMask.scanLine(y);
QRgb *tscan = (QRgb *)image.scanLine(y);
diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp
index c9b12c15f8..615a36fa36 100644
--- a/src/gui/image/qpnghandler.cpp
+++ b/src/gui/image/qpnghandler.cpp
@@ -554,10 +554,10 @@ bool QPngHandlerPrivate::readPngHeader()
#endif
png_uint_32 profLen;
png_get_iCCP(png_ptr, info_ptr, &name, &compressionType, &profileData, &profLen);
- colorSpace = QColorSpace::fromIccProfile(QByteArray((const char *)profileData, profLen));
- if (!colorSpace.isValid()) {
- qCDebug(lcImageIo) << "QPngHandler: Failed to parse ICC profile";
- } else {
+ Q_UNUSED(name);
+ Q_UNUSED(compressionType);
+ if (profLen > 0) {
+ colorSpace = QColorSpace::fromIccProfile(QByteArray((const char *)profileData, profLen));
QColorSpacePrivate *csD = QColorSpacePrivate::get(colorSpace);
if (csD->description.isEmpty())
csD->description = QString::fromLatin1((const char *)name);
@@ -926,15 +926,15 @@ bool QPNGImageWriter::writeImage(const QImage& image, int compression_in, const
color_type, 0, 0, 0); // sets #channels
#ifdef PNG_iCCP_SUPPORTED
- if (image.colorSpace().isValid()) {
- QColorSpace cs = image.colorSpace();
- // Support the old gamma making it override transferfunction.
- if (gamma != 0.0 && !qFuzzyCompare(cs.gamma(), 1.0f / gamma))
- cs = cs.withTransferFunction(QColorSpace::TransferFunction::Gamma, 1.0f / gamma);
+ QColorSpace cs = image.colorSpace();
+ // Support the old gamma making it override transferfunction (if possible)
+ if (cs.isValid() && gamma != 0.0 && !qFuzzyCompare(cs.gamma(), 1.0f / gamma))
+ cs = cs.withTransferFunction(QColorSpace::TransferFunction::Gamma, 1.0f / gamma);
+ QByteArray iccProfile = cs.iccProfile();
+ if (!iccProfile.isEmpty()) {
QByteArray iccProfileName = cs.description().toLatin1();
if (iccProfileName.isEmpty())
iccProfileName = QByteArrayLiteral("Custom");
- QByteArray iccProfile = cs.iccProfile();
png_set_iCCP(png_ptr, info_ptr,
#if PNG_LIBPNG_VER < 10500
iccProfileName.data(), PNG_COMPRESSION_TYPE_BASE, iccProfile.data(),
diff --git a/src/gui/image/qppmhandler.cpp b/src/gui/image/qppmhandler.cpp
index e53db69e66..3a4af46195 100644
--- a/src/gui/image/qppmhandler.cpp
+++ b/src/gui/image/qppmhandler.cpp
@@ -32,7 +32,7 @@ static void discard_pbm_line(QIODevice *d)
} while (res > 0 && buf[res-1] != '\n');
}
-static int read_pbm_int(QIODevice *d, bool *ok)
+static int read_pbm_int(QIODevice *d, bool *ok, int maxDigits = -1)
{
char c;
int val = -1;
@@ -50,6 +50,8 @@ static int read_pbm_int(QIODevice *d, bool *ok)
} else {
hasOverflow = true;
}
+ if (maxDigits > 0 && --maxDigits == 0)
+ break;
continue;
} else {
if (c == '#') // comment
@@ -65,6 +67,8 @@ static int read_pbm_int(QIODevice *d, bool *ok)
discard_pbm_line(d);
else
break;
+ if (maxDigits > 0 && --maxDigits == 0)
+ break;
}
if (val < 0)
*ok = false;
@@ -213,7 +217,7 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q
b = 0;
for (int i=0; i<8; i++) {
if (i < bitsLeft)
- b = (b << 1) | (read_pbm_int(device, &ok) & 1);
+ b = (b << 1) | (read_pbm_int(device, &ok, 1) & 1);
else
b = (b << 1) | (0 & 1); // pad it our self if we need to
}
@@ -265,13 +269,12 @@ static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, Q
return true;
}
-static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, const QByteArray &sourceFormat)
+static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, QByteArrayView sourceFormat)
{
QByteArray str;
QImage image = sourceImage;
- QByteArray format = sourceFormat;
+ const QByteArrayView format = sourceFormat.left(3); // ignore RAW part
- format = format.left(3); // ignore RAW part
bool gray = format == "pgm";
if (format == "pbm") {
@@ -341,7 +344,7 @@ static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, const QBy
qsizetype bpl = qsizetype(w) * (gray ? 1 : 3);
uchar *buf = new uchar[bpl];
if (image.format() == QImage::Format_Indexed8) {
- QList<QRgb> color = image.colorTable();
+ const QList<QRgb> color = image.colorTable();
for (uint y=0; y<h; y++) {
const uchar *b = image.constScanLine(y);
uchar *p = buf;
diff --git a/src/gui/itemmodels/qfileinfogatherer.cpp b/src/gui/itemmodels/qfileinfogatherer.cpp
index 0e0a3b11a5..41fb0a0db5 100644
--- a/src/gui/itemmodels/qfileinfogatherer.cpp
+++ b/src/gui/itemmodels/qfileinfogatherer.cpp
@@ -2,8 +2,10 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qfileinfogatherer_p.h"
+#include <qcoreapplication.h>
#include <qdebug.h>
-#include <qdiriterator.h>
+#include <qdirlisting.h>
+#include <private/qabstractfileiconprovider_p.h>
#include <private/qfileinfo_p.h>
#ifndef Q_OS_WIN
# include <unistd.h>
@@ -57,11 +59,40 @@ QFileInfoGatherer::QFileInfoGatherer(QObject *parent)
*/
QFileInfoGatherer::~QFileInfoGatherer()
{
- abort.storeRelaxed(true);
+ requestAbort();
+ wait();
+}
+
+bool QFileInfoGatherer::event(QEvent *event)
+{
+ if (event->type() == QEvent::DeferredDelete && isRunning()) {
+ // We have been asked to shut down later but were blocked,
+ // so the owning QFileSystemModel proceeded with its shut-down
+ // and deferred the destruction of the gatherer.
+ // If we are still blocked now, then we have three bad options:
+ // terminate, wait forever (preventing the process from shutting down),
+ // or accept a memory leak.
+ requestAbort();
+ if (!wait(5000)) {
+ // If the application is shutting down, then we terminate.
+ // Otherwise assume that sooner or later the thread will finish,
+ // and we delete it then.
+ if (QCoreApplication::closingDown())
+ terminate();
+ else
+ connect(this, &QThread::finished, this, [this]{ delete this; });
+ return true;
+ }
+ }
+
+ return QThread::event(event);
+}
+
+void QFileInfoGatherer::requestAbort()
+{
+ requestInterruption();
QMutexLocker locker(&mutex);
condition.wakeAll();
- locker.unlock();
- wait();
}
void QFileInfoGatherer::setResolveSymlinks(bool enable)
@@ -114,13 +145,12 @@ void QFileInfoGatherer::fetchExtendedInformation(const QString &path, const QStr
{
QMutexLocker locker(&mutex);
// See if we already have this dir/file in our queue
- int loc = this->path.lastIndexOf(path);
- while (loc > 0) {
- if (this->files.at(loc) == files) {
+ qsizetype loc = 0;
+ while ((loc = this->path.lastIndexOf(path, loc - 1)) != -1) {
+ if (this->files.at(loc) == files)
return;
- }
- loc = this->path.lastIndexOf(path, loc - 1);
}
+
#if QT_CONFIG(thread)
this->path.push(path);
this->files.push(files);
@@ -220,16 +250,23 @@ bool QFileInfoGatherer::isWatching() const
return result;
}
+/*! \internal
+
+ If \a v is \c false, the QFileSystemWatcher used internally will be deleted
+ and subsequent calls to watchPaths() will do nothing.
+
+ If \a v is \c true, subsequent calls to watchPaths() will add those paths to
+ the filesystem watcher; watchPaths() will initialize a QFileSystemWatcher if
+ one hasn't already been initialized.
+*/
void QFileInfoGatherer::setWatching(bool v)
{
#if QT_CONFIG(filesystemwatcher)
QMutexLocker locker(&mutex);
if (v != m_watching) {
- if (!v) {
- delete m_watcher;
- m_watcher = nullptr;
- }
m_watching = v;
+ if (!m_watching)
+ delete std::exchange(m_watcher, nullptr);
}
#else
Q_UNUSED(v);
@@ -281,10 +318,13 @@ void QFileInfoGatherer::list(const QString &directoryPath)
void QFileInfoGatherer::run()
{
forever {
+ // Disallow termination while we are holding a mutex or can be
+ // woken up cleanly.
+ setTerminationEnabled(false);
QMutexLocker locker(&mutex);
- while (!abort.loadRelaxed() && path.isEmpty())
+ while (!isInterruptionRequested() && path.isEmpty())
condition.wait(&mutex);
- if (abort.loadRelaxed())
+ if (isInterruptionRequested())
return;
const QString thisPath = std::as_const(path).front();
path.pop_front();
@@ -292,6 +332,10 @@ void QFileInfoGatherer::run()
files.pop_front();
locker.unlock();
+ // Some of the system APIs we call when gathering file infomration
+ // might hang (e.g. waiting for network), so we explicitly allow
+ // termination now.
+ setTerminationEnabled(true);
getFileInfos(thisPath, thisList);
}
}
@@ -299,8 +343,12 @@ void QFileInfoGatherer::run()
QExtendedInformation QFileInfoGatherer::getInfo(const QFileInfo &fileInfo) const
{
QExtendedInformation info(fileInfo);
- info.icon = m_iconProvider->icon(fileInfo);
- info.displayType = m_iconProvider->type(fileInfo);
+ if (m_iconProvider) {
+ info.icon = m_iconProvider->icon(fileInfo);
+ info.displayType = m_iconProvider->type(fileInfo);
+ } else {
+ info.displayType = QAbstractFileIconProviderPrivate::getFileType(fileInfo);
+ }
#if QT_CONFIG(filesystemwatcher)
// ### Not ready to listen all modifications by default
static const bool watchFiles = qEnvironmentVariableIsSet("QT_FILESYSTEMMODEL_WATCH_FILES");
@@ -340,21 +388,23 @@ void QFileInfoGatherer::getFileInfos(const QString &path, const QStringList &fil
#ifdef QT_BUILD_INTERNAL
fetchedRoot.storeRelaxed(true);
#endif
- QFileInfoList infoList;
+ QList<std::pair<QString, QFileInfo>> updatedFiles;
+ auto addToUpdatedFiles = [&updatedFiles](QFileInfo &&fileInfo) {
+ fileInfo.stat();
+ updatedFiles.emplace_back(std::pair{translateDriveName(fileInfo), fileInfo});
+ };
+
if (files.isEmpty()) {
- infoList = QDir::drives();
+ // QDir::drives() calls QFSFileEngine::drives() which creates the QFileInfoList on
+ // the stack and return it, so this list is not shared, so no detaching.
+ QFileInfoList infoList = QDir::drives();
+ updatedFiles.reserve(infoList.size());
+ for (auto rit = infoList.rbegin(), rend = infoList.rend(); rit != rend; ++rit)
+ addToUpdatedFiles(std::move(*rit));
} else {
- infoList.reserve(files.size());
- for (const auto &file : files)
- infoList << QFileInfo(file);
- }
- QList<QPair<QString, QFileInfo>> updatedFiles;
- updatedFiles.reserve(infoList.size());
- for (int i = infoList.size() - 1; i >= 0; --i) {
- QFileInfo driveInfo = infoList.at(i);
- driveInfo.stat();
- QString driveName = translateDriveName(driveInfo);
- updatedFiles.append(QPair<QString,QFileInfo>(driveName, driveInfo));
+ updatedFiles.reserve(files.size());
+ for (auto rit = files.crbegin(), rend = files.crend(); rit != rend; ++rit)
+ addToUpdatedFiles(QFileInfo(*rit));
}
emit updates(path, updatedFiles);
return;
@@ -364,14 +414,16 @@ void QFileInfoGatherer::getFileInfos(const QString &path, const QStringList &fil
base.start();
QFileInfo fileInfo;
bool firstTime = true;
- QList<QPair<QString, QFileInfo>> updatedFiles;
+ QList<std::pair<QString, QFileInfo>> updatedFiles;
QStringList filesToCheck = files;
QStringList allFiles;
if (files.isEmpty()) {
- QDirIterator dirIt(path, QDir::AllEntries | QDir::System | QDir::Hidden);
- while (!abort.loadRelaxed() && dirIt.hasNext()) {
- fileInfo = dirIt.nextFileInfo();
+ constexpr auto dirFilters = QDir::AllEntries | QDir::System | QDir::Hidden;
+ for (const auto &dirEntry : QDirListing(path, dirFilters)) {
+ if (isInterruptionRequested())
+ break;
+ fileInfo = dirEntry.fileInfo();
fileInfo.stat();
allFiles.append(fileInfo.fileName());
fetch(fileInfo, base, firstTime, updatedFiles, path);
@@ -381,7 +433,7 @@ void QFileInfoGatherer::getFileInfos(const QString &path, const QStringList &fil
emit newListOfFiles(path, allFiles);
QStringList::const_iterator filesIt = filesToCheck.constBegin();
- while (!abort.loadRelaxed() && filesIt != filesToCheck.constEnd()) {
+ while (!isInterruptionRequested() && filesIt != filesToCheck.constEnd()) {
fileInfo.setFile(path + QDir::separator() + *filesIt);
++filesIt;
fileInfo.stat();
@@ -393,9 +445,9 @@ void QFileInfoGatherer::getFileInfos(const QString &path, const QStringList &fil
}
void QFileInfoGatherer::fetch(const QFileInfo &fileInfo, QElapsedTimer &base, bool &firstTime,
- QList<QPair<QString, QFileInfo>> &updatedFiles, const QString &path)
+ QList<std::pair<QString, QFileInfo>> &updatedFiles, const QString &path)
{
- updatedFiles.append(QPair<QString, QFileInfo>(fileInfo.fileName(), fileInfo));
+ updatedFiles.emplace_back(std::pair(fileInfo.fileName(), fileInfo));
QElapsedTimer current;
current.start();
if ((firstTime && updatedFiles.size() > 100) || base.msecsTo(current) > 1000) {
diff --git a/src/gui/itemmodels/qfileinfogatherer_p.h b/src/gui/itemmodels/qfileinfogatherer_p.h
index e4b2bc889f..3d5f59c22e 100644
--- a/src/gui/itemmodels/qfileinfogatherer_p.h
+++ b/src/gui/itemmodels/qfileinfogatherer_p.h
@@ -24,7 +24,6 @@
#include <qfilesystemwatcher.h>
#endif
#include <qabstractfileiconprovider.h>
-#include <qpair.h>
#include <qstack.h>
#include <qdatetime.h>
#include <qdir.h>
@@ -32,6 +31,8 @@
#include <private/qfilesystemengine_p.h>
+#include <utility>
+
QT_REQUIRE_CONFIG(filesystemmodel);
QT_BEGIN_NAMESPACE
@@ -124,7 +125,7 @@ class Q_GUI_EXPORT QFileInfoGatherer : public QThread
Q_OBJECT
Q_SIGNALS:
- void updates(const QString &directory, const QList<QPair<QString, QFileInfo>> &updates);
+ void updates(const QString &directory, const QList<std::pair<QString, QFileInfo>> &updates);
void newListOfFiles(const QString &directory, const QStringList &listOfFiles) const;
void nameResolved(const QString &fileName, const QString &resolvedName) const;
void directoryLoaded(const QString &path);
@@ -148,6 +149,8 @@ public:
QAbstractFileIconProvider *iconProvider() const;
bool resolveSymlinks() const;
+ void requestAbort();
+
public Q_SLOTS:
void list(const QString &directoryPath);
void fetchExtendedInformation(const QString &path, const QStringList &files);
@@ -159,12 +162,15 @@ private Q_SLOTS:
void driveAdded();
void driveRemoved();
+protected:
+ bool event(QEvent *event) override;
+
private:
void run() override;
// called by run():
void getFileInfos(const QString &path, const QStringList &files);
void fetch(const QFileInfo &info, QElapsedTimer &base, bool &firstTime,
- QList<QPair<QString, QFileInfo>> &updatedFiles, const QString &path);
+ QList<std::pair<QString, QFileInfo>> &updatedFiles, const QString &path);
private:
void createWatcher();
@@ -175,7 +181,6 @@ private:
QStack<QString> path;
QStack<QStringList> files;
// end protected by mutex
- QAtomicInt abort;
#if QT_CONFIG(filesystemwatcher)
QFileSystemWatcher *m_watcher = nullptr;
diff --git a/src/gui/itemmodels/qfilesystemmodel.cpp b/src/gui/itemmodels/qfilesystemmodel.cpp
index 9a54b8d8bd..290891322f 100644
--- a/src/gui/itemmodels/qfilesystemmodel.cpp
+++ b/src/gui/itemmodels/qfilesystemmodel.cpp
@@ -31,6 +31,7 @@ using namespace Qt::StringLiterals;
\value FilePathRole
\value FileNameRole
\value FilePermissions
+ \value FileInfoRole The QFileInfo object for the index
*/
/*!
@@ -240,7 +241,7 @@ QModelIndex QFileSystemModel::index(int row, int column, const QModelIndex &pare
*/
QModelIndex QFileSystemModel::sibling(int row, int column, const QModelIndex &idx) const
{
- if (row == idx.row() && column < QFileSystemModelPrivate::NumColumns) {
+ if (row == idx.row() && column < columnCount(idx.parent())) {
// cheap sibling operation: just adjust the column:
return createIndex(row, column, idx.internalPointer());
} else {
@@ -438,7 +439,7 @@ QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QS
QFileSystemModelPrivate *p = const_cast<QFileSystemModelPrivate*>(this);
node = p->addNode(parent, element,info);
#if QT_CONFIG(filesystemwatcher)
- node->populate(fileInfoGatherer.getInfo(info));
+ node->populate(fileInfoGatherer->getInfo(info));
#endif
} else {
node = parent->children.value(element);
@@ -479,7 +480,7 @@ void QFileSystemModel::timerEvent(QTimerEvent *event)
for (int i = 0; i < d->toFetch.size(); ++i) {
const QFileSystemModelPrivate::QFileSystemNode *node = d->toFetch.at(i).node;
if (!node->hasInformation()) {
- d->fileInfoGatherer.fetchExtendedInformation(d->toFetch.at(i).dir,
+ d->fileInfoGatherer->fetchExtendedInformation(d->toFetch.at(i).dir,
QStringList(d->toFetch.at(i).file));
} else {
// qDebug("yah!, you saved a little gerbil soul");
@@ -650,7 +651,7 @@ void QFileSystemModel::fetchMore(const QModelIndex &parent)
return;
indexNode->populatedChildren = true;
#if QT_CONFIG(filesystemwatcher)
- d->fileInfoGatherer.list(filePath(parent));
+ d->fileInfoGatherer->list(filePath(parent));
#endif
}
@@ -693,7 +694,9 @@ QVariant QFileSystemModel::myComputer(int role) const
return QFileSystemModelPrivate::myComputer();
#if QT_CONFIG(filesystemwatcher)
case Qt::DecorationRole:
- return d->fileInfoGatherer.iconProvider()->icon(QAbstractFileIconProvider::Computer);
+ if (auto *provider = d->fileInfoGatherer->iconProvider())
+ return provider->icon(QAbstractFileIconProvider::Computer);
+ break;
#endif
}
return QVariant();
@@ -710,15 +713,15 @@ QVariant QFileSystemModel::data(const QModelIndex &index, int role) const
switch (role) {
case Qt::EditRole:
- if (index.column() == 0)
+ if (index.column() == QFileSystemModelPrivate::NameColumn)
return d->name(index);
Q_FALLTHROUGH();
case Qt::DisplayRole:
switch (index.column()) {
- case 0: return d->displayName(index);
- case 1: return d->size(index);
- case 2: return d->type(index);
- case 3: return d->time(index);
+ case QFileSystemModelPrivate::NameColumn: return d->displayName(index);
+ case QFileSystemModelPrivate::SizeColumn: return d->size(index);
+ case QFileSystemModelPrivate::TypeColumn: return d->type(index);
+ case QFileSystemModelPrivate::TimeColumn: return d->time(index);
default:
qWarning("data: invalid display value column %d", index.column());
break;
@@ -728,22 +731,23 @@ QVariant QFileSystemModel::data(const QModelIndex &index, int role) const
return filePath(index);
case FileNameRole:
return d->name(index);
+ case FileInfoRole:
+ return QVariant::fromValue(fileInfo(index));
case Qt::DecorationRole:
- if (index.column() == 0) {
+ if (index.column() == QFileSystemModelPrivate::NameColumn) {
QIcon icon = d->icon(index);
#if QT_CONFIG(filesystemwatcher)
if (icon.isNull()) {
- if (d->node(index)->isDir())
- icon = d->fileInfoGatherer.iconProvider()->icon(QAbstractFileIconProvider::Folder);
- else
- icon = d->fileInfoGatherer.iconProvider()->icon(QAbstractFileIconProvider::File);
+ using P = QAbstractFileIconProvider;
+ if (auto *provider = d->fileInfoGatherer->iconProvider())
+ icon = provider->icon(d->node(index)->isDir() ? P::Folder: P::File);
}
#endif // filesystemwatcher
return icon;
}
break;
case Qt::TextAlignmentRole:
- if (index.column() == 1)
+ if (index.column() == QFileSystemModelPrivate::SizeColumn)
return QVariant(Qt::AlignTrailing | Qt::AlignVCenter);
break;
case FilePermissions:
@@ -816,7 +820,7 @@ QString QFileSystemModelPrivate::name(const QModelIndex &index) const
QFileSystemNode *dirNode = node(index);
if (
#if QT_CONFIG(filesystemwatcher)
- fileInfoGatherer.resolveSymlinks() &&
+ fileInfoGatherer->resolveSymlinks() &&
#endif
!resolvedSymLinks.isEmpty() && dirNode->isSymLink(/* ignoreNtfsSymLinks = */ true)) {
QString fullPath = QDir::fromNativeSeparators(filePath(index));
@@ -901,7 +905,7 @@ bool QFileSystemModel::setData(const QModelIndex &idx, const QVariant &value, in
nodeToRename->fileName = newName;
nodeToRename->parent = parentNode;
#if QT_CONFIG(filesystemwatcher)
- nodeToRename->populate(d->fileInfoGatherer.getInfo(QFileInfo(parentPath, newName)));
+ nodeToRename->populate(d->fileInfoGatherer->getInfo(QFileInfo(parentPath, newName)));
#endif
nodeToRename->isVisible = true;
parentNode->children[newName] = nodeToRename.release();
@@ -937,23 +941,27 @@ QVariant QFileSystemModel::headerData(int section, Qt::Orientation orientation,
QString returnValue;
switch (section) {
- case 0: returnValue = tr("Name");
- break;
- case 1: returnValue = tr("Size");
- break;
- case 2: returnValue =
+ case QFileSystemModelPrivate::NameColumn:
+ returnValue = tr("Name");
+ break;
+ case QFileSystemModelPrivate::SizeColumn:
+ returnValue = tr("Size");
+ break;
+ case QFileSystemModelPrivate::TypeColumn:
+ returnValue =
#ifdef Q_OS_MAC
- tr("Kind", "Match OS X Finder");
+ tr("Kind", "Match OS X Finder");
#else
- tr("Type", "All other platforms");
+ tr("Type", "All other platforms");
#endif
- break;
+ break;
// Windows - Type
// OS X - Kind
// Konqueror - File Type
// Nautilus - Type
- case 3: returnValue = tr("Date Modified");
- break;
+ case QFileSystemModelPrivate::TimeColumn:
+ returnValue = tr("Date Modified");
+ break;
default: return QVariant();
}
return returnValue;
@@ -993,7 +1001,7 @@ Qt::ItemFlags QFileSystemModel::flags(const QModelIndex &index) const
/*!
\internal
*/
-void QFileSystemModelPrivate::_q_performDelayedSort()
+void QFileSystemModelPrivate::performDelayedSort()
{
Q_Q(QFileSystemModel);
q->sort(sortColumn, sortOrder);
@@ -1017,7 +1025,7 @@ public:
const QFileSystemModelPrivate::QFileSystemNode *r) const
{
switch (sortColumn) {
- case 0: {
+ case QFileSystemModelPrivate::NameColumn: {
#ifndef Q_OS_MAC
// place directories before files
bool left = l->isDir();
@@ -1027,7 +1035,7 @@ public:
#endif
return naturalCompare.compare(l->fileName, r->fileName) < 0;
}
- case 1:
+ case QFileSystemModelPrivate::SizeColumn:
{
// Directories go first
bool left = l->isDir();
@@ -1041,7 +1049,7 @@ public:
return sizeDifference < 0;
}
- case 2:
+ case QFileSystemModelPrivate::TypeColumn:
{
int compare = naturalCompare.compare(l->type(), r->type());
if (compare == 0)
@@ -1049,7 +1057,7 @@ public:
return compare < 0;
}
- case 3:
+ case QFileSystemModelPrivate::TimeColumn:
{
const QDateTime left = l->lastModified(QTimeZone::UTC);
const QDateTime right = r->lastModified(QTimeZone::UTC);
@@ -1102,11 +1110,10 @@ void QFileSystemModelPrivate::sortChildren(int column, const QModelIndex &parent
indexNode->visibleChildren.clear();
//No more dirty item we reset our internal dirty index
indexNode->dirtyChildrenIndex = -1;
- const int numValues = values.size();
- indexNode->visibleChildren.reserve(numValues);
- for (int i = 0; i < numValues; ++i) {
- indexNode->visibleChildren.append(values.at(i)->fileName);
- values.at(i)->isVisible = true;
+ indexNode->visibleChildren.reserve(values.size());
+ for (QFileSystemNode *node : std::as_const(values)) {
+ indexNode->visibleChildren.append(node->fileName);
+ node->isVisible = true;
}
if (!disableRecursiveSort) {
@@ -1132,10 +1139,8 @@ void QFileSystemModel::sort(int column, Qt::SortOrder order)
emit layoutAboutToBeChanged();
QModelIndexList oldList = persistentIndexList();
QList<QPair<QFileSystemModelPrivate::QFileSystemNode *, int>> oldNodes;
- const int nodeCount = oldList.size();
- oldNodes.reserve(nodeCount);
- for (int i = 0; i < nodeCount; ++i) {
- const QModelIndex &oldNode = oldList.at(i);
+ oldNodes.reserve(oldList.size());
+ for (const QModelIndex &oldNode : oldList) {
QPair<QFileSystemModelPrivate::QFileSystemNode*, int> pair(d->node(oldNode), oldNode.column());
oldNodes.append(pair);
}
@@ -1149,12 +1154,10 @@ void QFileSystemModel::sort(int column, Qt::SortOrder order)
d->sortOrder = order;
QModelIndexList newList;
- const int numOldNodes = oldNodes.size();
- newList.reserve(numOldNodes);
- for (int i = 0; i < numOldNodes; ++i) {
- const QPair<QFileSystemModelPrivate::QFileSystemNode*, int> &oldNode = oldNodes.at(i);
- newList.append(d->index(oldNode.first, oldNode.second));
- }
+ newList.reserve(oldNodes.size());
+ for (const auto &[node, col]: std::as_const(oldNodes))
+ newList.append(d->index(node, col));
+
changePersistentIndexList(oldList, newList);
emit layoutChanged();
}
@@ -1181,7 +1184,7 @@ QMimeData *QFileSystemModel::mimeData(const QModelIndexList &indexes) const
QList<QUrl> urls;
QList<QModelIndex>::const_iterator it = indexes.begin();
for (; it != indexes.end(); ++it)
- if ((*it).column() == 0)
+ if ((*it).column() == QFileSystemModelPrivate::NameColumn)
urls << QUrl::fromLocalFile(filePath(*it));
QMimeData *data = new QMimeData();
data->setUrls(urls);
@@ -1255,6 +1258,7 @@ QHash<int, QByteArray> QFileSystemModel::roleNames() const
ret.insert(QFileSystemModel::FilePathRole, QByteArrayLiteral("filePath"));
ret.insert(QFileSystemModel::FileNameRole, QByteArrayLiteral("fileName"));
ret.insert(QFileSystemModel::FilePermissions, QByteArrayLiteral("filePermissions"));
+ ret.insert(QFileSystemModel::FileInfoRole, QByteArrayLiteral("fileInfo"));
return ret;
}
@@ -1327,7 +1331,7 @@ void QFileSystemModel::setOptions(Options options)
#if QT_CONFIG(filesystemwatcher)
Q_D(QFileSystemModel);
if (changed.testFlag(DontWatchForChanges))
- d->fileInfoGatherer.setWatching(!options.testFlag(DontWatchForChanges));
+ d->fileInfoGatherer->setWatching(!options.testFlag(DontWatchForChanges));
#endif
if (changed.testFlag(DontUseCustomDirectoryIcons)) {
@@ -1348,7 +1352,7 @@ QFileSystemModel::Options QFileSystemModel::options() const
result.setFlag(DontResolveSymlinks, !resolveSymlinks());
#if QT_CONFIG(filesystemwatcher)
Q_D(const QFileSystemModel);
- result.setFlag(DontWatchForChanges, !d->fileInfoGatherer.isWatching());
+ result.setFlag(DontWatchForChanges, !d->fileInfoGatherer->isWatching());
#else
result.setFlag(DontWatchForChanges);
#endif
@@ -1370,7 +1374,7 @@ QString QFileSystemModel::filePath(const QModelIndex &index) const
QFileSystemModelPrivate::QFileSystemNode *dirNode = d->node(index);
if (dirNode->isSymLink()
#if QT_CONFIG(filesystemwatcher)
- && d->fileInfoGatherer.resolveSymlinks()
+ && d->fileInfoGatherer->resolveSymlinks()
#endif
&& d->resolvedSymLinks.contains(fullPath)
&& dirNode->isDir()) {
@@ -1432,7 +1436,7 @@ QModelIndex QFileSystemModel::mkdir(const QModelIndex &parent, const QString &na
Q_ASSERT(parentNode->children.contains(name));
QFileSystemModelPrivate::QFileSystemNode *node = parentNode->children[name];
#if QT_CONFIG(filesystemwatcher)
- node->populate(d->fileInfoGatherer.getInfo(QFileInfo(dir.absolutePath() + QDir::separator() + name)));
+ node->populate(d->fileInfoGatherer->getInfo(QFileInfo(dir.absolutePath() + QDir::separator() + name)));
#endif
d->addVisibleFiles(parentNode, QStringList(name));
return d->index(node);
@@ -1500,7 +1504,7 @@ QModelIndex QFileSystemModel::setRootPath(const QString &newPath)
if (!rootPath().isEmpty() && rootPath() != "."_L1) {
//This remove the watcher for the old rootPath
#if QT_CONFIG(filesystemwatcher)
- d->fileInfoGatherer.removePath(rootPath());
+ d->fileInfoGatherer->removePath(rootPath());
#endif
//This line "marks" the node as dirty, so the next fetchMore
//call on the path will ask the gatherer to install a watcher again
@@ -1556,7 +1560,7 @@ void QFileSystemModel::setIconProvider(QAbstractFileIconProvider *provider)
{
Q_D(QFileSystemModel);
#if QT_CONFIG(filesystemwatcher)
- d->fileInfoGatherer.setIconProvider(provider);
+ d->fileInfoGatherer->setIconProvider(provider);
#endif
d->root.updateIcon(provider, QString());
}
@@ -1568,9 +1572,9 @@ QAbstractFileIconProvider *QFileSystemModel::iconProvider() const
{
#if QT_CONFIG(filesystemwatcher)
Q_D(const QFileSystemModel);
- return d->fileInfoGatherer.iconProvider();
+ return d->fileInfoGatherer->iconProvider();
#else
- return 0;
+ return nullptr;
#endif
}
@@ -1624,7 +1628,7 @@ void QFileSystemModel::setResolveSymlinks(bool enable)
{
#if QT_CONFIG(filesystemwatcher)
Q_D(QFileSystemModel);
- d->fileInfoGatherer.setResolveSymlinks(enable);
+ d->fileInfoGatherer->setResolveSymlinks(enable);
#else
Q_UNUSED(enable);
#endif
@@ -1634,7 +1638,7 @@ bool QFileSystemModel::resolveSymlinks() const
{
#if QT_CONFIG(filesystemwatcher)
Q_D(const QFileSystemModel);
- return d->fileInfoGatherer.resolveSymlinks();
+ return d->fileInfoGatherer->resolveSymlinks();
#else
return false;
#endif
@@ -1739,7 +1743,7 @@ bool QFileSystemModel::event(QEvent *event)
#if QT_CONFIG(filesystemwatcher)
Q_D(QFileSystemModel);
if (event->type() == QEvent::LanguageChange) {
- d->root.retranslateStrings(d->fileInfoGatherer.iconProvider(), QString());
+ d->root.retranslateStrings(d->fileInfoGatherer->iconProvider(), QString());
return true;
}
#endif
@@ -1753,7 +1757,7 @@ bool QFileSystemModel::rmdir(const QModelIndex &aindex)
#if QT_CONFIG(filesystemwatcher)
if (success) {
QFileSystemModelPrivate * d = const_cast<QFileSystemModelPrivate*>(d_func());
- d->fileInfoGatherer.removePath(path);
+ d->fileInfoGatherer->removePath(path);
}
#endif
return success;
@@ -1765,7 +1769,7 @@ bool QFileSystemModel::rmdir(const QModelIndex &aindex)
Performed quick listing and see if any files have been added or removed,
then fetch more information on visible files.
*/
-void QFileSystemModelPrivate::_q_directoryChanged(const QString &directory, const QStringList &files)
+void QFileSystemModelPrivate::directoryChanged(const QString &directory, const QStringList &files)
{
QFileSystemModelPrivate::QFileSystemNode *parentNode = node(directory, false);
if (parentNode->children.size() == 0)
@@ -1913,8 +1917,8 @@ void QFileSystemModelPrivate::removeVisibleFile(QFileSystemNode *parentNode, int
The thread has received new information about files,
update and emit dataChanged if it has actually changed.
*/
-void QFileSystemModelPrivate::_q_fileSystemChanged(const QString &path,
- const QList<QPair<QString, QFileInfo>> &updates)
+void QFileSystemModelPrivate::fileSystemChanged(const QString &path,
+ const QList<std::pair<QString, QFileInfo>> &updates)
{
#if QT_CONFIG(filesystemwatcher)
Q_Q(QFileSystemModel);
@@ -1925,7 +1929,7 @@ void QFileSystemModelPrivate::_q_fileSystemChanged(const QString &path,
for (const auto &update : updates) {
QString fileName = update.first;
Q_ASSERT(!fileName.isEmpty());
- QExtendedInformation info = fileInfoGatherer.getInfo(update.second);
+ QExtendedInformation info = fileInfoGatherer->getInfo(update.second);
bool previouslyHere = parentNode->children.contains(fileName);
if (!previouslyHere) {
addNode(parentNode, fileName, info.fileInfo());
@@ -1991,9 +1995,16 @@ void QFileSystemModelPrivate::_q_fileSystemChanged(const QString &path,
&& visibleMin < parentNode->visibleChildren.size()
&& parentNode->visibleChildren.at(visibleMin) == min
&& visibleMax >= 0) {
- QModelIndex bottom = q->index(translateVisibleLocation(parentNode, visibleMin), 0, parentIndex);
- QModelIndex top = q->index(translateVisibleLocation(parentNode, visibleMax), 3, parentIndex);
- emit q->dataChanged(bottom, top);
+ // don't use NumColumns here, a subclass might override columnCount
+ const int lastColumn = q->columnCount(parentIndex) - 1;
+ const QModelIndex top = q->index(translateVisibleLocation(parentNode, visibleMin),
+ QFileSystemModelPrivate::NameColumn, parentIndex);
+ const QModelIndex bottom = q->index(translateVisibleLocation(parentNode, visibleMax),
+ lastColumn, parentIndex);
+ // We document that emitting dataChanged with indexes that don't have the
+ // same parent is undefined behavior.
+ Q_ASSERT(bottom.parent() == top.parent());
+ emit q->dataChanged(top, bottom);
}
/*min = QString();
@@ -2017,7 +2028,7 @@ void QFileSystemModelPrivate::_q_fileSystemChanged(const QString &path,
/*!
\internal
*/
-void QFileSystemModelPrivate::_q_resolvedName(const QString &fileName, const QString &resolvedName)
+void QFileSystemModelPrivate::resolvedName(const QString &fileName, const QString &resolvedName)
{
resolvedSymLinks[fileName] = resolvedName;
}
@@ -2049,22 +2060,41 @@ QStringList QFileSystemModelPrivate::unwatchPathsAt(const QModelIndex &index)
return false;
};
- const QStringList &watchedFiles = fileInfoGatherer.watchedFiles();
+ const QStringList &watchedFiles = fileInfoGatherer->watchedFiles();
std::copy_if(watchedFiles.cbegin(), watchedFiles.cend(),
std::back_inserter(result), filter);
- const QStringList &watchedDirectories = fileInfoGatherer.watchedDirectories();
+ const QStringList &watchedDirectories = fileInfoGatherer->watchedDirectories();
std::copy_if(watchedDirectories.cbegin(), watchedDirectories.cend(),
std::back_inserter(result), filter);
- fileInfoGatherer.unwatchPaths(result);
+ fileInfoGatherer->unwatchPaths(result);
return result;
}
#endif // filesystemwatcher && Q_OS_WIN
-QFileSystemModelPrivate::QFileSystemModelPrivate() = default;
+QFileSystemModelPrivate::QFileSystemModelPrivate()
+#if QT_CONFIG(filesystemwatcher)
+ : fileInfoGatherer(new QFileInfoGatherer)
+#endif // filesystemwatcher
+{
+}
-QFileSystemModelPrivate::~QFileSystemModelPrivate() = default;
+QFileSystemModelPrivate::~QFileSystemModelPrivate()
+{
+#if QT_CONFIG(filesystemwatcher)
+ fileInfoGatherer->requestAbort();
+ if (!fileInfoGatherer->wait(1000)) {
+ // If the thread hangs, perhaps because the network was disconnected
+ // while the gatherer was stat'ing a remote file, then don't block
+ // shutting down the model (which might block a file dialog and the
+ // main thread). Schedule the gatherer for later deletion; it's
+ // destructor will wait for the thread to finish.
+ auto *rawGatherer = fileInfoGatherer.release();
+ rawGatherer->deleteLater();
+ }
+#endif // filesystemwatcher
+}
/*!
\internal
@@ -2075,18 +2105,20 @@ void QFileSystemModelPrivate::init()
delayedSortTimer.setSingleShot(true);
- qRegisterMetaType<QList<QPair<QString, QFileInfo>>>();
+ qRegisterMetaType<QList<std::pair<QString, QFileInfo>>>();
#if QT_CONFIG(filesystemwatcher)
- q->connect(&fileInfoGatherer, SIGNAL(newListOfFiles(QString,QStringList)),
- q, SLOT(_q_directoryChanged(QString,QStringList)));
- q->connect(&fileInfoGatherer, SIGNAL(updates(QString, QList<QPair<QString, QFileInfo>>)), q,
- SLOT(_q_fileSystemChanged(QString, QList<QPair<QString, QFileInfo>>)));
- q->connect(&fileInfoGatherer, SIGNAL(nameResolved(QString,QString)),
- q, SLOT(_q_resolvedName(QString,QString)));
- q->connect(&fileInfoGatherer, SIGNAL(directoryLoaded(QString)),
- q, SIGNAL(directoryLoaded(QString)));
+ QObjectPrivate::connect(fileInfoGatherer.get(), &QFileInfoGatherer::newListOfFiles,
+ this, &QFileSystemModelPrivate::directoryChanged);
+ QObjectPrivate::connect(fileInfoGatherer.get(), &QFileInfoGatherer::updates,
+ this, &QFileSystemModelPrivate::fileSystemChanged);
+ QObjectPrivate::connect(fileInfoGatherer.get(), &QFileInfoGatherer::nameResolved,
+ this, &QFileSystemModelPrivate::resolvedName);
+ q->connect(fileInfoGatherer.get(), &QFileInfoGatherer::directoryLoaded,
+ q, &QFileSystemModel::directoryLoaded);
#endif // filesystemwatcher
- q->connect(&delayedSortTimer, SIGNAL(timeout()), q, SLOT(_q_performDelayedSort()), Qt::QueuedConnection);
+ QObjectPrivate::connect(&delayedSortTimer, &QTimer::timeout,
+ this, &QFileSystemModelPrivate::performDelayedSort,
+ Qt::QueuedConnection);
}
/*!
@@ -2099,8 +2131,14 @@ void QFileSystemModelPrivate::init()
*/
bool QFileSystemModelPrivate::filtersAcceptsNode(const QFileSystemNode *node) const
{
+ // When the model is set to only show files, then a node representing a dir
+ // should be hidden regardless of bypassFilters.
+ // QTBUG-74471
+ const bool hideDirs = (filters & (QDir::Dirs | QDir::AllDirs)) == 0;
+ const bool shouldHideDirNode = hideDirs && node->isDir();
+
// always accept drives
- if (node->parent == &root || bypassFilters.contains(node))
+ if (node->parent == &root || (!shouldHideDirNode && bypassFilters.contains(node)))
return true;
// If we don't know anything yet don't accept it
@@ -2109,7 +2147,6 @@ bool QFileSystemModelPrivate::filtersAcceptsNode(const QFileSystemNode *node) co
const bool filterPermissions = ((filters & QDir::PermissionMask)
&& (filters & QDir::PermissionMask) != QDir::PermissionMask);
- const bool hideDirs = !(filters & (QDir::Dirs | QDir::AllDirs));
const bool hideFiles = !(filters & QDir::Files);
const bool hideReadable = !(!filterPermissions || (filters & QDir::Readable));
const bool hideWritable = !(!filterPermissions || (filters & QDir::Writable));
diff --git a/src/gui/itemmodels/qfilesystemmodel.h b/src/gui/itemmodels/qfilesystemmodel.h
index d614ec2329..1fd1041f15 100644
--- a/src/gui/itemmodels/qfilesystemmodel.h
+++ b/src/gui/itemmodels/qfilesystemmodel.h
@@ -9,7 +9,6 @@
#include <QtCore/qpair.h>
#include <QtCore/qdir.h>
#include <QtGui/qicon.h>
-#include <QtCore/qdiriterator.h>
QT_REQUIRE_CONFIG(filesystemmodel);
@@ -33,11 +32,13 @@ Q_SIGNALS:
void directoryLoaded(const QString &path);
public:
+ // ### Qt 7: renumber these values to be before Qt::UserRole comment.
enum Roles {
FileIconRole = Qt::DecorationRole,
+ FileInfoRole = Qt::UserRole - 1,
FilePathRole = Qt::UserRole + 1,
FileNameRole = Qt::UserRole + 2,
- FilePermissions = Qt::UserRole + 3
+ FilePermissions = Qt::UserRole + 3,
};
enum Option
@@ -114,7 +115,6 @@ public:
qint64 size(const QModelIndex &index) const;
QString type(const QModelIndex &index) const;
- // ### Qt7 merge the two overloads, with tz QTimeZone::LocalTime
QDateTime lastModified(const QModelIndex &index) const;
QDateTime lastModified(const QModelIndex &index, const QTimeZone &tz) const;
@@ -135,13 +135,6 @@ private:
Q_DECLARE_PRIVATE(QFileSystemModel)
Q_DISABLE_COPY(QFileSystemModel)
- Q_PRIVATE_SLOT(d_func(), void _q_directoryChanged(const QString &directory, const QStringList &list))
- Q_PRIVATE_SLOT(d_func(), void _q_performDelayedSort())
- Q_PRIVATE_SLOT(d_func(),
- void _q_fileSystemChanged(const QString &path,
- const QList<QPair<QString, QFileInfo>> &))
- Q_PRIVATE_SLOT(d_func(), void _q_resolvedName(const QString &fileName, const QString &resolvedName))
-
friend class QFileDialogPrivate;
};
diff --git a/src/gui/itemmodels/qfilesystemmodel_p.h b/src/gui/itemmodels/qfilesystemmodel_p.h
index f30b4801bc..e01b0d56e6 100644
--- a/src/gui/itemmodels/qfilesystemmodel_p.h
+++ b/src/gui/itemmodels/qfilesystemmodel_p.h
@@ -63,7 +63,13 @@ class Q_GUI_EXPORT QFileSystemModelPrivate : public QAbstractItemModelPrivate
Q_DECLARE_PUBLIC(QFileSystemModel)
public:
- enum { NumColumns = 4 };
+ enum {
+ NameColumn,
+ SizeColumn,
+ TypeColumn,
+ TimeColumn,
+ NumColumns = 4
+ };
class QFileSystemNode
{
@@ -144,8 +150,12 @@ public:
return visibleChildren.indexOf(childName);
}
void updateIcon(QAbstractFileIconProvider *iconProvider, const QString &path) {
+ if (!iconProvider)
+ return;
+
if (info)
info->icon = iconProvider->icon(QFileInfo(path));
+
for (QFileSystemNode *child : std::as_const(children)) {
//On windows the root (My computer) has no path so we don't want to add a / for nothing (e.g. /C:/)
if (!path.isEmpty()) {
@@ -159,6 +169,9 @@ public:
}
void retranslateStrings(QAbstractFileIconProvider *iconProvider, const QString &path) {
+ if (!iconProvider)
+ return;
+
if (info)
info->displayType = iconProvider->type(QFileInfo(path));
for (QFileSystemNode *child : std::as_const(children)) {
@@ -244,18 +257,18 @@ public:
QString type(const QModelIndex &index) const;
QString time(const QModelIndex &index) const;
- void _q_directoryChanged(const QString &directory, const QStringList &list);
- void _q_performDelayedSort();
- void _q_fileSystemChanged(const QString &path, const QList<QPair<QString, QFileInfo>> &);
- void _q_resolvedName(const QString &fileName, const QString &resolvedName);
+ void directoryChanged(const QString &directory, const QStringList &list);
+ void performDelayedSort();
+ void fileSystemChanged(const QString &path, const QList<std::pair<QString, QFileInfo>> &);
+ void resolvedName(const QString &fileName, const QString &resolvedName);
QDir rootDir;
#if QT_CONFIG(filesystemwatcher)
# ifdef Q_OS_WIN
QStringList unwatchPathsAt(const QModelIndex &);
- void watchPaths(const QStringList &paths) { fileInfoGatherer.watchPaths(paths); }
+ void watchPaths(const QStringList &paths) { fileInfoGatherer->watchPaths(paths); }
# endif // Q_OS_WIN
- QFileInfoGatherer fileInfoGatherer;
+ std::unique_ptr<QFileInfoGatherer> fileInfoGatherer;
#endif // filesystemwatcher
QTimer delayedSortTimer;
QHash<const QFileSystemNode*, bool> bypassFilters;
diff --git a/src/gui/itemmodels/qstandarditemmodel.cpp b/src/gui/itemmodels/qstandarditemmodel.cpp
index 64ffdaa3b7..8b3e381431 100644
--- a/src/gui/itemmodels/qstandarditemmodel.cpp
+++ b/src/gui/itemmodels/qstandarditemmodel.cpp
@@ -19,6 +19,11 @@
QT_BEGIN_NAMESPACE
+// Used internally to store the flags
+namespace {
+constexpr auto DataFlagsRole = Qt::ItemDataRole(Qt::UserRole - 1);
+}
+
static inline QString qStandardItemModelDataListMimeType()
{
return QStringLiteral("application/x-qstandarditemmodeldatalist");
@@ -279,8 +284,7 @@ QMap<int, QVariant> QStandardItemPrivate::itemData() const
{
QMap<int, QVariant> result;
for (const auto &data : values) {
- // Qt::UserRole - 1 is used internally to store the flags
- if (data.role != Qt::UserRole - 1)
+ if (data.role != DataFlagsRole)
result.insert(data.role, data.value);
}
return result;
@@ -868,9 +872,15 @@ QStandardItem *QStandardItem::parent() const
Sets the item's data for the given \a role to the specified \a value.
If you subclass QStandardItem and reimplement this function, your
- reimplementation should call emitDataChanged() if you do not call
- the base implementation of setData(). This will ensure that e.g.
- views using the model are notified of the changes.
+ reimplementation should:
+ \list
+ \li call emitDataChanged() if you do not call the base implementation of
+ setData(). This will ensure that e.g. views using the model are notified
+ of the changes
+ \li call the base implementation for roles you don't handle, otherwise
+ setting flags, e.g. by calling setFlags(), setCheckable(), setEditable()
+ etc., will not work.
+ \endlist
\note The default implementation treats Qt::EditRole and Qt::DisplayRole
as referring to the same data.
@@ -924,6 +934,11 @@ void QStandardItem::clearData()
Returns the item's data for the given \a role, or an invalid
QVariant if there is no data for the role.
+ If you reimplement this function, your reimplementation should call
+ the base implementation for roles you don't handle, otherwise getting
+ flags, e.g. by calling flags(), isCheckable(), isEditable() etc.,
+ will not work.
+
\note The default implementation treats Qt::EditRole and Qt::DisplayRole
as referring to the same data.
*/
@@ -983,7 +998,7 @@ void QStandardItem::emitDataChanged()
*/
void QStandardItem::setFlags(Qt::ItemFlags flags)
{
- setData((int)flags, Qt::UserRole - 1);
+ setData((int)flags, DataFlagsRole);
}
/*!
@@ -998,7 +1013,7 @@ void QStandardItem::setFlags(Qt::ItemFlags flags)
*/
Qt::ItemFlags QStandardItem::flags() const
{
- QVariant v = data(Qt::UserRole - 1);
+ QVariant v = data(DataFlagsRole);
if (!v.isValid())
return (Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable
|Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled);
@@ -1858,28 +1873,30 @@ QStandardItem *QStandardItem::takeChild(int row, int column)
if (index != -1) {
QModelIndex changedIdx;
item = d->children.at(index);
- if (item && d->model) {
+ if (item) {
QStandardItemPrivate *const item_d = item->d_func();
- const int savedRows = item_d->rows;
- const int savedCols = item_d->columns;
- const QVector<QStandardItem*> savedChildren = item_d->children;
- if (savedRows > 0) {
- d->model->d_func()->rowsAboutToBeRemoved(item, 0, savedRows - 1);
- item_d->rows = 0;
- item_d->children = QVector<QStandardItem*>(); //slightly faster than clear
- d->model->d_func()->rowsRemoved(item, 0, savedRows);
- }
- if (savedCols > 0) {
- d->model->d_func()->columnsAboutToBeRemoved(item, 0, savedCols - 1);
- item_d->columns = 0;
- if (!item_d->children.isEmpty())
+ if (d->model) {
+ QStandardItemModelPrivate *const model_d = d->model->d_func();
+ const int savedRows = item_d->rows;
+ const int savedCols = item_d->columns;
+ const QVector<QStandardItem*> savedChildren = item_d->children;
+ if (savedRows > 0) {
+ model_d->rowsAboutToBeRemoved(item, 0, savedRows - 1);
+ item_d->rows = 0;
+ item_d->children = QVector<QStandardItem*>(); //slightly faster than clear
+ model_d->rowsRemoved(item, 0, savedRows);
+ }
+ if (savedCols > 0) {
+ model_d->columnsAboutToBeRemoved(item, 0, savedCols - 1);
+ item_d->columns = 0;
item_d->children = QVector<QStandardItem*>(); //slightly faster than clear
- d->model->d_func()->columnsRemoved(item, 0, savedCols);
+ model_d->columnsRemoved(item, 0, savedCols);
+ }
+ item_d->rows = savedRows;
+ item_d->columns = savedCols;
+ item_d->children = savedChildren;
+ changedIdx = d->model->indexFromItem(item);
}
- item_d->rows = savedRows;
- item_d->columns = savedCols;
- item_d->children = savedChildren;
- changedIdx = d->model->indexFromItem(item);
item_d->setParentAndModel(nullptr, nullptr);
}
d->children.replace(index, nullptr);
@@ -3099,13 +3116,13 @@ QStringList QStandardItemModel::mimeTypes() const
*/
QMimeData *QStandardItemModel::mimeData(const QModelIndexList &indexes) const
{
- QMimeData *data = QAbstractItemModel::mimeData(indexes);
+ std::unique_ptr<QMimeData> data(QAbstractItemModel::mimeData(indexes));
if (!data)
return nullptr;
const QString format = qStandardItemModelDataListMimeType();
if (!mimeTypes().contains(format))
- return data;
+ return data.release();
QByteArray encoded;
QDataStream stream(&encoded, QIODevice::WriteOnly);
@@ -3157,7 +3174,7 @@ QMimeData *QStandardItemModel::mimeData(const QModelIndexList &indexes) const
}
data->setData(format, encoded);
- return data;
+ return data.release();
}
diff --git a/src/gui/itemmodels/qstandarditemmodel_p.h b/src/gui/itemmodels/qstandarditemmodel_p.h
index def6c20727..a0c3f8a161 100644
--- a/src/gui/itemmodels/qstandarditemmodel_p.h
+++ b/src/gui/itemmodels/qstandarditemmodel_p.h
@@ -15,6 +15,8 @@
// We mean it.
//
+#include <QtGui/qstandarditemmodel.h>
+
#include <QtGui/private/qtguiglobal_p.h>
#include "private/qabstractitemmodel_p.h"
@@ -32,8 +34,10 @@ class QStandardItemData
{
public:
inline QStandardItemData() : role(-1) {}
- inline QStandardItemData(int r, const QVariant &v) : role(r), value(v) {}
- inline QStandardItemData(const std::pair<const int&, const QVariant&> &p) : role(p.first), value(p.second) {}
+ inline QStandardItemData(int r, const QVariant &v) :
+ role(r == Qt::EditRole ? Qt::DisplayRole : r), value(v) {}
+ inline QStandardItemData(const std::pair<const int&, const QVariant&> &p) :
+ role(p.first == Qt::EditRole ? Qt::DisplayRole : p.first), value(p.second) {}
int role;
QVariant value;
inline bool operator==(const QStandardItemData &other) const { return role == other.role && value == other.value; }
diff --git a/src/gui/kernel/qaction.cpp b/src/gui/kernel/qaction.cpp
index 0f389789a1..c67cfd53b1 100644
--- a/src/gui/kernel/qaction.cpp
+++ b/src/gui/kernel/qaction.cpp
@@ -171,9 +171,7 @@ QObject *QActionPrivate::menu() const
Once a QAction has been created, it should be added to the relevant
menu and toolbar, then connected to the slot which will perform
- the action. For example:
-
- \snippet ../widgets/mainwindows/application/mainwindow.cpp 19
+ the action.
Actions are added to widgets using QWidget::addAction() or
QGraphicsWidget::addAction(). Note that an action must be added to a
@@ -186,7 +184,7 @@ QObject *QActionPrivate::menu() const
use as menu items.
- \sa QMenu, QToolBar, {Qt Widgets - Application Example}
+ \sa QMenu, QToolBar
*/
/*!
diff --git a/src/gui/kernel/qaction_p.h b/src/gui/kernel/qaction_p.h
index 8aa75fdf89..e79cc26b4d 100644
--- a/src/gui/kernel/qaction_p.h
+++ b/src/gui/kernel/qaction_p.h
@@ -21,6 +21,8 @@
#if QT_CONFIG(shortcut)
# include <QtGui/private/qshortcutmap_p.h>
#endif
+
+#include <QtCore/qpointer.h>
#include "private/qobject_p.h"
QT_REQUIRE_CONFIG(action);
diff --git a/src/gui/kernel/qactiongroup_p.h b/src/gui/kernel/qactiongroup_p.h
index c7a058a6f2..ba939a2b10 100644
--- a/src/gui/kernel/qactiongroup_p.h
+++ b/src/gui/kernel/qactiongroup_p.h
@@ -21,6 +21,8 @@
#if QT_CONFIG(shortcut)
# include <QtGui/private/qshortcutmap_p.h>
#endif
+
+#include <QtCore/qpointer.h>
#include "private/qobject_p.h"
QT_REQUIRE_CONFIG(action);
diff --git a/src/gui/kernel/qcursor.cpp b/src/gui/kernel/qcursor.cpp
index 3f0cabbcb1..8e7747559a 100644
--- a/src/gui/kernel/qcursor.cpp
+++ b/src/gui/kernel/qcursor.cpp
@@ -439,8 +439,7 @@ QCursor::QCursor()
QCursor::QCursor(Qt::CursorShape shape)
: d(nullptr)
{
- if (!QCursorData::initialized)
- QCursorData::initialize();
+ QCursorData::initialize();
setShape(shape);
}
@@ -498,8 +497,7 @@ bool operator==(const QCursor &lhs, const QCursor &rhs) noexcept
*/
Qt::CursorShape QCursor::shape() const
{
- if (!QCursorData::initialized)
- QCursorData::initialize();
+ QCursorData::initialize();
return d->cshape;
}
@@ -512,8 +510,7 @@ Qt::CursorShape QCursor::shape() const
*/
void QCursor::setShape(Qt::CursorShape shape)
{
- if (!QCursorData::initialized)
- QCursorData::initialize();
+ QCursorData::initialize();
QCursorData *c = uint(shape) <= Qt::LastCursor ? qt_cursorTable[shape] : nullptr;
if (!c)
c = qt_cursorTable[0];
@@ -547,8 +544,7 @@ void QCursor::setShape(Qt::CursorShape shape)
*/
QBitmap QCursor::bitmap() const
{
- if (!QCursorData::initialized)
- QCursorData::initialize();
+ QCursorData::initialize();
if (d->bm)
return *(d->bm);
return QBitmap();
@@ -574,8 +570,7 @@ QBitmap QCursor::bitmap() const
*/
QBitmap QCursor::mask() const
{
- if (!QCursorData::initialized)
- QCursorData::initialize();
+ QCursorData::initialize();
if (d->bmm)
return *(d->bmm);
return QBitmap();
@@ -588,8 +583,7 @@ QBitmap QCursor::mask() const
QPixmap QCursor::pixmap() const
{
- if (!QCursorData::initialized)
- QCursorData::initialize();
+ QCursorData::initialize();
return d->pixmap;
}
@@ -600,8 +594,7 @@ QPixmap QCursor::pixmap() const
QPoint QCursor::hotSpot() const
{
- if (!QCursorData::initialized)
- QCursorData::initialize();
+ QCursorData::initialize();
return QPoint(d->hx, d->hy);
}
@@ -611,8 +604,7 @@ QPoint QCursor::hotSpot() const
QCursor::QCursor(const QCursor &c)
{
- if (!QCursorData::initialized)
- QCursorData::initialize();
+ QCursorData::initialize();
d = c.d;
d->ref.ref();
}
@@ -635,8 +627,7 @@ QCursor::~QCursor()
QCursor &QCursor::operator=(const QCursor &c)
{
- if (!QCursorData::initialized)
- QCursorData::initialize();
+ QCursorData::initialize();
if (c.d)
c.d->ref.ref();
if (d && !d->ref.deref())
@@ -707,8 +698,7 @@ void QCursorData::initialize()
QCursorData *QCursorData::setBitmap(const QBitmap &bitmap, const QBitmap &mask, int hotX, int hotY, qreal devicePixelRatio)
{
- if (!QCursorData::initialized)
- QCursorData::initialize();
+ QCursorData::initialize();
if (bitmap.depth() != 1 || mask.depth() != 1 || bitmap.size() != mask.size()) {
qWarning("QCursor: Cannot create bitmap cursor; invalid bitmap(s)");
QCursorData *c = qt_cursorTable[0];
diff --git a/src/gui/kernel/qdnd_p.h b/src/gui/kernel/qdnd_p.h
index c863a63620..b5a2e015f4 100644
--- a/src/gui/kernel/qdnd_p.h
+++ b/src/gui/kernel/qdnd_p.h
@@ -27,6 +27,8 @@
#include "private/qobject_p.h"
#include "QtGui/qbackingstore.h"
+#include <QtCore/qpointer.h>
+
QT_REQUIRE_CONFIG(draganddrop);
QT_BEGIN_NAMESPACE
diff --git a/src/gui/kernel/qdrag.cpp b/src/gui/kernel/qdrag.cpp
index 10bf7f33f0..4e707e4915 100644
--- a/src/gui/kernel/qdrag.cpp
+++ b/src/gui/kernel/qdrag.cpp
@@ -9,6 +9,8 @@
#include <qpoint.h>
#include "qdnd_p.h"
+#include <QtCore/qpointer.h>
+
QT_BEGIN_NAMESPACE
/*!
@@ -64,7 +66,7 @@ QT_BEGIN_NAMESPACE
required.
\sa {Drag and Drop}, QClipboard, QMimeData, {Draggable Icons Example},
- {Draggable Text Example}, {Drop Site Example}, {Fridge Magnets Example}
+ {Draggable Text Example}, {Drop Site Example}
*/
/*!
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index 8040a3647b..d8c11d72a6 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qevent.h"
+
#include "qcursor.h"
#include "private/qguiapplication_p.h"
#include "private/qinputdevice_p.h"
@@ -9,6 +10,7 @@
#include "qpa/qplatformintegration.h"
#include "private/qevent_p.h"
#include "private/qeventpoint_p.h"
+
#include "qfile.h"
#include "qhashfunctions.h"
#include "qmetaobject.h"
@@ -16,6 +18,7 @@
#include "qevent_p.h"
#include "qmath.h"
#include "qloggingcategory.h"
+#include "qpointer.h"
#if QT_CONFIG(draganddrop)
#include <qpa/qplatformdrag.h>
@@ -1837,10 +1840,6 @@ Q_IMPL_EVENT_COMMON(QResizeEvent)
special handling, you should reimplement the event handler and
ignore() the event.
- The \l{mainwindows/application#close event handler}{closeEvent() in the
- Application example} shows a close event handler that
- asks whether to save a document before closing.
-
If you want the widget to be deleted when it is closed, create it
with the Qt::WA_DeleteOnClose flag. This is very useful for
independent top-level windows in a multi-window application.
@@ -3772,6 +3771,13 @@ static void formatUnicodeString(QDebug d, const QString &s)
d << Qt::dec << '"';
}
+static QDebug operator<<(QDebug dbg, const QInputMethodEvent::Attribute &attr)
+{
+ dbg << "[type= " << attr.type << ", start=" << attr.start << ", length=" << attr.length
+ << ", value=" << attr.value << ']';
+ return dbg;
+}
+
static inline void formatInputMethodEvent(QDebug d, const QInputMethodEvent *e)
{
d << "QInputMethodEvent(";
@@ -3787,15 +3793,15 @@ static inline void formatInputMethodEvent(QDebug d, const QInputMethodEvent *e)
d << ", replacementStart=" << e->replacementStart() << ", replacementLength="
<< e->replacementLength();
}
- if (const int attributeCount = e->attributes().size()) {
+ const auto attributes = e->attributes();
+ auto it = attributes.cbegin();
+ const auto end = attributes.cend();
+ if (it != end) {
d << ", attributes= {";
- for (int a = 0; a < attributeCount; ++a) {
- const QInputMethodEvent::Attribute &at = e->attributes().at(a);
- if (a)
- d << ',';
- d << "[type= " << at.type << ", start=" << at.start << ", length=" << at.length
- << ", value=" << at.value << ']';
- }
+ d << *it;
+ ++it;
+ for (; it != end; ++it)
+ d << ',' << *it;
d << '}';
}
d << ')';
@@ -4122,6 +4128,10 @@ QDebug operator<<(QDebug dbg, const QEvent *e)
dbg << ", text=" << ke->text();
if (ke->isAutoRepeat())
dbg << ", autorepeat, count=" << ke->count();
+ if (dbg.verbosity() > QDebug::DefaultVerbosity) {
+ dbg << ", nativeScanCode=" << ke->nativeScanCode();
+ dbg << ", nativeVirtualKey=" << ke->nativeVirtualKey();
+ }
dbg << ')';
}
break;
@@ -4468,8 +4478,6 @@ Q_IMPL_EVENT_COMMON(QWindowStateChangeEvent)
*/
/*!
- \deprecated [6.2] Use another constructor.
-
Constructs a QTouchEvent with the given \a eventType, \a device,
\a touchPoints, and current keyboard \a modifiers at the time of the event.
*/
@@ -4749,6 +4757,46 @@ Q_IMPL_EVENT_COMMON(QApplicationStateChangeEvent)
Returns the state of the application.
*/
+/*!
+ \class QChildWindowEvent
+ \inmodule QtGui
+ \since 6.7
+ \brief The QChildWindowEvent class contains event parameters for
+ child window changes.
+
+ \ingroup events
+
+ Child window events are sent to windows when children are
+ added or removed.
+
+ In both cases you can only rely on the child being a QWindow
+ — not any subclass thereof. This is because in the
+ QEvent::ChildWindowAdded case the subclass is not yet fully
+ constructed, and in the QEvent::ChildWindowRemoved case it
+ might have already been destructed.
+*/
+
+/*!
+ Constructs a child window event object of a particular \a type
+ for the \a childWindow.
+
+ \a type can be QEvent::ChildWindowAdded or QEvent::ChildWindowRemoved.
+
+ \sa child()
+*/
+QChildWindowEvent::QChildWindowEvent(Type type, QWindow *childWindow)
+ : QEvent(type), c(childWindow)
+{
+}
+
+Q_IMPL_EVENT_COMMON(QChildWindowEvent)
+
+/*!
+ \fn QWindow *QChildWindowEvent::child() const
+
+ Returns the child window that was added or removed.
+*/
+
QMutableTouchEvent::~QMutableTouchEvent()
= default;
diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h
index 900524d218..a24f0c471c 100644
--- a/src/gui/kernel/qevent.h
+++ b/src/gui/kernel/qevent.h
@@ -14,7 +14,6 @@
#include <QtCore/qiodevice.h>
#include <QtCore/qlist.h>
#include <QtCore/qnamespace.h>
-#include <QtCore/qpointer.h>
#include <QtCore/qstring.h>
#include <QtCore/qurl.h>
#include <QtCore/qvariant.h>
@@ -34,6 +33,7 @@ QT_BEGIN_NAMESPACE
class QFile;
class QAction;
class QMouseEvent;
+template <typename T> class QPointer;
class QPointerEvent;
class QScreen;
#if QT_CONFIG(shortcut)
@@ -71,6 +71,7 @@ protected:
class Q_GUI_EXPORT QPointerEvent : public QInputEvent
{
+ Q_GADGET
Q_DECL_EVENT_COMMON(QPointerEvent)
public:
explicit QPointerEvent(Type type, const QPointingDevice *dev,
@@ -1020,6 +1021,17 @@ private:
Qt::ApplicationState m_applicationState;
};
+class Q_GUI_EXPORT QChildWindowEvent : public QEvent
+{
+ Q_DECL_EVENT_COMMON(QChildWindowEvent)
+public:
+ explicit QChildWindowEvent(Type type, QWindow *childWindow);
+ QWindow *child() const { return c; }
+
+private:
+ QWindow *c;
+};
+
QT_END_NAMESPACE
#endif // QEVENT_H
diff --git a/src/gui/kernel/qeventpoint.cpp b/src/gui/kernel/qeventpoint.cpp
index bbb0baee79..66d4f44ea0 100644
--- a/src/gui/kernel/qeventpoint.cpp
+++ b/src/gui/kernel/qeventpoint.cpp
@@ -536,6 +536,7 @@ void QMutableEventPoint::update(const QEventPoint &other, QEventPoint &target)
setEllipseDiameters(target, other.ellipseDiameters());
setRotation(target, other.rotation());
setVelocity(target, other.velocity());
+ setUniqueId(target, other.uniqueId()); // for TUIO
}
/*! \internal
diff --git a/src/gui/kernel/qeventpoint.h b/src/gui/kernel/qeventpoint.h
index 35b8b1f73d..518faecee2 100644
--- a/src/gui/kernel/qeventpoint.h
+++ b/src/gui/kernel/qeventpoint.h
@@ -20,7 +20,6 @@ class Q_GUI_EXPORT QEventPoint
{
Q_GADGET
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
- QDOC_PROPERTY(QPointingDevice *device READ device CONSTANT) // qdoc doesn't know const
Q_PROPERTY(const QPointingDevice *device READ device CONSTANT)
Q_PROPERTY(int id READ id CONSTANT)
Q_PROPERTY(QPointingDeviceUniqueId uniqueId READ uniqueId CONSTANT)
diff --git a/src/gui/kernel/qeventpoint_p.h b/src/gui/kernel/qeventpoint_p.h
index f70c285e3e..c339c7e3e1 100644
--- a/src/gui/kernel/qeventpoint_p.h
+++ b/src/gui/kernel/qeventpoint_p.h
@@ -17,7 +17,9 @@
#include <QtGui/private/qtguiglobal_p.h>
#include <QtGui/qevent.h>
+
#include <QtCore/qloggingcategory.h>
+#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 589a054c19..c97374e975 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -9,6 +9,7 @@
#include <qpa/qplatformintegrationfactory_p.h>
#include "private/qevent_p.h"
#include "private/qeventpoint_p.h"
+#include "private/qiconloader_p.h"
#include "qfont.h"
#include "qpointingdevice.h"
#include <qpa/qplatformfontdatabase.h>
@@ -16,12 +17,15 @@
#include <qpa/qplatformnativeinterface.h>
#include <qpa/qplatformtheme.h>
#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformkeymapper.h>
#include <QtCore/QAbstractEventDispatcher>
+#include <QtCore/QFileInfo>
#include <QtCore/QStandardPaths>
#include <QtCore/QVariant>
#include <QtCore/private/qcoreapplication_p.h>
#include <QtCore/private/qabstracteventdispatcher_p.h>
+#include <QtCore/private/qminimalflatset_p.h>
#include <QtCore/qmutex.h>
#include <QtCore/private/qthread_p.h>
#include <QtCore/private/qlocking_p.h>
@@ -50,6 +54,7 @@
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qwindowsysteminterface_p.h>
#include "private/qwindow_p.h"
+#include "private/qicon_p.h"
#include "private/qcursor_p.h"
#if QT_CONFIG(opengl)
# include "private/qopenglcontext_p.h"
@@ -231,7 +236,7 @@ static void initThemeHints()
static bool checkNeedPortalSupport()
{
#if QT_CONFIG(dbus)
- return !QStandardPaths::locate(QStandardPaths::RuntimeLocation, "flatpak-info"_L1).isEmpty() || qEnvironmentVariableIsSet("SNAP");
+ return QFileInfo::exists("/.flatpak-info"_L1) || qEnvironmentVariableIsSet("SNAP");
#else
return false;
#endif // QT_CONFIG(dbus)
@@ -258,7 +263,7 @@ struct QWindowGeometrySpecification
static inline int nextGeometryToken(const QByteArray &a, int &pos, char *op)
{
*op = 0;
- const int size = a.size();
+ const qsizetype size = a.size();
if (pos >= size)
return -1;
@@ -559,10 +564,12 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME
\list
\li \c {altgr}, detect the key \c {AltGr} found on some keyboards as
Qt::GroupSwitchModifier (since Qt 5.12).
- \li \c {darkmode=[1|2]} controls how Qt responds to the activation
+ \li \c {darkmode=[0|1|2]} controls how Qt responds to the activation
of the \e{Dark Mode for applications} introduced in Windows 10
1903 (since Qt 5.15).
+ A value of 0 disables dark mode support.
+
A value of 1 causes Qt to switch the window borders to black
when \e{Dark Mode for applications} is activated and no High
Contrast Theme is in use. This is intended for applications
@@ -581,13 +588,10 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME
\c none disables them.
\li \c {fontengine=freetype}, uses the FreeType font engine.
- \li \c {fontengine=directwrite}, uses the experimental DirectWrite
- font database and defaults to using the DirectWrite font
+ \li \c {fontengine=gdi}, uses the legacy GDI-based
+ font database and defaults to using the GDI font
engine (which is otherwise only used for some font types
- or font properties.) This affects font selection and aims
- to provide font naming more consistent with other platforms,
- but does not support all font formats, such as Postscript
- Type-1 or Microsoft FNT fonts.
+ or font properties.) (Since Qt 6.8).
\li \c {menus=[native|none]}, controls the use of native menus.
Native menus are implemented using Win32 API and are simpler than
@@ -601,7 +605,8 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME
\li \c {nocolorfonts} Turn off DirectWrite Color fonts
(since Qt 5.8).
- \li \c {nodirectwrite} Turn off DirectWrite fonts (since Qt 5.8).
+ \li \c {nodirectwrite} Turn off DirectWrite fonts (since Qt 5.8). This implicitly
+ also selects the GDI font engine.
\li \c {nomousefromtouch} Ignores mouse events synthesized
from touch events by the operating system.
@@ -751,7 +756,8 @@ QString QGuiApplication::applicationDisplayName()
of unread messages or similar.
The badge will be overlaid on the application's icon in the Dock
- on \macos, the home screen icon on iOS, or the task bar on Windows.
+ on \macos, the home screen icon on iOS, or the task bar on Windows
+ and Linux.
If the number is outside the range supported by the platform, the
number will be clamped to the supported range. If the number does
@@ -772,9 +778,9 @@ void QGuiApplication::setBadgeNumber(qint64 number)
\brief the base name of the desktop entry for this application
\since 5.7
- This is the file name, without the full path, of the desktop entry
- that represents this application according to the freedesktop desktop
- entry specification.
+ This is the file name, without the full path or the trailing ".desktop"
+ extension of the desktop entry that represents this application
+ according to the freedesktop desktop entry specification.
This property gives a precise indication of what desktop entry represents
the application and it is needed by the windowing system to retrieve
@@ -788,6 +794,15 @@ void QGuiApplication::setDesktopFileName(const QString &name)
if (!QGuiApplicationPrivate::desktopFileName)
QGuiApplicationPrivate::desktopFileName = new QString;
*QGuiApplicationPrivate::desktopFileName = name;
+ if (name.endsWith(QLatin1String(".desktop"))) { // ### Qt 7: remove
+ const QString filePath = QStandardPaths::locate(QStandardPaths::ApplicationsLocation, name);
+ if (!filePath.isEmpty()) {
+ qWarning("QGuiApplication::setDesktopFileName: the specified desktop file name "
+ "ends with .desktop. For compatibility reasons, the .desktop suffix will "
+ "be removed. Please specify a desktop file name without .desktop suffix");
+ (*QGuiApplicationPrivate::desktopFileName).chop(8);
+ }
+ }
}
QString QGuiApplication::desktopFileName()
@@ -814,7 +829,7 @@ QWindow *QGuiApplication::modalWindow()
CHECK_QAPP_INSTANCE(nullptr)
if (QGuiApplicationPrivate::self->modalWindowList.isEmpty())
return nullptr;
- return QGuiApplicationPrivate::self->modalWindowList.first();
+ return QGuiApplicationPrivate::self->modalWindowList.constFirst();
}
static void updateBlockedStatusRecursion(QWindow *window, bool shouldBeBlocked)
@@ -948,6 +963,8 @@ bool QGuiApplicationPrivate::isWindowBlocked(QWindow *window, QWindow **blocking
/*!
Returns the QWindow that receives events tied to focus,
such as key events.
+
+ \sa QWindow::requestActivate()
*/
QWindow *QGuiApplication::focusWindow()
{
@@ -1177,14 +1194,26 @@ QWindow *QGuiApplication::topLevelAt(const QPoint &pos)
\li \c xcb is a plugin for the X11 window system, used on some desktop Linux platforms.
\endlist
+ \note Calling this function without a QGuiApplication will return the default
+ platform name, if available. The default platform name is not affected by the
+ \c{-platform} command line option, or the \c QT_QPA_PLATFORM environment variable.
+
For more information about the platform plugins for embedded Linux devices,
see \l{Qt for Embedded Linux}.
*/
QString QGuiApplication::platformName()
{
- return QGuiApplicationPrivate::platform_name ?
- *QGuiApplicationPrivate::platform_name : QString();
+ if (!QGuiApplication::instance()) {
+#ifdef QT_QPA_DEFAULT_PLATFORM_NAME
+ return QStringLiteral(QT_QPA_DEFAULT_PLATFORM_NAME);
+#else
+ return QString();
+#endif
+ } else {
+ return QGuiApplicationPrivate::platform_name ?
+ *QGuiApplicationPrivate::platform_name : QString();
+ }
}
Q_LOGGING_CATEGORY(lcQpaPluginLoading, "qt.qpa.plugin");
@@ -1219,6 +1248,10 @@ static void init_platform(const QString &pluginNamesWithArguments, const QString
QGuiApplicationPrivate::platform_integration = QPlatformIntegrationFactory::create(name, arguments, argc, argv, platformPluginPath);
if (Q_UNLIKELY(!QGuiApplicationPrivate::platform_integration)) {
if (availablePlugins.contains(name)) {
+ if (name == QStringLiteral("xcb") && QVersionNumber::compare(QLibraryInfo::version(), QVersionNumber(6, 5, 0)) >= 0) {
+ qCWarning(lcQpaPluginLoading).nospace().noquote()
+ << "From 6.5.0, xcb-cursor0 or libxcb-cursor0 is needed to load the Qt xcb platform plugin.";
+ }
qCInfo(lcQpaPluginLoading).nospace().noquote()
<< "Could not load the Qt platform plugin \"" << name << "\" in \""
<< QDir::toNativeSeparators(platformPluginPath) << "\" even though it was found.";
@@ -1307,7 +1340,7 @@ static void init_platform(const QString &pluginNamesWithArguments, const QString
if (!platformArguments.isEmpty()) {
if (QObject *nativeInterface = QGuiApplicationPrivate::platform_integration->nativeInterface()) {
for (const QString &argument : std::as_const(platformArguments)) {
- const int equalsPos = argument.indexOf(u'=');
+ const qsizetype equalsPos = argument.indexOf(u'=');
const QByteArray name =
equalsPos != -1 ? argument.left(equalsPos).toUtf8() : argument.toUtf8();
const QVariant value =
@@ -1327,7 +1360,7 @@ static void init_plugins(const QList<QByteArray> &pluginList)
{
for (int i = 0; i < pluginList.size(); ++i) {
QByteArray pluginSpec = pluginList.at(i);
- int colonPos = pluginSpec.indexOf(':');
+ qsizetype colonPos = pluginSpec.indexOf(':');
QObject *plugin;
if (colonPos < 0)
plugin = QGenericPluginFactory::create(QLatin1StringView(pluginSpec), QString());
@@ -1498,7 +1531,7 @@ void QGuiApplicationPrivate::createPlatformIntegration()
init_platform(QLatin1StringView(platformName), platformPluginPath, platformThemeName, argc, argv);
if (const QPlatformTheme *theme = platformTheme())
- QStyleHintsPrivate::get(QGuiApplication::styleHints())->setColorScheme(theme->colorScheme());
+ QStyleHintsPrivate::get(QGuiApplication::styleHints())->updateColorScheme(theme->colorScheme());
if (!icon.isEmpty())
forcedWindowIcon = QDir::isAbsolutePath(icon) ? QIcon(icon) : QIcon::fromTheme(icon);
@@ -1517,7 +1550,11 @@ void QGuiApplicationPrivate::createEventDispatcher()
if (platform_integration == nullptr)
createPlatformIntegration();
- // The platform integration should not mess with the event dispatcher
+ // The platform integration should not result in creating an event dispatcher
+ Q_ASSERT_X(!threadData.loadRelaxed()->eventDispatcher, "QGuiApplication",
+ "Creating the platform integration resulted in creating an event dispatcher");
+
+ // Nor should it mess with the QCoreApplication's event dispatcher
Q_ASSERT(!eventDispatcher);
eventDispatcher = platform_integration->createEventDispatcher();
@@ -1594,7 +1631,7 @@ void Q_TRACE_INSTRUMENT(qtgui) QGuiApplicationPrivate::init()
++i;
if (argv[i] && *argv[i]) {
session_id = QString::fromLatin1(argv[i]);
- int p = session_id.indexOf(u'_');
+ qsizetype p = session_id.indexOf(u'_');
if (p >= 0) {
session_key = session_id.mid(p +1);
session_id = session_id.left(p);
@@ -1810,7 +1847,7 @@ Qt::KeyboardModifiers QGuiApplication::queryKeyboardModifiers()
{
CHECK_QAPP_INSTANCE(Qt::KeyboardModifiers{})
QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration();
- return pi->queryKeyboardModifiers();
+ return pi->keyMapper()->queryKeyboardModifiers();
}
/*!
@@ -1868,9 +1905,10 @@ QFunctionPointer QGuiApplication::platformFunction(const QByteArray &function)
Generally, no user interaction can take place before calling exec().
- To make your application perform idle processing, e.g., executing a special
- function whenever there are no pending events, use a QTimer with 0 timeout.
- More advanced idle processing schemes can be achieved using processEvents().
+ To make your application perform idle processing, e.g., executing a
+ special function whenever there are no pending events, use a QChronoTimer
+ with 0ns timeout. More advanced idle processing schemes can be achieved
+ using processEvents().
We recommend that you connect clean-up code to the
\l{QCoreApplication::}{aboutToQuit()} signal, instead of putting it in your
@@ -1960,7 +1998,8 @@ bool QGuiApplication::notify(QObject *object, QEvent *event)
*/
bool QGuiApplication::event(QEvent *e)
{
- if (e->type() == QEvent::LanguageChange) {
+ switch (e->type()) {
+ case QEvent::LanguageChange:
// if the layout direction was set explicitly, then don't override it here
if (layout_direction == Qt::LayoutDirectionAuto)
setLayoutDirection(layout_direction);
@@ -1968,13 +2007,15 @@ bool QGuiApplication::event(QEvent *e)
if (topLevelWindow->flags() != Qt::Desktop)
postEvent(topLevelWindow, new QEvent(QEvent::LanguageChange));
}
- } else if (e->type() == QEvent::ApplicationFontChange ||
- e->type() == QEvent::ApplicationPaletteChange) {
+ break;
+ case QEvent::ApplicationFontChange:
+ case QEvent::ApplicationPaletteChange:
for (auto *topLevelWindow : QGuiApplication::topLevelWindows()) {
if (topLevelWindow->flags() != Qt::Desktop)
postEvent(topLevelWindow, new QEvent(e->type()));
}
- } else if (e->type() == QEvent::Quit) {
+ break;
+ case QEvent::Quit:
// Close open windows. This is done in order to deliver de-expose
// events while the event loop is still running.
for (QWindow *topLevelWindow : QGuiApplication::topLevelWindows()) {
@@ -1986,8 +2027,10 @@ bool QGuiApplication::event(QEvent *e)
return true;
}
}
+ break;
+ default:
+ break;
}
-
return QCoreApplication::event(e);
}
@@ -2045,8 +2088,8 @@ void Q_TRACE_INSTRUMENT(qtgui) QGuiApplicationPrivate::processWindowSystemEvent(
case QWindowSystemInterfacePrivate::Leave:
QGuiApplicationPrivate::processLeaveEvent(static_cast<QWindowSystemInterfacePrivate::LeaveEvent *>(e));
break;
- case QWindowSystemInterfacePrivate::ActivatedWindow:
- QGuiApplicationPrivate::processActivatedEvent(static_cast<QWindowSystemInterfacePrivate::ActivatedWindowEvent *>(e));
+ case QWindowSystemInterfacePrivate::FocusWindow:
+ QGuiApplicationPrivate::processFocusWindowEvent(static_cast<QWindowSystemInterfacePrivate::FocusWindowEvent *>(e));
break;
case QWindowSystemInterfacePrivate::WindowStateChanged:
QGuiApplicationPrivate::processWindowStateChangedEvent(static_cast<QWindowSystemInterfacePrivate::WindowStateChangedEvent *>(e));
@@ -2214,12 +2257,14 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
qAbs(globalPoint.y() - pressPos.y()) > doubleClickDistance)
mousePressButton = Qt::NoButton;
} else {
+ static unsigned long lastPressTimestamp = 0;
mouse_buttons = e->buttons;
if (mousePress) {
ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval());
- doubleClick = e->timestamp - persistentEPD->eventPoint.pressTimestamp()
+ doubleClick = e->timestamp - lastPressTimestamp
< doubleClickInterval && button == mousePressButton;
mousePressButton = button;
+ lastPressTimestamp = e ->timestamp;
}
}
@@ -2359,6 +2404,7 @@ void QGuiApplicationPrivate::processWheelEvent(QWindowSystemInterfacePrivate::Wh
mouse_buttons, e->modifiers, e->phase, e->inverted, e->source, device);
ev.setTimestamp(e->timestamp);
QGuiApplication::sendSpontaneousEvent(window, &ev);
+ e->eventAccepted = ev.isAccepted();
#else
Q_UNUSED(e);
#endif // QT_CONFIG(wheelevent)
@@ -2466,10 +2512,10 @@ void QGuiApplicationPrivate::processLeaveEvent(QWindowSystemInterfacePrivate::Le
QCoreApplication::sendSpontaneousEvent(e->leave.data(), &event);
}
-void QGuiApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate::ActivatedWindowEvent *e)
+void QGuiApplicationPrivate::processFocusWindowEvent(QWindowSystemInterfacePrivate::FocusWindowEvent *e)
{
QWindow *previous = QGuiApplicationPrivate::focus_window;
- QWindow *newFocus = e->activated.data();
+ QWindow *newFocus = e->focused.data();
if (previous == newFocus)
return;
@@ -2557,34 +2603,18 @@ void QGuiApplicationPrivate::processWindowStateChangedEvent(QWindowSystemInterfa
void QGuiApplicationPrivate::processWindowScreenChangedEvent(QWindowSystemInterfacePrivate::WindowScreenChangedEvent *wse)
{
- if (QWindow *window = wse->window.data()) {
- if (window->screen() == wse->screen.data())
- return;
-
- const qreal oldDevicePixelRatio = window->screen() ? window->screen()->devicePixelRatio() : 1.0;
-
- if (QWindow *topLevelWindow = window->d_func()->topLevelWindow(QWindow::ExcludeTransients)) {
- if (QScreen *screen = wse->screen.data())
- topLevelWindow->d_func()->setTopLevelScreen(screen, false /* recreate */);
- else // Fall back to default behavior, and try to find some appropriate screen
- topLevelWindow->setScreen(nullptr);
- }
+ QWindow *window = wse->window.data();
+ if (!window)
+ return;
- // We may have changed scaling; trigger resize event if needed,
- // except on Windows, where we send resize events during WM_DPICHANGED
- // event handling. FIXME: unify DPI change handling across all platforms.
-#ifndef Q_OS_WIN
- if (window->handle()) {
- QWindowSystemInterfacePrivate::GeometryChangeEvent gce(window, QHighDpi::fromNativePixels(window->handle()->geometry(), window));
- processGeometryChangeEvent(&gce);
- }
-#endif
+ if (window->screen() == wse->screen.data())
+ return;
- const qreal newDevicePixelRatio = window->screen() ? window->screen()->devicePixelRatio() : 1.0;
- if (!qFuzzyCompare(oldDevicePixelRatio, newDevicePixelRatio)) {
- QEvent dprChangeEvent(QEvent::DevicePixelRatioChange);
- QGuiApplication::sendSpontaneousEvent(window, &dprChangeEvent);
- }
+ if (QWindow *topLevelWindow = window->d_func()->topLevelWindow(QWindow::ExcludeTransients)) {
+ if (QScreen *screen = wse->screen.data())
+ topLevelWindow->d_func()->setTopLevelScreen(screen, false /* recreate */);
+ else // Fall back to default behavior, and try to find some appropriate screen
+ topLevelWindow->setScreen(nullptr);
}
}
@@ -2592,9 +2622,7 @@ void QGuiApplicationPrivate::processWindowDevicePixelRatioChangedEvent(QWindowSy
{
if (wde->window.isNull())
return;
-
- QEvent dprChangeEvent(QEvent::DevicePixelRatioChange);
- QGuiApplication::sendSpontaneousEvent(wde->window, &dprChangeEvent);
+ QWindowPrivate::get(wde->window)->updateDevicePixelRatio();
}
void QGuiApplicationPrivate::processSafeAreaMarginsChangedEvent(QWindowSystemInterfacePrivate::SafeAreaMarginsChangedEvent *wse)
@@ -2613,30 +2641,23 @@ void QGuiApplicationPrivate::processThemeChanged(QWindowSystemInterfacePrivate::
if (self)
self->handleThemeChanged();
+ QIconPrivate::clearIconCache();
+
QEvent themeChangeEvent(QEvent::ThemeChange);
const QWindowList windows = tce->window ? QWindowList{tce->window} : window_list;
for (auto *window : windows)
QGuiApplication::sendSpontaneousEvent(window, &themeChangeEvent);
-
- QStyleHintsPrivate::get(QGuiApplication::styleHints())->setColorScheme(colorScheme());
-}
-
-/*!
- \internal
- \brief QGuiApplicationPrivate::colorScheme
- \return the platform theme's color scheme
- or Qt::ColorScheme::Unknown if a platform theme cannot be established
- */
-Qt::ColorScheme QGuiApplicationPrivate::colorScheme()
-{
- return platformTheme() ? platformTheme()->colorScheme()
- : Qt::ColorScheme::Unknown;
}
void QGuiApplicationPrivate::handleThemeChanged()
{
+ const auto newColorScheme = platformTheme() ? platformTheme()->colorScheme()
+ : Qt::ColorScheme::Unknown;
+ QStyleHintsPrivate::get(QGuiApplication::styleHints())->updateColorScheme(newColorScheme);
+
updatePalette();
+ QIconLoader::instance()->updateSystemTheme();
QAbstractFileIconProviderPrivate::clearIconTypeCache();
if (!(applicationResourceFlags & ApplicationFontExplicitlySet)) {
@@ -2903,17 +2924,17 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
// Send the TouchCancel to all windows with active touches and clean up.
QTouchEvent touchEvent(QEvent::TouchCancel, device, e->modifiers);
touchEvent.setTimestamp(e->timestamp);
- QSet<QWindow *> windowsNeedingCancel;
+ constexpr qsizetype Prealloc = decltype(devPriv->activePoints)::mapped_container_type::PreallocatedSize;
+ QMinimalVarLengthFlatSet<QWindow *, Prealloc> windowsNeedingCancel;
for (auto &epd : devPriv->activePoints.values()) {
if (QWindow *w = QMutableEventPoint::window(epd.eventPoint))
windowsNeedingCancel.insert(w);
}
- for (QSet<QWindow *>::const_iterator winIt = windowsNeedingCancel.constBegin(),
- winItEnd = windowsNeedingCancel.constEnd(); winIt != winItEnd; ++winIt) {
- QGuiApplication::sendSpontaneousEvent(*winIt, &touchEvent);
- }
+ for (QWindow *w : windowsNeedingCancel)
+ QGuiApplication::sendSpontaneousEvent(w, &touchEvent);
+
if (!self->synthesizedMousePoints.isEmpty() && !e->synthetic()) {
for (QHash<QWindow *, SynthesizedMouseData>::const_iterator synthIt = self->synthesizedMousePoints.constBegin(),
synthItEnd = self->synthesizedMousePoints.constEnd(); synthIt != synthItEnd; ++synthIt) {
@@ -3179,6 +3200,10 @@ void QGuiApplicationPrivate::processScreenLogicalDotsPerInchChange(QWindowSystem
s->d_func()->updateGeometry();
}
+ for (QWindow *window : QGuiApplication::allWindows())
+ if (window->screen() == e->screen)
+ QWindowPrivate::get(window)->updateDevicePixelRatio();
+
resetCachedDevicePixelRatio();
}
@@ -3237,6 +3262,16 @@ void QGuiApplicationPrivate::processExposeEvent(QWindowSystemInterfacePrivate::E
const bool wasExposed = p->exposed;
p->exposed = e->isExposed && window->screen();
+ // We expect that the platform plugins send DevicePixelRatioChange events.
+ // As a fail-safe make a final check here to make sure the cached DPR value is
+ // always up to date before sending the expose event.
+ if (e->isExposed && !e->region.isEmpty()) {
+ const bool dprWasChanged = QWindowPrivate::get(window)->updateDevicePixelRatio();
+ if (dprWasChanged)
+ qWarning() << "The cached device pixel ratio value was stale on window expose. "
+ << "Please file a QTBUG which explains how to reproduce.";
+ }
+
// We treat expose events for an already exposed window as paint events
if (wasExposed && p->exposed && shouldSynthesizePaintEvents) {
QPaintEvent paintEvent(e->region);
@@ -3462,7 +3497,8 @@ bool QGuiApplicationPrivate::setPalette(const QPalette &palette)
*/
QPalette QGuiApplicationPrivate::basePalette() const
{
- return platformTheme() ? *platformTheme()->palette() : Qt::gray;
+ const auto pf = platformTheme();
+ return pf && pf->palette() ? *pf->palette() : Qt::gray;
}
void QGuiApplicationPrivate::handlePaletteChanged(const char *className)
@@ -3629,9 +3665,13 @@ void QGuiApplicationPrivate::notifyWindowIconChanged()
The default is \c true.
- If this property is \c true, the applications quits when the last visible
- \l{Primary and Secondary Windows}{primary window} (i.e. top level window
- with no transient parent) is closed.
+ If this property is \c true, the application will attempt to
+ quit when the last visible \l{Primary and Secondary Windows}{primary window}
+ (i.e. top level window with no transient parent) is closed.
+
+ Note that attempting a quit may not necessarily result in the
+ application quitting, for example if there still are active
+ QEventLoopLocker instances, or the QEvent::Quit event is ignored.
\sa quit(), QWindow::close()
*/
@@ -3687,7 +3727,13 @@ bool QGuiApplicationPrivate::lastWindowClosed() const
bool QGuiApplicationPrivate::canQuitAutomatically()
{
- if (quitOnLastWindowClosed && !lastWindowClosed())
+ // The automatic quit functionality is triggered by
+ // both QEventLoopLocker and maybeLastWindowClosed.
+ // Although the former is a QCoreApplication feature
+ // we don't want to quit the application when there
+ // are open windows, regardless of whether the app
+ // also quits automatically on maybeLastWindowClosed.
+ if (!lastWindowClosed())
return false;
return QCoreApplicationPrivate::canQuitAutomatically();
@@ -3751,6 +3797,8 @@ Qt::ApplicationState QGuiApplication::applicationState()
*/
void QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy policy)
{
+ if (qApp)
+ qWarning("setHighDpiScaleFactorRoundingPolicy must be called before creating the QGuiApplication instance");
QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy = policy;
}
@@ -4341,7 +4389,7 @@ void *QGuiApplication::resolveInterface(const char *name, int revision) const
#if QT_CONFIG(xcb)
QT_NATIVE_INTERFACE_RETURN_IF(QX11Application, platformNativeInterface());
#endif
-#if defined(Q_OS_UNIX)
+#if QT_CONFIG(wayland)
QT_NATIVE_INTERFACE_RETURN_IF(QWaylandApplication, platformNativeInterface());
#endif
diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h
index ec63876058..cca79534fc 100644
--- a/src/gui/kernel/qguiapplication_p.h
+++ b/src/gui/kernel/qguiapplication_p.h
@@ -34,6 +34,8 @@
# include "private/qshortcutmap_p.h"
#endif
+#include <QtCore/qpointer.h>
+
#include <memory>
QT_BEGIN_NAMESPACE
@@ -113,7 +115,8 @@ public:
static void processEnterEvent(QWindowSystemInterfacePrivate::EnterEvent *e);
static void processLeaveEvent(QWindowSystemInterfacePrivate::LeaveEvent *e);
- static void processActivatedEvent(QWindowSystemInterfacePrivate::ActivatedWindowEvent *e);
+ static void processFocusWindowEvent(QWindowSystemInterfacePrivate::FocusWindowEvent *e);
+
static void processWindowStateChangedEvent(QWindowSystemInterfacePrivate::WindowStateChangedEvent *e);
static void processWindowScreenChangedEvent(QWindowSystemInterfacePrivate::WindowScreenChangedEvent *e);
static void processWindowDevicePixelRatioChangedEvent(QWindowSystemInterfacePrivate::WindowDevicePixelRatioChangedEvent *e);
@@ -336,8 +339,6 @@ private:
friend class QDragManager;
- static Qt::ColorScheme colorScheme();
-
static QGuiApplicationPrivate *self;
static int m_fakeMouseSourcePointId;
#ifdef Q_OS_WIN
@@ -400,8 +401,6 @@ struct Q_GUI_EXPORT QWindowsApplication
virtual bool isWinTabEnabled() const = 0;
virtual bool setWinTabEnabled(bool enabled) = 0;
- virtual bool isDarkMode() const = 0;
-
virtual DarkModeHandling darkModeHandling() const = 0;
virtual void setDarkModeHandling(DarkModeHandling handling) = 0;
@@ -420,7 +419,7 @@ struct Q_GUI_EXPORT QWindowsApplication
virtual QVariant gpu() const = 0; // internal, used by qtdiag
virtual QVariant gpuList() const = 0;
- virtual void lightSystemPalette(QPalette &pal) const = 0;
+ virtual void populateLightSystemPalette(QPalette &pal) const = 0;
};
#endif // Q_OS_WIN
diff --git a/src/gui/kernel/qguiapplication_platform.h b/src/gui/kernel/qguiapplication_platform.h
index b6182e42a3..545bf75c84 100644
--- a/src/gui/kernel/qguiapplication_platform.h
+++ b/src/gui/kernel/qguiapplication_platform.h
@@ -23,7 +23,7 @@ typedef struct _XDisplay Display;
struct xcb_connection_t;
#endif
-#if defined(Q_OS_UNIX)
+#if QT_CONFIG(wayland)
struct wl_display;
struct wl_compositor;
struct wl_seat;
@@ -46,7 +46,7 @@ struct Q_GUI_EXPORT QX11Application
};
#endif
-#if defined(Q_OS_UNIX) || defined(Q_CLANG_QDOC)
+#if QT_CONFIG(wayland) || defined(Q_QDOC)
struct Q_GUI_EXPORT QWaylandApplication
{
QT_DECLARE_NATIVE_INTERFACE(QWaylandApplication, 1, QGuiApplication)
diff --git a/src/gui/kernel/qguivariant.cpp b/src/gui/kernel/qguivariant.cpp
index 4fdc744029..fe72e7782f 100644
--- a/src/gui/kernel/qguivariant.cpp
+++ b/src/gui/kernel/qguivariant.cpp
@@ -56,7 +56,8 @@ QT_BEGIN_NAMESPACE
namespace {
-static const struct : QMetaTypeModuleHelper
+// NOLINTNEXTLINE(cppcoreguidelines-virtual-class-destructor): this is not a base class
+static constexpr struct : QMetaTypeModuleHelper
{
#define QT_IMPL_METATYPEINTERFACE_GUI_TYPES(MetaTypeName, MetaTypeId, RealName) \
QT_METATYPE_INTERFACE_INIT(RealName),
diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp
index 0f4803d92a..a0e1b48dcb 100644
--- a/src/gui/kernel/qhighdpiscaling.cpp
+++ b/src/gui/kernel/qhighdpiscaling.cpp
@@ -494,7 +494,8 @@ void QHighDpiScaling::updateHighDpiScaling()
qCDebug(lcHighDpi) << "Applying screen factors" << m_screenFactors;
int i = -1;
const auto screens = QGuiApplication::screens();
- for (const auto &[name, factor] : m_screenFactors) {
+ for (const auto &[name, rawFactor]: m_screenFactors) {
+ const qreal factor = roundScaleFactor(rawFactor);
++i;
if (name.isNull()) {
if (i < screens.size())
@@ -540,15 +541,17 @@ void QHighDpiScaling::setGlobalFactor(qreal factor)
if (!QGuiApplication::allWindows().isEmpty())
qWarning("QHighDpiScaling::setFactor: Should only be called when no windows exist.");
+ const auto screens = QGuiApplication::screens();
+
+ std::vector<QScreenPrivate::UpdateEmitter> updateEmitters;
+ for (QScreen *screen : screens)
+ updateEmitters.emplace_back(screen);
+
m_globalScalingActive = !qFuzzyCompare(factor, qreal(1));
m_factor = m_globalScalingActive ? factor : qreal(1);
m_active = m_globalScalingActive || m_screenFactorSet || m_platformPluginDpiScalingActive ;
- const auto screens = QGuiApplication::screens();
for (QScreen *screen : screens)
screen->d_func()->updateGeometry();
-
- // FIXME: The geometry has been updated based on the new scale factor,
- // but we don't emit any geometry change signals for the screens.
}
static const char scaleFactorProperty[] = "_q_scaleFactor";
@@ -565,6 +568,8 @@ void QHighDpiScaling::setScreenFactor(QScreen *screen, qreal factor)
m_active = true;
}
+ QScreenPrivate::UpdateEmitter updateEmitter(screen);
+
// Prefer associating the factor with screen name over the object
// since the screen object may be deleted on screen disconnects.
const QString name = screen->name();
@@ -573,9 +578,7 @@ void QHighDpiScaling::setScreenFactor(QScreen *screen, qreal factor)
else
QHighDpiScaling::m_namedScreenScaleFactors.insert(name, factor);
- // hack to force re-evaluation of screen geometry
- if (screen->handle())
- screen->d_func()->setPlatformScreen(screen->handle()); // updates geometries based on scale factor
+ screen->d_func()->updateGeometry();
}
QPoint QHighDpiScaling::mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen)
@@ -696,7 +699,7 @@ QVector<QHighDpiScaling::ScreenFactor> QHighDpiScaling::parseScreenScaleFactorsS
// - a semicolon-separated name=factor list: "foo=1.5;bar=2;baz=3"
const auto specs = screenScaleFactors.split(u';');
for (const auto &spec : specs) {
- const int equalsPos = spec.lastIndexOf(u'=');
+ const qsizetype equalsPos = spec.lastIndexOf(u'=');
if (equalsPos == -1) {
// screens in order
bool ok;
diff --git a/src/gui/kernel/qinputdevice.cpp b/src/gui/kernel/qinputdevice.cpp
index 8a4066c0a3..f7b216dcf0 100644
--- a/src/gui/kernel/qinputdevice.cpp
+++ b/src/gui/kernel/qinputdevice.cpp
@@ -235,6 +235,13 @@ Q_CONSTINIT static QBasicMutex devicesMutex;
/*!
Returns a list of all registered input devices (keyboards and pointing devices).
+ \note The list of devices is not always complete on all platforms. So far,
+ the most-complete information is available on the \l {Qt for Linux/X11}{X11}
+ platform, at startup and in response to hot-plugging. Most other platforms
+ are only able to provide generic devices of various types, only after receiving
+ events from them; and most platforms do not tell Qt when a device is plugged in,
+ or when it is unplugged at runtime.
+
\note The returned list cannot be used to add new devices. To add a simulated
touch screen for an autotest, QTest::createTouchDevice() can be used.
Platform plugins should call QWindowSystemInterface::registerInputDevice()
@@ -377,7 +384,7 @@ QDebug operator<<(QDebug debug, const QInputDevice *device)
debug << "QInputDevice(";
debug << '"' << device->name() << "\", type=" << device->type()
- << Qt::hex << ", ID=" << device->systemId() << ", seat='" << device->seatName() << "'";
+ << ", ID=" << device->systemId() << ", seat='" << device->seatName() << "'";
debug << ')';
return debug;
}
diff --git a/src/gui/kernel/qinternalmimedata.cpp b/src/gui/kernel/qinternalmimedata.cpp
index 9fd7f89a0f..d33402703e 100644
--- a/src/gui/kernel/qinternalmimedata.cpp
+++ b/src/gui/kernel/qinternalmimedata.cpp
@@ -20,7 +20,7 @@ static QStringList imageMimeFormats(const QList<QByteArray> &imageFormats)
formats.append("image/"_L1 + QLatin1StringView(format.toLower()));
//put png at the front because it is best
- int pngIndex = formats.indexOf("image/png"_L1);
+ const qsizetype pngIndex = formats.indexOf("image/png"_L1);
if (pngIndex != -1 && pngIndex != 0)
formats.move(pngIndex, 0);
diff --git a/src/gui/kernel/qkeymapper.cpp b/src/gui/kernel/qkeymapper.cpp
index aa8eca5214..4ceb508465 100644
--- a/src/gui/kernel/qkeymapper.cpp
+++ b/src/gui/kernel/qkeymapper.cpp
@@ -9,6 +9,7 @@
#include <private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformkeymapper.h>
QT_BEGIN_NAMESPACE
@@ -23,8 +24,7 @@ QT_BEGIN_NAMESPACE
/*!
Constructs a new key mapper.
*/
-QKeyMapper::QKeyMapper()
- : QObject(*new QKeyMapperPrivate, nullptr)
+QKeyMapper::QKeyMapper() : QObject()
{
}
@@ -35,34 +35,34 @@ QKeyMapper::~QKeyMapper()
{
}
-static QList<int> extractKeyFromEvent(QKeyEvent *e)
+QList<QKeyCombination> QKeyMapper::possibleKeys(const QKeyEvent *e)
{
- QList<int> result;
- if (e->key() && (e->key() != Qt::Key_unknown))
- result << e->keyCombination().toCombined();
- else if (!e->text().isEmpty())
- result << int(e->text().at(0).unicode() + (int)e->modifiers());
- return result;
-}
+ qCDebug(lcQpaKeyMapper).verbosity(3) << "Computing possible key combinations for" << e;
-QList<int> QKeyMapper::possibleKeys(QKeyEvent *e)
-{
- return instance()->d_func()->possibleKeys(e);
-}
+ const auto *platformIntegration = QGuiApplicationPrivate::platformIntegration();
+ const auto *platformKeyMapper = platformIntegration->keyMapper();
+ QList<QKeyCombination> result = platformKeyMapper->possibleKeyCombinations(e);
-extern bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event); // in qapplication_*.cpp
-void QKeyMapper::changeKeyboard()
-{
- // ## TODO: Support KeyboardLayoutChange on QPA
-#if 0
- // inform all toplevel widgets of the change
- QEvent e(QEvent::KeyboardLayoutChange);
- QWidgetList list = QApplication::topLevelWidgets();
- for (int i = 0; i < list.size(); ++i) {
- QWidget *w = list.at(i);
- qt_sendSpontaneousEvent(w, &e);
+ if (result.isEmpty()) {
+ if (e->key() && (e->key() != Qt::Key_unknown))
+ result << e->keyCombination();
+ else if (!e->text().isEmpty())
+ result << (Qt::Key(e->text().at(0).unicode()) | e->modifiers());
+ }
+
+#if QT_CONFIG(shortcut)
+ if (lcQpaKeyMapper().isDebugEnabled()) {
+ qCDebug(lcQpaKeyMapper) << "Resulting possible key combinations:";
+ for (auto keyCombination : result) {
+ auto keySequence = QKeySequence(keyCombination);
+ qCDebug(lcQpaKeyMapper).verbosity(0) << "\t-"
+ << keyCombination << "/" << keySequence << "/"
+ << qUtf8Printable(keySequence.toString(QKeySequence::NativeText));
+ }
}
#endif
+
+ return result;
}
Q_GLOBAL_STATIC(QKeyMapper, keymapper)
@@ -75,30 +75,6 @@ QKeyMapper *QKeyMapper::instance()
return keymapper();
}
-QKeyMapperPrivate *qt_keymapper_private()
-{
- return QKeyMapper::instance()->d_func();
-}
-
-QKeyMapperPrivate::QKeyMapperPrivate()
-{
- keyboardInputLocale = QLocale::system();
- keyboardInputDirection = keyboardInputLocale.textDirection();
-}
-
-QKeyMapperPrivate::~QKeyMapperPrivate()
-{
-}
-
-QList<int> QKeyMapperPrivate::possibleKeys(QKeyEvent *e)
-{
- QList<int> result = QGuiApplicationPrivate::platformIntegration()->possibleKeys(e);
- if (!result.isEmpty())
- return result;
-
- return extractKeyFromEvent(e);
-}
-
void *QKeyMapper::resolveInterface(const char *name, int revision) const
{
Q_UNUSED(name); Q_UNUSED(revision);
diff --git a/src/gui/kernel/qkeymapper_p.h b/src/gui/kernel/qkeymapper_p.h
index 96c5620665..1a6a9a608f 100644
--- a/src/gui/kernel/qkeymapper_p.h
+++ b/src/gui/kernel/qkeymapper_p.h
@@ -25,7 +25,6 @@
QT_BEGIN_NAMESPACE
-class QKeyMapperPrivate;
class Q_GUI_EXPORT QKeyMapper : public QObject
{
Q_OBJECT
@@ -34,35 +33,14 @@ public:
~QKeyMapper();
static QKeyMapper *instance();
- static void changeKeyboard();
- static QList<int> possibleKeys(QKeyEvent *e);
+ static QList<QKeyCombination> possibleKeys(const QKeyEvent *e);
QT_DECLARE_NATIVE_INTERFACE_ACCESSOR(QKeyMapper)
private:
- friend QKeyMapperPrivate *qt_keymapper_private();
- Q_DECLARE_PRIVATE(QKeyMapper)
Q_DISABLE_COPY_MOVE(QKeyMapper)
};
-struct KeyboardLayoutItem;
-class QKeyEvent;
-
-class QKeyMapperPrivate : public QObjectPrivate
-{
- Q_DECLARE_PUBLIC(QKeyMapper)
-public:
- QKeyMapperPrivate();
- ~QKeyMapperPrivate();
-
- QList<int> possibleKeys(QKeyEvent *e);
-
- QLocale keyboardInputLocale;
- Qt::LayoutDirection keyboardInputDirection;
-};
-
-QKeyMapperPrivate *qt_keymapper_private(); // from qkeymapper.cpp
-
// ----------------- QNativeInterface -----------------
namespace QNativeInterface::Private {
diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp
index 0e05eb3375..0529d940d2 100644
--- a/src/gui/kernel/qkeysequence.cpp
+++ b/src/gui/kernel/qkeysequence.cpp
@@ -13,7 +13,7 @@
#endif
#include "qvariant.h"
-#if defined(Q_OS_MACOS)
+#if defined(Q_OS_APPLE)
#include <QtCore/private/qcore_mac_p.h>
#endif
@@ -24,11 +24,11 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-#if defined(Q_OS_MACOS) || defined(Q_QDOC)
+#if defined(Q_OS_APPLE) || defined(Q_QDOC)
Q_CONSTINIT static bool qt_sequence_no_mnemonics = true;
-struct MacSpecialKey {
+struct AppleSpecialKey {
int key;
- ushort macSymbol;
+ ushort appleSymbol;
};
// Unicode code points for the glyphs associated with these keys
@@ -38,7 +38,7 @@ static constexpr int kControlUnicode = 0x2303;
static constexpr int kOptionUnicode = 0x2325;
static constexpr int kCommandUnicode = 0x2318;
-static constexpr MacSpecialKey entries[] = {
+static constexpr AppleSpecialKey entries[] = {
{ Qt::Key_Escape, 0x238B },
{ Qt::Key_Tab, 0x21E5 },
{ Qt::Key_Backtab, 0x21E4 },
@@ -63,45 +63,45 @@ static constexpr MacSpecialKey entries[] = {
{ Qt::Key_Eject, 0x23CF },
};
-static constexpr bool operator<(const MacSpecialKey &lhs, const MacSpecialKey &rhs)
+static constexpr bool operator<(const AppleSpecialKey &lhs, const AppleSpecialKey &rhs)
{
return lhs.key < rhs.key;
}
-static constexpr bool operator<(const MacSpecialKey &lhs, int rhs)
+static constexpr bool operator<(const AppleSpecialKey &lhs, int rhs)
{
return lhs.key < rhs;
}
-static constexpr bool operator<(int lhs, const MacSpecialKey &rhs)
+static constexpr bool operator<(int lhs, const AppleSpecialKey &rhs)
{
return lhs < rhs.key;
}
static_assert(q20::is_sorted(std::begin(entries), std::end(entries)));
-QChar qt_macSymbolForQtKey(int key)
+static QChar appleSymbolForQtKey(int key)
{
const auto i = std::lower_bound(std::begin(entries), std::end(entries), key);
if (i == std::end(entries) || key < *i)
return QChar();
- ushort macSymbol = i->macSymbol;
+ ushort appleSymbol = i->appleSymbol;
if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)
- && (macSymbol == kControlUnicode || macSymbol == kCommandUnicode)) {
- if (macSymbol == kControlUnicode)
- macSymbol = kCommandUnicode;
+ && (appleSymbol == kControlUnicode || appleSymbol == kCommandUnicode)) {
+ if (appleSymbol == kControlUnicode)
+ appleSymbol = kCommandUnicode;
else
- macSymbol = kControlUnicode;
+ appleSymbol = kControlUnicode;
}
- return QChar(macSymbol);
+ return QChar(appleSymbol);
}
-static int qtkeyForMacSymbol(const QChar ch)
+static int qtkeyForAppleSymbol(const QChar ch)
{
const ushort unicode = ch.unicode();
- for (const MacSpecialKey &entry : entries) {
- if (entry.macSymbol == unicode) {
+ for (const AppleSpecialKey &entry : entries) {
+ if (entry.appleSymbol == unicode) {
int key = entry.key;
if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)
&& (unicode == kControlUnicode || unicode == kCommandUnicode)) {
@@ -191,7 +191,7 @@ void Q_GUI_EXPORT qt_set_sequence_auto_mnemonic(bool b) { qt_sequence_no_mnemoni
QKeySequence objects can be cast to a QString to obtain a human-readable
translated version of the sequence. Similarly, the toString() function
- produces human-readable strings for use in menus. On \macos, the
+ produces human-readable strings for use in menus. On Apple platforms, the
appropriate symbols are used to describe keyboard shortcuts using special
keys on the Macintosh keyboard.
@@ -199,12 +199,12 @@ void Q_GUI_EXPORT qt_set_sequence_auto_mnemonic(bool b) { qt_sequence_no_mnemoni
code point of the character; for example, 'A' gives the same key sequence
as Qt::Key_A.
- \note On \macos, references to "Ctrl", Qt::CTRL, Qt::Key_Control
+ \note On Apple platforms, references to "Ctrl", Qt::CTRL, Qt::Key_Control
and Qt::ControlModifier correspond to the \uicontrol Command keys on the
Macintosh keyboard, and references to "Meta", Qt::META, Qt::Key_Meta and
- Qt::MetaModifier correspond to the \uicontrol Control keys. Developers on
- \macos can use the same shortcut descriptions across all platforms,
- and their applications will automatically work as expected on \macos.
+ Qt::MetaModifier correspond to the \uicontrol Control keys. In effect,
+ developers can use the same shortcut descriptions across all platforms,
+ and their applications will automatically work as expected on Apple platforms.
\section1 Standard Shortcuts
@@ -213,21 +213,21 @@ void Q_GUI_EXPORT qt_set_sequence_auto_mnemonic(bool b) { qt_sequence_no_mnemoni
setting up actions in a typical application. The table below shows
some common key sequences that are often used for these standard
shortcuts by applications on four widely-used platforms. Note
- that on \macos, the \uicontrol Ctrl value corresponds to the \uicontrol
+ that on Apple platforms, the \uicontrol Ctrl value corresponds to the \uicontrol
Command keys on the Macintosh keyboard, and the \uicontrol Meta value
corresponds to the \uicontrol Control keys.
\table
- \header \li StandardKey \li Windows \li \macos \li KDE Plasma \li GNOME
+ \header \li StandardKey \li Windows \li Apple platforms \li KDE Plasma \li GNOME
\row \li HelpContents \li F1 \li Ctrl+? \li F1 \li F1
\row \li WhatsThis \li Shift+F1 \li Shift+F1 \li Shift+F1 \li Shift+F1
\row \li Open \li Ctrl+O \li Ctrl+O \li Ctrl+O \li Ctrl+O
\row \li Close \li Ctrl+F4, Ctrl+W \li Ctrl+W, Ctrl+F4 \li Ctrl+W \li Ctrl+W
\row \li Save \li Ctrl+S \li Ctrl+S \li Ctrl+S \li Ctrl+S
\row \li Quit \li \li Ctrl+Q \li Ctrl+Q \li Ctrl+Q
- \row \li SaveAs \li \li Ctrl+Shift+S \li \li Ctrl+Shift+S
+ \row \li SaveAs \li Ctrl+Shift+S \li Ctrl+Shift+S \li Ctrl+Shift+S \li Ctrl+Shift+S
\row \li New \li Ctrl+N \li Ctrl+N \li Ctrl+N \li Ctrl+N
- \row \li Delete \li Del \li Del, Meta+D \li Del, Ctrl+D \li Del, Ctrl+D
+ \row \li Delete \li Del \li Forward Delete, Meta+D \li Del, Ctrl+D \li Del, Ctrl+D
\row \li Cut \li Ctrl+X, Shift+Del \li Ctrl+X, Meta+K \li Ctrl+X, F20, Shift+Del \li Ctrl+X, F20, Shift+Del
\row \li Copy \li Ctrl+C, Ctrl+Ins \li Ctrl+C \li Ctrl+C, F16, Ctrl+Ins \li Ctrl+C, F16, Ctrl+Ins
\row \li Paste \li Ctrl+V, Shift+Ins \li Ctrl+V, Meta+Y \li Ctrl+V, F18, Shift+Ins \li Ctrl+V, F18, Shift+Ins
@@ -287,7 +287,7 @@ void Q_GUI_EXPORT qt_set_sequence_auto_mnemonic(bool b) { qt_sequence_no_mnemoni
\row \li DeleteCompleteLine \li (none) \li (none) \li Ctrl+U \li Ctrl+U
\row \li InsertParagraphSeparator \li Enter \li Enter \li Enter \li Enter
\row \li InsertLineSeparator \li Shift+Enter \li Meta+Enter, Meta+O \li Shift+Enter \li Shift+Enter
- \row \li Backspace \li (none) \li Meta+H \li (none) \li (none)
+ \row \li Backspace \li (none) \li Delete, Meta+H \li (none) \li (none)
\row \li Cancel \li Escape \li Escape, Ctrl+. \li Escape \li Escape
\endtable
@@ -374,7 +374,7 @@ void Q_GUI_EXPORT qt_set_sequence_auto_mnemonic(bool b) { qt_sequence_no_mnemoni
\enum QKeySequence::SequenceFormat
\value NativeText The key sequence as a platform specific string.
- This means that it will be shown translated and on the Mac it will
+ This means that it will be shown translated and on Apple platforms it will
resemble a key sequence from the menu bar. This enum is best used when you
want to display the string to the user.
@@ -710,7 +710,7 @@ static constexpr int numKeyNames = sizeof keyname / sizeof *keyname;
\value InsertLineSeparator Insert a new line.
\value InsertParagraphSeparator Insert a new paragraph.
\value Italic Italic text.
- \value MoveToEndOfBlock Move cursor to end of block. This shortcut is only used on the \macos.
+ \value MoveToEndOfBlock Move cursor to end of block. This shortcut is only used on Apple platforms.
\value MoveToEndOfDocument Move cursor to end of document.
\value MoveToEndOfLine Move cursor to end of line.
\value MoveToNextChar Move cursor to next character.
@@ -721,7 +721,7 @@ static constexpr int numKeyNames = sizeof keyname / sizeof *keyname;
\value MoveToPreviousLine Move cursor to previous line.
\value MoveToPreviousPage Move cursor to previous page.
\value MoveToPreviousWord Move cursor to previous word.
- \value MoveToStartOfBlock Move cursor to start of a block. This shortcut is only used on \macos.
+ \value MoveToStartOfBlock Move cursor to start of a block. This shortcut is only used on Apple platforms.
\value MoveToStartOfDocument Move cursor to start of document.
\value MoveToStartOfLine Move cursor to start of line.
\value New Create new document.
@@ -739,7 +739,7 @@ static constexpr int numKeyNames = sizeof keyname / sizeof *keyname;
\value Save Save document.
\value SelectAll Select all text.
\value Deselect Deselect text. Since 5.1
- \value SelectEndOfBlock Extend selection to the end of a text block. This shortcut is only used on \macos.
+ \value SelectEndOfBlock Extend selection to the end of a text block. This shortcut is only used on Apple platforms.
\value SelectEndOfDocument Extend selection to end of document.
\value SelectEndOfLine Extend selection to end of line.
\value SelectNextChar Extend selection to next character.
@@ -750,7 +750,7 @@ static constexpr int numKeyNames = sizeof keyname / sizeof *keyname;
\value SelectPreviousLine Extend selection to previous line.
\value SelectPreviousPage Extend selection to previous page.
\value SelectPreviousWord Extend selection to previous word.
- \value SelectStartOfBlock Extend selection to the start of a text block. This shortcut is only used on \macos.
+ \value SelectStartOfBlock Extend selection to the start of a text block. This shortcut is only used on Apple platforms.
\value SelectStartOfDocument Extend selection to start of document.
\value SelectStartOfLine Extend selection to start of line.
\value Underline Underline text.
@@ -784,8 +784,8 @@ QKeySequence::QKeySequence(StandardKey key)
{
const QList <QKeySequence> bindings = keyBindings(key);
//pick only the first/primary shortcut from current bindings
- if (bindings.size() > 0) {
- d = bindings.first().d;
+ if (!bindings.isEmpty()) {
+ d = bindings.constFirst().d;
d->ref.ref();
}
else
@@ -940,7 +940,7 @@ QKeySequence QKeySequence::mnemonic(const QString &text)
return ret;
bool found = false;
- int p = 0;
+ qsizetype p = 0;
while (p >= 0) {
p = text.indexOf(u'&', p) + 1;
if (p <= 0 || p >= (int)text.size())
@@ -993,7 +993,7 @@ int QKeySequence::assign(const QString &ks, QKeySequence::SequenceFormat format)
{
QString keyseq = ks;
int n = 0;
- int p = 0, diff = 0;
+ qsizetype p = 0, diff = 0;
// Run through the whole string, but stop
// if we have MaxKeyCount keys before the end.
@@ -1018,7 +1018,7 @@ int QKeySequence::assign(const QString &ks, QKeySequence::SequenceFormat format)
}
QString part = keyseq.left(-1 == p ? keyseq.size() : p - diff);
keyseq = keyseq.right(-1 == p ? 0 : keyseq.size() - (p + 1));
- d->key[n] = QKeySequencePrivate::decodeString(std::move(part), format);
+ d->key[n] = QKeySequencePrivate::decodeString(std::move(part), format).toCombined();
++n;
}
return n;
@@ -1036,15 +1036,7 @@ Q_DECLARE_TYPEINFO(QModifKeyName, Q_RELOCATABLE_TYPE);
Q_GLOBAL_STATIC(QList<QModifKeyName>, globalModifs)
Q_GLOBAL_STATIC(QList<QModifKeyName>, globalPortableModifs)
-/*!
- Constructs a single key from the string \a str.
-*/
-int QKeySequence::decodeString(const QString &str)
-{
- return QKeySequencePrivate::decodeString(str, NativeText);
-}
-
-int QKeySequencePrivate::decodeString(QString accel, QKeySequence::SequenceFormat format)
+QKeyCombination QKeySequencePrivate::decodeString(QString accel, QKeySequence::SequenceFormat format)
{
Q_ASSERT(!accel.isEmpty());
@@ -1056,7 +1048,7 @@ int QKeySequencePrivate::decodeString(QString accel, QKeySequence::SequenceForma
if (nativeText) {
gmodifs = globalModifs();
if (gmodifs->isEmpty()) {
-#if defined(Q_OS_MACOS)
+#if defined(Q_OS_APPLE)
const bool dontSwap = qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta);
if (dontSwap)
*gmodifs << QModifKeyName(Qt::META, QChar(kCommandUnicode));
@@ -1098,7 +1090,7 @@ int QKeySequencePrivate::decodeString(QString accel, QKeySequence::SequenceForma
modifs += *gmodifs; // Test non-translated ones last
QString sl = accel;
-#if defined(Q_OS_MACOS)
+#if defined(Q_OS_APPLE)
for (int i = 0; i < modifs.size(); ++i) {
const QModifKeyName &mkf = modifs.at(i);
if (sl.contains(mkf.name)) {
@@ -1111,8 +1103,8 @@ int QKeySequencePrivate::decodeString(QString accel, QKeySequence::SequenceForma
return Qt::Key_unknown;
#endif
- int i = 0;
- int lastI = 0;
+ qsizetype i = 0;
+ qsizetype lastI = 0;
while ((i = sl.indexOf(u'+', i + 1)) != -1) {
const QStringView sub = QStringView{sl}.mid(lastI, i - lastI + 1);
// If we get here the shortcuts contains at least one '+'. We break up
@@ -1146,15 +1138,15 @@ int QKeySequencePrivate::decodeString(QString accel, QKeySequence::SequenceForma
lastI = i + 1;
}
- int p = accel.lastIndexOf(u'+', accel.size() - 2); // -2 so that Ctrl++ works
+ qsizetype p = accel.lastIndexOf(u'+', accel.size() - 2); // -2 so that Ctrl++ works
QStringView accelRef(accel);
if (p > 0)
accelRef = accelRef.mid(p + 1);
int fnum = 0;
if (accelRef.size() == 1) {
-#if defined(Q_OS_MACOS)
- int qtKey = qtkeyForMacSymbol(accelRef.at(0));
+#if defined(Q_OS_APPLE)
+ int qtKey = qtkeyForAppleSymbol(accelRef.at(0));
if (qtKey != -1) {
ret |= qtKey;
} else
@@ -1189,17 +1181,7 @@ int QKeySequencePrivate::decodeString(QString accel, QKeySequence::SequenceForma
if (!found)
return Qt::Key_unknown;
}
- return ret;
-}
-
-/*!
- Creates a shortcut string for \a key. For example,
- Qt::CTRL+Qt::Key_O gives "Ctrl+O". The strings, "Ctrl", "Shift", etc. are
- translated (using QObject::tr()) in the "QShortcut" context.
- */
-QString QKeySequence::encodeString(int key)
-{
- return QKeySequencePrivate::encodeString(key, NativeText);
+ return QKeyCombination::fromCombined(ret);
}
static inline void addKey(QString &str, const QString &theKey, QKeySequence::SequenceFormat format)
@@ -1216,20 +1198,24 @@ static inline void addKey(QString &str, const QString &theKey, QKeySequence::Seq
str += theKey;
}
-QString QKeySequencePrivate::encodeString(int key, QKeySequence::SequenceFormat format)
+QString QKeySequencePrivate::encodeString(QKeyCombination keyCombination, QKeySequence::SequenceFormat format)
{
bool nativeText = (format == QKeySequence::NativeText);
QString s;
+ const auto key = keyCombination.key();
+
// Handle -1 (Invalid Key) and Qt::Key_unknown gracefully
- if (key == -1 || key == Qt::Key_unknown)
+ if (keyCombination.toCombined() == -1 || key == Qt::Key_unknown)
return s;
-#if defined(Q_OS_MACOS)
+ const auto modifiers = keyCombination.keyboardModifiers();
+
+#if defined(Q_OS_APPLE)
if (nativeText) {
- // On OS X the order (by default) is Meta, Alt, Shift, Control.
+ // On Apple platforms the order (by default) is Meta, Alt, Shift, Control.
// If the AA_MacDontSwapCtrlAndMeta is enabled, then the order
- // is Ctrl, Alt, Shift, Meta. The macSymbolForQtKey does this swap
+ // is Ctrl, Alt, Shift, Meta. The appleSymbolForQtKey helper does this swap
// for us, which means that we have to adjust our order here.
// The upshot is a lot more infrastructure to keep the number of
// if tests down and the code relatively clean.
@@ -1248,33 +1234,33 @@ QString QKeySequencePrivate::encodeString(int key, QKeySequence::SequenceFormat
}
for (int i = 0; modifierOrder[i] != 0; ++i) {
- if (key & modifierOrder[i])
- s += qt_macSymbolForQtKey(qtkeyOrder[i]);
+ if (modifiers & modifierOrder[i])
+ s += appleSymbolForQtKey(qtkeyOrder[i]);
}
} else
#endif
{
// On other systems the order is Meta, Control, Alt, Shift
- if ((key & Qt::META) == Qt::META)
+ if (modifiers & Qt::MetaModifier)
s = nativeText ? QCoreApplication::translate("QShortcut", "Meta") : QString::fromLatin1("Meta");
- if ((key & Qt::CTRL) == Qt::CTRL)
+ if (modifiers & Qt::ControlModifier)
addKey(s, nativeText ? QCoreApplication::translate("QShortcut", "Ctrl") : QString::fromLatin1("Ctrl"), format);
- if ((key & Qt::ALT) == Qt::ALT)
+ if (modifiers & Qt::AltModifier)
addKey(s, nativeText ? QCoreApplication::translate("QShortcut", "Alt") : QString::fromLatin1("Alt"), format);
- if ((key & Qt::SHIFT) == Qt::SHIFT)
+ if (modifiers & Qt::ShiftModifier)
addKey(s, nativeText ? QCoreApplication::translate("QShortcut", "Shift") : QString::fromLatin1("Shift"), format);
}
- if ((key & Qt::KeypadModifier) == Qt::KeypadModifier)
+ if (modifiers & Qt::KeypadModifier)
addKey(s, nativeText ? QCoreApplication::translate("QShortcut", "Num") : QString::fromLatin1("Num"), format);
- QString p = keyName(key, format);
+ QString keyName = QKeySequencePrivate::keyName(key, format);
-#if defined(Q_OS_MACOS)
+#if defined(Q_OS_APPLE)
if (nativeText)
- s += p;
+ s += keyName;
else
#endif
- addKey(s, p, format);
+ addKey(s, keyName, format);
return s;
}
@@ -1286,10 +1272,9 @@ QString QKeySequencePrivate::encodeString(int key, QKeySequence::SequenceFormat
This static method is used by encodeString() and by the D-Bus menu exporter.
*/
-QString QKeySequencePrivate::keyName(int key, QKeySequence::SequenceFormat format)
+QString QKeySequencePrivate::keyName(Qt::Key key, QKeySequence::SequenceFormat format)
{
bool nativeText = (format == QKeySequence::NativeText);
- key &= ~(Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier | Qt::KeypadModifier);
QString p;
if (key && key < Qt::Key_Escape && key != Qt::Key_Space) {
@@ -1304,9 +1289,9 @@ QString QKeySequencePrivate::keyName(int key, QKeySequence::SequenceFormat forma
: QString::fromLatin1("F%1").arg(key - Qt::Key_F1 + 1);
} else if (key) {
int i=0;
-#if defined(Q_OS_MACOS)
+#if defined(Q_OS_APPLE)
if (nativeText) {
- QChar ch = qt_macSymbolForQtKey(key);
+ QChar ch = appleSymbolForQtKey(key);
if (!ch.isNull())
p = ch;
else
@@ -1314,7 +1299,7 @@ QString QKeySequencePrivate::keyName(int key, QKeySequence::SequenceFormat forma
} else
#endif
{
-#if defined(Q_OS_MACOS)
+#if defined(Q_OS_APPLE)
NonSymbol:
#endif
while (i < numKeyNames) {
@@ -1427,6 +1412,7 @@ bool QKeySequence::operator==(const QKeySequence &other) const
/*!
\since 5.6
+ \relates QKeySequence
Calculates the hash value of \a key, using
\a seed to seed the calculation.
@@ -1503,7 +1489,7 @@ bool QKeySequence::isDetached() const
If the key sequence has no keys, an empty string is returned.
- On \macos, the string returned resembles the sequence that is
+ On Apple platforms, the string returned resembles the sequence that is
shown in the menu bar if \a format is
QKeySequence::NativeText; otherwise, the string uses the
"portable" format, suitable for writing to a file.
@@ -1517,7 +1503,7 @@ QString QKeySequence::toString(SequenceFormat format) const
// look like our latin case on Windows and X11
int end = count();
for (int i = 0; i < end; ++i) {
- finalString += d->encodeString(d->key[i], format);
+ finalString += d->encodeString(QKeyCombination::fromCombined(d->key[i]), format);
finalString += ", "_L1;
}
finalString.truncate(finalString.size() - 2);
diff --git a/src/gui/kernel/qkeysequence.h b/src/gui/kernel/qkeysequence.h
index 44fd1f9cca..4dae26a755 100644
--- a/src/gui/kernel/qkeysequence.h
+++ b/src/gui/kernel/qkeysequence.h
@@ -115,6 +115,7 @@ public:
NativeText,
PortableText
};
+ Q_ENUM(SequenceFormat)
QKeySequence();
QKeySequence(const QString &key, SequenceFormat format = NativeText);
@@ -135,6 +136,7 @@ public:
PartialMatch,
ExactMatch
};
+ Q_ENUM(SequenceMatch);
QString toString(SequenceFormat format = PortableText) const;
static QKeySequence fromString(const QString &str, SequenceFormat format = PortableText);
@@ -165,8 +167,6 @@ public:
bool isDetached() const;
private:
- static int decodeString(const QString &ks);
- static QString encodeString(int key);
int assign(const QString &str);
int assign(const QString &str, SequenceFormat format);
void setKey(QKeyCombination key, int index);
diff --git a/src/gui/kernel/qkeysequence_p.h b/src/gui/kernel/qkeysequence_p.h
index 2f9a0b09aa..8b98e3778a 100644
--- a/src/gui/kernel/qkeysequence_p.h
+++ b/src/gui/kernel/qkeysequence_p.h
@@ -35,7 +35,7 @@ struct QKeyBinding
class QKeySequencePrivate
{
public:
- enum { MaxKeyCount = 4 }; // also used in QKeySequenceEdit
+ static constexpr int MaxKeyCount = 4 ; // also used in QKeySequenceEdit
constexpr QKeySequencePrivate() : ref(1), key{} {}
inline QKeySequencePrivate(const QKeySequencePrivate &copy) : ref(1)
{
@@ -44,10 +44,10 @@ public:
}
QAtomicInt ref;
int key[MaxKeyCount];
- static QString encodeString(int key, QKeySequence::SequenceFormat format);
+ static QString encodeString(QKeyCombination keyCombination, QKeySequence::SequenceFormat format);
// used in dbusmenu
- Q_GUI_EXPORT static QString keyName(int key, QKeySequence::SequenceFormat format);
- static int decodeString(QString accel, QKeySequence::SequenceFormat format);
+ Q_GUI_EXPORT static QString keyName(Qt::Key key, QKeySequence::SequenceFormat format);
+ static QKeyCombination decodeString(QString accel, QKeySequence::SequenceFormat format);
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qoffscreensurface.h b/src/gui/kernel/qoffscreensurface.h
index 15ad430dae..410b6d2b61 100644
--- a/src/gui/kernel/qoffscreensurface.h
+++ b/src/gui/kernel/qoffscreensurface.h
@@ -8,7 +8,7 @@
#include <QtCore/QObject>
#include <QtCore/qnativeinterface.h>
#include <QtGui/qsurface.h>
-Q_MOC_INCLUDE(<QScreen>)
+Q_MOC_INCLUDE(<QtGui/qscreen.h>)
QT_BEGIN_NAMESPACE
diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp
index a018f86763..dd41318f72 100644
--- a/src/gui/kernel/qopenglcontext.cpp
+++ b/src/gui/kernel/qopenglcontext.cpp
@@ -69,6 +69,7 @@ QOpenGLContext *qt_gl_global_share_context()
/*!
\class QOpenGLContext
+ \ingroup painting-3D
\inmodule QtGui
\since 5.0
\brief The QOpenGLContext class represents a native OpenGL context, enabling
@@ -137,6 +138,22 @@ QOpenGLContext *qt_gl_global_share_context()
application is portable between different platforms. However, if you use
QOpenGLFunctions::glBindFramebuffer(), this is done automatically for you.
+ \warning WebAssembly
+
+ We recommend that only one QOpenGLContext is made current with a QSurface,
+ for the entire lifetime of the QSurface. Should more than once context be used,
+ it is important to understand that multiple QOpenGLContext instances may be
+ backed by the same native context underneath with the WebAssembly platform.
+ Therefore, calling makeCurrent() with the same QSurface on two QOpenGLContext
+ objects may not switch to a different native context in the second call. As
+ a result, any OpenGL state changes done after the second makeCurrent() may
+ alter the state of the first QOpenGLContext as well, as they are all backed
+ by the same native context.
+
+ \note This means that when targeting WebAssembly with existing OpenGL-based
+ Qt code, some porting may be required to cater to these limitations.
+
+
\sa QOpenGLFunctions, QOpenGLBuffer, QOpenGLShaderProgram, QOpenGLFramebufferObject
*/
@@ -153,6 +170,9 @@ QOpenGLContext *QOpenGLContextPrivate::setCurrentContext(QOpenGLContext *context
qWarning("No QTLS available. currentContext won't work");
return nullptr;
}
+ if (!context)
+ return nullptr;
+
threadContext = new QGuiGLThreadContext;
qwindow_context_storage()->setLocalData(threadContext);
}
@@ -451,6 +471,11 @@ void QOpenGLContext::destroy()
If you wish to make the context current in order to do clean-up, make sure
to only connect to the signal using a direct connection.
+
+ \note In Qt for Python, this signal will not be received when emitted
+ from the destructor of QOpenGLWidget or QOpenGLWindow due to the Python
+ instance already being destroyed. We recommend doing cleanups
+ in QWidget::hideEvent() instead.
*/
/*!
diff --git a/src/gui/kernel/qpaintdevicewindow.cpp b/src/gui/kernel/qpaintdevicewindow.cpp
index bc7ac89b03..9e8c6ae5a8 100644
--- a/src/gui/kernel/qpaintdevicewindow.cpp
+++ b/src/gui/kernel/qpaintdevicewindow.cpp
@@ -171,6 +171,8 @@ bool QPaintDeviceWindow::event(QEvent *event)
auto region = QRect(QPoint(0, 0), size());
d->doFlush(region); // Will end up calling paintEvent
return true;
+ } else if (event->type() == QEvent::Resize) {
+ d->handleResizeEvent();
}
return QWindow::event(event);
diff --git a/src/gui/kernel/qpaintdevicewindow_p.h b/src/gui/kernel/qpaintdevicewindow_p.h
index 32db2cb7a4..85c11cbf91 100644
--- a/src/gui/kernel/qpaintdevicewindow_p.h
+++ b/src/gui/kernel/qpaintdevicewindow_p.h
@@ -31,6 +31,8 @@ public:
QPaintDeviceWindowPrivate();
~QPaintDeviceWindowPrivate() override;
+ virtual void handleResizeEvent() {}
+
virtual void beginPaint(const QRegion &region)
{
Q_UNUSED(region);
@@ -82,7 +84,7 @@ public:
void markWindowAsDirty()
{
Q_Q(QPaintDeviceWindow);
- dirtyRegion += QRect(QPoint(0, 0), q->size());
+ dirtyRegion = QRect(QPoint(0, 0), q->size());
}
private:
diff --git a/src/gui/kernel/qpalette.cpp b/src/gui/kernel/qpalette.cpp
index 4abbcd5e65..256ea52f01 100644
--- a/src/gui/kernel/qpalette.cpp
+++ b/src/gui/kernel/qpalette.cpp
@@ -1,8 +1,7 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qpalette.h"
-#include "qguiapplication.h"
+#include "qpalette_p.h"
#include "qguiapplication_p.h"
#include "qdatastream.h"
#include "qvariant.h"
@@ -12,60 +11,11 @@
QT_BEGIN_NAMESPACE
-static int qt_palette_count = 1;
-
-static constexpr QPalette::ResolveMask colorRoleOffset(QPalette::ColorGroup colorGroup)
-{
- return qToUnderlying(QPalette::NColorRoles) * qToUnderlying(colorGroup);
-}
-
-static constexpr QPalette::ResolveMask bitPosition(QPalette::ColorGroup colorGroup,
- QPalette::ColorRole colorRole)
-{
- return colorRole + colorRoleOffset(colorGroup);
-}
-
-static_assert(bitPosition(QPalette::ColorGroup(QPalette::NColorGroups - 1),
+static_assert(QPalettePrivate::bitPosition(QPalette::ColorGroup(QPalette::NColorGroups - 1),
QPalette::ColorRole(QPalette::NColorRoles - 1))
< sizeof(QPalette::ResolveMask) * CHAR_BIT,
"The resolve mask type is not wide enough to fit the entire bit mask.");
-class QPalettePrivate
-{
-public:
- class Data : public QSharedData {
- public:
- // Every instance of Data has to have a unique serial number, even
- // if it gets created by copying another - we wouldn't create a copy
- // in the first place if the serial number should be the same!
- Data(const Data &other)
- : QSharedData(other)
- {
- for (int grp = 0; grp < int(QPalette::NColorGroups); grp++) {
- for (int role = 0; role < int(QPalette::NColorRoles); role++)
- br[grp][role] = other.br[grp][role];
- }
- }
- Data() = default;
-
- QBrush br[QPalette::NColorGroups][QPalette::NColorRoles];
- const int ser_no = qt_palette_count++;
- };
-
- QPalettePrivate(const QExplicitlySharedDataPointer<Data> &data)
- : ref(1), data(data)
- { }
- QPalettePrivate()
- : QPalettePrivate(QExplicitlySharedDataPointer<Data>(new Data))
- { }
-
- QAtomicInt ref;
- QPalette::ResolveMask resolveMask = {0};
- static inline int qt_palette_private_count = 0;
- int detach_no = ++qt_palette_private_count;
- QExplicitlySharedDataPointer<Data> data;
-};
-
static QColor qt_mix_colors(QColor a, QColor b)
{
return QColor((a.red() + b.red()) / 2, (a.green() + b.green()) / 2,
@@ -100,6 +50,24 @@ static void qt_placeholder_from_text(QPalette &pal, int alpha = 50)
}
}
+static void qt_ensure_default_accent_color(QPalette &pal)
+{
+ // have a lighter/darker factor handy, depending on dark/light heuristics
+ const int lighter = pal.base().color().lightness() > pal.text().color().lightness() ? 130 : 70;
+
+ // Act only for color groups where no accent color is set
+ for (int i = 0; i < QPalette::NColorGroups; ++i) {
+ const QPalette::ColorGroup group = static_cast<QPalette::ColorGroup>(i);
+ if (!pal.isBrushSet(group, QPalette::Accent)) {
+ // Default to highlight if available, otherwise use a shade of base
+ const QBrush accentBrush = pal.isBrushSet(group, QPalette::Highlight)
+ ? pal.brush(group, QPalette::Highlight)
+ : pal.brush(group, QPalette::Base).color().lighter(lighter);
+ pal.setBrush(group, QPalette::Accent, accentBrush);
+ }
+ }
+}
+
static void qt_palette_from_color(QPalette &pal, const QColor &button)
{
int h, s, v;
@@ -124,6 +92,7 @@ static void qt_palette_from_color(QPalette &pal, const QColor &button)
whiteBrush, buttonBrush, buttonBrush);
qt_placeholder_from_text(pal);
+ qt_ensure_default_accent_color(pal);
}
/*!
@@ -325,6 +294,15 @@ static void qt_palette_from_color(QPalette &pal, const QColor &button)
*/
/*!
+ \fn const QBrush & QPalette::accent() const
+ \since 6.6
+
+ Returns the accent brush of the current color group.
+
+ \sa ColorRole, brush()
+*/
+
+/*!
\fn const QBrush & QPalette::link() const
Returns the unvisited link text brush of the current color group.
@@ -524,6 +502,13 @@ static void qt_palette_from_color(QPalette &pal, const QColor &button)
item. By default, the highlight color is
Qt::darkBlue.
+ \value [since 6.6] Accent
+ A color that typically contrasts or complements
+ Base, Window and Button colors. It usually represents
+ the users' choice of desktop personalisation.
+ Styling of interactive components is a typical use case.
+ Unless explicitly set, it defaults to Highlight.
+
\value HighlightedText A text color that contrasts with \c Highlight.
By default, the highlighted text color is Qt::white.
@@ -613,6 +598,7 @@ QPalette::QPalette(const QBrush &windowText, const QBrush &button,
base, window);
qt_placeholder_from_text(*this);
+ qt_ensure_default_accent_color(*this);
}
@@ -670,6 +656,7 @@ QPalette::QPalette(const QColor &button, const QColor &window)
whiteBrush, baseBrush, windowBrush);
qt_placeholder_from_text(*this);
+ qt_ensure_default_accent_color(*this);
}
/*!
@@ -807,7 +794,7 @@ void QPalette::setBrush(ColorGroup cg, ColorRole cr, const QBrush &b)
cg = Active;
}
- const auto newResolveMask = d->resolveMask | ResolveMask(1) << bitPosition(cg, cr);
+ const auto newResolveMask = d->resolveMask | ResolveMask(1) << QPalettePrivate::bitPosition(cg, cr);
const auto valueChanged = d->data->br[cg][cr] != b;
if (valueChanged) {
@@ -837,6 +824,10 @@ void QPalette::setBrush(ColorGroup cg, ColorRole cr, const QBrush &b)
*/
bool QPalette::isBrushSet(ColorGroup cg, ColorRole cr) const
{
+ // NoRole has no resolve mask and should never be set anyway
+ if (cr == NoRole)
+ return false;
+
if (cg == Current)
cg = currentGroup;
@@ -850,7 +841,7 @@ bool QPalette::isBrushSet(ColorGroup cg, ColorRole cr) const
return false;
}
- return d->resolveMask & (ResolveMask(1) << bitPosition(cg, cr));
+ return d->resolveMask & (ResolveMask(1) << QPalettePrivate::bitPosition(cg, cr));
}
/*!
@@ -885,8 +876,11 @@ void QPalette::detach()
Returns \c true (usually quickly) if this palette is equal to \a p;
otherwise returns \c false (slowly).
- \note The current ColorGroup is not taken into account when
- comparing palettes
+ \note The following is not taken into account when comparing palettes:
+ \list
+ \li the \c current ColorGroup
+ \li ColorRole NoRole \since 6.6
+ \endlist
\sa operator!=()
*/
@@ -896,6 +890,9 @@ bool QPalette::operator==(const QPalette &p) const
return true;
for(int grp = 0; grp < (int)NColorGroups; grp++) {
for(int role = 0; role < (int)NColorRoles; role++) {
+ // Dont't verify NoRole, because it has no resolve bit
+ if (role == NoRole)
+ continue;
if (d->data->br[grp][role] != p.d->data->br[grp][role])
return false;
}
@@ -953,7 +950,7 @@ static constexpr QPalette::ResolveMask allResolveMask()
QPalette::ResolveMask mask = {0};
for (int role = 0; role < int(QPalette::NColorRoles); ++role) {
for (int grp = 0; grp < int(QPalette::NColorGroups); ++grp) {
- mask |= (QPalette::ResolveMask(1) << bitPosition(QPalette::ColorGroup(grp), QPalette::ColorRole(role)));
+ mask |= (QPalette::ResolveMask(1) << QPalettePrivate::bitPosition(QPalette::ColorGroup(grp), QPalette::ColorRole(role)));
}
}
return mask;
@@ -979,8 +976,12 @@ QPalette QPalette::resolve(const QPalette &other) const
palette.detach();
for (int role = 0; role < int(NColorRoles); ++role) {
+ // Don't resolve NoRole, its bits are needed for Accent (see bitPosition)
+ if (role == NoRole)
+ continue;
+
for (int grp = 0; grp < int(NColorGroups); ++grp) {
- if (!(d->resolveMask & (ResolveMask(1) << bitPosition(ColorGroup(grp), ColorRole(role))))) {
+ if (!(d->resolveMask & (ResolveMask(1) << QPalettePrivate::bitPosition(ColorGroup(grp), ColorRole(role))))) {
palette.d->data.detach();
palette.d->data->br[grp][role] = other.d->data->br[grp][role];
}
@@ -1054,6 +1055,9 @@ QDataStream &operator<<(QDataStream &s, const QPalette &p)
max = QPalette::AlternateBase + 1;
else if (s.version() <= QDataStream::Qt_5_11)
max = QPalette::ToolTipText + 1;
+ else if (s.version() <= QDataStream::Qt_6_5)
+ max = QPalette::PlaceholderText + 1;
+
for (int r = 0; r < max; r++)
s << p.d->data->br[grp][r];
}
@@ -1097,15 +1101,25 @@ QDataStream &operator>>(QDataStream &s, QPalette &p)
} else if (s.version() <= QDataStream::Qt_5_11) {
p = QPalette();
max = QPalette::ToolTipText + 1;
+ } else if (s.version() <= QDataStream::Qt_6_5) {
+ p = QPalette();
+ max = QPalette::PlaceholderText + 1;
}
+
QBrush tmp;
for(int grp = 0; grp < (int)QPalette::NColorGroups; ++grp) {
+ const QPalette::ColorGroup group = static_cast<QPalette::ColorGroup>(grp);
for(int role = 0; role < max; ++role) {
s >> tmp;
- p.setBrush((QPalette::ColorGroup)grp, (QPalette::ColorRole)role, tmp);
+ p.setBrush(group, (QPalette::ColorRole)role, tmp);
}
+
+ // Accent defaults to Highlight for stream versions that don't have it.
+ if (s.version() < QDataStream::Qt_6_6)
+ p.setBrush(group, QPalette::Accent, p.brush(group, QPalette::Highlight));
}
+
}
return s;
}
@@ -1152,10 +1166,10 @@ void QPalette::setColorGroup(ColorGroup cg, const QBrush &windowText, const QBru
for (int cr = Highlight; cr <= LinkVisited; ++cr) {
if (cg == All) {
for (int group = Active; group < NColorGroups; ++group) {
- d->resolveMask &= ~(ResolveMask(1) << bitPosition(ColorGroup(group), ColorRole(cr)));
+ d->resolveMask &= ~(ResolveMask(1) << QPalettePrivate::bitPosition(ColorGroup(group), ColorRole(cr)));
}
} else {
- d->resolveMask &= ~(ResolveMask(1) << bitPosition(ColorGroup(cg), ColorRole(cr)));
+ d->resolveMask &= ~(ResolveMask(1) << QPalettePrivate::bitPosition(ColorGroup(cg), ColorRole(cr)));
}
}
}
diff --git a/src/gui/kernel/qpalette.h b/src/gui/kernel/qpalette.h
index 0a6dc0b381..a6162e1090 100644
--- a/src/gui/kernel/qpalette.h
+++ b/src/gui/kernel/qpalette.h
@@ -45,6 +45,7 @@ public:
operator QVariant() const;
// Do not change the order, the serialization format depends on it
+ // Ensure these values are kept in sync with QQuickColorGroup's properties.
enum ColorGroup { Active, Disabled, Inactive, NColorGroups, Current, All, Normal = Active };
Q_ENUM(ColorGroup)
enum ColorRole { WindowText, Button, Light, Midlight, Dark, Mid,
@@ -55,7 +56,8 @@ public:
NoRole,
ToolTipBase, ToolTipText,
PlaceholderText,
- NColorRoles = PlaceholderText + 1,
+ Accent,
+ NColorRoles = Accent + 1,
};
Q_ENUM(ColorRole)
@@ -98,6 +100,7 @@ public:
inline const QBrush &link() const { return brush(Link); }
inline const QBrush &linkVisited() const { return brush(LinkVisited); }
inline const QBrush &placeholderText() const { return brush(PlaceholderText); }
+ inline const QBrush &accent() const { return brush(Accent); }
bool operator==(const QPalette &p) const;
inline bool operator!=(const QPalette &p) const { return !(operator==(p)); }
diff --git a/src/gui/kernel/qpalette_p.h b/src/gui/kernel/qpalette_p.h
new file mode 100644
index 0000000000..ce7c30d66d
--- /dev/null
+++ b/src/gui/kernel/qpalette_p.h
@@ -0,0 +1,77 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QPALETTE_P_H
+#define QPALETTE_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 "qpalette.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_GUI_EXPORT QPalettePrivate
+{
+public:
+ class Data : public QSharedData {
+ public:
+ // Every instance of Data has to have a unique serial number, even
+ // if it gets created by copying another - we wouldn't create a copy
+ // in the first place if the serial number should be the same!
+ Data(const Data &other)
+ : QSharedData(other)
+ {
+ for (int grp = 0; grp < int(QPalette::NColorGroups); grp++) {
+ for (int role = 0; role < int(QPalette::NColorRoles); role++)
+ br[grp][role] = other.br[grp][role];
+ }
+ }
+ Data() = default;
+
+ QBrush br[QPalette::NColorGroups][QPalette::NColorRoles];
+ const int ser_no = qt_palette_count++;
+ };
+
+ QPalettePrivate(const QExplicitlySharedDataPointer<Data> &data)
+ : ref(1), data(data)
+ { }
+ QPalettePrivate()
+ : QPalettePrivate(QExplicitlySharedDataPointer<Data>(new Data))
+ { }
+
+ static constexpr QPalette::ResolveMask colorRoleOffset(QPalette::ColorGroup colorGroup)
+ {
+ // Exclude NoRole; that bit is used for Accent
+ return (qToUnderlying(QPalette::NColorRoles) - 1) * qToUnderlying(colorGroup);
+ }
+
+ static constexpr QPalette::ResolveMask bitPosition(QPalette::ColorGroup colorGroup,
+ QPalette::ColorRole colorRole)
+ {
+ // Map Accent into NoRole for resolving purposes
+ if (colorRole == QPalette::Accent)
+ colorRole = QPalette::NoRole;
+
+ return colorRole + colorRoleOffset(colorGroup);
+ }
+
+ QAtomicInt ref;
+ QPalette::ResolveMask resolveMask = {0};
+ static inline int qt_palette_count = 0;
+ static inline int qt_palette_private_count = 0;
+ int detach_no = ++qt_palette_private_count;
+ QExplicitlySharedDataPointer<Data> data;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPALETTE_P_H
diff --git a/src/gui/kernel/qplatformdialoghelper.cpp b/src/gui/kernel/qplatformdialoghelper.cpp
index 7038954ea0..93de7933d4 100644
--- a/src/gui/kernel/qplatformdialoghelper.cpp
+++ b/src/gui/kernel/qplatformdialoghelper.cpp
@@ -778,6 +778,9 @@ public:
QPixmap iconPixmap;
QString checkBoxLabel;
Qt::CheckState checkBoxState = Qt::Unchecked;
+ int defaultButtonId = 0;
+ int escapeButtonId = 0;
+ QMessageDialogOptions::Options options;
};
QMessageDialogOptions::QMessageDialogOptions(QMessageDialogOptionsPrivate *dd)
@@ -880,9 +883,9 @@ QPlatformDialogHelper::StandardButtons QMessageDialogOptions::standardButtons()
}
int QMessageDialogOptions::addButton(const QString &label, QPlatformDialogHelper::ButtonRole role,
- void *buttonImpl)
+ void *buttonImpl, int buttonId)
{
- const CustomButton b(d->nextCustomButtonId++, label, role, buttonImpl);
+ const CustomButton b(buttonId ? buttonId : d->nextCustomButtonId++, label, role, buttonImpl);
d->customButtons.append(b);
return b.id;
}
@@ -902,9 +905,14 @@ const QList<QMessageDialogOptions::CustomButton> &QMessageDialogOptions::customB
return d->customButtons;
}
+void QMessageDialogOptions::clearCustomButtons()
+{
+ d->customButtons.clear();
+}
+
const QMessageDialogOptions::CustomButton *QMessageDialogOptions::customButton(int id)
{
- int i = d->customButtons.indexOf(CustomButton(id));
+ const int i = int(d->customButtons.indexOf(CustomButton(id)));
return (i < 0 ? nullptr : &d->customButtons.at(i));
}
@@ -924,6 +932,49 @@ Qt::CheckState QMessageDialogOptions::checkBoxState() const
return d->checkBoxState;
}
+void QMessageDialogOptions::setDefaultButton(int id)
+{
+ d->defaultButtonId = id;
+}
+
+int QMessageDialogOptions::defaultButton() const
+{
+ return d->defaultButtonId;
+}
+
+void QMessageDialogOptions::setEscapeButton(int id)
+{
+ d->escapeButtonId = id;
+}
+
+int QMessageDialogOptions::escapeButton() const
+{
+ return d->escapeButtonId;
+}
+
+void QMessageDialogOptions::setOption(QMessageDialogOptions::Option option, bool on)
+{
+ if (!(d->options & option) != !on)
+ setOptions(d->options ^ option);
+}
+
+bool QMessageDialogOptions::testOption(QMessageDialogOptions::Option option) const
+{
+ return d->options & option;
+}
+
+void QMessageDialogOptions::setOptions(QMessageDialogOptions::Options options)
+{
+ if (options != d->options)
+ d->options = options;
+}
+
+QMessageDialogOptions::Options QMessageDialogOptions::options() const
+{
+ return d->options;
+}
+
+
QPlatformDialogHelper::ButtonRole QPlatformDialogHelper::buttonRole(QPlatformDialogHelper::StandardButton button)
{
switch (button) {
diff --git a/src/gui/kernel/qplatformdialoghelper.h b/src/gui/kernel/qplatformdialoghelper.h
index 25543a70b8..0569a7e2f9 100644
--- a/src/gui/kernel/qplatformdialoghelper.h
+++ b/src/gui/kernel/qplatformdialoghelper.h
@@ -157,7 +157,8 @@ public:
enum ColorDialogOption {
ShowAlphaChannel = 0x00000001,
NoButtons = 0x00000002,
- DontUseNativeDialog = 0x00000004
+ DontUseNativeDialog = 0x00000004,
+ NoEyeDropperButton = 0x00000008
};
Q_DECLARE_FLAGS(ColorDialogOptions, ColorDialogOption)
@@ -403,6 +404,13 @@ protected:
~QMessageDialogOptions();
public:
+ // Keep in sync with QMessageBox Option
+ enum class Option {
+ DontUseNativeDialog = 0x00000001,
+ };
+ Q_DECLARE_FLAGS(Options, Option);
+ Q_FLAG(Options);
+
// Keep in sync with QMessageBox::Icon
enum StandardIcon { NoIcon, Information, Warning, Critical, Question };
Q_ENUM(StandardIcon)
@@ -428,6 +436,11 @@ public:
void setDetailedText(const QString &text);
QString detailedText() const;
+ void setOption(Option option, bool on = true);
+ bool testOption(Option option) const;
+ void setOptions(Options options);
+ Options options() const;
+
void setStandardButtons(QPlatformDialogHelper::StandardButtons buttons);
QPlatformDialogHelper::StandardButtons standardButtons() const;
@@ -446,15 +459,22 @@ public:
};
int addButton(const QString &label, QPlatformDialogHelper::ButtonRole role,
- void *buttonImpl = nullptr);
+ void *buttonImpl = nullptr, int buttonId = 0);
void removeButton(int id);
const QList<CustomButton> &customButtons();
const CustomButton *customButton(int id);
+ void clearCustomButtons();
void setCheckBox(const QString &label, Qt::CheckState state);
QString checkBoxLabel() const;
Qt::CheckState checkBoxState() const;
+ void setEscapeButton(int id);
+ int escapeButton() const;
+
+ void setDefaultButton(int id);
+ int defaultButton() const;
+
private:
QMessageDialogOptionsPrivate *d;
};
diff --git a/src/gui/kernel/qplatformgraphicsbufferhelper.cpp b/src/gui/kernel/qplatformgraphicsbufferhelper.cpp
index 4c2b9e5b39..0ec2308453 100644
--- a/src/gui/kernel/qplatformgraphicsbufferhelper.cpp
+++ b/src/gui/kernel/qplatformgraphicsbufferhelper.cpp
@@ -179,14 +179,14 @@ bool QPlatformGraphicsBufferHelper::bindSWToTexture(const QPlatformGraphicsBuffe
QRect rect = subRect;
if (rect.isNull() || rect == QRect(QPoint(0,0),size)) {
if (needsRowLength)
- funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, image.bytesPerLine() / 4);
+ funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, GLint(image.bytesPerLine() / 4));
funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, size.width(), size.height(), 0, GL_RGBA, pixelType, image.constBits());
if (needsRowLength)
funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
} else {
if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
// OpenGL 2.1+ or OpenGL ES/3+
- funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, image.bytesPerLine() / 4);
+ funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, GLint(image.bytesPerLine() / 4));
funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType,
image.constScanLine(rect.y()) + rect.x() * 4);
funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
diff --git a/src/gui/kernel/qplatforminputcontext.cpp b/src/gui/kernel/qplatforminputcontext.cpp
index 985cefa12c..9d3ee4acb6 100644
--- a/src/gui/kernel/qplatforminputcontext.cpp
+++ b/src/gui/kernel/qplatforminputcontext.cpp
@@ -47,6 +47,11 @@ QT_BEGIN_NAMESPACE
QPlatformInputContext::QPlatformInputContext()
: QObject(*(new QPlatformInputContextPrivate))
{
+ // Delay initialization of cached input direction
+ // until super class has finished constructing.
+ QMetaObject::invokeMethod(this, [this]{
+ m_inputDirection = inputDirection();
+ }, Qt::QueuedConnection);
}
/*!
@@ -192,22 +197,29 @@ void QPlatformInputContext::emitInputPanelVisibleChanged()
QLocale QPlatformInputContext::locale() const
{
- return qt_keymapper_private()->keyboardInputLocale;
+ return QLocale::system();
}
void QPlatformInputContext::emitLocaleChanged()
{
emit QGuiApplication::inputMethod()->localeChanged();
+
+ // Changing the locale might have updated the input direction
+ emitInputDirectionChanged(inputDirection());
}
Qt::LayoutDirection QPlatformInputContext::inputDirection() const
{
- return qt_keymapper_private()->keyboardInputDirection;
+ return locale().textDirection();
}
void QPlatformInputContext::emitInputDirectionChanged(Qt::LayoutDirection newDirection)
{
+ if (newDirection == m_inputDirection)
+ return;
+
emit QGuiApplication::inputMethod()->inputDirectionChanged(newDirection);
+ m_inputDirection = newDirection;
}
/*!
diff --git a/src/gui/kernel/qplatforminputcontext.h b/src/gui/kernel/qplatforminputcontext.h
index 05d7497f9c..481f97a065 100644
--- a/src/gui/kernel/qplatforminputcontext.h
+++ b/src/gui/kernel/qplatforminputcontext.h
@@ -72,6 +72,8 @@ private:
friend class QGuiApplication;
friend class QGuiApplicationPrivate;
friend class QInputMethod;
+
+ Qt::LayoutDirection m_inputDirection;
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatforminputcontextfactory.cpp b/src/gui/kernel/qplatforminputcontextfactory.cpp
index 7074de56af..933d990f7c 100644
--- a/src/gui/kernel/qplatforminputcontextfactory.cpp
+++ b/src/gui/kernel/qplatforminputcontextfactory.cpp
@@ -28,10 +28,33 @@ QStringList QPlatformInputContextFactory::keys()
#endif
}
-QString QPlatformInputContextFactory::requested()
+QStringList QPlatformInputContextFactory::requested()
{
- QByteArray env = qgetenv("QT_IM_MODULE");
- return env.isNull() ? QString() : QString::fromLocal8Bit(env);
+ QStringList imList;
+ QByteArray env = qgetenv("QT_IM_MODULES");
+
+ if (!env.isEmpty())
+ imList = QString::fromLocal8Bit(env).split(QChar::fromLatin1(';'), Qt::SkipEmptyParts);
+
+ if (!imList.isEmpty())
+ return imList;
+
+ env = qgetenv("QT_IM_MODULE");
+ if (!env.isEmpty())
+ imList = {QString::fromLocal8Bit(env)};
+
+ return imList;
+}
+
+QPlatformInputContext *QPlatformInputContextFactory::create(const QStringList& keys)
+{
+ for (const QString &key : keys) {
+ auto plugin = create(key);
+ if (plugin)
+ return plugin;
+ }
+
+ return nullptr;
}
QPlatformInputContext *QPlatformInputContextFactory::create(const QString& key)
diff --git a/src/gui/kernel/qplatforminputcontextfactory_p.h b/src/gui/kernel/qplatforminputcontextfactory_p.h
index 4968a51a8b..5f5881c508 100644
--- a/src/gui/kernel/qplatforminputcontextfactory_p.h
+++ b/src/gui/kernel/qplatforminputcontextfactory_p.h
@@ -27,7 +27,8 @@ class Q_GUI_EXPORT QPlatformInputContextFactory
{
public:
static QStringList keys();
- static QString requested();
+ static QStringList requested();
+ static QPlatformInputContext *create(const QStringList &keys);
static QPlatformInputContext *create(const QString &key);
static QPlatformInputContext *create();
};
diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp
index b7117b121d..130b479c64 100644
--- a/src/gui/kernel/qplatformintegration.cpp
+++ b/src/gui/kernel/qplatformintegration.cpp
@@ -6,6 +6,7 @@
#include <qpa/qplatformfontdatabase.h>
#include <qpa/qplatformclipboard.h>
#include <qpa/qplatformaccessibility.h>
+#include <qpa/qplatformkeymapper.h>
#include <qpa/qplatformtheme.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qpixmap_raster_p.h>
@@ -228,6 +229,11 @@ QPlatformServices *QPlatformIntegration::services() const
\value ScreenWindowGrabbing The platform supports grabbing window on screen.
On Wayland, this capability can be reported as \c false. The default implementation
of hasCapability() returns \c true.
+
+ \value BackingStoreStaticContents The platform backingstore supports static contents.
+ On resize of the backingstore the static contents region is provided, and the backing
+ store is expected to propagate the static content to the resized backing store, without
+ clients needing to repaint the static content region.
*/
/*!
@@ -342,6 +348,21 @@ QPlatformInputContext *QPlatformIntegration::inputContext() const
return nullptr;
}
+/*!
+ Accessor for the platform integration's key mapper.
+
+ Default implementation returns a default QPlatformKeyMapper.
+
+ \sa QPlatformKeyMapper
+*/
+QPlatformKeyMapper *QPlatformIntegration::keyMapper() const
+{
+ static QPlatformKeyMapper *keyMapper = nullptr;
+ if (!keyMapper)
+ keyMapper = new QPlatformKeyMapper;
+ return keyMapper;
+}
+
#if QT_CONFIG(accessibility)
/*!
diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h
index 393845012a..a18ae821c7 100644
--- a/src/gui/kernel/qplatformintegration.h
+++ b/src/gui/kernel/qplatformintegration.h
@@ -33,6 +33,7 @@ class QPlatformOpenGLContext;
class QGuiGLFormat;
class QAbstractEventDispatcher;
class QPlatformInputContext;
+class QPlatformKeyMapper;
class QPlatformAccessibility;
class QPlatformTheme;
class QPlatformDialogHelper;
@@ -98,7 +99,8 @@ public:
MaximizeUsingFullscreenGeometry,
PaintEvents,
RhiBasedRendering,
- ScreenWindowGrabbing // whether QScreen::grabWindow() is supported
+ ScreenWindowGrabbing, // whether QScreen::grabWindow() is supported
+ BackingStoreStaticContents
};
virtual ~QPlatformIntegration() { }
@@ -171,8 +173,12 @@ public:
virtual QVariant styleHint(StyleHint hint) const;
virtual Qt::WindowState defaultWindowState(Qt::WindowFlags) const;
+protected:
virtual Qt::KeyboardModifiers queryKeyboardModifiers() const;
virtual QList<int> possibleKeys(const QKeyEvent *) const;
+ friend class QPlatformKeyMapper;
+public:
+ virtual QPlatformKeyMapper *keyMapper() const;
virtual QStringList themeNames() const;
virtual QPlatformTheme *createPlatformTheme(const QString &name) const;
diff --git a/src/gui/kernel/qplatformkeymapper.cpp b/src/gui/kernel/qplatformkeymapper.cpp
new file mode 100644
index 0000000000..f54e4ff379
--- /dev/null
+++ b/src/gui/kernel/qplatformkeymapper.cpp
@@ -0,0 +1,38 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qplatformkeymapper.h"
+
+#include <private/qguiapplication_p.h>
+#include <qpa/qplatformintegration.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcQpaKeyMapper, "qt.qpa.keymapper")
+
+QPlatformKeyMapper::~QPlatformKeyMapper()
+{
+}
+
+/*
+ Should return a list of possible key combinations for the given key event.
+
+ For example, given a US English keyboard layout, the key event Shift+5
+ can represent both a "Shift+5" key combination, as well as just "%".
+*/
+QList<QKeyCombination> QPlatformKeyMapper::possibleKeyCombinations(const QKeyEvent *event) const
+{
+ auto *platformIntegration = QGuiApplicationPrivate::platformIntegration();
+ QList<int> possibleKeys = platformIntegration->possibleKeys(event);
+ QList<QKeyCombination> combinations;
+ for (int key : possibleKeys)
+ combinations << QKeyCombination::fromCombined(key);
+ return combinations;
+}
+
+Qt::KeyboardModifiers QPlatformKeyMapper::queryKeyboardModifiers() const
+{
+ return QGuiApplicationPrivate::platformIntegration()->queryKeyboardModifiers();
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatformkeymapper.h b/src/gui/kernel/qplatformkeymapper.h
new file mode 100644
index 0000000000..fb5b0cdb8b
--- /dev/null
+++ b/src/gui/kernel/qplatformkeymapper.h
@@ -0,0 +1,36 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QPLATFORMKEYMAPPER_P
+#define QPLATFORMKEYMAPPER_P
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is part of the QPA API and is not meant to be used
+// in applications. Usage of this API may make your code
+// source and binary incompatible with future versions of Qt.
+//
+
+#include <QtGui/qtguiglobal.h>
+#include <QtCore/qloggingcategory.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_EXPORTED_LOGGING_CATEGORY(lcQpaKeyMapper, Q_GUI_EXPORT)
+
+class QKeyEvent;
+
+class Q_GUI_EXPORT QPlatformKeyMapper
+{
+public:
+ virtual ~QPlatformKeyMapper();
+
+ virtual QList<QKeyCombination> possibleKeyCombinations(const QKeyEvent *event) const;
+ virtual Qt::KeyboardModifiers queryKeyboardModifiers() const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPLATFORMKEYMAPPER_P
diff --git a/src/gui/kernel/qplatformscreen.cpp b/src/gui/kernel/qplatformscreen.cpp
index 9e038b4032..0369a0b12a 100644
--- a/src/gui/kernel/qplatformscreen.cpp
+++ b/src/gui/kernel/qplatformscreen.cpp
@@ -25,10 +25,8 @@ QPlatformScreen::QPlatformScreen()
QPlatformScreen::~QPlatformScreen()
{
Q_D(QPlatformScreen);
- if (d->screen) {
- qWarning("Manually deleting a QPlatformScreen. Call QWindowSystemInterface::handleScreenRemoved instead.");
- delete d->screen;
- }
+ Q_ASSERT_X(!d->screen, "QPlatformScreen",
+ "QPlatformScreens should be removed via QWindowSystemInterface::handleScreenRemoved()");
}
/*!
@@ -56,8 +54,9 @@ QPixmap QPlatformScreen::grabWindow(WId window, int x, int y, int width, int hei
QWindow *QPlatformScreen::topLevelAt(const QPoint & pos) const
{
const QWindowList list = QGuiApplication::topLevelWindows();
- for (int i = list.size()-1; i >= 0; --i) {
- QWindow *w = list[i];
+ const auto crend = list.crend();
+ for (auto it = list.crbegin(); it != crend; ++it) {
+ QWindow *w = *it;
if (w->isVisible() && QHighDpi::toNativePixels(w->geometry(), w).contains(pos))
return w;
}
diff --git a/src/gui/kernel/qplatformscreen.h b/src/gui/kernel/qplatformscreen.h
index 3ef5798aa1..a547a635e9 100644
--- a/src/gui/kernel/qplatformscreen.h
+++ b/src/gui/kernel/qplatformscreen.h
@@ -42,6 +42,7 @@ typedef QPair<qreal, qreal> QDpi;
class Q_GUI_EXPORT QPlatformScreen
{
+ Q_GADGET
Q_DECLARE_PRIVATE(QPlatformScreen)
public:
@@ -132,7 +133,7 @@ protected:
QScopedPointer<QPlatformScreenPrivate> d_ptr;
private:
- friend class QScreenPrivate;
+ friend class QScreen;
};
// Qt doesn't currently support running with no platform screen
diff --git a/src/gui/kernel/qplatformscreen_p.h b/src/gui/kernel/qplatformscreen_p.h
index e871fc16c8..345a90845c 100644
--- a/src/gui/kernel/qplatformscreen_p.h
+++ b/src/gui/kernel/qplatformscreen_p.h
@@ -20,14 +20,6 @@
#include <QtCore/qpointer.h>
#include <QtCore/qnativeinterface.h>
-#if defined(Q_OS_WIN32)
-#include <qwindowdefs_win.h>
-#endif
-
-#if defined(Q_OS_UNIX)
-struct wl_output;
-#endif
-
QT_BEGIN_NAMESPACE
class QScreen;
@@ -75,31 +67,6 @@ struct Q_GUI_EXPORT QWebOSScreen
virtual void addFlipListener(void (*callback)()) = 0;
};
#endif
-
-#if defined(Q_OS_WIN32) || defined(Q_QDOC)
-struct Q_GUI_EXPORT QWindowsScreen
-{
- QT_DECLARE_NATIVE_INTERFACE(QWindowsScreen, 1, QScreen)
- virtual HMONITOR handle() const = 0;
-};
-#endif
-
-#if defined(Q_OS_UNIX) || defined(Q_CLANG_QDOC)
-struct Q_GUI_EXPORT QWaylandScreen
-{
- QT_DECLARE_NATIVE_INTERFACE(QWaylandScreen, 1, QScreen)
- virtual wl_output *output() const = 0;
-};
-#endif
-
-#if defined(Q_OS_ANDROID) || defined(Q_QDOC)
-struct Q_GUI_EXPORT QAndroidScreen
-{
- QT_DECLARE_NATIVE_INTERFACE(QAndroidScreen, 1, QScreen)
- virtual int displayId() const = 0;
-};
-#endif
-
} // QNativeInterface::Private
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatformservices.cpp b/src/gui/kernel/qplatformservices.cpp
index 1c8062389d..7ff2a6c2f8 100644
--- a/src/gui/kernel/qplatformservices.cpp
+++ b/src/gui/kernel/qplatformservices.cpp
@@ -75,3 +75,5 @@ bool QPlatformServices::hasCapability(Capability capability) const
}
QT_END_NAMESPACE
+
+#include "moc_qplatformservices.cpp"
diff --git a/src/gui/kernel/qplatformsystemtrayicon.h b/src/gui/kernel/qplatformsystemtrayicon.h
index c2c80f9334..76a7ef03d9 100644
--- a/src/gui/kernel/qplatformsystemtrayicon.h
+++ b/src/gui/kernel/qplatformsystemtrayicon.h
@@ -6,6 +6,7 @@
#define QPLATFORMSYSTEMTRAYICON_H
#include <QtGui/qtguiglobal.h>
+#include <qpa/qplatformscreen.h>
#include "QtCore/qobject.h"
#ifndef QT_NO_SYSTEMTRAYICON
@@ -13,7 +14,6 @@
QT_BEGIN_NAMESPACE
class QPlatformMenu;
-class QPlatformScreen;
class QIcon;
class QString;
class QRect;
@@ -21,7 +21,6 @@ class QRect;
class Q_GUI_EXPORT QPlatformSystemTrayIcon : public QObject
{
Q_OBJECT
- Q_MOC_INCLUDE(<qpa/qplatformscreen.h>)
public:
enum ActivationReason {
Unknown,
diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp
index 6b6eb896ed..48978b849a 100644
--- a/src/gui/kernel/qplatformtheme.cpp
+++ b/src/gui/kernel/qplatformtheme.cpp
@@ -325,7 +325,7 @@ const QKeyBinding QPlatformThemePrivate::keyBindings[] = {
{QKeySequence::InsertLineSeparator, 0, Qt::SHIFT | Qt::Key_Enter, KB_All},
{QKeySequence::InsertLineSeparator, 0, Qt::SHIFT | Qt::Key_Return, KB_All},
{QKeySequence::InsertLineSeparator, 0, Qt::META | Qt::Key_O, KB_Mac},
- {QKeySequence::SaveAs, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_S, KB_Gnome | KB_Mac},
+ {QKeySequence::SaveAs, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_S, KB_All},
{QKeySequence::Preferences, 0, Qt::CTRL | Qt::Key_Comma, KB_Mac},
{QKeySequence::Quit, 0, Qt::CTRL | Qt::Key_Q, KB_X11 | KB_Gnome | KB_KDE | KB_Mac},
{QKeySequence::FullScreen, 1, Qt::META | Qt::CTRL | Qt::Key_F, KB_Mac},
@@ -335,6 +335,7 @@ const QKeyBinding QPlatformThemePrivate::keyBindings[] = {
{QKeySequence::FullScreen, 1, Qt::Key_F11, KB_Win | KB_KDE},
{QKeySequence::Deselect, 0, Qt::CTRL | Qt::SHIFT | Qt::Key_A, KB_X11},
{QKeySequence::DeleteCompleteLine, 0, Qt::CTRL | Qt::Key_U, KB_X11},
+ {QKeySequence::Backspace, 1, Qt::Key_Backspace, KB_Mac},
{QKeySequence::Backspace, 0, Qt::META | Qt::Key_H, KB_Mac},
{QKeySequence::Cancel, 0, Qt::Key_Escape, KB_All},
{QKeySequence::Cancel, 0, Qt::CTRL | Qt::Key_Period, KB_Mac}
@@ -374,6 +375,7 @@ Q_GUI_EXPORT QPalette qt_fusionPalette()
const QColor button = backGround;
const QColor shadow = dark.darker(135);
const QColor disabledShadow = shadow.lighter(150);
+ const QColor disabledHighlight(145, 145, 145);
QColor placeholder = text;
placeholder.setAlpha(128);
@@ -392,7 +394,11 @@ Q_GUI_EXPORT QPalette qt_fusionPalette()
fusionPalette.setBrush(QPalette::Active, QPalette::Highlight, highlight);
fusionPalette.setBrush(QPalette::Inactive, QPalette::Highlight, highlight);
- fusionPalette.setBrush(QPalette::Disabled, QPalette::Highlight, QColor(145, 145, 145));
+ fusionPalette.setBrush(QPalette::Disabled, QPalette::Highlight, disabledHighlight);
+
+ fusionPalette.setBrush(QPalette::Active, QPalette::Accent, highlight);
+ fusionPalette.setBrush(QPalette::Inactive, QPalette::Accent, highlight);
+ fusionPalette.setBrush(QPalette::Disabled, QPalette::Accent, disabledHighlight);
fusionPalette.setBrush(QPalette::PlaceholderText, placeholder);
@@ -632,7 +638,7 @@ QVariant QPlatformTheme::defaultThemeHint(ThemeHint hint)
case FlickMaximumVelocity:
return QVariant(2500);
case FlickDeceleration:
- return QVariant(5000);
+ return QVariant(1500);
case MenuBarFocusOnAltPressRelease:
return false;
case MouseCursorTheme:
diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp
index e2c9fc4141..5c0ae2ee2a 100644
--- a/src/gui/kernel/qplatformwindow.cpp
+++ b/src/gui/kernel/qplatformwindow.cpp
@@ -370,18 +370,18 @@ void QPlatformWindow::setMask(const QRegion &region)
Reimplement to let Qt be able to request activation/focus for a window
Some window systems will probably not have callbacks for this functionality,
- and then calling QWindowSystemInterface::handleWindowActivated(QWindow *w)
+ and then calling QWindowSystemInterface::handleFocusWindowChanged(QWindow *w)
would be sufficient.
If the window system has some event handling/callbacks then call
- QWindowSystemInterface::handleWindowActivated(QWindow *w) when the window system
+ QWindowSystemInterface::handleFocusWindowChanged(QWindow *w) when the window system
gives the notification.
- Default implementation calls QWindowSystem::handleWindowActivated(QWindow *w)
+ Default implementation calls QWindowSystem::handleFocusWindowChanged(QWindow *w)
*/
void QPlatformWindow::requestActivateWindow()
{
- QWindowSystemInterface::handleWindowActivated(window());
+ QWindowSystemInterface::handleFocusWindowChanged(window());
}
/*!
@@ -778,6 +778,15 @@ void QPlatformWindow::deliverUpdateRequest()
QWindow *w = window();
QWindowPrivate *wp = qt_window_private(w);
+
+ // We expect that the platform plugins send DevicePixelRatioChange events.
+ // As a fail-safe make a final check here to make sure the cached DPR value is
+ // always up to date before delivering the update request.
+ if (wp->updateDevicePixelRatio()) {
+ qWarning() << "The cached device pixel ratio value was stale on window update. "
+ << "Please file a QTBUG which explains how to reproduce.";
+ }
+
wp->updateRequestPending = false;
QEvent request(QEvent::UpdateRequest);
QCoreApplication::sendEvent(w, &request);
diff --git a/src/gui/kernel/qplatformwindow_p.h b/src/gui/kernel/qplatformwindow_p.h
index 65b8b4a2c5..2bbdfd5bf9 100644
--- a/src/gui/kernel/qplatformwindow_p.h
+++ b/src/gui/kernel/qplatformwindow_p.h
@@ -19,9 +19,11 @@
#include <QtCore/qbasictimer.h>
#include <QtCore/qrect.h>
#include <QtCore/qnativeinterface.h>
+#include <QtGui/qwindow.h>
-#if defined(Q_OS_UNIX)
+#if QT_CONFIG(wayland)
#include <any>
+#include <QtCore/qobject.h>
struct wl_surface;
#endif
@@ -41,6 +43,15 @@ public:
namespace QNativeInterface::Private {
+#if defined(Q_OS_WASM) || defined(Q_QDOC)
+struct Q_GUI_EXPORT QWasmWindow
+{
+ QT_DECLARE_NATIVE_INTERFACE(QWasmWindow, 1, QWindow)
+ virtual emscripten::val document() const = 0;
+ virtual emscripten::val clientArea() const = 0;
+};
+#endif
+
#if defined(Q_OS_MACOS) || defined(Q_QDOC)
struct Q_GUI_EXPORT QCocoaWindow
{
@@ -95,7 +106,7 @@ struct Q_GUI_EXPORT QWindowsWindow
};
#endif // Q_OS_WIN
-#if defined(Q_OS_UNIX)
+#if QT_CONFIG(wayland)
struct Q_GUI_EXPORT QWaylandWindow : public QObject
{
Q_OBJECT
@@ -115,6 +126,8 @@ public:
Q_SIGNALS:
void surfaceCreated();
void surfaceDestroyed();
+ void surfaceRoleCreated();
+ void surfaceRoleDestroyed();
void xdgActivationTokenCreated(const QString &token);
protected:
diff --git a/src/gui/kernel/qpointingdevice.cpp b/src/gui/kernel/qpointingdevice.cpp
index f890fc1ca8..c4c1e5fd5c 100644
--- a/src/gui/kernel/qpointingdevice.cpp
+++ b/src/gui/kernel/qpointingdevice.cpp
@@ -564,7 +564,7 @@ bool QPointingDevicePrivate::addPassiveGrabber(const QPointerEvent *event, const
bool QPointingDevicePrivate::setPassiveGrabberContext(QPointingDevicePrivate::EventPointData *epd, QObject *grabber, QObject *context)
{
- int i = epd->passiveGrabbers.indexOf(grabber);
+ qsizetype i = epd->passiveGrabbers.indexOf(grabber);
if (i < 0)
return false;
if (epd->passiveGrabbersContext.size() <= i)
@@ -581,7 +581,7 @@ bool QPointingDevicePrivate::removePassiveGrabber(const QPointerEvent *event, co
qWarning() << "point is not in activePoints" << point;
return false;
}
- int i = persistentPoint->passiveGrabbers.indexOf(grabber);
+ qsizetype i = persistentPoint->passiveGrabbers.indexOf(grabber);
if (i >= 0) {
if (Q_UNLIKELY(lcPointerGrab().isDebugEnabled())) {
qCDebug(lcPointerGrab) << name << "point" << point.id() << point.state()
@@ -644,7 +644,7 @@ void QPointingDevicePrivate::removeGrabber(QObject *grabber, bool cancel)
cancel ? QPointingDevice::CancelGrabExclusive : QPointingDevice::UngrabExclusive,
nullptr, epd.eventPoint);
}
- int pi = epd.passiveGrabbers.indexOf(grabber);
+ qsizetype pi = epd.passiveGrabbers.indexOf(grabber);
if (pi >= 0) {
qCDebug(lcPointerGrab) << name << "point" << epd.eventPoint.id() << epd.eventPoint.state()
<< ": removing passive grabber" << grabber;
@@ -708,7 +708,7 @@ QDebug operator<<(QDebug debug, const QPointingDevice *device)
if (device) {
debug << '"' << device->name() << "\" ";
QtDebugUtils::formatQEnum(debug, device->type());
- debug << " id=" << Qt::hex << device->systemId() << Qt::dec;
+ debug << " id=" << device->systemId();
if (!device->seatName().isEmpty())
debug << " seat=" << device->seatName();
if (device->pointerType() != QPointingDevice::PointerType::Generic) {
diff --git a/src/gui/kernel/qpointingdevice_p.h b/src/gui/kernel/qpointingdevice_p.h
index 403a54dc4f..b2f0574e9b 100644
--- a/src/gui/kernel/qpointingdevice_p.h
+++ b/src/gui/kernel/qpointingdevice_p.h
@@ -20,6 +20,8 @@
#include <QtGui/qpointingdevice.h>
#include <QtGui/private/qtguiglobal_p.h>
#include <QtGui/private/qinputdevice_p.h>
+
+#include <QtCore/qpointer.h>
#include <QtCore/private/qflatmap_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/gui/kernel/qrasterwindow.cpp b/src/gui/kernel/qrasterwindow.cpp
index 19d84c601d..f292344ca1 100644
--- a/src/gui/kernel/qrasterwindow.cpp
+++ b/src/gui/kernel/qrasterwindow.cpp
@@ -34,14 +34,20 @@ class QRasterWindowPrivate : public QPaintDeviceWindowPrivate
{
Q_DECLARE_PUBLIC(QRasterWindow)
public:
+ void handleResizeEvent() override
+ {
+ Q_Q(QRasterWindow);
+ if (backingstore->size() != q->size())
+ markWindowAsDirty();
+ }
+
void beginPaint(const QRegion &region) override
{
Q_Q(QRasterWindow);
const QSize size = q->size();
- if (backingstore->size() != size) {
+ if (backingstore->size() != size)
backingstore->resize(size);
- markWindowAsDirty();
- }
+
backingstore->beginPaint(region);
}
@@ -102,6 +108,10 @@ QPaintDevice *QRasterWindow::redirected(QPoint *) const
return d->backingstore->paintDevice();
}
+void QRasterWindow::resizeEvent(QResizeEvent *)
+{
+}
+
QT_END_NAMESPACE
#include "moc_qrasterwindow.cpp"
diff --git a/src/gui/kernel/qrasterwindow.h b/src/gui/kernel/qrasterwindow.h
index 05d71e1655..986bf6b511 100644
--- a/src/gui/kernel/qrasterwindow.h
+++ b/src/gui/kernel/qrasterwindow.h
@@ -23,6 +23,7 @@ public:
protected:
int metric(PaintDeviceMetric metric) const override;
QPaintDevice *redirected(QPoint *) const override;
+ void resizeEvent(QResizeEvent *event) override;
private:
Q_DISABLE_COPY(QRasterWindow)
diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp
index 3932567eae..83641e7676 100644
--- a/src/gui/kernel/qscreen.cpp
+++ b/src/gui/kernel/qscreen.cpp
@@ -37,29 +37,23 @@ QT_BEGIN_NAMESPACE
\inmodule QtGui
*/
-QScreen::QScreen(QPlatformScreen *screen)
+QScreen::QScreen(QPlatformScreen *platformScreen)
: QObject(*new QScreenPrivate(), nullptr)
{
Q_D(QScreen);
- d->setPlatformScreen(screen);
-}
-
-void QScreenPrivate::setPlatformScreen(QPlatformScreen *screen)
-{
- Q_Q(QScreen);
- platformScreen = screen;
- platformScreen->d_func()->screen = q;
- orientation = platformScreen->orientation();
- logicalDpi = QPlatformScreen::overrideDpi(platformScreen->logicalDpi());
+ d->platformScreen = platformScreen;
+ platformScreen->d_func()->screen = this;
- refreshRate = platformScreen->refreshRate();
+ d->orientation = platformScreen->orientation();
+ d->logicalDpi = QPlatformScreen::overrideDpi(platformScreen->logicalDpi());
+ d->refreshRate = platformScreen->refreshRate();
// safeguard ourselves against buggy platform behavior...
- if (refreshRate < 1.0)
- refreshRate = 60.0;
+ if (d->refreshRate < 1.0)
+ d->refreshRate = 60.0;
- updateGeometry();
- updatePrimaryOrientation(); // derived from the geometry
+ d->updateGeometry();
+ d->updatePrimaryOrientation(); // derived from the geometry
}
void QScreenPrivate::updateGeometry()
@@ -72,45 +66,13 @@ void QScreenPrivate::updateGeometry()
/*!
Destroys the screen.
+
+ \internal
*/
QScreen::~QScreen()
{
- // Remove screen
- const bool wasPrimary = QGuiApplication::primaryScreen() == this;
- QGuiApplicationPrivate::screen_list.removeOne(this);
- QGuiApplicationPrivate::resetCachedDevicePixelRatio();
-
- if (!qGuiApp)
- return;
-
- QScreen *newPrimaryScreen = QGuiApplication::primaryScreen();
- if (wasPrimary && newPrimaryScreen)
- emit qGuiApp->primaryScreenChanged(newPrimaryScreen);
-
- // Allow clients to manage windows that are affected by the screen going
- // away, before we fall back to moving them to the primary screen.
- emit qApp->screenRemoved(this);
-
- if (QGuiApplication::closingDown())
- return;
-
- bool movingFromVirtualSibling = newPrimaryScreen
- && newPrimaryScreen->handle()->virtualSiblings().contains(handle());
-
- // Move any leftover windows to the primary screen
- const auto allWindows = QGuiApplication::allWindows();
- for (QWindow *window : allWindows) {
- if (!window->isTopLevel() || window->screen() != this)
- continue;
-
- const bool wasVisible = window->isVisible();
- window->setScreen(newPrimaryScreen);
-
- // Re-show window if moved from a virtual sibling screen. Otherwise
- // leave it up to the application developer to show the window.
- if (movingFromVirtualSibling)
- window->setVisible(wasVisible);
- }
+ Q_ASSERT_X(!QGuiApplicationPrivate::screen_list.contains(this), "QScreen",
+ "QScreens should be removed via QWindowSystemInterface::handleScreenRemoved()");
}
/*!
@@ -398,8 +360,11 @@ QList<QScreen *> QScreen::virtualSiblings() const
const QList<QPlatformScreen *> platformScreens = d->platformScreen->virtualSiblings();
QList<QScreen *> screens;
screens.reserve(platformScreens.size());
- for (QPlatformScreen *platformScreen : platformScreens)
- screens << platformScreen->screen();
+ for (QPlatformScreen *platformScreen : platformScreens) {
+ // Only consider platform screens that have been added
+ if (auto *knownScreen = platformScreen->screen())
+ screens << knownScreen;
+ }
return screens;
}
@@ -496,8 +461,8 @@ Qt::ScreenOrientation QScreen::orientation() const
\property QScreen::refreshRate
\brief the approximate vertical refresh rate of the screen in Hz
- \warning Avoid using the screen's refresh rate to drive animations
- via a timer such as QTimer. Instead use QWindow::requestUpdate().
+ \warning Avoid using the screen's refresh rate to drive animations via a
+ timer such as QChronoTimer. Instead use QWindow::requestUpdate().
\sa QWindow::requestUpdate()
*/
@@ -738,8 +703,23 @@ QPixmap QScreen::grabWindow(WId window, int x, int y, int width, int height)
result.setDevicePixelRatio(result.devicePixelRatio() * factor);
return result;
}
+
+/*!
+ \fn template <typename QNativeInterface> QNativeInterface *QScreen::nativeInterface() const
+
+ Returns a native interface of the given type for the screen.
+
+ This function provides access to platform specific functionality
+ of QScreen, as defined in the QNativeInterface namespace:
+
+ \annotatedlist native-interfaces-qscreen
+
+ If the requested interface is not available a \nullptr is returned.
+ */
+
void *QScreen::resolveInterface(const char *name, int revision) const
{
+ using namespace QNativeInterface;
using namespace QNativeInterface::Private;
auto *platformScreen = handle();
@@ -767,7 +747,7 @@ void *QScreen::resolveInterface(const char *name, int revision) const
QT_NATIVE_INTERFACE_RETURN_IF(QAndroidScreen, platformScreen);
#endif
-#if defined(Q_OS_UNIX)
+#if QT_CONFIG(wayland)
QT_NATIVE_INTERFACE_RETURN_IF(QWaylandScreen, platformScreen);
#endif
diff --git a/src/gui/kernel/qscreen.h b/src/gui/kernel/qscreen.h
index d2fc74fbda..9442e7525b 100644
--- a/src/gui/kernel/qscreen.h
+++ b/src/gui/kernel/qscreen.h
@@ -147,5 +147,7 @@ Q_GUI_EXPORT QDebug operator<<(QDebug, const QScreen *);
QT_END_NAMESPACE
+#include <QtGui/qscreen_platform.h>
+
#endif // QSCREEN_H
diff --git a/src/gui/kernel/qscreen_p.h b/src/gui/kernel/qscreen_p.h
index b9e726a9dc..964bc1cc58 100644
--- a/src/gui/kernel/qscreen_p.h
+++ b/src/gui/kernel/qscreen_p.h
@@ -40,7 +40,6 @@ class QScreenPrivate : public QObjectPrivate, public QScreenData
{
Q_DECLARE_PUBLIC(QScreen)
public:
- void setPlatformScreen(QPlatformScreen *screen);
void updateGeometry();
void updatePrimaryOrientation();
diff --git a/src/gui/kernel/qscreen_platform.h b/src/gui/kernel/qscreen_platform.h
new file mode 100644
index 0000000000..6f40e9273f
--- /dev/null
+++ b/src/gui/kernel/qscreen_platform.h
@@ -0,0 +1,61 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSCREEN_PLATFORM_H
+#define QSCREEN_PLATFORM_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is part of the native interface APIs. Usage of
+// this API may make your code source and binary incompatible
+// with future versions of Qt.
+//
+
+#include <QtGui/qtguiglobal.h>
+
+#include <QtCore/qnativeinterface.h>
+#include <QtGui/qguiapplication.h>
+
+#if defined(Q_OS_WIN32)
+#include <QtGui/qwindowdefs_win.h>
+#endif
+
+#if QT_CONFIG(wayland)
+struct wl_output;
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace QNativeInterface {
+
+#if defined(Q_OS_WIN32) || defined(Q_QDOC)
+struct Q_GUI_EXPORT QWindowsScreen
+{
+ QT_DECLARE_NATIVE_INTERFACE(QWindowsScreen, 1, QScreen)
+ virtual HMONITOR handle() const = 0;
+};
+#endif
+
+#if QT_CONFIG(wayland) || defined(Q_QDOC)
+struct Q_GUI_EXPORT QWaylandScreen
+{
+ QT_DECLARE_NATIVE_INTERFACE(QWaylandScreen, 1, QScreen)
+ virtual wl_output *output() const = 0;
+};
+#endif
+
+#if defined(Q_OS_ANDROID) || defined(Q_QDOC)
+struct Q_GUI_EXPORT QAndroidScreen
+{
+ QT_DECLARE_NATIVE_INTERFACE(QAndroidScreen, 1, QScreen)
+ virtual int displayId() const = 0;
+};
+#endif
+
+} // namespace QNativeInterface
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/gui/kernel/qsessionmanager.cpp b/src/gui/kernel/qsessionmanager.cpp
index 705866f903..0a1ff95656 100644
--- a/src/gui/kernel/qsessionmanager.cpp
+++ b/src/gui/kernel/qsessionmanager.cpp
@@ -281,10 +281,6 @@ void QSessionManager::setRestartCommand(const QStringList &command)
/*!
Returns the currently set restart command.
- To iterate over the list, you can use the \l foreach pseudo-keyword:
-
- \snippet code/src_gui_kernel_qguiapplication.cpp 3
-
\sa setRestartCommand(), restartHint()
*/
QStringList QSessionManager::restartCommand() const
@@ -307,10 +303,6 @@ void QSessionManager::setDiscardCommand(const QStringList &command)
/*!
Returns the currently set discard command.
- To iterate over the list, you can use the \l foreach pseudo-keyword:
-
- \snippet code/src_gui_kernel_qguiapplication.cpp 4
-
\sa setDiscardCommand(), restartCommand(), setRestartCommand()
*/
QStringList QSessionManager::discardCommand() const
diff --git a/src/gui/kernel/qsessionmanager_p.h b/src/gui/kernel/qsessionmanager_p.h
index 60e20b1747..c98f7a5a1d 100644
--- a/src/gui/kernel/qsessionmanager_p.h
+++ b/src/gui/kernel/qsessionmanager_p.h
@@ -27,7 +27,7 @@ QT_BEGIN_NAMESPACE
class QPlatformSessionManager;
-class QSessionManagerPrivate : public QObjectPrivate
+class Q_GUI_EXPORT QSessionManagerPrivate : public QObjectPrivate
{
public:
QSessionManagerPrivate(const QString &id,
diff --git a/src/gui/kernel/qshortcut.cpp b/src/gui/kernel/qshortcut.cpp
index b10d96237e..3f6822cb03 100644
--- a/src/gui/kernel/qshortcut.cpp
+++ b/src/gui/kernel/qshortcut.cpp
@@ -96,7 +96,7 @@ QT_BEGIN_NAMESPACE
\sa activated()
*/
-static bool simpleContextMatcher(QObject *object, Qt::ShortcutContext context)
+bool QShortcutPrivate::simpleContextMatcher(QObject *object, Qt::ShortcutContext context)
{
auto guiShortcut = qobject_cast<QShortcut *>(object);
if (QGuiApplication::applicationState() != Qt::ApplicationActive || guiShortcut == nullptr)
diff --git a/src/gui/kernel/qshortcut_p.h b/src/gui/kernel/qshortcut_p.h
index a99cca27c1..8ff833d477 100644
--- a/src/gui/kernel/qshortcut_p.h
+++ b/src/gui/kernel/qshortcut_p.h
@@ -43,6 +43,8 @@ public:
virtual QShortcutMap::ContextMatcher contextMatcher() const;
virtual bool handleWhatsThis() { return false; }
+ static bool simpleContextMatcher(QObject *object, Qt::ShortcutContext context);
+
QList<QKeySequence> sc_sequences;
QString sc_whatsthis;
Qt::ShortcutContext sc_context = Qt::WindowShortcut;
diff --git a/src/gui/kernel/qshortcutmap.cpp b/src/gui/kernel/qshortcutmap.cpp
index ed03f00542..800e703ac2 100644
--- a/src/gui/kernel/qshortcutmap.cpp
+++ b/src/gui/kernel/qshortcutmap.cpp
@@ -29,23 +29,23 @@ Q_LOGGING_CATEGORY(lcShortcutMap, "qt.gui.shortcutmap")
struct QShortcutEntry
{
QShortcutEntry()
- : keyseq(0), context(Qt::WindowShortcut), enabled(false), autorepeat(1), id(0), owner(nullptr), contextMatcher(nullptr)
+ : keySequence(0), context(Qt::WindowShortcut), enabled(false), autorepeat(1), id(0), owner(nullptr), contextMatcher(nullptr)
{}
QShortcutEntry(const QKeySequence &k)
- : keyseq(k), context(Qt::WindowShortcut), enabled(false), autorepeat(1), id(0), owner(nullptr), contextMatcher(nullptr)
+ : keySequence(k), context(Qt::WindowShortcut), enabled(false), autorepeat(1), id(0), owner(nullptr), contextMatcher(nullptr)
{}
QShortcutEntry(QObject *o, const QKeySequence &k, Qt::ShortcutContext c, int i, bool a, QShortcutMap::ContextMatcher m)
- : keyseq(k), context(c), enabled(true), autorepeat(a), id(i), owner(o), contextMatcher(m)
+ : keySequence(k), context(c), enabled(true), autorepeat(a), id(i), owner(o), contextMatcher(m)
{}
bool correctContext() const { return contextMatcher(owner, context); }
bool operator<(const QShortcutEntry &f) const
- { return keyseq < f.keyseq; }
+ { return keySequence < f.keySequence; }
- QKeySequence keyseq;
+ QKeySequence keySequence;
Qt::ShortcutContext context;
bool enabled : 1;
bool autorepeat : 1;
@@ -88,7 +88,7 @@ public:
}
QShortcutMap *q_ptr; // Private's parent
- QList<QShortcutEntry> sequences; // All sequences!
+ QList<QShortcutEntry> shortcuts; // All shortcuts!
int currentId; // Global shortcut ID number
int ambigCount; // Index of last enabled ambiguous dispatch
@@ -120,18 +120,18 @@ QShortcutMap::~QShortcutMap()
Adds a shortcut to the global map.
Returns the id of the newly added shortcut.
*/
-int QShortcutMap::addShortcut(QObject *owner, const QKeySequence &key, Qt::ShortcutContext context, ContextMatcher matcher)
+int QShortcutMap::addShortcut(QObject *owner, const QKeySequence &keySequence, Qt::ShortcutContext context, ContextMatcher matcher)
{
Q_ASSERT_X(owner, "QShortcutMap::addShortcut", "All shortcuts need an owner");
- Q_ASSERT_X(!key.isEmpty(), "QShortcutMap::addShortcut", "Cannot add keyless shortcuts to map");
+ Q_ASSERT_X(!keySequence.isEmpty(), "QShortcutMap::addShortcut", "Cannot add keyless shortcuts to map");
Q_D(QShortcutMap);
- QShortcutEntry newEntry(owner, key, context, --(d->currentId), true, matcher);
- const auto it = std::upper_bound(d->sequences.begin(), d->sequences.end(), newEntry);
- d->sequences.insert(it, newEntry); // Insert sorted
+ QShortcutEntry newEntry(owner, keySequence, context, --(d->currentId), true, matcher);
+ const auto it = std::upper_bound(d->shortcuts.begin(), d->shortcuts.end(), newEntry);
+ d->shortcuts.insert(it, newEntry); // Insert sorted
qCDebug(lcShortcutMap).nospace()
<< "QShortcutMap::addShortcut(" << owner << ", "
- << key << ", " << context << ") added shortcut with ID " << d->currentId;
+ << keySequence << ", " << context << ") added shortcut with ID " << d->currentId;
return d->currentId;
}
@@ -144,36 +144,36 @@ int QShortcutMap::addShortcut(QObject *owner, const QKeySequence &key, Qt::Short
Returns the number of sequences removed from the map.
*/
-int QShortcutMap::removeShortcut(int id, QObject *owner, const QKeySequence &key)
+int QShortcutMap::removeShortcut(int id, QObject *owner, const QKeySequence &keySequence)
{
Q_D(QShortcutMap);
int itemsRemoved = 0;
bool allOwners = (owner == nullptr);
- bool allKeys = key.isEmpty();
+ bool allKeys = keySequence.isEmpty();
bool allIds = id == 0;
auto debug = qScopeGuard([&](){
qCDebug(lcShortcutMap).nospace()
<< "QShortcutMap::removeShortcut(" << id << ", " << owner << ", "
- << key << ") removed " << itemsRemoved << " shortcuts(s)";
+ << keySequence << ") removed " << itemsRemoved << " shortcuts(s)";
});
// Special case, remove everything
if (allOwners && allKeys && allIds) {
- itemsRemoved = d->sequences.size();
- d->sequences.clear();
+ itemsRemoved = d->shortcuts.size();
+ d->shortcuts.clear();
return itemsRemoved;
}
- int i = d->sequences.size()-1;
+ int i = d->shortcuts.size()-1;
while (i>=0)
{
- const QShortcutEntry &entry = d->sequences.at(i);
+ const QShortcutEntry &entry = d->shortcuts.at(i);
int entryId = entry.id;
if ((allOwners || entry.owner == owner)
&& (allIds || entry.id == id)
- && (allKeys || entry.keyseq == key)) {
- d->sequences.removeAt(i);
+ && (allKeys || entry.keySequence == keySequence)) {
+ d->shortcuts.removeAt(i);
++itemsRemoved;
}
if (id == entryId)
@@ -191,22 +191,22 @@ int QShortcutMap::removeShortcut(int id, QObject *owner, const QKeySequence &key
are changed.
Returns the number of sequences which are matched in the map.
*/
-int QShortcutMap::setShortcutEnabled(bool enable, int id, QObject *owner, const QKeySequence &key)
+int QShortcutMap::setShortcutEnabled(bool enable, int id, QObject *owner, const QKeySequence &keySequence)
{
Q_D(QShortcutMap);
int itemsChanged = 0;
bool allOwners = (owner == nullptr);
- bool allKeys = key.isEmpty();
+ bool allKeys = keySequence.isEmpty();
bool allIds = id == 0;
- int i = d->sequences.size()-1;
+ int i = d->shortcuts.size()-1;
while (i>=0)
{
- QShortcutEntry entry = d->sequences.at(i);
+ QShortcutEntry entry = d->shortcuts.at(i);
if ((allOwners || entry.owner == owner)
&& (allIds || entry.id == id)
- && (allKeys || entry.keyseq == key)) {
- d->sequences[i].enabled = enable;
+ && (allKeys || entry.keySequence == keySequence)) {
+ d->shortcuts[i].enabled = enable;
++itemsChanged;
}
if (id == entry.id)
@@ -215,7 +215,7 @@ int QShortcutMap::setShortcutEnabled(bool enable, int id, QObject *owner, const
}
qCDebug(lcShortcutMap).nospace()
<< "QShortcutMap::setShortcutEnabled(" << enable << ", " << id << ", "
- << owner << ", " << key << ") = " << itemsChanged;
+ << owner << ", " << keySequence << ") = " << itemsChanged;
return itemsChanged;
}
@@ -227,22 +227,22 @@ int QShortcutMap::setShortcutEnabled(bool enable, int id, QObject *owner, const
are changed.
Returns the number of sequences which are matched in the map.
*/
-int QShortcutMap::setShortcutAutoRepeat(bool on, int id, QObject *owner, const QKeySequence &key)
+int QShortcutMap::setShortcutAutoRepeat(bool on, int id, QObject *owner, const QKeySequence &keySequence)
{
Q_D(QShortcutMap);
int itemsChanged = 0;
bool allOwners = (owner == nullptr);
- bool allKeys = key.isEmpty();
+ bool allKeys = keySequence.isEmpty();
bool allIds = id == 0;
- int i = d->sequences.size()-1;
+ int i = d->shortcuts.size()-1;
while (i>=0)
{
- QShortcutEntry entry = d->sequences.at(i);
+ QShortcutEntry entry = d->shortcuts.at(i);
if ((allOwners || entry.owner == owner)
&& (allIds || entry.id == id)
- && (allKeys || entry.keyseq == key)) {
- d->sequences[i].autorepeat = on;
+ && (allKeys || entry.keySequence == keySequence)) {
+ d->shortcuts[i].autorepeat = on;
++itemsChanged;
}
if (id == entry.id)
@@ -251,7 +251,7 @@ int QShortcutMap::setShortcutAutoRepeat(bool on, int id, QObject *owner, const Q
}
qCDebug(lcShortcutMap).nospace()
<< "QShortcutMap::setShortcutAutoRepeat(" << on << ", " << id << ", "
- << owner << ", " << key << ") = " << itemsChanged;
+ << owner << ", " << keySequence << ") = " << itemsChanged;
return itemsChanged;
}
@@ -365,11 +365,12 @@ bool QShortcutMap::hasShortcutForKeySequence(const QKeySequence &seq) const
{
Q_D(const QShortcutMap);
QShortcutEntry entry(seq); // needed for searching
- const auto itEnd = d->sequences.cend();
- auto it = std::lower_bound(d->sequences.cbegin(), itEnd, entry);
+ const auto itEnd = d->shortcuts.cend();
+ auto it = std::lower_bound(d->shortcuts.cbegin(), itEnd, entry);
for (;it != itEnd; ++it) {
- if (matches(entry.keyseq, (*it).keyseq) == QKeySequence::ExactMatch && (*it).correctContext() && (*it).enabled) {
+ if (entry.keySequence.matches(it->keySequence) == QKeySequence::ExactMatch
+ && (*it).correctContext() && (*it).enabled) {
return true;
}
}
@@ -388,11 +389,11 @@ bool QShortcutMap::hasShortcutForKeySequence(const QKeySequence &seq) const
QKeySequence::SequenceMatch QShortcutMap::find(QKeyEvent *e, int ignoredModifiers)
{
Q_D(QShortcutMap);
- if (!d->sequences.size())
+ if (!d->shortcuts.size())
return QKeySequence::NoMatch;
createNewSequences(e, d->newEntries, ignoredModifiers);
- qCDebug(lcShortcutMap) << "Possible shortcut key sequences:" << d->newEntries;
+ qCDebug(lcShortcutMap) << "Possible input sequences:" << d->newEntries;
// Should never happen
if (d->newEntries == d->currentSequences) {
@@ -407,26 +408,33 @@ QKeySequence::SequenceMatch QShortcutMap::find(QKeyEvent *e, int ignoredModifier
bool partialFound = false;
bool identicalDisabledFound = false;
QList<QKeySequence> okEntries;
- int result = QKeySequence::NoMatch;
+ QKeySequence::SequenceMatch result = QKeySequence::NoMatch;
for (int i = d->newEntries.size()-1; i >= 0 ; --i) {
QShortcutEntry entry(d->newEntries.at(i)); // needed for searching
- const auto itEnd = d->sequences.constEnd();
- auto it = std::lower_bound(d->sequences.constBegin(), itEnd, entry);
+ qCDebug(lcShortcutMap) << "Looking for shortcuts matching" << entry.keySequence;
+
+ QKeySequence::SequenceMatch bestMatchForEntry = QKeySequence::NoMatch;
+
+ const auto itEnd = d->shortcuts.constEnd();
+ auto it = std::lower_bound(d->shortcuts.constBegin(), itEnd, entry);
+ for (; it != itEnd; ++it) {
+ QKeySequence::SequenceMatch match = entry.keySequence.matches(it->keySequence);
+ qCDebug(lcShortcutMap) << " -" << match << "for shortcut" << it->keySequence;
- int oneKSResult = QKeySequence::NoMatch;
- int tempRes = QKeySequence::NoMatch;
- do {
- if (it == itEnd)
+ // If we got a valid match, there might still be more keys to check against,
+ // but if we get no match, we know that there are no more possible matches.
+ if (match == QKeySequence::NoMatch)
break;
- tempRes = matches(entry.keyseq, (*it).keyseq);
- oneKSResult = qMax(oneKSResult, tempRes);
- if (tempRes != QKeySequence::NoMatch && (*it).correctContext()) {
- if (tempRes == QKeySequence::ExactMatch) {
+
+ bestMatchForEntry = qMax(bestMatchForEntry, match);
+
+ if ((*it).correctContext()) {
+ if (match == QKeySequence::ExactMatch) {
if ((*it).enabled)
d->identicals.append(&*it);
else
identicalDisabledFound = true;
- } else if (tempRes == QKeySequence::PartialMatch) {
+ } else if (match == QKeySequence::PartialMatch) {
// We don't need partials, if we have identicals
if (d->identicals.size())
break;
@@ -434,20 +442,18 @@ QKeySequence::SequenceMatch QShortcutMap::find(QKeyEvent *e, int ignoredModifier
// key events when all partials are disabled!
partialFound |= (*it).enabled;
}
+ } else {
+ qCDebug(lcShortcutMap) << " - But context was not correct";
}
- ++it;
- // If we got a valid match on this run, there might still be more keys to check against,
- // so we'll loop once more. If we get NoMatch, there's guaranteed no more possible
- // matches in the shortcutmap.
- } while (tempRes != QKeySequence::NoMatch);
+ }
// If the type of match improves (ergo, NoMatch->Partial, or Partial->Exact), clear the
// previous list. If this match is equal or better than the last match, append to the list
- if (oneKSResult > result) {
+ if (bestMatchForEntry > result) {
okEntries.clear();
qCDebug(lcShortcutMap) << "Found better match (" << d->newEntries << "), clearing key sequence list";
}
- if (oneKSResult && oneKSResult >= result) {
+ if (bestMatchForEntry && bestMatchForEntry >= result) {
okEntries << d->newEntries.at(i);
qCDebug(lcShortcutMap) << "Added ok key sequence" << d->newEntries;
}
@@ -466,7 +472,7 @@ QKeySequence::SequenceMatch QShortcutMap::find(QKeyEvent *e, int ignoredModifier
if (result != QKeySequence::NoMatch)
d->currentSequences = okEntries;
qCDebug(lcShortcutMap) << "Returning shortcut match == " << result;
- return QKeySequence::SequenceMatch(result);
+ return result;
}
/*! \internal
@@ -487,7 +493,7 @@ void QShortcutMap::clearSequence(QList<QKeySequence> &ksl)
void QShortcutMap::createNewSequences(QKeyEvent *e, QList<QKeySequence> &ksl, int ignoredModifiers)
{
Q_D(QShortcutMap);
- QList<int> possibleKeys = QKeyMapper::possibleKeys(e);
+ QList<QKeyCombination> possibleKeys = QKeyMapper::possibleKeys(e);
qCDebug(lcShortcutMap) << "Creating new sequences for" << e
<< "with ignoredModifiers=" << Qt::KeyboardModifiers(ignoredModifiers);
int pkTotal = possibleKeys.size();
@@ -516,46 +522,13 @@ void QShortcutMap::createNewSequences(QKeyEvent *e, QList<QKeySequence> &ksl, in
curKsl.setKey(QKeyCombination::fromCombined(0), 2);
curKsl.setKey(QKeyCombination::fromCombined(0), 3);
}
- curKsl.setKey(QKeyCombination::fromCombined(possibleKeys.at(pkNum) & ~ignoredModifiers), index);
+ const int key = possibleKeys.at(pkNum).toCombined();
+ curKsl.setKey(QKeyCombination::fromCombined(key & ~ignoredModifiers), index);
}
}
}
/*! \internal
- Basically the same function as QKeySequence::matches(const QKeySequence &seq) const
- only that is specially handles Key_hyphen as Key_Minus, as people mix these up all the time and
- they conceptually the same.
-*/
-QKeySequence::SequenceMatch QShortcutMap::matches(const QKeySequence &seq1,
- const QKeySequence &seq2) const
-{
- uint userN = seq1.count(),
- seqN = seq2.count();
-
- if (userN > seqN)
- return QKeySequence::NoMatch;
-
- // If equal in length, we have a potential ExactMatch sequence,
- // else we already know it can only be partial.
- QKeySequence::SequenceMatch match = (userN == seqN
- ? QKeySequence::ExactMatch
- : QKeySequence::PartialMatch);
-
- for (uint i = 0; i < userN; ++i) {
- int userKey = seq1[i].toCombined(),
- sequenceKey = seq2[i].toCombined();
- if ((userKey & Qt::Key_unknown) == Qt::Key_hyphen)
- userKey = (userKey & Qt::KeyboardModifierMask) | Qt::Key_Minus;
- if ((sequenceKey & Qt::Key_unknown) == Qt::Key_hyphen)
- sequenceKey = (sequenceKey & Qt::KeyboardModifierMask) | Qt::Key_Minus;
- if (userKey != sequenceKey)
- return QKeySequence::NoMatch;
- }
- return match;
-}
-
-
-/*! \internal
Converts keyboard button states into modifier states
*/
int QShortcutMap::translateModifiers(Qt::KeyboardModifiers modifiers)
@@ -590,7 +563,7 @@ void QShortcutMap::dispatchEvent(QKeyEvent *e)
if (!d->identicals.size())
return;
- const QKeySequence &curKey = d->identicals.at(0)->keyseq;
+ const QKeySequence &curKey = d->identicals.at(0)->keySequence;
if (d->prevSequence != curKey) {
d->ambigCount = 0;
d->prevSequence = curKey;
@@ -621,15 +594,15 @@ void QShortcutMap::dispatchEvent(QKeyEvent *e)
if (ambiguousShortcuts.size() > 1) {
qCDebug(lcShortcutMap) << "The following shortcuts are about to be activated ambiguously:";
for (const QShortcutEntry *entry : std::as_const(ambiguousShortcuts))
- qCDebug(lcShortcutMap).nospace() << "- " << entry->keyseq << " (belonging to " << entry->owner << ")";
+ qCDebug(lcShortcutMap).nospace() << "- " << entry->keySequence << " (belonging to " << entry->owner << ")";
}
qCDebug(lcShortcutMap).nospace()
<< "QShortcutMap::dispatchEvent(): Sending QShortcutEvent(\""
- << next->keyseq.toString() << "\", " << next->id << ", "
+ << next->keySequence.toString() << "\", " << next->id << ", "
<< static_cast<bool>(enabledShortcuts>1) << ") to object(" << next->owner << ')';
}
- QShortcutEvent se(next->keyseq, next->id, enabledShortcuts>1);
+ QShortcutEvent se(next->keySequence, next->id, enabledShortcuts > 1);
QCoreApplication::sendEvent(const_cast<QObject *>(next->owner), &se);
}
@@ -637,7 +610,7 @@ QList<QKeySequence> QShortcutMap::keySequences(bool getAll) const
{
Q_D(const QShortcutMap);
QList<QKeySequence> keys;
- for (auto sequence : d->sequences) {
+ for (auto sequence : d->shortcuts) {
bool addSequence = false;
if (sequence.enabled) {
if (getAll || sequence.context == Qt::ApplicationShortcut ||
@@ -666,7 +639,7 @@ QList<QKeySequence> QShortcutMap::keySequences(bool getAll) const
}
}
if (addSequence)
- keys << sequence.keyseq;
+ keys << sequence.keySequence;
}
}
return keys;
@@ -681,8 +654,8 @@ QList<QKeySequence> QShortcutMap::keySequences(bool getAll) const
void QShortcutMap::dumpMap() const
{
Q_D(const QShortcutMap);
- for (int i = 0; i < d->sequences.size(); ++i)
- qDebug().nospace() << &(d->sequences.at(i));
+ for (int i = 0; i < d->shortcuts.size(); ++i)
+ qDebug().nospace() << &(d->shortcuts.at(i));
}
#endif
diff --git a/src/gui/kernel/qshortcutmap_p.h b/src/gui/kernel/qshortcutmap_p.h
index 194738f0ac..26d2b5301c 100644
--- a/src/gui/kernel/qshortcutmap_p.h
+++ b/src/gui/kernel/qshortcutmap_p.h
@@ -62,7 +62,6 @@ private:
void dispatchEvent(QKeyEvent *e);
QKeySequence::SequenceMatch find(QKeyEvent *e, int ignoredModifiers = 0);
- QKeySequence::SequenceMatch matches(const QKeySequence &seq1, const QKeySequence &seq2) const;
QList<const QShortcutEntry *> matches() const;
void createNewSequences(QKeyEvent *e, QList<QKeySequence> &ksl, int ignoredModifiers);
void clearSequence(QList<QKeySequence> &ksl);
diff --git a/src/gui/kernel/qsimpledrag.cpp b/src/gui/kernel/qsimpledrag.cpp
index 77cbfd2b96..a90e8dd33c 100644
--- a/src/gui/kernel/qsimpledrag.cpp
+++ b/src/gui/kernel/qsimpledrag.cpp
@@ -34,9 +34,10 @@ Q_LOGGING_CATEGORY(lcDnd, "qt.gui.dnd")
static QWindow* topLevelAt(const QPoint &pos)
{
- QWindowList list = QGuiApplication::topLevelWindows();
- for (int i = list.size()-1; i >= 0; --i) {
- QWindow *w = list.at(i);
+ const QWindowList list = QGuiApplication::topLevelWindows();
+ const auto crend = list.crend();
+ for (auto it = list.crbegin(); it != crend; ++it) {
+ QWindow *w = *it;
if (w->isVisible() && w->handle() && w->geometry().contains(pos) && !qobject_cast<QShapedPixmapWindow*>(w))
return w;
}
diff --git a/src/gui/kernel/qstylehints.cpp b/src/gui/kernel/qstylehints.cpp
index 5becae76c6..5029701f24 100644
--- a/src/gui/kernel/qstylehints.cpp
+++ b/src/gui/kernel/qstylehints.cpp
@@ -595,11 +595,15 @@ int QStyleHints::mouseQuickSelectionThreshold() const
/*!
\internal
- QStyleHintsPrivate::setColorScheme - set a new color scheme.
+ QStyleHintsPrivate::updateColorScheme - set a new color scheme.
+
+ This function is called by the QPA plugin when the system theme changes. This in
+ turn might be the result of an explicit request of a color scheme via setColorScheme.
+
Set \a colorScheme as the new color scheme of the QStyleHints.
The colorSchemeChanged signal will be emitted if present and new color scheme differ.
*/
-void QStyleHintsPrivate::setColorScheme(Qt::ColorScheme colorScheme)
+void QStyleHintsPrivate::updateColorScheme(Qt::ColorScheme colorScheme)
{
if (m_colorScheme == colorScheme)
return;
diff --git a/src/gui/kernel/qstylehints_p.h b/src/gui/kernel/qstylehints_p.h
index c58386d7a3..2b3979512a 100644
--- a/src/gui/kernel/qstylehints_p.h
+++ b/src/gui/kernel/qstylehints_p.h
@@ -41,7 +41,7 @@ public:
int m_touchDoubleTapDistance = -1;
Qt::ColorScheme colorScheme() const { return m_colorScheme; }
- void setColorScheme(Qt::ColorScheme colorScheme);
+ void updateColorScheme(Qt::ColorScheme colorScheme);
static QStyleHintsPrivate *get(QStyleHints *q);
diff --git a/src/gui/kernel/qsurfaceformat.cpp b/src/gui/kernel/qsurfaceformat.cpp
index cc2bbea551..74add6e973 100644
--- a/src/gui/kernel/qsurfaceformat.cpp
+++ b/src/gui/kernel/qsurfaceformat.cpp
@@ -765,7 +765,7 @@ Q_GLOBAL_STATIC(QSurfaceFormat, qt_default_surface_format)
question's own setFormat() function. However, it is often more convenient to
set the format for all windows once at the start of the application. It also
guarantees proper behavior in cases where shared contexts are required,
- because settings the format via this function guarantees that all contexts
+ because setting the format via this function guarantees that all contexts
and surfaces, even the ones created internally by Qt, will use the same
format.
diff --git a/src/gui/kernel/qtestsupport_gui.cpp b/src/gui/kernel/qtestsupport_gui.cpp
index ac58ab449c..869eddce49 100644
--- a/src/gui/kernel/qtestsupport_gui.cpp
+++ b/src/gui/kernel/qtestsupport_gui.cpp
@@ -29,7 +29,7 @@ QT_BEGIN_NAMESPACE
\note Since focus is an exclusive property, \a window may loose its focus to another window at
any time - even after the method has returned \c true.
- \sa qWaitForWindowExposed(), QWindow::isActive()
+ \sa qWaitForWindowExposed(), qWaitForWindowFocused(), QWindow::isActive()
*/
Q_GUI_EXPORT bool QTest::qWaitForWindowActive(QWindow *window, int timeout)
{
@@ -45,6 +45,27 @@ Q_GUI_EXPORT bool QTest::qWaitForWindowActive(QWindow *window, int timeout)
}
/*!
+ \since 6.7
+
+ Returns \c true, if \a window is the focus window within \a timeout. Otherwise returns \c false.
+
+ The method is useful in tests that call QWindow::show() and rely on the window
+ having focus (for receiving keyboard events e.g.) before proceeding.
+
+ \note The method will time out and return \c false if another window prevents \a window from
+ becoming focused.
+
+ \note Since focus is an exclusive property, \a window may loose its focus to another window at
+ any time - even after the method has returned \c true.
+
+ \sa qWaitForWindowExposed(), qWaitForWindowActive(), QGuiApplication::focusWindow()
+*/
+Q_GUI_EXPORT bool QTest::qWaitForWindowFocused(QWindow *window, QDeadlineTimer timeout)
+{
+ return QTest::qWaitFor([&]() { return qGuiApp->focusWindow() == window; }, timeout);
+}
+
+/*!
\since 5.0
Returns \c true, if \a window is exposed within \a timeout milliseconds. Otherwise returns \c false.
diff --git a/src/gui/kernel/qtestsupport_gui.h b/src/gui/kernel/qtestsupport_gui.h
index e93fd52018..e5b2a88455 100644
--- a/src/gui/kernel/qtestsupport_gui.h
+++ b/src/gui/kernel/qtestsupport_gui.h
@@ -23,6 +23,7 @@ Q_GUI_EXPORT bool qt_handleTouchEventv2(QWindow *w, const QPointingDevice *devic
namespace QTest {
[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowActive(QWindow *window, int timeout = 5000);
+[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowFocused(QWindow *widget, QDeadlineTimer timeout = std::chrono::seconds{5});
[[nodiscard]] Q_GUI_EXPORT bool qWaitForWindowExposed(QWindow *window, int timeout = 5000);
Q_GUI_EXPORT QPointingDevice * createTouchDevice(QInputDevice::DeviceType devType = QInputDevice::DeviceType::TouchScreen,
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index 39cbf0d734..b40fd7e8e8 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -128,7 +128,7 @@ QWindow::QWindow(QScreen *targetScreen)
, QSurface(QSurface::Window)
{
Q_D(QWindow);
- d->init(targetScreen);
+ d->init(nullptr, targetScreen);
}
static QWindow *nonDesktopParent(QWindow *parent)
@@ -169,11 +169,11 @@ QWindow::QWindow(QWindow *parent)
\sa setParent()
*/
QWindow::QWindow(QWindowPrivate &dd, QWindow *parent)
- : QObject(dd, nonDesktopParent(parent))
+ : QObject(dd, nullptr)
, QSurface(QSurface::Window)
{
Q_D(QWindow);
- d->init();
+ d->init(nonDesktopParent(parent));
}
/*!
@@ -183,6 +183,8 @@ QWindow::~QWindow()
{
Q_D(QWindow);
d->destroy();
+ // Decouple from parent before window goes under
+ setParent(nullptr);
QGuiApplicationPrivate::window_list.removeAll(this);
if (!QGuiApplicationPrivate::is_app_closing)
QGuiApplicationPrivate::instance()->modalWindowList.removeOne(this);
@@ -206,15 +208,19 @@ QWindowPrivate::QWindowPrivate()
QWindowPrivate::~QWindowPrivate()
= default;
-void QWindowPrivate::init(QScreen *targetScreen)
+void QWindowPrivate::init(QWindow *parent, QScreen *targetScreen)
{
Q_Q(QWindow);
+ q->QObject::setParent(parent);
+
isWindow = true;
parentWindow = static_cast<QWindow *>(q->QObject::parent());
+ QScreen *connectScreen = targetScreen ? targetScreen : QGuiApplication::primaryScreen();
+
if (!parentWindow)
- connectToScreen(targetScreen ? targetScreen : QGuiApplication::primaryScreen());
+ connectToScreen(connectScreen);
// If your application aborts here, you are probably creating a QWindow
// before the screen list is populated.
@@ -224,6 +230,27 @@ void QWindowPrivate::init(QScreen *targetScreen)
QGuiApplicationPrivate::window_list.prepend(q);
requestedFormat = QSurfaceFormat::defaultFormat();
+ devicePixelRatio = connectScreen->devicePixelRatio();
+
+ QObject::connect(q, &QWindow::screenChanged, q, [q, this](QScreen *){
+ // We may have changed scaling; trigger resize event if needed,
+ // except on Windows, where we send resize events during WM_DPICHANGED
+ // event handling. FIXME: unify DPI change handling across all platforms.
+#ifndef Q_OS_WIN
+ if (q->handle()) {
+ QWindowSystemInterfacePrivate::GeometryChangeEvent gce(q, QHighDpi::fromNativePixels(q->handle()->geometry(), q));
+ QGuiApplicationPrivate::processGeometryChangeEvent(&gce);
+ }
+#else
+ Q_UNUSED(q);
+#endif
+ updateDevicePixelRatio();
+ });
+
+ if (parentWindow) {
+ QChildWindowEvent childAddedEvent(QEvent::ChildWindowAdded, q);
+ QCoreApplication::sendEvent(parentWindow, &childAddedEvent);
+ }
}
/*!
@@ -428,14 +455,14 @@ void QWindowPrivate::updateSiblingPosition(SiblingPosition position)
QObjectList &siblings = q->parent()->d_ptr->children;
- const int siblingCount = siblings.size() - 1;
+ const qsizetype siblingCount = siblings.size() - 1;
if (siblingCount == 0)
return;
- const int currentPosition = siblings.indexOf(q);
+ const qsizetype currentPosition = siblings.indexOf(q);
Q_ASSERT(currentPosition >= 0);
- const int targetPosition = position == PositionTop ? siblingCount : 0;
+ const qsizetype targetPosition = position == PositionTop ? siblingCount : 0;
if (currentPosition == targetPosition)
return;
@@ -494,7 +521,9 @@ void QWindowPrivate::setTopLevelScreen(QScreen *newScreen, bool recreate)
}
}
-void QWindowPrivate::create(bool recursive, WId nativeHandle)
+static constexpr auto kForeignWindowId = "_q_foreignWinId";
+
+void QWindowPrivate::create(bool recursive)
{
Q_Q(QWindow);
if (platformWindow)
@@ -505,11 +534,16 @@ void QWindowPrivate::create(bool recursive, WId nativeHandle)
// the platformWindow, if there was one, is now gone, so make this flag reflect reality now
updateRequestPending = false;
- const qreal currentDevicePixelRatio = q->devicePixelRatio();
-
if (q->parent())
q->parent()->create();
+ if (platformWindow) {
+ // Creating the parent window will end up creating any child window
+ // that was already visible, via setVisible. If this applies to us,
+ // we will already have a platform window at this point.
+ return;
+ }
+
// QPlatformWindow will poll geometry() during construction below. Set the
// screen here so that high-dpi scaling will use the correct scale factor.
if (q->isTopLevel()) {
@@ -517,6 +551,8 @@ void QWindowPrivate::create(bool recursive, WId nativeHandle)
setTopLevelScreen(screen, false);
}
+ const WId nativeHandle = q->property(kForeignWindowId).value<WId>();
+
QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
platformWindow = nativeHandle ? platformIntegration->createForeignWindow(q, nativeHandle)
: platformIntegration->createPlatformWindow(q);
@@ -552,10 +588,7 @@ void QWindowPrivate::create(bool recursive, WId nativeHandle)
QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceCreated);
QGuiApplication::sendEvent(q, &e);
- if (!qFuzzyCompare(currentDevicePixelRatio, q->devicePixelRatio())) {
- QEvent dprChangeEvent(QEvent::DevicePixelRatioChange);
- QGuiApplication::sendEvent(q, &dprChangeEvent);
- }
+ updateDevicePixelRatio();
if (needsUpdate)
q->requestUpdate();
@@ -599,7 +632,9 @@ void QWindowPrivate::setMinOrMaxSize(QSize *oldSizeMember, const QSize &size,
// resize window if current size is outside of min and max limits
if (minimumSize.width() <= maximumSize.width()
|| minimumSize.height() <= maximumSize.height()) {
- q->resize(q->geometry().size().expandedTo(minimumSize).boundedTo(maximumSize));
+ const QSize currentSize = q->size();
+ const QSize boundedSize = currentSize.expandedTo(minimumSize).boundedTo(maximumSize);
+ q->resize(boundedSize);
}
}
@@ -689,6 +724,7 @@ void QWindow::create()
Returns the window's platform id.
\note This function will cause the platform window to be created if it is not already.
+ Returns 0, if the platform window creation failed.
For platforms where this id might be useful, the value returned
will uniquely represent the window inside the corresponding screen.
@@ -702,6 +738,9 @@ WId QWindow::winId() const
if (!d->platformWindow)
const_cast<QWindow *>(this)->create();
+ if (!d->platformWindow)
+ return 0;
+
return d->platformWindow->winId();
}
@@ -745,6 +784,10 @@ void QWindow::setParent(QWindow *parent)
return;
}
+ QEvent parentAboutToChangeEvent(QEvent::ParentWindowAboutToChange);
+ QCoreApplication::sendEvent(this, &parentAboutToChangeEvent);
+
+ const auto previousParent = d->parentWindow;
QObject::setParent(parent);
d->parentWindow = parent;
@@ -767,6 +810,19 @@ void QWindow::setParent(QWindow *parent)
}
QGuiApplicationPrivate::updateBlockedStatus(this);
+
+ if (previousParent) {
+ QChildWindowEvent childRemovedEvent(QEvent::ChildWindowRemoved, this);
+ QCoreApplication::sendEvent(previousParent, &childRemovedEvent);
+ }
+
+ if (parent) {
+ QChildWindowEvent childAddedEvent(QEvent::ChildWindowAdded, this);
+ QCoreApplication::sendEvent(parent, &childAddedEvent);
+ }
+
+ QEvent parentChangedEvent(QEvent::ParentWindowChange);
+ QCoreApplication::sendEvent(this, &parentChangedEvent);
}
/*!
@@ -1258,6 +1314,8 @@ bool QWindow::isExposed() const
Typically active windows should appear active from a style perspective.
To get the window that currently has focus, use QGuiApplication::focusWindow().
+
+ \sa requestActivate()
*/
bool QWindow::isActive() const
{
@@ -1331,14 +1389,31 @@ Qt::ScreenOrientation QWindow::contentOrientation() const
qreal QWindow::devicePixelRatio() const
{
Q_D(const QWindow);
+ return d->devicePixelRatio;
+}
+
+/*
+ Updates the cached devicePixelRatio value by polling for a new value.
+ Sends QEvent::DevicePixelRatioChange to the window if the DPR has changed.
+ Returns true if the DPR was changed.
+*/
+bool QWindowPrivate::updateDevicePixelRatio()
+{
+ Q_Q(QWindow);
// If there is no platform window use the associated screen's devicePixelRatio,
// which typically is the primary screen and will be correct for single-display
// systems (a very common case).
- if (!d->platformWindow)
- return screen()->devicePixelRatio();
+ const qreal newDevicePixelRatio = platformWindow ?
+ platformWindow->devicePixelRatio() * QHighDpiScaling::factor(q) : q->screen()->devicePixelRatio();
+
+ if (newDevicePixelRatio == devicePixelRatio)
+ return false;
- return d->platformWindow->devicePixelRatio() * QHighDpiScaling::factor(this);
+ devicePixelRatio = newDevicePixelRatio;
+ QEvent dprChangeEvent(QEvent::DevicePixelRatioChange);
+ QGuiApplication::sendEvent(q, &dprChangeEvent);
+ return true;
}
Qt::WindowState QWindowPrivate::effectiveState(Qt::WindowStates state)
@@ -1609,20 +1684,18 @@ void QWindow::setY(int arg)
\property QWindow::width
\brief the width of the window's geometry
*/
-void QWindow::setWidth(int arg)
+void QWindow::setWidth(int w)
{
- if (width() != arg)
- resize(arg, height());
+ resize(w, height());
}
/*!
\property QWindow::height
\brief the height of the window's geometry
*/
-void QWindow::setHeight(int arg)
+void QWindow::setHeight(int h)
{
- if (height() != arg)
- resize(width(), arg);
+ resize(width(), h);
}
/*!
@@ -1944,12 +2017,16 @@ void QWindow::resize(int w, int h)
void QWindow::resize(const QSize &newSize)
{
Q_D(QWindow);
+
+ const QSize oldSize = size();
+ if (newSize == oldSize)
+ return;
+
d->positionPolicy = QWindowPrivate::WindowFrameExclusive;
if (d->platformWindow) {
d->platformWindow->setGeometry(
QHighDpi::toNativeWindowGeometry(QRect(position(), newSize), this));
} else {
- const QSize oldSize = d->geometry.size();
d->geometry.setSize(newSize);
if (newSize.width() != oldSize.width())
emit widthChanged(newSize.width());
@@ -1986,6 +2063,16 @@ void QWindowPrivate::destroy()
QObject *object = childrenWindows.at(i);
if (object->isWindowType()) {
QWindow *w = static_cast<QWindow*>(object);
+ auto *childPlatformWindow = w->handle();
+ if (!childPlatformWindow)
+ continue;
+
+ // Decouple the foreign window from this window,
+ // so that destroying our native handle doesn't
+ // bring down the foreign window as well.
+ if (childPlatformWindow->isForeignWindow())
+ childPlatformWindow->setParent(nullptr);
+
qt_window_private(w)->destroy();
}
}
@@ -2158,20 +2245,26 @@ QObject *QWindow::focusObject() const
/*!
Shows the window.
- This is equivalent to calling showFullScreen(), showMaximized(), or showNormal(),
+ For child windows, this is equivalent to calling showNormal().
+ Otherwise, it is equivalent to calling showFullScreen(), showMaximized(), or showNormal(),
depending on the platform's default behavior for the window type and flags.
\sa showFullScreen(), showMaximized(), showNormal(), hide(), QStyleHints::showIsFullScreen(), flags()
*/
void QWindow::show()
{
- Qt::WindowState defaultState = QGuiApplicationPrivate::platformIntegration()->defaultWindowState(d_func()->windowFlags);
- if (defaultState == Qt::WindowFullScreen)
- showFullScreen();
- else if (defaultState == Qt::WindowMaximized)
- showMaximized();
- else
+ if (parent()) {
showNormal();
+ } else {
+ const auto *platformIntegration = QGuiApplicationPrivate::platformIntegration();
+ Qt::WindowState defaultState = platformIntegration->defaultWindowState(d_func()->windowFlags);
+ if (defaultState == Qt::WindowFullScreen)
+ showFullScreen();
+ else if (defaultState == Qt::WindowMaximized)
+ showMaximized();
+ else
+ showNormal();
+ }
}
/*!
@@ -2777,7 +2870,12 @@ QPointF QWindow::mapToGlobal(const QPointF &pos) const
// Map the position (and the window's global position) to native coordinates, perform
// the addition, and then map back to device independent coordinates.
QPointF nativeLocalPos = QHighDpi::toNativeLocalPosition(pos, this);
- QPointF nativeWindowGlobalPos = QHighDpi::toNativeGlobalPosition(QPointF(d->globalPosition()), this);
+ // Get the native window position directly from the platform window
+ // if available (it can be null if the window hasn't been shown yet),
+ // or fall back to scaling the QWindow position.
+ QPointF nativeWindowGlobalPos = d->platformWindow
+ ? d->platformWindow->mapToGlobal(QPoint(0,0)).toPointF()
+ : QHighDpi::toNativeGlobalPosition(QPointF(d->globalPosition()), this);
QPointF nativeGlobalPos = nativeLocalPos + nativeWindowGlobalPos;
QPointF deviceIndependentGlobalPos = QHighDpi::fromNativeGlobalPosition(nativeGlobalPos, this);
return deviceIndependentGlobalPos;
@@ -2815,7 +2913,12 @@ QPointF QWindow::mapFromGlobal(const QPointF &pos) const
// Calculate local position in the native coordinate system. (See comment for the
// corresponding mapToGlobal() code above).
QPointF nativeGlobalPos = QHighDpi::toNativeGlobalPosition(pos, this);
- QPointF nativeWindowGlobalPos = QHighDpi::toNativeGlobalPosition(QPointF(d->globalPosition()), this);
+ // Get the native window position directly from the platform window
+ // if available (it can be null if the window hasn't been shown yet),
+ // or fall back to scaling the QWindow position.
+ QPointF nativeWindowGlobalPos = d->platformWindow
+ ? d->platformWindow->mapToGlobal(QPoint(0,0)).toPointF()
+ : QHighDpi::toNativeGlobalPosition(QPointF(d->globalPosition()), this);
QPointF nativeLocalPos = nativeGlobalPos - nativeWindowGlobalPos;
QPointF deviceIndependentLocalPos = QHighDpi::fromNativeLocalPosition(nativeLocalPos, this);
return deviceIndependentLocalPos;
@@ -2897,7 +3000,11 @@ QWindow *QWindow::fromWinId(WId id)
}
QWindow *window = new QWindow;
- qt_window_private(window)->create(false, id);
+
+ // Persist the winId in a private property so that we
+ // can recreate the window after being destroyed.
+ window->setProperty(kForeignWindowId, id);
+ window->create();
if (!window->handle()) {
delete window;
@@ -3046,10 +3153,14 @@ void *QWindow::resolveInterface(const char *name, int revision) const
QT_NATIVE_INTERFACE_RETURN_IF(QCocoaWindow, platformWindow);
#endif
-#if defined(Q_OS_UNIX)
+#if QT_CONFIG(wayland)
QT_NATIVE_INTERFACE_RETURN_IF(QWaylandWindow, platformWindow);
#endif
+#if defined(Q_OS_WASM)
+ QT_NATIVE_INTERFACE_RETURN_IF(QWasmWindow, platformWindow);
+#endif
+
return nullptr;
}
diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h
index ef633d093a..f6c8aee9f6 100644
--- a/src/gui/kernel/qwindow_p.h
+++ b/src/gui/kernel/qwindow_p.h
@@ -26,6 +26,8 @@
#include <QtGui/qicon.h>
#include <QtGui/qpalette.h>
+#include <QtCore/qpointer.h>
+
QT_BEGIN_NAMESPACE
class Q_GUI_EXPORT QWindowPrivate : public QObjectPrivate
@@ -42,7 +44,7 @@ public:
QWindowPrivate();
~QWindowPrivate() override;
- void init(QScreen *targetScreen = nullptr);
+ void init(QWindow *parent, QScreen *targetScreen = nullptr);
#ifndef QT_NO_CURSOR
void setCursor(const QCursor *c = nullptr);
@@ -64,7 +66,7 @@ public:
void updateSiblingPosition(SiblingPosition);
bool windowRecreationRequired(QScreen *newScreen) const;
- void create(bool recursive, WId nativeHandle = 0);
+ void create(bool recursive);
void destroy();
void setTopLevelScreen(QScreen *newScreen, bool recreate);
void connectToScreen(QScreen *topLevelScreen);
@@ -74,6 +76,16 @@ public:
void setTransientParent(QWindow *parent);
virtual void clearFocusObject();
+
+ enum class FocusTarget {
+ First,
+ Last,
+ Current,
+ Next,
+ Prev
+ };
+ virtual void setFocusToTarget(QWindowPrivate::FocusTarget) {}
+
virtual QRectF closestAcceptableGeometry(const QRectF &rect) const;
void setMinOrMaxSize(QSize *oldSizeMember, const QSize &size,
@@ -89,6 +101,8 @@ public:
void setAutomaticPositionAndResizeEnabled(bool a)
{ positionAutomatic = resizeAutomatic = a; }
+ bool updateDevicePixelRatio();
+
static QWindowPrivate *get(QWindow *window) { return window->d_func(); }
static Qt::WindowState effectiveState(Qt::WindowStates);
@@ -106,6 +120,7 @@ public:
QString windowFilePath;
QIcon windowIcon;
QRect geometry;
+ qreal devicePixelRatio = 1.0;
Qt::WindowStates windowState = Qt::WindowNoState;
QWindow::Visibility visibility = QWindow::Hidden;
bool resizeEventPending = true;
@@ -140,7 +155,6 @@ public:
bool hasCursor = false;
#endif
- bool compositing = false;
QElapsedTimer lastComposeTime;
#if QT_CONFIG(vulkan)
diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp
index 00343fef66..1875594300 100644
--- a/src/gui/kernel/qwindowsysteminterface.cpp
+++ b/src/gui/kernel/qwindowsysteminterface.cpp
@@ -138,7 +138,7 @@ static bool handleWindowSystemEvent(Args ...args)
return QWindowSystemHelper<Delivery>::template handleEvent<EventType>(args...);
}
-int QWindowSystemInterfacePrivate::windowSystemEventsQueued()
+qsizetype QWindowSystemInterfacePrivate::windowSystemEventsQueued()
{
return windowSystemEventQueue.count();
}
@@ -240,9 +240,9 @@ void QWindowSystemInterface::handleEnterLeaveEvent(QWindow *enter, QWindow *leav
handleEnterEvent(enter, local, global);
}
-QT_DEFINE_QPA_EVENT_HANDLER(void, handleWindowActivated, QWindow *window, Qt::FocusReason r)
+QT_DEFINE_QPA_EVENT_HANDLER(void, handleFocusWindowChanged, QWindow *window, Qt::FocusReason r)
{
- handleWindowSystemEvent<QWindowSystemInterfacePrivate::ActivatedWindowEvent, Delivery>(window, r);
+ handleWindowSystemEvent<QWindowSystemInterfacePrivate::FocusWindowEvent, Delivery>(window, r);
}
QT_DEFINE_QPA_EVENT_HANDLER(void, handleWindowStateChanged, QWindow *window, Qt::WindowStates newState, int oldState)
@@ -389,61 +389,34 @@ QT_DEFINE_QPA_EVENT_HANDLER(bool, handleMouseEvent, QWindow *window, ulong times
Qt::MouseButton button, QEvent::Type type, Qt::KeyboardModifiers mods,
Qt::MouseEventSource source)
{
- Q_ASSERT_X(type != QEvent::MouseButtonDblClick && type != QEvent::NonClientAreaMouseButtonDblClick,
- "QWindowSystemInterface::handleMouseEvent",
- "QTBUG-71263: Native double clicks are not implemented.");
- auto localPos = QHighDpi::fromNativeLocalPosition(local, window);
- auto globalPos = QHighDpi::fromNativeGlobalPosition(global, window);
-
- return handleWindowSystemEvent<QWindowSystemInterfacePrivate::MouseEvent, Delivery>(window,
- timestamp, localPos, globalPos, state, mods, button, type, source, false, device);
-}
-bool QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *window,
- const QPointF &local, const QPointF &global,
- Qt::MouseButtons state,
- Qt::MouseButton button, QEvent::Type type,
- Qt::KeyboardModifiers mods,
- Qt::MouseEventSource source)
-{
- const unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
- return handleFrameStrutMouseEvent(window, time, local, global, state, button, type, mods, source);
-}
+ bool isNonClientArea = {};
-bool QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *window, const QPointingDevice *device,
- const QPointF &local, const QPointF &global,
- Qt::MouseButtons state,
- Qt::MouseButton button, QEvent::Type type,
- Qt::KeyboardModifiers mods,
- Qt::MouseEventSource source)
-{
- const unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
- return handleFrameStrutMouseEvent(window, time, device, local, global, state, button, type, mods, source);
-}
-
-bool QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *window, ulong timestamp,
- const QPointF &local, const QPointF &global,
- Qt::MouseButtons state,
- Qt::MouseButton button, QEvent::Type type,
- Qt::KeyboardModifiers mods,
- Qt::MouseEventSource source)
-{
- return handleFrameStrutMouseEvent(window, timestamp, QPointingDevice::primaryPointingDevice(),
- local, global, state, button, type, mods, source);
-}
+ switch (type) {
+ case QEvent::MouseButtonDblClick:
+ case QEvent::NonClientAreaMouseButtonDblClick:
+ Q_ASSERT_X(false, "QWindowSystemInterface::handleMouseEvent",
+ "QTBUG-71263: Native double clicks are not implemented.");
+ return false;
+ case QEvent::MouseMove:
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ isNonClientArea = false;
+ break;
+ case QEvent::NonClientAreaMouseMove:
+ case QEvent::NonClientAreaMouseButtonPress:
+ case QEvent::NonClientAreaMouseButtonRelease:
+ isNonClientArea = true;
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
-bool QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *window, ulong timestamp, const QPointingDevice *device,
- const QPointF &local, const QPointF &global,
- Qt::MouseButtons state,
- Qt::MouseButton button, QEvent::Type type,
- Qt::KeyboardModifiers mods,
- Qt::MouseEventSource source)
-{
auto localPos = QHighDpi::fromNativeLocalPosition(local, window);
auto globalPos = QHighDpi::fromNativeGlobalPosition(global, window);
- return handleWindowSystemEvent<QWindowSystemInterfacePrivate::MouseEvent>(window,
- timestamp, localPos, globalPos, state, mods, button, type, source, true, device);
+ return handleWindowSystemEvent<QWindowSystemInterfacePrivate::MouseEvent, Delivery>(window,
+ timestamp, localPos, globalPos, state, mods, button, type, source, isNonClientArea, device);
}
bool QWindowSystemInterface::handleShortcutEvent(QWindow *window, ulong timestamp, int keyCode, Qt::KeyboardModifiers modifiers, quint32 nativeScanCode,
@@ -738,9 +711,9 @@ QT_DEFINE_QPA_EVENT_HANDLER(bool, handleTouchCancelEvent, QWindow *window, ulong
The screen should be deleted by calling QWindowSystemInterface::handleScreenRemoved().
*/
-void QWindowSystemInterface::handleScreenAdded(QPlatformScreen *ps, bool isPrimary)
+void QWindowSystemInterface::handleScreenAdded(QPlatformScreen *platformScreen, bool isPrimary)
{
- QScreen *screen = new QScreen(ps);
+ QScreen *screen = new QScreen(platformScreen);
if (isPrimary)
QGuiApplicationPrivate::screen_list.prepend(screen);
@@ -767,9 +740,45 @@ void QWindowSystemInterface::handleScreenAdded(QPlatformScreen *ps, bool isPrima
*/
void QWindowSystemInterface::handleScreenRemoved(QPlatformScreen *platformScreen)
{
- // Important to keep this order since the QSceen doesn't own the platform screen.
- // The QScreen destructor will take care changing the primary screen, so no need here.
- delete platformScreen->screen();
+ QScreen *screen = platformScreen->screen();
+
+ // Remove screen
+ const bool wasPrimary = QGuiApplication::primaryScreen() == screen;
+ QGuiApplicationPrivate::screen_list.removeOne(screen);
+ QGuiApplicationPrivate::resetCachedDevicePixelRatio();
+
+ if (qGuiApp) {
+ QScreen *newPrimaryScreen = QGuiApplication::primaryScreen();
+ if (wasPrimary && newPrimaryScreen)
+ emit qGuiApp->primaryScreenChanged(newPrimaryScreen);
+
+ // Allow clients to manage windows that are affected by the screen going
+ // away, before we fall back to moving them to the primary screen.
+ emit qApp->screenRemoved(screen);
+
+ if (!QGuiApplication::closingDown()) {
+ bool movingFromVirtualSibling = newPrimaryScreen
+ && newPrimaryScreen->handle()->virtualSiblings().contains(platformScreen);
+
+ // Move any leftover windows to the primary screen
+ const auto allWindows = QGuiApplication::allWindows();
+ for (QWindow *window : allWindows) {
+ if (!window->isTopLevel() || window->screen() != screen)
+ continue;
+
+ const bool wasVisible = window->isVisible();
+ window->setScreen(newPrimaryScreen);
+
+ // Re-show window if moved from a virtual sibling screen. Otherwise
+ // leave it up to the application developer to show the window.
+ if (movingFromVirtualSibling)
+ window->setVisible(wasVisible);
+ }
+ }
+ }
+
+ // Important to keep this order since the QSceen doesn't own the platform screen
+ delete screen;
delete platformScreen;
}
@@ -782,7 +791,7 @@ void QWindowSystemInterface::handleScreenRemoved(QPlatformScreen *platformScreen
void QWindowSystemInterface::handlePrimaryScreenChanged(QPlatformScreen *newPrimary)
{
QScreen *newPrimaryScreen = newPrimary->screen();
- int indexOfScreen = QGuiApplicationPrivate::screen_list.indexOf(newPrimaryScreen);
+ qsizetype indexOfScreen = QGuiApplicationPrivate::screen_list.indexOf(newPrimaryScreen);
Q_ASSERT(indexOfScreen >= 0);
if (indexOfScreen == 0)
return;
@@ -805,6 +814,11 @@ void QWindowSystemInterface::handleScreenGeometryChange(QScreen *screen, const Q
void QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(QScreen *screen, qreal dpiX, qreal dpiY)
{
+ // Keep QHighDpiScaling::m_active in sync with platform screen state, in
+ // order to make scaling calls made during DPI change use the new state.
+ // FIXME: Remove when QHighDpiScaling::m_active has been removed.
+ QHighDpiScaling::updateHighDpiScaling();
+
const QDpi effectiveDpi = QPlatformScreen::overrideDpi(QDpi{dpiX, dpiY});
handleWindowSystemEvent<QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent>(screen,
effectiveDpi.first, effectiveDpi.second);
@@ -1049,7 +1063,7 @@ Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QWindowSystemInterface::TouchPo
*/
bool QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
{
- const int count = QWindowSystemInterfacePrivate::windowSystemEventQueue.count();
+ const qsizetype count = QWindowSystemInterfacePrivate::windowSystemEventQueue.count();
if (!count)
return false;
if (!QGuiApplication::instance()) {
@@ -1196,6 +1210,13 @@ Q_GUI_EXPORT bool qt_sendShortcutOverrideEvent(QObject *o, ulong timestamp, int
#endif
}
+Q_GUI_EXPORT void qt_handleWheelEvent(QWindow *window, const QPointF &local, const QPointF &global,
+ QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods,
+ Qt::ScrollPhase phase)
+{
+ QWindowSystemInterface::handleWheelEvent(window, local, global, pixelDelta, angleDelta, mods, phase);
+}
+
namespace QTest
{
Q_GUI_EXPORT QPointingDevice * createTouchDevice(QInputDevice::DeviceType devType,
diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h
index 37b06b0b04..4fc61a475d 100644
--- a/src/gui/kernel/qwindowsysteminterface.h
+++ b/src/gui/kernel/qwindowsysteminterface.h
@@ -64,31 +64,6 @@ public:
Qt::KeyboardModifiers mods = Qt::NoModifier,
Qt::MouseEventSource source = Qt::MouseEventNotSynthesized);
- static bool handleFrameStrutMouseEvent(QWindow *window, const QPointF &local,
- const QPointF &global, Qt::MouseButtons state,
- Qt::MouseButton button, QEvent::Type type,
- Qt::KeyboardModifiers mods = Qt::NoModifier,
- Qt::MouseEventSource source =
- Qt::MouseEventNotSynthesized);
- static bool handleFrameStrutMouseEvent(QWindow *window, const QPointingDevice *device,
- const QPointF &local, const QPointF &global,
- Qt::MouseButtons state,
- Qt::MouseButton button, QEvent::Type type,
- Qt::KeyboardModifiers mods = Qt::NoModifier,
- Qt::MouseEventSource source =
- Qt::MouseEventNotSynthesized);
- static bool handleFrameStrutMouseEvent(QWindow *window, ulong timestamp, const QPointF &local,
- const QPointF &global, Qt::MouseButtons state,
- Qt::MouseButton button, QEvent::Type type,
- Qt::KeyboardModifiers mods = Qt::NoModifier,
- Qt::MouseEventSource source =
- Qt::MouseEventNotSynthesized);
- static bool handleFrameStrutMouseEvent(QWindow *window, ulong timestamp, const QPointingDevice *device,
- const QPointF &local, const QPointF &global, Qt::MouseButtons state,
- Qt::MouseButton button, QEvent::Type type,
- Qt::KeyboardModifiers mods = Qt::NoModifier,
- Qt::MouseEventSource source = Qt::MouseEventNotSynthesized);
-
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);
@@ -182,8 +157,9 @@ public:
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
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 *window, Qt::FocusReason r = Qt::OtherFocusReason);
+ static void handleFocusWindowChanged(QWindow *window, Qt::FocusReason r = Qt::OtherFocusReason);
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
static void handleWindowStateChanged(QWindow *window, Qt::WindowStates newState, int oldState = -1);
@@ -255,6 +231,8 @@ public:
Qt::MouseButtons buttons = {}, int xTilt = 0, int yTilt = 0,
qreal tangentialPressure = 0, qreal rotation = 0, int z = 0,
Qt::KeyboardModifiers modifiers = Qt::NoModifier);
+
+ // The following 4 functions are deprecated (QTBUG-114560)
static bool handleTabletEnterProximityEvent(ulong timestamp, int deviceType, int pointerType, qint64 uid);
static void handleTabletEnterProximityEvent(int deviceType, int pointerType, qint64 uid);
static bool handleTabletLeaveProximityEvent(ulong timestamp, int deviceType, int pointerType, qint64 uid);
diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h
index 3569667325..51ab58fc99 100644
--- a/src/gui/kernel/qwindowsysteminterface_p.h
+++ b/src/gui/kernel/qwindowsysteminterface_p.h
@@ -40,7 +40,7 @@ public:
GeometryChange = 0x02,
Enter = UserInputEvent | 0x03,
Leave = UserInputEvent | 0x04,
- ActivatedWindow = 0x05,
+ FocusWindow = 0x05,
WindowStateChanged = 0x06,
Mouse = UserInputEvent | 0x07,
Wheel = UserInputEvent | 0x09,
@@ -125,12 +125,12 @@ public:
QPointer<QWindow> leave;
};
- class ActivatedWindowEvent : public WindowSystemEvent {
+ class FocusWindowEvent : public WindowSystemEvent {
public:
- explicit ActivatedWindowEvent(QWindow *activatedWindow, Qt::FocusReason r)
- : WindowSystemEvent(ActivatedWindow), activated(activatedWindow), reason(r)
+ explicit FocusWindowEvent(QWindow *focusedWindow, Qt::FocusReason r)
+ : WindowSystemEvent(FocusWindow), focused(focusedWindow), reason(r)
{ }
- QPointer<QWindow> activated;
+ QPointer<QWindow> focused;
Qt::FocusReason reason;
};
@@ -473,7 +473,7 @@ public:
}
void append(WindowSystemEvent *e)
{ const QMutexLocker locker(&mutex); impl.append(e); }
- int count() const
+ qsizetype count() const
{ const QMutexLocker locker(&mutex); return impl.size(); }
WindowSystemEvent *peekAtFirstOfType(EventType t) const
{
@@ -500,7 +500,7 @@ public:
static WindowSystemEventList windowSystemEventQueue;
- static int windowSystemEventsQueued();
+ static qsizetype windowSystemEventsQueued();
static bool nonUserInputEventsQueued();
static WindowSystemEvent *getWindowSystemEvent();
static WindowSystemEvent *getNonUserInputWindowSystemEvent();
diff --git a/src/gui/math3d/qmatrix4x4.cpp b/src/gui/math3d/qmatrix4x4.cpp
index 39625cdfb4..d04a502519 100644
--- a/src/gui/math3d/qmatrix4x4.cpp
+++ b/src/gui/math3d/qmatrix4x4.cpp
@@ -100,7 +100,7 @@ QMatrix4x4::QMatrix4x4(const float *values)
*/
/*!
- \fn QGenericMatrix<N, M, float> QMatrix4x4::toGenericMatrix() const
+ \fn template <int N, int M> QGenericMatrix<N, M, float> QMatrix4x4::toGenericMatrix() const
Constructs a NxM generic matrix from the left-most N columns and
top-most M rows of this 4x4 matrix. If N or M is greater than 4,
diff --git a/src/gui/math3d/qquaternion.cpp b/src/gui/math3d/qquaternion.cpp
index 018f6fb731..e7c5945208 100644
--- a/src/gui/math3d/qquaternion.cpp
+++ b/src/gui/math3d/qquaternion.cpp
@@ -26,14 +26,14 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn QQuaternion::QQuaternion()
+ \fn QQuaternion::QQuaternion() noexcept
Constructs an identity quaternion (1, 0, 0, 0), i.e. with the vector (0, 0, 0)
and scalar 1.
*/
/*!
- \fn QQuaternion::QQuaternion(Qt::Initialization)
+ \fn QQuaternion::QQuaternion(Qt::Initialization) noexcept
\since 5.5
\internal
@@ -41,7 +41,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn QQuaternion::QQuaternion(float scalar, float xpos, float ypos, float zpos)
+ \fn QQuaternion::QQuaternion(float scalar, float xpos, float ypos, float zpos) noexcept
Constructs a quaternion with the vector (\a xpos, \a ypos, \a zpos)
and \a scalar.
@@ -50,7 +50,7 @@ QT_BEGIN_NAMESPACE
#ifndef QT_NO_VECTOR3D
/*!
- \fn QQuaternion::QQuaternion(float scalar, const QVector3D& vector)
+ \fn QQuaternion::QQuaternion(float scalar, const QVector3D &vector) noexcept
Constructs a quaternion vector from the specified \a vector and
\a scalar.
@@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn QVector3D QQuaternion::vector() const
+ \fn QVector3D QQuaternion::vector() const noexcept
Returns the vector component of this quaternion.
@@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn void QQuaternion::setVector(const QVector3D& vector)
+ \fn void QQuaternion::setVector(const QVector3D &vector) noexcept
Sets the vector component of this quaternion to \a vector.
@@ -77,7 +77,7 @@ QT_BEGIN_NAMESPACE
#endif
/*!
- \fn void QQuaternion::setVector(float x, float y, float z)
+ \fn void QQuaternion::setVector(float x, float y, float z) noexcept
Sets the vector component of this quaternion to (\a x, \a y, \a z).
@@ -87,13 +87,13 @@ QT_BEGIN_NAMESPACE
#ifndef QT_NO_VECTOR4D
/*!
- \fn QQuaternion::QQuaternion(const QVector4D& vector)
+ \fn QQuaternion::QQuaternion(const QVector4D &vector) noexcept
Constructs a quaternion from the components of \a vector.
*/
/*!
- \fn QVector4D QQuaternion::toVector4D() const
+ \fn QVector4D QQuaternion::toVector4D() const noexcept
Returns this quaternion as a 4D vector.
*/
@@ -101,14 +101,14 @@ QT_BEGIN_NAMESPACE
#endif
/*!
- \fn bool QQuaternion::isNull() const
+ \fn bool QQuaternion::isNull() const noexcept
Returns \c true if the x, y, z, and scalar components of this
quaternion are set to 0.0; otherwise returns \c false.
*/
/*!
- \fn bool QQuaternion::isIdentity() const
+ \fn bool QQuaternion::isIdentity() const noexcept
Returns \c true if the x, y, and z components of this
quaternion are set to 0.0, and the scalar component is set
@@ -116,7 +116,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn float QQuaternion::x() const
+ \fn float QQuaternion::x() const noexcept
Returns the x coordinate of this quaternion's vector.
@@ -124,7 +124,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn float QQuaternion::y() const
+ \fn float QQuaternion::y() const noexcept
Returns the y coordinate of this quaternion's vector.
@@ -132,7 +132,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn float QQuaternion::z() const
+ \fn float QQuaternion::z() const noexcept
Returns the z coordinate of this quaternion's vector.
@@ -140,7 +140,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn float QQuaternion::scalar() const
+ \fn float QQuaternion::scalar() const noexcept
Returns the scalar component of this quaternion.
@@ -148,7 +148,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn void QQuaternion::setX(float x)
+ \fn void QQuaternion::setX(float x) noexcept
Sets the x coordinate of this quaternion's vector to the given
\a x coordinate.
@@ -157,7 +157,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn void QQuaternion::setY(float y)
+ \fn void QQuaternion::setY(float y) noexcept
Sets the y coordinate of this quaternion's vector to the given
\a y coordinate.
@@ -166,7 +166,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn void QQuaternion::setZ(float z)
+ \fn void QQuaternion::setZ(float z) noexcept
Sets the z coordinate of this quaternion's vector to the given
\a z coordinate.
@@ -175,7 +175,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn void QQuaternion::setScalar(float scalar)
+ \fn void QQuaternion::setScalar(float scalar) noexcept
Sets the scalar component of this quaternion to \a scalar.
@@ -183,7 +183,7 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn float QQuaternion::dotProduct(const QQuaternion &q1, const QQuaternion &q2)
+ \fn float QQuaternion::dotProduct(const QQuaternion &q1, const QQuaternion &q2) noexcept
\since 5.5
Returns the dot product of \a q1 and \a q2.
@@ -227,8 +227,6 @@ float QQuaternion::lengthSquared() const
QQuaternion QQuaternion::normalized() const
{
const float scale = length();
- if (qFuzzyCompare(scale, 1.0f))
- return *this;
if (qFuzzyIsNull(scale))
return QQuaternion(0.0f, 0.0f, 0.0f, 0.0f);
return *this / scale;
@@ -243,7 +241,7 @@ QQuaternion QQuaternion::normalized() const
void QQuaternion::normalize()
{
const float len = length();
- if (qFuzzyCompare(len, 1.0f) || qFuzzyIsNull(len))
+ if (qFuzzyIsNull(len))
return;
xp /= len;
@@ -253,7 +251,7 @@ void QQuaternion::normalize()
}
/*!
- \fn QQuaternion QQuaternion::inverted() const
+ \fn QQuaternion QQuaternion::inverted() const noexcept
\since 5.5
Returns the inverse of this quaternion.
@@ -263,7 +261,7 @@ void QQuaternion::normalize()
*/
/*!
- \fn QQuaternion QQuaternion::conjugated() const
+ \fn QQuaternion QQuaternion::conjugated() const noexcept
\since 5.5
Returns the conjugate of this quaternion, which is
@@ -280,13 +278,13 @@ void QQuaternion::normalize()
\snippet code/src_gui_math3d_qquaternion.cpp 1
*/
-QVector3D QQuaternion::rotatedVector(const QVector3D& vector) const
+QVector3D QQuaternion::rotatedVector(const QVector3D &vector) const
{
return (*this * QQuaternion(0, vector) * conjugated()).vector();
}
/*!
- \fn QQuaternion &QQuaternion::operator+=(const QQuaternion &quaternion)
+ \fn QQuaternion &QQuaternion::operator+=(const QQuaternion &quaternion) noexcept
Adds the given \a quaternion to this quaternion and returns a reference to
this quaternion.
@@ -295,7 +293,7 @@ QVector3D QQuaternion::rotatedVector(const QVector3D& vector) const
*/
/*!
- \fn QQuaternion &QQuaternion::operator-=(const QQuaternion &quaternion)
+ \fn QQuaternion &QQuaternion::operator-=(const QQuaternion &quaternion) noexcept
Subtracts the given \a quaternion from this quaternion and returns a
reference to this quaternion.
@@ -304,7 +302,7 @@ QVector3D QQuaternion::rotatedVector(const QVector3D& vector) const
*/
/*!
- \fn QQuaternion &QQuaternion::operator*=(float factor)
+ \fn QQuaternion &QQuaternion::operator*=(float factor) noexcept
Multiplies this quaternion's components by the given \a factor, and
returns a reference to this quaternion.
@@ -313,7 +311,7 @@ QVector3D QQuaternion::rotatedVector(const QVector3D& vector) const
*/
/*!
- \fn QQuaternion &QQuaternion::operator*=(const QQuaternion &quaternion)
+ \fn QQuaternion &QQuaternion::operator*=(const QQuaternion &quaternion) noexcept
Multiplies this quaternion by \a quaternion and returns a reference
to this quaternion.
@@ -331,7 +329,7 @@ QVector3D QQuaternion::rotatedVector(const QVector3D& vector) const
#ifndef QT_NO_VECTOR3D
/*!
- \fn void QQuaternion::getAxisAndAngle(QVector3D *axis, float *angle) const
+ \fn void QQuaternion::getAxisAndAngle(QVector3D *axis, float *angle) const noexcept
\since 5.5
\overload
@@ -347,7 +345,7 @@ QVector3D QQuaternion::rotatedVector(const QVector3D& vector) const
\sa getAxisAndAngle()
*/
-QQuaternion QQuaternion::fromAxisAndAngle(const QVector3D& axis, float angle)
+QQuaternion QQuaternion::fromAxisAndAngle(const QVector3D &axis, float angle)
{
// Algorithm from:
// http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q56
@@ -388,7 +386,7 @@ void QQuaternion::getAxisAndAngle(float *x, float *y, float *z, float *angle) co
*y = yp / length;
*z = zp / length;
}
- *angle = qRadiansToDegrees(2.0f * std::acos(wp));
+ *angle = qRadiansToDegrees(2.0f * std::atan2(length, wp));
} else {
// angle is 0 (mod 2*pi), so any axis will fit
*x = *y = *z = *angle = 0.0f;
@@ -740,21 +738,21 @@ QQuaternion QQuaternion::rotationTo(const QVector3D &from, const QVector3D &to)
#endif // QT_NO_VECTOR3D
/*!
- \fn bool QQuaternion::operator==(const QQuaternion &q1, const QQuaternion &q2)
+ \fn bool QQuaternion::operator==(const QQuaternion &q1, const QQuaternion &q2) noexcept
Returns \c true if \a q1 is equal to \a q2; otherwise returns \c false.
This operator uses an exact floating-point comparison.
*/
/*!
- \fn bool QQuaternion::operator!=(const QQuaternion &q1, const QQuaternion &q2)
+ \fn bool QQuaternion::operator!=(const QQuaternion &q1, const QQuaternion &q2) noexcept
Returns \c true if \a q1 is not equal to \a q2; otherwise returns \c false.
This operator uses an exact floating-point comparison.
*/
/*!
- \fn const QQuaternion operator+(const QQuaternion &q1, const QQuaternion &q2)
+ \fn const QQuaternion operator+(const QQuaternion &q1, const QQuaternion &q2) noexcept
\relates QQuaternion
Returns a QQuaternion object that is the sum of the given quaternions,
@@ -764,7 +762,7 @@ QQuaternion QQuaternion::rotationTo(const QVector3D &from, const QVector3D &to)
*/
/*!
- \fn const QQuaternion operator-(const QQuaternion &q1, const QQuaternion &q2)
+ \fn const QQuaternion operator-(const QQuaternion &q1, const QQuaternion &q2) noexcept
\relates QQuaternion
Returns a QQuaternion object that is formed by subtracting
@@ -774,7 +772,7 @@ QQuaternion QQuaternion::rotationTo(const QVector3D &from, const QVector3D &to)
*/
/*!
- \fn const QQuaternion operator*(float factor, const QQuaternion &quaternion)
+ \fn const QQuaternion operator*(float factor, const QQuaternion &quaternion) noexcept
\relates QQuaternion
Returns a copy of the given \a quaternion, multiplied by the
@@ -784,7 +782,7 @@ QQuaternion QQuaternion::rotationTo(const QVector3D &from, const QVector3D &to)
*/
/*!
- \fn const QQuaternion operator*(const QQuaternion &quaternion, float factor)
+ \fn const QQuaternion operator*(const QQuaternion &quaternion, float factor) noexcept
\relates QQuaternion
Returns a copy of the given \a quaternion, multiplied by the
@@ -794,7 +792,7 @@ QQuaternion QQuaternion::rotationTo(const QVector3D &from, const QVector3D &to)
*/
/*!
- \fn const QQuaternion operator*(const QQuaternion &q1, const QQuaternion& q2)
+ \fn const QQuaternion operator*(const QQuaternion &q1, const QQuaternion &q2) noexcept
\relates QQuaternion
Multiplies \a q1 and \a q2 using quaternion multiplication.
@@ -805,7 +803,7 @@ QQuaternion QQuaternion::rotationTo(const QVector3D &from, const QVector3D &to)
*/
/*!
- \fn const QQuaternion operator-(const QQuaternion &quaternion)
+ \fn const QQuaternion operator-(const QQuaternion &quaternion) noexcept
\relates QQuaternion
\overload
@@ -828,7 +826,7 @@ QQuaternion QQuaternion::rotationTo(const QVector3D &from, const QVector3D &to)
#ifndef QT_NO_VECTOR3D
/*!
- \fn QVector3D operator*(const QQuaternion &quaternion, const QVector3D &vec)
+ \fn QVector3D operator*(const QQuaternion &quaternion, const QVector3D &vec) noexcept
\since 5.5
\relates QQuaternion
@@ -838,7 +836,7 @@ QQuaternion QQuaternion::rotationTo(const QVector3D &from, const QVector3D &to)
#endif
/*!
- \fn bool qFuzzyCompare(const QQuaternion& q1, const QQuaternion& q2)
+ \fn bool qFuzzyCompare(const QQuaternion &q1, const QQuaternion &q2) noexcept
\relates QQuaternion
Returns \c true if \a q1 and \a q2 are equal, allowing for a small
@@ -857,7 +855,7 @@ QQuaternion QQuaternion::rotationTo(const QVector3D &from, const QVector3D &to)
\sa nlerp()
*/
QQuaternion QQuaternion::slerp
- (const QQuaternion& q1, const QQuaternion& q2, float t)
+ (const QQuaternion &q1, const QQuaternion &q2, float t)
{
// Handle the easy cases first.
if (t <= 0.0f)
@@ -906,7 +904,7 @@ QQuaternion QQuaternion::slerp
\sa slerp()
*/
QQuaternion QQuaternion::nlerp
- (const QQuaternion& q1, const QQuaternion& q2, float t)
+ (const QQuaternion &q1, const QQuaternion &q2, float t)
{
// Handle the easy cases first.
if (t <= 0.0f)
diff --git a/src/gui/math3d/qquaternion.h b/src/gui/math3d/qquaternion.h
index 226a077d4c..7cfbd9b818 100644
--- a/src/gui/math3d/qquaternion.h
+++ b/src/gui/math3d/qquaternion.h
@@ -17,117 +17,123 @@ QT_BEGIN_NAMESPACE
class QMatrix4x4;
class QVariant;
-class Q_GUI_EXPORT QQuaternion
+class QT6_ONLY(Q_GUI_EXPORT) QQuaternion
{
public:
- QQuaternion();
- explicit QQuaternion(Qt::Initialization) {}
- QQuaternion(float scalar, float xpos, float ypos, float zpos);
+ constexpr QQuaternion() noexcept;
+ explicit QQuaternion(Qt::Initialization) noexcept {}
+ constexpr QQuaternion(float scalar, float xpos, float ypos, float zpos) noexcept;
#ifndef QT_NO_VECTOR3D
- QQuaternion(float scalar, const QVector3D& vector);
+ constexpr QQuaternion(float scalar, const QVector3D &vector) noexcept;
#endif
#ifndef QT_NO_VECTOR4D
- explicit QQuaternion(const QVector4D& vector);
+ constexpr explicit QQuaternion(const QVector4D &vector) noexcept;
#endif
- bool isNull() const;
- bool isIdentity() const;
+ constexpr bool isNull() const noexcept;
+ constexpr bool isIdentity() const noexcept;
#ifndef QT_NO_VECTOR3D
- QVector3D vector() const;
- void setVector(const QVector3D& vector);
+ constexpr QVector3D vector() const noexcept;
+ constexpr void setVector(const QVector3D &vector) noexcept;
#endif
- void setVector(float x, float y, float z);
+ constexpr void setVector(float x, float y, float z) noexcept;
- float x() const;
- float y() const;
- float z() const;
- float scalar() const;
+ constexpr float x() const noexcept;
+ constexpr float y() const noexcept;
+ constexpr float z() const noexcept;
+ constexpr float scalar() const noexcept;
- void setX(float x);
- void setY(float y);
- void setZ(float z);
- void setScalar(float scalar);
+ constexpr void setX(float x) noexcept;
+ constexpr void setY(float y) noexcept;
+ constexpr void setZ(float z) noexcept;
+ constexpr void setScalar(float scalar) noexcept;
- constexpr static inline float dotProduct(const QQuaternion &q1, const QQuaternion &q2);
+ constexpr static float dotProduct(const QQuaternion &q1, const QQuaternion &q2) noexcept;
- float length() const;
- float lengthSquared() const;
+ // ### Qt 7: make the next four constexpr
+ // (perhaps using std::hypot, constexpr in C++26, or constexpr qHypot)
+ QT7_ONLY(Q_GUI_EXPORT) float length() const;
+ QT7_ONLY(Q_GUI_EXPORT) float lengthSquared() const;
- [[nodiscard]] QQuaternion normalized() const;
- void normalize();
+ [[nodiscard]] QT7_ONLY(Q_GUI_EXPORT) QQuaternion normalized() const;
+ QT7_ONLY(Q_GUI_EXPORT) void normalize();
- inline QQuaternion inverted() const;
+ constexpr QQuaternion inverted() const noexcept;
- [[nodiscard]] QQuaternion conjugated() const;
+ [[nodiscard]] constexpr QQuaternion conjugated() const noexcept;
- QVector3D rotatedVector(const QVector3D& vector) const;
+ QT7_ONLY(Q_GUI_EXPORT) QVector3D rotatedVector(const QVector3D &vector) const;
- QQuaternion &operator+=(const QQuaternion &quaternion);
- QQuaternion &operator-=(const QQuaternion &quaternion);
- QQuaternion &operator*=(float factor);
- QQuaternion &operator*=(const QQuaternion &quaternion);
- QQuaternion &operator/=(float divisor);
+ constexpr QQuaternion &operator+=(const QQuaternion &quaternion) noexcept;
+ constexpr QQuaternion &operator-=(const QQuaternion &quaternion) noexcept;
+ constexpr QQuaternion &operator*=(float factor) noexcept;
+ constexpr QQuaternion &operator*=(const QQuaternion &quaternion) noexcept;
+ constexpr QQuaternion &operator/=(float divisor);
QT_WARNING_PUSH
QT_WARNING_DISABLE_FLOAT_COMPARE
- friend inline bool operator==(const QQuaternion &q1, const QQuaternion &q2) noexcept
+ friend constexpr bool operator==(const QQuaternion &q1, const QQuaternion &q2) noexcept
{
return q1.wp == q2.wp && q1.xp == q2.xp && q1.yp == q2.yp && q1.zp == q2.zp;
}
- friend inline bool operator!=(const QQuaternion &q1, const QQuaternion &q2) noexcept
+ friend constexpr bool operator!=(const QQuaternion &q1, const QQuaternion &q2) noexcept
{
return !(q1 == q2);
}
QT_WARNING_POP
- friend inline const QQuaternion operator+(const QQuaternion &q1, const QQuaternion &q2);
- friend inline const QQuaternion operator-(const QQuaternion &q1, const QQuaternion &q2);
- friend inline const QQuaternion operator*(float factor, const QQuaternion &quaternion);
- friend inline const QQuaternion operator*(const QQuaternion &quaternion, float factor);
- friend inline const QQuaternion operator*(const QQuaternion &q1, const QQuaternion& q2);
- friend inline const QQuaternion operator-(const QQuaternion &quaternion);
- friend inline const QQuaternion operator/(const QQuaternion &quaternion, float divisor);
+ friend constexpr QQuaternion operator+(const QQuaternion &q1, const QQuaternion &q2) noexcept;
+ friend constexpr QQuaternion operator-(const QQuaternion &q1, const QQuaternion &q2) noexcept;
+ friend constexpr QQuaternion operator*(float factor, const QQuaternion &quaternion) noexcept;
+ friend constexpr QQuaternion operator*(const QQuaternion &quaternion, float factor) noexcept;
+ friend constexpr QQuaternion operator*(const QQuaternion &q1, const QQuaternion &q2) noexcept;
+ friend constexpr QQuaternion operator-(const QQuaternion &quaternion) noexcept;
+ friend constexpr QQuaternion operator/(const QQuaternion &quaternion, float divisor);
- friend inline bool qFuzzyCompare(const QQuaternion& q1, const QQuaternion& q2);
+ friend constexpr bool qFuzzyCompare(const QQuaternion &q1, const QQuaternion &q2) noexcept;
#ifndef QT_NO_VECTOR4D
- QVector4D toVector4D() const;
+ constexpr QVector4D toVector4D() const noexcept;
#endif
- operator QVariant() const;
+ QT7_ONLY(Q_GUI_EXPORT) operator QVariant() const;
#ifndef QT_NO_VECTOR3D
inline void getAxisAndAngle(QVector3D *axis, float *angle) const;
- static QQuaternion fromAxisAndAngle(const QVector3D& axis, float angle);
+ QT7_ONLY(Q_GUI_EXPORT) static QQuaternion fromAxisAndAngle(const QVector3D &axis, float angle);
#endif
- void getAxisAndAngle(float *x, float *y, float *z, float *angle) const;
- static QQuaternion fromAxisAndAngle
- (float x, float y, float z, float angle);
+ QT7_ONLY(Q_GUI_EXPORT) void getAxisAndAngle(float *x, float *y, float *z, float *angle) const;
+ QT7_ONLY(Q_GUI_EXPORT) static QQuaternion fromAxisAndAngle(float x, float y, float z,
+ float angle);
#ifndef QT_NO_VECTOR3D
inline QVector3D toEulerAngles() const;
- static inline QQuaternion fromEulerAngles(const QVector3D &eulerAngles);
+ QT7_ONLY(Q_GUI_EXPORT) static inline QQuaternion fromEulerAngles(const QVector3D &eulerAngles);
#endif
- void getEulerAngles(float *pitch, float *yaw, float *roll) const;
- static QQuaternion fromEulerAngles(float pitch, float yaw, float roll);
+ QT7_ONLY(Q_GUI_EXPORT) void getEulerAngles(float *pitch, float *yaw, float *roll) const;
+ QT7_ONLY(Q_GUI_EXPORT) static QQuaternion fromEulerAngles(float pitch, float yaw, float roll);
- QMatrix3x3 toRotationMatrix() const;
- static QQuaternion fromRotationMatrix(const QMatrix3x3 &rot3x3);
+ QT7_ONLY(Q_GUI_EXPORT) QMatrix3x3 toRotationMatrix() const;
+ QT7_ONLY(Q_GUI_EXPORT) static QQuaternion fromRotationMatrix(const QMatrix3x3 &rot3x3);
#ifndef QT_NO_VECTOR3D
- void getAxes(QVector3D *xAxis, QVector3D *yAxis, QVector3D *zAxis) const;
- static QQuaternion fromAxes(const QVector3D &xAxis, const QVector3D &yAxis, const QVector3D &zAxis);
+ QT7_ONLY(Q_GUI_EXPORT) void getAxes(QVector3D *xAxis, QVector3D *yAxis, QVector3D *zAxis) const;
+ QT7_ONLY(Q_GUI_EXPORT) static QQuaternion fromAxes(const QVector3D &xAxis,
+ const QVector3D &yAxis,
+ const QVector3D &zAxis);
- static QQuaternion fromDirection(const QVector3D &direction, const QVector3D &up);
+ QT7_ONLY(Q_GUI_EXPORT) static QQuaternion fromDirection(const QVector3D &direction,
+ const QVector3D &up);
- static QQuaternion rotationTo(const QVector3D &from, const QVector3D &to);
+ QT7_ONLY(Q_GUI_EXPORT) static QQuaternion rotationTo(const QVector3D &from,
+ const QVector3D &to);
#endif
- static QQuaternion slerp
- (const QQuaternion& q1, const QQuaternion& q2, float t);
- static QQuaternion nlerp
- (const QQuaternion& q1, const QQuaternion& q2, float t);
+ QT7_ONLY(Q_GUI_EXPORT) static QQuaternion slerp(const QQuaternion &q1, const QQuaternion &q2,
+ float t);
+ QT7_ONLY(Q_GUI_EXPORT) static QQuaternion nlerp(const QQuaternion &q1, const QQuaternion &q2,
+ float t);
private:
float wp, xp, yp, zp;
@@ -135,40 +141,41 @@ private:
Q_DECLARE_TYPEINFO(QQuaternion, Q_PRIMITIVE_TYPE);
-inline QQuaternion::QQuaternion() : wp(1.0f), xp(0.0f), yp(0.0f), zp(0.0f) {}
+constexpr QQuaternion::QQuaternion() noexcept : wp(1.0f), xp(0.0f), yp(0.0f), zp(0.0f) {}
-inline QQuaternion::QQuaternion(float aScalar, float xpos, float ypos, float zpos) : wp(aScalar), xp(xpos), yp(ypos), zp(zpos) {}
+constexpr QQuaternion::QQuaternion(float aScalar, float xpos, float ypos, float zpos) noexcept
+ : wp(aScalar), xp(xpos), yp(ypos), zp(zpos) {}
QT_WARNING_PUSH
QT_WARNING_DISABLE_FLOAT_COMPARE
-inline bool QQuaternion::isNull() const
+constexpr bool QQuaternion::isNull() const noexcept
{
return wp == 0.0f && xp == 0.0f && yp == 0.0f && zp == 0.0f;
}
-inline bool QQuaternion::isIdentity() const
+constexpr bool QQuaternion::isIdentity() const noexcept
{
return wp == 1.0f && xp == 0.0f && yp == 0.0f && zp == 0.0f;
}
QT_WARNING_POP
-inline float QQuaternion::x() const { return xp; }
-inline float QQuaternion::y() const { return yp; }
-inline float QQuaternion::z() const { return zp; }
-inline float QQuaternion::scalar() const { return wp; }
+constexpr float QQuaternion::x() const noexcept { return xp; }
+constexpr float QQuaternion::y() const noexcept { return yp; }
+constexpr float QQuaternion::z() const noexcept { return zp; }
+constexpr float QQuaternion::scalar() const noexcept { return wp; }
-inline void QQuaternion::setX(float aX) { xp = aX; }
-inline void QQuaternion::setY(float aY) { yp = aY; }
-inline void QQuaternion::setZ(float aZ) { zp = aZ; }
-inline void QQuaternion::setScalar(float aScalar) { wp = aScalar; }
+constexpr void QQuaternion::setX(float aX) noexcept { xp = aX; }
+constexpr void QQuaternion::setY(float aY) noexcept { yp = aY; }
+constexpr void QQuaternion::setZ(float aZ) noexcept { zp = aZ; }
+constexpr void QQuaternion::setScalar(float aScalar) noexcept { wp = aScalar; }
-constexpr inline float QQuaternion::dotProduct(const QQuaternion &q1, const QQuaternion &q2)
+constexpr float QQuaternion::dotProduct(const QQuaternion &q1, const QQuaternion &q2) noexcept
{
return q1.wp * q2.wp + q1.xp * q2.xp + q1.yp * q2.yp + q1.zp * q2.zp;
}
-inline QQuaternion QQuaternion::inverted() const
+constexpr QQuaternion QQuaternion::inverted() const noexcept
{
// Need some extra precision if the length is very small.
double len = double(wp) * double(wp) +
@@ -181,12 +188,12 @@ inline QQuaternion QQuaternion::inverted() const
return QQuaternion(0.0f, 0.0f, 0.0f, 0.0f);
}
-inline QQuaternion QQuaternion::conjugated() const
+constexpr QQuaternion QQuaternion::conjugated() const noexcept
{
return QQuaternion(wp, -xp, -yp, -zp);
}
-inline QQuaternion &QQuaternion::operator+=(const QQuaternion &quaternion)
+constexpr QQuaternion &QQuaternion::operator+=(const QQuaternion &quaternion) noexcept
{
wp += quaternion.wp;
xp += quaternion.xp;
@@ -195,7 +202,7 @@ inline QQuaternion &QQuaternion::operator+=(const QQuaternion &quaternion)
return *this;
}
-inline QQuaternion &QQuaternion::operator-=(const QQuaternion &quaternion)
+constexpr QQuaternion &QQuaternion::operator-=(const QQuaternion &quaternion) noexcept
{
wp -= quaternion.wp;
xp -= quaternion.xp;
@@ -204,7 +211,7 @@ inline QQuaternion &QQuaternion::operator-=(const QQuaternion &quaternion)
return *this;
}
-inline QQuaternion &QQuaternion::operator*=(float factor)
+constexpr QQuaternion &QQuaternion::operator*=(float factor) noexcept
{
wp *= factor;
xp *= factor;
@@ -213,7 +220,7 @@ inline QQuaternion &QQuaternion::operator*=(float factor)
return *this;
}
-inline const QQuaternion operator*(const QQuaternion &q1, const QQuaternion& q2)
+constexpr QQuaternion operator*(const QQuaternion &q1, const QQuaternion &q2) noexcept
{
float yy = (q1.wp - q1.yp) * (q2.wp + q2.zp);
float zz = (q1.wp + q1.yp) * (q2.wp - q2.zp);
@@ -229,13 +236,13 @@ inline const QQuaternion operator*(const QQuaternion &q1, const QQuaternion& q2)
return QQuaternion(w, x, y, z);
}
-inline QQuaternion &QQuaternion::operator*=(const QQuaternion &quaternion)
+constexpr QQuaternion &QQuaternion::operator*=(const QQuaternion &quaternion) noexcept
{
*this = *this * quaternion;
return *this;
}
-inline QQuaternion &QQuaternion::operator/=(float divisor)
+constexpr QQuaternion &QQuaternion::operator/=(float divisor)
{
wp /= divisor;
xp /= divisor;
@@ -244,37 +251,37 @@ inline QQuaternion &QQuaternion::operator/=(float divisor)
return *this;
}
-inline const QQuaternion operator+(const QQuaternion &q1, const QQuaternion &q2)
+constexpr QQuaternion operator+(const QQuaternion &q1, const QQuaternion &q2) noexcept
{
return QQuaternion(q1.wp + q2.wp, q1.xp + q2.xp, q1.yp + q2.yp, q1.zp + q2.zp);
}
-inline const QQuaternion operator-(const QQuaternion &q1, const QQuaternion &q2)
+constexpr QQuaternion operator-(const QQuaternion &q1, const QQuaternion &q2) noexcept
{
return QQuaternion(q1.wp - q2.wp, q1.xp - q2.xp, q1.yp - q2.yp, q1.zp - q2.zp);
}
-inline const QQuaternion operator*(float factor, const QQuaternion &quaternion)
+constexpr QQuaternion operator*(float factor, const QQuaternion &quaternion) noexcept
{
return QQuaternion(quaternion.wp * factor, quaternion.xp * factor, quaternion.yp * factor, quaternion.zp * factor);
}
-inline const QQuaternion operator*(const QQuaternion &quaternion, float factor)
+constexpr QQuaternion operator*(const QQuaternion &quaternion, float factor) noexcept
{
return QQuaternion(quaternion.wp * factor, quaternion.xp * factor, quaternion.yp * factor, quaternion.zp * factor);
}
-inline const QQuaternion operator-(const QQuaternion &quaternion)
+constexpr QQuaternion operator-(const QQuaternion &quaternion) noexcept
{
return QQuaternion(-quaternion.wp, -quaternion.xp, -quaternion.yp, -quaternion.zp);
}
-inline const QQuaternion operator/(const QQuaternion &quaternion, float divisor)
+constexpr QQuaternion operator/(const QQuaternion &quaternion, float divisor)
{
return QQuaternion(quaternion.wp / divisor, quaternion.xp / divisor, quaternion.yp / divisor, quaternion.zp / divisor);
}
-inline bool qFuzzyCompare(const QQuaternion& q1, const QQuaternion& q2)
+constexpr bool qFuzzyCompare(const QQuaternion &q1, const QQuaternion &q2) noexcept
{
return qFuzzyCompare(q1.wp, q2.wp) &&
qFuzzyCompare(q1.xp, q2.xp) &&
@@ -284,17 +291,17 @@ inline bool qFuzzyCompare(const QQuaternion& q1, const QQuaternion& q2)
#ifndef QT_NO_VECTOR3D
-inline QQuaternion::QQuaternion(float aScalar, const QVector3D& aVector)
+constexpr QQuaternion::QQuaternion(float aScalar, const QVector3D &aVector) noexcept
: wp(aScalar), xp(aVector.x()), yp(aVector.y()), zp(aVector.z()) {}
-inline void QQuaternion::setVector(const QVector3D& aVector)
+constexpr void QQuaternion::setVector(const QVector3D &aVector) noexcept
{
xp = aVector.x();
yp = aVector.y();
zp = aVector.z();
}
-inline QVector3D QQuaternion::vector() const
+constexpr QVector3D QQuaternion::vector() const noexcept
{
return QVector3D(xp, yp, zp);
}
@@ -325,7 +332,7 @@ inline QQuaternion QQuaternion::fromEulerAngles(const QVector3D &eulerAngles)
#endif
-inline void QQuaternion::setVector(float aX, float aY, float aZ)
+constexpr void QQuaternion::setVector(float aX, float aY, float aZ) noexcept
{
xp = aX;
yp = aY;
@@ -334,10 +341,10 @@ inline void QQuaternion::setVector(float aX, float aY, float aZ)
#ifndef QT_NO_VECTOR4D
-inline QQuaternion::QQuaternion(const QVector4D& aVector)
+constexpr QQuaternion::QQuaternion(const QVector4D &aVector) noexcept
: wp(aVector.w()), xp(aVector.x()), yp(aVector.y()), zp(aVector.z()) {}
-inline QVector4D QQuaternion::toVector4D() const
+constexpr QVector4D QQuaternion::toVector4D() const noexcept
{
return QVector4D(xp, yp, zp, wp);
}
diff --git a/src/gui/opengl/platform/egl/qeglconvenience.cpp b/src/gui/opengl/platform/egl/qeglconvenience.cpp
index 3d5b99c38c..4af50d72f2 100644
--- a/src/gui/opengl/platform/egl/qeglconvenience.cpp
+++ b/src/gui/opengl/platform/egl/qeglconvenience.cpp
@@ -88,13 +88,12 @@ QList<EGLint> q_createConfigAttributesFromFormat(const QSurfaceFormat &format)
bool q_reduceConfigAttributes(QList<EGLint> *configAttributes)
{
- int i = -1;
// Reduce the complexity of a configuration request to ask for less
// because the previous request did not result in success. Returns
// true if the complexity was reduced, or false if no further
// reductions in complexity are possible.
- i = configAttributes->indexOf(EGL_SWAP_BEHAVIOR);
+ qsizetype i = configAttributes->indexOf(EGL_SWAP_BEHAVIOR);
if (i >= 0) {
configAttributes->remove(i,2);
}
@@ -216,14 +215,17 @@ EGLConfig QEglConfigChooser::chooseConfig()
configureAttributes.append(EGL_OPENVG_BIT);
break;
#ifdef EGL_VERSION_1_4
- case QSurfaceFormat::DefaultRenderableType:
+ case QSurfaceFormat::DefaultRenderableType: {
#ifndef QT_NO_OPENGL
- if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL)
+ // NVIDIA EGL only provides desktop GL for development purposes, and recommends against using it.
+ const char *vendor = eglQueryString(display(), EGL_VENDOR);
+ if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL && (!vendor || !strstr(vendor, "NVIDIA")))
configureAttributes.append(EGL_OPENGL_BIT);
else
#endif // QT_NO_OPENGL
needsES2Plus = true;
break;
+ }
case QSurfaceFormat::OpenGL:
configureAttributes.append(EGL_OPENGL_BIT);
break;
@@ -255,7 +257,7 @@ EGLConfig QEglConfigChooser::chooseConfig()
// Fetch all of the matching configurations and find the
// first that matches the pixel format we wanted.
- int i = configureAttributes.indexOf(EGL_RED_SIZE);
+ qsizetype i = configureAttributes.indexOf(EGL_RED_SIZE);
m_confAttrRed = configureAttributes.at(i+1);
i = configureAttributes.indexOf(EGL_GREEN_SIZE);
m_confAttrGreen = configureAttributes.at(i+1);
@@ -265,7 +267,8 @@ EGLConfig QEglConfigChooser::chooseConfig()
m_confAttrAlpha = i == -1 ? 0 : configureAttributes.at(i+1);
QList<EGLConfig> configs(matching);
- eglChooseConfig(display(), configureAttributes.constData(), configs.data(), configs.size(), &matching);
+ eglChooseConfig(display(), configureAttributes.constData(), configs.data(),
+ EGLint(configs.size()), &matching);
if (!cfg && matching > 0)
cfg = configs.first();
@@ -353,6 +356,7 @@ QSurfaceFormat q_glFormatFromConfig(EGLDisplay display, const EGLConfig config,
else if (referenceFormat.renderableType() == QSurfaceFormat::DefaultRenderableType
#ifndef QT_NO_OPENGL
&& QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL
+ && !strstr(eglQueryString(display, EGL_VENDOR), "NVIDIA")
#endif
&& (renderableType & EGL_OPENGL_BIT))
format.setRenderableType(QSurfaceFormat::OpenGL);
diff --git a/src/gui/opengl/qopengl.cpp b/src/gui/opengl/qopengl.cpp
index 7c997103d5..587975085a 100644
--- a/src/gui/opengl/qopengl.cpp
+++ b/src/gui/opengl/qopengl.cpp
@@ -385,7 +385,8 @@ static bool readGpuFeatures(const QOpenGLConfig::Gpu &gpu,
QJsonParseError error;
const QJsonDocument document = QJsonDocument::fromJson(jsonAsciiData, &error);
if (document.isNull()) {
- const int lineNumber = 1 + jsonAsciiData.left(error.offset).count('\n');
+ const qsizetype lineNumber =
+ QByteArrayView(jsonAsciiData).left(error.offset).count('\n') + 1;
QTextStream str(errorMessage);
str << "Failed to parse data: \"" << error.errorString()
<< "\" at line " << lineNumber << " (offset: "
diff --git a/src/gui/opengl/qopengl.h b/src/gui/opengl/qopengl.h
index 7e5b8e6961..e9a11080ce 100644
--- a/src/gui/opengl/qopengl.h
+++ b/src/gui/opengl/qopengl.h
@@ -8,9 +8,19 @@
#ifndef QT_NO_OPENGL
-// Windows always needs this to ensure that APIENTRY gets defined
+// On Windows we need to ensure that APIENTRY and WINGDIAPI are defined before
+// we can include gl.h. But we do not want to include <windows.h> in this public
+// Qt header, as it pollutes the global namespace with macros.
#if defined(Q_OS_WIN)
-# include <QtCore/qt_windows.h>
+# ifndef APIENTRY
+# define APIENTRY __stdcall
+# define Q_UNDEF_APIENTRY
+# endif // APIENTRY
+# ifndef WINGDIAPI
+# define WINGDIAPI __declspec(dllimport)
+# define Q_UNDEF_WINGDIAPI
+# endif // WINGDIAPI
+# define QT_APIENTRY __stdcall
#endif
// Note: Apple is a "controlled platform" for OpenGL ABI so we
@@ -128,11 +138,11 @@ typedef char GLchar;
// OS X 10.6 doesn't define these which are needed below
// OS X 10.7 and later define them in gl3.h
-#ifndef APIENTRY
-#define APIENTRY
+#ifndef QT_APIENTRY
+#define QT_APIENTRY
#endif
-#ifndef APIENTRYP
-#define APIENTRYP APIENTRY *
+#ifndef QT_APIENTRYP
+#define QT_APIENTRYP QT_APIENTRY *
#endif
#ifndef GLAPI
#define GLAPI extern
@@ -231,15 +241,15 @@ struct _cl_event;
#endif
#ifndef GL_ARB_debug_output
-typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const GLvoid *userParam);
+typedef void (QT_APIENTRY *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const GLvoid *userParam);
#endif
#ifndef GL_AMD_debug_output
-typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam);
+typedef void (QT_APIENTRY *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam);
#endif
#ifndef GL_KHR_debug
-typedef void (APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const GLvoid *userParam);
+typedef void (QT_APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const GLvoid *userParam);
#endif
#ifndef GL_NV_vdpau_interop
@@ -256,8 +266,8 @@ typedef ptrdiff_t qopengl_GLintptr;
typedef ptrdiff_t qopengl_GLsizeiptr;
-#if defined(APIENTRY) && !defined(QOPENGLF_APIENTRY)
-# define QOPENGLF_APIENTRY APIENTRY
+#if defined(QT_APIENTRY) && !defined(QOPENGLF_APIENTRY)
+# define QOPENGLF_APIENTRY QT_APIENTRY
#endif
# ifndef QOPENGLF_APIENTRYP
@@ -271,6 +281,15 @@ typedef ptrdiff_t qopengl_GLsizeiptr;
QT_END_NAMESPACE
+#ifdef Q_UNDEF_WINGDIAPI
+# undef WINGDIAPI
+# undef Q_UNDEF_WINGDIAPI
+#endif
+#ifdef Q_UNDEF_APIENTRY
+# undef APIENTRY
+# undef Q_UNDEF_APIENTRY
+#endif
+
#endif // QT_NO_OPENGL
#endif // QOPENGL_H
diff --git a/src/gui/opengl/qopenglextensions_p.h b/src/gui/opengl/qopenglextensions_p.h
index fdb9b51f06..a6c4a68c6c 100644
--- a/src/gui/opengl/qopenglextensions_p.h
+++ b/src/gui/opengl/qopenglextensions_p.h
@@ -59,7 +59,9 @@ public:
StandardDerivatives = 0x02000000,
ASTCTextureCompression = 0x04000000,
ETC2TextureCompression = 0x08000000,
- HalfFloatVertex = 0x10000000
+ HalfFloatVertex = 0x10000000,
+ MultiView = 0x20000000,
+ MultiViewExtended = 0x40000000
};
Q_DECLARE_FLAGS(OpenGLExtensions, OpenGLExtension)
@@ -68,9 +70,9 @@ public:
GLvoid *glMapBuffer(GLenum target, GLenum access);
void glGetBufferSubData(GLenum target, qopengl_GLintptr offset, qopengl_GLsizeiptr size, GLvoid *data);
- void glDiscardFramebufferEXT (GLenum target, GLsizei numAttachments, const GLenum *attachments);
void flushShared();
+ void discardFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments);
QOpenGLExtensionsPrivate *d() const;
@@ -115,14 +117,6 @@ inline void QOpenGLExtensions::glGetBufferSubData(GLenum target, qopengl_GLintpt
Q_OPENGL_FUNCTIONS_DEBUG
}
-
-inline void QOpenGLExtensions::glDiscardFramebufferEXT (GLenum target, GLsizei numAttachments, const GLenum *attachments)
-{
- Q_D(QOpenGLExtensions);
- Q_ASSERT(QOpenGLExtensions::isInitialized(d));
- d->DiscardFramebuffer(target,numAttachments, attachments);
- Q_OPENGL_FUNCTIONS_DEBUG
-}
QT_END_NAMESPACE
#endif // QOPENGL_EXTENSIONS_P_H
diff --git a/src/gui/opengl/qopenglfunctions.cpp b/src/gui/opengl/qopenglfunctions.cpp
index ee76987566..c9352fbc31 100644
--- a/src/gui/opengl/qopenglfunctions.cpp
+++ b/src/gui/opengl/qopenglfunctions.cpp
@@ -348,6 +348,10 @@ static int qt_gl_resolve_extensions()
extensions |= QOpenGLExtensions::StandardDerivatives;
if (extensionMatcher.match("GL_ARB_half_float_vertex"))
extensions |= QOpenGLExtensions::HalfFloatVertex;
+ if (extensionMatcher.match("GL_OVR_multiview"))
+ extensions |= QOpenGLExtensions::MultiView;
+ if (extensionMatcher.match("GL_OVR_multiview2"))
+ extensions |= QOpenGLExtensions::MultiViewExtended;
if (ctx->isOpenGLES()) {
if (format.majorVersion() >= 2)
@@ -361,6 +365,7 @@ static int qt_gl_resolve_extensions()
| QOpenGLExtensions::FramebufferBlit
| QOpenGLExtensions::FramebufferMultisample
| QOpenGLExtensions::Sized8Formats
+ | QOpenGLExtensions::DiscardFramebuffer
| QOpenGLExtensions::StandardDerivatives
| QOpenGLExtensions::ETC2TextureCompression
| QOpenGLExtensions::HalfFloatVertex;
@@ -446,6 +451,9 @@ static int qt_gl_resolve_extensions()
if (format.version() >= qMakePair(3, 3))
extensions |= QOpenGLExtensions::TextureSwizzle;
+ if (format.version() >= qMakePair(4, 3) || extensionMatcher.match("GL_ARB_invalidate_subdata"))
+ extensions |= QOpenGLExtensions::DiscardFramebuffer;
+
if (extensionMatcher.match("GL_ARB_map_buffer_range"))
extensions |= QOpenGLExtensions::MapBufferRange;
@@ -5047,7 +5055,23 @@ QOpenGLExtensionsPrivate::QOpenGLExtensionsPrivate(QOpenGLContext *ctx)
MapBuffer = RESOLVE(MapBuffer);
GetBufferSubData = RESOLVE(GetBufferSubData);
DiscardFramebuffer = RESOLVE(DiscardFramebuffer);
- }
+}
+
+void QOpenGLExtensions::discardFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments)
+{
+ Q_D(QOpenGLExtensions);
+ Q_ASSERT(QOpenGLExtensions::isInitialized(d));
+ Q_ASSERT(d->f.InvalidateFramebuffer || d->DiscardFramebuffer);
+
+ // On GLES >= 3 we prefer glInvalidateFramebuffer, even if the
+ // discard extension is present
+ if (d->f.InvalidateFramebuffer)
+ d->f.InvalidateFramebuffer(target, numAttachments, attachments);
+ else
+ d->DiscardFramebuffer(target, numAttachments, attachments);
+
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
void QOpenGLExtensions::flushShared()
{
diff --git a/src/gui/opengl/qopenglprogrambinarycache_p.h b/src/gui/opengl/qopenglprogrambinarycache_p.h
index 0237c81fc5..c3850bdee3 100644
--- a/src/gui/opengl/qopenglprogrambinarycache_p.h
+++ b/src/gui/opengl/qopenglprogrambinarycache_p.h
@@ -20,7 +20,7 @@
#include <QtCore/qmutex.h>
#include <QtCore/QLoggingCategory>
#include <QtGui/private/qopenglcontext_p.h>
-#include <QtGui/private/qshader_p.h>
+#include <rhi/qshader.h>
QT_BEGIN_NAMESPACE
diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp
index f609cddd3c..2304ee2256 100644
--- a/src/gui/painting/qbackingstore.cpp
+++ b/src/gui/painting/qbackingstore.cpp
@@ -230,7 +230,8 @@ void QBackingStore::flush(const QRegion &region, QWindow *window, const QPoint &
void QBackingStore::resize(const QSize &size)
{
d_ptr->size = size;
- handle()->resize(QHighDpi::scale(size, d_ptr->deviceIndependentToNativeFactor()), d_ptr->staticContents);
+ const qreal factor = d_ptr->deviceIndependentToNativeFactor();
+ handle()->resize(QHighDpi::scale(size, factor), QHighDpi::scale(d_ptr->staticContents, factor));
}
/*!
@@ -266,6 +267,13 @@ bool QBackingStore::scroll(const QRegion &area, int dx, int dy)
*/
void QBackingStore::setStaticContents(const QRegion &region)
{
+ [[maybe_unused]] static const bool didCheckPlatformSupport = []{
+ const auto *integration = QGuiApplicationPrivate::platformIntegration();
+ if (!integration->hasCapability(QPlatformIntegration::BackingStoreStaticContents))
+ qWarning("QBackingStore::setStaticContents(): Platform does not support static contents");
+ return true;
+ }();
+
d_ptr->staticContents = region;
}
diff --git a/src/gui/painting/qbackingstoredefaultcompositor.cpp b/src/gui/painting/qbackingstoredefaultcompositor.cpp
index 383fb651dd..c1452ca768 100644
--- a/src/gui/painting/qbackingstoredefaultcompositor.cpp
+++ b/src/gui/painting/qbackingstoredefaultcompositor.cpp
@@ -18,18 +18,13 @@ QBackingStoreDefaultCompositor::~QBackingStoreDefaultCompositor()
void QBackingStoreDefaultCompositor::reset()
{
m_rhi = nullptr;
- delete m_psNoBlend;
- m_psNoBlend = nullptr;
- delete m_psBlend;
- m_psBlend = nullptr;
- delete m_psPremulBlend;
- m_psPremulBlend = nullptr;
- delete m_sampler;
- m_sampler = nullptr;
- delete m_vbuf;
- m_vbuf = nullptr;
- delete m_texture;
- m_texture = nullptr;
+ m_psNoBlend.reset();
+ m_psBlend.reset();
+ m_psPremulBlend.reset();
+ m_samplerNearest.reset();
+ m_samplerLinear.reset();
+ m_vbuf.reset();
+ m_texture.reset();
m_widgetQuadData.reset();
for (PerQuadData &d : m_textureQuadData)
d.reset();
@@ -100,7 +95,7 @@ QRhiTexture *QBackingStoreDefaultCompositor::toTexture(const QImage &sourceImage
const bool resized = !m_texture || m_texture->pixelSize() != image.size();
if (dirtyRegion.isEmpty() && !resized)
- return m_texture;
+ return m_texture.get();
if (needsConversion)
image = image.convertToFormat(QImage::Format_RGBA8888);
@@ -109,11 +104,11 @@ QRhiTexture *QBackingStoreDefaultCompositor::toTexture(const QImage &sourceImage
if (resized) {
if (!m_texture)
- m_texture = rhi->newTexture(QRhiTexture::RGBA8, image.size());
+ m_texture.reset(rhi->newTexture(QRhiTexture::RGBA8, image.size()));
else
m_texture->setPixelSize(image.size());
m_texture->create();
- resourceUpdates->uploadTexture(m_texture, image);
+ resourceUpdates->uploadTexture(m_texture.get(), image);
} else {
QRect imageRect = image.rect();
QRect rect = dirtyRegion.boundingRect() & imageRect;
@@ -122,10 +117,10 @@ QRhiTexture *QBackingStoreDefaultCompositor::toTexture(const QImage &sourceImage
subresDesc.setSourceSize(rect.size());
subresDesc.setDestinationTopLeft(rect.topLeft());
QRhiTextureUploadDescription uploadDesc(QRhiTextureUploadEntry(0, 0, subresDesc));
- resourceUpdates->uploadTexture(m_texture, uploadDesc);
+ resourceUpdates->uploadTexture(m_texture.get(), uploadDesc);
}
- return m_texture;
+ return m_texture.get();
}
static inline QRect scaledRect(const QRect &rect, qreal factor)
@@ -171,7 +166,7 @@ static QMatrix4x4 targetTransform(const QRectF &target, const QRect &viewport, b
matrix(1,3) = y_translate;
matrix(0,0) = x_scale;
- matrix(1,1) = y_scale;
+ matrix(1,1) = (invertY ? -1.0 : 1.0) * y_scale;
return matrix;
}
@@ -280,7 +275,7 @@ enum class PipelineBlend {
static QRhiGraphicsPipeline *createGraphicsPipeline(QRhi *rhi,
QRhiShaderResourceBindings *srb,
- QRhiSwapChain *swapchain,
+ QRhiRenderPassDescriptor *rpDesc,
PipelineBlend blend)
{
QRhiGraphicsPipeline *ps = rhi->newGraphicsPipeline();
@@ -324,7 +319,7 @@ static QRhiGraphicsPipeline *createGraphicsPipeline(QRhi *rhi,
});
ps->setVertexInputLayout(inputLayout);
ps->setShaderResourceBindings(srb);
- ps->setRenderPassDescriptor(swapchain->renderPassDescriptor());
+ ps->setRenderPassDescriptor(rpDesc);
if (!ps->create()) {
qWarning("QBackingStoreDefaultCompositor: Failed to build graphics pipeline");
@@ -347,7 +342,7 @@ QBackingStoreDefaultCompositor::PerQuadData QBackingStoreDefaultCompositor::crea
d.srb = m_rhi->newShaderResourceBindings();
d.srb->setBindings({
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf, 0, UBUF_SIZE),
- QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture, m_sampler)
+ QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture, m_samplerNearest.get())
});
if (!d.srb->create())
qWarning("QBackingStoreDefaultCompositor: Failed to create srb");
@@ -357,7 +352,7 @@ QBackingStoreDefaultCompositor::PerQuadData QBackingStoreDefaultCompositor::crea
d.srbExtra = m_rhi->newShaderResourceBindings();
d.srbExtra->setBindings({
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d.ubuf, 0, UBUF_SIZE),
- QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, textureExtra, m_sampler)
+ QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, textureExtra, m_samplerNearest.get())
});
if (!d.srbExtra->create())
qWarning("QBackingStoreDefaultCompositor: Failed to create srb");
@@ -368,27 +363,31 @@ QBackingStoreDefaultCompositor::PerQuadData QBackingStoreDefaultCompositor::crea
return d;
}
-void QBackingStoreDefaultCompositor::updatePerQuadData(PerQuadData *d, QRhiTexture *texture, QRhiTexture *textureExtra)
+void QBackingStoreDefaultCompositor::updatePerQuadData(PerQuadData *d, QRhiTexture *texture, QRhiTexture *textureExtra,
+ UpdateQuadDataOptions options)
{
// This whole check-if-texture-ptr-is-different is needed because there is
// nothing saying a QPlatformTextureList cannot return a different
// QRhiTexture* from the same index in a subsequent flush.
- if (d->lastUsedTexture == texture || !d->srb)
+ const QRhiSampler::Filter filter = options.testFlag(NeedsLinearFiltering) ? QRhiSampler::Linear : QRhiSampler::Nearest;
+ if ((d->lastUsedTexture == texture && d->lastUsedFilter == filter) || !d->srb)
return;
+ QRhiSampler *sampler = filter == QRhiSampler::Linear ? m_samplerLinear.get() : m_samplerNearest.get();
d->srb->setBindings({
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d->ubuf, 0, UBUF_SIZE),
- QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture, m_sampler)
+ QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture, sampler)
});
d->srb->updateResources(QRhiShaderResourceBindings::BindingsAreSorted);
d->lastUsedTexture = texture;
+ d->lastUsedFilter = filter;
if (textureExtra) {
d->srbExtra->setBindings({
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, d->ubuf, 0, UBUF_SIZE),
- QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, textureExtra, m_sampler)
+ QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, textureExtra, sampler)
});
d->srbExtra->updateResources(QRhiShaderResourceBindings::BindingsAreSorted);
@@ -397,17 +396,18 @@ void QBackingStoreDefaultCompositor::updatePerQuadData(PerQuadData *d, QRhiTextu
}
void QBackingStoreDefaultCompositor::updateUniforms(PerQuadData *d, QRhiResourceUpdateBatch *resourceUpdates,
- const QMatrix4x4 &target, const QMatrix3x3 &source, UpdateUniformOption option)
+ const QMatrix4x4 &target, const QMatrix3x3 &source,
+ UpdateUniformOptions options)
{
resourceUpdates->updateDynamicBuffer(d->ubuf, 0, 64, target.constData());
updateMatrix3x3(resourceUpdates, d->ubuf, source);
float opacity = 1.0f;
resourceUpdates->updateDynamicBuffer(d->ubuf, 112, 4, &opacity);
- qint32 textureSwizzle = static_cast<qint32>(option);
+ qint32 textureSwizzle = options;
resourceUpdates->updateDynamicBuffer(d->ubuf, 116, 4, &textureSwizzle);
}
-void QBackingStoreDefaultCompositor::ensureResources(QRhiSwapChain *swapchain, QRhiResourceUpdateBatch *resourceUpdates)
+void QBackingStoreDefaultCompositor::ensureResources(QRhiResourceUpdateBatch *resourceUpdates, QRhiRenderPassDescriptor *rpDesc)
{
static const float vertexData[] = {
-1, -1, 0, 0, 0,
@@ -419,30 +419,37 @@ void QBackingStoreDefaultCompositor::ensureResources(QRhiSwapChain *swapchain, Q
};
if (!m_vbuf) {
- m_vbuf = m_rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData));
+ m_vbuf.reset(m_rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData)));
if (m_vbuf->create())
- resourceUpdates->uploadStaticBuffer(m_vbuf, vertexData);
+ resourceUpdates->uploadStaticBuffer(m_vbuf.get(), vertexData);
else
qWarning("QBackingStoreDefaultCompositor: Failed to create vertex buffer");
}
- if (!m_sampler) {
- m_sampler = m_rhi->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
- QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
- if (!m_sampler->create())
- qWarning("QBackingStoreDefaultCompositor: Failed to create sampler");
+ if (!m_samplerNearest) {
+ m_samplerNearest.reset(m_rhi->newSampler(QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
+ QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge));
+ if (!m_samplerNearest->create())
+ qWarning("QBackingStoreDefaultCompositor: Failed to create sampler (Nearest filtering)");
+ }
+
+ if (!m_samplerLinear) {
+ m_samplerLinear.reset(m_rhi->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
+ QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge));
+ if (!m_samplerLinear->create())
+ qWarning("QBackingStoreDefaultCompositor: Failed to create sampler (Linear filtering)");
}
if (!m_widgetQuadData.isValid())
- m_widgetQuadData = createPerQuadData(m_texture);
+ m_widgetQuadData = createPerQuadData(m_texture.get());
QRhiShaderResourceBindings *srb = m_widgetQuadData.srb; // just for the layout
if (!m_psNoBlend)
- m_psNoBlend = createGraphicsPipeline(m_rhi, srb, swapchain, PipelineBlend::None);
+ m_psNoBlend.reset(createGraphicsPipeline(m_rhi, srb, rpDesc, PipelineBlend::None));
if (!m_psBlend)
- m_psBlend = createGraphicsPipeline(m_rhi, srb, swapchain, PipelineBlend::Alpha);
+ m_psBlend.reset(createGraphicsPipeline(m_rhi, srb, rpDesc, PipelineBlend::Alpha));
if (!m_psPremulBlend)
- m_psPremulBlend = createGraphicsPipeline(m_rhi, srb, swapchain, PipelineBlend::PremulAlpha);
+ m_psPremulBlend.reset(createGraphicsPipeline(m_rhi, srb, rpDesc, PipelineBlend::PremulAlpha));
}
QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatformBackingStore *backingStore,
@@ -455,6 +462,9 @@ QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatfo
QPlatformTextureList *textures,
bool translucentBackground)
{
+ if (!rhi)
+ return QPlatformBackingStore::FlushFailed;
+
Q_ASSERT(textures); // may be empty if there are no render-to-texture widgets at all, but null it cannot be
if (!m_rhi) {
@@ -508,12 +518,15 @@ QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatfo
if (!gotTextureFromGraphicsBuffer)
toTexture(backingStore, rhi, resourceUpdates, scaledRegion(region, sourceDevicePixelRatio, offset), &flags);
- ensureResources(swapchain, resourceUpdates);
+ ensureResources(resourceUpdates, swapchain->renderPassDescriptor());
+ UpdateUniformOptions uniformOptions;
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
- const UpdateUniformOption uniformOption = (flags & QPlatformBackingStore::TextureSwizzle) != 0? NeedsRedBlueSwap : NoOption;
+ if (flags & QPlatformBackingStore::TextureSwizzle)
+ uniformOptions |= NeedsRedBlueSwap;
#else
- const UpdateUniformOption uniformOption = (flags & QPlatformBackingStore::TextureSwizzle) != 0? NeedsAlphaRotate : NoOption;
+ if (flags & QPlatformBackingStore::TextureSwizzle)
+ uniformOptions |= NeedsAlphaRotate;
#endif
const bool premultiplied = (flags & QPlatformBackingStore::TexturePremultiplied) != 0;
SourceTransformOrigin origin = SourceTransformOrigin::TopLeft;
@@ -522,19 +535,29 @@ QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatfo
const qreal dpr = window->devicePixelRatio();
const QRect deviceWindowRect = scaledRect(QRect(QPoint(), window->size()), dpr);
- const QPoint deviceWindowOffset = scaledOffset(offset, dpr);
+ const QRect sourceWindowRect = scaledRect(QRect(QPoint(), window->size()), sourceDevicePixelRatio);
+ // If sourceWindowRect is larger than deviceWindowRect, we are doing high
+ // DPI downscaling. In that case Linear filtering is a must, whereas for the
+ // 1:1 case Nearest must be used for Qt 5 visual compatibility.
+ const bool needsLinearSampler = sourceWindowRect.width() > deviceWindowRect.width()
+ && sourceWindowRect.height() > deviceWindowRect.height();
+
+ const bool invertTargetY = !rhi->isYUpInNDC();
+ const bool invertSource = !rhi->isYUpInFramebuffer();
- const bool invertTargetY = rhi->clipSpaceCorrMatrix().data()[5] < 0.0f;
- const bool invertSource = rhi->isYUpInFramebuffer() != rhi->isYUpInNDC();
if (m_texture) {
- // The backingstore is for the entire tlw.
- // In case of native children offset tells the position relative to the tlw.
- const QRect srcRect = toBottomLeftRect(deviceWindowRect.translated(deviceWindowOffset), m_texture->pixelSize().height());
+ // The backingstore is for the entire tlw. In case of native children, offset tells the position
+ // relative to the tlw. The window rect is scaled by the source device pixel ratio to get
+ // the source rect.
+ const QPoint sourceWindowOffset = scaledOffset(offset, sourceDevicePixelRatio);
+ const QRect srcRect = toBottomLeftRect(sourceWindowRect.translated(sourceWindowOffset), m_texture->pixelSize().height());
const QMatrix3x3 source = sourceTransform(srcRect, m_texture->pixelSize(), origin);
QMatrix4x4 target; // identity
if (invertTargetY)
target.data()[5] = -1.0f;
- updateUniforms(&m_widgetQuadData, resourceUpdates, target, source, uniformOption);
+ updateUniforms(&m_widgetQuadData, resourceUpdates, target, source, uniformOptions);
+ if (needsLinearSampler)
+ updatePerQuadData(&m_widgetQuadData, m_texture.get(), nullptr, NeedsLinearFiltering);
}
const int textureWidgetCount = textures->count();
@@ -546,10 +569,13 @@ QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatfo
}
for (int i = 0; i < textureWidgetCount; ++i) {
+ const bool invertSourceForTextureWidget = textures->flags(i).testFlag(QPlatformTextureList::MirrorVertically)
+ ? !invertSource : invertSource;
QMatrix4x4 target;
QMatrix3x3 source;
if (!prepareDrawForRenderToTextureWidget(textures, i, window, deviceWindowRect,
- offset, invertTargetY, invertSource, &target, &source))
+ offset, invertTargetY, invertSourceForTextureWidget,
+ &target, &source))
{
m_textureQuadData[i].reset();
continue;
@@ -557,13 +583,13 @@ QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatfo
QRhiTexture *t = textures->texture(i);
QRhiTexture *tExtra = textures->textureExtra(i);
if (t) {
- if (!m_textureQuadData[i].isValid()) {
+ if (!m_textureQuadData[i].isValid())
m_textureQuadData[i] = createPerQuadData(t, tExtra);
- }
- else {
+ else
updatePerQuadData(&m_textureQuadData[i], t, tExtra);
- }
- updateUniforms(&m_textureQuadData[i], resourceUpdates, target, source, NoOption);
+ updateUniforms(&m_textureQuadData[i], resourceUpdates, target, source);
+ if (needsLinearSampler)
+ updatePerQuadData(&m_textureQuadData[i], t, tExtra, NeedsLinearFiltering);
} else {
m_textureQuadData[i].reset();
}
@@ -585,9 +611,9 @@ QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatfo
cb->beginPass(target, clearColor, { 1.0f, 0 });
- cb->setGraphicsPipeline(m_psNoBlend);
+ cb->setGraphicsPipeline(m_psNoBlend.get());
cb->setViewport({ 0, 0, float(outputSizeInPixels.width()), float(outputSizeInPixels.height()) });
- QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf, 0);
+ QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf.get(), 0);
cb->setVertexInput(0, 1, &vbufBinding);
// Textures for renderToTexture widgets.
@@ -605,7 +631,7 @@ QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatfo
}
}
- cb->setGraphicsPipeline(premultiplied ? m_psPremulBlend : m_psBlend);
+ cb->setGraphicsPipeline(premultiplied ? m_psPremulBlend.get() : m_psBlend.get());
// Backingstore texture with the normal widgets.
if (m_texture) {
@@ -619,9 +645,9 @@ QPlatformBackingStore::FlushResult QBackingStoreDefaultCompositor::flush(QPlatfo
if (flags.testFlag(QPlatformTextureList::StacksOnTop)) {
if (m_textureQuadData[i].isValid()) {
if (flags.testFlag(QPlatformTextureList::NeedsPremultipliedAlphaBlending))
- cb->setGraphicsPipeline(m_psPremulBlend);
+ cb->setGraphicsPipeline(m_psPremulBlend.get());
else
- cb->setGraphicsPipeline(m_psBlend);
+ cb->setGraphicsPipeline(m_psBlend.get());
QRhiShaderResourceBindings* srb = m_textureQuadData[i].srb;
if (buffer == QRhiSwapChain::RightBuffer && m_textureQuadData[i].srbExtra)
diff --git a/src/gui/painting/qbackingstoredefaultcompositor_p.h b/src/gui/painting/qbackingstoredefaultcompositor_p.h
index d69c17f98f..c5a8ffd328 100644
--- a/src/gui/painting/qbackingstoredefaultcompositor_p.h
+++ b/src/gui/painting/qbackingstoredefaultcompositor_p.h
@@ -16,7 +16,7 @@
//
#include <qpa/qplatformbackingstore.h>
-#include <QtGui/private/qrhi_p.h>
+#include <rhi/qrhi.h>
QT_BEGIN_NAMESPACE
@@ -45,12 +45,16 @@ public:
private:
enum UpdateUniformOption {
- NoOption = 0x00,
- NeedsRedBlueSwap = 0x01,
- NeedsAlphaRotate = 0x02,
+ NeedsRedBlueSwap = 1 << 0,
+ NeedsAlphaRotate = 1 << 1
};
+ Q_DECLARE_FLAGS(UpdateUniformOptions, UpdateUniformOption)
+ enum UpdateQuadDataOption {
+ NeedsLinearFiltering = 1 << 0
+ };
+ Q_DECLARE_FLAGS(UpdateQuadDataOptions, UpdateQuadDataOption)
- void ensureResources(QRhiSwapChain *swapchain, QRhiResourceUpdateBatch *resourceUpdates);
+ void ensureResources(QRhiResourceUpdateBatch *resourceUpdates, QRhiRenderPassDescriptor *rpDesc);
QRhiTexture *toTexture(const QImage &image,
QRhi *rhi,
QRhiResourceUpdateBatch *resourceUpdates,
@@ -58,13 +62,14 @@ private:
QPlatformBackingStore::TextureFlags *flags) const;
mutable QRhi *m_rhi = nullptr;
- mutable QRhiTexture *m_texture = nullptr;
+ mutable std::unique_ptr<QRhiTexture> m_texture;
- QRhiBuffer *m_vbuf = nullptr;
- QRhiSampler *m_sampler = nullptr;
- QRhiGraphicsPipeline *m_psNoBlend = nullptr;
- QRhiGraphicsPipeline *m_psBlend = nullptr;
- QRhiGraphicsPipeline *m_psPremulBlend = nullptr;
+ std::unique_ptr<QRhiBuffer> m_vbuf;
+ std::unique_ptr<QRhiSampler> m_samplerNearest;
+ std::unique_ptr<QRhiSampler> m_samplerLinear;
+ std::unique_ptr<QRhiGraphicsPipeline> m_psNoBlend;
+ std::unique_ptr<QRhiGraphicsPipeline> m_psBlend;
+ std::unique_ptr<QRhiGraphicsPipeline> m_psPremulBlend;
struct PerQuadData {
QRhiBuffer *ubuf = nullptr;
@@ -73,6 +78,7 @@ private:
QRhiShaderResourceBindings *srbExtra = nullptr; // may be null (used for stereo)
QRhiTexture *lastUsedTexture = nullptr;
QRhiTexture *lastUsedTextureExtra = nullptr; // may be null (used for stereo)
+ QRhiSampler::Filter lastUsedFilter = QRhiSampler::None;
bool isValid() const { return ubuf && srb; }
void reset() {
delete ubuf;
@@ -85,15 +91,18 @@ private:
}
lastUsedTexture = nullptr;
lastUsedTextureExtra = nullptr;
+ lastUsedFilter = QRhiSampler::None;
}
};
PerQuadData m_widgetQuadData;
QVarLengthArray<PerQuadData, 8> m_textureQuadData;
PerQuadData createPerQuadData(QRhiTexture *texture, QRhiTexture *textureExtra = nullptr);
- void updatePerQuadData(PerQuadData *d, QRhiTexture *texture, QRhiTexture *textureExtra = nullptr);
+ void updatePerQuadData(PerQuadData *d, QRhiTexture *texture, QRhiTexture *textureExtra = nullptr,
+ UpdateQuadDataOptions options = {});
void updateUniforms(PerQuadData *d, QRhiResourceUpdateBatch *resourceUpdates,
- const QMatrix4x4 &target, const QMatrix3x3 &source, UpdateUniformOption option);
+ const QMatrix4x4 &target, const QMatrix3x3 &source,
+ UpdateUniformOptions options = {});
};
QT_END_NAMESPACE
diff --git a/src/gui/painting/qbackingstorerhisupport.cpp b/src/gui/painting/qbackingstorerhisupport.cpp
index 05329d61c5..fe5589dc2d 100644
--- a/src/gui/painting/qbackingstorerhisupport.cpp
+++ b/src/gui/painting/qbackingstorerhisupport.cpp
@@ -8,20 +8,9 @@
#if QT_CONFIG(opengl)
#include <QtGui/qoffscreensurface.h>
#include <QtGui/private/qopenglcontext_p.h>
-#include <QtGui/private/qrhigles2_p.h>
-#endif
-
-#ifdef Q_OS_WIN
-#include <QtGui/private/qrhid3d11_p.h>
-#include <QtGui/private/qrhid3d12_p.h>
-#endif
-
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
-#include <QtGui/private/qrhimetal_p.h>
#endif
#if QT_CONFIG(vulkan)
-#include <QtGui/private/qrhivulkan_p.h>
#include <QtGui/private/qvulkandefaultinstance_p.h>
#endif
@@ -67,6 +56,19 @@ bool QBackingStoreRhiSupport::create()
QOffscreenSurface *surface = nullptr;
QRhi::Flags flags;
+ // These must be the same env.vars Qt Quick uses (as documented), in order
+ // to ensure symmetry in the behavior between a QQuickWindow and a
+ // (QRhi-based) widget top-level window.
+ if (qEnvironmentVariableIntValue("QSG_RHI_PREFER_SOFTWARE_RENDERER"))
+ flags |= QRhi::PreferSoftwareRenderer;
+ if (qEnvironmentVariableIntValue("QSG_RHI_PROFILE"))
+ flags |= QRhi::EnableDebugMarkers | QRhi::EnableTimestamps;
+
+ if (m_config.api() == QPlatformBackingStoreRhiConfig::Null) {
+ QRhiNullInitParams params;
+ rhi = QRhi::create(QRhi::Null, &params, flags);
+ }
+
#if QT_CONFIG(opengl)
if (!rhi && m_config.api() == QPlatformBackingStoreRhiConfig::OpenGL) {
surface = QRhiGles2InitParams::newFallbackSurface(m_format);
@@ -86,7 +88,7 @@ bool QBackingStoreRhiSupport::create()
params.enableDebugLayer = m_config.isDebugLayerEnabled();
rhi = QRhi::create(QRhi::D3D11, &params, flags);
if (!rhi && !flags.testFlag(QRhi::PreferSoftwareRenderer)) {
- qCDebug(lcQpaBackingStore, "Failed to create a D3D device with default settings; "
+ qCDebug(lcQpaBackingStore, "Failed to create a D3D11 device with default settings; "
"attempting to get a software rasterizer backed device instead");
flags |= QRhi::PreferSoftwareRenderer;
rhi = QRhi::create(QRhi::D3D11, &params, flags);
@@ -95,11 +97,17 @@ bool QBackingStoreRhiSupport::create()
QRhiD3D12InitParams params;
params.enableDebugLayer = m_config.isDebugLayerEnabled();
rhi = QRhi::create(QRhi::D3D12, &params, flags);
+ if (!rhi && !flags.testFlag(QRhi::PreferSoftwareRenderer)) {
+ qCDebug(lcQpaBackingStore, "Failed to create a D3D12 device with default settings; "
+ "attempting to get a software rasterizer backed device instead");
+ flags |= QRhi::PreferSoftwareRenderer;
+ rhi = QRhi::create(QRhi::D3D12, &params, flags);
+ }
}
}
#endif
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+#if QT_CONFIG(metal)
if (!rhi && m_config.api() == QPlatformBackingStoreRhiConfig::Metal) {
QRhiMetalInitParams params;
// For parity with Qt Quick, fall back to OpenGL when there is no Metal (f.ex. in macOS virtual machines).
@@ -188,13 +196,14 @@ QRhiSwapChain *QBackingStoreRhiSupport::swapChainForWindow(QWindow *window)
bool QBackingStoreRhiSupportWindowWatcher::eventFilter(QObject *obj, QEvent *event)
{
- if (event->type() == QEvent::PlatformSurface
- && static_cast<QPlatformSurfaceEvent *>(event)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed)
+ if (event->type() == QEvent::WindowAboutToChangeInternal
+ || (event->type() == QEvent::PlatformSurface
+ && static_cast<QPlatformSurfaceEvent *>(event)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed))
{
QWindow *window = qobject_cast<QWindow *>(obj);
auto it = m_rhiSupport->m_swapchains.find(window);
if (it != m_rhiSupport->m_swapchains.end()) {
- qCDebug(lcQpaBackingStore) << "SurfaceAboutToBeDestroyed received for tracked window" << window << "cleaning up swapchain";
+ qCDebug(lcQpaBackingStore) << event << "received for" << window << "- cleaning up swapchain";
auto data = *it;
m_rhiSupport->m_swapchains.erase(it);
data.reset(); // deletes 'this'
@@ -263,7 +272,7 @@ bool QBackingStoreRhiSupport::checkForceRhi(QPlatformBackingStoreRhiConfig *outC
if (config.isEnabled()) {
#if defined(Q_OS_WIN)
config.setApi(QPlatformBackingStoreRhiConfig::D3D11);
-#elif defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+#elif QT_CONFIG(metal)
config.setApi(QPlatformBackingStoreRhiConfig::Metal);
#elif QT_CONFIG(opengl)
config.setApi(QPlatformBackingStoreRhiConfig::OpenGL);
@@ -283,7 +292,7 @@ bool QBackingStoreRhiSupport::checkForceRhi(QPlatformBackingStoreRhiConfig *outC
if (backend == QStringLiteral("d3d12"))
config.setApi(QPlatformBackingStoreRhiConfig::D3D12);
#endif
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+#if QT_CONFIG(metal)
if (backend == QStringLiteral("metal"))
config.setApi(QPlatformBackingStoreRhiConfig::Metal);
#endif
diff --git a/src/gui/painting/qbackingstorerhisupport_p.h b/src/gui/painting/qbackingstorerhisupport_p.h
index c8aa8f46ea..39ce36c680 100644
--- a/src/gui/painting/qbackingstorerhisupport_p.h
+++ b/src/gui/painting/qbackingstorerhisupport_p.h
@@ -19,7 +19,7 @@
#include <QtGui/qwindow.h>
#include <QtGui/qsurfaceformat.h>
#include <QtGui/qoffscreensurface.h>
-#include <QtGui/private/qrhi_p.h>
+#include <rhi/qrhi.h>
#include <qpa/qplatformbackingstore.h>
QT_BEGIN_NAMESPACE
diff --git a/src/gui/painting/qbezier_p.h b/src/gui/painting/qbezier_p.h
index 373a35b2be..6c39dd55f9 100644
--- a/src/gui/painting/qbezier_p.h
+++ b/src/gui/painting/qbezier_p.h
@@ -18,7 +18,6 @@
#include <QtGui/private/qtguiglobal_p.h>
#include "QtCore/qline.h"
#include "QtCore/qlist.h"
-#include "QtCore/qpair.h"
#include "QtCore/qpoint.h"
#include "QtCore/qrect.h"
#include "QtGui/qtransform.h"
diff --git a/src/gui/painting/qblendfunctions.cpp b/src/gui/painting/qblendfunctions.cpp
index 2a51d06204..fa9f89262c 100644
--- a/src/gui/painting/qblendfunctions.cpp
+++ b/src/gui/painting/qblendfunctions.cpp
@@ -152,7 +152,7 @@ void qt_blend_rgb16_on_rgb16(uchar *dst, int dbpl,
if (const_alpha == 256) {
int length = w << 1;
- while (h--) {
+ while (--h >= 0) {
memcpy(dst, src, length);
dst += dbpl;
src += sbpl;
@@ -162,7 +162,7 @@ void qt_blend_rgb16_on_rgb16(uchar *dst, int dbpl,
const quint16 *s = (const quint16 *) src;
quint8 a = (255 * const_alpha) >> 8;
quint8 ia = 255 - a;
- while (h--) {
+ while (--h >= 0) {
for (int x=0; x<w; ++x) {
d[x] = BYTE_MUL_RGB16(s[x], a) + BYTE_MUL_RGB16(d[x], ia);
}
diff --git a/src/gui/painting/qblendfunctions_p.h b/src/gui/painting/qblendfunctions_p.h
index 90a7dbcf64..2f5ed36c73 100644
--- a/src/gui/painting/qblendfunctions_p.h
+++ b/src/gui/painting/qblendfunctions_p.h
@@ -89,7 +89,7 @@ void qt_scale_image_16bit(uchar *destPixels, int dbpl,
if (xend < 0 || xend >= (int)(sbpl/sizeof(SRC)))
--w;
- while (h--) {
+ while (--h >= 0) {
const SRC *src = (const SRC *) (srcPixels + (srcy >> 16) * sbpl);
quint32 srcx = basex;
int x = 0;
@@ -180,7 +180,7 @@ template <typename T> void qt_scale_image_32bit(uchar *destPixels, int dbpl,
if (xend < 0 || xend >= (int)(sbpl/sizeof(quint32)))
--w;
- while (h--) {
+ while (--h >= 0) {
const uint *src = (const quint32 *) (srcPixels + (srcy >> 16) * sbpl);
quint32 srcx = basex;
int x = 0;
diff --git a/src/gui/painting/qcmyk_p.h b/src/gui/painting/qcmyk_p.h
new file mode 100644
index 0000000000..d00a4b5a6e
--- /dev/null
+++ b/src/gui/painting/qcmyk_p.h
@@ -0,0 +1,88 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QCMYK_P_H
+#define QCMYK_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/qcolor.h>
+
+QT_BEGIN_NAMESPACE
+
+class QCmyk32
+{
+private:
+ uint m_cmyk = 0;
+
+public:
+ QCmyk32() = default;
+
+ constexpr QCmyk32(int cyan, int magenta, int yellow, int black) :
+#if QT_BYTE_ORDER == Q_BIG_ENDIAN
+ m_cmyk(cyan << 24 | magenta << 16 | yellow << 8 | black)
+#else
+ m_cmyk(cyan | magenta << 8 | yellow << 16 | black << 24)
+#endif
+ {
+ }
+
+#if QT_BYTE_ORDER == Q_BIG_ENDIAN
+ constexpr int cyan() const noexcept { return (m_cmyk >> 24) & 0xff; }
+ constexpr int magenta() const noexcept { return (m_cmyk >> 16) & 0xff; }
+ constexpr int yellow() const noexcept { return (m_cmyk >> 8) & 0xff; }
+ constexpr int black() const noexcept { return (m_cmyk ) & 0xff; }
+#else
+ constexpr int cyan() const noexcept { return (m_cmyk ) & 0xff; }
+ constexpr int magenta() const noexcept { return (m_cmyk >> 8) & 0xff; }
+ constexpr int yellow() const noexcept { return (m_cmyk >> 16) & 0xff; }
+ constexpr int black() const noexcept { return (m_cmyk >> 24) & 0xff; }
+#endif
+
+ QColor toColor() const noexcept
+ {
+ return QColor::fromCmyk(cyan(), magenta(), yellow(), black());
+ }
+
+ constexpr uint toUint() const noexcept
+ {
+ return m_cmyk;
+ }
+
+ constexpr static QCmyk32 fromCmyk32(uint cmyk) noexcept
+ {
+ QCmyk32 result;
+ result.m_cmyk = cmyk;
+ return result;
+ }
+
+ static QCmyk32 fromRgba(QRgb rgba) noexcept
+ {
+ const QColor c = QColor(rgba).toCmyk();
+ return QCmyk32(c.cyan(), c.magenta(), c.yellow(), c.black());
+ }
+
+ static QCmyk32 fromColor(const QColor &color) noexcept
+ {
+ QColor c = color.toCmyk();
+ return QCmyk32(c.cyan(), c.magenta(), c.yellow(), c.black());
+ }
+};
+
+static_assert(sizeof(QCmyk32) == sizeof(int));
+static_assert(alignof(QCmyk32) == alignof(int));
+static_assert(std::is_standard_layout_v<QCmyk32>);
+
+QT_END_NAMESPACE
+
+#endif // QCMYK_P_H
diff --git a/src/gui/painting/qcolorclut_p.h b/src/gui/painting/qcolorclut_p.h
new file mode 100644
index 0000000000..d95e9701b7
--- /dev/null
+++ b/src/gui/painting/qcolorclut_p.h
@@ -0,0 +1,127 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QCOLORCLUT_H
+#define QCOLORCLUT_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/qlist.h>
+#include <QtGui/private/qcolormatrix_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// A 3/4-dimensional lookup table compatible with ICC lut8, lut16, mAB, and mBA formats.
+class QColorCLUT
+{
+ inline static QColorVector interpolate(const QColorVector &a, const QColorVector &b, float t)
+ {
+ return a + (b - a) * t; // faster than std::lerp by assuming no super large or non-number floats
+ }
+ inline static void interpolateIn(QColorVector &a, const QColorVector &b, float t)
+ {
+ a += (b - a) * t;
+ }
+public:
+ uint32_t gridPointsX = 0;
+ uint32_t gridPointsY = 0;
+ uint32_t gridPointsZ = 0;
+ uint32_t gridPointsW = 1;
+ QList<QColorVector> table;
+
+ bool isEmpty() const { return table.isEmpty(); }
+
+ QColorVector apply(const QColorVector &v) const
+ {
+ Q_ASSERT(table.size() == gridPointsX * gridPointsY * gridPointsZ * gridPointsW);
+ QColorVector frac;
+ const float x = std::clamp(v.x, 0.0f, 1.0f) * (gridPointsX - 1);
+ const float y = std::clamp(v.y, 0.0f, 1.0f) * (gridPointsY - 1);
+ const float z = std::clamp(v.z, 0.0f, 1.0f) * (gridPointsZ - 1);
+ const float w = std::clamp(v.w, 0.0f, 1.0f) * (gridPointsW - 1);
+ const uint32_t lox = static_cast<uint32_t>(std::floor(x));
+ const uint32_t hix = std::min(lox + 1, gridPointsX - 1);
+ const uint32_t loy = static_cast<uint32_t>(std::floor(y));
+ const uint32_t hiy = std::min(loy + 1, gridPointsY - 1);
+ const uint32_t loz = static_cast<uint32_t>(std::floor(z));
+ const uint32_t hiz = std::min(loz + 1, gridPointsZ - 1);
+ const uint32_t low = static_cast<uint32_t>(std::floor(w));
+ const uint32_t hiw = std::min(low + 1, gridPointsW - 1);
+ frac.x = x - static_cast<float>(lox);
+ frac.y = y - static_cast<float>(loy);
+ frac.z = z - static_cast<float>(loz);
+ frac.w = w - static_cast<float>(low);
+ if (gridPointsW > 1) {
+ auto index = [&](qsizetype x, qsizetype y, qsizetype z, qsizetype w) -> qsizetype {
+ return x * gridPointsW * gridPointsZ * gridPointsY
+ + y * gridPointsW * gridPointsZ
+ + z * gridPointsW
+ + w;
+ };
+ QColorVector tmp[8];
+ // interpolate over w
+ tmp[0] = interpolate(table[index(lox, loy, loz, low)],
+ table[index(lox, loy, loz, hiw)], frac.w);
+ tmp[1] = interpolate(table[index(lox, loy, hiz, low)],
+ table[index(lox, loy, hiz, hiw)], frac.w);
+ tmp[2] = interpolate(table[index(lox, hiy, loz, low)],
+ table[index(lox, hiy, loz, hiw)], frac.w);
+ tmp[3] = interpolate(table[index(lox, hiy, hiz, low)],
+ table[index(lox, hiy, hiz, hiw)], frac.w);
+ tmp[4] = interpolate(table[index(hix, loy, loz, low)],
+ table[index(hix, loy, loz, hiw)], frac.w);
+ tmp[5] = interpolate(table[index(hix, loy, hiz, low)],
+ table[index(hix, loy, hiz, hiw)], frac.w);
+ tmp[6] = interpolate(table[index(hix, hiy, loz, low)],
+ table[index(hix, hiy, loz, hiw)], frac.w);
+ tmp[7] = interpolate(table[index(hix, hiy, hiz, low)],
+ table[index(hix, hiy, hiz, hiw)], frac.w);
+ // interpolate over z
+ for (int i = 0; i < 4; ++i)
+ interpolateIn(tmp[i * 2], tmp[i * 2 + 1], frac.z);
+ // interpolate over y
+ for (int i = 0; i < 2; ++i)
+ interpolateIn(tmp[i * 4], tmp[i * 4 + 2], frac.y);
+ // interpolate over x
+ interpolateIn(tmp[0], tmp[4], frac.x);
+ return tmp[0];
+ }
+ auto index = [&](qsizetype x, qsizetype y, qsizetype z) -> qsizetype {
+ return x * gridPointsZ * gridPointsY
+ + y * gridPointsZ
+ + z;
+ };
+ QColorVector tmp[8] = {
+ table[index(lox, loy, loz)],
+ table[index(lox, loy, hiz)],
+ table[index(lox, hiy, loz)],
+ table[index(lox, hiy, hiz)],
+ table[index(hix, loy, loz)],
+ table[index(hix, loy, hiz)],
+ table[index(hix, hiy, loz)],
+ table[index(hix, hiy, hiz)]
+ };
+ // interpolate over z
+ for (int i = 0; i < 4; ++i)
+ interpolateIn(tmp[i * 2], tmp[i * 2 + 1], frac.z);
+ // interpolate over y
+ for (int i = 0; i < 2; ++i)
+ interpolateIn(tmp[i * 4], tmp[i * 4 + 2], frac.y);
+ // interpolate over x
+ interpolateIn(tmp[0], tmp[4], frac.x);
+ return tmp[0];
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif // QCOLORCLUT_H
diff --git a/src/gui/painting/qcolormatrix_p.h b/src/gui/painting/qcolormatrix_p.h
index 1ce5df6264..6a9b9f4f9a 100644
--- a/src/gui/painting/qcolormatrix_p.h
+++ b/src/gui/painting/qcolormatrix_p.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOLORMATRIX_H
@@ -18,6 +18,7 @@
#include <QtGui/qtguiglobal.h>
#include <QtCore/qpoint.h>
#include <QtCore/private/qglobal_p.h>
+#include <QtCore/private/qsimd_p.h>
#include <cmath>
QT_BEGIN_NAMESPACE
@@ -27,25 +28,24 @@ class QColorVector
{
public:
QColorVector() = default;
- constexpr QColorVector(float x, float y, float z) : x(x), y(y), z(z) { }
- explicit constexpr QColorVector(const QPointF &chr) // from XY chromaticity
- : x(chr.x() / chr.y())
- , y(1.0f)
- , z((1.0 - chr.x() - chr.y()) / chr.y())
- { }
- float x = 0.0f; // X, x or red
- float y = 0.0f; // Y, y or green
- float z = 0.0f; // Z, Y or blue
- float _unused = 0.0f;
+ constexpr QColorVector(float x, float y, float z, float w = 0.0f) noexcept : x(x), y(y), z(z), w(w) { }
+ static constexpr QColorVector fromXYChromaticity(QPointF chr)
+ { return {float(chr.x() / chr.y()), 1.0f, float((1.0f - chr.x() - chr.y()) / chr.y())}; }
+ float x = 0.0f; // X, x, L, or red/cyan
+ float y = 0.0f; // Y, y, a, or green/magenta
+ float z = 0.0f; // Z, Y, b, or blue/yellow
+ float w = 0.0f; // unused, or black
- friend inline bool operator==(const QColorVector &v1, const QColorVector &v2);
- friend inline bool operator!=(const QColorVector &v1, const QColorVector &v2);
- bool isNull() const
+ constexpr bool isNull() const noexcept
{
- return !x && !y && !z;
+ return !x && !y && !z && !w;
+ }
+ bool isValid() const noexcept
+ {
+ return std::isfinite(x) && std::isfinite(y) && std::isfinite(z);
}
- static bool isValidChromaticity(const QPointF &chr)
+ static constexpr bool isValidChromaticity(const QPointF &chr)
{
if (chr.x() < qreal(0.0) || chr.x() > qreal(1.0))
return false;
@@ -56,26 +56,149 @@ public:
return true;
}
+ constexpr QColorVector operator*(float f) const { return QColorVector(x * f, y * f, z * f, w * f); }
+ constexpr QColorVector operator+(const QColorVector &v) const { return QColorVector(x + v.x, y + v.y, z + v.z, w + v.w); }
+ constexpr QColorVector operator-(const QColorVector &v) const { return QColorVector(x - v.x, y - v.y, z - v.z, w - v.w); }
+ void operator+=(const QColorVector &v) { x += v.x; y += v.y; z += v.z; w += v.w; }
+
+ QPointF toChromaticity() const
+ {
+ if (isNull())
+ return QPointF();
+ float mag = 1.0f / (x + y + z);
+ return QPointF(x * mag, y * mag);
+ }
+
// Common whitepoints:
static constexpr QPointF D50Chromaticity() { return QPointF(0.34567, 0.35850); }
static constexpr QPointF D65Chromaticity() { return QPointF(0.31271, 0.32902); }
- static constexpr QColorVector D50() { return QColorVector(D50Chromaticity()); }
- static constexpr QColorVector D65() { return QColorVector(D65Chromaticity()); }
+ static constexpr QColorVector D50() { return fromXYChromaticity(D50Chromaticity()); }
+ static constexpr QColorVector D65() { return fromXYChromaticity(D65Chromaticity()); }
+
+ QColorVector xyzToLab() const
+ {
+ constexpr QColorVector ref = D50();
+ constexpr float eps = 0.008856f;
+ constexpr float kap = 903.3f;
+#if defined(__SSE2__)
+ const __m128 iref = _mm_setr_ps(1.f / ref.x, 1.f / ref.y, 1.f / ref.z, 0.f);
+ __m128 v = _mm_loadu_ps(&x);
+ v = _mm_mul_ps(v, iref);
+
+ const __m128 f3 = _mm_set1_ps(3.f);
+ __m128 est = _mm_add_ps(_mm_set1_ps(0.25f), _mm_mul_ps(v, _mm_set1_ps(0.75f))); // float est = 0.25f + (x * 0.75f);
+ __m128 estsq = _mm_mul_ps(est, est);
+ est = _mm_sub_ps(est, _mm_mul_ps(_mm_sub_ps(_mm_mul_ps(estsq, est), v),
+ _mm_rcp_ps(_mm_mul_ps(estsq, f3)))); // est -= ((est * est * est) - x) / (3.f * (est * est));
+ estsq = _mm_mul_ps(est, est);
+ est = _mm_sub_ps(est, _mm_mul_ps(_mm_sub_ps(_mm_mul_ps(estsq, est), v),
+ _mm_rcp_ps(_mm_mul_ps(estsq, f3)))); // est -= ((est * est * est) - x) / (3.f * (est * est));
+ estsq = _mm_mul_ps(est, est);
+ est = _mm_sub_ps(est, _mm_mul_ps(_mm_sub_ps(_mm_mul_ps(estsq, est), v),
+ _mm_rcp_ps(_mm_mul_ps(estsq, f3)))); // est -= ((est * est * est) - x) / (3.f * (est * est));
+ estsq = _mm_mul_ps(est, est);
+ est = _mm_sub_ps(est, _mm_mul_ps(_mm_sub_ps(_mm_mul_ps(estsq, est), v),
+ _mm_rcp_ps(_mm_mul_ps(estsq, f3)))); // est -= ((est * est * est) - x) / (3.f * (est * est));
+
+ __m128 kapmul = _mm_mul_ps(_mm_add_ps(_mm_mul_ps(v, _mm_set1_ps(kap)), _mm_set1_ps(16.f)),
+ _mm_set1_ps(1.f / 116.f)); // f_ = (kap * f_ + 16.f) * (1.f / 116.f);
+ __m128 cmpgt = _mm_cmpgt_ps(v, _mm_set1_ps(eps)); // if (f_ > eps)
+#if defined(__SSE4_1__)
+ v = _mm_blendv_ps(kapmul, est, cmpgt); // if (..) f_ =.. else f_ =..
+#else
+ v = _mm_or_ps(_mm_and_ps(cmpgt, est), _mm_andnot_ps(cmpgt, kapmul));
+#endif
+ alignas(16) float out[4];
+ _mm_store_ps(out, v);
+ const float L = 116.f * out[1] - 16.f;
+ const float a = 500.f * (out[0] - out[1]);
+ const float b = 200.f * (out[1] - out[2]);
+#else
+ float xr = x * (1.f / ref.x);
+ float yr = y * (1.f / ref.y);
+ float zr = z * (1.f / ref.z);
+
+ float fx, fy, fz;
+ if (xr > eps)
+ fx = fastCbrt(xr);
+ else
+ fx = (kap * xr + 16.f) * (1.f / 116.f);
+ if (yr > eps)
+ fy = fastCbrt(yr);
+ else
+ fy = (kap * yr + 16.f) * (1.f / 116.f);
+ if (zr > eps)
+ fz = fastCbrt(zr);
+ else
+ fz = (kap * zr + 16.f) * (1.f / 116.f);
+
+ const float L = 116.f * fy - 16.f;
+ const float a = 500.f * (fx - fy);
+ const float b = 200.f * (fy - fz);
+#endif
+ // We output Lab values that has been scaled to 0.0->1.0 values, see also labToXyz.
+ return QColorVector(L * (1.f / 100.f), (a + 128.f) * (1.f / 255.f), (b + 128.f) * (1.f / 255.f));
+ }
+
+ QColorVector labToXyz() const
+ {
+ constexpr QColorVector ref = D50();
+ constexpr float eps = 0.008856f;
+ constexpr float kap = 903.3f;
+ // This transform has been guessed from the ICC spec, but it is not stated
+ // anywhere to be the one to use to map to and from 0.0->1.0 values:
+ const float L = x * 100.f;
+ const float a = (y * 255.f) - 128.f;
+ const float b = (z * 255.f) - 128.f;
+ // From here is official Lab->XYZ conversion:
+ float fy = (L + 16.f) * (1.f / 116.f);
+ float fx = fy + (a * (1.f / 500.f));
+ float fz = fy - (b * (1.f / 200.f));
+
+ float xr, yr, zr;
+ if (fx * fx * fx > eps)
+ xr = fx * fx * fx;
+ else
+ xr = (116.f * fx - 16) * (1.f / kap);
+ if (L > (kap * eps))
+ yr = fy * fy * fy;
+ else
+ yr = L * (1.f / kap);
+ if (fz * fz * fz > eps)
+ zr = fz * fz * fz;
+ else
+ zr = (116.f * fz - 16) * (1.f / kap);
+
+ xr = xr * ref.x;
+ yr = yr * ref.y;
+ zr = zr * ref.z;
+ return QColorVector(xr, yr, zr);
+ }
+ friend inline bool comparesEqual(const QColorVector &lhs, const QColorVector &rhs);
+ Q_DECLARE_EQUALITY_COMPARABLE(QColorVector);
+
+private:
+ static float fastCbrt(float x)
+ {
+ // This gives us cube root within the precision we need.
+ float est = 0.25f + (x * 0.75f); // guessing a cube-root of numbers between 0.01 and 1.
+ est -= ((est * est * est) - x) / (3.f * (est * est));
+ est -= ((est * est * est) - x) / (3.f * (est * est));
+ est -= ((est * est * est) - x) / (3.f * (est * est));
+ est -= ((est * est * est) - x) / (3.f * (est * est));
+ // Q_ASSERT(qAbs(est - std::cbrt(x)) < 0.0001f);
+ return est;
+ }
};
-inline bool operator==(const QColorVector &v1, const QColorVector &v2)
+inline bool comparesEqual(const QColorVector &v1, const QColorVector &v2)
{
return (std::abs(v1.x - v2.x) < (1.0f / 2048.0f))
&& (std::abs(v1.y - v2.y) < (1.0f / 2048.0f))
- && (std::abs(v1.z - v2.z) < (1.0f / 2048.0f));
+ && (std::abs(v1.z - v2.z) < (1.0f / 2048.0f))
+ && (std::abs(v1.w - v2.w) < (1.0f / 2048.0f));
}
-inline bool operator!=(const QColorVector &v1, const QColorVector &v2)
-{
- return !(v1 == v2);
-}
-
-
// A matrix mapping 3 value colors.
// Not using QTransform because only floats are needed and performance is critical.
class QColorMatrix
@@ -86,20 +209,20 @@ public:
QColorVector g;
QColorVector b;
- friend inline bool operator==(const QColorMatrix &m1, const QColorMatrix &m2);
- friend inline bool operator!=(const QColorMatrix &m1, const QColorMatrix &m2);
-
- bool isNull() const
+ constexpr bool isNull() const
{
return r.isNull() && g.isNull() && b.isNull();
}
+ constexpr float determinant() const
+ {
+ return r.x * (b.z * g.y - g.z * b.y) -
+ r.y * (b.z * g.x - g.z * b.x) +
+ r.z * (b.y * g.x - g.y * b.x);
+ }
bool isValid() const
{
// A color matrix must be invertible
- float det = r.x * (b.z * g.y - g.z * b.y) -
- r.y * (b.z * g.x - g.z * b.x) +
- r.z * (b.y * g.x - g.y * b.x);
- return !qFuzzyIsNull(det);
+ return std::isnormal(determinant());
}
bool isIdentity() const noexcept
{
@@ -108,9 +231,7 @@ public:
QColorMatrix inverted() const
{
- float det = r.x * (b.z * g.y - g.z * b.y) -
- r.y * (b.z * g.x - g.z * b.x) +
- r.z * (b.y * g.x - g.y * b.x);
+ float det = determinant();
det = 1.0f / det;
QColorMatrix inv;
inv.r.x = (g.y * b.z - b.y * g.z) * det;
@@ -124,20 +245,20 @@ public:
inv.b.z = (r.x * g.y - g.x * r.y) * det;
return inv;
}
- QColorMatrix operator*(const QColorMatrix &o) const
+ friend inline constexpr QColorMatrix operator*(const QColorMatrix &a, const QColorMatrix &o)
{
QColorMatrix comb;
- comb.r.x = r.x * o.r.x + g.x * o.r.y + b.x * o.r.z;
- comb.g.x = r.x * o.g.x + g.x * o.g.y + b.x * o.g.z;
- comb.b.x = r.x * o.b.x + g.x * o.b.y + b.x * o.b.z;
+ comb.r.x = a.r.x * o.r.x + a.g.x * o.r.y + a.b.x * o.r.z;
+ comb.g.x = a.r.x * o.g.x + a.g.x * o.g.y + a.b.x * o.g.z;
+ comb.b.x = a.r.x * o.b.x + a.g.x * o.b.y + a.b.x * o.b.z;
- comb.r.y = r.y * o.r.x + g.y * o.r.y + b.y * o.r.z;
- comb.g.y = r.y * o.g.x + g.y * o.g.y + b.y * o.g.z;
- comb.b.y = r.y * o.b.x + g.y * o.b.y + b.y * o.b.z;
+ comb.r.y = a.r.y * o.r.x + a.g.y * o.r.y + a.b.y * o.r.z;
+ comb.g.y = a.r.y * o.g.x + a.g.y * o.g.y + a.b.y * o.g.z;
+ comb.b.y = a.r.y * o.b.x + a.g.y * o.b.y + a.b.y * o.b.z;
- comb.r.z = r.z * o.r.x + g.z * o.r.y + b.z * o.r.z;
- comb.g.z = r.z * o.g.x + g.z * o.g.y + b.z * o.g.z;
- comb.b.z = r.z * o.b.x + g.z * o.b.y + b.z * o.b.z;
+ comb.r.z = a.r.z * o.r.x + a.g.z * o.r.y + a.b.z * o.r.z;
+ comb.g.z = a.r.z * o.g.x + a.g.z * o.g.y + a.b.z * o.g.z;
+ comb.b.z = a.r.z * o.b.x + a.g.z * o.b.y + a.b.z * o.b.z;
return comb;
}
@@ -164,6 +285,32 @@ public:
{ 0.0f, v.y, 0.0f },
{ 0.0f, 0.0f, v.z } };
}
+ static QColorMatrix chromaticAdaptation(const QColorVector &whitePoint)
+ {
+ constexpr QColorVector whitePointD50 = QColorVector::D50();
+ if (whitePoint != whitePointD50) {
+ // A chromatic adaptation to map a white point to XYZ D50.
+
+ // The Bradford method chromatic adaptation matrix:
+ const QColorMatrix abrad = { { 0.8951f, -0.7502f, 0.0389f },
+ { 0.2664f, 1.7135f, -0.0685f },
+ { -0.1614f, 0.0367f, 1.0296f } };
+ const QColorMatrix abradinv = { { 0.9869929f, 0.4323053f, -0.0085287f },
+ { -0.1470543f, 0.5183603f, 0.0400428f },
+ { 0.1599627f, 0.0492912f, 0.9684867f } };
+
+ const QColorVector srcCone = abrad.map(whitePoint);
+ if (srcCone.x && srcCone.y && srcCone.z) {
+ const QColorVector dstCone = abrad.map(whitePointD50);
+ const QColorMatrix wToD50 = { { dstCone.x / srcCone.x, 0, 0 },
+ { 0, dstCone.y / srcCone.y, 0 },
+ { 0, 0, dstCone.z / srcCone.z } };
+ return abradinv * (wToD50 * abrad);
+ }
+ }
+ return QColorMatrix::identity();
+ }
+
// These are used to recognize matrices from ICC profiles:
static QColorMatrix toXyzFromSRgb()
{
@@ -189,18 +336,15 @@ public:
{ 0.1351922452f, 0.7118769884f, 0.0000000000f },
{ 0.0313525312f, 0.0000856627f, 0.8251883388f } };
}
+ friend inline bool comparesEqual(const QColorMatrix &lhs, const QColorMatrix &rhs);
+ Q_DECLARE_EQUALITY_COMPARABLE(QColorMatrix);
};
-inline bool operator==(const QColorMatrix &m1, const QColorMatrix &m2)
+inline bool comparesEqual(const QColorMatrix &m1, const QColorMatrix &m2)
{
return (m1.r == m2.r) && (m1.g == m2.g) && (m1.b == m2.b);
}
-inline bool operator!=(const QColorMatrix &m1, const QColorMatrix &m2)
-{
- return !(m1 == m2);
-}
-
QT_END_NAMESPACE
#endif // QCOLORMATRIX_P_H
diff --git a/src/gui/painting/qcolorspace.cpp b/src/gui/painting/qcolorspace.cpp
index 487c295298..7a1d34a408 100644
--- a/src/gui/painting/qcolorspace.cpp
+++ b/src/gui/painting/qcolorspace.cpp
@@ -5,6 +5,7 @@
#include "qcolorspace_p.h"
#include "qcolortransform.h"
+#include "qcolorclut_p.h"
#include "qcolormatrix_p.h"
#include "qcolortransferfunction_p.h"
#include "qcolortransform_p.h"
@@ -80,49 +81,19 @@ bool QColorSpacePrimaries::areValid() const
QColorMatrix QColorSpacePrimaries::toXyzMatrix() const
{
// This converts to XYZ in some undefined scale.
- QColorMatrix toXyz = { QColorVector(redPoint),
- QColorVector(greenPoint),
- QColorVector(bluePoint) };
+ QColorMatrix toXyz = { QColorVector::fromXYChromaticity(redPoint),
+ QColorVector::fromXYChromaticity(greenPoint),
+ QColorVector::fromXYChromaticity(bluePoint) };
// Since the white point should be (1.0, 1.0, 1.0) in the
// input, we can figure out the scale by using the
// inverse conversion on the white point.
- QColorVector wXyz(whitePoint);
+ const auto wXyz = QColorVector::fromXYChromaticity(whitePoint);
QColorVector whiteScale = toXyz.inverted().map(wXyz);
// Now we have scaled conversion to XYZ relative to the given whitepoint
toXyz = toXyz * QColorMatrix::fromScale(whiteScale);
- // But we want a conversion to XYZ relative to D50
- QColorVector wXyzD50 = QColorVector::D50();
-
- if (wXyz != wXyzD50) {
- // Do chromatic adaptation to map our white point to XYZ D50.
-
- // The Bradford method chromatic adaptation matrix:
- QColorMatrix abrad = { { 0.8951f, -0.7502f, 0.0389f },
- { 0.2664f, 1.7135f, -0.0685f },
- { -0.1614f, 0.0367f, 1.0296f } };
- QColorMatrix abradinv = { { 0.9869929f, 0.4323053f, -0.0085287f },
- { -0.1470543f, 0.5183603f, 0.0400428f },
- { 0.1599627f, 0.0492912f, 0.9684867f } };
-
- QColorVector srcCone = abrad.map(wXyz);
- QColorVector dstCone = abrad.map(wXyzD50);
-
- if (srcCone.x && srcCone.y && srcCone.z) {
- QColorMatrix wToD50 = { { dstCone.x / srcCone.x, 0, 0 },
- { 0, dstCone.y / srcCone.y, 0 },
- { 0, 0, dstCone.z / srcCone.z } };
-
-
- QColorMatrix chromaticAdaptation = abradinv * (wToD50 * abrad);
- toXyz = chromaticAdaptation * toXyz;
- } else {
- toXyz.r = {0, 0, 0}; // set to invalid value
- }
- }
-
return toXyz;
}
@@ -132,6 +103,7 @@ QColorSpacePrivate::QColorSpacePrivate()
QColorSpacePrivate::QColorSpacePrivate(QColorSpace::NamedColorSpace namedColorSpace)
: namedColorSpace(namedColorSpace)
+ , colorModel(QColorSpace::ColorModel::Rgb)
{
switch (namedColorSpace) {
case QColorSpace::SRgb:
@@ -169,6 +141,7 @@ QColorSpacePrivate::QColorSpacePrivate(QColorSpace::NamedColorSpace namedColorSp
QColorSpacePrivate::QColorSpacePrivate(QColorSpace::Primaries primaries, QColorSpace::TransferFunction transferFunction, float gamma)
: primaries(primaries)
, transferFunction(transferFunction)
+ , colorModel(QColorSpace::ColorModel::Rgb)
, gamma(gamma)
{
identifyColorSpace();
@@ -180,18 +153,50 @@ QColorSpacePrivate::QColorSpacePrivate(const QColorSpacePrimaries &primaries,
float gamma)
: primaries(QColorSpace::Primaries::Custom)
, transferFunction(transferFunction)
+ , colorModel(QColorSpace::ColorModel::Rgb)
, gamma(gamma)
+ , whitePoint(QColorVector::fromXYChromaticity(primaries.whitePoint))
{
Q_ASSERT(primaries.areValid());
toXyz = primaries.toXyzMatrix();
- whitePoint = QColorVector(primaries.whitePoint);
+ chad = QColorMatrix::chromaticAdaptation(whitePoint);
+ toXyz = chad * toXyz;
+
identifyColorSpace();
setTransferFunction();
}
+QColorSpacePrivate::QColorSpacePrivate(const QPointF &whitePoint,
+ QColorSpace::TransferFunction transferFunction,
+ float gamma)
+ : primaries(QColorSpace::Primaries::Custom)
+ , transferFunction(transferFunction)
+ , colorModel(QColorSpace::ColorModel::Gray)
+ , gamma(gamma)
+ , whitePoint(QColorVector::fromXYChromaticity(whitePoint))
+{
+ chad = QColorMatrix::chromaticAdaptation(this->whitePoint);
+ toXyz = chad;
+ setTransferFunction();
+}
+
+QColorSpacePrivate::QColorSpacePrivate(const QPointF &whitePoint, const QList<uint16_t> &transferFunctionTable)
+ : primaries(QColorSpace::Primaries::Custom)
+ , transferFunction(QColorSpace::TransferFunction::Custom)
+ , colorModel(QColorSpace::ColorModel::Gray)
+ , gamma(0)
+ , whitePoint(QColorVector::fromXYChromaticity(whitePoint))
+{
+ chad = QColorMatrix::chromaticAdaptation(this->whitePoint);
+ toXyz = chad;
+ setTransferFunctionTable(transferFunctionTable);
+ setTransferFunction();
+}
+
QColorSpacePrivate::QColorSpacePrivate(QColorSpace::Primaries primaries, const QList<uint16_t> &transferFunctionTable)
: primaries(primaries)
, transferFunction(QColorSpace::TransferFunction::Custom)
+ , colorModel(QColorSpace::ColorModel::Rgb)
, gamma(0)
{
setTransferFunctionTable(transferFunctionTable);
@@ -202,11 +207,14 @@ QColorSpacePrivate::QColorSpacePrivate(QColorSpace::Primaries primaries, const Q
QColorSpacePrivate::QColorSpacePrivate(const QColorSpacePrimaries &primaries, const QList<uint16_t> &transferFunctionTable)
: primaries(QColorSpace::Primaries::Custom)
, transferFunction(QColorSpace::TransferFunction::Custom)
+ , colorModel(QColorSpace::ColorModel::Rgb)
, gamma(0)
+ , whitePoint(QColorVector::fromXYChromaticity(primaries.whitePoint))
{
Q_ASSERT(primaries.areValid());
toXyz = primaries.toXyzMatrix();
- whitePoint = QColorVector(primaries.whitePoint);
+ chad = QColorMatrix::chromaticAdaptation(whitePoint);
+ toXyz = chad * toXyz;
setTransferFunctionTable(transferFunctionTable);
identifyColorSpace();
initialize();
@@ -218,16 +226,18 @@ QColorSpacePrivate::QColorSpacePrivate(const QColorSpacePrimaries &primaries,
const QList<uint16_t> &blueTransferFunctionTable)
: primaries(QColorSpace::Primaries::Custom)
, transferFunction(QColorSpace::TransferFunction::Custom)
+ , colorModel(QColorSpace::ColorModel::Rgb)
, gamma(0)
{
Q_ASSERT(primaries.areValid());
toXyz = primaries.toXyzMatrix();
- whitePoint = QColorVector(primaries.whitePoint);
+ whitePoint = QColorVector::fromXYChromaticity(primaries.whitePoint);
+ chad = QColorMatrix::chromaticAdaptation(whitePoint);
+ toXyz = chad * toXyz;
setTransferFunctionTables(redTransferFunctionTable,
greenTransferFunctionTable,
blueTransferFunctionTable);
identifyColorSpace();
- setToXyzMatrix();
}
void QColorSpacePrivate::identifyColorSpace()
@@ -304,7 +314,9 @@ void QColorSpacePrivate::setToXyzMatrix()
}
QColorSpacePrimaries colorSpacePrimaries(primaries);
toXyz = colorSpacePrimaries.toXyzMatrix();
- whitePoint = QColorVector(colorSpacePrimaries.whitePoint);
+ whitePoint = QColorVector::fromXYChromaticity(colorSpacePrimaries.whitePoint);
+ chad = QColorMatrix::chromaticAdaptation(whitePoint);
+ toXyz = chad * toXyz;
}
void QColorSpacePrivate::setTransferFunctionTable(const QList<uint16_t> &transferFunctionTable)
@@ -319,7 +331,7 @@ void QColorSpacePrivate::setTransferFunctionTable(const QList<uint16_t> &transfe
QColorTransferFunction curve;
if (table.asColorTransferFunction(&curve)) {
// Table recognized as a specific curve
- if (curve.isLinear()) {
+ if (curve.isIdentity()) {
transferFunction = QColorSpace::TransferFunction::Linear;
gamma = 1.0f;
} else if (curve.isSRgb()) {
@@ -418,7 +430,12 @@ QColorTransform QColorSpacePrivate::transformationToColorSpace(const QColorSpace
combined.d = ptr;
ptr->colorSpaceIn = this;
ptr->colorSpaceOut = out;
- ptr->colorMatrix = out->toXyz.inverted() * toXyz;
+ if (isThreeComponentMatrix())
+ ptr->colorMatrix = toXyz;
+ else
+ ptr->colorMatrix = QColorMatrix::identity();
+ if (out->isThreeComponentMatrix())
+ ptr->colorMatrix = out->toXyz.inverted() * ptr->colorMatrix;
if (ptr->isIdentity())
return QColorTransform();
return combined;
@@ -431,10 +448,32 @@ QColorTransform QColorSpacePrivate::transformationToXYZ() const
transform.d = ptr;
ptr->colorSpaceIn = this;
ptr->colorSpaceOut = this;
- ptr->colorMatrix = toXyz;
+ // Convert to XYZ relative to our white point, not the regular D50 white point.
+ if (isThreeComponentMatrix())
+ ptr->colorMatrix = QColorMatrix::chromaticAdaptation(whitePoint).inverted() * toXyz;
+ else
+ ptr->colorMatrix = QColorMatrix::identity();
return transform;
}
+bool QColorSpacePrivate::isThreeComponentMatrix() const
+{
+ return transformModel == QColorSpace::TransformModel::ThreeComponentMatrix;
+}
+
+void QColorSpacePrivate::clearElementListProcessingForEdit()
+{
+ Q_ASSERT(transformModel == QColorSpace::TransformModel::ElementListProcessing);
+ Q_ASSERT(primaries == QColorSpace::Primaries::Custom);
+ Q_ASSERT(transferFunction == QColorSpace::TransferFunction::Custom);
+
+ transformModel = QColorSpace::TransformModel::ThreeComponentMatrix;
+ colorModel = QColorSpace::ColorModel::Rgb;
+ isPcsLab = false;
+ mAB.clear();
+ mBA.clear();
+}
+
/*!
\class QColorSpace
\brief The QColorSpace class provides a color space abstraction.
@@ -457,9 +496,10 @@ QColorTransform QColorSpacePrivate::transformationToXYZ() const
A color space can generally speaking be conceived as a combination of set of primary
colors and a transfer function. The primaries defines the axes of the color space, and
the transfer function how values are mapped on the axes.
- The primaries are defined by three primary colors that represent exactly how red, green,
- and blue look in this particular color space, and a white color that represents where
- and how bright pure white is. The range of colors expressible by the primary colors is
+ The primaries are for ColorModel::Rgb color spaces defined by three primary colors that
+ represent exactly how red, green, and blue look in this particular color space, and a white
+ color that represents where and how bright pure white is. For grayscale color spaces, only
+ a single white primary is needed. The range of colors expressible by the primary colors is
called the gamut, and a color space that can represent a wider range of colors is also
known as a wide-gamut color space.
@@ -513,6 +553,35 @@ QColorTransform QColorSpacePrivate::transformationToXYZ() const
*/
/*!
+ \enum QColorSpace::TransformModel
+ \since 6.8
+
+ Defines the processing model used for color space transforms.
+
+ \value ThreeComponentMatrix The transform consist of a matrix calculated from primaries and set of transfer functions
+ for each color channel. This is very fast and used by all predefined color spaces. Any color space on this form is
+ reversible and always both valid sources and targets.
+ \value ElementListProcessing The transforms are one or two lists of processing elements that can do many things,
+ each list only process either to the connection color space or from it. This is very flexible, but rather
+ slow, and can only be set by reading ICC profiles (See \l fromIccProfile()). Since the two lists are
+ separate a color space on this form can be a valid source, but not necessarily also a valid target. When changing
+ either primaries or transfer function on a color space on this type it will reset to an empty ThreeComponentMatrix form.
+*/
+
+/*!
+ \enum QColorSpace::ColorModel
+ \since 6.8
+
+ Defines the color model used by the color space data.
+
+ \value Undefined No color model
+ \value Rgb An RGB color model with red, green, and blue colors. Can apply to RGB and grayscale data.
+ \value Gray A gray scale color model. Can only apply to grayscale data.
+ \value Cmyk Can only represent color data defined with cyan, magenta, yellow, and black colors.
+ In effect only QImage::Format_CMYK32. Note Cmyk color spaces will be TransformModel::ElementListProcessing.
+*/
+
+/*!
\fn QColorSpace::QColorSpace()
Creates a new colorspace object that represents an undefined and invalid colorspace.
@@ -575,6 +644,28 @@ QColorSpace::QColorSpace(QColorSpace::Primaries gamut, const QList<uint16_t> &tr
}
/*!
+ Creates a custom grayscale color space with the white point \a whitePoint, using the transfer function \a transferFunction and
+ optionally \a gamma.
+
+ \since 6.8
+*/
+QColorSpace::QColorSpace(const QPointF &whitePoint, TransferFunction transferFunction, float gamma)
+ : d_ptr(new QColorSpacePrivate(whitePoint, transferFunction, gamma))
+{
+}
+
+/*!
+ Creates a custom grayscale color space with white point \a whitePoint, and using the custom transfer function described by
+ \a transferFunctionTable.
+
+ \since 6.8
+*/
+QColorSpace::QColorSpace(const QPointF &whitePoint, const QList<uint16_t> &transferFunctionTable)
+ : d_ptr(new QColorSpacePrivate(whitePoint, transferFunctionTable))
+{
+}
+
+/*!
Creates a custom colorspace with a primaries based on the chromaticities of the primary colors \a whitePoint,
\a redPoint, \a greenPoint and \a bluePoint, and using the transfer function \a transferFunction and optionally \a gamma.
*/
@@ -689,7 +780,10 @@ void QColorSpace::setTransferFunction(QColorSpace::TransferFunction transferFunc
if (d_ptr->transferFunction == transferFunction && d_ptr->gamma == gamma)
return;
detach();
- d_ptr->description.clear();
+ if (d_ptr->transformModel == TransformModel::ElementListProcessing)
+ d_ptr->clearElementListProcessingForEdit();
+ d_ptr->iccProfile = {};
+ d_ptr->description = QString();
d_ptr->transferFunction = transferFunction;
d_ptr->gamma = gamma;
d_ptr->identifyColorSpace();
@@ -710,7 +804,10 @@ void QColorSpace::setTransferFunction(const QList<uint16_t> &transferFunctionTab
return;
}
detach();
- d_ptr->description.clear();
+ if (d_ptr->transformModel == TransformModel::ElementListProcessing)
+ d_ptr->clearElementListProcessingForEdit();
+ d_ptr->iccProfile = {};
+ d_ptr->description = QString();
d_ptr->setTransferFunctionTable(transferFunctionTable);
d_ptr->gamma = 0;
d_ptr->identifyColorSpace();
@@ -737,7 +834,10 @@ void QColorSpace::setTransferFunctions(const QList<uint16_t> &redTransferFunctio
return;
}
detach();
- d_ptr->description.clear();
+ if (d_ptr->transformModel == TransformModel::ElementListProcessing)
+ d_ptr->clearElementListProcessingForEdit();
+ d_ptr->iccProfile = {};
+ d_ptr->description = QString();
d_ptr->setTransferFunctionTables(redTransferFunctionTable,
greenTransferFunctionTable,
blueTransferFunctionTable);
@@ -753,7 +853,7 @@ void QColorSpace::setTransferFunctions(const QList<uint16_t> &redTransferFunctio
*/
QColorSpace QColorSpace::withTransferFunction(QColorSpace::TransferFunction transferFunction, float gamma) const
{
- if (!isValid() || transferFunction == QColorSpace::TransferFunction::Custom)
+ if (!isValid() || transferFunction == TransferFunction::Custom)
return *this;
if (d_ptr->transferFunction == transferFunction && d_ptr->gamma == gamma)
return *this;
@@ -813,8 +913,12 @@ void QColorSpace::setPrimaries(QColorSpace::Primaries primariesId)
if (d_ptr->primaries == primariesId)
return;
detach();
- d_ptr->description.clear();
+ if (d_ptr->transformModel == TransformModel::ElementListProcessing)
+ d_ptr->clearElementListProcessingForEdit();
+ d_ptr->iccProfile = {};
+ d_ptr->description = QString();
d_ptr->primaries = primariesId;
+ d_ptr->colorModel = QColorSpace::ColorModel::Rgb;
d_ptr->identifyColorSpace();
d_ptr->setToXyzMatrix();
}
@@ -836,17 +940,100 @@ void QColorSpace::setPrimaries(const QPointF &whitePoint, const QPointF &redPoin
return;
}
QColorMatrix toXyz = primaries.toXyzMatrix();
- if (QColorVector(primaries.whitePoint) == d_ptr->whitePoint && toXyz == d_ptr->toXyz)
+ QColorMatrix chad = QColorMatrix::chromaticAdaptation(QColorVector::fromXYChromaticity(whitePoint));
+ toXyz = chad * toXyz;
+ if (QColorVector::fromXYChromaticity(primaries.whitePoint) == d_ptr->whitePoint
+ && toXyz == d_ptr->toXyz && chad == d_ptr->chad)
return;
detach();
- d_ptr->description.clear();
+ if (d_ptr->transformModel == TransformModel::ElementListProcessing)
+ d_ptr->clearElementListProcessingForEdit();
+ d_ptr->iccProfile = {};
+ d_ptr->description = QString();
d_ptr->primaries = QColorSpace::Primaries::Custom;
+ d_ptr->colorModel = QColorSpace::ColorModel::Rgb;
d_ptr->toXyz = toXyz;
- d_ptr->whitePoint = QColorVector(primaries.whitePoint);
+ d_ptr->chad = chad;
+ d_ptr->whitePoint = QColorVector::fromXYChromaticity(primaries.whitePoint);
+ d_ptr->identifyColorSpace();
+}
+
+/*!
+ Returns the white point used for this color space. Returns a null QPointF if not defined.
+
+ \since 6.8
+*/
+QPointF QColorSpace::whitePoint() const
+{
+ if (Q_UNLIKELY(!d_ptr))
+ return QPointF();
+ return d_ptr->whitePoint.toChromaticity();
+}
+
+/*!
+ Sets the white point to used for this color space to \a whitePoint.
+
+ \since 6.8
+*/
+void QColorSpace::setWhitePoint(const QPointF &whitePoint)
+{
+ if (Q_UNLIKELY(!d_ptr)) {
+ d_ptr = new QColorSpacePrivate(whitePoint, TransferFunction::Custom, 0.0f);
+ return;
+ }
+ if (QColorVector::fromXYChromaticity(whitePoint) == d_ptr->whitePoint)
+ return;
+ detach();
+ if (d_ptr->transformModel == TransformModel::ElementListProcessing)
+ d_ptr->clearElementListProcessingForEdit();
+ d_ptr->iccProfile = {};
+ d_ptr->description = QString();
+ d_ptr->primaries = QColorSpace::Primaries::Custom;
+ // An RGB color model stays RGB, a gray stays gray, but an undefined one can now be considered gray
+ if (d_ptr->colorModel == QColorSpace::ColorModel::Undefined)
+ d_ptr->colorModel = QColorSpace::ColorModel::Gray;
+ QColorVector wXyz(QColorVector::fromXYChromaticity(whitePoint));
+ if (d_ptr->transformModel == QColorSpace::TransformModel::ThreeComponentMatrix) {
+ if (d_ptr->colorModel == QColorSpace::ColorModel::Rgb) {
+ // Rescale toXyz to new whitepoint
+ QColorMatrix rawToXyz = d_ptr->chad.inverted() * d_ptr->toXyz;
+ QColorVector whiteScale = rawToXyz.inverted().map(wXyz);
+ rawToXyz = rawToXyz * QColorMatrix::fromScale(whiteScale);
+ d_ptr->chad = QColorMatrix::chromaticAdaptation(wXyz);
+ d_ptr->toXyz = d_ptr->chad * rawToXyz;
+ } else if (d_ptr->colorModel == QColorSpace::ColorModel::Gray) {
+ d_ptr->chad = d_ptr->toXyz = QColorMatrix::chromaticAdaptation(wXyz);
+ }
+ }
+ d_ptr->whitePoint = wXyz;
d_ptr->identifyColorSpace();
}
/*!
+ Returns the transfrom processing model used for this color space.
+
+ \since 6.8
+*/
+QColorSpace::TransformModel QColorSpace::transformModel() const noexcept
+{
+ if (Q_UNLIKELY(!d_ptr))
+ return QColorSpace::TransformModel::ThreeComponentMatrix;
+ return d_ptr->transformModel;
+}
+
+/*!
+ Returns the color model this color space can represent
+
+ \since 6.8
+*/
+QColorSpace::ColorModel QColorSpace::colorModel() const noexcept
+{
+ if (Q_UNLIKELY(!d_ptr))
+ return QColorSpace::ColorModel::Undefined;
+ return d_ptr->colorModel;
+}
+
+/*!
\internal
*/
void QColorSpace::detach()
@@ -884,7 +1071,7 @@ QByteArray QColorSpace::iccProfile() const
Creates a QColorSpace from ICC profile \a iccProfile.
\note Not all ICC profiles are supported. QColorSpace only supports
- RGB-XYZ ICC profiles that are three-component matrix-based.
+ RGB or Gray ICC profiles.
If the ICC profile is not supported an invalid QColorSpace is returned
where you can still read the original ICC profile using iccProfile().
@@ -902,13 +1089,51 @@ QColorSpace QColorSpace::fromIccProfile(const QByteArray &iccProfile)
}
/*!
- Returns \c true if the color space is valid.
+ Returns \c true if the color space is valid. For a color space with \c TransformModel::ThreeComponentMatrix
+ that means both primaries and transfer functions set, and implies isValidTarget().
+ For a color space with \c TransformModel::ElementListProcessing it means it has a valid source transform, to
+ check if it also a valid target color space use isValidTarget().
+
+ \sa isValidTarget()
*/
bool QColorSpace::isValid() const noexcept
{
- return d_ptr
- && d_ptr->toXyz.isValid()
- && d_ptr->trc[0].isValid() && d_ptr->trc[1].isValid() && d_ptr->trc[2].isValid();
+ if (!d_ptr)
+ return false;
+ return d_ptr->isValid();
+}
+
+/*!
+ \since 6.8
+
+ Returns \c true if the color space is a valid target color space.
+*/
+bool QColorSpace::isValidTarget() const noexcept
+{
+ if (!d_ptr)
+ return false;
+ if (!d_ptr->isThreeComponentMatrix())
+ return !d_ptr->mBA.isEmpty();
+ return d_ptr->isValid();
+}
+
+/*!
+ \internal
+*/
+bool QColorSpacePrivate::isValid() const noexcept
+{
+ if (!isThreeComponentMatrix())
+ return !mAB.isEmpty();
+ if (!toXyz.isValid())
+ return false;
+ if (colorModel == QColorSpace::ColorModel::Gray) {
+ if (!trc[0].isValid())
+ return false;
+ } else {
+ if (!trc[0].isValid() || !trc[1].isValid() || !trc[2].isValid())
+ return false;
+ }
+ return true;
}
/*!
@@ -925,6 +1150,53 @@ bool QColorSpace::isValid() const noexcept
otherwise returns \c false
*/
+static bool compareElement(const QColorSpacePrivate::TransferElement &element,
+ const QColorSpacePrivate::TransferElement &other)
+{
+ return element.trc[0] == other.trc[0]
+ && element.trc[1] == other.trc[1]
+ && element.trc[2] == other.trc[2]
+ && element.trc[3] == other.trc[3];
+}
+
+static bool compareElement(const QColorMatrix &element,
+ const QColorMatrix &other)
+{
+ return element == other;
+}
+
+static bool compareElement(const QColorVector &element,
+ const QColorVector &other)
+{
+ return element == other;
+}
+
+static bool compareElement(const QColorCLUT &element,
+ const QColorCLUT &other)
+{
+ if (element.gridPointsX != other.gridPointsX)
+ return false;
+ if (element.gridPointsY != other.gridPointsY)
+ return false;
+ if (element.gridPointsZ != other.gridPointsZ)
+ return false;
+ if (element.gridPointsW != other.gridPointsW)
+ return false;
+ if (element.table.size() != other.table.size())
+ return false;
+ for (qsizetype i = 0; i < element.table.size(); ++i) {
+ if (element.table[i] != other.table[i])
+ return false;
+ }
+ return true;
+}
+
+template<typename T>
+static bool compareElements(const T &element, const QColorSpacePrivate::Element &other)
+{
+ return compareElement(element, std::get<T>(other));
+}
+
/*!
\internal
*/
@@ -932,43 +1204,89 @@ bool QColorSpace::equals(const QColorSpace &other) const
{
if (d_ptr == other.d_ptr)
return true;
- if (!d_ptr || !other.d_ptr)
+ if (!d_ptr)
return false;
+ return d_ptr->equals(other.d_ptr.constData());
+}
- if (d_ptr->namedColorSpace && other.d_ptr->namedColorSpace)
- return d_ptr->namedColorSpace == other.d_ptr->namedColorSpace;
+/*!
+ \internal
+*/
+bool QColorSpacePrivate::equals(const QColorSpacePrivate *other) const
+{
+ if (!other)
+ return false;
+
+ if (namedColorSpace && other->namedColorSpace)
+ return namedColorSpace == other->namedColorSpace;
const bool valid1 = isValid();
- const bool valid2 = other.isValid();
+ const bool valid2 = other->isValid();
if (valid1 != valid2)
return false;
if (!valid1 && !valid2) {
- if (!d_ptr->iccProfile.isEmpty() || !other.d_ptr->iccProfile.isEmpty())
- return d_ptr->iccProfile == other.d_ptr->iccProfile;
+ if (!iccProfile.isEmpty() || !other->iccProfile.isEmpty())
+ return iccProfile == other->iccProfile;
+ return false;
}
// At this point one or both color spaces are unknown, and must be compared in detail instead
- if (primaries() != QColorSpace::Primaries::Custom && other.primaries() != QColorSpace::Primaries::Custom) {
- if (primaries() != other.primaries())
+ if (transformModel != other->transformModel)
+ return false;
+
+ if (!isThreeComponentMatrix()) {
+ if (isPcsLab != other->isPcsLab)
+ return false;
+ if (colorModel != other->colorModel)
+ return false;
+ if (mAB.count() != other->mAB.count())
+ return false;
+ if (mBA.count() != other->mBA.count())
+ return false;
+
+ // Compare element types
+ for (qsizetype i = 0; i < mAB.count(); ++i) {
+ if (mAB[i].index() != other->mAB[i].index())
+ return false;
+ }
+ for (qsizetype i = 0; i < mBA.count(); ++i) {
+ if (mBA[i].index() != other->mBA[i].index())
+ return false;
+ }
+
+ // Compare element contents
+ for (qsizetype i = 0; i < mAB.count(); ++i) {
+ if (!std::visit([&](auto &&elm) { return compareElements(elm, other->mAB[i]); }, mAB[i]))
+ return false;
+ }
+ for (qsizetype i = 0; i < mBA.count(); ++i) {
+ if (!std::visit([&](auto &&elm) { return compareElements(elm, other->mBA[i]); }, mBA[i]))
+ return false;
+ }
+
+ return true;
+ }
+
+ if (primaries != QColorSpace::Primaries::Custom && other->primaries != QColorSpace::Primaries::Custom) {
+ if (primaries != other->primaries)
return false;
} else {
- if (d_ptr->toXyz != other.d_ptr->toXyz)
+ if (toXyz != other->toXyz)
return false;
}
- if (transferFunction() != QColorSpace::TransferFunction::Custom &&
- other.transferFunction() != QColorSpace::TransferFunction::Custom) {
- if (transferFunction() != other.transferFunction())
+ if (transferFunction != QColorSpace::TransferFunction::Custom && other->transferFunction != QColorSpace::TransferFunction::Custom) {
+ if (transferFunction != other->transferFunction)
return false;
- if (transferFunction() == QColorSpace::TransferFunction::Gamma)
- return (qAbs(gamma() - other.gamma()) <= (1.0f / 512.0f));
+ if (transferFunction == QColorSpace::TransferFunction::Gamma)
+ return (qAbs(gamma - other->gamma) <= (1.0f / 512.0f));
return true;
}
- if (d_ptr->trc[0] != other.d_ptr->trc[0] ||
- d_ptr->trc[1] != other.d_ptr->trc[1] ||
- d_ptr->trc[2] != other.d_ptr->trc[2])
+ if (trc[0] != other->trc[0] ||
+ trc[1] != other->trc[1] ||
+ trc[2] != other->trc[2])
return false;
return true;
@@ -980,11 +1298,15 @@ bool QColorSpace::equals(const QColorSpace &other) const
*/
QColorTransform QColorSpace::transformationToColorSpace(const QColorSpace &colorspace) const
{
- if (!isValid() || !colorspace.isValid())
+ if (!isValid())
return QColorTransform();
if (*this == colorspace)
return QColorTransform();
+ if (!colorspace.isValidTarget()) {
+ qWarning() << "QColorSpace::transformationToColorSpace: colorspace not a valid target";
+ return QColorTransform();
+ }
return d_ptr->transformationToColorSpace(colorspace.d_ptr.get());
}
@@ -1024,6 +1346,7 @@ QString QColorSpace::description() const noexcept
void QColorSpace::setDescription(const QString &description)
{
detach();
+ d_ptr->iccProfile = {};
d_ptr->userDescription = description;
}
@@ -1066,6 +1389,28 @@ QDataStream &operator>>(QDataStream &s, QColorSpace &colorSpace)
#endif // QT_NO_DATASTREAM
#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QColorSpacePrivate::TransferElement &)
+{
+ return dbg << ":Transfer";
+}
+QDebug operator<<(QDebug dbg, const QColorMatrix &)
+{
+ return dbg << ":Matrix";
+}
+QDebug operator<<(QDebug dbg, const QColorVector &)
+{
+ return dbg << ":Offset";
+}
+QDebug operator<<(QDebug dbg, const QColorCLUT &)
+{
+ return dbg << ":CLUT";
+}
+QDebug operator<<(QDebug dbg, const QList<QColorSpacePrivate::Element> &elements)
+{
+ for (auto &&element : elements)
+ std::visit([&](auto &&elm) { dbg << elm; }, element);
+ return dbg;
+}
QDebug operator<<(QDebug dbg, const QColorSpace &colorSpace)
{
QDebugStateSaver saver(dbg);
@@ -1074,8 +1419,22 @@ QDebug operator<<(QDebug dbg, const QColorSpace &colorSpace)
if (colorSpace.d_ptr) {
if (colorSpace.d_ptr->namedColorSpace)
dbg << colorSpace.d_ptr->namedColorSpace << ", ";
- dbg << colorSpace.primaries() << ", " << colorSpace.transferFunction();
- dbg << ", gamma=" << colorSpace.gamma();
+ if (!colorSpace.isValid()) {
+ dbg << "Invalid";
+ if (!colorSpace.d_ptr->iccProfile.isEmpty())
+ dbg << " with profile data";
+ } else if (colorSpace.d_ptr->isThreeComponentMatrix()) {
+ dbg << colorSpace.primaries() << ", " << colorSpace.transferFunction();
+ dbg << ", gamma=" << colorSpace.gamma();
+ } else {
+ if (colorSpace.d_ptr->isPcsLab)
+ dbg << "PCSLab, ";
+ else
+ dbg << "PCSXYZ, ";
+ dbg << "A2B" << colorSpace.d_ptr->mAB;
+ if (!colorSpace.d_ptr->mBA.isEmpty())
+ dbg << ", B2A" << colorSpace.d_ptr->mBA;
+ }
}
dbg << ')';
return dbg;
diff --git a/src/gui/painting/qcolorspace.h b/src/gui/painting/qcolorspace.h
index 4fb5c4273f..488cbd6a53 100644
--- a/src/gui/painting/qcolorspace.h
+++ b/src/gui/painting/qcolorspace.h
@@ -45,9 +45,23 @@ public:
ProPhotoRgb
};
Q_ENUM(TransferFunction)
+ enum class TransformModel : uint8_t {
+ ThreeComponentMatrix = 0,
+ ElementListProcessing,
+ };
+ Q_ENUM(TransformModel)
+ enum class ColorModel : uint8_t {
+ Undefined = 0,
+ Rgb = 1,
+ Gray = 2,
+ Cmyk = 3,
+ };
+ Q_ENUM(ColorModel)
QColorSpace() noexcept = default;
QColorSpace(NamedColorSpace namedColorSpace);
+ QColorSpace(const QPointF &whitePoint, TransferFunction transferFunction, float gamma = 0.0f);
+ QColorSpace(const QPointF &whitePoint, const QList<uint16_t> &transferFunctionTable);
QColorSpace(Primaries primaries, TransferFunction transferFunction, float gamma = 0.0f);
QColorSpace(Primaries primaries, float gamma);
QColorSpace(Primaries primaries, const QList<uint16_t> &transferFunctionTable);
@@ -99,9 +113,14 @@ public:
void setPrimaries(Primaries primariesId);
void setPrimaries(const QPointF &whitePoint, const QPointF &redPoint,
const QPointF &greenPoint, const QPointF &bluePoint);
+ void setWhitePoint(const QPointF &whitePoint);
+ QPointF whitePoint() const;
+ TransformModel transformModel() const noexcept;
+ ColorModel colorModel() const noexcept;
void detach();
bool isValid() const noexcept;
+ bool isValidTarget() const noexcept;
friend inline bool operator==(const QColorSpace &colorSpace1, const QColorSpace &colorSpace2)
{ return colorSpace1.equals(colorSpace2); }
diff --git a/src/gui/painting/qcolorspace_p.h b/src/gui/painting/qcolorspace_p.h
index 39d901ecdf..4ec801b16b 100644
--- a/src/gui/painting/qcolorspace_p.h
+++ b/src/gui/painting/qcolorspace_p.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2018 The Qt Company Ltd.
+// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QCOLORSPACE_P_H
@@ -16,6 +16,7 @@
//
#include "qcolorspace.h"
+#include "qcolorclut_p.h"
#include "qcolormatrix_p.h"
#include "qcolortrc_p.h"
#include "qcolortrclut_p.h"
@@ -65,6 +66,8 @@ public:
const QList<uint16_t> &redTransferFunctionTable,
const QList<uint16_t> &greenTransferFunctionTable,
const QList<uint16_t> &blueRransferFunctionTable);
+ QColorSpacePrivate(const QPointF &whitePoint, QColorSpace::TransferFunction transferFunction, float gamma);
+ QColorSpacePrivate(const QPointF &whitePoint, const QList<uint16_t> &transferFunctionTable);
QColorSpacePrivate(const QColorSpacePrivate &other) = default;
static const QColorSpacePrivate *get(const QColorSpace &colorSpace)
@@ -77,6 +80,9 @@ public:
return colorSpace.d_ptr.get();
}
+ bool equals(const QColorSpacePrivate *other) const;
+ bool isValid() const noexcept;
+
void initialize();
void setToXyzMatrix();
void setTransferFunction();
@@ -88,21 +94,39 @@ public:
QColorTransform transformationToColorSpace(const QColorSpacePrivate *out) const;
QColorTransform transformationToXYZ() const;
+ bool isThreeComponentMatrix() const;
+ void clearElementListProcessingForEdit();
+
static constexpr QColorSpace::NamedColorSpace Unknown = QColorSpace::NamedColorSpace(0);
QColorSpace::NamedColorSpace namedColorSpace = Unknown;
QColorSpace::Primaries primaries = QColorSpace::Primaries::Custom;
QColorSpace::TransferFunction transferFunction = QColorSpace::TransferFunction::Custom;
+ QColorSpace::TransformModel transformModel = QColorSpace::TransformModel::ThreeComponentMatrix;
+ QColorSpace::ColorModel colorModel = QColorSpace::ColorModel::Undefined;
float gamma = 0.0f;
QColorVector whitePoint;
+ // Three component matrix data:
QColorTrc trc[3];
QColorMatrix toXyz;
-
+ QColorMatrix chad;
+
+ // Element list processing data:
+ struct TransferElement {
+ QColorTrc trc[4];
+ };
+ using Element = std::variant<TransferElement, QColorMatrix, QColorVector, QColorCLUT>;
+ bool isPcsLab = false;
+ // A = device, B = PCS
+ QList<Element> mAB, mBA;
+
+ // Metadata
QString description;
QString userDescription;
QByteArray iccProfile;
+ // Cached tables for three component matrix transform:
Q_CONSTINIT static QBasicMutex s_lutWriteLock;
struct LUT {
LUT() = default;
diff --git a/src/gui/painting/qcolortransferfunction_p.h b/src/gui/painting/qcolortransferfunction_p.h
index a9bb26df59..484cc69114 100644
--- a/src/gui/painting/qcolortransferfunction_p.h
+++ b/src/gui/painting/qcolortransferfunction_p.h
@@ -16,44 +16,52 @@
//
#include <QtGui/private/qtguiglobal_p.h>
+#include <QtCore/QFlags>
#include <cmath>
QT_BEGIN_NAMESPACE
// Defines a ICC parametric curve type 4
-class Q_GUI_EXPORT QColorTransferFunction
+class QColorTransferFunction
{
public:
QColorTransferFunction() noexcept
- : m_a(1.0f), m_b(0.0f), m_c(1.0f), m_d(0.0f), m_e(0.0f), m_f(0.0f), m_g(1.0f), m_flags(0)
+ : m_a(1.0f), m_b(0.0f), m_c(1.0f), m_d(0.0f), m_e(0.0f), m_f(0.0f), m_g(1.0f)
+ , m_flags(Hints(Hint::Calculated) | Hint::IsGamma | Hint::IsIdentity)
{ }
+
QColorTransferFunction(float a, float b, float c, float d, float e, float f, float g) noexcept
- : m_a(a), m_b(b), m_c(c), m_d(d), m_e(e), m_f(f), m_g(g), m_flags(0)
+ : m_a(a), m_b(b), m_c(c), m_d(d), m_e(e), m_f(f), m_g(g), m_flags()
{ }
bool isGamma() const
{
updateHints();
- return m_flags & quint32(Hints::IsGamma);
+ return m_flags & Hint::IsGamma;
}
- bool isLinear() const
+ bool isIdentity() const
{
updateHints();
- return m_flags & quint32(Hints::IsLinear);
+ return m_flags & Hint::IsIdentity;
}
bool isSRgb() const
{
updateHints();
- return m_flags & quint32(Hints::IsSRgb);
+ return m_flags & Hint::IsSRgb;
}
float apply(float x) const
{
if (x < m_d)
return m_c * x + m_f;
+ float t = std::pow(m_a * x + m_b, m_g);
+ if (std::isfinite(t))
+ return t + m_e;
+ if (t > 0.f)
+ return 1.f;
else
- return std::pow(m_a * x + m_b, m_g) + m_e;
+ return 0.f;
}
QColorTransferFunction inverted() const
@@ -62,7 +70,7 @@ public:
d = m_c * m_d + m_f;
- if (!qFuzzyIsNull(m_c)) {
+ if (std::isnormal(m_c)) {
c = 1.0f / m_c;
f = -m_f / m_c;
} else {
@@ -70,8 +78,12 @@ public:
f = 0.0f;
}
- if (!qFuzzyIsNull(m_a) && !qFuzzyIsNull(m_g)) {
+ bool valid_abeg = std::isnormal(m_a) && std::isnormal(m_g);
+ if (valid_abeg)
a = std::pow(1.0f / m_a, m_g);
+ if (valid_abeg && !std::isfinite(a))
+ valid_abeg = false;
+ if (valid_abeg) {
b = -a * m_e;
e = -m_b / m_a;
g = 1.0f / m_g;
@@ -88,15 +100,19 @@ public:
// A few predefined curves:
static QColorTransferFunction fromGamma(float gamma)
{
- return QColorTransferFunction(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, gamma);
+ return QColorTransferFunction(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, gamma,
+ Hints(Hint::Calculated) | Hint::IsGamma |
+ (paramCompare(gamma, 1.0f) ? Hint::IsIdentity : Hint::NoHint));
}
static QColorTransferFunction fromSRgb()
{
- return QColorTransferFunction(1.0f / 1.055f, 0.055f / 1.055f, 1.0f / 12.92f, 0.04045f, 0.0f, 0.0f, 2.4f);
+ return QColorTransferFunction(1.0f / 1.055f, 0.055f / 1.055f, 1.0f / 12.92f, 0.04045f, 0.0f, 0.0f, 2.4f,
+ Hints(Hint::Calculated) | Hint::IsSRgb);
}
static QColorTransferFunction fromProPhotoRgb()
{
- return QColorTransferFunction(1.0f, 0.0f, 1.0f / 16.0f, 16.0f / 512.0f, 0.0f, 0.0f, 1.8f);
+ return QColorTransferFunction(1.0f, 0.0f, 1.0f / 16.0f, 16.0f / 512.0f, 0.0f, 0.0f, 1.8f,
+ Hints(Hint::Calculated));
}
bool matches(const QColorTransferFunction &o) const
{
@@ -116,7 +132,20 @@ public:
float m_f;
float m_g;
+ enum class Hint : quint32 {
+ NoHint = 0,
+ Calculated = 1,
+ IsGamma = 2,
+ IsIdentity = 4,
+ IsSRgb = 8
+ };
+
+ Q_DECLARE_FLAGS(Hints, Hint);
+
private:
+ QColorTransferFunction(float a, float b, float c, float d, float e, float f, float g, Hints flags) noexcept
+ : m_a(a), m_b(b), m_c(c), m_d(d), m_e(e), m_f(f), m_g(g), m_flags(flags)
+ { }
static inline bool paramCompare(float p1, float p2)
{
// Much fuzzier than fuzzy compare.
@@ -127,7 +156,7 @@ private:
void updateHints() const
{
- if (m_flags & quint32(Hints::Calculated))
+ if (m_flags & Hint::Calculated)
return;
// We do not consider the case with m_d = 1.0f linear or simple,
// since it wouldn't be linear for applyExtended().
@@ -135,24 +164,21 @@ private:
&& paramCompare(m_d, 0.0f)
&& paramCompare(m_e, 0.0f);
if (simple) {
- m_flags |= quint32(Hints::IsGamma);
+ m_flags |= Hint::IsGamma;
if (qFuzzyCompare(m_g, 1.0f))
- m_flags |= quint32(Hints::IsLinear);
+ m_flags |= Hint::IsIdentity;
} else {
if (*this == fromSRgb())
- m_flags |= quint32(Hints::IsSRgb);
+ m_flags |= Hint::IsSRgb;
}
- m_flags |= quint32(Hints::Calculated);
+ m_flags |= Hint::Calculated;
}
- enum class Hints : quint32 {
- Calculated = 1,
- IsGamma = 2,
- IsLinear = 4,
- IsSRgb = 8
- };
- mutable quint32 m_flags;
+
+ mutable Hints m_flags;
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QColorTransferFunction::Hints);
+
inline bool operator==(const QColorTransferFunction &f1, const QColorTransferFunction &f2)
{
return f1.matches(f2);
diff --git a/src/gui/painting/qcolortransfertable_p.h b/src/gui/painting/qcolortransfertable_p.h
index dc0f5804fd..ce6ad0c4b2 100644
--- a/src/gui/painting/qcolortransfertable_p.h
+++ b/src/gui/painting/qcolortransfertable_p.h
@@ -29,25 +29,38 @@ QT_BEGIN_NAMESPACE
class Q_GUI_EXPORT QColorTransferTable
{
public:
- QColorTransferTable() noexcept
- : m_tableSize(0)
- { }
- QColorTransferTable(uint32_t size, const QList<uint8_t> &table) noexcept
- : m_tableSize(size), m_table8(table)
+ enum Type : uint8_t {
+ TwoWay = 0,
+ OneWay,
+ };
+ QColorTransferTable() noexcept = default;
+ QColorTransferTable(uint32_t size, const QList<uint8_t> &table, Type type = TwoWay) noexcept
+ : m_type(type), m_tableSize(size), m_table8(table)
{
Q_ASSERT(qsizetype(size) <= table.size());
}
- QColorTransferTable(uint32_t size, const QList<uint16_t> &table) noexcept
- : m_tableSize(size), m_table16(table)
+ QColorTransferTable(uint32_t size, const QList<uint16_t> &table, Type type = TwoWay) noexcept
+ : m_type(type), m_tableSize(size), m_table16(table)
{
Q_ASSERT(qsizetype(size) <= table.size());
}
- bool isEmpty() const
+ bool isEmpty() const noexcept
{
return m_tableSize == 0;
}
+ bool isIdentity() const
+ {
+ if (isEmpty())
+ return true;
+ if (m_tableSize != 2)
+ return false;
+ if (!m_table8.isEmpty())
+ return m_table8[0] == 0 && m_table8[1] == 255;
+ return m_table16[0] == 0 && m_table16[1] == 65535;
+ }
+
bool checkValidity() const
{
if (isEmpty())
@@ -58,7 +71,11 @@ public:
// At least 2 elements
if (m_tableSize < 2)
return false;
- // The table must describe an injective curve:
+ return (m_type == OneWay) || checkInvertibility();
+ }
+ bool checkInvertibility() const
+ {
+ // The two-way tables must describe an injective curve:
if (!m_table8.isEmpty()) {
uint8_t val = 0;
for (uint i = 0; i < m_tableSize; ++i) {
@@ -80,15 +97,17 @@ public:
float apply(float x) const
{
+ if (isEmpty())
+ return x;
x = std::clamp(x, 0.0f, 1.0f);
x *= m_tableSize - 1;
- const uint32_t lo = static_cast<uint32_t>(std::floor(x));
+ const uint32_t lo = static_cast<uint32_t>(x);
const uint32_t hi = std::min(lo + 1, m_tableSize - 1);
const float frac = x - lo;
if (!m_table16.isEmpty())
- return (m_table16[lo] * (1.0f - frac) + m_table16[hi] * frac) * (1.0f/65535.0f);
+ return (m_table16[lo] + (m_table16[hi] - m_table16[lo]) * frac) * (1.0f/65535.0f);
if (!m_table8.isEmpty())
- return (m_table8[lo] * (1.0f - frac) + m_table8[hi] * frac) * (1.0f/255.0f);
+ return (m_table8[lo] + (m_table8[hi] - m_table8[lo]) * frac) * (1.0f/255.0f);
return x;
}
@@ -96,47 +115,25 @@ public:
float applyInverse(float x, float resultLargerThan = 0.0f) const
{
Q_ASSERT(resultLargerThan >= 0.0f && resultLargerThan <= 1.0f);
+ Q_ASSERT(m_type == TwoWay);
if (x <= 0.0f)
return 0.0f;
if (x >= 1.0f)
return 1.0f;
- if (!m_table16.isEmpty()) {
- const float v = x * 65535.0f;
- uint32_t i = static_cast<uint32_t>(std::floor(resultLargerThan * (m_tableSize - 1)));
- auto it = std::lower_bound(m_table16.cbegin() + i, m_table16.cend(), v);
- i = it - m_table16.cbegin();
- if (i == 0)
- return 0.0f;
- if (i >= m_tableSize - 1)
- return 1.0f;
- const float y1 = m_table16[i - 1];
- const float y2 = m_table16[i];
- Q_ASSERT(v >= y1 && v <= y2);
- const float fr = (v - y1) / (y2 - y1);
- return (i + fr) * (1.0f / (m_tableSize - 1));
-
- }
- if (!m_table8.isEmpty()) {
- const float v = x * 255.0f;
- uint32_t i = static_cast<uint32_t>(std::floor(resultLargerThan * (m_tableSize - 1)));
- auto it = std::lower_bound(m_table8.cbegin() + i, m_table8.cend(), v);
- i = it - m_table8.cbegin();
- if (i == 0)
- return 0.0f;
- if (i >= m_tableSize - 1)
- return 1.0f;
- const float y1 = m_table8[i - 1];
- const float y2 = m_table8[i];
- Q_ASSERT(v >= y1 && v <= y2);
- const float fr = (v - y1) / (y2 - y1);
- return (i + fr) * (1.0f / (m_tableSize - 1));
- }
+ if (!m_table16.isEmpty())
+ return inverseLookup(x * 65535.0f, resultLargerThan, m_table16, m_tableSize - 1);
+ if (!m_table8.isEmpty())
+ return inverseLookup(x * 255.0f, resultLargerThan, m_table8, m_tableSize - 1);
return x;
}
bool asColorTransferFunction(QColorTransferFunction *transferFn)
{
Q_ASSERT(transferFn);
+ if (isEmpty()) {
+ *transferFn = QColorTransferFunction();
+ return true;
+ }
if (m_tableSize < 2)
return false;
if (!m_table8.isEmpty() && (m_table8[0] != 0 || m_table8[m_tableSize - 1] != 255))
@@ -186,15 +183,36 @@ public:
friend inline bool operator!=(const QColorTransferTable &t1, const QColorTransferTable &t2);
friend inline bool operator==(const QColorTransferTable &t1, const QColorTransferTable &t2);
- uint32_t m_tableSize;
+ Type m_type = TwoWay;
+ uint32_t m_tableSize = 0;
QList<uint8_t> m_table8;
QList<uint16_t> m_table16;
+private:
+ template<typename T>
+ static float inverseLookup(float needle, float resultLargerThan, const QList<T> &table, quint32 tableMax)
+ {
+ uint32_t i = static_cast<uint32_t>(resultLargerThan * tableMax);
+ auto it = std::lower_bound(table.cbegin() + i, table.cend(), needle);
+ i = it - table.cbegin();
+ if (i == 0)
+ return 0.0f;
+ if (i >= tableMax)
+ return 1.0f;
+ const float y1 = table[i - 1];
+ const float y2 = table[i];
+ Q_ASSERT(needle >= y1 && needle <= y2);
+ const float fr = (needle - y1) / (y2 - y1);
+ return (i + fr) * (1.0f / tableMax);
+ }
+
};
inline bool operator!=(const QColorTransferTable &t1, const QColorTransferTable &t2)
{
if (t1.m_tableSize != t2.m_tableSize)
return true;
+ if (t1.m_type != t2.m_type)
+ return true;
if (t1.m_table8.isEmpty() != t2.m_table8.isEmpty())
return true;
if (t1.m_table16.isEmpty() != t2.m_table16.isEmpty())
diff --git a/src/gui/painting/qcolortransform.cpp b/src/gui/painting/qcolortransform.cpp
index 579d99d09c..aac07bdc09 100644
--- a/src/gui/painting/qcolortransform.cpp
+++ b/src/gui/painting/qcolortransform.cpp
@@ -1,9 +1,11 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qcolortransform.h"
#include "qcolortransform_p.h"
+#include "qcmyk_p.h"
+#include "qcolorclut_p.h"
#include "qcolormatrix_p.h"
#include "qcolorspace_p.h"
#include "qcolortrc_p.h"
@@ -139,11 +141,31 @@ bool QColorTransform::compare(const QColorTransform &other) const
return false;
if (bool(d->colorSpaceOut) != bool(other.d->colorSpaceOut))
return false;
- for (int i = 0; i < 3; ++i) {
- if (d->colorSpaceIn && d->colorSpaceIn->trc[i] != other.d->colorSpaceIn->trc[i])
+ if (d->colorSpaceIn) {
+ if (d->colorSpaceIn->transformModel != other.d->colorSpaceIn->transformModel)
return false;
- if (d->colorSpaceOut && d->colorSpaceOut->trc[i] != other.d->colorSpaceOut->trc[i])
+ if (d->colorSpaceIn->isThreeComponentMatrix()) {
+ for (int i = 0; i < 3; ++i) {
+ if (d->colorSpaceIn && d->colorSpaceIn->trc[i] != other.d->colorSpaceIn->trc[i])
+ return false;
+ }
+ } else {
+ if (!d->colorSpaceIn->equals(other.d->colorSpaceIn.constData()))
+ return false;
+ }
+ }
+ if (d->colorSpaceOut) {
+ if (d->colorSpaceOut->transformModel != other.d->colorSpaceOut->transformModel)
return false;
+ if (d->colorSpaceOut->isThreeComponentMatrix()) {
+ for (int i = 0; i < 3; ++i) {
+ if (d->colorSpaceOut && d->colorSpaceOut->trc[i] != other.d->colorSpaceOut->trc[i])
+ return false;
+ }
+ } else {
+ if (!d->colorSpaceOut->equals(other.d->colorSpaceOut.constData()))
+ return false;
+ }
}
return true;
}
@@ -159,29 +181,7 @@ QRgb QColorTransform::map(QRgb argb) const
return argb;
constexpr float f = 1.0f / 255.0f;
QColorVector c = { qRed(argb) * f, qGreen(argb) * f, qBlue(argb) * f };
- if (d->colorSpaceIn->lut.generated.loadAcquire()) {
- c.x = d->colorSpaceIn->lut[0]->toLinear(c.x);
- c.y = d->colorSpaceIn->lut[1]->toLinear(c.y);
- c.z = d->colorSpaceIn->lut[2]->toLinear(c.z);
- } else {
- c.x = d->colorSpaceIn->trc[0].apply(c.x);
- c.y = d->colorSpaceIn->trc[1].apply(c.y);
- c.z = d->colorSpaceIn->trc[2].apply(c.z);
- }
- c = d->colorMatrix.map(c);
- c.x = std::max(0.0f, std::min(1.0f, c.x));
- c.y = std::max(0.0f, std::min(1.0f, c.y));
- c.z = std::max(0.0f, std::min(1.0f, c.z));
- if (d->colorSpaceOut->lut.generated.loadAcquire()) {
- c.x = d->colorSpaceOut->lut[0]->fromLinear(c.x);
- c.y = d->colorSpaceOut->lut[1]->fromLinear(c.y);
- c.z = d->colorSpaceOut->lut[2]->fromLinear(c.z);
- } else {
- c.x = d->colorSpaceOut->trc[0].applyInverse(c.x);
- c.y = d->colorSpaceOut->trc[1].applyInverse(c.y);
- c.z = d->colorSpaceOut->trc[2].applyInverse(c.z);
- }
-
+ c = d->map(c);
return qRgba(c.x * 255 + 0.5f, c.y * 255 + 0.5f, c.z * 255 + 0.5f, qAlpha(argb));
}
@@ -196,29 +196,7 @@ QRgba64 QColorTransform::map(QRgba64 rgba64) const
return rgba64;
constexpr float f = 1.0f / 65535.0f;
QColorVector c = { rgba64.red() * f, rgba64.green() * f, rgba64.blue() * f };
- if (d->colorSpaceIn->lut.generated.loadAcquire()) {
- c.x = d->colorSpaceIn->lut[0]->toLinear(c.x);
- c.y = d->colorSpaceIn->lut[1]->toLinear(c.y);
- c.z = d->colorSpaceIn->lut[2]->toLinear(c.z);
- } else {
- c.x = d->colorSpaceIn->trc[0].apply(c.x);
- c.y = d->colorSpaceIn->trc[1].apply(c.y);
- c.z = d->colorSpaceIn->trc[2].apply(c.z);
- }
- c = d->colorMatrix.map(c);
- c.x = std::max(0.0f, std::min(1.0f, c.x));
- c.y = std::max(0.0f, std::min(1.0f, c.y));
- c.z = std::max(0.0f, std::min(1.0f, c.z));
- if (d->colorSpaceOut->lut.generated.loadAcquire()) {
- c.x = d->colorSpaceOut->lut[0]->fromLinear(c.x);
- c.y = d->colorSpaceOut->lut[1]->fromLinear(c.y);
- c.z = d->colorSpaceOut->lut[2]->fromLinear(c.z);
- } else {
- c.x = d->colorSpaceOut->trc[0].applyInverse(c.x);
- c.y = d->colorSpaceOut->trc[1].applyInverse(c.y);
- c.z = d->colorSpaceOut->trc[2].applyInverse(c.z);
- }
-
+ c = d->map(c);
return QRgba64::fromRgba64(c.x * 65535.f + 0.5f, c.y * 65535.f + 0.5f, c.z * 65535.f + 0.5f, rgba64.alpha());
}
@@ -232,14 +210,11 @@ QRgbaFloat16 QColorTransform::map(QRgbaFloat16 rgbafp16) const
{
if (!d)
return rgbafp16;
- QColorVector c;
- c.x = d->colorSpaceIn->trc[0].applyExtended(rgbafp16.r);
- c.y = d->colorSpaceIn->trc[1].applyExtended(rgbafp16.g);
- c.z = d->colorSpaceIn->trc[2].applyExtended(rgbafp16.b);
- c = d->colorMatrix.map(c);
- rgbafp16.r = qfloat16(d->colorSpaceOut->trc[0].applyInverseExtended(c.x));
- rgbafp16.g = qfloat16(d->colorSpaceOut->trc[1].applyInverseExtended(c.y));
- rgbafp16.b = qfloat16(d->colorSpaceOut->trc[2].applyInverseExtended(c.z));
+ QColorVector c(rgbafp16.r, rgbafp16.g, rgbafp16.b);
+ c = d->mapExtended(c);
+ rgbafp16.r = qfloat16(c.x);
+ rgbafp16.g = qfloat16(c.y);
+ rgbafp16.b = qfloat16(c.z);
return rgbafp16;
}
@@ -253,14 +228,11 @@ QRgbaFloat32 QColorTransform::map(QRgbaFloat32 rgbafp32) const
{
if (!d)
return rgbafp32;
- QColorVector c;
- c.x = d->colorSpaceIn->trc[0].applyExtended(rgbafp32.r);
- c.y = d->colorSpaceIn->trc[1].applyExtended(rgbafp32.g);
- c.z = d->colorSpaceIn->trc[2].applyExtended(rgbafp32.b);
- c = d->colorMatrix.map(c);
- rgbafp32.r = d->colorSpaceOut->trc[0].applyInverseExtended(c.x);
- rgbafp32.g = d->colorSpaceOut->trc[1].applyInverseExtended(c.y);
- rgbafp32.b = d->colorSpaceOut->trc[2].applyInverseExtended(c.z);
+ QColorVector c(rgbafp32.r, rgbafp32.g, rgbafp32.b);
+ c = d->mapExtended(c);
+ rgbafp32.r = c.x;
+ rgbafp32.g = c.y;
+ rgbafp32.b = c.z;
return rgbafp32;
}
@@ -273,44 +245,42 @@ QColor QColorTransform::map(const QColor &color) const
if (!d)
return color;
QColor clr = color;
- if (color.spec() != QColor::ExtendedRgb || color.spec() != QColor::Rgb)
- clr = clr.toRgb();
-
- QColorVector c = { (float)clr.redF(), (float)clr.greenF(), (float)clr.blueF() };
- if (clr.spec() == QColor::ExtendedRgb) {
- c.x = d->colorSpaceIn->trc[0].applyExtended(c.x);
- c.y = d->colorSpaceIn->trc[1].applyExtended(c.y);
- c.z = d->colorSpaceIn->trc[2].applyExtended(c.z);
- } else {
- c.x = d->colorSpaceIn->trc[0].apply(c.x);
- c.y = d->colorSpaceIn->trc[1].apply(c.y);
- c.z = d->colorSpaceIn->trc[2].apply(c.z);
- }
- c = d->colorMatrix.map(c);
- bool inGamut = c.x >= 0.0f && c.x <= 1.0f && c.y >= 0.0f && c.y <= 1.0f && c.z >= 0.0f && c.z <= 1.0f;
- if (inGamut) {
- if (d->colorSpaceOut->lut.generated.loadAcquire()) {
- c.x = d->colorSpaceOut->lut[0]->fromLinear(c.x);
- c.y = d->colorSpaceOut->lut[1]->fromLinear(c.y);
- c.z = d->colorSpaceOut->lut[2]->fromLinear(c.z);
- } else {
- c.x = d->colorSpaceOut->trc[0].applyInverse(c.x);
- c.y = d->colorSpaceOut->trc[1].applyInverse(c.y);
- c.z = d->colorSpaceOut->trc[2].applyInverse(c.z);
- }
- } else {
- c.x = d->colorSpaceOut->trc[0].applyInverseExtended(c.x);
- c.y = d->colorSpaceOut->trc[1].applyInverseExtended(c.y);
- c.z = d->colorSpaceOut->trc[2].applyInverseExtended(c.z);
+ if (d->colorSpaceIn->colorModel == QColorSpace::ColorModel::Rgb) {
+ if (color.spec() != QColor::ExtendedRgb && color.spec() != QColor::Rgb)
+ clr = clr.toRgb();
+ } else if (d->colorSpaceIn->colorModel == QColorSpace::ColorModel::Cmyk) {
+ if (color.spec() != QColor::Cmyk)
+ clr = clr.toCmyk();
}
+
+ QColorVector c =
+ (clr.spec() == QColor::Cmyk)
+ ? QColorVector(clr.cyanF(), clr.magentaF(), clr.yellowF(), clr.blackF())
+ : QColorVector(clr.redF(), clr.greenF(), clr.blueF());
+
+ c = d->mapExtended(c);
+
QColor out;
- out.setRgbF(c.x, c.y, c.z, color.alphaF());
+ if (d->colorSpaceOut->colorModel == QColorSpace::ColorModel::Cmyk) {
+ c.x = std::clamp(c.x, 0.f, 1.f);
+ c.y = std::clamp(c.y, 0.f, 1.f);
+ c.z = std::clamp(c.z, 0.f, 1.f);
+ c.w = std::clamp(c.w, 0.f, 1.f);
+ out.setCmykF(c.x, c.y, c.z, c.w, color.alphaF());
+ } else {
+ out.setRgbF(c.x, c.y, c.z, color.alphaF());
+ }
return out;
}
// Optimized sub-routines for fast block based conversion:
-template<bool DoClamp = true>
+enum ApplyMatrixForm {
+ DoNotClamp = 0,
+ DoClamp = 1
+};
+
+template<ApplyMatrixForm doClamp = DoClamp>
static void applyMatrix(QColorVector *buffer, const qsizetype len, const QColorMatrix &colorMatrix)
{
#if defined(__SSE2__)
@@ -330,7 +300,7 @@ static void applyMatrix(QColorVector *buffer, const qsizetype len, const QColorM
cx = _mm_add_ps(cx, cy);
cx = _mm_add_ps(cx, cz);
// Clamp:
- if (DoClamp) {
+ if (doClamp) {
cx = _mm_min_ps(cx, maxV);
cx = _mm_max_ps(cx, minV);
}
@@ -350,19 +320,19 @@ static void applyMatrix(QColorVector *buffer, const qsizetype len, const QColorM
cx = vaddq_f32(cx, cy);
cx = vaddq_f32(cx, cz);
// Clamp:
- if (DoClamp) {
+ if (doClamp) {
cx = vminq_f32(cx, maxV);
cx = vmaxq_f32(cx, minV);
}
vst1q_f32(&buffer[j].x, cx);
}
#else
- for (int j = 0; j < len; ++j) {
+ for (qsizetype j = 0; j < len; ++j) {
const QColorVector cv = colorMatrix.map(buffer[j]);
- if (DoClamp) {
- buffer[j].x = std::max(0.0f, std::min(1.0f, cv.x));
- buffer[j].y = std::max(0.0f, std::min(1.0f, cv.y));
- buffer[j].z = std::max(0.0f, std::min(1.0f, cv.z));
+ if (doClamp) {
+ buffer[j].x = std::clamp(cv.x, 0.f, 1.f);
+ buffer[j].y = std::clamp(cv.y, 0.f, 1.f);
+ buffer[j].z = std::clamp(cv.z, 0.f, 1.f);
} else {
buffer[j] = cv;
}
@@ -370,6 +340,39 @@ static void applyMatrix(QColorVector *buffer, const qsizetype len, const QColorM
#endif
}
+template<ApplyMatrixForm doClamp = DoClamp>
+static void clampIfNeeded(QColorVector *buffer, const qsizetype len)
+{
+ if constexpr (doClamp != DoClamp)
+ return;
+#if defined(__SSE2__)
+ const __m128 minV = _mm_set1_ps(0.0f);
+ const __m128 maxV = _mm_set1_ps(1.0f);
+ for (qsizetype j = 0; j < len; ++j) {
+ __m128 c = _mm_loadu_ps(&buffer[j].x);
+ c = _mm_min_ps(c, maxV);
+ c = _mm_max_ps(c, minV);
+ _mm_storeu_ps(&buffer[j].x, c);
+ }
+#elif defined(__ARM_NEON__)
+ const float32x4_t minV = vdupq_n_f32(0.0f);
+ const float32x4_t maxV = vdupq_n_f32(1.0f);
+ for (qsizetype j = 0; j < len; ++j) {
+ float32x4_t c = vld1q_f32(&buffer[j].x);
+ c = vminq_f32(c, maxV);
+ c = vmaxq_f32(c, minV);
+ vst1q_f32(&buffer[j].x, c);
+ }
+#else
+ for (qsizetype j = 0; j < len; ++j) {
+ const QColorVector cv = buffer[j];
+ buffer[j].x = std::clamp(cv.x, 0.f, 1.f);
+ buffer[j].y = std::clamp(cv.y, 0.f, 1.f);
+ buffer[j].z = std::clamp(cv.z, 0.f, 1.f);
+ }
+#endif
+}
+
#if defined(__SSE2__) || defined(__ARM_NEON__)
template<typename T>
static constexpr inline bool isArgb();
@@ -386,9 +389,29 @@ inline int getAlpha<QRgb>(const QRgb &p)
template<>
inline int getAlpha<QRgba64>(const QRgba64 &p)
{ return p.alpha(); }
+
#endif
template<typename T>
+static float getAlphaF(const T &);
+template<> float getAlphaF(const QRgb &r)
+{
+ return qAlpha(r) * (1.f / 255.f);
+}
+template<> float getAlphaF(const QCmyk32 &)
+{
+ return 1.f;
+}
+template<> float getAlphaF(const QRgba64 &r)
+{
+ return r.alpha() * (1.f / 65535.f);
+}
+template<> float getAlphaF(const QRgbaFloat32 &r)
+{
+ return r.a;
+}
+
+template<typename T>
static void loadPremultiplied(QColorVector *buffer, const T *src, const qsizetype len, const QColorTransformPrivate *d_ptr);
template<typename T>
static void loadUnpremultiplied(QColorVector *buffer, const T *src, const qsizetype len, const QColorTransformPrivate *d_ptr);
@@ -424,7 +447,7 @@ inline void loadP<QRgba64>(const QRgba64 &p, __m128i &v)
template<typename T>
static void loadPremultiplied(QColorVector *buffer, const T *src, const qsizetype len, const QColorTransformPrivate *d_ptr)
{
- const __m128 v4080 = _mm_set1_ps(4080.f);
+ const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
const __m128 iFF00 = _mm_set1_ps(1.0f / (255 * 256));
constexpr bool isARGB = isArgb<T>();
for (qsizetype i = 0; i < len; ++i) {
@@ -443,7 +466,7 @@ static void loadPremultiplied(QColorVector *buffer, const T *src, const qsizetyp
vf = _mm_andnot_ps(vAlphaMask, vf);
// LUT
- v = _mm_cvtps_epi32(_mm_mul_ps(vf, v4080));
+ v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
const int ridx = isARGB ? _mm_extract_epi16(v, 4) : _mm_extract_epi16(v, 0);
const int gidx = _mm_extract_epi16(v, 2);
const int bidx = isARGB ? _mm_extract_epi16(v, 0) : _mm_extract_epi16(v, 4);
@@ -459,7 +482,7 @@ static void loadPremultiplied(QColorVector *buffer, const T *src, const qsizetyp
template<>
void loadPremultiplied<QRgbaFloat32>(QColorVector *buffer, const QRgbaFloat32 *src, const qsizetype len, const QColorTransformPrivate *d_ptr)
{
- const __m128 v4080 = _mm_set1_ps(4080.f);
+ const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
const __m128 viFF00 = _mm_set1_ps(1.0f / (255 * 256));
const __m128 vZero = _mm_set1_ps(0.0f);
const __m128 vOne = _mm_set1_ps(1.0f);
@@ -481,7 +504,7 @@ void loadPremultiplied<QRgbaFloat32>(QColorVector *buffer, const QRgbaFloat32 *s
const __m128 over = _mm_cmpgt_ps(vf, vOne);
if (_mm_movemask_ps(_mm_or_ps(under, over)) == 0) {
// Within gamut
- __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, v4080));
+ __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
const int ridx = _mm_extract_epi16(v, 0);
const int gidx = _mm_extract_epi16(v, 2);
const int bidx = _mm_extract_epi16(v, 4);
@@ -500,7 +523,7 @@ void loadPremultiplied<QRgbaFloat32>(QColorVector *buffer, const QRgbaFloat32 *s
}
}
-// Load to [0-4080] in 4x32 SIMD
+// Load to [0->TrcResolution] in 4x32 SIMD
template<typename T>
static inline void loadPU(const T &p, __m128i &v);
@@ -514,7 +537,7 @@ inline void loadPU<QRgb>(const QRgb &p, __m128i &v)
v = _mm_unpacklo_epi8(v, _mm_setzero_si128());
v = _mm_unpacklo_epi16(v, _mm_setzero_si128());
#endif
- v = _mm_slli_epi32(v, 4);
+ v = _mm_slli_epi32(v, QColorTrcLut::ShiftUp);
}
template<>
@@ -527,7 +550,7 @@ inline void loadPU<QRgba64>(const QRgba64 &p, __m128i &v)
#else
v = _mm_unpacklo_epi16(v, _mm_setzero_si128());
#endif
- v = _mm_srli_epi32(v, 4);
+ v = _mm_srli_epi32(v, QColorTrcLut::ShiftDown);
}
template<typename T>
@@ -552,7 +575,7 @@ void loadUnpremultiplied(QColorVector *buffer, const T *src, const qsizetype len
template<>
void loadUnpremultiplied<QRgbaFloat32>(QColorVector *buffer, const QRgbaFloat32 *src, const qsizetype len, const QColorTransformPrivate *d_ptr)
{
- const __m128 v4080 = _mm_set1_ps(4080.f);
+ const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
const __m128 iFF00 = _mm_set1_ps(1.0f / (255 * 256));
const __m128 vZero = _mm_set1_ps(0.0f);
const __m128 vOne = _mm_set1_ps(1.0f);
@@ -562,7 +585,7 @@ void loadUnpremultiplied<QRgbaFloat32>(QColorVector *buffer, const QRgbaFloat32
const __m128 over = _mm_cmpgt_ps(vf, vOne);
if (_mm_movemask_ps(_mm_or_ps(under, over)) == 0) {
// Within gamut
- __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, v4080));
+ __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
const int ridx = _mm_extract_epi16(v, 0);
const int gidx = _mm_extract_epi16(v, 2);
const int bidx = _mm_extract_epi16(v, 4);
@@ -623,7 +646,7 @@ static void loadPremultiplied(QColorVector *buffer, const T *src, const qsizetyp
vf = vreinterpretq_f32_u32(vbicq_u32(vreinterpretq_u32_f32(vf), vAlphaMask));
// LUT
- v = vcvtq_u32_f32(vaddq_f32(vmulq_n_f32(vf, 4080.f), vdupq_n_f32(0.5f)));
+ v = vcvtq_u32_f32(vaddq_f32(vmulq_n_f32(vf, float(QColorTrcLut::Resolution)), vdupq_n_f32(0.5f)));
const int ridx = isARGB ? vgetq_lane_u32(v, 2) : vgetq_lane_u32(v, 0);
const int gidx = vgetq_lane_u32(v, 1);
const int bidx = isARGB ? vgetq_lane_u32(v, 0) : vgetq_lane_u32(v, 2);
@@ -636,7 +659,7 @@ static void loadPremultiplied(QColorVector *buffer, const T *src, const qsizetyp
}
}
-// Load to [0-4080] in 4x32 SIMD
+// Load to [0->TrcResultion] in 4x32 SIMD
template<typename T>
static inline void loadPU(const T &p, uint32x4_t &v);
@@ -644,7 +667,7 @@ template<>
inline void loadPU<QRgb>(const QRgb &p, uint32x4_t &v)
{
v = vmovl_u16(vget_low_u16(vmovl_u8(vreinterpret_u8_u32(vmov_n_u32(p)))));
- v = vshlq_n_u32(v, 4);
+ v = vshlq_n_u32(v, QColorTrcLut::ShiftUp);
}
template<>
@@ -653,7 +676,7 @@ inline void loadPU<QRgba64>(const QRgba64 &p, uint32x4_t &v)
uint16x4_t v16 = vreinterpret_u16_u64(vld1_u64(reinterpret_cast<const uint64_t *>(&p)));
v16 = vsub_u16(v16, vshr_n_u16(v16, 8));
v = vmovl_u16(v16);
- v = vshrq_n_u32(v, 4);
+ v = vshrq_n_u32(v, QColorTrcLut::ShiftDown);
}
template<typename T>
@@ -682,7 +705,7 @@ void loadPremultiplied<QRgb>(QColorVector *buffer, const QRgb *src, const qsizet
const uint p = src[i];
const int a = qAlpha(p);
if (a) {
- const float ia = 4080.0f / a;
+ const float ia = float(QColorTrcLut::Resolution) / a;
const int ridx = int(qRed(p) * ia + 0.5f);
const int gidx = int(qGreen(p) * ia + 0.5f);
const int bidx = int(qBlue(p) * ia + 0.5f);
@@ -702,7 +725,7 @@ void loadPremultiplied<QRgba64>(QColorVector *buffer, const QRgba64 *src, const
const QRgba64 &p = src[i];
const int a = p.alpha();
if (a) {
- const float ia = 4080.0f / a;
+ const float ia = float(QColorTrcLut::Resolution) / a;
const int ridx = int(p.red() * ia + 0.5f);
const int gidx = int(p.green() * ia + 0.5f);
const int bidx = int(p.blue() * ia + 0.5f);
@@ -792,17 +815,18 @@ inline void storeP<QRgba64>(QRgba64 &p, __m128i &v, int a)
#endif
}
-template<typename T>
-static void storePremultiplied(T *dst, const T *src, const QColorVector *buffer, const qsizetype len,
+template<typename D, typename S,
+ typename = std::enable_if_t<!std::is_same_v<D, QRgbaFloat32>, void>>
+static void storePremultiplied(D *dst, const S *src, const QColorVector *buffer, const qsizetype len,
const QColorTransformPrivate *d_ptr)
{
- const __m128 v4080 = _mm_set1_ps(4080.f);
+ const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
const __m128 iFF00 = _mm_set1_ps(1.0f / (255 * 256));
- constexpr bool isARGB = isArgb<T>();
+ constexpr bool isARGB = isArgb<D>();
for (qsizetype i = 0; i < len; ++i) {
- const int a = getAlpha<T>(src[i]);
+ const int a = getAlpha<S>(src[i]);
__m128 vf = _mm_loadu_ps(&buffer[i].x);
- __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, v4080));
+ __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
__m128 va = _mm_mul_ps(_mm_set1_ps(a), iFF00);
const int ridx = _mm_extract_epi16(v, 0);
const int gidx = _mm_extract_epi16(v, 2);
@@ -813,21 +837,21 @@ static void storePremultiplied(T *dst, const T *src, const QColorVector *buffer,
vf = _mm_cvtepi32_ps(v);
vf = _mm_mul_ps(vf, va);
v = _mm_cvtps_epi32(vf);
- storeP<T>(dst[i], v, a);
+ storeP<D>(dst[i], v, a);
}
}
-template<>
-void storePremultiplied<QRgbaFloat32>(QRgbaFloat32 *dst, const QRgbaFloat32 *src,
- const QColorVector *buffer, const qsizetype len,
- const QColorTransformPrivate *d_ptr)
+template<typename S>
+static void storePremultiplied(QRgbaFloat32 *dst, const S *src,
+ const QColorVector *buffer, const qsizetype len,
+ const QColorTransformPrivate *d_ptr)
{
- const __m128 v4080 = _mm_set1_ps(4080.f);
+ const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
const __m128 vZero = _mm_set1_ps(0.0f);
const __m128 vOne = _mm_set1_ps(1.0f);
const __m128 viFF00 = _mm_set1_ps(1.0f / (255 * 256));
for (qsizetype i = 0; i < len; ++i) {
- const float a = src[i].a;
+ const float a = getAlphaF<S>(src[i]);
__m128 va = _mm_set1_ps(a);
__m128 vf = _mm_loadu_ps(&buffer[i].x);
const __m128 under = _mm_cmplt_ps(vf, vZero);
@@ -835,7 +859,7 @@ void storePremultiplied<QRgbaFloat32>(QRgbaFloat32 *dst, const QRgbaFloat32 *src
if (_mm_movemask_ps(_mm_or_ps(under, over)) == 0) {
// Within gamut
va = _mm_mul_ps(va, viFF00);
- __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, v4080));
+ __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
const int ridx = _mm_extract_epi16(v, 0);
const int gidx = _mm_extract_epi16(v, 2);
const int bidx = _mm_extract_epi16(v, 4);
@@ -874,16 +898,17 @@ inline void storePU<QRgba64>(QRgba64 &p, __m128i &v, int a)
_mm_storel_epi64((__m128i *)&p, v);
}
-template<typename T>
-static void storeUnpremultiplied(T *dst, const T *src, const QColorVector *buffer, const qsizetype len,
+template<typename D, typename S,
+ typename = std::enable_if_t<!std::is_same_v<D, QRgbaFloat32>, void>>
+static void storeUnpremultiplied(D *dst, const S *src, const QColorVector *buffer, const qsizetype len,
const QColorTransformPrivate *d_ptr)
{
- const __m128 v4080 = _mm_set1_ps(4080.f);
- constexpr bool isARGB = isArgb<T>();
+ const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
+ constexpr bool isARGB = isArgb<D>();
for (qsizetype i = 0; i < len; ++i) {
- const int a = getAlpha<T>(src[i]);
+ const int a = getAlpha<S>(src[i]);
__m128 vf = _mm_loadu_ps(&buffer[i].x);
- __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, v4080));
+ __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
const int ridx = _mm_extract_epi16(v, 0);
const int gidx = _mm_extract_epi16(v, 2);
const int bidx = _mm_extract_epi16(v, 4);
@@ -891,27 +916,27 @@ static void storeUnpremultiplied(T *dst, const T *src, const QColorVector *buffe
v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[0]->m_fromLinear[ridx], isARGB ? 2 : 0);
v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[1]->m_fromLinear[gidx], 1);
v = _mm_insert_epi16(v, d_ptr->colorSpaceOut->lut[2]->m_fromLinear[bidx], isARGB ? 0 : 2);
- storePU<T>(dst[i], v, a);
+ storePU<D>(dst[i], v, a);
}
}
-template<>
-void storeUnpremultiplied<QRgbaFloat32>(QRgbaFloat32 *dst, const QRgbaFloat32 *src,
- const QColorVector *buffer, const qsizetype len,
- const QColorTransformPrivate *d_ptr)
+template<typename S>
+void storeUnpremultiplied(QRgbaFloat32 *dst, const S *src,
+ const QColorVector *buffer, const qsizetype len,
+ const QColorTransformPrivate *d_ptr)
{
- const __m128 v4080 = _mm_set1_ps(4080.f);
+ const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
const __m128 vZero = _mm_set1_ps(0.0f);
const __m128 vOne = _mm_set1_ps(1.0f);
const __m128 viFF00 = _mm_set1_ps(1.0f / (255 * 256));
for (qsizetype i = 0; i < len; ++i) {
- const float a = src[i].a;
+ const float a = getAlphaF<S>(src[i]);
__m128 vf = _mm_loadu_ps(&buffer[i].x);
const __m128 under = _mm_cmplt_ps(vf, vZero);
const __m128 over = _mm_cmpgt_ps(vf, vOne);
if (_mm_movemask_ps(_mm_or_ps(under, over)) == 0) {
// Within gamut
- __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, v4080));
+ __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
const int ridx = _mm_extract_epi16(v, 0);
const int gidx = _mm_extract_epi16(v, 2);
const int bidx = _mm_extract_epi16(v, 4);
@@ -931,15 +956,14 @@ void storeUnpremultiplied<QRgbaFloat32>(QRgbaFloat32 *dst, const QRgbaFloat32 *s
}
template<typename T>
-static void storeOpaque(T *dst, const T *src, const QColorVector *buffer, const qsizetype len,
+static void storeOpaque(T *dst, const QColorVector *buffer, const qsizetype len,
const QColorTransformPrivate *d_ptr)
{
- Q_UNUSED(src);
- const __m128 v4080 = _mm_set1_ps(4080.f);
+ const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
constexpr bool isARGB = isArgb<T>();
for (qsizetype i = 0; i < len; ++i) {
__m128 vf = _mm_loadu_ps(&buffer[i].x);
- __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, v4080));
+ __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
const int ridx = _mm_extract_epi16(v, 0);
const int gidx = _mm_extract_epi16(v, 2);
const int bidx = _mm_extract_epi16(v, 4);
@@ -952,12 +976,10 @@ static void storeOpaque(T *dst, const T *src, const QColorVector *buffer, const
}
template<>
-void storeOpaque<QRgbaFloat32>(QRgbaFloat32 *dst, const QRgbaFloat32 *src,
- const QColorVector *buffer, const qsizetype len,
- const QColorTransformPrivate *d_ptr)
+void storeOpaque(QRgbaFloat32 *dst, const QColorVector *buffer, const qsizetype len,
+ const QColorTransformPrivate *d_ptr)
{
- Q_UNUSED(src);
- const __m128 v4080 = _mm_set1_ps(4080.f);
+ const __m128 vTrcRes = _mm_set1_ps(float(QColorTrcLut::Resolution));
const __m128 vZero = _mm_set1_ps(0.0f);
const __m128 vOne = _mm_set1_ps(1.0f);
const __m128 viFF00 = _mm_set1_ps(1.0f / (255 * 256));
@@ -967,7 +989,7 @@ void storeOpaque<QRgbaFloat32>(QRgbaFloat32 *dst, const QRgbaFloat32 *src,
const __m128 over = _mm_cmpgt_ps(vf, vOne);
if (_mm_movemask_ps(_mm_or_ps(under, over)) == 0) {
// Within gamut
- __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, v4080));
+ __m128i v = _mm_cvtps_epi32(_mm_mul_ps(vf, vTrcRes));
const int ridx = _mm_extract_epi16(v, 0);
const int gidx = _mm_extract_epi16(v, 2);
const int bidx = _mm_extract_epi16(v, 4);
@@ -1000,16 +1022,17 @@ inline void storeP<QRgba64>(QRgba64 &p, const uint16x4_t &v)
vst1_u16((uint16_t *)&p, v);
}
-template<typename T>
-static void storePremultiplied(T *dst, const T *src, const QColorVector *buffer, const qsizetype len,
+template<typename D, typename S,
+ typename = std::enable_if_t<!std::is_same_v<D, QRgbaFloat32>, void>>
+static void storePremultiplied(D *dst, const S *src, const QColorVector *buffer, const qsizetype len,
const QColorTransformPrivate *d_ptr)
{
const float iFF00 = 1.0f / (255 * 256);
- constexpr bool isARGB = isArgb<T>();
+ constexpr bool isARGB = isArgb<D>();
for (qsizetype i = 0; i < len; ++i) {
- const int a = getAlpha<T>(src[i]);
+ const int a = getAlpha<S>(src[i]);
float32x4_t vf = vld1q_f32(&buffer[i].x);
- uint32x4_t v = vcvtq_u32_f32(vaddq_f32(vmulq_n_f32(vf, 4080.f), vdupq_n_f32(0.5f)));
+ uint32x4_t v = vcvtq_u32_f32(vaddq_f32(vmulq_n_f32(vf, float(QColorTrcLut::Resolution)), vdupq_n_f32(0.5f)));
const int ridx = vgetq_lane_u32(v, 0);
const int gidx = vgetq_lane_u32(v, 1);
const int bidx = vgetq_lane_u32(v, 2);
@@ -1022,7 +1045,7 @@ static void storePremultiplied(T *dst, const T *src, const QColorVector *buffer,
v = vcvtq_u32_f32(vf);
uint16x4_t v16 = vmovn_u32(v);
v16 = vset_lane_u16(a, v16, 3);
- storeP<T>(dst[i], v16);
+ storeP<D>(dst[i], v16);
}
}
@@ -1044,34 +1067,34 @@ inline void storePU<QRgba64>(QRgba64 &p, uint16x4_t &v, int a)
vst1_u16((uint16_t *)&p, v);
}
-template<typename T>
-static void storeUnpremultiplied(T *dst, const T *src, const QColorVector *buffer, const qsizetype len,
+template<typename D, typename S,
+ typename = std::enable_if_t<!std::is_same_v<D, QRgbaFloat32>, void>>
+static void storeUnpremultiplied(D *dst, const S *src, const QColorVector *buffer, const qsizetype len,
const QColorTransformPrivate *d_ptr)
{
- constexpr bool isARGB = isArgb<T>();
+ constexpr bool isARGB = isArgb<D>();
for (qsizetype i = 0; i < len; ++i) {
- const int a = getAlpha<T>(src[i]);
+ const int a = getAlpha<S>(src[i]);
float32x4_t vf = vld1q_f32(&buffer[i].x);
- uint16x4_t v = vmovn_u32(vcvtq_u32_f32(vaddq_f32(vmulq_n_f32(vf, 4080.f), vdupq_n_f32(0.5f))));
+ uint16x4_t v = vmovn_u32(vcvtq_u32_f32(vaddq_f32(vmulq_n_f32(vf, float(QColorTrcLut::Resolution)), vdupq_n_f32(0.5f))));
const int ridx = vget_lane_u16(v, 0);
const int gidx = vget_lane_u16(v, 1);
const int bidx = vget_lane_u16(v, 2);
v = vset_lane_u16(d_ptr->colorSpaceOut->lut[0]->m_fromLinear[ridx], v, isARGB ? 2 : 0);
v = vset_lane_u16(d_ptr->colorSpaceOut->lut[1]->m_fromLinear[gidx], v, 1);
v = vset_lane_u16(d_ptr->colorSpaceOut->lut[2]->m_fromLinear[bidx], v, isARGB ? 0 : 2);
- storePU<T>(dst[i], v, a);
+ storePU<D>(dst[i], v, a);
}
}
template<typename T>
-static void storeOpaque(T *dst, const T *src, const QColorVector *buffer, const qsizetype len,
+static void storeOpaque(T *dst, const QColorVector *buffer, const qsizetype len,
const QColorTransformPrivate *d_ptr)
{
- Q_UNUSED(src);
constexpr bool isARGB = isArgb<T>();
for (qsizetype i = 0; i < len; ++i) {
float32x4_t vf = vld1q_f32(&buffer[i].x);
- uint16x4_t v = vmovn_u32(vcvtq_u32_f32(vaddq_f32(vmulq_n_f32(vf, 4080.f), vdupq_n_f32(0.5f))));
+ uint16x4_t v = vmovn_u32(vcvtq_u32_f32(vaddq_f32(vmulq_n_f32(vf, float(QColorTrcLut::Resolution)), vdupq_n_f32(0.5f))));
const int ridx = vget_lane_u16(v, 0);
const int gidx = vget_lane_u16(v, 1);
const int bidx = vget_lane_u16(v, 2);
@@ -1088,9 +1111,9 @@ static void storePremultiplied(QRgb *dst, const QRgb *src, const QColorVector *b
for (qsizetype i = 0; i < len; ++i) {
const int a = qAlpha(src[i]);
const float fa = a / (255.0f * 256.0f);
- const float r = d_ptr->colorSpaceOut->lut[0]->m_fromLinear[int(buffer[i].x * 4080.0f + 0.5f)];
- const float g = d_ptr->colorSpaceOut->lut[1]->m_fromLinear[int(buffer[i].y * 4080.0f + 0.5f)];
- const float b = d_ptr->colorSpaceOut->lut[2]->m_fromLinear[int(buffer[i].z * 4080.0f + 0.5f)];
+ const float r = d_ptr->colorSpaceOut->lut[0]->m_fromLinear[int(buffer[i].x * float(QColorTrcLut::Resolution) + 0.5f)];
+ const float g = d_ptr->colorSpaceOut->lut[1]->m_fromLinear[int(buffer[i].y * float(QColorTrcLut::Resolution) + 0.5f)];
+ const float b = d_ptr->colorSpaceOut->lut[2]->m_fromLinear[int(buffer[i].z * float(QColorTrcLut::Resolution) + 0.5f)];
dst[i] = qRgba(r * fa + 0.5f, g * fa + 0.5f, b * fa + 0.5f, a);
}
}
@@ -1106,10 +1129,9 @@ static void storeUnpremultiplied(QRgb *dst, const QRgb *src, const QColorVector
}
}
-static void storeOpaque(QRgb *dst, const QRgb *src, const QColorVector *buffer, const qsizetype len,
+static void storeOpaque(QRgb *dst, const QColorVector *buffer, const qsizetype len,
const QColorTransformPrivate *d_ptr)
{
- Q_UNUSED(src);
for (qsizetype i = 0; i < len; ++i) {
const int r = d_ptr->colorSpaceOut->lut[0]->u8FromLinearF32(buffer[i].x);
const int g = d_ptr->colorSpaceOut->lut[1]->u8FromLinearF32(buffer[i].y);
@@ -1118,34 +1140,36 @@ static void storeOpaque(QRgb *dst, const QRgb *src, const QColorVector *buffer,
}
}
-static void storePremultiplied(QRgba64 *dst, const QRgba64 *src, const QColorVector *buffer, const qsizetype len,
+template<typename S>
+static void storePremultiplied(QRgba64 *dst, const S *src, const QColorVector *buffer, const qsizetype len,
const QColorTransformPrivate *d_ptr)
{
for (qsizetype i = 0; i < len; ++i) {
- const int a = src[i].alpha();
+ const int a = getAlphaF(src[i]) * 65535.f;
const float fa = a / (255.0f * 256.0f);
- const float r = d_ptr->colorSpaceOut->lut[0]->m_fromLinear[int(buffer[i].x * 4080.0f + 0.5f)];
- const float g = d_ptr->colorSpaceOut->lut[1]->m_fromLinear[int(buffer[i].y * 4080.0f + 0.5f)];
- const float b = d_ptr->colorSpaceOut->lut[2]->m_fromLinear[int(buffer[i].z * 4080.0f + 0.5f)];
+ const float r = d_ptr->colorSpaceOut->lut[0]->m_fromLinear[int(buffer[i].x * float(QColorTrcLut::Resolution) + 0.5f)];
+ const float g = d_ptr->colorSpaceOut->lut[1]->m_fromLinear[int(buffer[i].y * float(QColorTrcLut::Resolution) + 0.5f)];
+ const float b = d_ptr->colorSpaceOut->lut[2]->m_fromLinear[int(buffer[i].z * float(QColorTrcLut::Resolution) + 0.5f)];
dst[i] = qRgba64(r * fa + 0.5f, g * fa + 0.5f, b * fa + 0.5f, a);
}
}
-static void storeUnpremultiplied(QRgba64 *dst, const QRgba64 *src, const QColorVector *buffer, const qsizetype len,
+template<typename S>
+static void storeUnpremultiplied(QRgba64 *dst, const S *src, const QColorVector *buffer, const qsizetype len,
const QColorTransformPrivate *d_ptr)
{
for (qsizetype i = 0; i < len; ++i) {
+ const int a = getAlphaF(src[i]) * 65535.f;
const int r = d_ptr->colorSpaceOut->lut[0]->u16FromLinearF32(buffer[i].x);
const int g = d_ptr->colorSpaceOut->lut[1]->u16FromLinearF32(buffer[i].y);
const int b = d_ptr->colorSpaceOut->lut[2]->u16FromLinearF32(buffer[i].z);
- dst[i] = qRgba64(r, g, b, src[i].alpha());
+ dst[i] = qRgba64(r, g, b, a);
}
}
-static void storeOpaque(QRgba64 *dst, const QRgba64 *src, const QColorVector *buffer, const qsizetype len,
+static void storeOpaque(QRgba64 *dst, const QColorVector *buffer, const qsizetype len,
const QColorTransformPrivate *d_ptr)
{
- Q_UNUSED(src);
for (qsizetype i = 0; i < len; ++i) {
const int r = d_ptr->colorSpaceOut->lut[0]->u16FromLinearF32(buffer[i].x);
const int g = d_ptr->colorSpaceOut->lut[1]->u16FromLinearF32(buffer[i].y);
@@ -1155,11 +1179,12 @@ static void storeOpaque(QRgba64 *dst, const QRgba64 *src, const QColorVector *bu
}
#endif
#if !defined(__SSE2__)
-static void storePremultiplied(QRgbaFloat32 *dst, const QRgbaFloat32 *src, const QColorVector *buffer,
+template<typename S>
+static void storePremultiplied(QRgbaFloat32 *dst, const S *src, const QColorVector *buffer,
const qsizetype len, const QColorTransformPrivate *d_ptr)
{
for (qsizetype i = 0; i < len; ++i) {
- const float a = src[i].a;
+ const float a = getAlphaF(src[i]);
dst[i].r = d_ptr->colorSpaceOut->trc[0].applyInverseExtended(buffer[i].x) * a;
dst[i].g = d_ptr->colorSpaceOut->trc[1].applyInverseExtended(buffer[i].y) * a;
dst[i].b = d_ptr->colorSpaceOut->trc[2].applyInverseExtended(buffer[i].z) * a;
@@ -1167,11 +1192,12 @@ static void storePremultiplied(QRgbaFloat32 *dst, const QRgbaFloat32 *src, const
}
}
-static void storeUnpremultiplied(QRgbaFloat32 *dst, const QRgbaFloat32 *src, const QColorVector *buffer,
+template<typename S>
+static void storeUnpremultiplied(QRgbaFloat32 *dst, const S *src, const QColorVector *buffer,
const qsizetype len, const QColorTransformPrivate *d_ptr)
{
for (qsizetype i = 0; i < len; ++i) {
- const float a = src[i].a;
+ const float a = getAlphaF(src[i]);
dst[i].r = d_ptr->colorSpaceOut->trc[0].applyInverseExtended(buffer[i].x);
dst[i].g = d_ptr->colorSpaceOut->trc[1].applyInverseExtended(buffer[i].y);
dst[i].b = d_ptr->colorSpaceOut->trc[2].applyInverseExtended(buffer[i].z);
@@ -1179,10 +1205,9 @@ static void storeUnpremultiplied(QRgbaFloat32 *dst, const QRgbaFloat32 *src, con
}
}
-static void storeOpaque(QRgbaFloat32 *dst, const QRgbaFloat32 *src, const QColorVector *buffer, const qsizetype len,
+static void storeOpaque(QRgbaFloat32 *dst, const QColorVector *buffer, const qsizetype len,
const QColorTransformPrivate *d_ptr)
{
- Q_UNUSED(src);
for (qsizetype i = 0; i < len; ++i) {
dst[i].r = d_ptr->colorSpaceOut->trc[0].applyInverseExtended(buffer[i].x);
dst[i].g = d_ptr->colorSpaceOut->trc[1].applyInverseExtended(buffer[i].y);
@@ -1191,20 +1216,35 @@ static void storeOpaque(QRgbaFloat32 *dst, const QRgbaFloat32 *src, const QColor
}
}
#endif
-static void storeGray(quint8 *dst, const QRgb *src, const QColorVector *buffer, const qsizetype len,
+
+static void loadGray(QColorVector *buffer, const quint8 *src, const qsizetype len, const QColorTransformPrivate *d_ptr)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const float y = d_ptr->colorSpaceIn->lut[0]->u8ToLinearF32(src[i]);
+ buffer[i] = d_ptr->colorSpaceIn->whitePoint * y;
+ }
+}
+
+static void loadGray(QColorVector *buffer, const quint16 *src, const qsizetype len, const QColorTransformPrivate *d_ptr)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const float y = d_ptr->colorSpaceIn->lut[0]->u16ToLinearF32(src[i]);
+ buffer[i] = d_ptr->colorSpaceIn->whitePoint * y;
+ }
+}
+
+static void storeOpaque(quint8 *dst, const QColorVector *buffer, const qsizetype len,
const QColorTransformPrivate *d_ptr)
{
- Q_UNUSED(src);
for (qsizetype i = 0; i < len; ++i)
- dst[i] = d_ptr->colorSpaceOut->lut[1]->u8FromLinearF32(buffer[i].y);
+ dst[i] = d_ptr->colorSpaceOut->lut[0]->u8FromLinearF32(buffer[i].y);
}
-static void storeGray(quint16 *dst, const QRgba64 *src, const QColorVector *buffer, const qsizetype len,
+static void storeOpaque(quint16 *dst, const QColorVector *buffer, const qsizetype len,
const QColorTransformPrivate *d_ptr)
{
- Q_UNUSED(src);
for (qsizetype i = 0; i < len; ++i)
- dst[i] = d_ptr->colorSpaceOut->lut[1]->u16FromLinearF32(buffer[i].y);
+ dst[i] = d_ptr->colorSpaceOut->lut[0]->u16FromLinearF32(buffer[i].y);
}
static constexpr qsizetype WorkBlockSize = 256;
@@ -1218,53 +1258,493 @@ private:
alignas(T) char data[sizeof(T) * Count];
};
+void loadUnpremultipliedLUT(QColorVector *buffer, const QRgb *src, const qsizetype len)
+{
+ const float f = 1.0f / 255.f;
+ for (qsizetype i = 0; i < len; ++i) {
+ const uint p = src[i];
+ buffer[i].x = qRed(p) * f;
+ buffer[i].y = qGreen(p) * f;
+ buffer[i].z = qBlue(p) * f;
+ }
+}
+
+void loadUnpremultipliedLUT(QColorVector *buffer, const QCmyk32 *src, const qsizetype len)
+{
+ const float f = 1.0f / 255.f;
+ for (qsizetype i = 0; i < len; ++i) {
+ const QCmyk32 p = src[i];
+ buffer[i].x = (p.cyan() * f);
+ buffer[i].y = (p.magenta() * f);
+ buffer[i].z = (p.yellow() * f);
+ buffer[i].w = (p.black() * f);
+ }
+}
+
+void loadUnpremultipliedLUT(QColorVector *buffer, const QRgba64 *src, const qsizetype len)
+{
+ const float f = 1.0f / 65535.f;
+ for (qsizetype i = 0; i < len; ++i) {
+ buffer[i].x = src[i].red() * f;
+ buffer[i].y = src[i].green() * f;
+ buffer[i].z = src[i].blue() * f;
+ }
+}
+
+void loadUnpremultipliedLUT(QColorVector *buffer, const QRgbaFloat32 *src, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ buffer[i].x = src[i].r;
+ buffer[i].y = src[i].g;
+ buffer[i].z = src[i].b;
+ }
+}
+
+void loadPremultipliedLUT(QColorVector *buffer, const QRgb *src, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const uint p = src[i];
+ const float f = 1.0f / qAlpha(p);
+ buffer[i].x = (qRed(p) * f);
+ buffer[i].y = (qGreen(p) * f);
+ buffer[i].z = (qBlue(p) * f);
+ }
+}
+
+void loadPremultipliedLUT(QColorVector *, const QCmyk32 *, const qsizetype)
+{
+ Q_UNREACHABLE();
+}
+
+void loadPremultipliedLUT(QColorVector *buffer, const QRgba64 *src, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const float f = 1.0f / src[i].alpha();
+ buffer[i].x = (src[i].red() * f);
+ buffer[i].y = (src[i].green() * f);
+ buffer[i].z = (src[i].blue() * f);
+ }
+}
+
+void loadPremultipliedLUT(QColorVector *buffer, const QRgbaFloat32 *src, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const float f = 1.0f / src[i].a;
+ buffer[i].x = src[i].r * f;
+ buffer[i].y = src[i].g * f;
+ buffer[i].z = src[i].b * f;
+ }
+}
template<typename T>
-void QColorTransformPrivate::apply(T *dst, const T *src, qsizetype count, TransformFlags flags) const
+static void storeUnpremultipliedLUT(QRgb *dst, const T *, const QColorVector *buffer, const qsizetype len)
{
- if (!colorMatrix.isValid())
+ for (qsizetype i = 0; i < len; ++i) {
+ const int r = buffer[i].x * 255.f;
+ const int g = buffer[i].y * 255.f;
+ const int b = buffer[i].z * 255.f;
+ dst[i] = 0xff000000 | (r << 16) | (g << 8) | (b << 0);
+ }
+}
+
+template<>
+void storeUnpremultipliedLUT(QRgb *dst, const QRgb *src, const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int r = buffer[i].x * 255.f;
+ const int g = buffer[i].y * 255.f;
+ const int b = buffer[i].z * 255.f;
+ dst[i] = (src[i] & 0xff000000) | (r << 16) | (g << 8) | (b << 0);
+ }
+}
+
+
+template<typename T>
+void storeUnpremultipliedLUT(QCmyk32 *dst, const T *, const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int c = buffer[i].x * 255.f;
+ const int m = buffer[i].y * 255.f;
+ const int y = buffer[i].z * 255.f;
+ const int k = buffer[i].w * 255.f;
+ dst[i] = QCmyk32(c, m, y, k);
+ }
+}
+
+template<typename T>
+static void storeUnpremultipliedLUT(QRgba64 *dst, const T *,
+ const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int r = buffer[i].x * 65535.f;
+ const int g = buffer[i].y * 65535.f;
+ const int b = buffer[i].z * 65535.f;
+ dst[i] = qRgba64(r, g, b, 65535);
+ }
+}
+
+template<>
+void storeUnpremultipliedLUT(QRgba64 *dst, const QRgb *src,
+ const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int a = qAlpha(src[i]) * 257;
+ const int r = buffer[i].x * 65535.f;
+ const int g = buffer[i].y * 65535.f;
+ const int b = buffer[i].z * 65535.f;
+ dst[i] = qRgba64(r, g, b, a);
+ }
+}
+
+template<>
+void storeUnpremultipliedLUT(QRgba64 *dst, const QRgba64 *src,
+ const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int r = buffer[i].x * 65535.f;
+ const int g = buffer[i].y * 65535.f;
+ const int b = buffer[i].z * 65535.f;
+ dst[i] = qRgba64(r, g, b, src[i].alpha());
+ }
+}
+
+template<typename T>
+static void storeUnpremultipliedLUT(QRgbaFloat32 *dst, const T *src,
+ const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const float r = buffer[i].x;
+ const float g = buffer[i].y;
+ const float b = buffer[i].z;
+ dst[i] = QRgbaFloat32{r, g, b, getAlphaF(src[i])};
+ }
+}
+
+template<typename T>
+static void storePremultipliedLUT(QRgb *, const T *, const QColorVector *, const qsizetype);
+
+template<>
+void storePremultipliedLUT(QRgb *dst, const QRgb *src, const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int a = qAlpha(src[i]);
+ const int r = buffer[i].x * a;
+ const int g = buffer[i].y * a;
+ const int b = buffer[i].z * a;
+ dst[i] = (src[i] & 0xff000000) | (r << 16) | (g << 8) | (b << 0);
+ }
+}
+
+template<>
+void storePremultipliedLUT(QRgb *dst, const QCmyk32 *, const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int r = buffer[i].x * 255.f;
+ const int g = buffer[i].y * 255.f;
+ const int b = buffer[i].z * 255.f;
+ dst[i] = 0xff000000 | (r << 16) | (g << 8) | (b << 0);
+ }
+}
+
+
+template<typename T>
+static void storePremultipliedLUT(QCmyk32 *dst, const T *src, const QColorVector *buffer, const qsizetype len)
+{
+ storeUnpremultipliedLUT(dst, src, buffer, len);
+}
+
+template<typename T>
+static void storePremultipliedLUT(QRgba64 *, const T *, const QColorVector *, const qsizetype);
+
+template<>
+void storePremultipliedLUT(QRgba64 *dst, const QRgb *src, const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int a = qAlpha(src[i]) * 257;
+ const int r = buffer[i].x * a;
+ const int g = buffer[i].y * a;
+ const int b = buffer[i].z * a;
+ dst[i] = qRgba64(r, g, b, a);
+ }
+}
+
+template<>
+void storePremultipliedLUT(QRgba64 *dst, const QCmyk32 *, const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int r = buffer[i].x * 65535.f;
+ const int g = buffer[i].y * 65535.f;
+ const int b = buffer[i].z * 65535.f;
+ dst[i] = qRgba64(r, g, b, 65535);
+ }
+}
+
+template<>
+void storePremultipliedLUT(QRgba64 *dst, const QRgba64 *src, const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const int a = src[i].alpha();
+ const int r = buffer[i].x * a;
+ const int g = buffer[i].y * a;
+ const int b = buffer[i].z * a;
+ dst[i] = qRgba64(r, g, b, a);
+ }
+}
+
+template<typename T>
+static void storePremultipliedLUT(QRgbaFloat32 *dst, const T *src, const QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i) {
+ const float a = getAlphaF(src[i]);
+ const float r = buffer[i].x * a;
+ const float g = buffer[i].y * a;
+ const float b = buffer[i].z * a;
+ dst[i] = QRgbaFloat32{r, g, b, a};
+ }
+}
+
+static void visitElement(const QColorSpacePrivate::TransferElement &element, QColorVector *buffer, const qsizetype len)
+{
+ const bool doW = element.trc[3].isValid();
+ for (qsizetype i = 0; i < len; ++i) {
+ buffer[i].x = element.trc[0].apply(buffer[i].x);
+ buffer[i].y = element.trc[1].apply(buffer[i].y);
+ buffer[i].z = element.trc[2].apply(buffer[i].z);
+ if (doW)
+ buffer[i].w = element.trc[3].apply(buffer[i].w);
+ }
+}
+
+static void visitElement(const QColorMatrix &element, QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i)
+ buffer[i] = element.map(buffer[i]);
+}
+
+static void visitElement(const QColorVector &offset, QColorVector *buffer, const qsizetype len)
+{
+ for (qsizetype i = 0; i < len; ++i)
+ buffer[i] += offset;
+}
+
+static void visitElement(const QColorCLUT &element, QColorVector *buffer, const qsizetype len)
+{
+ if (element.isEmpty())
return;
+ for (qsizetype i = 0; i < len; ++i)
+ buffer[i] = element.apply(buffer[i]);
+}
- updateLutsIn();
- updateLutsOut();
+/*!
+ \internal
+*/
+QColorVector QColorTransformPrivate::map(QColorVector c) const
+{
+ if (colorSpaceIn->isThreeComponentMatrix()) {
+ if (colorSpaceIn->lut.generated.loadAcquire()) {
+ c.x = colorSpaceIn->lut[0]->toLinear(c.x);
+ c.y = colorSpaceIn->lut[1]->toLinear(c.y);
+ c.z = colorSpaceIn->lut[2]->toLinear(c.z);
+ } else {
+ c.x = colorSpaceIn->trc[0].apply(c.x);
+ c.y = colorSpaceIn->trc[1].apply(c.y);
+ c.z = colorSpaceIn->trc[2].apply(c.z);
+ }
+ c = colorMatrix.map(c);
+ } else {
+ // Do element based conversion
+ for (auto &&element : colorSpaceIn->mAB)
+ std::visit([&c](auto &&elm) { visitElement(elm, &c, 1); }, element);
+ }
+ c.x = std::clamp(c.x, 0.0f, 1.0f);
+ c.y = std::clamp(c.y, 0.0f, 1.0f);
+ c.z = std::clamp(c.z, 0.0f, 1.0f);
+
+ // Match Profile Connection Spaces (PCS):
+ if (colorSpaceOut->isPcsLab && !colorSpaceIn->isPcsLab)
+ c = c.xyzToLab();
+ else if (colorSpaceIn->isPcsLab && !colorSpaceOut->isPcsLab)
+ c = c.labToXyz();
+
+ if (colorSpaceOut->isThreeComponentMatrix()) {
+ if (!colorSpaceIn->isThreeComponentMatrix()) {
+ c = colorMatrix.map(c);
+ c.x = std::clamp(c.x, 0.0f, 1.0f);
+ c.y = std::clamp(c.y, 0.0f, 1.0f);
+ c.z = std::clamp(c.z, 0.0f, 1.0f);
+ }
+ if (colorSpaceOut->lut.generated.loadAcquire()) {
+ c.x = colorSpaceOut->lut[0]->fromLinear(c.x);
+ c.y = colorSpaceOut->lut[1]->fromLinear(c.y);
+ c.z = colorSpaceOut->lut[2]->fromLinear(c.z);
+ } else {
+ c.x = colorSpaceOut->trc[0].applyInverse(c.x);
+ c.y = colorSpaceOut->trc[1].applyInverse(c.y);
+ c.z = colorSpaceOut->trc[2].applyInverse(c.z);
+ }
+ } else {
+ // Do element based conversion
+ for (auto &&element : colorSpaceOut->mBA)
+ std::visit([&c](auto &&elm) { visitElement(elm, &c, 1); }, element);
+ c.x = std::clamp(c.x, 0.0f, 1.0f);
+ c.y = std::clamp(c.y, 0.0f, 1.0f);
+ c.z = std::clamp(c.z, 0.0f, 1.0f);
+ }
+ return c;
+}
- bool doApplyMatrix = !colorMatrix.isIdentity();
- constexpr bool DoClip = !std::is_same_v<T, QRgbaFloat16> && !std::is_same_v<T, QRgbaFloat32>;
+/*!
+ \internal
+*/
+QColorVector QColorTransformPrivate::mapExtended(QColorVector c) const
+{
+ if (colorSpaceIn->isThreeComponentMatrix()) {
+ c.x = colorSpaceIn->trc[0].applyExtended(c.x);
+ c.y = colorSpaceIn->trc[1].applyExtended(c.y);
+ c.z = colorSpaceIn->trc[2].applyExtended(c.z);
+ c = colorMatrix.map(c);
+ } else {
+ // Do element based conversion
+ for (auto &&element : colorSpaceIn->mAB)
+ std::visit([&c](auto &&elm) { visitElement(elm, &c, 1); }, element);
+ }
- QUninitialized<QColorVector, WorkBlockSize> buffer;
+ // Match Profile Connection Spaces (PCS):
+ if (colorSpaceOut->isPcsLab && !colorSpaceIn->isPcsLab)
+ c = c.xyzToLab();
+ else if (colorSpaceIn->isPcsLab && !colorSpaceOut->isPcsLab)
+ c = c.labToXyz();
+
+ if (colorSpaceOut->isThreeComponentMatrix()) {
+ if (!colorSpaceIn->isThreeComponentMatrix())
+ c = colorMatrix.map(c);
+ c.x = colorSpaceOut->trc[0].applyInverseExtended(c.x);
+ c.y = colorSpaceOut->trc[1].applyInverseExtended(c.y);
+ c.z = colorSpaceOut->trc[2].applyInverseExtended(c.z);
+ } else {
+ // Do element based conversion
+ for (auto &&element : colorSpaceOut->mBA)
+ std::visit([&c](auto &&elm) { visitElement(elm, &c, 1); }, element);
+ }
+ return c;
+}
+
+template<typename S>
+void QColorTransformPrivate::applyConvertIn(const S *src, QColorVector *buffer, qsizetype len, TransformFlags flags) const
+{
+ // Avoid compiling this part for S=QCmyk32:
+ if constexpr (!std::is_same_v<S, QCmyk32>) {
+ if (colorSpaceIn->isThreeComponentMatrix()) {
+ if (flags & InputPremultiplied)
+ loadPremultiplied(buffer, src, len, this);
+ else
+ loadUnpremultiplied(buffer, src, len, this);
+
+ if (!colorSpaceOut->isThreeComponentMatrix())
+ applyMatrix<DoClamp>(buffer, len, colorMatrix); // colorMatrix should have the first half only.
+ return;
+ }
+ }
+ Q_ASSERT(!colorSpaceIn->isThreeComponentMatrix());
+
+ if (flags & InputPremultiplied)
+ loadPremultipliedLUT(buffer, src, len);
+ else
+ loadUnpremultipliedLUT(buffer, src, len);
+
+ if constexpr (std::is_same_v<S, QRgbaFloat16> || std::is_same_v<S, QRgbaFloat32>)
+ clampIfNeeded<DoClamp>(buffer, len);
+
+ // Do element based conversion
+ for (auto &&element : colorSpaceIn->mAB)
+ std::visit([&buffer, len](auto &&elm) { visitElement(elm, buffer, len); }, element);
+}
+
+template<typename D, typename S>
+void QColorTransformPrivate::applyConvertOut(D *dst, const S *src, QColorVector *buffer, qsizetype len, TransformFlags flags) const
+{
+ constexpr ApplyMatrixForm doClamp = (std::is_same_v<D, QRgbaFloat16> || std::is_same_v<D, QRgbaFloat32>) ? DoNotClamp : DoClamp;
+ // Avoid compiling this part for D=QCmyk32:
+ if constexpr (!std::is_same_v<D, QCmyk32>) {
+ if (colorSpaceOut->isThreeComponentMatrix()) {
+ applyMatrix<doClamp>(buffer, len, colorMatrix); // colorMatrix should have the latter half only.
+
+ if constexpr (std::is_same_v<S, QCmyk32>) {
+ storeOpaque(dst, buffer, len, this);
+ } else {
+ if (flags & InputOpaque)
+ storeOpaque(dst, buffer, len, this);
+ else if (flags & OutputPremultiplied)
+ storePremultiplied(dst, src, buffer, len, this);
+ else
+ storeUnpremultiplied(dst, src, buffer, len, this);
+ }
+ return;
+ }
+ }
+ Q_ASSERT(!colorSpaceOut->isThreeComponentMatrix());
+
+ // Do element based conversion
+ for (auto &&element : colorSpaceOut->mBA)
+ std::visit([&buffer, len](auto &&elm) { visitElement(elm, buffer, len); }, element);
+
+ clampIfNeeded<doClamp>(buffer, len);
+
+ if (flags & OutputPremultiplied)
+ storePremultipliedLUT(dst, src, buffer, len);
+ else
+ storeUnpremultipliedLUT(dst, src, buffer, len);
+}
+
+template<typename D, typename S>
+void QColorTransformPrivate::applyElementListTransform(D *dst, const S *src, qsizetype count, TransformFlags flags) const
+{
+ Q_ASSERT(!colorSpaceIn->isThreeComponentMatrix() || !colorSpaceOut->isThreeComponentMatrix());
+ if (!colorMatrix.isValid())
+ return;
+
+ if (colorSpaceIn->isThreeComponentMatrix())
+ updateLutsIn();
+ if (colorSpaceOut->isThreeComponentMatrix())
+ updateLutsOut();
+
+ QUninitialized<QColorVector, WorkBlockSize> buffer;
qsizetype i = 0;
while (i < count) {
const qsizetype len = qMin(count - i, WorkBlockSize);
- if (flags & InputPremultiplied)
- loadPremultiplied(buffer, src + i, len, this);
- else
- loadUnpremultiplied(buffer, src + i, len, this);
- if (doApplyMatrix)
- applyMatrix<DoClip>(buffer, len, colorMatrix);
+ applyConvertIn(src + i, buffer, len, flags);
- if (flags & InputOpaque)
- storeOpaque(dst + i, src + i, buffer, len, this);
- else if (flags & OutputPremultiplied)
- storePremultiplied(dst + i, src + i, buffer, len, this);
- else
- storeUnpremultiplied(dst + i, src + i, buffer, len, this);
+ // Match Profile Connection Spaces (PCS):
+ if (colorSpaceOut->isPcsLab && !colorSpaceIn->isPcsLab) {
+ for (qsizetype j = 0; j < len; ++j)
+ buffer[j] = buffer[j].xyzToLab();
+ } else if (colorSpaceIn->isPcsLab && !colorSpaceOut->isPcsLab) {
+ for (qsizetype j = 0; j < len; ++j)
+ buffer[j] = buffer[j].labToXyz();
+ }
+
+ applyConvertOut(dst + i, src + i, buffer, len, flags);
i += len;
}
}
template<typename D, typename S>
-void QColorTransformPrivate::applyReturnGray(D *dst, const S *src, qsizetype count, TransformFlags flags) const
+void QColorTransformPrivate::applyThreeComponentMatrix(D *dst, const S *src, qsizetype count, TransformFlags flags) const
{
+ Q_ASSERT(colorSpaceIn->isThreeComponentMatrix() && colorSpaceOut->isThreeComponentMatrix());
+
if (!colorMatrix.isValid())
return;
updateLutsIn();
updateLutsOut();
- QUninitialized<QColorVector, WorkBlockSize> buffer;
+ bool doApplyMatrix = !colorMatrix.isIdentity();
+ constexpr ApplyMatrixForm doClamp = (std::is_same_v<D, QRgbaFloat16> || std::is_same_v<D, QRgbaFloat32>) ? DoNotClamp : DoClamp;
+ QUninitialized<QColorVector, WorkBlockSize> buffer;
qsizetype i = 0;
while (i < count) {
const qsizetype len = qMin(count - i, WorkBlockSize);
@@ -1273,9 +1753,17 @@ void QColorTransformPrivate::applyReturnGray(D *dst, const S *src, qsizetype cou
else
loadUnpremultiplied(buffer, src + i, len, this);
- applyMatrix(buffer, len, colorMatrix);
+ if (doApplyMatrix)
+ applyMatrix<doClamp>(buffer, len, colorMatrix);
+ else
+ clampIfNeeded<doClamp>(buffer, len);
- storeGray(dst + i, src + i, buffer, len, this);
+ if (flags & InputOpaque)
+ storeOpaque(dst + i, buffer, len, this);
+ else if (flags & OutputPremultiplied)
+ storePremultiplied(dst + i, src + i, buffer, len, this);
+ else
+ storeUnpremultiplied(dst + i, src + i, buffer, len, this);
i += len;
}
@@ -1283,110 +1771,228 @@ void QColorTransformPrivate::applyReturnGray(D *dst, const S *src, qsizetype cou
/*!
\internal
- \enum QColorTransformPrivate::TransformFlag
+ Applies the color transformation on \a count S pixels starting from
+ \a src and stores the result in \a dst as D pixels .
- Defines how the transform is to be applied.
+ Assumes unpremultiplied data by default. Set \a flags to change defaults.
- \value Unpremultiplied The input and output should both be unpremultiplied.
- \value InputOpaque The input is guaranteed to be opaque.
- \value InputPremultiplied The input is premultiplied.
- \value OutputPremultiplied The output should be premultiplied.
- \value Premultiplied Both input and output should both be premultiplied.
+ \sa prepare()
*/
+template<typename D, typename S>
+void QColorTransformPrivate::apply(D *dst, const S *src, qsizetype count, TransformFlags flags) const
+{
+ if constexpr (!std::is_same_v<D, QCmyk32> && !std::is_same_v<S, QCmyk32>) {
+ if (isThreeComponentMatrix())
+ return applyThreeComponentMatrix<D, S>(dst, src, count, flags);
+ }
+ applyElementListTransform<D, S>(dst, src, count, flags);
+}
/*!
\internal
- Prepares a color transformation for fast application. You do not need to
- call this explicitly as it will be called implicitly on the first transforms, but
- if you want predictable performance on the first transforms, you can perform it
- in advance.
+ Is to be called on a color-transform to XYZ, returns only luminance values.
- \sa QColorTransform::map(), apply()
-*/
-void QColorTransformPrivate::prepare()
+ */
+template<typename D, typename S>
+void QColorTransformPrivate::applyReturnGray(D *dst, const S *src, qsizetype count, TransformFlags flags) const
{
- updateLutsIn();
+ Q_ASSERT(colorSpaceOut->isThreeComponentMatrix());
updateLutsOut();
-}
+ if (!colorSpaceIn->isThreeComponentMatrix()) {
+ QUninitialized<QColorVector, WorkBlockSize> buffer;
-/*!
- \internal
- Applies the color transformation on \a count QRgb pixels starting from
- \a src and stores the result in \a dst.
+ qsizetype i = 0;
+ while (i < count) {
+ const qsizetype len = qMin(count - i, WorkBlockSize);
- Thread-safe if prepare() has been called first.
+ applyConvertIn(src, buffer, len, flags);
- Assumes unpremultiplied data by default. Set \a flags to change defaults.
+ // Match Profile Connection Spaces (PCS):
+ if (colorSpaceOut->isPcsLab && !colorSpaceIn->isPcsLab) {
+ for (qsizetype j = 0; j < len; ++j)
+ buffer[j] = buffer[j].xyzToLab();
+ } else if (colorSpaceIn->isPcsLab && !colorSpaceOut->isPcsLab) {
+ for (qsizetype j = 0; j < len; ++j)
+ buffer[j] = buffer[j].labToXyz();
+ }
- \sa prepare()
-*/
-void QColorTransformPrivate::apply(QRgb *dst, const QRgb *src, qsizetype count, TransformFlags flags) const
-{
- apply<QRgb>(dst, src, count, flags);
-}
+ applyMatrix<DoClamp>(buffer, len, colorMatrix);
+ storeOpaque(dst + i, buffer, len, this);
-/*!
- \internal
- Applies the color transformation on \a count QRgba64 pixels starting from
- \a src and stores the result in \a dst.
+ i += len;
+ }
+ return;
+ }
+ if constexpr (!std::is_same_v<S, QCmyk32>) {
+ if (!colorMatrix.isValid())
+ return;
- Thread-safe if prepare() has been called first.
+ updateLutsIn();
- Assumes unpremultiplied data by default. Set \a flags to change defaults.
+ QUninitialized<QColorVector, WorkBlockSize> buffer;
- \sa prepare()
-*/
-void QColorTransformPrivate::apply(QRgba64 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags) const
-{
- apply<QRgba64>(dst, src, count, flags);
+ qsizetype i = 0;
+ while (i < count) {
+ const qsizetype len = qMin(count - i, WorkBlockSize);
+ if (flags & InputPremultiplied)
+ loadPremultiplied(buffer, src + i, len, this);
+ else
+ loadUnpremultiplied(buffer, src + i, len, this);
+
+ applyMatrix<DoClamp>(buffer, len, colorMatrix);
+
+ storeOpaque(dst + i, buffer, len, this);
+
+ i += len;
+ }
+ } else {
+ Q_UNREACHABLE();
+ }
}
/*!
\internal
- Applies the color transformation on \a count QRgbaFloat32 pixels starting from
- \a src and stores the result in \a dst.
+*/
+template<typename D, typename S>
+void QColorTransformPrivate::applyGray(D *dst, const S *src, qsizetype count, TransformFlags) const
+{
+ Q_ASSERT(colorSpaceIn->isThreeComponentMatrix());
+ updateLutsIn();
+ if constexpr (std::is_same_v<D, QRgb> || std::is_same_v<D, QRgba64> || std::is_same_v<D, QRgbaFloat32> || std::is_same_v<D, QCmyk32>) {
+ if (!colorSpaceOut->isThreeComponentMatrix()) {
+ QUninitialized<QColorVector, WorkBlockSize> buffer;
- Thread-safe if prepare() has been called first.
+ qsizetype i = 0;
+ while (i < count) {
+ const qsizetype len = qMin(count - i, WorkBlockSize);
+ loadGray(buffer, src + i, len, this);
- Assumes unpremultiplied data by default. Set \a flags to change defaults.
+ applyMatrix<DoClamp>(buffer, len, colorMatrix);
- \sa prepare()
-*/
-void QColorTransformPrivate::apply(QRgbaFloat32 *dst, const QRgbaFloat32 *src, qsizetype count,
- TransformFlags flags) const
-{
- apply<QRgbaFloat32>(dst, src, count, flags);
+ // Match Profile Connection Spaces (PCS):
+ if (colorSpaceOut->isPcsLab && !colorSpaceIn->isPcsLab) {
+ for (qsizetype j = 0; j < len; ++j)
+ buffer[j] = buffer[j].xyzToLab();
+ } else if (colorSpaceIn->isPcsLab && !colorSpaceOut->isPcsLab) {
+ for (qsizetype j = 0; j < len; ++j)
+ buffer[j] = buffer[j].labToXyz();
+ }
+
+ // Do element based conversion
+ for (auto &&element : colorSpaceOut->mBA)
+ std::visit([&buffer, len](auto &&elm) { visitElement(elm, buffer, len); }, element);
+
+ clampIfNeeded<DoClamp>(buffer, len);
+
+ storeUnpremultipliedLUT(dst, src, buffer, len); // input is always opaque
+
+ i += len;
+ }
+ return;
+ }
+ }
+ Q_ASSERT(colorSpaceOut->isThreeComponentMatrix());
+ if constexpr (!std::is_same_v<D, QCmyk32>) {
+ if (!colorMatrix.isValid())
+ return;
+
+ updateLutsOut();
+
+ QUninitialized<QColorVector, WorkBlockSize> buffer;
+
+ qsizetype i = 0;
+ while (i < count) {
+ const qsizetype len = qMin(count - i, WorkBlockSize);
+ loadGray(buffer, src + i, len, this);
+
+ applyMatrix<DoClamp>(buffer, len, colorMatrix);
+
+ storeOpaque(dst + i, buffer, len, this);
+ i += len;
+ }
+ } else {
+ Q_UNREACHABLE();
+ }
}
/*!
\internal
- Is to be called on a color-transform to XYZ, returns only luminance values.
+ \enum QColorTransformPrivate::TransformFlag
+
+ Defines how the transform should handle alpha values.
+ \value Unpremultiplied The input and output should both be unpremultiplied.
+ \value InputOpaque The input is guaranteed to be opaque.
+ \value InputPremultiplied The input is premultiplied.
+ \value OutputPremultiplied The output should be premultiplied.
+ \value Premultiplied Both input and output should both be premultiplied.
*/
-void QColorTransformPrivate::apply(quint8 *dst, const QRgb *src, qsizetype count, TransformFlags flags) const
-{
- applyReturnGray<quint8, QRgb>(dst, src, count, flags);
-}
/*!
\internal
- Is to be called on a color-transform to XYZ, returns only luminance values.
+ Prepares a color transformation for fast application. You do not need to
+ call this explicitly as it will be called implicitly on the first transforms, but
+ if you want predictable performance on the first transforms, you can perform it
+ in advance.
+ \sa QColorTransform::map(), apply()
*/
-void QColorTransformPrivate::apply(quint16 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags) const
+void QColorTransformPrivate::prepare()
{
- applyReturnGray<quint16, QRgba64>(dst, src, count, flags);
+ updateLutsIn();
+ updateLutsOut();
}
+// Only allow versions increasing precision
+template void QColorTransformPrivate::applyReturnGray<quint8, QRgb>(quint8 *dst, const QRgb *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::applyReturnGray<quint8, QCmyk32>(quint8 *dst, const QCmyk32 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::applyReturnGray<quint16, QCmyk32>(quint16 *dst, const QCmyk32 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::applyReturnGray<quint16, QRgba64>(quint16 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::applyGray<quint8, quint8>(quint8 *dst, const quint8 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::applyGray<quint16, quint8>(quint16 *dst, const quint8 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::applyGray<quint16, quint16>(quint16 *dst, const quint16 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::applyGray<QRgb, quint8>(QRgb *dst, const quint8 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::applyGray<QCmyk32, quint8>(QCmyk32 *dst, const quint8 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::applyGray<QCmyk32, quint16>(QCmyk32 *dst, const quint16 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::applyGray<QRgba64, quint16>(QRgba64 *dst, const quint16 *src, qsizetype count, TransformFlags flags) const;
+
+template void QColorTransformPrivate::apply<QRgb, QRgb>(QRgb *dst, const QRgb *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QRgb, QCmyk32>(QRgb *dst, const QCmyk32 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QCmyk32, QRgb>(QCmyk32 *dst, const QRgb *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QCmyk32, QCmyk32>(QCmyk32 *dst, const QCmyk32 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QCmyk32, QRgba64>(QCmyk32 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QCmyk32, QRgbaFloat32>(QCmyk32 *dst, const QRgbaFloat32 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QRgba64, QRgb>(QRgba64 *dst, const QRgb *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QRgba64, QCmyk32>(QRgba64 *dst, const QCmyk32 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QRgba64, QRgba64>(QRgba64 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QRgbaFloat32, QRgb>(QRgbaFloat32 *dst, const QRgb *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QRgbaFloat32, QCmyk32>(QRgbaFloat32 *dst, const QCmyk32 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QRgbaFloat32, QRgba64>(QRgbaFloat32 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags) const;
+template void QColorTransformPrivate::apply<QRgbaFloat32, QRgbaFloat32>(QRgbaFloat32 *dst, const QRgbaFloat32 *src, qsizetype count, TransformFlags flags) const;
+
+bool QColorTransformPrivate::isThreeComponentMatrix() const
+{
+ if (colorSpaceIn && !colorSpaceIn->isThreeComponentMatrix())
+ return false;
+ if (colorSpaceOut && !colorSpaceOut->isThreeComponentMatrix())
+ return false;
+ return true;
+}
/*!
\internal
*/
bool QColorTransformPrivate::isIdentity() const
{
+ if (colorSpaceIn == colorSpaceOut)
+ return true;
if (!colorMatrix.isIdentity())
return false;
if (colorSpaceIn && colorSpaceOut) {
+ if (colorSpaceIn->equals(colorSpaceOut.constData()))
+ return true;
+ if (!isThreeComponentMatrix())
+ return false;
if (colorSpaceIn->transferFunction != colorSpaceOut->transferFunction)
return false;
if (colorSpaceIn->transferFunction == QColorSpace::TransferFunction::Custom) {
@@ -1395,6 +2001,8 @@ bool QColorTransformPrivate::isIdentity() const
&& colorSpaceIn->trc[2] == colorSpaceOut->trc[2];
}
} else {
+ if (!isThreeComponentMatrix())
+ return false;
if (colorSpaceIn && colorSpaceIn->transferFunction != QColorSpace::TransferFunction::Linear)
return false;
if (colorSpaceOut && colorSpaceOut->transferFunction != QColorSpace::TransferFunction::Linear)
diff --git a/src/gui/painting/qcolortransform_p.h b/src/gui/painting/qcolortransform_p.h
index e5be45bb20..59ea6a2405 100644
--- a/src/gui/painting/qcolortransform_p.h
+++ b/src/gui/painting/qcolortransform_p.h
@@ -22,6 +22,7 @@
#include <QtGui/qrgbafloat.h>
QT_BEGIN_NAMESPACE
+class QCmyk32;
class QColorTransformPrivate : public QSharedData
{
@@ -36,6 +37,7 @@ public:
void updateLutsIn() const;
void updateLutsOut() const;
bool isIdentity() const;
+ bool isThreeComponentMatrix() const;
Q_GUI_EXPORT void prepare();
enum TransformFlag {
@@ -47,19 +49,25 @@ public:
};
Q_DECLARE_FLAGS(TransformFlags, TransformFlag)
- void apply(QRgb *dst, const QRgb *src, qsizetype count, TransformFlags flags = Unpremultiplied) const;
- void apply(QRgba64 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags = Unpremultiplied) const;
- void apply(QRgbaFloat32 *dst, const QRgbaFloat32 *src, qsizetype count,
- TransformFlags flags = Unpremultiplied) const;
- void apply(quint8 *dst, const QRgb *src, qsizetype count, TransformFlags flags = Unpremultiplied) const;
- void apply(quint16 *dst, const QRgba64 *src, qsizetype count, TransformFlags flags = Unpremultiplied) const;
-
- template<typename T>
- void apply(T *dst, const T *src, qsizetype count, TransformFlags flags) const;
+ QColorVector map(QColorVector color) const;
+ QColorVector mapExtended(QColorVector color) const;
template<typename D, typename S>
+ void apply(D *dst, const S *src, qsizetype count, TransformFlags flags) const;
+ template<typename D, typename S>
+ void applyGray(D *dst, const S *src, qsizetype count, TransformFlags flags) const;
+ template<typename D, typename S>
void applyReturnGray(D *dst, const S *src, qsizetype count, TransformFlags flags) const;
+private:
+ template<typename S>
+ void applyConvertIn(const S *src, QColorVector *buffer, qsizetype len, TransformFlags flags) const;
+ template<typename D, typename S>
+ void applyConvertOut(D *dst, const S *src, QColorVector *buffer, qsizetype len, TransformFlags flags) const;
+ template<typename D, typename S>
+ void applyElementListTransform(D *dst, const S *src, qsizetype count, TransformFlags flags) const;
+ template<typename D, typename S>
+ void applyThreeComponentMatrix(D *dst, const S *src, qsizetype count, TransformFlags flags) const;
};
QT_END_NAMESPACE
diff --git a/src/gui/painting/qcolortrc_p.h b/src/gui/painting/qcolortrc_p.h
index 9e879bb3e2..d1ad1987df 100644
--- a/src/gui/painting/qcolortrc_p.h
+++ b/src/gui/painting/qcolortrc_p.h
@@ -21,17 +21,15 @@
QT_BEGIN_NAMESPACE
-
-// Defines an ICC TRC (Tone Reproduction Curve)
+// Defines a TRC (Tone Reproduction Curve)
class Q_GUI_EXPORT QColorTrc
{
public:
- QColorTrc() noexcept : m_type(Type::Uninitialized)
- { }
- QColorTrc(const QColorTransferFunction &fun) : m_type(Type::Function), m_fun(fun)
- { }
- QColorTrc(const QColorTransferTable &table) : m_type(Type::Table), m_table(table)
- { }
+ QColorTrc() noexcept : m_type(Type::Uninitialized) { }
+ QColorTrc(const QColorTransferFunction &fun) : m_type(Type::Function), m_fun(fun) { }
+ QColorTrc(const QColorTransferTable &table) : m_type(Type::Table), m_table(table) { }
+ QColorTrc(QColorTransferFunction &&fun) noexcept : m_type(Type::Function), m_fun(std::move(fun)) { }
+ QColorTrc(QColorTransferTable &&table) noexcept : m_type(Type::Table), m_table(std::move(table)) { }
enum class Type {
Uninitialized,
@@ -39,9 +37,10 @@ public:
Table
};
- bool isLinear() const
+ bool isIdentity() const
{
- return m_type == Type::Uninitialized || (m_type == Type::Function && m_fun.isLinear());
+ return (m_type == Type::Function && m_fun.isIdentity())
+ || (m_type == Type::Table && m_table.isIdentity());
}
bool isValid() const
{
diff --git a/src/gui/painting/qcolortrclut.cpp b/src/gui/painting/qcolortrclut.cpp
index 6f1cacea75..8a7673bc00 100644
--- a/src/gui/painting/qcolortrclut.cpp
+++ b/src/gui/painting/qcolortrclut.cpp
@@ -13,43 +13,80 @@ std::shared_ptr<QColorTrcLut> QColorTrcLut::create()
return std::make_shared<Access>();
}
-std::shared_ptr<QColorTrcLut> QColorTrcLut::fromGamma(qreal gamma)
+std::shared_ptr<QColorTrcLut> QColorTrcLut::fromGamma(qreal gamma, Direction dir)
{
auto cp = create();
+ cp->setFromGamma(gamma, dir);
+ return cp;
+}
- 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)));
- }
-
+std::shared_ptr<QColorTrcLut> QColorTrcLut::fromTransferFunction(const QColorTransferFunction &fun, Direction dir)
+{
+ auto cp = create();
+ cp->setFromTransferFunction(fun, dir);
return cp;
}
-std::shared_ptr<QColorTrcLut> QColorTrcLut::fromTransferFunction(const QColorTransferFunction &fun)
+std::shared_ptr<QColorTrcLut> QColorTrcLut::fromTransferTable(const QColorTransferTable &table, Direction dir)
{
auto cp = create();
- QColorTransferFunction inv = fun.inverted();
+ cp->setFromTransferTable(table, dir);
+ return cp;
+}
- for (int i = 0; i <= (255 * 16); ++i) {
- cp->m_toLinear[i] = ushort(qRound(fun.apply(i / qreal(255 * 16)) * (255 * 256)));
- cp->m_fromLinear[i] = ushort(qRound(inv.apply(i / qreal(255 * 16)) * (255 * 256)));
+void QColorTrcLut::setFromGamma(qreal gamma, Direction dir)
+{
+ if (dir & ToLinear) {
+ if (!m_toLinear)
+ m_toLinear.reset(new ushort[Resolution + 1]);
+ for (int i = 0; i <= Resolution; ++i)
+ m_toLinear[i] = ushort(qRound(qPow(i / qreal(Resolution), gamma) * (255 * 256)));
}
- return cp;
+ if (dir & FromLinear) {
+ if (!m_fromLinear)
+ m_fromLinear.reset(new ushort[Resolution + 1]);
+ for (int i = 0; i <= Resolution; ++i)
+ m_fromLinear[i] = ushort(qRound(qPow(i / qreal(Resolution), qreal(1) / gamma) * (255 * 256)));
+ }
}
-std::shared_ptr<QColorTrcLut> QColorTrcLut::fromTransferTable(const QColorTransferTable &table)
+void QColorTrcLut::setFromTransferFunction(const QColorTransferFunction &fun, Direction dir)
{
- auto cp = create();
+ if (dir & ToLinear) {
+ if (!m_toLinear)
+ m_toLinear.reset(new ushort[Resolution + 1]);
+ for (int i = 0; i <= Resolution; ++i)
+ m_toLinear[i] = ushort(qRound(fun.apply(i / qreal(Resolution)) * (255 * 256)));
+ }
- float minInverse = 0.0f;
- for (int i = 0; i <= (255 * 16); ++i) {
- cp->m_toLinear[i] = ushort(qBound(0, qRound(table.apply(i / qreal(255 * 16)) * (255 * 256)), 65280));
- minInverse = table.applyInverse(i / qreal(255 * 16), minInverse);
- cp->m_fromLinear[i] = ushort(qBound(0, qRound(minInverse * (255 * 256)), 65280));
+ if (dir & FromLinear) {
+ if (!m_fromLinear)
+ m_fromLinear.reset(new ushort[Resolution + 1]);
+ QColorTransferFunction inv = fun.inverted();
+ for (int i = 0; i <= Resolution; ++i)
+ m_fromLinear[i] = ushort(qRound(inv.apply(i / qreal(Resolution)) * (255 * 256)));
}
+}
- return cp;
+void QColorTrcLut::setFromTransferTable(const QColorTransferTable &table, Direction dir)
+{
+ if (dir & ToLinear) {
+ if (!m_toLinear)
+ m_toLinear.reset(new ushort[Resolution + 1]);
+ for (int i = 0; i <= Resolution; ++i)
+ m_toLinear[i] = ushort(qBound(0, qRound(table.apply(i / qreal(Resolution)) * (255 * 256)), 65280));
+ }
+
+ if (dir & FromLinear) {
+ if (!m_fromLinear)
+ m_fromLinear.reset(new ushort[Resolution + 1]);
+ float minInverse = 0.0f;
+ for (int i = 0; i <= Resolution; ++i) {
+ minInverse = table.applyInverse(i / qreal(Resolution), minInverse);
+ m_fromLinear[i] = ushort(qBound(0, qRound(minInverse * (255 * 256)), 65280));
+ }
+ }
}
QT_END_NAMESPACE
diff --git a/src/gui/painting/qcolortrclut_p.h b/src/gui/painting/qcolortrclut_p.h
index c6b73d9f69..3ebab42809 100644
--- a/src/gui/painting/qcolortrclut_p.h
+++ b/src/gui/painting/qcolortrclut_p.h
@@ -36,9 +36,22 @@ class QColorTransferTable;
class Q_GUI_EXPORT QColorTrcLut
{
public:
- static std::shared_ptr<QColorTrcLut> fromGamma(qreal gamma);
- static std::shared_ptr<QColorTrcLut> fromTransferFunction(const QColorTransferFunction &transfn);
- static std::shared_ptr<QColorTrcLut> fromTransferTable(const QColorTransferTable &transTable);
+ static constexpr uint32_t ShiftUp = 4; // Amount to shift up from 1->255
+ static constexpr uint32_t ShiftDown = (8 - ShiftUp); // Amount to shift down from 1->65280
+ static constexpr qsizetype Resolution = (1 << ShiftUp) * 255; // Number of entries in table
+
+ enum Direction {
+ ToLinear = 1,
+ FromLinear = 2,
+ BiLinear = ToLinear | FromLinear
+ };
+
+ static std::shared_ptr<QColorTrcLut> fromGamma(qreal gamma, Direction dir = BiLinear);
+ static std::shared_ptr<QColorTrcLut> fromTransferFunction(const QColorTransferFunction &transFn, Direction dir = BiLinear);
+ static std::shared_ptr<QColorTrcLut> fromTransferTable(const QColorTransferTable &transTable, Direction dir = BiLinear);
+ void setFromGamma(qreal gamma, Direction dir = BiLinear);
+ void setFromTransferFunction(const QColorTransferFunction &transFn, Direction dir = BiLinear);
+ void setFromTransferTable(const QColorTransferTable &transTable, Direction dir = BiLinear);
// The following methods all convert opaque or unpremultiplied colors:
@@ -47,7 +60,7 @@ public:
#if defined(__SSE2__)
__m128i v = _mm_cvtsi32_si128(rgb32);
v = _mm_unpacklo_epi8(v, _mm_setzero_si128());
- const __m128i vidx = _mm_slli_epi16(v, 4);
+ const __m128i vidx = _mm_slli_epi16(v, ShiftUp);
const int ridx = _mm_extract_epi16(vidx, 2);
const int gidx = _mm_extract_epi16(vidx, 1);
const int bidx = _mm_extract_epi16(vidx, 0);
@@ -62,7 +75,7 @@ public:
#elif (defined(__ARM_NEON__) || defined(__ARM_NEON)) && Q_BYTE_ORDER == Q_LITTLE_ENDIAN
uint8x8_t v8 = vreinterpret_u8_u32(vmov_n_u32(rgb32));
uint16x4_t v16 = vget_low_u16(vmovl_u8(v8));
- const uint16x4_t vidx = vshl_n_u16(v16, 4);
+ const uint16x4_t vidx = vshl_n_u16(v16, ShiftUp);
const int ridx = vget_lane_u16(vidx, 2);
const int gidx = vget_lane_u16(vidx, 1);
const int bidx = vget_lane_u16(vidx, 0);
@@ -73,9 +86,9 @@ public:
v16 = vadd_u16(v16, vshr_n_u16(v16, 8));
return QRgba64::fromRgba64(vget_lane_u64(vreinterpret_u64_u16(v16), 0));
#else
- uint r = m_toLinear[qRed(rgb32) << 4];
- uint g = m_toLinear[qGreen(rgb32) << 4];
- uint b = m_toLinear[qBlue(rgb32) << 4];
+ uint r = m_toLinear[qRed(rgb32) << ShiftUp];
+ uint g = m_toLinear[qGreen(rgb32) << ShiftUp];
+ uint b = m_toLinear[qBlue(rgb32) << ShiftUp];
r = r + (r >> 8);
g = g + (g >> 8);
b = b + (b >> 8);
@@ -86,30 +99,30 @@ public:
QRgb toLinear(QRgb rgb32) const
{
- return convertWithTable(rgb32, m_toLinear);
+ return convertWithTable(rgb32, m_toLinear.get());
}
QRgba64 toLinear(QRgba64 rgb64) const
{
- return convertWithTable(rgb64, m_toLinear);
+ return convertWithTable(rgb64, m_toLinear.get());
}
float u8ToLinearF32(int c) const
{
- ushort v = m_toLinear[c << 4];
+ ushort v = m_toLinear[c << ShiftUp];
return v * (1.0f / (255*256));
}
float u16ToLinearF32(int c) const
{
c -= (c >> 8);
- ushort v = m_toLinear[c >> 4];
+ ushort v = m_toLinear[c >> ShiftDown];
return v * (1.0f / (255*256));
}
float toLinear(float f) const
{
- ushort v = m_toLinear[(int)(f * (255 * 16) + 0.5f)];
+ ushort v = m_toLinear[(int)(f * Resolution + 0.5f)];
return v * (1.0f / (255*256));
}
@@ -118,7 +131,7 @@ public:
#if defined(__SSE2__)
__m128i v = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&rgb64));
v = _mm_sub_epi16(v, _mm_srli_epi16(v, 8));
- const __m128i vidx = _mm_srli_epi16(v, 4);
+ const __m128i vidx = _mm_srli_epi16(v, ShiftDown);
const int ridx = _mm_extract_epi16(vidx, 0);
const int gidx = _mm_extract_epi16(vidx, 1);
const int bidx = _mm_extract_epi16(vidx, 2);
@@ -132,7 +145,7 @@ public:
#elif (defined(__ARM_NEON__) || defined(__ARM_NEON)) && Q_BYTE_ORDER == Q_LITTLE_ENDIAN
uint16x4_t v = vreinterpret_u16_u64(vmov_n_u64(rgb64));
v = vsub_u16(v, vshr_n_u16(v, 8));
- const uint16x4_t vidx = vshr_n_u16(v, 4);
+ const uint16x4_t vidx = vshr_n_u16(v, ShiftDown);
const int ridx = vget_lane_u16(vidx, 0);
const int gidx = vget_lane_u16(vidx, 1);
const int bidx = vget_lane_u16(vidx, 2);
@@ -151,56 +164,56 @@ public:
g = g - (g >> 8);
b = b - (b >> 8);
a = (a + 0x80) >> 8;
- r = (m_fromLinear[r >> 4] + 0x80) >> 8;
- g = (m_fromLinear[g >> 4] + 0x80) >> 8;
- b = (m_fromLinear[b >> 4] + 0x80) >> 8;
+ r = (m_fromLinear[r >> ShiftDown] + 0x80) >> 8;
+ g = (m_fromLinear[g >> ShiftDown] + 0x80) >> 8;
+ b = (m_fromLinear[b >> ShiftDown] + 0x80) >> 8;
return (a << 24) | (r << 16) | (g << 8) | b;
#endif
}
QRgb fromLinear(QRgb rgb32) const
{
- return convertWithTable(rgb32, m_fromLinear);
+ return convertWithTable(rgb32, m_fromLinear.get());
}
QRgba64 fromLinear(QRgba64 rgb64) const
{
- return convertWithTable(rgb64, m_fromLinear);
+ return convertWithTable(rgb64, m_fromLinear.get());
}
int u8FromLinearF32(float f) const
{
- ushort v = m_fromLinear[(int)(f * (255 * 16) + 0.5f)];
+ ushort v = m_fromLinear[(int)(f * Resolution + 0.5f)];
return (v + 0x80) >> 8;
}
int u16FromLinearF32(float f) const
{
- ushort v = m_fromLinear[(int)(f * (255 * 16) + 0.5f)];
+ ushort v = m_fromLinear[(int)(f * Resolution + 0.5f)];
return v + (v >> 8);
}
float fromLinear(float f) const
{
- ushort v = m_fromLinear[(int)(f * (255 * 16) + 0.5f)];
+ ushort v = m_fromLinear[(int)(f * Resolution + 0.5f)];
return v * (1.0f / (255*256));
}
// 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]
+ // We translate from 0->Resolution (4080 = 255*16) for the same speed up,
+ // and to keep the tables small enough to fit in most inner caches.
+ std::unique_ptr<ushort[]> m_toLinear; // [0->Resolution] -> [0-65280]
+ std::unique_ptr<ushort[]> m_fromLinear; // [0->Resolution] -> [0-65280]
private:
- QColorTrcLut() { } // force uninitialized members
+ QColorTrcLut() = default;
static std::shared_ptr<QColorTrcLut> create();
Q_ALWAYS_INLINE static QRgb convertWithTable(QRgb rgb32, const ushort *table)
{
- const int r = (table[qRed(rgb32) << 4] + 0x80) >> 8;
- const int g = (table[qGreen(rgb32) << 4] + 0x80) >> 8;
- const int b = (table[qBlue(rgb32) << 4] + 0x80) >> 8;
+ const int r = (table[qRed(rgb32) << ShiftUp] + 0x80) >> 8;
+ const int g = (table[qGreen(rgb32) << ShiftUp] + 0x80) >> 8;
+ const int b = (table[qBlue(rgb32) << ShiftUp] + 0x80) >> 8;
return (rgb32 & 0xff000000) | (r << 16) | (g << 8) | b;
}
Q_ALWAYS_INLINE static QRgba64 convertWithTable(QRgba64 rgb64, const ushort *table)
@@ -208,7 +221,7 @@ private:
#if defined(__SSE2__)
__m128i v = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(&rgb64));
v = _mm_sub_epi16(v, _mm_srli_epi16(v, 8));
- const __m128i vidx = _mm_srli_epi16(v, 4);
+ const __m128i vidx = _mm_srli_epi16(v, ShiftDown);
const int ridx = _mm_extract_epi16(vidx, 2);
const int gidx = _mm_extract_epi16(vidx, 1);
const int bidx = _mm_extract_epi16(vidx, 0);
@@ -222,7 +235,7 @@ private:
#elif (defined(__ARM_NEON__) || defined(__ARM_NEON)) && Q_BYTE_ORDER == Q_LITTLE_ENDIAN
uint16x4_t v = vreinterpret_u16_u64(vmov_n_u64(rgb64));
v = vsub_u16(v, vshr_n_u16(v, 8));
- const uint16x4_t vidx = vshr_n_u16(v, 4);
+ const uint16x4_t vidx = vshr_n_u16(v, ShiftDown);
const int ridx = vget_lane_u16(vidx, 2);
const int gidx = vget_lane_u16(vidx, 1);
const int bidx = vget_lane_u16(vidx, 0);
@@ -238,9 +251,9 @@ private:
r = r - (r >> 8);
g = g - (g >> 8);
b = b - (b >> 8);
- r = table[r >> 4];
- g = table[g >> 4];
- b = table[b >> 4];
+ r = table[r >> ShiftDown];
+ g = table[g >> ShiftDown];
+ b = table[b >> ShiftDown];
r = r + (r >> 8);
g = g + (g >> 8);
b = b + (b >> 8);
diff --git a/src/gui/painting/qcompositionfunctions.cpp b/src/gui/painting/qcompositionfunctions.cpp
index 46e1a812fc..00fd749fe6 100644
--- a/src/gui/painting/qcompositionfunctions.cpp
+++ b/src/gui/painting/qcompositionfunctions.cpp
@@ -397,25 +397,25 @@ struct RgbaFPOperationsSSE2 : public RgbaFPOperationsBase
typedef __m128 OptimalType;
typedef __m128 OptimalScalar;
- static OptimalType load(const Type *ptr)
+ static OptimalType Q_DECL_VECTORCALL load(const Type *ptr)
{
- return _mm_load_ps(reinterpret_cast<const float *>(ptr));
+ return _mm_loadu_ps(reinterpret_cast<const float *>(ptr));
}
- static OptimalType convert(const Type &value)
+ static OptimalType Q_DECL_VECTORCALL convert(const Type &value)
{
return load(&value);
}
- static void store(Type *ptr, OptimalType value)
+ static void Q_DECL_VECTORCALL store(Type *ptr, OptimalType value)
{
- _mm_store_ps(reinterpret_cast<float *>(ptr), value);
+ _mm_storeu_ps(reinterpret_cast<float *>(ptr), value);
}
- static OptimalType add(OptimalType a, OptimalType b)
+ static OptimalType Q_DECL_VECTORCALL add(OptimalType a, OptimalType b)
{
return _mm_add_ps(a, b);
}
// same as above:
// static OptimalScalar add(OptimalScalar a, OptimalScalar b)
- static OptimalType plus(OptimalType a, OptimalType b)
+ static OptimalType Q_DECL_VECTORCALL plus(OptimalType a, OptimalType b)
{
a = _mm_add_ps(a, b);
__m128 aa = _mm_min_ps(a, _mm_set1_ps(1.0f));
@@ -425,37 +425,37 @@ struct RgbaFPOperationsSSE2 : public RgbaFPOperationsBase
a = _mm_shuffle_ps(a, aa, _MM_SHUFFLE(0, 2, 1, 0));
return a;
}
- static OptimalScalar alpha(OptimalType c)
+ static OptimalScalar Q_DECL_VECTORCALL alpha(OptimalType c)
{
return _mm_shuffle_ps(c, c, _MM_SHUFFLE(3, 3, 3, 3));
}
- static OptimalScalar invAlpha(Scalar c)
+ static OptimalScalar Q_DECL_VECTORCALL invAlpha(Scalar c)
{
return _mm_set1_ps(1.0f - float(c));
}
- static OptimalScalar invAlpha(OptimalType c)
+ static OptimalScalar Q_DECL_VECTORCALL invAlpha(OptimalType c)
{
return _mm_sub_ps(_mm_set1_ps(1.0f), alpha(c));
}
- static OptimalScalar scalar(Scalar n)
+ static OptimalScalar Q_DECL_VECTORCALL scalar(Scalar n)
{
return _mm_set1_ps(float(n));
}
- static OptimalType multiplyAlpha(OptimalType val, OptimalScalar a)
+ static OptimalType Q_DECL_VECTORCALL multiplyAlpha(OptimalType val, OptimalScalar a)
{
return _mm_mul_ps(val, a);
}
- static OptimalType interpolate(OptimalType x, OptimalScalar a1, OptimalType y, OptimalScalar a2)
+ static OptimalType Q_DECL_VECTORCALL interpolate(OptimalType x, OptimalScalar a1, OptimalType y, OptimalScalar a2)
{
return add(multiplyAlpha(x, a1), multiplyAlpha(y, a2));
}
- static OptimalType multiplyAlpha8bit(OptimalType val, uint8_t a)
+ static OptimalType Q_DECL_VECTORCALL multiplyAlpha8bit(OptimalType val, uint8_t a)
{
return multiplyAlpha(val, _mm_set1_ps(a * (1.0f / 255.0f)));
}
// same as above:
// static OptimalScalar multiplyAlpha8bit(OptimalScalar a, uint8_t a)
- static OptimalType interpolate8bit(OptimalType x, uint8_t a1, OptimalType y, uint8_t a2)
+ static OptimalType Q_DECL_VECTORCALL interpolate8bit(OptimalType x, uint8_t a1, OptimalType y, uint8_t a2)
{
return add(multiplyAlpha8bit(x, a1), multiplyAlpha8bit(y, a2));
}
diff --git a/src/gui/painting/qcoregraphics.mm b/src/gui/painting/qcoregraphics.mm
index b03ebe55e6..27b46202f5 100644
--- a/src/gui/painting/qcoregraphics.mm
+++ b/src/gui/painting/qcoregraphics.mm
@@ -162,6 +162,9 @@ QT_BEGIN_NAMESPACE
QPixmap qt_mac_toQPixmap(const NSImage *image, const QSizeF &size)
{
+ // ### TODO: add parameter so that we can decide whether to maintain the aspect
+ // ratio of the image (positioning the image inside the pixmap of size \a size),
+ // or whether we want to fill the resulting pixmap by stretching the image.
const NSSize pixmapSize = NSMakeSize(size.width(), size.height());
QPixmap pixmap(pixmapSize.width, pixmapSize.height);
pixmap.fill(Qt::transparent);
@@ -182,6 +185,25 @@ QPixmap qt_mac_toQPixmap(const NSImage *image, const QSizeF &size)
#endif // Q_OS_MACOS
+#ifdef QT_PLATFORM_UIKIT
+
+QImage qt_mac_toQImage(const UIImage *image, QSizeF size)
+{
+ // ### TODO: same as above
+ QImage ret(size.width(), size.height(), QImage::Format_ARGB32_Premultiplied);
+ ret.fill(Qt::transparent);
+ QMacCGContext ctx(&ret);
+ if (!ctx)
+ return QImage();
+ UIGraphicsPushContext(ctx);
+ const CGRect rect = CGRectMake(0, 0, size.width(), size.height());
+ [image drawInRect:rect];
+ UIGraphicsPopContext();
+ return ret;
+}
+
+#endif // QT_PLATFORM_UIKIT
+
// ---------------------- Colors and Brushes ----------------------
QColor qt_mac_toQColor(CGColorRef color)
@@ -386,11 +408,14 @@ void QMacCGContext::initialize(QPaintDevice *paintDevice)
// Find the underlying QImage of the paint device
switch (int deviceType = paintDevice->devType()) {
case QInternal::Pixmap: {
- auto *platformPixmap = static_cast<QPixmap*>(paintDevice)->handle();
- if (platformPixmap && platformPixmap->classId() == QPlatformPixmap::RasterClass)
- initialize(platformPixmap->buffer());
- else
- qWarning() << "QMacCGContext: Unsupported pixmap class" << platformPixmap->classId();
+ if (auto *platformPixmap = static_cast<QPixmap*>(paintDevice)->handle()) {
+ if (platformPixmap->classId() == QPlatformPixmap::RasterClass)
+ initialize(platformPixmap->buffer());
+ else
+ qWarning() << "QMacCGContext: Unsupported pixmap class" << platformPixmap->classId();
+ } else {
+ qWarning() << "QMacCGContext: Empty platformPixmap";
+ }
break;
}
case QInternal::Image:
diff --git a/src/gui/painting/qcoregraphics_p.h b/src/gui/painting/qcoregraphics_p.h
index f0640ba500..a35f27a730 100644
--- a/src/gui/painting/qcoregraphics_p.h
+++ b/src/gui/painting/qcoregraphics_p.h
@@ -23,16 +23,23 @@
#include <CoreGraphics/CoreGraphics.h>
-#if defined(__OBJC__) && defined(Q_OS_MACOS)
-#include <AppKit/AppKit.h>
-#define HAVE_APPKIT
+#if defined(__OBJC__)
+# if defined(Q_OS_MACOS)
+# include <AppKit/AppKit.h>
+# elif defined(QT_PLATFORM_UIKIT)
+# include <UIKit/UIKit.h>
+# endif
#endif
QT_BEGIN_NAMESPACE
Q_GUI_EXPORT CGBitmapInfo qt_mac_bitmapInfoForImage(const QImage &image);
-#ifdef HAVE_APPKIT
+#ifdef QT_PLATFORM_UIKIT
+Q_GUI_EXPORT QImage qt_mac_toQImage(const UIImage *image, QSizeF size);
+#endif
+
+#ifdef Q_OS_MACOS
Q_GUI_EXPORT QPixmap qt_mac_toQPixmap(const NSImage *image, const QSizeF &size);
QT_END_NAMESPACE
@@ -57,7 +64,7 @@ Q_GUI_EXPORT void qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBou
Q_GUI_EXPORT void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransform *orig_xform);
-#ifdef HAVE_APPKIT
+#ifdef Q_OS_MACOS
Q_GUI_EXPORT QColor qt_mac_toQColor(const NSColor *color);
Q_GUI_EXPORT QBrush qt_mac_toQBrush(const NSColor *color, QPalette::ColorGroup colorGroup = QPalette::Normal);
#endif
@@ -81,6 +88,4 @@ private:
QT_END_NAMESPACE
-#undef HAVE_APPKIT
-
#endif // QCOREGRAPHICS_P_H
diff --git a/src/gui/painting/qcosmeticstroker.cpp b/src/gui/painting/qcosmeticstroker.cpp
index f555b56adb..a0eddf65d9 100644
--- a/src/gui/painting/qcosmeticstroker.cpp
+++ b/src/gui/painting/qcosmeticstroker.cpp
@@ -364,7 +364,7 @@ void QCosmeticStroker::drawPoints(const QPoint *points, int num)
const QPoint *end = points + num;
while (points < end) {
QPointF p = QPointF(*points) * state->matrix;
- drawPixel(this, qRound(p.x()), qRound(p.y()), 255);
+ drawPixel(this, std::floor(p.x()), std::floor(p.y()), 255);
++points;
}
@@ -377,7 +377,7 @@ void QCosmeticStroker::drawPoints(const QPointF *points, int num)
const QPointF *end = points + num;
while (points < end) {
QPointF p = (*points) * state->matrix;
- drawPixel(this, qRound(p.x()), qRound(p.y()), 255);
+ drawPixel(this, std::floor(p.x()), std::floor(p.y()), 255);
++points;
}
diff --git a/src/gui/painting/qcssutil.cpp b/src/gui/painting/qcssutil.cpp
index db9b7c24fe..caface7d1a 100644
--- a/src/gui/painting/qcssutil.cpp
+++ b/src/gui/painting/qcssutil.cpp
@@ -168,28 +168,28 @@ void qDrawEdge(QPainter *p, qreal x1, qreal y1, qreal x2, qreal y2, qreal dw1, q
if (width == 1 || (dw1 == 0 && dw2 == 0)) {
p->drawRect(QRectF(x1, y1, x2-x1, y2-y1));
} else { // draw trapezoid
- QPolygonF quad;
+ std::array<QPointF, 4> quad;
switch (edge) {
case TopEdge:
- quad << QPointF(x1, y1) << QPointF(x1 + dw1, y2)
- << QPointF(x2 - dw2, y2) << QPointF(x2, y1);
+ quad = {QPointF(x1, y1), QPointF(x1 + dw1, y2),
+ QPointF(x2 - dw2, y2), QPointF(x2, y1)};
break;
case BottomEdge:
- quad << QPointF(x1 + dw1, y1) << QPointF(x1, y2)
- << QPointF(x2, y2) << QPointF(x2 - dw2, y1);
+ quad = {QPointF(x1 + dw1, y1), QPointF(x1, y2),
+ QPointF(x2, y2), QPointF(x2 - dw2, y1)};
break;
case LeftEdge:
- quad << QPointF(x1, y1) << QPointF(x1, y2)
- << QPointF(x2, y2 - dw2) << QPointF(x2, y1 + dw1);
+ quad = {QPointF(x1, y1), QPointF(x1, y2),
+ QPointF(x2, y2 - dw2), QPointF(x2, y1 + dw1)};
break;
case RightEdge:
- quad << QPointF(x1, y1 + dw1) << QPointF(x1, y2 - dw2)
- << QPointF(x2, y2) << QPointF(x2, y1);
+ quad = {QPointF(x1, y1 + dw1), QPointF(x1, y2 - dw2),
+ QPointF(x2, y2), QPointF(x2, y1)};
break;
default:
break;
}
- p->drawConvexPolygon(quad);
+ p->drawConvexPolygon(quad.data(), static_cast<int>(quad.size()));
}
break;
}
@@ -268,6 +268,7 @@ void qDrawEdge(QPainter *p, qreal x1, qreal y1, qreal x2, qreal y2, qreal dw1, q
default:
break;
}
+ break;
}
default:
break;
diff --git a/src/gui/painting/qdatabuffer_p.h b/src/gui/painting/qdatabuffer_p.h
index 1e62c8d924..8f467afe4e 100644
--- a/src/gui/painting/qdatabuffer_p.h
+++ b/src/gui/painting/qdatabuffer_p.h
@@ -89,13 +89,16 @@ public:
}
void shrink(qsizetype size) {
+ Q_ASSERT(capacity >= size);
capacity = size;
if (size) {
buffer = (Type*) realloc(static_cast<void*>(buffer), capacity * sizeof(Type));
Q_CHECK_PTR(buffer);
+ siz = std::min(siz, size);
} else {
free(buffer);
buffer = nullptr;
+ siz = 0;
}
}
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index 3ab54b9167..b7a943be38 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -176,7 +176,7 @@ static void QT_FASTCALL convertRGBA32FPMToRGBA64PM(QRgba64 *buffer, int count)
}
}
-static Convert64Func convert64ToRGBA64PM[QImage::NImageFormats] = {
+static Convert64Func convert64ToRGBA64PM[] = {
nullptr,
nullptr,
nullptr,
@@ -213,7 +213,10 @@ static Convert64Func convert64ToRGBA64PM[QImage::NImageFormats] = {
convertRGBA32FPMToRGBA64PM,
convertRGBA32FToRGBA64PM,
convertRGBA32FPMToRGBA64PM,
+ nullptr,
};
+
+static_assert(std::size(convert64ToRGBA64PM) == QImage::NImageFormats);
#endif
#if QT_CONFIG(raster_fp)
@@ -247,7 +250,7 @@ static void QT_FASTCALL convertRGBA16FToRGBA32F(QRgbaFloat32 *buffer, const quin
qFloatFromFloat16((float *)buffer, (const qfloat16 *)src, count * 4);
}
-static Convert64ToFPFunc convert64ToRGBA32F[QImage::NImageFormats] = {
+static Convert64ToFPFunc convert64ToRGBA32F[] = {
nullptr,
nullptr,
nullptr,
@@ -284,8 +287,11 @@ static Convert64ToFPFunc convert64ToRGBA32F[QImage::NImageFormats] = {
nullptr,
nullptr,
nullptr,
+ nullptr,
};
+static_assert(std::size(convert64ToRGBA32F) == QImage::NImageFormats);
+
static void convertRGBA32FToRGBA32FPM(QRgbaFloat32 *buffer, int count)
{
for (int i = 0; i < count; ++i)
@@ -353,7 +359,7 @@ static uint *QT_FASTCALL destFetchUndefined(uint *buffer, QRasterBuffer *, int,
return buffer;
}
-static DestFetchProc destFetchProc[QImage::NImageFormats] =
+static DestFetchProc destFetchProc[] =
{
nullptr, // Format_Invalid
destFetchMono, // Format_Mono,
@@ -391,8 +397,11 @@ static DestFetchProc destFetchProc[QImage::NImageFormats] =
destFetch, // Format_RGBX32FPx4
destFetch, // Format_RGBA32FPx4
destFetch, // Format_RGBA32FPx4_Premultiplied
+ destFetch, // Format_CMYK8888
};
+static_assert(std::size(destFetchProc) == QImage::NImageFormats);
+
#if QT_CONFIG(raster_64bit)
static QRgba64 *QT_FASTCALL destFetch64(QRgba64 *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
{
@@ -410,7 +419,7 @@ static QRgba64 * QT_FASTCALL destFetch64Undefined(QRgba64 *buffer, QRasterBuffer
return buffer;
}
-static DestFetchProc64 destFetchProc64[QImage::NImageFormats] =
+static DestFetchProc64 destFetchProc64[] =
{
nullptr, // Format_Invalid
nullptr, // Format_Mono,
@@ -448,7 +457,10 @@ static DestFetchProc64 destFetchProc64[QImage::NImageFormats] =
destFetch64, // Format_RGBX32FPx4
destFetch64, // Format_RGBA32FPx4
destFetch64, // Format_RGBA32FPx4_Premultiplied
+ destFetch64, // Format_CMYK8888
};
+
+static_assert(std::size(destFetchProc64) == QImage::NImageFormats);
#endif
#if QT_CONFIG(raster_fp)
@@ -466,7 +478,7 @@ static QRgbaFloat32 *QT_FASTCALL destFetchFPUndefined(QRgbaFloat32 *buffer, QRas
{
return buffer;
}
-static DestFetchProcFP destFetchProcFP[QImage::NImageFormats] =
+static DestFetchProcFP destFetchProcFP[] =
{
nullptr, // Format_Invalid
nullptr, // Format_Mono,
@@ -504,7 +516,10 @@ static DestFetchProcFP destFetchProcFP[QImage::NImageFormats] =
destFetchRGBFP, // Format_RGBX32FPx4
destFetchFP, // Format_RGBA32FPx4
destFetchRGBFP, // Format_RGBA32FPx4_Premultiplied
+ destFetchFP, // Format_CMYK8888
};
+
+static_assert(std::size(destFetchProcFP) == QImage::NImageFormats);
#endif
/*
@@ -513,9 +528,8 @@ static DestFetchProcFP destFetchProcFP[QImage::NImageFormats] =
*/
static inline QRgb findNearestColor(QRgb color, QRasterBuffer *rbuf)
{
- QRgb color_0 = qPremultiply(rbuf->destColor0);
- QRgb color_1 = qPremultiply(rbuf->destColor1);
- color = qPremultiply(color);
+ const QRgb color_0 = rbuf->destColor0;
+ const QRgb color_1 = rbuf->destColor1;
int r = qRed(color);
int g = qGreen(color);
@@ -630,7 +644,7 @@ static void QT_FASTCALL destStoreGray8(QRasterBuffer *rasterBuffer, int x, int y
QColorTransform tf = QColorSpacePrivate::get(fromCS)->transformationToXYZ();
QColorTransformPrivate *tfd = QColorTransformPrivate::get(tf);
- tfd->apply(data, buffer, length, QColorTransformPrivate::InputPremultiplied);
+ tfd->applyReturnGray(data, buffer, length, QColorTransformPrivate::InputPremultiplied);
}
}
@@ -654,11 +668,11 @@ static void QT_FASTCALL destStoreGray16(QRasterBuffer *rasterBuffer, int x, int
QRgba64 tmp_line[BufferSize];
for (int k = 0; k < length; ++k)
tmp_line[k] = QRgba64::fromArgb32(buffer[k]);
- tfd->apply(data, tmp_line, length, QColorTransformPrivate::InputPremultiplied);
+ tfd->applyReturnGray(data, tmp_line, length, QColorTransformPrivate::InputPremultiplied);
}
}
-static DestStoreProc destStoreProc[QImage::NImageFormats] =
+static DestStoreProc destStoreProc[] =
{
nullptr, // Format_Invalid
destStoreMono, // Format_Mono,
@@ -696,8 +710,11 @@ static DestStoreProc destStoreProc[QImage::NImageFormats] =
destStore, // Format_RGBX32FPx4
destStore, // Format_RGBA32FPx4
destStore, // Format_RGBA32FPx4_Premultiplied
+ destStore, // Format_CMYK8888
};
+static_assert(std::size(destStoreProc) == QImage::NImageFormats);
+
#if QT_CONFIG(raster_64bit)
static void QT_FASTCALL destStore64(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length)
{
@@ -732,7 +749,7 @@ static void QT_FASTCALL destStore64Gray8(QRasterBuffer *rasterBuffer, int x, int
QColorTransformPrivate *tfd = QColorTransformPrivate::get(tf);
quint16 gray_line[BufferSize];
- tfd->apply(gray_line, buffer, length, QColorTransformPrivate::InputPremultiplied);
+ tfd->applyReturnGray(gray_line, buffer, length, QColorTransformPrivate::InputPremultiplied);
for (int k = 0; k < length; ++k)
data[k] = qt_div_257(gray_line[k]);
}
@@ -754,11 +771,11 @@ static void QT_FASTCALL destStore64Gray16(QRasterBuffer *rasterBuffer, int x, in
QColorSpace fromCS = rasterBuffer->colorSpace.isValid() ? rasterBuffer->colorSpace : QColorSpace::SRgb;
QColorTransform tf = QColorSpacePrivate::get(fromCS)->transformationToXYZ();
QColorTransformPrivate *tfd = QColorTransformPrivate::get(tf);
- tfd->apply(data, buffer, length, QColorTransformPrivate::InputPremultiplied);
+ tfd->applyReturnGray(data, buffer, length, QColorTransformPrivate::InputPremultiplied);
}
}
-static DestStoreProc64 destStoreProc64[QImage::NImageFormats] =
+static DestStoreProc64 destStoreProc64[] =
{
nullptr, // Format_Invalid
nullptr, // Format_Mono,
@@ -796,7 +813,10 @@ static DestStoreProc64 destStoreProc64[QImage::NImageFormats] =
destStore64, // Format_RGBX32FPx4
destStore64, // Format_RGBA32FPx4
destStore64, // Format_RGBA32FPx4_Premultiplied
+ destStore64, // Format_CMYK8888
};
+
+static_assert(std::size(destStoreProc64) == QImage::NImageFormats);
#endif
#if QT_CONFIG(raster_fp)
@@ -3071,7 +3091,7 @@ static const QRgbaFloat32 *QT_FASTCALL fetchTransformedBilinearFP(QRgbaFloat32 *
#endif // QT_CONFIG(raster_fp)
// FetchUntransformed can have more specialized methods added depending on SIMD features.
-static SourceFetchProc sourceFetchUntransformed[QImage::NImageFormats] = {
+static SourceFetchProc sourceFetchUntransformed[] = {
nullptr, // Invalid
fetchUntransformed, // Mono
fetchUntransformed, // MonoLsb
@@ -3108,9 +3128,12 @@ static SourceFetchProc sourceFetchUntransformed[QImage::NImageFormats] = {
fetchUntransformed, // RGBX32Px4
fetchUntransformed, // RGBA32FPx4
fetchUntransformed, // RGBA32FPx4_Premultiplied
+ fetchUntransformed, // CMYK8888
};
-static const SourceFetchProc sourceFetchGeneric[NBlendTypes] = {
+static_assert(std::size(sourceFetchUntransformed) == QImage::NImageFormats);
+
+static const SourceFetchProc sourceFetchGeneric[] = {
fetchUntransformed, // Untransformed
fetchUntransformed, // Tiled
fetchTransformed<BlendTransformed, QPixelLayout::BPPNone>, // Transformed
@@ -3119,7 +3142,9 @@ static const SourceFetchProc sourceFetchGeneric[NBlendTypes] = {
fetchTransformedBilinear<BlendTransformedBilinearTiled, QPixelLayout::BPPNone> // TransformedBilinearTiled
};
-static SourceFetchProc sourceFetchARGB32PM[NBlendTypes] = {
+static_assert(std::size(sourceFetchGeneric) == NBlendTypes);
+
+static SourceFetchProc sourceFetchARGB32PM[] = {
fetchUntransformedARGB32PM, // Untransformed
fetchUntransformedARGB32PM, // Tiled
fetchTransformed<BlendTransformed, QPixelLayout::BPP32>, // Transformed
@@ -3128,7 +3153,9 @@ static SourceFetchProc sourceFetchARGB32PM[NBlendTypes] = {
fetchTransformedBilinearARGB32PM<BlendTransformedBilinearTiled> // BilinearTiled
};
-static SourceFetchProc sourceFetchAny16[NBlendTypes] = {
+static_assert(std::size(sourceFetchARGB32PM) == NBlendTypes);
+
+static SourceFetchProc sourceFetchAny16[] = {
fetchUntransformed, // Untransformed
fetchUntransformed, // Tiled
fetchTransformed<BlendTransformed, QPixelLayout::BPP16>, // Transformed
@@ -3137,7 +3164,9 @@ static SourceFetchProc sourceFetchAny16[NBlendTypes] = {
fetchTransformedBilinear<BlendTransformedBilinearTiled, QPixelLayout::BPP16> // TransformedBilinearTiled
};
-static SourceFetchProc sourceFetchAny32[NBlendTypes] = {
+static_assert(std::size(sourceFetchAny16) == NBlendTypes);
+
+static SourceFetchProc sourceFetchAny32[] = {
fetchUntransformed, // Untransformed
fetchUntransformed, // Tiled
fetchTransformed<BlendTransformed, QPixelLayout::BPP32>, // Transformed
@@ -3146,6 +3175,8 @@ static SourceFetchProc sourceFetchAny32[NBlendTypes] = {
fetchTransformedBilinear<BlendTransformedBilinearTiled, QPixelLayout::BPP32> // TransformedBilinearTiled
};
+static_assert(std::size(sourceFetchAny32) == NBlendTypes);
+
static inline SourceFetchProc getSourceFetch(TextureBlendType blendType, QImage::Format format)
{
if (format == QImage::Format_RGB32 || format == QImage::Format_ARGB32_Premultiplied)
@@ -3160,7 +3191,7 @@ static inline SourceFetchProc getSourceFetch(TextureBlendType blendType, QImage:
}
#if QT_CONFIG(raster_64bit)
-static const SourceFetchProc64 sourceFetchGeneric64[NBlendTypes] = {
+static const SourceFetchProc64 sourceFetchGeneric64[] = {
fetchUntransformed64, // Untransformed
fetchUntransformed64, // Tiled
fetchTransformed64<BlendTransformed>, // Transformed
@@ -3169,7 +3200,9 @@ static const SourceFetchProc64 sourceFetchGeneric64[NBlendTypes] = {
fetchTransformedBilinear64<BlendTransformedBilinearTiled> // BilinearTiled
};
-static const SourceFetchProc64 sourceFetchRGBA64PM[NBlendTypes] = {
+static_assert(std::size(sourceFetchGeneric64) == NBlendTypes);
+
+static const SourceFetchProc64 sourceFetchRGBA64PM[] = {
fetchUntransformedRGBA64PM, // Untransformed
fetchUntransformedRGBA64PM, // Tiled
fetchTransformed64<BlendTransformed>, // Transformed
@@ -3178,6 +3211,8 @@ static const SourceFetchProc64 sourceFetchRGBA64PM[NBlendTypes] = {
fetchTransformedBilinear64<BlendTransformedBilinearTiled> // BilinearTiled
};
+static_assert(std::size(sourceFetchRGBA64PM) == NBlendTypes);
+
static inline SourceFetchProc64 getSourceFetch64(TextureBlendType blendType, QImage::Format format)
{
if (format == QImage::Format_RGBX64 || format == QImage::Format_RGBA64_Premultiplied)
@@ -3187,7 +3222,7 @@ static inline SourceFetchProc64 getSourceFetch64(TextureBlendType blendType, QIm
#endif
#if QT_CONFIG(raster_fp)
-static const SourceFetchProcFP sourceFetchGenericFP[NBlendTypes] = {
+static const SourceFetchProcFP sourceFetchGenericFP[] = {
fetchUntransformedFP, // Untransformed
fetchUntransformedFP, // Tiled
fetchTransformedFP<BlendTransformed>, // Transformed
@@ -3196,6 +3231,8 @@ static const SourceFetchProcFP sourceFetchGenericFP[NBlendTypes] = {
fetchTransformedBilinearFP<BlendTransformedBilinearTiled> // BilinearTiled
};
+static_assert(std::size(sourceFetchGenericFP) == NBlendTypes);
+
static inline SourceFetchProcFP getSourceFetchFP(TextureBlendType blendType, QImage::Format /*format*/)
{
return sourceFetchGenericFP[blendType];
@@ -3256,6 +3293,7 @@ public:
static Type null() { return 0; }
static Type fetchSingle(const QGradientData& gradient, qreal v)
{
+ Q_ASSERT(std::isfinite(v));
return qt_gradient_pixel(&gradient, v);
}
static Type fetchSingle(const QGradientData& gradient, int v)
@@ -3276,6 +3314,7 @@ public:
static Type null() { return QRgba64::fromRgba64(0); }
static Type fetchSingle(const QGradientData& gradient, qreal v)
{
+ Q_ASSERT(std::isfinite(v));
return qt_gradient_pixel64(&gradient, v);
}
static Type fetchSingle(const QGradientData& gradient, int v)
@@ -3297,6 +3336,7 @@ public:
static Type null() { return QRgbaFloat32::fromRgba64(0,0,0,0); }
static Type fetchSingle(const QGradientData& gradient, qreal v)
{
+ Q_ASSERT(std::isfinite(v));
return qt_gradient_pixelFP(&gradient, v);
}
static Type fetchSingle(const QGradientData& gradient, int v)
@@ -3414,7 +3454,6 @@ static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const Q
v->sqrfr = data->gradient.radial.focal.radius * data->gradient.radial.focal.radius;
v->a = v->dr * v->dr - v->dx*v->dx - v->dy*v->dy;
- v->inv2a = 1 / (2 * v->a);
v->extended = !qFuzzyIsNull(data->gradient.radial.focal.radius) || v->a <= 0;
}
@@ -3447,7 +3486,13 @@ public:
}
} else {
while (buffer < end) {
- *buffer++ = GradientBase::fetchSingle(data->gradient, qSqrt(det) - b);
+ BlendType result = GradientBase::null();
+ if (det >= 0) {
+ qreal w = qSqrt(det) - b;
+ result = GradientBase::fetchSingle(data->gradient, w);
+ }
+
+ *buffer++ = result;
det += delta_det;
delta_det += delta_delta_det;
@@ -3605,7 +3650,6 @@ static inline Operator getOperator(const QSpanData *data, const QT_FT_Span *span
{
Operator op;
bool solidSource = false;
-
switch(data->type) {
case QSpanData::Solid:
solidSource = data->solidColor.alphaF() >= 1.0f;
@@ -3649,7 +3693,7 @@ static inline Operator getOperator(const QSpanData *data, const QT_FT_Span *span
solidSource = !data->texture.hasAlpha;
op.srcFetch = getSourceFetch(getBlendType(data), data->texture.format);
#if QT_CONFIG(raster_64bit)
- op.srcFetch64 = getSourceFetch64(getBlendType(data), data->texture.format);;
+ op.srcFetch64 = getSourceFetch64(getBlendType(data), data->texture.format);
#endif
#if QT_CONFIG(raster_fp)
op.srcFetchFP = getSourceFetchFP(getBlendType(data), data->texture.format);
@@ -3779,7 +3823,8 @@ static void spanfill_from_first(QRasterBuffer *rasterBuffer, QPixelLayout::BPP b
#define QT_THREAD_PARALLEL_FILLS(function) \
const int segments = (count + 32) / 64; \
QThreadPool *threadPool = QThreadPoolPrivate::qtGuiInstance(); \
- if (segments > 1 && threadPool && !threadPool->contains(QThread::currentThread())) { \
+ if (segments > 1 && qPixelLayouts[data->rasterBuffer->format].bpp >= QPixelLayout::BPP8 \
+ && threadPool && !threadPool->contains(QThread::currentThread())) { \
QSemaphore semaphore; \
int c = 0; \
for (int i = 0; i < segments; ++i) { \
@@ -4965,16 +5010,11 @@ void qBlendTexture(int count, const QT_FT_Span *spans, void *userData)
proc(count, spans, userData);
}
-static void blend_vertical_gradient_argb(int count, const QT_FT_Span *spans, void *userData)
+static inline bool calculate_fixed_gradient_factors(int count, const QT_FT_Span *spans,
+ const QSpanData *data,
+ const LinearGradientValues &linear,
+ int *pyinc, int *poff)
{
- QSpanData *data = reinterpret_cast<QSpanData *>(userData);
-
- LinearGradientValues linear;
- getLinearGradientValues(&linear, data);
-
- CompositionFunctionSolid funcSolid =
- functionForModeSolid[data->rasterBuffer->compositionMode];
-
/*
The logic for vertical gradient calculations is a mathematically
reduced copy of that in fetchLinearGradient() - which is basically:
@@ -4989,8 +5029,32 @@ static void blend_vertical_gradient_argb(int count, const QT_FT_Span *spans, voi
This has then been converted to fixed point to improve performance.
*/
const int gss = GRADIENT_STOPTABLE_SIZE - 1;
- int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
- int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE));
+ qreal ryinc = linear.dy * data->m22 * gss * FIXPT_SIZE;
+ qreal roff = (linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss * FIXPT_SIZE;
+ const int limit = std::numeric_limits<int>::max() - FIXPT_SIZE;
+ if (count && (std::fabs(ryinc) < limit) && (std::fabs(roff) < limit)
+ && (std::fabs(ryinc * spans->y + roff) < limit)
+ && (std::fabs(ryinc * (spans + count - 1)->y + roff) < limit)) {
+ *pyinc = int(ryinc);
+ *poff = int(roff);
+ return true;
+ }
+ return false;
+}
+
+static bool blend_vertical_gradient_argb(int count, const QT_FT_Span *spans, void *userData)
+{
+ QSpanData *data = reinterpret_cast<QSpanData *>(userData);
+
+ LinearGradientValues linear;
+ getLinearGradientValues(&linear, data);
+
+ CompositionFunctionSolid funcSolid =
+ functionForModeSolid[data->rasterBuffer->compositionMode];
+
+ int yinc(0), off(0);
+ if (!calculate_fixed_gradient_factors(count, spans, data, linear, &yinc, &off))
+ return false;
while (count--) {
int y = spans->y;
@@ -5003,21 +5067,20 @@ static void blend_vertical_gradient_argb(int count, const QT_FT_Span *spans, voi
funcSolid(dst, spans->len, color, spans->coverage);
++spans;
}
+ return true;
}
template<ProcessSpans blend_color>
-static void blend_vertical_gradient(int count, const QT_FT_Span *spans, void *userData)
+static bool blend_vertical_gradient(int count, const QT_FT_Span *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
LinearGradientValues linear;
getLinearGradientValues(&linear, data);
- // Based on the same logic as blend_vertical_gradient_argb.
-
- const int gss = GRADIENT_STOPTABLE_SIZE - 1;
- int yinc = int((linear.dy * data->m22 * gss) * FIXPT_SIZE);
- int off = int((((linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss) * FIXPT_SIZE));
+ int yinc(0), off(0);
+ if (!calculate_fixed_gradient_factors(count, spans, data, linear, &yinc, &off))
+ return false;
while (count--) {
int y = spans->y;
@@ -5030,6 +5093,7 @@ static void blend_vertical_gradient(int count, const QT_FT_Span *spans, void *us
blend_color(1, spans, userData);
++spans;
}
+ return true;
}
void qBlendGradient(int count, const QT_FT_Span *spans, void *userData)
@@ -5044,8 +5108,8 @@ void qBlendGradient(int count, const QT_FT_Span *spans, void *userData)
break;
case QImage::Format_RGB32:
case QImage::Format_ARGB32_Premultiplied:
- if (isVerticalGradient)
- return blend_vertical_gradient_argb(count, spans, userData);
+ if (isVerticalGradient && blend_vertical_gradient_argb(count, spans, userData))
+ return;
return blend_src_generic(count, spans, userData);
#if defined(__SSE2__) || defined(__ARM_NEON__) || (Q_PROCESSOR_WORDSIZE == 8)
case QImage::Format_ARGB32:
@@ -5067,8 +5131,8 @@ void qBlendGradient(int count, const QT_FT_Span *spans, void *userData)
case QImage::Format_RGBA32FPx4_Premultiplied:
#endif
#if QT_CONFIG(raster_64bit)
- if (isVerticalGradient)
- return blend_vertical_gradient<blend_color_generic_rgb64>(count, spans, userData);
+ if (isVerticalGradient && blend_vertical_gradient<blend_color_generic_rgb64>(count, spans, userData))
+ return;
return blend_src_generic_rgb64(count, spans, userData);
#endif // QT_CONFIG(raster_64bit)
#if QT_CONFIG(raster_fp)
@@ -5078,13 +5142,13 @@ void qBlendGradient(int count, const QT_FT_Span *spans, void *userData)
case QImage::Format_RGBX32FPx4:
case QImage::Format_RGBA32FPx4:
case QImage::Format_RGBA32FPx4_Premultiplied:
- if (isVerticalGradient)
- return blend_vertical_gradient<blend_color_generic_fp>(count, spans, userData);
+ if (isVerticalGradient && blend_vertical_gradient<blend_color_generic_fp>(count, spans, userData))
+ return;
return blend_src_generic_fp(count, spans, userData);
#endif
default:
- if (isVerticalGradient)
- return blend_vertical_gradient<blend_color_generic>(count, spans, userData);
+ if (isVerticalGradient && blend_vertical_gradient<blend_color_generic>(count, spans, userData))
+ return;
return blend_src_generic(count, spans, userData);
}
Q_UNREACHABLE();
@@ -5100,7 +5164,7 @@ inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer,
const int destStride = rasterBuffer->stride<DST>();
if (mapWidth > 8) {
- while (mapHeight--) {
+ while (--mapHeight >= 0) {
int x0 = 0;
int n = 0;
for (int x = 0; x < mapWidth; x += 8) {
@@ -5130,7 +5194,7 @@ inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer,
map += mapStride;
}
} else {
- while (mapHeight--) {
+ while (--mapHeight >= 0) {
int x0 = 0;
int n = 0;
for (uchar s = *map; s; s <<= 1) {
@@ -5438,7 +5502,7 @@ void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
if (!clip) {
quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
const int destStride = rasterBuffer->stride<quint16>();
- while (mapHeight--) {
+ while (--mapHeight >= 0) {
for (int i = 0; i < mapWidth; ++i)
alphamapblend_quint16(map[i], dest, i, c);
dest += destStride;
@@ -5492,7 +5556,7 @@ static void qt_alphamapblit_argb32(QRasterBuffer *rasterBuffer,
if (!clip) {
quint32 *dest = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
- while (mapHeight--) {
+ while (--mapHeight >= 0) {
for (int i = 0; i < mapWidth; ++i) {
const int coverage = map[i];
alphamapblend_argb32(dest + i, coverage, srcColor, c, colorProfile);
@@ -5810,7 +5874,7 @@ static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer,
if (!clip) {
quint32 *dst = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
const int destStride = rasterBuffer->stride<quint32>();
- while (mapHeight--) {
+ while (--mapHeight >= 0) {
for (int i = 0; i < mapWidth; ++i) {
const uint coverage = src[i];
alphargbblend_argb32(dst + i, coverage, srcColor, c, colorProfile);
@@ -5954,7 +6018,7 @@ static void qt_rectfill_fp32x4(QRasterBuffer *rasterBuffer,
// Map table for destination image format. Contains function pointers
// for blends of various types unto the destination
-DrawHelper qDrawHelper[QImage::NImageFormats] =
+DrawHelper qDrawHelper[] =
{
// Format_Invalid,
{ nullptr, nullptr, nullptr, nullptr, nullptr },
@@ -6231,6 +6295,8 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
},
};
+static_assert(std::size(qDrawHelper) == QImage::NImageFormats);
+
#if !defined(Q_PROCESSOR_X86)
void qt_memfill64(quint64 *dest, quint64 color, qsizetype count)
{
@@ -6323,7 +6389,7 @@ static void qInitDrawhelperFunctions()
qt_memfill32 = qt_memfill_template<quint32>;
qt_memfill64 = qt_memfill_template<quint64>;
#elif defined(__SSE2__)
-# ifndef __AVX2__
+# ifndef __haswell__
qt_memfill32 = qt_memfill32_sse2;
qt_memfill64 = qt_memfill64_sse2;
# endif
@@ -6430,7 +6496,7 @@ static void qInitDrawhelperFunctions()
extern void QT_FASTCALL storeRGBx64FromRGBA64PM_sse4(uchar *, const QRgba64 *, int, int, const QList<QRgb> *, QDitherInfo *);
extern void QT_FASTCALL destStore64ARGB32_sse4(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length);
extern void QT_FASTCALL destStore64RGBA8888_sse4(QRasterBuffer *rasterBuffer, int x, int y, const QRgba64 *buffer, int length);
-# ifndef __AVX2__
+# ifndef __haswell__
qPixelLayouts[QImage::Format_ARGB32].fetchToARGB32PM = fetchARGB32ToARGB32PM_sse4;
qPixelLayouts[QImage::Format_ARGB32].convertToARGB32PM = convertARGB32ToARGB32PM_sse4;
qPixelLayouts[QImage::Format_RGBA8888].fetchToARGB32PM = fetchRGBA8888ToARGB32PM_sse4;
diff --git a/src/gui/painting/qdrawhelper_avx2.cpp b/src/gui/painting/qdrawhelper_avx2.cpp
index 17a52402ae..34de69ecf4 100644
--- a/src/gui/painting/qdrawhelper_avx2.cpp
+++ b/src/gui/painting/qdrawhelper_avx2.cpp
@@ -442,14 +442,14 @@ void QT_FASTCALL comp_func_SourceOver_rgbafp_avx2(QRgbaFloat32 *dst, const QRgba
_mm256_storeu_ps((float *)(dst + x), dstVector);
}
if (x < length) {
- __m128 srcVector = _mm_load_ps((float *)(src + x));
- __m128 dstVector = _mm_load_ps((const float *)(dst + x));
+ __m128 srcVector = _mm_loadu_ps((const float *)&src[x]);
+ __m128 dstVector = _mm_loadu_ps((const float *)&dst[x]);
srcVector = _mm_mul_ps(srcVector, constAlphaVector);
__m128 alphaChannel = _mm_permute_ps(srcVector, _MM_SHUFFLE(3, 3, 3, 3));
alphaChannel = _mm_sub_ps(one, alphaChannel);
dstVector = _mm_mul_ps(dstVector, alphaChannel);
dstVector = _mm_add_ps(dstVector, srcVector);
- _mm_store_ps((float *)(dst + x), dstVector);
+ _mm_storeu_ps((float *)(dst + x), dstVector);
}
}
#endif
@@ -544,12 +544,12 @@ void QT_FASTCALL comp_func_Source_rgbafp_avx2(QRgbaFloat32 *dst, const QRgbaFloa
_mm256_storeu_ps((float *)&dst[x], dstVector);
}
if (x < length) {
- __m128 srcVector = _mm_load_ps((const float *)&src[x]);
- __m128 dstVector = _mm_load_ps((const float *)&dst[x]);
+ __m128 srcVector = _mm_loadu_ps((const float *)&src[x]);
+ __m128 dstVector = _mm_loadu_ps((const float *)&dst[x]);
srcVector = _mm_mul_ps(srcVector, constAlphaVector);
dstVector = _mm_mul_ps(dstVector, oneMinusConstAlpha);
dstVector = _mm_add_ps(dstVector, srcVector);
- _mm_store_ps((float *)&dst[x], dstVector);
+ _mm_storeu_ps((float *)&dst[x], dstVector);
}
}
}
@@ -630,7 +630,7 @@ void QT_FASTCALL comp_func_solid_Source_rgbafp_avx2(QRgbaFloat32 *dst, int lengt
const float a = const_alpha / 255.0f;
const __m128 alphaVector = _mm_set1_ps(a);
const __m128 minusAlphaVector = _mm_set1_ps(1.0f - a);
- __m128 colorVector = _mm_load_ps((const float *)&color);
+ __m128 colorVector = _mm_loadu_ps((const float *)&color);
colorVector = _mm_mul_ps(colorVector, alphaVector);
const __m256 colorVector256 = _mm256_insertf128_ps(_mm256_castps128_ps256(colorVector), colorVector, 1);
const __m256 minusAlphaVector256 = _mm256_set1_ps(1.0f - a);
@@ -642,10 +642,10 @@ void QT_FASTCALL comp_func_solid_Source_rgbafp_avx2(QRgbaFloat32 *dst, int lengt
_mm256_storeu_ps((float *)&dst[x], dstVector);
}
if (x < length) {
- __m128 dstVector = _mm_load_ps((const float *)&dst[x]);
+ __m128 dstVector = _mm_loadu_ps((const float *)&dst[x]);
dstVector = _mm_mul_ps(dstVector, minusAlphaVector);
dstVector = _mm_add_ps(dstVector, colorVector);
- _mm_store_ps((float *)&dst[x], dstVector);
+ _mm_storeu_ps((float *)&dst[x], dstVector);
}
}
}
@@ -657,7 +657,7 @@ void QT_FASTCALL comp_func_solid_SourceOver_rgbafp_avx2(QRgbaFloat32 *dst, int l
for (int i = 0; i < length; ++i)
dst[i] = color;
} else {
- __m128 colorVector = _mm_load_ps((const float *)&color);
+ __m128 colorVector = _mm_loadu_ps((const float *)&color);
if (const_alpha != 255)
colorVector = _mm_mul_ps(colorVector, _mm_set1_ps(const_alpha / 255.f));
__m128 minusAlphaOfColorVector =
@@ -673,10 +673,10 @@ void QT_FASTCALL comp_func_solid_SourceOver_rgbafp_avx2(QRgbaFloat32 *dst, int l
_mm256_storeu_ps((float *)&dst[x], dstVector);
}
if (x < length) {
- __m128 dstVector = _mm_load_ps((const float *)&dst[x]);
+ __m128 dstVector = _mm_loadu_ps((const float *)&dst[x]);
dstVector = _mm_mul_ps(dstVector, minusAlphaOfColorVector);
dstVector = _mm_add_ps(dstVector, colorVector);
- _mm_store_ps((float *)&dst[x], dstVector);
+ _mm_storeu_ps((float *)&dst[x], dstVector);
}
}
}
@@ -1345,13 +1345,16 @@ const QRgba64 *QT_FASTCALL fetchRGBA64ToRGBA64PM_avx2(QRgba64 *buffer, const uch
vslo = _mm256_srli_epi32(vslo, 16);
vshi = _mm256_srli_epi32(vshi, 16);
vs256 = _mm256_packus_epi32(vslo, vshi);
+ vs256 = _mm256_blend_epi16(vs256, va256, 0x88);
_mm256_storeu_si256((__m256i *)(buffer + i), vs256);
}
for (; i < count; ++i) {
+ const auto a = s[i].alpha();
__m128i vs = _mm_loadl_epi64((const __m128i *)(s + i));
__m128i va = _mm_shufflelo_epi16(vs, _MM_SHUFFLE(3, 3, 3, 3));
vs = multiplyAlpha65535(vs, va);
_mm_storel_epi64((__m128i *)(buffer + i), vs);
+ buffer[i].setAlpha(a);
}
return buffer;
}
@@ -1554,7 +1557,7 @@ const QRgbaFloat32 *QT_FASTCALL fetchRGBA16FToRGBA32F_avx2(QRgbaFloat32 *buffer,
__m128 vsa = _mm_permute_ps(vsf, _MM_SHUFFLE(3, 3, 3, 3));
vsf = _mm_mul_ps(vsf, vsa);
vsf = _mm_insert_ps(vsf, vsa, 0x30);
- _mm_store_ps((float *)(buffer + i), vsf);
+ _mm_storeu_ps((float *)(buffer + i), vsf);
}
return buffer;
}
@@ -1566,7 +1569,7 @@ void QT_FASTCALL storeRGBX16FFromRGBA32F_avx2(uchar *dest, const QRgbaFloat32 *s
const __m128 *s = reinterpret_cast<const __m128 *>(src);
const __m128 zero = _mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f);
for (int i = 0; i < count; ++i) {
- __m128 vsf = _mm_load_ps(reinterpret_cast<const float *>(s + i));
+ __m128 vsf = _mm_loadu_ps(reinterpret_cast<const float *>(s + i));
const __m128 vsa = _mm_permute_ps(vsf, _MM_SHUFFLE(3, 3, 3, 3));
const float a = _mm_cvtss_f32(vsa);
if (a == 1.0f)
@@ -1590,7 +1593,7 @@ void QT_FASTCALL storeRGBA16FFromRGBA32F_avx2(uchar *dest, const QRgbaFloat32 *s
const __m128 *s = reinterpret_cast<const __m128 *>(src);
const __m128 zero = _mm_set1_ps(0.0f);
for (int i = 0; i < count; ++i) {
- __m128 vsf = _mm_load_ps(reinterpret_cast<const float *>(s + i));
+ __m128 vsf = _mm_loadu_ps(reinterpret_cast<const float *>(s + i));
const __m128 vsa = _mm_permute_ps(vsf, _MM_SHUFFLE(3, 3, 3, 3));
const float a = _mm_cvtss_f32(vsa);
if (a == 1.0f)
diff --git a/src/gui/painting/qdrawhelper_mips_dsp.cpp b/src/gui/painting/qdrawhelper_mips_dsp.cpp
index af2c6598b2..86dcde2b58 100644
--- a/src/gui/painting/qdrawhelper_mips_dsp.cpp
+++ b/src/gui/painting/qdrawhelper_mips_dsp.cpp
@@ -95,7 +95,7 @@ void qt_blend_rgb16_on_rgb16_mips_dspr2(uchar *destPixels, int dbpl,
}
else {
int length = w << 1;
- while (h--) {
+ while (--h >= 0) {
memcpy(destPixels, srcPixels, length);
destPixels += dbpl;
srcPixels += sbpl;
@@ -130,7 +130,7 @@ void qt_blend_rgb16_on_rgb16_mips_dsp(uchar *destPixels, int dbpl,
}
else {
int length = w << 1;
- while (h--) {
+ while (--h >= 0) {
memcpy(destPixels, srcPixels, length);
destPixels += dbpl;
srcPixels += sbpl;
diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp
index 17ec693649..1fceb83710 100644
--- a/src/gui/painting/qdrawhelper_neon.cpp
+++ b/src/gui/painting/qdrawhelper_neon.cpp
@@ -185,7 +185,7 @@ void qt_blend_rgb16_on_argb32_neon(uchar *destPixels, int dbpl,
quint8 a = (255 * const_alpha) >> 8;
quint8 ia = 255 - a;
- while (h--) {
+ while (--h >= 0) {
for (int x=0; x<w; ++x)
dst[x] = INTERPOLATE_PIXEL_255(qConvertRgb16To32(src[x]), a, dst[x], ia);
dst += dbpl;
@@ -228,7 +228,7 @@ static inline void blockBlit16(quint16 *dst, quint16 *src, int dstride, int sstr
u.pointer = dst;
if (u.address & 2) {
- while (h--) {
+ while (--h >= 0) {
// align dst
dst[0] = src[0];
if (Width > 1)
@@ -237,7 +237,7 @@ static inline void blockBlit16(quint16 *dst, quint16 *src, int dstride, int sstr
src += sstride;
}
} else {
- while (h--) {
+ while (--h >= 0) {
scanLineBlit16<Width>(dst, src, dstride);
dst += dstride;
diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h
index 5f58d55dd0..833ddd7b16 100644
--- a/src/gui/painting/qdrawhelper_p.h
+++ b/src/gui/painting/qdrawhelper_p.h
@@ -174,7 +174,6 @@ struct RadialGradientValues
qreal dr;
qreal sqrfr;
qreal a;
- qreal inv2a;
bool extended;
};
@@ -402,12 +401,12 @@ const BlendType * QT_FASTCALL qt_fetch_radial_gradient_template(BlendType *buffe
bool affine = !data->m13 && !data->m23;
BlendType *end = buffer + length;
+ qreal inv_a = 1 / qreal(2 * op->radial.a);
+
if (affine) {
rx -= data->gradient.radial.focal.x;
ry -= data->gradient.radial.focal.y;
- qreal inv_a = 1 / qreal(2 * op->radial.a);
-
const qreal delta_rx = data->m11;
const qreal delta_ry = data->m12;
@@ -452,8 +451,8 @@ const BlendType * QT_FASTCALL qt_fetch_radial_gradient_template(BlendType *buffe
if (det >= 0) {
qreal detSqrt = qSqrt(det);
- qreal s0 = (-b - detSqrt) * op->radial.inv2a;
- qreal s1 = (-b + detSqrt) * op->radial.inv2a;
+ qreal s0 = (-b - detSqrt) * inv_a;
+ qreal s1 = (-b + detSqrt) * inv_a;
qreal s = qMax(s0, s1);
diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp
index 22014ec175..79590534f3 100644
--- a/src/gui/painting/qdrawhelper_sse2.cpp
+++ b/src/gui/painting/qdrawhelper_sse2.cpp
@@ -197,7 +197,7 @@ void QT_FASTCALL comp_func_Source_sse2(uint *dst, const uint *src, int length, u
}
}
-#ifndef __AVX2__
+#ifndef __haswell__
static Q_NEVER_INLINE
void Q_DECL_VECTORCALL qt_memfillXX_aligned(void *dest, __m128i value128, quintptr bytecount)
{
@@ -281,7 +281,7 @@ void qt_memfill32_sse2(quint32 *dest, quint32 value, qsizetype count)
qt_memfillXX_aligned(dest, _mm_set1_epi32(value), count * sizeof(quint32));
}
-#endif // !__AVX2__
+#endif // !__haswell__
void QT_FASTCALL comp_func_solid_Source_sse2(uint *destPixels, int length, uint color, uint const_alpha)
{
@@ -361,7 +361,7 @@ void qt_bitmapblit32_sse2_base(QRasterBuffer *rasterBuffer, int x, int y,
0x04040404, 0x08080808);
const __m128i maskadd2 = _mm_set_epi32(0x7f7f7f7f, 0x7e7e7e7e,
0x7c7c7c7c, 0x78787878);
- while (height--) {
+ while (--height >= 0) {
for (int x = 0; x < width; x += 8) {
const quint8 s = src[x >> 3];
if (!s)
@@ -380,7 +380,7 @@ void qt_bitmapblit32_sse2_base(QRasterBuffer *rasterBuffer, int x, int y,
src += stride;
}
} else {
- while (height--) {
+ while (--height >= 0) {
const quint8 s = *src;
if (s) {
__m128i mask1 = _mm_set1_epi8(s);
@@ -423,7 +423,7 @@ QT_WARNING_DISABLE_MSVC(4309) // truncation of constant value
const __m128i maskadd = _mm_set_epi16(0x7f7f, 0x7e7e, 0x7c7c, 0x7878,
0x7070, 0x6060, 0x4040, 0x0000);
- while (height--) {
+ while (--height >= 0) {
for (int x = 0; x < width; x += 8) {
const quint8 s = src[x >> 3];
if (!s)
@@ -558,7 +558,7 @@ void qt_scale_image_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
if (xend < 0 || xend >= (int)(sbpl/sizeof(quint32)))
--w;
- while (h--) {
+ while (--h >= 0) {
const uint *src = (const quint32 *) (srcPixels + (srcy >> 16) * sbpl);
int srcx = basex;
int x = 0;
diff --git a/src/gui/painting/qdrawhelper_sse4.cpp b/src/gui/painting/qdrawhelper_sse4.cpp
index 7b9481eb3a..a7b4e6ba76 100644
--- a/src/gui/painting/qdrawhelper_sse4.cpp
+++ b/src/gui/painting/qdrawhelper_sse4.cpp
@@ -10,7 +10,7 @@
QT_BEGIN_NAMESPACE
-#ifndef __AVX2__
+#ifndef __haswell__
template<bool RGBA>
static void convertARGBToARGB32PM_sse4(uint *buffer, const uint *src, int count)
{
@@ -106,7 +106,7 @@ static void convertARGBToRGBA64PM_sse4(QRgba64 *buffer, const uint *src, int cou
buffer[i] = QRgba64::fromArgb32(s).premultiplied();
}
}
-#endif // __AVX2__
+#endif // __haswell__
static inline __m128 Q_DECL_VECTORCALL reciprocal_mul_ps(__m128 a, float mul)
{
@@ -375,7 +375,7 @@ static inline void convertRGBA64FromRGBA64PM_sse4(QRgba64 *buffer, const QRgba64
}
}
-#ifndef __AVX2__
+#ifndef __haswell__
void QT_FASTCALL convertARGB32ToARGB32PM_sse4(uint *buffer, int count, const QList<QRgb> *)
{
convertARGBToARGB32PM_sse4<false>(buffer, buffer, count);
@@ -427,7 +427,7 @@ const QRgba64 *QT_FASTCALL fetchRGBA8888ToRGBA64PM_sse4(QRgba64 *buffer, const u
convertARGBToRGBA64PM_sse4<true>(buffer, reinterpret_cast<const uint *>(src) + index, count);
return buffer;
}
-#endif // __AVX2__
+#endif // __haswell__
void QT_FASTCALL storeRGB32FromARGB32PM_sse4(uchar *dest, const uint *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
diff --git a/src/gui/painting/qfixed_p.h b/src/gui/painting/qfixed_p.h
index f3718a097e..c0a13d057f 100644
--- a/src/gui/painting/qfixed_p.h
+++ b/src/gui/painting/qfixed_p.h
@@ -18,6 +18,7 @@
#include <QtGui/private/qtguiglobal_p.h>
#include "QtCore/qdebug.h"
#include "QtCore/qpoint.h"
+#include "QtCore/qnumeric.h"
#include "QtCore/qsize.h"
QT_BEGIN_NAMESPACE
@@ -136,6 +137,22 @@ constexpr inline QFixed operator+(uint i, QFixed d) { return d+i; }
constexpr inline QFixed operator-(uint i, QFixed d) { return -(d-i); }
// constexpr inline QFixed operator*(qreal d, QFixed d2) { return d2*d; }
+inline bool qAddOverflow(QFixed v1, QFixed v2, QFixed *r)
+{
+ int val;
+ bool result = qAddOverflow(v1.value(), v2.value(), &val);
+ r->setValue(val);
+ return result;
+}
+
+inline bool qMulOverflow(QFixed v1, QFixed v2, QFixed *r)
+{
+ int val;
+ bool result = qMulOverflow(v1.value(), v2.value(), &val);
+ r->setValue(val);
+ return result;
+}
+
#ifndef QT_NO_DEBUG_STREAM
inline QDebug &operator<<(QDebug &dbg, QFixed f)
{ return dbg << f.toReal(); }
diff --git a/src/gui/painting/qicc.cpp b/src/gui/painting/qicc.cpp
index 9d95c80bf8..c01fa433ea 100644
--- a/src/gui/painting/qicc.cpp
+++ b/src/gui/painting/qicc.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qicc_p.h"
@@ -12,6 +12,8 @@
#include <qloggingcategory.h>
#include <qstring.h>
+#include "qcolorclut_p.h"
+#include "qcolormatrix_p.h"
#include "qcolorspace_p.h"
#include "qcolortrc_p.h"
@@ -20,6 +22,8 @@
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcIcc, "qt.gui.icc", QtWarningMsg)
+namespace QIcc {
+
struct ICCProfileHeader
{
quint32_be profileSize;
@@ -58,18 +62,23 @@ constexpr quint32 IccTag(uchar a, uchar b, uchar c, uchar d)
enum class ColorSpaceType : quint32 {
Rgb = IccTag('R', 'G', 'B', ' '),
Gray = IccTag('G', 'R', 'A', 'Y'),
+ Cmyk = IccTag('C', 'M', 'Y', 'K'),
};
enum class ProfileClass : quint32 {
- Input = IccTag('s', 'c', 'r', 'n'),
+ Input = IccTag('s', 'c', 'n', 'r'),
Display = IccTag('m', 'n', 't', 'r'),
- // Not supported:
Output = IccTag('p', 'r', 't', 'r'),
ColorSpace = IccTag('s', 'p', 'a', 'c'),
+ // Not supported:
+ DeviceLink = IccTag('l', 'i', 'n', 'k'),
+ Abstract = IccTag('a', 'b', 's', 't'),
+ NamedColor = IccTag('n', 'm', 'c', 'l'),
};
enum class Tag : quint32 {
acsp = IccTag('a', 'c', 's', 'p'),
+ Lab_ = IccTag('L', 'a', 'b', ' '),
RGB_ = IccTag('R', 'G', 'B', ' '),
XYZ_ = IccTag('X', 'Y', 'Z', ' '),
rXYZ = IccTag('r', 'X', 'Y', 'Z'),
@@ -81,8 +90,18 @@ enum class Tag : quint32 {
kTRC = IccTag('k', 'T', 'R', 'C'),
A2B0 = IccTag('A', '2', 'B', '0'),
A2B1 = IccTag('A', '2', 'B', '1'),
+ A2B2 = IccTag('A', '2', 'B', '2'),
B2A0 = IccTag('B', '2', 'A', '0'),
B2A1 = IccTag('B', '2', 'A', '1'),
+ B2A2 = IccTag('B', '2', 'A', '2'),
+ B2D0 = IccTag('B', '2', 'D', '0'),
+ B2D1 = IccTag('B', '2', 'D', '1'),
+ B2D2 = IccTag('B', '2', 'D', '2'),
+ B2D3 = IccTag('B', '2', 'D', '3'),
+ D2B0 = IccTag('D', '2', 'B', '0'),
+ D2B1 = IccTag('D', '2', 'B', '1'),
+ D2B2 = IccTag('D', '2', 'B', '2'),
+ D2B3 = IccTag('D', '2', 'B', '3'),
desc = IccTag('d', 'e', 's', 'c'),
text = IccTag('t', 'e', 'x', 't'),
cprt = IccTag('c', 'p', 'r', 't'),
@@ -93,9 +112,11 @@ enum class Tag : quint32 {
mft1 = IccTag('m', 'f', 't', '1'),
mft2 = IccTag('m', 'f', 't', '2'),
mluc = IccTag('m', 'l', 'u', 'c'),
+ mpet = IccTag('m', 'p', 'e', 't'),
mAB_ = IccTag('m', 'A', 'B', ' '),
mBA_ = IccTag('m', 'B', 'A', ' '),
chad = IccTag('c', 'h', 'a', 'd'),
+ gamt = IccTag('g', 'a', 'm', 't'),
sf32 = IccTag('s', 'f', '3', '2'),
// Apple extensions for ICCv2:
@@ -104,7 +125,9 @@ enum class Tag : quint32 {
aabg = IccTag('a', 'a', 'b', 'g'),
};
-inline size_t qHash(const Tag &key, size_t seed = 0)
+} // namespace QIcc
+
+inline size_t qHash(const QIcc::Tag &key, size_t seed = 0)
{
return qHash(quint32(key), seed);
}
@@ -159,6 +182,46 @@ struct MlucTagData : GenericTagData {
MlucTagRecord records[1];
};
+struct Lut8TagData : GenericTagData {
+ quint8 inputChannels;
+ quint8 outputChannels;
+ quint8 clutGridPoints;
+ quint8 padding;
+ qint32_be e1;
+ qint32_be e2;
+ qint32_be e3;
+ qint32_be e4;
+ qint32_be e5;
+ qint32_be e6;
+ qint32_be e7;
+ qint32_be e8;
+ qint32_be e9;
+ // followed by parameter values: quint8[inputChannels * 256];
+ // followed by parameter values: quint8[outputChannels * clutGridPoints^inputChannels];
+ // followed by parameter values: quint8[outputChannels * 256];
+};
+
+struct Lut16TagData : GenericTagData {
+ quint8 inputChannels;
+ quint8 outputChannels;
+ quint8 clutGridPoints;
+ quint8 padding;
+ qint32_be e1;
+ qint32_be e2;
+ qint32_be e3;
+ qint32_be e4;
+ qint32_be e5;
+ qint32_be e6;
+ qint32_be e7;
+ qint32_be e8;
+ qint32_be e9;
+ quint16_be inputTableEntries;
+ quint16_be outputTableEntries;
+ // followed by parameter values: quint16_be[inputChannels * inputTableEntries];
+ // followed by parameter values: quint16_be[outputChannels * clutGridPoints^inputChannels];
+ // followed by parameter values: quint16_be[outputChannels * outputTableEntries];
+};
+
// For both mAB and mBA
struct mABTagData : GenericTagData {
quint8 inputChannels;
@@ -169,10 +232,34 @@ struct mABTagData : GenericTagData {
quint32_be mCurvesOffset;
quint32_be clutOffset;
quint32_be aCurvesOffset;
+ // followed by embedded data for the offsets above
+};
+
+struct mpetTagData : GenericTagData {
+ quint16_be inputChannels;
+ quint16_be outputChannels;
+ quint32_be processingElements;
+ // element offset table
+ // element data
};
struct Sf32TagData : GenericTagData {
- quint32_be value[1];
+ quint32_be value[9];
+};
+
+struct MatrixElement {
+ qint32_be e0;
+ qint32_be e1;
+ qint32_be e2;
+ qint32_be e3;
+ qint32_be e4;
+ qint32_be e5;
+ qint32_be e6;
+ qint32_be e7;
+ qint32_be e8;
+ qint32_be e9;
+ qint32_be e10;
+ qint32_be e11;
};
static int toFixedS1516(float x)
@@ -204,19 +291,19 @@ static bool isValidIccProfile(const ICCProfileHeader &header)
if (header.profileClass != uint(ProfileClass::Input)
&& header.profileClass != uint(ProfileClass::Display)
- && (header.profileClass != uint(ProfileClass::Output)
- || header.inputColorSpace != uint(ColorSpaceType::Gray))) {
+ && header.profileClass != uint(ProfileClass::Output)
+ && header.profileClass != uint(ProfileClass::ColorSpace)) {
qCInfo(lcIcc, "Unsupported ICC profile class 0x%x", quint32(header.profileClass));
return false;
}
if (header.inputColorSpace != uint(ColorSpaceType::Rgb)
- && header.inputColorSpace != uint(ColorSpaceType::Gray)) {
+ && header.inputColorSpace != uint(ColorSpaceType::Gray)
+ && header.inputColorSpace != uint(ColorSpaceType::Cmyk)) {
qCInfo(lcIcc, "Unsupported ICC input color space 0x%x", quint32(header.inputColorSpace));
return false;
}
- if (header.pcs != 0x58595a20 /* 'XYZ '*/) {
- // ### support PCSLAB
- qCInfo(lcIcc, "Unsupported ICC profile connection space 0x%x", quint32(header.pcs));
+ if (header.pcs != uint(Tag::XYZ_) && header.pcs != uint(Tag::Lab_)) {
+ qCInfo(lcIcc, "Invalid ICC profile connection space 0x%x", quint32(header.pcs));
return false;
}
@@ -234,7 +321,7 @@ static bool isValidIccProfile(const ICCProfileHeader &header)
static int writeColorTrc(QDataStream &stream, const QColorTrc &trc)
{
- if (trc.isLinear()) {
+ if (trc.isIdentity()) {
stream << uint(Tag::curv) << uint(0);
stream << uint(0);
return 12;
@@ -274,6 +361,10 @@ static int writeColorTrc(QDataStream &stream, const QColorTrc &trc)
stream << ushort(trc.m_table.m_table8[i] * 257U);
}
}
+ if (trc.m_table.m_tableSize & 1) {
+ stream << ushort(0);
+ return 12 + 2 * trc.m_table.m_tableSize + 2;
+ }
return 12 + 2 * trc.m_table.m_tableSize;
}
@@ -283,10 +374,21 @@ QByteArray toIccProfile(const QColorSpace &space)
return QByteArray();
const QColorSpacePrivate *spaceDPtr = QColorSpacePrivate::get(space);
+ // This should catch anything not three component matrix based as we can only get that from parsed ICC
+ if (!spaceDPtr->iccProfile.isEmpty())
+ return spaceDPtr->iccProfile;
+ Q_ASSERT(spaceDPtr->isThreeComponentMatrix());
+
+ int fixedLengthTagCount = 5;
+ bool writeChad = false;
+ if (!spaceDPtr->whitePoint.isNull() && spaceDPtr->whitePoint != QColorVector::D50()) {
+ writeChad = true;
+ fixedLengthTagCount++;
+ }
- constexpr int tagCount = 9;
- constexpr uint profileDataOffset = 128 + 4 + 12 * tagCount;
- constexpr uint variableTagTableOffsets = 128 + 4 + 12 * 5;
+ const int tagCount = fixedLengthTagCount + 4;
+ const uint profileDataOffset = 128 + 4 + 12 * tagCount;
+ const uint variableTagTableOffsets = 128 + 4 + 12 * fixedLengthTagCount;
uint currentOffset = 0;
uint rTrcOffset, gTrcOffset, bTrcOffset;
uint rTrcSize, gTrcSize, bTrcSize;
@@ -299,10 +401,10 @@ QByteArray toIccProfile(const QColorSpace &space)
// Profile header:
stream << uint(0); // Size, we will update this later
stream << uint(0);
- stream << uint(0x02400000); // Version 2.4 (note we use 'para' from version 4)
+ stream << uint(0x04400000); // Version 4.4
stream << uint(ProfileClass::Display);
stream << uint(Tag::RGB_);
- stream << uint(Tag::XYZ_);
+ stream << (spaceDPtr->isPcsLab ? uint(Tag::Lab_) : uint(Tag::XYZ_));
stream << uint(0) << uint(0) << uint(0);
stream << uint(Tag::acsp);
stream << uint(0) << uint(0) << uint(0);
@@ -316,19 +418,23 @@ QByteArray toIccProfile(const QColorSpace &space)
stream << uint(0) << uint(0) << uint(0) << uint(0) << uint(0) << uint(0) << uint(0);
// Tag table:
+ currentOffset = profileDataOffset;
stream << uint(tagCount);
stream << uint(Tag::rXYZ) << uint(profileDataOffset + 00) << uint(20);
stream << uint(Tag::gXYZ) << uint(profileDataOffset + 20) << uint(20);
stream << uint(Tag::bXYZ) << uint(profileDataOffset + 40) << uint(20);
stream << uint(Tag::wtpt) << uint(profileDataOffset + 60) << uint(20);
- stream << uint(Tag::cprt) << uint(profileDataOffset + 80) << uint(12);
+ stream << uint(Tag::cprt) << uint(profileDataOffset + 80) << uint(34);
+ currentOffset += 20 + 20 + 20 + 20 + 34 + 2;
+ if (writeChad) {
+ stream << uint(Tag::chad) << uint(currentOffset) << uint(44);
+ currentOffset += 44;
+ }
// From here the offset and size will be updated later:
stream << uint(Tag::rTRC) << uint(0) << uint(0);
stream << uint(Tag::gTRC) << uint(0) << uint(0);
stream << uint(Tag::bTRC) << uint(0) << uint(0);
stream << uint(Tag::desc) << uint(0) << uint(0);
- // TODO: consider adding 'chad' tag (required in ICC >=4 when we have non-D50 whitepoint)
- currentOffset = profileDataOffset;
// Tag data:
stream << uint(Tag::XYZ_) << uint(0);
@@ -347,9 +453,25 @@ QByteArray toIccProfile(const QColorSpace &space)
stream << toFixedS1516(spaceDPtr->whitePoint.x);
stream << toFixedS1516(spaceDPtr->whitePoint.y);
stream << toFixedS1516(spaceDPtr->whitePoint.z);
- stream << uint(Tag::text) << uint(0);
- stream << uint(IccTag('N', '/', 'A', '\0'));
- currentOffset += 92;
+ stream << uint(Tag::mluc) << uint(0);
+ stream << uint(1) << uint(12);
+ stream << uchar('e') << uchar('n') << uchar('U') << uchar('S');
+ stream << uint(6) << uint(28);
+ stream << ushort('N') << ushort('/') << ushort('A');
+ stream << ushort(0); // 4-byte alignment
+ if (writeChad) {
+ QColorMatrix chad = QColorMatrix::chromaticAdaptation(spaceDPtr->whitePoint);
+ stream << uint(Tag::sf32) << uint(0);
+ stream << toFixedS1516(chad.r.x);
+ stream << toFixedS1516(chad.g.x);
+ stream << toFixedS1516(chad.b.x);
+ stream << toFixedS1516(chad.r.y);
+ stream << toFixedS1516(chad.g.y);
+ stream << toFixedS1516(chad.b.y);
+ stream << toFixedS1516(chad.r.z);
+ stream << toFixedS1516(chad.g.z);
+ stream << toFixedS1516(chad.b.z);
+ }
// From now on the data is variable sized:
rTrcOffset = currentOffset;
@@ -372,16 +494,20 @@ QByteArray toIccProfile(const QColorSpace &space)
currentOffset += bTrcSize;
}
+ // Writing description
descOffset = currentOffset;
- QByteArray description = space.description().toUtf8();
- stream << uint(Tag::desc) << uint(0);
- stream << uint(description.size() + 1);
- stream.writeRawData(description.constData(), description.size() + 1);
- stream << uint(0) << uint(0);
- stream << ushort(0) << uchar(0);
- QByteArray macdesc(67, '\0');
- stream.writeRawData(macdesc.constData(), 67);
- descSize = 90 + description.size() + 1;
+ const QString description = space.description();
+ stream << uint(Tag::mluc) << uint(0);
+ stream << uint(1) << uint(12);
+ stream << uchar('e') << uchar('n') << uchar('U') << uchar('S');
+ stream << uint(description.size() * 2) << uint(28);
+ for (QChar ch : description)
+ stream << ushort(ch.unicode());
+ descSize = 28 + description.size() * 2;
+ if (description.size() & 1) {
+ stream << ushort(0);
+ currentOffset += 2;
+ }
currentOffset += descSize;
buffer.close();
@@ -412,7 +538,7 @@ struct TagEntry {
quint32 size;
};
-bool parseXyzData(const QByteArray &data, const TagEntry &tagEntry, QColorVector &colorVector)
+static bool parseXyzData(const QByteArray &data, const TagEntry &tagEntry, QColorVector &colorVector)
{
if (tagEntry.size < sizeof(XYZTagData)) {
qCWarning(lcIcc) << "Undersized XYZ tag";
@@ -431,23 +557,22 @@ bool parseXyzData(const QByteArray &data, const TagEntry &tagEntry, QColorVector
return true;
}
-bool parseTRC(const QByteArray &data, const TagEntry &tagEntry, QColorTrc &gamma)
+static quint32 parseTRC(const QByteArrayView &tagData, QColorTrc &gamma, QColorTransferTable::Type type = QColorTransferTable::TwoWay)
{
- const GenericTagData trcData = qFromUnaligned<GenericTagData>(data.constData()
- + tagEntry.offset);
+ const GenericTagData trcData = qFromUnaligned<GenericTagData>(tagData.constData());
if (trcData.type == quint32(Tag::curv)) {
Q_STATIC_ASSERT(sizeof(CurvTagData) == 12);
- const CurvTagData curv = qFromUnaligned<CurvTagData>(data.constData() + tagEntry.offset);
+ const CurvTagData curv = qFromUnaligned<CurvTagData>(tagData.constData());
if (curv.valueCount > (1 << 16))
- return false;
- if (tagEntry.size - 12 < 2 * curv.valueCount)
- return false;
- const auto valueOffset = tagEntry.offset + sizeof(CurvTagData);
+ return 0;
+ if (tagData.size() < qsizetype(12 + 2 * curv.valueCount))
+ return 0;
+ const auto valueOffset = sizeof(CurvTagData);
if (curv.valueCount == 0) {
gamma.m_type = QColorTrc::Type::Function;
gamma.m_fun = QColorTransferFunction(); // Linear
} else if (curv.valueCount == 1) {
- const quint16 v = qFromBigEndian<quint16>(data.constData() + valueOffset);
+ const quint16 v = qFromBigEndian<quint16>(tagData.constData() + valueOffset);
gamma.m_type = QColorTrc::Type::Function;
gamma.m_fun = QColorTransferFunction::fromGamma(v * (1.0f / 256.0f));
} else {
@@ -455,12 +580,12 @@ bool parseTRC(const QByteArray &data, const TagEntry &tagEntry, QColorTrc &gamma
tabl.resize(curv.valueCount);
static_assert(sizeof(GenericTagData) == 2 * sizeof(quint32_be),
"GenericTagData has padding. The following code is a subject to UB.");
- qFromBigEndian<quint16>(data.constData() + valueOffset, curv.valueCount, tabl.data());
- QColorTransferTable table = QColorTransferTable(curv.valueCount, std::move(tabl));
+ qFromBigEndian<quint16>(tagData.constData() + valueOffset, curv.valueCount, tabl.data());
+ QColorTransferTable table(curv.valueCount, tabl, type);
QColorTransferFunction curve;
if (!table.checkValidity()) {
qCWarning(lcIcc) << "Invalid curv table";
- return false;
+ return 0;
} else if (!table.asColorTransferFunction(&curve)) {
gamma.m_type = QColorTrc::Type::Table;
gamma.m_table = table;
@@ -470,43 +595,43 @@ bool parseTRC(const QByteArray &data, const TagEntry &tagEntry, QColorTrc &gamma
gamma.m_fun = curve;
}
}
- return true;
+ return 12 + 2 * curv.valueCount;
}
if (trcData.type == quint32(Tag::para)) {
Q_STATIC_ASSERT(sizeof(ParaTagData) == 12);
- const ParaTagData para = qFromUnaligned<ParaTagData>(data.constData() + tagEntry.offset);
- const auto parametersOffset = tagEntry.offset + sizeof(ParaTagData);
+ const ParaTagData para = qFromUnaligned<ParaTagData>(tagData.constData());
+ const auto parametersOffset = sizeof(ParaTagData);
quint32 parameters[7];
switch (para.curveType) {
case 0: {
- if (tagEntry.size < sizeof(ParaTagData) + 1 * 4)
- return false;
- qFromBigEndian<quint32>(data.constData() + parametersOffset, 1, parameters);
+ if (tagData.size() < 12 + 1 * 4)
+ return 0;
+ qFromBigEndian<quint32>(tagData.constData() + parametersOffset, 1, parameters);
float g = fromFixedS1516(parameters[0]);
gamma.m_type = QColorTrc::Type::Function;
gamma.m_fun = QColorTransferFunction::fromGamma(g);
- break;
+ return 12 + 1 * 4;
}
case 1: {
- if (tagEntry.size < sizeof(ParaTagData) + 3 * 4)
- return false;
- qFromBigEndian<quint32>(data.constData() + parametersOffset, 3, parameters);
+ if (tagData.size() < 12 + 3 * 4)
+ return 0;
+ qFromBigEndian<quint32>(tagData.constData() + parametersOffset, 3, parameters);
if (parameters[1] == 0)
- return false;
+ return 0;
float g = fromFixedS1516(parameters[0]);
float a = fromFixedS1516(parameters[1]);
float b = fromFixedS1516(parameters[2]);
float d = -b / a;
gamma.m_type = QColorTrc::Type::Function;
gamma.m_fun = QColorTransferFunction(a, b, 0.0f, d, 0.0f, 0.0f, g);
- break;
+ return 12 + 3 * 4;
}
case 2: {
- if (tagEntry.size < sizeof(ParaTagData) + 4 * 4)
- return false;
- qFromBigEndian<quint32>(data.constData() + parametersOffset, 4, parameters);
+ if (tagData.size() < 12 + 4 * 4)
+ return 0;
+ qFromBigEndian<quint32>(tagData.constData() + parametersOffset, 4, parameters);
if (parameters[1] == 0)
- return false;
+ return 0;
float g = fromFixedS1516(parameters[0]);
float a = fromFixedS1516(parameters[1]);
float b = fromFixedS1516(parameters[2]);
@@ -514,12 +639,12 @@ bool parseTRC(const QByteArray &data, const TagEntry &tagEntry, QColorTrc &gamma
float d = -b / a;
gamma.m_type = QColorTrc::Type::Function;
gamma.m_fun = QColorTransferFunction(a, b, 0.0f, d, c, c, g);
- break;
+ return 12 + 4 * 4;
}
case 3: {
- if (tagEntry.size < sizeof(ParaTagData) + 5 * 4)
- return false;
- qFromBigEndian<quint32>(data.constData() + parametersOffset, 5, parameters);
+ if (tagData.size() < 12 + 5 * 4)
+ return 0;
+ qFromBigEndian<quint32>(tagData.constData() + parametersOffset, 5, parameters);
float g = fromFixedS1516(parameters[0]);
float a = fromFixedS1516(parameters[1]);
float b = fromFixedS1516(parameters[2]);
@@ -527,12 +652,12 @@ bool parseTRC(const QByteArray &data, const TagEntry &tagEntry, QColorTrc &gamma
float d = fromFixedS1516(parameters[4]);
gamma.m_type = QColorTrc::Type::Function;
gamma.m_fun = QColorTransferFunction(a, b, c, d, 0.0f, 0.0f, g);
- break;
+ return 12 + 5 * 4;
}
case 4: {
- if (tagEntry.size < sizeof(ParaTagData) + 7 * 4)
- return false;
- qFromBigEndian<quint32>(data.constData() + parametersOffset, 7, parameters);
+ if (tagData.size() < 12 + 7 * 4)
+ return 0;
+ qFromBigEndian<quint32>(tagData.constData() + parametersOffset, 7, parameters);
float g = fromFixedS1516(parameters[0]);
float a = fromFixedS1516(parameters[1]);
float b = fromFixedS1516(parameters[2]);
@@ -542,19 +667,401 @@ bool parseTRC(const QByteArray &data, const TagEntry &tagEntry, QColorTrc &gamma
float f = fromFixedS1516(parameters[6]);
gamma.m_type = QColorTrc::Type::Function;
gamma.m_fun = QColorTransferFunction(a, b, c, d, e, f, g);
- break;
+ return 12 + 7 * 4;
}
default:
qCWarning(lcIcc) << "Unknown para type" << uint(para.curveType);
+ return 0;
+ }
+ return true;
+ }
+ qCWarning(lcIcc) << "Invalid TRC data type" << Qt::hex << trcData.type;
+ return 0;
+}
+
+template<typename T>
+static void parseCLUT(const T *tableData, const float f, QColorCLUT *clut, uchar outputChannels)
+{
+ if (outputChannels == 4) {
+ for (qsizetype index = 0; index < clut->table.size(); ++index) {
+ QColorVector v(tableData[index * 4 + 0] * f,
+ tableData[index * 4 + 1] * f,
+ tableData[index * 4 + 2] * f,
+ tableData[index * 4 + 3] * f);
+ clut->table[index] = v;
+ };
+ } else {
+ for (qsizetype index = 0; index < clut->table.size(); ++index) {
+ QColorVector v(tableData[index * 3 + 0] * f,
+ tableData[index * 3 + 1] * f,
+ tableData[index * 3 + 2] * f);
+ clut->table[index] = v;
+ };
+ }
+}
+
+// very simple version for small values (<=4) of exp.
+static constexpr qsizetype intPow(qsizetype x, qsizetype exp)
+{
+ return (exp <= 1) ? x : x * intPow(x, exp - 1);
+}
+
+// Parses lut8 and lut16 type elements
+template<typename T>
+static bool parseLutData(const QByteArray &data, const TagEntry &tagEntry, QColorSpacePrivate *colorSpacePrivate, bool isAb)
+{
+ if (tagEntry.size < sizeof(T)) {
+ qCWarning(lcIcc) << "Undersized lut8/lut16 tag";
+ return false;
+ }
+ if (qsizetype(tagEntry.size) > data.size()) {
+ qCWarning(lcIcc) << "Truncated lut8/lut16 tag";
+ return false;
+ }
+ using S = std::conditional_t<std::is_same_v<T, Lut8TagData>, uint8_t, uint16_t>;
+ const T lut = qFromUnaligned<T>(data.constData() + tagEntry.offset);
+ int inputTableEntries, outputTableEntries, precision;
+ if constexpr (std::is_same_v<T, Lut8TagData>) {
+ Q_ASSERT(lut.type == quint32(Tag::mft1));
+ if (!colorSpacePrivate->isPcsLab && isAb) {
+ qCWarning(lcIcc) << "Lut8 can not output XYZ values";
+ return false;
+ }
+ inputTableEntries = 256;
+ outputTableEntries = 256;
+ precision = 1;
+ } else {
+ Q_ASSERT(lut.type == quint32(Tag::mft2));
+ inputTableEntries = lut.inputTableEntries;
+ outputTableEntries = lut.outputTableEntries;
+ if (inputTableEntries < 2 || inputTableEntries > 4096)
+ return false;
+ if (outputTableEntries < 2 || outputTableEntries > 4096)
+ return false;
+ precision = 2;
+ }
+
+ bool inTableIsLinear = true, outTableIsLinear = true;
+ QColorSpacePrivate::TransferElement inTableElement;
+ QColorSpacePrivate::TransferElement outTableElement;
+ QColorCLUT clutElement;
+ QColorMatrix matrixElement;
+
+ matrixElement.r.x = fromFixedS1516(lut.e1);
+ matrixElement.g.x = fromFixedS1516(lut.e2);
+ matrixElement.b.x = fromFixedS1516(lut.e3);
+ matrixElement.r.y = fromFixedS1516(lut.e4);
+ matrixElement.g.y = fromFixedS1516(lut.e5);
+ matrixElement.b.y = fromFixedS1516(lut.e6);
+ matrixElement.r.z = fromFixedS1516(lut.e7);
+ matrixElement.g.z = fromFixedS1516(lut.e8);
+ matrixElement.b.z = fromFixedS1516(lut.e9);
+ if (!colorSpacePrivate->isPcsLab && !isAb && !matrixElement.isValid()) {
+ qCWarning(lcIcc) << "Invalid matrix values in lut8/lut16";
+ return false;
+ }
+
+ if (lut.inputChannels != 3 && !(isAb && colorSpacePrivate->colorModel == QColorSpace::ColorModel::Cmyk && lut.inputChannels == 4)) {
+ qCWarning(lcIcc) << "Unsupported lut8/lut16 input channel count" << lut.inputChannels;
+ return false;
+ }
+
+ if (lut.outputChannels != 3 && !(!isAb && colorSpacePrivate->colorModel == QColorSpace::ColorModel::Cmyk && lut.outputChannels == 4)) {
+ qCWarning(lcIcc) << "Unsupported lut8/lut16 output channel count" << lut.outputChannels;
+ return false;
+ }
+
+ const qsizetype clutTableSize = intPow(lut.clutGridPoints, lut.inputChannels);
+ if (tagEntry.size < (sizeof(T) + precision * lut.inputChannels * inputTableEntries
+ + precision * lut.outputChannels * outputTableEntries
+ + precision * lut.outputChannels * clutTableSize)) {
+ qCWarning(lcIcc) << "Undersized lut8/lut16 tag, no room for tables";
+ return false;
+ }
+ if (colorSpacePrivate->colorModel == QColorSpace::ColorModel::Cmyk && clutTableSize == 0) {
+ qCWarning(lcIcc) << "Cmyk conversion must have a CLUT";
+ return false;
+ }
+
+ const uint8_t *tableData = reinterpret_cast<const uint8_t *>(data.constData() + tagEntry.offset + sizeof(T));
+
+ for (int j = 0; j < lut.inputChannels; ++j) {
+ QList<S> input(inputTableEntries);
+ qFromBigEndian<S>(tableData, inputTableEntries, input.data());
+ QColorTransferTable table(inputTableEntries, input, QColorTransferTable::OneWay);
+ if (!table.checkValidity()) {
+ qCWarning(lcIcc) << "Bad input table in lut8/lut16";
+ return false;
+ }
+ if (!table.isIdentity())
+ inTableIsLinear = false;
+ inTableElement.trc[j] = std::move(table);
+ tableData += inputTableEntries * precision;
+ }
+
+ clutElement.table.resize(clutTableSize);
+ clutElement.gridPointsX = clutElement.gridPointsY = clutElement.gridPointsZ = lut.clutGridPoints;
+ if (lut.inputChannels == 4)
+ clutElement.gridPointsW = lut.clutGridPoints;
+
+ if constexpr (std::is_same_v<T, Lut8TagData>) {
+ parseCLUT(tableData, 1.f / 255.f, &clutElement, lut.outputChannels);
+ } else {
+ float f = 1.0f / 65535.f;
+ if (colorSpacePrivate->isPcsLab && isAb) // Legacy lut16 conversion to Lab
+ f = 1.0f / 65280.f;
+ QList<S> clutTable(clutTableSize * lut.outputChannels);
+ qFromBigEndian<S>(tableData, clutTable.size(), clutTable.data());
+ parseCLUT(clutTable.constData(), f, &clutElement, lut.outputChannels);
+ }
+ tableData += clutTableSize * lut.outputChannels * precision;
+
+ for (int j = 0; j < lut.outputChannels; ++j) {
+ QList<S> output(outputTableEntries);
+ qFromBigEndian<S>(tableData, outputTableEntries, output.data());
+ QColorTransferTable table(outputTableEntries, output, QColorTransferTable::OneWay);
+ if (!table.checkValidity()) {
+ qCWarning(lcIcc) << "Bad output table in lut8/lut16";
return false;
}
+ if (!table.isIdentity())
+ outTableIsLinear = false;
+ outTableElement.trc[j] = std::move(table);
+ tableData += outputTableEntries * precision;
+ }
+
+ if (isAb) {
+ if (!inTableIsLinear)
+ colorSpacePrivate->mAB.append(inTableElement);
+ if (!clutElement.isEmpty())
+ colorSpacePrivate->mAB.append(clutElement);
+ if (!outTableIsLinear || colorSpacePrivate->mAB.isEmpty())
+ colorSpacePrivate->mAB.append(outTableElement);
+ } else {
+ // The matrix is only to be applied if the input color-space is XYZ
+ if (!colorSpacePrivate->isPcsLab && !matrixElement.isIdentity())
+ colorSpacePrivate->mBA.append(matrixElement);
+ if (!inTableIsLinear)
+ colorSpacePrivate->mBA.append(inTableElement);
+ if (!clutElement.isEmpty())
+ colorSpacePrivate->mBA.append(clutElement);
+ if (!outTableIsLinear || colorSpacePrivate->mBA.isEmpty())
+ colorSpacePrivate->mBA.append(outTableElement);
+ }
+ return true;
+}
+
+// Parses mAB and mBA type elements
+static bool parseMabData(const QByteArray &data, const TagEntry &tagEntry, QColorSpacePrivate *colorSpacePrivate, bool isAb)
+{
+ if (tagEntry.size < sizeof(mABTagData)) {
+ qCWarning(lcIcc) << "Undersized mAB/mBA tag";
+ return false;
+ }
+ if (qsizetype(tagEntry.size) > data.size()) {
+ qCWarning(lcIcc) << "Truncated mAB/mBA tag";
+ return false;
+ }
+ const mABTagData mab = qFromUnaligned<mABTagData>(data.constData() + tagEntry.offset);
+ if ((mab.type != quint32(Tag::mAB_) && isAb) || (mab.type != quint32(Tag::mBA_) && !isAb)){
+ qCWarning(lcIcc) << "Bad mAB/mBA content type";
+ return false;
+ }
+
+ if (mab.inputChannels != 3 && !(isAb && colorSpacePrivate->colorModel == QColorSpace::ColorModel::Cmyk && mab.inputChannels == 4)) {
+ qCWarning(lcIcc) << "Unsupported mAB/mBA input channel count" << mab.inputChannels;
+ return false;
+ }
+
+ if (mab.outputChannels != 3 && !(!isAb && colorSpacePrivate->colorModel == QColorSpace::ColorModel::Cmyk && mab.outputChannels == 4)) {
+ qCWarning(lcIcc) << "Unsupported mAB/mBA output channel count" << mab.outputChannels;
+ return false;
+ }
+
+ // These combinations are legal: B, M + Matrix + B, A + Clut + B, A + Clut + M + Matrix + B
+ if (!mab.bCurvesOffset) {
+ qCWarning(lcIcc) << "Illegal mAB/mBA without B table";
+ return false;
+ }
+ if (((bool)mab.matrixOffset != (bool)mab.mCurvesOffset) ||
+ ((bool)mab.aCurvesOffset != (bool)mab.clutOffset)) {
+ qCWarning(lcIcc) << "Illegal mAB/mBA element combination";
+ return false;
+ }
+
+ if (mab.aCurvesOffset > (tagEntry.size - 3 * sizeof(GenericTagData)) ||
+ mab.bCurvesOffset > (tagEntry.size - 3 * sizeof(GenericTagData)) ||
+ mab.mCurvesOffset > (tagEntry.size - 3 * sizeof(GenericTagData)) ||
+ mab.matrixOffset > (tagEntry.size - 4 * 12) ||
+ mab.clutOffset > (tagEntry.size - 20)) {
+ qCWarning(lcIcc) << "Illegal mAB/mBA element offset";
+ return false;
+ }
+
+ QColorSpacePrivate::TransferElement bTableElement;
+ QColorSpacePrivate::TransferElement aTableElement;
+ QColorCLUT clutElement;
+ QColorSpacePrivate::TransferElement mTableElement;
+ QColorMatrix matrixElement;
+ QColorVector offsetElement;
+
+ auto parseCurves = [&data, &tagEntry] (uint curvesOffset, QColorTrc *table, int channels) {
+ for (int i = 0; i < channels; ++i) {
+ if (qsizetype(tagEntry.offset + curvesOffset + 12) > data.size() || curvesOffset + 12 > tagEntry.size) {
+ qCWarning(lcIcc) << "Space missing for channel curves in mAB/mBA";
+ return false;
+ }
+ auto size = parseTRC(QByteArrayView(data).sliced(tagEntry.offset + curvesOffset, tagEntry.size - curvesOffset), table[i], QColorTransferTable::OneWay);
+ if (!size)
+ return false;
+ if (size & 2) size += 2; // possible padding
+ curvesOffset += size;
+ }
return true;
+ };
+
+ bool bCurvesAreLinear = true, aCurvesAreLinear = true, mCurvesAreLinear = true;
+
+ // B Curves
+ if (!parseCurves(mab.bCurvesOffset, bTableElement.trc, isAb ? mab.outputChannels : mab.inputChannels)) {
+ qCWarning(lcIcc) << "Invalid B curves";
+ return false;
+ } else {
+ bCurvesAreLinear = bTableElement.trc[0].isIdentity() && bTableElement.trc[1].isIdentity() && bTableElement.trc[2].isIdentity();
}
- qCWarning(lcIcc) << "Invalid TRC data type";
+
+ // A Curves
+ if (mab.aCurvesOffset) {
+ if (!parseCurves(mab.aCurvesOffset, aTableElement.trc, isAb ? mab.inputChannels : mab.outputChannels)) {
+ qCWarning(lcIcc) << "Invalid A curves";
+ return false;
+ } else {
+ aCurvesAreLinear = aTableElement.trc[0].isIdentity() && aTableElement.trc[1].isIdentity() && aTableElement.trc[2].isIdentity();
+ }
+ }
+
+ // M Curves
+ if (mab.mCurvesOffset) {
+ if (!parseCurves(mab.mCurvesOffset, mTableElement.trc, 3)) {
+ qCWarning(lcIcc) << "Invalid M curves";
+ return false;
+ } else {
+ mCurvesAreLinear = mTableElement.trc[0].isIdentity() && mTableElement.trc[1].isIdentity() && mTableElement.trc[2].isIdentity();
+ }
+ }
+
+ // Matrix
+ if (mab.matrixOffset) {
+ const MatrixElement matrix = qFromUnaligned<MatrixElement>(data.constData() + tagEntry.offset + mab.matrixOffset);
+ matrixElement.r.x = fromFixedS1516(matrix.e0);
+ matrixElement.g.x = fromFixedS1516(matrix.e1);
+ matrixElement.b.x = fromFixedS1516(matrix.e2);
+ matrixElement.r.y = fromFixedS1516(matrix.e3);
+ matrixElement.g.y = fromFixedS1516(matrix.e4);
+ matrixElement.b.y = fromFixedS1516(matrix.e5);
+ matrixElement.r.z = fromFixedS1516(matrix.e6);
+ matrixElement.g.z = fromFixedS1516(matrix.e7);
+ matrixElement.b.z = fromFixedS1516(matrix.e8);
+ offsetElement.x = fromFixedS1516(matrix.e9);
+ offsetElement.y = fromFixedS1516(matrix.e10);
+ offsetElement.z = fromFixedS1516(matrix.e11);
+ if (!matrixElement.isValid() || !offsetElement.isValid()) {
+ qCWarning(lcIcc) << "Invalid matrix values in mAB/mBA element";
+ return false;
+ }
+ }
+
+ // CLUT
+ if (mab.clutOffset) {
+ clutElement.gridPointsX = uint8_t(data[tagEntry.offset + mab.clutOffset]);
+ clutElement.gridPointsY = uint8_t(data[tagEntry.offset + mab.clutOffset + 1]);
+ clutElement.gridPointsZ = uint8_t(data[tagEntry.offset + mab.clutOffset + 2]);
+ clutElement.gridPointsW = std::max(uint8_t(data[tagEntry.offset + mab.clutOffset + 3]), uint8_t(1));
+ const uchar precision = data[tagEntry.offset + mab.clutOffset + 16];
+ if (precision > 2 || precision < 1) {
+ qCWarning(lcIcc) << "Invalid mAB/mBA element CLUT precision";
+ return false;
+ }
+ if (clutElement.gridPointsX < 2 || clutElement.gridPointsY < 2 || clutElement.gridPointsZ < 2) {
+ qCWarning(lcIcc) << "Empty CLUT";
+ return false;
+ }
+ const qsizetype clutTableSize = clutElement.gridPointsX * clutElement.gridPointsY * clutElement.gridPointsZ * clutElement.gridPointsW;
+ if ((mab.clutOffset + 20 + clutTableSize * mab.outputChannels * precision) > tagEntry.size) {
+ qCWarning(lcIcc) << "CLUT oversized for tag";
+ return false;
+ }
+
+ clutElement.table.resize(clutTableSize);
+ if (precision == 2) {
+ QList<uint16_t> clutTable(clutTableSize * mab.outputChannels);
+ qFromBigEndian<uint16_t>(data.constData() + tagEntry.offset + mab.clutOffset + 20, clutTable.size(), clutTable.data());
+ parseCLUT(clutTable.constData(), (1.f/65535.f), &clutElement, mab.outputChannels);
+ } else {
+ const uint8_t *clutTable = reinterpret_cast<const uint8_t *>(data.constData() + tagEntry.offset + mab.clutOffset + 20);
+ parseCLUT(clutTable, (1.f/255.f), &clutElement, mab.outputChannels);
+ }
+ } else if (colorSpacePrivate->colorModel == QColorSpace::ColorModel::Cmyk) {
+ qCWarning(lcIcc) << "Cmyk conversion must have a CLUT";
+ return false;
+ }
+
+ if (isAb) {
+ if (mab.aCurvesOffset) {
+ if (!aCurvesAreLinear)
+ colorSpacePrivate->mAB.append(std::move(aTableElement));
+ if (!clutElement.isEmpty())
+ colorSpacePrivate->mAB.append(std::move(clutElement));
+ }
+ if (mab.mCurvesOffset && mab.outputChannels == 3) {
+ if (!mCurvesAreLinear)
+ colorSpacePrivate->mAB.append(std::move(mTableElement));
+ if (!matrixElement.isIdentity())
+ colorSpacePrivate->mAB.append(std::move(matrixElement));
+ if (!offsetElement.isNull())
+ colorSpacePrivate->mAB.append(std::move(offsetElement));
+ }
+ if (!bCurvesAreLinear|| colorSpacePrivate->mAB.isEmpty())
+ colorSpacePrivate->mAB.append(std::move(bTableElement));
+ } else {
+ if (!bCurvesAreLinear)
+ colorSpacePrivate->mBA.append(std::move(bTableElement));
+ if (mab.mCurvesOffset && mab.inputChannels == 3) {
+ if (!matrixElement.isIdentity())
+ colorSpacePrivate->mBA.append(std::move(matrixElement));
+ if (!offsetElement.isNull())
+ colorSpacePrivate->mBA.append(std::move(offsetElement));
+ if (!mCurvesAreLinear)
+ colorSpacePrivate->mBA.append(std::move(mTableElement));
+ }
+ if (mab.aCurvesOffset) {
+ if (!clutElement.isEmpty())
+ colorSpacePrivate->mBA.append(std::move(clutElement));
+ if (!aCurvesAreLinear)
+ colorSpacePrivate->mBA.append(std::move(aTableElement));
+ }
+ if (colorSpacePrivate->mBA.isEmpty()) // Ensure non-empty to indicate valid empty transform
+ colorSpacePrivate->mBA.append(std::move(bTableElement));
+ }
+
+ return true;
+}
+
+static bool parseA2B(const QByteArray &data, const TagEntry &tagEntry, QColorSpacePrivate *privat, bool isAb)
+{
+ const GenericTagData a2bData = qFromUnaligned<GenericTagData>(data.constData() + tagEntry.offset);
+ if (a2bData.type == quint32(Tag::mft1))
+ return parseLutData<Lut8TagData>(data, tagEntry, privat, isAb);
+ else if (a2bData.type == quint32(Tag::mft2))
+ return parseLutData<Lut16TagData>(data, tagEntry, privat, isAb);
+ else if (a2bData.type == quint32(Tag::mAB_) || a2bData.type == quint32(Tag::mBA_))
+ return parseMabData(data, tagEntry, privat, isAb);
+
+ qCWarning(lcIcc) << "fromIccProfile: Unknown A2B/B2A data type";
return false;
}
-bool parseDesc(const QByteArray &data, const TagEntry &tagEntry, QString &descName)
+static bool parseDesc(const QByteArray &data, const TagEntry &tagEntry, QString &descName)
{
const GenericTagData tag = qFromUnaligned<GenericTagData>(data.constData() + tagEntry.offset);
@@ -581,7 +1088,7 @@ bool parseDesc(const QByteArray &data, const TagEntry &tagEntry, QString &descNa
const MlucTagData mluc = qFromUnaligned<MlucTagData>(data.constData() + tagEntry.offset);
if (mluc.recordCount < 1)
return false;
- if (mluc.recordSize < 12)
+ if (mluc.recordSize != 12)
return false;
// We just use the primary record regardless of language or country.
const quint32 stringOffset = mluc.records[0].offset;
@@ -601,6 +1108,147 @@ bool parseDesc(const QByteArray &data, const TagEntry &tagEntry, QString &descNa
return true;
}
+static bool parseRgbMatrix(const QByteArray &data, const QHash<Tag, TagEntry> &tagIndex, QColorSpacePrivate *colorspaceDPtr)
+{
+ // Parse XYZ tags
+ if (!parseXyzData(data, tagIndex[Tag::rXYZ], colorspaceDPtr->toXyz.r))
+ return false;
+ if (!parseXyzData(data, tagIndex[Tag::gXYZ], colorspaceDPtr->toXyz.g))
+ return false;
+ if (!parseXyzData(data, tagIndex[Tag::bXYZ], colorspaceDPtr->toXyz.b))
+ return false;
+ if (!parseXyzData(data, tagIndex[Tag::wtpt], colorspaceDPtr->whitePoint))
+ return false;
+ if (!colorspaceDPtr->toXyz.isValid() || !colorspaceDPtr->whitePoint.isValid() || colorspaceDPtr->whitePoint.isNull()) {
+ qCWarning(lcIcc) << "Invalid XYZ values in RGB matrix";
+ return false;
+ }
+
+ colorspaceDPtr->primaries = QColorSpace::Primaries::Custom;
+ if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromSRgb()) {
+ qCDebug(lcIcc) << "fromIccProfile: sRGB primaries detected";
+ colorspaceDPtr->primaries = QColorSpace::Primaries::SRgb;
+ } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromAdobeRgb()) {
+ qCDebug(lcIcc) << "fromIccProfile: Adobe RGB primaries detected";
+ colorspaceDPtr->primaries = QColorSpace::Primaries::AdobeRgb;
+ } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromDciP3D65()) {
+ qCDebug(lcIcc) << "fromIccProfile: DCI-P3 D65 primaries detected";
+ colorspaceDPtr->primaries = QColorSpace::Primaries::DciP3D65;
+ }
+ if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromProPhotoRgb()) {
+ qCDebug(lcIcc) << "fromIccProfile: ProPhoto RGB primaries detected";
+ colorspaceDPtr->primaries = QColorSpace::Primaries::ProPhotoRgb;
+ }
+ return true;
+}
+
+static bool parseGrayMatrix(const QByteArray &data, const QHash<Tag, TagEntry> &tagIndex, QColorSpacePrivate *colorspaceDPtr)
+{
+ QColorVector whitePoint;
+ if (!parseXyzData(data, tagIndex[Tag::wtpt], whitePoint))
+ return false;
+ if (!whitePoint.isValid() || !qFuzzyCompare(whitePoint.y, 1.0f) || (1.0f + whitePoint.z + whitePoint.x) == 0.0f) {
+ qCWarning(lcIcc) << "fromIccProfile: Invalid ICC profile - gray white-point not normalized";
+ return false;
+ }
+ colorspaceDPtr->primaries = QColorSpace::Primaries::Custom;
+ colorspaceDPtr->whitePoint = whitePoint;
+ return true;
+}
+
+static bool parseChad(const QByteArray &data, const TagEntry &tagEntry, QColorSpacePrivate *colorspaceDPtr)
+{
+ if (tagEntry.size < sizeof(Sf32TagData) || qsizetype(tagEntry.size) > data.size())
+ return false;
+ const Sf32TagData chadtag = qFromUnaligned<Sf32TagData>(data.constData() + tagEntry.offset);
+ if (chadtag.type != uint32_t(Tag::sf32)) {
+ qCWarning(lcIcc, "fromIccProfile: bad chad data type");
+ return false;
+ }
+ QColorMatrix chad;
+ chad.r.x = fromFixedS1516(chadtag.value[0]);
+ chad.g.x = fromFixedS1516(chadtag.value[1]);
+ chad.b.x = fromFixedS1516(chadtag.value[2]);
+ chad.r.y = fromFixedS1516(chadtag.value[3]);
+ chad.g.y = fromFixedS1516(chadtag.value[4]);
+ chad.b.y = fromFixedS1516(chadtag.value[5]);
+ chad.r.z = fromFixedS1516(chadtag.value[6]);
+ chad.g.z = fromFixedS1516(chadtag.value[7]);
+ chad.b.z = fromFixedS1516(chadtag.value[8]);
+
+ if (!chad.isValid()) {
+ qCWarning(lcIcc, "fromIccProfile: invalid chad matrix");
+ return false;
+ }
+ colorspaceDPtr->chad = chad;
+ return true;
+}
+
+static bool parseTRCs(const QByteArray &data, const QHash<Tag, TagEntry> &tagIndex, QColorSpacePrivate *colorspaceDPtr, bool isColorSpaceTypeGray)
+{
+ TagEntry rTrc;
+ TagEntry gTrc;
+ TagEntry bTrc;
+ if (isColorSpaceTypeGray) {
+ rTrc = tagIndex[Tag::kTRC];
+ gTrc = tagIndex[Tag::kTRC];
+ bTrc = tagIndex[Tag::kTRC];
+ } else if (tagIndex.contains(Tag::aarg) && tagIndex.contains(Tag::aagg) && tagIndex.contains(Tag::aabg)) {
+ // Apple extension for parametric version of TRCs in ICCv2:
+ rTrc = tagIndex[Tag::aarg];
+ gTrc = tagIndex[Tag::aagg];
+ bTrc = tagIndex[Tag::aabg];
+ } else {
+ rTrc = tagIndex[Tag::rTRC];
+ gTrc = tagIndex[Tag::gTRC];
+ bTrc = tagIndex[Tag::bTRC];
+ }
+
+ QColorTrc rCurve;
+ QColorTrc gCurve;
+ QColorTrc bCurve;
+ if (!parseTRC(QByteArrayView(data).sliced(rTrc.offset, rTrc.size), rCurve, QColorTransferTable::TwoWay)) {
+ qCWarning(lcIcc) << "fromIccProfile: Invalid rTRC";
+ return false;
+ }
+ if (!parseTRC(QByteArrayView(data).sliced(gTrc.offset, gTrc.size), gCurve, QColorTransferTable::TwoWay)) {
+ qCWarning(lcIcc) << "fromIccProfile: Invalid gTRC";
+ return false;
+ }
+ if (!parseTRC(QByteArrayView(data).sliced(bTrc.offset, bTrc.size), bCurve, QColorTransferTable::TwoWay)) {
+ qCWarning(lcIcc) << "fromIccProfile: Invalid bTRC";
+ return false;
+ }
+ if (rCurve == gCurve && gCurve == bCurve) {
+ if (rCurve.isIdentity()) {
+ qCDebug(lcIcc) << "fromIccProfile: Linear gamma detected";
+ colorspaceDPtr->trc[0] = QColorTransferFunction();
+ colorspaceDPtr->transferFunction = QColorSpace::TransferFunction::Linear;
+ colorspaceDPtr->gamma = 1.0f;
+ } else if (rCurve.m_type == QColorTrc::Type::Function && rCurve.m_fun.isGamma()) {
+ qCDebug(lcIcc) << "fromIccProfile: Simple gamma detected";
+ colorspaceDPtr->trc[0] = QColorTransferFunction::fromGamma(rCurve.m_fun.m_g);
+ colorspaceDPtr->transferFunction = QColorSpace::TransferFunction::Gamma;
+ colorspaceDPtr->gamma = rCurve.m_fun.m_g;
+ } else if (rCurve.m_type == QColorTrc::Type::Function && rCurve.m_fun.isSRgb()) {
+ qCDebug(lcIcc) << "fromIccProfile: sRGB gamma detected";
+ colorspaceDPtr->trc[0] = QColorTransferFunction::fromSRgb();
+ colorspaceDPtr->transferFunction = QColorSpace::TransferFunction::SRgb;
+ } else {
+ colorspaceDPtr->trc[0] = rCurve;
+ colorspaceDPtr->transferFunction = QColorSpace::TransferFunction::Custom;
+ }
+ colorspaceDPtr->trc[1] = colorspaceDPtr->trc[0];
+ colorspaceDPtr->trc[2] = colorspaceDPtr->trc[0];
+ } else {
+ colorspaceDPtr->trc[0] = rCurve;
+ colorspaceDPtr->trc[1] = gCurve;
+ colorspaceDPtr->trc[2] = bCurve;
+ colorspaceDPtr->transferFunction = QColorSpace::TransferFunction::Custom;
+ }
+ return true;
+}
+
bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
{
if (data.size() < qsizetype(sizeof(ICCProfileHeader))) {
@@ -657,146 +1305,92 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
tagIndex.insert(Tag(quint32(tagTable.signature)), { tagTable.offset, tagTable.size });
}
- // Check the profile is three-component matrix based (what we currently support):
+ bool threeComponentMatrix = true;
+
if (header.inputColorSpace == uint(ColorSpaceType::Rgb)) {
+ // Check the profile is three-component matrix based:
if (!tagIndex.contains(Tag::rXYZ) || !tagIndex.contains(Tag::gXYZ) || !tagIndex.contains(Tag::bXYZ) ||
!tagIndex.contains(Tag::rTRC) || !tagIndex.contains(Tag::gTRC) || !tagIndex.contains(Tag::bTRC) ||
- !tagIndex.contains(Tag::wtpt)) {
- qCInfo(lcIcc) << "fromIccProfile: Unsupported ICC profile - not three component matrix based";
- return false;
+ !tagIndex.contains(Tag::wtpt) || header.pcs == uint(Tag::Lab_)) {
+ threeComponentMatrix = false;
+ // Check if the profile is valid n-LUT based:
+ if (!tagIndex.contains(Tag::A2B0)) {
+ qCWarning(lcIcc) << "fromIccProfile: Invalid ICC profile - neither valid three component nor n-LUT";
+ return false;
+ }
}
- } else {
- Q_ASSERT(header.inputColorSpace == uint(ColorSpaceType::Gray));
+ } else if (header.inputColorSpace == uint(ColorSpaceType::Gray)) {
if (!tagIndex.contains(Tag::kTRC) || !tagIndex.contains(Tag::wtpt)) {
qCWarning(lcIcc) << "fromIccProfile: Invalid ICC profile - not valid gray scale based";
return false;
}
+ } else if (header.inputColorSpace == uint(ColorSpaceType::Cmyk)) {
+ threeComponentMatrix = false;
+ if (!tagIndex.contains(Tag::A2B0)) {
+ qCWarning(lcIcc) << "fromIccProfile: Invalid ICC profile - CMYK, not n-LUT";
+ return false;
+ }
+ } else {
+ Q_UNREACHABLE();
}
colorSpace->detach();
QColorSpacePrivate *colorspaceDPtr = QColorSpacePrivate::get(*colorSpace);
- if (header.inputColorSpace == uint(ColorSpaceType::Rgb)) {
- // Parse XYZ tags
- if (!parseXyzData(data, tagIndex[Tag::rXYZ], colorspaceDPtr->toXyz.r))
- return false;
- if (!parseXyzData(data, tagIndex[Tag::gXYZ], colorspaceDPtr->toXyz.g))
- return false;
- if (!parseXyzData(data, tagIndex[Tag::bXYZ], colorspaceDPtr->toXyz.b))
- return false;
- if (!parseXyzData(data, tagIndex[Tag::wtpt], colorspaceDPtr->whitePoint))
- return false;
+ if (threeComponentMatrix) {
+ colorspaceDPtr->isPcsLab = false;
+ colorspaceDPtr->transformModel = QColorSpace::TransformModel::ThreeComponentMatrix;
- colorspaceDPtr->primaries = QColorSpace::Primaries::Custom;
- if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromSRgb()) {
- qCDebug(lcIcc) << "fromIccProfile: sRGB primaries detected";
- colorspaceDPtr->primaries = QColorSpace::Primaries::SRgb;
- } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromAdobeRgb()) {
- qCDebug(lcIcc) << "fromIccProfile: Adobe RGB primaries detected";
- colorspaceDPtr->primaries = QColorSpace::Primaries::AdobeRgb;
- } else if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromDciP3D65()) {
- qCDebug(lcIcc) << "fromIccProfile: DCI-P3 D65 primaries detected";
- colorspaceDPtr->primaries = QColorSpace::Primaries::DciP3D65;
- }
- if (colorspaceDPtr->toXyz == QColorMatrix::toXyzFromProPhotoRgb()) {
- qCDebug(lcIcc) << "fromIccProfile: ProPhoto RGB primaries detected";
- colorspaceDPtr->primaries = QColorSpace::Primaries::ProPhotoRgb;
- }
- } else {
- // We will use sRGB primaries and fit to match the given white-point if
- // it doesn't match sRGB's.
- QColorVector whitePoint;
- if (!parseXyzData(data, tagIndex[Tag::wtpt], whitePoint))
- return false;
- if (!qFuzzyCompare(whitePoint.y, 1.0f) || (1.0f + whitePoint.z + whitePoint.x) == 0.0f) {
- qCWarning(lcIcc) << "fromIccProfile: Invalid ICC profile - gray white-point not normalized";
- return false;
- }
- if (whitePoint == QColorVector::D65()) {
- colorspaceDPtr->primaries = QColorSpace::Primaries::SRgb;
+ if (header.inputColorSpace == uint(ColorSpaceType::Rgb)) {
+ if (!parseRgbMatrix(data, tagIndex, colorspaceDPtr))
+ return false;
+ colorspaceDPtr->colorModel = QColorSpace::ColorModel::Rgb;
+ } else if (header.inputColorSpace == uint(ColorSpaceType::Gray)) {
+ if (!parseGrayMatrix(data, tagIndex, colorspaceDPtr))
+ return false;
+ colorspaceDPtr->colorModel = QColorSpace::ColorModel::Gray;
} else {
- colorspaceDPtr->primaries = QColorSpace::Primaries::Custom;
- // Calculate chromaticity from xyz (assuming y == 1.0f).
- float y = 1.0f / (1.0f + whitePoint.z + whitePoint.x);
- float x = whitePoint.x * y;
- QColorSpacePrimaries primaries(QColorSpace::Primaries::SRgb);
- primaries.whitePoint = QPointF(x,y);
- if (!primaries.areValid()) {
- qCWarning(lcIcc, "fromIccProfile: Invalid ICC profile - invalid white-point(%f, %f)", x, y);
+ Q_UNREACHABLE();
+ }
+ if (auto it = tagIndex.constFind(Tag::chad); it != tagIndex.constEnd()) {
+ if (!parseChad(data, it.value(), colorspaceDPtr))
return false;
- }
- colorspaceDPtr->toXyz = primaries.toXyzMatrix();
+ } else {
+ colorspaceDPtr->chad = QColorMatrix::chromaticAdaptation(colorspaceDPtr->whitePoint);
}
- }
- // Reset the matrix to our canonical values:
- if (colorspaceDPtr->primaries != QColorSpace::Primaries::Custom)
- colorspaceDPtr->setToXyzMatrix();
+ if (colorspaceDPtr->colorModel == QColorSpace::ColorModel::Gray)
+ colorspaceDPtr->toXyz = colorspaceDPtr->chad;
- // Parse TRC tags
- TagEntry rTrc;
- TagEntry gTrc;
- TagEntry bTrc;
- if (header.inputColorSpace == uint(ColorSpaceType::Gray)) {
- rTrc = tagIndex[Tag::kTRC];
- gTrc = tagIndex[Tag::kTRC];
- bTrc = tagIndex[Tag::kTRC];
- } else if (tagIndex.contains(Tag::aarg) && tagIndex.contains(Tag::aagg) && tagIndex.contains(Tag::aabg)) {
- // Apple extension for parametric version of TRCs in ICCv2:
- rTrc = tagIndex[Tag::aarg];
- gTrc = tagIndex[Tag::aagg];
- bTrc = tagIndex[Tag::aabg];
+ // Reset the matrix to our canonical values:
+ if (colorspaceDPtr->primaries != QColorSpace::Primaries::Custom)
+ colorspaceDPtr->setToXyzMatrix();
+
+ if (!parseTRCs(data, tagIndex, colorspaceDPtr, header.inputColorSpace == uint(ColorSpaceType::Gray)))
+ return false;
} else {
- rTrc = tagIndex[Tag::rTRC];
- gTrc = tagIndex[Tag::gTRC];
- bTrc = tagIndex[Tag::bTRC];
- }
+ colorspaceDPtr->isPcsLab = (header.pcs == uint(Tag::Lab_));
+ colorspaceDPtr->transformModel = QColorSpace::TransformModel::ElementListProcessing;
+ if (header.inputColorSpace == uint(ColorSpaceType::Cmyk))
+ colorspaceDPtr->colorModel = QColorSpace::ColorModel::Cmyk;
+ else
+ colorspaceDPtr->colorModel = QColorSpace::ColorModel::Rgb;
- QColorTrc rCurve;
- QColorTrc gCurve;
- QColorTrc bCurve;
- if (!parseTRC(data, rTrc, rCurve)) {
- qCWarning(lcIcc) << "fromIccProfile: Invalid rTRC";
- return false;
- }
- if (!parseTRC(data, gTrc, gCurve)) {
- qCWarning(lcIcc) << "fromIccProfile: Invalid gTRC";
- return false;
- }
- if (!parseTRC(data, bTrc, bCurve)) {
- qCWarning(lcIcc) << "fromIccProfile: Invalid bTRC";
- return false;
- }
- if (rCurve == gCurve && gCurve == bCurve && rCurve.m_type == QColorTrc::Type::Function) {
- if (rCurve.m_fun.isLinear()) {
- qCDebug(lcIcc) << "fromIccProfile: Linear gamma detected";
- colorspaceDPtr->trc[0] = QColorTransferFunction();
- colorspaceDPtr->transferFunction = QColorSpace::TransferFunction::Linear;
- colorspaceDPtr->gamma = 1.0f;
- } else if (rCurve.m_fun.isGamma()) {
- qCDebug(lcIcc) << "fromIccProfile: Simple gamma detected";
- colorspaceDPtr->trc[0] = QColorTransferFunction::fromGamma(rCurve.m_fun.m_g);
- colorspaceDPtr->transferFunction = QColorSpace::TransferFunction::Gamma;
- colorspaceDPtr->gamma = rCurve.m_fun.m_g;
- } else if (rCurve.m_fun.isSRgb()) {
- qCDebug(lcIcc) << "fromIccProfile: sRGB gamma detected";
- colorspaceDPtr->trc[0] = QColorTransferFunction::fromSRgb();
- colorspaceDPtr->transferFunction = QColorSpace::TransferFunction::SRgb;
- } else {
- colorspaceDPtr->trc[0] = rCurve;
- colorspaceDPtr->transferFunction = QColorSpace::TransferFunction::Custom;
+ // Only parse the default perceptual transform for now
+ if (!parseA2B(data, tagIndex[Tag::A2B0], colorspaceDPtr, true))
+ return false;
+ if (auto it = tagIndex.constFind(Tag::B2A0); it != tagIndex.constEnd()) {
+ if (!parseA2B(data, it.value(), colorspaceDPtr, false))
+ return false;
}
- colorspaceDPtr->trc[1] = colorspaceDPtr->trc[0];
- colorspaceDPtr->trc[2] = colorspaceDPtr->trc[0];
- } else {
- colorspaceDPtr->trc[0] = rCurve;
- colorspaceDPtr->trc[1] = gCurve;
- colorspaceDPtr->trc[2] = bCurve;
- colorspaceDPtr->transferFunction = QColorSpace::TransferFunction::Custom;
+ if (auto it = tagIndex.constFind(Tag::wtpt); it != tagIndex.constEnd()) {
+ if (!parseXyzData(data, it.value(), colorspaceDPtr->whitePoint))
+ return false;
+ }
}
- if (tagIndex.contains(Tag::desc)) {
- if (!parseDesc(data, tagIndex[Tag::desc], colorspaceDPtr->description))
+ if (auto it = tagIndex.constFind(Tag::desc); it != tagIndex.constEnd()) {
+ if (!parseDesc(data, it.value(), colorspaceDPtr->description))
qCWarning(lcIcc) << "fromIccProfile: Failed to parse description";
else
qCDebug(lcIcc) << "fromIccProfile: Description" << colorspaceDPtr->description;
@@ -808,6 +1402,7 @@ bool fromIccProfile(const QByteArray &data, QColorSpace *colorSpace)
colorspaceDPtr->iccProfile = data;
+ Q_ASSERT(colorspaceDPtr->isValid());
return true;
}
diff --git a/src/gui/painting/qimageeffects.cpp b/src/gui/painting/qimageeffects.cpp
new file mode 100644
index 0000000000..7c2b947e08
--- /dev/null
+++ b/src/gui/painting/qimageeffects.cpp
@@ -0,0 +1,327 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qmath.h"
+#include "qdrawhelper_p.h"
+#include "qmemrotate_p.h"
+#include "qpainter.h"
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+
+template <int shift>
+inline int qt_static_shift(int value)
+{
+ if (shift == 0)
+ return value;
+ else if (shift > 0)
+ return value << (uint(shift) & 0x1f);
+ else
+ return value >> (uint(-shift) & 0x1f);
+}
+
+template<int aprec, int zprec>
+inline void qt_blurinner(uchar *bptr, int &zR, int &zG, int &zB, int &zA, int alpha)
+{
+ QRgb *pixel = (QRgb *)bptr;
+
+#define Z_MASK (0xff << zprec)
+ const int A_zprec = qt_static_shift<zprec - 24>(*pixel) & Z_MASK;
+ const int R_zprec = qt_static_shift<zprec - 16>(*pixel) & Z_MASK;
+ const int G_zprec = qt_static_shift<zprec - 8>(*pixel) & Z_MASK;
+ const int B_zprec = qt_static_shift<zprec>(*pixel) & Z_MASK;
+#undef Z_MASK
+
+ const int zR_zprec = zR >> aprec;
+ const int zG_zprec = zG >> aprec;
+ const int zB_zprec = zB >> aprec;
+ const int zA_zprec = zA >> aprec;
+
+ zR += alpha * (R_zprec - zR_zprec);
+ zG += alpha * (G_zprec - zG_zprec);
+ zB += alpha * (B_zprec - zB_zprec);
+ zA += alpha * (A_zprec - zA_zprec);
+
+#define ZA_MASK (0xff << (zprec + aprec))
+ *pixel =
+ qt_static_shift<24 - zprec - aprec>(zA & ZA_MASK)
+ | qt_static_shift<16 - zprec - aprec>(zR & ZA_MASK)
+ | qt_static_shift<8 - zprec - aprec>(zG & ZA_MASK)
+ | qt_static_shift<-zprec - aprec>(zB & ZA_MASK);
+#undef ZA_MASK
+}
+
+const int alphaIndex = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3);
+
+template<int aprec, int zprec>
+inline void qt_blurinner_alphaOnly(uchar *bptr, int &z, int alpha)
+{
+ const int A_zprec = int(*(bptr)) << zprec;
+ const int z_zprec = z >> aprec;
+ z += alpha * (A_zprec - z_zprec);
+ *(bptr) = z >> (zprec + aprec);
+}
+
+template<int aprec, int zprec, bool alphaOnly>
+inline void qt_blurrow(QImage & im, int line, int alpha)
+{
+ uchar *bptr = im.scanLine(line);
+
+ int zR = 0, zG = 0, zB = 0, zA = 0;
+
+ if (alphaOnly && im.format() != QImage::Format_Indexed8)
+ bptr += alphaIndex;
+
+ const int stride = im.depth() >> 3;
+ const int im_width = im.width();
+ for (int index = 0; index < im_width; ++index) {
+ if (alphaOnly)
+ qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
+ else
+ qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
+ bptr += stride;
+ }
+
+ bptr -= stride;
+
+ for (int index = im_width - 2; index >= 0; --index) {
+ bptr -= stride;
+ if (alphaOnly)
+ qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
+ else
+ qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
+ }
+}
+
+/*
+* expblur(QImage &img, int radius)
+*
+* Based on exponential blur algorithm by Jani Huhtanen
+*
+* In-place blur of image 'img' with kernel
+* of approximate radius 'radius'.
+*
+* Blurs with two sided exponential impulse
+* response.
+*
+* aprec = precision of alpha parameter
+* in fixed-point format 0.aprec
+*
+* zprec = precision of state parameters
+* zR,zG,zB and zA in fp format 8.zprec
+*/
+template <int aprec, int zprec, bool alphaOnly>
+void expblur(QImage &img, qreal radius, bool improvedQuality = false, int transposed = 0)
+{
+ // halve the radius if we're using two passes
+ if (improvedQuality)
+ radius *= qreal(0.5);
+
+ Q_ASSERT(img.format() == QImage::Format_ARGB32_Premultiplied
+ || img.format() == QImage::Format_RGB32
+ || img.format() == QImage::Format_Indexed8
+ || img.format() == QImage::Format_Grayscale8);
+
+ // choose the alpha such that pixels at radius distance from a fully
+ // saturated pixel will have an alpha component of no greater than
+ // the cutOffIntensity
+ const qreal cutOffIntensity = 2;
+ int alpha = radius <= qreal(1e-5)
+ ? ((1 << aprec)-1)
+ : qRound((1<<aprec)*(1 - qPow(cutOffIntensity * (1 / qreal(255)), 1 / radius)));
+
+ int img_height = img.height();
+ for (int row = 0; row < img_height; ++row) {
+ for (int i = 0; i <= int(improvedQuality); ++i)
+ qt_blurrow<aprec, zprec, alphaOnly>(img, row, alpha);
+ }
+
+ QImage temp(img.height(), img.width(), img.format());
+ temp.setDevicePixelRatio(img.devicePixelRatio());
+ if (transposed >= 0) {
+ if (img.depth() == 8) {
+ qt_memrotate270(reinterpret_cast<const quint8*>(img.bits()),
+ img.width(), img.height(), img.bytesPerLine(),
+ reinterpret_cast<quint8*>(temp.bits()),
+ temp.bytesPerLine());
+ } else {
+ qt_memrotate270(reinterpret_cast<const quint32*>(img.bits()),
+ img.width(), img.height(), img.bytesPerLine(),
+ reinterpret_cast<quint32*>(temp.bits()),
+ temp.bytesPerLine());
+ }
+ } else {
+ if (img.depth() == 8) {
+ qt_memrotate90(reinterpret_cast<const quint8*>(img.bits()),
+ img.width(), img.height(), img.bytesPerLine(),
+ reinterpret_cast<quint8*>(temp.bits()),
+ temp.bytesPerLine());
+ } else {
+ qt_memrotate90(reinterpret_cast<const quint32*>(img.bits()),
+ img.width(), img.height(), img.bytesPerLine(),
+ reinterpret_cast<quint32*>(temp.bits()),
+ temp.bytesPerLine());
+ }
+ }
+
+ img_height = temp.height();
+ for (int row = 0; row < img_height; ++row) {
+ for (int i = 0; i <= int(improvedQuality); ++i)
+ qt_blurrow<aprec, zprec, alphaOnly>(temp, row, alpha);
+ }
+
+ if (transposed == 0) {
+ if (img.depth() == 8) {
+ qt_memrotate90(reinterpret_cast<const quint8*>(temp.bits()),
+ temp.width(), temp.height(), temp.bytesPerLine(),
+ reinterpret_cast<quint8*>(img.bits()),
+ img.bytesPerLine());
+ } else {
+ qt_memrotate90(reinterpret_cast<const quint32*>(temp.bits()),
+ temp.width(), temp.height(), temp.bytesPerLine(),
+ reinterpret_cast<quint32*>(img.bits()),
+ img.bytesPerLine());
+ }
+ } else {
+ img = temp;
+ }
+}
+
+} // namespace
+
+#define AVG(a,b) ( ((((a)^(b)) & 0xfefefefeUL) >> 1) + ((a)&(b)) )
+#define AVG16(a,b) ( ((((a)^(b)) & 0xf7deUL) >> 1) + ((a)&(b)) )
+
+QImage qt_halfScaled(const QImage &source)
+{
+ if (source.width() < 2 || source.height() < 2)
+ return QImage();
+
+ QImage srcImage = source;
+
+ if (source.format() == QImage::Format_Indexed8 || source.format() == QImage::Format_Grayscale8) {
+ // assumes grayscale
+ QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
+ dest.setDevicePixelRatio(source.devicePixelRatio());
+
+ const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits());
+ qsizetype sx = srcImage.bytesPerLine();
+ qsizetype sx2 = sx << 1;
+
+ uchar *dst = reinterpret_cast<uchar*>(dest.bits());
+ qsizetype dx = dest.bytesPerLine();
+ int ww = dest.width();
+ int hh = dest.height();
+
+ for (int y = hh; y; --y, dst += dx, src += sx2) {
+ const uchar *p1 = src;
+ const uchar *p2 = src + sx;
+ uchar *q = dst;
+ for (int x = ww; x; --x, ++q, p1 += 2, p2 += 2)
+ *q = ((int(p1[0]) + int(p1[1]) + int(p2[0]) + int(p2[1])) + 2) >> 2;
+ }
+
+ return dest;
+ } else if (source.format() == QImage::Format_ARGB8565_Premultiplied) {
+ QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
+ dest.setDevicePixelRatio(source.devicePixelRatio());
+
+ const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits());
+ qsizetype sx = srcImage.bytesPerLine();
+ qsizetype sx2 = sx << 1;
+
+ uchar *dst = reinterpret_cast<uchar*>(dest.bits());
+ qsizetype dx = dest.bytesPerLine();
+ int ww = dest.width();
+ int hh = dest.height();
+
+ for (int y = hh; y; --y, dst += dx, src += sx2) {
+ const uchar *p1 = src;
+ const uchar *p2 = src + sx;
+ uchar *q = dst;
+ for (int x = ww; x; --x, q += 3, p1 += 6, p2 += 6) {
+ // alpha
+ q[0] = AVG(AVG(p1[0], p1[3]), AVG(p2[0], p2[3]));
+ // rgb
+ const quint16 p16_1 = (p1[2] << 8) | p1[1];
+ const quint16 p16_2 = (p1[5] << 8) | p1[4];
+ const quint16 p16_3 = (p2[2] << 8) | p2[1];
+ const quint16 p16_4 = (p2[5] << 8) | p2[4];
+ const quint16 result = AVG16(AVG16(p16_1, p16_2), AVG16(p16_3, p16_4));
+ q[1] = result & 0xff;
+ q[2] = result >> 8;
+ }
+ }
+
+ return dest;
+ } else if (source.format() != QImage::Format_ARGB32_Premultiplied
+ && source.format() != QImage::Format_RGB32)
+ {
+ srcImage = source.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ }
+
+ QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
+ dest.setDevicePixelRatio(source.devicePixelRatio());
+
+ const quint32 *src = reinterpret_cast<const quint32*>(const_cast<const QImage &>(srcImage).bits());
+ qsizetype sx = srcImage.bytesPerLine() >> 2;
+ qsizetype sx2 = sx << 1;
+
+ quint32 *dst = reinterpret_cast<quint32*>(dest.bits());
+ qsizetype dx = dest.bytesPerLine() >> 2;
+ int ww = dest.width();
+ int hh = dest.height();
+
+ for (int y = hh; y; --y, dst += dx, src += sx2) {
+ const quint32 *p1 = src;
+ const quint32 *p2 = src + sx;
+ quint32 *q = dst;
+ for (int x = ww; x; --x, q++, p1 += 2, p2 += 2)
+ *q = AVG(AVG(p1[0], p1[1]), AVG(p2[0], p2[1]));
+ }
+
+ return dest;
+}
+
+#undef AVG
+#undef AVG16
+
+Q_GUI_EXPORT void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0)
+{
+ if (blurImage.format() != QImage::Format_ARGB32_Premultiplied
+ && blurImage.format() != QImage::Format_RGB32)
+ {
+ blurImage = std::move(blurImage).convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ }
+
+ qreal scale = 1;
+ if (radius >= 4 && blurImage.width() >= 2 && blurImage.height() >= 2) {
+ blurImage = qt_halfScaled(blurImage);
+ scale = 2;
+ radius *= qreal(0.5);
+ }
+
+ if (alphaOnly)
+ expblur<12, 10, true>(blurImage, radius, quality, transposed);
+ else
+ expblur<12, 10, false>(blurImage, radius, quality, transposed);
+
+ if (p) {
+ p->scale(scale, scale);
+ p->setRenderHint(QPainter::SmoothPixmapTransform);
+ p->drawImage(QRect(QPoint(0, 0), blurImage.deviceIndependentSize().toSize()), blurImage);
+ }
+}
+
+Q_GUI_EXPORT void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0)
+{
+ if (blurImage.format() == QImage::Format_Indexed8 || blurImage.format() == QImage::Format_Grayscale8)
+ expblur<12, 10, true>(blurImage, radius, quality, transposed);
+ else
+ expblur<12, 10, false>(blurImage, radius, quality, transposed);
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/painting/qoutlinemapper.cpp b/src/gui/painting/qoutlinemapper.cpp
index 93eac5cced..2f87ff43b7 100644
--- a/src/gui/painting/qoutlinemapper.cpp
+++ b/src/gui/painting/qoutlinemapper.cpp
@@ -50,7 +50,7 @@ void QOutlineMapper::setClipRect(QRect clipRect)
if (clipRect != m_clip_rect) {
m_clip_rect = limitCoords(clipRect);
- const int mw = 64; // margin width. No need to trigger clipping for slight overshooting
+ const int mw = 1 << 10; // margin width. No need to trigger clipping for slight overshooting
m_clip_trigger_rect = QRectF(limitCoords(m_clip_rect.adjusted(-mw, -mw, mw, mw)));
}
}
diff --git a/src/gui/painting/qpagelayout.cpp b/src/gui/painting/qpagelayout.cpp
index 456fcf8802..e60f464d6e 100644
--- a/src/gui/painting/qpagelayout.cpp
+++ b/src/gui/painting/qpagelayout.cpp
@@ -39,41 +39,19 @@ Q_GUI_EXPORT qreal qt_pointMultiplier(QPageLayout::Unit unit)
// Multiplier for converting pixels to points.
extern qreal qt_pixelMultiplier(int resolution);
-QPointF qt_convertPoint(const QPointF &xy, QPageLayout::Unit fromUnits, QPageLayout::Unit toUnits)
-{
- // If the size have the same units, or are all 0, then don't need to convert
- if (fromUnits == toUnits || xy.isNull())
- return xy;
-
- // If converting to points then convert and round to 0 decimal places
- if (toUnits == QPageLayout::Point) {
- const qreal multiplier = qt_pointMultiplier(fromUnits);
- return QPointF(qRound(xy.x() * multiplier),
- qRound(xy.y() * multiplier));
- }
-
- // If converting to other units, need to convert to unrounded points first
- QPointF pointXy = (fromUnits == QPageLayout::Point) ? xy : xy * qt_pointMultiplier(fromUnits);
-
- // Then convert from points to required units rounded to 2 decimal places
- const qreal multiplier = qt_pointMultiplier(toUnits);
- return QPointF(qRound(pointXy.x() * 100 / multiplier) / 100.0,
- qRound(pointXy.y() * 100 / multiplier) / 100.0);
-}
-
Q_GUI_EXPORT QMarginsF qt_convertMargins(const QMarginsF &margins, QPageLayout::Unit fromUnits, QPageLayout::Unit toUnits)
{
// If the margins have the same units, or are all 0, then don't need to convert
if (fromUnits == toUnits || margins.isNull())
return margins;
- // If converting to points then convert and round to 0 decimal places
+ // If converting to points then convert and round up to 2 decimal places
if (toUnits == QPageLayout::Point) {
- const qreal multiplier = qt_pointMultiplier(fromUnits);
- return QMarginsF(qRound(margins.left() * multiplier),
- qRound(margins.top() * multiplier),
- qRound(margins.right() * multiplier),
- qRound(margins.bottom() * multiplier));
+ const qreal multiplierX100 = qt_pointMultiplier(fromUnits) * 100;
+ return QMarginsF(qCeil(margins.left() * multiplierX100) / 100.0,
+ qCeil(margins.top() * multiplierX100) / 100.0,
+ qCeil(margins.right() * multiplierX100) / 100.0,
+ qCeil(margins.bottom() * multiplierX100) / 100.0);
}
// If converting to other units, need to convert to unrounded points first
@@ -101,10 +79,10 @@ public:
bool isValid() const;
- void clampMargins(const QMarginsF &margins);
+ QMarginsF clampMargins(const QMarginsF &margins) const;
QMarginsF margins(QPageLayout::Unit units) const;
- QMargins marginsPoints() const;
+ QMarginsF marginsPoints() const;
QMargins marginsPixels(int resolution) const;
void setDefaultMargins(const QMarginsF &minMargins);
@@ -173,12 +151,12 @@ bool QPageLayoutPrivate::isValid() const
return m_pageSize.isValid();
}
-void QPageLayoutPrivate::clampMargins(const QMarginsF &margins)
+QMarginsF QPageLayoutPrivate::clampMargins(const QMarginsF &margins) const
{
- m_margins = QMarginsF(qBound(m_minMargins.left(), margins.left(), m_maxMargins.left()),
- qBound(m_minMargins.top(), margins.top(), m_maxMargins.top()),
- qBound(m_minMargins.right(), margins.right(), m_maxMargins.right()),
- qBound(m_minMargins.bottom(), margins.bottom(), m_maxMargins.bottom()));
+ return QMarginsF(qBound(m_minMargins.left(), margins.left(), m_maxMargins.left()),
+ qBound(m_minMargins.top(), margins.top(), m_maxMargins.top()),
+ qBound(m_minMargins.right(), margins.right(), m_maxMargins.right()),
+ qBound(m_minMargins.bottom(), margins.bottom(), m_maxMargins.bottom()));
}
QMarginsF QPageLayoutPrivate::margins(QPageLayout::Unit units) const
@@ -186,14 +164,14 @@ QMarginsF QPageLayoutPrivate::margins(QPageLayout::Unit units) const
return qt_convertMargins(m_margins, m_units, units);
}
-QMargins QPageLayoutPrivate::marginsPoints() const
+QMarginsF QPageLayoutPrivate::marginsPoints() const
{
- return qt_convertMargins(m_margins, m_units, QPageLayout::Point).toMargins();
+ return qt_convertMargins(m_margins, m_units, QPageLayout::Point);
}
QMargins QPageLayoutPrivate::marginsPixels(int resolution) const
{
- return marginsPoints() / qt_pixelMultiplier(resolution);
+ return QMarginsF(marginsPoints() / qt_pixelMultiplier(resolution)).toMargins();
}
void QPageLayoutPrivate::setDefaultMargins(const QMarginsF &minMargins)
@@ -204,7 +182,7 @@ void QPageLayoutPrivate::setDefaultMargins(const QMarginsF &minMargins)
qMax(m_fullSize.width() - m_minMargins.left(), qreal(0)),
qMax(m_fullSize.height() - m_minMargins.top(), qreal(0)));
if (m_mode == QPageLayout::StandardMode)
- clampMargins(m_margins);
+ m_margins = clampMargins(m_margins);
}
QSizeF QPageLayoutPrivate::fullSizeUnits(QPageLayout::Unit units) const
@@ -310,6 +288,27 @@ QRectF QPageLayoutPrivate::paintRect() const
\value StandardMode Paint Rect includes margins, margins must fall between the minimum and maximum.
\value FullPageMode Paint Rect excludes margins, margins can be any value and must be managed manually.
+
+ In StandardMode, when setting margins, use \l{QPageLayout::OutOfBoundsPolicy::}{Clamp} to
+ automatically clamp the margins to fall between the minimum and maximum
+ allowed values.
+
+ \sa OutOfBoundsPolicy
+*/
+
+/*!
+ \enum QPageLayout::OutOfBoundsPolicy
+ \since 6.8
+
+ Defines the policy for margins that are out of bounds
+
+ \value Reject The margins must fall within the minimum and maximum values,
+ otherwise they will be rejected.
+ \value Clamp The margins are clamped between the minimum and maximum
+ values to ensure they are valid.
+
+ \note The policy has no effect in \l{QPageLayout::Mode}{FullPageMode},
+ where all margins are accepted.
*/
/*!
@@ -547,39 +546,52 @@ QPageLayout::Unit QPageLayout::units() const
}
/*!
- Sets the page margins of the page layout to \a margins
+ Sets the page margins of the page layout to \a margins.
Returns true if the margins were successfully set.
The units used are those currently defined for the layout. To use different
units then call setUnits() first.
- If in the default StandardMode then all the new margins must fall between the
- minimum margins set and the maximum margins allowed by the page size,
- otherwise the margins will not be set.
-
- If in FullPageMode then any margin values will be accepted.
+ Since Qt 6.8, the optional \a outOfBoundsPolicy can be used to specify how
+ margins that are out of bounds are handled.
\sa margins(), units()
*/
-bool QPageLayout::setMargins(const QMarginsF &margins)
+bool QPageLayout::setMargins(const QMarginsF &margins, OutOfBoundsPolicy outOfBoundsPolicy)
{
if (d->m_mode == FullPageMode) {
- d.detach();
- d->m_margins = margins;
+ if (margins != d->m_margins) {
+ d.detach();
+ d->m_margins = margins;
+ }
return true;
- } else if (margins.left() >= d->m_minMargins.left()
- && margins.right() >= d->m_minMargins.right()
- && margins.top() >= d->m_minMargins.top()
- && margins.bottom() >= d->m_minMargins.bottom()
- && margins.left() <= d->m_maxMargins.left()
- && margins.right() <= d->m_maxMargins.right()
- && margins.top() <= d->m_maxMargins.top()
- && margins.bottom() <= d->m_maxMargins.bottom()) {
- d.detach();
- d->m_margins = margins;
+ }
+
+ if (outOfBoundsPolicy == OutOfBoundsPolicy::Clamp) {
+ const QMarginsF clampedMargins = d->clampMargins(margins);
+ if (clampedMargins != d->m_margins) {
+ d.detach();
+ d->m_margins = clampedMargins;
+ }
return true;
}
+
+ if (margins.left() >= d->m_minMargins.left()
+ && margins.right() >= d->m_minMargins.right()
+ && margins.top() >= d->m_minMargins.top()
+ && margins.bottom() >= d->m_minMargins.bottom()
+ && margins.left() <= d->m_maxMargins.left()
+ && margins.right() <= d->m_maxMargins.right()
+ && margins.top() <= d->m_maxMargins.top()
+ && margins.bottom() <= d->m_maxMargins.bottom()) {
+ if (margins != d->m_margins) {
+ d.detach();
+ d->m_margins = margins;
+ }
+ return true;
+ }
+
return false;
}
@@ -590,23 +602,27 @@ bool QPageLayout::setMargins(const QMarginsF &margins)
The units used are those currently defined for the layout. To use different
units call setUnits() first.
- If in the default StandardMode then the new margin must fall between the
- minimum margin set and the maximum margin allowed by the page size,
- otherwise the margin will not be set.
-
- If in FullPageMode then any margin values will be accepted.
+ Since Qt 6.8, the optional \a outOfBoundsPolicy can be used to specify how
+ margins that are out of bounds are handled.
\sa setMargins(), margins()
*/
-bool QPageLayout::setLeftMargin(qreal leftMargin)
+bool QPageLayout::setLeftMargin(qreal leftMargin, OutOfBoundsPolicy outOfBoundsPolicy)
{
+ if (d->m_mode == StandardMode && outOfBoundsPolicy == OutOfBoundsPolicy::Clamp)
+ leftMargin = qBound(d->m_minMargins.left(), leftMargin, d->m_maxMargins.left());
+
+ if (qFuzzyCompare(leftMargin, d->m_margins.left()))
+ return true;
+
if (d->m_mode == FullPageMode
|| (leftMargin >= d->m_minMargins.left() && leftMargin <= d->m_maxMargins.left())) {
d.detach();
d->m_margins.setLeft(leftMargin);
return true;
}
+
return false;
}
@@ -617,23 +633,27 @@ bool QPageLayout::setLeftMargin(qreal leftMargin)
The units used are those currently defined for the layout. To use different
units call setUnits() first.
- If in the default StandardMode then the new margin must fall between the
- minimum margin set and the maximum margin allowed by the page size,
- otherwise the margin will not be set.
-
- If in FullPageMode then any margin values will be accepted.
+ Since Qt 6.8, the optional \a outOfBoundsPolicy can be used to specify how
+ margins that are out of bounds are handled.
\sa setMargins(), margins()
*/
-bool QPageLayout::setRightMargin(qreal rightMargin)
+bool QPageLayout::setRightMargin(qreal rightMargin, OutOfBoundsPolicy outOfBoundsPolicy)
{
+ if (d->m_mode == StandardMode && outOfBoundsPolicy == OutOfBoundsPolicy::Clamp)
+ rightMargin = qBound(d->m_minMargins.right(), rightMargin, d->m_maxMargins.right());
+
+ if (qFuzzyCompare(rightMargin, d->m_margins.right()))
+ return true;
+
if (d->m_mode == FullPageMode
|| (rightMargin >= d->m_minMargins.right() && rightMargin <= d->m_maxMargins.right())) {
d.detach();
d->m_margins.setRight(rightMargin);
return true;
}
+
return false;
}
@@ -644,23 +664,27 @@ bool QPageLayout::setRightMargin(qreal rightMargin)
The units used are those currently defined for the layout. To use different
units call setUnits() first.
- If in the default StandardMode then the new margin must fall between the
- minimum margin set and the maximum margin allowed by the page size,
- otherwise the margin will not be set.
-
- If in FullPageMode then any margin values will be accepted.
+ Since Qt 6.8, the optional \a outOfBoundsPolicy can be used to specify how
+ margins that are out of bounds are handled.
\sa setMargins(), margins()
*/
-bool QPageLayout::setTopMargin(qreal topMargin)
+bool QPageLayout::setTopMargin(qreal topMargin, OutOfBoundsPolicy outOfBoundsPolicy)
{
+ if (d->m_mode == StandardMode && outOfBoundsPolicy == OutOfBoundsPolicy::Clamp)
+ topMargin = qBound(d->m_minMargins.top(), topMargin, d->m_maxMargins.top());
+
+ if (qFuzzyCompare(topMargin, d->m_margins.top()))
+ return true;
+
if (d->m_mode == FullPageMode
|| (topMargin >= d->m_minMargins.top() && topMargin <= d->m_maxMargins.top())) {
d.detach();
d->m_margins.setTop(topMargin);
return true;
}
+
return false;
}
@@ -671,23 +695,27 @@ bool QPageLayout::setTopMargin(qreal topMargin)
The units used are those currently defined for the layout. To use different
units call setUnits() first.
- If in the default StandardMode then the new margin must fall between the
- minimum margin set and the maximum margin allowed by the page size,
- otherwise the margin will not be set.
-
- If in FullPageMode then any margin values will be accepted.
+ Since Qt 6.8, the optional \a outOfBoundsPolicy can be used to specify how
+ margins that are out of bounds are handled.
\sa setMargins(), margins()
*/
-bool QPageLayout::setBottomMargin(qreal bottomMargin)
+bool QPageLayout::setBottomMargin(qreal bottomMargin, OutOfBoundsPolicy outOfBoundsPolicy)
{
+ if (d->m_mode == StandardMode && outOfBoundsPolicy == OutOfBoundsPolicy::Clamp)
+ bottomMargin = qBound(d->m_minMargins.bottom(), bottomMargin, d->m_maxMargins.bottom());
+
+ if (qFuzzyCompare(bottomMargin, d->m_margins.bottom()))
+ return true;
+
if (d->m_mode == FullPageMode
|| (bottomMargin >= d->m_minMargins.bottom() && bottomMargin <= d->m_maxMargins.bottom())) {
d.detach();
d->m_margins.setBottom(bottomMargin);
return true;
}
+
return false;
}
@@ -721,7 +749,7 @@ QMarginsF QPageLayout::margins(Unit units) const
QMargins QPageLayout::marginsPoints() const
{
- return d->marginsPoints();
+ return d->marginsPoints().toMargins();
}
/*!
@@ -888,7 +916,7 @@ QRect QPageLayout::paintRectPoints() const
if (!isValid())
return QRect();
return d->m_mode == FullPageMode ? d->fullRectPoints()
- : d->fullRectPoints() - d->marginsPoints();
+ : d->fullRectPoints() - d->marginsPoints().toMargins();
}
/*!
diff --git a/src/gui/painting/qpagelayout.h b/src/gui/painting/qpagelayout.h
index 29be2f9725..1e340b6d75 100644
--- a/src/gui/painting/qpagelayout.h
+++ b/src/gui/painting/qpagelayout.h
@@ -40,6 +40,11 @@ public:
FullPageMode // Paint Rect excludes margins
};
+ enum class OutOfBoundsPolicy {
+ Reject,
+ Clamp
+ };
+
QPageLayout();
QPageLayout(const QPageSize &pageSize, Orientation orientation,
const QMarginsF &margins, Unit units = Point,
@@ -68,11 +73,19 @@ public:
void setUnits(Unit units);
Unit units() const;
+#if QT_GUI_REMOVED_SINCE(6, 8)
bool setMargins(const QMarginsF &margins);
bool setLeftMargin(qreal leftMargin);
bool setRightMargin(qreal rightMargin);
bool setTopMargin(qreal topMargin);
bool setBottomMargin(qreal bottomMargin);
+#endif
+
+ bool setMargins(const QMarginsF &margins, OutOfBoundsPolicy outOfBoundsPolicy = OutOfBoundsPolicy::Reject);
+ bool setLeftMargin(qreal leftMargin, OutOfBoundsPolicy outOfBoundsPolicy = OutOfBoundsPolicy::Reject);
+ bool setRightMargin(qreal rightMargin, OutOfBoundsPolicy outOfBoundsPolicy = OutOfBoundsPolicy::Reject);
+ bool setTopMargin(qreal topMargin, OutOfBoundsPolicy outOfBoundsPolicy = OutOfBoundsPolicy::Reject);
+ bool setBottomMargin(qreal bottomMargin, OutOfBoundsPolicy outOfBoundsPolicy = OutOfBoundsPolicy::Reject);
QMarginsF margins() const;
QMarginsF margins(Unit units) const;
diff --git a/src/gui/painting/qpageranges.cpp b/src/gui/painting/qpageranges.cpp
index 500673b22f..99a0009883 100644
--- a/src/gui/painting/qpageranges.cpp
+++ b/src/gui/painting/qpageranges.cpp
@@ -255,7 +255,7 @@ int QPageRanges::firstPage() const
{
if (isEmpty())
return 0;
- return d->intervals.first().from;
+ return d->intervals.constFirst().from;
}
/*!
@@ -266,7 +266,7 @@ int QPageRanges::lastPage() const
{
if (isEmpty())
return 0;
- return d->intervals.last().to;
+ return d->intervals.constLast().to;
}
/*!
diff --git a/src/gui/painting/qpagesize.cpp b/src/gui/painting/qpagesize.cpp
index 3ed633bf99..37f66fe63d 100644
--- a/src/gui/painting/qpagesize.cpp
+++ b/src/gui/painting/qpagesize.cpp
@@ -543,7 +543,7 @@ static QSize qt_convertPointsToPixels(const QSize &size, int resolution)
if (!size.isValid() || resolution <= 0)
return QSize();
const qreal multiplier = qt_pixelMultiplier(resolution);
- return QSize(qRound(size.width() / multiplier), qRound(size.height() / multiplier));
+ return QSize(qFloor(size.width() / multiplier), qFloor(size.height() / multiplier));
}
static QSizeF qt_convertPointsToUnits(const QSize &size, QPageSize::Unit units)
@@ -869,7 +869,7 @@ QSizeF QPageSizePrivate::size(QPageSize::Unit units) const
QSize QPageSizePrivate::sizePixels(int resolution) const
{
- return qt_convertPointsToPixels(m_pointSize, resolution);;
+ return qt_convertPointsToPixels(m_pointSize, resolution);
}
diff --git a/src/gui/painting/qpagesize.h b/src/gui/painting/qpagesize.h
index b3629bb8d2..221863aad7 100644
--- a/src/gui/painting/qpagesize.h
+++ b/src/gui/painting/qpagesize.h
@@ -203,7 +203,9 @@ public:
void swap(QPageSize &other) noexcept { d.swap(other.d); }
+#if QT_GUI_REMOVED_SINCE(6, 4)
friend Q_GUI_EXPORT bool operator==(const QPageSize &lhs, const QPageSize &rhs);
+#endif
bool isEquivalentTo(const QPageSize &other) const;
bool isValid() const;
diff --git a/src/gui/painting/qpaintengine.cpp b/src/gui/painting/qpaintengine.cpp
index 839be3bd41..aface3744d 100644
--- a/src/gui/painting/qpaintengine.cpp
+++ b/src/gui/painting/qpaintengine.cpp
@@ -481,6 +481,8 @@ void QPaintEngine::drawEllipse(const QRectF &rect)
}
/*!
+ \overload
+
The default implementation of this function calls the floating
point version of this function
*/
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index ac9af070f1..f62373d4ef 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -240,8 +240,7 @@ QRasterPaintEnginePrivate::QRasterPaintEnginePrivate() :
/*!
\class QRasterPaintEngine
- \preliminary
- \ingroup qws
+ \internal
\inmodule QtGui
\since 4.2
@@ -2262,7 +2261,7 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
|| d->rasterBuffer->compositionMode == QPainter::CompositionMode_Source))
{
RotationType rotationType = qRotationType(s->matrix);
- Q_ASSUME(d->rasterBuffer->format < QImage::NImageFormats);
+ Q_ASSERT(d->rasterBuffer->format < QImage::NImageFormats);
const QPixelLayout::BPP plBpp = qPixelLayouts[d->rasterBuffer->format].bpp;
if (rotationType != NoRotation && qMemRotateFunctions[plBpp][rotationType] && img.rect().contains(sr.toAlignedRect())) {
@@ -2343,9 +2342,16 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
}
SrcOverScaleFunc func = qScaleFunctions[d->rasterBuffer->format][img.format()];
if (func && (!clip || clip->hasRectClip)) {
+ QRectF tr = qt_mapRect_non_normalizing(r, s->matrix);
+ if (!s->flags.antialiased) {
+ tr.setX(qRound(tr.x()));
+ tr.setY(qRound(tr.y()));
+ tr.setWidth(qRound(tr.width()));
+ tr.setHeight(qRound(tr.height()));
+ }
func(d->rasterBuffer->buffer(), d->rasterBuffer->bytesPerLine(),
img.bits(), img.bytesPerLine(), img.height(),
- qt_mapRect_non_normalizing(r, s->matrix), sr,
+ tr, sr,
!clip ? d->deviceRect : clip->clipRect,
s->intOpacity);
return;
@@ -3391,16 +3397,18 @@ void QRasterPaintEngine::drawBitmap(const QPointF &pos, const QImage &image, QSp
// Boundaries
int w = image.width();
int h = image.height();
- int ymax = qMin(qRound(pos.y() + h), d->rasterBuffer->height());
- int ymin = qMax(qRound(pos.y()), 0);
- int xmax = qMin(qRound(pos.x() + w), d->rasterBuffer->width());
- int xmin = qMax(qRound(pos.x()), 0);
+ int px = qRound(pos.x());
+ int py = qRound(pos.y());
+ int ymax = qMin(py + h, d->rasterBuffer->height());
+ int ymin = qMax(py, 0);
+ int xmax = qMin(px + w, d->rasterBuffer->width());
+ int xmin = qMax(px, 0);
- int x_offset = xmin - qRound(pos.x());
+ int x_offset = xmin - px;
QImage::Format format = image.format();
for (int y = ymin; y < ymax; ++y) {
- const uchar *src = image.scanLine(y - qRound(pos.y()));
+ const uchar *src = image.scanLine(y - py);
if (format == QImage::Format_MonoLSB) {
for (int x = 0; x < xmax - xmin; ++x) {
int src_x = x + x_offset;
@@ -3705,15 +3713,9 @@ bool QRasterPaintEnginePrivate::canUseImageBlitting(QPainter::CompositionMode mo
QImage::Format dFormat = rasterBuffer->format;
QImage::Format sFormat = image.format();
- // Formats must match or source format must be a subset of destination format
- if (dFormat != sFormat && image.pixelFormat().alphaUsage() == QPixelFormat::IgnoresAlpha) {
- if ((sFormat == QImage::Format_RGB32 && dFormat == QImage::Format_ARGB32)
- || (sFormat == QImage::Format_RGBX8888 && dFormat == QImage::Format_RGBA8888)
- || (sFormat == QImage::Format_RGBX64 && dFormat == QImage::Format_RGBA64))
- sFormat = dFormat;
- else
- sFormat = qt_maybeAlphaVersionWithSameDepth(sFormat); // this returns premul formats
- }
+ // Formats must match or source format must be an opaque version of destination format
+ if (dFormat != sFormat && image.pixelFormat().alphaUsage() == QPixelFormat::IgnoresAlpha)
+ dFormat = qt_maybeDataCompatibleOpaqueVersion(dFormat);
return (dFormat == sFormat);
}
@@ -3800,7 +3802,7 @@ void QClipData::initialize()
return;
if (!m_clipLines)
- m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight);
+ m_clipLines = (ClipLine *)calloc(clipSpanHeight, sizeof(ClipLine));
Q_CHECK_PTR(m_clipLines);
QT_TRY {
diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp
index 7f1c7e356d..9468876c23 100644
--- a/src/gui/painting/qpaintengineex.cpp
+++ b/src/gui/painting/qpaintengineex.cpp
@@ -902,7 +902,7 @@ void QPaintEngineEx::drawPoints(const QPoint *points, int pointCount)
void QPaintEngineEx::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
{
- Q_ASSUME(pointCount >= 2);
+ Q_ASSERT(pointCount >= 2);
QVectorPath path((const qreal *) points, pointCount, nullptr, QVectorPath::polygonFlags(mode));
if (mode == PolylineMode)
@@ -913,7 +913,7 @@ void QPaintEngineEx::drawPolygon(const QPointF *points, int pointCount, PolygonD
void QPaintEngineEx::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
{
- Q_ASSUME(pointCount >= 2);
+ Q_ASSERT(pointCount >= 2);
int count = pointCount<<1;
QVarLengthArray<qreal> pts(count);
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index e69f369dbe..f4b9741eed 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -221,7 +221,7 @@ qreal QPainterPrivate::effectiveDevicePixelRatio() const
if (device->devType() == QInternal::Printer)
return qreal(1);
- return qMax(qreal(1), device->devicePixelRatio());
+ return device->devicePixelRatio();
}
QTransform QPainterPrivate::hidpiScaleTransform() const
@@ -1125,24 +1125,22 @@ void QPainterPrivate::updateState(QPainterState *newState)
The QPainter class also provides a means of controlling the
rendering quality through its RenderHint enum and the support for
floating point precision: All the functions for drawing primitives
- has a floating point version. These are often used in combination
+ have floating point versions.
+
+ \snippet code/src_gui_painting_qpainter.cpp floatBased
+
+ These are often used in combination
with the \l {RenderHint}{QPainter::Antialiasing} render hint.
+ \snippet code/src_gui_painting_qpainter.cpp renderHint
+
\table 100%
\row
+ \li Comparing concentric circles with int and float, and with or without
+ anti-aliased rendering. Using the floating point precision versions
+ produces evenly spaced rings. Anti-aliased rendering results in
+ smooth circles.
\li \inlineimage qpainter-concentriccircles.png
- \li
- \b {Concentric Circles Example}
-
- The \l {painting/concentriccircles}{Concentric Circles} example
- shows the improved rendering quality that can be obtained using
- floating point precision and anti-aliasing when drawing custom
- widgets.
-
- The application's main window displays several widgets which are
- drawn using the various combinations of precision and
- anti-aliasing.
-
\endtable
The RenderHint enum specifies flags to QPainter that may or may
@@ -1420,7 +1418,7 @@ void QPainterPrivate::updateState(QPainterState *newState)
This value was added in Qt 6.4.
\sa renderHints(), setRenderHint(), {QPainter#Rendering
- Quality}{Rendering Quality}, {Concentric Circles Example}
+ Quality}{Rendering Quality}
*/
@@ -1767,9 +1765,12 @@ bool QPainter::begin(QPaintDevice *pd)
qWarning("QPainter::begin: Cannot paint on a null image");
qt_cleanup_painter_state(d);
return false;
- } else if (img->format() == QImage::Format_Indexed8) {
- // Painting on indexed8 images is not supported.
- qWarning("QPainter::begin: Cannot paint on an image with the QImage::Format_Indexed8 format");
+ } else if (img->format() == QImage::Format_Indexed8 ||
+ img->format() == QImage::Format_CMYK8888) {
+ // Painting on these formats is not supported.
+ qWarning() << "QPainter::begin: Cannot paint on an image with the"
+ << img->format()
+ << "format";
qt_cleanup_painter_state(d);
return false;
}
@@ -1824,7 +1825,7 @@ bool QPainter::begin(QPaintDevice *pd)
Q_ASSERT(d->engine->isActive());
- if (!d->state->redirectionMatrix.isIdentity() || d->effectiveDevicePixelRatio() > 1)
+ if (!d->state->redirectionMatrix.isIdentity() || !qFuzzyCompare(d->effectiveDevicePixelRatio(), qreal(1.0)))
d->updateMatrix();
Q_ASSERT(d->engine->isActive());
@@ -3901,8 +3902,10 @@ void QPainter::drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius,
#endif
Q_D(QPainter);
- if (!d->engine)
+ if (!d->engine) {
+ qWarning("QPainter::drawRoundedRect: Painter not active");
return;
+ }
if (xRadius <= 0 || yRadius <= 0) { // draw normal rectangle
drawRect(rect);
@@ -3963,8 +3966,10 @@ void QPainter::drawEllipse(const QRectF &r)
#endif
Q_D(QPainter);
- if (!d->engine)
+ if (!d->engine) {
+ qWarning("QPainter::drawEllipse: Painter not active");
return;
+ }
QRectF rect(r.normalized());
@@ -4004,8 +4009,10 @@ void QPainter::drawEllipse(const QRect &r)
#endif
Q_D(QPainter);
- if (!d->engine)
+ if (!d->engine) {
+ qWarning("QPainter::drawEllipse: Painter not active");
return;
+ }
QRect rect(r.normalized());
@@ -4091,8 +4098,10 @@ void QPainter::drawArc(const QRectF &r, int a, int alen)
#endif
Q_D(QPainter);
- if (!d->engine)
+ if (!d->engine) {
+ qWarning("QPainter::drawArc: Painter not active");
return;
+ }
QRectF rect = r.normalized();
@@ -4153,8 +4162,10 @@ void QPainter::drawPie(const QRectF &r, int a, int alen)
#endif
Q_D(QPainter);
- if (!d->engine)
+ if (!d->engine) {
+ qWarning("QPainter::drawPie: Painter not active");
return;
+ }
if (a > (360*16)) {
a = a % (360*16);
@@ -4222,8 +4233,10 @@ void QPainter::drawChord(const QRectF &r, int a, int alen)
#endif
Q_D(QPainter);
- if (!d->engine)
+ if (!d->engine) {
+ qWarning("QPainter::drawChord: Painter not active");
return;
+ }
QRectF rect = r.normalized();
@@ -6509,8 +6522,10 @@ void QPainter::drawPicture(const QPointF &p, const QPicture &picture)
{
Q_D(QPainter);
- if (!d->engine)
+ if (!d->engine) {
+ qWarning("QPainter::drawPicture: Painter not active");
return;
+ }
if (!d->extended)
d->updateState(d->state);
@@ -6621,8 +6636,10 @@ void QPainter::fillRect(const QRectF &r, const QBrush &brush)
{
Q_D(QPainter);
- if (!d->engine)
+ if (!d->engine) {
+ qWarning("QPainter::fillRect: Painter not active");
return;
+ }
if (d->extended && !needsEmulation(brush)) {
d->extended->fillRect(r, brush);
@@ -6656,8 +6673,10 @@ void QPainter::fillRect(const QRect &r, const QBrush &brush)
{
Q_D(QPainter);
- if (!d->engine)
+ if (!d->engine) {
+ qWarning("QPainter::fillRect: Painter not active");
return;
+ }
if (d->extended && !needsEmulation(brush)) {
d->extended->fillRect(r, brush);
@@ -6694,8 +6713,10 @@ void QPainter::fillRect(const QRect &r, const QColor &color)
{
Q_D(QPainter);
- if (!d->engine)
+ if (!d->engine) {
+ qWarning("QPainter::fillRect: Painter not active");
return;
+ }
if (d->extended) {
d->extended->fillRect(r, color);
diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp
index 69473ef0f4..8d23d167b0 100644
--- a/src/gui/painting/qpainterpath.cpp
+++ b/src/gui/painting/qpainterpath.cpp
@@ -517,10 +517,8 @@ QPainterPath::QPainterPath(const QPainterPath &other) = default;
*/
QPainterPath::QPainterPath(const QPointF &startPoint)
- : d_ptr(new QPainterPathPrivate)
+ : d_ptr(new QPainterPathPrivate(startPoint))
{
- Element e = { startPoint.x(), startPoint.y(), MoveToElement };
- d_func()->elements << e;
}
void QPainterPath::detach()
@@ -1491,7 +1489,7 @@ QRectF QPainterPath::controlPointRect() const
bool QPainterPath::isEmpty() const
{
- return !d_ptr || (d_ptr->elements.size() == 1 && d_ptr->elements.first().type == MoveToElement);
+ return !d_ptr || (d_ptr->elements.size() == 1 && d_ptr->elements.constFirst().type == MoveToElement);
}
/*!
@@ -2444,14 +2442,14 @@ QDataStream &operator>>(QDataStream &s, QPainterPath &p)
int size;
s >> size;
- if (size == 0)
+ if (size == 0) {
+ p = {};
return s;
+ }
p.ensureData(); // in case if p.d_func() == 0
- if (p.d_func()->elements.size() == 1) {
- Q_ASSERT(p.d_func()->elements.at(0).type == QPainterPath::MoveToElement);
- p.d_func()->elements.clear();
- }
+ p.detach();
+ p.d_func()->elements.clear();
for (int i=0; i<size; ++i) {
int type;
double x, y;
@@ -2474,9 +2472,7 @@ QDataStream &operator>>(QDataStream &s, QPainterPath &p)
s >> fillRule;
Q_ASSERT(fillRule == Qt::OddEvenFill || fillRule == Qt::WindingFill);
p.d_func()->fillRule = Qt::FillRule(fillRule);
- p.d_func()->dirtyBounds = true;
- p.d_func()->dirtyControlBounds = true;
- if (errorDetected)
+ if (errorDetected || p.d_func()->elements.isEmpty())
p = QPainterPath(); // Better than to return path with possibly corrupt datastructure, which would likely cause crash
return s;
}
diff --git a/src/gui/painting/qpainterpath_p.h b/src/gui/painting/qpainterpath_p.h
index 55164bc347..a07b6cca37 100644
--- a/src/gui/painting/qpainterpath_p.h
+++ b/src/gui/painting/qpainterpath_p.h
@@ -119,6 +119,21 @@ public:
{
}
+ QPainterPathPrivate(QPointF startPoint)
+ : QSharedData(),
+ elements{ { startPoint.x(), startPoint.y(), QPainterPath::MoveToElement } },
+ cStart(0),
+ fillRule(Qt::OddEvenFill),
+ bounds(startPoint, QSizeF(0, 0)),
+ controlBounds(startPoint, QSizeF(0, 0)),
+ require_moveTo(false),
+ dirtyBounds(false),
+ dirtyControlBounds(false),
+ convex(false),
+ pathConverter(nullptr)
+ {
+ }
+
QPainterPathPrivate(const QPainterPathPrivate &other) noexcept
: QSharedData(other),
elements(other.elements),
diff --git a/src/gui/painting/qpathclipper.cpp b/src/gui/painting/qpathclipper.cpp
index 7ada65ce03..10a0639b53 100644
--- a/src/gui/painting/qpathclipper.cpp
+++ b/src/gui/painting/qpathclipper.cpp
@@ -650,7 +650,8 @@ int QKdPointTree::build(int begin, int end, int depth)
}
}
- qSwap(m_nodes.at(last), m_nodes.at(begin));
+ if (last != begin)
+ qSwap(m_nodes.at(last), m_nodes.at(begin));
if (last > begin)
m_nodes.at(last).left = &m_nodes.at(build(begin, last, depth + 1));
diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp
index 02fd2fdeea..38f2a9b803 100644
--- a/src/gui/painting/qpdf.cpp
+++ b/src/gui/painting/qpdf.cpp
@@ -7,6 +7,7 @@
#include "qplatformdefs.h"
+#include <private/qcmyk_p.h>
#include <private/qfont_p.h>
#include <private/qmath_p.h>
#include <private/qpainter_p.h>
@@ -44,7 +45,7 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-inline QPaintEngine::PaintEngineFeatures qt_pdf_decide_features()
+constexpr QPaintEngine::PaintEngineFeatures qt_pdf_decide_features()
{
QPaintEngine::PaintEngineFeatures f = QPaintEngine::AllFeatures;
f &= ~(QPaintEngine::PorterDuff
@@ -99,7 +100,7 @@ static void removeTransparencyFromBrush(QBrush &brush)
const char *qt_real_to_string(qreal val, char *buf) {
const char *ret = buf;
- if (qIsNaN(val)) {
+ if (!qIsFinite(val) || std::abs(val) > std::numeric_limits<quint32>::max()) {
*(buf++) = '0';
*(buf++) = ' ';
*buf = 0;
@@ -110,8 +111,8 @@ const char *qt_real_to_string(qreal val, char *buf) {
*(buf++) = '-';
val = -val;
}
- unsigned int ival = (unsigned int) val;
- qreal frac = val - (qreal)ival;
+ qreal frac = std::modf(val, &val);
+ quint32 ival(val);
int ifrac = (int)(frac * 1000000000);
if (ifrac == 1000000000) {
@@ -270,13 +271,6 @@ namespace QPdf {
dev->open(QIODevice::ReadWrite | QIODevice::Truncate);
}
- void ByteStream::constructor_helper(QByteArray *ba)
- {
- delete dev;
- dev = new QBuffer(ba);
- dev->open(QIODevice::ReadWrite);
- }
-
void ByteStream::prepareBuffer()
{
Q_ASSERT(!dev->isSequential());
@@ -285,16 +279,17 @@ namespace QPdf {
&& size > maxMemorySize()) {
// Switch to file backing.
QTemporaryFile *newFile = new QTemporaryFile;
- newFile->open();
- dev->reset();
- while (!dev->atEnd()) {
- QByteArray buf = dev->read(chunkSize());
- newFile->write(buf);
+ if (newFile->open()) {
+ dev->reset();
+ while (!dev->atEnd()) {
+ QByteArray buf = dev->read(chunkSize());
+ newFile->write(buf);
+ }
+ delete dev;
+ dev = newFile;
+ ba.clear();
+ fileBackingActive = true;
}
- delete dev;
- dev = newFile;
- ba.clear();
- fileBackingActive = true;
}
if (dev->pos() != size) {
dev->seek(size);
@@ -1239,17 +1234,8 @@ void QPdfEngine::setPen()
QBrush b = d->pen.brush();
Q_ASSERT(b.style() == Qt::SolidPattern && b.isOpaque());
- QColor rgba = b.color();
- if (d->grayscale) {
- qreal gray = qGray(rgba.rgba())/255.;
- *d->currentPage << gray << gray << gray;
- } else {
- *d->currentPage << rgba.redF()
- << rgba.greenF()
- << rgba.blueF();
- }
+ d->writeColor(QPdfEnginePrivate::ColorDomain::Stroking, b.color());
*d->currentPage << "SCN\n";
-
*d->currentPage << d->pen.widthF() << "w ";
int pdfCapStyle = 0;
@@ -1303,18 +1289,9 @@ void QPdfEngine::setBrush()
if (!patternObject && !specifyColor)
return;
- *d->currentPage << (patternObject ? "/PCSp cs " : "/CSp cs ");
- if (specifyColor) {
- QColor rgba = d->brush.color();
- if (d->grayscale) {
- qreal gray = qGray(rgba.rgba())/255.;
- *d->currentPage << gray << gray << gray;
- } else {
- *d->currentPage << rgba.redF()
- << rgba.greenF()
- << rgba.blueF();
- }
- }
+ const auto domain = patternObject ? QPdfEnginePrivate::ColorDomain::NonStrokingPattern
+ : QPdfEnginePrivate::ColorDomain::NonStroking;
+ d->writeColor(domain, specifyColor ? d->brush.color() : QColor());
if (patternObject)
*d->currentPage << "/Pat" << patternObject;
*d->currentPage << "scn\n";
@@ -1454,9 +1431,9 @@ int QPdfEngine::metric(QPaintDevice::PaintDeviceMetric metricType) const
QPdfEnginePrivate::QPdfEnginePrivate()
: clipEnabled(false), allClipped(false), hasPen(true), hasBrush(false), simplePen(false),
needsTransform(false), pdfVersion(QPdfEngine::Version_1_4),
+ colorModel(QPdfEngine::ColorModel::Auto),
outDevice(nullptr), ownsDevice(false),
embedFonts(true),
- grayscale(false),
m_pageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(10, 10, 10, 10))
{
initResources();
@@ -1511,7 +1488,9 @@ bool QPdfEngine::begin(QPaintDevice *pdev)
d->catalog = 0;
d->info = 0;
d->graphicsState = 0;
- d->patternColorSpace = 0;
+ d->patternColorSpaceRGB = 0;
+ d->patternColorSpaceGrayscale = 0;
+ d->patternColorSpaceCMYK = 0;
d->simplePen = false;
d->needsTransform = false;
@@ -1629,10 +1608,108 @@ void QPdfEnginePrivate::writeHeader()
">>\n"
"endobj\n");
- // color space for pattern
- patternColorSpace = addXrefEntry(-1);
+ // color spaces for pattern
+ patternColorSpaceRGB = addXrefEntry(-1);
xprintf("[/Pattern /DeviceRGB]\n"
"endobj\n");
+ patternColorSpaceGrayscale = addXrefEntry(-1);
+ xprintf("[/Pattern /DeviceGray]\n"
+ "endobj\n");
+ patternColorSpaceCMYK = addXrefEntry(-1);
+ xprintf("[/Pattern /DeviceCMYK]\n"
+ "endobj\n");
+}
+
+QPdfEngine::ColorModel QPdfEnginePrivate::colorModelForColor(const QColor &color) const
+{
+ switch (colorModel) {
+ case QPdfEngine::ColorModel::RGB:
+ case QPdfEngine::ColorModel::Grayscale:
+ case QPdfEngine::ColorModel::CMYK:
+ return colorModel;
+ case QPdfEngine::ColorModel::Auto:
+ switch (color.spec()) {
+ case QColor::Invalid:
+ case QColor::Rgb:
+ case QColor::Hsv:
+ case QColor::Hsl:
+ case QColor::ExtendedRgb:
+ return QPdfEngine::ColorModel::RGB;
+ case QColor::Cmyk:
+ return QPdfEngine::ColorModel::CMYK;
+ }
+
+ break;
+ }
+
+ Q_UNREACHABLE_RETURN(QPdfEngine::ColorModel::RGB);
+}
+
+void QPdfEnginePrivate::writeColor(ColorDomain domain, const QColor &color)
+{
+ // Switch to the right colorspace.
+ // For simplicity: do it even if it redundant (= already in that colorspace)
+ const QPdfEngine::ColorModel actualColorModel = colorModelForColor(color);
+
+ switch (actualColorModel) {
+ case QPdfEngine::ColorModel::RGB:
+ switch (domain) {
+ case ColorDomain::Stroking:
+ *currentPage << "/CSp CS\n"; break;
+ case ColorDomain::NonStroking:
+ *currentPage << "/CSp cs\n"; break;
+ case ColorDomain::NonStrokingPattern:
+ *currentPage << "/PCSp cs\n"; break;
+ }
+ break;
+ case QPdfEngine::ColorModel::Grayscale:
+ switch (domain) {
+ case ColorDomain::Stroking:
+ *currentPage << "/CSpg CS\n"; break;
+ case ColorDomain::NonStroking:
+ *currentPage << "/CSpg cs\n"; break;
+ case ColorDomain::NonStrokingPattern:
+ *currentPage << "/PCSpg cs\n"; break;
+ }
+ break;
+ case QPdfEngine::ColorModel::CMYK:
+ switch (domain) {
+ case ColorDomain::Stroking:
+ *currentPage << "/CSpcmyk CS\n"; break;
+ case ColorDomain::NonStroking:
+ *currentPage << "/CSpcmyk cs\n"; break;
+ case ColorDomain::NonStrokingPattern:
+ *currentPage << "/PCSpcmyk cs\n"; break;
+ }
+ break;
+ case QPdfEngine::ColorModel::Auto:
+ Q_UNREACHABLE_RETURN();
+ }
+
+ // If we also have a color specified, write it out.
+ if (!color.isValid())
+ return;
+
+ switch (actualColorModel) {
+ case QPdfEngine::ColorModel::RGB:
+ *currentPage << color.redF()
+ << color.greenF()
+ << color.blueF();
+ break;
+ case QPdfEngine::ColorModel::Grayscale: {
+ const qreal gray = qGray(color.rgba()) / 255.;
+ *currentPage << gray;
+ break;
+ }
+ case QPdfEngine::ColorModel::CMYK:
+ *currentPage << color.cyanF()
+ << color.magentaF()
+ << color.yellowF()
+ << color.blackF();
+ break;
+ case QPdfEngine::ColorModel::Auto:
+ Q_UNREACHABLE_RETURN();
+ }
}
void QPdfEnginePrivate::writeInfo()
@@ -1697,7 +1774,8 @@ int QPdfEnginePrivate::writeXmpDcumentMetaData()
const QString metaDataDate = timeStr + tzStr;
QFile metaDataFile(":/qpdf/qpdfa_metadata.xml"_L1);
- metaDataFile.open(QIODevice::ReadOnly);
+ bool ok = metaDataFile.open(QIODevice::ReadOnly);
+ Q_ASSERT(ok);
metaDataContent = QString::fromUtf8(metaDataFile.readAll()).arg(producer.toHtmlEscaped(),
title.toHtmlEscaped(),
creator.toHtmlEscaped(),
@@ -1723,7 +1801,8 @@ int QPdfEnginePrivate::writeOutputIntent()
const int colorProfile = addXrefEntry(-1);
{
QFile colorProfileFile(":/qpdf/sRGB2014.icc"_L1);
- colorProfileFile.open(QIODevice::ReadOnly);
+ bool ok = colorProfileFile.open(QIODevice::ReadOnly);
+ Q_ASSERT(ok);
const QByteArray colorProfileData = colorProfileFile.readAll();
QByteArray data;
@@ -2078,12 +2157,18 @@ void QPdfEnginePrivate::writePage()
xprintf("<<\n"
"/ColorSpace <<\n"
"/PCSp %d 0 R\n"
+ "/PCSpg %d 0 R\n"
+ "/PCSpcmyk %d 0 R\n"
"/CSp /DeviceRGB\n"
"/CSpg /DeviceGray\n"
+ "/CSpcmyk /DeviceCMYK\n"
">>\n"
"/ExtGState <<\n"
"/GSa %d 0 R\n",
- patternColorSpace, graphicsState);
+ patternColorSpaceRGB,
+ patternColorSpaceGrayscale,
+ patternColorSpaceCMYK,
+ graphicsState);
for (int i = 0; i < currentPage->graphicStates.size(); ++i)
xprintf("/GState%d %d 0 R\n", currentPage->graphicStates.at(i), currentPage->graphicStates.at(i));
@@ -2336,7 +2421,7 @@ int QPdfEnginePrivate::writeCompressed(const char *src, int len)
return len;
}
-int QPdfEnginePrivate::writeImage(const QByteArray &data, int width, int height, int depth,
+int QPdfEnginePrivate::writeImage(const QByteArray &data, int width, int height, WriteImageOption option,
int maskObject, int softMaskObject, bool dct, bool isMono)
{
int image = addXrefEntry(-1);
@@ -2346,7 +2431,8 @@ int QPdfEnginePrivate::writeImage(const QByteArray &data, int width, int height,
"/Width %d\n"
"/Height %d\n", width, height);
- if (depth == 1) {
+ switch (option) {
+ case WriteImageOption::Monochrome:
if (!isMono) {
xprintf("/ImageMask true\n"
"/Decode [1 0]\n");
@@ -2354,10 +2440,21 @@ int QPdfEnginePrivate::writeImage(const QByteArray &data, int width, int height,
xprintf("/BitsPerComponent 1\n"
"/ColorSpace /DeviceGray\n");
}
- } else {
+ break;
+ case WriteImageOption::Grayscale:
+ xprintf("/BitsPerComponent 8\n"
+ "/ColorSpace /DeviceGray\n");
+ break;
+ case WriteImageOption::RGB:
xprintf("/BitsPerComponent 8\n"
- "/ColorSpace %s\n", (depth == 32) ? "/DeviceRGB" : "/DeviceGray");
+ "/ColorSpace /DeviceRGB\n");
+ break;
+ case WriteImageOption::CMYK:
+ xprintf("/BitsPerComponent 8\n"
+ "/ColorSpace /DeviceCMYK\n");
+ break;
}
+
if (maskObject > 0)
xprintf("/Mask %d 0 R\n", maskObject);
if (softMaskObject > 0)
@@ -2396,7 +2493,23 @@ struct QGradientBound {
};
Q_DECLARE_TYPEINFO(QGradientBound, Q_PRIMITIVE_TYPE);
-int QPdfEnginePrivate::createShadingFunction(const QGradient *gradient, int from, int to, bool reflect, bool alpha)
+void QPdfEnginePrivate::ShadingFunctionResult::writeColorSpace(QPdf::ByteStream *stream) const
+{
+ *stream << "/ColorSpace ";
+ switch (colorModel) {
+ case QPdfEngine::ColorModel::RGB:
+ *stream << "/DeviceRGB\n"; break;
+ case QPdfEngine::ColorModel::Grayscale:
+ *stream << "/DeviceGray\n"; break;
+ case QPdfEngine::ColorModel::CMYK:
+ *stream << "/DeviceCMYK\n"; break;
+ case QPdfEngine::ColorModel::Auto:
+ Q_UNREACHABLE(); break;
+ }
+}
+
+QPdfEnginePrivate::ShadingFunctionResult
+QPdfEnginePrivate::createShadingFunction(const QGradient *gradient, int from, int to, bool reflect, bool alpha)
{
QGradientStops stops = gradient->stops();
if (stops.isEmpty()) {
@@ -2408,6 +2521,35 @@ int QPdfEnginePrivate::createShadingFunction(const QGradient *gradient, int from
if (stops.at(stops.size() - 1).first < 1)
stops.append(QGradientStop(1, stops.at(stops.size() - 1).second));
+ // Color to use which colorspace to use
+ const QColor referenceColor = stops.constFirst().second;
+
+ switch (colorModel) {
+ case QPdfEngine::ColorModel::RGB:
+ case QPdfEngine::ColorModel::Grayscale:
+ case QPdfEngine::ColorModel::CMYK:
+ break;
+ case QPdfEngine::ColorModel::Auto: {
+ // Make sure that all the stops have the same color spec
+ // (we don't support anything else)
+ const QColor::Spec referenceSpec = referenceColor.spec();
+ bool warned = false;
+ for (QGradientStop &stop : stops) {
+ if (stop.second.spec() != referenceSpec) {
+ if (!warned) {
+ qWarning("QPdfEngine: unable to create a gradient between colors of different spec");
+ warned = true;
+ }
+ stop.second = stop.second.convertTo(referenceSpec);
+ }
+ }
+ break;
+ }
+ }
+
+ ShadingFunctionResult result;
+ result.colorModel = colorModelForColor(referenceColor);
+
QList<int> functions;
const int numStops = stops.size();
functions.reserve(numStops - 1);
@@ -2423,8 +2565,31 @@ int QPdfEnginePrivate::createShadingFunction(const QGradient *gradient, int from
s << "/C0 [" << stops.at(i).second.alphaF() << "]\n"
"/C1 [" << stops.at(i + 1).second.alphaF() << "]\n";
} else {
- s << "/C0 [" << stops.at(i).second.redF() << stops.at(i).second.greenF() << stops.at(i).second.blueF() << "]\n"
- "/C1 [" << stops.at(i + 1).second.redF() << stops.at(i + 1).second.greenF() << stops.at(i + 1).second.blueF() << "]\n";
+ switch (result.colorModel) {
+ case QPdfEngine::ColorModel::RGB:
+ s << "/C0 [" << stops.at(i).second.redF() << stops.at(i).second.greenF() << stops.at(i).second.blueF() << "]\n"
+ "/C1 [" << stops.at(i + 1).second.redF() << stops.at(i + 1).second.greenF() << stops.at(i + 1).second.blueF() << "]\n";
+ break;
+ case QPdfEngine::ColorModel::Grayscale:
+ s << "/C0 [" << (qGray(stops.at(i).second.rgba()) / 255.) << "]\n"
+ "/C1 [" << (qGray(stops.at(i + 1).second.rgba()) / 255.) << "]\n";
+ break;
+ case QPdfEngine::ColorModel::CMYK:
+ s << "/C0 [" << stops.at(i).second.cyanF()
+ << stops.at(i).second.magentaF()
+ << stops.at(i).second.yellowF()
+ << stops.at(i).second.blackF() << "]\n"
+ "/C1 [" << stops.at(i + 1).second.cyanF()
+ << stops.at(i + 1).second.magentaF()
+ << stops.at(i + 1).second.yellowF()
+ << stops.at(i + 1).second.blackF() << "]\n";
+ break;
+
+ case QPdfEngine::ColorModel::Auto:
+ Q_UNREACHABLE();
+ break;
+ }
+
}
s << ">>\n"
"endobj\n";
@@ -2492,7 +2657,8 @@ int QPdfEnginePrivate::createShadingFunction(const QGradient *gradient, int from
} else {
function = functions.at(0);
}
- return function;
+ result.function = function;
+ return result;
}
int QPdfEnginePrivate::generateLinearGradientShader(const QLinearGradient *gradient, const QTransform &matrix, bool alpha)
@@ -2538,17 +2704,22 @@ int QPdfEnginePrivate::generateLinearGradientShader(const QLinearGradient *gradi
}
}
- int function = createShadingFunction(gradient, from, to, reflect, alpha);
+ const auto shadingFunctionResult = createShadingFunction(gradient, from, to, reflect, alpha);
QByteArray shader;
QPdf::ByteStream s(&shader);
s << "<<\n"
- "/ShadingType 2\n"
- "/ColorSpace " << (alpha ? "/DeviceGray\n" : "/DeviceRGB\n") <<
- "/AntiAlias true\n"
+ "/ShadingType 2\n";
+
+ if (alpha)
+ s << "/ColorSpace /DeviceGray\n";
+ else
+ shadingFunctionResult.writeColorSpace(&s);
+
+ s << "/AntiAlias true\n"
"/Coords [" << start.x() << start.y() << stop.x() << stop.y() << "]\n"
"/Extend [true true]\n"
- "/Function " << function << "0 R\n"
+ "/Function " << shadingFunctionResult.function << "0 R\n"
">>\n"
"endobj\n";
int shaderObject = addXrefEntry(-1);
@@ -2606,18 +2777,23 @@ int QPdfEnginePrivate::generateRadialGradientShader(const QRadialGradient *gradi
}
}
- int function = createShadingFunction(gradient, from, to, reflect, alpha);
+ const auto shadingFunctionResult = createShadingFunction(gradient, from, to, reflect, alpha);
QByteArray shader;
QPdf::ByteStream s(&shader);
s << "<<\n"
- "/ShadingType 3\n"
- "/ColorSpace " << (alpha ? "/DeviceGray\n" : "/DeviceRGB\n") <<
- "/AntiAlias true\n"
+ "/ShadingType 3\n";
+
+ if (alpha)
+ s << "/ColorSpace /DeviceGray\n";
+ else
+ shadingFunctionResult.writeColorSpace(&s);
+
+ s << "/AntiAlias true\n"
"/Domain [0 1]\n"
"/Coords [" << p0.x() << p0.y() << r0 << p1.x() << p1.y() << r1 << "]\n"
"/Extend [true true]\n"
- "/Function " << function << "0 R\n"
+ "/Function " << shadingFunctionResult.function << "0 R\n"
">>\n"
"endobj\n";
int shaderObject = addXrefEntry(-1);
@@ -2856,6 +3032,7 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, bool lossless,
QImage image = img;
QImage::Format format = image.format();
+ const bool grayscale = (colorModel == QPdfEngine::ColorModel::Grayscale);
if (pdfVersion == QPdfEngine::Version_A1b) {
if (image.hasAlphaChannel()) {
@@ -2879,7 +3056,7 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, bool lossless,
format = QImage::Format_Mono;
} else {
*bitmap = false;
- if (format != QImage::Format_RGB32 && format != QImage::Format_ARGB32) {
+ if (format != QImage::Format_RGB32 && format != QImage::Format_ARGB32 && format != QImage::Format_CMYK8888) {
image = image.convertToFormat(QImage::Format_ARGB32);
format = QImage::Format_ARGB32;
}
@@ -2887,7 +3064,6 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, bool lossless,
int w = image.width();
int h = image.height();
- int d = image.depth();
if (format == QImage::Format_Mono) {
int bytesPerLine = (w + 7) >> 3;
@@ -2898,7 +3074,7 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, bool lossless,
memcpy(rawdata, image.constScanLine(y), bytesPerLine);
rawdata += bytesPerLine;
}
- object = writeImage(data, w, h, d, 0, 0, false, is_monochrome(img.colorTable()));
+ object = writeImage(data, w, h, WriteImageOption::Monochrome, 0, 0, false, is_monochrome(img.colorTable()));
} else {
QByteArray softMaskData;
bool dct = false;
@@ -2910,10 +3086,14 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, bool lossless,
QBuffer buffer(&imageData);
QImageWriter writer(&buffer, "jpeg");
writer.setQuality(94);
+ if (format == QImage::Format_CMYK8888) {
+ // PDFs require CMYK colors not to be inverted in the JPEG encoding
+ writer.setSubType("CMYK");
+ }
writer.write(image);
dct = true;
- if (format != QImage::Format_RGB32) {
+ if (format != QImage::Format_RGB32 && format != QImage::Format_CMYK8888) {
softMaskData.resize(w * h);
uchar *sdata = (uchar *)softMaskData.data();
for (int y = 0; y < h; ++y) {
@@ -2928,41 +3108,59 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, bool lossless,
}
}
} else {
- imageData.resize(grayscale ? w * h : 3 * w * h);
- uchar *data = (uchar *)imageData.data();
- softMaskData.resize(w * h);
- uchar *sdata = (uchar *)softMaskData.data();
- for (int y = 0; y < h; ++y) {
- const QRgb *rgb = (const QRgb *)image.constScanLine(y);
+ if (format == QImage::Format_CMYK8888) {
+ imageData.resize(grayscale ? w * h : w * h * 4);
+ uchar *data = (uchar *)imageData.data();
+ const qsizetype bytesPerLine = image.bytesPerLine();
if (grayscale) {
- for (int x = 0; x < w; ++x) {
- *(data++) = qGray(*rgb);
- uchar alpha = qAlpha(*rgb);
- *sdata++ = alpha;
- hasMask |= (alpha < 255);
- hasAlpha |= (alpha != 0 && alpha != 255);
- ++rgb;
+ for (int y = 0; y < h; ++y) {
+ const uint *cmyk = (const uint *)image.constScanLine(y);
+ for (int x = 0; x < w; ++x)
+ *data++ = qGray(QCmyk32::fromCmyk32(*cmyk++).toColor().rgba());
}
} else {
- for (int x = 0; x < w; ++x) {
- *(data++) = qRed(*rgb);
- *(data++) = qGreen(*rgb);
- *(data++) = qBlue(*rgb);
- uchar alpha = qAlpha(*rgb);
- *sdata++ = alpha;
- hasMask |= (alpha < 255);
- hasAlpha |= (alpha != 0 && alpha != 255);
- ++rgb;
+ for (int y = 0; y < h; ++y) {
+ uchar *start = data + y * w * 4;
+ memcpy(start, image.constScanLine(y), bytesPerLine);
+ }
+ }
+ } else {
+ imageData.resize(grayscale ? w * h : 3 * w * h);
+ uchar *data = (uchar *)imageData.data();
+ softMaskData.resize(w * h);
+ uchar *sdata = (uchar *)softMaskData.data();
+ for (int y = 0; y < h; ++y) {
+ const QRgb *rgb = (const QRgb *)image.constScanLine(y);
+ if (grayscale) {
+ for (int x = 0; x < w; ++x) {
+ *(data++) = qGray(*rgb);
+ uchar alpha = qAlpha(*rgb);
+ *sdata++ = alpha;
+ hasMask |= (alpha < 255);
+ hasAlpha |= (alpha != 0 && alpha != 255);
+ ++rgb;
+ }
+ } else {
+ for (int x = 0; x < w; ++x) {
+ *(data++) = qRed(*rgb);
+ *(data++) = qGreen(*rgb);
+ *(data++) = qBlue(*rgb);
+ uchar alpha = qAlpha(*rgb);
+ *sdata++ = alpha;
+ hasMask |= (alpha < 255);
+ hasAlpha |= (alpha != 0 && alpha != 255);
+ ++rgb;
+ }
}
}
}
- if (format == QImage::Format_RGB32)
+ if (format == QImage::Format_RGB32 || format == QImage::Format_CMYK8888)
hasAlpha = hasMask = false;
}
int maskObject = 0;
int softMaskObject = 0;
if (hasAlpha) {
- softMaskObject = writeImage(softMaskData, w, h, 8, 0, 0);
+ softMaskObject = writeImage(softMaskData, w, h, WriteImageOption::Grayscale, 0, 0);
} else if (hasMask) {
// dither the soft mask to 1bit and add it. This also helps PDF viewers
// without transparency support
@@ -2978,9 +3176,18 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, bool lossless,
}
mdata += bytesPerLine;
}
- maskObject = writeImage(mask, w, h, 1, 0, 0);
+ maskObject = writeImage(mask, w, h, WriteImageOption::Monochrome, 0, 0);
}
- object = writeImage(imageData, w, h, grayscale ? 8 : 32,
+
+ const WriteImageOption option = [&]() {
+ if (grayscale)
+ return WriteImageOption::Grayscale;
+ if (format == QImage::Format_CMYK8888)
+ return WriteImageOption::CMYK;
+ return WriteImageOption::RGB;
+ }();
+
+ object = writeImage(imageData, w, h, option,
maskObject, softMaskObject, dct);
}
imageCache.insert(serial_no, object);
diff --git a/src/gui/painting/qpdf_p.h b/src/gui/painting/qpdf_p.h
index 2c70ddf664..3c34e0bd7a 100644
--- a/src/gui/painting/qpdf_p.h
+++ b/src/gui/painting/qpdf_p.h
@@ -60,10 +60,6 @@ namespace QPdf {
static inline int maxMemorySize() { return 100000000; }
static inline int chunkSize() { return 10000000; }
- protected:
- void constructor_helper(QIODevice *dev);
- void constructor_helper(QByteArray *ba);
-
private:
void prepareBuffer();
@@ -142,7 +138,7 @@ public:
};
QPdfEngine();
- QPdfEngine(QPdfEnginePrivate &d);
+ explicit QPdfEngine(QPdfEnginePrivate &d);
~QPdfEngine() {}
void setOutputFilename(const QString &filename);
@@ -157,6 +153,18 @@ public:
void addFileAttachment(const QString &fileName, const QByteArray &data, const QString &mimeType);
+ // keep in sync with QPdfWriter
+ enum class ColorModel
+ {
+ RGB,
+ Grayscale,
+ CMYK,
+ Auto,
+ };
+
+ ColorModel colorModel() const;
+ void setColorModel(ColorModel model);
+
// reimplementations QPaintEngine
bool begin(QPaintDevice *pdev) override;
bool end() override;
@@ -240,6 +248,7 @@ public:
bool needsTransform;
qreal opacity;
QPdfEngine::PdfVersion pdfVersion;
+ QPdfEngine::ColorModel colorModel;
QHash<QFontEngine::FaceId, QFontSubset *> fonts;
@@ -255,7 +264,6 @@ public:
QString creator;
bool embedFonts;
int resolution;
- bool grayscale;
// Page layout: size, orientation and margins
QPageLayout m_pageLayout;
@@ -265,8 +273,22 @@ private:
int generateGradientShader(const QGradient *gradient, const QTransform &matrix, bool alpha = false);
int generateLinearGradientShader(const QLinearGradient *lg, const QTransform &matrix, bool alpha);
int generateRadialGradientShader(const QRadialGradient *gradient, const QTransform &matrix, bool alpha);
- int createShadingFunction(const QGradient *gradient, int from, int to, bool reflect, bool alpha);
+ struct ShadingFunctionResult
+ {
+ int function;
+ QPdfEngine::ColorModel colorModel;
+ void writeColorSpace(QPdf::ByteStream *stream) const;
+ };
+ ShadingFunctionResult createShadingFunction(const QGradient *gradient, int from, int to, bool reflect, bool alpha);
+
+ enum class ColorDomain {
+ Stroking,
+ NonStroking,
+ NonStrokingPattern,
+ };
+ QPdfEngine::ColorModel colorModelForColor(const QColor &color) const;
+ void writeColor(ColorDomain domain, const QColor &color);
void writeInfo();
int writeXmpDcumentMetaData();
int writeOutputIntent();
@@ -282,7 +304,15 @@ private:
QDataStream* stream;
int streampos;
- int writeImage(const QByteArray &data, int width, int height, int depth,
+ enum class WriteImageOption
+ {
+ Monochrome,
+ Grayscale,
+ RGB,
+ CMYK,
+ };
+
+ int writeImage(const QByteArray &data, int width, int height, WriteImageOption option,
int maskObject, int softMaskObject, bool dct = false, bool isMono = false);
void writePage();
@@ -316,7 +346,10 @@ private:
// various PDF objects
int pageRoot, namesRoot, destsRoot, attachmentsRoot, catalog, info;
- int graphicsState, patternColorSpace;
+ int graphicsState;
+ int patternColorSpaceRGB;
+ int patternColorSpaceGrayscale;
+ int patternColorSpaceCMYK;
QList<uint> pages;
QHash<qint64, uint> imageCache;
QHash<QPair<uint, uint>, uint > alphaCache;
diff --git a/src/gui/painting/qpdfwriter.cpp b/src/gui/painting/qpdfwriter.cpp
index f28a460d7c..bce65927ab 100644
--- a/src/gui/painting/qpdfwriter.cpp
+++ b/src/gui/painting/qpdfwriter.cpp
@@ -295,6 +295,53 @@ bool QPdfWriter::newPage()
return d->engine->newPage();
}
+/*!
+ \enum QPdfWriter::ColorModel
+ \since 6.8
+
+ This enumeration describes the way in which the PDF engine interprets
+ stroking and filling colors, set as a QPainter's pen or brush (via
+ QPen and QBrush).
+
+ \value RGB All colors are converted to RGB and saved as such in the
+ PDF.
+
+ \value Grayscale All colors are converted to grayscale. For backwards
+ compatibility, they are emitted in the PDF output as RGB colors, with
+ identical quantities of red, green and blue.
+
+ \value CMYK All colors are converted to CMYK and saved as such.
+
+ \value Auto RGB colors are emitted as RGB; CMYK colors are emitted as
+ CMYK. Colors of any other color spec are converted to RGB.
+ This is the default since Qt 6.8.
+
+ \sa QColor, QGradient
+*/
+
+/*!
+ \since 6.8
+
+ Returns the color model used by this PDF writer.
+ The default is QPdfWriter::ColorModel::Auto.
+*/
+QPdfWriter::ColorModel QPdfWriter::colorModel() const
+{
+ Q_D(const QPdfWriter);
+ return static_cast<ColorModel>(d->engine->d_func()->colorModel);
+}
+
+/*!
+ \since 6.8
+
+ Sets the color model used by this PDF writer to \a model.
+*/
+void QPdfWriter::setColorModel(ColorModel model)
+{
+ Q_D(QPdfWriter);
+ d->engine->d_func()->colorModel = static_cast<QPdfEngine::ColorModel>(model);
+}
+
QT_END_NAMESPACE
#include "moc_qpdfwriter.cpp"
diff --git a/src/gui/painting/qpdfwriter.h b/src/gui/painting/qpdfwriter.h
index 5885c4ef1a..1a4b607b66 100644
--- a/src/gui/painting/qpdfwriter.h
+++ b/src/gui/painting/qpdfwriter.h
@@ -44,6 +44,18 @@ public:
void addFileAttachment(const QString &fileName, const QByteArray &data, const QString &mimeType = QString());
+ enum class ColorModel
+ {
+ RGB,
+ Grayscale,
+ CMYK,
+ Auto,
+ };
+ Q_ENUM(ColorModel)
+
+ ColorModel colorModel() const;
+ void setColorModel(ColorModel model);
+
protected:
QPaintEngine *paintEngine() const override;
int metric(PaintDeviceMetric id) const override;
diff --git a/src/gui/painting/qpen.cpp b/src/gui/painting/qpen.cpp
index 958539feda..d37beda6b6 100644
--- a/src/gui/painting/qpen.cpp
+++ b/src/gui/painting/qpen.cpp
@@ -10,8 +10,6 @@
QT_BEGIN_NAMESPACE
-typedef QPenPrivate QPenData;
-
/*!
\class QPen
\inmodule QtGui
@@ -193,7 +191,7 @@ typedef QPenPrivate QPenData;
*/
QPenPrivate::QPenPrivate(const QBrush &_brush, qreal _width, Qt::PenStyle penStyle,
Qt::PenCapStyle _capStyle, Qt::PenJoinStyle _joinStyle)
- : ref(1), dashOffset(0), miterLimit(2),
+ : dashOffset(0), miterLimit(2),
cosmetic(false)
{
width = _width;
@@ -209,17 +207,13 @@ static const Qt::PenJoinStyle qpen_default_join = Qt::BevelJoin;
class QPenDataHolder
{
public:
- QPenData *pen;
+ QPen::DataPtr pen;
QPenDataHolder(const QBrush &brush, qreal width, Qt::PenStyle penStyle,
Qt::PenCapStyle penCapStyle, Qt::PenJoinStyle _joinStyle)
- : pen(new QPenData(brush, width, penStyle, penCapStyle, _joinStyle))
+ : pen(new QPenPrivate(brush, width, penStyle, penCapStyle, _joinStyle))
{ }
- ~QPenDataHolder()
- {
- if (!pen->ref.deref())
- delete pen;
- pen = nullptr;
- }
+ ~QPenDataHolder() = default;
+ Q_DISABLE_COPY_MOVE(QPenDataHolder)
};
Q_GLOBAL_STATIC_WITH_ARGS(QPenDataHolder, defaultPenInstance,
@@ -234,7 +228,6 @@ Q_GLOBAL_STATIC_WITH_ARGS(QPenDataHolder, nullPenInstance,
QPen::QPen()
{
d = defaultPenInstance()->pen;
- d->ref.ref();
}
/*!
@@ -247,9 +240,8 @@ QPen::QPen(Qt::PenStyle style)
{
if (style == Qt::NoPen) {
d = nullPenInstance()->pen;
- d->ref.ref();
} else {
- d = new QPenData(Qt::black, 1, style, qpen_default_cap, qpen_default_join);
+ d = new QPenPrivate(Qt::black, 1, style, qpen_default_cap, qpen_default_join);
}
}
@@ -262,7 +254,7 @@ QPen::QPen(Qt::PenStyle style)
QPen::QPen(const QColor &color)
{
- d = new QPenData(color, 1, Qt::SolidLine, qpen_default_cap, qpen_default_join);
+ d = new QPenPrivate(color, 1, Qt::SolidLine, qpen_default_cap, qpen_default_join);
}
@@ -277,7 +269,7 @@ QPen::QPen(const QColor &color)
QPen::QPen(const QBrush &brush, qreal width, Qt::PenStyle s, Qt::PenCapStyle c, Qt::PenJoinStyle j)
{
- d = new QPenData(brush, width, s, c, j);
+ d = new QPenPrivate(brush, width, s, c, j);
}
/*!
@@ -287,10 +279,8 @@ QPen::QPen(const QBrush &brush, qreal width, Qt::PenStyle s, Qt::PenCapStyle c,
*/
QPen::QPen(const QPen &p) noexcept
+ : d(p.d)
{
- d = p.d;
- if (d)
- d->ref.ref();
}
@@ -309,11 +299,9 @@ QPen::QPen(const QPen &p) noexcept
Destroys the pen.
*/
-QPen::~QPen()
-{
- if (d && !d->ref.deref())
- delete d;
-}
+QPen::~QPen() = default;
+
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QPenPrivate)
/*!
\fn void QPen::detach()
@@ -327,14 +315,7 @@ QPen::~QPen()
void QPen::detach()
{
- if (d->ref.loadRelaxed() == 1)
- return;
-
- QPenData *x = new QPenData(*static_cast<QPenData *>(d));
- if (!d->ref.deref())
- delete d;
- x->ref.storeRelaxed(1);
- d = x;
+ d.detach();
}
@@ -407,9 +388,8 @@ void QPen::setStyle(Qt::PenStyle s)
return;
detach();
d->style = s;
- QPenData *dd = static_cast<QPenData *>(d);
- dd->dashPattern.clear();
- dd->dashOffset = 0;
+ d->dashPattern.clear();
+ d->dashOffset = 0;
}
/*!
@@ -419,36 +399,35 @@ void QPen::setStyle(Qt::PenStyle s)
*/
QList<qreal> QPen::dashPattern() const
{
- QPenData *dd = static_cast<QPenData *>(d);
if (d->style == Qt::SolidLine || d->style == Qt::NoPen) {
return QList<qreal>();
- } else if (dd->dashPattern.isEmpty()) {
+ } else if (d->dashPattern.isEmpty()) {
const qreal space = 2;
const qreal dot = 1;
const qreal dash = 4;
switch (d->style) {
case Qt::DashLine:
- dd->dashPattern.reserve(2);
- dd->dashPattern << dash << space;
+ d->dashPattern.reserve(2);
+ d->dashPattern << dash << space;
break;
case Qt::DotLine:
- dd->dashPattern.reserve(2);
- dd->dashPattern << dot << space;
+ d->dashPattern.reserve(2);
+ d->dashPattern << dot << space;
break;
case Qt::DashDotLine:
- dd->dashPattern.reserve(4);
- dd->dashPattern << dash << space << dot << space;
+ d->dashPattern.reserve(4);
+ d->dashPattern << dash << space << dot << space;
break;
case Qt::DashDotDotLine:
- dd->dashPattern.reserve(6);
- dd->dashPattern << dash << space << dot << space << dot << space;
+ d->dashPattern.reserve(6);
+ d->dashPattern << dash << space << dot << space << dot << space;
break;
default:
break;
}
}
- return dd->dashPattern;
+ return d->dashPattern;
}
/*!
@@ -487,13 +466,12 @@ void QPen::setDashPattern(const QList<qreal> &pattern)
return;
detach();
- QPenData *dd = static_cast<QPenData *>(d);
- dd->dashPattern = pattern;
+ d->dashPattern = pattern;
d->style = Qt::CustomDashLine;
- if ((dd->dashPattern.size() % 2) == 1) {
+ if ((d->dashPattern.size() % 2) == 1) {
qWarning("QPen::setDashPattern: Pattern not of even length");
- dd->dashPattern << 1;
+ d->dashPattern << 1;
}
}
@@ -505,8 +483,7 @@ void QPen::setDashPattern(const QList<qreal> &pattern)
*/
qreal QPen::dashOffset() const
{
- QPenData *dd = static_cast<QPenData *>(d);
- return dd->dashOffset;
+ return d->dashOffset;
}
/*!
Sets the dash offset (the starting point on the dash pattern) for this pen
@@ -528,13 +505,12 @@ qreal QPen::dashOffset() const
*/
void QPen::setDashOffset(qreal offset)
{
- if (qFuzzyCompare(offset, static_cast<QPenData *>(d)->dashOffset))
+ if (qFuzzyCompare(offset, d->dashOffset))
return;
detach();
- QPenData *dd = static_cast<QPenData *>(d);
- dd->dashOffset = offset;
+ d->dashOffset = offset;
if (d->style != Qt::CustomDashLine) {
- dd->dashPattern = dashPattern();
+ d->dashPattern = dashPattern();
d->style = Qt::CustomDashLine;
}
}
@@ -547,8 +523,7 @@ void QPen::setDashOffset(qreal offset)
*/
qreal QPen::miterLimit() const
{
- const QPenData *dd = static_cast<QPenData *>(d);
- return dd->miterLimit;
+ return d->miterLimit;
}
/*!
@@ -570,8 +545,7 @@ qreal QPen::miterLimit() const
void QPen::setMiterLimit(qreal limit)
{
detach();
- QPenData *dd = static_cast<QPenData *>(d);
- dd->miterLimit = limit;
+ d->miterLimit = limit;
}
@@ -782,8 +756,7 @@ bool QPen::isSolid() const
bool QPen::isCosmetic() const
{
- QPenData *dd = static_cast<QPenData *>(d);
- return (dd->cosmetic == true) || d->width == 0;
+ return (d->cosmetic == true) || d->width == 0;
}
@@ -797,8 +770,7 @@ bool QPen::isCosmetic() const
void QPen::setCosmetic(bool cosmetic)
{
detach();
- QPenData *dd = static_cast<QPenData *>(d);
- dd->cosmetic = cosmetic;
+ d->cosmetic = cosmetic;
}
@@ -825,19 +797,17 @@ void QPen::setCosmetic(bool cosmetic)
bool QPen::operator==(const QPen &p) const
{
- QPenData *dd = static_cast<QPenData *>(d);
- QPenData *pdd = static_cast<QPenData *>(p.d);
return (p.d == d)
|| (p.d->style == d->style
&& p.d->capStyle == d->capStyle
&& p.d->joinStyle == d->joinStyle
&& p.d->width == d->width
- && pdd->miterLimit == dd->miterLimit
+ && p.d->miterLimit == d->miterLimit
&& (d->style != Qt::CustomDashLine
- || (qFuzzyCompare(pdd->dashOffset, dd->dashOffset) &&
- pdd->dashPattern == dd->dashPattern))
+ || (qFuzzyCompare(p.d->dashOffset, d->dashOffset) &&
+ p.d->dashPattern == d->dashPattern))
&& p.d->brush == d->brush
- && pdd->cosmetic == dd->cosmetic);
+ && p.d->cosmetic == d->cosmetic);
}
@@ -869,14 +839,13 @@ bool QPen::isDetached()
QDataStream &operator<<(QDataStream &s, const QPen &p)
{
- QPenData *dd = static_cast<QPenData *>(p.d);
if (s.version() < 3) {
s << (quint8)p.style();
} else if (s.version() < QDataStream::Qt_4_3) {
s << (quint8)(uint(p.style()) | uint(p.capStyle()) | uint(p.joinStyle()));
} else {
s << (quint16)(uint(p.style()) | uint(p.capStyle()) | uint(p.joinStyle()));
- s << (bool)(dd->cosmetic);
+ s << (bool)(p.d->cosmetic);
}
if (s.version() < 7) {
@@ -965,16 +934,15 @@ QDataStream &operator>>(QDataStream &s, QPen &p)
}
p.detach();
- QPenData *dd = static_cast<QPenData *>(p.d);
- dd->width = width;
- dd->brush = brush;
- dd->style = Qt::PenStyle(style & Qt::MPenStyle);
- dd->capStyle = Qt::PenCapStyle(style & Qt::MPenCapStyle);
- dd->joinStyle = Qt::PenJoinStyle(style & Qt::MPenJoinStyle);
- dd->dashPattern = dashPattern;
- dd->miterLimit = miterLimit;
- dd->dashOffset = dashOffset;
- dd->cosmetic = cosmetic;
+ p.d->width = width;
+ p.d->brush = brush;
+ p.d->style = Qt::PenStyle(style & Qt::MPenStyle);
+ p.d->capStyle = Qt::PenCapStyle(style & Qt::MPenCapStyle);
+ p.d->joinStyle = Qt::PenJoinStyle(style & Qt::MPenJoinStyle);
+ p.d->dashPattern = dashPattern;
+ p.d->miterLimit = miterLimit;
+ p.d->dashOffset = dashOffset;
+ p.d->cosmetic = cosmetic;
return s;
}
diff --git a/src/gui/painting/qpen.h b/src/gui/painting/qpen.h
index 2f38098496..3367b96c35 100644
--- a/src/gui/painting/qpen.h
+++ b/src/gui/painting/qpen.h
@@ -4,6 +4,7 @@
#ifndef QPEN_H
#define QPEN_H
+#include <QtCore/qshareddata.h>
#include <QtGui/qtguiglobal.h>
#include <QtGui/qcolor.h>
#include <QtGui/qbrush.h>
@@ -21,6 +22,8 @@ Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QPen &);
Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QPen &);
#endif
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QPenPrivate, Q_GUI_EXPORT)
+
class Q_GUI_EXPORT QPen
{
public:
@@ -34,10 +37,9 @@ public:
~QPen();
QPen &operator=(const QPen &pen) noexcept;
- QPen(QPen &&other) noexcept
- : d(std::exchange(other.d, nullptr)) {}
+ QPen(QPen &&other) noexcept = default;
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QPen)
- void swap(QPen &other) noexcept { qt_ptr_swap(d, other.d); }
+ void swap(QPen &other) noexcept { d.swap(other.d); }
Qt::PenStyle style() const;
void setStyle(Qt::PenStyle);
@@ -79,15 +81,19 @@ public:
operator QVariant() const;
bool isDetached();
+
private:
friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QPen &);
friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QPen &);
+public:
+ using DataPtr = QExplicitlySharedDataPointer<QPenPrivate>;
+
+private:
void detach();
- class QPenPrivate *d;
+ DataPtr d;
public:
- typedef QPenPrivate * DataPtr;
inline DataPtr &data_ptr() { return d; }
};
diff --git a/src/gui/painting/qpen_p.h b/src/gui/painting/qpen_p.h
index 39ed024d85..a939c5e4f6 100644
--- a/src/gui/painting/qpen_p.h
+++ b/src/gui/painting/qpen_p.h
@@ -16,14 +16,15 @@
//
#include <QtCore/private/qglobal_p.h>
+#include <QtCore/qshareddata.h>
QT_BEGIN_NAMESPACE
-class QPenPrivate {
+class QPenPrivate : public QSharedData
+{
public:
QPenPrivate(const QBrush &brush, qreal width, Qt::PenStyle, Qt::PenCapStyle,
Qt::PenJoinStyle _joinStyle);
- QAtomicInt ref;
qreal width;
QBrush brush;
Qt::PenStyle style;
diff --git a/src/gui/painting/qpixellayout.cpp b/src/gui/painting/qpixellayout.cpp
index b196f48617..4f2f0ae13a 100644
--- a/src/gui/painting/qpixellayout.cpp
+++ b/src/gui/painting/qpixellayout.cpp
@@ -7,6 +7,7 @@
#include "qpixellayout_p.h"
#include "qrgba64_p.h"
#include <QtCore/private/qsimd_p.h>
+#include <QtGui/private/qcmyk_p.h>
QT_BEGIN_NAMESPACE
@@ -1187,10 +1188,12 @@ static const QRgba64 *QT_FASTCALL fetchRGBA64ToRGBA64PM(QRgba64 *buffer, const u
const QRgba64 *s = reinterpret_cast<const QRgba64 *>(src) + index;
#ifdef __SSE2__
for (int i = 0; i < count; ++i) {
+ const auto a = s[i].alpha();
__m128i vs = _mm_loadl_epi64((const __m128i *)(s + i));
__m128i va = _mm_shufflelo_epi16(vs, _MM_SHUFFLE(3, 3, 3, 3));
vs = multiplyAlpha65535(vs, va);
_mm_storel_epi64((__m128i *)(buffer + i), vs);
+ buffer[i].setAlpha(a);
}
#else
for (int i = 0; i < count; ++i)
@@ -1655,11 +1658,71 @@ static const QRgba64 *QT_FASTCALL fetchRGBA32FPMToRGBA64PM(QRgba64 *buffer, cons
return buffer;
}
+inline const uint *qt_convertCMYK8888ToARGB32PM(uint *buffer, const uint *src, int count)
+{
+ UNALIASED_CONVERSION_LOOP(buffer, src, count, [](uint s) {
+ const QColor color = QCmyk32::fromCmyk32(s).toColor();
+ return color.rgba();
+ });
+ return buffer;
+}
+
+static void QT_FASTCALL convertCMYK8888ToARGB32PM(uint *buffer, int count, const QList<QRgb> *)
+{
+ qt_convertCMYK8888ToARGB32PM(buffer, buffer, count);
+}
+
+static const QRgba64 *QT_FASTCALL convertCMYK8888ToToRGBA64PM(QRgba64 *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = QCmyk32::fromCmyk32(src[i]).toColor().rgba64();
+ return buffer;
+}
+
+static const uint *QT_FASTCALL fetchCMYK8888ToARGB32PM(uint *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const uint *s = reinterpret_cast<const uint *>(src) + index;
+ for (int i = 0; i < count; ++i)
+ buffer[i] = QCmyk32::fromCmyk32(s[i]).toColor().rgba();
+ return buffer;
+}
+
+static const QRgba64 *QT_FASTCALL fetchCMYK8888ToRGBA64PM(QRgba64 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const uint *s = reinterpret_cast<const uint *>(src) + index;
+ for (int i = 0; i < count; ++i)
+ buffer[i] = QCmyk32::fromCmyk32(s[i]).toColor().rgba64();
+ return buffer;
+}
+
+static void QT_FASTCALL storeCMYK8888FromARGB32PM(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = reinterpret_cast<uint *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ QColor c = qUnpremultiply(src[i]);
+ d[i] = QCmyk32::fromColor(c).toUint();
+ }
+}
+
+static void QT_FASTCALL storeCMYK8888FromRGB32(uchar *dest, const uint *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = reinterpret_cast<uint *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ QColor c = src[i];
+ d[i] = QCmyk32::fromColor(c).toUint();
+ }
+}
+
// Note:
// convertToArgb32() assumes that no color channel is less than 4 bits.
// storeRGBFromARGB32PM() assumes that no color channel is more than 8 bits.
// QImage::rgbSwapped() assumes that the red and blue color channels have the same number of bits.
-QPixelLayout qPixelLayouts[QImage::NImageFormats] = {
+QPixelLayout qPixelLayouts[] = {
{ false, false, QPixelLayout::BPPNone, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }, // Format_Invalid
{ false, false, QPixelLayout::BPP1MSB, nullptr,
convertIndexedToARGB32PM, convertIndexedTo<QRgba64>,
@@ -1777,9 +1840,13 @@ QPixelLayout qPixelLayouts[QImage::NImageFormats] = {
convertPassThrough, nullptr,
fetchRGB32FToRGB32, fetchRGBA32FPMToRGBA64PM,
storeRGB32FFromRGB32, storeRGB32FFromRGB32 }, // Format_RGBA32FPx4_Premultiplied
+ { false, false, QPixelLayout::BPP32, nullptr,
+ convertCMYK8888ToARGB32PM, convertCMYK8888ToToRGBA64PM,
+ fetchCMYK8888ToARGB32PM, fetchCMYK8888ToRGBA64PM,
+ storeCMYK8888FromARGB32PM, storeCMYK8888FromRGB32 }, // Format_CMYK8888
};
-static_assert(sizeof(qPixelLayouts) / sizeof(*qPixelLayouts) == QImage::NImageFormats);
+static_assert(std::size(qPixelLayouts) == QImage::NImageFormats);
static void QT_FASTCALL convertFromRgb64(uint *dest, const QRgba64 *src, int length)
{
@@ -1914,7 +1981,15 @@ static void QT_FASTCALL storeRGBA32FPMFromRGBA64PM(uchar *dest, const QRgba64 *s
d[i] = qConvertRgb64ToRgbaF32(src[i]);
}
-ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats] = {
+static void QT_FASTCALL storeCMYKFromRGBA64PM(uchar *dest, const QRgba64 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = reinterpret_cast<uint *>(dest) + index;
+ for (int i = 0; i < count; ++i)
+ d[i] = QCmyk32::fromColor(QColor(src[i])).toUint();
+}
+
+ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[] = {
nullptr,
nullptr,
nullptr,
@@ -1951,8 +2026,11 @@ ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats] = {
storeRGBX32FFromRGBA64PM,
storeRGBA32FFromRGBA64PM,
storeRGBA32FPMFromRGBA64PM,
+ storeCMYKFromRGBA64PM,
};
+static_assert(std::size(qStoreFromRGBA64PM) == QImage::NImageFormats);
+
#if QT_CONFIG(raster_fp)
static void QT_FASTCALL convertToRgbaF32(QRgbaFloat32 *dest, const uint *src, int length)
{
@@ -1998,7 +2076,16 @@ static const QRgbaFloat32 * QT_FASTCALL convertRGB30ToRGBA32F(QRgbaFloat32 *buff
return buffer;
}
-ConvertToFPFunc qConvertToRGBA32F[QImage::NImageFormats] = {
+static const QRgbaFloat32 * QT_FASTCALL convertCMYKToRGBA32F(QRgbaFloat32 *buffer, const uint *src, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = QRgbaFloat32::fromArgb32(QCmyk32::fromCmyk32(src[i]).toColor().rgba());
+
+ return buffer;
+}
+
+ConvertToFPFunc qConvertToRGBA32F[] = {
nullptr,
convertIndexedTo<QRgbaFloat32>,
convertIndexedTo<QRgbaFloat32>,
@@ -2035,8 +2122,11 @@ ConvertToFPFunc qConvertToRGBA32F[QImage::NImageFormats] = {
nullptr,
nullptr,
nullptr,
+ convertCMYKToRGBA32F,
};
+static_assert(std::size(qConvertToRGBA32F) == QImage::NImageFormats);
+
static const QRgbaFloat32 *QT_FASTCALL fetchRGBX64ToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
const QList<QRgb> *, QDitherInfo *)
{
@@ -2101,7 +2191,17 @@ static const QRgbaFloat32 *QT_FASTCALL fetchRGBA32F(QRgbaFloat32 *, const uchar
return s;
}
-FetchAndConvertPixelsFuncFP qFetchToRGBA32F[QImage::NImageFormats] = {
+static const QRgbaFloat32 *QT_FASTCALL fetchCMYKToRGBA32F(QRgbaFloat32 *buffer, const uchar *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ const uint *s = reinterpret_cast<const uint *>(src) + index;
+ for (int i = 0; i < count; ++i)
+ buffer[i] = QRgbaFloat32::fromArgb32(QCmyk32::fromCmyk32(s[i]).toColor().rgba());
+
+ return buffer;
+}
+
+FetchAndConvertPixelsFuncFP qFetchToRGBA32F[] = {
nullptr,
fetchIndexedToRGBA32F<QPixelLayout::BPP1MSB>,
fetchIndexedToRGBA32F<QPixelLayout::BPP1LSB>,
@@ -2138,8 +2238,11 @@ FetchAndConvertPixelsFuncFP qFetchToRGBA32F[QImage::NImageFormats] = {
fetchRGBA32F,
fetchRGBA32FToRGBA32F,
fetchRGBA32F,
+ fetchCMYKToRGBA32F,
};
+static_assert(std::size(qFetchToRGBA32F) == QImage::NImageFormats);
+
static void QT_FASTCALL convertFromRgba32f(uint *dest, const QRgbaFloat32 *src, int length)
{
for (int i = 0; i < length; ++i)
@@ -2276,7 +2379,17 @@ static void QT_FASTCALL storeRGBA32FPMFromRGBA32F(uchar *dest, const QRgbaFloat3
}
}
-ConvertAndStorePixelsFuncFP qStoreFromRGBA32F[QImage::NImageFormats] = {
+static void QT_FASTCALL storeCMYKFromRGBA32F(uchar *dest, const QRgbaFloat32 *src, int index, int count,
+ const QList<QRgb> *, QDitherInfo *)
+{
+ uint *d = reinterpret_cast<uint *>(dest) + index;
+ for (int i = 0; i < count; ++i) {
+ // Yikes, this really needs enablers in QColor and friends
+ d[i] = QCmyk32::fromColor(QColor(src[i].toArgb32())).toUint();
+ }
+}
+
+ConvertAndStorePixelsFuncFP qStoreFromRGBA32F[] = {
nullptr,
nullptr,
nullptr,
@@ -2313,7 +2426,11 @@ ConvertAndStorePixelsFuncFP qStoreFromRGBA32F[QImage::NImageFormats] = {
storeRGBX32FFromRGBA32F,
storeRGBA32FFromRGBA32F,
storeRGBA32FPMFromRGBA32F,
+ storeCMYKFromRGBA32F,
};
+
+static_assert(std::size(qStoreFromRGBA32F) == QImage::NImageFormats);
+
#endif // QT_CONFIG(raster_fp)
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpixellayout_p.h b/src/gui/painting/qpixellayout_p.h
index 45f6c15365..14f19f4e74 100644
--- a/src/gui/painting/qpixellayout_p.h
+++ b/src/gui/painting/qpixellayout_p.h
@@ -321,12 +321,12 @@ struct QPixelLayout
extern ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats];
#if QT_CONFIG(raster_fp)
-extern ConvertToFPFunc qConvertToRGBA32F[QImage::NImageFormats];
-extern FetchAndConvertPixelsFuncFP qFetchToRGBA32F[QImage::NImageFormats];
-extern ConvertAndStorePixelsFuncFP qStoreFromRGBA32F[QImage::NImageFormats];
+extern ConvertToFPFunc qConvertToRGBA32F[];
+extern FetchAndConvertPixelsFuncFP qFetchToRGBA32F[];
+extern ConvertAndStorePixelsFuncFP qStoreFromRGBA32F[];
#endif
-extern QPixelLayout qPixelLayouts[QImage::NImageFormats];
+extern QPixelLayout qPixelLayouts[];
extern MemRotateFunc qMemRotateFunctions[QPixelLayout::BPPCount][3];
diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h
index d928af650a..1d55e9ab6a 100644
--- a/src/gui/painting/qplatformbackingstore.h
+++ b/src/gui/painting/qplatformbackingstore.h
@@ -36,7 +36,6 @@ class QPlatformGraphicsBuffer;
class QRhi;
class QRhiTexture;
class QRhiResourceUpdateBatch;
-class QRhiSwapChain;
struct Q_GUI_EXPORT QPlatformBackingStoreRhiConfig
{
@@ -94,7 +93,8 @@ public:
enum Flag {
StacksOnTop = 0x01,
TextureIsSrgb = 0x02,
- NeedsPremultipliedAlphaBlending = 0x04
+ NeedsPremultipliedAlphaBlending = 0x04,
+ MirrorVertically = 0x08
};
Q_DECLARE_FLAGS(Flags, Flag)
@@ -173,7 +173,6 @@ public:
void setRhiConfig(const QPlatformBackingStoreRhiConfig &config);
QRhi *rhi() const;
- QRhiSwapChain *rhiSwapChain() const;
void surfaceAboutToBeDestroyed();
void graphicsDeviceReportedLost();
diff --git a/src/gui/painting/qpolygon.cpp b/src/gui/painting/qpolygon.cpp
index a3a89d7504..d615245eb4 100644
--- a/src/gui/painting/qpolygon.cpp
+++ b/src/gui/painting/qpolygon.cpp
@@ -419,12 +419,7 @@ QRect QPolygon::boundingRect() const
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QPolygon &a)
{
- QDebugStateSaver saver(dbg);
- dbg.nospace() << "QPolygon(";
- for (int i = 0; i < a.size(); ++i)
- dbg.nospace() << a.at(i);
- dbg.nospace() << ')';
- return dbg;
+ return QtPrivate::printSequentialContainer(dbg, "QPolygon", a);
}
#endif
@@ -702,13 +697,7 @@ QDataStream &operator>>(QDataStream &s, QPolygon &a)
QDataStream &operator<<(QDataStream &s, const QPolygonF &a)
{
- quint32 len = a.size();
- uint i;
-
- s << len;
- for (i = 0; i < len; ++i)
- s << a.at(i);
- return s;
+ return s << static_cast<const QList<QPointF> &>(a);
}
/*!
@@ -723,29 +712,14 @@ QDataStream &operator<<(QDataStream &s, const QPolygonF &a)
QDataStream &operator>>(QDataStream &s, QPolygonF &a)
{
- quint32 len;
- uint i;
-
- s >> len;
- a.reserve(a.size() + (int)len);
- QPointF p;
- for (i = 0; i < len; ++i) {
- s >> p;
- a.insert(i, p);
- }
- return s;
+ return s >> static_cast<QList<QPointF> &>(a);
}
#endif //QT_NO_DATASTREAM
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QPolygonF &a)
{
- QDebugStateSaver saver(dbg);
- dbg.nospace() << "QPolygonF(";
- for (int i = 0; i < a.size(); ++i)
- dbg.nospace() << a.at(i);
- dbg.nospace() << ')';
- return dbg;
+ return QtPrivate::printSequentialContainer(dbg, "QPolygonF", a);
}
#endif
diff --git a/src/gui/painting/qrasterbackingstore.cpp b/src/gui/painting/qrasterbackingstore.cpp
index c0df8088d4..3b3ef2fd2e 100644
--- a/src/gui/painting/qrasterbackingstore.cpp
+++ b/src/gui/painting/qrasterbackingstore.cpp
@@ -67,7 +67,7 @@ void QRasterBackingStore::beginPaint(const QRegion &region)
if (m_image.devicePixelRatio() != nativeWindowDevicePixelRatio || m_image.size() != effectiveBufferSize) {
m_image = QImage(effectiveBufferSize, format());
m_image.setDevicePixelRatio(nativeWindowDevicePixelRatio);
- if (m_image.format() == QImage::Format_ARGB32_Premultiplied)
+ if (m_image.hasAlphaChannel())
m_image.fill(Qt::transparent);
}
diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp
index 94f1f31e6a..8b712ee46d 100644
--- a/src/gui/painting/qregion.cpp
+++ b/src/gui/painting/qregion.cpp
@@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE
contains() a QPoint or QRect. The bounding rectangle can be found
with boundingRect().
- Iteration over the region (with begin(), end(), or C++11
+ Iteration over the region (with begin(), end(), or
ranged-for loops) gives a decomposition of the region into
rectangles.
diff --git a/src/gui/painting/qrgbafloat.h b/src/gui/painting/qrgbafloat.h
index 160623eb1e..da74328f71 100644
--- a/src/gui/painting/qrgbafloat.h
+++ b/src/gui/painting/qrgbafloat.h
@@ -61,19 +61,19 @@ public:
constexpr bool isOpaque() const { return a >= FastType(1.0f); }
constexpr bool isTransparent() const { return a <= FastType(0.0f); }
- constexpr FastType red() const { return r; }
- constexpr FastType green() const { return g; }
- constexpr FastType blue() const { return b; }
- constexpr FastType alpha() const { return a; }
- void setRed(FastType _red) { r = F(_red); }
- void setGreen(FastType _green) { g = F(_green); }
- void setBlue(FastType _blue) { b = F(_blue); }
- void setAlpha(FastType _alpha) { a = F(_alpha); }
-
- constexpr FastType redNormalized() const { return clamp01(r); }
- constexpr FastType greenNormalized() const { return clamp01(g); }
- constexpr FastType blueNormalized() const { return clamp01(b); }
- constexpr FastType alphaNormalized() const { return clamp01(a); }
+ constexpr float red() const { return r; }
+ constexpr float green() const { return g; }
+ constexpr float blue() const { return b; }
+ constexpr float alpha() const { return a; }
+ void setRed(float _red) { r = F(_red); }
+ void setGreen(float _green) { g = F(_green); }
+ void setBlue(float _blue) { b = F(_blue); }
+ void setAlpha(float _alpha) { a = F(_alpha); }
+
+ constexpr float redNormalized() const { return clamp01(r); }
+ constexpr float greenNormalized() const { return clamp01(g); }
+ constexpr float blueNormalized() const { return clamp01(b); }
+ constexpr float alphaNormalized() const { return clamp01(a); }
constexpr quint8 red8() const { return qRound(redNormalized() * FastType(255.0f)); }
constexpr quint8 green8() const { return qRound(greenNormalized() * FastType(255.0f)); }
diff --git a/src/gui/painting/qrgbafloat.qdoc b/src/gui/painting/qrgbafloat.qdoc
index f41064df38..3ec0d209f4 100644
--- a/src/gui/painting/qrgbafloat.qdoc
+++ b/src/gui/painting/qrgbafloat.qdoc
@@ -33,7 +33,7 @@
*/
/*!
- \fn template<typename F> QRgbaFloat<F>::fromRgba64(quint16 r, quint16 g, quint16 b, quint16 a)
+ \fn template<typename F> QRgbaFloat QRgbaFloat<F>::fromRgba64(quint16 red, quint16 green, quint16 blue, quint16 alpha)
Constructs a QRgbaFloat value from the four 16-bit integer color channels \a red, \a green, \a blue and \a alpha.
@@ -41,7 +41,7 @@
*/
/*!
- \fn template<typename F> QRgbaFloat<F>::fromRgba(quint8 red, quint8 green, quint8 blue, quint8 alpha)
+ \fn template<typename F> QRgbaFloat QRgbaFloat<F>::fromRgba(quint8 red, quint8 green, quint8 blue, quint8 alpha)
Constructs a QRgbaFloat value from the four 8-bit color channels \a red, \a green, \a blue and \a alpha.
@@ -49,7 +49,7 @@
*/
/*!
- \fn template<typename F> QRgbaFloat<F>::fromArgb32(uint rgb)
+ \fn template<typename F> QRgbaFloat QRgbaFloat<F>::fromArgb32(uint rgb)
Constructs a QRgbaFloat value from the 32bit ARGB value \a rgb.
@@ -81,7 +81,7 @@
*/
/*!
- \fn template<typename F> void QRgbaFloat<F>::setRed(QRgbaFloat::FastType red)
+ \fn template<typename F> void QRgbaFloat<F>::setRed(float red)
Sets the red color component of this color to \a red.
@@ -97,7 +97,7 @@
*/
/*!
- \fn template<typename F> void QRgbaFloat<F>::setGreen(QRgbaFloat::FastType green)
+ \fn template<typename F> void QRgbaFloat<F>::setGreen(float green)
Sets the green color component of this color to \a green.
@@ -113,7 +113,7 @@
*/
/*!
- \fn template<typename F> void QRgbaFloat<F>::setBlue(QRgbaFloat::FastType blue)
+ \fn template<typename F> void QRgbaFloat<F>::setBlue(float blue)
Sets the blue color component of this color to \a blue.
@@ -129,7 +129,7 @@
*/
/*!
- \fn template<typename F> void QRgbaFloat<F>::setAlpha(QRgbaFloat::FastType alpha)
+ \fn template<typename F> void QRgbaFloat<F>::setAlpha(float alpha)
Sets the alpha of this color to \a alpha.
diff --git a/src/gui/painting/qrhibackingstore.cpp b/src/gui/painting/qrhibackingstore.cpp
index fd7045e3f6..586dfb44a4 100644
--- a/src/gui/painting/qrhibackingstore.cpp
+++ b/src/gui/painting/qrhibackingstore.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qrhibackingstore_p.h"
+#include <private/qimage_p.h>
QT_BEGIN_NAMESPACE
@@ -14,17 +15,24 @@ QRhiBackingStore::~QRhiBackingStore()
{
}
-void QRhiBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
+void QRhiBackingStore::flush(QWindow *flushedWindow, const QRegion &region, const QPoint &offset)
{
Q_UNUSED(region);
Q_UNUSED(offset);
- if (window != this->window())
+ if (flushedWindow->surfaceType() != window()->surfaceType()) {
+ qWarning() << "Cannot flush child window" << flushedWindow
+ << "with surface type" << flushedWindow->surfaceType() << ";"
+ << "Must match" << window()->surfaceType() << "of" << window();
+
+ // FIXME: Support different surface types by not tying the
+ // RHI config to the backing store itself (per window config).
return;
+ }
if (!rhi()) {
QPlatformBackingStoreRhiConfig rhiConfig;
- switch (window->surfaceType()) {
+ switch (window()->surfaceType()) {
case QSurface::OpenGLSurface:
rhiConfig.setApi(QPlatformBackingStoreRhiConfig::OpenGL);
break;
@@ -40,7 +48,21 @@ void QRhiBackingStore::flush(QWindow *window, const QRegion &region, const QPoin
static QPlatformTextureList emptyTextureList;
bool translucentBackground = m_image.hasAlphaChannel();
- rhiFlush(window, window->devicePixelRatio(), region, offset, &emptyTextureList, translucentBackground);
+ rhiFlush(flushedWindow, flushedWindow->devicePixelRatio(),
+ region, offset, &emptyTextureList, translucentBackground);
+}
+
+QImage::Format QRhiBackingStore::format() const
+{
+ QImage::Format fmt = QRasterBackingStore::format();
+
+ // With render-to-texture widgets and QRhi-based flushing the backingstore
+ // image must have an alpha channel. Hence upgrading the format. Matches
+ // what other platforms (Windows, xcb) do.
+ if (QImage::toPixelFormat(fmt).alphaUsage() != QPixelFormat::UsesAlpha)
+ fmt = qt_maybeDataCompatibleAlphaVersion(fmt);
+
+ return fmt;
}
QT_END_NAMESPACE
diff --git a/src/gui/painting/qrhibackingstore_p.h b/src/gui/painting/qrhibackingstore_p.h
index 95778fa74c..f222db860f 100644
--- a/src/gui/painting/qrhibackingstore_p.h
+++ b/src/gui/painting/qrhibackingstore_p.h
@@ -26,6 +26,7 @@ public:
~QRhiBackingStore();
void flush(QWindow *window, const QRegion &region, const QPoint &offset) override;
+ QImage::Format format() const override;
};
QT_END_NAMESPACE
diff --git a/src/gui/painting/qt_attribution.json b/src/gui/painting/qt_attribution.json
index d0f2468e6a..33ed2fd5c7 100644
--- a/src/gui/painting/qt_attribution.json
+++ b/src/gui/painting/qt_attribution.json
@@ -9,7 +9,7 @@
"Description": "FreeType is a freely available software library to render fonts.",
"Homepage": "http://www.freetype.org",
"License": "Freetype Project License or GNU General Public License v2.0 only",
- "LicenseId": "FTL or GPL-2.0",
+ "LicenseId": "FTL OR GPL-2.0-only",
"LicenseFile": "../../3rdparty/freetype/LICENSE.txt",
"Copyright": "Copyright 2000-2016 by David Turner, Robert Wilhelm, and Werner Lemberg."
},
@@ -24,9 +24,9 @@
"LicenseId": "BSD-2-Clause AND Imlib2",
"License": "BSD 2-clause \"Simplified\" License and Imlib2 License",
"LicenseFile": "QIMAGETRANSFORM_LICENSE.txt",
- "Copyright": "Copyright (C) 2004, 2005 Daniel M. Duley.
- (C) Carsten Haitzler and various contributors.
- (C) Willem Monsuwe <willem@stack.nl>"
+ "Copyright": ["Copyright (C) 2004, 2005 Daniel M. Duley.",
+ "(C) Carsten Haitzler and various contributors.",
+ "(C) Willem Monsuwe <willem@stack.nl>"]
},
{
"Id": "xserverhelper",
@@ -40,7 +40,7 @@
"License": "X11 License and Historical Permission Notice and Disclaimer",
"LicenseId": "X11 AND HPND",
"LicenseFile": "XCONSORTIUM_LICENSE.txt",
- "Copyright": "Copyright (c) 1987, 1988 X Consortium
-Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts."
+ "Copyright": ["Copyright (c) 1987, 1988 X Consortium",
+ "Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts."]
}
]
diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp
index 6c49cd35ea..df57d2c190 100644
--- a/src/gui/painting/qtransform.cpp
+++ b/src/gui/painting/qtransform.cpp
@@ -54,7 +54,7 @@ static void nanWarning(const char *func)
if (t == TxProject) { \
qreal w = (m_matrix[0][2] * FX_ + m_matrix[1][2] * FY_ + m_matrix[2][2]); \
if (w < qreal(Q_NEAR_CLIP)) w = qreal(Q_NEAR_CLIP); \
- w = 1./w; \
+ w = qreal(1.)/w; \
nx *= w; \
ny *= w; \
} \
@@ -358,7 +358,7 @@ QTransform &QTransform::translate(qreal dx, qreal dy)
if (dx == 0 && dy == 0)
return *this;
#ifndef QT_NO_DEBUG
- if (qIsNaN(dx) | qIsNaN(dy)) {
+ if (qIsNaN(dx) || qIsNaN(dy)) {
nanWarning("translate");
return *this;
}
@@ -401,7 +401,7 @@ QTransform &QTransform::translate(qreal dx, qreal dy)
QTransform QTransform::fromTranslate(qreal dx, qreal dy)
{
#ifndef QT_NO_DEBUG
- if (qIsNaN(dx) | qIsNaN(dy)) {
+ if (qIsNaN(dx) || qIsNaN(dy)) {
nanWarning("fromTranslate");
return QTransform();
}
@@ -426,7 +426,7 @@ QTransform & QTransform::scale(qreal sx, qreal sy)
if (sx == 1 && sy == 1)
return *this;
#ifndef QT_NO_DEBUG
- if (qIsNaN(sx) | qIsNaN(sy)) {
+ if (qIsNaN(sx) || qIsNaN(sy)) {
nanWarning("scale");
return *this;
}
@@ -467,7 +467,7 @@ QTransform & QTransform::scale(qreal sx, qreal sy)
QTransform QTransform::fromScale(qreal sx, qreal sy)
{
#ifndef QT_NO_DEBUG
- if (qIsNaN(sx) | qIsNaN(sy)) {
+ if (qIsNaN(sx) || qIsNaN(sy)) {
nanWarning("fromScale");
return QTransform();
}
@@ -492,7 +492,7 @@ QTransform & QTransform::shear(qreal sh, qreal sv)
if (sh == 0 && sv == 0)
return *this;
#ifndef QT_NO_DEBUG
- if (qIsNaN(sh) | qIsNaN(sv)) {
+ if (qIsNaN(sh) || qIsNaN(sv)) {
nanWarning("shear");
return *this;
}
@@ -1145,30 +1145,8 @@ QPoint QTransform::map(const QPoint &p) const
qreal x = 0, y = 0;
TransformationType t = inline_type();
- switch(t) {
- case TxNone:
- x = fx;
- y = fy;
- break;
- case TxTranslate:
- x = fx + m_matrix[2][0];
- y = fy + m_matrix[2][1];
- break;
- case TxScale:
- x = m_matrix[0][0] * fx + m_matrix[2][0];
- y = m_matrix[1][1] * fy + m_matrix[2][1];
- break;
- case TxRotate:
- case TxShear:
- case TxProject:
- x = m_matrix[0][0] * fx + m_matrix[1][0] * fy + m_matrix[2][0];
- y = m_matrix[0][1] * fx + m_matrix[1][1] * fy + m_matrix[2][1];
- if (t == TxProject) {
- qreal w = 1./(m_matrix[0][2] * fx + m_matrix[1][2] * fy + m_matrix[2][2]);
- x *= w;
- y *= w;
- }
- }
+ MAP(fx, fy, x, y);
+
return QPoint(qRound(x), qRound(y));
}
@@ -1196,30 +1174,8 @@ QPointF QTransform::map(const QPointF &p) const
qreal x = 0, y = 0;
TransformationType t = inline_type();
- switch(t) {
- case TxNone:
- x = fx;
- y = fy;
- break;
- case TxTranslate:
- x = fx + m_matrix[2][0];
- y = fy + m_matrix[2][1];
- break;
- case TxScale:
- x = m_matrix[0][0] * fx + m_matrix[2][0];
- y = m_matrix[1][1] * fy + m_matrix[2][1];
- break;
- case TxRotate:
- case TxShear:
- case TxProject:
- x = m_matrix[0][0] * fx + m_matrix[1][0] * fy + m_matrix[2][0];
- y = m_matrix[0][1] * fx + m_matrix[1][1] * fy + m_matrix[2][1];
- if (t == TxProject) {
- qreal w = 1./(m_matrix[0][2] * fx + m_matrix[1][2] * fy + m_matrix[2][2]);
- x *= w;
- y *= w;
- }
- }
+ MAP(fx, fy, x, y);
+
return QPointF(x, y);
}
@@ -1267,41 +1223,9 @@ QLine QTransform::map(const QLine &l) const
qreal x1 = 0, y1 = 0, x2 = 0, y2 = 0;
TransformationType t = inline_type();
- switch(t) {
- case TxNone:
- x1 = fx1;
- y1 = fy1;
- x2 = fx2;
- y2 = fy2;
- break;
- case TxTranslate:
- x1 = fx1 + m_matrix[2][0];
- y1 = fy1 + m_matrix[2][1];
- x2 = fx2 + m_matrix[2][0];
- y2 = fy2 + m_matrix[2][1];
- break;
- case TxScale:
- x1 = m_matrix[0][0] * fx1 + m_matrix[2][0];
- y1 = m_matrix[1][1] * fy1 + m_matrix[2][1];
- x2 = m_matrix[0][0] * fx2 + m_matrix[2][0];
- y2 = m_matrix[1][1] * fy2 + m_matrix[2][1];
- break;
- case TxRotate:
- case TxShear:
- case TxProject:
- x1 = m_matrix[0][0] * fx1 + m_matrix[1][0] * fy1 + m_matrix[2][0];
- y1 = m_matrix[0][1] * fx1 + m_matrix[1][1] * fy1 + m_matrix[2][1];
- x2 = m_matrix[0][0] * fx2 + m_matrix[1][0] * fy2 + m_matrix[2][0];
- y2 = m_matrix[0][1] * fx2 + m_matrix[1][1] * fy2 + m_matrix[2][1];
- if (t == TxProject) {
- qreal w = 1./(m_matrix[0][2] * fx1 + m_matrix[1][2] * fy1 + m_matrix[2][2]);
- x1 *= w;
- y1 *= w;
- w = 1./(m_matrix[0][2] * fx2 + m_matrix[1][2] * fy2 + m_matrix[2][2]);
- x2 *= w;
- y2 *= w;
- }
- }
+ MAP(fx1, fy1, x1, y1);
+ MAP(fx2, fy2, x2, y2);
+
return QLine(qRound(x1), qRound(y1), qRound(x2), qRound(y2));
}
@@ -1326,66 +1250,12 @@ QLineF QTransform::map(const QLineF &l) const
qreal x1 = 0, y1 = 0, x2 = 0, y2 = 0;
TransformationType t = inline_type();
- switch(t) {
- case TxNone:
- x1 = fx1;
- y1 = fy1;
- x2 = fx2;
- y2 = fy2;
- break;
- case TxTranslate:
- x1 = fx1 + m_matrix[2][0];
- y1 = fy1 + m_matrix[2][1];
- x2 = fx2 + m_matrix[2][0];
- y2 = fy2 + m_matrix[2][1];
- break;
- case TxScale:
- x1 = m_matrix[0][0] * fx1 + m_matrix[2][0];
- y1 = m_matrix[1][1] * fy1 + m_matrix[2][1];
- x2 = m_matrix[0][0] * fx2 + m_matrix[2][0];
- y2 = m_matrix[1][1] * fy2 + m_matrix[2][1];
- break;
- case TxRotate:
- case TxShear:
- case TxProject:
- x1 = m_matrix[0][0] * fx1 + m_matrix[1][0] * fy1 + m_matrix[2][0];
- y1 = m_matrix[0][1] * fx1 + m_matrix[1][1] * fy1 + m_matrix[2][1];
- x2 = m_matrix[0][0] * fx2 + m_matrix[1][0] * fy2 + m_matrix[2][0];
- y2 = m_matrix[0][1] * fx2 + m_matrix[1][1] * fy2 + m_matrix[2][1];
- if (t == TxProject) {
- qreal w = 1./(m_matrix[0][2] * fx1 + m_matrix[1][2] * fy1 + m_matrix[2][2]);
- x1 *= w;
- y1 *= w;
- w = 1./(m_matrix[0][2] * fx2 + m_matrix[1][2] * fy2 + m_matrix[2][2]);
- x2 *= w;
- y2 *= w;
- }
- }
- return QLineF(x1, y1, x2, y2);
-}
+ MAP(fx1, fy1, x1, y1);
+ MAP(fx2, fy2, x2, y2);
-static QPolygonF mapProjective(const QTransform &transform, const QPolygonF &poly)
-{
- if (poly.size() == 0)
- return poly;
-
- if (poly.size() == 1)
- return QPolygonF() << transform.map(poly.at(0));
-
- QPainterPath path;
- path.addPolygon(poly);
-
- path = transform.map(path);
-
- QPolygonF result;
- const int elementCount = path.elementCount();
- result.reserve(elementCount);
- for (int i = 0; i < elementCount; ++i)
- result << path.elementAt(i);
- return result;
+ return QLineF(x1, y1, x2, y2);
}
-
/*!
\fn QPolygonF operator *(const QPolygonF &polygon, const QTransform &matrix)
\since 4.3
@@ -1419,9 +1289,6 @@ QPolygonF QTransform::map(const QPolygonF &a) const
if (t <= TxTranslate)
return a.translated(m_matrix[2][0], m_matrix[2][1]);
- if (t >= QTransform::TxProject)
- return mapProjective(*this, a);
-
int size = a.size();
int i;
QPolygonF p(size);
@@ -1449,9 +1316,6 @@ QPolygon QTransform::map(const QPolygon &a) const
if (t <= TxTranslate)
return a.translated(qRound(m_matrix[2][0]), qRound(m_matrix[2][1]));
- if (t >= QTransform::TxProject)
- return mapProjective(*this, QPolygonF(a)).toPolygon();
-
int size = a.size();
int i;
QPolygon p(size);
@@ -1882,14 +1746,6 @@ void QTransform::setMatrix(qreal m11, qreal m12, qreal m13,
m_dirty = TxProject;
}
-static inline bool needsPerspectiveClipping(const QRectF &rect, const QTransform &transform)
-{
- const qreal wx = qMin(transform.m13() * rect.left(), transform.m13() * rect.right());
- const qreal wy = qMin(transform.m23() * rect.top(), transform.m23() * rect.bottom());
-
- return wx + wy + transform.m33() < Q_NEAR_CLIP;
-}
-
QRect QTransform::mapRect(const QRect &rect) const
{
TransformationType t = inline_type();
@@ -1910,8 +1766,7 @@ QRect QTransform::mapRect(const QRect &rect) const
y -= h;
}
return QRect(x, y, w, h);
- } else if (t < TxProject || !needsPerspectiveClipping(rect, *this)) {
- // see mapToPolygon for explanations of the algorithm.
+ } else {
qreal x = 0, y = 0;
MAP(rect.left(), rect.top(), x, y);
qreal xmin = x;
@@ -1933,11 +1788,7 @@ QRect QTransform::mapRect(const QRect &rect) const
ymin = qMin(ymin, y);
xmax = qMax(xmax, x);
ymax = qMax(ymax, y);
- return QRect(qRound(xmin), qRound(ymin), qRound(xmax)-qRound(xmin), qRound(ymax)-qRound(ymin));
- } else {
- QPainterPath path;
- path.addRect(rect);
- return map(path).boundingRect().toRect();
+ return QRectF(xmin, ymin, xmax-xmin, ymax-ymin).toRect();
}
}
@@ -1980,7 +1831,7 @@ QRectF QTransform::mapRect(const QRectF &rect) const
y -= h;
}
return QRectF(x, y, w, h);
- } else if (t < TxProject || !needsPerspectiveClipping(rect, *this)) {
+ } else {
qreal x = 0, y = 0;
MAP(rect.x(), rect.y(), x, y);
qreal xmin = x;
@@ -2003,10 +1854,6 @@ QRectF QTransform::mapRect(const QRectF &rect) const
xmax = qMax(xmax, x);
ymax = qMax(ymax, y);
return QRectF(xmin, ymin, xmax-xmin, ymax - ymin);
- } else {
- QPainterPath path;
- path.addRect(rect);
- return map(path).boundingRect();
}
}
diff --git a/src/gui/platform/android/qandroidnativeinterface.cpp b/src/gui/platform/android/qandroidnativeinterface.cpp
index 1bc718cbf1..c1c4b7149f 100644
--- a/src/gui/platform/android/qandroidnativeinterface.cpp
+++ b/src/gui/platform/android/qandroidnativeinterface.cpp
@@ -35,6 +35,20 @@ QOffscreenSurface *QNativeInterface::QAndroidOffscreenSurface::fromNative(ANati
&QAndroidOffScreenIntegration::createOffscreenSurface>(nativeSurface);
}
-QT_DEFINE_PRIVATE_NATIVE_INTERFACE(QAndroidScreen);
+/*!
+ \class QNativeInterface::QAndroidScreen
+ \since 6.7
+ \brief Native interface to a screen.
+
+ Accessed through QScreen::nativeInterface().
+ \inmodule QtGui
+ \ingroup native-interfaces
+ \ingroup native-interfaces-qscreen
+*/
+/*!
+ \fn int QNativeInterface::QAndroidScreen::displayId() const;
+ \return the id of the underlying Android display.
+*/
+QT_DEFINE_NATIVE_INTERFACE(QAndroidScreen);
QT_END_NAMESPACE
diff --git a/src/gui/platform/darwin/qappleiconengine.mm b/src/gui/platform/darwin/qappleiconengine.mm
new file mode 100644
index 0000000000..7e0ed184dc
--- /dev/null
+++ b/src/gui/platform/darwin/qappleiconengine.mm
@@ -0,0 +1,464 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qappleiconengine_p.h"
+
+#if defined(Q_OS_MACOS)
+# include <AppKit/AppKit.h>
+#elif defined(QT_PLATFORM_UIKIT)
+# include <UIKit/UIKit.h>
+#endif
+
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qpalette.h>
+#include <QtGui/qstylehints.h>
+
+#include <QtGui/private/qcoregraphics_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+namespace {
+auto *loadImage(const QString &iconName)
+{
+ static constexpr std::pair<QLatin1StringView, NSString *> iconMap[] = {
+ {"address-book-new"_L1, @"book.closed"},
+ {"application-exit"_L1, @"xmark.circle"},
+ {"appointment-new"_L1, @"calendar.badge.plus"},
+ {"call-start"_L1, @"phone.arrow.up.right"},
+ {"call-stop"_L1, @"phone.down"},
+ {"contact-new"_L1, @"person.crop.circle.badge.plus"},
+ {"document-new"_L1, @"doc.badge.plus"},
+ {"document-open"_L1, @"folder"},
+ {"document-open-recent"_L1, @"doc.badge.clock"},
+ {"document-page-setup"_L1, @"doc.badge.gearshape"},
+ {"document-print"_L1, @"printer"},
+ //{"document-print-preview"_L1, @""},
+ {"document-properties"_L1, @"doc.badge.ellipsis"},
+ //{"document-revert"_L1, @""},
+ {"document-save"_L1, @"square.and.arrow.down"},
+ //{"document-save-as"_L1, @""},
+ {"document-send"_L1, @"paperplane"},
+ {"edit-clear"_L1, @"xmark.circle"},
+ {"edit-copy"_L1, @"doc.on.doc"},
+ {"edit-cut"_L1, @"scissors"},
+ {"edit-delete"_L1, @"delete.left"},
+ {"edit-find"_L1, @"magnifyingglass"},
+ //{"edit-find-replace"_L1, @"arrow.up.left.and.down.right.magnifyingglass"},
+ {"edit-paste"_L1, @"clipboard"},
+ {"edit-redo"_L1, @"arrowshape.turn.up.right"},
+ //{"edit-select-all"_L1, @""},
+ {"edit-undo"_L1, @"arrowshape.turn.up.left"},
+ {"folder-new"_L1, @"folder.badge.plus"},
+ {"format-indent-less"_L1, @"decrease.indent"},
+ {"format-indent-more"_L1, @"increase.indent"},
+ {"format-justify-center"_L1, @"text.aligncenter"},
+ {"format-justify-fill"_L1, @"text.justify"},
+ {"format-justify-left"_L1, @"text.justify.left"},
+ {"format-justify-right"_L1, @"text.justify.right"},
+ {"format-text-direction-ltr"_L1, @"text.justify.leading"},
+ {"format-text-direction-rtl"_L1, @"text.justify.trailing"},
+ {"format-text-bold"_L1, @"bold"},
+ {"format-text-italic"_L1, @"italic"},
+ {"format-text-underline"_L1, @"underline"},
+ {"format-text-strikethrough"_L1, @"strikethrough"},
+ //{"go-bottom"_L1, @""},
+ {"go-down"_L1, @"arrowshape.down"},
+ {"go-first"_L1, @"increase.indent"},
+ {"go-home"_L1, @"house"},
+ //{"go-jump"_L1, @""},
+ //{"go-last"_L1, @""},
+ {"go-next"_L1, @"arrowshape.right"},
+ {"go-previous"_L1, @"arrowshape.left"},
+ //{"go-top"_L1, @""},
+ {"go-up"_L1, @"arrowshape.up"},
+ {"help-about"_L1, @"info.circle"},
+ //{"help-contents"_L1, @""},
+ {"help-faq"_L1, @"questionmark.app"},
+ {"insert-image"_L1, @"photo.badge.plus"},
+ {"insert-link"_L1, @"link.badge.plus"},
+ //{"insert-object"_L1, @""},
+ {"insert-text"_L1, @"textformat"},
+ {"list-add"_L1, @"plus.circle"},
+ {"list-remove"_L1, @"minus.circle"},
+ {"mail-forward"_L1, @"arrowshape.turn.up.right"},
+ {"mail-mark-important"_L1, @"star"},
+ {"mail-mark-junk"_L1, @"xmark.bin"},
+ {"mail-mark-notjunk"_L1, @"trash.slash"},
+ {"mail-mark-read"_L1, @"envelope.open"},
+ {"mail-mark-unread"_L1, @"envelope.fill"},
+ {"mail-message-new"_L1, @"square.and.pencil"},
+ {"mail-reply-all"_L1, @"arrowshape.turn.up.left.2"},
+ {"mail-reply-sender"_L1, @"arrowshape.turn.up.left"},
+ {"mail-send"_L1, @"paperplane"},
+ {"mail-send-receive"_L1, @"envelope.arrow.triangle.branch"},
+ {"media-eject"_L1, @"eject"},
+ {"media-playback-pause"_L1, @"pause"},
+ {"media-playback-start"_L1, @"play"},
+ {"media-playback-stop"_L1, @"stop"},
+ {"media-record"_L1, @"record.circle"},
+ {"media-seek-backward"_L1, @"backward"},
+ {"media-seek-forward"_L1, @"forward"},
+ {"media-skip-backward"_L1, @"backward.end.alt"},
+ {"media-skip-forward"_L1, @"forward.end.alt"},
+ {"object-flip-horizontal"_L1, @"rectangle.landscape.rotate"},
+ {"object-flip-vertical"_L1, @"rectangle.portrait.rotate"},
+ {"object-rotate-left"_L1, @"rotate.left"},
+ {"object-rotate-right"_L1, @"rotate.right"},
+ {"process-stop"_L1, @"stop.circle"},
+ {"system-lock-screen"_L1, @"lock.display"},
+ {"system-log-out"_L1, @"door.left.hand.open"},
+ //{"system-run"_L1, @""},
+ {"system-search"_L1, @"magnifyingglass"},
+ //{"system-reboot"_L1, @""},
+ {"system-shutdown"_L1, @"power"},
+ //{"tools-check-spelling"_L1, @""},
+ {"view-fullscreen"_L1, @"arrow.up.left.and.arrow.down.right"},
+ {"view-refresh"_L1, @"arrow.clockwise"},
+ {"view-restore"_L1, @"arrow.down.right.and.arrow.up.left"},
+ //{"view-sort-ascending"_L1, @""},
+ //{"view-sort-descending"_L1, @""},
+ {"window-close"_L1, @"xmark.circle"},
+ {"window-new"_L1, @"macwindow.badge.plus"},
+ {"zoom-fit-best"_L1, @"square.arrowtriangle.4.outward"},
+ {"zoom-in"_L1, @"plus.magnifyingglass"},
+ //{"zoom-original"_L1, @""},
+ {"zoom-out"_L1, @"minus.magnifyingglass"},
+ {"process-working"_L1, @"circle.dotted"},
+ //{"accessories-calculator"_L1, @""},
+ //{"accessories-character-map"_L1, @""},
+ {"accessories-dictionary"_L1, @"character.book.closed"},
+ {"accessories-text-editor"_L1, @"textformat"},
+ {"help-browser"_L1, @"folder.badge.questionmark"},
+ {"multimedia-volume-control"_L1, @"speaker.wave.3"},
+ {"preferences-desktop-accessibility"_L1, @"accessibility"},
+ //{"preferences-desktop-font"_L1, @""},
+ {"preferences-desktop-keyboard"_L1, @"keyboard.badge.ellipsis"},
+ //{"preferences-desktop-locale"_L1, @""},
+ //{"preferences-desktop-multimedia"_L1, @""},
+ //{"preferences-desktop-screensaver"_L1, @""},
+ //{"preferences-desktop-theme"_L1, @""},
+ //{"preferences-desktop-wallpaper"_L1, @""},
+ {"system-file-manager"_L1, @"folder.badge.gearshape"},
+ //{"system-software-install"_L1, @""},
+ //{"system-software-update"_L1, @""}, d
+ //{"utilities-system-monitor"_L1, @""},
+ {"utilities-terminal"_L1, @"apple.terminal"},
+ //{"applications-accessories"_L1, @""},
+ //{"applications-development"_L1, @""},
+ //{"applications-engineering"_L1, @""},
+ {"applications-games"_L1, @"gamecontroller"},
+ //{"applications-graphics"_L1, @""},
+ {"applications-internet"_L1, @"network"},
+ {"applications-multimedia"_L1, @"tv.and.mediabox"},
+ //{"applications-office"_L1, @""},
+ //{"applications-other"_L1, @""},
+ {"applications-science"_L1, @"atom"},
+ //{"applications-system"_L1, @""},
+ //{"applications-utilities"_L1, @""},
+ {"preferences-desktop"_L1, @"menubar.dock.rectangle"},
+ //{"preferences-desktop-peripherals"_L1, @""},
+ //{"preferences-desktop-personal"_L1, @""},
+ //{"preferences-other"_L1, @""},
+ //{"preferences-system"_L1, @""},
+ {"preferences-system-network"_L1, @"network"},
+ {"system-help"_L1, @"questionmark.diamond"},
+ {"audio-card"_L1, @"waveform.circle"},
+ {"audio-input-microphone"_L1, @"mic"},
+ {"battery"_L1, @"battery.100percent"},
+ {"camera-photo"_L1, @"camera"},
+ {"camera-video"_L1, @"video"},
+ {"camera-web"_L1, @"web.camera"},
+ {"computer"_L1, @"desktopcomputer"},
+ {"drive-harddisk"_L1, @"internaldrive"},
+ {"drive-optical"_L1, @"opticaldiscdrive"},
+ {"drive-removable-media"_L1, @"externaldrive"},
+ {"input-gaming"_L1, @"gamecontroller"}, // "games" also using this one
+ {"input-keyboard"_L1, @"keyboard"},
+ {"input-mouse"_L1, @"computermouse"},
+ {"input-tablet"_L1, @"ipad"},
+ {"media-flash"_L1, @"mediastick"},
+ //{"media-floppy"_L1, @""},
+ //{"media-optical"_L1, @""},
+ {"media-tape"_L1, @"recordingtape"},
+ //{"modem"_L1, @""},
+ {"multimedia-player"_L1, @"play.rectangle"},
+ {"network-wired"_L1, @"app.connected.to.app.below.fill"},
+ {"network-wireless"_L1, @"wifi"},
+ //{"pda"_L1, @""},
+ {"phone"_L1, @"iphone"},
+ {"printer"_L1, @"printer"},
+ {"scanner"_L1, @"scanner"},
+ {"video-display"_L1, @"play.display"},
+ //{"emblem-default"_L1, @""},
+ {"emblem-documents"_L1, @"doc.circle"},
+ {"emblem-downloads"_L1, @"arrow.down.circle"},
+ {"emblem-favorite"_L1, @"star"},
+ {"emblem-important"_L1, @"exclamationmark.bubble.circle"},
+ {"emblem-mail"_L1, @"envelope"},
+ {"emblem-photos"_L1, @"photo.stack"},
+ //{"emblem-readonly"_L1, @""},
+ {"emblem-shared"_L1, @"folder.badge.person.crop"},
+ {"emblem-symbolic-link"_L1, @"link.circle"},
+ {"emblem-synchronized"_L1, @"arrow.triangle.2.circlepath.circle"},
+ {"emblem-system"_L1, @"gear"},
+ //{"emblem-unreadable"_L1, @""},
+ {"folder"_L1, @"folder"},
+ //{"folder-remote"_L1, @""},
+ {"network-server"_L1, @"server.rack"},
+ //{"network-workgroup"_L1, @""},
+ //{"start-here"_L1, @""},
+ {"user-bookmarks"_L1, @"bookmark.circle"},
+ {"user-desktop"_L1, @"desktopcomputer"}, //"computer" also using this one
+ {"user-home"_L1, @"house"}, //"go-home" also using this one
+ {"user-trash"_L1, @"trash"},
+ {"appointment-missed"_L1, @"calendar.badge.exclamationmark"},
+ {"appointment-soon"_L1, @"calendar.badge.clock"},
+ {"audio-volume-high"_L1, @"speaker.wave.3"},
+ {"audio-volume-low"_L1, @"speaker.wave.1"},
+ {"audio-volume-medium"_L1, @"speaker.wave.2"},
+ {"audio-volume-muted"_L1, @"speaker.slash"},
+ {"battery-caution"_L1, @"minus.plus.batteryblock.exclamationmark"},
+ {"battery-low"_L1, @"battery.25percent"}, // there are different levels that can be low battery
+ {"dialog-error"_L1, @"exclamationmark.bubble"},
+ {"dialog-information"_L1, @"info.circle"},
+ {"dialog-password"_L1, @"lock"},
+ {"dialog-question"_L1, @"questionmark.circle"},
+ {"dialog-warning"_L1, @"exclamationmark.octagon"},
+ {"folder-drag-accept"_L1, @"plus.rectangle.on.folder"},
+ //{"folder-open"_L1, @""},
+ {"folder-visiting"_L1, @"folder.circle"},
+ {"image-loading"_L1, @"photo.circle"},
+ {"image-missing"_L1, @"photo"},
+ {"mail-attachment"_L1, @"paperclip"},
+ {"mail-unread"_L1, @"envelope.badge"},
+ {"mail-read"_L1, @"envelope.open"},
+ {"mail-replied"_L1, @"arrowshape.turn.up.left"},
+ //{"mail-signed"_L1, @""},
+ //{"mail-signed-verified"_L1, @""},
+ {"media-playlist-repeat"_L1, @"repet"},
+ {"media-playlist-shuffle"_L1, @"shuffle"},
+ //{"network-error"_L1, @""},
+ //{"network-idle"_L1, @""},
+ {"network-offline"_L1, @"network.slash"},
+ //{"network-receive"_L1, @""},
+ //{"network-transmit"_L1, @""},
+ //{"network-transmit-receive"_L1, @""},
+ //{"printer-error"_L1, @""},
+ {"printer-printing"_L1, @"printer.dotmatrix.filled.and.paper"}, // not sure
+ {"security-high"_L1, @"lock.shield"},
+ //{"security-medium"_L1, @""},
+ {"security-low"_L1, @"lock.trianglebadge.exclamationmark"},
+ {"software-update-available"_L1, @"arrowshape.up.circle"},
+ {"software-update-urgent"_L1, @"exclamationmark.transmission"},
+ {"sync-error"_L1, @"exclamationmark.arrow.triangle.2.circlepath"},
+ {"sync-synchronizing"_L1, @"arrow.triangle.2.circlepath"},
+ {"task-due"_L1, @"clock.badge.exclamationmark"},
+ {"task-past-due"_L1, @"clock.badge.xmark"},
+ {"user-available"_L1, @"person.crop.circle.badge.checkmark"},
+ {"user-away"_L1, @"person.crop.circle.badge.clock"},
+ //{"user-idle"_L1, @""},
+ {"user-offline"_L1, @"person.crop.circle.badge.xmark"},
+ //{"user-trash-full"_L1, @""},
+ {"weather-clear"_L1, @"sun.max"},
+ {"weather-clear-night"_L1, @"moon"},
+ {"weather-few-clouds"_L1, @"cloud.sun"},
+ {"weather-few-clouds-night"_L1, @"cloud.moon"},
+ {"weather-fog"_L1, @"cloud.fog"},
+ {"weather-overcast"_L1, @"cloud"},
+ //{"weather-severe-alert"_L1, @""},
+ {"weather-showers"_L1, @"cloud.rain"},
+ //{"weather-showers-scattered"_L1, @""},
+ {"weather-snow"_L1, @"cloud.snow"},
+ {"weather-storm"_L1, @"tropicalstorm"},
+ };
+ const auto it = std::find_if(std::begin(iconMap), std::end(iconMap), [iconName](const auto &c){
+ return c.first == iconName;
+ });
+ NSString *systemIconName = it != std::end(iconMap) ? it->second : iconName.toNSString();
+#if defined(Q_OS_MACOS)
+ return [NSImage imageWithSystemSymbolName:systemIconName accessibilityDescription:nil];
+#elif defined(QT_PLATFORM_UIKIT)
+ return [UIImage systemImageNamed:systemIconName];
+#endif
+}
+}
+
+QAppleIconEngine::QAppleIconEngine(const QString &iconName)
+ : m_iconName(iconName), m_image(loadImage(iconName))
+{
+ if (m_image)
+ [m_image retain];
+}
+
+QAppleIconEngine::~QAppleIconEngine()
+{
+ if (m_image)
+ [m_image release];
+}
+
+QIconEngine *QAppleIconEngine::clone() const
+{
+ return new QAppleIconEngine(m_iconName);
+}
+
+QString QAppleIconEngine::key() const
+{
+ return u"QAppleIconEngine"_s;
+}
+
+QString QAppleIconEngine::iconName()
+{
+ return m_iconName;
+}
+
+bool QAppleIconEngine::isNull()
+{
+ return m_image == nullptr;
+}
+
+QList<QSize> QAppleIconEngine::availableIconSizes(double aspectRatio)
+{
+ const qreal devicePixelRatio = qGuiApp->devicePixelRatio();
+ const QList<QSize> sizes = {
+ {qRound(16 * devicePixelRatio), qRound(16. * devicePixelRatio / aspectRatio)},
+ {qRound(32 * devicePixelRatio), qRound(32. * devicePixelRatio / aspectRatio)},
+ {qRound(64 * devicePixelRatio), qRound(64. * devicePixelRatio / aspectRatio)},
+ {qRound(128 * devicePixelRatio), qRound(128. * devicePixelRatio / aspectRatio)},
+ {qRound(256 * devicePixelRatio), qRound(256. * devicePixelRatio / aspectRatio)},
+ };
+ return sizes;
+}
+
+QList<QSize> QAppleIconEngine::availableSizes(QIcon::Mode, QIcon::State)
+{
+ const double aspectRatio = isNull() ? 1.0 : m_image.size.width / m_image.size.height;
+ return availableIconSizes(aspectRatio);
+}
+
+QSize QAppleIconEngine::actualSize(const QSize &size, QIcon::Mode /*mode*/, QIcon::State /*state*/)
+{
+ const double inputAspectRatio = isNull() ? 1.0 : m_image.size.width / m_image.size.height;
+ const double outputAspectRatio = size.width() / size.height();
+ QSize result = size;
+ if (outputAspectRatio > inputAspectRatio)
+ result.rwidth() = result.height() * inputAspectRatio;
+ else
+ result.rheight() = result.width() / inputAspectRatio;
+ return result;
+}
+
+QPixmap QAppleIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
+{
+ return scaledPixmap(size, mode, state, 1.0);
+}
+
+namespace {
+#if defined(Q_OS_MACOS)
+auto *configuredImage(const NSImage *image, const QColor &color)
+{
+ auto *config = [NSImageSymbolConfiguration configurationWithPointSize:48
+ weight:NSFontWeightRegular
+ scale:NSImageSymbolScaleLarge];
+ if (@available(macOS 12, *)) {
+ auto *primaryColor = [NSColor colorWithSRGBRed:color.redF()
+ green:color.greenF()
+ blue:color.blueF()
+ alpha:color.alphaF()];
+
+ auto *colorConfig = [NSImageSymbolConfiguration configurationWithHierarchicalColor:primaryColor];
+ config = [config configurationByApplyingConfiguration:colorConfig];
+ }
+
+ return [image imageWithSymbolConfiguration:config];
+}
+#elif defined(QT_PLATFORM_UIKIT)
+auto *configuredImage(const UIImage *image, const QColor &color)
+{
+ auto *config = [UIImageSymbolConfiguration configurationWithPointSize:48
+ weight:UIImageSymbolWeightRegular
+ scale:UIImageSymbolScaleLarge];
+
+ if (@available(iOS 15, *)) {
+ auto *primaryColor = [UIColor colorWithRed:color.redF()
+ green:color.greenF()
+ blue:color.blueF()
+ alpha:color.alphaF()];
+
+ auto *colorConfig = [UIImageSymbolConfiguration configurationWithHierarchicalColor:primaryColor];
+ config = [config configurationByApplyingConfiguration:colorConfig];
+ }
+ return [image imageByApplyingSymbolConfiguration:config];
+}
+#endif
+}
+
+QPixmap QAppleIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
+{
+ const quint64 cacheKey = calculateCacheKey(mode, state);
+ if (cacheKey != m_cacheKey || m_pixmap.size() != size || m_pixmap.devicePixelRatio() != scale) {
+ const QSize paintSize = actualSize(size, mode, state);
+ const QSize paintOffset = paintSize != size
+ ? (QSizeF(size - paintSize) * 0.5).toSize()
+ : QSize();
+
+ m_pixmap = QPixmap(size * scale);
+ m_pixmap.setDevicePixelRatio(scale);
+ m_pixmap.fill(Qt::transparent);
+
+ QPainter painter(&m_pixmap);
+ paint(&painter, QRect(paintOffset.width(), paintOffset.height(),
+ paintSize.width(), paintSize.height()), mode, state);
+
+ m_cacheKey = cacheKey;
+ }
+ return m_pixmap;
+}
+
+void QAppleIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
+{
+ Q_UNUSED(state);
+
+ QColor color;
+ const QPalette palette;
+ switch (mode) {
+ case QIcon::Normal:
+ color = palette.color(QPalette::Inactive, QPalette::Text);
+ break;
+ case QIcon::Disabled:
+ color = palette.color(QPalette::Disabled, QPalette::Text);
+ break;
+ case QIcon::Active:
+ color = palette.color(QPalette::Active, QPalette::Text);
+ break;
+ case QIcon::Selected:
+ color = palette.color(QPalette::Active, QPalette::HighlightedText);
+ break;
+ }
+ const auto *image = configuredImage(m_image, color);
+
+ QMacCGContext ctx(painter);
+
+#if defined(Q_OS_MACOS)
+ NSGraphicsContext *gc = [NSGraphicsContext graphicsContextWithCGContext:ctx flipped:YES];
+ [NSGraphicsContext saveGraphicsState];
+ [NSGraphicsContext setCurrentContext:gc];
+
+ const NSSize pixmapSize = NSMakeSize(rect.width(), rect.height());
+ [image setSize:pixmapSize];
+ const NSRect sourceRect = NSMakeRect(0, 0, pixmapSize.width, pixmapSize.height);
+ const NSRect iconRect = NSMakeRect(rect.x(), rect.y(), pixmapSize.width, pixmapSize.height);
+
+ [image drawInRect:iconRect fromRect:sourceRect operation:NSCompositingOperationSourceOver fraction:1.0 respectFlipped:YES hints:nil];
+ [NSGraphicsContext restoreGraphicsState];
+#elif defined(QT_PLATFORM_UIKIT)
+ UIGraphicsPushContext(ctx);
+ const CGRect cgrect = CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
+ [image drawInRect:cgrect];
+ UIGraphicsPopContext();
+#endif
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/platform/darwin/qappleiconengine_p.h b/src/gui/platform/darwin/qappleiconengine_p.h
new file mode 100644
index 0000000000..2a4ff7fc64
--- /dev/null
+++ b/src/gui/platform/darwin/qappleiconengine_p.h
@@ -0,0 +1,64 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QAPPLEICONENGINE_P_H
+#define QAPPLEICONENGINE_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/qiconengine.h>
+
+#include <QtCore/private/qcore_mac_p.h>
+
+Q_FORWARD_DECLARE_OBJC_CLASS(UIImage);
+Q_FORWARD_DECLARE_OBJC_CLASS(NSImage);
+
+QT_BEGIN_NAMESPACE
+
+class Q_GUI_EXPORT QAppleIconEngine : public QIconEngine
+{
+public:
+ QAppleIconEngine(const QString &iconName);
+ ~QAppleIconEngine();
+ QIconEngine *clone() const override;
+ QString key() const override;
+ QString iconName() override;
+ bool isNull() override;
+
+ QList<QSize> availableSizes(QIcon::Mode, QIcon::State) override;
+ QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
+ QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
+ QPixmap scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale) override;
+ void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override;
+
+ static QList<QSize> availableIconSizes(double aspectRatio = 1.0);
+
+private:
+ static constexpr quint64 calculateCacheKey(QIcon::Mode mode, QIcon::State state)
+ {
+ return (quint64(mode) << 32) | state;
+ }
+
+ const QString m_iconName;
+#if defined(Q_OS_MACOS)
+ const NSImage *m_image;
+#elif defined(QT_PLATFORM_UIKIT)
+ const UIImage *m_image;
+#endif
+ mutable QPixmap m_pixmap;
+ mutable quint64 m_cacheKey = {};
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QAPPLEICONENGINE_P_H
diff --git a/src/gui/platform/darwin/qapplekeymapper.mm b/src/gui/platform/darwin/qapplekeymapper.mm
index f7dbc1990d..b8ff5c9d6d 100644
--- a/src/gui/platform/darwin/qapplekeymapper.mm
+++ b/src/gui/platform/darwin/qapplekeymapper.mm
@@ -18,7 +18,6 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcQpaKeyMapper, "qt.qpa.keymapper");
Q_LOGGING_CATEGORY(lcQpaKeyMapperKeys, "qt.qpa.keymapper.keys");
static Qt::KeyboardModifiers swapModifiersIfNeeded(const Qt::KeyboardModifiers modifiers)
@@ -37,36 +36,6 @@ static Qt::KeyboardModifiers swapModifiersIfNeeded(const Qt::KeyboardModifiers m
return swappedModifiers;
}
-Qt::Key QAppleKeyMapper::fromNSString(Qt::KeyboardModifiers qtModifiers, NSString *characters,
- NSString *charactersIgnoringModifiers, QString &text)
-{
- if ([characters isEqualToString:@"\t"]) {
- if (qtModifiers & Qt::ShiftModifier)
- return Qt::Key_Backtab;
- return Qt::Key_Tab;
- } else if ([characters isEqualToString:@"\r"]) {
- if (qtModifiers & Qt::KeypadModifier)
- return Qt::Key_Enter;
- return Qt::Key_Return;
- }
- if ([characters length] != 0 || [charactersIgnoringModifiers length] != 0) {
- QChar ch;
- if (((qtModifiers & Qt::MetaModifier) || (qtModifiers & Qt::AltModifier)) &&
- ([charactersIgnoringModifiers length] != 0)) {
- ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
- } else if ([characters length] != 0) {
- ch = QChar([characters characterAtIndex:0]);
- }
- if (!(qtModifiers & (Qt::ControlModifier | Qt::MetaModifier)) &&
- (ch.unicode() < 0xf700 || ch.unicode() > 0xf8ff)) {
- text = QString::fromNSString(characters);
- }
- if (!ch.isNull())
- return Qt::Key(ch.toUpper().unicode());
- }
- return Qt::Key_unknown;
-}
-
#ifdef Q_OS_MACOS
static constexpr std::tuple<NSEventModifierFlags, Qt::KeyboardModifier> cocoaModifierMap[] = {
{ NSEventModifierFlagShift, Qt::ShiftModifier },
@@ -384,7 +353,7 @@ Qt::Key QAppleKeyMapper::fromCocoaKey(QChar keyCode)
// ------------------------------------------------
-Qt::KeyboardModifiers QAppleKeyMapper::queryKeyboardModifiers()
+Qt::KeyboardModifiers QAppleKeyMapper::queryKeyboardModifiers() const
{
return fromCocoaModifiers(NSEvent.modifierFlags);
}
@@ -538,11 +507,9 @@ const QAppleKeyMapper::KeyMap &QAppleKeyMapper::keyMapForKey(VirtualKeyCode virt
where each modifier-key combination has been mapped to the
key it will produce.
*/
-QList<int> QAppleKeyMapper::possibleKeys(const QKeyEvent *event) const
+QList<QKeyCombination> QAppleKeyMapper::possibleKeyCombinations(const QKeyEvent *event) const
{
- QList<int> ret;
-
- qCDebug(lcQpaKeyMapper) << "Computing possible keys for" << event;
+ QList<QKeyCombination> ret;
const auto nativeVirtualKey = event->nativeVirtualKey();
if (!nativeVirtualKey)
@@ -555,16 +522,49 @@ QList<int> QAppleKeyMapper::possibleKeys(const QKeyEvent *event) const
auto eventModifiers = event->modifiers();
- // The complete set of event modifiers, along with the
- // unmodified key, is always a valid key combination,
- // and the first priority.
- ret << int(eventModifiers) + int(unmodifiedKey);
+ int startingModifierLayer = 0;
+ if (toCocoaModifiers(eventModifiers) & NSEventModifierFlagCommand) {
+ // When the Command key is pressed AppKit seems to do key equivalent
+ // matching using a Latin/Roman interpretation of the current keyboard
+ // layout. For example, for a Greek layout, pressing Option+Command+C
+ // produces a key event with chars="ç" and unmodchars="ψ", but AppKit
+ // still treats this as a match for a key equivalent of Option+Command+C.
+ // We can't do the same by just applying the modifiers to our key map,
+ // as that too contains "ψ" for the Option+Command combination. What we
+ // can do instead is take advantage of the fact that the Command
+ // modifier layer in all/most keyboard layouts contains a Latin
+ // layer. We then combine that with the modifiers of the event
+ // to produce the resulting "Latin" key combination.
+ static constexpr int kCommandLayer = 2;
+ ret << QKeyCombination::fromCombined(
+ int(eventModifiers) + int(keyMap[kCommandLayer]));
+
+ // If the unmodified key is outside of Latin1, we also treat
+ // that as a valid key combination, even if AppKit natively
+ // does not. For example, for a Greek layout, we still want
+ // to support Option+Command+ψ as a key combination, as it's
+ // unlikely to clash with the Latin key combination we added
+ // above.
+
+ // However, if the unmodified key is within Latin1, we skip
+ // it, to avoid these types of conflicts. For example, in
+ // the same Greek layout, pressing the key next to Tab will
+ // produce a Latin ';' symbol, but we've already treated that
+ // as 'q' above, thanks to the Command modifier, so we skip
+ // the potential Command+; key combination. This is also in
+ // line with what AppKit natively does.
+
+ // Skipping Latin1 unmodified keys also handles the case of
+ // a Latin layout, where the unmodified and modified keys
+ // are the same.
+
+ if (unmodifiedKey <= 0xff)
+ startingModifierLayer = 1;
+ }
// FIXME: We only compute the first 8 combinations. Why?
- for (int i = 1; i < 8; ++i) {
+ for (int i = startingModifierLayer; i < 15; ++i) {
auto keyAfterApplyingModifiers = keyMap[i];
- if (keyAfterApplyingModifiers == unmodifiedKey)
- continue;
if (!keyAfterApplyingModifiers)
continue;
@@ -575,18 +575,39 @@ QList<int> QAppleKeyMapper::possibleKeys(const QKeyEvent *event) const
// If the event includes more modifiers than the candidate they
// will need to be included in the resulting key combination.
auto additionalModifiers = eventModifiers & ~candidateModifiers;
- ret << int(additionalModifiers) + int(keyAfterApplyingModifiers);
- }
- }
- if (lcQpaKeyMapper().isDebugEnabled()) {
- qCDebug(lcQpaKeyMapper) << "Possible keys:";
- for (int keyAndModifiers : ret) {
- auto keyCombination = QKeyCombination::fromCombined(keyAndModifiers);
- auto keySequence = QKeySequence(keyCombination);
- qCDebug(lcQpaKeyMapper).verbosity(0) << "\t-"
- << keyCombination << "/" << keySequence << "/"
- << qUtf8Printable(keySequence.toString(QKeySequence::NativeText));
+ auto keyCombination = QKeyCombination::fromCombined(
+ int(additionalModifiers) + int(keyAfterApplyingModifiers));
+
+ // If there's an existing key combination with the same key,
+ // but a different set of modifiers, we want to choose only
+ // one of them, by priority (see below).
+ const auto existingCombination = std::find_if(
+ ret.begin(), ret.end(), [&](auto existingCombination) {
+ return existingCombination.key() == keyAfterApplyingModifiers;
+ });
+
+ if (existingCombination != ret.end()) {
+ // We prioritize the combination with the more specific
+ // modifiers. In the case where the number of modifiers
+ // are the same, we want to prioritize Command over Option
+ // over Control over Shift. Unfortunately the order (and
+ // hence value) of the modifiers in Qt::KeyboardModifier
+ // does not match our preferred order when Control and
+ // Meta is switched, but we can work around that by
+ // explicitly swapping the modifiers and using that
+ // for the comparison. This also works when the
+ // Qt::AA_MacDontSwapCtrlAndMeta application attribute
+ // is set, as the incoming modifiers are then left
+ // as is, and we can still trust the order.
+ auto existingModifiers = swapModifiersIfNeeded(existingCombination->keyboardModifiers());
+ auto replacementModifiers = swapModifiersIfNeeded(additionalModifiers);
+ if (replacementModifiers > existingModifiers)
+ *existingCombination = keyCombination;
+ } else {
+ // All is good, no existing combination has this key
+ ret << keyCombination;
+ }
}
}
@@ -597,6 +618,36 @@ QList<int> QAppleKeyMapper::possibleKeys(const QKeyEvent *event) const
#else // iOS
+Qt::Key QAppleKeyMapper::fromNSString(Qt::KeyboardModifiers qtModifiers, NSString *characters,
+ NSString *charactersIgnoringModifiers, QString &text)
+{
+ if ([characters isEqualToString:@"\t"]) {
+ if (qtModifiers & Qt::ShiftModifier)
+ return Qt::Key_Backtab;
+ return Qt::Key_Tab;
+ } else if ([characters isEqualToString:@"\r"]) {
+ if (qtModifiers & Qt::KeypadModifier)
+ return Qt::Key_Enter;
+ return Qt::Key_Return;
+ }
+ if ([characters length] != 0 || [charactersIgnoringModifiers length] != 0) {
+ QChar ch;
+ if (((qtModifiers & Qt::MetaModifier) || (qtModifiers & Qt::AltModifier)) &&
+ ([charactersIgnoringModifiers length] != 0)) {
+ ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
+ } else if ([characters length] != 0) {
+ ch = QChar([characters characterAtIndex:0]);
+ }
+ if (!(qtModifiers & (Qt::ControlModifier | Qt::MetaModifier)) &&
+ (ch.unicode() < 0xf700 || ch.unicode() > 0xf8ff)) {
+ text = QString::fromNSString(characters);
+ }
+ if (!ch.isNull())
+ return Qt::Key(ch.toUpper().unicode());
+ }
+ return Qt::Key_unknown;
+}
+
// Keyboard keys (non-modifiers)
API_AVAILABLE(ios(13.4)) Qt::Key QAppleKeyMapper::fromUIKitKey(NSString *keyCode)
{
diff --git a/src/gui/platform/darwin/qapplekeymapper_p.h b/src/gui/platform/darwin/qapplekeymapper_p.h
index 34557c8ede..1f3494d16f 100644
--- a/src/gui/platform/darwin/qapplekeymapper_p.h
+++ b/src/gui/platform/darwin/qapplekeymapper_p.h
@@ -19,6 +19,8 @@
#include <Carbon/Carbon.h>
#endif
+#include <qpa/qplatformkeymapper.h>
+
#include <QtCore/QList>
#include <QtCore/QHash>
#include <QtGui/QKeyEvent>
@@ -27,13 +29,12 @@
QT_BEGIN_NAMESPACE
-class Q_GUI_EXPORT QAppleKeyMapper
+class Q_GUI_EXPORT QAppleKeyMapper : public QPlatformKeyMapper
{
public:
- static Qt::KeyboardModifiers queryKeyboardModifiers();
- QList<int> possibleKeys(const QKeyEvent *event) const;
- static Qt::Key fromNSString(Qt::KeyboardModifiers qtMods, NSString *characters,
- NSString *charactersIgnoringModifiers, QString &text);
+ Qt::KeyboardModifiers queryKeyboardModifiers() const override;
+ QList<QKeyCombination> possibleKeyCombinations(const QKeyEvent *event) const override;
+
#ifdef Q_OS_MACOS
static Qt::KeyboardModifiers fromCocoaModifiers(NSEventModifierFlags cocoaModifiers);
static NSEventModifierFlags toCocoaModifiers(Qt::KeyboardModifiers);
@@ -41,6 +42,9 @@ public:
static QChar toCocoaKey(Qt::Key key);
static Qt::Key fromCocoaKey(QChar keyCode);
#else
+ static Qt::Key fromNSString(Qt::KeyboardModifiers qtMods, NSString *characters,
+ NSString *charactersIgnoringModifiers, QString &text);
+
static Qt::Key fromUIKitKey(NSString *keyCode);
static Qt::KeyboardModifiers fromUIKitModifiers(ulong uikitModifiers);
static ulong toUIKitModifiers(Qt::KeyboardModifiers);
diff --git a/src/gui/platform/darwin/qmacmimeregistry.mm b/src/gui/platform/darwin/qmacmimeregistry.mm
index acbe671e1a..6710a0656f 100644
--- a/src/gui/platform/darwin/qmacmimeregistry.mm
+++ b/src/gui/platform/darwin/qmacmimeregistry.mm
@@ -21,20 +21,6 @@ Q_GLOBAL_STATIC(QStringList, globalDraggedTypesList)
// implemented in qutimimeconverter.mm
void registerBuiltInTypes();
-/*!
- \fn void qRegisterDraggedTypes(const QStringList &types)
- \relates QUtiMimeConverter
-
- Registers the given \a types as custom pasteboard types.
-
- This function should be called to enable the Drag and Drop events
- for custom pasteboard types on Cocoa implementations. This is required
- in addition to a QUtiMimeConverter subclass implementation. By default
- drag and drop is enabled for all standard pasteboard types.
-
- \sa QUtiMimeConverter
-*/
-
void registerDraggedTypes(const QStringList &types)
{
(*globalDraggedTypesList()) += types;
diff --git a/src/gui/platform/darwin/qutimimeconverter.mm b/src/gui/platform/darwin/qutimimeconverter.mm
index 975f00cf88..ee643fd0c6 100644
--- a/src/gui/platform/darwin/qutimimeconverter.mm
+++ b/src/gui/platform/darwin/qutimimeconverter.mm
@@ -3,6 +3,7 @@
#include <ImageIO/ImageIO.h>
#include <CoreFoundation/CoreFoundation.h>
+#include <UniformTypeIdentifiers/UTCoreTypes.h>
#include <QtCore/qsystemdetection.h>
#include <QtCore/qurl.h>
@@ -53,7 +54,21 @@ using namespace Qt::StringLiterals;
By subclasses this class, one can extend Qt's drag and drop
and clipboard handling to convert to and from unsupported, or proprietary, UTI formats.
- A subclass of QUtiMimeConverter will automatically be registered, and active, upon instantiation.
+ Construct an instance of your converter implementation after instantiating
+ QGuiApplication:
+
+ \code
+ int main(int argc, char **argv)
+ {
+ QGuiApplication app(argc, argv);
+ JsonMimeConverter jsonConverter;
+ }
+ \endcode
+
+ Destroying the instance will unregister the converter and remove support
+ for the conversion. It is also valid to heap-allocate the converter
+ instance; Qt takes ownership and will delete the converter object during
+ QGuiApplication shut-down.
Qt has predefined support for the following UTIs:
\list
@@ -94,6 +109,8 @@ QUtiMimeConverter::QUtiMimeConverter(HandlerScope scope)
/*!
Constructs a new conversion object and adds it to the
globally accessed list of available converters.
+
+ Call this constructor after QGuiApplication has been created.
*/
QUtiMimeConverter::QUtiMimeConverter()
: QUtiMimeConverter(HandlerScopeFlag::All)
@@ -763,7 +780,7 @@ QList<QByteArray> QMacMimeTiff::convertFromMime(const QString &mime,
QCFType<CFMutableDataRef> data = CFDataCreateMutable(0, 0);
QCFType<CGImageDestinationRef> imageDestination = CGImageDestinationCreateWithData(data,
- kUTTypeTIFF, 1, 0);
+ (CFStringRef)UTTypeTIFF.identifier, 1, 0);
if (!imageDestination)
return QList<QByteArray>();
diff --git a/src/gui/platform/ios/PrivacyInfo.xcprivacy b/src/gui/platform/ios/PrivacyInfo.xcprivacy
new file mode 100644
index 0000000000..bde2b167c7
--- /dev/null
+++ b/src/gui/platform/ios/PrivacyInfo.xcprivacy
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>NSPrivacyTracking</key>
+ <false/>
+ <key>NSPrivacyCollectedDataTypes</key>
+ <array/>
+ <key>NSPrivacyTrackingDomains</key>
+ <array/>
+ <key>NSPrivacyAccessedAPITypes</key>
+ <array>
+ <dict>
+ <key>NSPrivacyAccessedAPIType</key>
+ <string>NSPrivacyAccessedAPICategorySystemBootTime</string>
+ <key>NSPrivacyAccessedAPITypeReasons</key>
+ <array>
+ <string>35F9.1</string> <!-- QUIView event handling -->
+ </array>
+ </dict>
+ </array>
+</dict>
+</plist>
diff --git a/src/gui/platform/macos/qcocoanativeinterface.mm b/src/gui/platform/macos/qcocoanativeinterface.mm
index a41f9b16da..cb6acb4496 100644
--- a/src/gui/platform/macos/qcocoanativeinterface.mm
+++ b/src/gui/platform/macos/qcocoanativeinterface.mm
@@ -1,7 +1,11 @@
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <QtGui/private/qopenglcontext_p.h>
+#include <QtGui/qtgui-config.h>
+#ifndef QT_NO_OPENGL
+# include <QtGui/private/qopenglcontext_p.h>
+#endif
+
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformopenglcontext.h>
#include <qpa/qplatformintegration.h>
diff --git a/src/gui/platform/unix/dbusmenu/qdbusmenuconnection.cpp b/src/gui/platform/unix/dbusmenu/qdbusmenuconnection.cpp
index 9391b77f6a..1023b16662 100644
--- a/src/gui/platform/unix/dbusmenu/qdbusmenuconnection.cpp
+++ b/src/gui/platform/unix/dbusmenu/qdbusmenuconnection.cpp
@@ -40,14 +40,14 @@ QDBusMenuConnection::QDBusMenuConnection(QObject *parent, const QString &service
, m_connection(serviceName.isNull() ? QDBusConnection::sessionBus()
: QDBusConnection::connectToBus(QDBusConnection::SessionBus, serviceName))
, m_dbusWatcher(new QDBusServiceWatcher(StatusNotifierWatcherService, m_connection, QDBusServiceWatcher::WatchForRegistration, this))
- , m_statusNotifierHostRegistered(false)
+ , m_watcherRegistered(false)
{
#ifndef QT_NO_SYSTEMTRAYICON
- QDBusInterface systrayHost(StatusNotifierWatcherService, StatusNotifierWatcherPath, StatusNotifierWatcherService, m_connection);
- if (systrayHost.isValid() && systrayHost.property("IsStatusNotifierHostRegistered").toBool())
- m_statusNotifierHostRegistered = true;
+ // Start monitoring if any known tray-related services are registered.
+ if (m_connection.interface()->isServiceRegistered(StatusNotifierWatcherService))
+ m_watcherRegistered = true;
else
- qCDebug(qLcMenu) << "StatusNotifierHost is not registered";
+ qCDebug(qLcMenu) << "failed to find service" << StatusNotifierWatcherService;
#endif
}
diff --git a/src/gui/platform/unix/dbusmenu/qdbusmenuconnection_p.h b/src/gui/platform/unix/dbusmenu/qdbusmenuconnection_p.h
index 69713b12bd..37033e2fa3 100644
--- a/src/gui/platform/unix/dbusmenu/qdbusmenuconnection_p.h
+++ b/src/gui/platform/unix/dbusmenu/qdbusmenuconnection_p.h
@@ -39,7 +39,7 @@ public:
~QDBusMenuConnection();
QDBusConnection connection() const { return m_connection; }
QDBusServiceWatcher *dbusWatcher() const { return m_dbusWatcher; }
- bool isStatusNotifierHostRegistered() const { return m_statusNotifierHostRegistered; }
+ bool isWatcherRegistered() const { return m_watcherRegistered; }
#ifndef QT_NO_SYSTEMTRAYICON
bool registerTrayIconMenu(QDBusTrayIcon *item);
void unregisterTrayIconMenu(QDBusTrayIcon *item);
@@ -60,7 +60,7 @@ private:
QString m_serviceName;
QDBusConnection m_connection;
QDBusServiceWatcher *m_dbusWatcher;
- bool m_statusNotifierHostRegistered;
+ bool m_watcherRegistered;
};
QT_END_NAMESPACE
diff --git a/src/gui/platform/unix/dbusmenu/qdbusmenutypes.cpp b/src/gui/platform/unix/dbusmenu/qdbusmenutypes.cpp
index d2469a0d26..b7fd035883 100644
--- a/src/gui/platform/unix/dbusmenu/qdbusmenutypes.cpp
+++ b/src/gui/platform/unix/dbusmenu/qdbusmenutypes.cpp
@@ -217,19 +217,19 @@ QDBusMenuShortcut QDBusMenuItem::convertKeySequence(const QKeySequence &sequence
QDBusMenuShortcut shortcut;
for (int i = 0; i < sequence.count(); ++i) {
QStringList tokens;
- int key = sequence[i].toCombined();
- if (key & Qt::MetaModifier)
+ auto modifiers = sequence[i].keyboardModifiers();
+ if (modifiers & Qt::MetaModifier)
tokens << QStringLiteral("Super");
- if (key & Qt::ControlModifier)
+ if (modifiers & Qt::ControlModifier)
tokens << QStringLiteral("Control");
- if (key & Qt::AltModifier)
+ if (modifiers & Qt::AltModifier)
tokens << QStringLiteral("Alt");
- if (key & Qt::ShiftModifier)
+ if (modifiers & Qt::ShiftModifier)
tokens << QStringLiteral("Shift");
- if (key & Qt::KeypadModifier)
+ if (modifiers & Qt::KeypadModifier)
tokens << QStringLiteral("Num");
- QString keyName = QKeySequencePrivate::keyName(key, QKeySequence::PortableText);
+ QString keyName = QKeySequencePrivate::keyName(sequence[i].key(), QKeySequence::PortableText);
if (keyName == "+"_L1)
tokens << QStringLiteral("plus");
else if (keyName == "-"_L1)
diff --git a/src/gui/platform/unix/dbustray/qdbustrayicon.cpp b/src/gui/platform/unix/dbustray/qdbustrayicon.cpp
index 18334e5715..0dff9b598e 100644
--- a/src/gui/platform/unix/dbustray/qdbustrayicon.cpp
+++ b/src/gui/platform/unix/dbustray/qdbustrayicon.cpp
@@ -198,7 +198,10 @@ QTemporaryFile *QDBusTrayIcon::tempIcon(const QIcon &icon)
if (!necessary)
return nullptr;
QTemporaryFile *ret = new QTemporaryFile(tempFileTemplate(), this);
- ret->open();
+ if (!ret->open()) {
+ delete ret;
+ return nullptr;
+ }
icon.pixmap(QSize(22, 22)).save(ret);
ret->close();
return ret;
@@ -331,8 +334,11 @@ void QDBusTrayIcon::notificationClosed(uint id, uint reason)
bool QDBusTrayIcon::isSystemTrayAvailable() const
{
QDBusMenuConnection * conn = const_cast<QDBusTrayIcon *>(this)->dBusConnection();
- qCDebug(qLcTray) << conn->isStatusNotifierHostRegistered();
- return conn->isStatusNotifierHostRegistered();
+
+ // If the KDE watcher service is registered, we must be on a desktop
+ // where a StatusNotifier-conforming system tray exists.
+ qCDebug(qLcTray) << conn->isWatcherRegistered();
+ return conn->isWatcherRegistered();
}
QT_END_NAMESPACE
diff --git a/src/gui/platform/unix/qgenericunixservices.cpp b/src/gui/platform/unix/qgenericunixservices.cpp
index 1563b38d54..bfd2556b1e 100644
--- a/src/gui/platform/unix/qgenericunixservices.cpp
+++ b/src/gui/platform/unix/qgenericunixservices.cpp
@@ -162,7 +162,7 @@ static inline bool launch(const QString &launcher, const QUrl &url,
#if QT_CONFIG(dbus)
static inline bool checkNeedPortalSupport()
{
- return !QStandardPaths::locate(QStandardPaths::RuntimeLocation, "flatpak-info"_L1).isEmpty() || qEnvironmentVariableIsSet("SNAP");
+ return QFileInfo::exists("/.flatpak-info"_L1) || qEnvironmentVariableIsSet("SNAP");
}
static inline QDBusMessage xdgDesktopPortalOpenFile(const QUrl &url, const QString &parentWindow,
@@ -177,8 +177,7 @@ static inline QDBusMessage xdgDesktopPortalOpenFile(const QUrl &url, const QStri
// handle_token (s) - A string that will be used as the last element of the @handle.
// writable (b) - Whether to allow the chosen application to write to the file.
-#ifdef O_PATH
- const int fd = qt_safe_open(QFile::encodeName(url.toLocalFile()), O_PATH);
+ const int fd = qt_safe_open(QFile::encodeName(url.toLocalFile()), O_RDONLY);
if (fd != -1) {
QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.portal.Desktop"_L1,
"/org/freedesktop/portal/desktop"_L1,
@@ -188,7 +187,7 @@ static inline QDBusMessage xdgDesktopPortalOpenFile(const QUrl &url, const QStri
QDBusUnixFileDescriptor descriptor;
descriptor.giveFileDescriptor(fd);
- QVariantMap options = { { "writable"_L1, true } };
+ QVariantMap options = {};
if (!xdgActivationToken.isEmpty()) {
options.insert("activation_token"_L1, xdgActivationToken);
@@ -198,11 +197,6 @@ static inline QDBusMessage xdgDesktopPortalOpenFile(const QUrl &url, const QStri
return QDBusConnection::sessionBus().call(message);
}
-#else
- Q_UNUSED(url);
- Q_UNUSED(parentWindow)
- Q_UNUSED(xdgActivationToken)
-#endif
return QDBusMessage::createError(QDBusError::InternalError, qt_error_string());
}
@@ -360,9 +354,13 @@ private Q_SLOTS:
{
if (result != 0)
return;
- XDGDesktopColor color{};
- map.value(u"color"_s).value<QDBusArgument>() >> color;
- Q_EMIT colorPicked(color.toQColor());
+ if (map.contains(u"color"_s)) {
+ XDGDesktopColor color{};
+ map.value(u"color"_s).value<QDBusArgument>() >> color;
+ Q_EMIT colorPicked(color.toQColor());
+ } else {
+ Q_EMIT colorPicked({});
+ }
deleteLater();
}
@@ -424,9 +422,11 @@ QByteArray QGenericUnixServices::desktopEnvironment() const
template<typename F>
void runWithXdgActivationToken(F &&functionToCall)
{
+#if QT_CONFIG(wayland)
QWindow *window = qGuiApp->focusWindow();
if (!window) {
+ functionToCall({});
return;
}
@@ -436,13 +436,17 @@ void runWithXdgActivationToken(F &&functionToCall)
dynamic_cast<QNativeInterface::Private::QWaylandWindow *>(window->handle());
if (!waylandWindow || !waylandApp) {
+ functionToCall({});
return;
}
- waylandWindow->requestXdgActivationToken(waylandApp->lastInputSerial());
QObject::connect(waylandWindow,
&QNativeInterface::Private::QWaylandWindow::xdgActivationTokenCreated,
waylandWindow, functionToCall, Qt::SingleShotConnection);
+ waylandWindow->requestXdgActivationToken(waylandApp->lastInputSerial());
+#else
+ functionToCall({});
+#endif
}
bool QGenericUnixServices::openUrl(const QUrl &url)
@@ -560,9 +564,7 @@ QPlatformServiceColorPicker *QGenericUnixServices::colorPicker(QWindow *parent)
QString QGenericUnixServices::portalWindowIdentifier(QWindow *window)
{
- if (QGuiApplication::platformName() == QLatin1String("xcb"))
- return "x11:"_L1 + QString::number(window->winId(), 16);
-
+ Q_UNUSED(window);
return QString();
}
@@ -575,6 +577,37 @@ bool QGenericUnixServices::hasCapability(Capability capability) const
return false;
}
+void QGenericUnixServices::setApplicationBadge(qint64 number)
+{
+#if QT_CONFIG(dbus)
+ if (qGuiApp->desktopFileName().isEmpty()) {
+ qWarning("QGuiApplication::desktopFileName() is empty");
+ return;
+ }
+
+
+ const QString launcherUrl = QStringLiteral("application://") + qGuiApp->desktopFileName() + QStringLiteral(".desktop");
+ const qint64 count = qBound(0, number, 9999);
+ QVariantMap dbusUnityProperties;
+
+ if (count > 0) {
+ dbusUnityProperties[QStringLiteral("count")] = count;
+ dbusUnityProperties[QStringLiteral("count-visible")] = true;
+ } else {
+ dbusUnityProperties[QStringLiteral("count-visible")] = false;
+ }
+
+ auto signal = QDBusMessage::createSignal(QStringLiteral("/com/canonical/unity/launcherentry/")
+ + qGuiApp->applicationName(), QStringLiteral("com.canonical.Unity.LauncherEntry"), QStringLiteral("Update"));
+
+ signal.setArguments({launcherUrl, dbusUnityProperties});
+
+ QDBusConnection::sessionBus().send(signal);
+#else
+ Q_UNUSED(number)
+#endif
+}
+
QT_END_NAMESPACE
#include "qgenericunixservices.moc"
diff --git a/src/gui/platform/unix/qgenericunixservices_p.h b/src/gui/platform/unix/qgenericunixservices_p.h
index 701bcfc78f..56e15103f7 100644
--- a/src/gui/platform/unix/qgenericunixservices_p.h
+++ b/src/gui/platform/unix/qgenericunixservices_p.h
@@ -35,6 +35,7 @@ public:
bool openDocument(const QUrl &url) override;
QPlatformServiceColorPicker *colorPicker(QWindow *parent = nullptr) override;
+ void setApplicationBadge(qint64 number);
virtual QString portalWindowIdentifier(QWindow *window);
private:
diff --git a/src/gui/platform/unix/qgenericunixthemes.cpp b/src/gui/platform/unix/qgenericunixthemes.cpp
index d767767893..fc4b2296d2 100644
--- a/src/gui/platform/unix/qgenericunixthemes.cpp
+++ b/src/gui/platform/unix/qgenericunixthemes.cpp
@@ -33,6 +33,12 @@
#include <QDBusConnectionInterface>
#include <private/qdbusplatformmenu_p.h>
#include <private/qdbusmenubar_p.h>
+#include <private/qflatmap_p.h>
+#include <QJsonDocument>
+#include <QJsonArray>
+#include <QJsonObject>
+#include <QJsonValue>
+#include <QJsonParseError>
#endif
#if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON)
#include <private/qdbustrayicon_p.h>
@@ -77,7 +83,7 @@ static bool isDBusTrayAvailable() {
static bool dbusTrayAvailableKnown = false;
if (!dbusTrayAvailableKnown) {
QDBusMenuConnection conn;
- if (conn.isStatusNotifierHostRegistered())
+ if (conn.isWatcherRegistered())
dbusTrayAvailable = true;
dbusTrayAvailableKnown = true;
qCDebug(qLcTray) << "D-Bus tray available:" << dbusTrayAvailable;
@@ -119,7 +125,7 @@ static bool isDBusGlobalMenuAvailable()
/*!
* \internal
* The QGenericUnixThemeDBusListener class listens to the SettingChanged DBus signal
- * and translates it into the QDbusSettingType enum.
+ * and translates it into combinations of the enums \c Provider and \c Setting.
* Upon construction, it logs success/failure of the DBus connection.
*
* The signal settingChanged delivers the normalized setting type and the new value as a string.
@@ -131,35 +137,98 @@ class QGenericUnixThemeDBusListener : public QObject
Q_OBJECT
public:
- QGenericUnixThemeDBusListener(const QString &service, const QString &path, const QString &interface, const QString &signal);
- enum class SettingType {
- KdeGlobalTheme,
- KdeApplicationStyle,
- GtkTheme,
- Unknown
+ enum class Provider {
+ Kde,
+ Gtk,
+ Gnome,
};
- Q_ENUM(SettingType)
+ Q_ENUM(Provider)
- static SettingType toSettingType(const QString &location, const QString &key);
+ enum class Setting {
+ Theme,
+ ApplicationStyle,
+ ColorScheme,
+ };
+ Q_ENUM(Setting)
+
+ QGenericUnixThemeDBusListener();
+ QGenericUnixThemeDBusListener(const QString &service, const QString &path,
+ const QString &interface, const QString &signal);
private Q_SLOTS:
void onSettingChanged(const QString &location, const QString &key, const QDBusVariant &value);
Q_SIGNALS:
- void settingChanged(QGenericUnixThemeDBusListener::SettingType type, const QString &value);
+ void settingChanged(QGenericUnixThemeDBusListener::Provider provider,
+ QGenericUnixThemeDBusListener::Setting setting,
+ const QString &value);
+
+private:
+ struct DBusKey
+ {
+ QString location;
+ QString key;
+ DBusKey(const QString &loc, const QString &k) : location(loc), key(k) {};
+ bool operator<(const DBusKey &other) const
+ {
+ return location + key < other.location + other.key;
+ }
+ };
+
+ struct ChangeSignal
+ {
+ Provider provider;
+ Setting setting;
+ ChangeSignal(Provider p, Setting s) : provider(p), setting(s) {}
+ ChangeSignal() {}
+ };
+ // Json keys
+ static constexpr QLatin1StringView s_dbusLocation = QLatin1StringView("DBusLocation");
+ static constexpr QLatin1StringView s_dbusKey = QLatin1StringView("DBusKey");
+ static constexpr QLatin1StringView s_provider = QLatin1StringView("Provider");
+ static constexpr QLatin1StringView s_setting = QLatin1StringView("Setting");
+ static constexpr QLatin1StringView s_signals = QLatin1StringView("DbusSignals");
+ static constexpr QLatin1StringView s_root = QLatin1StringView("Qt.qpa.DBusSignals");
+
+ QFlatMap <DBusKey, ChangeSignal> m_signalMap;
+
+ void init(const QString &service, const QString &path,
+ const QString &interface, const QString &signal);
+
+ std::optional<ChangeSignal> findSignal(const QString &location, const QString &key) const;
+ void populateSignalMap();
+ void loadJson(const QString &fileName);
+ void saveJson(const QString &fileName) const;
};
QGenericUnixThemeDBusListener::QGenericUnixThemeDBusListener(const QString &service,
const QString &path, const QString &interface, const QString &signal)
{
+ init (service, path, interface, signal);
+}
+
+QGenericUnixThemeDBusListener::QGenericUnixThemeDBusListener()
+{
+ static constexpr QLatin1StringView service("");
+ static constexpr QLatin1StringView path("/org/freedesktop/portal/desktop");
+ static constexpr QLatin1StringView interface("org.freedesktop.portal.Settings");
+ static constexpr QLatin1StringView signal("SettingChanged");
+
+ init (service, path, interface, signal);
+}
+
+void QGenericUnixThemeDBusListener::init(const QString &service, const QString &path,
+ const QString &interface, const QString &signal)
+{
QDBusConnection dbus = QDBusConnection::sessionBus();
const bool dBusRunning = dbus.isConnected();
bool dBusSignalConnected = false;
#define LOG service << path << interface << signal;
if (dBusRunning) {
+ populateSignalMap();
qRegisterMetaType<QDBusVariant>();
dBusSignalConnected = dbus.connect(service, path, interface, signal, this,
SLOT(onSettingChanged(QString,QString,QDBusVariant)));
@@ -182,26 +251,155 @@ QGenericUnixThemeDBusListener::QGenericUnixThemeDBusListener(const QString &serv
#undef LOG
}
-QGenericUnixThemeDBusListener::SettingType QGenericUnixThemeDBusListener::toSettingType(
- const QString &location, const QString &key)
+void QGenericUnixThemeDBusListener::loadJson(const QString &fileName)
+{
+ Q_ASSERT(!fileName.isEmpty());
+#define CHECK(cond, warning)\
+ if (!cond) {\
+ qCWarning(lcQpaThemeDBus) << fileName << warning << "Falling back to default.";\
+ return;\
+ }
+
+#define PARSE(var, enumeration, string)\
+ enumeration var;\
+ {\
+ bool success;\
+ const int val = QMetaEnum::fromType<enumeration>().keyToValue(string.toLatin1(), &success);\
+ CHECK(success, "Parse Error: Invalid value" << string << "for" << #var);\
+ var = static_cast<enumeration>(val);\
+ }
+
+ QFile file(fileName);
+ CHECK(file.exists(), fileName << "doesn't exist.");
+ CHECK(file.open(QIODevice::ReadOnly), "could not be opened for reading.");
+
+ QJsonParseError error;
+ QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &error);
+ CHECK((error.error == QJsonParseError::NoError), error.errorString());
+ CHECK(doc.isObject(), "Parse Error: Expected root object" << s_root);
+
+ const QJsonObject &root = doc.object();
+ CHECK(root.contains(s_root), "Parse Error: Expected root object" << s_root);
+ CHECK(root[s_root][s_signals].isArray(), "Parse Error: Expected array" << s_signals);
+
+ const QJsonArray &sigs = root[s_root][s_signals].toArray();
+ CHECK((sigs.count() > 0), "Parse Error: Found empty array" << s_signals);
+
+ for (auto sig = sigs.constBegin(); sig != sigs.constEnd(); ++sig) {
+ CHECK(sig->isObject(), "Parse Error: Expected object array" << s_signals);
+ const QJsonObject &obj = sig->toObject();
+ CHECK(obj.contains(s_dbusLocation), "Parse Error: Expected key" << s_dbusLocation);
+ CHECK(obj.contains(s_dbusKey), "Parse Error: Expected key" << s_dbusKey);
+ CHECK(obj.contains(s_provider), "Parse Error: Expected key" << s_provider);
+ CHECK(obj.contains(s_setting), "Parse Error: Expected key" << s_setting);
+ const QString &location = obj[s_dbusLocation].toString();
+ const QString &key = obj[s_dbusKey].toString();
+ const QString &providerString = obj[s_provider].toString();
+ const QString &settingString = obj[s_setting].toString();
+ PARSE(provider, Provider, providerString);
+ PARSE(setting, Setting, settingString);
+ const DBusKey dkey(location, key);
+ CHECK (!m_signalMap.contains(dkey), "Duplicate key" << location << key);
+ m_signalMap.insert(dkey, ChangeSignal(provider, setting));
+ }
+#undef PARSE
+#undef CHECK
+
+ if (m_signalMap.count() > 0)
+ qCInfo(lcQpaThemeDBus) << "Successfully imported" << fileName;
+ else
+ qCWarning(lcQpaThemeDBus) << "No data imported from" << fileName << "falling back to default.";
+
+#ifdef QT_DEBUG
+ const int count = m_signalMap.count();
+ if (count == 0)
+ return;
+
+ qCDebug(lcQpaThemeDBus) << "Listening to" << count << "signals:";
+ for (auto it = m_signalMap.constBegin(); it != m_signalMap.constEnd(); ++it) {
+ qDebug() << it.key().key << it.key().location << "mapped to"
+ << it.value().provider << it.value().setting;
+ }
+
+#endif
+}
+
+void QGenericUnixThemeDBusListener::saveJson(const QString &fileName) const
+{
+ Q_ASSERT(!m_signalMap.isEmpty());
+ Q_ASSERT(!fileName.isEmpty());
+ QFile file(fileName);
+ if (!file.open(QIODevice::WriteOnly)) {
+ qCWarning(lcQpaThemeDBus) << fileName << "could not be opened for writing.";
+ return;
+ }
+
+ QJsonArray sigs;
+ for (auto sig = m_signalMap.constBegin(); sig != m_signalMap.constEnd(); ++sig) {
+ const DBusKey &dkey = sig.key();
+ const ChangeSignal &csig = sig.value();
+ QJsonObject obj;
+ obj[s_dbusLocation] = dkey.location;
+ obj[s_dbusKey] = dkey.key;
+ obj[s_provider] = QLatin1StringView(QMetaEnum::fromType<Provider>()
+ .valueToKey(static_cast<int>(csig.provider)));
+ obj[s_setting] = QLatin1StringView(QMetaEnum::fromType<Setting>()
+ .valueToKey(static_cast<int>(csig.setting)));
+ sigs.append(obj);
+ }
+ QJsonObject obj;
+ obj[s_signals] = sigs;
+ QJsonObject root;
+ root[s_root] = obj;
+ QJsonDocument doc(root);
+ file.write(doc.toJson());
+ file.close();
+}
+
+void QGenericUnixThemeDBusListener::populateSignalMap()
{
- if (location == QLatin1StringView("org.kde.kdeglobals.KDE")
- && key == QLatin1StringView("widgetStyle"))
- return SettingType::KdeApplicationStyle;
- if (location == QLatin1StringView("org.kde.kdeglobals.General")
- && key == QLatin1StringView("ColorScheme"))
- return SettingType::KdeGlobalTheme;
- if (location == QLatin1StringView("org.gnome.desktop.interface")
- && key == QLatin1StringView("gtk-theme"))
- return SettingType::GtkTheme;
- return SettingType::Unknown;
+ m_signalMap.clear();
+ const QString &loadJsonFile = qEnvironmentVariable("QT_QPA_DBUS_SIGNALS");
+ if (!loadJsonFile.isEmpty())
+ loadJson(loadJsonFile);
+ if (!m_signalMap.isEmpty())
+ return;
+
+ m_signalMap.insert(DBusKey("org.kde.kdeglobals.KDE"_L1, "widgetStyle"_L1),
+ ChangeSignal(Provider::Kde, Setting::ApplicationStyle));
+
+ m_signalMap.insert(DBusKey("org.kde.kdeglobals.General"_L1, "ColorScheme"_L1),
+ ChangeSignal(Provider::Kde, Setting::Theme));
+
+ m_signalMap.insert(DBusKey("org.gnome.desktop.interface"_L1, "gtk-theme"_L1),
+ ChangeSignal(Provider::Gtk, Setting::Theme));
+
+ m_signalMap.insert(DBusKey("org.freedesktop.appearance"_L1, "color-scheme"_L1),
+ ChangeSignal(Provider::Gnome, Setting::ColorScheme));
+
+ const QString &saveJsonFile = qEnvironmentVariable("QT_QPA_DBUS_SIGNALS_SAVE");
+ if (!saveJsonFile.isEmpty())
+ saveJson(saveJsonFile);
+}
+
+std::optional<QGenericUnixThemeDBusListener::ChangeSignal>
+ QGenericUnixThemeDBusListener::findSignal(const QString &location, const QString &key) const
+{
+ const DBusKey dkey(location, key);
+ std::optional<QGenericUnixThemeDBusListener::ChangeSignal> ret;
+ if (m_signalMap.contains(dkey))
+ ret.emplace(m_signalMap.value(dkey));
+
+ return ret;
}
void QGenericUnixThemeDBusListener::onSettingChanged(const QString &location, const QString &key, const QDBusVariant &value)
{
- const SettingType type = toSettingType(location, key);
- if (type != SettingType::Unknown)
- emit settingChanged(type, value.variant().toString());
+ auto sig = findSignal(location, key);
+ if (!sig.has_value())
+ return;
+
+ emit settingChanged(sig.value().provider, sig.value().setting, value.variant().toString());
}
#endif //QT_NO_DBUS
@@ -381,24 +579,30 @@ public:
private:
std::unique_ptr<QGenericUnixThemeDBusListener> dbus;
bool initDbus();
- void settingChangedHandler(QGenericUnixThemeDBusListener::SettingType type, const QString &value);
+ void settingChangedHandler(QGenericUnixThemeDBusListener::Provider provider,
+ QGenericUnixThemeDBusListener::Setting setting,
+ const QString &value);
#endif // QT_NO_DBUS
};
#ifndef QT_NO_DBUS
-void QKdeThemePrivate::settingChangedHandler(QGenericUnixThemeDBusListener::SettingType type, const QString &value)
+void QKdeThemePrivate::settingChangedHandler(QGenericUnixThemeDBusListener::Provider provider,
+ QGenericUnixThemeDBusListener::Setting setting,
+ const QString &value)
{
- switch (type) {
- case QGenericUnixThemeDBusListener::SettingType::KdeGlobalTheme:
+ if (provider != QGenericUnixThemeDBusListener::Provider::Kde)
+ return;
+
+ switch (setting) {
+ case QGenericUnixThemeDBusListener::Setting::ColorScheme:
+ qCDebug(lcQpaThemeDBus) << "KDE color theme changed to:" << value;
+ break;
+ case QGenericUnixThemeDBusListener::Setting::Theme:
qCDebug(lcQpaThemeDBus) << "KDE global theme changed to:" << value;
break;
- case QGenericUnixThemeDBusListener::SettingType::KdeApplicationStyle:
+ case QGenericUnixThemeDBusListener::Setting::ApplicationStyle:
qCDebug(lcQpaThemeDBus) << "KDE application style changed to:" << value;
break;
- case QGenericUnixThemeDBusListener::SettingType::GtkTheme:
- return; // KDE can change GTK2 / GTK3 themes. Ignored here, handled in GnomeTheme
- case QGenericUnixThemeDBusListener::SettingType::Unknown:
- Q_UNREACHABLE();
}
refresh();
@@ -406,20 +610,17 @@ void QKdeThemePrivate::settingChangedHandler(QGenericUnixThemeDBusListener::Sett
bool QKdeThemePrivate::initDbus()
{
- static constexpr QLatin1StringView service("");
- static constexpr QLatin1StringView path("/org/freedesktop/portal/desktop");
- static constexpr QLatin1StringView interface("org.freedesktop.portal.Settings");
- static constexpr QLatin1StringView signal("SettingChanged");
-
- dbus.reset(new QGenericUnixThemeDBusListener(service, path, interface, signal));
+ dbus.reset(new QGenericUnixThemeDBusListener());
Q_ASSERT(dbus);
// Wrap slot in a lambda to avoid inheriting QKdeThemePrivate from QObject
- auto wrapper = [this](QGenericUnixThemeDBusListener::SettingType type, const QString &value) {
- settingChangedHandler(type, value);
+ auto wrapper = [this](QGenericUnixThemeDBusListener::Provider provider,
+ QGenericUnixThemeDBusListener::Setting setting,
+ const QString &value) {
+ settingChangedHandler(provider, setting, value);
};
- return QObject::connect(dbus.get(), &QGenericUnixThemeDBusListener::settingChanged, wrapper);
+ return QObject::connect(dbus.get(), &QGenericUnixThemeDBusListener::settingChanged, dbus.get(), wrapper);
}
#endif // QT_NO_DBUS
@@ -756,7 +957,7 @@ Qt::ColorScheme QKdeTheme::colorScheme() const
/*!
\internal
- \brief QKdeTheme::setColorScheme - guess and set appearance for unix themes.
+ \brief QKdeTheme::updateColorScheme - guess and set appearance for unix themes.
KDE themes do not have an appearance property.
The key words "dark" or "light" should be part of the theme name.
This is, however, not a mandatory convention.
@@ -936,21 +1137,23 @@ QGnomeThemePrivate::~QGnomeThemePrivate()
#ifndef QT_NO_DBUS
bool QGnomeThemePrivate::initDbus()
{
- static constexpr QLatin1StringView service("");
- static constexpr QLatin1StringView path("/org/freedesktop/portal/desktop");
- static constexpr QLatin1StringView interface("org.freedesktop.portal.Settings");
- static constexpr QLatin1StringView signal("SettingChanged");
- dbus.reset(new QGenericUnixThemeDBusListener(service, path, interface, signal));
+ dbus.reset(new QGenericUnixThemeDBusListener());
Q_ASSERT(dbus);
// Wrap slot in a lambda to avoid inheriting QGnomeThemePrivate from QObject
- auto wrapper = [this](QGenericUnixThemeDBusListener::SettingType type, const QString &value) {
- if (type == QGenericUnixThemeDBusListener::SettingType::GtkTheme)
+ auto wrapper = [this](QGenericUnixThemeDBusListener::Provider provider,
+ QGenericUnixThemeDBusListener::Setting setting,
+ const QString &value) {
+ if (provider != QGenericUnixThemeDBusListener::Provider::Gnome
+ && provider != QGenericUnixThemeDBusListener::Provider::Gtk) {
+ return;
+ }
+
+ if (setting == QGenericUnixThemeDBusListener::Setting::Theme)
updateColorScheme(value);
};
- return QObject::connect(dbus.get(), &QGenericUnixThemeDBusListener::settingChanged, wrapper);
-
+ return QObject::connect(dbus.get(), &QGenericUnixThemeDBusListener::settingChanged, dbus.get(), wrapper);
}
void QGnomeThemePrivate::updateColorScheme(const QString &themeName)
diff --git a/src/gui/platform/unix/qunixnativeinterface.cpp b/src/gui/platform/unix/qunixnativeinterface.cpp
index 1f891de0f5..09561d9ada 100644
--- a/src/gui/platform/unix/qunixnativeinterface.cpp
+++ b/src/gui/platform/unix/qunixnativeinterface.cpp
@@ -231,10 +231,11 @@ QT_DEFINE_PRIVATE_NATIVE_INTERFACE(QEvdevKeyMapper);
#endif // QT_CONFIG(evdev)
-#if defined(Q_OS_UNIX)
+#if QT_CONFIG(wayland)
/*!
\class QNativeInterface::QWaylandApplication
+ \inheaderfile QGuiApplication
\since 6.5
\brief Native interface to a Wayland application.
@@ -271,19 +272,28 @@ QT_DEFINE_PRIVATE_NATIVE_INTERFACE(QEvdevKeyMapper);
\fn wl_seat *QNativeInterface::QWaylandApplication::lastInputSeat() const
\return the seat on which the last input event happened.
*/
+/*!
+ \fn wl_seat *QNativeInterface::QWaylandApplication::seat() const
+ \return the seat associated with the default input device.
+*/
QT_DEFINE_NATIVE_INTERFACE(QWaylandApplication);
/*!
- \class QNativeInterface::Private::QWaylandScreen
- \since 6.5
- \internal
- \brief Native interface to QPlatformScreen.
+ \class QNativeInterface::QWaylandScreen
+ \since 6.7
+ \brief Native interface to a screen on Wayland.
+
+ Accessed through QScreen::nativeInterface().
\inmodule QtGui
\ingroup native-interfaces
+ \ingroup native-interfaces-qscreen
*/
-
-QT_DEFINE_PRIVATE_NATIVE_INTERFACE(QWaylandScreen);
+/*!
+ \fn wl_output *QNativeInterface::QWaylandScreen::output() const
+ \return the underlying wl_output of this QScreen.
+*/
+QT_DEFINE_NATIVE_INTERFACE(QWaylandScreen);
/*!
\class QNativeInterface::QWaylandWindow
@@ -296,6 +306,6 @@ QT_DEFINE_PRIVATE_NATIVE_INTERFACE(QWaylandScreen);
QT_DEFINE_PRIVATE_NATIVE_INTERFACE(QWaylandWindow);
-#endif // Q_OS_UNIX
+#endif // QT_CONFIG(wayland)
QT_END_NAMESPACE
diff --git a/src/gui/platform/unix/qxkbcommon.cpp b/src/gui/platform/unix/qxkbcommon.cpp
index fafc566e32..ed29db3005 100644
--- a/src/gui/platform/unix/qxkbcommon.cpp
+++ b/src/gui/platform/unix/qxkbcommon.cpp
@@ -17,8 +17,6 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcXkbcommon, "qt.xkbcommon")
-
static int keysymToQtKey_internal(xkb_keysym_t keysym, Qt::KeyboardModifiers modifiers,
xkb_state *state, xkb_keycode_t code,
bool superAsMeta, bool hyperAsMeta);
@@ -239,10 +237,14 @@ static constexpr const auto KeyTbl = qMakeArray(
Xkb2Qt<XKB_KEY_dead_small_schwa, Qt::Key_Dead_Small_Schwa>,
Xkb2Qt<XKB_KEY_dead_capital_schwa, Qt::Key_Dead_Capital_Schwa>,
Xkb2Qt<XKB_KEY_dead_greek, Qt::Key_Dead_Greek>,
+/* The following four XKB_KEY_dead keys got removed in libxkbcommon 1.6.0
+ The define check is kind of version check here. */
+#ifdef XKB_KEY_dead_lowline
Xkb2Qt<XKB_KEY_dead_lowline, Qt::Key_Dead_Lowline>,
Xkb2Qt<XKB_KEY_dead_aboveverticalline, Qt::Key_Dead_Aboveverticalline>,
Xkb2Qt<XKB_KEY_dead_belowverticalline, Qt::Key_Dead_Belowverticalline>,
Xkb2Qt<XKB_KEY_dead_longsolidusoverlay, Qt::Key_Dead_Longsolidusoverlay>,
+#endif
// Special keys from X.org - This include multimedia keys,
// wireless/bluetooth/uwb keys, special launcher keys, etc.
@@ -298,6 +300,7 @@ static constexpr const auto KeyTbl = qMakeArray(
Xkb2Qt<XKB_KEY_XF86Book, Qt::Key_Book>,
Xkb2Qt<XKB_KEY_XF86CD, Qt::Key_CD>,
Xkb2Qt<XKB_KEY_XF86Calculater, Qt::Key_Calculator>,
+ Xkb2Qt<XKB_KEY_XF86Calculator, Qt::Key_Calculator>,
Xkb2Qt<XKB_KEY_XF86Clear, Qt::Key_Clear>,
Xkb2Qt<XKB_KEY_XF86ClearGrab, Qt::Key_ClearGrab>,
Xkb2Qt<XKB_KEY_XF86Close, Qt::Key_Close>,
@@ -488,9 +491,11 @@ int QXkbCommon::keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers modifie
// With standard shortcuts we should prefer a latin character, this is
// for checks like "some qkeyevent == QKeySequence::Copy" to work even
// when using for example 'russian' keyboard layout.
- xkb_keysym_t latinKeysym = QXkbCommon::lookupLatinKeysym(state, code);
- if (latinKeysym != XKB_KEY_NoSymbol)
- keysym = latinKeysym;
+ if (!QXkbCommon::isLatin1(keysym)) {
+ xkb_keysym_t latinKeysym = QXkbCommon::lookupLatinKeysym(state, code);
+ if (latinKeysym != XKB_KEY_NoSymbol)
+ keysym = latinKeysym;
+ }
}
return keysymToQtKey_internal(keysym, modifiers, state, code, superAsMeta, hyperAsMeta);
@@ -510,13 +515,13 @@ static int keysymToQtKey_internal(xkb_keysym_t keysym, Qt::KeyboardModifiers mod
// numeric keypad keys
qtKey = Qt::Key_0 + (keysym - XKB_KEY_KP_0);
} else if (QXkbCommon::isLatin1(keysym)) {
- // Upper-case first, since Qt::Keys are defined in terms of their
- // upper-case versions.
+ // Most Qt::Key values are determined by their upper-case version,
+ // where this is in the Latin-1 repertoire. So start with that:
qtKey = QXkbCommon::qxkbcommon_xkb_keysym_to_upper(keysym);
- // Upper-casing a Latin1 character might move it out of Latin1 range,
- // for example U+00B5 MICRO SIGN, which upper-case equivalent is
- // U+039C GREEK CAPITAL LETTER MU. If that's the case, then map the
- // original lower-case character.
+ // However, Key_mu and Key_ydiaeresis are U+00B5 MICRO SIGN and
+ // U+00FF LATIN SMALL LETTER Y WITH DIAERESIS, both lower-case,
+ // with upper-case forms outside Latin-1, so use them as they are
+ // since they're the Qt::Key values.
if (!QXkbCommon::isLatin1(qtKey))
qtKey = keysym;
} else {
@@ -562,7 +567,7 @@ static int keysymToQtKey_internal(xkb_keysym_t keysym, Qt::KeyboardModifiers mod
return qtKey;
}
-Qt::KeyboardModifiers QXkbCommon::modifiers(struct xkb_state *state)
+Qt::KeyboardModifiers QXkbCommon::modifiers(struct xkb_state *state, xkb_keysym_t keysym)
{
Qt::KeyboardModifiers modifiers = Qt::NoModifier;
@@ -575,6 +580,9 @@ Qt::KeyboardModifiers QXkbCommon::modifiers(struct xkb_state *state)
if (xkb_state_mod_name_is_active(state, XKB_MOD_NAME_LOGO, XKB_STATE_MODS_EFFECTIVE) > 0)
modifiers |= Qt::MetaModifier;
+ if (isKeypad(keysym))
+ modifiers |= Qt::KeypadModifier;
+
return modifiers;
}
@@ -591,10 +599,24 @@ static const Qt::KeyboardModifiers ModsTbl[] = {
Qt::NoModifier // Fall-back to raw Key_*, for non-latin1 kb layouts
};
+/*
+ Compatibility until all sub modules have transitioned to new API below
+*/
QList<int> QXkbCommon::possibleKeys(xkb_state *state, const QKeyEvent *event,
bool superAsMeta, bool hyperAsMeta)
{
QList<int> result;
+ auto keyCombinations = possibleKeyCombinations(state, event, superAsMeta, hyperAsMeta);
+ for (auto keyCombination : keyCombinations)
+ result << keyCombination.toCombined();
+
+ return result;
+}
+
+QList<QKeyCombination> QXkbCommon::possibleKeyCombinations(xkb_state *state, const QKeyEvent *event,
+ bool superAsMeta, bool hyperAsMeta)
+{
+ QList<QKeyCombination> result;
quint32 keycode = event->nativeScanCode();
if (!keycode)
return result;
@@ -608,7 +630,7 @@ QList<int> QXkbCommon::possibleKeys(xkb_state *state, const QKeyEvent *event,
ScopedXKBState scopedXkbQueryState(xkb_state_new(keymap));
xkb_state *queryState = scopedXkbQueryState.get();
if (!queryState) {
- qCWarning(lcXkbcommon) << Q_FUNC_INFO << "failed to compile xkb keymap";
+ qCWarning(lcQpaKeyMapper) << Q_FUNC_INFO << "failed to compile xkb keymap";
return result;
}
// get kb state from the master state and update the temporary state
@@ -634,7 +656,7 @@ QList<int> QXkbCommon::possibleKeys(xkb_state *state, const QKeyEvent *event,
int baseQtKey = keysymToQtKey_internal(sym, modifiers, queryState, keycode, superAsMeta, hyperAsMeta);
if (baseQtKey)
- result += (baseQtKey + int(modifiers));
+ result += QKeyCombination::fromCombined(baseQtKey + int(modifiers));
xkb_mod_index_t shiftMod = xkb_keymap_mod_get_index(keymap, "Shift");
xkb_mod_index_t altMod = xkb_keymap_mod_get_index(keymap, "Alt");
@@ -680,8 +702,9 @@ QList<int> QXkbCommon::possibleKeys(xkb_state *state, const QKeyEvent *event,
// catch only more specific shortcuts, i.e. Ctrl+Shift+= also generates Ctrl++ and +,
// but Ctrl++ is more specific than +, so we should skip the last one
bool ambiguous = false;
- for (int shortcut : std::as_const(result)) {
- if (int(shortcut & ~Qt::KeyboardModifierMask) == qtKey && (shortcut & mods) == mods) {
+ for (auto keyCombination : std::as_const(result)) {
+ if (keyCombination.key() == qtKey
+ && (keyCombination.keyboardModifiers() & mods) == mods) {
ambiguous = true;
break;
}
@@ -689,7 +712,7 @@ QList<int> QXkbCommon::possibleKeys(xkb_state *state, const QKeyEvent *event,
if (ambiguous)
continue;
- result += (qtKey + int(mods));
+ result += QKeyCombination::fromCombined(qtKey + int(mods));
}
}
@@ -721,18 +744,23 @@ void QXkbCommon::verifyHasLatinLayout(xkb_keymap *keymap)
// selected layouts is irrelevant. Properly functioning desktop environments
// handle this behind the scenes, even if no latin key based layout has been
// explicitly listed in the selected layouts.
- qCDebug(lcXkbcommon, "no keyboard layouts with latin keys present");
+ qCDebug(lcQpaKeyMapper, "no keyboard layouts with latin keys present");
}
xkb_keysym_t QXkbCommon::lookupLatinKeysym(xkb_state *state, xkb_keycode_t keycode)
{
xkb_layout_index_t layout;
xkb_keysym_t sym = XKB_KEY_NoSymbol;
+ if (!state)
+ return sym;
xkb_keymap *keymap = xkb_state_get_keymap(state);
const xkb_layout_index_t layoutCount = xkb_keymap_num_layouts_for_key(keymap, keycode);
+ const xkb_layout_index_t currentLayout = xkb_state_key_get_layout(state, keycode);
// Look at user layouts in the order in which they are defined in system
// settings to find a latin keysym.
for (layout = 0; layout < layoutCount; ++layout) {
+ if (layout == currentLayout)
+ continue;
const xkb_keysym_t *syms = nullptr;
xkb_level_index_t level = xkb_state_key_get_level(state, keycode, layout);
if (xkb_keymap_key_get_syms_by_level(keymap, keycode, layout, level, &syms) != 1)
@@ -743,6 +771,34 @@ xkb_keysym_t QXkbCommon::lookupLatinKeysym(xkb_state *state, xkb_keycode_t keyco
}
}
+ if (sym == XKB_KEY_NoSymbol)
+ return sym;
+
+ xkb_mod_mask_t latchedMods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LATCHED);
+ xkb_mod_mask_t lockedMods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LOCKED);
+
+ // Check for uniqueness, consider the following setup:
+ // setxkbmap -layout us,ru,us -variant dvorak,, -option 'grp:ctrl_alt_toggle' (set 'ru' as active).
+ // In this setup, the user would expect to trigger a ctrl+q shortcut by pressing ctrl+<physical x key>,
+ // because "US dvorak" is higher up in the layout settings list. This check verifies that an obtained
+ // 'sym' can not be acquired by any other layout higher up in the user's layout list. If it can be acquired
+ // then the obtained key is not unique. This prevents ctrl+<physical q key> from generating a ctrl+q
+ // shortcut in the above described setup. We don't want ctrl+<physical x key> and ctrl+<physical q key> to
+ // generate the same shortcut event in this case.
+ const xkb_keycode_t minKeycode = xkb_keymap_min_keycode(keymap);
+ const xkb_keycode_t maxKeycode = xkb_keymap_max_keycode(keymap);
+ ScopedXKBState queryState(xkb_state_new(keymap));
+ for (xkb_layout_index_t prevLayout = 0; prevLayout < layout; ++prevLayout) {
+ xkb_state_update_mask(queryState.get(), 0, latchedMods, lockedMods, 0, 0, prevLayout);
+ for (xkb_keycode_t code = minKeycode; code < maxKeycode; ++code) {
+ xkb_keysym_t prevSym = xkb_state_key_get_one_sym(queryState.get(), code);
+ if (prevSym == sym) {
+ sym = XKB_KEY_NoSymbol;
+ break;
+ }
+ }
+ }
+
return sym;
}
@@ -762,7 +818,7 @@ void QXkbCommon::setXkbContext(QPlatformInputContext *inputContext, struct xkb_c
QMetaMethod method = inputContext->metaObject()->method(methodIndex);
Q_ASSERT(method.isValid());
if (!method.isValid())
- qCWarning(lcXkbcommon) << normalizedSignature << "not found on" << inputContextClassName;
+ qCWarning(lcQpaKeyMapper) << normalizedSignature << "not found on" << inputContextClassName;
return method;
}();
diff --git a/src/gui/platform/unix/qxkbcommon_p.h b/src/gui/platform/unix/qxkbcommon_p.h
index adc96b2ad4..a40d794451 100644
--- a/src/gui/platform/unix/qxkbcommon_p.h
+++ b/src/gui/platform/unix/qxkbcommon_p.h
@@ -23,12 +23,12 @@
#include <xkbcommon/xkbcommon.h>
+#include <qpa/qplatformkeymapper.h>
+
#include <memory>
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcXkbcommon)
-
class QEvent;
class QKeyEvent;
class QPlatformInputContext;
@@ -44,26 +44,67 @@ public:
static int keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers modifiers);
static int keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers modifiers,
xkb_state *state, xkb_keycode_t code,
- bool superAsMeta = false, bool hyperAsMeta = false);
+ bool superAsMeta = true, bool hyperAsMeta = true);
// xkbcommon_* API is part of libxkbcommon internals, with modifications as
// described in the header of the implementation file.
static void xkbcommon_XConvertCase(xkb_keysym_t sym, xkb_keysym_t *lower, xkb_keysym_t *upper);
static xkb_keysym_t qxkbcommon_xkb_keysym_to_upper(xkb_keysym_t ks);
- static Qt::KeyboardModifiers modifiers(struct xkb_state *state);
+ static Qt::KeyboardModifiers modifiers(struct xkb_state *state, xkb_keysym_t keysym = XKB_KEY_VoidSymbol);
- static QList<int> possibleKeys(xkb_state *state, const QKeyEvent *event,
- bool superAsMeta = false, bool hyperAsMeta = false);
+ static QList<int> possibleKeys(xkb_state *state,
+ const QKeyEvent *event, bool superAsMeta = false, bool hyperAsMeta = false);
+ static QList<QKeyCombination> possibleKeyCombinations(xkb_state *state,
+ const QKeyEvent *event, bool superAsMeta = false, bool hyperAsMeta = false);
static void verifyHasLatinLayout(xkb_keymap *keymap);
static xkb_keysym_t lookupLatinKeysym(xkb_state *state, xkb_keycode_t keycode);
static bool isLatin1(xkb_keysym_t sym) {
- return sym <= 0xff;
+ return sym >= 0x20 && sym <= 0xff;
}
static bool isKeypad(xkb_keysym_t sym) {
- return sym >= XKB_KEY_KP_Space && sym <= XKB_KEY_KP_9;
+ switch (sym) {
+ case XKB_KEY_KP_Space:
+ case XKB_KEY_KP_Tab:
+ case XKB_KEY_KP_Enter:
+ case XKB_KEY_KP_F1:
+ case XKB_KEY_KP_F2:
+ case XKB_KEY_KP_F3:
+ case XKB_KEY_KP_F4:
+ case XKB_KEY_KP_Home:
+ case XKB_KEY_KP_Left:
+ case XKB_KEY_KP_Up:
+ case XKB_KEY_KP_Right:
+ case XKB_KEY_KP_Down:
+ case XKB_KEY_KP_Prior:
+ case XKB_KEY_KP_Next:
+ case XKB_KEY_KP_End:
+ case XKB_KEY_KP_Begin:
+ case XKB_KEY_KP_Insert:
+ case XKB_KEY_KP_Delete:
+ case XKB_KEY_KP_Equal:
+ case XKB_KEY_KP_Multiply:
+ case XKB_KEY_KP_Add:
+ case XKB_KEY_KP_Separator:
+ case XKB_KEY_KP_Subtract:
+ case XKB_KEY_KP_Decimal:
+ case XKB_KEY_KP_Divide:
+ case XKB_KEY_KP_0:
+ case XKB_KEY_KP_1:
+ case XKB_KEY_KP_2:
+ case XKB_KEY_KP_3:
+ case XKB_KEY_KP_4:
+ case XKB_KEY_KP_5:
+ case XKB_KEY_KP_6:
+ case XKB_KEY_KP_7:
+ case XKB_KEY_KP_8:
+ case XKB_KEY_KP_9:
+ return true;
+ default:
+ return false;
+ }
}
static void setXkbContext(QPlatformInputContext *inputContext, struct xkb_context *context);
diff --git a/src/gui/platform/wasm/qlocalfileapi.cpp b/src/gui/platform/wasm/qlocalfileapi.cpp
index bfcb5a5866..76b99361c4 100644
--- a/src/gui/platform/wasm/qlocalfileapi.cpp
+++ b/src/gui/platform/wasm/qlocalfileapi.cpp
@@ -12,26 +12,15 @@ std::string qtFilterListToFileInputAccept(const QStringList &filterList)
{
QStringList transformed;
for (const auto &filter : filterList) {
-
- emscripten::val::global("console").call<void>("log", filter.toStdString());
-
const auto type = Type::fromQt(filter);
if (type && type->accept()) {
const auto &extensions = type->accept()->mimeType().extensions();
- for (const auto &ext : extensions) {
- emscripten::val::global("console").call<void>("log",
- ext.value().toString().toStdString());
- }
-
std::transform(extensions.begin(), extensions.end(), std::back_inserter(transformed),
[](const Type::Accept::MimeType::Extension &extension) {
return extension.value().toString();
});
}
}
- for (const QString &tran : transformed) {
- emscripten::val::global("console").call<void>("log", tran.toStdString());
- }
return transformed.join(QStringLiteral(",")).toStdString();
}
@@ -39,13 +28,12 @@ std::optional<emscripten::val> qtFilterListToTypes(const QStringList &filterList
{
using namespace qstdweb;
using namespace emscripten;
-
auto types = emscripten::val::array();
for (const auto &fileFilter : filterList) {
auto type = Type::fromQt(fileFilter);
if (type) {
- auto jsType = val::object();
+ auto jsType = emscripten::val::object();
jsType.set("description", type->description().toString().toStdString());
if (type->accept()) {
jsType.set("accept", ([&mimeType = type->accept()->mimeType()]() {
@@ -190,7 +178,7 @@ Type::Accept::MimeType::Extension::fromQt(QStringView qtRepresentation)
emscripten::val makeOpenFileOptions(const QStringList &filterList, bool acceptMultiple)
{
auto options = emscripten::val::object();
- if (auto typeList = qtFilterListToTypes(filterList)) {
+ if (auto typeList = qtFilterListToTypes(filterList); typeList) {
options.set("types", std::move(*typeList));
options.set("excludeAcceptAllOption", true);
}
diff --git a/src/gui/platform/wasm/qwasmlocalfileaccess.cpp b/src/gui/platform/wasm/qwasmlocalfileaccess.cpp
index 762d5e1a40..a946cda043 100644
--- a/src/gui/platform/wasm/qwasmlocalfileaccess.cpp
+++ b/src/gui/platform/wasm/qwasmlocalfileaccess.cpp
@@ -135,66 +135,18 @@ void readFiles(const qstdweb::FileList &fileList,
(*readFile)(0);
}
-QStringList acceptListFromQtFormat(const std::string &qtAcceptList)
+QStringList makeFilterList(const std::string &qtAcceptList)
{
// copy of qt_make_filter_list() from qfiledialog.cpp
- auto make_filter_list = [](const QString &filter) -> QStringList
- {
- if (filter.isEmpty())
- return QStringList();
-
- QString sep(";;");
- if (!filter.contains(sep) && filter.contains(u'\n'))
- sep = u'\n';
-
- return filter.split(sep);
- };
-
- const QStringList fileFilter = make_filter_list(QString::fromStdString(qtAcceptList));
- QStringList transformed;
- for (const auto &element : fileFilter) {
- // Accepts either a string in format:
- // GROUP3
- // or in this format:
- // GROUP1 (GROUP2)
- // Group 1 is treated as the description, whereas group 2 or 3 are treated as the filter
- // list.
- static QRegularExpression regex(
- QString(QStringLiteral("(?:([^(]*)\\(([^()]+)\\)[^)]*)|([^()]+)")));
- static QRegularExpression wordCharacterRegex(QString(QStringLiteral("\\w")));
- const auto match = regex.match(element);
-
- if (!match.hasMatch())
- continue;
-
- constexpr size_t FilterListFromParensIndex = 2;
- constexpr size_t PlainFilterListIndex = 3;
- QString filterList = match.captured(match.hasCaptured(FilterListFromParensIndex)
- ? FilterListFromParensIndex
- : PlainFilterListIndex);
- for (auto singleExtension : filterList.split(QStringLiteral(" "), Qt::SkipEmptyParts)) {
- // Checks for a filter that matches everything:
- // Any number of asterisks or any number of asterisks with a '.' between them.
- // The web filter does not support wildcards.
- static QRegularExpression qtAcceptAllRegex(QRegularExpression::anchoredPattern(
- QString(QStringLiteral("[*]+|[*]+\\.[*]+"))));
- if (qtAcceptAllRegex.match(singleExtension).hasMatch())
- continue;
-
- // Checks for correctness. The web filter only allows filename extensions and does not
- // filter the actual filenames, therefore we check whether the filter provided only
- // filters for the extension.
- static QRegularExpression qtFilenameMatcherRegex(QRegularExpression::anchoredPattern(
- QString(QStringLiteral("(\\*?)(\\.[^*]+)"))));
-
- auto extensionMatch = qtFilenameMatcherRegex.match(singleExtension);
- if (extensionMatch.hasMatch())
- transformed.append(extensionMatch.captured(2));
- }
- }
- return transformed;
+ auto filter = QString::fromStdString(qtAcceptList);
+ if (filter.isEmpty())
+ return QStringList();
+ QString sep(";;");
+ if (!filter.contains(sep) && filter.contains(u'\n'))
+ sep = u'\n';
+
+ return filter.split(sep);
}
-
}
void downloadDataAsFile(const char *content, size_t size, const std::string &fileNameHint)
@@ -225,7 +177,7 @@ void openFiles(const std::string &accept, FileSelectMode fileSelectMode,
const std::function<char *(uint64_t size, const std::string& name)> &acceptFile,
const std::function<void()> &fileDataReady)
{
- FileDialog::showOpen(acceptListFromQtFormat(accept), fileSelectMode, {
+ FileDialog::showOpen(makeFilterList(accept), fileSelectMode, {
.thenFunc = [=](emscripten::val result) {
auto files = qstdweb::FileList(result);
fileDialogClosed(files.length());
@@ -258,6 +210,11 @@ void saveDataToFileInChunks(emscripten::val fileHandle, const QByteArray &data)
std::function<void(val result)> continuation;
};
+ static constexpr size_t desiredChunkSize = 1024u;
+#if defined(__EMSCRIPTEN_SHARED_MEMORY__)
+ qstdweb::Uint8Array chunkArray(desiredChunkSize);
+#endif
+
auto state = std::make_shared<State>();
state->written = 0u;
state->continuation = [=](val) mutable {
@@ -267,11 +224,30 @@ void saveDataToFileInChunks(emscripten::val fileHandle, const QByteArray &data)
state.reset();
return;
}
- static constexpr size_t desiredChunkSize = 1024u;
+
const auto currentChunkSize = std::min(remaining, desiredChunkSize);
- Promise::make(writable, QStringLiteral("write"), {
- .thenFunc = state->continuation,
- }, val(typed_memory_view(currentChunkSize, data.constData() + state->written)));
+
+#if defined(__EMSCRIPTEN_SHARED_MEMORY__)
+ // If shared memory is used, WebAssembly.Memory is instantiated with the 'shared'
+ // option on. Passing a typed_memory_view to SharedArrayBuffer to
+ // FileSystemWritableFileStream.write is disallowed by security policies, so we
+ // need to make a copy of the data to a chunk array buffer.
+ Promise::make(
+ writable, QStringLiteral("write"),
+ {
+ .thenFunc = state->continuation,
+ },
+ chunkArray.copyFrom(data.constData() + state->written, currentChunkSize)
+ .val()
+ .call<emscripten::val>("subarray", emscripten::val(0),
+ emscripten::val(currentChunkSize)));
+#else
+ Promise::make(writable, QStringLiteral("write"),
+ {
+ .thenFunc = state->continuation,
+ },
+ val(typed_memory_view(currentChunkSize, data.constData() + state->written)));
+#endif
state->written += currentChunkSize;
};
diff --git a/src/gui/platform/wasm/qwasmnativeinterface.cpp b/src/gui/platform/wasm/qwasmnativeinterface.cpp
new file mode 100644
index 0000000000..7313629a8d
--- /dev/null
+++ b/src/gui/platform/wasm/qwasmnativeinterface.cpp
@@ -0,0 +1,17 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+
+
+#include <QtGui/private/qguiapplication_p.h>
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformwindow_p.h>
+
+
+QT_BEGIN_NAMESPACE
+
+using namespace QNativeInterface::Private;
+
+QT_DEFINE_PRIVATE_NATIVE_INTERFACE(QWasmWindow);
+
+QT_END_NAMESPACE
diff --git a/src/gui/platform/windows/qwindowsguieventdispatcher.cpp b/src/gui/platform/windows/qwindowsguieventdispatcher.cpp
index f70655380d..c2f0efe96e 100644
--- a/src/gui/platform/windows/qwindowsguieventdispatcher.cpp
+++ b/src/gui/platform/windows/qwindowsguieventdispatcher.cpp
@@ -197,3 +197,5 @@ const char *QWindowsGuiEventDispatcher::windowsMessageName(UINT msg)
}
QT_END_NAMESPACE
+
+#include "moc_qwindowsguieventdispatcher_p.cpp"
diff --git a/src/gui/platform/windows/qwindowsmimeconverter.cpp b/src/gui/platform/windows/qwindowsmimeconverter.cpp
index d7998a3eb7..49d524cb99 100644
--- a/src/gui/platform/windows/qwindowsmimeconverter.cpp
+++ b/src/gui/platform/windows/qwindowsmimeconverter.cpp
@@ -25,6 +25,22 @@ QT_BEGIN_NAMESPACE
conversions between Windows Clipboard and MIME formats, you can convert
proprietary clipboard formats to MIME formats.
+ Construct an instance of your converter implementation after instantiating
+ QGuiApplication:
+
+ \code
+ int main(int argc, char **argv)
+ {
+ QGuiApplication app(argc, argv);
+ JsonMimeConverter jsonConverter;
+ }
+ \endcode
+
+ Destroying the instance will unregister the converter and remove support
+ for the conversion. It is also valid to heap-allocate the converter
+ instance; Qt takes ownership and will delete the converter object during
+ QGuiApplication shut-down.
+
Qt has predefined support for the following Windows Clipboard formats:
\table
@@ -112,6 +128,8 @@ QT_BEGIN_NAMESPACE
The instance is automatically registered, and will be called to convert data during
clipboard or drag'n'drop operations.
+
+ Call this constructor after QGuiApplication has been created.
*/
QWindowsMimeConverter::QWindowsMimeConverter()
{
diff --git a/src/gui/platform/windows/qwindowsnativeinterface.cpp b/src/gui/platform/windows/qwindowsnativeinterface.cpp
index 86c6593f5d..44f230e1d3 100644
--- a/src/gui/platform/windows/qwindowsnativeinterface.cpp
+++ b/src/gui/platform/windows/qwindowsnativeinterface.cpp
@@ -89,14 +89,20 @@ QOpenGLContext *QNativeInterface::QWGLContext::fromNative(HGLRC context, HWND wi
QT_DEFINE_PRIVATE_NATIVE_INTERFACE(QWindowsApplication);
/*!
- \class QNativeInterface::Private::QWindowsScreen
- \since 6.5
- \internal
- \brief Native interface to QScreen, to be retrieved from QPlatformIntegration.
+ \class QNativeInterface::QWindowsScreen
+ \since 6.7
+ \brief Native interface to a screen.
+
+ Accessed through QScreen::nativeInterface().
\inmodule QtGui
\ingroup native-interfaces
+ \ingroup native-interfaces-qscreen
*/
-QT_DEFINE_PRIVATE_NATIVE_INTERFACE(QWindowsScreen);
+/*!
+ * \fn HWMONITOR QNativeInterface::QWindowsScreen::handle() const;
+ * \return The underlying HWMONITOR of the screen.
+ */
+QT_DEFINE_NATIVE_INTERFACE(QWindowsScreen);
/*!
\enum QNativeInterface::Private::QWindowsApplication::TouchWindowTouchType
@@ -175,15 +181,7 @@ QT_DEFINE_PRIVATE_NATIVE_INTERFACE(QWindowsScreen);
\value DarkModeStyle The Windows Vista style will be turned off and
a simple dark style will be used.
- \sa isDarkMode(), setDarkModeHandling()
-*/
-
-/*!
- \fn bool QNativeInterface::Private::QWindowsApplication::isDarkMode() const = 0
- \internal
-
- Returns \c true if Windows 10 is configured to use dark mode for
- applications.
+ \sa setDarkModeHandling()
*/
/*!
diff --git a/src/gui/platform/windows/qwindowsthemecache.cpp b/src/gui/platform/windows/qwindowsthemecache.cpp
new file mode 100644
index 0000000000..3bb92e67ca
--- /dev/null
+++ b/src/gui/platform/windows/qwindowsthemecache.cpp
@@ -0,0 +1,79 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwindowsthemecache_p.h"
+#include <QtCore/qdebug.h>
+#include <QtCore/qhash.h>
+
+QT_BEGIN_NAMESPACE
+
+// Theme names matching the QWindowsVistaStylePrivate::Theme enumeration.
+constexpr const wchar_t *themeNames[] = {
+ L"BUTTON", L"COMBOBOX", L"EDIT", L"HEADER", L"LISTVIEW",
+ L"MENU", L"PROGRESS", L"REBAR", L"SCROLLBAR", L"SPIN",
+ L"TAB", L"TASKDIALOG", L"TOOLBAR", L"TOOLTIP", L"TRACKBAR",
+ L"WINDOW", L"STATUS", L"TREEVIEW"
+};
+
+typedef std::array<HTHEME, std::size(themeNames)> ThemeArray;
+typedef QHash<HWND, ThemeArray> ThemesCache;
+Q_GLOBAL_STATIC(ThemesCache, themesCache);
+
+QString QWindowsThemeCache::themeName(int theme)
+{
+ return theme >= 0 && theme < int(std::size(themeNames))
+ ? QString::fromWCharArray(themeNames[theme]) : QString();
+}
+
+HTHEME QWindowsThemeCache::createTheme(int theme, HWND hwnd)
+{
+ if (Q_UNLIKELY(theme < 0 || theme >= int(std::size(themeNames)) || !hwnd)) {
+ qWarning("Invalid parameters #%d, %p", theme, hwnd);
+ return nullptr;
+ }
+
+ // Get or create themes array for this window.
+ ThemesCache *cache = themesCache();
+ auto it = cache->find(hwnd);
+ if (it == cache->end())
+ it = cache->insert(hwnd, ThemeArray {});
+
+ // Get or create theme data
+ ThemeArray &themes = *it;
+ if (!themes[theme]) {
+ const wchar_t *name = themeNames[theme];
+ themes[theme] = OpenThemeData(hwnd, name);
+ if (Q_UNLIKELY(!themes[theme]))
+ qErrnoWarning("OpenThemeData() failed for theme %d (%s).",
+ theme, qPrintable(themeName(theme)));
+ }
+ return themes[theme];
+}
+
+static void clearThemes(ThemeArray &themes)
+{
+ for (auto &theme : themes) {
+ if (theme) {
+ CloseThemeData(theme);
+ theme = nullptr;
+ }
+ }
+}
+
+void QWindowsThemeCache::clearThemeCache(HWND hwnd)
+{
+ ThemesCache *cache = themesCache();
+ auto it = cache->find(hwnd);
+ if (it == cache->end())
+ return;
+ clearThemes(*it);
+}
+
+void QWindowsThemeCache::clearAllThemeCaches()
+{
+ ThemesCache *cache = themesCache();
+ for (auto &themeArray : *cache)
+ clearThemes(themeArray);
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/platform/windows/qwindowsthemecache_p.h b/src/gui/platform/windows/qwindowsthemecache_p.h
new file mode 100644
index 0000000000..beb724dc5c
--- /dev/null
+++ b/src/gui/platform/windows/qwindowsthemecache_p.h
@@ -0,0 +1,35 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWINDOWSTHEME_CACHE_P_H
+#define QWINDOWSTHEME_CACHE_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 <QtCore/qt_windows.h>
+#include <uxtheme.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QWindowsThemeCache
+{
+ Q_GUI_EXPORT QString themeName(int theme);
+ Q_GUI_EXPORT HTHEME createTheme(int theme, HWND hwnd);
+ Q_GUI_EXPORT void clearThemeCache(HWND hwnd);
+ Q_GUI_EXPORT void clearAllThemeCaches();
+}
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSTHEME_CACHE_P_H
diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp
index 3b9c150166..a39709c726 100644
--- a/src/gui/rhi/qrhi.cpp
+++ b/src/gui/rhi/qrhi.cpp
@@ -1,23 +1,23 @@
-// Copyright (C) 2019 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qrhi_p_p.h"
+#include "qrhi_p.h"
#include <qmath.h>
#include <QLoggingCategory>
-#include "qrhinull_p_p.h"
+#include "qrhinull_p.h"
#ifndef QT_NO_OPENGL
-#include "qrhigles2_p_p.h"
+#include "qrhigles2_p.h"
#endif
#if QT_CONFIG(vulkan)
-#include "qrhivulkan_p_p.h"
+#include "qrhivulkan_p.h"
#endif
#ifdef Q_OS_WIN
-#include "qrhid3d11_p_p.h"
-#include "qrhid3d12_p_p.h"
+#include "qrhid3d11_p.h"
+#include "qrhid3d12_p.h"
#endif
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
-#include "qrhimetal_p_p.h"
+#if QT_CONFIG(metal)
+#include "qrhimetal_p.h"
#endif
#include <memory>
@@ -28,8 +28,10 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
/*!
\class QRhi
- \internal
- \inmodule QtGui
+ \ingroup painting-3D
+ \inmodule QtGuiPrivate
+ \inheaderfile rhi/qrhi.h
+ \since 6.6
\brief Accelerated 2D/3D graphics API abstraction.
@@ -40,52 +42,55 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
\l{https://developer.apple.com/metal/}{Metal}, and
\l{https://www.khronos.org/vulkan/}{Vulkan}.
- Some of the main design goals are:
-
- \list
-
- \li Simple, minimal, understandable, extensible. Follow the proven path of the
- Qt Quick scenegraph.
-
- \li Aim to be a product - and in the bigger picture, part of a product (Qt) -
- that is usable out of the box both by internal (such as, Qt Quick) and,
- eventually, external users.
-
- \li Not a complete 1:1 wrapper for any of the underlying APIs. The feature set
- is tuned towards the needs of Qt's 2D and 3D offering (QPainter, Qt Quick, Qt
- 3D Studio). Iterate and evolve in a sustainable manner.
-
- \li Intrinsically cross-platform, without reinventing: abstracting
- cross-platform aspects of certain APIs (such as, OpenGL context creation and
- windowing system interfaces, Vulkan instance and surface management) is not in
- scope here. These are delegated to the existing QtGui facilities (QWindow,
- QOpenGLContext, QVulkanInstance) and its backing QPA architecture.
-
- \endlist
+ \warning The QRhi family of classes in the Qt Gui module, including QShader
+ and QShaderDescription, offer limited compatibility guarantees. There are
+ no source or binary compatibility guarantees for these classes, meaning the
+ API is only guaranteed to work with the Qt version the application was
+ developed against. Source incompatible changes are however aimed to be kept
+ at a minimum and will only be made in minor releases (6.7, 6.8, and so on).
+ To use these classes in an application, link to
+ \c{Qt::GuiPrivate} (if using CMake), and include the headers with the \c
+ rhi prefix, for example \c{#include <rhi/qrhi.h>}.
Each QRhi instance is backed by a backend for a specific graphics API. The
selection of the backend is a run time choice and is up to the application
or library that creates the QRhi instance. Some backends are available on
multiple platforms (OpenGL, Vulkan, Null), while APIs specific to a given
platform are only available when running on the platform in question (Metal
- on macOS/iOS/tvOS, Direct3D on Windows).
+ on macOS/iOS, Direct3D on Windows).
The available backends currently are:
\list
- \li OpenGL 2.1 or OpenGL ES 2.0 or newer. Some extensions are utilized when
- present, for example to enable multisample framebuffers.
+ \li OpenGL 2.1 / OpenGL ES 2.0 or newer. Some extensions and newer core
+ specification features are utilized when present, for example to enable
+ multisample framebuffers or compute shaders. Operating in core profile
+ contexts is supported as well. If necessary, applications can query the
+ \l{QRhi::Feature}{feature flags} at runtime to check for features that are
+ not supported in the OpenGL context backing the QRhi. The OpenGL backend
+ builds on QOpenGLContext, QOpenGLFunctions, and the related cross-platform
+ infrastructure of the Qt GUI module.
- \li Direct3D 11.1
+ \li Direct3D 11.1 or newer, with Shader Model 5.0 or newer. When the D3D
+ runtime has no support for 11.1 features or Shader Model 5.0,
+ initialization using an accelerated graphics device will fail, but using
+ the
+ \l{https://learn.microsoft.com/en-us/windows/win32/direct3darticles/directx-warp}{software
+ adapter} is still an option.
- \li Direct3D 12
+ \li Direct3D 12 on Windows 10 version 1703 and newer, with Shader Model 5.0
+ or newer. Qt requires ID3D12Device2 to be present, hence the requirement
+ for at least version 1703 of Windows 10. The D3D12 device is by default
+ created with specifying a minimum feature level of
+ \c{D3D_FEATURE_LEVEL_11_0}.
- \li Metal
+ \li Metal 1.2 or newer.
- \li Vulkan 1.0, optionally with some extensions that are part of Vulkan 1.1
+ \li Vulkan 1.0 or newer, optionally utilizing some Vulkan 1.1 level
+ features.
- \li Null - A "dummy" backend that issues no graphics calls at all.
+ \li Null, a "dummy" backend that issues no graphics calls at all.
\endlist
@@ -95,15 +100,60 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
are then generated from that, together with reflection information (inputs,
outputs, shader resources). This is then packed into easily and efficiently
serializable QShader instances. The compilers and tools to generate such
- shaders are not part of QRhi, but the core classes for using such shaders,
- QShader and QShaderDescription, are.
+ shaders are not part of QRhi and the Qt GUI module, but the core classes
+ for using such shaders, QShader and QShaderDescription, are. The APIs and
+ tools for performing compilation and translation are part of the Qt Shader
+ Tools module.
+
+ See the \l{RHI Window Example} for an introductory example of creating a
+ portable, cross-platform application that performs accelerated 3D rendering
+ onto a QWindow using QRhi.
+
+ \section1 An Impression of the API
- \section2 Design Fundamentals
+ To provide a quick look at the API with a short yet complete example that
+ does not involve window-related setup, the following is a complete,
+ runnable cross-platform application that renders 20 frames off-screen, and
+ then saves the generated images to files after reading back the texture
+ contents from the GPU. For an example that renders on-screen, which then
+ involves setting up a QWindow and a swapchain, refer to the
+ \l{RHI Window Example}.
+
+ For brevity, the initialization of the QRhi is done based on the platform:
+ the sample code here chooses Direct 3D 12 on Windows, Metal on macOS and
+ iOS, and Vulkan otherwise. OpenGL and Direct 3D 11 are never used by this
+ application, but support for those could be introduced with a few
+ additional lines.
+
+ \snippet rhioffscreen/main.cpp 0
+
+ The result of the application is 20 \c PNG images (frame0.png -
+ frame19.png). These contain a rotating triangle with varying opacity over a
+ green background.
+
+ The vertex and fragment shaders are expected to be processed and packaged
+ into \c{.qsb} files. The Vulkan-compatible GLSL source code is the
+ following:
+
+ \e color.vert
+ \snippet rhioffscreen/color.vert 0
+
+ \e color.frag
+ \snippet rhioffscreen/color.frag 0
+
+ To manually compile and transpile these shaders to a number of targets
+ (SPIR-V, HLSL, MSL, GLSL) and generate the \c{.qsb} files the application
+ loads at run time, run \c{qsb --qt6 color.vert -o color.vert.qsb} and
+ \c{qsb --qt6 color.frag -o color.frag.qsb}. Alternatively, the Qt Shader
+ Tools module offers build system integration for CMake, the
+ \c qt_add_shaders() CMake function, that can achieve the same at build time.
+
+ \section1 Design Fundamentals
A QRhi cannot be instantiated directly. Instead, use the create()
function. Delete the QRhi instance normally to release the graphics device.
- \section3 Resources
+ \section2 Resources
Instances of classes deriving from QRhiResource, such as, QRhiBuffer,
QRhiTexture, etc., encapsulate zero, one, or more native graphics
@@ -111,10 +161,10 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
functions of the QRhi, such as, newBuffer(), newTexture(),
newTextureRenderTarget(), newSwapChain().
- \badcode
- vbuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData));
- if (!vbuf->create()) { error }
- ...
+ \code
+ QRhiBuffer *vbuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData));
+ if (!vbuf->create()) { error(); }
+ // ...
delete vbuf;
\endcode
@@ -123,9 +173,10 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
\li The returned value from functions like newBuffer() is always owned by
the caller.
- \li Just creating a QRhiResource subclass never allocates or initializes any
- native resources. That is only done when calling the \c create() function of a
- subclass, for example, QRhiBuffer::create() or QRhiTexture::create().
+ \li Just creating an instance of a QRhiResource subclass never allocates or
+ initializes any native resources. That is only done when calling the
+ \c create() function of a subclass, for example, QRhiBuffer::create() or
+ QRhiTexture::create().
\li The exceptions are
QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor(),
@@ -149,15 +200,15 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
\li Note that this does not mean that a QRhiResource can freely be
destroy()'ed or deleted within a frame (that is, in a
- \l{QRhiCommandBuffer::beginFrame()}{beginFrame()} -
- \l{QRhiCommandBuffer::endFrame()}{endFrame()} section). As a general rule,
- all referenced QRhiResource objects must stay unchanged until the frame is
- submitted by calling \l{QRhiCommandBuffer::endFrame()}{endFrame()}. To ease
- this, QRhiResource::deleteLater() is provided as a convenience.
+ \l{QRhi::beginFrame()}{beginFrame()} - \l{QRhi::endFrame()}{endFrame()}
+ section). As a general rule, all referenced QRhiResource objects must stay
+ unchanged until the frame is submitted by calling
+ \l{QRhi::endFrame()}{endFrame()}. To ease this,
+ QRhiResource::deleteLater() is provided as a convenience.
\endlist
- \section3 Command buffers and deferred command execution
+ \section2 Command buffers and deferred command execution
Regardless of the design and capabilities of the underlying graphics API,
all QRhi backends implement some level of command buffers. No
@@ -184,7 +235,7 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
As a general rule, all referenced QRhiResource objects must stay valid and
unmodified until the frame is submitted by calling
- \l{QRhiCommandBuffer::endFrame()}{endFrame()}. On the other hand, calling
+ \l{QRhi::endFrame()}{endFrame()}. On the other hand, calling
\l{QRhiResource::destroy()}{destroy()} or deleting the QRhiResource are
always safe once the frame is submitted, regardless of the status of the
underlying native resources (which may still be in use by the GPU - but
@@ -192,10 +243,20 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
Unlike APIs like OpenGL, upload and copy type of commands cannot be mixed
with draw commands. The typical renderer will involve a sequence similar to
- the following: \c{(re)create resources} - \c{begin frame} - \c{record
- uploads and copies} - \c{start renderpass} - \c{record draw calls} - \c{end
- renderpass} - \c{end frame}. Recording copy type of operations happens via
- QRhiResourceUpdateBatch. Such operations are committed typically on
+ the following:
+
+ \list
+ \li (re)create resources
+ \li begin frame
+ \li record/issue uploads and copies
+ \li start recording a render pass
+ \li record draw calls
+ \li end render pass
+ \li end frame
+ \endlist
+
+ Recording copy type of operations happens via QRhiResourceUpdateBatch. Such
+ operations are committed typically on
\l{QRhiCommandBuffer::beginPass()}{beginPass()}.
When working with legacy rendering engines designed for OpenGL, the
@@ -214,7 +275,7 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
remain the primary way of operating since this is what fits Qt's various UI
technologies best.
- \section3 Threading
+ \section2 Threading
A QRhi instance and the associated resources can be created and used on any
thread but all usage must be limited to that one single thread. When
@@ -243,7 +304,7 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
(gui) thread, but becomes important when a separate, dedicated render
thread is used.
- \section3 Resource synchronization
+ \section2 Resource synchronization
QRhi does not expose APIs for resource barriers or image layout
transitions. Such synchronization is done implicitly by the backends, where
@@ -263,7 +324,7 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
different access (one for load, one for store) is supported even within the
same pass.
- \section3 Resource reuse
+ \section2 Resource reuse
From the user's point of view a QRhiResource is reusable immediately after
calling QRhiResource::destroy(). With the exception of swapchains, calling
@@ -283,24 +344,24 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
though there is a good chance that under the hood the QRhiBuffer is now
backed by a whole new native buffer.
- \badcode
- ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 256);
+ \code
+ QRhiBuffer *ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 256);
ubuf->create();
- srb = rhi->newShaderResourceBindings()
+ QRhiShaderResourceBindings *srb = rhi->newShaderResourceBindings()
srb->setBindings({
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, ubuf)
});
srb->create();
- ...
+ // ...
// now in a later frame we need to grow the buffer to a larger size
ubuf->setSize(512);
ubuf->create(); // same as ubuf->destroy(); ubuf->create();
- // That's it, srb needs no changes whatsoever, any references in it to
- // ubuf stay valid. When it comes to internal details, such as that
+ // srb needs no changes whatsoever, any references in it to ubuf
+ // stay valid. When it comes to internal details, such as that
// ubuf may now be backed by a completely different native buffer
// resource, that is is recognized and handled automatically by the
// next setShaderResources().
@@ -315,7 +376,7 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
resource underneath, without having to update the QRhiTextureRenderTarget
as that will be done implicitly in beginPass().
- \section3 Pooled objects
+ \section2 Pooled objects
In addition to resources, there are pooled objects as well, such as,
QRhiResourceUpdateBatch. An instance is retrieved via a \c next function,
@@ -325,24 +386,25 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
QRhiCommandBuffer::beginPass() or QRhiCommandBuffer::endPass(). These
functions take care of returning the batch to the pool. Alternatively, a
batch can be "canceled" and returned to the pool without processing by
- calling QRhiResourceUpdateBatch::destroy().
+ calling QRhiResourceUpdateBatch::release().
A typical pattern is thus:
- \badcode
+ \code
QRhiResourceUpdateBatch *resUpdates = rhi->nextResourceUpdateBatch();
- ...
+ // ...
resUpdates->updateDynamicBuffer(ubuf, 0, 64, mvp.constData());
if (!image.isNull()) {
resUpdates->uploadTexture(texture, image);
image = QImage();
}
- ...
+ // ...
QRhiCommandBuffer *cb = m_sc->currentFrameCommandBuffer();
+ // note the last argument
cb->beginPass(swapchain->currentFrameRenderTarget(), clearCol, clearDs, resUpdates);
\endcode
- \section3 Swapchain specifics
+ \section2 Swapchain specifics
QRhiSwapChain features some special semantics due to the peculiar nature of
swapchains.
@@ -373,30 +435,174 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
\endlist
- \section3 Ownership
+ \section2 Ownership
The general rule is no ownership transfer. Creating a QRhi with an already
existing graphics device does not mean the QRhi takes ownership of the
device object. Similarly, ownership is not given away when a device or
texture object is "exported" via QRhi::nativeHandles() or
- QRhiTexture::nativeHandles(). Most importantly, passing pointers in structs
+ QRhiTexture::nativeTexture(). Most importantly, passing pointers in structs
and via setters does not transfer ownership.
- \section2 Troubleshooting
+ \section1 Troubleshooting and Profiling
+
+ \section2 Error reporting
+
+ Functions such as \l QRhi::create() and the resource classes' \c create()
+ member functions (e.g., \l QRhiBuffer::create()) indicate failure with the
+ return value (\nullptr or
+ \c false, respectively). When working with QShader, \l QShader::fromSerialized()
+ returns an invalid QShader (for which \l{QShader::isValid()}{isValid()} returns
+ \c false) when the data passed to the function cannot be successfully deserialized.
+ Some functions, beginFrame() in particular, may also sometimes report "soft failures",
+ such as \l FrameOpSwapChainOutOfDate, which do not indicate an unrecoverable error,
+ but rather should be seen as a "try again later" response.
- Errors are printed to the output via qWarning(). Additional debug messages
- can be enabled via the following logging categories. Messages from these
- categories are not printed by default unless explicitly enabled via
- QLoggingCategory or the \c QT_LOGGING_RULES environment variable.
+ Warnings and errors may get printed at any time to the debug output via
+ qWarning(). It is therefore always advisable to inspect the output of the
+ application.
+
+ Additional debug messages can be enabled via the following logging
+ categories. Messages from these categories are not printed by default
+ unless explicitly enabled via QLoggingCategory or the \c QT_LOGGING_RULES
+ environment variable. For better interoperation with Qt Quick, the
+ environment variable \c{QSG_INFO} also enables these debug prints.
\list
\li \c{qt.rhi.general}
\endlist
- It is strongly advised to inspect the output with the logging categories
- (\c{qt.rhi.*}) enabled whenever a QRhi-based application is not behaving as
- expected. For better interoperation with Qt Quick, the environment variable
- \c{QSG_INFO} also enables these debug prints.
+ Additionally, applications can query the \l{QRhi::backendName()}{QRhi
+ backend name} and
+ \l{QRhi::driverInfo()}{graphics device information} from a successfully
+ initialized QRhi. This can then be printed to the user or stored in the
+ application logs even in production builds, if desired.
+
+ \section2 Investigating rendering problems
+
+ When the rendering results are not as expected, or the application is
+ experiencing problems, always consider checking with the the native 3D
+ APIs' debug and validation facilities. QRhi itself features limited error
+ checking since replicating the already existing, vast amount of
+ functionality in the underlying layers is not reasonable.
+
+ \list
+
+ \li For Vulkan, controlling the
+ \l{https://github.com/KhronosGroup/Vulkan-ValidationLayers}{Vulkan
+ Validation Layers} is not in the scope of the QRhi, but rather can be
+ achieved by configuring the \l QVulkanInstance with the appropriate layers.
+ For example, call \c{instance.setLayers({ "VK_LAYER_KHRONOS_validation" });}
+ before invoking \l{QVulkanInstance::create()}{create()} on the QVulkanInstance.
+ (note that this assumes that the validation layers are actually installed
+ and available, e.g. from the Vulkan SDK) By default, QVulkanInstance conveniently
+ redirects the Vulkan debug messages to qDebug, meaning the validation messages get
+ printed just like other Qt warnings.
+
+ \li With Direct 3D 11 and 12, a graphics device with the debug layer
+ enabled can be requested by toggling the \c enableDebugLayer flag in the
+ appropriate \l{QRhiD3D11InitParams}{init params struct}. The messages appear on the
+ debug output, which is visible in Qt Creator's messages panel or via a tool
+ such as \l{https://learn.microsoft.com/en-us/sysinternals/downloads/debugview}{DebugView}.
+
+ \li For Metal, controlling Metal Validation is outside of QRhi's scope.
+ Rather, to enable validation, run the application with the environment
+ variable \c{METAL_DEVICE_WRAPPER_TYPE=1} set, or run the application within
+ XCode. There may also be further settings and environment variable in modern
+ XCode and macOS versions. See for instance
+ \l{https://developer.apple.com/documentation/metal/diagnosing_metal_programming_issues_early}{this
+ page}.
+
+ \endlist
+
+ \section2 Frame captures and performance profiling
+
+ A Qt application rendering with QRhi to a window while relying on a 3D API
+ under the hood, is, from the windowing and graphics pipeline perspective at
+ least, no different from any other (non-Qt) applications using the same 3D
+ API. This means that tools and practices for debugging and profiling
+ applications involving 3D graphics, such as games, all apply to such a Qt
+ application as well.
+
+ A few examples of tools that can provide insights into the rendering
+ internals of Qt applications that use QRhi, which includes Qt Quick and Qt
+ Quick 3D based projects as well:
+
+ \list
+
+ \li \l{https://renderdoc.org/}{RenderDoc} allows taking frame captures and
+ introspecting the recorded commands and pipeline state on Windows and Linux
+ for applications using OpenGL, Vulkan, D3D11, or D3D12. When trying to
+ figure out why some parts of the 3D scene do not show up as expected,
+ RenderDoc is often a fast and efficient way to check the pipeline stages
+ and the related state and discover the missing or incorrect value. It is
+ also a tool that is actively used when developing Qt itself.
+
+ \li For NVIDIA-based systems,
+ \l{https://developer.nvidia.com/nsight-graphics}{Nsight Graphics} provides
+ a graphics debugger tool on Windows and Linux. In addition to investigating the commands
+ in the frame and the pipeline, the vendor-specific tools allow looking at timings and
+ hardware performance information, which is not something simple frame captures can provide.
+
+ \li For AMD-based systems, the \l{https://gpuopen.com/rgp/}{Radeon GPU
+ Profiler} can be used to gain deeper insights into the application's
+ rendering and its performance.
+
+ \li As QRhi supports Direct 3D 12, using
+ \l{https://devblogs.microsoft.com/pix/download/}{PIX}, a performance tuning
+ and debugging tool for DirectX 12 games on Windows is an option as well.
+
+ \li On macOS,
+ \l{https://developer.apple.com/documentation/metal/debugging_tools/viewing_your_gpu_workload_with_the_metal_debugger}{the
+ XCode Metal debugger} can be used to take and introspect frame
+ captures, to investigate performance details, and debug shaders. In macOS 13 it is also possible
+ to enable an overlay that displays frame rate and other information for any Metal-based window by
+ setting the environment variable \c{MTL_HUD_ENABLED=1}.
+
+ \endlist
+
+ On mobile and embedded platforms, there may be vendor and platform-specific
+ tools, provided by the GPU or SoC vendor, available to perform performance
+ profiling of application using OpenGL ES or Vulkan.
+
+ When capturing frames, remember that objects and groups of commands can be
+ named via debug markers, as long as \l{QRhi::EnableDebugMarkers}{debug
+ markers were enabled} for the QRhi, and the graphics API in use supports
+ this. To annotate the command stream, call
+ \l{QRhiCommandBuffer::debugMarkBegin()}{debugMarkBegin()},
+ \l{QRhiCommandBuffer::debugMarkEnd()}{debugMarkEnd()} and/or
+ \l{QRhiCommandBuffer::debugMarkMsg()}{debugMarkMsg()}.
+ This can be particularly useful in larger frames with multiple render passes.
+ Resources are named by calling \l{QRhiResource::setName()}{setName()} before create().
+
+ To perform basic timing measurements on the CPU and GPU side within the
+ application, \l QElapsedTimer and
+ \l QRhiCommandBuffer::lastCompletedGpuTime() can be used. The latter is
+ only available with select graphics APIs at the moment and requires opting
+ in via the \l QRhi::EnableTimestamps flag.
+
+ \section2 Resource leak checking
+
+ When destroying a QRhi object without properly destroying all buffers,
+ textures, and other resources created from it, warnings about this are
+ printed to the debug output whenever the application is a debug build, or
+ when the \c QT_RHI_LEAK_CHECK environment variable is set to a non-zero
+ value. This is a simple way to discover design issues around resource
+ handling within the application rendering logic. Note however that some
+ platforms and underlying graphics APIs may perform their own allocation and
+ resource leak detection as well, over which Qt will have no direct control.
+ For example, when using Vulkan, the memory allocator may raise failing
+ assertions in debug builds when resources that own graphics memory
+ allocations are not destroyed before the QRhi. In addition, the Vulkan
+ validation layer, when enabled, will issue warnings about native graphics
+ resources that were not released. Similarly, with Direct 3D warnings may
+ get printed about unreleased COM objects when the application does not
+ destroy the QRhi and its resources in the correct order.
+
+ \sa {RHI Window Example}, QRhiCommandBuffer, QRhiResourceUpdateBatch,
+ QRhiShaderResourceBindings, QShader, QRhiBuffer, QRhiTexture,
+ QRhiRenderBuffer, QRhiSampler, QRhiTextureRenderTarget,
+ QRhiGraphicsPipeline, QRhiComputePipeline, QRhiSwapChain
*/
/*!
@@ -415,13 +621,18 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
\enum QRhi::Flag
Describes what special features to enable.
- \value EnableProfiling This flag has currently no effect.
-
\value EnableDebugMarkers Enables debug marker groups. Without this frame
debugging features like making debug groups and custom resource name
visible in external GPU debugging tools will not be available and functions
- like QRhiCommandBuffer::debugMarkBegin() will become a no-op. Avoid
- enabling in production builds as it may involve a performance penalty.
+ like QRhiCommandBuffer::debugMarkBegin() will become no-ops. Avoid enabling
+ in production builds as it may involve a small performance impact. Has no
+ effect when the QRhi::DebugMarkers feature is not reported as supported.
+
+ \value EnableTimestamps Enables GPU timestamp collection. When not set,
+ QRhiCommandBuffer::lastCompletedGpuTime() always returns 0. Enable this
+ only when needed since there may be a small amount of extra work involved
+ (e.g. timestamp queries), depending on the underlying graphics API. Has no
+ effect when the QRhi::Timestamps feature is not reported as supported.
\value PreferSoftwareRenderer Indicates that backends should prefer
choosing an adapter or physical device that renders in software on the CPU.
@@ -443,7 +654,7 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
mechanism because the cost of maintaining the related data structures is
not insignificant with some backends. With Vulkan this feature maps
directly to VkPipelineCache, vkGetPipelineCacheData and
- VkPipelineCacheCreateInfo::pInitialData. With D3D11 there is no real
+ VkPipelineCacheCreateInfo::pInitialData. With Direct3D 11 there is no real
pipline cache, but the results of HLSL->DXBC compilations are stored and
can be serialized/deserialized via this mechanism. This allows skipping the
time consuming D3DCompile() in future runs of the applications for shaders
@@ -455,6 +666,17 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
mechanisms for shader/program binaries provided by Qt. Writing to those may
get disabled whenever this flag is set since storing program binaries to
multiple caches is not sensible.
+
+ \value SuppressSmokeTestWarnings Indicates that, with backends where this
+ is relevant, certain, non-fatal QRhi::create() failures should not
+ produce qWarning() calls. For example, with D3D11, passing this flag
+ makes a number of warning messages (that appear due to QRhi::create()
+ failing) to become categorized debug prints instead under the commonly used
+ \c{qt.rhi.general} logging category. This can be used by engines, such as
+ Qt Quick, that feature fallback logic, i.e. they retry calling create()
+ with a different set of flags (such as, \l PreferSoftwareRenderer), in order
+ to hide the unconditional warnings from the output that would be printed
+ when the first create() attempt had failed.
*/
/*!
@@ -492,8 +714,12 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
QRhiCommandBuffer::debugMarkBegin()) are supported.
\value Timestamps Indicates that command buffer timestamps are supported.
- Relevant for addGpuFrameTimeCallback(). Can be expected to be supported on
- D3D11 and Vulkan, assuming the underlying implementation supports it.
+ Relevant for QRhiCommandBuffer::lastCompletedGpuTime(). This can be
+ expected to be supported on Metal, Vulkan, Direct 3D 11 and 12, and OpenGL
+ contexts of version 3.3 or newer. However, with some of these APIs support
+ for timestamp queries is technically optional, and therefore it cannot be
+ guaranteed that this feature is always supported with every implementation
+ of them.
\value Instancing Indicates that instanced drawing is supported. In
practice this feature will be unsupported with OpenGL ES 2.0 and OpenGL
@@ -563,7 +789,7 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
\value WideLines Indicates that lines with a width other than 1 are
supported. When reported as not supported, the line width set on the
graphics pipeline state is ignored. This can always be false with some
- backends (D3D11, Metal). With Vulkan, the value depends on the
+ backends (D3D11, D3D12, Metal). With Vulkan, the value depends on the
implementation. With OpenGL, wide lines are not supported in core profile
contexts.
@@ -724,7 +950,7 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
with image load/store. This feature is only available with some backends as
it does not map well to all graphics APIs, and it is only meant to provide
support for special cases anyhow. In practice the feature can be expected to
- be supported with Direct3D 11 and Vulkan.
+ be supported with Direct3D 11/12 and Vulkan.
\value NonFillPolygonMode Indicates that setting a PolygonMode other than
the default Fill is supported for QRhiGraphicsPipeline. A common use case
@@ -745,8 +971,8 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
When not supported, build() will succeed but just show a warning message
and the values of the target attributes will be broken. In practice this
feature will be unsupported in some OpenGL ES 2.0 and OpenGL 2.x
- implementations. Note that while D3D does support half precision input
- attributes, it does not support the half3 type. The D3D backends pass
+ implementations. Note that while Direct3D 11/12 does support half precision
+ input attributes, it does not support the half3 type. The D3D backends pass
half3 attributes as half4. To ensure cross platform compatibility, half3
inputs should be padded to 8 bytes.
@@ -758,6 +984,58 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
\value ThreeDimensionalTextureMipmaps Indicates that generating 3D texture
mipmaps are supported. In practice this feature will be unsupported with
Direct 3D 12.
+
+ \value MultiView Indicates that multiview, see e.g.
+ \l{https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_multiview.html}{VK_KHR_multiview}
+ is supported. With OpenGL ES 2.0, Direct 3D 11, and OpenGL (ES)
+ implementations without \c{GL_OVR_multiview2} this feature will not be
+ supported. With Vulkan 1.1 and newer, and Direct 3D 12 multiview is
+ typically supported. When reported as supported, creating a
+ QRhiTextureRenderTarget with a QRhiColorAttachment that references a texture
+ array and has \l{QRhiColorAttachment::setMultiViewCount()}{multiViewCount}
+ set enables recording a render pass that uses multiview rendering. In addition,
+ any QRhiGraphicsPipeline used in that render pass must have
+ \l{QRhiGraphicsPipeline::setMultiViewCount()}{the same view count set}. Note that
+ multiview is only available in combination with 2D texture arrays. It cannot
+ be used to optimize the rendering into individual textures (e.g. two, for
+ the left and right eyes). Rather, the target of a multiview render pass is
+ always a texture array, automatically rendering to the layer (array element)
+ corresponding to each view. Therefore this feature implies \l TextureArrays
+ as well. Multiview rendering is not supported in combination with
+ tessellation or geometry shaders. See QRhiColorAttachment::setMultiViewCount()
+ for further details on multiview rendering. This enum value has been introduced in Qt 6.7.
+
+ \value TextureViewFormat Indicates that setting a
+ \l{QRhiTexture::setWriteViewFormat()}{view format} on a QRhiTexture is
+ effective. When reported as supported, setting the read (sampling) or write
+ (render target / image load-store) view mode changes the texture's viewing
+ format. When unsupported, setting a view format has no effect. Note that Qt
+ has no knowledge or control over format compatibility or resource view rules
+ in the underlying 3D API and its implementation. Passing in unsuitable,
+ incompatible formats may lead to errors and unspecified behavior. This is
+ provided mainly to allow "casting" rendering into a texture created with an
+ sRGB format to non-sRGB to avoid the unwanted linear->sRGB conversion on
+ shader writes. Other types of casting may or may not be functional,
+ depending on the underlying API. Currently implemented for Vulkan and Direct
+ 3D 12. With D3D12 the feature is available only if
+ \c CastingFullyTypedFormatSupported is supported, see
+ \l{https://microsoft.github.io/DirectX-Specs/d3d/RelaxedCasting.html} (and
+ note that QRhi always uses fully typed formats for textures.) This enum
+ value has been introduced in Qt 6.8.
+
+ \value ResolveDepthStencil Indicates that resolving a multisample depth or
+ depth-stencil texture is supported. Otherwise,
+ \l{QRhiTextureRenderTargetDescription::setDepthResolveTexture()}{setting a
+ depth resolve texture} is not functional and must be avoided. Direct 3D 11
+ and 12 have no support for resolving depth/depth-stencil formats, and
+ therefore this feature will never be supported with those. Vulkan 1.0 has no
+ API to request resolving a depth-stencil attachment. Therefore, with Vulkan
+ this feature will only be supported with Vulkan 1.2 and up, and on 1.1
+ implementations with the appropriate extensions present. This feature is
+ provided for the rare case when resolving into a non-multisample depth
+ texture becomes necessary, for example when rendering into an
+ OpenXR-provided depth texture (XR_KHR_composition_layer_depth). This enum
+ value has been introduced in Qt 6.8.
*/
/*!
@@ -869,22 +1147,28 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
/*!
\class QRhiInitParams
- \internal
\inmodule QtGui
+ \since 6.6
\brief Base class for backend-specific initialization parameters.
Contains fields that are relevant to all backends.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
\class QRhiDepthStencilClearValue
- \internal
\inmodule QtGui
+ \since 6.6
\brief Specifies clear values for a depth or stencil buffer.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
- \fn QRhiDepthStencilClearValue::QRhiDepthStencilClearValue()
+ \fn QRhiDepthStencilClearValue::QRhiDepthStencilClearValue() = default
Constructs a depth/stencil clear value with depth clear value 1.0f and
stencil clear value 0.
@@ -901,6 +1185,26 @@ QRhiDepthStencilClearValue::QRhiDepthStencilClearValue(float d, quint32 s)
}
/*!
+ \fn float QRhiDepthStencilClearValue::depthClearValue() const
+ \return the depth clear value. In most cases this is 1.0f.
+ */
+
+/*!
+ \fn void QRhiDepthStencilClearValue::setDepthClearValue(float d)
+ Sets the depth clear value to \a d.
+ */
+
+/*!
+ \fn quint32 QRhiDepthStencilClearValue::stencilClearValue() const
+ \return the stencil clear value. In most cases this is 0.
+ */
+
+/*!
+ \fn void QRhiDepthStencilClearValue::setStencilClearValue(quint32 s)
+ Sets the stencil clear value to \a s.
+ */
+
+/*!
\fn bool QRhiDepthStencilClearValue::operator==(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) noexcept
\return \c true if the values in the two QRhiDepthStencilClearValue objects
@@ -934,8 +1238,8 @@ QDebug operator<<(QDebug dbg, const QRhiDepthStencilClearValue &v)
/*!
\class QRhiViewport
- \internal
\inmodule QtGui
+ \since 6.6
\brief Specifies a viewport rectangle.
Used with QRhiCommandBuffer::setViewport().
@@ -945,20 +1249,23 @@ QDebug operator<<(QDebug dbg, const QRhiDepthStencilClearValue &v)
Typical usage is like the following:
- \badcode
+ \code
const QSize outputSizeInPixels = swapchain->currentPixelSize();
const QRhiViewport viewport(0, 0, outputSizeInPixels.width(), outputSizeInPixels.height());
- cb->beginPass(swapchain->currentFrameRenderTarget(), { 0, 0, 0, 1 }, { 1, 0 });
+ cb->beginPass(swapchain->currentFrameRenderTarget(), Qt::black, { 1.0f, 0 });
cb->setGraphicsPipeline(ps);
cb->setViewport(viewport);
- ...
+ // ...
\endcode
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
\sa QRhiCommandBuffer::setViewport(), QRhi::clipSpaceCorrMatrix(), QRhiScissor
*/
/*!
- \fn QRhiViewport::QRhiViewport()
+ \fn QRhiViewport::QRhiViewport() = default
Constructs a viewport description with an empty rectangle and a depth range
of 0.0f - 1.0f.
@@ -984,6 +1291,41 @@ QRhiViewport::QRhiViewport(float x, float y, float w, float h, float minDepth, f
}
/*!
+ \fn std::array<float, 4> QRhiViewport::viewport() const
+ \return the viewport x, y, width, and height.
+ */
+
+/*!
+ \fn void QRhiViewport::setViewport(float x, float y, float w, float h)
+ Sets the viewport's position and size to \a x, \a y, \a w, and \a h.
+
+ \note Viewports are specified in a coordinate system that has its origin in
+ the bottom-left.
+ */
+
+/*!
+ \fn float QRhiViewport::minDepth() const
+ \return the minDepth value of the depth range of the viewport.
+ */
+
+/*!
+ \fn void QRhiViewport::setMinDepth(float minDepth)
+ Sets the \a minDepth of the depth range of the viewport.
+ By default this is set to 0.0f.
+ */
+
+/*!
+ \fn float QRhiViewport::maxDepth() const
+ \return the maxDepth value of the depth range of the viewport.
+ */
+
+/*!
+ \fn void QRhiViewport::setMaxDepth(float maxDepth)
+ Sets the \a maxDepth of the depth range of the viewport.
+ By default this is set to 1.0f.
+ */
+
+/*!
\fn bool QRhiViewport::operator==(const QRhiViewport &a, const QRhiViewport &b) noexcept
\return \c true if the values in the two QRhiViewport objects
@@ -1021,8 +1363,8 @@ QDebug operator<<(QDebug dbg, const QRhiViewport &v)
/*!
\class QRhiScissor
- \internal
\inmodule QtGui
+ \since 6.6
\brief Specifies a scissor rectangle.
Used with QRhiCommandBuffer::setScissor(). Setting a scissor rectangle is
@@ -1036,11 +1378,14 @@ QDebug operator<<(QDebug dbg, const QRhiViewport &v)
appropriate. Therefore, any rendering logic targeting OpenGL can feed
scissor rectangles into QRhiScissor as-is, without any adaptation.
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
\sa QRhiCommandBuffer::setScissor(), QRhiViewport
*/
/*!
- \fn QRhiScissor::QRhiScissor()
+ \fn QRhiScissor::QRhiScissor() = default
Constructs an empty scissor.
*/
@@ -1061,6 +1406,19 @@ QRhiScissor::QRhiScissor(int x, int y, int w, int h)
}
/*!
+ \fn std::array<int, 4> QRhiScissor::scissor() const
+ \return the scissor position and size.
+ */
+
+/*!
+ \fn void QRhiScissor::setScissor(int x, int y, int w, int h)
+ Sets the scissor position and size to \a x, \a y, \a w, \a h.
+
+ \note The position is always expected to be specified in a coordinate
+ system that has its origin in the bottom-left corner, like OpenGL.
+ */
+
+/*!
\fn bool QRhiScissor::operator==(const QRhiScissor &a, const QRhiScissor &b) noexcept
\return \c true if the values in the two QRhiScissor objects
@@ -1096,8 +1454,8 @@ QDebug operator<<(QDebug dbg, const QRhiScissor &s)
/*!
\class QRhiVertexInputBinding
- \internal
\inmodule QtGui
+ \since 6.6
\brief Describes a vertex input binding.
Specifies the stride (in bytes, must be a multiple of 4), the
@@ -1115,7 +1473,7 @@ QDebug operator<<(QDebug dbg, const QRhiScissor &s)
format in a buffer (or separate buffers even). Defining two bindings
could then be done like this:
- \badcode
+ \code
QRhiVertexInputLayout inputLayout;
inputLayout.setBindings({
{ 3 * sizeof(float) },
@@ -1132,7 +1490,7 @@ QDebug operator<<(QDebug dbg, const QRhiScissor &s)
vertices, assuming we have a single buffer with first the positions and
then the texture coordinates:
- \badcode
+ \code
const QRhiCommandBuffer::VertexInput vbufBindings[] = {
{ cubeBuf, 0 },
{ cubeBuf, 36 * 3 * sizeof(float) }
@@ -1148,6 +1506,9 @@ QDebug operator<<(QDebug dbg, const QRhiScissor &s)
\note the stride must always be a multiple of 4.
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
\sa QRhiCommandBuffer::setVertexInput()
*/
@@ -1160,7 +1521,7 @@ QDebug operator<<(QDebug dbg, const QRhiScissor &s)
*/
/*!
- \fn QRhiVertexInputBinding::QRhiVertexInputBinding()
+ \fn QRhiVertexInputBinding::QRhiVertexInputBinding() = default
Constructs a default vertex input binding description.
*/
@@ -1180,6 +1541,36 @@ QRhiVertexInputBinding::QRhiVertexInputBinding(quint32 stride, Classification cl
}
/*!
+ \fn quint32 QRhiVertexInputBinding::stride() const
+ \return the stride in bytes.
+ */
+
+/*!
+ \fn void QRhiVertexInputBinding::setStride(quint32 s)
+ Sets the stride to \a s.
+ */
+
+/*!
+ \fn QRhiVertexInputBinding::Classification QRhiVertexInputBinding::classification() const
+ \return the input data classification.
+ */
+
+/*!
+ \fn void QRhiVertexInputBinding::setClassification(Classification c)
+ Sets the input data classification \a c. By default this is set to PerVertex.
+ */
+
+/*!
+ \fn quint32 QRhiVertexInputBinding::instanceStepRate() const
+ \return the instance step rate.
+ */
+
+/*!
+ \fn void QRhiVertexInputBinding::setInstanceStepRate(quint32 rate)
+ Sets the instance step \a rate. By default this is set to 1.
+ */
+
+/*!
\fn bool QRhiVertexInputBinding::operator==(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) noexcept
\return \c true if the values in the two QRhiVertexInputBinding objects
@@ -1213,14 +1604,15 @@ QDebug operator<<(QDebug dbg, const QRhiVertexInputBinding &b)
/*!
\class QRhiVertexInputAttribute
- \internal
\inmodule QtGui
+ \since 6.6
\brief Describes a single vertex input element.
The members specify the binding number, location, format, and offset for a
single vertex input element.
- \note For HLSL it is assumed that the vertex shader uses
+ \note For HLSL it is assumed that the vertex shader translated from SPIR-V
+ uses
\c{TEXCOORD<location>} as the semantic for each input. Hence no separate
semantic name and index.
@@ -1236,7 +1628,7 @@ QDebug operator<<(QDebug dbg, const QRhiVertexInputBinding &b)
non-interleaved format in a buffer (or separate buffers even). Once two
bindings are defined, the attributes could be specified as:
- \badcode
+ \code
QRhiVertexInputLayout inputLayout;
inputLayout.setBindings({
{ 3 * sizeof(float) },
@@ -1253,7 +1645,7 @@ QDebug operator<<(QDebug dbg, const QRhiVertexInputBinding &b)
vertices, assuming we have a single buffer with first the positions and
then the texture coordinates:
- \badcode
+ \code
const QRhiCommandBuffer::VertexInput vbufBindings[] = {
{ cubeBuf, 0 },
{ cubeBuf, 36 * 3 * sizeof(float) }
@@ -1265,7 +1657,7 @@ QDebug operator<<(QDebug dbg, const QRhiVertexInputBinding &b)
binding, with multiple attributes referring to that same buffer binding
point:
- \badcode
+ \code
QRhiVertexInputLayout inputLayout;
inputLayout.setBindings({
{ 5 * sizeof(float) }
@@ -1278,11 +1670,14 @@ QDebug operator<<(QDebug dbg, const QRhiVertexInputBinding &b)
and then:
- \badcode
+ \code
const QRhiCommandBuffer::VertexInput vbufBinding(interleavedCubeBuf, 0);
cb->setVertexInput(0, 1, &vbufBinding);
\endcode
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
\sa QRhiCommandBuffer::setVertexInput()
*/
@@ -1305,20 +1700,30 @@ QDebug operator<<(QDebug dbg, const QRhiVertexInputBinding &b)
\value SInt3 Three component signed integer vector
\value SInt2 Two component signed integer vector
\value SInt Signed integer
- \value Half4 Four component half precision (16bit) float vector
- \value Half3 Three component half precision (16bit) float vector
- \value Half2 Two component half precision (16bit) float vector
- \value Half half precision (16bit) float
+ \value Half4 Four component half precision (16 bit) float vector
+ \value Half3 Three component half precision (16 bit) float vector
+ \value Half2 Two component half precision (16 bit) float vector
+ \value Half Half precision (16 bit) float
+ \value UShort4 Four component unsigned short (16 bit) integer vector
+ \value UShort3 Three component unsigned short (16 bit) integer vector
+ \value UShort2 Two component unsigned short (16 bit) integer vector
+ \value UShort Unsigned short (16 bit) integer
+ \value SShort4 Four component signed short (16 bit) integer vector
+ \value SShort3 Three component signed short (16 bit) integer vector
+ \value SShort2 Two component signed short (16 bit) integer vector
+ \value SShort Signed short (16 bit) integer
\note Support for half precision floating point attributes is indicated at
- run time by the QRhi::Feature::HalfAttributes feature flag. Note that D3D
- supports half input attributes, but does not support the Half3 type. The
- D3D backends pass through Half3 as Half4. To ensure cross platform
- compatibility, Half3 inputs should be padded to 8 bytes.
+ run time by the QRhi::Feature::HalfAttributes feature flag.
+
+ \note Direct3D 11/12 supports 16 bit input attributes, but does not support
+ the Half3, UShort3 or SShort3 types. The D3D backends pass through Half3 as
+ Half4, UShort3 as UShort4, and SShort3 as SShort4. To ensure cross platform
+ compatibility, 16 bit inputs should be padded to 8 bytes.
*/
/*!
- \fn QRhiVertexInputAttribute::QRhiVertexInputAttribute()
+ \fn QRhiVertexInputAttribute::QRhiVertexInputAttribute() = default
Constructs a default vertex input attribute description.
*/
@@ -1343,6 +1748,67 @@ QRhiVertexInputAttribute::QRhiVertexInputAttribute(int binding, int location, Fo
}
/*!
+ \fn int QRhiVertexInputAttribute::binding() const
+ \return the binding point index.
+ */
+
+/*!
+ \fn void QRhiVertexInputAttribute::setBinding(int b)
+ Sets the binding point index to \a b.
+ By default this is set to 0.
+ */
+
+/*!
+ \fn int QRhiVertexInputAttribute::location() const
+ \return the location of the vertex input element.
+ */
+
+/*!
+ \fn void QRhiVertexInputAttribute::setLocation(int loc)
+ Sets the location of the vertex input element to \a loc.
+ By default this is set to 0.
+ */
+
+/*!
+ \fn QRhiVertexInputAttribute::Format QRhiVertexInputAttribute::format() const
+ \return the format of the vertex input element.
+ */
+
+/*!
+ \fn void QRhiVertexInputAttribute::setFormat(Format f)
+ Sets the format of the vertex input element to \a f.
+ By default this is set to Float4.
+ */
+
+/*!
+ \fn quint32 QRhiVertexInputAttribute::offset() const
+ \return the byte offset for the input element.
+ */
+
+/*!
+ \fn void QRhiVertexInputAttribute::setOffset(quint32 ofs)
+ Sets the byte offset for the input element to \a ofs.
+ */
+
+/*!
+ \fn int QRhiVertexInputAttribute::matrixSlice() const
+
+ \return the matrix slice if the input element corresponds to a row or
+ column of a matrix, or -1 if not relevant.
+ */
+
+/*!
+ \fn void QRhiVertexInputAttribute::setMatrixSlice(int slice)
+
+ Sets the matrix \a slice. By default this is set to -1, and should be set
+ to a >= 0 value only when this attribute corresponds to a row or column of
+ a matrix (for example, a 4x4 matrix becomes 4 vec4s, consuming 4
+ consecutive vertex input locations), in which case it is the index of the
+ row or column. \c{location - matrixSlice} must always be equal to the \c
+ location for the first row or column of the unrolled matrix.
+ */
+
+/*!
\fn bool QRhiVertexInputAttribute::operator==(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) noexcept
\return \c true if the values in the two QRhiVertexInputAttribute objects
@@ -1465,6 +1931,24 @@ quint32 QRhiImplementation::byteSizePerVertexForVertexInputFormat(QRhiVertexInpu
case QRhiVertexInputAttribute::Half:
return sizeof(qfloat16);
+ case QRhiVertexInputAttribute::UShort4:
+ return 4 * sizeof(quint16);
+ case QRhiVertexInputAttribute::UShort3:
+ return 4 * sizeof(quint16); // ivec3 still takes 8 bytes
+ case QRhiVertexInputAttribute::UShort2:
+ return 2 * sizeof(quint16);
+ case QRhiVertexInputAttribute::UShort:
+ return sizeof(quint16);
+
+ case QRhiVertexInputAttribute::SShort4:
+ return 4 * sizeof(qint16);
+ case QRhiVertexInputAttribute::SShort3:
+ return 4 * sizeof(qint16); // uvec3 still takes 8 bytes
+ case QRhiVertexInputAttribute::SShort2:
+ return 2 * sizeof(qint16);
+ case QRhiVertexInputAttribute::SShort:
+ return sizeof(qint16);
+
default:
Q_UNREACHABLE_RETURN(1);
}
@@ -1472,21 +1956,102 @@ quint32 QRhiImplementation::byteSizePerVertexForVertexInputFormat(QRhiVertexInpu
/*!
\class QRhiVertexInputLayout
- \internal
\inmodule QtGui
+ \since 6.6
\brief Describes the layout of vertex inputs consumed by a vertex shader.
The vertex input layout is defined by the collections of
QRhiVertexInputBinding and QRhiVertexInputAttribute.
+
+ As an example, let's assume that we have a single buffer with 3 component
+ vertex positions and 2 component UV coordinates interleaved (\c x, \c y, \c
+ z, \c u, \c v), that the position and UV are expected at input locations 0
+ and 1 by the vertex shader, and that the vertex buffer will be bound at
+ binding point 0 using
+ \l{QRhiCommandBuffer::setVertexInput()}{setVertexInput()} later on:
+
+ \code
+ QRhiVertexInputLayout inputLayout;
+ inputLayout.setBindings({
+ { 5 * sizeof(float) }
+ });
+ inputLayout.setAttributes({
+ { 0, 0, QRhiVertexInputAttribute::Float3, 0 },
+ { 0, 1, QRhiVertexInputAttribute::Float2, 3 * sizeof(float) }
+ });
+ \endcode
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
- \fn QRhiVertexInputLayout::QRhiVertexInputLayout()
+ \fn QRhiVertexInputLayout::QRhiVertexInputLayout() = default
Constructs an empty vertex input layout description.
*/
/*!
+ \fn void QRhiVertexInputLayout::setBindings(std::initializer_list<QRhiVertexInputBinding> list)
+ Sets the bindings from the specified \a list.
+ */
+
+/*!
+ \fn template<typename InputIterator> void QRhiVertexInputLayout::setBindings(InputIterator first, InputIterator last)
+ Sets the bindings using the iterators \a first and \a last.
+ */
+
+/*!
+ \fn const QRhiVertexInputBinding *QRhiVertexInputLayout::cbeginBindings() const
+ \return a const iterator pointing to the first item in the binding list.
+ */
+
+/*!
+ \fn const QRhiVertexInputBinding *QRhiVertexInputLayout::cendBindings() const
+ \return a const iterator pointing just after the last item in the binding list.
+ */
+
+/*!
+ \fn const QRhiVertexInputBinding *QRhiVertexInputLayout::bindingAt(qsizetype index) const
+ \return the binding at the given \a index.
+ */
+
+/*!
+ \fn qsizetype QRhiVertexInputLayout::bindingCount() const
+ \return the number of bindings.
+ */
+
+/*!
+ \fn void QRhiVertexInputLayout::setAttributes(std::initializer_list<QRhiVertexInputAttribute> list)
+ Sets the attributes from the specified \a list.
+ */
+
+/*!
+ \fn template<typename InputIterator> void QRhiVertexInputLayout::setAttributes(InputIterator first, InputIterator last)
+ Sets the attributes using the iterators \a first and \a last.
+ */
+
+/*!
+ \fn const QRhiVertexInputAttribute *QRhiVertexInputLayout::cbeginAttributes() const
+ \return a const iterator pointing to the first item in the attribute list.
+ */
+
+/*!
+ \fn const QRhiVertexInputAttribute *QRhiVertexInputLayout::cendAttributes() const
+ \return a const iterator pointing just after the last item in the attribute list.
+ */
+
+/*!
+ \fn const QRhiVertexInputAttribute *QRhiVertexInputLayout::attributeAt(qsizetype index) const
+ \return the attribute at the given \a index.
+ */
+
+/*!
+ \fn qsizetype QRhiVertexInputLayout::attributeCount() const
+ \return the number of attributes.
+ */
+
+/*!
\fn bool QRhiVertexInputLayout::operator==(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) noexcept
\return \c true if the values in the two QRhiVertexInputLayout objects
@@ -1519,9 +2084,39 @@ QDebug operator<<(QDebug dbg, const QRhiVertexInputLayout &v)
/*!
\class QRhiShaderStage
- \internal
\inmodule QtGui
+ \since 6.6
\brief Specifies the type and the shader code for a shader stage in the pipeline.
+
+ When setting up a QRhiGraphicsPipeline, a collection of shader stages are
+ specified. The QRhiShaderStage contains a QShader and some associated
+ metadata, such as the graphics pipeline stage, and the
+ \l{QShader::Variant}{shader variant} to select. There is no need to specify
+ the shader language or version because the QRhi backend in use at runtime
+ will take care of choosing the appropriate shader version from the
+ collection within the QShader.
+
+ The typical usage is in combination with
+ QRhiGraphicsPipeline::setShaderStages(), shown here with a simple approach
+ to load the QShader from \c{.qsb} files generated offline or at build time:
+
+ \code
+ QShader getShader(const QString &name)
+ {
+ QFile f(name);
+ return f.open(QIODevice::ReadOnly) ? QShader::fromSerialized(f.readAll()) : QShader();
+ }
+
+ QShader vs = getShader("material.vert.qsb");
+ QShader fs = getShader("material.frag.qsb");
+ pipeline->setShaderStages({
+ { QRhiShaderStage::Vertex, vs },
+ { QRhiShaderStage::Fragment, fs }
+ });
+ \endcode
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
@@ -1546,13 +2141,46 @@ QDebug operator<<(QDebug dbg, const QRhiVertexInputLayout &v)
*/
/*!
- \fn QRhiShaderStage::QRhiShaderStage()
+ \fn QRhiShaderStage::QRhiShaderStage() = default
Constructs a shader stage description for the vertex stage with an empty
QShader.
*/
/*!
+ \fn QRhiShaderStage::Type QRhiShaderStage::type() const
+ \return the type of the stage.
+ */
+
+/*!
+ \fn void QRhiShaderStage::setType(Type t)
+
+ Sets the type of the stage to \a t. Setters should rarely be needed in
+ pratice. Most applications will likely use the QRhiShaderStage constructor
+ in most cases.
+ */
+
+/*!
+ \fn QShader QRhiShaderStage::shader() const
+ \return the QShader to be used for this stage in the graphics pipeline.
+ */
+
+/*!
+ \fn void QRhiShaderStage::setShader(const QShader &s)
+ Sets the shader collection \a s.
+ */
+
+/*!
+ \fn QShader::Variant QRhiShaderStage::shaderVariant() const
+ \return the requested shader variant.
+ */
+
+/*!
+ \fn void QRhiShaderStage::setShaderVariant(QShader::Variant v)
+ Sets the requested shader variant \a v.
+ */
+
+/*!
Constructs a shader stage description with the \a type of the stage and the
\a shader.
@@ -1602,12 +2230,14 @@ QDebug operator<<(QDebug dbg, const QRhiShaderStage &s)
/*!
\class QRhiColorAttachment
- \internal
\inmodule QtGui
+ \since 6.6
\brief Describes the a single color attachment of a render target.
A color attachment is either a QRhiTexture or a QRhiRenderBuffer. The
- former, when texture() is set, is used in most cases.
+ former, i.e. when texture() is set, is used in most cases.
+ QRhiColorAttachment is commonly used in combination with
+ QRhiTextureRenderTargetDescription.
\note texture() and renderBuffer() cannot be both set (be non-null at the
same time).
@@ -1634,10 +2264,15 @@ QDebug operator<<(QDebug dbg, const QRhiShaderStage &s)
\note when resolving is enabled, the multisample data may not be written
out at all. This means that the multisample texture() must not be used
afterwards with shaders for sampling when resolveTexture() is set.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
+ \sa QRhiTextureRenderTargetDescription
*/
/*!
- \fn QRhiColorAttachment::QRhiColorAttachment()
+ \fn QRhiColorAttachment::QRhiColorAttachment() = default
Constructs an empty color attachment description.
*/
@@ -1661,9 +2296,194 @@ QRhiColorAttachment::QRhiColorAttachment(QRhiRenderBuffer *renderBuffer)
}
/*!
+ \fn QRhiTexture *QRhiColorAttachment::texture() const
+
+ \return the texture this attachment description references, or \nullptr if
+ there is none.
+ */
+
+/*!
+ \fn void QRhiColorAttachment::setTexture(QRhiTexture *tex)
+
+ Sets the texture \a tex.
+
+ \note texture() and renderBuffer() cannot be both set (be non-null at the
+ same time).
+ */
+
+/*!
+ \fn QRhiRenderBuffer *QRhiColorAttachment::renderBuffer() const
+
+ \return the renderbuffer this attachment description references, or
+ \nullptr if there is none.
+
+ In practice associating a QRhiRenderBuffer with a QRhiColorAttachment makes
+ the most sense when setting up multisample rendering via a multisample
+ \l{QRhiRenderBuffer::Type}{color} renderbuffer that is then resolved into a
+ non-multisample texture at the end of the render pass.
+ */
+
+/*!
+ \fn void QRhiColorAttachment::setRenderBuffer(QRhiRenderBuffer *rb)
+
+ Sets the renderbuffer \a rb.
+
+ \note texture() and renderBuffer() cannot be both set (be non-null at the
+ same time).
+ */
+
+/*!
+ \fn int QRhiColorAttachment::layer() const
+ \return the layer index (cubemap face or array layer). 0 by default.
+ */
+
+/*!
+ \fn void QRhiColorAttachment::setLayer(int layer)
+ Sets the \a layer index.
+ */
+
+/*!
+ \fn int QRhiColorAttachment::level() const
+ \return the mip level. 0 by default.
+ */
+
+/*!
+ \fn void QRhiColorAttachment::setLevel(int level)
+ Sets the mip \a level.
+ */
+
+/*!
+ \fn QRhiTexture *QRhiColorAttachment::resolveTexture() const
+
+ \return the resolve texture this attachment description references, or
+ \nullptr if there is none.
+
+ Setting a non-null resolve texture is applicable when the attachment
+ references a multisample texture or renderbuffer. The QRhiTexture in the
+ resolveTexture() is then a non-multisample 2D texture (or texture array)
+ with the same size (but a sample count of 1). The multisample content is
+ automatically resolved into this texture at the end of each render pass.
+ */
+
+/*!
+ \fn void QRhiColorAttachment::setResolveTexture(QRhiTexture *tex)
+
+ Sets the resolve texture \a tex.
+
+ \a tex is expected to be a 2D texture or a 2D texture array. In either
+ case, resolving targets a single mip level of a single layer (array
+ element) of \a tex. The mip level and array layer are specified by
+ resolveLevel() and resolveLayer().
+
+ An exception is \l{setMultiViewCount()}{multiview}: when the color
+ attachment is associated with a texture array and multiview is enabled, the
+ resolve texture must also be a texture array with sufficient elements for
+ all views. In this case all elements that correspond to views are resolved
+ automatically; the behavior is similar to the following pseudo-code:
+ \badcode
+ for (i = 0; i < multiViewCount(); ++i)
+ resolve texture's layer() + i into resolveTexture's resolveLayer() + i
+ \endcode
+
+ Setting a non-multisample texture to resolve a multisample texture or
+ renderbuffer automatically at the end of the render pass is often
+ preferable to working with multisample textures (and not setting a resolve
+ texture), because it avoids the need for writing dedicated fragment shaders
+ that work exclusively with multisample textures (\c sampler2DMS, \c
+ texelFetch, etc.), and rather allows using the same shader as one would if
+ the attachment's texture was not multisampled to begin with. This comes at
+ the expense of an additional resource (the non-multisample \a tex).
+ */
+
+/*!
+ \fn int QRhiColorAttachment::resolveLayer() const
+ \return the currently set resolve texture layer. Defaults to 0.
+ */
+
+/*!
+ \fn void QRhiColorAttachment::setResolveLayer(int layer)
+ Sets the resolve texture \a layer to use.
+ */
+
+/*!
+ \fn int QRhiColorAttachment::resolveLevel() const
+ \return the currently set resolve texture mip level. Defaults to 0.
+ */
+
+/*!
+ \fn void QRhiColorAttachment::setResolveLevel(int level)
+ Sets the resolve texture mip \a level to use.
+ */
+
+/*!
+ \fn int QRhiColorAttachment::multiViewCount() const
+
+ \return the currently set number of views. Defaults to 0 which indicates
+ the render target with this color attachment is not going to be used with
+ multiview rendering.
+
+ \since 6.7
+ */
+
+/*!
+ \fn void QRhiColorAttachment::setMultiViewCount(int count)
+
+ Sets the view \a count. Setting a value larger than 1 indicates that the
+ render target with this color attachment is going to be used with multiview
+ rendering. The default value is 0. Values smaller than 2 indicate no
+ multiview rendering.
+
+ When \a count is set to \c 2 or greater, the color attachment must be
+ associated with a 2D texture array. layer() and multiViewCount() together
+ define the range of texture array elements that are targeted during
+ multiview rendering.
+
+ For example, if \c layer is \c 0 and \c multiViewCount is \c 2, the texture
+ array must have 2 (or more) elements, and the multiview rendering will
+ target elements 0 and 1. The \c{gl_ViewIndex} variable in the shaders has a
+ value of \c 0 or \c 1 then, where view \c 0 corresponds to the texture array
+ element \c 0, and view \c 1 to the array element \c 1.
+
+ \note Setting a \a count larger than 1, using a texture array as texture(),
+ and calling \l{QRhiCommandBuffer::beginPass()}{beginPass()} on a
+ QRhiTextureRenderTarget with this color attachment implies multiview
+ rendering for the entire render pass. multiViewCount() should not be set
+ unless multiview rendering is wanted. Multiview cannot be used with texture
+ types other than 2D texture arrays. (although 3D textures may work,
+ depending on the graphics API and backend; applications are nonetheless
+ advised not to rely on that and only use 2D texture arrays as the render
+ targets of multiview rendering)
+
+ See
+ \l{https://registry.khronos.org/OpenGL/extensions/OVR/OVR_multiview.txt}{GL_OVR_multiview}
+ for more details regarding multiview rendering. Do note that Qt requires
+ \l{https://registry.khronos.org/OpenGL/extensions/OVR/OVR_multiview2.txt}{GL_OVR_multiview2}
+ as well, when running on OpenGL (ES).
+
+ Multiview rendering is available only when the
+ \l{QRhi::MultiView}{MultiView} feature is reported as supported from
+ \l{QRhi::isFeatureSupported()}{isFeatureSupported()}.
+
+ \note For portability, be aware of limitations that exist for multiview
+ rendering with some of the graphics APIs. It is recommended that multiview
+ render passes do not rely on any of the features that
+ \l{https://registry.khronos.org/OpenGL/extensions/OVR/OVR_multiview.txt}{GL_OVR_multiview}
+ declares as unsupported. The one exception is shader stage outputs other
+ than \c{gl_Position} depending on \c{gl_ViewIndex}: that can be relied on
+ (even with OpenGL) because QRhi never reports multiview as supported without
+ \c{GL_OVR_multiview2} also being present.
+
+ \note Multiview rendering is not supported in combination with tessellation
+ or geometry shaders, even though some implementations of some graphics APIs
+ may allow this.
+
+ \since 6.7
+ */
+
+/*!
\class QRhiTextureRenderTargetDescription
- \internal
\inmodule QtGui
+ \since 6.6
\brief Describes the color and depth or depth/stencil attachments of a render target.
A texture render target has zero or more textures as color attachments,
@@ -1672,10 +2492,97 @@ QRhiColorAttachment::QRhiColorAttachment(QRhiRenderBuffer *renderBuffer)
\note depthStencilBuffer() and depthTexture() cannot be both set (cannot be
non-null at the same time).
+
+ Let's look at some example usages in combination with
+ QRhiTextureRenderTarget.
+
+ Due to the constructors, the targeting a texture (and no depth/stencil
+ buffer) is simple:
+
+ \code
+ QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(256, 256), 1, QRhiTexture::RenderTarget);
+ texture->create();
+ QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ texture }));
+ \endcode
+
+ The following creates a texture render target that is set up to target mip
+ level #2 of a texture:
+
+ \code
+ QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget | QRhiTexture::MipMapped);
+ texture->create();
+ QRhiColorAttachment colorAtt(texture);
+ colorAtt.setLevel(2);
+ QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ colorAtt });
+ \endcode
+
+ Another example, this time to render into a depth texture:
+
+ \code
+ QRhiTexture *shadowMap = rhi->newTexture(QRhiTexture::D32F, QSize(1024, 1024), 1, QRhiTexture::RenderTarget);
+ shadowMap->create();
+ QRhiTextureRenderTargetDescription rtDesc;
+ rtDesc.setDepthTexture(shadowMap);
+ QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget(rtDesc);
+ \endcode
+
+ A very common case, having a texture as the color attachment and a
+ renderbuffer as depth/stencil to enable depth testing:
+
+ \code
+ QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1. QRhiTexture::RenderTarget);
+ texture->create();
+ QRhiRenderBuffer *depthStencil = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, QSize(512, 512));
+ depthStencil->create();
+ QRhiTextureRenderTargetDescription rtDesc({ texture }, depthStencil);
+ QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget(rtDesc);
+ \endcode
+
+ Finally, to enable multisample rendering in a portable manner (so also
+ supporting OpenGL ES 3.0), using a QRhiRenderBuffer as the (multisample)
+ color buffer and then resolving into a regular (non-multisample) 2D
+ texture. To enable depth testing, a depth-stencil buffer, which also must
+ use the same sample count, is used as well:
+
+ \code
+ QRhiRenderBuffer *colorBuffer = rhi->newRenderBuffer(QRhiRenderBuffer::Color, QSize(512, 512), 4); // 4x MSAA
+ colorBuffer->create();
+ QRhiRenderBuffer *depthStencil = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, QSize(512, 512), 4);
+ depthStencil->create();
+ QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget);
+ texture->create();
+ QRhiColorAttachment colorAtt(colorBuffer);
+ colorAtt.setResolveTexture(texture);
+ QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ colorAtt, depthStencil });
+ \endcode
+
+ \note when multisample resolving is enabled, the multisample data may not be
+ written out at all. This means that the multisample texture in a color
+ attachment must not be used afterwards with shaders for sampling (or other
+ purposes) whenever a resolve texture is set, since the multisample color
+ buffer is merely an intermediate storage then that gets no data written back
+ on some GPU architectures at all. See
+ \l{QRhiTextureRenderTarget::Flag}{PreserveColorContents} for more details.
+
+ \note When using setDepthTexture(), not setDepthStencilBuffer(), and the
+ depth (stencil) data is not of interest afterwards, set the
+ DoNotStoreDepthStencilContents flag on the QRhiTextureRenderTarget. This
+ allows indicating to the underlying 3D API that the depth/stencil data can
+ be discarded, leading potentially to better performance with tiled GPU
+ architectures. When the depth-stencil buffer is a QRhiRenderBuffer (and also
+ for the multisample color texture, see previous note) this is implicit, but
+ with a depth (stencil) QRhiTexture the intention needs to be declared
+ explicitly. By default QRhi assumes that the data is of interest (e.g., the
+ depth texture is sampled in a shader afterwards).
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
+ \sa QRhiColorAttachment, QRhiTextureRenderTarget
*/
/*!
- \fn QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription()
+ \fn QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription() = default
Constructs an empty texture render target description.
*/
@@ -1717,9 +2624,125 @@ QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription(const QRh
}
/*!
+ \fn void QRhiTextureRenderTargetDescription::setColorAttachments(std::initializer_list<QRhiColorAttachment> list)
+ Sets the \a list of color attachments.
+ */
+
+/*!
+ \fn template<typename InputIterator> void QRhiTextureRenderTargetDescription::setColorAttachments(InputIterator first, InputIterator last)
+ Sets the list of color attachments via the iterators \a first and \a last.
+ */
+
+/*!
+ \fn const QRhiColorAttachment *QRhiTextureRenderTargetDescription::cbeginColorAttachments() const
+ \return a const iterator pointing to the first item in the attachment list.
+ */
+
+/*!
+ \fn const QRhiColorAttachment *QRhiTextureRenderTargetDescription::cendColorAttachments() const
+ \return a const iterator pointing just after the last item in the attachment list.
+ */
+
+/*!
+ \fn const QRhiColorAttachment *QRhiTextureRenderTargetDescription::colorAttachmentAt(qsizetype index) const
+ \return the color attachment at the specified \a index.
+ */
+
+/*!
+ \fn qsizetype QRhiTextureRenderTargetDescription::colorAttachmentCount() const
+ \return the number of currently set color attachments.
+ */
+
+/*!
+ \fn QRhiRenderBuffer *QRhiTextureRenderTargetDescription::depthStencilBuffer() const
+ \return the renderbuffer used as depth-stencil buffer, or \nullptr if none was set.
+ */
+
+/*!
+ \fn void QRhiTextureRenderTargetDescription::setDepthStencilBuffer(QRhiRenderBuffer *renderBuffer)
+
+ Sets the \a renderBuffer for depth-stencil. Not mandatory, e.g. when no
+ depth test/write or stencil-related features are used within any graphics
+ pipelines in any of the render passes for this render target, it can be
+ left set to \nullptr.
+
+ \note depthStencilBuffer() and depthTexture() cannot be both set (cannot be
+ non-null at the same time).
+
+ Using a QRhiRenderBuffer over a 2D QRhiTexture as the depth or
+ depth/stencil buffer is very common, and is the recommended approach for
+ applications. Using a QRhiTexture, and so setDepthTexture() becomes
+ relevant if the depth data is meant to be accessed (e.g. sampled in a
+ shader) afterwards, or when
+ \l{QRhiColorAttachment::setMultiViewCount()}{multiview rendering} is
+ involved (because then the depth texture must be a texture array).
+
+ \sa setDepthTexture()
+ */
+
+/*!
+ \fn QRhiTexture *QRhiTextureRenderTargetDescription::depthTexture() const
+ \return the currently referenced depth texture, or \nullptr if none was set.
+ */
+
+/*!
+ \fn void QRhiTextureRenderTargetDescription::setDepthTexture(QRhiTexture *texture)
+
+ Sets the \a texture for depth-stencil. This is an alternative to
+ setDepthStencilBuffer(), where instead of a QRhiRenderBuffer a QRhiTexture
+ with a suitable type (e.g., QRhiTexture::D32F) is provided.
+
+ \note depthStencilBuffer() and depthTexture() cannot be both set (cannot be
+ non-null at the same time).
+
+ \a texture can either be a 2D texture or a 2D texture array (when texture
+ arrays are supported). Specifying a texture array is relevant in particular
+ with
+ \l{QRhiColorAttachment::setMultiViewCount()}{multiview rendering}.
+
+ \note If \a texture is a format with a stencil component, such as
+ \l QRhiTexture::D24S8, it will serve as the stencil buffer as well.
+
+ \sa setDepthStencilBuffer()
+ */
+
+/*!
+ \fn QRhiTexture *QRhiTextureRenderTargetDescription::depthResolveTexture() const
+
+ \return the texture to which a multisample depth (or depth-stencil) texture
+ (or texture array) is resolved to. \nullptr if there is none, which is the
+ most common case.
+
+ \since 6.8
+ \sa QRhiColorAttachment::resolveTexture(), depthTexture()
+ */
+
+/*!
+ \fn void QRhiTextureRenderTargetDescription::setDepthResolveTexture(QRhiTexture *tex)
+
+ Sets the depth (or depth-stencil) resolve texture \a tex.
+
+ \a tex is expected to be a 2D texture or a 2D texture array with a format
+ matching the texture set via setDepthTexture().
+
+ \note Resolving depth (or depth-stencil) data is only functional when the
+ \l ResolveDepthStencil feature is reported as supported at run time. Support
+ for depth-stencil resolve is not universally available among the graphics
+ APIs. Designs assuming unconditional availability of depth-stencil resolve
+ are therefore non-portable, and should be avoided.
+
+ \note As an additional limitation for OpenGL ES in particular, setting a
+ depth resolve texture may only be functional in combination with
+ setDepthTexture(), not with setDepthStencilBuffer().
+
+ \since 6.8
+ \sa QRhiColorAttachment::setResolveTexture(), setDepthTexture()
+ */
+
+/*!
\class QRhiTextureSubresourceUploadDescription
- \internal
\inmodule QtGui
+ \since 6.6
\brief Describes the source for one mip level in a layer in a texture upload operation.
The source content is specified either as a QImage or as a raw blob. The
@@ -1776,10 +2799,15 @@ QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription(const QRh
in order to be portable across all backends) If this cannot be ensured, the
caller is strongly encouraged to call QImage::detach() on the image before
passing it to uploadTexture().
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
+ \sa QRhiTextureUploadDescription
*/
/*!
- \fn QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription()
+ \fn QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription() = default
Constructs an empty subresource description.
@@ -1827,12 +2855,109 @@ QRhiTextureSubresourceUploadDescription::QRhiTextureSubresourceUploadDescription
}
/*!
+ \fn QImage QRhiTextureSubresourceUploadDescription::image() const
+ \return the currently set QImage.
+ */
+
+/*!
+ \fn void QRhiTextureSubresourceUploadDescription::setImage(const QImage &image)
+
+ Sets \a image.
+ Upon textures loading, the image data will be read as is, with no formats conversions.
+
+ \note image() and data() cannot be both set at the same time.
+ */
+
+/*!
+ \fn QByteArray QRhiTextureSubresourceUploadDescription::data() const
+ \return the currently set raw pixel data.
+ */
+
+/*!
+ \fn void QRhiTextureSubresourceUploadDescription::setData(const QByteArray &data)
+
+ Sets \a data.
+
+ \note image() and data() cannot be both set at the same time.
+ */
+
+/*!
+ \fn quint32 QRhiTextureSubresourceUploadDescription::dataStride() const
+ \return the currently set data stride.
+ */
+
+/*!
+ \fn void QRhiTextureSubresourceUploadDescription::setDataStride(quint32 stride)
+
+ Sets the data \a stride in bytes. By default this is 0 and not always
+ relevant. When providing raw data(), and the stride is not specified via
+ setDataStride(), the stride (row pitch, row length in bytes) of the
+ provided data must be equal to \c{width * pixelSize} where \c pixelSize is
+ the number of bytes used for one pixel, and there must be no additional
+ padding between rows. Otherwise, if there is additional space between the
+ lines, set a non-zero \a stride. All this is applicable only when raw image
+ data is provided, and is not necessary when working QImage since that has
+ its own \l{QImage::bytesPerLine()}{stride} value.
+
+ \note Setting the stride via setDataStride() is only functional when
+ QRhi::ImageDataStride is reported as
+ \l{QRhi::isFeatureSupported()}{supported}.
+
+ \note When a QImage is given, the stride returned from
+ QImage::bytesPerLine() is taken into account automatically and therefore
+ there is no need to set the data stride manually.
+ */
+
+/*!
+ \fn QPoint QRhiTextureSubresourceUploadDescription::destinationTopLeft() const
+ \return the currently set destination top-left position. Defaults to (0, 0).
+ */
+
+/*!
+ \fn void QRhiTextureSubresourceUploadDescription::setDestinationTopLeft(const QPoint &p)
+ Sets the destination top-left position \a p.
+ */
+
+/*!
+ \fn QSize QRhiTextureSubresourceUploadDescription::sourceSize() const
+
+ \return the source size in pixels. Defaults to a default-constructed QSize,
+ which indicates the entire subresource.
+ */
+
+/*!
+ \fn void QRhiTextureSubresourceUploadDescription::setSourceSize(const QSize &size)
+
+ Sets the source \a size in pixels.
+
+ \note Setting sourceSize() or sourceTopLeft() may trigger a QImage copy
+ internally, depending on the format and the backend.
+ */
+
+/*!
+ \fn QPoint QRhiTextureSubresourceUploadDescription::sourceTopLeft() const
+ \return the currently set source top-left position. Defaults to (0, 0).
+ */
+
+/*!
+ \fn void QRhiTextureSubresourceUploadDescription::setSourceTopLeft(const QPoint &p)
+
+ Sets the source top-left position \a p.
+
+ \note Setting sourceSize() or sourceTopLeft() may trigger a QImage copy
+ internally, depending on the format and the backend.
+ */
+
+/*!
\class QRhiTextureUploadEntry
- \internal
\inmodule QtGui
+ \since 6.6
\brief Describes one layer (face for cubemaps, slice for 3D textures,
element for texture arrays) in a texture upload operation.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
@@ -1858,18 +2983,61 @@ QRhiTextureUploadEntry::QRhiTextureUploadEntry(int layer, int level,
}
/*!
+ \fn int QRhiTextureUploadEntry::layer() const
+ \return the currently set layer index (cubemap face, array layer). Defaults to 0.
+ */
+
+/*!
+ \fn void QRhiTextureUploadEntry::setLayer(int layer)
+ Sets the \a layer.
+ */
+
+/*!
+ \fn int QRhiTextureUploadEntry::level() const
+ \return the currently set mip level. Defaults to 0.
+ */
+
+/*!
+ \fn void QRhiTextureUploadEntry::setLevel(int level)
+ Sets the mip \a level.
+ */
+
+/*!
+ \fn QRhiTextureSubresourceUploadDescription QRhiTextureUploadEntry::description() const
+ \return the currently set subresource description.
+ */
+
+/*!
+ \fn void QRhiTextureUploadEntry::setDescription(const QRhiTextureSubresourceUploadDescription &desc)
+ Sets the subresource description \a desc.
+ */
+
+/*!
\class QRhiTextureUploadDescription
- \internal
\inmodule QtGui
+ \since 6.6
\brief Describes a texture upload operation.
Used with QRhiResourceUpdateBatch::uploadTexture(). That function has two
variants: one taking a QImage and one taking a
QRhiTextureUploadDescription. The former is a convenience version,
internally creating a QRhiTextureUploadDescription with a single image
- targeting level 0 for layer 0. However, when cubemaps, pre-generated mip
- images, or compressed textures are involved, applications will have to work
- directly with this class instead.
+ targeting level 0 for layer 0.
+
+ An example of the the common, simple case of wanting to upload the contents
+ of a QImage to a QRhiTexture with a matching pixel size:
+
+ \code
+ QImage image(256, 256, QImage::Format_RGBA8888);
+ image.fill(Qt::green); // or could use a QPainter targeting image
+ QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(256, 256));
+ texture->create();
+ QRhiResourceUpdateBatch *u = rhi->nextResourceUpdateBatch();
+ u->uploadTexture(texture, image);
+ \endcode
+
+ When cubemaps, pre-generated mip images, compressed textures, or partial
+ uploads are involved, applications will have to use this class instead.
QRhiTextureUploadDescription also enables specifying batched uploads, which
are useful for example when generating an atlas or glyph cache texture:
@@ -1885,10 +3053,10 @@ QRhiTextureUploadEntry::QRhiTextureUploadEntry(int layer, int level,
For example, specifying the faces of a cubemap could look like the following:
- \badcode
+ \code
QImage faces[6];
- ...
- QList<QRhiTextureUploadEntry> entries;
+ // ...
+ QVarLengthArray<QRhiTextureUploadEntry, 6> entries;
for (int i = 0; i < 6; ++i)
entries.append(QRhiTextureUploadEntry(i, 0, faces[i]));
QRhiTextureUploadDescription desc;
@@ -1898,7 +3066,7 @@ QRhiTextureUploadEntry::QRhiTextureUploadEntry(int layer, int level,
Another example that specifies mip images for a compressed texture:
- \badcode
+ \code
QList<QRhiTextureUploadEntry> entries;
const int mipCount = rhi->mipLevelsForSize(compressedTexture->pixelSize());
for (int level = 0; level < mipCount; ++level) {
@@ -1913,7 +3081,7 @@ QRhiTextureUploadEntry::QRhiTextureUploadEntry(int layer, int level,
With partial uploads targeting the same subresource, it is recommended to
batch them into a single upload request, whenever possible:
- \badcode
+ \code
QRhiTextureSubresourceUploadDescription subresDesc(image);
subresDesc.setSourceSize(QSize(10, 10));
subResDesc.setDestinationTopLeft(QPoint(50, 40));
@@ -1927,6 +3095,11 @@ QRhiTextureUploadEntry::QRhiTextureUploadEntry(int layer, int level,
QRhiTextureUploadDescription desc({ entry, entry2});
resourceUpdates->uploadTexture(texture, desc);
\endcode
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
+ \sa QRhiResourceUpdateBatch
*/
/*!
@@ -1959,9 +3132,39 @@ QRhiTextureUploadDescription::QRhiTextureUploadDescription(std::initializer_list
}
/*!
+ \fn void QRhiTextureUploadDescription::setEntries(std::initializer_list<QRhiTextureUploadEntry> list)
+ Sets the \a list of entries.
+ */
+
+/*!
+ \fn template<typename InputIterator> void QRhiTextureUploadDescription::setEntries(InputIterator first, InputIterator last)
+ Sets the list of entries using the iterators \a first and \a last.
+ */
+
+/*!
+ \fn const QRhiTextureUploadEntry *QRhiTextureUploadDescription::cbeginEntries() const
+ \return a const iterator pointing to the first item in the entry list.
+ */
+
+/*!
+ \fn const QRhiTextureUploadEntry *QRhiTextureUploadDescription::cendEntries() const
+ \return a const iterator pointing just after the last item in the entry list.
+ */
+
+/*!
+ \fn const QRhiTextureUploadEntry *QRhiTextureUploadDescription::entryAt(qsizetype index) const
+ \return the entry at \a index.
+ */
+
+/*!
+ \fn qsizetype QRhiTextureUploadDescription::entryCount() const
+ \return the number of entries.
+ */
+
+/*!
\class QRhiTextureCopyDescription
- \internal
\inmodule QtGui
+ \since 6.6
\brief Describes a texture-to-texture copy operation.
An empty pixelSize() indicates that the entire subresource is to be copied.
@@ -1981,6 +3184,9 @@ QRhiTextureUploadDescription::QRhiTextureUploadDescription(std::initializer_list
copied at a time. The source and destination layer and mip level indices can
differ, but the size and position must be carefully controlled to avoid out
of bounds copies, in which case the behavior is undefined.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
@@ -1990,9 +3196,83 @@ QRhiTextureUploadDescription::QRhiTextureUploadDescription(std::initializer_list
*/
/*!
+ \fn QSize QRhiTextureCopyDescription::pixelSize() const
+ \return the size of the region to copy.
+
+ \note An empty pixelSize() indicates that the entire subresource is to be
+ copied. A default constructed copy description therefore leads to copying
+ the entire subresource at level 0 of layer 0.
+ */
+
+/*!
+ \fn void QRhiTextureCopyDescription::setPixelSize(const QSize &sz)
+ Sets the size of the region to copy to \a sz.
+ */
+
+/*!
+ \fn int QRhiTextureCopyDescription::sourceLayer() const
+ \return the source array layer (cubemap face or array layer index). Defaults to 0.
+ */
+
+/*!
+ \fn void QRhiTextureCopyDescription::setSourceLayer(int layer)
+ Sets the source array \a layer.
+ */
+
+/*!
+ \fn int QRhiTextureCopyDescription::sourceLevel() const
+ \return the source mip level. Defaults to 0.
+ */
+
+/*!
+ \fn void QRhiTextureCopyDescription::setSourceLevel(int level)
+ Sets the source mip \a level.
+ */
+
+/*!
+ \fn QPoint QRhiTextureCopyDescription::sourceTopLeft() const
+ \return the source top-left position (in pixels). Defaults to (0, 0).
+ */
+
+/*!
+ \fn void QRhiTextureCopyDescription::setSourceTopLeft(const QPoint &p)
+ Sets the source top-left position to \a p.
+ */
+
+/*!
+ \fn int QRhiTextureCopyDescription::destinationLayer() const
+ \return the destination array layer (cubemap face or array layer index). Default to 0.
+ */
+
+/*!
+ \fn void QRhiTextureCopyDescription::setDestinationLayer(int layer)
+ Sets the destination array \a layer.
+ */
+
+/*!
+ \fn int QRhiTextureCopyDescription::destinationLevel() const
+ \return the destionation mip level. Defaults to 0.
+ */
+
+/*!
+ \fn void QRhiTextureCopyDescription::setDestinationLevel(int level)
+ Sets the destination mip \a level.
+ */
+
+/*!
+ \fn QPoint QRhiTextureCopyDescription::destinationTopLeft() const
+ \return the destionation top-left position in pixels. Defaults to (0, 0).
+ */
+
+/*!
+ \fn void QRhiTextureCopyDescription::setDestinationTopLeft(const QPoint &p)
+ Sets the destination top-left position \a p.
+ */
+
+/*!
\class QRhiReadbackDescription
- \internal
\inmodule QtGui
+ \since 6.6
\brief Describes a readback (reading back texture contents from possibly GPU-only memory) operation.
The source of the readback operation is either a QRhiTexture or the
@@ -2010,10 +3290,13 @@ QRhiTextureUploadDescription::QRhiTextureUploadDescription(std::initializer_list
\note Multisample textures cannot be read back. Readbacks are supported for
multisample swapchain buffers however.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
- \fn QRhiReadbackDescription::QRhiReadbackDescription()
+ \fn QRhiReadbackDescription::QRhiReadbackDescription() = default
Constructs an empty texture readback description.
@@ -2037,32 +3320,140 @@ QRhiReadbackDescription::QRhiReadbackDescription(QRhiTexture *texture)
}
/*!
+ \fn QRhiTexture *QRhiReadbackDescription::texture() const
+
+ \return the QRhiTexture that is read back. Can be left set to \nullptr
+ which indicates that the backbuffer of the current swapchain is to be used
+ instead.
+ */
+
+/*!
+ \fn void QRhiReadbackDescription::setTexture(QRhiTexture *tex)
+
+ Sets the texture \a tex as the source of the readback operation.
+
+ Setting \nullptr is valid too, in which case the current swapchain's
+ current backbuffer is used. (but then the readback cannot be issued in a
+ non-swapchain-based frame)
+
+ \note Multisample textures cannot be read back. Readbacks are supported for
+ multisample swapchain buffers however.
+
+ \note Textures used in readbacks must be created with
+ QRhiTexture::UsedAsTransferSource.
+
+ \note Swapchains used in readbacks must be created with
+ QRhiSwapChain::UsedAsTransferSource.
+ */
+
+/*!
+ \fn int QRhiReadbackDescription::layer() const
+
+ \return the currently set array layer (cubemap face, array index). Defaults to 0.
+
+ Applicable only when the source of the readback is a QRhiTexture.
+ */
+
+/*!
+ \fn void QRhiReadbackDescription::setLayer(int layer)
+ Sets the array \a layer to read back.
+ */
+
+/*!
+ \fn int QRhiReadbackDescription::level() const
+
+ \return the currently set mip level. Defaults to 0.
+
+ Applicable only when the source of the readback is a QRhiTexture.
+ */
+
+/*!
+ \fn void QRhiReadbackDescription::setLevel(int level)
+ Sets the mip \a level to read back.
+ */
+
+/*!
\class QRhiReadbackResult
- \internal
\inmodule QtGui
- \brief Describes the results of a potentially asynchronous readback operation.
+ \since 6.6
+ \brief Describes the results of a potentially asynchronous buffer or texture readback operation.
When \l completed is set, the function is invoked when the \l data is
available. \l format and \l pixelSize are set upon completion together with
\l data.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+ */
+
+/*!
+ \variable QRhiReadbackResult::completed
+
+ Callback that is invoked upon completion, on the thread the QRhi operates
+ on. Can be left set to \nullptr, in which case no callback is invoked.
*/
/*!
+ \variable QRhiReadbackResult::format
+
+ Valid only for textures, the texture format.
+ */
+
+/*!
+ \variable QRhiReadbackResult::pixelSize
+
+ Valid only for textures, the size in pixels.
+ */
+
+/*!
+ \variable QRhiReadbackResult::data
+
+ The buffer or image data.
+
+ \sa QRhiResourceUpdateBatch::readBackTexture(), QRhiResourceUpdateBatch::readBackBuffer()
+ */
+
+
+/*!
\class QRhiNativeHandles
- \internal
\inmodule QtGui
+ \since 6.6
\brief Base class for classes exposing backend-specific collections of native resource objects.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
\class QRhiResource
- \internal
\inmodule QtGui
+ \since 6.6
\brief Base class for classes encapsulating native resource objects.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+ */
+
+/*!
+ \enum QRhiResource::Type
+ Specifies type of the resource.
+
+ \value Buffer
+ \value Texture
+ \value Sampler
+ \value RenderBuffer
+ \value RenderPassDescriptor
+ \value SwapChainRenderTarget
+ \value TextureRenderTarget
+ \value ShaderResourceBindings
+ \value GraphicsPipeline
+ \value SwapChain
+ \value ComputePipeline
+ \value CommandBuffer
*/
/*!
- \fn QRhiResource::Type QRhiResource::resourceType() const
+ \fn virtual QRhiResource::Type QRhiResource::resourceType() const = 0
\return the type of the resource.
*/
@@ -2094,7 +3485,7 @@ QRhiResource::~QRhiResource()
}
/*!
- \fn void QRhiResource::destroy()
+ \fn virtual void QRhiResource::destroy() = 0
Releases (or requests deferred releasing of) the underlying native graphics
resources. Safe to call multiple times, subsequent invocations will be a
@@ -2108,7 +3499,7 @@ QRhiResource::~QRhiResource()
released until the frame is submitted by QRhi::endFrame().
The QRhiResource destructor also performs the same task, so calling this
- function is not necessary before destroying a QRhiResource.
+ function is not necessary before deleting a QRhiResource.
\sa deleteLater()
*/
@@ -2121,11 +3512,42 @@ QRhiResource::~QRhiResource()
requirement of not altering QRhiResource objects that are referenced by the
frame being recorded.
+ If the QRhi that created this object is already destroyed, the object is
+ deleted immediately.
+
+ Using deleteLater() can be a useful convenience in many cases, and it
+ complements the low-level guarantee (that the underlying native graphics
+ objects are never destroyed until it is safe to do so and it is known for
+ sure that they are not used by the GPU in an still in-flight frame), by
+ offering a way to make sure the C++ object instances (of QRhiBuffer,
+ QRhiTexture, etc.) themselves also stay valid until the end of the current
+ frame.
+
+ The following example shows a convenient way of creating a throwaway buffer
+ that is only used in one frame and gets automatically released in
+ endFrame(). (when it comes to the underlying native buffer(s), the usual
+ guarantee applies: the QRhi backend defers the releasing of those until it
+ is guaranteed that the frame in which the buffer is accessed by the GPU has
+ completed)
+
+ \code
+ rhi->beginFrame(swapchain);
+ QRhiBuffer *buf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, 256);
+ buf->deleteLater(); // !
+ u = rhi->nextResourceUpdateBatch();
+ u->uploadStaticBuffer(buf, data);
+ // ... draw with buf
+ rhi->endFrame();
+ \endcode
+
\sa destroy()
*/
void QRhiResource::deleteLater()
{
- m_rhi->addDeleteLater(this);
+ if (m_rhi)
+ m_rhi->addDeleteLater(this);
+ else
+ delete this;
}
/*!
@@ -2139,7 +3561,7 @@ QByteArray QRhiResource::name() const
/*!
Sets a \a name for the object.
- This has two uses: to get descriptive names for the native graphics
+ This allows getting descriptive names for the native graphics
resources visible in graphics debugging tools, such as
\l{https://renderdoc.org/}{RenderDoc} and
\l{https://developer.apple.com/xcode/}{XCode}.
@@ -2174,17 +3596,140 @@ quint64 QRhiResource::globalResourceId() const
/*!
\return the QRhi that created this resource.
+
+ If the QRhi that created this object is already destroyed, the result is
+ \nullptr.
*/
QRhi *QRhiResource::rhi() const
{
- return m_rhi->q;
+ return m_rhi ? m_rhi->q : nullptr;
}
/*!
\class QRhiBuffer
- \internal
\inmodule QtGui
+ \since 6.6
\brief Vertex, index, or uniform (constant) buffer resource.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
+ A QRhiBuffer encapsulates zero, one, or more native buffer objects (such as
+ a \c VkBuffer or \c MTLBuffer). With some graphics APIs and backends
+ certain types of buffers may not use a native buffer object at all (e.g.
+ OpenGL if uniform buffer objects are not used), but this is transparent to
+ the user of the QRhiBuffer API. Similarly, the fact that some types of
+ buffers may use two or three native buffers underneath, in order to allow
+ efficient per-frame content update without stalling the GPU pipeline, is
+ mostly invisible to the applications and libraries.
+
+ A QRhiBuffer instance is always created by calling
+ \l{QRhi::newBuffer()}{the QRhi's newBuffer() function}. This creates no
+ native graphics resources. To do that, call create() after setting the
+ appropriate options, such as the type, usage flags, size, although in most cases these
+ are already set based on the arguments passed to
+ \l{QRhi::newBuffer()}{newBuffer()}.
+
+ \section2 Example usage
+
+ To create a uniform buffer for a shader where the GLSL uniform block
+ contains a single \c mat4 member, and update the contents:
+
+ \code
+ QRhiBuffer *ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64);
+ if (!ubuf->create()) { error(); }
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+ QMatrix4x4 mvp;
+ // ... set up the modelview-projection matrix
+ batch->updateDynamicBuffer(ubuf, 0, 64, mvp.constData());
+ // ...
+ commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call
+ \endcode
+
+ An example of creating a buffer with vertex data:
+
+ \code
+ const float vertices[] = { -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 1.0f };
+ QRhiBuffer *vbuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertices));
+ if (!vbuf->create()) { error(); }
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+ batch->uploadStaticBuffer(vbuf, vertices);
+ // ...
+ commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call
+ \endcode
+
+ An index buffer:
+
+ \code
+ static const quint16 indices[] = { 0, 1, 2 };
+ QRhiBuffer *ibuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(indices));
+ if (!ibuf->create()) { error(); }
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+ batch->uploadStaticBuffer(ibuf, indices);
+ // ...
+ commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call
+ \endcode
+
+ \section2 Common patterns
+
+ A call to create() destroys any existing native resources if create() was
+ successfully called before. If those native resources are still in use by
+ an in-flight frame (i.e., there's a chance they are still read by the GPU),
+ the destroying of those resources is deferred automatically. Thus a very
+ common and convenient pattern to safely increase the size of an already
+ initialized buffer is the following. In practice this drops and creates a
+ whole new set of native resources underneath, so it is not necessarily a
+ cheap operation, but is more convenient and still faster than the
+ alternatives, because by not destroying the \c buf object itself, all
+ references to it stay valid in other data structures (e.g., in any
+ QRhiShaderResourceBinding the QRhiBuffer is referenced from).
+
+ \code
+ if (buf->size() < newSize) {
+ buf->setSize(newSize);
+ if (!buf->create()) { error(); }
+ }
+ // continue using buf, fill it with new data
+ \endcode
+
+ When working with uniform buffers, it will sometimes be necessary to
+ combine data for multiple draw calls into a single buffer for efficiency
+ reasons. Be aware of the aligment requirements: with some graphics APIs
+ offsets for a uniform buffer must be aligned to 256 bytes. This applies
+ both to QRhiShaderResourceBinding and to the dynamic offsets passed to
+ \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()}. Use the
+ \l{QRhi::ubufAlignment()}{ubufAlignment()} and
+ \l{QRhi::ubufAligned()}{ubufAligned()} functions to create portable code.
+ As an example, the following is an outline for issuing multiple (\c N) draw
+ calls with the same pipeline and geometry, but with a different data in the
+ uniform buffers exposed at binding point 0. This assumes the buffer is
+ exposed via
+ \l{QRhiShaderResourceBinding::uniformBufferWithDynamicOffset()}{uniformBufferWithDynamicOffset()}
+ which allows passing a QRhiCommandBuffer::DynamicOffset list to
+ \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()}.
+
+ \code
+ const int N = 2;
+ const int UB_SIZE = 64 + 4; // assuming a uniform block with { mat4 matrix; float opacity; }
+ const int ONE_UBUF_SIZE = rhi->ubufAligned(UB_SIZE);
+ const int TOTAL_UBUF_SIZE = N * ONE_UBUF_SIZE;
+ QRhiBuffer *ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, TOTAL_UBUF_SIZE);
+ if (!ubuf->create()) { error(); }
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+ for (int i = 0; i < N; ++i) {
+ batch->updateDynamicBuffer(ubuf, i * ONE_UBUF_SIZE, 64, matrix.constData());
+ batch->updateDynamicBuffer(ubuf, i * ONE_UBUF_SIZE + 64, 4, &opacity);
+ }
+ // ...
+ // beginPass(), set pipeline, etc., and then:
+ for (int i = 0; i < N; ++i) {
+ QRhiCommandBuffer::DynamicOffset dynOfs[] = { { 0, i * ONE_UBUF_SIZE } };
+ cb->setShaderResources(srb, 1, dynOfs);
+ cb->draw(36);
+ }
+ \endcode
+
+ \sa QRhiResourceUpdateBatch, QRhi, QRhiCommandBuffer
*/
/*!
@@ -2220,14 +3765,14 @@ QRhi *QRhiResource::rhi() const
Flag values to specify how the buffer is going to be used.
\value VertexBuffer Vertex buffer. This allows the QRhiBuffer to be used in
- \l{setVertexInput()}{QRhiCommandBuffer::setVertexInput()}.
+ \l{QRhiCommandBuffer::setVertexInput()}{setVertexInput()}.
\value IndexBuffer Index buffer. This allows the QRhiBuffer to be used in
- \l{setVertexInput()}{QRhiCommandBuffer::setVertexInput()}.
+ \l{QRhiCommandBuffer::setVertexInput()}{setVertexInput()}.
\value UniformBuffer Uniform buffer (also called constant buffer). This
allows the QRhiBuffer to be used in combination with
- \l{UniformBuffer}{QRhiShaderResourceBinding::UniformBuffer}. When
+ \l{QRhiShaderResourceBinding::UniformBuffer}{UniformBuffer}. When
\l{QRhi::NonDynamicUniformBuffers}{NonDynamicUniformBuffers} is reported as
not supported, this usage can only be combined with the type Dynamic.
@@ -2241,21 +3786,8 @@ QRhi *QRhiResource::rhi() const
*/
/*!
- \fn void QRhiBuffer::setSize(int sz)
-
- Sets the size of the buffer in bytes. The size is normally specified in
- QRhi::newBuffer() so this function is only used when the size has to be
- changed. As with other setters, the size only takes effect when calling
- create(), and for already created buffers this involves releasing the previous
- native resource and creating new ones under the hood.
-
- Backends may choose to allocate buffers bigger than \a sz in order to
- fulfill alignment requirements. This is hidden from the applications and
- size() will always report the size requested in \a sz.
- */
-
-/*!
\class QRhiBuffer::NativeBuffer
+ \inmodule QtGui
\brief Contains information about the underlying native resources of a buffer.
*/
@@ -2267,10 +3799,13 @@ QRhi *QRhiResource::rhi() const
objects array are pointers to a GLuint. With Vulkan, the native handle is a
VkBuffer, so the elements of the array are pointers to a VkBuffer. With
Direct3D 11 and Metal the elements are pointers to a ID3D11Buffer or
- MTLBuffer pointer, respectively.
+ MTLBuffer pointer, respectively. With Direct3D 12, the elements are
+ pointers to a ID3D12Resource.
\note Pay attention to the fact that the elements are always pointers to
the native buffer handle type, even if the native type itself is a pointer.
+ (so the elements are \c{VkBuffer *} on Vulkan, even though VkBuffer itself
+ is a pointer on 64-bit architectures).
*/
/*!
@@ -2306,7 +3841,7 @@ QRhiResource::Type QRhiBuffer::resourceType() const
}
/*!
- \fn bool QRhiBuffer::create()
+ \fn virtual bool QRhiBuffer::create() = 0
Creates the corresponding native graphics resources. If there are already
resources present due to an earlier create() with no corresponding
@@ -2317,6 +3852,50 @@ QRhiResource::Type QRhiBuffer::resourceType() const
*/
/*!
+ \fn QRhiBuffer::Type QRhiBuffer::type() const
+ \return the buffer type.
+ */
+
+/*!
+ \fn void QRhiBuffer::setType(Type t)
+ Sets the buffer's type to \a t.
+ */
+
+/*!
+ \fn QRhiBuffer::UsageFlags QRhiBuffer::usage() const
+ \return the buffer's usage flags.
+ */
+
+/*!
+ \fn void QRhiBuffer::setUsage(UsageFlags u)
+ Sets the buffer's usage flags to \a u.
+ */
+
+/*!
+ \fn quint32 QRhiBuffer::size() const
+
+ \return the buffer's size in bytes.
+
+ This is always the value that was passed to setSize() or QRhi::newBuffer().
+ Internally, the native buffers may be bigger if that is required by the
+ underlying graphics API.
+ */
+
+/*!
+ \fn void QRhiBuffer::setSize(quint32 sz)
+
+ Sets the size of the buffer in bytes. The size is normally specified in
+ QRhi::newBuffer() so this function is only used when the size has to be
+ changed. As with other setters, the size only takes effect when calling
+ create(), and for already created buffers this involves releasing the previous
+ native resource and creating new ones under the hood.
+
+ Backends may choose to allocate buffers bigger than \a sz in order to
+ fulfill alignment requirements. This is hidden from the applications and
+ size() will always report the size requested in \a sz.
+ */
+
+/*!
\return the underlying native resources for this buffer. The returned value
will be empty if exposing the underlying native resources is not supported by
the backend.
@@ -2404,18 +3983,18 @@ void QRhiBuffer::endFullDynamicBufferUpdateForCurrentFrame()
/*!
\class QRhiRenderBuffer
- \internal
\inmodule QtGui
+ \since 6.6
\brief Renderbuffer resource.
Renderbuffers cannot be sampled or read but have some benefits over
textures in some cases:
- A DepthStencil renderbuffer may be lazily allocated and be backed by
+ A \l DepthStencil renderbuffer may be lazily allocated and be backed by
transient memory with some APIs. On some platforms this may mean the
depth/stencil buffer uses no physical backing at all.
- Color renderbuffers are useful since QRhi::MultisampleRenderBuffer may be
+ \l Color renderbuffers are useful since QRhi::MultisampleRenderBuffer may be
supported even when QRhi::MultisampleTexture is not.
How the renderbuffer is implemented by a backend is not exposed to the
@@ -2429,6 +4008,9 @@ void QRhiBuffer::endFullDynamicBufferUpdateForCurrentFrame()
QRhi provides automatic sizing behavior to match the color buffers, which
means calling setPixelSize() and create() are not necessary for such
renderbuffers.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
@@ -2440,6 +4022,22 @@ void QRhiBuffer::endFullDynamicBufferUpdateForCurrentFrame()
*/
/*!
+ \struct QRhiRenderBuffer::NativeRenderBuffer
+ \inmodule QtGui
+ \brief Wraps a native renderbuffer object.
+ */
+
+/*!
+ \variable QRhiRenderBuffer::NativeRenderBuffer::object
+ \brief 64-bit integer containing the native object handle.
+
+ Used with QRhiRenderBuffer::createFrom().
+
+ With OpenGL the native handle is a GLuint value. \c object is expected to
+ be a valid OpenGL renderbuffer object ID.
+ */
+
+/*!
\enum QRhiRenderBuffer::Flag
Flag values for flags() and setFlags()
@@ -2476,7 +4074,7 @@ QRhiResource::Type QRhiRenderBuffer::resourceType() const
}
/*!
- \fn bool QRhiRenderBuffer::create()
+ \fn virtual bool QRhiRenderBuffer::create() = 0
Creates the corresponding native graphics resources. If there are already
resources present due to an earlier create() with no corresponding
@@ -2525,16 +4123,121 @@ bool QRhiRenderBuffer::createFrom(NativeRenderBuffer src)
}
/*!
- \fn QRhiTexture::Format QRhiRenderBuffer::backingFormat() const
+ \fn QRhiRenderBuffer::Type QRhiRenderBuffer::type() const
+ \return the renderbuffer type.
+ */
+
+/*!
+ \fn void QRhiRenderBuffer::setType(Type t)
+ Sets the type to \a t.
+ */
+
+/*!
+ \fn QSize QRhiRenderBuffer::pixelSize() const
+ \return the pixel size.
+ */
+
+/*!
+ \fn void QRhiRenderBuffer::setPixelSize(const QSize &sz)
+ Sets the size (in pixels) to \a sz.
+ */
+
+/*!
+ \fn int QRhiRenderBuffer::sampleCount() const
+ \return the sample count. 1 means no multisample antialiasing.
+ */
+
+/*!
+ \fn void QRhiRenderBuffer::setSampleCount(int s)
+ Sets the sample count to \a s.
+ */
+
+/*!
+ \fn QRhiRenderBuffer::Flags QRhiRenderBuffer::flags() const
+ \return the flags.
+ */
+
+/*!
+ \fn void QRhiRenderBuffer::setFlags(Flags f)
+ Sets the flags to \a f.
+ */
+
+/*!
+ \fn virtual QRhiTexture::Format QRhiRenderBuffer::backingFormat() const = 0
\internal
*/
/*!
\class QRhiTexture
- \internal
\inmodule QtGui
+ \since 6.6
\brief Texture resource.
+
+ A QRhiTexture encapsulates a native texture object, such as a \c VkImage or
+ \c MTLTexture.
+
+ A QRhiTexture instance is always created by calling
+ \l{QRhi::newTexture()}{the QRhi's newTexture() function}. This creates no
+ native graphics resources. To do that, call create() after setting the
+ appropriate options, such as the format and size, although in most cases
+ these are already set based on the arguments passed to
+ \l{QRhi::newTexture()}{newTexture()}.
+
+ Setting the \l{QRhiTexture::Flags}{flags} correctly is essential, otherwise
+ various errors can occur depending on the underlying QRhi backend and
+ graphics API. For example, when a texture will be rendered into from a
+ render pass via QRhiTextureRenderTarget, the texture must be created with
+ the \l RenderTarget flag set. Similarly, when the texture is going to be
+ \l{QRhiResourceUpdateBatch::readBackTexture()}{read back}, the \l
+ UsedAsTransferSource flag must be set upfront. Mipmapped textures must have
+ the MipMapped flag set. And so on. It is not possible to change the flags
+ once create() has succeeded. To release the existing and create a new
+ native texture object with the changed settings, call the setters and call
+ create() again. This then might be a potentially expensive operation.
+
+ \section2 Example usage
+
+ To create a 2D texture with a size of 512x512 pixels and set its contents to all green:
+
+ \code
+ QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512));
+ if (!texture->create()) { error(); }
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+ QImage image(512, 512, QImage::Format_RGBA8888);
+ image.fill(Qt::green);
+ batch->uploadTexture(texture, image);
+ // ...
+ commandBuffer->resourceUpdate(batch); // or, alternatively, pass 'batch' to a beginPass() call
+ \endcode
+
+ \section2 Common patterns
+
+ A call to create() destroys any existing native resources if create() was
+ successfully called before. If those native resources are still in use by
+ an in-flight frame (i.e., there's a chance they are still read by the GPU),
+ the destroying of those resources is deferred automatically. Thus a very
+ common and convenient pattern to safely change the size of an already
+ existing texture is the following. In practice this drops and creates a
+ whole new native texture resource underneath, so it is not necessarily a
+ cheap operation, but is more convenient and still faster than the
+ alternatives, because by not destroying the \c texture object itself, all
+ references to it stay valid in other data structures (e.g., in any
+ QShaderResourceBinding the QRhiTexture is referenced from).
+
+ \code
+ // determine newSize, e.g. based on the swapchain's output size or other factors
+ if (texture->pixelSize() != newSize) {
+ texture->setPixelSize(newSize);
+ if (!texture->create()) { error(); }
+ }
+ // continue using texture, fill it with new data
+ \endcode
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
+ \sa QRhiResourceUpdateBatch, QRhi, QRhiTextureRenderTarget
*/
/*!
@@ -2688,7 +4391,8 @@ bool QRhiRenderBuffer::createFrom(NativeRenderBuffer src)
*/
/*!
- \class QRhiTexture::NativeTexture
+ \struct QRhiTexture::NativeTexture
+ \inmodule QtGui
\brief Contains information about the underlying native resources of a texture.
*/
@@ -2697,9 +4401,10 @@ bool QRhiRenderBuffer::createFrom(NativeRenderBuffer src)
\brief 64-bit integer containing the native object handle.
With OpenGL, the native handle is a GLuint value, so \c object can then be
- cast to a GLuint. With Vulkan, the native handle is a VkImage, so \c
- object can be cast to a VkImage. With Direct3D 11 and Metal \c
- object contains a ID3D11Texture2D or MTLTexture pointer, respectively.
+ cast to a GLuint. With Vulkan, the native handle is a VkImage, so \c object
+ can be cast to a VkImage. With Direct3D 11 and Metal \c object contains a
+ ID3D11Texture2D or MTLTexture pointer, respectively. With Direct3D 12
+ \c object contains a ID3D12Resource pointer.
*/
/*!
@@ -2729,7 +4434,7 @@ QRhiResource::Type QRhiTexture::resourceType() const
}
/*!
- \fn bool QRhiTexture::create()
+ \fn virtual bool QRhiTexture::create() = 0
Creates the corresponding native graphics resources. If there are already
resources present due to an earlier create() with no corresponding
@@ -2752,13 +4457,16 @@ QRhiTexture::NativeTexture QRhiTexture::nativeTexture()
}
/*!
- Similar to create() except that no new native textures are created. Instead,
- the native texture resources specified by \a src is used.
+ Similar to create(), except that no new native textures are created.
+ Instead, the native texture resources specified by \a src is used.
This allows importing an existing native texture object (which must belong
to the same device or sharing context, depending on the graphics API) from
an external graphics engine.
+ \return true if the specified existing native texture object has been
+ successfully wrapped as a non-owning QRhiTexture.
+
\note format(), pixelSize(), sampleCount(), and flags() must still be set
correctly. Passing incorrect sizes and other values to QRhi::newTexture()
and then following it with a createFrom() expecting that the native texture
@@ -2811,10 +4519,196 @@ void QRhiTexture::setNativeLayout(int layout)
}
/*!
+ \fn QRhiTexture::Format QRhiTexture::format() const
+ \return the texture format.
+ */
+
+/*!
+ \fn void QRhiTexture::setFormat(QRhiTexture::Format fmt)
+
+ Sets the requested texture format to \a fmt.
+
+ \note The value set is only taken into account upon the next call to
+ create(), i.e. when the underlying graphics resource are (re)created.
+ Setting a new value is futile otherwise and must be avoided since it can
+ lead to inconsistent state.
+ */
+
+/*!
+ \fn QSize QRhiTexture::pixelSize() const
+ \return the size in pixels.
+ */
+
+/*!
+ \fn void QRhiTexture::setPixelSize(const QSize &sz)
+
+ Sets the texture size, specified in pixels, to \a sz.
+
+ \note The value set is only taken into account upon the next call to
+ create(), i.e. when the underlying graphics resource are (re)created.
+ Setting a new value is futile otherwise and must be avoided since it can
+ lead to inconsistent state. The same applies to all other setters as well.
+ */
+
+/*!
+ \fn int QRhiTexture::depth() const
+ \return the depth for 3D textures.
+ */
+
+/*!
+ \fn void QRhiTexture::setDepth(int depth)
+ Sets the \a depth for a 3D texture.
+ */
+
+/*!
+ \fn int QRhiTexture::arraySize() const
+ \return the texture array size.
+ */
+
+/*!
+ \fn void QRhiTexture::setArraySize(int arraySize)
+ Sets the texture \a arraySize.
+ */
+
+/*!
+ \fn int QRhiTexture::arrayRangeStart() const
+
+ \return the first array layer when setArrayRange() was called.
+
+ \sa setArrayRange()
+ */
+
+/*!
+ \fn int QRhiTexture::arrayRangeLength() const
+
+ \return the exposed array range size when setArrayRange() was called.
+
+ \sa setArrayRange()
+*/
+
+/*!
+ \fn void QRhiTexture::setArrayRange(int startIndex, int count)
+
+ Normally all array layers are exposed and it is up to the shader to select
+ the layer via the third coordinate passed to the \c{texture()} GLSL
+ function when sampling the \c sampler2DArray. When QRhi::TextureArrayRange
+ is reported as supported, calling setArrayRange() before create() or
+ createFrom() requests selecting only the specified range, \a count elements
+ starting from \a startIndex. The shader logic can then be written with this
+ in mind.
+
+ \sa QRhi::TextureArrayRange
+ */
+
+/*!
+ \fn Flags QRhiTexture::flags() const
+ \return the texture flags.
+ */
+
+/*!
+ \fn void QRhiTexture::setFlags(Flags f)
+ Sets the texture flags to \a f.
+ */
+
+/*!
+ \fn int QRhiTexture::sampleCount() const
+ \return the sample count. 1 means no multisample antialiasing.
+ */
+
+/*!
+ \fn void QRhiTexture::setSampleCount(int s)
+ Sets the sample count to \a s.
+ */
+
+/*!
+ \struct QRhiTexture::ViewFormat
+ \inmodule QtGui
+ \since 6.8
+ \brief Specifies the view format for reading or writing from or to the texture.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+ */
+
+/*!
+ \variable QRhiTexture::ViewFormat::format
+ */
+
+/*!
+ \variable QRhiTexture::ViewFormat::srgb
+ */
+
+/*!
+ \fn QRhiTexture::ViewFormat QRhiTexture::readViewFormat() const
+ \since 6.8
+ \return the view format used when sampling the texture. When not called, the view
+ format is assumed to be the same as format().
+ */
+
+/*!
+ \fn void QRhiTexture::setReadViewFormat(const ViewFormat &fmt)
+ \since 6.8
+
+ Sets the shader resource view format (or the format of the view used for
+ sampling the texture) to \a fmt. By default the same format (and sRGB-ness)
+ is used as the texture itself, and in most cases this function does not need
+ to be called.
+
+ This setting is only taken into account when the \l TextureViewFormat
+ feature is reported as supported.
+
+ \note This functionality is provided to allow "casting" between
+ non-sRGB and sRGB in order to get the shader reads perform, or not perform,
+ the implicit sRGB conversions. Other types of casting may or may not be
+ functional.
+ */
+
+/*!
+ \fn QRhiTexture::ViewFormat QRhiTexture::writeViewFormat() const
+ \since 6.8
+ \return the view format used when writing to the texture and when using it
+ with image load/store. When not called, the view format is assumed to be the
+ same as format().
+ */
+
+/*!
+ \fn void QRhiTexture::setWriteViewFormat(const ViewFormat &fmt)
+ \since 6.8
+
+ Sets the render target view format to \a fmt. By default the same format
+ (and sRGB-ness) is used as the texture itself, and in most cases this
+ function does not need to be called.
+
+ One common use case for providing a write view format is working with
+ externally provided textures that, outside of our control, use an sRGB
+ format with 3D APIs such as Vulkan or Direct 3D, but the rendering engine is
+ already prepared to handle linearization and conversion to sRGB at the end
+ of its shading pipeline. In this case what is wanted when rendering into
+ such a texture is a render target view (e.g. VkImageView) that has the same,
+ but non-sRGB format. (if e.g. from an OpenXR implementation one gets a
+ VK_FORMAT_R8G8B8A8_SRGB texture, it is likely that rendering into it should
+ be done using a VK_FORMAT_R8G8B8A8_UNORM view, if that is what the rendering
+ engine's pipeline requires; in this example one would call this function
+ with a ViewFormat that has a format of QRhiTexture::RGBA8 and \c srgb set to
+ \c false).
+
+ This setting is only taken into account when the \l TextureViewFormat
+ feature is reported as supported.
+
+ \note This functionality is provided to allow "casting" between
+ non-sRGB and sRGB in order to get the shader write not perform, or perform,
+ the implicit sRGB conversions. Other types of casting may or may not be
+ functional.
+ */
+
+/*!
\class QRhiSampler
- \internal
\inmodule QtGui
+ \since 6.6
\brief Sampler resource.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
@@ -2871,14 +4765,91 @@ QRhiResource::Type QRhiSampler::resourceType() const
}
/*!
+ \fn QRhiSampler::Filter QRhiSampler::magFilter() const
+ \return the magnification filter mode.
+ */
+
+/*!
+ \fn void QRhiSampler::setMagFilter(Filter f)
+ Sets the magnification filter mode to \a f.
+ */
+
+/*!
+ \fn QRhiSampler::Filter QRhiSampler::minFilter() const
+ \return the minification filter mode.
+ */
+
+/*!
+ \fn void QRhiSampler::setMinFilter(Filter f)
+ Sets the minification filter mode to \a f.
+ */
+
+/*!
+ \fn QRhiSampler::Filter QRhiSampler::mipmapMode() const
+ \return the mipmap filter mode.
+ */
+
+/*!
+ \fn void QRhiSampler::setMipmapMode(Filter f)
+
+ Sets the mipmap filter mode to \a f.
+
+ Leave this set to None when the texture has no mip levels, or when the mip
+ levels are not to be taken into account.
+ */
+
+/*!
+ \fn QRhiSampler::AddressMode QRhiSampler::addressU() const
+ \return the horizontal wrap mode.
+ */
+
+/*!
+ \fn void QRhiSampler::setAddressU(AddressMode mode)
+ Sets the horizontal wrap \a mode.
+ */
+
+/*!
+ \fn QRhiSampler::AddressMode QRhiSampler::addressV() const
+ \return the vertical wrap mode.
+ */
+
+/*!
+ \fn void QRhiSampler::setAddressV(AddressMode mode)
+ Sets the vertical wrap \a mode.
+ */
+
+/*!
+ \fn QRhiSampler::AddressMode QRhiSampler::addressW() const
+ \return the depth wrap mode.
+ */
+
+/*!
+ \fn void QRhiSampler::setAddressW(AddressMode mode)
+ Sets the depth wrap \a mode.
+ */
+
+/*!
+ \fn QRhiSampler::CompareOp QRhiSampler::textureCompareOp() const
+ \return the texture comparison function.
+ */
+
+/*!
+ \fn void QRhiSampler::setTextureCompareOp(CompareOp op)
+ Sets the texture comparison function \a op.
+ */
+
+/*!
\class QRhiRenderPassDescriptor
- \internal
\inmodule QtGui
+ \since 6.6
\brief Render pass resource.
A render pass, if such a concept exists in the underlying graphics API, is
a collection of attachments (color, depth, stencil) and describes how those
attachments are used.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
@@ -2898,7 +4869,7 @@ QRhiResource::Type QRhiRenderPassDescriptor::resourceType() const
}
/*!
- \fn bool QRhiRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const
+ \fn virtual bool QRhiRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const = 0
\return true if the \a other QRhiRenderPassDescriptor is compatible with
this one, meaning \c this and \a other can be used interchangebly in
@@ -2933,7 +4904,7 @@ QRhiResource::Type QRhiRenderPassDescriptor::resourceType() const
*/
/*!
- \fn QRhiRenderPassDescriptor *QRhiRenderPassDescriptor::newCompatibleRenderPassDescriptor() const
+ \fn virtual QRhiRenderPassDescriptor *QRhiRenderPassDescriptor::newCompatibleRenderPassDescriptor() const = 0
\return a new QRhiRenderPassDescriptor that is
\l{isCompatible()}{compatible} with this one.
@@ -2954,7 +4925,7 @@ QRhiResource::Type QRhiRenderPassDescriptor::resourceType() const
*/
/*!
- \fn QVector<quint32> QRhiRenderPassDescriptor::serializedFormat() const
+ \fn virtual QVector<quint32> QRhiRenderPassDescriptor::serializedFormat() const = 0
\return a vector of integers containing an opaque blob describing the data
relevant for \l{isCompatible()}{compatibility}.
@@ -2985,10 +4956,20 @@ const QRhiNativeHandles *QRhiRenderPassDescriptor::nativeHandles()
/*!
\class QRhiRenderTarget
- \internal
\inmodule QtGui
+ \since 6.6
\brief Represents an onscreen (swapchain) or offscreen (texture) render target.
+ Applications do not create an instance of this class directly. Rather, it
+ is the subclass QRhiTextureRenderTarget that is instantiable by clients of
+ the API via \l{QRhi::newTextureRenderTarget()}{newTextureRenderTarget()}.
+ The other subclass is QRhiSwapChainRenderTarget, which is the type
+ QRhiSwapChain returns when calling
+ \l{QRhiSwapChain::currentFrameRenderTarget()}{currentFrameRenderTarget()}.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
\sa QRhiSwapChainRenderTarget, QRhiTextureRenderTarget
*/
@@ -3001,7 +4982,7 @@ QRhiRenderTarget::QRhiRenderTarget(QRhiImplementation *rhi)
}
/*!
- \fn QSize QRhiRenderTarget::pixelSize() const
+ \fn virtual QSize QRhiRenderTarget::pixelSize() const = 0
\return the size in pixels.
@@ -3019,7 +5000,7 @@ QRhiRenderTarget::QRhiRenderTarget(QRhiImplementation *rhi)
*/
/*!
- \fn float QRhiRenderTarget::devicePixelRatio() const
+ \fn virtual float QRhiRenderTarget::devicePixelRatio() const = 0
\return the device pixel ratio. For QRhiTextureRenderTarget this is always
1. For targets retrieved from a QRhiSwapChain the value reflects the
@@ -3028,6 +5009,25 @@ QRhiRenderTarget::QRhiRenderTarget(QRhiImplementation *rhi)
*/
/*!
+ \fn virtual int QRhiRenderTarget::sampleCount() const = 0
+
+ \return the sample count or 1 if multisample antialiasing is not relevant for
+ this render target.
+ */
+
+/*!
+ \fn QRhiRenderPassDescriptor *QRhiRenderTarget::renderPassDescriptor() const
+
+ \return the associated QRhiRenderPassDescriptor.
+ */
+
+/*!
+ \fn void QRhiRenderTarget::setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
+
+ Sets the QRhiRenderPassDescriptor \a desc for use with this render target.
+ */
+
+/*!
\internal
*/
QRhiSwapChainRenderTarget::QRhiSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain_)
@@ -3038,14 +5038,17 @@ QRhiSwapChainRenderTarget::QRhiSwapChainRenderTarget(QRhiImplementation *rhi, QR
/*!
\class QRhiSwapChainRenderTarget
- \internal
\inmodule QtGui
+ \since 6.6
\brief Swapchain render target resource.
When targeting the color buffers of a swapchain, active render target is a
QRhiSwapChainRenderTarget. This is what
QRhiSwapChain::currentFrameRenderTarget() returns.
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
\sa QRhiSwapChain
*/
@@ -3065,8 +5068,8 @@ QRhiResource::Type QRhiSwapChainRenderTarget::resourceType() const
/*!
\class QRhiTextureRenderTarget
- \internal
\inmodule QtGui
+ \since 6.6
\brief Texture render target resource.
A texture render target allows rendering into one or more textures,
@@ -3082,15 +5085,18 @@ QRhiResource::Type QRhiSwapChainRenderTarget::resourceType() const
The simplest example of creating a render target with a texture as its
single color attachment:
- \badcode
- texture = rhi->newTexture(QRhiTexture::RGBA8, size, 1, QRhiTexture::RenderTarget);
+ \code
+ QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, size, 1, QRhiTexture::RenderTarget);
texture->create();
- rt = rhi->newTextureRenderTarget({ texture });
+ QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ texture });
rp = rt->newCompatibleRenderPassDescriptor();
rt->setRenderPassDescriptor(rt);
rt->create();
// rt can now be used with beginPass()
\endcode
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
@@ -3105,7 +5111,19 @@ QRhiResource::Type QRhiSwapChainRenderTarget::resourceType() const
\value PreserveColorContents Indicates that the contents of the color
attachments is to be loaded when starting a render pass, instead of
clearing. This is potentially more expensive, especially on mobile (tiled)
- GPUs, but allows preserving the existing contents between passes.
+ GPUs, but allows preserving the existing contents between passes. When doing
+ multisample rendering with a resolve texture set, setting this flag also
+ requests the multisample color data to be stored (written out) to the
+ multisample texture or render buffer. (for non-multisample rendering the
+ color data is always stored, but for MSAA storing the multisample data
+ decreases efficiency for certain GPU architectures, hence defaulting to not
+ writing it out) Note however that this is non-portable: in some cases there
+ is no intermediate multisample texture on the graphics API level, e.g. when
+ using OpenGL ES's \c{GL_EXT_multisampled_render_to_texture} as it is all
+ implicit, handled by the OpenGL ES implementation. In that case,
+ PreserveColorContents will likely have no effect. Therefore, avoid relying
+ on this flag when using multisample rendering and the color attachment is
+ using a multisample QRhiTexture (not QRhiRenderBuffer).
\value PreserveDepthStencilContents Indicates that the contents of the
depth texture is to be loaded when starting a render pass, instead
@@ -3113,6 +5131,13 @@ QRhiResource::Type QRhiSwapChainRenderTarget::resourceType() const
(QRhiTextureRenderTargetDescription::depthTexture() is set) because
depth/stencil renderbuffers may not have any physical backing and data may
not be written out in the first place.
+
+ \value DoNotStoreDepthStencilContents Indicates that the contents of the
+ depth texture does not need to be written out. Relevant only when a
+ QRhiTexture, not QRhiRenderBuffer, is used as the depth-stencil buffer,
+ because for QRhiRenderBuffer this is implicit. When a depthResolveTexture is
+ set, the flag is not relevant, because the behavior is then as if the flag
+ was set. This enum value is introduced in Qt 6.8.
*/
/*!
@@ -3136,7 +5161,7 @@ QRhiResource::Type QRhiTextureRenderTarget::resourceType() const
}
/*!
- \fn QRhiRenderPassDescriptor *QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor()
+ \fn virtual QRhiRenderPassDescriptor *QRhiTextureRenderTarget::newCompatibleRenderPassDescriptor() = 0
\return a new QRhiRenderPassDescriptor that is compatible with this render
target.
@@ -3146,7 +5171,8 @@ QRhiResource::Type QRhiTextureRenderTarget::resourceType() const
QRhiGraphicsPipeline::setRenderPassDescriptor(). A render pass descriptor
describes the attachments (color, depth/stencil) and the load/store
behavior that can be affected by flags(). A QRhiGraphicsPipeline can only
- be used in combination with a render target that has the same
+ be used in combination with a render target that has a
+ \l{QRhiRenderPassDescriptor::isCompatible()}{compatible}
QRhiRenderPassDescriptor set.
Two QRhiTextureRenderTarget instances can share the same render pass
@@ -3162,7 +5188,7 @@ QRhiResource::Type QRhiTextureRenderTarget::resourceType() const
*/
/*!
- \fn bool QRhiTextureRenderTarget::create()
+ \fn virtual bool QRhiTextureRenderTarget::create() = 0
Creates the corresponding native graphics resources. If there are already
resources present due to an earlier create() with no corresponding
@@ -3186,9 +5212,29 @@ QRhiResource::Type QRhiTextureRenderTarget::resourceType() const
*/
/*!
+ \fn QRhiTextureRenderTargetDescription QRhiTextureRenderTarget::description() const
+ \return the render target description.
+ */
+
+/*!
+ \fn void QRhiTextureRenderTarget::setDescription(const QRhiTextureRenderTargetDescription &desc)
+ Sets the render target description \a desc.
+ */
+
+/*!
+ \fn QRhiTextureRenderTarget::Flags QRhiTextureRenderTarget::flags() const
+ \return the currently set flags.
+ */
+
+/*!
+ \fn void QRhiTextureRenderTarget::setFlags(Flags f)
+ Sets the flags to \a f.
+ */
+
+/*!
\class QRhiShaderResourceBindings
- \internal
\inmodule QtGui
+ \since 6.6
\brief Encapsulates resources for making buffer, texture, sampler resources visible to shaders.
A QRhiShaderResourceBindings is a collection of QRhiShaderResourceBinding
@@ -3209,19 +5255,19 @@ QRhiResource::Type QRhiTextureRenderTarget::resourceType() const
QRhiShaderResourceBindings could be created and then passed to
QRhiGraphicsPipeline::setShaderResourceBindings():
- \badcode
- srb = rhi->newShaderResourceBindings();
+ \code
+ QRhiShaderResourceBindings *srb = rhi->newShaderResourceBindings();
srb->setBindings({
QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, ubuf),
QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, texture, sampler)
});
srb->create();
- ...
- ps = rhi->newGraphicsPipeline();
- ...
+ // ...
+ QRhiGraphicsPipeline *ps = rhi->newGraphicsPipeline();
+ // ...
ps->setShaderResourceBindings(srb);
ps->create();
- ...
+ // ...
cb->setGraphicsPipeline(ps);
cb->setShaderResources(); // binds srb
\endcode
@@ -3240,17 +5286,28 @@ QRhiResource::Type QRhiTextureRenderTarget::resourceType() const
srb argument. As long as the layouts (so the number of bindings and the
binding points) match between two QRhiShaderResourceBindings, they can both
be used with the same pipeline, assuming the pipeline was created with one of
- them in the first place.
+ them in the first place. See isLayoutCompatible() for more details.
- \badcode
- srb2 = rhi->newShaderResourceBindings();
- ...
+ \code
+ QRhiShaderResourceBindings *srb2 = rhi->newShaderResourceBindings();
+ // ...
cb->setGraphicsPipeline(ps);
cb->setShaderResources(srb2); // binds srb2
\endcode
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
+ \typedef QRhiShaderResourceBindingSet
+ \relates QRhi
+ \since 6.7
+
+ Synonym for QRhiShaderResourceBindings.
+*/
+
+/*!
\internal
*/
QRhiShaderResourceBindings::QRhiShaderResourceBindings(QRhiImplementation *rhi)
@@ -3313,7 +5370,7 @@ bool QRhiShaderResourceBindings::isLayoutCompatible(const QRhiShaderResourceBind
\l{isLayoutCompatible()}{layout compatibility tests}.
Given two objects \c srb1 and \c srb2, if the data returned from this
- function is identical, then \c{srb1->isLayoutCompatible(srb2), and vice
+ function is identical, then \c{srb1->isLayoutCompatible(srb2)}, and vice
versa hold true as well.
\note The returned data is meant to be used for storing in memory and
@@ -3338,14 +5395,47 @@ void QRhiImplementation::updateLayoutDesc(QRhiShaderResourceBindings *srb)
}
/*!
+ \fn void QRhiShaderResourceBindings::setBindings(std::initializer_list<QRhiShaderResourceBinding> list)
+ Sets the \a list of bindings.
+ */
+
+/*!
+ \fn template<typename InputIterator> void QRhiShaderResourceBindings::setBindings(InputIterator first, InputIterator last)
+ Sets the list of bindings from the iterators \a first and \a last.
+ */
+
+/*!
+ \fn const QRhiShaderResourceBinding *QRhiShaderResourceBindings::cbeginBindings() const
+ \return a const iterator pointing to the first item in the binding list.
+ */
+
+/*!
+ \fn const QRhiShaderResourceBinding *QRhiShaderResourceBindings::cendBindings() const
+ \return a const iterator pointing just after the last item in the binding list.
+ */
+
+/*!
+ \fn const QRhiShaderResourceBinding *QRhiShaderResourceBindings::bindingAt(qsizetype index) const
+ \return the binding at the specified \a index.
+ */
+
+/*!
+ \fn qsizetype QRhiShaderResourceBindings::bindingCount() const
+ \return the number of bindings.
+ */
+
+/*!
\class QRhiShaderResourceBinding
- \internal
\inmodule QtGui
+ \since 6.6
\brief Describes the shader resource for a single binding point.
A QRhiShaderResourceBinding cannot be constructed directly. Instead, use the
static functions such as uniformBuffer() or sampledTexture() to get an
instance.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
@@ -3402,7 +5492,7 @@ void QRhiImplementation::updateLayoutDesc(QRhiShaderResourceBindings *srb)
For example, \c a and \c b below are not equal, but are compatible layout-wise:
- \badcode
+ \code
auto a = QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, buffer);
auto b = QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, someOtherBuffer, 256);
\endcode
@@ -4276,18 +6366,44 @@ QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb)
/*!
\class QRhiGraphicsPipeline
- \internal
\inmodule QtGui
+ \since 6.6
\brief Graphics pipeline state resource.
+ Represents a graphics pipeline. What exactly this map to in the underlying
+ native graphics API, varies. Where there is a concept of pipeline objects,
+ for example with Vulkan, the QRhi backend will create such an object upon
+ calling create(). Elsewhere, for example with OpenGL, the
+ QRhiGraphicsPipeline may merely collect the various state, and create()'s
+ main task is to set up the corresponding shader program, but deferring
+ looking at any of the requested state to a later point.
+
+ As with all QRhiResource subclasses, the two-phased initialization pattern
+ applies: setting any values via the setters, for example setDepthTest(), is
+ only effective after calling create(). Avoid changing any values once the
+ QRhiGraphicsPipeline has been initialized via create(). To change some
+ state, set the new value and call create() again. However, that will
+ effectively release all underlying native resources and create new ones. As
+ a result, it may be a heavy, expensive operation. Rather, prefer creating
+ multiple pipelines with the different states, and
+ \l{QRhiCommandBuffer::setGraphicsPipeline()}{switch between them} when
+ recording the render pass.
+
\note Setting the shader stages is mandatory. There must be at least one
stage, and there must be a vertex stage.
\note Setting the shader resource bindings is mandatory. The referenced
QRhiShaderResourceBindings must already have create() called on it by the
time create() is called. Associating with a QRhiShaderResourceBindings that
- has no bindings is also valid, as long as no shader in any stage expects
- any resources.
+ has no bindings is also valid, as long as no shader in any stage expects any
+ resources. Using a QRhiShaderResourceBindings object that does not specify
+ any actual resources (i.e., the buffers, textures, etc. for the binding
+ points are set to \nullptr) is valid as well, as long as a
+ \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible}
+ QRhiShaderResourceBindings, that specifies resources for all the bindings,
+ is going to be set via
+ \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()} when
+ recording the render pass.
\note Setting the render pass descriptor is mandatory. To obtain a
QRhiRenderPassDescriptor that can be passed to setRenderPassDescriptor(),
@@ -4300,20 +6416,49 @@ QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb)
render target's color and depth stencil attachments.
\note The depth test, depth write, and stencil test are disabled by
- default.
+ default. The face culling mode defaults to no culling.
\note stencilReadMask() and stencilWriteMask() apply to both faces. They
both default to 0xFF.
- */
-/*!
- \fn void QRhiGraphicsPipeline::setTargetBlends(const QList<TargetBlend> &blends)
+ \section2 Example usage
+
+ All settings of a graphics pipeline have defaults which might be suitable
+ to many applications. Therefore a minimal example of creating a graphics
+ pipeline could be the following. This assumes that the vertex shader takes
+ a single \c{vec3 position} input at the input location 0. With the
+ QRhiShaderResourceBindings and QRhiRenderPassDescriptor objects, plus the
+ QShader collections for the vertex and fragment stages, a pipeline could be
+ created like this:
+
+ \code
+ QRhiShaderResourceBindings *srb;
+ QRhiRenderPassDescriptor *rpDesc;
+ QShader vs, fs;
+ // ...
+
+ QRhiVertexInputLayout inputLayout;
+ inputLayout.setBindings({ { 3 * sizeof(float) } });
+ inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float3, 0 } });
- Sets the blend specification for color attachments. Each element in \a
- blends corresponds to a color attachment of the render target.
+ QRhiGraphicsPipeline *ps = rhi->newGraphicsPipeline();
+ ps->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } });
+ ps->setVertexInputLayout(inputLayout);
+ ps->setShaderResourceBindings(srb);
+ ps->setRenderPassDescriptor(rpDesc);
+ if (!ps->create()) { error(); }
+ \endcode
+
+ The above code creates a pipeline object that uses the defaults for many
+ settings and states. For example, it will use a \l Triangles topology, no
+ backface culling, blending is disabled but color write is enabled for all
+ four channels, depth test/write are disabled, stencil operations are
+ disabled.
- By default no blends are set, which is a shortcut to disabling blending and
- enabling color write for all four channels.
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
+ \sa QRhiCommandBuffer, QRhi
*/
/*!
@@ -4472,21 +6617,85 @@ QDebug operator<<(QDebug dbg, const QRhiShaderResourceBindings &srb)
*/
/*!
- \class QRhiGraphicsPipeline::TargetBlend
- \internal
+ \struct QRhiGraphicsPipeline::TargetBlend
\inmodule QtGui
+ \since 6.6
\brief Describes the blend state for one color attachment.
Defaults to color write enabled, blending disabled. The blend values are
set up for pre-multiplied alpha (One, OneMinusSrcAlpha, One,
- OneMinusSrcAlpha) by default.
+ OneMinusSrcAlpha) by default. This means that to get the alpha blending
+ mode Qt Quick uses, it is enough to set the \c enable flag to true while
+ leaving other values at their defaults.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
- \class QRhiGraphicsPipeline::StencilOpState
- \internal
+ \variable QRhiGraphicsPipeline::TargetBlend::colorWrite
+ */
+
+/*!
+ \variable QRhiGraphicsPipeline::TargetBlend::enable
+ */
+
+/*!
+ \variable QRhiGraphicsPipeline::TargetBlend::srcColor
+ */
+
+/*!
+ \variable QRhiGraphicsPipeline::TargetBlend::dstColor
+ */
+
+/*!
+ \variable QRhiGraphicsPipeline::TargetBlend::opColor
+ */
+
+/*!
+ \variable QRhiGraphicsPipeline::TargetBlend::srcAlpha
+ */
+
+/*!
+ \variable QRhiGraphicsPipeline::TargetBlend::dstAlpha
+ */
+
+/*!
+ \variable QRhiGraphicsPipeline::TargetBlend::opAlpha
+ */
+
+/*!
+ \struct QRhiGraphicsPipeline::StencilOpState
\inmodule QtGui
+ \since 6.6
\brief Describes the stencil operation state.
+
+ The default-constructed StencilOpState has the following set:
+ \list
+ \li failOp - \l Keep
+ \li depthFailOp - \l Keep
+ \li passOp - \l Keep
+ \li compareOp \l Always
+ \endlist
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+ */
+
+/*!
+ \variable QRhiGraphicsPipeline::StencilOpState::failOp
+ */
+
+/*!
+ \variable QRhiGraphicsPipeline::StencilOpState::depthFailOp
+ */
+
+/*!
+ \variable QRhiGraphicsPipeline::StencilOpState::passOp
+ */
+
+/*!
+ \variable QRhiGraphicsPipeline::StencilOpState::compareOp
*/
/*!
@@ -4506,7 +6715,7 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
}
/*!
- \fn bool QRhiGraphicsPipeline::create()
+ \fn virtual bool QRhiGraphicsPipeline::create() = 0
Creates the corresponding native graphics resources. If there are already
resources present due to an earlier create() with no corresponding
@@ -4514,23 +6723,132 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
\return \c true when successful, \c false when a graphics operation failed.
Regardless of the return value, calling destroy() is always safe.
+
+ \note This may be, depending on the underlying graphics API, an expensive
+ operation, especially when shaders get compiled/optimized from source or
+ from an intermediate bytecode format to the GPU's own instruction set.
+ Where applicable, the QRhi backend automatically sets up the relevant
+ non-persistent facilities to accelerate this, for example the Vulkan
+ backend automatically creates a \c VkPipelineCache to improve data reuse
+ during the lifetime of the application.
+
+ \note Drivers may also employ various persistent (disk-based) caching
+ strategies for shader and pipeline data, which is hidden to and is outside
+ of Qt's control. In some cases, depending on the graphics API and the QRhi
+ backend, there are facilities within QRhi for manually managing such a
+ cache, allowing the retrieval of a serializable blob that can then be
+ reloaded in the future runs of the application to ensure faster pipeline
+ creation times. See QRhi::pipelineCacheData() and
+ QRhi::setPipelineCacheData() for details. Note also that when working with
+ a QRhi instance managed by a higher level Qt framework, such as Qt Quick,
+ it is possible that such disk-based caching is taken care of automatically,
+ for example QQuickWindow uses a disk-based pipeline cache by default (which
+ comes in addition to any driver-level caching).
+ */
+
+/*!
+ \fn QRhiGraphicsPipeline::Flags QRhiGraphicsPipeline::flags() const
+ \return the currently set flags.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setFlags(Flags f)
+ Sets the flags \a f.
+ */
+
+/*!
+ \fn QRhiGraphicsPipeline::Topology QRhiGraphicsPipeline::topology() const
+ \return the currently set primitive topology.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setTopology(Topology t)
+ Sets the primitive topology \a t.
+ */
+
+/*!
+ \fn QRhiGraphicsPipeline::CullMode QRhiGraphicsPipeline::cullMode() const
+ \return the currently set face culling mode.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setCullMode(CullMode mode)
+ Sets the specified face culling \a mode.
+ */
+
+/*!
+ \fn QRhiGraphicsPipeline::FrontFace QRhiGraphicsPipeline::frontFace() const
+ \return the currently set front face mode.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setFrontFace(FrontFace f)
+ Sets the front face mode \a f.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setTargetBlends(std::initializer_list<TargetBlend> list)
+
+ Sets the \a list of render target blend settings. This is a list because
+ when multiple render targets are used (i.e., a QRhiTextureRenderTarget with
+ more than one QRhiColorAttachment), there needs to be a TargetBlend
+ structure per render target (color attachment).
+
+ By default there is one default-constructed TargetBlend set.
+
+ \sa QRhi::MaxColorAttachments
+ */
+
+/*!
+ \fn template<typename InputIterator> void QRhiGraphicsPipeline::setTargetBlends(InputIterator first, InputIterator last)
+ Sets the list of render target blend settings from the iterators \a first and \a last.
+ */
+
+/*!
+ \fn const QRhiGraphicsPipeline::TargetBlend *QRhiGraphicsPipeline::cbeginTargetBlends() const
+ \return a const iterator pointing to the first item in the render target blend setting list.
+ */
+
+/*!
+ \fn const QRhiGraphicsPipeline::TargetBlend *QRhiGraphicsPipeline::cendTargetBlends() const
+ \return a const iterator pointing just after the last item in the render target blend setting list.
+ */
+
+/*!
+ \fn const QRhiGraphicsPipeline::TargetBlend *QRhiGraphicsPipeline::targetBlendAt(qsizetype index) const
+ \return the render target blend setting at the specified \a index.
+ */
+
+/*!
+ \fn qsizetype QRhiGraphicsPipeline::targetBlendCount() const
+ \return the number of render target blend settings.
+ */
+
+/*!
+ \fn bool QRhiGraphicsPipeline::hasDepthTest() const
+ \return true if depth testing is enabled.
*/
/*!
\fn void QRhiGraphicsPipeline::setDepthTest(bool enable)
- Enables or disables depth testing. Both depth test and the writing out of
- depth data are disabled by default.
+ Enables or disables depth testing based on \a enable. Both depth test and
+ the writing out of depth data are disabled by default.
\sa setDepthWrite()
*/
/*!
+ \fn bool QRhiGraphicsPipeline::hasDepthWrite() const
+ \return true if depth write is enabled.
+ */
+
+/*!
\fn void QRhiGraphicsPipeline::setDepthWrite(bool enable)
- Controls the writing out of depth data into the depth buffer. By default
- this is disabled. Depth write is typically enabled together with the depth
- test.
+ Controls the writing out of depth data into the depth buffer based on
+ \a enable. By default this is disabled. Depth write is typically enabled
+ together with the depth test.
\note Enabling depth write without having depth testing enabled may not
lead to the desired result, and should be avoided.
@@ -4539,9 +6857,233 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
*/
/*!
+ \fn QRhiGraphicsPipeline::CompareOp QRhiGraphicsPipeline::depthOp() const
+ \return the depth comparison function.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setDepthOp(CompareOp op)
+ Sets the depth comparison function \a op.
+ */
+
+/*!
+ \fn bool QRhiGraphicsPipeline::hasStencilTest() const
+ \return true if stencil testing is enabled.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setStencilTest(bool enable)
+ Enables or disables stencil tests based on \a enable.
+ By default this is disabled.
+ */
+
+/*!
+ \fn QRhiGraphicsPipeline::StencilOpState QRhiGraphicsPipeline::stencilFront() const
+ \return the current stencil test state for front faces.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setStencilFront(const StencilOpState &state)
+ Sets the stencil test \a state for front faces.
+ */
+
+/*!
+ \fn QRhiGraphicsPipeline::StencilOpState QRhiGraphicsPipeline::stencilBack() const
+ \return the current stencil test state for back faces.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setStencilBack(const StencilOpState &state)
+ Sets the stencil test \a state for back faces.
+ */
+
+/*!
+ \fn quint32 QRhiGraphicsPipeline::stencilReadMask() const
+ \return the currrent stencil read mask.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setStencilReadMask(quint32 mask)
+ Sets the stencil read \a mask. The default value is 0xFF.
+ */
+
+/*!
+ \fn quint32 QRhiGraphicsPipeline::stencilWriteMask() const
+ \return the current stencil write mask.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setStencilWriteMask(quint32 mask)
+ Sets the stencil write \a mask. The default value is 0xFF.
+ */
+
+/*!
+ \fn int QRhiGraphicsPipeline::sampleCount() const
+ \return the currently set sample count. 1 means no multisample antialiasing.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setSampleCount(int s)
+
+ Sets the sample count. Typical values for \a s are 1, 4, or 8. The pipeline
+ must always be compatible with the render target, i.e. the sample counts
+ must match.
+
+ \sa QRhi::supportedSampleCounts()
+ */
+
+/*!
+ \fn float QRhiGraphicsPipeline::lineWidth() const
+ \return the currently set line width. The default is 1.0f.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setLineWidth(float width)
+
+ Sets the line \a width. If the QRhi::WideLines feature is reported as
+ unsupported at runtime, values other than 1.0f are ignored.
+ */
+
+/*!
+ \fn int QRhiGraphicsPipeline::depthBias() const
+ \return the currently set depth bias.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setDepthBias(int bias)
+ Sets the depth \a bias. The default value is 0.
+ */
+
+/*!
+ \fn float QRhiGraphicsPipeline::slopeScaledDepthBias() const
+ \return the currently set slope scaled depth bias.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setSlopeScaledDepthBias(float bias)
+ Sets the slope scaled depth \a bias. The default value is 0.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setShaderStages(std::initializer_list<QRhiShaderStage> list)
+ Sets the \a list of shader stages.
+ */
+
+/*!
+ \fn template<typename InputIterator> void QRhiGraphicsPipeline::setShaderStages(InputIterator first, InputIterator last)
+ Sets the list of shader stages from the iterators \a first and \a last.
+ */
+
+/*!
+ \fn const QRhiShaderStage *QRhiGraphicsPipeline::cbeginShaderStages() const
+ \return a const iterator pointing to the first item in the shader stage list.
+ */
+
+/*!
+ \fn const QRhiShaderStage *QRhiGraphicsPipeline::cendShaderStages() const
+ \return a const iterator pointing just after the last item in the shader stage list.
+ */
+
+/*!
+ \fn const QRhiShaderStage *QRhiGraphicsPipeline::shaderStageAt(qsizetype index) const
+ \return the shader stage at the specified \a index.
+ */
+
+/*!
+ \fn qsizetype QRhiGraphicsPipeline::shaderStageCount() const
+ \return the number of shader stages in this pipeline.
+ */
+
+/*!
+ \fn QRhiVertexInputLayout QRhiGraphicsPipeline::vertexInputLayout() const
+ \return the currently set vertex input layout specification.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setVertexInputLayout(const QRhiVertexInputLayout &layout)
+ Specifies the vertex input \a layout.
+ */
+
+/*!
+ \fn QRhiShaderResourceBindings *QRhiGraphicsPipeline::shaderResourceBindings() const
+ \return the currently associated QRhiShaderResourceBindings object.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setShaderResourceBindings(QRhiShaderResourceBindings *srb)
+
+ Associates with \a srb describing the resource binding layout and the
+ resources (QRhiBuffer, QRhiTexture) themselves. The latter is optional,
+ because only the layout matters during pipeline creation. Therefore, the \a
+ srb passed in here can leave the actual buffer or texture objects
+ unspecified (\nullptr) as long as there is another,
+ \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible}
+ QRhiShaderResourceBindings bound via
+ \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()} before
+ recording the draw calls.
+ */
+
+/*!
+ \fn QRhiRenderPassDescriptor *QRhiGraphicsPipeline::renderPassDescriptor() const
+ \return the currently set QRhiRenderPassDescriptor.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
+ Associates with the specified QRhiRenderPassDescriptor \a desc.
+ */
+
+/*!
+ \fn int QRhiGraphicsPipeline::patchControlPointCount() const
+ \return the currently set patch control point count.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setPatchControlPointCount(int count)
+
+ Sets the number of patch control points to \a count. The default value is
+ 3. This is used only when the topology is set to \l Patches.
+ */
+
+/*!
+ \fn QRhiGraphicsPipeline::PolygonMode QRhiGraphicsPipeline::polygonMode() const
+ \return the polygon mode.
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setPolygonMode(PolygonMode mode)
+ Sets the polygon \a mode. The default is Fill.
+
+ \sa QRhi::NonFillPolygonMode
+ */
+
+/*!
+ \fn int QRhiGraphicsPipeline::multiViewCount() const
+ \return the view count. The default is 0, indicating no multiview rendering.
+ \since 6.7
+ */
+
+/*!
+ \fn void QRhiGraphicsPipeline::setMultiViewCount(int count)
+ Sets the view \a count for multiview rendering. The default is 0,
+ indicating no multiview rendering.
+ \a count must be 2 or larger to trigger multiview rendering.
+
+ Multiview is only available when the \l{QRhi::MultiView}{MultiView feature}
+ is reported as supported. The render target must be a 2D texture array, and
+ the color attachment for the render target must have the same \a count set.
+
+ See QRhiColorAttachment::setMultiViewCount() for further details on
+ multiview rendering.
+
+ \since 6.7
+ \sa QRhi::MultiView, QRhiColorAttachment::setMultiViewCount()
+ */
+
+/*!
\class QRhiSwapChain
- \internal
\inmodule QtGui
+ \since 6.6
\brief Swapchain resource.
A swapchain enables presenting rendering results to a surface. A swapchain
@@ -4551,7 +7093,7 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
Below is a typical pattern for creating and managing a swapchain and some
associated resources in order to render onto a QWindow:
- \badcode
+ \code
void init()
{
sc = rhi->newSwapChain();
@@ -4597,7 +7139,7 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
Releasing the swapchain must happen while the QWindow and the underlying
native window is fully up and running. Building on the previous example:
- \badcode
+ \code
void releaseSwapChain()
{
if (hasSwapChain) {
@@ -4629,7 +7171,7 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
events. QExposeEvent is a loosely specified event that is sent whenever a
window gets mapped, obscured, and resized, depending on the platform.
- \badcode
+ \code
void Window::exposeEvent(QExposeEvent *)
{
// initialize and start rendering when the window becomes usable for graphics purposes
@@ -4675,6 +7217,9 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
command at the end of a frame. For OpenGL, it is necessary to request the
appropriate sample count also via QSurfaceFormat, by calling
QSurfaceFormat::setDefaultFormat() before initializing the QRhi.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
@@ -4733,6 +7278,14 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
\enum QRhiSwapChain::Format
Describes the swapchain format. The default format is SDR.
+ This enum is used with
+ \l{QRhiSwapChain::isFormatSupported()}{isFormatSupported()} to check
+ upfront if creating the swapchain with the given format is supported by the
+ platform and the window's associated screen, and with
+ \l{QRhiSwapChain::setFormat()}{setFormat()}
+ to set the requested format in the swapchain before calling
+ \l{QRhiSwapChain::createOrResize()}{createOrResize()} for the first time.
+
\value SDR 8-bit RGBA or BGRA, depending on the backend and platform. With
OpenGL ES in particular, it could happen that the platform provides less
than 8 bits (e.g. due to EGL and the QSurfaceFormat choosing a 565 or 444
@@ -4744,10 +7297,14 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const
(same as SDR/sRGB) and linear colors. Conversion to the display's native
color space (such as, HDR10) is performed by the windowing system. On
Windows this is the canonical color space of the system compositor, and is
- the recommended format for HDR swapchains in general.
+ the recommended format for HDR swapchains in general on desktop platforms.
\value HDR10 10-bit unsigned int RGB or BGR with 2 bit alpha, high dynamic
range, HDR10 (Rec. 2020) color space with an ST2084 PQ transfer function.
+
+ \value HDRExtendedDisplayP3Linear 16-bit float RGBA, high dynamic range,
+ extended linear Display P3 color space. The primary choice for HDR on
+ platforms such as iOS and VisionOS.
*/
/*!
@@ -4793,7 +7350,7 @@ QRhiResource::Type QRhiSwapChain::resourceType() const
*/
/*!
- \fn QSize QRhiSwapChain::surfacePixelSize()
+ \fn virtual QSize QRhiSwapChain::surfacePixelSize() = 0
\return The size of the window's associated surface or layer.
@@ -4801,13 +7358,13 @@ QRhiResource::Type QRhiSwapChain::resourceType() const
QWindow::devicePixelRatio()}. With some graphics APIs and windowing system
interfaces (for example, Vulkan) there is a theoretical possibility for a
surface to assume a size different from the associated window. To support
- these cases, rendering logic must always base size-derived calculations
+ these cases, \b{rendering logic must always base size-derived calculations
(such as, viewports) on the size reported from QRhiSwapChain, and never on
- the size queried from QWindow.
+ the size queried from QWindow}.
- \note Can also be called before createOrResize(), if at least window() is
- already set) This in combination with currentPixelSize() allows to detect
- when a swapchain needs to be resized. However, watch out for the fact that
+ \note \b{Can also be called before createOrResize(), if at least window() is
+ already set. This in combination with currentPixelSize() allows to detect
+ when a swapchain needs to be resized.} However, watch out for the fact that
the size of the underlying native object (surface, layer, or similar) is
"live", so whenever this function is called, it returns the latest value
reported by the underlying implementation, without any atomicity guarantee.
@@ -4828,9 +7385,9 @@ QRhiResource::Type QRhiSwapChain::resourceType() const
*/
/*!
- \fn bool QRhiSwapChain::isFormatSuported(Format f)
+ \fn virtual bool QRhiSwapChain::isFormatSupported(Format f) = 0
- \return true if the given swapchain format is supported. SDR is always
+ \return true if the given swapchain format \a f is supported. SDR is always
supported.
\note Can be called independently of createOrResize(), but window() must
@@ -4841,20 +7398,45 @@ QRhiResource::Type QRhiSwapChain::resourceType() const
time. If the result is true for a HDR format, then creating the swapchain
with that format is expected to succeed as long as the window is not moved
to another screen in the meantime.
+
+ The main use of this function is to call it before the first
+ createOrResize() after the window is already set. This allow the QRhi
+ backends to perform platform or windowing system specific queries to
+ determine if the window (and the screen it is on) is capable of true HDR
+ output with the specified format.
+
+ When the format is reported as supported, call setFormat() to set the
+ requested format and call createOrResize(). Be aware of the consequences
+ however: successfully requesting a HDR format will involve having to deal
+ with a different color space, possibly doing white level correction for
+ non-HDR-aware content, adjusting tonemapping methods, adjusting offscreen
+ render target settings, etc.
+
+ \sa setFormat()
*/
/*!
- \fn QRhiCommandBuffer *QRhiSwapChain::currentFrameCommandBuffer()
+ \fn virtual QRhiCommandBuffer *QRhiSwapChain::currentFrameCommandBuffer() = 0
- \return a command buffer on which rendering commands can be recorded. Only
- valid within a QRhi::beginFrame() - QRhi::endFrame() block where
- beginFrame() was called with this swapchain.
+ \return a command buffer on which rendering commands and resource updates
+ can be recorded within a \l{QRhi::beginFrame()}{beginFrame} -
+ \l{QRhi::endFrame()}{endFrame} block, assuming beginFrame() was called with
+ this swapchain.
- \note the value must not be cached and reused between frames
+ \note The returned object is valid also after endFrame(), up until the next
+ beginFrame(), but the returned command buffer should not be used to record
+ any commands then. Rather, it can be used to query data collected during
+ the frame (or previous frames), for example by calling
+ \l{QRhiCommandBuffer::lastCompletedGpuTime()}{lastCompletedGpuTime()}.
+
+ \note The value must not be cached and reused between frames. The caller
+ should not hold on to the returned object once
+ \l{QRhi::beginFrame()}{beginFrame()} is called again. Instead, the command
+ buffer object should be queried again by calling this function.
*/
/*!
- \fn QRhiRenderTarget *QRhiSwapChain::currentFrameRenderTarget()
+ \fn virtual QRhiRenderTarget *QRhiSwapChain::currentFrameRenderTarget() = 0
\return a render target that can used with beginPass() in order to render
the swapchain's current backbuffer. Only valid within a
@@ -4879,10 +7461,9 @@ QRhiResource::Type QRhiSwapChain::resourceType() const
is backed by two color buffers, one for each eye, instead of just one.
When stereoscopic rendering is not supported, the return value will be
- the default target. For the time being the only backend and 3D API where traditional
- stereoscopic rendering is supported is OpenGL (excluding OpenGL ES), in
+ the default target. It is supported by all hardware backends except for Metal, in
combination with \l QSurfaceFormat::StereoBuffers, assuming it is supported
- by the graphics and display driver stack at run time. All other backends
+ by the graphics and display driver stack at run time. Metal and Null backends
are going to return the default render target from this overload.
\note the value must not be cached and reused between frames
@@ -4894,7 +7475,7 @@ QRhiRenderTarget *QRhiSwapChain::currentFrameRenderTarget(StereoTargetBuffer tar
}
/*!
- \fn bool QRhiSwapChain::createOrResize()
+ \fn virtual bool QRhiSwapChain::createOrResize() = 0
Creates the swapchain if not already done and resizes the swapchain buffers
to match the current size of the targeted surface. Call this whenever the
@@ -4910,18 +7491,121 @@ QRhiRenderTarget *QRhiSwapChain::currentFrameRenderTarget(StereoTargetBuffer tar
*/
/*!
+ \fn QWindow *QRhiSwapChain::window() const
+ \return the currently set window.
+ */
+
+/*!
+ \fn void QRhiSwapChain::setWindow(QWindow *window)
+ Sets the \a window.
+ */
+
+/*!
+ \fn QRhiSwapChainProxyData QRhiSwapChain::proxyData() const
+ \return the currently set proxy data.
+ */
+
+/*!
+ \fn void QRhiSwapChain::setProxyData(const QRhiSwapChainProxyData &d)
+ Sets the proxy data \a d.
+
+ \sa QRhi::updateSwapChainProxyData()
+ */
+
+/*!
+ \fn QRhiSwapChain::Flags QRhiSwapChain::flags() const
+ \return the currently set flags.
+ */
+
+/*!
+ \fn void QRhiSwapChain::setFlags(Flags f)
+ Sets the flags \a f.
+ */
+
+/*!
+ \fn QRhiSwapChain::Format QRhiSwapChain::format() const
+ \return the currently set format.
+ */
+
+/*!
+ \fn void QRhiSwapChain::setFormat(Format f)
+ Sets the format \a f.
+
+ Avoid setting formats that are reported as unsupported from
+ isFormatSupported(). Note that support for a given format may depend on the
+ screen the swapchain's associated window is opened on. On some platforms,
+ such as Windows and macOS, for HDR output to work it is necessary to have
+ HDR output enabled in the display settings.
+
+ See isFormatSupported(), \l QRhiSwapChainHdrInfo, and \l Format for more
+ information on high dynamic range output.
+ */
+
+/*!
+ \fn QRhiRenderBuffer *QRhiSwapChain::depthStencil() const
+ \return the currently associated renderbuffer for depth-stencil.
+ */
+
+/*!
+ \fn void QRhiSwapChain::setDepthStencil(QRhiRenderBuffer *ds)
+ Sets the renderbuffer \a ds for use as a depth-stencil buffer.
+ */
+
+/*!
+ \fn int QRhiSwapChain::sampleCount() const
+ \return the currently set sample count. 1 means no multisample antialiasing.
+ */
+
+/*!
+ \fn void QRhiSwapChain::setSampleCount(int samples)
+
+ Sets the sample count. Common values for \a samples are 1 (no MSAA), 4 (4x
+ MSAA), or 8 (8x MSAA).
+
+ \sa QRhi::supportedSampleCounts()
+ */
+
+/*!
+ \fn QRhiRenderPassDescriptor *QRhiSwapChain::renderPassDescriptor() const
+ \return the currently associated QRhiRenderPassDescriptor object.
+ */
+
+/*!
+ \fn void QRhiSwapChain::setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
+ Associates with the QRhiRenderPassDescriptor \a desc.
+ */
+
+/*!
+ \fn virtual QRhiRenderPassDescriptor *QRhiSwapChain::newCompatibleRenderPassDescriptor() = 0;
+
+ \return a new QRhiRenderPassDescriptor that is compatible with this swapchain.
+
+ The returned value is used in two ways: it can be passed to
+ setRenderPassDescriptor() and
+ QRhiGraphicsPipeline::setRenderPassDescriptor(). A render pass descriptor
+ describes the attachments (color, depth/stencil) and the load/store
+ behavior that can be affected by flags(). A QRhiGraphicsPipeline can only
+ be used in combination with a swapchain that has a
+ \l{QRhiRenderPassDescriptor::isCompatible()}{compatible}
+ QRhiRenderPassDescriptor set.
+
+ \sa createOrResize()
+ */
+
+/*!
\struct QRhiSwapChainHdrInfo
- \internal
\inmodule QtGui
+ \since 6.6
\brief Describes the high dynamic range related information of the
swapchain's associated output.
- To perform tonemapping, one often needs to know the maximum luminance of
- the display the swapchain's window is associated with. While this is often
- made user-configurable, it can be highly useful to set defaults based on
- the values reported by the display itself, thus providing a decent starting
- point.
+ To perform HDR-compatible tonemapping, where the target range is not [0,1],
+ one often needs to know the maximum luminance of the display the
+ swapchain's window is associated with. While this is often made
+ user-configurable (think brightness, gamma and similar settings in games),
+ it can be highly useful to set defaults based on the values reported by the
+ display itself, thus providing a decent starting point.
There are some problems however: the information is exposed in different
forms on different platforms, whereas with cross-platform graphics APIs
@@ -4929,11 +7613,6 @@ QRhiRenderTarget *QRhiSwapChain::currentFrameRenderTarget(StereoTargetBuffer tar
information is not in the scope of the API (and may rather be retrievable
via other platform-specific means, if any).
- The struct returned from QRhiSwapChain::hdrInfo() contains either some
- hard-coded defaults, indicated by the \c isHardCodedDefaults field, or real
- values received from an API such as DXGI (IDXGIOutput6) or Cocoa
- (NSScreen). The default is 1000 nits for maximum luminance.
-
With Metal on macOS/iOS, there is no luminance values exposed in the
platform APIs. Instead, the maximum color component value, that would be
1.0 in a non-HDR setup, is provided. The \c limitsType field indicates what
@@ -4942,17 +7621,168 @@ QRhiRenderTarget *QRhiSwapChain::currentFrameRenderTarget(StereoTargetBuffer tar
fit.
With an API like Vulkan, where there is no way to get such information, the
- values are always the built-in defaults and \c isHardCodedDefaults is
- always true.
+ values are always the built-in defaults.
+
+ Therefore, the struct returned from QRhiSwapChain::hdrInfo() contains
+ either some hard-coded defaults or real values received from an API such as
+ DXGI (IDXGIOutput6) or Cocoa (NSScreen). When no platform queries are
+ available (or needs using platform facilities out of scope for QRhi), the
+ hard-coded defaults are a maximum luminance of 1000 nits and an SDR white
+ level of 200.
+
+ The struct also exposes the presumed luminance behavior of the platform and
+ its compositor, to indicate what a color component value of 1.0 is treated
+ as in a HDR color buffer. In some cases it will be necessary to perform
+ color correction of non-HDR content composited with HDR content. To enable
+ this, the SDR white level is queried from the system on some platforms
+ (Windows) and exposed here.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
\sa QRhiSwapChain::hdrInfo()
*/
/*!
+ \enum QRhiSwapChainHdrInfo::LimitsType
+
+ \value LuminanceInNits Indicates that the \l limits union has its
+ \c luminanceInNits struct set
+
+ \value ColorComponentValue Indicates that the \l limits union has its
+ \c colorComponentValue struct set
+*/
+
+/*!
+ \enum QRhiSwapChainHdrInfo::LuminanceBehavior
+
+ \value SceneReferred Indicates that the color value of 1.0 is interpreted
+ as 80 nits. This is the behavior of HDR-enabled windows with the Windows
+ compositor. See
+ \l{https://learn.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range}{this
+ page} for more information on HDR on Windows.
+
+ \value DisplayReferred Indicates that the color value of 1.0 is interpreted
+ as the value of the SDR white. (which can be e.g. 200 nits, but will vary
+ depending on screen brightness) This is the behavior of HDR-enabled windows
+ on Apple platforms. See
+ \l{https://developer.apple.com/documentation/metal/hdr_content/displaying_hdr_content_in_a_metal_layer}{this
+ page} for more information on Apple's EDR system.
+*/
+
+/*!
+ \variable QRhiSwapChainHdrInfo::limitsType
+
+ With Metal on macOS/iOS, there is no luminance values exposed in the
+ platform APIs. Instead, the maximum color component value, that would be
+ 1.0 in a non-HDR setup, is provided. This value indicates what kind of
+ information is available in \l limits.
+
+ \sa QRhiSwapChain::hdrInfo()
+*/
+
+/*!
+ \variable QRhiSwapChainHdrInfo::limits
+
+ Contains the actual values queried from the graphics API or the platform.
+ The type of data is indicated by \l limitsType. This is therefore a union.
+ There are currently two options:
+
+ Luminance values in nits:
+
+ \code
+ struct {
+ float minLuminance;
+ float maxLuminance;
+ } luminanceInNits;
+ \endcode
+
+ On Windows the minimum and maximum luminance depends on the screen
+ brightness. While not relevant for desktops, on laptops the screen
+ brightness may change at any time. Increasing brightness implies decreased
+ maximum luminance. In addition, the results may also be dependent on the
+ HDR Content Brightness set in Windows Settings' System/Display/HDR view,
+ if there is such a setting.
+
+ Note however that the changes made to the laptop screen's brightness or in
+ the system settings while the application is running are not necessarily
+ reflected in the returned values, meaning calling hdrInfo() again may still
+ return the same luminance range as before for the rest of the process'
+ lifetime. The exact behavior is up to DXGI and Qt has no control over it.
+
+ \note The Windows compositor works in scene-referred mode for HDR content.
+ A color component value of 1.0 corresponds to a luminance of 80 nits. When
+ rendering non-HDR content (e.g. 2D UI elements), the correction of the
+ white level is often necessary. (e.g., outputting the fragment color (1, 1,
+ 1) will likely lead to showing a shade of white that is too dim on-screen)
+ See \l sdrWhiteLevel.
+
+ For macOS/iOS, the current maximum and potential maximum color
+ component values are provided:
+
+ \code
+ struct {
+ float maxColorComponentValue;
+ float maxPotentialColorComponentValue;
+ } colorComponentValue;
+ \endcode
+
+ The value may depend on the screen brightness, which on laptops means that
+ the result may change in the next call to hdrInfo() if the brightness was
+ changed in the meantime. The maximum screen brightness implies a maximum
+ color value of 1.0.
+
+ \note Apple's EDR is display-referred. 1.0 corresponds to a luminance level
+ of SDR white (e.g. 200 nits), the value of which varies based on the screen
+ brightness and possibly other settings. The exact luminance value for that,
+ or the maximum luminance of the display, are not exposed to the
+ applications.
+
+ \note It has been observed that the color component values are not set to
+ the correct larger-than-1 value right away on startup on some macOS
+ systems, but the values tend to change during or after the first frame.
+
+ \sa QRhiSwapChain::hdrInfo()
+*/
+
+/*!
+ \variable QRhiSwapChainHdrInfo::luminanceBehavior
+
+ Describes the platform's presumed behavior with regards to color values.
+
+ \sa sdrWhiteLevel
+ */
+
+/*!
+ \variable QRhiSwapChainHdrInfo::sdrWhiteLevel
+
+ On Windows this is the dynamic SDR white level in nits. The value is
+ dependent on the screen brightness (on laptops), and the SDR or HDR Content
+ Brightness settings in the Windows settings' System/Display/HDR view.
+
+ To perform white level correction for non-HDR (SDR) content, such as 2D UI
+ elemenents, multiply the final color with sdrWhiteLevel / 80.0 whenever
+ \l luminanceBehavior is SceneReferred. (assuming Windows and a linear
+ extended sRGB (scRGB) color space)
+
+ On other platforms the value is always a pre-defined value, 200. This may
+ not match the system's actual SDR white level, but the value of this
+ variable is not relevant in practice when the \l luminanceBehavior is
+ DisplayReferred, because then the color component value of 1.0 refers to
+ the SDR white by default.
+
+ \sa luminanceBehavior
+*/
+
+/*!
\return the HDR information for the associated display.
- The returned struct is always the default one if createOrResize() has not
- been successfully called yet.
+ Do not assume that this is a cheap operation. Depending on the platform,
+ this function makes various platform queries which may have a performance
+ impact.
+
+ \note Can be called before createOrResize() as long as the window is
+ \l{setWindow()}{set}.
\note What happens when moving a window with an initialized swapchain
between displays (HDR to HDR with different characteristics, HDR to SDR,
@@ -4967,10 +7797,11 @@ QRhiRenderTarget *QRhiSwapChain::currentFrameRenderTarget(StereoTargetBuffer tar
QRhiSwapChainHdrInfo QRhiSwapChain::hdrInfo()
{
QRhiSwapChainHdrInfo info;
- info.isHardCodedDefaults = true;
info.limitsType = QRhiSwapChainHdrInfo::LuminanceInNits;
info.limits.luminanceInNits.minLuminance = 0.0f;
info.limits.luminanceInNits.maxLuminance = 1000.0f;
+ info.luminanceBehavior = QRhiSwapChainHdrInfo::SceneReferred;
+ info.sdrWhiteLevel = 200.0f;
return info;
}
@@ -4978,7 +7809,7 @@ QRhiSwapChainHdrInfo QRhiSwapChain::hdrInfo()
QDebug operator<<(QDebug dbg, const QRhiSwapChainHdrInfo &info)
{
QDebugStateSaver saver(dbg);
- dbg.nospace() << "QRhiSwapChainHdrInfo(" << (info.isHardCodedDefaults ? "with hard-coded defaults" : "queried from system");
+ dbg.nospace() << "QRhiSwapChainHdrInfo(";
switch (info.limitsType) {
case QRhiSwapChainHdrInfo::LuminanceInNits:
dbg.nospace() << " minLuminance=" << info.limits.luminanceInNits.minLuminance
@@ -4986,6 +7817,15 @@ QDebug operator<<(QDebug dbg, const QRhiSwapChainHdrInfo &info)
break;
case QRhiSwapChainHdrInfo::ColorComponentValue:
dbg.nospace() << " maxColorComponentValue=" << info.limits.colorComponentValue.maxColorComponentValue;
+ dbg.nospace() << " maxPotentialColorComponentValue=" << info.limits.colorComponentValue.maxPotentialColorComponentValue;
+ break;
+ }
+ switch (info.luminanceBehavior) {
+ case QRhiSwapChainHdrInfo::SceneReferred:
+ dbg.nospace() << " scene-referred, SDR white level=" << info.sdrWhiteLevel;
+ break;
+ case QRhiSwapChainHdrInfo::DisplayReferred:
+ dbg.nospace() << " display-referred";
break;
}
dbg.nospace() << ')';
@@ -4995,8 +7835,8 @@ QDebug operator<<(QDebug dbg, const QRhiSwapChainHdrInfo &info)
/*!
\class QRhiComputePipeline
- \internal
\inmodule QtGui
+ \since 6.6
\brief Compute pipeline state resource.
\note Setting the shader resource bindings is mandatory. The referenced
@@ -5004,6 +7844,9 @@ QDebug operator<<(QDebug dbg, const QRhiSwapChainHdrInfo &info)
time create() is called.
\note Setting the shader is mandatory.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
@@ -5033,15 +7876,59 @@ QRhiComputePipeline::QRhiComputePipeline(QRhiImplementation *rhi)
}
/*!
+ \fn QRhiComputePipeline::Flags QRhiComputePipeline::flags() const
+ \return the currently set flags.
+ */
+
+/*!
+ \fn void QRhiComputePipeline::setFlags(Flags f)
+ Sets the flags \a f.
+ */
+
+/*!
+ \fn QRhiShaderStage QRhiComputePipeline::shaderStage() const
+ \return the currently set shader.
+ */
+
+/*!
+ \fn void QRhiComputePipeline::setShaderStage(const QRhiShaderStage &stage)
+
+ Sets the shader to use. \a stage can only refer to the
+ \l{QRhiShaderStage::Compute}{compute stage}.
+ */
+
+/*!
+ \fn QRhiShaderResourceBindings *QRhiComputePipeline::shaderResourceBindings() const
+ \return the currently associated QRhiShaderResourceBindings object.
+ */
+
+/*!
+ \fn void QRhiComputePipeline::setShaderResourceBindings(QRhiShaderResourceBindings *srb)
+
+ Associates with \a srb describing the resource binding layout and the
+ resources (QRhiBuffer, QRhiTexture) themselves. The latter is optional. As
+ with graphics pipelines, the \a srb passed in here can leave the actual
+ buffer or texture objects unspecified (\nullptr) as long as there is
+ another,
+ \l{QRhiShaderResourceBindings::isLayoutCompatible()}{layout-compatible}
+ QRhiShaderResourceBindings bound via
+ \l{QRhiCommandBuffer::setShaderResources()}{setShaderResources()} before
+ recording the dispatch call.
+ */
+
+/*!
\class QRhiCommandBuffer
- \internal
\inmodule QtGui
+ \since 6.6
\brief Command buffer resource.
Not creatable by applications at the moment. The only ways to obtain a
valid QRhiCommandBuffer are to get it from the targeted swapchain via
QRhiSwapChain::currentFrameCommandBuffer(), or, in case of rendering
completely offscreen, initializing one via QRhi::beginOffscreenFrame().
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
@@ -5102,7 +7989,7 @@ QRhiResource::Type QRhiCommandBuffer::resourceType() const
return CommandBuffer;
}
-static const char *resourceTypeStr(QRhiResource *res)
+static const char *resourceTypeStr(const QRhiResource *res)
{
switch (res->resourceType()) {
case QRhiResource::Buffer:
@@ -5153,8 +8040,10 @@ QRhiImplementation::~QRhiImplementation()
qWarning("QRhi %p going down with %d unreleased resources that own native graphics objects. This is not nice.",
q, int(resources.size()));
}
- for (QRhiResource *res : std::as_const(resources)) {
- if (leakCheck)
+ for (auto it = resources.cbegin(), end = resources.cend(); it != end; ++it) {
+ QRhiResource *res = it.key();
+ const bool ownsNativeResources = it.value();
+ if (leakCheck && ownsNativeResources)
qWarning(" %s resource %p (%s)", resourceTypeStr(res), res, res->m_objectName.constData());
// Null out the resource's rhi pointer. This is why it makes sense to do null
@@ -5364,6 +8253,17 @@ void QRhiImplementation::textureFormatInfo(QRhiTexture::Format format, const QSi
*bytesPerPixel = bpc;
}
+bool QRhiImplementation::isStencilSupportingFormat(QRhiTexture::Format format) const
+{
+ switch (format) {
+ case QRhiTexture::D24S8:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
bool QRhiImplementation::sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps)
{
if (ps->cbeginShaderStages() == ps->cendShaderStages()) {
@@ -5483,6 +8383,41 @@ bool QRhiImplementation::sanityCheckShaderResourceBindings(QRhiShaderResourceBin
return true;
}
+int QRhiImplementation::effectiveSampleCount(int sampleCount) const
+{
+ // Stay compatible with QSurfaceFormat and friends where samples == 0 means the same as 1.
+ const int s = qBound(1, sampleCount, 64);
+ const QList<int> supported = supportedSampleCounts();
+ int result = 1;
+
+ // Stay compatible with Qt 5 in that requesting an unsupported sample count
+ // is not an error (although we still do a categorized debug print about
+ // this), and rather a supported value, preferably a close one, not just 1,
+ // is used instead. This is actually deviating from Qt 5 as that performs a
+ // clamping only and does not handle cases such as when sample count 2 is
+ // not supported but 4 is. (OpenGL handles things like that gracefully,
+ // other APIs may not, so improve this by picking the next largest, or in
+ // absence of that, the largest value; this with the goal to not reduce
+ // quality by rather picking a larger-than-requested value than a smaller one)
+
+ for (int i = 0, ie = supported.count(); i != ie; ++i) {
+ // assumes the 'supported' list is sorted
+ if (supported[i] >= s) {
+ result = supported[i];
+ break;
+ }
+ }
+
+ if (result != s) {
+ if (result == 1 && !supported.isEmpty())
+ result = supported.last();
+ qCDebug(QRHI_LOG_INFO, "Attempted to set unsupported sample count %d, using %d instead",
+ sampleCount, result);
+ }
+
+ return result;
+}
+
/*!
\internal
*/
@@ -5498,15 +8433,31 @@ QRhi::~QRhi()
if (!d)
return;
+ runCleanup();
+
qDeleteAll(d->pendingDeleteResources);
d->pendingDeleteResources.clear();
- runCleanup();
-
d->destroy();
delete d;
}
+void QRhiImplementation::prepareForCreate(QRhi *rhi, QRhi::Implementation impl, QRhi::Flags flags)
+{
+ q = rhi;
+
+ // Play nice with QSG_INFO since that is still the most commonly used
+ // way to get graphics info printed from Qt Quick apps, and the Quick
+ // scenegraph is our primary user.
+ if (qEnvironmentVariableIsSet("QSG_INFO"))
+ const_cast<QLoggingCategory &>(QRHI_LOG_INFO()).setEnabled(QtDebugMsg, true);
+
+ debugMarkers = flags.testFlag(QRhi::EnableDebugMarkers);
+
+ implType = impl;
+ implThread = QThread::currentThread();
+}
+
/*!
\return a new QRhi instance with a backend for the graphics API specified
by \a impl with the specified \a flags.
@@ -5574,7 +8525,7 @@ QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags, QRh
break;
#endif
case Metal:
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+#if QT_CONFIG(metal)
r->d = new QRhiMetal(static_cast<QRhiMetalInitParams *>(params),
static_cast<QRhiMetalNativeHandles *>(importDevice));
break;
@@ -5584,31 +8535,27 @@ QRhi *QRhi::create(Implementation impl, QRhiInitParams *params, Flags flags, QRh
#endif
case D3D12:
#ifdef Q_OS_WIN
+#ifdef QRHI_D3D12_AVAILABLE
r->d = new QRhiD3D12(static_cast<QRhiD3D12InitParams *>(params),
static_cast<QRhiD3D12NativeHandles *>(importDevice));
break;
#else
+ qWarning("Qt was built without Direct3D 12 support. "
+ "This is likely due to having ancient SDK headers (such as d3d12.h) in the Qt build environment. "
+ "Rebuild Qt with an SDK supporting D3D12 features introduced in Windows 10 version 1703, "
+ "or use an MSVC build as those typically are built with more up-to-date SDKs.");
+ break;
+#endif
+#else
qWarning("This platform has no Direct3D 12 support");
break;
#endif
}
if (r->d) {
- r->d->q = r.get();
-
- // Play nice with QSG_INFO since that is still the most commonly used
- // way to get graphics info printed from Qt Quick apps, and the Quick
- // scenegraph is our primary user.
- if (qEnvironmentVariableIsSet("QSG_INFO"))
- const_cast<QLoggingCategory &>(QRHI_LOG_INFO()).setEnabled(QtDebugMsg, true);
-
- r->d->debugMarkers = flags.testFlag(EnableDebugMarkers);
-
- if (r->d->create(flags)) {
- r->d->implType = impl;
- r->d->implThread = QThread::currentThread();
+ r->d->prepareForCreate(r.get(), impl, flags);
+ if (r->d->create(flags))
return r.release();
- }
}
return nullptr;
@@ -5637,7 +8584,7 @@ bool QRhi::probe(QRhi::Implementation impl, QRhiInitParams *params)
// create() and then drop the result.
if (impl == Metal) {
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+#if QT_CONFIG(metal)
ok = QRhiMetal::probe(static_cast<QRhiMetalInitParams *>(params));
#endif
} else {
@@ -5650,8 +8597,15 @@ bool QRhi::probe(QRhi::Implementation impl, QRhiInitParams *params)
/*!
\struct QRhiSwapChainProxyData
- \internal
\inmodule QtGui
+ \since 6.6
+
+ \brief Opaque data describing native objects needed to set up a swapchain.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
+ \sa QRhi::updateSwapChainProxyData()
*/
/*!
@@ -5681,7 +8635,7 @@ bool QRhi::probe(QRhi::Implementation impl, QRhiInitParams *params)
*/
QRhiSwapChainProxyData QRhi::updateSwapChainProxyData(QRhi::Implementation impl, QWindow *window)
{
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+#if QT_CONFIG(metal)
if (impl == Metal)
return QRhiMetal::updateSwapChainProxyData(window);
#else
@@ -5733,9 +8687,11 @@ const char *QRhi::backendName() const
/*!
\enum QRhiDriverInfo::DeviceType
- Specifies the graphics device's type, when the information is available. In
- practice this is only applicable with Vulkan and Metal. With others the
- value will always be UnknownDevice.
+ Specifies the graphics device's type, when the information is available.
+
+ In practice this is only applicable with Vulkan and Metal. With Direct 3D
+ 11 and 12, using an adapter with the software flag set leads to the value
+ \c CpuDevice. Otherwise, and with OpenGL, the value is always UnknownDevice.
\value UnknownDevice
\value IntegratedDevice
@@ -5747,8 +8703,8 @@ const char *QRhi::backendName() const
/*!
\struct QRhiDriverInfo
- \internal
\inmodule QtGui
+ \since 6.6
\brief Describes the physical device, adapter, or graphics API
implementation that is used by an initialized QRhi.
@@ -5760,8 +8716,35 @@ const char *QRhi::backendName() const
\c{GL_VERSION}. The deviceId is always 0 for OpenGL. vendorId is always 0
for OpenGL and Metal. deviceType is always UnknownDevice for OpenGL and
Direct 3D.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
+/*!
+ \variable QRhiDriverInfo::deviceName
+
+ \sa QRhi::driverInfo()
+*/
+
+/*!
+ \variable QRhiDriverInfo::deviceId
+
+ \sa QRhi::driverInfo()
+*/
+
+/*!
+ \variable QRhiDriverInfo::vendorId
+
+ \sa QRhi::driverInfo()
+*/
+
+/*!
+ \variable QRhiDriverInfo::deviceType
+
+ \sa QRhi::driverInfo(), QRhiDriverInfo::DeviceType
+*/
+
#ifndef QT_NO_DEBUG_STREAM
static inline const char *deviceTypeStr(QRhiDriverInfo::DeviceType type)
{
@@ -5829,6 +8812,33 @@ void QRhi::addCleanupCallback(const CleanupCallback &callback)
}
/*!
+ \overload
+
+ Registers \a callback to be invoked either when the QRhi is destroyed or
+ when runCleanup() is called. This overload takes an opaque pointer, \a key,
+ that is used to ensure that a given callback is registered (and so called)
+ only once.
+
+ \sa removeCleanupCallback()
+ */
+void QRhi::addCleanupCallback(const void *key, const CleanupCallback &callback)
+{
+ d->addCleanupCallback(key, callback);
+}
+
+/*!
+ Deregisters the callback with \a key. If no cleanup callback was registered
+ with \a key, the function does nothing. Callbacks registered without a key
+ cannot be removed.
+
+ \sa addCleanupCallback()
+ */
+void QRhi::removeCleanupCallback(const void *key)
+{
+ d->removeCleanupCallback(key);
+}
+
+/*!
Invokes all registered cleanup functions. The list of cleanup callbacks it
then cleared. Normally destroying the QRhi does this automatically, but
sometimes it can be useful to trigger cleanup in order to release all
@@ -5842,42 +8852,17 @@ void QRhi::runCleanup()
f(this);
d->cleanupCallbacks.clear();
-}
-/*!
- Registers a \a callback that is called with an elapsed time calculated from
- GPU timestamps asynchronously after a timestamp becomes available at some
- point after presenting a frame.
-
- The callback is called with a float value that is meant to be in
- milliseconds and represents the elapsed time on the GPU side for a given
- frame. Care must be exercised with the interpretation of the value, as what
- it exactly is is not controlled by Qt and depends on the underlying
- graphics API and its implementation. In particular, comparing the values
- between different graphics APIs is discouraged and may be meaningless.
-
- The timing values become available asynchronously, sometimes several frames
- after the frame has been submitted in endFrame(). There is currently no way
- to identify the frame. The callback is invoked whenever the timestamp
- queries complete.
+ for (auto it = d->keyedCleanupCallbacks.cbegin(), end = d->keyedCleanupCallbacks.cend(); it != end; ++it)
+ it.value()(this);
- \note This is only supported when the Timestamp feature is reported as
- supported from isFeatureSupported(). Otherwise the \a callback is never
- called.
-
- The \a callback is always called on the thread the QRhi lives and operates
- on. While not guaranteed, it is typical that the callback is invoked from
- within beginFrame().
- */
-void QRhi::addGpuFrameTimeCallback(const GpuFrameTimeCallback &callback)
-{
- d->addGpuFrameTimeCallback(callback);
+ d->keyedCleanupCallbacks.clear();
}
/*!
\class QRhiResourceUpdateBatch
- \internal
\inmodule QtGui
+ \since 6.6
\brief Records upload and copy type of operations.
With QRhi it is no longer possible to perform copy type of operations at
@@ -5893,6 +8878,9 @@ void QRhi::addGpuFrameTimeCallback(const GpuFrameTimeCallback &callback)
To get an available, empty batch from the pool, call
QRhi::nextResourceUpdateBatch().
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
@@ -5936,29 +8924,26 @@ void QRhiResourceUpdateBatch::release()
that is then merged into another when starting to first render pass later
on:
- \badcode
- void init()
- {
- ...
- initialUpdates = rhi->nextResourceUpdateBatch();
- initialUpdates->uploadStaticBuffer(vbuf, vertexData);
- initialUpdates->uploadStaticBuffer(ibuf, indexData);
- ...
- }
+ \code
+ void init()
+ {
+ initialUpdates = rhi->nextResourceUpdateBatch();
+ initialUpdates->uploadStaticBuffer(vbuf, vertexData);
+ initialUpdates->uploadStaticBuffer(ibuf, indexData);
+ // ...
+ }
- void render()
- {
- ...
- QRhiResourceUpdateBatch *resUpdates = rhi->nextResourceUpdateBatch();
- if (initialUpdates) {
- resUpdates->merge(initialUpdates);
- initialUpdates->release();
- initialUpdates = nullptr;
+ void render()
+ {
+ QRhiResourceUpdateBatch *resUpdates = rhi->nextResourceUpdateBatch();
+ if (initialUpdates) {
+ resUpdates->merge(initialUpdates);
+ initialUpdates->release();
+ initialUpdates = nullptr;
+ }
+ // resUpdates->updateDynamicBuffer(...);
+ cb->beginPass(rt, clearCol, clearDs, resUpdates);
}
- resUpdates->updateDynamicBuffer(...);
- ...
- cb->beginPass(rt, clearCol, clearDs, resUpdates);
- }
\endcode
*/
void QRhiResourceUpdateBatch::merge(QRhiResourceUpdateBatch *other)
@@ -6000,8 +8985,8 @@ bool QRhiResourceUpdateBatch::hasOptimalCapacity() const
\note QRhi transparently manages double buffering in order to prevent
stalling the graphics pipeline. The fact that a QRhiBuffer may have
- multiple native underneath can be safely ignored when using the QRhi and
- QRhiResourceUpdateBatch.
+ multiple native buffer objects underneath can be safely ignored when using
+ the QRhi and QRhiResourceUpdateBatch.
*/
void QRhiResourceUpdateBatch::updateDynamicBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
{
@@ -6035,6 +9020,8 @@ void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, quint32 offset
}
/*!
+ \overload
+
Enqueues updating the entire QRhiBuffer \a buf created with the type
QRhiBuffer::Immutable or QRhiBuffer::Static.
*/
@@ -6056,7 +9043,7 @@ void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, const void *da
A readback is asynchronous. \a result contains a callback that is invoked
when the operation has completed. The data is provided in
- QRhiBufferReadbackResult::data. Upon successful completion that QByteArray
+ QRhiReadbackResult::data. Upon successful completion that QByteArray
will have a size equal to \a size. On failure the QByteArray will be empty.
\note Reading buffers with a usage different than QRhiBuffer::UniformBuffer
@@ -6073,7 +9060,7 @@ void QRhiResourceUpdateBatch::uploadStaticBuffer(QRhiBuffer *buf, const void *da
\sa readBackTexture(), QRhi::isFeatureSupported(), QRhi::resourceLimit()
*/
-void QRhiResourceUpdateBatch::readBackBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, QRhiBufferReadbackResult *result)
+void QRhiResourceUpdateBatch::readBackBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, QRhiReadbackResult *result)
{
const int idx = d->activeBufferOpCount++;
if (idx < d->bufferOps.size())
@@ -6147,10 +9134,10 @@ void QRhiResourceUpdateBatch::copyTexture(QRhiTexture *dst, QRhiTexture *src, co
application. Therefore, \a result provides not just the data but also a
callback as operations on the batch are asynchronous by nature:
- \badcode
- beginFrame(sc);
- beginPass
- ...
+ \code
+ rhi->beginFrame(swapchain);
+ cb->beginPass(swapchain->currentFrameRenderTarget(), colorClear, dsClear);
+ // ...
QRhiReadbackResult *rbResult = new QRhiReadbackResult;
rbResult->completed = [rbResult] {
{
@@ -6161,11 +9148,11 @@ void QRhiResourceUpdateBatch::copyTexture(QRhiTexture *dst, QRhiTexture *src, co
}
delete rbResult;
};
- u = nextResourceUpdateBatch();
+ QRhiResourceUpdateBatch *u = nextResourceUpdateBatch();
QRhiReadbackDescription rb; // no texture -> uses the current backbuffer of sc
u->readBackTexture(rb, rbResult);
- endPass(u);
- endFrame(sc);
+ cb->endPass(u);
+ rhi->endFrame(swapchain);
\endcode
\note The texture must be created with QRhiTexture::UsedAsTransferSource.
@@ -6242,11 +9229,43 @@ void QRhiResourceUpdateBatch::generateMips(QRhiTexture *tex)
\note Can be called outside beginFrame() - endFrame() as well since a batch
instance just collects data on its own, it does not perform any operations.
- \warning The maximum number of batches is 64. When this limit is reached,
- the function will return null until a batch is returned to the pool.
+ Due to not being tied to a frame being recorded, the following sequence is
+ valid for example:
+
+ \code
+ rhi->beginFrame(swapchain);
+ QRhiResourceUpdateBatch *u = rhi->nextResourceUpdateBatch();
+ u->uploadStaticBuffer(buf, data);
+ // ... do not commit the batch
+ rhi->endFrame();
+ // u stays valid (assuming buf stays valid as well)
+ rhi->beginFrame(swapchain);
+ swapchain->currentFrameCommandBuffer()->resourceUpdate(u);
+ // ... draw with buf
+ rhi->endFrame();
+ \endcode
+
+ \warning The maximum number of batches per QRhi is 64. When this limit is
+ reached, the function will return null until a batch is returned to the
+ pool.
*/
QRhiResourceUpdateBatch *QRhi::nextResourceUpdateBatch()
{
+ // By default we prefer spreading out the utilization of the 64 batches as
+ // much as possible, meaning we won't pick the first one even if it's free,
+ // but prefer picking one after the last picked one. Relevant due to how
+ // QVLA and QRhiBufferData allocations behind the bufferOps are reused; in
+ // typical Qt Quick scenes this leads to a form of (eventually) seeding all
+ // the 64 resource batches with buffer operation data allocations which are
+ // then reused in subsequent frames. This comes at the expense of using
+ // more memory, but has proven good results when (CPU) profiling typical
+ // Quick/Quick3D apps.
+ //
+ // Prefering memory over performance means that we always pick the first
+ // free batch, and triggering the aggressive deallocating of all backing
+ // memory (see trimOpLists) before returning it.
+ static const bool preferMemoryOverPerformance = qEnvironmentVariableIntValue("QT_RHI_MINIMIZE_POOLS");
+
auto nextFreeBatch = [this]() -> QRhiResourceUpdateBatch * {
auto isFree = [this](int i) -> QRhiResourceUpdateBatch * {
const quint64 mask = 1ULL << quint64(i);
@@ -6254,7 +9273,8 @@ QRhiResourceUpdateBatch *QRhi::nextResourceUpdateBatch()
d->resUpdPoolMap |= mask;
QRhiResourceUpdateBatch *u = d->resUpdPool[i];
QRhiResourceUpdateBatchPrivate::get(u)->poolIndex = i;
- d->lastResUpdIdx = i;
+ if (!preferMemoryOverPerformance)
+ d->lastResUpdIdx = i;
return u;
}
return nullptr;
@@ -6283,6 +9303,9 @@ QRhiResourceUpdateBatch *QRhi::nextResourceUpdateBatch()
qWarning("Resource update batch pool exhausted (max is 64)");
}
+ if (preferMemoryOverPerformance && u)
+ u->d->trimOpLists();
+
return u;
}
@@ -6297,7 +9320,15 @@ void QRhiResourceUpdateBatchPrivate::free()
rhi->resUpdPoolMap &= ~mask;
poolIndex = -1;
+ // textureOps is cleared, to not keep the potentially large image pixel
+ // data alive, but it is expected that the container keeps the list alloc
+ // at least. Only trimOpList() goes for the more aggressive route with squeeze.
textureOps.clear();
+
+ // bufferOps is not touched, to allow reusing allocations (incl. in the
+ // elements' QRhiBufferData) as much as possible when this batch is used
+ // again in the future, which is important for performance, in particular
+ // with Qt Quick.
}
void QRhiResourceUpdateBatchPrivate::merge(QRhiResourceUpdateBatchPrivate *other)
@@ -6325,13 +9356,21 @@ bool QRhiResourceUpdateBatchPrivate::hasOptimalCapacity() const
void QRhiResourceUpdateBatchPrivate::trimOpLists()
{
- Q_ASSERT(poolIndex == -1); // must not be in use
+ // Unlike free(), this is expected to aggressively deallocate all memory
+ // used by both the buffer and texture operation lists. (i.e. using
+ // squeeze() to only keep the stack prealloc of the QVLAs)
+ //
+ // This (e.g. just the destruction of bufferOps elements) may have a
+ // non-negligible performance impact e.g. with Qt Quick with scenes where
+ // there are lots of buffer operations per frame.
activeBufferOpCount = 0;
bufferOps.clear();
+ bufferOps.squeeze();
activeTextureOpCount = 0;
textureOps.clear();
+ textureOps.squeeze();
}
/*!
@@ -6386,13 +9425,13 @@ void QRhiCommandBuffer::resourceUpdate(QRhiResourceUpdateBatch *resourceUpdates)
made on \a rt. Therefore, if \a rt has a QRhiTexture color attachment \c
texture, and one needs to make the texture a different size, the following
is then valid:
- \badcode
- rt = rhi->newTextureRenderTarget({ { texture } });
+ \code
+ QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget({ { texture } });
rt->create();
- ...
+ // ...
texture->setPixelSize(new_size);
texture->create();
- cb->beginPass(rt, ...); // this is ok, no explicit rt->create() is required before
+ cb->beginPass(rt, colorClear, dsClear); // this is ok, no explicit rt->create() is required before
\endcode
\a flags allow controlling certain advanced functionality. One commonly used
@@ -6537,7 +9576,7 @@ void QRhiCommandBuffer::setShaderResources(QRhiShaderResourceBindings *srb,
floats for position (so 5 floats per vertex: x, y, r, g, b). A QRhiGraphicsPipeline for
this shader can then be created using the input layout:
- \badcode
+ \code
QRhiVertexInputLayout inputLayout;
inputLayout.setBindings({
{ 5 * sizeof(float) }
@@ -6550,11 +9589,10 @@ void QRhiCommandBuffer::setShaderResources(QRhiShaderResourceBindings *srb,
Here there is one buffer binding (binding number 0), with two inputs
referencing it. When recording the pass, once the pipeline is set, the
- vertex bindings can be specified simply like the following (using C++11
- initializer syntax), assuming vbuf is the QRhiBuffer with all the
- interleaved position+color data:
+ vertex bindings can be specified simply like the following, assuming vbuf
+ is the QRhiBuffer with all the interleaved position+color data:
- \badcode
+ \code
const QRhiCommandBuffer::VertexInput vbufBinding(vbuf, 0);
cb->setVertexInput(0, 1, &vbufBinding);
\endcode
@@ -6839,9 +9877,9 @@ const QRhiNativeHandles *QRhiCommandBuffer::nativeHandles()
called when the pass recording was started with specifying
QRhiCommandBuffer::ExternalContent.
- With Vulkan or Metal one can query the native command buffer or encoder
- objects via nativeHandles() and enqueue commands to them. With OpenGL or
- Direct3D 11 the (device) context can be retrieved from
+ With Vulkan, Metal, or Direct3D 12 one can query the native command buffer
+ or encoder objects via nativeHandles() and enqueue commands to them. With
+ OpenGL or Direct3D 11 the (device) context can be retrieved from
QRhi::nativeHandles(). However, this must never be done without ensuring
the QRhiCommandBuffer's state stays up-to-date. Hence the requirement for
wrapping any externally added command recording between beginExternal() and
@@ -6889,6 +9927,72 @@ void QRhiCommandBuffer::endExternal()
}
/*!
+ \return the last available timestamp, in seconds, when
+ \l QRhi::EnableTimestamps was enabled when creating the QRhi. The value
+ indicates the elapsed time on the GPU during the last completed frame.
+
+ \note Do not expect results other than 0 when the QRhi::Timestamps feature
+ is not reported as supported, or when QRhi::EnableTimestamps was not passed
+ to QRhi::create(). There are exceptions to this, because with some graphics
+ APIs (Metal) timings are available without having to perform extra
+ operations (timestamp queries), but portable applications should always
+ consciously opt-in to timestamp collection when they know it is needed, and
+ call this function accordingly.
+
+ Care must be exercised with the interpretation of the value, as its
+ precision and granularity is often not controlled by Qt, and depends on the
+ underlying graphics API and its implementation. In particular, comparing
+ the values between different graphics APIs and hardware is discouraged and
+ may be meaningless.
+
+ When the frame was recorded with \l{QRhi::beginFrame()}{beginFrame()} and
+ \l{QRhi::endFrame()}{endFrame()}, i.e., with a swapchain, the timing values
+ will likely become available asynchronously. The returned value may
+ therefore be 0 (e.g., for the first 1-2 frames) or the last known value
+ referring to some previous frame. The value my also
+ become 0 again under certain conditions, such as when resizing the window.
+ It can be expected that the most up-to-date available value is retrieved in
+ beginFrame() and becomes queriable via this function once beginFrame()
+ returns.
+
+ \note Do not assume that the value refers to the previous
+ (\c{currently_recorded - 1}) frame. It may refer to \c{currently_recorded -
+ 2} or \c{currently_recorded - 3} as well. The exact behavior may depend on
+ the graphics API and its implementation.
+
+ On the other hand, with offscreen frames the returned value is up-to-date
+ once \l{QRhi::endOffscreenFrame()}{endOffscreenFrame()} returns, because
+ offscreen frames reduce GPU pipelining and wait the the commands to be
+ complete.
+
+ \note This means that, unlike with swapchain frames, with offscreen frames
+ the returned value is guaranteed to refer to the frame that has just been
+ submitted and completed. (assuming this function is called after
+ endOffscreenFrame() but before the next beginOffscreenFrame())
+
+ Watch out for the consequences of GPU frequency scaling and GPU clock
+ changes, depending on the platform. For example, on Windows the returned
+ timing may vary in a quite wide range between frames with modern graphics
+ cards, even when submitting frames with a similar, or the same workload.
+ This is out of scope for Qt to control and solve, generally speaking.
+ However, the D3D12 backend automatically calls
+ \l{https://learn.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-setstablepowerstate}{ID3D12Device::SetStablePowerState()}
+ whenever the environment variable \c QT_D3D_STABLE_POWER_STATE is set to a
+ non-zero value. This can greatly stabilize the result. It can also have a
+ non-insignificant effect on the CPU-side timings measured via QElapsedTimer
+ for example, especially when offscreen frames are involved.
+
+ \note Do not and never ship applications to production with
+ \c QT_D3D_STABLE_POWER_STATE set. See the Windows API documentation for details.
+
+ \sa QRhi::Timestamps, QRhi::EnableTimestamps
+ */
+double QRhiCommandBuffer::lastCompletedGpuTime()
+{
+ return m_rhi->lastCompletedGpuTime(this);
+}
+
+/*!
\return the value (typically an offset) \a v aligned to the uniform buffer
alignment given by by ubufAlignment().
*/
@@ -7024,7 +10128,8 @@ int QRhi::resourceLimit(ResourceLimit limit) const
for the device, context, and similar concepts used by the backend.
Cast to QRhiVulkanNativeHandles, QRhiD3D11NativeHandles,
- QRhiGles2NativeHandles, QRhiMetalNativeHandles as appropriate.
+ QRhiD3D12NativeHandles, QRhiGles2NativeHandles, or QRhiMetalNativeHandles
+ as appropriate.
\note No ownership is transferred, neither for the returned pointer nor for
any native objects.
@@ -7224,12 +10329,70 @@ void QRhi::setPipelineCacheData(const QByteArray &data)
/*!
\struct QRhiStats
- \internal
\inmodule QtGui
+ \since 6.6
\brief Statistics provided from the underlying memory allocator.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
+/*!
+ \variable QRhiStats::totalPipelineCreationTime
+
+ The total time in milliseconds spent in graphics and compute pipeline
+ creation, which usually involves shader compilation or cache lookups, and
+ potentially expensive processing.
+
+ \note The value should not be compared between different backends since the
+ concept of "pipelines" and what exactly happens under the hood during, for
+ instance, a call to QRhiGraphicsPipeline::create(), differ greatly between
+ graphics APIs and their implementations.
+
+ \sa QRhi::statistics()
+*/
+
+/*!
+ \variable QRhiStats::blockCount
+
+ Statistic reported from the Vulkan or D3D12 memory allocator.
+
+ \sa QRhi::statistics()
+*/
+
+/*!
+ \variable QRhiStats::allocCount
+
+ Statistic reported from the Vulkan or D3D12 memory allocator.
+
+ \sa QRhi::statistics()
+*/
+
+/*!
+ \variable QRhiStats::usedBytes
+
+ Statistic reported from the Vulkan or D3D12 memory allocator.
+
+ \sa QRhi::statistics()
+*/
+
+/*!
+ \variable QRhiStats::unusedBytes
+
+ Statistic reported from the Vulkan or D3D12 memory allocator.
+
+ \sa QRhi::statistics()
+*/
+
+/*!
+ \variable QRhiStats::totalUsageBytes
+
+ Valid only with D3D12 currently. Matches IDXGIAdapter3::QueryVideoMemoryInfo().
+
+ \sa QRhi::statistics()
+*/
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QRhiStats &info)
{
@@ -7489,6 +10652,14 @@ QRhiTexture *QRhi::newTextureArray(QRhiTexture::Format format,
minification filter \a minFilter, mipmapping mode \a mipmapMode, and the
addressing (wrap) modes \a addressU, \a addressV, and \a addressW.
+ \note Setting \a mipmapMode to a value other than \c None implies that
+ images for all relevant mip levels will be provided either via
+ \l{QRhiResourceUpdateBatch::uploadTexture()}{texture uploads} or by calling
+ \l{QRhiResourceUpdateBatch::generateMips()}{generateMips()} on the texture
+ that is used with this sampler. Attempting to use the sampler with a
+ texture that has no data for all relevant mip levels will lead to rendering
+ errors, with the exact behavior dependent on the underlying graphics API.
+
\sa QRhiResource::destroy()
*/
QRhiSampler *QRhi::newSampler(QRhiSampler::Filter magFilter,
@@ -7692,26 +10863,29 @@ int QRhi::currentFrameSlot() const
beginOffscreenFrame, endOffscreenFrame, beginFrame, ...) is possible too
but it does reduce parallelism so it should be done only infrequently.
- Offscreen frames do not let the CPU - potentially - generate another frame
+ Offscreen frames do not let the CPU potentially generate another frame
while the GPU is still processing the previous one. This has the side
effect that if readbacks are scheduled, the results are guaranteed to be
available once endOffscreenFrame() returns. That is not the case with
- frames targeting a swapchain.
+ frames targeting a swapchain: there the GPU is potentially better utilized,
+ but working with readback operations needs more care from the application
+ because endFrame(), unlike endOffscreenFrame(), does not guarantee that the
+ results from the readback are available at that point.
The skeleton of rendering a frame without a swapchain and then reading the
frame contents back could look like the following:
- \badcode
- QRhiReadbackResult rbResult;
- QRhiCommandBuffer *cb;
- beginOffscreenFrame(&cb);
- beginPass
- ...
- u = nextResourceUpdateBatch();
- u->readBackTexture(rb, &rbResult);
- endPass(u);
- endOffscreenFrame();
- // image data available in rbResult
+ \code
+ QRhiReadbackResult rbResult;
+ QRhiCommandBuffer *cb;
+ rhi->beginOffscreenFrame(&cb);
+ cb->beginPass(rt, colorClear, dsClear);
+ // ...
+ u = nextResourceUpdateBatch();
+ u->readBackTexture(rb, &rbResult);
+ cb->endPass(u);
+ rhi->endOffscreenFrame();
+ // image data available in rbResult
\endcode
\sa endOffscreenFrame(), beginFrame()
@@ -7772,6 +10946,9 @@ QRhi::FrameOpResult QRhi::finish()
With some backend this list of supported values is fixed in advance, while
with some others the (physical) device properties indicate what is
supported at run time.
+
+ \sa QRhiRenderBuffer::setSampleCount(), QRhiTexture::setSampleCount(),
+ QRhiGraphicsPipeline::setSampleCount(), QRhiSwapChain::setSampleCount()
*/
QList<int> QRhi::supportedSampleCounts() const
{
diff --git a/src/gui/rhi/qrhi.h b/src/gui/rhi/qrhi.h
new file mode 100644
index 0000000000..d20b7e00d1
--- /dev/null
+++ b/src/gui/rhi/qrhi.h
@@ -0,0 +1,2026 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QRHI_H
+#define QRHI_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is part of the RHI API, with limited compatibility guarantees.
+// Usage of this API may make your code source and binary incompatible with
+// future versions of Qt.
+//
+
+#include <QtGui/qtguiglobal.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qthread.h>
+#include <QtGui/qmatrix4x4.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qimage.h>
+#include <functional>
+#include <array>
+
+#include <rhi/qshader.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWindow;
+class QRhi;
+class QRhiImplementation;
+class QRhiBuffer;
+class QRhiRenderBuffer;
+class QRhiTexture;
+class QRhiSampler;
+class QRhiCommandBuffer;
+class QRhiResourceUpdateBatch;
+class QRhiResourceUpdateBatchPrivate;
+class QRhiSwapChain;
+
+class Q_GUI_EXPORT QRhiDepthStencilClearValue
+{
+public:
+ QRhiDepthStencilClearValue() = default;
+ QRhiDepthStencilClearValue(float d, quint32 s);
+
+ float depthClearValue() const { return m_d; }
+ void setDepthClearValue(float d) { m_d = d; }
+
+ quint32 stencilClearValue() const { return m_s; }
+ void setStencilClearValue(quint32 s) { m_s = s; }
+
+private:
+ float m_d = 1.0f;
+ quint32 m_s = 0;
+
+ friend bool operator==(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) noexcept
+ {
+ return a.m_d == b.m_d && a.m_s == b.m_s;
+ }
+
+ friend bool operator!=(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) noexcept
+ {
+ return !(a == b);
+ }
+
+ friend size_t qHash(const QRhiDepthStencilClearValue &v, size_t seed = 0) noexcept
+ {
+ QtPrivate::QHashCombine hash;
+ seed = hash(seed, v.m_d);
+ seed = hash(seed, v.m_s);
+ return seed;
+ }
+};
+
+Q_DECLARE_TYPEINFO(QRhiDepthStencilClearValue, Q_RELOCATABLE_TYPE);
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiDepthStencilClearValue &);
+#endif
+
+class Q_GUI_EXPORT QRhiViewport
+{
+public:
+ QRhiViewport() = default;
+ QRhiViewport(float x, float y, float w, float h, float minDepth = 0.0f, float maxDepth = 1.0f);
+
+ std::array<float, 4> viewport() const { return m_rect; }
+ void setViewport(float x, float y, float w, float h) {
+ m_rect[0] = x; m_rect[1] = y; m_rect[2] = w; m_rect[3] = h;
+ }
+
+ float minDepth() const { return m_minDepth; }
+ void setMinDepth(float minDepth) { m_minDepth = minDepth; }
+
+ float maxDepth() const { return m_maxDepth; }
+ void setMaxDepth(float maxDepth) { m_maxDepth = maxDepth; }
+
+private:
+ std::array<float, 4> m_rect { { 0.0f, 0.0f, 0.0f, 0.0f } };
+ float m_minDepth = 0.0f;
+ float m_maxDepth = 1.0f;
+
+ friend bool operator==(const QRhiViewport &a, const QRhiViewport &b) noexcept
+ {
+ return a.m_rect == b.m_rect
+ && a.m_minDepth == b.m_minDepth
+ && a.m_maxDepth == b.m_maxDepth;
+ }
+
+ friend bool operator!=(const QRhiViewport &a, const QRhiViewport &b) noexcept
+ {
+ return !(a == b);
+ }
+
+ friend size_t qHash(const QRhiViewport &v, size_t seed = 0) noexcept
+ {
+ QtPrivate::QHashCombine hash;
+ seed = hash(seed, v.m_rect[0]);
+ seed = hash(seed, v.m_rect[1]);
+ seed = hash(seed, v.m_rect[2]);
+ seed = hash(seed, v.m_rect[3]);
+ seed = hash(seed, v.m_minDepth);
+ seed = hash(seed, v.m_maxDepth);
+ return seed;
+ }
+};
+
+Q_DECLARE_TYPEINFO(QRhiViewport, Q_RELOCATABLE_TYPE);
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiViewport &);
+#endif
+
+class Q_GUI_EXPORT QRhiScissor
+{
+public:
+ QRhiScissor() = default;
+ QRhiScissor(int x, int y, int w, int h);
+
+ std::array<int, 4> scissor() const { return m_rect; }
+ void setScissor(int x, int y, int w, int h) {
+ m_rect[0] = x; m_rect[1] = y; m_rect[2] = w; m_rect[3] = h;
+ }
+
+private:
+ std::array<int, 4> m_rect { { 0, 0, 0, 0 } };
+
+ friend bool operator==(const QRhiScissor &a, const QRhiScissor &b) noexcept
+ {
+ return a.m_rect == b.m_rect;
+ }
+
+ friend bool operator!=(const QRhiScissor &a, const QRhiScissor &b) noexcept
+ {
+ return !(a == b);
+ }
+
+ friend size_t qHash(const QRhiScissor &v, size_t seed = 0) noexcept
+ {
+ QtPrivate::QHashCombine hash;
+ seed = hash(seed, v.m_rect[0]);
+ seed = hash(seed, v.m_rect[1]);
+ seed = hash(seed, v.m_rect[2]);
+ seed = hash(seed, v.m_rect[3]);
+ return seed;
+ }
+};
+
+Q_DECLARE_TYPEINFO(QRhiScissor, Q_RELOCATABLE_TYPE);
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiScissor &);
+#endif
+
+class Q_GUI_EXPORT QRhiVertexInputBinding
+{
+public:
+ enum Classification {
+ PerVertex,
+ PerInstance
+ };
+
+ QRhiVertexInputBinding() = default;
+ QRhiVertexInputBinding(quint32 stride, Classification cls = PerVertex, quint32 stepRate = 1);
+
+ quint32 stride() const { return m_stride; }
+ void setStride(quint32 s) { m_stride = s; }
+
+ Classification classification() const { return m_classification; }
+ void setClassification(Classification c) { m_classification = c; }
+
+ quint32 instanceStepRate() const { return m_instanceStepRate; }
+ void setInstanceStepRate(quint32 rate) { m_instanceStepRate = rate; }
+
+private:
+ quint32 m_stride = 0;
+ Classification m_classification = PerVertex;
+ quint32 m_instanceStepRate = 1;
+
+ friend bool operator==(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) noexcept
+ {
+ return a.m_stride == b.m_stride
+ && a.m_classification == b.m_classification
+ && a.m_instanceStepRate == b.m_instanceStepRate;
+ }
+
+ friend bool operator!=(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) noexcept
+ {
+ return !(a == b);
+ }
+
+ friend size_t qHash(const QRhiVertexInputBinding &v, size_t seed = 0) noexcept
+ {
+ QtPrivate::QHashCombine hash;
+ seed = hash(seed, v.m_stride);
+ seed = hash(seed, v.m_classification);
+ seed = hash(seed, v.m_instanceStepRate);
+ return seed;
+ }
+};
+
+Q_DECLARE_TYPEINFO(QRhiVertexInputBinding, Q_RELOCATABLE_TYPE);
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiVertexInputBinding &);
+#endif
+
+class Q_GUI_EXPORT QRhiVertexInputAttribute
+{
+public:
+ enum Format {
+ Float4,
+ Float3,
+ Float2,
+ Float,
+ UNormByte4,
+ UNormByte2,
+ UNormByte,
+ UInt4,
+ UInt3,
+ UInt2,
+ UInt,
+ SInt4,
+ SInt3,
+ SInt2,
+ SInt,
+ Half4,
+ Half3,
+ Half2,
+ Half,
+ UShort4,
+ UShort3,
+ UShort2,
+ UShort,
+ SShort4,
+ SShort3,
+ SShort2,
+ SShort,
+ };
+
+ QRhiVertexInputAttribute() = default;
+ QRhiVertexInputAttribute(int binding, int location, Format format, quint32 offset, int matrixSlice = -1);
+
+ int binding() const { return m_binding; }
+ void setBinding(int b) { m_binding = b; }
+
+ int location() const { return m_location; }
+ void setLocation(int loc) { m_location = loc; }
+
+ Format format() const { return m_format; }
+ void setFormat(Format f) { m_format = f; }
+
+ quint32 offset() const { return m_offset; }
+ void setOffset(quint32 ofs) { m_offset = ofs; }
+
+ int matrixSlice() const { return m_matrixSlice; }
+ void setMatrixSlice(int slice) { m_matrixSlice = slice; }
+
+private:
+ int m_binding = 0;
+ int m_location = 0;
+ Format m_format = Float4;
+ quint32 m_offset = 0;
+ int m_matrixSlice = -1;
+
+ friend bool operator==(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) noexcept
+ {
+ return a.m_binding == b.m_binding
+ && a.m_location == b.m_location
+ && a.m_format == b.m_format
+ && a.m_offset == b.m_offset;
+ // matrixSlice excluded intentionally
+ }
+
+ friend bool operator!=(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) noexcept
+ {
+ return !(a == b);
+ }
+
+ friend size_t qHash(const QRhiVertexInputAttribute &v, size_t seed = 0) noexcept
+ {
+ QtPrivate::QHashCombine hash;
+ seed = hash(seed, v.m_binding);
+ seed = hash(seed, v.m_location);
+ seed = hash(seed, v.m_format);
+ seed = hash(seed, v.m_offset);
+ return seed;
+ }
+};
+
+Q_DECLARE_TYPEINFO(QRhiVertexInputAttribute, Q_RELOCATABLE_TYPE);
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiVertexInputAttribute &);
+#endif
+
+class Q_GUI_EXPORT QRhiVertexInputLayout
+{
+public:
+ QRhiVertexInputLayout() = default;
+
+ void setBindings(std::initializer_list<QRhiVertexInputBinding> list) { m_bindings = list; }
+ template<typename InputIterator>
+ void setBindings(InputIterator first, InputIterator last)
+ {
+ m_bindings.clear();
+ std::copy(first, last, std::back_inserter(m_bindings));
+ }
+ const QRhiVertexInputBinding *cbeginBindings() const { return m_bindings.cbegin(); }
+ const QRhiVertexInputBinding *cendBindings() const { return m_bindings.cend(); }
+ const QRhiVertexInputBinding *bindingAt(qsizetype index) const { return &m_bindings.at(index); }
+ qsizetype bindingCount() const { return m_bindings.count(); }
+
+ void setAttributes(std::initializer_list<QRhiVertexInputAttribute> list) { m_attributes = list; }
+ template<typename InputIterator>
+ void setAttributes(InputIterator first, InputIterator last)
+ {
+ m_attributes.clear();
+ std::copy(first, last, std::back_inserter(m_attributes));
+ }
+ const QRhiVertexInputAttribute *cbeginAttributes() const { return m_attributes.cbegin(); }
+ const QRhiVertexInputAttribute *cendAttributes() const { return m_attributes.cend(); }
+ const QRhiVertexInputAttribute *attributeAt(qsizetype index) const { return &m_attributes.at(index); }
+ qsizetype attributeCount() const { return m_attributes.count(); }
+
+private:
+ QVarLengthArray<QRhiVertexInputBinding, 8> m_bindings;
+ QVarLengthArray<QRhiVertexInputAttribute, 8> m_attributes;
+
+ friend bool operator==(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) noexcept
+ {
+ return a.m_bindings == b.m_bindings && a.m_attributes == b.m_attributes;
+ }
+
+ friend bool operator!=(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) noexcept
+ {
+ return !(a == b);
+ }
+
+ friend size_t qHash(const QRhiVertexInputLayout &v, size_t seed = 0) noexcept
+ {
+ QtPrivate::QHashCombine hash;
+ seed = hash(seed, v.m_bindings);
+ seed = hash(seed, v.m_attributes);
+ return seed;
+ }
+
+ friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiVertexInputLayout &);
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiVertexInputLayout &);
+#endif
+
+class Q_GUI_EXPORT QRhiShaderStage
+{
+public:
+ enum Type {
+ Vertex,
+ TessellationControl,
+ TessellationEvaluation,
+ Geometry,
+ Fragment,
+ Compute
+ };
+
+ QRhiShaderStage() = default;
+ QRhiShaderStage(Type type, const QShader &shader,
+ QShader::Variant v = QShader::StandardShader);
+
+ Type type() const { return m_type; }
+ void setType(Type t) { m_type = t; }
+
+ QShader shader() const { return m_shader; }
+ void setShader(const QShader &s) { m_shader = s; }
+
+ QShader::Variant shaderVariant() const { return m_shaderVariant; }
+ void setShaderVariant(QShader::Variant v) { m_shaderVariant = v; }
+
+private:
+ Type m_type = Vertex;
+ QShader m_shader;
+ QShader::Variant m_shaderVariant = QShader::StandardShader;
+
+ friend bool operator==(const QRhiShaderStage &a, const QRhiShaderStage &b) noexcept
+ {
+ return a.m_type == b.m_type
+ && a.m_shader == b.m_shader
+ && a.m_shaderVariant == b.m_shaderVariant;
+ }
+
+ friend bool operator!=(const QRhiShaderStage &a, const QRhiShaderStage &b) noexcept
+ {
+ return !(a == b);
+ }
+
+ friend size_t qHash(const QRhiShaderStage &v, size_t seed = 0) noexcept
+ {
+ QtPrivate::QHashCombine hash;
+ seed = hash(seed, v.m_type);
+ seed = hash(seed, v.m_shader);
+ seed = hash(seed, v.m_shaderVariant);
+ return seed;
+ }
+};
+
+Q_DECLARE_TYPEINFO(QRhiShaderStage, Q_RELOCATABLE_TYPE);
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderStage &);
+#endif
+
+using QRhiGraphicsShaderStage = QRhiShaderStage;
+
+class Q_GUI_EXPORT QRhiShaderResourceBinding
+{
+public:
+ enum Type {
+ UniformBuffer,
+ SampledTexture,
+ Texture,
+ Sampler,
+ ImageLoad,
+ ImageStore,
+ ImageLoadStore,
+ BufferLoad,
+ BufferStore,
+ BufferLoadStore
+ };
+
+ enum StageFlag {
+ VertexStage = 1 << 0,
+ TessellationControlStage = 1 << 1,
+ TessellationEvaluationStage = 1 << 2,
+ GeometryStage = 1 << 3,
+ FragmentStage = 1 << 4,
+ ComputeStage = 1 << 5
+ };
+ Q_DECLARE_FLAGS(StageFlags, StageFlag)
+
+ QRhiShaderResourceBinding() = default;
+
+ bool isLayoutCompatible(const QRhiShaderResourceBinding &other) const;
+
+ static QRhiShaderResourceBinding uniformBuffer(int binding, StageFlags stage, QRhiBuffer *buf);
+ static QRhiShaderResourceBinding uniformBuffer(int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size);
+ static QRhiShaderResourceBinding uniformBufferWithDynamicOffset(int binding, StageFlags stage, QRhiBuffer *buf, quint32 size);
+
+ static QRhiShaderResourceBinding sampledTexture(int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler);
+
+ struct TextureAndSampler {
+ QRhiTexture *tex;
+ QRhiSampler *sampler;
+ };
+ static QRhiShaderResourceBinding sampledTextures(int binding, StageFlags stage, int count, const TextureAndSampler *texSamplers);
+
+ static QRhiShaderResourceBinding texture(int binding, StageFlags stage, QRhiTexture *tex);
+ static QRhiShaderResourceBinding textures(int binding, StageFlags stage, int count, QRhiTexture **tex);
+ static QRhiShaderResourceBinding sampler(int binding, StageFlags stage, QRhiSampler *sampler);
+
+ static QRhiShaderResourceBinding imageLoad(int binding, StageFlags stage, QRhiTexture *tex, int level);
+ static QRhiShaderResourceBinding imageStore(int binding, StageFlags stage, QRhiTexture *tex, int level);
+ static QRhiShaderResourceBinding imageLoadStore(int binding, StageFlags stage, QRhiTexture *tex, int level);
+
+ static QRhiShaderResourceBinding bufferLoad(int binding, StageFlags stage, QRhiBuffer *buf);
+ static QRhiShaderResourceBinding bufferLoad(int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size);
+ static QRhiShaderResourceBinding bufferStore(int binding, StageFlags stage, QRhiBuffer *buf);
+ static QRhiShaderResourceBinding bufferStore(int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size);
+ static QRhiShaderResourceBinding bufferLoadStore(int binding, StageFlags stage, QRhiBuffer *buf);
+ static QRhiShaderResourceBinding bufferLoadStore(int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size);
+
+ struct Data
+ {
+ int binding;
+ QRhiShaderResourceBinding::StageFlags stage;
+ QRhiShaderResourceBinding::Type type;
+ struct UniformBufferData {
+ QRhiBuffer *buf;
+ quint32 offset;
+ quint32 maybeSize;
+ bool hasDynamicOffset;
+ };
+ static constexpr int MAX_TEX_SAMPLER_ARRAY_SIZE = 16;
+ struct TextureAndOrSamplerData {
+ int count;
+ TextureAndSampler texSamplers[MAX_TEX_SAMPLER_ARRAY_SIZE];
+ };
+ struct StorageImageData {
+ QRhiTexture *tex;
+ int level;
+ };
+ struct StorageBufferData {
+ QRhiBuffer *buf;
+ quint32 offset;
+ quint32 maybeSize;
+ };
+ union {
+ UniformBufferData ubuf;
+ TextureAndOrSamplerData stex;
+ StorageImageData simage;
+ StorageBufferData sbuf;
+ } u;
+
+ int arraySize() const
+ {
+ return type == QRhiShaderResourceBinding::SampledTexture || type == QRhiShaderResourceBinding::Texture
+ ? u.stex.count
+ : 1;
+ }
+
+ template<typename Output>
+ Output serialize(Output dst) const
+ {
+ // must write out exactly LAYOUT_DESC_ENTRIES_PER_BINDING elements here
+ *dst++ = quint32(binding);
+ *dst++ = quint32(stage);
+ *dst++ = quint32(type);
+ *dst++ = quint32(arraySize());
+ return dst;
+ }
+ };
+
+ static constexpr int LAYOUT_DESC_ENTRIES_PER_BINDING = 4;
+
+ template<typename Output>
+ static void serializeLayoutDescription(const QRhiShaderResourceBinding *first,
+ const QRhiShaderResourceBinding *last,
+ Output dst)
+ {
+ while (first != last) {
+ dst = first->d.serialize(dst);
+ ++first;
+ }
+ }
+
+private:
+ Data d;
+ friend class QRhiImplementation;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiShaderResourceBinding::StageFlags)
+
+Q_DECLARE_TYPEINFO(QRhiShaderResourceBinding, Q_PRIMITIVE_TYPE);
+
+Q_GUI_EXPORT bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) noexcept;
+Q_GUI_EXPORT bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) noexcept;
+Q_GUI_EXPORT size_t qHash(const QRhiShaderResourceBinding &b, size_t seed = 0) noexcept;
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBinding &);
+#endif
+
+class Q_GUI_EXPORT QRhiColorAttachment
+{
+public:
+ QRhiColorAttachment() = default;
+ QRhiColorAttachment(QRhiTexture *texture);
+ QRhiColorAttachment(QRhiRenderBuffer *renderBuffer);
+
+ QRhiTexture *texture() const { return m_texture; }
+ void setTexture(QRhiTexture *tex) { m_texture = tex; }
+
+ QRhiRenderBuffer *renderBuffer() const { return m_renderBuffer; }
+ void setRenderBuffer(QRhiRenderBuffer *rb) { m_renderBuffer = rb; }
+
+ int layer() const { return m_layer; }
+ void setLayer(int layer) { m_layer = layer; }
+
+ int level() const { return m_level; }
+ void setLevel(int level) { m_level = level; }
+
+ QRhiTexture *resolveTexture() const { return m_resolveTexture; }
+ void setResolveTexture(QRhiTexture *tex) { m_resolveTexture = tex; }
+
+ int resolveLayer() const { return m_resolveLayer; }
+ void setResolveLayer(int layer) { m_resolveLayer = layer; }
+
+ int resolveLevel() const { return m_resolveLevel; }
+ void setResolveLevel(int level) { m_resolveLevel = level; }
+
+ int multiViewCount() const { return m_multiViewCount; }
+ void setMultiViewCount(int count) { m_multiViewCount = count; }
+
+private:
+ QRhiTexture *m_texture = nullptr;
+ QRhiRenderBuffer *m_renderBuffer = nullptr;
+ int m_layer = 0;
+ int m_level = 0;
+ QRhiTexture *m_resolveTexture = nullptr;
+ int m_resolveLayer = 0;
+ int m_resolveLevel = 0;
+ int m_multiViewCount = 0;
+};
+
+Q_DECLARE_TYPEINFO(QRhiColorAttachment, Q_RELOCATABLE_TYPE);
+
+class Q_GUI_EXPORT QRhiTextureRenderTargetDescription
+{
+public:
+ QRhiTextureRenderTargetDescription() = default;
+ QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment);
+ QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment, QRhiRenderBuffer *depthStencilBuffer);
+ QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment, QRhiTexture *depthTexture);
+
+ void setColorAttachments(std::initializer_list<QRhiColorAttachment> list) { m_colorAttachments = list; }
+ template<typename InputIterator>
+ void setColorAttachments(InputIterator first, InputIterator last)
+ {
+ m_colorAttachments.clear();
+ std::copy(first, last, std::back_inserter(m_colorAttachments));
+ }
+ const QRhiColorAttachment *cbeginColorAttachments() const { return m_colorAttachments.cbegin(); }
+ const QRhiColorAttachment *cendColorAttachments() const { return m_colorAttachments.cend(); }
+ const QRhiColorAttachment *colorAttachmentAt(qsizetype index) const { return &m_colorAttachments.at(index); }
+ qsizetype colorAttachmentCount() const { return m_colorAttachments.count(); }
+
+ QRhiRenderBuffer *depthStencilBuffer() const { return m_depthStencilBuffer; }
+ void setDepthStencilBuffer(QRhiRenderBuffer *renderBuffer) { m_depthStencilBuffer = renderBuffer; }
+
+ QRhiTexture *depthTexture() const { return m_depthTexture; }
+ void setDepthTexture(QRhiTexture *texture) { m_depthTexture = texture; }
+
+ QRhiTexture *depthResolveTexture() const { return m_depthResolveTexture; }
+ void setDepthResolveTexture(QRhiTexture *tex) { m_depthResolveTexture = tex; }
+
+private:
+ QVarLengthArray<QRhiColorAttachment, 8> m_colorAttachments;
+ QRhiRenderBuffer *m_depthStencilBuffer = nullptr;
+ QRhiTexture *m_depthTexture = nullptr;
+ QRhiTexture *m_depthResolveTexture = nullptr;
+};
+
+class Q_GUI_EXPORT QRhiTextureSubresourceUploadDescription
+{
+public:
+ QRhiTextureSubresourceUploadDescription() = default;
+ explicit QRhiTextureSubresourceUploadDescription(const QImage &image);
+ QRhiTextureSubresourceUploadDescription(const void *data, quint32 size);
+ explicit QRhiTextureSubresourceUploadDescription(const QByteArray &data);
+
+ QImage image() const { return m_image; }
+ void setImage(const QImage &image) { m_image = image; }
+
+ QByteArray data() const { return m_data; }
+ void setData(const QByteArray &data) { m_data = data; }
+
+ quint32 dataStride() const { return m_dataStride; }
+ void setDataStride(quint32 stride) { m_dataStride = stride; }
+
+ QPoint destinationTopLeft() const { return m_destinationTopLeft; }
+ void setDestinationTopLeft(const QPoint &p) { m_destinationTopLeft = p; }
+
+ QSize sourceSize() const { return m_sourceSize; }
+ void setSourceSize(const QSize &size) { m_sourceSize = size; }
+
+ QPoint sourceTopLeft() const { return m_sourceTopLeft; }
+ void setSourceTopLeft(const QPoint &p) { m_sourceTopLeft = p; }
+
+private:
+ QImage m_image;
+ QByteArray m_data;
+ quint32 m_dataStride = 0;
+ QPoint m_destinationTopLeft;
+ QSize m_sourceSize;
+ QPoint m_sourceTopLeft;
+};
+
+Q_DECLARE_TYPEINFO(QRhiTextureSubresourceUploadDescription, Q_RELOCATABLE_TYPE);
+
+class Q_GUI_EXPORT QRhiTextureUploadEntry
+{
+public:
+ QRhiTextureUploadEntry() = default;
+ QRhiTextureUploadEntry(int layer, int level, const QRhiTextureSubresourceUploadDescription &desc);
+
+ int layer() const { return m_layer; }
+ void setLayer(int layer) { m_layer = layer; }
+
+ int level() const { return m_level; }
+ void setLevel(int level) { m_level = level; }
+
+ QRhiTextureSubresourceUploadDescription description() const { return m_desc; }
+ void setDescription(const QRhiTextureSubresourceUploadDescription &desc) { m_desc = desc; }
+
+private:
+ int m_layer = 0;
+ int m_level = 0;
+ QRhiTextureSubresourceUploadDescription m_desc;
+};
+
+Q_DECLARE_TYPEINFO(QRhiTextureUploadEntry, Q_RELOCATABLE_TYPE);
+
+class Q_GUI_EXPORT QRhiTextureUploadDescription
+{
+public:
+ QRhiTextureUploadDescription() = default;
+ QRhiTextureUploadDescription(const QRhiTextureUploadEntry &entry);
+ QRhiTextureUploadDescription(std::initializer_list<QRhiTextureUploadEntry> list);
+
+ void setEntries(std::initializer_list<QRhiTextureUploadEntry> list) { m_entries = list; }
+ template<typename InputIterator>
+ void setEntries(InputIterator first, InputIterator last)
+ {
+ m_entries.clear();
+ std::copy(first, last, std::back_inserter(m_entries));
+ }
+ const QRhiTextureUploadEntry *cbeginEntries() const { return m_entries.cbegin(); }
+ const QRhiTextureUploadEntry *cendEntries() const { return m_entries.cend(); }
+ const QRhiTextureUploadEntry *entryAt(qsizetype index) const { return &m_entries.at(index); }
+ qsizetype entryCount() const { return m_entries.count(); }
+
+private:
+ QVarLengthArray<QRhiTextureUploadEntry, 16> m_entries;
+};
+
+class Q_GUI_EXPORT QRhiTextureCopyDescription
+{
+public:
+ QRhiTextureCopyDescription() = default;
+
+ QSize pixelSize() const { return m_pixelSize; }
+ void setPixelSize(const QSize &sz) { m_pixelSize = sz; }
+
+ int sourceLayer() const { return m_sourceLayer; }
+ void setSourceLayer(int layer) { m_sourceLayer = layer; }
+
+ int sourceLevel() const { return m_sourceLevel; }
+ void setSourceLevel(int level) { m_sourceLevel = level; }
+
+ QPoint sourceTopLeft() const { return m_sourceTopLeft; }
+ void setSourceTopLeft(const QPoint &p) { m_sourceTopLeft = p; }
+
+ int destinationLayer() const { return m_destinationLayer; }
+ void setDestinationLayer(int layer) { m_destinationLayer = layer; }
+
+ int destinationLevel() const { return m_destinationLevel; }
+ void setDestinationLevel(int level) { m_destinationLevel = level; }
+
+ QPoint destinationTopLeft() const { return m_destinationTopLeft; }
+ void setDestinationTopLeft(const QPoint &p) { m_destinationTopLeft = p; }
+
+private:
+ QSize m_pixelSize;
+ int m_sourceLayer = 0;
+ int m_sourceLevel = 0;
+ QPoint m_sourceTopLeft;
+ int m_destinationLayer = 0;
+ int m_destinationLevel = 0;
+ QPoint m_destinationTopLeft;
+};
+
+Q_DECLARE_TYPEINFO(QRhiTextureCopyDescription, Q_RELOCATABLE_TYPE);
+
+class Q_GUI_EXPORT QRhiReadbackDescription
+{
+public:
+ QRhiReadbackDescription() = default;
+ QRhiReadbackDescription(QRhiTexture *texture);
+
+ QRhiTexture *texture() const { return m_texture; }
+ void setTexture(QRhiTexture *tex) { m_texture = tex; }
+
+ int layer() const { return m_layer; }
+ void setLayer(int layer) { m_layer = layer; }
+
+ int level() const { return m_level; }
+ void setLevel(int level) { m_level = level; }
+
+private:
+ QRhiTexture *m_texture = nullptr;
+ int m_layer = 0;
+ int m_level = 0;
+};
+
+Q_DECLARE_TYPEINFO(QRhiReadbackDescription, Q_RELOCATABLE_TYPE);
+
+struct Q_GUI_EXPORT QRhiNativeHandles
+{
+};
+
+class Q_GUI_EXPORT QRhiResource
+{
+public:
+ enum Type {
+ Buffer,
+ Texture,
+ Sampler,
+ RenderBuffer,
+ RenderPassDescriptor,
+ SwapChainRenderTarget,
+ TextureRenderTarget,
+ ShaderResourceBindings,
+ GraphicsPipeline,
+ SwapChain,
+ ComputePipeline,
+ CommandBuffer
+ };
+
+ virtual ~QRhiResource();
+
+ virtual Type resourceType() const = 0;
+
+ virtual void destroy() = 0;
+
+ void deleteLater();
+
+ QByteArray name() const;
+ void setName(const QByteArray &name);
+
+ quint64 globalResourceId() const;
+
+ QRhi *rhi() const;
+
+protected:
+ QRhiResource(QRhiImplementation *rhi);
+ Q_DISABLE_COPY(QRhiResource)
+ friend class QRhiImplementation;
+ QRhiImplementation *m_rhi = nullptr;
+ quint64 m_id;
+ QByteArray m_objectName;
+};
+
+class Q_GUI_EXPORT QRhiBuffer : public QRhiResource
+{
+public:
+ enum Type {
+ Immutable,
+ Static,
+ Dynamic
+ };
+
+ enum UsageFlag {
+ VertexBuffer = 1 << 0,
+ IndexBuffer = 1 << 1,
+ UniformBuffer = 1 << 2,
+ StorageBuffer = 1 << 3
+ };
+ Q_DECLARE_FLAGS(UsageFlags, UsageFlag)
+
+ struct NativeBuffer {
+ const void *objects[3];
+ int slotCount;
+ };
+
+ QRhiResource::Type resourceType() const override;
+
+ Type type() const { return m_type; }
+ void setType(Type t) { m_type = t; }
+
+ UsageFlags usage() const { return m_usage; }
+ void setUsage(UsageFlags u) { m_usage = u; }
+
+ quint32 size() const { return m_size; }
+ void setSize(quint32 sz) { m_size = sz; }
+
+ virtual bool create() = 0;
+
+ virtual NativeBuffer nativeBuffer();
+
+ virtual char *beginFullDynamicBufferUpdateForCurrentFrame();
+ virtual void endFullDynamicBufferUpdateForCurrentFrame();
+
+protected:
+ QRhiBuffer(QRhiImplementation *rhi, Type type_, UsageFlags usage_, quint32 size_);
+ Type m_type;
+ UsageFlags m_usage;
+ quint32 m_size;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiBuffer::UsageFlags)
+
+class Q_GUI_EXPORT QRhiTexture : public QRhiResource
+{
+public:
+ enum Flag {
+ RenderTarget = 1 << 0,
+ CubeMap = 1 << 2,
+ MipMapped = 1 << 3,
+ sRGB = 1 << 4,
+ UsedAsTransferSource = 1 << 5,
+ UsedWithGenerateMips = 1 << 6,
+ UsedWithLoadStore = 1 << 7,
+ UsedAsCompressedAtlas = 1 << 8,
+ ExternalOES = 1 << 9,
+ ThreeDimensional = 1 << 10,
+ TextureRectangleGL = 1 << 11,
+ TextureArray = 1 << 12,
+ OneDimensional = 1 << 13
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ enum Format {
+ UnknownFormat,
+
+ RGBA8,
+ BGRA8,
+ R8,
+ RG8,
+ R16,
+ RG16,
+ RED_OR_ALPHA8,
+
+ RGBA16F,
+ RGBA32F,
+ R16F,
+ R32F,
+
+ RGB10A2,
+
+ D16,
+ D24,
+ D24S8,
+ D32F,
+
+ BC1,
+ BC2,
+ BC3,
+ BC4,
+ BC5,
+ BC6H,
+ BC7,
+
+ ETC2_RGB8,
+ ETC2_RGB8A1,
+ ETC2_RGBA8,
+
+ ASTC_4x4,
+ ASTC_5x4,
+ ASTC_5x5,
+ ASTC_6x5,
+ ASTC_6x6,
+ ASTC_8x5,
+ ASTC_8x6,
+ ASTC_8x8,
+ ASTC_10x5,
+ ASTC_10x6,
+ ASTC_10x8,
+ ASTC_10x10,
+ ASTC_12x10,
+ ASTC_12x12
+ };
+
+ struct NativeTexture {
+ quint64 object;
+ int layout; // or state
+ };
+
+ QRhiResource::Type resourceType() const override;
+
+ Format format() const { return m_format; }
+ void setFormat(Format fmt) { m_format = fmt; }
+
+ QSize pixelSize() const { return m_pixelSize; }
+ void setPixelSize(const QSize &sz) { m_pixelSize = sz; }
+
+ int depth() const { return m_depth; }
+ void setDepth(int depth) { m_depth = depth; }
+
+ int arraySize() const { return m_arraySize; }
+ void setArraySize(int arraySize) { m_arraySize = arraySize; }
+
+ int arrayRangeStart() const { return m_arrayRangeStart; }
+ int arrayRangeLength() const { return m_arrayRangeLength; }
+ void setArrayRange(int startIndex, int count)
+ {
+ m_arrayRangeStart = startIndex;
+ m_arrayRangeLength = count;
+ }
+
+ Flags flags() const { return m_flags; }
+ void setFlags(Flags f) { m_flags = f; }
+
+ int sampleCount() const { return m_sampleCount; }
+ void setSampleCount(int s) { m_sampleCount = s; }
+
+ struct ViewFormat {
+ QRhiTexture::Format format;
+ bool srgb;
+ };
+ ViewFormat readViewFormat() const { return m_readViewFormat; }
+ void setReadViewFormat(const ViewFormat &fmt) { m_readViewFormat = fmt; }
+ ViewFormat writeViewFormat() const { return m_writeViewFormat; }
+ void setWriteViewFormat(const ViewFormat &fmt) { m_writeViewFormat = fmt; }
+
+ virtual bool create() = 0;
+ virtual NativeTexture nativeTexture();
+ virtual bool createFrom(NativeTexture src);
+ virtual void setNativeLayout(int layout);
+
+protected:
+ QRhiTexture(QRhiImplementation *rhi, Format format_, const QSize &pixelSize_, int depth_,
+ int arraySize_, int sampleCount_, Flags flags_);
+ Format m_format;
+ QSize m_pixelSize;
+ int m_depth;
+ int m_arraySize;
+ int m_sampleCount;
+ Flags m_flags;
+ int m_arrayRangeStart = -1;
+ int m_arrayRangeLength = -1;
+ ViewFormat m_readViewFormat = { UnknownFormat, false };
+ ViewFormat m_writeViewFormat = { UnknownFormat, false };
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiTexture::Flags)
+
+class Q_GUI_EXPORT QRhiSampler : public QRhiResource
+{
+public:
+ enum Filter {
+ None,
+ Nearest,
+ Linear
+ };
+
+ enum AddressMode {
+ Repeat,
+ ClampToEdge,
+ Mirror,
+ };
+
+ enum CompareOp {
+ Never,
+ Less,
+ Equal,
+ LessOrEqual,
+ Greater,
+ NotEqual,
+ GreaterOrEqual,
+ Always
+ };
+
+ QRhiResource::Type resourceType() const override;
+
+ Filter magFilter() const { return m_magFilter; }
+ void setMagFilter(Filter f) { m_magFilter = f; }
+
+ Filter minFilter() const { return m_minFilter; }
+ void setMinFilter(Filter f) { m_minFilter = f; }
+
+ Filter mipmapMode() const { return m_mipmapMode; }
+ void setMipmapMode(Filter f) { m_mipmapMode = f; }
+
+ AddressMode addressU() const { return m_addressU; }
+ void setAddressU(AddressMode mode) { m_addressU = mode; }
+
+ AddressMode addressV() const { return m_addressV; }
+ void setAddressV(AddressMode mode) { m_addressV = mode; }
+
+ AddressMode addressW() const { return m_addressW; }
+ void setAddressW(AddressMode mode) { m_addressW = mode; }
+
+ CompareOp textureCompareOp() const { return m_compareOp; }
+ void setTextureCompareOp(CompareOp op) { m_compareOp = op; }
+
+ virtual bool create() = 0;
+
+protected:
+ QRhiSampler(QRhiImplementation *rhi,
+ Filter magFilter_, Filter minFilter_, Filter mipmapMode_,
+ AddressMode u_, AddressMode v_, AddressMode w_);
+ Filter m_magFilter;
+ Filter m_minFilter;
+ Filter m_mipmapMode;
+ AddressMode m_addressU;
+ AddressMode m_addressV;
+ AddressMode m_addressW;
+ CompareOp m_compareOp;
+};
+
+class Q_GUI_EXPORT QRhiRenderBuffer : public QRhiResource
+{
+public:
+ enum Type {
+ DepthStencil,
+ Color
+ };
+
+ enum Flag {
+ UsedWithSwapChainOnly = 1 << 0
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ struct NativeRenderBuffer {
+ quint64 object;
+ };
+
+ QRhiResource::Type resourceType() const override;
+
+ Type type() const { return m_type; }
+ void setType(Type t) { m_type = t; }
+
+ QSize pixelSize() const { return m_pixelSize; }
+ void setPixelSize(const QSize &sz) { m_pixelSize = sz; }
+
+ int sampleCount() const { return m_sampleCount; }
+ void setSampleCount(int s) { m_sampleCount = s; }
+
+ Flags flags() const { return m_flags; }
+ void setFlags(Flags f) { m_flags = f; }
+
+ virtual bool create() = 0;
+ virtual bool createFrom(NativeRenderBuffer src);
+
+ virtual QRhiTexture::Format backingFormat() const = 0;
+
+protected:
+ QRhiRenderBuffer(QRhiImplementation *rhi, Type type_, const QSize &pixelSize_,
+ int sampleCount_, Flags flags_, QRhiTexture::Format backingFormatHint_);
+ Type m_type;
+ QSize m_pixelSize;
+ int m_sampleCount;
+ Flags m_flags;
+ QRhiTexture::Format m_backingFormatHint;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiRenderBuffer::Flags)
+
+class Q_GUI_EXPORT QRhiRenderPassDescriptor : public QRhiResource
+{
+public:
+ QRhiResource::Type resourceType() const override;
+
+ virtual bool isCompatible(const QRhiRenderPassDescriptor *other) const = 0;
+ virtual const QRhiNativeHandles *nativeHandles();
+
+ virtual QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const = 0;
+
+ virtual QVector<quint32> serializedFormat() const = 0;
+
+protected:
+ QRhiRenderPassDescriptor(QRhiImplementation *rhi);
+};
+
+class Q_GUI_EXPORT QRhiRenderTarget : public QRhiResource
+{
+public:
+ virtual QSize pixelSize() const = 0;
+ virtual float devicePixelRatio() const = 0;
+ virtual int sampleCount() const = 0;
+
+ QRhiRenderPassDescriptor *renderPassDescriptor() const { return m_renderPassDesc; }
+ void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc) { m_renderPassDesc = desc; }
+
+protected:
+ QRhiRenderTarget(QRhiImplementation *rhi);
+ QRhiRenderPassDescriptor *m_renderPassDesc = nullptr;
+};
+
+class Q_GUI_EXPORT QRhiSwapChainRenderTarget : public QRhiRenderTarget
+{
+public:
+ QRhiResource::Type resourceType() const override;
+ QRhiSwapChain *swapChain() const { return m_swapchain; }
+
+protected:
+ QRhiSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain_);
+ QRhiSwapChain *m_swapchain;
+};
+
+class Q_GUI_EXPORT QRhiTextureRenderTarget : public QRhiRenderTarget
+{
+public:
+ enum Flag {
+ PreserveColorContents = 1 << 0,
+ PreserveDepthStencilContents = 1 << 1,
+ DoNotStoreDepthStencilContents = 1 << 2
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ QRhiResource::Type resourceType() const override;
+
+ QRhiTextureRenderTargetDescription description() const { return m_desc; }
+ void setDescription(const QRhiTextureRenderTargetDescription &desc) { m_desc = desc; }
+
+ Flags flags() const { return m_flags; }
+ void setFlags(Flags f) { m_flags = f; }
+
+ virtual QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() = 0;
+
+ virtual bool create() = 0;
+
+protected:
+ QRhiTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc_, Flags flags_);
+ QRhiTextureRenderTargetDescription m_desc;
+ Flags m_flags;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiTextureRenderTarget::Flags)
+
+class Q_GUI_EXPORT QRhiShaderResourceBindings : public QRhiResource
+{
+public:
+ QRhiResource::Type resourceType() const override;
+
+ void setBindings(std::initializer_list<QRhiShaderResourceBinding> list) { m_bindings = list; }
+ template<typename InputIterator>
+ void setBindings(InputIterator first, InputIterator last)
+ {
+ m_bindings.clear();
+ std::copy(first, last, std::back_inserter(m_bindings));
+ }
+ const QRhiShaderResourceBinding *cbeginBindings() const { return m_bindings.cbegin(); }
+ const QRhiShaderResourceBinding *cendBindings() const { return m_bindings.cend(); }
+ const QRhiShaderResourceBinding *bindingAt(qsizetype index) const { return &m_bindings.at(index); }
+ qsizetype bindingCount() const { return m_bindings.count(); }
+
+ bool isLayoutCompatible(const QRhiShaderResourceBindings *other) const;
+
+ QVector<quint32> serializedLayoutDescription() const { return m_layoutDesc; }
+
+ virtual bool create() = 0;
+
+ enum UpdateFlag {
+ BindingsAreSorted = 0x01
+ };
+ Q_DECLARE_FLAGS(UpdateFlags, UpdateFlag)
+
+ virtual void updateResources(UpdateFlags flags = {}) = 0;
+
+protected:
+ static constexpr int BINDING_PREALLOC = 12;
+ QRhiShaderResourceBindings(QRhiImplementation *rhi);
+ QVarLengthArray<QRhiShaderResourceBinding, BINDING_PREALLOC> m_bindings;
+ size_t m_layoutDescHash = 0;
+ // Intentionally not using QVLA for m_layoutDesc: clients like Qt Quick are much
+ // better served with an implicitly shared container here, because they will likely
+ // throw this directly into structs serving as cache keys.
+ QVector<quint32> m_layoutDesc;
+ friend class QRhiImplementation;
+#ifndef QT_NO_DEBUG_STREAM
+ friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBindings &);
+#endif
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiShaderResourceBindings::UpdateFlags)
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBindings &);
+#endif
+
+// The proper name. Until it gets rolled out universally, have the better name
+// as a typedef. Eventually it should be reversed (the old name being a typedef
+// to the new one).
+using QRhiShaderResourceBindingSet = QRhiShaderResourceBindings;
+
+class Q_GUI_EXPORT QRhiGraphicsPipeline : public QRhiResource
+{
+public:
+ enum Flag {
+ UsesBlendConstants = 1 << 0,
+ UsesStencilRef = 1 << 1,
+ UsesScissor = 1 << 2,
+ CompileShadersWithDebugInfo = 1 << 3
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ enum Topology {
+ Triangles,
+ TriangleStrip,
+ TriangleFan,
+ Lines,
+ LineStrip,
+ Points,
+ Patches
+ };
+
+ enum CullMode {
+ None,
+ Front,
+ Back
+ };
+
+ enum FrontFace {
+ CCW,
+ CW
+ };
+
+ enum ColorMaskComponent {
+ R = 1 << 0,
+ G = 1 << 1,
+ B = 1 << 2,
+ A = 1 << 3
+ };
+ Q_DECLARE_FLAGS(ColorMask, ColorMaskComponent)
+
+ enum BlendFactor {
+ Zero,
+ One,
+ SrcColor,
+ OneMinusSrcColor,
+ DstColor,
+ OneMinusDstColor,
+ SrcAlpha,
+ OneMinusSrcAlpha,
+ DstAlpha,
+ OneMinusDstAlpha,
+ ConstantColor,
+ OneMinusConstantColor,
+ ConstantAlpha,
+ OneMinusConstantAlpha,
+ SrcAlphaSaturate,
+ Src1Color,
+ OneMinusSrc1Color,
+ Src1Alpha,
+ OneMinusSrc1Alpha
+ };
+
+ enum BlendOp {
+ Add,
+ Subtract,
+ ReverseSubtract,
+ Min,
+ Max
+ };
+
+ struct TargetBlend {
+ ColorMask colorWrite = ColorMask(0xF); // R | G | B | A
+ bool enable = false;
+ BlendFactor srcColor = One;
+ BlendFactor dstColor = OneMinusSrcAlpha;
+ BlendOp opColor = Add;
+ BlendFactor srcAlpha = One;
+ BlendFactor dstAlpha = OneMinusSrcAlpha;
+ BlendOp opAlpha = Add;
+ };
+
+ enum CompareOp {
+ Never,
+ Less,
+ Equal,
+ LessOrEqual,
+ Greater,
+ NotEqual,
+ GreaterOrEqual,
+ Always
+ };
+
+ enum StencilOp {
+ StencilZero,
+ Keep,
+ Replace,
+ IncrementAndClamp,
+ DecrementAndClamp,
+ Invert,
+ IncrementAndWrap,
+ DecrementAndWrap
+ };
+
+ struct StencilOpState {
+ StencilOp failOp = Keep;
+ StencilOp depthFailOp = Keep;
+ StencilOp passOp = Keep;
+ CompareOp compareOp = Always;
+ };
+
+ enum PolygonMode {
+ Fill,
+ Line
+ };
+
+ QRhiResource::Type resourceType() const override;
+
+ Flags flags() const { return m_flags; }
+ void setFlags(Flags f) { m_flags = f; }
+
+ Topology topology() const { return m_topology; }
+ void setTopology(Topology t) { m_topology = t; }
+
+ CullMode cullMode() const { return m_cullMode; }
+ void setCullMode(CullMode mode) { m_cullMode = mode; }
+
+ FrontFace frontFace() const { return m_frontFace; }
+ void setFrontFace(FrontFace f) { m_frontFace = f; }
+
+ void setTargetBlends(std::initializer_list<TargetBlend> list) { m_targetBlends = list; }
+ template<typename InputIterator>
+ void setTargetBlends(InputIterator first, InputIterator last)
+ {
+ m_targetBlends.clear();
+ std::copy(first, last, std::back_inserter(m_targetBlends));
+ }
+ const TargetBlend *cbeginTargetBlends() const { return m_targetBlends.cbegin(); }
+ const TargetBlend *cendTargetBlends() const { return m_targetBlends.cend(); }
+ const TargetBlend *targetBlendAt(qsizetype index) const { return &m_targetBlends.at(index); }
+ qsizetype targetBlendCount() const { return m_targetBlends.count(); }
+
+ bool hasDepthTest() const { return m_depthTest; }
+ void setDepthTest(bool enable) { m_depthTest = enable; }
+
+ bool hasDepthWrite() const { return m_depthWrite; }
+ void setDepthWrite(bool enable) { m_depthWrite = enable; }
+
+ CompareOp depthOp() const { return m_depthOp; }
+ void setDepthOp(CompareOp op) { m_depthOp = op; }
+
+ bool hasStencilTest() const { return m_stencilTest; }
+ void setStencilTest(bool enable) { m_stencilTest = enable; }
+
+ StencilOpState stencilFront() const { return m_stencilFront; }
+ void setStencilFront(const StencilOpState &state) { m_stencilFront = state; }
+
+ StencilOpState stencilBack() const { return m_stencilBack; }
+ void setStencilBack(const StencilOpState &state) { m_stencilBack = state; }
+
+ quint32 stencilReadMask() const { return m_stencilReadMask; }
+ void setStencilReadMask(quint32 mask) { m_stencilReadMask = mask; }
+
+ quint32 stencilWriteMask() const { return m_stencilWriteMask; }
+ void setStencilWriteMask(quint32 mask) { m_stencilWriteMask = mask; }
+
+ int sampleCount() const { return m_sampleCount; }
+ void setSampleCount(int s) { m_sampleCount = s; }
+
+ float lineWidth() const { return m_lineWidth; }
+ void setLineWidth(float width) { m_lineWidth = width; }
+
+ int depthBias() const { return m_depthBias; }
+ void setDepthBias(int bias) { m_depthBias = bias; }
+
+ float slopeScaledDepthBias() const { return m_slopeScaledDepthBias; }
+ void setSlopeScaledDepthBias(float bias) { m_slopeScaledDepthBias = bias; }
+
+ void setShaderStages(std::initializer_list<QRhiShaderStage> list) { m_shaderStages = list; }
+ template<typename InputIterator>
+ void setShaderStages(InputIterator first, InputIterator last)
+ {
+ m_shaderStages.clear();
+ std::copy(first, last, std::back_inserter(m_shaderStages));
+ }
+ const QRhiShaderStage *cbeginShaderStages() const { return m_shaderStages.cbegin(); }
+ const QRhiShaderStage *cendShaderStages() const { return m_shaderStages.cend(); }
+ const QRhiShaderStage *shaderStageAt(qsizetype index) const { return &m_shaderStages.at(index); }
+ qsizetype shaderStageCount() const { return m_shaderStages.count(); }
+
+ QRhiVertexInputLayout vertexInputLayout() const { return m_vertexInputLayout; }
+ void setVertexInputLayout(const QRhiVertexInputLayout &layout) { m_vertexInputLayout = layout; }
+
+ QRhiShaderResourceBindings *shaderResourceBindings() const { return m_shaderResourceBindings; }
+ void setShaderResourceBindings(QRhiShaderResourceBindings *srb) { m_shaderResourceBindings = srb; }
+
+ QRhiRenderPassDescriptor *renderPassDescriptor() const { return m_renderPassDesc; }
+ void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc) { m_renderPassDesc = desc; }
+
+ int patchControlPointCount() const { return m_patchControlPointCount; }
+ void setPatchControlPointCount(int count) { m_patchControlPointCount = count; }
+
+ PolygonMode polygonMode() const {return m_polygonMode; }
+ void setPolygonMode(PolygonMode mode) {m_polygonMode = mode; }
+
+ int multiViewCount() const { return m_multiViewCount; }
+ void setMultiViewCount(int count) { m_multiViewCount = count; }
+
+ virtual bool create() = 0;
+
+protected:
+ QRhiGraphicsPipeline(QRhiImplementation *rhi);
+ Flags m_flags;
+ Topology m_topology = Triangles;
+ CullMode m_cullMode = None;
+ FrontFace m_frontFace = CCW;
+ QVarLengthArray<TargetBlend, 8> m_targetBlends;
+ bool m_depthTest = false;
+ bool m_depthWrite = false;
+ CompareOp m_depthOp = Less;
+ bool m_stencilTest = false;
+ StencilOpState m_stencilFront;
+ StencilOpState m_stencilBack;
+ quint32 m_stencilReadMask = 0xFF;
+ quint32 m_stencilWriteMask = 0xFF;
+ int m_sampleCount = 1;
+ float m_lineWidth = 1.0f;
+ int m_depthBias = 0;
+ float m_slopeScaledDepthBias = 0.0f;
+ int m_patchControlPointCount = 3;
+ PolygonMode m_polygonMode = Fill;
+ int m_multiViewCount = 0;
+ QVarLengthArray<QRhiShaderStage, 4> m_shaderStages;
+ QRhiVertexInputLayout m_vertexInputLayout;
+ QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr;
+ QRhiRenderPassDescriptor *m_renderPassDesc = nullptr;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiGraphicsPipeline::Flags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiGraphicsPipeline::ColorMask)
+Q_DECLARE_TYPEINFO(QRhiGraphicsPipeline::TargetBlend, Q_RELOCATABLE_TYPE);
+
+struct QRhiSwapChainHdrInfo
+{
+ enum LimitsType {
+ LuminanceInNits,
+ ColorComponentValue
+ };
+
+ enum LuminanceBehavior {
+ SceneReferred,
+ DisplayReferred
+ };
+
+ LimitsType limitsType;
+ union {
+ struct {
+ float minLuminance;
+ float maxLuminance;
+ } luminanceInNits;
+ struct {
+ float maxColorComponentValue;
+ float maxPotentialColorComponentValue;
+ } colorComponentValue;
+ } limits;
+ LuminanceBehavior luminanceBehavior;
+ float sdrWhiteLevel;
+};
+
+Q_DECLARE_TYPEINFO(QRhiSwapChainHdrInfo, Q_RELOCATABLE_TYPE);
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiSwapChainHdrInfo &);
+#endif
+
+struct QRhiSwapChainProxyData
+{
+ void *reserved[2] = {};
+};
+
+class Q_GUI_EXPORT QRhiSwapChain : public QRhiResource
+{
+public:
+ enum Flag {
+ SurfaceHasPreMulAlpha = 1 << 0,
+ SurfaceHasNonPreMulAlpha = 1 << 1,
+ sRGB = 1 << 2,
+ UsedAsTransferSource = 1 << 3,
+ NoVSync = 1 << 4,
+ MinimalBufferCount = 1 << 5
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ enum Format {
+ SDR,
+ HDRExtendedSrgbLinear,
+ HDR10,
+ HDRExtendedDisplayP3Linear
+ };
+
+ enum StereoTargetBuffer {
+ LeftBuffer,
+ RightBuffer
+ };
+
+ QRhiResource::Type resourceType() const override;
+
+ QWindow *window() const { return m_window; }
+ void setWindow(QWindow *window) { m_window = window; }
+
+ QRhiSwapChainProxyData proxyData() const { return m_proxyData; }
+ void setProxyData(const QRhiSwapChainProxyData &d) { m_proxyData = d; }
+
+ Flags flags() const { return m_flags; }
+ void setFlags(Flags f) { m_flags = f; }
+
+ Format format() const { return m_format; }
+ void setFormat(Format f) { m_format = f; }
+
+ QRhiRenderBuffer *depthStencil() const { return m_depthStencil; }
+ void setDepthStencil(QRhiRenderBuffer *ds) { m_depthStencil = ds; }
+
+ int sampleCount() const { return m_sampleCount; }
+ void setSampleCount(int samples) { m_sampleCount = samples; }
+
+ QRhiRenderPassDescriptor *renderPassDescriptor() const { return m_renderPassDesc; }
+ void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc) { m_renderPassDesc = desc; }
+
+ QSize currentPixelSize() const { return m_currentPixelSize; }
+
+ virtual QRhiCommandBuffer *currentFrameCommandBuffer() = 0;
+ virtual QRhiRenderTarget *currentFrameRenderTarget() = 0;
+ virtual QRhiRenderTarget *currentFrameRenderTarget(StereoTargetBuffer targetBuffer);
+ virtual QSize surfacePixelSize() = 0;
+ virtual bool isFormatSupported(Format f) = 0;
+ virtual QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() = 0;
+ virtual bool createOrResize() = 0;
+ virtual QRhiSwapChainHdrInfo hdrInfo();
+
+protected:
+ QRhiSwapChain(QRhiImplementation *rhi);
+ QWindow *m_window = nullptr;
+ Flags m_flags;
+ Format m_format = SDR;
+ QRhiRenderBuffer *m_depthStencil = nullptr;
+ int m_sampleCount = 1;
+ QRhiRenderPassDescriptor *m_renderPassDesc = nullptr;
+ QSize m_currentPixelSize;
+ QRhiSwapChainProxyData m_proxyData;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiSwapChain::Flags)
+
+class Q_GUI_EXPORT QRhiComputePipeline : public QRhiResource
+{
+public:
+ enum Flag {
+ CompileShadersWithDebugInfo = 1 << 0
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ QRhiResource::Type resourceType() const override;
+ virtual bool create() = 0;
+
+ Flags flags() const { return m_flags; }
+ void setFlags(Flags f) { m_flags = f; }
+
+ QRhiShaderStage shaderStage() const { return m_shaderStage; }
+ void setShaderStage(const QRhiShaderStage &stage) { m_shaderStage = stage; }
+
+ QRhiShaderResourceBindings *shaderResourceBindings() const { return m_shaderResourceBindings; }
+ void setShaderResourceBindings(QRhiShaderResourceBindings *srb) { m_shaderResourceBindings = srb; }
+
+protected:
+ QRhiComputePipeline(QRhiImplementation *rhi);
+ Flags m_flags;
+ QRhiShaderStage m_shaderStage;
+ QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiComputePipeline::Flags)
+
+class Q_GUI_EXPORT QRhiCommandBuffer : public QRhiResource
+{
+public:
+ enum IndexFormat {
+ IndexUInt16,
+ IndexUInt32
+ };
+
+ enum BeginPassFlag {
+ ExternalContent = 0x01,
+ DoNotTrackResourcesForCompute = 0x02
+ };
+ Q_DECLARE_FLAGS(BeginPassFlags, BeginPassFlag)
+
+ QRhiResource::Type resourceType() const override;
+
+ void resourceUpdate(QRhiResourceUpdateBatch *resourceUpdates);
+
+ void beginPass(QRhiRenderTarget *rt,
+ const QColor &colorClearValue,
+ const QRhiDepthStencilClearValue &depthStencilClearValue,
+ QRhiResourceUpdateBatch *resourceUpdates = nullptr,
+ BeginPassFlags flags = {});
+ void endPass(QRhiResourceUpdateBatch *resourceUpdates = nullptr);
+
+ void setGraphicsPipeline(QRhiGraphicsPipeline *ps);
+ using DynamicOffset = QPair<int, quint32>; // binding, offset
+ void setShaderResources(QRhiShaderResourceBindings *srb = nullptr,
+ int dynamicOffsetCount = 0,
+ const DynamicOffset *dynamicOffsets = nullptr);
+ using VertexInput = QPair<QRhiBuffer *, quint32>; // buffer, offset
+ void setVertexInput(int startBinding, int bindingCount, const VertexInput *bindings,
+ QRhiBuffer *indexBuf = nullptr, quint32 indexOffset = 0,
+ IndexFormat indexFormat = IndexUInt16);
+
+ void setViewport(const QRhiViewport &viewport);
+ void setScissor(const QRhiScissor &scissor);
+ void setBlendConstants(const QColor &c);
+ void setStencilRef(quint32 refValue);
+
+ void draw(quint32 vertexCount,
+ quint32 instanceCount = 1,
+ quint32 firstVertex = 0,
+ quint32 firstInstance = 0);
+
+ void drawIndexed(quint32 indexCount,
+ quint32 instanceCount = 1,
+ quint32 firstIndex = 0,
+ qint32 vertexOffset = 0,
+ quint32 firstInstance = 0);
+
+ void debugMarkBegin(const QByteArray &name);
+ void debugMarkEnd();
+ void debugMarkMsg(const QByteArray &msg);
+
+ void beginComputePass(QRhiResourceUpdateBatch *resourceUpdates = nullptr, BeginPassFlags flags = {});
+ void endComputePass(QRhiResourceUpdateBatch *resourceUpdates = nullptr);
+ void setComputePipeline(QRhiComputePipeline *ps);
+ void dispatch(int x, int y, int z);
+
+ const QRhiNativeHandles *nativeHandles();
+ void beginExternal();
+ void endExternal();
+
+ double lastCompletedGpuTime();
+
+protected:
+ QRhiCommandBuffer(QRhiImplementation *rhi);
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiCommandBuffer::BeginPassFlags)
+
+struct Q_GUI_EXPORT QRhiReadbackResult
+{
+ std::function<void()> completed = nullptr;
+ QRhiTexture::Format format;
+ QSize pixelSize;
+ QByteArray data;
+};
+
+class Q_GUI_EXPORT QRhiResourceUpdateBatch
+{
+public:
+ ~QRhiResourceUpdateBatch();
+
+ void release();
+
+ void merge(QRhiResourceUpdateBatch *other);
+ bool hasOptimalCapacity() const;
+
+ void updateDynamicBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data);
+ void uploadStaticBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data);
+ void uploadStaticBuffer(QRhiBuffer *buf, const void *data);
+ void readBackBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, QRhiReadbackResult *result);
+ void uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc);
+ void uploadTexture(QRhiTexture *tex, const QImage &image);
+ void copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc = QRhiTextureCopyDescription());
+ void readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result);
+ void generateMips(QRhiTexture *tex);
+
+private:
+ QRhiResourceUpdateBatch(QRhiImplementation *rhi);
+ Q_DISABLE_COPY(QRhiResourceUpdateBatch)
+ QRhiResourceUpdateBatchPrivate *d;
+ friend class QRhiResourceUpdateBatchPrivate;
+ friend class QRhi;
+};
+
+struct Q_GUI_EXPORT QRhiDriverInfo
+{
+ enum DeviceType {
+ UnknownDevice,
+ IntegratedDevice,
+ DiscreteDevice,
+ ExternalDevice,
+ VirtualDevice,
+ CpuDevice
+ };
+
+ QByteArray deviceName;
+ quint64 deviceId = 0;
+ quint64 vendorId = 0;
+ DeviceType deviceType = UnknownDevice;
+};
+
+Q_DECLARE_TYPEINFO(QRhiDriverInfo, Q_RELOCATABLE_TYPE);
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiDriverInfo &);
+#endif
+
+struct Q_GUI_EXPORT QRhiStats
+{
+ qint64 totalPipelineCreationTime = 0;
+ // Vulkan or D3D12 memory allocator statistics
+ quint32 blockCount = 0;
+ quint32 allocCount = 0;
+ quint64 usedBytes = 0;
+ quint64 unusedBytes = 0;
+ // D3D12 only, from IDXGIAdapter3::QueryVideoMemoryInfo(), incl. all resources
+ quint64 totalUsageBytes = 0;
+};
+
+Q_DECLARE_TYPEINFO(QRhiStats, Q_RELOCATABLE_TYPE);
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiStats &);
+#endif
+
+struct Q_GUI_EXPORT QRhiInitParams
+{
+};
+
+class Q_GUI_EXPORT QRhi
+{
+public:
+ enum Implementation {
+ Null,
+ Vulkan,
+ OpenGLES2,
+ D3D11,
+ Metal,
+ D3D12
+ };
+
+ enum Flag {
+ EnableDebugMarkers = 1 << 0,
+ PreferSoftwareRenderer = 1 << 1,
+ EnablePipelineCacheDataSave = 1 << 2,
+ EnableTimestamps = 1 << 3,
+ SuppressSmokeTestWarnings = 1 << 4
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ enum FrameOpResult {
+ FrameOpSuccess = 0,
+ FrameOpError,
+ FrameOpSwapChainOutOfDate,
+ FrameOpDeviceLost
+ };
+
+ enum Feature {
+ MultisampleTexture = 1,
+ MultisampleRenderBuffer,
+ DebugMarkers,
+ Timestamps,
+ Instancing,
+ CustomInstanceStepRate,
+ PrimitiveRestart,
+ NonDynamicUniformBuffers,
+ NonFourAlignedEffectiveIndexBufferOffset,
+ NPOTTextureRepeat,
+ RedOrAlpha8IsRed,
+ ElementIndexUint,
+ Compute,
+ WideLines,
+ VertexShaderPointSize,
+ BaseVertex,
+ BaseInstance,
+ TriangleFanTopology,
+ ReadBackNonUniformBuffer,
+ ReadBackNonBaseMipLevel,
+ TexelFetch,
+ RenderToNonBaseMipLevel,
+ IntAttributes,
+ ScreenSpaceDerivatives,
+ ReadBackAnyTextureFormat,
+ PipelineCacheDataLoadSave,
+ ImageDataStride,
+ RenderBufferImport,
+ ThreeDimensionalTextures,
+ RenderTo3DTextureSlice,
+ TextureArrays,
+ Tessellation,
+ GeometryShader,
+ TextureArrayRange,
+ NonFillPolygonMode,
+ OneDimensionalTextures,
+ OneDimensionalTextureMipmaps,
+ HalfAttributes,
+ RenderToOneDimensionalTexture,
+ ThreeDimensionalTextureMipmaps,
+ MultiView,
+ TextureViewFormat,
+ ResolveDepthStencil
+ };
+
+ enum BeginFrameFlag {
+ };
+ Q_DECLARE_FLAGS(BeginFrameFlags, BeginFrameFlag)
+
+ enum EndFrameFlag {
+ SkipPresent = 1 << 0
+ };
+ Q_DECLARE_FLAGS(EndFrameFlags, EndFrameFlag)
+
+ enum ResourceLimit {
+ TextureSizeMin = 1,
+ TextureSizeMax,
+ MaxColorAttachments,
+ FramesInFlight,
+ MaxAsyncReadbackFrames,
+ MaxThreadGroupsPerDimension,
+ MaxThreadsPerThreadGroup,
+ MaxThreadGroupX,
+ MaxThreadGroupY,
+ MaxThreadGroupZ,
+ TextureArraySizeMax,
+ MaxUniformBufferRange,
+ MaxVertexInputs,
+ MaxVertexOutputs
+ };
+
+ ~QRhi();
+
+ static QRhi *create(Implementation impl,
+ QRhiInitParams *params,
+ Flags flags = {},
+ QRhiNativeHandles *importDevice = nullptr);
+ static bool probe(Implementation impl, QRhiInitParams *params);
+
+ Implementation backend() const;
+ const char *backendName() const;
+ static const char *backendName(Implementation impl);
+ QRhiDriverInfo driverInfo() const;
+ QThread *thread() const;
+
+ using CleanupCallback = std::function<void(QRhi *)>;
+ void addCleanupCallback(const CleanupCallback &callback);
+ void addCleanupCallback(const void *key, const CleanupCallback &callback);
+ void removeCleanupCallback(const void *key);
+ void runCleanup();
+
+ QRhiGraphicsPipeline *newGraphicsPipeline();
+ QRhiComputePipeline *newComputePipeline();
+ QRhiShaderResourceBindings *newShaderResourceBindings();
+
+ QRhiBuffer *newBuffer(QRhiBuffer::Type type,
+ QRhiBuffer::UsageFlags usage,
+ quint32 size);
+
+ QRhiRenderBuffer *newRenderBuffer(QRhiRenderBuffer::Type type,
+ const QSize &pixelSize,
+ int sampleCount = 1,
+ QRhiRenderBuffer::Flags flags = {},
+ QRhiTexture::Format backingFormatHint = QRhiTexture::UnknownFormat);
+
+ QRhiTexture *newTexture(QRhiTexture::Format format,
+ const QSize &pixelSize,
+ int sampleCount = 1,
+ QRhiTexture::Flags flags = {});
+
+ QRhiTexture *newTexture(QRhiTexture::Format format,
+ int width, int height, int depth,
+ int sampleCount = 1,
+ QRhiTexture::Flags flags = {});
+
+ QRhiTexture *newTextureArray(QRhiTexture::Format format,
+ int arraySize,
+ const QSize &pixelSize,
+ int sampleCount = 1,
+ QRhiTexture::Flags flags = {});
+
+ QRhiSampler *newSampler(QRhiSampler::Filter magFilter,
+ QRhiSampler::Filter minFilter,
+ QRhiSampler::Filter mipmapMode,
+ QRhiSampler::AddressMode addressU,
+ QRhiSampler::AddressMode addressV,
+ QRhiSampler::AddressMode addressW = QRhiSampler::Repeat);
+
+ QRhiTextureRenderTarget *newTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
+ QRhiTextureRenderTarget::Flags flags = {});
+
+ QRhiSwapChain *newSwapChain();
+ FrameOpResult beginFrame(QRhiSwapChain *swapChain, BeginFrameFlags flags = {});
+ FrameOpResult endFrame(QRhiSwapChain *swapChain, EndFrameFlags flags = {});
+ bool isRecordingFrame() const;
+ int currentFrameSlot() const;
+
+ FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, BeginFrameFlags flags = {});
+ FrameOpResult endOffscreenFrame(EndFrameFlags flags = {});
+
+ QRhi::FrameOpResult finish();
+
+ QRhiResourceUpdateBatch *nextResourceUpdateBatch();
+
+ QList<int> supportedSampleCounts() const;
+
+ int ubufAlignment() const;
+ int ubufAligned(int v) const;
+
+ static int mipLevelsForSize(const QSize &size);
+ static QSize sizeForMipLevel(int mipLevel, const QSize &baseLevelSize);
+
+ bool isYUpInFramebuffer() const;
+ bool isYUpInNDC() const;
+ bool isClipDepthZeroToOne() const;
+
+ QMatrix4x4 clipSpaceCorrMatrix() const;
+
+ bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags = {}) const;
+ bool isFeatureSupported(QRhi::Feature feature) const;
+ int resourceLimit(ResourceLimit limit) const;
+
+ const QRhiNativeHandles *nativeHandles();
+ bool makeThreadLocalNativeContextCurrent();
+
+ static constexpr int MAX_MIP_LEVELS = 16; // -> max width or height is 65536
+
+ void releaseCachedResources();
+
+ bool isDeviceLost() const;
+
+ QByteArray pipelineCacheData();
+ void setPipelineCacheData(const QByteArray &data);
+
+ QRhiStats statistics() const;
+
+ static QRhiSwapChainProxyData updateSwapChainProxyData(Implementation impl, QWindow *window);
+
+protected:
+ QRhi();
+
+private:
+ Q_DISABLE_COPY(QRhi)
+ QRhiImplementation *d = nullptr;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QRhi::Flags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QRhi::BeginFrameFlags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QRhi::EndFrameFlags)
+
+QT_END_NAMESPACE
+
+#include <rhi/qrhi_platform.h>
+
+#endif
diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h
index 561ab2dd9e..b5429372a8 100644
--- a/src/gui/rhi/qrhi_p.h
+++ b/src/gui/rhi/qrhi_p.h
@@ -1,8 +1,8 @@
-// Copyright (C) 2019 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QRHI_H
-#define QRHI_H
+#ifndef QRHI_P_H
+#define QRHI_P_H
//
// W A R N I N G
@@ -15,1961 +15,803 @@
// We mean it.
//
-#include <QtGui/qtguiglobal.h>
-#include <QSize>
-#include <QMatrix4x4>
-#include <QList>
-#include <QVarLengthArray>
-#include <QThread>
-#include <QColor>
-#include <QImage>
-#include <functional>
-#include <array>
-#include <private/qshader_p.h>
+#include <rhi/qrhi.h>
+#include <QBitArray>
+#include <QAtomicInt>
+#include <QElapsedTimer>
+#include <QLoggingCategory>
+#include <QtCore/qset.h>
+#include <QtCore/qvarlengtharray.h>
QT_BEGIN_NAMESPACE
-class QWindow;
-class QRhi;
-class QRhiImplementation;
-class QRhiBuffer;
-class QRhiRenderBuffer;
-class QRhiTexture;
-class QRhiSampler;
-class QRhiCommandBuffer;
-class QRhiResourceUpdateBatch;
-class QRhiResourceUpdateBatchPrivate;
-class QRhiSwapChain;
-
-class Q_GUI_EXPORT QRhiDepthStencilClearValue
-{
-public:
- QRhiDepthStencilClearValue() = default;
- QRhiDepthStencilClearValue(float d, quint32 s);
+#define QRHI_RES(t, x) static_cast<t *>(x)
+#define QRHI_RES_RHI(t) t *rhiD = static_cast<t *>(m_rhi)
- float depthClearValue() const { return m_d; }
- void setDepthClearValue(float d) { m_d = d; }
+Q_DECLARE_LOGGING_CATEGORY(QRHI_LOG_INFO)
- quint32 stencilClearValue() const { return m_s; }
- void setStencilClearValue(quint32 s) { m_s = s; }
+class QRhiImplementation
+{
+public:
+ virtual ~QRhiImplementation();
-private:
- float m_d = 1.0f;
- quint32 m_s = 0;
+ virtual bool create(QRhi::Flags flags) = 0;
+ virtual void destroy() = 0;
- friend bool operator==(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) noexcept
+ virtual QRhiGraphicsPipeline *createGraphicsPipeline() = 0;
+ virtual QRhiComputePipeline *createComputePipeline() = 0;
+ virtual QRhiShaderResourceBindings *createShaderResourceBindings() = 0;
+ virtual QRhiBuffer *createBuffer(QRhiBuffer::Type type,
+ QRhiBuffer::UsageFlags usage,
+ quint32 size) = 0;
+ virtual QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
+ const QSize &pixelSize,
+ int sampleCount,
+ QRhiRenderBuffer::Flags flags,
+ QRhiTexture::Format backingFormatHint) = 0;
+ virtual QRhiTexture *createTexture(QRhiTexture::Format format,
+ const QSize &pixelSize,
+ int depth,
+ int arraySize,
+ int sampleCount,
+ QRhiTexture::Flags flags) = 0;
+ virtual QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
+ QRhiSampler::Filter minFilter,
+ QRhiSampler::Filter mipmapMode,
+ QRhiSampler:: AddressMode u,
+ QRhiSampler::AddressMode v,
+ QRhiSampler::AddressMode w) = 0;
+
+ virtual QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
+ QRhiTextureRenderTarget::Flags flags) = 0;
+
+ virtual QRhiSwapChain *createSwapChain() = 0;
+ virtual QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) = 0;
+ virtual QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) = 0;
+ virtual QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) = 0;
+ virtual QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) = 0;
+ virtual QRhi::FrameOpResult finish() = 0;
+
+ virtual void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0;
+
+ virtual void beginPass(QRhiCommandBuffer *cb,
+ QRhiRenderTarget *rt,
+ const QColor &colorClearValue,
+ const QRhiDepthStencilClearValue &depthStencilClearValue,
+ QRhiResourceUpdateBatch *resourceUpdates,
+ QRhiCommandBuffer::BeginPassFlags flags) = 0;
+ virtual void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0;
+
+ virtual void setGraphicsPipeline(QRhiCommandBuffer *cb,
+ QRhiGraphicsPipeline *ps) = 0;
+
+ virtual void setShaderResources(QRhiCommandBuffer *cb,
+ QRhiShaderResourceBindings *srb,
+ int dynamicOffsetCount,
+ const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) = 0;
+
+ virtual void setVertexInput(QRhiCommandBuffer *cb,
+ int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
+ QRhiBuffer *indexBuf, quint32 indexOffset,
+ QRhiCommandBuffer::IndexFormat indexFormat) = 0;
+
+ virtual void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) = 0;
+ virtual void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) = 0;
+ virtual void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) = 0;
+ virtual void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) = 0;
+
+ virtual void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
+ quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) = 0;
+ virtual void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
+ quint32 instanceCount, quint32 firstIndex,
+ qint32 vertexOffset, quint32 firstInstance) = 0;
+
+ virtual void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) = 0;
+ virtual void debugMarkEnd(QRhiCommandBuffer *cb) = 0;
+ virtual void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) = 0;
+
+ virtual void beginComputePass(QRhiCommandBuffer *cb,
+ QRhiResourceUpdateBatch *resourceUpdates,
+ QRhiCommandBuffer::BeginPassFlags flags) = 0;
+ virtual void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0;
+ virtual void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) = 0;
+ virtual void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) = 0;
+
+ virtual const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) = 0;
+ virtual void beginExternal(QRhiCommandBuffer *cb) = 0;
+ virtual void endExternal(QRhiCommandBuffer *cb) = 0;
+ virtual double lastCompletedGpuTime(QRhiCommandBuffer *cb) = 0;
+
+ virtual QList<int> supportedSampleCounts() const = 0;
+ virtual int ubufAlignment() const = 0;
+ virtual bool isYUpInFramebuffer() const = 0;
+ virtual bool isYUpInNDC() const = 0;
+ virtual bool isClipDepthZeroToOne() const = 0;
+ virtual QMatrix4x4 clipSpaceCorrMatrix() const = 0;
+ virtual bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const = 0;
+ virtual bool isFeatureSupported(QRhi::Feature feature) const = 0;
+ virtual int resourceLimit(QRhi::ResourceLimit limit) const = 0;
+ virtual const QRhiNativeHandles *nativeHandles() = 0;
+ virtual QRhiDriverInfo driverInfo() const = 0;
+ virtual QRhiStats statistics() = 0;
+ virtual bool makeThreadLocalNativeContextCurrent() = 0;
+ virtual void releaseCachedResources() = 0;
+ virtual bool isDeviceLost() const = 0;
+
+ virtual QByteArray pipelineCacheData() = 0;
+ virtual void setPipelineCacheData(const QByteArray &data) = 0;
+
+ void prepareForCreate(QRhi *rhi, QRhi::Implementation impl, QRhi::Flags flags);
+
+ bool isCompressedFormat(QRhiTexture::Format format) const;
+ void compressedFormatInfo(QRhiTexture::Format format, const QSize &size,
+ quint32 *bpl, quint32 *byteSize,
+ QSize *blockDim) const;
+ void textureFormatInfo(QRhiTexture::Format format, const QSize &size,
+ quint32 *bpl, quint32 *byteSize, quint32 *bytesPerPixel) const;
+ bool isStencilSupportingFormat(QRhiTexture::Format format) const;
+
+ void registerResource(QRhiResource *res, bool ownsNativeResources = true)
{
- return a.m_d == b.m_d && a.m_s == b.m_s;
+ // The ownsNativeResources is relevant for the (graphics resource) leak
+ // check in ~QRhiImplementation; when false, the registration's sole
+ // purpose is to automatically null out the resource's m_rhi pointer in
+ // case the rhi goes away first. (which should not happen in
+ // well-written applications but we try to be graceful)
+ resources.insert(res, ownsNativeResources);
}
- friend bool operator!=(const QRhiDepthStencilClearValue &a, const QRhiDepthStencilClearValue &b) noexcept
+ void unregisterResource(QRhiResource *res)
{
- return !(a == b);
+ resources.remove(res);
}
- friend size_t qHash(const QRhiDepthStencilClearValue &v, size_t seed = 0) noexcept
+ void addDeleteLater(QRhiResource *res)
{
- QtPrivate::QHashCombine hash;
- seed = hash(seed, v.m_d);
- seed = hash(seed, v.m_s);
- return seed;
- }
-};
-
-Q_DECLARE_TYPEINFO(QRhiDepthStencilClearValue, Q_RELOCATABLE_TYPE);
-
-#ifndef QT_NO_DEBUG_STREAM
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiDepthStencilClearValue &);
-#endif
-
-class Q_GUI_EXPORT QRhiViewport
-{
-public:
- QRhiViewport() = default;
- QRhiViewport(float x, float y, float w, float h, float minDepth = 0.0f, float maxDepth = 1.0f);
-
- std::array<float, 4> viewport() const { return m_rect; }
- void setViewport(float x, float y, float w, float h) {
- m_rect[0] = x; m_rect[1] = y; m_rect[2] = w; m_rect[3] = h;
+ if (inFrame)
+ pendingDeleteResources.insert(res);
+ else
+ delete res;
}
- float minDepth() const { return m_minDepth; }
- void setMinDepth(float minDepth) { m_minDepth = minDepth; }
-
- float maxDepth() const { return m_maxDepth; }
- void setMaxDepth(float maxDepth) { m_maxDepth = maxDepth; }
-
-private:
- std::array<float, 4> m_rect { { 0.0f, 0.0f, 0.0f, 0.0f } };
- float m_minDepth = 0.0f;
- float m_maxDepth = 1.0f;
-
- friend bool operator==(const QRhiViewport &a, const QRhiViewport &b) noexcept
+ void addCleanupCallback(const QRhi::CleanupCallback &callback)
{
- return a.m_rect == b.m_rect
- && a.m_minDepth == b.m_minDepth
- && a.m_maxDepth == b.m_maxDepth;
+ cleanupCallbacks.append(callback);
}
- friend bool operator!=(const QRhiViewport &a, const QRhiViewport &b) noexcept
+ void addCleanupCallback(const void *key, const QRhi::CleanupCallback &callback)
{
- return !(a == b);
+ keyedCleanupCallbacks[key] = callback;
}
- friend size_t qHash(const QRhiViewport &v, size_t seed = 0) noexcept
+ void removeCleanupCallback(const void *key)
{
- QtPrivate::QHashCombine hash;
- seed = hash(seed, v.m_rect[0]);
- seed = hash(seed, v.m_rect[1]);
- seed = hash(seed, v.m_rect[2]);
- seed = hash(seed, v.m_rect[3]);
- seed = hash(seed, v.m_minDepth);
- seed = hash(seed, v.m_maxDepth);
- return seed;
+ keyedCleanupCallbacks.remove(key);
}
-};
-
-Q_DECLARE_TYPEINFO(QRhiViewport, Q_RELOCATABLE_TYPE);
-#ifndef QT_NO_DEBUG_STREAM
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiViewport &);
-#endif
+ bool sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps);
+ bool sanityCheckShaderResourceBindings(QRhiShaderResourceBindings *srb);
+ void updateLayoutDesc(QRhiShaderResourceBindings *srb);
-class Q_GUI_EXPORT QRhiScissor
-{
-public:
- QRhiScissor() = default;
- QRhiScissor(int x, int y, int w, int h);
-
- std::array<int, 4> scissor() const { return m_rect; }
- void setScissor(int x, int y, int w, int h) {
- m_rect[0] = x; m_rect[1] = y; m_rect[2] = w; m_rect[3] = h;
+ quint32 pipelineCacheRhiId() const
+ {
+ const quint32 ver = (QT_VERSION_MAJOR << 16) | (QT_VERSION_MINOR << 8) | (QT_VERSION_PATCH);
+ return (quint32(implType) << 24) | ver;
}
-private:
- std::array<int, 4> m_rect { { 0, 0, 0, 0 } };
-
- friend bool operator==(const QRhiScissor &a, const QRhiScissor &b) noexcept
+ void pipelineCreationStart()
{
- return a.m_rect == b.m_rect;
+ pipelineCreationTimer.start();
}
- friend bool operator!=(const QRhiScissor &a, const QRhiScissor &b) noexcept
+ void pipelineCreationEnd()
{
- return !(a == b);
+ accumulatedPipelineCreationTime += pipelineCreationTimer.elapsed();
}
- friend size_t qHash(const QRhiScissor &v, size_t seed = 0) noexcept
+ qint64 totalPipelineCreationTime() const
{
- QtPrivate::QHashCombine hash;
- seed = hash(seed, v.m_rect[0]);
- seed = hash(seed, v.m_rect[1]);
- seed = hash(seed, v.m_rect[2]);
- seed = hash(seed, v.m_rect[3]);
- return seed;
+ return accumulatedPipelineCreationTime;
}
-};
-
-Q_DECLARE_TYPEINFO(QRhiScissor, Q_RELOCATABLE_TYPE);
-#ifndef QT_NO_DEBUG_STREAM
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiScissor &);
-#endif
-
-class Q_GUI_EXPORT QRhiVertexInputBinding
-{
-public:
- enum Classification {
- PerVertex,
- PerInstance
- };
-
- QRhiVertexInputBinding() = default;
- QRhiVertexInputBinding(quint32 stride, Classification cls = PerVertex, quint32 stepRate = 1);
-
- quint32 stride() const { return m_stride; }
- void setStride(quint32 s) { m_stride = s; }
-
- Classification classification() const { return m_classification; }
- void setClassification(Classification c) { m_classification = c; }
+ QRhiVertexInputAttribute::Format shaderDescVariableFormatToVertexInputFormat(QShaderDescription::VariableType type) const;
+ quint32 byteSizePerVertexForVertexInputFormat(QRhiVertexInputAttribute::Format format) const;
- quint32 instanceStepRate() const { return m_instanceStepRate; }
- void setInstanceStepRate(quint32 rate) { m_instanceStepRate = rate; }
-
-private:
- quint32 m_stride = 0;
- Classification m_classification = PerVertex;
- quint32 m_instanceStepRate = 1;
-
- friend bool operator==(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) noexcept
+ static const QRhiShaderResourceBinding::Data *shaderResourceBindingData(const QRhiShaderResourceBinding &binding)
{
- return a.m_stride == b.m_stride
- && a.m_classification == b.m_classification
- && a.m_instanceStepRate == b.m_instanceStepRate;
+ return &binding.d;
}
- friend bool operator!=(const QRhiVertexInputBinding &a, const QRhiVertexInputBinding &b) noexcept
+ static QRhiShaderResourceBinding::Data *shaderResourceBindingData(QRhiShaderResourceBinding &binding)
{
- return !(a == b);
+ return &binding.d;
}
- friend size_t qHash(const QRhiVertexInputBinding &v, size_t seed = 0) noexcept
+ static bool sortedBindingLessThan(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
{
- QtPrivate::QHashCombine hash;
- seed = hash(seed, v.m_stride);
- seed = hash(seed, v.m_classification);
- seed = hash(seed, v.m_instanceStepRate);
- return seed;
+ return a.d.binding < b.d.binding;
}
-};
-Q_DECLARE_TYPEINFO(QRhiVertexInputBinding, Q_RELOCATABLE_TYPE);
+ int effectiveSampleCount(int sampleCount) const;
-#ifndef QT_NO_DEBUG_STREAM
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiVertexInputBinding &);
-#endif
+ QRhi *q;
-class Q_GUI_EXPORT QRhiVertexInputAttribute
-{
-public:
- enum Format {
- Float4,
- Float3,
- Float2,
- Float,
- UNormByte4,
- UNormByte2,
- UNormByte,
- UInt4,
- UInt3,
- UInt2,
- UInt,
- SInt4,
- SInt3,
- SInt2,
- SInt,
- Half4,
- Half3,
- Half2,
- Half
- };
+ static const int MAX_SHADER_CACHE_ENTRIES = 128;
- QRhiVertexInputAttribute() = default;
- QRhiVertexInputAttribute(int binding, int location, Format format, quint32 offset, int matrixSlice = -1);
+ bool debugMarkers = false;
+ int currentFrameSlot = 0; // for vk, mtl, and similar. unused by gl and d3d11.
+ bool inFrame = false;
- int binding() const { return m_binding; }
- void setBinding(int b) { m_binding = b; }
+private:
+ QRhi::Implementation implType;
+ QThread *implThread;
+ QVarLengthArray<QRhiResourceUpdateBatch *, 4> resUpdPool;
+ quint64 resUpdPoolMap = 0;
+ int lastResUpdIdx = -1;
+ QHash<QRhiResource *, bool> resources;
+ QSet<QRhiResource *> pendingDeleteResources;
+ QVarLengthArray<QRhi::CleanupCallback, 4> cleanupCallbacks;
+ QHash<const void *, QRhi::CleanupCallback> keyedCleanupCallbacks;
+ QElapsedTimer pipelineCreationTimer;
+ qint64 accumulatedPipelineCreationTime = 0;
- int location() const { return m_location; }
- void setLocation(int loc) { m_location = loc; }
+ friend class QRhi;
+ friend class QRhiResourceUpdateBatchPrivate;
+};
- Format format() const { return m_format; }
- void setFormat(Format f) { m_format = f; }
+enum QRhiTargetRectBoundMode
+{
+ UnBounded,
+ Bounded
+};
- quint32 offset() const { return m_offset; }
- void setOffset(quint32 ofs) { m_offset = ofs; }
+template<QRhiTargetRectBoundMode boundingMode, typename T, size_t N>
+bool qrhi_toTopLeftRenderTargetRect(const QSize &outputSize, const std::array<T, N> &r,
+ T *x, T *y, T *w, T *h)
+{
+ // x,y are bottom-left in QRhiScissor and QRhiViewport but top-left in
+ // Vulkan/Metal/D3D. Our input is an OpenGL-style scissor rect where both
+ // negative x or y, and partly or completely out of bounds rects are
+ // allowed. The only thing the input here cannot have is a negative width
+ // or height. We must handle all other input gracefully, clamping to a zero
+ // width or height rect in the worst case, and ensuring the resulting rect
+ // is inside the rendertarget's bounds because some APIs' validation/debug
+ // layers are allergic to out of bounds scissor rects.
- int matrixSlice() const { return m_matrixSlice; }
- void setMatrixSlice(int slice) { m_matrixSlice = slice; }
+ const T outputWidth = outputSize.width();
+ const T outputHeight = outputSize.height();
+ const T inputWidth = r[2];
+ const T inputHeight = r[3];
-private:
- int m_binding = 0;
- int m_location = 0;
- Format m_format = Float4;
- quint32 m_offset = 0;
- int m_matrixSlice = -1;
+ if (inputWidth < 0 || inputHeight < 0)
+ return false;
- friend bool operator==(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) noexcept
- {
- return a.m_binding == b.m_binding
- && a.m_location == b.m_location
- && a.m_format == b.m_format
- && a.m_offset == b.m_offset;
- // matrixSlice excluded intentionally
- }
+ *x = r[0];
+ *y = outputHeight - (r[1] + inputHeight);
+ *w = inputWidth;
+ *h = inputHeight;
- friend bool operator!=(const QRhiVertexInputAttribute &a, const QRhiVertexInputAttribute &b) noexcept
- {
- return !(a == b);
- }
+ if (boundingMode == Bounded) {
+ const T widthOffset = *x < 0 ? -*x : 0;
+ const T heightOffset = *y < 0 ? -*y : 0;
+ *w = *x < outputWidth ? qMax<T>(0, inputWidth - widthOffset) : 0;
+ *h = *y < outputHeight ? qMax<T>(0, inputHeight - heightOffset) : 0;
- friend size_t qHash(const QRhiVertexInputAttribute &v, size_t seed = 0) noexcept
- {
- QtPrivate::QHashCombine hash;
- seed = hash(seed, v.m_binding);
- seed = hash(seed, v.m_location);
- seed = hash(seed, v.m_format);
- seed = hash(seed, v.m_offset);
- return seed;
- }
-};
+ if (outputWidth > 0)
+ *x = qBound<T>(0, *x, outputWidth - 1);
+ if (outputHeight > 0)
+ *y = qBound<T>(0, *y, outputHeight - 1);
-Q_DECLARE_TYPEINFO(QRhiVertexInputAttribute, Q_RELOCATABLE_TYPE);
+ if (*x + *w > outputWidth)
+ *w = qMax<T>(0, outputWidth - *x);
+ if (*y + *h > outputHeight)
+ *h = qMax<T>(0, outputHeight - *y);
+ }
+ return true;
+}
-#ifndef QT_NO_DEBUG_STREAM
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiVertexInputAttribute &);
-#endif
+struct QRhiBufferDataPrivate
+{
+ Q_DISABLE_COPY_MOVE(QRhiBufferDataPrivate)
+ QRhiBufferDataPrivate() { }
+ ~QRhiBufferDataPrivate() { delete[] largeData; }
+ int ref = 1;
+ quint32 size = 0;
+ quint32 largeAlloc = 0;
+ char *largeData = nullptr;
+ static constexpr quint32 SMALL_DATA_SIZE = 1024;
+ char data[SMALL_DATA_SIZE];
+};
-class Q_GUI_EXPORT QRhiVertexInputLayout
+// no detach-with-contents, no atomic refcount, no shrink
+class QRhiBufferData
{
public:
- QRhiVertexInputLayout() = default;
-
- void setBindings(std::initializer_list<QRhiVertexInputBinding> list) { m_bindings = list; }
- template<typename InputIterator>
- void setBindings(InputIterator first, InputIterator last)
+ QRhiBufferData() = default;
+ ~QRhiBufferData()
{
- m_bindings.clear();
- std::copy(first, last, std::back_inserter(m_bindings));
+ if (d && !--d->ref)
+ delete d;
}
- const QRhiVertexInputBinding *cbeginBindings() const { return m_bindings.cbegin(); }
- const QRhiVertexInputBinding *cendBindings() const { return m_bindings.cend(); }
- const QRhiVertexInputBinding *bindingAt(qsizetype index) const { return &m_bindings.at(index); }
- qsizetype bindingCount() const { return m_bindings.count(); }
-
- void setAttributes(std::initializer_list<QRhiVertexInputAttribute> list) { m_attributes = list; }
- template<typename InputIterator>
- void setAttributes(InputIterator first, InputIterator last)
+ QRhiBufferData(const QRhiBufferData &other)
+ : d(other.d)
{
- m_attributes.clear();
- std::copy(first, last, std::back_inserter(m_attributes));
+ if (d)
+ d->ref += 1;
}
- const QRhiVertexInputAttribute *cbeginAttributes() const { return m_attributes.cbegin(); }
- const QRhiVertexInputAttribute *cendAttributes() const { return m_attributes.cend(); }
- const QRhiVertexInputAttribute *attributeAt(qsizetype index) const { return &m_attributes.at(index); }
- qsizetype attributeCount() const { return m_attributes.count(); }
-
-private:
- QVarLengthArray<QRhiVertexInputBinding, 8> m_bindings;
- QVarLengthArray<QRhiVertexInputAttribute, 8> m_attributes;
-
- friend bool operator==(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) noexcept
- {
- return a.m_bindings == b.m_bindings && a.m_attributes == b.m_attributes;
- }
-
- friend bool operator!=(const QRhiVertexInputLayout &a, const QRhiVertexInputLayout &b) noexcept
- {
- return !(a == b);
- }
-
- friend size_t qHash(const QRhiVertexInputLayout &v, size_t seed = 0) noexcept
+ QRhiBufferData &operator=(const QRhiBufferData &other)
{
- QtPrivate::QHashCombine hash;
- seed = hash(seed, v.m_bindings);
- seed = hash(seed, v.m_attributes);
- return seed;
- }
-
- friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiVertexInputLayout &);
-};
-
-#ifndef QT_NO_DEBUG_STREAM
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiVertexInputLayout &);
-#endif
-
-class Q_GUI_EXPORT QRhiShaderStage
-{
-public:
- enum Type {
- Vertex,
- TessellationControl,
- TessellationEvaluation,
- Geometry,
- Fragment,
- Compute
- };
-
- QRhiShaderStage() = default;
- QRhiShaderStage(Type type, const QShader &shader,
- QShader::Variant v = QShader::StandardShader);
-
- Type type() const { return m_type; }
- void setType(Type t) { m_type = t; }
-
- QShader shader() const { return m_shader; }
- void setShader(const QShader &s) { m_shader = s; }
-
- QShader::Variant shaderVariant() const { return m_shaderVariant; }
- void setShaderVariant(QShader::Variant v) { m_shaderVariant = v; }
-
-private:
- Type m_type = Vertex;
- QShader m_shader;
- QShader::Variant m_shaderVariant = QShader::StandardShader;
-
- friend bool operator==(const QRhiShaderStage &a, const QRhiShaderStage &b) noexcept
+ if (d == other.d)
+ return *this;
+ if (other.d)
+ other.d->ref += 1;
+ if (d && !--d->ref)
+ delete d;
+ d = other.d;
+ return *this;
+ }
+ const char *constData() const
{
- return a.m_type == b.m_type
- && a.m_shader == b.m_shader
- && a.m_shaderVariant == b.m_shaderVariant;
+ return d->size <= QRhiBufferDataPrivate::SMALL_DATA_SIZE ? d->data : d->largeData;
}
-
- friend bool operator!=(const QRhiShaderStage &a, const QRhiShaderStage &b) noexcept
+ quint32 size() const
{
- return !(a == b);
+ return d->size;
}
-
- friend size_t qHash(const QRhiShaderStage &v, size_t seed = 0) noexcept
+ void assign(const char *s, quint32 size)
{
- QtPrivate::QHashCombine hash;
- seed = hash(seed, v.m_type);
- seed = hash(seed, v.m_shader);
- seed = hash(seed, v.m_shaderVariant);
- return seed;
+ if (!d) {
+ d = new QRhiBufferDataPrivate;
+ } else if (d->ref != 1) {
+ d->ref -= 1;
+ d = new QRhiBufferDataPrivate;
+ }
+ d->size = size;
+ if (size <= QRhiBufferDataPrivate::SMALL_DATA_SIZE) {
+ memcpy(d->data, s, size);
+ } else {
+ if (d->largeAlloc < size) {
+ delete[] d->largeData;
+ d->largeAlloc = size;
+ d->largeData = new char[size];
+ }
+ memcpy(d->largeData, s, size);
+ }
}
+private:
+ QRhiBufferDataPrivate *d = nullptr;
};
-Q_DECLARE_TYPEINFO(QRhiShaderStage, Q_RELOCATABLE_TYPE);
-
-#ifndef QT_NO_DEBUG_STREAM
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderStage &);
-#endif
+Q_DECLARE_TYPEINFO(QRhiBufferData, Q_RELOCATABLE_TYPE);
-using QRhiGraphicsShaderStage = QRhiShaderStage;
-
-class Q_GUI_EXPORT QRhiShaderResourceBinding
+class QRhiResourceUpdateBatchPrivate
{
public:
- enum Type {
- UniformBuffer,
- SampledTexture,
- Texture,
- Sampler,
- ImageLoad,
- ImageStore,
- ImageLoadStore,
- BufferLoad,
- BufferStore,
- BufferLoadStore
- };
-
- enum StageFlag {
- VertexStage = 1 << 0,
- TessellationControlStage = 1 << 1,
- TessellationEvaluationStage = 1 << 2,
- GeometryStage = 1 << 3,
- FragmentStage = 1 << 4,
- ComputeStage = 1 << 5
- };
- Q_DECLARE_FLAGS(StageFlags, StageFlag)
-
- QRhiShaderResourceBinding() = default;
+ struct BufferOp {
+ enum Type {
+ DynamicUpdate,
+ StaticUpload,
+ Read
+ };
+ Type type;
+ QRhiBuffer *buf;
+ quint32 offset;
+ QRhiBufferData data;
+ quint32 readSize;
+ QRhiReadbackResult *result;
+
+ static BufferOp dynamicUpdate(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
+ {
+ BufferOp op = {};
+ op.type = DynamicUpdate;
+ op.buf = buf;
+ op.offset = offset;
+ const int effectiveSize = size ? size : buf->size();
+ op.data.assign(reinterpret_cast<const char *>(data), effectiveSize);
+ return op;
+ }
- bool isLayoutCompatible(const QRhiShaderResourceBinding &other) const;
+ static void changeToDynamicUpdate(BufferOp *op, QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
+ {
+ op->type = DynamicUpdate;
+ op->buf = buf;
+ op->offset = offset;
+ const int effectiveSize = size ? size : buf->size();
+ op->data.assign(reinterpret_cast<const char *>(data), effectiveSize);
+ }
- static QRhiShaderResourceBinding uniformBuffer(int binding, StageFlags stage, QRhiBuffer *buf);
- static QRhiShaderResourceBinding uniformBuffer(int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size);
- static QRhiShaderResourceBinding uniformBufferWithDynamicOffset(int binding, StageFlags stage, QRhiBuffer *buf, quint32 size);
+ static BufferOp staticUpload(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
+ {
+ BufferOp op = {};
+ op.type = StaticUpload;
+ op.buf = buf;
+ op.offset = offset;
+ const int effectiveSize = size ? size : buf->size();
+ op.data.assign(reinterpret_cast<const char *>(data), effectiveSize);
+ return op;
+ }
- static QRhiShaderResourceBinding sampledTexture(int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler);
+ static void changeToStaticUpload(BufferOp *op, QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
+ {
+ op->type = StaticUpload;
+ op->buf = buf;
+ op->offset = offset;
+ const int effectiveSize = size ? size : buf->size();
+ op->data.assign(reinterpret_cast<const char *>(data), effectiveSize);
+ }
- struct TextureAndSampler {
- QRhiTexture *tex;
- QRhiSampler *sampler;
+ static BufferOp read(QRhiBuffer *buf, quint32 offset, quint32 size, QRhiReadbackResult *result)
+ {
+ BufferOp op = {};
+ op.type = Read;
+ op.buf = buf;
+ op.offset = offset;
+ op.readSize = size;
+ op.result = result;
+ return op;
+ }
};
- static QRhiShaderResourceBinding sampledTextures(int binding, StageFlags stage, int count, const TextureAndSampler *texSamplers);
-
- static QRhiShaderResourceBinding texture(int binding, StageFlags stage, QRhiTexture *tex);
- static QRhiShaderResourceBinding textures(int binding, StageFlags stage, int count, QRhiTexture **tex);
- static QRhiShaderResourceBinding sampler(int binding, StageFlags stage, QRhiSampler *sampler);
-
- static QRhiShaderResourceBinding imageLoad(int binding, StageFlags stage, QRhiTexture *tex, int level);
- static QRhiShaderResourceBinding imageStore(int binding, StageFlags stage, QRhiTexture *tex, int level);
- static QRhiShaderResourceBinding imageLoadStore(int binding, StageFlags stage, QRhiTexture *tex, int level);
-
- static QRhiShaderResourceBinding bufferLoad(int binding, StageFlags stage, QRhiBuffer *buf);
- static QRhiShaderResourceBinding bufferLoad(int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size);
- static QRhiShaderResourceBinding bufferStore(int binding, StageFlags stage, QRhiBuffer *buf);
- static QRhiShaderResourceBinding bufferStore(int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size);
- static QRhiShaderResourceBinding bufferLoadStore(int binding, StageFlags stage, QRhiBuffer *buf);
- static QRhiShaderResourceBinding bufferLoadStore(int binding, StageFlags stage, QRhiBuffer *buf, quint32 offset, quint32 size);
- struct Data
- {
- int binding;
- QRhiShaderResourceBinding::StageFlags stage;
- QRhiShaderResourceBinding::Type type;
- struct UniformBufferData {
- QRhiBuffer *buf;
- quint32 offset;
- quint32 maybeSize;
- bool hasDynamicOffset;
- };
- static const int MAX_TEX_SAMPLER_ARRAY_SIZE = 16;
- struct TextureAndOrSamplerData {
- int count;
- TextureAndSampler texSamplers[MAX_TEX_SAMPLER_ARRAY_SIZE];
- };
- struct StorageImageData {
- QRhiTexture *tex;
- int level;
+ struct TextureOp {
+ enum Type {
+ Upload,
+ Copy,
+ Read,
+ GenMips
};
- struct StorageBufferData {
- QRhiBuffer *buf;
- quint32 offset;
- quint32 maybeSize;
- };
- union {
- UniformBufferData ubuf;
- TextureAndOrSamplerData stex;
- StorageImageData simage;
- StorageBufferData sbuf;
- } u;
-
- int arraySize() const
+ Type type;
+ QRhiTexture *dst;
+ // Specifying multiple uploads for a subresource must be supported.
+ // In the backend this can then end up, where applicable, as a
+ // single, batched copy operation with only one set of barriers.
+ // This helps when doing for example glyph cache fills.
+ using MipLevelUploadList = std::array<QVector<QRhiTextureSubresourceUploadDescription>, QRhi::MAX_MIP_LEVELS>;
+ QVarLengthArray<MipLevelUploadList, 6> subresDesc;
+ QRhiTexture *src;
+ QRhiTextureCopyDescription desc;
+ QRhiReadbackDescription rb;
+ QRhiReadbackResult *result;
+
+ static TextureOp upload(QRhiTexture *tex, const QRhiTextureUploadDescription &desc)
{
- return type == QRhiShaderResourceBinding::SampledTexture || type == QRhiShaderResourceBinding::Texture
- ? u.stex.count
- : 1;
+ TextureOp op = {};
+ op.type = Upload;
+ op.dst = tex;
+ int maxLayer = -1;
+ for (auto it = desc.cbeginEntries(), itEnd = desc.cendEntries(); it != itEnd; ++it) {
+ if (it->layer() > maxLayer)
+ maxLayer = it->layer();
+ }
+ op.subresDesc.resize(maxLayer + 1);
+ for (auto it = desc.cbeginEntries(), itEnd = desc.cendEntries(); it != itEnd; ++it)
+ op.subresDesc[it->layer()][it->level()].append(it->description());
+ return op;
}
- template<typename Output>
- Output serialize(Output dst) const
+ static TextureOp copy(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc)
{
- // must write out exactly LAYOUT_DESC_ENTRIES_PER_BINDING elements here
- *dst++ = quint32(binding);
- *dst++ = quint32(stage);
- *dst++ = quint32(type);
- *dst++ = quint32(arraySize());
- return dst;
+ TextureOp op = {};
+ op.type = Copy;
+ op.dst = dst;
+ op.src = src;
+ op.desc = desc;
+ return op;
}
- };
- static const int LAYOUT_DESC_ENTRIES_PER_BINDING = 4;
-
- template<typename Output>
- static void serializeLayoutDescription(const QRhiShaderResourceBinding *first,
- const QRhiShaderResourceBinding *last,
- Output dst)
- {
- while (first != last) {
- dst = first->d.serialize(dst);
- ++first;
+ static TextureOp read(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
+ {
+ TextureOp op = {};
+ op.type = Read;
+ op.rb = rb;
+ op.result = result;
+ return op;
}
- }
-
-private:
- Data d;
- friend class QRhiImplementation;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiShaderResourceBinding::StageFlags)
-
-Q_DECLARE_TYPEINFO(QRhiShaderResourceBinding, Q_PRIMITIVE_TYPE);
-
-Q_GUI_EXPORT bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) noexcept;
-Q_GUI_EXPORT bool operator!=(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b) noexcept;
-Q_GUI_EXPORT size_t qHash(const QRhiShaderResourceBinding &b, size_t seed = 0) noexcept;
-#ifndef QT_NO_DEBUG_STREAM
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBinding &);
-#endif
-
-class Q_GUI_EXPORT QRhiColorAttachment
-{
-public:
- QRhiColorAttachment() = default;
- QRhiColorAttachment(QRhiTexture *texture);
- QRhiColorAttachment(QRhiRenderBuffer *renderBuffer);
-
- QRhiTexture *texture() const { return m_texture; }
- void setTexture(QRhiTexture *tex) { m_texture = tex; }
- QRhiRenderBuffer *renderBuffer() const { return m_renderBuffer; }
- void setRenderBuffer(QRhiRenderBuffer *rb) { m_renderBuffer = rb; }
-
- int layer() const { return m_layer; }
- void setLayer(int layer) { m_layer = layer; }
+ static TextureOp genMips(QRhiTexture *tex)
+ {
+ TextureOp op = {};
+ op.type = GenMips;
+ op.dst = tex;
+ return op;
+ }
+ };
- int level() const { return m_level; }
- void setLevel(int level) { m_level = level; }
+ int activeBufferOpCount = 0; // this is the real number of used elements in bufferOps, not bufferOps.count()
+ static const int BUFFER_OPS_STATIC_ALLOC = 1024;
+ QVarLengthArray<BufferOp, BUFFER_OPS_STATIC_ALLOC> bufferOps;
- QRhiTexture *resolveTexture() const { return m_resolveTexture; }
- void setResolveTexture(QRhiTexture *tex) { m_resolveTexture = tex; }
+ int activeTextureOpCount = 0; // this is the real number of used elements in textureOps, not textureOps.count()
+ static const int TEXTURE_OPS_STATIC_ALLOC = 256;
+ QVarLengthArray<TextureOp, TEXTURE_OPS_STATIC_ALLOC> textureOps;
- int resolveLayer() const { return m_resolveLayer; }
- void setResolveLayer(int layer) { m_resolveLayer = layer; }
+ QRhiResourceUpdateBatch *q = nullptr;
+ QRhiImplementation *rhi = nullptr;
+ int poolIndex = -1;
- int resolveLevel() const { return m_resolveLevel; }
- void setResolveLevel(int level) { m_resolveLevel = level; }
+ void free();
+ void merge(QRhiResourceUpdateBatchPrivate *other);
+ bool hasOptimalCapacity() const;
+ void trimOpLists();
-private:
- QRhiTexture *m_texture = nullptr;
- QRhiRenderBuffer *m_renderBuffer = nullptr;
- int m_layer = 0;
- int m_level = 0;
- QRhiTexture *m_resolveTexture = nullptr;
- int m_resolveLayer = 0;
- int m_resolveLevel = 0;
+ static QRhiResourceUpdateBatchPrivate *get(QRhiResourceUpdateBatch *b) { return b->d; }
};
-Q_DECLARE_TYPEINFO(QRhiColorAttachment, Q_RELOCATABLE_TYPE);
-
-class Q_GUI_EXPORT QRhiTextureRenderTargetDescription
+template<typename T>
+struct QRhiBatchedBindings
{
-public:
- QRhiTextureRenderTargetDescription() = default;
- QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment);
- QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment, QRhiRenderBuffer *depthStencilBuffer);
- QRhiTextureRenderTargetDescription(const QRhiColorAttachment &colorAttachment, QRhiTexture *depthTexture);
-
- void setColorAttachments(std::initializer_list<QRhiColorAttachment> list) { m_colorAttachments = list; }
- template<typename InputIterator>
- void setColorAttachments(InputIterator first, InputIterator last)
- {
- m_colorAttachments.clear();
- std::copy(first, last, std::back_inserter(m_colorAttachments));
+ void feed(int binding, T resource) { // binding must be strictly increasing
+ if (curBinding == -1 || binding > curBinding + 1) {
+ finish();
+ curBatch.startBinding = binding;
+ curBatch.resources.clear();
+ curBatch.resources.append(resource);
+ } else {
+ Q_ASSERT(binding == curBinding + 1);
+ curBatch.resources.append(resource);
+ }
+ curBinding = binding;
}
- const QRhiColorAttachment *cbeginColorAttachments() const { return m_colorAttachments.cbegin(); }
- const QRhiColorAttachment *cendColorAttachments() const { return m_colorAttachments.cend(); }
- const QRhiColorAttachment *colorAttachmentAt(qsizetype index) const { return &m_colorAttachments.at(index); }
- qsizetype colorAttachmentCount() const { return m_colorAttachments.count(); }
-
- QRhiRenderBuffer *depthStencilBuffer() const { return m_depthStencilBuffer; }
- void setDepthStencilBuffer(QRhiRenderBuffer *renderBuffer) { m_depthStencilBuffer = renderBuffer; }
-
- QRhiTexture *depthTexture() const { return m_depthTexture; }
- void setDepthTexture(QRhiTexture *texture) { m_depthTexture = texture; }
-
-private:
- QVarLengthArray<QRhiColorAttachment, 8> m_colorAttachments;
- QRhiRenderBuffer *m_depthStencilBuffer = nullptr;
- QRhiTexture *m_depthTexture = nullptr;
-};
-
-class Q_GUI_EXPORT QRhiTextureSubresourceUploadDescription
-{
-public:
- QRhiTextureSubresourceUploadDescription() = default;
- explicit QRhiTextureSubresourceUploadDescription(const QImage &image);
- QRhiTextureSubresourceUploadDescription(const void *data, quint32 size);
- explicit QRhiTextureSubresourceUploadDescription(const QByteArray &data);
-
- QImage image() const { return m_image; }
- void setImage(const QImage &image) { m_image = image; }
-
- QByteArray data() const { return m_data; }
- void setData(const QByteArray &data) { m_data = data; }
-
- quint32 dataStride() const { return m_dataStride; }
- void setDataStride(quint32 stride) { m_dataStride = stride; }
-
- QPoint destinationTopLeft() const { return m_destinationTopLeft; }
- void setDestinationTopLeft(const QPoint &p) { m_destinationTopLeft = p; }
-
- QSize sourceSize() const { return m_sourceSize; }
- void setSourceSize(const QSize &size) { m_sourceSize = size; }
-
- QPoint sourceTopLeft() const { return m_sourceTopLeft; }
- void setSourceTopLeft(const QPoint &p) { m_sourceTopLeft = p; }
-
-private:
- QImage m_image;
- QByteArray m_data;
- quint32 m_dataStride = 0;
- QPoint m_destinationTopLeft;
- QSize m_sourceSize;
- QPoint m_sourceTopLeft;
-};
-
-Q_DECLARE_TYPEINFO(QRhiTextureSubresourceUploadDescription, Q_RELOCATABLE_TYPE);
-class Q_GUI_EXPORT QRhiTextureUploadEntry
-{
-public:
- QRhiTextureUploadEntry() = default;
- QRhiTextureUploadEntry(int layer, int level, const QRhiTextureSubresourceUploadDescription &desc);
-
- int layer() const { return m_layer; }
- void setLayer(int layer) { m_layer = layer; }
+ bool finish() {
+ if (!curBatch.resources.isEmpty())
+ batches.append(curBatch);
+ return !batches.isEmpty();
+ }
- int level() const { return m_level; }
- void setLevel(int level) { m_level = level; }
+ void clear() {
+ batches.clear();
+ curBatch.resources.clear();
+ curBinding = -1;
+ }
- QRhiTextureSubresourceUploadDescription description() const { return m_desc; }
- void setDescription(const QRhiTextureSubresourceUploadDescription &desc) { m_desc = desc; }
+ struct Batch {
+ uint startBinding;
+ QVarLengthArray<T, 4> resources;
-private:
- int m_layer = 0;
- int m_level = 0;
- QRhiTextureSubresourceUploadDescription m_desc;
-};
+ bool operator==(const Batch &other) const
+ {
+ return startBinding == other.startBinding && resources == other.resources;
+ }
-Q_DECLARE_TYPEINFO(QRhiTextureUploadEntry, Q_RELOCATABLE_TYPE);
+ bool operator!=(const Batch &other) const
+ {
+ return !operator==(other);
+ }
+ };
-class Q_GUI_EXPORT QRhiTextureUploadDescription
-{
-public:
- QRhiTextureUploadDescription() = default;
- QRhiTextureUploadDescription(const QRhiTextureUploadEntry &entry);
- QRhiTextureUploadDescription(std::initializer_list<QRhiTextureUploadEntry> list);
+ QVarLengthArray<Batch, 4> batches; // sorted by startBinding
- void setEntries(std::initializer_list<QRhiTextureUploadEntry> list) { m_entries = list; }
- template<typename InputIterator>
- void setEntries(InputIterator first, InputIterator last)
+ bool operator==(const QRhiBatchedBindings<T> &other) const
{
- m_entries.clear();
- std::copy(first, last, std::back_inserter(m_entries));
+ return batches == other.batches;
}
- const QRhiTextureUploadEntry *cbeginEntries() const { return m_entries.cbegin(); }
- const QRhiTextureUploadEntry *cendEntries() const { return m_entries.cend(); }
- const QRhiTextureUploadEntry *entryAt(qsizetype index) const { return &m_entries.at(index); }
- qsizetype entryCount() const { return m_entries.count(); }
-
-private:
- QVarLengthArray<QRhiTextureUploadEntry, 16> m_entries;
-};
-
-class Q_GUI_EXPORT QRhiTextureCopyDescription
-{
-public:
- QRhiTextureCopyDescription() = default;
-
- QSize pixelSize() const { return m_pixelSize; }
- void setPixelSize(const QSize &sz) { m_pixelSize = sz; }
-
- int sourceLayer() const { return m_sourceLayer; }
- void setSourceLayer(int layer) { m_sourceLayer = layer; }
-
- int sourceLevel() const { return m_sourceLevel; }
- void setSourceLevel(int level) { m_sourceLevel = level; }
-
- QPoint sourceTopLeft() const { return m_sourceTopLeft; }
- void setSourceTopLeft(const QPoint &p) { m_sourceTopLeft = p; }
-
- int destinationLayer() const { return m_destinationLayer; }
- void setDestinationLayer(int layer) { m_destinationLayer = layer; }
-
- int destinationLevel() const { return m_destinationLevel; }
- void setDestinationLevel(int level) { m_destinationLevel = level; }
-
- QPoint destinationTopLeft() const { return m_destinationTopLeft; }
- void setDestinationTopLeft(const QPoint &p) { m_destinationTopLeft = p; }
-
-private:
- QSize m_pixelSize;
- int m_sourceLayer = 0;
- int m_sourceLevel = 0;
- QPoint m_sourceTopLeft;
- int m_destinationLayer = 0;
- int m_destinationLevel = 0;
- QPoint m_destinationTopLeft;
-};
-Q_DECLARE_TYPEINFO(QRhiTextureCopyDescription, Q_RELOCATABLE_TYPE);
-
-class Q_GUI_EXPORT QRhiReadbackDescription
-{
-public:
- QRhiReadbackDescription() = default;
- QRhiReadbackDescription(QRhiTexture *texture);
-
- QRhiTexture *texture() const { return m_texture; }
- void setTexture(QRhiTexture *tex) { m_texture = tex; }
-
- int layer() const { return m_layer; }
- void setLayer(int layer) { m_layer = layer; }
-
- int level() const { return m_level; }
- void setLevel(int level) { m_level = level; }
+ bool operator!=(const QRhiBatchedBindings<T> &other) const
+ {
+ return !operator==(other);
+ }
private:
- QRhiTexture *m_texture = nullptr;
- int m_layer = 0;
- int m_level = 0;
+ Batch curBatch;
+ int curBinding = -1;
};
-Q_DECLARE_TYPEINFO(QRhiReadbackDescription, Q_RELOCATABLE_TYPE);
-
-struct Q_GUI_EXPORT QRhiNativeHandles
-{
-};
-
-class Q_GUI_EXPORT QRhiResource
+class QRhiGlobalObjectIdGenerator
{
public:
- enum Type {
- Buffer,
- Texture,
- Sampler,
- RenderBuffer,
- RenderPassDescriptor,
- SwapChainRenderTarget,
- TextureRenderTarget,
- ShaderResourceBindings,
- GraphicsPipeline,
- SwapChain,
- ComputePipeline,
- CommandBuffer
- };
-
- virtual ~QRhiResource();
-
- virtual Type resourceType() const = 0;
-
- virtual void destroy() = 0;
-
- void deleteLater();
-
- QByteArray name() const;
- void setName(const QByteArray &name);
-
- quint64 globalResourceId() const;
-
- QRhi *rhi() const;
-
-protected:
- QRhiResource(QRhiImplementation *rhi);
- Q_DISABLE_COPY(QRhiResource)
- friend class QRhiImplementation;
- QRhiImplementation *m_rhi = nullptr;
- quint64 m_id;
- QByteArray m_objectName;
+#ifdef Q_ATOMIC_INT64_IS_SUPPORTED
+ using Type = quint64;
+#else
+ using Type = quint32;
+#endif
+ static Type newId();
};
-class Q_GUI_EXPORT QRhiBuffer : public QRhiResource
+class QRhiPassResourceTracker
{
public:
- enum Type {
- Immutable,
- Static,
- Dynamic
- };
-
- enum UsageFlag {
- VertexBuffer = 1 << 0,
- IndexBuffer = 1 << 1,
- UniformBuffer = 1 << 2,
- StorageBuffer = 1 << 3
- };
- Q_DECLARE_FLAGS(UsageFlags, UsageFlag)
+ bool isEmpty() const;
+ void reset();
- struct NativeBuffer {
- const void *objects[3];
- int slotCount;
+ struct UsageState {
+ int layout;
+ int access;
+ int stage;
};
- QRhiResource::Type resourceType() const override;
-
- Type type() const { return m_type; }
- void setType(Type t) { m_type = t; }
-
- UsageFlags usage() const { return m_usage; }
- void setUsage(UsageFlags u) { m_usage = u; }
-
- quint32 size() const { return m_size; }
- void setSize(quint32 sz) { m_size = sz; }
-
- virtual bool create() = 0;
-
- virtual NativeBuffer nativeBuffer();
-
- virtual char *beginFullDynamicBufferUpdateForCurrentFrame();
- virtual void endFullDynamicBufferUpdateForCurrentFrame();
-
-protected:
- QRhiBuffer(QRhiImplementation *rhi, Type type_, UsageFlags usage_, quint32 size_);
- Type m_type;
- UsageFlags m_usage;
- quint32 m_size;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiBuffer::UsageFlags)
-
-class Q_GUI_EXPORT QRhiTexture : public QRhiResource
-{
-public:
- enum Flag {
- RenderTarget = 1 << 0,
- CubeMap = 1 << 2,
- MipMapped = 1 << 3,
- sRGB = 1 << 4,
- UsedAsTransferSource = 1 << 5,
- UsedWithGenerateMips = 1 << 6,
- UsedWithLoadStore = 1 << 7,
- UsedAsCompressedAtlas = 1 << 8,
- ExternalOES = 1 << 9,
- ThreeDimensional = 1 << 10,
- TextureRectangleGL = 1 << 11,
- TextureArray = 1 << 12,
- OneDimensional = 1 << 13
- };
- Q_DECLARE_FLAGS(Flags, Flag)
-
- enum Format {
- UnknownFormat,
-
- RGBA8,
- BGRA8,
- R8,
- RG8,
- R16,
- RG16,
- RED_OR_ALPHA8,
-
- RGBA16F,
- RGBA32F,
- R16F,
- R32F,
-
- RGB10A2,
-
- D16,
- D24,
- D24S8,
- D32F,
-
- BC1,
- BC2,
- BC3,
- BC4,
- BC5,
- BC6H,
- BC7,
-
- ETC2_RGB8,
- ETC2_RGB8A1,
- ETC2_RGBA8,
-
- ASTC_4x4,
- ASTC_5x4,
- ASTC_5x5,
- ASTC_6x5,
- ASTC_6x6,
- ASTC_8x5,
- ASTC_8x6,
- ASTC_8x8,
- ASTC_10x5,
- ASTC_10x6,
- ASTC_10x8,
- ASTC_10x10,
- ASTC_12x10,
- ASTC_12x12
+ enum BufferStage {
+ BufVertexInputStage,
+ BufVertexStage,
+ BufTCStage,
+ BufTEStage,
+ BufFragmentStage,
+ BufComputeStage,
+ BufGeometryStage
};
- struct NativeTexture {
- quint64 object;
- int layout; // or state
+ enum BufferAccess {
+ BufVertexInput,
+ BufIndexRead,
+ BufUniformRead,
+ BufStorageLoad,
+ BufStorageStore,
+ BufStorageLoadStore
};
- QRhiResource::Type resourceType() const override;
-
- Format format() const { return m_format; }
- void setFormat(Format fmt) { m_format = fmt; }
-
- QSize pixelSize() const { return m_pixelSize; }
- void setPixelSize(const QSize &sz) { m_pixelSize = sz; }
-
- int depth() const { return m_depth; }
- void setDepth(int depth) { m_depth = depth; }
-
- int arraySize() const { return m_arraySize; }
- void setArraySize(int arraySize) { m_arraySize = arraySize; }
-
- int arrayRangeStart() const { return m_arrayRangeStart; }
- int arrayRangeLength() const { return m_arrayRangeLength; }
- void setArrayRange(int startIndex, int count)
- {
- m_arrayRangeStart = startIndex;
- m_arrayRangeLength = count;
- }
-
- Flags flags() const { return m_flags; }
- void setFlags(Flags f) { m_flags = f; }
-
- int sampleCount() const { return m_sampleCount; }
- void setSampleCount(int s) { m_sampleCount = s; }
-
- virtual bool create() = 0;
- virtual NativeTexture nativeTexture();
- virtual bool createFrom(NativeTexture src);
- virtual void setNativeLayout(int layout);
-
-protected:
- QRhiTexture(QRhiImplementation *rhi, Format format_, const QSize &pixelSize_, int depth_,
- int arraySize_, int sampleCount_, Flags flags_);
- Format m_format;
- QSize m_pixelSize;
- int m_depth;
- int m_arraySize;
- int m_sampleCount;
- Flags m_flags;
- int m_arrayRangeStart = -1;
- int m_arrayRangeLength = -1;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiTexture::Flags)
-
-class Q_GUI_EXPORT QRhiSampler : public QRhiResource
-{
-public:
- enum Filter {
- None,
- Nearest,
- Linear
- };
+ void registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage,
+ const UsageState &state);
- enum AddressMode {
- Repeat,
- ClampToEdge,
- Mirror,
+ enum TextureStage {
+ TexVertexStage,
+ TexTCStage,
+ TexTEStage,
+ TexFragmentStage,
+ TexColorOutputStage,
+ TexDepthOutputStage,
+ TexComputeStage,
+ TexGeometryStage
};
- enum CompareOp {
- Never,
- Less,
- Equal,
- LessOrEqual,
- Greater,
- NotEqual,
- GreaterOrEqual,
- Always
+ enum TextureAccess {
+ TexSample,
+ TexColorOutput,
+ TexDepthOutput,
+ TexStorageLoad,
+ TexStorageStore,
+ TexStorageLoadStore
};
- QRhiResource::Type resourceType() const override;
-
- Filter magFilter() const { return m_magFilter; }
- void setMagFilter(Filter f) { m_magFilter = f; }
-
- Filter minFilter() const { return m_minFilter; }
- void setMinFilter(Filter f) { m_minFilter = f; }
-
- Filter mipmapMode() const { return m_mipmapMode; }
- void setMipmapMode(Filter f) { m_mipmapMode = f; }
-
- AddressMode addressU() const { return m_addressU; }
- void setAddressU(AddressMode mode) { m_addressU = mode; }
-
- AddressMode addressV() const { return m_addressV; }
- void setAddressV(AddressMode mode) { m_addressV = mode; }
-
- AddressMode addressW() const { return m_addressW; }
- void setAddressW(AddressMode mode) { m_addressW = mode; }
-
- CompareOp textureCompareOp() const { return m_compareOp; }
- void setTextureCompareOp(CompareOp op) { m_compareOp = op; }
+ void registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage,
+ const UsageState &state);
- virtual bool create() = 0;
-
-protected:
- QRhiSampler(QRhiImplementation *rhi,
- Filter magFilter_, Filter minFilter_, Filter mipmapMode_,
- AddressMode u_, AddressMode v_, AddressMode w_);
- Filter m_magFilter;
- Filter m_minFilter;
- Filter m_mipmapMode;
- AddressMode m_addressU;
- AddressMode m_addressV;
- AddressMode m_addressW;
- CompareOp m_compareOp;
-};
-
-class Q_GUI_EXPORT QRhiRenderBuffer : public QRhiResource
-{
-public:
- enum Type {
- DepthStencil,
- Color
+ struct Buffer {
+ int slot;
+ BufferAccess access;
+ BufferStage stage;
+ UsageState stateAtPassBegin;
};
- enum Flag {
- UsedWithSwapChainOnly = 1 << 0
- };
- Q_DECLARE_FLAGS(Flags, Flag)
+ using BufferIterator = QHash<QRhiBuffer *, Buffer>::const_iterator;
+ BufferIterator cbeginBuffers() const { return m_buffers.cbegin(); }
+ BufferIterator cendBuffers() const { return m_buffers.cend(); }
- struct NativeRenderBuffer {
- quint64 object;
+ struct Texture {
+ TextureAccess access;
+ TextureStage stage;
+ UsageState stateAtPassBegin;
};
- QRhiResource::Type resourceType() const override;
-
- Type type() const { return m_type; }
- void setType(Type t) { m_type = t; }
-
- QSize pixelSize() const { return m_pixelSize; }
- void setPixelSize(const QSize &sz) { m_pixelSize = sz; }
+ using TextureIterator = QHash<QRhiTexture *, Texture>::const_iterator;
+ TextureIterator cbeginTextures() const { return m_textures.cbegin(); }
+ TextureIterator cendTextures() const { return m_textures.cend(); }
- int sampleCount() const { return m_sampleCount; }
- void setSampleCount(int s) { m_sampleCount = s; }
+ static BufferStage toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages);
+ static TextureStage toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages);
- Flags flags() const { return m_flags; }
- void setFlags(Flags h) { m_flags = h; }
-
- virtual bool create() = 0;
- virtual bool createFrom(NativeRenderBuffer src);
-
- virtual QRhiTexture::Format backingFormat() const = 0;
-
-protected:
- QRhiRenderBuffer(QRhiImplementation *rhi, Type type_, const QSize &pixelSize_,
- int sampleCount_, Flags flags_, QRhiTexture::Format backingFormatHint_);
- Type m_type;
- QSize m_pixelSize;
- int m_sampleCount;
- Flags m_flags;
- QRhiTexture::Format m_backingFormatHint;
+private:
+ QHash<QRhiBuffer *, Buffer> m_buffers;
+ QHash<QRhiTexture *, Texture> m_textures;
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiRenderBuffer::Flags)
+Q_DECLARE_TYPEINFO(QRhiPassResourceTracker::Buffer, Q_RELOCATABLE_TYPE);
+Q_DECLARE_TYPEINFO(QRhiPassResourceTracker::Texture, Q_RELOCATABLE_TYPE);
-class Q_GUI_EXPORT QRhiRenderPassDescriptor : public QRhiResource
+template<typename T, int GROW = 1024>
+class QRhiBackendCommandList
{
public:
- QRhiResource::Type resourceType() const override;
-
- virtual bool isCompatible(const QRhiRenderPassDescriptor *other) const = 0;
- virtual const QRhiNativeHandles *nativeHandles();
-
- virtual QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const = 0;
-
- virtual QVector<quint32> serializedFormat() const = 0;
-
-protected:
- QRhiRenderPassDescriptor(QRhiImplementation *rhi);
+ QRhiBackendCommandList() = default;
+ ~QRhiBackendCommandList() { delete[] v; }
+ inline void reset() { p = 0; }
+ inline bool isEmpty() const { return p == 0; }
+ inline T &get() {
+ if (p == a) {
+ a += GROW;
+ T *nv = new T[a];
+ if (v) {
+ memcpy(nv, v, p * sizeof(T));
+ delete[] v;
+ }
+ v = nv;
+ }
+ return v[p++];
+ }
+ inline void unget() { --p; }
+ inline T *cbegin() const { return v; }
+ inline T *cend() const { return v + p; }
+ inline T *begin() { return v; }
+ inline T *end() { return v + p; }
+private:
+ Q_DISABLE_COPY(QRhiBackendCommandList)
+ T *v = nullptr;
+ int a = 0;
+ int p = 0;
};
-class Q_GUI_EXPORT QRhiRenderTarget : public QRhiResource
+struct QRhiRenderTargetAttachmentTracker
{
-public:
- virtual QSize pixelSize() const = 0;
- virtual float devicePixelRatio() const = 0;
- virtual int sampleCount() const = 0;
+ struct ResId { quint64 id; uint generation; };
+ using ResIdList = QVarLengthArray<ResId, 8 * 2 + 1>; // color, resolve, ds
- QRhiRenderPassDescriptor *renderPassDescriptor() const { return m_renderPassDesc; }
- void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc) { m_renderPassDesc = desc; }
+ template<typename TexType, typename RenderBufferType>
+ static void updateResIdList(const QRhiTextureRenderTargetDescription &desc, ResIdList *dst);
-protected:
- QRhiRenderTarget(QRhiImplementation *rhi);
- QRhiRenderPassDescriptor *m_renderPassDesc = nullptr;
+ template<typename TexType, typename RenderBufferType>
+ static bool isUpToDate(const QRhiTextureRenderTargetDescription &desc, const ResIdList &currentResIdList);
};
-class Q_GUI_EXPORT QRhiSwapChainRenderTarget : public QRhiRenderTarget
+inline bool operator==(const QRhiRenderTargetAttachmentTracker::ResId &a, const QRhiRenderTargetAttachmentTracker::ResId &b)
{
-public:
- QRhiResource::Type resourceType() const override;
- QRhiSwapChain *swapChain() const { return m_swapchain; }
-
-protected:
- QRhiSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain_);
- QRhiSwapChain *m_swapchain;
-};
-
-class Q_GUI_EXPORT QRhiTextureRenderTarget : public QRhiRenderTarget
-{
-public:
- enum Flag {
- PreserveColorContents = 1 << 0,
- PreserveDepthStencilContents = 1 << 1
- };
- Q_DECLARE_FLAGS(Flags, Flag)
-
- QRhiResource::Type resourceType() const override;
-
- QRhiTextureRenderTargetDescription description() const { return m_desc; }
- void setDescription(const QRhiTextureRenderTargetDescription &desc) { m_desc = desc; }
-
- Flags flags() const { return m_flags; }
- void setFlags(Flags f) { m_flags = f; }
+ return a.id == b.id && a.generation == b.generation;
+}
- virtual QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() = 0;
-
- virtual bool create() = 0;
-
-protected:
- QRhiTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc_, Flags flags_);
- QRhiTextureRenderTargetDescription m_desc;
- Flags m_flags;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiTextureRenderTarget::Flags)
-
-class Q_GUI_EXPORT QRhiShaderResourceBindings : public QRhiResource
+inline bool operator!=(const QRhiRenderTargetAttachmentTracker::ResId &a, const QRhiRenderTargetAttachmentTracker::ResId &b)
{
-public:
- QRhiResource::Type resourceType() const override;
-
- void setBindings(std::initializer_list<QRhiShaderResourceBinding> list) { m_bindings = list; }
- template<typename InputIterator>
- void setBindings(InputIterator first, InputIterator last)
- {
- m_bindings.clear();
- std::copy(first, last, std::back_inserter(m_bindings));
- }
- const QRhiShaderResourceBinding *cbeginBindings() const { return m_bindings.cbegin(); }
- const QRhiShaderResourceBinding *cendBindings() const { return m_bindings.cend(); }
- const QRhiShaderResourceBinding *bindingAt(qsizetype index) const { return &m_bindings.at(index); }
- qsizetype bindingCount() const { return m_bindings.count(); }
-
- bool isLayoutCompatible(const QRhiShaderResourceBindings *other) const;
-
- QVector<quint32> serializedLayoutDescription() const { return m_layoutDesc; }
-
- virtual bool create() = 0;
-
- enum UpdateFlag {
- BindingsAreSorted = 0x01
- };
- Q_DECLARE_FLAGS(UpdateFlags, UpdateFlag)
-
- virtual void updateResources(UpdateFlags flags = {}) = 0;
-
-protected:
- static const int BINDING_PREALLOC = 12;
- QRhiShaderResourceBindings(QRhiImplementation *rhi);
- QVarLengthArray<QRhiShaderResourceBinding, BINDING_PREALLOC> m_bindings;
- size_t m_layoutDescHash = 0;
- // Intentionally not using QVLA for m_layoutDesc: clients like Qt Quick are much
- // better served with an implicitly shared container here, because they will likely
- // throw this directly into structs serving as cache keys.
- QVector<quint32> m_layoutDesc;
- friend class QRhiImplementation;
-#ifndef QT_NO_DEBUG_STREAM
- friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBindings &);
-#endif
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiShaderResourceBindings::UpdateFlags)
-
-#ifndef QT_NO_DEBUG_STREAM
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiShaderResourceBindings &);
-#endif
+ return !(a == b);
+}
-class Q_GUI_EXPORT QRhiGraphicsPipeline : public QRhiResource
+template<typename TexType, typename RenderBufferType>
+void QRhiRenderTargetAttachmentTracker::updateResIdList(const QRhiTextureRenderTargetDescription &desc, ResIdList *dst)
{
-public:
- enum Flag {
- UsesBlendConstants = 1 << 0,
- UsesStencilRef = 1 << 1,
- UsesScissor = 1 << 2,
- CompileShadersWithDebugInfo = 1 << 3
- };
- Q_DECLARE_FLAGS(Flags, Flag)
-
- enum Topology {
- Triangles,
- TriangleStrip,
- TriangleFan,
- Lines,
- LineStrip,
- Points,
- Patches
- };
-
- enum CullMode {
- None,
- Front,
- Back
- };
-
- enum FrontFace {
- CCW,
- CW
- };
-
- enum ColorMaskComponent {
- R = 1 << 0,
- G = 1 << 1,
- B = 1 << 2,
- A = 1 << 3
- };
- Q_DECLARE_FLAGS(ColorMask, ColorMaskComponent)
-
- enum BlendFactor {
- Zero,
- One,
- SrcColor,
- OneMinusSrcColor,
- DstColor,
- OneMinusDstColor,
- SrcAlpha,
- OneMinusSrcAlpha,
- DstAlpha,
- OneMinusDstAlpha,
- ConstantColor,
- OneMinusConstantColor,
- ConstantAlpha,
- OneMinusConstantAlpha,
- SrcAlphaSaturate,
- Src1Color,
- OneMinusSrc1Color,
- Src1Alpha,
- OneMinusSrc1Alpha
- };
-
- enum BlendOp {
- Add,
- Subtract,
- ReverseSubtract,
- Min,
- Max
- };
-
- struct TargetBlend {
- ColorMask colorWrite = ColorMask(0xF); // R | G | B | A
- bool enable = false;
- BlendFactor srcColor = One;
- BlendFactor dstColor = OneMinusSrcAlpha;
- BlendOp opColor = Add;
- BlendFactor srcAlpha = One;
- BlendFactor dstAlpha = OneMinusSrcAlpha;
- BlendOp opAlpha = Add;
- };
-
- enum CompareOp {
- Never,
- Less,
- Equal,
- LessOrEqual,
- Greater,
- NotEqual,
- GreaterOrEqual,
- Always
- };
-
- enum StencilOp {
- StencilZero,
- Keep,
- Replace,
- IncrementAndClamp,
- DecrementAndClamp,
- Invert,
- IncrementAndWrap,
- DecrementAndWrap
- };
-
- struct StencilOpState {
- StencilOp failOp = Keep;
- StencilOp depthFailOp = Keep;
- StencilOp passOp = Keep;
- CompareOp compareOp = Always;
- };
-
- enum PolygonMode {
- Fill,
- Line
- };
-
- QRhiResource::Type resourceType() const override;
-
- Flags flags() const { return m_flags; }
- void setFlags(Flags f) { m_flags = f; }
-
- Topology topology() const { return m_topology; }
- void setTopology(Topology t) { m_topology = t; }
-
- CullMode cullMode() const { return m_cullMode; }
- void setCullMode(CullMode mode) { m_cullMode = mode; }
-
- FrontFace frontFace() const { return m_frontFace; }
- void setFrontFace(FrontFace f) { m_frontFace = f; }
-
- void setTargetBlends(std::initializer_list<TargetBlend> list) { m_targetBlends = list; }
- template<typename InputIterator>
- void setTargetBlends(InputIterator first, InputIterator last)
- {
- m_targetBlends.clear();
- std::copy(first, last, std::back_inserter(m_targetBlends));
+ const bool hasDepthStencil = desc.depthStencilBuffer() || desc.depthTexture();
+ dst->resize(desc.colorAttachmentCount() * 2 + (hasDepthStencil ? 1 : 0));
+ int n = 0;
+ for (auto it = desc.cbeginColorAttachments(), itEnd = desc.cendColorAttachments(); it != itEnd; ++it, ++n) {
+ const QRhiColorAttachment &colorAtt(*it);
+ if (colorAtt.texture()) {
+ TexType *texD = QRHI_RES(TexType, colorAtt.texture());
+ (*dst)[n] = { texD->globalResourceId(), texD->generation };
+ } else if (colorAtt.renderBuffer()) {
+ RenderBufferType *rbD = QRHI_RES(RenderBufferType, colorAtt.renderBuffer());
+ (*dst)[n] = { rbD->globalResourceId(), rbD->generation };
+ } else {
+ (*dst)[n] = { 0, 0 };
+ }
+ ++n;
+ if (colorAtt.resolveTexture()) {
+ TexType *texD = QRHI_RES(TexType, colorAtt.resolveTexture());
+ (*dst)[n] = { texD->globalResourceId(), texD->generation };
+ } else {
+ (*dst)[n] = { 0, 0 };
+ }
}
- const TargetBlend *cbeginTargetBlends() const { return m_targetBlends.cbegin(); }
- const TargetBlend *cendTargetBlends() const { return m_targetBlends.cend(); }
- const TargetBlend *targetBlendAt(qsizetype index) const { return &m_targetBlends.at(index); }
- qsizetype targetBlendCount() const { return m_targetBlends.count(); }
-
- bool hasDepthTest() const { return m_depthTest; }
- void setDepthTest(bool enable) { m_depthTest = enable; }
-
- bool hasDepthWrite() const { return m_depthWrite; }
- void setDepthWrite(bool enable) { m_depthWrite = enable; }
-
- CompareOp depthOp() const { return m_depthOp; }
- void setDepthOp(CompareOp op) { m_depthOp = op; }
-
- bool hasStencilTest() const { return m_stencilTest; }
- void setStencilTest(bool enable) { m_stencilTest = enable; }
-
- StencilOpState stencilFront() const { return m_stencilFront; }
- void setStencilFront(const StencilOpState &state) { m_stencilFront = state; }
-
- StencilOpState stencilBack() const { return m_stencilBack; }
- void setStencilBack(const StencilOpState &state) { m_stencilBack = state; }
-
- quint32 stencilReadMask() const { return m_stencilReadMask; }
- void setStencilReadMask(quint32 mask) { m_stencilReadMask = mask; }
-
- quint32 stencilWriteMask() const { return m_stencilWriteMask; }
- void setStencilWriteMask(quint32 mask) { m_stencilWriteMask = mask; }
-
- int sampleCount() const { return m_sampleCount; }
- void setSampleCount(int s) { m_sampleCount = s; }
-
- float lineWidth() const { return m_lineWidth; }
- void setLineWidth(float width) { m_lineWidth = width; }
-
- int depthBias() const { return m_depthBias; }
- void setDepthBias(int bias) { m_depthBias = bias; }
-
- float slopeScaledDepthBias() const { return m_slopeScaledDepthBias; }
- void setSlopeScaledDepthBias(float bias) { m_slopeScaledDepthBias = bias; }
-
- void setShaderStages(std::initializer_list<QRhiShaderStage> list) { m_shaderStages = list; }
- template<typename InputIterator>
- void setShaderStages(InputIterator first, InputIterator last)
- {
- m_shaderStages.clear();
- std::copy(first, last, std::back_inserter(m_shaderStages));
+ if (hasDepthStencil) {
+ if (desc.depthTexture()) {
+ TexType *depthTexD = QRHI_RES(TexType, desc.depthTexture());
+ (*dst)[n] = { depthTexD->globalResourceId(), depthTexD->generation };
+ } else if (desc.depthStencilBuffer()) {
+ RenderBufferType *depthRbD = QRHI_RES(RenderBufferType, desc.depthStencilBuffer());
+ (*dst)[n] = { depthRbD->globalResourceId(), depthRbD->generation };
+ } else {
+ (*dst)[n] = { 0, 0 };
+ }
}
- const QRhiShaderStage *cbeginShaderStages() const { return m_shaderStages.cbegin(); }
- const QRhiShaderStage *cendShaderStages() const { return m_shaderStages.cend(); }
- const QRhiShaderStage *shaderStageAt(qsizetype index) const { return &m_shaderStages.at(index); }
- qsizetype shaderStageCount() const { return m_shaderStages.count(); }
-
- QRhiVertexInputLayout vertexInputLayout() const { return m_vertexInputLayout; }
- void setVertexInputLayout(const QRhiVertexInputLayout &layout) { m_vertexInputLayout = layout; }
-
- QRhiShaderResourceBindings *shaderResourceBindings() const { return m_shaderResourceBindings; }
- void setShaderResourceBindings(QRhiShaderResourceBindings *srb) { m_shaderResourceBindings = srb; }
-
- QRhiRenderPassDescriptor *renderPassDescriptor() const { return m_renderPassDesc; }
- void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc) { m_renderPassDesc = desc; }
-
- int patchControlPointCount() const { return m_patchControlPointCount; }
- void setPatchControlPointCount(int count) { m_patchControlPointCount = count; }
-
- PolygonMode polygonMode() const {return m_polygonMode; }
- void setPolygonMode(PolygonMode mode) {m_polygonMode = mode; }
-
- virtual bool create() = 0;
-
-protected:
- QRhiGraphicsPipeline(QRhiImplementation *rhi);
- Flags m_flags;
- Topology m_topology = Triangles;
- CullMode m_cullMode = None;
- FrontFace m_frontFace = CCW;
- QVarLengthArray<TargetBlend, 8> m_targetBlends;
- bool m_depthTest = false;
- bool m_depthWrite = false;
- CompareOp m_depthOp = Less;
- bool m_stencilTest = false;
- StencilOpState m_stencilFront;
- StencilOpState m_stencilBack;
- quint32 m_stencilReadMask = 0xFF;
- quint32 m_stencilWriteMask = 0xFF;
- int m_sampleCount = 1;
- float m_lineWidth = 1.0f;
- int m_depthBias = 0;
- float m_slopeScaledDepthBias = 0.0f;
- int m_patchControlPointCount = 3;
- PolygonMode m_polygonMode = Fill;
- QVarLengthArray<QRhiShaderStage, 4> m_shaderStages;
- QRhiVertexInputLayout m_vertexInputLayout;
- QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr;
- QRhiRenderPassDescriptor *m_renderPassDesc = nullptr;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiGraphicsPipeline::Flags)
-Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiGraphicsPipeline::ColorMask)
-Q_DECLARE_TYPEINFO(QRhiGraphicsPipeline::TargetBlend, Q_RELOCATABLE_TYPE);
-
-struct QRhiSwapChainHdrInfo
-{
- bool isHardCodedDefaults;
- enum LimitsType {
- LuminanceInNits,
- ColorComponentValue
- };
- LimitsType limitsType;
- union {
- struct {
- float minLuminance;
- float maxLuminance;
- } luminanceInNits;
- struct {
- float maxColorComponentValue;
- } colorComponentValue;
- } limits;
-};
-
-Q_DECLARE_TYPEINFO(QRhiSwapChainHdrInfo, Q_RELOCATABLE_TYPE);
-
-#ifndef QT_NO_DEBUG_STREAM
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiSwapChainHdrInfo &);
-#endif
-
-struct QRhiSwapChainProxyData
-{
- void *reserved[2] = {};
-};
-
-class Q_GUI_EXPORT QRhiSwapChain : public QRhiResource
-{
-public:
- enum Flag {
- SurfaceHasPreMulAlpha = 1 << 0,
- SurfaceHasNonPreMulAlpha = 1 << 1,
- sRGB = 1 << 2,
- UsedAsTransferSource = 1 << 3,
- NoVSync = 1 << 4,
- MinimalBufferCount = 1 << 5
- };
- Q_DECLARE_FLAGS(Flags, Flag)
-
- enum Format {
- SDR,
- HDRExtendedSrgbLinear,
- HDR10
- };
-
- enum StereoTargetBuffer {
- LeftBuffer,
- RightBuffer
- };
-
- QRhiResource::Type resourceType() const override;
-
- QWindow *window() const { return m_window; }
- void setWindow(QWindow *window) { m_window = window; }
-
- QRhiSwapChainProxyData proxyData() const { return m_proxyData; }
- void setProxyData(const QRhiSwapChainProxyData &d) { m_proxyData = d; }
-
- Flags flags() const { return m_flags; }
- void setFlags(Flags f) { m_flags = f; }
-
- Format format() const { return m_format; }
- void setFormat(Format f) { m_format = f; }
-
- QRhiRenderBuffer *depthStencil() const { return m_depthStencil; }
- void setDepthStencil(QRhiRenderBuffer *ds) { m_depthStencil = ds; }
-
- int sampleCount() const { return m_sampleCount; }
- void setSampleCount(int samples) { m_sampleCount = samples; }
-
- QRhiRenderPassDescriptor *renderPassDescriptor() const { return m_renderPassDesc; }
- void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc) { m_renderPassDesc = desc; }
-
- QSize currentPixelSize() const { return m_currentPixelSize; }
-
- virtual QRhiCommandBuffer *currentFrameCommandBuffer() = 0;
- virtual QRhiRenderTarget *currentFrameRenderTarget() = 0;
- virtual QRhiRenderTarget *currentFrameRenderTarget(StereoTargetBuffer targetBuffer);
- virtual QSize surfacePixelSize() = 0;
- virtual bool isFormatSupported(Format f) = 0;
- virtual QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() = 0;
- virtual bool createOrResize() = 0;
- virtual QRhiSwapChainHdrInfo hdrInfo();
-
-protected:
- QRhiSwapChain(QRhiImplementation *rhi);
- QWindow *m_window = nullptr;
- Flags m_flags;
- Format m_format = SDR;
- QRhiRenderBuffer *m_depthStencil = nullptr;
- int m_sampleCount = 1;
- QRhiRenderPassDescriptor *m_renderPassDesc = nullptr;
- QSize m_currentPixelSize;
- QRhiSwapChainProxyData m_proxyData;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiSwapChain::Flags)
-
-class Q_GUI_EXPORT QRhiComputePipeline : public QRhiResource
-{
-public:
- enum Flag {
- CompileShadersWithDebugInfo = 1 << 0
- };
- Q_DECLARE_FLAGS(Flags, Flag)
-
- QRhiResource::Type resourceType() const override;
- virtual bool create() = 0;
-
- Flags flags() const { return m_flags; }
- void setFlags(Flags f) { m_flags = f; }
-
- QRhiShaderStage shaderStage() const { return m_shaderStage; }
- void setShaderStage(const QRhiShaderStage &stage) { m_shaderStage = stage; }
-
- QRhiShaderResourceBindings *shaderResourceBindings() const { return m_shaderResourceBindings; }
- void setShaderResourceBindings(QRhiShaderResourceBindings *srb) { m_shaderResourceBindings = srb; }
-
-protected:
- QRhiComputePipeline(QRhiImplementation *rhi);
- Flags m_flags;
- QRhiShaderStage m_shaderStage;
- QRhiShaderResourceBindings *m_shaderResourceBindings = nullptr;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiComputePipeline::Flags)
-
-class Q_GUI_EXPORT QRhiCommandBuffer : public QRhiResource
-{
-public:
- enum IndexFormat {
- IndexUInt16,
- IndexUInt32
- };
-
- enum BeginPassFlag {
- ExternalContent = 0x01,
- DoNotTrackResourcesForCompute = 0x02
- };
- Q_DECLARE_FLAGS(BeginPassFlags, BeginPassFlag)
-
- QRhiResource::Type resourceType() const override;
-
- void resourceUpdate(QRhiResourceUpdateBatch *resourceUpdates);
-
- void beginPass(QRhiRenderTarget *rt,
- const QColor &colorClearValue,
- const QRhiDepthStencilClearValue &depthStencilClearValue,
- QRhiResourceUpdateBatch *resourceUpdates = nullptr,
- BeginPassFlags flags = {});
- void endPass(QRhiResourceUpdateBatch *resourceUpdates = nullptr);
-
- void setGraphicsPipeline(QRhiGraphicsPipeline *ps);
- using DynamicOffset = QPair<int, quint32>; // binding, offset
- void setShaderResources(QRhiShaderResourceBindings *srb = nullptr,
- int dynamicOffsetCount = 0,
- const DynamicOffset *dynamicOffsets = nullptr);
- using VertexInput = QPair<QRhiBuffer *, quint32>; // buffer, offset
- void setVertexInput(int startBinding, int bindingCount, const VertexInput *bindings,
- QRhiBuffer *indexBuf = nullptr, quint32 indexOffset = 0,
- IndexFormat indexFormat = IndexUInt16);
-
- void setViewport(const QRhiViewport &viewport);
- void setScissor(const QRhiScissor &scissor);
- void setBlendConstants(const QColor &c);
- void setStencilRef(quint32 refValue);
-
- void draw(quint32 vertexCount,
- quint32 instanceCount = 1,
- quint32 firstVertex = 0,
- quint32 firstInstance = 0);
-
- void drawIndexed(quint32 indexCount,
- quint32 instanceCount = 1,
- quint32 firstIndex = 0,
- qint32 vertexOffset = 0,
- quint32 firstInstance = 0);
-
- void debugMarkBegin(const QByteArray &name);
- void debugMarkEnd();
- void debugMarkMsg(const QByteArray &msg);
-
- void beginComputePass(QRhiResourceUpdateBatch *resourceUpdates = nullptr, BeginPassFlags flags = {});
- void endComputePass(QRhiResourceUpdateBatch *resourceUpdates = nullptr);
- void setComputePipeline(QRhiComputePipeline *ps);
- void dispatch(int x, int y, int z);
-
- const QRhiNativeHandles *nativeHandles();
- void beginExternal();
- void endExternal();
-
-protected:
- QRhiCommandBuffer(QRhiImplementation *rhi);
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiCommandBuffer::BeginPassFlags)
-
-struct Q_GUI_EXPORT QRhiReadbackResult
-{
- std::function<void()> completed = nullptr;
- QRhiTexture::Format format;
- QSize pixelSize;
- QByteArray data;
-};
-
-using QRhiBufferReadbackResult = QRhiReadbackResult;
-
-class Q_GUI_EXPORT QRhiResourceUpdateBatch
-{
-public:
- ~QRhiResourceUpdateBatch();
-
- void release();
-
- void merge(QRhiResourceUpdateBatch *other);
- bool hasOptimalCapacity() const;
-
- void updateDynamicBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data);
- void uploadStaticBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data);
- void uploadStaticBuffer(QRhiBuffer *buf, const void *data);
- void readBackBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, QRhiBufferReadbackResult *result);
- void uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc);
- void uploadTexture(QRhiTexture *tex, const QImage &image);
- void copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc = QRhiTextureCopyDescription());
- void readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result);
- void generateMips(QRhiTexture *tex);
-
-private:
- QRhiResourceUpdateBatch(QRhiImplementation *rhi);
- Q_DISABLE_COPY(QRhiResourceUpdateBatch)
- QRhiResourceUpdateBatchPrivate *d;
- friend class QRhiResourceUpdateBatchPrivate;
- friend class QRhi;
-};
-
-struct Q_GUI_EXPORT QRhiDriverInfo
-{
- enum DeviceType {
- UnknownDevice,
- IntegratedDevice,
- DiscreteDevice,
- ExternalDevice,
- VirtualDevice,
- CpuDevice
- };
-
- QByteArray deviceName;
- quint64 deviceId = 0;
- quint64 vendorId = 0;
- DeviceType deviceType = UnknownDevice;
-};
-
-Q_DECLARE_TYPEINFO(QRhiDriverInfo, Q_RELOCATABLE_TYPE);
+}
-#ifndef QT_NO_DEBUG_STREAM
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiDriverInfo &);
-#endif
-
-struct Q_GUI_EXPORT QRhiStats
+template<typename TexType, typename RenderBufferType>
+bool QRhiRenderTargetAttachmentTracker::isUpToDate(const QRhiTextureRenderTargetDescription &desc, const ResIdList &currentResIdList)
{
- qint64 totalPipelineCreationTime = 0;
- // Vulkan or D3D12 memory allocator statistics
- quint32 blockCount = 0;
- quint32 allocCount = 0;
- quint64 usedBytes = 0;
- quint64 unusedBytes = 0;
- // D3D12 only, from IDXGIAdapter3::QueryVideoMemoryInfo(), incl. all resources
- quint64 totalUsageBytes = 0;
-};
+ // Just as setShaderResources() recognizes if an srb's referenced
+ // resources have been rebuilt (got a create() since the srb's
+ // create()), we should do the same for the textures and renderbuffers
+ // referenced from the rendertarget. It is not uncommon that a texture
+ // or ds buffer gets resized due to following a window size in some
+ // form, which involves a create() on them. It is then nice if the
+ // render target auto-rebuilds in beginPass().
-Q_DECLARE_TYPEINFO(QRhiStats, Q_RELOCATABLE_TYPE);
+ ResIdList resIdList;
+ updateResIdList<TexType, RenderBufferType>(desc, &resIdList);
+ return resIdList == currentResIdList;
+}
-#ifndef QT_NO_DEBUG_STREAM
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QRhiStats &);
-#endif
-
-struct Q_GUI_EXPORT QRhiInitParams
-{
-};
-
-class Q_GUI_EXPORT QRhi
+template<typename T>
+inline T *qrhi_objectFromProxyData(QRhiSwapChainProxyData *pd, QWindow *window, QRhi::Implementation impl, uint objectIndex)
{
-public:
- enum Implementation {
- Null,
- Vulkan,
- OpenGLES2,
- D3D11,
- Metal,
- D3D12
- };
-
- enum Flag {
- EnableProfiling = 1 << 0,
- EnableDebugMarkers = 1 << 1,
- PreferSoftwareRenderer = 1 << 2,
- EnablePipelineCacheDataSave = 1 << 3
- };
- Q_DECLARE_FLAGS(Flags, Flag)
-
- enum FrameOpResult {
- FrameOpSuccess = 0,
- FrameOpError,
- FrameOpSwapChainOutOfDate,
- FrameOpDeviceLost
- };
-
- enum Feature {
- MultisampleTexture = 1,
- MultisampleRenderBuffer,
- DebugMarkers,
- Timestamps,
- Instancing,
- CustomInstanceStepRate,
- PrimitiveRestart,
- NonDynamicUniformBuffers,
- NonFourAlignedEffectiveIndexBufferOffset,
- NPOTTextureRepeat,
- RedOrAlpha8IsRed,
- ElementIndexUint,
- Compute,
- WideLines,
- VertexShaderPointSize,
- BaseVertex,
- BaseInstance,
- TriangleFanTopology,
- ReadBackNonUniformBuffer,
- ReadBackNonBaseMipLevel,
- TexelFetch,
- RenderToNonBaseMipLevel,
- IntAttributes,
- ScreenSpaceDerivatives,
- ReadBackAnyTextureFormat,
- PipelineCacheDataLoadSave,
- ImageDataStride,
- RenderBufferImport,
- ThreeDimensionalTextures,
- RenderTo3DTextureSlice,
- TextureArrays,
- Tessellation,
- GeometryShader,
- TextureArrayRange,
- NonFillPolygonMode,
- OneDimensionalTextures,
- OneDimensionalTextureMipmaps,
- HalfAttributes,
- RenderToOneDimensionalTexture,
- ThreeDimensionalTextureMipmaps
- };
-
- enum BeginFrameFlag {
- };
- Q_DECLARE_FLAGS(BeginFrameFlags, BeginFrameFlag)
-
- enum EndFrameFlag {
- SkipPresent = 1 << 0
- };
- Q_DECLARE_FLAGS(EndFrameFlags, EndFrameFlag)
-
- enum ResourceLimit {
- TextureSizeMin = 1,
- TextureSizeMax,
- MaxColorAttachments,
- FramesInFlight,
- MaxAsyncReadbackFrames,
- MaxThreadGroupsPerDimension,
- MaxThreadsPerThreadGroup,
- MaxThreadGroupX,
- MaxThreadGroupY,
- MaxThreadGroupZ,
- TextureArraySizeMax,
- MaxUniformBufferRange,
- MaxVertexInputs,
- MaxVertexOutputs
- };
-
- ~QRhi();
-
- static QRhi *create(Implementation impl,
- QRhiInitParams *params,
- Flags flags = {},
- QRhiNativeHandles *importDevice = nullptr);
- static bool probe(Implementation impl, QRhiInitParams *params);
-
- Implementation backend() const;
- const char *backendName() const;
- static const char *backendName(Implementation impl);
- QRhiDriverInfo driverInfo() const;
- QThread *thread() const;
-
- using CleanupCallback = std::function<void(QRhi *)>;
- void addCleanupCallback(const CleanupCallback &callback);
- void runCleanup();
-
- using GpuFrameTimeCallback = std::function<void(float t)>;
- void addGpuFrameTimeCallback(const GpuFrameTimeCallback &callback);
-
- QRhiGraphicsPipeline *newGraphicsPipeline();
- QRhiComputePipeline *newComputePipeline();
- QRhiShaderResourceBindings *newShaderResourceBindings();
-
- QRhiBuffer *newBuffer(QRhiBuffer::Type type,
- QRhiBuffer::UsageFlags usage,
- quint32 size);
-
- QRhiRenderBuffer *newRenderBuffer(QRhiRenderBuffer::Type type,
- const QSize &pixelSize,
- int sampleCount = 1,
- QRhiRenderBuffer::Flags flags = {},
- QRhiTexture::Format backingFormatHint = QRhiTexture::UnknownFormat);
-
- QRhiTexture *newTexture(QRhiTexture::Format format,
- const QSize &pixelSize,
- int sampleCount = 1,
- QRhiTexture::Flags flags = {});
-
- QRhiTexture *newTexture(QRhiTexture::Format format,
- int width, int height, int depth,
- int sampleCount = 1,
- QRhiTexture::Flags flags = {});
-
- QRhiTexture *newTextureArray(QRhiTexture::Format format,
- int arraySize,
- const QSize &pixelSize,
- int sampleCount = 1,
- QRhiTexture::Flags flags = {});
-
- QRhiSampler *newSampler(QRhiSampler::Filter magFilter,
- QRhiSampler::Filter minFilter,
- QRhiSampler::Filter mipmapMode,
- QRhiSampler::AddressMode addressU,
- QRhiSampler::AddressMode addressV,
- QRhiSampler::AddressMode addressW = QRhiSampler::Repeat);
-
- QRhiTextureRenderTarget *newTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
- QRhiTextureRenderTarget::Flags flags = {});
-
- QRhiSwapChain *newSwapChain();
- FrameOpResult beginFrame(QRhiSwapChain *swapChain, BeginFrameFlags flags = {});
- FrameOpResult endFrame(QRhiSwapChain *swapChain, EndFrameFlags flags = {});
- bool isRecordingFrame() const;
- int currentFrameSlot() const;
-
- FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, BeginFrameFlags flags = {});
- FrameOpResult endOffscreenFrame(EndFrameFlags flags = {});
-
- QRhi::FrameOpResult finish();
-
- QRhiResourceUpdateBatch *nextResourceUpdateBatch();
-
- QList<int> supportedSampleCounts() const;
-
- int ubufAlignment() const;
- int ubufAligned(int v) const;
-
- static int mipLevelsForSize(const QSize &size);
- static QSize sizeForMipLevel(int mipLevel, const QSize &baseLevelSize);
-
- bool isYUpInFramebuffer() const;
- bool isYUpInNDC() const;
- bool isClipDepthZeroToOne() const;
-
- QMatrix4x4 clipSpaceCorrMatrix() const;
-
- bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags = {}) const;
- bool isFeatureSupported(QRhi::Feature feature) const;
- int resourceLimit(ResourceLimit limit) const;
-
- const QRhiNativeHandles *nativeHandles();
- bool makeThreadLocalNativeContextCurrent();
-
- static const int MAX_MIP_LEVELS = 16; // a width and/or height of 65536 should be enough for everyone
-
- void releaseCachedResources();
-
- bool isDeviceLost() const;
-
- QByteArray pipelineCacheData();
- void setPipelineCacheData(const QByteArray &data);
-
- QRhiStats statistics() const;
-
- static QRhiSwapChainProxyData updateSwapChainProxyData(Implementation impl, QWindow *window);
-
-protected:
- QRhi();
-
-private:
- Q_DISABLE_COPY(QRhi)
- QRhiImplementation *d = nullptr;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QRhi::Flags)
-Q_DECLARE_OPERATORS_FOR_FLAGS(QRhi::BeginFrameFlags)
-Q_DECLARE_OPERATORS_FOR_FLAGS(QRhi::EndFrameFlags)
+ Q_ASSERT(objectIndex < std::size(pd->reserved));
+ if (!pd->reserved[objectIndex]) // // was not set, no other choice, do it here, whatever thread this is
+ *pd = QRhi::updateSwapChainProxyData(impl, window);
+ return static_cast<T *>(pd->reserved[objectIndex]);
+}
QT_END_NAMESPACE
diff --git a/src/gui/rhi/qrhi_p_p.h b/src/gui/rhi/qrhi_p_p.h
deleted file mode 100644
index 4e2b62bda6..0000000000
--- a/src/gui/rhi/qrhi_p_p.h
+++ /dev/null
@@ -1,819 +0,0 @@
-// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QRHI_P_H
-#define QRHI_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 "qrhi_p.h"
-#include <QBitArray>
-#include <QAtomicInt>
-#include <QElapsedTimer>
-#include <QLoggingCategory>
-#include <QtCore/qset.h>
-#include <QtCore/qvarlengtharray.h>
-
-QT_BEGIN_NAMESPACE
-
-#define QRHI_RES(t, x) static_cast<t *>(x)
-#define QRHI_RES_RHI(t) t *rhiD = static_cast<t *>(m_rhi)
-
-Q_DECLARE_LOGGING_CATEGORY(QRHI_LOG_INFO)
-
-class QRhiImplementation
-{
-public:
- virtual ~QRhiImplementation();
-
- virtual bool create(QRhi::Flags flags) = 0;
- virtual void destroy() = 0;
-
- virtual QRhiGraphicsPipeline *createGraphicsPipeline() = 0;
- virtual QRhiComputePipeline *createComputePipeline() = 0;
- virtual QRhiShaderResourceBindings *createShaderResourceBindings() = 0;
- virtual QRhiBuffer *createBuffer(QRhiBuffer::Type type,
- QRhiBuffer::UsageFlags usage,
- quint32 size) = 0;
- virtual QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
- const QSize &pixelSize,
- int sampleCount,
- QRhiRenderBuffer::Flags flags,
- QRhiTexture::Format backingFormatHint) = 0;
- virtual QRhiTexture *createTexture(QRhiTexture::Format format,
- const QSize &pixelSize,
- int depth,
- int arraySize,
- int sampleCount,
- QRhiTexture::Flags flags) = 0;
- virtual QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
- QRhiSampler::Filter minFilter,
- QRhiSampler::Filter mipmapMode,
- QRhiSampler:: AddressMode u,
- QRhiSampler::AddressMode v,
- QRhiSampler::AddressMode w) = 0;
-
- virtual QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
- QRhiTextureRenderTarget::Flags flags) = 0;
-
- virtual QRhiSwapChain *createSwapChain() = 0;
- virtual QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) = 0;
- virtual QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) = 0;
- virtual QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) = 0;
- virtual QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) = 0;
- virtual QRhi::FrameOpResult finish() = 0;
-
- virtual void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0;
-
- virtual void beginPass(QRhiCommandBuffer *cb,
- QRhiRenderTarget *rt,
- const QColor &colorClearValue,
- const QRhiDepthStencilClearValue &depthStencilClearValue,
- QRhiResourceUpdateBatch *resourceUpdates,
- QRhiCommandBuffer::BeginPassFlags flags) = 0;
- virtual void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0;
-
- virtual void setGraphicsPipeline(QRhiCommandBuffer *cb,
- QRhiGraphicsPipeline *ps) = 0;
-
- virtual void setShaderResources(QRhiCommandBuffer *cb,
- QRhiShaderResourceBindings *srb,
- int dynamicOffsetCount,
- const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) = 0;
-
- virtual void setVertexInput(QRhiCommandBuffer *cb,
- int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
- QRhiBuffer *indexBuf, quint32 indexOffset,
- QRhiCommandBuffer::IndexFormat indexFormat) = 0;
-
- virtual void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) = 0;
- virtual void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) = 0;
- virtual void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) = 0;
- virtual void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) = 0;
-
- virtual void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
- quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) = 0;
- virtual void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
- quint32 instanceCount, quint32 firstIndex,
- qint32 vertexOffset, quint32 firstInstance) = 0;
-
- virtual void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) = 0;
- virtual void debugMarkEnd(QRhiCommandBuffer *cb) = 0;
- virtual void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) = 0;
-
- virtual void beginComputePass(QRhiCommandBuffer *cb,
- QRhiResourceUpdateBatch *resourceUpdates,
- QRhiCommandBuffer::BeginPassFlags flags) = 0;
- virtual void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) = 0;
- virtual void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) = 0;
- virtual void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) = 0;
-
- virtual const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) = 0;
- virtual void beginExternal(QRhiCommandBuffer *cb) = 0;
- virtual void endExternal(QRhiCommandBuffer *cb) = 0;
-
- virtual QList<int> supportedSampleCounts() const = 0;
- virtual int ubufAlignment() const = 0;
- virtual bool isYUpInFramebuffer() const = 0;
- virtual bool isYUpInNDC() const = 0;
- virtual bool isClipDepthZeroToOne() const = 0;
- virtual QMatrix4x4 clipSpaceCorrMatrix() const = 0;
- virtual bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const = 0;
- virtual bool isFeatureSupported(QRhi::Feature feature) const = 0;
- virtual int resourceLimit(QRhi::ResourceLimit limit) const = 0;
- virtual const QRhiNativeHandles *nativeHandles() = 0;
- virtual QRhiDriverInfo driverInfo() const = 0;
- virtual QRhiStats statistics() = 0;
- virtual bool makeThreadLocalNativeContextCurrent() = 0;
- virtual void releaseCachedResources() = 0;
- virtual bool isDeviceLost() const = 0;
-
- virtual QByteArray pipelineCacheData() = 0;
- virtual void setPipelineCacheData(const QByteArray &data) = 0;
-
- bool isCompressedFormat(QRhiTexture::Format format) const;
- void compressedFormatInfo(QRhiTexture::Format format, const QSize &size,
- quint32 *bpl, quint32 *byteSize,
- QSize *blockDim) const;
- void textureFormatInfo(QRhiTexture::Format format, const QSize &size,
- quint32 *bpl, quint32 *byteSize, quint32 *bytesPerPixel) const;
-
- // only really care about resources that own native graphics resources underneath
- void registerResource(QRhiResource *res)
- {
- resources.insert(res);
- }
-
- void unregisterResource(QRhiResource *res)
- {
- resources.remove(res);
- }
-
- QSet<QRhiResource *> activeResources() const
- {
- return resources;
- }
-
- void addDeleteLater(QRhiResource *res)
- {
- if (inFrame)
- pendingDeleteResources.insert(res);
- else
- delete res;
- }
-
- void addCleanupCallback(const QRhi::CleanupCallback &callback)
- {
- cleanupCallbacks.append(callback);
- }
-
- void addGpuFrameTimeCallback(const QRhi::GpuFrameTimeCallback &callback)
- {
- gpuFrameTimeCallbacks.append(callback);
- }
-
- bool hasGpuFrameTimeCallback() const
- {
- return !gpuFrameTimeCallbacks.isEmpty();
- }
-
- void runGpuFrameTimeCallbacks(float t)
- {
- for (const QRhi::GpuFrameTimeCallback &f : std::as_const(gpuFrameTimeCallbacks))
- f(t);
- }
-
- bool sanityCheckGraphicsPipeline(QRhiGraphicsPipeline *ps);
- bool sanityCheckShaderResourceBindings(QRhiShaderResourceBindings *srb);
- void updateLayoutDesc(QRhiShaderResourceBindings *srb);
-
- quint32 pipelineCacheRhiId() const
- {
- const quint32 ver = (QT_VERSION_MAJOR << 16) | (QT_VERSION_MINOR << 8) | (QT_VERSION_PATCH);
- return (quint32(implType) << 24) | ver;
- }
-
- void pipelineCreationStart()
- {
- pipelineCreationTimer.start();
- }
-
- void pipelineCreationEnd()
- {
- accumulatedPipelineCreationTime += pipelineCreationTimer.elapsed();
- }
-
- qint64 totalPipelineCreationTime() const
- {
- return accumulatedPipelineCreationTime;
- }
-
- QRhiVertexInputAttribute::Format shaderDescVariableFormatToVertexInputFormat(QShaderDescription::VariableType type) const;
- quint32 byteSizePerVertexForVertexInputFormat(QRhiVertexInputAttribute::Format format) const;
-
- static const QRhiShaderResourceBinding::Data *shaderResourceBindingData(const QRhiShaderResourceBinding &binding)
- {
- return &binding.d;
- }
-
- static QRhiShaderResourceBinding::Data *shaderResourceBindingData(QRhiShaderResourceBinding &binding)
- {
- return &binding.d;
- }
-
- static bool sortedBindingLessThan(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBinding &b)
- {
- return a.d.binding < b.d.binding;
- }
-
- QRhi *q;
-
- static const int MAX_SHADER_CACHE_ENTRIES = 128;
-
- bool debugMarkers = false;
- int currentFrameSlot = 0; // for vk, mtl, and similar. unused by gl and d3d11.
- bool inFrame = false;
-
-private:
- QRhi::Implementation implType;
- QThread *implThread;
- QVarLengthArray<QRhiResourceUpdateBatch *, 4> resUpdPool;
- quint64 resUpdPoolMap = 0;
- int lastResUpdIdx = -1;
- QSet<QRhiResource *> resources;
- QSet<QRhiResource *> pendingDeleteResources;
- QVarLengthArray<QRhi::CleanupCallback, 4> cleanupCallbacks;
- QVarLengthArray<QRhi::GpuFrameTimeCallback, 4> gpuFrameTimeCallbacks;
- QElapsedTimer pipelineCreationTimer;
- qint64 accumulatedPipelineCreationTime = 0;
-
- friend class QRhi;
- friend class QRhiResourceUpdateBatchPrivate;
-};
-
-enum QRhiTargetRectBoundMode
-{
- UnBounded,
- Bounded
-};
-
-template<QRhiTargetRectBoundMode boundingMode, typename T, size_t N>
-bool qrhi_toTopLeftRenderTargetRect(const QSize &outputSize, const std::array<T, N> &r,
- T *x, T *y, T *w, T *h)
-{
- // x,y are bottom-left in QRhiScissor and QRhiViewport but top-left in
- // Vulkan/Metal/D3D. Our input is an OpenGL-style scissor rect where both
- // negative x or y, and partly or completely out of bounds rects are
- // allowed. The only thing the input here cannot have is a negative width
- // or height. We must handle all other input gracefully, clamping to a zero
- // width or height rect in the worst case, and ensuring the resulting rect
- // is inside the rendertarget's bounds because some APIs' validation/debug
- // layers are allergic to out of bounds scissor rects.
-
- const T outputWidth = outputSize.width();
- const T outputHeight = outputSize.height();
- const T inputWidth = r[2];
- const T inputHeight = r[3];
-
- if (inputWidth < 0 || inputHeight < 0)
- return false;
-
- *x = r[0];
- *y = outputHeight - (r[1] + inputHeight);
- *w = inputWidth;
- *h = inputHeight;
-
- if (boundingMode == Bounded) {
- const T widthOffset = *x < 0 ? -*x : 0;
- const T heightOffset = *y < 0 ? -*y : 0;
- *w = *x < outputWidth ? qMax<T>(0, inputWidth - widthOffset) : 0;
- *h = *y < outputHeight ? qMax<T>(0, inputHeight - heightOffset) : 0;
-
- if (outputWidth > 0)
- *x = qBound<T>(0, *x, outputWidth - 1);
- if (outputHeight > 0)
- *y = qBound<T>(0, *y, outputHeight - 1);
-
- if (*x + *w > outputWidth)
- *w = qMax<T>(0, outputWidth - *x);
- if (*y + *h > outputHeight)
- *h = qMax<T>(0, outputHeight - *y);
- }
- return true;
-}
-
-struct QRhiBufferDataPrivate
-{
- Q_DISABLE_COPY_MOVE(QRhiBufferDataPrivate)
- QRhiBufferDataPrivate() { }
- ~QRhiBufferDataPrivate() { delete[] largeData; }
- int ref = 1;
- quint32 size = 0;
- quint32 largeAlloc = 0;
- char *largeData = nullptr;
- static constexpr quint32 SMALL_DATA_SIZE = 1024;
- char data[SMALL_DATA_SIZE];
-};
-
-// no detach-with-contents, no atomic refcount, no shrink
-class QRhiBufferData
-{
-public:
- QRhiBufferData() = default;
- ~QRhiBufferData()
- {
- if (d && !--d->ref)
- delete d;
- }
- QRhiBufferData(const QRhiBufferData &other)
- : d(other.d)
- {
- if (d)
- d->ref += 1;
- }
- QRhiBufferData &operator=(const QRhiBufferData &other)
- {
- if (d == other.d)
- return *this;
- if (other.d)
- other.d->ref += 1;
- if (d && !--d->ref)
- delete d;
- d = other.d;
- return *this;
- }
- const char *constData() const
- {
- return d->size <= QRhiBufferDataPrivate::SMALL_DATA_SIZE ? d->data : d->largeData;
- }
- quint32 size() const
- {
- return d->size;
- }
- void assign(const char *s, quint32 size)
- {
- if (!d) {
- d = new QRhiBufferDataPrivate;
- } else if (d->ref != 1) {
- d->ref -= 1;
- d = new QRhiBufferDataPrivate;
- }
- d->size = size;
- if (size <= QRhiBufferDataPrivate::SMALL_DATA_SIZE) {
- memcpy(d->data, s, size);
- } else {
- if (d->largeAlloc < size) {
- delete[] d->largeData;
- d->largeAlloc = size;
- d->largeData = new char[size];
- }
- memcpy(d->largeData, s, size);
- }
- }
-private:
- QRhiBufferDataPrivate *d = nullptr;
-};
-
-Q_DECLARE_TYPEINFO(QRhiBufferData, Q_RELOCATABLE_TYPE);
-
-class QRhiResourceUpdateBatchPrivate
-{
-public:
- struct BufferOp {
- enum Type {
- DynamicUpdate,
- StaticUpload,
- Read
- };
- Type type;
- QRhiBuffer *buf;
- quint32 offset;
- QRhiBufferData data;
- quint32 readSize;
- QRhiBufferReadbackResult *result;
-
- static BufferOp dynamicUpdate(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
- {
- BufferOp op = {};
- op.type = DynamicUpdate;
- op.buf = buf;
- op.offset = offset;
- const int effectiveSize = size ? size : buf->size();
- op.data.assign(reinterpret_cast<const char *>(data), effectiveSize);
- return op;
- }
-
- static void changeToDynamicUpdate(BufferOp *op, QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
- {
- op->type = DynamicUpdate;
- op->buf = buf;
- op->offset = offset;
- const int effectiveSize = size ? size : buf->size();
- op->data.assign(reinterpret_cast<const char *>(data), effectiveSize);
- }
-
- static BufferOp staticUpload(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
- {
- BufferOp op = {};
- op.type = StaticUpload;
- op.buf = buf;
- op.offset = offset;
- const int effectiveSize = size ? size : buf->size();
- op.data.assign(reinterpret_cast<const char *>(data), effectiveSize);
- return op;
- }
-
- static void changeToStaticUpload(BufferOp *op, QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
- {
- op->type = StaticUpload;
- op->buf = buf;
- op->offset = offset;
- const int effectiveSize = size ? size : buf->size();
- op->data.assign(reinterpret_cast<const char *>(data), effectiveSize);
- }
-
- static BufferOp read(QRhiBuffer *buf, quint32 offset, quint32 size, QRhiBufferReadbackResult *result)
- {
- BufferOp op = {};
- op.type = Read;
- op.buf = buf;
- op.offset = offset;
- op.readSize = size;
- op.result = result;
- return op;
- }
- };
-
- struct TextureOp {
- enum Type {
- Upload,
- Copy,
- Read,
- GenMips
- };
- Type type;
- QRhiTexture *dst;
- // Specifying multiple uploads for a subresource must be supported.
- // In the backend this can then end up, where applicable, as a
- // single, batched copy operation with only one set of barriers.
- // This helps when doing for example glyph cache fills.
- using MipLevelUploadList = std::array<QVector<QRhiTextureSubresourceUploadDescription>, QRhi::MAX_MIP_LEVELS>;
- QVarLengthArray<MipLevelUploadList, 6> subresDesc;
- QRhiTexture *src;
- QRhiTextureCopyDescription desc;
- QRhiReadbackDescription rb;
- QRhiReadbackResult *result;
-
- static TextureOp upload(QRhiTexture *tex, const QRhiTextureUploadDescription &desc)
- {
- TextureOp op = {};
- op.type = Upload;
- op.dst = tex;
- int maxLayer = -1;
- for (auto it = desc.cbeginEntries(), itEnd = desc.cendEntries(); it != itEnd; ++it) {
- if (it->layer() > maxLayer)
- maxLayer = it->layer();
- }
- op.subresDesc.resize(maxLayer + 1);
- for (auto it = desc.cbeginEntries(), itEnd = desc.cendEntries(); it != itEnd; ++it)
- op.subresDesc[it->layer()][it->level()].append(it->description());
- return op;
- }
-
- static TextureOp copy(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc)
- {
- TextureOp op = {};
- op.type = Copy;
- op.dst = dst;
- op.src = src;
- op.desc = desc;
- return op;
- }
-
- static TextureOp read(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
- {
- TextureOp op = {};
- op.type = Read;
- op.rb = rb;
- op.result = result;
- return op;
- }
-
- static TextureOp genMips(QRhiTexture *tex)
- {
- TextureOp op = {};
- op.type = GenMips;
- op.dst = tex;
- return op;
- }
- };
-
- int activeBufferOpCount = 0; // this is the real number of used elements in bufferOps, not bufferOps.count()
- static const int BUFFER_OPS_STATIC_ALLOC = 1024;
- QVarLengthArray<BufferOp, BUFFER_OPS_STATIC_ALLOC> bufferOps;
-
- int activeTextureOpCount = 0; // this is the real number of used elements in textureOps, not textureOps.count()
- static const int TEXTURE_OPS_STATIC_ALLOC = 256;
- QVarLengthArray<TextureOp, TEXTURE_OPS_STATIC_ALLOC> textureOps;
-
- QRhiResourceUpdateBatch *q = nullptr;
- QRhiImplementation *rhi = nullptr;
- int poolIndex = -1;
-
- void free();
- void merge(QRhiResourceUpdateBatchPrivate *other);
- bool hasOptimalCapacity() const;
- void trimOpLists();
-
- static QRhiResourceUpdateBatchPrivate *get(QRhiResourceUpdateBatch *b) { return b->d; }
-};
-
-template<typename T>
-struct QRhiBatchedBindings
-{
- void feed(int binding, T resource) { // binding must be strictly increasing
- if (curBinding == -1 || binding > curBinding + 1) {
- finish();
- curBatch.startBinding = binding;
- curBatch.resources.clear();
- curBatch.resources.append(resource);
- } else {
- Q_ASSERT(binding == curBinding + 1);
- curBatch.resources.append(resource);
- }
- curBinding = binding;
- }
-
- bool finish() {
- if (!curBatch.resources.isEmpty())
- batches.append(curBatch);
- return !batches.isEmpty();
- }
-
- void clear() {
- batches.clear();
- curBatch.resources.clear();
- curBinding = -1;
- }
-
- struct Batch {
- uint startBinding;
- QVarLengthArray<T, 4> resources;
-
- bool operator==(const Batch &other) const
- {
- return startBinding == other.startBinding && resources == other.resources;
- }
-
- bool operator!=(const Batch &other) const
- {
- return !operator==(other);
- }
- };
-
- QVarLengthArray<Batch, 4> batches; // sorted by startBinding
-
- bool operator==(const QRhiBatchedBindings<T> &other) const
- {
- return batches == other.batches;
- }
-
- bool operator!=(const QRhiBatchedBindings<T> &other) const
- {
- return !operator==(other);
- }
-
-private:
- Batch curBatch;
- int curBinding = -1;
-};
-
-class QRhiGlobalObjectIdGenerator
-{
-public:
-#ifdef Q_ATOMIC_INT64_IS_SUPPORTED
- using Type = quint64;
-#else
- using Type = quint32;
-#endif
- static Type newId();
-};
-
-class QRhiPassResourceTracker
-{
-public:
- bool isEmpty() const;
- void reset();
-
- struct UsageState {
- int layout;
- int access;
- int stage;
- };
-
- enum BufferStage {
- BufVertexInputStage,
- BufVertexStage,
- BufTCStage,
- BufTEStage,
- BufFragmentStage,
- BufComputeStage,
- BufGeometryStage
- };
-
- enum BufferAccess {
- BufVertexInput,
- BufIndexRead,
- BufUniformRead,
- BufStorageLoad,
- BufStorageStore,
- BufStorageLoadStore
- };
-
- void registerBuffer(QRhiBuffer *buf, int slot, BufferAccess *access, BufferStage *stage,
- const UsageState &state);
-
- enum TextureStage {
- TexVertexStage,
- TexTCStage,
- TexTEStage,
- TexFragmentStage,
- TexColorOutputStage,
- TexDepthOutputStage,
- TexComputeStage,
- TexGeometryStage
- };
-
- enum TextureAccess {
- TexSample,
- TexColorOutput,
- TexDepthOutput,
- TexStorageLoad,
- TexStorageStore,
- TexStorageLoadStore
- };
-
- void registerTexture(QRhiTexture *tex, TextureAccess *access, TextureStage *stage,
- const UsageState &state);
-
- struct Buffer {
- int slot;
- BufferAccess access;
- BufferStage stage;
- UsageState stateAtPassBegin;
- };
-
- using BufferIterator = QHash<QRhiBuffer *, Buffer>::const_iterator;
- BufferIterator cbeginBuffers() const { return m_buffers.cbegin(); }
- BufferIterator cendBuffers() const { return m_buffers.cend(); }
-
- struct Texture {
- TextureAccess access;
- TextureStage stage;
- UsageState stateAtPassBegin;
- };
-
- using TextureIterator = QHash<QRhiTexture *, Texture>::const_iterator;
- TextureIterator cbeginTextures() const { return m_textures.cbegin(); }
- TextureIterator cendTextures() const { return m_textures.cend(); }
-
- static BufferStage toPassTrackerBufferStage(QRhiShaderResourceBinding::StageFlags stages);
- static TextureStage toPassTrackerTextureStage(QRhiShaderResourceBinding::StageFlags stages);
-
-private:
- QHash<QRhiBuffer *, Buffer> m_buffers;
- QHash<QRhiTexture *, Texture> m_textures;
-};
-
-Q_DECLARE_TYPEINFO(QRhiPassResourceTracker::Buffer, Q_RELOCATABLE_TYPE);
-Q_DECLARE_TYPEINFO(QRhiPassResourceTracker::Texture, Q_RELOCATABLE_TYPE);
-
-template<typename T, int GROW = 1024>
-class QRhiBackendCommandList
-{
-public:
- QRhiBackendCommandList() = default;
- ~QRhiBackendCommandList() { delete[] v; }
- inline void reset() { p = 0; }
- inline bool isEmpty() const { return p == 0; }
- inline T &get() {
- if (p == a) {
- a += GROW;
- T *nv = new T[a];
- if (v) {
- memcpy(nv, v, p * sizeof(T));
- delete[] v;
- }
- v = nv;
- }
- return v[p++];
- }
- inline void unget() { --p; }
- inline T *cbegin() const { return v; }
- inline T *cend() const { return v + p; }
- inline T *begin() { return v; }
- inline T *end() { return v + p; }
-private:
- Q_DISABLE_COPY(QRhiBackendCommandList)
- T *v = nullptr;
- int a = 0;
- int p = 0;
-};
-
-struct QRhiRenderTargetAttachmentTracker
-{
- struct ResId { quint64 id; uint generation; };
- using ResIdList = QVarLengthArray<ResId, 8 * 2 + 1>; // color, resolve, ds
-
- template<typename TexType, typename RenderBufferType>
- static void updateResIdList(const QRhiTextureRenderTargetDescription &desc, ResIdList *dst);
-
- template<typename TexType, typename RenderBufferType>
- static bool isUpToDate(const QRhiTextureRenderTargetDescription &desc, const ResIdList &currentResIdList);
-};
-
-inline bool operator==(const QRhiRenderTargetAttachmentTracker::ResId &a, const QRhiRenderTargetAttachmentTracker::ResId &b)
-{
- return a.id == b.id && a.generation == b.generation;
-}
-
-inline bool operator!=(const QRhiRenderTargetAttachmentTracker::ResId &a, const QRhiRenderTargetAttachmentTracker::ResId &b)
-{
- return !(a == b);
-}
-
-template<typename TexType, typename RenderBufferType>
-void QRhiRenderTargetAttachmentTracker::updateResIdList(const QRhiTextureRenderTargetDescription &desc, ResIdList *dst)
-{
- const bool hasDepthStencil = desc.depthStencilBuffer() || desc.depthTexture();
- dst->resize(desc.colorAttachmentCount() * 2 + (hasDepthStencil ? 1 : 0));
- int n = 0;
- for (auto it = desc.cbeginColorAttachments(), itEnd = desc.cendColorAttachments(); it != itEnd; ++it, ++n) {
- const QRhiColorAttachment &colorAtt(*it);
- if (colorAtt.texture()) {
- TexType *texD = QRHI_RES(TexType, colorAtt.texture());
- (*dst)[n] = { texD->globalResourceId(), texD->generation };
- } else if (colorAtt.renderBuffer()) {
- RenderBufferType *rbD = QRHI_RES(RenderBufferType, colorAtt.renderBuffer());
- (*dst)[n] = { rbD->globalResourceId(), rbD->generation };
- } else {
- (*dst)[n] = { 0, 0 };
- }
- ++n;
- if (colorAtt.resolveTexture()) {
- TexType *texD = QRHI_RES(TexType, colorAtt.resolveTexture());
- (*dst)[n] = { texD->globalResourceId(), texD->generation };
- } else {
- (*dst)[n] = { 0, 0 };
- }
- }
- if (hasDepthStencil) {
- if (desc.depthTexture()) {
- TexType *depthTexD = QRHI_RES(TexType, desc.depthTexture());
- (*dst)[n] = { depthTexD->globalResourceId(), depthTexD->generation };
- } else if (desc.depthStencilBuffer()) {
- RenderBufferType *depthRbD = QRHI_RES(RenderBufferType, desc.depthStencilBuffer());
- (*dst)[n] = { depthRbD->globalResourceId(), depthRbD->generation };
- } else {
- (*dst)[n] = { 0, 0 };
- }
- }
-}
-
-template<typename TexType, typename RenderBufferType>
-bool QRhiRenderTargetAttachmentTracker::isUpToDate(const QRhiTextureRenderTargetDescription &desc, const ResIdList &currentResIdList)
-{
- // Just as setShaderResources() recognizes if an srb's referenced
- // resources have been rebuilt (got a create() since the srb's
- // create()), we should do the same for the textures and renderbuffers
- // referenced from the rendertarget. It is not uncommon that a texture
- // or ds buffer gets resized due to following a window size in some
- // form, which involves a create() on them. It is then nice if the
- // render target auto-rebuilds in beginPass().
-
- ResIdList resIdList;
- updateResIdList<TexType, RenderBufferType>(desc, &resIdList);
- return resIdList == currentResIdList;
-}
-
-template<typename T>
-inline T *qrhi_objectFromProxyData(QRhiSwapChainProxyData *pd, QWindow *window, QRhi::Implementation impl, uint objectIndex)
-{
- Q_ASSERT(objectIndex < std::size(pd->reserved));
- if (!pd->reserved[objectIndex]) // // was not set, no other choice, do it here, whatever thread this is
- *pd = QRhi::updateSwapChainProxyData(impl, window);
- return static_cast<T *>(pd->reserved[objectIndex]);
-}
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/gui/rhi/qrhi_platform.h b/src/gui/rhi/qrhi_platform.h
new file mode 100644
index 0000000000..e7be522c52
--- /dev/null
+++ b/src/gui/rhi/qrhi_platform.h
@@ -0,0 +1,175 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QRHIPLATFORM_H
+#define QRHIPLATFORM_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is part of the RHI API, with limited compatibility guarantees.
+// Usage of this API may make your code source and binary incompatible with
+// future versions of Qt.
+//
+
+#include <rhi/qrhi.h>
+
+#if QT_CONFIG(opengl)
+#include <QtGui/qsurfaceformat.h>
+#endif
+
+#if QT_CONFIG(vulkan)
+#include <QtGui/qvulkaninstance.h>
+#endif
+
+#if QT_CONFIG(metal) || defined(Q_QDOC)
+Q_FORWARD_DECLARE_OBJC_CLASS(MTLDevice);
+Q_FORWARD_DECLARE_OBJC_CLASS(MTLCommandQueue);
+Q_FORWARD_DECLARE_OBJC_CLASS(MTLCommandBuffer);
+Q_FORWARD_DECLARE_OBJC_CLASS(MTLRenderCommandEncoder);
+#endif
+
+QT_BEGIN_NAMESPACE
+
+struct Q_GUI_EXPORT QRhiNullInitParams : public QRhiInitParams
+{
+};
+
+struct Q_GUI_EXPORT QRhiNullNativeHandles : public QRhiNativeHandles
+{
+};
+
+#if QT_CONFIG(opengl) || defined(Q_QDOC)
+
+class QOpenGLContext;
+class QOffscreenSurface;
+class QSurface;
+class QWindow;
+
+struct Q_GUI_EXPORT QRhiGles2InitParams : public QRhiInitParams
+{
+ QRhiGles2InitParams();
+
+ QSurfaceFormat format;
+ QSurface *fallbackSurface = nullptr;
+ QWindow *window = nullptr;
+ QOpenGLContext *shareContext = nullptr;
+
+ static QOffscreenSurface *newFallbackSurface(const QSurfaceFormat &format = QSurfaceFormat::defaultFormat());
+};
+
+struct Q_GUI_EXPORT QRhiGles2NativeHandles : public QRhiNativeHandles
+{
+ QOpenGLContext *context = nullptr;
+};
+
+#endif // opengl/qdoc
+
+#if (QT_CONFIG(vulkan) && __has_include(<vulkan/vulkan.h>)) || defined(Q_QDOC)
+
+struct Q_GUI_EXPORT QRhiVulkanInitParams : public QRhiInitParams
+{
+ QVulkanInstance *inst = nullptr;
+ QWindow *window = nullptr;
+ QByteArrayList deviceExtensions;
+
+ static QByteArrayList preferredInstanceExtensions();
+ static QByteArrayList preferredExtensionsForImportedDevice();
+};
+
+struct Q_GUI_EXPORT QRhiVulkanNativeHandles : public QRhiNativeHandles
+{
+ // to import a physical device (always required)
+ VkPhysicalDevice physDev = VK_NULL_HANDLE;
+ // to import a device and queue
+ VkDevice dev = VK_NULL_HANDLE;
+ quint32 gfxQueueFamilyIdx = 0;
+ quint32 gfxQueueIdx = 0;
+ // and optionally, the mem allocator
+ void *vmemAllocator = nullptr;
+
+ // only for querying (rhi->nativeHandles())
+ VkQueue gfxQueue = VK_NULL_HANDLE;
+ QVulkanInstance *inst = nullptr;
+};
+
+struct Q_GUI_EXPORT QRhiVulkanCommandBufferNativeHandles : public QRhiNativeHandles
+{
+ VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
+};
+
+struct Q_GUI_EXPORT QRhiVulkanRenderPassNativeHandles : public QRhiNativeHandles
+{
+ VkRenderPass renderPass = VK_NULL_HANDLE;
+};
+
+#endif // vulkan/qdoc
+
+#if defined(Q_OS_WIN) || defined(Q_QDOC)
+
+// no d3d includes here, to prevent precompiled header mess due to COM, hence the void pointers
+
+struct Q_GUI_EXPORT QRhiD3D11InitParams : public QRhiInitParams
+{
+ bool enableDebugLayer = false;
+};
+
+struct Q_GUI_EXPORT QRhiD3D11NativeHandles : public QRhiNativeHandles
+{
+ // to import a device and a context
+ void *dev = nullptr;
+ void *context = nullptr;
+ // alternatively, to specify the device feature level and/or the adapter to use
+ int featureLevel = 0;
+ quint32 adapterLuidLow = 0;
+ qint32 adapterLuidHigh = 0;
+};
+
+struct Q_GUI_EXPORT QRhiD3D12InitParams : public QRhiInitParams
+{
+ bool enableDebugLayer = false;
+};
+
+struct Q_GUI_EXPORT QRhiD3D12NativeHandles : public QRhiNativeHandles
+{
+ // to import a device
+ void *dev = nullptr;
+ int minimumFeatureLevel = 0;
+ // to just specify the adapter to use, set these and leave dev set to null
+ quint32 adapterLuidLow = 0;
+ qint32 adapterLuidHigh = 0;
+ // in addition, can specify the command queue to use
+ void *commandQueue = nullptr;
+};
+
+struct Q_GUI_EXPORT QRhiD3D12CommandBufferNativeHandles : public QRhiNativeHandles
+{
+ void *commandList = nullptr; // ID3D12GraphicsCommandList1
+};
+
+#endif // WIN/QDOC
+
+#if QT_CONFIG(metal) || defined(Q_QDOC)
+
+struct Q_GUI_EXPORT QRhiMetalInitParams : public QRhiInitParams
+{
+};
+
+struct Q_GUI_EXPORT QRhiMetalNativeHandles : public QRhiNativeHandles
+{
+ MTLDevice *dev = nullptr;
+ MTLCommandQueue *cmdQueue = nullptr;
+};
+
+struct Q_GUI_EXPORT QRhiMetalCommandBufferNativeHandles : public QRhiNativeHandles
+{
+ MTLCommandBuffer *commandBuffer = nullptr;
+ MTLRenderCommandEncoder *encoder = nullptr;
+};
+
+#endif // MACOS/IOS/QDOC
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp
index d9f323eb1a..b09baf57b2 100644
--- a/src/gui/rhi/qrhid3d11.cpp
+++ b/src/gui/rhi/qrhid3d11.cpp
@@ -1,16 +1,14 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qrhid3d11_p_p.h"
-#include "qshader_p.h"
+#include "qrhid3d11_p.h"
+#include "qshader.h"
#include "vs_test_p.h"
#include <QWindow>
#include <qmath.h>
-#include <private/qsystemlibrary_p.h>
#include <QtCore/qcryptographichash.h>
#include <QtCore/private/qsystemerror_p.h>
-
-#include <d3dcompiler.h>
+#include "qrhid3dhelpers_p.h"
QT_BEGIN_NAMESPACE
@@ -28,10 +26,13 @@ using namespace Qt::StringLiterals;
/*!
\class QRhiD3D11InitParams
- \internal
\inmodule QtGui
+ \since 6.6
\brief Direct3D 11 specific initialization parameters.
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
A D3D11-based QRhi needs no special parameters for initialization. If
desired, enableDebugLayer can be set to \c true to enable the Direct3D
debug layer. This can be useful during development, but should be avoided
@@ -70,16 +71,71 @@ using namespace Qt::StringLiterals;
*/
/*!
+ \variable QRhiD3D11InitParams::enableDebugLayer
+
+ When set to true, a debug device is created, assuming the debug layer is
+ available. The default value is false.
+*/
+
+/*!
\class QRhiD3D11NativeHandles
- \internal
\inmodule QtGui
+ \since 6.6
\brief Holds the D3D device and device context used by the QRhi.
\note The class uses \c{void *} as the type since including the COM-based
\c{d3d11.h} headers is not acceptable here. The actual types are
\c{ID3D11Device *} and \c{ID3D11DeviceContext *}.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
+/*!
+ \variable QRhiD3D11NativeHandles::dev
+
+ Points to a
+ \l{https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nn-d3d11-id3d11device}{ID3D11Device}
+ or left set to \nullptr if no existing device is to be imported.
+
+ \note When importing a device, both the device and the device context must be set to valid objects.
+*/
+
+/*!
+ \variable QRhiD3D11NativeHandles::context
+
+ Points to a \l{https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nn-d3d11-id3d11devicecontext}{ID3D11DeviceContext}
+ or left set to \nullptr if no existing device context is to be imported.
+
+ \note When importing a device, both the device and the device context must be set to valid objects.
+*/
+
+/*!
+ \variable QRhiD3D11NativeHandles::featureLevel
+
+ Specifies the feature level passed to
+ \l{https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-d3d11createdevice}{D3D11CreateDevice()}.
+ Relevant only when QRhi creates the device, ignored when importing a device
+ and device context. When not set, the default rules outlined in the D3D
+ documentation apply.
+*/
+
+/*!
+ \variable QRhiD3D11NativeHandles::adapterLuidLow
+
+ The low part of the local identifier (LUID) of the DXGI adapter to use.
+ Relevant only when QRhi creates the device, ignored when importing a device
+ and device context.
+*/
+
+/*!
+ \variable QRhiD3D11NativeHandles::adapterLuidHigh
+
+ The high part of the local identifier (LUID) of the DXGI adapter to use.
+ Relevant only when QRhi creates the device, ignored when importing a device
+ and device context.
+*/
+
// help mingw with its ancient sdk headers
#ifndef DXGI_ADAPTER_FLAG_SOFTWARE
#define DXGI_ADAPTER_FLAG_SOFTWARE 2
@@ -161,13 +217,14 @@ bool QRhiD3D11::create(QRhi::Flags flags)
if (qEnvironmentVariableIntValue("QT_D3D_FLIP_DISCARD"))
qWarning("The default swap effect is FLIP_DISCARD, QT_D3D_FLIP_DISCARD is now ignored");
- if (qEnvironmentVariableIntValue("QT_D3D_NO_FLIP"))
- qWarning("Non-FLIP swapchains are no longer supported, QT_D3D_NO_FLIP is now ignored");
-
- qCDebug(QRHI_LOG_INFO, "FLIP_* swapchain supported = true, ALLOW_TEARING supported = %s",
- supportsAllowTearing ? "true" : "false");
+ // Support for flip model swapchains is required now (since we are
+ // targeting Windows 10+), but the option for using the old model is still
+ // there. (some features are not supported then, however)
+ useLegacySwapchainModel = qEnvironmentVariableIntValue("QT_D3D_NO_FLIP");
- qCDebug(QRHI_LOG_INFO, "Default swap effect: FLIP_DISCARD");
+ qCDebug(QRHI_LOG_INFO, "FLIP_* swapchain supported = true, ALLOW_TEARING supported = %s, use legacy (non-FLIP) model = %s",
+ supportsAllowTearing ? "true" : "false",
+ useLegacySwapchainModel ? "true" : "false");
if (!importedDeviceAndContext) {
IDXGIAdapter1 *adapter;
@@ -216,9 +273,7 @@ bool QRhiD3D11::create(QRhi::Flags flags)
if (!activeAdapter && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) {
activeAdapter = adapter;
adapterLuid = desc.AdapterLuid;
- driverInfoStruct.deviceName = name.toUtf8();
- driverInfoStruct.deviceId = desc.DeviceId;
- driverInfoStruct.vendorId = desc.VendorId;
+ QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
qCDebug(QRHI_LOG_INFO, " using this adapter");
} else {
adapter->Release();
@@ -261,21 +316,46 @@ bool QRhiD3D11::create(QRhi::Flags flags)
return false;
}
+ const bool supports11_1 = SUCCEEDED(ctx->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast<void **>(&context)));
+ ctx->Release();
+ if (!supports11_1) {
+ qWarning("ID3D11DeviceContext1 not supported");
+ return false;
+ }
+
// Test if creating a Shader Model 5.0 vertex shader works; we want to
// fail already in create() if that's not the case.
ID3D11VertexShader *testShader = nullptr;
if (SUCCEEDED(dev->CreateVertexShader(g_testVertexShader, sizeof(g_testVertexShader), nullptr, &testShader))) {
testShader->Release();
} else {
- qWarning("D3D11 smoke test failed (failed to create vertex shader)");
- ctx->Release();
+ static const char *msg = "D3D11 smoke test: Failed to create vertex shader";
+ if (flags.testFlag(QRhi::SuppressSmokeTestWarnings))
+ qCDebug(QRHI_LOG_INFO, "%s", msg);
+ else
+ qWarning("%s", msg);
return false;
}
- const bool supports11_1 = SUCCEEDED(ctx->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast<void **>(&context)));
- ctx->Release();
- if (!supports11_1) {
- qWarning("ID3D11DeviceContext1 not supported");
+ D3D11_FEATURE_DATA_D3D11_OPTIONS features = {};
+ if (SUCCEEDED(dev->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &features, sizeof(features)))) {
+ // The D3D _runtime_ may be 11.1, but the underlying _driver_ may
+ // still not support this D3D_FEATURE_LEVEL_11_1 feature. (e.g.
+ // because it only does 11_0)
+ if (!features.ConstantBufferOffsetting) {
+ static const char *msg = "D3D11 smoke test: Constant buffer offsetting is not supported by the driver";
+ if (flags.testFlag(QRhi::SuppressSmokeTestWarnings))
+ qCDebug(QRHI_LOG_INFO, "%s", msg);
+ else
+ qWarning("%s", msg);
+ return false;
+ }
+ } else {
+ static const char *msg = "D3D11 smoke test: Failed to query D3D11_FEATURE_D3D11_OPTIONS";
+ if (flags.testFlag(QRhi::SuppressSmokeTestWarnings))
+ qCDebug(QRHI_LOG_INFO, "%s", msg);
+ else
+ qWarning("%s", msg);
return false;
}
} else {
@@ -285,12 +365,14 @@ bool QRhiD3D11::create(QRhi::Flags flags)
if (SUCCEEDED(dev->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void **>(&dxgiDev)))) {
IDXGIAdapter *adapter = nullptr;
if (SUCCEEDED(dxgiDev->GetAdapter(&adapter))) {
- DXGI_ADAPTER_DESC desc;
- adapter->GetDesc(&desc);
- adapterLuid = desc.AdapterLuid;
- driverInfoStruct.deviceName = QString::fromUtf16(reinterpret_cast<char16_t *>(desc.Description)).toUtf8();
- driverInfoStruct.deviceId = desc.DeviceId;
- driverInfoStruct.vendorId = desc.VendorId;
+ IDXGIAdapter1 *adapter1 = nullptr;
+ if (SUCCEEDED(adapter->QueryInterface(__uuidof(IDXGIAdapter1), reinterpret_cast<void **>(&adapter1)))) {
+ DXGI_ADAPTER_DESC1 desc;
+ adapter1->GetDesc1(&desc);
+ adapterLuid = desc.AdapterLuid;
+ QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
+ adapter1->Release();
+ }
adapter->Release();
}
dxgiDev->Release();
@@ -326,6 +408,17 @@ void QRhiD3D11::destroy()
clearShaderCache();
+ if (ofr.tsDisjointQuery) {
+ ofr.tsDisjointQuery->Release();
+ ofr.tsDisjointQuery = nullptr;
+ }
+ for (int i = 0; i < 2; ++i) {
+ if (ofr.tsQueries[i]) {
+ ofr.tsQueries[i]->Release();
+ ofr.tsQueries[i] = nullptr;
+ }
+ }
+
if (annotations) {
annotations->Release();
annotations = nullptr;
@@ -373,19 +466,13 @@ QList<int> QRhiD3D11::supportedSampleCounts() const
return { 1, 2, 4, 8 };
}
-DXGI_SAMPLE_DESC QRhiD3D11::effectiveSampleCount(int sampleCount) const
+DXGI_SAMPLE_DESC QRhiD3D11::effectiveSampleDesc(int sampleCount) const
{
DXGI_SAMPLE_DESC desc;
desc.Count = 1;
desc.Quality = 0;
- // Stay compatible with QSurfaceFormat and friends where samples == 0 means the same as 1.
- int s = qBound(1, sampleCount, 64);
-
- if (!supportedSampleCounts().contains(s)) {
- qWarning("Attempted to set unsupported sample count %d", sampleCount);
- return desc;
- }
+ const int s = effectiveSampleCount(sampleCount);
desc.Count = UINT(s);
if (s > 1)
@@ -534,6 +621,12 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const
return true;
case QRhi::ThreeDimensionalTextureMipmaps:
return true;
+ case QRhi::MultiView:
+ return false;
+ case QRhi::TextureViewFormat:
+ return false; // because we use fully typed formats for textures and relaxed casting is a D3D12 thing
+ case QRhi::ResolveDepthStencil:
+ return false;
default:
Q_UNREACHABLE();
return false;
@@ -1204,7 +1297,6 @@ const QRhiNativeHandles *QRhiD3D11::nativeHandles(QRhiCommandBuffer *cb)
void QRhiD3D11::beginExternal(QRhiCommandBuffer *cb)
{
QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
- // no timestampSwapChain, in order to avoid timestamp mess
executeCommandBuffer(cbD);
cbD->resetCommands();
}
@@ -1221,6 +1313,25 @@ void QRhiD3D11::endExternal(QRhiCommandBuffer *cb)
}
}
+double QRhiD3D11::lastCompletedGpuTime(QRhiCommandBuffer *cb)
+{
+ QD3D11CommandBuffer *cbD = QRHI_RES(QD3D11CommandBuffer, cb);
+ return cbD->lastGpuTime;
+}
+
+static inline QD3D11RenderTargetData *rtData(QRhiRenderTarget *rt)
+{
+ switch (rt->resourceType()) {
+ case QRhiResource::SwapChainRenderTarget:
+ return &QRHI_RES(QD3D11SwapChainRenderTarget, rt)->d;
+ case QRhiResource::TextureRenderTarget:
+ return &QRHI_RES(QD3D11TextureRenderTarget, rt)->d;
+ default:
+ Q_UNREACHABLE();
+ return nullptr;
+ }
+}
+
QRhi::FrameOpResult QRhiD3D11::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
{
Q_UNUSED(flags);
@@ -1229,30 +1340,6 @@ QRhi::FrameOpResult QRhiD3D11::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF
contextState.currentSwapChain = swapChainD;
const int currentFrameSlot = swapChainD->currentFrameSlot;
- if (swapChainD->timestampActive[currentFrameSlot]) {
- ID3D11Query *tsDisjoint = swapChainD->timestampDisjointQuery[currentFrameSlot];
- const int tsIdx = QD3D11SwapChain::BUFFER_COUNT * currentFrameSlot;
- ID3D11Query *tsStart = swapChainD->timestampQuery[tsIdx];
- ID3D11Query *tsEnd = swapChainD->timestampQuery[tsIdx + 1];
- quint64 timestamps[2];
- D3D11_QUERY_DATA_TIMESTAMP_DISJOINT dj;
- bool ok = true;
- ok &= context->GetData(tsDisjoint, &dj, sizeof(dj), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
- ok &= context->GetData(tsEnd, &timestamps[1], sizeof(quint64), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
- // this above is often not ready, not even in frame_where_recorded+2,
- // not clear why. so make the whole thing async and do not touch the
- // queries until they are finally all available in frame this+2 or
- // this+4 or ...
- ok &= context->GetData(tsStart, &timestamps[0], sizeof(quint64), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
- if (ok) {
- if (!dj.Disjoint && dj.Frequency) {
- const float elapsedMs = (timestamps[1] - timestamps[0]) / float(dj.Frequency) * 1000.0f;
- runGpuFrameTimeCallbacks(elapsedMs);
- }
- swapChainD->timestampActive[currentFrameSlot] = false;
- } // else leave timestampActive set to true, will retry in a subsequent beginFrame
- }
-
swapChainD->cb.resetState();
swapChainD->rt.d.rtv[0] = swapChainD->sampleDesc.Count > 1 ?
@@ -1261,6 +1348,22 @@ QRhi::FrameOpResult QRhiD3D11::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF
finishActiveReadbacks();
+ if (swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex]) {
+ double elapsedSec = 0;
+ if (swapChainD->timestamps.tryQueryTimestamps(swapChainD->currentTimestampPairIndex, context, &elapsedSec))
+ swapChainD->cb.lastGpuTime = elapsedSec;
+ }
+
+ ID3D11Query *tsStart = swapChainD->timestamps.query[swapChainD->currentTimestampPairIndex * 2];
+ ID3D11Query *tsDisjoint = swapChainD->timestamps.disjointQuery[swapChainD->currentTimestampPairIndex];
+ const bool recordTimestamps = tsStart && tsDisjoint && !swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex];
+
+ QD3D11CommandBuffer::Command &cmd(swapChainD->cb.commands.get());
+ cmd.cmd = QD3D11CommandBuffer::Command::BeginFrame;
+ cmd.args.beginFrame.tsQuery = recordTimestamps ? tsStart : nullptr;
+ cmd.args.beginFrame.tsDisjointQuery = recordTimestamps ? tsDisjoint : nullptr;
+ cmd.args.beginFrame.swapchainData = rtData(&swapChainD->rt);
+
return QRhi::FrameOpSuccess;
}
@@ -1270,17 +1373,13 @@ QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
Q_ASSERT(contextState.currentSwapChain = swapChainD);
const int currentFrameSlot = swapChainD->currentFrameSlot;
- ID3D11Query *tsDisjoint = swapChainD->timestampDisjointQuery[currentFrameSlot];
- const int tsIdx = QD3D11SwapChain::BUFFER_COUNT * currentFrameSlot;
- ID3D11Query *tsStart = swapChainD->timestampQuery[tsIdx];
- ID3D11Query *tsEnd = swapChainD->timestampQuery[tsIdx + 1];
- const bool recordTimestamps = tsDisjoint && tsStart && tsEnd && !swapChainD->timestampActive[currentFrameSlot];
+ QD3D11CommandBuffer::Command &cmd(swapChainD->cb.commands.get());
+ cmd.cmd = QD3D11CommandBuffer::Command::EndFrame;
+ cmd.args.endFrame.tsQuery = nullptr; // done later manually, see below
+ cmd.args.endFrame.tsDisjointQuery = nullptr;
// send all commands to the context
- if (recordTimestamps)
- executeCommandBuffer(&swapChainD->cb, swapChainD);
- else
- executeCommandBuffer(&swapChainD->cb);
+ executeCommandBuffer(&swapChainD->cb);
if (swapChainD->sampleDesc.Count > 1) {
context->ResolveSubresource(swapChainD->backBufferTex, 0,
@@ -1288,17 +1387,25 @@ QRhi::FrameOpResult QRhiD3D11::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
swapChainD->colorFormat);
}
- // this is here because we want to include the time spent on the resolve as well
+ // this is here because we want to include the time spent on the ResolveSubresource as well
+ ID3D11Query *tsEnd = swapChainD->timestamps.query[swapChainD->currentTimestampPairIndex * 2 + 1];
+ ID3D11Query *tsDisjoint = swapChainD->timestamps.disjointQuery[swapChainD->currentTimestampPairIndex];
+ const bool recordTimestamps = tsEnd && tsDisjoint && !swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex];
if (recordTimestamps) {
context->End(tsEnd);
context->End(tsDisjoint);
- swapChainD->timestampActive[currentFrameSlot] = true;
+ swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex] = true;
+ swapChainD->currentTimestampPairIndex = (swapChainD->currentTimestampPairIndex + 1) % QD3D11SwapChainTimestamps::TIMESTAMP_PAIRS;
}
if (!flags.testFlag(QRhi::SkipPresent)) {
UINT presentFlags = 0;
if (swapChainD->swapInterval == 0 && (swapChainD->swapChainFlags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING))
presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
+ if (!swapChainD->swapChain) {
+ qWarning("Failed to present: IDXGISwapChain is unavailable");
+ return QRhi::FrameOpError;
+ }
HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
qWarning("Device loss detected in Present()");
@@ -1333,6 +1440,36 @@ QRhi::FrameOpResult QRhiD3D11::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi:
ofr.cbWrapper.resetState();
*cb = &ofr.cbWrapper;
+ if (rhiFlags.testFlag(QRhi::EnableTimestamps)) {
+ D3D11_QUERY_DESC queryDesc = {};
+ if (!ofr.tsDisjointQuery) {
+ queryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
+ HRESULT hr = dev->CreateQuery(&queryDesc, &ofr.tsDisjointQuery);
+ if (FAILED(hr)) {
+ qWarning("Failed to create timestamp disjoint query: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ return QRhi::FrameOpError;
+ }
+ }
+ queryDesc.Query = D3D11_QUERY_TIMESTAMP;
+ for (int i = 0; i < 2; ++i) {
+ if (!ofr.tsQueries[i]) {
+ HRESULT hr = dev->CreateQuery(&queryDesc, &ofr.tsQueries[i]);
+ if (FAILED(hr)) {
+ qWarning("Failed to create timestamp query: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ return QRhi::FrameOpError;
+ }
+ }
+ }
+ }
+
+ QD3D11CommandBuffer::Command &cmd(ofr.cbWrapper.commands.get());
+ cmd.cmd = QD3D11CommandBuffer::Command::BeginFrame;
+ cmd.args.beginFrame.tsQuery = ofr.tsQueries[0] ? ofr.tsQueries[0] : nullptr;
+ cmd.args.beginFrame.tsDisjointQuery = ofr.tsDisjointQuery ? ofr.tsDisjointQuery : nullptr;
+ cmd.args.beginFrame.swapchainData = nullptr;
+
return QRhi::FrameOpSuccess;
}
@@ -1341,10 +1478,41 @@ QRhi::FrameOpResult QRhiD3D11::endOffscreenFrame(QRhi::EndFrameFlags flags)
Q_UNUSED(flags);
ofr.active = false;
+ QD3D11CommandBuffer::Command &cmd(ofr.cbWrapper.commands.get());
+ cmd.cmd = QD3D11CommandBuffer::Command::EndFrame;
+ cmd.args.endFrame.tsQuery = ofr.tsQueries[1] ? ofr.tsQueries[1] : nullptr;
+ cmd.args.endFrame.tsDisjointQuery = ofr.tsDisjointQuery ? ofr.tsDisjointQuery : nullptr;
+
executeCommandBuffer(&ofr.cbWrapper);
+ context->Flush();
finishActiveReadbacks();
+ if (ofr.tsQueries[0]) {
+ quint64 timestamps[2];
+ D3D11_QUERY_DATA_TIMESTAMP_DISJOINT dj;
+ HRESULT hr;
+ bool ok = true;
+ do {
+ hr = context->GetData(ofr.tsDisjointQuery, &dj, sizeof(dj), 0);
+ } while (hr == S_FALSE);
+ ok &= hr == S_OK;
+ do {
+ hr = context->GetData(ofr.tsQueries[1], &timestamps[1], sizeof(quint64), 0);
+ } while (hr == S_FALSE);
+ ok &= hr == S_OK;
+ do {
+ hr = context->GetData(ofr.tsQueries[0], &timestamps[0], sizeof(quint64), 0);
+ } while (hr == S_FALSE);
+ ok &= hr == S_OK;
+ if (ok) {
+ if (!dj.Disjoint && dj.Frequency) {
+ const float elapsedMs = (timestamps[1] - timestamps[0]) / float(dj.Frequency) * 1000.0f;
+ ofr.cbWrapper.lastGpuTime = elapsedMs / 1000.0;
+ }
+ }
+ }
+
return QRhi::FrameOpSuccess;
}
@@ -1382,9 +1550,9 @@ static inline DXGI_FORMAT toD3DTextureFormat(QRhiTexture::Format format, QRhiTex
case QRhiTexture::D16:
return DXGI_FORMAT_R16_TYPELESS;
case QRhiTexture::D24:
- return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
+ return DXGI_FORMAT_R24G8_TYPELESS;
case QRhiTexture::D24S8:
- return DXGI_FORMAT_D24_UNORM_S8_UINT;
+ return DXGI_FORMAT_R24G8_TYPELESS;
case QRhiTexture::D32F:
return DXGI_FORMAT_R32_TYPELESS;
@@ -1485,7 +1653,7 @@ QRhi::FrameOpResult QRhiD3D11::finish()
} else {
Q_ASSERT(contextState.currentSwapChain);
Q_ASSERT(contextState.currentSwapChain->cb.recordingPass == QD3D11CommandBuffer::NoPass);
- executeCommandBuffer(&contextState.currentSwapChain->cb); // no timestampSwapChain, in order to avoid timestamp mess
+ executeCommandBuffer(&contextState.currentSwapChain->cb);
contextState.currentSwapChain->cb.resetCommands();
}
}
@@ -1860,19 +2028,6 @@ void QRhiD3D11::finishActiveReadbacks()
f();
}
-static inline QD3D11RenderTargetData *rtData(QRhiRenderTarget *rt)
-{
- switch (rt->resourceType()) {
- case QRhiResource::SwapChainRenderTarget:
- return &QRHI_RES(QD3D11SwapChainRenderTarget, rt)->d;
- case QRhiResource::TextureRenderTarget:
- return &QRHI_RES(QD3D11TextureRenderTarget, rt)->d;
- default:
- Q_UNREACHABLE();
- return nullptr;
- }
-}
-
void QRhiD3D11::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
{
Q_ASSERT(QRHI_RES(QD3D11CommandBuffer, cb)->recordingPass == QD3D11CommandBuffer::NoPass);
@@ -1991,6 +2146,8 @@ void QRhiD3D11::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resource
cmd.args.resolveSubRes.srcSubRes = D3D11CalcSubresource(0, UINT(colorAtt.layer()), 1);
cmd.args.resolveSubRes.format = dstTexD->dxgiFormat;
}
+ if (rtTex->m_desc.depthResolveTexture())
+ qWarning("Resolving multisample depth-stencil buffers is not supported with D3D");
}
cbD->recordingPass = QD3D11CommandBuffer::NoPass;
@@ -2578,7 +2735,7 @@ void QRhiD3D11::resetShaderResources()
currentShaderMask &= ~StageU##MaskBit; \
}
-void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *timestampSwapChain)
+void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD)
{
quint32 stencilRef = 0;
float blendConstants[] = { 1, 1, 1, 1 };
@@ -2591,26 +2748,30 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *
};
int currentShaderMask = 0xFF;
- if (timestampSwapChain) {
- const int currentFrameSlot = timestampSwapChain->currentFrameSlot;
- ID3D11Query *tsDisjoint = timestampSwapChain->timestampDisjointQuery[currentFrameSlot];
- const int tsIdx = QD3D11SwapChain::BUFFER_COUNT * currentFrameSlot;
- ID3D11Query *tsStart = timestampSwapChain->timestampQuery[tsIdx];
- if (tsDisjoint && tsStart && !timestampSwapChain->timestampActive[currentFrameSlot]) {
- // The timestamps seem to include vsync time with Present(1), except
- // when running on a non-primary gpu. This is not ideal. So try working
- // it around by issuing a semi-fake OMSetRenderTargets early and
- // writing the first timestamp only afterwards.
- context->Begin(tsDisjoint);
- QD3D11RenderTargetData *rtD = rtData(&timestampSwapChain->rt);
- context->OMSetRenderTargets(UINT(rtD->colorAttCount), rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv);
- context->End(tsStart); // just record a timestamp, no Begin needed
- }
- }
-
for (auto it = cbD->commands.cbegin(), end = cbD->commands.cend(); it != end; ++it) {
const QD3D11CommandBuffer::Command &cmd(*it);
switch (cmd.cmd) {
+ case QD3D11CommandBuffer::Command::BeginFrame:
+ if (cmd.args.beginFrame.tsDisjointQuery)
+ context->Begin(cmd.args.beginFrame.tsDisjointQuery);
+ if (cmd.args.beginFrame.tsQuery) {
+ if (cmd.args.beginFrame.swapchainData) {
+ // The timestamps seem to include vsync time with Present(1), except
+ // when running on a non-primary gpu. This is not ideal. So try working
+ // it around by issuing a semi-fake OMSetRenderTargets early and
+ // writing the first timestamp only afterwards.
+ QD3D11RenderTargetData *rtD = cmd.args.beginFrame.swapchainData;
+ context->OMSetRenderTargets(UINT(rtD->colorAttCount), rtD->colorAttCount ? rtD->rtv : nullptr, rtD->dsv);
+ }
+ context->End(cmd.args.beginFrame.tsQuery); // no Begin() for D3D11_QUERY_TIMESTAMP
+ }
+ break;
+ case QD3D11CommandBuffer::Command::EndFrame:
+ if (cmd.args.endFrame.tsQuery)
+ context->End(cmd.args.endFrame.tsQuery);
+ if (cmd.args.endFrame.tsDisjointQuery)
+ context->End(cmd.args.endFrame.tsDisjointQuery);
+ break;
case QD3D11CommandBuffer::Command::ResetShaderResources:
resetShaderResources();
break;
@@ -2964,7 +3125,7 @@ bool QD3D11RenderBuffer::create()
return false;
QRHI_RES_RHI(QRhiD3D11);
- sampleDesc = rhiD->effectiveSampleCount(m_sampleCount);
+ sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount);
D3D11_TEXTURE2D_DESC desc = {};
desc.Width = UINT(m_pixelSize.width());
@@ -3106,7 +3267,7 @@ static inline DXGI_FORMAT toD3DDepthTextureDSVFormat(QRhiTexture::Format format)
case QRhiTexture::Format::D16:
return DXGI_FORMAT_D16_UNORM;
case QRhiTexture::Format::D24:
- return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
+ return DXGI_FORMAT_D24_UNORM_S8_UINT;
case QRhiTexture::Format::D24S8:
return DXGI_FORMAT_D24_UNORM_S8_UINT;
case QRhiTexture::Format::D32F:
@@ -3135,7 +3296,7 @@ bool QD3D11Texture::prepareCreate(QSize *adjustedSize)
QRHI_RES_RHI(QRhiD3D11);
dxgiFormat = toD3DTextureFormat(m_format, m_flags);
mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
- sampleDesc = rhiD->effectiveSampleCount(m_sampleCount);
+ sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount);
if (sampleDesc.Count > 1) {
if (isCube) {
qWarning("Cubemap texture cannot be multisample");
@@ -3170,12 +3331,10 @@ bool QD3D11Texture::prepareCreate(QSize *adjustedSize)
qWarning("Texture cannot be both 1D and 3D");
return false;
}
- m_depth = qMax(1, m_depth);
if (m_depth > 1 && !is3D) {
qWarning("Texture cannot have a depth of %d when it is not 3D", m_depth);
return false;
}
- m_arraySize = qMax(0, m_arraySize);
if (m_arraySize > 0 && !isArray) {
qWarning("Texture cannot have an array size of %d when it is not an array", m_arraySize);
return false;
@@ -3215,7 +3374,7 @@ bool QD3D11Texture::finishCreate()
srvDesc.Texture1DArray.ArraySize = UINT(m_arrayRangeLength);
} else {
srvDesc.Texture1DArray.FirstArraySlice = 0;
- srvDesc.Texture1DArray.ArraySize = UINT(m_arraySize);
+ srvDesc.Texture1DArray.ArraySize = UINT(qMax(0, m_arraySize));
}
} else {
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
@@ -3229,7 +3388,7 @@ bool QD3D11Texture::finishCreate()
srvDesc.Texture2DMSArray.ArraySize = UINT(m_arrayRangeLength);
} else {
srvDesc.Texture2DMSArray.FirstArraySlice = 0;
- srvDesc.Texture2DMSArray.ArraySize = UINT(m_arraySize);
+ srvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, m_arraySize));
}
} else {
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
@@ -3239,7 +3398,7 @@ bool QD3D11Texture::finishCreate()
srvDesc.Texture2DArray.ArraySize = UINT(m_arrayRangeLength);
} else {
srvDesc.Texture2DArray.FirstArraySlice = 0;
- srvDesc.Texture2DArray.ArraySize = UINT(m_arraySize);
+ srvDesc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
}
}
} else {
@@ -3302,7 +3461,7 @@ bool QD3D11Texture::create()
D3D11_TEXTURE1D_DESC desc = {};
desc.Width = UINT(size.width());
desc.MipLevels = mipLevelCount;
- desc.ArraySize = isArray ? UINT(m_arraySize) : 1;
+ desc.ArraySize = isArray ? UINT(qMax(0, m_arraySize)) : 1;
desc.Format = dxgiFormat;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = bindFlags;
@@ -3322,7 +3481,7 @@ bool QD3D11Texture::create()
desc.Width = UINT(size.width());
desc.Height = UINT(size.height());
desc.MipLevels = mipLevelCount;
- desc.ArraySize = isCube ? 6 : (isArray ? UINT(m_arraySize) : 1);
+ desc.ArraySize = isCube ? 6 : (isArray ? UINT(qMax(0, m_arraySize)) : 1);
desc.Format = dxgiFormat;
desc.SampleDesc = sampleDesc;
desc.Usage = D3D11_USAGE_DEFAULT;
@@ -3341,7 +3500,7 @@ bool QD3D11Texture::create()
D3D11_TEXTURE3D_DESC desc = {};
desc.Width = UINT(size.width());
desc.Height = UINT(size.height());
- desc.Depth = UINT(m_depth);
+ desc.Depth = UINT(qMax(1, m_depth));
desc.MipLevels = mipLevelCount;
desc.Format = dxgiFormat;
desc.Usage = D3D11_USAGE_DEFAULT;
@@ -3414,7 +3573,7 @@ ID3D11UnorderedAccessView *QD3D11Texture::unorderedAccessViewForLevel(int level)
desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2DARRAY;
desc.Texture2DArray.MipSlice = UINT(level);
desc.Texture2DArray.FirstArraySlice = 0;
- desc.Texture2DArray.ArraySize = UINT(m_arraySize);
+ desc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
} else if (is3D) {
desc.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE3D;
desc.Texture3D.MipSlice = UINT(level);
@@ -3574,7 +3733,9 @@ QD3D11RenderPassDescriptor::~QD3D11RenderPassDescriptor()
void QD3D11RenderPassDescriptor::destroy()
{
- // nothing to do here
+ QRHI_RES_RHI(QRhiD3D11);
+ if (rhiD)
+ rhiD->unregisterResource(this);
}
bool QD3D11RenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const
@@ -3585,7 +3746,10 @@ bool QD3D11RenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *ot
QRhiRenderPassDescriptor *QD3D11RenderPassDescriptor::newCompatibleRenderPassDescriptor() const
{
- return new QD3D11RenderPassDescriptor(m_rhi);
+ QD3D11RenderPassDescriptor *rpD = new QD3D11RenderPassDescriptor(m_rhi);
+ QRHI_RES_RHI(QRhiD3D11);
+ rhiD->registerResource(rpD, false);
+ return rpD;
}
QVector<quint32> QD3D11RenderPassDescriptor::serializedFormat() const
@@ -3667,7 +3831,10 @@ void QD3D11TextureRenderTarget::destroy()
QRhiRenderPassDescriptor *QD3D11TextureRenderTarget::newCompatibleRenderPassDescriptor()
{
- return new QD3D11RenderPassDescriptor(m_rhi);
+ QD3D11RenderPassDescriptor *rpD = new QD3D11RenderPassDescriptor(m_rhi);
+ QRHI_RES_RHI(QRhiD3D11);
+ rhiD->registerResource(rpD, false);
+ return rpD;
}
bool QD3D11TextureRenderTarget::create()
@@ -3763,6 +3930,27 @@ bool QD3D11TextureRenderTarget::create()
dsvDesc.Format = toD3DDepthTextureDSVFormat(depthTexD->format());
dsvDesc.ViewDimension = depthTexD->sampleDesc.Count > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS
: D3D11_DSV_DIMENSION_TEXTURE2D;
+ if (depthTexD->flags().testFlag(QRhiTexture::TextureArray)) {
+ if (depthTexD->sampleDesc.Count > 1) {
+ dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMSARRAY;
+ if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
+ dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
+ dsvDesc.Texture2DMSArray.ArraySize = UINT(depthTexD->arrayRangeLength());
+ } else {
+ dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
+ dsvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
+ }
+ } else {
+ dsvDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DARRAY;
+ if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
+ dsvDesc.Texture2DArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
+ dsvDesc.Texture2DArray.ArraySize = UINT(depthTexD->arrayRangeLength());
+ } else {
+ dsvDesc.Texture2DArray.FirstArraySlice = 0;
+ dsvDesc.Texture2DArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
+ }
+ }
+ }
HRESULT hr = rhiD->dev->CreateDepthStencilView(depthTexD->tex, &dsvDesc, &dsv);
if (FAILED(hr)) {
qWarning("Failed to create dsv: %s",
@@ -3831,6 +4019,10 @@ void QD3D11ShaderResourceBindings::destroy()
{
sortedBindings.clear();
boundResourceData.clear();
+
+ QRHI_RES_RHI(QRhiD3D11);
+ if (rhiD)
+ rhiD->unregisterResource(this);
}
bool QD3D11ShaderResourceBindings::create()
@@ -3862,6 +4054,7 @@ bool QD3D11ShaderResourceBindings::create()
}
generation += 1;
+ rhiD->registerResource(this, false);
return true;
}
@@ -4052,6 +4245,22 @@ static inline DXGI_FORMAT toD3DAttributeFormat(QRhiVertexInputAttribute::Format
return DXGI_FORMAT_R16G16_FLOAT;
case QRhiVertexInputAttribute::Half:
return DXGI_FORMAT_R16_FLOAT;
+ case QRhiVertexInputAttribute::UShort4:
+ // Note: D3D does not support UShort3. Pass through UShort3 as UShort4.
+ case QRhiVertexInputAttribute::UShort3:
+ return DXGI_FORMAT_R16G16B16A16_UINT;
+ case QRhiVertexInputAttribute::UShort2:
+ return DXGI_FORMAT_R16G16_UINT;
+ case QRhiVertexInputAttribute::UShort:
+ return DXGI_FORMAT_R16_UINT;
+ case QRhiVertexInputAttribute::SShort4:
+ // Note: D3D does not support SShort3. Pass through SShort3 as SShort4.
+ case QRhiVertexInputAttribute::SShort3:
+ return DXGI_FORMAT_R16G16B16A16_SINT;
+ case QRhiVertexInputAttribute::SShort2:
+ return DXGI_FORMAT_R16G16_SINT;
+ case QRhiVertexInputAttribute::SShort:
+ return DXGI_FORMAT_R16_SINT;
default:
Q_UNREACHABLE();
return DXGI_FORMAT_R32G32B32A32_FLOAT;
@@ -4164,18 +4373,6 @@ static inline D3D11_BLEND_OP toD3DBlendOp(QRhiGraphicsPipeline::BlendOp op)
}
}
-static pD3DCompile resolveD3DCompile()
-{
- for (const wchar_t *libraryName : {L"D3DCompiler_47", L"D3DCompiler_43"}) {
- QSystemLibrary library(libraryName);
- if (library.load()) {
- if (auto symbol = library.resolve("D3DCompile"))
- return reinterpret_cast<pD3DCompile>(symbol);
- }
- }
- return nullptr;
-}
-
static inline QByteArray sourceHash(const QByteArray &source)
{
// taken from the GL backend, use the same mechanism to get a key
@@ -4241,7 +4438,7 @@ QByteArray QRhiD3D11::compileHlslShaderSource(const QShader &shader, QShader::Va
return cacheIt.value();
}
- static const pD3DCompile d3dCompile = resolveD3DCompile();
+ static const pD3DCompile d3dCompile = QRhiD3D::resolveD3DCompile();
if (d3dCompile == nullptr) {
qWarning("Unable to resolve function D3DCompile()");
return QByteArray();
@@ -4291,7 +4488,7 @@ bool QD3D11GraphicsPipeline::create()
rastDesc.SlopeScaledDepthBias = m_slopeScaledDepthBias;
rastDesc.DepthClipEnable = true;
rastDesc.ScissorEnable = m_flags.testFlag(UsesScissor);
- rastDesc.MultisampleEnable = rhiD->effectiveSampleCount(m_sampleCount).Count > 1;
+ rastDesc.MultisampleEnable = rhiD->effectiveSampleDesc(m_sampleCount).Count > 1;
HRESULT hr = rhiD->dev->CreateRasterizerState(&rastDesc, &rastState);
if (FAILED(hr)) {
qWarning("Failed to create rasterizer state: %s",
@@ -4609,20 +4806,93 @@ void QD3D11CommandBuffer::destroy()
// nothing to do here
}
+bool QD3D11SwapChainTimestamps::prepare(QRhiD3D11 *rhiD)
+{
+ // Creates the query objects if not yet done, but otherwise calling this
+ // function is expected to be a no-op.
+
+ D3D11_QUERY_DESC queryDesc = {};
+ for (int i = 0; i < TIMESTAMP_PAIRS; ++i) {
+ if (!disjointQuery[i]) {
+ queryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
+ HRESULT hr = rhiD->dev->CreateQuery(&queryDesc, &disjointQuery[i]);
+ if (FAILED(hr)) {
+ qWarning("Failed to create timestamp disjoint query: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ return false;
+ }
+ }
+ queryDesc.Query = D3D11_QUERY_TIMESTAMP;
+ for (int j = 0; j < 2; ++j) {
+ const int idx = 2 * i + j;
+ if (!query[idx]) {
+ HRESULT hr = rhiD->dev->CreateQuery(&queryDesc, &query[idx]);
+ if (FAILED(hr)) {
+ qWarning("Failed to create timestamp query: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+void QD3D11SwapChainTimestamps::destroy()
+{
+ for (int i = 0; i < TIMESTAMP_PAIRS; ++i) {
+ active[i] = false;
+ if (disjointQuery[i]) {
+ disjointQuery[i]->Release();
+ disjointQuery[i] = nullptr;
+ }
+ for (int j = 0; j < 2; ++j) {
+ const int idx = TIMESTAMP_PAIRS * i + j;
+ if (query[idx]) {
+ query[idx]->Release();
+ query[idx] = nullptr;
+ }
+ }
+ }
+}
+
+bool QD3D11SwapChainTimestamps::tryQueryTimestamps(int pairIndex, ID3D11DeviceContext *context, double *elapsedSec)
+{
+ bool result = false;
+ if (!active[pairIndex])
+ return result;
+
+ ID3D11Query *tsDisjoint = disjointQuery[pairIndex];
+ ID3D11Query *tsStart = query[pairIndex * 2];
+ ID3D11Query *tsEnd = query[pairIndex * 2 + 1];
+ quint64 timestamps[2];
+ D3D11_QUERY_DATA_TIMESTAMP_DISJOINT dj;
+
+ bool ok = true;
+ ok &= context->GetData(tsDisjoint, &dj, sizeof(dj), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
+ ok &= context->GetData(tsEnd, &timestamps[1], sizeof(quint64), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
+ ok &= context->GetData(tsStart, &timestamps[0], sizeof(quint64), D3D11_ASYNC_GETDATA_DONOTFLUSH) == S_OK;
+
+ if (ok) {
+ if (!dj.Disjoint && dj.Frequency) {
+ const float elapsedMs = (timestamps[1] - timestamps[0]) / float(dj.Frequency) * 1000.0f;
+ *elapsedSec = elapsedMs / 1000.0;
+ result = true;
+ }
+ active[pairIndex] = false;
+ } // else leave active set, will retry in a subsequent beginFrame
+
+ return result;
+}
+
QD3D11SwapChain::QD3D11SwapChain(QRhiImplementation *rhi)
- : QRhiSwapChain(rhi),
- rt(rhi, this),
- cb(rhi)
+ : QRhiSwapChain(rhi), rt(rhi, this), rtRight(rhi, this), cb(rhi)
{
backBufferTex = nullptr;
backBufferRtv = nullptr;
for (int i = 0; i < BUFFER_COUNT; ++i) {
msaaTex[i] = nullptr;
msaaRtv[i] = nullptr;
- timestampActive[i] = false;
- timestampDisjointQuery[i] = nullptr;
- timestampQuery[2 * i] = nullptr;
- timestampQuery[2 * i + 1] = nullptr;
}
}
@@ -4637,6 +4907,10 @@ void QD3D11SwapChain::releaseBuffers()
backBufferRtv->Release();
backBufferRtv = nullptr;
}
+ if (backBufferRtvRight) {
+ backBufferRtvRight->Release();
+ backBufferRtvRight = nullptr;
+ }
if (backBufferTex) {
backBufferTex->Release();
backBufferTex = nullptr;
@@ -4660,19 +4934,7 @@ void QD3D11SwapChain::destroy()
releaseBuffers();
- for (int i = 0; i < BUFFER_COUNT; ++i) {
- if (timestampDisjointQuery[i]) {
- timestampDisjointQuery[i]->Release();
- timestampDisjointQuery[i] = nullptr;
- }
- for (int j = 0; j < 2; ++j) {
- const int idx = BUFFER_COUNT * i + j;
- if (timestampQuery[idx]) {
- timestampQuery[idx]->Release();
- timestampQuery[idx] = nullptr;
- }
- }
- }
+ timestamps.destroy();
swapChain->Release();
swapChain = nullptr;
@@ -4688,8 +4950,12 @@ void QD3D11SwapChain::destroy()
}
QRHI_RES_RHI(QRhiD3D11);
- if (rhiD)
+ if (rhiD) {
rhiD->unregisterResource(this);
+ // See Deferred Destruction Issues with Flip Presentation Swap Chains in
+ // https://learn.microsoft.com/en-us/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-flush
+ rhiD->context->Flush();
+ }
}
QRhiCommandBuffer *QD3D11SwapChain::currentFrameCommandBuffer()
@@ -4702,48 +4968,15 @@ QRhiRenderTarget *QD3D11SwapChain::currentFrameRenderTarget()
return &rt;
}
-QSize QD3D11SwapChain::surfacePixelSize()
+QRhiRenderTarget *QD3D11SwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
{
- Q_ASSERT(m_window);
- return m_window->size() * m_window->devicePixelRatio();
+ return targetBuffer == StereoTargetBuffer::LeftBuffer? &rt: &rtRight;
}
-static bool output6ForWindow(QWindow *w, IDXGIAdapter1 *adapter, IDXGIOutput6 **result)
-{
- bool ok = false;
- QRect wr = w->geometry();
- wr = QRect(wr.topLeft() * w->devicePixelRatio(), wr.size() * w->devicePixelRatio());
- const QPoint center = wr.center();
- IDXGIOutput *currentOutput = nullptr;
- IDXGIOutput *output = nullptr;
- for (UINT i = 0; adapter->EnumOutputs(i, &output) != DXGI_ERROR_NOT_FOUND; ++i) {
- DXGI_OUTPUT_DESC desc;
- output->GetDesc(&desc);
- const RECT r = desc.DesktopCoordinates;
- const QRect dr(QPoint(r.left, r.top), QPoint(r.right - 1, r.bottom - 1));
- if (dr.contains(center)) {
- currentOutput = output;
- break;
- } else {
- output->Release();
- }
- }
- if (currentOutput) {
- ok = SUCCEEDED(currentOutput->QueryInterface(__uuidof(IDXGIOutput6), reinterpret_cast<void **>(result)));
- currentOutput->Release();
- }
- return ok;
-}
-
-static bool outputDesc1ForWindow(QWindow *w, IDXGIAdapter1 *adapter, DXGI_OUTPUT_DESC1 *result)
+QSize QD3D11SwapChain::surfacePixelSize()
{
- bool ok = false;
- IDXGIOutput6 *out6 = nullptr;
- if (output6ForWindow(w, adapter, &out6)) {
- ok = SUCCEEDED(out6->GetDesc1(result));
- out6->Release();
- }
- return ok;
+ Q_ASSERT(m_window);
+ return m_window->size() * m_window->devicePixelRatio();
}
bool QD3D11SwapChain::isFormatSupported(Format f)
@@ -4758,8 +4991,10 @@ bool QD3D11SwapChain::isFormatSupported(Format f)
QRHI_RES_RHI(QRhiD3D11);
DXGI_OUTPUT_DESC1 desc1;
- if (outputDesc1ForWindow(m_window, rhiD->activeAdapter, &desc1))
- return desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
+ if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &desc1)) {
+ if (desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020)
+ return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10;
+ }
return false;
}
@@ -4767,14 +5002,16 @@ bool QD3D11SwapChain::isFormatSupported(Format f)
QRhiSwapChainHdrInfo QD3D11SwapChain::hdrInfo()
{
QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo();
- if (m_format != QRhiSwapChain::SDR && m_window) {
+ // Must use m_window, not window, given this may be called before createOrResize().
+ if (m_window) {
QRHI_RES_RHI(QRhiD3D11);
DXGI_OUTPUT_DESC1 hdrOutputDesc;
- if (outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc)) {
- info.isHardCodedDefaults = false;
+ if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc)) {
info.limitsType = QRhiSwapChainHdrInfo::LuminanceInNits;
info.limits.luminanceInNits.minLuminance = hdrOutputDesc.MinLuminance;
info.limits.luminanceInNits.maxLuminance = hdrOutputDesc.MaxLuminance;
+ info.luminanceBehavior = QRhiSwapChainHdrInfo::SceneReferred; // 1.0 = 80 nits
+ info.sdrWhiteLevel = QRhiD3D::sdrWhiteLevelInNits(hdrOutputDesc);
}
}
return info;
@@ -4782,7 +5019,10 @@ QRhiSwapChainHdrInfo QD3D11SwapChain::hdrInfo()
QRhiRenderPassDescriptor *QD3D11SwapChain::newCompatibleRenderPassDescriptor()
{
- return new QD3D11RenderPassDescriptor(m_rhi);
+ QD3D11RenderPassDescriptor *rpD = new QD3D11RenderPassDescriptor(m_rhi);
+ QRHI_RES_RHI(QRhiD3D11);
+ rhiD->registerResource(rpD, false);
+ return rpD;
}
bool QD3D11SwapChain::newColorBuffer(const QSize &size, DXGI_FORMAT format, DXGI_SAMPLE_DESC sampleDesc,
@@ -4821,26 +5061,19 @@ bool QD3D11SwapChain::newColorBuffer(const QSize &size, DXGI_FORMAT format, DXGI
return true;
}
-static const DXGI_FORMAT DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
-static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
-
bool QRhiD3D11::ensureDirectCompositionDevice()
{
if (dcompDevice)
return true;
qCDebug(QRHI_LOG_INFO, "Creating Direct Composition device (needed for semi-transparent windows)");
-
- HRESULT hr = DCompositionCreateDevice(nullptr, __uuidof(IDCompositionDevice), reinterpret_cast<void **>(&dcompDevice));
- if (FAILED(hr)) {
- qWarning("Failed to Direct Composition device: %s",
- qPrintable(QSystemError::windowsComString(hr)));
- return false;
- }
-
- return true;
+ dcompDevice = QRhiD3D::createDirectCompositionDevice();
+ return dcompDevice ? true : false;
}
+static const DXGI_FORMAT DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
+static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
+
bool QD3D11SwapChain::createOrResize()
{
// Can be called multiple times due to window resizes - that is not the
@@ -4848,6 +5081,7 @@ bool QD3D11SwapChain::createOrResize()
// resize the buffers then.
const bool needsRegistration = !window || window != m_window;
+ const bool stereo = m_window->format().stereo();
// except if the window actually changes
if (window && window != m_window)
@@ -4866,9 +5100,9 @@ bool QD3D11SwapChain::createOrResize()
QRHI_RES_RHI(QRhiD3D11);
if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
- if (rhiD->ensureDirectCompositionDevice()) {
+ if (!rhiD->useLegacySwapchainModel && rhiD->ensureDirectCompositionDevice()) {
if (!dcompTarget) {
- hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd, true, &dcompTarget);
+ hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd, false, &dcompTarget);
if (FAILED(hr)) {
qWarning("Failed to create Direct Compsition target for the window: %s",
qPrintable(QSystemError::windowsComString(hr)));
@@ -4899,13 +5133,13 @@ bool QD3D11SwapChain::createOrResize()
swapChainFlags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
if (!swapChain) {
- sampleDesc = rhiD->effectiveSampleCount(m_sampleCount);
+ sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount);
colorFormat = DEFAULT_FORMAT;
srgbAdjustedColorFormat = m_flags.testFlag(sRGB) ? DEFAULT_SRGB_FORMAT : DEFAULT_FORMAT;
DXGI_COLOR_SPACE_TYPE hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; // SDR
DXGI_OUTPUT_DESC1 hdrOutputDesc;
- if (outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc) && m_format != SDR) {
+ if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc) && m_format != SDR) {
// https://docs.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range
if (hdrOutputDesc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) {
switch (m_format) {
@@ -4945,8 +5179,9 @@ bool QD3D11SwapChain::createOrResize()
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
desc.BufferCount = BUFFER_COUNT;
desc.Flags = swapChainFlags;
- desc.Scaling = DXGI_SCALING_NONE;
- desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
+ desc.Scaling = rhiD->useLegacySwapchainModel ? DXGI_SCALING_STRETCH : DXGI_SCALING_NONE;
+ desc.SwapEffect = rhiD->useLegacySwapchainModel ? DXGI_SWAP_EFFECT_DISCARD : DXGI_SWAP_EFFECT_FLIP_DISCARD;
+ desc.Stereo = stereo;
if (dcompVisual) {
// With DirectComposition setting AlphaMode to STRAIGHT fails the
@@ -5006,14 +5241,19 @@ bool QD3D11SwapChain::createOrResize()
qWarning("Failed to set content for Direct Composition visual: %s",
qPrintable(QSystemError::windowsComString(hr)));
}
+ } else {
+ // disable Alt+Enter; not relevant when using DirectComposition
+ rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
}
}
if (FAILED(hr)) {
- qWarning("Failed to create D3D11 swapchain: %s",
- qPrintable(QSystemError::windowsComString(hr)));
+ qWarning("Failed to create D3D11 swapchain: %s"
+ " (Width=%u Height=%u Format=%u SampleCount=%u BufferCount=%u Scaling=%u SwapEffect=%u Stereo=%u)",
+ qPrintable(QSystemError::windowsComString(hr)),
+ desc.Width, desc.Height, UINT(desc.Format), desc.SampleDesc.Count,
+ desc.BufferCount, UINT(desc.Scaling), UINT(desc.SwapEffect), UINT(desc.Stereo));
return false;
}
- rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
} else {
releaseBuffers();
// flip model -> buffer count is the real buffer count, not 1 like with the legacy modes
@@ -5060,6 +5300,19 @@ bool QD3D11SwapChain::createOrResize()
return false;
}
+ if (stereo) {
+ // Create a second render target view for the right eye
+ rtvDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2DARRAY;
+ rtvDesc.Texture2DArray.FirstArraySlice = 1;
+ rtvDesc.Texture2DArray.ArraySize = 1;
+ hr = rhiD->dev->CreateRenderTargetView(backBufferTex, &rtvDesc, &backBufferRtvRight);
+ if (FAILED(hr)) {
+ qWarning("Failed to create rtv for swapchain backbuffer (right eye): %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ return false;
+ }
+ }
+
// Try to reduce stalls by having a dedicated MSAA texture per swapchain buffer.
for (int i = 0; i < BUFFER_COUNT; ++i) {
if (sampleDesc.Count > 1) {
@@ -5098,31 +5351,20 @@ bool QD3D11SwapChain::createOrResize()
rtD->d.colorAttCount = 1;
rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
- if (rhiD->hasGpuFrameTimeCallback()) {
- D3D11_QUERY_DESC queryDesc = {};
- for (int i = 0; i < BUFFER_COUNT; ++i) {
- if (!timestampDisjointQuery[i]) {
- queryDesc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
- hr = rhiD->dev->CreateQuery(&queryDesc, &timestampDisjointQuery[i]);
- if (FAILED(hr)) {
- qWarning("Failed to create timestamp disjoint query: %s",
- qPrintable(QSystemError::windowsComString(hr)));
- break;
- }
- }
- queryDesc.Query = D3D11_QUERY_TIMESTAMP;
- for (int j = 0; j < 2; ++j) {
- const int idx = BUFFER_COUNT * i + j; // one pair per buffer (frame)
- if (!timestampQuery[idx]) {
- hr = rhiD->dev->CreateQuery(&queryDesc, &timestampQuery[idx]);
- if (FAILED(hr)) {
- qWarning("Failed to create timestamp query: %s",
- qPrintable(QSystemError::windowsComString(hr)));
- break;
- }
- }
- }
- }
+ if (stereo) {
+ rtD = QRHI_RES(QD3D11SwapChainRenderTarget, &rtRight);
+ rtD->d.rp = QRHI_RES(QD3D11RenderPassDescriptor, m_renderPassDesc);
+ rtD->d.pixelSize = pixelSize;
+ rtD->d.dpr = float(window->devicePixelRatio());
+ rtD->d.sampleCount = int(sampleDesc.Count);
+ rtD->d.colorAttCount = 1;
+ rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
+ rtD->d.rtv[0] = backBufferRtvRight;
+ rtD->d.dsv = ds ? ds->dsv : nullptr;
+ }
+
+ if (rhiD->rhiFlags.testFlag(QRhi::EnableTimestamps)) {
+ timestamps.prepare(rhiD);
// timestamp queries are optional so we can go on even if they failed
}
diff --git a/src/gui/rhi/qrhid3d11_p.h b/src/gui/rhi/qrhid3d11_p.h
index 2ab3e9fea3..7644748407 100644
--- a/src/gui/rhi/qrhid3d11_p.h
+++ b/src/gui/rhi/qrhid3d11_p.h
@@ -1,8 +1,8 @@
-// Copyright (C) 2019 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QRHID3D11_H
-#define QRHID3D11_H
+#ifndef QRHID3D11_P_H
+#define QRHID3D11_P_H
//
// W A R N I N G
@@ -15,28 +15,852 @@
// We mean it.
//
-#include <private/qrhi_p.h>
+#include "qrhi_p.h"
+#include <rhi/qshaderdescription.h>
+#include <QWindow>
-// no d3d includes here, to prevent precompiled header mess due to COM
+#include <d3d11_1.h>
+#include <dxgi1_6.h>
+#include <dcomp.h>
QT_BEGIN_NAMESPACE
-struct Q_GUI_EXPORT QRhiD3D11InitParams : public QRhiInitParams
+class QRhiD3D11;
+
+struct QD3D11Buffer : public QRhiBuffer
+{
+ QD3D11Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
+ ~QD3D11Buffer();
+ void destroy() override;
+ bool create() override;
+ QRhiBuffer::NativeBuffer nativeBuffer() override;
+ char *beginFullDynamicBufferUpdateForCurrentFrame() override;
+ void endFullDynamicBufferUpdateForCurrentFrame() override;
+
+ ID3D11UnorderedAccessView *unorderedAccessView(quint32 offset);
+
+ ID3D11Buffer *buffer = nullptr;
+ char *dynBuf = nullptr;
+ bool hasPendingDynamicUpdates = false;
+ QHash<quint32, ID3D11UnorderedAccessView *> uavs;
+ uint generation = 0;
+ friend class QRhiD3D11;
+};
+
+struct QD3D11RenderBuffer : public QRhiRenderBuffer
+{
+ QD3D11RenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
+ int sampleCount, QRhiRenderBuffer::Flags flags,
+ QRhiTexture::Format backingFormatHint);
+ ~QD3D11RenderBuffer();
+ void destroy() override;
+ bool create() override;
+ QRhiTexture::Format backingFormat() const override;
+
+ ID3D11Texture2D *tex = nullptr;
+ ID3D11DepthStencilView *dsv = nullptr;
+ ID3D11RenderTargetView *rtv = nullptr;
+ DXGI_FORMAT dxgiFormat;
+ DXGI_SAMPLE_DESC sampleDesc;
+ uint generation = 0;
+ friend class QRhiD3D11;
+};
+
+struct QD3D11Texture : public QRhiTexture
+{
+ QD3D11Texture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
+ int arraySize, int sampleCount, Flags flags);
+ ~QD3D11Texture();
+ void destroy() override;
+ bool create() override;
+ bool createFrom(NativeTexture src) override;
+ NativeTexture nativeTexture() override;
+
+ bool prepareCreate(QSize *adjustedSize = nullptr);
+ bool finishCreate();
+ ID3D11UnorderedAccessView *unorderedAccessViewForLevel(int level);
+ ID3D11Resource *textureResource() const
+ {
+ if (tex)
+ return tex;
+ else if (tex1D)
+ return tex1D;
+ return tex3D;
+ }
+
+ ID3D11Texture2D *tex = nullptr;
+ ID3D11Texture3D *tex3D = nullptr;
+ ID3D11Texture1D *tex1D = nullptr;
+ bool owns = true;
+ ID3D11ShaderResourceView *srv = nullptr;
+ DXGI_FORMAT dxgiFormat;
+ uint mipLevelCount = 0;
+ DXGI_SAMPLE_DESC sampleDesc;
+ ID3D11UnorderedAccessView *perLevelViews[QRhi::MAX_MIP_LEVELS];
+ uint generation = 0;
+ friend class QRhiD3D11;
+};
+
+struct QD3D11Sampler : public QRhiSampler
+{
+ QD3D11Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
+ AddressMode u, AddressMode v, AddressMode w);
+ ~QD3D11Sampler();
+ void destroy() override;
+ bool create() override;
+
+ ID3D11SamplerState *samplerState = nullptr;
+ uint generation = 0;
+ friend class QRhiD3D11;
+};
+
+struct QD3D11RenderPassDescriptor : public QRhiRenderPassDescriptor
+{
+ QD3D11RenderPassDescriptor(QRhiImplementation *rhi);
+ ~QD3D11RenderPassDescriptor();
+ void destroy() override;
+ bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
+ QVector<quint32> serializedFormat() const override;
+};
+
+struct QD3D11RenderTargetData
+{
+ QD3D11RenderTargetData(QRhiImplementation *)
+ {
+ for (int i = 0; i < MAX_COLOR_ATTACHMENTS; ++i)
+ rtv[i] = nullptr;
+ }
+
+ QD3D11RenderPassDescriptor *rp = nullptr;
+ QSize pixelSize;
+ float dpr = 1;
+ int sampleCount = 1;
+ int colorAttCount = 0;
+ int dsAttCount = 0;
+
+ static const int MAX_COLOR_ATTACHMENTS = 8;
+ ID3D11RenderTargetView *rtv[MAX_COLOR_ATTACHMENTS];
+ ID3D11DepthStencilView *dsv = nullptr;
+
+ QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList;
+};
+
+struct QD3D11SwapChainRenderTarget : public QRhiSwapChainRenderTarget
+{
+ QD3D11SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
+ ~QD3D11SwapChainRenderTarget();
+ void destroy() override;
+
+ QSize pixelSize() const override;
+ float devicePixelRatio() const override;
+ int sampleCount() const override;
+
+ QD3D11RenderTargetData d;
+};
+
+struct QD3D11TextureRenderTarget : public QRhiTextureRenderTarget
+{
+ QD3D11TextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags);
+ ~QD3D11TextureRenderTarget();
+ void destroy() override;
+
+ QSize pixelSize() const override;
+ float devicePixelRatio() const override;
+ int sampleCount() const override;
+
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
+ bool create() override;
+
+ QD3D11RenderTargetData d;
+ bool ownsRtv[QD3D11RenderTargetData::MAX_COLOR_ATTACHMENTS];
+ ID3D11RenderTargetView *rtv[QD3D11RenderTargetData::MAX_COLOR_ATTACHMENTS];
+ bool ownsDsv = false;
+ ID3D11DepthStencilView *dsv = nullptr;
+ friend class QRhiD3D11;
+};
+
+struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings
+{
+ QD3D11ShaderResourceBindings(QRhiImplementation *rhi);
+ ~QD3D11ShaderResourceBindings();
+ void destroy() override;
+ bool create() override;
+ void updateResources(UpdateFlags flags) override;
+
+ bool hasDynamicOffset = false;
+ QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
+ uint generation = 0;
+
+ // Keep track of the generation number of each referenced QRhi* to be able
+ // to detect that the batched bindings are out of date.
+ struct BoundUniformBufferData {
+ quint64 id;
+ uint generation;
+ };
+ struct BoundSampledTextureData {
+ int count;
+ struct {
+ quint64 texId;
+ uint texGeneration;
+ quint64 samplerId;
+ uint samplerGeneration;
+ } d[QRhiShaderResourceBinding::Data::MAX_TEX_SAMPLER_ARRAY_SIZE];
+ };
+ struct BoundStorageImageData {
+ quint64 id;
+ uint generation;
+ };
+ struct BoundStorageBufferData {
+ quint64 id;
+ uint generation;
+ };
+ struct BoundResourceData {
+ union {
+ BoundUniformBufferData ubuf;
+ BoundSampledTextureData stex;
+ BoundStorageImageData simage;
+ BoundStorageBufferData sbuf;
+ };
+ };
+ QVarLengthArray<BoundResourceData, 8> boundResourceData;
+
+ struct StageUniformBufferBatches {
+ bool present = false;
+ QRhiBatchedBindings<ID3D11Buffer *> ubufs;
+ QRhiBatchedBindings<UINT> ubuforigbindings;
+ QRhiBatchedBindings<UINT> ubufoffsets;
+ QRhiBatchedBindings<UINT> ubufsizes;
+ void finish() {
+ present = ubufs.finish();
+ ubuforigbindings.finish();
+ ubufoffsets.finish();
+ ubufsizes.finish();
+ }
+ void clear() {
+ ubufs.clear();
+ ubuforigbindings.clear();
+ ubufoffsets.clear();
+ ubufsizes.clear();
+ }
+ };
+
+ struct StageSamplerBatches {
+ bool present = false;
+ QRhiBatchedBindings<ID3D11SamplerState *> samplers;
+ QRhiBatchedBindings<ID3D11ShaderResourceView *> shaderresources;
+ void finish() {
+ present = samplers.finish();
+ shaderresources.finish();
+ }
+ void clear() {
+ samplers.clear();
+ shaderresources.clear();
+ }
+ };
+
+ struct StageUavBatches {
+ bool present = false;
+ QRhiBatchedBindings<ID3D11UnorderedAccessView *> uavs;
+ void finish() {
+ present = uavs.finish();
+ }
+ void clear() {
+ uavs.clear();
+ }
+ };
+
+ StageUniformBufferBatches vsUniformBufferBatches;
+ StageUniformBufferBatches hsUniformBufferBatches;
+ StageUniformBufferBatches dsUniformBufferBatches;
+ StageUniformBufferBatches gsUniformBufferBatches;
+ StageUniformBufferBatches fsUniformBufferBatches;
+ StageUniformBufferBatches csUniformBufferBatches;
+
+ StageSamplerBatches vsSamplerBatches;
+ StageSamplerBatches hsSamplerBatches;
+ StageSamplerBatches dsSamplerBatches;
+ StageSamplerBatches gsSamplerBatches;
+ StageSamplerBatches fsSamplerBatches;
+ StageSamplerBatches csSamplerBatches;
+
+ StageUavBatches csUavBatches;
+
+ friend class QRhiD3D11;
+};
+
+Q_DECLARE_TYPEINFO(QD3D11ShaderResourceBindings::BoundResourceData, Q_RELOCATABLE_TYPE);
+
+struct QD3D11GraphicsPipeline : public QRhiGraphicsPipeline
+{
+ QD3D11GraphicsPipeline(QRhiImplementation *rhi);
+ ~QD3D11GraphicsPipeline();
+ void destroy() override;
+ bool create() override;
+
+ ID3D11DepthStencilState *dsState = nullptr;
+ ID3D11BlendState *blendState = nullptr;
+ struct {
+ ID3D11VertexShader *shader = nullptr;
+ QShader::NativeResourceBindingMap nativeResourceBindingMap;
+ } vs;
+ struct {
+ ID3D11HullShader *shader = nullptr;
+ QShader::NativeResourceBindingMap nativeResourceBindingMap;
+ } hs;
+ struct {
+ ID3D11DomainShader *shader = nullptr;
+ QShader::NativeResourceBindingMap nativeResourceBindingMap;
+ } ds;
+ struct {
+ ID3D11GeometryShader *shader = nullptr;
+ QShader::NativeResourceBindingMap nativeResourceBindingMap;
+ } gs;
+ struct {
+ ID3D11PixelShader *shader = nullptr;
+ QShader::NativeResourceBindingMap nativeResourceBindingMap;
+ } fs;
+ ID3D11InputLayout *inputLayout = nullptr;
+ D3D11_PRIMITIVE_TOPOLOGY d3dTopology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
+ ID3D11RasterizerState *rastState = nullptr;
+ uint generation = 0;
+ friend class QRhiD3D11;
+};
+
+struct QD3D11ComputePipeline : public QRhiComputePipeline
{
- bool enableDebugLayer = false;
+ QD3D11ComputePipeline(QRhiImplementation *rhi);
+ ~QD3D11ComputePipeline();
+ void destroy() override;
+ bool create() override;
+
+ struct {
+ ID3D11ComputeShader *shader = nullptr;
+ QShader::NativeResourceBindingMap nativeResourceBindingMap;
+ } cs;
+ uint generation = 0;
+ friend class QRhiD3D11;
+};
+
+struct QD3D11SwapChain;
+
+struct QD3D11CommandBuffer : public QRhiCommandBuffer
+{
+ QD3D11CommandBuffer(QRhiImplementation *rhi);
+ ~QD3D11CommandBuffer();
+ void destroy() override;
+
+ // these must be kept at a reasonably low value otherwise sizeof Command explodes
+ static const int MAX_DYNAMIC_OFFSET_COUNT = 8;
+ static const int MAX_VERTEX_BUFFER_BINDING_COUNT = 8;
+
+ struct Command {
+ enum Cmd {
+ BeginFrame,
+ EndFrame,
+ ResetShaderResources,
+ SetRenderTarget,
+ Clear,
+ Viewport,
+ Scissor,
+ BindVertexBuffers,
+ BindIndexBuffer,
+ BindGraphicsPipeline,
+ BindShaderResources,
+ StencilRef,
+ BlendConstants,
+ Draw,
+ DrawIndexed,
+ UpdateSubRes,
+ CopySubRes,
+ ResolveSubRes,
+ GenMip,
+ DebugMarkBegin,
+ DebugMarkEnd,
+ DebugMarkMsg,
+ BindComputePipeline,
+ Dispatch
+ };
+ enum ClearFlag { Color = 1, Depth = 2, Stencil = 4 };
+ Cmd cmd;
+
+ // QRhi*/QD3D11* references should be kept at minimum (so no
+ // QRhiTexture/Buffer/etc. pointers).
+ union Args {
+ struct {
+ ID3D11Query *tsQuery;
+ ID3D11Query *tsDisjointQuery;
+ QD3D11RenderTargetData *swapchainData;
+ } beginFrame;
+ struct {
+ ID3D11Query *tsQuery;
+ ID3D11Query *tsDisjointQuery;
+ } endFrame;
+ struct {
+ QRhiRenderTarget *rt;
+ } setRenderTarget;
+ struct {
+ QRhiRenderTarget *rt;
+ int mask;
+ float c[4];
+ float d;
+ quint32 s;
+ } clear;
+ struct {
+ float x, y, w, h;
+ float d0, d1;
+ } viewport;
+ struct {
+ int x, y, w, h;
+ } scissor;
+ struct {
+ int startSlot;
+ int slotCount;
+ ID3D11Buffer *buffers[MAX_VERTEX_BUFFER_BINDING_COUNT];
+ UINT offsets[MAX_VERTEX_BUFFER_BINDING_COUNT];
+ UINT strides[MAX_VERTEX_BUFFER_BINDING_COUNT];
+ } bindVertexBuffers;
+ struct {
+ ID3D11Buffer *buffer;
+ quint32 offset;
+ DXGI_FORMAT format;
+ } bindIndexBuffer;
+ struct {
+ QD3D11GraphicsPipeline *ps;
+ } bindGraphicsPipeline;
+ struct {
+ QD3D11ShaderResourceBindings *srb;
+ bool offsetOnlyChange;
+ int dynamicOffsetCount;
+ uint dynamicOffsetPairs[MAX_DYNAMIC_OFFSET_COUNT * 2]; // binding, offsetInConstants
+ } bindShaderResources;
+ struct {
+ QD3D11GraphicsPipeline *ps;
+ quint32 ref;
+ } stencilRef;
+ struct {
+ QD3D11GraphicsPipeline *ps;
+ float c[4];
+ } blendConstants;
+ struct {
+ QD3D11GraphicsPipeline *ps;
+ quint32 vertexCount;
+ quint32 instanceCount;
+ quint32 firstVertex;
+ quint32 firstInstance;
+ } draw;
+ struct {
+ QD3D11GraphicsPipeline *ps;
+ quint32 indexCount;
+ quint32 instanceCount;
+ quint32 firstIndex;
+ qint32 vertexOffset;
+ quint32 firstInstance;
+ } drawIndexed;
+ struct {
+ ID3D11Resource *dst;
+ UINT dstSubRes;
+ bool hasDstBox;
+ D3D11_BOX dstBox;
+ const void *src; // must come from retain*()
+ UINT srcRowPitch;
+ } updateSubRes;
+ struct {
+ ID3D11Resource *dst;
+ UINT dstSubRes;
+ UINT dstX;
+ UINT dstY;
+ UINT dstZ;
+ ID3D11Resource *src;
+ UINT srcSubRes;
+ bool hasSrcBox;
+ D3D11_BOX srcBox;
+ } copySubRes;
+ struct {
+ ID3D11Resource *dst;
+ UINT dstSubRes;
+ ID3D11Resource *src;
+ UINT srcSubRes;
+ DXGI_FORMAT format;
+ } resolveSubRes;
+ struct {
+ ID3D11ShaderResourceView *srv;
+ } genMip;
+ struct {
+ char s[64];
+ } debugMark;
+ struct {
+ QD3D11ComputePipeline *ps;
+ } bindComputePipeline;
+ struct {
+ UINT x;
+ UINT y;
+ UINT z;
+ } dispatch;
+ } args;
+ };
+
+ enum PassType {
+ NoPass,
+ RenderPass,
+ ComputePass
+ };
+
+ QRhiBackendCommandList<Command> commands;
+ PassType recordingPass;
+ double lastGpuTime = 0;
+ QRhiRenderTarget *currentTarget;
+ QRhiGraphicsPipeline *currentGraphicsPipeline;
+ QRhiComputePipeline *currentComputePipeline;
+ uint currentPipelineGeneration;
+ QRhiShaderResourceBindings *currentGraphicsSrb;
+ QRhiShaderResourceBindings *currentComputeSrb;
+ uint currentSrbGeneration;
+ ID3D11Buffer *currentIndexBuffer;
+ quint32 currentIndexOffset;
+ DXGI_FORMAT currentIndexFormat;
+ ID3D11Buffer *currentVertexBuffers[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
+ quint32 currentVertexOffsets[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
+
+ QVarLengthArray<QByteArray, 4> dataRetainPool;
+ QVarLengthArray<QRhiBufferData, 4> bufferDataRetainPool;
+ QVarLengthArray<QImage, 4> imageRetainPool;
+
+ // relies heavily on implicit sharing (no copies of the actual data will be made)
+ const uchar *retainData(const QByteArray &data) {
+ dataRetainPool.append(data);
+ return reinterpret_cast<const uchar *>(dataRetainPool.last().constData());
+ }
+ const uchar *retainBufferData(const QRhiBufferData &data) {
+ bufferDataRetainPool.append(data);
+ return reinterpret_cast<const uchar *>(bufferDataRetainPool.last().constData());
+ }
+ const uchar *retainImage(const QImage &image) {
+ imageRetainPool.append(image);
+ return imageRetainPool.last().constBits();
+ }
+ void resetCommands() {
+ commands.reset();
+ dataRetainPool.clear();
+ bufferDataRetainPool.clear();
+ imageRetainPool.clear();
+ }
+ void resetState() {
+ recordingPass = NoPass;
+ // do not zero lastGpuTime
+ currentTarget = nullptr;
+ resetCommands();
+ resetCachedState();
+ }
+ void resetCachedState() {
+ currentGraphicsPipeline = nullptr;
+ currentComputePipeline = nullptr;
+ currentPipelineGeneration = 0;
+ currentGraphicsSrb = nullptr;
+ currentComputeSrb = nullptr;
+ currentSrbGeneration = 0;
+ currentIndexBuffer = nullptr;
+ currentIndexOffset = 0;
+ currentIndexFormat = DXGI_FORMAT_R16_UINT;
+ memset(currentVertexBuffers, 0, sizeof(currentVertexBuffers));
+ memset(currentVertexOffsets, 0, sizeof(currentVertexOffsets));
+ }
+};
+
+struct QD3D11SwapChainTimestamps
+{
+ static const int TIMESTAMP_PAIRS = 2;
+
+ bool active[TIMESTAMP_PAIRS] = {};
+ ID3D11Query *disjointQuery[TIMESTAMP_PAIRS] = {};
+ ID3D11Query *query[TIMESTAMP_PAIRS * 2] = {};
+
+ bool prepare(QRhiD3D11 *rhiD);
+ void destroy();
+ bool tryQueryTimestamps(int idx, ID3D11DeviceContext *context, double *elapsedSec);
+};
+
+struct QD3D11SwapChain : public QRhiSwapChain
+{
+ QD3D11SwapChain(QRhiImplementation *rhi);
+ ~QD3D11SwapChain();
+ void destroy() override;
+
+ QRhiCommandBuffer *currentFrameCommandBuffer() override;
+ QRhiRenderTarget *currentFrameRenderTarget() override;
+ QRhiRenderTarget *currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override;
+
+ QSize surfacePixelSize() override;
+ bool isFormatSupported(Format f) override;
+ QRhiSwapChainHdrInfo hdrInfo() override;
+
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
+ bool createOrResize() override;
+
+ void releaseBuffers();
+ bool newColorBuffer(const QSize &size, DXGI_FORMAT format, DXGI_SAMPLE_DESC sampleDesc,
+ ID3D11Texture2D **tex, ID3D11RenderTargetView **rtv) const;
+
+ QWindow *window = nullptr;
+ QSize pixelSize;
+ QD3D11SwapChainRenderTarget rt;
+ QD3D11SwapChainRenderTarget rtRight;
+ QD3D11CommandBuffer cb;
+ DXGI_FORMAT colorFormat;
+ DXGI_FORMAT srgbAdjustedColorFormat;
+ IDXGISwapChain *swapChain = nullptr;
+ UINT swapChainFlags = 0;
+ ID3D11Texture2D *backBufferTex;
+ ID3D11RenderTargetView *backBufferRtv;
+ ID3D11RenderTargetView *backBufferRtvRight = nullptr;
+ static const int BUFFER_COUNT = 2;
+ ID3D11Texture2D *msaaTex[BUFFER_COUNT];
+ ID3D11RenderTargetView *msaaRtv[BUFFER_COUNT];
+ DXGI_SAMPLE_DESC sampleDesc;
+ int currentFrameSlot = 0;
+ int frameCount = 0;
+ QD3D11RenderBuffer *ds = nullptr;
+ UINT swapInterval = 1;
+ IDCompositionTarget *dcompTarget = nullptr;
+ IDCompositionVisual *dcompVisual = nullptr;
+ QD3D11SwapChainTimestamps timestamps;
+ int currentTimestampPairIndex = 0;
};
-struct Q_GUI_EXPORT QRhiD3D11NativeHandles : public QRhiNativeHandles
+class QRhiD3D11 : public QRhiImplementation
{
- // to import a device and a context
- void *dev = nullptr;
- void *context = nullptr;
- // alternatively, to specify the device feature level and/or the adapter to use
- int featureLevel = 0;
- quint32 adapterLuidLow = 0;
- qint32 adapterLuidHigh = 0;
+public:
+ QRhiD3D11(QRhiD3D11InitParams *params, QRhiD3D11NativeHandles *importDevice = nullptr);
+
+ bool create(QRhi::Flags flags) override;
+ void destroy() override;
+
+ QRhiGraphicsPipeline *createGraphicsPipeline() override;
+ QRhiComputePipeline *createComputePipeline() override;
+ QRhiShaderResourceBindings *createShaderResourceBindings() override;
+ QRhiBuffer *createBuffer(QRhiBuffer::Type type,
+ QRhiBuffer::UsageFlags usage,
+ quint32 size) override;
+ QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
+ const QSize &pixelSize,
+ int sampleCount,
+ QRhiRenderBuffer::Flags flags,
+ QRhiTexture::Format backingFormatHint) override;
+ QRhiTexture *createTexture(QRhiTexture::Format format,
+ const QSize &pixelSize,
+ int depth,
+ int arraySize,
+ int sampleCount,
+ QRhiTexture::Flags flags) override;
+ QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
+ QRhiSampler::Filter minFilter,
+ QRhiSampler::Filter mipmapMode,
+ QRhiSampler:: AddressMode u,
+ QRhiSampler::AddressMode v,
+ QRhiSampler::AddressMode w) override;
+
+ QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
+ QRhiTextureRenderTarget::Flags flags) override;
+
+ QRhiSwapChain *createSwapChain() override;
+ QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
+ QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
+ QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
+ QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
+ QRhi::FrameOpResult finish() override;
+
+ void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+
+ void beginPass(QRhiCommandBuffer *cb,
+ QRhiRenderTarget *rt,
+ const QColor &colorClearValue,
+ const QRhiDepthStencilClearValue &depthStencilClearValue,
+ QRhiResourceUpdateBatch *resourceUpdates,
+ QRhiCommandBuffer::BeginPassFlags flags) override;
+ void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+
+ void setGraphicsPipeline(QRhiCommandBuffer *cb,
+ QRhiGraphicsPipeline *ps) override;
+
+ void setShaderResources(QRhiCommandBuffer *cb,
+ QRhiShaderResourceBindings *srb,
+ int dynamicOffsetCount,
+ const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
+
+ void setVertexInput(QRhiCommandBuffer *cb,
+ int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
+ QRhiBuffer *indexBuf, quint32 indexOffset,
+ QRhiCommandBuffer::IndexFormat indexFormat) override;
+
+ void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
+ void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
+ void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
+ void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
+
+ void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
+ quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
+
+ void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
+ quint32 instanceCount, quint32 firstIndex,
+ qint32 vertexOffset, quint32 firstInstance) override;
+
+ void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
+ void debugMarkEnd(QRhiCommandBuffer *cb) override;
+ void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
+
+ void beginComputePass(QRhiCommandBuffer *cb,
+ QRhiResourceUpdateBatch *resourceUpdates,
+ QRhiCommandBuffer::BeginPassFlags flags) override;
+ void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+ void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
+ void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
+
+ const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
+ void beginExternal(QRhiCommandBuffer *cb) override;
+ void endExternal(QRhiCommandBuffer *cb) override;
+ double lastCompletedGpuTime(QRhiCommandBuffer *cb) override;
+
+ QList<int> supportedSampleCounts() const override;
+ int ubufAlignment() const override;
+ bool isYUpInFramebuffer() const override;
+ bool isYUpInNDC() const override;
+ bool isClipDepthZeroToOne() const override;
+ QMatrix4x4 clipSpaceCorrMatrix() const override;
+ bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
+ bool isFeatureSupported(QRhi::Feature feature) const override;
+ int resourceLimit(QRhi::ResourceLimit limit) const override;
+ const QRhiNativeHandles *nativeHandles() override;
+ QRhiDriverInfo driverInfo() const override;
+ QRhiStats statistics() override;
+ bool makeThreadLocalNativeContextCurrent() override;
+ void releaseCachedResources() override;
+ bool isDeviceLost() const override;
+
+ QByteArray pipelineCacheData() override;
+ void setPipelineCacheData(const QByteArray &data) override;
+
+ void enqueueSubresUpload(QD3D11Texture *texD, QD3D11CommandBuffer *cbD,
+ int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc);
+ void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
+ void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD,
+ const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[]);
+ void executeBufferHostWrites(QD3D11Buffer *bufD);
+ void bindShaderResources(QD3D11ShaderResourceBindings *srbD,
+ const uint *dynOfsPairs, int dynOfsPairCount,
+ bool offsetOnlyChange);
+ void resetShaderResources();
+ void executeCommandBuffer(QD3D11CommandBuffer *cbD);
+ DXGI_SAMPLE_DESC effectiveSampleDesc(int sampleCount) const;
+ void finishActiveReadbacks();
+ void reportLiveObjects(ID3D11Device *device);
+ void clearShaderCache();
+ QByteArray compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, uint flags,
+ QString *error, QShaderKey *usedShaderKey);
+ bool ensureDirectCompositionDevice();
+
+ QRhi::Flags rhiFlags;
+ bool debugLayer = false;
+ bool importedDeviceAndContext = false;
+ ID3D11Device *dev = nullptr;
+ ID3D11DeviceContext1 *context = nullptr;
+ D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL(0);
+ LUID adapterLuid = {};
+ ID3DUserDefinedAnnotation *annotations = nullptr;
+ IDXGIAdapter1 *activeAdapter = nullptr;
+ IDXGIFactory1 *dxgiFactory = nullptr;
+ IDCompositionDevice *dcompDevice = nullptr;
+ bool supportsAllowTearing = false;
+ bool useLegacySwapchainModel = false;
+ bool deviceLost = false;
+ QRhiD3D11NativeHandles nativeHandlesStruct;
+ QRhiDriverInfo driverInfoStruct;
+
+ struct {
+ int vsHighestActiveVertexBufferBinding = -1;
+ bool vsHasIndexBufferBound = false;
+ int vsHighestActiveSrvBinding = -1;
+ int hsHighestActiveSrvBinding = -1;
+ int dsHighestActiveSrvBinding = -1;
+ int gsHighestActiveSrvBinding = -1;
+ int fsHighestActiveSrvBinding = -1;
+ int csHighestActiveSrvBinding = -1;
+ int csHighestActiveUavBinding = -1;
+ QD3D11SwapChain *currentSwapChain = nullptr;
+ } contextState;
+
+ struct OffscreenFrame {
+ OffscreenFrame(QRhiImplementation *rhi) : cbWrapper(rhi) { }
+ bool active = false;
+ QD3D11CommandBuffer cbWrapper;
+ ID3D11Query *tsQueries[2] = {};
+ ID3D11Query *tsDisjointQuery = nullptr;
+ } ofr;
+
+ struct TextureReadback {
+ QRhiReadbackDescription desc;
+ QRhiReadbackResult *result;
+ ID3D11Texture2D *stagingTex;
+ quint32 byteSize;
+ quint32 bpl;
+ QSize pixelSize;
+ QRhiTexture::Format format;
+ };
+ QVarLengthArray<TextureReadback, 2> activeTextureReadbacks;
+ struct BufferReadback {
+ QRhiReadbackResult *result;
+ quint32 byteSize;
+ ID3D11Buffer *stagingBuf;
+ };
+ QVarLengthArray<BufferReadback, 2> activeBufferReadbacks;
+
+ struct Shader {
+ Shader() = default;
+ Shader(IUnknown *s, const QByteArray &bytecode, const QShader::NativeResourceBindingMap &rbm)
+ : s(s), bytecode(bytecode), nativeResourceBindingMap(rbm) { }
+ IUnknown *s;
+ QByteArray bytecode;
+ QShader::NativeResourceBindingMap nativeResourceBindingMap;
+ };
+ QHash<QRhiShaderStage, Shader> m_shaderCache;
+
+ // This is what gets exposed as the "pipeline cache", not that that concept
+ // applies anyway. Here we are just storing the DX bytecode for a shader so
+ // we can skip the HLSL->DXBC compilation when the QShader has HLSL source
+ // code and the same shader source has already been compiled before.
+ // m_shaderCache seemingly does the same, but this here does not care about
+ // the ID3D11*Shader, this is just about the bytecode and about allowing
+ // the data to be serialized to persistent storage and then reloaded in
+ // future runs of the app, or when creating another QRhi, etc.
+ struct BytecodeCacheKey {
+ QByteArray sourceHash;
+ QByteArray target;
+ QByteArray entryPoint;
+ uint compileFlags;
+ };
+ QHash<BytecodeCacheKey, QByteArray> m_bytecodeCache;
};
+Q_DECLARE_TYPEINFO(QRhiD3D11::TextureReadback, Q_RELOCATABLE_TYPE);
+Q_DECLARE_TYPEINFO(QRhiD3D11::BufferReadback, Q_RELOCATABLE_TYPE);
+
+inline bool operator==(const QRhiD3D11::BytecodeCacheKey &a, const QRhiD3D11::BytecodeCacheKey &b) noexcept
+{
+ return a.sourceHash == b.sourceHash
+ && a.target == b.target
+ && a.entryPoint == b.entryPoint
+ && a.compileFlags == b.compileFlags;
+}
+
+inline bool operator!=(const QRhiD3D11::BytecodeCacheKey &a, const QRhiD3D11::BytecodeCacheKey &b) noexcept
+{
+ return !(a == b);
+}
+
+inline size_t qHash(const QRhiD3D11::BytecodeCacheKey &k, size_t seed = 0) noexcept
+{
+ return qHash(k.sourceHash, seed) ^ qHash(k.target) ^ qHash(k.entryPoint) ^ k.compileFlags;
+}
+
QT_END_NAMESPACE
#endif
diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h
deleted file mode 100644
index 8b56ccbf33..0000000000
--- a/src/gui/rhi/qrhid3d11_p_p.h
+++ /dev/null
@@ -1,833 +0,0 @@
-// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QRHID3D11_P_H
-#define QRHID3D11_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 "qrhid3d11_p.h"
-#include "qrhi_p_p.h"
-#include "qshaderdescription_p.h"
-#include <QWindow>
-
-#include <d3d11_1.h>
-#include <dxgi1_6.h>
-#include <dcomp.h>
-
-QT_BEGIN_NAMESPACE
-
-struct QD3D11Buffer : public QRhiBuffer
-{
- QD3D11Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
- ~QD3D11Buffer();
- void destroy() override;
- bool create() override;
- QRhiBuffer::NativeBuffer nativeBuffer() override;
- char *beginFullDynamicBufferUpdateForCurrentFrame() override;
- void endFullDynamicBufferUpdateForCurrentFrame() override;
-
- ID3D11UnorderedAccessView *unorderedAccessView(quint32 offset);
-
- ID3D11Buffer *buffer = nullptr;
- char *dynBuf = nullptr;
- bool hasPendingDynamicUpdates = false;
- QHash<quint32, ID3D11UnorderedAccessView *> uavs;
- uint generation = 0;
- friend class QRhiD3D11;
-};
-
-struct QD3D11RenderBuffer : public QRhiRenderBuffer
-{
- QD3D11RenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
- int sampleCount, QRhiRenderBuffer::Flags flags,
- QRhiTexture::Format backingFormatHint);
- ~QD3D11RenderBuffer();
- void destroy() override;
- bool create() override;
- QRhiTexture::Format backingFormat() const override;
-
- ID3D11Texture2D *tex = nullptr;
- ID3D11DepthStencilView *dsv = nullptr;
- ID3D11RenderTargetView *rtv = nullptr;
- DXGI_FORMAT dxgiFormat;
- DXGI_SAMPLE_DESC sampleDesc;
- uint generation = 0;
- friend class QRhiD3D11;
-};
-
-struct QD3D11Texture : public QRhiTexture
-{
- QD3D11Texture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
- int arraySize, int sampleCount, Flags flags);
- ~QD3D11Texture();
- void destroy() override;
- bool create() override;
- bool createFrom(NativeTexture src) override;
- NativeTexture nativeTexture() override;
-
- bool prepareCreate(QSize *adjustedSize = nullptr);
- bool finishCreate();
- ID3D11UnorderedAccessView *unorderedAccessViewForLevel(int level);
- ID3D11Resource *textureResource() const
- {
- if (tex)
- return tex;
- else if (tex1D)
- return tex1D;
- return tex3D;
- }
-
- ID3D11Texture2D *tex = nullptr;
- ID3D11Texture3D *tex3D = nullptr;
- ID3D11Texture1D *tex1D = nullptr;
- bool owns = true;
- ID3D11ShaderResourceView *srv = nullptr;
- DXGI_FORMAT dxgiFormat;
- uint mipLevelCount = 0;
- DXGI_SAMPLE_DESC sampleDesc;
- ID3D11UnorderedAccessView *perLevelViews[QRhi::MAX_MIP_LEVELS];
- uint generation = 0;
- friend class QRhiD3D11;
-};
-
-struct QD3D11Sampler : public QRhiSampler
-{
- QD3D11Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
- AddressMode u, AddressMode v, AddressMode w);
- ~QD3D11Sampler();
- void destroy() override;
- bool create() override;
-
- ID3D11SamplerState *samplerState = nullptr;
- uint generation = 0;
- friend class QRhiD3D11;
-};
-
-struct QD3D11RenderPassDescriptor : public QRhiRenderPassDescriptor
-{
- QD3D11RenderPassDescriptor(QRhiImplementation *rhi);
- ~QD3D11RenderPassDescriptor();
- void destroy() override;
- bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
- QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
- QVector<quint32> serializedFormat() const override;
-};
-
-struct QD3D11RenderTargetData
-{
- QD3D11RenderTargetData(QRhiImplementation *)
- {
- for (int i = 0; i < MAX_COLOR_ATTACHMENTS; ++i)
- rtv[i] = nullptr;
- }
-
- QD3D11RenderPassDescriptor *rp = nullptr;
- QSize pixelSize;
- float dpr = 1;
- int sampleCount = 1;
- int colorAttCount = 0;
- int dsAttCount = 0;
-
- static const int MAX_COLOR_ATTACHMENTS = 8;
- ID3D11RenderTargetView *rtv[MAX_COLOR_ATTACHMENTS];
- ID3D11DepthStencilView *dsv = nullptr;
-
- QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList;
-};
-
-struct QD3D11SwapChainRenderTarget : public QRhiSwapChainRenderTarget
-{
- QD3D11SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
- ~QD3D11SwapChainRenderTarget();
- void destroy() override;
-
- QSize pixelSize() const override;
- float devicePixelRatio() const override;
- int sampleCount() const override;
-
- QD3D11RenderTargetData d;
-};
-
-struct QD3D11TextureRenderTarget : public QRhiTextureRenderTarget
-{
- QD3D11TextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags);
- ~QD3D11TextureRenderTarget();
- void destroy() override;
-
- QSize pixelSize() const override;
- float devicePixelRatio() const override;
- int sampleCount() const override;
-
- QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
- bool create() override;
-
- QD3D11RenderTargetData d;
- bool ownsRtv[QD3D11RenderTargetData::MAX_COLOR_ATTACHMENTS];
- ID3D11RenderTargetView *rtv[QD3D11RenderTargetData::MAX_COLOR_ATTACHMENTS];
- bool ownsDsv = false;
- ID3D11DepthStencilView *dsv = nullptr;
- friend class QRhiD3D11;
-};
-
-struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings
-{
- QD3D11ShaderResourceBindings(QRhiImplementation *rhi);
- ~QD3D11ShaderResourceBindings();
- void destroy() override;
- bool create() override;
- void updateResources(UpdateFlags flags) override;
-
- bool hasDynamicOffset = false;
- QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
- uint generation = 0;
-
- // Keep track of the generation number of each referenced QRhi* to be able
- // to detect that the batched bindings are out of date.
- struct BoundUniformBufferData {
- quint64 id;
- uint generation;
- };
- struct BoundSampledTextureData {
- int count;
- struct {
- quint64 texId;
- uint texGeneration;
- quint64 samplerId;
- uint samplerGeneration;
- } d[QRhiShaderResourceBinding::Data::MAX_TEX_SAMPLER_ARRAY_SIZE];
- };
- struct BoundStorageImageData {
- quint64 id;
- uint generation;
- };
- struct BoundStorageBufferData {
- quint64 id;
- uint generation;
- };
- struct BoundResourceData {
- union {
- BoundUniformBufferData ubuf;
- BoundSampledTextureData stex;
- BoundStorageImageData simage;
- BoundStorageBufferData sbuf;
- };
- };
- QVarLengthArray<BoundResourceData, 8> boundResourceData;
-
- struct StageUniformBufferBatches {
- bool present = false;
- QRhiBatchedBindings<ID3D11Buffer *> ubufs;
- QRhiBatchedBindings<UINT> ubuforigbindings;
- QRhiBatchedBindings<UINT> ubufoffsets;
- QRhiBatchedBindings<UINT> ubufsizes;
- void finish() {
- present = ubufs.finish();
- ubuforigbindings.finish();
- ubufoffsets.finish();
- ubufsizes.finish();
- }
- void clear() {
- ubufs.clear();
- ubuforigbindings.clear();
- ubufoffsets.clear();
- ubufsizes.clear();
- }
- };
-
- struct StageSamplerBatches {
- bool present = false;
- QRhiBatchedBindings<ID3D11SamplerState *> samplers;
- QRhiBatchedBindings<ID3D11ShaderResourceView *> shaderresources;
- void finish() {
- present = samplers.finish();
- shaderresources.finish();
- }
- void clear() {
- samplers.clear();
- shaderresources.clear();
- }
- };
-
- struct StageUavBatches {
- bool present = false;
- QRhiBatchedBindings<ID3D11UnorderedAccessView *> uavs;
- void finish() {
- present = uavs.finish();
- }
- void clear() {
- uavs.clear();
- }
- };
-
- StageUniformBufferBatches vsUniformBufferBatches;
- StageUniformBufferBatches hsUniformBufferBatches;
- StageUniformBufferBatches dsUniformBufferBatches;
- StageUniformBufferBatches gsUniformBufferBatches;
- StageUniformBufferBatches fsUniformBufferBatches;
- StageUniformBufferBatches csUniformBufferBatches;
-
- StageSamplerBatches vsSamplerBatches;
- StageSamplerBatches hsSamplerBatches;
- StageSamplerBatches dsSamplerBatches;
- StageSamplerBatches gsSamplerBatches;
- StageSamplerBatches fsSamplerBatches;
- StageSamplerBatches csSamplerBatches;
-
- StageUavBatches csUavBatches;
-
- friend class QRhiD3D11;
-};
-
-Q_DECLARE_TYPEINFO(QD3D11ShaderResourceBindings::BoundResourceData, Q_RELOCATABLE_TYPE);
-
-struct QD3D11GraphicsPipeline : public QRhiGraphicsPipeline
-{
- QD3D11GraphicsPipeline(QRhiImplementation *rhi);
- ~QD3D11GraphicsPipeline();
- void destroy() override;
- bool create() override;
-
- ID3D11DepthStencilState *dsState = nullptr;
- ID3D11BlendState *blendState = nullptr;
- struct {
- ID3D11VertexShader *shader = nullptr;
- QShader::NativeResourceBindingMap nativeResourceBindingMap;
- } vs;
- struct {
- ID3D11HullShader *shader = nullptr;
- QShader::NativeResourceBindingMap nativeResourceBindingMap;
- } hs;
- struct {
- ID3D11DomainShader *shader = nullptr;
- QShader::NativeResourceBindingMap nativeResourceBindingMap;
- } ds;
- struct {
- ID3D11GeometryShader *shader = nullptr;
- QShader::NativeResourceBindingMap nativeResourceBindingMap;
- } gs;
- struct {
- ID3D11PixelShader *shader = nullptr;
- QShader::NativeResourceBindingMap nativeResourceBindingMap;
- } fs;
- ID3D11InputLayout *inputLayout = nullptr;
- D3D11_PRIMITIVE_TOPOLOGY d3dTopology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
- ID3D11RasterizerState *rastState = nullptr;
- uint generation = 0;
- friend class QRhiD3D11;
-};
-
-struct QD3D11ComputePipeline : public QRhiComputePipeline
-{
- QD3D11ComputePipeline(QRhiImplementation *rhi);
- ~QD3D11ComputePipeline();
- void destroy() override;
- bool create() override;
-
- struct {
- ID3D11ComputeShader *shader = nullptr;
- QShader::NativeResourceBindingMap nativeResourceBindingMap;
- } cs;
- uint generation = 0;
- friend class QRhiD3D11;
-};
-
-struct QD3D11SwapChain;
-
-struct QD3D11CommandBuffer : public QRhiCommandBuffer
-{
- QD3D11CommandBuffer(QRhiImplementation *rhi);
- ~QD3D11CommandBuffer();
- void destroy() override;
-
- // these must be kept at a reasonably low value otherwise sizeof Command explodes
- static const int MAX_DYNAMIC_OFFSET_COUNT = 8;
- static const int MAX_VERTEX_BUFFER_BINDING_COUNT = 8;
-
- struct Command {
- enum Cmd {
- ResetShaderResources,
- SetRenderTarget,
- Clear,
- Viewport,
- Scissor,
- BindVertexBuffers,
- BindIndexBuffer,
- BindGraphicsPipeline,
- BindShaderResources,
- StencilRef,
- BlendConstants,
- Draw,
- DrawIndexed,
- UpdateSubRes,
- CopySubRes,
- ResolveSubRes,
- GenMip,
- DebugMarkBegin,
- DebugMarkEnd,
- DebugMarkMsg,
- BindComputePipeline,
- Dispatch
- };
- enum ClearFlag { Color = 1, Depth = 2, Stencil = 4 };
- Cmd cmd;
-
- // QRhi*/QD3D11* references should be kept at minimum (so no
- // QRhiTexture/Buffer/etc. pointers).
- union Args {
- struct {
- QRhiRenderTarget *rt;
- } setRenderTarget;
- struct {
- QRhiRenderTarget *rt;
- int mask;
- float c[4];
- float d;
- quint32 s;
- } clear;
- struct {
- float x, y, w, h;
- float d0, d1;
- } viewport;
- struct {
- int x, y, w, h;
- } scissor;
- struct {
- int startSlot;
- int slotCount;
- ID3D11Buffer *buffers[MAX_VERTEX_BUFFER_BINDING_COUNT];
- UINT offsets[MAX_VERTEX_BUFFER_BINDING_COUNT];
- UINT strides[MAX_VERTEX_BUFFER_BINDING_COUNT];
- } bindVertexBuffers;
- struct {
- ID3D11Buffer *buffer;
- quint32 offset;
- DXGI_FORMAT format;
- } bindIndexBuffer;
- struct {
- QD3D11GraphicsPipeline *ps;
- } bindGraphicsPipeline;
- struct {
- QD3D11ShaderResourceBindings *srb;
- bool offsetOnlyChange;
- int dynamicOffsetCount;
- uint dynamicOffsetPairs[MAX_DYNAMIC_OFFSET_COUNT * 2]; // binding, offsetInConstants
- } bindShaderResources;
- struct {
- QD3D11GraphicsPipeline *ps;
- quint32 ref;
- } stencilRef;
- struct {
- QD3D11GraphicsPipeline *ps;
- float c[4];
- } blendConstants;
- struct {
- QD3D11GraphicsPipeline *ps;
- quint32 vertexCount;
- quint32 instanceCount;
- quint32 firstVertex;
- quint32 firstInstance;
- } draw;
- struct {
- QD3D11GraphicsPipeline *ps;
- quint32 indexCount;
- quint32 instanceCount;
- quint32 firstIndex;
- qint32 vertexOffset;
- quint32 firstInstance;
- } drawIndexed;
- struct {
- ID3D11Resource *dst;
- UINT dstSubRes;
- bool hasDstBox;
- D3D11_BOX dstBox;
- const void *src; // must come from retain*()
- UINT srcRowPitch;
- } updateSubRes;
- struct {
- ID3D11Resource *dst;
- UINT dstSubRes;
- UINT dstX;
- UINT dstY;
- UINT dstZ;
- ID3D11Resource *src;
- UINT srcSubRes;
- bool hasSrcBox;
- D3D11_BOX srcBox;
- } copySubRes;
- struct {
- ID3D11Resource *dst;
- UINT dstSubRes;
- ID3D11Resource *src;
- UINT srcSubRes;
- DXGI_FORMAT format;
- } resolveSubRes;
- struct {
- ID3D11ShaderResourceView *srv;
- } genMip;
- struct {
- char s[64];
- } debugMark;
- struct {
- QD3D11ComputePipeline *ps;
- } bindComputePipeline;
- struct {
- UINT x;
- UINT y;
- UINT z;
- } dispatch;
- } args;
- };
-
- enum PassType {
- NoPass,
- RenderPass,
- ComputePass
- };
-
- QRhiBackendCommandList<Command> commands;
- PassType recordingPass;
- QRhiRenderTarget *currentTarget;
- QRhiGraphicsPipeline *currentGraphicsPipeline;
- QRhiComputePipeline *currentComputePipeline;
- uint currentPipelineGeneration;
- QRhiShaderResourceBindings *currentGraphicsSrb;
- QRhiShaderResourceBindings *currentComputeSrb;
- uint currentSrbGeneration;
- ID3D11Buffer *currentIndexBuffer;
- quint32 currentIndexOffset;
- DXGI_FORMAT currentIndexFormat;
- ID3D11Buffer *currentVertexBuffers[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
- quint32 currentVertexOffsets[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
-
- QVarLengthArray<QByteArray, 4> dataRetainPool;
- QVarLengthArray<QRhiBufferData, 4> bufferDataRetainPool;
- QVarLengthArray<QImage, 4> imageRetainPool;
-
- // relies heavily on implicit sharing (no copies of the actual data will be made)
- const uchar *retainData(const QByteArray &data) {
- dataRetainPool.append(data);
- return reinterpret_cast<const uchar *>(dataRetainPool.last().constData());
- }
- const uchar *retainBufferData(const QRhiBufferData &data) {
- bufferDataRetainPool.append(data);
- return reinterpret_cast<const uchar *>(bufferDataRetainPool.last().constData());
- }
- const uchar *retainImage(const QImage &image) {
- imageRetainPool.append(image);
- return imageRetainPool.last().constBits();
- }
- void resetCommands() {
- commands.reset();
- dataRetainPool.clear();
- bufferDataRetainPool.clear();
- imageRetainPool.clear();
- }
- void resetState() {
- recordingPass = NoPass;
- currentTarget = nullptr;
- resetCommands();
- resetCachedState();
- }
- void resetCachedState() {
- currentGraphicsPipeline = nullptr;
- currentComputePipeline = nullptr;
- currentPipelineGeneration = 0;
- currentGraphicsSrb = nullptr;
- currentComputeSrb = nullptr;
- currentSrbGeneration = 0;
- currentIndexBuffer = nullptr;
- currentIndexOffset = 0;
- currentIndexFormat = DXGI_FORMAT_R16_UINT;
- memset(currentVertexBuffers, 0, sizeof(currentVertexBuffers));
- memset(currentVertexOffsets, 0, sizeof(currentVertexOffsets));
- }
-};
-
-struct QD3D11SwapChain : public QRhiSwapChain
-{
- QD3D11SwapChain(QRhiImplementation *rhi);
- ~QD3D11SwapChain();
- void destroy() override;
-
- QRhiCommandBuffer *currentFrameCommandBuffer() override;
- QRhiRenderTarget *currentFrameRenderTarget() override;
-
- QSize surfacePixelSize() override;
- bool isFormatSupported(Format f) override;
- QRhiSwapChainHdrInfo hdrInfo() override;
-
- QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
- bool createOrResize() override;
-
- void releaseBuffers();
- bool newColorBuffer(const QSize &size, DXGI_FORMAT format, DXGI_SAMPLE_DESC sampleDesc,
- ID3D11Texture2D **tex, ID3D11RenderTargetView **rtv) const;
-
- QWindow *window = nullptr;
- QSize pixelSize;
- QD3D11SwapChainRenderTarget rt;
- QD3D11CommandBuffer cb;
- DXGI_FORMAT colorFormat;
- DXGI_FORMAT srgbAdjustedColorFormat;
- IDXGISwapChain *swapChain = nullptr;
- UINT swapChainFlags = 0;
- static const int BUFFER_COUNT = 2;
- ID3D11Texture2D *backBufferTex;
- ID3D11RenderTargetView *backBufferRtv;
- ID3D11Texture2D *msaaTex[BUFFER_COUNT];
- ID3D11RenderTargetView *msaaRtv[BUFFER_COUNT];
- DXGI_SAMPLE_DESC sampleDesc;
- int currentFrameSlot = 0;
- int frameCount = 0;
- QD3D11RenderBuffer *ds = nullptr;
- bool timestampActive[BUFFER_COUNT];
- ID3D11Query *timestampDisjointQuery[BUFFER_COUNT];
- ID3D11Query *timestampQuery[BUFFER_COUNT * 2];
- UINT swapInterval = 1;
- IDCompositionTarget *dcompTarget = nullptr;
- IDCompositionVisual *dcompVisual = nullptr;
-};
-
-class QRhiD3D11 : public QRhiImplementation
-{
-public:
- QRhiD3D11(QRhiD3D11InitParams *params, QRhiD3D11NativeHandles *importDevice = nullptr);
-
- bool create(QRhi::Flags flags) override;
- void destroy() override;
-
- QRhiGraphicsPipeline *createGraphicsPipeline() override;
- QRhiComputePipeline *createComputePipeline() override;
- QRhiShaderResourceBindings *createShaderResourceBindings() override;
- QRhiBuffer *createBuffer(QRhiBuffer::Type type,
- QRhiBuffer::UsageFlags usage,
- quint32 size) override;
- QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
- const QSize &pixelSize,
- int sampleCount,
- QRhiRenderBuffer::Flags flags,
- QRhiTexture::Format backingFormatHint) override;
- QRhiTexture *createTexture(QRhiTexture::Format format,
- const QSize &pixelSize,
- int depth,
- int arraySize,
- int sampleCount,
- QRhiTexture::Flags flags) override;
- QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
- QRhiSampler::Filter minFilter,
- QRhiSampler::Filter mipmapMode,
- QRhiSampler:: AddressMode u,
- QRhiSampler::AddressMode v,
- QRhiSampler::AddressMode w) override;
-
- QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
- QRhiTextureRenderTarget::Flags flags) override;
-
- QRhiSwapChain *createSwapChain() override;
- QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
- QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
- QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
- QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
- QRhi::FrameOpResult finish() override;
-
- void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
-
- void beginPass(QRhiCommandBuffer *cb,
- QRhiRenderTarget *rt,
- const QColor &colorClearValue,
- const QRhiDepthStencilClearValue &depthStencilClearValue,
- QRhiResourceUpdateBatch *resourceUpdates,
- QRhiCommandBuffer::BeginPassFlags flags) override;
- void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
-
- void setGraphicsPipeline(QRhiCommandBuffer *cb,
- QRhiGraphicsPipeline *ps) override;
-
- void setShaderResources(QRhiCommandBuffer *cb,
- QRhiShaderResourceBindings *srb,
- int dynamicOffsetCount,
- const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
-
- void setVertexInput(QRhiCommandBuffer *cb,
- int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
- QRhiBuffer *indexBuf, quint32 indexOffset,
- QRhiCommandBuffer::IndexFormat indexFormat) override;
-
- void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
- void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
- void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
- void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
-
- void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
- quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
-
- void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
- quint32 instanceCount, quint32 firstIndex,
- qint32 vertexOffset, quint32 firstInstance) override;
-
- void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
- void debugMarkEnd(QRhiCommandBuffer *cb) override;
- void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
-
- void beginComputePass(QRhiCommandBuffer *cb,
- QRhiResourceUpdateBatch *resourceUpdates,
- QRhiCommandBuffer::BeginPassFlags flags) override;
- void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
- void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
- void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
-
- const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
- void beginExternal(QRhiCommandBuffer *cb) override;
- void endExternal(QRhiCommandBuffer *cb) override;
-
- QList<int> supportedSampleCounts() const override;
- int ubufAlignment() const override;
- bool isYUpInFramebuffer() const override;
- bool isYUpInNDC() const override;
- bool isClipDepthZeroToOne() const override;
- QMatrix4x4 clipSpaceCorrMatrix() const override;
- bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
- bool isFeatureSupported(QRhi::Feature feature) const override;
- int resourceLimit(QRhi::ResourceLimit limit) const override;
- const QRhiNativeHandles *nativeHandles() override;
- QRhiDriverInfo driverInfo() const override;
- QRhiStats statistics() override;
- bool makeThreadLocalNativeContextCurrent() override;
- void releaseCachedResources() override;
- bool isDeviceLost() const override;
-
- QByteArray pipelineCacheData() override;
- void setPipelineCacheData(const QByteArray &data) override;
-
- void enqueueSubresUpload(QD3D11Texture *texD, QD3D11CommandBuffer *cbD,
- int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc);
- void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
- void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD,
- const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[]);
- void executeBufferHostWrites(QD3D11Buffer *bufD);
- void bindShaderResources(QD3D11ShaderResourceBindings *srbD,
- const uint *dynOfsPairs, int dynOfsPairCount,
- bool offsetOnlyChange);
- void resetShaderResources();
- void executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *timestampSwapChain = nullptr);
- DXGI_SAMPLE_DESC effectiveSampleCount(int sampleCount) const;
- void finishActiveReadbacks();
- void reportLiveObjects(ID3D11Device *device);
- void clearShaderCache();
- QByteArray compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, uint flags,
- QString *error, QShaderKey *usedShaderKey);
- bool ensureDirectCompositionDevice();
-
- QRhi::Flags rhiFlags;
- bool debugLayer = false;
- bool importedDeviceAndContext = false;
- ID3D11Device *dev = nullptr;
- ID3D11DeviceContext1 *context = nullptr;
- D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL(0);
- LUID adapterLuid = {};
- ID3DUserDefinedAnnotation *annotations = nullptr;
- IDXGIAdapter1 *activeAdapter = nullptr;
- IDXGIFactory1 *dxgiFactory = nullptr;
- IDCompositionDevice *dcompDevice = nullptr;
- bool supportsAllowTearing = false;
- bool deviceLost = false;
- QRhiD3D11NativeHandles nativeHandlesStruct;
- QRhiDriverInfo driverInfoStruct;
-
- struct {
- int vsHighestActiveVertexBufferBinding = -1;
- bool vsHasIndexBufferBound = false;
- int vsHighestActiveSrvBinding = -1;
- int hsHighestActiveSrvBinding = -1;
- int dsHighestActiveSrvBinding = -1;
- int gsHighestActiveSrvBinding = -1;
- int fsHighestActiveSrvBinding = -1;
- int csHighestActiveSrvBinding = -1;
- int csHighestActiveUavBinding = -1;
- QD3D11SwapChain *currentSwapChain = nullptr;
- } contextState;
-
- struct OffscreenFrame {
- OffscreenFrame(QRhiImplementation *rhi) : cbWrapper(rhi) { }
- bool active = false;
- QD3D11CommandBuffer cbWrapper;
- } ofr;
-
- struct TextureReadback {
- QRhiReadbackDescription desc;
- QRhiReadbackResult *result;
- ID3D11Texture2D *stagingTex;
- quint32 byteSize;
- quint32 bpl;
- QSize pixelSize;
- QRhiTexture::Format format;
- };
- QVarLengthArray<TextureReadback, 2> activeTextureReadbacks;
- struct BufferReadback {
- QRhiBufferReadbackResult *result;
- quint32 byteSize;
- ID3D11Buffer *stagingBuf;
- };
- QVarLengthArray<BufferReadback, 2> activeBufferReadbacks;
-
- struct Shader {
- Shader() = default;
- Shader(IUnknown *s, const QByteArray &bytecode, const QShader::NativeResourceBindingMap &rbm)
- : s(s), bytecode(bytecode), nativeResourceBindingMap(rbm) { }
- IUnknown *s;
- QByteArray bytecode;
- QShader::NativeResourceBindingMap nativeResourceBindingMap;
- };
- QHash<QRhiShaderStage, Shader> m_shaderCache;
-
- // This is what gets exposed as the "pipeline cache", not that that concept
- // applies anyway. Here we are just storing the DX bytecode for a shader so
- // we can skip the HLSL->DXBC compilation when the QShader has HLSL source
- // code and the same shader source has already been compiled before.
- // m_shaderCache seemingly does the same, but this here does not care about
- // the ID3D11*Shader, this is just about the bytecode and about allowing
- // the data to be serialized to persistent storage and then reloaded in
- // future runs of the app, or when creating another QRhi, etc.
- struct BytecodeCacheKey {
- QByteArray sourceHash;
- QByteArray target;
- QByteArray entryPoint;
- uint compileFlags;
- };
- QHash<BytecodeCacheKey, QByteArray> m_bytecodeCache;
-};
-
-Q_DECLARE_TYPEINFO(QRhiD3D11::TextureReadback, Q_RELOCATABLE_TYPE);
-Q_DECLARE_TYPEINFO(QRhiD3D11::BufferReadback, Q_RELOCATABLE_TYPE);
-
-inline bool operator==(const QRhiD3D11::BytecodeCacheKey &a, const QRhiD3D11::BytecodeCacheKey &b) noexcept
-{
- return a.sourceHash == b.sourceHash
- && a.target == b.target
- && a.entryPoint == b.entryPoint
- && a.compileFlags == b.compileFlags;
-}
-
-inline bool operator!=(const QRhiD3D11::BytecodeCacheKey &a, const QRhiD3D11::BytecodeCacheKey &b) noexcept
-{
- return !(a == b);
-}
-
-inline size_t qHash(const QRhiD3D11::BytecodeCacheKey &k, size_t seed = 0) noexcept
-{
- return qHash(k.sourceHash, seed) ^ qHash(k.target) ^ qHash(k.entryPoint) ^ k.compileFlags;
-}
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/gui/rhi/qrhid3d12.cpp b/src/gui/rhi/qrhid3d12.cpp
index 20d01db1fa..0f176c683d 100644
--- a/src/gui/rhi/qrhid3d12.cpp
+++ b/src/gui/rhi/qrhid3d12.cpp
@@ -1,19 +1,20 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qrhid3d12_p_p.h"
-#include "qshader_p.h"
-#include <QWindow>
+#include "qrhid3d12_p.h"
#include <qmath.h>
-#include <private/qsystemlibrary_p.h>
-#include <QtCore/qcryptographichash.h>
#include <QtCore/private/qsystemerror_p.h>
-
-#include <d3dcompiler.h>
#include <comdef.h>
-
+#include "qrhid3dhelpers_p.h"
#include "cs_mipmap_p.h"
+#if __has_include(<pix.h>)
+#include <pix.h>
+#define QRHI_D3D12_HAS_OLD_PIX
+#endif
+
+#ifdef __ID3D12Device2_INTERFACE_DEFINED__
+
QT_BEGIN_NAMESPACE
/*
@@ -25,6 +26,9 @@ QT_BEGIN_NAMESPACE
\inmodule QtGui
\brief Direct3D 12 specific initialization parameters.
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
A D3D12-based QRhi needs no special parameters for initialization. If
desired, enableDebugLayer can be set to \c true to enable the Direct3D
debug layer. This can be useful during development, but should be avoided
@@ -58,27 +62,90 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \variable QRhiD3D12InitParams::enableDebugLayer
+
+ When set to true, the debug layer is enabled, if installed and available.
+ The default value is false.
+*/
+
+/*!
\class QRhiD3D12NativeHandles
\inmodule QtGui
\brief Holds the D3D12 device used by the QRhi.
\note The class uses \c{void *} as the type since including the COM-based
- \c{d3d12.h} headers is not acceptable here. The actual type is
- \c{ID3D12Device *}.
+ \c{d3d12.h} headers is not acceptable here. The actual types are
+ \c{ID3D12Device *} and \c{ID3D12CommandQueue *}.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
+ \variable QRhiD3D12NativeHandles::dev
+
+ Points to a
+ \l{https://learn.microsoft.com/en-us/windows/win32/api/d3d12/nn-d3d12-id3d12device}{ID3D12Device}
+ or left set to \nullptr if no existing device is to be imported.
+*/
+
+/*!
+ \variable QRhiD3D12NativeHandles::minimumFeatureLevel
+
+ Specifies the \b minimum feature level passed to
+ \l{https://learn.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-d3d12createdevice}{D3D12CreateDevice()}.
+ When not set, \c{D3D_FEATURE_LEVEL_11_0} is used. See
+ \l{https://learn.microsoft.com/en-us/windows/win32/direct3d12/hardware-feature-levels}{this
+ page} for details.
+
+ Relevant only when QRhi creates the device, ignored when importing a device
+ and device context.
+*/
+
+/*!
+ \variable QRhiD3D12NativeHandles::adapterLuidLow
+
+ The low part of the local identifier (LUID) of the DXGI adapter to use.
+ Relevant only when QRhi creates the device, ignored when importing a device
+ and device context.
+*/
+
+/*!
+ \variable QRhiD3D12NativeHandles::adapterLuidHigh
+
+ The high part of the local identifier (LUID) of the DXGI adapter to use.
+ Relevant only when QRhi creates the device, ignored when importing a device
+ and device context.
+*/
+
+/*!
+ \variable QRhiD3D12NativeHandles::commandQueue
+
+ When set, must point to a
+ \l{https://learn.microsoft.com/en-us/windows/win32/api/d3d12/nn-d3d12-id3d12commandqueue}{ID3D12CommandQueue}.
+ It allows to optionally import a command queue as well, in addition to a
+ device.
+*/
+
+/*!
\class QRhiD3D12CommandBufferNativeHandles
\inmodule QtGui
- \brief Holds the ID3D12GraphicsCommandList object that is backing a QRhiCommandBuffer.
+ \brief Holds the ID3D12GraphicsCommandList1 object that is backing a QRhiCommandBuffer.
\note The command list object is only guaranteed to be valid, and
in recording state, while recording a frame. That is, between a
\l{QRhi::beginFrame()}{beginFrame()} - \l{QRhi::endFrame()}{endFrame()} or
\l{QRhi::beginOffscreenFrame()}{beginOffscreenFrame()} -
\l{QRhi::endOffscreenFrame()}{endOffscreenFrame()} pair.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
+/*!
+ \variable QRhiD3D12CommandBufferNativeHandles::commandList
+*/
+
// https://learn.microsoft.com/en-us/windows/win32/direct3d12/hardware-feature-levels
static const D3D_FEATURE_LEVEL MIN_FEATURE_LEVEL = D3D_FEATURE_LEVEL_11_0;
@@ -87,8 +154,14 @@ QRhiD3D12::QRhiD3D12(QRhiD3D12InitParams *params, QRhiD3D12NativeHandles *import
debugLayer = params->enableDebugLayer;
if (importParams) {
if (importParams->dev) {
- dev = reinterpret_cast<ID3D12Device *>(importParams->dev);
- importedDevice = true;
+ ID3D12Device *d3d12Device = reinterpret_cast<ID3D12Device *>(importParams->dev);
+ if (SUCCEEDED(d3d12Device->QueryInterface(__uuidof(ID3D12Device2), reinterpret_cast<void **>(&dev)))) {
+ // get rid of the ref added by QueryInterface
+ d3d12Device->Release();
+ importedDevice = true;
+ } else {
+ qWarning("ID3D12Device2 not supported, cannot import device");
+ }
}
if (importParams->commandQueue) {
cmdQueue = reinterpret_cast<ID3D12CommandQueue *>(importParams->commandQueue);
@@ -134,9 +207,20 @@ bool QRhiD3D12::create(QRhi::Flags flags)
factoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
HRESULT hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2), reinterpret_cast<void **>(&dxgiFactory));
if (FAILED(hr)) {
- qWarning("CreateDXGIFactory2() failed to create DXGI factory: %s",
- qPrintable(QSystemError::windowsComString(hr)));
- return false;
+ // retry without debug, if it was requested (to match D3D11 backend behavior)
+ if (debugLayer) {
+ qCDebug(QRHI_LOG_INFO, "Debug layer was requested but is not available. "
+ "Attempting to create DXGIFactory2 without it.");
+ factoryFlags &= ~DXGI_CREATE_FACTORY_DEBUG;
+ hr = CreateDXGIFactory2(factoryFlags, __uuidof(IDXGIFactory2), reinterpret_cast<void **>(&dxgiFactory));
+ }
+ if (SUCCEEDED(hr)) {
+ debugLayer = false;
+ } else {
+ qWarning("CreateDXGIFactory2() failed to create DXGI factory: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ return false;
+ }
}
supportsAllowTearing = false;
@@ -204,9 +288,7 @@ bool QRhiD3D12::create(QRhi::Flags flags)
if (!activeAdapter && (requestedAdapterIndex < 0 || requestedAdapterIndex == adapterIndex)) {
activeAdapter = adapter;
adapterLuid = desc.AdapterLuid;
- driverInfoStruct.deviceName = name.toUtf8();
- driverInfoStruct.deviceId = desc.DeviceId;
- driverInfoStruct.vendorId = desc.VendorId;
+ QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
qCDebug(QRHI_LOG_INFO, " using this adapter");
} else {
adapter->Release();
@@ -222,7 +304,7 @@ bool QRhiD3D12::create(QRhi::Flags flags)
hr = D3D12CreateDevice(activeAdapter,
minimumFeatureLevel,
- __uuidof(ID3D12Device),
+ __uuidof(ID3D12Device2),
reinterpret_cast<void **>(&dev));
if (FAILED(hr)) {
qWarning("Failed to create D3D12 device: %s", qPrintable(QSystemError::windowsComString(hr)));
@@ -236,16 +318,20 @@ bool QRhiD3D12::create(QRhi::Flags flags)
for (int adapterIndex = 0; dxgiFactory->EnumAdapters1(UINT(adapterIndex), &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) {
DXGI_ADAPTER_DESC1 desc;
adapter->GetDesc1(&desc);
- adapter->Release();
if (desc.AdapterLuid.LowPart == adapterLuid.LowPart
&& desc.AdapterLuid.HighPart == adapterLuid.HighPart)
{
- driverInfoStruct.deviceName = QString::fromUtf16(reinterpret_cast<char16_t *>(desc.Description)).toUtf8();
- driverInfoStruct.deviceId = desc.DeviceId;
- driverInfoStruct.vendorId = desc.VendorId;
+ activeAdapter = adapter;
+ QRhiD3D::fillDriverInfo(&driverInfoStruct, desc);
break;
+ } else {
+ adapter->Release();
}
}
+ if (!activeAdapter) {
+ qWarning("No adapter");
+ return false;
+ }
qCDebug(QRHI_LOG_INFO, "Using imported device %p", dev);
}
@@ -347,6 +433,9 @@ bool QRhiD3D12::create(QRhi::Flags flags)
qWarning("Could not create host-visible staging area");
return false;
}
+ QString decoratedName = QLatin1String("Small staging area buffer/");
+ decoratedName += QString::number(i);
+ smallStagingAreas[i].mem.buffer->SetName(reinterpret_cast<LPCWSTR>(decoratedName.utf16()));
}
if (!shaderVisibleCbvSrvUavHeap.create(dev,
@@ -357,6 +446,53 @@ bool QRhiD3D12::create(QRhi::Flags flags)
return false;
}
+ if (flags.testFlag(QRhi::EnableTimestamps)) {
+ static bool wantsStablePowerState = qEnvironmentVariableIntValue("QT_D3D_STABLE_POWER_STATE");
+ //
+ // https://learn.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12device-setstablepowerstate
+ //
+ // NB! This is a _global_ setting, affecting other processes (and 3D
+ // APIs such as Vulkan), as long as this application is running. Hence
+ // making it an env.var. for now. Never enable it in production. But
+ // extremely useful for the GPU timings with NVIDIA at least; the
+ // timestamps become stable and smooth, making the number readable and
+ // actually useful e.g. in Quick 3D's DebugView when this is enabled.
+ // (otherwise the number's all over the place)
+ //
+ // See also
+ // https://developer.nvidia.com/blog/advanced-api-performance-setstablepowerstate/
+ // for possible other approaches.
+ //
+ if (wantsStablePowerState)
+ dev->SetStablePowerState(TRUE);
+
+ hr = cmdQueue->GetTimestampFrequency(&timestampTicksPerSecond);
+ if (FAILED(hr)) {
+ qWarning("Failed to query timestamp frequency: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ return false;
+ }
+ if (!timestampQueryHeap.create(dev, QD3D12_FRAMES_IN_FLIGHT * 2, D3D12_QUERY_HEAP_TYPE_TIMESTAMP)) {
+ qWarning("Failed to create timestamp query pool");
+ return false;
+ }
+ const quint32 readbackBufSize = QD3D12_FRAMES_IN_FLIGHT * 2 * sizeof(quint64);
+ if (!timestampReadbackArea.create(this, readbackBufSize, D3D12_HEAP_TYPE_READBACK)) {
+ qWarning("Failed to create timestamp readback buffer");
+ return false;
+ }
+ timestampReadbackArea.mem.buffer->SetName(L"Timestamp readback buffer");
+ memset(timestampReadbackArea.mem.p, 0, readbackBufSize);
+ }
+
+ caps = {};
+ D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {};
+ if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &options3, sizeof(options3)))) {
+ caps.multiView = options3.ViewInstancingTier != D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED;
+ // https://microsoft.github.io/DirectX-Specs/d3d/RelaxedCasting.html
+ caps.textureViewFormat = options3.CastingFullyTypedFormatSupported;
+ }
+
deviceLost = false;
offscreenActive = false;
@@ -385,6 +521,9 @@ void QRhiD3D12::destroy()
}
}
+ timestampQueryHeap.destroy();
+ timestampReadbackArea.destroy();
+
shaderVisibleCbvSrvUavHeap.destroy();
for (int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i)
@@ -400,8 +539,10 @@ void QRhiD3D12::destroy()
cbvSrvUavPool.destroy();
for (int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
- cmdAllocators[i]->Release();
- cmdAllocators[i] = nullptr;
+ if (cmdAllocators[i]) {
+ cmdAllocators[i]->Release();
+ cmdAllocators[i] = nullptr;
+ }
}
if (fullFenceEvent) {
@@ -514,9 +655,13 @@ bool QRhiD3D12::isFeatureSupported(QRhi::Feature feature) const
case QRhi::MultisampleRenderBuffer:
return true;
case QRhi::DebugMarkers:
- return false; // ###
+#ifdef QRHI_D3D12_HAS_OLD_PIX
+ return true;
+#else
+ return false;
+#endif
case QRhi::Timestamps:
- return false; // ###
+ return true;
case QRhi::Instancing:
return true;
case QRhi::CustomInstanceStepRate:
@@ -589,6 +734,14 @@ bool QRhiD3D12::isFeatureSupported(QRhi::Feature feature) const
return true;
case QRhi::ThreeDimensionalTextureMipmaps:
return false; // we generate mipmaps ourselves with compute and this is not implemented
+ case QRhi::MultiView:
+ return caps.multiView;
+ case QRhi::TextureViewFormat:
+ return caps.textureViewFormat;
+ case QRhi::ResolveDepthStencil:
+ // there is no Multisample Resolve support for depth/stencil formats
+ // https://learn.microsoft.com/en-us/windows/win32/direct3ddxgi/hardware-support-for-direct3d-12-1-formats
+ return false;
}
return false;
}
@@ -745,15 +898,18 @@ void QRhiD3D12::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline
}
cbD->cmdList->IASetPrimitiveTopology(psD->topology);
+
+ if (psD->viewInstanceMask)
+ cbD->cmdList->SetViewInstanceMask(psD->viewInstanceMask);
}
}
-void QRhiD3D12::visitUniformBuffer(QD3D12Stage s,
- const QRhiShaderResourceBinding::Data::UniformBufferData &d,
- int,
- int binding,
- int dynamicOffsetCount,
- const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
+void QD3D12CommandBuffer::visitUniformBuffer(QD3D12Stage s,
+ const QRhiShaderResourceBinding::Data::UniformBufferData &d,
+ int,
+ int binding,
+ int dynamicOffsetCount,
+ const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
{
QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, d.buf);
quint32 offset = d.offset;
@@ -766,29 +922,30 @@ void QRhiD3D12::visitUniformBuffer(QD3D12Stage s,
}
}
}
- visitorData.cbufs[s].append({ bufD->handles[currentFrameSlot], offset });
+ QRHI_RES_RHI(QRhiD3D12);
+ visitorData.cbufs[s].append({ bufD->handles[rhiD->currentFrameSlot], offset });
}
-void QRhiD3D12::visitTexture(QD3D12Stage s,
- const QRhiShaderResourceBinding::TextureAndSampler &d,
- int)
+void QD3D12CommandBuffer::visitTexture(QD3D12Stage s,
+ const QRhiShaderResourceBinding::TextureAndSampler &d,
+ int)
{
QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d.tex);
visitorData.srvs[s].append(texD->srv);
}
-void QRhiD3D12::visitSampler(QD3D12Stage s,
- const QRhiShaderResourceBinding::TextureAndSampler &d,
- int)
+void QD3D12CommandBuffer::visitSampler(QD3D12Stage s,
+ const QRhiShaderResourceBinding::TextureAndSampler &d,
+ int)
{
QD3D12Sampler *samplerD = QRHI_RES(QD3D12Sampler, d.sampler);
visitorData.samplers[s].append(samplerD->lookupOrCreateShaderVisibleDescriptor());
}
-void QRhiD3D12::visitStorageBuffer(QD3D12Stage s,
- const QRhiShaderResourceBinding::Data::StorageBufferData &d,
- QD3D12ShaderResourceVisitor::StorageOp,
- int)
+void QD3D12CommandBuffer::visitStorageBuffer(QD3D12Stage s,
+ const QRhiShaderResourceBinding::Data::StorageBufferData &d,
+ QD3D12ShaderResourceVisitor::StorageOp,
+ int)
{
QD3D12Buffer *bufD = QRHI_RES(QD3D12Buffer, d.buf);
// SPIRV-Cross generated HLSL uses RWByteAddressBuffer
@@ -801,17 +958,17 @@ void QRhiD3D12::visitStorageBuffer(QD3D12Stage s,
visitorData.uavs[s].append({ bufD->handles[0], uavDesc });
}
-void QRhiD3D12::visitStorageImage(QD3D12Stage s,
- const QRhiShaderResourceBinding::Data::StorageImageData &d,
- QD3D12ShaderResourceVisitor::StorageOp,
- int)
+void QD3D12CommandBuffer::visitStorageImage(QD3D12Stage s,
+ const QRhiShaderResourceBinding::Data::StorageImageData &d,
+ QD3D12ShaderResourceVisitor::StorageOp,
+ int)
{
QD3D12Texture *texD = QRHI_RES(QD3D12Texture, d.tex);
const bool isCube = texD->m_flags.testFlag(QRhiTexture::CubeMap);
const bool isArray = texD->m_flags.testFlag(QRhiTexture::TextureArray);
const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
- uavDesc.Format = texD->dxgiFormat;
+ uavDesc.Format = texD->rtFormat;
if (isCube) {
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
uavDesc.Texture2DArray.MipSlice = UINT(d.level);
@@ -821,7 +978,7 @@ void QRhiD3D12::visitStorageImage(QD3D12Stage s,
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
uavDesc.Texture2DArray.MipSlice = UINT(d.level);
uavDesc.Texture2DArray.FirstArraySlice = 0;
- uavDesc.Texture2DArray.ArraySize = UINT(texD->m_arraySize);
+ uavDesc.Texture2DArray.ArraySize = UINT(qMax(0, texD->m_arraySize));
} else if (is3D) {
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D;
uavDesc.Texture3D.MipSlice = UINT(d.level);
@@ -850,8 +1007,8 @@ void QRhiD3D12::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
QD3D12ShaderResourceBindings *srbD = QRHI_RES(QD3D12ShaderResourceBindings, srb);
- for (int i = 0, ie = srbD->sortedBindings.size(); i != ie; ++i) {
- const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->sortedBindings[i]);
+ for (int i = 0, ie = srbD->m_bindings.size(); i != ie; ++i) {
+ const QRhiShaderResourceBinding::Data *b = shaderResourceBindingData(srbD->m_bindings[i]);
switch (b->type) {
case QRhiShaderResourceBinding::UniformBuffer:
{
@@ -963,14 +1120,15 @@ void QRhiD3D12::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
QD3D12ShaderResourceVisitor visitor(srbD, stageData, gfxPsD ? 5 : 1);
+ QD3D12CommandBuffer::VisitorData &visitorData(cbD->visitorData);
visitorData = {};
using namespace std::placeholders;
- visitor.uniformBuffer = std::bind(&QRhiD3D12::visitUniformBuffer, this, _1, _2, _3, _4, dynamicOffsetCount, dynamicOffsets);
- visitor.texture = std::bind(&QRhiD3D12::visitTexture, this, _1, _2, _3);
- visitor.sampler = std::bind(&QRhiD3D12::visitSampler, this, _1, _2, _3);
- visitor.storageBuffer = std::bind(&QRhiD3D12::visitStorageBuffer, this, _1, _2, _3, _4);
- visitor.storageImage = std::bind(&QRhiD3D12::visitStorageImage, this, _1, _2, _3, _4);
+ visitor.uniformBuffer = std::bind(&QD3D12CommandBuffer::visitUniformBuffer, cbD, _1, _2, _3, _4, dynamicOffsetCount, dynamicOffsets);
+ visitor.texture = std::bind(&QD3D12CommandBuffer::visitTexture, cbD, _1, _2, _3);
+ visitor.sampler = std::bind(&QD3D12CommandBuffer::visitSampler, cbD, _1, _2, _3);
+ visitor.storageBuffer = std::bind(&QD3D12CommandBuffer::visitStorageBuffer, cbD, _1, _2, _3, _4);
+ visitor.storageImage = std::bind(&QD3D12CommandBuffer::visitStorageImage, cbD, _1, _2, _3, _4);
visitor.visit();
@@ -1261,19 +1419,43 @@ void QRhiD3D12::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
void QRhiD3D12::debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name)
{
- Q_UNUSED(cb);
+ if (!debugMarkers)
+ return;
+
+ QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
+#ifdef QRHI_D3D12_HAS_OLD_PIX
+ PIXBeginEvent(cbD->cmdList, PIX_COLOR_DEFAULT, reinterpret_cast<LPCWSTR>(QString::fromLatin1(name).utf16()));
+#else
+ Q_UNUSED(cbD);
Q_UNUSED(name);
+#endif
}
void QRhiD3D12::debugMarkEnd(QRhiCommandBuffer *cb)
{
- Q_UNUSED(cb);
+ if (!debugMarkers)
+ return;
+
+ QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
+#ifdef QRHI_D3D12_HAS_OLD_PIX
+ PIXEndEvent(cbD->cmdList);
+#else
+ Q_UNUSED(cbD);
+#endif
}
void QRhiD3D12::debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg)
{
- Q_UNUSED(cb);
+ if (!debugMarkers)
+ return;
+
+ QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
+#ifdef QRHI_D3D12_HAS_OLD_PIX
+ PIXSetMarker(cbD->cmdList, PIX_COLOR_DEFAULT, reinterpret_cast<LPCWSTR>(QString::fromLatin1(msg).utf16()));
+#else
+ Q_UNUSED(cbD);
Q_UNUSED(msg);
+#endif
}
const QRhiNativeHandles *QRhiD3D12::nativeHandles(QRhiCommandBuffer *cb)
@@ -1300,6 +1482,28 @@ void QRhiD3D12::endExternal(QRhiCommandBuffer *cb)
}
}
+double QRhiD3D12::lastCompletedGpuTime(QRhiCommandBuffer *cb)
+{
+ QD3D12CommandBuffer *cbD = QRHI_RES(QD3D12CommandBuffer, cb);
+ return cbD->lastGpuTime;
+}
+
+static void calculateGpuTime(QD3D12CommandBuffer *cbD,
+ int timestampPairStartIndex,
+ const quint8 *readbackBufPtr,
+ quint64 timestampTicksPerSecond)
+{
+ const size_t byteOffset = timestampPairStartIndex * sizeof(quint64);
+ const quint64 *p = reinterpret_cast<const quint64 *>(readbackBufPtr + byteOffset);
+ const quint64 startTime = *p++;
+ const quint64 endTime = *p;
+ if (startTime < endTime) {
+ const quint64 ticks = endTime - startTime;
+ const double timeSec = ticks / double(timestampTicksPerSecond);
+ cbD->lastGpuTime = timeSec;
+ }
+}
+
QRhi::FrameOpResult QRhiD3D12::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
{
Q_UNUSED(flags);
@@ -1321,7 +1525,7 @@ QRhi::FrameOpResult QRhiD3D12::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF
// be in flight anymore). With Qt Quick this situation cannot happen anyway
// by design (one QRhi per window).
for (QD3D12SwapChain *sc : std::as_const(swapchains))
- sc->waitCommandCompletionForFrameSlot(sc->currentFrameSlot);
+ sc->waitCommandCompletionForFrameSlot(currentFrameSlot); // note: swapChainD->currentFrameSlot, not sc's
HRESULT hr = cmdAllocators[currentFrameSlot]->Reset();
if (FAILED(hr)) {
@@ -1343,6 +1547,16 @@ QRhi::FrameOpResult QRhiD3D12::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF
swapChainD->rtWrapper.d.dsv = swapChainD->ds ? swapChainD->ds->dsv.cpuHandle
: D3D12_CPU_DESCRIPTOR_HANDLE { 0 };
+ if (swapChainD->stereo) {
+ swapChainD->rtWrapperRight.d.rtv[0] = swapChainD->sampleDesc.Count > 1
+ ? swapChainD->msaaRtvs[swapChainD->currentBackBufferIndex].cpuHandle
+ : swapChainD->rtvsRight[swapChainD->currentBackBufferIndex].cpuHandle;
+
+ swapChainD->rtWrapperRight.d.dsv =
+ swapChainD->ds ? swapChainD->ds->dsv.cpuHandle : D3D12_CPU_DESCRIPTOR_HANDLE{ 0 };
+ }
+
+
// Time to release things that are marked for currentFrameSlot since due to
// the wait above we know that the previous commands on the GPU for this
// slot must have finished already.
@@ -1360,6 +1574,20 @@ QRhi::FrameOpResult QRhiD3D12::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF
finishActiveReadbacks(); // last, in case the readback-completed callback issues rhi calls
+ if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
+ // Read the timestamps for the previous frame for this slot. (the
+ // ResolveQuery() should have completed by now due to the wait above)
+ const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
+ calculateGpuTime(cbD,
+ timestampPairStartIndex,
+ timestampReadbackArea.mem.p,
+ timestampTicksPerSecond);
+ // Write the start timestamp for this frame for this slot.
+ cbD->cmdList->EndQuery(timestampQueryHeap.heap,
+ D3D12_QUERY_TYPE_TIMESTAMP,
+ timestampPairStartIndex);
+ }
+
return QRhi::FrameOpSuccess;
}
@@ -1384,7 +1612,20 @@ QRhi::FrameOpResult QRhiD3D12::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
barrierGen.addTransitionBarrier(backBufferResourceHandle, D3D12_RESOURCE_STATE_PRESENT);
barrierGen.enqueueBufferedTransitionBarriers(cbD);
- ID3D12GraphicsCommandList *cmdList = cbD->cmdList;
+ if (timestampQueryHeap.isValid()) {
+ const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
+ cbD->cmdList->EndQuery(timestampQueryHeap.heap,
+ D3D12_QUERY_TYPE_TIMESTAMP,
+ timestampPairStartIndex + 1);
+ cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
+ D3D12_QUERY_TYPE_TIMESTAMP,
+ timestampPairStartIndex,
+ 2,
+ timestampReadbackArea.mem.buffer,
+ timestampPairStartIndex * sizeof(quint64));
+ }
+
+ ID3D12GraphicsCommandList1 *cmdList = cbD->cmdList;
HRESULT hr = cmdList->Close();
if (FAILED(hr)) {
qWarning("Failed to close command list: %s",
@@ -1402,6 +1643,10 @@ QRhi::FrameOpResult QRhiD3D12::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
{
presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
}
+ if (!swapChainD->swapChain) {
+ qWarning("Failed to present, no swapchain");
+ return QRhi::FrameOpError;
+ }
HRESULT hr = swapChainD->swapChain->Present(swapChainD->swapInterval, presentFlags);
if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET) {
qWarning("Device loss detected in Present()");
@@ -1468,6 +1713,12 @@ QRhi::FrameOpResult QRhiD3D12::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi:
bindShaderVisibleHeaps(cbD);
+ if (timestampQueryHeap.isValid() && timestampTicksPerSecond) {
+ cbD->cmdList->EndQuery(timestampQueryHeap.heap,
+ D3D12_QUERY_TYPE_TIMESTAMP,
+ currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT);
+ }
+
offscreenActive = true;
*cb = cbD;
@@ -1481,7 +1732,20 @@ QRhi::FrameOpResult QRhiD3D12::endOffscreenFrame(QRhi::EndFrameFlags flags)
offscreenActive = false;
QD3D12CommandBuffer *cbD = offscreenCb[currentFrameSlot];
- ID3D12GraphicsCommandList *cmdList = cbD->cmdList;
+ if (timestampQueryHeap.isValid()) {
+ const int timestampPairStartIndex = currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT;
+ cbD->cmdList->EndQuery(timestampQueryHeap.heap,
+ D3D12_QUERY_TYPE_TIMESTAMP,
+ timestampPairStartIndex + 1);
+ cbD->cmdList->ResolveQueryData(timestampQueryHeap.heap,
+ D3D12_QUERY_TYPE_TIMESTAMP,
+ timestampPairStartIndex,
+ 2,
+ timestampReadbackArea.mem.buffer,
+ timestampPairStartIndex * sizeof(quint64));
+ }
+
+ ID3D12GraphicsCommandList1 *cmdList = cbD->cmdList;
HRESULT hr = cmdList->Close();
if (FAILED(hr)) {
qWarning("Failed to close command list: %s",
@@ -1501,6 +1765,14 @@ QRhi::FrameOpResult QRhiD3D12::endOffscreenFrame(QRhi::EndFrameFlags flags)
// previous) frame is safe since we waited for completion above.
finishActiveReadbacks(true);
+ // the timestamp query results should be available too, given the wait
+ if (timestampQueryHeap.isValid()) {
+ calculateGpuTime(cbD,
+ currentFrameSlot * QD3D12_FRAMES_IN_FLIGHT,
+ timestampReadbackArea.mem.p,
+ timestampTicksPerSecond);
+ }
+
return QRhi::FrameOpSuccess;
}
@@ -1522,7 +1794,7 @@ QRhi::FrameOpResult QRhiD3D12::finish()
Q_ASSERT(cbD->recordingPass == QD3D12CommandBuffer::NoPass);
- ID3D12GraphicsCommandList *cmdList = cbD->cmdList;
+ ID3D12GraphicsCommandList1 *cmdList = cbD->cmdList;
HRESULT hr = cmdList->Close();
if (FAILED(hr)) {
qWarning("Failed to close command list: %s",
@@ -1707,15 +1979,19 @@ void QRhiD3D12::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resource
barrierGen.addTransitionBarrier(dstTexD->handle, D3D12_RESOURCE_STATE_RESOLVE_DEST);
barrierGen.enqueueBufferedTransitionBarriers(cbD);
- const UINT srcSubresource = calcSubresource(0, UINT(colorAtt.layer()), 1);
- const UINT dstSubresource = calcSubresource(UINT(colorAtt.resolveLevel()),
- UINT(colorAtt.resolveLayer()),
- dstTexD->mipLevelCount);
- cbD->cmdList->ResolveSubresource(dstRes->resource, dstSubresource,
- srcRes->resource, srcSubresource,
- dstTexD->dxgiFormat);
+ const UINT resolveCount = colorAtt.multiViewCount() >= 2 ? colorAtt.multiViewCount() : 1;
+ for (UINT resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
+ const UINT srcSubresource = calcSubresource(0, UINT(colorAtt.layer()) + resolveIdx, 1);
+ const UINT dstSubresource = calcSubresource(UINT(colorAtt.resolveLevel()),
+ UINT(colorAtt.resolveLayer()) + resolveIdx,
+ dstTexD->mipLevelCount);
+ cbD->cmdList->ResolveSubresource(dstRes->resource, dstSubresource,
+ srcRes->resource, srcSubresource,
+ dstTexD->dxgiFormat);
+ }
}
-
+ if (rtTex->m_desc.depthResolveTexture())
+ qWarning("Resolving multisample depth-stencil buffers is not supported with D3D");
}
cbD->recordingPass = QD3D12CommandBuffer::NoPass;
@@ -1962,6 +2238,36 @@ void QD3D12CpuDescriptorPool::release(const QD3D12Descriptor &descriptor, quint3
quint64(descriptor.cpuHandle.ptr));
}
+bool QD3D12QueryHeap::create(ID3D12Device *device,
+ quint32 queryCount,
+ D3D12_QUERY_HEAP_TYPE heapType)
+{
+ capacity = queryCount;
+
+ D3D12_QUERY_HEAP_DESC heapDesc = {};
+ heapDesc.Type = heapType;
+ heapDesc.Count = capacity;
+
+ HRESULT hr = device->CreateQueryHeap(&heapDesc, __uuidof(ID3D12QueryHeap), reinterpret_cast<void **>(&heap));
+ if (FAILED(hr)) {
+ qWarning("Failed to create query heap: %s", qPrintable(QSystemError::windowsComString(hr)));
+ heap = nullptr;
+ capacity = 0;
+ return false;
+ }
+
+ return true;
+}
+
+void QD3D12QueryHeap::destroy()
+{
+ if (heap) {
+ heap->Release();
+ heap = nullptr;
+ }
+ capacity = 0;
+}
+
bool QD3D12StagingArea::create(QRhiD3D12 *rhi, quint32 capacity, D3D12_HEAP_TYPE heapType)
{
Q_ASSERT(heapType == D3D12_HEAP_TYPE_UPLOAD || heapType == D3D12_HEAP_TYPE_READBACK);
@@ -2302,8 +2608,8 @@ static inline QPair<int, int> mapBinding(int binding, const QShader::NativeResou
void QD3D12ShaderResourceVisitor::visit()
{
- for (int bindingIdx = 0, bindingCount = srb->sortedBindings.count(); bindingIdx != bindingCount; ++bindingIdx) {
- const QRhiShaderResourceBinding &b(srb->sortedBindings[bindingIdx]);
+ for (int bindingIdx = 0, bindingCount = srb->m_bindings.count(); bindingIdx != bindingCount; ++bindingIdx) {
+ const QRhiShaderResourceBinding &b(srb->m_bindings[bindingIdx]);
const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
for (int stageIdx = 0; stageIdx < stageCount; ++stageIdx) {
@@ -2454,6 +2760,7 @@ bool QD3D12MipmapGenerator::create(QRhiD3D12 *rhiD)
// b0
rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
+ rootParams[0].Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
// t0
descriptorRanges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
@@ -2800,24 +3107,18 @@ void QRhiD3D12::waitGpu()
}
}
-DXGI_SAMPLE_DESC QRhiD3D12::effectiveSampleCount(int sampleCount, DXGI_FORMAT format) const
+DXGI_SAMPLE_DESC QRhiD3D12::effectiveSampleDesc(int sampleCount, DXGI_FORMAT format) const
{
DXGI_SAMPLE_DESC desc;
desc.Count = 1;
desc.Quality = 0;
- // Stay compatible with QSurfaceFormat and friends where samples == 0 means the same as 1.
- int s = qBound(1, sampleCount, 64);
-
- if (!supportedSampleCounts().contains(s)) {
- qWarning("Attempted to set unsupported sample count %d", sampleCount);
- return desc;
- }
+ const int s = effectiveSampleCount(sampleCount);
if (s > 1) {
D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msaaInfo = {};
msaaInfo.Format = format;
- msaaInfo.SampleCount = s;
+ msaaInfo.SampleCount = UINT(s);
if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msaaInfo, sizeof(msaaInfo)))) {
if (msaaInfo.NumQualityLevels > 0) {
desc.Count = UINT(s);
@@ -2831,7 +3132,7 @@ DXGI_SAMPLE_DESC QRhiD3D12::effectiveSampleCount(int sampleCount, DXGI_FORMAT fo
return desc;
}
-bool QRhiD3D12::startCommandListForCurrentFrameSlot(ID3D12GraphicsCommandList **cmdList)
+bool QRhiD3D12::startCommandListForCurrentFrameSlot(ID3D12GraphicsCommandList1 **cmdList)
{
ID3D12CommandAllocator *cmdAlloc = cmdAllocators[currentFrameSlot];
if (!*cmdList) {
@@ -2839,7 +3140,7 @@ bool QRhiD3D12::startCommandListForCurrentFrameSlot(ID3D12GraphicsCommandList **
D3D12_COMMAND_LIST_TYPE_DIRECT,
cmdAlloc,
nullptr,
- __uuidof(ID3D12GraphicsCommandList),
+ __uuidof(ID3D12GraphicsCommandList1),
reinterpret_cast<void **>(cmdList));
if (FAILED(hr)) {
qWarning("Failed to create command list: %s", qPrintable(QSystemError::windowsComString(hr)));
@@ -2997,18 +3298,42 @@ void QRhiD3D12::enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpd
for (int layer = 0, maxLayer = u.subresDesc.size(); layer < maxLayer; ++layer) {
for (int level = 0; level < QRhi::MAX_MIP_LEVELS; ++level) {
for (const QRhiTextureSubresourceUploadDescription &subresDesc : std::as_const(u.subresDesc[layer][level])) {
- const UINT subresource = calcSubresource(UINT(level), is3D ? 0u : UINT(layer), texD->mipLevelCount);
- D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
- UINT64 totalBytes = 0;
- D3D12_RESOURCE_DESC desc = res->desc;
- if (is3D) {
- desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
- desc.DepthOrArraySize = 1;
+ D3D12_SUBRESOURCE_FOOTPRINT footprint = {};
+ footprint.Format = res->desc.Format;
+ footprint.Depth = 1;
+ quint32 totalBytes = 0;
+
+ const QSize subresSize = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
+ : subresDesc.sourceSize();
+ const QPoint srcPos = subresDesc.sourceTopLeft();
+ QPoint dstPos = subresDesc.destinationTopLeft();
+
+ if (!subresDesc.image().isNull()) {
+ const QImage img = subresDesc.image();
+ const int bpl = img.bytesPerLine();
+ footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
+ totalBytes = footprint.RowPitch * img.height();
+ } else if (!subresDesc.data().isEmpty() && isCompressedFormat(texD->m_format)) {
+ QSize blockDim;
+ quint32 bpl = 0;
+ compressedFormatInfo(texD->m_format, subresSize, &bpl, nullptr, &blockDim);
+ footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
+ const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
+ totalBytes = footprint.RowPitch * rowCount;
+ } else if (!subresDesc.data().isEmpty()) {
+ quint32 bpl = 0;
+ if (subresDesc.dataStride())
+ bpl = subresDesc.dataStride();
+ else
+ textureFormatInfo(texD->m_format, subresSize, &bpl, nullptr, nullptr);
+ footprint.RowPitch = aligned<UINT>(bpl, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
+ totalBytes = footprint.RowPitch * subresSize.height();
+ } else {
+ qWarning("Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
+ continue;
}
- dev->GetCopyableFootprints(&desc, subresource, 1, 0,
- &layout, nullptr, nullptr, &totalBytes);
- const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(quint32(totalBytes), 1);
+ const quint32 allocSize = QD3D12StagingArea::allocSizeForArray(totalBytes, 1);
QD3D12StagingArea::Allocation stagingAlloc;
if (smallStagingAreas[currentFrameSlot].remainingCapacity() >= allocSize)
stagingAlloc = smallStagingAreas[currentFrameSlot].get(allocSize);
@@ -3025,32 +3350,29 @@ void QRhiD3D12::enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpd
}
}
- const UINT requiredBytesPerLine = layout.Footprint.RowPitch; // multiple of 256
- const QSize subresSize = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
- : subresDesc.sourceSize();
- const QPoint srcPos = subresDesc.sourceTopLeft();
- QPoint dstPos = subresDesc.destinationTopLeft();
-
D3D12_TEXTURE_COPY_LOCATION dst;
dst.pResource = res->resource;
dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
- dst.SubresourceIndex = subresource;
+ dst.SubresourceIndex = calcSubresource(UINT(level), is3D ? 0u : UINT(layer), texD->mipLevelCount);
D3D12_TEXTURE_COPY_LOCATION src;
src.pResource = stagingAlloc.buffer;
src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
src.PlacedFootprint.Offset = stagingAlloc.bufferOffset;
- src.PlacedFootprint.Footprint = layout.Footprint;
D3D12_BOX srcBox; // back, right, bottom are exclusive
if (!subresDesc.image().isNull()) {
- QImage img = subresDesc.image();
+ const QImage img = subresDesc.image();
const int bpc = qMax(1, img.depth() / 8);
const int bpl = img.bytesPerLine();
QSize size = subresDesc.sourceSize().isEmpty() ? img.size() : subresDesc.sourceSize();
size.setWidth(qMin(size.width(), img.width() - srcPos.x()));
size.setHeight(qMin(size.height(), img.height() - srcPos.y()));
+
+ footprint.Width = size.width();
+ footprint.Height = size.height();
+
srcBox.left = 0;
srcBox.top = 0;
srcBox.right = UINT(size.width());
@@ -3061,7 +3383,7 @@ void QRhiD3D12::enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpd
const uchar *imgPtr = img.constBits();
const quint32 lineBytes = size.width() * bpc;
for (int y = 0, h = size.height(); y < h; ++y) {
- memcpy(stagingAlloc.p + y * requiredBytesPerLine,
+ memcpy(stagingAlloc.p + y * footprint.RowPitch,
imgPtr + srcPos.x() * bpc + (y + srcPos.y()) * bpl,
lineBytes);
}
@@ -3078,15 +3400,19 @@ void QRhiD3D12::enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpd
// width and height must be multiples of the block width and height
srcBox.right = aligned(subresSize.width(), blockDim.width());
srcBox.bottom = aligned(subresSize.height(), blockDim.height());
+
srcBox.front = 0;
srcBox.back = 1;
- const quint32 copyBytes = qMin(bpl, requiredBytesPerLine);
+ footprint.Width = aligned(subresSize.width(), blockDim.width());
+ footprint.Height = aligned(subresSize.height(), blockDim.height());
+
+ const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
const QByteArray imgData = subresDesc.data();
const char *imgPtr = imgData.constData();
const int rowCount = aligned(subresSize.height(), blockDim.height()) / blockDim.height();
for (int y = 0; y < rowCount; ++y)
- memcpy(stagingAlloc.p + y * requiredBytesPerLine, imgPtr + y * bpl, copyBytes);
+ memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + y * bpl, copyBytes);
} else if (!subresDesc.data().isEmpty()) {
srcBox.left = 0;
srcBox.top = 0;
@@ -3095,24 +3421,24 @@ void QRhiD3D12::enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpd
srcBox.front = 0;
srcBox.back = 1;
+ footprint.Width = subresSize.width();
+ footprint.Height = subresSize.height();
+
quint32 bpl = 0;
if (subresDesc.dataStride())
bpl = subresDesc.dataStride();
else
textureFormatInfo(texD->m_format, subresSize, &bpl, nullptr, nullptr);
- const quint32 copyBytes = qMin(bpl, requiredBytesPerLine);
+ const quint32 copyBytes = qMin(bpl, footprint.RowPitch);
const QByteArray data = subresDesc.data();
const char *imgPtr = data.constData();
for (int y = 0, h = subresSize.height(); y < h; ++y)
- memcpy(stagingAlloc.p + y * requiredBytesPerLine, imgPtr + y * bpl, copyBytes);
- } else {
- qWarning("Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
- if (ownStagingArea.has_value())
- ownStagingArea->destroyWithDeferredRelease(&releaseQueue);
- continue;
+ memcpy(stagingAlloc.p + y * footprint.RowPitch, imgPtr + y * bpl, copyBytes);
}
+ src.PlacedFootprint.Footprint = footprint;
+
cbD->cmdList->CopyTextureRegion(&dst,
UINT(dstPos.x()),
UINT(dstPos.y()),
@@ -3663,7 +3989,7 @@ bool QD3D12RenderBuffer::create()
case QRhiRenderBuffer::Color:
{
dxgiFormat = toD3DTextureFormat(backingFormat(), {});
- sampleDesc = rhiD->effectiveSampleCount(m_sampleCount, dxgiFormat);
+ sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
D3D12_RESOURCE_DESC resourceDesc = {};
resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
resourceDesc.Width = UINT64(m_pixelSize.width());
@@ -3704,7 +4030,7 @@ bool QD3D12RenderBuffer::create()
case QRhiRenderBuffer::DepthStencil:
{
dxgiFormat = DS_FORMAT;
- sampleDesc = rhiD->effectiveSampleCount(m_sampleCount, dxgiFormat);
+ sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
D3D12_RESOURCE_DESC resourceDesc = {};
resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
resourceDesc.Width = UINT64(m_pixelSize.width());
@@ -3857,10 +4183,30 @@ bool QD3D12Texture::prepareCreate(QSize *adjustedSize)
const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
: (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
- QRHI_RES_RHI(QRhiD3D12);
dxgiFormat = toD3DTextureFormat(m_format, m_flags);
+ if (isDepth) {
+ srvFormat = toD3DDepthTextureSRVFormat(m_format);
+ rtFormat = toD3DDepthTextureDSVFormat(m_format);
+ } else {
+ srvFormat = dxgiFormat;
+ rtFormat = dxgiFormat;
+ }
+ if (m_writeViewFormat.format != UnknownFormat) {
+ if (isDepth)
+ rtFormat = toD3DDepthTextureDSVFormat(m_writeViewFormat.format);
+ else
+ rtFormat = toD3DTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
+ }
+ if (m_readViewFormat.format != UnknownFormat) {
+ if (isDepth)
+ srvFormat = toD3DDepthTextureSRVFormat(m_readViewFormat.format);
+ else
+ srvFormat = toD3DTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
+ }
+
+ QRHI_RES_RHI(QRhiD3D12);
mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
- sampleDesc = rhiD->effectiveSampleCount(m_sampleCount, dxgiFormat);
+ sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
if (sampleDesc.Count > 1) {
if (isCube) {
qWarning("Cubemap texture cannot be multisample");
@@ -3895,12 +4241,10 @@ bool QD3D12Texture::prepareCreate(QSize *adjustedSize)
qWarning("Texture cannot be both 1D and 3D");
return false;
}
- m_depth = qMax(1, m_depth);
if (m_depth > 1 && !is3D) {
qWarning("Texture cannot have a depth of %d when it is not 3D", m_depth);
return false;
}
- m_arraySize = qMax(0, m_arraySize);
if (m_arraySize > 0 && !isArray) {
qWarning("Texture cannot have an array size of %d when it is not an array", m_arraySize);
return false;
@@ -3919,14 +4263,13 @@ bool QD3D12Texture::prepareCreate(QSize *adjustedSize)
bool QD3D12Texture::finishCreate()
{
QRHI_RES_RHI(QRhiD3D12);
- const bool isDepth = isDepthTextureFormat(m_format);
const bool isCube = m_flags.testFlag(CubeMap);
const bool is3D = m_flags.testFlag(ThreeDimensional);
const bool isArray = m_flags.testFlag(TextureArray);
const bool is1D = m_flags.testFlag(OneDimensional);
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
- srvDesc.Format = isDepth ? toD3DDepthTextureSRVFormat(m_format) : dxgiFormat;
+ srvDesc.Format = srvFormat;
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
if (isCube) {
@@ -3942,7 +4285,7 @@ bool QD3D12Texture::finishCreate()
srvDesc.Texture1DArray.ArraySize = UINT(m_arrayRangeLength);
} else {
srvDesc.Texture1DArray.FirstArraySlice = 0;
- srvDesc.Texture1DArray.ArraySize = UINT(m_arraySize);
+ srvDesc.Texture1DArray.ArraySize = UINT(qMax(0, m_arraySize));
}
} else {
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D;
@@ -3956,7 +4299,7 @@ bool QD3D12Texture::finishCreate()
srvDesc.Texture2DMSArray.ArraySize = UINT(m_arrayRangeLength);
} else {
srvDesc.Texture2DMSArray.FirstArraySlice = 0;
- srvDesc.Texture2DMSArray.ArraySize = UINT(m_arraySize);
+ srvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, m_arraySize));
}
} else {
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
@@ -3966,7 +4309,7 @@ bool QD3D12Texture::finishCreate()
srvDesc.Texture2DArray.ArraySize = UINT(m_arrayRangeLength);
} else {
srvDesc.Texture2DArray.FirstArraySlice = 0;
- srvDesc.Texture2DArray.ArraySize = UINT(m_arraySize);
+ srvDesc.Texture2DArray.ArraySize = UINT(qMax(0, m_arraySize));
}
}
} else {
@@ -4016,7 +4359,7 @@ bool QD3D12Texture::create()
bool needsOptimizedClearValueSpecified = false;
UINT resourceFlags = 0;
- if (m_flags.testFlag(RenderTarget)) {
+ if (m_flags.testFlag(RenderTarget) || sampleDesc.Count > 1) {
if (isDepth)
resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
else
@@ -4039,7 +4382,10 @@ bool QD3D12Texture::create()
: D3D12_RESOURCE_DIMENSION_TEXTURE2D);
resourceDesc.Width = UINT64(size.width());
resourceDesc.Height = UINT(size.height());
- resourceDesc.DepthOrArraySize = isCube ? 6 : (isArray ? UINT(m_arraySize) : (is3D ? m_depth : 1));
+ resourceDesc.DepthOrArraySize = isCube ? 6
+ : (isArray ? UINT(qMax(0, m_arraySize))
+ : (is3D ? qMax(1, m_depth)
+ : 1));
resourceDesc.MipLevels = mipLevelCount;
resourceDesc.Format = dxgiFormat;
resourceDesc.SampleDesc = sampleDesc;
@@ -4135,6 +4481,10 @@ QD3D12Sampler::~QD3D12Sampler()
void QD3D12Sampler::destroy()
{
shaderVisibleDescriptor = {};
+
+ QRHI_RES_RHI(QRhiD3D12);
+ if (rhiD)
+ rhiD->unregisterResource(this);
}
static inline D3D12_FILTER toD3DFilter(QRhiSampler::Filter minFilter, QRhiSampler::Filter magFilter, QRhiSampler::Filter mipFilter)
@@ -4215,6 +4565,9 @@ bool QD3D12Sampler::create()
desc.MaxAnisotropy = 1.0f;
desc.ComparisonFunc = toD3DTextureComparisonFunc(m_compareOp);
desc.MaxLOD = m_mipmapMode == None ? 0.0f : 10000.0f;
+
+ QRHI_RES_RHI(QRhiD3D12);
+ rhiD->registerResource(this, false);
return true;
}
@@ -4275,7 +4628,7 @@ QRhiRenderPassDescriptor *QD3D12TextureRenderTarget::newCompatibleRenderPassDesc
QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
if (texD)
- rpD->colorFormat[rpD->colorAttachmentCount] = texD->dxgiFormat;
+ rpD->colorFormat[rpD->colorAttachmentCount] = texD->rtFormat;
else if (rbD)
rpD->colorFormat[rpD->colorAttachmentCount] = rbD->dxgiFormat;
rpD->colorAttachmentCount += 1;
@@ -4293,6 +4646,8 @@ QRhiRenderPassDescriptor *QD3D12TextureRenderTarget::newCompatibleRenderPassDesc
rpD->updateSerializedFormat();
+ QRHI_RES_RHI(QRhiD3D12);
+ rhiD->registerResource(rpD);
return rpD;
}
@@ -4321,19 +4676,21 @@ bool QD3D12TextureRenderTarget::create()
qWarning("Could not look up texture handle for render target");
return false;
}
+ const bool isMultiView = it->multiViewCount() >= 2;
+ UINT layerCount = isMultiView ? UINT(it->multiViewCount()) : 1;
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
- rtvDesc.Format = toD3DTextureFormat(texD->format(), texD->flags());
+ rtvDesc.Format = texD->rtFormat;
if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
- rtvDesc.Texture2DArray.ArraySize = 1;
+ rtvDesc.Texture2DArray.ArraySize = layerCount;
} else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
if (texD->flags().testFlag(QRhiTexture::TextureArray)) {
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
rtvDesc.Texture1DArray.MipSlice = UINT(colorAtt.level());
rtvDesc.Texture1DArray.FirstArraySlice = UINT(colorAtt.layer());
- rtvDesc.Texture1DArray.ArraySize = 1;
+ rtvDesc.Texture1DArray.ArraySize = layerCount;
} else {
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D;
rtvDesc.Texture1D.MipSlice = UINT(colorAtt.level());
@@ -4342,18 +4699,18 @@ bool QD3D12TextureRenderTarget::create()
if (texD->sampleDesc.Count > 1) {
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
rtvDesc.Texture2DMSArray.FirstArraySlice = UINT(colorAtt.layer());
- rtvDesc.Texture2DMSArray.ArraySize = 1;
+ rtvDesc.Texture2DMSArray.ArraySize = layerCount;
} else {
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
rtvDesc.Texture2DArray.FirstArraySlice = UINT(colorAtt.layer());
- rtvDesc.Texture2DArray.ArraySize = 1;
+ rtvDesc.Texture2DArray.ArraySize = layerCount;
}
} else if (texD->flags().testFlag(QRhiTexture::ThreeDimensional)) {
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
rtvDesc.Texture3D.MipSlice = UINT(colorAtt.level());
rtvDesc.Texture3D.FirstWSlice = UINT(colorAtt.layer());
- rtvDesc.Texture3D.WSize = 1;
+ rtvDesc.Texture3D.WSize = layerCount;
} else {
if (texD->sampleDesc.Count > 1) {
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
@@ -4396,9 +4753,30 @@ bool QD3D12TextureRenderTarget::create()
return false;
}
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
- dsvDesc.Format = toD3DDepthTextureDSVFormat(depthTexD->format());
+ dsvDesc.Format = depthTexD->rtFormat;
dsvDesc.ViewDimension = depthTexD->sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
: D3D12_DSV_DIMENSION_TEXTURE2D;
+ if (depthTexD->flags().testFlag(QRhiTexture::TextureArray)) {
+ if (depthTexD->sampleDesc.Count > 1) {
+ dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
+ if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
+ dsvDesc.Texture2DMSArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
+ dsvDesc.Texture2DMSArray.ArraySize = UINT(depthTexD->arrayRangeLength());
+ } else {
+ dsvDesc.Texture2DMSArray.FirstArraySlice = 0;
+ dsvDesc.Texture2DMSArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
+ }
+ } else {
+ dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
+ if (depthTexD->arrayRangeStart() >= 0 && depthTexD->arrayRangeLength() >= 0) {
+ dsvDesc.Texture2DArray.FirstArraySlice = UINT(depthTexD->arrayRangeStart());
+ dsvDesc.Texture2DArray.ArraySize = UINT(depthTexD->arrayRangeLength());
+ } else {
+ dsvDesc.Texture2DArray.FirstArraySlice = 0;
+ dsvDesc.Texture2DArray.ArraySize = UINT(qMax(0, depthTexD->arraySize()));
+ }
+ }
+ }
dsv = rhiD->dsvPool.allocate(1);
if (!dsv.isValid()) {
qWarning("Failed to allocate DSV for texture render target");
@@ -4465,25 +4843,21 @@ QD3D12ShaderResourceBindings::~QD3D12ShaderResourceBindings()
void QD3D12ShaderResourceBindings::destroy()
{
- sortedBindings.clear();
+ QRHI_RES_RHI(QRhiD3D12);
+ if (rhiD)
+ rhiD->unregisterResource(this);
}
bool QD3D12ShaderResourceBindings::create()
{
- if (!sortedBindings.isEmpty())
- destroy();
-
QRHI_RES_RHI(QRhiD3D12);
if (!rhiD->sanityCheckShaderResourceBindings(this))
return false;
rhiD->updateLayoutDesc(this);
- std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
- std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
-
hasDynamicOffset = false;
- for (const QRhiShaderResourceBinding &b : sortedBindings) {
+ for (const QRhiShaderResourceBinding &b : std::as_const(m_bindings)) {
const QRhiShaderResourceBinding::Data *bd = QRhiImplementation::shaderResourceBindingData(b);
if (bd->type == QRhiShaderResourceBinding::UniformBuffer && bd->u.ubuf.hasDynamicOffset) {
hasDynamicOffset = true;
@@ -4500,16 +4874,13 @@ bool QD3D12ShaderResourceBindings::create()
// therefore impossible.
generation += 1;
+ rhiD->registerResource(this, false);
return true;
}
void QD3D12ShaderResourceBindings::updateResources(UpdateFlags flags)
{
- sortedBindings.clear();
- std::copy(m_bindings.cbegin(), m_bindings.cend(), std::back_inserter(sortedBindings));
- if (!flags.testFlag(BindingsAreSorted))
- std::sort(sortedBindings.begin(), sortedBindings.end(), QRhiImplementation::sortedBindingLessThan);
-
+ Q_UNUSED(flags);
generation += 1;
}
@@ -4527,6 +4898,7 @@ void QD3D12ShaderResourceBindings::visitUniformBuffer(QD3D12Stage s,
rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
rootParam.ShaderVisibility = qd3d12_stageToVisibility(s);
rootParam.Descriptor.ShaderRegister = shaderRegister;
+ rootParam.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_DATA_STATIC;
visitorData.cbParams[s].append(rootParam);
}
@@ -4718,21 +5090,14 @@ QD3D12ObjectHandle QD3D12ShaderResourceBindings::createRootSignature(const QD3D1
return QD3D12RootSignature::addToPool(&rhiD->rootSignaturePool, rootSig);
}
-// For now we mirror exactly what's done in the D3D11 backend, meaning we use
-// the old shader compiler (so like fxc, not dxc) to generate shader model 5.0
-// output. Some day this should be moved to the new compiler and DXIL.
-
-static pD3DCompile resolveD3DCompile()
-{
- for (const wchar_t *libraryName : {L"D3DCompiler_47", L"D3DCompiler_43"}) {
- QSystemLibrary library(libraryName);
- if (library.load()) {
- if (auto symbol = library.resolve("D3DCompile"))
- return reinterpret_cast<pD3DCompile>(symbol);
- }
- }
- return nullptr;
-}
+// For shader model < 6.0 we do the same as the D3D11 backend: use the old
+// compiler (D3DCompile) to generate DXBC, just as qsb does (when -c is passed)
+// by invoking fxc, not dxc. For SM >= 6.0 we have to use the new compiler and
+// work with DXIL. And that involves IDxcCompiler and needs the presence of
+// dxcompiler.dll and dxil.dll at runtime. Plus there's a chance we have
+// ancient SDK headers when not using MSVC. So this is heavily optional,
+// meaning support for dxc can be disabled both at build time (no dxcapi.h) and
+// at run time (no DLLs).
static inline void makeHlslTargetString(char target[7], const char stage[3], int version)
{
@@ -4747,9 +5112,139 @@ static inline void makeHlslTargetString(char target[7], const char stage[3], int
target[6] = '\0';
}
+enum class HlslCompileFlag
+{
+ WithDebugInfo = 0x01
+};
+
+static QByteArray legacyCompile(const QShaderCode &hlslSource, const char *target, int flags, QString *error)
+{
+ static const pD3DCompile d3dCompile = QRhiD3D::resolveD3DCompile();
+ if (!d3dCompile) {
+ qWarning("Unable to resolve function D3DCompile()");
+ return QByteArray();
+ }
+
+ ID3DBlob *bytecode = nullptr;
+ ID3DBlob *errors = nullptr;
+ UINT d3dCompileFlags = 0;
+ if (flags & int(HlslCompileFlag::WithDebugInfo))
+ d3dCompileFlags |= D3DCOMPILE_DEBUG;
+
+ HRESULT hr = d3dCompile(hlslSource.shader().constData(), SIZE_T(hlslSource.shader().size()),
+ nullptr, nullptr, nullptr,
+ hlslSource.entryPoint().constData(), target, d3dCompileFlags, 0, &bytecode, &errors);
+ if (FAILED(hr) || !bytecode) {
+ qWarning("HLSL shader compilation failed: 0x%x", uint(hr));
+ if (errors) {
+ *error = QString::fromUtf8(static_cast<const char *>(errors->GetBufferPointer()),
+ int(errors->GetBufferSize()));
+ errors->Release();
+ }
+ return QByteArray();
+ }
+
+ QByteArray result;
+ result.resize(int(bytecode->GetBufferSize()));
+ memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
+ bytecode->Release();
+ return result;
+}
+
+#ifdef QRHI_D3D12_HAS_DXC
+
+#ifndef DXC_CP_UTF8
+#define DXC_CP_UTF8 65001
+#endif
+
+#ifndef DXC_ARG_DEBUG
+#define DXC_ARG_DEBUG L"-Zi"
+#endif
+
+static QByteArray dxcCompile(const QShaderCode &hlslSource, const char *target, int flags, QString *error)
+{
+ static std::pair<IDxcCompiler *, IDxcLibrary *> dxc = QRhiD3D::createDxcCompiler();
+ IDxcCompiler *compiler = dxc.first;
+ if (!compiler) {
+ qWarning("Unable to instantiate IDxcCompiler. Likely no dxcompiler.dll and dxil.dll present. "
+ "Use windeployqt or try https://github.com/microsoft/DirectXShaderCompiler/releases");
+ return QByteArray();
+ }
+ IDxcLibrary *library = dxc.second;
+ if (!library)
+ return QByteArray();
+
+ IDxcBlobEncoding *sourceBlob = nullptr;
+ HRESULT hr = library->CreateBlobWithEncodingOnHeapCopy(hlslSource.shader().constData(),
+ UINT32(hlslSource.shader().size()),
+ DXC_CP_UTF8,
+ &sourceBlob);
+ if (FAILED(hr)) {
+ qWarning("Failed to create source blob for dxc: 0x%x (%s)",
+ uint(hr),
+ qPrintable(QSystemError::windowsComString(hr)));
+ return QByteArray();
+ }
+
+ const QString entryPointStr = QString::fromLatin1(hlslSource.entryPoint());
+ const QString targetStr = QString::fromLatin1(target);
+
+ QVarLengthArray<LPCWSTR, 4> argPtrs;
+ QString debugArg;
+ if (flags & int(HlslCompileFlag::WithDebugInfo)) {
+ debugArg = QString::fromUtf16(reinterpret_cast<const char16_t *>(DXC_ARG_DEBUG));
+ argPtrs.append(reinterpret_cast<LPCWSTR>(debugArg.utf16()));
+ }
+
+ IDxcOperationResult *result = nullptr;
+ hr = compiler->Compile(sourceBlob,
+ nullptr,
+ reinterpret_cast<LPCWSTR>(entryPointStr.utf16()),
+ reinterpret_cast<LPCWSTR>(targetStr.utf16()),
+ argPtrs.data(), argPtrs.count(),
+ nullptr, 0,
+ nullptr,
+ &result);
+ sourceBlob->Release();
+ if (SUCCEEDED(hr))
+ result->GetStatus(&hr);
+ if (FAILED(hr)) {
+ qWarning("HLSL shader compilation failed: 0x%x (%s)",
+ uint(hr),
+ qPrintable(QSystemError::windowsComString(hr)));
+ if (result) {
+ IDxcBlobEncoding *errorsBlob = nullptr;
+ if (SUCCEEDED(result->GetErrorBuffer(&errorsBlob))) {
+ if (errorsBlob) {
+ *error = QString::fromUtf8(static_cast<const char *>(errorsBlob->GetBufferPointer()),
+ int(errorsBlob->GetBufferSize()));
+ errorsBlob->Release();
+ }
+ }
+ }
+ return QByteArray();
+ }
+
+ IDxcBlob *bytecode = nullptr;
+ if FAILED(result->GetResult(&bytecode)) {
+ qWarning("No result from IDxcCompiler: 0x%x (%s)",
+ uint(hr),
+ qPrintable(QSystemError::windowsComString(hr)));
+ return QByteArray();
+ }
+
+ QByteArray ba;
+ ba.resize(int(bytecode->GetBufferSize()));
+ memcpy(ba.data(), bytecode->GetBufferPointer(), size_t(ba.size()));
+ bytecode->Release();
+ return ba;
+}
+
+#endif // QRHI_D3D12_HAS_DXC
+
static QByteArray compileHlslShaderSource(const QShader &shader,
QShader::Variant shaderVariant,
- UINT flags,
+ int flags,
QString *error,
QShaderKey *usedShaderKey)
{
@@ -4806,33 +5301,17 @@ static QByteArray compileHlslShaderSource(const QShader &shader,
break;
}
- static const pD3DCompile d3dCompile = resolveD3DCompile();
- if (!d3dCompile) {
- qWarning("Unable to resolve function D3DCompile()");
- return QByteArray();
- }
-
- ID3DBlob *bytecode = nullptr;
- ID3DBlob *errors = nullptr;
- HRESULT hr = d3dCompile(hlslSource.shader().constData(), SIZE_T(hlslSource.shader().size()),
- nullptr, nullptr, nullptr,
- hlslSource.entryPoint().constData(), target, flags, 0, &bytecode, &errors);
- if (FAILED(hr) || !bytecode) {
- qWarning("HLSL shader compilation failed: 0x%x", uint(hr));
- if (errors) {
- *error = QString::fromUtf8(static_cast<const char *>(errors->GetBufferPointer()),
- int(errors->GetBufferSize()));
- errors->Release();
- }
- return QByteArray();
+ if (key.sourceVersion().version() >= 60) {
+#ifdef QRHI_D3D12_HAS_DXC
+ return dxcCompile(hlslSource, target, flags, error);
+#else
+ qWarning("Attempted to runtime-compile HLSL source code for shader model >= 6.0 "
+ "but the Qt build has no support for DXC. "
+ "Rebuild Qt with a recent Windows SDK or switch to an MSVC build.");
+#endif
}
- QByteArray result;
- result.resize(int(bytecode->GetBufferSize()));
- memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
- bytecode->Release();
-
- return result;
+ return legacyCompile(hlslSource, target, flags, error);
}
static inline UINT8 toD3DColorWriteMask(QRhiGraphicsPipeline::ColorMask c)
@@ -5067,6 +5546,22 @@ static inline DXGI_FORMAT toD3DAttributeFormat(QRhiVertexInputAttribute::Format
return DXGI_FORMAT_R16G16_FLOAT;
case QRhiVertexInputAttribute::Half:
return DXGI_FORMAT_R16_FLOAT;
+ case QRhiVertexInputAttribute::UShort4:
+ // Note: D3D does not support UShort3. Pass through UShort3 as UShort4.
+ case QRhiVertexInputAttribute::UShort3:
+ return DXGI_FORMAT_R16G16B16A16_UINT;
+ case QRhiVertexInputAttribute::UShort2:
+ return DXGI_FORMAT_R16G16_UINT;
+ case QRhiVertexInputAttribute::UShort:
+ return DXGI_FORMAT_R16_UINT;
+ case QRhiVertexInputAttribute::SShort4:
+ // Note: D3D does not support SShort3. Pass through SShort3 as SShort4.
+ case QRhiVertexInputAttribute::SShort3:
+ return DXGI_FORMAT_R16G16B16A16_SINT;
+ case QRhiVertexInputAttribute::SShort2:
+ return DXGI_FORMAT_R16G16_SINT;
+ case QRhiVertexInputAttribute::SShort:
+ return DXGI_FORMAT_R16_SINT;
}
Q_UNREACHABLE_RETURN(DXGI_FORMAT_R32G32B32A32_FLOAT);
}
@@ -5122,16 +5617,16 @@ bool QD3D12GraphicsPipeline::create()
} else {
QString error;
QShaderKey shaderKey;
- UINT compileFlags = 0;
+ int compileFlags = 0;
if (m_flags.testFlag(CompileShadersWithDebugInfo))
- compileFlags |= D3DCOMPILE_DEBUG;
+ compileFlags |= int(HlslCompileFlag::WithDebugInfo);
const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(),
shaderStage.shaderVariant(),
compileFlags,
&error,
&shaderKey);
if (bytecode.isEmpty()) {
- qWarning("HLSL compute shader compilation failed: %s", qPrintable(error));
+ qWarning("HLSL graphics shader compilation failed: %s", qPrintable(error));
return false;
}
@@ -5159,32 +5654,94 @@ bool QD3D12GraphicsPipeline::create()
}
QD3D12RenderPassDescriptor *rpD = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
- const DXGI_SAMPLE_DESC sampleDesc = rhiD->effectiveSampleCount(m_sampleCount, DXGI_FORMAT(rpD->colorFormat[0]));
+ const DXGI_SAMPLE_DESC sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, DXGI_FORMAT(rpD->colorFormat[0]));
+
+ struct {
+ QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
+ QD3D12PipelineStateSubObject<D3D12_INPUT_LAYOUT_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT> inputLayout;
+ QD3D12PipelineStateSubObject<D3D12_PRIMITIVE_TOPOLOGY_TYPE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY> primitiveTopology;
+ QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS> VS;
+ QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS> HS;
+ QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS> DS;
+ QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS> GS;
+ QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS> PS;
+ QD3D12PipelineStateSubObject<D3D12_RASTERIZER_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER> rasterizerState;
+ QD3D12PipelineStateSubObject<D3D12_DEPTH_STENCIL_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL> depthStencilState;
+ QD3D12PipelineStateSubObject<D3D12_BLEND_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND> blendState;
+ QD3D12PipelineStateSubObject<D3D12_RT_FORMAT_ARRAY, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS> rtFormats;
+ QD3D12PipelineStateSubObject<DXGI_FORMAT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT> dsFormat;
+ QD3D12PipelineStateSubObject<DXGI_SAMPLE_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC> sampleDesc;
+ QD3D12PipelineStateSubObject<UINT, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK> sampleMask;
+ QD3D12PipelineStateSubObject<D3D12_VIEW_INSTANCING_DESC, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING> viewInstancingDesc;
+ } stream;
+
+ stream.rootSig.object = rootSig;
+
+ QVarLengthArray<D3D12_INPUT_ELEMENT_DESC, 4> inputDescs;
+ QByteArrayList matrixSliceSemantics;
+ if (!shaderBytecode[VS].isEmpty()) {
+ for (auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
+ it != itEnd; ++it)
+ {
+ D3D12_INPUT_ELEMENT_DESC desc = {};
+ // The output from SPIRV-Cross uses TEXCOORD<location> as the
+ // semantic, except for matrices that are unrolled into consecutive
+ // vec2/3/4s attributes and need TEXCOORD<location>_ as
+ // SemanticName and row/column index as SemanticIndex.
+ const int matrixSlice = it->matrixSlice();
+ if (matrixSlice < 0) {
+ desc.SemanticName = "TEXCOORD";
+ desc.SemanticIndex = UINT(it->location());
+ } else {
+ QByteArray sem;
+ sem.resize(16);
+ qsnprintf(sem.data(), sem.size(), "TEXCOORD%d_", it->location() - matrixSlice);
+ matrixSliceSemantics.append(sem);
+ desc.SemanticName = matrixSliceSemantics.last().constData();
+ desc.SemanticIndex = UINT(matrixSlice);
+ }
+ desc.Format = toD3DAttributeFormat(it->format());
+ desc.InputSlot = UINT(it->binding());
+ desc.AlignedByteOffset = it->offset();
+ const QRhiVertexInputBinding *inputBinding = m_vertexInputLayout.bindingAt(it->binding());
+ if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance) {
+ desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
+ desc.InstanceDataStepRate = inputBinding->instanceStepRate();
+ } else {
+ desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
+ }
+ inputDescs.append(desc);
+ }
+ }
+
+ stream.inputLayout.object.NumElements = inputDescs.count();
+ stream.inputLayout.object.pInputElementDescs = inputDescs.isEmpty() ? nullptr : inputDescs.constData();
+
+ stream.primitiveTopology.object = toD3DTopologyType(m_topology);
+ topology = toD3DTopology(m_topology, m_patchControlPointCount);
- D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
- psoDesc.pRootSignature = rootSig;
for (const QRhiShaderStage &shaderStage : std::as_const(m_shaderStages)) {
const int d3dStage = qd3d12_stage(shaderStage.type());
switch (d3dStage) {
case VS:
- psoDesc.VS.pShaderBytecode = shaderBytecode[d3dStage].constData();
- psoDesc.VS.BytecodeLength = shaderBytecode[d3dStage].size();
+ stream.VS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
+ stream.VS.object.BytecodeLength = shaderBytecode[d3dStage].size();
break;
case HS:
- psoDesc.HS.pShaderBytecode = shaderBytecode[d3dStage].constData();
- psoDesc.HS.BytecodeLength = shaderBytecode[d3dStage].size();
+ stream.HS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
+ stream.HS.object.BytecodeLength = shaderBytecode[d3dStage].size();
break;
case DS:
- psoDesc.DS.pShaderBytecode = shaderBytecode[d3dStage].constData();
- psoDesc.DS.BytecodeLength = shaderBytecode[d3dStage].size();
+ stream.DS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
+ stream.DS.object.BytecodeLength = shaderBytecode[d3dStage].size();
break;
case GS:
- psoDesc.GS.pShaderBytecode = shaderBytecode[d3dStage].constData();
- psoDesc.GS.BytecodeLength = shaderBytecode[d3dStage].size();
+ stream.GS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
+ stream.GS.object.BytecodeLength = shaderBytecode[d3dStage].size();
break;
case PS:
- psoDesc.PS.pShaderBytecode = shaderBytecode[d3dStage].constData();
- psoDesc.PS.BytecodeLength = shaderBytecode[d3dStage].size();
+ stream.PS.object.pShaderBytecode = shaderBytecode[d3dStage].constData();
+ stream.PS.object.BytecodeLength = shaderBytecode[d3dStage].size();
break;
default:
Q_UNREACHABLE();
@@ -5192,7 +5749,32 @@ bool QD3D12GraphicsPipeline::create()
}
}
- psoDesc.BlendState.IndependentBlendEnable = m_targetBlends.count() > 1;
+ stream.rasterizerState.object.FillMode = toD3DFillMode(m_polygonMode);
+ stream.rasterizerState.object.CullMode = toD3DCullMode(m_cullMode);
+ stream.rasterizerState.object.FrontCounterClockwise = m_frontFace == CCW;
+ stream.rasterizerState.object.DepthBias = m_depthBias;
+ stream.rasterizerState.object.SlopeScaledDepthBias = m_slopeScaledDepthBias;
+ stream.rasterizerState.object.DepthClipEnable = TRUE;
+ stream.rasterizerState.object.MultisampleEnable = sampleDesc.Count > 1;
+
+ stream.depthStencilState.object.DepthEnable = m_depthTest;
+ stream.depthStencilState.object.DepthWriteMask = m_depthWrite ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
+ stream.depthStencilState.object.DepthFunc = toD3DCompareOp(m_depthOp);
+ stream.depthStencilState.object.StencilEnable = m_stencilTest;
+ if (m_stencilTest) {
+ stream.depthStencilState.object.StencilReadMask = UINT8(m_stencilReadMask);
+ stream.depthStencilState.object.StencilWriteMask = UINT8(m_stencilWriteMask);
+ stream.depthStencilState.object.FrontFace.StencilFailOp = toD3DStencilOp(m_stencilFront.failOp);
+ stream.depthStencilState.object.FrontFace.StencilDepthFailOp = toD3DStencilOp(m_stencilFront.depthFailOp);
+ stream.depthStencilState.object.FrontFace.StencilPassOp = toD3DStencilOp(m_stencilFront.passOp);
+ stream.depthStencilState.object.FrontFace.StencilFunc = toD3DCompareOp(m_stencilFront.compareOp);
+ stream.depthStencilState.object.BackFace.StencilFailOp = toD3DStencilOp(m_stencilBack.failOp);
+ stream.depthStencilState.object.BackFace.StencilDepthFailOp = toD3DStencilOp(m_stencilBack.depthFailOp);
+ stream.depthStencilState.object.BackFace.StencilPassOp = toD3DStencilOp(m_stencilBack.passOp);
+ stream.depthStencilState.object.BackFace.StencilFunc = toD3DCompareOp(m_stencilBack.compareOp);
+ }
+
+ stream.blendState.object.IndependentBlendEnable = m_targetBlends.count() > 1;
for (int i = 0, ie = m_targetBlends.count(); i != ie; ++i) {
const QRhiGraphicsPipeline::TargetBlend &b(m_targetBlends[i]);
D3D12_RENDER_TARGET_BLEND_DESC blend = {};
@@ -5204,95 +5786,40 @@ bool QD3D12GraphicsPipeline::create()
blend.DestBlendAlpha = toD3DBlendFactor(b.dstAlpha, false);
blend.BlendOpAlpha = toD3DBlendOp(b.opAlpha);
blend.RenderTargetWriteMask = toD3DColorWriteMask(b.colorWrite);
- psoDesc.BlendState.RenderTarget[i] = blend;
+ stream.blendState.object.RenderTarget[i] = blend;
}
if (m_targetBlends.isEmpty()) {
D3D12_RENDER_TARGET_BLEND_DESC blend = {};
blend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
- psoDesc.BlendState.RenderTarget[0] = blend;
+ stream.blendState.object.RenderTarget[0] = blend;
}
- psoDesc.SampleMask = 0xFFFFFFFF;
+ stream.rtFormats.object.NumRenderTargets = rpD->colorAttachmentCount;
+ for (int i = 0; i < rpD->colorAttachmentCount; ++i)
+ stream.rtFormats.object.RTFormats[i] = DXGI_FORMAT(rpD->colorFormat[i]);
- psoDesc.RasterizerState.FillMode = toD3DFillMode(m_polygonMode);
- psoDesc.RasterizerState.CullMode = toD3DCullMode(m_cullMode);
- psoDesc.RasterizerState.FrontCounterClockwise = m_frontFace == CCW;
- psoDesc.RasterizerState.DepthBias = m_depthBias;
- psoDesc.RasterizerState.SlopeScaledDepthBias = m_slopeScaledDepthBias;
- psoDesc.RasterizerState.DepthClipEnable = TRUE;
- psoDesc.RasterizerState.MultisampleEnable = sampleDesc.Count > 1;
+ stream.dsFormat.object = rpD->hasDepthStencil ? DXGI_FORMAT(rpD->dsFormat) : DXGI_FORMAT_UNKNOWN;
- psoDesc.DepthStencilState.DepthEnable = m_depthTest;
- psoDesc.DepthStencilState.DepthWriteMask = m_depthWrite ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
- psoDesc.DepthStencilState.DepthFunc = toD3DCompareOp(m_depthOp);
- psoDesc.DepthStencilState.StencilEnable = m_stencilTest;
- if (m_stencilTest) {
- psoDesc.DepthStencilState.StencilReadMask = UINT8(m_stencilReadMask);
- psoDesc.DepthStencilState.StencilWriteMask = UINT8(m_stencilWriteMask);
- psoDesc.DepthStencilState.FrontFace.StencilFailOp = toD3DStencilOp(m_stencilFront.failOp);
- psoDesc.DepthStencilState.FrontFace.StencilDepthFailOp = toD3DStencilOp(m_stencilFront.depthFailOp);
- psoDesc.DepthStencilState.FrontFace.StencilPassOp = toD3DStencilOp(m_stencilFront.passOp);
- psoDesc.DepthStencilState.FrontFace.StencilFunc = toD3DCompareOp(m_stencilFront.compareOp);
- psoDesc.DepthStencilState.BackFace.StencilFailOp = toD3DStencilOp(m_stencilBack.failOp);
- psoDesc.DepthStencilState.BackFace.StencilDepthFailOp = toD3DStencilOp(m_stencilBack.depthFailOp);
- psoDesc.DepthStencilState.BackFace.StencilPassOp = toD3DStencilOp(m_stencilBack.passOp);
- psoDesc.DepthStencilState.BackFace.StencilFunc = toD3DCompareOp(m_stencilBack.compareOp);
- }
+ stream.sampleDesc.object = sampleDesc;
- QVarLengthArray<D3D12_INPUT_ELEMENT_DESC, 4> inputDescs;
- QByteArrayList matrixSliceSemantics;
- if (!shaderBytecode[VS].isEmpty()) {
- for (auto it = m_vertexInputLayout.cbeginAttributes(), itEnd = m_vertexInputLayout.cendAttributes();
- it != itEnd; ++it)
- {
- D3D12_INPUT_ELEMENT_DESC desc = {};
- // The output from SPIRV-Cross uses TEXCOORD<location> as the
- // semantic, except for matrices that are unrolled into consecutive
- // vec2/3/4s attributes and need TEXCOORD<location>_ as
- // SemanticName and row/column index as SemanticIndex.
- const int matrixSlice = it->matrixSlice();
- if (matrixSlice < 0) {
- desc.SemanticName = "TEXCOORD";
- desc.SemanticIndex = UINT(it->location());
- } else {
- QByteArray sem;
- sem.resize(16);
- qsnprintf(sem.data(), sem.size(), "TEXCOORD%d_", it->location() - matrixSlice);
- matrixSliceSemantics.append(sem);
- desc.SemanticName = matrixSliceSemantics.last().constData();
- desc.SemanticIndex = UINT(matrixSlice);
- }
- desc.Format = toD3DAttributeFormat(it->format());
- desc.InputSlot = UINT(it->binding());
- desc.AlignedByteOffset = it->offset();
- const QRhiVertexInputBinding *inputBinding = m_vertexInputLayout.bindingAt(it->binding());
- if (inputBinding->classification() == QRhiVertexInputBinding::PerInstance) {
- desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
- desc.InstanceDataStepRate = inputBinding->instanceStepRate();
- } else {
- desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
- }
- inputDescs.append(desc);
+ stream.sampleMask.object = 0xFFFFFFFF;
+
+ viewInstanceMask = 0;
+ const bool isMultiView = m_multiViewCount >= 2;
+ stream.viewInstancingDesc.object.ViewInstanceCount = isMultiView ? m_multiViewCount : 0;
+ QVarLengthArray<D3D12_VIEW_INSTANCE_LOCATION, 4> viewInstanceLocations;
+ if (isMultiView) {
+ for (int i = 0; i < m_multiViewCount; ++i) {
+ viewInstanceMask |= (1 << i);
+ viewInstanceLocations.append({ 0, UINT(i) });
}
- }
- if (!inputDescs.isEmpty()) {
- psoDesc.InputLayout.pInputElementDescs = inputDescs.constData();
- psoDesc.InputLayout.NumElements = inputDescs.count();
+ stream.viewInstancingDesc.object.pViewInstanceLocations = viewInstanceLocations.constData();
}
- psoDesc.PrimitiveTopologyType = toD3DTopologyType(m_topology);
- topology = toD3DTopology(m_topology, m_patchControlPointCount);
-
- psoDesc.NumRenderTargets = rpD->colorAttachmentCount;
- for (int i = 0; i < rpD->colorAttachmentCount; ++i)
- psoDesc.RTVFormats[i] = DXGI_FORMAT(rpD->colorFormat[i]);
- psoDesc.DSVFormat = rpD->hasDepthStencil ? DXGI_FORMAT(rpD->dsFormat) : DXGI_FORMAT_UNKNOWN;
- psoDesc.SampleDesc = sampleDesc;
+ const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = { sizeof(stream), &stream };
ID3D12PipelineState *pso = nullptr;
- HRESULT hr = rhiD->dev->CreateGraphicsPipelineState(&psoDesc,
- __uuidof(ID3D12PipelineState),
- reinterpret_cast<void **>(&pso));
+ HRESULT hr = rhiD->dev->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState), reinterpret_cast<void **>(&pso));
if (FAILED(hr)) {
qWarning("Failed to create graphics pipeline state: %s",
qPrintable(QSystemError::windowsComString(hr)));
@@ -5356,9 +5883,9 @@ bool QD3D12ComputePipeline::create()
} else {
QString error;
QShaderKey shaderKey;
- UINT compileFlags = 0;
+ int compileFlags = 0;
if (m_flags.testFlag(CompileShadersWithDebugInfo))
- compileFlags |= D3DCOMPILE_DEBUG;
+ compileFlags |= int(HlslCompileFlag::WithDebugInfo);
const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(),
m_shaderStage.shaderVariant(),
compileFlags,
@@ -5391,14 +5918,16 @@ bool QD3D12ComputePipeline::create()
return false;
}
- D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
- psoDesc.pRootSignature = rootSig;
- psoDesc.CS.pShaderBytecode = shaderBytecode.constData();
- psoDesc.CS.BytecodeLength = shaderBytecode.size();
+ struct {
+ QD3D12PipelineStateSubObject<ID3D12RootSignature *, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE> rootSig;
+ QD3D12PipelineStateSubObject<D3D12_SHADER_BYTECODE, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_CS> CS;
+ } stream;
+ stream.rootSig.object = rootSig;
+ stream.CS.object.pShaderBytecode = shaderBytecode.constData();
+ stream.CS.object.BytecodeLength = shaderBytecode.size();
+ const D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = { sizeof(stream), &stream };
ID3D12PipelineState *pso = nullptr;
- HRESULT hr = rhiD->dev->CreateComputePipelineState(&psoDesc,
- __uuidof(ID3D12PipelineState),
- reinterpret_cast<void **>(&pso));
+ HRESULT hr = rhiD->dev->CreatePipelineState(&streamDesc, __uuidof(ID3D12PipelineState), reinterpret_cast<void **>(&pso));
if (FAILED(hr)) {
qWarning("Failed to create compute pipeline state: %s",
qPrintable(QSystemError::windowsComString(hr)));
@@ -5431,7 +5960,9 @@ QD3D12RenderPassDescriptor::~QD3D12RenderPassDescriptor()
void QD3D12RenderPassDescriptor::destroy()
{
- // nothing to do here
+ QRHI_RES_RHI(QRhiD3D12);
+ if (rhiD)
+ rhiD->unregisterResource(this);
}
bool QD3D12RenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const
@@ -5474,13 +6005,17 @@ void QD3D12RenderPassDescriptor::updateSerializedFormat()
QRhiRenderPassDescriptor *QD3D12RenderPassDescriptor::newCompatibleRenderPassDescriptor() const
{
- QD3D12RenderPassDescriptor *rp = new QD3D12RenderPassDescriptor(m_rhi);
- rp->colorAttachmentCount = colorAttachmentCount;
- rp->hasDepthStencil = hasDepthStencil;
- memcpy(rp->colorFormat, colorFormat, sizeof(colorFormat));
- rp->dsFormat = dsFormat;
- rp->updateSerializedFormat();
- return rp;
+ QD3D12RenderPassDescriptor *rpD = new QD3D12RenderPassDescriptor(m_rhi);
+ rpD->colorAttachmentCount = colorAttachmentCount;
+ rpD->hasDepthStencil = hasDepthStencil;
+ memcpy(rpD->colorFormat, colorFormat, sizeof(colorFormat));
+ rpD->dsFormat = dsFormat;
+
+ rpD->updateSerializedFormat();
+
+ QRHI_RES_RHI(QRhiD3D12);
+ rhiD->registerResource(rpD);
+ return rpD;
}
QVector<quint32> QD3D12RenderPassDescriptor::serializedFormat() const
@@ -5544,6 +6079,7 @@ int QD3D12SwapChainRenderTarget::sampleCount() const
QD3D12SwapChain::QD3D12SwapChain(QRhiImplementation *rhi)
: QRhiSwapChain(rhi),
rtWrapper(rhi, this),
+ rtWrapperRight(rhi, this),
cbWrapper(rhi)
{
}
@@ -5600,6 +6136,8 @@ void QD3D12SwapChain::releaseBuffers()
for (UINT i = 0; i < BUFFER_COUNT; ++i) {
rhiD->resourcePool.remove(colorBuffers[i]);
rhiD->rtvPool.release(rtvs[i], 1);
+ if (stereo)
+ rhiD->rtvPool.release(rtvsRight[i], 1);
if (!msaaBuffers[i].isNull())
rhiD->resourcePool.remove(msaaBuffers[i]);
if (msaaRtvs[i].isValid())
@@ -5634,48 +6172,15 @@ QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget()
return &rtWrapper;
}
-QSize QD3D12SwapChain::surfacePixelSize()
+QRhiRenderTarget *QD3D12SwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
{
- Q_ASSERT(m_window);
- return m_window->size() * m_window->devicePixelRatio();
-}
-
-static bool output6ForWindow(QWindow *w, IDXGIAdapter1 *adapter, IDXGIOutput6 **result)
-{
- bool ok = false;
- QRect wr = w->geometry();
- wr = QRect(wr.topLeft() * w->devicePixelRatio(), wr.size() * w->devicePixelRatio());
- const QPoint center = wr.center();
- IDXGIOutput *currentOutput = nullptr;
- IDXGIOutput *output = nullptr;
- for (UINT i = 0; adapter->EnumOutputs(i, &output) != DXGI_ERROR_NOT_FOUND; ++i) {
- DXGI_OUTPUT_DESC desc;
- output->GetDesc(&desc);
- const RECT r = desc.DesktopCoordinates;
- const QRect dr(QPoint(r.left, r.top), QPoint(r.right - 1, r.bottom - 1));
- if (dr.contains(center)) {
- currentOutput = output;
- break;
- } else {
- output->Release();
- }
- }
- if (currentOutput) {
- ok = SUCCEEDED(currentOutput->QueryInterface(__uuidof(IDXGIOutput6), reinterpret_cast<void **>(result)));
- currentOutput->Release();
- }
- return ok;
+ return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
}
-static bool outputDesc1ForWindow(QWindow *w, IDXGIAdapter1 *adapter, DXGI_OUTPUT_DESC1 *result)
+QSize QD3D12SwapChain::surfacePixelSize()
{
- bool ok = false;
- IDXGIOutput6 *out6 = nullptr;
- if (output6ForWindow(w, adapter, &out6)) {
- ok = SUCCEEDED(out6->GetDesc1(result));
- out6->Release();
- }
- return ok;
+ Q_ASSERT(m_window);
+ return m_window->size() * m_window->devicePixelRatio();
}
bool QD3D12SwapChain::isFormatSupported(Format f)
@@ -5690,8 +6195,10 @@ bool QD3D12SwapChain::isFormatSupported(Format f)
QRHI_RES_RHI(QRhiD3D12);
DXGI_OUTPUT_DESC1 desc1;
- if (outputDesc1ForWindow(m_window, rhiD->activeAdapter, &desc1))
- return desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
+ if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &desc1)) {
+ if (desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020)
+ return f == QRhiSwapChain::HDRExtendedSrgbLinear || f == QRhiSwapChain::HDR10;
+ }
return false;
}
@@ -5699,14 +6206,16 @@ bool QD3D12SwapChain::isFormatSupported(Format f)
QRhiSwapChainHdrInfo QD3D12SwapChain::hdrInfo()
{
QRhiSwapChainHdrInfo info = QRhiSwapChain::hdrInfo();
- if (m_format != QRhiSwapChain::SDR && m_window) {
+ // Must use m_window, not window, given this may be called before createOrResize().
+ if (m_window) {
QRHI_RES_RHI(QRhiD3D12);
DXGI_OUTPUT_DESC1 hdrOutputDesc;
- if (outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc)) {
- info.isHardCodedDefaults = false;
+ if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc)) {
info.limitsType = QRhiSwapChainHdrInfo::LuminanceInNits;
info.limits.luminanceInNits.minLuminance = hdrOutputDesc.MinLuminance;
info.limits.luminanceInNits.maxLuminance = hdrOutputDesc.MaxLuminance;
+ info.luminanceBehavior = QRhiSwapChainHdrInfo::SceneReferred; // 1.0 = 80 nits
+ info.sdrWhiteLevel = QRhiD3D::sdrWhiteLevelInNits(hdrOutputDesc);
}
}
return info;
@@ -5723,28 +6232,25 @@ QRhiRenderPassDescriptor *QD3D12SwapChain::newCompatibleRenderPassDescriptor()
rpD->colorFormat[0] = int(srgbAdjustedColorFormat);
rpD->dsFormat = QD3D12RenderBuffer::DS_FORMAT;
rpD->updateSerializedFormat();
+
+ QRHI_RES_RHI(QRhiD3D12);
+ rhiD->registerResource(rpD);
return rpD;
}
-static const DXGI_FORMAT DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
-static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
-
bool QRhiD3D12::ensureDirectCompositionDevice()
{
if (dcompDevice)
return true;
qCDebug(QRHI_LOG_INFO, "Creating Direct Composition device (needed for semi-transparent windows)");
-
- HRESULT hr = DCompositionCreateDevice(nullptr, __uuidof(IDCompositionDevice), reinterpret_cast<void **>(&dcompDevice));
- if (FAILED(hr)) {
- qWarning("Failed to Direct Composition device: %s", qPrintable(QSystemError::windowsComString(hr)));
- return false;
- }
-
- return true;
+ dcompDevice = QRhiD3D::createDirectCompositionDevice();
+ return dcompDevice ? true : false;
}
+static const DXGI_FORMAT DEFAULT_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM;
+static const DXGI_FORMAT DEFAULT_SRGB_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
+
void QD3D12SwapChain::chooseFormats()
{
colorFormat = DEFAULT_FORMAT;
@@ -5752,7 +6258,7 @@ void QD3D12SwapChain::chooseFormats()
hdrColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; // SDR
DXGI_OUTPUT_DESC1 hdrOutputDesc;
QRHI_RES_RHI(QRhiD3D12);
- if (outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc) && m_format != SDR) {
+ if (QRhiD3D::outputDesc1ForWindow(m_window, rhiD->activeAdapter, &hdrOutputDesc) && m_format != SDR) {
// https://docs.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range
if (hdrOutputDesc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) {
switch (m_format) {
@@ -5777,7 +6283,7 @@ void QD3D12SwapChain::chooseFormats()
"(or Use HDR is Off in the Display Settings), ignoring HDR format request");
}
}
- sampleDesc = rhiD->effectiveSampleCount(m_sampleCount, colorFormat);
+ sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, colorFormat);
}
bool QD3D12SwapChain::createOrResize()
@@ -5802,13 +6308,14 @@ bool QD3D12SwapChain::createOrResize()
HWND hwnd = reinterpret_cast<HWND>(window->winId());
HRESULT hr;
QRHI_RES_RHI(QRhiD3D12);
+ stereo = m_window->format().stereo() && rhiD->dxgiFactory->IsWindowedStereoEnabled();
if (m_flags.testFlag(SurfaceHasPreMulAlpha) || m_flags.testFlag(SurfaceHasNonPreMulAlpha)) {
if (rhiD->ensureDirectCompositionDevice()) {
if (!dcompTarget) {
- hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd, true, &dcompTarget);
+ hr = rhiD->dcompDevice->CreateTargetForHwnd(hwnd, false, &dcompTarget);
if (FAILED(hr)) {
- qWarning("Failed to create Direct Compsition target for the window: %s",
+ qWarning("Failed to create Direct Composition target for the window: %s",
qPrintable(QSystemError::windowsComString(hr)));
}
}
@@ -5844,6 +6351,7 @@ bool QD3D12SwapChain::createOrResize()
desc.Flags = swapChainFlags;
desc.Scaling = DXGI_SCALING_NONE;
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
+ desc.Stereo = stereo;
if (dcompVisual) {
// With DirectComposition setting AlphaMode to STRAIGHT fails the
@@ -5898,13 +6406,19 @@ bool QD3D12SwapChain::createOrResize()
qWarning("Failed to set content for Direct Composition visual: %s",
qPrintable(QSystemError::windowsComString(hr)));
}
+ } else {
+ // disable Alt+Enter; not relevant when using DirectComposition
+ rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
}
}
if (FAILED(hr)) {
- qWarning("Failed to create D3D12 swapchain: %s", qPrintable(QSystemError::windowsComString(hr)));
+ qWarning("Failed to create D3D12 swapchain: %s"
+ " (Width=%u Height=%u Format=%u SampleCount=%u BufferCount=%u Scaling=%u SwapEffect=%u Stereo=%u)",
+ qPrintable(QSystemError::windowsComString(hr)),
+ desc.Width, desc.Height, UINT(desc.Format), desc.SampleDesc.Count,
+ desc.BufferCount, UINT(desc.Scaling), UINT(desc.SwapEffect), UINT(desc.Stereo));
return false;
}
- rhiD->dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
for (int i = 0; i < QD3D12_FRAMES_IN_FLIGHT; ++i) {
hr = rhiD->dev->CreateFence(0,
@@ -5951,6 +6465,16 @@ bool QD3D12SwapChain::createOrResize()
rtvDesc.Format = srgbAdjustedColorFormat;
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvs[i].cpuHandle);
+
+ if (stereo) {
+ rtvsRight[i] = rhiD->rtvPool.allocate(1);
+ D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
+ rtvDesc.Format = srgbAdjustedColorFormat;
+ rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
+ rtvDesc.Texture2DArray.ArraySize = 1;
+ rtvDesc.Texture2DArray.FirstArraySlice = 1;
+ rhiD->dev->CreateRenderTargetView(colorBuffer, &rtvDesc, rtvsRight[i].cpuHandle);
+ }
}
if (m_depthStencil && m_depthStencil->sampleCount() != m_sampleCount) {
@@ -6023,6 +6547,15 @@ bool QD3D12SwapChain::createOrResize()
rtD->d.colorAttCount = 1;
rtD->d.dsAttCount = m_depthStencil ? 1 : 0;
+ rtWrapperRight.setRenderPassDescriptor(m_renderPassDesc);
+ QD3D12SwapChainRenderTarget *rtDr = QRHI_RES(QD3D12SwapChainRenderTarget, &rtWrapperRight);
+ rtDr->d.rp = QRHI_RES(QD3D12RenderPassDescriptor, m_renderPassDesc);
+ rtDr->d.pixelSize = pixelSize;
+ rtDr->d.dpr = float(window->devicePixelRatio());
+ rtDr->d.sampleCount = int(sampleDesc.Count);
+ rtDr->d.colorAttCount = 1;
+ rtDr->d.dsAttCount = m_depthStencil ? 1 : 0;
+
if (needsRegistration) {
rhiD->swapchains.insert(this);
rhiD->registerResource(this);
@@ -6032,3 +6565,5 @@ bool QD3D12SwapChain::createOrResize()
}
QT_END_NAMESPACE
+
+#endif // __ID3D12Device2_INTERFACE_DEFINED__
diff --git a/src/gui/rhi/qrhid3d12_p.h b/src/gui/rhi/qrhid3d12_p.h
index e49ef57eaf..3f9abbb5ac 100644
--- a/src/gui/rhi/qrhid3d12_p.h
+++ b/src/gui/rhi/qrhid3d12_p.h
@@ -1,8 +1,8 @@
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QRHID3D12_H
-#define QRHID3D12_H
+#ifndef QRHID3D12_P_H
+#define QRHID3D12_P_H
//
// W A R N I N G
@@ -15,34 +15,1234 @@
// We mean it.
//
-#include <private/qrhi_p.h>
+#include "qrhi_p.h"
+#include <QWindow>
+#include <QBitArray>
-// no d3d includes here, to prevent precompiled header mess due to COM
+#include <optional>
+#include <array>
+
+#include <d3d12.h>
+#include <d3d12sdklayers.h>
+#include <dxgi1_6.h>
+#include <dcomp.h>
+
+#include "D3D12MemAlloc.h"
+
+// ID3D12Device2 and ID3D12GraphicsCommandList1 and types and enums introduced
+// with those are hard requirements now. These should be declared in any
+// moderately recent d3d12.h, but if it is an SDK from before Windows 10
+// version 1703 then these types could be missing. In the absence of other
+// options, handle this by skipping all the code and making QRhi::create() fail
+// in such builds.
+#ifdef __ID3D12Device2_INTERFACE_DEFINED__
+#define QRHI_D3D12_AVAILABLE
QT_BEGIN_NAMESPACE
-struct Q_GUI_EXPORT QRhiD3D12InitParams : public QRhiInitParams
+static const int QD3D12_FRAMES_IN_FLIGHT = 2;
+
+class QRhiD3D12;
+
+struct QD3D12Descriptor
+{
+ D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = {};
+ D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = {};
+
+ bool isValid() const { return cpuHandle.ptr != 0; }
+};
+
+struct QD3D12ReleaseQueue;
+
+struct QD3D12DescriptorHeap
+{
+ bool isValid() const { return heap && capacity; }
+ bool create(ID3D12Device *device,
+ quint32 descriptorCount,
+ D3D12_DESCRIPTOR_HEAP_TYPE heapType,
+ D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags);
+ void createWithExisting(const QD3D12DescriptorHeap &other,
+ quint32 offsetInDescriptors,
+ quint32 descriptorCount);
+ void destroy();
+ void destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue);
+
+ QD3D12Descriptor get(quint32 count);
+ QD3D12Descriptor at(quint32 index) const;
+ quint32 remainingCapacity() const { return capacity - head; }
+
+ QD3D12Descriptor incremented(const QD3D12Descriptor &descriptor, quint32 offsetInDescriptors) const
+ {
+ D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = descriptor.cpuHandle;
+ cpuHandle.ptr += offsetInDescriptors * descriptorByteSize;
+ D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = descriptor.gpuHandle;
+ if (gpuHandle.ptr)
+ gpuHandle.ptr += offsetInDescriptors * descriptorByteSize;
+ return { cpuHandle, gpuHandle };
+ }
+
+ ID3D12DescriptorHeap *heap = nullptr;
+ quint32 capacity = 0;
+ QD3D12Descriptor heapStart;
+ quint32 head = 0;
+ quint32 descriptorByteSize = 0;
+ D3D12_DESCRIPTOR_HEAP_TYPE heapType;
+ D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags;
+};
+
+struct QD3D12CpuDescriptorPool
+{
+ bool isValid() const { return !heaps.isEmpty(); }
+ bool create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE heapType, const char *debugName = "");
+ void destroy();
+
+ QD3D12Descriptor allocate(quint32 count);
+ void release(const QD3D12Descriptor &descriptor, quint32 count);
+
+ static const int DESCRIPTORS_PER_HEAP = 256;
+
+ struct HeapWithMap {
+ QD3D12DescriptorHeap heap;
+ QBitArray map;
+ static HeapWithMap init(const QD3D12DescriptorHeap &heap, quint32 descriptorCount) {
+ HeapWithMap result;
+ result.heap = heap;
+ result.map.resize(descriptorCount);
+ return result;
+ }
+ };
+
+ ID3D12Device *device;
+ quint32 descriptorByteSize;
+ QVector<HeapWithMap> heaps;
+ const char *debugName;
+};
+
+struct QD3D12QueryHeap
+{
+ bool isValid() const { return heap && capacity; }
+ bool create(ID3D12Device *device,
+ quint32 queryCount,
+ D3D12_QUERY_HEAP_TYPE heapType);
+ void destroy();
+
+ ID3D12QueryHeap *heap = nullptr;
+ quint32 capacity = 0;
+};
+
+struct QD3D12StagingArea
+{
+ static const quint32 ALIGNMENT = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT; // 512 so good enough both for cb and texdata
+
+ struct Allocation {
+ quint8 *p = nullptr;
+ D3D12_GPU_VIRTUAL_ADDRESS gpuAddr = 0;
+ ID3D12Resource *buffer = nullptr;
+ quint32 bufferOffset = 0;
+ bool isValid() const { return p != nullptr; }
+ };
+
+ bool isValid() const { return allocation && mem.isValid(); }
+ bool create(QRhiD3D12 *rhi, quint32 capacity, D3D12_HEAP_TYPE heapType);
+ void destroy();
+ void destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue);
+
+ Allocation get(quint32 byteSize);
+
+ quint32 remainingCapacity() const
+ {
+ return capacity - head;
+ }
+
+ static quint32 allocSizeForArray(quint32 size, int count = 1)
+ {
+ return count * ((size + ALIGNMENT - 1) & ~(ALIGNMENT - 1));
+ }
+
+ Allocation mem;
+ ID3D12Resource *resource = nullptr;
+ D3D12MA::Allocation *allocation = nullptr;
+ quint32 head;
+ quint32 capacity;
+};
+
+struct QD3D12ObjectHandle
+{
+ quint32 index = 0;
+ quint32 generation = 0;
+
+ // the default, null handle is guaranteed to give ObjectPool::isValid() == false
+ bool isNull() const { return index == 0 && generation == 0; }
+};
+
+inline bool operator==(const QD3D12ObjectHandle &a, const QD3D12ObjectHandle &b) noexcept
+{
+ return a.index == b.index && a.generation == b.generation;
+}
+
+inline bool operator!=(const QD3D12ObjectHandle &a, const QD3D12ObjectHandle &b) noexcept
+{
+ return !(a == b);
+}
+
+template<typename T>
+struct QD3D12ObjectPool
+{
+ void create(const char *debugName = "")
+ {
+ this->debugName = debugName;
+ Q_ASSERT(data.isEmpty());
+ data.append(Data()); // index 0 is always invalid
+ }
+
+ void destroy() {
+ int leakCount = 0; // will nicely destroy everything here, but warn about it if enabled
+ for (Data &d : data) {
+ if (d.object.has_value()) {
+ leakCount += 1;
+ d.object->releaseResources();
+ }
+ }
+ data.clear();
+#ifndef QT_NO_DEBUG
+ // debug builds: just do it always
+ static bool leakCheck = true;
+#else
+ // release builds: opt-in
+ static bool leakCheck = qEnvironmentVariableIntValue("QT_RHI_LEAK_CHECK");
+#endif
+ if (leakCheck) {
+ if (leakCount > 0) {
+ qWarning("QD3D12ObjectPool::destroy(): Pool %p '%s' had %d unreleased objects",
+ this, debugName, leakCount);
+ }
+ }
+ }
+
+ bool isValid(const QD3D12ObjectHandle &handle) const
+ {
+ return handle.index > 0
+ && handle.index < quint32(data.count())
+ && handle.generation > 0
+ && handle.generation == data[handle.index].generation
+ && data[handle.index].object.has_value();
+ }
+
+ T lookup(const QD3D12ObjectHandle &handle) const
+ {
+ return isValid(handle) ? *data[handle.index].object : T();
+ }
+
+ const T *lookupRef(const QD3D12ObjectHandle &handle) const
+ {
+ return isValid(handle) ? &*data[handle.index].object : nullptr;
+ }
+
+ T *lookupRef(const QD3D12ObjectHandle &handle)
+ {
+ return isValid(handle) ? &*data[handle.index].object : nullptr;
+ }
+
+ QD3D12ObjectHandle add(const T &object)
+ {
+ Q_ASSERT(!data.isEmpty());
+ const quint32 count = quint32(data.count());
+ quint32 index = 1; // index 0 is always invalid
+ for (; index < count; ++index) {
+ if (!data[index].object.has_value())
+ break;
+ }
+ if (index < count) {
+ data[index].object = object;
+ quint32 &generation = data[index].generation;
+ generation += 1u;
+ return { index, generation };
+ } else {
+ data.append({ object, 1 });
+ return { count, 1 };
+ }
+ }
+
+ void remove(const QD3D12ObjectHandle &handle)
+ {
+ if (T *object = lookupRef(handle)) {
+ object->releaseResources();
+ data[handle.index].object.reset();
+ }
+ }
+
+ const char *debugName;
+ struct Data {
+ std::optional<T> object;
+ quint32 generation = 0;
+ };
+ QVector<Data> data;
+};
+
+struct QD3D12Resource
+{
+ ID3D12Resource *resource;
+ D3D12_RESOURCE_STATES state;
+ D3D12_RESOURCE_DESC desc;
+ D3D12MA::Allocation *allocation;
+ void *cpuMapPtr;
+ enum { UavUsageRead = 0x01, UavUsageWrite = 0x02 };
+ int uavUsage;
+ bool owns;
+
+ // note that this assumes the allocation (if there is one) and the resource
+ // are separately releaseable, see D3D12MemAlloc docs
+ static QD3D12ObjectHandle addToPool(QD3D12ObjectPool<QD3D12Resource> *pool,
+ ID3D12Resource *resource,
+ D3D12_RESOURCE_STATES state,
+ D3D12MA::Allocation *allocation = nullptr,
+ void *cpuMapPtr = nullptr)
+ {
+ Q_ASSERT(resource);
+ return pool->add({ resource, state, resource->GetDesc(), allocation, cpuMapPtr, 0, true });
+ }
+
+ // for QRhiTexture::createFrom() where the ID3D12Resource is not owned by us
+ static QD3D12ObjectHandle addNonOwningToPool(QD3D12ObjectPool<QD3D12Resource> *pool,
+ ID3D12Resource *resource,
+ D3D12_RESOURCE_STATES state)
+ {
+ Q_ASSERT(resource);
+ return pool->add({ resource, state, resource->GetDesc(), nullptr, nullptr, 0, false });
+ }
+
+ void releaseResources()
+ {
+ if (owns) {
+ // order matters: resource first, then the allocation
+ resource->Release();
+ if (allocation)
+ allocation->Release();
+ }
+ }
+};
+
+struct QD3D12Pipeline
+{
+ enum Type {
+ Graphics,
+ Compute
+ };
+ Type type;
+ ID3D12PipelineState *pso;
+
+ static QD3D12ObjectHandle addToPool(QD3D12ObjectPool<QD3D12Pipeline> *pool,
+ Type type,
+ ID3D12PipelineState *pso)
+ {
+ return pool->add({ type, pso });
+ }
+
+ void releaseResources()
+ {
+ pso->Release();
+ }
+};
+
+struct QD3D12RootSignature
{
- bool enableDebugLayer = false;
+ ID3D12RootSignature *rootSig;
+
+ static QD3D12ObjectHandle addToPool(QD3D12ObjectPool<QD3D12RootSignature> *pool,
+ ID3D12RootSignature *rootSig)
+ {
+ return pool->add({ rootSig });
+ }
+
+ void releaseResources()
+ {
+ rootSig->Release();
+ }
};
-struct Q_GUI_EXPORT QRhiD3D12NativeHandles : public QRhiNativeHandles
+struct QD3D12ReleaseQueue
{
- // to import a device
- void *dev = nullptr;
- int minimumFeatureLevel = 0;
- // to just specify the adapter to use, set these and leave dev set to null
- quint32 adapterLuidLow = 0;
- qint32 adapterLuidHigh = 0;
- // in addition, can specify the command queue to use
- void *commandQueue = nullptr;
+ void create(QD3D12ObjectPool<QD3D12Resource> *resourcePool,
+ QD3D12ObjectPool<QD3D12Pipeline> *pipelinePool,
+ QD3D12ObjectPool<QD3D12RootSignature> *rootSignaturePool)
+ {
+ this->resourcePool = resourcePool;
+ this->pipelinePool = pipelinePool;
+ this->rootSignaturePool = rootSignaturePool;
+ }
+
+ void deferredReleaseResource(const QD3D12ObjectHandle &handle);
+ void deferredReleaseResourceWithViews(const QD3D12ObjectHandle &handle,
+ QD3D12CpuDescriptorPool *pool,
+ const QD3D12Descriptor &viewsStart,
+ int viewCount);
+ void deferredReleasePipeline(const QD3D12ObjectHandle &handle);
+ void deferredReleaseRootSignature(const QD3D12ObjectHandle &handle);
+ void deferredReleaseCallback(std::function<void(void*)> callback, void *userData);
+ void deferredReleaseResourceAndAllocation(ID3D12Resource *resource,
+ D3D12MA::Allocation *allocation);
+ void deferredReleaseDescriptorHeap(ID3D12DescriptorHeap *heap);
+ void deferredReleaseViews(QD3D12CpuDescriptorPool *pool,
+ const QD3D12Descriptor &viewsStart,
+ int viewCount);
+
+ void activatePendingDeferredReleaseRequests(int frameSlot);
+ void executeDeferredReleases(int frameSlot, bool forced = false);
+ void releaseAll();
+
+ struct DeferredReleaseEntry {
+ enum Type {
+ Resource,
+ Pipeline,
+ RootSignature,
+ Callback,
+ ResourceAndAllocation,
+ DescriptorHeap,
+ Views
+ };
+ Type type = Resource;
+ std::optional<int> frameSlotToBeReleasedIn;
+ QD3D12ObjectHandle handle;
+ QD3D12CpuDescriptorPool *poolForViews = nullptr;
+ QD3D12Descriptor viewsStart;
+ int viewCount = 0;
+ std::function<void(void*)> callback = nullptr;
+ void *callbackUserData = nullptr;
+ QPair<ID3D12Resource *, D3D12MA::Allocation *> resourceAndAllocation = {};
+ ID3D12DescriptorHeap *descriptorHeap = nullptr;
+ };
+ QVector<DeferredReleaseEntry> queue;
+ QD3D12ObjectPool<QD3D12Resource> *resourcePool = nullptr;
+ QD3D12ObjectPool<QD3D12Pipeline> *pipelinePool = nullptr;
+ QD3D12ObjectPool<QD3D12RootSignature> *rootSignaturePool = nullptr;
};
-struct Q_GUI_EXPORT QRhiD3D12CommandBufferNativeHandles : public QRhiNativeHandles
+struct QD3D12CommandBuffer;
+
+struct QD3D12ResourceBarrierGenerator
{
- void *commandList = nullptr; // ID3D12GraphicsCommandList
+ static const int PREALLOC = 16;
+
+ void create(QD3D12ObjectPool<QD3D12Resource> *resourcePool)
+ {
+ this->resourcePool = resourcePool;
+ }
+
+ void addTransitionBarrier(const QD3D12ObjectHandle &resourceHandle, D3D12_RESOURCE_STATES stateAfter);
+ void enqueueBufferedTransitionBarriers(QD3D12CommandBuffer *cbD);
+ void enqueueSubresourceTransitionBarrier(QD3D12CommandBuffer *cbD,
+ const QD3D12ObjectHandle &resourceHandle,
+ UINT subresource,
+ D3D12_RESOURCE_STATES stateBefore,
+ D3D12_RESOURCE_STATES stateAfter);
+ void enqueueUavBarrier(QD3D12CommandBuffer *cbD, const QD3D12ObjectHandle &resourceHandle);
+
+ struct TransitionResourceBarrier {
+ QD3D12ObjectHandle resourceHandle;
+ D3D12_RESOURCE_STATES stateBefore;
+ D3D12_RESOURCE_STATES stateAfter;
+ };
+ QVarLengthArray<TransitionResourceBarrier, PREALLOC> transitionResourceBarriers;
+ QD3D12ObjectPool<QD3D12Resource> *resourcePool = nullptr;
+};
+
+struct QD3D12ShaderBytecodeCache
+{
+ struct Shader {
+ Shader() = default;
+ Shader(const QByteArray &bytecode, const QShader::NativeResourceBindingMap &rbm)
+ : bytecode(bytecode), nativeResourceBindingMap(rbm)
+ { }
+ QByteArray bytecode;
+ QShader::NativeResourceBindingMap nativeResourceBindingMap;
+ };
+
+ QHash<QRhiShaderStage, Shader> data;
+
+ void insertWithCapacityLimit(const QRhiShaderStage &key, const Shader &s);
+};
+
+struct QD3D12ShaderVisibleDescriptorHeap
+{
+ bool create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE type, quint32 perFrameDescriptorCount);
+ void destroy();
+ void destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue);
+
+ QD3D12DescriptorHeap heap;
+ QD3D12DescriptorHeap perFrameHeapSlice[QD3D12_FRAMES_IN_FLIGHT];
+};
+
+// wrap foreign struct so we can legally supply equality operators and qHash:
+struct Q_D3D12_SAMPLER_DESC
+{
+ D3D12_SAMPLER_DESC desc;
+
+ friend bool operator==(const Q_D3D12_SAMPLER_DESC &lhs, const Q_D3D12_SAMPLER_DESC &rhs) noexcept
+ {
+ return lhs.desc.Filter == rhs.desc.Filter
+ && lhs.desc.AddressU == rhs.desc.AddressU
+ && lhs.desc.AddressV == rhs.desc.AddressV
+ && lhs.desc.AddressW == rhs.desc.AddressW
+ && lhs.desc.MipLODBias == rhs.desc.MipLODBias
+ && lhs.desc.MaxAnisotropy == rhs.desc.MaxAnisotropy
+ && lhs.desc.ComparisonFunc == rhs.desc.ComparisonFunc
+ // BorderColor is never used, skip it
+ && lhs.desc.MinLOD == rhs.desc.MinLOD
+ && lhs.desc.MaxLOD == rhs.desc.MaxLOD;
+ }
+
+ friend bool operator!=(const Q_D3D12_SAMPLER_DESC &lhs, const Q_D3D12_SAMPLER_DESC &rhs) noexcept
+ {
+ return !(lhs == rhs);
+ }
+
+ friend size_t qHash(const Q_D3D12_SAMPLER_DESC &key, size_t seed = 0) noexcept
+ {
+ QtPrivate::QHashCombine hash;
+ seed = hash(seed, key.desc.Filter);
+ seed = hash(seed, key.desc.AddressU);
+ seed = hash(seed, key.desc.AddressV);
+ seed = hash(seed, key.desc.AddressW);
+ seed = hash(seed, key.desc.MipLODBias);
+ seed = hash(seed, key.desc.MaxAnisotropy);
+ seed = hash(seed, key.desc.ComparisonFunc);
+ // BorderColor is never used, skip it
+ seed = hash(seed, key.desc.MinLOD);
+ seed = hash(seed, key.desc.MaxLOD);
+ return seed;
+ }
+};
+
+struct QD3D12SamplerManager
+{
+ const quint32 MAX_SAMPLERS = 512;
+
+ bool create(ID3D12Device *device);
+ void destroy();
+
+ QD3D12Descriptor getShaderVisibleDescriptor(const D3D12_SAMPLER_DESC &desc);
+
+ ID3D12Device *device = nullptr;
+ QD3D12ShaderVisibleDescriptorHeap shaderVisibleSamplerHeap;
+ QHash<Q_D3D12_SAMPLER_DESC, QD3D12Descriptor> gpuMap;
+};
+
+enum QD3D12Stage { VS = 0, HS, DS, GS, PS, CS };
+
+static inline QD3D12Stage qd3d12_stage(QRhiShaderStage::Type type)
+{
+ switch (type) {
+ case QRhiShaderStage::Vertex:
+ return VS;
+ case QRhiShaderStage::TessellationControl:
+ return HS;
+ case QRhiShaderStage::TessellationEvaluation:
+ return DS;
+ case QRhiShaderStage::Geometry:
+ return GS;
+ case QRhiShaderStage::Fragment:
+ return PS;
+ case QRhiShaderStage::Compute:
+ return CS;
+ }
+ Q_UNREACHABLE_RETURN(VS);
+}
+
+static inline D3D12_SHADER_VISIBILITY qd3d12_stageToVisibility(QD3D12Stage s)
+{
+ switch (s) {
+ case VS:
+ return D3D12_SHADER_VISIBILITY_VERTEX;
+ case HS:
+ return D3D12_SHADER_VISIBILITY_HULL;
+ case DS:
+ return D3D12_SHADER_VISIBILITY_DOMAIN;
+ case GS:
+ return D3D12_SHADER_VISIBILITY_GEOMETRY;
+ case PS:
+ return D3D12_SHADER_VISIBILITY_PIXEL;
+ case CS:
+ return D3D12_SHADER_VISIBILITY_ALL;
+ }
+ Q_UNREACHABLE_RETURN(D3D12_SHADER_VISIBILITY_ALL);
+}
+
+static inline QRhiShaderResourceBinding::StageFlag qd3d12_stageToSrb(QD3D12Stage s)
+{
+ switch (s) {
+ case VS:
+ return QRhiShaderResourceBinding::VertexStage;
+ case HS:
+ return QRhiShaderResourceBinding::TessellationControlStage;
+ case DS:
+ return QRhiShaderResourceBinding::TessellationEvaluationStage;
+ case GS:
+ return QRhiShaderResourceBinding::GeometryStage;
+ case PS:
+ return QRhiShaderResourceBinding::FragmentStage;
+ case CS:
+ return QRhiShaderResourceBinding::ComputeStage;
+ }
+ Q_UNREACHABLE_RETURN(QRhiShaderResourceBinding::VertexStage);
+}
+
+struct QD3D12ShaderStageData
+{
+ bool valid = false; // to allow simple arrays where unused stages are indicated by !valid
+ QD3D12Stage stage = VS;
+ QShader::NativeResourceBindingMap nativeResourceBindingMap;
+};
+
+struct QD3D12ShaderResourceBindings;
+
+struct QD3D12ShaderResourceVisitor
+{
+ enum StorageOp { Load = 0, Store, LoadStore };
+
+ QD3D12ShaderResourceVisitor(const QD3D12ShaderResourceBindings *srb,
+ const QD3D12ShaderStageData *stageData,
+ int stageCount)
+ : srb(srb),
+ stageData(stageData),
+ stageCount(stageCount)
+ {
+ }
+
+ std::function<void(QD3D12Stage, const QRhiShaderResourceBinding::Data::UniformBufferData &, int, int)> uniformBuffer = nullptr;
+ std::function<void(QD3D12Stage, const QRhiShaderResourceBinding::TextureAndSampler &, int)> texture = nullptr;
+ std::function<void(QD3D12Stage, const QRhiShaderResourceBinding::TextureAndSampler &, int)> sampler = nullptr;
+ std::function<void(QD3D12Stage, const QRhiShaderResourceBinding::Data::StorageImageData &, StorageOp, int)> storageImage = nullptr;
+ std::function<void(QD3D12Stage, const QRhiShaderResourceBinding::Data::StorageBufferData &, StorageOp, int)> storageBuffer = nullptr;
+
+ void visit();
+
+ const QD3D12ShaderResourceBindings *srb;
+ const QD3D12ShaderStageData *stageData;
+ int stageCount;
+};
+
+struct QD3D12Readback
+{
+ // common
+ int frameSlot = -1;
+ QRhiReadbackResult *result = nullptr;
+ QD3D12StagingArea staging;
+ quint32 byteSize = 0;
+ // textures
+ quint32 bytesPerLine = 0;
+ QSize pixelSize;
+ QRhiTexture::Format format = QRhiTexture::UnknownFormat;
+ quint32 stagingRowPitch = 0;
+};
+
+struct QD3D12MipmapGenerator
+{
+ bool create(QRhiD3D12 *rhiD);
+ void destroy();
+ void generate(QD3D12CommandBuffer *cbD, const QD3D12ObjectHandle &textureHandle);
+
+ QRhiD3D12 *rhiD;
+ QD3D12ObjectHandle rootSigHandle;
+ QD3D12ObjectHandle pipelineHandle;
+};
+
+struct QD3D12MemoryAllocator
+{
+ bool create(ID3D12Device *device, IDXGIAdapter1 *adapter);
+ void destroy();
+
+ HRESULT createResource(D3D12_HEAP_TYPE heapType,
+ const D3D12_RESOURCE_DESC *resourceDesc,
+ D3D12_RESOURCE_STATES initialState,
+ const D3D12_CLEAR_VALUE *optimizedClearValue,
+ D3D12MA::Allocation **maybeAllocation,
+ REFIID riidResource,
+ void **ppvResource);
+
+ void getBudget(D3D12MA::Budget *localBudget, D3D12MA::Budget *nonLocalBudget);
+
+ bool isUsingD3D12MA() const { return allocator != nullptr; }
+
+ ID3D12Device *device = nullptr;
+ D3D12MA::Allocator *allocator = nullptr;
+};
+
+struct QD3D12Buffer : public QRhiBuffer
+{
+ QD3D12Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
+ ~QD3D12Buffer();
+
+ void destroy() override;
+ bool create() override;
+ QRhiBuffer::NativeBuffer nativeBuffer() override;
+ char *beginFullDynamicBufferUpdateForCurrentFrame() override;
+ void endFullDynamicBufferUpdateForCurrentFrame() override;
+
+ void executeHostWritesForFrameSlot(int frameSlot);
+
+ QD3D12ObjectHandle handles[QD3D12_FRAMES_IN_FLIGHT] = {};
+ struct HostWrite {
+ quint32 offset;
+ QRhiBufferData data;
+ };
+ QVarLengthArray<HostWrite, 16> pendingHostWrites[QD3D12_FRAMES_IN_FLIGHT];
+ friend class QRhiD3D12;
+ friend struct QD3D12CommandBuffer;
+};
+
+struct QD3D12RenderBuffer : public QRhiRenderBuffer
+{
+ QD3D12RenderBuffer(QRhiImplementation *rhi,
+ Type type,
+ const QSize &pixelSize,
+ int sampleCount,
+ Flags flags,
+ QRhiTexture::Format backingFormatHint);
+ ~QD3D12RenderBuffer();
+ void destroy() override;
+ bool create() override;
+ QRhiTexture::Format backingFormat() const override;
+
+ static const DXGI_FORMAT DS_FORMAT = DXGI_FORMAT_D24_UNORM_S8_UINT;
+
+ QD3D12ObjectHandle handle;
+ QD3D12Descriptor rtv;
+ QD3D12Descriptor dsv;
+ DXGI_FORMAT dxgiFormat;
+ DXGI_SAMPLE_DESC sampleDesc;
+ uint generation = 0;
+ friend class QRhiD3D12;
+};
+
+struct QD3D12Texture : public QRhiTexture
+{
+ QD3D12Texture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
+ int arraySize, int sampleCount, Flags flags);
+ ~QD3D12Texture();
+ void destroy() override;
+ bool create() override;
+ bool createFrom(NativeTexture src) override;
+ NativeTexture nativeTexture() override;
+ void setNativeLayout(int layout) override;
+
+ bool prepareCreate(QSize *adjustedSize = nullptr);
+ bool finishCreate();
+
+ QD3D12ObjectHandle handle;
+ QD3D12Descriptor srv;
+ DXGI_FORMAT dxgiFormat;
+ DXGI_FORMAT srvFormat;
+ DXGI_FORMAT rtFormat; // RTV/DSV/UAV
+ uint mipLevelCount;
+ DXGI_SAMPLE_DESC sampleDesc;
+ uint generation = 0;
+ friend class QRhiD3D12;
+ friend struct QD3D12CommandBuffer;
+};
+
+struct QD3D12Sampler : public QRhiSampler
+{
+ QD3D12Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
+ AddressMode u, AddressMode v, AddressMode w);
+ ~QD3D12Sampler();
+ void destroy() override;
+ bool create() override;
+
+ QD3D12Descriptor lookupOrCreateShaderVisibleDescriptor();
+
+ D3D12_SAMPLER_DESC desc = {};
+ QD3D12Descriptor shaderVisibleDescriptor;
+};
+
+struct QD3D12RenderPassDescriptor : public QRhiRenderPassDescriptor
+{
+ QD3D12RenderPassDescriptor(QRhiImplementation *rhi);
+ ~QD3D12RenderPassDescriptor();
+ void destroy() override;
+ bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
+ QVector<quint32> serializedFormat() const override;
+
+ void updateSerializedFormat();
+
+ static const int MAX_COLOR_ATTACHMENTS = 8;
+ int colorAttachmentCount = 0;
+ bool hasDepthStencil = false;
+ int colorFormat[MAX_COLOR_ATTACHMENTS];
+ int dsFormat;
+ QVector<quint32> serializedFormatData;
+};
+
+struct QD3D12RenderTargetData
+{
+ QD3D12RenderTargetData(QRhiImplementation *) { }
+
+ QD3D12RenderPassDescriptor *rp = nullptr;
+ QSize pixelSize;
+ float dpr = 1;
+ int sampleCount = 1;
+ int colorAttCount = 0;
+ int dsAttCount = 0;
+ QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList;
+ static const int MAX_COLOR_ATTACHMENTS = QD3D12RenderPassDescriptor::MAX_COLOR_ATTACHMENTS;
+ D3D12_CPU_DESCRIPTOR_HANDLE rtv[MAX_COLOR_ATTACHMENTS];
+ D3D12_CPU_DESCRIPTOR_HANDLE dsv;
+};
+
+struct QD3D12SwapChainRenderTarget : public QRhiSwapChainRenderTarget
+{
+ QD3D12SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
+ ~QD3D12SwapChainRenderTarget();
+ void destroy() override;
+
+ QSize pixelSize() const override;
+ float devicePixelRatio() const override;
+ int sampleCount() const override;
+
+ QD3D12RenderTargetData d;
+};
+
+struct QD3D12TextureRenderTarget : public QRhiTextureRenderTarget
+{
+ QD3D12TextureRenderTarget(QRhiImplementation *rhi,
+ const QRhiTextureRenderTargetDescription &desc,
+ Flags flags);
+ ~QD3D12TextureRenderTarget();
+ void destroy() override;
+
+ QSize pixelSize() const override;
+ float devicePixelRatio() const override;
+ int sampleCount() const override;
+
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
+ bool create() override;
+
+ QD3D12RenderTargetData d;
+ bool ownsRtv[QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS];
+ QD3D12Descriptor rtv[QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS];
+ bool ownsDsv = false;
+ QD3D12Descriptor dsv;
+ friend class QRhiD3D12;
+};
+
+struct QD3D12ShaderResourceBindings : public QRhiShaderResourceBindings
+{
+ QD3D12ShaderResourceBindings(QRhiImplementation *rhi);
+ ~QD3D12ShaderResourceBindings();
+ void destroy() override;
+ bool create() override;
+ void updateResources(UpdateFlags flags) override;
+
+ QD3D12ObjectHandle createRootSignature(const QD3D12ShaderStageData *stageData, int stageCount);
+
+ struct VisitorData {
+ QVarLengthArray<D3D12_ROOT_PARAMETER1, 2> cbParams[6];
+
+ D3D12_ROOT_PARAMETER1 srvTables[6] = {};
+ QVarLengthArray<D3D12_DESCRIPTOR_RANGE1, 4> srvRanges[6];
+ quint32 currentSrvRangeOffset[6] = {};
+
+ QVarLengthArray<D3D12_ROOT_PARAMETER1, 4> samplerTables[6];
+ std::array<D3D12_DESCRIPTOR_RANGE1, 16> samplerRanges[6] = {};
+ int samplerRangeHeads[6] = {};
+
+ D3D12_ROOT_PARAMETER1 uavTables[6] = {};
+ QVarLengthArray<D3D12_DESCRIPTOR_RANGE1, 4> uavRanges[6];
+ quint32 currentUavRangeOffset[6] = {};
+ } visitorData;
+
+
+ void visitUniformBuffer(QD3D12Stage s,
+ const QRhiShaderResourceBinding::Data::UniformBufferData &d,
+ int shaderRegister,
+ int binding);
+ void visitTexture(QD3D12Stage s,
+ const QRhiShaderResourceBinding::TextureAndSampler &d,
+ int shaderRegister);
+ void visitSampler(QD3D12Stage s,
+ const QRhiShaderResourceBinding::TextureAndSampler &d,
+ int shaderRegister);
+ void visitStorageBuffer(QD3D12Stage s,
+ const QRhiShaderResourceBinding::Data::StorageBufferData &d,
+ QD3D12ShaderResourceVisitor::StorageOp op,
+ int shaderRegister);
+ void visitStorageImage(QD3D12Stage s,
+ const QRhiShaderResourceBinding::Data::StorageImageData &d,
+ QD3D12ShaderResourceVisitor::StorageOp op,
+ int shaderRegister);
+
+ bool hasDynamicOffset = false;
+ uint generation = 0;
+
+ friend class QRhiD3D12;
+ friend struct QD3D12ShaderResourceVisitor;
+};
+
+struct QD3D12GraphicsPipeline : public QRhiGraphicsPipeline
+{
+ QD3D12GraphicsPipeline(QRhiImplementation *rhi);
+ ~QD3D12GraphicsPipeline();
+ void destroy() override;
+ bool create() override;
+
+ QD3D12ObjectHandle handle;
+ QD3D12ObjectHandle rootSigHandle;
+ std::array<QD3D12ShaderStageData, 5> stageData;
+ D3D12_PRIMITIVE_TOPOLOGY topology;
+ UINT viewInstanceMask = 0;
+ uint generation = 0;
+ friend class QRhiD3D12;
+};
+
+struct QD3D12ComputePipeline : public QRhiComputePipeline
+{
+ QD3D12ComputePipeline(QRhiImplementation *rhi);
+ ~QD3D12ComputePipeline();
+ void destroy() override;
+ bool create() override;
+
+ QD3D12ObjectHandle handle;
+ QD3D12ObjectHandle rootSigHandle;
+ QD3D12ShaderStageData stageData;
+ uint generation = 0;
+ friend class QRhiD3D12;
+};
+
+struct QD3D12CommandBuffer : public QRhiCommandBuffer
+{
+ QD3D12CommandBuffer(QRhiImplementation *rhi);
+ ~QD3D12CommandBuffer();
+ void destroy() override;
+
+ const QRhiNativeHandles *nativeHandles();
+
+ ID3D12GraphicsCommandList1 *cmdList = nullptr; // not owned
+ QRhiD3D12CommandBufferNativeHandles nativeHandlesStruct;
+
+ enum PassType {
+ NoPass,
+ RenderPass,
+ ComputePass
+ };
+
+ void resetState()
+ {
+ recordingPass = NoPass;
+ currentTarget = nullptr;
+
+ resetPerPassState();
+ }
+
+ void resetPerPassState()
+ {
+ currentGraphicsPipeline = nullptr;
+ currentComputePipeline = nullptr;
+ currentPipelineGeneration = 0;
+ currentGraphicsSrb = nullptr;
+ currentComputeSrb = nullptr;
+ currentSrbGeneration = 0;
+ currentIndexBuffer = {};
+ currentIndexOffset = 0;
+ currentIndexFormat = DXGI_FORMAT_R16_UINT;
+ currentVertexBuffers = {};
+ currentVertexOffsets = {};
+ }
+
+ // per-frame
+ PassType recordingPass;
+ QRhiRenderTarget *currentTarget;
+
+ // per-pass
+ QD3D12GraphicsPipeline *currentGraphicsPipeline;
+ QD3D12ComputePipeline *currentComputePipeline;
+ uint currentPipelineGeneration;
+ QRhiShaderResourceBindings *currentGraphicsSrb;
+ QRhiShaderResourceBindings *currentComputeSrb;
+ uint currentSrbGeneration;
+ QD3D12ObjectHandle currentIndexBuffer;
+ quint32 currentIndexOffset;
+ DXGI_FORMAT currentIndexFormat;
+ std::array<QD3D12ObjectHandle, D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> currentVertexBuffers;
+ std::array<quint32, D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> currentVertexOffsets;
+
+ // global
+ double lastGpuTime = 0;
+
+ // per-setShaderResources
+ struct VisitorData {
+ QVarLengthArray<QPair<QD3D12ObjectHandle, quint32>, 4> cbufs[6];
+ QVarLengthArray<QD3D12Descriptor, 8> srvs[6];
+ QVarLengthArray<QD3D12Descriptor, 8> samplers[6];
+ QVarLengthArray<QPair<QD3D12ObjectHandle, D3D12_UNORDERED_ACCESS_VIEW_DESC>, 4> uavs[6];
+ } visitorData;
+
+ void visitUniformBuffer(QD3D12Stage s,
+ const QRhiShaderResourceBinding::Data::UniformBufferData &d,
+ int shaderRegister,
+ int binding,
+ int dynamicOffsetCount,
+ const QRhiCommandBuffer::DynamicOffset *dynamicOffsets);
+ void visitTexture(QD3D12Stage s,
+ const QRhiShaderResourceBinding::TextureAndSampler &d,
+ int shaderRegister);
+ void visitSampler(QD3D12Stage s,
+ const QRhiShaderResourceBinding::TextureAndSampler &d,
+ int shaderRegister);
+ void visitStorageBuffer(QD3D12Stage s,
+ const QRhiShaderResourceBinding::Data::StorageBufferData &d,
+ QD3D12ShaderResourceVisitor::StorageOp op,
+ int shaderRegister);
+ void visitStorageImage(QD3D12Stage s,
+ const QRhiShaderResourceBinding::Data::StorageImageData &d,
+ QD3D12ShaderResourceVisitor::StorageOp op,
+ int shaderRegister);
+};
+
+struct QD3D12SwapChain : public QRhiSwapChain
+{
+ QD3D12SwapChain(QRhiImplementation *rhi);
+ ~QD3D12SwapChain();
+ void destroy() override;
+
+ QRhiCommandBuffer *currentFrameCommandBuffer() override;
+ QRhiRenderTarget *currentFrameRenderTarget() override;
+ QRhiRenderTarget *currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override;
+
+ QSize surfacePixelSize() override;
+ bool isFormatSupported(Format f) override;
+ QRhiSwapChainHdrInfo hdrInfo() override;
+
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
+ bool createOrResize() override;
+
+ void releaseBuffers();
+ void waitCommandCompletionForFrameSlot(int frameSlot);
+ void addCommandCompletionSignalForCurrentFrameSlot();
+ void chooseFormats();
+
+ QWindow *window = nullptr;
+ IDXGISwapChain1 *sourceSwapChain1 = nullptr;
+ IDXGISwapChain3 *swapChain = nullptr;
+ QSize pixelSize;
+ UINT swapInterval = 1;
+ UINT swapChainFlags = 0;
+ BOOL stereo = false;
+ DXGI_FORMAT colorFormat;
+ DXGI_FORMAT srgbAdjustedColorFormat;
+ DXGI_COLOR_SPACE_TYPE hdrColorSpace;
+ IDCompositionTarget *dcompTarget = nullptr;
+ IDCompositionVisual *dcompVisual = nullptr;
+ static const UINT BUFFER_COUNT = 3;
+ QD3D12ObjectHandle colorBuffers[BUFFER_COUNT];
+ QD3D12Descriptor rtvs[BUFFER_COUNT];
+ QD3D12Descriptor rtvsRight[BUFFER_COUNT];
+ DXGI_SAMPLE_DESC sampleDesc;
+ QD3D12ObjectHandle msaaBuffers[BUFFER_COUNT];
+ QD3D12Descriptor msaaRtvs[BUFFER_COUNT];
+ QD3D12RenderBuffer *ds = nullptr;
+ UINT currentBackBufferIndex = 0;
+ QD3D12SwapChainRenderTarget rtWrapper;
+ QD3D12SwapChainRenderTarget rtWrapperRight;
+ QD3D12CommandBuffer cbWrapper;
+
+ struct FrameResources {
+ ID3D12Fence *fence = nullptr;
+ HANDLE fenceEvent = nullptr;
+ UINT64 fenceCounter = 0;
+ ID3D12GraphicsCommandList1 *cmdList = nullptr;
+ } frameRes[QD3D12_FRAMES_IN_FLIGHT];
+
+ int currentFrameSlot = 0; // index in frameRes
+};
+
+template<typename T, D3D12_PIPELINE_STATE_SUBOBJECT_TYPE Type>
+struct alignas(void*) QD3D12PipelineStateSubObject
+{
+ D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type = Type;
+ T object = {};
+};
+
+class QRhiD3D12 : public QRhiImplementation
+{
+public:
+ // 16MB * QD3D12_FRAMES_IN_FLIGHT; buffer and texture upload staging data that
+ // gets no space from this will get their own temporary staging areas.
+ static const quint32 SMALL_STAGING_AREA_BYTES_PER_FRAME = 16 * 1024 * 1024;
+
+ static const quint32 SHADER_VISIBLE_CBV_SRV_UAV_HEAP_PER_FRAME_START_SIZE = 16384;
+
+ QRhiD3D12(QRhiD3D12InitParams *params, QRhiD3D12NativeHandles *importDevice = nullptr);
+
+ bool create(QRhi::Flags flags) override;
+ void destroy() override;
+
+ QRhiGraphicsPipeline *createGraphicsPipeline() override;
+ QRhiComputePipeline *createComputePipeline() override;
+ QRhiShaderResourceBindings *createShaderResourceBindings() override;
+ QRhiBuffer *createBuffer(QRhiBuffer::Type type,
+ QRhiBuffer::UsageFlags usage,
+ quint32 size) override;
+ QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
+ const QSize &pixelSize,
+ int sampleCount,
+ QRhiRenderBuffer::Flags flags,
+ QRhiTexture::Format backingFormatHint) override;
+ QRhiTexture *createTexture(QRhiTexture::Format format,
+ const QSize &pixelSize,
+ int depth,
+ int arraySize,
+ int sampleCount,
+ QRhiTexture::Flags flags) override;
+ QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
+ QRhiSampler::Filter minFilter,
+ QRhiSampler::Filter mipmapMode,
+ QRhiSampler:: AddressMode u,
+ QRhiSampler::AddressMode v,
+ QRhiSampler::AddressMode w) override;
+
+ QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
+ QRhiTextureRenderTarget::Flags flags) override;
+
+ QRhiSwapChain *createSwapChain() override;
+ QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
+ QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
+ QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
+ QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
+ QRhi::FrameOpResult finish() override;
+
+ void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+
+ void beginPass(QRhiCommandBuffer *cb,
+ QRhiRenderTarget *rt,
+ const QColor &colorClearValue,
+ const QRhiDepthStencilClearValue &depthStencilClearValue,
+ QRhiResourceUpdateBatch *resourceUpdates,
+ QRhiCommandBuffer::BeginPassFlags flags) override;
+ void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+
+ void setGraphicsPipeline(QRhiCommandBuffer *cb,
+ QRhiGraphicsPipeline *ps) override;
+
+ void setShaderResources(QRhiCommandBuffer *cb,
+ QRhiShaderResourceBindings *srb,
+ int dynamicOffsetCount,
+ const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
+
+ void setVertexInput(QRhiCommandBuffer *cb,
+ int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
+ QRhiBuffer *indexBuf, quint32 indexOffset,
+ QRhiCommandBuffer::IndexFormat indexFormat) override;
+
+ void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
+ void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
+ void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
+ void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
+
+ void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
+ quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
+
+ void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
+ quint32 instanceCount, quint32 firstIndex,
+ qint32 vertexOffset, quint32 firstInstance) override;
+
+ void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
+ void debugMarkEnd(QRhiCommandBuffer *cb) override;
+ void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
+
+ void beginComputePass(QRhiCommandBuffer *cb,
+ QRhiResourceUpdateBatch *resourceUpdates,
+ QRhiCommandBuffer::BeginPassFlags flags) override;
+ void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+ void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
+ void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
+
+ const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
+ void beginExternal(QRhiCommandBuffer *cb) override;
+ void endExternal(QRhiCommandBuffer *cb) override;
+ double lastCompletedGpuTime(QRhiCommandBuffer *cb) override;
+
+ QList<int> supportedSampleCounts() const override;
+ int ubufAlignment() const override;
+ bool isYUpInFramebuffer() const override;
+ bool isYUpInNDC() const override;
+ bool isClipDepthZeroToOne() const override;
+ QMatrix4x4 clipSpaceCorrMatrix() const override;
+ bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
+ bool isFeatureSupported(QRhi::Feature feature) const override;
+ int resourceLimit(QRhi::ResourceLimit limit) const override;
+ const QRhiNativeHandles *nativeHandles() override;
+ QRhiDriverInfo driverInfo() const override;
+ QRhiStats statistics() override;
+ bool makeThreadLocalNativeContextCurrent() override;
+ void releaseCachedResources() override;
+ bool isDeviceLost() const override;
+
+ QByteArray pipelineCacheData() override;
+ void setPipelineCacheData(const QByteArray &data) override;
+
+ void waitGpu();
+ DXGI_SAMPLE_DESC effectiveSampleDesc(int sampleCount, DXGI_FORMAT format) const;
+ bool ensureDirectCompositionDevice();
+ bool startCommandListForCurrentFrameSlot(ID3D12GraphicsCommandList1 **cmdList);
+ void enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates);
+ void finishActiveReadbacks(bool forced = false);
+ bool ensureShaderVisibleDescriptorHeapCapacity(QD3D12ShaderVisibleDescriptorHeap *h,
+ D3D12_DESCRIPTOR_HEAP_TYPE type,
+ int frameSlot,
+ quint32 neededDescriptorCount,
+ bool *gotNew);
+ void bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD);
+
+ bool debugLayer = false;
+ ID3D12Device2 *dev = nullptr;
+ D3D_FEATURE_LEVEL minimumFeatureLevel = D3D_FEATURE_LEVEL(0);
+ LUID adapterLuid = {};
+ bool importedDevice = false;
+ bool importedCommandQueue = false;
+ QRhi::Flags rhiFlags;
+ IDXGIFactory2 *dxgiFactory = nullptr;
+ bool supportsAllowTearing = false;
+ IDXGIAdapter1 *activeAdapter = nullptr;
+ QRhiDriverInfo driverInfoStruct;
+ QRhiD3D12NativeHandles nativeHandlesStruct;
+ bool deviceLost = false;
+ ID3D12CommandQueue *cmdQueue = nullptr;
+ ID3D12Fence *fullFence = nullptr;
+ HANDLE fullFenceEvent = nullptr;
+ UINT64 fullFenceCounter = 0;
+ ID3D12CommandAllocator *cmdAllocators[QD3D12_FRAMES_IN_FLIGHT] = {};
+ QD3D12MemoryAllocator vma;
+ QD3D12CpuDescriptorPool rtvPool;
+ QD3D12CpuDescriptorPool dsvPool;
+ QD3D12CpuDescriptorPool cbvSrvUavPool;
+ QD3D12ObjectPool<QD3D12Resource> resourcePool;
+ QD3D12ObjectPool<QD3D12Pipeline> pipelinePool;
+ QD3D12ObjectPool<QD3D12RootSignature> rootSignaturePool;
+ QD3D12ReleaseQueue releaseQueue;
+ QD3D12ResourceBarrierGenerator barrierGen;
+ QD3D12SamplerManager samplerMgr;
+ QD3D12MipmapGenerator mipmapGen;
+ QD3D12StagingArea smallStagingAreas[QD3D12_FRAMES_IN_FLIGHT];
+ QD3D12ShaderVisibleDescriptorHeap shaderVisibleCbvSrvUavHeap;
+ UINT64 timestampTicksPerSecond = 0;
+ QD3D12QueryHeap timestampQueryHeap;
+ QD3D12StagingArea timestampReadbackArea;
+ IDCompositionDevice *dcompDevice = nullptr;
+ QD3D12SwapChain *currentSwapChain = nullptr;
+ QSet<QD3D12SwapChain *> swapchains;
+ QD3D12ShaderBytecodeCache shaderBytecodeCache;
+ QVarLengthArray<QD3D12Readback, 4> activeReadbacks;
+ bool offscreenActive = false;
+ QD3D12CommandBuffer *offscreenCb[QD3D12_FRAMES_IN_FLIGHT] = {};
+
+ struct {
+ bool multiView = false;
+ bool textureViewFormat = false;
+ } caps;
};
QT_END_NAMESPACE
+#endif // __ID3D12Device2_INTERFACE_DEFINED__
+
#endif
diff --git a/src/gui/rhi/qrhid3d12_p_p.h b/src/gui/rhi/qrhid3d12_p_p.h
deleted file mode 100644
index dec217e771..0000000000
--- a/src/gui/rhi/qrhid3d12_p_p.h
+++ /dev/null
@@ -1,1194 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QRHID3D12_P_H
-#define QRHID3D12_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 "qrhid3d12_p.h"
-#include "qrhi_p_p.h"
-#include "qshaderdescription_p.h"
-#include <QWindow>
-#include <QBitArray>
-
-#include <optional>
-#include <array>
-
-#include <d3d12.h>
-#include <d3d12sdklayers.h>
-#include <dxgi1_6.h>
-#include <dcomp.h>
-
-#include "D3D12MemAlloc.h"
-
-QT_BEGIN_NAMESPACE
-
-static const int QD3D12_FRAMES_IN_FLIGHT = 2;
-
-class QRhiD3D12;
-
-struct QD3D12Descriptor
-{
- D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = {};
- D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = {};
-
- bool isValid() const { return cpuHandle.ptr != 0; }
-};
-
-struct QD3D12ReleaseQueue;
-
-struct QD3D12DescriptorHeap
-{
- bool isValid() const { return heap && capacity; }
- bool create(ID3D12Device *device,
- quint32 descriptorCount,
- D3D12_DESCRIPTOR_HEAP_TYPE heapType,
- D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags);
- void createWithExisting(const QD3D12DescriptorHeap &other,
- quint32 offsetInDescriptors,
- quint32 descriptorCount);
- void destroy();
- void destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue);
-
- QD3D12Descriptor get(quint32 count);
- QD3D12Descriptor at(quint32 index) const;
- quint32 remainingCapacity() const { return capacity - head; }
-
- QD3D12Descriptor incremented(const QD3D12Descriptor &descriptor, quint32 offsetInDescriptors) const
- {
- D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = descriptor.cpuHandle;
- cpuHandle.ptr += offsetInDescriptors * descriptorByteSize;
- D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle = descriptor.gpuHandle;
- if (gpuHandle.ptr)
- gpuHandle.ptr += offsetInDescriptors * descriptorByteSize;
- return { cpuHandle, gpuHandle };
- }
-
- ID3D12DescriptorHeap *heap = nullptr;
- quint32 capacity = 0;
- QD3D12Descriptor heapStart;
- quint32 head = 0;
- quint32 descriptorByteSize = 0;
- D3D12_DESCRIPTOR_HEAP_TYPE heapType;
- D3D12_DESCRIPTOR_HEAP_FLAGS heapFlags;
-};
-
-struct QD3D12CpuDescriptorPool
-{
- bool isValid() const { return !heaps.isEmpty(); }
- bool create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE heapType, const char *debugName = "");
- void destroy();
-
- QD3D12Descriptor allocate(quint32 count);
- void release(const QD3D12Descriptor &descriptor, quint32 count);
-
- static const int DESCRIPTORS_PER_HEAP = 256;
-
- struct HeapWithMap {
- QD3D12DescriptorHeap heap;
- QBitArray map;
- static HeapWithMap init(const QD3D12DescriptorHeap &heap, quint32 descriptorCount) {
- HeapWithMap result;
- result.heap = heap;
- result.map.resize(descriptorCount);
- return result;
- }
- };
-
- ID3D12Device *device;
- quint32 descriptorByteSize;
- QVector<HeapWithMap> heaps;
- const char *debugName;
-};
-
-struct QD3D12StagingArea
-{
- static const quint32 ALIGNMENT = D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT; // 512 so good enough both for cb and texdata
-
- struct Allocation {
- quint8 *p = nullptr;
- D3D12_GPU_VIRTUAL_ADDRESS gpuAddr = 0;
- ID3D12Resource *buffer = nullptr;
- quint32 bufferOffset = 0;
- bool isValid() const { return p != nullptr; }
- };
-
- bool isValid() const { return allocation && mem.isValid(); }
- bool create(QRhiD3D12 *rhi, quint32 capacity, D3D12_HEAP_TYPE heapType);
- void destroy();
- void destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue);
-
- Allocation get(quint32 byteSize);
-
- quint32 remainingCapacity() const
- {
- return capacity - head;
- }
-
- static quint32 allocSizeForArray(quint32 size, int count = 1)
- {
- return count * ((size + ALIGNMENT - 1) & ~(ALIGNMENT - 1));
- }
-
- Allocation mem;
- ID3D12Resource *resource = nullptr;
- D3D12MA::Allocation *allocation = nullptr;
- quint32 head;
- quint32 capacity;
-};
-
-struct QD3D12ObjectHandle
-{
- quint32 index = 0;
- quint32 generation = 0;
-
- // the default, null handle is guaranteed to give ObjectPool::isValid() == false
- bool isNull() const { return index == 0 && generation == 0; }
-};
-
-inline bool operator==(const QD3D12ObjectHandle &a, const QD3D12ObjectHandle &b) noexcept
-{
- return a.index == b.index && a.generation == b.generation;
-}
-
-inline bool operator!=(const QD3D12ObjectHandle &a, const QD3D12ObjectHandle &b) noexcept
-{
- return !(a == b);
-}
-
-template<typename T>
-struct QD3D12ObjectPool
-{
- void create(const char *debugName = "")
- {
- this->debugName = debugName;
- Q_ASSERT(data.isEmpty());
- data.append(Data()); // index 0 is always invalid
- }
-
- void destroy() {
- int leakCount = 0; // will nicely destroy everything here, but warn about it if enabled
- for (Data &d : data) {
- if (d.object.has_value()) {
- leakCount += 1;
- d.object->releaseResources();
- }
- }
- data.clear();
-#ifndef QT_NO_DEBUG
- // debug builds: just do it always
- static bool leakCheck = true;
-#else
- // release builds: opt-in
- static bool leakCheck = qEnvironmentVariableIntValue("QT_RHI_LEAK_CHECK");
-#endif
- if (leakCheck) {
- if (leakCount > 0) {
- qWarning("QD3D12ObjectPool::destroy(): Pool %p '%s' had %d unreleased objects",
- this, debugName, leakCount);
- }
- }
- }
-
- bool isValid(const QD3D12ObjectHandle &handle) const
- {
- return handle.index > 0
- && handle.index < quint32(data.count())
- && handle.generation > 0
- && handle.generation == data[handle.index].generation
- && data[handle.index].object.has_value();
- }
-
- T lookup(const QD3D12ObjectHandle &handle) const
- {
- return isValid(handle) ? *data[handle.index].object : T();
- }
-
- const T *lookupRef(const QD3D12ObjectHandle &handle) const
- {
- return isValid(handle) ? &*data[handle.index].object : nullptr;
- }
-
- T *lookupRef(const QD3D12ObjectHandle &handle)
- {
- return isValid(handle) ? &*data[handle.index].object : nullptr;
- }
-
- QD3D12ObjectHandle add(const T &object)
- {
- Q_ASSERT(!data.isEmpty());
- const quint32 count = quint32(data.count());
- quint32 index = 1; // index 0 is always invalid
- for (; index < count; ++index) {
- if (!data[index].object.has_value())
- break;
- }
- if (index < count) {
- data[index].object = object;
- quint32 &generation = data[index].generation;
- generation += 1u;
- return { index, generation };
- } else {
- data.append({ object, 1 });
- return { count, 1 };
- }
- }
-
- void remove(const QD3D12ObjectHandle &handle)
- {
- if (T *object = lookupRef(handle)) {
- object->releaseResources();
- data[handle.index].object.reset();
- }
- }
-
- const char *debugName;
- struct Data {
- std::optional<T> object;
- quint32 generation = 0;
- };
- QVector<Data> data;
-};
-
-struct QD3D12Resource
-{
- ID3D12Resource *resource;
- D3D12_RESOURCE_STATES state;
- D3D12_RESOURCE_DESC desc;
- D3D12MA::Allocation *allocation;
- void *cpuMapPtr;
- enum { UavUsageRead = 0x01, UavUsageWrite = 0x02 };
- int uavUsage;
- bool owns;
-
- // note that this assumes the allocation (if there is one) and the resource
- // are separately releaseable, see D3D12MemAlloc docs
- static QD3D12ObjectHandle addToPool(QD3D12ObjectPool<QD3D12Resource> *pool,
- ID3D12Resource *resource,
- D3D12_RESOURCE_STATES state,
- D3D12MA::Allocation *allocation = nullptr,
- void *cpuMapPtr = nullptr)
- {
- Q_ASSERT(resource);
- return pool->add({ resource, state, resource->GetDesc(), allocation, cpuMapPtr, 0, true });
- }
-
- // for QRhiTexture::createFrom() where the ID3D12Resource is not owned by us
- static QD3D12ObjectHandle addNonOwningToPool(QD3D12ObjectPool<QD3D12Resource> *pool,
- ID3D12Resource *resource,
- D3D12_RESOURCE_STATES state)
- {
- Q_ASSERT(resource);
- return pool->add({ resource, state, resource->GetDesc(), nullptr, nullptr, 0, false });
- }
-
- void releaseResources()
- {
- if (owns) {
- // order matters: resource first, then the allocation
- resource->Release();
- if (allocation)
- allocation->Release();
- }
- }
-};
-
-struct QD3D12Pipeline
-{
- enum Type {
- Graphics,
- Compute
- };
- Type type;
- ID3D12PipelineState *pso;
-
- static QD3D12ObjectHandle addToPool(QD3D12ObjectPool<QD3D12Pipeline> *pool,
- Type type,
- ID3D12PipelineState *pso)
- {
- return pool->add({ type, pso });
- }
-
- void releaseResources()
- {
- pso->Release();
- }
-};
-
-struct QD3D12RootSignature
-{
- ID3D12RootSignature *rootSig;
-
- static QD3D12ObjectHandle addToPool(QD3D12ObjectPool<QD3D12RootSignature> *pool,
- ID3D12RootSignature *rootSig)
- {
- return pool->add({ rootSig });
- }
-
- void releaseResources()
- {
- rootSig->Release();
- }
-};
-
-struct QD3D12ReleaseQueue
-{
- void create(QD3D12ObjectPool<QD3D12Resource> *resourcePool,
- QD3D12ObjectPool<QD3D12Pipeline> *pipelinePool,
- QD3D12ObjectPool<QD3D12RootSignature> *rootSignaturePool)
- {
- this->resourcePool = resourcePool;
- this->pipelinePool = pipelinePool;
- this->rootSignaturePool = rootSignaturePool;
- }
-
- void deferredReleaseResource(const QD3D12ObjectHandle &handle);
- void deferredReleaseResourceWithViews(const QD3D12ObjectHandle &handle,
- QD3D12CpuDescriptorPool *pool,
- const QD3D12Descriptor &viewsStart,
- int viewCount);
- void deferredReleasePipeline(const QD3D12ObjectHandle &handle);
- void deferredReleaseRootSignature(const QD3D12ObjectHandle &handle);
- void deferredReleaseCallback(std::function<void(void*)> callback, void *userData);
- void deferredReleaseResourceAndAllocation(ID3D12Resource *resource,
- D3D12MA::Allocation *allocation);
- void deferredReleaseDescriptorHeap(ID3D12DescriptorHeap *heap);
- void deferredReleaseViews(QD3D12CpuDescriptorPool *pool,
- const QD3D12Descriptor &viewsStart,
- int viewCount);
-
- void activatePendingDeferredReleaseRequests(int frameSlot);
- void executeDeferredReleases(int frameSlot, bool forced = false);
- void releaseAll();
-
- struct DeferredReleaseEntry {
- enum Type {
- Resource,
- Pipeline,
- RootSignature,
- Callback,
- ResourceAndAllocation,
- DescriptorHeap,
- Views
- };
- Type type = Resource;
- std::optional<int> frameSlotToBeReleasedIn;
- QD3D12ObjectHandle handle;
- QD3D12CpuDescriptorPool *poolForViews = nullptr;
- QD3D12Descriptor viewsStart;
- int viewCount = 0;
- std::function<void(void*)> callback = nullptr;
- void *callbackUserData = nullptr;
- QPair<ID3D12Resource *, D3D12MA::Allocation *> resourceAndAllocation = {};
- ID3D12DescriptorHeap *descriptorHeap = nullptr;
- };
- QVector<DeferredReleaseEntry> queue;
- QD3D12ObjectPool<QD3D12Resource> *resourcePool = nullptr;
- QD3D12ObjectPool<QD3D12Pipeline> *pipelinePool = nullptr;
- QD3D12ObjectPool<QD3D12RootSignature> *rootSignaturePool = nullptr;
-};
-
-struct QD3D12CommandBuffer;
-
-struct QD3D12ResourceBarrierGenerator
-{
- static const int PREALLOC = 16;
-
- void create(QD3D12ObjectPool<QD3D12Resource> *resourcePool)
- {
- this->resourcePool = resourcePool;
- }
-
- void addTransitionBarrier(const QD3D12ObjectHandle &resourceHandle, D3D12_RESOURCE_STATES stateAfter);
- void enqueueBufferedTransitionBarriers(QD3D12CommandBuffer *cbD);
- void enqueueSubresourceTransitionBarrier(QD3D12CommandBuffer *cbD,
- const QD3D12ObjectHandle &resourceHandle,
- UINT subresource,
- D3D12_RESOURCE_STATES stateBefore,
- D3D12_RESOURCE_STATES stateAfter);
- void enqueueUavBarrier(QD3D12CommandBuffer *cbD, const QD3D12ObjectHandle &resourceHandle);
-
- struct TransitionResourceBarrier {
- QD3D12ObjectHandle resourceHandle;
- D3D12_RESOURCE_STATES stateBefore;
- D3D12_RESOURCE_STATES stateAfter;
- };
- QVarLengthArray<TransitionResourceBarrier, PREALLOC> transitionResourceBarriers;
- QD3D12ObjectPool<QD3D12Resource> *resourcePool = nullptr;
-};
-
-struct QD3D12ShaderBytecodeCache
-{
- struct Shader {
- Shader() = default;
- Shader(const QByteArray &bytecode, const QShader::NativeResourceBindingMap &rbm)
- : bytecode(bytecode), nativeResourceBindingMap(rbm)
- { }
- QByteArray bytecode;
- QShader::NativeResourceBindingMap nativeResourceBindingMap;
- };
-
- QHash<QRhiShaderStage, Shader> data;
-
- void insertWithCapacityLimit(const QRhiShaderStage &key, const Shader &s);
-};
-
-struct QD3D12ShaderVisibleDescriptorHeap
-{
- bool create(ID3D12Device *device, D3D12_DESCRIPTOR_HEAP_TYPE type, quint32 perFrameDescriptorCount);
- void destroy();
- void destroyWithDeferredRelease(QD3D12ReleaseQueue *releaseQueue);
-
- QD3D12DescriptorHeap heap;
- QD3D12DescriptorHeap perFrameHeapSlice[QD3D12_FRAMES_IN_FLIGHT];
-};
-
-// wrap foreign struct so we can legally supply equality operators and qHash:
-struct Q_D3D12_SAMPLER_DESC
-{
- D3D12_SAMPLER_DESC desc;
-
- friend bool operator==(const Q_D3D12_SAMPLER_DESC &lhs, const Q_D3D12_SAMPLER_DESC &rhs) noexcept
- {
- return lhs.desc.Filter == rhs.desc.Filter
- && lhs.desc.AddressU == rhs.desc.AddressU
- && lhs.desc.AddressV == rhs.desc.AddressV
- && lhs.desc.AddressW == rhs.desc.AddressW
- && lhs.desc.MipLODBias == rhs.desc.MipLODBias
- && lhs.desc.MaxAnisotropy == rhs.desc.MaxAnisotropy
- && lhs.desc.ComparisonFunc == rhs.desc.ComparisonFunc
- // BorderColor is never used, skip it
- && lhs.desc.MinLOD == rhs.desc.MinLOD
- && lhs.desc.MaxLOD == rhs.desc.MaxLOD;
- }
-
- friend bool operator!=(const Q_D3D12_SAMPLER_DESC &lhs, const Q_D3D12_SAMPLER_DESC &rhs) noexcept
- {
- return !(lhs == rhs);
- }
-
- friend size_t qHash(const Q_D3D12_SAMPLER_DESC &key, size_t seed = 0) noexcept
- {
- QtPrivate::QHashCombine hash;
- seed = hash(seed, key.desc.Filter);
- seed = hash(seed, key.desc.AddressU);
- seed = hash(seed, key.desc.AddressV);
- seed = hash(seed, key.desc.AddressW);
- seed = hash(seed, key.desc.MipLODBias);
- seed = hash(seed, key.desc.MaxAnisotropy);
- seed = hash(seed, key.desc.ComparisonFunc);
- // BorderColor is never used, skip it
- seed = hash(seed, key.desc.MinLOD);
- seed = hash(seed, key.desc.MaxLOD);
- return seed;
- }
-};
-
-struct QD3D12SamplerManager
-{
- const quint32 MAX_SAMPLERS = 512;
-
- bool create(ID3D12Device *device);
- void destroy();
-
- QD3D12Descriptor getShaderVisibleDescriptor(const D3D12_SAMPLER_DESC &desc);
-
- ID3D12Device *device = nullptr;
- QD3D12ShaderVisibleDescriptorHeap shaderVisibleSamplerHeap;
- QHash<Q_D3D12_SAMPLER_DESC, QD3D12Descriptor> gpuMap;
-};
-
-enum QD3D12Stage { VS = 0, HS, DS, GS, PS, CS };
-
-static inline QD3D12Stage qd3d12_stage(QRhiShaderStage::Type type)
-{
- switch (type) {
- case QRhiShaderStage::Vertex:
- return VS;
- case QRhiShaderStage::TessellationControl:
- return HS;
- case QRhiShaderStage::TessellationEvaluation:
- return DS;
- case QRhiShaderStage::Geometry:
- return GS;
- case QRhiShaderStage::Fragment:
- return PS;
- case QRhiShaderStage::Compute:
- return CS;
- }
- Q_UNREACHABLE_RETURN(VS);
-}
-
-static inline D3D12_SHADER_VISIBILITY qd3d12_stageToVisibility(QD3D12Stage s)
-{
- switch (s) {
- case VS:
- return D3D12_SHADER_VISIBILITY_VERTEX;
- case HS:
- return D3D12_SHADER_VISIBILITY_HULL;
- case DS:
- return D3D12_SHADER_VISIBILITY_DOMAIN;
- case GS:
- return D3D12_SHADER_VISIBILITY_GEOMETRY;
- case PS:
- return D3D12_SHADER_VISIBILITY_PIXEL;
- case CS:
- return D3D12_SHADER_VISIBILITY_ALL;
- }
- Q_UNREACHABLE_RETURN(D3D12_SHADER_VISIBILITY_ALL);
-}
-
-static inline QRhiShaderResourceBinding::StageFlag qd3d12_stageToSrb(QD3D12Stage s)
-{
- switch (s) {
- case VS:
- return QRhiShaderResourceBinding::VertexStage;
- case HS:
- return QRhiShaderResourceBinding::TessellationControlStage;
- case DS:
- return QRhiShaderResourceBinding::TessellationEvaluationStage;
- case GS:
- return QRhiShaderResourceBinding::GeometryStage;
- case PS:
- return QRhiShaderResourceBinding::FragmentStage;
- case CS:
- return QRhiShaderResourceBinding::ComputeStage;
- }
- Q_UNREACHABLE_RETURN(QRhiShaderResourceBinding::VertexStage);
-}
-
-struct QD3D12ShaderStageData
-{
- bool valid = false; // to allow simple arrays where unused stages are indicated by !valid
- QD3D12Stage stage = VS;
- QShader::NativeResourceBindingMap nativeResourceBindingMap;
-};
-
-struct QD3D12ShaderResourceBindings;
-
-struct QD3D12ShaderResourceVisitor
-{
- enum StorageOp { Load = 0, Store, LoadStore };
-
- QD3D12ShaderResourceVisitor(const QD3D12ShaderResourceBindings *srb,
- const QD3D12ShaderStageData *stageData,
- int stageCount)
- : srb(srb),
- stageData(stageData),
- stageCount(stageCount)
- {
- }
-
- std::function<void(QD3D12Stage, const QRhiShaderResourceBinding::Data::UniformBufferData &, int, int)> uniformBuffer = nullptr;
- std::function<void(QD3D12Stage, const QRhiShaderResourceBinding::TextureAndSampler &, int)> texture = nullptr;
- std::function<void(QD3D12Stage, const QRhiShaderResourceBinding::TextureAndSampler &, int)> sampler = nullptr;
- std::function<void(QD3D12Stage, const QRhiShaderResourceBinding::Data::StorageImageData &, StorageOp, int)> storageImage = nullptr;
- std::function<void(QD3D12Stage, const QRhiShaderResourceBinding::Data::StorageBufferData &, StorageOp, int)> storageBuffer = nullptr;
-
- void visit();
-
- const QD3D12ShaderResourceBindings *srb;
- const QD3D12ShaderStageData *stageData;
- int stageCount;
-};
-
-struct QD3D12Readback
-{
- // common
- int frameSlot = -1;
- QRhiReadbackResult *result = nullptr;
- QD3D12StagingArea staging;
- quint32 byteSize = 0;
- // textures
- quint32 bytesPerLine = 0;
- QSize pixelSize;
- QRhiTexture::Format format = QRhiTexture::UnknownFormat;
- quint32 stagingRowPitch = 0;
-};
-
-struct QD3D12MipmapGenerator
-{
- bool create(QRhiD3D12 *rhiD);
- void destroy();
- void generate(QD3D12CommandBuffer *cbD, const QD3D12ObjectHandle &textureHandle);
-
- QRhiD3D12 *rhiD;
- QD3D12ObjectHandle rootSigHandle;
- QD3D12ObjectHandle pipelineHandle;
-};
-
-struct QD3D12MemoryAllocator
-{
- bool create(ID3D12Device *device, IDXGIAdapter1 *adapter);
- void destroy();
-
- HRESULT createResource(D3D12_HEAP_TYPE heapType,
- const D3D12_RESOURCE_DESC *resourceDesc,
- D3D12_RESOURCE_STATES initialState,
- const D3D12_CLEAR_VALUE *optimizedClearValue,
- D3D12MA::Allocation **maybeAllocation,
- REFIID riidResource,
- void **ppvResource);
-
- void getBudget(D3D12MA::Budget *localBudget, D3D12MA::Budget *nonLocalBudget);
-
- bool isUsingD3D12MA() const { return allocator != nullptr; }
-
- ID3D12Device *device = nullptr;
- D3D12MA::Allocator *allocator = nullptr;
-};
-
-struct QD3D12Buffer : public QRhiBuffer
-{
- QD3D12Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
- ~QD3D12Buffer();
-
- void destroy() override;
- bool create() override;
- QRhiBuffer::NativeBuffer nativeBuffer() override;
- char *beginFullDynamicBufferUpdateForCurrentFrame() override;
- void endFullDynamicBufferUpdateForCurrentFrame() override;
-
- void executeHostWritesForFrameSlot(int frameSlot);
-
- QD3D12ObjectHandle handles[QD3D12_FRAMES_IN_FLIGHT] = {};
- struct HostWrite {
- quint32 offset;
- QRhiBufferData data;
- };
- QVarLengthArray<HostWrite, 16> pendingHostWrites[QD3D12_FRAMES_IN_FLIGHT];
- friend class QRhiD3D12;
-};
-
-struct QD3D12RenderBuffer : public QRhiRenderBuffer
-{
- QD3D12RenderBuffer(QRhiImplementation *rhi,
- Type type,
- const QSize &pixelSize,
- int sampleCount,
- Flags flags,
- QRhiTexture::Format backingFormatHint);
- ~QD3D12RenderBuffer();
- void destroy() override;
- bool create() override;
- QRhiTexture::Format backingFormat() const override;
-
- static const DXGI_FORMAT DS_FORMAT = DXGI_FORMAT_D24_UNORM_S8_UINT;
-
- QD3D12ObjectHandle handle;
- QD3D12Descriptor rtv;
- QD3D12Descriptor dsv;
- DXGI_FORMAT dxgiFormat;
- DXGI_SAMPLE_DESC sampleDesc;
- uint generation = 0;
- friend class QRhiD3D12;
-};
-
-struct QD3D12Texture : public QRhiTexture
-{
- QD3D12Texture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
- int arraySize, int sampleCount, Flags flags);
- ~QD3D12Texture();
- void destroy() override;
- bool create() override;
- bool createFrom(NativeTexture src) override;
- NativeTexture nativeTexture() override;
- void setNativeLayout(int layout) override;
-
- bool prepareCreate(QSize *adjustedSize = nullptr);
- bool finishCreate();
-
- QD3D12ObjectHandle handle;
- QD3D12Descriptor srv;
- DXGI_FORMAT dxgiFormat;
- uint mipLevelCount;
- DXGI_SAMPLE_DESC sampleDesc;
- uint generation = 0;
- friend class QRhiD3D12;
-};
-
-struct QD3D12Sampler : public QRhiSampler
-{
- QD3D12Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
- AddressMode u, AddressMode v, AddressMode w);
- ~QD3D12Sampler();
- void destroy() override;
- bool create() override;
-
- QD3D12Descriptor lookupOrCreateShaderVisibleDescriptor();
-
- D3D12_SAMPLER_DESC desc = {};
- QD3D12Descriptor shaderVisibleDescriptor;
-};
-
-struct QD3D12RenderPassDescriptor : public QRhiRenderPassDescriptor
-{
- QD3D12RenderPassDescriptor(QRhiImplementation *rhi);
- ~QD3D12RenderPassDescriptor();
- void destroy() override;
- bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
- QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
- QVector<quint32> serializedFormat() const override;
-
- void updateSerializedFormat();
-
- static const int MAX_COLOR_ATTACHMENTS = 8;
- int colorAttachmentCount = 0;
- bool hasDepthStencil = false;
- int colorFormat[MAX_COLOR_ATTACHMENTS];
- int dsFormat;
- QVector<quint32> serializedFormatData;
-};
-
-struct QD3D12RenderTargetData
-{
- QD3D12RenderTargetData(QRhiImplementation *) { }
-
- QD3D12RenderPassDescriptor *rp = nullptr;
- QSize pixelSize;
- float dpr = 1;
- int sampleCount = 1;
- int colorAttCount = 0;
- int dsAttCount = 0;
- QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList;
- static const int MAX_COLOR_ATTACHMENTS = QD3D12RenderPassDescriptor::MAX_COLOR_ATTACHMENTS;
- D3D12_CPU_DESCRIPTOR_HANDLE rtv[MAX_COLOR_ATTACHMENTS];
- D3D12_CPU_DESCRIPTOR_HANDLE dsv;
-};
-
-struct QD3D12SwapChainRenderTarget : public QRhiSwapChainRenderTarget
-{
- QD3D12SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
- ~QD3D12SwapChainRenderTarget();
- void destroy() override;
-
- QSize pixelSize() const override;
- float devicePixelRatio() const override;
- int sampleCount() const override;
-
- QD3D12RenderTargetData d;
-};
-
-struct QD3D12TextureRenderTarget : public QRhiTextureRenderTarget
-{
- QD3D12TextureRenderTarget(QRhiImplementation *rhi,
- const QRhiTextureRenderTargetDescription &desc,
- Flags flags);
- ~QD3D12TextureRenderTarget();
- void destroy() override;
-
- QSize pixelSize() const override;
- float devicePixelRatio() const override;
- int sampleCount() const override;
-
- QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
- bool create() override;
-
- QD3D12RenderTargetData d;
- bool ownsRtv[QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS];
- QD3D12Descriptor rtv[QD3D12RenderTargetData::MAX_COLOR_ATTACHMENTS];
- bool ownsDsv = false;
- QD3D12Descriptor dsv;
- friend class QRhiD3D12;
-};
-
-struct QD3D12ShaderResourceBindings : public QRhiShaderResourceBindings
-{
- QD3D12ShaderResourceBindings(QRhiImplementation *rhi);
- ~QD3D12ShaderResourceBindings();
- void destroy() override;
- bool create() override;
- void updateResources(UpdateFlags flags) override;
-
- QD3D12ObjectHandle createRootSignature(const QD3D12ShaderStageData *stageData, int stageCount);
-
- struct VisitorData {
- QVarLengthArray<D3D12_ROOT_PARAMETER1, 2> cbParams[6];
-
- D3D12_ROOT_PARAMETER1 srvTables[6] = {};
- QVarLengthArray<D3D12_DESCRIPTOR_RANGE1, 4> srvRanges[6];
- quint32 currentSrvRangeOffset[6] = {};
-
- QVarLengthArray<D3D12_ROOT_PARAMETER1, 4> samplerTables[6];
- std::array<D3D12_DESCRIPTOR_RANGE1, 16> samplerRanges[6] = {};
- int samplerRangeHeads[6] = {};
-
- D3D12_ROOT_PARAMETER1 uavTables[6] = {};
- QVarLengthArray<D3D12_DESCRIPTOR_RANGE1, 4> uavRanges[6];
- quint32 currentUavRangeOffset[6] = {};
- } visitorData;
-
-
- void visitUniformBuffer(QD3D12Stage s,
- const QRhiShaderResourceBinding::Data::UniformBufferData &d,
- int shaderRegister,
- int binding);
- void visitTexture(QD3D12Stage s,
- const QRhiShaderResourceBinding::TextureAndSampler &d,
- int shaderRegister);
- void visitSampler(QD3D12Stage s,
- const QRhiShaderResourceBinding::TextureAndSampler &d,
- int shaderRegister);
- void visitStorageBuffer(QD3D12Stage s,
- const QRhiShaderResourceBinding::Data::StorageBufferData &d,
- QD3D12ShaderResourceVisitor::StorageOp op,
- int shaderRegister);
- void visitStorageImage(QD3D12Stage s,
- const QRhiShaderResourceBinding::Data::StorageImageData &d,
- QD3D12ShaderResourceVisitor::StorageOp op,
- int shaderRegister);
-
- QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
- bool hasDynamicOffset = false;
- uint generation = 0;
-};
-
-struct QD3D12GraphicsPipeline : public QRhiGraphicsPipeline
-{
- QD3D12GraphicsPipeline(QRhiImplementation *rhi);
- ~QD3D12GraphicsPipeline();
- void destroy() override;
- bool create() override;
-
- QD3D12ObjectHandle handle;
- QD3D12ObjectHandle rootSigHandle;
- std::array<QD3D12ShaderStageData, 5> stageData;
- D3D12_PRIMITIVE_TOPOLOGY topology;
- uint generation = 0;
- friend class QRhiD3D12;
-};
-
-struct QD3D12ComputePipeline : public QRhiComputePipeline
-{
- QD3D12ComputePipeline(QRhiImplementation *rhi);
- ~QD3D12ComputePipeline();
- void destroy() override;
- bool create() override;
-
- QD3D12ObjectHandle handle;
- QD3D12ObjectHandle rootSigHandle;
- QD3D12ShaderStageData stageData;
- uint generation = 0;
- friend class QRhiD3D12;
-};
-
-struct QD3D12CommandBuffer : public QRhiCommandBuffer
-{
- QD3D12CommandBuffer(QRhiImplementation *rhi);
- ~QD3D12CommandBuffer();
- void destroy() override;
-
- const QRhiNativeHandles *nativeHandles();
-
- ID3D12GraphicsCommandList *cmdList = nullptr; // not owned
- QRhiD3D12CommandBufferNativeHandles nativeHandlesStruct;
-
- enum PassType {
- NoPass,
- RenderPass,
- ComputePass
- };
-
- void resetState()
- {
- recordingPass = NoPass;
- currentTarget = nullptr;
-
- resetPerPassState();
- }
-
- void resetPerPassState()
- {
- currentGraphicsPipeline = nullptr;
- currentComputePipeline = nullptr;
- currentPipelineGeneration = 0;
- currentGraphicsSrb = nullptr;
- currentComputeSrb = nullptr;
- currentSrbGeneration = 0;
- currentIndexBuffer = {};
- currentIndexOffset = 0;
- currentIndexFormat = DXGI_FORMAT_R16_UINT;
- currentVertexBuffers = {};
- currentVertexOffsets = {};
- }
-
- PassType recordingPass;
- QRhiRenderTarget *currentTarget;
-
- QD3D12GraphicsPipeline *currentGraphicsPipeline;
- QD3D12ComputePipeline *currentComputePipeline;
- uint currentPipelineGeneration;
- QRhiShaderResourceBindings *currentGraphicsSrb;
- QRhiShaderResourceBindings *currentComputeSrb;
- uint currentSrbGeneration;
- QD3D12ObjectHandle currentIndexBuffer;
- quint32 currentIndexOffset;
- DXGI_FORMAT currentIndexFormat;
- std::array<QD3D12ObjectHandle, D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> currentVertexBuffers;
- std::array<quint32, D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> currentVertexOffsets;
-};
-
-struct QD3D12SwapChain : public QRhiSwapChain
-{
- QD3D12SwapChain(QRhiImplementation *rhi);
- ~QD3D12SwapChain();
- void destroy() override;
-
- QRhiCommandBuffer *currentFrameCommandBuffer() override;
- QRhiRenderTarget *currentFrameRenderTarget() override;
-
- QSize surfacePixelSize() override;
- bool isFormatSupported(Format f) override;
- QRhiSwapChainHdrInfo hdrInfo() override;
-
- QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
- bool createOrResize() override;
-
- void releaseBuffers();
- void waitCommandCompletionForFrameSlot(int frameSlot);
- void addCommandCompletionSignalForCurrentFrameSlot();
- void chooseFormats();
-
- QWindow *window = nullptr;
- IDXGISwapChain1 *sourceSwapChain1 = nullptr;
- IDXGISwapChain3 *swapChain = nullptr;
- QSize pixelSize;
- UINT swapInterval = 1;
- UINT swapChainFlags = 0;
- DXGI_FORMAT colorFormat;
- DXGI_FORMAT srgbAdjustedColorFormat;
- DXGI_COLOR_SPACE_TYPE hdrColorSpace;
- IDCompositionTarget *dcompTarget = nullptr;
- IDCompositionVisual *dcompVisual = nullptr;
- static const UINT BUFFER_COUNT = 3;
- QD3D12ObjectHandle colorBuffers[BUFFER_COUNT];
- QD3D12Descriptor rtvs[BUFFER_COUNT];
- DXGI_SAMPLE_DESC sampleDesc;
- QD3D12ObjectHandle msaaBuffers[BUFFER_COUNT];
- QD3D12Descriptor msaaRtvs[BUFFER_COUNT];
- QD3D12RenderBuffer *ds = nullptr;
- UINT currentBackBufferIndex = 0;
- QD3D12SwapChainRenderTarget rtWrapper;
- QD3D12CommandBuffer cbWrapper;
-
- struct FrameResources {
- ID3D12Fence *fence = nullptr;
- HANDLE fenceEvent = nullptr;
- UINT64 fenceCounter = 0;
- ID3D12GraphicsCommandList *cmdList = nullptr;
- } frameRes[QD3D12_FRAMES_IN_FLIGHT];
-
- int currentFrameSlot = 0; // index in frameRes
-};
-
-class QRhiD3D12 : public QRhiImplementation
-{
-public:
- // 16MB * QD3D12_FRAMES_IN_FLIGHT; buffer and texture upload staging data that
- // gets no space from this will get their own temporary staging areas.
- static const quint32 SMALL_STAGING_AREA_BYTES_PER_FRAME = 16 * 1024 * 1024;
-
- static const quint32 SHADER_VISIBLE_CBV_SRV_UAV_HEAP_PER_FRAME_START_SIZE = 16384;
-
- QRhiD3D12(QRhiD3D12InitParams *params, QRhiD3D12NativeHandles *importDevice = nullptr);
-
- bool create(QRhi::Flags flags) override;
- void destroy() override;
-
- QRhiGraphicsPipeline *createGraphicsPipeline() override;
- QRhiComputePipeline *createComputePipeline() override;
- QRhiShaderResourceBindings *createShaderResourceBindings() override;
- QRhiBuffer *createBuffer(QRhiBuffer::Type type,
- QRhiBuffer::UsageFlags usage,
- quint32 size) override;
- QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
- const QSize &pixelSize,
- int sampleCount,
- QRhiRenderBuffer::Flags flags,
- QRhiTexture::Format backingFormatHint) override;
- QRhiTexture *createTexture(QRhiTexture::Format format,
- const QSize &pixelSize,
- int depth,
- int arraySize,
- int sampleCount,
- QRhiTexture::Flags flags) override;
- QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
- QRhiSampler::Filter minFilter,
- QRhiSampler::Filter mipmapMode,
- QRhiSampler:: AddressMode u,
- QRhiSampler::AddressMode v,
- QRhiSampler::AddressMode w) override;
-
- QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
- QRhiTextureRenderTarget::Flags flags) override;
-
- QRhiSwapChain *createSwapChain() override;
- QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
- QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
- QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
- QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
- QRhi::FrameOpResult finish() override;
-
- void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
-
- void beginPass(QRhiCommandBuffer *cb,
- QRhiRenderTarget *rt,
- const QColor &colorClearValue,
- const QRhiDepthStencilClearValue &depthStencilClearValue,
- QRhiResourceUpdateBatch *resourceUpdates,
- QRhiCommandBuffer::BeginPassFlags flags) override;
- void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
-
- void setGraphicsPipeline(QRhiCommandBuffer *cb,
- QRhiGraphicsPipeline *ps) override;
-
- void setShaderResources(QRhiCommandBuffer *cb,
- QRhiShaderResourceBindings *srb,
- int dynamicOffsetCount,
- const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
-
- void setVertexInput(QRhiCommandBuffer *cb,
- int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
- QRhiBuffer *indexBuf, quint32 indexOffset,
- QRhiCommandBuffer::IndexFormat indexFormat) override;
-
- void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
- void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
- void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
- void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
-
- void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
- quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
-
- void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
- quint32 instanceCount, quint32 firstIndex,
- qint32 vertexOffset, quint32 firstInstance) override;
-
- void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
- void debugMarkEnd(QRhiCommandBuffer *cb) override;
- void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
-
- void beginComputePass(QRhiCommandBuffer *cb,
- QRhiResourceUpdateBatch *resourceUpdates,
- QRhiCommandBuffer::BeginPassFlags flags) override;
- void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
- void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
- void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
-
- const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
- void beginExternal(QRhiCommandBuffer *cb) override;
- void endExternal(QRhiCommandBuffer *cb) override;
-
- QList<int> supportedSampleCounts() const override;
- int ubufAlignment() const override;
- bool isYUpInFramebuffer() const override;
- bool isYUpInNDC() const override;
- bool isClipDepthZeroToOne() const override;
- QMatrix4x4 clipSpaceCorrMatrix() const override;
- bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
- bool isFeatureSupported(QRhi::Feature feature) const override;
- int resourceLimit(QRhi::ResourceLimit limit) const override;
- const QRhiNativeHandles *nativeHandles() override;
- QRhiDriverInfo driverInfo() const override;
- QRhiStats statistics() override;
- bool makeThreadLocalNativeContextCurrent() override;
- void releaseCachedResources() override;
- bool isDeviceLost() const override;
-
- QByteArray pipelineCacheData() override;
- void setPipelineCacheData(const QByteArray &data) override;
-
- void waitGpu();
- DXGI_SAMPLE_DESC effectiveSampleCount(int sampleCount, DXGI_FORMAT format) const;
- bool ensureDirectCompositionDevice();
- bool startCommandListForCurrentFrameSlot(ID3D12GraphicsCommandList **cmdList);
- void enqueueResourceUpdates(QD3D12CommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates);
- void finishActiveReadbacks(bool forced = false);
- bool ensureShaderVisibleDescriptorHeapCapacity(QD3D12ShaderVisibleDescriptorHeap *h,
- D3D12_DESCRIPTOR_HEAP_TYPE type,
- int frameSlot,
- quint32 neededDescriptorCount,
- bool *gotNew);
- void bindShaderVisibleHeaps(QD3D12CommandBuffer *cbD);
-
- bool debugLayer = false;
- ID3D12Device *dev = nullptr;
- D3D_FEATURE_LEVEL minimumFeatureLevel = D3D_FEATURE_LEVEL(0);
- LUID adapterLuid = {};
- bool importedDevice = false;
- bool importedCommandQueue = false;
- QRhi::Flags rhiFlags;
- IDXGIFactory2 *dxgiFactory = nullptr;
- bool supportsAllowTearing = false;
- IDXGIAdapter1 *activeAdapter = nullptr;
- QRhiDriverInfo driverInfoStruct;
- QRhiD3D12NativeHandles nativeHandlesStruct;
- bool deviceLost = false;
- ID3D12CommandQueue *cmdQueue = nullptr;
- ID3D12Fence *fullFence = nullptr;
- HANDLE fullFenceEvent = nullptr;
- UINT64 fullFenceCounter = 0;
- ID3D12CommandAllocator *cmdAllocators[QD3D12_FRAMES_IN_FLIGHT] = {};
- QD3D12MemoryAllocator vma;
- QD3D12CpuDescriptorPool rtvPool;
- QD3D12CpuDescriptorPool dsvPool;
- QD3D12CpuDescriptorPool cbvSrvUavPool;
- QD3D12ObjectPool<QD3D12Resource> resourcePool;
- QD3D12ObjectPool<QD3D12Pipeline> pipelinePool;
- QD3D12ObjectPool<QD3D12RootSignature> rootSignaturePool;
- QD3D12ReleaseQueue releaseQueue;
- QD3D12ResourceBarrierGenerator barrierGen;
- QD3D12SamplerManager samplerMgr;
- QD3D12MipmapGenerator mipmapGen;
- QD3D12StagingArea smallStagingAreas[QD3D12_FRAMES_IN_FLIGHT];
- QD3D12ShaderVisibleDescriptorHeap shaderVisibleCbvSrvUavHeap;
- IDCompositionDevice *dcompDevice = nullptr;
- QD3D12SwapChain *currentSwapChain = nullptr;
- QSet<QD3D12SwapChain *> swapchains;
- QD3D12ShaderBytecodeCache shaderBytecodeCache;
- QVarLengthArray<QD3D12Readback, 4> activeReadbacks;
- bool offscreenActive = false;
- QD3D12CommandBuffer *offscreenCb[QD3D12_FRAMES_IN_FLIGHT] = {};
-
- struct VisitorData {
- QVarLengthArray<QPair<QD3D12ObjectHandle, quint32>, 4> cbufs[6];
- QVarLengthArray<QD3D12Descriptor, 8> srvs[6];
- QVarLengthArray<QD3D12Descriptor, 8> samplers[6];
- QVarLengthArray<QPair<QD3D12ObjectHandle, D3D12_UNORDERED_ACCESS_VIEW_DESC>, 4> uavs[6];
- } visitorData;
-
- void visitUniformBuffer(QD3D12Stage s,
- const QRhiShaderResourceBinding::Data::UniformBufferData &d,
- int shaderRegister,
- int binding,
- int dynamicOffsetCount,
- const QRhiCommandBuffer::DynamicOffset *dynamicOffsets);
- void visitTexture(QD3D12Stage s,
- const QRhiShaderResourceBinding::TextureAndSampler &d,
- int shaderRegister);
- void visitSampler(QD3D12Stage s,
- const QRhiShaderResourceBinding::TextureAndSampler &d,
- int shaderRegister);
- void visitStorageBuffer(QD3D12Stage s,
- const QRhiShaderResourceBinding::Data::StorageBufferData &d,
- QD3D12ShaderResourceVisitor::StorageOp op,
- int shaderRegister);
- void visitStorageImage(QD3D12Stage s,
- const QRhiShaderResourceBinding::Data::StorageImageData &d,
- QD3D12ShaderResourceVisitor::StorageOp op,
- int shaderRegister);
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/gui/rhi/qrhid3dhelpers.cpp b/src/gui/rhi/qrhid3dhelpers.cpp
new file mode 100644
index 0000000000..216c358cbe
--- /dev/null
+++ b/src/gui/rhi/qrhid3dhelpers.cpp
@@ -0,0 +1,172 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qrhid3dhelpers_p.h"
+#include <QtCore/private/qsystemlibrary_p.h>
+#include <QtCore/private/qsystemerror_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QRhiD3D {
+
+bool output6ForWindow(QWindow *w, IDXGIAdapter1 *adapter, IDXGIOutput6 **result)
+{
+ bool ok = false;
+ QRect wr = w->geometry();
+ wr = QRect(wr.topLeft() * w->devicePixelRatio(), wr.size() * w->devicePixelRatio());
+ const QPoint center = wr.center();
+ IDXGIOutput *currentOutput = nullptr;
+ IDXGIOutput *output = nullptr;
+ for (UINT i = 0; adapter->EnumOutputs(i, &output) != DXGI_ERROR_NOT_FOUND; ++i) {
+ DXGI_OUTPUT_DESC desc;
+ output->GetDesc(&desc);
+ const RECT r = desc.DesktopCoordinates;
+ const QRect dr(QPoint(r.left, r.top), QPoint(r.right - 1, r.bottom - 1));
+ if (dr.contains(center)) {
+ currentOutput = output;
+ break;
+ } else {
+ output->Release();
+ }
+ }
+ if (currentOutput) {
+ ok = SUCCEEDED(currentOutput->QueryInterface(__uuidof(IDXGIOutput6), reinterpret_cast<void **>(result)));
+ currentOutput->Release();
+ }
+ return ok;
+}
+
+bool outputDesc1ForWindow(QWindow *w, IDXGIAdapter1 *adapter, DXGI_OUTPUT_DESC1 *result)
+{
+ bool ok = false;
+ IDXGIOutput6 *out6 = nullptr;
+ if (output6ForWindow(w, adapter, &out6)) {
+ ok = SUCCEEDED(out6->GetDesc1(result));
+ out6->Release();
+ }
+ return ok;
+}
+
+float sdrWhiteLevelInNits(const DXGI_OUTPUT_DESC1 &outputDesc)
+{
+ QVector<DISPLAYCONFIG_PATH_INFO> pathInfos;
+ uint32_t pathInfoCount, modeInfoCount;
+ LONG result;
+ do {
+ if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &pathInfoCount, &modeInfoCount) == ERROR_SUCCESS) {
+ pathInfos.resize(pathInfoCount);
+ QVector<DISPLAYCONFIG_MODE_INFO> modeInfos(modeInfoCount);
+ result = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &pathInfoCount, pathInfos.data(), &modeInfoCount, modeInfos.data(), nullptr);
+ } else {
+ return 200.0f;
+ }
+ } while (result == ERROR_INSUFFICIENT_BUFFER);
+
+ MONITORINFOEX monitorInfo = {};
+ monitorInfo.cbSize = sizeof(monitorInfo);
+ GetMonitorInfo(outputDesc.Monitor, &monitorInfo);
+
+ for (const DISPLAYCONFIG_PATH_INFO &info : pathInfos) {
+ DISPLAYCONFIG_SOURCE_DEVICE_NAME deviceName = {};
+ deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
+ deviceName.header.size = sizeof(deviceName);
+ deviceName.header.adapterId = info.sourceInfo.adapterId;
+ deviceName.header.id = info.sourceInfo.id;
+ if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) {
+ if (!wcscmp(monitorInfo.szDevice, deviceName.viewGdiDeviceName)) {
+ DISPLAYCONFIG_SDR_WHITE_LEVEL whiteLevel = {};
+ whiteLevel.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL;
+ whiteLevel.header.size = sizeof(DISPLAYCONFIG_SDR_WHITE_LEVEL);
+ whiteLevel.header.adapterId = info.targetInfo.adapterId;
+ whiteLevel.header.id = info.targetInfo.id;
+ if (DisplayConfigGetDeviceInfo(&whiteLevel.header) == ERROR_SUCCESS)
+ return whiteLevel.SDRWhiteLevel * 80 / 1000.0f;
+ }
+ }
+ }
+
+ return 200.0f;
+}
+
+pD3DCompile resolveD3DCompile()
+{
+ for (const wchar_t *libraryName : {L"D3DCompiler_47", L"D3DCompiler_43"}) {
+ QSystemLibrary library(libraryName);
+ if (library.load()) {
+ if (auto symbol = library.resolve("D3DCompile"))
+ return reinterpret_cast<pD3DCompile>(symbol);
+ } else {
+ qWarning("Failed to load D3DCompiler_47/43.dll");
+ }
+ }
+ return nullptr;
+}
+
+IDCompositionDevice *createDirectCompositionDevice()
+{
+ QSystemLibrary dcomplib(QStringLiteral("dcomp"));
+ typedef HRESULT (__stdcall *DCompositionCreateDeviceFuncPtr)(
+ _In_opt_ IDXGIDevice *dxgiDevice,
+ _In_ REFIID iid,
+ _Outptr_ void **dcompositionDevice);
+ DCompositionCreateDeviceFuncPtr func = reinterpret_cast<DCompositionCreateDeviceFuncPtr>(
+ dcomplib.resolve("DCompositionCreateDevice"));
+ if (!func) {
+ qWarning("Unable to resolve DCompositionCreateDevice, perhaps dcomp.dll is missing?");
+ return nullptr;
+ }
+ IDCompositionDevice *device = nullptr;
+ HRESULT hr = func(nullptr, __uuidof(IDCompositionDevice), reinterpret_cast<void **>(&device));
+ if (FAILED(hr)) {
+ qWarning("Failed to create Direct Composition device: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ return nullptr;
+ }
+ return device;
+}
+
+#ifdef QRHI_D3D12_HAS_DXC
+std::pair<IDxcCompiler *, IDxcLibrary *> createDxcCompiler()
+{
+ QSystemLibrary dxclib(QStringLiteral("dxcompiler"));
+ // this will not be in the system library location, hence onlySystemDirectory==false
+ if (!dxclib.load(false)) {
+ qWarning("Failed to load dxcompiler.dll");
+ return {};
+ }
+ DxcCreateInstanceProc func = reinterpret_cast<DxcCreateInstanceProc>(dxclib.resolve("DxcCreateInstance"));
+ if (!func) {
+ qWarning("Unable to resolve DxcCreateInstance");
+ return {};
+ }
+ IDxcCompiler *compiler = nullptr;
+ HRESULT hr = func(CLSID_DxcCompiler, __uuidof(IDxcCompiler), reinterpret_cast<void**>(&compiler));
+ if (FAILED(hr)) {
+ qWarning("Failed to create dxc compiler instance: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ return {};
+ }
+ IDxcLibrary *library = nullptr;
+ hr = func(CLSID_DxcLibrary, __uuidof(IDxcLibrary), reinterpret_cast<void**>(&library));
+ if (FAILED(hr)) {
+ qWarning("Failed to create dxc library instance: %s",
+ qPrintable(QSystemError::windowsComString(hr)));
+ return {};
+ }
+ return { compiler, library };
+}
+#endif
+
+void fillDriverInfo(QRhiDriverInfo *info, const DXGI_ADAPTER_DESC1 &desc)
+{
+ const QString name = QString::fromUtf16(reinterpret_cast<const char16_t *>(desc.Description));
+ info->deviceName = name.toUtf8();
+ info->deviceId = desc.DeviceId;
+ info->vendorId = desc.VendorId;
+ info->deviceType = (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) ? QRhiDriverInfo::CpuDevice
+ : QRhiDriverInfo::UnknownDevice;
+}
+
+} // namespace
+
+QT_END_NAMESPACE
diff --git a/src/gui/rhi/qrhid3dhelpers_p.h b/src/gui/rhi/qrhid3dhelpers_p.h
new file mode 100644
index 0000000000..f31cdc8d11
--- /dev/null
+++ b/src/gui/rhi/qrhid3dhelpers_p.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QRHID3DHELPERS_P_H
+#define QRHID3DHELPERS_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 <rhi/qrhi.h>
+
+#include <QtGui/qwindow.h>
+
+#include <dxgi1_6.h>
+#include <dcomp.h>
+#include <d3dcompiler.h>
+
+#if __has_include(<dxcapi.h>)
+#include <dxcapi.h>
+#define QRHI_D3D12_HAS_DXC
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace QRhiD3D {
+
+bool output6ForWindow(QWindow *w, IDXGIAdapter1 *adapter, IDXGIOutput6 **result);
+bool outputDesc1ForWindow(QWindow *w, IDXGIAdapter1 *adapter, DXGI_OUTPUT_DESC1 *result);
+float sdrWhiteLevelInNits(const DXGI_OUTPUT_DESC1 &outputDesc);
+
+pD3DCompile resolveD3DCompile();
+
+IDCompositionDevice *createDirectCompositionDevice();
+
+#ifdef QRHI_D3D12_HAS_DXC
+std::pair<IDxcCompiler *, IDxcLibrary *> createDxcCompiler();
+#endif
+
+void fillDriverInfo(QRhiDriverInfo *info, const DXGI_ADAPTER_DESC1 &desc);
+
+} // namespace
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp
index a9bb8473a2..dcaa87a5ff 100644
--- a/src/gui/rhi/qrhigles2.cpp
+++ b/src/gui/rhi/qrhigles2.cpp
@@ -1,12 +1,13 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qrhigles2_p_p.h"
+#include "qrhigles2_p.h"
#include <QOffscreenSurface>
#include <QOpenGLContext>
#include <QtCore/qmap.h>
#include <QtGui/private/qopenglextensions_p.h>
#include <QtGui/private/qopenglprogrambinarycache_p.h>
+#include <QtGui/private/qwindow_p.h>
#include <qpa/qplatformopenglcontext.h>
#include <qmath.h>
@@ -27,10 +28,13 @@ QT_BEGIN_NAMESPACE
/*!
\class QRhiGles2InitParams
- \internal
\inmodule QtGui
+ \since 6.6
\brief OpenGL specific initialization parameters.
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
An OpenGL-based QRhi needs an already created QSurface that can be used in
combination with QOpenGLContext. Most commonly, this is a QOffscreenSurface
in practice. Additionally, while optional, it is recommended that the QWindow
@@ -104,12 +108,50 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \variable QRhiGles2InitParams::format
+
+ The QSurfaceFormat, initialized to QSurfaceFormat::defaultFormat() by default.
+*/
+
+/*!
+ \variable QRhiGles2InitParams::fallbackSurface
+
+ A QSurface compatible with \l format. Typically a QOffscreenSurface.
+ Providing this is mandatory. Be aware of the threading implications: a
+ QOffscreenSurface, like QWindow, must only ever be created and destroyed on
+ the main (gui) thread, even if the QRhi is created and operates on another
+ thread.
+*/
+
+/*!
+ \variable QRhiGles2InitParams::window
+
+ Optional, but setting it is recommended when targeting a QWindow with the
+ QRhi.
+*/
+
+/*!
+ \variable QRhiGles2InitParams::shareContext
+
+ Optional, the QOpenGLContext to share resource with. QRhi creates its own
+ context, and setting this member to a valid QOpenGLContext leads to calling
+ \l{QOpenGLContext::setShareContext()}{setShareContext()} with it.
+*/
+
+/*!
\class QRhiGles2NativeHandles
- \internal
\inmodule QtGui
+ \since 6.6
\brief Holds the OpenGL context used by the QRhi.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
+/*!
+ \variable QRhiGles2NativeHandles::context
+*/
+
#ifndef GL_BGRA
#define GL_BGRA 0x80E1
#endif
@@ -174,6 +216,10 @@ QT_BEGIN_NAMESPACE
#define GL_DEPTH_COMPONENT32F 0x8CAC
#endif
+#ifndef GL_UNSIGNED_INT_24_8
+#define GL_UNSIGNED_INT_24_8 0x84FA
+#endif
+
#ifndef GL_STENCIL_INDEX
#define GL_STENCIL_INDEX 0x1901
#endif
@@ -199,7 +245,7 @@ QT_BEGIN_NAMESPACE
#endif
#ifndef GL_FRAMEBUFFER_SRGB
-#define GL_FRAMEBUFFER_SRGB 0x8DB9
+#define GL_FRAMEBUFFER_SRGB 0x8DB9
#endif
#ifndef GL_READ_FRAMEBUFFER
@@ -314,6 +360,10 @@ QT_BEGIN_NAMESPACE
#define GL_TEXTURE_2D_MULTISAMPLE 0x9100
#endif
+#ifndef GL_TEXTURE_2D_MULTISAMPLE_ARRAY
+#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102
+#endif
+
#ifndef GL_TEXTURE_EXTERNAL_OES
#define GL_TEXTURE_EXTERNAL_OES 0x8D65
#endif
@@ -443,15 +493,39 @@ QT_BEGIN_NAMESPACE
#endif
#ifndef GL_TEXTURE_1D
-# define GL_TEXTURE_1D 0x0DE0
+# define GL_TEXTURE_1D 0x0DE0
#endif
#ifndef GL_TEXTURE_1D_ARRAY
-# define GL_TEXTURE_1D_ARRAY 0x8C18
+# define GL_TEXTURE_1D_ARRAY 0x8C18
#endif
#ifndef GL_HALF_FLOAT
-#define GL_HALF_FLOAT 0x140B
+#define GL_HALF_FLOAT 0x140B
+#endif
+
+#ifndef GL_MAX_VERTEX_OUTPUT_COMPONENTS
+#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122
+#endif
+
+#ifndef GL_TIMESTAMP
+#define GL_TIMESTAMP 0x8E28
+#endif
+
+#ifndef GL_QUERY_RESULT
+#define GL_QUERY_RESULT 0x8866
+#endif
+
+#ifndef GL_QUERY_RESULT_AVAILABLE
+#define GL_QUERY_RESULT_AVAILABLE 0x8867
+#endif
+
+#ifndef GL_BUFFER
+#define GL_BUFFER 0x82E0
+#endif
+
+#ifndef GL_PROGRAM
+#define GL_PROGRAM 0x82E2
#endif
/*!
@@ -658,6 +732,8 @@ bool QRhiGles2::create(QRhi::Flags flags)
return false;
f = static_cast<QOpenGLExtensions *>(ctx->extraFunctions());
+ const QSurfaceFormat actualFormat = ctx->format();
+ caps.gles = actualFormat.renderableType() == QSurfaceFormat::OpenGLES;
if (!caps.gles) {
glPolygonMode = reinterpret_cast<void(QOPENGLF_APIENTRYP)(GLenum, GLenum)>(
@@ -708,8 +784,6 @@ bool QRhiGles2::create(QRhi::Flags flags)
if (version)
driverInfoStruct.deviceName += QByteArray(version);
- const QSurfaceFormat actualFormat = ctx->format();
-
caps.ctxMajor = actualFormat.majorVersion();
caps.ctxMinor = actualFormat.minorVersion();
@@ -769,8 +843,6 @@ bool QRhiGles2::create(QRhi::Flags flags)
f->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &caps.maxTextureSize);
- caps.gles = actualFormat.renderableType() == QSurfaceFormat::OpenGLES;
-
if (!caps.gles || caps.ctxMajor >= 3) {
// non-ES or ES 3.0+
f->glGetIntegerv(GL_MAX_DRAW_BUFFERS, &caps.maxDrawBuffers);
@@ -782,8 +854,8 @@ bool QRhiGles2::create(QRhi::Flags flags)
caps.maxDrawBuffers = 1;
caps.hasDrawBuffersFunc = false;
// This does not mean MSAA is not supported, just that we cannot query
- // the supported sample counts.
- caps.maxSamples = 1;
+ // the supported sample counts. Assume that 4x is always supported.
+ caps.maxSamples = 4;
}
caps.msaaRenderBuffer = f->hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)
@@ -820,7 +892,13 @@ bool QRhiGles2::create(QRhi::Flags flags)
#else
caps.needsDepthStencilCombinedAttach = false;
#endif
- caps.srgbCapableDefaultFramebuffer = f->hasOpenGLExtension(QOpenGLExtensions::SRGBFrameBuffer);
+
+ // QOpenGLExtensions::SRGBFrameBuffer is not useful here. We need to know if
+ // controlling the sRGB-on-shader-write state is supported, not that if the
+ // default framebuffer is sRGB-capable. And there are two different
+ // extensions for desktop and ES.
+ caps.srgbWriteControl = ctx->hasExtension("GL_EXT_framebuffer_sRGB") || ctx->hasExtension("GL_EXT_sRGB_write_control");
+
caps.coreProfile = actualFormat.profile() == QSurfaceFormat::CoreProfile;
if (caps.gles)
@@ -941,7 +1019,7 @@ bool QRhiGles2::create(QRhi::Flags flags)
f->glGetIntegerv(GL_MAX_VARYING_VECTORS, &caps.maxVertexOutputs);
} else if (caps.ctxMajor >= 3) {
GLint components = 0;
- f->glGetIntegerv(GL_MAX_VARYING_COMPONENTS, &components);
+ f->glGetIntegerv(caps.coreProfile ? GL_MAX_VERTEX_OUTPUT_COMPONENTS : GL_MAX_VARYING_COMPONENTS, &components);
caps.maxVertexOutputs = components / 4;
} else {
// OpenGL before 3.0 only has this, and not the same as
@@ -954,7 +1032,8 @@ bool QRhiGles2::create(QRhi::Flags flags)
if (!caps.gles) {
f->glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
- f->glEnable(GL_POINT_SPRITE);
+ if (!caps.coreProfile)
+ f->glEnable(GL_POINT_SPRITE);
} // else (with gles) these are always on
// Match D3D and others when it comes to seamless cubemap filtering.
@@ -965,6 +1044,60 @@ bool QRhiGles2::create(QRhi::Flags flags)
caps.halfAttributes = f->hasOpenGLExtension(QOpenGLExtensions::HalfFloatVertex);
+ // We always require GL_OVR_multiview2 for symmetry with other backends.
+ caps.multiView = f->hasOpenGLExtension(QOpenGLExtensions::MultiView)
+ && f->hasOpenGLExtension(QOpenGLExtensions::MultiViewExtended);
+ if (caps.multiView) {
+ glFramebufferTextureMultiviewOVR =
+ reinterpret_cast<void(QOPENGLF_APIENTRYP)(GLenum, GLenum, GLuint, GLint, GLint, GLsizei)>(
+ ctx->getProcAddress(QByteArrayLiteral("glFramebufferTextureMultiviewOVR")));
+ }
+
+ // Only do timestamp queries on OpenGL 3.3+.
+ caps.timestamps = !caps.gles && (caps.ctxMajor > 3 || (caps.ctxMajor == 3 && caps.ctxMinor >= 3));
+ if (caps.timestamps) {
+ glQueryCounter = reinterpret_cast<void(QOPENGLF_APIENTRYP)(GLuint, GLenum)>(
+ ctx->getProcAddress(QByteArrayLiteral("glQueryCounter")));
+ glGetQueryObjectui64v = reinterpret_cast<void(QOPENGLF_APIENTRYP)(GLuint, GLenum, quint64 *)>(
+ ctx->getProcAddress(QByteArrayLiteral("glGetQueryObjectui64v")));
+ if (!glQueryCounter || !glGetQueryObjectui64v)
+ caps.timestamps = false;
+ }
+
+ // glObjectLabel is available on OpenGL ES 3.2+ and OpenGL 4.3+
+ if (caps.gles)
+ caps.objectLabel = caps.ctxMajor > 3 || (caps.ctxMajor == 3 && caps.ctxMinor >= 2);
+ else
+ caps.objectLabel = caps.ctxMajor > 4 || (caps.ctxMajor == 4 && caps.ctxMinor >= 3);
+ if (caps.objectLabel) {
+ glObjectLabel = reinterpret_cast<void(QOPENGLF_APIENTRYP)(GLenum, GLuint, GLsizei, const GLchar *)>(
+ ctx->getProcAddress(QByteArrayLiteral("glObjectLabel")));
+ }
+
+ if (caps.gles) {
+ // This is the third way to get multisample rendering with GLES. (1. is
+ // multisample render buffer -> resolve to texture; 2. is multisample
+ // texture with GLES 3.1; 3. is this, avoiding the explicit multisample
+ // buffer and should be more efficient with tiled architectures.
+ // Interesting also because 2. does not seem to work in practice on
+ // devices such as the Quest 3)
+ caps.glesMultisampleRenderToTexture = ctx->hasExtension("GL_EXT_multisampled_render_to_texture");
+ if (caps.glesMultisampleRenderToTexture) {
+ glFramebufferTexture2DMultisampleEXT = reinterpret_cast<void(QOPENGLF_APIENTRYP)(GLenum, GLenum, GLenum, GLuint, GLint, GLsizei)>(
+ ctx->getProcAddress(QByteArrayLiteral("glFramebufferTexture2DMultisampleEXT")));
+ }
+ caps.glesMultiviewMultisampleRenderToTexture = ctx->hasExtension("GL_OVR_multiview_multisampled_render_to_texture");
+ if (caps.glesMultiviewMultisampleRenderToTexture) {
+ glFramebufferTextureMultisampleMultiviewOVR = reinterpret_cast<void(QOPENGLF_APIENTRYP)(GLenum, GLenum, GLuint, GLint, GLsizei, GLint, GLsizei)>(
+ ctx->getProcAddress(QByteArrayLiteral("glFramebufferTextureMultisampleMultiviewOVR")));
+ }
+ } else {
+ caps.glesMultisampleRenderToTexture = false;
+ caps.glesMultiviewMultisampleRenderToTexture = false;
+ }
+
+ caps.unpackRowLength = !caps.gles || caps.ctxMajor >= 3;
+
nativeHandlesStruct.context = ctx;
contextLost = false;
@@ -980,6 +1113,11 @@ void QRhiGles2::destroy()
ensureContext();
executeDeferredReleases();
+ if (ofr.tsQueries[0]) {
+ f->glDeleteQueries(2, ofr.tsQueries);
+ ofr.tsQueries[0] = ofr.tsQueries[1] = 0;
+ }
+
if (vao) {
f->glDeleteVertexArrays(1, &vao);
vao = 0;
@@ -1017,6 +1155,7 @@ void QRhiGles2::executeDeferredReleases()
break;
case QRhiGles2::DeferredReleaseEntry::TextureRenderTarget:
f->glDeleteFramebuffers(1, &e.textureRenderTarget.framebuffer);
+ f->glDeleteTextures(1, &e.textureRenderTarget.nonMsaaThrowawayDepthTexture);
break;
default:
Q_UNREACHABLE();
@@ -1036,17 +1175,6 @@ QList<int> QRhiGles2::supportedSampleCounts() const
return supportedSampleCountList;
}
-int QRhiGles2::effectiveSampleCount(int sampleCount) const
-{
- // Stay compatible with QSurfaceFormat and friends where samples == 0 means the same as 1.
- const int s = qBound(1, sampleCount, 64);
- if (!supportedSampleCounts().contains(s)) {
- qWarning("Attempted to set unsupported sample count %d", sampleCount);
- return 1;
- }
- return s;
-}
-
QRhiSwapChain *QRhiGles2::createSwapChain()
{
return new QGles2SwapChain(this);
@@ -1171,13 +1299,13 @@ static inline void toGlTextureFormat(QRhiTexture::Format format, const QRhiGles2
*glintformat = GL_DEPTH_COMPONENT24;
*glsizedintformat = *glintformat;
*glformat = GL_DEPTH_COMPONENT;
- *gltype = GL_UNSIGNED_SHORT;
+ *gltype = GL_UNSIGNED_INT;
break;
case QRhiTexture::D24S8:
*glintformat = GL_DEPTH24_STENCIL8;
*glsizedintformat = *glintformat;
*glformat = GL_DEPTH_STENCIL;
- *gltype = GL_UNSIGNED_SHORT;
+ *gltype = GL_UNSIGNED_INT_24_8;
break;
case QRhiTexture::D32F:
*glintformat = GL_DEPTH_COMPONENT32F;
@@ -1254,7 +1382,7 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const
case QRhi::DebugMarkers:
return false;
case QRhi::Timestamps:
- return false;
+ return caps.timestamps;
case QRhi::Instancing:
return caps.instancing;
case QRhi::CustomInstanceStepRate:
@@ -1300,7 +1428,7 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const
case QRhi::PipelineCacheDataLoadSave:
return caps.programBinary;
case QRhi::ImageDataStride:
- return !caps.gles || caps.ctxMajor >= 3;
+ return caps.unpackRowLength;
case QRhi::RenderBufferImport:
return true;
case QRhi::ThreeDimensionalTextures:
@@ -1327,6 +1455,12 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const
return caps.texture1D;
case QRhi::ThreeDimensionalTextureMipmaps:
return caps.texture3D;
+ case QRhi::MultiView:
+ return caps.multiView && caps.maxTextureArraySize > 0;
+ case QRhi::TextureViewFormat:
+ return false;
+ case QRhi::ResolveDepthStencil:
+ return true;
default:
Q_UNREACHABLE_RETURN(false);
}
@@ -1901,10 +2035,14 @@ const QRhiNativeHandles *QRhiGles2::nativeHandles(QRhiCommandBuffer *cb)
return nullptr;
}
-static inline void addBoundaryCommand(QGles2CommandBuffer *cbD, QGles2CommandBuffer::Command::Cmd type)
+static inline void addBoundaryCommand(QGles2CommandBuffer *cbD, QGles2CommandBuffer::Command::Cmd type, GLuint tsQuery = 0)
{
QGles2CommandBuffer::Command &cmd(cbD->commands.get());
cmd.cmd = type;
+ if (type == QGles2CommandBuffer::Command::BeginFrame)
+ cmd.args.beginFrame.timestampQuery = tsQuery;
+ else if (type == QGles2CommandBuffer::Command::EndFrame)
+ cmd.args.endFrame.timestampQuery = tsQuery;
}
void QRhiGles2::beginExternal(QRhiCommandBuffer *cb)
@@ -1964,6 +2102,12 @@ void QRhiGles2::endExternal(QRhiCommandBuffer *cb)
enqueueBindFramebuffer(cbD->currentTarget, cbD);
}
+double QRhiGles2::lastCompletedGpuTime(QRhiCommandBuffer *cb)
+{
+ QGles2CommandBuffer *cbD = QRHI_RES(QGles2CommandBuffer, cb);
+ return cbD->lastGpuTime;
+}
+
QRhi::FrameOpResult QRhiGles2::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags)
{
QGles2SwapChain *swapChainD = QRHI_RES(QGles2SwapChain, swapChain);
@@ -1977,7 +2121,17 @@ QRhi::FrameOpResult QRhiGles2::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF
executeDeferredReleases();
swapChainD->cb.resetState();
- addBoundaryCommand(&swapChainD->cb, QGles2CommandBuffer::Command::BeginFrame);
+ if (swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex]) {
+ double elapsedSec = 0;
+ if (swapChainD->timestamps.tryQueryTimestamps(swapChainD->currentTimestampPairIndex, this, &elapsedSec))
+ swapChainD->cb.lastGpuTime = elapsedSec;
+ }
+
+ GLuint tsStart = swapChainD->timestamps.query[swapChainD->currentTimestampPairIndex * 2];
+ GLuint tsEnd = swapChainD->timestamps.query[swapChainD->currentTimestampPairIndex * 2 + 1];
+ const bool recordTimestamps = tsStart && tsEnd && !swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex];
+
+ addBoundaryCommand(&swapChainD->cb, QGles2CommandBuffer::Command::BeginFrame, recordTimestamps ? tsStart : 0);
return QRhi::FrameOpSuccess;
}
@@ -1987,7 +2141,15 @@ QRhi::FrameOpResult QRhiGles2::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
QGles2SwapChain *swapChainD = QRHI_RES(QGles2SwapChain, swapChain);
Q_ASSERT(currentSwapChain == swapChainD);
- addBoundaryCommand(&swapChainD->cb, QGles2CommandBuffer::Command::EndFrame);
+ GLuint tsStart = swapChainD->timestamps.query[swapChainD->currentTimestampPairIndex * 2];
+ GLuint tsEnd = swapChainD->timestamps.query[swapChainD->currentTimestampPairIndex * 2 + 1];
+ const bool recordTimestamps = tsStart && tsEnd && !swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex];
+ if (recordTimestamps) {
+ swapChainD->timestamps.active[swapChainD->currentTimestampPairIndex] = true;
+ swapChainD->currentTimestampPairIndex = (swapChainD->currentTimestampPairIndex + 1) % QGles2SwapChainTimestamps::TIMESTAMP_PAIRS;
+ }
+
+ addBoundaryCommand(&swapChainD->cb, QGles2CommandBuffer::Command::EndFrame, recordTimestamps ? tsEnd : 0);
if (!ensureContext(swapChainD->surface))
return contextLost ? QRhi::FrameOpDeviceLost : QRhi::FrameOpError;
@@ -2019,7 +2181,12 @@ QRhi::FrameOpResult QRhiGles2::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi:
executeDeferredReleases();
ofr.cbWrapper.resetState();
- addBoundaryCommand(&ofr.cbWrapper, QGles2CommandBuffer::Command::BeginFrame);
+ if (rhiFlags.testFlag(QRhi::EnableTimestamps) && caps.timestamps) {
+ if (!ofr.tsQueries[0])
+ f->glGenQueries(2, ofr.tsQueries);
+ }
+
+ addBoundaryCommand(&ofr.cbWrapper, QGles2CommandBuffer::Command::BeginFrame, ofr.tsQueries[0]);
*cb = &ofr.cbWrapper;
return QRhi::FrameOpSuccess;
@@ -2031,7 +2198,7 @@ QRhi::FrameOpResult QRhiGles2::endOffscreenFrame(QRhi::EndFrameFlags flags)
Q_ASSERT(ofr.active);
ofr.active = false;
- addBoundaryCommand(&ofr.cbWrapper, QGles2CommandBuffer::Command::EndFrame);
+ addBoundaryCommand(&ofr.cbWrapper, QGles2CommandBuffer::Command::EndFrame, ofr.tsQueries[1]);
if (!ensureContext())
return contextLost ? QRhi::FrameOpDeviceLost : QRhi::FrameOpError;
@@ -2044,6 +2211,16 @@ QRhi::FrameOpResult QRhiGles2::endOffscreenFrame(QRhi::EndFrameFlags flags)
// another, sharing context.
f->glFlush();
+ if (ofr.tsQueries[0]) {
+ quint64 timestamps[2];
+ glGetQueryObjectui64v(ofr.tsQueries[1], GL_QUERY_RESULT, &timestamps[1]);
+ glGetQueryObjectui64v(ofr.tsQueries[0], GL_QUERY_RESULT, &timestamps[0]);
+ if (timestamps[1] >= timestamps[0]) {
+ const quint64 nanoseconds = timestamps[1] - timestamps[0];
+ ofr.cbWrapper.lastGpuTime = nanoseconds / 1000000000.0; // seconds
+ }
+ }
+
return QRhi::FrameOpSuccess;
}
@@ -2163,17 +2340,15 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb
const GLenum effectiveTarget = faceTargetBase + (isCubeMap ? uint(layer) : 0u);
const QPoint dp = subresDesc.destinationTopLeft();
const QByteArray rawData = subresDesc.data();
- if (!subresDesc.image().isNull()) {
- QImage img = subresDesc.image();
- QSize size = img.size();
+
+ auto setCmdByNotCompressedData = [&](const void* data, QSize size, quint32 dataStride)
+ {
+ quint32 bytesPerLine = 0;
+ quint32 bytesPerPixel = 0;
+ textureFormatInfo(texD->m_format, size, &bytesPerLine, nullptr, &bytesPerPixel);
+
QGles2CommandBuffer::Command &cmd(cbD->commands.get());
cmd.cmd = QGles2CommandBuffer::Command::SubImage;
- if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
- const QPoint sp = subresDesc.sourceTopLeft();
- if (!subresDesc.sourceSize().isEmpty())
- size = subresDesc.sourceSize();
- img = img.copy(sp.x(), sp.y(), size.width(), size.height());
- }
cmd.args.subImage.target = texD->target;
cmd.args.subImage.texture = texD->texture;
cmd.args.subImage.faceTarget = effectiveTarget;
@@ -2185,10 +2360,38 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb
cmd.args.subImage.h = size.height();
cmd.args.subImage.glformat = texD->glformat;
cmd.args.subImage.gltype = texD->gltype;
- cmd.args.subImage.rowStartAlign = 4;
- cmd.args.subImage.rowLength = 0;
- cmd.args.subImage.data = cbD->retainImage(img);
+
+ if (dataStride == 0)
+ dataStride = bytesPerLine;
+
+ cmd.args.subImage.rowStartAlign = (dataStride & 3) ? 1 : 4;
+ cmd.args.subImage.rowLength = caps.unpackRowLength ? (bytesPerPixel ? dataStride / bytesPerPixel : 0) : 0;
+
+ cmd.args.subImage.data = data;
+ };
+
+ if (!subresDesc.image().isNull()) {
+ QImage img = subresDesc.image();
+ QSize size = img.size();
+ if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
+ const QPoint sp = subresDesc.sourceTopLeft();
+ if (!subresDesc.sourceSize().isEmpty())
+ size = subresDesc.sourceSize();
+
+ if (caps.unpackRowLength) {
+ cbD->retainImage(img);
+ // create a non-owning wrapper for the subimage
+ const uchar *data = img.constBits() + sp.y() * img.bytesPerLine() + sp.x() * (qMax(1, img.depth() / 8));
+ img = QImage(data, size.width(), size.height(), img.bytesPerLine(), img.format());
+ } else {
+ img = img.copy(sp.x(), sp.y(), size.width(), size.height());
+ }
+ }
+
+ setCmdByNotCompressedData(cbD->retainImage(img), size, img.bytesPerLine());
} else if (!rawData.isEmpty() && isCompressed) {
+ const int depth = qMax(1, texD->m_depth);
+ const int arraySize = qMax(0, texD->m_arraySize);
if ((texD->flags().testFlag(QRhiTexture::UsedAsCompressedAtlas) || is3D || isArray)
&& !texD->zeroInitialized)
{
@@ -2200,9 +2403,9 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb
quint32 byteSize = 0;
compressedFormatInfo(texD->m_format, texD->m_pixelSize, nullptr, &byteSize, nullptr);
if (is3D)
- byteSize *= texD->m_depth;
+ byteSize *= depth;
if (isArray)
- byteSize *= texD->m_arraySize;
+ byteSize *= arraySize;
QByteArray zeroBuf(byteSize, 0);
QGles2CommandBuffer::Command &cmd(cbD->commands.get());
cmd.cmd = QGles2CommandBuffer::Command::CompressedImage;
@@ -2212,9 +2415,8 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb
cmd.args.compressedImage.level = level;
cmd.args.compressedImage.glintformat = texD->glintformat;
cmd.args.compressedImage.w = texD->m_pixelSize.width();
- cmd.args.compressedImage.h =
- is1D && isArray ? texD->m_arraySize : texD->m_pixelSize.height();
- cmd.args.compressedImage.depth = is3D ? texD->m_depth : (isArray ? texD->m_arraySize : 0);
+ cmd.args.compressedImage.h = is1D && isArray ? arraySize : texD->m_pixelSize.height();
+ cmd.args.compressedImage.depth = is3D ? depth : (isArray ? arraySize : 0);
cmd.args.compressedImage.size = byteSize;
cmd.args.compressedImage.data = cbD->retainData(zeroBuf);
texD->zeroInitialized = true;
@@ -2246,39 +2448,16 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb
cmd.args.compressedImage.level = level;
cmd.args.compressedImage.glintformat = texD->glintformat;
cmd.args.compressedImage.w = size.width();
- cmd.args.compressedImage.h = is1D && isArray ? texD->m_arraySize : size.height();
- cmd.args.compressedImage.depth = is3D ? texD->m_depth : (isArray ? texD->m_arraySize : 0);
+ cmd.args.compressedImage.h = is1D && isArray ? arraySize : size.height();
+ cmd.args.compressedImage.depth = is3D ? depth : (isArray ? arraySize : 0);
cmd.args.compressedImage.size = rawData.size();
cmd.args.compressedImage.data = cbD->retainData(rawData);
}
} else if (!rawData.isEmpty()) {
const QSize size = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize)
: subresDesc.sourceSize();
- quint32 bytesPerLine = 0;
- quint32 bytesPerPixel = 0;
- textureFormatInfo(texD->m_format, size, &bytesPerLine, nullptr, &bytesPerPixel);
- QGles2CommandBuffer::Command &cmd(cbD->commands.get());
- cmd.cmd = QGles2CommandBuffer::Command::SubImage;
- cmd.args.subImage.target = texD->target;
- cmd.args.subImage.texture = texD->texture;
- cmd.args.subImage.faceTarget = effectiveTarget;
- cmd.args.subImage.level = level;
- cmd.args.subImage.dx = dp.x();
- cmd.args.subImage.dy = is1D && isArray ? layer : dp.y();
- cmd.args.subImage.dz = is3D || isArray ? layer : 0;
- cmd.args.subImage.w = size.width();
- cmd.args.subImage.h = size.height();
- cmd.args.subImage.glformat = texD->glformat;
- cmd.args.subImage.gltype = texD->gltype;
- // Default unpack alignment (row start alignment
- // requirement) is 4. QImage guarantees 4 byte aligned
- // row starts, but our raw data here does not.
- cmd.args.subImage.rowStartAlign = (bytesPerLine & 3) ? 1 : 4;
- if (subresDesc.dataStride() && bytesPerPixel)
- cmd.args.subImage.rowLength = subresDesc.dataStride() / bytesPerPixel;
- else
- cmd.args.subImage.rowLength = 0;
- cmd.args.subImage.data = cbD->retainData(rawData);
+
+ setCmdByNotCompressedData(cbD->retainData(rawData), size, subresDesc.dataStride());
} else {
qWarning("Invalid texture upload for %p layer=%d mip=%d", texD, layer, level);
}
@@ -2797,6 +2976,8 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
const QGles2CommandBuffer::Command &cmd(*it);
switch (cmd.cmd) {
case QGles2CommandBuffer::Command::BeginFrame:
+ if (cmd.args.beginFrame.timestampQuery)
+ glQueryCounter(cmd.args.beginFrame.timestampQuery, GL_TIMESTAMP);
if (caps.coreProfile) {
if (!vao)
f->glGenVertexArrays(1, &vao);
@@ -2823,6 +3004,8 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
#endif
if (vao)
f->glBindVertexArray(0);
+ if (cmd.args.endFrame.timestampQuery)
+ glQueryCounter(cmd.args.endFrame.timestampQuery, GL_TIMESTAMP);
break;
case QGles2CommandBuffer::Command::ResetFrame:
if (vao)
@@ -2967,6 +3150,38 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
type = GL_HALF_FLOAT;
size = 1;
break;
+ case QRhiVertexInputAttribute::UShort4:
+ type = GL_UNSIGNED_SHORT;
+ size = 4;
+ break;
+ case QRhiVertexInputAttribute::UShort3:
+ type = GL_UNSIGNED_SHORT;
+ size = 3;
+ break;
+ case QRhiVertexInputAttribute::UShort2:
+ type = GL_UNSIGNED_SHORT;
+ size = 2;
+ break;
+ case QRhiVertexInputAttribute::UShort:
+ type = GL_UNSIGNED_SHORT;
+ size = 1;
+ break;
+ case QRhiVertexInputAttribute::SShort4:
+ type = GL_SHORT;
+ size = 4;
+ break;
+ case QRhiVertexInputAttribute::SShort3:
+ type = GL_SHORT;
+ size = 3;
+ break;
+ case QRhiVertexInputAttribute::SShort2:
+ type = GL_SHORT;
+ size = 2;
+ break;
+ case QRhiVertexInputAttribute::SShort:
+ type = GL_SHORT;
+ size = 1;
+ break;
default:
break;
}
@@ -3109,7 +3324,7 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
}
if (caps.hasDrawBuffersFunc)
f->glDrawBuffers(bufs.count(), bufs.constData());
- if (caps.srgbCapableDefaultFramebuffer) {
+ if (caps.srgbWriteControl) {
if (cmd.args.bindFramebuffer.srgb)
f->glEnable(GL_FRAMEBUFFER_SRGB);
else
@@ -3141,7 +3356,7 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
break;
case QGles2CommandBuffer::Command::GetBufferSubData:
{
- QRhiBufferReadbackResult *result = cmd.args.getBufferSubData.result;
+ QRhiReadbackResult *result = cmd.args.getBufferSubData.result;
bindVertexIndexBufferWithStateReset(&state, f, cmd.args.getBufferSubData.target, cmd.args.getBufferSubData.buffer);
if (caps.gles) {
if (caps.properMapBuffer) {
@@ -3264,6 +3479,14 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
result->data.resize(w * h * 8);
f->glReadPixels(0, 0, w, h, GL_RGBA, GL_HALF_FLOAT, result->data.data());
break;
+ case QRhiTexture::R16F:
+ result->data.resize(w * h * 2);
+ f->glReadPixels(0, 0, w, h, GL_RED, GL_HALF_FLOAT, result->data.data());
+ break;
+ case QRhiTexture::R32F:
+ result->data.resize(w * h * 4);
+ f->glReadPixels(0, 0, w, h, GL_RED, GL_FLOAT, result->data.data());
+ break;
case QRhiTexture::RGBA32F:
result->data.resize(w * h * 16);
f->glReadPixels(0, 0, w, h, GL_RGBA, GL_FLOAT, result->data.data());
@@ -3362,23 +3585,128 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
break;
case QGles2CommandBuffer::Command::BlitFromRenderbuffer:
{
+ // Altering the scissor state, so reset the stored state, although
+ // not strictly required as long as blit is done in endPass() only.
+ cbD->graphicsPassState.reset();
+ f->glDisable(GL_SCISSOR_TEST);
GLuint fbo[2];
f->glGenFramebuffers(2, fbo);
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo[0]);
- f->glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_RENDERBUFFER, cmd.args.blitFromRb.renderbuffer);
+ const bool ds = cmd.args.blitFromRenderbuffer.isDepthStencil;
+ if (ds) {
+ f->glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ GL_RENDERBUFFER, cmd.args.blitFromRenderbuffer.renderbuffer);
+ f->glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+ GL_RENDERBUFFER, cmd.args.blitFromRenderbuffer.renderbuffer);
+ } else {
+ f->glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_RENDERBUFFER, cmd.args.blitFromRenderbuffer.renderbuffer);
+ }
f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo[1]);
- if (cmd.args.blitFromRb.target == GL_TEXTURE_3D || cmd.args.blitFromRb.target == GL_TEXTURE_2D_ARRAY) {
- f->glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- cmd.args.blitFromRb.texture, cmd.args.blitFromRb.dstLevel, cmd.args.blitFromRb.dstLayer);
+ if (cmd.args.blitFromRenderbuffer.target == GL_TEXTURE_3D || cmd.args.blitFromRenderbuffer.target == GL_TEXTURE_2D_ARRAY) {
+ if (ds) {
+ f->glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ cmd.args.blitFromRenderbuffer.dstTexture,
+ cmd.args.blitFromRenderbuffer.dstLevel,
+ cmd.args.blitFromRenderbuffer.dstLayer);
+ f->glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+ cmd.args.blitFromRenderbuffer.dstTexture,
+ cmd.args.blitFromRenderbuffer.dstLevel,
+ cmd.args.blitFromRenderbuffer.dstLayer);
+ } else {
+ f->glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ cmd.args.blitFromRenderbuffer.dstTexture,
+ cmd.args.blitFromRenderbuffer.dstLevel,
+ cmd.args.blitFromRenderbuffer.dstLayer);
+ }
} else {
- f->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, cmd.args.blitFromRb.target,
- cmd.args.blitFromRb.texture, cmd.args.blitFromRb.dstLevel);
+ if (ds) {
+ f->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, cmd.args.blitFromRenderbuffer.target,
+ cmd.args.blitFromRenderbuffer.dstTexture, cmd.args.blitFromRenderbuffer.dstLevel);
+ f->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, cmd.args.blitFromRenderbuffer.target,
+ cmd.args.blitFromRenderbuffer.dstTexture, cmd.args.blitFromRenderbuffer.dstLevel);
+ } else {
+ f->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, cmd.args.blitFromRenderbuffer.target,
+ cmd.args.blitFromRenderbuffer.dstTexture, cmd.args.blitFromRenderbuffer.dstLevel);
+ }
}
- f->glBlitFramebuffer(0, 0, cmd.args.blitFromRb.w, cmd.args.blitFromRb.h,
- 0, 0, cmd.args.blitFromRb.w, cmd.args.blitFromRb.h,
- GL_COLOR_BUFFER_BIT,
- GL_LINEAR);
+ f->glBlitFramebuffer(0, 0, cmd.args.blitFromRenderbuffer.w, cmd.args.blitFromRenderbuffer.h,
+ 0, 0, cmd.args.blitFromRenderbuffer.w, cmd.args.blitFromRenderbuffer.h,
+ ds ? GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT : GL_COLOR_BUFFER_BIT,
+ GL_NEAREST); // Qt 5 used Nearest when resolving samples, stick to that
+ f->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject());
+ f->glDeleteFramebuffers(2, fbo);
+ }
+ break;
+ case QGles2CommandBuffer::Command::BlitFromTexture:
+ {
+ // Altering the scissor state, so reset the stored state, although
+ // not strictly required as long as blit is done in endPass() only.
+ cbD->graphicsPassState.reset();
+ f->glDisable(GL_SCISSOR_TEST);
+ GLuint fbo[2];
+ f->glGenFramebuffers(2, fbo);
+ f->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo[0]);
+ const bool ds = cmd.args.blitFromTexture.isDepthStencil;
+ if (cmd.args.blitFromTexture.srcTarget == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) {
+ if (ds) {
+ f->glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ cmd.args.blitFromTexture.srcTexture,
+ cmd.args.blitFromTexture.srcLevel,
+ cmd.args.blitFromTexture.srcLayer);
+ f->glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+ cmd.args.blitFromTexture.srcTexture,
+ cmd.args.blitFromTexture.srcLevel,
+ cmd.args.blitFromTexture.srcLayer);
+ } else {
+ f->glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ cmd.args.blitFromTexture.srcTexture,
+ cmd.args.blitFromTexture.srcLevel,
+ cmd.args.blitFromTexture.srcLayer);
+ }
+ } else {
+ if (ds) {
+ f->glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, cmd.args.blitFromTexture.srcTarget,
+ cmd.args.blitFromTexture.srcTexture, cmd.args.blitFromTexture.srcLevel);
+ f->glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, cmd.args.blitFromTexture.srcTarget,
+ cmd.args.blitFromTexture.srcTexture, cmd.args.blitFromTexture.srcLevel);
+ } else {
+ f->glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, cmd.args.blitFromTexture.srcTarget,
+ cmd.args.blitFromTexture.srcTexture, cmd.args.blitFromTexture.srcLevel);
+ }
+ }
+ f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo[1]);
+ if (cmd.args.blitFromTexture.dstTarget == GL_TEXTURE_3D || cmd.args.blitFromTexture.dstTarget == GL_TEXTURE_2D_ARRAY) {
+ if (ds) {
+ f->glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+ cmd.args.blitFromTexture.dstTexture,
+ cmd.args.blitFromTexture.dstLevel,
+ cmd.args.blitFromTexture.dstLayer);
+ f->glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+ cmd.args.blitFromTexture.dstTexture,
+ cmd.args.blitFromTexture.dstLevel,
+ cmd.args.blitFromTexture.dstLayer);
+ } else {
+ f->glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ cmd.args.blitFromTexture.dstTexture,
+ cmd.args.blitFromTexture.dstLevel,
+ cmd.args.blitFromTexture.dstLayer);
+ }
+ } else {
+ if (ds) {
+ f->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, cmd.args.blitFromTexture.dstTarget,
+ cmd.args.blitFromTexture.dstTexture, cmd.args.blitFromTexture.dstLevel);
+ f->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, cmd.args.blitFromTexture.dstTarget,
+ cmd.args.blitFromTexture.dstTexture, cmd.args.blitFromTexture.dstLevel);
+ } else {
+ f->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, cmd.args.blitFromTexture.dstTarget,
+ cmd.args.blitFromTexture.dstTexture, cmd.args.blitFromTexture.dstLevel);
+ }
+ }
+ f->glBlitFramebuffer(0, 0, cmd.args.blitFromTexture.w, cmd.args.blitFromTexture.h,
+ 0, 0, cmd.args.blitFromTexture.w, cmd.args.blitFromTexture.h,
+ ds ? GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT : GL_COLOR_BUFFER_BIT,
+ GL_NEAREST); // Qt 5 used Nearest when resolving samples, stick to that
f->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject());
f->glDeleteFramebuffers(2, fbo);
}
@@ -3427,6 +3755,13 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
if (caps.compute)
f->glMemoryBarrier(cmd.args.barrier.barriers);
break;
+ case QGles2CommandBuffer::Command::InvalidateFramebuffer:
+ if (caps.gles && caps.ctxMajor >= 3) {
+ f->glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER,
+ cmd.args.invalidateFramebuffer.attCount,
+ cmd.args.invalidateFramebuffer.att);
+ }
+ break;
default:
break;
}
@@ -4225,32 +4560,129 @@ void QRhiGles2::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resource
if (cbD->currentTarget->resourceType() == QRhiResource::TextureRenderTarget) {
QGles2TextureRenderTarget *rtTex = QRHI_RES(QGles2TextureRenderTarget, cbD->currentTarget);
- if (rtTex->m_desc.cbeginColorAttachments() != rtTex->m_desc.cendColorAttachments()) {
- // handle only 1 color attachment and only (msaa) renderbuffer
- const QRhiColorAttachment &colorAtt(*rtTex->m_desc.cbeginColorAttachments());
- if (colorAtt.resolveTexture()) {
- Q_ASSERT(colorAtt.renderBuffer());
+ for (auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
+ it != itEnd; ++it)
+ {
+ const QRhiColorAttachment &colorAtt(*it);
+ if (!colorAtt.resolveTexture())
+ continue;
+
+ QGles2Texture *resolveTexD = QRHI_RES(QGles2Texture, colorAtt.resolveTexture());
+ const QSize size = resolveTexD->pixelSize();
+ if (colorAtt.renderBuffer()) {
QGles2RenderBuffer *rbD = QRHI_RES(QGles2RenderBuffer, colorAtt.renderBuffer());
- const QSize size = colorAtt.resolveTexture()->pixelSize();
if (rbD->pixelSize() != size) {
qWarning("Resolve source (%dx%d) and target (%dx%d) size does not match",
rbD->pixelSize().width(), rbD->pixelSize().height(), size.width(), size.height());
}
QGles2CommandBuffer::Command &cmd(cbD->commands.get());
cmd.cmd = QGles2CommandBuffer::Command::BlitFromRenderbuffer;
- cmd.args.blitFromRb.renderbuffer = rbD->renderbuffer;
- cmd.args.blitFromRb.w = size.width();
- cmd.args.blitFromRb.h = size.height();
- QGles2Texture *colorTexD = QRHI_RES(QGles2Texture, colorAtt.resolveTexture());
- if (colorTexD->m_flags.testFlag(QRhiTexture::CubeMap))
- cmd.args.blitFromRb.target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + uint(colorAtt.resolveLayer());
+ cmd.args.blitFromRenderbuffer.renderbuffer = rbD->renderbuffer;
+ cmd.args.blitFromRenderbuffer.w = size.width();
+ cmd.args.blitFromRenderbuffer.h = size.height();
+ if (resolveTexD->m_flags.testFlag(QRhiTexture::CubeMap))
+ cmd.args.blitFromRenderbuffer.target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + uint(colorAtt.resolveLayer());
else
- cmd.args.blitFromRb.target = colorTexD->target;
- cmd.args.blitFromRb.texture = colorTexD->texture;
- cmd.args.blitFromRb.dstLevel = colorAtt.resolveLevel();
- const bool hasZ = colorTexD->m_flags.testFlag(QRhiTexture::ThreeDimensional)
- || colorTexD->m_flags.testFlag(QRhiTexture::TextureArray);
- cmd.args.blitFromRb.dstLayer = hasZ ? colorAtt.resolveLayer() : 0;
+ cmd.args.blitFromRenderbuffer.target = resolveTexD->target;
+ cmd.args.blitFromRenderbuffer.dstTexture = resolveTexD->texture;
+ cmd.args.blitFromRenderbuffer.dstLevel = colorAtt.resolveLevel();
+ const bool hasZ = resolveTexD->m_flags.testFlag(QRhiTexture::ThreeDimensional)
+ || resolveTexD->m_flags.testFlag(QRhiTexture::TextureArray);
+ cmd.args.blitFromRenderbuffer.dstLayer = hasZ ? colorAtt.resolveLayer() : 0;
+ cmd.args.blitFromRenderbuffer.isDepthStencil = false;
+ } else if (caps.glesMultisampleRenderToTexture) {
+ // Nothing to do, resolving into colorAtt.resolveTexture() is automatic,
+ // colorAtt.texture() is in fact not used for anything.
+ } else {
+ Q_ASSERT(colorAtt.texture());
+ QGles2Texture *texD = QRHI_RES(QGles2Texture, colorAtt.texture());
+ if (texD->pixelSize() != size) {
+ qWarning("Resolve source (%dx%d) and target (%dx%d) size does not match",
+ texD->pixelSize().width(), texD->pixelSize().height(), size.width(), size.height());
+ }
+ const int resolveCount = colorAtt.multiViewCount() >= 2 ? colorAtt.multiViewCount() : 1;
+ for (int resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
+ const int srcLayer = colorAtt.layer() + resolveIdx;
+ const int dstLayer = colorAtt.resolveLayer() + resolveIdx;
+ QGles2CommandBuffer::Command &cmd(cbD->commands.get());
+ cmd.cmd = QGles2CommandBuffer::Command::BlitFromTexture;
+ if (texD->m_flags.testFlag(QRhiTexture::CubeMap))
+ cmd.args.blitFromTexture.srcTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + uint(srcLayer);
+ else
+ cmd.args.blitFromTexture.srcTarget = texD->target;
+ cmd.args.blitFromTexture.srcTexture = texD->texture;
+ cmd.args.blitFromTexture.srcLevel = colorAtt.level();
+ cmd.args.blitFromTexture.srcLayer = 0;
+ if (texD->m_flags.testFlag(QRhiTexture::ThreeDimensional) || texD->m_flags.testFlag(QRhiTexture::TextureArray))
+ cmd.args.blitFromTexture.srcLayer = srcLayer;
+ cmd.args.blitFromTexture.w = size.width();
+ cmd.args.blitFromTexture.h = size.height();
+ if (resolveTexD->m_flags.testFlag(QRhiTexture::CubeMap))
+ cmd.args.blitFromTexture.dstTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + uint(dstLayer);
+ else
+ cmd.args.blitFromTexture.dstTarget = resolveTexD->target;
+ cmd.args.blitFromTexture.dstTexture = resolveTexD->texture;
+ cmd.args.blitFromTexture.dstLevel = colorAtt.resolveLevel();
+ cmd.args.blitFromTexture.dstLayer = 0;
+ if (resolveTexD->m_flags.testFlag(QRhiTexture::ThreeDimensional) || resolveTexD->m_flags.testFlag(QRhiTexture::TextureArray))
+ cmd.args.blitFromTexture.dstLayer = dstLayer;
+ cmd.args.blitFromTexture.isDepthStencil = false;
+ }
+ }
+ }
+
+ if (rtTex->m_desc.depthResolveTexture()) {
+ QGles2Texture *depthResolveTexD = QRHI_RES(QGles2Texture, rtTex->m_desc.depthResolveTexture());
+ const QSize size = depthResolveTexD->pixelSize();
+ if (rtTex->m_desc.depthStencilBuffer()) {
+ QGles2RenderBuffer *rbD = QRHI_RES(QGles2RenderBuffer, rtTex->m_desc.depthStencilBuffer());
+ QGles2CommandBuffer::Command &cmd(cbD->commands.get());
+ cmd.cmd = QGles2CommandBuffer::Command::BlitFromRenderbuffer;
+ cmd.args.blitFromRenderbuffer.renderbuffer = rbD->renderbuffer;
+ cmd.args.blitFromRenderbuffer.w = size.width();
+ cmd.args.blitFromRenderbuffer.h = size.height();
+ cmd.args.blitFromRenderbuffer.target = depthResolveTexD->target;
+ cmd.args.blitFromRenderbuffer.dstTexture = depthResolveTexD->texture;
+ cmd.args.blitFromRenderbuffer.dstLevel = 0;
+ cmd.args.blitFromRenderbuffer.dstLayer = 0;
+ cmd.args.blitFromRenderbuffer.isDepthStencil = true;
+ } else if (caps.glesMultisampleRenderToTexture) {
+ // Nothing to do, resolving into depthResolveTexture() is automatic.
+ } else {
+ QGles2Texture *depthTexD = QRHI_RES(QGles2Texture, rtTex->m_desc.depthTexture());
+ const int resolveCount = depthTexD->arraySize() >= 2 ? depthTexD->arraySize() : 1;
+ for (int resolveIdx = 0; resolveIdx < resolveCount; ++resolveIdx) {
+ QGles2CommandBuffer::Command &cmd(cbD->commands.get());
+ cmd.cmd = QGles2CommandBuffer::Command::BlitFromTexture;
+ cmd.args.blitFromTexture.srcTarget = depthTexD->target;
+ cmd.args.blitFromTexture.srcTexture = depthTexD->texture;
+ cmd.args.blitFromTexture.srcLevel = 0;
+ cmd.args.blitFromTexture.srcLayer = resolveIdx;
+ cmd.args.blitFromTexture.w = size.width();
+ cmd.args.blitFromTexture.h = size.height();
+ cmd.args.blitFromTexture.dstTarget = depthResolveTexD->target;
+ cmd.args.blitFromTexture.dstTexture = depthResolveTexD->texture;
+ cmd.args.blitFromTexture.dstLevel = 0;
+ cmd.args.blitFromTexture.dstLayer = resolveIdx;
+ cmd.args.blitFromTexture.isDepthStencil = true;
+ }
+ }
+ }
+
+ const bool mayDiscardDepthStencil =
+ (rtTex->m_desc.depthStencilBuffer()
+ || (rtTex->m_desc.depthTexture() && rtTex->m_flags.testFlag(QRhiTextureRenderTarget::DoNotStoreDepthStencilContents)))
+ && !rtTex->m_desc.depthResolveTexture();
+ if (mayDiscardDepthStencil) {
+ QGles2CommandBuffer::Command &cmd(cbD->commands.get());
+ cmd.cmd = QGles2CommandBuffer::Command::InvalidateFramebuffer;
+ if (caps.needsDepthStencilCombinedAttach) {
+ cmd.args.invalidateFramebuffer.attCount = 1;
+ cmd.args.invalidateFramebuffer.att[0] = GL_DEPTH_STENCIL_ATTACHMENT;
+ } else {
+ cmd.args.invalidateFramebuffer.attCount = 2;
+ cmd.args.invalidateFramebuffer.att[0] = GL_DEPTH_ATTACHMENT;
+ cmd.args.invalidateFramebuffer.att[1] = GL_STENCIL_ATTACHMENT;
}
}
}
@@ -4885,6 +5317,9 @@ bool QGles2Buffer::create()
rhiD->f->glBindBuffer(targetForDataOps, buffer);
rhiD->f->glBufferData(targetForDataOps, nonZeroSize, nullptr, m_type == Dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
+ if (rhiD->glObjectLabel)
+ rhiD->glObjectLabel(GL_BUFFER, buffer, -1, m_objectName.constData());
+
usageState.access = AccessNone;
rhiD->registerResource(this);
@@ -5039,6 +5474,9 @@ bool QGles2RenderBuffer::create()
break;
}
+ if (rhiD->glObjectLabel)
+ rhiD->glObjectLabel(GL_RENDERBUFFER, renderbuffer, -1, m_objectName.constData());
+
owns = true;
generation += 1;
rhiD->registerResource(this);
@@ -5155,12 +5593,10 @@ bool QGles2Texture::prepareCreate(QSize *adjustedSize)
return false;
}
- m_depth = qMax(1, m_depth);
if (m_depth > 1 && !is3D) {
qWarning("Texture cannot have a depth of %d when it is not 3D", m_depth);
return false;
}
- m_arraySize = qMax(0, m_arraySize);
if (m_arraySize > 0 && !isArray) {
qWarning("Texture cannot have an array size of %d when it is not an array", m_arraySize);
return false;
@@ -5171,7 +5607,7 @@ bool QGles2Texture::prepareCreate(QSize *adjustedSize)
}
target = isCube ? GL_TEXTURE_CUBE_MAP
- : m_sampleCount > 1 ? GL_TEXTURE_2D_MULTISAMPLE
+ : m_sampleCount > 1 ? (isArray ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_MULTISAMPLE)
: (is3D ? GL_TEXTURE_3D
: (is1D ? (isArray ? GL_TEXTURE_1D_ARRAY : GL_TEXTURE_1D)
: (isArray ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D)));
@@ -5235,13 +5671,13 @@ bool QGles2Texture::create()
const QSize mipSize = rhiD->q->sizeForMipLevel(level, size);
if (isArray)
rhiD->f->glTexImage2D(target, level, GLint(glintformat), mipSize.width(),
- m_arraySize, 0, glformat, gltype, nullptr);
+ qMax(0, m_arraySize), 0, glformat, gltype, nullptr);
else
rhiD->glTexImage1D(target, level, GLint(glintformat), mipSize.width(), 0,
glformat, gltype, nullptr);
}
} else if (is3D || isArray) {
- const int layerCount = is3D ? m_depth : m_arraySize;
+ const int layerCount = is3D ? qMax(1, m_depth) : qMax(0, m_arraySize);
if (hasMipMaps) {
for (int level = 0; level != mipLevelCount; ++level) {
const QSize mipSize = rhiD->q->sizeForMipLevel(level, size);
@@ -5263,8 +5699,16 @@ bool QGles2Texture::create()
}
}
} else {
- rhiD->f->glTexImage2D(target, 0, GLint(glintformat), size.width(), size.height(),
- 0, glformat, gltype, nullptr);
+ // 2D texture. For multisample textures the GLES 3.1
+ // glStorage2DMultisample must be used for portability.
+ if (m_sampleCount > 1 && rhiD->caps.multisampledTexture) {
+ // internal format must be sized
+ rhiD->f->glTexStorage2DMultisample(target, m_sampleCount, glsizedintformat,
+ size.width(), size.height(), GL_TRUE);
+ } else {
+ rhiD->f->glTexImage2D(target, 0, GLint(glintformat), size.width(), size.height(),
+ 0, glformat, gltype, nullptr);
+ }
}
} else {
// Must be specified with immutable storage functions otherwise
@@ -5273,10 +5717,14 @@ bool QGles2Texture::create()
if (is1D && !isArray)
rhiD->glTexStorage1D(target, mipLevelCount, glsizedintformat, size.width());
else if (!is1D && (is3D || isArray))
- rhiD->f->glTexStorage3D(target, mipLevelCount, glsizedintformat, size.width(), size.height(), is3D ? m_depth : m_arraySize);
+ rhiD->f->glTexStorage3D(target, mipLevelCount, glsizedintformat, size.width(), size.height(),
+ is3D ? qMax(1, m_depth) : qMax(0, m_arraySize));
+ else if (m_sampleCount > 1)
+ rhiD->f->glTexStorage2DMultisample(target, m_sampleCount, glsizedintformat,
+ size.width(), size.height(), GL_TRUE);
else
rhiD->f->glTexStorage2D(target, mipLevelCount, glsizedintformat, size.width(),
- is1D ? m_arraySize : size.height());
+ is1D ? qMax(0, m_arraySize) : size.height());
}
specified = true;
} else {
@@ -5286,6 +5734,9 @@ bool QGles2Texture::create()
specified = false;
}
+ if (rhiD->glObjectLabel)
+ rhiD->glObjectLabel(GL_TEXTURE, texture, -1, m_objectName.constData());
+
owns = true;
generation += 1;
@@ -5332,7 +5783,9 @@ QGles2Sampler::~QGles2Sampler()
void QGles2Sampler::destroy()
{
- // nothing to do here
+ QRHI_RES_RHI(QRhiGles2);
+ if (rhiD)
+ rhiD->unregisterResource(this);
}
bool QGles2Sampler::create()
@@ -5345,6 +5798,8 @@ bool QGles2Sampler::create()
d.gltexcomparefunc = toGlTextureCompareFunc(m_compareOp);
generation += 1;
+ QRHI_RES_RHI(QRhiGles2);
+ rhiD->registerResource(this, false);
return true;
}
@@ -5361,7 +5816,9 @@ QGles2RenderPassDescriptor::~QGles2RenderPassDescriptor()
void QGles2RenderPassDescriptor::destroy()
{
- // nothing to do here
+ QRHI_RES_RHI(QRhiGles2);
+ if (rhiD)
+ rhiD->unregisterResource(this);
}
bool QGles2RenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const
@@ -5372,7 +5829,10 @@ bool QGles2RenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *ot
QRhiRenderPassDescriptor *QGles2RenderPassDescriptor::newCompatibleRenderPassDescriptor() const
{
- return new QGles2RenderPassDescriptor(m_rhi);
+ QGles2RenderPassDescriptor *rpD = new QGles2RenderPassDescriptor(m_rhi);
+ QRHI_RES_RHI(QRhiGles2);
+ rhiD->registerResource(rpD, false);
+ return rpD;
}
QVector<quint32> QGles2RenderPassDescriptor::serializedFormat() const
@@ -5433,8 +5893,10 @@ void QGles2TextureRenderTarget::destroy()
e.type = QRhiGles2::DeferredReleaseEntry::TextureRenderTarget;
e.textureRenderTarget.framebuffer = framebuffer;
+ e.textureRenderTarget.nonMsaaThrowawayDepthTexture = nonMsaaThrowawayDepthTexture;
framebuffer = 0;
+ nonMsaaThrowawayDepthTexture = 0;
QRHI_RES_RHI(QRhiGles2);
if (rhiD) {
@@ -5445,7 +5907,10 @@ void QGles2TextureRenderTarget::destroy()
QRhiRenderPassDescriptor *QGles2TextureRenderTarget::newCompatibleRenderPassDescriptor()
{
- return new QGles2RenderPassDescriptor(m_rhi);
+ QGles2RenderPassDescriptor *rpD = new QGles2RenderPassDescriptor(m_rhi);
+ QRHI_RES_RHI(QRhiGles2);
+ rhiD->registerResource(rpD, false);
+ return rpD;
}
bool QGles2TextureRenderTarget::create()
@@ -5478,6 +5943,7 @@ bool QGles2TextureRenderTarget::create()
d.colorAttCount = 0;
int attIndex = 0;
+ int multiViewCount = 0;
for (auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
d.colorAttCount += 1;
const QRhiColorAttachment &colorAtt(*it);
@@ -5488,20 +5954,56 @@ bool QGles2TextureRenderTarget::create()
QGles2Texture *texD = QRHI_RES(QGles2Texture, texture);
Q_ASSERT(texD->texture && texD->specified);
if (texD->flags().testFlag(QRhiTexture::ThreeDimensional) || texD->flags().testFlag(QRhiTexture::TextureArray)) {
- rhiD->f->glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), texD->texture,
- colorAtt.level(), colorAtt.layer());
+ if (colorAtt.multiViewCount() < 2) {
+ rhiD->f->glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), texD->texture,
+ colorAtt.level(), colorAtt.layer());
+ } else {
+ multiViewCount = colorAtt.multiViewCount();
+ if (texD->sampleCount() > 1 && rhiD->caps.glesMultiviewMultisampleRenderToTexture && colorAtt.resolveTexture()) {
+ // Special path for GLES and GL_OVR_multiview_multisampled_render_to_texture:
+ // ignore the color attachment's (multisample) texture
+ // array and give the resolve texture array to GL. (no
+ // explicit resolving is needed by us later on)
+ QGles2Texture *resolveTexD = QRHI_RES(QGles2Texture, colorAtt.resolveTexture());
+ rhiD->glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0 + uint(attIndex),
+ resolveTexD->texture,
+ colorAtt.resolveLevel(),
+ texD->sampleCount(),
+ colorAtt.resolveLayer(),
+ multiViewCount);
+ } else {
+ rhiD->glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0 + uint(attIndex),
+ texD->texture,
+ colorAtt.level(),
+ colorAtt.layer(),
+ multiViewCount);
+ }
+ }
} else if (texD->flags().testFlag(QRhiTexture::OneDimensional)) {
rhiD->glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex),
texD->target + uint(colorAtt.layer()), texD->texture,
colorAtt.level());
} else {
- const GLenum faceTargetBase = texD->flags().testFlag(QRhiTexture::CubeMap) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : texD->target;
- rhiD->f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), faceTargetBase + uint(colorAtt.layer()),
- texD->texture, colorAtt.level());
+ if (texD->sampleCount() > 1 && rhiD->caps.glesMultisampleRenderToTexture && colorAtt.resolveTexture()) {
+ // Special path for GLES and GL_EXT_multisampled_render_to_texture:
+ // ignore the color attachment's (multisample) texture and
+ // give the resolve texture to GL. (no explicit resolving is
+ // needed by us later on)
+ QGles2Texture *resolveTexD = QRHI_RES(QGles2Texture, colorAtt.resolveTexture());
+ const GLenum faceTargetBase = resolveTexD->flags().testFlag(QRhiTexture::CubeMap) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : resolveTexD->target;
+ rhiD->glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), faceTargetBase + uint(colorAtt.resolveLayer()),
+ resolveTexD->texture, colorAtt.level(), texD->sampleCount());
+ } else {
+ const GLenum faceTargetBase = texD->flags().testFlag(QRhiTexture::CubeMap) ? GL_TEXTURE_CUBE_MAP_POSITIVE_X : texD->target;
+ rhiD->f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + uint(attIndex), faceTargetBase + uint(colorAtt.layer()),
+ texD->texture, colorAtt.level());
+ }
}
if (attIndex == 0) {
d.pixelSize = rhiD->q->sizeForMipLevel(colorAtt.level(), texD->pixelSize());
- d.sampleCount = 1;
+ d.sampleCount = texD->sampleCount();
}
} else if (renderBuffer) {
QGles2RenderBuffer *rbD = QRHI_RES(QGles2RenderBuffer, renderBuffer);
@@ -5522,12 +6024,14 @@ bool QGles2TextureRenderTarget::create()
} else {
rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
depthRbD->renderbuffer);
- if (depthRbD->stencilRenderbuffer)
+ if (depthRbD->stencilRenderbuffer) {
rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
depthRbD->stencilRenderbuffer);
- else // packed
+ } else {
+ // packed depth-stencil
rhiD->f->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
depthRbD->renderbuffer);
+ }
}
if (d.colorAttCount == 0) {
d.pixelSize = depthRbD->pixelSize();
@@ -5535,11 +6039,105 @@ bool QGles2TextureRenderTarget::create()
}
} else {
QGles2Texture *depthTexD = QRHI_RES(QGles2Texture, m_desc.depthTexture());
- rhiD->f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexD->target,
- depthTexD->texture, 0);
+ if (multiViewCount < 2) {
+ if (depthTexD->sampleCount() > 1 && rhiD->caps.glesMultisampleRenderToTexture && m_desc.depthResolveTexture()) {
+ // Special path for GLES and
+ // GL_EXT_multisampled_render_to_texture, for depth-stencil.
+ // Relevant only when depthResolveTexture is set.
+ QGles2Texture *depthResolveTexD = QRHI_RES(QGles2Texture, m_desc.depthResolveTexture());
+ rhiD->glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthResolveTexD->target,
+ depthResolveTexD->texture, 0, depthTexD->sampleCount());
+ if (rhiD->isStencilSupportingFormat(depthResolveTexD->format())) {
+ rhiD->glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, depthResolveTexD->target,
+ depthResolveTexD->texture, 0, depthTexD->sampleCount());
+ }
+ } else {
+ rhiD->f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexD->target,
+ depthTexD->texture, 0);
+ if (rhiD->isStencilSupportingFormat(depthTexD->format())) {
+ rhiD->f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, depthTexD->target,
+ depthTexD->texture, 0);
+ }
+ }
+ } else {
+ if (depthTexD->sampleCount() > 1 && rhiD->caps.glesMultiviewMultisampleRenderToTexture) {
+ // And so it turns out
+ // https://registry.khronos.org/OpenGL/extensions/OVR/OVR_multiview.txt
+ // does not work with multisample 2D texture arrays. (at least
+ // that's what Issue 30 in the extension spec seems to imply)
+ //
+ // There is https://registry.khronos.org/OpenGL/extensions/EXT/EXT_multiview_texture_multisample.txt
+ // that seems to resolve that, but that does not seem to
+ // work (or not available) on GLES devices such as the Quest 3.
+ //
+ // So instead, on GLES we can use the
+ // multisample-multiview-auto-resolving version (which in
+ // turn is not supported on desktop GL e.g. by NVIDIA), too
+ // bad we have a multisample depth texture array here as
+ // every other API out there requires that. So, in absence
+ // of a depthResolveTexture, create a temporary one ignoring
+ // what the user has already created.
+ //
+ if (!m_flags.testFlag(DoNotStoreDepthStencilContents) && !m_desc.depthResolveTexture()) {
+ qWarning("Attempted to create a multiview+multisample QRhiTextureRenderTarget, but DoNotStoreDepthStencilContents was not set."
+ " This path has no choice but to behave as if DoNotStoreDepthStencilContents was set, because QRhi is forced to create"
+ " a throwaway non-multisample depth texture here. Set the flag to silence this warning, or set a depthResolveTexture.");
+ }
+ if (m_desc.depthResolveTexture()) {
+ QGles2Texture *depthResolveTexD = QRHI_RES(QGles2Texture, m_desc.depthResolveTexture());
+ rhiD->glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER,
+ GL_DEPTH_ATTACHMENT,
+ depthResolveTexD->texture,
+ 0,
+ depthTexD->sampleCount(),
+ 0,
+ multiViewCount);
+ if (rhiD->isStencilSupportingFormat(depthResolveTexD->format())) {
+ rhiD->glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER,
+ GL_STENCIL_ATTACHMENT,
+ depthResolveTexD->texture,
+ 0,
+ depthTexD->sampleCount(),
+ 0,
+ multiViewCount);
+ }
+ } else {
+ if (!nonMsaaThrowawayDepthTexture) {
+ rhiD->f->glGenTextures(1, &nonMsaaThrowawayDepthTexture);
+ rhiD->f->glBindTexture(GL_TEXTURE_2D_ARRAY, nonMsaaThrowawayDepthTexture);
+ rhiD->f->glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_DEPTH24_STENCIL8,
+ depthTexD->pixelSize().width(), depthTexD->pixelSize().height(), multiViewCount);
+ }
+ rhiD->glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER,
+ GL_DEPTH_ATTACHMENT,
+ nonMsaaThrowawayDepthTexture,
+ 0,
+ depthTexD->sampleCount(),
+ 0,
+ multiViewCount);
+ rhiD->glFramebufferTextureMultisampleMultiviewOVR(GL_FRAMEBUFFER,
+ GL_STENCIL_ATTACHMENT,
+ nonMsaaThrowawayDepthTexture,
+ 0,
+ depthTexD->sampleCount(),
+ 0,
+ multiViewCount);
+ }
+ } else {
+ // The depth texture here must be an array with at least
+ // multiViewCount elements, and the format should be D24 or D32F
+ // for depth only, or D24S8 for depth and stencil.
+ rhiD->glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexD->texture,
+ 0, 0, multiViewCount);
+ if (rhiD->isStencilSupportingFormat(depthTexD->format())) {
+ rhiD->glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, depthTexD->texture,
+ 0, 0, multiViewCount);
+ }
+ }
+ }
if (d.colorAttCount == 0) {
d.pixelSize = depthTexD->pixelSize();
- d.sampleCount = 1;
+ d.sampleCount = depthTexD->sampleCount();
}
}
d.dsAttCount = 1;
@@ -5556,6 +6154,9 @@ bool QGles2TextureRenderTarget::create()
return false;
}
+ if (rhiD->glObjectLabel)
+ rhiD->glObjectLabel(GL_FRAMEBUFFER, framebuffer, -1, m_objectName.constData());
+
QRhiRenderTargetAttachmentTracker::updateResIdList<QGles2Texture, QGles2RenderBuffer>(m_desc, &d.currentResIdList);
rhiD->registerResource(this);
@@ -5592,7 +6193,9 @@ QGles2ShaderResourceBindings::~QGles2ShaderResourceBindings()
void QGles2ShaderResourceBindings::destroy()
{
- // nothing to do here
+ QRHI_RES_RHI(QRhiGles2);
+ if (rhiD)
+ rhiD->unregisterResource(this);
}
bool QGles2ShaderResourceBindings::create()
@@ -5615,6 +6218,7 @@ bool QGles2ShaderResourceBindings::create()
rhiD->updateLayoutDesc(this);
generation += 1;
+ rhiD->registerResource(this, false);
return true;
}
@@ -5799,6 +6403,9 @@ bool QGles2GraphicsPipeline::create()
currentSrb = nullptr;
currentSrbGeneration = 0;
+ if (rhiD->glObjectLabel)
+ rhiD->glObjectLabel(GL_PROGRAM, program, -1, m_objectName.constData());
+
rhiD->pipelineCreationEnd();
generation += 1;
rhiD->registerResource(this);
@@ -5969,7 +6576,12 @@ QRhiRenderTarget *QGles2SwapChain::currentFrameRenderTarget(StereoTargetBuffer t
QSize QGles2SwapChain::surfacePixelSize()
{
Q_ASSERT(m_window);
- return m_window->size() * m_window->devicePixelRatio();
+ if (QPlatformWindow *platformWindow = m_window->handle())
+ // Prefer using QPlatformWindow geometry and DPR in order to avoid
+ // errors due to rounded QWindow geometry.
+ return platformWindow->geometry().size() * platformWindow->devicePixelRatio();
+ else
+ return m_window->size() * m_window->devicePixelRatio();
}
bool QGles2SwapChain::isFormatSupported(Format f)
@@ -5979,7 +6591,10 @@ bool QGles2SwapChain::isFormatSupported(Format f)
QRhiRenderPassDescriptor *QGles2SwapChain::newCompatibleRenderPassDescriptor()
{
- return new QGles2RenderPassDescriptor(m_rhi);
+ QGles2RenderPassDescriptor *rpD = new QGles2RenderPassDescriptor(m_rhi);
+ QRHI_RES_RHI(QRhiGles2);
+ rhiD->registerResource(rpD, false);
+ return rpD;
}
void QGles2SwapChain::initSwapChainRenderTarget(QGles2SwapChainRenderTarget *rt)
@@ -6023,15 +6638,59 @@ bool QGles2SwapChain::createOrResize()
frameCount = 0;
+ QRHI_RES_RHI(QRhiGles2);
+ if (rhiD->rhiFlags.testFlag(QRhi::EnableTimestamps) && rhiD->caps.timestamps)
+ timestamps.prepare(rhiD);
+
// The only reason to register this fairly fake gl swapchain
// object with no native resources underneath is to be able to
// implement a safe destroy().
- if (needsRegistration) {
- QRHI_RES_RHI(QRhiGles2);
- rhiD->registerResource(this);
- }
+ if (needsRegistration)
+ rhiD->registerResource(this, false);
return true;
}
+void QGles2SwapChainTimestamps::prepare(QRhiGles2 *rhiD)
+{
+ if (!query[0])
+ rhiD->f->glGenQueries(TIMESTAMP_PAIRS * 2, query);
+}
+
+void QGles2SwapChainTimestamps::destroy(QRhiGles2 *rhiD)
+{
+ rhiD->f->glDeleteQueries(TIMESTAMP_PAIRS * 2, query);
+ memset(active, 0, sizeof(active));
+ memset(query, 0, sizeof(query));
+}
+
+bool QGles2SwapChainTimestamps::tryQueryTimestamps(int pairIndex, QRhiGles2 *rhiD, double *elapsedSec)
+{
+ if (!active[pairIndex])
+ return false;
+
+ GLuint tsStart = query[pairIndex * 2];
+ GLuint tsEnd = query[pairIndex * 2 + 1];
+
+ GLuint ready = GL_FALSE;
+ rhiD->f->glGetQueryObjectuiv(tsEnd, GL_QUERY_RESULT_AVAILABLE, &ready);
+
+ if (!ready)
+ return false;
+
+ bool result = false;
+ quint64 timestamps[2];
+ rhiD->glGetQueryObjectui64v(tsStart, GL_QUERY_RESULT, &timestamps[0]);
+ rhiD->glGetQueryObjectui64v(tsEnd, GL_QUERY_RESULT, &timestamps[1]);
+
+ if (timestamps[1] >= timestamps[0]) {
+ const quint64 nanoseconds = timestamps[1] - timestamps[0];
+ *elapsedSec = nanoseconds / 1000000000.0;
+ result = true;
+ }
+
+ active[pairIndex] = false;
+ return result;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/rhi/qrhigles2_p.h b/src/gui/rhi/qrhigles2_p.h
index e3f4fbe7d7..4139579864 100644
--- a/src/gui/rhi/qrhigles2_p.h
+++ b/src/gui/rhi/qrhigles2_p.h
@@ -1,8 +1,8 @@
-// Copyright (C) 2019 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QRHIGLES2_H
-#define QRHIGLES2_H
+#ifndef QRHIGLES2_P_H
+#define QRHIGLES2_P_H
//
// W A R N I N G
@@ -15,33 +15,1125 @@
// We mean it.
//
-#include <private/qrhi_p.h>
-#include <QtGui/qsurfaceformat.h>
+#include "qrhi_p.h"
+#include <rhi/qshaderdescription.h>
+#include <qopengl.h>
+#include <QByteArray>
+#include <QWindow>
+#include <QPointer>
+#include <QtCore/private/qduplicatetracker_p.h>
+#include <optional>
QT_BEGIN_NAMESPACE
-class QOpenGLContext;
-class QOffscreenSurface;
-class QSurface;
-class QWindow;
+class QOpenGLExtensions;
+class QRhiGles2;
-struct Q_GUI_EXPORT QRhiGles2InitParams : public QRhiInitParams
+struct QGles2Buffer : public QRhiBuffer
{
- QRhiGles2InitParams();
+ QGles2Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
+ ~QGles2Buffer();
+ void destroy() override;
+ bool create() override;
+ QRhiBuffer::NativeBuffer nativeBuffer() override;
+ char *beginFullDynamicBufferUpdateForCurrentFrame() override;
+ void endFullDynamicBufferUpdateForCurrentFrame() override;
- QSurfaceFormat format;
- QSurface *fallbackSurface = nullptr;
- QWindow *window = nullptr;
- QOpenGLContext *shareContext = nullptr;
+ quint32 nonZeroSize = 0;
+ GLuint buffer = 0;
+ GLenum targetForDataOps;
+ QByteArray data;
+ enum Access {
+ AccessNone,
+ AccessVertex,
+ AccessIndex,
+ AccessUniform,
+ AccessStorageRead,
+ AccessStorageWrite,
+ AccessStorageReadWrite,
+ AccessUpdate
+ };
+ struct UsageState {
+ Access access;
+ };
+ UsageState usageState;
+ friend class QRhiGles2;
+};
+
+struct QGles2RenderBuffer : public QRhiRenderBuffer
+{
+ QGles2RenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
+ int sampleCount, QRhiRenderBuffer::Flags flags,
+ QRhiTexture::Format backingFormatHint);
+ ~QGles2RenderBuffer();
+ void destroy() override;
+ bool create() override;
+ bool createFrom(NativeRenderBuffer src) override;
+ QRhiTexture::Format backingFormat() const override;
+
+ GLuint renderbuffer = 0;
+ GLuint stencilRenderbuffer = 0; // when packed depth-stencil not supported
+ int samples;
+ bool owns = true;
+ uint generation = 0;
+ friend class QRhiGles2;
+};
+
+struct QGles2SamplerData
+{
+ GLenum glminfilter = 0;
+ GLenum glmagfilter = 0;
+ GLenum glwraps = 0;
+ GLenum glwrapt = 0;
+ GLenum glwrapr = 0;
+ GLenum gltexcomparefunc = 0;
+};
+
+inline bool operator==(const QGles2SamplerData &a, const QGles2SamplerData &b)
+{
+ return a.glminfilter == b.glminfilter
+ && a.glmagfilter == b.glmagfilter
+ && a.glwraps == b.glwraps
+ && a.glwrapt == b.glwrapt
+ && a.glwrapr == b.glwrapr
+ && a.gltexcomparefunc == b.gltexcomparefunc;
+}
+
+inline bool operator!=(const QGles2SamplerData &a, const QGles2SamplerData &b)
+{
+ return !(a == b);
+}
+
+struct QGles2Texture : public QRhiTexture
+{
+ QGles2Texture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
+ int arraySize, int sampleCount, Flags flags);
+ ~QGles2Texture();
+ void destroy() override;
+ bool create() override;
+ bool createFrom(NativeTexture src) override;
+ NativeTexture nativeTexture() override;
+
+ bool prepareCreate(QSize *adjustedSize = nullptr);
+
+ GLuint texture = 0;
+ bool owns = true;
+ GLenum target;
+ GLenum glintformat;
+ GLenum glsizedintformat;
+ GLenum glformat;
+ GLenum gltype;
+ QGles2SamplerData samplerState;
+ bool specified = false;
+ bool zeroInitialized = false;
+ int mipLevelCount = 0;
+
+ enum Access {
+ AccessNone,
+ AccessSample,
+ AccessFramebuffer,
+ AccessStorageRead,
+ AccessStorageWrite,
+ AccessStorageReadWrite,
+ AccessUpdate,
+ AccessRead
+ };
+ struct UsageState {
+ Access access;
+ };
+ UsageState usageState;
+
+ uint generation = 0;
+ friend class QRhiGles2;
+};
+
+struct QGles2Sampler : public QRhiSampler
+{
+ QGles2Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
+ AddressMode u, AddressMode v, AddressMode w);
+ ~QGles2Sampler();
+ void destroy() override;
+ bool create() override;
+
+ QGles2SamplerData d;
+ uint generation = 0;
+ friend class QRhiGles2;
+};
+
+struct QGles2RenderPassDescriptor : public QRhiRenderPassDescriptor
+{
+ QGles2RenderPassDescriptor(QRhiImplementation *rhi);
+ ~QGles2RenderPassDescriptor();
+ void destroy() override;
+ bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
+ QVector<quint32> serializedFormat() const override;
+};
+
+struct QGles2RenderTargetData
+{
+ QGles2RenderTargetData(QRhiImplementation *) { }
+
+ bool isValid() const { return rp != nullptr; }
+
+ QGles2RenderPassDescriptor *rp = nullptr;
+ QSize pixelSize;
+ float dpr = 1;
+ int sampleCount = 1;
+ int colorAttCount = 0;
+ int dsAttCount = 0;
+ bool srgbUpdateAndBlend = false;
+ QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList;
+ std::optional<QRhiSwapChain::StereoTargetBuffer> stereoTarget;
+};
+
+struct QGles2SwapChainRenderTarget : public QRhiSwapChainRenderTarget
+{
+ QGles2SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
+ ~QGles2SwapChainRenderTarget();
+ void destroy() override;
+
+ QSize pixelSize() const override;
+ float devicePixelRatio() const override;
+ int sampleCount() const override;
- static QOffscreenSurface *newFallbackSurface(const QSurfaceFormat &format = QSurfaceFormat::defaultFormat());
+ QGles2RenderTargetData d;
};
-struct Q_GUI_EXPORT QRhiGles2NativeHandles : public QRhiNativeHandles
+struct QGles2TextureRenderTarget : public QRhiTextureRenderTarget
{
- QOpenGLContext *context = nullptr;
+ QGles2TextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags);
+ ~QGles2TextureRenderTarget();
+ void destroy() override;
+
+ QSize pixelSize() const override;
+ float devicePixelRatio() const override;
+ int sampleCount() const override;
+
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
+ bool create() override;
+
+ QGles2RenderTargetData d;
+ GLuint framebuffer = 0;
+ GLuint nonMsaaThrowawayDepthTexture = 0;
+ friend class QRhiGles2;
+};
+
+struct QGles2ShaderResourceBindings : public QRhiShaderResourceBindings
+{
+ QGles2ShaderResourceBindings(QRhiImplementation *rhi);
+ ~QGles2ShaderResourceBindings();
+ void destroy() override;
+ bool create() override;
+ void updateResources(UpdateFlags flags) override;
+
+ bool hasDynamicOffset = false;
+ uint generation = 0;
+ friend class QRhiGles2;
};
+struct QGles2UniformDescription
+{
+ QShaderDescription::VariableType type;
+ int glslLocation;
+ int binding;
+ quint32 offset;
+ quint32 size;
+ int arrayDim;
+};
+
+Q_DECLARE_TYPEINFO(QGles2UniformDescription, Q_RELOCATABLE_TYPE);
+
+struct QGles2SamplerDescription
+{
+ int glslLocation;
+ int combinedBinding;
+ int tbinding;
+ int sbinding;
+};
+
+Q_DECLARE_TYPEINFO(QGles2SamplerDescription, Q_RELOCATABLE_TYPE);
+
+using QGles2UniformDescriptionVector = QVarLengthArray<QGles2UniformDescription, 8>;
+using QGles2SamplerDescriptionVector = QVarLengthArray<QGles2SamplerDescription, 4>;
+
+struct QGles2UniformState
+{
+ static constexpr int MAX_TRACKED_LOCATION = 1023;
+ int componentCount;
+ float v[4];
+};
+
+struct QGles2GraphicsPipeline : public QRhiGraphicsPipeline
+{
+ QGles2GraphicsPipeline(QRhiImplementation *rhi);
+ ~QGles2GraphicsPipeline();
+ void destroy() override;
+ bool create() override;
+
+ GLuint program = 0;
+ GLenum drawMode = GL_TRIANGLES;
+ QGles2UniformDescriptionVector uniforms;
+ QGles2SamplerDescriptionVector samplers;
+ QGles2UniformState uniformState[QGles2UniformState::MAX_TRACKED_LOCATION + 1];
+ QRhiShaderResourceBindings *currentSrb = nullptr;
+ uint currentSrbGeneration = 0;
+ uint generation = 0;
+ friend class QRhiGles2;
+};
+
+struct QGles2ComputePipeline : public QRhiComputePipeline
+{
+ QGles2ComputePipeline(QRhiImplementation *rhi);
+ ~QGles2ComputePipeline();
+ void destroy() override;
+ bool create() override;
+
+ GLuint program = 0;
+ QGles2UniformDescriptionVector uniforms;
+ QGles2SamplerDescriptionVector samplers;
+ QGles2UniformState uniformState[QGles2UniformState::MAX_TRACKED_LOCATION + 1];
+ QRhiShaderResourceBindings *currentSrb = nullptr;
+ uint currentSrbGeneration = 0;
+ uint generation = 0;
+ friend class QRhiGles2;
+};
+
+struct QGles2CommandBuffer : public QRhiCommandBuffer
+{
+ QGles2CommandBuffer(QRhiImplementation *rhi);
+ ~QGles2CommandBuffer();
+ void destroy() override;
+
+ // keep at a reasonably low value otherwise sizeof Command explodes
+ static const int MAX_DYNAMIC_OFFSET_COUNT = 8;
+
+ struct Command {
+ enum Cmd {
+ BeginFrame,
+ EndFrame,
+ ResetFrame,
+ Viewport,
+ Scissor,
+ BlendConstants,
+ StencilRef,
+ BindVertexBuffer,
+ BindIndexBuffer,
+ Draw,
+ DrawIndexed,
+ BindGraphicsPipeline,
+ BindShaderResources,
+ BindFramebuffer,
+ Clear,
+ BufferSubData,
+ GetBufferSubData,
+ CopyTex,
+ ReadPixels,
+ SubImage,
+ CompressedImage,
+ CompressedSubImage,
+ BlitFromRenderbuffer,
+ BlitFromTexture,
+ GenMip,
+ BindComputePipeline,
+ Dispatch,
+ BarriersForPass,
+ Barrier,
+ InvalidateFramebuffer
+ };
+ Cmd cmd;
+
+ // QRhi*/QGles2* references should be kept at minimum (so no
+ // QRhiTexture/Buffer/etc. pointers).
+ union Args {
+ struct {
+ GLuint timestampQuery;
+ } beginFrame;
+ struct {
+ GLuint timestampQuery;
+ } endFrame;
+ struct {
+ float x, y, w, h;
+ float d0, d1;
+ } viewport;
+ struct {
+ int x, y, w, h;
+ } scissor;
+ struct {
+ float r, g, b, a;
+ } blendConstants;
+ struct {
+ quint32 ref;
+ QRhiGraphicsPipeline *ps;
+ } stencilRef;
+ struct {
+ QRhiGraphicsPipeline *ps;
+ GLuint buffer;
+ quint32 offset;
+ int binding;
+ } bindVertexBuffer;
+ struct {
+ GLuint buffer;
+ quint32 offset;
+ GLenum type;
+ } bindIndexBuffer;
+ struct {
+ QRhiGraphicsPipeline *ps;
+ quint32 vertexCount;
+ quint32 firstVertex;
+ quint32 instanceCount;
+ quint32 baseInstance;
+ } draw;
+ struct {
+ QRhiGraphicsPipeline *ps;
+ quint32 indexCount;
+ quint32 firstIndex;
+ quint32 instanceCount;
+ quint32 baseInstance;
+ qint32 baseVertex;
+ } drawIndexed;
+ struct {
+ QRhiGraphicsPipeline *ps;
+ } bindGraphicsPipeline;
+ struct {
+ QRhiGraphicsPipeline *maybeGraphicsPs;
+ QRhiComputePipeline *maybeComputePs;
+ QRhiShaderResourceBindings *srb;
+ int dynamicOffsetCount;
+ uint dynamicOffsetPairs[MAX_DYNAMIC_OFFSET_COUNT * 2]; // binding, offset
+ } bindShaderResources;
+ struct {
+ GLbitfield mask;
+ float c[4];
+ float d;
+ quint32 s;
+ } clear;
+ struct {
+ GLuint fbo;
+ bool srgb;
+ int colorAttCount;
+ bool stereo;
+ QRhiSwapChain::StereoTargetBuffer stereoTarget;
+ } bindFramebuffer;
+ struct {
+ GLenum target;
+ GLuint buffer;
+ int offset;
+ int size;
+ const void *data; // must come from retainData()
+ } bufferSubData;
+ struct {
+ QRhiReadbackResult *result;
+ GLenum target;
+ GLuint buffer;
+ int offset;
+ int size;
+ } getBufferSubData;
+ struct {
+ GLenum srcTarget;
+ GLenum srcFaceTarget;
+ GLuint srcTexture;
+ int srcLevel;
+ int srcX;
+ int srcY;
+ int srcZ;
+ GLenum dstTarget;
+ GLuint dstTexture;
+ GLenum dstFaceTarget;
+ int dstLevel;
+ int dstX;
+ int dstY;
+ int dstZ;
+ int w;
+ int h;
+ } copyTex;
+ struct {
+ QRhiReadbackResult *result;
+ GLuint texture;
+ int w;
+ int h;
+ QRhiTexture::Format format;
+ GLenum readTarget;
+ int level;
+ int slice3D;
+ } readPixels;
+ struct {
+ GLenum target;
+ GLuint texture;
+ GLenum faceTarget;
+ int level;
+ int dx;
+ int dy;
+ int dz;
+ int w;
+ int h;
+ GLenum glformat;
+ GLenum gltype;
+ int rowStartAlign;
+ int rowLength;
+ const void *data; // must come from retainImage()
+ } subImage;
+ struct {
+ GLenum target;
+ GLuint texture;
+ GLenum faceTarget;
+ int level;
+ GLenum glintformat;
+ int w;
+ int h;
+ int depth;
+ int size;
+ const void *data; // must come from retainData()
+ } compressedImage;
+ struct {
+ GLenum target;
+ GLuint texture;
+ GLenum faceTarget;
+ int level;
+ int dx;
+ int dy;
+ int dz;
+ int w;
+ int h;
+ GLenum glintformat;
+ int size;
+ const void *data; // must come from retainData()
+ } compressedSubImage;
+ struct {
+ GLuint renderbuffer;
+ int w;
+ int h;
+ GLenum target;
+ GLuint dstTexture;
+ int dstLevel;
+ int dstLayer;
+ bool isDepthStencil;
+ } blitFromRenderbuffer;
+ struct {
+ GLenum srcTarget;
+ GLuint srcTexture;
+ int srcLevel;
+ int srcLayer;
+ int w;
+ int h;
+ GLenum dstTarget;
+ GLuint dstTexture;
+ int dstLevel;
+ int dstLayer;
+ bool isDepthStencil;
+ } blitFromTexture;
+ struct {
+ GLenum target;
+ GLuint texture;
+ } genMip;
+ struct {
+ QRhiComputePipeline *ps;
+ } bindComputePipeline;
+ struct {
+ GLuint x;
+ GLuint y;
+ GLuint z;
+ } dispatch;
+ struct {
+ int trackerIndex;
+ } barriersForPass;
+ struct {
+ GLbitfield barriers;
+ } barrier;
+ struct {
+ int attCount;
+ GLenum att[3];
+ } invalidateFramebuffer;
+ } args;
+ };
+
+ enum PassType {
+ NoPass,
+ RenderPass,
+ ComputePass
+ };
+
+ QRhiBackendCommandList<Command> commands;
+ QVarLengthArray<QRhiPassResourceTracker, 8> passResTrackers;
+ int currentPassResTrackerIndex;
+
+ PassType recordingPass;
+ bool passNeedsResourceTracking;
+ double lastGpuTime = 0;
+ QRhiRenderTarget *currentTarget;
+ QRhiGraphicsPipeline *currentGraphicsPipeline;
+ QRhiComputePipeline *currentComputePipeline;
+ uint currentPipelineGeneration;
+ QRhiShaderResourceBindings *currentGraphicsSrb;
+ QRhiShaderResourceBindings *currentComputeSrb;
+ uint currentSrbGeneration;
+
+ struct GraphicsPassState {
+ bool valid = false;
+ bool scissor;
+ bool cullFace;
+ GLenum cullMode;
+ GLenum frontFace;
+ bool blendEnabled;
+ struct ColorMask { bool r, g, b, a; } colorMask;
+ struct Blend {
+ GLenum srcColor;
+ GLenum dstColor;
+ GLenum srcAlpha;
+ GLenum dstAlpha;
+ GLenum opColor;
+ GLenum opAlpha;
+ } blend;
+ bool depthTest;
+ bool depthWrite;
+ GLenum depthFunc;
+ bool stencilTest;
+ GLuint stencilReadMask;
+ GLuint stencilWriteMask;
+ struct StencilFace {
+ GLenum func;
+ GLenum failOp;
+ GLenum zfailOp;
+ GLenum zpassOp;
+ } stencil[2]; // front, back
+ bool polyOffsetFill;
+ float polyOffsetFactor;
+ float polyOffsetUnits;
+ float lineWidth;
+ int cpCount;
+ GLenum polygonMode;
+ void reset() { valid = false; }
+ struct {
+ // not part of QRhiGraphicsPipeline but used by setGraphicsPipeline()
+ GLint stencilRef = 0;
+ } dynamic;
+ } graphicsPassState;
+
+ struct ComputePassState {
+ enum Access {
+ Read = 0x01,
+ Write = 0x02
+ };
+ QHash<QRhiResource *, QPair<int, bool> > writtenResources;
+ void reset() {
+ writtenResources.clear();
+ }
+ } computePassState;
+
+ struct TextureUnitState {
+ void *ps;
+ uint psGeneration;
+ uint texture;
+ } textureUnitState[16];
+
+ QVarLengthArray<QByteArray, 4> dataRetainPool;
+ QVarLengthArray<QRhiBufferData, 4> bufferDataRetainPool;
+ QVarLengthArray<QImage, 4> imageRetainPool;
+
+ // relies heavily on implicit sharing (no copies of the actual data will be made)
+ const void *retainData(const QByteArray &data) {
+ dataRetainPool.append(data);
+ return dataRetainPool.last().constData();
+ }
+ const uchar *retainBufferData(const QRhiBufferData &data) {
+ bufferDataRetainPool.append(data);
+ return reinterpret_cast<const uchar *>(bufferDataRetainPool.last().constData());
+ }
+ const void *retainImage(const QImage &image) {
+ imageRetainPool.append(image);
+ return imageRetainPool.last().constBits();
+ }
+ void resetCommands() {
+ commands.reset();
+ dataRetainPool.clear();
+ bufferDataRetainPool.clear();
+ imageRetainPool.clear();
+
+ passResTrackers.clear();
+ currentPassResTrackerIndex = -1;
+ }
+ void resetState() {
+ recordingPass = NoPass;
+ passNeedsResourceTracking = true;
+ // do not zero lastGpuTime
+ currentTarget = nullptr;
+ resetCommands();
+ resetCachedState();
+ }
+ void resetCachedState() {
+ currentGraphicsPipeline = nullptr;
+ currentComputePipeline = nullptr;
+ currentPipelineGeneration = 0;
+ currentGraphicsSrb = nullptr;
+ currentComputeSrb = nullptr;
+ currentSrbGeneration = 0;
+ graphicsPassState.reset();
+ computePassState.reset();
+ memset(textureUnitState, 0, sizeof(textureUnitState));
+ }
+};
+
+inline bool operator==(const QGles2CommandBuffer::GraphicsPassState::StencilFace &a,
+ const QGles2CommandBuffer::GraphicsPassState::StencilFace &b)
+{
+ return a.func == b.func
+ && a.failOp == b.failOp
+ && a.zfailOp == b.zfailOp
+ && a.zpassOp == b.zpassOp;
+}
+
+inline bool operator!=(const QGles2CommandBuffer::GraphicsPassState::StencilFace &a,
+ const QGles2CommandBuffer::GraphicsPassState::StencilFace &b)
+{
+ return !(a == b);
+}
+
+inline bool operator==(const QGles2CommandBuffer::GraphicsPassState::ColorMask &a,
+ const QGles2CommandBuffer::GraphicsPassState::ColorMask &b)
+{
+ return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
+}
+
+inline bool operator!=(const QGles2CommandBuffer::GraphicsPassState::ColorMask &a,
+ const QGles2CommandBuffer::GraphicsPassState::ColorMask &b)
+{
+ return !(a == b);
+}
+
+inline bool operator==(const QGles2CommandBuffer::GraphicsPassState::Blend &a,
+ const QGles2CommandBuffer::GraphicsPassState::Blend &b)
+{
+ return a.srcColor == b.srcColor
+ && a.dstColor == b.dstColor
+ && a.srcAlpha == b.srcAlpha
+ && a.dstAlpha == b.dstAlpha
+ && a.opColor == b.opColor
+ && a.opAlpha == b.opAlpha;
+}
+
+inline bool operator!=(const QGles2CommandBuffer::GraphicsPassState::Blend &a,
+ const QGles2CommandBuffer::GraphicsPassState::Blend &b)
+{
+ return !(a == b);
+}
+
+struct QGles2SwapChainTimestamps
+{
+ static const int TIMESTAMP_PAIRS = 2;
+
+ bool active[TIMESTAMP_PAIRS] = {};
+ GLuint query[TIMESTAMP_PAIRS * 2] = {};
+
+ void prepare(QRhiGles2 *rhiD);
+ void destroy(QRhiGles2 *rhiD);
+ bool tryQueryTimestamps(int pairIndex, QRhiGles2 *rhiD, double *elapsedSec);
+};
+
+struct QGles2SwapChain : public QRhiSwapChain
+{
+ QGles2SwapChain(QRhiImplementation *rhi);
+ ~QGles2SwapChain();
+ void destroy() override;
+
+ QRhiCommandBuffer *currentFrameCommandBuffer() override;
+ QRhiRenderTarget *currentFrameRenderTarget() override;
+ QRhiRenderTarget *currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override;
+
+ QSize surfacePixelSize() override;
+ bool isFormatSupported(Format f) override;
+
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
+ bool createOrResize() override;
+
+ void initSwapChainRenderTarget(QGles2SwapChainRenderTarget *rt);
+
+ QSurface *surface = nullptr;
+ QSize pixelSize;
+ QGles2SwapChainRenderTarget rt;
+ QGles2SwapChainRenderTarget rtLeft;
+ QGles2SwapChainRenderTarget rtRight;
+ QGles2CommandBuffer cb;
+ int frameCount = 0;
+ QGles2SwapChainTimestamps timestamps;
+ int currentTimestampPairIndex = 0;
+};
+
+class QRhiGles2 : public QRhiImplementation
+{
+public:
+ QRhiGles2(QRhiGles2InitParams *params, QRhiGles2NativeHandles *importDevice = nullptr);
+
+ bool create(QRhi::Flags flags) override;
+ void destroy() override;
+
+ QRhiGraphicsPipeline *createGraphicsPipeline() override;
+ QRhiComputePipeline *createComputePipeline() override;
+ QRhiShaderResourceBindings *createShaderResourceBindings() override;
+ QRhiBuffer *createBuffer(QRhiBuffer::Type type,
+ QRhiBuffer::UsageFlags usage,
+ quint32 size) override;
+ QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
+ const QSize &pixelSize,
+ int sampleCount,
+ QRhiRenderBuffer::Flags flags,
+ QRhiTexture::Format backingFormatHint) override;
+ QRhiTexture *createTexture(QRhiTexture::Format format,
+ const QSize &pixelSize,
+ int depth,
+ int arraySize,
+ int sampleCount,
+ QRhiTexture::Flags flags) override;
+ QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
+ QRhiSampler::Filter minFilter,
+ QRhiSampler::Filter mipmapMode,
+ QRhiSampler:: AddressMode u,
+ QRhiSampler::AddressMode v,
+ QRhiSampler::AddressMode w) override;
+
+ QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
+ QRhiTextureRenderTarget::Flags flags) override;
+
+ QRhiSwapChain *createSwapChain() override;
+ QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
+ QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
+ QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
+ QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
+ QRhi::FrameOpResult finish() override;
+
+ void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+
+ void beginPass(QRhiCommandBuffer *cb,
+ QRhiRenderTarget *rt,
+ const QColor &colorClearValue,
+ const QRhiDepthStencilClearValue &depthStencilClearValue,
+ QRhiResourceUpdateBatch *resourceUpdates,
+ QRhiCommandBuffer::BeginPassFlags flags) override;
+ void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+
+ void setGraphicsPipeline(QRhiCommandBuffer *cb,
+ QRhiGraphicsPipeline *ps) override;
+
+ void setShaderResources(QRhiCommandBuffer *cb,
+ QRhiShaderResourceBindings *srb,
+ int dynamicOffsetCount,
+ const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
+
+ void setVertexInput(QRhiCommandBuffer *cb,
+ int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
+ QRhiBuffer *indexBuf, quint32 indexOffset,
+ QRhiCommandBuffer::IndexFormat indexFormat) override;
+
+ void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
+ void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
+ void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
+ void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
+
+ void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
+ quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
+
+ void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
+ quint32 instanceCount, quint32 firstIndex,
+ qint32 vertexOffset, quint32 firstInstance) override;
+
+ void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
+ void debugMarkEnd(QRhiCommandBuffer *cb) override;
+ void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
+
+ void beginComputePass(QRhiCommandBuffer *cb,
+ QRhiResourceUpdateBatch *resourceUpdates,
+ QRhiCommandBuffer::BeginPassFlags flags) override;
+ void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+ void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
+ void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
+
+ const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
+ void beginExternal(QRhiCommandBuffer *cb) override;
+ void endExternal(QRhiCommandBuffer *cb) override;
+ double lastCompletedGpuTime(QRhiCommandBuffer *cb) override;
+
+ QList<int> supportedSampleCounts() const override;
+ int ubufAlignment() const override;
+ bool isYUpInFramebuffer() const override;
+ bool isYUpInNDC() const override;
+ bool isClipDepthZeroToOne() const override;
+ QMatrix4x4 clipSpaceCorrMatrix() const override;
+ bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
+ bool isFeatureSupported(QRhi::Feature feature) const override;
+ int resourceLimit(QRhi::ResourceLimit limit) const override;
+ const QRhiNativeHandles *nativeHandles() override;
+ QRhiDriverInfo driverInfo() const override;
+ QRhiStats statistics() override;
+ bool makeThreadLocalNativeContextCurrent() override;
+ void releaseCachedResources() override;
+ bool isDeviceLost() const override;
+
+ QByteArray pipelineCacheData() override;
+ void setPipelineCacheData(const QByteArray &data) override;
+
+ bool ensureContext(QSurface *surface = nullptr) const;
+ QSurface *evaluateFallbackSurface() const;
+ void executeDeferredReleases();
+ void trackedBufferBarrier(QGles2CommandBuffer *cbD, QGles2Buffer *bufD, QGles2Buffer::Access access);
+ void trackedImageBarrier(QGles2CommandBuffer *cbD, QGles2Texture *texD, QGles2Texture::Access access);
+ void enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cbD,
+ int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc);
+ void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
+ void trackedRegisterBuffer(QRhiPassResourceTracker *passResTracker,
+ QGles2Buffer *bufD,
+ QRhiPassResourceTracker::BufferAccess access,
+ QRhiPassResourceTracker::BufferStage stage);
+ void trackedRegisterTexture(QRhiPassResourceTracker *passResTracker,
+ QGles2Texture *texD,
+ QRhiPassResourceTracker::TextureAccess access,
+ QRhiPassResourceTracker::TextureStage stage);
+ void executeCommandBuffer(QRhiCommandBuffer *cb);
+ void executeBindGraphicsPipeline(QGles2CommandBuffer *cbD, QGles2GraphicsPipeline *psD);
+ void bindCombinedSampler(QGles2CommandBuffer *cbD, QGles2Texture *texD, QGles2Sampler *samplerD,
+ void *ps, uint psGeneration, int glslLocation,
+ int *texUnit, bool *activeTexUnitAltered);
+ void bindShaderResources(QGles2CommandBuffer *cbD,
+ QRhiGraphicsPipeline *maybeGraphicsPs, QRhiComputePipeline *maybeComputePs,
+ QRhiShaderResourceBindings *srb,
+ const uint *dynOfsPairs, int dynOfsCount);
+ QGles2RenderTargetData *enqueueBindFramebuffer(QRhiRenderTarget *rt, QGles2CommandBuffer *cbD,
+ bool *wantsColorClear = nullptr, bool *wantsDsClear = nullptr);
+ void enqueueBarriersForPass(QGles2CommandBuffer *cbD);
+ QByteArray shaderSource(const QRhiShaderStage &shaderStage, QShaderVersion *shaderVersion);
+ bool compileShader(GLuint program, const QRhiShaderStage &shaderStage, QShaderVersion *shaderVersion);
+ bool linkProgram(GLuint program);
+ void registerUniformIfActive(const QShaderDescription::BlockVariable &var,
+ const QByteArray &namePrefix, int binding, int baseOffset,
+ GLuint program,
+ QDuplicateTracker<int, 256> *activeUniformLocations,
+ QGles2UniformDescriptionVector *dst);
+ void gatherUniforms(GLuint program, const QShaderDescription::UniformBlock &ub,
+ QDuplicateTracker<int, 256> *activeUniformLocations, QGles2UniformDescriptionVector *dst);
+ void gatherSamplers(GLuint program, const QShaderDescription::InOutVariable &v,
+ QGles2SamplerDescriptionVector *dst);
+ void gatherGeneratedSamplers(GLuint program,
+ const QShader::SeparateToCombinedImageSamplerMapping &mapping,
+ QGles2SamplerDescriptionVector *dst);
+ void sanityCheckVertexFragmentInterface(const QShaderDescription &vsDesc, const QShaderDescription &fsDesc);
+ bool isProgramBinaryDiskCacheEnabled() const;
+
+ enum ProgramCacheResult {
+ ProgramCacheHit,
+ ProgramCacheMiss,
+ ProgramCacheError
+ };
+ ProgramCacheResult tryLoadFromDiskOrPipelineCache(const QRhiShaderStage *stages,
+ int stageCount,
+ GLuint program,
+ const QVector<QShaderDescription::InOutVariable> &inputVars,
+ QByteArray *cacheKey);
+ void trySaveToDiskCache(GLuint program, const QByteArray &cacheKey);
+ void trySaveToPipelineCache(GLuint program, const QByteArray &cacheKey, bool force = false);
+
+ QRhi::Flags rhiFlags;
+ QOpenGLContext *ctx = nullptr;
+ bool importedContext = false;
+ QSurfaceFormat requestedFormat;
+ QSurface *fallbackSurface = nullptr;
+ QPointer<QWindow> maybeWindow = nullptr;
+ QOpenGLContext *maybeShareContext = nullptr;
+ mutable bool needsMakeCurrentDueToSwap = false;
+ QOpenGLExtensions *f = nullptr;
+ void (QOPENGLF_APIENTRYP glPolygonMode) (GLenum, GLenum) = nullptr;
+ void(QOPENGLF_APIENTRYP glTexImage1D)(GLenum, GLint, GLint, GLsizei, GLint, GLenum, GLenum,
+ const void *) = nullptr;
+ void(QOPENGLF_APIENTRYP glTexStorage1D)(GLenum, GLint, GLenum, GLsizei) = nullptr;
+ void(QOPENGLF_APIENTRYP glTexSubImage1D)(GLenum, GLint, GLint, GLsizei, GLenum, GLenum,
+ const GLvoid *) = nullptr;
+ void(QOPENGLF_APIENTRYP glCopyTexSubImage1D)(GLenum, GLint, GLint, GLint, GLint,
+ GLsizei) = nullptr;
+ void(QOPENGLF_APIENTRYP glCompressedTexImage1D)(GLenum, GLint, GLenum, GLsizei, GLint, GLsizei,
+ const GLvoid *) = nullptr;
+ void(QOPENGLF_APIENTRYP glCompressedTexSubImage1D)(GLenum, GLint, GLint, GLsizei, GLenum,
+ GLsizei, const GLvoid *) = nullptr;
+ void(QOPENGLF_APIENTRYP glFramebufferTexture1D)(GLenum, GLenum, GLenum, GLuint,
+ GLint) = nullptr;
+ void(QOPENGLF_APIENTRYP glFramebufferTextureMultiviewOVR)(GLenum, GLenum, GLuint, GLint,
+ GLint, GLsizei) = nullptr;
+ void (QOPENGLF_APIENTRYP glQueryCounter)(GLuint, GLenum) = nullptr;
+ void (QOPENGLF_APIENTRYP glGetQueryObjectui64v)(GLuint, GLenum, quint64 *) = nullptr;
+ void (QOPENGLF_APIENTRYP glObjectLabel)(GLenum, GLuint, GLsizei, const GLchar *) = nullptr;
+ void (QOPENGLF_APIENTRYP glFramebufferTexture2DMultisampleEXT)(GLenum, GLenum, GLenum, GLuint, GLint, GLsizei) = nullptr;
+ void (QOPENGLF_APIENTRYP glFramebufferTextureMultisampleMultiviewOVR)(GLenum, GLenum, GLuint, GLint, GLsizei, GLint, GLsizei) = nullptr;
+ uint vao = 0;
+ struct Caps {
+ Caps()
+ : ctxMajor(2),
+ ctxMinor(0),
+ maxTextureSize(2048),
+ maxDrawBuffers(4),
+ maxSamples(16),
+ maxTextureArraySize(0),
+ maxThreadGroupsPerDimension(0),
+ maxThreadsPerThreadGroup(0),
+ maxThreadGroupsX(0),
+ maxThreadGroupsY(0),
+ maxThreadGroupsZ(0),
+ maxUniformVectors(4096),
+ maxVertexInputs(8),
+ maxVertexOutputs(8),
+ msaaRenderBuffer(false),
+ multisampledTexture(false),
+ npotTextureFull(true),
+ gles(false),
+ fixedIndexPrimitiveRestart(false),
+ bgraExternalFormat(false),
+ bgraInternalFormat(false),
+ r8Format(false),
+ r16Format(false),
+ floatFormats(false),
+ rgb10Formats(false),
+ depthTexture(false),
+ packedDepthStencil(false),
+ needsDepthStencilCombinedAttach(false),
+ srgbWriteControl(false),
+ coreProfile(false),
+ uniformBuffers(false),
+ elementIndexUint(false),
+ depth24(false),
+ rgba8Format(false),
+ instancing(false),
+ baseVertex(false),
+ compute(false),
+ textureCompareMode(false),
+ properMapBuffer(false),
+ nonBaseLevelFramebufferTexture(false),
+ texelFetch(false),
+ intAttributes(true),
+ screenSpaceDerivatives(false),
+ programBinary(false),
+ texture3D(false),
+ tessellation(false),
+ geometryShader(false),
+ texture1D(false),
+ hasDrawBuffersFunc(false),
+ halfAttributes(false),
+ multiView(false),
+ timestamps(false),
+ objectLabel(false),
+ glesMultisampleRenderToTexture(false),
+ glesMultiviewMultisampleRenderToTexture(false),
+ unpackRowLength(false)
+ { }
+ int ctxMajor;
+ int ctxMinor;
+ int maxTextureSize;
+ int maxDrawBuffers;
+ int maxSamples;
+ int maxTextureArraySize;
+ int maxThreadGroupsPerDimension;
+ int maxThreadsPerThreadGroup;
+ int maxThreadGroupsX;
+ int maxThreadGroupsY;
+ int maxThreadGroupsZ;
+ int maxUniformVectors;
+ int maxVertexInputs;
+ int maxVertexOutputs;
+ // Multisample fb and blit are supported (GLES 3.0 or OpenGL 3.x). Not
+ // the same as multisample textures!
+ uint msaaRenderBuffer : 1;
+ uint multisampledTexture : 1;
+ uint npotTextureFull : 1;
+ uint gles : 1;
+ uint fixedIndexPrimitiveRestart : 1;
+ uint bgraExternalFormat : 1;
+ uint bgraInternalFormat : 1;
+ uint r8Format : 1;
+ uint r16Format : 1;
+ uint floatFormats : 1;
+ uint rgb10Formats : 1;
+ uint depthTexture : 1;
+ uint packedDepthStencil : 1;
+ uint needsDepthStencilCombinedAttach : 1;
+ uint srgbWriteControl : 1;
+ uint coreProfile : 1;
+ uint uniformBuffers : 1;
+ uint elementIndexUint : 1;
+ uint depth24 : 1;
+ uint rgba8Format : 1;
+ uint instancing : 1;
+ uint baseVertex : 1;
+ uint compute : 1;
+ uint textureCompareMode : 1;
+ uint properMapBuffer : 1;
+ uint nonBaseLevelFramebufferTexture : 1;
+ uint texelFetch : 1;
+ uint intAttributes : 1;
+ uint screenSpaceDerivatives : 1;
+ uint programBinary : 1;
+ uint texture3D : 1;
+ uint tessellation : 1;
+ uint geometryShader : 1;
+ uint texture1D : 1;
+ uint hasDrawBuffersFunc : 1;
+ uint halfAttributes : 1;
+ uint multiView : 1;
+ uint timestamps : 1;
+ uint objectLabel : 1;
+ uint glesMultisampleRenderToTexture : 1;
+ uint glesMultiviewMultisampleRenderToTexture : 1;
+ uint unpackRowLength : 1;
+ } caps;
+ QGles2SwapChain *currentSwapChain = nullptr;
+ QSet<GLint> supportedCompressedFormats;
+ mutable QList<int> supportedSampleCountList;
+ QRhiGles2NativeHandles nativeHandlesStruct;
+ QRhiDriverInfo driverInfoStruct;
+ mutable bool contextLost = false;
+
+ struct DeferredReleaseEntry {
+ enum Type {
+ Buffer,
+ Pipeline,
+ Texture,
+ RenderBuffer,
+ TextureRenderTarget
+ };
+ Type type;
+ union {
+ struct {
+ GLuint buffer;
+ } buffer;
+ struct {
+ GLuint program;
+ } pipeline;
+ struct {
+ GLuint texture;
+ } texture;
+ struct {
+ GLuint renderbuffer;
+ GLuint renderbuffer2;
+ } renderbuffer;
+ struct {
+ GLuint framebuffer;
+ GLuint nonMsaaThrowawayDepthTexture;
+ } textureRenderTarget;
+ };
+ };
+ QList<DeferredReleaseEntry> releaseQueue;
+
+ struct OffscreenFrame {
+ OffscreenFrame(QRhiImplementation *rhi) : cbWrapper(rhi) { }
+ bool active = false;
+ QGles2CommandBuffer cbWrapper;
+ GLuint tsQueries[2] = {};
+ } ofr;
+
+ QHash<QRhiShaderStage, uint> m_shaderCache;
+
+ struct PipelineCacheData {
+ quint32 format;
+ QByteArray data;
+ };
+ QHash<QByteArray, PipelineCacheData> m_pipelineCache;
+};
+
+Q_DECLARE_TYPEINFO(QRhiGles2::DeferredReleaseEntry, Q_RELOCATABLE_TYPE);
+
QT_END_NAMESPACE
#endif
diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h
deleted file mode 100644
index c3d85c1d09..0000000000
--- a/src/gui/rhi/qrhigles2_p_p.h
+++ /dev/null
@@ -1,1076 +0,0 @@
-// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QRHIGLES2_P_H
-#define QRHIGLES2_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 "qrhigles2_p.h"
-#include "qrhi_p_p.h"
-#include "qshaderdescription_p.h"
-#include <qopengl.h>
-#include <QByteArray>
-#include <QWindow>
-#include <QPointer>
-#include <QtCore/private/qduplicatetracker_p.h>
-#include <optional>
-
-QT_BEGIN_NAMESPACE
-
-class QOpenGLExtensions;
-
-struct QGles2Buffer : public QRhiBuffer
-{
- QGles2Buffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
- ~QGles2Buffer();
- void destroy() override;
- bool create() override;
- QRhiBuffer::NativeBuffer nativeBuffer() override;
- char *beginFullDynamicBufferUpdateForCurrentFrame() override;
- void endFullDynamicBufferUpdateForCurrentFrame() override;
-
- quint32 nonZeroSize = 0;
- GLuint buffer = 0;
- GLenum targetForDataOps;
- QByteArray data;
- enum Access {
- AccessNone,
- AccessVertex,
- AccessIndex,
- AccessUniform,
- AccessStorageRead,
- AccessStorageWrite,
- AccessStorageReadWrite,
- AccessUpdate
- };
- struct UsageState {
- Access access;
- };
- UsageState usageState;
- friend class QRhiGles2;
-};
-
-struct QGles2RenderBuffer : public QRhiRenderBuffer
-{
- QGles2RenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
- int sampleCount, QRhiRenderBuffer::Flags flags,
- QRhiTexture::Format backingFormatHint);
- ~QGles2RenderBuffer();
- void destroy() override;
- bool create() override;
- bool createFrom(NativeRenderBuffer src) override;
- QRhiTexture::Format backingFormat() const override;
-
- GLuint renderbuffer = 0;
- GLuint stencilRenderbuffer = 0; // when packed depth-stencil not supported
- int samples;
- bool owns = true;
- uint generation = 0;
- friend class QRhiGles2;
-};
-
-struct QGles2SamplerData
-{
- GLenum glminfilter = 0;
- GLenum glmagfilter = 0;
- GLenum glwraps = 0;
- GLenum glwrapt = 0;
- GLenum glwrapr = 0;
- GLenum gltexcomparefunc = 0;
-};
-
-inline bool operator==(const QGles2SamplerData &a, const QGles2SamplerData &b)
-{
- return a.glminfilter == b.glminfilter
- && a.glmagfilter == b.glmagfilter
- && a.glwraps == b.glwraps
- && a.glwrapt == b.glwrapt
- && a.glwrapr == b.glwrapr
- && a.gltexcomparefunc == b.gltexcomparefunc;
-}
-
-inline bool operator!=(const QGles2SamplerData &a, const QGles2SamplerData &b)
-{
- return !(a == b);
-}
-
-struct QGles2Texture : public QRhiTexture
-{
- QGles2Texture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
- int arraySize, int sampleCount, Flags flags);
- ~QGles2Texture();
- void destroy() override;
- bool create() override;
- bool createFrom(NativeTexture src) override;
- NativeTexture nativeTexture() override;
-
- bool prepareCreate(QSize *adjustedSize = nullptr);
-
- GLuint texture = 0;
- bool owns = true;
- GLenum target;
- GLenum glintformat;
- GLenum glsizedintformat;
- GLenum glformat;
- GLenum gltype;
- QGles2SamplerData samplerState;
- bool specified = false;
- bool zeroInitialized = false;
- int mipLevelCount = 0;
-
- enum Access {
- AccessNone,
- AccessSample,
- AccessFramebuffer,
- AccessStorageRead,
- AccessStorageWrite,
- AccessStorageReadWrite,
- AccessUpdate,
- AccessRead
- };
- struct UsageState {
- Access access;
- };
- UsageState usageState;
-
- uint generation = 0;
- friend class QRhiGles2;
-};
-
-struct QGles2Sampler : public QRhiSampler
-{
- QGles2Sampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
- AddressMode u, AddressMode v, AddressMode w);
- ~QGles2Sampler();
- void destroy() override;
- bool create() override;
-
- QGles2SamplerData d;
- uint generation = 0;
- friend class QRhiGles2;
-};
-
-struct QGles2RenderPassDescriptor : public QRhiRenderPassDescriptor
-{
- QGles2RenderPassDescriptor(QRhiImplementation *rhi);
- ~QGles2RenderPassDescriptor();
- void destroy() override;
- bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
- QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
- QVector<quint32> serializedFormat() const override;
-};
-
-struct QGles2RenderTargetData
-{
- QGles2RenderTargetData(QRhiImplementation *) { }
-
- bool isValid() const { return rp != nullptr; }
-
- QGles2RenderPassDescriptor *rp = nullptr;
- QSize pixelSize;
- float dpr = 1;
- int sampleCount = 1;
- int colorAttCount = 0;
- int dsAttCount = 0;
- bool srgbUpdateAndBlend = false;
- QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList;
- std::optional<QRhiSwapChain::StereoTargetBuffer> stereoTarget;
-};
-
-struct QGles2SwapChainRenderTarget : public QRhiSwapChainRenderTarget
-{
- QGles2SwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
- ~QGles2SwapChainRenderTarget();
- void destroy() override;
-
- QSize pixelSize() const override;
- float devicePixelRatio() const override;
- int sampleCount() const override;
-
- QGles2RenderTargetData d;
-};
-
-struct QGles2TextureRenderTarget : public QRhiTextureRenderTarget
-{
- QGles2TextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags);
- ~QGles2TextureRenderTarget();
- void destroy() override;
-
- QSize pixelSize() const override;
- float devicePixelRatio() const override;
- int sampleCount() const override;
-
- QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
- bool create() override;
-
- QGles2RenderTargetData d;
- GLuint framebuffer = 0;
- friend class QRhiGles2;
-};
-
-struct QGles2ShaderResourceBindings : public QRhiShaderResourceBindings
-{
- QGles2ShaderResourceBindings(QRhiImplementation *rhi);
- ~QGles2ShaderResourceBindings();
- void destroy() override;
- bool create() override;
- void updateResources(UpdateFlags flags) override;
-
- bool hasDynamicOffset = false;
- uint generation = 0;
- friend class QRhiGles2;
-};
-
-struct QGles2UniformDescription
-{
- QShaderDescription::VariableType type;
- int glslLocation;
- int binding;
- quint32 offset;
- quint32 size;
- int arrayDim;
-};
-
-Q_DECLARE_TYPEINFO(QGles2UniformDescription, Q_RELOCATABLE_TYPE);
-
-struct QGles2SamplerDescription
-{
- int glslLocation;
- int combinedBinding;
- int tbinding;
- int sbinding;
-};
-
-Q_DECLARE_TYPEINFO(QGles2SamplerDescription, Q_RELOCATABLE_TYPE);
-
-using QGles2UniformDescriptionVector = QVarLengthArray<QGles2UniformDescription, 8>;
-using QGles2SamplerDescriptionVector = QVarLengthArray<QGles2SamplerDescription, 4>;
-
-struct QGles2UniformState
-{
- static constexpr int MAX_TRACKED_LOCATION = 1023;
- int componentCount;
- float v[4];
-};
-
-struct QGles2GraphicsPipeline : public QRhiGraphicsPipeline
-{
- QGles2GraphicsPipeline(QRhiImplementation *rhi);
- ~QGles2GraphicsPipeline();
- void destroy() override;
- bool create() override;
-
- GLuint program = 0;
- GLenum drawMode = GL_TRIANGLES;
- QGles2UniformDescriptionVector uniforms;
- QGles2SamplerDescriptionVector samplers;
- QGles2UniformState uniformState[QGles2UniformState::MAX_TRACKED_LOCATION + 1];
- QRhiShaderResourceBindings *currentSrb = nullptr;
- uint currentSrbGeneration = 0;
- uint generation = 0;
- friend class QRhiGles2;
-};
-
-struct QGles2ComputePipeline : public QRhiComputePipeline
-{
- QGles2ComputePipeline(QRhiImplementation *rhi);
- ~QGles2ComputePipeline();
- void destroy() override;
- bool create() override;
-
- GLuint program = 0;
- QGles2UniformDescriptionVector uniforms;
- QGles2SamplerDescriptionVector samplers;
- QGles2UniformState uniformState[QGles2UniformState::MAX_TRACKED_LOCATION + 1];
- QRhiShaderResourceBindings *currentSrb = nullptr;
- uint currentSrbGeneration = 0;
- uint generation = 0;
- friend class QRhiGles2;
-};
-
-struct QGles2CommandBuffer : public QRhiCommandBuffer
-{
- QGles2CommandBuffer(QRhiImplementation *rhi);
- ~QGles2CommandBuffer();
- void destroy() override;
-
- // keep at a reasonably low value otherwise sizeof Command explodes
- static const int MAX_DYNAMIC_OFFSET_COUNT = 8;
-
- struct Command {
- enum Cmd {
- BeginFrame,
- EndFrame,
- ResetFrame,
- Viewport,
- Scissor,
- BlendConstants,
- StencilRef,
- BindVertexBuffer,
- BindIndexBuffer,
- Draw,
- DrawIndexed,
- BindGraphicsPipeline,
- BindShaderResources,
- BindFramebuffer,
- Clear,
- BufferSubData,
- GetBufferSubData,
- CopyTex,
- ReadPixels,
- SubImage,
- CompressedImage,
- CompressedSubImage,
- BlitFromRenderbuffer,
- GenMip,
- BindComputePipeline,
- Dispatch,
- BarriersForPass,
- Barrier
- };
- Cmd cmd;
-
- // QRhi*/QGles2* references should be kept at minimum (so no
- // QRhiTexture/Buffer/etc. pointers).
- union Args {
- struct {
- float x, y, w, h;
- float d0, d1;
- } viewport;
- struct {
- int x, y, w, h;
- } scissor;
- struct {
- float r, g, b, a;
- } blendConstants;
- struct {
- quint32 ref;
- QRhiGraphicsPipeline *ps;
- } stencilRef;
- struct {
- QRhiGraphicsPipeline *ps;
- GLuint buffer;
- quint32 offset;
- int binding;
- } bindVertexBuffer;
- struct {
- GLuint buffer;
- quint32 offset;
- GLenum type;
- } bindIndexBuffer;
- struct {
- QRhiGraphicsPipeline *ps;
- quint32 vertexCount;
- quint32 firstVertex;
- quint32 instanceCount;
- quint32 baseInstance;
- } draw;
- struct {
- QRhiGraphicsPipeline *ps;
- quint32 indexCount;
- quint32 firstIndex;
- quint32 instanceCount;
- quint32 baseInstance;
- qint32 baseVertex;
- } drawIndexed;
- struct {
- QRhiGraphicsPipeline *ps;
- } bindGraphicsPipeline;
- struct {
- QRhiGraphicsPipeline *maybeGraphicsPs;
- QRhiComputePipeline *maybeComputePs;
- QRhiShaderResourceBindings *srb;
- int dynamicOffsetCount;
- uint dynamicOffsetPairs[MAX_DYNAMIC_OFFSET_COUNT * 2]; // binding, offset
- } bindShaderResources;
- struct {
- GLbitfield mask;
- float c[4];
- float d;
- quint32 s;
- } clear;
- struct {
- GLuint fbo;
- bool srgb;
- int colorAttCount;
- bool stereo;
- QRhiSwapChain::StereoTargetBuffer stereoTarget;
- } bindFramebuffer;
- struct {
- GLenum target;
- GLuint buffer;
- int offset;
- int size;
- const void *data; // must come from retainData()
- } bufferSubData;
- struct {
- QRhiBufferReadbackResult *result;
- GLenum target;
- GLuint buffer;
- int offset;
- int size;
- } getBufferSubData;
- struct {
- GLenum srcTarget;
- GLenum srcFaceTarget;
- GLuint srcTexture;
- int srcLevel;
- int srcX;
- int srcY;
- int srcZ;
- GLenum dstTarget;
- GLuint dstTexture;
- GLenum dstFaceTarget;
- int dstLevel;
- int dstX;
- int dstY;
- int dstZ;
- int w;
- int h;
- } copyTex;
- struct {
- QRhiReadbackResult *result;
- GLuint texture;
- int w;
- int h;
- QRhiTexture::Format format;
- GLenum readTarget;
- int level;
- int slice3D;
- } readPixels;
- struct {
- GLenum target;
- GLuint texture;
- GLenum faceTarget;
- int level;
- int dx;
- int dy;
- int dz;
- int w;
- int h;
- GLenum glformat;
- GLenum gltype;
- int rowStartAlign;
- int rowLength;
- const void *data; // must come from retainImage()
- } subImage;
- struct {
- GLenum target;
- GLuint texture;
- GLenum faceTarget;
- int level;
- GLenum glintformat;
- int w;
- int h;
- int depth;
- int size;
- const void *data; // must come from retainData()
- } compressedImage;
- struct {
- GLenum target;
- GLuint texture;
- GLenum faceTarget;
- int level;
- int dx;
- int dy;
- int dz;
- int w;
- int h;
- GLenum glintformat;
- int size;
- const void *data; // must come from retainData()
- } compressedSubImage;
- struct {
- GLuint renderbuffer;
- int w;
- int h;
- GLenum target;
- GLuint texture;
- int dstLevel;
- int dstLayer;
- } blitFromRb;
- struct {
- GLenum target;
- GLuint texture;
- } genMip;
- struct {
- QRhiComputePipeline *ps;
- } bindComputePipeline;
- struct {
- GLuint x;
- GLuint y;
- GLuint z;
- } dispatch;
- struct {
- int trackerIndex;
- } barriersForPass;
- struct {
- GLbitfield barriers;
- } barrier;
- } args;
- };
-
- enum PassType {
- NoPass,
- RenderPass,
- ComputePass
- };
-
- QRhiBackendCommandList<Command> commands;
- QVarLengthArray<QRhiPassResourceTracker, 8> passResTrackers;
- int currentPassResTrackerIndex;
-
- PassType recordingPass;
- bool passNeedsResourceTracking;
- QRhiRenderTarget *currentTarget;
- QRhiGraphicsPipeline *currentGraphicsPipeline;
- QRhiComputePipeline *currentComputePipeline;
- uint currentPipelineGeneration;
- QRhiShaderResourceBindings *currentGraphicsSrb;
- QRhiShaderResourceBindings *currentComputeSrb;
- uint currentSrbGeneration;
-
- struct GraphicsPassState {
- bool valid = false;
- bool scissor;
- bool cullFace;
- GLenum cullMode;
- GLenum frontFace;
- bool blendEnabled;
- struct ColorMask { bool r, g, b, a; } colorMask;
- struct Blend {
- GLenum srcColor;
- GLenum dstColor;
- GLenum srcAlpha;
- GLenum dstAlpha;
- GLenum opColor;
- GLenum opAlpha;
- } blend;
- bool depthTest;
- bool depthWrite;
- GLenum depthFunc;
- bool stencilTest;
- GLuint stencilReadMask;
- GLuint stencilWriteMask;
- struct StencilFace {
- GLenum func;
- GLenum failOp;
- GLenum zfailOp;
- GLenum zpassOp;
- } stencil[2]; // front, back
- bool polyOffsetFill;
- float polyOffsetFactor;
- float polyOffsetUnits;
- float lineWidth;
- int cpCount;
- GLenum polygonMode;
- void reset() { valid = false; }
- struct {
- // not part of QRhiGraphicsPipeline but used by setGraphicsPipeline()
- GLint stencilRef = 0;
- } dynamic;
- } graphicsPassState;
-
- struct ComputePassState {
- enum Access {
- Read = 0x01,
- Write = 0x02
- };
- QHash<QRhiResource *, QPair<int, bool> > writtenResources;
- void reset() {
- writtenResources.clear();
- }
- } computePassState;
-
- struct TextureUnitState {
- void *ps;
- uint psGeneration;
- uint texture;
- } textureUnitState[16];
-
- QVarLengthArray<QByteArray, 4> dataRetainPool;
- QVarLengthArray<QRhiBufferData, 4> bufferDataRetainPool;
- QVarLengthArray<QImage, 4> imageRetainPool;
-
- // relies heavily on implicit sharing (no copies of the actual data will be made)
- const void *retainData(const QByteArray &data) {
- dataRetainPool.append(data);
- return dataRetainPool.last().constData();
- }
- const uchar *retainBufferData(const QRhiBufferData &data) {
- bufferDataRetainPool.append(data);
- return reinterpret_cast<const uchar *>(bufferDataRetainPool.last().constData());
- }
- const void *retainImage(const QImage &image) {
- imageRetainPool.append(image);
- return imageRetainPool.last().constBits();
- }
- void resetCommands() {
- commands.reset();
- dataRetainPool.clear();
- bufferDataRetainPool.clear();
- imageRetainPool.clear();
-
- passResTrackers.clear();
- currentPassResTrackerIndex = -1;
- }
- void resetState() {
- recordingPass = NoPass;
- passNeedsResourceTracking = true;
- currentTarget = nullptr;
- resetCommands();
- resetCachedState();
- }
- void resetCachedState() {
- currentGraphicsPipeline = nullptr;
- currentComputePipeline = nullptr;
- currentPipelineGeneration = 0;
- currentGraphicsSrb = nullptr;
- currentComputeSrb = nullptr;
- currentSrbGeneration = 0;
- graphicsPassState.reset();
- computePassState.reset();
- memset(textureUnitState, 0, sizeof(textureUnitState));
- }
-};
-
-inline bool operator==(const QGles2CommandBuffer::GraphicsPassState::StencilFace &a,
- const QGles2CommandBuffer::GraphicsPassState::StencilFace &b)
-{
- return a.func == b.func
- && a.failOp == b.failOp
- && a.zfailOp == b.zfailOp
- && a.zpassOp == b.zpassOp;
-}
-
-inline bool operator!=(const QGles2CommandBuffer::GraphicsPassState::StencilFace &a,
- const QGles2CommandBuffer::GraphicsPassState::StencilFace &b)
-{
- return !(a == b);
-}
-
-inline bool operator==(const QGles2CommandBuffer::GraphicsPassState::ColorMask &a,
- const QGles2CommandBuffer::GraphicsPassState::ColorMask &b)
-{
- return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
-}
-
-inline bool operator!=(const QGles2CommandBuffer::GraphicsPassState::ColorMask &a,
- const QGles2CommandBuffer::GraphicsPassState::ColorMask &b)
-{
- return !(a == b);
-}
-
-inline bool operator==(const QGles2CommandBuffer::GraphicsPassState::Blend &a,
- const QGles2CommandBuffer::GraphicsPassState::Blend &b)
-{
- return a.srcColor == b.srcColor
- && a.dstColor == b.dstColor
- && a.srcAlpha == b.srcAlpha
- && a.dstAlpha == b.dstAlpha
- && a.opColor == b.opColor
- && a.opAlpha == b.opAlpha;
-}
-
-inline bool operator!=(const QGles2CommandBuffer::GraphicsPassState::Blend &a,
- const QGles2CommandBuffer::GraphicsPassState::Blend &b)
-{
- return !(a == b);
-}
-
-struct QGles2SwapChain : public QRhiSwapChain
-{
- QGles2SwapChain(QRhiImplementation *rhi);
- ~QGles2SwapChain();
- void destroy() override;
-
- QRhiCommandBuffer *currentFrameCommandBuffer() override;
- QRhiRenderTarget *currentFrameRenderTarget() override;
- QRhiRenderTarget *currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override;
-
- QSize surfacePixelSize() override;
- bool isFormatSupported(Format f) override;
-
- QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
- bool createOrResize() override;
-
- void initSwapChainRenderTarget(QGles2SwapChainRenderTarget *rt);
-
- QSurface *surface = nullptr;
- QSize pixelSize;
- QGles2SwapChainRenderTarget rt;
- QGles2SwapChainRenderTarget rtLeft;
- QGles2SwapChainRenderTarget rtRight;
- QGles2CommandBuffer cb;
- int frameCount = 0;
-};
-
-class QRhiGles2 : public QRhiImplementation
-{
-public:
- QRhiGles2(QRhiGles2InitParams *params, QRhiGles2NativeHandles *importDevice = nullptr);
-
- bool create(QRhi::Flags flags) override;
- void destroy() override;
-
- QRhiGraphicsPipeline *createGraphicsPipeline() override;
- QRhiComputePipeline *createComputePipeline() override;
- QRhiShaderResourceBindings *createShaderResourceBindings() override;
- QRhiBuffer *createBuffer(QRhiBuffer::Type type,
- QRhiBuffer::UsageFlags usage,
- quint32 size) override;
- QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
- const QSize &pixelSize,
- int sampleCount,
- QRhiRenderBuffer::Flags flags,
- QRhiTexture::Format backingFormatHint) override;
- QRhiTexture *createTexture(QRhiTexture::Format format,
- const QSize &pixelSize,
- int depth,
- int arraySize,
- int sampleCount,
- QRhiTexture::Flags flags) override;
- QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
- QRhiSampler::Filter minFilter,
- QRhiSampler::Filter mipmapMode,
- QRhiSampler:: AddressMode u,
- QRhiSampler::AddressMode v,
- QRhiSampler::AddressMode w) override;
-
- QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
- QRhiTextureRenderTarget::Flags flags) override;
-
- QRhiSwapChain *createSwapChain() override;
- QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
- QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
- QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
- QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
- QRhi::FrameOpResult finish() override;
-
- void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
-
- void beginPass(QRhiCommandBuffer *cb,
- QRhiRenderTarget *rt,
- const QColor &colorClearValue,
- const QRhiDepthStencilClearValue &depthStencilClearValue,
- QRhiResourceUpdateBatch *resourceUpdates,
- QRhiCommandBuffer::BeginPassFlags flags) override;
- void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
-
- void setGraphicsPipeline(QRhiCommandBuffer *cb,
- QRhiGraphicsPipeline *ps) override;
-
- void setShaderResources(QRhiCommandBuffer *cb,
- QRhiShaderResourceBindings *srb,
- int dynamicOffsetCount,
- const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
-
- void setVertexInput(QRhiCommandBuffer *cb,
- int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
- QRhiBuffer *indexBuf, quint32 indexOffset,
- QRhiCommandBuffer::IndexFormat indexFormat) override;
-
- void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
- void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
- void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
- void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
-
- void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
- quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
-
- void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
- quint32 instanceCount, quint32 firstIndex,
- qint32 vertexOffset, quint32 firstInstance) override;
-
- void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
- void debugMarkEnd(QRhiCommandBuffer *cb) override;
- void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
-
- void beginComputePass(QRhiCommandBuffer *cb,
- QRhiResourceUpdateBatch *resourceUpdates,
- QRhiCommandBuffer::BeginPassFlags flags) override;
- void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
- void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
- void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
-
- const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
- void beginExternal(QRhiCommandBuffer *cb) override;
- void endExternal(QRhiCommandBuffer *cb) override;
-
- QList<int> supportedSampleCounts() const override;
- int ubufAlignment() const override;
- bool isYUpInFramebuffer() const override;
- bool isYUpInNDC() const override;
- bool isClipDepthZeroToOne() const override;
- QMatrix4x4 clipSpaceCorrMatrix() const override;
- bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
- bool isFeatureSupported(QRhi::Feature feature) const override;
- int resourceLimit(QRhi::ResourceLimit limit) const override;
- const QRhiNativeHandles *nativeHandles() override;
- QRhiDriverInfo driverInfo() const override;
- QRhiStats statistics() override;
- bool makeThreadLocalNativeContextCurrent() override;
- void releaseCachedResources() override;
- bool isDeviceLost() const override;
-
- QByteArray pipelineCacheData() override;
- void setPipelineCacheData(const QByteArray &data) override;
-
- bool ensureContext(QSurface *surface = nullptr) const;
- QSurface *evaluateFallbackSurface() const;
- void executeDeferredReleases();
- void trackedBufferBarrier(QGles2CommandBuffer *cbD, QGles2Buffer *bufD, QGles2Buffer::Access access);
- void trackedImageBarrier(QGles2CommandBuffer *cbD, QGles2Texture *texD, QGles2Texture::Access access);
- void enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cbD,
- int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc);
- void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
- void trackedRegisterBuffer(QRhiPassResourceTracker *passResTracker,
- QGles2Buffer *bufD,
- QRhiPassResourceTracker::BufferAccess access,
- QRhiPassResourceTracker::BufferStage stage);
- void trackedRegisterTexture(QRhiPassResourceTracker *passResTracker,
- QGles2Texture *texD,
- QRhiPassResourceTracker::TextureAccess access,
- QRhiPassResourceTracker::TextureStage stage);
- void executeCommandBuffer(QRhiCommandBuffer *cb);
- void executeBindGraphicsPipeline(QGles2CommandBuffer *cbD, QGles2GraphicsPipeline *psD);
- void bindCombinedSampler(QGles2CommandBuffer *cbD, QGles2Texture *texD, QGles2Sampler *samplerD,
- void *ps, uint psGeneration, int glslLocation,
- int *texUnit, bool *activeTexUnitAltered);
- void bindShaderResources(QGles2CommandBuffer *cbD,
- QRhiGraphicsPipeline *maybeGraphicsPs, QRhiComputePipeline *maybeComputePs,
- QRhiShaderResourceBindings *srb,
- const uint *dynOfsPairs, int dynOfsCount);
- QGles2RenderTargetData *enqueueBindFramebuffer(QRhiRenderTarget *rt, QGles2CommandBuffer *cbD,
- bool *wantsColorClear = nullptr, bool *wantsDsClear = nullptr);
- void enqueueBarriersForPass(QGles2CommandBuffer *cbD);
- int effectiveSampleCount(int sampleCount) const;
- QByteArray shaderSource(const QRhiShaderStage &shaderStage, QShaderVersion *shaderVersion);
- bool compileShader(GLuint program, const QRhiShaderStage &shaderStage, QShaderVersion *shaderVersion);
- bool linkProgram(GLuint program);
- void registerUniformIfActive(const QShaderDescription::BlockVariable &var,
- const QByteArray &namePrefix, int binding, int baseOffset,
- GLuint program,
- QDuplicateTracker<int, 256> *activeUniformLocations,
- QGles2UniformDescriptionVector *dst);
- void gatherUniforms(GLuint program, const QShaderDescription::UniformBlock &ub,
- QDuplicateTracker<int, 256> *activeUniformLocations, QGles2UniformDescriptionVector *dst);
- void gatherSamplers(GLuint program, const QShaderDescription::InOutVariable &v,
- QGles2SamplerDescriptionVector *dst);
- void gatherGeneratedSamplers(GLuint program,
- const QShader::SeparateToCombinedImageSamplerMapping &mapping,
- QGles2SamplerDescriptionVector *dst);
- void sanityCheckVertexFragmentInterface(const QShaderDescription &vsDesc, const QShaderDescription &fsDesc);
- bool isProgramBinaryDiskCacheEnabled() const;
-
- enum ProgramCacheResult {
- ProgramCacheHit,
- ProgramCacheMiss,
- ProgramCacheError
- };
- ProgramCacheResult tryLoadFromDiskOrPipelineCache(const QRhiShaderStage *stages,
- int stageCount,
- GLuint program,
- const QVector<QShaderDescription::InOutVariable> &inputVars,
- QByteArray *cacheKey);
- void trySaveToDiskCache(GLuint program, const QByteArray &cacheKey);
- void trySaveToPipelineCache(GLuint program, const QByteArray &cacheKey, bool force = false);
-
- QRhi::Flags rhiFlags;
- QOpenGLContext *ctx = nullptr;
- bool importedContext = false;
- QSurfaceFormat requestedFormat;
- QSurface *fallbackSurface = nullptr;
- QPointer<QWindow> maybeWindow = nullptr;
- QOpenGLContext *maybeShareContext = nullptr;
- mutable bool needsMakeCurrentDueToSwap = false;
- QOpenGLExtensions *f = nullptr;
- void (QOPENGLF_APIENTRYP glPolygonMode) (GLenum, GLenum) = nullptr;
- void(QOPENGLF_APIENTRYP glTexImage1D)(GLenum, GLint, GLint, GLsizei, GLint, GLenum, GLenum,
- const void *) = nullptr;
- void(QOPENGLF_APIENTRYP glTexStorage1D)(GLenum, GLint, GLenum, GLsizei) = nullptr;
- void(QOPENGLF_APIENTRYP glTexSubImage1D)(GLenum, GLint, GLint, GLsizei, GLenum, GLenum,
- const GLvoid *) = nullptr;
- void(QOPENGLF_APIENTRYP glCopyTexSubImage1D)(GLenum, GLint, GLint, GLint, GLint,
- GLsizei) = nullptr;
- void(QOPENGLF_APIENTRYP glCompressedTexImage1D)(GLenum, GLint, GLenum, GLsizei, GLint, GLsizei,
- const GLvoid *) = nullptr;
- void(QOPENGLF_APIENTRYP glCompressedTexSubImage1D)(GLenum, GLint, GLint, GLsizei, GLenum,
- GLsizei, const GLvoid *) = nullptr;
- void(QOPENGLF_APIENTRYP glFramebufferTexture1D)(GLenum, GLenum, GLenum, GLuint,
- GLint) = nullptr;
-
- uint vao = 0;
- struct Caps {
- Caps()
- : ctxMajor(2),
- ctxMinor(0),
- maxTextureSize(2048),
- maxDrawBuffers(4),
- maxSamples(16),
- maxTextureArraySize(0),
- maxThreadGroupsPerDimension(0),
- maxThreadsPerThreadGroup(0),
- maxThreadGroupsX(0),
- maxThreadGroupsY(0),
- maxThreadGroupsZ(0),
- maxUniformVectors(4096),
- maxVertexInputs(8),
- maxVertexOutputs(8),
- msaaRenderBuffer(false),
- multisampledTexture(false),
- npotTextureFull(true),
- gles(false),
- fixedIndexPrimitiveRestart(false),
- bgraExternalFormat(false),
- bgraInternalFormat(false),
- r8Format(false),
- r16Format(false),
- floatFormats(false),
- rgb10Formats(false),
- depthTexture(false),
- packedDepthStencil(false),
- needsDepthStencilCombinedAttach(false),
- srgbCapableDefaultFramebuffer(false),
- coreProfile(false),
- uniformBuffers(false),
- elementIndexUint(false),
- depth24(false),
- rgba8Format(false),
- instancing(false),
- baseVertex(false),
- compute(false),
- textureCompareMode(false),
- properMapBuffer(false),
- nonBaseLevelFramebufferTexture(false),
- texelFetch(false),
- intAttributes(true),
- screenSpaceDerivatives(false),
- programBinary(false),
- texture3D(false),
- tessellation(false),
- geometryShader(false),
- texture1D(false),
- hasDrawBuffersFunc(false),
- halfAttributes(false)
- { }
- int ctxMajor;
- int ctxMinor;
- int maxTextureSize;
- int maxDrawBuffers;
- int maxSamples;
- int maxTextureArraySize;
- int maxThreadGroupsPerDimension;
- int maxThreadsPerThreadGroup;
- int maxThreadGroupsX;
- int maxThreadGroupsY;
- int maxThreadGroupsZ;
- int maxUniformVectors;
- int maxVertexInputs;
- int maxVertexOutputs;
- // Multisample fb and blit are supported (GLES 3.0 or OpenGL 3.x). Not
- // the same as multisample textures!
- uint msaaRenderBuffer : 1;
- uint multisampledTexture : 1;
- uint npotTextureFull : 1;
- uint gles : 1;
- uint fixedIndexPrimitiveRestart : 1;
- uint bgraExternalFormat : 1;
- uint bgraInternalFormat : 1;
- uint r8Format : 1;
- uint r16Format : 1;
- uint floatFormats : 1;
- uint rgb10Formats : 1;
- uint depthTexture : 1;
- uint packedDepthStencil : 1;
- uint needsDepthStencilCombinedAttach : 1;
- uint srgbCapableDefaultFramebuffer : 1;
- uint coreProfile : 1;
- uint uniformBuffers : 1;
- uint elementIndexUint : 1;
- uint depth24 : 1;
- uint rgba8Format : 1;
- uint instancing : 1;
- uint baseVertex : 1;
- uint compute : 1;
- uint textureCompareMode : 1;
- uint properMapBuffer : 1;
- uint nonBaseLevelFramebufferTexture : 1;
- uint texelFetch : 1;
- uint intAttributes : 1;
- uint screenSpaceDerivatives : 1;
- uint programBinary : 1;
- uint texture3D : 1;
- uint tessellation : 1;
- uint geometryShader : 1;
- uint texture1D : 1;
- uint hasDrawBuffersFunc : 1;
- uint halfAttributes : 1;
- } caps;
- QGles2SwapChain *currentSwapChain = nullptr;
- QSet<GLint> supportedCompressedFormats;
- mutable QList<int> supportedSampleCountList;
- QRhiGles2NativeHandles nativeHandlesStruct;
- QRhiDriverInfo driverInfoStruct;
- mutable bool contextLost = false;
-
- struct DeferredReleaseEntry {
- enum Type {
- Buffer,
- Pipeline,
- Texture,
- RenderBuffer,
- TextureRenderTarget
- };
- Type type;
- union {
- struct {
- GLuint buffer;
- } buffer;
- struct {
- GLuint program;
- } pipeline;
- struct {
- GLuint texture;
- } texture;
- struct {
- GLuint renderbuffer;
- GLuint renderbuffer2;
- } renderbuffer;
- struct {
- GLuint framebuffer;
- } textureRenderTarget;
- };
- };
- QList<DeferredReleaseEntry> releaseQueue;
-
- struct OffscreenFrame {
- OffscreenFrame(QRhiImplementation *rhi) : cbWrapper(rhi) { }
- bool active = false;
- QGles2CommandBuffer cbWrapper;
- } ofr;
-
- QHash<QRhiShaderStage, uint> m_shaderCache;
-
- struct PipelineCacheData {
- quint32 format;
- QByteArray data;
- };
- QHash<QByteArray, PipelineCacheData> m_pipelineCache;
-};
-
-Q_DECLARE_TYPEINFO(QRhiGles2::DeferredReleaseEntry, Q_RELOCATABLE_TYPE);
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm
index 196016d9ca..89facf5be8 100644
--- a/src/gui/rhi/qrhimetal.mm
+++ b/src/gui/rhi/qrhimetal.mm
@@ -1,8 +1,8 @@
-// Copyright (C) 2019 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qrhimetal_p_p.h"
-#include <QtGui/private/qshader_p_p.h>
+#include "qrhimetal_p.h"
+#include "qshader_p.h"
#include <QGuiApplication>
#include <QWindow>
#include <QUrl>
@@ -40,19 +40,28 @@ QT_BEGIN_NAMESPACE
#error ARC not supported
#endif
-// Note: we expect everything here pass the Metal API validation when running
-// in Debug mode in XCode (or with METAL_DEVICE_WRAPPER_TYPE=1). An exception
-// is the nextDrawable Called Early blah blah warning, which is plain and
-// simply false. This may not be present with newer XCode. There may also be
-// warnings about threading (e.g. about accessing view.layer), those are
-// expected for now.
+// Even though the macOS 13 MTLBinaryArchive problem (QTBUG-106703) seems
+// to be solved in later 13.x releases, we have reports from old Intel hardware
+// and older macOS versions where this causes problems (QTBUG-114338).
+// Thus we no longer do OS version based differentiation, but rather have a
+// single toggle that is currently on, and so QRhi::(set)pipelineCache()
+// does nothing with Metal.
+#define QRHI_METAL_DISABLE_BINARY_ARCHIVE
+
+// We should be able to operate with command buffers that do not automatically
+// retain/release the resources used by them. (since we have logic that mirrors
+// other backends such as the Vulkan one anyway)
+#define QRHI_METAL_COMMAND_BUFFERS_WITH_UNRETAINED_REFERENCES
/*!
\class QRhiMetalInitParams
\inmodule QtRhi
- \internal
+ \since 6.6
\brief Metal specific initialization parameters.
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
A Metal-based QRhi needs no special parameters for initialization.
\badcode
@@ -85,14 +94,30 @@ QT_BEGIN_NAMESPACE
/*!
\class QRhiMetalNativeHandles
\inmodule QtRhi
- \internal
+ \since 6.6
\brief Holds the Metal device used by the QRhi.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
+ \variable QRhiMetalNativeHandles::dev
+
+ Set to a valid MTLDevice to import an existing device.
+*/
+
+/*!
+ \variable QRhiMetalNativeHandles::cmdQueue
+
+ Set to a valid MTLCommandQueue when importing an existing command queue.
+ When \nullptr, QRhi will create a new command queue.
+*/
+
+/*!
\class QRhiMetalCommandBufferNativeHandles
\inmodule QtRhi
- \internal
+ \since 6.6
\brief Holds the MTLCommandBuffer and MTLRenderCommandEncoder objects that are backing a QRhiCommandBuffer.
\note The command buffer object is only guaranteed to be valid while
@@ -104,8 +129,19 @@ QT_BEGIN_NAMESPACE
\note The command encoder is only valid while recording a pass, that is,
between \l{QRhiCommandBuffer::beginPass()} -
\l{QRhiCommandBuffer::endPass()}.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
+/*!
+ \variable QRhiMetalCommandBufferNativeHandles::commandBuffer
+*/
+
+/*!
+ \variable QRhiMetalCommandBufferNativeHandles::encoder
+*/
+
struct QMetalShader
{
id<MTLLibrary> lib = nil;
@@ -133,8 +169,8 @@ struct QRhiMetalData
id<MTLDevice> dev = nil;
id<MTLCommandQueue> cmdQueue = nil;
API_AVAILABLE(macosx(11.0), ios(14.0)) id<MTLBinaryArchive> binArch = nil;
- bool binArchWasEmpty = false;
+ id<MTLCommandBuffer> newCommandBuffer();
MTLRenderPassDescriptor *createDefaultRenderPass(bool hasDepthStencil,
const QColor &colorClearValue,
const QRhiDepthStencilClearValue &depthStencilClearValue,
@@ -194,6 +230,7 @@ struct QRhiMetalData
struct OffscreenFrame {
OffscreenFrame(QRhiImplementation *rhi) : cbWrapper(rhi) { }
bool active = false;
+ double lastGpuTime = 0;
QMetalCommandBuffer cbWrapper;
} ofr;
@@ -211,7 +248,7 @@ struct QRhiMetalData
struct BufferReadback
{
int activeFrameSlot = -1;
- QRhiBufferReadbackResult *result;
+ QRhiReadbackResult *result;
quint32 offset;
quint32 readSize;
id<MTLBuffer> buf;
@@ -296,6 +333,7 @@ struct QMetalShaderResourceBindingsData {
struct QMetalCommandBufferData
{
id<MTLCommandBuffer> cb;
+ double lastGpuTime = 0;
id<MTLRenderCommandEncoder> currentRenderPassEncoder;
id<MTLComputeCommandEncoder> currentComputePassEncoder;
id<MTLComputeCommandEncoder> tessellationComputeEncoder;
@@ -330,8 +368,11 @@ struct QMetalRenderTargetData
struct {
ColorAtt colorAtt[QMetalRenderPassDescriptor::MAX_COLOR_ATTACHMENTS];
id<MTLTexture> dsTex = nil;
+ id<MTLTexture> dsResolveTex = nil;
bool hasStencil = false;
bool depthNeedsStore = false;
+ bool preserveColor = false;
+ bool preserveDs = false;
} fb;
QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList;
@@ -350,6 +391,15 @@ struct QMetalGraphicsPipelineData
float slopeScaledDepthBias;
QMetalShader vs;
QMetalShader fs;
+ struct ExtraBufferManager {
+ enum class WorkBufType {
+ DeviceLocal,
+ HostVisible
+ };
+ QMetalBuffer *acquireWorkBuffer(QRhiMetal *rhiD, quint32 size, WorkBufType type = WorkBufType::DeviceLocal);
+ QVector<QMetalBuffer *> deviceLocalWorkBuffers;
+ QVector<QMetalBuffer *> hostVisibleWorkBuffers;
+ } extraBufMgr;
struct Tessellation {
QMetalGraphicsPipelineData *q = nullptr;
bool enabled = false;
@@ -383,13 +433,6 @@ struct QMetalGraphicsPipelineData
id<MTLComputePipelineState> vsCompPipeline(QRhiMetal *rhiD, QShader::Variant vertexCompVariant);
id<MTLComputePipelineState> tescCompPipeline(QRhiMetal *rhiD);
id<MTLRenderPipelineState> teseFragRenderPipeline(QRhiMetal *rhiD, QMetalGraphicsPipeline *pipeline);
- enum class WorkBufType {
- DeviceLocal,
- HostVisible
- };
- QMetalBuffer *acquireWorkBuffer(QRhiMetal *rhiD, quint32 size, WorkBufType type = WorkBufType::DeviceLocal);
- QVector<QMetalBuffer *> deviceLocalWorkBuffers;
- QVector<QMetalBuffer *> hostVisibleWorkBuffers;
} tess;
void setupVertexInputDescriptor(MTLVertexDescriptor *desc);
void setupStageInputDescriptor(MTLStageInputOutputDescriptor *desc);
@@ -413,6 +456,7 @@ struct QMetalSwapChainData
CAMetalLayer *layer = nullptr;
id<CAMetalDrawable> curDrawable = nil;
dispatch_semaphore_t sem[QMTL_FRAMES_IN_FLIGHT];
+ double lastGpuTime[QMTL_FRAMES_IN_FLIGHT];
MTLRenderPassDescriptor *rp = nullptr;
id<MTLTexture> msaaTex[QMTL_FRAMES_IN_FLIGHT];
QRhiTexture::Format rhiColorFormat;
@@ -432,7 +476,7 @@ QRhiMetal::QRhiMetal(QRhiMetalInitParams *params, QRhiMetalNativeHandles *import
importedDevice = importDevice != nullptr;
if (importedDevice) {
- if (d->dev) {
+ if (importDevice->dev) {
d->dev = (id<MTLDevice>) importDevice->dev;
importedCmdQueue = importDevice->cmdQueue != nullptr;
if (importedCmdQueue)
@@ -466,8 +510,24 @@ bool QRhiMetal::probe(QRhiMetalInitParams *params)
return false;
}
+id<MTLCommandBuffer> QRhiMetalData::newCommandBuffer()
+{
+#ifdef QRHI_METAL_COMMAND_BUFFERS_WITH_UNRETAINED_REFERENCES
+ // Do not let the command buffer mess with the refcount of objects. We do
+ // have a proper render loop and will manage lifetimes similarly to other
+ // backends (Vulkan).
+ return [cmdQueue commandBufferWithUnretainedReferences];
+#else
+ return [cmdQueue commandBuffer];
+#endif
+}
+
bool QRhiMetalData::setupBinaryArchive(NSURL *sourceFileUrl)
{
+#ifdef QRHI_METAL_DISABLE_BINARY_ARCHIVE
+ return false;
+#endif
+
if (@available(macOS 11.0, iOS 14.0, *)) {
[binArch release];
MTLBinaryArchiveDescriptor *binArchDesc = [MTLBinaryArchiveDescriptor new];
@@ -480,7 +540,6 @@ bool QRhiMetalData::setupBinaryArchive(NSURL *sourceFileUrl)
qWarning("newBinaryArchiveWithDescriptor failed: %s", qPrintable(msg));
return false;
}
- binArchWasEmpty = sourceFileUrl == nil;
return true;
}
return false;
@@ -508,9 +567,7 @@ bool QRhiMetal::create(QRhi::Flags flags)
// suitable as deviceId because it does not seem stable on macOS and can
// apparently change when the system is rebooted.
-#ifdef Q_OS_IOS
- driverInfoStruct.deviceType = QRhiDriverInfo::IntegratedDevice;
-#else
+#ifdef Q_OS_MACOS
if (@available(macOS 10.15, *)) {
const MTLDeviceLocation deviceLocation = [d->dev location];
switch (deviceLocation) {
@@ -527,6 +584,8 @@ bool QRhiMetal::create(QRhi::Flags flags)
break;
}
}
+#else
+ driverInfoStruct.deviceType = QRhiDriverInfo::IntegratedDevice;
#endif
const QOperatingSystemVersion ver = QOperatingSystemVersion::current();
@@ -552,6 +611,7 @@ bool QRhiMetal::create(QRhi::Flags flags)
if (@available(macOS 10.15, *))
caps.isAppleGPU = [d->dev supportsFamily:MTLGPUFamilyApple7];
caps.maxThreadGroupSize = 1024;
+ caps.multiView = true;
#elif defined(Q_OS_TVOS)
if ([d->dev supportsFeatureSet: MTLFeatureSet(30003)]) // MTLFeatureSet_tvOS_GPUFamily2_v1
caps.maxTextureSize = 16384;
@@ -578,8 +638,10 @@ bool QRhiMetal::create(QRhi::Flags flags)
}
caps.isAppleGPU = true;
if (@available(iOS 13, *)) {
- if ([d->dev supportsFamily:MTLGPUFamilyApple4])
+ if ([d->dev supportsFamily: MTLGPUFamilyApple4])
caps.maxThreadGroupSize = 1024;
+ if ([d->dev supportsFamily: MTLGPUFamilyApple5])
+ caps.multiView = true;
}
#endif
@@ -629,17 +691,6 @@ QVector<int> QRhiMetal::supportedSampleCounts() const
return caps.supportedSampleCounts;
}
-int QRhiMetal::effectiveSampleCount(int sampleCount) const
-{
- // Stay compatible with QSurfaceFormat and friends where samples == 0 means the same as 1.
- const int s = qBound(1, sampleCount, 64);
- if (!supportedSampleCounts().contains(s)) {
- qWarning("Attempted to set unsupported sample count %d", sampleCount);
- return 1;
- }
- return s;
-}
-
QRhiSwapChain *QRhiMetal::createSwapChain()
{
return new QMetalSwapChain(this);
@@ -727,7 +778,7 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const
case QRhi::DebugMarkers:
return true;
case QRhi::Timestamps:
- return false;
+ return true;
case QRhi::Instancing:
return true;
case QRhi::CustomInstanceStepRate:
@@ -805,6 +856,12 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const
return false;
case QRhi::ThreeDimensionalTextureMipmaps:
return true;
+ case QRhi::MultiView:
+ return caps.multiView;
+ case QRhi::TextureViewFormat:
+ return false;
+ case QRhi::ResolveDepthStencil:
+ return true;
default:
Q_UNREACHABLE();
return false;
@@ -1441,11 +1498,11 @@ void QRhiMetal::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline
psD->makeActiveForCurrentRenderPassEncoder(cbD);
} else {
// mark work buffers that can now be safely reused as reusable
- for (QMetalBuffer *workBuf : psD->d->tess.deviceLocalWorkBuffers) {
+ for (QMetalBuffer *workBuf : psD->d->extraBufMgr.deviceLocalWorkBuffers) {
if (workBuf && workBuf->lastActiveFrameSlot == currentFrameSlot)
workBuf->lastActiveFrameSlot = -1;
}
- for (QMetalBuffer *workBuf : psD->d->tess.hostVisibleWorkBuffers) {
+ for (QMetalBuffer *workBuf : psD->d->extraBufMgr.hostVisibleWorkBuffers) {
if (workBuf && workBuf->lastActiveFrameSlot == currentFrameSlot)
workBuf->lastActiveFrameSlot = -1;
}
@@ -1937,6 +1994,7 @@ void QRhiMetal::tessellatedDraw(const TessDrawArgs &args)
const quint32 vertexOrIndexCount = indexed ? args.drawIndexed.indexCount : args.draw.vertexCount;
QMetalGraphicsPipelineData::Tessellation &tess(graphicsPipeline->d->tess);
+ QMetalGraphicsPipelineData::ExtraBufferManager &extraBufMgr(graphicsPipeline->d->extraBufMgr);
const quint32 patchCount = tess.patchCountForDrawCall(vertexOrIndexCount, instanceCount);
QMetalBuffer *vertOutBuf = nullptr;
QMetalBuffer *tescOutBuf = nullptr;
@@ -1970,7 +2028,7 @@ void QRhiMetal::tessellatedDraw(const TessDrawArgs &args)
if (outputBufferBinding >= 0) {
const quint32 workBufSize = tess.vsCompOutputBufferSize(vertexOrIndexCount, instanceCount);
- vertOutBuf = tess.acquireWorkBuffer(this, workBufSize);
+ vertOutBuf = extraBufMgr.acquireWorkBuffer(this, workBufSize);
if (!vertOutBuf)
return;
[computeEncoder setBuffer: vertOutBuf->d->buf[0] offset: 0 atIndex: outputBufferBinding];
@@ -2018,7 +2076,7 @@ void QRhiMetal::tessellatedDraw(const TessDrawArgs &args)
if (outputBufferBinding >= 0) {
const quint32 workBufSize = tess.tescCompOutputBufferSize(patchCount);
- tescOutBuf = tess.acquireWorkBuffer(this, workBufSize);
+ tescOutBuf = extraBufMgr.acquireWorkBuffer(this, workBufSize);
if (!tescOutBuf)
return;
[computeEncoder setBuffer: tescOutBuf->d->buf[0] offset: 0 atIndex: outputBufferBinding];
@@ -2026,14 +2084,14 @@ void QRhiMetal::tessellatedDraw(const TessDrawArgs &args)
if (patchOutputBufferBinding >= 0) {
const quint32 workBufSize = tess.tescCompPatchOutputBufferSize(patchCount);
- tescPatchOutBuf = tess.acquireWorkBuffer(this, workBufSize);
+ tescPatchOutBuf = extraBufMgr.acquireWorkBuffer(this, workBufSize);
if (!tescPatchOutBuf)
return;
[computeEncoder setBuffer: tescPatchOutBuf->d->buf[0] offset: 0 atIndex: patchOutputBufferBinding];
}
if (tessFactorBufferBinding >= 0) {
- tescFactorBuf = tess.acquireWorkBuffer(this, patchCount * sizeof(MTLQuadTessellationFactorsHalf));
+ tescFactorBuf = extraBufMgr.acquireWorkBuffer(this, patchCount * sizeof(MTLQuadTessellationFactorsHalf));
[computeEncoder setBuffer: tescFactorBuf->d->buf[0] offset: 0 atIndex: tessFactorBufferBinding];
}
@@ -2042,7 +2100,7 @@ void QRhiMetal::tessellatedDraw(const TessDrawArgs &args)
quint32 inControlPointCount;
quint32 patchCount;
} params;
- tescParamsBuf = tess.acquireWorkBuffer(this, sizeof(params), QMetalGraphicsPipelineData::Tessellation::WorkBufType::HostVisible);
+ tescParamsBuf = extraBufMgr.acquireWorkBuffer(this, sizeof(params), QMetalGraphicsPipelineData::ExtraBufferManager::WorkBufType::HostVisible);
if (!tescParamsBuf)
return;
params.inControlPointCount = tess.inControlPointCount;
@@ -2111,6 +2169,39 @@ void QRhiMetal::tessellatedDraw(const TessDrawArgs &args)
}
}
+void QRhiMetal::adjustForMultiViewDraw(quint32 *instanceCount, QRhiCommandBuffer *cb)
+{
+ QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
+ const int multiViewCount = cbD->currentGraphicsPipeline->m_multiViewCount;
+ if (multiViewCount <= 1)
+ return;
+
+ const QMap<int, int> &ebb(cbD->currentGraphicsPipeline->d->vs.nativeShaderInfo.extraBufferBindings);
+ const int viewMaskBufBinding = ebb.value(QShaderPrivate::MslMultiViewMaskBufferBinding, -1);
+ if (viewMaskBufBinding == -1) {
+ qWarning("No extra buffer for multiview in the vertex shader; was it built with --view-count specified?");
+ return;
+ }
+ struct {
+ quint32 viewOffset;
+ quint32 viewCount;
+ } multiViewInfo;
+ multiViewInfo.viewOffset = 0;
+ multiViewInfo.viewCount = quint32(multiViewCount);
+ QMetalBuffer *buf = cbD->currentGraphicsPipeline->d->extraBufMgr.acquireWorkBuffer(this, sizeof(multiViewInfo),
+ QMetalGraphicsPipelineData::ExtraBufferManager::WorkBufType::HostVisible);
+ if (buf) {
+ id<MTLBuffer> mtlbuf = buf->d->buf[0];
+ char *p = reinterpret_cast<char *>([mtlbuf contents]);
+ memcpy(p, &multiViewInfo, sizeof(multiViewInfo));
+ [cbD->d->currentRenderPassEncoder setVertexBuffer: mtlbuf offset: 0 atIndex: viewMaskBufBinding];
+ // The instance count is adjusted for layered rendering. The vertex shader is expected to contain something like:
+ // uint gl_ViewIndex = spvViewMask[0] + (gl_InstanceIndex - gl_BaseInstance) % spvViewMask[1];
+ // where spvViewMask is the buffer with multiViewInfo passed in above.
+ *instanceCount *= multiViewCount;
+ }
+}
+
void QRhiMetal::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
quint32 instanceCount, quint32 firstVertex, quint32 firstInstance)
{
@@ -2129,6 +2220,8 @@ void QRhiMetal::draw(QRhiCommandBuffer *cb, quint32 vertexCount,
return;
}
+ adjustForMultiViewDraw(&instanceCount, cb);
+
if (caps.baseVertexAndInstance) {
[cbD->d->currentRenderPassEncoder drawPrimitives: cbD->currentGraphicsPipeline->d->primitiveType
vertexStart: firstVertex vertexCount: vertexCount instanceCount: instanceCount baseInstance: firstInstance];
@@ -2167,6 +2260,8 @@ void QRhiMetal::drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
return;
}
+ adjustForMultiViewDraw(&instanceCount, cb);
+
if (caps.baseVertexAndInstance) {
[cbD->d->currentRenderPassEncoder drawIndexedPrimitives: cbD->currentGraphicsPipeline->d->primitiveType
indexCount: indexCount
@@ -2237,6 +2332,12 @@ void QRhiMetal::endExternal(QRhiCommandBuffer *cb)
cbD->resetPerPassCachedState();
}
+double QRhiMetal::lastCompletedGpuTime(QRhiCommandBuffer *cb)
+{
+ QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
+ return cbD->d->lastGpuTime;
+}
+
QRhi::FrameOpResult QRhiMetal::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
{
Q_UNUSED(flags);
@@ -2263,10 +2364,7 @@ QRhi::FrameOpResult QRhiMetal::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF
[d->captureScope beginScope];
- // Do not let the command buffer mess with the refcount of objects. We do
- // have a proper render loop and will manage lifetimes similarly to other
- // backends (Vulkan).
- swapChainD->cbWrapper.d->cb = [d->cmdQueue commandBufferWithUnretainedReferences];
+ swapChainD->cbWrapper.d->cb = d->newCommandBuffer();
QMetalRenderTargetData::ColorAtt colorAtt;
if (swapChainD->samples > 1) {
@@ -2278,6 +2376,7 @@ QRhi::FrameOpResult QRhiMetal::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF
swapChainD->rtWrapper.d->fb.colorAtt[0] = colorAtt;
swapChainD->rtWrapper.d->fb.dsTex = swapChainD->ds ? swapChainD->ds->d->tex : nil;
+ swapChainD->rtWrapper.d->fb.dsResolveTex = nil;
swapChainD->rtWrapper.d->fb.hasStencil = swapChainD->ds ? true : false;
swapChainD->rtWrapper.d->fb.depthNeedsStore = false;
@@ -2285,7 +2384,8 @@ QRhi::FrameOpResult QRhiMetal::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginF
swapChainD->ds->lastActiveFrameSlot = currentFrameSlot;
executeDeferredReleases();
- swapChainD->cbWrapper.resetState();
+ swapChainD->cbWrapper.resetState(swapChainD->d->lastGpuTime[currentFrameSlot]);
+ swapChainD->d->lastGpuTime[currentFrameSlot] = 0;
finishActiveReadbacks();
return QRhi::FrameOpSuccess;
@@ -2297,10 +2397,21 @@ QRhi::FrameOpResult QRhiMetal::endFrame(QRhiSwapChain *swapChain, QRhi::EndFrame
Q_ASSERT(currentSwapChain == swapChainD);
__block int thisFrameSlot = currentFrameSlot;
- [swapChainD->cbWrapper.d->cb addCompletedHandler: ^(id<MTLCommandBuffer>) {
+ [swapChainD->cbWrapper.d->cb addCompletedHandler: ^(id<MTLCommandBuffer> cb) {
+ swapChainD->d->lastGpuTime[thisFrameSlot] += cb.GPUEndTime - cb.GPUStartTime;
dispatch_semaphore_signal(swapChainD->d->sem[thisFrameSlot]);
}];
+#ifdef QRHI_METAL_COMMAND_BUFFERS_WITH_UNRETAINED_REFERENCES
+ // When Metal API validation diagnostics is enabled in Xcode the texture is
+ // released before the command buffer is done with it. Manually keep it alive
+ // to work around this.
+ id<MTLTexture> drawableTexture = [swapChainD->d->curDrawable.texture retain];
+ [swapChainD->cbWrapper.d->cb addCompletedHandler:^(id<MTLCommandBuffer>) {
+ [drawableTexture release];
+ }];
+#endif
+
const bool needsPresent = !flags.testFlag(QRhi::SkipPresent);
const bool presentsWithTransaction = swapChainD->d->layer.presentsWithTransaction;
if (!presentsWithTransaction && needsPresent) {
@@ -2347,10 +2458,11 @@ QRhi::FrameOpResult QRhiMetal::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi:
d->ofr.active = true;
*cb = &d->ofr.cbWrapper;
- d->ofr.cbWrapper.d->cb = [d->cmdQueue commandBufferWithUnretainedReferences];
+ d->ofr.cbWrapper.d->cb = d->newCommandBuffer();
executeDeferredReleases();
- d->ofr.cbWrapper.resetState();
+ d->ofr.cbWrapper.resetState(d->ofr.lastGpuTime);
+ d->ofr.lastGpuTime = 0;
finishActiveReadbacks();
return QRhi::FrameOpSuccess;
@@ -2362,10 +2474,13 @@ QRhi::FrameOpResult QRhiMetal::endOffscreenFrame(QRhi::EndFrameFlags flags)
Q_ASSERT(d->ofr.active);
d->ofr.active = false;
- [d->ofr.cbWrapper.d->cb commit];
+ id<MTLCommandBuffer> cb = d->ofr.cbWrapper.d->cb;
+ [cb commit];
// offscreen frames wait for completion, unlike swapchain ones
- [d->ofr.cbWrapper.d->cb waitUntilCompleted];
+ [cb waitUntilCompleted];
+
+ d->ofr.lastGpuTime += cb.GPUEndTime - cb.GPUStartTime;
finishActiveReadbacks(true);
@@ -2406,10 +2521,13 @@ QRhi::FrameOpResult QRhiMetal::finish()
}
if (inFrame) {
- if (d->ofr.active)
- d->ofr.cbWrapper.d->cb = [d->cmdQueue commandBufferWithUnretainedReferences];
- else
- swapChainD->cbWrapper.d->cb = [d->cmdQueue commandBufferWithUnretainedReferences];
+ if (d->ofr.active) {
+ d->ofr.lastGpuTime += cb.GPUEndTime - cb.GPUStartTime;
+ d->ofr.cbWrapper.d->cb = d->newCommandBuffer();
+ } else {
+ swapChainD->d->lastGpuTime[currentFrameSlot] += cb.GPUEndTime - cb.GPUStartTime;
+ swapChainD->cbWrapper.d->cb = d->newCommandBuffer();
+ }
}
executeDeferredReleases(true);
@@ -2471,7 +2589,6 @@ void QRhiMetal::enqueueSubresUpload(QMetalTexture *texD, void *mp, void *blitEnc
int w = img.width();
int h = img.height();
int bpl = img.bytesPerLine();
- int srcOffset = 0;
if (!subresDesc.sourceSize().isEmpty() || !subresDesc.sourceTopLeft().isNull()) {
const int sx = subresDesc.sourceTopLeft().x();
@@ -2480,10 +2597,12 @@ void QRhiMetal::enqueueSubresUpload(QMetalTexture *texD, void *mp, void *blitEnc
w = subresDesc.sourceSize().width();
h = subresDesc.sourceSize().height();
}
- if (img.depth() == 32) {
- memcpy(reinterpret_cast<char *>(mp) + *curOfs, img.constBits(), size_t(fullImageSizeBytes));
- srcOffset = sy * bpl + sx * 4;
- // bpl remains set to the original image's row stride
+ if (w == img.width()) {
+ const int bpc = qMax(1, img.depth() / 8);
+ Q_ASSERT(h * img.bytesPerLine() <= fullImageSizeBytes);
+ memcpy(reinterpret_cast<char *>(mp) + *curOfs,
+ img.constBits() + sy * img.bytesPerLine() + sx * bpc,
+ h * img.bytesPerLine());
} else {
img = img.copy(sx, sy, w, h);
bpl = img.bytesPerLine();
@@ -2495,7 +2614,7 @@ void QRhiMetal::enqueueSubresUpload(QMetalTexture *texD, void *mp, void *blitEnc
}
[blitEnc copyFromBuffer: texD->d->stagingBuf[currentFrameSlot]
- sourceOffset: NSUInteger(*curOfs + srcOffset)
+ sourceOffset: NSUInteger(*curOfs)
sourceBytesPerRow: NSUInteger(bpl)
sourceBytesPerImage: 0
sourceSize: MTLSizeMake(NSUInteger(w), NSUInteger(h), 1)
@@ -2587,6 +2706,15 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
QMetalCommandBuffer *cbD = QRHI_RES(QMetalCommandBuffer, cb);
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
+ id<MTLBlitCommandEncoder> blitEnc = nil;
+ auto ensureBlit = [&blitEnc, cbD, this]() {
+ if (!blitEnc) {
+ blitEnc = [cbD->d->cb blitCommandEncoder];
+ if (debugMarkers)
+ [blitEnc pushDebugGroup: @"Texture upload/copy"];
+ }
+ };
+
for (int opIdx = 0; opIdx < ud->activeBufferOpCount; ++opIdx) {
const QRhiResourceUpdateBatchPrivate::BufferOp &u(ud->bufferOps[opIdx]);
if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::DynamicUpdate) {
@@ -2625,19 +2753,17 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
readback.readSize = u.readSize;
readback.result = u.result;
d->activeBufferReadbacks.append(readback);
+#ifdef Q_OS_MACOS
+ if (bufD->d->managed) {
+ // On non-Apple Silicon, manually synchronize memory from GPU to CPU
+ ensureBlit();
+ [blitEnc synchronizeResource:readback.buf];
+ }
+#endif
}
}
}
- id<MTLBlitCommandEncoder> blitEnc = nil;
- auto ensureBlit = [&blitEnc, cbD, this] {
- if (!blitEnc) {
- blitEnc = [cbD->d->cb blitCommandEncoder];
- if (debugMarkers)
- [blitEnc pushDebugGroup: @"Texture upload/copy"];
- }
- };
-
for (int opIdx = 0; opIdx < ud->activeTextureOpCount; ++opIdx) {
const QRhiResourceUpdateBatchPrivate::TextureOp &u(ud->textureOps[opIdx]);
if (u.type == QRhiResourceUpdateBatchPrivate::TextureOp::Upload) {
@@ -2848,28 +2974,39 @@ void QRhiMetal::beginPass(QRhiCommandBuffer *cb,
if (!QRhiRenderTargetAttachmentTracker::isUpToDate<QMetalTexture, QMetalRenderBuffer>(rtTex->description(), rtD->currentResIdList))
rtTex->create();
cbD->d->currentPassRpDesc = d->createDefaultRenderPass(rtD->dsAttCount, colorClearValue, depthStencilClearValue, rtD->colorAttCount);
- if (rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents)) {
+ if (rtD->fb.preserveColor) {
for (uint i = 0; i < uint(rtD->colorAttCount); ++i)
cbD->d->currentPassRpDesc.colorAttachments[i].loadAction = MTLLoadActionLoad;
}
- if (rtD->dsAttCount && rtTex->m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents)) {
+ if (rtD->dsAttCount && rtD->fb.preserveDs) {
cbD->d->currentPassRpDesc.depthAttachment.loadAction = MTLLoadActionLoad;
cbD->d->currentPassRpDesc.stencilAttachment.loadAction = MTLLoadActionLoad;
}
+ int colorAttCount = 0;
for (auto it = rtTex->m_desc.cbeginColorAttachments(), itEnd = rtTex->m_desc.cendColorAttachments();
it != itEnd; ++it)
{
- if (it->texture())
+ colorAttCount += 1;
+ if (it->texture()) {
QRHI_RES(QMetalTexture, it->texture())->lastActiveFrameSlot = currentFrameSlot;
- else if (it->renderBuffer())
+ if (it->multiViewCount() >= 2)
+ cbD->d->currentPassRpDesc.renderTargetArrayLength = NSUInteger(it->multiViewCount());
+ } else if (it->renderBuffer()) {
QRHI_RES(QMetalRenderBuffer, it->renderBuffer())->lastActiveFrameSlot = currentFrameSlot;
+ }
if (it->resolveTexture())
QRHI_RES(QMetalTexture, it->resolveTexture())->lastActiveFrameSlot = currentFrameSlot;
}
if (rtTex->m_desc.depthStencilBuffer())
QRHI_RES(QMetalRenderBuffer, rtTex->m_desc.depthStencilBuffer())->lastActiveFrameSlot = currentFrameSlot;
- if (rtTex->m_desc.depthTexture())
- QRHI_RES(QMetalTexture, rtTex->m_desc.depthTexture())->lastActiveFrameSlot = currentFrameSlot;
+ if (rtTex->m_desc.depthTexture()) {
+ QMetalTexture *depthTexture = QRHI_RES(QMetalTexture, rtTex->m_desc.depthTexture());
+ depthTexture->lastActiveFrameSlot = currentFrameSlot;
+ if (colorAttCount == 0 && depthTexture->arraySize() >= 2)
+ cbD->d->currentPassRpDesc.renderTargetArrayLength = NSUInteger(depthTexture->arraySize());
+ }
+ if (rtTex->m_desc.depthResolveTexture())
+ QRHI_RES(QMetalTexture, rtTex->m_desc.depthResolveTexture())->lastActiveFrameSlot = currentFrameSlot;
}
break;
default:
@@ -2883,7 +3020,8 @@ void QRhiMetal::beginPass(QRhiCommandBuffer *cb,
cbD->d->currentPassRpDesc.colorAttachments[i].depthPlane = NSUInteger(rtD->fb.colorAtt[i].slice);
cbD->d->currentPassRpDesc.colorAttachments[i].level = NSUInteger(rtD->fb.colorAtt[i].level);
if (rtD->fb.colorAtt[i].resolveTex) {
- cbD->d->currentPassRpDesc.colorAttachments[i].storeAction = MTLStoreActionMultisampleResolve;
+ cbD->d->currentPassRpDesc.colorAttachments[i].storeAction = rtD->fb.preserveColor ? MTLStoreActionStoreAndMultisampleResolve
+ : MTLStoreActionMultisampleResolve;
cbD->d->currentPassRpDesc.colorAttachments[i].resolveTexture = rtD->fb.colorAtt[i].resolveTex;
cbD->d->currentPassRpDesc.colorAttachments[i].resolveSlice = NSUInteger(rtD->fb.colorAtt[i].resolveLayer);
cbD->d->currentPassRpDesc.colorAttachments[i].resolveLevel = NSUInteger(rtD->fb.colorAtt[i].resolveLevel);
@@ -2896,6 +3034,15 @@ void QRhiMetal::beginPass(QRhiCommandBuffer *cb,
cbD->d->currentPassRpDesc.stencilAttachment.texture = rtD->fb.hasStencil ? rtD->fb.dsTex : nil;
if (rtD->fb.depthNeedsStore) // Depth/Stencil is set to DontCare by default, override if needed
cbD->d->currentPassRpDesc.depthAttachment.storeAction = MTLStoreActionStore;
+ if (rtD->fb.dsResolveTex) {
+ cbD->d->currentPassRpDesc.depthAttachment.storeAction = rtD->fb.depthNeedsStore ? MTLStoreActionStoreAndMultisampleResolve
+ : MTLStoreActionMultisampleResolve;
+ cbD->d->currentPassRpDesc.depthAttachment.resolveTexture = rtD->fb.dsResolveTex;
+ if (rtD->fb.hasStencil) {
+ cbD->d->currentPassRpDesc.stencilAttachment.resolveTexture = rtD->fb.dsResolveTex;
+ cbD->d->currentPassRpDesc.stencilAttachment.storeAction = cbD->d->currentPassRpDesc.depthAttachment.storeAction;
+ }
+ }
}
cbD->d->currentRenderPassEncoder = [cbD->d->cb renderCommandEncoderWithDescriptor: cbD->d->currentPassRpDesc];
@@ -3666,12 +3813,10 @@ bool QMetalTexture::prepareCreate(QSize *adjustedSize)
qWarning("Texture cannot be both 1D and cube");
return false;
}
- m_depth = qMax(1, m_depth);
if (m_depth > 1 && !is3D) {
qWarning("Texture cannot have a depth of %d when it is not 3D", m_depth);
return false;
}
- m_arraySize = qMax(0, m_arraySize);
if (m_arraySize > 0 && !isArray) {
qWarning("Texture cannot have an array size of %d when it is not an array", m_arraySize);
return false;
@@ -3707,11 +3852,11 @@ bool QMetalTexture::create()
desc.textureType = isArray ? MTLTextureType1DArray : MTLTextureType1D;
} else if (isArray) {
#ifdef Q_OS_IOS
- if (samples > 1) {
- // would be available on iOS 14.0+ but cannot test for that with a 13 SDK
- qWarning("Multisample 2D texture array is not supported on iOS");
+ if (@available(iOS 14, *)) {
+ desc.textureType = samples > 1 ? MTLTextureType2DMultisampleArray : MTLTextureType2DArray;
+ } else {
+ desc.textureType = MTLTextureType2DArray;
}
- desc.textureType = MTLTextureType2DArray;
#else
desc.textureType = samples > 1 ? MTLTextureType2DMultisampleArray : MTLTextureType2DArray;
#endif
@@ -3721,12 +3866,12 @@ bool QMetalTexture::create()
desc.pixelFormat = d->format;
desc.width = NSUInteger(size.width());
desc.height = NSUInteger(size.height());
- desc.depth = is3D ? m_depth : 1;
+ desc.depth = is3D ? qMax(1, m_depth) : 1;
desc.mipmapLevelCount = NSUInteger(mipLevelCount);
if (samples > 1)
desc.sampleCount = NSUInteger(samples);
if (isArray)
- desc.arrayLength = NSUInteger(m_arraySize);
+ desc.arrayLength = NSUInteger(qMax(0, m_arraySize));
desc.resourceOptions = MTLResourceStorageModePrivate;
desc.storageMode = MTLStorageModePrivate;
desc.usage = MTLTextureUsageShaderRead;
@@ -3785,7 +3930,8 @@ id<MTLTexture> QMetalTextureData::viewForLevel(int level)
const bool isCube = q->m_flags.testFlag(QRhiTexture::CubeMap);
const bool isArray = q->m_flags.testFlag(QRhiTexture::TextureArray);
id<MTLTexture> view = [tex newTextureViewWithPixelFormat: format textureType: type
- levels: NSMakeRange(NSUInteger(level), 1) slices: NSMakeRange(0, isCube ? 6 : (isArray ? q->m_arraySize : 1))];
+ levels: NSMakeRange(NSUInteger(level), 1)
+ slices: NSMakeRange(0, isCube ? 6 : (isArray ? qMax(0, q->m_arraySize) : 1))];
perLevelViews[level] = view;
return view;
@@ -3930,7 +4076,9 @@ QMetalRenderPassDescriptor::~QMetalRenderPassDescriptor()
void QMetalRenderPassDescriptor::destroy()
{
- // nothing to do here
+ QRHI_RES_RHI(QRhiMetal);
+ if (rhiD)
+ rhiD->unregisterResource(this);
}
bool QMetalRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const
@@ -3973,13 +4121,17 @@ void QMetalRenderPassDescriptor::updateSerializedFormat()
QRhiRenderPassDescriptor *QMetalRenderPassDescriptor::newCompatibleRenderPassDescriptor() const
{
- QMetalRenderPassDescriptor *rp = new QMetalRenderPassDescriptor(m_rhi);
- rp->colorAttachmentCount = colorAttachmentCount;
- rp->hasDepthStencil = hasDepthStencil;
- memcpy(rp->colorFormat, colorFormat, sizeof(colorFormat));
- rp->dsFormat = dsFormat;
- rp->updateSerializedFormat();
- return rp;
+ QMetalRenderPassDescriptor *rpD = new QMetalRenderPassDescriptor(m_rhi);
+ rpD->colorAttachmentCount = colorAttachmentCount;
+ rpD->hasDepthStencil = hasDepthStencil;
+ memcpy(rpD->colorFormat, colorFormat, sizeof(colorFormat));
+ rpD->dsFormat = dsFormat;
+
+ rpD->updateSerializedFormat();
+
+ QRHI_RES_RHI(QRhiMetal);
+ rhiD->registerResource(rpD, false);
+ return rpD;
}
QVector<quint32> QMetalRenderPassDescriptor::serializedFormat() const
@@ -4035,7 +4187,9 @@ QMetalTextureRenderTarget::~QMetalTextureRenderTarget()
void QMetalTextureRenderTarget::destroy()
{
- // nothing to do here
+ QRHI_RES_RHI(QRhiMetal);
+ if (rhiD)
+ rhiD->unregisterResource(this);
}
QRhiRenderPassDescriptor *QMetalTextureRenderTarget::newCompatibleRenderPassDescriptor()
@@ -4058,6 +4212,9 @@ QRhiRenderPassDescriptor *QMetalTextureRenderTarget::newCompatibleRenderPassDesc
rpD->dsFormat = int(QRHI_RES(QMetalRenderBuffer, m_desc.depthStencilBuffer())->d->format);
rpD->updateSerializedFormat();
+
+ QRHI_RES_RHI(QRhiMetal);
+ rhiD->registerResource(rpD, false);
return rpD;
}
@@ -4108,8 +4265,9 @@ bool QMetalTextureRenderTarget::create()
if (m_desc.depthTexture()) {
QMetalTexture *depthTexD = QRHI_RES(QMetalTexture, m_desc.depthTexture());
d->fb.dsTex = depthTexD->d->tex;
- d->fb.hasStencil = false;
- d->fb.depthNeedsStore = true;
+ d->fb.hasStencil = rhiD->isStencilSupportingFormat(depthTexD->format());
+ d->fb.depthNeedsStore = !m_flags.testFlag(DoNotStoreDepthStencilContents) && !m_desc.depthResolveTexture();
+ d->fb.preserveDs = m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents);
if (d->colorAttCount == 0) {
d->pixelSize = depthTexD->pixelSize();
d->sampleCount = depthTexD->samples;
@@ -4119,18 +4277,27 @@ bool QMetalTextureRenderTarget::create()
d->fb.dsTex = depthRbD->d->tex;
d->fb.hasStencil = true;
d->fb.depthNeedsStore = false;
+ d->fb.preserveDs = false;
if (d->colorAttCount == 0) {
d->pixelSize = depthRbD->pixelSize();
d->sampleCount = depthRbD->samples;
}
}
+ if (m_desc.depthResolveTexture()) {
+ QMetalTexture *depthResolveTexD = QRHI_RES(QMetalTexture, m_desc.depthResolveTexture());
+ d->fb.dsResolveTex = depthResolveTexD->d->tex;
+ }
d->dsAttCount = 1;
} else {
d->dsAttCount = 0;
}
+ if (d->colorAttCount > 0)
+ d->fb.preserveColor = m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents);
+
QRhiRenderTargetAttachmentTracker::updateResIdList<QMetalTexture, QMetalRenderBuffer>(m_desc, &d->currentResIdList);
+ rhiD->registerResource(this, false);
return true;
}
@@ -4166,6 +4333,10 @@ void QMetalShaderResourceBindings::destroy()
{
sortedBindings.clear();
maxBinding = -1;
+
+ QRHI_RES_RHI(QRhiMetal);
+ if (rhiD)
+ rhiD->unregisterResource(this);
}
bool QMetalShaderResourceBindings::create()
@@ -4192,6 +4363,7 @@ bool QMetalShaderResourceBindings::create()
memset(&bd, 0, sizeof(BoundResourceData));
generation += 1;
+ rhiD->registerResource(this, false);
return true;
}
@@ -4234,10 +4406,10 @@ void QMetalGraphicsPipeline::destroy()
d->tess.compTesc.destroy();
d->tess.vertTese.destroy();
- qDeleteAll(d->tess.deviceLocalWorkBuffers);
- d->tess.deviceLocalWorkBuffers.clear();
- qDeleteAll(d->tess.hostVisibleWorkBuffers);
- d->tess.hostVisibleWorkBuffers.clear();
+ qDeleteAll(d->extraBufMgr.deviceLocalWorkBuffers);
+ d->extraBufMgr.deviceLocalWorkBuffers.clear();
+ qDeleteAll(d->extraBufMgr.hostVisibleWorkBuffers);
+ d->extraBufMgr.hostVisibleWorkBuffers.clear();
delete d->bufferSizeBuffer;
d->bufferSizeBuffer = nullptr;
@@ -4309,6 +4481,22 @@ static inline MTLVertexFormat toMetalAttributeFormat(QRhiVertexInputAttribute::F
return MTLVertexFormatHalf2;
case QRhiVertexInputAttribute::Half:
return MTLVertexFormatHalf;
+ case QRhiVertexInputAttribute::UShort4:
+ return MTLVertexFormatUShort4;
+ case QRhiVertexInputAttribute::UShort3:
+ return MTLVertexFormatUShort3;
+ case QRhiVertexInputAttribute::UShort2:
+ return MTLVertexFormatUShort2;
+ case QRhiVertexInputAttribute::UShort:
+ return MTLVertexFormatUShort;
+ case QRhiVertexInputAttribute::SShort4:
+ return MTLVertexFormatShort4;
+ case QRhiVertexInputAttribute::SShort3:
+ return MTLVertexFormatShort3;
+ case QRhiVertexInputAttribute::SShort2:
+ return MTLVertexFormatShort2;
+ case QRhiVertexInputAttribute::SShort:
+ return MTLVertexFormatShort;
default:
Q_UNREACHABLE();
return MTLVertexFormatFloat4;
@@ -4464,6 +4652,24 @@ static inline MTLPrimitiveType toMetalPrimitiveType(QRhiGraphicsPipeline::Topolo
}
}
+static inline MTLPrimitiveTopologyClass toMetalPrimitiveTopologyClass(QRhiGraphicsPipeline::Topology t)
+{
+ switch (t) {
+ case QRhiGraphicsPipeline::Triangles:
+ case QRhiGraphicsPipeline::TriangleStrip:
+ case QRhiGraphicsPipeline::TriangleFan:
+ return MTLPrimitiveTopologyClassTriangle;
+ case QRhiGraphicsPipeline::Lines:
+ case QRhiGraphicsPipeline::LineStrip:
+ return MTLPrimitiveTopologyClassLine;
+ case QRhiGraphicsPipeline::Points:
+ return MTLPrimitiveTopologyClassPoint;
+ default:
+ Q_UNREACHABLE();
+ return MTLPrimitiveTopologyClassTriangle;
+ }
+}
+
static inline MTLCullMode toMetalCullMode(QRhiGraphicsPipeline::CullMode c)
{
switch (c) {
@@ -4704,6 +4910,7 @@ void QMetalGraphicsPipelineData::setupVertexInputDescriptor(MTLVertexDescriptor
desc.attributes[loc].bufferIndex = NSUInteger(firstVertexBinding + it->binding());
}
int bindingIndex = 0;
+ const NSUInteger viewCount = qMax<NSUInteger>(1, q->multiViewCount());
for (auto it = vertexInputLayout.cbeginBindings(), itEnd = vertexInputLayout.cendBindings();
it != itEnd; ++it, ++bindingIndex)
{
@@ -4712,6 +4919,8 @@ void QMetalGraphicsPipelineData::setupVertexInputDescriptor(MTLVertexDescriptor
it->classification() == QRhiVertexInputBinding::PerInstance
? MTLVertexStepFunctionPerInstance : MTLVertexStepFunctionPerVertex;
desc.layouts[layoutIdx].stepRate = NSUInteger(it->instanceStepRate());
+ if (desc.layouts[layoutIdx].stepFunction == MTLVertexStepFunctionPerInstance)
+ desc.layouts[layoutIdx].stepRate *= viewCount;
desc.layouts[layoutIdx].stride = it->stride();
}
}
@@ -4760,33 +4969,10 @@ void QRhiMetalData::trySeedingRenderPipelineFromBinaryArchive(MTLRenderPipelineD
}
}
-static bool canAddToBinaryArchive(QRhiMetalData *d)
-{
- if (@available(macOS 11.0, iOS 14.0, *)) {
- if (!d->binArch)
- return false;
-
- // ### QTBUG-106703, QTBUG-108216, revisit after 13.0
- if (!d->binArchWasEmpty && d->q->osMajor >= 13) {
- static bool logPrinted = false;
- if (!logPrinted) {
- logPrinted = true;
- qCDebug(QRHI_LOG_INFO, "Skipping adding more pipelines to MTLBinaryArchive on this OS version (%d.%d) due to known issues.",
- d->q->osMajor, d->q->osMinor);
- }
- return false;
- }
-
- return true;
- } else {
- return false;
- }
-}
-
void QRhiMetalData::addRenderPipelineToBinaryArchive(MTLRenderPipelineDescriptor *rpDesc)
{
if (@available(macOS 11.0, iOS 14.0, *)) {
- if (canAddToBinaryArchive(this)) {
+ if (binArch) {
NSError *err = nil;
if (![binArch addRenderPipelineFunctionsWithDescriptor: rpDesc error: &err]) {
const QString msg = QString::fromNSString(err.localizedDescription);
@@ -4888,6 +5074,9 @@ bool QMetalGraphicsPipeline::createVertexFragmentPipeline()
QMetalRenderPassDescriptor *rpD = QRHI_RES(QMetalRenderPassDescriptor, m_renderPassDesc);
setupAttachmentsInMetalRenderPassDescriptor(rpDesc, rpD);
+ if (m_multiViewCount >= 2)
+ rpDesc.inputPrimitiveTopology = toMetalPrimitiveTopologyClass(m_topology);
+
rhiD->d->trySeedingRenderPipelineFromBinaryArchive(rpDesc);
if (rhiD->rhiFlags.testFlag(QRhi::EnablePipelineCacheDataSave))
@@ -5410,7 +5599,7 @@ id<MTLRenderPipelineState> QMetalGraphicsPipelineData::Tessellation::teseFragRen
return ps;
}
-QMetalBuffer *QMetalGraphicsPipelineData::Tessellation::acquireWorkBuffer(QRhiMetal *rhiD, quint32 size, WorkBufType type)
+QMetalBuffer *QMetalGraphicsPipelineData::ExtraBufferManager::acquireWorkBuffer(QRhiMetal *rhiD, quint32 size, WorkBufType type)
{
QVector<QMetalBuffer *> *workBuffers = type == WorkBufType::DeviceLocal ? &deviceLocalWorkBuffers : &hostVisibleWorkBuffers;
@@ -5476,6 +5665,9 @@ bool QMetalGraphicsPipeline::createTessellationPipelines(const QShader &tessVert
return false;
}
+ if (m_multiViewCount >= 2)
+ qWarning("Multiview is not supported with tessellation");
+
// Now the vertex shader is a compute shader.
// It should have three dedicated *VertexAsComputeShader variants.
// What the requested variant was (Standard or Batchable) plays no role here.
@@ -5766,7 +5958,7 @@ void QRhiMetalData::trySeedingComputePipelineFromBinaryArchive(MTLComputePipelin
void QRhiMetalData::addComputePipelineToBinaryArchive(MTLComputePipelineDescriptor *cpDesc)
{
if (@available(macOS 11.0, iOS 14.0, *)) {
- if (canAddToBinaryArchive(this)) {
+ if (binArch) {
NSError *err = nil;
if (![binArch addComputePipelineFunctionsWithDescriptor: cpDesc error: &err]) {
const QString msg = QString::fromNSString(err.localizedDescription);
@@ -5897,8 +6089,9 @@ const QRhiNativeHandles *QMetalCommandBuffer::nativeHandles()
return &nativeHandlesStruct;
}
-void QMetalCommandBuffer::resetState()
+void QMetalCommandBuffer::resetState(double lastGpuTime)
{
+ d->lastGpuTime = lastGpuTime;
d->currentRenderPassEncoder = nil;
d->currentComputePassEncoder = nil;
d->tessellationComputeEncoder = nil;
@@ -5982,6 +6175,7 @@ void QMetalSwapChain::destroy()
#endif
d->layer = nullptr;
+ m_proxyData = {};
[d->curDrawable release];
d->curDrawable = nil;
@@ -6045,14 +6239,24 @@ QSize QMetalSwapChain::surfacePixelSize()
bool QMetalSwapChain::isFormatSupported(Format f)
{
-#ifdef Q_OS_MACOS
- return f == SDR || f == HDRExtendedSrgbLinear;
-#endif
+ if (f == HDRExtendedSrgbLinear) {
+ if (@available(macOS 10.11, iOS 16.0, *))
+ return hdrInfo().limits.colorComponentValue.maxPotentialColorComponentValue > 1.0f;
+ else
+ return false;
+ } else if (f == HDRExtendedDisplayP3Linear) {
+ if (@available(macOS 11.0, iOS 14.0, *))
+ return hdrInfo().limits.colorComponentValue.maxPotentialColorComponentValue > 1.0f;
+ else
+ return false;
+ }
return f == SDR;
}
QRhiRenderPassDescriptor *QMetalSwapChain::newCompatibleRenderPassDescriptor()
{
+ QRHI_RES_RHI(QRhiMetal);
+
chooseFormats(); // ensure colorFormat and similar are filled out
QMetalRenderPassDescriptor *rpD = new QMetalRenderPassDescriptor(m_rhi);
@@ -6063,7 +6267,6 @@ QRhiRenderPassDescriptor *QMetalSwapChain::newCompatibleRenderPassDescriptor()
#ifdef Q_OS_MACOS
// m_depthStencil may not be built yet so cannot rely on computed fields in it
- QRHI_RES_RHI(QRhiMetal);
rpD->dsFormat = rhiD->d->dev.depth24Stencil8PixelFormatSupported
? MTLPixelFormatDepth24Unorm_Stencil8 : MTLPixelFormatDepth32Float_Stencil8;
#else
@@ -6071,6 +6274,8 @@ QRhiRenderPassDescriptor *QMetalSwapChain::newCompatibleRenderPassDescriptor()
#endif
rpD->updateSerializedFormat();
+
+ rhiD->registerResource(rpD, false);
return rpD;
}
@@ -6079,7 +6284,7 @@ void QMetalSwapChain::chooseFormats()
QRHI_RES_RHI(QRhiMetal);
samples = rhiD->effectiveSampleCount(m_sampleCount);
// pick a format that is allowed for CAMetalLayer.pixelFormat
- if (m_format == HDRExtendedSrgbLinear) {
+ if (m_format == HDRExtendedSrgbLinear || m_format == HDRExtendedDisplayP3Linear) {
d->colorFormat = MTLPixelFormatRGBA16Float;
d->rhiColorFormat = QRhiTexture::RGBA16F;
return;
@@ -6126,13 +6331,18 @@ bool QMetalSwapChain::createOrResize()
chooseFormats();
if (d->colorFormat != d->layer.pixelFormat)
d->layer.pixelFormat = d->colorFormat;
-#ifdef Q_OS_MACOS
- // Can't enable this on iOS until wantsExtendedDynamicRangeContent is available
+
if (m_format == HDRExtendedSrgbLinear) {
- d->layer.colorspace = CGColorSpaceCreateWithName(kCGColorSpaceExtendedLinearSRGB);
- d->layer.wantsExtendedDynamicRangeContent = YES;
+ if (@available(macOS 10.11, iOS 16.0, *)) {
+ d->layer.colorspace = CGColorSpaceCreateWithName(kCGColorSpaceExtendedLinearSRGB);
+ d->layer.wantsExtendedDynamicRangeContent = YES;
+ }
+ } else if (m_format == HDRExtendedDisplayP3Linear) {
+ if (@available(macOS 11.0, iOS 16.0, *)) {
+ d->layer.colorspace = CGColorSpaceCreateWithName(kCGColorSpaceExtendedLinearDisplayP3);
+ d->layer.wantsExtendedDynamicRangeContent = YES;
+ }
}
-#endif
if (m_flags.testFlag(UsedAsTransferSource))
d->layer.framebufferOnly = NO;
@@ -6202,6 +6412,7 @@ bool QMetalSwapChain::createOrResize()
d->curDrawable = nil;
for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) {
+ d->lastGpuTime[i] = 0;
if (!d->sem[i])
d->sem[i] = dispatch_semaphore_create(QMTL_FRAMES_IN_FLIGHT - 1);
}
@@ -6264,21 +6475,28 @@ QRhiSwapChainHdrInfo QMetalSwapChain::hdrInfo()
{
QRhiSwapChainHdrInfo info;
info.limitsType = QRhiSwapChainHdrInfo::ColorComponentValue;
- if (m_format == SDR) {
- info.limits.colorComponentValue.maxColorComponentValue = 1;
- return info;
- }
+ info.limits.colorComponentValue.maxColorComponentValue = 1;
+ info.limits.colorComponentValue.maxPotentialColorComponentValue = 1;
+ info.luminanceBehavior = QRhiSwapChainHdrInfo::DisplayReferred; // 1.0 = SDR white
+ info.sdrWhiteLevel = 200; // typical value, but dummy (don't know the real one); won't matter due to being display-referred
-#ifdef Q_OS_MACOS
- info.isHardCodedDefaults = false;
- NSView *view = reinterpret_cast<NSView *>(window->winId());
- info.limits.colorComponentValue.maxColorComponentValue = view.window.screen.maximumExtendedDynamicRangeColorComponentValue;
-#else
- // ### Fixme: Maybe retrieve the brightness from the screen and if we're not at full brightness we might be able to do more.
- // For now, assume 2, in line with iPhone 12 specs that claim 625 nits max brightness and 1200 nits max HDR brightness.
- info.isHardCodedDefaults = true;
- info.limits.colorComponentValue.maxColorComponentValue = 2;
+ if (m_window) {
+ // Must use m_window, not window, given this may be called before createOrResize().
+#if defined(Q_OS_MACOS)
+ NSView *view = reinterpret_cast<NSView *>(m_window->winId());
+ NSScreen *screen = view.window.screen;
+ info.limits.colorComponentValue.maxColorComponentValue = screen.maximumExtendedDynamicRangeColorComponentValue;
+ info.limits.colorComponentValue.maxPotentialColorComponentValue = screen.maximumPotentialExtendedDynamicRangeColorComponentValue;
+#elif defined(Q_OS_IOS)
+ if (@available(iOS 16.0, *)) {
+ UIView *view = reinterpret_cast<UIView *>(m_window->winId());
+ UIScreen *screen = view.window.windowScene.screen;
+ info.limits.colorComponentValue.maxColorComponentValue = view.window.windowScene.screen.currentEDRHeadroom;
+ info.limits.colorComponentValue.maxPotentialColorComponentValue = screen.potentialEDRHeadroom;
+ }
#endif
+ }
+
return info;
}
diff --git a/src/gui/rhi/qrhimetal_p.h b/src/gui/rhi/qrhimetal_p.h
index 016bf749e2..f539148b2c 100644
--- a/src/gui/rhi/qrhimetal_p.h
+++ b/src/gui/rhi/qrhimetal_p.h
@@ -1,8 +1,8 @@
-// Copyright (C) 2019 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QRHIMETAL_H
-#define QRHIMETAL_H
+#ifndef QRHIMETAL_P_H
+#define QRHIMETAL_P_H
//
// W A R N I N G
@@ -15,29 +15,494 @@
// We mean it.
//
-#include <private/qrhi_p.h>
-
-Q_FORWARD_DECLARE_OBJC_CLASS(MTLDevice);
-Q_FORWARD_DECLARE_OBJC_CLASS(MTLCommandQueue);
-Q_FORWARD_DECLARE_OBJC_CLASS(MTLCommandBuffer);
-Q_FORWARD_DECLARE_OBJC_CLASS(MTLRenderCommandEncoder);
+#include "qrhi_p.h"
+#include <QWindow>
QT_BEGIN_NAMESPACE
-struct Q_GUI_EXPORT QRhiMetalInitParams : public QRhiInitParams
+static const int QMTL_FRAMES_IN_FLIGHT = 2;
+
+// have to hide the ObjC stuff, this header cannot contain MTL* at all
+struct QMetalBufferData;
+
+struct QMetalBuffer : public QRhiBuffer
+{
+ QMetalBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
+ ~QMetalBuffer();
+ void destroy() override;
+ bool create() override;
+ QRhiBuffer::NativeBuffer nativeBuffer() override;
+ char *beginFullDynamicBufferUpdateForCurrentFrame() override;
+ void endFullDynamicBufferUpdateForCurrentFrame() override;
+
+ QMetalBufferData *d;
+ uint generation = 0;
+ int lastActiveFrameSlot = -1;
+ friend class QRhiMetal;
+ friend struct QMetalShaderResourceBindings;
+
+ static constexpr int WorkBufPoolUsage = 1 << 8;
+ static_assert(WorkBufPoolUsage > QRhiBuffer::StorageBuffer);
+};
+
+struct QMetalRenderBufferData;
+
+struct QMetalRenderBuffer : public QRhiRenderBuffer
+{
+ QMetalRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
+ int sampleCount, QRhiRenderBuffer::Flags flags,
+ QRhiTexture::Format backingFormatHint);
+ ~QMetalRenderBuffer();
+ void destroy() override;
+ bool create() override;
+ QRhiTexture::Format backingFormat() const override;
+
+ QMetalRenderBufferData *d;
+ int samples = 1;
+ uint generation = 0;
+ int lastActiveFrameSlot = -1;
+ friend class QRhiMetal;
+};
+
+struct QMetalTextureData;
+
+struct QMetalTexture : public QRhiTexture
+{
+ QMetalTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
+ int arraySize, int sampleCount, Flags flags);
+ ~QMetalTexture();
+ void destroy() override;
+ bool create() override;
+ bool createFrom(NativeTexture src) override;
+ NativeTexture nativeTexture() override;
+
+ bool prepareCreate(QSize *adjustedSize = nullptr);
+
+ QMetalTextureData *d;
+ int mipLevelCount = 0;
+ int samples = 1;
+ uint generation = 0;
+ int lastActiveFrameSlot = -1;
+ friend class QRhiMetal;
+ friend struct QMetalShaderResourceBindings;
+ friend struct QMetalTextureData;
+};
+
+struct QMetalSamplerData;
+
+struct QMetalSampler : public QRhiSampler
+{
+ QMetalSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
+ AddressMode u, AddressMode v, AddressMode w);
+ ~QMetalSampler();
+ void destroy() override;
+ bool create() override;
+
+ QMetalSamplerData *d;
+ uint generation = 0;
+ int lastActiveFrameSlot = -1;
+ friend class QRhiMetal;
+ friend struct QMetalShaderResourceBindings;
+};
+
+struct QMetalRenderPassDescriptor : public QRhiRenderPassDescriptor
{
+ QMetalRenderPassDescriptor(QRhiImplementation *rhi);
+ ~QMetalRenderPassDescriptor();
+ void destroy() override;
+ bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
+ QVector<quint32> serializedFormat() const override;
+
+ void updateSerializedFormat();
+
+ // there is no MTLRenderPassDescriptor here as one will be created for each pass in beginPass()
+
+ // but the things needed for the render pipeline descriptor have to be provided
+ static const int MAX_COLOR_ATTACHMENTS = 8;
+ int colorAttachmentCount = 0;
+ bool hasDepthStencil = false;
+ int colorFormat[MAX_COLOR_ATTACHMENTS];
+ int dsFormat;
+ QVector<quint32> serializedFormatData;
+};
+
+struct QMetalRenderTargetData;
+
+struct QMetalSwapChainRenderTarget : public QRhiSwapChainRenderTarget
+{
+ QMetalSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
+ ~QMetalSwapChainRenderTarget();
+ void destroy() override;
+
+ QSize pixelSize() const override;
+ float devicePixelRatio() const override;
+ int sampleCount() const override;
+
+ QMetalRenderTargetData *d;
+};
+
+struct QMetalTextureRenderTarget : public QRhiTextureRenderTarget
+{
+ QMetalTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags);
+ ~QMetalTextureRenderTarget();
+ void destroy() override;
+
+ QSize pixelSize() const override;
+ float devicePixelRatio() const override;
+ int sampleCount() const override;
+
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
+ bool create() override;
+
+ QMetalRenderTargetData *d;
+ friend class QRhiMetal;
};
-struct Q_GUI_EXPORT QRhiMetalNativeHandles : public QRhiNativeHandles
+struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings
{
- MTLDevice *dev = nullptr;
- MTLCommandQueue *cmdQueue = nullptr;
+ QMetalShaderResourceBindings(QRhiImplementation *rhi);
+ ~QMetalShaderResourceBindings();
+ void destroy() override;
+ bool create() override;
+ void updateResources(UpdateFlags flags) override;
+
+ QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
+ int maxBinding = -1;
+
+ struct BoundUniformBufferData {
+ quint64 id;
+ uint generation;
+ };
+ struct BoundSampledTextureData {
+ int count;
+ struct {
+ quint64 texId;
+ uint texGeneration;
+ quint64 samplerId;
+ uint samplerGeneration;
+ } d[QRhiShaderResourceBinding::Data::MAX_TEX_SAMPLER_ARRAY_SIZE];
+ };
+ struct BoundStorageImageData {
+ quint64 id;
+ uint generation;
+ };
+ struct BoundStorageBufferData {
+ quint64 id;
+ uint generation;
+ };
+ struct BoundResourceData {
+ union {
+ BoundUniformBufferData ubuf;
+ BoundSampledTextureData stex;
+ BoundStorageImageData simage;
+ BoundStorageBufferData sbuf;
+ };
+ };
+ QVarLengthArray<BoundResourceData, 8> boundResourceData;
+
+ uint generation = 0;
+ friend class QRhiMetal;
};
-struct Q_GUI_EXPORT QRhiMetalCommandBufferNativeHandles : public QRhiNativeHandles
+struct QMetalGraphicsPipelineData;
+struct QMetalCommandBuffer;
+
+struct QMetalGraphicsPipeline : public QRhiGraphicsPipeline
{
- MTLCommandBuffer *commandBuffer = nullptr;
- MTLRenderCommandEncoder *encoder = nullptr;
+ QMetalGraphicsPipeline(QRhiImplementation *rhi);
+ ~QMetalGraphicsPipeline();
+ void destroy() override;
+ bool create() override;
+
+ void makeActiveForCurrentRenderPassEncoder(QMetalCommandBuffer *cbD);
+ void setupAttachmentsInMetalRenderPassDescriptor(void *metalRpDesc, QMetalRenderPassDescriptor *rpD);
+ void setupMetalDepthStencilDescriptor(void *metalDsDesc);
+ void mapStates();
+ bool createVertexFragmentPipeline();
+ bool createTessellationPipelines(const QShader &tessVert, const QShader &tesc, const QShader &tese, const QShader &tessFrag);
+
+ QMetalGraphicsPipelineData *d;
+ uint generation = 0;
+ int lastActiveFrameSlot = -1;
+ friend class QRhiMetal;
+};
+
+struct QMetalComputePipelineData;
+
+struct QMetalComputePipeline : public QRhiComputePipeline
+{
+ QMetalComputePipeline(QRhiImplementation *rhi);
+ ~QMetalComputePipeline();
+ void destroy() override;
+ bool create() override;
+
+ QMetalComputePipelineData *d;
+ uint generation = 0;
+ int lastActiveFrameSlot = -1;
+ friend class QRhiMetal;
+};
+
+struct QMetalCommandBufferData;
+struct QMetalSwapChain;
+
+struct QMetalCommandBuffer : public QRhiCommandBuffer
+{
+ QMetalCommandBuffer(QRhiImplementation *rhi);
+ ~QMetalCommandBuffer();
+ void destroy() override;
+
+ QMetalCommandBufferData *d = nullptr;
+ QRhiMetalCommandBufferNativeHandles nativeHandlesStruct;
+
+ enum PassType {
+ NoPass,
+ RenderPass,
+ ComputePass
+ };
+
+ // per-pass (render or compute command encoder) persistent state
+ PassType recordingPass;
+ QRhiRenderTarget *currentTarget;
+
+ // per-pass (render or compute command encoder) volatile (cached) state
+ QMetalGraphicsPipeline *currentGraphicsPipeline;
+ QMetalComputePipeline *currentComputePipeline;
+ uint currentPipelineGeneration;
+ QMetalShaderResourceBindings *currentGraphicsSrb;
+ QMetalShaderResourceBindings *currentComputeSrb;
+ uint currentSrbGeneration;
+ int currentResSlot;
+ QMetalBuffer *currentIndexBuffer;
+ quint32 currentIndexOffset;
+ QRhiCommandBuffer::IndexFormat currentIndexFormat;
+ int currentCullMode;
+ int currentTriangleFillMode;
+ int currentFrontFaceWinding;
+ QPair<float, float> currentDepthBiasValues;
+
+ const QRhiNativeHandles *nativeHandles();
+ void resetState(double lastGpuTime = 0);
+ void resetPerPassState();
+ void resetPerPassCachedState();
+};
+
+struct QMetalSwapChainData;
+
+struct QMetalSwapChain : public QRhiSwapChain
+{
+ QMetalSwapChain(QRhiImplementation *rhi);
+ ~QMetalSwapChain();
+ void destroy() override;
+
+ QRhiCommandBuffer *currentFrameCommandBuffer() override;
+ QRhiRenderTarget *currentFrameRenderTarget() override;
+ QSize surfacePixelSize() override;
+ bool isFormatSupported(Format f) override;
+
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
+
+ bool createOrResize() override;
+
+ virtual QRhiSwapChainHdrInfo hdrInfo() override;
+
+ void chooseFormats();
+ void waitUntilCompleted(int slot);
+
+ QWindow *window = nullptr;
+ QSize pixelSize;
+ int currentFrameSlot = 0; // 0..QMTL_FRAMES_IN_FLIGHT-1
+ int frameCount = 0;
+ int samples = 1;
+ QMetalSwapChainRenderTarget rtWrapper;
+ QMetalCommandBuffer cbWrapper;
+ QMetalRenderBuffer *ds = nullptr;
+ QMetalSwapChainData *d = nullptr;
+};
+
+struct QRhiMetalData;
+
+class QRhiMetal : public QRhiImplementation
+{
+public:
+ QRhiMetal(QRhiMetalInitParams *params, QRhiMetalNativeHandles *importDevice = nullptr);
+ ~QRhiMetal();
+
+ static bool probe(QRhiMetalInitParams *params);
+ static QRhiSwapChainProxyData updateSwapChainProxyData(QWindow *window);
+
+ bool create(QRhi::Flags flags) override;
+ void destroy() override;
+
+ QRhiGraphicsPipeline *createGraphicsPipeline() override;
+ QRhiComputePipeline *createComputePipeline() override;
+ QRhiShaderResourceBindings *createShaderResourceBindings() override;
+ QRhiBuffer *createBuffer(QRhiBuffer::Type type,
+ QRhiBuffer::UsageFlags usage,
+ quint32 size) override;
+ QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
+ const QSize &pixelSize,
+ int sampleCount,
+ QRhiRenderBuffer::Flags flags,
+ QRhiTexture::Format backingFormatHint) override;
+ QRhiTexture *createTexture(QRhiTexture::Format format,
+ const QSize &pixelSize,
+ int depth,
+ int arraySize,
+ int sampleCount,
+ QRhiTexture::Flags flags) override;
+ QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
+ QRhiSampler::Filter minFilter,
+ QRhiSampler::Filter mipmapMode,
+ QRhiSampler:: AddressMode u,
+ QRhiSampler::AddressMode v,
+ QRhiSampler::AddressMode w) override;
+
+ QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
+ QRhiTextureRenderTarget::Flags flags) override;
+
+ QRhiSwapChain *createSwapChain() override;
+ QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
+ QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
+ QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
+ QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
+ QRhi::FrameOpResult finish() override;
+
+ void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+
+ void beginPass(QRhiCommandBuffer *cb,
+ QRhiRenderTarget *rt,
+ const QColor &colorClearValue,
+ const QRhiDepthStencilClearValue &depthStencilClearValue,
+ QRhiResourceUpdateBatch *resourceUpdates,
+ QRhiCommandBuffer::BeginPassFlags flags) override;
+ void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+
+ void setGraphicsPipeline(QRhiCommandBuffer *cb,
+ QRhiGraphicsPipeline *ps) override;
+
+ void setShaderResources(QRhiCommandBuffer *cb,
+ QRhiShaderResourceBindings *srb,
+ int dynamicOffsetCount,
+ const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
+
+ void setVertexInput(QRhiCommandBuffer *cb,
+ int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
+ QRhiBuffer *indexBuf, quint32 indexOffset,
+ QRhiCommandBuffer::IndexFormat indexFormat) override;
+
+ void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
+ void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
+ void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
+ void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
+
+ void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
+ quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
+
+ void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
+ quint32 instanceCount, quint32 firstIndex,
+ qint32 vertexOffset, quint32 firstInstance) override;
+
+ void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
+ void debugMarkEnd(QRhiCommandBuffer *cb) override;
+ void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
+
+ void beginComputePass(QRhiCommandBuffer *cb,
+ QRhiResourceUpdateBatch *resourceUpdates,
+ QRhiCommandBuffer::BeginPassFlags flags) override;
+ void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+ void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
+ void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
+
+ const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
+ void beginExternal(QRhiCommandBuffer *cb) override;
+ void endExternal(QRhiCommandBuffer *cb) override;
+ double lastCompletedGpuTime(QRhiCommandBuffer *cb) override;
+
+ QList<int> supportedSampleCounts() const override;
+ int ubufAlignment() const override;
+ bool isYUpInFramebuffer() const override;
+ bool isYUpInNDC() const override;
+ bool isClipDepthZeroToOne() const override;
+ QMatrix4x4 clipSpaceCorrMatrix() const override;
+ bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
+ bool isFeatureSupported(QRhi::Feature feature) const override;
+ int resourceLimit(QRhi::ResourceLimit limit) const override;
+ const QRhiNativeHandles *nativeHandles() override;
+ QRhiDriverInfo driverInfo() const override;
+ QRhiStats statistics() override;
+ bool makeThreadLocalNativeContextCurrent() override;
+ void releaseCachedResources() override;
+ bool isDeviceLost() const override;
+
+ QByteArray pipelineCacheData() override;
+ void setPipelineCacheData(const QByteArray &data) override;
+
+ void executeDeferredReleases(bool forced = false);
+ void finishActiveReadbacks(bool forced = false);
+ qsizetype subresUploadByteSize(const QRhiTextureSubresourceUploadDescription &subresDesc) const;
+ void enqueueSubresUpload(QMetalTexture *texD, void *mp, void *blitEncPtr,
+ int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc,
+ qsizetype *curOfs);
+ void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
+ void executeBufferHostWritesForSlot(QMetalBuffer *bufD, int slot);
+ void executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD);
+ static const int SUPPORTED_STAGES = 5;
+ void enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD,
+ QMetalCommandBuffer *cbD,
+ int dynamicOffsetCount,
+ const QRhiCommandBuffer::DynamicOffset *dynamicOffsets,
+ bool offsetOnlyChange,
+ const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[SUPPORTED_STAGES]);
+ struct TessDrawArgs {
+ QMetalCommandBuffer *cbD;
+ enum {
+ NonIndexed,
+ U16Indexed,
+ U32Indexed
+ } type;
+ struct NonIndexedArgs {
+ quint32 vertexCount;
+ quint32 instanceCount;
+ quint32 firstVertex;
+ quint32 firstInstance;
+ };
+ struct IndexedArgs {
+ quint32 indexCount;
+ quint32 instanceCount;
+ quint32 firstIndex;
+ qint32 vertexOffset;
+ quint32 firstInstance;
+ void *indexBuffer;
+ };
+ union {
+ NonIndexedArgs draw;
+ IndexedArgs drawIndexed;
+ };
+ };
+ void tessellatedDraw(const TessDrawArgs &args);
+ void adjustForMultiViewDraw(quint32 *instanceCount, QRhiCommandBuffer *cb);
+
+ QRhi::Flags rhiFlags;
+ bool importedDevice = false;
+ bool importedCmdQueue = false;
+ QMetalSwapChain *currentSwapChain = nullptr;
+ QSet<QMetalSwapChain *> swapchains;
+ QRhiMetalNativeHandles nativeHandlesStruct;
+ QRhiDriverInfo driverInfoStruct;
+ quint32 osMajor = 0;
+ quint32 osMinor = 0;
+
+ struct {
+ int maxTextureSize = 4096;
+ bool baseVertexAndInstance = true;
+ QVector<int> supportedSampleCounts;
+ bool isAppleGPU = false;
+ int maxThreadGroupSize = 512;
+ bool multiView = false;
+ } caps;
+
+ QRhiMetalData *d = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h
deleted file mode 100644
index c76a29b0a8..0000000000
--- a/src/gui/rhi/qrhimetal_p_p.h
+++ /dev/null
@@ -1,509 +0,0 @@
-// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QRHIMETAL_P_H
-#define QRHIMETAL_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 "qrhimetal_p.h"
-#include "qrhi_p_p.h"
-#include <QWindow>
-
-QT_BEGIN_NAMESPACE
-
-static const int QMTL_FRAMES_IN_FLIGHT = 2;
-
-// have to hide the ObjC stuff, this header cannot contain MTL* at all
-struct QMetalBufferData;
-
-struct QMetalBuffer : public QRhiBuffer
-{
- QMetalBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
- ~QMetalBuffer();
- void destroy() override;
- bool create() override;
- QRhiBuffer::NativeBuffer nativeBuffer() override;
- char *beginFullDynamicBufferUpdateForCurrentFrame() override;
- void endFullDynamicBufferUpdateForCurrentFrame() override;
-
- QMetalBufferData *d;
- uint generation = 0;
- int lastActiveFrameSlot = -1;
- friend class QRhiMetal;
- friend struct QMetalShaderResourceBindings;
-
- static constexpr int WorkBufPoolUsage = 1 << 8;
- static_assert(WorkBufPoolUsage > QRhiBuffer::StorageBuffer);
-};
-
-struct QMetalRenderBufferData;
-
-struct QMetalRenderBuffer : public QRhiRenderBuffer
-{
- QMetalRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
- int sampleCount, QRhiRenderBuffer::Flags flags,
- QRhiTexture::Format backingFormatHint);
- ~QMetalRenderBuffer();
- void destroy() override;
- bool create() override;
- QRhiTexture::Format backingFormat() const override;
-
- QMetalRenderBufferData *d;
- int samples = 1;
- uint generation = 0;
- int lastActiveFrameSlot = -1;
- friend class QRhiMetal;
-};
-
-struct QMetalTextureData;
-
-struct QMetalTexture : public QRhiTexture
-{
- QMetalTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
- int arraySize, int sampleCount, Flags flags);
- ~QMetalTexture();
- void destroy() override;
- bool create() override;
- bool createFrom(NativeTexture src) override;
- NativeTexture nativeTexture() override;
-
- bool prepareCreate(QSize *adjustedSize = nullptr);
-
- QMetalTextureData *d;
- int mipLevelCount = 0;
- int samples = 1;
- uint generation = 0;
- int lastActiveFrameSlot = -1;
- friend class QRhiMetal;
- friend struct QMetalShaderResourceBindings;
- friend struct QMetalTextureData;
-};
-
-struct QMetalSamplerData;
-
-struct QMetalSampler : public QRhiSampler
-{
- QMetalSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
- AddressMode u, AddressMode v, AddressMode w);
- ~QMetalSampler();
- void destroy() override;
- bool create() override;
-
- QMetalSamplerData *d;
- uint generation = 0;
- int lastActiveFrameSlot = -1;
- friend class QRhiMetal;
- friend struct QMetalShaderResourceBindings;
-};
-
-struct QMetalRenderPassDescriptor : public QRhiRenderPassDescriptor
-{
- QMetalRenderPassDescriptor(QRhiImplementation *rhi);
- ~QMetalRenderPassDescriptor();
- void destroy() override;
- bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
- QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
- QVector<quint32> serializedFormat() const override;
-
- void updateSerializedFormat();
-
- // there is no MTLRenderPassDescriptor here as one will be created for each pass in beginPass()
-
- // but the things needed for the render pipeline descriptor have to be provided
- static const int MAX_COLOR_ATTACHMENTS = 8;
- int colorAttachmentCount = 0;
- bool hasDepthStencil = false;
- int colorFormat[MAX_COLOR_ATTACHMENTS];
- int dsFormat;
- QVector<quint32> serializedFormatData;
-};
-
-struct QMetalRenderTargetData;
-
-struct QMetalSwapChainRenderTarget : public QRhiSwapChainRenderTarget
-{
- QMetalSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
- ~QMetalSwapChainRenderTarget();
- void destroy() override;
-
- QSize pixelSize() const override;
- float devicePixelRatio() const override;
- int sampleCount() const override;
-
- QMetalRenderTargetData *d;
-};
-
-struct QMetalTextureRenderTarget : public QRhiTextureRenderTarget
-{
- QMetalTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags);
- ~QMetalTextureRenderTarget();
- void destroy() override;
-
- QSize pixelSize() const override;
- float devicePixelRatio() const override;
- int sampleCount() const override;
-
- QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
- bool create() override;
-
- QMetalRenderTargetData *d;
- friend class QRhiMetal;
-};
-
-struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings
-{
- QMetalShaderResourceBindings(QRhiImplementation *rhi);
- ~QMetalShaderResourceBindings();
- void destroy() override;
- bool create() override;
- void updateResources(UpdateFlags flags) override;
-
- QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
- int maxBinding = -1;
-
- struct BoundUniformBufferData {
- quint64 id;
- uint generation;
- };
- struct BoundSampledTextureData {
- int count;
- struct {
- quint64 texId;
- uint texGeneration;
- quint64 samplerId;
- uint samplerGeneration;
- } d[QRhiShaderResourceBinding::Data::MAX_TEX_SAMPLER_ARRAY_SIZE];
- };
- struct BoundStorageImageData {
- quint64 id;
- uint generation;
- };
- struct BoundStorageBufferData {
- quint64 id;
- uint generation;
- };
- struct BoundResourceData {
- union {
- BoundUniformBufferData ubuf;
- BoundSampledTextureData stex;
- BoundStorageImageData simage;
- BoundStorageBufferData sbuf;
- };
- };
- QVarLengthArray<BoundResourceData, 8> boundResourceData;
-
- uint generation = 0;
- friend class QRhiMetal;
-};
-
-struct QMetalGraphicsPipelineData;
-struct QMetalCommandBuffer;
-
-struct QMetalGraphicsPipeline : public QRhiGraphicsPipeline
-{
- QMetalGraphicsPipeline(QRhiImplementation *rhi);
- ~QMetalGraphicsPipeline();
- void destroy() override;
- bool create() override;
-
- void makeActiveForCurrentRenderPassEncoder(QMetalCommandBuffer *cbD);
- void setupAttachmentsInMetalRenderPassDescriptor(void *metalRpDesc, QMetalRenderPassDescriptor *rpD);
- void setupMetalDepthStencilDescriptor(void *metalDsDesc);
- void mapStates();
- bool createVertexFragmentPipeline();
- bool createTessellationPipelines(const QShader &tessVert, const QShader &tesc, const QShader &tese, const QShader &tessFrag);
-
- QMetalGraphicsPipelineData *d;
- uint generation = 0;
- int lastActiveFrameSlot = -1;
- friend class QRhiMetal;
-};
-
-struct QMetalComputePipelineData;
-
-struct QMetalComputePipeline : public QRhiComputePipeline
-{
- QMetalComputePipeline(QRhiImplementation *rhi);
- ~QMetalComputePipeline();
- void destroy() override;
- bool create() override;
-
- QMetalComputePipelineData *d;
- uint generation = 0;
- int lastActiveFrameSlot = -1;
- friend class QRhiMetal;
-};
-
-struct QMetalCommandBufferData;
-struct QMetalSwapChain;
-
-struct QMetalCommandBuffer : public QRhiCommandBuffer
-{
- QMetalCommandBuffer(QRhiImplementation *rhi);
- ~QMetalCommandBuffer();
- void destroy() override;
-
- QMetalCommandBufferData *d = nullptr;
- QRhiMetalCommandBufferNativeHandles nativeHandlesStruct;
-
- enum PassType {
- NoPass,
- RenderPass,
- ComputePass
- };
-
- // per-pass (render or compute command encoder) persistent state
- PassType recordingPass;
- QRhiRenderTarget *currentTarget;
-
- // per-pass (render or compute command encoder) volatile (cached) state
- QMetalGraphicsPipeline *currentGraphicsPipeline;
- QMetalComputePipeline *currentComputePipeline;
- uint currentPipelineGeneration;
- QMetalShaderResourceBindings *currentGraphicsSrb;
- QMetalShaderResourceBindings *currentComputeSrb;
- uint currentSrbGeneration;
- int currentResSlot;
- QMetalBuffer *currentIndexBuffer;
- quint32 currentIndexOffset;
- QRhiCommandBuffer::IndexFormat currentIndexFormat;
- int currentCullMode;
- int currentTriangleFillMode;
- int currentFrontFaceWinding;
- QPair<float, float> currentDepthBiasValues;
-
- const QRhiNativeHandles *nativeHandles();
- void resetState();
- void resetPerPassState();
- void resetPerPassCachedState();
-};
-
-struct QMetalSwapChainData;
-
-struct QMetalSwapChain : public QRhiSwapChain
-{
- QMetalSwapChain(QRhiImplementation *rhi);
- ~QMetalSwapChain();
- void destroy() override;
-
- QRhiCommandBuffer *currentFrameCommandBuffer() override;
- QRhiRenderTarget *currentFrameRenderTarget() override;
- QSize surfacePixelSize() override;
- bool isFormatSupported(Format f) override;
-
- QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
-
- bool createOrResize() override;
-
- virtual QRhiSwapChainHdrInfo hdrInfo() override;
-
- void chooseFormats();
- void waitUntilCompleted(int slot);
-
- QWindow *window = nullptr;
- QSize pixelSize;
- int currentFrameSlot = 0; // 0..QMTL_FRAMES_IN_FLIGHT-1
- int frameCount = 0;
- int samples = 1;
- QMetalSwapChainRenderTarget rtWrapper;
- QMetalCommandBuffer cbWrapper;
- QMetalRenderBuffer *ds = nullptr;
- QMetalSwapChainData *d = nullptr;
-};
-
-struct QRhiMetalData;
-
-class QRhiMetal : public QRhiImplementation
-{
-public:
- QRhiMetal(QRhiMetalInitParams *params, QRhiMetalNativeHandles *importDevice = nullptr);
- ~QRhiMetal();
-
- static bool probe(QRhiMetalInitParams *params);
- static QRhiSwapChainProxyData updateSwapChainProxyData(QWindow *window);
-
- bool create(QRhi::Flags flags) override;
- void destroy() override;
-
- QRhiGraphicsPipeline *createGraphicsPipeline() override;
- QRhiComputePipeline *createComputePipeline() override;
- QRhiShaderResourceBindings *createShaderResourceBindings() override;
- QRhiBuffer *createBuffer(QRhiBuffer::Type type,
- QRhiBuffer::UsageFlags usage,
- quint32 size) override;
- QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
- const QSize &pixelSize,
- int sampleCount,
- QRhiRenderBuffer::Flags flags,
- QRhiTexture::Format backingFormatHint) override;
- QRhiTexture *createTexture(QRhiTexture::Format format,
- const QSize &pixelSize,
- int depth,
- int arraySize,
- int sampleCount,
- QRhiTexture::Flags flags) override;
- QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
- QRhiSampler::Filter minFilter,
- QRhiSampler::Filter mipmapMode,
- QRhiSampler:: AddressMode u,
- QRhiSampler::AddressMode v,
- QRhiSampler::AddressMode w) override;
-
- QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
- QRhiTextureRenderTarget::Flags flags) override;
-
- QRhiSwapChain *createSwapChain() override;
- QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
- QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
- QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
- QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
- QRhi::FrameOpResult finish() override;
-
- void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
-
- void beginPass(QRhiCommandBuffer *cb,
- QRhiRenderTarget *rt,
- const QColor &colorClearValue,
- const QRhiDepthStencilClearValue &depthStencilClearValue,
- QRhiResourceUpdateBatch *resourceUpdates,
- QRhiCommandBuffer::BeginPassFlags flags) override;
- void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
-
- void setGraphicsPipeline(QRhiCommandBuffer *cb,
- QRhiGraphicsPipeline *ps) override;
-
- void setShaderResources(QRhiCommandBuffer *cb,
- QRhiShaderResourceBindings *srb,
- int dynamicOffsetCount,
- const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
-
- void setVertexInput(QRhiCommandBuffer *cb,
- int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
- QRhiBuffer *indexBuf, quint32 indexOffset,
- QRhiCommandBuffer::IndexFormat indexFormat) override;
-
- void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
- void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
- void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
- void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
-
- void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
- quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
-
- void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
- quint32 instanceCount, quint32 firstIndex,
- qint32 vertexOffset, quint32 firstInstance) override;
-
- void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
- void debugMarkEnd(QRhiCommandBuffer *cb) override;
- void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
-
- void beginComputePass(QRhiCommandBuffer *cb,
- QRhiResourceUpdateBatch *resourceUpdates,
- QRhiCommandBuffer::BeginPassFlags flags) override;
- void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
- void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
- void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
-
- const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
- void beginExternal(QRhiCommandBuffer *cb) override;
- void endExternal(QRhiCommandBuffer *cb) override;
-
- QList<int> supportedSampleCounts() const override;
- int ubufAlignment() const override;
- bool isYUpInFramebuffer() const override;
- bool isYUpInNDC() const override;
- bool isClipDepthZeroToOne() const override;
- QMatrix4x4 clipSpaceCorrMatrix() const override;
- bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
- bool isFeatureSupported(QRhi::Feature feature) const override;
- int resourceLimit(QRhi::ResourceLimit limit) const override;
- const QRhiNativeHandles *nativeHandles() override;
- QRhiDriverInfo driverInfo() const override;
- QRhiStats statistics() override;
- bool makeThreadLocalNativeContextCurrent() override;
- void releaseCachedResources() override;
- bool isDeviceLost() const override;
-
- QByteArray pipelineCacheData() override;
- void setPipelineCacheData(const QByteArray &data) override;
-
- void executeDeferredReleases(bool forced = false);
- void finishActiveReadbacks(bool forced = false);
- qsizetype subresUploadByteSize(const QRhiTextureSubresourceUploadDescription &subresDesc) const;
- void enqueueSubresUpload(QMetalTexture *texD, void *mp, void *blitEncPtr,
- int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc,
- qsizetype *curOfs);
- void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
- void executeBufferHostWritesForSlot(QMetalBuffer *bufD, int slot);
- void executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD);
- static const int SUPPORTED_STAGES = 5;
- void enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD,
- QMetalCommandBuffer *cbD,
- int dynamicOffsetCount,
- const QRhiCommandBuffer::DynamicOffset *dynamicOffsets,
- bool offsetOnlyChange,
- const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[SUPPORTED_STAGES]);
- int effectiveSampleCount(int sampleCount) const;
- struct TessDrawArgs {
- QMetalCommandBuffer *cbD;
- enum {
- NonIndexed,
- U16Indexed,
- U32Indexed
- } type;
- struct NonIndexedArgs {
- quint32 vertexCount;
- quint32 instanceCount;
- quint32 firstVertex;
- quint32 firstInstance;
- };
- struct IndexedArgs {
- quint32 indexCount;
- quint32 instanceCount;
- quint32 firstIndex;
- qint32 vertexOffset;
- quint32 firstInstance;
- void *indexBuffer;
- };
- union {
- NonIndexedArgs draw;
- IndexedArgs drawIndexed;
- };
- };
- void tessellatedDraw(const TessDrawArgs &args);
-
- QRhi::Flags rhiFlags;
- bool importedDevice = false;
- bool importedCmdQueue = false;
- QMetalSwapChain *currentSwapChain = nullptr;
- QSet<QMetalSwapChain *> swapchains;
- QRhiMetalNativeHandles nativeHandlesStruct;
- QRhiDriverInfo driverInfoStruct;
- quint32 osMajor = 0;
- quint32 osMinor = 0;
-
- struct {
- int maxTextureSize = 4096;
- bool baseVertexAndInstance = true;
- QVector<int> supportedSampleCounts;
- bool isAppleGPU = false;
- int maxThreadGroupSize = 512;
- } caps;
-
- QRhiMetalData *d = nullptr;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/gui/rhi/qrhinull.cpp b/src/gui/rhi/qrhinull.cpp
index ec1b5aa64a..566b922c1b 100644
--- a/src/gui/rhi/qrhinull.cpp
+++ b/src/gui/rhi/qrhinull.cpp
@@ -1,7 +1,7 @@
-// Copyright (C) 2019 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qrhinull_p_p.h"
+#include "qrhinull_p.h"
#include <qmath.h>
#include <QPainter>
@@ -9,10 +9,13 @@ QT_BEGIN_NAMESPACE
/*!
\class QRhiNullInitParams
- \internal
\inmodule QtGui
+ \since 6.6
\brief Null backend specific initialization parameters.
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
A Null QRhi needs no special parameters for initialization.
\badcode
@@ -28,9 +31,12 @@ QT_BEGIN_NAMESPACE
/*!
\class QRhiNullNativeHandles
- \internal
\inmodule QtGui
+ \since 6.6
\brief Empty.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
QRhiNull::QRhiNull(QRhiNullInitParams *params)
@@ -344,6 +350,12 @@ void QRhiNull::endExternal(QRhiCommandBuffer *cb)
Q_UNUSED(cb);
}
+double QRhiNull::lastCompletedGpuTime(QRhiCommandBuffer *cb)
+{
+ Q_UNUSED(cb);
+ return 0;
+}
+
QRhi::FrameOpResult QRhiNull::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags)
{
Q_UNUSED(flags);
@@ -456,7 +468,7 @@ void QRhiNull::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *re
QNullBuffer *bufD = QRHI_RES(QNullBuffer, u.buf);
memcpy(bufD->data + u.offset, u.data.constData(), size_t(u.data.size()));
} else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
- QRhiBufferReadbackResult *result = u.result;
+ QRhiReadbackResult *result = u.result;
result->data.resize(u.readSize);
QNullBuffer *bufD = QRHI_RES(QNullBuffer, u.buf);
memcpy(result->data.data(), bufD->data + u.offset, size_t(u.readSize));
@@ -664,10 +676,11 @@ bool QNullTexture::create()
const bool is1D = m_flags.testFlags(OneDimensional);
QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
: (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
- m_depth = qMax(1, m_depth);
const int mipLevelCount = hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1;
- m_arraySize = qMax(0, m_arraySize);
- const int layerCount = is3D ? m_depth : (isCube ? 6 : (isArray ? m_arraySize : 1));
+ const int layerCount = is3D ? qMax(1, m_depth)
+ : (isCube ? 6
+ : (isArray ? qMax(0, m_arraySize)
+ : 1));
if (m_format == RGBA8) {
image.resize(layerCount);
@@ -716,10 +729,15 @@ QNullSampler::~QNullSampler()
void QNullSampler::destroy()
{
+ QRHI_RES_RHI(QRhiNull);
+ if (rhiD)
+ rhiD->unregisterResource(this);
}
bool QNullSampler::create()
{
+ QRHI_RES_RHI(QRhiNull);
+ rhiD->registerResource(this);
return true;
}
@@ -735,6 +753,9 @@ QNullRenderPassDescriptor::~QNullRenderPassDescriptor()
void QNullRenderPassDescriptor::destroy()
{
+ QRHI_RES_RHI(QRhiNull);
+ if (rhiD)
+ rhiD->unregisterResource(this);
}
bool QNullRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other) const
@@ -745,7 +766,10 @@ bool QNullRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *oth
QRhiRenderPassDescriptor *QNullRenderPassDescriptor::newCompatibleRenderPassDescriptor() const
{
- return new QNullRenderPassDescriptor(m_rhi);
+ QNullRenderPassDescriptor *rpD = new QNullRenderPassDescriptor(m_rhi);
+ QRHI_RES_RHI(QRhiNull);
+ rhiD->registerResource(rpD, false);
+ return rpD;
}
QVector<quint32> QNullRenderPassDescriptor::serializedFormat() const
@@ -798,11 +822,17 @@ QNullTextureRenderTarget::~QNullTextureRenderTarget()
void QNullTextureRenderTarget::destroy()
{
+ QRHI_RES_RHI(QRhiNull);
+ if (rhiD)
+ rhiD->unregisterResource(this);
}
QRhiRenderPassDescriptor *QNullTextureRenderTarget::newCompatibleRenderPassDescriptor()
{
- return new QNullRenderPassDescriptor(m_rhi);
+ QNullRenderPassDescriptor *rpD = new QNullRenderPassDescriptor(m_rhi);
+ QRHI_RES_RHI(QRhiNull);
+ rhiD->registerResource(rpD, false);
+ return rpD;
}
bool QNullTextureRenderTarget::create()
@@ -820,6 +850,7 @@ bool QNullTextureRenderTarget::create()
d.pixelSize = m_desc.depthTexture()->pixelSize();
}
QRhiRenderTargetAttachmentTracker::updateResIdList<QNullTexture, QNullRenderBuffer>(m_desc, &d.currentResIdList);
+ rhiD->registerResource(this);
return true;
}
@@ -853,6 +884,9 @@ QNullShaderResourceBindings::~QNullShaderResourceBindings()
void QNullShaderResourceBindings::destroy()
{
+ QRHI_RES_RHI(QRhiNull);
+ if (rhiD)
+ rhiD->unregisterResource(this);
}
bool QNullShaderResourceBindings::create()
@@ -863,6 +897,7 @@ bool QNullShaderResourceBindings::create()
rhiD->updateLayoutDesc(this);
+ rhiD->registerResource(this, false);
return true;
}
@@ -883,6 +918,9 @@ QNullGraphicsPipeline::~QNullGraphicsPipeline()
void QNullGraphicsPipeline::destroy()
{
+ QRHI_RES_RHI(QRhiNull);
+ if (rhiD)
+ rhiD->unregisterResource(this);
}
bool QNullGraphicsPipeline::create()
@@ -891,6 +929,7 @@ bool QNullGraphicsPipeline::create()
if (!rhiD->sanityCheckGraphicsPipeline(this))
return false;
+ rhiD->registerResource(this);
return true;
}
@@ -906,10 +945,15 @@ QNullComputePipeline::~QNullComputePipeline()
void QNullComputePipeline::destroy()
{
+ QRHI_RES_RHI(QRhiNull);
+ if (rhiD)
+ rhiD->unregisterResource(this);
}
bool QNullComputePipeline::create()
{
+ QRHI_RES_RHI(QRhiNull);
+ rhiD->registerResource(this);
return true;
}
@@ -969,7 +1013,10 @@ bool QNullSwapChain::isFormatSupported(Format f)
QRhiRenderPassDescriptor *QNullSwapChain::newCompatibleRenderPassDescriptor()
{
- return new QNullRenderPassDescriptor(m_rhi);
+ QNullRenderPassDescriptor *rpD = new QNullRenderPassDescriptor(m_rhi);
+ QRHI_RES_RHI(QRhiNull);
+ rhiD->registerResource(rpD, false);
+ return rpD;
}
bool QNullSwapChain::createOrResize()
diff --git a/src/gui/rhi/qrhinull_p.h b/src/gui/rhi/qrhinull_p.h
index 061b6eba4a..fc266b4f38 100644
--- a/src/gui/rhi/qrhinull_p.h
+++ b/src/gui/rhi/qrhinull_p.h
@@ -1,8 +1,8 @@
-// Copyright (C) 2019 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QRHINULL_H
-#define QRHINULL_H
+#ifndef QRHINULL_P_H
+#define QRHINULL_P_H
//
// W A R N I N G
@@ -15,16 +15,279 @@
// We mean it.
//
-#include <private/qrhi_p.h>
+#include "qrhi_p.h"
QT_BEGIN_NAMESPACE
-struct Q_GUI_EXPORT QRhiNullInitParams : public QRhiInitParams
+struct QNullBuffer : public QRhiBuffer
{
+ QNullBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
+ ~QNullBuffer();
+ void destroy() override;
+ bool create() override;
+ char *beginFullDynamicBufferUpdateForCurrentFrame() override;
+
+ char *data = nullptr;
+};
+
+struct QNullRenderBuffer : public QRhiRenderBuffer
+{
+ QNullRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
+ int sampleCount, QRhiRenderBuffer::Flags flags,
+ QRhiTexture::Format backingFormatHint);
+ ~QNullRenderBuffer();
+ void destroy() override;
+ bool create() override;
+ QRhiTexture::Format backingFormat() const override;
+
+ bool valid = false;
+ uint generation = 0;
+};
+
+struct QNullTexture : public QRhiTexture
+{
+ QNullTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
+ int arraySize, int sampleCount, Flags flags);
+ ~QNullTexture();
+ void destroy() override;
+ bool create() override;
+ bool createFrom(NativeTexture src) override;
+
+ bool valid = false;
+ QVarLengthArray<std::array<QImage, QRhi::MAX_MIP_LEVELS>, 6> image;
+ uint generation = 0;
+};
+
+struct QNullSampler : public QRhiSampler
+{
+ QNullSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
+ AddressMode u, AddressMode v, AddressMode w);
+ ~QNullSampler();
+ void destroy() override;
+ bool create() override;
+};
+
+struct QNullRenderPassDescriptor : public QRhiRenderPassDescriptor
+{
+ QNullRenderPassDescriptor(QRhiImplementation *rhi);
+ ~QNullRenderPassDescriptor();
+ void destroy() override;
+ bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
+ QVector<quint32> serializedFormat() const override;
+};
+
+struct QNullRenderTargetData
+{
+ QNullRenderTargetData(QRhiImplementation *) { }
+
+ QNullRenderPassDescriptor *rp = nullptr;
+ QSize pixelSize;
+ float dpr = 1;
+ QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList;
+};
+
+struct QNullSwapChainRenderTarget : public QRhiSwapChainRenderTarget
+{
+ QNullSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
+ ~QNullSwapChainRenderTarget();
+ void destroy() override;
+
+ QSize pixelSize() const override;
+ float devicePixelRatio() const override;
+ int sampleCount() const override;
+
+ QNullRenderTargetData d;
+};
+
+struct QNullTextureRenderTarget : public QRhiTextureRenderTarget
+{
+ QNullTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags);
+ ~QNullTextureRenderTarget();
+ void destroy() override;
+
+ QSize pixelSize() const override;
+ float devicePixelRatio() const override;
+ int sampleCount() const override;
+
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
+ bool create() override;
+
+ QNullRenderTargetData d;
+};
+
+struct QNullShaderResourceBindings : public QRhiShaderResourceBindings
+{
+ QNullShaderResourceBindings(QRhiImplementation *rhi);
+ ~QNullShaderResourceBindings();
+ void destroy() override;
+ bool create() override;
+ void updateResources(UpdateFlags flags) override;
+};
+
+struct QNullGraphicsPipeline : public QRhiGraphicsPipeline
+{
+ QNullGraphicsPipeline(QRhiImplementation *rhi);
+ ~QNullGraphicsPipeline();
+ void destroy() override;
+ bool create() override;
+};
+
+struct QNullComputePipeline : public QRhiComputePipeline
+{
+ QNullComputePipeline(QRhiImplementation *rhi);
+ ~QNullComputePipeline();
+ void destroy() override;
+ bool create() override;
};
-struct Q_GUI_EXPORT QRhiNullNativeHandles : public QRhiNativeHandles
+struct QNullCommandBuffer : public QRhiCommandBuffer
{
+ QNullCommandBuffer(QRhiImplementation *rhi);
+ ~QNullCommandBuffer();
+ void destroy() override;
+};
+
+struct QNullSwapChain : public QRhiSwapChain
+{
+ QNullSwapChain(QRhiImplementation *rhi);
+ ~QNullSwapChain();
+ void destroy() override;
+
+ QRhiCommandBuffer *currentFrameCommandBuffer() override;
+ QRhiRenderTarget *currentFrameRenderTarget() override;
+
+ QSize surfacePixelSize() override;
+ bool isFormatSupported(Format f) override;
+
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
+ bool createOrResize() override;
+
+ QWindow *window = nullptr;
+ QNullSwapChainRenderTarget rt;
+ QNullCommandBuffer cb;
+ int frameCount = 0;
+};
+
+class QRhiNull : public QRhiImplementation
+{
+public:
+ QRhiNull(QRhiNullInitParams *params);
+
+ bool create(QRhi::Flags flags) override;
+ void destroy() override;
+
+ QRhiGraphicsPipeline *createGraphicsPipeline() override;
+ QRhiComputePipeline *createComputePipeline() override;
+ QRhiShaderResourceBindings *createShaderResourceBindings() override;
+ QRhiBuffer *createBuffer(QRhiBuffer::Type type,
+ QRhiBuffer::UsageFlags usage,
+ quint32 size) override;
+ QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
+ const QSize &pixelSize,
+ int sampleCount,
+ QRhiRenderBuffer::Flags flags,
+ QRhiTexture::Format backingFormatHint) override;
+ QRhiTexture *createTexture(QRhiTexture::Format format,
+ const QSize &pixelSize,
+ int depth,
+ int arraySize,
+ int sampleCount,
+ QRhiTexture::Flags flags) override;
+ QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
+ QRhiSampler::Filter minFilter,
+ QRhiSampler::Filter mipmapMode,
+ QRhiSampler:: AddressMode u,
+ QRhiSampler::AddressMode v,
+ QRhiSampler::AddressMode w) override;
+
+ QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
+ QRhiTextureRenderTarget::Flags flags) override;
+
+ QRhiSwapChain *createSwapChain() override;
+ QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
+ QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
+ QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
+ QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
+ QRhi::FrameOpResult finish() override;
+
+ void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+
+ void beginPass(QRhiCommandBuffer *cb,
+ QRhiRenderTarget *rt,
+ const QColor &colorClearValue,
+ const QRhiDepthStencilClearValue &depthStencilClearValue,
+ QRhiResourceUpdateBatch *resourceUpdates,
+ QRhiCommandBuffer::BeginPassFlags flags) override;
+ void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+
+ void setGraphicsPipeline(QRhiCommandBuffer *cb,
+ QRhiGraphicsPipeline *ps) override;
+
+ void setShaderResources(QRhiCommandBuffer *cb,
+ QRhiShaderResourceBindings *srb,
+ int dynamicOffsetCount,
+ const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
+
+ void setVertexInput(QRhiCommandBuffer *cb,
+ int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
+ QRhiBuffer *indexBuf, quint32 indexOffset,
+ QRhiCommandBuffer::IndexFormat indexFormat) override;
+
+ void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
+ void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
+ void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
+ void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
+
+ void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
+ quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
+
+ void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
+ quint32 instanceCount, quint32 firstIndex,
+ qint32 vertexOffset, quint32 firstInstance) override;
+
+ void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
+ void debugMarkEnd(QRhiCommandBuffer *cb) override;
+ void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
+
+ void beginComputePass(QRhiCommandBuffer *cb,
+ QRhiResourceUpdateBatch *resourceUpdates,
+ QRhiCommandBuffer::BeginPassFlags flags) override;
+ void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+ void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
+ void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
+
+ const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
+ void beginExternal(QRhiCommandBuffer *cb) override;
+ void endExternal(QRhiCommandBuffer *cb) override;
+ double lastCompletedGpuTime(QRhiCommandBuffer *cb) override;
+
+ QList<int> supportedSampleCounts() const override;
+ int ubufAlignment() const override;
+ bool isYUpInFramebuffer() const override;
+ bool isYUpInNDC() const override;
+ bool isClipDepthZeroToOne() const override;
+ QMatrix4x4 clipSpaceCorrMatrix() const override;
+ bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
+ bool isFeatureSupported(QRhi::Feature feature) const override;
+ int resourceLimit(QRhi::ResourceLimit limit) const override;
+ const QRhiNativeHandles *nativeHandles() override;
+ QRhiDriverInfo driverInfo() const override;
+ QRhiStats statistics() override;
+ bool makeThreadLocalNativeContextCurrent() override;
+ void releaseCachedResources() override;
+ bool isDeviceLost() const override;
+
+ QByteArray pipelineCacheData() override;
+ void setPipelineCacheData(const QByteArray &data) override;
+
+ void simulateTextureUpload(const QRhiResourceUpdateBatchPrivate::TextureOp &u);
+ void simulateTextureCopy(const QRhiResourceUpdateBatchPrivate::TextureOp &u);
+ void simulateTextureGenMips(const QRhiResourceUpdateBatchPrivate::TextureOp &u);
+
+ QRhiNullNativeHandles nativeHandlesStruct;
+ QRhiSwapChain *currentSwapChain = nullptr;
+ QNullCommandBuffer offscreenCommandBuffer;
};
QT_END_NAMESPACE
diff --git a/src/gui/rhi/qrhinull_p_p.h b/src/gui/rhi/qrhinull_p_p.h
deleted file mode 100644
index 2ace5a36b6..0000000000
--- a/src/gui/rhi/qrhinull_p_p.h
+++ /dev/null
@@ -1,295 +0,0 @@
-// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QRHINULL_P_H
-#define QRHINULL_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 "qrhinull_p.h"
-#include "qrhi_p_p.h"
-
-QT_BEGIN_NAMESPACE
-
-struct QNullBuffer : public QRhiBuffer
-{
- QNullBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
- ~QNullBuffer();
- void destroy() override;
- bool create() override;
- char *beginFullDynamicBufferUpdateForCurrentFrame() override;
-
- char *data = nullptr;
-};
-
-struct QNullRenderBuffer : public QRhiRenderBuffer
-{
- QNullRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
- int sampleCount, QRhiRenderBuffer::Flags flags,
- QRhiTexture::Format backingFormatHint);
- ~QNullRenderBuffer();
- void destroy() override;
- bool create() override;
- QRhiTexture::Format backingFormat() const override;
-
- bool valid = false;
- uint generation = 0;
-};
-
-struct QNullTexture : public QRhiTexture
-{
- QNullTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
- int arraySize, int sampleCount, Flags flags);
- ~QNullTexture();
- void destroy() override;
- bool create() override;
- bool createFrom(NativeTexture src) override;
-
- bool valid = false;
- QVarLengthArray<std::array<QImage, QRhi::MAX_MIP_LEVELS>, 6> image;
- uint generation = 0;
-};
-
-struct QNullSampler : public QRhiSampler
-{
- QNullSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
- AddressMode u, AddressMode v, AddressMode w);
- ~QNullSampler();
- void destroy() override;
- bool create() override;
-};
-
-struct QNullRenderPassDescriptor : public QRhiRenderPassDescriptor
-{
- QNullRenderPassDescriptor(QRhiImplementation *rhi);
- ~QNullRenderPassDescriptor();
- void destroy() override;
- bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
- QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
- QVector<quint32> serializedFormat() const override;
-};
-
-struct QNullRenderTargetData
-{
- QNullRenderTargetData(QRhiImplementation *) { }
-
- QNullRenderPassDescriptor *rp = nullptr;
- QSize pixelSize;
- float dpr = 1;
- QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList;
-};
-
-struct QNullSwapChainRenderTarget : public QRhiSwapChainRenderTarget
-{
- QNullSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
- ~QNullSwapChainRenderTarget();
- void destroy() override;
-
- QSize pixelSize() const override;
- float devicePixelRatio() const override;
- int sampleCount() const override;
-
- QNullRenderTargetData d;
-};
-
-struct QNullTextureRenderTarget : public QRhiTextureRenderTarget
-{
- QNullTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags);
- ~QNullTextureRenderTarget();
- void destroy() override;
-
- QSize pixelSize() const override;
- float devicePixelRatio() const override;
- int sampleCount() const override;
-
- QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
- bool create() override;
-
- QNullRenderTargetData d;
-};
-
-struct QNullShaderResourceBindings : public QRhiShaderResourceBindings
-{
- QNullShaderResourceBindings(QRhiImplementation *rhi);
- ~QNullShaderResourceBindings();
- void destroy() override;
- bool create() override;
- void updateResources(UpdateFlags flags) override;
-};
-
-struct QNullGraphicsPipeline : public QRhiGraphicsPipeline
-{
- QNullGraphicsPipeline(QRhiImplementation *rhi);
- ~QNullGraphicsPipeline();
- void destroy() override;
- bool create() override;
-};
-
-struct QNullComputePipeline : public QRhiComputePipeline
-{
- QNullComputePipeline(QRhiImplementation *rhi);
- ~QNullComputePipeline();
- void destroy() override;
- bool create() override;
-};
-
-struct QNullCommandBuffer : public QRhiCommandBuffer
-{
- QNullCommandBuffer(QRhiImplementation *rhi);
- ~QNullCommandBuffer();
- void destroy() override;
-};
-
-struct QNullSwapChain : public QRhiSwapChain
-{
- QNullSwapChain(QRhiImplementation *rhi);
- ~QNullSwapChain();
- void destroy() override;
-
- QRhiCommandBuffer *currentFrameCommandBuffer() override;
- QRhiRenderTarget *currentFrameRenderTarget() override;
-
- QSize surfacePixelSize() override;
- bool isFormatSupported(Format f) override;
-
- QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
- bool createOrResize() override;
-
- QWindow *window = nullptr;
- QNullSwapChainRenderTarget rt;
- QNullCommandBuffer cb;
- int frameCount = 0;
-};
-
-class QRhiNull : public QRhiImplementation
-{
-public:
- QRhiNull(QRhiNullInitParams *params);
-
- bool create(QRhi::Flags flags) override;
- void destroy() override;
-
- QRhiGraphicsPipeline *createGraphicsPipeline() override;
- QRhiComputePipeline *createComputePipeline() override;
- QRhiShaderResourceBindings *createShaderResourceBindings() override;
- QRhiBuffer *createBuffer(QRhiBuffer::Type type,
- QRhiBuffer::UsageFlags usage,
- quint32 size) override;
- QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
- const QSize &pixelSize,
- int sampleCount,
- QRhiRenderBuffer::Flags flags,
- QRhiTexture::Format backingFormatHint) override;
- QRhiTexture *createTexture(QRhiTexture::Format format,
- const QSize &pixelSize,
- int depth,
- int arraySize,
- int sampleCount,
- QRhiTexture::Flags flags) override;
- QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
- QRhiSampler::Filter minFilter,
- QRhiSampler::Filter mipmapMode,
- QRhiSampler:: AddressMode u,
- QRhiSampler::AddressMode v,
- QRhiSampler::AddressMode w) override;
-
- QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
- QRhiTextureRenderTarget::Flags flags) override;
-
- QRhiSwapChain *createSwapChain() override;
- QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
- QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
- QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
- QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
- QRhi::FrameOpResult finish() override;
-
- void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
-
- void beginPass(QRhiCommandBuffer *cb,
- QRhiRenderTarget *rt,
- const QColor &colorClearValue,
- const QRhiDepthStencilClearValue &depthStencilClearValue,
- QRhiResourceUpdateBatch *resourceUpdates,
- QRhiCommandBuffer::BeginPassFlags flags) override;
- void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
-
- void setGraphicsPipeline(QRhiCommandBuffer *cb,
- QRhiGraphicsPipeline *ps) override;
-
- void setShaderResources(QRhiCommandBuffer *cb,
- QRhiShaderResourceBindings *srb,
- int dynamicOffsetCount,
- const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
-
- void setVertexInput(QRhiCommandBuffer *cb,
- int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
- QRhiBuffer *indexBuf, quint32 indexOffset,
- QRhiCommandBuffer::IndexFormat indexFormat) override;
-
- void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
- void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
- void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
- void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
-
- void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
- quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
-
- void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
- quint32 instanceCount, quint32 firstIndex,
- qint32 vertexOffset, quint32 firstInstance) override;
-
- void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
- void debugMarkEnd(QRhiCommandBuffer *cb) override;
- void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
-
- void beginComputePass(QRhiCommandBuffer *cb,
- QRhiResourceUpdateBatch *resourceUpdates,
- QRhiCommandBuffer::BeginPassFlags flags) override;
- void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
- void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
- void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
-
- const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
- void beginExternal(QRhiCommandBuffer *cb) override;
- void endExternal(QRhiCommandBuffer *cb) override;
-
- QList<int> supportedSampleCounts() const override;
- int ubufAlignment() const override;
- bool isYUpInFramebuffer() const override;
- bool isYUpInNDC() const override;
- bool isClipDepthZeroToOne() const override;
- QMatrix4x4 clipSpaceCorrMatrix() const override;
- bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
- bool isFeatureSupported(QRhi::Feature feature) const override;
- int resourceLimit(QRhi::ResourceLimit limit) const override;
- const QRhiNativeHandles *nativeHandles() override;
- QRhiDriverInfo driverInfo() const override;
- QRhiStats statistics() override;
- bool makeThreadLocalNativeContextCurrent() override;
- void releaseCachedResources() override;
- bool isDeviceLost() const override;
-
- QByteArray pipelineCacheData() override;
- void setPipelineCacheData(const QByteArray &data) override;
-
- void simulateTextureUpload(const QRhiResourceUpdateBatchPrivate::TextureOp &u);
- void simulateTextureCopy(const QRhiResourceUpdateBatchPrivate::TextureOp &u);
- void simulateTextureGenMips(const QRhiResourceUpdateBatchPrivate::TextureOp &u);
-
- QRhiNullNativeHandles nativeHandlesStruct;
- QRhiSwapChain *currentSwapChain = nullptr;
- QNullCommandBuffer offscreenCommandBuffer;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp
index b2f72dce49..3dd3c57bd4 100644
--- a/src/gui/rhi/qrhivulkan.cpp
+++ b/src/gui/rhi/qrhivulkan.cpp
@@ -1,8 +1,8 @@
-// Copyright (C) 2019 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qrhivulkan_p_p.h"
-#include "qrhivulkanext_p.h"
+#include "qrhivulkan_p.h"
+#include <qpa/qplatformvulkaninstance.h>
#define VMA_IMPLEMENTATION
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
@@ -59,10 +59,13 @@ QT_BEGIN_NAMESPACE
/*!
\class QRhiVulkanInitParams
- \internal
\inmodule QtGui
+ \since 6.6
\brief Vulkan specific initialization parameters.
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+
A Vulkan-based QRhi needs at minimum a valid QVulkanInstance. It is up to
the user to ensure this is available and initialized. This is typically
done in main() similarly to the following:
@@ -165,18 +168,87 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \variable QRhiVulkanInitParams::inst
+
+ The QVulkanInstance that has already been successfully
+ \l{QVulkanInstance::create()}{created}, required.
+*/
+
+/*!
+ \variable QRhiVulkanInitParams::window
+
+ Optional, but recommended when targeting a QWindow.
+*/
+
+/*!
+ \variable QRhiVulkanInitParams::deviceExtensions
+
+ Optional, empty by default. The list of Vulkan device extensions to enable.
+ Unsupported extensions are ignored gracefully.
+*/
+
+/*!
\class QRhiVulkanNativeHandles
- \internal
\inmodule QtGui
+ \since 6.6
\brief Collects device, queue, and other Vulkan objects that are used by the QRhi.
\note Ownership of the Vulkan objects is never transferred.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
+ \variable QRhiVulkanNativeHandles::physDev
+
+ When different from \nullptr, specifies the Vulkan physical device to use.
+*/
+
+/*!
+ \variable QRhiVulkanNativeHandles::dev
+
+ When wanting to import not just a physical device, but also use an already
+ existing VkDevice, set this and the graphics queue index and family index.
+*/
+
+/*!
+ \variable QRhiVulkanNativeHandles::gfxQueueFamilyIdx
+
+ Graphics queue family index.
+*/
+
+/*!
+ \variable QRhiVulkanNativeHandles::gfxQueueIdx
+
+ Graphics queue index.
+*/
+
+/*!
+ \variable QRhiVulkanNativeHandles::vmemAllocator
+
+ Relevant only when importing an existing memory allocator object,
+ leave it set to \nullptr otherwise.
+*/
+
+/*!
+ \variable QRhiVulkanNativeHandles::gfxQueue
+
+ Output only, not used by QRhi::create(), only set by the
+ QRhi::nativeHandles() accessor. The graphics VkQueue used by the QRhi.
+*/
+
+/*!
+ \variable QRhiVulkanNativeHandles::inst
+
+ Output only, not used by QRhi::create(), only set by the
+ QRhi::nativeHandles() accessor. The QVulkanInstance used by the QRhi.
+*/
+
+/*!
\class QRhiVulkanCommandBufferNativeHandles
- \internal
\inmodule QtGui
+ \since 6.6
\brief Holds the Vulkan command buffer object that is backing a QRhiCommandBuffer.
\note The Vulkan command buffer object is only guaranteed to be valid, and
@@ -184,15 +256,33 @@ QT_BEGIN_NAMESPACE
\l{QRhi::beginFrame()}{beginFrame()} - \l{QRhi::endFrame()}{endFrame()} or
\l{QRhi::beginOffscreenFrame()}{beginOffscreenFrame()} -
\l{QRhi::endOffscreenFrame()}{endOffscreenFrame()} pair.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
/*!
+ \variable QRhiVulkanCommandBufferNativeHandles::commandBuffer
+
+ The VkCommandBuffer object.
+*/
+
+/*!
\class QRhiVulkanRenderPassNativeHandles
- \internal
\inmodule QtGui
+ \since 6.6
\brief Holds the Vulkan render pass object backing a QRhiRenderPassDescriptor.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
*/
+/*!
+ \variable QRhiVulkanRenderPassNativeHandles::renderPass
+
+ The VkRenderPass object.
+*/
+
template <class Int>
inline Int aligned(Int v, Int byteAlign)
{
@@ -221,6 +311,13 @@ static inline VmaAllocator toVmaAllocator(QVkAllocator a)
return reinterpret_cast<VmaAllocator>(a);
}
+/*!
+ \return the list of instance extensions that are expected to be enabled on
+ the QVulkanInstance that is used for the Vulkan-based QRhi.
+
+ The returned list can be safely passed to QVulkanInstance::setExtensions()
+ as-is, because unsupported extensions are filtered out automatically.
+ */
QByteArrayList QRhiVulkanInitParams::preferredInstanceExtensions()
{
return {
@@ -228,11 +325,18 @@ QByteArrayList QRhiVulkanInitParams::preferredInstanceExtensions()
};
}
+/*!
+ \return the list of device extensions that are expected to be enabled on the
+ \c VkDevice when creating a Vulkan-based QRhi with an externally created
+ \c VkDevice object.
+ */
QByteArrayList QRhiVulkanInitParams::preferredExtensionsForImportedDevice()
{
return {
QByteArrayLiteral("VK_KHR_swapchain"),
- QByteArrayLiteral("VK_EXT_vertex_attribute_divisor")
+ QByteArrayLiteral("VK_EXT_vertex_attribute_divisor"),
+ QByteArrayLiteral("VK_KHR_create_renderpass2"),
+ QByteArrayLiteral("VK_KHR_depth_stencil_resolve")
};
}
@@ -326,6 +430,8 @@ bool QRhiVulkan::create(QRhi::Flags flags)
for (const char *ext : inst->extensions())
qCDebug(QRHI_LOG_INFO, " %s", ext);
}
+
+ caps = {};
caps.debugUtils = inst->extensions().contains(QByteArrayLiteral("VK_EXT_debug_utils"));
QList<VkQueueFamilyProperties> queueFamilyProps;
@@ -427,7 +533,65 @@ bool QRhiVulkan::create(QRhi::Flags flags)
driverInfoStruct.vendorId = physDevProperties.vendorID;
driverInfoStruct.deviceType = toRhiDeviceType(physDevProperties.deviceType);
- f->vkGetPhysicalDeviceFeatures(physDev, &physDevFeatures);
+ bool featuresQueried = false;
+#ifdef VK_VERSION_1_1
+ VkPhysicalDeviceFeatures2 physDevFeaturesChainable = {};
+ physDevFeaturesChainable.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+#endif
+
+ // Vulkan >=1.2 headers at build time, >=1.2 implementation at run time
+#ifdef VK_VERSION_1_2
+ if (!featuresQueried) {
+ // Vulkan11Features, Vulkan12Features, etc. are only in Vulkan 1.2 and newer.
+ if (caps.apiVersion >= QVersionNumber(1, 2)) {
+ physDevFeatures11IfApi12OrNewer = {};
+ physDevFeatures11IfApi12OrNewer.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
+ physDevFeatures12 = {};
+ physDevFeatures12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
+#ifdef VK_VERSION_1_3
+ physDevFeatures13 = {};
+ physDevFeatures13.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
+#endif
+ physDevFeaturesChainable.pNext = &physDevFeatures11IfApi12OrNewer;
+ physDevFeatures11IfApi12OrNewer.pNext = &physDevFeatures12;
+#ifdef VK_VERSION_1_3
+ if (caps.apiVersion >= QVersionNumber(1, 3))
+ physDevFeatures12.pNext = &physDevFeatures13;
+#endif
+ f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
+ memcpy(&physDevFeatures, &physDevFeaturesChainable.features, sizeof(VkPhysicalDeviceFeatures));
+ featuresQueried = true;
+ }
+ }
+#endif // VK_VERSION_1_2
+
+ // Vulkan >=1.1 headers at build time, 1.1 implementation at run time
+#ifdef VK_VERSION_1_1
+ if (!featuresQueried) {
+ // Vulkan versioning nightmares: if the runtime API version is 1.1,
+ // there is no Vulkan11Features (introduced in 1.2+, the headers might
+ // have the types and structs, but the Vulkan implementation version at
+ // run time is what matters). But there are individual feature structs.
+ // For multiview, it is important to get this right since at the time of
+ // writing Quest 3 Android is a Vulkan 1.1 implementation at run time on
+ // the headset.
+ if (caps.apiVersion == QVersionNumber(1, 1)) {
+ multiviewFeaturesIfApi11 = {};
+ multiviewFeaturesIfApi11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
+ physDevFeaturesChainable.pNext = &multiviewFeaturesIfApi11;
+ f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeaturesChainable);
+ memcpy(&physDevFeatures, &physDevFeaturesChainable.features, sizeof(VkPhysicalDeviceFeatures));
+ featuresQueried = true;
+ }
+ }
+#endif
+
+ if (!featuresQueried) {
+ // If the API version at run time is 1.0 (or we are building with
+ // ancient 1.0 headers), then do the Vulkan 1.0 query.
+ f->vkGetPhysicalDeviceFeatures(physDev, &physDevFeatures);
+ featuresQueried = true;
+ }
// Choose queue and create device, unless the device was specified in importParams.
if (!importedDevice) {
@@ -499,13 +663,28 @@ bool QRhiVulkan::create(QRhi::Flags flags)
}
}
- caps.vertexAttribDivisor = false;
+#ifdef VK_EXT_vertex_attribute_divisor
if (devExts.contains(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
if (hasPhysDevProp2) {
requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
caps.vertexAttribDivisor = true;
}
}
+#endif
+
+#ifdef VK_KHR_create_renderpass2
+ if (devExts.contains(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME)) {
+ requestedDevExts.append(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME);
+ caps.renderPass2KHR = true;
+ }
+#endif
+
+#ifdef VK_KHR_depth_stencil_resolve
+ if (devExts.contains(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME)) {
+ requestedDevExts.append(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME);
+ caps.depthStencilResolveKHR = true;
+ }
+#endif
for (const QByteArray &ext : requestedDeviceExtensions) {
if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
@@ -558,42 +737,27 @@ bool QRhiVulkan::create(QRhi::Flags flags)
// tessellationShader, geometryShader
// textureCompressionETC2, textureCompressionASTC_LDR, textureCompressionBC
-#ifdef VK_VERSION_1_2 // Vulkan11Features is only in Vulkan 1.2
- VkPhysicalDeviceFeatures2 physDevFeatures2 = {};
- physDevFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
-
- VkPhysicalDeviceVulkan11Features features11 = {};
- features11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
- VkPhysicalDeviceVulkan12Features features12 = {};
- features12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
-#ifdef VK_VERSION_1_3
- VkPhysicalDeviceVulkan13Features features13 = {};
- features13.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
+#ifdef VK_VERSION_1_1
+ physDevFeaturesChainable.features.robustBufferAccess = VK_FALSE;
#endif
-
- if (caps.apiVersion >= QVersionNumber(1, 2)) {
- physDevFeatures2.pNext = &features11;
- features11.pNext = &features12;
#ifdef VK_VERSION_1_3
- if (caps.apiVersion >= QVersionNumber(1, 3))
- features12.pNext = &features13;
+ physDevFeatures13.robustImageAccess = VK_FALSE;
#endif
- f->vkGetPhysicalDeviceFeatures2(physDev, &physDevFeatures2);
- physDevFeatures2.features.robustBufferAccess = VK_FALSE;
-#ifdef VK_VERSION_1_3
- features13.robustImageAccess = VK_FALSE;
+#ifdef VK_VERSION_1_1
+ if (caps.apiVersion >= QVersionNumber(1, 1)) {
+ // For a >=1.2 implementation at run time, this will enable all
+ // (1.0-1.3) features reported as supported, except the ones we turn
+ // off explicitly above. For a 1.1 implementation at run time, this
+ // only enables the 1.0 and multiview features reported as
+ // supported. We will not be bothering with the Vulkan 1.1
+ // individual feature struct nonsense.
+ devInfo.pNext = &physDevFeaturesChainable;
+ } else
#endif
-
- devInfo.pNext = &physDevFeatures2;
- }
-#endif // VK_VERSION_1_2
-
- VkPhysicalDeviceFeatures features;
- if (!devInfo.pNext) {
- memcpy(&features, &physDevFeatures, sizeof(features));
- features.robustBufferAccess = VK_FALSE;
- devInfo.pEnabledFeatures = &features;
+ {
+ physDevFeatures.robustBufferAccess = VK_FALSE;
+ devInfo.pEnabledFeatures = &physDevFeatures;
}
VkResult err = f->vkCreateDevice(physDev, &devInfo, nullptr, &dev);
@@ -603,6 +767,13 @@ bool QRhiVulkan::create(QRhi::Flags flags)
}
} else {
qCDebug(QRHI_LOG_INFO, "Using imported device %p", dev);
+
+ // Here we have no way to tell if the extensions got enabled or not.
+ // Pretend it's all there and supported. If getProcAddress fails, we'll
+ // handle that gracefully.
+ caps.vertexAttribDivisor = true;
+ caps.renderPass2KHR = true;
+ caps.depthStencilResolveKHR = true;
}
vkGetPhysicalDeviceSurfaceCapabilitiesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR>(
@@ -611,13 +782,6 @@ bool QRhiVulkan::create(QRhi::Flags flags)
inst->getInstanceProcAddr("vkGetPhysicalDeviceSurfaceFormatsKHR"));
vkGetPhysicalDeviceSurfacePresentModesKHR = reinterpret_cast<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR>(
inst->getInstanceProcAddr("vkGetPhysicalDeviceSurfacePresentModesKHR"));
- if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR
- || !vkGetPhysicalDeviceSurfaceFormatsKHR
- || !vkGetPhysicalDeviceSurfacePresentModesKHR)
- {
- qWarning("Physical device surface queries not available");
- return false;
- }
df = inst->deviceFunctions(dev);
@@ -657,6 +821,28 @@ bool QRhiVulkan::create(QRhi::Flags flags)
caps.nonFillPolygonMode = physDevFeatures.fillModeNonSolid;
+#ifdef VK_VERSION_1_2
+ if (caps.apiVersion >= QVersionNumber(1, 2))
+ caps.multiView = physDevFeatures11IfApi12OrNewer.multiview;
+#endif
+
+#ifdef VK_VERSION_1_1
+ if (caps.apiVersion == QVersionNumber(1, 1))
+ caps.multiView = multiviewFeaturesIfApi11.multiview;
+#endif
+
+ // With Vulkan 1.2 renderpass2 and depth_stencil_resolve are core, but we
+ // have to support the case of 1.1 + extensions, in particular for the Quest
+ // 3 (Android, Vulkan 1.1 at the time of writing). Therefore, always rely on
+ // the KHR extension for now.
+#ifdef VK_KHR_create_renderpass2
+ if (caps.renderPass2KHR) {
+ vkCreateRenderPass2KHR = reinterpret_cast<PFN_vkCreateRenderPass2KHR>(f->vkGetDeviceProcAddr(dev, "vkCreateRenderPass2KHR"));
+ if (!vkCreateRenderPass2KHR) // handle it gracefully, the caps flag may be incorrect when using an imported VkDevice
+ caps.renderPass2KHR = false;
+ }
+#endif
+
if (!importedAllocator) {
VmaVulkanFunctions funcs = {};
funcs.vkGetInstanceProcAddr = wrap_vkGetInstanceProcAddr;
@@ -670,12 +856,9 @@ bool QRhiVulkan::create(QRhi::Flags flags)
allocatorInfo.device = dev;
allocatorInfo.pVulkanFunctions = &funcs;
allocatorInfo.instance = inst->vkInstance();
- const QVersionNumber apiVer = inst->apiVersion();
- if (!apiVer.isNull()) {
- allocatorInfo.vulkanApiVersion = VK_MAKE_VERSION(apiVer.majorVersion(),
- apiVer.minorVersion(),
- apiVer.microVersion());
- }
+ allocatorInfo.vulkanApiVersion = VK_MAKE_VERSION(caps.apiVersion.majorVersion(),
+ caps.apiVersion.minorVersion(),
+ caps.apiVersion.microVersion());
VmaAllocator vmaallocator;
VkResult err = vmaCreateAllocator(&allocatorInfo, &vmaallocator);
if (err != VK_SUCCESS) {
@@ -723,6 +906,7 @@ bool QRhiVulkan::create(QRhi::Flags flags)
nativeHandlesStruct.gfxQueueIdx = gfxQueueIdx;
nativeHandlesStruct.gfxQueue = gfxQueue;
nativeHandlesStruct.vmemAllocator = allocator;
+ nativeHandlesStruct.inst = inst;
return true;
}
@@ -1183,6 +1367,8 @@ bool QRhiVulkan::createDefaultRenderPass(QVkRenderPassDescriptor *rpD, bool hasD
rpD->colorRefs.append({ 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL });
rpD->hasDepthStencil = hasDepthStencil;
+ rpD->hasDepthStencilResolve = false;
+ rpD->multiViewCount = 0;
if (hasDepthStencil) {
// clear on load + no store + lazy alloc + transient image should play
@@ -1252,28 +1438,190 @@ bool QRhiVulkan::createDefaultRenderPass(QVkRenderPassDescriptor *rpD, bool hasD
return true;
}
+struct MultiViewRenderPassSetupHelper
+{
+ bool prepare(VkRenderPassCreateInfo *rpInfo, int multiViewCount, bool multiViewCap)
+ {
+ if (multiViewCount < 2)
+ return true;
+ if (!multiViewCap) {
+ qWarning("Cannot create multiview render pass without support for the Vulkan 1.1 multiview feature");
+ return false;
+ }
+#ifdef VK_VERSION_1_1
+ uint32_t allViewsMask = 0;
+ for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
+ allViewsMask |= (1 << i);
+ multiViewMask = allViewsMask;
+ multiViewCorrelationMask = allViewsMask;
+ multiViewInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
+ multiViewInfo.subpassCount = 1;
+ multiViewInfo.pViewMasks = &multiViewMask;
+ multiViewInfo.correlationMaskCount = 1;
+ multiViewInfo.pCorrelationMasks = &multiViewCorrelationMask;
+ rpInfo->pNext = &multiViewInfo;
+#endif
+ return true;
+ }
+
+#ifdef VK_VERSION_1_1
+ VkRenderPassMultiviewCreateInfo multiViewInfo = {};
+ uint32_t multiViewMask = 0;
+ uint32_t multiViewCorrelationMask = 0;
+#endif
+};
+
+#ifdef VK_KHR_create_renderpass2
+// Effectively converts a VkRenderPassCreateInfo into a VkRenderPassCreateInfo2,
+// adding depth-stencil resolve support. Assumes a single subpass and no subpass
+// dependencies.
+struct RenderPass2SetupHelper
+{
+ bool prepare(VkRenderPassCreateInfo2 *rpInfo2, const VkRenderPassCreateInfo *rpInfo, const QVkRenderPassDescriptor *rpD, int multiViewCount) {
+ *rpInfo2 = {};
+
+ viewMask = 0;
+ if (multiViewCount >= 2) {
+ for (uint32_t i = 0; i < uint32_t(multiViewCount); ++i)
+ viewMask |= (1 << i);
+ }
+
+ attDescs2.resize(rpInfo->attachmentCount);
+ for (qsizetype i = 0; i < attDescs2.count(); ++i) {
+ VkAttachmentDescription2KHR &att2(attDescs2[i]);
+ const VkAttachmentDescription &att(rpInfo->pAttachments[i]);
+ att2 = {};
+ att2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
+ att2.flags = att.flags;
+ att2.format = att.format;
+ att2.samples = att.samples;
+ att2.loadOp = att.loadOp;
+ att2.storeOp = att.storeOp;
+ att2.stencilLoadOp = att.stencilLoadOp;
+ att2.stencilStoreOp = att.stencilStoreOp;
+ att2.initialLayout = att.initialLayout;
+ att2.finalLayout = att.finalLayout;
+ }
+
+ attRefs2.clear();
+ subpass2 = {};
+ subpass2.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR;
+ const VkSubpassDescription &subpassDesc(rpInfo->pSubpasses[0]);
+ subpass2.flags = subpassDesc.flags;
+ subpass2.pipelineBindPoint = subpassDesc.pipelineBindPoint;
+ if (multiViewCount >= 2)
+ subpass2.viewMask = viewMask;
+
+ // color attachment refs
+ qsizetype startIndex = attRefs2.count();
+ for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
+ attRefs2.append({});
+ VkAttachmentReference2KHR &attref2(attRefs2.last());
+ const VkAttachmentReference &attref(subpassDesc.pColorAttachments[j]);
+ attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
+ attref2.attachment = attref.attachment;
+ attref2.layout = attref.layout;
+ attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ }
+ subpass2.colorAttachmentCount = subpassDesc.colorAttachmentCount;
+ subpass2.pColorAttachments = attRefs2.constData() + startIndex;
+
+ // color resolve refs
+ if (subpassDesc.pResolveAttachments) {
+ startIndex = attRefs2.count();
+ for (uint32_t j = 0; j < subpassDesc.colorAttachmentCount; ++j) {
+ attRefs2.append({});
+ VkAttachmentReference2KHR &attref2(attRefs2.last());
+ const VkAttachmentReference &attref(subpassDesc.pResolveAttachments[j]);
+ attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
+ attref2.attachment = attref.attachment;
+ attref2.layout = attref.layout;
+ attref2.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ }
+ subpass2.pResolveAttachments = attRefs2.constData() + startIndex;
+ }
+
+ // depth-stencil ref
+ if (subpassDesc.pDepthStencilAttachment) {
+ startIndex = attRefs2.count();
+ attRefs2.append({});
+ VkAttachmentReference2KHR &attref2(attRefs2.last());
+ const VkAttachmentReference &attref(*subpassDesc.pDepthStencilAttachment);
+ attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
+ attref2.attachment = attref.attachment;
+ attref2.layout = attref.layout;
+ attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
+ subpass2.pDepthStencilAttachment = attRefs2.constData() + startIndex;
+ }
+
+ // depth-stencil resolve ref
+#ifdef VK_KHR_depth_stencil_resolve
+ dsResolveDesc = {};
+ if (rpD->hasDepthStencilResolve) {
+ startIndex = attRefs2.count();
+ attRefs2.append({});
+ VkAttachmentReference2KHR &attref2(attRefs2.last());
+ attref2.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR;
+ attref2.attachment = rpD->dsResolveRef.attachment;
+ attref2.layout = rpD->dsResolveRef.layout;
+ attref2.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
+ dsResolveDesc.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE_KHR;
+ dsResolveDesc.depthResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
+ dsResolveDesc.stencilResolveMode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
+ dsResolveDesc.pDepthStencilResolveAttachment = attRefs2.constData() + startIndex;
+ subpass2.pNext = &dsResolveDesc;
+ }
+#endif
+
+ rpInfo2->sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR;
+ rpInfo2->pNext = nullptr; // the 1.1 VkRenderPassMultiviewCreateInfo is part of the '2' structs
+ rpInfo2->flags = rpInfo->flags;
+ rpInfo2->attachmentCount = rpInfo->attachmentCount;
+ rpInfo2->pAttachments = attDescs2.constData();
+ rpInfo2->subpassCount = 1;
+ rpInfo2->pSubpasses = &subpass2;
+ if (multiViewCount >= 2) {
+ rpInfo2->correlatedViewMaskCount = 1;
+ rpInfo2->pCorrelatedViewMasks = &viewMask;
+ }
+ return true;
+ }
+
+ QVarLengthArray<VkAttachmentDescription2KHR, 8> attDescs2;
+ QVarLengthArray<VkAttachmentReference2KHR, 8> attRefs2;
+ VkSubpassDescription2KHR subpass2;
+#ifdef VK_KHR_depth_stencil_resolve
+ VkSubpassDescriptionDepthStencilResolveKHR dsResolveDesc;
+#endif
+ uint32_t viewMask;
+};
+#endif // VK_KHR_create_renderpass2
+
bool QRhiVulkan::createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
- const QRhiColorAttachment *firstColorAttachment,
- const QRhiColorAttachment *lastColorAttachment,
+ const QRhiColorAttachment *colorAttachmentsBegin,
+ const QRhiColorAttachment *colorAttachmentsEnd,
bool preserveColor,
bool preserveDs,
+ bool storeDs,
QRhiRenderBuffer *depthStencilBuffer,
- QRhiTexture *depthTexture)
+ QRhiTexture *depthTexture,
+ QRhiTexture *depthResolveTexture)
{
- // attachment list layout is color (0-8), ds (0-1), resolve (0-8)
+ // attachment list layout is color (0-8), ds (0-1), resolve (0-8), ds resolve (0-1)
- for (auto it = firstColorAttachment; it != lastColorAttachment; ++it) {
+ int multiViewCount = 0;
+ for (auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
QVkTexture *texD = QRHI_RES(QVkTexture, it->texture());
QVkRenderBuffer *rbD = QRHI_RES(QVkRenderBuffer, it->renderBuffer());
Q_ASSERT(texD || rbD);
- const VkFormat vkformat = texD ? texD->vkformat : rbD->vkformat;
+ const VkFormat vkformat = texD ? texD->viewFormat : rbD->vkformat;
const VkSampleCountFlagBits samples = texD ? texD->samples : rbD->samples;
VkAttachmentDescription attDesc = {};
attDesc.format = vkformat;
attDesc.samples = samples;
attDesc.loadOp = preserveColor ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
- attDesc.storeOp = it->resolveTexture() ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
+ attDesc.storeOp = (it->resolveTexture() && !preserveColor) ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
// this has to interact correctly with activateTextureRenderTarget(), hence leaving in COLOR_ATT
@@ -1283,16 +1631,27 @@ bool QRhiVulkan::createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
const VkAttachmentReference ref = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
rpD->colorRefs.append(ref);
+
+ if (it->multiViewCount() >= 2) {
+ if (multiViewCount > 0 && multiViewCount != it->multiViewCount())
+ qWarning("Inconsistent multiViewCount in color attachment set");
+ else
+ multiViewCount = it->multiViewCount();
+ } else if (multiViewCount > 0) {
+ qWarning("Mixing non-multiview color attachments within a multiview render pass");
+ }
}
+ Q_ASSERT(multiViewCount == 0 || multiViewCount >= 2);
+ rpD->multiViewCount = uint32_t(multiViewCount);
rpD->hasDepthStencil = depthStencilBuffer || depthTexture;
if (rpD->hasDepthStencil) {
- const VkFormat dsFormat = depthTexture ? QRHI_RES(QVkTexture, depthTexture)->vkformat
+ const VkFormat dsFormat = depthTexture ? QRHI_RES(QVkTexture, depthTexture)->viewFormat
: QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->vkformat;
const VkSampleCountFlagBits samples = depthTexture ? QRHI_RES(QVkTexture, depthTexture)->samples
: QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->samples;
const VkAttachmentLoadOp loadOp = preserveDs ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_CLEAR;
- const VkAttachmentStoreOp storeOp = depthTexture ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ const VkAttachmentStoreOp storeOp = storeDs ? VK_ATTACHMENT_STORE_OP_STORE : VK_ATTACHMENT_STORE_OP_DONT_CARE;
VkAttachmentDescription attDesc = {};
attDesc.format = dsFormat;
attDesc.samples = samples;
@@ -1300,13 +1659,17 @@ bool QRhiVulkan::createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
attDesc.storeOp = storeOp;
attDesc.stencilLoadOp = loadOp;
attDesc.stencilStoreOp = storeOp;
- attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ attDesc.initialLayout = preserveDs ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED;
attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
rpD->attDescs.append(attDesc);
+ if (depthTexture && depthTexture->arraySize() >= 2 && colorAttachmentsBegin == colorAttachmentsEnd) {
+ multiViewCount = depthTexture->arraySize();
+ rpD->multiViewCount = multiViewCount;
+ }
}
rpD->dsRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
- for (auto it = firstColorAttachment; it != lastColorAttachment; ++it) {
+ for (auto it = colorAttachmentsBegin; it != colorAttachmentsEnd; ++it) {
if (it->resolveTexture()) {
QVkTexture *rtexD = QRHI_RES(QVkTexture, it->resolveTexture());
const VkFormat dstFormat = rtexD->vkformat;
@@ -1325,7 +1688,7 @@ bool QRhiVulkan::createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
}
VkAttachmentDescription attDesc = {};
- attDesc.format = dstFormat;
+ attDesc.format = rtexD->viewFormat;
attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // ignored
attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
@@ -1344,6 +1707,31 @@ bool QRhiVulkan::createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
}
Q_ASSERT(rpD->colorRefs.size() == rpD->resolveRefs.size());
+ rpD->hasDepthStencilResolve = rpD->hasDepthStencil && depthResolveTexture;
+ if (rpD->hasDepthStencilResolve) {
+ QVkTexture *rtexD = QRHI_RES(QVkTexture, depthResolveTexture);
+ if (rtexD->samples > VK_SAMPLE_COUNT_1_BIT)
+ qWarning("Resolving into a multisample depth texture is not supported");
+
+ QVkTexture *texD = QRHI_RES(QVkTexture, depthResolveTexture);
+ if (texD->vkformat != rtexD->vkformat) {
+ qWarning("Multisample resolve between different depth-stencil formats (%d and %d) is not supported.",
+ int(texD->vkformat), int(rtexD->vkformat));
+ }
+
+ VkAttachmentDescription attDesc = {};
+ attDesc.format = rtexD->viewFormat;
+ attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
+ attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // ignored
+ attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attDesc.stencilLoadOp = attDesc.loadOp;
+ attDesc.stencilStoreOp = attDesc.storeOp;
+ attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ attDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
+ rpD->attDescs.append(attDesc);
+ }
+ rpD->dsResolveRef = { uint32_t(rpD->attDescs.size() - 1), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL };
+
// rpD->subpassDeps stays empty: don't yet know the correct initial/final
// access and stage stuff for the implicit deps at this point, so leave it
// to the resource tracking and activateTextureRenderTarget() to generate
@@ -1353,10 +1741,35 @@ bool QRhiVulkan::createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
VkSubpassDescription subpassDesc;
fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
- VkResult err = df->vkCreateRenderPass(dev, &rpInfo, nullptr, &rpD->rp);
- if (err != VK_SUCCESS) {
- qWarning("Failed to create renderpass: %d", err);
+ MultiViewRenderPassSetupHelper multiViewHelper;
+ if (!multiViewHelper.prepare(&rpInfo, multiViewCount, caps.multiView))
return false;
+
+#ifdef VK_KHR_create_renderpass2
+ if (rpD->hasDepthStencilResolve && caps.renderPass2KHR) {
+ // Use the KHR extension, not the 1.2 core API, in order to support Vulkan 1.1.
+ VkRenderPassCreateInfo2KHR rpInfo2;
+ RenderPass2SetupHelper rp2Helper;
+ if (!rp2Helper.prepare(&rpInfo2, &rpInfo, rpD, multiViewCount))
+ return false;
+
+ VkResult err = vkCreateRenderPass2KHR(dev, &rpInfo2, nullptr, &rpD->rp);
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to create renderpass (using VkRenderPassCreateInfo2KHR): %d", err);
+ return false;
+ }
+ } else
+#endif
+ {
+ if (rpD->hasDepthStencilResolve) {
+ qWarning("Resolving multisample depth-stencil buffers is not supported without "
+ "VK_KHR_depth_stencil_resolve and VK_KHR_create_renderpass2");
+ }
+ VkResult err = df->vkCreateRenderPass(dev, &rpInfo, nullptr, &rpD->rp);
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to create renderpass: %d", err);
+ return false;
+ }
}
return true;
@@ -1443,9 +1856,16 @@ bool QRhiVulkan::recreateSwapChain(QRhiSwapChain *swapChain)
if (swapChainD->supportsReadback && swapChainD->m_flags.testFlag(QRhiSwapChain::UsedAsTransferSource))
usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+ const bool stereo = bool(swapChainD->m_window) && (swapChainD->m_window->format().stereo())
+ && surfaceCaps.maxImageArrayLayers > 1;
+ swapChainD->stereo = stereo;
+
VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR;
if (swapChainD->m_flags.testFlag(QRhiSwapChain::NoVSync)) {
- if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_MAILBOX_KHR))
+ // Stereo has a weird bug, when using VK_PRESENT_MODE_MAILBOX_KHR,
+ // black screen is shown, but there is no validation error.
+ // Detected on Windows, with NVidia RTX A series (at least 4000 and 6000) driver 535.98
+ if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_MAILBOX_KHR) && !stereo)
presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
else if (swapChainD->supportedPresentationModes.contains(VK_PRESENT_MODE_IMMEDIATE_KHR))
presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
@@ -1469,7 +1889,7 @@ bool QRhiVulkan::recreateSwapChain(QRhiSwapChain *swapChain)
swapChainInfo.imageFormat = swapChainD->colorFormat;
swapChainInfo.imageColorSpace = swapChainD->colorSpace;
swapChainInfo.imageExtent = VkExtent2D { uint32_t(swapChainD->pixelSize.width()), uint32_t(swapChainD->pixelSize.height()) };
- swapChainInfo.imageArrayLayers = 1;
+ swapChainInfo.imageArrayLayers = stereo ? 2u : 1u;
swapChainInfo.imageUsage = usage;
swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
swapChainInfo.preTransform = preTransform;
@@ -1531,7 +1951,9 @@ bool QRhiVulkan::recreateSwapChain(QRhiSwapChain *swapChain)
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
- swapChainD->imageRes.resize(swapChainD->bufferCount);
+ // Double up for stereo
+ swapChainD->imageRes.resize(swapChainD->bufferCount * (stereo ? 2u : 1u));
+
for (int i = 0; i < swapChainD->bufferCount; ++i) {
QVkSwapChain::ImageResources &image(swapChainD->imageRes[i]);
image.image = swapChainImages[i];
@@ -1559,6 +1981,36 @@ bool QRhiVulkan::recreateSwapChain(QRhiSwapChain *swapChain)
image.lastUse = QVkSwapChain::ImageResources::ScImageUseNone;
}
+ if (stereo) {
+ for (int i = 0; i < swapChainD->bufferCount; ++i) {
+ QVkSwapChain::ImageResources &image(swapChainD->imageRes[i + swapChainD->bufferCount]);
+ image.image = swapChainImages[i];
+ if (swapChainD->samples > VK_SAMPLE_COUNT_1_BIT) {
+ image.msaaImage = msaaImages[i];
+ image.msaaImageView = msaaViews[i];
+ }
+
+ VkImageViewCreateInfo imgViewInfo = {};
+ imgViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ imgViewInfo.image = swapChainImages[i];
+ imgViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ imgViewInfo.format = swapChainD->colorFormat;
+ imgViewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
+ imgViewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
+ imgViewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
+ imgViewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
+ imgViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ imgViewInfo.subresourceRange.baseArrayLayer = 1;
+ imgViewInfo.subresourceRange.levelCount = imgViewInfo.subresourceRange.layerCount = 1;
+ err = df->vkCreateImageView(dev, &imgViewInfo, nullptr, &image.imageView);
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to create swapchain image view %d: %d", i, err);
+ return false;
+ }
+
+ image.lastUse = QVkSwapChain::ImageResources::ScImageUseNone;
+ }
+ }
swapChainD->currentImageIndex = 0;
@@ -1626,7 +2078,7 @@ void QRhiVulkan::releaseSwapChainResources(QRhiSwapChain *swapChain)
}
}
- for (int i = 0; i < swapChainD->bufferCount; ++i) {
+ for (int i = 0; i < swapChainD->bufferCount * (swapChainD->stereo ? 2 : 1); ++i) {
QVkSwapChain::ImageResources &image(swapChainD->imageRes[i]);
if (image.fb) {
df->vkDestroyFramebuffer(dev, image.fb, nullptr);
@@ -1671,12 +2123,32 @@ void QRhiVulkan::ensureCommandPoolForNewFrame()
df->vkResetCommandPool(dev, cmdPool[currentFrameSlot], flags);
}
+double QRhiVulkan::elapsedSecondsFromTimestamp(quint64 timestamp[2], bool *ok)
+{
+ quint64 mask = 0;
+ for (quint64 i = 0; i < timestampValidBits; i += 8)
+ mask |= 0xFFULL << i;
+ const quint64 ts0 = timestamp[0] & mask;
+ const quint64 ts1 = timestamp[1] & mask;
+ const float nsecsPerTick = physDevProperties.limits.timestampPeriod;
+ if (!qFuzzyIsNull(nsecsPerTick)) {
+ const float elapsedMs = float(ts1 - ts0) * nsecsPerTick / 1000000.0f;
+ const double elapsedSec = elapsedMs / 1000.0;
+ *ok = true;
+ return elapsedSec;
+ }
+ *ok = false;
+ return 0;
+}
+
QRhi::FrameOpResult QRhiVulkan::beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags)
{
QVkSwapChain *swapChainD = QRHI_RES(QVkSwapChain, swapChain);
const int frameResIndex = swapChainD->bufferCount > 1 ? swapChainD->currentFrameSlot : 0;
QVkSwapChain::FrameResources &frame(swapChainD->frameRes[frameResIndex]);
+ inst->handle()->beginFrame(swapChainD->window);
+
if (!frame.imageAcquired) {
// Wait if we are too far ahead, i.e. the thread gets throttled based on the presentation rate
// (note that we are using FIFO mode -> vsync)
@@ -1720,30 +2192,6 @@ QRhi::FrameOpResult QRhiVulkan::beginFrame(QRhiSwapChain *swapChain, QRhi::Begin
// mess up A's in-flight commands (as they are not in flight anymore).
waitCommandCompletion(frameResIndex);
- // Now is the time to read the timestamps for the previous frame for this slot.
- if (frame.timestampQueryIndex >= 0) {
- quint64 timestamp[2] = { 0, 0 };
- VkResult err = df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(frame.timestampQueryIndex), 2,
- 2 * sizeof(quint64), timestamp, sizeof(quint64),
- VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
- timestampQueryPoolMap.clearBit(frame.timestampQueryIndex / 2);
- frame.timestampQueryIndex = -1;
- if (err == VK_SUCCESS) {
- quint64 mask = 0;
- for (quint64 i = 0; i < timestampValidBits; i += 8)
- mask |= 0xFFULL << i;
- const quint64 ts0 = timestamp[0] & mask;
- const quint64 ts1 = timestamp[1] & mask;
- const float nsecsPerTick = physDevProperties.limits.timestampPeriod;
- if (!qFuzzyIsNull(nsecsPerTick)) {
- const float elapsedMs = float(ts1 - ts0) * nsecsPerTick / 1000000.0f;
- runGpuFrameTimeCallbacks(elapsedMs);
- }
- } else {
- qWarning("Failed to query timestamp: %d", err);
- }
- }
-
currentFrameSlot = int(swapChainD->currentFrameSlot);
currentSwapChain = swapChainD;
if (swapChainD->ds)
@@ -1757,9 +2205,40 @@ QRhi::FrameOpResult QRhiVulkan::beginFrame(QRhiSwapChain *swapChain, QRhi::Begin
if (cbres != QRhi::FrameOpSuccess)
return cbres;
- // when profiling is enabled, pick a free query (pair) from the pool
- int timestampQueryIdx = -1;
- if (hasGpuFrameTimeCallback() && swapChainD->bufferCount > 1) { // no timestamps if not having at least 2 frames in flight
+ swapChainD->cbWrapper.cb = frame.cmdBuf;
+
+ QVkSwapChain::ImageResources &image(swapChainD->imageRes[swapChainD->currentImageIndex]);
+ swapChainD->rtWrapper.d.fb = image.fb;
+
+ if (swapChainD->stereo) {
+ QVkSwapChain::ImageResources &image(
+ swapChainD->imageRes[swapChainD->currentImageIndex + swapChainD->bufferCount]);
+ swapChainD->rtWrapperRight.d.fb = image.fb;
+ }
+
+ prepareNewFrame(&swapChainD->cbWrapper);
+
+ // Read the timestamps for the previous frame for this slot.
+ if (frame.timestampQueryIndex >= 0) {
+ quint64 timestamp[2] = { 0, 0 };
+ VkResult err = df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(frame.timestampQueryIndex), 2,
+ 2 * sizeof(quint64), timestamp, sizeof(quint64),
+ VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
+ timestampQueryPoolMap.clearBit(frame.timestampQueryIndex / 2);
+ frame.timestampQueryIndex = -1;
+ if (err == VK_SUCCESS) {
+ bool ok = false;
+ const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
+ if (ok)
+ swapChainD->cbWrapper.lastGpuTime = elapsedSec;
+ } else {
+ qWarning("Failed to query timestamp: %d", err);
+ }
+ }
+
+ // No timestamps if the client did not opt in, or when not having at least 2 frames in flight.
+ if (rhiFlags.testFlag(QRhi::EnableTimestamps) && swapChainD->bufferCount > 1) {
+ int timestampQueryIdx = -1;
for (int i = 0; i < timestampQueryPoolMap.size(); ++i) {
if (!timestampQueryPoolMap.testBit(i)) {
timestampQueryPoolMap.setBit(i);
@@ -1767,21 +2246,14 @@ QRhi::FrameOpResult QRhiVulkan::beginFrame(QRhiSwapChain *swapChain, QRhi::Begin
break;
}
}
+ if (timestampQueryIdx >= 0) {
+ df->vkCmdResetQueryPool(frame.cmdBuf, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
+ // record timestamp at the start of the command buffer
+ df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+ timestampQueryPool, uint32_t(timestampQueryIdx));
+ frame.timestampQueryIndex = timestampQueryIdx;
+ }
}
- if (timestampQueryIdx >= 0) {
- df->vkCmdResetQueryPool(frame.cmdBuf, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
- // record timestamp at the start of the command buffer
- df->vkCmdWriteTimestamp(frame.cmdBuf, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
- timestampQueryPool, uint32_t(timestampQueryIdx));
- frame.timestampQueryIndex = timestampQueryIdx;
- }
-
- swapChainD->cbWrapper.cb = frame.cmdBuf;
-
- QVkSwapChain::ImageResources &image(swapChainD->imageRes[swapChainD->currentImageIndex]);
- swapChainD->rtWrapper.d.fb = image.fb;
-
- prepareNewFrame(&swapChainD->cbWrapper);
return QRhi::FrameOpSuccess;
}
@@ -1791,6 +2263,10 @@ QRhi::FrameOpResult QRhiVulkan::endFrame(QRhiSwapChain *swapChain, QRhi::EndFram
QVkSwapChain *swapChainD = QRHI_RES(QVkSwapChain, swapChain);
Q_ASSERT(currentSwapChain == swapChainD);
+ auto cleanup = qScopeGuard([this, swapChainD] {
+ inst->handle()->endFrame(swapChainD->window);
+ });
+
recordPrimaryCommandBuffer(&swapChainD->cbWrapper);
int frameResIndex = swapChainD->bufferCount > 1 ? swapChainD->currentFrameSlot : 0;
@@ -2031,6 +2507,24 @@ QRhi::FrameOpResult QRhiVulkan::beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi
prepareNewFrame(cbWrapper);
ofr.active = true;
+ if (rhiFlags.testFlag(QRhi::EnableTimestamps)) {
+ int timestampQueryIdx = -1;
+ for (int i = 0; i < timestampQueryPoolMap.size(); ++i) {
+ if (!timestampQueryPoolMap.testBit(i)) {
+ timestampQueryPoolMap.setBit(i);
+ timestampQueryIdx = i * 2;
+ break;
+ }
+ }
+ if (timestampQueryIdx >= 0) {
+ df->vkCmdResetQueryPool(cbWrapper->cb, timestampQueryPool, uint32_t(timestampQueryIdx), 2);
+ // record timestamp at the start of the command buffer
+ df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
+ timestampQueryPool, uint32_t(timestampQueryIdx));
+ ofr.timestampQueryIndex = timestampQueryIdx;
+ }
+ }
+
*cb = cbWrapper;
return QRhi::FrameOpSuccess;
}
@@ -2044,6 +2538,12 @@ QRhi::FrameOpResult QRhiVulkan::endOffscreenFrame(QRhi::EndFrameFlags flags)
QVkCommandBuffer *cbWrapper(ofr.cbWrapper[currentFrameSlot]);
recordPrimaryCommandBuffer(cbWrapper);
+ // record another timestamp, when enabled
+ if (ofr.timestampQueryIndex >= 0) {
+ df->vkCmdWriteTimestamp(cbWrapper->cb, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
+ timestampQueryPool, uint32_t(ofr.timestampQueryIndex + 1));
+ }
+
if (!ofr.cmdFence) {
VkFenceCreateInfo fenceInfo = {};
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
@@ -2066,6 +2566,24 @@ QRhi::FrameOpResult QRhiVulkan::endOffscreenFrame(QRhi::EndFrameFlags flags)
// previous) frame is safe since we waited for completion above.
finishActiveReadbacks(true);
+ // Read the timestamps, if we wrote them.
+ if (ofr.timestampQueryIndex >= 0) {
+ quint64 timestamp[2] = { 0, 0 };
+ VkResult err = df->vkGetQueryPoolResults(dev, timestampQueryPool, uint32_t(ofr.timestampQueryIndex), 2,
+ 2 * sizeof(quint64), timestamp, sizeof(quint64),
+ VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
+ timestampQueryPoolMap.clearBit(ofr.timestampQueryIndex / 2);
+ ofr.timestampQueryIndex = -1;
+ if (err == VK_SUCCESS) {
+ bool ok = false;
+ const double elapsedSec = elapsedSecondsFromTimestamp(timestamp, &ok);
+ if (ok)
+ cbWrapper->lastGpuTime = elapsedSec;
+ } else {
+ qWarning("Failed to query timestamp: %d", err);
+ }
+ }
+
return QRhi::FrameOpSuccess;
}
@@ -2183,6 +2701,13 @@ void QRhiVulkan::activateTextureRenderTarget(QVkCommandBuffer *cbD, QVkTextureRe
QRhiPassResourceTracker::TexDepthOutputStage);
depthTexD->lastActiveFrameSlot = currentFrameSlot;
}
+ if (rtD->m_desc.depthResolveTexture()) {
+ QVkTexture *depthResolveTexD = QRHI_RES(QVkTexture, rtD->m_desc.depthResolveTexture());
+ trackedRegisterTexture(&passResTracker, depthResolveTexD,
+ QRhiPassResourceTracker::TexDepthOutput,
+ QRhiPassResourceTracker::TexDepthOutputStage);
+ depthResolveTexD->lastActiveFrameSlot = currentFrameSlot;
+ }
}
void QRhiVulkan::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
@@ -2324,6 +2849,11 @@ void QRhiVulkan::beginPass(QRhiCommandBuffer *cb,
float(colorClearValue.alphaF()) } };
cvs.append(cv);
}
+ for (int i = 0; i < rtD->dsResolveAttCount; ++i) {
+ VkClearValue cv;
+ cv.depthStencil = { depthStencilClearValue.depthClearValue(), depthStencilClearValue.stencilClearValue() };
+ cvs.append(cv);
+ }
rpBeginInfo.clearValueCount = uint32_t(cvs.size());
QVkCommandBuffer::Command &cmd(cbD->commands.get());
@@ -2717,7 +3247,7 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
case QRhiShaderResourceBinding::ImageLoadStore:
{
QVkTexture *texD = QRHI_RES(QVkTexture, b->u.simage.tex);
- VkImageView view = texD->imageViewForLevel(b->u.simage.level);
+ VkImageView view = texD->perLevelImageViewForLoadStore(b->u.simage.level);
if (view) {
writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
bd.simage.id = texD->m_id;
@@ -2971,12 +3501,12 @@ void QRhiVulkan::prepareUploadSubres(QVkTexture *texD, int layer, int level,
const int sy = subresDesc.sourceTopLeft().y();
if (!subresDesc.sourceSize().isEmpty())
size = subresDesc.sourceSize();
- if (image.depth() == 32) {
- // The staging buffer will get the full image
- // regardless, just adjust the vk
- // buffer-to-image copy start offset.
- copyInfo.bufferOffset += VkDeviceSize(sy * image.bytesPerLine() + sx * 4);
- // bufferRowLength remains set to the original image's width
+
+ if (size.width() == image.width()) {
+ // No need to make a QImage copy here, can copy from the source
+ // QImage into staging directly.
+ src = image.constBits() + sy * image.bytesPerLine() + sx * bpc;
+ copySizeBytes = size.height() * image.bytesPerLine();
} else {
image = image.copy(sx, sy, size.width(), size.height());
src = image.constBits();
@@ -3039,6 +3569,12 @@ void QRhiVulkan::prepareUploadSubres(QVkTexture *texD, int layer, int level,
}
}
+void QRhiVulkan::printExtraErrorInfo(VkResult err)
+{
+ if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY)
+ qWarning() << "Out of device memory, current allocator statistics are" << statistics();
+}
+
void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates)
{
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
@@ -3076,6 +3612,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
bufD->stagingAllocations[currentFrameSlot] = allocation;
} else {
qWarning("Failed to create staging buffer of size %u: %d", bufD->m_size, err);
+ printExtraErrorInfo(err);
continue;
}
}
@@ -3164,6 +3701,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
readback.stagingAlloc = allocation;
} else {
qWarning("Failed to create readback buffer of size %u: %d", readback.byteSize, err);
+ printExtraErrorInfo(err);
continue;
}
@@ -3213,6 +3751,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
&utexD->stagingBuffers[currentFrameSlot], &allocation, nullptr);
if (err != VK_SUCCESS) {
qWarning("Failed to create image staging buffer of size %d: %d", int(stagingSize), err);
+ printExtraErrorInfo(err);
continue;
}
utexD->stagingAllocations[currentFrameSlot] = allocation;
@@ -3369,6 +3908,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
readback.stagingAlloc = allocation;
} else {
qWarning("Failed to create readback buffer of size %u: %d", readback.byteSize, err);
+ printExtraErrorInfo(err);
continue;
}
@@ -3434,10 +3974,10 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
if (!origStage)
origStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
- for (int layer = 0; layer < (isCube ? 6 : (isArray ? utexD->m_arraySize : 1)); ++layer) {
+ for (int layer = 0; layer < (isCube ? 6 : (isArray ? qMax(0, utexD->m_arraySize) : 1)); ++layer) {
int w = utexD->m_pixelSize.width();
int h = utexD->m_pixelSize.height();
- int depth = is3D ? utexD->m_depth : 1;
+ int depth = is3D ? qMax(1, utexD->m_depth) : 1;
for (int level = 1; level < int(utexD->mipLevelCount); ++level) {
if (level == 1) {
subresourceBarrier(cbD, utexD->image,
@@ -3616,6 +4156,8 @@ void QRhiVulkan::executeDeferredReleases(bool forced)
df->vkDestroyImageView(dev, e.textureRenderTarget.rtv[att], nullptr);
df->vkDestroyImageView(dev, e.textureRenderTarget.resrtv[att], nullptr);
}
+ df->vkDestroyImageView(dev, e.textureRenderTarget.dsv, nullptr);
+ df->vkDestroyImageView(dev, e.textureRenderTarget.resdsv, nullptr);
break;
case QRhiVulkan::DeferredReleaseEntry::RenderPass:
df->vkDestroyRenderPass(dev, e.renderPass.rp, nullptr);
@@ -3725,18 +4267,12 @@ QList<int> QRhiVulkan::supportedSampleCounts() const
return result;
}
-VkSampleCountFlagBits QRhiVulkan::effectiveSampleCount(int sampleCount)
+VkSampleCountFlagBits QRhiVulkan::effectiveSampleCountBits(int sampleCount)
{
- // Stay compatible with QSurfaceFormat and friends where samples == 0 means the same as 1.
- sampleCount = qBound(1, sampleCount, 64);
-
- if (!supportedSampleCounts().contains(sampleCount)) {
- qWarning("Attempted to set unsupported sample count %d", sampleCount);
- return VK_SAMPLE_COUNT_1_BIT;
- }
+ const int s = effectiveSampleCount(sampleCount);
for (const auto &qvk_sampleCount : qvk_sampleCounts) {
- if (qvk_sampleCount.count == sampleCount)
+ if (qvk_sampleCount.count == s)
return qvk_sampleCount.mask;
}
@@ -4119,6 +4655,14 @@ void QRhiVulkan::recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhi
QRhiSwapChain *QRhiVulkan::createSwapChain()
{
+ if (!vkGetPhysicalDeviceSurfaceCapabilitiesKHR
+ || !vkGetPhysicalDeviceSurfaceFormatsKHR
+ || !vkGetPhysicalDeviceSurfacePresentModesKHR)
+ {
+ qWarning("Physical device surface queries not available");
+ return nullptr;
+ }
+
return new QVkSwapChain(this);
}
@@ -4271,6 +4815,12 @@ bool QRhiVulkan::isFeatureSupported(QRhi::Feature feature) const
return true;
case QRhi::ThreeDimensionalTextureMipmaps:
return true;
+ case QRhi::MultiView:
+ return caps.multiView;
+ case QRhi::TextureViewFormat:
+ return true;
+ case QRhi::ResolveDepthStencil:
+ return caps.renderPass2KHR && caps.depthStencilResolveKHR;
default:
Q_UNREACHABLE_RETURN(false);
}
@@ -4403,6 +4953,7 @@ QByteArray QRhiVulkan::pipelineCacheData()
header.deviceId = physDevProperties.deviceID;
header.dataSize = quint32(dataSize);
header.uuidSize = VK_UUID_SIZE;
+ header.reserved = 0;
memcpy(data.data(), &header, headerSize);
memcpy(data.data() + headerSize, physDevProperties.pipelineCacheUUID, VK_UUID_SIZE);
@@ -5153,6 +5704,12 @@ void QRhiVulkan::endExternal(QRhiCommandBuffer *cb)
cbD->resetCachedState();
}
+double QRhiVulkan::lastCompletedGpuTime(QRhiCommandBuffer *cb)
+{
+ QVkCommandBuffer *cbD = QRHI_RES(QVkCommandBuffer, cb);
+ return cbD->lastGpuTime;
+}
+
void QRhiVulkan::setObjectName(uint64_t object, VkObjectType type, const QByteArray &name, int slot)
{
#ifdef VK_EXT_debug_utils
@@ -5293,6 +5850,22 @@ static inline VkFormat toVkAttributeFormat(QRhiVertexInputAttribute::Format form
return VK_FORMAT_R16G16_SFLOAT;
case QRhiVertexInputAttribute::Half:
return VK_FORMAT_R16_SFLOAT;
+ case QRhiVertexInputAttribute::UShort4:
+ return VK_FORMAT_R16G16B16A16_UINT;
+ case QRhiVertexInputAttribute::UShort3:
+ return VK_FORMAT_R16G16B16_UINT;
+ case QRhiVertexInputAttribute::UShort2:
+ return VK_FORMAT_R16G16_UINT;
+ case QRhiVertexInputAttribute::UShort:
+ return VK_FORMAT_R16_UINT;
+ case QRhiVertexInputAttribute::SShort4:
+ return VK_FORMAT_R16G16B16A16_SINT;
+ case QRhiVertexInputAttribute::SShort3:
+ return VK_FORMAT_R16G16B16_SINT;
+ case QRhiVertexInputAttribute::SShort2:
+ return VK_FORMAT_R16G16_SINT;
+ case QRhiVertexInputAttribute::SShort:
+ return VK_FORMAT_R16_SINT;
default:
Q_UNREACHABLE_RETURN(VK_FORMAT_R32G32B32A32_SFLOAT);
}
@@ -5662,7 +6235,8 @@ bool QVkBuffer::create()
}
if (err != VK_SUCCESS) {
- qWarning("Failed to create buffer: %d", err);
+ qWarning("Failed to create buffer of size %u: %d", nonZeroSize, err);
+ rhiD->printExtraErrorInfo(err);
return false;
}
@@ -5770,7 +6344,7 @@ bool QVkRenderBuffer::create()
return false;
QRHI_RES_RHI(QRhiVulkan);
- samples = rhiD->effectiveSampleCount(m_sampleCount);
+ samples = rhiD->effectiveSampleCountBits(m_sampleCount);
switch (m_type) {
case QRhiRenderBuffer::Color:
@@ -5888,6 +6462,15 @@ bool QVkTexture::prepareCreate(QSize *adjustedSize)
QRHI_RES_RHI(QRhiVulkan);
vkformat = toVkTextureFormat(m_format, m_flags);
+ if (m_writeViewFormat.format != UnknownFormat)
+ viewFormat = toVkTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
+ else
+ viewFormat = vkformat;
+ if (m_readViewFormat.format != UnknownFormat)
+ viewFormatForSampling = toVkTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
+ else
+ viewFormatForSampling = vkformat;
+
VkFormatProperties props;
rhiD->f->vkGetPhysicalDeviceFormatProperties(rhiD->physDev, vkformat, &props);
const bool canSampleOptimal = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
@@ -5911,7 +6494,7 @@ bool QVkTexture::prepareCreate(QSize *adjustedSize)
qWarning("Too many mip levels (%d, max is %d), truncating mip chain", mipLevelCount, maxLevels);
mipLevelCount = maxLevels;
}
- samples = rhiD->effectiveSampleCount(m_sampleCount);
+ samples = rhiD->effectiveSampleCountBits(m_sampleCount);
if (samples > VK_SAMPLE_COUNT_1_BIT) {
if (isCube) {
qWarning("Cubemap texture cannot be multisample");
@@ -5942,12 +6525,10 @@ bool QVkTexture::prepareCreate(QSize *adjustedSize)
qWarning("Texture cannot be both 1D and 3D");
return false;
}
- m_depth = qMax(1, m_depth);
if (m_depth > 1 && !is3D) {
qWarning("Texture cannot have a depth of %d when it is not 3D", m_depth);
return false;
}
- m_arraySize = qMax(0, m_arraySize);
if (m_arraySize > 0 && !isArray) {
qWarning("Texture cannot have an array size of %d when it is not an array", m_arraySize);
return false;
@@ -5985,7 +6566,7 @@ bool QVkTexture::finishCreate()
: (is3D ? VK_IMAGE_VIEW_TYPE_3D
: (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
: (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
- viewInfo.format = vkformat;
+ viewInfo.format = viewFormatForSampling;
viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
@@ -5996,7 +6577,7 @@ bool QVkTexture::finishCreate()
viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_arrayRangeStart);
viewInfo.subresourceRange.layerCount = uint32_t(m_arrayRangeLength);
} else {
- viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? m_arraySize : 1);
+ viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
}
VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo, nullptr, &imageView);
@@ -6050,9 +6631,9 @@ bool QVkTexture::create()
imageInfo.format = vkformat;
imageInfo.extent.width = uint32_t(size.width());
imageInfo.extent.height = uint32_t(size.height());
- imageInfo.extent.depth = is3D ? m_depth : 1;
+ imageInfo.extent.depth = is3D ? qMax(1, m_depth) : 1;
imageInfo.mipLevels = mipLevelCount;
- imageInfo.arrayLayers = isCube ? 6 : (isArray ? m_arraySize : 1);
+ imageInfo.arrayLayers = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
imageInfo.samples = samples;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
@@ -6077,7 +6658,14 @@ bool QVkTexture::create()
VmaAllocation allocation;
VkResult err = vmaCreateImage(toVmaAllocator(rhiD->allocator), &imageInfo, &allocInfo, &image, &allocation, nullptr);
if (err != VK_SUCCESS) {
- qWarning("Failed to create image: %d", err);
+ qWarning("Failed to create image (with VkImageCreateInfo %ux%u depth %u vkformat 0x%X mips %u layers %u vksamples 0x%X): %d",
+ imageInfo.extent.width, imageInfo.extent.height, imageInfo.extent.depth,
+ int(imageInfo.format),
+ imageInfo.mipLevels,
+ imageInfo.arrayLayers,
+ int(imageInfo.samples),
+ err);
+ rhiD->printExtraErrorInfo(err);
return false;
}
imageAlloc = allocation;
@@ -6124,7 +6712,7 @@ void QVkTexture::setNativeLayout(int layout)
usageState.layout = VkImageLayout(layout);
}
-VkImageView QVkTexture::imageViewForLevel(int level)
+VkImageView QVkTexture::perLevelImageViewForLoadStore(int level)
{
Q_ASSERT(level >= 0 && level < int(mipLevelCount));
if (perLevelImageViews[level] != VK_NULL_HANDLE)
@@ -6144,7 +6732,7 @@ VkImageView QVkTexture::imageViewForLevel(int level)
: (is3D ? VK_IMAGE_VIEW_TYPE_3D
: (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
: (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
- viewInfo.format = vkformat;
+ viewInfo.format = viewFormat; // this is writeViewFormat, regardless of Load, Store, or LoadStore; intentional
viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
@@ -6153,7 +6741,7 @@ VkImageView QVkTexture::imageViewForLevel(int level)
viewInfo.subresourceRange.baseMipLevel = uint32_t(level);
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = 0;
- viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? m_arraySize : 1);
+ viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? qMax(0, m_arraySize) : 1);
VkImageView v = VK_NULL_HANDLE;
QRHI_RES_RHI(QRhiVulkan);
@@ -6231,7 +6819,7 @@ bool QVkSampler::create()
QVkRenderPassDescriptor::QVkRenderPassDescriptor(QRhiImplementation *rhi)
: QRhiRenderPassDescriptor(rhi)
{
- serializedFormatData.reserve(32);
+ serializedFormatData.reserve(64);
}
QVkRenderPassDescriptor::~QVkRenderPassDescriptor()
@@ -6294,6 +6882,10 @@ bool QVkRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other
return false;
if (hasDepthStencil != o->hasDepthStencil)
return false;
+ if (hasDepthStencilResolve != o->hasDepthStencilResolve)
+ return false;
+ if (multiViewCount != o->multiViewCount)
+ return false;
for (int i = 0, ie = colorRefs.size(); i != ie; ++i) {
const uint32_t attIdx = colorRefs[i].attachment;
@@ -6319,6 +6911,14 @@ bool QVkRenderPassDescriptor::isCompatible(const QRhiRenderPassDescriptor *other
return false;
}
+ if (hasDepthStencilResolve) {
+ const uint32_t attIdx = dsResolveRef.attachment;
+ if (attIdx != o->dsResolveRef.attachment)
+ return false;
+ if (attIdx != VK_ATTACHMENT_UNUSED && !attachmentDescriptionEquals(attDescs[attIdx], o->attDescs[attIdx]))
+ return false;
+ }
+
// subpassDeps is not included
return true;
@@ -6333,6 +6933,8 @@ void QVkRenderPassDescriptor::updateSerializedFormat()
*p++ = colorRefs.size();
*p++ = resolveRefs.size();
*p++ = hasDepthStencil;
+ *p++ = hasDepthStencilResolve;
+ *p++ = multiViewCount;
auto serializeAttachmentData = [this, &p](uint32_t attIdx) {
const bool used = attIdx != VK_ATTACHMENT_UNUSED;
@@ -6364,6 +6966,12 @@ void QVkRenderPassDescriptor::updateSerializedFormat()
*p++ = attIdx;
serializeAttachmentData(attIdx);
}
+
+ if (hasDepthStencilResolve) {
+ const uint32_t attIdx = dsResolveRef.attachment;
+ *p++ = attIdx;
+ serializeAttachmentData(attIdx);
+ }
}
QRhiRenderPassDescriptor *QVkRenderPassDescriptor::newCompatibleRenderPassDescriptor() const
@@ -6376,13 +6984,22 @@ QRhiRenderPassDescriptor *QVkRenderPassDescriptor::newCompatibleRenderPassDescri
rpD->resolveRefs = resolveRefs;
rpD->subpassDeps = subpassDeps;
rpD->hasDepthStencil = hasDepthStencil;
+ rpD->hasDepthStencilResolve = hasDepthStencilResolve;
+ rpD->multiViewCount = multiViewCount;
rpD->dsRef = dsRef;
+ rpD->dsResolveRef = dsResolveRef;
VkRenderPassCreateInfo rpInfo;
VkSubpassDescription subpassDesc;
fillRenderPassCreateInfo(&rpInfo, &subpassDesc, rpD);
QRHI_RES_RHI(QRhiVulkan);
+ MultiViewRenderPassSetupHelper multiViewHelper;
+ if (!multiViewHelper.prepare(&rpInfo, multiViewCount, rhiD->caps.multiView)) {
+ delete rpD;
+ return nullptr;
+ }
+
VkResult err = rhiD->df->vkCreateRenderPass(rhiD->dev, &rpInfo, nullptr, &rpD->rp);
if (err != VK_SUCCESS) {
qWarning("Failed to create renderpass: %d", err);
@@ -6471,6 +7088,11 @@ void QVkTextureRenderTarget::destroy()
resrtv[att] = VK_NULL_HANDLE;
}
+ e.textureRenderTarget.dsv = dsv;
+ dsv = VK_NULL_HANDLE;
+ e.textureRenderTarget.resdsv = resdsv;
+ resdsv = VK_NULL_HANDLE;
+
QRHI_RES_RHI(QRhiVulkan);
if (rhiD) {
rhiD->releaseQueue.append(e);
@@ -6489,8 +7111,10 @@ QRhiRenderPassDescriptor *QVkTextureRenderTarget::newCompatibleRenderPassDescrip
m_desc.cendColorAttachments(),
m_flags.testFlag(QRhiTextureRenderTarget::PreserveColorContents),
m_flags.testFlag(QRhiTextureRenderTarget::PreserveDepthStencilContents),
+ m_desc.depthTexture() && !m_flags.testFlag(DoNotStoreDepthStencilContents) && !m_desc.depthResolveTexture(),
m_desc.depthStencilBuffer(),
- m_desc.depthTexture()))
+ m_desc.depthTexture(),
+ m_desc.depthResolveTexture()))
{
delete rp;
return nullptr;
@@ -6513,6 +7137,7 @@ bool QVkTextureRenderTarget::create()
QRHI_RES_RHI(QRhiVulkan);
QVarLengthArray<VkImageView, 8> views;
+ d.multiViewCount = 0;
d.colorAttCount = 0;
int attIndex = 0;
@@ -6523,13 +7148,17 @@ bool QVkTextureRenderTarget::create()
Q_ASSERT(texD || rbD);
if (texD) {
Q_ASSERT(texD->flags().testFlag(QRhiTexture::RenderTarget));
+ const bool is1D = texD->flags().testFlag(QRhiTexture::OneDimensional);
+ const bool isMultiView = it->multiViewCount() >= 2;
+ if (isMultiView && d.multiViewCount == 0)
+ d.multiViewCount = it->multiViewCount();
VkImageViewCreateInfo viewInfo = {};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = texD->image;
- viewInfo.viewType = texD->flags().testFlag(QRhiTexture::OneDimensional)
- ? VK_IMAGE_VIEW_TYPE_1D
- : VK_IMAGE_VIEW_TYPE_2D;
- viewInfo.format = texD->vkformat;
+ viewInfo.viewType = is1D ? VK_IMAGE_VIEW_TYPE_1D
+ : (isMultiView ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
+ : VK_IMAGE_VIEW_TYPE_2D);
+ viewInfo.format = texD->viewFormat;
viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
@@ -6538,7 +7167,7 @@ bool QVkTextureRenderTarget::create()
viewInfo.subresourceRange.baseMipLevel = uint32_t(it->level());
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->layer());
- viewInfo.subresourceRange.layerCount = 1;
+ viewInfo.subresourceRange.layerCount = uint32_t(isMultiView ? it->multiViewCount() : 1);
VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo, nullptr, &rtv[attIndex]);
if (err != VK_SUCCESS) {
qWarning("Failed to create render target image view: %d", err);
@@ -6563,7 +7192,25 @@ bool QVkTextureRenderTarget::create()
if (hasDepthStencil) {
if (m_desc.depthTexture()) {
QVkTexture *depthTexD = QRHI_RES(QVkTexture, m_desc.depthTexture());
- views.append(depthTexD->imageView);
+ // need a dedicated view just because viewFormat may differ from vkformat
+ VkImageViewCreateInfo viewInfo = {};
+ viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ viewInfo.image = depthTexD->image;
+ viewInfo.viewType = d.multiViewCount > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.format = depthTexD->viewFormat;
+ viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
+ viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
+ viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
+ viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
+ viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
+ viewInfo.subresourceRange.levelCount = 1;
+ viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
+ VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo, nullptr, &dsv);
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to create depth-stencil image view for rt: %d", err);
+ return false;
+ }
+ views.append(dsv);
if (d.colorAttCount == 0) {
d.pixelSize = depthTexD->pixelSize();
d.sampleCount = depthTexD->samples;
@@ -6583,6 +7230,7 @@ bool QVkTextureRenderTarget::create()
d.resolveAttCount = 0;
attIndex = 0;
+ Q_ASSERT(d.multiViewCount == 0 || d.multiViewCount >= 2);
for (auto it = m_desc.cbeginColorAttachments(), itEnd = m_desc.cendColorAttachments(); it != itEnd; ++it, ++attIndex) {
if (it->resolveTexture()) {
QVkTexture *resTexD = QRHI_RES(QVkTexture, it->resolveTexture());
@@ -6592,8 +7240,9 @@ bool QVkTextureRenderTarget::create()
VkImageViewCreateInfo viewInfo = {};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewInfo.image = resTexD->image;
- viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
- viewInfo.format = resTexD->vkformat;
+ viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
+ : VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.format = resTexD->viewFormat;
viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
@@ -6602,7 +7251,7 @@ bool QVkTextureRenderTarget::create()
viewInfo.subresourceRange.baseMipLevel = uint32_t(it->resolveLevel());
viewInfo.subresourceRange.levelCount = 1;
viewInfo.subresourceRange.baseArrayLayer = uint32_t(it->resolveLayer());
- viewInfo.subresourceRange.layerCount = 1;
+ viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo, nullptr, &resrtv[attIndex]);
if (err != VK_SUCCESS) {
qWarning("Failed to create render target resolve image view: %d", err);
@@ -6612,6 +7261,36 @@ bool QVkTextureRenderTarget::create()
}
}
+ if (m_desc.depthResolveTexture()) {
+ QVkTexture *resTexD = QRHI_RES(QVkTexture, m_desc.depthResolveTexture());
+ Q_ASSERT(resTexD->flags().testFlag(QRhiTexture::RenderTarget));
+
+ VkImageViewCreateInfo viewInfo = {};
+ viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ viewInfo.image = resTexD->image;
+ viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
+ : VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.format = resTexD->viewFormat;
+ viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
+ viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
+ viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
+ viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
+ viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
+ viewInfo.subresourceRange.baseMipLevel = 0;
+ viewInfo.subresourceRange.levelCount = 1;
+ viewInfo.subresourceRange.baseArrayLayer = 0;
+ viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
+ VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo, nullptr, &resdsv);
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to create render target depth resolve image view: %d", err);
+ return false;
+ }
+ views.append(resdsv);
+ d.dsResolveAttCount = 1;
+ } else {
+ d.dsResolveAttCount = 0;
+ }
+
if (!m_renderPassDesc)
qWarning("QVkTextureRenderTarget: No renderpass descriptor set. See newCompatibleRenderPassDescriptor() and setRenderPassDescriptor().");
@@ -6621,7 +7300,7 @@ bool QVkTextureRenderTarget::create()
VkFramebufferCreateInfo fbInfo = {};
fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
fbInfo.renderPass = d.rp->rp;
- fbInfo.attachmentCount = uint32_t(d.colorAttCount + d.dsAttCount + d.resolveAttCount);
+ fbInfo.attachmentCount = uint32_t(d.colorAttCount + d.dsAttCount + d.resolveAttCount + d.dsResolveAttCount);
fbInfo.pAttachments = views.constData();
fbInfo.width = uint32_t(d.pixelSize.width());
fbInfo.height = uint32_t(d.pixelSize.height());
@@ -6880,7 +7559,9 @@ bool QVkGraphicsPipeline::create()
pipelineInfo.pStages = shaderStageCreateInfos.constData();
QVarLengthArray<VkVertexInputBindingDescription, 4> vertexBindings;
+#ifdef VK_EXT_vertex_attribute_divisor
QVarLengthArray<VkVertexInputBindingDivisorDescriptionEXT> nonOneStepRates;
+#endif
int bindingIndex = 0;
for (auto it = m_vertexInputLayout.cbeginBindings(), itEnd = m_vertexInputLayout.cendBindings();
it != itEnd; ++it, ++bindingIndex)
@@ -6892,9 +7573,12 @@ bool QVkGraphicsPipeline::create()
? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE
};
if (it->classification() == QRhiVertexInputBinding::PerInstance && it->instanceStepRate() != 1) {
+#ifdef VK_EXT_vertex_attribute_divisor
if (rhiD->caps.vertexAttribDivisor) {
nonOneStepRates.append({ uint32_t(bindingIndex), it->instanceStepRate() });
- } else {
+ } else
+#endif
+ {
qWarning("QRhiVulkan: Instance step rates other than 1 not supported without "
"VK_EXT_vertex_attribute_divisor on the device and "
"VK_KHR_get_physical_device_properties2 on the instance");
@@ -6920,13 +7604,15 @@ bool QVkGraphicsPipeline::create()
vertexInputInfo.pVertexBindingDescriptions = vertexBindings.constData();
vertexInputInfo.vertexAttributeDescriptionCount = uint32_t(vertexAttributes.size());
vertexInputInfo.pVertexAttributeDescriptions = vertexAttributes.constData();
+#ifdef VK_EXT_vertex_attribute_divisor
VkPipelineVertexInputDivisorStateCreateInfoEXT divisorInfo = {};
if (!nonOneStepRates.isEmpty()) {
- divisorInfo.sType = VkStructureType(1000190001); // VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT
+ divisorInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
divisorInfo.vertexBindingDivisorCount = uint32_t(nonOneStepRates.size());
divisorInfo.pVertexBindingDivisors = nonOneStepRates.constData();
vertexInputInfo.pNext = &divisorInfo;
}
+#endif
pipelineInfo.pVertexInputState = &vertexInputInfo;
QVarLengthArray<VkDynamicState, 8> dynEnable;
@@ -6997,7 +7683,7 @@ bool QVkGraphicsPipeline::create()
VkPipelineMultisampleStateCreateInfo msInfo = {};
msInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
- msInfo.rasterizationSamples = rhiD->effectiveSampleCount(m_sampleCount);
+ msInfo.rasterizationSamples = rhiD->effectiveSampleCountBits(m_sampleCount);
pipelineInfo.pMultisampleState = &msInfo;
VkPipelineDepthStencilStateCreateInfo dsInfo = {};
@@ -7196,6 +7882,7 @@ const QRhiNativeHandles *QVkCommandBuffer::nativeHandles()
QVkSwapChain::QVkSwapChain(QRhiImplementation *rhi)
: QRhiSwapChain(rhi),
rtWrapper(rhi, this),
+ rtWrapperRight(rhi, this),
cbWrapper(rhi)
{
}
@@ -7238,6 +7925,11 @@ QRhiRenderTarget *QVkSwapChain::currentFrameRenderTarget()
return &rtWrapper;
}
+QRhiRenderTarget *QVkSwapChain::currentFrameRenderTarget(StereoTargetBuffer targetBuffer)
+{
+ return !stereo || targetBuffer == StereoTargetBuffer::LeftBuffer ? &rtWrapper : &rtWrapperRight;
+}
+
QSize QVkSwapChain::surfacePixelSize()
{
if (!ensureSurface())
@@ -7265,6 +7957,9 @@ static inline bool hdrFormatMatchesVkSurfaceFormat(QRhiSwapChain::Format f, cons
case QRhiSwapChain::HDR10:
return (s.format == VK_FORMAT_A2B10G10R10_UNORM_PACK32 || s.format == VK_FORMAT_A2R10G10B10_UNORM_PACK32)
&& s.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT;
+ case QRhiSwapChain::HDRExtendedDisplayP3Linear:
+ return s.format == VK_FORMAT_R16G16B16A16_SFLOAT
+ && s.colorSpace == VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT;
default:
break;
}
@@ -7374,11 +8069,9 @@ bool QVkSwapChain::ensureSurface()
const bool srgbRequested = m_flags.testFlag(sRGB);
for (int i = 0; i < int(formatCount); ++i) {
if (formats[i].format != VK_FORMAT_UNDEFINED) {
- bool ok = false;
- if (m_format == SDR)
- ok = srgbRequested == isSrgbFormat(formats[i].format);
- else
- ok = hdrFormatMatchesVkSurfaceFormat(m_format, formats[i]);
+ bool ok = srgbRequested == isSrgbFormat(formats[i].format);
+ if (m_format != SDR)
+ ok &= hdrFormatMatchesVkSurfaceFormat(m_format, formats[i]);
if (ok) {
colorFormat = formats[i].format;
colorSpace = formats[i].colorSpace;
@@ -7387,7 +8080,7 @@ bool QVkSwapChain::ensureSurface()
}
}
- samples = rhiD->effectiveSampleCount(m_sampleCount);
+ samples = rhiD->effectiveSampleCountBits(m_sampleCount);
quint32 presModeCount = 0;
rhiD->vkGetPhysicalDeviceSurfacePresentModesKHR(rhiD->physDev, surface, &presModeCount, nullptr);
@@ -7458,6 +8151,7 @@ bool QVkSwapChain::createOrResize()
rtWrapper.d.dsAttCount = 0;
ds = nullptr;
}
+ rtWrapper.d.dsResolveAttCount = 0;
if (samples > VK_SAMPLE_COUNT_1_BIT)
rtWrapper.d.resolveAttCount = 1;
else
@@ -7474,7 +8168,7 @@ bool QVkSwapChain::createOrResize()
VkFramebufferCreateInfo fbInfo = {};
fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
fbInfo.renderPass = rtWrapper.d.rp->rp;
- fbInfo.attachmentCount = uint32_t(rtWrapper.d.colorAttCount + rtWrapper.d.dsAttCount + rtWrapper.d.resolveAttCount);
+ fbInfo.attachmentCount = uint32_t(rtWrapper.d.colorAttCount + rtWrapper.d.dsAttCount + rtWrapper.d.resolveAttCount + rtWrapper.d.dsResolveAttCount);
fbInfo.pAttachments = views;
fbInfo.width = uint32_t(pixelSize.width());
fbInfo.height = uint32_t(pixelSize.height());
@@ -7487,6 +8181,56 @@ bool QVkSwapChain::createOrResize()
}
}
+ if (stereo) {
+ rtWrapperRight.setRenderPassDescriptor(
+ m_renderPassDesc); // for the public getter in QRhiRenderTarget
+ rtWrapperRight.d.rp = QRHI_RES(QVkRenderPassDescriptor, m_renderPassDesc);
+ Q_ASSERT(rtWrapperRight.d.rp && rtWrapperRight.d.rp->rp);
+
+ rtWrapperRight.d.pixelSize = pixelSize;
+ rtWrapperRight.d.dpr = float(window->devicePixelRatio());
+ rtWrapperRight.d.sampleCount = samples;
+ rtWrapperRight.d.colorAttCount = 1;
+ if (m_depthStencil) {
+ rtWrapperRight.d.dsAttCount = 1;
+ ds = QRHI_RES(QVkRenderBuffer, m_depthStencil);
+ } else {
+ rtWrapperRight.d.dsAttCount = 0;
+ ds = nullptr;
+ }
+ rtWrapperRight.d.dsResolveAttCount = 0;
+ if (samples > VK_SAMPLE_COUNT_1_BIT)
+ rtWrapperRight.d.resolveAttCount = 1;
+ else
+ rtWrapperRight.d.resolveAttCount = 0;
+
+ for (int i = 0; i < bufferCount; ++i) {
+ QVkSwapChain::ImageResources &image(imageRes[i + bufferCount]);
+ VkImageView views[3] = {
+ // color, ds, resolve
+ samples > VK_SAMPLE_COUNT_1_BIT ? image.msaaImageView : image.imageView,
+ ds ? ds->imageView : VK_NULL_HANDLE,
+ samples > VK_SAMPLE_COUNT_1_BIT ? image.imageView : VK_NULL_HANDLE
+ };
+
+ VkFramebufferCreateInfo fbInfo = {};
+ fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+ fbInfo.renderPass = rtWrapperRight.d.rp->rp;
+ fbInfo.attachmentCount = uint32_t(rtWrapperRight.d.colorAttCount + rtWrapperRight.d.dsAttCount
+ + rtWrapperRight.d.resolveAttCount + rtWrapperRight.d.dsResolveAttCount);
+ fbInfo.pAttachments = views;
+ fbInfo.width = uint32_t(pixelSize.width());
+ fbInfo.height = uint32_t(pixelSize.height());
+ fbInfo.layers = 1;
+
+ VkResult err = rhiD->df->vkCreateFramebuffer(rhiD->dev, &fbInfo, nullptr, &image.fb);
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to create framebuffer: %d", err);
+ return false;
+ }
+ }
+ }
+
frameCount = 0;
if (needsRegistration)
diff --git a/src/gui/rhi/qrhivulkan_p.h b/src/gui/rhi/qrhivulkan_p.h
index f592cf7e54..f23d8550f0 100644
--- a/src/gui/rhi/qrhivulkan_p.h
+++ b/src/gui/rhi/qrhivulkan_p.h
@@ -1,8 +1,8 @@
-// Copyright (C) 2019 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QRHIVULKAN_H
-#define QRHIVULKAN_H
+#ifndef QRHIVULKAN_P_H
+#define QRHIVULKAN_P_H
//
// W A R N I N G
@@ -15,44 +15,1025 @@
// We mean it.
//
-#include <private/qrhi_p.h>
-#include <QtGui/qvulkaninstance.h> // this is where vulkan.h gets pulled in
+#include "qrhi_p.h"
QT_BEGIN_NAMESPACE
-struct Q_GUI_EXPORT QRhiVulkanInitParams : public QRhiInitParams
+class QVulkanFunctions;
+class QVulkanDeviceFunctions;
+
+static const int QVK_FRAMES_IN_FLIGHT = 2;
+
+static const int QVK_DESC_SETS_PER_POOL = 128;
+static const int QVK_UNIFORM_BUFFERS_PER_POOL = 256;
+static const int QVK_COMBINED_IMAGE_SAMPLERS_PER_POOL = 256;
+static const int QVK_STORAGE_BUFFERS_PER_POOL = 128;
+static const int QVK_STORAGE_IMAGES_PER_POOL = 128;
+
+static const int QVK_MAX_ACTIVE_TIMESTAMP_PAIRS = 16;
+
+// no vk_mem_alloc.h available here, void* is good enough
+typedef void * QVkAlloc;
+typedef void * QVkAllocator;
+
+struct QVkBuffer : public QRhiBuffer
{
- QVulkanInstance *inst = nullptr;
+ QVkBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
+ ~QVkBuffer();
+ void destroy() override;
+ bool create() override;
+ QRhiBuffer::NativeBuffer nativeBuffer() override;
+ char *beginFullDynamicBufferUpdateForCurrentFrame() override;
+ void endFullDynamicBufferUpdateForCurrentFrame() override;
+
+ VkBuffer buffers[QVK_FRAMES_IN_FLIGHT];
+ QVkAlloc allocations[QVK_FRAMES_IN_FLIGHT];
+ struct DynamicUpdate {
+ quint32 offset;
+ QRhiBufferData data;
+ };
+ QVarLengthArray<DynamicUpdate, 16> pendingDynamicUpdates[QVK_FRAMES_IN_FLIGHT];
+ VkBuffer stagingBuffers[QVK_FRAMES_IN_FLIGHT];
+ QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT];
+ struct UsageState {
+ VkAccessFlags access = 0;
+ VkPipelineStageFlags stage = 0;
+ };
+ UsageState usageState[QVK_FRAMES_IN_FLIGHT];
+ int lastActiveFrameSlot = -1;
+ uint generation = 0;
+ friend class QRhiVulkan;
+};
+
+Q_DECLARE_TYPEINFO(QVkBuffer::DynamicUpdate, Q_RELOCATABLE_TYPE);
+
+struct QVkTexture;
+
+struct QVkRenderBuffer : public QRhiRenderBuffer
+{
+ QVkRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
+ int sampleCount, Flags flags,
+ QRhiTexture::Format backingFormatHint);
+ ~QVkRenderBuffer();
+ void destroy() override;
+ bool create() override;
+ QRhiTexture::Format backingFormat() const override;
+
+ VkDeviceMemory memory = VK_NULL_HANDLE;
+ VkImage image = VK_NULL_HANDLE;
+ VkImageView imageView = VK_NULL_HANDLE;
+ VkSampleCountFlagBits samples;
+ QVkTexture *backingTexture = nullptr;
+ VkFormat vkformat;
+ int lastActiveFrameSlot = -1;
+ uint generation = 0;
+ friend class QRhiVulkan;
+};
+
+struct QVkTexture : public QRhiTexture
+{
+ QVkTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
+ int arraySize, int sampleCount, Flags flags);
+ ~QVkTexture();
+ void destroy() override;
+ bool create() override;
+ bool createFrom(NativeTexture src) override;
+ NativeTexture nativeTexture() override;
+ void setNativeLayout(int layout) override;
+
+ bool prepareCreate(QSize *adjustedSize = nullptr);
+ bool finishCreate();
+ VkImageView perLevelImageViewForLoadStore(int level);
+
+ VkImage image = VK_NULL_HANDLE;
+ VkImageView imageView = VK_NULL_HANDLE;
+ QVkAlloc imageAlloc = nullptr;
+ VkBuffer stagingBuffers[QVK_FRAMES_IN_FLIGHT];
+ QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT];
+ VkImageView perLevelImageViews[QRhi::MAX_MIP_LEVELS];
+ bool owns = true;
+ struct UsageState {
+ // no tracking of subresource layouts (some operations can keep
+ // subresources in different layouts for some time, but that does not
+ // need to be kept track of)
+ VkImageLayout layout;
+ VkAccessFlags access;
+ VkPipelineStageFlags stage;
+ };
+ UsageState usageState;
+ VkFormat vkformat;
+ uint mipLevelCount = 0;
+ VkSampleCountFlagBits samples;
+ VkFormat viewFormat;
+ VkFormat viewFormatForSampling;
+ int lastActiveFrameSlot = -1;
+ uint generation = 0;
+ friend class QRhiVulkan;
+};
+
+struct QVkSampler : public QRhiSampler
+{
+ QVkSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
+ AddressMode u, AddressMode v, AddressMode w);
+ ~QVkSampler();
+ void destroy() override;
+ bool create() override;
+
+ VkSampler sampler = VK_NULL_HANDLE;
+ int lastActiveFrameSlot = -1;
+ uint generation = 0;
+ friend class QRhiVulkan;
+};
+
+struct QVkRenderPassDescriptor : public QRhiRenderPassDescriptor
+{
+ QVkRenderPassDescriptor(QRhiImplementation *rhi);
+ ~QVkRenderPassDescriptor();
+ void destroy() override;
+ bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
+ QVector<quint32> serializedFormat() const override;
+ const QRhiNativeHandles *nativeHandles() override;
+
+ void updateSerializedFormat();
+
+ VkRenderPass rp = VK_NULL_HANDLE;
+ bool ownsRp = false;
+ QVarLengthArray<VkAttachmentDescription, 8> attDescs;
+ QVarLengthArray<VkAttachmentReference, 8> colorRefs;
+ QVarLengthArray<VkAttachmentReference, 8> resolveRefs;
+ QVarLengthArray<VkSubpassDependency, 2> subpassDeps;
+ bool hasDepthStencil = false;
+ bool hasDepthStencilResolve = false;
+ uint32_t multiViewCount = 0;
+ VkAttachmentReference dsRef;
+ VkAttachmentReference dsResolveRef;
+ QVector<quint32> serializedFormatData;
+ QRhiVulkanRenderPassNativeHandles nativeHandlesStruct;
+ int lastActiveFrameSlot = -1;
+};
+
+struct QVkRenderTargetData
+{
+ VkFramebuffer fb = VK_NULL_HANDLE;
+ QVkRenderPassDescriptor *rp = nullptr;
+ QSize pixelSize;
+ float dpr = 1;
+ int sampleCount = 1;
+ int colorAttCount = 0;
+ int dsAttCount = 0;
+ int resolveAttCount = 0;
+ int dsResolveAttCount = 0;
+ int multiViewCount = 0;
+ QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList;
+ static const int MAX_COLOR_ATTACHMENTS = 8;
+};
+
+struct QVkSwapChainRenderTarget : public QRhiSwapChainRenderTarget
+{
+ QVkSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
+ ~QVkSwapChainRenderTarget();
+ void destroy() override;
+
+ QSize pixelSize() const override;
+ float devicePixelRatio() const override;
+ int sampleCount() const override;
+
+ QVkRenderTargetData d;
+};
+
+struct QVkTextureRenderTarget : public QRhiTextureRenderTarget
+{
+ QVkTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags);
+ ~QVkTextureRenderTarget();
+ void destroy() override;
+
+ QSize pixelSize() const override;
+ float devicePixelRatio() const override;
+ int sampleCount() const override;
+
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
+ bool create() override;
+
+ QVkRenderTargetData d;
+ VkImageView rtv[QVkRenderTargetData::MAX_COLOR_ATTACHMENTS];
+ VkImageView dsv = VK_NULL_HANDLE;
+ VkImageView resrtv[QVkRenderTargetData::MAX_COLOR_ATTACHMENTS];
+ VkImageView resdsv = VK_NULL_HANDLE;
+ int lastActiveFrameSlot = -1;
+ friend class QRhiVulkan;
+};
+
+struct QVkShaderResourceBindings : public QRhiShaderResourceBindings
+{
+ QVkShaderResourceBindings(QRhiImplementation *rhi);
+ ~QVkShaderResourceBindings();
+ void destroy() override;
+ bool create() override;
+ void updateResources(UpdateFlags flags) override;
+
+ QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
+ bool hasSlottedResource = false;
+ bool hasDynamicOffset = false;
+ int poolIndex = -1;
+ VkDescriptorSetLayout layout = VK_NULL_HANDLE;
+ VkDescriptorSet descSets[QVK_FRAMES_IN_FLIGHT]; // multiple sets to support dynamic buffers
+ int lastActiveFrameSlot = -1;
+ uint generation = 0;
+
+ // Keep track of the generation number of each referenced QRhi* to be able
+ // to detect that the underlying descriptor set became out of date and they
+ // need to be written again with the up-to-date VkBuffer etc. objects.
+ struct BoundUniformBufferData {
+ quint64 id;
+ uint generation;
+ };
+ struct BoundSampledTextureData {
+ int count;
+ struct {
+ quint64 texId;
+ uint texGeneration;
+ quint64 samplerId;
+ uint samplerGeneration;
+ } d[QRhiShaderResourceBinding::Data::MAX_TEX_SAMPLER_ARRAY_SIZE];
+ };
+ struct BoundStorageImageData {
+ quint64 id;
+ uint generation;
+ };
+ struct BoundStorageBufferData {
+ quint64 id;
+ uint generation;
+ };
+ struct BoundResourceData {
+ union {
+ BoundUniformBufferData ubuf;
+ BoundSampledTextureData stex;
+ BoundStorageImageData simage;
+ BoundStorageBufferData sbuf;
+ };
+ };
+ QVarLengthArray<BoundResourceData, 8> boundResourceData[QVK_FRAMES_IN_FLIGHT];
+
+ friend class QRhiVulkan;
+};
+
+Q_DECLARE_TYPEINFO(QVkShaderResourceBindings::BoundResourceData, Q_RELOCATABLE_TYPE);
+
+struct QVkGraphicsPipeline : public QRhiGraphicsPipeline
+{
+ QVkGraphicsPipeline(QRhiImplementation *rhi);
+ ~QVkGraphicsPipeline();
+ void destroy() override;
+ bool create() override;
+
+ VkPipelineLayout layout = VK_NULL_HANDLE;
+ VkPipeline pipeline = VK_NULL_HANDLE;
+ int lastActiveFrameSlot = -1;
+ uint generation = 0;
+ friend class QRhiVulkan;
+};
+
+struct QVkComputePipeline : public QRhiComputePipeline
+{
+ QVkComputePipeline(QRhiImplementation *rhi);
+ ~QVkComputePipeline();
+ void destroy() override;
+ bool create() override;
+
+ VkPipelineLayout layout = VK_NULL_HANDLE;
+ VkPipeline pipeline = VK_NULL_HANDLE;
+ int lastActiveFrameSlot = -1;
+ uint generation = 0;
+ friend class QRhiVulkan;
+};
+
+struct QVkCommandBuffer : public QRhiCommandBuffer
+{
+ QVkCommandBuffer(QRhiImplementation *rhi);
+ ~QVkCommandBuffer();
+ void destroy() override;
+
+ const QRhiNativeHandles *nativeHandles();
+
+ VkCommandBuffer cb = VK_NULL_HANDLE; // primary
+ QRhiVulkanCommandBufferNativeHandles nativeHandlesStruct;
+
+ enum PassType {
+ NoPass,
+ RenderPass,
+ ComputePass
+ };
+
+ void resetState() {
+ recordingPass = NoPass;
+ passUsesSecondaryCb = false;
+ lastGpuTime = 0;
+ currentTarget = nullptr;
+ activeSecondaryCbStack.clear();
+ resetCommands();
+ resetCachedState();
+ }
+
+ void resetCachedState() {
+ currentGraphicsPipeline = nullptr;
+ currentComputePipeline = nullptr;
+ currentPipelineGeneration = 0;
+ currentGraphicsSrb = nullptr;
+ currentComputeSrb = nullptr;
+ currentSrbGeneration = 0;
+ currentDescSetSlot = -1;
+ currentIndexBuffer = VK_NULL_HANDLE;
+ currentIndexOffset = 0;
+ currentIndexFormat = VK_INDEX_TYPE_UINT16;
+ memset(currentVertexBuffers, 0, sizeof(currentVertexBuffers));
+ memset(currentVertexOffsets, 0, sizeof(currentVertexOffsets));
+ inExternal = false;
+ }
+
+ PassType recordingPass;
+ bool passUsesSecondaryCb;
+ double lastGpuTime = 0;
+ QRhiRenderTarget *currentTarget;
+ QRhiGraphicsPipeline *currentGraphicsPipeline;
+ QRhiComputePipeline *currentComputePipeline;
+ uint currentPipelineGeneration;
+ QRhiShaderResourceBindings *currentGraphicsSrb;
+ QRhiShaderResourceBindings *currentComputeSrb;
+ uint currentSrbGeneration;
+ int currentDescSetSlot;
+ VkBuffer currentIndexBuffer;
+ quint32 currentIndexOffset;
+ VkIndexType currentIndexFormat;
+ static const int VERTEX_INPUT_RESOURCE_SLOT_COUNT = 32;
+ VkBuffer currentVertexBuffers[VERTEX_INPUT_RESOURCE_SLOT_COUNT];
+ quint32 currentVertexOffsets[VERTEX_INPUT_RESOURCE_SLOT_COUNT];
+ QVarLengthArray<VkCommandBuffer, 4> activeSecondaryCbStack;
+ bool inExternal;
+
+ struct {
+ QHash<QRhiResource *, QPair<VkAccessFlags, bool> > writtenResources;
+ void reset() {
+ writtenResources.clear();
+ }
+ } computePassState;
+
+ struct Command {
+ enum Cmd {
+ CopyBuffer,
+ CopyBufferToImage,
+ CopyImage,
+ CopyImageToBuffer,
+ ImageBarrier,
+ BufferBarrier,
+ BlitImage,
+ BeginRenderPass,
+ EndRenderPass,
+ BindPipeline,
+ BindDescriptorSet,
+ BindVertexBuffer,
+ BindIndexBuffer,
+ SetViewport,
+ SetScissor,
+ SetBlendConstants,
+ SetStencilRef,
+ Draw,
+ DrawIndexed,
+ DebugMarkerBegin,
+ DebugMarkerEnd,
+ DebugMarkerInsert,
+ TransitionPassResources,
+ Dispatch,
+ ExecuteSecondary
+ };
+ Cmd cmd;
+
+ union Args {
+ struct {
+ VkBuffer src;
+ VkBuffer dst;
+ VkBufferCopy desc;
+ } copyBuffer;
+ struct {
+ VkBuffer src;
+ VkImage dst;
+ VkImageLayout dstLayout;
+ int count;
+ int bufferImageCopyIndex;
+ } copyBufferToImage;
+ struct {
+ VkImage src;
+ VkImageLayout srcLayout;
+ VkImage dst;
+ VkImageLayout dstLayout;
+ VkImageCopy desc;
+ } copyImage;
+ struct {
+ VkImage src;
+ VkImageLayout srcLayout;
+ VkBuffer dst;
+ VkBufferImageCopy desc;
+ } copyImageToBuffer;
+ struct {
+ VkPipelineStageFlags srcStageMask;
+ VkPipelineStageFlags dstStageMask;
+ int count;
+ int index;
+ } imageBarrier;
+ struct {
+ VkPipelineStageFlags srcStageMask;
+ VkPipelineStageFlags dstStageMask;
+ int count;
+ int index;
+ } bufferBarrier;
+ struct {
+ VkImage src;
+ VkImageLayout srcLayout;
+ VkImage dst;
+ VkImageLayout dstLayout;
+ VkFilter filter;
+ VkImageBlit desc;
+ } blitImage;
+ struct {
+ VkRenderPassBeginInfo desc;
+ int clearValueIndex;
+ bool useSecondaryCb;
+ } beginRenderPass;
+ struct {
+ } endRenderPass;
+ struct {
+ VkPipelineBindPoint bindPoint;
+ VkPipeline pipeline;
+ } bindPipeline;
+ struct {
+ VkPipelineBindPoint bindPoint;
+ VkPipelineLayout pipelineLayout;
+ VkDescriptorSet descSet;
+ int dynamicOffsetCount;
+ int dynamicOffsetIndex;
+ } bindDescriptorSet;
+ struct {
+ int startBinding;
+ int count;
+ int vertexBufferIndex;
+ int vertexBufferOffsetIndex;
+ } bindVertexBuffer;
+ struct {
+ VkBuffer buf;
+ VkDeviceSize ofs;
+ VkIndexType type;
+ } bindIndexBuffer;
+ struct {
+ VkViewport viewport;
+ } setViewport;
+ struct {
+ VkRect2D scissor;
+ } setScissor;
+ struct {
+ float c[4];
+ } setBlendConstants;
+ struct {
+ uint32_t ref;
+ } setStencilRef;
+ struct {
+ uint32_t vertexCount;
+ uint32_t instanceCount;
+ uint32_t firstVertex;
+ uint32_t firstInstance;
+ } draw;
+ struct {
+ uint32_t indexCount;
+ uint32_t instanceCount;
+ uint32_t firstIndex;
+ int32_t vertexOffset;
+ uint32_t firstInstance;
+ } drawIndexed;
+ struct {
+#ifdef VK_EXT_debug_utils
+ VkDebugUtilsLabelEXT label;
+ int labelNameIndex;
+#endif
+ } debugMarkerBegin;
+ struct {
+ } debugMarkerEnd;
+ struct {
+#ifdef VK_EXT_debug_utils
+ VkDebugUtilsLabelEXT label;
+ int labelNameIndex;
+#endif
+ } debugMarkerInsert;
+ struct {
+ int trackerIndex;
+ } transitionResources;
+ struct {
+ int x, y, z;
+ } dispatch;
+ struct {
+ VkCommandBuffer cb;
+ } executeSecondary;
+ } args;
+ };
+
+ QRhiBackendCommandList<Command> commands;
+ QVarLengthArray<QRhiPassResourceTracker, 8> passResTrackers;
+ int currentPassResTrackerIndex;
+
+ void resetCommands() {
+ commands.reset();
+ resetPools();
+
+ passResTrackers.clear();
+ currentPassResTrackerIndex = -1;
+ }
+
+ void resetPools() {
+ pools.clearValue.clear();
+ pools.bufferImageCopy.clear();
+ pools.dynamicOffset.clear();
+ pools.vertexBuffer.clear();
+ pools.vertexBufferOffset.clear();
+ pools.debugMarkerData.clear();
+ pools.imageBarrier.clear();
+ pools.bufferBarrier.clear();
+ }
+
+ struct {
+ QVarLengthArray<VkClearValue, 4> clearValue;
+ QVarLengthArray<VkBufferImageCopy, 16> bufferImageCopy;
+ QVarLengthArray<uint32_t, 4> dynamicOffset;
+ QVarLengthArray<VkBuffer, 4> vertexBuffer;
+ QVarLengthArray<VkDeviceSize, 4> vertexBufferOffset;
+ QVarLengthArray<QByteArray, 4> debugMarkerData;
+ QVarLengthArray<VkImageMemoryBarrier, 8> imageBarrier;
+ QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarrier;
+ } pools;
+
+ friend class QRhiVulkan;
+};
+
+struct QVkSwapChain : public QRhiSwapChain
+{
+ QVkSwapChain(QRhiImplementation *rhi);
+ ~QVkSwapChain();
+ void destroy() override;
+
+ QRhiCommandBuffer *currentFrameCommandBuffer() override;
+ QRhiRenderTarget *currentFrameRenderTarget() override;
+ QRhiRenderTarget *currentFrameRenderTarget(StereoTargetBuffer targetBuffer) override;
+
+ QSize surfacePixelSize() override;
+ bool isFormatSupported(Format f) override;
+
+ QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
+ bool createOrResize() override;
+
+ bool ensureSurface();
+
+ static const quint32 EXPECTED_MAX_BUFFER_COUNT = 4;
+
QWindow *window = nullptr;
- QByteArrayList deviceExtensions;
+ QSize pixelSize;
+ bool supportsReadback = false;
+ bool stereo = false;
+ VkSwapchainKHR sc = VK_NULL_HANDLE;
+ int bufferCount = 0;
+ VkSurfaceKHR surface = VK_NULL_HANDLE;
+ VkSurfaceKHR lastConnectedSurface = VK_NULL_HANDLE;
+ VkFormat colorFormat = VK_FORMAT_B8G8R8A8_UNORM;
+ VkColorSpaceKHR colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
+ QVkRenderBuffer *ds = nullptr;
+ VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
+ QVarLengthArray<VkPresentModeKHR, 8> supportedPresentationModes;
+ VkDeviceMemory msaaImageMem = VK_NULL_HANDLE;
+ QVkSwapChainRenderTarget rtWrapper;
+ QVkSwapChainRenderTarget rtWrapperRight;
+ QVkCommandBuffer cbWrapper;
+
+ struct ImageResources {
+ VkImage image = VK_NULL_HANDLE;
+ VkImageView imageView = VK_NULL_HANDLE;
+ VkFramebuffer fb = VK_NULL_HANDLE;
+ VkImage msaaImage = VK_NULL_HANDLE;
+ VkImageView msaaImageView = VK_NULL_HANDLE;
+ enum LastUse {
+ ScImageUseNone,
+ ScImageUseRender,
+ ScImageUseTransferSource
+ };
+ LastUse lastUse = ScImageUseNone;
+ };
+ QVarLengthArray<ImageResources, EXPECTED_MAX_BUFFER_COUNT> imageRes;
+
+ struct FrameResources {
+ VkFence imageFence = VK_NULL_HANDLE;
+ bool imageFenceWaitable = false;
+ VkSemaphore imageSem = VK_NULL_HANDLE;
+ VkSemaphore drawSem = VK_NULL_HANDLE;
+ bool imageAcquired = false;
+ bool imageSemWaitable = false;
+ VkFence cmdFence = VK_NULL_HANDLE;
+ bool cmdFenceWaitable = false;
+ VkCommandBuffer cmdBuf = VK_NULL_HANDLE; // primary
+ int timestampQueryIndex = -1;
+ } frameRes[QVK_FRAMES_IN_FLIGHT];
- static QByteArrayList preferredInstanceExtensions();
- static QByteArrayList preferredExtensionsForImportedDevice();
+ quint32 currentImageIndex = 0; // index in imageRes
+ quint32 currentFrameSlot = 0; // index in frameRes
+ int frameCount = 0;
+
+ friend class QRhiVulkan;
};
-struct Q_GUI_EXPORT QRhiVulkanNativeHandles : public QRhiNativeHandles
+class QRhiVulkan : public QRhiImplementation
{
- // to import a physical device (always required)
+public:
+ QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *importParams = nullptr);
+
+ bool create(QRhi::Flags flags) override;
+ void destroy() override;
+
+ QRhiGraphicsPipeline *createGraphicsPipeline() override;
+ QRhiComputePipeline *createComputePipeline() override;
+ QRhiShaderResourceBindings *createShaderResourceBindings() override;
+ QRhiBuffer *createBuffer(QRhiBuffer::Type type,
+ QRhiBuffer::UsageFlags usage,
+ quint32 size) override;
+ QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
+ const QSize &pixelSize,
+ int sampleCount,
+ QRhiRenderBuffer::Flags flags,
+ QRhiTexture::Format backingFormatHint) override;
+ QRhiTexture *createTexture(QRhiTexture::Format format,
+ const QSize &pixelSize,
+ int depth,
+ int arraySize,
+ int sampleCount,
+ QRhiTexture::Flags flags) override;
+ QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
+ QRhiSampler::Filter minFilter,
+ QRhiSampler::Filter mipmapMode,
+ QRhiSampler:: AddressMode u,
+ QRhiSampler::AddressMode v,
+ QRhiSampler::AddressMode w) override;
+
+ QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
+ QRhiTextureRenderTarget::Flags flags) override;
+
+ QRhiSwapChain *createSwapChain() override;
+ QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
+ QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
+ QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
+ QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
+ QRhi::FrameOpResult finish() override;
+
+ void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+
+ void beginPass(QRhiCommandBuffer *cb,
+ QRhiRenderTarget *rt,
+ const QColor &colorClearValue,
+ const QRhiDepthStencilClearValue &depthStencilClearValue,
+ QRhiResourceUpdateBatch *resourceUpdates,
+ QRhiCommandBuffer::BeginPassFlags flags) override;
+ void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+
+ void setGraphicsPipeline(QRhiCommandBuffer *cb,
+ QRhiGraphicsPipeline *ps) override;
+
+ void setShaderResources(QRhiCommandBuffer *cb,
+ QRhiShaderResourceBindings *srb,
+ int dynamicOffsetCount,
+ const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
+
+ void setVertexInput(QRhiCommandBuffer *cb,
+ int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
+ QRhiBuffer *indexBuf, quint32 indexOffset,
+ QRhiCommandBuffer::IndexFormat indexFormat) override;
+
+ void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
+ void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
+ void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
+ void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
+
+ void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
+ quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
+
+ void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
+ quint32 instanceCount, quint32 firstIndex,
+ qint32 vertexOffset, quint32 firstInstance) override;
+
+ void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
+ void debugMarkEnd(QRhiCommandBuffer *cb) override;
+ void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
+
+ void beginComputePass(QRhiCommandBuffer *cb,
+ QRhiResourceUpdateBatch *resourceUpdates,
+ QRhiCommandBuffer::BeginPassFlags flags) override;
+ void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
+ void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
+ void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
+
+ const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
+ void beginExternal(QRhiCommandBuffer *cb) override;
+ void endExternal(QRhiCommandBuffer *cb) override;
+ double lastCompletedGpuTime(QRhiCommandBuffer *cb) override;
+
+ QList<int> supportedSampleCounts() const override;
+ int ubufAlignment() const override;
+ bool isYUpInFramebuffer() const override;
+ bool isYUpInNDC() const override;
+ bool isClipDepthZeroToOne() const override;
+ QMatrix4x4 clipSpaceCorrMatrix() const override;
+ bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
+ bool isFeatureSupported(QRhi::Feature feature) const override;
+ int resourceLimit(QRhi::ResourceLimit limit) const override;
+ const QRhiNativeHandles *nativeHandles() override;
+ QRhiDriverInfo driverInfo() const override;
+ QRhiStats statistics() override;
+ bool makeThreadLocalNativeContextCurrent() override;
+ void releaseCachedResources() override;
+ bool isDeviceLost() const override;
+
+ QByteArray pipelineCacheData() override;
+ void setPipelineCacheData(const QByteArray &data) override;
+
+ VkResult createDescriptorPool(VkDescriptorPool *pool);
+ bool allocateDescriptorSet(VkDescriptorSetAllocateInfo *allocInfo, VkDescriptorSet *result, int *resultPoolIndex);
+ uint32_t chooseTransientImageMemType(VkImage img, uint32_t startIndex);
+ bool createTransientImage(VkFormat format, const QSize &pixelSize, VkImageUsageFlags usage,
+ VkImageAspectFlags aspectMask, VkSampleCountFlagBits samples,
+ VkDeviceMemory *mem, VkImage *images, VkImageView *views, int count);
+
+ bool recreateSwapChain(QRhiSwapChain *swapChain);
+ void releaseSwapChainResources(QRhiSwapChain *swapChain);
+
+ VkFormat optimalDepthStencilFormat();
+ VkSampleCountFlagBits effectiveSampleCountBits(int sampleCount);
+ bool createDefaultRenderPass(QVkRenderPassDescriptor *rpD,
+ bool hasDepthStencil,
+ VkSampleCountFlagBits samples,
+ VkFormat colorFormat);
+ bool createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
+ const QRhiColorAttachment *colorAttachmentsBegin,
+ const QRhiColorAttachment *colorAttachmentsEnd,
+ bool preserveColor,
+ bool preserveDs,
+ bool storeDs,
+ QRhiRenderBuffer *depthStencilBuffer,
+ QRhiTexture *depthTexture,
+ QRhiTexture *depthResolveTexture);
+ bool ensurePipelineCache(const void *initialData = nullptr, size_t initialDataSize = 0);
+ VkShaderModule createShader(const QByteArray &spirv);
+
+ void prepareNewFrame(QRhiCommandBuffer *cb);
+ VkCommandBuffer startSecondaryCommandBuffer(QVkRenderTargetData *rtD = nullptr);
+ void endAndEnqueueSecondaryCommandBuffer(VkCommandBuffer cb, QVkCommandBuffer *cbD);
+ QRhi::FrameOpResult startPrimaryCommandBuffer(VkCommandBuffer *cb);
+ QRhi::FrameOpResult endAndSubmitPrimaryCommandBuffer(VkCommandBuffer cb, VkFence cmdFence,
+ VkSemaphore *waitSem, VkSemaphore *signalSem);
+ void waitCommandCompletion(int frameSlot);
+ VkDeviceSize subresUploadByteSize(const QRhiTextureSubresourceUploadDescription &subresDesc) const;
+ using BufferImageCopyList = QVarLengthArray<VkBufferImageCopy, 16>;
+ void prepareUploadSubres(QVkTexture *texD, int layer, int level,
+ const QRhiTextureSubresourceUploadDescription &subresDesc,
+ size_t *curOfs, void *mp,
+ BufferImageCopyList *copyInfos);
+ void enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates);
+ void executeBufferHostWritesForSlot(QVkBuffer *bufD, int slot);
+ void enqueueTransitionPassResources(QVkCommandBuffer *cbD);
+ void recordPrimaryCommandBuffer(QVkCommandBuffer *cbD);
+ void trackedRegisterBuffer(QRhiPassResourceTracker *passResTracker,
+ QVkBuffer *bufD,
+ int slot,
+ QRhiPassResourceTracker::BufferAccess access,
+ QRhiPassResourceTracker::BufferStage stage);
+ void trackedRegisterTexture(QRhiPassResourceTracker *passResTracker,
+ QVkTexture *texD,
+ QRhiPassResourceTracker::TextureAccess access,
+ QRhiPassResourceTracker::TextureStage stage);
+ void recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhiPassResourceTracker &tracker);
+ void activateTextureRenderTarget(QVkCommandBuffer *cbD, QVkTextureRenderTarget *rtD);
+ void executeDeferredReleases(bool forced = false);
+ void finishActiveReadbacks(bool forced = false);
+
+ void setObjectName(uint64_t object, VkObjectType type, const QByteArray &name, int slot = -1);
+ void trackedBufferBarrier(QVkCommandBuffer *cbD, QVkBuffer *bufD, int slot,
+ VkAccessFlags access, VkPipelineStageFlags stage);
+ void trackedImageBarrier(QVkCommandBuffer *cbD, QVkTexture *texD,
+ VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage);
+ void depthStencilExplicitBarrier(QVkCommandBuffer *cbD, QVkRenderBuffer *rbD);
+ void subresourceBarrier(QVkCommandBuffer *cbD, VkImage image,
+ VkImageLayout oldLayout, VkImageLayout newLayout,
+ VkAccessFlags srcAccess, VkAccessFlags dstAccess,
+ VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage,
+ int startLayer, int layerCount,
+ int startLevel, int levelCount);
+ void updateShaderResourceBindings(QRhiShaderResourceBindings *srb, int descSetIdx = -1);
+ void ensureCommandPoolForNewFrame();
+ double elapsedSecondsFromTimestamp(quint64 timestamp[2], bool *ok);
+ void printExtraErrorInfo(VkResult err);
+
+ QVulkanInstance *inst = nullptr;
+ QWindow *maybeWindow = nullptr;
+ QByteArrayList requestedDeviceExtensions;
+ bool importedDevice = false;
VkPhysicalDevice physDev = VK_NULL_HANDLE;
- // to import a device and queue
VkDevice dev = VK_NULL_HANDLE;
+ VkCommandPool cmdPool[QVK_FRAMES_IN_FLIGHT] = {};
quint32 gfxQueueFamilyIdx = 0;
quint32 gfxQueueIdx = 0;
VkQueue gfxQueue = VK_NULL_HANDLE;
- // and optionally, the mem allocator
- void *vmemAllocator = nullptr;
-};
+ quint32 timestampValidBits = 0;
+ bool importedAllocator = false;
+ QVkAllocator allocator = nullptr;
+ QVulkanFunctions *f = nullptr;
+ QVulkanDeviceFunctions *df = nullptr;
+ QRhi::Flags rhiFlags;
+ VkPhysicalDeviceFeatures physDevFeatures;
+#ifdef VK_VERSION_1_1
+ VkPhysicalDeviceMultiviewFeatures multiviewFeaturesIfApi11;
+#endif
+#ifdef VK_VERSION_1_2
+ VkPhysicalDeviceVulkan11Features physDevFeatures11IfApi12OrNewer;
+ VkPhysicalDeviceVulkan12Features physDevFeatures12;
+#endif
+#ifdef VK_VERSION_1_3
+ VkPhysicalDeviceVulkan13Features physDevFeatures13;
+#endif
+ VkPhysicalDeviceProperties physDevProperties;
+ VkDeviceSize ubufAlign;
+ VkDeviceSize texbufAlign;
+ bool deviceLost = false;
+ bool releaseCachedResourcesCalledBeforeFrameStart = false;
-struct Q_GUI_EXPORT QRhiVulkanCommandBufferNativeHandles : public QRhiNativeHandles
-{
- VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
-};
+#ifdef VK_EXT_debug_utils
+ PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT = nullptr;
+ PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT = nullptr;
+ PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT = nullptr;
+ PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT = nullptr;
+#endif
-struct Q_GUI_EXPORT QRhiVulkanRenderPassNativeHandles : public QRhiNativeHandles
-{
- VkRenderPass renderPass = VK_NULL_HANDLE;
+ PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR = nullptr;
+ PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR;
+ PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR;
+ PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR;
+ PFN_vkQueuePresentKHR vkQueuePresentKHR;
+ PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
+ PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR;
+ PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR;
+
+#ifdef VK_KHR_create_renderpass2
+ PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr;
+#endif
+
+ struct {
+ bool compute = false;
+ bool wideLines = false;
+ bool debugUtils = false;
+ bool vertexAttribDivisor = false;
+ bool texture3DSliceAs2D = false;
+ bool tessellation = false;
+ bool geometryShader = false;
+ bool nonFillPolygonMode = false;
+ bool multiView = false;
+ bool renderPass2KHR = false;
+ bool depthStencilResolveKHR = false;
+ QVersionNumber apiVersion;
+ } caps;
+
+ VkPipelineCache pipelineCache = VK_NULL_HANDLE;
+ struct DescriptorPoolData {
+ DescriptorPoolData() { }
+ DescriptorPoolData(VkDescriptorPool pool_)
+ : pool(pool_)
+ { }
+ VkDescriptorPool pool = VK_NULL_HANDLE;
+ int refCount = 0;
+ int allocedDescSets = 0;
+ };
+ QVarLengthArray<DescriptorPoolData, 8> descriptorPools;
+ QVarLengthArray<VkCommandBuffer, 4> freeSecondaryCbs[QVK_FRAMES_IN_FLIGHT];
+
+ VkQueryPool timestampQueryPool = VK_NULL_HANDLE;
+ QBitArray timestampQueryPoolMap;
+
+ VkFormat optimalDsFormat = VK_FORMAT_UNDEFINED;
+ QMatrix4x4 clipCorrectMatrix;
+
+ QVkSwapChain *currentSwapChain = nullptr;
+ QSet<QVkSwapChain *> swapchains;
+ QRhiVulkanNativeHandles nativeHandlesStruct;
+ QRhiDriverInfo driverInfoStruct;
+
+ struct OffscreenFrame {
+ OffscreenFrame(QRhiImplementation *rhi)
+ {
+ for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
+ cbWrapper[i] = new QVkCommandBuffer(rhi);
+ }
+ ~OffscreenFrame()
+ {
+ for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
+ delete cbWrapper[i];
+ }
+ bool active = false;
+ QVkCommandBuffer *cbWrapper[QVK_FRAMES_IN_FLIGHT];
+ VkFence cmdFence = VK_NULL_HANDLE;
+ int timestampQueryIndex = -1;
+ } ofr;
+
+ struct TextureReadback {
+ int activeFrameSlot = -1;
+ QRhiReadbackDescription desc;
+ QRhiReadbackResult *result;
+ VkBuffer stagingBuf;
+ QVkAlloc stagingAlloc;
+ quint32 byteSize;
+ QSize pixelSize;
+ QRhiTexture::Format format;
+ };
+ QVarLengthArray<TextureReadback, 2> activeTextureReadbacks;
+ struct BufferReadback {
+ int activeFrameSlot = -1;
+ QRhiReadbackResult *result;
+ quint32 byteSize;
+ VkBuffer stagingBuf;
+ QVkAlloc stagingAlloc;
+ };
+ QVarLengthArray<BufferReadback, 2> activeBufferReadbacks;
+
+ struct DeferredReleaseEntry {
+ enum Type {
+ Pipeline,
+ ShaderResourceBindings,
+ Buffer,
+ RenderBuffer,
+ Texture,
+ Sampler,
+ TextureRenderTarget,
+ RenderPass,
+ StagingBuffer,
+ SecondaryCommandBuffer
+ };
+ Type type;
+ int lastActiveFrameSlot; // -1 if not used otherwise 0..FRAMES_IN_FLIGHT-1
+ union {
+ struct {
+ VkPipeline pipeline;
+ VkPipelineLayout layout;
+ } pipelineState;
+ struct {
+ int poolIndex;
+ VkDescriptorSetLayout layout;
+ } shaderResourceBindings;
+ struct {
+ VkBuffer buffers[QVK_FRAMES_IN_FLIGHT];
+ QVkAlloc allocations[QVK_FRAMES_IN_FLIGHT];
+ VkBuffer stagingBuffers[QVK_FRAMES_IN_FLIGHT];
+ QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT];
+ } buffer;
+ struct {
+ VkDeviceMemory memory;
+ VkImage image;
+ VkImageView imageView;
+ } renderBuffer;
+ struct {
+ VkImage image;
+ VkImageView imageView;
+ QVkAlloc allocation;
+ VkBuffer stagingBuffers[QVK_FRAMES_IN_FLIGHT];
+ QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT];
+ VkImageView extraImageViews[QRhi::MAX_MIP_LEVELS];
+ } texture;
+ struct {
+ VkSampler sampler;
+ } sampler;
+ struct {
+ VkFramebuffer fb;
+ VkImageView rtv[QVkRenderTargetData::MAX_COLOR_ATTACHMENTS];
+ VkImageView resrtv[QVkRenderTargetData::MAX_COLOR_ATTACHMENTS];
+ VkImageView dsv;
+ VkImageView resdsv;
+ } textureRenderTarget;
+ struct {
+ VkRenderPass rp;
+ } renderPass;
+ struct {
+ VkBuffer stagingBuffer;
+ QVkAlloc stagingAllocation;
+ } stagingBuffer;
+ struct {
+ VkCommandBuffer cb;
+ } secondaryCommandBuffer;
+ };
+ };
+ QList<DeferredReleaseEntry> releaseQueue;
};
+Q_DECLARE_TYPEINFO(QRhiVulkan::DescriptorPoolData, Q_RELOCATABLE_TYPE);
+Q_DECLARE_TYPEINFO(QRhiVulkan::DeferredReleaseEntry, Q_RELOCATABLE_TYPE);
+Q_DECLARE_TYPEINFO(QRhiVulkan::TextureReadback, Q_RELOCATABLE_TYPE);
+Q_DECLARE_TYPEINFO(QRhiVulkan::BufferReadback, Q_RELOCATABLE_TYPE);
+
QT_END_NAMESPACE
#endif
diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h
deleted file mode 100644
index 22214723ae..0000000000
--- a/src/gui/rhi/qrhivulkan_p_p.h
+++ /dev/null
@@ -1,1001 +0,0 @@
-// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QRHIVULKAN_P_H
-#define QRHIVULKAN_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 "qrhivulkan_p.h"
-#include "qrhi_p_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class QVulkanFunctions;
-class QVulkanDeviceFunctions;
-
-static const int QVK_FRAMES_IN_FLIGHT = 2;
-
-static const int QVK_DESC_SETS_PER_POOL = 128;
-static const int QVK_UNIFORM_BUFFERS_PER_POOL = 256;
-static const int QVK_COMBINED_IMAGE_SAMPLERS_PER_POOL = 256;
-static const int QVK_STORAGE_BUFFERS_PER_POOL = 128;
-static const int QVK_STORAGE_IMAGES_PER_POOL = 128;
-
-static const int QVK_MAX_ACTIVE_TIMESTAMP_PAIRS = 16;
-
-// no vk_mem_alloc.h available here, void* is good enough
-typedef void * QVkAlloc;
-typedef void * QVkAllocator;
-
-struct QVkBuffer : public QRhiBuffer
-{
- QVkBuffer(QRhiImplementation *rhi, Type type, UsageFlags usage, quint32 size);
- ~QVkBuffer();
- void destroy() override;
- bool create() override;
- QRhiBuffer::NativeBuffer nativeBuffer() override;
- char *beginFullDynamicBufferUpdateForCurrentFrame() override;
- void endFullDynamicBufferUpdateForCurrentFrame() override;
-
- VkBuffer buffers[QVK_FRAMES_IN_FLIGHT];
- QVkAlloc allocations[QVK_FRAMES_IN_FLIGHT];
- struct DynamicUpdate {
- quint32 offset;
- QRhiBufferData data;
- };
- QVarLengthArray<DynamicUpdate, 16> pendingDynamicUpdates[QVK_FRAMES_IN_FLIGHT];
- VkBuffer stagingBuffers[QVK_FRAMES_IN_FLIGHT];
- QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT];
- struct UsageState {
- VkAccessFlags access = 0;
- VkPipelineStageFlags stage = 0;
- };
- UsageState usageState[QVK_FRAMES_IN_FLIGHT];
- int lastActiveFrameSlot = -1;
- uint generation = 0;
- friend class QRhiVulkan;
-};
-
-Q_DECLARE_TYPEINFO(QVkBuffer::DynamicUpdate, Q_RELOCATABLE_TYPE);
-
-struct QVkTexture;
-
-struct QVkRenderBuffer : public QRhiRenderBuffer
-{
- QVkRenderBuffer(QRhiImplementation *rhi, Type type, const QSize &pixelSize,
- int sampleCount, Flags flags,
- QRhiTexture::Format backingFormatHint);
- ~QVkRenderBuffer();
- void destroy() override;
- bool create() override;
- QRhiTexture::Format backingFormat() const override;
-
- VkDeviceMemory memory = VK_NULL_HANDLE;
- VkImage image = VK_NULL_HANDLE;
- VkImageView imageView = VK_NULL_HANDLE;
- VkSampleCountFlagBits samples;
- QVkTexture *backingTexture = nullptr;
- VkFormat vkformat;
- int lastActiveFrameSlot = -1;
- uint generation = 0;
- friend class QRhiVulkan;
-};
-
-struct QVkTexture : public QRhiTexture
-{
- QVkTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth,
- int arraySize, int sampleCount, Flags flags);
- ~QVkTexture();
- void destroy() override;
- bool create() override;
- bool createFrom(NativeTexture src) override;
- NativeTexture nativeTexture() override;
- void setNativeLayout(int layout) override;
-
- bool prepareCreate(QSize *adjustedSize = nullptr);
- bool finishCreate();
- VkImageView imageViewForLevel(int level);
-
- VkImage image = VK_NULL_HANDLE;
- VkImageView imageView = VK_NULL_HANDLE;
- QVkAlloc imageAlloc = nullptr;
- VkBuffer stagingBuffers[QVK_FRAMES_IN_FLIGHT];
- QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT];
- VkImageView perLevelImageViews[QRhi::MAX_MIP_LEVELS];
- bool owns = true;
- struct UsageState {
- // no tracking of subresource layouts (some operations can keep
- // subresources in different layouts for some time, but that does not
- // need to be kept track of)
- VkImageLayout layout;
- VkAccessFlags access;
- VkPipelineStageFlags stage;
- };
- UsageState usageState;
- VkFormat vkformat;
- uint mipLevelCount = 0;
- VkSampleCountFlagBits samples;
- int lastActiveFrameSlot = -1;
- uint generation = 0;
- friend class QRhiVulkan;
-};
-
-struct QVkSampler : public QRhiSampler
-{
- QVkSampler(QRhiImplementation *rhi, Filter magFilter, Filter minFilter, Filter mipmapMode,
- AddressMode u, AddressMode v, AddressMode w);
- ~QVkSampler();
- void destroy() override;
- bool create() override;
-
- VkSampler sampler = VK_NULL_HANDLE;
- int lastActiveFrameSlot = -1;
- uint generation = 0;
- friend class QRhiVulkan;
-};
-
-struct QVkRenderPassDescriptor : public QRhiRenderPassDescriptor
-{
- QVkRenderPassDescriptor(QRhiImplementation *rhi);
- ~QVkRenderPassDescriptor();
- void destroy() override;
- bool isCompatible(const QRhiRenderPassDescriptor *other) const override;
- QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() const override;
- QVector<quint32> serializedFormat() const override;
- const QRhiNativeHandles *nativeHandles() override;
-
- void updateSerializedFormat();
-
- VkRenderPass rp = VK_NULL_HANDLE;
- bool ownsRp = false;
- QVarLengthArray<VkAttachmentDescription, 8> attDescs;
- QVarLengthArray<VkAttachmentReference, 8> colorRefs;
- QVarLengthArray<VkAttachmentReference, 8> resolveRefs;
- QVarLengthArray<VkSubpassDependency, 2> subpassDeps;
- bool hasDepthStencil = false;
- VkAttachmentReference dsRef;
- QVector<quint32> serializedFormatData;
- QRhiVulkanRenderPassNativeHandles nativeHandlesStruct;
- int lastActiveFrameSlot = -1;
-};
-
-struct QVkRenderTargetData
-{
- VkFramebuffer fb = VK_NULL_HANDLE;
- QVkRenderPassDescriptor *rp = nullptr;
- QSize pixelSize;
- float dpr = 1;
- int sampleCount = 1;
- int colorAttCount = 0;
- int dsAttCount = 0;
- int resolveAttCount = 0;
- QRhiRenderTargetAttachmentTracker::ResIdList currentResIdList;
- static const int MAX_COLOR_ATTACHMENTS = 8;
-};
-
-struct QVkSwapChainRenderTarget : public QRhiSwapChainRenderTarget
-{
- QVkSwapChainRenderTarget(QRhiImplementation *rhi, QRhiSwapChain *swapchain);
- ~QVkSwapChainRenderTarget();
- void destroy() override;
-
- QSize pixelSize() const override;
- float devicePixelRatio() const override;
- int sampleCount() const override;
-
- QVkRenderTargetData d;
-};
-
-struct QVkTextureRenderTarget : public QRhiTextureRenderTarget
-{
- QVkTextureRenderTarget(QRhiImplementation *rhi, const QRhiTextureRenderTargetDescription &desc, Flags flags);
- ~QVkTextureRenderTarget();
- void destroy() override;
-
- QSize pixelSize() const override;
- float devicePixelRatio() const override;
- int sampleCount() const override;
-
- QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
- bool create() override;
-
- QVkRenderTargetData d;
- VkImageView rtv[QVkRenderTargetData::MAX_COLOR_ATTACHMENTS];
- VkImageView resrtv[QVkRenderTargetData::MAX_COLOR_ATTACHMENTS];
- int lastActiveFrameSlot = -1;
- friend class QRhiVulkan;
-};
-
-struct QVkShaderResourceBindings : public QRhiShaderResourceBindings
-{
- QVkShaderResourceBindings(QRhiImplementation *rhi);
- ~QVkShaderResourceBindings();
- void destroy() override;
- bool create() override;
- void updateResources(UpdateFlags flags) override;
-
- QVarLengthArray<QRhiShaderResourceBinding, 8> sortedBindings;
- bool hasSlottedResource = false;
- bool hasDynamicOffset = false;
- int poolIndex = -1;
- VkDescriptorSetLayout layout = VK_NULL_HANDLE;
- VkDescriptorSet descSets[QVK_FRAMES_IN_FLIGHT]; // multiple sets to support dynamic buffers
- int lastActiveFrameSlot = -1;
- uint generation = 0;
-
- // Keep track of the generation number of each referenced QRhi* to be able
- // to detect that the underlying descriptor set became out of date and they
- // need to be written again with the up-to-date VkBuffer etc. objects.
- struct BoundUniformBufferData {
- quint64 id;
- uint generation;
- };
- struct BoundSampledTextureData {
- int count;
- struct {
- quint64 texId;
- uint texGeneration;
- quint64 samplerId;
- uint samplerGeneration;
- } d[QRhiShaderResourceBinding::Data::MAX_TEX_SAMPLER_ARRAY_SIZE];
- };
- struct BoundStorageImageData {
- quint64 id;
- uint generation;
- };
- struct BoundStorageBufferData {
- quint64 id;
- uint generation;
- };
- struct BoundResourceData {
- union {
- BoundUniformBufferData ubuf;
- BoundSampledTextureData stex;
- BoundStorageImageData simage;
- BoundStorageBufferData sbuf;
- };
- };
- QVarLengthArray<BoundResourceData, 8> boundResourceData[QVK_FRAMES_IN_FLIGHT];
-
- friend class QRhiVulkan;
-};
-
-Q_DECLARE_TYPEINFO(QVkShaderResourceBindings::BoundResourceData, Q_RELOCATABLE_TYPE);
-
-struct QVkGraphicsPipeline : public QRhiGraphicsPipeline
-{
- QVkGraphicsPipeline(QRhiImplementation *rhi);
- ~QVkGraphicsPipeline();
- void destroy() override;
- bool create() override;
-
- VkPipelineLayout layout = VK_NULL_HANDLE;
- VkPipeline pipeline = VK_NULL_HANDLE;
- int lastActiveFrameSlot = -1;
- uint generation = 0;
- friend class QRhiVulkan;
-};
-
-struct QVkComputePipeline : public QRhiComputePipeline
-{
- QVkComputePipeline(QRhiImplementation *rhi);
- ~QVkComputePipeline();
- void destroy() override;
- bool create() override;
-
- VkPipelineLayout layout = VK_NULL_HANDLE;
- VkPipeline pipeline = VK_NULL_HANDLE;
- int lastActiveFrameSlot = -1;
- uint generation = 0;
- friend class QRhiVulkan;
-};
-
-struct QVkCommandBuffer : public QRhiCommandBuffer
-{
- QVkCommandBuffer(QRhiImplementation *rhi);
- ~QVkCommandBuffer();
- void destroy() override;
-
- const QRhiNativeHandles *nativeHandles();
-
- VkCommandBuffer cb = VK_NULL_HANDLE; // primary
- QRhiVulkanCommandBufferNativeHandles nativeHandlesStruct;
-
- enum PassType {
- NoPass,
- RenderPass,
- ComputePass
- };
-
- void resetState() {
- recordingPass = NoPass;
- passUsesSecondaryCb = false;
- currentTarget = nullptr;
- activeSecondaryCbStack.clear();
- resetCommands();
- resetCachedState();
- }
-
- void resetCachedState() {
- currentGraphicsPipeline = nullptr;
- currentComputePipeline = nullptr;
- currentPipelineGeneration = 0;
- currentGraphicsSrb = nullptr;
- currentComputeSrb = nullptr;
- currentSrbGeneration = 0;
- currentDescSetSlot = -1;
- currentIndexBuffer = VK_NULL_HANDLE;
- currentIndexOffset = 0;
- currentIndexFormat = VK_INDEX_TYPE_UINT16;
- memset(currentVertexBuffers, 0, sizeof(currentVertexBuffers));
- memset(currentVertexOffsets, 0, sizeof(currentVertexOffsets));
- inExternal = false;
- }
-
- PassType recordingPass;
- bool passUsesSecondaryCb;
- QRhiRenderTarget *currentTarget;
- QRhiGraphicsPipeline *currentGraphicsPipeline;
- QRhiComputePipeline *currentComputePipeline;
- uint currentPipelineGeneration;
- QRhiShaderResourceBindings *currentGraphicsSrb;
- QRhiShaderResourceBindings *currentComputeSrb;
- uint currentSrbGeneration;
- int currentDescSetSlot;
- VkBuffer currentIndexBuffer;
- quint32 currentIndexOffset;
- VkIndexType currentIndexFormat;
- static const int VERTEX_INPUT_RESOURCE_SLOT_COUNT = 32;
- VkBuffer currentVertexBuffers[VERTEX_INPUT_RESOURCE_SLOT_COUNT];
- quint32 currentVertexOffsets[VERTEX_INPUT_RESOURCE_SLOT_COUNT];
- QVarLengthArray<VkCommandBuffer, 4> activeSecondaryCbStack;
- bool inExternal;
-
- struct {
- QHash<QRhiResource *, QPair<VkAccessFlags, bool> > writtenResources;
- void reset() {
- writtenResources.clear();
- }
- } computePassState;
-
- struct Command {
- enum Cmd {
- CopyBuffer,
- CopyBufferToImage,
- CopyImage,
- CopyImageToBuffer,
- ImageBarrier,
- BufferBarrier,
- BlitImage,
- BeginRenderPass,
- EndRenderPass,
- BindPipeline,
- BindDescriptorSet,
- BindVertexBuffer,
- BindIndexBuffer,
- SetViewport,
- SetScissor,
- SetBlendConstants,
- SetStencilRef,
- Draw,
- DrawIndexed,
- DebugMarkerBegin,
- DebugMarkerEnd,
- DebugMarkerInsert,
- TransitionPassResources,
- Dispatch,
- ExecuteSecondary
- };
- Cmd cmd;
-
- union Args {
- struct {
- VkBuffer src;
- VkBuffer dst;
- VkBufferCopy desc;
- } copyBuffer;
- struct {
- VkBuffer src;
- VkImage dst;
- VkImageLayout dstLayout;
- int count;
- int bufferImageCopyIndex;
- } copyBufferToImage;
- struct {
- VkImage src;
- VkImageLayout srcLayout;
- VkImage dst;
- VkImageLayout dstLayout;
- VkImageCopy desc;
- } copyImage;
- struct {
- VkImage src;
- VkImageLayout srcLayout;
- VkBuffer dst;
- VkBufferImageCopy desc;
- } copyImageToBuffer;
- struct {
- VkPipelineStageFlags srcStageMask;
- VkPipelineStageFlags dstStageMask;
- int count;
- int index;
- } imageBarrier;
- struct {
- VkPipelineStageFlags srcStageMask;
- VkPipelineStageFlags dstStageMask;
- int count;
- int index;
- } bufferBarrier;
- struct {
- VkImage src;
- VkImageLayout srcLayout;
- VkImage dst;
- VkImageLayout dstLayout;
- VkFilter filter;
- VkImageBlit desc;
- } blitImage;
- struct {
- VkRenderPassBeginInfo desc;
- int clearValueIndex;
- bool useSecondaryCb;
- } beginRenderPass;
- struct {
- } endRenderPass;
- struct {
- VkPipelineBindPoint bindPoint;
- VkPipeline pipeline;
- } bindPipeline;
- struct {
- VkPipelineBindPoint bindPoint;
- VkPipelineLayout pipelineLayout;
- VkDescriptorSet descSet;
- int dynamicOffsetCount;
- int dynamicOffsetIndex;
- } bindDescriptorSet;
- struct {
- int startBinding;
- int count;
- int vertexBufferIndex;
- int vertexBufferOffsetIndex;
- } bindVertexBuffer;
- struct {
- VkBuffer buf;
- VkDeviceSize ofs;
- VkIndexType type;
- } bindIndexBuffer;
- struct {
- VkViewport viewport;
- } setViewport;
- struct {
- VkRect2D scissor;
- } setScissor;
- struct {
- float c[4];
- } setBlendConstants;
- struct {
- uint32_t ref;
- } setStencilRef;
- struct {
- uint32_t vertexCount;
- uint32_t instanceCount;
- uint32_t firstVertex;
- uint32_t firstInstance;
- } draw;
- struct {
- uint32_t indexCount;
- uint32_t instanceCount;
- uint32_t firstIndex;
- int32_t vertexOffset;
- uint32_t firstInstance;
- } drawIndexed;
- struct {
-#ifdef VK_EXT_debug_utils
- VkDebugUtilsLabelEXT label;
- int labelNameIndex;
-#endif
- } debugMarkerBegin;
- struct {
- } debugMarkerEnd;
- struct {
-#ifdef VK_EXT_debug_utils
- VkDebugUtilsLabelEXT label;
- int labelNameIndex;
-#endif
- } debugMarkerInsert;
- struct {
- int trackerIndex;
- } transitionResources;
- struct {
- int x, y, z;
- } dispatch;
- struct {
- VkCommandBuffer cb;
- } executeSecondary;
- } args;
- };
-
- QRhiBackendCommandList<Command> commands;
- QVarLengthArray<QRhiPassResourceTracker, 8> passResTrackers;
- int currentPassResTrackerIndex;
-
- void resetCommands() {
- commands.reset();
- resetPools();
-
- passResTrackers.clear();
- currentPassResTrackerIndex = -1;
- }
-
- void resetPools() {
- pools.clearValue.clear();
- pools.bufferImageCopy.clear();
- pools.dynamicOffset.clear();
- pools.vertexBuffer.clear();
- pools.vertexBufferOffset.clear();
- pools.debugMarkerData.clear();
- pools.imageBarrier.clear();
- pools.bufferBarrier.clear();
- }
-
- struct {
- QVarLengthArray<VkClearValue, 4> clearValue;
- QVarLengthArray<VkBufferImageCopy, 16> bufferImageCopy;
- QVarLengthArray<uint32_t, 4> dynamicOffset;
- QVarLengthArray<VkBuffer, 4> vertexBuffer;
- QVarLengthArray<VkDeviceSize, 4> vertexBufferOffset;
- QVarLengthArray<QByteArray, 4> debugMarkerData;
- QVarLengthArray<VkImageMemoryBarrier, 8> imageBarrier;
- QVarLengthArray<VkBufferMemoryBarrier, 8> bufferBarrier;
- } pools;
-
- friend class QRhiVulkan;
-};
-
-struct QVkSwapChain : public QRhiSwapChain
-{
- QVkSwapChain(QRhiImplementation *rhi);
- ~QVkSwapChain();
- void destroy() override;
-
- QRhiCommandBuffer *currentFrameCommandBuffer() override;
- QRhiRenderTarget *currentFrameRenderTarget() override;
-
- QSize surfacePixelSize() override;
- bool isFormatSupported(Format f) override;
-
- QRhiRenderPassDescriptor *newCompatibleRenderPassDescriptor() override;
- bool createOrResize() override;
-
- bool ensureSurface();
-
- static const quint32 EXPECTED_MAX_BUFFER_COUNT = 4;
-
- QWindow *window = nullptr;
- QSize pixelSize;
- bool supportsReadback = false;
- VkSwapchainKHR sc = VK_NULL_HANDLE;
- int bufferCount = 0;
- VkSurfaceKHR surface = VK_NULL_HANDLE;
- VkSurfaceKHR lastConnectedSurface = VK_NULL_HANDLE;
- VkFormat colorFormat = VK_FORMAT_B8G8R8A8_UNORM;
- VkColorSpaceKHR colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
- QVkRenderBuffer *ds = nullptr;
- VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT;
- QVarLengthArray<VkPresentModeKHR, 8> supportedPresentationModes;
- VkDeviceMemory msaaImageMem = VK_NULL_HANDLE;
- QVkSwapChainRenderTarget rtWrapper;
- QVkCommandBuffer cbWrapper;
-
- struct ImageResources {
- VkImage image = VK_NULL_HANDLE;
- VkImageView imageView = VK_NULL_HANDLE;
- VkFramebuffer fb = VK_NULL_HANDLE;
- VkImage msaaImage = VK_NULL_HANDLE;
- VkImageView msaaImageView = VK_NULL_HANDLE;
- enum LastUse {
- ScImageUseNone,
- ScImageUseRender,
- ScImageUseTransferSource
- };
- LastUse lastUse = ScImageUseNone;
- };
- QVarLengthArray<ImageResources, EXPECTED_MAX_BUFFER_COUNT> imageRes;
-
- struct FrameResources {
- VkFence imageFence = VK_NULL_HANDLE;
- bool imageFenceWaitable = false;
- VkSemaphore imageSem = VK_NULL_HANDLE;
- VkSemaphore drawSem = VK_NULL_HANDLE;
- bool imageAcquired = false;
- bool imageSemWaitable = false;
- VkFence cmdFence = VK_NULL_HANDLE;
- bool cmdFenceWaitable = false;
- VkCommandBuffer cmdBuf = VK_NULL_HANDLE; // primary
- int timestampQueryIndex = -1;
- } frameRes[QVK_FRAMES_IN_FLIGHT];
-
- quint32 currentImageIndex = 0; // index in imageRes
- quint32 currentFrameSlot = 0; // index in frameRes
- int frameCount = 0;
-
- friend class QRhiVulkan;
-};
-
-class QRhiVulkan : public QRhiImplementation
-{
-public:
- QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *importParams = nullptr);
-
- bool create(QRhi::Flags flags) override;
- void destroy() override;
-
- QRhiGraphicsPipeline *createGraphicsPipeline() override;
- QRhiComputePipeline *createComputePipeline() override;
- QRhiShaderResourceBindings *createShaderResourceBindings() override;
- QRhiBuffer *createBuffer(QRhiBuffer::Type type,
- QRhiBuffer::UsageFlags usage,
- quint32 size) override;
- QRhiRenderBuffer *createRenderBuffer(QRhiRenderBuffer::Type type,
- const QSize &pixelSize,
- int sampleCount,
- QRhiRenderBuffer::Flags flags,
- QRhiTexture::Format backingFormatHint) override;
- QRhiTexture *createTexture(QRhiTexture::Format format,
- const QSize &pixelSize,
- int depth,
- int arraySize,
- int sampleCount,
- QRhiTexture::Flags flags) override;
- QRhiSampler *createSampler(QRhiSampler::Filter magFilter,
- QRhiSampler::Filter minFilter,
- QRhiSampler::Filter mipmapMode,
- QRhiSampler:: AddressMode u,
- QRhiSampler::AddressMode v,
- QRhiSampler::AddressMode w) override;
-
- QRhiTextureRenderTarget *createTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc,
- QRhiTextureRenderTarget::Flags flags) override;
-
- QRhiSwapChain *createSwapChain() override;
- QRhi::FrameOpResult beginFrame(QRhiSwapChain *swapChain, QRhi::BeginFrameFlags flags) override;
- QRhi::FrameOpResult endFrame(QRhiSwapChain *swapChain, QRhi::EndFrameFlags flags) override;
- QRhi::FrameOpResult beginOffscreenFrame(QRhiCommandBuffer **cb, QRhi::BeginFrameFlags flags) override;
- QRhi::FrameOpResult endOffscreenFrame(QRhi::EndFrameFlags flags) override;
- QRhi::FrameOpResult finish() override;
-
- void resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
-
- void beginPass(QRhiCommandBuffer *cb,
- QRhiRenderTarget *rt,
- const QColor &colorClearValue,
- const QRhiDepthStencilClearValue &depthStencilClearValue,
- QRhiResourceUpdateBatch *resourceUpdates,
- QRhiCommandBuffer::BeginPassFlags flags) override;
- void endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
-
- void setGraphicsPipeline(QRhiCommandBuffer *cb,
- QRhiGraphicsPipeline *ps) override;
-
- void setShaderResources(QRhiCommandBuffer *cb,
- QRhiShaderResourceBindings *srb,
- int dynamicOffsetCount,
- const QRhiCommandBuffer::DynamicOffset *dynamicOffsets) override;
-
- void setVertexInput(QRhiCommandBuffer *cb,
- int startBinding, int bindingCount, const QRhiCommandBuffer::VertexInput *bindings,
- QRhiBuffer *indexBuf, quint32 indexOffset,
- QRhiCommandBuffer::IndexFormat indexFormat) override;
-
- void setViewport(QRhiCommandBuffer *cb, const QRhiViewport &viewport) override;
- void setScissor(QRhiCommandBuffer *cb, const QRhiScissor &scissor) override;
- void setBlendConstants(QRhiCommandBuffer *cb, const QColor &c) override;
- void setStencilRef(QRhiCommandBuffer *cb, quint32 refValue) override;
-
- void draw(QRhiCommandBuffer *cb, quint32 vertexCount,
- quint32 instanceCount, quint32 firstVertex, quint32 firstInstance) override;
-
- void drawIndexed(QRhiCommandBuffer *cb, quint32 indexCount,
- quint32 instanceCount, quint32 firstIndex,
- qint32 vertexOffset, quint32 firstInstance) override;
-
- void debugMarkBegin(QRhiCommandBuffer *cb, const QByteArray &name) override;
- void debugMarkEnd(QRhiCommandBuffer *cb) override;
- void debugMarkMsg(QRhiCommandBuffer *cb, const QByteArray &msg) override;
-
- void beginComputePass(QRhiCommandBuffer *cb,
- QRhiResourceUpdateBatch *resourceUpdates,
- QRhiCommandBuffer::BeginPassFlags flags) override;
- void endComputePass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates) override;
- void setComputePipeline(QRhiCommandBuffer *cb, QRhiComputePipeline *ps) override;
- void dispatch(QRhiCommandBuffer *cb, int x, int y, int z) override;
-
- const QRhiNativeHandles *nativeHandles(QRhiCommandBuffer *cb) override;
- void beginExternal(QRhiCommandBuffer *cb) override;
- void endExternal(QRhiCommandBuffer *cb) override;
-
- QList<int> supportedSampleCounts() const override;
- int ubufAlignment() const override;
- bool isYUpInFramebuffer() const override;
- bool isYUpInNDC() const override;
- bool isClipDepthZeroToOne() const override;
- QMatrix4x4 clipSpaceCorrMatrix() const override;
- bool isTextureFormatSupported(QRhiTexture::Format format, QRhiTexture::Flags flags) const override;
- bool isFeatureSupported(QRhi::Feature feature) const override;
- int resourceLimit(QRhi::ResourceLimit limit) const override;
- const QRhiNativeHandles *nativeHandles() override;
- QRhiDriverInfo driverInfo() const override;
- QRhiStats statistics() override;
- bool makeThreadLocalNativeContextCurrent() override;
- void releaseCachedResources() override;
- bool isDeviceLost() const override;
-
- QByteArray pipelineCacheData() override;
- void setPipelineCacheData(const QByteArray &data) override;
-
- VkResult createDescriptorPool(VkDescriptorPool *pool);
- bool allocateDescriptorSet(VkDescriptorSetAllocateInfo *allocInfo, VkDescriptorSet *result, int *resultPoolIndex);
- uint32_t chooseTransientImageMemType(VkImage img, uint32_t startIndex);
- bool createTransientImage(VkFormat format, const QSize &pixelSize, VkImageUsageFlags usage,
- VkImageAspectFlags aspectMask, VkSampleCountFlagBits samples,
- VkDeviceMemory *mem, VkImage *images, VkImageView *views, int count);
-
- bool recreateSwapChain(QRhiSwapChain *swapChain);
- void releaseSwapChainResources(QRhiSwapChain *swapChain);
-
- VkFormat optimalDepthStencilFormat();
- VkSampleCountFlagBits effectiveSampleCount(int sampleCount);
- bool createDefaultRenderPass(QVkRenderPassDescriptor *rpD,
- bool hasDepthStencil,
- VkSampleCountFlagBits samples,
- VkFormat colorFormat);
- bool createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
- const QRhiColorAttachment *firstColorAttachment,
- const QRhiColorAttachment *lastColorAttachment,
- bool preserveColor,
- bool preserveDs,
- QRhiRenderBuffer *depthStencilBuffer,
- QRhiTexture *depthTexture);
- bool ensurePipelineCache(const void *initialData = nullptr, size_t initialDataSize = 0);
- VkShaderModule createShader(const QByteArray &spirv);
-
- void prepareNewFrame(QRhiCommandBuffer *cb);
- VkCommandBuffer startSecondaryCommandBuffer(QVkRenderTargetData *rtD = nullptr);
- void endAndEnqueueSecondaryCommandBuffer(VkCommandBuffer cb, QVkCommandBuffer *cbD);
- QRhi::FrameOpResult startPrimaryCommandBuffer(VkCommandBuffer *cb);
- QRhi::FrameOpResult endAndSubmitPrimaryCommandBuffer(VkCommandBuffer cb, VkFence cmdFence,
- VkSemaphore *waitSem, VkSemaphore *signalSem);
- void waitCommandCompletion(int frameSlot);
- VkDeviceSize subresUploadByteSize(const QRhiTextureSubresourceUploadDescription &subresDesc) const;
- using BufferImageCopyList = QVarLengthArray<VkBufferImageCopy, 16>;
- void prepareUploadSubres(QVkTexture *texD, int layer, int level,
- const QRhiTextureSubresourceUploadDescription &subresDesc,
- size_t *curOfs, void *mp,
- BufferImageCopyList *copyInfos);
- void enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates);
- void executeBufferHostWritesForSlot(QVkBuffer *bufD, int slot);
- void enqueueTransitionPassResources(QVkCommandBuffer *cbD);
- void recordPrimaryCommandBuffer(QVkCommandBuffer *cbD);
- void trackedRegisterBuffer(QRhiPassResourceTracker *passResTracker,
- QVkBuffer *bufD,
- int slot,
- QRhiPassResourceTracker::BufferAccess access,
- QRhiPassResourceTracker::BufferStage stage);
- void trackedRegisterTexture(QRhiPassResourceTracker *passResTracker,
- QVkTexture *texD,
- QRhiPassResourceTracker::TextureAccess access,
- QRhiPassResourceTracker::TextureStage stage);
- void recordTransitionPassResources(QVkCommandBuffer *cbD, const QRhiPassResourceTracker &tracker);
- void activateTextureRenderTarget(QVkCommandBuffer *cbD, QVkTextureRenderTarget *rtD);
- void executeDeferredReleases(bool forced = false);
- void finishActiveReadbacks(bool forced = false);
-
- void setObjectName(uint64_t object, VkObjectType type, const QByteArray &name, int slot = -1);
- void trackedBufferBarrier(QVkCommandBuffer *cbD, QVkBuffer *bufD, int slot,
- VkAccessFlags access, VkPipelineStageFlags stage);
- void trackedImageBarrier(QVkCommandBuffer *cbD, QVkTexture *texD,
- VkImageLayout layout, VkAccessFlags access, VkPipelineStageFlags stage);
- void depthStencilExplicitBarrier(QVkCommandBuffer *cbD, QVkRenderBuffer *rbD);
- void subresourceBarrier(QVkCommandBuffer *cbD, VkImage image,
- VkImageLayout oldLayout, VkImageLayout newLayout,
- VkAccessFlags srcAccess, VkAccessFlags dstAccess,
- VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage,
- int startLayer, int layerCount,
- int startLevel, int levelCount);
- void updateShaderResourceBindings(QRhiShaderResourceBindings *srb, int descSetIdx = -1);
- void ensureCommandPoolForNewFrame();
-
- QVulkanInstance *inst = nullptr;
- QWindow *maybeWindow = nullptr;
- QByteArrayList requestedDeviceExtensions;
- bool importedDevice = false;
- VkPhysicalDevice physDev = VK_NULL_HANDLE;
- VkDevice dev = VK_NULL_HANDLE;
- VkCommandPool cmdPool[QVK_FRAMES_IN_FLIGHT] = {};
- quint32 gfxQueueFamilyIdx = 0;
- quint32 gfxQueueIdx = 0;
- VkQueue gfxQueue = VK_NULL_HANDLE;
- quint32 timestampValidBits = 0;
- bool importedAllocator = false;
- QVkAllocator allocator = nullptr;
- QVulkanFunctions *f = nullptr;
- QVulkanDeviceFunctions *df = nullptr;
- QRhi::Flags rhiFlags;
- VkPhysicalDeviceFeatures physDevFeatures;
- VkPhysicalDeviceProperties physDevProperties;
- VkDeviceSize ubufAlign;
- VkDeviceSize texbufAlign;
- bool deviceLost = false;
- bool releaseCachedResourcesCalledBeforeFrameStart = false;
-
-#ifdef VK_EXT_debug_utils
- PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT = nullptr;
- PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT = nullptr;
- PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT = nullptr;
- PFN_vkCmdInsertDebugUtilsLabelEXT vkCmdInsertDebugUtilsLabelEXT = nullptr;
-#endif
-
- PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR = nullptr;
- PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR;
- PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR;
- PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR;
- PFN_vkQueuePresentKHR vkQueuePresentKHR;
- PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
- PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR;
- PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR;
-
- struct {
- bool compute = false;
- bool wideLines = false;
- bool debugUtils = false;
- bool vertexAttribDivisor = false;
- bool texture3DSliceAs2D = false;
- bool tessellation = false;
- bool geometryShader = false;
- bool nonFillPolygonMode = false;
- QVersionNumber apiVersion;
- } caps;
-
- VkPipelineCache pipelineCache = VK_NULL_HANDLE;
- struct DescriptorPoolData {
- DescriptorPoolData() { }
- DescriptorPoolData(VkDescriptorPool pool_)
- : pool(pool_)
- { }
- VkDescriptorPool pool = VK_NULL_HANDLE;
- int refCount = 0;
- int allocedDescSets = 0;
- };
- QVarLengthArray<DescriptorPoolData, 8> descriptorPools;
- QVarLengthArray<VkCommandBuffer, 4> freeSecondaryCbs[QVK_FRAMES_IN_FLIGHT];
-
- VkQueryPool timestampQueryPool = VK_NULL_HANDLE;
- QBitArray timestampQueryPoolMap;
-
- VkFormat optimalDsFormat = VK_FORMAT_UNDEFINED;
- QMatrix4x4 clipCorrectMatrix;
-
- QVkSwapChain *currentSwapChain = nullptr;
- QSet<QVkSwapChain *> swapchains;
- QRhiVulkanNativeHandles nativeHandlesStruct;
- QRhiDriverInfo driverInfoStruct;
-
- struct OffscreenFrame {
- OffscreenFrame(QRhiImplementation *rhi)
- {
- for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
- cbWrapper[i] = new QVkCommandBuffer(rhi);
- }
- ~OffscreenFrame()
- {
- for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
- delete cbWrapper[i];
- }
- bool active = false;
- QVkCommandBuffer *cbWrapper[QVK_FRAMES_IN_FLIGHT];
- VkFence cmdFence = VK_NULL_HANDLE;
- } ofr;
-
- struct TextureReadback {
- int activeFrameSlot = -1;
- QRhiReadbackDescription desc;
- QRhiReadbackResult *result;
- VkBuffer stagingBuf;
- QVkAlloc stagingAlloc;
- quint32 byteSize;
- QSize pixelSize;
- QRhiTexture::Format format;
- };
- QVarLengthArray<TextureReadback, 2> activeTextureReadbacks;
- struct BufferReadback {
- int activeFrameSlot = -1;
- QRhiBufferReadbackResult *result;
- quint32 byteSize;
- VkBuffer stagingBuf;
- QVkAlloc stagingAlloc;
- };
- QVarLengthArray<BufferReadback, 2> activeBufferReadbacks;
-
- struct DeferredReleaseEntry {
- enum Type {
- Pipeline,
- ShaderResourceBindings,
- Buffer,
- RenderBuffer,
- Texture,
- Sampler,
- TextureRenderTarget,
- RenderPass,
- StagingBuffer,
- SecondaryCommandBuffer
- };
- Type type;
- int lastActiveFrameSlot; // -1 if not used otherwise 0..FRAMES_IN_FLIGHT-1
- union {
- struct {
- VkPipeline pipeline;
- VkPipelineLayout layout;
- } pipelineState;
- struct {
- int poolIndex;
- VkDescriptorSetLayout layout;
- } shaderResourceBindings;
- struct {
- VkBuffer buffers[QVK_FRAMES_IN_FLIGHT];
- QVkAlloc allocations[QVK_FRAMES_IN_FLIGHT];
- VkBuffer stagingBuffers[QVK_FRAMES_IN_FLIGHT];
- QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT];
- } buffer;
- struct {
- VkDeviceMemory memory;
- VkImage image;
- VkImageView imageView;
- } renderBuffer;
- struct {
- VkImage image;
- VkImageView imageView;
- QVkAlloc allocation;
- VkBuffer stagingBuffers[QVK_FRAMES_IN_FLIGHT];
- QVkAlloc stagingAllocations[QVK_FRAMES_IN_FLIGHT];
- VkImageView extraImageViews[QRhi::MAX_MIP_LEVELS];
- } texture;
- struct {
- VkSampler sampler;
- } sampler;
- struct {
- VkFramebuffer fb;
- VkImageView rtv[QVkRenderTargetData::MAX_COLOR_ATTACHMENTS];
- VkImageView resrtv[QVkRenderTargetData::MAX_COLOR_ATTACHMENTS];
- } textureRenderTarget;
- struct {
- VkRenderPass rp;
- } renderPass;
- struct {
- VkBuffer stagingBuffer;
- QVkAlloc stagingAllocation;
- } stagingBuffer;
- struct {
- VkCommandBuffer cb;
- } secondaryCommandBuffer;
- };
- };
- QList<DeferredReleaseEntry> releaseQueue;
-};
-
-Q_DECLARE_TYPEINFO(QRhiVulkan::DescriptorPoolData, Q_RELOCATABLE_TYPE);
-Q_DECLARE_TYPEINFO(QRhiVulkan::DeferredReleaseEntry, Q_RELOCATABLE_TYPE);
-Q_DECLARE_TYPEINFO(QRhiVulkan::TextureReadback, Q_RELOCATABLE_TYPE);
-Q_DECLARE_TYPEINFO(QRhiVulkan::BufferReadback, Q_RELOCATABLE_TYPE);
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/gui/rhi/qrhivulkanext_p.h b/src/gui/rhi/qrhivulkanext_p.h
deleted file mode 100644
index 02b346948b..0000000000
--- a/src/gui/rhi/qrhivulkanext_p.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QRHIVULKANEXT_P_H
-#define QRHIVULKANEXT_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 "qrhivulkan_p.h"
-
-QT_BEGIN_NAMESPACE
-
-#ifndef VK_EXT_vertex_attribute_divisor
-#define VK_EXT_vertex_attribute_divisor 1
-#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 2
-#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor"
-
-typedef struct VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT {
- VkStructureType sType;
- void* pNext;
- uint32_t maxVertexAttribDivisor;
-} VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT;
-
-typedef struct VkVertexInputBindingDivisorDescriptionEXT {
- uint32_t binding;
- uint32_t divisor;
-} VkVertexInputBindingDivisorDescriptionEXT;
-
-typedef struct VkPipelineVertexInputDivisorStateCreateInfoEXT {
- VkStructureType sType;
- const void* pNext;
- uint32_t vertexBindingDivisorCount;
- const VkVertexInputBindingDivisorDescriptionEXT* pVertexBindingDivisors;
-} VkPipelineVertexInputDivisorStateCreateInfoEXT;
-#endif // VK_EXT_vertex_attribute_divisor
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/gui/rhi/qshader.cpp b/src/gui/rhi/qshader.cpp
index 52cb503521..d5fb53e7e6 100644
--- a/src/gui/rhi/qshader.cpp
+++ b/src/gui/rhi/qshader.cpp
@@ -1,7 +1,7 @@
-// Copyright (C) 2019 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qshader_p_p.h"
+#include "qshader_p.h"
#include <QDataStream>
#include <QBuffer>
@@ -9,8 +9,9 @@ QT_BEGIN_NAMESPACE
/*!
\class QShader
- \internal
+ \ingroup painting-3D
\inmodule QtGui
+ \since 6.6
\brief Contains multiple versions of a shader translated to multiple shading languages,
together with reflection metadata.
@@ -21,6 +22,16 @@ QT_BEGIN_NAMESPACE
as, Vulkan, Metal, Direct3D, and OpenGL, take QShader as their input
whenever a shader needs to be specified.
+ \warning The QRhi family of classes in the Qt Gui module, including QShader
+ and QShaderDescription, offer limited compatibility guarantees. There are
+ no source or binary compatibility guarantees for these classes, meaning the
+ API is only guaranteed to work with the Qt version the application was
+ developed against. Source incompatible changes are however aimed to be kept
+ at a minimum and will only be made in minor releases (6.7, 6.8, and so on).
+ To use these classes in an application, link to
+ \c{Qt::GuiPrivate} (if using CMake), and include the headers with the \c
+ rhi prefix, for example \c{#include <rhi/qshader.h>}.
+
A QShader instance is empty and thus invalid by default. To get a useful
instance, the two typical methods are:
@@ -68,8 +79,9 @@ QT_BEGIN_NAMESPACE
can be returned or passed by value. Detach happens implicitly when calling
a setter.
- For reference, QRhi expects that a QShader suitable for all its
- backends contains at least the following:
+ For reference, a typical, portable QRhi expects that a QShader suitable for
+ all its backends contains at least the following. (this excludes support
+ for core profile OpenGL contexts, add GLSL 150 or newer for that)
\list
@@ -77,11 +89,11 @@ QT_BEGIN_NAMESPACE
\li GLSL/ES 100 source code suitable for OpenGL ES 2.0 or newer
- \li GLSL 120 source code suitable for OpenGL 2.1
+ \li GLSL 120 source code suitable for OpenGL 2.1 or newer
- \li HLSL Shader Model 5.0 source code or the corresponding DXBC bytecode suitable for Direct3D 11
+ \li HLSL Shader Model 5.0 source code or the corresponding DXBC bytecode suitable for Direct3D 11/12
- \li Metal Shading Language 1.2 source code or the corresponding bytecode suitable for Metal
+ \li Metal Shading Language 1.2 source code or the corresponding bytecode suitable for Metal 1.2 or newer
\endlist
@@ -102,8 +114,8 @@ QT_BEGIN_NAMESPACE
/*!
\class QShaderVersion
- \internal
\inmodule QtGui
+ \since 6.6
\brief Specifies the shading language version.
@@ -128,6 +140,9 @@ QT_BEGIN_NAMESPACE
A default constructed QShaderVersion contains a version of 100 and no
flags set.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QShader
+ for details.
*/
/*!
@@ -140,13 +155,16 @@ QT_BEGIN_NAMESPACE
/*!
\class QShaderKey
- \internal
\inmodule QtGui
+ \since 6.6
\brief Specifies the shading language, the version with flags, and the variant.
A default constructed QShaderKey has source set to SpirvShader and
sourceVersion set to 100. sourceVariant defaults to StandardShader.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QShader
+ for details.
*/
/*!
@@ -196,14 +214,39 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \enum QShader::SerializedFormatVersion
+ Describes the desired output format when serializing the QShader.
+
+ The default value for the \c version argument of serialized() is \c Latest.
+ This is sufficient in the vast majority of cases. Specifying another value
+ is needed only when the intention is to generate serialized data that can
+ be loaded by earlier Qt versions. For example, the \c qsb tool uses these
+ enum values when the \c{--qsbversion} command-line argument is given.
+
+ \note Targeting earlier versions will make certain features disfunctional
+ with the generated asset. This is not an issue when using the asset with
+ the specified, older Qt version, given that that Qt version does not have
+ the newer features in newer Qt versions that rely on additional data
+ generated in the QShader and the serialized data stream, but may become a
+ problem if the generated asset is then used with a newer Qt version.
+
+ \value Latest The current Qt version
+ \value Qt_6_5 Qt 6.5
+ \value Qt_6_4 Qt 6.4
+ */
+
+/*!
\class QShaderCode
- \internal
\inmodule QtGui
+ \since 6.6
\brief Contains source or binary code for a shader and additional metadata.
When shader() is empty after retrieving a QShaderCode instance from
QShader, it indicates no shader code was found for the requested key.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QShader
+ for details.
*/
/*!
@@ -226,7 +269,7 @@ void QShader::detach()
}
/*!
- \internal
+ Constructs a copy of \a other.
*/
QShader::QShader(const QShader &other)
: d(other.d)
@@ -236,7 +279,7 @@ QShader::QShader(const QShader &other)
}
/*!
- \internal
+ Assigns \a other to this object.
*/
QShader &QShader::operator=(const QShader &other)
{
@@ -256,6 +299,28 @@ QShader &QShader::operator=(const QShader &other)
}
/*!
+ \fn QShader::QShader(QShader &&other) noexcept
+ \since 6.7
+
+ Move-constructs a new QShader from \a other.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new value.
+*/
+
+/*!
+ \fn QShader &QShader::operator=(QShader &&other)
+ \since 6.7
+
+ Move-assigns \a other to this QShader instance.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new value.
+*/
+
+/*!
Destructor.
*/
QShader::~QShader()
@@ -265,6 +330,14 @@ QShader::~QShader()
}
/*!
+ \fn void QShader::swap(QShader &other)
+ \since 6.7
+
+ Swaps shader \a other with this shader. This operation is very fast and
+ never fails.
+*/
+
+/*!
\return true if the QShader contains at least one shader version.
*/
bool QShader::isValid() const
@@ -366,7 +439,11 @@ static void writeShaderKey(QDataStream *ds, const QShaderKey &k)
QShader, suitable for writing to files or other I/O devices.
By default the latest serialization format is used. Use \a version
- parameter to serialize for a compatibility Qt version.
+ parameter to serialize for a compatibility Qt version. Only when it is
+ known that the generated data stream must be made compatible with an older
+ Qt version at the expense of making it incompatible with features
+ introduced since that Qt version, should another value (for example,
+ \l{SerializedFormatVersion}{Qt_6_5} for Qt 6.5) be used.
\sa fromSerialized()
*/
@@ -455,6 +532,9 @@ static void readShaderKey(QDataStream *ds, QShaderKey *k)
/*!
Creates a new QShader instance from the given \a data.
+ If \a data cannot be deserialized successfully, the result is a default
+ constructed QShader for which isValid() returns \c false.
+
\sa serialized()
*/
QShader QShader::fromSerialized(const QByteArray &data)
@@ -577,16 +657,79 @@ QShader QShader::fromSerialized(const QByteArray &data)
return bs;
}
+/*!
+ \fn QShaderVersion::QShaderVersion() = default
+ */
+
+/*!
+ Constructs a new QShaderVersion with version \a v and flags \a f.
+ */
QShaderVersion::QShaderVersion(int v, Flags f)
: m_version(v), m_flags(f)
{
}
+/*!
+ \fn int QShaderVersion::version() const
+ \return the version.
+ */
+
+/*!
+ \fn void QShaderVersion::setVersion(int v)
+ Sets the shading language version to \a v.
+ */
+
+/*!
+ \fn QShaderVersion::Flags QShaderVersion::flags() const
+ \return the flags.
+ */
+
+/*!
+ \fn void QShaderVersion::setFlags(Flags f)
+ Sets the flags \a f.
+ */
+
+/*!
+ \fn QShaderCode::QShaderCode() = default
+ */
+
+/*!
+ Constructs a new QShaderCode with the specified shader source \a code and
+ \a entry point name.
+ */
QShaderCode::QShaderCode(const QByteArray &code, const QByteArray &entry)
: m_shader(code), m_entryPoint(entry)
{
}
+/*!
+ \fn QByteArray QShaderCode::shader() const
+ \return the shader source or bytecode.
+ */
+
+/*!
+ \fn void QShaderCode::setShader(const QByteArray &code)
+ Sets the shader source or byte \a code.
+ */
+
+/*!
+ \fn QByteArray QShaderCode::entryPoint() const
+ \return the entry point name.
+ */
+
+/*!
+ \fn void QShaderCode::setEntryPoint(const QByteArray &entry)
+ Sets the \a entry point name.
+ */
+
+/*!
+ \fn QShaderKey::QShaderKey() = default
+ */
+
+/*!
+ Constructs a new QShaderKey with shader type \a s, version \a sver, and
+ variant \a svar.
+ */
QShaderKey::QShaderKey(QShader::Source s,
const QShaderVersion &sver,
QShader::Variant svar)
@@ -597,6 +740,36 @@ QShaderKey::QShaderKey(QShader::Source s,
}
/*!
+ \fn QShader::Source QShaderKey::source() const
+ \return the shader type.
+ */
+
+/*!
+ \fn void QShaderKey::setSource(QShader::Source s)
+ Sets the shader type \a s.
+ */
+
+/*!
+ \fn QShaderVersion QShaderKey::sourceVersion() const
+ \return the shading language version.
+ */
+
+/*!
+ \fn void QShaderKey::setSourceVersion(const QShaderVersion &sver)
+ Sets the shading language version \a sver.
+ */
+
+/*!
+ \fn QShader::Variant QShaderKey::sourceVariant() const
+ \return the type of the variant to use.
+ */
+
+/*!
+ \fn void QShaderKey::setSourceVariant(QShader::Variant svar)
+ Sets the type of variant to use to \a svar.
+ */
+
+/*!
Returns \c true if the two QShader objects \a lhs and \a rhs are equal,
meaning they are for the same stage with matching sets of shader source or
binary code.
@@ -614,10 +787,9 @@ bool operator==(const QShader &lhs, const QShader &rhs) noexcept
}
/*!
- \internal
\fn bool operator!=(const QShader &lhs, const QShader &rhs)
- Returns \c false if the values in the two QShader objects \a a and \a b
+ Returns \c false if the values in the two QShader objects \a lhs and \a rhs
are equal; otherwise returns \c true.
\relates QShader
@@ -635,7 +807,7 @@ size_t qHash(const QShader &s, size_t seed) noexcept
seed = hash(seed, s.stage());
if (!s.d->shaders.isEmpty()) {
seed = hash(seed, s.d->shaders.firstKey());
- seed = hash(seed, s.d->shaders.first());
+ seed = hash(seed, std::as_const(s.d->shaders).first());
}
}
return seed;
@@ -660,6 +832,8 @@ size_t qHash(const QShaderVersion &s, size_t seed) noexcept
#endif
/*!
+ \return true if \a lhs is smaller than \a rhs.
+
Establishes a sorting order between the two QShaderVersion \a lhs and \a rhs.
\relates QShaderVersion
@@ -676,11 +850,10 @@ bool operator<(const QShaderVersion &lhs, const QShaderVersion &rhs) noexcept
}
/*!
- \internal
\fn bool operator!=(const QShaderVersion &lhs, const QShaderVersion &rhs)
- Returns \c false if the values in the two QShaderVersion objects \a a
- and \a b are equal; otherwise returns \c true.
+ Returns \c false if the values in the two QShaderVersion objects \a lhs
+ and \a rhs are equal; otherwise returns \c true.
\relates QShaderVersion
*/
@@ -697,6 +870,8 @@ bool operator==(const QShaderKey &lhs, const QShaderKey &rhs) noexcept
}
/*!
+ \return true if \a lhs is smaller than \a rhs.
+
Establishes a sorting order between the two keys \a lhs and \a rhs.
\relates QShaderKey
@@ -719,11 +894,10 @@ bool operator<(const QShaderKey &lhs, const QShaderKey &rhs) noexcept
}
/*!
- \internal
\fn bool operator!=(const QShaderKey &lhs, const QShaderKey &rhs)
- Returns \c false if the values in the two QShaderKey objects \a a
- and \a b are equal; otherwise returns \c true.
+ Returns \c false if the values in the two QShaderKey objects \a lhs
+ and \a rhs are equal; otherwise returns \c true.
\relates QShaderKey
*/
@@ -753,11 +927,10 @@ bool operator==(const QShaderCode &lhs, const QShaderCode &rhs) noexcept
}
/*!
- \internal
\fn bool operator!=(const QShaderCode &lhs, const QShaderCode &rhs)
- Returns \c false if the values in the two QShaderCode objects \a a
- and \a b are equal; otherwise returns \c true.
+ Returns \c false if the values in the two QShaderCode objects \a lhs
+ and \a rhs are equal; otherwise returns \c true.
\relates QShaderCode
*/
@@ -895,6 +1068,8 @@ void QShader::removeResourceBindingMap(const QShaderKey &key)
/*!
\struct QShader::SeparateToCombinedImageSamplerMapping
+ \inmodule QtGui
+ \brief Mapping metadata for sampler uniforms.
Describes a mapping from a traditional combined image sampler uniform to
binding points for a separate texture and sampler.
@@ -904,9 +1079,24 @@ void QShader::removeResourceBindingMap(const QShaderKey &key)
contains a \c sampler2D (or sampler3D, etc.) uniform with the name of
\c{_54} which corresponds to two separate resource bindings (\c 1 and \c 2)
in the original shader.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QShader
+ for details.
*/
/*!
+ \variable QShader::SeparateToCombinedImageSamplerMapping::combinedSamplerName
+*/
+
+/*!
+ \variable QShader::SeparateToCombinedImageSamplerMapping::textureBinding
+*/
+
+/*!
+ \variable QShader::SeparateToCombinedImageSamplerMapping::samplerBinding
+*/
+
+/*!
\return the combined image sampler mapping list for \a key, or an empty
list if there is no data available for \a key, for example because such a
mapping is not applicable for the shading language.
@@ -953,6 +1143,8 @@ void QShader::removeSeparateToCombinedImageSamplerMappingList(const QShaderKey &
/*!
\struct QShader::NativeShaderInfo
+ \inmodule QtGui
+ \brief Additional metadata about the native shader code.
Describes information about the native shader code, if applicable. This
becomes relevant with certain shader languages for certain shader stages,
@@ -969,9 +1161,20 @@ void QShader::removeSeparateToCombinedImageSamplerMappingList(const QShaderKey &
not be present at all if per-patch output variables were not used. The fact
that the shader code relies on such a buffer present can be indicated by
the data in this struct.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QShader
+ for details.
*/
/*!
+ \variable QShader::NativeShaderInfo::flags
+*/
+
+/*!
+ \variable QShader::NativeShaderInfo::extraBufferBindings
+*/
+
+/*!
\return the native shader info struct for \a key, or an empty object if
there is no data available for \a key, for example because such a mapping
is not applicable for the shading language or the shader stage.
diff --git a/src/gui/rhi/qshader.h b/src/gui/rhi/qshader.h
new file mode 100644
index 0000000000..2465081366
--- /dev/null
+++ b/src/gui/rhi/qshader.h
@@ -0,0 +1,241 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSHADER_H
+#define QSHADER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is part of the RHI API, with limited compatibility guarantees.
+// Usage of this API may make your code source and binary incompatible with
+// future versions of Qt.
+//
+
+#include <QtGui/qtguiglobal.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qmap.h>
+#include <rhi/qshaderdescription.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QShaderPrivate;
+class QShaderKey;
+
+#ifdef Q_OS_INTEGRITY
+ class QShaderVersion;
+ size_t qHash(const QShaderVersion &, size_t = 0) noexcept;
+#endif
+
+class Q_GUI_EXPORT QShaderVersion
+{
+public:
+ enum Flag {
+ GlslEs = 0x01
+ };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ QShaderVersion() = default;
+ QShaderVersion(int v, Flags f = Flags());
+
+ int version() const { return m_version; }
+ void setVersion(int v) { m_version = v; }
+
+ Flags flags() const { return m_flags; }
+ void setFlags(Flags f) { m_flags = f; }
+
+private:
+ int m_version = 100;
+ Flags m_flags;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderVersion::Flags)
+Q_DECLARE_TYPEINFO(QShaderVersion, Q_RELOCATABLE_TYPE);
+
+class QShaderCode;
+Q_GUI_EXPORT size_t qHash(const QShaderCode &, size_t = 0) noexcept;
+
+class Q_GUI_EXPORT QShaderCode
+{
+public:
+ QShaderCode() = default;
+ QShaderCode(const QByteArray &code, const QByteArray &entry = QByteArray());
+
+ QByteArray shader() const { return m_shader; }
+ void setShader(const QByteArray &code) { m_shader = code; }
+
+ QByteArray entryPoint() const { return m_entryPoint; }
+ void setEntryPoint(const QByteArray &entry) { m_entryPoint = entry; }
+
+private:
+ friend Q_GUI_EXPORT size_t qHash(const QShaderCode &, size_t) noexcept;
+
+ QByteArray m_shader;
+ QByteArray m_entryPoint;
+};
+
+Q_DECLARE_TYPEINFO(QShaderCode, Q_RELOCATABLE_TYPE);
+
+class Q_GUI_EXPORT QShader
+{
+public:
+ enum Stage {
+ VertexStage = 0,
+ TessellationControlStage,
+ TessellationEvaluationStage,
+ GeometryStage,
+ FragmentStage,
+ ComputeStage
+ };
+
+ enum Source {
+ SpirvShader = 0,
+ GlslShader,
+ HlslShader,
+ DxbcShader, // fxc
+ MslShader,
+ DxilShader, // dxc
+ MetalLibShader, // xcrun metal + xcrun metallib
+ WgslShader
+ };
+
+ enum Variant {
+ StandardShader = 0,
+ BatchableVertexShader,
+ UInt16IndexedVertexAsComputeShader,
+ UInt32IndexedVertexAsComputeShader,
+ NonIndexedVertexAsComputeShader
+ };
+
+ enum class SerializedFormatVersion {
+ Latest = 0,
+ Qt_6_5,
+ Qt_6_4
+ };
+
+ QShader();
+ QShader(const QShader &other);
+ QShader &operator=(const QShader &other);
+ QShader(QShader &&other) noexcept : d(std::exchange(other.d, nullptr)) {}
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QShader)
+ ~QShader();
+
+ void swap(QShader &other) noexcept { qt_ptr_swap(d, other.d); }
+ void detach();
+
+ bool isValid() const;
+
+ Stage stage() const;
+ void setStage(Stage stage);
+
+ QShaderDescription description() const;
+ void setDescription(const QShaderDescription &desc);
+
+ QList<QShaderKey> availableShaders() const;
+ QShaderCode shader(const QShaderKey &key) const;
+ void setShader(const QShaderKey &key, const QShaderCode &shader);
+ void removeShader(const QShaderKey &key);
+
+ QByteArray serialized(SerializedFormatVersion version = SerializedFormatVersion::Latest) const;
+ static QShader fromSerialized(const QByteArray &data);
+
+ using NativeResourceBindingMap = QMap<int, QPair<int, int> >; // binding -> native_binding[, native_binding]
+ NativeResourceBindingMap nativeResourceBindingMap(const QShaderKey &key) const;
+ void setResourceBindingMap(const QShaderKey &key, const NativeResourceBindingMap &map);
+ void removeResourceBindingMap(const QShaderKey &key);
+
+ struct SeparateToCombinedImageSamplerMapping {
+ QByteArray combinedSamplerName;
+ int textureBinding;
+ int samplerBinding;
+ };
+ using SeparateToCombinedImageSamplerMappingList = QList<SeparateToCombinedImageSamplerMapping>;
+ SeparateToCombinedImageSamplerMappingList separateToCombinedImageSamplerMappingList(const QShaderKey &key) const;
+ void setSeparateToCombinedImageSamplerMappingList(const QShaderKey &key,
+ const SeparateToCombinedImageSamplerMappingList &list);
+ void removeSeparateToCombinedImageSamplerMappingList(const QShaderKey &key);
+
+ struct NativeShaderInfo {
+ int flags = 0;
+ QMap<int, int> extraBufferBindings;
+ };
+ NativeShaderInfo nativeShaderInfo(const QShaderKey &key) const;
+ void setNativeShaderInfo(const QShaderKey &key, const NativeShaderInfo &info);
+ void removeNativeShaderInfo(const QShaderKey &key);
+
+private:
+ QShaderPrivate *d;
+ friend struct QShaderPrivate;
+ friend Q_GUI_EXPORT bool operator==(const QShader &, const QShader &) noexcept;
+ friend Q_GUI_EXPORT size_t qHash(const QShader &, size_t) noexcept;
+#ifndef QT_NO_DEBUG_STREAM
+ friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QShader &);
+#endif
+};
+
+class Q_GUI_EXPORT QShaderKey
+{
+public:
+ QShaderKey() = default;
+ QShaderKey(QShader::Source s,
+ const QShaderVersion &sver,
+ QShader::Variant svar = QShader::StandardShader);
+
+ QShader::Source source() const { return m_source; }
+ void setSource(QShader::Source s) { m_source = s; }
+
+ QShaderVersion sourceVersion() const { return m_sourceVersion; }
+ void setSourceVersion(const QShaderVersion &sver) { m_sourceVersion = sver; }
+
+ QShader::Variant sourceVariant() const { return m_sourceVariant; }
+ void setSourceVariant(QShader::Variant svar) { m_sourceVariant = svar; }
+
+private:
+ QShader::Source m_source = QShader::SpirvShader;
+ QShaderVersion m_sourceVersion;
+ QShader::Variant m_sourceVariant = QShader::StandardShader;
+};
+
+Q_DECLARE_TYPEINFO(QShaderKey, Q_RELOCATABLE_TYPE);
+
+Q_GUI_EXPORT bool operator==(const QShader &lhs, const QShader &rhs) noexcept;
+Q_GUI_EXPORT size_t qHash(const QShader &s, size_t seed = 0) noexcept;
+
+inline bool operator!=(const QShader &lhs, const QShader &rhs) noexcept
+{
+ return !(lhs == rhs);
+}
+
+Q_GUI_EXPORT bool operator==(const QShaderVersion &lhs, const QShaderVersion &rhs) noexcept;
+Q_GUI_EXPORT bool operator<(const QShaderVersion &lhs, const QShaderVersion &rhs) noexcept;
+Q_GUI_EXPORT bool operator==(const QShaderKey &lhs, const QShaderKey &rhs) noexcept;
+Q_GUI_EXPORT bool operator<(const QShaderKey &lhs, const QShaderKey &rhs) noexcept;
+Q_GUI_EXPORT bool operator==(const QShaderCode &lhs, const QShaderCode &rhs) noexcept;
+
+inline bool operator!=(const QShaderVersion &lhs, const QShaderVersion &rhs) noexcept
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const QShaderKey &lhs, const QShaderKey &rhs) noexcept
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const QShaderCode &lhs, const QShaderCode &rhs) noexcept
+{
+ return !(lhs == rhs);
+}
+
+Q_GUI_EXPORT size_t qHash(const QShaderKey &k, size_t seed = 0) noexcept;
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QShader &);
+Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QShaderKey &k);
+Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QShaderVersion &v);
+#endif
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/gui/rhi/qshader_p.h b/src/gui/rhi/qshader_p.h
index f85b075a83..f77bcb1259 100644
--- a/src/gui/rhi/qshader_p.h
+++ b/src/gui/rhi/qshader_p.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2019 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QSHADER_P_H
@@ -15,225 +15,77 @@
// We mean it.
//
-#include <QtGui/qtguiglobal.h>
-#include <QtCore/qhash.h>
-#include <QtCore/qmap.h>
-#include <private/qshaderdescription_p.h>
+#include <rhi/qshader.h>
+#include <QtCore/QAtomicInt>
+#include <QtCore/QMap>
+#include <QtCore/QDebug>
QT_BEGIN_NAMESPACE
-struct QShaderPrivate;
-class QShaderKey;
-
-#ifdef Q_OS_INTEGRITY
- class QShaderVersion;
- size_t qHash(const QShaderVersion &, size_t = 0) noexcept;
-#endif
-
-class Q_GUI_EXPORT QShaderVersion
-{
-public:
- enum Flag {
- GlslEs = 0x01
- };
- Q_DECLARE_FLAGS(Flags, Flag)
-
- QShaderVersion() = default;
- QShaderVersion(int v, Flags f = Flags());
-
- int version() const { return m_version; }
- void setVersion(int v) { m_version = v; }
-
- Flags flags() const { return m_flags; }
- void setFlags(Flags f) { m_flags = f; }
-
-private:
- int m_version = 100;
- Flags m_flags;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderVersion::Flags)
-Q_DECLARE_TYPEINFO(QShaderVersion, Q_RELOCATABLE_TYPE);
-
-class QShaderCode;
-Q_GUI_EXPORT size_t qHash(const QShaderCode &, size_t = 0) noexcept;
-
-class Q_GUI_EXPORT QShaderCode
-{
-public:
- QShaderCode() = default;
- QShaderCode(const QByteArray &code, const QByteArray &entry = QByteArray());
-
- QByteArray shader() const { return m_shader; }
- void setShader(const QByteArray &code) { m_shader = code; }
-
- QByteArray entryPoint() const { return m_entryPoint; }
- void setEntryPoint(const QByteArray &entry) { m_entryPoint = entry; }
-
-private:
- friend Q_GUI_EXPORT size_t qHash(const QShaderCode &, size_t) noexcept;
-
- QByteArray m_shader;
- QByteArray m_entryPoint;
-};
-
-Q_DECLARE_TYPEINFO(QShaderCode, Q_RELOCATABLE_TYPE);
-
-class Q_GUI_EXPORT QShader
+struct Q_GUI_EXPORT QShaderPrivate
{
-public:
- enum Stage {
- VertexStage = 0,
- TessellationControlStage,
- TessellationEvaluationStage,
- GeometryStage,
- FragmentStage,
- ComputeStage
- };
-
- enum Source {
- SpirvShader = 0,
- GlslShader,
- HlslShader,
- DxbcShader, // fxc
- MslShader,
- DxilShader, // dxc
- MetalLibShader, // xcrun metal + xcrun metallib
- WgslShader
- };
-
- enum Variant {
- StandardShader = 0,
- BatchableVertexShader,
- UInt16IndexedVertexAsComputeShader,
- UInt32IndexedVertexAsComputeShader,
- NonIndexedVertexAsComputeShader
- };
-
- enum class SerializedFormatVersion {
- Latest = 0,
- Qt_6_5,
- Qt_6_4
- };
-
- QShader();
- QShader(const QShader &other);
- QShader &operator=(const QShader &other);
- ~QShader();
- void detach();
-
- bool isValid() const;
-
- Stage stage() const;
- void setStage(Stage stage);
-
- QShaderDescription description() const;
- void setDescription(const QShaderDescription &desc);
-
- QList<QShaderKey> availableShaders() const;
- QShaderCode shader(const QShaderKey &key) const;
- void setShader(const QShaderKey &key, const QShaderCode &shader);
- void removeShader(const QShaderKey &key);
-
- QByteArray serialized(SerializedFormatVersion version = SerializedFormatVersion::Latest) const;
- static QShader fromSerialized(const QByteArray &data);
-
- using NativeResourceBindingMap = QMap<int, QPair<int, int> >; // binding -> native_binding[, native_binding]
- NativeResourceBindingMap nativeResourceBindingMap(const QShaderKey &key) const;
- void setResourceBindingMap(const QShaderKey &key, const NativeResourceBindingMap &map);
- void removeResourceBindingMap(const QShaderKey &key);
-
- struct SeparateToCombinedImageSamplerMapping {
- QByteArray combinedSamplerName;
- int textureBinding;
- int samplerBinding;
- };
- using SeparateToCombinedImageSamplerMappingList = QList<SeparateToCombinedImageSamplerMapping>;
- SeparateToCombinedImageSamplerMappingList separateToCombinedImageSamplerMappingList(const QShaderKey &key) const;
- void setSeparateToCombinedImageSamplerMappingList(const QShaderKey &key,
- const SeparateToCombinedImageSamplerMappingList &list);
- void removeSeparateToCombinedImageSamplerMappingList(const QShaderKey &key);
-
- struct NativeShaderInfo {
- int flags = 0;
- QMap<int, int> extraBufferBindings;
+ static const int QSB_VERSION = 9;
+ static const int QSB_VERSION_WITHOUT_INPUT_OUTPUT_INTERFACE_BLOCKS = 8;
+ static const int QSB_VERSION_WITHOUT_EXTENDED_STORAGE_BUFFER_INFO = 7;
+ static const int QSB_VERSION_WITHOUT_NATIVE_SHADER_INFO = 6;
+ static const int QSB_VERSION_WITHOUT_SEPARATE_IMAGES_AND_SAMPLERS = 5;
+ static const int QSB_VERSION_WITHOUT_VAR_ARRAYDIMS = 4;
+ static const int QSB_VERSION_WITH_CBOR = 3;
+ static const int QSB_VERSION_WITH_BINARY_JSON = 2;
+ static const int QSB_VERSION_WITHOUT_BINDINGS = 1;
+
+ enum MslNativeShaderInfoExtraBufferBindings {
+ MslTessVertIndicesBufferBinding = 0,
+ MslTessVertTescOutputBufferBinding,
+ MslTessTescTessLevelBufferBinding,
+ MslTessTescPatchOutputBufferBinding,
+ MslTessTescParamsBufferBinding,
+ MslTessTescInputBufferBinding,
+ MslBufferSizeBufferBinding,
+ MslMultiViewMaskBufferBinding
};
- NativeShaderInfo nativeShaderInfo(const QShaderKey &key) const;
- void setNativeShaderInfo(const QShaderKey &key, const NativeShaderInfo &info);
- void removeNativeShaderInfo(const QShaderKey &key);
-
-private:
- QShaderPrivate *d;
- friend struct QShaderPrivate;
- friend Q_GUI_EXPORT bool operator==(const QShader &, const QShader &) noexcept;
- friend Q_GUI_EXPORT size_t qHash(const QShader &, size_t) noexcept;
-#ifndef QT_NO_DEBUG_STREAM
- friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QShader &);
-#endif
-};
-
-class Q_GUI_EXPORT QShaderKey
-{
-public:
- QShaderKey() = default;
- QShaderKey(QShader::Source s,
- const QShaderVersion &sver,
- QShader::Variant svar = QShader::StandardShader);
-
- QShader::Source source() const { return m_source; }
- void setSource(QShader::Source s) { m_source = s; }
-
- QShaderVersion sourceVersion() const { return m_sourceVersion; }
- void setSourceVersion(const QShaderVersion &sver) { m_sourceVersion = sver; }
- QShader::Variant sourceVariant() const { return m_sourceVariant; }
- void setSourceVariant(QShader::Variant svar) { m_sourceVariant = svar; }
-
-private:
- QShader::Source m_source = QShader::SpirvShader;
- QShaderVersion m_sourceVersion;
- QShader::Variant m_sourceVariant = QShader::StandardShader;
+ QShaderPrivate()
+ : ref(1)
+ {
+ }
+
+ QShaderPrivate(const QShaderPrivate &other)
+ : ref(1),
+ qsbVersion(other.qsbVersion),
+ stage(other.stage),
+ desc(other.desc),
+ shaders(other.shaders),
+ bindings(other.bindings),
+ combinedImageMap(other.combinedImageMap),
+ nativeShaderInfoMap(other.nativeShaderInfoMap)
+ {
+ }
+
+ static QShaderPrivate *get(QShader *s) { return s->d; }
+ static const QShaderPrivate *get(const QShader *s) { return s->d; }
+ static int qtQsbVersion(QShader::SerializedFormatVersion qtVersion) {
+ switch (qtVersion) {
+ case QShader::SerializedFormatVersion::Qt_6_4:
+ return (QShaderPrivate::QSB_VERSION_WITHOUT_SEPARATE_IMAGES_AND_SAMPLERS + 1);
+ case QShader::SerializedFormatVersion::Qt_6_5:
+ return (QShaderPrivate::QSB_VERSION_WITHOUT_EXTENDED_STORAGE_BUFFER_INFO + 1);
+ default:
+ return QShaderPrivate::QSB_VERSION;
+ }
+ }
+
+ QAtomicInt ref;
+ int qsbVersion = QSB_VERSION;
+ QShader::Stage stage = QShader::VertexStage;
+ QShaderDescription desc;
+ // QMap not QHash because we need to be able to iterate based on sorted keys
+ QMap<QShaderKey, QShaderCode> shaders;
+ QMap<QShaderKey, QShader::NativeResourceBindingMap> bindings;
+ QMap<QShaderKey, QShader::SeparateToCombinedImageSamplerMappingList> combinedImageMap;
+ QMap<QShaderKey, QShader::NativeShaderInfo> nativeShaderInfoMap;
};
-Q_DECLARE_TYPEINFO(QShaderKey, Q_RELOCATABLE_TYPE);
-
-Q_GUI_EXPORT bool operator==(const QShader &lhs, const QShader &rhs) noexcept;
-Q_GUI_EXPORT size_t qHash(const QShader &s, size_t seed = 0) noexcept;
-
-inline bool operator!=(const QShader &lhs, const QShader &rhs) noexcept
-{
- return !(lhs == rhs);
-}
-
-Q_GUI_EXPORT bool operator==(const QShaderVersion &lhs, const QShaderVersion &rhs) noexcept;
-Q_GUI_EXPORT bool operator<(const QShaderVersion &lhs, const QShaderVersion &rhs) noexcept;
-Q_GUI_EXPORT bool operator==(const QShaderKey &lhs, const QShaderKey &rhs) noexcept;
-Q_GUI_EXPORT bool operator<(const QShaderKey &lhs, const QShaderKey &rhs) noexcept;
-Q_GUI_EXPORT bool operator==(const QShaderCode &lhs, const QShaderCode &rhs) noexcept;
-
-inline bool operator!=(const QShaderVersion &lhs, const QShaderVersion &rhs) noexcept
-{
- return !(lhs == rhs);
-}
-
-inline bool operator!=(const QShaderKey &lhs, const QShaderKey &rhs) noexcept
-{
- return !(lhs == rhs);
-}
-
-inline bool operator!=(const QShaderCode &lhs, const QShaderCode &rhs) noexcept
-{
- return !(lhs == rhs);
-}
-
-Q_GUI_EXPORT size_t qHash(const QShaderKey &k, size_t seed = 0) noexcept;
-
-#ifndef QT_NO_DEBUG_STREAM
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QShader &);
-Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QShaderKey &k);
-Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QShaderVersion &v);
-#endif
-
QT_END_NAMESPACE
#endif
diff --git a/src/gui/rhi/qshader_p_p.h b/src/gui/rhi/qshader_p_p.h
deleted file mode 100644
index 9cc9207f69..0000000000
--- a/src/gui/rhi/qshader_p_p.h
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QSHADER_P_P_H
-#define QSHADER_P_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of a number of Qt sources files. This header file may change from
-// version to version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qshader_p.h"
-#include <QtCore/QAtomicInt>
-#include <QtCore/QMap>
-#include <QtCore/QDebug>
-
-QT_BEGIN_NAMESPACE
-
-struct Q_GUI_EXPORT QShaderPrivate
-{
- static const int QSB_VERSION = 9;
- static const int QSB_VERSION_WITHOUT_INPUT_OUTPUT_INTERFACE_BLOCKS = 8;
- static const int QSB_VERSION_WITHOUT_EXTENDED_STORAGE_BUFFER_INFO = 7;
- static const int QSB_VERSION_WITHOUT_NATIVE_SHADER_INFO = 6;
- static const int QSB_VERSION_WITHOUT_SEPARATE_IMAGES_AND_SAMPLERS = 5;
- static const int QSB_VERSION_WITHOUT_VAR_ARRAYDIMS = 4;
- static const int QSB_VERSION_WITH_CBOR = 3;
- static const int QSB_VERSION_WITH_BINARY_JSON = 2;
- static const int QSB_VERSION_WITHOUT_BINDINGS = 1;
-
- enum MslNativeShaderInfoExtraBufferBindings {
- MslTessVertIndicesBufferBinding = 0,
- MslTessVertTescOutputBufferBinding,
- MslTessTescTessLevelBufferBinding,
- MslTessTescPatchOutputBufferBinding,
- MslTessTescParamsBufferBinding,
- MslTessTescInputBufferBinding,
- MslBufferSizeBufferBinding
- };
-
- QShaderPrivate()
- : ref(1)
- {
- }
-
- QShaderPrivate(const QShaderPrivate &other)
- : ref(1),
- qsbVersion(other.qsbVersion),
- stage(other.stage),
- desc(other.desc),
- shaders(other.shaders),
- bindings(other.bindings),
- combinedImageMap(other.combinedImageMap),
- nativeShaderInfoMap(other.nativeShaderInfoMap)
- {
- }
-
- static QShaderPrivate *get(QShader *s) { return s->d; }
- static const QShaderPrivate *get(const QShader *s) { return s->d; }
- static int qtQsbVersion(QShader::SerializedFormatVersion qtVersion) {
- switch (qtVersion) {
- case QShader::SerializedFormatVersion::Qt_6_4:
- return (QShaderPrivate::QSB_VERSION_WITHOUT_SEPARATE_IMAGES_AND_SAMPLERS + 1);
- case QShader::SerializedFormatVersion::Qt_6_5:
- return (QShaderPrivate::QSB_VERSION_WITHOUT_EXTENDED_STORAGE_BUFFER_INFO + 1);
- default:
- return QShaderPrivate::QSB_VERSION;
- }
- }
-
- QAtomicInt ref;
- int qsbVersion = QSB_VERSION;
- QShader::Stage stage = QShader::VertexStage;
- QShaderDescription desc;
- // QMap not QHash because we need to be able to iterate based on sorted keys
- QMap<QShaderKey, QShaderCode> shaders;
- QMap<QShaderKey, QShader::NativeResourceBindingMap> bindings;
- QMap<QShaderKey, QShader::SeparateToCombinedImageSamplerMappingList> combinedImageMap;
- QMap<QShaderKey, QShader::NativeShaderInfo> nativeShaderInfoMap;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/gui/rhi/qshaderdescription.cpp b/src/gui/rhi/qshaderdescription.cpp
index 44fcd936fd..f64daf02ef 100644
--- a/src/gui/rhi/qshaderdescription.cpp
+++ b/src/gui/rhi/qshaderdescription.cpp
@@ -1,8 +1,8 @@
-// Copyright (C) 2019 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qshaderdescription_p_p.h"
-#include "qshader_p_p.h"
+#include "qshaderdescription_p.h"
+#include "qshader_p.h"
#include <QDebug>
#include <QDataStream>
#include <QJsonObject>
@@ -12,11 +12,22 @@ QT_BEGIN_NAMESPACE
/*!
\class QShaderDescription
- \internal
+ \ingroup painting-3D
\inmodule QtGui
+ \since 6.6
\brief Describes the interface of a shader.
+ \warning The QRhi family of classes in the Qt Gui module, including QShader
+ and QShaderDescription, offer limited compatibility guarantees. There are
+ no source or binary compatibility guarantees for these classes, meaning the
+ API is only guaranteed to work with the Qt version the application was
+ developed against. Source incompatible changes are however aimed to be kept
+ at a minimum and will only be made in minor releases (6.7, 6.8, and so on).
+ To use these classes in an application, link to
+ \c{Qt::GuiPrivate} (if using CMake), and include the headers with the \c
+ rhi prefix, for example \c{#include <rhi/qshaderdescription.h>}.
+
A shader typically has a set of inputs and outputs. A vertex shader for
example has a number of input variables and may use one or more uniform
buffers to access data (e.g. a modelview matrix) provided by the
@@ -51,8 +62,6 @@ QT_BEGIN_NAMESPACE
float opacity;
} ubuf;
- out gl_PerVertex { vec4 gl_Position; };
-
void main()
{
v_color = color;
@@ -200,28 +209,179 @@ QT_BEGIN_NAMESPACE
\value ImageRect
\value ImageBuffer
\value Struct
+ \value Half
+ \value Half2
+ \value Half3
+ \value Half4
*/
/*!
- \class QShaderDescription::InOutVariable
- \internal
+ \enum QShaderDescription::ImageFormat
+ Image format.
+
+ \value ImageFormatUnknown
+ \value ImageFormatRgba32f
+ \value ImageFormatRgba16f
+ \value ImageFormatR32f
+ \value ImageFormatRgba8
+ \value ImageFormatRgba8Snorm
+ \value ImageFormatRg32f
+ \value ImageFormatRg16f
+ \value ImageFormatR11fG11fB10f
+ \value ImageFormatR16f
+ \value ImageFormatRgba16
+ \value ImageFormatRgb10A2
+ \value ImageFormatRg16
+ \value ImageFormatRg8
+ \value ImageFormatR16
+ \value ImageFormatR8
+ \value ImageFormatRgba16Snorm
+ \value ImageFormatRg16Snorm
+ \value ImageFormatRg8Snorm
+ \value ImageFormatR16Snorm
+ \value ImageFormatR8Snorm
+ \value ImageFormatRgba32i
+ \value ImageFormatRgba16i
+ \value ImageFormatRgba8i
+ \value ImageFormatR32i
+ \value ImageFormatRg32i
+ \value ImageFormatRg16i
+ \value ImageFormatRg8i
+ \value ImageFormatR16i
+ \value ImageFormatR8i
+ \value ImageFormatRgba32ui
+ \value ImageFormatRgba16ui
+ \value ImageFormatRgba8ui
+ \value ImageFormatR32ui
+ \value ImageFormatRgb10a2ui
+ \value ImageFormatRg32ui
+ \value ImageFormatRg16ui
+ \value ImageFormatRg8ui
+ \value ImageFormatR16ui
+ \value ImageFormatR8ui
+ */
+
+/*!
+ \enum QShaderDescription::ImageFlag
+ Image flags.
+
+ \value ReadOnlyImage
+ \value WriteOnlyImage
+ */
+
+/*!
+ \enum QShaderDescription::QualifierFlag
+ Qualifier flags.
+
+ \value QualifierReadOnly
+ \value QualifierWriteOnly
+ \value QualifierCoherent
+ \value QualifierVolatile
+ \value QualifierRestrict
+ */
+
+/*!
+ \struct QShaderDescription::InOutVariable
\inmodule QtGui
+ \since 6.6
\brief Describes an input or output variable in the shader.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QShaderDescription
+ for details.
*/
/*!
- \class QShaderDescription::BlockVariable
- \internal
+ \variable QShaderDescription::InOutVariable::name
+ */
+
+/*!
+ \variable QShaderDescription::InOutVariable::type
+ */
+
+/*!
+ \variable QShaderDescription::InOutVariable::location
+ */
+
+/*!
+ \variable QShaderDescription::InOutVariable::binding
+ */
+
+/*!
+ \variable QShaderDescription::InOutVariable::descriptorSet
+ */
+
+/*!
+ \variable QShaderDescription::InOutVariable::imageFormat
+ */
+
+/*!
+ \variable QShaderDescription::InOutVariable::imageFlags
+ */
+
+/*!
+ \variable QShaderDescription::InOutVariable::arrayDims
+ */
+
+/*!
+ \variable QShaderDescription::InOutVariable::perPatch
+ */
+
+/*!
+ \variable QShaderDescription::InOutVariable::structMembers
+ */
+
+/*!
+ \struct QShaderDescription::BlockVariable
\inmodule QtGui
+ \since 6.6
\brief Describes a member of a uniform or push constant block.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QShaderDescription
+ for details.
*/
/*!
- \class QShaderDescription::UniformBlock
- \internal
+ \variable QShaderDescription::BlockVariable::name
+ */
+
+/*!
+ \variable QShaderDescription::BlockVariable::type
+ */
+
+/*!
+ \variable QShaderDescription::BlockVariable::offset
+ */
+
+/*!
+ \variable QShaderDescription::BlockVariable::size
+ */
+
+/*!
+ \variable QShaderDescription::BlockVariable::arrayDims
+ */
+
+/*!
+ \variable QShaderDescription::BlockVariable::arrayStride
+ */
+
+/*!
+ \variable QShaderDescription::BlockVariable::matrixStride
+ */
+
+/*!
+ \variable QShaderDescription::BlockVariable::matrixIsRowMajor
+ */
+
+/*!
+ \variable QShaderDescription::BlockVariable::structMembers
+ */
+
+/*!
+ \struct QShaderDescription::UniformBlock
\inmodule QtGui
+ \since 6.6
\brief Describes a uniform block.
@@ -229,22 +389,157 @@ QT_BEGIN_NAMESPACE
(like GLSL 120 or GLSL/ES 100), uniform blocks are replaced with ordinary
uniforms in a struct. The name of the struct, and so the prefix for the
uniforms generated from the block members, is given by structName.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QShaderDescription
+ for details.
*/
/*!
- \class QShaderDescription::PushConstantBlock
- \internal
+ \variable QShaderDescription::UniformBlock::blockName
+ */
+
+/*!
+ \variable QShaderDescription::UniformBlock::structName
+ */
+
+/*!
+ \variable QShaderDescription::UniformBlock::size
+ */
+
+/*!
+ \variable QShaderDescription::UniformBlock::binding
+ */
+
+/*!
+ \variable QShaderDescription::UniformBlock::descriptorSet
+ */
+
+/*!
+ \variable QShaderDescription::UniformBlock::members
+ */
+
+/*!
+ \struct QShaderDescription::PushConstantBlock
\inmodule QtGui
+ \since 6.6
\brief Describes a push constant block.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QShaderDescription
+ for details.
*/
/*!
- \class QShaderDescription::StorageBlock
- \internal
+ \variable QShaderDescription::PushConstantBlock::name
+ */
+
+/*!
+ \variable QShaderDescription::PushConstantBlock::size
+ */
+
+/*!
+ \variable QShaderDescription::PushConstantBlock::members
+ */
+
+/*!
+ \struct QShaderDescription::StorageBlock
\inmodule QtGui
+ \since 6.6
\brief Describes a shader storage block.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QShaderDescription
+ for details.
+ */
+
+/*!
+ \variable QShaderDescription::StorageBlock::blockName
+ */
+
+/*!
+ \variable QShaderDescription::StorageBlock::instanceName
+ */
+
+/*!
+ \variable QShaderDescription::StorageBlock::knownSize
+ */
+
+/*!
+ \variable QShaderDescription::StorageBlock::binding
+ */
+
+/*!
+ \variable QShaderDescription::StorageBlock::descriptorSet
+ */
+
+/*!
+ \variable QShaderDescription::StorageBlock::members
+ */
+
+/*!
+ \variable QShaderDescription::StorageBlock::runtimeArrayStride
+ */
+
+/*!
+ \variable QShaderDescription::StorageBlock::qualifierFlags
+ */
+
+/*!
+ \struct QShaderDescription::BuiltinVariable
+ \inmodule QtGui
+ \since 6.6
+
+ \brief Describes a built-in variable.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QShaderDescription
+ for details.
+ */
+
+/*!
+ \variable QShaderDescription::BuiltinVariable::type
+ */
+
+/*!
+ \variable QShaderDescription::BuiltinVariable::varType
+ */
+
+/*!
+ \variable QShaderDescription::BuiltinVariable::arrayDims
+ */
+
+/*!
+ \enum QShaderDescription::BuiltinType
+ Built-in variable type.
+
+ \value PositionBuiltin
+ \value PointSizeBuiltin
+ \value ClipDistanceBuiltin
+ \value CullDistanceBuiltin
+ \value VertexIdBuiltin
+ \value InstanceIdBuiltin
+ \value PrimitiveIdBuiltin
+ \value InvocationIdBuiltin
+ \value LayerBuiltin
+ \value ViewportIndexBuiltin
+ \value TessLevelOuterBuiltin
+ \value TessLevelInnerBuiltin
+ \value TessCoordBuiltin
+ \value PatchVerticesBuiltin
+ \value FragCoordBuiltin
+ \value PointCoordBuiltin
+ \value FrontFacingBuiltin
+ \value SampleIdBuiltin
+ \value SamplePositionBuiltin
+ \value SampleMaskBuiltin
+ \value FragDepthBuiltin
+ \value NumWorkGroupsBuiltin
+ \value WorkgroupSizeBuiltin
+ \value WorkgroupIdBuiltin
+ \value LocalInvocationIdBuiltin
+ \value GlobalInvocationIdBuiltin
+ \value LocalInvocationIndexBuiltin
+ \value VertexIndexBuiltin
+ \value InstanceIndexBuiltin
*/
/*!
@@ -267,7 +562,7 @@ void QShaderDescription::detach()
}
/*!
- \internal
+ Constructs a copy of \a other.
*/
QShaderDescription::QShaderDescription(const QShaderDescription &other)
: d(other.d)
@@ -276,7 +571,7 @@ QShaderDescription::QShaderDescription(const QShaderDescription &other)
}
/*!
- \internal
+ Assigns \a other to this object.
*/
QShaderDescription &QShaderDescription::operator=(const QShaderDescription &other)
{
@@ -574,7 +869,7 @@ uint QShaderDescription::tessellationOutputVertexCount() const
\value UnknownTessellationMode
\value TrianglesTessellationMode
\value QuadTessellationMode
- \value IsolinesTessellationMode
+ \value IsolineTessellationMode
*/
/*!
diff --git a/src/gui/rhi/qshaderdescription.h b/src/gui/rhi/qshaderdescription.h
new file mode 100644
index 0000000000..02492a1598
--- /dev/null
+++ b/src/gui/rhi/qshaderdescription.h
@@ -0,0 +1,386 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSHADERDESCRIPTION_H
+#define QSHADERDESCRIPTION_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is part of the RHI API, with limited compatibility guarantees.
+// Usage of this API may make your code source and binary incompatible with
+// future versions of Qt.
+//
+
+#include <QtGui/qtguiglobal.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qlist.h>
+#include <array>
+
+QT_BEGIN_NAMESPACE
+
+struct QShaderDescriptionPrivate;
+class QDataStream;
+
+class Q_GUI_EXPORT QShaderDescription
+{
+public:
+ QShaderDescription();
+ QShaderDescription(const QShaderDescription &other);
+ QShaderDescription &operator=(const QShaderDescription &other);
+ ~QShaderDescription();
+ void detach();
+
+ bool isValid() const;
+
+ void serialize(QDataStream *stream, int version) const;
+ QByteArray toJson() const;
+
+ static QShaderDescription deserialize(QDataStream *stream, int version);
+
+ enum VariableType {
+ Unknown = 0,
+
+ // do not reorder
+ Float,
+ Vec2,
+ Vec3,
+ Vec4,
+ Mat2,
+ Mat2x3,
+ Mat2x4,
+ Mat3,
+ Mat3x2,
+ Mat3x4,
+ Mat4,
+ Mat4x2,
+ Mat4x3,
+
+ Int,
+ Int2,
+ Int3,
+ Int4,
+
+ Uint,
+ Uint2,
+ Uint3,
+ Uint4,
+
+ Bool,
+ Bool2,
+ Bool3,
+ Bool4,
+
+ Double,
+ Double2,
+ Double3,
+ Double4,
+ DMat2,
+ DMat2x3,
+ DMat2x4,
+ DMat3,
+ DMat3x2,
+ DMat3x4,
+ DMat4,
+ DMat4x2,
+ DMat4x3,
+
+ Sampler1D,
+ Sampler2D,
+ Sampler2DMS,
+ Sampler3D,
+ SamplerCube,
+ Sampler1DArray,
+ Sampler2DArray,
+ Sampler2DMSArray,
+ Sampler3DArray,
+ SamplerCubeArray,
+ SamplerRect,
+ SamplerBuffer,
+ SamplerExternalOES,
+ Sampler,
+
+ Image1D,
+ Image2D,
+ Image2DMS,
+ Image3D,
+ ImageCube,
+ Image1DArray,
+ Image2DArray,
+ Image2DMSArray,
+ Image3DArray,
+ ImageCubeArray,
+ ImageRect,
+ ImageBuffer,
+
+ Struct,
+
+ Half,
+ Half2,
+ Half3,
+ Half4
+ };
+
+ enum ImageFormat {
+ // must match SPIR-V's ImageFormat
+ ImageFormatUnknown = 0,
+ ImageFormatRgba32f = 1,
+ ImageFormatRgba16f = 2,
+ ImageFormatR32f = 3,
+ ImageFormatRgba8 = 4,
+ ImageFormatRgba8Snorm = 5,
+ ImageFormatRg32f = 6,
+ ImageFormatRg16f = 7,
+ ImageFormatR11fG11fB10f = 8,
+ ImageFormatR16f = 9,
+ ImageFormatRgba16 = 10,
+ ImageFormatRgb10A2 = 11,
+ ImageFormatRg16 = 12,
+ ImageFormatRg8 = 13,
+ ImageFormatR16 = 14,
+ ImageFormatR8 = 15,
+ ImageFormatRgba16Snorm = 16,
+ ImageFormatRg16Snorm = 17,
+ ImageFormatRg8Snorm = 18,
+ ImageFormatR16Snorm = 19,
+ ImageFormatR8Snorm = 20,
+ ImageFormatRgba32i = 21,
+ ImageFormatRgba16i = 22,
+ ImageFormatRgba8i = 23,
+ ImageFormatR32i = 24,
+ ImageFormatRg32i = 25,
+ ImageFormatRg16i = 26,
+ ImageFormatRg8i = 27,
+ ImageFormatR16i = 28,
+ ImageFormatR8i = 29,
+ ImageFormatRgba32ui = 30,
+ ImageFormatRgba16ui = 31,
+ ImageFormatRgba8ui = 32,
+ ImageFormatR32ui = 33,
+ ImageFormatRgb10a2ui = 34,
+ ImageFormatRg32ui = 35,
+ ImageFormatRg16ui = 36,
+ ImageFormatRg8ui = 37,
+ ImageFormatR16ui = 38,
+ ImageFormatR8ui = 39
+ };
+
+ enum ImageFlag {
+ ReadOnlyImage = 1 << 0,
+ WriteOnlyImage = 1 << 1
+ };
+ Q_DECLARE_FLAGS(ImageFlags, ImageFlag)
+
+ enum QualifierFlag {
+ QualifierReadOnly = 1 << 0,
+ QualifierWriteOnly = 1 << 1,
+ QualifierCoherent = 1 << 2,
+ QualifierVolatile = 1 << 3,
+ QualifierRestrict = 1 << 4,
+ };
+ Q_DECLARE_FLAGS(QualifierFlags, QualifierFlag)
+
+ // Optional data (like decorations) usually default to an otherwise invalid value (-1 or 0). This is intentional.
+
+ struct BlockVariable {
+ QByteArray name;
+ VariableType type = Unknown;
+ int offset = 0;
+ int size = 0;
+ QList<int> arrayDims;
+ int arrayStride = 0;
+ int matrixStride = 0;
+ bool matrixIsRowMajor = false;
+ QList<BlockVariable> structMembers;
+ };
+
+ struct InOutVariable {
+ QByteArray name;
+ VariableType type = Unknown;
+ int location = -1;
+ int binding = -1;
+ int descriptorSet = -1;
+ ImageFormat imageFormat = ImageFormatUnknown;
+ ImageFlags imageFlags;
+ QList<int> arrayDims;
+ bool perPatch = false;
+ QList<BlockVariable> structMembers;
+ };
+
+ struct UniformBlock {
+ QByteArray blockName;
+ QByteArray structName; // instanceName
+ int size = 0;
+ int binding = -1;
+ int descriptorSet = -1;
+ QList<BlockVariable> members;
+ };
+
+ struct PushConstantBlock {
+ QByteArray name;
+ int size = 0;
+ QList<BlockVariable> members;
+ };
+
+ struct StorageBlock {
+ QByteArray blockName;
+ QByteArray instanceName;
+ int knownSize = 0;
+ int binding = -1;
+ int descriptorSet = -1;
+ QList<BlockVariable> members;
+ int runtimeArrayStride = 0;
+ QualifierFlags qualifierFlags;
+ };
+
+ QList<InOutVariable> inputVariables() const;
+ QList<InOutVariable> outputVariables() const;
+ QList<UniformBlock> uniformBlocks() const;
+ QList<PushConstantBlock> pushConstantBlocks() const;
+ QList<StorageBlock> storageBlocks() const;
+ QList<InOutVariable> combinedImageSamplers() const;
+ QList<InOutVariable> separateImages() const;
+ QList<InOutVariable> separateSamplers() const;
+ QList<InOutVariable> storageImages() const;
+
+ enum BuiltinType {
+ // must match SpvBuiltIn
+ PositionBuiltin = 0,
+ PointSizeBuiltin = 1,
+ ClipDistanceBuiltin = 3,
+ CullDistanceBuiltin = 4,
+ VertexIdBuiltin = 5,
+ InstanceIdBuiltin = 6,
+ PrimitiveIdBuiltin = 7,
+ InvocationIdBuiltin = 8,
+ LayerBuiltin = 9,
+ ViewportIndexBuiltin = 10,
+ TessLevelOuterBuiltin = 11,
+ TessLevelInnerBuiltin = 12,
+ TessCoordBuiltin = 13,
+ PatchVerticesBuiltin = 14,
+ FragCoordBuiltin = 15,
+ PointCoordBuiltin = 16,
+ FrontFacingBuiltin = 17,
+ SampleIdBuiltin = 18,
+ SamplePositionBuiltin = 19,
+ SampleMaskBuiltin = 20,
+ FragDepthBuiltin = 22,
+ NumWorkGroupsBuiltin = 24,
+ WorkgroupSizeBuiltin = 25,
+ WorkgroupIdBuiltin = 26,
+ LocalInvocationIdBuiltin = 27,
+ GlobalInvocationIdBuiltin = 28,
+ LocalInvocationIndexBuiltin = 29,
+ VertexIndexBuiltin = 42,
+ InstanceIndexBuiltin = 43
+ };
+
+ struct BuiltinVariable {
+ BuiltinType type;
+ VariableType varType;
+ QList<int> arrayDims;
+ };
+
+ QList<BuiltinVariable> inputBuiltinVariables() const;
+ QList<BuiltinVariable> outputBuiltinVariables() const;
+
+ std::array<uint, 3> computeShaderLocalSize() const;
+
+ uint tessellationOutputVertexCount() const;
+
+ enum TessellationMode {
+ UnknownTessellationMode,
+ TrianglesTessellationMode,
+ QuadTessellationMode,
+ IsolineTessellationMode
+ };
+
+ TessellationMode tessellationMode() const;
+
+ enum TessellationWindingOrder {
+ UnknownTessellationWindingOrder,
+ CwTessellationWindingOrder,
+ CcwTessellationWindingOrder
+ };
+
+ TessellationWindingOrder tessellationWindingOrder() const;
+
+ enum TessellationPartitioning {
+ UnknownTessellationPartitioning,
+ EqualTessellationPartitioning,
+ FractionalEvenTessellationPartitioning,
+ FractionalOddTessellationPartitioning
+ };
+
+ TessellationPartitioning tessellationPartitioning() const;
+
+private:
+ QShaderDescriptionPrivate *d;
+ friend struct QShaderDescriptionPrivate;
+#ifndef QT_NO_DEBUG_STREAM
+ friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription &);
+#endif
+ friend Q_GUI_EXPORT bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) noexcept;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderDescription::ImageFlags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderDescription::QualifierFlags)
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription &);
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::InOutVariable &);
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::BlockVariable &);
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::UniformBlock &);
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::PushConstantBlock &);
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::StorageBlock &);
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::BuiltinVariable &);
+#endif
+
+Q_GUI_EXPORT bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) noexcept;
+Q_GUI_EXPORT bool operator==(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) noexcept;
+Q_GUI_EXPORT bool operator==(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) noexcept;
+Q_GUI_EXPORT bool operator==(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) noexcept;
+Q_GUI_EXPORT bool operator==(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) noexcept;
+Q_GUI_EXPORT bool operator==(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) noexcept;
+Q_GUI_EXPORT bool operator==(const QShaderDescription::BuiltinVariable &lhs, const QShaderDescription::BuiltinVariable &rhs) noexcept;
+
+inline bool operator!=(const QShaderDescription &lhs, const QShaderDescription &rhs) noexcept
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) noexcept
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) noexcept
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) noexcept
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) noexcept
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) noexcept
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator!=(const QShaderDescription::BuiltinVariable &lhs, const QShaderDescription::BuiltinVariable &rhs) noexcept
+{
+ return !(lhs == rhs);
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/gui/rhi/qshaderdescription_p.h b/src/gui/rhi/qshaderdescription_p.h
index 990cb12003..df694bbf40 100644
--- a/src/gui/rhi/qshaderdescription_p.h
+++ b/src/gui/rhi/qshaderdescription_p.h
@@ -1,8 +1,8 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QSHADERDESCRIPTION_H
-#define QSHADERDESCRIPTION_H
+#ifndef QSHADERDESCRIPTION_P_H
+#define QSHADERDESCRIPTION_P_H
//
// W A R N I N G
@@ -15,376 +15,67 @@
// We mean it.
//
-#include <QtGui/qtguiglobal.h>
-#include <QtCore/QString>
+#include <rhi/qshaderdescription.h>
#include <QtCore/QList>
-#include <QtCore/private/qglobal_p.h>
-#include <array>
+#include <QtCore/QAtomicInt>
+#include <QtCore/QJsonDocument>
QT_BEGIN_NAMESPACE
-struct QShaderDescriptionPrivate;
-class QDataStream;
-
-class Q_GUI_EXPORT QShaderDescription
+struct Q_GUI_EXPORT QShaderDescriptionPrivate
{
-public:
- QShaderDescription();
- QShaderDescription(const QShaderDescription &other);
- QShaderDescription &operator=(const QShaderDescription &other);
- ~QShaderDescription();
- void detach();
-
- bool isValid() const;
-
- void serialize(QDataStream *stream, int version) const;
- QByteArray toJson() const;
-
- static QShaderDescription deserialize(QDataStream *stream, int version);
-
- enum VariableType {
- Unknown = 0,
-
- // do not reorder
- Float,
- Vec2,
- Vec3,
- Vec4,
- Mat2,
- Mat2x3,
- Mat2x4,
- Mat3,
- Mat3x2,
- Mat3x4,
- Mat4,
- Mat4x2,
- Mat4x3,
-
- Int,
- Int2,
- Int3,
- Int4,
-
- Uint,
- Uint2,
- Uint3,
- Uint4,
-
- Bool,
- Bool2,
- Bool3,
- Bool4,
-
- Double,
- Double2,
- Double3,
- Double4,
- DMat2,
- DMat2x3,
- DMat2x4,
- DMat3,
- DMat3x2,
- DMat3x4,
- DMat4,
- DMat4x2,
- DMat4x3,
-
- Sampler1D,
- Sampler2D,
- Sampler2DMS,
- Sampler3D,
- SamplerCube,
- Sampler1DArray,
- Sampler2DArray,
- Sampler2DMSArray,
- Sampler3DArray,
- SamplerCubeArray,
- SamplerRect,
- SamplerBuffer,
- SamplerExternalOES,
- Sampler,
-
- Image1D,
- Image2D,
- Image2DMS,
- Image3D,
- ImageCube,
- Image1DArray,
- Image2DArray,
- Image2DMSArray,
- Image3DArray,
- ImageCubeArray,
- ImageRect,
- ImageBuffer,
-
- Struct,
-
- Half,
- Half2,
- Half3,
- Half4
- };
-
- enum ImageFormat {
- // must match SPIR-V's ImageFormat
- ImageFormatUnknown = 0,
- ImageFormatRgba32f = 1,
- ImageFormatRgba16f = 2,
- ImageFormatR32f = 3,
- ImageFormatRgba8 = 4,
- ImageFormatRgba8Snorm = 5,
- ImageFormatRg32f = 6,
- ImageFormatRg16f = 7,
- ImageFormatR11fG11fB10f = 8,
- ImageFormatR16f = 9,
- ImageFormatRgba16 = 10,
- ImageFormatRgb10A2 = 11,
- ImageFormatRg16 = 12,
- ImageFormatRg8 = 13,
- ImageFormatR16 = 14,
- ImageFormatR8 = 15,
- ImageFormatRgba16Snorm = 16,
- ImageFormatRg16Snorm = 17,
- ImageFormatRg8Snorm = 18,
- ImageFormatR16Snorm = 19,
- ImageFormatR8Snorm = 20,
- ImageFormatRgba32i = 21,
- ImageFormatRgba16i = 22,
- ImageFormatRgba8i = 23,
- ImageFormatR32i = 24,
- ImageFormatRg32i = 25,
- ImageFormatRg16i = 26,
- ImageFormatRg8i = 27,
- ImageFormatR16i = 28,
- ImageFormatR8i = 29,
- ImageFormatRgba32ui = 30,
- ImageFormatRgba16ui = 31,
- ImageFormatRgba8ui = 32,
- ImageFormatR32ui = 33,
- ImageFormatRgb10a2ui = 34,
- ImageFormatRg32ui = 35,
- ImageFormatRg16ui = 36,
- ImageFormatRg8ui = 37,
- ImageFormatR16ui = 38,
- ImageFormatR8ui = 39
- };
-
- enum ImageFlag {
- ReadOnlyImage = 1 << 0,
- WriteOnlyImage = 1 << 1
- };
- Q_DECLARE_FLAGS(ImageFlags, ImageFlag)
-
- enum QualifierFlag {
- QualifierReadOnly = 1 << 0,
- QualifierWriteOnly = 1 << 1,
- QualifierCoherent = 1 << 2,
- QualifierVolatile = 1 << 3,
- QualifierRestrict = 1 << 4,
- };
- Q_DECLARE_FLAGS(QualifierFlags, QualifierFlag)
-
- // Optional data (like decorations) usually default to an otherwise invalid value (-1 or 0). This is intentional.
-
- struct BlockVariable
+ QShaderDescriptionPrivate()
+ : ref(1)
{
- QByteArray name;
- VariableType type = Unknown;
- int offset = 0;
- int size = 0;
- QList<int> arrayDims;
- int arrayStride = 0;
- int matrixStride = 0;
- bool matrixIsRowMajor = false;
- QList<BlockVariable> structMembers;
- };
-
- struct InOutVariable {
- QByteArray name;
- VariableType type = Unknown;
- int location = -1;
- int binding = -1;
- int descriptorSet = -1;
- ImageFormat imageFormat = ImageFormatUnknown;
- ImageFlags imageFlags;
- QList<int> arrayDims;
- bool perPatch = false;
- QList<BlockVariable> structMembers;
- };
-
- struct UniformBlock {
- QByteArray blockName;
- QByteArray structName; // instanceName
- int size = 0;
- int binding = -1;
- int descriptorSet = -1;
- QList<BlockVariable> members;
- };
-
- struct PushConstantBlock {
- QByteArray name;
- int size = 0;
- QList<BlockVariable> members;
- };
-
- struct StorageBlock {
- QByteArray blockName;
- QByteArray instanceName;
- int knownSize = 0;
- int binding = -1;
- int descriptorSet = -1;
- QList<BlockVariable> members;
- int runtimeArrayStride = 0;
- QualifierFlags qualifierFlags;
- };
-
- QList<InOutVariable> inputVariables() const;
- QList<InOutVariable> outputVariables() const;
- QList<UniformBlock> uniformBlocks() const;
- QList<PushConstantBlock> pushConstantBlocks() const;
- QList<StorageBlock> storageBlocks() const;
- QList<InOutVariable> combinedImageSamplers() const;
- QList<InOutVariable> separateImages() const;
- QList<InOutVariable> separateSamplers() const;
- QList<InOutVariable> storageImages() const;
-
- enum BuiltinType {
- // must match SpvBuiltIn
- PositionBuiltin = 0,
- PointSizeBuiltin = 1,
- ClipDistanceBuiltin = 3,
- CullDistanceBuiltin = 4,
- VertexIdBuiltin = 5,
- InstanceIdBuiltin = 6,
- PrimitiveIdBuiltin = 7,
- InvocationIdBuiltin = 8,
- LayerBuiltin = 9,
- ViewportIndexBuiltin = 10,
- TessLevelOuterBuiltin = 11,
- TessLevelInnerBuiltin = 12,
- TessCoordBuiltin = 13,
- PatchVerticesBuiltin = 14,
- FragCoordBuiltin = 15,
- PointCoordBuiltin = 16,
- FrontFacingBuiltin = 17,
- SampleIdBuiltin = 18,
- SamplePositionBuiltin = 19,
- SampleMaskBuiltin = 20,
- FragDepthBuiltin = 22,
- NumWorkGroupsBuiltin = 24,
- WorkgroupSizeBuiltin = 25,
- WorkgroupIdBuiltin = 26,
- LocalInvocationIdBuiltin = 27,
- GlobalInvocationIdBuiltin = 28,
- LocalInvocationIndexBuiltin = 29,
- VertexIndexBuiltin = 42,
- InstanceIndexBuiltin = 43
- };
-
- struct BuiltinVariable {
- BuiltinType type;
- VariableType varType;
- QList<int> arrayDims;
- };
-
- QList<BuiltinVariable> inputBuiltinVariables() const;
- QList<BuiltinVariable> outputBuiltinVariables() const;
-
- std::array<uint, 3> computeShaderLocalSize() const;
-
- uint tessellationOutputVertexCount() const;
-
- enum TessellationMode {
- UnknownTessellationMode,
- TrianglesTessellationMode,
- QuadTessellationMode,
- IsolineTessellationMode
- };
-
- TessellationMode tessellationMode() const;
-
- enum TessellationWindingOrder {
- UnknownTessellationWindingOrder,
- CwTessellationWindingOrder,
- CcwTessellationWindingOrder
- };
-
- TessellationWindingOrder tessellationWindingOrder() const;
-
- enum TessellationPartitioning {
- UnknownTessellationPartitioning,
- EqualTessellationPartitioning,
- FractionalEvenTessellationPartitioning,
- FractionalOddTessellationPartitioning
- };
-
- TessellationPartitioning tessellationPartitioning() const;
-
-private:
- QShaderDescriptionPrivate *d;
- friend struct QShaderDescriptionPrivate;
-#ifndef QT_NO_DEBUG_STREAM
- friend Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription &);
-#endif
- friend Q_GUI_EXPORT bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) noexcept;
+ }
+
+ QShaderDescriptionPrivate(const QShaderDescriptionPrivate &other)
+ : ref(1),
+ inVars(other.inVars),
+ outVars(other.outVars),
+ uniformBlocks(other.uniformBlocks),
+ pushConstantBlocks(other.pushConstantBlocks),
+ storageBlocks(other.storageBlocks),
+ combinedImageSamplers(other.combinedImageSamplers),
+ separateImages(other.separateImages),
+ separateSamplers(other.separateSamplers),
+ storageImages(other.storageImages),
+ inBuiltins(other.inBuiltins),
+ outBuiltins(other.outBuiltins),
+ localSize(other.localSize),
+ tessOutVertCount(other.tessOutVertCount),
+ tessMode(other.tessMode),
+ tessWind(other.tessWind),
+ tessPart(other.tessPart)
+ {
+ }
+
+ static QShaderDescriptionPrivate *get(QShaderDescription *desc) { return desc->d; }
+ static const QShaderDescriptionPrivate *get(const QShaderDescription *desc) { return desc->d; }
+
+ QJsonDocument makeDoc();
+ void writeToStream(QDataStream *stream, int version);
+ void loadFromStream(QDataStream *stream, int version);
+
+ QAtomicInt ref;
+ QList<QShaderDescription::InOutVariable> inVars;
+ QList<QShaderDescription::InOutVariable> outVars;
+ QList<QShaderDescription::UniformBlock> uniformBlocks;
+ QList<QShaderDescription::PushConstantBlock> pushConstantBlocks;
+ QList<QShaderDescription::StorageBlock> storageBlocks;
+ QList<QShaderDescription::InOutVariable> combinedImageSamplers;
+ QList<QShaderDescription::InOutVariable> separateImages;
+ QList<QShaderDescription::InOutVariable> separateSamplers;
+ QList<QShaderDescription::InOutVariable> storageImages;
+ QList<QShaderDescription::BuiltinVariable> inBuiltins;
+ QList<QShaderDescription::BuiltinVariable> outBuiltins;
+ std::array<uint, 3> localSize = {};
+ uint tessOutVertCount = 0;
+ QShaderDescription::TessellationMode tessMode = QShaderDescription::UnknownTessellationMode;
+ QShaderDescription::TessellationWindingOrder tessWind = QShaderDescription::UnknownTessellationWindingOrder;
+ QShaderDescription::TessellationPartitioning tessPart = QShaderDescription::UnknownTessellationPartitioning;
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderDescription::ImageFlags)
-Q_DECLARE_OPERATORS_FOR_FLAGS(QShaderDescription::QualifierFlags)
-
-#ifndef QT_NO_DEBUG_STREAM
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription &);
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::InOutVariable &);
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::BlockVariable &);
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::UniformBlock &);
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::PushConstantBlock &);
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::StorageBlock &);
-Q_GUI_EXPORT QDebug operator<<(QDebug, const QShaderDescription::BuiltinVariable &);
-#endif
-
-Q_GUI_EXPORT bool operator==(const QShaderDescription &lhs, const QShaderDescription &rhs) noexcept;
-Q_GUI_EXPORT bool operator==(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) noexcept;
-Q_GUI_EXPORT bool operator==(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) noexcept;
-Q_GUI_EXPORT bool operator==(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) noexcept;
-Q_GUI_EXPORT bool operator==(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) noexcept;
-Q_GUI_EXPORT bool operator==(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) noexcept;
-Q_GUI_EXPORT bool operator==(const QShaderDescription::BuiltinVariable &lhs, const QShaderDescription::BuiltinVariable &rhs) noexcept;
-
-inline bool operator!=(const QShaderDescription &lhs, const QShaderDescription &rhs) noexcept
-{
- return !(lhs == rhs);
-}
-
-inline bool operator!=(const QShaderDescription::InOutVariable &lhs, const QShaderDescription::InOutVariable &rhs) noexcept
-{
- return !(lhs == rhs);
-}
-
-inline bool operator!=(const QShaderDescription::BlockVariable &lhs, const QShaderDescription::BlockVariable &rhs) noexcept
-{
- return !(lhs == rhs);
-}
-
-inline bool operator!=(const QShaderDescription::UniformBlock &lhs, const QShaderDescription::UniformBlock &rhs) noexcept
-{
- return !(lhs == rhs);
-}
-
-inline bool operator!=(const QShaderDescription::PushConstantBlock &lhs, const QShaderDescription::PushConstantBlock &rhs) noexcept
-{
- return !(lhs == rhs);
-}
-
-inline bool operator!=(const QShaderDescription::StorageBlock &lhs, const QShaderDescription::StorageBlock &rhs) noexcept
-{
- return !(lhs == rhs);
-}
-
-inline bool operator!=(const QShaderDescription::BuiltinVariable &lhs, const QShaderDescription::BuiltinVariable &rhs) noexcept
-{
- return !(lhs == rhs);
-}
-
QT_END_NAMESPACE
#endif
diff --git a/src/gui/rhi/qshaderdescription_p_p.h b/src/gui/rhi/qshaderdescription_p_p.h
deleted file mode 100644
index c22ddda8ad..0000000000
--- a/src/gui/rhi/qshaderdescription_p_p.h
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QSHADERDESCRIPTION_P_H
-#define QSHADERDESCRIPTION_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists for the convenience
-// of a number of Qt sources files. This header file may change from
-// version to version without notice, or even be removed.
-//
-// We mean it.
-//
-
-#include "qshaderdescription_p.h"
-#include <QtCore/QList>
-#include <QtCore/QAtomicInt>
-#include <QtCore/QJsonDocument>
-
-QT_BEGIN_NAMESPACE
-
-struct Q_GUI_EXPORT QShaderDescriptionPrivate
-{
- QShaderDescriptionPrivate()
- : ref(1)
- {
- }
-
- QShaderDescriptionPrivate(const QShaderDescriptionPrivate &other)
- : ref(1),
- inVars(other.inVars),
- outVars(other.outVars),
- uniformBlocks(other.uniformBlocks),
- pushConstantBlocks(other.pushConstantBlocks),
- storageBlocks(other.storageBlocks),
- combinedImageSamplers(other.combinedImageSamplers),
- separateImages(other.separateImages),
- separateSamplers(other.separateSamplers),
- storageImages(other.storageImages),
- inBuiltins(other.inBuiltins),
- outBuiltins(other.outBuiltins),
- localSize(other.localSize),
- tessOutVertCount(other.tessOutVertCount),
- tessMode(other.tessMode),
- tessWind(other.tessWind),
- tessPart(other.tessPart)
- {
- }
-
- static QShaderDescriptionPrivate *get(QShaderDescription *desc) { return desc->d; }
- static const QShaderDescriptionPrivate *get(const QShaderDescription *desc) { return desc->d; }
-
- QJsonDocument makeDoc();
- void writeToStream(QDataStream *stream, int version);
- void loadFromStream(QDataStream *stream, int version);
-
- QAtomicInt ref;
- QList<QShaderDescription::InOutVariable> inVars;
- QList<QShaderDescription::InOutVariable> outVars;
- QList<QShaderDescription::UniformBlock> uniformBlocks;
- QList<QShaderDescription::PushConstantBlock> pushConstantBlocks;
- QList<QShaderDescription::StorageBlock> storageBlocks;
- QList<QShaderDescription::InOutVariable> combinedImageSamplers;
- QList<QShaderDescription::InOutVariable> separateImages;
- QList<QShaderDescription::InOutVariable> separateSamplers;
- QList<QShaderDescription::InOutVariable> storageImages;
- QList<QShaderDescription::BuiltinVariable> inBuiltins;
- QList<QShaderDescription::BuiltinVariable> outBuiltins;
- std::array<uint, 3> localSize = {};
- uint tessOutVertCount = 0;
- QShaderDescription::TessellationMode tessMode = QShaderDescription::UnknownTessellationMode;
- QShaderDescription::TessellationWindingOrder tessWind = QShaderDescription::UnknownTessellationWindingOrder;
- QShaderDescription::TessellationPartitioning tessPart = QShaderDescription::UnknownTessellationPartitioning;
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/gui/text/coretext/qcoretextfontdatabase.mm b/src/gui/text/coretext/qcoretextfontdatabase.mm
index 61c662cd45..19f3a2b335 100644
--- a/src/gui/text/coretext/qcoretextfontdatabase.mm
+++ b/src/gui/text/coretext/qcoretextfontdatabase.mm
@@ -361,7 +361,7 @@ static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd)
fd->fixedPitch = false;
if (QCFType<CTFontRef> tempFont = CTFontCreateWithFontDescriptor(font, 0.0, 0)) {
- uint tag = MAKE_TAG('O', 'S', '/', '2');
+ uint tag = QFont::Tag("OS/2").value();
CTFontRef tempFontRef = tempFont;
void *userData = reinterpret_cast<void *>(&tempFontRef);
uint length = 128;
@@ -489,6 +489,31 @@ QFontEngine *QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>::fontEngine
qreal scaledPointSize = fontDef.pixelSize;
CGAffineTransform matrix = qt_transform_from_fontdef(fontDef);
+
+ if (!fontDef.variableAxisValues.isEmpty()) {
+ QCFType<CFMutableDictionaryRef> variations = CFDictionaryCreateMutable(nullptr,
+ fontDef.variableAxisValues.size(),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ for (auto it = fontDef.variableAxisValues.constBegin();
+ it != fontDef.variableAxisValues.constEnd();
+ ++it) {
+ const quint32 tag = it.key().value();
+ const float value = it.value();
+ QCFType<CFNumberRef> tagRef = CFNumberCreate(nullptr, kCFNumberIntType, &tag);
+ QCFType<CFNumberRef> valueRef = CFNumberCreate(nullptr, kCFNumberFloatType, &value);
+
+ CFDictionarySetValue(variations, tagRef, valueRef);
+ }
+ QCFType<CFDictionaryRef> attributes = CFDictionaryCreate(nullptr,
+ (const void **) &kCTFontVariationAttribute,
+ (const void **) &variations,
+ 1,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ descriptor = CTFontDescriptorCreateCopyWithAttributes(descriptor, attributes);
+ }
+
if (QCFType<CTFontRef> font = CTFontCreateWithFontDescriptor(descriptor, scaledPointSize, &matrix))
return new QCoreTextFontEngine(font, fontDef);
@@ -504,7 +529,7 @@ QFontEngine *QCoreTextFontDatabaseEngineFactory<QFontEngineFT>::fontEngine(const
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));
+ static_cast<QFont::HintingPreference>(fontDef.hintingPreference), fontDef.variableAxisValues);
} else if (NSURL *url = descriptorAttribute<NSURL>(descriptor, kCTFontURLAttribute)) {
QFontEngine::FaceId faceId;
@@ -515,6 +540,8 @@ QFontEngine *QCoreTextFontDatabaseEngineFactory<QFontEngineFT>::fontEngine(const
QString styleName = QCFString(CTFontDescriptorCopyAttribute(descriptor, kCTFontStyleNameAttribute));
faceId.index = QFreetypeFace::getFaceIndexByStyleName(faceFileName, styleName);
+ faceId.variableAxes = fontDef.variableAxisValues;
+
return QFontEngineFT::create(fontDef, faceId);
}
// We end up here with a descriptor does not contain Qt font data or kCTFontURLAttribute.
@@ -527,7 +554,7 @@ QFontEngine *QCoreTextFontDatabaseEngineFactory<QFontEngineFT>::fontEngine(const
template <class T>
QFontEngine *QCoreTextFontDatabaseEngineFactory<T>::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
{
- return T::create(fontData, pixelSize, hintingPreference);
+ return T::create(fontData, pixelSize, hintingPreference, {});
}
// Explicitly instantiate so that we don't need the plugin to involve FreeType
@@ -545,7 +572,7 @@ CFArrayRef fallbacksForDescriptor(CTFontDescriptorRef descriptor)
}
CFArrayRef cascadeList = CFArrayRef(CTFontCopyDefaultCascadeListForLanguages(font,
- (CFArrayRef)[NSUserDefaults.standardUserDefaults stringArrayForKey:@"AppleLanguages"]));
+ (CFArrayRef)NSLocale.preferredLanguages));
if (!cascadeList) {
qCWarning(lcQpaFonts) << "Failed to create fallback cascade list for" << descriptor;
@@ -714,13 +741,20 @@ QStringList QCoreTextFontDatabase::addApplicationFont(const QByteArray &fontData
if (!fontData.isEmpty()) {
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);
+ if (QCFType<CFArrayRef> descriptors = CTFontManagerCreateFontDescriptorsFromData(fontDataReference)) {
CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
- CFArrayAppendValue(array, descriptor);
+ const int count = CFArrayGetCount(descriptors);
+
+ for (int i = 0; i < count; ++i) {
+ CTFontDescriptorRef descriptor = CTFontDescriptorRef(CFArrayGetValueAtIndex(descriptors, i));
+
+ // 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);
+ CFArrayAppendValue(array, descriptor);
+ }
+
fonts = array;
}
} else {
@@ -862,7 +896,7 @@ static CTFontDescriptorRef fontDescriptorFromTheme(QPlatformTheme::Font f)
UIFontDescriptor *desc = [UIFontDescriptor preferredFontDescriptorWithTextStyle:textStyle];
return static_cast<CTFontDescriptorRef>(CFBridgingRetain(desc));
}
-#endif // Q_OS_IOS, Q_OS_TVOS, Q_OS_WATCHOS
+#endif // QT_PLATFORM_UIKIT
// macOS default case and iOS fallback case
return descriptorForFontType(fontTypeFromTheme(f));
@@ -905,7 +939,7 @@ void QCoreTextFontDatabase::populateThemeFonts()
auto addFontVariants = [&](CTFontDescriptorRef descriptor) {
QCFType<CFArrayRef> matchingDescriptors = CTFontDescriptorCreateMatchingFontDescriptors(descriptor, nullptr);
- const int matchingDescriptorsCount = CFArrayGetCount(matchingDescriptors);
+ const int matchingDescriptorsCount = matchingDescriptors ? CFArrayGetCount(matchingDescriptors) : 0;
qCDebug(lcQpaFonts) << "Enumerating font variants based on" << id(descriptor)
<< "resulted in" << matchingDescriptorsCount << "matching descriptors"
<< matchingDescriptors.as<NSArray*>();
@@ -980,5 +1014,10 @@ QList<int> QCoreTextFontDatabase::standardSizes() const
return ret;
}
+bool QCoreTextFontDatabase::supportsVariableApplicationFonts() const
+{
+ return true;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/text/coretext/qcoretextfontdatabase_p.h b/src/gui/text/coretext/qcoretextfontdatabase_p.h
index 74c3f30b79..eeea9ad640 100644
--- a/src/gui/text/coretext/qcoretextfontdatabase_p.h
+++ b/src/gui/text/coretext/qcoretextfontdatabase_p.h
@@ -46,6 +46,7 @@ public:
QFont defaultFont() const override;
bool fontsAlwaysScalable() const override;
QList<int> standardSizes() const override;
+ bool supportsVariableApplicationFonts() const override;
// For iOS and macOS platform themes
QFont *themeFont(QPlatformTheme::Font) const;
diff --git a/src/gui/text/coretext/qfontengine_coretext.mm b/src/gui/text/coretext/qfontengine_coretext.mm
index 599a7f08c3..1050c03d75 100644
--- a/src/gui/text/coretext/qfontengine_coretext.mm
+++ b/src/gui/text/coretext/qfontengine_coretext.mm
@@ -12,6 +12,9 @@
#include <QtGui/qpainterpath.h>
#include <private/qcoregraphics_p.h>
#include <private/qimage_p.h>
+#include <private/qguiapplication_p.h>
+#include <private/qstringiterator_p.h>
+#include <qpa/qplatformtheme.h>
#include <cmath>
@@ -125,9 +128,13 @@ public:
QByteArray m_fontData;
};
-QCoreTextFontEngine *QCoreTextFontEngine::create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
+QCoreTextFontEngine *QCoreTextFontEngine::create(const QByteArray &fontData,
+ qreal pixelSize,
+ QFont::HintingPreference hintingPreference,
+ const QMap<QFont::Tag, float> &variableAxisValues)
{
Q_UNUSED(hintingPreference);
+ Q_UNUSED(variableAxisValues);
QCFType<CFDataRef> fontDataReference = fontData.toRawCFData();
QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithCFData(fontDataReference);
@@ -186,6 +193,7 @@ void QCoreTextFontEngine::init()
face_id.index = 0;
QCFString name = CTFontCopyName(ctfont, kCTFontUniqueNameKey);
face_id.filename = QString::fromCFString(name).toUtf8();
+ face_id.variableAxes = fontDef.variableAxisValues;
QCFString family = CTFontCopyFamilyName(ctfont);
fontDef.families = QStringList(family);
@@ -230,7 +238,7 @@ void QCoreTextFontEngine::init()
synthesisFlags |= SynthesizedItalic;
avgCharWidth = 0;
- QByteArray os2Table = getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
+ QByteArray os2Table = getSfntTable(QFont::Tag("OS/2").value());
unsigned emSize = CTFontGetUnitsPerEm(ctfont);
if (os2Table.size() >= 10) {
fsType = qFromBigEndian<quint16>(os2Table.constData() + 8);
@@ -267,29 +275,30 @@ glyph_t QCoreTextFontEngine::glyphIndex(uint ucs4) const
return glyphIndices[0];
}
-bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
- int *nglyphs, QFontEngine::ShaperFlags flags) const
+int QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
+ int *nglyphs, QFontEngine::ShaperFlags flags) const
{
Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
if (*nglyphs < len) {
*nglyphs = len;
- return false;
+ return -1;
}
QVarLengthArray<CGGlyph> cgGlyphs(len);
CTFontGetGlyphsForCharacters(ctfont, (const UniChar*)str, cgGlyphs.data(), len);
int glyph_pos = 0;
- for (int i = 0; i < len; ++i) {
- glyphs->glyphs[glyph_pos] = cgGlyphs[i];
- if (glyph_pos < i)
- cgGlyphs[glyph_pos] = cgGlyphs[i];
- glyph_pos++;
-
- // If it's a non-BMP char, skip the lower part of surrogate pair and go
- // directly to the next char without increasing glyph_pos
- if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate())
- ++i;
+ int mappedGlyphs = 0;
+ QStringIterator it(str, str + len);
+ while (it.hasNext()) {
+ qsizetype idx = it.index();
+ char32_t ucs4 = it.next();
+ glyphs->glyphs[glyph_pos] = cgGlyphs[idx];
+ if (glyph_pos < idx)
+ cgGlyphs[glyph_pos] = cgGlyphs[idx];
+ if (glyphs->glyphs[glyph_pos] != 0 || isIgnorableChar(ucs4))
+ mappedGlyphs++;
+ glyph_pos++;
}
*nglyphs = glyph_pos;
@@ -298,7 +307,7 @@ bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *
if (!(flags & GlyphIndicesOnly))
loadAdvancesForGlyphs(cgGlyphs, glyphs);
- return true;
+ return mappedGlyphs;
}
glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph)
@@ -716,10 +725,12 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, const QFixedPoint &subP
// draw with white or black fill, and then invert the glyph image in the latter case,
// producing an alpha map. This covers the most common use-cases, but longer term we
// should propagate the fill color all the way from the paint engine, and include it
- //in the key for the glyph cache.
+ // in the key for the glyph cache.
- if (!qt_mac_applicationIsInDarkMode())
- return kCGColorBlack;
+ if (auto *platformTheme = QGuiApplicationPrivate::platformTheme()) {
+ if (platformTheme->colorScheme() != Qt::ColorScheme::Dark)
+ return kCGColorBlack;
+ }
}
return kCGColorWhite;
}();
diff --git a/src/gui/text/coretext/qfontengine_coretext_p.h b/src/gui/text/coretext/qfontengine_coretext_p.h
index 665b827f11..2f388c32bc 100644
--- a/src/gui/text/coretext/qfontengine_coretext_p.h
+++ b/src/gui/text/coretext/qfontengine_coretext_p.h
@@ -38,7 +38,7 @@ public:
~QCoreTextFontEngine();
glyph_t glyphIndex(uint ucs4) const override;
- bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
+ int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
void recalcAdvances(QGlyphLayout *, ShaperFlags) const override;
glyph_metrics_t boundingBox(glyph_t glyph) override;
@@ -91,7 +91,7 @@ public:
static bool ct_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *length);
static QFont::Weight qtWeightFromCFWeight(float value);
- static QCoreTextFontEngine *create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference);
+ static QCoreTextFontEngine *create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference, const QMap<QFont::Tag, float> &variableAxisValue);
protected:
QCoreTextFontEngine(const QFontDef &def);
diff --git a/src/gui/text/freetype/qfontengine_ft.cpp b/src/gui/text/freetype/qfontengine_ft.cpp
index 5b48ad979b..d3791f1f6e 100644
--- a/src/gui/text/freetype/qfontengine_ft.cpp
+++ b/src/gui/text/freetype/qfontengine_ft.cpp
@@ -12,6 +12,7 @@
#include <qscreen.h>
#include <qpa/qplatformscreen.h>
#include <QtCore/QUuid>
+#include <QtCore/QLoggingCategory>
#include <QtGui/QPainterPath>
#ifndef QT_NO_FREETYPE
@@ -34,6 +35,7 @@
#include FT_GLYPH_H
#include FT_MODULE_H
#include FT_LCD_FILTER_H
+#include FT_MULTIPLE_MASTERS_H
#if defined(FT_CONFIG_OPTIONS_H)
#include FT_CONFIG_OPTIONS_H
@@ -53,6 +55,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcFontMatch)
+
using namespace Qt::StringLiterals;
#define FLOOR(x) ((x) & -64)
@@ -111,8 +115,11 @@ public:
QtFreetypeData::~QtFreetypeData()
{
- for (QHash<QFontEngine::FaceId, QFreetypeFace *>::ConstIterator iter = faces.cbegin(); iter != faces.cend(); ++iter)
+ for (auto iter = faces.cbegin(); iter != faces.cend(); ++iter) {
iter.value()->cleanup();
+ if (!iter.value()->ref.deref())
+ delete iter.value();
+ }
faces.clear();
FT_Done_FreeType(library);
library = nullptr;
@@ -183,10 +190,15 @@ int QFreetypeFace::getPointInOutline(glyph_t glyph, int flags, quint32 point, QF
return Err_Ok;
}
+bool QFreetypeFace::isScalable() const
+{
+ return FT_IS_SCALABLE(face);
+}
+
bool QFreetypeFace::isScalableBitmap() const
{
#ifdef FT_HAS_COLOR
- return !FT_IS_SCALABLE(face) && FT_HAS_COLOR(face);
+ return !isScalable() && FT_HAS_COLOR(face);
#else
return false;
#endif
@@ -209,10 +221,28 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
QtFreetypeData *freetypeData = qt_getFreetypeData();
- QFreetypeFace *freetype = freetypeData->faces.value(face_id, nullptr);
- if (freetype) {
- freetype->ref.ref();
- } else {
+ QFreetypeFace *freetype = nullptr;
+ auto it = freetypeData->faces.find(face_id);
+ if (it != freetypeData->faces.end()) {
+ freetype = *it;
+
+ Q_ASSERT(freetype->ref.loadRelaxed() > 0);
+ if (freetype->ref.loadRelaxed() == 1) {
+ // If there is only one reference left to the face, it means it is only referenced by
+ // the cache itself, and thus it is in cleanup state (but the final outside reference
+ // was removed on a different thread so it could not be deleted right away). We then
+ // complete the cleanup and pretend we didn't find it, so that it can be re-created with
+ // the present state.
+ freetype->cleanup();
+ freetypeData->faces.erase(it);
+ delete freetype;
+ freetype = nullptr;
+ } else {
+ freetype->ref.ref();
+ }
+ }
+
+ if (!freetype) {
const auto deleter = [](QFreetypeFace *f) { delete f; };
std::unique_ptr<QFreetypeFace, decltype(deleter)> newFreetype(new QFreetypeFace, deleter);
FT_Face face;
@@ -243,7 +273,23 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
} else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) {
return nullptr;
}
+
+#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 20900
+ if (face_id.instanceIndex >= 0) {
+ qCDebug(lcFontMatch)
+ << "Selecting named instance" << (face_id.instanceIndex)
+ << "in" << face_id.filename;
+ FT_Set_Named_Instance(face, face_id.instanceIndex + 1);
+ }
+#endif
newFreetype->face = face;
+ newFreetype->mm_var = nullptr;
+ if (FT_IS_NAMED_INSTANCE(newFreetype->face)) {
+ FT_Error ftresult;
+ ftresult = FT_Get_MM_Var(face, &newFreetype->mm_var);
+ if (ftresult != FT_Err_Ok)
+ newFreetype->mm_var = nullptr;
+ }
newFreetype->ref.storeRelaxed(1);
newFreetype->xsize = 0;
@@ -282,6 +328,25 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
FT_Set_Char_Size(face, newFreetype->face->available_sizes[0].x_ppem, newFreetype->face->available_sizes[0].y_ppem, 0, 0);
FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
+
+ if (!face_id.variableAxes.isEmpty()) {
+ FT_MM_Var *var = nullptr;
+ FT_Get_MM_Var(newFreetype->face, &var);
+ if (var != nullptr) {
+ QVarLengthArray<FT_Fixed, 16> coords(var->num_axis);
+ FT_Get_Var_Design_Coordinates(face, var->num_axis, coords.data());
+ for (FT_UInt i = 0; i < var->num_axis; ++i) {
+ if (const auto tag = QFont::Tag::fromValue(var->axis[i].tag)) {
+ const auto it = face_id.variableAxes.constFind(*tag);
+ if (it != face_id.variableAxes.constEnd())
+ coords[i] = FT_Fixed(*it * 65536);
+ }
+ }
+ FT_Set_Var_Design_Coordinates(face, var->num_axis, coords.data());
+ FT_Done_MM_Var(qt_getFreetype(), var);
+ }
+ }
+
QT_TRY {
freetypeData->faces.insert(face_id, newFreetype.get());
} QT_CATCH(...) {
@@ -290,6 +355,7 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
QT_RETHROW;
}
freetype = newFreetype.release();
+ freetype->ref.ref();
}
return freetype;
}
@@ -297,30 +363,45 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
void QFreetypeFace::cleanup()
{
hbFace.reset();
+ if (mm_var && face && face->glyph)
+ FT_Done_MM_Var(face->glyph->library, mm_var);
+ mm_var = nullptr;
FT_Done_Face(face);
face = nullptr;
}
void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
{
- if (!ref.deref()) {
- if (face) {
- QtFreetypeData *freetypeData = qt_getFreetypeData();
-
- cleanup();
-
- auto it = freetypeData->faces.constFind(face_id);
- if (it != freetypeData->faces.constEnd())
- freetypeData->faces.erase(it);
-
- if (freetypeData->faces.isEmpty()) {
- FT_Done_FreeType(freetypeData->library);
- freetypeData->library = nullptr;
+ Q_UNUSED(face_id);
+ bool deleteThis = !ref.deref();
+
+ // If the only reference left over is the cache's reference, we remove it from the cache,
+ // granted that we are on the correct thread. If not, we leave it there to be cleaned out
+ // later. While we are at it, we also purge all left over faces which are only referenced
+ // from the cache.
+ if (face && ref.loadRelaxed() == 1) {
+ QtFreetypeData *freetypeData = qt_getFreetypeData();
+ for (auto it = freetypeData->faces.constBegin(); it != freetypeData->faces.constEnd(); ) {
+ if (it.value()->ref.loadRelaxed() == 1) {
+ it.value()->cleanup();
+ if (it.value() == this)
+ deleteThis = true; // This face, delete at end of function for safety
+ else
+ delete it.value();
+ it = freetypeData->faces.erase(it);
+ } else {
+ ++it;
}
}
- delete this;
+ if (freetypeData->faces.isEmpty()) {
+ FT_Done_FreeType(freetypeData->library);
+ freetypeData->library = nullptr;
+ }
}
+
+ if (deleteThis)
+ delete this;
}
static int computeFaceIndex(const QString &faceFileName, const QString &styleName)
@@ -339,12 +420,12 @@ static int computeFaceIndex(const QString &faceFileName, const QString &styleNam
break;
}
- QString faceStyleName = QString::fromLatin1(face->style_name);
+ const bool found = QLatin1StringView(face->style_name) == styleName;
numFaces = face->num_faces;
FT_Done_Face(face);
- if (faceStyleName == styleName)
+ if (found)
return faceIndex;
} while (++faceIndex < numFaces);
@@ -674,27 +755,32 @@ namespace {
fontDef.weight = QFont::Bold;
}
- bool initFromData(const QByteArray &fontData)
+ bool initFromData(const QByteArray &fontData, const QMap<QFont::Tag, float> &variableAxisValues)
{
FaceId faceId;
faceId.filename = "";
faceId.index = 0;
faceId.uuid = QUuid::createUuid().toByteArray();
+ faceId.variableAxes = variableAxisValues;
return init(faceId, true, Format_None, fontData);
}
};
}
-QFontEngineFT *QFontEngineFT::create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
+QFontEngineFT *QFontEngineFT::create(const QByteArray &fontData,
+ qreal pixelSize,
+ QFont::HintingPreference hintingPreference,
+ const QMap<QFont::Tag, float> &variableAxisValues)
{
QFontDef fontDef;
fontDef.pixelSize = pixelSize;
fontDef.stretch = QFont::Unstretched;
fontDef.hintingPreference = hintingPreference;
+ fontDef.variableAxisValues = variableAxisValues;
QFontEngineFTRawData *fe = new QFontEngineFTRawData(fontDef);
- if (!fe->initFromData(fontData)) {
+ if (!fe->initFromData(fontData, variableAxisValues)) {
delete fe;
return nullptr;
}
@@ -747,6 +833,37 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
static void dont_delete(void*) {}
+static FT_UShort calculateActualWeight(QFreetypeFace *freetypeFace, FT_Face face, QFontEngine::FaceId faceId)
+{
+ FT_MM_Var *var = freetypeFace->mm_var;
+ if (var != nullptr && faceId.instanceIndex >= 0 && FT_UInt(faceId.instanceIndex) < var->num_namedstyles) {
+ for (FT_UInt axis = 0; axis < var->num_axis; ++axis) {
+ if (var->axis[axis].tag == QFont::Tag("wght").value()) {
+ return var->namedstyle[faceId.instanceIndex].coords[axis] >> 16;
+ }
+ }
+ }
+ if (const TT_OS2 *os2 = reinterpret_cast<const TT_OS2 *>(FT_Get_Sfnt_Table(face, ft_sfnt_os2))) {
+ return os2->usWeightClass;
+ }
+
+ return 700;
+}
+
+static bool calculateActualItalic(QFreetypeFace *freetypeFace, FT_Face face, QFontEngine::FaceId faceId)
+{
+ FT_MM_Var *var = freetypeFace->mm_var;
+ if (var != nullptr && faceId.instanceIndex >= 0 && FT_UInt(faceId.instanceIndex) < var->num_namedstyles) {
+ for (FT_UInt axis = 0; axis < var->num_axis; ++axis) {
+ if (var->axis[axis].tag == QFont::Tag("ital").value()) {
+ return (var->namedstyle[faceId.instanceIndex].coords[axis] >> 16) == 1;
+ }
+ }
+ }
+
+ return (face->style_flags & FT_STYLE_FLAG_ITALIC);
+}
+
bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
QFreetypeFace *freetypeFace)
{
@@ -770,7 +887,7 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
PS_FontInfoRec psrec;
// don't assume that type1 fonts are symbol fonts by default
if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
- symbol = !fontDef.families.isEmpty() && bool(fontDef.families.first().contains("symbol"_L1, Qt::CaseInsensitive));
+ symbol = !fontDef.families.isEmpty() && bool(fontDef.families.constFirst().contains("symbol"_L1, Qt::CaseInsensitive));
}
freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing, &scalableBitmapScaleFactor);
@@ -778,18 +895,18 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
FT_Face face = lockFace();
if (FT_IS_SCALABLE(face)) {
- bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC) && !qEnvironmentVariableIsSet("QT_NO_SYNTHESIZED_ITALIC");
+ bool isItalic = calculateActualItalic(freetype, face, faceId);
+ bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !isItalic && !qEnvironmentVariableIsSet("QT_NO_SYNTHESIZED_ITALIC");
if (fake_oblique)
obliquen = true;
FT_Set_Transform(face, &matrix, nullptr);
freetype->matrix = matrix;
// fake bold
if ((fontDef.weight >= QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face) && !qEnvironmentVariableIsSet("QT_NO_SYNTHESIZED_BOLD")) {
- if (const TT_OS2 *os2 = reinterpret_cast<const TT_OS2 *>(FT_Get_Sfnt_Table(face, ft_sfnt_os2))) {
- if (os2->usWeightClass < 700 &&
- (fontDef.pixelSize < 64 || qEnvironmentVariableIsSet("QT_NO_SYNTHESIZED_BOLD_LIMIT"))) {
- embolden = true;
- }
+ FT_UShort actualWeight = calculateActualWeight(freetype, face, faceId);
+ if (actualWeight < 700 &&
+ (fontDef.pixelSize < 64 || qEnvironmentVariableIsSet("QT_NO_SYNTHESIZED_BOLD_LIMIT"))) {
+ embolden = true;
}
}
// underline metrics
@@ -1253,7 +1370,7 @@ QFontEngine::Properties QFontEngineFT::properties() const
{
Properties p = freetype->properties();
if (p.postscriptName.isEmpty()) {
- p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.families.first().toUtf8());
+ p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(fontDef.families.constFirst().toUtf8());
}
return freetype->properties();
@@ -1480,7 +1597,7 @@ void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_me
bool QFontEngineFT::supportsTransformation(const QTransform &transform) const
{
- return transform.type() <= QTransform::TxRotate;
+ return transform.type() <= QTransform::TxRotate && (freetype->isScalable() || freetype->isScalableBitmap());
}
void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
@@ -1561,15 +1678,16 @@ glyph_t QFontEngineFT::glyphIndex(uint ucs4) const
return glyph;
}
-bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
+int QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
QFontEngine::ShaperFlags flags) const
{
Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
if (*nglyphs < len) {
*nglyphs = len;
- return false;
+ return -1;
}
+ int mappedGlyphs = 0;
int glyph_pos = 0;
if (freetype->symbol_map) {
FT_Face face = freetype->face;
@@ -1602,6 +1720,8 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs
if (uc < QFreetypeFace::cmapCacheSize)
freetype->cmapCache[uc] = glyph;
}
+ if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
+ mappedGlyphs++;
++glyph_pos;
}
} else {
@@ -1623,6 +1743,8 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs
freetype->cmapCache[uc] = glyph;
}
}
+ if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
+ mappedGlyphs++;
++glyph_pos;
}
}
@@ -1633,7 +1755,7 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs
if (!(flags & GlyphIndicesOnly))
recalcAdvances(glyphs, flags);
- return true;
+ return mappedGlyphs;
}
bool QFontEngineFT::shouldUseDesignMetrics(QFontEngine::ShaperFlags flags) const
@@ -1828,7 +1950,8 @@ glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph,
// outline drawing. To ensure the bounding box matches the rendered glyph, we
// need to do the same here.
- const bool needsImageTransform = !FT_IS_SCALABLE(freetype->face) && !matrix.isIdentity();
+ const bool needsImageTransform = !FT_IS_SCALABLE(freetype->face)
+ && matrix.type() > QTransform::TxTranslate;
if (needsImageTransform && format == QFontEngine::Format_Mono)
format = QFontEngine::Format_A8;
Glyph *g = loadGlyphFor(glyph, subPixelPosition, format, matrix, true, true);
@@ -1957,7 +2080,8 @@ QImage QFontEngineFT::alphaMapForGlyph(glyph_t g,
const QFixedPoint &subPixelPosition,
const QTransform &t)
{
- const bool needsImageTransform = !FT_IS_SCALABLE(freetype->face) && !t.isIdentity();
+ const bool needsImageTransform = !FT_IS_SCALABLE(freetype->face)
+ && t.type() > QTransform::TxTranslate;
const GlyphFormat neededFormat = antialias || needsImageTransform ? Format_A8 : Format_Mono;
Glyph *glyph = loadGlyphFor(g, subPixelPosition, neededFormat, t, false, true);
diff --git a/src/gui/text/freetype/qfontengine_ft_p.h b/src/gui/text/freetype/qfontengine_ft_p.h
index e195174960..bdd4549827 100644
--- a/src/gui/text/freetype/qfontengine_ft_p.h
+++ b/src/gui/text/freetype/qfontengine_ft_p.h
@@ -19,6 +19,7 @@
#include <ft2build.h>
#include FT_FREETYPE_H
+#include FT_MULTIPLE_MASTERS_H
#ifndef Q_OS_WIN
@@ -62,6 +63,7 @@ public:
}
FT_Face face;
+ FT_MM_Var *mm_var;
int xsize; // 26.6
int ysize; // 26.6
FT_Matrix matrix;
@@ -75,6 +77,7 @@ public:
int getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints);
+ bool isScalable() const;
bool isScalableBitmap() const;
static void addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale);
@@ -183,7 +186,7 @@ private:
void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
QPainterPath *path, QTextItem::RenderFlags flags) override;
- bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
+ int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override;
glyph_metrics_t boundingBox(glyph_t glyph) override;
@@ -266,7 +269,7 @@ private:
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);
+ static QFontEngineFT *create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference, const QMap<QFont::Tag, float> &variableAxisValue);
protected:
diff --git a/src/gui/text/freetype/qfreetypefontdatabase.cpp b/src/gui/text/freetype/qfreetypefontdatabase.cpp
index cf1ca42ab4..018e590ac2 100644
--- a/src/gui/text/freetype/qfreetypefontdatabase.cpp
+++ b/src/gui/text/freetype/qfreetypefontdatabase.cpp
@@ -10,6 +10,8 @@
#include <QtCore/QLibraryInfo>
#include <QtCore/QDir>
#include <QtCore/QtEndian>
+#include <QtCore/QLoggingCategory>
+#include <QtCore/QUuid>
#undef QT_NO_FREETYPE
#include "qfontengine_ft_p.h"
@@ -18,8 +20,14 @@
#include FT_TRUETYPE_TABLES_H
#include FT_ERRORS_H
+#include FT_MULTIPLE_MASTERS_H
+#include FT_SFNT_NAMES_H
+#include FT_TRUETYPE_IDS_H
+
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcFontDb)
+
using namespace Qt::StringLiterals;
void QFreeTypeFontDatabase::populateFontDatabase()
@@ -54,6 +62,16 @@ QFontEngine *QFreeTypeFontDatabase::fontEngine(const QFontDef &fontDef, void *us
QFontEngine::FaceId faceId;
faceId.filename = QFile::encodeName(fontfile->fileName);
faceId.index = fontfile->indexValue;
+ faceId.instanceIndex = fontfile->instanceIndex;
+ faceId.variableAxes = fontDef.variableAxisValues;
+
+ // Make sure the FaceId compares uniquely in cases where a
+ // file name is not provided.
+ if (faceId.filename.isEmpty()) {
+ QUuid::Id128Bytes id{};
+ memcpy(&id, &usrPtr, sizeof(usrPtr));
+ faceId.uuid = QUuid(id).toByteArray();
+ }
return QFontEngineFT::create(fontDef, faceId, fontfile->data);
}
@@ -61,7 +79,7 @@ QFontEngine *QFreeTypeFontDatabase::fontEngine(const QFontDef &fontDef, void *us
QFontEngine *QFreeTypeFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize,
QFont::HintingPreference hintingPreference)
{
- return QFontEngineFT::create(fontData, pixelSize, hintingPreference);
+ return QFontEngineFT::create(fontData, pixelSize, hintingPreference, {});
}
QStringList QFreeTypeFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *applicationFont)
@@ -77,6 +95,114 @@ void QFreeTypeFontDatabase::releaseHandle(void *handle)
extern FT_Library qt_getFreetype();
+void QFreeTypeFontDatabase::addNamedInstancesForFace(void *face_,
+ int faceIndex,
+ const QString &family,
+ const QString &styleName,
+ QFont::Weight weight,
+ QFont::Stretch stretch,
+ QFont::Style style,
+ bool fixedPitch,
+ const QSupportedWritingSystems &writingSystems,
+ const QByteArray &fileName,
+ const QByteArray &fontData)
+{
+ FT_Face face = reinterpret_cast<FT_Face>(face_);
+
+ // Note: The following does not actually depend on API from 2.9, but the
+ // FT_Set_Named_Instance() was added in 2.9, so to avoid populating the database with
+ // named instances that cannot be selected, we disable the feature on older Freetype
+ // versions.
+#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 20900
+ FT_MM_Var *var = nullptr;
+ FT_Get_MM_Var(face, &var);
+ if (var != nullptr) {
+ std::unique_ptr<FT_MM_Var, void(*)(FT_MM_Var*)> varGuard(var, [](FT_MM_Var *res) {
+ FT_Done_MM_Var(qt_getFreetype(), res);
+ });
+
+ for (FT_UInt i = 0; i < var->num_namedstyles; ++i) {
+ FT_UInt id = var->namedstyle[i].strid;
+
+ QFont::Weight instanceWeight = weight;
+ QFont::Stretch instanceStretch = stretch;
+ QFont::Style instanceStyle = style;
+ for (FT_UInt axis = 0; axis < var->num_axis; ++axis) {
+ if (var->axis[axis].tag == QFont::Tag("wght").value()) {
+ instanceWeight = QFont::Weight(var->namedstyle[i].coords[axis] >> 16);
+ } else if (var->axis[axis].tag == QFont::Tag("wdth").value()) {
+ instanceStretch = QFont::Stretch(var->namedstyle[i].coords[axis] >> 16);
+ } else if (var->axis[axis].tag == QFont::Tag("ital").value()) {
+ FT_UInt ital = var->namedstyle[i].coords[axis] >> 16;
+ if (ital == 1)
+ instanceStyle = QFont::StyleItalic;
+ else
+ instanceStyle = QFont::StyleNormal;
+ }
+ }
+
+ FT_UInt count = FT_Get_Sfnt_Name_Count(face);
+ for (FT_UInt j = 0; j < count; ++j) {
+ FT_SfntName name;
+ if (FT_Get_Sfnt_Name(face, j, &name))
+ continue;
+
+ if (name.name_id != id)
+ continue;
+
+ // Only support Unicode for now
+ if (name.encoding_id != TT_MS_ID_UNICODE_CS)
+ continue;
+
+ // Sfnt names stored as UTF-16BE
+ QString instanceName;
+ for (FT_UInt k = 0; k < name.string_len; k += 2)
+ instanceName += QChar((name.string[k] << 8) + name.string[k + 1]);
+ if (instanceName != styleName) {
+ FontFile *variantFontFile = new FontFile{
+ QFile::decodeName(fileName),
+ faceIndex,
+ int(i),
+ fontData
+ };
+
+ qCDebug(lcFontDb) << "Registering named instance" << i
+ << ":" << instanceName
+ << "for font family" << family
+ << "with weight" << instanceWeight
+ << ", style" << instanceStyle
+ << ", stretch" << instanceStretch;
+
+ registerFont(family,
+ instanceName,
+ QString(),
+ instanceWeight,
+ instanceStyle,
+ instanceStretch,
+ true,
+ true,
+ 0,
+ fixedPitch,
+ writingSystems,
+ variantFontFile);
+ }
+ }
+ }
+ }
+#else
+ Q_UNUSED(face);
+ Q_UNUSED(family);
+ Q_UNUSED(styleName);
+ Q_UNUSED(weight);
+ Q_UNUSED(stretch);
+ Q_UNUSED(style);
+ Q_UNUSED(fixedPitch);
+ Q_UNUSED(writingSystems);
+ Q_UNUSED(fontData);
+#endif
+
+}
+
QStringList QFreeTypeFontDatabase::addTTFile(const QByteArray &fontData, const QByteArray &file, QFontDatabasePrivate::ApplicationFont *applicationFont)
{
FT_Library library = qt_getFreetype();
@@ -194,6 +320,7 @@ QStringList QFreeTypeFontDatabase::addTTFile(const QByteArray &fontData, const Q
FontFile *fontFile = new FontFile{
QFile::decodeName(file),
index,
+ -1,
fontData
};
@@ -211,6 +338,9 @@ QStringList QFreeTypeFontDatabase::addTTFile(const QByteArray &fontData, const Q
}
registerFont(family, styleName, QString(), weight, style, stretch, true, true, 0, fixedPitch, writingSystems, fontFile);
+
+ addNamedInstancesForFace(face, index, family, styleName, weight, stretch, style, fixedPitch, writingSystems, file, fontData);
+
families.append(family);
FT_Done_Face(face);
@@ -219,4 +349,13 @@ QStringList QFreeTypeFontDatabase::addTTFile(const QByteArray &fontData, const Q
return families;
}
+bool QFreeTypeFontDatabase::supportsVariableApplicationFonts() const
+{
+#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 20900
+ return true;
+#else
+ return false;
+#endif
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/text/freetype/qfreetypefontdatabase_p.h b/src/gui/text/freetype/qfreetypefontdatabase_p.h
index ffb10a2e5c..5fcec585d2 100644
--- a/src/gui/text/freetype/qfreetypefontdatabase_p.h
+++ b/src/gui/text/freetype/qfreetypefontdatabase_p.h
@@ -26,6 +26,7 @@ struct FontFile
{
QString fileName;
int indexValue;
+ int instanceIndex = -1;
// Note: The data may be implicitly shared throughout the
// font database and platform font database, so be careful
@@ -41,6 +42,14 @@ public:
QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override;
QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *applicationFont = nullptr) override;
void releaseHandle(void *handle) override;
+ bool supportsVariableApplicationFonts() const override;
+
+ static void addNamedInstancesForFace(void *face, int faceIndex,
+ const QString &family, const QString &styleName,
+ QFont::Weight weight, QFont::Stretch stretch,
+ QFont::Style style, bool fixedPitch,
+ const QSupportedWritingSystems &writingSystems,
+ const QByteArray &fileName, const QByteArray &fontData);
static QStringList addTTFile(const QByteArray &fontData, const QByteArray &file, QFontDatabasePrivate::ApplicationFont *applicationFont = nullptr);
};
diff --git a/src/gui/text/qabstracttextdocumentlayout.cpp b/src/gui/text/qabstracttextdocumentlayout.cpp
index 9c75031e32..3e5144b157 100644
--- a/src/gui/text/qabstracttextdocumentlayout.cpp
+++ b/src/gui/text/qabstracttextdocumentlayout.cpp
@@ -101,7 +101,7 @@ QTextObjectInterface::~QTextObjectInterface()
\warning Copy and Paste operations ignore custom text objects.
- \sa {Text Object Example}, QTextCharFormat, QTextLayout
+ \sa QTextCharFormat, QTextLayout
*/
/*!
diff --git a/src/gui/text/qabstracttextdocumentlayout_p.h b/src/gui/text/qabstracttextdocumentlayout_p.h
index f10c1d9bd2..6bd42d78d8 100644
--- a/src/gui/text/qabstracttextdocumentlayout_p.h
+++ b/src/gui/text/qabstracttextdocumentlayout_p.h
@@ -19,7 +19,9 @@
#include "private/qobject_p.h"
#include "qtextdocument_p.h"
#include "qabstracttextdocumentlayout.h"
+
#include "QtCore/qhash.h"
+#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp
index f79369a36b..e5815ffce2 100644
--- a/src/gui/text/qcssparser.cpp
+++ b/src/gui/text/qcssparser.cpp
@@ -39,14 +39,18 @@ static const QCssKnownValue properties[NumProperties - 1] = {
{ "-qt-background-role", QtBackgroundRole },
{ "-qt-block-indent", QtBlockIndent },
{ "-qt-fg-texture-cachekey", QtForegroundTextureCacheKey },
+ { "-qt-foreground", QtForeground },
{ "-qt-line-height-type", QtLineHeightType },
{ "-qt-list-indent", QtListIndent },
{ "-qt-list-number-prefix", QtListNumberPrefix },
{ "-qt-list-number-suffix", QtListNumberSuffix },
{ "-qt-paragraph-type", QtParagraphType },
+ { "-qt-stroke-color", QtStrokeColor },
+ { "-qt-stroke-width", QtStrokeWidth },
{ "-qt-style-features", QtStyleFeatures },
{ "-qt-table-type", QtTableType },
{ "-qt-user-state", QtUserState },
+ { "accent-color", QtAccent },
{ "alternate-background-color", QtAlternateBackground },
{ "background", Background },
{ "background-attachment", BackgroundAttachment },
@@ -811,6 +815,10 @@ static BrushData parseBrushValue(const QCss::Value &v, const QPalette &pal)
QStringList spreads;
spreads << "pad"_L1 << "reflect"_L1 << "repeat"_L1;
+ int coordinateMode = -1;
+ QStringList coordinateModes;
+ coordinateModes << "logical"_L1 << "stretchtodevice"_L1 << "objectbounding"_L1 << "object"_L1;
+
bool dependsOnThePalette = false;
Parser parser(lst.at(1));
while (parser.hasNext()) {
@@ -837,11 +845,12 @@ static BrushData parseBrushValue(const QCss::Value &v, const QPalette &pal)
parser.next();
QCss::Value value;
(void)parser.parseTerm(&value);
- if (attr.compare("spread"_L1, Qt::CaseInsensitive) == 0) {
+ if (attr.compare("spread"_L1, Qt::CaseInsensitive) == 0)
spread = spreads.indexOf(value.variant.toString());
- } else {
+ else if (attr.compare("coordinatemode"_L1, Qt::CaseInsensitive) == 0)
+ coordinateMode = coordinateModes.indexOf(value.variant.toString());
+ else
vars[attr] = value.variant.toReal();
- }
}
parser.skipSpace();
(void)parser.test(COMMA);
@@ -850,7 +859,7 @@ static BrushData parseBrushValue(const QCss::Value &v, const QPalette &pal)
if (gradType == 0) {
QLinearGradient lg(vars.value("x1"_L1), vars.value("y1"_L1),
vars.value("x2"_L1), vars.value("y2"_L1));
- lg.setCoordinateMode(QGradient::ObjectBoundingMode);
+ lg.setCoordinateMode(coordinateMode < 0 ? QGradient::ObjectBoundingMode : QGradient::CoordinateMode(coordinateMode));
lg.setStops(stops);
if (spread != -1)
lg.setSpread(QGradient::Spread(spread));
@@ -864,7 +873,7 @@ static BrushData parseBrushValue(const QCss::Value &v, const QPalette &pal)
QRadialGradient rg(vars.value("cx"_L1), vars.value("cy"_L1),
vars.value("radius"_L1), vars.value("fx"_L1),
vars.value("fy"_L1));
- rg.setCoordinateMode(QGradient::ObjectBoundingMode);
+ rg.setCoordinateMode(coordinateMode < 0 ? QGradient::ObjectBoundingMode : QGradient::CoordinateMode(coordinateMode));
rg.setStops(stops);
if (spread != -1)
rg.setSpread(QGradient::Spread(spread));
@@ -876,7 +885,7 @@ static BrushData parseBrushValue(const QCss::Value &v, const QPalette &pal)
if (gradType == 2) {
QConicalGradient cg(vars.value("cx"_L1), vars.value("cy"_L1), vars.value("angle"_L1));
- cg.setCoordinateMode(QGradient::ObjectBoundingMode);
+ cg.setCoordinateMode(coordinateMode < 0 ? QGradient::ObjectBoundingMode : QGradient::CoordinateMode(coordinateMode));
cg.setStops(stops);
if (spread != -1)
cg.setSpread(QGradient::Spread(spread));
@@ -978,9 +987,11 @@ void ValueExtractor::borderValue(const Declaration &decl, int *width, QCss::Bord
}
data.color = parseBrushValue(decl.d->values.at(i), pal);
- *color = brushFromData(data.color, pal);
- if (data.color.type != BrushData::DependsOnThePalette)
- decl.d->parsed = QVariant::fromValue<BorderData>(data);
+ if (data.color.type != BrushData::Invalid) {
+ *color = brushFromData(data.color, pal);
+ if (data.color.type != BrushData::DependsOnThePalette)
+ decl.d->parsed = QVariant::fromValue<BorderData>(data);
+ }
}
static void parseShorthandBackgroundProperty(const QList<QCss::Value> &values, BrushData *brush, QString *image, Repeat *repeat, Qt::Alignment *alignment, const QPalette &pal)
@@ -1341,17 +1352,23 @@ bool ValueExtractor::extractFont(QFont *font, int *fontSizeAdjustment)
return hit;
}
-bool ValueExtractor::extractPalette(QBrush *fg, QBrush *sfg, QBrush *sbg, QBrush *abg, QBrush *pfg)
+bool ValueExtractor::extractPalette(QBrush *foreground,
+ QBrush *selectedForeground,
+ QBrush *selectedBackground,
+ QBrush *alternateBackground,
+ QBrush *placeHolderTextForeground,
+ QBrush *accent)
{
bool hit = false;
for (int i = 0; i < declarations.size(); ++i) {
const Declaration &decl = declarations.at(i);
switch (decl.d->propertyId) {
- case Color: *fg = decl.brushValue(pal); break;
- case QtSelectionForeground: *sfg = decl.brushValue(pal); break;
- case QtSelectionBackground: *sbg = decl.brushValue(pal); break;
- case QtAlternateBackground: *abg = decl.brushValue(pal); break;
- case QtPlaceHolderTextColor: *pfg = decl.brushValue(pal); break;
+ case Color: *foreground = decl.brushValue(pal); break;
+ case QtSelectionForeground: *selectedForeground = decl.brushValue(pal); break;
+ case QtSelectionBackground: *selectedBackground = decl.brushValue(pal); break;
+ case QtAlternateBackground: *alternateBackground = decl.brushValue(pal); break;
+ case QtPlaceHolderTextColor: *placeHolderTextForeground = decl.brushValue(pal); break;
+ case QtAccent: *accent = decl.brushValue(pal); break;
default: continue;
}
hit = true;
diff --git a/src/gui/text/qcssparser_p.h b/src/gui/text/qcssparser_p.h
index 8e4c7ce62d..c1cfb1ac9b 100644
--- a/src/gui/text/qcssparser_p.h
+++ b/src/gui/text/qcssparser_p.h
@@ -166,6 +166,10 @@ enum Property {
WordSpacing,
TextDecorationColor,
QtPlaceHolderTextColor,
+ QtAccent,
+ QtStrokeWidth,
+ QtStrokeColor,
+ QtForeground,
NumProperties
};
@@ -823,7 +827,9 @@ struct Q_GUI_EXPORT ValueExtractor
bool extractBox(int *margins, int *paddings, int *spacing = nullptr);
bool extractBorder(int *borders, QBrush *colors, BorderStyle *Styles, QSize *radii);
bool extractOutline(int *borders, QBrush *colors, BorderStyle *Styles, QSize *radii, int *offsets);
- bool extractPalette(QBrush *fg, QBrush *sfg, QBrush *sbg, QBrush *abg, QBrush *pfg);
+ bool extractPalette(QBrush *foreground, QBrush *selectedForeground, QBrush *selectedBackground,
+ QBrush *alternateBackground, QBrush *placeHolderTextForeground,
+ QBrush *accent);
int extractStyleFeatures();
bool extractImage(QIcon *icon, Qt::Alignment *a, QSize *size);
bool extractIcon(QIcon *icon, QSize *size);
diff --git a/src/gui/text/qdistancefield.cpp b/src/gui/text/qdistancefield.cpp
index adbde11237..fe230188c6 100644
--- a/src/gui/text/qdistancefield.cpp
+++ b/src/gui/text/qdistancefield.cpp
@@ -1058,7 +1058,7 @@ QImage QDistanceField::toImage(QImage::Format format) const
}
if (image.format() != format)
- image = image.convertToFormat(format);
+ image = std::move(image).convertToFormat(format);
}
return image;
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index 1efe3c06d8..f3b861957e 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -90,6 +90,9 @@ bool QFontDef::exactMatch(const QFontDef &other) const
return false;
}
+ if (variableAxisValues != other.variableAxisValues)
+ return false;
+
return (styleHint == other.styleHint
&& styleStrategy == other.styleStrategy
&& weight == other.weight
@@ -213,7 +216,7 @@ QFontPrivate::QFontPrivate(const QFontPrivate &other)
strikeOut(other.strikeOut), kerning(other.kerning),
capital(other.capital), letterSpacingIsAbsolute(other.letterSpacingIsAbsolute),
letterSpacing(other.letterSpacing), wordSpacing(other.wordSpacing),
- scFont(other.scFont)
+ features(other.features), scFont(other.scFont)
{
if (scFont && scFont != this)
scFont->ref.ref();
@@ -343,9 +346,38 @@ void QFontPrivate::resolve(uint mask, const QFontPrivate *other)
wordSpacing = other->wordSpacing;
if (! (mask & QFont::CapitalizationResolved))
capital = other->capital;
+
+ if (!(mask & QFont::FeaturesResolved))
+ features = other->features;
+
+ if (!(mask & QFont::VariableAxesResolved))
+ request.variableAxisValues = other->request.variableAxisValues;
}
+bool QFontPrivate::hasVariableAxis(QFont::Tag tag, float value) const
+{
+ return request.variableAxisValues.contains(tag) && request.variableAxisValues.value(tag) == value;
+}
+
+void QFontPrivate::setVariableAxis(QFont::Tag tag, float value)
+{
+ request.variableAxisValues.insert(tag, value);
+}
+
+void QFontPrivate::unsetVariableAxis(QFont::Tag tag)
+{
+ request.variableAxisValues.remove(tag);
+}
+
+void QFontPrivate::setFeature(QFont::Tag tag, quint32 value)
+{
+ features.insert(tag, value);
+}
+void QFontPrivate::unsetFeature(QFont::Tag tag)
+{
+ features.remove(tag);
+}
QFontEngineData::QFontEngineData()
@@ -460,8 +492,6 @@ QFontEngineData::~QFontEngineData()
The font matching algorithm works as follows:
\list 1
\li The specified font families (set by setFamilies()) are searched for.
- \li If not found, then if set the specified font family exists and can be used to represent
- the writing system in use, it will be selected.
\li If not, a replacement font that supports the writing system is
selected. The font matching algorithm will try to find the
best match for all the properties set in the QFont. How this is
@@ -531,7 +561,7 @@ QFontEngineData::~QFontEngineData()
Information on encodings can be found from the
\l{UTR17} page.
- \sa QFontMetrics, QFontInfo, QFontDatabase, {Character Map Example}
+ \sa QFontMetrics, QFontInfo, QFontDatabase
*/
/*!
@@ -912,12 +942,6 @@ int QFont::pointSize() const
\li No hinting
\endtable
- \note Please be aware that altering the hinting preference on Windows is available through
- the DirectWrite font engine. This is available on Windows Vista after installing the platform
- update, and on Windows 7. In order to use this extension, configure Qt using -directwrite.
- The target application will then depend on the availability of DirectWrite on the target
- system.
-
*/
/*!
@@ -1438,6 +1462,14 @@ QFont::StyleHint QFont::styleHint() const
\value NoAntialias don't antialias the fonts.
\value NoSubpixelAntialias avoid subpixel antialiasing on the fonts if possible.
\value PreferAntialias antialias if possible.
+ \value [since 6.8] ContextFontMerging If the selected font does not contain a certain character,
+ then Qt automatically chooses a similar-looking fallback font that contains the
+ character. By default this is done on a character-by-character basis. This means that in
+ certain uncommon cases, multiple fonts may be used to represent one string of text even
+ if it's in the same script. Setting \c ContextFontMerging will try finding the fallback
+ font that matches the largest subset of the input string instead. This will be more
+ expensive for strings where missing glyphs occur, but may give more consistent results.
+ If \c NoFontMerging is set, then \c ContextFontMerging will have no effect.
\value NoFontMerging If the font selected for a certain writing system
does not contain a character requested to draw, then Qt automatically chooses a similar
looking font that contains the character. The NoFontMerging flag disables this feature.
@@ -1510,7 +1542,7 @@ void QFont::setStyleStrategy(StyleStrategy s)
Predefined stretch values that follow the CSS naming convention. The higher
the value, the more stretched the text is.
- \value AnyStretch 0 Accept any stretch matched using the other QFont properties (added in Qt 5.8)
+ \value [since 5.8] AnyStretch 0 Accept any stretch matched using the other QFont properties
\value UltraCondensed 50
\value ExtraCondensed 62
\value Condensed 75
@@ -1748,6 +1780,7 @@ bool QFont::operator==(const QFont &f) const
&& f.d->letterSpacingIsAbsolute == d->letterSpacingIsAbsolute
&& f.d->letterSpacing == d->letterSpacing
&& f.d->wordSpacing == d->wordSpacing
+ && f.d->features == d->features
));
}
@@ -1785,7 +1818,37 @@ bool QFont::operator<(const QFont &f) const
int f1attrs = (f.d->underline << 3) + (f.d->overline << 2) + (f.d->strikeOut<<1) + f.d->kerning;
int f2attrs = (d->underline << 3) + (d->overline << 2) + (d->strikeOut<<1) + d->kerning;
- return f1attrs < f2attrs;
+ if (f1attrs != f2attrs) return f1attrs < f2attrs;
+
+ if (d->features.size() != f.d->features.size())
+ return f.d->features.size() < d->features.size();
+
+ {
+ auto it = d->features.constBegin();
+ auto jt = f.d->features.constBegin();
+ for (; it != d->features.constEnd(); ++it, ++jt) {
+ if (it.key() != jt.key())
+ return jt.key() < it.key();
+ if (it.value() != jt.value())
+ return jt.value() < it.value();
+ }
+ }
+
+ if (r1.variableAxisValues.size() != r2.variableAxisValues.size())
+ return r1.variableAxisValues.size() < r2.variableAxisValues.size();
+
+ {
+ auto it = r1.variableAxisValues.constBegin();
+ auto jt = r2.variableAxisValues.constBegin();
+ for (; it != r1.variableAxisValues.constEnd(); ++it, ++jt) {
+ if (it.key() != jt.key())
+ return jt.key() < it.key();
+ if (it.value() != jt.value())
+ return jt.value() < it.value();
+ }
+ }
+
+ return false;
}
@@ -2206,6 +2269,404 @@ void QFont::cacheStatistics()
{
}
+/*!
+ \class QFont::Tag
+ \brief The QFont::Tag type provides access to advanced font features.
+ \since 6.7
+ \inmodule QtGui
+
+ QFont provides access to advanced features when shaping text. A feature is defined
+ by a tag, which can be represented as a four-character string, or as a 32bit integer
+ value. This type represents such a tag in a type-safe way. It can be constructed from
+ a four-character, 8bit string literal, or from a corresponding 32bit integer value.
+ Using a shorter or longer string literal will result in a compile-time error.
+
+ \code
+ QFont font;
+ // Correct
+ font.setFeature("frac");
+
+ // Wrong - won't compile
+ font.setFeature("fraction");
+
+ // Wrong - will produce runtime warning and fail
+ font.setFeature(u"fraction"_s);
+ \endcode
+
+ The named constructors allow to create a tag from an 32bit integer or string value,
+ and will return a \c std::nullopt when the input is invalid.
+
+ \sa QFont::setFeature(), QFont::featureTags()
+*/
+
+/*!
+ \fn QFont::Tag::Tag()
+
+ Default constructor, producing an invalid tag.
+*/
+
+/*!
+ \fn template <size_t N> QFont::Tag::Tag(const char (&str)[N]) noexcept
+
+ Constructs a tag from a string literal, \a str. The literal must be exactly four
+ characters long.
+
+ \code
+ font.setFeature("frac", 1);
+ \endcode
+
+ \sa fromString(), fromValue()
+*/
+
+/*!
+ \fn bool QFont::Tag::comparesEqual(const QFont::Tag &lhs, const QFont::Tag &rhs) noexcept
+ \fn Qt::strong_ordering QFont::Tag::compareThreeWay(const QFont::Tag &lhs, const QFont::Tag &rhs) noexcept
+
+ Compare \a lhs with \a rhs for equality and ordering.
+*/
+
+/*!
+ \fn size_t QFont::Tag::qHash(QFont::Tag key, size_t seed) noexcept
+
+ Returns the hash value for \a key, using \a seed to seed the calculation.
+*/
+
+/*!
+ \fn quint32 QFont::Tag::value() const noexcept
+
+ Returns the numerical value of this tag.
+
+ \sa isValid(), fromValue()
+*/
+
+/*!
+ \fn bool QFont::Tag::isValid() const noexcept
+
+ Returns whether the tag is valid. A tag is valid if its value is not zero.
+
+ \sa value(), fromValue(), fromString()
+*/
+
+/*!
+ \fn QByteArray QFont::Tag::toString() const noexcept
+
+ Returns the string representation of this tag as a byte array.
+
+ \sa fromString()
+*/
+
+/*!
+ \fn std::optional<QFont::Tag> QFont::Tag::fromValue(quint32 value) noexcept
+
+ Returns a tag constructed from \a value, or \c std::nullopt if the tag produced
+ would be invalid.
+
+ \sa isValid()
+*/
+
+/*!
+ Returns a tag constructed from the string in \a view. The string must be exactly
+ four characters long.
+
+ Returns \c std::nullopt if the input is not four characters long, or if the tag
+ produced would be invalid.
+
+ \sa isValid(), fromValue()
+*/
+std::optional<QFont::Tag> QFont::Tag::fromString(QAnyStringView view) noexcept
+{
+ if (view.size() != 4) {
+ qWarning("The tag name must be exactly 4 characters long!");
+ return std::nullopt;
+ }
+ const QFont::Tag maybeTag = view.visit([](auto view) {
+ using CharType = decltype(view.at(0));
+ if constexpr (std::is_same_v<CharType, char>) {
+ const char bytes[5] = { view.at(0), view.at(1), view.at(2), view.at(3), 0 };
+ return Tag(bytes);
+ } else {
+ const char bytes[5] = { view.at(0).toLatin1(), view.at(1).toLatin1(),
+ view.at(2).toLatin1(), view.at(3).toLatin1(), 0 };
+ return Tag(bytes);
+ }
+ });
+ return maybeTag.isValid() ? std::optional<Tag>(maybeTag) : std::nullopt;
+}
+
+/*!
+ \fn QDataStream &operator<<(QDataStream &, QFont::Tag)
+ \fn QDataStream &operator>>(QDataStream &, QFont::Tag &)
+ \relates QFont::Tag
+
+ Data stream operators for QFont::Tag.
+*/
+
+/*!
+ \since 6.7
+
+ Applies a \a value to the variable axis corresponding to \a tag.
+
+ Variable fonts provide a way to store multiple variations (with different weights, widths
+ or styles) in the same font file. The variations are given as floating point values for
+ a pre-defined set of parameters, called "variable axes". Specific instances are typically
+ given names by the font designer, and, in Qt, these can be selected using setStyleName()
+ just like traditional sub-families.
+
+ In some cases, it is also useful to provide arbitrary values for the different axes. For
+ instance, if a font has a Regular and Bold sub-family, you may want a weight in-between these.
+ You could then manually request this by supplying a custom value for the "wght" axis in the
+ font.
+
+ \code
+ QFont font;
+ font.setVariableAxis("wght", (QFont::Normal + QFont::Bold) / 2.0f);
+ \endcode
+
+ If the "wght" axis is supported by the font and the given value is within its defined range,
+ a font corresponding to the weight 550.0 will be provided.
+
+ There are a few standard axes than many fonts provide, such as "wght" (weight), "wdth" (width),
+ "ital" (italic) and "opsz" (optical size). They each have indivdual ranges defined in the font
+ itself. For instance, "wght" may span from 100 to 900 (QFont::Thin to QFont::Black) whereas
+ "ital" can span from 0 to 1 (from not italic to fully italic).
+
+ A font may also choose to define custom axes; the only limitation is that the name has to
+ meet the requirements for a QFont::Tag (sequence of four latin-1 characters.)
+
+ By default, no variable axes are set.
+
+ \note In order to use variable axes on Windows, the application has to run with either the
+ FreeType or DirectWrite font databases. See the documentation for
+ QGuiApplication::QGuiApplication() for more information on how to select these technologies.
+
+ \sa unsetVariableAxis
+ */
+void QFont::setVariableAxis(Tag tag, float value)
+{
+ if (tag.isValid()) {
+ if (resolve_mask & QFont::VariableAxesResolved && d->hasVariableAxis(tag, value))
+ return;
+
+ detach();
+
+ d->setVariableAxis(tag, value);
+ resolve_mask |= QFont::VariableAxesResolved;
+ }
+}
+
+/*!
+ \since 6.7
+
+ Unsets a previously set variable axis value given by \a tag.
+
+ \note If no value has previously been given for this tag, the QFont will still consider its
+ variable axes as set when resolving against other QFont values.
+
+ \sa setVariableAxis
+*/
+void QFont::unsetVariableAxis(Tag tag)
+{
+ if (tag.isValid()) {
+ detach();
+
+ d->unsetVariableAxis(tag);
+ resolve_mask |= QFont::VariableAxesResolved;
+ }
+}
+
+/*!
+ \since 6.7
+
+ Returns a list of tags for all variable axes currently set on this QFont.
+
+ See \l{QFont::}{setVariableAxis()} for more details on variable axes.
+
+ \sa QFont::Tag, setVariableAxis(), unsetVariableAxis(), isVariableAxisSet(), clearVariableAxes()
+*/
+QList<QFont::Tag> QFont::variableAxisTags() const
+{
+ return d->request.variableAxisValues.keys();
+}
+
+/*!
+ \since 6.7
+
+ Returns the value set for a specific variable axis \a tag. If the tag has not been set, 0.0 will
+ be returned instead.
+
+ See \l{QFont::}{setVariableAxis()} for more details on variable axes.
+
+ \sa QFont::Tag, setVariableAxis(), unsetVariableAxis(), isVariableAxisSet(), clearVariableAxes()
+*/
+float QFont::variableAxisValue(Tag tag) const
+{
+ return d->request.variableAxisValues.value(tag);
+}
+
+/*!
+ \since 6.7
+
+ Returns true if a value for the variable axis given by \a tag has been set on the QFont,
+ otherwise returns false.
+
+ See \l{QFont::}{setVariableAxis()} for more details on font variable axes.
+
+ \sa QFont::Tag, setVariableAxis(), unsetVariableAxis(), variableAxisValue(), clearVariableAxes()
+*/
+bool QFont::isVariableAxisSet(Tag tag) const
+{
+ return d->request.variableAxisValues.contains(tag);
+}
+
+/*!
+ \since 6.7
+
+ Clears any previously set variable axis values on the QFont.
+
+ See \l{QFont::}{setVariableAxis()} for more details on variable axes.
+
+ \sa QFont::Tag, setVariableAxis(), unsetVariableAxis(), isVariableAxisSet(), variableAxisValue()
+*/
+void QFont::clearVariableAxes()
+{
+ if (d->request.variableAxisValues.isEmpty())
+ return;
+
+ detach();
+ d->request.variableAxisValues.clear();
+}
+
+
+/*!
+ \since 6.7
+ \overload
+
+ Applies an integer value to the typographical feature specified by \a tag when shaping the
+ text. This provides advanced access to the font shaping process, and can be used to support
+ font features that are otherwise not covered in the API.
+
+ The feature is specified by a \l{QFont::Tag}{tag}, which is typically encoded from the
+ four-character feature name in the font feature map.
+
+ This integer \a value passed along with the tag in most cases represents a boolean value: A zero
+ value means the feature is disabled, and a non-zero value means it is enabled. For certain
+ font features, however, it may have other interpretations. For example, when applied to the
+ \c salt feature, the value is an index that specifies the stylistic alternative to use.
+
+ For example, the \c frac font feature will convert diagonal fractions separated with a slash
+ (such as \c 1/2) with a different representation. Typically this will involve baking the full
+ fraction into a single character width (such as \c ½).
+
+ If a font supports the \c frac feature, then it can be enabled in the shaper by setting
+ \c{features["frac"] = 1} in the font feature map.
+
+ \note By default, Qt will enable and disable certain font features based on other font
+ properties. In particular, the \c kern feature will be enabled/disabled depending on the
+ \l kerning() property of the QFont. In addition, all ligature features
+ (\c liga, \c clig, \c dlig, \c hlig) will be disabled if a \l letterSpacing() is applied,
+ but only for writing systems where the use of ligature is cosmetic. For writing systems where
+ ligatures are required, the features will remain in their default state. The values set using
+ setFeature() and related functions will override the default behavior. If, for instance,
+ the feature "kern" is set to 1, then kerning will always be enabled, regardless of whether the
+ kerning property is set to false. Similarly, if it is set to 0, then it will always be disabled.
+ To reset a font feature to its default behavior, you can unset it using unsetFeature().
+
+ \sa QFont::Tag, clearFeatures(), setFeature(), unsetFeature(), featureTags()
+*/
+void QFont::setFeature(Tag tag, quint32 value)
+{
+ if (tag.isValid()) {
+ d->detachButKeepEngineData(this);
+ d->setFeature(tag, value);
+ resolve_mask |= QFont::FeaturesResolved;
+ }
+}
+
+/*!
+ \since 6.7
+ \overload
+
+ Unsets the \a tag from the map of explicitly enabled/disabled features.
+
+ \note Even if the feature has not previously been added, this will mark the font features map
+ as modified in this QFont, so that it will take precedence when resolving against other fonts.
+
+ Unsetting an existing feature on the QFont reverts behavior to the default.
+
+ See \l setFeature() for more details on font features.
+
+ \sa QFont::Tag, clearFeatures(), setFeature(), featureTags(), featureValue()
+*/
+void QFont::unsetFeature(Tag tag)
+{
+ if (tag.isValid()) {
+ d->detachButKeepEngineData(this);
+ d->unsetFeature(tag);
+ resolve_mask |= QFont::FeaturesResolved;
+ }
+}
+
+/*!
+ \since 6.7
+
+ Returns a list of tags for all font features currently set on this QFont.
+
+ See \l{QFont::}{setFeature()} for more details on font features.
+
+ \sa QFont::Tag, setFeature(), unsetFeature(), isFeatureSet(), clearFeatures()
+*/
+QList<QFont::Tag> QFont::featureTags() const
+{
+ return d->features.keys();
+}
+
+/*!
+ \since 6.7
+
+ Returns the value set for a specific feature \a tag. If the tag has not been set, 0 will be
+ returned instead.
+
+ See \l{QFont::}{setFeature()} for more details on font features.
+
+ \sa QFont::Tag, setFeature(), unsetFeature(), featureTags(), isFeatureSet()
+*/
+quint32 QFont::featureValue(Tag tag) const
+{
+ return d->features.value(tag);
+}
+
+/*!
+ \since 6.7
+
+ Returns true if a value for the feature given by \a tag has been set on the QFont, otherwise
+ returns false.
+
+ See \l{QFont::}{setFeature()} for more details on font features.
+
+ \sa QFont::Tag, setFeature(), unsetFeature(), featureTags(), featureValue()
+*/
+bool QFont::isFeatureSet(Tag tag) const
+{
+ return d->features.contains(tag);
+}
+
+/*!
+ \since 6.7
+
+ Clears any previously set features on the QFont.
+
+ See \l{QFont::}{setFeature()} for more details on font features.
+
+ \sa QFont::Tag, setFeature(), unsetFeature(), featureTags(), featureValue()
+*/
+void QFont::clearFeatures()
+{
+ if (d->features.isEmpty())
+ return;
+
+ d->detachButKeepEngineData(this);
+ d->features.clear();
+}
extern QStringList qt_fallbacksForFamily(const QString &family, QFont::Style style,
QFont::StyleHint styleHint, QChar::Script script);
@@ -2285,9 +2746,9 @@ void QFont::setFamilies(const QStringList &families)
QDataStream &operator<<(QDataStream &s, const QFont &font)
{
if (s.version() == 1) {
- s << font.d->request.families.first().toLatin1();
+ s << font.d->request.families.constFirst().toLatin1();
} else {
- s << font.d->request.families.first();
+ s << font.d->request.families.constFirst();
if (s.version() >= QDataStream::Qt_5_4)
s << font.d->request.styleName;
}
@@ -2343,6 +2804,10 @@ QDataStream &operator<<(QDataStream &s, const QFont &font)
else
s << font.d->request.families;
}
+ if (s.version() >= QDataStream::Qt_6_6)
+ s << font.d->features;
+ if (s.version() >= QDataStream::Qt_6_7)
+ s << font.d->request.variableAxisValues;
return s;
}
@@ -2457,9 +2922,35 @@ QDataStream &operator>>(QDataStream &s, QFont &font)
else
font.d->request.families = value;
}
+ if (s.version() >= QDataStream::Qt_6_6) {
+ font.d->features.clear();
+ s >> font.d->features;
+ }
+ if (s.version() >= QDataStream::Qt_6_7) {
+ font.d->request.variableAxisValues.clear();
+ s >> font.d->request.variableAxisValues;
+ }
+
return s;
}
+QDataStream &operator<<(QDataStream &stream, QFont::Tag tag)
+{
+ stream << tag.value();
+ return stream;
+}
+
+QDataStream &operator>>(QDataStream &stream, QFont::Tag &tag)
+{
+ quint32 value;
+ stream >> value;
+ if (const auto maybeTag = QFont::Tag::fromValue(value))
+ tag = *maybeTag;
+ else
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return stream;
+}
+
#endif // QT_NO_DATASTREAM
@@ -2510,6 +3001,35 @@ QDataStream &operator>>(QDataStream &s, QFont &font)
info object is \e not updated.
\endlist
+ \section1 Checking for the existence of a font
+
+ Sometimes it can be useful to check if a font exists before attempting
+ to use it. The most thorough way of doing so is by using \l {exactMatch()}:
+
+ \code
+ const QFont segoeFont(QLatin1String("Segoe UI"));
+ if (QFontInfo(segoeFont).exactMatch()) {
+ // Use the font...
+ }
+ \endcode
+
+ However, this deep search of families can be expensive on some platforms.
+ \c QFontDatabase::families().contains() is a faster, but less thorough
+ alternative:
+
+ \code
+ const QLatin1String segoeUiFamilyName("Segoe UI");
+ if (QFontDatabase::families().contains(segoeUiFamilyName)) {
+ const QFont segoeFont(segoeUiFamilyName);
+ // Use the font...
+ }
+ \endcode
+
+ It's less thorough because it's not a complete search: some font family
+ aliases may be missing from the list. However, this approach results in
+ faster application startup times, and so should always be preferred if
+ possible.
+
\sa QFont, QFontMetrics, QFontDatabase
*/
@@ -2526,6 +3046,8 @@ QDataStream &operator>>(QDataStream &s, QFont &font)
Use QPainter::fontInfo() to get the font info when painting.
This will give correct results also when painting on paint device
that is not screen-compatible.
+
+ \sa {Checking for the existence of a font}
*/
QFontInfo::QFontInfo(const QFont &font)
: d(font.d)
@@ -2567,13 +3089,13 @@ QFontInfo &QFontInfo::operator=(const QFontInfo &fi)
/*!
Returns the family name of the matched window system font.
- \sa QFont::family()
+ \sa QFont::family(), {Checking for the existence of a font}
*/
QString QFontInfo::family() const
{
QFontEngine *engine = d->engineForScript(QChar::Script_Common);
Q_ASSERT(engine != nullptr);
- return engine->fontDef.families.isEmpty() ? QString() : engine->fontDef.families.first();
+ return engine->fontDef.families.isEmpty() ? QString() : engine->fontDef.families.constFirst();
}
/*!
@@ -2752,7 +3274,7 @@ bool QFontInfo::fixedPitch() const
QChar ch[2] = { u'i', u'm' };
QGlyphLayoutArray<2> g;
int l = 2;
- if (!engine->stringToCMap(ch, 2, &g, &l, {}))
+ if (engine->stringToCMap(ch, 2, &g, &l, {}) < 0)
Q_UNREACHABLE();
Q_ASSERT(l == 2);
engine->fontDef.fixedPitch = g.advances[0] == g.advances[1];
@@ -3305,6 +3827,13 @@ QDebug operator<<(QDebug stream, const QFont &font)
return stream;
}
+
+QDebug operator<<(QDebug debug, QFont::Tag tag)
+{
+ QDebugStateSaver saver(debug);
+ debug.noquote() << tag.toString();
+ return debug;
+}
#endif
QT_END_NAMESPACE
diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h
index 6a5c890395..66a5f7c155 100644
--- a/src/gui/text/qfont.h
+++ b/src/gui/text/qfont.h
@@ -4,6 +4,8 @@
#ifndef QFONT_H
#define QFONT_H
+#include <QtCore/qcompare.h>
+#include <QtCore/qendian.h>
#include <QtCore/qshareddata.h>
#include <QtGui/qtguiglobal.h>
#include <QtGui/qwindowdefs.h>
@@ -45,6 +47,7 @@ public:
NoAntialias = 0x0100,
NoSubpixelAntialias = 0x0800,
PreferNoShaping = 0x1000,
+ ContextFontMerging = 0x2000,
NoFontMerging = 0x8000
};
Q_ENUM(StyleStrategy)
@@ -126,7 +129,9 @@ public:
HintingPreferenceResolved = 0x8000,
StyleNameResolved = 0x10000,
FamiliesResolved = 0x20000,
- AllPropertiesResolved = 0x3ffff
+ FeaturesResolved = 0x40000,
+ VariableAxesResolved = 0x80000,
+ AllPropertiesResolved = 0xfffff
};
Q_ENUM(ResolveProperties)
@@ -206,6 +211,75 @@ public:
void setHintingPreference(HintingPreference hintingPreference);
HintingPreference hintingPreference() const;
+ struct Tag
+ {
+ constexpr Tag() = default;
+
+ template <size_t N>
+ constexpr Q_IMPLICIT Tag(const char (&str)[N]) noexcept
+ : m_value((quint32(str[0]) << 24) | (quint32(str[1]) << 16)
+ | (quint32(str[2]) << 8) | quint32(str[3]))
+ {
+ static_assert(N == 5, "The tag name must be exactly 4 characters long!");
+ }
+
+ constexpr bool isValid() const noexcept { return m_value != 0; }
+ constexpr quint32 value() const noexcept { return m_value; }
+
+ QByteArray toString() const
+ {
+ const char data[] = {
+ char((m_value & 0xff000000) >> 24),
+ char((m_value & 0x00ff0000) >> 16),
+ char((m_value & 0x0000ff00) >> 8),
+ char((m_value & 0x000000ff)) };
+ return QByteArray(data, sizeof(data));
+ }
+
+ static constexpr std::optional<Tag> fromValue(quint32 value) noexcept
+ {
+ Tag maybeTag;
+ maybeTag.m_value = value;
+ return maybeTag.isValid() ? std::optional<Tag>(maybeTag) : std::nullopt;
+ }
+ Q_GUI_EXPORT static std::optional<Tag> fromString(QAnyStringView view) noexcept;
+
+#ifndef QT_NO_DATASTREAM
+ friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, Tag);
+ friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, Tag &);
+#endif
+
+#ifndef QT_NO_DEBUG_STREAM
+ friend Q_GUI_EXPORT QDebug operator<<(QDebug debug, Tag tag);
+#endif
+
+ friend constexpr size_t qHash(Tag key, size_t seed = 0) noexcept
+ { return qHash(key.value(), seed); }
+
+ private:
+ friend constexpr bool comparesEqual(const Tag &lhs, const Tag &rhs) noexcept
+ { return lhs.m_value == rhs.m_value; }
+ friend constexpr Qt::strong_ordering compareThreeWay(const Tag &lhs, const Tag &rhs) noexcept
+ { return Qt::compareThreeWay(lhs.m_value, rhs.m_value); }
+ Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(QFont::Tag)
+
+ quint32 m_value = 0;
+ };
+
+ void setFeature(Tag tag, quint32 value);
+ void unsetFeature(Tag tag);
+ quint32 featureValue(Tag tag) const;
+ bool isFeatureSet(Tag tag) const;
+ QList<Tag> featureTags() const;
+ void clearFeatures();
+
+ void setVariableAxis(Tag tag, float value);
+ void unsetVariableAxis(Tag tag);
+ bool isVariableAxisSet(Tag tag) const;
+ float variableAxisValue(Tag tag) const;
+ void clearVariableAxes();
+ QList<Tag> variableAxisTags() const;
+
// dupicated from QFontInfo
bool exactMatch() const;
diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h
index 13738bb096..b674e71103 100644
--- a/src/gui/text/qfont_p.h
+++ b/src/gui/text/qfont_p.h
@@ -55,6 +55,7 @@ struct QFontDef
QString styleName;
QStringList fallBackFamilies;
+ QMap<QFont::Tag, float> variableAxisValues;
qreal pointSize;
qreal pixelSize;
@@ -85,6 +86,7 @@ struct QFontDef
&& families == other.families
&& styleName == other.styleName
&& hintingPreference == other.hintingPreference
+ && variableAxisValues == other.variableAxisValues
;
}
inline bool operator<(const QFontDef &other) const
@@ -103,6 +105,22 @@ struct QFontDef
if (ignorePitch != other.ignorePitch) return ignorePitch < other.ignorePitch;
if (fixedPitch != other.fixedPitch) return fixedPitch < other.fixedPitch;
+ if (variableAxisValues != other.variableAxisValues) {
+ if (variableAxisValues.size() != other.variableAxisValues.size())
+ return variableAxisValues.size() < other.variableAxisValues.size();
+
+ {
+ auto it = variableAxisValues.constBegin();
+ auto jt = other.variableAxisValues.constBegin();
+ for (; it != variableAxisValues.constEnd(); ++it, ++jt) {
+ if (it.key() != jt.key())
+ return jt.key() < it.key();
+ if (it.value() != jt.value())
+ return jt.value() < it.value();
+ }
+ }
+ }
+
return false;
}
};
@@ -120,7 +138,9 @@ inline size_t qHash(const QFontDef &fd, size_t seed = 0) noexcept
fd.fixedPitch,
fd.families,
fd.styleName,
- fd.hintingPreference);
+ fd.hintingPreference,
+ fd.variableAxisValues.keys(),
+ fd.variableAxisValues.values());
}
class QFontEngineData
@@ -164,6 +184,7 @@ public:
QFixed letterSpacing;
QFixed wordSpacing;
+ QHash<QFont::Tag, quint32> features;
mutable QFontPrivate *scFont;
QFont smallCapsFont() const { return QFont(smallCapsFontPrivate()); }
@@ -178,6 +199,13 @@ public:
static void detachButKeepEngineData(QFont *font);
+ void setFeature(QFont::Tag tag, quint32 value);
+ void unsetFeature(QFont::Tag tag);
+
+ void setVariableAxis(QFont::Tag tag, float value);
+ void unsetVariableAxis(QFont::Tag tag);
+ bool hasVariableAxis(QFont::Tag tag, float value) const;
+
private:
QFontPrivate &operator=(const QFontPrivate &) { return *this; }
};
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp
index 5dd3437e35..d3a13d801b 100644
--- a/src/gui/text/qfontdatabase.cpp
+++ b/src/gui/text/qfontdatabase.cpp
@@ -670,7 +670,8 @@ static QStringList fallbacksForFamily(const QString &family, QFont::Style style,
return *fallbacks;
// make sure that the db has all fallback families
- QStringList retList = QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fallbacksForFamily(family,style,styleHint,script);
+ QStringList userFallbacks = db->applicationFallbackFontFamilies.value(script == QChar::Script_Common ? QChar::Script_Latin : script);
+ QStringList retList = userFallbacks + QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fallbacksForFamily(family,style,styleHint,script);
QStringList::iterator i;
for (i = retList.begin(); i != retList.end(); ++i) {
@@ -733,7 +734,7 @@ QFontEngine *QFontDatabasePrivate::loadSingleEngine(int script,
// Also check for OpenType tables when using complex scripts
if (Q_UNLIKELY(!engine->supportsScript(QChar::Script(script)))) {
qWarning(" OpenType support missing for \"%s\", script %d",
- qPrintable(def.families.first()), script);
+ qPrintable(def.families.constFirst()), script);
return nullptr;
}
@@ -758,7 +759,7 @@ QFontEngine *QFontDatabasePrivate::loadSingleEngine(int script,
// Also check for OpenType tables when using complex scripts
if (!engine->supportsScript(QChar::Script(script))) {
qWarning(" OpenType support missing for \"%s\", script %d",
- +qPrintable(def.families.first()), script);
+ +qPrintable(def.families.constFirst()), script);
if (engine->ref.loadRelaxed() == 0)
delete engine;
return nullptr;
@@ -1201,7 +1202,7 @@ QString QFontDatabase::styleString(const QFontInfo &fontInfo)
each combination of family and style, displaying this information
in a tree view.
- \sa QFont, QFontInfo, QFontMetrics, {Character Map Example}
+ \sa QFont, QFontInfo, QFontMetrics
*/
/*!
@@ -2360,6 +2361,126 @@ bool QFontDatabase::removeAllApplicationFonts()
}
/*!
+ \since 6.8
+
+ Adds \a familyName as an application-defined fallback font for \a script.
+
+ When Qt encounters characters that are not supported by the selected font, it will search
+ through a list of fallback fonts to find a match for them. This ensures that combining multiple
+ scripts in a single string is possible, even if the main font does not support them.
+
+ The list of fallback fonts is selected based on the script of the string as well as other
+ conditions, such as system language.
+
+ While the system fallback list is usually sufficient, there are cases where it is useful
+ to override the default behavior. One such case is for using application fonts as fallback to
+ ensure cross-platform consistency.
+
+ In another case the application may be written in a script with regional differences and want
+ to run it untranslated in multiple regions. In this case, it might be useful to override the
+ local region's fallback with one that matches the language of the application.
+
+ By passing \a familyName to addApplicationFallbackFontFamily(), this will become the preferred
+ family when matching missing characters from \a script. The \a script must be a valid script
+ (\c QChar::Script_Latin or higher). When adding multiple fonts for the same script, they will
+ be prioritized in reverse order, so that the last family added will be checked first and so
+ on.
+
+ \sa setApplicationFallbackFontFamilies(), removeApplicationFallbackFontFamily(), applicationFallbackFontFamilies()
+*/
+void QFontDatabase::addApplicationFallbackFontFamily(QChar::Script script, const QString &familyName)
+{
+ QMutexLocker locker(fontDatabaseMutex());
+
+ if (script < QChar::Script_Latin) {
+ qCWarning(lcFontDb) << "Invalid script passed to addApplicationFallbackFontFamily:" << script;
+ return;
+ }
+
+ auto *db = QFontDatabasePrivate::instance();
+ auto it = db->applicationFallbackFontFamilies.find(script);
+ if (it == db->applicationFallbackFontFamilies.end())
+ it = db->applicationFallbackFontFamilies.insert(script, QStringList{});
+
+ it->prepend(familyName);
+ db->fallbacksCache.clear();
+}
+
+/*!
+ \since 6.8
+
+ Removes \a familyName from the list of application-defined fallback fonts for \a script,
+ provided that it has previously been added with \l{addApplicationFallbackFontFamily()}.
+
+ Returns true if the family name was in the list and false if it was not.
+
+ \sa addApplicationFallbackFontFamily(), setApplicationFallbackFontFamilies(), applicationFallbackFontFamilies()
+*/
+bool QFontDatabase::removeApplicationFallbackFontFamily(QChar::Script script, const QString &familyName)
+{
+ QMutexLocker locker(fontDatabaseMutex());
+
+ auto *db = QFontDatabasePrivate::instance();
+ auto it = db->applicationFallbackFontFamilies.find(script);
+ if (it != db->applicationFallbackFontFamilies.end()) {
+ if (it->removeAll(familyName) > 0) {
+ if (it->isEmpty())
+ it = db->applicationFallbackFontFamilies.erase(it);
+ QFontCache::instance()->clear();
+ db->fallbacksCache.clear();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/*!
+ \since 6.8
+
+ Sets the list of application-defined fallback fonts for \a script to \a familyNames.
+
+ When Qt encounters a character in \a script which is not supported by the current font, it will
+ check the families in \a familyNames, in order from first to last, until it finds a match. See
+ \l{addApplicationFallbackFontFamily()} for more details.
+
+ This function overwrites the current list of application-defined fallback fonts for \a script.
+
+ \sa addApplicationFallbackFontFamily(), removeApplicationFallbackFontFamily(), applicationFallbackFontFamilies()
+*/
+void QFontDatabase::setApplicationFallbackFontFamilies(QChar::Script script, const QStringList &familyNames)
+{
+ QMutexLocker locker(fontDatabaseMutex());
+
+ if (script < QChar::Script_Latin) {
+ qCWarning(lcFontDb) << "Invalid script passed to setApplicationFallbackFontFamilies:" << script;
+ return;
+ }
+
+ auto *db = QFontDatabasePrivate::instance();
+ db->applicationFallbackFontFamilies[script] = familyNames;
+
+ QFontCache::instance()->clear();
+ db->fallbacksCache.clear();
+}
+
+/*!
+ \since 6.8
+
+ Returns the list of application-defined fallback font families previously added for \a script
+ by the \l{addApplicationFallbackFontFamily()} function.
+
+ \sa setApplicationFallbackFontFamilies(), addApplicationFallbackFontFamily(), removeApplicationFallbackFontFamily()
+*/
+QStringList QFontDatabase::applicationFallbackFontFamilies(QChar::Script script)
+{
+ QMutexLocker locker(fontDatabaseMutex());
+
+ auto *db = QFontDatabasePrivate::instance();
+ return db->applicationFallbackFontFamilies.value(script);
+}
+
+/*!
\internal
*/
QFontEngine *QFontDatabasePrivate::findFont(const QFontDef &req,
@@ -2465,7 +2586,7 @@ QFontEngine *QFontDatabasePrivate::findFont(const QFontDef &req,
if (!engine) {
QtFontDesc desc;
do {
- index = match(multi ? QChar::Script_Common : script, def, def.families.first(), ""_L1, &desc, blackListed);
+ index = match(multi ? QChar::Script_Common : script, def, def.families.constFirst(), ""_L1, &desc, blackListed);
if (index >= 0) {
QFontDef loadDef = def;
if (loadDef.families.isEmpty())
@@ -2541,7 +2662,7 @@ void QFontDatabasePrivate::load(const QFontPrivate *d, int script)
family_list << req.families.at(0);
// add the default family
- auto families = QGuiApplication::font().families();
+ const auto families = QGuiApplication::font().families();
if (!families.isEmpty()) {
QString defaultFamily = families.first();
if (! family_list.contains(defaultFamily))
diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h
index c66451a164..91a534265e 100644
--- a/src/gui/text/qfontdatabase.h
+++ b/src/gui/text/qfontdatabase.h
@@ -112,6 +112,11 @@ public:
static bool removeApplicationFont(int id);
static bool removeAllApplicationFonts();
+ static void addApplicationFallbackFontFamily(QChar::Script script, const QString &familyName);
+ static bool removeApplicationFallbackFontFamily(QChar::Script script, const QString &familyName);
+ static void setApplicationFallbackFontFamilies(QChar::Script, const QStringList &familyNames);
+ static QStringList applicationFallbackFontFamilies(QChar::Script script);
+
static QFont systemFont(SystemFont type);
};
diff --git a/src/gui/text/qfontdatabase_p.h b/src/gui/text/qfontdatabase_p.h
index a0796d25c0..38e1b4ad20 100644
--- a/src/gui/text/qfontdatabase_p.h
+++ b/src/gui/text/qfontdatabase_p.h
@@ -204,6 +204,8 @@ public:
QtFontFamily **families;
bool populated = false;
+ QHash<QChar::Script, QStringList> applicationFallbackFontFamilies;
+
QCache<QtFontFallbacksCacheKey, QStringList> fallbacksCache;
struct ApplicationFont {
QString fileName;
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 5035b61fe9..4e78aaac2e 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -13,6 +13,7 @@
#include "qpainter.h"
#include "qpainterpath.h"
#include "qvarlengtharray.h"
+#include "qtextengine_p.h"
#include <qmath.h>
#include <qendian.h>
#include <private/qstringiterator_p.h>
@@ -182,8 +183,10 @@ bool QFontEngine::supportsScript(QChar::Script script) const
#if QT_CONFIG(harfbuzz)
// in AAT fonts, 'gsub' table is effectively replaced by 'mort'/'morx' table
uint lenMort = 0, lenMorx = 0;
- if (getSfntTableData(MAKE_TAG('m','o','r','t'), nullptr, &lenMort) || getSfntTableData(MAKE_TAG('m','o','r','x'), nullptr, &lenMorx))
+ if (getSfntTableData(QFont::Tag("mort").value(), nullptr, &lenMort)
+ || getSfntTableData(QFont::Tag("morx").value(), nullptr, &lenMorx)) {
return true;
+ }
if (hb_face_t *face = hb_qt_face_get_for_engine(const_cast<QFontEngine *>(this))) {
unsigned int script_count = HB_OT_MAX_TAGS_PER_SCRIPT;
@@ -381,7 +384,7 @@ void QFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rig
bool QFontEngine::processHheaTable() const
{
- QByteArray hhea = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a'));
+ QByteArray hhea = getSfntTable(QFont::Tag("hhea").value());
if (hhea.size() >= 10) {
auto ptr = hhea.constData();
qint16 ascent = qFromBigEndian<qint16>(ptr + 4);
@@ -407,9 +410,9 @@ bool QFontEngine::processHheaTable() const
void QFontEngine::initializeHeightMetrics() const
{
bool hasEmbeddedBitmaps =
- !getSfntTable(MAKE_TAG('E', 'B', 'L', 'C')).isEmpty()
- || !getSfntTable(MAKE_TAG('C', 'B', 'L', 'C')).isEmpty()
- || !getSfntTable(MAKE_TAG('b', 'd', 'a', 't')).isEmpty();
+ !getSfntTable(QFont::Tag("EBLC").value()).isEmpty()
+ || !getSfntTable(QFont::Tag("CBLC").value()).isEmpty()
+ || !getSfntTable(QFont::Tag("bdat").value()).isEmpty();
if (!hasEmbeddedBitmaps) {
// Get HHEA table values if available
processHheaTable();
@@ -429,7 +432,7 @@ void QFontEngine::initializeHeightMetrics() const
bool QFontEngine::processOS2Table() const
{
- QByteArray os2 = getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
+ QByteArray os2 = getSfntTable(QFont::Tag("OS/2").value());
if (os2.size() >= 78) {
auto ptr = os2.constData();
quint16 fsSelection = qFromBigEndian<quint16>(ptr + 62);
@@ -505,7 +508,7 @@ qreal QFontEngine::minRightBearing() const
if (m_minRightBearing == kBearingNotInitialized) {
// Try the 'hhea' font table first, which covers the entire font
- QByteArray hheaTable = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a'));
+ QByteArray hheaTable = getSfntTable(QFont::Tag("hhea").value());
if (hheaTable.size() >= int(kMinRightSideBearingOffset + sizeof(qint16))) {
const uchar *tableData = reinterpret_cast<const uchar *>(hheaTable.constData());
Q_ASSERT(q16Dot16ToFloat(qFromBigEndian<quint32>(tableData)) == 1.0);
@@ -1045,7 +1048,7 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor)
{
kerning_pairs.clear();
- QByteArray tab = getSfntTable(MAKE_TAG('k', 'e', 'r', 'n'));
+ QByteArray tab = getSfntTable(QFont::Tag("kern").value());
if (tab.isEmpty())
return;
@@ -1134,7 +1137,7 @@ end:
int QFontEngine::glyphCount() const
{
- QByteArray maxpTable = getSfntTable(MAKE_TAG('m', 'a', 'x', 'p'));
+ QByteArray maxpTable = getSfntTable(QFont::Tag("maxp").value());
if (maxpTable.size() < 6)
return 0;
@@ -1181,7 +1184,7 @@ const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSy
int tableToUse = -1;
int score = Invalid;
for (int n = 0; n < numTables; ++n) {
- quint16 platformId;
+ quint16 platformId = 0;
if (!qSafeFromBigEndian(maps + 8 * n, endPtr, &platformId))
return nullptr;
@@ -1232,6 +1235,7 @@ const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSy
default:
break;
}
+ break;
default:
break;
}
@@ -1311,7 +1315,7 @@ resolveTable:
quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode)
{
const uchar *end = cmap + cmapSize;
- quint16 format;
+ quint16 format = 0;
if (!qSafeFromBigEndian(cmap, end, &format))
return 0;
@@ -1328,7 +1332,7 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint
if (unicode >= 0xffff)
return 0;
- quint16 segCountX2;
+ quint16 segCountX2 = 0;
if (!qSafeFromBigEndian(cmap + 6, end, &segCountX2))
return 0;
@@ -1336,7 +1340,7 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint
int i = 0;
for (; i < segCountX2/2; ++i) {
- quint16 codePoint;
+ quint16 codePoint = 0;
if (!qSafeFromBigEndian(ends + 2 * i, end, &codePoint))
return 0;
if (codePoint >= unicode)
@@ -1345,7 +1349,7 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint
const unsigned char *idx = ends + segCountX2 + 2 + 2*i;
- quint16 startIndex;
+ quint16 startIndex = 0;
if (!qSafeFromBigEndian(idx, end, &startIndex))
return 0;
if (startIndex > unicode)
@@ -1353,20 +1357,20 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint
idx += segCountX2;
- quint16 tmp;
+ quint16 tmp = 0;
if (!qSafeFromBigEndian(idx, end, &tmp))
return 0;
qint16 idDelta = qint16(tmp);
idx += segCountX2;
- quint16 idRangeoffset_t;
+ quint16 idRangeoffset_t = 0;
if (!qSafeFromBigEndian(idx, end, &idRangeoffset_t))
return 0;
- quint16 glyphIndex;
+ quint16 glyphIndex = 0;
if (idRangeoffset_t) {
- quint16 id;
+ quint16 id = 0;
if (!qSafeFromBigEndian(idRangeoffset_t + 2 * (unicode - startIndex) + idx, end, &id))
return 0;
@@ -1379,17 +1383,17 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint
}
return glyphIndex;
} else if (format == 6) {
- quint16 tableSize;
+ quint16 tableSize = 0;
if (!qSafeFromBigEndian(cmap + 2, end, &tableSize))
return 0;
- quint16 firstCode6;
+ quint16 firstCode6 = 0;
if (!qSafeFromBigEndian(cmap + 6, end, &firstCode6))
return 0;
if (unicode < firstCode6)
return 0;
- quint16 entryCount6;
+ quint16 entryCount6 = 0;
if (!qSafeFromBigEndian(cmap + 8, end, &entryCount6))
return 0;
if (entryCount6 * 2 + 10 > tableSize)
@@ -1405,7 +1409,7 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint
qSafeFromBigEndian(cmap + 10 + (entryIndex6 * 2), end, &index);
return index;
} else if (format == 12) {
- quint32 nGroups;
+ quint32 nGroups = 0;
if (!qSafeFromBigEndian(cmap + 12, end, &nGroups))
return 0;
@@ -1415,19 +1419,19 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint
while (left <= right) {
int middle = left + ( ( right - left ) >> 1 );
- quint32 startCharCode;
+ quint32 startCharCode = 0;
if (!qSafeFromBigEndian(cmap + 12 * middle, end, &startCharCode))
return 0;
if (unicode < startCharCode)
right = middle - 1;
else {
- quint32 endCharCode;
+ quint32 endCharCode = 0;
if (!qSafeFromBigEndian(cmap + 12 * middle + 4, end, &endCharCode))
return 0;
if (unicode <= endCharCode) {
- quint32 index;
+ quint32 index = 0;
if (!qSafeFromBigEndian(cmap + 12 * middle + 8, end, &index))
return 0;
@@ -1471,10 +1475,10 @@ bool QFontEngine::hasUnreliableGlyphOutline() const
QFixed QFontEngine::firstLeftBearing(const QGlyphLayout &glyphs)
{
- if (glyphs.numGlyphs >= 1) {
- glyph_t glyph = glyphs.glyphs[0];
+ for (int i = 0; i < glyphs.numGlyphs; ++i) {
+ glyph_t glyph = glyphs.glyphs[i];
glyph_metrics_t gi = boundingBox(glyph);
- if (gi.isValid())
+ if (gi.isValid() && gi.width > 0)
return gi.leftBearing();
}
return 0;
@@ -1539,12 +1543,12 @@ glyph_t QFontEngineBox::glyphIndex(uint ucs4) const
return 1;
}
-bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
+int QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
{
Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
if (*nglyphs < len) {
*nglyphs = len;
- return false;
+ return -1;
}
int ucs4Length = 0;
@@ -1560,7 +1564,7 @@ bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyph
if (!(flags & GlyphIndicesOnly))
recalcAdvances(glyphs, flags);
- return true;
+ return *nglyphs;
}
void QFontEngineBox::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const
@@ -1727,7 +1731,7 @@ void QFontEngineMulti::ensureFallbackFamiliesQueried()
if (styleHint == QFont::AnyStyle && fontDef.fixedPitch)
styleHint = QFont::TypeWriter;
- setFallbackFamiliesList(qt_fallbacksForFamily(fontDef.families.first(),
+ setFallbackFamiliesList(qt_fallbacksForFamily(fontDef.families.constFirst(),
QFont::Style(fontDef.style), styleHint,
QChar::Script(m_script)));
}
@@ -1743,7 +1747,7 @@ void QFontEngineMulti::setFallbackFamiliesList(const QStringList &fallbackFamili
QFontEngine *engine = m_engines.at(0);
engine->ref.ref();
m_engines[1] = engine;
- m_fallbackFamilies << fontDef.families.first();
+ m_fallbackFamilies << fontDef.families.constFirst();
} else {
m_engines.resize(m_fallbackFamilies.size() + 1);
}
@@ -1790,11 +1794,7 @@ QFontEngine *QFontEngineMulti::loadEngine(int at)
glyph_t QFontEngineMulti::glyphIndex(uint ucs4) const
{
glyph_t glyph = engine(0)->glyphIndex(ucs4);
- if (glyph == 0
- && ucs4 != QChar::LineSeparator
- && ucs4 != QChar::LineFeed
- && ucs4 != QChar::CarriageReturn
- && ucs4 != QChar::ParagraphSeparator) {
+ if (glyph == 0 && !isIgnorableChar(ucs4)) {
if (!m_fallbackFamiliesQueried)
const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) {
@@ -1821,13 +1821,55 @@ glyph_t QFontEngineMulti::glyphIndex(uint ucs4) const
return glyph;
}
-bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
- QGlyphLayout *glyphs, int *nglyphs,
- QFontEngine::ShaperFlags flags) const
+int QFontEngineMulti::stringToCMap(const QChar *str, int len,
+ QGlyphLayout *glyphs, int *nglyphs,
+ QFontEngine::ShaperFlags flags) const
{
- if (!engine(0)->stringToCMap(str, len, glyphs, nglyphs, flags))
- return false;
+ const int originalNumGlyphs = glyphs->numGlyphs;
+ int mappedGlyphCount = engine(0)->stringToCMap(str, len, glyphs, nglyphs, flags);
+ if (mappedGlyphCount < 0)
+ return -1;
+
+ // If ContextFontMerging is set and the match for the string was incomplete, we try all
+ // fallbacks on the full string until we find the best match.
+ bool contextFontMerging = mappedGlyphCount < *nglyphs && (fontDef.styleStrategy & QFont::ContextFontMerging);
+ if (contextFontMerging) {
+ QVarLengthGlyphLayoutArray tempLayout(len);
+ if (!m_fallbackFamiliesQueried)
+ const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
+
+ int maxGlyphCount = 0;
+ uchar engineIndex = 0;
+ for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) {
+ int numGlyphs = len;
+ const_cast<QFontEngineMulti *>(this)->ensureEngineAt(x);
+ maxGlyphCount = engine(x)->stringToCMap(str, len, &tempLayout, &numGlyphs, flags);
+
+ // If we found a better match, we copy data into the main QGlyphLayout
+ if (maxGlyphCount > mappedGlyphCount) {
+ *nglyphs = numGlyphs;
+ glyphs->numGlyphs = originalNumGlyphs;
+ glyphs->copy(&tempLayout);
+ engineIndex = x;
+ if (maxGlyphCount == numGlyphs)
+ break;
+ }
+ }
+ if (engineIndex > 0) {
+ for (int y = 0; y < glyphs->numGlyphs; ++y) {
+ if (glyphs->glyphs[y] != 0)
+ glyphs->glyphs[y] |= (engineIndex << 24);
+ }
+ } else {
+ contextFontMerging = false;
+ }
+
+ mappedGlyphCount = maxGlyphCount;
+ }
+
+ // Fill in missing glyphs by going through string one character at the time and finding
+ // the first viable fallback.
int glyph_pos = 0;
QStringIterator it(str, str + len);
@@ -1858,15 +1900,10 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
lastFallback = -1;
}
- if (glyphs->glyphs[glyph_pos] == 0
- && ucs4 != QChar::LineSeparator
- && ucs4 != QChar::LineFeed
- && ucs4 != QChar::CarriageReturn
- && ucs4 != QChar::ParagraphSeparator
- && QChar::category(ucs4) != QChar::Other_PrivateUse) {
+ if (glyphs->glyphs[glyph_pos] == 0 && !isIgnorableChar(ucs4)) {
if (!m_fallbackFamiliesQueried)
const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
- for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) {
+ for (int x = contextFontMerging ? 0 : 1, n = qMin(m_engines.size(), 256); x < n; ++x) {
QFontEngine *engine = m_engines.at(x);
if (!engine) {
if (!shouldLoadFontEngineForCharacter(x, ucs4))
@@ -1905,17 +1942,32 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
int precedingCharacterFontEngine = glyphs->glyphs[glyph_pos - 1] >> 24;
if (selectorFontEngine != precedingCharacterFontEngine) {
- QFontEngine *engine = m_engines.at(selectorFontEngine);
- glyph_t glyph = engine->glyphIndex(previousUcs4);
- if (glyph != 0) {
- glyphs->glyphs[glyph_pos - 1] = glyph;
- if (!(flags & GlyphIndicesOnly)) {
- QGlyphLayout g = glyphs->mid(glyph_pos - 1, 1);
- engine->recalcAdvances(&g, flags);
+ // Emoji variant selectors are specially handled and should affect font
+ // selection. If VS-16 is used, then this means we want to select a color
+ // font. If the selected font is already a color font, we do not need search
+ // again. If the VS-15 is used, then this means we want to select a non-color
+ // font. If the selected font is not a color font, we don't do anything.
+ const QFontEngine *selectedEngine = m_engines.at(precedingCharacterFontEngine);
+ const bool colorFont = selectedEngine->isColorFont();
+ const char32_t vs15 = 0xFE0E;
+ const char32_t vs16 = 0xFE0F;
+ bool adaptVariantSelector = ucs4 < vs15
+ || (ucs4 == vs15 && colorFont)
+ || (ucs4 == vs16 && !colorFont);
+
+ if (adaptVariantSelector) {
+ QFontEngine *engine = m_engines.at(selectorFontEngine);
+ glyph_t glyph = engine->glyphIndex(previousUcs4);
+ if (glyph != 0) {
+ glyphs->glyphs[glyph_pos - 1] = glyph;
+ if (!(flags & GlyphIndicesOnly)) {
+ QGlyphLayout g = glyphs->mid(glyph_pos - 1, 1);
+ engine->recalcAdvances(&g, flags);
+ }
+
+ // set the high byte to indicate which engine the glyph came from
+ glyphs->glyphs[glyph_pos - 1] |= (selectorFontEngine << 24);
}
-
- // set the high byte to indicate which engine the glyph came from
- glyphs->glyphs[glyph_pos - 1] |= (selectorFontEngine << 24);
}
}
}
@@ -1928,8 +1980,7 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
*nglyphs = glyph_pos;
glyphs->numGlyphs = glyph_pos;
-
- return true;
+ return mappedGlyphCount;
}
bool QFontEngineMulti::shouldLoadFontEngineForCharacter(int at, uint ucs4) const
@@ -2221,7 +2272,7 @@ bool QFontEngineMulti::canRender(const QChar *string, int len) const
QGlyphLayout g;
g.numGlyphs = nglyphs;
g.glyphs = glyphs.data();
- if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly))
+ if (stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly) < 0)
Q_UNREACHABLE();
for (int i = 0; i < nglyphs; i++) {
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index dbad0d95f9..a0e0801354 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -29,13 +29,6 @@ class QFontEngineGlyphCache;
struct QGlyphLayout;
-#define MAKE_TAG(ch1, ch2, ch3, ch4) (\
- (((quint32)(ch1)) << 24) | \
- (((quint32)(ch2)) << 16) | \
- (((quint32)(ch3)) << 8) | \
- ((quint32)(ch4)) \
- )
-
// ### this only used in getPointInOutline(), refactor it and then remove these magic numbers
enum HB_Compat_Error {
Err_Ok = 0x0000,
@@ -83,7 +76,8 @@ public:
enum ShaperFlag {
DesignMetrics = 0x0002,
- GlyphIndicesOnly = 0x0004
+ GlyphIndicesOnly = 0x0004,
+ FullStringFallback = 0x008
};
Q_DECLARE_FLAGS(ShaperFlags, ShaperFlag)
@@ -127,11 +121,13 @@ public:
virtual bool getSfntTableData(uint tag, uchar *buffer, uint *length) const;
struct FaceId {
- FaceId() : index(0), encoding(0) {}
+ FaceId() : index(0), instanceIndex(-1), encoding(0) {}
QByteArray filename;
QByteArray uuid;
int index;
+ int instanceIndex;
int encoding;
+ QMap<QFont::Tag, float> variableAxes;
};
virtual FaceId faceId() const { return FaceId(); }
enum SynthesizedFlags {
@@ -152,11 +148,21 @@ public:
return subPixelPositionFor(QFixedPoint(x, 0)).x;
}
+ bool isColorFont() const { return glyphFormat == Format_ARGB; }
+ static bool isIgnorableChar(char32_t ucs4)
+ {
+ return ucs4 == QChar::LineSeparator
+ || ucs4 == QChar::LineFeed
+ || ucs4 == QChar::CarriageReturn
+ || ucs4 == QChar::ParagraphSeparator
+ || QChar::category(ucs4) == QChar::Other_Control;
+ }
+
virtual QFixed emSquareSize() const { return ascent(); }
/* returns 0 as glyph index for non existent glyphs */
virtual glyph_t glyphIndex(uint ucs4) const = 0;
- virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const = 0;
+ virtual int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const = 0;
virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const {}
virtual void doKerning(QGlyphLayout *, ShaperFlags) const;
@@ -370,13 +376,18 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QFontEngine::ShaperFlags)
inline bool operator ==(const QFontEngine::FaceId &f1, const QFontEngine::FaceId &f2)
{
- return f1.index == f2.index && f1.encoding == f2.encoding && f1.filename == f2.filename && f1.uuid == f2.uuid;
+ return f1.index == f2.index
+ && f1.encoding == f2.encoding
+ && f1.filename == f2.filename
+ && f1.uuid == f2.uuid
+ && f1.instanceIndex == f2.instanceIndex
+ && f1.variableAxes == f2.variableAxes;
}
inline size_t qHash(const QFontEngine::FaceId &f, size_t seed = 0)
noexcept(noexcept(qHash(f.filename)))
{
- return qHashMulti(seed, f.filename, f.uuid, f.index, f.encoding);
+ return qHashMulti(seed, f.filename, f.uuid, f.index, f.instanceIndex, f.encoding, f.variableAxes.keys(), f.variableAxes.values());
}
@@ -391,7 +402,7 @@ public:
~QFontEngineBox();
virtual glyph_t glyphIndex(uint ucs4) const override;
- virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
+ virtual int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const override;
void draw(QPaintEngine *p, qreal x, qreal y, const QTextItemInt &si);
@@ -429,7 +440,7 @@ public:
~QFontEngineMulti();
virtual glyph_t glyphIndex(uint ucs4) const override;
- virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
+ virtual int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override;
virtual glyph_metrics_t boundingBox(glyph_t glyph) override;
diff --git a/src/gui/text/qfontinfo.h b/src/gui/text/qfontinfo.h
index c162003801..0edee5abe5 100644
--- a/src/gui/text/qfontinfo.h
+++ b/src/gui/text/qfontinfo.h
@@ -7,6 +7,8 @@
#include <QtGui/qtguiglobal.h>
#include <QtGui/qfont.h>
+#include <QtCore/qshareddata.h>
+
QT_BEGIN_NAMESPACE
diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp
index cd0886440b..f7e405f0b5 100644
--- a/src/gui/text/qfontmetrics.cpp
+++ b/src/gui/text/qfontmetrics.cpp
@@ -91,7 +91,7 @@ extern void qt_format_text(const QFont& font, const QRectF &_r,
Example:
\snippet code/src_gui_text_qfontmetrics.cpp 0
- \sa QFont, QFontInfo, QFontDatabase, {Character Map Example}
+ \sa QFont, QFontInfo, QFontDatabase
*/
/*!
diff --git a/src/gui/text/qfontmetrics.h b/src/gui/text/qfontmetrics.h
index 8f16ccb5a7..1942d1fa83 100644
--- a/src/gui/text/qfontmetrics.h
+++ b/src/gui/text/qfontmetrics.h
@@ -6,9 +6,11 @@
#include <QtGui/qtguiglobal.h>
#include <QtGui/qfont.h>
+
#ifndef QT_INCLUDE_COMPAT
#include <QtCore/qrect.h>
#endif
+#include <QtCore/qshareddata.h>
QT_BEGIN_NAMESPACE
diff --git a/src/gui/text/qfontsubset.cpp b/src/gui/text/qfontsubset.cpp
index 1f5ffac8d4..f6c973e522 100644
--- a/src/gui/text/qfontsubset.cpp
+++ b/src/gui/text/qfontsubset.cpp
@@ -401,7 +401,7 @@ static QTtfTable generateHead(const qttf_head_table &head)
{
const int head_size = 54;
QTtfTable t;
- t.tag = MAKE_TAG('h', 'e', 'a', 'd');
+ t.tag = QFont::Tag("head").value();
t.data.resize(head_size);
QTtfStream s(t.data);
@@ -472,7 +472,7 @@ static QTtfTable generateHhea(const qttf_hhea_table &hhea)
{
const int hhea_size = 36;
QTtfTable t;
- t.tag = MAKE_TAG('h', 'h', 'e', 'a');
+ t.tag = QFont::Tag("hhea").value();
t.data.resize(hhea_size);
QTtfStream s(t.data);
@@ -523,7 +523,7 @@ static QTtfTable generateMaxp(const qttf_maxp_table &maxp)
{
const int maxp_size = 32;
QTtfTable t;
- t.tag = MAKE_TAG('m', 'a', 'x', 'p');
+ t.tag = QFont::Tag("maxp").value();
t.data.resize(maxp_size);
QTtfStream s(t.data);
@@ -603,7 +603,7 @@ static QTtfTable generateName(const QList<QTtfNameRecord> &name)
const int char_size = 2;
QTtfTable t;
- t.tag = MAKE_TAG('n', 'a', 'm', 'e');
+ t.tag = QFont::Tag("name").value();
const int name_size = 6 + 12*name.size();
int string_size = 0;
@@ -958,15 +958,15 @@ static QList<QTtfTable> generateGlyphTables(qttf_font_tables &tables, const QLis
tables.hhea.numberOfHMetrics = nGlyphs;
QTtfTable glyf;
- glyf.tag = MAKE_TAG('g', 'l', 'y', 'f');
+ glyf.tag = QFont::Tag("glyf").value();
QTtfTable loca;
- loca.tag = MAKE_TAG('l', 'o', 'c', 'a');
+ loca.tag = QFont::Tag("loca").value();
loca.data.resize(glyf_size < max_size_small ? (nGlyphs+1)*sizeof(quint16) : (nGlyphs+1)*sizeof(quint32));
QTtfStream ls(loca.data);
QTtfTable hmtx;
- hmtx.tag = MAKE_TAG('h', 'm', 't', 'x');
+ hmtx.tag = QFont::Tag("hmtx").value();
hmtx.data.resize(nGlyphs*4);
QTtfStream hs(hmtx.data);
@@ -1066,7 +1066,7 @@ static QByteArray bindFont(const QList<QTtfTable>& _tables)
for (int i = 0; i < tables.size(); ++i) {
const QTtfTable &t = tables.at(i);
const quint32 size = (t.data.size() + 3) & ~3;
- if (t.tag == MAKE_TAG('h', 'e', 'a', 'd'))
+ if (t.tag == QFont::Tag("head").value())
head_offset = table_offset;
f << t.tag
<< checksum(t.data)
@@ -1186,7 +1186,7 @@ QByteArray QFontSubset::toTruetype() const
tables.append(generateMaxp(font.maxp));
// name
QTtfTable name_table;
- name_table.tag = MAKE_TAG('n', 'a', 'm', 'e');
+ name_table.tag = QFont::Tag("name").value();
if (!noEmbed)
name_table.data = fontEngine->getSfntTable(name_table.tag);
if (name_table.data.isEmpty()) {
@@ -1195,7 +1195,7 @@ QByteArray QFontSubset::toTruetype() const
name.copyright = "Fake font"_L1;
else
name.copyright = QLatin1StringView(properties.copyright);
- name.family = fontEngine->fontDef.families.first();
+ name.family = fontEngine->fontDef.families.constFirst();
name.subfamily = "Regular"_L1; // ######
name.postscript_name = QLatin1StringView(properties.postscriptName);
name_table = generateName(name);
@@ -1204,7 +1204,7 @@ QByteArray QFontSubset::toTruetype() const
if (!noEmbed) {
QTtfTable os2;
- os2.tag = MAKE_TAG('O', 'S', '/', '2');
+ os2.tag = QFont::Tag("OS/2").value();
os2.data = fontEngine->getSfntTable(os2.tag);
if (!os2.data.isEmpty())
tables.append(os2);
diff --git a/src/gui/text/qplatformfontdatabase.cpp b/src/gui/text/qplatformfontdatabase.cpp
index ce7713db03..a146254f68 100644
--- a/src/gui/text/qplatformfontdatabase.cpp
+++ b/src/gui/text/qplatformfontdatabase.cpp
@@ -646,6 +646,18 @@ bool QPlatformFontDatabase::isFamilyPopulated(const QString &familyName)
}
/*!
+ Returns true if this font database supports loading named instances from variable application
+ fonts.
+
+ \since 6.7
+*/
+bool QPlatformFontDatabase::supportsVariableApplicationFonts() const
+{
+ return false;
+}
+
+
+/*!
\class QPlatformFontDatabase
\since 5.0
\internal
diff --git a/src/gui/text/qplatformfontdatabase.h b/src/gui/text/qplatformfontdatabase.h
index a5e65086a8..3007a11838 100644
--- a/src/gui/text/qplatformfontdatabase.h
+++ b/src/gui/text/qplatformfontdatabase.h
@@ -89,6 +89,8 @@ public:
virtual bool fontsAlwaysScalable() const;
virtual QList<int> standardSizes() const;
+ virtual bool supportsVariableApplicationFonts() const;
+
// helper
static QSupportedWritingSystems writingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2]);
static QSupportedWritingSystems writingSystemsFromOS2Table(const char *os2Table, size_t length);
diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp
index 5b4f5d6b1b..54676b3560 100644
--- a/src/gui/text/qrawfont.cpp
+++ b/src/gui/text/qrawfont.cpp
@@ -440,7 +440,7 @@ qreal QRawFont::underlinePosition() const
*/
QString QRawFont::familyName() const
{
- return d->isValid() ? d->fontEngine->fontDef.families.first() : QString();
+ return d->isValid() ? d->fontEngine->fontDef.families.constFirst() : QString();
}
/*!
@@ -498,7 +498,7 @@ QList<quint32> QRawFont::glyphIndexesForString(const QString &text) const
QGlyphLayout glyphs;
glyphs.numGlyphs = numGlyphs;
glyphs.glyphs = glyphIndexes.data();
- if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly))
+ if (d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly) < 0)
Q_UNREACHABLE();
glyphIndexes.resize(numGlyphs);
@@ -531,7 +531,7 @@ bool QRawFont::glyphIndexesForChars(const QChar *chars, int numChars, quint32 *g
QGlyphLayout glyphs;
glyphs.numGlyphs = *numGlyphs;
glyphs.glyphs = glyphIndexes;
- return d->fontEngine->stringToCMap(chars, numChars, &glyphs, numGlyphs, QFontEngine::GlyphIndicesOnly);
+ return d->fontEngine->stringToCMap(chars, numChars, &glyphs, numGlyphs, QFontEngine::GlyphIndicesOnly) >= 0;
}
/*!
@@ -632,17 +632,33 @@ QFont::HintingPreference QRawFont::hintingPreference() const
}
/*!
- Retrieves the sfnt table named \a tagName from the underlying physical font, or an empty
- byte array if no such table was found. The returned font table's byte order is Big Endian, like
- the sfnt format specifies. The \a tagName must be four characters long and should be formatted
- in the default endianness of the current platform.
+ \fn QByteArray QRawFont::fontTable(const char *tag) const
+ \overload fontTable(QFont::Tag)
+
+ The name must be a four-character string.
+*/
+
+/*!
+ \fn QByteArray QRawFont::fontTable(QFont::Tag tag) const
+ \since 6.7
+
+ Retrieves the sfnt table specified by \a tag from the underlying physical font,
+ or an empty byte array if no such table was found. The returned font table's byte order is
+ Big Endian, like the sfnt format specifies.
*/
-QByteArray QRawFont::fontTable(const char *tagName) const
+QByteArray QRawFont::fontTable(const char *tag) const
+{
+ if (auto maybeTag = QFont::Tag::fromString(tag))
+ return fontTable(*maybeTag);
+ return QByteArray();
+}
+
+QByteArray QRawFont::fontTable(QFont::Tag tag) const
{
if (!d->isValid())
return QByteArray();
- return d->fontEngine->getSfntTable(MAKE_TAG(tagName[0], tagName[1], tagName[2], tagName[3]));
+ return d->fontEngine->getSfntTable(tag.value());
}
/*!
diff --git a/src/gui/text/qrawfont.h b/src/gui/text/qrawfont.h
index ca202d897f..d23d0c1493 100644
--- a/src/gui/text/qrawfont.h
+++ b/src/gui/text/qrawfont.h
@@ -105,6 +105,7 @@ public:
QList<QFontDatabase::WritingSystem> supportedWritingSystems() const;
QByteArray fontTable(const char *tagName) const;
+ QByteArray fontTable(QFont::Tag tag) const;
static QRawFont fromFont(const QFont &font,
QFontDatabase::WritingSystem writingSystem = QFontDatabase::Any);
diff --git a/src/gui/text/qtextcursor.cpp b/src/gui/text/qtextcursor.cpp
index c23bcf0317..5730f55e6a 100644
--- a/src/gui/text/qtextcursor.cpp
+++ b/src/gui/text/qtextcursor.cpp
@@ -1679,7 +1679,7 @@ static void getText(QString &text, QTextDocumentPrivate *priv, const QString &do
const int offsetInFragment = qMax(0, pos - fragIt.position());
const int len = qMin(int(frag->size_array[0] - offsetInFragment), end - pos);
- text += QString(docText.constData() + frag->stringPosition + offsetInFragment, len);
+ text += QStringView(docText.constData() + frag->stringPosition + offsetInFragment, len);
pos += len;
}
}
@@ -2300,7 +2300,7 @@ void QTextCursor::insertImage(const QTextImageFormat &format, QTextFrameFormat::
d->priv->beginEditBlock();
d->remove();
const int idx = d->priv->formatCollection()->indexForFormat(fmt);
- d->priv->insert(d->position, QString(QChar(QChar::ObjectReplacementCharacter)), idx);
+ d->priv->insert(d->position, QChar(QChar::ObjectReplacementCharacter), idx);
d->priv->endEditBlock();
}
diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp
index e5dc5136cb..15a313e13d 100644
--- a/src/gui/text/qtextdocument.cpp
+++ b/src/gui/text/qtextdocument.cpp
@@ -11,6 +11,7 @@
#include "qtexttable.h"
#include "qtextlist.h"
#include <qdebug.h>
+#include <qloggingcategory.h>
#if QT_CONFIG(regularexpression)
#include <qregularexpression.h>
#endif
@@ -42,6 +43,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcLayout);
+
using namespace Qt::StringLiterals;
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION unsigned int qt_int_sqrt(unsigned int n);
@@ -51,6 +54,8 @@ namespace {
};
/*!
+ \fn bool Qt::mightBeRichText(QAnyStringView text)
+
Returns \c true if the string \a text is likely to be rich text;
otherwise returns \c false.
@@ -60,18 +65,21 @@ namespace {
for common cases, there is no guarantee.
This function is defined in the \c <QTextDocument> header file.
-*/
-bool Qt::mightBeRichText(const QString& text)
+
+ \note In Qt versions prior to 6.7, this function took QString only.
+ */
+template <typename T>
+static bool mightBeRichTextImpl(T text)
{
if (text.isEmpty())
return false;
- int start = 0;
+ qsizetype start = 0;
- while (start < text.size() && text.at(start).isSpace())
+ while (start < text.size() && QChar(text.at(start)).isSpace())
++start;
// skip a leading <?xml ... ?> as for example with xhtml
- if (QStringView{text}.mid(start, 5).compare("<?xml"_L1) == 0) {
+ if (text.mid(start, 5).compare("<?xml"_L1) == 0) {
while (start < text.size()) {
if (text.at(start) == u'?'
&& start + 2 < text.size()
@@ -82,35 +90,36 @@ bool Qt::mightBeRichText(const QString& text)
++start;
}
- while (start < text.size() && text.at(start).isSpace())
+ while (start < text.size() && QChar(text.at(start)).isSpace())
++start;
}
- if (QStringView{text}.mid(start, 5).compare("<!doc"_L1, Qt::CaseInsensitive) == 0)
+ if (text.mid(start, 5).compare("<!doc"_L1, Qt::CaseInsensitive) == 0)
return true;
- int open = start;
+ qsizetype open = start;
while (open < text.size() && text.at(open) != u'<'
&& text.at(open) != u'\n') {
- if (text.at(open) == u'&' && QStringView{text}.mid(open + 1, 3) == "lt;"_L1)
+ if (text.at(open) == u'&' && text.mid(open + 1, 3) == "lt;"_L1)
return true; // support desperate attempt of user to see <...>
++open;
}
if (open < text.size() && text.at(open) == u'<') {
- const int close = text.indexOf(u'>', open);
+ const qsizetype close = text.indexOf(u'>', open);
if (close > -1) {
- QString tag;
- for (int i = open+1; i < close; ++i) {
- if (text[i].isDigit() || text[i].isLetter())
- tag += text[i];
- else if (!tag.isEmpty() && text[i].isSpace())
+ QVarLengthArray<char16_t> tag;
+ for (qsizetype i = open + 1; i < close; ++i) {
+ const auto current = QChar(text[i]);
+ if (current.isDigit() || current.isLetter())
+ tag.append(current.toLower().unicode());
+ else if (!tag.isEmpty() && current.isSpace())
break;
- else if (!tag.isEmpty() && text[i] == u'/' && i + 1 == close)
+ else if (!tag.isEmpty() && current == u'/' && i + 1 == close)
break;
- else if (!text[i].isSpace() && (!tag.isEmpty() || text[i] != u'!'))
+ else if (!current.isSpace() && (!tag.isEmpty() || current != u'!'))
return false; // that's not a tag
}
#ifndef QT_NO_TEXTHTMLPARSER
- return QTextHtmlParser::lookupElement(std::move(tag).toLower()) != -1;
+ return QTextHtmlParser::lookupElement(tag) != -1;
#else
return false;
#endif // QT_NO_TEXTHTMLPARSER
@@ -119,6 +128,16 @@ bool Qt::mightBeRichText(const QString& text)
return false;
}
+static bool mightBeRichTextImpl(QUtf8StringView text)
+{
+ return mightBeRichTextImpl(QLatin1StringView(QByteArrayView(text)));
+}
+
+bool Qt::mightBeRichText(QAnyStringView text)
+{
+ return text.visit([](auto text) { return mightBeRichTextImpl(text); });
+}
+
/*!
Converts the plain text string \a plain to an HTML-formatted
paragraph while preserving most of its look.
@@ -131,12 +150,12 @@ bool Qt::mightBeRichText(const QString& text)
*/
QString Qt::convertFromPlainText(const QString &plain, Qt::WhiteSpaceMode mode)
{
- int col = 0;
+ qsizetype col = 0;
QString rich;
rich += "<p>"_L1;
- for (int i = 0; i < plain.size(); ++i) {
+ for (qsizetype i = 0; i < plain.size(); ++i) {
if (plain[i] == u'\n'){
- int c = 1;
+ qsizetype c = 1;
while (i+1 < plain.size() && plain[i+1] == u'\n') {
i++;
c++;
@@ -235,7 +254,7 @@ QString Qt::convertFromPlainText(const QString &plain, Qt::WhiteSpaceMode mode)
\li Text block group format changes.
\endlist
- \sa QTextCursor, QTextEdit, {Rich Text Processing}, {Text Object Example}
+ \sa QTextCursor, QTextEdit, {Rich Text Processing}
*/
/*!
@@ -711,6 +730,8 @@ void QTextDocument::setTextWidth(qreal width)
{
Q_D(QTextDocument);
QSizeF sz = d->pageSize;
+
+ qCDebug(lcLayout) << "page size" << sz << "-> width" << width;
sz.setWidth(width);
sz.setHeight(-1);
setPageSize(sz);
@@ -1138,6 +1159,8 @@ QString QTextDocument::metaInformation(MetaInformation info) const
return d->url;
case CssMedia:
return d->cssMedia;
+ case FrontMatter:
+ return d->frontMatter;
}
return QString();
}
@@ -1161,6 +1184,9 @@ void QTextDocument::setMetaInformation(MetaInformation info, const QString &stri
case CssMedia:
d->cssMedia = string;
break;
+ case FrontMatter:
+ d->frontMatter = string;
+ break;
}
}
@@ -1200,10 +1226,18 @@ QString QTextDocument::toPlainText() const
Q_D(const QTextDocument);
QString txt = d->plainText();
+ constexpr char16_t delims[] = { 0xfdd0, 0xfdd1,
+ QChar::ParagraphSeparator, QChar::LineSeparator, QChar::Nbsp };
+
+ const size_t pos = std::u16string_view(txt).find_first_of(
+ std::u16string_view(delims, std::size(delims)));
+ if (pos == std::u16string_view::npos)
+ return txt;
+
QChar *uc = txt.data();
- QChar *e = uc + txt.size();
+ QChar *const e = uc + txt.size();
- for (; uc != e; ++uc) {
+ for (uc += pos; uc != e; ++uc) {
switch (uc->unicode()) {
case 0xfdd0: // QTextBeginningOfFrame
case 0xfdd1: // QTextEndOfFrame
@@ -1267,6 +1301,8 @@ void QTextDocument::setHtml(const QString &html)
d->enableUndoRedo(false);
d->beginEditBlock();
d->clear();
+ // ctor calls parse() to build up QTextHtmlParser::nodes list
+ // then import() populates the QTextDocument from those
QTextHtmlImporter(this, html, QTextHtmlImporter::ImportToDocument).import();
d->endEditBlock();
d->enableUndoRedo(previousState);
@@ -1298,6 +1334,10 @@ void QTextDocument::setHtml(const QString &html)
\value CssMedia This value is used to select the corresponding '@media'
rule, if any, from a specified CSS stylesheet when setHtml()
is called. This enum value has been introduced in Qt 6.3.
+ \value FrontMatter This value is used to select header material, if any was
+ extracted during parsing of the source file (currently
+ only from Markdown format). This enum value has been
+ introduced in Qt 6.8.
\sa metaInformation(), setMetaInformation(), setHtml()
*/
@@ -1471,6 +1511,10 @@ static bool findInBlock(const QTextBlock &block, const QRegularExpression &expr,
If the \a from position is 0 (the default) the search begins from the beginning
of the document; otherwise it begins at the specified position.
+
+ \warning For historical reasons, the case sensitivity option set on
+ \a expr is ignored. Instead, the \a options are used to determine
+ if the search is case sensitive or not.
*/
QTextCursor QTextDocument::find(const QRegularExpression &expr, int from, FindFlags options) const
{
@@ -2366,11 +2410,14 @@ QString QTextHtmlExporter::toHtml(ExportMode mode)
fragmentMarkers = (mode == ExportFragment);
- html += QString::fromLatin1("<meta charset=\"utf-8\" />");
+ html += "<meta charset=\"utf-8\" />"_L1;
QString title = doc->metaInformation(QTextDocument::DocumentTitle);
- if (!title.isEmpty())
- html += QString::fromLatin1("<title>") + title + QString::fromLatin1("</title>");
+ if (!title.isEmpty()) {
+ html += "<title>"_L1;
+ html += title;
+ html += "</title>"_L1;
+ }
html += "<style type=\"text/css\">\n"_L1;
html += "p, li { white-space: pre-wrap; }\n"_L1;
html += "hr { height: 1px; border-width: 0; }\n"_L1;
@@ -2518,7 +2565,9 @@ bool QTextHtmlExporter::emitCharFormatStyle(const QTextCharFormat &format)
html += u';';
attributesEmitted = true;
}
- } else if (format.hasProperty(QTextFormat::FontPixelSize)) {
+ } else if (format.hasProperty(QTextFormat::FontPixelSize)
+ && format.property(QTextFormat::FontPixelSize)
+ != defaultCharFormat.property(QTextFormat::FontPixelSize)) {
html += " font-size:"_L1;
html += QString::number(format.intProperty(QTextFormat::FontPixelSize));
html += "px;"_L1;
@@ -2597,6 +2646,53 @@ bool QTextHtmlExporter::emitCharFormatStyle(const QTextCharFormat &format)
html += " -qt-fg-texture-cachekey:"_L1;
html += QString::number(cacheKey);
html += ";"_L1;
+ } else if (brush.style() == Qt::LinearGradientPattern
+ || brush.style() == Qt::RadialGradientPattern
+ || brush.style() == Qt::ConicalGradientPattern) {
+ const QGradient *gradient = brush.gradient();
+ if (gradient->type() == QGradient::LinearGradient) {
+ const QLinearGradient *linearGradient = static_cast<const QLinearGradient *>(brush.gradient());
+
+ html += " -qt-foreground: qlineargradient("_L1;
+ html += "x1:"_L1 + QString::number(linearGradient->start().x()) + u',';
+ html += "y1:"_L1 + QString::number(linearGradient->start().y()) + u',';
+ html += "x2:"_L1 + QString::number(linearGradient->finalStop().x()) + u',';
+ html += "y2:"_L1 + QString::number(linearGradient->finalStop().y()) + u',';
+ } else if (gradient->type() == QGradient::RadialGradient) {
+ const QRadialGradient *radialGradient = static_cast<const QRadialGradient *>(brush.gradient());
+
+ html += " -qt-foreground: qradialgradient("_L1;
+ html += "cx:"_L1 + QString::number(radialGradient->center().x()) + u',';
+ html += "cy:"_L1 + QString::number(radialGradient->center().y()) + u',';
+ html += "fx:"_L1 + QString::number(radialGradient->focalPoint().x()) + u',';
+ html += "fy:"_L1 + QString::number(radialGradient->focalPoint().y()) + u',';
+ html += "radius:"_L1 + QString::number(radialGradient->radius()) + u',';
+ } else {
+ const QConicalGradient *conicalGradient = static_cast<const QConicalGradient *>(brush.gradient());
+
+ html += " -qt-foreground: qconicalgradient("_L1;
+ html += "cx:"_L1 + QString::number(conicalGradient->center().x()) + u',';
+ html += "cy:"_L1 + QString::number(conicalGradient->center().y()) + u',';
+ html += "angle:"_L1 + QString::number(conicalGradient->angle()) + u',';
+ }
+
+ const QStringList coordinateModes = { "logical"_L1, "stretchtodevice"_L1, "objectbounding"_L1, "object"_L1 };
+ html += "coordinatemode:"_L1;
+ html += coordinateModes.at(int(gradient->coordinateMode()));
+ html += u',';
+
+ const QStringList spreads = { "pad"_L1, "reflect"_L1, "repeat"_L1 };
+ html += "spread:"_L1;
+ html += spreads.at(int(gradient->spread()));
+
+ for (const QGradientStop &stop : gradient->stops()) {
+ html += ",stop:"_L1;
+ html += QString::number(stop.first);
+ html += u' ';
+ html += colorValue(stop.second);
+ }
+
+ html += ");"_L1;
} else {
html += " color:"_L1;
html += colorValue(brush.color());
@@ -2652,6 +2748,18 @@ bool QTextHtmlExporter::emitCharFormatStyle(const QTextCharFormat &format)
attributesEmitted = true;
}
+ if (format.hasProperty(QTextFormat::TextOutline)) {
+ QPen outlinePen = format.textOutline();
+ html += " -qt-stroke-color:"_L1;
+ html += colorValue(outlinePen.color());
+ html += u';';
+
+ html += " -qt-stroke-width:"_L1;
+ html += QString::number(outlinePen.widthF());
+ html += "px;"_L1;
+ attributesEmitted = true;
+ }
+
return attributesEmitted;
}
@@ -3015,7 +3123,8 @@ void QTextHtmlExporter::emitBlock(const QTextBlock &block)
html += u'"';
}
- QString styleString = QString::fromLatin1("margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px;");
+ QString styleString;
+ styleString += "margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px;"_L1;
if (format.hasProperty(QTextFormat::ListIndent)) {
styleString += " -qt-list-indent: "_L1;
@@ -3445,7 +3554,7 @@ void QTextHtmlExporter::emitFrameStyle(const QTextFrameFormat &format, FrameType
{
const auto styleAttribute = " style=\""_L1;
html += styleAttribute;
- const int originalHtmlLength = html.size();
+ const qsizetype originalHtmlLength = html.size();
if (frameType == TextFrame)
html += "-qt-table-type: frame;"_L1;
@@ -3554,7 +3663,7 @@ QString QTextDocument::toMarkdown(QTextDocument::MarkdownFeatures features) cons
#if QT_CONFIG(textmarkdownreader)
void QTextDocument::setMarkdown(const QString &markdown, QTextDocument::MarkdownFeatures features)
{
- QTextMarkdownImporter(features).import(this, markdown);
+ QTextMarkdownImporter(this, features).import(markdown);
}
#endif
diff --git a/src/gui/text/qtextdocument.h b/src/gui/text/qtextdocument.h
index 01ed9789ed..b6253bfa46 100644
--- a/src/gui/text/qtextdocument.h
+++ b/src/gui/text/qtextdocument.h
@@ -35,7 +35,10 @@ class QTextCursor;
namespace Qt
{
+#if QT_GUI_REMOVED_SINCE(6, 7)
Q_GUI_EXPORT bool mightBeRichText(const QString&);
+#endif
+ Q_GUI_EXPORT bool mightBeRichText(QAnyStringView);
Q_GUI_EXPORT QString convertFromPlainText(const QString &plain, WhiteSpaceMode mode = WhiteSpacePre);
}
@@ -102,7 +105,8 @@ public:
enum MetaInformation {
DocumentTitle,
DocumentUrl,
- CssMedia
+ CssMedia,
+ FrontMatter,
};
void setMetaInformation(MetaInformation info, const QString &);
QString metaInformation(MetaInformation info) const;
@@ -116,7 +120,7 @@ public:
enum MarkdownFeature {
MarkdownNoHTML = 0x0020 | 0x0040,
MarkdownDialectCommonMark = 0,
- MarkdownDialectGitHub = 0x0004 | 0x0008 | 0x0400 | 0x0100 | 0x0200 | 0x0800 | 0x4000
+ MarkdownDialectGitHub = 0x0004 | 0x0008 | 0x0400 | 0x0100 | 0x0200 | 0x0800 | 0x4000 | 0x100000
};
Q_DECLARE_FLAGS(MarkdownFeatures, MarkdownFeature)
Q_FLAG(MarkdownFeatures)
diff --git a/src/gui/text/qtextdocument_p.cpp b/src/gui/text/qtextdocument_p.cpp
index 9e630f3787..3c1fc04d4b 100644
--- a/src/gui/text/qtextdocument_p.cpp
+++ b/src/gui/text/qtextdocument_p.cpp
@@ -349,8 +349,10 @@ int QTextDocumentPrivate::insert_block(int pos, uint strPos, int format, int blo
QTextBlockGroup *group = qobject_cast<QTextBlockGroup *>(objectForFormat(blockFormat));
if (group) {
group->blockInserted(QTextBlock(this, b));
- docChangeOldLength--;
- docChangeLength--;
+ if (command != QTextUndoCommand::BlockDeleted) {
+ docChangeOldLength--;
+ docChangeLength--;
+ }
}
QTextFrame *frame = qobject_cast<QTextFrame *>(objectForFormat(formats.format(format)));
@@ -443,7 +445,7 @@ void QTextDocumentPrivate::insert(int pos, int strPos, int strLength, int format
finishEdit();
}
-void QTextDocumentPrivate::insert(int pos, const QString &str, int format)
+void QTextDocumentPrivate::insert(int pos, QStringView str, int format)
{
if (str.size() == 0)
return;
diff --git a/src/gui/text/qtextdocument_p.h b/src/gui/text/qtextdocument_p.h
index 84a79691e9..1c4edc4329 100644
--- a/src/gui/text/qtextdocument_p.h
+++ b/src/gui/text/qtextdocument_p.h
@@ -142,7 +142,9 @@ public:
void setLayout(QAbstractTextDocumentLayout *layout);
- void insert(int pos, const QString &text, int format);
+ void insert(int pos, QStringView text, int format);
+ void insert(int pos, QChar c, int format)
+ { insert(pos, QStringView(&c, 1), format); }
void insert(int pos, int strPos, int strLength, int format);
int insertBlock(int pos, int blockFormat, int charFormat, QTextUndoCommand::Operation = QTextUndoCommand::MoveCursor);
int insertBlock(QChar blockSeparator, int pos, int blockFormat, int charFormat,
@@ -354,6 +356,7 @@ public:
QString title;
QString url;
QString cssMedia;
+ QString frontMatter;
qreal indentWidth;
qreal documentMargin;
QUrl baseUrl;
diff --git a/src/gui/text/qtextdocumentfragment.cpp b/src/gui/text/qtextdocumentfragment.cpp
index 9e99992929..1b6e76c201 100644
--- a/src/gui/text/qtextdocumentfragment.cpp
+++ b/src/gui/text/qtextdocumentfragment.cpp
@@ -488,7 +488,8 @@ void QTextHtmlImporter::import()
* means there was a tag closing in the input html
*/
if (currentNodeIdx > 0 && (currentNode->parent != currentNodeIdx - 1)) {
- blockTagClosed = closeTag();
+ const bool lastBlockTagClosed = closeTag();
+ blockTagClosed = blockTagClosed || lastBlockTagClosed;
// visually collapse subsequent block tags, but if the element after the closed block tag
// is for example an inline element (!isBlock) we have to make sure we start a new paragraph by setting
// hasBlock to false.
@@ -540,6 +541,7 @@ void QTextHtmlImporter::import()
appendBlock(block, currentNode->charFormat);
+ blockTagClosed = false;
hasBlock = true;
}
@@ -575,14 +577,12 @@ bool QTextHtmlImporter::appendNodeText()
if (wsm == QTextHtmlParserNode::WhiteSpacePre || wsm == QTextHtmlParserNode::WhiteSpacePreWrap)
compressNextWhitespace = PreserveWhiteSpace;
- QString text = currentNode->text;
+ const QString text = currentNode->text;
QString textToInsert;
textToInsert.reserve(text.size());
- for (int i = 0; i < text.size(); ++i) {
- QChar ch = text.at(i);
-
+ for (QChar ch : text) {
if (ch.isSpace()
&& ch != QChar::Nbsp
&& ch != QChar::ParagraphSeparator) {
@@ -1313,8 +1313,7 @@ QTextDocumentFragment QTextDocumentFragment::fromMarkdown(const QString &markdow
QTextDocumentFragment res;
res.d = new QTextDocumentFragmentPrivate;
- QTextMarkdownImporter importer(features);
- importer.import(res.d->doc, markdown);
+ QTextMarkdownImporter(res.d->doc, features).import(markdown);
return res;
}
diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp
index 56ce6861f1..452f814231 100644
--- a/src/gui/text/qtextdocumentlayout.cpp
+++ b/src/gui/text/qtextdocumentlayout.cpp
@@ -25,6 +25,7 @@
#include <qbasictimer.h>
#include "private/qfunctions_p.h"
#include <qloggingcategory.h>
+#include <QtCore/qpointer.h>
#include <algorithm>
@@ -1817,11 +1818,20 @@ void QTextDocumentLayoutPrivate::drawTableCell(const QRectF &cellRect, QPainter
if (r >= headerRowCount)
topMargin += td->headerHeight.toReal();
- if (!td->borderCollapse && td->border != 0) {
+ // If cell border configured, don't draw default border for cells. It will be taken care later by
+ // drawTableCellBorder().
+ bool cellBorderConfigured = (cell.format().hasProperty(QTextFormat::TableCellLeftBorder) ||
+ cell.format().hasProperty(QTextFormat::TableCellTopBorder) ||
+ cell.format().hasProperty(QTextFormat::TableCellRightBorder) ||
+ cell.format().hasProperty(QTextFormat::TableCellBottomBorder));
+
+ if (!td->borderCollapse && td->border != 0 && !cellBorderConfigured) {
const QBrush oldBrush = painter->brush();
const QPen oldPen = painter->pen();
- const qreal border = td->border.toReal();
+ // If border is configured for the table (and not explicitly for the cell), then
+ // always draw 1px border around the cell
+ const qreal border = 1;
QRectF borderRect(cellRect.left() - border, cellRect.top() - border, cellRect.width() + border, cellRect.height() + border);
@@ -1884,7 +1894,8 @@ void QTextDocumentLayoutPrivate::drawTableCell(const QRectF &cellRect, QPainter
}
// paint over the background - otherwise we would have to adjust the background paint cellRect for the border values
- drawTableCellBorder(cellRect, painter, table, td, cell);
+ if (cellBorderConfigured)
+ drawTableCellBorder(cellRect, painter, table, td, cell);
const QFixed verticalOffset = td->cellVerticalOffsets.at(c + r * table->columns());
@@ -2070,7 +2081,7 @@ void QTextDocumentLayoutPrivate::drawBlock(const QPointF &offset, QPainter *pain
const qreal width = blockFormat.lengthProperty(QTextFormat::BlockTrailingHorizontalRulerWidth).value(r.width());
const auto color = blockFormat.hasProperty(QTextFormat::BackgroundBrush)
? qvariant_cast<QBrush>(blockFormat.property(QTextFormat::BackgroundBrush)).color()
- : context.palette.color(QPalette::Dark);
+ : context.palette.color(QPalette::Inactive, QPalette::WindowText);
painter->setPen(color);
qreal y = r.bottom();
if (bl.length() == 1)
@@ -2205,17 +2216,15 @@ void QTextDocumentLayoutPrivate::drawListItem(const QPointF &offset, QPainter *p
}
case QTextListFormat::ListSquare:
if (!marker)
- painter->fillRect(r, brush);
+ painter->fillRect(r, painter->pen().brush());
break;
case QTextListFormat::ListCircle:
- if (!marker) {
- painter->setPen(QPen(brush, 0));
+ if (!marker)
painter->drawEllipse(r.translated(0.5, 0.5)); // pixel align for sharper rendering
- }
break;
case QTextListFormat::ListDisc:
if (!marker) {
- painter->setBrush(brush);
+ painter->setBrush(painter->pen().brush());
painter->setPen(Qt::NoPen);
painter->drawEllipse(r);
}
@@ -3111,7 +3120,7 @@ void QTextDocumentLayoutPrivate::layoutFlow(QTextFrame::Iterator it, QTextLayout
QTextBlockFormat previousBlockFormat = previousIt.currentBlock().blockFormat();
QFixed maximumBlockWidth = 0;
- while (!it.atEnd()) {
+ while (!it.atEnd() && layoutStruct->absoluteY() < QFIXED_MAX) {
QTextFrame *c = it.currentFrame();
int docPos;
@@ -3361,7 +3370,7 @@ void QTextDocumentLayoutPrivate::layoutFlow(QTextFrame::Iterator it, QTextLayout
if (!fd->floats.isEmpty())
contentHasAlignment = true;
- if (it.atEnd()) {
+ if (it.atEnd() || layoutStruct->absoluteY() >= QFIXED_MAX) {
//qDebug("layout done!");
currentLazyLayoutPosition = -1;
QCheckPoint cp;
@@ -3547,6 +3556,11 @@ void QTextDocumentLayoutPrivate::layoutBlock(const QTextBlock &bl, int blockPosi
while (layoutStruct->pageHeight > 0 && layoutStruct->absoluteY() + lineBreakHeight > layoutStruct->pageBottom &&
layoutStruct->contentHeight() >= lineBreakHeight) {
+ if (layoutStruct->pageHeight == QFIXED_MAX) {
+ layoutStruct->y = QFIXED_MAX - layoutStruct->frameY;
+ break;
+ }
+
layoutStruct->newPage();
floatMargins(layoutStruct->y, layoutStruct, &left, &right);
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index eded3e3f33..a18157ab9b 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -36,15 +36,10 @@ public:
Itemizer(const QString &string, const QScriptAnalysis *analysis, QScriptItemArray &items)
: m_string(string),
m_analysis(analysis),
- m_items(items),
- m_splitter(nullptr)
+ m_items(items)
{
}
- ~Itemizer()
- {
- delete m_splitter;
- }
-
+ ~Itemizer() = default;
/// generate the script items
/// The caps parameter is used to choose the algorithm of splitting text and assigning roles to the textitems
void generate(int start, int length, QFont::Capitalization caps)
@@ -101,7 +96,7 @@ private:
return;
if (!m_splitter)
- m_splitter = new QTextBoundaryFinder(QTextBoundaryFinder::Word,
+ m_splitter = std::make_unique<QTextBoundaryFinder>(QTextBoundaryFinder::Word,
m_string.constData(), m_string.size(),
/*buffer*/nullptr, /*buffer size*/0);
@@ -171,7 +166,7 @@ private:
const QString &m_string;
const QScriptAnalysis * const m_analysis;
QScriptItemArray &m_items;
- QTextBoundaryFinder *m_splitter;
+ std::unique_ptr<QTextBoundaryFinder> m_splitter;
};
// -----------------------------------------------------------------------------------------------------
@@ -1404,6 +1399,7 @@ void QTextEngine::shapeText(int item) const
bool kerningEnabled;
bool letterSpacingIsAbsolute;
bool shapingEnabled = false;
+ QHash<QFont::Tag, quint32> features;
QFixed letterSpacing, wordSpacing;
#ifndef QT_NO_RAWFONT
if (useRawFont) {
@@ -1417,6 +1413,7 @@ void QTextEngine::shapeText(int item) const
wordSpacing = QFixed::fromReal(font.wordSpacing());
letterSpacing = QFixed::fromReal(font.letterSpacing());
letterSpacingIsAbsolute = true;
+ features = font.d->features;
} else
#endif
{
@@ -1429,6 +1426,7 @@ void QTextEngine::shapeText(int item) const
letterSpacingIsAbsolute = font.d->letterSpacingIsAbsolute;
letterSpacing = font.d->letterSpacing;
wordSpacing = font.d->wordSpacing;
+ features = font.d->features;
if (letterSpacingIsAbsolute && letterSpacing.value())
letterSpacing *= font.d->dpi / qt_defaultDpiY();
@@ -1436,8 +1434,7 @@ void QTextEngine::shapeText(int item) const
// split up the item into parts that come from different font engines
// k * 3 entries, array[k] == index in string, array[k + 1] == index in glyphs, array[k + 2] == engine index
- QList<uint> itemBoundaries;
- itemBoundaries.reserve(24);
+ QVarLengthArray<uint, 24> itemBoundaries;
QGlyphLayout initialGlyphs = availableGlyphs(&si);
int nGlyphs = initialGlyphs.numGlyphs;
@@ -1448,7 +1445,7 @@ void QTextEngine::shapeText(int item) const
shapingEnabled
? QFontEngine::GlyphIndicesOnly
: QFontEngine::ShaperFlag(0);
- if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags))
+ if (fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags) < 0)
Q_UNREACHABLE();
}
@@ -1457,9 +1454,9 @@ void QTextEngine::shapeText(int item) const
for (int i = 0, glyph_pos = 0; i < itemLength; ++i, ++glyph_pos) {
const uint engineIdx = initialGlyphs.glyphs[glyph_pos] >> 24;
if (lastEngine != engineIdx) {
- itemBoundaries.append(i);
- itemBoundaries.append(glyph_pos);
- itemBoundaries.append(engineIdx);
+ itemBoundaries.push_back(i);
+ itemBoundaries.push_back(glyph_pos);
+ itemBoundaries.push_back(engineIdx);
if (engineIdx != 0) {
QFontEngine *actualFontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx);
@@ -1475,14 +1472,21 @@ void QTextEngine::shapeText(int item) const
++i;
}
} else {
- itemBoundaries.append(0);
- itemBoundaries.append(0);
- itemBoundaries.append(0);
+ itemBoundaries.push_back(0);
+ itemBoundaries.push_back(0);
+ itemBoundaries.push_back(0);
}
#if QT_CONFIG(harfbuzz)
if (Q_LIKELY(shapingEnabled)) {
- si.num_glyphs = shapeTextWithHarfbuzzNG(si, string, itemLength, fontEngine, itemBoundaries, kerningEnabled, letterSpacing != 0);
+ si.num_glyphs = shapeTextWithHarfbuzzNG(si,
+ string,
+ itemLength,
+ fontEngine,
+ itemBoundaries,
+ kerningEnabled,
+ letterSpacing != 0,
+ features);
} else
#endif
{
@@ -1592,9 +1596,10 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si,
const ushort *string,
int itemLength,
QFontEngine *fontEngine,
- const QList<uint> &itemBoundaries,
+ QSpan<uint> itemBoundaries,
bool kerningEnabled,
- bool hasLetterSpacing) const
+ bool hasLetterSpacing,
+ const QHash<QFont::Tag, quint32> &fontFeatures) const
{
uint glyphs_shaped = 0;
@@ -1613,7 +1618,7 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si,
// ### TODO get_default_for_script?
props.language = hb_language_get_default(); // use default language from locale
- for (int k = 0; k < itemBoundaries.size(); k += 3) {
+ for (qsizetype k = 0; k < itemBoundaries.size(); k += 3) {
const uint item_pos = itemBoundaries[k];
const uint item_length = (k + 4 < itemBoundaries.size() ? itemBoundaries[k + 3] : itemLength) - item_pos;
const uint engineIdx = itemBoundaries[k + 2];
@@ -1648,14 +1653,24 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si,
|| script == QChar::Script_Khmer || script == QChar::Script_Nko);
bool dontLigate = hasLetterSpacing && !scriptRequiresOpenType;
- const hb_feature_t features[5] = {
- { HB_TAG('k','e','r','n'), !!kerningEnabled, HB_FEATURE_GLOBAL_START, HB_FEATURE_GLOBAL_END },
- { HB_TAG('l','i','g','a'), false, HB_FEATURE_GLOBAL_START, HB_FEATURE_GLOBAL_END },
- { HB_TAG('c','l','i','g'), false, HB_FEATURE_GLOBAL_START, HB_FEATURE_GLOBAL_END },
- { HB_TAG('d','l','i','g'), false, HB_FEATURE_GLOBAL_START, HB_FEATURE_GLOBAL_END },
- { HB_TAG('h','l','i','g'), false, HB_FEATURE_GLOBAL_START, HB_FEATURE_GLOBAL_END }
- };
- const int num_features = dontLigate ? 5 : 1;
+
+ QHash<QFont::Tag, quint32> features;
+ features.insert(QFont::Tag("kern"), !!kerningEnabled);
+ if (dontLigate) {
+ features.insert(QFont::Tag("liga"), false);
+ features.insert(QFont::Tag("clig"), false);
+ features.insert(QFont::Tag("dlig"), false);
+ features.insert(QFont::Tag("hlig"), false);
+ }
+ features.insert(fontFeatures);
+
+ QVarLengthArray<hb_feature_t, 16> featureArray;
+ for (auto it = features.constBegin(); it != features.constEnd(); ++it) {
+ featureArray.append({ it.key().value(),
+ it.value(),
+ HB_FEATURE_GLOBAL_START,
+ HB_FEATURE_GLOBAL_END });
+ }
// whitelist cross-platforms shapers only
static const char *shaper_list[] = {
@@ -1665,7 +1680,11 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si,
nullptr
};
- bool shapedOk = hb_shape_full(hb_font, buffer, features, num_features, shaper_list);
+ bool shapedOk = hb_shape_full(hb_font,
+ buffer,
+ featureArray.constData(),
+ features.size(),
+ shaper_list);
if (Q_UNLIKELY(!shapedOk)) {
hb_buffer_destroy(buffer);
return 0;
@@ -2634,14 +2653,15 @@ QTextEngine::LayoutData::LayoutData()
currentMaxWidth = 0;
}
-QTextEngine::LayoutData::LayoutData(const QString &str, void **stack_memory, int _allocated)
+QTextEngine::LayoutData::LayoutData(const QString &str, void **stack_memory, qsizetype _allocated)
: string(str)
{
allocated = _allocated;
- int space_charAttributes = int(sizeof(QCharAttributes) * string.size() / sizeof(void*) + 1);
- int space_logClusters = int(sizeof(unsigned short) * string.size() / sizeof(void*) + 1);
- available_glyphs = ((int)allocated - space_charAttributes - space_logClusters)*(int)sizeof(void*)/(int)QGlyphLayout::SpaceNeeded;
+ constexpr qsizetype voidSize = sizeof(void*);
+ qsizetype space_charAttributes = sizeof(QCharAttributes) * string.size() / voidSize + 1;
+ qsizetype space_logClusters = sizeof(unsigned short) * string.size() / voidSize + 1;
+ available_glyphs = (allocated - space_charAttributes - space_logClusters) * voidSize / QGlyphLayout::SpaceNeeded;
if (available_glyphs < str.size()) {
// need to allocate on the heap
@@ -2682,15 +2702,16 @@ bool QTextEngine::LayoutData::reallocate(int totalGlyphs)
return true;
}
- int space_charAttributes = int(sizeof(QCharAttributes) * string.size() / sizeof(void*) + 1);
- int space_logClusters = int(sizeof(unsigned short) * string.size() / sizeof(void*) + 1);
- int space_glyphs = (totalGlyphs * QGlyphLayout::SpaceNeeded) / sizeof(void *) + 2;
+ const qsizetype space_charAttributes = (sizeof(QCharAttributes) * string.size() / sizeof(void*) + 1);
+ const qsizetype space_logClusters = (sizeof(unsigned short) * string.size() / sizeof(void*) + 1);
+ const qsizetype space_glyphs = qsizetype(totalGlyphs) * QGlyphLayout::SpaceNeeded / sizeof(void *) + 2;
- int newAllocated = space_charAttributes + space_glyphs + space_logClusters;
- // These values can be negative if the length of string/glyphs causes overflow,
+ const qsizetype newAllocated = space_charAttributes + space_glyphs + space_logClusters;
+ // Check if the length of string/glyphs causes int overflow,
// we can't layout such a long string all at once, so return false here to
// indicate there is a failure
- if (space_charAttributes < 0 || space_logClusters < 0 || space_glyphs < 0 || newAllocated < allocated) {
+ if (size_t(space_charAttributes) > INT_MAX || size_t(space_logClusters) > INT_MAX || totalGlyphs < 0
+ || size_t(space_glyphs) > INT_MAX || size_t(newAllocated) > INT_MAX || newAllocated < allocated) {
layoutState = LayoutFailed;
return false;
}
@@ -2710,7 +2731,7 @@ bool QTextEngine::LayoutData::reallocate(int totalGlyphs)
logClustersPtr = (unsigned short *) m;
m += space_logClusters;
- const int space_preGlyphLayout = space_charAttributes + space_logClusters;
+ const qsizetype space_preGlyphLayout = space_charAttributes + space_logClusters;
if (allocated < space_preGlyphLayout)
memset(memory + allocated, 0, (space_preGlyphLayout - allocated)*sizeof(void *));
@@ -2720,6 +2741,21 @@ bool QTextEngine::LayoutData::reallocate(int totalGlyphs)
return true;
}
+void QGlyphLayout::copy(QGlyphLayout *oldLayout)
+{
+ Q_ASSERT(offsets != oldLayout->offsets);
+
+ int n = std::min(numGlyphs, oldLayout->numGlyphs);
+
+ memcpy(offsets, oldLayout->offsets, n * sizeof(QFixedPoint));
+ memcpy(attributes, oldLayout->attributes, n * sizeof(QGlyphAttributes));
+ memcpy(justifications, oldLayout->justifications, n * sizeof(QGlyphJustification));
+ memcpy(advances, oldLayout->advances, n * sizeof(QFixed));
+ memcpy(glyphs, oldLayout->glyphs, n * sizeof(glyph_t));
+
+ numGlyphs = n;
+}
+
// grow to the new size, copying the existing data to the new layout
void QGlyphLayout::grow(char *address, int totalGlyphs)
{
@@ -2930,11 +2966,11 @@ static inline bool prevCharJoins(const QString &string, int pos)
return joining == QChar::Joining_Dual || joining == QChar::Joining_Causing;
}
-static inline bool isRetainableControlCode(QChar c)
+static constexpr bool isRetainableControlCode(char16_t c) noexcept
{
- return (c.unicode() >= 0x202a && c.unicode() <= 0x202e) // LRE, RLE, PDF, LRO, RLO
- || (c.unicode() >= 0x200e && c.unicode() <= 0x200f) // LRM, RLM
- || (c.unicode() >= 0x2066 && c.unicode() <= 0x2069); // LRI, RLI, FSI, PDI
+ return (c >= 0x202a && c <= 0x202e) // LRE, RLE, PDF, LRO, RLO
+ || (c >= 0x200e && c <= 0x200f) // LRM, RLM
+ || (c >= 0x2066 && c <= 0x2069); // LRI, RLI, FSI, PDI
}
static QString stringMidRetainingBidiCC(const QString &string,
@@ -2947,14 +2983,14 @@ static QString stringMidRetainingBidiCC(const QString &string,
{
QString prefix;
for (int i=subStringFrom; i<midStart; ++i) {
- QChar c = string.at(i);
+ char16_t c = string.at(i).unicode();
if (isRetainableControlCode(c))
prefix += c;
}
QString suffix;
for (int i=midStart + midLength; i<subStringTo; ++i) {
- QChar c = string.at(i);
+ char16_t c = string.at(i).unicode();
if (isRetainableControlCode(c))
suffix += c;
}
@@ -3011,7 +3047,7 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, QFixed width, int flags,
{
QFontEngine *engine = fnt.d->engineForScript(QChar::Script_Common);
- QChar ellipsisChar = u'\x2026';
+ constexpr char16_t ellipsisChar = u'\x2026';
// We only want to use the ellipsis character if it is from the main
// font (not one of the fallbacks), since using a fallback font
@@ -3023,7 +3059,7 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, QFixed width, int flags,
engine = multiEngine->engine(0);
}
- glyph_t glyph = engine->glyphIndex(ellipsisChar.unicode());
+ glyph_t glyph = engine->glyphIndex(ellipsisChar);
QGlyphLayout glyphs;
glyphs.numGlyphs = 1;
@@ -3043,7 +3079,7 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, QFixed width, int flags,
ellipsisText = QStringLiteral("...");
} else {
engine = fnt.d->engineForScript(QChar::Script_Common);
- glyph = engine->glyphIndex(ellipsisChar.unicode());
+ glyph = engine->glyphIndex(ellipsisChar);
engine->recalcAdvances(&glyphs, { });
ellipsisText = ellipsisChar;
}
@@ -3160,7 +3196,7 @@ void QTextEngine::setBoundary(int strPos) const
QFixed QTextEngine::calculateTabWidth(int item, QFixed x) const
{
- const QScriptItem &si = layoutData->items[item];
+ const QScriptItem &si = layoutData->items.at(item);
QFixed dpiScale = 1;
if (QTextDocumentPrivate::get(block) != nullptr && QTextDocumentPrivate::get(block)->layout() != nullptr) {
@@ -3202,7 +3238,7 @@ QFixed QTextEngine::calculateTabWidth(int item, QFixed x) const
// find next tab to calculate the width required.
tab = QFixed::fromReal(tabSpec.position);
for (int i=item + 1; i < layoutData->items.size(); i++) {
- const QScriptItem &item = layoutData->items[i];
+ const QScriptItem &item = layoutData->items.at(i);
if (item.analysis.flags == QScriptAnalysis::TabOrObject) { // found it.
tabSectionEnd = item.position;
break;
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index 59e332c64a..c01d3a0711 100644
--- a/src/gui/text/qtextengine_p.h
+++ b/src/gui/text/qtextengine_p.h
@@ -26,6 +26,7 @@
#include "QtCore/qlist.h"
#include "QtCore/qnamespace.h"
#include "QtCore/qset.h"
+#include <QtCore/qspan.h>
#include "QtCore/qstring.h"
#include "QtCore/qvarlengtharray.h"
@@ -158,10 +159,8 @@ Q_DECLARE_TYPEINFO(QGlyphAttributes, Q_PRIMITIVE_TYPE);
struct QGlyphLayout
{
- enum {
- SpaceNeeded = sizeof(glyph_t) + sizeof(QFixed) + sizeof(QFixedPoint)
- + sizeof(QGlyphAttributes) + sizeof(QGlyphJustification)
- };
+ static constexpr qsizetype SpaceNeeded = sizeof(glyph_t) + sizeof(QFixed) + sizeof(QFixedPoint)
+ + sizeof(QGlyphAttributes) + sizeof(QGlyphJustification);
// init to 0 not needed, done when shaping
QFixedPoint *offsets; // 8 bytes per element
@@ -177,7 +176,7 @@ struct QGlyphLayout
inline explicit QGlyphLayout(char *address, int totalGlyphs)
{
offsets = reinterpret_cast<QFixedPoint *>(address);
- int offset = totalGlyphs * sizeof(QFixedPoint);
+ qsizetype offset = totalGlyphs * sizeof(QFixedPoint);
glyphs = reinterpret_cast<glyph_t *>(address + offset);
offset += totalGlyphs * sizeof(glyph_t);
advances = reinterpret_cast<QFixed *>(address + offset);
@@ -210,7 +209,7 @@ struct QGlyphLayout
last = numGlyphs;
if (first == 0 && last == numGlyphs
&& reinterpret_cast<char *>(offsets + numGlyphs) == reinterpret_cast<char *>(glyphs)) {
- memset(static_cast<void *>(offsets), 0, (numGlyphs * SpaceNeeded));
+ memset(static_cast<void *>(offsets), 0, qsizetype(numGlyphs) * SpaceNeeded);
} else {
const int num = last - first;
memset(static_cast<void *>(offsets + first), 0, num * sizeof(QFixedPoint));
@@ -225,6 +224,7 @@ struct QGlyphLayout
return reinterpret_cast<char *>(offsets);
}
+ void copy(QGlyphLayout *other);
void grow(char *address, int totalGlyphs);
};
@@ -371,12 +371,12 @@ public:
LayoutFailed
};
struct Q_GUI_EXPORT LayoutData {
- LayoutData(const QString &str, void **stack_memory, int mem_size);
+ LayoutData(const QString &str, void **stack_memory, qsizetype mem_size);
LayoutData();
~LayoutData();
mutable QScriptItemArray items;
- int allocated;
- int available_glyphs;
+ qsizetype allocated;
+ qsizetype available_glyphs;
void **memory;
unsigned short *logClustersPtr;
QGlyphLayout glyphLayout;
@@ -621,9 +621,14 @@ private:
void addRequiredBoundaries() const;
void shapeText(int item) const;
#if QT_CONFIG(harfbuzz)
- int shapeTextWithHarfbuzzNG(const QScriptItem &si, const ushort *string, int itemLength,
- QFontEngine *fontEngine, const QList<uint> &itemBoundaries,
- bool kerningEnabled, bool hasLetterSpacing) const;
+ int shapeTextWithHarfbuzzNG(const QScriptItem &si,
+ const ushort *string,
+ int itemLength,
+ QFontEngine *fontEngine,
+ QSpan<uint> itemBoundaries,
+ bool kerningEnabled,
+ bool hasLetterSpacing,
+ const QHash<QFont::Tag, quint32> &features) const;
#endif
int endOfLine(int lineNum);
diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp
index 8be3a0d442..daa79a55d2 100644
--- a/src/gui/text/qtextformat.cpp
+++ b/src/gui/text/qtextformat.cpp
@@ -405,27 +405,27 @@ Q_GUI_EXPORT QDataStream &operator<<(QDataStream &stream, const QTextFormat &fmt
{
QMap<int, QVariant> properties = fmt.properties();
if (stream.version() < QDataStream::Qt_6_0) {
- auto it = properties.find(QTextFormat::FontLetterSpacingType);
- if (it != properties.end()) {
+ auto it = properties.constFind(QTextFormat::FontLetterSpacingType);
+ if (it != properties.cend()) {
properties[QTextFormat::OldFontLetterSpacingType] = it.value();
properties.erase(it);
}
- it = properties.find(QTextFormat::FontStretch);
- if (it != properties.end()) {
+ it = properties.constFind(QTextFormat::FontStretch);
+ if (it != properties.cend()) {
properties[QTextFormat::OldFontStretch] = it.value();
properties.erase(it);
}
- it = properties.find(QTextFormat::TextUnderlineColor);
- if (it != properties.end()) {
+ it = properties.constFind(QTextFormat::TextUnderlineColor);
+ if (it != properties.cend()) {
properties[QTextFormat::OldTextUnderlineColor] = it.value();
properties.erase(it);
}
- it = properties.find(QTextFormat::FontFamilies);
- if (it != properties.end()) {
- properties[QTextFormat::OldFontFamily] = QVariant(it.value().toStringList().first());
+ it = properties.constFind(QTextFormat::FontFamilies);
+ if (it != properties.cend()) {
+ properties[QTextFormat::OldFontFamily] = QVariant(it.value().toStringList().constFirst());
properties.erase(it);
}
}
@@ -684,6 +684,8 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextTableCellFormat &
numeric lists.
\value ListNumberSuffix Defines the text which is appended to item numbers in
numeric lists.
+ \value [since 6.6] ListStart
+ Defines the first value of a list.
Table and frame properties
@@ -953,7 +955,11 @@ void QTextFormat::merge(const QTextFormat &other)
p->props.reserve(p->props.size() + otherProps.size());
for (int i = 0; i < otherProps.size(); ++i) {
const QT_PREPEND_NAMESPACE(Property) &prop = otherProps.at(i);
- p->insertProperty(prop.key, prop.value);
+ if (prop.value.isValid()) {
+ p->insertProperty(prop.key, prop.value);
+ } else {
+ p->clearProperty(prop.key);
+ }
}
}
@@ -1210,10 +1216,8 @@ void QTextFormat::setProperty(int propertyId, const QVariant &value)
{
if (!d)
d = new QTextFormatPrivate;
- if (!value.isValid())
- clearProperty(propertyId);
- else
- d->insertProperty(propertyId, value);
+
+ d->insertProperty(propertyId, value);
}
/*!
@@ -2167,7 +2171,7 @@ QFont QTextCharFormat::font() const
associated QTextBlockFormat that specifies its characteristics.
To cater for left-to-right and right-to-left languages you can set
- a block's direction with setDirection(). Paragraph alignment is
+ a block's direction with setLayoutDirection(). Paragraph alignment is
set with setAlignment(). Margins are controlled by setTopMargin(),
setBottomMargin(), setLeftMargin(), setRightMargin(). Overall
indentation is set with setIndent(), the indentation of the first
@@ -2238,13 +2242,8 @@ void QTextBlockFormat::setTabPositions(const QList<QTextOption::Tab> &tabs)
{
QList<QVariant> list;
list.reserve(tabs.size());
- QList<QTextOption::Tab>::ConstIterator iter = tabs.constBegin();
- while (iter != tabs.constEnd()) {
- QVariant v;
- v.setValue(*iter);
- list.append(v);
- ++iter;
- }
+ for (const auto &e : tabs)
+ list.append(QVariant::fromValue(e));
setProperty(TabPositions, list);
}
@@ -2260,13 +2259,10 @@ QList<QTextOption::Tab> QTextBlockFormat::tabPositions() const
if (variant.isNull())
return QList<QTextOption::Tab>();
QList<QTextOption::Tab> answer;
- QList<QVariant> variantsList = qvariant_cast<QList<QVariant> >(variant);
- QList<QVariant>::Iterator iter = variantsList.begin();
+ const QList<QVariant> variantsList = qvariant_cast<QList<QVariant> >(variant);
answer.reserve(variantsList.size());
- while(iter != variantsList.end()) {
- answer.append( qvariant_cast<QTextOption::Tab>(*iter));
- ++iter;
- }
+ for (const auto &e: variantsList)
+ answer.append(qvariant_cast<QTextOption::Tab>(e));
return answer;
}
@@ -3160,7 +3156,8 @@ QTextTableFormat::QTextTableFormat()
: QTextFrameFormat()
{
setObjectType(TableObject);
- setCellSpacing(2);
+ setCellPadding(4);
+ setBorderCollapse(true);
setBorder(1);
}
@@ -3997,7 +3994,7 @@ bool QTextFormatCollection::hasFormatCached(const QTextFormat &format) const
int QTextFormatCollection::objectFormatIndex(int objectIndex) const
{
- if (objectIndex == -1)
+ if (objectIndex == -1 || objectIndex >= objFormats.size())
return -1;
return objFormats.at(objectIndex);
}
diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp
index 16e2d7bd3a..ee92cece78 100644
--- a/src/gui/text/qtexthtmlparser.cpp
+++ b/src/gui/text/qtexthtmlparser.cpp
@@ -413,17 +413,17 @@ static const QTextHtmlElement elements[Html_NumElements]= {
{ "var", Html_var, QTextHtmlElement::DisplayInline },
};
-static bool operator<(const QString &str, const QTextHtmlElement &e)
+static bool operator<(QStringView str, const QTextHtmlElement &e)
{
return str < QLatin1StringView(e.name);
}
-static bool operator<(const QTextHtmlElement &e, const QString &str)
+static bool operator<(const QTextHtmlElement &e, QStringView str)
{
return QLatin1StringView(e.name) < str;
}
-static const QTextHtmlElement *lookupElementHelper(const QString &element)
+static const QTextHtmlElement *lookupElementHelper(QStringView element)
{
const QTextHtmlElement *start = &elements[0];
const QTextHtmlElement *end = &elements[Html_NumElements];
@@ -433,7 +433,7 @@ static const QTextHtmlElement *lookupElementHelper(const QString &element)
return e;
}
-int QTextHtmlParser::lookupElement(const QString &element)
+int QTextHtmlParser::lookupElement(QStringView element)
{
const QTextHtmlElement *e = lookupElementHelper(element);
if (!e)
@@ -1181,7 +1181,7 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d
QCss::ValueExtractor extractor(declarations);
extractor.extractBox(margin, padding);
- if (id == Html_td || id == Html_th) {
+ auto getBorderValues = [&extractor](qreal *borderWidth, QBrush *borderBrush, QTextFrameFormat::BorderStyle *borderStyles) {
QCss::BorderStyle cssStyles[4];
int cssBorder[4];
QSize cssRadii[4]; // unused
@@ -1193,20 +1193,24 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d
// QCss::BorderWidth parsing below which expects a single value
// will not work as expected - which in this case does not matter
// because tableBorder is not relevant for cells.
- extractor.extractBorder(cssBorder, tableCellBorderBrush, cssStyles, cssRadii);
+ bool hit = extractor.extractBorder(cssBorder, borderBrush, cssStyles, cssRadii);
for (int i = 0; i < 4; ++i) {
- tableCellBorderStyle[i] = toQTextFrameFormat(cssStyles[i]);
- tableCellBorder[i] = static_cast<qreal>(cssBorder[i]);
+ borderStyles[i] = toQTextFrameFormat(cssStyles[i]);
+ borderWidth[i] = static_cast<qreal>(cssBorder[i]);
}
- }
+ return hit;
+ };
+
+ if (id == Html_td || id == Html_th)
+ getBorderValues(tableCellBorder, tableCellBorderBrush, tableCellBorderStyle);
for (int i = 0; i < declarations.size(); ++i) {
const QCss::Declaration &decl = declarations.at(i);
if (decl.d->values.isEmpty()) continue;
QCss::KnownValue identifier = QCss::UnknownValue;
- if (decl.d->values.first().type == QCss::Value::KnownIdentifier)
- identifier = static_cast<QCss::KnownValue>(decl.d->values.first().variant.toInt());
+ if (decl.d->values.constFirst().type == QCss::Value::KnownIdentifier)
+ identifier = static_cast<QCss::KnownValue>(decl.d->values.constFirst().variant.toInt());
switch (decl.d->propertyId) {
case QCss::BorderColor: borderBrush = QBrush(decl.colorValue()); break;
@@ -1220,6 +1224,19 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d
tableBorder = borders[0];
}
break;
+ case QCss::Border: {
+ qreal tblBorder[4];
+ QBrush tblBorderBrush[4];
+ QTextFrameFormat::BorderStyle tblBorderStyle[4];
+ if (getBorderValues(tblBorder, tblBorderBrush, tblBorderStyle)) {
+ tableBorder = tblBorder[0];
+ if (tblBorderBrush[0].color().isValid())
+ borderBrush = tblBorderBrush[0];
+ if (tblBorderStyle[0] != static_cast<QTextFrameFormat::BorderStyle>(-1))
+ borderStyle = tblBorderStyle[0];
+ }
+ }
+ break;
case QCss::BorderCollapse:
borderCollapse = decl.borderCollapseValue();
break;
@@ -1233,10 +1250,10 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d
}
break;
case QCss::QtBlockIndent:
- blockFormat.setIndent(decl.d->values.first().variant.toInt());
+ blockFormat.setIndent(decl.d->values.constFirst().variant.toInt());
break;
case QCss::QtLineHeightType: {
- QString lineHeightTypeName = decl.d->values.first().variant.toString();
+ QString lineHeightTypeName = decl.d->values.constFirst().variant.toString();
QTextBlockFormat::LineHeightTypes lineHeightType;
if (lineHeightTypeName.compare("proportional"_L1, Qt::CaseInsensitive) == 0)
lineHeightType = QTextBlockFormat::ProportionalHeight;
@@ -1265,7 +1282,7 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d
lineHeightType = QTextBlockFormat::MinimumHeight;
} else {
bool ok;
- QCss::Value cssValue = decl.d->values.first();
+ QCss::Value cssValue = decl.d->values.constFirst();
QString value = cssValue.toString();
lineHeight = value.toDouble(&ok);
if (ok) {
@@ -1297,19 +1314,19 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d
hasCssListIndent = true;
break;
case QCss::QtParagraphType:
- if (decl.d->values.first().variant.toString().compare("empty"_L1, Qt::CaseInsensitive) == 0)
+ if (decl.d->values.constFirst().variant.toString().compare("empty"_L1, Qt::CaseInsensitive) == 0)
isEmptyParagraph = true;
break;
case QCss::QtTableType:
- if (decl.d->values.first().variant.toString().compare("frame"_L1, Qt::CaseInsensitive) == 0)
+ if (decl.d->values.constFirst().variant.toString().compare("frame"_L1, Qt::CaseInsensitive) == 0)
isTextFrame = true;
- else if (decl.d->values.first().variant.toString().compare("root"_L1, Qt::CaseInsensitive) == 0) {
+ else if (decl.d->values.constFirst().variant.toString().compare("root"_L1, Qt::CaseInsensitive) == 0) {
isTextFrame = true;
isRootFrame = true;
}
break;
case QCss::QtUserState:
- userState = decl.d->values.first().variant.toInt();
+ userState = decl.d->values.constFirst().variant.toInt();
break;
case QCss::Whitespace:
switch (identifier) {
@@ -1363,10 +1380,10 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d
setListStyle(decl.d->values);
break;
case QCss::QtListNumberPrefix:
- textListNumberPrefix = decl.d->values.first().variant.toString();
+ textListNumberPrefix = decl.d->values.constFirst().variant.toString();
break;
case QCss::QtListNumberSuffix:
- textListNumberSuffix = decl.d->values.first().variant.toString();
+ textListNumberSuffix = decl.d->values.constFirst().variant.toString();
break;
case QCss::TextAlignment:
switch (identifier) {
@@ -1381,12 +1398,36 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d
{
if (resourceProvider != nullptr && QTextDocumentPrivate::get(resourceProvider) != nullptr) {
bool ok;
- qint64 searchKey = decl.d->values.first().variant.toLongLong(&ok);
+ qint64 searchKey = decl.d->values.constFirst().variant.toLongLong(&ok);
if (ok)
applyForegroundImage(searchKey, resourceProvider);
}
break;
}
+ case QCss::QtStrokeColor:
+ {
+ QPen pen = charFormat.textOutline();
+ pen.setStyle(Qt::SolidLine);
+ pen.setColor(decl.colorValue());
+ charFormat.setTextOutline(pen);
+ break;
+ }
+ case QCss::QtStrokeWidth:
+ {
+ qreal width;
+ if (decl.realValue(&width, "px")) {
+ QPen pen = charFormat.textOutline();
+ pen.setWidthF(width);
+ charFormat.setTextOutline(pen);
+ }
+ break;
+ }
+ case QCss::QtForeground:
+ {
+ QBrush brush = decl.brushValue();
+ charFormat.setForeground(brush);
+ break;
+ }
default: break;
}
}
@@ -1594,10 +1635,9 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes)
node->charFormat.setProperty(QTextFormat::FontSizeAdjustment, n);
} else if (key == "face"_L1) {
if (value.contains(u',')) {
- const QStringList values = value.split(u',');
QStringList families;
- for (const QString &family : values)
- families << family.trimmed();
+ for (auto family : value.tokenize(u','))
+ families << family.trimmed().toString();
node->charFormat.setFontFamilies(families);
} else {
node->charFormat.setFontFamilies(QStringList(value));
@@ -1698,7 +1738,8 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes)
}
break;
case Html_table:
- if (key == "border"_L1) {
+ // If table border already set through css style, prefer that one otherwise consider this value
+ if (key == "border"_L1 && !node->tableBorder) {
setFloatAttribute(&node->tableBorder, value);
} else if (key == "bgcolor"_L1) {
QColor c = QColor::fromString(value);
@@ -2080,7 +2121,7 @@ QList<QCss::Declaration> standardDeclarationForNode(const QTextHtmlParserNode &n
decl.d->propertyId = QCss::FontFamily;
QList<QCss::Value> values;
val.type = QCss::Value::String;
- val.variant = QFontDatabase::systemFont(QFontDatabase::FixedFont).families().first();
+ val.variant = QFontDatabase::systemFont(QFontDatabase::FixedFont).families().constFirst();
values << val;
decl.d->values = values;
decl.d->inheritable = true;
diff --git a/src/gui/text/qtexthtmlparser_p.h b/src/gui/text/qtexthtmlparser_p.h
index ecbc238171..dd52baa23e 100644
--- a/src/gui/text/qtexthtmlparser_p.h
+++ b/src/gui/text/qtexthtmlparser_p.h
@@ -276,7 +276,7 @@ public:
void parse(const QString &text, const QTextDocument *resourceProvider);
- static int lookupElement(const QString &element);
+ static int lookupElement(QStringView element);
Q_GUI_EXPORT static QString parseEntity(QStringView entity);
diff --git a/src/gui/text/qtextimagehandler.cpp b/src/gui/text/qtextimagehandler.cpp
index 70e8961467..5c56c30711 100644
--- a/src/gui/text/qtextimagehandler.cpp
+++ b/src/gui/text/qtextimagehandler.cpp
@@ -23,12 +23,14 @@ static inline QString findAtNxFileOrResource(const QString &baseFileName,
{
// qt_findAtNxFile expects a file name that can be tested with QFile::exists.
// so if the format.name() is a file:/ or qrc:/ URL, then we need to strip away the schema.
- QString localFile = baseFileName;
- if (localFile.startsWith("file:/"_L1))
- localFile = localFile.sliced(6);
- else if (localFile.startsWith("qrc:/"_L1))
- localFile = localFile.sliced(3);
-
+ QString localFile;
+ const QUrl url(baseFileName);
+ if (url.isLocalFile())
+ localFile = url.toLocalFile();
+ else if (baseFileName.startsWith("qrc:/"_L1))
+ localFile = baseFileName.sliced(3);
+ else
+ localFile = baseFileName;
extern QString qt_findAtNxFile(const QString &baseFileName, qreal targetDevicePixelRatio,
qreal *sourceDevicePixelRatio);
return qt_findAtNxFile(localFile, targetDevicePixelRatio, sourceDevicePixelRatio);
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index eee86d9a6f..f0c7dd24e5 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -741,7 +741,7 @@ int QTextLayout::leftCursorPosition(int oldPos) const
return newPos;
}
-/*!/
+/*!
Returns \c true if position \a pos is a valid cursor position.
In a Unicode context some positions in the text are not valid
@@ -1043,12 +1043,9 @@ QList<QGlyphRun> QTextLayout::glyphRuns(int from,
for (int i=0; i<d->lines.size(); ++i) {
if (d->lines.at(i).from > from + length)
break;
- else if (d->lines.at(i).from + d->lines[i].length >= from) {
- QList<QGlyphRun> glyphRuns = QTextLine(i, d).glyphRuns(from, length, retrievalFlags);
-
- for (int j = 0; j < glyphRuns.size(); j++) {
- const QGlyphRun &glyphRun = glyphRuns.at(j);
-
+ else if (d->lines.at(i).from + d->lines.at(i).length >= from) {
+ const QList<QGlyphRun> glyphRuns = QTextLine(i, d).glyphRuns(from, length, retrievalFlags);
+ for (const QGlyphRun &glyphRun : glyphRuns) {
QRawFont rawFont = glyphRun.rawFont();
QFontEngine *fontEngine = rawFont.d->fontEngine;
@@ -1107,7 +1104,6 @@ void QTextLayout::draw(QPainter *p, const QPointF &pos, const QList<FormatRange>
int firstLine = 0;
int lastLine = d->lines.size();
for (int i = 0; i < d->lines.size(); ++i) {
- QTextLine l(i, d);
const QScriptLine &sl = d->lines.at(i);
if (sl.y > clipe) {
@@ -1656,7 +1652,7 @@ void QTextLine::setNumColumns(int numColumns)
void QTextLine::setNumColumns(int numColumns, qreal alignmentWidth)
{
QScriptLine &line = eng->lines[index];
- line.width = QFixed::fromReal(alignmentWidth);
+ line.width = QFixed::fromReal(qBound(0.0, alignmentWidth, qreal(QFIXED_MAX)));
line.length = 0;
line.textWidth = 0;
layout_helper(numColumns);
@@ -1672,23 +1668,18 @@ namespace {
struct LineBreakHelper
{
- LineBreakHelper()
- : glyphCount(0), maxGlyphs(0), currentPosition(0), fontEngine(nullptr), logClusters(nullptr),
- manualWrap(false), whiteSpaceOrObject(true)
- {
- }
-
+ LineBreakHelper() = default;
QScriptLine tmpData;
QScriptLine spaceData;
QGlyphLayout glyphs;
- int glyphCount;
- int maxGlyphs;
- int currentPosition;
- glyph_t previousGlyph;
- QFontEngine *previousGlyphFontEngine;
+ int glyphCount = 0;
+ int maxGlyphs = 0;
+ int currentPosition = 0;
+ glyph_t previousGlyph = 0;
+ QExplicitlySharedDataPointer<QFontEngine> previousGlyphFontEngine;
QFixed minw;
QFixed currentSoftHyphenWidth;
@@ -1696,11 +1687,11 @@ namespace {
QFixed rightBearing;
QFixed minimumRightBearing;
- QFontEngine *fontEngine;
- const unsigned short *logClusters;
+ QExplicitlySharedDataPointer<QFontEngine> fontEngine;
+ const unsigned short *logClusters = nullptr;
- bool manualWrap;
- bool whiteSpaceOrObject;
+ bool manualWrap = false;
+ bool whiteSpaceOrObject = true;
bool checkFullOtherwiseExtend(QScriptLine &line);
@@ -1744,13 +1735,13 @@ namespace {
{
if (currentPosition <= 0)
return;
- calculateRightBearing(fontEngine, currentGlyph());
+ calculateRightBearing(fontEngine.data(), currentGlyph());
}
inline void calculateRightBearingForPreviousGlyph()
{
if (previousGlyph > 0)
- calculateRightBearing(previousGlyphFontEngine, previousGlyph);
+ calculateRightBearing(previousGlyphFontEngine.data(), previousGlyph);
}
static const QFixed RightBearingNotCalculated;
@@ -2164,9 +2155,12 @@ found:
eng->maxWidth = qMax(eng->maxWidth, line.textWidth);
} else {
eng->minWidth = qMax(eng->minWidth, lbh.minw);
- eng->layoutData->currentMaxWidth += line.textWidth;
- if (!manuallyWrapped)
- eng->layoutData->currentMaxWidth += lbh.spaceData.textWidth;
+ if (qAddOverflow(eng->layoutData->currentMaxWidth, line.textWidth, &eng->layoutData->currentMaxWidth))
+ eng->layoutData->currentMaxWidth = QFIXED_MAX;
+ if (!manuallyWrapped) {
+ if (qAddOverflow(eng->layoutData->currentMaxWidth, lbh.spaceData.textWidth, &eng->layoutData->currentMaxWidth))
+ eng->layoutData->currentMaxWidth = QFIXED_MAX;
+ }
eng->maxWidth = qMax(eng->maxWidth, eng->layoutData->currentMaxWidth);
if (manuallyWrapped)
eng->layoutData->currentMaxWidth = 0;
@@ -2229,20 +2223,20 @@ int QTextLine::textLength() const
return eng->lines.at(index).length + eng->lines.at(index).trailingSpaces;
}
-static void setPenAndDrawBackground(QPainter *p, const QPen &defaultPen, const QTextCharFormat &chf, const QRectF &r)
+static void drawBackground(QPainter *p, const QTextCharFormat &chf, const QRectF &r)
{
- QBrush c = chf.foreground();
- if (c.style() == Qt::NoBrush) {
- p->setPen(defaultPen);
- }
-
QBrush bg = chf.background();
if (bg.style() != Qt::NoBrush && !chf.property(SuppressBackground).toBool())
p->fillRect(r.toAlignedRect(), bg);
- if (c.style() != Qt::NoBrush) {
- p->setPen(QPen(c, 0));
- }
+}
+static void setPen(QPainter *p, const QPen &defaultPen, const QTextCharFormat &chf)
+{
+ QBrush c = chf.foreground();
+ if (c.style() == Qt::NoBrush)
+ p->setPen(defaultPen);
+ else
+ p->setPen(QPen(c, 0));
}
#if !defined(QT_NO_RAWFONT)
@@ -2637,7 +2631,6 @@ void QTextLine::draw_internal(QPainter *p, const QPointF &origPos,
Q_ASSERT(!eng->useRawFont);
#endif
const QScriptLine &line = eng->lines[index];
- QPen pen = p->pen();
bool noText = (selection && selection->format.property(SuppressText).toBool());
@@ -2649,8 +2642,7 @@ void QTextLine::draw_internal(QPainter *p, const QPointF &origPos,
const qreal lineHeight = line.height().toReal();
QRectF r(origPos.x() + line.x.toReal(), origPos.y() + line.y.toReal(),
lineHeight / 2, QFontMetrics(eng->font()).horizontalAdvance(u' '));
- setPenAndDrawBackground(p, QPen(), selection->format, r);
- p->setPen(pen);
+ drawBackground(p, selection->format, r);
}
return;
}
@@ -2663,7 +2655,7 @@ void QTextLine::draw_internal(QPainter *p, const QPointF &origPos,
else
p->translate(origPos);
- QTextLineItemIterator iterator(eng, index, pos, selection);
+
QFixed lineBase = line.base();
eng->clearDecorations();
eng->enableDelayDecorations();
@@ -2673,183 +2665,207 @@ void QTextLine::draw_internal(QPainter *p, const QPointF &origPos,
const QTextFormatCollection *formatCollection = eng->formatCollection();
bool suppressColors = (eng->option.flags() & QTextOption::SuppressColors);
- while (!iterator.atEnd()) {
- QScriptItem &si = iterator.next();
-
- if (selection && selection->start >= 0 && iterator.isOutsideSelection())
- continue;
-
- if (si.analysis.flags == QScriptAnalysis::LineOrParagraphSeparator
- && !(eng->option.flags() & QTextOption::ShowLineAndParagraphSeparators))
- continue;
- QFixed itemBaseLine = y;
- QFont f = eng->font(si);
- QTextCharFormat format;
- if (formatCollection != nullptr)
- format = formatCollection->defaultTextFormat();
+ auto prepareFormat = [suppressColors, selection, this](QTextCharFormat &format,
+ QScriptItem *si) {
+ format.merge(eng->format(si));
- if (eng->hasFormats() || selection || formatCollection) {
- format.merge(eng->format(&si));
+ if (suppressColors) {
+ format.clearForeground();
+ format.clearBackground();
+ format.clearProperty(QTextFormat::TextUnderlineColor);
+ }
+ if (selection)
+ format.merge(selection->format);
+ };
- if (suppressColors) {
- format.clearForeground();
- format.clearBackground();
- format.clearProperty(QTextFormat::TextUnderlineColor);
- }
- if (selection)
- format.merge(selection->format);
-
- setPenAndDrawBackground(p, pen, format, QRectF(iterator.x.toReal(), (y - lineBase).toReal(),
- iterator.itemWidth.toReal(), line.height().toReal()));
-
- const qreal baseLineOffset = format.baselineOffset() / 100.0;
- QTextCharFormat::VerticalAlignment valign = format.verticalAlignment();
- if (valign == QTextCharFormat::AlignSuperScript
- || valign == QTextCharFormat::AlignSubScript
- || !qFuzzyIsNull(baseLineOffset))
- {
- QFontEngine *fe = f.d->engineForScript(si.analysis.script);
- QFixed height = fe->ascent() + fe->descent();
- itemBaseLine -= height * QFixed::fromReal(baseLineOffset);
-
- if (valign == QTextCharFormat::AlignSubScript)
- itemBaseLine += height * QFixed::fromReal(format.subScriptBaseline() / 100.0);
- else if (valign == QTextCharFormat::AlignSuperScript)
- itemBaseLine -= height * QFixed::fromReal(format.superScriptBaseline() / 100.0);
+ {
+ QTextLineItemIterator iterator(eng, index, pos, selection);
+ while (!iterator.atEnd()) {
+ QScriptItem &si = iterator.next();
+
+ if (eng->hasFormats() || selection || formatCollection) {
+ QTextCharFormat format;
+ if (formatCollection != nullptr)
+ format = formatCollection->defaultTextFormat();
+ prepareFormat(format, &si);
+ drawBackground(p, format, QRectF(iterator.x.toReal(), (y - lineBase).toReal(),
+ iterator.itemWidth.toReal(), line.height().toReal()));
}
}
+ }
- if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
+ QPen pen = p->pen();
+ {
+ QTextLineItemIterator iterator(eng, index, pos, selection);
+ while (!iterator.atEnd()) {
+ QScriptItem &si = iterator.next();
- if (eng->hasFormats()) {
- p->save();
- if (si.analysis.flags == QScriptAnalysis::Object && QTextDocumentPrivate::get(eng->block)) {
- QFixed itemY = y - si.ascent;
- switch (format.verticalAlignment()) {
- case QTextCharFormat::AlignTop:
- itemY = y - lineBase;
- break;
- case QTextCharFormat::AlignMiddle:
- itemY = y - lineBase + (line.height() - si.height()) / 2;
- break;
- case QTextCharFormat::AlignBottom:
- itemY = y - lineBase + line.height() - si.height();
- break;
- default:
- break;
- }
+ if (selection && selection->start >= 0 && iterator.isOutsideSelection())
+ continue;
- QRectF itemRect(iterator.x.toReal(), itemY.toReal(), iterator.itemWidth.toReal(), si.height().toReal());
-
- eng->docLayout()->drawInlineObject(p, itemRect,
- QTextInlineObject(iterator.item, eng),
- si.position + eng->block.position(),
- format);
- if (selection) {
- QBrush bg = format.brushProperty(ObjectSelectionBrush);
- if (bg.style() != Qt::NoBrush) {
- QColor c = bg.color();
- c.setAlpha(128);
- p->fillRect(itemRect, c);
- }
- }
- } else { // si.isTab
- QFont f = eng->font(si);
- QTextItemInt gf(si, &f, format);
- gf.chars = nullptr;
- gf.num_chars = 0;
- gf.width = iterator.itemWidth;
- QPainterPrivate::get(p)->drawTextItem(QPointF(iterator.x.toReal(), y.toReal()), gf, eng);
- if (eng->option.flags() & QTextOption::ShowTabsAndSpaces) {
- const QChar visualTab = QChar(QChar::VisualTabCharacter);
- int w = QFontMetrics(f).horizontalAdvance(visualTab);
- qreal x = iterator.itemWidth.toReal() - w; // Right-aligned
- if (x < 0)
- p->setClipRect(QRectF(iterator.x.toReal(), line.y.toReal(),
- iterator.itemWidth.toReal(), line.height().toReal()),
- Qt::IntersectClip);
- else
- x /= 2; // Centered
- p->setFont(f);
- p->drawText(QPointF(iterator.x.toReal() + x,
- y.toReal()), visualTab);
- }
+ if (si.analysis.flags == QScriptAnalysis::LineOrParagraphSeparator
+ && !(eng->option.flags() & QTextOption::ShowLineAndParagraphSeparators))
+ continue;
+ QFixed itemBaseLine = y;
+ QFont f = eng->font(si);
+ QTextCharFormat format;
+ if (formatCollection != nullptr)
+ format = formatCollection->defaultTextFormat();
+
+ if (eng->hasFormats() || selection || formatCollection) {
+ prepareFormat(format, &si);
+ setPen(p, pen, format);
+
+ const qreal baseLineOffset = format.baselineOffset() / 100.0;
+ QTextCharFormat::VerticalAlignment valign = format.verticalAlignment();
+ if (valign == QTextCharFormat::AlignSuperScript
+ || valign == QTextCharFormat::AlignSubScript
+ || !qFuzzyIsNull(baseLineOffset))
+ {
+ QFontEngine *fe = f.d->engineForScript(si.analysis.script);
+ QFixed height = fe->ascent() + fe->descent();
+ itemBaseLine -= height * QFixed::fromReal(baseLineOffset);
+
+ if (valign == QTextCharFormat::AlignSubScript)
+ itemBaseLine += height * QFixed::fromReal(format.subScriptBaseline() / 100.0);
+ else if (valign == QTextCharFormat::AlignSuperScript)
+ itemBaseLine -= height * QFixed::fromReal(format.superScriptBaseline() / 100.0);
}
- p->restore();
}
- continue;
- }
+ if (si.analysis.flags >= QScriptAnalysis::TabOrObject) {
- unsigned short *logClusters = eng->logClusters(&si);
- QGlyphLayout glyphs = eng->shapedGlyphs(&si);
+ if (eng->hasFormats()) {
+ p->save();
+ if (si.analysis.flags == QScriptAnalysis::Object && QTextDocumentPrivate::get(eng->block)) {
+ QFixed itemY = y - si.ascent;
+ switch (format.verticalAlignment()) {
+ case QTextCharFormat::AlignTop:
+ itemY = y - lineBase;
+ break;
+ case QTextCharFormat::AlignMiddle:
+ itemY = y - lineBase + (line.height() - si.height()) / 2;
+ break;
+ case QTextCharFormat::AlignBottom:
+ itemY = y - lineBase + line.height() - si.height();
+ break;
+ default:
+ break;
+ }
- QTextItemInt gf(glyphs.mid(iterator.glyphsStart, iterator.glyphsEnd - iterator.glyphsStart),
- &f, eng->layoutData->string.unicode() + iterator.itemStart,
- iterator.itemEnd - iterator.itemStart, eng->fontEngine(si), format);
- gf.logClusters = logClusters + iterator.itemStart - si.position;
- gf.width = iterator.itemWidth;
- gf.justified = line.justified;
- gf.initWithScriptItem(si);
-
- Q_ASSERT(gf.fontEngine);
-
- QPointF pos(iterator.x.toReal(), itemBaseLine.toReal());
- if (format.penProperty(QTextFormat::TextOutline).style() != Qt::NoPen) {
- QPainterPath path;
- path.setFillRule(Qt::WindingFill);
-
- if (gf.glyphs.numGlyphs)
- gf.fontEngine->addOutlineToPath(pos.x(), pos.y(), gf.glyphs, &path, gf.flags);
- if (gf.flags) {
- const QFontEngine *fe = gf.fontEngine;
- const qreal lw = fe->lineThickness().toReal();
- if (gf.flags & QTextItem::Underline) {
- qreal offs = fe->underlinePosition().toReal();
- path.addRect(pos.x(), pos.y() + offs, gf.width.toReal(), lw);
- }
- if (gf.flags & QTextItem::Overline) {
- qreal offs = fe->ascent().toReal() + 1;
- path.addRect(pos.x(), pos.y() - offs, gf.width.toReal(), lw);
- }
- if (gf.flags & QTextItem::StrikeOut) {
- qreal offs = fe->ascent().toReal() / 3;
- path.addRect(pos.x(), pos.y() - offs, gf.width.toReal(), lw);
+ QRectF itemRect(iterator.x.toReal(), itemY.toReal(), iterator.itemWidth.toReal(), si.height().toReal());
+
+ eng->docLayout()->drawInlineObject(p, itemRect,
+ QTextInlineObject(iterator.item, eng),
+ si.position + eng->block.position(),
+ format);
+ if (selection) {
+ QBrush bg = format.brushProperty(ObjectSelectionBrush);
+ if (bg.style() != Qt::NoBrush) {
+ QColor c = bg.color();
+ c.setAlpha(128);
+ p->fillRect(itemRect, c);
+ }
+ }
+ } else { // si.isTab
+ QFont f = eng->font(si);
+ QTextItemInt gf(si, &f, format);
+ gf.chars = nullptr;
+ gf.num_chars = 0;
+ gf.width = iterator.itemWidth;
+ QPainterPrivate::get(p)->drawTextItem(QPointF(iterator.x.toReal(), y.toReal()), gf, eng);
+ if (eng->option.flags() & QTextOption::ShowTabsAndSpaces) {
+ const QChar visualTab = QChar(QChar::VisualTabCharacter);
+ int w = QFontMetrics(f).horizontalAdvance(visualTab);
+ qreal x = iterator.itemWidth.toReal() - w; // Right-aligned
+ if (x < 0)
+ p->setClipRect(QRectF(iterator.x.toReal(), line.y.toReal(),
+ iterator.itemWidth.toReal(), line.height().toReal()),
+ Qt::IntersectClip);
+ else
+ x /= 2; // Centered
+ p->setFont(f);
+ p->drawText(QPointF(iterator.x.toReal() + x,
+ y.toReal()), visualTab);
+ }
+
+ }
+ p->restore();
}
+
+ continue;
}
- p->save();
- p->setRenderHint(QPainter::Antialiasing);
- //Currently QPen with a Qt::NoPen style still returns a default
- //QBrush which != Qt::NoBrush so we need this specialcase to reset it
- if (p->pen().style() == Qt::NoPen)
- p->setBrush(Qt::NoBrush);
- else
- p->setBrush(p->pen().brush());
+ unsigned short *logClusters = eng->logClusters(&si);
+ QGlyphLayout glyphs = eng->shapedGlyphs(&si);
- p->setPen(format.textOutline());
- p->drawPath(path);
- p->restore();
- } else {
- if (noText)
- gf.glyphs.numGlyphs = 0; // slightly less elegant than it should be
- QPainterPrivate::get(p)->drawTextItem(pos, gf, eng);
- }
+ QTextItemInt gf(glyphs.mid(iterator.glyphsStart, iterator.glyphsEnd - iterator.glyphsStart),
+ &f, eng->layoutData->string.unicode() + iterator.itemStart,
+ iterator.itemEnd - iterator.itemStart, eng->fontEngine(si), format);
+ gf.logClusters = logClusters + iterator.itemStart - si.position;
+ gf.width = iterator.itemWidth;
+ gf.justified = line.justified;
+ gf.initWithScriptItem(si);
+
+ Q_ASSERT(gf.fontEngine);
+
+ QPointF pos(iterator.x.toReal(), itemBaseLine.toReal());
+ if (format.penProperty(QTextFormat::TextOutline).style() != Qt::NoPen) {
+ QPainterPath path;
+ path.setFillRule(Qt::WindingFill);
+
+ if (gf.glyphs.numGlyphs)
+ gf.fontEngine->addOutlineToPath(pos.x(), pos.y(), gf.glyphs, &path, gf.flags);
+ if (gf.flags) {
+ const QFontEngine *fe = gf.fontEngine;
+ const qreal lw = fe->lineThickness().toReal();
+ if (gf.flags & QTextItem::Underline) {
+ qreal offs = fe->underlinePosition().toReal();
+ path.addRect(pos.x(), pos.y() + offs, gf.width.toReal(), lw);
+ }
+ if (gf.flags & QTextItem::Overline) {
+ qreal offs = fe->ascent().toReal() + 1;
+ path.addRect(pos.x(), pos.y() - offs, gf.width.toReal(), lw);
+ }
+ if (gf.flags & QTextItem::StrikeOut) {
+ qreal offs = fe->ascent().toReal() / 3;
+ path.addRect(pos.x(), pos.y() - offs, gf.width.toReal(), lw);
+ }
+ }
- if ((si.analysis.flags == QScriptAnalysis::Space
- || si.analysis.flags == QScriptAnalysis::Nbsp)
- && (eng->option.flags() & QTextOption::ShowTabsAndSpaces)) {
- QBrush c = format.foreground();
- if (c.style() != Qt::NoBrush)
- p->setPen(c.color());
- const QChar visualSpace = si.analysis.flags == QScriptAnalysis::Space ? u'\xb7' : u'\xb0';
- QFont oldFont = p->font();
- p->setFont(eng->font(si));
- p->drawText(QPointF(iterator.x.toReal(), itemBaseLine.toReal()), visualSpace);
- p->setPen(pen);
- p->setFont(oldFont);
+ p->save();
+ p->setRenderHint(QPainter::Antialiasing);
+ //Currently QPen with a Qt::NoPen style still returns a default
+ //QBrush which != Qt::NoBrush so we need this specialcase to reset it
+ if (p->pen().style() == Qt::NoPen)
+ p->setBrush(Qt::NoBrush);
+ else
+ p->setBrush(p->pen().brush());
+
+ p->setPen(format.textOutline());
+ p->drawPath(path);
+ p->restore();
+ } else {
+ if (noText)
+ gf.glyphs.numGlyphs = 0; // slightly less elegant than it should be
+ QPainterPrivate::get(p)->drawTextItem(pos, gf, eng);
+ }
+
+ if ((si.analysis.flags == QScriptAnalysis::Space
+ || si.analysis.flags == QScriptAnalysis::Nbsp)
+ && (eng->option.flags() & QTextOption::ShowTabsAndSpaces)) {
+ QBrush c = format.foreground();
+ if (c.style() != Qt::NoBrush)
+ p->setPen(c.color());
+ const QChar visualSpace = si.analysis.flags == QScriptAnalysis::Space ? u'\xb7' : u'\xb0';
+ QFont oldFont = p->font();
+ p->setFont(eng->font(si));
+ p->drawText(QPointF(iterator.x.toReal(), itemBaseLine.toReal()), visualSpace);
+ p->setPen(pen);
+ p->setFont(oldFont);
+ }
}
}
eng->drawDecorations(p);
diff --git a/src/gui/text/qtextlist.cpp b/src/gui/text/qtextlist.cpp
index 90a6cf8867..7ec8b6215e 100644
--- a/src/gui/text/qtextlist.cpp
+++ b/src/gui/text/qtextlist.cpp
@@ -186,16 +186,14 @@ QString QTextList::itemText(const QTextBlock &blockIt) const
if (itemNumber < 1) {
result = QString::number(itemNumber);
} else if (itemNumber < 5000) {
- QByteArray romanNumeral;
+ QString romanNumeral;
// works for up to 4999 items
- static const char romanSymbolsLower[] = "iiivixxxlxcccdcmmmm";
- static const char romanSymbolsUpper[] = "IIIVIXXXLXCCCDCMMMM";
- QByteArray romanSymbols; // wrap to have "mid"
+ QLatin1StringView romanSymbols;
if (style == QTextListFormat::ListLowerRoman)
- romanSymbols = QByteArray::fromRawData(romanSymbolsLower, sizeof(romanSymbolsLower));
+ romanSymbols = "iiivixxxlxcccdcmmmm"_L1;
else
- romanSymbols = QByteArray::fromRawData(romanSymbolsUpper, sizeof(romanSymbolsUpper));
+ romanSymbols = "IIIVIXXXLXCCCDCMMMM"_L1;
int c[] = { 1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000 };
int n = itemNumber;
@@ -220,10 +218,10 @@ QString QTextList::itemText(const QTextBlock &blockIt) const
numDigits = q;
}
- romanNumeral.append(romanSymbols.mid(startDigit, numDigits));
+ romanNumeral.append(romanSymbols.sliced(startDigit, numDigits));
}
}
- result = QString::fromLatin1(romanNumeral);
+ result = std::move(romanNumeral);
} else {
result = u"?"_s;
}
diff --git a/src/gui/text/qtextmarkdownimporter.cpp b/src/gui/text/qtextmarkdownimporter.cpp
index bb95678ef1..e7fcad67b5 100644
--- a/src/gui/text/qtextmarkdownimporter.cpp
+++ b/src/gui/text/qtextmarkdownimporter.cpp
@@ -27,6 +27,8 @@ Q_LOGGING_CATEGORY(lcMD, "qt.text.markdown")
static const QChar qtmi_Newline = u'\n';
static const QChar qtmi_Space = u' ';
+static constexpr auto markerString() noexcept { return "---"_L1; }
+
// TODO maybe eliminate the margins after all views recognize BlockQuoteLevel, CSS can format it, etc.
static const int qtmi_BlockQuoteIndent =
40; // pixels, same as in QTextHtmlParserNode::initializeProperties
@@ -46,7 +48,8 @@ static_assert(int(QTextMarkdownImporter::FeaturePermissiveAutoLinks) == MD_FLAG_
static_assert(int(QTextMarkdownImporter::FeatureTasklists) == MD_FLAG_TASKLISTS);
static_assert(int(QTextMarkdownImporter::FeatureNoHTML) == MD_FLAG_NOHTML);
static_assert(int(QTextMarkdownImporter::DialectCommonMark) == MD_DIALECT_COMMONMARK);
-static_assert(int(QTextMarkdownImporter::DialectGitHub) == (MD_DIALECT_GITHUB | MD_FLAG_UNDERLINE));
+static_assert(int(QTextMarkdownImporter::DialectGitHub) ==
+ (MD_DIALECT_GITHUB | MD_FLAG_UNDERLINE | QTextMarkdownImporter::FeatureFrontMatter));
// --------------------------------------------------------
// MD4C callback function wrappers
@@ -104,18 +107,19 @@ static Qt::Alignment MdAlignment(MD_ALIGN a, Qt::Alignment defaultAlignment = Qt
}
}
-QTextMarkdownImporter::QTextMarkdownImporter(QTextMarkdownImporter::Features features)
- : m_monoFont(QFontDatabase::systemFont(QFontDatabase::FixedFont))
+QTextMarkdownImporter::QTextMarkdownImporter(QTextDocument *doc, QTextMarkdownImporter::Features features)
+ : m_cursor(doc)
+ , m_monoFont(QFontDatabase::systemFont(QFontDatabase::FixedFont))
, m_features(features)
{
}
-QTextMarkdownImporter::QTextMarkdownImporter(QTextDocument::MarkdownFeatures features)
- : QTextMarkdownImporter(static_cast<QTextMarkdownImporter::Features>(int(features)))
+QTextMarkdownImporter::QTextMarkdownImporter(QTextDocument *doc, QTextDocument::MarkdownFeatures features)
+ : QTextMarkdownImporter(doc, static_cast<QTextMarkdownImporter::Features>(int(features)))
{
}
-void QTextMarkdownImporter::import(QTextDocument *doc, const QString &markdown)
+void QTextMarkdownImporter::import(const QString &markdown)
{
MD_PARSER callbacks = {
0, // abi_version
@@ -128,19 +132,36 @@ void QTextMarkdownImporter::import(QTextDocument *doc, const QString &markdown)
&CbDebugLog,
nullptr // syntax
};
- m_doc = doc;
- m_paragraphMargin = m_doc->defaultFont().pointSize() * 2 / 3;
- m_cursor = new QTextCursor(doc);
+ QTextDocument *doc = m_cursor.document();
+ const auto defaultFont = doc->defaultFont();
+ m_paragraphMargin = defaultFont.pointSize() * 2 / 3;
doc->clear();
- if (doc->defaultFont().pointSize() != -1)
- m_monoFont.setPointSize(doc->defaultFont().pointSize());
+ if (defaultFont.pointSize() != -1)
+ m_monoFont.setPointSize(defaultFont.pointSize());
else
- m_monoFont.setPixelSize(doc->defaultFont().pixelSize());
- qCDebug(lcMD) << "default font" << doc->defaultFont() << "mono font" << m_monoFont;
- QByteArray md = markdown.toUtf8();
- md_parse(md.constData(), MD_SIZE(md.size()), &callbacks, this);
- delete m_cursor;
- m_cursor = nullptr;
+ m_monoFont.setPixelSize(defaultFont.pixelSize());
+ qCDebug(lcMD) << "default font" << defaultFont << "mono font" << m_monoFont;
+ QStringView md = markdown;
+
+ if (m_features.testFlag(QTextMarkdownImporter::FeatureFrontMatter) && md.startsWith(markerString())) {
+ qsizetype endMarkerPos = md.indexOf(markerString(), markerString().size() + 1);
+ if (endMarkerPos > 4) {
+ qsizetype firstLinePos = 4; // first line of yaml
+ while (md.at(firstLinePos) == '\n'_L1 || md.at(firstLinePos) == '\r'_L1)
+ ++firstLinePos;
+ auto frontMatter = md.sliced(firstLinePos, endMarkerPos - firstLinePos);
+ firstLinePos = endMarkerPos + 4; // first line of markdown after yaml
+ while (md.size() > firstLinePos && (md.at(firstLinePos) == '\n'_L1 || md.at(firstLinePos) == '\r'_L1))
+ ++firstLinePos;
+ md = md.sliced(firstLinePos);
+ doc->setMetaInformation(QTextDocument::FrontMatter, frontMatter.toString());
+ qCDebug(lcMD) << "extracted FrontMatter: size" << frontMatter.size();
+ }
+ }
+ const auto mdUtf8 = md.toUtf8();
+ m_cursor.beginEditBlock();
+ md_parse(mdUtf8.constData(), MD_SIZE(mdUtf8.size()), &callbacks, this);
+ m_cursor.endEditBlock();
}
int QTextMarkdownImporter::cbEnterBlock(int blockType, void *det)
@@ -179,11 +200,11 @@ int QTextMarkdownImporter::cbEnterBlock(int blockType, void *det)
charFmt.setFontWeight(QFont::Bold);
blockFmt.setHeadingLevel(int(detail->level));
m_needsInsertBlock = false;
- if (m_doc->isEmpty()) {
- m_cursor->setBlockFormat(blockFmt);
- m_cursor->setCharFormat(charFmt);
+ if (m_cursor.document()->isEmpty()) {
+ m_cursor.setBlockFormat(blockFmt);
+ m_cursor.setCharFormat(charFmt);
} else {
- m_cursor->insertBlock(blockFmt, charFmt);
+ m_cursor.insertBlock(blockFmt, charFmt);
}
qCDebug(lcMD, "H%d", detail->level);
} break;
@@ -198,7 +219,7 @@ int QTextMarkdownImporter::cbEnterBlock(int blockType, void *det)
} break;
case MD_BLOCK_UL: {
if (m_needsInsertList) // list nested in an empty list
- m_listStack.push(m_cursor->insertList(m_listFormat));
+ m_listStack.push(m_cursor.insertList(m_listFormat));
else
m_needsInsertList = true;
MD_BLOCK_UL_DETAIL *detail = static_cast<MD_BLOCK_UL_DETAIL *>(det);
@@ -219,7 +240,7 @@ int QTextMarkdownImporter::cbEnterBlock(int blockType, void *det)
} break;
case MD_BLOCK_OL: {
if (m_needsInsertList) // list nested in an empty list
- m_listStack.push(m_cursor->insertList(m_listFormat));
+ m_listStack.push(m_cursor.insertList(m_listFormat));
else
m_needsInsertList = true;
MD_BLOCK_OL_DETAIL *detail = static_cast<MD_BLOCK_OL_DETAIL *>(det);
@@ -240,10 +261,10 @@ int QTextMarkdownImporter::cbEnterBlock(int blockType, void *det)
qWarning("malformed table in Markdown input");
return 1;
}
- *m_cursor = cell.firstCursorPosition();
- QTextBlockFormat blockFmt = m_cursor->blockFormat();
+ m_cursor = cell.firstCursorPosition();
+ QTextBlockFormat blockFmt = m_cursor.blockFormat();
blockFmt.setAlignment(MdAlignment(detail->align));
- m_cursor->setBlockFormat(blockFmt);
+ m_cursor.setBlockFormat(blockFmt);
qCDebug(lcMD) << "TD; align" << detail->align << MdAlignment(detail->align) << "col" << m_tableCol;
} break;
case MD_BLOCK_TH: {
@@ -271,13 +292,13 @@ int QTextMarkdownImporter::cbEnterBlock(int blockType, void *det)
case MD_BLOCK_TABLE:
m_tableColumnCount = 0;
m_tableRowCount = 0;
- m_currentTable = m_cursor->insertTable(1, 1); // we don't know the dimensions yet
+ m_currentTable = m_cursor.insertTable(1, 1); // we don't know the dimensions yet
break;
case MD_BLOCK_HR: {
qCDebug(lcMD, "HR");
QTextBlockFormat blockFmt;
blockFmt.setProperty(QTextFormat::BlockTrailingHorizontalRulerWidth, 1);
- m_cursor->insertBlock(blockFmt, QTextCharFormat());
+ m_cursor.insertBlock(blockFmt, QTextCharFormat());
} break;
default:
break; // nothing to do for now
@@ -295,7 +316,7 @@ int QTextMarkdownImporter::cbLeaveBlock(int blockType, void *detail)
case MD_BLOCK_UL:
case MD_BLOCK_OL:
if (Q_UNLIKELY(m_needsInsertList))
- m_listStack.push(m_cursor->createList(m_listFormat));
+ m_listStack.push(m_cursor.createList(m_listFormat));
if (Q_UNLIKELY(m_listStack.isEmpty())) {
qCWarning(lcMD, "list ended unexpectedly");
} else {
@@ -333,7 +354,7 @@ int QTextMarkdownImporter::cbLeaveBlock(int blockType, void *detail)
case MD_BLOCK_TABLE:
qCDebug(lcMD) << "table ended with" << m_currentTable->columns() << "cols and" << m_currentTable->rows() << "rows";
m_currentTable = nullptr;
- m_cursor->movePosition(QTextCursor::End);
+ m_cursor.movePosition(QTextCursor::End);
break;
case MD_BLOCK_LI:
qCDebug(lcMD, "LI at level %d ended", int(m_listStack.size()));
@@ -350,7 +371,7 @@ int QTextMarkdownImporter::cbLeaveBlock(int blockType, void *detail)
m_needsInsertBlock = true;
} break;
case MD_BLOCK_H:
- m_cursor->setCharFormat(QTextCharFormat());
+ m_cursor.setCharFormat(QTextCharFormat());
break;
default:
break;
@@ -401,10 +422,10 @@ int QTextMarkdownImporter::cbEnterSpan(int spanType, void *det)
break;
}
m_spanFormatStack.push(charFmt);
- qCDebug(lcMD) << spanType << "setCharFormat" << charFmt.font().families().first()
+ qCDebug(lcMD) << spanType << "setCharFormat" << charFmt.font().families().constFirst()
<< charFmt.fontWeight() << (charFmt.fontItalic() ? "italic" : "")
<< charFmt.foreground().color().name();
- m_cursor->setCharFormat(charFmt);
+ m_cursor.setCharFormat(charFmt);
return 0; // no error
}
@@ -417,8 +438,8 @@ int QTextMarkdownImporter::cbLeaveSpan(int spanType, void *detail)
if (!m_spanFormatStack.isEmpty())
charFmt = m_spanFormatStack.top();
}
- m_cursor->setCharFormat(charFmt);
- qCDebug(lcMD) << spanType << "setCharFormat" << charFmt.font().families().first()
+ m_cursor.setCharFormat(charFmt);
+ qCDebug(lcMD) << spanType << "setCharFormat" << charFmt.font().families().constFirst()
<< charFmt.fontWeight() << (charFmt.fontItalic() ? "italic" : "")
<< charFmt.foreground().color().name();
if (spanType == int(MD_SPAN_IMG))
@@ -462,7 +483,7 @@ int QTextMarkdownImporter::cbText(int textType, const char *text, unsigned size)
if (m_htmlTagDepth)
m_htmlAccumulator += s;
else
- m_cursor->insertHtml(s);
+ m_cursor.insertHtml(s);
s = QString();
break;
#endif
@@ -484,11 +505,11 @@ int QTextMarkdownImporter::cbText(int textType, const char *text, unsigned size)
m_htmlAccumulator += s;
if (!m_htmlTagDepth) { // all open tags are now closed
qCDebug(lcMD) << "HTML" << m_htmlAccumulator;
- m_cursor->insertHtml(m_htmlAccumulator);
+ m_cursor.insertHtml(m_htmlAccumulator);
if (m_spanFormatStack.isEmpty())
- m_cursor->setCharFormat(QTextCharFormat());
+ m_cursor.setCharFormat(QTextCharFormat());
else
- m_cursor->setCharFormat(m_spanFormatStack.top());
+ m_cursor.setCharFormat(m_spanFormatStack.top());
m_htmlAccumulator = QString();
}
#endif
@@ -518,24 +539,24 @@ int QTextMarkdownImporter::cbText(int textType, const char *text, unsigned size)
m_imageFormat.setProperty(QTextFormat::ImageAltText, s);
qCDebug(lcMD) << "image" << m_imageFormat.name()
<< "title" << m_imageFormat.stringProperty(QTextFormat::ImageTitle)
- << "alt" << s << "relative to" << m_doc->baseUrl();
- m_cursor->insertImage(m_imageFormat);
+ << "alt" << s << "relative to" << m_cursor.document()->baseUrl();
+ m_cursor.insertImage(m_imageFormat);
return 0; // no error
}
if (!s.isEmpty())
- m_cursor->insertText(s);
- if (m_cursor->currentList()) {
+ m_cursor.insertText(s);
+ if (m_cursor.currentList()) {
// The list item will indent the list item's text, so we don't need indentation on the block.
- QTextBlockFormat bfmt = m_cursor->blockFormat();
+ QTextBlockFormat bfmt = m_cursor.blockFormat();
bfmt.setIndent(0);
- m_cursor->setBlockFormat(bfmt);
+ m_cursor.setBlockFormat(bfmt);
}
if (lcMD().isEnabled(QtDebugMsg)) {
- QTextBlockFormat bfmt = m_cursor->blockFormat();
+ QTextBlockFormat bfmt = m_cursor.blockFormat();
QString debugInfo;
- if (m_cursor->currentList())
- debugInfo = "in list at depth "_L1 + QString::number(m_cursor->currentList()->format().indent());
+ if (m_cursor.currentList())
+ debugInfo = "in list at depth "_L1 + QString::number(m_cursor.currentList()->format().indent());
if (bfmt.hasProperty(QTextFormat::BlockQuoteLevel))
debugInfo += "in blockquote at depth "_L1 +
QString::number(bfmt.intProperty(QTextFormat::BlockQuoteLevel));
@@ -552,7 +573,7 @@ int QTextMarkdownImporter::cbText(int textType, const char *text, unsigned size)
Insert a new block based on stored state.
m_cursor cannot store the state for the _next_ block ahead of time, because
- m_cursor->setBlockFormat() controls the format of the block that the cursor
+ m_cursor.setBlockFormat() controls the format of the block that the cursor
is already in; so cbLeaveBlock() cannot call setBlockFormat() without
altering the block that was just added. Therefore cbLeaveBlock() and the
following cbEnterBlock() set variables to remember what formatting should
@@ -594,19 +615,19 @@ void QTextMarkdownImporter::insertBlock()
blockFormat.setMarker(m_markerType);
if (!m_listStack.isEmpty())
blockFormat.setIndent(m_listStack.size());
- if (m_doc->isEmpty()) {
- m_cursor->setBlockFormat(blockFormat);
- m_cursor->setCharFormat(charFormat);
+ if (m_cursor.document()->isEmpty()) {
+ m_cursor.setBlockFormat(blockFormat);
+ m_cursor.setCharFormat(charFormat);
} else if (m_listItem) {
- m_cursor->insertBlock(blockFormat, QTextCharFormat());
- m_cursor->setCharFormat(charFormat);
+ m_cursor.insertBlock(blockFormat, QTextCharFormat());
+ m_cursor.setCharFormat(charFormat);
} else {
- m_cursor->insertBlock(blockFormat, charFormat);
+ m_cursor.insertBlock(blockFormat, charFormat);
}
if (m_needsInsertList) {
- m_listStack.push(m_cursor->createList(m_listFormat));
+ m_listStack.push(m_cursor.createList(m_listFormat));
} else if (!m_listStack.isEmpty() && m_listItem && m_listStack.top()) {
- m_listStack.top()->add(m_cursor->block());
+ m_listStack.top()->add(m_cursor.block());
}
m_needsInsertList = false;
m_needsInsertBlock = false;
diff --git a/src/gui/text/qtextmarkdownimporter_p.h b/src/gui/text/qtextmarkdownimporter_p.h
index b7974da56e..8b8f4ec9bb 100644
--- a/src/gui/text/qtextmarkdownimporter_p.h
+++ b/src/gui/text/qtextmarkdownimporter_p.h
@@ -46,6 +46,7 @@ public:
FeaturePermissiveWWWAutoLinks = 0x0400,
FeatureTasklists = 0x0800,
FeatureUnderline = 0x4000,
+ FeatureFrontMatter = 0x100000, // Qt feature, not yet in MD4C
// composite flags
FeaturePermissiveAutoLinks = FeaturePermissiveMailAutoLinks
| FeaturePermissiveURLAutoLinks | FeaturePermissiveWWWAutoLinks,
@@ -55,10 +56,10 @@ public:
};
Q_DECLARE_FLAGS(Features, Feature)
- QTextMarkdownImporter(Features features);
- QTextMarkdownImporter(QTextDocument::MarkdownFeatures features);
+ QTextMarkdownImporter(QTextDocument *doc, Features features);
+ QTextMarkdownImporter(QTextDocument *doc, QTextDocument::MarkdownFeatures features);
- void import(QTextDocument *doc, const QString &markdown);
+ void import(const QString &markdown);
public:
// MD4C callbacks
@@ -72,8 +73,7 @@ private:
void insertBlock();
private:
- QTextDocument *m_doc = nullptr;
- QTextCursor *m_cursor = nullptr;
+ QTextCursor m_cursor;
QTextTable *m_currentTable = nullptr; // because m_cursor->currentTable() doesn't work
#if QT_CONFIG(regularexpression)
QString m_htmlAccumulator;
diff --git a/src/gui/text/qtextmarkdownwriter.cpp b/src/gui/text/qtextmarkdownwriter.cpp
index 5fb67ccc67..361158e722 100644
--- a/src/gui/text/qtextmarkdownwriter.cpp
+++ b/src/gui/text/qtextmarkdownwriter.cpp
@@ -10,7 +10,9 @@
#include "qtexttable.h"
#include "qtextcursor.h"
#include "qtextimagehandler_p.h"
+#include "qtextmarkdownimporter_p.h"
#include "qloggingcategory.h"
+#include <QtCore/QRegularExpression>
#if QT_CONFIG(itemmodel)
#include "qabstractitemmodel.h"
#endif
@@ -38,6 +40,7 @@ QTextMarkdownWriter::QTextMarkdownWriter(QTextStream &stream, QTextDocument::Mar
bool QTextMarkdownWriter::writeAll(const QTextDocument *document)
{
+ writeFrontMatter(document->metaInformation(QTextDocument::FrontMatter));
writeFrame(document->rootFrame());
return true;
}
@@ -76,6 +79,19 @@ void QTextMarkdownWriter::writeTable(const QAbstractItemModel *table)
}
#endif
+void QTextMarkdownWriter::writeFrontMatter(const QString &fm)
+{
+ const bool featureEnabled = m_features.testFlag(
+ static_cast<QTextDocument::MarkdownFeature>(QTextMarkdownImporter::FeatureFrontMatter));
+ qCDebug(lcMDW) << "writing FrontMatter?" << featureEnabled << "size" << fm.size();
+ if (fm.isEmpty() || !featureEnabled)
+ return;
+ m_stream << "---\n"_L1 << fm;
+ if (!fm.endsWith(qtmw_Newline))
+ m_stream << qtmw_Newline;
+ m_stream << "---\n"_L1;
+}
+
void QTextMarkdownWriter::writeFrame(const QTextFrame *frame)
{
Q_ASSERT(frame);
@@ -112,17 +128,22 @@ void QTextMarkdownWriter::writeFrame(const QTextFrame *frame)
// suppress needless blank lines, when there will be a big change in block format
bool nextIsDifferent = false;
bool ending = false;
+ int blockQuoteIndent = 0;
+ int nextBlockQuoteIndent = 0;
{
QTextFrame::iterator next = iterator;
++next;
+ QTextBlockFormat format = iterator.currentBlock().blockFormat();
+ QTextBlockFormat nextFormat = next.currentBlock().blockFormat();
+ blockQuoteIndent = format.intProperty(QTextFormat::BlockQuoteLevel);
+ nextBlockQuoteIndent = nextFormat.intProperty(QTextFormat::BlockQuoteLevel);
if (next.atEnd()) {
nextIsDifferent = true;
ending = true;
} else {
- QTextBlockFormat format = iterator.currentBlock().blockFormat();
- QTextBlockFormat nextFormat = next.currentBlock().blockFormat();
if (nextFormat.indent() != format.indent() ||
- nextFormat.property(QTextFormat::BlockCodeLanguage) != format.property(QTextFormat::BlockCodeLanguage))
+ nextFormat.property(QTextFormat::BlockCodeLanguage) !=
+ format.property(QTextFormat::BlockCodeLanguage))
nextIsDifferent = true;
}
}
@@ -139,8 +160,10 @@ void QTextMarkdownWriter::writeFrame(const QTextFrame *frame)
tableRow = cell.row();
}
} else if (!block.textList()) {
- if (lastWasList)
+ if (lastWasList) {
m_stream << qtmw_Newline;
+ m_linePrefixWritten = false;
+ }
}
int endingCol = writeBlock(block, !table, table && tableRow == 0,
nextIsDifferent && !block.textList());
@@ -164,8 +187,16 @@ void QTextMarkdownWriter::writeFrame(const QTextFrame *frame)
} else if (endingCol > 0) {
if (block.textList() || block.blockFormat().hasProperty(QTextFormat::BlockCodeLanguage)) {
m_stream << qtmw_Newline;
+ if (block.textList()) {
+ m_stream << m_linePrefix;
+ m_linePrefixWritten = true;
+ }
} else {
- m_stream << qtmw_Newline << qtmw_Newline;
+ m_stream << qtmw_Newline;
+ if (nextBlockQuoteIndent < blockQuoteIndent)
+ setLinePrefixForBlockQuote(nextBlockQuoteIndent);
+ m_stream << m_linePrefix;
+ m_stream << qtmw_Newline;
m_doubleNewlineWritten = true;
}
}
@@ -211,6 +242,16 @@ QTextMarkdownWriter::ListInfo QTextMarkdownWriter::listInfo(QTextList *list)
return m_listInfo.value(list);
}
+void QTextMarkdownWriter::setLinePrefixForBlockQuote(int level)
+{
+ m_linePrefix.clear();
+ if (level > 0) {
+ m_linePrefix.reserve(level * 2);
+ for (int i = 0; i < level; ++i)
+ m_linePrefix += u"> ";
+ }
+}
+
static int nearestWordWrapIndex(const QString &s, int before)
{
before = qMin(before, s.size());
@@ -248,15 +289,53 @@ static int adjacentBackticksCount(const QString &s)
return ret;
}
+/*! \internal
+ Escape anything at the beginning of a line of markdown that would be
+ misinterpreted by a markdown parser, including any period that follows a
+ number (to avoid misinterpretation as a numbered list item).
+ https://spec.commonmark.org/0.31.2/#backslash-escapes
+*/
static void maybeEscapeFirstChar(QString &s)
{
+ static const QRegularExpression numericListRe(uR"(\d+([\.)])\s)"_s);
+ static const QLatin1StringView specialFirstCharacters("#*+-");
+
QString sTrimmed = s.trimmed();
if (sTrimmed.isEmpty())
return;
- char firstChar = sTrimmed.at(0).toLatin1();
- if (firstChar == '*' || firstChar == '+' || firstChar == '-') {
- int i = s.indexOf(QLatin1Char(firstChar));
+ QChar firstChar = sTrimmed.at(0);
+ if (specialFirstCharacters.contains(firstChar)) {
+ int i = s.indexOf(firstChar); // == 0 unless s got trimmed
s.insert(i, u'\\');
+ } else {
+ auto match = numericListRe.match(s, 0, QRegularExpression::NormalMatch,
+ QRegularExpression::AnchorAtOffsetMatchOption);
+ if (match.hasMatch())
+ s.insert(match.capturedStart(1), qtmw_Backslash);
+ }
+}
+
+/*! \internal
+ Escape all backslashes. Then escape any special character that stands
+ alone or prefixes a "word", including the \c < that starts an HTML tag.
+ https://spec.commonmark.org/0.31.2/#backslash-escapes
+*/
+static void escapeSpecialCharacters(QString &s)
+{
+ static const QRegularExpression spaceRe(uR"(\s+)"_s);
+ static const QRegularExpression specialRe(uR"([<!*[`&]+[/\w])"_s);
+
+ s.replace("\\"_L1, "\\\\"_L1);
+
+ int i = 0;
+ while (i >= 0) {
+ if (int j = s.indexOf(specialRe, i); j >= 0) {
+ s.insert(j, qtmw_Backslash);
+ i = j + 3;
+ }
+ i = s.indexOf(spaceRe, i);
+ if (i >= 0)
+ ++i; // past the whitespace, if found
}
}
@@ -336,10 +415,20 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign
const bool codeBlock = blockFmt.hasProperty(QTextFormat::BlockCodeFence) ||
blockFmt.stringProperty(QTextFormat::BlockCodeLanguage).size() > 0 ||
blockFmt.nonBreakableLines();
+ const int blockQuoteLevel = blockFmt.intProperty(QTextFormat::BlockQuoteLevel);
if (m_fencedCodeBlock && !codeBlock) {
m_stream << m_linePrefix << m_codeBlockFence << qtmw_Newline;
m_fencedCodeBlock = false;
m_codeBlockFence.clear();
+ m_linePrefixWritten = m_linePrefix.size() > 0;
+ }
+ m_linePrefix.clear();
+ if (!blockFmt.headingLevel() && blockQuoteLevel > 0) {
+ setLinePrefixForBlockQuote(blockQuoteLevel);
+ if (!m_linePrefixWritten) {
+ m_stream << m_linePrefix;
+ m_linePrefixWritten = true;
+ }
}
if (block.textList()) { // it's a list-item
auto fmt = block.textList()->format();
@@ -416,31 +505,27 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign
if (blockFmt.hasProperty(QTextFormat::BlockIndent))
m_codeBlockFence = QString(m_wrappedLineIndent, qtmw_Space) + m_codeBlockFence;
// A block quote can contain an indented code block, but not vice-versa.
- m_stream << m_linePrefix << m_codeBlockFence
- << blockFmt.stringProperty(QTextFormat::BlockCodeLanguage) << qtmw_Newline;
+ m_stream << m_codeBlockFence << blockFmt.stringProperty(QTextFormat::BlockCodeLanguage)
+ << qtmw_Newline << m_linePrefix;
m_fencedCodeBlock = true;
}
wrap = false;
} else if (!blockFmt.indent()) {
m_wrappedLineIndent = 0;
- m_linePrefix.clear();
- if (blockFmt.hasProperty(QTextFormat::BlockQuoteLevel)) {
- int level = blockFmt.intProperty(QTextFormat::BlockQuoteLevel);
- QString quoteMarker = QStringLiteral("> ");
- m_linePrefix.reserve(level * 2);
- for (int i = 0; i < level; ++i)
- m_linePrefix += quoteMarker;
- }
if (blockFmt.hasProperty(QTextFormat::BlockCodeLanguage)) {
// A block quote can contain an indented code block, but not vice-versa.
m_linePrefix += QString(4, qtmw_Space);
m_indentedCodeBlock = true;
}
+ if (!m_linePrefixWritten) {
+ m_stream << m_linePrefix;
+ m_linePrefixWritten = true;
+ }
}
- if (blockFmt.headingLevel())
+ if (blockFmt.headingLevel()) {
m_stream << QByteArray(blockFmt.headingLevel(), '#') << ' ';
- else
- m_stream << m_linePrefix;
+ wrap = false;
+ }
QString wrapIndentString = m_linePrefix + QString(m_wrappedLineIndent, qtmw_Space);
// It would be convenient if QTextStream had a lineCharPos() accessor,
@@ -453,12 +538,17 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign
bool italic = false;
bool underline = false;
bool strikeOut = false;
+ bool endingMarkers = false;
QString backticks(qtmw_Backtick);
for (QTextBlock::Iterator frag = block.begin(); !frag.atEnd(); ++frag) {
missedBlankCodeBlockLine = false;
QString fragmentText = frag.fragment().text();
while (fragmentText.endsWith(qtmw_Newline))
fragmentText.chop(1);
+ if (!(m_fencedCodeBlock || m_indentedCodeBlock)) {
+ escapeSpecialCharacters(fragmentText);
+ maybeEscapeFirstChar(fragmentText);
+ }
if (block.textList()) { // <li>first line</br>continuation</li>
QString newlineIndent =
QString(qtmw_Newline) + QString(m_wrappedLineIndent, qtmw_Space);
@@ -520,26 +610,36 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign
if (startsOrEndsWithBacktick)
markers += qtmw_Space;
mono = monoFrag;
+ if (!mono)
+ endingMarkers = true;
}
if (!blockFmt.headingLevel() && !mono) {
if (fontInfo.bold() != bold) {
markers += "**"_L1;
bold = fontInfo.bold();
+ if (!bold)
+ endingMarkers = true;
}
if (fontInfo.italic() != italic) {
markers += u'*';
italic = fontInfo.italic();
+ if (!italic)
+ endingMarkers = true;
}
if (fontInfo.strikeOut() != strikeOut) {
markers += "~~"_L1;
strikeOut = fontInfo.strikeOut();
+ if (!strikeOut)
+ endingMarkers = true;
}
if (fontInfo.underline() != underline) {
- // Markdown doesn't support underline, but the parser will treat a single underline
- // the same as a single asterisk, and the marked fragment will be rendered in italics.
- // That will have to do.
+ // CommonMark specifies underline as another way to get emphasis (italics):
+ // https://spec.commonmark.org/0.31.2/#example-148
+ // but md4c allows us to distinguish them; so we support underlining (in GitHub dialect).
markers += u'_';
underline = fontInfo.underline();
+ if (!underline)
+ endingMarkers = true;
}
}
}
@@ -549,7 +649,8 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign
bool breakingLine = false;
while (i < fragLen) {
if (col >= ColumnLimit) {
- m_stream << qtmw_Newline << wrapIndentString;
+ m_stream << markers << qtmw_Newline << wrapIndentString;
+ markers.clear();
col = m_wrappedLineIndent;
while (i < fragLen && fragmentText[i].isSpace())
++i;
@@ -559,6 +660,13 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign
int wi = nearestWordWrapIndex(fragmentText, j);
if (wi < 0) {
j = fragLen;
+ // can't break within the fragment: we need to break already _before_ it
+ if (endingMarkers) {
+ m_stream << markers;
+ markers.clear();
+ }
+ m_stream << qtmw_Newline << wrapIndentString;
+ col = m_wrappedLineIndent;
} else if (wi >= i) {
j = wi;
breakingLine = true;
@@ -582,8 +690,12 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign
col += subfrag.size();
}
i = j + 1;
- }
+ } // loop over fragment characters (we know we need to break somewhere)
} else {
+ if (!m_linePrefixWritten && col == wrapIndentString.size()) {
+ m_stream << m_linePrefix;
+ col += m_linePrefix.size();
+ }
m_stream << markers << fragmentText;
col += markers.size() + fragmentText.size();
}
@@ -615,6 +727,7 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign
}
if (missedBlankCodeBlockLine)
m_stream << qtmw_Newline;
+ m_linePrefixWritten = false;
return col;
}
diff --git a/src/gui/text/qtextmarkdownwriter_p.h b/src/gui/text/qtextmarkdownwriter_p.h
index b940e37ddc..c0989b8f72 100644
--- a/src/gui/text/qtextmarkdownwriter_p.h
+++ b/src/gui/text/qtextmarkdownwriter_p.h
@@ -36,6 +36,7 @@ public:
int writeBlock(const QTextBlock &block, bool table, bool ignoreFormat, bool ignoreEmpty);
void writeFrame(const QTextFrame *frame);
+ void writeFrontMatter(const QString &fm);
private:
struct ListInfo {
@@ -43,6 +44,7 @@ private:
};
ListInfo listInfo(QTextList *list);
+ void setLinePrefixForBlockQuote(int level);
private:
QTextStream &m_stream;
@@ -53,6 +55,7 @@ private:
int m_wrappedLineIndent = 0;
int m_lastListIndent = 1;
bool m_doubleNewlineWritten = false;
+ bool m_linePrefixWritten = false;
bool m_indentedCodeBlock = false;
bool m_fencedCodeBlock = false;
};
diff --git a/src/gui/text/qtextobject.cpp b/src/gui/text/qtextobject.cpp
index f9452f43ad..6aafdc1a25 100644
--- a/src/gui/text/qtextobject.cpp
+++ b/src/gui/text/qtextobject.cpp
@@ -42,7 +42,7 @@ QT_BEGIN_NAMESPACE
objects, you will also need to reimplement QTextDocument::createObject()
which acts as a factory method for creating text objects.
- \sa QTextDocument, {Text Object Example}
+ \sa QTextDocument
*/
/*!
diff --git a/src/gui/text/qtextodfwriter.cpp b/src/gui/text/qtextodfwriter.cpp
index 546859037c..b50771c12f 100644
--- a/src/gui/text/qtextodfwriter.cpp
+++ b/src/gui/text/qtextodfwriter.cpp
@@ -18,9 +18,10 @@
#include "qtexttable.h"
#include "qtextcursor.h"
#include "qtextimagehandler_p.h"
-#include "qzipwriter_p.h"
#include <QDebug>
+#include <QtCore/private/qzipwriter_p.h>
+
QT_BEGIN_NAMESPACE
diff --git a/src/gui/text/qtextoption.cpp b/src/gui/text/qtextoption.cpp
index 3e5b5bc000..b6beadbe91 100644
--- a/src/gui/text/qtextoption.cpp
+++ b/src/gui/text/qtextoption.cpp
@@ -329,7 +329,7 @@ QList<QTextOption::Tab> QTextOption::tabs() const
*/
/*!
- \variable Tab::position
+ \variable QTextOption::Tab::position
Distance from the start of the paragraph.
The position of a tab is from the start of the paragraph which implies that when
the alignment of the paragraph is set to centered, the tab is interpreted to be
diff --git a/src/gui/text/unix/qfontconfigdatabase.cpp b/src/gui/text/unix/qfontconfigdatabase.cpp
index 474644b871..d607d38235 100644
--- a/src/gui/text/unix/qfontconfigdatabase.cpp
+++ b/src/gui/text/unix/qfontconfigdatabase.cpp
@@ -16,7 +16,6 @@
#include <qpa/qplatformservices.h>
#include <QtGui/private/qguiapplication_p.h>
-#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtGui/qguiapplication.h>
@@ -29,6 +28,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcFontDb)
+
static inline int mapToQtWeightForRange(int fcweight, int fcLower, int fcUpper, int qtLower, int qtUpper)
{
return qtLower + ((fcweight - fcLower) * (qtUpper - qtLower)) / (fcUpper - fcLower);
@@ -366,7 +367,10 @@ static inline bool requiresOpenType(int writingSystem)
|| writingSystem == QFontDatabase::Khmer || writingSystem == QFontDatabase::Nko);
}
-static void populateFromPattern(FcPattern *pattern, QFontDatabasePrivate::ApplicationFont *applicationFont = nullptr)
+static void populateFromPattern(FcPattern *pattern,
+ QFontDatabasePrivate::ApplicationFont *applicationFont = nullptr,
+ FT_Face face = nullptr,
+ QFontconfigDatabase *db = nullptr)
{
QString familyName;
QString familyNameLang;
@@ -489,6 +493,20 @@ static void populateFromPattern(FcPattern *pattern, QFontDatabasePrivate::Applic
}
QPlatformFontDatabase::registerFont(familyName,styleName,QLatin1StringView((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,fixedPitch,writingSystems,fontFile);
+ if (applicationFont != nullptr && face != nullptr && db != nullptr) {
+ db->addNamedInstancesForFace(face,
+ indexValue,
+ familyName,
+ styleName,
+ weight,
+ stretch,
+ style,
+ fixedPitch,
+ writingSystems,
+ QByteArray((const char*)file_value),
+ applicationFont->data);
+ }
+
// qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size;
for (int k = 1; FcPatternGetString(pattern, FC_FAMILY, k, &value) == FcResultMatch; ++k) {
@@ -528,6 +546,11 @@ static void populateFromPattern(FcPattern *pattern, QFontDatabasePrivate::Applic
}
+static bool isDprScaling()
+{
+ return !qFuzzyCompare(qApp->devicePixelRatio(), 1.0);
+}
+
QFontconfigDatabase::~QFontconfigDatabase()
{
FcConfigDestroy(FcConfigGetCurrent());
@@ -556,6 +579,12 @@ void QFontconfigDatabase::populateFontDatabase()
FcObjectSetAdd(os, *p);
++p;
}
+
+#ifdef FC_VARIABLE
+ /* Support the named instance of Variable Fonts. */
+ FcPatternAddBool(pattern, FC_VARIABLE, FcFalse);
+#endif
+
fonts = FcFontList(nullptr, pattern, os);
FcObjectSetDestroy(os);
FcPatternDestroy(pattern);
@@ -613,7 +642,7 @@ QFontEngineMulti *QFontconfigDatabase::fontEngineMulti(QFontEngine *fontEngine,
}
namespace {
-QFontEngine::HintStyle defaultHintStyleFromMatch(QFont::HintingPreference hintingPreference, FcPattern *match, bool useXftConf)
+QFontEngine::HintStyle defaultHintStyleFromMatch(QFont::HintingPreference hintingPreference, FcPattern *match, bool preferXftConf)
{
switch (hintingPreference) {
case QFont::PreferNoHinting:
@@ -626,9 +655,16 @@ QFontEngine::HintStyle defaultHintStyleFromMatch(QFont::HintingPreference hintin
break;
}
- if (QHighDpiScaling::isActive())
+ if (isDprScaling())
return QFontEngine::HintNone;
+ void *hintStyleResource =
+ QGuiApplication::platformNativeInterface()->nativeResourceForScreen("hintstyle",
+ QGuiApplication::primaryScreen());
+ int xftHintStyle = int(reinterpret_cast<qintptr>(hintStyleResource));
+ if (preferXftConf && xftHintStyle > 0)
+ return QFontEngine::HintStyle(xftHintStyle - 1);
+
int hint_style = 0;
if (FcPatternGetInteger (match, FC_HINT_STYLE, 0, &hint_style) == FcResultMatch) {
switch (hint_style) {
@@ -645,21 +681,21 @@ QFontEngine::HintStyle defaultHintStyleFromMatch(QFont::HintingPreference hintin
break;
}
}
-
- if (useXftConf) {
- void *hintStyleResource =
- QGuiApplication::platformNativeInterface()->nativeResourceForScreen("hintstyle",
- QGuiApplication::primaryScreen());
- int hintStyle = int(reinterpret_cast<qintptr>(hintStyleResource));
- if (hintStyle > 0)
- return QFontEngine::HintStyle(hintStyle - 1);
- }
+ if (xftHintStyle > 0)
+ return QFontEngine::HintStyle(xftHintStyle - 1);
return QFontEngine::HintFull;
}
-QFontEngine::SubpixelAntialiasingType subpixelTypeFromMatch(FcPattern *match, bool useXftConf)
+QFontEngine::SubpixelAntialiasingType subpixelTypeFromMatch(FcPattern *match, bool preferXftConf)
{
+ void *subpixelTypeResource =
+ QGuiApplication::platformNativeInterface()->nativeResourceForScreen("subpixeltype",
+ QGuiApplication::primaryScreen());
+ int xftSubpixelType = int(reinterpret_cast<qintptr>(subpixelTypeResource));
+ if (preferXftConf && xftSubpixelType > 0)
+ return QFontEngine::SubpixelAntialiasingType(xftSubpixelType - 1);
+
int subpixel = FC_RGBA_UNKNOWN;
if (FcPatternGetInteger(match, FC_RGBA, 0, &subpixel) == FcResultMatch) {
switch (subpixel) {
@@ -680,14 +716,8 @@ QFontEngine::SubpixelAntialiasingType subpixelTypeFromMatch(FcPattern *match, bo
}
}
- if (useXftConf) {
- void *subpixelTypeResource =
- QGuiApplication::platformNativeInterface()->nativeResourceForScreen("subpixeltype",
- QGuiApplication::primaryScreen());
- int subpixelType = int(reinterpret_cast<qintptr>(subpixelTypeResource));
- if (subpixelType > 0)
- return QFontEngine::SubpixelAntialiasingType(subpixelType - 1);
- }
+ if (xftSubpixelType > 0)
+ return QFontEngine::SubpixelAntialiasingType(xftSubpixelType - 1);
return QFontEngine::Subpixel_None;
}
@@ -702,6 +732,8 @@ QFontEngine *QFontconfigDatabase::fontEngine(const QFontDef &f, void *usrPtr)
QFontEngine::FaceId fid;
fid.filename = QFile::encodeName(fontfile->fileName);
fid.index = fontfile->indexValue;
+ fid.instanceIndex = fontfile->instanceIndex;
+ fid.variableAxes = f.variableAxisValues;
// FIXME: Unify with logic in QFontEngineFT::create()
QFontEngineFT *engine = new QFontEngineFT(f);
@@ -803,26 +835,28 @@ QStringList QFontconfigDatabase::fallbacksForFamily(const QString &family, QFont
return fallbackFamilies;
}
-static FcPattern *queryFont(const FcChar8 *file, const QByteArray &data, int id, FcBlanks *blanks, int *count)
+static FcPattern *queryFont(const FcChar8 *file, const QByteArray &data, int id, FcBlanks *blanks, int *count, FT_Face *face)
{
#if FC_VERSION < 20402
Q_UNUSED(data);
+ *face = nullptr;
return FcFreeTypeQuery(file, id, blanks, count);
#else
- if (data.isEmpty())
+ if (data.isEmpty()) {
+ *face = nullptr;
return FcFreeTypeQuery(file, id, blanks, count);
+ }
FT_Library lib = qt_getFreetype();
FcPattern *pattern = nullptr;
- FT_Face face;
- if (!FT_New_Memory_Face(lib, (const FT_Byte *)data.constData(), data.size(), id, &face)) {
- *count = face->num_faces;
-
- pattern = FcFreeTypeQueryFace(face, file, id, blanks);
+ if (!FT_New_Memory_Face(lib, (const FT_Byte *)data.constData(), data.size(), id, face)) {
+ *count = (*face)->num_faces;
- FT_Done_Face(face);
+ pattern = FcFreeTypeQueryFace(*face, file, id, blanks);
+ } else {
+ *face = nullptr;
}
return pattern;
@@ -850,8 +884,9 @@ QStringList QFontconfigDatabase::addApplicationFont(const QByteArray &fontData,
FcPattern *pattern;
do {
+ FT_Face face;
pattern = queryFont((const FcChar8 *)QFile::encodeName(fileName).constData(),
- fontData, id, blanks, &count);
+ fontData, id, blanks, &count, &face);
if (!pattern)
return families;
@@ -860,7 +895,10 @@ QStringList QFontconfigDatabase::addApplicationFont(const QByteArray &fontData,
QString family = QString::fromUtf8(reinterpret_cast<const char *>(fam));
families << family;
}
- populateFromPattern(pattern, applicationFont);
+ populateFromPattern(pattern, applicationFont, face, this);
+
+ if (face)
+ FT_Done_Face(face);
FcFontSetAdd(set, pattern);
@@ -925,28 +963,20 @@ QFont QFontconfigDatabase::defaultFont() const
void QFontconfigDatabase::setupFontEngine(QFontEngineFT *engine, const QFontDef &fontDef) const
{
bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias);
- bool forcedAntialiasSetting = !antialias || QHighDpiScaling::isActive();
+ bool forcedAntialiasSetting = !antialias || isDprScaling();
const QPlatformServices *services = QGuiApplicationPrivate::platformIntegration()->services();
- bool useXftConf = false;
+ bool preferXftConf = false;
if (services) {
const QList<QByteArray> desktopEnv = services->desktopEnvironment().split(':');
- useXftConf = desktopEnv.contains("GNOME") || desktopEnv.contains("UNITY") || desktopEnv.contains("XFCE");
- }
-
- if (useXftConf && !forcedAntialiasSetting) {
- void *antialiasResource =
- QGuiApplication::platformNativeInterface()->nativeResourceForScreen("antialiasingEnabled",
- QGuiApplication::primaryScreen());
- int antialiasingEnabled = int(reinterpret_cast<qintptr>(antialiasResource));
- if (antialiasingEnabled > 0)
- antialias = antialiasingEnabled - 1;
+ preferXftConf = !(desktopEnv.contains("KDE") || desktopEnv.contains("LXQT") || desktopEnv.contains("UKUI"));
}
QFontEngine::GlyphFormat format;
// try and get the pattern
FcPattern *pattern = FcPatternCreate();
+ FcPattern *match = nullptr;
FcValue value;
value.type = FcTypeString;
@@ -965,7 +995,7 @@ void QFontconfigDatabase::setupFontEngine(QFontEngineFT *engine, const QFontDef
FcPatternAdd(pattern,FC_INDEX,value,true);
}
- if (fontDef.pixelSize > 0.1)
+ if (!qFuzzyIsNull(fontDef.pixelSize))
FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontDef.pixelSize);
FcResult result;
@@ -973,9 +1003,68 @@ void QFontconfigDatabase::setupFontEngine(QFontEngineFT *engine, const QFontDef
FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
FcDefaultSubstitute(pattern);
- FcPattern *match = FcFontMatch(nullptr, pattern, &result);
+#ifdef FC_VARIABLE
+ if (!fid.filename.isEmpty()) {
+ // FC_INDEX is ignored during processing in FcFontMatch.
+ // So iterate FcPatterns directly and find it out.
+ FcFontSet *fcsets[2], *fcfs;
+
+ fcsets[0] = FcConfigGetFonts(nullptr, FcSetSystem);
+ fcsets[1] = FcConfigGetFonts(nullptr, FcSetApplication);
+ for (int nset = 0; nset < 2; nset++) {
+ fcfs = fcsets[nset];
+ if (fcfs == nullptr)
+ continue;
+ for (int fnum = 0; fnum < fcfs->nfont; fnum++) {
+ FcPattern *fcpat = fcfs->fonts[fnum];
+ FcChar8 *fcfile;
+ FcBool variable;
+ double fcpixelsize;
+ int fcindex;
+
+ // Skip the variable font itself, only to use the named instances and normal fonts here
+ if (FcPatternGetBool(fcpat, FC_VARIABLE, 0, &variable) == FcResultMatch &&
+ variable == FcTrue)
+ continue;
+
+ if (!qFuzzyIsNull(fontDef.pixelSize)) {
+ if (FcPatternGetDouble(fcpat, FC_PIXEL_SIZE, 0, &fcpixelsize) == FcResultMatch &&
+ fontDef.pixelSize != fcpixelsize)
+ continue;
+ }
+
+ if (FcPatternGetString(fcpat, FC_FILE, 0, &fcfile) == FcResultMatch &&
+ FcPatternGetInteger(fcpat, FC_INDEX, 0, &fcindex) == FcResultMatch) {
+ QByteArray f = QByteArray::fromRawData((const char *)fcfile,
+ qstrlen((const char *)fcfile));
+ if (f == fid.filename && fcindex == fid.index) {
+ // We found it.
+ match = FcFontRenderPrepare(nullptr, pattern, fcpat);
+ goto bail;
+ }
+ }
+ }
+ }
+ }
+bail:
+#endif
+
+ if (!match)
+ match = FcFontMatch(nullptr, pattern, &result);
+
+ int xftAntialias = 0;
+ if (!forcedAntialiasSetting) {
+ void *antialiasResource =
+ QGuiApplication::platformNativeInterface()->nativeResourceForScreen("antialiasingEnabled",
+ QGuiApplication::primaryScreen());
+ xftAntialias = int(reinterpret_cast<qintptr>(antialiasResource));
+ if ((preferXftConf || !match) && xftAntialias > 0) {
+ antialias = xftAntialias - 1;
+ forcedAntialiasSetting = true;
+ }
+ }
if (match) {
- engine->setDefaultHintStyle(defaultHintStyleFromMatch((QFont::HintingPreference)fontDef.hintingPreference, match, useXftConf));
+ engine->setDefaultHintStyle(defaultHintStyleFromMatch((QFont::HintingPreference)fontDef.hintingPreference, match, preferXftConf));
FcBool fc_autohint;
if (FcPatternGetBool(match, FC_AUTOHINT,0, &fc_autohint) == FcResultMatch)
@@ -996,18 +1085,37 @@ void QFontconfigDatabase::setupFontEngine(QFontEngineFT *engine, const QFontDef
if (antialias) {
QFontEngine::SubpixelAntialiasingType subpixelType = QFontEngine::Subpixel_None;
if (!(fontDef.styleStrategy & QFont::NoSubpixelAntialias))
- subpixelType = subpixelTypeFromMatch(match, useXftConf);
+ subpixelType = subpixelTypeFromMatch(match, preferXftConf);
engine->subpixelType = subpixelType;
-
- format = (subpixelType == QFontEngine::Subpixel_None)
- ? QFontEngine::Format_A8
- : QFontEngine::Format_A32;
- } else
- format = QFontEngine::Format_Mono;
+ }
FcPatternDestroy(match);
- } else
- format = antialias ? QFontEngine::Format_A8 : QFontEngine::Format_Mono;
+ } else {
+ void *hintStyleResource =
+ QGuiApplication::platformNativeInterface()->nativeResourceForScreen("hintstyle",
+ QGuiApplication::primaryScreen());
+ int xftHintStyle = int(reinterpret_cast<qintptr>(hintStyleResource));
+ if (xftHintStyle > 0)
+ engine->setDefaultHintStyle(QFontEngine::HintStyle(xftHintStyle - 1));
+ if (antialias) {
+ engine->subpixelType = QFontEngine::Subpixel_None;
+ if (!(fontDef.styleStrategy & QFont::NoSubpixelAntialias)) {
+ void *subpixelTypeResource =
+ QGuiApplication::platformNativeInterface()->nativeResourceForScreen("subpixeltype",
+ QGuiApplication::primaryScreen());
+ int xftSubpixelType = int(reinterpret_cast<qintptr>(subpixelTypeResource));
+ if (xftSubpixelType > 1)
+ engine->subpixelType = QFontEngine::SubpixelAntialiasingType(xftSubpixelType - 1);
+ }
+ }
+ }
+ if (antialias) {
+ format = (engine->subpixelType == QFontEngine::Subpixel_None)
+ ? QFontEngine::Format_A8
+ : QFontEngine::Format_A32;
+ } else {
+ format = QFontEngine::Format_Mono;
+ }
FcPatternDestroy(pattern);
@@ -1016,4 +1124,13 @@ void QFontconfigDatabase::setupFontEngine(QFontEngineFT *engine, const QFontDef
engine->glyphFormat = format;
}
+bool QFontconfigDatabase::supportsVariableApplicationFonts() const
+{
+#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 20900
+ return true;
+#else
+ return false;
+#endif
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/text/unix/qfontconfigdatabase_p.h b/src/gui/text/unix/qfontconfigdatabase_p.h
index cf15306e40..dd7a70a375 100644
--- a/src/gui/text/unix/qfontconfigdatabase_p.h
+++ b/src/gui/text/unix/qfontconfigdatabase_p.h
@@ -28,6 +28,7 @@ public:
~QFontconfigDatabase() override;
void populateFontDatabase() override;
void invalidate() override;
+ bool supportsVariableApplicationFonts() const override;
QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QChar::Script script) override;
QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override;
QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override;
diff --git a/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp b/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp
index 6b4933cca7..2e15fbb1ac 100644
--- a/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp
+++ b/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp
@@ -18,6 +18,32 @@ QT_BEGIN_NAMESPACE
// Defined in gui/text/qfontdatabase.cpp
Q_GUI_EXPORT QFontDatabase::WritingSystem qt_writing_system_for_script(int script);
+template<typename T>
+struct DirectWriteScope {
+ DirectWriteScope(T *res = nullptr) : m_res(res) {}
+ ~DirectWriteScope() {
+ if (m_res != nullptr)
+ m_res->Release();
+ }
+
+ T **operator&()
+ {
+ return &m_res;
+ }
+
+ T *operator->()
+ {
+ return m_res;
+ }
+
+ T *operator*() {
+ return m_res;
+ }
+
+private:
+ T *m_res;
+};
+
QWindowsDirectWriteFontDatabase::QWindowsDirectWriteFontDatabase()
{
qCDebug(lcQpaFonts) << "Creating DirectWrite database";
@@ -80,6 +106,12 @@ static QFont::Style fromDirectWriteStyle(DWRITE_FONT_STYLE style)
void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName)
{
auto it = m_populatedFonts.find(familyName);
+ if (it == m_populatedFonts.end() && m_populatedBitmapFonts.contains(familyName)) {
+ qCDebug(lcQpaFonts) << "Populating bitmap font" << familyName;
+ QWindowsFontDatabase::populateFamily(familyName);
+ return;
+ }
+
IDWriteFontFamily *fontFamily = it != m_populatedFonts.end() ? it.value() : nullptr;
if (fontFamily == nullptr) {
qCWarning(lcQpaFonts) << "Cannot find" << familyName << "in list of fonts";
@@ -98,7 +130,7 @@ void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName)
const bool antialias = false;
const int size = SMOOTH_SCALABLE;
- IDWriteFontList *matchingFonts;
+ DirectWriteScope<IDWriteFontList> matchingFonts;
if (SUCCEEDED(fontFamily->GetMatchingFonts(DWRITE_FONT_WEIGHT_REGULAR,
DWRITE_FONT_STRETCH_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
@@ -106,7 +138,7 @@ void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName)
for (uint j = 0; j < matchingFonts->GetFontCount(); ++j) {
IDWriteFont *font;
if (SUCCEEDED(matchingFonts->GetFont(j, &font))) {
- IDWriteFont1 *font1 = nullptr;
+ DirectWriteScope<IDWriteFont1> font1;
if (!SUCCEEDED(font->QueryInterface(__uuidof(IDWriteFont1),
reinterpret_cast<void **>(&font1)))) {
qCWarning(lcQpaFonts) << "COM object does not support IDWriteFont1";
@@ -116,27 +148,23 @@ void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName)
QString defaultLocaleFamilyName;
QString englishLocaleFamilyName;
- IDWriteFontFamily *fontFamily2;
+ DirectWriteScope<IDWriteFontFamily> fontFamily2;
if (SUCCEEDED(font1->GetFontFamily(&fontFamily2))) {
- IDWriteLocalizedStrings *names;
+ DirectWriteScope<IDWriteLocalizedStrings> names;
if (SUCCEEDED(fontFamily2->GetFamilyNames(&names))) {
- defaultLocaleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
- englishLocaleFamilyName = localeString(names, englishLocale);
-
- names->Release();
+ defaultLocaleFamilyName = hasDefaultLocale ? localeString(*names, defaultLocale) : QString();
+ englishLocaleFamilyName = localeString(*names, englishLocale);
}
-
- fontFamily2->Release();
}
if (defaultLocaleFamilyName.isEmpty() && englishLocaleFamilyName.isEmpty())
englishLocaleFamilyName = familyName;
{
- IDWriteLocalizedStrings *names;
+ DirectWriteScope<IDWriteLocalizedStrings> names;
if (SUCCEEDED(font1->GetFaceNames(&names))) {
- QString defaultLocaleStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
- QString englishLocaleStyleName = localeString(names, englishLocale);
+ QString defaultLocaleStyleName = hasDefaultLocale ? localeString(*names, defaultLocale) : QString();
+ QString englishLocaleStyleName = localeString(*names, englishLocale);
QFont::Stretch stretch = fromDirectWriteStretch(font1->GetStretch());
QFont::Style style = fromDirectWriteStyle(font1->GetStyle());
@@ -145,77 +173,233 @@ void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName)
qCDebug(lcQpaFonts) << "Family" << familyName << "has english variant" << englishLocaleStyleName << ", in default locale:" << defaultLocaleStyleName << stretch << style << weight << fixed;
- IDWriteFontFace *face = nullptr;
+ DirectWriteScope<IDWriteFontFace> face;
if (SUCCEEDED(font->CreateFontFace(&face))) {
- QSupportedWritingSystems writingSystems;
-
- const void *tableData = nullptr;
- UINT32 tableSize;
- void *tableContext = nullptr;
- BOOL exists;
- HRESULT hr = face->TryGetFontTable(qbswap<quint32>(MAKE_TAG('O','S','/','2')),
- &tableData,
- &tableSize,
- &tableContext,
- &exists);
- if (SUCCEEDED(hr) && exists) {
- writingSystems = QPlatformFontDatabase::writingSystemsFromOS2Table(reinterpret_cast<const char *>(tableData), tableSize);
- } else { // Fall back to checking first character of each Unicode range in font (may include too many writing systems)
- quint32 rangeCount;
- hr = font1->GetUnicodeRanges(0, nullptr, &rangeCount);
-
- if (rangeCount > 0) {
- QVarLengthArray<DWRITE_UNICODE_RANGE, QChar::ScriptCount> ranges(rangeCount);
-
- hr = font1->GetUnicodeRanges(rangeCount, ranges.data(), &rangeCount);
- if (SUCCEEDED(hr)) {
- for (uint i = 0; i < rangeCount; ++i) {
- QChar::Script script = QChar::script(ranges.at(i).first);
-
- QFontDatabase::WritingSystem writingSystem = qt_writing_system_for_script(script);
-
- if (writingSystem > QFontDatabase::Any && writingSystem < QFontDatabase::WritingSystemsCount)
- writingSystems.setSupported(writingSystem);
- }
- } else {
- const QString errorString = qt_error_string(int(hr));
- qCWarning(lcQpaFonts) << "Failed to get unicode ranges for font" << englishLocaleFamilyName << englishLocaleStyleName << ":" << errorString;
- }
- }
- }
+ QSupportedWritingSystems writingSystems = supportedWritingSystems(*face);
if (!englishLocaleStyleName.isEmpty() || defaultLocaleStyleName.isEmpty()) {
qCDebug(lcQpaFonts) << "Font" << englishLocaleFamilyName << englishLocaleStyleName << "supports writing systems:" << writingSystems;
- QPlatformFontDatabase::registerFont(englishLocaleFamilyName, englishLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face);
- face->AddRef();
+ QPlatformFontDatabase::registerFont(englishLocaleFamilyName,
+ englishLocaleStyleName,
+ QString(),
+ weight,
+ style,
+ stretch,
+ antialias,
+ scalable,
+ size,
+ fixed,
+ writingSystems,
+ new FontHandle(*face, englishLocaleFamilyName));
}
if (!defaultLocaleFamilyName.isEmpty() && defaultLocaleFamilyName != englishLocaleFamilyName) {
- QPlatformFontDatabase::registerFont(defaultLocaleFamilyName, defaultLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face);
- face->AddRef();
+ QPlatformFontDatabase::registerFont(defaultLocaleFamilyName,
+ defaultLocaleStyleName,
+ QString(),
+ weight,
+ style,
+ stretch,
+ antialias,
+ scalable,
+ size,
+ fixed,
+ writingSystems,
+ new FontHandle(*face, defaultLocaleFamilyName));
}
-
- face->Release();
}
-
- names->Release();
}
}
+ }
+ }
+ }
+}
- font1->Release();
- font->Release();
+QSupportedWritingSystems QWindowsDirectWriteFontDatabase::supportedWritingSystems(IDWriteFontFace *face) const
+{
+ QSupportedWritingSystems writingSystems;
+ writingSystems.setSupported(QFontDatabase::Any);
+
+ DirectWriteScope<IDWriteFontFace1> face1;
+ if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace1),
+ reinterpret_cast<void **>(&face1)))) {
+ const void *tableData = nullptr;
+ UINT32 tableSize;
+ void *tableContext = nullptr;
+ BOOL exists;
+ HRESULT hr = face->TryGetFontTable(qFromBigEndian(QFont::Tag("OS/2").value()),
+ &tableData,
+ &tableSize,
+ &tableContext,
+ &exists);
+ if (SUCCEEDED(hr) && exists) {
+ writingSystems = QPlatformFontDatabase::writingSystemsFromOS2Table(reinterpret_cast<const char *>(tableData), tableSize);
+ } else { // Fall back to checking first character of each Unicode range in font (may include too many writing systems)
+ quint32 rangeCount;
+ hr = face1->GetUnicodeRanges(0, nullptr, &rangeCount);
+
+ if (rangeCount > 0) {
+ QVarLengthArray<DWRITE_UNICODE_RANGE, QChar::ScriptCount> ranges(rangeCount);
+
+ hr = face1->GetUnicodeRanges(rangeCount, ranges.data(), &rangeCount);
+ if (SUCCEEDED(hr)) {
+ for (uint i = 0; i < rangeCount; ++i) {
+ QChar::Script script = QChar::script(ranges.at(i).first);
+
+ QFontDatabase::WritingSystem writingSystem = qt_writing_system_for_script(script);
+
+ if (writingSystem > QFontDatabase::Any && writingSystem < QFontDatabase::WritingSystemsCount)
+ writingSystems.setSupported(writingSystem);
+ }
+ } else {
+ const QString errorString = qt_error_string(int(hr));
+ qCWarning(lcQpaFonts) << "Failed to get unicode ranges for font:" << errorString;
+ }
}
}
+ }
+
+ return writingSystems;
+}
+
+bool QWindowsDirectWriteFontDatabase::populateFamilyAliases(const QString &missingFamily)
+{
+ // If the font has not been populated, it is possible this is a legacy font family supported
+ // by GDI. We make an attempt at loading it via GDI and then add this face directly to the
+ // database.
+ if (!missingFamily.isEmpty()
+ && missingFamily.size() < LF_FACESIZE
+ && !m_populatedFonts.contains(missingFamily)
+ && !m_populatedBitmapFonts.contains(missingFamily)) {
+ qCDebug(lcQpaFonts) << "Loading unpopulated" << missingFamily << ". Trying GDI.";
+
+ LOGFONT lf;
+ memset(&lf, 0, sizeof(LOGFONT));
+ memcpy(lf.lfFaceName, missingFamily.utf16(), missingFamily.size() * sizeof(wchar_t));
+
+ HFONT hfont = CreateFontIndirect(&lf);
+ if (hfont) {
+ HDC dummy = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(dummy, hfont);
+
+ DirectWriteScope<IDWriteFontFace> directWriteFontFace;
+ if (SUCCEEDED(data()->directWriteGdiInterop->CreateFontFaceFromHdc(dummy, &directWriteFontFace))) {
+ DirectWriteScope<IDWriteFontCollection> fontCollection;
+ if (SUCCEEDED(data()->directWriteFactory->GetSystemFontCollection(&fontCollection))) {
+ DirectWriteScope<IDWriteFont> font;
+ if (SUCCEEDED(fontCollection->GetFontFromFontFace(*directWriteFontFace, &font))) {
+
+ DirectWriteScope<IDWriteFont1> font1;
+ if (SUCCEEDED(font->QueryInterface(__uuidof(IDWriteFont1),
+ reinterpret_cast<void **>(&font1)))) {
+ DirectWriteScope<IDWriteLocalizedStrings> names;
+ if (SUCCEEDED(font1->GetFaceNames(&names))) {
+ wchar_t englishLocale[] = L"en-us";
+ QString englishLocaleStyleName = localeString(*names, englishLocale);
+
+ QFont::Stretch stretch = fromDirectWriteStretch(font1->GetStretch());
+ QFont::Style style = fromDirectWriteStyle(font1->GetStyle());
+ QFont::Weight weight = fromDirectWriteWeight(font1->GetWeight());
+ bool fixed = font1->IsMonospacedFont();
+
+ QSupportedWritingSystems writingSystems = supportedWritingSystems(*directWriteFontFace);
+
+ qCDebug(lcQpaFonts) << "Registering legacy font family" << missingFamily;
+ QPlatformFontDatabase::registerFont(missingFamily,
+ englishLocaleStyleName,
+ QString(),
+ weight,
+ style,
+ stretch,
+ false,
+ true,
+ 0xffff,
+ fixed,
+ writingSystems,
+ new FontHandle(*directWriteFontFace, missingFamily));
+
+ SelectObject(dummy, oldFont);
+ DeleteObject(hfont);
+
+ return true;
+ }
+ }
+ }
+ }
+ }
- matchingFonts->Release();
+ SelectObject(dummy, oldFont);
+ DeleteObject(hfont);
+ }
}
+
+ // Skip over implementation in QWindowsFontDatabase
+ return QWindowsFontDatabaseBase::populateFamilyAliases(missingFamily);
+}
+
+QFontEngine *QWindowsDirectWriteFontDatabase::fontEngine(const QByteArray &fontData,
+ qreal pixelSize,
+ QFont::HintingPreference hintingPreference)
+{
+ // Skip over implementation in QWindowsFontDatabase
+ return QWindowsFontDatabaseBase::fontEngine(fontData, pixelSize, hintingPreference);
}
QFontEngine *QWindowsDirectWriteFontDatabase::fontEngine(const QFontDef &fontDef, void *handle)
{
- IDWriteFontFace *face = reinterpret_cast<IDWriteFontFace *>(handle);
- Q_ASSERT(face != nullptr);
+ const FontHandle *fontHandle = static_cast<const FontHandle *>(handle);
+ IDWriteFontFace *face = fontHandle->fontFace;
+ if (face == nullptr) {
+ qCDebug(lcQpaFonts) << "Falling back to GDI";
+ return QWindowsFontDatabase::fontEngine(fontDef, handle);
+ }
+
+ DWRITE_FONT_SIMULATIONS simulations = DWRITE_FONT_SIMULATIONS_NONE;
+ if (fontDef.weight >= QFont::DemiBold || fontDef.style != QFont::StyleNormal) {
+ DirectWriteScope<IDWriteFontFace3> face3;
+ if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace3),
+ reinterpret_cast<void **>(&face3)))) {
+ if (fontDef.weight >= QFont::DemiBold && face3->GetWeight() < DWRITE_FONT_WEIGHT_DEMI_BOLD)
+ simulations |= DWRITE_FONT_SIMULATIONS_BOLD;
+
+ if (fontDef.style != QFont::StyleNormal && face3->GetStyle() == DWRITE_FONT_STYLE_NORMAL)
+ simulations |= DWRITE_FONT_SIMULATIONS_OBLIQUE;
+ }
+ }
+
+ DirectWriteScope<IDWriteFontFace5> newFace;
+ if (!fontDef.variableAxisValues.isEmpty() || simulations != DWRITE_FONT_SIMULATIONS_NONE) {
+ DirectWriteScope<IDWriteFontFace5> face5;
+ if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace5),
+ reinterpret_cast<void **>(&face5)))) {
+ DirectWriteScope<IDWriteFontResource> font;
+ if (SUCCEEDED(face5->GetFontResource(&font))) {
+ UINT32 fontAxisCount = font->GetFontAxisCount();
+ QVarLengthArray<DWRITE_FONT_AXIS_VALUE, 8> fontAxisValues(fontAxisCount);
+
+ if (!fontDef.variableAxisValues.isEmpty()) {
+ if (SUCCEEDED(face5->GetFontAxisValues(fontAxisValues.data(), fontAxisCount))) {
+ for (UINT32 i = 0; i < fontAxisCount; ++i) {
+ if (auto maybeTag = QFont::Tag::fromValue(qToBigEndian<UINT32>(fontAxisValues[i].axisTag))) {
+ if (fontDef.variableAxisValues.contains(*maybeTag))
+ fontAxisValues[i].value = fontDef.variableAxisValues.value(*maybeTag);
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(font->CreateFontFace(simulations,
+ !fontDef.variableAxisValues.isEmpty() ? fontAxisValues.data() : nullptr,
+ !fontDef.variableAxisValues.isEmpty() ? fontAxisCount : 0,
+ &newFace))) {
+ face = *newFace;
+ } else {
+ qCWarning(lcQpaFonts) << "DirectWrite: Can't create font face for variable axis values";
+ }
+ }
+ }
+ }
QWindowsFontEngineDirectWrite *fontEngine = new QWindowsFontEngineDirectWrite(face, fontDef.pixelSize, data());
fontEngine->initFontInfo(fontDef, defaultVerticalDPI());
@@ -249,111 +433,255 @@ QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray
loadedData = file.readAll();
}
- IDWriteFontFace *face = createDirectWriteFace(loadedData);
- if (face == nullptr) {
+ QList<IDWriteFontFace *> faces = createDirectWriteFaces(loadedData);
+ if (faces.isEmpty()) {
qCWarning(lcQpaFonts) << "Failed to create DirectWrite face from font data. Font may be unsupported.";
return QStringList();
}
- wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH];
- bool hasDefaultLocale = GetUserDefaultLocaleName(defaultLocale, LOCALE_NAME_MAX_LENGTH) != 0;
- wchar_t englishLocale[] = L"en-us";
+ QSet<QString> ret;
+ for (int i = 0; i < faces.size(); ++i) {
+ IDWriteFontFace *face = faces.at(i);
+ wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH];
+ bool hasDefaultLocale = GetUserDefaultLocaleName(defaultLocale, LOCALE_NAME_MAX_LENGTH) != 0;
+ wchar_t englishLocale[] = L"en-us";
+
+ static const int SMOOTH_SCALABLE = 0xffff;
+ const bool scalable = true;
+ const bool antialias = false;
+ const int size = SMOOTH_SCALABLE;
+
+ QSupportedWritingSystems writingSystems = supportedWritingSystems(face);
+ DirectWriteScope<IDWriteFontFace3> face3;
+ if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace3),
+ reinterpret_cast<void **>(&face3)))) {
+ QString defaultLocaleFamilyName;
+ QString englishLocaleFamilyName;
+
+ IDWriteLocalizedStrings *names = nullptr;
+ if (SUCCEEDED(face3->GetFamilyNames(&names))) {
+ defaultLocaleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
+ englishLocaleFamilyName = localeString(names, englishLocale);
+
+ names->Release();
+ }
- static const int SMOOTH_SCALABLE = 0xffff;
- const QString foundryName; // No such concept.
- const bool scalable = true;
- const bool antialias = false;
- const int size = SMOOTH_SCALABLE;
+ QString defaultLocaleStyleName;
+ QString englishLocaleStyleName;
+ if (SUCCEEDED(face3->GetFaceNames(&names))) {
+ defaultLocaleStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
+ englishLocaleStyleName = localeString(names, englishLocale);
- QSupportedWritingSystems writingSystems;
- writingSystems.setSupported(QFontDatabase::Any);
- writingSystems.setSupported(QFontDatabase::Latin);
+ names->Release();
+ }
- QStringList ret;
- IDWriteFontFace3 *face3 = nullptr;
- if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace3),
- reinterpret_cast<void **>(&face3)))) {
- QString defaultLocaleFamilyName;
- QString englishLocaleFamilyName;
+ BOOL ok;
+ QString defaultLocaleGdiCompatibleFamilyName;
+ QString englishLocaleGdiCompatibleFamilyName;
+ if (SUCCEEDED(face3->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &names, &ok)) && ok) {
+ defaultLocaleGdiCompatibleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
+ englishLocaleGdiCompatibleFamilyName = localeString(names, englishLocale);
- IDWriteLocalizedStrings *names;
- if (SUCCEEDED(face3->GetFamilyNames(&names))) {
- defaultLocaleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
- englishLocaleFamilyName = localeString(names, englishLocale);
+ names->Release();
+ }
- names->Release();
- }
+ QString defaultLocaleGdiCompatibleStyleName;
+ QString englishLocaleGdiCompatibleStyleName;
+ if (SUCCEEDED(face3->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_WIN32_SUBFAMILY_NAMES, &names, &ok)) && ok) {
+ defaultLocaleGdiCompatibleStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
+ englishLocaleGdiCompatibleStyleName = localeString(names, englishLocale);
- QString defaultLocaleStyleName;
- QString englishLocaleStyleName;
- if (SUCCEEDED(face3->GetFaceNames(&names))) {
- defaultLocaleStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
- englishLocaleStyleName = localeString(names, englishLocale);
+ names->Release();
+ }
- names->Release();
- }
+ QString defaultLocaleTypographicFamilyName;
+ QString englishLocaleTypographicFamilyName;
+ if (SUCCEEDED(face3->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_TYPOGRAPHIC_FAMILY_NAMES, &names, &ok)) && ok) {
+ defaultLocaleTypographicFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
+ englishLocaleTypographicFamilyName = localeString(names, englishLocale);
- QFont::Stretch stretch = fromDirectWriteStretch(face3->GetStretch());
- QFont::Style style = fromDirectWriteStyle(face3->GetStyle());
- QFont::Weight weight = fromDirectWriteWeight(face3->GetWeight());
- bool fixed = face3->IsMonospacedFont();
-
- qCDebug(lcQpaFonts) << "\tFont names:" << englishLocaleFamilyName << ", " << defaultLocaleFamilyName
- << ", style names:" << englishLocaleStyleName << ", " << defaultLocaleStyleName
- << ", stretch:" << stretch
- << ", style:" << style
- << ", weight:" << weight
- << ", fixed:" << fixed;
-
- if (!englishLocaleFamilyName.isEmpty()) {
- if (applicationFont != nullptr) {
- QFontDatabasePrivate::ApplicationFont::Properties properties;
- properties.style = style;
- properties.weight = weight;
- properties.familyName = englishLocaleFamilyName;
- properties.styleName = englishLocaleStyleName;
- applicationFont->properties.append(properties);
+ names->Release();
}
- ret.append(englishLocaleFamilyName);
- QPlatformFontDatabase::registerFont(englishLocaleFamilyName, englishLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face);
- face->AddRef();
- }
+ QString defaultLocaleTypographicStyleName;
+ QString englishLocaleTypographicStyleName;
+ if (SUCCEEDED(face3->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_TYPOGRAPHIC_SUBFAMILY_NAMES, &names, &ok)) && ok) {
+ defaultLocaleTypographicStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
+ englishLocaleTypographicStyleName = localeString(names, englishLocale);
- if (!defaultLocaleFamilyName.isEmpty() && defaultLocaleFamilyName != englishLocaleFamilyName) {
- if (applicationFont != nullptr) {
- QFontDatabasePrivate::ApplicationFont::Properties properties;
- properties.style = style;
- properties.weight = weight;
- properties.familyName = englishLocaleFamilyName;
- properties.styleName = englishLocaleStyleName;
- applicationFont->properties.append(properties);
+ names->Release();
}
- ret.append(defaultLocaleFamilyName);
- QPlatformFontDatabase::registerFont(defaultLocaleFamilyName, defaultLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face);
- face->AddRef();
- }
+ QFont::Stretch stretch = fromDirectWriteStretch(face3->GetStretch());
+ QFont::Style style = fromDirectWriteStyle(face3->GetStyle());
+ QFont::Weight weight = fromDirectWriteWeight(face3->GetWeight());
+ bool fixed = face3->IsMonospacedFont();
+
+ qCDebug(lcQpaFonts) << "\tFont names:" << englishLocaleFamilyName << ", " << defaultLocaleFamilyName
+ << ", style names:" << englishLocaleStyleName << ", " << defaultLocaleStyleName
+ << ", stretch:" << stretch
+ << ", style:" << style
+ << ", weight:" << weight
+ << ", fixed:" << fixed;
+
+ if (!englishLocaleFamilyName.isEmpty()) {
+ if (applicationFont != nullptr) {
+ QFontDatabasePrivate::ApplicationFont::Properties properties;
+ properties.style = style;
+ properties.weight = weight;
+ properties.familyName = englishLocaleFamilyName;
+ properties.styleName = englishLocaleStyleName;
+ applicationFont->properties.append(properties);
+ }
- face3->Release();
- } else {
- qCWarning(lcQpaFonts) << "Unable to query IDWriteFontFace3 interface from font face.";
- }
+ ret.insert(englishLocaleFamilyName);
+ QPlatformFontDatabase::registerFont(englishLocaleFamilyName,
+ englishLocaleStyleName,
+ QString(),
+ weight,
+ style,
+ stretch,
+ antialias,
+ scalable,
+ size,
+ fixed,
+ writingSystems,
+ new FontHandle(face, englishLocaleFamilyName));
+ }
- face->Release();
+ if (!defaultLocaleFamilyName.isEmpty() && !ret.contains(defaultLocaleFamilyName)) {
+ if (applicationFont != nullptr) {
+ QFontDatabasePrivate::ApplicationFont::Properties properties;
+ properties.style = style;
+ properties.weight = weight;
+ properties.familyName = englishLocaleFamilyName;
+ properties.styleName = englishLocaleStyleName;
+ applicationFont->properties.append(properties);
+ }
- return ret;
-}
+ ret.insert(defaultLocaleFamilyName);
+ QPlatformFontDatabase::registerFont(defaultLocaleFamilyName,
+ defaultLocaleStyleName,
+ QString(),
+ weight,
+ style,
+ stretch,
+ antialias,
+ scalable,
+ size,
+ fixed,
+ writingSystems,
+ new FontHandle(face, defaultLocaleFamilyName));
+ }
-void QWindowsDirectWriteFontDatabase::releaseHandle(void *handle)
-{
- IDWriteFontFace *face = reinterpret_cast<IDWriteFontFace *>(handle);
- face->Release();
-}
+ if (!englishLocaleGdiCompatibleFamilyName.isEmpty() &&
+ !ret.contains(englishLocaleGdiCompatibleFamilyName)) {
+ if (applicationFont != nullptr) {
+ QFontDatabasePrivate::ApplicationFont::Properties properties;
+ properties.style = style;
+ properties.weight = weight;
+ properties.familyName = englishLocaleGdiCompatibleFamilyName;
+ applicationFont->properties.append(properties);
+ }
-bool QWindowsDirectWriteFontDatabase::fontsAlwaysScalable() const
-{
- return true;
+ ret.insert(englishLocaleGdiCompatibleFamilyName);
+ QPlatformFontDatabase::registerFont(englishLocaleGdiCompatibleFamilyName,
+ englishLocaleGdiCompatibleStyleName,
+ QString(),
+ weight,
+ style,
+ stretch,
+ antialias,
+ scalable,
+ size,
+ fixed,
+ writingSystems,
+ new FontHandle(face, englishLocaleGdiCompatibleFamilyName));
+ }
+
+ if (!defaultLocaleGdiCompatibleFamilyName.isEmpty()
+ && !ret.contains(defaultLocaleGdiCompatibleFamilyName)) {
+ if (applicationFont != nullptr) {
+ QFontDatabasePrivate::ApplicationFont::Properties properties;
+ properties.style = style;
+ properties.weight = weight;
+ properties.familyName = defaultLocaleGdiCompatibleFamilyName;
+ applicationFont->properties.append(properties);
+ }
+
+ ret.insert(defaultLocaleGdiCompatibleFamilyName);
+ QPlatformFontDatabase::registerFont(defaultLocaleGdiCompatibleFamilyName,
+ defaultLocaleGdiCompatibleStyleName,
+ QString(),
+ weight,
+ style,
+ stretch,
+ antialias,
+ scalable,
+ size,
+ fixed,
+ writingSystems,
+ new FontHandle(face, defaultLocaleGdiCompatibleFamilyName));
+ }
+
+ if (!englishLocaleTypographicFamilyName.isEmpty()
+ && !ret.contains(englishLocaleTypographicFamilyName)) {
+ if (applicationFont != nullptr) {
+ QFontDatabasePrivate::ApplicationFont::Properties properties;
+ properties.style = style;
+ properties.weight = weight;
+ properties.familyName = englishLocaleTypographicFamilyName;
+ applicationFont->properties.append(properties);
+ }
+
+ ret.insert(englishLocaleTypographicFamilyName);
+ QPlatformFontDatabase::registerFont(englishLocaleTypographicFamilyName,
+ englishLocaleTypographicStyleName,
+ QString(),
+ weight,
+ style,
+ stretch,
+ antialias,
+ scalable,
+ size,
+ fixed,
+ writingSystems,
+ new FontHandle(face, englishLocaleTypographicFamilyName));
+ }
+
+ if (!defaultLocaleTypographicFamilyName.isEmpty()
+ && !ret.contains(defaultLocaleTypographicFamilyName)) {
+ if (applicationFont != nullptr) {
+ QFontDatabasePrivate::ApplicationFont::Properties properties;
+ properties.style = style;
+ properties.weight = weight;
+ properties.familyName = defaultLocaleTypographicFamilyName;
+ applicationFont->properties.append(properties);
+ }
+
+ ret.insert(defaultLocaleTypographicFamilyName);
+ QPlatformFontDatabase::registerFont(defaultLocaleTypographicFamilyName,
+ defaultLocaleTypographicStyleName,
+ QString(),
+ weight,
+ style,
+ stretch,
+ antialias,
+ scalable,
+ size,
+ fixed,
+ writingSystems,
+ new FontHandle(face, defaultLocaleTypographicFamilyName));
+ }
+
+ } else {
+ qCWarning(lcQpaFonts) << "Unable to query IDWriteFontFace3 interface from font face.";
+ }
+
+ face->Release();
+ }
+
+ return ret.values();
}
bool QWindowsDirectWriteFontDatabase::isPrivateFontFamily(const QString &family) const
@@ -362,62 +690,103 @@ bool QWindowsDirectWriteFontDatabase::isPrivateFontFamily(const QString &family)
return false;
}
+static int QT_WIN_CALLBACK populateBitmapFonts(const LOGFONT *logFont,
+ const TEXTMETRIC *textmetric,
+ DWORD type,
+ LPARAM lparam)
+{
+ Q_UNUSED(textmetric);
+
+ // the "@family" fonts are just the same as "family". Ignore them.
+ const ENUMLOGFONTEX *f = reinterpret_cast<const ENUMLOGFONTEX *>(logFont);
+ const wchar_t *faceNameW = f->elfLogFont.lfFaceName;
+ if (faceNameW[0] && faceNameW[0] != L'@' && wcsncmp(faceNameW, L"WST_", 4)) {
+ const QString faceName = QString::fromWCharArray(faceNameW);
+ if (type & RASTER_FONTTYPE || type == 0) {
+ QWindowsDirectWriteFontDatabase *db = reinterpret_cast<QWindowsDirectWriteFontDatabase *>(lparam);
+ if (!db->hasPopulatedFont(faceName)) {
+ db->registerFontFamily(faceName);
+ db->registerBitmapFont(faceName);
+ }
+ }
+ }
+ return 1; // continue
+}
+
void QWindowsDirectWriteFontDatabase::populateFontDatabase()
{
wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH];
bool hasDefaultLocale = GetUserDefaultLocaleName(defaultLocale, LOCALE_NAME_MAX_LENGTH) != 0;
wchar_t englishLocale[] = L"en-us";
- const QString defaultFontName = defaultFont().families().first();
- const QString systemDefaultFontName = systemDefaultFont().families().first();
+ const QString defaultFontName = defaultFont().families().constFirst();
+ const QString systemDefaultFontName = systemDefaultFont().families().constFirst();
+
+ DirectWriteScope<IDWriteFontCollection2> fontCollection;
+ DirectWriteScope<IDWriteFactory6> factory6;
+ if (FAILED(data()->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory6),
+ reinterpret_cast<void **>(&factory6)))) {
+ qCWarning(lcQpaFonts) << "Can't initialize IDWriteFactory6. Use GDI font engine instead.";
+ return;
+ }
- IDWriteFontCollection *fontCollection;
- if (SUCCEEDED(data()->directWriteFactory->GetSystemFontCollection(&fontCollection))) {
+ if (SUCCEEDED(factory6->GetSystemFontCollection(false,
+ DWRITE_FONT_FAMILY_MODEL_TYPOGRAPHIC,
+ &fontCollection))) {
for (uint i = 0; i < fontCollection->GetFontFamilyCount(); ++i) {
- IDWriteFontFamily *fontFamily;
+ DirectWriteScope<IDWriteFontFamily2> fontFamily;
if (SUCCEEDED(fontCollection->GetFontFamily(i, &fontFamily))) {
QString defaultLocaleName;
QString englishLocaleName;
- IDWriteLocalizedStrings *names;
+ DirectWriteScope<IDWriteLocalizedStrings> names;
if (SUCCEEDED(fontFamily->GetFamilyNames(&names))) {
if (hasDefaultLocale)
- defaultLocaleName = localeString(names, defaultLocale);
+ defaultLocaleName = localeString(*names, defaultLocale);
- englishLocaleName = localeString(names, englishLocale);
+ englishLocaleName = localeString(*names, englishLocale);
}
qCDebug(lcQpaFonts) << "Registering font, english name = " << englishLocaleName << ", name in current locale = " << defaultLocaleName;
if (!defaultLocaleName.isEmpty()) {
registerFontFamily(defaultLocaleName);
- m_populatedFonts.insert(defaultLocaleName, fontFamily);
+ m_populatedFonts.insert(defaultLocaleName, *fontFamily);
fontFamily->AddRef();
if (defaultLocaleName == defaultFontName && defaultFontName != systemDefaultFontName) {
qDebug(lcQpaFonts) << "Adding default font" << systemDefaultFontName << "as alternative to" << defaultLocaleName;
- m_populatedFonts.insert(systemDefaultFontName, fontFamily);
+ m_populatedFonts.insert(systemDefaultFontName, *fontFamily);
fontFamily->AddRef();
}
}
if (!englishLocaleName.isEmpty() && englishLocaleName != defaultLocaleName) {
registerFontFamily(englishLocaleName);
- m_populatedFonts.insert(englishLocaleName, fontFamily);
+ m_populatedFonts.insert(englishLocaleName, *fontFamily);
fontFamily->AddRef();
if (englishLocaleName == defaultFontName && defaultFontName != systemDefaultFontName) {
qDebug(lcQpaFonts) << "Adding default font" << systemDefaultFontName << "as alternative to" << englishLocaleName;
- m_populatedFonts.insert(systemDefaultFontName, fontFamily);
+ m_populatedFonts.insert(systemDefaultFontName, *fontFamily);
fontFamily->AddRef();
}
}
-
- fontFamily->Release();
}
}
}
+
+ // Since bitmap fonts are not supported by DirectWrite, we need to populate these as well
+ {
+ HDC dummy = GetDC(0);
+ LOGFONT lf;
+ lf.lfCharSet = DEFAULT_CHARSET;
+ lf.lfFaceName[0] = 0;
+ lf.lfPitchAndFamily = 0;
+ EnumFontFamiliesEx(dummy, &lf, populateBitmapFonts, reinterpret_cast<intptr_t>(this), 0);
+ ReleaseDC(0, dummy);
+ }
}
QFont QWindowsDirectWriteFontDatabase::defaultFont() const
@@ -425,4 +794,16 @@ QFont QWindowsDirectWriteFontDatabase::defaultFont() const
return QFont(QStringLiteral("Segoe UI"));
}
+bool QWindowsDirectWriteFontDatabase::supportsVariableApplicationFonts() const
+{
+ QSharedPointer<QWindowsFontEngineData> fontEngineData = data();
+ DirectWriteScope<IDWriteFactory5> factory5;
+ if (SUCCEEDED(fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory5),
+ reinterpret_cast<void **>(&factory5)))) {
+ return true;
+ }
+
+ return false;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h b/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h
index 89b216a239..093c629a16 100644
--- a/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h
+++ b/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h
@@ -20,17 +20,18 @@
QT_REQUIRE_CONFIG(directwrite3);
-#include "qwindowsfontdatabasebase_p.h"
+#include "qwindowsfontdatabase_p.h"
#include <QtCore/qloggingcategory.h>
struct IDWriteFactory;
struct IDWriteFont;
+struct IDWriteFont1;
struct IDWriteFontFamily;
struct IDWriteLocalizedStrings;
QT_BEGIN_NAMESPACE
-class Q_GUI_EXPORT QWindowsDirectWriteFontDatabase : public QWindowsFontDatabaseBase
+class Q_GUI_EXPORT QWindowsDirectWriteFontDatabase : public QWindowsFontDatabase
{
Q_DISABLE_COPY_MOVE(QWindowsDirectWriteFontDatabase)
public:
@@ -39,19 +40,34 @@ public:
void populateFontDatabase() override;
void populateFamily(const QString &familyName) override;
+ bool populateFamilyAliases(const QString &missingFamily) override;
QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override;
+ QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override;
QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const override;
QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *font = nullptr) override;
- void releaseHandle(void *handle) override;
QFont defaultFont() const override;
- bool fontsAlwaysScalable() const override;
bool isPrivateFontFamily(const QString &family) const override;
+ bool supportsVariableApplicationFonts() const override;
+
+ void registerBitmapFont(const QString &bitmapFont)
+ {
+ m_populatedBitmapFonts.insert(bitmapFont);
+ }
+
+ bool hasPopulatedFont(const QString &fontFamily) const
+ {
+ return m_populatedFonts.contains(fontFamily);
+ }
private:
+ friend class QWindowsFontEngineDirectWrite;
static QString localeString(IDWriteLocalizedStrings *names, wchar_t localeName[]);
+ QSupportedWritingSystems supportedWritingSystems(IDWriteFontFace *face) const;
+
QHash<QString, IDWriteFontFamily *> m_populatedFonts;
+ QSet<QString> m_populatedBitmapFonts;
};
QT_END_NAMESPACE
diff --git a/src/gui/text/windows/qwindowsfontdatabase.cpp b/src/gui/text/windows/qwindowsfontdatabase.cpp
index 2de53be6a8..adc06a6c2a 100644
--- a/src/gui/text/windows/qwindowsfontdatabase.cpp
+++ b/src/gui/text/windows/qwindowsfontdatabase.cpp
@@ -10,7 +10,6 @@
#include <QtGui/QFont>
#include <QtGui/QGuiApplication>
-#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtGui/private/qtgui-config_p.h>
#include <QtCore/qmath.h>
@@ -32,6 +31,8 @@
# include "qwindowsfontenginedirectwrite_p.h"
#endif
+#include <mutex>
+
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
@@ -55,7 +56,7 @@ static inline bool useDirectWrite(QFont::HintingPreference hintingPreference,
return hintingPreference == QFont::PreferNoHinting
|| hintingPreference == QFont::PreferVerticalHinting
- || (QHighDpiScaling::isActive() && hintingPreference == QFont::PreferDefaultHinting);
+ || (!qFuzzyCompare(qApp->devicePixelRatio(), 1.0) && hintingPreference == QFont::PreferDefaultHinting);
}
#endif // !QT_NO_DIRECTWRITE
@@ -190,17 +191,6 @@ static inline QFontDatabase::WritingSystem writingSystemFromCharSet(uchar charSe
return QFontDatabase::Any;
}
-#ifdef MAKE_TAG
-#undef MAKE_TAG
-#endif
-// GetFontData expects the tags in little endian ;(
-#define MAKE_TAG(ch1, ch2, ch3, ch4) (\
- (((quint32)(ch4)) << 24) | \
- (((quint32)(ch3)) << 16) | \
- (((quint32)(ch2)) << 8) | \
- ((quint32)(ch1)) \
- )
-
bool qt_localizedName(const QString &name)
{
const QChar *c = name.unicode();
@@ -378,7 +368,7 @@ QString qt_getEnglishName(const QString &familyName, bool includeStyle)
HGDIOBJ oldobj = SelectObject( hdc, hfont );
- const DWORD name_tag = MAKE_TAG( 'n', 'a', 'm', 'e' );
+ const DWORD name_tag = qFromBigEndian(QFont::Tag("name").value());
// get the name table
unsigned char *table = 0;
@@ -427,7 +417,7 @@ QFontNames qt_getCanonicalFontNames(const LOGFONT &lf)
// get the name table
QByteArray table;
- const DWORD name_tag = MAKE_TAG('n', 'a', 'm', 'e');
+ const DWORD name_tag = qFromBigEndian(QFont::Tag("name").value());
DWORD bytes = GetFontData(hdc, name_tag, 0, 0, 0);
if (bytes != GDI_ERROR) {
table.resize(bytes);
@@ -443,18 +433,6 @@ QFontNames qt_getCanonicalFontNames(const LOGFONT &lf)
return fontNames;
}
-static QChar *createFontFile(const QString &faceName)
-{
- QChar *faceNamePtr = nullptr;
- if (!faceName.isEmpty()) {
- const int nameLength = qMin(faceName.length(), LF_FACESIZE - 1);
- faceNamePtr = new QChar[nameLength + 1];
- memcpy(static_cast<void *>(faceNamePtr), faceName.data(), sizeof(wchar_t) * nameLength);
- faceNamePtr[nameLength] = u'\0';
- }
- return faceNamePtr;
-}
-
namespace {
struct StoreFontPayload {
StoreFontPayload(const QString &family,
@@ -561,33 +539,35 @@ static bool addFontToDatabase(QString familyName,
writingSystems.setSupported(ws);
}
- // We came here from populating a different font family, so we have
- // to ensure the entire typographic family is populated before we
- // mark it as such inside registerFont()
- if (!subFamilyName.isEmpty()
- && familyName != subFamilyName
- && sfp->populatedFontFamily != familyName
- && !QPlatformFontDatabase::isFamilyPopulated(familyName)) {
- sfp->windowsFontDatabase->populateFamily(familyName);
- }
-
+ const bool wasPopulated = QPlatformFontDatabase::isFamilyPopulated(familyName);
QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight,
- style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
+ style, stretch, antialias, scalable, size, fixed, writingSystems, new QWindowsFontDatabase::FontHandle(faceName));
+
// add fonts windows can generate for us:
if (weight <= QFont::DemiBold && styleName.isEmpty())
QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold,
- style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
+ style, stretch, antialias, scalable, size, fixed, writingSystems, new QWindowsFontDatabase::FontHandle(faceName));
if (style != QFont::StyleItalic && styleName.isEmpty())
QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, weight,
- QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
+ QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, new QWindowsFontDatabase::FontHandle(faceName));
if (weight <= QFont::DemiBold && style != QFont::StyleItalic && styleName.isEmpty())
QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold,
- QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
+ QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, new QWindowsFontDatabase::FontHandle(faceName));
+
+ // We came here from populating a different font family, so we have
+ // to ensure the entire typographic family is populated before we
+ // mark it as such inside registerFont()
+ if (!subFamilyName.isEmpty()
+ && familyName != subFamilyName
+ && sfp->populatedFontFamily != familyName
+ && !wasPopulated) {
+ sfp->windowsFontDatabase->populateFamily(familyName);
+ }
if (!subFamilyName.isEmpty() && familyName != subFamilyName) {
QPlatformFontDatabase::registerFont(subFamilyName, subFamilyStyle, foundryName, weight,
- style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
+ style, stretch, antialias, scalable, size, fixed, writingSystems, new QWindowsFontDatabase::FontHandle(faceName));
}
if (!englishName.isEmpty() && englishName != familyName)
@@ -725,7 +705,7 @@ void QWindowsFontDatabase::populateFontDatabase()
EnumFontFamiliesEx(dummy, &lf, populateFontFamilies, 0, 0);
ReleaseDC(0, dummy);
// Work around EnumFontFamiliesEx() not listing the system font.
- const QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().families().first();
+ const QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().families().constFirst();
if (QPlatformFontDatabase::resolveFontFamilyAlias(systemDefaultFamily) == systemDefaultFamily)
QPlatformFontDatabase::registerFontFamily(systemDefaultFamily);
addDefaultEUDCFont();
@@ -733,6 +713,7 @@ void QWindowsFontDatabase::populateFontDatabase()
void QWindowsFontDatabase::invalidate()
{
+ QWindowsFontDatabaseBase::invalidate();
removeApplicationFonts();
}
@@ -758,7 +739,8 @@ QWindowsFontDatabase::~QWindowsFontDatabase()
QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, void *handle)
{
- const QString faceName(static_cast<const QChar*>(handle));
+ FontHandle *fontHandle = static_cast<FontHandle *>(handle);
+ const QString faceName = fontHandle->faceName.left(LF_FACESIZE - 1);
QFontEngine *fe = QWindowsFontDatabase::createEngine(fontDef, faceName,
defaultVerticalDPI(),
data());
@@ -820,7 +802,7 @@ QT_WARNING_POP
if (fontEngine) {
if (request.families != fontEngine->fontDef.families) {
qWarning("%s: Failed to load font. Got fallback instead: %s", __FUNCTION__,
- qPrintable(fontEngine->fontDef.families.first()));
+ qPrintable(fontEngine->fontDef.families.constFirst()));
if (fontEngine->ref.loadRelaxed() == 0)
delete fontEngine;
fontEngine = 0;
@@ -844,10 +826,13 @@ QT_WARNING_POP
Q_ASSERT_X(false, Q_FUNC_INFO, "Unhandled font engine.");
}
- UniqueFontData uniqueData;
+ UniqueFontData uniqueData{};
uniqueData.handle = fontHandle;
- uniqueData.refCount.ref();
- m_uniqueFontData[uniqueFamilyName] = uniqueData;
+ ++uniqueData.refCount;
+ {
+ const std::scoped_lock lock(m_uniqueFontDataMutex);
+ m_uniqueFontData[uniqueFamilyName] = uniqueData;
+ }
}
} else {
RemoveFontMemResourceEx(fontHandle);
@@ -868,36 +853,70 @@ QT_WARNING_POP
return fontEngine;
}
-static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData)
+static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData, const uchar *fileEndSentinel)
{
QList<quint32> offsets;
- const quint32 headerTag = *reinterpret_cast<const quint32 *>(fontData);
- if (headerTag != MAKE_TAG('t', 't', 'c', 'f')) {
- if (headerTag != MAKE_TAG(0, 1, 0, 0)
- && headerTag != MAKE_TAG('O', 'T', 'T', 'O')
- && headerTag != MAKE_TAG('t', 'r', 'u', 'e')
- && headerTag != MAKE_TAG('t', 'y', 'p', '1'))
+ if (fileEndSentinel - fontData < 12) {
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
+ return offsets;
+ }
+
+ const quint32 headerTag = qFromUnaligned<quint32>(fontData);
+ if (headerTag != qFromBigEndian(QFont::Tag("ttcf").value())) {
+ if (headerTag != qFromBigEndian(QFont::Tag("\0\1\0\0").value())
+ && headerTag != qFromBigEndian(QFont::Tag("OTTO").value())
+ && headerTag != qFromBigEndian(QFont::Tag("true").value())
+ && headerTag != qFromBigEndian(QFont::Tag("typ1").value())) {
return offsets;
+ }
offsets << 0;
return offsets;
}
+
+ const quint32 maximumNumFonts = 0xffff;
const quint32 numFonts = qFromBigEndian<quint32>(fontData + 8);
- for (uint i = 0; i < numFonts; ++i) {
- offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4);
+ if (numFonts > maximumNumFonts) {
+ qCWarning(lcQpaFonts) << "Font collection of" << numFonts << "fonts is too large. Aborting.";
+ return offsets;
+ }
+
+ if (quintptr(fileEndSentinel - fontData) > 12 + (numFonts - 1) * 4) {
+ for (quint32 i = 0; i < numFonts; ++i)
+ offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4);
+ } else {
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
}
+
return offsets;
}
-static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, const uchar **table, quint32 *length)
+static void getFontTable(const uchar *fileBegin, const uchar *fileEndSentinel, const uchar *data, quint32 tag, const uchar **table, quint32 *length)
{
- const quint16 numTables = qFromBigEndian<quint16>(data + 4);
- for (uint i = 0; i < numTables; ++i) {
- const quint32 offset = 12 + 16 * i;
- if (*reinterpret_cast<const quint32 *>(data + offset) == tag) {
- *table = fileBegin + qFromBigEndian<quint32>(data + offset + 8);
- *length = qFromBigEndian<quint32>(data + offset + 12);
- return;
+ if (fileEndSentinel - data >= 6) {
+ const quint16 numTables = qFromBigEndian<quint16>(data + 4);
+ if (fileEndSentinel - data >= 28 + 16 * (numTables - 1)) {
+ for (quint32 i = 0; i < numTables; ++i) {
+ const quint32 offset = 12 + 16 * i;
+ if (qFromUnaligned<quint32>(data + offset) == tag) {
+ const quint32 tableOffset = qFromBigEndian<quint32>(data + offset + 8);
+ if (quintptr(fileEndSentinel - fileBegin) <= tableOffset) {
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
+ break;
+ }
+ *table = fileBegin + tableOffset;
+ *length = qFromBigEndian<quint32>(data + offset + 12);
+ if (quintptr(fileEndSentinel - *table) < *length) {
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
+ break;
+ }
+ return;
+ }
+ }
+ } else {
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
}
+ } else {
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
}
*table = 0;
*length = 0;
@@ -910,8 +929,9 @@ static void getFamiliesAndSignatures(const QByteArray &fontData,
QList<QFontValues> *values)
{
const uchar *data = reinterpret_cast<const uchar *>(fontData.constData());
+ const uchar *dataEndSentinel = data + fontData.size();
- QList<quint32> offsets = getTrueTypeFontOffsets(data);
+ QList<quint32> offsets = getTrueTypeFontOffsets(data, dataEndSentinel);
if (offsets.isEmpty())
return;
@@ -919,7 +939,9 @@ static void getFamiliesAndSignatures(const QByteArray &fontData,
const uchar *font = data + offsets.at(i);
const uchar *table;
quint32 length;
- getFontTable(data, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length);
+ getFontTable(data, dataEndSentinel, font,
+ qFromBigEndian(QFont::Tag("name").value()),
+ &table, &length);
if (!table)
continue;
QFontNames names = qt_getCanonicalFontNames(table, length);
@@ -928,8 +950,11 @@ static void getFamiliesAndSignatures(const QByteArray &fontData,
families->append(std::move(names));
- if (values || signatures)
- getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length);
+ if (values || signatures) {
+ getFontTable(data, dataEndSentinel, font,
+ qFromBigEndian(QFont::Tag("OS/2").value()),
+ &table, &length);
+ }
if (values) {
QFontValues fontValues;
@@ -1087,10 +1112,22 @@ void QWindowsFontDatabase::removeApplicationFonts()
m_eudcFonts.clear();
}
+QWindowsFontDatabase::FontHandle::FontHandle(IDWriteFontFace *face, const QString &name)
+ : fontFace(face), faceName(name)
+{
+ fontFace->AddRef();
+}
+
+
+QWindowsFontDatabase::FontHandle::~FontHandle()
+{
+ if (fontFace != nullptr)
+ fontFace->Release();
+}
+
void QWindowsFontDatabase::releaseHandle(void *handle)
{
- const QChar *faceName = reinterpret_cast<const QChar *>(handle);
- delete[] faceName;
+ delete static_cast<FontHandle *>(handle);
}
QString QWindowsFontDatabase::fontDir() const
@@ -1107,18 +1144,22 @@ bool QWindowsFontDatabase::fontsAlwaysScalable() const
void QWindowsFontDatabase::derefUniqueFont(const QString &uniqueFont)
{
- if (m_uniqueFontData.contains(uniqueFont)) {
- if (!m_uniqueFontData[uniqueFont].refCount.deref()) {
- RemoveFontMemResourceEx(m_uniqueFontData[uniqueFont].handle);
- m_uniqueFontData.remove(uniqueFont);
+ const std::scoped_lock lock(m_uniqueFontDataMutex);
+ const auto it = m_uniqueFontData.find(uniqueFont);
+ if (it != m_uniqueFontData.end()) {
+ if (--it->refCount == 0) {
+ RemoveFontMemResourceEx(it->handle);
+ m_uniqueFontData.erase(it);
}
}
}
void QWindowsFontDatabase::refUniqueFont(const QString &uniqueFont)
{
- if (m_uniqueFontData.contains(uniqueFont))
- m_uniqueFontData[uniqueFont].refCount.ref();
+ const std::scoped_lock lock(m_uniqueFontDataMutex);
+ const auto it = m_uniqueFontData.find(uniqueFont);
+ if (it != m_uniqueFontData.end())
+ ++it->refCount;
}
QStringList QWindowsFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const
@@ -1186,6 +1227,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q
HRESULT hr = data->directWriteGdiInterop->CreateFontFaceFromHdc(data->hdc, &directWriteFontFace);
if (SUCCEEDED(hr)) {
bool isColorFont = false;
+ bool needsSimulation = false;
#if QT_CONFIG(direct2d)
IDWriteFontFace2 *directWriteFontFace2 = nullptr;
if (SUCCEEDED(directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace2),
@@ -1193,10 +1235,12 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q
if (directWriteFontFace2->IsColorFont())
isColorFont = directWriteFontFace2->GetPaletteEntryCount() > 0;
+ needsSimulation = directWriteFontFace2->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE;
+
directWriteFontFace2->Release();
}
#endif // direct2d
- useDw = useDw || useDirectWrite(hintingPreference, fam, isColorFont);
+ useDw = useDw || useDirectWrite(hintingPreference, fam, isColorFont) || needsSimulation;
qCDebug(lcQpaFonts)
<< __FUNCTION__ << request.families.first() << request.pointSize << "pt"
<< "hintingPreference=" << hintingPreference << "color=" << isColorFont
@@ -1212,9 +1256,6 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q
QFontDef fontDef = request;
fontDef.families = QStringList(QString::fromWCharArray(n));
-
- if (isColorFont)
- fedw->glyphFormat = QFontEngine::Format_ARGB;
fedw->initFontInfo(fontDef, dpi);
fe = fedw;
}
diff --git a/src/gui/text/windows/qwindowsfontdatabase_ft.cpp b/src/gui/text/windows/qwindowsfontdatabase_ft.cpp
index f30a39aecc..0604a85e35 100644
--- a/src/gui/text/windows/qwindowsfontdatabase_ft.cpp
+++ b/src/gui/text/windows/qwindowsfontdatabase_ft.cpp
@@ -295,6 +295,21 @@ static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *t
return 1;
}
+bool QWindowsFontDatabaseFT::populateFamilyAliases(const QString &missingFamily)
+{
+ Q_UNUSED(missingFamily);
+
+ if (m_hasPopulatedAliases)
+ return false;
+
+ QStringList families = QFontDatabase::families();
+ for (const QString &family : families)
+ populateFamily(family);
+ m_hasPopulatedAliases = true;
+
+ return true;
+}
+
/*
\brief Populates the font database using EnumFontFamiliesEx().
@@ -363,7 +378,7 @@ void QWindowsFontDatabaseFT::populateFontDatabase()
EnumFontFamiliesEx(dummy, &lf, populateFontFamilies, 0, 0);
ReleaseDC(0, dummy);
// Work around EnumFontFamiliesEx() not listing the system font
- const QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().families().first();
+ const QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().families().constFirst();
if (QPlatformFontDatabase::resolveFontFamilyAlias(systemDefaultFamily) == systemDefaultFamily)
QPlatformFontDatabase::registerFontFamily(systemDefaultFamily);
}
@@ -371,7 +386,7 @@ void QWindowsFontDatabaseFT::populateFontDatabase()
QFontEngine * QWindowsFontDatabaseFT::fontEngine(const QFontDef &fontDef, void *handle)
{
QFontEngine *fe = QFreeTypeFontDatabase::fontEngine(fontDef, handle);
- qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef.families.first() << fe << handle;
+ qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef.families.constFirst() << fe << handle;
return fe;
}
diff --git a/src/gui/text/windows/qwindowsfontdatabase_ft_p.h b/src/gui/text/windows/qwindowsfontdatabase_ft_p.h
index b908cd54c6..381a7be4e7 100644
--- a/src/gui/text/windows/qwindowsfontdatabase_ft_p.h
+++ b/src/gui/text/windows/qwindowsfontdatabase_ft_p.h
@@ -25,6 +25,7 @@ class Q_GUI_EXPORT QWindowsFontDatabaseFT : public QFreeTypeFontDatabase
{
public:
void populateFontDatabase() override;
+ bool populateFamilyAliases(const QString &familyName) override;
void populateFamily(const QString &familyName) override;
QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override;
QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize,
@@ -36,6 +37,8 @@ public:
QString fontDir() const override;
QFont defaultFont() const override;
+
+ bool m_hasPopulatedAliases = false;
};
QT_END_NAMESPACE
diff --git a/src/gui/text/windows/qwindowsfontdatabase_p.h b/src/gui/text/windows/qwindowsfontdatabase_p.h
index 923f875336..0c99c91fde 100644
--- a/src/gui/text/windows/qwindowsfontdatabase_p.h
+++ b/src/gui/text/windows/qwindowsfontdatabase_p.h
@@ -21,6 +21,7 @@
#include <QtCore/QSharedPointer>
#include <QtCore/QLoggingCategory>
#include <QtCore/qhashfunctions.h>
+#include <QtCore/qmutex.h>
#include <QtCore/qt_windows.h>
QT_BEGIN_NAMESPACE
@@ -44,6 +45,7 @@ public:
void populateFontDatabase() override;
void invalidate() override;
+ void removeApplicationFonts();
void populateFamily(const QString &familyName) override;
bool populateFamilyAliases(const QString &missingFamily) override;
@@ -73,8 +75,16 @@ public:
static void debugFormat(QDebug &d, const LOGFONT &lf);
#endif // !QT_NO_DEBUG_STREAM
+ struct FontHandle {
+ FontHandle(const QString &name) : faceName(name) {}
+ FontHandle(IDWriteFontFace *face, const QString &name);
+ ~FontHandle();
+
+ IDWriteFontFace *fontFace = nullptr;
+ QString faceName;
+ };
+
private:
- void removeApplicationFonts();
void addDefaultEUDCFont();
struct WinApplicationFont {
@@ -86,9 +96,10 @@ private:
struct UniqueFontData {
HANDLE handle;
- QAtomicInt refCount;
+ int refCount;
};
+ QMutex m_uniqueFontDataMutex; // protects m_uniqueFontData
QMap<QString, UniqueFontData> m_uniqueFontData;
static unsigned m_fontOptions;
diff --git a/src/gui/text/windows/qwindowsfontdatabasebase.cpp b/src/gui/text/windows/qwindowsfontdatabasebase.cpp
index f45678c65c..84e619b0d9 100644
--- a/src/gui/text/windows/qwindowsfontdatabasebase.cpp
+++ b/src/gui/text/windows/qwindowsfontdatabasebase.cpp
@@ -359,10 +359,10 @@ namespace {
{
}
- inline void addKey(const void *key, const QByteArray &fontData)
+ inline void addKey(const QByteArray &fontData)
{
- Q_ASSERT(!m_fontDatas.contains(key));
- m_fontDatas.insert(key, fontData);
+ if (!m_fontDatas.contains(fontData.data()))
+ m_fontDatas.insert(fontData.data(), fontData);
}
inline void removeKey(const void *key)
@@ -378,6 +378,11 @@ namespace {
UINT32 fontFileReferenceKeySize,
OUT IDWriteFontFileStream **fontFileStream) override;
+ void clear()
+ {
+ m_fontDatas.clear();
+ }
+
private:
ULONG m_referenceCount;
QHash<const void *, QByteArray> m_fontDatas;
@@ -435,52 +440,62 @@ namespace {
return S_OK;
}
- class CustomFontFileLoader
+} // Anonymous namespace
+
+class QCustomFontFileLoader
+{
+public:
+ QCustomFontFileLoader(IDWriteFactory *factory)
{
- public:
- CustomFontFileLoader(IDWriteFactory *factory)
- {
- m_directWriteFactory = factory;
+ m_directWriteFactory = factory;
- if (m_directWriteFactory) {
- m_directWriteFactory->AddRef();
+ if (m_directWriteFactory) {
+ m_directWriteFactory->AddRef();
- m_directWriteFontFileLoader = new DirectWriteFontFileLoader();
- m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
- }
+ m_directWriteFontFileLoader = new DirectWriteFontFileLoader();
+ m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
}
+ }
- ~CustomFontFileLoader()
- {
- if (m_directWriteFactory != nullptr && m_directWriteFontFileLoader != nullptr)
- m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
+ ~QCustomFontFileLoader()
+ {
+ clear();
- if (m_directWriteFactory != nullptr)
- m_directWriteFactory->Release();
- }
+ if (m_directWriteFactory != nullptr && m_directWriteFontFileLoader != nullptr)
+ m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
- void addKey(const void *key, const QByteArray &fontData)
- {
- if (m_directWriteFontFileLoader != nullptr)
- m_directWriteFontFileLoader->addKey(key, fontData);
- }
+ if (m_directWriteFactory != nullptr)
+ m_directWriteFactory->Release();
+ }
- void removeKey(const void *key)
- {
- if (m_directWriteFontFileLoader != nullptr)
- m_directWriteFontFileLoader->removeKey(key);
- }
+ void addKey(const QByteArray &fontData)
+ {
+ if (m_directWriteFontFileLoader != nullptr)
+ m_directWriteFontFileLoader->addKey(fontData);
+ }
- IDWriteFontFileLoader *loader() const
- {
- return m_directWriteFontFileLoader;
- }
+ void removeKey(const void *key)
+ {
+ if (m_directWriteFontFileLoader != nullptr)
+ m_directWriteFontFileLoader->removeKey(key);
+ }
+
+ IDWriteFontFileLoader *loader() const
+ {
+ return m_directWriteFontFileLoader;
+ }
+
+ void clear()
+ {
+ if (m_directWriteFontFileLoader != nullptr)
+ m_directWriteFontFileLoader->clear();
+ }
+
+private:
+ IDWriteFactory *m_directWriteFactory = nullptr;
+ DirectWriteFontFileLoader *m_directWriteFontFileLoader = nullptr;
+};
- private:
- IDWriteFactory *m_directWriteFactory = nullptr;
- DirectWriteFontFileLoader *m_directWriteFontFileLoader = nullptr;
- };
-} // Anonymous namespace
#endif // directwrite && direct2d
@@ -550,12 +565,27 @@ void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory
IUnknown *result = nullptr;
# if QT_CONFIG(directwrite3)
- DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), &result);
+ qCDebug(lcQpaFonts) << "Trying to create IDWriteFactory6";
+ DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory6), &result);
+
+ if (result == nullptr) {
+ qCDebug(lcQpaFonts) << "Trying to create IDWriteFactory5";
+ DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory5), &result);
+ }
+
+ if (result == nullptr) {
+ qCDebug(lcQpaFonts) << "Trying to create IDWriteFactory3";
+ DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), &result);
+ }
# endif
- if (result == nullptr)
+
+ if (result == nullptr) {
+ qCDebug(lcQpaFonts) << "Trying to create IDWriteFactory2";
DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result);
+ }
if (result == nullptr) {
+ qCDebug(lcQpaFonts) << "Trying to create plain IDWriteFactory";
if (FAILED(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &result))) {
qErrnoWarning("DWriteCreateFactory failed");
return;
@@ -691,28 +721,47 @@ QFont QWindowsFontDatabaseBase::systemDefaultFont()
return systemFont;
}
+void QWindowsFontDatabaseBase::invalidate()
+{
+#if QT_CONFIG(directwrite)
+ m_fontFileLoader.reset(nullptr);
+#endif
+}
+
#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
-IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArray &fontData) const
+IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArray &fontData)
{
+ QList<IDWriteFontFace *> faces = createDirectWriteFaces(fontData, false);
+ Q_ASSERT(faces.size() <= 1);
+
+ return faces.isEmpty() ? nullptr : faces.first();
+}
+
+QList<IDWriteFontFace *> QWindowsFontDatabaseBase::createDirectWriteFaces(const QByteArray &fontData,
+ bool queryVariations) const
+{
+ QList<IDWriteFontFace *> ret;
QSharedPointer<QWindowsFontEngineData> fontEngineData = data();
if (fontEngineData->directWriteFactory == nullptr) {
qCWarning(lcQpaFonts) << "DirectWrite factory not created in QWindowsFontDatabaseBase::createDirectWriteFace()";
- return nullptr;
+ return ret;
}
- CustomFontFileLoader fontFileLoader(fontEngineData->directWriteFactory);
- fontFileLoader.addKey(this, fontData);
+ if (m_fontFileLoader == nullptr)
+ m_fontFileLoader.reset(new QCustomFontFileLoader(fontEngineData->directWriteFactory));
+
+ m_fontFileLoader->addKey(fontData);
IDWriteFontFile *fontFile = nullptr;
- const void *key = this;
+ const void *key = fontData.data();
HRESULT hres = fontEngineData->directWriteFactory->CreateCustomFontFileReference(&key,
sizeof(void *),
- fontFileLoader.loader(),
+ m_fontFileLoader->loader(),
&fontFile);
if (FAILED(hres)) {
qErrnoWarning(hres, "%s: CreateCustomFontFileReference failed", __FUNCTION__);
- return nullptr;
+ return ret;
}
BOOL isSupportedFontType;
@@ -722,25 +771,65 @@ IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArra
fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces);
if (!isSupportedFontType) {
fontFile->Release();
- return nullptr;
+ return ret;
}
+#if QT_CONFIG(directwrite3)
+ IDWriteFactory5 *factory5 = nullptr;
+ if (queryVariations && SUCCEEDED(fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory5),
+ reinterpret_cast<void **>(&factory5)))) {
+
+ IDWriteFontSetBuilder1 *builder;
+ if (SUCCEEDED(factory5->CreateFontSetBuilder(&builder))) {
+ if (SUCCEEDED(builder->AddFontFile(fontFile))) {
+ IDWriteFontSet *fontSet;
+ if (SUCCEEDED(builder->CreateFontSet(&fontSet))) {
+ int count = fontSet->GetFontCount();
+ qCDebug(lcQpaFonts) << "Found" << count << "variations in font file";
+ for (int i = 0; i < count; ++i) {
+ IDWriteFontFaceReference *ref;
+ if (SUCCEEDED(fontSet->GetFontFaceReference(i, &ref))) {
+ IDWriteFontFace3 *face;
+ if (SUCCEEDED(ref->CreateFontFace(&face))) {
+ ret.append(face);
+ }
+ ref->Release();
+ }
+ }
+ fontSet->Release();
+ }
+ }
+
+ builder->Release();
+ }
+
+ factory5->Release();
+ }
+#else
+ Q_UNUSED(queryVariations);
+#endif
+
// ### Currently no support for .ttc, but we could easily return a list here.
- IDWriteFontFace *directWriteFontFace = nullptr;
- hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType,
- 1,
- &fontFile,
- 0,
- DWRITE_FONT_SIMULATIONS_NONE,
- &directWriteFontFace);
- if (FAILED(hres)) {
- qErrnoWarning(hres, "%s: CreateFontFace failed", __FUNCTION__);
- fontFile->Release();
- return nullptr;
+ if (ret.isEmpty()) {
+ IDWriteFontFace *directWriteFontFace = nullptr;
+ hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType,
+ 1,
+ &fontFile,
+ 0,
+ DWRITE_FONT_SIMULATIONS_NONE,
+ &directWriteFontFace);
+ if (FAILED(hres)) {
+ qErrnoWarning(hres, "%s: CreateFontFace failed", __FUNCTION__);
+ fontFile->Release();
+ return ret;
+ } else {
+ ret.append(directWriteFontFace);
+ }
}
fontFile->Release();
- return directWriteFontFace;
+
+ return ret;
}
#endif // directwrite && direct2d
@@ -760,7 +849,10 @@ QFontEngine *QWindowsFontDatabaseBase::fontEngine(const QByteArray &fontData, qr
if (fontEngineData->directWriteFactory == nullptr)
return nullptr;
- IDWriteFontFace *directWriteFontFace = createDirectWriteFace(fontData);
+ IDWriteFontFace * directWriteFontFace = createDirectWriteFace(fontData);
+ if (directWriteFontFace == nullptr)
+ return nullptr;
+
fontEngine = new QWindowsFontEngineDirectWrite(directWriteFontFace,
pixelSize,
fontEngineData);
@@ -802,7 +894,7 @@ QString QWindowsFontDatabaseBase::familyForStyleHint(QFont::StyleHint styleHint)
default:
break;
}
- return QStringLiteral("MS Shell Dlg 2");
+ return QStringLiteral("Tahoma");
}
// Creation functions
diff --git a/src/gui/text/windows/qwindowsfontdatabasebase_p.h b/src/gui/text/windows/qwindowsfontdatabasebase_p.h
index 60acc5cb06..55a3363551 100644
--- a/src/gui/text/windows/qwindowsfontdatabasebase_p.h
+++ b/src/gui/text/windows/qwindowsfontdatabasebase_p.h
@@ -29,6 +29,10 @@
QT_BEGIN_NAMESPACE
+#if QT_CONFIG(directwrite)
+ class QCustomFontFileLoader;
+#endif
+
class QWindowsFontEngineData
{
Q_DISABLE_COPY_MOVE(QWindowsFontEngineData)
@@ -56,6 +60,8 @@ public:
QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override;
QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override;
+ void invalidate() override;
+
static int defaultVerticalDPI();
static QSharedPointer<QWindowsFontEngineData> data();
@@ -91,11 +97,17 @@ public:
protected:
#if QT_CONFIG(directwrite)
- IDWriteFontFace *createDirectWriteFace(const QByteArray &fontData) const;
+ QList<IDWriteFontFace *> createDirectWriteFaces(const QByteArray &fontData,
+ bool queryVariations = true) const;
+ IDWriteFontFace *createDirectWriteFace(const QByteArray &fontData);
#endif
private:
static bool init(QSharedPointer<QWindowsFontEngineData> data);
+
+#if QT_CONFIG(directwrite)
+ mutable std::unique_ptr<QCustomFontFileLoader> m_fontFileLoader;
+#endif
};
QT_END_NAMESPACE
diff --git a/src/gui/text/windows/qwindowsfontengine.cpp b/src/gui/text/windows/qwindowsfontengine.cpp
index 5aef72eab3..5de80dc8a3 100644
--- a/src/gui/text/windows/qwindowsfontengine.cpp
+++ b/src/gui/text/windows/qwindowsfontengine.cpp
@@ -104,7 +104,7 @@ void QWindowsFontEngine::getCMap()
SelectObject(hdc, hfont);
bool symb = false;
if (ttf) {
- cmapTable = getSfntTable(MAKE_TAG('c', 'm', 'a', 'p'));
+ cmapTable = getSfntTable(QFont::Tag("cmap").value());
cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()),
cmapTable.size(), &symb, &cmapSize);
}
@@ -132,8 +132,9 @@ void QWindowsFontEngine::getCMap()
}
}
-int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs) const
+int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs, int *mappedGlyphs) const
{
+ *mappedGlyphs = 0;
int glyph_pos = 0;
{
if (symbol) {
@@ -143,6 +144,8 @@ int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLa
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
if (!glyphs->glyphs[glyph_pos] && uc < 0x100)
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000);
+ if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
+ (*mappedGlyphs)++;
++glyph_pos;
}
} else if (ttf) {
@@ -150,6 +153,8 @@ int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLa
while (it.hasNext()) {
const uint uc = it.next();
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
+ if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
+ (*mappedGlyphs)++;
++glyph_pos;
}
} else {
@@ -160,6 +165,8 @@ int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLa
glyphs->glyphs[glyph_pos] = uc;
else
glyphs->glyphs[glyph_pos] = 0;
+ if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
+ (*mappedGlyphs)++;
++glyph_pos;
}
}
@@ -259,7 +266,7 @@ HGDIOBJ QWindowsFontEngine::selectDesignFont() const
return SelectObject(m_fontEngineData->hdc, designFont);
}
-bool QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
+int QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
{
Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
if (*nglyphs < len) {
@@ -268,12 +275,13 @@ bool QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *g
}
glyphs->numGlyphs = *nglyphs;
- *nglyphs = getGlyphIndexes(str, len, glyphs);
+ int mappedGlyphs;
+ *nglyphs = getGlyphIndexes(str, len, glyphs, &mappedGlyphs);
if (!(flags & GlyphIndicesOnly))
recalcAdvances(glyphs, flags);
- return true;
+ return mappedGlyphs;
}
inline void calculateTTFGlyphWidth(HDC hdc, UINT glyph, int &width)
@@ -471,7 +479,7 @@ namespace {
QFixed QWindowsFontEngine::capHeight() const
{
- const QByteArray tableData = getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
+ const QByteArray tableData = getSfntTable(QFont::Tag("OS/2").value());
if (size_t(tableData.size()) >= sizeof(OS2Table)) {
const OS2Table *table = reinterpret_cast<const OS2Table *>(tableData.constData());
if (qFromBigEndian<quint16>(table->version) >= 2) {
@@ -1089,7 +1097,7 @@ QImage QWindowsFontEngine::alphaRGBMapForGlyph(glyph_t glyph,
QFontEngine *QWindowsFontEngine::cloneWithSize(qreal pixelSize) const
{
QFontDef request = fontDef;
- QString actualFontName = request.families.first();
+ QString actualFontName = request.families.constFirst();
if (!uniqueFamilyName.isEmpty())
request.families = QStringList(uniqueFamilyName);
request.pixelSize = pixelSize;
diff --git a/src/gui/text/windows/qwindowsfontengine_p.h b/src/gui/text/windows/qwindowsfontengine_p.h
index afe8ee4ca5..07f4db3c4a 100644
--- a/src/gui/text/windows/qwindowsfontengine_p.h
+++ b/src/gui/text/windows/qwindowsfontengine_p.h
@@ -48,7 +48,7 @@ public:
QFixed emSquareSize() const override;
glyph_t glyphIndex(uint ucs4) const override;
- bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
+ int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const override;
void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) override;
@@ -88,7 +88,7 @@ public:
bool hasUnreliableGlyphOutline() const override;
- int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs) const;
+ int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs, int *mappedGlyphs) const;
void getCMap();
bool getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const;
diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp
index 14dd064c33..47b8a7ee3c 100644
--- a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp
+++ b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp
@@ -12,10 +12,14 @@
#include <QtCore/private/qwinregistry_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
-#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtGui/qpainterpath.h>
-#include <dwrite_2.h>
+#if QT_CONFIG(directwrite3)
+# include "qwindowsdirectwritefontdatabase_p.h"
+# include <dwrite_3.h>
+#else
+# include <dwrite_2.h>
+#endif
#include <d2d1.h>
@@ -158,10 +162,13 @@ static DWRITE_MEASURING_MODE renderModeToMeasureMode(DWRITE_RENDERING_MODE rende
}
}
-static DWRITE_RENDERING_MODE hintingPreferenceToRenderingMode(const QFontDef &fontDef)
+DWRITE_RENDERING_MODE QWindowsFontEngineDirectWrite::hintingPreferenceToRenderingMode(const QFontDef &fontDef) const
{
+ if ((fontDef.styleStrategy & QFont::NoAntialias) && glyphFormat != QFontEngine::Format_ARGB)
+ return DWRITE_RENDERING_MODE_ALIASED;
+
QFont::HintingPreference hintingPreference = QFont::HintingPreference(fontDef.hintingPreference);
- if (QHighDpiScaling::isActive() && hintingPreference == QFont::PreferDefaultHinting) {
+ if (!qFuzzyCompare(qApp->devicePixelRatio(), 1.0) && hintingPreference == QFont::PreferDefaultHinting) {
// Microsoft documentation recommends using asymmetric rendering for small fonts
// at pixel size 16 and less, and symmetric for larger fonts.
hintingPreference = fontDef.pixelSize > 16.0
@@ -212,7 +219,7 @@ QWindowsFontEngineDirectWrite::QWindowsFontEngineDirectWrite(IDWriteFontFace *di
fontDef.pixelSize = pixelSize;
collectMetrics();
- cache_cost = (m_ascent.toInt() + m_descent.toInt()) * m_xHeight.toInt() * 2000;
+ cache_cost = m_xHeight.toInt() * m_xHeight.toInt() * 2000;
}
QWindowsFontEngineDirectWrite::~QWindowsFontEngineDirectWrite()
@@ -354,12 +361,14 @@ void QWindowsFontEngineDirectWrite::collectMetrics()
fontFile->Release();
}
- QByteArray table = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a'));
+ QByteArray table = getSfntTable(QFont::Tag("hhea").value());
const int advanceWidthMaxLocation = 10;
if (table.size() >= advanceWidthMaxLocation + int(sizeof(quint16))) {
quint16 advanceWidthMax = qFromBigEndian<quint16>(table.constData() + advanceWidthMaxLocation);
m_maxAdvanceWidth = DESIGN_TO_LOGICAL(advanceWidthMax);
}
+
+ loadKerningPairs(emSquareSize() / QFixed::fromReal(fontDef.pixelSize));
}
QFixed QWindowsFontEngineDirectWrite::underlinePosition() const
@@ -426,13 +435,13 @@ glyph_t QWindowsFontEngineDirectWrite::glyphIndex(uint ucs4) const
return glyphIndex;
}
-bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
- int *nglyphs, QFontEngine::ShaperFlags flags) const
+int QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
+ int *nglyphs, QFontEngine::ShaperFlags flags) const
{
Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
if (*nglyphs < len) {
*nglyphs = len;
- return false;
+ return -1;
}
QVarLengthArray<UINT32> codePoints(len);
@@ -446,11 +455,15 @@ bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGly
glyphIndices.data());
if (FAILED(hr)) {
qErrnoWarning("%s: GetGlyphIndicesW failed", __FUNCTION__);
- return false;
+ return -1;
}
- for (int i = 0; i < actualLength; ++i)
+ int mappedGlyphs = 0;
+ for (int i = 0; i < actualLength; ++i) {
glyphs->glyphs[i] = glyphIndices.at(i);
+ if (glyphs->glyphs[i] != 0 || isIgnorableChar(codePoints.at(i)))
+ mappedGlyphs++;
+ }
*nglyphs = actualLength;
glyphs->numGlyphs = actualLength;
@@ -458,7 +471,7 @@ bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGly
if (!(flags & GlyphIndicesOnly))
recalcAdvances(glyphs, {});
- return true;
+ return mappedGlyphs;
}
QFontEngine::FaceId QWindowsFontEngineDirectWrite::faceId() const
@@ -466,7 +479,7 @@ QFontEngine::FaceId QWindowsFontEngineDirectWrite::faceId() const
return m_faceId;
}
-void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const
+void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags shaperFlags) const
{
QVarLengthArray<UINT16> glyphIndices(glyphs->numGlyphs);
@@ -478,11 +491,14 @@ void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEn
HRESULT hr;
DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(fontDef);
- if (renderMode == DWRITE_RENDERING_MODE_GDI_CLASSIC || renderMode == DWRITE_RENDERING_MODE_GDI_NATURAL) {
+ bool needsDesignMetrics = shaperFlags & QFontEngine::DesignMetrics;
+ if (!needsDesignMetrics && (renderMode == DWRITE_RENDERING_MODE_GDI_CLASSIC
+ || renderMode == DWRITE_RENDERING_MODE_GDI_NATURAL
+ || renderMode == DWRITE_RENDERING_MODE_ALIASED)) {
hr = m_directWriteFontFace->GetGdiCompatibleGlyphMetrics(float(fontDef.pixelSize),
1.0f,
NULL,
- TRUE,
+ renderMode == DWRITE_RENDERING_MODE_GDI_NATURAL,
glyphIndices.data(),
glyphIndices.size(),
glyphMetrics.data());
@@ -586,7 +602,9 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(const QGlyphLayout &g
for (int i = 0; i < glyphs.numGlyphs; ++i)
w += glyphs.effectiveAdvance(i);
- return glyph_metrics_t(0, -ascent(), w - lastRightBearing(glyphs), ascent() + descent(), w, 0);
+ const QFixed leftBearing = firstLeftBearing(glyphs);
+ return glyph_metrics_t(leftBearing, -ascent(), w - leftBearing - lastRightBearing(glyphs),
+ ascent() + descent(), w, 0);
}
glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(glyph_t g)
@@ -665,7 +683,10 @@ QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph,
bool QWindowsFontEngineDirectWrite::supportsHorizontalSubPixelPositions() const
{
- return true;
+ DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(fontDef);
+ return (renderMode != DWRITE_RENDERING_MODE_GDI_CLASSIC
+ && renderMode != DWRITE_RENDERING_MODE_GDI_NATURAL
+ && renderMode != DWRITE_RENDERING_MODE_ALIASED);
}
QFontEngine::Properties QWindowsFontEngineDirectWrite::properties() const
@@ -768,7 +789,10 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
if (SUCCEEDED(hr)) {
RECT rect;
- glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
+ glyphAnalysis->GetAlphaTextureBounds(renderMode == DWRITE_RENDERING_MODE_ALIASED
+ ? DWRITE_TEXTURE_ALIASED_1x1
+ : DWRITE_TEXTURE_CLEARTYPE_3x1,
+ &rect);
if (rect.top == rect.bottom || rect.left == rect.right)
return QImage();
@@ -849,7 +873,8 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
b,
a,
colorGlyphsAnalysis,
- boundingRect);
+ boundingRect,
+ renderMode);
}
colorGlyphsAnalysis->Release();
@@ -876,7 +901,8 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
b,
a,
glyphAnalysis,
- boundingRect);
+ boundingRect,
+ renderMode);
}
glyphAnalysis->Release();
@@ -894,7 +920,8 @@ void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination,
float b,
float a,
IDWriteGlyphRunAnalysis *glyphAnalysis,
- const QRect &boundingRect)
+ const QRect &boundingRect,
+ DWRITE_RENDERING_MODE renderMode)
{
const int width = destination->width();
const int height = destination->height();
@@ -915,12 +942,14 @@ void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination,
BYTE *alphaValues = alphaValueArray.data();
memset(alphaValues, 0, size);
- HRESULT hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1,
+ HRESULT hr = glyphAnalysis->CreateAlphaTexture(renderMode == DWRITE_RENDERING_MODE_ALIASED
+ ? DWRITE_TEXTURE_ALIASED_1x1
+ : DWRITE_TEXTURE_CLEARTYPE_3x1,
&rect,
alphaValues,
size);
if (SUCCEEDED(hr)) {
- if (destination->hasAlphaChannel()) {
+ if (destination->hasAlphaChannel()) { // Color glyphs
for (int y = 0; y < height; ++y) {
uint *dest = reinterpret_cast<uint *>(destination->scanLine(y));
BYTE *src = alphaValues + width * 3 * y;
@@ -938,7 +967,16 @@ void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination,
qRound(qAlpha(currentRgb) * (1.0 - averageAlpha) + averageAlpha * 255));
}
}
+ } else if (renderMode == DWRITE_RENDERING_MODE_ALIASED) {
+ for (int y = 0; y < height; ++y) {
+ uint *dest = reinterpret_cast<uint *>(destination->scanLine(y));
+ BYTE *src = alphaValues + width * y;
+ for (int x = 0; x < width; ++x) {
+ int alpha = *(src++);
+ dest[x] = (alpha << 16) + (alpha << 8) + alpha;
+ }
+ }
} else {
for (int y = 0; y < height; ++y) {
uint *dest = reinterpret_cast<uint *>(destination->scanLine(y));
@@ -1007,6 +1045,27 @@ void QWindowsFontEngineDirectWrite::initFontInfo(const QFontDef &request,
fontDef.pointSize = fontDef.pixelSize * 72. / dpi;
else if (fontDef.pixelSize == -1)
fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.);
+
+ m_faceId.variableAxes = request.variableAxisValues;
+
+#if QT_CONFIG(directwrite3)
+ IDWriteFontFace3 *face3 = nullptr;
+ if (SUCCEEDED(m_directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace3),
+ reinterpret_cast<void **>(&face3)))) {
+ IDWriteLocalizedStrings *names;
+ if (SUCCEEDED(face3->GetFaceNames(&names))) {
+ wchar_t englishLocale[] = L"en-us";
+ fontDef.styleName = QWindowsDirectWriteFontDatabase::localeString(names, englishLocale);
+ names->Release();
+ }
+
+ // Color font
+ if (face3->GetPaletteEntryCount() > 0)
+ glyphFormat = QFontEngine::Format_ARGB;
+
+ face3->Release();
+ }
+#endif
}
QString QWindowsFontEngineDirectWrite::fontNameSubstitute(const QString &familyName)
@@ -1092,7 +1151,7 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph
if (SUCCEEDED(hr)) {
RECT rect;
- glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
+ glyphAnalysis->GetAlphaTextureBounds(renderMode == DWRITE_RENDERING_MODE_ALIASED ? DWRITE_TEXTURE_ALIASED_1x1 : DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
glyphAnalysis->Release();
int margin = glyphMargin(format);
diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h b/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h
index df6df1ad17..d7c9a79267 100644
--- a/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h
+++ b/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h
@@ -22,6 +22,7 @@ QT_REQUIRE_CONFIG(directwrite);
#include <QtGui/private/qfontengine_p.h>
#include <QtCore/QSharedPointer>
+#include <dwrite.h>
struct IDWriteFont;
struct IDWriteFontFace;
@@ -52,8 +53,8 @@ public:
QFixed emSquareSize() const override;
glyph_t glyphIndex(uint ucs4) const override;
- bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
- ShaperFlags flags) const override;
+ int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
+ ShaperFlags flags) const override;
void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const override;
void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
@@ -108,8 +109,16 @@ private:
const QTransform &xform,
const QColor &color = QColor());
void collectMetrics();
- void renderGlyphRun(QImage *destination, float r, float g, float b, float a, IDWriteGlyphRunAnalysis *glyphAnalysis, const QRect &boundingRect);
+ void renderGlyphRun(QImage *destination,
+ float r,
+ float g,
+ float b,
+ float a,
+ IDWriteGlyphRunAnalysis *glyphAnalysis,
+ const QRect &boundingRect,
+ DWRITE_RENDERING_MODE renderMode);
static QString filenameFromFontFile(IDWriteFontFile *fontFile);
+ DWRITE_RENDERING_MODE hintingPreferenceToRenderingMode(const QFontDef &fontDef) const;
const QSharedPointer<QWindowsFontEngineData> m_fontEngineData;
diff --git a/src/gui/util/qastchandler.cpp b/src/gui/util/qastchandler.cpp
index f5c1d84f91..ec8b92f557 100644
--- a/src/gui/util/qastchandler.cpp
+++ b/src/gui/util/qastchandler.cpp
@@ -109,9 +109,9 @@ QTextureFileData QAstcHandler::read()
int zBlocks = (zSz + header->blockDimZ - 1) / header->blockDimZ;
int byteCount = 0;
- bool oob = mul_overflow(xBlocks, yBlocks, &byteCount)
- || mul_overflow(byteCount, zBlocks, &byteCount)
- || mul_overflow(byteCount, 16, &byteCount);
+ bool oob = qMulOverflow(xBlocks, yBlocks, &byteCount)
+ || qMulOverflow(byteCount, zBlocks, &byteCount)
+ || qMulOverflow(byteCount, 16, &byteCount);
res.setDataOffset(sizeof(AstcHeader));
diff --git a/src/gui/util/qdesktopservices.cpp b/src/gui/util/qdesktopservices.cpp
index 4a12f6db6f..379d18dd60 100644
--- a/src/gui/util/qdesktopservices.cpp
+++ b/src/gui/util/qdesktopservices.cpp
@@ -238,10 +238,11 @@ bool QDesktopServices::openUrl(const QUrl &url)
the destruction of the handler object does not overlap with concurrent
invocations of openUrl() using it.
- \section1 iOS
+ \section1 iOS and \macos
- To use this function for receiving data from other apps on iOS you also need to
- add the custom scheme to the \c CFBundleURLSchemes list in your Info.plist file:
+ To use this function for receiving data from other apps on iOS/\macos
+ you also need to add the custom scheme to the \c CFBundleURLSchemes
+ list in your Info.plist file:
\snippet code/src_gui_util_qdesktopservices.cpp 4
@@ -256,7 +257,7 @@ bool QDesktopServices::openUrl(const QUrl &url)
\snippet code/src_gui_util_qdesktopservices.cpp 7
- iOS will search for /.well-known/apple-app-site-association on your domain,
+ iOS/\macos will search for /.well-known/apple-app-site-association on your domain,
when the application is installed. If you want to listen to
\c{https://your.domain.com/help?topic=ABCDEF} you need to provide the following
content there:
diff --git a/src/gui/util/qgraphicsframecapture.cpp b/src/gui/util/qgraphicsframecapture.cpp
new file mode 100644
index 0000000000..e49fb83008
--- /dev/null
+++ b/src/gui/util/qgraphicsframecapture.cpp
@@ -0,0 +1,123 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qgraphicsframecapture_p.h"
+#if (defined (Q_OS_WIN) || defined(Q_OS_LINUX)) && QT_CONFIG(library)
+#include "qgraphicsframecapturerenderdoc_p_p.h"
+#elif QT_CONFIG(metal)
+#include "qgraphicsframecapturemetal_p_p.h"
+#else
+#include "qgraphicsframecapture_p_p.h"
+#endif
+
+#include <QtCore/qstandardpaths.h>
+#include <QtCore/qcoreapplication.h>
+
+QT_BEGIN_NAMESPACE
+
+QGraphicsFrameCapturePrivate::QGraphicsFrameCapturePrivate()
+ : m_capturePath(QStandardPaths::writableLocation(QStandardPaths::TempLocation) +
+ QStringLiteral("/") + QCoreApplication::applicationName() +
+ QStringLiteral("/captures")),
+ m_capturePrefix(QCoreApplication::applicationName())
+{
+
+}
+
+QGraphicsFrameCapture::QGraphicsFrameCapture()
+{
+#if (defined (Q_OS_WIN) || defined(Q_OS_LINUX)) && QT_CONFIG(library)
+ d.reset(new QGraphicsFrameCaptureRenderDoc);
+#elif QT_CONFIG(metal)
+ d.reset(new QGraphicsFrameCaptureMetal);
+#endif
+}
+
+QGraphicsFrameCapture::~QGraphicsFrameCapture()
+{
+
+}
+
+void QGraphicsFrameCapture::setRhi(QRhi *rhi)
+{
+ if (!d.isNull())
+ d->setRhi(rhi);
+}
+
+void QGraphicsFrameCapture::startCaptureFrame()
+{
+ if (!d.isNull())
+ d->startCaptureFrame();
+}
+
+void QGraphicsFrameCapture::endCaptureFrame()
+{
+ if (!d.isNull())
+ d->endCaptureFrame();
+}
+
+QString QGraphicsFrameCapture::capturePath() const
+{
+ if (!d.isNull())
+ return d->capturePath();
+ return QString();
+}
+
+void QGraphicsFrameCapture::setCapturePath(const QString &path)
+{
+ if (!d.isNull())
+ d->setCapturePath(path);
+}
+
+QString QGraphicsFrameCapture::capturePrefix() const
+{
+ if (!d.isNull())
+ return d->capturePrefix();
+ return QString();
+}
+
+void QGraphicsFrameCapture::setCapturePrefix(const QString &prefix)
+{
+ if (!d.isNull())
+ d->setCapturePrefix(prefix);
+}
+
+QString QGraphicsFrameCapture::capturedFileName()
+{
+ if (!d.isNull())
+ return d->capturedFileName();
+
+ return QString();
+}
+
+QStringList QGraphicsFrameCapture::capturedFilesNames()
+{
+ if (!d.isNull())
+ return d->capturedFilesNames();
+
+ return QStringList();
+}
+
+bool QGraphicsFrameCapture::isLoaded() const
+{
+ if (!d.isNull())
+ return d->initialized();
+
+ return false;
+}
+
+bool QGraphicsFrameCapture::isCapturing() const
+{
+ if (!d.isNull())
+ return d->isCapturing();
+
+ return false;
+}
+
+void QGraphicsFrameCapture::openCapture() const
+{
+ if (!d.isNull())
+ d->openCapture();
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/util/qgraphicsframecapture_p.h b/src/gui/util/qgraphicsframecapture_p.h
new file mode 100644
index 0000000000..fef37d2869
--- /dev/null
+++ b/src/gui/util/qgraphicsframecapture_p.h
@@ -0,0 +1,55 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QGRAPHICSFRAMECAPTURE_P_H
+#define QGRAPHICSFRAMECAPTURE_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/qscopedpointer.h>
+#include <QtGui/qtguiglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsFrameCapturePrivate;
+class QRhi;
+
+class Q_GUI_EXPORT QGraphicsFrameCapture
+{
+public:
+ QGraphicsFrameCapture();
+ ~QGraphicsFrameCapture();
+
+ void setRhi(QRhi *rhi);
+ void startCaptureFrame();
+ void endCaptureFrame();
+
+ QString capturePath() const;
+ void setCapturePath(const QString &path);
+
+ QString capturePrefix() const;
+ void setCapturePrefix(const QString &prefix);
+
+ QString capturedFileName();
+ QStringList capturedFilesNames();
+
+ bool isLoaded() const;
+ bool isCapturing() const;
+ void openCapture() const;
+
+private:
+ QScopedPointer<QGraphicsFrameCapturePrivate> d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGRAPHICSFRAMECAPTURE_P_H
diff --git a/src/gui/util/qgraphicsframecapture_p_p.h b/src/gui/util/qgraphicsframecapture_p_p.h
new file mode 100644
index 0000000000..f8dbd2ca1d
--- /dev/null
+++ b/src/gui/util/qgraphicsframecapture_p_p.h
@@ -0,0 +1,67 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QGRAPHICSFRAMECAPTURE_P_P_H
+#define QGRAPHICSFRAMECAPTURE_P_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/qnamespace.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qstringlist.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcGraphicsFrameCapture)
+
+class QRhi;
+struct QRhiNativeHandles;
+
+class QGraphicsFrameCapturePrivate
+{
+public:
+ QGraphicsFrameCapturePrivate() ;
+ virtual ~QGraphicsFrameCapturePrivate() = default;
+
+ virtual void setRhi(QRhi *rhi) = 0;
+ virtual void startCaptureFrame() = 0;
+ virtual void endCaptureFrame() = 0;
+
+ QString capturePath() const { return m_capturePath; };
+ virtual void setCapturePath(const QString &path) { m_capturePath = path; }
+
+ QString capturePrefix() const { return m_capturePrefix; }
+ virtual void setCapturePrefix(const QString &prefix) { m_capturePrefix = prefix; }
+
+ virtual QString capturedFileName() const
+ {
+ return !m_capturedFilesNames.isEmpty() ? m_capturedFilesNames.last() : QString();
+ }
+ virtual QStringList capturedFilesNames() const { return m_capturedFilesNames; }
+
+ virtual bool initialized() const = 0;
+ virtual bool isCapturing() const = 0;
+ virtual void openCapture() = 0;
+
+protected:
+ QRhi *m_rhi = nullptr;
+ QRhiNativeHandles *m_rhiHandles = nullptr;
+ void *m_nativeHandle = nullptr;
+ QString m_capturePath;
+ QString m_capturePrefix;
+ QStringList m_capturedFilesNames;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGRAPHICSFRAMECAPTURE_P_P_H
diff --git a/src/gui/util/qgraphicsframecapturemetal.mm b/src/gui/util/qgraphicsframecapturemetal.mm
new file mode 100644
index 0000000000..b0ff0bab2b
--- /dev/null
+++ b/src/gui/util/qgraphicsframecapturemetal.mm
@@ -0,0 +1,169 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qgraphicsframecapturemetal_p_p.h"
+#include <QtCore/qurl.h>
+#include "Metal/Metal.h"
+#include "qglobal.h"
+#include <QtGui/rhi/qrhi.h>
+#include <QtGui/rhi/qrhi_platform.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcGraphicsFrameCapture, "qt.gui.graphicsframecapture")
+
+#if __has_feature(objc_arc)
+#error ARC not supported
+#endif
+
+uint QGraphicsFrameCaptureMetal::frameNumber = 0;
+
+QGraphicsFrameCaptureMetal::QGraphicsFrameCaptureMetal()
+{
+ qputenv("METAL_CAPTURE_ENABLED", QByteArrayLiteral("1"));
+
+ m_captureDescriptor = [MTLCaptureDescriptor new];
+}
+
+QGraphicsFrameCaptureMetal::~QGraphicsFrameCaptureMetal()
+{
+#if defined(Q_OS_MACOS) && QT_CONFIG(process)
+ if (m_process) {
+ m_process->terminate();
+ delete m_process;
+ }
+#endif
+ [m_captureDescriptor release];
+}
+
+void QGraphicsFrameCaptureMetal::setRhi(QRhi *rhi)
+{
+ if (!rhi)
+ return;
+
+ QRhi::Implementation backend = rhi->backend();
+ const QRhiNativeHandles *nh = rhi->nativeHandles();
+
+ switch (backend) {
+ case QRhi::Implementation::Metal: {
+ const QRhiMetalNativeHandles *mtlnh = static_cast<const QRhiMetalNativeHandles *>(nh);
+ if (mtlnh->cmdQueue) {
+ m_captureDescriptor.captureObject = mtlnh->cmdQueue;
+ } else if (mtlnh->dev) {
+ m_captureDescriptor.captureObject = mtlnh->dev;
+ } else {
+ qCWarning(lcGraphicsFrameCapture) << "No valid Metal Device or Metal Command Queue found";
+ m_initialized = false;
+ return;
+ }
+ break;
+ }
+ default: {
+ qCWarning(lcGraphicsFrameCapture) << "Invalid handles were provided. MTLCaptureManager works only with Metal API";
+ m_initialized = false;
+ return;
+ break;
+ }
+ }
+
+ if (!m_captureManager) {
+ m_captureManager = MTLCaptureManager.sharedCaptureManager;
+ bool supportDocs = [m_captureManager supportsDestination:MTLCaptureDestinationGPUTraceDocument];
+ if (supportDocs) {
+ m_captureDescriptor.destination = MTLCaptureDestinationGPUTraceDocument;
+ m_initialized = true;
+ }
+ }
+}
+
+void QGraphicsFrameCaptureMetal::startCaptureFrame()
+{
+ if (!initialized()) {
+ qCWarning(lcGraphicsFrameCapture) << "Capturing on Metal was not initialized. Starting capturing can not be done.";
+ return;
+ }
+
+ if (isCapturing()) {
+ qCWarning(lcGraphicsFrameCapture) << "A frame capture is already in progress,"
+ "will not initiate another one until QGraphicsFrameCapture::endCaptureFrame is called.";
+ return;
+ }
+
+ updateCaptureFileName();
+ NSError *error;
+ if (![m_captureManager startCaptureWithDescriptor:m_captureDescriptor error:&error]) {
+ QString errorMsg = QString::fromNSString(error.localizedDescription);
+ qCWarning(lcGraphicsFrameCapture, "Failed to start capture : %s", qPrintable(errorMsg));
+ }
+}
+
+void QGraphicsFrameCaptureMetal::endCaptureFrame()
+{
+ if (!initialized()) {
+ qCWarning(lcGraphicsFrameCapture) << "Capturing on Metal was not initialized. End capturing can not be done.";
+ return;
+ }
+
+ if (!isCapturing()) {
+ qCWarning(lcGraphicsFrameCapture) << "A call to QGraphicsFrameCapture::endCaptureFrame can not be done"
+ " without a call to QGraphicsFrameCapture::startCaptureFrame";
+ return;
+ }
+
+ [m_captureManager stopCapture];
+ m_capturedFilesNames.append(QString::fromNSString(m_traceURL.path));
+ frameNumber++;
+}
+
+bool QGraphicsFrameCaptureMetal::initialized() const
+{
+ return m_initialized;
+}
+
+bool QGraphicsFrameCaptureMetal::isCapturing() const
+{
+ if (!initialized()) {
+ qCWarning(lcGraphicsFrameCapture) << "Capturing on Metal was not initialized. Can not query if capturing is in progress or not.";
+ return false;
+ }
+
+ return [m_captureManager isCapturing];
+}
+
+void QGraphicsFrameCaptureMetal::openCapture()
+{
+#if defined(Q_OS_MACOS)
+#if !QT_CONFIG(process)
+ qFatal("QGraphicsFrameCapture requires QProcess on macOS");
+#else
+ if (!initialized()) {
+ qCWarning(lcGraphicsFrameCapture) << "Capturing on Metal was not initialized. Can not open XCode with a valid capture.";
+ return;
+ }
+
+ if (!m_process) {
+ m_process = new QProcess();
+ m_process->setProgram(QStringLiteral("xed"));
+ QStringList args;
+ args.append(QUrl::fromNSURL(m_traceURL).toLocalFile());
+ m_process->setArguments(args);
+ }
+
+ m_process->kill();
+ m_process->start();
+#endif
+#endif
+}
+
+void QGraphicsFrameCaptureMetal::updateCaptureFileName()
+{
+ m_traceURL = QUrl::fromLocalFile(m_capturePath + "/" + m_capturePrefix + "_" + QString::number(frameNumber) + ".gputrace").toNSURL();
+ // We need to remove the trace file if it already existed else MTLCaptureManager
+ // will fail to.
+ if ([NSFileManager.defaultManager fileExistsAtPath:m_traceURL.path])
+ [NSFileManager.defaultManager removeItemAtURL:m_traceURL error:nil];
+
+ m_captureDescriptor.outputURL = m_traceURL;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/util/qgraphicsframecapturemetal_p_p.h b/src/gui/util/qgraphicsframecapturemetal_p_p.h
new file mode 100644
index 0000000000..d703949de2
--- /dev/null
+++ b/src/gui/util/qgraphicsframecapturemetal_p_p.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QGRAPHICSFRAMEDECAPTUREMETAL_P_P_H
+#define QGRAPHICSFRAMEDECAPTUREMETAL_P_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 "qgraphicsframecapture_p_p.h"
+#include <QtCore/qmutex.h>
+#ifdef Q_OS_MACOS
+#include <QtCore/qprocess.h>
+#endif
+
+Q_FORWARD_DECLARE_OBJC_CLASS(MTLCaptureManager);
+Q_FORWARD_DECLARE_OBJC_CLASS(MTLCaptureDescriptor);
+Q_FORWARD_DECLARE_OBJC_CLASS(NSURL);
+
+QT_BEGIN_NAMESPACE
+
+class QGraphicsFrameCaptureMetal : public QGraphicsFrameCapturePrivate
+{
+public:
+ QGraphicsFrameCaptureMetal();
+ ~QGraphicsFrameCaptureMetal();
+
+ void setRhi(QRhi *rhi) override;
+ void startCaptureFrame() override;
+ void endCaptureFrame() override;
+ bool initialized() const override;
+ bool isCapturing() const override;
+ void openCapture() override;
+
+private:
+ void updateCaptureFileName();
+#if defined(Q_OS_MACOS) && QT_CONFIG(process)
+ QProcess *m_process = nullptr;
+#endif
+ MTLCaptureManager *m_captureManager = nullptr;
+ MTLCaptureDescriptor *m_captureDescriptor = nullptr;
+ NSURL *m_traceURL = nullptr;
+ bool m_initialized = false;
+ static uint frameNumber;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGRAPHICSFRAMEDECAPTUREMETAL_P_P_H
diff --git a/src/gui/util/qgraphicsframecapturerenderdoc.cpp b/src/gui/util/qgraphicsframecapturerenderdoc.cpp
new file mode 100644
index 0000000000..88ba9d839f
--- /dev/null
+++ b/src/gui/util/qgraphicsframecapturerenderdoc.cpp
@@ -0,0 +1,310 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qgraphicsframecapturerenderdoc_p_p.h"
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qlibrary.h>
+#include <QtCore/qmutex.h>
+#include "QtGui/rhi/qrhi.h"
+#include "QtGui/rhi/qrhi_platform.h"
+#include "QtGui/qopenglcontext.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcGraphicsFrameCapture, "qt.gui.graphicsframecapture")
+
+RENDERDOC_API_1_6_0 *QGraphicsFrameCaptureRenderDoc::s_rdocApi = nullptr;
+#if QT_CONFIG(thread)
+QBasicMutex QGraphicsFrameCaptureRenderDoc::s_frameCaptureMutex;
+#endif
+
+#if QT_CONFIG(opengl)
+static void *glNativeContext(QOpenGLContext *context) {
+ void *nctx = nullptr;
+ if (context != nullptr && context->isValid()) {
+#ifdef Q_OS_WIN
+ nctx = context->nativeInterface<QNativeInterface::QWGLContext>()->nativeContext();
+#endif
+
+#ifdef Q_OS_LINUX
+#if QT_CONFIG(egl)
+ QNativeInterface::QEGLContext *eglItf = context->nativeInterface<QNativeInterface::QEGLContext>();
+ if (eglItf)
+ nctx = eglItf->nativeContext();
+#endif
+
+#if QT_CONFIG(xcb_glx_plugin)
+ QNativeInterface::QGLXContext *glxItf = context->nativeInterface<QNativeInterface::QGLXContext>();
+ if (glxItf)
+ nctx = glxItf->nativeContext();
+#endif
+#endif
+
+#if QT_CONFIG(metal)
+ nctx = context->nativeInterface<QNativeInterface::QCocoaGLContext>()->nativeContext();
+#endif
+ }
+ return nctx;
+}
+#endif // QT_CONFIG(opengl)
+
+/*!
+ \class QGraphicsFrameCaptureRenderDoc
+ \internal
+ \brief The QGraphicsFrameCaptureRenderDoc class provides a way to capture a record of draw calls
+ for different graphics APIs.
+ \since 6.6
+ \inmodule QtGui
+
+ For applications that render using graphics APIs like Vulkan or OpenGL, it would be
+ convenient to have a way to check the draw calls done by the application. Specially
+ for applications that make a large amount of draw calls and the output is different
+ from what is expected.
+
+ This class acts as a wrapper over \l {https://renderdoc.org/}{RenderDoc} that allows
+ applications to capture a rendered frame either programmatically, by clicking a key
+ on the keyboard or both. The captured frame could be viewed later using RenderDoc GUI.
+
+ Read the \l {https://renderdoc.org/docs/index.html} {RenderDoc Documentation}
+ for more information.
+
+ \section1 API device handle
+
+ The functions that capture a frame like QGraphicsFrameCaptureRenderDoc::startCaptureFrame takes a device
+ pointer as argument. This pointer is unique for each graphics API and is associated
+ with the window that will be captured. This pointer has a default value of \c nullptr.
+ If no value is passed to the function the underlying API will try to find the device to
+ use, but it is not guaranteed specially in a multi-window applications.
+
+ For OpenGL, the pointer should be the OpenGL context on the platform OpenGL is being
+ used. For example, on Windows it should be \c HGLRC.
+
+ For Vulkan, the pointer should point to the dispatch table within the \c VkInstance.
+*/
+
+
+
+/*!
+ Creates a new object of this class. The constructor will load RenderDoc library
+ from the default path.
+
+ Only one instance of RenderDoc library is loaded at runtime which means creating
+ several instances of this class will not affect the RenderDoc initialization.
+*/
+
+QGraphicsFrameCaptureRenderDoc::QGraphicsFrameCaptureRenderDoc()
+ : m_nativeHandlesSet(false)
+{
+ if (!s_rdocApi)
+ init();
+}
+
+void QGraphicsFrameCaptureRenderDoc::setRhi(QRhi *rhi)
+{
+ if (!rhi)
+ return;
+
+ QRhi::Implementation backend = rhi->backend();
+ const QRhiNativeHandles *nh = rhi->nativeHandles();
+
+ switch (backend) {
+ case QRhi::Implementation::D3D11: {
+#ifdef Q_OS_WIN
+ const QRhiD3D11NativeHandles *d3d11nh = static_cast<const QRhiD3D11NativeHandles *>(nh);
+ m_nativeHandle = d3d11nh->dev;
+ break;
+#endif
+ qCWarning(lcGraphicsFrameCapture) << "Could not find valid handles for D3D11. Check platform support";
+ break;
+ }
+ case QRhi::Implementation::D3D12: {
+#ifdef Q_OS_WIN
+ const QRhiD3D12NativeHandles *d3d12nh = static_cast<const QRhiD3D12NativeHandles *>(nh);
+ m_nativeHandle = d3d12nh->dev;
+ break;
+#endif
+ qCWarning(lcGraphicsFrameCapture) << "Could not find valid handles for D3D12. Check platform support";
+ break;
+ }
+ case QRhi::Implementation::Vulkan: {
+#if QT_CONFIG(vulkan)
+ const QRhiVulkanNativeHandles *vknh = static_cast<const QRhiVulkanNativeHandles *>(nh);
+ m_nativeHandle = RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(vknh->inst->vkInstance());
+ break;
+#endif
+ qCWarning(lcGraphicsFrameCapture) << "Could not find valid handles for Vulkan. Check platform support";
+ break;
+ }
+ case QRhi::Implementation::OpenGLES2: {
+#ifndef QT_NO_OPENGL
+ const QRhiGles2NativeHandles *glnh = static_cast<const QRhiGles2NativeHandles *>(nh);
+ m_nativeHandle = glNativeContext(glnh->context);
+ if (m_nativeHandle)
+ break;
+#endif
+ qCWarning(lcGraphicsFrameCapture) << "Could not find valid handles for OpenGL. Check platform support";
+ break;
+ }
+ case QRhi::Implementation::Metal:
+ case QRhi::Implementation::Null:
+ qCWarning(lcGraphicsFrameCapture) << "Invalid handles were provided."
+ " Metal and Null backends are not supported with RenderDoc";
+ break;
+ }
+
+ if (m_nativeHandle)
+ m_nativeHandlesSet = true;
+}
+
+/*!
+ Starts a frame capture using the set native handles provided through QGraphicsFrameCaptureRenderDoc::setRhi
+ \a device. This function must be called before QGraphicsFrameCaptureRenderDoc::endCaptureFrame.
+ \sa {API device handle}
+*/
+void QGraphicsFrameCaptureRenderDoc::startCaptureFrame()
+{
+
+ if (!initialized()) {
+ qCWarning(lcGraphicsFrameCapture) << "RenderDoc was not initialized."
+ " Starting capturing can not be done.";
+ return;
+ }
+
+#if QT_CONFIG(thread)
+ // There is a single instance of RenderDoc library and it needs mutex for multithreading access.
+ QMutexLocker locker(&s_frameCaptureMutex);
+#endif
+ if (s_rdocApi->IsFrameCapturing()) {
+ qCWarning(lcGraphicsFrameCapture) << "A frame capture is already in progress, "
+ "will not initiate another one until"
+ " QGraphicsFrameCapture::endCaptureFrame is called.";
+ return;
+ }
+
+ qCInfo(lcGraphicsFrameCapture) << "A frame capture is going to start.";
+ updateCapturePathAndTemplate();
+ s_rdocApi->StartFrameCapture(m_nativeHandle, nullptr);
+}
+
+/*!
+ Ends a frame capture started by a call to QGraphicsFrameCaptureRenderDoc::startCaptureFrame
+ using the set native handles provided through QGraphicsFrameCaptureRenderDoc::setRhi.
+ This function must be called after QGraphicsFrameCaptureRenderDoc::startCaptureFrame.
+ Otherwise, a warning message will be printend and nothing will happen.
+ \sa {API device handle}
+*/
+void QGraphicsFrameCaptureRenderDoc::endCaptureFrame()
+{
+ if (!initialized()) {
+ qCWarning(lcGraphicsFrameCapture) << "RenderDoc was not initialized."
+ " End capturing can not be done.";
+ return;
+ }
+
+#if QT_CONFIG(thread)
+ // There is a single instance of RenderDoc library and it needs mutex for multithreading access.
+ QMutexLocker locker(&s_frameCaptureMutex);
+#endif
+ if (!s_rdocApi->IsFrameCapturing()) {
+ qCWarning(lcGraphicsFrameCapture) << "A call to QGraphicsFrameCapture::endCaptureFrame can not be done"
+ " without a call to QGraphicsFrameCapture::startCaptureFrame";
+ return;
+ }
+
+ qCInfo(lcGraphicsFrameCapture) << "A frame capture is going to end.";
+ uint32_t result = s_rdocApi->EndFrameCapture(m_nativeHandle, nullptr);
+
+ if (result) {
+ uint32_t count = s_rdocApi->GetNumCaptures();
+ uint32_t pathLength = 0;
+ s_rdocApi->GetCapture(count - 1, nullptr, &pathLength, nullptr);
+ if (pathLength > 0) {
+ QVarLengthArray<char> name(pathLength, 0);
+ s_rdocApi->GetCapture(count - 1, name.data(), &pathLength, nullptr);
+ m_capturedFilesNames.append(QString::fromUtf8(name.data(), -1));
+ }
+ }
+}
+
+void QGraphicsFrameCaptureRenderDoc::updateCapturePathAndTemplate()
+{
+ if (!initialized()) {
+ qCWarning(lcGraphicsFrameCapture) << "RenderDoc was not initialized."
+ " Updating save location can not be done.";
+ return;
+ }
+
+
+ QString rdocFilePathTemplate = m_capturePath + QStringLiteral("/") + m_capturePrefix;
+ s_rdocApi->SetCaptureFilePathTemplate(rdocFilePathTemplate.toUtf8().constData());
+}
+
+/*!
+ Returns true if the API is loaded and can capture frames or not.
+*/
+bool QGraphicsFrameCaptureRenderDoc::initialized() const
+{
+ return s_rdocApi && m_nativeHandlesSet;
+}
+
+bool QGraphicsFrameCaptureRenderDoc::isCapturing() const
+{
+ if (!initialized()) {
+ qCWarning(lcGraphicsFrameCapture) << "RenderDoc was not initialized."
+ " Can not query if capturing is in progress or not.";
+ return false;
+ }
+
+ return s_rdocApi->IsFrameCapturing();
+}
+
+void QGraphicsFrameCaptureRenderDoc::openCapture()
+{
+ if (!initialized()) {
+ qCWarning(lcGraphicsFrameCapture) << "RenderDoc was not initialized."
+ " Can not open RenderDoc UI tool.";
+ return;
+ }
+
+#if QT_CONFIG(thread)
+ // There is a single instance of RenderDoc library and it needs mutex for multithreading access.
+ QMutexLocker locker(&s_frameCaptureMutex);
+#endif
+ if (s_rdocApi->IsTargetControlConnected())
+ s_rdocApi->ShowReplayUI();
+ else
+ s_rdocApi->LaunchReplayUI(1, nullptr);
+}
+
+void QGraphicsFrameCaptureRenderDoc::init()
+{
+#if QT_CONFIG(thread)
+ // There is a single instance of RenderDoc library and it needs mutex for multithreading access.
+ QMutexLocker locker(&s_frameCaptureMutex);
+#endif
+
+ QLibrary renderDocLib(QStringLiteral("renderdoc"));
+ pRENDERDOC_GetAPI RENDERDOC_GetAPI = (pRENDERDOC_GetAPI) renderDocLib.resolve("RENDERDOC_GetAPI");
+ if (!renderDocLib.isLoaded() || (RENDERDOC_GetAPI == nullptr)) {
+ qCWarning(lcGraphicsFrameCapture) << renderDocLib.errorString().toLatin1();
+ return;
+ }
+
+ int ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_6_0, static_cast<void **>(static_cast<void *>(&s_rdocApi)));
+
+ if (ret == 0) {
+ qCWarning(lcGraphicsFrameCapture) << "The requested RenderDoc API is invalid or not supported";
+ return;
+ }
+
+ s_rdocApi->MaskOverlayBits(RENDERDOC_OverlayBits::eRENDERDOC_Overlay_None,
+ RENDERDOC_OverlayBits::eRENDERDOC_Overlay_None);
+ s_rdocApi->SetCaptureKeys(nullptr, 0);
+ s_rdocApi->SetFocusToggleKeys(nullptr, 0);
+
+ QString rdocFilePathTemplate = m_capturePath + QStringLiteral("/") + m_capturePrefix;
+ s_rdocApi->SetCaptureFilePathTemplate(rdocFilePathTemplate.toUtf8().constData());
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/util/qgraphicsframecapturerenderdoc_p_p.h b/src/gui/util/qgraphicsframecapturerenderdoc_p_p.h
new file mode 100644
index 0000000000..c0d92ea733
--- /dev/null
+++ b/src/gui/util/qgraphicsframecapturerenderdoc_p_p.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QGRAPHICSFRAMECAPTURERENDERDOC_P_P_H
+#define QGRAPHICSFRAMECAPTURERENDERDOC_P_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 <renderdoc_app.h>
+#include "qgraphicsframecapture_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#if QT_CONFIG(thread)
+class QBasicMutex;
+#endif
+
+class QGraphicsFrameCaptureRenderDoc : public QGraphicsFrameCapturePrivate
+{
+public:
+ QGraphicsFrameCaptureRenderDoc();
+ ~QGraphicsFrameCaptureRenderDoc() = default;
+
+ void setRhi(QRhi *rhi) override;
+ void startCaptureFrame() override;
+ void endCaptureFrame() override;
+ bool initialized() const override;
+ bool isCapturing() const override;
+ void openCapture() override;
+
+private:
+ void init();
+ void updateCapturePathAndTemplate();
+ static RENDERDOC_API_1_5_0 *s_rdocApi;
+#if QT_CONFIG(thread)
+ static QBasicMutex s_frameCaptureMutex;
+#endif
+ bool m_nativeHandlesSet;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGRAPHICSFRAMECAPTURERENDERDOC_P_P_H
diff --git a/src/gui/util/qgridlayoutengine.cpp b/src/gui/util/qgridlayoutengine.cpp
index 1cc42d3260..07981e8388 100644
--- a/src/gui/util/qgridlayoutengine.cpp
+++ b/src/gui/util/qgridlayoutengine.cpp
@@ -13,6 +13,8 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
+#define LAYOUTITEMSIZE_MAX (1 << 24)
+
template<typename T>
static void insertOrRemoveItems(QList<T> &items, int index, int delta)
{
@@ -194,7 +196,8 @@ void QGridLayoutRowData::calculateGeometries(int start, int end, qreal targetSiz
sumAvailable = targetSize - totalBox.q_minimumSize;
if (sumAvailable > 0.0) {
- qreal sumDesired = totalBox.q_preferredSize - totalBox.q_minimumSize;
+ const qreal totalBox_preferredSize = qMin(totalBox.q_preferredSize, qreal(LAYOUTITEMSIZE_MAX));
+ qreal sumDesired = totalBox_preferredSize - totalBox.q_minimumSize;
for (int i = 0; i < n; ++i) {
if (ignore.testBit(start + i)) {
@@ -203,7 +206,8 @@ void QGridLayoutRowData::calculateGeometries(int start, int end, qreal targetSiz
}
const QGridLayoutBox &box = boxes.at(start + i);
- qreal desired = box.q_preferredSize - box.q_minimumSize;
+ const qreal box_preferredSize = qMin(box.q_preferredSize, qreal(LAYOUTITEMSIZE_MAX));
+ qreal desired = box_preferredSize - box.q_minimumSize;
factors[i] = growthFactorBelowPreferredSize(desired, sumAvailable, sumDesired);
sumFactors += factors[i];
}
@@ -716,7 +720,7 @@ void QGridLayoutItem::dump(int indent) const
if (q_alignment != 0)
qDebug("%*s Alignment: %x", indent, "", uint(q_alignment));
qDebug("%*s Horizontal size policy: %x Vertical size policy: %x",
- indent, "", sizePolicy(Qt::Horizontal), sizePolicy(Qt::Vertical));
+ indent, "", (unsigned int)sizePolicy(Qt::Horizontal), (unsigned int)sizePolicy(Qt::Vertical));
}
#endif
@@ -758,6 +762,8 @@ QGridLayoutEngine::QGridLayoutEngine(Qt::Alignment defaultAlignment, bool snapTo
m_visualDirection = Qt::LeftToRight;
m_defaultAlignment = defaultAlignment;
m_snapToPixelGrid = snapToPixelGrid;
+ m_uniformCellWidths = false;
+ m_uniformCellHeights = false;
invalidate();
}
@@ -875,6 +881,34 @@ qreal QGridLayoutEngine::rowSizeHint(Qt::SizeHint which, int row, Qt::Orientatio
return q_infos[orientation].boxes.value(row).q_sizes(which);
}
+bool QGridLayoutEngine::uniformCellWidths() const
+{
+ return m_uniformCellWidths;
+}
+
+void QGridLayoutEngine::setUniformCellWidths(bool uniformCellWidths)
+{
+ if (m_uniformCellWidths == uniformCellWidths)
+ return;
+
+ m_uniformCellWidths = uniformCellWidths;
+ invalidate();
+}
+
+bool QGridLayoutEngine::uniformCellHeights() const
+{
+ return m_uniformCellHeights;
+}
+
+void QGridLayoutEngine::setUniformCellHeights(bool uniformCellHeights)
+{
+ if (m_uniformCellHeights == uniformCellHeights)
+ return;
+
+ m_uniformCellHeights = uniformCellHeights;
+ invalidate();
+}
+
void QGridLayoutEngine::setRowAlignment(int row, Qt::Alignment alignment,
Qt::Orientation orientation)
{
@@ -930,8 +964,11 @@ void QGridLayoutEngine::insertItem(QGridLayoutItem *item, int index)
for (int i = item->firstRow(); i <= item->lastRow(); ++i) {
for (int j = item->firstColumn(); j <= item->lastColumn(); ++j) {
- if (itemAt(i, j))
- qWarning("QGridLayoutEngine::addItem: Cell (%d, %d) already taken", i, j);
+ const auto existingItem = itemAt(i, j);
+ if (existingItem) {
+ qWarning("QGridLayoutEngine::addItem: Can't add %s at cell (%d, %d) because it's already taken by %s",
+ qPrintable(item->toString()), i, j, qPrintable(existingItem->toString()));
+ }
setItemAt(i, j, item);
}
}
@@ -1145,7 +1182,7 @@ void QGridLayoutEngine::dump(int indent) const
{
qDebug("%*sEngine", indent, "");
- qDebug("%*s Items (%d)", indent, "", q_items.count());
+ qDebug("%*s Items (%lld)", indent, "", q_items.count());
int i;
for (i = 0; i < q_items.count(); ++i)
q_items.at(i)->dump(indent + 2);
@@ -1499,6 +1536,27 @@ void QGridLayoutEngine::fillRowData(QGridLayoutRowData *rowData,
rowSpacing = qMax(windowMargin, rowSpacing);
}
}
+
+ if (rowData->boxes.size() > 1 &&
+ ((orientation == Qt::Horizontal && m_uniformCellWidths) ||
+ (orientation == Qt::Vertical && m_uniformCellHeights))) {
+ qreal averagePreferredSize = 0.;
+ qreal minimumMaximumSize = std::numeric_limits<qreal>::max();
+ qreal maximumMinimumSize = 0.;
+ for (const auto &box : rowData->boxes) {
+ averagePreferredSize += box.q_preferredSize;
+ minimumMaximumSize = qMin(minimumMaximumSize, box.q_maximumSize);
+ maximumMinimumSize = qMax(maximumMinimumSize, box.q_minimumSize);
+ }
+ averagePreferredSize /= rowData->boxes.size();
+ minimumMaximumSize = qMax(minimumMaximumSize, maximumMinimumSize);
+ averagePreferredSize = qBound(maximumMinimumSize, averagePreferredSize, minimumMaximumSize);
+ for (auto &box : rowData->boxes) {
+ box.q_preferredSize = averagePreferredSize;
+ box.q_minimumSize = maximumMinimumSize;
+ box.q_maximumSize = minimumMaximumSize;
+ }
+ }
}
void QGridLayoutEngine::ensureEffectiveFirstAndLastRows() const
diff --git a/src/gui/util/qgridlayoutengine_p.h b/src/gui/util/qgridlayoutengine_p.h
index 8344d488c1..2f60cb99fd 100644
--- a/src/gui/util/qgridlayoutengine_p.h
+++ b/src/gui/util/qgridlayoutengine_p.h
@@ -24,6 +24,7 @@
#include <QtCore/qpair.h>
#include <QtCore/qsize.h>
#include <QtCore/qrect.h>
+#include <QtCore/qdebug.h>
#include <float.h>
#include "qlayoutpolicy_p.h"
@@ -283,6 +284,8 @@ public:
virtual QLayoutPolicy::ControlTypes controlTypes(LayoutSide side) const;
+ inline virtual QString toString() const { return QDebug::toString(this); }
+
QRectF geometryWithin(qreal x, qreal y, qreal width, qreal height, qreal rowDescent, Qt::Alignment align, bool snapToPixelGrid) const;
QGridLayoutBox box(Qt::Orientation orientation, bool snapToPixelGrid, qreal constraint = -1.0) const;
@@ -334,6 +337,12 @@ public:
qreal rowSizeHint(Qt::SizeHint which, int row,
Qt::Orientation orientation = Qt::Vertical) const;
+ bool uniformCellWidths() const;
+ void setUniformCellWidths(bool uniformCellWidths);
+
+ bool uniformCellHeights() const;
+ void setUniformCellHeights(bool uniformCellHeights);
+
void setRowAlignment(int row, Qt::Alignment alignment, Qt::Orientation orientation);
Qt::Alignment rowAlignment(int row, Qt::Orientation orientation) const;
@@ -415,6 +424,8 @@ private:
// Configuration
Qt::Alignment m_defaultAlignment;
unsigned m_snapToPixelGrid : 1;
+ unsigned m_uniformCellWidths : 1;
+ unsigned m_uniformCellHeights : 1;
// Lazily computed from the above user input
mutable QHVContainer<int> q_cachedEffectiveFirstRows;
diff --git a/src/gui/util/qktxhandler.cpp b/src/gui/util/qktxhandler.cpp
index f04da929c3..35f1df1185 100644
--- a/src/gui/util/qktxhandler.cpp
+++ b/src/gui/util/qktxhandler.cpp
@@ -41,7 +41,7 @@ struct KTXHeader {
quint32 bytesOfKeyValueData;
};
-static const quint32 qktxh_headerSize = sizeof(KTXHeader);
+static constexpr quint32 qktxh_headerSize = sizeof(KTXHeader);
// Currently unused, declared for future reference
struct KTXKeyValuePairItem {
@@ -71,11 +71,24 @@ struct KTXMipmapLevel {
*/
};
-// Returns the nearest multiple of 'rounding' greater than or equal to 'value'
-constexpr quint32 withPadding(quint32 value, quint32 rounding)
+// Returns the nearest multiple of 4 greater than or equal to 'value'
+static const std::optional<quint32> nearestMultipleOf4(quint32 value)
{
- Q_ASSERT(rounding > 1);
- return value + (rounding - 1) - ((value + (rounding - 1)) % rounding);
+ constexpr quint32 rounding = 4;
+ quint32 result = 0;
+ if (qAddOverflow(value, rounding - 1, &result))
+ return std::nullopt;
+ result &= ~(rounding - 1);
+ return result;
+}
+
+// Returns a view with prechecked bounds
+static QByteArrayView safeView(QByteArrayView view, quint32 start, quint32 length)
+{
+ quint32 end = 0;
+ if (qAddOverflow(start, length, &end) || end > quint32(view.length()))
+ return {};
+ return view.sliced(start, length);
}
QKtxHandler::~QKtxHandler() = default;
@@ -83,8 +96,7 @@ QKtxHandler::~QKtxHandler() = default;
bool QKtxHandler::canRead(const QByteArray &suffix, const QByteArray &block)
{
Q_UNUSED(suffix);
-
- return (qstrncmp(block.constData(), ktxIdentifier, KTX_IDENTIFIER_LENGTH) == 0);
+ return block.startsWith(ktxIdentifier);
}
QTextureFileData QKtxHandler::read()
@@ -93,55 +105,122 @@ QTextureFileData QKtxHandler::read()
return QTextureFileData();
const QByteArray buf = device()->readAll();
- const quint32 dataSize = quint32(buf.size());
- if (dataSize < qktxh_headerSize || !canRead(QByteArray(), buf)) {
- qCDebug(lcQtGuiTextureIO, "Invalid KTX file %s", logName().constData());
+ if (static_cast<size_t>(buf.size()) > std::numeric_limits<quint32>::max()) {
+ qWarning(lcQtGuiTextureIO, "Too big KTX file %s", logName().constData());
+ return QTextureFileData();
+ }
+
+ if (!canRead(QByteArray(), buf)) {
+ qWarning(lcQtGuiTextureIO, "Invalid KTX file %s", logName().constData());
return QTextureFileData();
}
- const KTXHeader *header = reinterpret_cast<const KTXHeader *>(buf.data());
- if (!checkHeader(*header)) {
- qCDebug(lcQtGuiTextureIO, "Unsupported KTX file format in %s", logName().constData());
+ if (buf.size() < qsizetype(qktxh_headerSize)) {
+ qWarning(lcQtGuiTextureIO, "Invalid KTX header size in %s", logName().constData());
+ return QTextureFileData();
+ }
+
+ KTXHeader header;
+ memcpy(&header, buf.data(), qktxh_headerSize);
+ if (!checkHeader(header)) {
+ qWarning(lcQtGuiTextureIO, "Unsupported KTX file format in %s", logName().constData());
return QTextureFileData();
}
QTextureFileData texData;
texData.setData(buf);
- texData.setSize(QSize(decode(header->pixelWidth), decode(header->pixelHeight)));
- texData.setGLFormat(decode(header->glFormat));
- texData.setGLInternalFormat(decode(header->glInternalFormat));
- texData.setGLBaseInternalFormat(decode(header->glBaseInternalFormat));
+ texData.setSize(QSize(decode(header.pixelWidth), decode(header.pixelHeight)));
+ texData.setGLFormat(decode(header.glFormat));
+ texData.setGLInternalFormat(decode(header.glInternalFormat));
+ texData.setGLBaseInternalFormat(decode(header.glBaseInternalFormat));
- texData.setNumLevels(decode(header->numberOfMipmapLevels));
- texData.setNumFaces(decode(header->numberOfFaces));
+ texData.setNumLevels(decode(header.numberOfMipmapLevels));
+ texData.setNumFaces(decode(header.numberOfFaces));
+
+ const quint32 bytesOfKeyValueData = decode(header.bytesOfKeyValueData);
+ quint32 headerKeyValueSize;
+ if (qAddOverflow(qktxh_headerSize, bytesOfKeyValueData, &headerKeyValueSize)) {
+ qWarning(lcQtGuiTextureIO, "Overflow in size of key value data in header of KTX file %s",
+ logName().constData());
+ return QTextureFileData();
+ }
- const quint32 bytesOfKeyValueData = decode(header->bytesOfKeyValueData);
- if (qktxh_headerSize + bytesOfKeyValueData < quint64(buf.size())) // oob check
- texData.setKeyValueMetadata(decodeKeyValues(
- QByteArrayView(buf.data() + qktxh_headerSize, bytesOfKeyValueData)));
- quint32 offset = qktxh_headerSize + bytesOfKeyValueData;
+ if (headerKeyValueSize >= quint32(buf.size())) {
+ qWarning(lcQtGuiTextureIO, "OOB request in KTX file %s", logName().constData());
+ return QTextureFileData();
+ }
+
+ // File contains key/values
+ if (bytesOfKeyValueData > 0) {
+ auto keyValueDataView = safeView(buf, qktxh_headerSize, bytesOfKeyValueData);
+ if (keyValueDataView.isEmpty()) {
+ qWarning(lcQtGuiTextureIO, "Invalid view in KTX file %s", logName().constData());
+ return QTextureFileData();
+ }
+
+ auto keyValues = decodeKeyValues(keyValueDataView);
+ if (!keyValues) {
+ qWarning(lcQtGuiTextureIO, "Could not parse key values in KTX file %s",
+ logName().constData());
+ return QTextureFileData();
+ }
+
+ texData.setKeyValueMetadata(*keyValues);
+ }
+
+ // Technically, any number of levels is allowed but if the value is bigger than
+ // what is possible in KTX V2 (and what makes sense) we return an error.
+ // maxLevels = log2(max(width, height, depth))
+ const int maxLevels = (sizeof(quint32) * 8)
+ - qCountLeadingZeroBits(std::max(
+ { header.pixelWidth, header.pixelHeight, header.pixelDepth }));
+
+ if (texData.numLevels() > maxLevels) {
+ qWarning(lcQtGuiTextureIO, "Too many levels in KTX file %s", logName().constData());
+ return QTextureFileData();
+ }
- constexpr int MAX_ITERATIONS = 32; // cap iterations in case of corrupt data
+ if (texData.numFaces() != 1 && texData.numFaces() != 6) {
+ qWarning(lcQtGuiTextureIO, "Invalid number of faces in KTX file %s", logName().constData());
+ return QTextureFileData();
+ }
- for (int level = 0; level < qMin(texData.numLevels(), MAX_ITERATIONS); level++) {
- if (offset + sizeof(quint32) > dataSize) // Corrupt file; avoid oob read
- break;
+ quint32 offset = headerKeyValueSize;
+ for (int level = 0; level < texData.numLevels(); level++) {
+ const auto imageSizeView = safeView(buf, offset, sizeof(quint32));
+ if (imageSizeView.isEmpty()) {
+ qWarning(lcQtGuiTextureIO, "OOB request in KTX file %s", logName().constData());
+ return QTextureFileData();
+ }
- const quint32 imageSize = decode(qFromUnaligned<quint32>(buf.data() + offset));
- offset += sizeof(quint32);
+ const quint32 imageSize = decode(qFromUnaligned<quint32>(imageSizeView.data()));
+ offset += sizeof(quint32); // overflow checked indirectly above
- for (int face = 0; face < qMin(texData.numFaces(), MAX_ITERATIONS); face++) {
+ for (int face = 0; face < texData.numFaces(); face++) {
texData.setDataOffset(offset, level, face);
texData.setDataLength(imageSize, level, face);
// Add image data and padding to offset
- offset += withPadding(imageSize, 4);
+ const auto padded = nearestMultipleOf4(imageSize);
+ if (!padded) {
+ qWarning(lcQtGuiTextureIO, "Overflow in KTX file %s", logName().constData());
+ return QTextureFileData();
+ }
+
+ quint32 offsetNext;
+ if (qAddOverflow(offset, *padded, &offsetNext)) {
+ qWarning(lcQtGuiTextureIO, "OOB request in KTX file %s", logName().constData());
+ return QTextureFileData();
+ }
+
+ offset = offsetNext;
}
}
if (!texData.isValid()) {
- qCDebug(lcQtGuiTextureIO, "Invalid values in header of KTX file %s", logName().constData());
+ qWarning(lcQtGuiTextureIO, "Invalid values in header of KTX file %s",
+ logName().constData());
return QTextureFileData();
}
@@ -187,33 +266,83 @@ bool QKtxHandler::checkHeader(const KTXHeader &header)
return is2D && (isCubeMap || isCompressedImage);
}
-QMap<QByteArray, QByteArray> QKtxHandler::decodeKeyValues(QByteArrayView view) const
+std::optional<QMap<QByteArray, QByteArray>> QKtxHandler::decodeKeyValues(QByteArrayView view) const
{
QMap<QByteArray, QByteArray> output;
quint32 offset = 0;
- while (offset < view.size() + sizeof(quint32)) {
+ while (offset < quint32(view.size())) {
+ const auto keyAndValueByteSizeView = safeView(view, offset, sizeof(quint32));
+ if (keyAndValueByteSizeView.isEmpty()) {
+ qWarning(lcQtGuiTextureIO, "Invalid view in KTX key-value");
+ return std::nullopt;
+ }
+
const quint32 keyAndValueByteSize =
- decode(qFromUnaligned<quint32>(view.constData() + offset));
- offset += sizeof(quint32);
+ decode(qFromUnaligned<quint32>(keyAndValueByteSizeView.data()));
- if (offset + keyAndValueByteSize > quint64(view.size()))
- break; // oob read
+ quint32 offsetKeyAndValueStart;
+ if (qAddOverflow(offset, quint32(sizeof(quint32)), &offsetKeyAndValueStart)) {
+ qWarning(lcQtGuiTextureIO, "Overflow in KTX key-value");
+ return std::nullopt;
+ }
+
+ quint32 offsetKeyAndValueEnd;
+ if (qAddOverflow(offsetKeyAndValueStart, keyAndValueByteSize, &offsetKeyAndValueEnd)) {
+ qWarning(lcQtGuiTextureIO, "Overflow in KTX key-value");
+ return std::nullopt;
+ }
+
+ const auto keyValueView = safeView(view, offsetKeyAndValueStart, keyAndValueByteSize);
+ if (keyValueView.isEmpty()) {
+ qWarning(lcQtGuiTextureIO, "Invalid view in KTX key-value");
+ return std::nullopt;
+ }
// 'key' is a UTF-8 string ending with a null terminator, 'value' is the rest.
// To separate the key and value we convert the complete data to utf-8 and find the first
// null terminator from the left, here we split the data into two.
- const auto str = QString::fromUtf8(view.constData() + offset, keyAndValueByteSize);
- const int idx = str.indexOf('\0'_L1);
- if (idx == -1)
- continue;
-
- const QByteArray key = str.left(idx).toUtf8();
- const size_t keySize = key.size() + 1; // Actual data size
- const QByteArray value = QByteArray::fromRawData(view.constData() + offset + keySize,
- keyAndValueByteSize - keySize);
-
- offset = withPadding(offset + keyAndValueByteSize, 4);
- output.insert(key, value);
+
+ const int idx = keyValueView.indexOf('\0');
+ if (idx == -1) {
+ qWarning(lcQtGuiTextureIO, "Invalid key in KTX key-value");
+ return std::nullopt;
+ }
+
+ const QByteArrayView keyView = safeView(view, offsetKeyAndValueStart, idx);
+ if (keyView.isEmpty()) {
+ qWarning(lcQtGuiTextureIO, "Overflow in KTX key-value");
+ return std::nullopt;
+ }
+
+ const quint32 keySize = idx + 1; // Actual data size
+
+ quint32 offsetValueStart;
+ if (qAddOverflow(offsetKeyAndValueStart, keySize, &offsetValueStart)) {
+ qWarning(lcQtGuiTextureIO, "Overflow in KTX key-value");
+ return std::nullopt;
+ }
+
+ quint32 valueSize;
+ if (qSubOverflow(keyAndValueByteSize, keySize, &valueSize)) {
+ qWarning(lcQtGuiTextureIO, "Underflow in KTX key-value");
+ return std::nullopt;
+ }
+
+ const QByteArrayView valueView = safeView(view, offsetValueStart, valueSize);
+ if (valueView.isEmpty()) {
+ qWarning(lcQtGuiTextureIO, "Invalid view in KTX key-value");
+ return std::nullopt;
+ }
+
+ output.insert(keyView.toByteArray(), valueView.toByteArray());
+
+ const auto offsetNext = nearestMultipleOf4(offsetKeyAndValueEnd);
+ if (!offsetNext) {
+ qWarning(lcQtGuiTextureIO, "Overflow in KTX key-value");
+ return std::nullopt;
+ }
+
+ offset = *offsetNext;
}
return output;
diff --git a/src/gui/util/qktxhandler_p.h b/src/gui/util/qktxhandler_p.h
index 7d54b20922..3a0b8fcf7e 100644
--- a/src/gui/util/qktxhandler_p.h
+++ b/src/gui/util/qktxhandler_p.h
@@ -17,6 +17,8 @@
#include "qtexturefilehandler_p.h"
+#include <optional>
+
QT_BEGIN_NAMESPACE
struct KTXHeader;
@@ -33,7 +35,7 @@ public:
private:
bool checkHeader(const KTXHeader &header);
- QMap<QByteArray, QByteArray> decodeKeyValues(QByteArrayView view) const;
+ std::optional<QMap<QByteArray, QByteArray>> decodeKeyValues(QByteArrayView view) const;
quint32 decode(quint32 val) const;
bool inverseEndian = false;
diff --git a/src/gui/util/qvalidator.cpp b/src/gui/util/qvalidator.cpp
index 8b0f9ac321..2a81006657 100644
--- a/src/gui/util/qvalidator.cpp
+++ b/src/gui/util/qvalidator.cpp
@@ -362,34 +362,45 @@ static qlonglong pow10(int exp)
return result;
}
-QValidator::State QIntValidator::validate(QString & input, int&) const
+template <typename T> static inline
+std::optional<QValidator::State> initialResultCheck(T min, T max, const ParsingResult &result)
{
- QByteArray buff;
- if (!locale().d->m_data->validateChars(input, QLocaleData::IntegerMode, &buff, -1,
- locale().numberOptions())) {
- return Invalid;
- }
+ if (result.state == ParsingResult::Invalid)
+ return QValidator::Invalid;
+ const CharBuff &buff = result.buff;
if (buff.isEmpty())
- return Intermediate;
+ return QValidator::Intermediate;
- const bool startsWithMinus(buff[0] == '-');
- if (b >= 0 && startsWithMinus)
- return Invalid;
+ char ch = buff[0];
+ const bool signConflicts = (min >= 0 && ch == '-') || (max < 0 && ch == '+');
+ if (signConflicts)
+ return QValidator::Invalid;
- const bool startsWithPlus(buff[0] == '+');
- if (t < 0 && startsWithPlus)
- return Invalid;
+ if (result.state == ParsingResult::Intermediate)
+ return QValidator::Intermediate;
- if (buff.size() == 1 && (startsWithPlus || startsWithMinus))
- return Intermediate;
+ return std::nullopt;
+}
- bool ok;
- qlonglong entered = QLocaleData::bytearrayToLongLong(buff, 10, &ok);
- if (!ok)
+QValidator::State QIntValidator::validate(QString & input, int&) const
+{
+ ParsingResult result =
+ locale().d->m_data->validateChars(input, QLocaleData::IntegerMode, -1,
+ locale().numberOptions());
+
+ std::optional<State> opt = initialResultCheck(b, t, result);
+ if (opt)
+ return *opt;
+
+ const CharBuff &buff = result.buff;
+ QSimpleParsedNumber r = QLocaleData::bytearrayToLongLong(buff, 10);
+ if (!r.ok())
return Invalid;
+ qint64 entered = r.result;
if (entered >= b && entered <= t) {
+ bool ok = false;
locale().toInt(input, &ok);
return ok ? Acceptable : Intermediate;
}
@@ -401,7 +412,7 @@ QValidator::State QIntValidator::validate(QString & input, int&) const
// of a number of digits equal to or less than the max value as intermediate.
int buffLength = buff.size();
- if (startsWithPlus)
+ if (buff[0] == '+')
buffLength--;
const int tLength = t != 0 ? static_cast<int>(std::log10(qAbs(t))) + 1 : 1;
@@ -414,15 +425,15 @@ QValidator::State QIntValidator::validate(QString & input, int&) const
/*! \reimp */
void QIntValidator::fixup(QString &input) const
{
- QByteArray buff;
- if (!locale().d->m_data->validateChars(input, QLocaleData::IntegerMode, &buff, -1,
- locale().numberOptions())) {
+ auto [parseState, buff] =
+ locale().d->m_data->validateChars(input, QLocaleData::IntegerMode, -1,
+ locale().numberOptions());
+ if (parseState == ParsingResult::Invalid)
return;
- }
- bool ok;
- qlonglong entered = QLocaleData::bytearrayToLongLong(buff, 10, &ok);
- if (ok)
- input = locale().toString(entered);
+
+ QSimpleParsedNumber r = QLocaleData::bytearrayToLongLong(buff, 10);
+ if (r.ok())
+ input = locale().toString(r.result);
}
/*!
@@ -646,19 +657,12 @@ QValidator::State QDoubleValidator::validate(QString & input, int &) const
QValidator::State QDoubleValidatorPrivate::validateWithLocale(QString &input, QLocaleData::NumberMode numMode, const QLocale &locale) const
{
Q_Q(const QDoubleValidator);
- QByteArray buff;
- if (!locale.d->m_data->validateChars(input, numMode, &buff, q->dec, locale.numberOptions())) {
- return QValidator::Invalid;
- }
+ ParsingResult result =
+ locale.d->m_data->validateChars(input, numMode, q->dec, locale.numberOptions());
- if (buff.isEmpty())
- return QValidator::Intermediate;
-
- if (q->b >= 0 && buff.startsWith('-'))
- return QValidator::Invalid;
-
- if (q->t < 0 && buff.startsWith('+'))
- return QValidator::Invalid;
+ std::optional<QValidator::State> opt = initialResultCheck(q->b, q->t, result);
+ if (opt)
+ return *opt;
bool ok = false;
double i = locale.toDouble(input, &ok); // returns 0.0 if !ok
@@ -737,15 +741,16 @@ void QDoubleValidatorPrivate::fixupWithLocale(QString &input, QLocaleData::Numbe
const QLocale &locale) const
{
Q_Q(const QDoubleValidator);
- QByteArray buff;
// Passing -1 as the number of decimals, because fixup() exists to improve
// an Intermediate value, if it can.
- if (!locale.d->m_data->validateChars(input, numMode, &buff, -1, locale.numberOptions()))
+ auto [parseState, buff] =
+ locale.d->m_data->validateChars(input, numMode, -1, locale.numberOptions());
+ if (parseState == ParsingResult::Invalid)
return;
- // buff now contains data in C locale.
+ // buff contains data in C locale.
bool ok = false;
- const double entered = buff.toDouble(&ok);
+ const double entered = QByteArrayView(buff).toDouble(&ok);
if (ok) {
// Here we need to adjust the output format accordingly
char mode;
@@ -769,7 +774,7 @@ void QDoubleValidatorPrivate::fixupWithLocale(QString &input, QLocaleData::Numbe
if (eIndex < 0)
eIndex = buff.size();
precision = eIndex - (buff.contains('.') ? 1 : 0)
- - (buff.startsWith('-') || buff.startsWith('+') ? 1 : 0);
+ - (buff[0] == '-' || buff[0] == '+' ? 1 : 0);
}
// Use q->dec to limit the number of decimals, because we want the
// fixup() result to pass validate().
diff --git a/src/gui/vulkan/generated_header.txt b/src/gui/vulkan/licenseheader.h.in
index 3b6a0ea72a..3b6a0ea72a 100644
--- a/src/gui/vulkan/generated_header.txt
+++ b/src/gui/vulkan/licenseheader.h.in
diff --git a/src/gui/vulkan/qbasicvulkanplatforminstance.cpp b/src/gui/vulkan/qbasicvulkanplatforminstance.cpp
index 31e27cdac5..bbe9f9e1cb 100644
--- a/src/gui/vulkan/qbasicvulkanplatforminstance.cpp
+++ b/src/gui/vulkan/qbasicvulkanplatforminstance.cpp
@@ -259,8 +259,13 @@ void QBasicPlatformVulkanInstance::initInstance(QVulkanInstance *instance, const
VkInstanceCreateInfo instInfo = {};
instInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instInfo.pApplicationInfo = &appInfo;
- if (!flags.testFlag(QVulkanInstance::NoPortabilityDrivers))
- instInfo.flags |= 0x00000001; // VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR
+ if (!flags.testFlag(QVulkanInstance::NoPortabilityDrivers)) {
+ // With old Vulkan SDKs setting a non-zero flags gives a validation error.
+ // Whereas from 1.3.216 on the portability bit is required for MoltenVK to function.
+ // Hence the version check.
+ if (m_supportedApiVersion >= QVersionNumber(1, 3, 216))
+ instInfo.flags |= 0x00000001; // VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR
+ }
QList<const char *> layerNameVec;
for (const QByteArray &ba : std::as_const(m_enabledLayers))
diff --git a/src/gui/vulkan/qplatformvulkaninstance.cpp b/src/gui/vulkan/qplatformvulkaninstance.cpp
index 2955f2f300..2685a5c6f8 100644
--- a/src/gui/vulkan/qplatformvulkaninstance.cpp
+++ b/src/gui/vulkan/qplatformvulkaninstance.cpp
@@ -64,4 +64,15 @@ void QPlatformVulkanInstance::setDebugUtilsFilters(const QList<QVulkanInstance::
Q_UNUSED(filters);
}
+void QPlatformVulkanInstance::beginFrame(QWindow *window)
+{
+ Q_UNUSED(window);
+}
+
+void QPlatformVulkanInstance::endFrame(QWindow *window)
+{
+ Q_UNUSED(window);
+}
+
+
QT_END_NAMESPACE
diff --git a/src/gui/vulkan/qplatformvulkaninstance.h b/src/gui/vulkan/qplatformvulkaninstance.h
index 40ba602524..d34cb77d1b 100644
--- a/src/gui/vulkan/qplatformvulkaninstance.h
+++ b/src/gui/vulkan/qplatformvulkaninstance.h
@@ -46,6 +46,8 @@ public:
virtual void presentQueued(QWindow *window);
virtual void setDebugFilters(const QList<QVulkanInstance::DebugFilter> &filters);
virtual void setDebugUtilsFilters(const QList<QVulkanInstance::DebugUtilsFilter> &filters);
+ virtual void beginFrame(QWindow *window);
+ virtual void endFrame(QWindow *window);
private:
QScopedPointer<QPlatformVulkanInstancePrivate> d_ptr;
diff --git a/src/gui/vulkan/qvulkandefaultinstance.cpp b/src/gui/vulkan/qvulkandefaultinstance.cpp
index f2de61a9ba..b4f343cf17 100644
--- a/src/gui/vulkan/qvulkandefaultinstance.cpp
+++ b/src/gui/vulkan/qvulkandefaultinstance.cpp
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qvulkandefaultinstance_p.h"
-#include <private/qrhivulkan_p.h>
+#include <rhi/qrhi.h>
#include <QLoggingCategory>
QT_BEGIN_NAMESPACE
diff --git a/src/gui/vulkan/qvulkanfunctions.cpp b/src/gui/vulkan/qvulkanfunctions.cpp
index e6bf10068f..6a30799502 100644
--- a/src/gui/vulkan/qvulkanfunctions.cpp
+++ b/src/gui/vulkan/qvulkanfunctions.cpp
@@ -13,7 +13,7 @@ QT_BEGIN_NAMESPACE
\wrapper
\brief The QVulkanFunctions class provides cross-platform access to the
- instance level core Vulkan 1.2 API.
+ instance level core Vulkan 1.3 API.
Qt and Qt applications do not link to any Vulkan libraries by default.
Instead, all functions are resolved dynamically at run time. Each
@@ -45,17 +45,17 @@ QT_BEGIN_NAMESPACE
\l{https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkGetInstanceProcAddr.html}{the
man page for vkGetInstanceProcAddr} for more information.
- \note The member function prototypes for Vulkan 1.1 and 1.2 commands are
- ifdefed with the appropriate \c{VK_VERSION_1_x} that is defined by the
- Vulkan headers. Therefore these functions will only be callable by an
+ \note The member function prototypes for Vulkan 1.1, 1.2, and 1.3 commands
+ are \c ifdefed with the appropriate \c{VK_VERSION_1_x} that is defined by
+ the Vulkan headers. As such, these functions will only be callable by an
application when the system's (on which the application is built) Vulkan
- header is new enough and it contains 1.1 and 1.2 Vulkan API definitions.
- When building Qt from source, this has an additional consequence: the
- Vulkan headers on the build environment must also be 1.1 and 1.2 capable in
- order to get a Qt build that supports resolving the 1.1 and 1.2 API
- commands. If either of these conditions is not met, applications will only
- be able to call the Vulkan 1.0 commands through QVulkanFunctions and
- QVulkanDeviceFunctions.
+ header is new enough and it contains 1.1, 1.2, or 1.3 Vulkan API
+ definitions. When building Qt from source, this has an additional
+ consequence: the Vulkan headers on the build environment must also be 1.1,
+ 1.2, and 1.3 compatible to get a Qt build that supports resolving
+ the 1.1, 1.2, and 1.3 API commands. If neither of these conditions is met,
+ applications will only be able to call the Vulkan 1.0 commands through
+ QVulkanFunctions and QVulkanDeviceFunctions.
\sa QVulkanInstance, QVulkanDeviceFunctions, QWindow::setVulkanInstance(), QWindow::setSurfaceType()
*/
@@ -68,7 +68,7 @@ QT_BEGIN_NAMESPACE
\wrapper
\brief The QVulkanDeviceFunctions class provides cross-platform access to
- the device level core Vulkan 1.2 API.
+ the device level core Vulkan 1.3 API.
Qt and Qt applications do not link to any Vulkan libraries by default.
Instead, all functions are resolved dynamically at run time. Each
diff --git a/src/gui/vulkan/qvulkaninstance.cpp b/src/gui/vulkan/qvulkaninstance.cpp
index 946a183d89..6d3020d62d 100644
--- a/src/gui/vulkan/qvulkaninstance.cpp
+++ b/src/gui/vulkan/qvulkaninstance.cpp
@@ -12,6 +12,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QVulkanInstance
\since 5.10
+ \ingroup painting-3D
\inmodule QtGui
\brief The QVulkanInstance class represents a native Vulkan instance, enabling
@@ -244,7 +245,8 @@ QVulkanInstance::QVulkanInstance()
/*!
Destructor.
- \note current() will return \nullptr once the instance is destroyed.
+ \note \l {QVulkanInstance::}{vkInstance()} will return \nullptr once the
+ instance is destroyed.
*/
QVulkanInstance::~QVulkanInstance()
{
@@ -539,8 +541,8 @@ void QVulkanInstance::setApiVersion(const QVersionNumber &vulkanVersion)
\return true if successful, false on error or when Vulkan is not supported.
- When successful, the pointer to this QVulkanInstance is retrievable via the
- static function current().
+ When successful, the pointer to this QVulkanInstance is retrievable via
+ \l {QVulkanInstance::}{vkInstance()}.
The Vulkan instance and library is available as long as this
QVulkanInstance exists, or until destroy() is called.
diff --git a/src/gui/vulkan/qvulkanwindow.cpp b/src/gui/vulkan/qvulkanwindow.cpp
index 5a86b43290..00a5c5f869 100644
--- a/src/gui/vulkan/qvulkanwindow.cpp
+++ b/src/gui/vulkan/qvulkanwindow.cpp
@@ -178,12 +178,11 @@ Q_DECLARE_LOGGING_CATEGORY(lcGuiVk)
As an exception to this rule, \c robustBufferAccess is never enabled. Use the
callback mechanism described below, if enabling that feature is desired.
- Just enabling the 1.0 core features is not always sufficient, and therefore
- full control over the VkPhysicalDeviceFeatures used for device creation is
- possible too by registering a callback function with
+ This is not always desirable, and may be insufficient with Vulkan 1.1 and
+ higher. Therefore, full control over the VkPhysicalDeviceFeatures used for
+ device creation is possible too by registering a callback function with
setEnabledFeaturesModifier(). When set, the callback function is invoked,
- letting it alter the VkPhysicalDeviceFeatures, instead of enabling only the
- 1.0 core features.
+ letting it alter the VkPhysicalDeviceFeatures or VkPhysicalDeviceFeatures2.
\sa QVulkanInstance, QWindow
*/
@@ -448,7 +447,7 @@ void QVulkanWindow::setPreferredColorFormats(const QList<VkFormat> &formats)
static struct {
VkSampleCountFlagBits mask;
int count;
-} qvk_sampleCounts[] = {
+} q_vk_sampleCounts[] = {
// keep this sorted by 'count'
{ VK_SAMPLE_COUNT_1_BIT, 1 },
{ VK_SAMPLE_COUNT_2_BIT, 2 },
@@ -488,7 +487,7 @@ QList<int> QVulkanWindow::supportedSampleCounts()
VkSampleCountFlags depth = limits->framebufferDepthSampleCounts;
VkSampleCountFlags stencil = limits->framebufferStencilSampleCounts;
- for (const auto &qvk_sampleCount : qvk_sampleCounts) {
+ for (const auto &qvk_sampleCount : q_vk_sampleCounts) {
if ((color & qvk_sampleCount.mask)
&& (depth & qvk_sampleCount.mask)
&& (stencil & qvk_sampleCount.mask))
@@ -537,7 +536,7 @@ void QVulkanWindow::setSampleCount(int sampleCount)
return;
}
- for (const auto &qvk_sampleCount : qvk_sampleCounts) {
+ for (const auto &qvk_sampleCount : q_vk_sampleCounts) {
if (qvk_sampleCount.count == sampleCount) {
d->sampleCount = qvk_sampleCount.mask;
return;
@@ -702,17 +701,22 @@ void QVulkanWindowPrivate::init()
devInfo.enabledExtensionCount = devExts.size();
devInfo.ppEnabledExtensionNames = devExts.constData();
- VkPhysicalDeviceFeatures features;
- memset(&features, 0, sizeof(features));
- if (enabledFeaturesModifier) {
+ VkPhysicalDeviceFeatures features = {};
+ VkPhysicalDeviceFeatures2 features2 = {};
+ if (enabledFeatures2Modifier) {
+ features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ enabledFeatures2Modifier(features2);
+ devInfo.pNext = &features2;
+ } else if (enabledFeaturesModifier) {
enabledFeaturesModifier(features);
+ devInfo.pEnabledFeatures = &features;
} else {
// Enable all supported 1.0 core features, except ones that likely
// involve a performance penalty.
f->vkGetPhysicalDeviceFeatures(physDev, &features);
features.robustBufferAccess = VK_FALSE;
+ devInfo.pEnabledFeatures = &features;
}
- devInfo.pEnabledFeatures = &features;
// Device layers are not supported by QVulkanWindow since that's an already deprecated
// API. However, have a workaround for systems with older API and layers (f.ex. L4T
@@ -1625,16 +1629,12 @@ void QVulkanWindow::setQueueCreateInfoModifier(const QueueCreateInfoModifier &mo
praticular, \c robustBufferAccess is always disabled in order to avoid
unexpected performance hits.
- This however is not always sufficient when working with Vulkan 1.1 or 1.2
- features and extensions. Hence this callback mechanism.
-
The VkPhysicalDeviceFeatures reference passed in is all zeroed out at the
point when the function is invoked. It is up to the function to change
- members to true, or set up \c pNext chains as it sees fit.
+ members as it sees fit.
- \note When setting up \c pNext chains, make sure the referenced objects
- have a long enough lifetime, for example by storing them as member
- variables in the QVulkanWindow subclass.
+ \note To control Vulkan 1.1, 1.2, or 1.3 features, use
+ EnabledFeatures2Modifier instead.
\sa setEnabledFeaturesModifier()
*/
@@ -1642,9 +1642,14 @@ void QVulkanWindow::setQueueCreateInfoModifier(const QueueCreateInfoModifier &mo
/*!
Sets the enabled device features modification function \a modifier.
- \sa EnabledFeaturesModifier
+ \note To control Vulkan 1.1, 1.2, or 1.3 features, use
+ the overload taking a EnabledFeatures2Modifier instead.
+
+ \note \a modifier is passed to the callback function with all members set
+ to false. It is up to the function to change members as it sees fit.
- \since 6.4
+ \since 6.7
+ \sa EnabledFeaturesModifier
*/
void QVulkanWindow::setEnabledFeaturesModifier(const EnabledFeaturesModifier &modifier)
{
@@ -1653,6 +1658,45 @@ void QVulkanWindow::setEnabledFeaturesModifier(const EnabledFeaturesModifier &mo
}
/*!
+ \typedef QVulkanWindow::EnabledFeatures2Modifier
+
+ A function that is called during graphics initialization to alter the
+ VkPhysicalDeviceFeatures2 that is changed to the VkDeviceCreateInfo.
+
+ By default QVulkanWindow enables all Vulkan 1.0 core features that the
+ physical device reports as supported, with certain exceptions. In
+ praticular, \c robustBufferAccess is always disabled in order to avoid
+ unexpected performance hits.
+
+ This however is not always sufficient when working with Vulkan 1.1, 1.2, or
+ 1.3 features and extensions. Hence this callback mechanism. If only Vulkan
+ 1.0 is relevant at run time, use setEnabledFeaturesModifier() instead.
+
+ The VkPhysicalDeviceFeatures2 reference passed to the callback function
+ with \c sType set, but the rest zeroed out. It is up to the function to
+ change members to true, or set up \c pNext chains as it sees fit.
+
+ \note When setting up \c pNext chains, make sure the referenced objects
+ have a long enough lifetime, for example by storing them as member
+ variables in the QVulkanWindow subclass.
+
+ \since 6.7
+ \sa setEnabledFeaturesModifier()
+ */
+
+/*!
+ Sets the enabled device features modification function \a modifier.
+ \overload
+ \since 6.7
+ \sa EnabledFeatures2Modifier
+*/
+void QVulkanWindow::setEnabledFeaturesModifier(EnabledFeatures2Modifier modifier)
+{
+ Q_D(QVulkanWindow);
+ d->enabledFeatures2Modifier = std::move(modifier);
+}
+
+/*!
Returns true if this window has successfully initialized all Vulkan
resources, including the swapchain.
@@ -1852,13 +1896,26 @@ void QVulkanWindowRenderer::logicalDeviceLost()
{
}
+QSize QVulkanWindowPrivate::surfacePixelSize() const
+{
+ Q_Q(const QVulkanWindow);
+ VkSurfaceCapabilitiesKHR surfaceCaps = {};
+ vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physDevs.at(physDevIndex), surface, &surfaceCaps);
+ VkExtent2D bufferSize = surfaceCaps.currentExtent;
+ if (bufferSize.width == uint32_t(-1)) {
+ Q_ASSERT(bufferSize.height == uint32_t(-1));
+ return q->size() * q->devicePixelRatio();
+ }
+ return QSize(int(bufferSize.width), int(bufferSize.height));
+}
+
void QVulkanWindowPrivate::beginFrame()
{
if (!swapChain || framePending)
return;
Q_Q(QVulkanWindow);
- if (q->size() * q->devicePixelRatio() != swapChainImageSize) {
+ if (swapChainImageSize != surfacePixelSize()) {
recreateSwapChain();
if (!swapChain)
return;
@@ -1927,7 +1984,7 @@ void QVulkanWindowPrivate::beginFrame()
}
if (frameGrabbing)
- frameGrabTargetImage = QImage(swapChainImageSize, QImage::Format_RGBA8888);
+ frameGrabTargetImage = QImage(swapChainImageSize, QImage::Format_RGBA8888); // the format is as documented
if (renderer) {
framePending = true;
@@ -2443,6 +2500,19 @@ VkFormat QVulkanWindow::depthStencilFormat() const
This usually matches the size of the window, but may also differ in case
\c vkGetPhysicalDeviceSurfaceCapabilitiesKHR reports a fixed size.
+ In addition, it has been observed on some platforms that the
+ Vulkan-reported surface size is different with high DPI scaling active,
+ meaning the QWindow-reported
+ \l{QWindow::}{size()} multiplied with the \l{QWindow::}{devicePixelRatio()}
+ was 1 pixel less or more when compared to the value returned from here,
+ presumably due to differences in rounding. Rendering code should be aware
+ of this, and any related rendering logic must be based in the value returned
+ from here, never on the QWindow-reported size. Regardless of which pixel size
+ is correct in theory, Vulkan rendering must only ever rely on the Vulkan
+ API-reported surface size. Otherwise validation errors may occur, e.g. when
+ setting the viewport, because the application-provided values may become
+ out-of-bounds from Vulkan's perspective.
+
\note Calling this function is only valid from the invocation of
QVulkanWindowRenderer::initSwapChainResources() up until
QVulkanWindowRenderer::releaseSwapChainResources().
@@ -2714,6 +2784,12 @@ bool QVulkanWindow::supportsGrab() const
incomplete image, that has the correct size but not the content yet. The
content will be delivered via the frameGrabbed() signal in the latter case.
+ The returned QImage always has a format of QImage::Format_RGBA8888. If the
+ colorFormat() is \c VK_FORMAT_B8G8R8A8_UNORM, the red and blue channels are
+ swapped automatically since this format is commonly used as the default
+ choice for swapchain color buffers. With any other color buffer format,
+ there is no conversion performed by this function.
+
\note This function should not be called when a frame is in progress
(that is, frameReady() has not yet been called back by the application).
@@ -2742,6 +2818,9 @@ QImage QVulkanWindow::grab()
d->frameGrabbing = true;
d->beginFrame();
+ if (d->colorFormat == VK_FORMAT_B8G8R8A8_UNORM)
+ d->frameGrabTargetImage = std::move(d->frameGrabTargetImage).rgbSwapped();
+
return d->frameGrabTargetImage;
}
diff --git a/src/gui/vulkan/qvulkanwindow.h b/src/gui/vulkan/qvulkanwindow.h
index d0bdd3683e..537dbc4ae1 100644
--- a/src/gui/vulkan/qvulkanwindow.h
+++ b/src/gui/vulkan/qvulkanwindow.h
@@ -54,6 +54,14 @@ public:
virtual void logicalDeviceLost();
};
+#ifndef VK_VERSION_1_1
+typedef struct VkPhysicalDeviceFeatures2 {
+ VkStructureType sType;
+ void* pNext;
+ VkPhysicalDeviceFeatures features;
+} VkPhysicalDeviceFeatures2;
+#endif
+
class Q_GUI_EXPORT QVulkanWindow : public QWindow
{
Q_OBJECT
@@ -79,6 +87,8 @@ public:
typedef std::function<void(VkPhysicalDeviceFeatures &)> EnabledFeaturesModifier;
void setEnabledFeaturesModifier(const EnabledFeaturesModifier &modifier);
+ typedef std::function<void(VkPhysicalDeviceFeatures2 &)> EnabledFeatures2Modifier;
+ void setEnabledFeaturesModifier(EnabledFeatures2Modifier modifier);
void setPreferredColorFormats(const QList<VkFormat> &formats);
diff --git a/src/gui/vulkan/qvulkanwindow_p.h b/src/gui/vulkan/qvulkanwindow_p.h
index 9eaead9e07..7a0ee091e6 100644
--- a/src/gui/vulkan/qvulkanwindow_p.h
+++ b/src/gui/vulkan/qvulkanwindow_p.h
@@ -36,6 +36,7 @@ public:
void init();
void reset();
bool createDefaultRenderPass();
+ QSize surfacePixelSize() const;
void recreateSwapChain();
uint32_t chooseTransientImageMemType(VkImage img, uint32_t startIndex);
bool createTransientImage(VkFormat format, VkImageUsageFlags usage, VkImageAspectFlags aspectMask,
@@ -68,6 +69,7 @@ public:
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT;
QVulkanWindow::QueueCreateInfoModifier queueCreateInfoModifier;
QVulkanWindow::EnabledFeaturesModifier enabledFeaturesModifier;
+ QVulkanWindow::EnabledFeatures2Modifier enabledFeatures2Modifier;
VkDevice dev = VK_NULL_HANDLE;
QVulkanDeviceFunctions *devFuncs;
diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt
index 69043b006a..e977400245 100644
--- a/src/network/CMakeLists.txt
+++ b/src/network/CMakeLists.txt
@@ -20,12 +20,15 @@ qt_internal_add_module(Network
access/qnetworkcookie.cpp access/qnetworkcookie.h access/qnetworkcookie_p.h
access/qnetworkcookiejar.cpp access/qnetworkcookiejar.h access/qnetworkcookiejar_p.h
access/qnetworkfile.cpp access/qnetworkfile_p.h
+ access/qhttpheaders.cpp access/qhttpheaders.h
access/qhttpheaderparser.cpp access/qhttpheaderparser_p.h
+ access/qhttpheadershelper.cpp access/qhttpheadershelper_p.h
access/qnetworkreply.cpp access/qnetworkreply.h access/qnetworkreply_p.h
access/qnetworkreplydataimpl.cpp access/qnetworkreplydataimpl_p.h
access/qnetworkreplyfileimpl.cpp access/qnetworkreplyfileimpl_p.h
access/qnetworkreplyimpl.cpp access/qnetworkreplyimpl_p.h
access/qnetworkrequest.cpp access/qnetworkrequest.h access/qnetworkrequest_p.h
+ compat/removed_api.cpp
kernel/qauthenticator.cpp kernel/qauthenticator.h kernel/qauthenticator_p.h
kernel/qhostaddress.cpp kernel/qhostaddress.h kernel/qhostaddress_p.h
kernel/qhostinfo.cpp kernel/qhostinfo.h kernel/qhostinfo_p.h
@@ -53,8 +56,14 @@ qt_internal_add_module(Network
ssl/qsslsocket.h
ssl/qtlsbackend.cpp ssl/qtlsbackend_p.h
DEFINES
+ QT_NO_CONTEXTLESS_CONNECT
QT_NO_FOREACH
QT_NO_USING_NAMESPACE
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ QT_NO_CAST_FROM_BYTEARRAY
+ QT_NO_URL_CAST_FROM_STRING
+ QT_USE_NODISCARD_FILE_OPEN
INCLUDE_DIRECTORIES
kernel
LIBRARIES
@@ -63,10 +72,11 @@ qt_internal_add_module(Network
Qt::Core
PRIVATE_MODULE_INTERFACE
Qt::CorePrivate
+ NO_PCH_SOURCES
+ compat/removed_api.cpp
PRECOMPILED_HEADER
"../corelib/global/qt_pch.h"
GENERATE_CPP_EXPORTS
- GENERATE_PRIVATE_CPP_EXPORTS
)
## Scopes:
@@ -118,6 +128,7 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_http
access/qdecompresshelper.cpp access/qdecompresshelper_p.h
access/qhttp1configuration.cpp access/qhttp1configuration.h
access/qhttp2configuration.cpp access/qhttp2configuration.h
+ access/qhttp2connection.cpp access/qhttp2connection_p.h
access/qhttp2protocolhandler.cpp access/qhttp2protocolhandler_p.h
access/qhttpmultipart.cpp access/qhttpmultipart.h access/qhttpmultipart_p.h
access/qhttpnetworkconnection.cpp access/qhttpnetworkconnection_p.h
@@ -128,6 +139,11 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_http
access/qhttpprotocolhandler.cpp access/qhttpprotocolhandler_p.h
access/qhttpthreaddelegate.cpp access/qhttpthreaddelegate_p.h
access/qnetworkreplyhttpimpl.cpp access/qnetworkreplyhttpimpl_p.h
+ access/qnetworkrequestfactory.cpp access/qnetworkrequestfactory_p.h
+ access/qnetworkrequestfactory.h
+ access/qrestaccessmanager.cpp access/qrestaccessmanager.h access/qrestaccessmanager_p.h
+ access/qrestreply.cpp access/qrestreply.h access/qrestreply_p.h
+ access/qsocketabstraction_p.h
socket/qhttpsocketengine.cpp socket/qhttpsocketengine_p.h
)
@@ -176,11 +192,6 @@ qt_internal_extend_target(Network CONDITION UNIX
socket/qnet_unix_p.h
)
-qt_internal_extend_target(Network CONDITION QT_FEATURE_dlopen AND UNIX
- LIBRARIES
- ${CMAKE_DL_LIBS}
-)
-
qt_internal_extend_target(Network CONDITION QT_FEATURE_linux_netlink AND UNIX
SOURCES
kernel/qnetworkinterface_linux.cpp
@@ -191,11 +202,6 @@ qt_internal_extend_target(Network CONDITION UNIX AND NOT QT_FEATURE_linux_netlin
kernel/qnetworkinterface_unix.cpp
)
-qt_internal_extend_target(Network CONDITION ANDROID AND QT_FEATURE_dnslookup
- SOURCES
- kernel/qdnslookup_android.cpp
-)
-
qt_internal_extend_target(Network CONDITION WIN32
SOURCES
kernel/qhostinfo_win.cpp
@@ -208,11 +214,8 @@ qt_internal_extend_target(Network CONDITION WIN32
iphlpapi
secur32
winhttp
-)
-
-qt_internal_extend_target(Network CONDITION QT_FEATURE_dnslookup AND WIN32
- SOURCES
- kernel/qdnslookup_win.cpp
+ DEFINES
+ NOMINMAX
)
qt_internal_extend_target(Network CONDITION APPLE AND NOT UIKIT
@@ -221,19 +224,29 @@ qt_internal_extend_target(Network CONDITION APPLE AND NOT UIKIT
${FWSystemConfiguration}
)
-qt_internal_extend_target(Network CONDITION APPLE AND NOT UIKIT
+qt_internal_extend_target(Network CONDITION APPLE
LIBRARIES
- ${FWCoreServices}
- ${FWSystemConfiguration}
+ ${FWCFNetwork}
)
-qt_internal_extend_target(Network CONDITION APPLE
+qt_internal_extend_target(Network CONDITION QT_FEATURE_dnslookup AND QT_FEATURE_libresolv
+ SOURCES
+ kernel/qdnslookup_unix.cpp
LIBRARIES
- ${FWCFNetwork}
+ WrapResolv::WrapResolv
+)
+
+qt_internal_extend_target(Network CONDITION QT_FEATURE_dnslookup AND WIN32
+ SOURCES
+ kernel/qdnslookup_win.cpp
)
+qt_internal_extend_target(Network CONDITION QT_FEATURE_dnslookup AND NOT QT_FEATURE_libresolv AND NOT WIN32
+ SOURCES
+ kernel/qdnslookup_dummy.cpp
+)
-qt_internal_extend_target(Network CONDITION IOS OR MACOS
+qt_internal_extend_target(Network CONDITION APPLE
SOURCES
kernel/qnetconmonitor_darwin.mm
LIBRARIES
@@ -245,7 +258,7 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_networklistmanager AND NO
kernel/qnetconmonitor_win.cpp
)
-qt_internal_extend_target(Network CONDITION NOT IOS AND NOT MACOS AND NOT QT_FEATURE_networklistmanager
+qt_internal_extend_target(Network CONDITION NOT APPLE AND NOT QT_FEATURE_networklistmanager
SOURCES
kernel/qnetconmonitor_stub.cpp
)
@@ -260,7 +273,7 @@ qt_internal_extend_target(Network CONDITION UIKIT
kernel/qnetworkinterface_uikit_p.h
)
-qt_internal_extend_target(Network CONDITION APPLE
+qt_internal_extend_target(Network CONDITION APPLE AND NOT VISIONOS
SOURCES
kernel/qnetworkproxy_darwin.cpp
)
@@ -278,7 +291,7 @@ qt_internal_extend_target(Network CONDITION ANDROID
kernel/qnetworkproxy_android.cpp
)
-qt_internal_extend_target(Network CONDITION UNIX AND NOT ANDROID AND NOT APPLE AND NOT QT_FEATURE_libproxy AND (UNIX OR WINRT)
+qt_internal_extend_target(Network CONDITION UNIX AND NOT ANDROID AND NOT (APPLE AND NOT VISIONOS) AND NOT QT_FEATURE_libproxy AND (UNIX OR WINRT)
SOURCES
kernel/qnetworkproxy_generic.cpp
)
@@ -365,40 +378,44 @@ qt_internal_extend_target(Network CONDITION QT_FEATURE_ocsp AND QT_FEATURE_opens
ssl/qocsp_p.h
)
-qt_internal_extend_target(Network CONDITION QT_FEATURE_dnslookup AND UNIX AND NOT ANDROID
- SOURCES
- kernel/qdnslookup_unix.cpp
-)
qt_internal_add_docs(Network
doc/qtnetwork.qdocconf
)
-qt_internal_extend_target(Network CONDITION WIN32 PUBLIC_LIBRARIES ws2_32) # special case: mkspecs/common/msvc-desktop.conf
+# See mkspecs/common/msvc-desktop.conf
+qt_internal_extend_target(Network CONDITION WIN32 PUBLIC_LIBRARIES ws2_32)
-qt_internal_extend_target(Network CONDITION QNX PUBLIC_LIBRARIES socket) # special case: mkspecs/common/qcc-base-qnx.conf
+# See mkspecs/common/qcc-base-qnx.conf
+qt_internal_extend_target(Network CONDITION QNX PUBLIC_LIBRARIES socket)
qt_internal_extend_target(Network CONDITION SOLARIS PUBLIC_LIBRARIES socket nsl)
-if (WIN32)
- set_source_files_properties(Network # include windows.h (causing clashes with "interface" define)
- kernel/qauthenticator.cpp
- kernel/qdnslookup_win.cpp
- kernel/qhostaddress.cpp
- kernel/qhostinfo.cpp
- kernel/qhostinfo_win.cpp
- kernel/qnetconmonitor_win.cpp
- kernel/qnetworkinterface_win.cpp
- kernel/qnetworkproxy_win.cpp
- socket/qabstractsocket.cpp
- socket/qlocalserver.cpp
- socket/qlocalserver_win.cpp
- socket/qlocalsocket_win.cpp
- socket/qnativesocketengine.cpp
- socket/qnativesocketengine_win.cpp
- PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
-endif()
+qt_internal_extend_target(Network CONDITION WIN32
+ NO_UNITY_BUILD_SOURCES
+ kernel/qauthenticator.cpp
+ kernel/qdnslookup_win.cpp
+ kernel/qhostaddress.cpp
+ kernel/qhostinfo.cpp
+ kernel/qhostinfo_win.cpp
+ kernel/qnetconmonitor_win.cpp
+ kernel/qnetworkinterface_win.cpp
+ kernel/qnetworkproxy_win.cpp
+ socket/qabstractsocket.cpp
+ socket/qlocalserver.cpp
+ socket/qlocalserver_win.cpp
+ socket/qlocalsocket_win.cpp
+ socket/qnativesocketengine.cpp
+ socket/qnativesocketengine_win.cpp
+)
# include the snippet projects for developer-builds
if(QT_FEATURE_private_tests)
add_subdirectory(doc/snippets/network)
endif()
+qt_internal_extend_target(Network
+ # Workaround for QTBUG-118229:
+ # Function called by inline methods taking a pointer to a private class as a parameter
+ EXTRA_LINKER_SCRIPT_EXPORTS
+ # QNetworkDatagram::destroy(QNetworkDatagramPrivate *d)
+ "_ZN*16QNetworkDatagram7destroyEP*23QNetworkDatagramPrivate*"
+)
diff --git a/src/network/access/http2/hpack.cpp b/src/network/access/http2/hpack.cpp
index 58af04bbb5..9e970dda53 100644
--- a/src/network/access/http2/hpack.cpp
+++ b/src/network/access/http2/hpack.cpp
@@ -91,7 +91,7 @@ bool read_bit_pattern(const BitPattern &pattern, BitIStream &inputStream)
return true;
}
-bool is_request_pseudo_header(const QByteArray &name)
+bool is_request_pseudo_header(QByteArrayView name)
{
return name == ":method" || name == ":scheme" ||
name == ":authority" || name == ":path";
@@ -194,8 +194,8 @@ bool Encoder::encodeRequestPseudoHeaders(BitOStream &outputStream,
using size_type = decltype(header.size());
bool methodFound = false;
- const char *headerName[] = {":authority", ":scheme", ":path"};
- const size_type nHeaders = sizeof headerName / sizeof headerName[0];
+ constexpr QByteArrayView headerName[] = {":authority", ":scheme", ":path"};
+ constexpr size_type nHeaders = std::size(headerName);
bool headerFound[nHeaders] = {};
for (const auto &field : header) {
@@ -504,6 +504,49 @@ void Decoder::handleStreamError(BitIStream &inputStream)
// HTTP2 layer will end with session error/COMPRESSION_ERROR.
}
+std::optional<QUrl> makePromiseKeyUrl(const HttpHeader &requestHeader)
+{
+ constexpr QByteArrayView names[] = { ":authority", ":method", ":path", ":scheme" };
+ enum PseudoHeaderEnum
+ {
+ Authority,
+ Method,
+ Path,
+ Scheme
+ };
+ std::array<std::optional<QByteArrayView>, std::size(names)> pseudoHeaders{};
+ for (const auto &field : requestHeader) {
+ const auto *it = std::find(std::begin(names), std::end(names), QByteArrayView(field.name));
+ if (it != std::end(names)) {
+ const auto index = std::distance(std::begin(names), it);
+ if (field.value.isEmpty() || pseudoHeaders.at(index).has_value())
+ return {};
+ pseudoHeaders[index] = field.value;
+ }
+ }
+
+ auto optionalIsSet = [](const auto &x) { return x.has_value(); };
+ if (!std::all_of(pseudoHeaders.begin(), pseudoHeaders.end(), optionalIsSet)) {
+ // All four required, HTTP/2 8.1.2.3.
+ return {};
+ }
+
+ const QByteArrayView method = pseudoHeaders[Method].value();
+ if (method.compare("get", Qt::CaseInsensitive) != 0 &&
+ method.compare("head", Qt::CaseInsensitive) != 0) {
+ return {};
+ }
+
+ QUrl url;
+ url.setScheme(QLatin1StringView(pseudoHeaders[Scheme].value()));
+ url.setAuthority(QLatin1StringView(pseudoHeaders[Authority].value()));
+ url.setPath(QLatin1StringView(pseudoHeaders[Path].value()));
+
+ if (!url.isValid())
+ return {};
+ return url;
+}
+
}
QT_END_NAMESPACE
diff --git a/src/network/access/http2/hpack_p.h b/src/network/access/http2/hpack_p.h
index 75693da73c..b407b81941 100644
--- a/src/network/access/http2/hpack_p.h
+++ b/src/network/access/http2/hpack_p.h
@@ -18,8 +18,10 @@
#include "hpacktable_p.h"
#include <QtCore/qglobal.h>
+#include <QtCore/qurl.h>
#include <vector>
+#include <optional>
QT_BEGIN_NAMESPACE
@@ -112,6 +114,7 @@ private:
FieldLookupTable lookupTable;
};
+std::optional<QUrl> makePromiseKeyUrl(const HttpHeader &requestHeader);
}
QT_END_NAMESPACE
diff --git a/src/network/access/http2/hpacktable.cpp b/src/network/access/http2/hpacktable.cpp
index 74a09a207f..2c728b37e3 100644
--- a/src/network/access/http2/hpacktable.cpp
+++ b/src/network/access/http2/hpacktable.cpp
@@ -26,8 +26,10 @@ HeaderSize entry_size(QByteArrayView name, QByteArrayView value)
// for counting the number of references to the name and value would have
// 32 octets of overhead."
- const unsigned sum = unsigned(name.size() + value.size());
- if (std::numeric_limits<unsigned>::max() - 32 < sum)
+ size_t sum;
+ if (qAddOverflow(size_t(name.size()), size_t(value.size()), &sum))
+ return HeaderSize();
+ if (sum > (std::numeric_limits<unsigned>::max() - 32))
return HeaderSize();
return HeaderSize(true, quint32(sum + 32));
}
diff --git a/src/network/access/http2/http2frames.cpp b/src/network/access/http2/http2frames.cpp
index 0c70c98ef8..e07c96b803 100644
--- a/src/network/access/http2/http2frames.cpp
+++ b/src/network/access/http2/http2frames.cpp
@@ -135,6 +135,7 @@ FrameStatus Frame::validateHeader() const
// 6.6 PUSH_PROMISE
if (framePayloadSize < 4)
return FrameStatus::sizeError;
+ break;
default:
// DATA/HEADERS/CONTINUATION will be verified
// when we have payload.
@@ -258,7 +259,7 @@ const uchar *Frame::hpackBlockBegin() const
return begin;
}
-FrameStatus FrameReader::read(QAbstractSocket &socket)
+FrameStatus FrameReader::read(QIODevice &socket)
{
if (offset < frameHeaderSize) {
if (!readHeader(socket))
@@ -286,7 +287,7 @@ FrameStatus FrameReader::read(QAbstractSocket &socket)
return frame.validatePayload();
}
-bool FrameReader::readHeader(QAbstractSocket &socket)
+bool FrameReader::readHeader(QIODevice &socket)
{
Q_ASSERT(offset < frameHeaderSize);
@@ -302,7 +303,7 @@ bool FrameReader::readHeader(QAbstractSocket &socket)
return offset == frameHeaderSize;
}
-bool FrameReader::readPayload(QAbstractSocket &socket)
+bool FrameReader::readPayload(QIODevice &socket)
{
Q_ASSERT(offset < frame.buffer.size());
Q_ASSERT(frame.buffer.size() > frameHeaderSize);
@@ -393,7 +394,7 @@ void FrameWriter::updatePayloadSize()
setPayloadSize(size);
}
-bool FrameWriter::write(QAbstractSocket &socket) const
+bool FrameWriter::write(QIODevice &socket) const
{
auto &buffer = frame.buffer;
Q_ASSERT(buffer.size() >= frameHeaderSize);
@@ -407,7 +408,7 @@ bool FrameWriter::write(QAbstractSocket &socket) const
return nWritten != -1 && size_type(nWritten) == buffer.size();
}
-bool FrameWriter::writeHEADERS(QAbstractSocket &socket, quint32 sizeLimit)
+bool FrameWriter::writeHEADERS(QIODevice &socket, quint32 sizeLimit)
{
auto &buffer = frame.buffer;
Q_ASSERT(buffer.size() >= frameHeaderSize);
@@ -457,7 +458,7 @@ bool FrameWriter::writeHEADERS(QAbstractSocket &socket, quint32 sizeLimit)
return true;
}
-bool FrameWriter::writeDATA(QAbstractSocket &socket, quint32 sizeLimit,
+bool FrameWriter::writeDATA(QIODevice &socket, quint32 sizeLimit,
const uchar *src, quint32 size)
{
// With DATA frame(s) we always have:
diff --git a/src/network/access/http2/http2frames_p.h b/src/network/access/http2/http2frames_p.h
index be87f43fbe..48e3f751b7 100644
--- a/src/network/access/http2/http2frames_p.h
+++ b/src/network/access/http2/http2frames_p.h
@@ -27,7 +27,7 @@
QT_BEGIN_NAMESPACE
class QHttp2ProtocolHandler;
-class QAbstractSocket;
+class QIODevice;
namespace Http2
{
@@ -65,15 +65,15 @@ struct Q_AUTOTEST_EXPORT Frame
class Q_AUTOTEST_EXPORT FrameReader
{
public:
- FrameStatus read(QAbstractSocket &socket);
+ FrameStatus read(QIODevice &socket);
Frame &inboundFrame()
{
return frame;
}
private:
- bool readHeader(QAbstractSocket &socket);
- bool readPayload(QAbstractSocket &socket);
+ bool readHeader(QIODevice &socket);
+ bool readPayload(QIODevice &socket);
quint32 offset = 0;
Frame frame;
@@ -123,20 +123,25 @@ public:
{
append(&payload[0], &payload[0] + payload.size());
}
+ void append(QByteArrayView payload)
+ {
+ append(reinterpret_cast<const uchar *>(payload.begin()),
+ reinterpret_cast<const uchar *>(payload.end()));
+ }
void append(const uchar *begin, const uchar *end);
// Write as a single frame:
- bool write(QAbstractSocket &socket) const;
+ bool write(QIODevice &socket) const;
// Two types of frames we are sending are affected by frame size limits:
// HEADERS and DATA. HEADERS' payload (hpacked HTTP headers, following a
// frame header) is always in our 'buffer', we send the initial HEADERS
// frame first and then CONTINUTATION frame(s) if needed:
- bool writeHEADERS(QAbstractSocket &socket, quint32 sizeLimit);
+ bool writeHEADERS(QIODevice &socket, quint32 sizeLimit);
// With DATA frames the actual payload is never in our 'buffer', it's a
// 'readPointer' from QNonContiguousData. We split this payload as needed
// into DATA frames with correct payload size fitting into frame size limit:
- bool writeDATA(QAbstractSocket &socket, quint32 sizeLimit,
+ bool writeDATA(QIODevice &socket, quint32 sizeLimit,
const uchar *src, quint32 size);
private:
void updatePayloadSize();
diff --git a/src/network/access/http2/http2protocol.cpp b/src/network/access/http2/http2protocol.cpp
index 966f294e81..8e7e176c41 100644
--- a/src/network/access/http2/http2protocol.cpp
+++ b/src/network/access/http2/http2protocol.cpp
@@ -76,12 +76,10 @@ void appendProtocolUpgradeHeaders(const QHttp2Configuration &config, QHttpNetwor
Q_ASSERT(request);
// RFC 2616, 14.10
// RFC 7540, 3.2
- QByteArray value(request->headerField("Connection"));
+ const QByteArray connectionHeader = request->headerField("Connection");
+ const auto separator = connectionHeader.isEmpty() ? QByteArrayView() : QByteArrayView(", ");
// We _append_ 'Upgrade':
- if (value.size())
- value += ", ";
-
- value += "Upgrade, HTTP2-Settings";
+ QByteArray value = connectionHeader + separator + "Upgrade, HTTP2-Settings";
request->setHeaderField("Connection", value);
// This we just (re)write.
request->setHeaderField("Upgrade", "h2c");
@@ -186,19 +184,45 @@ QNetworkReply::NetworkError qt_error(quint32 errorCode)
bool is_protocol_upgraded(const QHttpNetworkReply &reply)
{
- if (reply.statusCode() == 101) {
- // Do some minimal checks here - we expect 'Upgrade: h2c' to be found.
- const auto &header = reply.header();
- for (const QPair<QByteArray, QByteArray> &field : header) {
- if (field.first.compare("upgrade", Qt::CaseInsensitive) == 0 &&
- field.second.compare("h2c", Qt::CaseInsensitive) == 0)
- return true;
- }
+ if (reply.statusCode() != 101)
+ return false;
+
+ // Do some minimal checks here - we expect 'Upgrade: h2c' to be found.
+ for (const auto &v : reply.header().values(QHttpHeaders::WellKnownHeader::Upgrade)) {
+ if (v.compare("h2c", Qt::CaseInsensitive) == 0)
+ return true;
}
return false;
}
+std::vector<uchar> assemble_hpack_block(const std::vector<Frame> &frames)
+{
+ std::vector<uchar> hpackBlock;
+
+ size_t total = 0;
+ for (const auto &frame : frames) {
+ if (qAddOverflow(total, size_t{frame.hpackBlockSize()}, &total))
+ return hpackBlock;
+ }
+
+ if (!total)
+ return hpackBlock;
+
+ hpackBlock.resize(total);
+ auto dst = hpackBlock.begin();
+ for (const auto &frame : frames) {
+ if (const auto hpackBlockSize = frame.hpackBlockSize()) {
+ const uchar *src = frame.hpackBlockBegin();
+ std::copy(src, src + hpackBlockSize, dst);
+ dst += hpackBlockSize;
+ }
+ }
+
+ return hpackBlock;
+}
+
+
} // namespace Http2
QT_END_NAMESPACE
diff --git a/src/network/access/http2/http2protocol_p.h b/src/network/access/http2/http2protocol_p.h
index e5068ad81a..fb5ff199c5 100644
--- a/src/network/access/http2/http2protocol_p.h
+++ b/src/network/access/http2/http2protocol_p.h
@@ -21,6 +21,8 @@
#include <QtCore/private/qglobal_p.h>
#include <QtCore/qmap.h>
+#include <vector>
+
// Different HTTP/2 constants/values as defined by RFC 7540.
QT_BEGIN_NAMESPACE
@@ -118,6 +120,7 @@ const qint32 qtDefaultStreamReceiveWindowSize = maxSessionReceiveWindowSize / 10
struct Frame configurationToSettingsFrame(const QHttp2Configuration &configuration);
QByteArray settingsFrameToBase64(const Frame &settingsFrame);
void appendProtocolUpgradeHeaders(const QHttp2Configuration &configuration, QHttpNetworkRequest *request);
+std::vector<uchar> assemble_hpack_block(const std::vector<Frame> &frames);
extern const Q_AUTOTEST_EXPORT char Http2clientPreface[clientPrefaceLength];
diff --git a/src/network/access/qabstractnetworkcache.cpp b/src/network/access/qabstractnetworkcache.cpp
index c8b940d801..3cd55d46fa 100644
--- a/src/network/access/qabstractnetworkcache.cpp
+++ b/src/network/access/qabstractnetworkcache.cpp
@@ -3,6 +3,8 @@
#include "qabstractnetworkcache.h"
#include "qabstractnetworkcache_p.h"
+#include "qnetworkrequest_p.h"
+#include "qhttpheadershelper_p.h"
#include <qdatastream.h>
#include <qdatetime.h>
@@ -28,14 +30,14 @@ public:
url == other.url
&& lastModified == other.lastModified
&& expirationDate == other.expirationDate
- && headers == other.headers
- && saveToDisk == other.saveToDisk;
+ && saveToDisk == other.saveToDisk
+ && QHttpHeadersHelper::compareStrict(headers, other.headers);
}
QUrl url;
QDateTime lastModified;
QDateTime expirationDate;
- QNetworkCacheMetaData::RawHeaderList headers;
+ QHttpHeaders headers;
QNetworkCacheMetaData::AttributesMap attributes;
bool saveToDisk;
@@ -207,21 +209,45 @@ void QNetworkCacheMetaData::setUrl(const QUrl &url)
Returns a list of all raw headers that are set in this meta data.
The list is in the same order that the headers were set.
- \sa setRawHeaders()
+ \sa setRawHeaders(), headers()
*/
QNetworkCacheMetaData::RawHeaderList QNetworkCacheMetaData::rawHeaders() const
{
- return d->headers;
+ return QNetworkHeadersPrivate::fromHttpToRaw(d->headers);
}
/*!
Sets the raw headers to \a list.
- \sa rawHeaders()
+ \sa rawHeaders(), setHeaders()
*/
void QNetworkCacheMetaData::setRawHeaders(const RawHeaderList &list)
{
- d->headers = list;
+ d->headers = QNetworkHeadersPrivate::fromRawToHttp(list);
+}
+
+/*!
+ \since 6.8
+
+ Returns headers in form of QHttpHeaders that are set in this meta data.
+
+ \sa setHeaders()
+*/
+QHttpHeaders QNetworkCacheMetaData::headers() const
+{
+ return d->headers;
+}
+
+/*!
+ \since 6.8
+
+ Sets the headers of this network cache meta data to \a headers.
+
+ \sa headers()
+*/
+void QNetworkCacheMetaData::setHeaders(const QHttpHeaders &headers)
+{
+ d->headers = headers;
}
/*!
@@ -367,7 +393,8 @@ void QNetworkCacheMetaDataPrivate::load(QDataStream &in, QNetworkCacheMetaData &
in >> p->lastModified;
in >> p->saveToDisk;
in >> p->attributes;
- in >> p->headers;
+ QNetworkCacheMetaData::RawHeaderList list; in >> list;
+ metaData.setRawHeaders(list);
}
/*!
diff --git a/src/network/access/qabstractnetworkcache.h b/src/network/access/qabstractnetworkcache.h
index c70dcf737c..b12fd4f863 100644
--- a/src/network/access/qabstractnetworkcache.h
+++ b/src/network/access/qabstractnetworkcache.h
@@ -48,6 +48,9 @@ public:
RawHeaderList rawHeaders() const;
void setRawHeaders(const RawHeaderList &headers);
+ QHttpHeaders headers() const;
+ void setHeaders(const QHttpHeaders &headers);
+
QDateTime lastModified() const;
void setLastModified(const QDateTime &dateTime);
diff --git a/src/network/access/qabstractprotocolhandler_p.h b/src/network/access/qabstractprotocolhandler_p.h
index ad82aae66e..da5eaeeb74 100644
--- a/src/network/access/qabstractprotocolhandler_p.h
+++ b/src/network/access/qabstractprotocolhandler_p.h
@@ -23,7 +23,7 @@ QT_BEGIN_NAMESPACE
class QHttpNetworkConnectionChannel;
class QHttpNetworkReply;
-class QAbstractSocket;
+class QIODevice;
class QHttpNetworkConnection;
class QAbstractProtocolHandler {
@@ -39,7 +39,7 @@ public:
protected:
QHttpNetworkConnectionChannel *m_channel;
QHttpNetworkReply *m_reply;
- QAbstractSocket *m_socket;
+ QIODevice *m_socket;
QHttpNetworkConnection *m_connection;
};
diff --git a/src/network/access/qdecompresshelper.cpp b/src/network/access/qdecompresshelper.cpp
index 98c9860450..52a0d9fc06 100644
--- a/src/network/access/qdecompresshelper.cpp
+++ b/src/network/access/qdecompresshelper.cpp
@@ -3,7 +3,6 @@
#include "qdecompresshelper_p.h"
-#include <QtCore/private/qbytearray_p.h>
#include <QtCore/qiodevice.h>
#include <QtCore/qcoreapplication.h>
@@ -24,7 +23,7 @@ QT_BEGIN_NAMESPACE
namespace {
struct ContentEncodingMapping
{
- char name[8];
+ QByteArrayView name;
QDecompressHelper::ContentEncoding encoding;
};
@@ -39,10 +38,10 @@ constexpr ContentEncodingMapping contentEncodingMapping[] {
{ "deflate", QDecompressHelper::Deflate },
};
-QDecompressHelper::ContentEncoding encodingFromByteArray(const QByteArray &ce) noexcept
+QDecompressHelper::ContentEncoding encodingFromByteArray(QByteArrayView ce) noexcept
{
for (const auto &mapping : contentEncodingMapping) {
- if (ce.compare(QByteArrayView(mapping.name, strlen(mapping.name)), Qt::CaseInsensitive) == 0)
+ if (ce.compare(mapping.name, Qt::CaseInsensitive) == 0)
return mapping.encoding;
}
return QDecompressHelper::None;
@@ -68,22 +67,19 @@ ZSTD_DStream *toZstandardPointer(void *ptr)
#endif
}
-bool QDecompressHelper::isSupportedEncoding(const QByteArray &encoding)
+bool QDecompressHelper::isSupportedEncoding(QByteArrayView encoding)
{
return encodingFromByteArray(encoding) != QDecompressHelper::None;
}
QByteArrayList QDecompressHelper::acceptedEncoding()
{
- static QByteArrayList accepted = []() {
- QByteArrayList list;
- list.reserve(sizeof(contentEncodingMapping) / sizeof(contentEncodingMapping[0]));
- for (const auto &mapping : contentEncodingMapping) {
- list << QByteArray(mapping.name);
- }
- return list;
- }();
- return accepted;
+ QByteArrayList list;
+ list.reserve(std::size(contentEncodingMapping));
+ for (const auto &mapping : contentEncodingMapping) {
+ list << mapping.name.toByteArray();
+ }
+ return list;
}
QDecompressHelper::~QDecompressHelper()
@@ -91,7 +87,7 @@ QDecompressHelper::~QDecompressHelper()
clear();
}
-bool QDecompressHelper::setEncoding(const QByteArray &encoding)
+bool QDecompressHelper::setEncoding(QByteArrayView encoding)
{
Q_ASSERT(contentEncoding == QDecompressHelper::None);
if (contentEncoding != QDecompressHelper::None) {
diff --git a/src/network/access/qdecompresshelper_p.h b/src/network/access/qdecompresshelper_p.h
index 54a9fe92c8..c837c14521 100644
--- a/src/network/access/qdecompresshelper_p.h
+++ b/src/network/access/qdecompresshelper_p.h
@@ -37,7 +37,7 @@ public:
QDecompressHelper() = default;
~QDecompressHelper();
- bool setEncoding(const QByteArray &contentEncoding);
+ bool setEncoding(QByteArrayView contentEncoding);
bool isCountingBytes() const;
void setCountingBytesEnabled(bool shouldCount);
@@ -57,7 +57,7 @@ public:
void setDecompressedSafetyCheckThreshold(qint64 threshold);
- static bool isSupportedEncoding(const QByteArray &encoding);
+ static bool isSupportedEncoding(QByteArrayView encoding);
static QByteArrayList acceptedEncoding();
QString errorString() const;
diff --git a/src/network/access/qhsts.cpp b/src/network/access/qhsts.cpp
index 39905f3548..21ed08ce4a 100644
--- a/src/network/access/qhsts.cpp
+++ b/src/network/access/qhsts.cpp
@@ -3,6 +3,8 @@
#include "qhsts_p.h"
+#include "qhttpheaders.h"
+
#include "QtCore/private/qipaddress_p.h"
#include "QtCore/qlist.h"
@@ -40,7 +42,7 @@ static bool is_valid_domain_name(const QString &host)
return true;
}
-void QHstsCache::updateFromHeaders(const QList<QPair<QByteArray, QByteArray>> &headers,
+void QHstsCache::updateFromHeaders(const QHttpHeaders &headers,
const QUrl &url)
{
if (!url.isValid())
@@ -286,7 +288,7 @@ static bool isSeparator(char c)
return isLWS(c) || std::find(separators, end, c) != end;
}
-static QByteArray unescapeMaxAge(const QByteArray &value)
+static QByteArrayView unescapeMaxAge(QByteArrayView value)
{
if (value.size() < 2 || value[0] != '"')
return value;
@@ -324,27 +326,25 @@ quoted-pair = "\" CHAR
*/
-bool QHstsHeaderParser::parse(const QList<QPair<QByteArray, QByteArray>> &headers)
+bool QHstsHeaderParser::parse(const QHttpHeaders &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;
- }
+ for (const auto &value : headers.values(
+ QHttpHeaders::WellKnownHeader::StrictTransportSecurity)) {
+ header = value;
+ // 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;
}
}
@@ -400,7 +400,7 @@ bool QHstsHeaderParser::parseDirective()
if (token == ";") // That's a weird grammar, but that's what it is.
return true;
- if (!isTOKEN(token[0])) // Not a valid directive-name.
+ if (!isTOKEN(token.at(0))) // Not a valid directive-name.
return false;
const QByteArray directiveName = token;
@@ -445,7 +445,7 @@ bool QHstsHeaderParser::processDirective(const QByteArray &name, const QByteArra
return false;
}
- const QByteArray unescapedValue = unescapeMaxAge(value);
+ const QByteArrayView unescapedValue = unescapeMaxAge(value);
if (!unescapedValue.size())
return false;
@@ -481,13 +481,13 @@ bool QHstsHeaderParser::nextToken()
// 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]))
+ while (tokenPos < header.size() && isLWS(header.at(tokenPos)))
++tokenPos;
if (tokenPos == header.size())
return true;
- const char ch = header[tokenPos];
+ const char ch = header.at(tokenPos);
if (ch == ';' || ch == '=') {
token.append(ch);
++tokenPos;
@@ -501,17 +501,17 @@ bool QHstsHeaderParser::nextToken()
if (ch == '"') {
int last = tokenPos + 1;
while (last < header.size()) {
- if (header[last] == '"') {
+ if (header.at(last) == '"') {
// The end of a quoted-string.
break;
- } else if (header[last] == '\\') {
+ } else if (header.at(last) == '\\') {
// quoted-pair = "\" CHAR
- if (last + 1 < header.size() && isCHAR(header[last + 1]))
+ if (last + 1 < header.size() && isCHAR(header.at(last + 1)))
last += 2;
else
return false;
} else {
- if (!isTEXT(header[last]))
+ if (!isTEXT(header.at(last)))
return false;
++last;
}
@@ -532,7 +532,7 @@ bool QHstsHeaderParser::nextToken()
return false;
int last = tokenPos + 1;
- while (last < header.size() && isTOKEN(header[last]))
+ while (last < header.size() && isTOKEN(header.at(last)))
++last;
token = header.mid(tokenPos, last - tokenPos);
diff --git a/src/network/access/qhsts_p.h b/src/network/access/qhsts_p.h
index 96d4ee8dc5..ff9378197b 100644
--- a/src/network/access/qhsts_p.h
+++ b/src/network/access/qhsts_p.h
@@ -31,11 +31,13 @@
QT_BEGIN_NAMESPACE
+class QHttpHeaders;
+
class Q_AUTOTEST_EXPORT QHstsCache
{
public:
- void updateFromHeaders(const QList<QPair<QByteArray, QByteArray>> &headers,
+ void updateFromHeaders(const QHttpHeaders &headers,
const QUrl &url);
void updateFromPolicies(const QList<QHstsPolicy> &hosts);
void updateKnownHost(const QUrl &url, const QDateTime &expires,
@@ -90,7 +92,7 @@ class Q_AUTOTEST_EXPORT QHstsHeaderParser
{
public:
- bool parse(const QList<QPair<QByteArray, QByteArray>> &headers);
+ bool parse(const QHttpHeaders &headers);
QDateTime expirationDate() const { return expiry; }
bool includeSubDomains() const { return subDomainsFound; }
diff --git a/src/network/access/qhstspolicy.cpp b/src/network/access/qhstspolicy.cpp
index 504c2203a4..323e562c3c 100644
--- a/src/network/access/qhstspolicy.cpp
+++ b/src/network/access/qhstspolicy.cpp
@@ -21,8 +21,8 @@ QT_BEGIN_NAMESPACE
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().
+ applies to subdomains, either in the constructor or by calling \l setExpiry(),
+ \l setHost() and \l setIncludesSubDomains().
\sa QNetworkAccessManager::setStrictTransportSecurityEnabled()
*/
diff --git a/src/network/access/qhttp1configuration.h b/src/network/access/qhttp1configuration.h
index 4b66745f54..128b8aa5aa 100644
--- a/src/network/access/qhttp1configuration.h
+++ b/src/network/access/qhttp1configuration.h
@@ -9,9 +9,7 @@
#include <utility>
#include <cstdint>
-#ifndef Q_CLANG_QDOC
QT_REQUIRE_CONFIG(http);
-#endif
QT_BEGIN_NAMESPACE
diff --git a/src/network/access/qhttp2configuration.h b/src/network/access/qhttp2configuration.h
index 4b3b7d54a2..ae08b664d4 100644
--- a/src/network/access/qhttp2configuration.h
+++ b/src/network/access/qhttp2configuration.h
@@ -8,9 +8,7 @@
#include <QtCore/qshareddata.h>
-#ifndef Q_QDOC
QT_REQUIRE_CONFIG(http);
-#endif
QT_BEGIN_NAMESPACE
diff --git a/src/network/access/qhttp2connection.cpp b/src/network/access/qhttp2connection.cpp
new file mode 100644
index 0000000000..8560e0da38
--- /dev/null
+++ b/src/network/access/qhttp2connection.cpp
@@ -0,0 +1,1752 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qhttp2connection_p.h"
+
+#include <private/bitstreams_p.h>
+
+#include <QtCore/private/qnumeric_p.h>
+#include <QtCore/private/qiodevice_p.h>
+#include <QtCore/private/qnoncontiguousbytedevice_p.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/QRandomGenerator>
+#include <QtCore/qloggingcategory.h>
+
+#include <algorithm>
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(qHttp2ConnectionLog, "qt.network.http2.connection", QtCriticalMsg)
+
+using namespace Qt::StringLiterals;
+using namespace Http2;
+
+/*!
+ \class QHttp2Stream
+ \inmodule QtNetwork
+ \internal
+
+ The QHttp2Stream class represents a single HTTP/2 stream.
+ Must be created by QHttp2Connection.
+
+ \sa QHttp2Connection
+*/
+
+QHttp2Stream::QHttp2Stream(QHttp2Connection *connection, quint32 streamID) noexcept
+ : QObject(connection), m_streamID(streamID)
+{
+ Q_ASSERT(connection);
+ Q_ASSERT(streamID); // stream id 0 is reserved for connection control messages
+ qCDebug(qHttp2ConnectionLog, "[%p] new stream %u", connection, streamID);
+}
+
+QHttp2Stream::~QHttp2Stream() noexcept = default;
+
+/*!
+ \fn quint32 QHttp2Stream::streamID() const noexcept
+
+ Returns the stream ID of this stream.
+*/
+
+/*!
+ \fn void QHttp2Stream::headersReceived(const HPack::HttpHeader &headers, bool endStream)
+
+ This signal is emitted when the remote peer has sent a HEADERS frame, and
+ potentially some CONTINUATION frames, ending with the END_HEADERS flag
+ to this stream.
+
+ The headers are internally combined and decompressed, and are accessible
+ through the \a headers parameter. If the END_STREAM flag was set, the
+ \a endStream parameter will be \c true, indicating that the peer does not
+ intend to send any more frames on this stream.
+
+ \sa receivedHeaders()
+*/
+
+/*!
+ \fn void QHttp2Stream::headersUpdated()
+
+ This signal may be emitted if a new HEADERS frame was received after
+ already processing a previous HEADERS frame.
+
+ \sa headersReceived(), receivedHeaders()
+*/
+
+/*!
+ \fn void QHttp2Stream::errorOccurred(quint32 errorCode, const QString &errorString)
+
+ This signal is emitted when the stream has encountered an error. The
+ \a errorCode parameter is the HTTP/2 error code, and the \a errorString
+ parameter is a human-readable description of the error.
+
+ \sa https://www.rfc-editor.org/rfc/rfc7540#section-7
+*/
+
+/*!
+ \fn void QHttp2Stream::stateChanged(State newState)
+
+ This signal is emitted when the state of the stream changes. The \a newState
+ parameter is the new state of the stream.
+
+ Examples of this is sending or receiving a frame with the END_STREAM flag.
+ This will transition the stream to the HalfClosedLocal or HalfClosedRemote
+ state, respectively.
+
+ \sa state()
+*/
+
+
+/*!
+ \fn void QHttp2Stream::promisedStreamReceived(quint32 newStreamID)
+
+ This signal is emitted when the remote peer has promised a new stream with
+ the given \a newStreamID.
+
+ \sa QHttp2Connection::promisedStream()
+*/
+
+/*!
+ \fn void QHttp2Stream::uploadBlocked()
+
+ This signal is emitted when the stream is unable to send more data because
+ the remote peer's receive window is full.
+
+ This is mostly intended for diagnostics as there is no expectation that the
+ user can do anything to react to this.
+*/
+
+/*!
+ \fn void QHttp2Stream::dataReceived(const QByteArray &data, bool endStream)
+
+ This signal is emitted when the stream has received a DATA frame from the
+ remote peer. The \a data parameter contains the payload of the frame, and
+ the \a endStream parameter is \c true if the END_STREAM flag was set.
+
+ \sa downloadBuffer()
+*/
+
+/*!
+ \fn void QHttp2Stream::bytesWritten(qint64 bytesWritten)
+
+ This signal is emitted when the stream has written \a bytesWritten bytes to
+ the network.
+*/
+
+/*!
+ \fn void QHttp2Stream::uploadDeviceError(const QString &errorString)
+
+ This signal is emitted if the upload device encounters an error while
+ sending data. The \a errorString parameter is a human-readable description
+ of the error.
+*/
+
+/*!
+ \fn void QHttp2Stream::uploadFinished()
+
+ This signal is emitted when the stream has finished sending all the data
+ from the upload device.
+
+ If the END_STREAM flag was set for sendData() then the stream will be
+ closed for further writes before this signal is emitted.
+*/
+
+/*!
+ \fn bool QHttp2Stream::isUploadingDATA() const noexcept
+
+ Returns \c true if the stream is currently sending DATA frames.
+*/
+
+/*!
+ \fn State QHttp2Stream::state() const noexcept
+
+ Returns the current state of the stream.
+
+ \sa stateChanged()
+*/
+/*!
+ \fn bool QHttp2Stream::isActive() const noexcept
+
+ Returns \c true if the stream has been opened and is not yet closed.
+*/
+/*!
+ \fn bool QHttp2Stream::isPromisedStream() const noexcept
+
+ Returns \c true if the stream was promised by the remote peer.
+*/
+/*!
+ \fn bool QHttp2Stream::wasReset() const noexcept
+
+ Returns \c true if the stream was reset by the remote peer.
+*/
+/*!
+ \fn quint32 QHttp2Stream::RST_STREAM_code() const noexcept
+
+ Returns the HTTP/2 error code if the stream was reset by the remote peer.
+ If the stream was not reset, this function returns 0.
+*/
+/*!
+ \fn HPack::HttpHeader QHttp2Stream::receivedHeaders() const noexcept
+
+ Returns the headers received from the remote peer, if any.
+*/
+/*!
+ \fn QByteDataBuffer QHttp2Stream::downloadBuffer() const noexcept
+
+ Returns the buffer containing the data received from the remote peer.
+*/
+
+void QHttp2Stream::finishWithError(quint32 errorCode, const QString &message)
+{
+ qCDebug(qHttp2ConnectionLog, "[%p] stream %u finished with error: %ls (error code: %u)",
+ getConnection(), m_streamID, qUtf16Printable(message), errorCode);
+ transitionState(StateTransition::RST);
+ emit errorOccurred(errorCode, message);
+}
+
+void QHttp2Stream::finishWithError(quint32 errorCode)
+{
+ QNetworkReply::NetworkError error = QNetworkReply::NoError;
+ QString message;
+ qt_error(errorCode, error, message);
+ finishWithError(error, message);
+}
+
+/*!
+ Sends a RST_STREAM frame with the given \a errorCode.
+ This closes the stream for both sides, any further frames will be dropped.
+
+ Returns \c false if the stream is closed or idle, also if it fails to send
+ the RST_STREAM frame. Otherwise, returns \c true.
+*/
+bool QHttp2Stream::sendRST_STREAM(quint32 errorCode)
+{
+ if (m_state == State::Closed || m_state == State::Idle)
+ return false;
+ qCDebug(qHttp2ConnectionLog, "[%p] sending RST_STREAM on stream %u, code: %u", getConnection(),
+ m_streamID, errorCode);
+ transitionState(StateTransition::RST);
+
+ QHttp2Connection *connection = getConnection();
+ FrameWriter &frameWriter = connection->frameWriter;
+ frameWriter.start(FrameType::RST_STREAM, FrameFlag::EMPTY, m_streamID);
+ frameWriter.append(errorCode);
+ return frameWriter.write(*connection->getSocket());
+}
+
+/*!
+ Sends a DATA frame with the bytes obtained from \a device.
+
+ This function will send as many DATA frames as needed to send all the data
+ from \a device. If \a endStream is \c true, the END_STREAM flag will be set.
+
+ \a device must stay alive for the duration of the upload.
+ A way of doing this is to heap-allocate the \a device and parent it to the
+ QHttp2Stream.
+*/
+void QHttp2Stream::sendDATA(QIODevice *device, bool endStream)
+{
+ Q_ASSERT(!m_uploadDevice);
+ Q_ASSERT(!m_uploadByteDevice);
+ Q_ASSERT(device);
+ if (m_state != State::Open && m_state != State::HalfClosedRemote)
+ return;
+
+ auto *byteDevice = QNonContiguousByteDeviceFactory::create(device);
+ connect(this, &QHttp2Stream::uploadFinished, byteDevice, &QObject::deleteLater);
+ byteDevice->setParent(this);
+ m_uploadDevice = device;
+ qCDebug(qHttp2ConnectionLog, "[%p] starting sendDATA on stream %u, of IODevice: %p",
+ getConnection(), m_streamID, device);
+ sendDATA(byteDevice, endStream);
+}
+
+/*!
+ Sends a DATA frame with the bytes obtained from \a device.
+
+ This function will send as many DATA frames as needed to send all the data
+ from \a device. If \a endStream is \c true, the END_STREAM flag will be set.
+
+ \a device must stay alive for the duration of the upload.
+ A way of doing this is to heap-allocate the \a device and parent it to the
+ QHttp2Stream.
+*/
+void QHttp2Stream::sendDATA(QNonContiguousByteDevice *device, bool endStream)
+{
+ Q_ASSERT(!m_uploadByteDevice);
+ Q_ASSERT(device);
+ if (m_state != State::Open && m_state != State::HalfClosedRemote)
+ return;
+
+ qCDebug(qHttp2ConnectionLog, "[%p] starting sendDATA on stream %u, of device: %p",
+ getConnection(), m_streamID, device);
+
+ m_uploadByteDevice = device;
+ m_endStreamAfterDATA = endStream;
+ connect(m_uploadByteDevice, &QNonContiguousByteDevice::readyRead, this,
+ &QHttp2Stream::maybeResumeUpload);
+ connect(m_uploadByteDevice, &QObject::destroyed, this, &QHttp2Stream::uploadDeviceDestroyed);
+
+ internalSendDATA();
+}
+
+void QHttp2Stream::internalSendDATA()
+{
+ Q_ASSERT(m_uploadByteDevice);
+ QHttp2Connection *connection = getConnection();
+ Q_ASSERT(connection->maxFrameSize > frameHeaderSize);
+ QIODevice *socket = connection->getSocket();
+
+ qCDebug(qHttp2ConnectionLog,
+ "[%p] stream %u, about to write to socket, current session window size: %d, stream "
+ "window size: %d, bytes available: %lld",
+ connection, m_streamID, connection->sessionSendWindowSize, m_sendWindow,
+ m_uploadByteDevice->size() - m_uploadByteDevice->pos());
+
+ qint32 remainingWindowSize = std::min<qint32>(connection->sessionSendWindowSize, m_sendWindow);
+ FrameWriter &frameWriter = connection->frameWriter;
+ qint64 totalBytesWritten = 0;
+ const auto deviceCanRead = [this, connection] {
+ // We take advantage of knowing the internals of one of the devices used.
+ // It will request X bytes to move over to the http thread if there's
+ // not enough left, so we give it a large size. It will anyway return
+ // the size it can actually provide.
+ const qint64 requestSize = connection->maxFrameSize * 10ll;
+ qint64 tmp = 0;
+ return m_uploadByteDevice->readPointer(requestSize, tmp) != nullptr && tmp > 0;
+ };
+
+ bool sentEND_STREAM = false;
+ while (remainingWindowSize && deviceCanRead()) {
+ quint32 bytesWritten = 0;
+ qint32 remainingBytesInFrame = qint32(connection->maxFrameSize);
+ frameWriter.start(FrameType::DATA, FrameFlag::EMPTY, streamID());
+
+ while (remainingWindowSize && deviceCanRead() && remainingBytesInFrame) {
+ const qint32 maxToWrite = std::min(remainingWindowSize, remainingBytesInFrame);
+
+ qint64 outBytesAvail = 0;
+ const char *readPointer = m_uploadByteDevice->readPointer(maxToWrite, outBytesAvail);
+ if (!readPointer || outBytesAvail <= 0) {
+ qCDebug(qHttp2ConnectionLog,
+ "[%p] stream %u, cannot write data, device (%p) has %lld bytes available",
+ connection, m_streamID, m_uploadByteDevice, outBytesAvail);
+ break;
+ }
+ const qint32 bytesToWrite = qint32(std::min<qint64>(maxToWrite, outBytesAvail));
+ frameWriter.append(QByteArrayView(readPointer, bytesToWrite));
+ m_uploadByteDevice->advanceReadPointer(bytesToWrite);
+
+ bytesWritten += bytesToWrite;
+
+ m_sendWindow -= bytesToWrite;
+ Q_ASSERT(m_sendWindow >= 0);
+ connection->sessionSendWindowSize -= bytesToWrite;
+ Q_ASSERT(connection->sessionSendWindowSize >= 0);
+ remainingBytesInFrame -= bytesToWrite;
+ Q_ASSERT(remainingBytesInFrame >= 0);
+ remainingWindowSize -= bytesToWrite;
+ Q_ASSERT(remainingWindowSize >= 0);
+ }
+
+ qCDebug(qHttp2ConnectionLog, "[%p] stream %u, writing %u bytes to socket", connection,
+ m_streamID, bytesWritten);
+ if (!deviceCanRead() && m_uploadByteDevice->atEnd() && m_endStreamAfterDATA) {
+ sentEND_STREAM = true;
+ frameWriter.addFlag(FrameFlag::END_STREAM);
+ }
+ if (!frameWriter.write(*socket)) {
+ qCDebug(qHttp2ConnectionLog, "[%p] stream %u, failed to write to socket", connection,
+ m_streamID);
+ finishWithError(QNetworkReply::ProtocolFailure, "failed to write to socket"_L1);
+ return;
+ }
+
+ totalBytesWritten += bytesWritten;
+ }
+
+ qCDebug(qHttp2ConnectionLog,
+ "[%p] stream %u, wrote %lld bytes total, if the device is not exhausted, we'll write "
+ "more later. Remaining window size: %d",
+ connection, m_streamID, totalBytesWritten, remainingWindowSize);
+
+ emit bytesWritten(totalBytesWritten);
+ if (sentEND_STREAM || (!deviceCanRead() && m_uploadByteDevice->atEnd())) {
+ qCDebug(qHttp2ConnectionLog,
+ "[%p] stream %u, exhausted device %p, sent END_STREAM? %d, %ssending end stream "
+ "after DATA",
+ connection, m_streamID, m_uploadByteDevice, sentEND_STREAM,
+ m_endStreamAfterDATA ? "" : "not ");
+ if (!sentEND_STREAM && m_endStreamAfterDATA) {
+ // We need to send an empty DATA frame with END_STREAM since we
+ // have exhausted the device, but we haven't sent END_STREAM yet.
+ // This can happen if we got a final readyRead to signify no more
+ // data available, but we hadn't sent the END_STREAM flag yet.
+ frameWriter.start(FrameType::DATA, FrameFlag::END_STREAM, streamID());
+ frameWriter.write(*socket);
+ }
+ finishSendDATA();
+ } else if (isUploadBlocked()) {
+ qCDebug(qHttp2ConnectionLog, "[%p] stream %u, upload blocked", connection, m_streamID);
+ emit uploadBlocked();
+ }
+}
+
+void QHttp2Stream::finishSendDATA()
+{
+ if (m_endStreamAfterDATA)
+ transitionState(StateTransition::CloseLocal);
+
+ disconnect(m_uploadByteDevice, nullptr, this, nullptr);
+ m_uploadDevice = nullptr;
+ m_uploadByteDevice = nullptr;
+ emit uploadFinished();
+}
+
+void QHttp2Stream::maybeResumeUpload()
+{
+ qCDebug(qHttp2ConnectionLog,
+ "[%p] stream %u, maybeResumeUpload. Upload device: %p, bytes available: %lld, blocked? "
+ "%d",
+ getConnection(), m_streamID, m_uploadByteDevice,
+ !m_uploadByteDevice ? 0 : m_uploadByteDevice->size() - m_uploadByteDevice->pos(),
+ isUploadBlocked());
+ if (isUploadingDATA() && !isUploadBlocked())
+ internalSendDATA();
+}
+
+/*!
+ Returns \c true if the stream is currently unable to send more data because
+ the remote peer's receive window is full.
+*/
+bool QHttp2Stream::isUploadBlocked() const noexcept
+{
+ constexpr auto MinFrameSize = Http2::frameHeaderSize + 1; // 1 byte payload
+ return isUploadingDATA()
+ && (m_sendWindow <= MinFrameSize
+ || getConnection()->sessionSendWindowSize <= MinFrameSize);
+}
+
+void QHttp2Stream::uploadDeviceReadChannelFinished()
+{
+ maybeResumeUpload();
+}
+
+/*!
+ Sends a HEADERS frame with the given \a headers and \a priority.
+ If \a endStream is \c true, the END_STREAM flag will be set, and the stream
+ will be closed for future writes.
+ If the headers are too large, or the stream is not in the correct state,
+ this function will return \c false. Otherwise, it will return \c true.
+*/
+bool QHttp2Stream::sendHEADERS(const HPack::HttpHeader &headers, bool endStream, quint8 priority)
+{
+ using namespace HPack;
+ if (auto hs = header_size(headers);
+ !hs.first || hs.second > getConnection()->maxHeaderListSize()) {
+ return false;
+ }
+
+ transitionState(StateTransition::Open);
+
+ Q_ASSERT(m_state == State::Open || m_state == State::HalfClosedRemote);
+
+ QHttp2Connection *connection = getConnection();
+
+ qCDebug(qHttp2ConnectionLog, "[%p] stream %u, sending HEADERS frame with %u entries",
+ connection, streamID(), uint(headers.size()));
+
+ QIODevice *socket = connection->getSocket();
+ FrameWriter &frameWriter = connection->frameWriter;
+
+ frameWriter.start(FrameType::HEADERS, FrameFlag::PRIORITY | FrameFlag::END_HEADERS, streamID());
+ if (endStream)
+ frameWriter.addFlag(FrameFlag::END_STREAM);
+
+ frameWriter.append(quint32()); // No stream dependency in Qt.
+ frameWriter.append(priority);
+
+ // Compress in-place:
+ BitOStream outputStream(frameWriter.outboundFrame().buffer);
+ if (connection->m_connectionType == QHttp2Connection::Type::Client) {
+ if (!connection->encoder.encodeRequest(outputStream, headers))
+ return false;
+ } else {
+ if (!connection->encoder.encodeResponse(outputStream, headers))
+ return false;
+ }
+
+ bool result = frameWriter.writeHEADERS(*socket, connection->maxFrameSize);
+ if (endStream)
+ transitionState(StateTransition::CloseLocal);
+
+ return result;
+}
+
+/*!
+ Sends a WINDOW_UPDATE frame with the given \a delta.
+ This increases our receive window size for this stream, allowing the remote
+ peer to send more data.
+*/
+void QHttp2Stream::sendWINDOW_UPDATE(quint32 delta)
+{
+ QHttp2Connection *connection = getConnection();
+ m_recvWindow += qint32(delta);
+ connection->sendWINDOW_UPDATE(streamID(), delta);
+}
+
+void QHttp2Stream::uploadDeviceDestroyed()
+{
+ if (isUploadingDATA()) {
+ // We're in the middle of sending DATA frames, we need to abort
+ // the stream.
+ sendRST_STREAM(CANCEL);
+ emit uploadDeviceError("Upload device destroyed while uploading"_L1);
+ }
+ m_uploadDevice = nullptr;
+}
+
+void QHttp2Stream::setState(State newState)
+{
+ if (m_state == newState)
+ return;
+ qCDebug(qHttp2ConnectionLog, "[%p] stream %u, state changed from %d to %d", getConnection(),
+ streamID(), int(m_state), int(newState));
+ m_state = newState;
+ emit stateChanged(newState);
+}
+
+// Changes the state as appropriate given the current state and the transition.
+// Always call this before emitting any signals since the recipient might rely
+// on the new state!
+void QHttp2Stream::transitionState(StateTransition transition)
+{
+ switch (m_state) {
+ case State::Idle:
+ if (transition == StateTransition::Open)
+ setState(State::Open);
+ else
+ Q_UNREACHABLE(); // We should transition to Open before ever getting here
+ break;
+ case State::Open:
+ switch (transition) {
+ case StateTransition::CloseLocal:
+ setState(State::HalfClosedLocal);
+ break;
+ case StateTransition::CloseRemote:
+ setState(State::HalfClosedRemote);
+ break;
+ case StateTransition::RST:
+ setState(State::Closed);
+ break;
+ case StateTransition::Open: // no-op
+ break;
+ }
+ break;
+ case State::HalfClosedLocal:
+ if (transition == StateTransition::CloseRemote || transition == StateTransition::RST)
+ setState(State::Closed);
+ break;
+ case State::HalfClosedRemote:
+ if (transition == StateTransition::CloseLocal || transition == StateTransition::RST)
+ setState(State::Closed);
+ break;
+ case State::ReservedRemote:
+ if (transition == StateTransition::RST) {
+ setState(State::Closed);
+ } else if (transition == StateTransition::CloseLocal) { // Receiving HEADER closes local
+ setState(State::HalfClosedLocal);
+ }
+ break;
+ case State::Closed:
+ break;
+ }
+}
+
+void QHttp2Stream::handleDATA(const Frame &inboundFrame)
+{
+ QHttp2Connection *connection = getConnection();
+
+ qCDebug(qHttp2ConnectionLog, "[%p] stream %u, received DATA frame with payload of %u bytes",
+ connection, m_streamID, inboundFrame.payloadSize());
+
+ if (qint32(inboundFrame.payloadSize()) > m_recvWindow) {
+ qCDebug(qHttp2ConnectionLog,
+ "[%p] stream %u, received DATA frame with payload size %u, "
+ "but recvWindow is %d, sending FLOW_CONTROL_ERROR",
+ connection, m_streamID, inboundFrame.payloadSize(), m_recvWindow);
+ finishWithError(QNetworkReply::ProtocolFailure, "flow control error"_L1);
+ sendRST_STREAM(FLOW_CONTROL_ERROR);
+ return;
+ }
+ m_recvWindow -= qint32(inboundFrame.payloadSize());
+ const bool endStream = inboundFrame.flags().testFlag(FrameFlag::END_STREAM);
+ // Uncompress data if needed and append it ...
+ if (inboundFrame.dataSize() > 0 || endStream) {
+ QByteArray fragment(reinterpret_cast<const char *>(inboundFrame.dataBegin()),
+ inboundFrame.dataSize());
+ if (endStream)
+ transitionState(StateTransition::CloseRemote);
+ emit dataReceived(fragment, endStream);
+ m_downloadBuffer.append(std::move(fragment));
+ }
+
+ if (!endStream && m_recvWindow < connection->streamInitialReceiveWindowSize / 2) {
+ // @future[consider]: emit signal instead
+ sendWINDOW_UPDATE(quint32(connection->streamInitialReceiveWindowSize - m_recvWindow));
+ }
+}
+
+void QHttp2Stream::handleHEADERS(Http2::FrameFlags frameFlags, const HPack::HttpHeader &headers)
+{
+ if (m_state == State::Idle)
+ transitionState(StateTransition::Open);
+ const bool endStream = frameFlags.testFlag(FrameFlag::END_STREAM);
+ if (endStream)
+ transitionState(StateTransition::CloseRemote);
+ if (!headers.empty()) {
+ m_headers.insert(m_headers.end(), headers.begin(), headers.end());
+ emit headersUpdated();
+ }
+ emit headersReceived(headers, endStream);
+}
+
+void QHttp2Stream::handleRST_STREAM(const Frame &inboundFrame)
+{
+ transitionState(StateTransition::RST);
+ m_RST_STREAM_code = qFromBigEndian<quint32>(inboundFrame.dataBegin());
+ if (isUploadingDATA()) {
+ disconnect(m_uploadByteDevice, nullptr, this, nullptr);
+ m_uploadDevice = nullptr;
+ m_uploadByteDevice = nullptr;
+ }
+ finishWithError(*m_RST_STREAM_code, ""_L1);
+}
+
+void QHttp2Stream::handleWINDOW_UPDATE(const Frame &inboundFrame)
+{
+ const quint32 delta = qFromBigEndian<quint32>(inboundFrame.dataBegin());
+ const bool valid = delta && delta <= quint32(std::numeric_limits<qint32>::max());
+ qint32 sum = 0;
+ if (!valid || qAddOverflow(m_sendWindow, qint32(delta), &sum)) {
+ qCDebug(qHttp2ConnectionLog,
+ "[%p] stream %u, received WINDOW_UPDATE frame with invalid delta %u, sending "
+ "PROTOCOL_ERROR",
+ getConnection(), m_streamID, delta);
+ finishWithError(QNetworkReply::ProtocolFailure, "invalid WINDOW_UPDATE delta"_L1);
+ sendRST_STREAM(PROTOCOL_ERROR);
+ return;
+ }
+ m_sendWindow = sum;
+ // Stream may have been unblocked, so maybe try to write again
+ if (isUploadingDATA())
+ maybeResumeUpload();
+}
+
+/*!
+ \class QHttp2Connection
+ \inmodule QtNetwork
+ \internal
+
+ The QHttp2Connection class represents a HTTP/2 connection.
+ It can only be created through the static functions
+ createDirectConnection(), createUpgradedConnection(),
+ and createDirectServerConnection().
+
+ createDirectServerConnection() is used for server-side connections, and has
+ certain limitations that a client does not.
+
+ As a client you can create a QHttp2Stream with createStream().
+
+ \sa QHttp2Stream
+*/
+
+/*!
+ \fn void QHttp2Connection::newIncomingStream(QHttp2Stream *stream)
+
+ This signal is emitted when a new \a stream is received from the remote
+ peer.
+*/
+
+/*!
+ \fn void QHttp2Connection::newPromisedStream(QHttp2Stream *stream)
+
+ This signal is emitted when the remote peer has promised a new \a stream.
+*/
+
+/*!
+ \fn void QHttp2Connection::errorReceived()
+
+ This signal is emitted when the connection has received an error.
+*/
+
+/*!
+ \fn void QHttp2Connection::connectionClosed()
+
+ This signal is emitted when the connection has been closed.
+*/
+
+/*!
+ \fn void QHttp2Connection::settingsFrameReceived()
+
+ This signal is emitted when the connection has received a SETTINGS frame.
+*/
+
+/*!
+ \fn void QHttp2Connection::errorOccurred(Http2::Http2Error errorCode, const QString &errorString)
+
+ This signal is emitted when the connection has encountered an error. The
+ \a errorCode parameter is the HTTP/2 error code, and the \a errorString
+ parameter is a human-readable description of the error.
+*/
+
+/*!
+ \fn void QHttp2Connection::receivedGOAWAY(quint32 errorCode, quint32 lastStreamID)
+
+ This signal is emitted when the connection has received a GOAWAY frame. The
+ \a errorCode parameter is the HTTP/2 error code, and the \a lastStreamID
+ parameter is the last stream ID that the remote peer will process.
+
+ Any streams of a higher stream ID created by us will be ignored or reset.
+*/
+
+/*!
+ Create a new HTTP2 connection given a \a config and a \a socket.
+ This function assumes that the Upgrade headers etc. in http/1 have already
+ been sent and that the connection is already upgraded to http/2.
+
+ The object returned will be a child to the \a socket, or null on failure.
+*/
+QHttp2Connection *QHttp2Connection::createUpgradedConnection(QIODevice *socket,
+ const QHttp2Configuration &config)
+{
+ Q_ASSERT(socket);
+
+ auto connection = std::unique_ptr<QHttp2Connection>(new QHttp2Connection(socket));
+ connection->setH2Configuration(config);
+ connection->m_connectionType = QHttp2Connection::Type::Client;
+ // HTTP2 connection is already established and request was sent, so stream 1
+ // is already 'active' and is closed for any further outgoing data.
+ QHttp2Stream *stream = connection->createStreamInternal().unwrap();
+ Q_ASSERT(stream->streamID() == 1);
+ stream->setState(QHttp2Stream::State::HalfClosedLocal);
+ connection->m_upgradedConnection = true;
+
+ if (!connection->sendClientPreface()) {
+ qCWarning(qHttp2ConnectionLog, "[%p] Failed to send client preface", connection.get());
+ return nullptr;
+ }
+
+ return connection.release();
+}
+
+/*!
+ Create a new HTTP2 connection given a \a config and a \a socket.
+ This function will immediately send the client preface.
+
+ The object returned will be a child to the \a socket, or null on failure.
+*/
+QHttp2Connection *QHttp2Connection::createDirectConnection(QIODevice *socket,
+ const QHttp2Configuration &config)
+{
+ auto connection = std::unique_ptr<QHttp2Connection>(new QHttp2Connection(socket));
+ connection->setH2Configuration(config);
+ connection->m_connectionType = QHttp2Connection::Type::Client;
+
+ if (!connection->sendClientPreface()) {
+ qCWarning(qHttp2ConnectionLog, "[%p] Failed to send client preface", connection.get());
+ return nullptr;
+ }
+
+ return connection.release();
+}
+
+/*!
+ Create a new HTTP2 connection given a \a config and a \a socket.
+
+ The object returned will be a child to the \a socket, or null on failure.
+*/
+QHttp2Connection *QHttp2Connection::createDirectServerConnection(QIODevice *socket,
+ const QHttp2Configuration &config)
+{
+ auto connection = std::unique_ptr<QHttp2Connection>(new QHttp2Connection(socket));
+ connection->setH2Configuration(config);
+ connection->m_connectionType = QHttp2Connection::Type::Server;
+
+ connection->m_nextStreamID = 2; // server-initiated streams must be even
+
+ connection->m_waitingForClientPreface = true;
+
+ return connection.release();
+}
+
+/*!
+ Creates a stream on this connection.
+
+ Automatically picks the next available stream ID and returns a pointer to
+ the new stream, if possible. Otherwise returns an error.
+
+ \sa QHttp2Connection::CreateStreamError, QHttp2Stream
+*/
+QH2Expected<QHttp2Stream *, QHttp2Connection::CreateStreamError> QHttp2Connection::createStream()
+{
+ Q_ASSERT(m_connectionType == Type::Client); // This overload is just for clients
+ if (m_nextStreamID > lastValidStreamID)
+ return { QHttp2Connection::CreateStreamError::StreamIdsExhausted };
+ return createStreamInternal();
+}
+
+QH2Expected<QHttp2Stream *, QHttp2Connection::CreateStreamError>
+QHttp2Connection::createStreamInternal()
+{
+ if (m_goingAway)
+ return { QHttp2Connection::CreateStreamError::ReceivedGOAWAY };
+ const quint32 streamID = m_nextStreamID;
+ if (size_t(m_maxConcurrentStreams) <= size_t(numActiveLocalStreams()))
+ return { QHttp2Connection::CreateStreamError::MaxConcurrentStreamsReached };
+ m_nextStreamID += 2;
+ return { createStreamInternal_impl(streamID) };
+}
+
+QHttp2Stream *QHttp2Connection::createStreamInternal_impl(quint32 streamID)
+{
+ qsizetype numStreams = m_streams.size();
+ QPointer<QHttp2Stream> &stream = m_streams[streamID];
+ if (numStreams == m_streams.size()) // stream already existed
+ return nullptr;
+ stream = new QHttp2Stream(this, streamID);
+ stream->m_recvWindow = streamInitialReceiveWindowSize;
+ stream->m_sendWindow = streamInitialSendWindowSize;
+ return stream;
+}
+
+qsizetype QHttp2Connection::numActiveStreamsImpl(quint32 mask) const noexcept
+{
+ const auto shouldCount = [mask](const QPointer<QHttp2Stream> &stream) -> bool {
+ return stream && (stream->streamID() & 1) == mask;
+ };
+ return std::count_if(m_streams.cbegin(), m_streams.cend(), shouldCount);
+}
+
+/*!
+ \internal
+ The number of streams the remote peer has started that are still active.
+*/
+qsizetype QHttp2Connection::numActiveRemoteStreams() const noexcept
+{
+ const quint32 RemoteMask = m_connectionType == Type::Client ? 0 : 1;
+ return numActiveStreamsImpl(RemoteMask);
+}
+
+/*!
+ \internal
+ The number of streams we have started that are still active.
+*/
+qsizetype QHttp2Connection::numActiveLocalStreams() const noexcept
+{
+ const quint32 LocalMask = m_connectionType == Type::Client ? 1 : 0;
+ return numActiveStreamsImpl(LocalMask);
+}
+
+/*!
+ Return a pointer to a stream with the given \a streamID, or null if no such
+ stream exists or it was deleted.
+*/
+QHttp2Stream *QHttp2Connection::getStream(quint32 streamID) const
+{
+ return m_streams.value(streamID, nullptr).get();
+}
+
+
+/*!
+ \fn QHttp2Stream *QHttp2Connection::promisedStream(const QUrl &streamKey) const
+
+ Returns a pointer to the stream that was promised with the given
+ \a streamKey, if any. Otherwise, returns null.
+*/
+
+/*!
+ \fn void QHttp2Connection::close()
+
+ This sends a GOAWAY frame on the connection stream, gracefully closing the
+ connection.
+*/
+
+/*!
+ \fn bool QHttp2Connection::isGoingAway() const noexcept
+
+ Returns \c true if the connection is in the process of being closed, or
+ \c false otherwise.
+*/
+
+/*!
+ \fn quint32 QHttp2Connection::maxConcurrentStreams() const noexcept
+
+ Returns the maximum number of concurrent streams we are allowed to have
+ active at any given time. This is a directional setting, and the remote
+ peer may have a different value.
+*/
+
+/*!
+ \fn quint32 QHttp2Connection::maxHeaderListSize() const noexcept
+
+ Returns the maximum size of the header which the peer is willing to accept.
+*/
+
+/*!
+ \fn bool QHttp2Connection::isUpgradedConnection() const noexcept
+
+ Returns \c true if this connection was created as a result of an HTTP/1
+ upgrade to HTTP/2, or \c false otherwise.
+*/
+
+QHttp2Connection::QHttp2Connection(QIODevice *socket) : QObject(socket)
+{
+ Q_ASSERT(socket);
+ Q_ASSERT(socket->isOpen());
+ Q_ASSERT(socket->openMode() & QIODevice::ReadWrite);
+ // We don't make any connections directly because this is used in
+ // in the http2 protocol handler, which is used by
+ // QHttpNetworkConnectionChannel. Which in turn owns and deals with all the
+ // socket connections.
+}
+
+QHttp2Connection::~QHttp2Connection() noexcept
+{
+ // delete streams now so that any calls it might make back to this
+ // Connection will operate on a valid object.
+ for (QPointer<QHttp2Stream> &stream : std::exchange(m_streams, {}))
+ delete stream.get();
+}
+
+bool QHttp2Connection::serverCheckClientPreface()
+{
+ if (!m_waitingForClientPreface)
+ return true;
+ auto *socket = getSocket();
+ if (socket->bytesAvailable() < Http2::clientPrefaceLength)
+ return false;
+ if (!readClientPreface()) {
+ socket->close();
+ emit errorOccurred(Http2Error::PROTOCOL_ERROR, "invalid client preface"_L1);
+ qCDebug(qHttp2ConnectionLog, "[%p] Invalid client preface", this);
+ return false;
+ }
+ qCDebug(qHttp2ConnectionLog, "[%p] Peer sent valid client preface", this);
+ m_waitingForClientPreface = false;
+ if (!sendServerPreface()) {
+ connectionError(Http2::INTERNAL_ERROR, "Failed to send server preface");
+ return false;
+ }
+ return true;
+}
+
+bool QHttp2Connection::sendPing()
+{
+ std::array<char, 8> data;
+
+ QRandomGenerator gen;
+ gen.generate(data.begin(), data.end());
+ return sendPing(data);
+}
+
+bool QHttp2Connection::sendPing(QByteArrayView data)
+{
+ frameWriter.start(FrameType::PING, FrameFlag::EMPTY, connectionStreamID);
+
+ Q_ASSERT(data.length() == 8);
+ if (!m_lastPingSignature) {
+ m_lastPingSignature = data.toByteArray();
+ } else {
+ qCWarning(qHttp2ConnectionLog, "[%p] No PING is sent while waiting for the previous PING.", this);
+ return false;
+ }
+
+ frameWriter.append((uchar*)data.data(), (uchar*)data.end());
+ frameWriter.write(*getSocket());
+ return true;
+}
+
+/*!
+ This function must be called when you have received a readyRead signal
+ (or equivalent) from the QIODevice. It will read and process any incoming
+ HTTP/2 frames and emit signals as appropriate.
+*/
+void QHttp2Connection::handleReadyRead()
+{
+ /* event loop */
+ if (m_connectionType == Type::Server && !serverCheckClientPreface())
+ return;
+
+ const auto streamIsActive = [](const QPointer<QHttp2Stream> &stream) {
+ return stream && stream->isActive();
+ };
+ if (m_goingAway && std::none_of(m_streams.cbegin(), m_streams.cend(), streamIsActive)) {
+ close();
+ return;
+ }
+ QIODevice *socket = getSocket();
+
+ qCDebug(qHttp2ConnectionLog, "[%p] Receiving data, %lld bytes available", this,
+ socket->bytesAvailable());
+
+ using namespace Http2;
+ while (!m_goingAway || std::any_of(m_streams.cbegin(), m_streams.cend(), streamIsActive)) {
+ const auto result = frameReader.read(*socket);
+ if (result != FrameStatus::goodFrame)
+ qCDebug(qHttp2ConnectionLog, "[%p] Tried to read frame, got %d", this, int(result));
+ switch (result) {
+ case FrameStatus::incompleteFrame:
+ return;
+ case FrameStatus::protocolError:
+ return connectionError(PROTOCOL_ERROR, "invalid frame");
+ case FrameStatus::sizeError:
+ return connectionError(FRAME_SIZE_ERROR, "invalid frame size");
+ default:
+ break;
+ }
+
+ Q_ASSERT(result == FrameStatus::goodFrame);
+
+ inboundFrame = std::move(frameReader.inboundFrame());
+
+ const auto frameType = inboundFrame.type();
+ qCDebug(qHttp2ConnectionLog, "[%p] Successfully read a frame, with type: %d", this,
+ int(frameType));
+ if (continuationExpected && frameType != FrameType::CONTINUATION)
+ return connectionError(PROTOCOL_ERROR, "CONTINUATION expected");
+
+ switch (frameType) {
+ case FrameType::DATA:
+ handleDATA();
+ break;
+ case FrameType::HEADERS:
+ handleHEADERS();
+ break;
+ case FrameType::PRIORITY:
+ handlePRIORITY();
+ break;
+ case FrameType::RST_STREAM:
+ handleRST_STREAM();
+ break;
+ case FrameType::SETTINGS:
+ handleSETTINGS();
+ break;
+ case FrameType::PUSH_PROMISE:
+ handlePUSH_PROMISE();
+ break;
+ case FrameType::PING:
+ handlePING();
+ break;
+ case FrameType::GOAWAY:
+ handleGOAWAY();
+ break;
+ case FrameType::WINDOW_UPDATE:
+ handleWINDOW_UPDATE();
+ break;
+ case FrameType::CONTINUATION:
+ handleCONTINUATION();
+ break;
+ case FrameType::LAST_FRAME_TYPE:
+ // 5.1 - ignore unknown frames.
+ break;
+ }
+ }
+}
+
+bool QHttp2Connection::readClientPreface()
+{
+ auto *socket = getSocket();
+ Q_ASSERT(socket->bytesAvailable() >= Http2::clientPrefaceLength);
+ char buffer[Http2::clientPrefaceLength];
+ const qint64 read = socket->read(buffer, Http2::clientPrefaceLength);
+ if (read != Http2::clientPrefaceLength)
+ return false;
+ return memcmp(buffer, Http2::Http2clientPreface, Http2::clientPrefaceLength) == 0;
+}
+
+/*!
+ This function must be called when the socket has been disconnected, and will
+ end all remaining streams with an error.
+*/
+void QHttp2Connection::handleConnectionClosure()
+{
+ const auto errorString = QCoreApplication::translate("QHttp", "Connection closed");
+ for (auto it = m_streams.begin(), end = m_streams.end(); it != end; ++it) {
+ auto stream = it.value();
+ if (stream && stream->isActive())
+ stream->finishWithError(QNetworkReply::RemoteHostClosedError, errorString);
+ }
+}
+
+void QHttp2Connection::setH2Configuration(QHttp2Configuration config)
+{
+ m_config = std::move(config);
+
+ // These values comes from our own API so trust it to be sane.
+ maxSessionReceiveWindowSize = qint32(m_config.sessionReceiveWindowSize());
+ pushPromiseEnabled = m_config.serverPushEnabled();
+ streamInitialReceiveWindowSize = qint32(m_config.streamReceiveWindowSize());
+ encoder.setCompressStrings(m_config.huffmanCompressionEnabled());
+}
+
+void QHttp2Connection::connectionError(Http2Error errorCode, const char *message)
+{
+ Q_ASSERT(message);
+ if (m_goingAway)
+ return;
+
+ qCCritical(qHttp2ConnectionLog, "[%p] Connection error: %s (%d)", this, message,
+ int(errorCode));
+
+ m_goingAway = true;
+ sendGOAWAY(errorCode);
+ const auto error = qt_error(errorCode);
+ auto messageView = QLatin1StringView(message);
+
+ for (QHttp2Stream *stream : std::as_const(m_streams)) {
+ if (stream && stream->isActive())
+ stream->finishWithError(error, messageView);
+ }
+
+ closeSession();
+}
+
+void QHttp2Connection::closeSession()
+{
+ emit connectionClosed();
+}
+
+bool QHttp2Connection::streamWasReset(quint32 streamID) noexcept
+{
+ return m_resetStreamIDs.contains(streamID);
+}
+
+bool QHttp2Connection::isInvalidStream(quint32 streamID) noexcept
+{
+ auto stream = m_streams.value(streamID, nullptr);
+ return !stream && !streamWasReset(streamID);
+}
+
+bool QHttp2Connection::sendClientPreface()
+{
+ QIODevice *socket = getSocket();
+ // 3.5 HTTP/2 Connection Preface
+ const qint64 written = socket->write(Http2clientPreface, clientPrefaceLength);
+ if (written != clientPrefaceLength)
+ return false;
+
+ if (!sendSETTINGS()) {
+ qCWarning(qHttp2ConnectionLog, "[%p] Failed to send SETTINGS", this);
+ return false;
+ }
+ return true;
+}
+
+bool QHttp2Connection::sendServerPreface()
+{
+ // We send our SETTINGS frame and ACK the client's SETTINGS frame when it
+ // arrives.
+ if (!sendSETTINGS()) {
+ qCWarning(qHttp2ConnectionLog, "[%p] Failed to send SETTINGS", this);
+ return false;
+ }
+ return true;
+}
+
+bool QHttp2Connection::sendSETTINGS()
+{
+ QIODevice *socket = getSocket();
+ // 6.5 SETTINGS
+ frameWriter.setOutboundFrame(configurationToSettingsFrame(m_config));
+ qCDebug(qHttp2ConnectionLog, "[%p] Sending SETTINGS frame, %d bytes", this,
+ frameWriter.outboundFrame().payloadSize());
+ Q_ASSERT(frameWriter.outboundFrame().payloadSize());
+
+ if (!frameWriter.write(*socket))
+ return false;
+
+ sessionReceiveWindowSize = maxSessionReceiveWindowSize;
+ // We only send WINDOW_UPDATE for the connection if the size differs from the
+ // default 64 KB:
+ const auto delta = maxSessionReceiveWindowSize - defaultSessionWindowSize;
+ if (delta && !sendWINDOW_UPDATE(connectionStreamID, delta))
+ return false;
+
+ waitingForSettingsACK = true;
+ return true;
+}
+
+bool QHttp2Connection::sendWINDOW_UPDATE(quint32 streamID, quint32 delta)
+{
+ qCDebug(qHttp2ConnectionLog, "[%p] Sending WINDOW_UPDATE frame, stream %d, delta %u", this,
+ streamID, delta);
+ frameWriter.start(FrameType::WINDOW_UPDATE, FrameFlag::EMPTY, streamID);
+ frameWriter.append(delta);
+ return frameWriter.write(*getSocket());
+}
+
+bool QHttp2Connection::sendGOAWAY(quint32 errorCode)
+{
+ frameWriter.start(FrameType::GOAWAY, FrameFlag::EMPTY,
+ Http2PredefinedParameters::connectionStreamID);
+ frameWriter.append(quint32(m_lastIncomingStreamID));
+ frameWriter.append(errorCode);
+ return frameWriter.write(*getSocket());
+}
+
+bool QHttp2Connection::sendSETTINGS_ACK()
+{
+ frameWriter.start(FrameType::SETTINGS, FrameFlag::ACK, Http2::connectionStreamID);
+ return frameWriter.write(*getSocket());
+}
+
+void QHttp2Connection::handleDATA()
+{
+ Q_ASSERT(inboundFrame.type() == FrameType::DATA);
+
+ const auto streamID = inboundFrame.streamID();
+ if (streamID == connectionStreamID)
+ return connectionError(PROTOCOL_ERROR, "DATA on the connection stream");
+
+ if (isInvalidStream(streamID))
+ return connectionError(ENHANCE_YOUR_CALM, "DATA on invalid stream");
+
+ if (qint32(inboundFrame.payloadSize()) > sessionReceiveWindowSize) {
+ qCDebug(qHttp2ConnectionLog,
+ "[%p] Received DATA frame with payload size %u, "
+ "but recvWindow is %d, sending FLOW_CONTROL_ERROR",
+ this, inboundFrame.payloadSize(), sessionReceiveWindowSize);
+ return connectionError(FLOW_CONTROL_ERROR, "Flow control error");
+ }
+
+ sessionReceiveWindowSize -= inboundFrame.payloadSize();
+
+ auto it = m_streams.constFind(streamID);
+ if (it != m_streams.cend() && it.value())
+ it.value()->handleDATA(inboundFrame);
+
+ if (sessionReceiveWindowSize < maxSessionReceiveWindowSize / 2) {
+ // @future[consider]: emit signal instead
+ QMetaObject::invokeMethod(this, &QHttp2Connection::sendWINDOW_UPDATE, Qt::QueuedConnection,
+ quint32(connectionStreamID),
+ quint32(maxSessionReceiveWindowSize - sessionReceiveWindowSize));
+ sessionReceiveWindowSize = maxSessionReceiveWindowSize;
+ }
+}
+
+void QHttp2Connection::handleHEADERS()
+{
+ Q_ASSERT(inboundFrame.type() == FrameType::HEADERS);
+
+ const auto streamID = inboundFrame.streamID();
+ qCDebug(qHttp2ConnectionLog, "[%p] Received HEADERS frame on stream %d", this, streamID);
+
+ if (streamID == connectionStreamID)
+ return connectionError(PROTOCOL_ERROR, "HEADERS on 0x0 stream");
+
+ const bool isClient = m_connectionType == Type::Client;
+ const bool isClientInitiatedStream = !!(streamID & 1);
+ const bool isRemotelyInitiatedStream = isClient ^ isClientInitiatedStream;
+
+ if (isRemotelyInitiatedStream && streamID > m_lastIncomingStreamID) {
+ QHttp2Stream *newStream = createStreamInternal_impl(streamID);
+ Q_ASSERT(newStream);
+ m_lastIncomingStreamID = streamID;
+ qCDebug(qHttp2ConnectionLog, "[%p] Created new incoming stream %d", this, streamID);
+ emit newIncomingStream(newStream);
+ } else if (auto it = m_streams.constFind(streamID); it == m_streams.cend()) {
+ qCDebug(qHttp2ConnectionLog, "[%p] Received HEADERS on non-existent stream %d", this,
+ streamID);
+ return connectionError(PROTOCOL_ERROR, "HEADERS on invalid stream");
+ } else if (!*it || (*it)->wasReset()) {
+ qCDebug(qHttp2ConnectionLog, "[%p] Received HEADERS on reset stream %d", this, streamID);
+ return connectionError(ENHANCE_YOUR_CALM, "HEADERS on invalid stream");
+ }
+
+ const auto flags = inboundFrame.flags();
+ if (flags.testFlag(FrameFlag::PRIORITY)) {
+ qCDebug(qHttp2ConnectionLog, "[%p] HEADERS frame on stream %d has PRIORITY flag", this,
+ streamID);
+ handlePRIORITY();
+ if (m_goingAway)
+ return;
+ }
+
+ const bool endHeaders = flags.testFlag(FrameFlag::END_HEADERS);
+ continuedFrames.clear();
+ continuedFrames.push_back(std::move(inboundFrame));
+ if (!endHeaders) {
+ continuationExpected = true;
+ return;
+ }
+
+ handleContinuedHEADERS();
+}
+
+void QHttp2Connection::handlePRIORITY()
+{
+ Q_ASSERT(inboundFrame.type() == FrameType::PRIORITY
+ || inboundFrame.type() == FrameType::HEADERS);
+
+ const auto streamID = inboundFrame.streamID();
+ if (streamID == connectionStreamID)
+ return connectionError(PROTOCOL_ERROR, "PRIORITY on 0x0 stream");
+
+ if (isInvalidStream(streamID))
+ return connectionError(ENHANCE_YOUR_CALM, "PRIORITY on invalid stream");
+
+ quint32 streamDependency = 0;
+ uchar weight = 0;
+ const bool noErr = inboundFrame.priority(&streamDependency, &weight);
+ Q_UNUSED(noErr);
+ Q_ASSERT(noErr);
+
+ const bool exclusive = streamDependency & 0x80000000;
+ streamDependency &= ~0x80000000;
+
+ // Ignore this for now ...
+ // Can be used for streams (re)prioritization - 5.3
+ Q_UNUSED(exclusive);
+ Q_UNUSED(weight);
+}
+
+void QHttp2Connection::handleRST_STREAM()
+{
+ Q_ASSERT(inboundFrame.type() == FrameType::RST_STREAM);
+
+ // "RST_STREAM frames MUST be associated with a stream.
+ // If a RST_STREAM frame is received with a stream identifier of 0x0,
+ // the recipient MUST treat this as a connection error (Section 5.4.1)
+ // of type PROTOCOL_ERROR.
+ const auto streamID = inboundFrame.streamID();
+ if (streamID == connectionStreamID)
+ return connectionError(PROTOCOL_ERROR, "RST_STREAM on 0x0");
+
+ if (!(streamID & 0x1)) { // @future[server]: must be updated for server-side handling
+ // RST_STREAM on a promised stream:
+ // since we do not keep track of such streams,
+ // just ignore.
+ return;
+ }
+
+ // Anything greater than m_nextStreamID has not been started yet.
+ if (streamID >= m_nextStreamID) {
+ // "RST_STREAM frames MUST NOT be sent for a stream
+ // in the "idle" state. .. the recipient MUST treat this
+ // as a connection error (Section 5.4.1) of type PROTOCOL_ERROR."
+ return connectionError(PROTOCOL_ERROR, "RST_STREAM on idle stream");
+ }
+
+ Q_ASSERT(inboundFrame.dataSize() == 4);
+
+ if (QPointer<QHttp2Stream> stream = m_streams[streamID])
+ stream->handleRST_STREAM(inboundFrame);
+}
+
+void QHttp2Connection::handleSETTINGS()
+{
+ // 6.5 SETTINGS.
+ Q_ASSERT(inboundFrame.type() == FrameType::SETTINGS);
+
+ if (inboundFrame.streamID() != connectionStreamID)
+ return connectionError(PROTOCOL_ERROR, "SETTINGS on invalid stream");
+
+ if (inboundFrame.flags().testFlag(FrameFlag::ACK)) {
+ if (!waitingForSettingsACK)
+ return connectionError(PROTOCOL_ERROR, "unexpected SETTINGS ACK");
+ qCDebug(qHttp2ConnectionLog, "[%p] Received SETTINGS ACK", this);
+ waitingForSettingsACK = false;
+ return;
+ }
+ qCDebug(qHttp2ConnectionLog, "[%p] Received SETTINGS frame", this);
+
+ if (inboundFrame.dataSize()) {
+ auto src = inboundFrame.dataBegin();
+ for (const uchar *end = src + inboundFrame.dataSize(); src != end; src += 6) {
+ const Settings identifier = Settings(qFromBigEndian<quint16>(src));
+ const quint32 intVal = qFromBigEndian<quint32>(src + 2);
+ if (!acceptSetting(identifier, intVal)) {
+ // If not accepted - we finish with connectionError.
+ qCDebug(qHttp2ConnectionLog, "[%p] Received an unacceptable setting, %u, %u", this,
+ quint32(identifier), intVal);
+ return; // connectionError already called in acceptSetting.
+ }
+ }
+ }
+
+ qCDebug(qHttp2ConnectionLog, "[%p] Sending SETTINGS ACK", this);
+ emit settingsFrameReceived();
+ sendSETTINGS_ACK();
+}
+
+void QHttp2Connection::handlePUSH_PROMISE()
+{
+ // 6.6 PUSH_PROMISE.
+ Q_ASSERT(inboundFrame.type() == FrameType::PUSH_PROMISE);
+
+ if (!pushPromiseEnabled && !waitingForSettingsACK) {
+ // This means, server ACKed our 'NO PUSH',
+ // but sent us PUSH_PROMISE anyway.
+ return connectionError(PROTOCOL_ERROR, "unexpected PUSH_PROMISE frame");
+ }
+
+ const auto streamID = inboundFrame.streamID();
+ if (streamID == connectionStreamID)
+ return connectionError(PROTOCOL_ERROR, "PUSH_PROMISE with invalid associated stream (0x0)");
+
+ auto it = m_streams.constFind(streamID);
+#if 0 // Needs to be done after some timeout in case the stream has only just been reset
+ if (it != m_streams.constEnd()) {
+ QHttp2Stream *associatedStream = it->get();
+ if (associatedStream->state() != QHttp2Stream::State::Open
+ && associatedStream->state() != QHttp2Stream::State::HalfClosedLocal) {
+ // Cause us to error out below:
+ it = m_streams.constEnd();
+ }
+ }
+#endif
+ if (it == m_streams.constEnd())
+ return connectionError(ENHANCE_YOUR_CALM, "PUSH_PROMISE with invalid associated stream");
+
+ const auto reservedID = qFromBigEndian<quint32>(inboundFrame.dataBegin());
+ if ((reservedID & 1) || reservedID <= m_lastIncomingStreamID || reservedID > lastValidStreamID)
+ return connectionError(PROTOCOL_ERROR, "PUSH_PROMISE with invalid promised stream ID");
+
+ auto *stream = createStreamInternal_impl(reservedID);
+ if (!stream)
+ return connectionError(PROTOCOL_ERROR, "PUSH_PROMISE with already active stream ID");
+ m_lastIncomingStreamID = reservedID;
+ stream->setState(QHttp2Stream::State::ReservedRemote);
+
+ if (!pushPromiseEnabled) {
+ // "ignoring a PUSH_PROMISE frame causes the stream state to become
+ // indeterminate" - let's send RST_STREAM frame with REFUSE_STREAM code.
+ stream->sendRST_STREAM(REFUSE_STREAM);
+ }
+
+ const bool endHeaders = inboundFrame.flags().testFlag(FrameFlag::END_HEADERS);
+ continuedFrames.clear();
+ continuedFrames.push_back(std::move(inboundFrame));
+
+ if (!endHeaders) {
+ continuationExpected = true;
+ return;
+ }
+
+ handleContinuedHEADERS();
+}
+
+void QHttp2Connection::handlePING()
+{
+ Q_ASSERT(inboundFrame.type() == FrameType::PING);
+ Q_ASSERT(inboundFrame.dataSize() == 8);
+
+ if (inboundFrame.streamID() != connectionStreamID)
+ return connectionError(PROTOCOL_ERROR, "PING on invalid stream");
+
+ if (inboundFrame.flags() & FrameFlag::ACK) {
+ QByteArrayView pingSignature(reinterpret_cast<const char *>(inboundFrame.dataBegin()), 8);
+ if (!m_lastPingSignature.has_value()) {
+ emit pingFrameRecived(PingState::PongNoPingSent);
+ qCWarning(qHttp2ConnectionLog, "[%p] PING with ACK received but no PING was sent.", this);
+ } else if (pingSignature != m_lastPingSignature) {
+ emit pingFrameRecived(PingState::PongSignatureChanged);
+ qCWarning(qHttp2ConnectionLog, "[%p] PING signature does not match the last PING.", this);
+ } else {
+ emit pingFrameRecived(PingState::PongSignatureIdentical);
+ }
+ m_lastPingSignature.reset();
+ return;
+ } else {
+ emit pingFrameRecived(PingState::Ping);
+
+ }
+
+
+ frameWriter.start(FrameType::PING, FrameFlag::ACK, connectionStreamID);
+ frameWriter.append(inboundFrame.dataBegin(), inboundFrame.dataBegin() + 8);
+ frameWriter.write(*getSocket());
+}
+
+void QHttp2Connection::handleGOAWAY()
+{
+ // 6.8 GOAWAY
+
+ Q_ASSERT(inboundFrame.type() == FrameType::GOAWAY);
+ // "An endpoint MUST treat a GOAWAY frame with a stream identifier
+ // other than 0x0 as a connection error (Section 5.4.1) of type PROTOCOL_ERROR."
+ if (inboundFrame.streamID() != connectionStreamID)
+ return connectionError(PROTOCOL_ERROR, "GOAWAY on invalid stream");
+
+ const uchar *const src = inboundFrame.dataBegin();
+ quint32 lastStreamID = qFromBigEndian<quint32>(src);
+ const quint32 errorCode = qFromBigEndian<quint32>(src + 4);
+
+ if (!lastStreamID) {
+ // "The last stream identifier can be set to 0 if no
+ // streams were processed."
+ lastStreamID = 1;
+ } 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");
+ } else if (lastStreamID >= m_nextStreamID) {
+ // "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."
+ if (lastStreamID != lastValidStreamID || errorCode != HTTP2_NO_ERROR)
+ return connectionError(PROTOCOL_ERROR, "GOAWAY invalid stream/error code");
+ } else {
+ lastStreamID += 2;
+ }
+
+ m_goingAway = true;
+
+ emit receivedGOAWAY(errorCode, lastStreamID);
+
+ for (quint32 id = lastStreamID; id < m_nextStreamID; id += 2) {
+ QHttp2Stream *stream = m_streams.value(id, nullptr);
+ if (stream && stream->isActive())
+ stream->finishWithError(errorCode, "Received GOAWAY"_L1);
+ }
+
+ const auto isActive = [](const QHttp2Stream *stream) { return stream && stream->isActive(); };
+ if (std::none_of(m_streams.cbegin(), m_streams.cend(), isActive))
+ closeSession();
+}
+
+void QHttp2Connection::handleWINDOW_UPDATE()
+{
+ Q_ASSERT(inboundFrame.type() == FrameType::WINDOW_UPDATE);
+
+ const quint32 delta = qFromBigEndian<quint32>(inboundFrame.dataBegin());
+ const bool valid = delta && delta <= quint32(std::numeric_limits<qint32>::max());
+ const auto streamID = inboundFrame.streamID();
+
+ qCDebug(qHttp2ConnectionLog(), "[%p] Received WINDOW_UPDATE, stream %d, delta %d", this,
+ streamID, delta);
+ if (streamID == connectionStreamID) {
+ qint32 sum = 0;
+ if (!valid || qAddOverflow(sessionSendWindowSize, qint32(delta), &sum))
+ return connectionError(PROTOCOL_ERROR, "WINDOW_UPDATE invalid delta");
+ sessionSendWindowSize = sum;
+ for (auto &stream : m_streams) {
+ if (!stream || !stream->isActive())
+ continue;
+ // Stream may have been unblocked, so maybe try to write again
+ if (stream->isUploadingDATA() && !stream->isUploadBlocked())
+ QMetaObject::invokeMethod(stream, &QHttp2Stream::maybeResumeUpload,
+ Qt::QueuedConnection);
+ }
+ } else {
+ QHttp2Stream *stream = m_streams.value(streamID);
+ if (!stream || !stream->isActive()) {
+ // WINDOW_UPDATE on closed streams can be ignored.
+ qCDebug(qHttp2ConnectionLog, "[%p] Received WINDOW_UPDATE on closed stream %d", this,
+ streamID);
+ return;
+ }
+ stream->handleWINDOW_UPDATE(inboundFrame);
+ }
+}
+
+void QHttp2Connection::handleCONTINUATION()
+{
+ Q_ASSERT(inboundFrame.type() == FrameType::CONTINUATION);
+ if (continuedFrames.empty())
+ return connectionError(PROTOCOL_ERROR,
+ "CONTINUATION without a preceding HEADERS or PUSH_PROMISE");
+
+ if (inboundFrame.streamID() != continuedFrames.front().streamID())
+ return connectionError(PROTOCOL_ERROR, "CONTINUATION on invalid stream");
+
+ const bool endHeaders = inboundFrame.flags().testFlag(FrameFlag::END_HEADERS);
+ continuedFrames.push_back(std::move(inboundFrame));
+
+ if (!endHeaders)
+ return;
+
+ continuationExpected = false;
+ handleContinuedHEADERS();
+}
+
+void QHttp2Connection::handleContinuedHEADERS()
+{
+ // 'Continued' HEADERS can be: the initial HEADERS/PUSH_PROMISE frame
+ // with/without END_HEADERS flag set plus, if no END_HEADERS flag,
+ // a sequence of one or more CONTINUATION frames.
+ Q_ASSERT(!continuedFrames.empty());
+ const auto firstFrameType = continuedFrames[0].type();
+ Q_ASSERT(firstFrameType == FrameType::HEADERS || firstFrameType == FrameType::PUSH_PROMISE);
+
+ const auto streamID = continuedFrames[0].streamID();
+
+ const auto streamIt = m_streams.constFind(streamID);
+ if (firstFrameType == FrameType::HEADERS) {
+ if (streamIt != m_streams.cend()) {
+ QHttp2Stream *stream = streamIt.value();
+ if (stream->state() != QHttp2Stream::State::HalfClosedLocal
+ && stream->state() != QHttp2Stream::State::ReservedRemote
+ && stream->state() != QHttp2Stream::State::Idle
+ && stream->state() != QHttp2Stream::State::Open) {
+ // We can receive HEADERS on streams initiated by our requests
+ // (these streams are in halfClosedLocal or open state) or
+ // remote-reserved streams from a server's PUSH_PROMISE.
+ stream->finishWithError(QNetworkReply::ProtocolFailure,
+ "HEADERS on invalid stream"_L1);
+ stream->sendRST_STREAM(CANCEL);
+ return;
+ }
+ }
+ // Else: we cannot just ignore our peer's HEADERS frames - they change
+ // HPACK context - even though the stream was reset; apparently the peer
+ // has yet to see the reset.
+ }
+
+ std::vector<uchar> hpackBlock(assemble_hpack_block(continuedFrames));
+ const bool hasHeaderFields = !hpackBlock.empty();
+ if (hasHeaderFields) {
+ HPack::BitIStream inputStream{ hpackBlock.data(), hpackBlock.data() + hpackBlock.size() };
+ if (!decoder.decodeHeaderFields(inputStream))
+ return connectionError(COMPRESSION_ERROR, "HPACK decompression failed");
+ } else {
+ if (firstFrameType == FrameType::PUSH_PROMISE) {
+ // It could be a PRIORITY sent in HEADERS - already handled by this
+ // point in handleHEADERS. If it was PUSH_PROMISE (HTTP/2 8.2.1):
+ // "The header fields in PUSH_PROMISE and any subsequent CONTINUATION
+ // frames MUST be a valid and complete set of request header fields
+ // (Section 8.1.2.3) ... If a client receives a PUSH_PROMISE that does
+ // not include a complete and valid set of header fields or the :method
+ // pseudo-header field identifies a method that is not safe, it MUST
+ // respond with a stream error (Section 5.4.2) of type PROTOCOL_ERROR."
+ if (streamIt != m_streams.cend())
+ (*streamIt)->sendRST_STREAM(PROTOCOL_ERROR);
+ return;
+ }
+
+ // We got back an empty hpack block. Now let's figure out if there was an error.
+ constexpr auto hpackBlockHasContent = [](const auto &c) { return c.hpackBlockSize() > 0; };
+ const bool anyHpackBlock = std::any_of(continuedFrames.cbegin(), continuedFrames.cend(),
+ hpackBlockHasContent);
+ if (anyHpackBlock) // There was hpack block data, but returned empty => it overflowed.
+ return connectionError(FRAME_SIZE_ERROR, "HEADERS frame too large");
+ }
+
+ if (streamIt == m_streams.cend()) // No more processing without a stream from here on.
+ return;
+
+ switch (firstFrameType) {
+ case FrameType::HEADERS:
+ streamIt.value()->handleHEADERS(continuedFrames[0].flags(), decoder.decodedHeader());
+ break;
+ case FrameType::PUSH_PROMISE: {
+ std::optional<QUrl> promiseKey = HPack::makePromiseKeyUrl(decoder.decodedHeader());
+ if (!promiseKey)
+ return; // invalid URL/key !
+ if (m_promisedStreams.contains(*promiseKey))
+ return; // already promised!
+ const auto promiseID = qFromBigEndian<quint32>(continuedFrames[0].dataBegin());
+ QHttp2Stream *stream = m_streams.value(promiseID);
+ stream->transitionState(QHttp2Stream::StateTransition::CloseLocal);
+ stream->handleHEADERS(continuedFrames[0].flags(), decoder.decodedHeader());
+ emit newPromisedStream(stream); // @future[consider] add promise key as argument?
+ m_promisedStreams.emplace(*promiseKey, promiseID);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+bool QHttp2Connection::acceptSetting(Http2::Settings identifier, quint32 newValue)
+{
+ switch (identifier) {
+ case Settings::HEADER_TABLE_SIZE_ID: {
+ qCDebug(qHttp2ConnectionLog, "[%p] Received SETTINGS HEADER_TABLE_SIZE %d", this, newValue);
+ if (newValue > maxAcceptableTableSize) {
+ connectionError(PROTOCOL_ERROR, "SETTINGS invalid table size");
+ return false;
+ }
+ encoder.setMaxDynamicTableSize(newValue);
+ break;
+ }
+ case Settings::INITIAL_WINDOW_SIZE_ID: {
+ qCDebug(qHttp2ConnectionLog, "[%p] Received SETTINGS INITIAL_WINDOW_SIZE %d", this,
+ newValue);
+ // For every active stream - adjust its window
+ // (and handle possible overflows as errors).
+ if (newValue > quint32(std::numeric_limits<qint32>::max())) {
+ connectionError(FLOW_CONTROL_ERROR, "SETTINGS invalid initial window size");
+ return false;
+ }
+
+ const qint32 delta = qint32(newValue) - streamInitialSendWindowSize;
+ streamInitialSendWindowSize = qint32(newValue);
+
+ qCDebug(qHttp2ConnectionLog, "[%p] Adjusting initial window size for %zu streams by %d",
+ this, size_t(m_streams.size()), delta);
+ for (const QPointer<QHttp2Stream> &stream : std::as_const(m_streams)) {
+ if (!stream || !stream->isActive())
+ continue;
+ qint32 sum = 0;
+ if (qAddOverflow(stream->m_sendWindow, delta, &sum)) {
+ stream->sendRST_STREAM(PROTOCOL_ERROR);
+ stream->finishWithError(QNetworkReply::ProtocolFailure,
+ "SETTINGS window overflow"_L1);
+ continue;
+ }
+ stream->m_sendWindow = sum;
+ if (delta > 0 && stream->isUploadingDATA() && !stream->isUploadBlocked()) {
+ QMetaObject::invokeMethod(stream, &QHttp2Stream::maybeResumeUpload,
+ Qt::QueuedConnection);
+ }
+ }
+ break;
+ }
+ case Settings::MAX_CONCURRENT_STREAMS_ID: {
+ qCDebug(qHttp2ConnectionLog, "[%p] Received SETTINGS MAX_CONCURRENT_STREAMS %d", this,
+ newValue);
+ m_maxConcurrentStreams = newValue;
+ break;
+ }
+ case Settings::MAX_FRAME_SIZE_ID: {
+ qCDebug(qHttp2ConnectionLog, "[%p] Received SETTINGS MAX_FRAME_SIZE %d", this, newValue);
+ if (newValue < Http2::minPayloadLimit || newValue > Http2::maxPayloadSize) {
+ connectionError(PROTOCOL_ERROR, "SETTINGS max frame size is out of range");
+ return false;
+ }
+ maxFrameSize = newValue;
+ break;
+ }
+ case Settings::MAX_HEADER_LIST_SIZE_ID: {
+ qCDebug(qHttp2ConnectionLog, "[%p] Received SETTINGS MAX_HEADER_LIST_SIZE %d", this,
+ newValue);
+ // We just remember this value, it can later
+ // prevent us from sending any request (and this
+ // will end up in request/reply error).
+ m_maxHeaderListSize = newValue;
+ break;
+ }
+ case Http2::Settings::ENABLE_PUSH_ID:
+ qCDebug(qHttp2ConnectionLog, "[%p] Received SETTINGS ENABLE_PUSH %d", this, newValue);
+ if (newValue != 0 && newValue != 1) {
+ connectionError(PROTOCOL_ERROR, "SETTINGS peer sent illegal value for ENABLE_PUSH");
+ return false;
+ }
+ if (m_connectionType == Type::Client) {
+ if (newValue == 1) {
+ connectionError(PROTOCOL_ERROR, "SETTINGS server sent ENABLE_PUSH=1");
+ return false;
+ }
+ } else { // server-side
+ pushPromiseEnabled = newValue;
+ break;
+ }
+ }
+
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qhttp2connection_p.cpp"
diff --git a/src/network/access/qhttp2connection_p.h b/src/network/access/qhttp2connection_p.h
new file mode 100644
index 0000000000..ca2cae58e0
--- /dev/null
+++ b/src/network/access/qhttp2connection_p.h
@@ -0,0 +1,372 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef HTTP2CONNECTION_P_H
+#define HTTP2CONNECTION_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 <private/qtnetworkglobal_p.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qxpfunctional.h>
+#include <QtNetwork/qhttp2configuration.h>
+#include <QtNetwork/qtcpsocket.h>
+
+#include <private/http2protocol_p.h>
+#include <private/http2streams_p.h>
+#include <private/http2frames_p.h>
+#include <private/hpack_p.h>
+
+#include <variant>
+#include <optional>
+#include <type_traits>
+#include <limits>
+
+QT_BEGIN_NAMESPACE
+
+template <typename T, typename Err>
+class QH2Expected
+{
+ static_assert(!std::is_same_v<T, Err>, "T and Err must be different types");
+public:
+ // Rule Of Zero applies
+ QH2Expected(T &&value) : m_data(std::move(value)) { }
+ QH2Expected(const T &value) : m_data(value) { }
+ QH2Expected(Err &&error) : m_data(std::move(error)) { }
+ QH2Expected(const Err &error) : m_data(error) { }
+
+ QH2Expected &operator=(T &&value)
+ {
+ m_data = std::move(value);
+ return *this;
+ }
+ QH2Expected &operator=(const T &value)
+ {
+ m_data = value;
+ return *this;
+ }
+ QH2Expected &operator=(Err &&error)
+ {
+ m_data = std::move(error);
+ return *this;
+ }
+ QH2Expected &operator=(const Err &error)
+ {
+ m_data = error;
+ return *this;
+ }
+ T unwrap() const
+ {
+ Q_ASSERT(ok());
+ return std::get<T>(m_data);
+ }
+ Err error() const
+ {
+ Q_ASSERT(has_error());
+ return std::get<Err>(m_data);
+ }
+ bool ok() const noexcept { return std::holds_alternative<T>(m_data); }
+ bool has_value() const noexcept { return ok(); }
+ bool has_error() const noexcept { return std::holds_alternative<Err>(m_data); }
+ void clear() noexcept { m_data.reset(); }
+
+private:
+ std::variant<T, Err> m_data;
+};
+
+class QHttp2Connection;
+class Q_NETWORK_EXPORT QHttp2Stream : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY_MOVE(QHttp2Stream)
+
+public:
+ enum class State { Idle, ReservedRemote, Open, HalfClosedLocal, HalfClosedRemote, Closed };
+ Q_ENUM(State)
+ constexpr static quint8 DefaultPriority = 127;
+
+ ~QHttp2Stream() noexcept;
+
+ // HTTP2 things
+ quint32 streamID() const noexcept { return m_streamID; }
+
+ // Are we waiting for a larger send window before sending more data?
+ bool isUploadBlocked() const noexcept;
+ bool isUploadingDATA() const noexcept { return m_uploadByteDevice != nullptr; }
+ State state() const noexcept { return m_state; }
+ bool isActive() const noexcept { return m_state != State::Closed && m_state != State::Idle; }
+ bool isPromisedStream() const noexcept { return m_isReserved; }
+ bool wasReset() const noexcept { return m_RST_STREAM_code.has_value(); }
+ quint32 RST_STREAM_code() const noexcept { return m_RST_STREAM_code.value_or(0); }
+ // Just the list of headers, as received, may contain duplicates:
+ HPack::HttpHeader receivedHeaders() const noexcept { return m_headers; }
+
+ QByteDataBuffer downloadBuffer() const noexcept { return m_downloadBuffer; }
+
+Q_SIGNALS:
+ void headersReceived(const HPack::HttpHeader &headers, bool endStream);
+ void headersUpdated();
+ void errorOccurred(quint32 errorCode, const QString &errorString);
+ void stateChanged(QHttp2Stream::State newState);
+ void promisedStreamReceived(quint32 newStreamID);
+ void uploadBlocked();
+ void dataReceived(const QByteArray &data, bool endStream);
+
+ void bytesWritten(qint64 bytesWritten);
+ void uploadDeviceError(const QString &errorString);
+ void uploadFinished();
+
+public Q_SLOTS:
+ bool sendRST_STREAM(quint32 errorCode);
+ bool sendHEADERS(const HPack::HttpHeader &headers, bool endStream,
+ quint8 priority = DefaultPriority);
+ void sendDATA(QIODevice *device, bool endStream);
+ void sendDATA(QNonContiguousByteDevice *device, bool endStream);
+ void sendWINDOW_UPDATE(quint32 delta);
+
+private Q_SLOTS:
+ void maybeResumeUpload();
+ void uploadDeviceReadChannelFinished();
+ void uploadDeviceDestroyed();
+
+private:
+ friend class QHttp2Connection;
+ QHttp2Stream(QHttp2Connection *connection, quint32 streamID) noexcept;
+
+ [[nodiscard]] QHttp2Connection *getConnection() const
+ {
+ return qobject_cast<QHttp2Connection *>(parent());
+ }
+
+ enum class StateTransition {
+ Open,
+ CloseLocal,
+ CloseRemote,
+ RST,
+ };
+
+ void setState(State newState);
+ void transitionState(StateTransition transition);
+ void internalSendDATA();
+ void finishSendDATA();
+
+ void handleDATA(const Http2::Frame &inboundFrame);
+ void handleHEADERS(Http2::FrameFlags frameFlags, const HPack::HttpHeader &headers);
+ void handleRST_STREAM(const Http2::Frame &inboundFrame);
+ void handleWINDOW_UPDATE(const Http2::Frame &inboundFrame);
+
+ void finishWithError(quint32 errorCode, const QString &message);
+ void finishWithError(quint32 errorCode);
+
+ // Keep it const since it never changes after creation
+ const quint32 m_streamID = 0;
+ qint32 m_recvWindow = 0;
+ qint32 m_sendWindow = 0;
+ bool m_endStreamAfterDATA = false;
+ std::optional<quint32> m_RST_STREAM_code;
+
+ QIODevice *m_uploadDevice = nullptr;
+ QNonContiguousByteDevice *m_uploadByteDevice = nullptr;
+
+ QByteDataBuffer m_downloadBuffer;
+ State m_state = State::Idle;
+ HPack::HttpHeader m_headers;
+ bool m_isReserved = false;
+};
+
+class Q_NETWORK_EXPORT QHttp2Connection : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY_MOVE(QHttp2Connection)
+
+public:
+ enum class CreateStreamError {
+ MaxConcurrentStreamsReached,
+ StreamIdsExhausted,
+ ReceivedGOAWAY,
+ };
+ Q_ENUM(CreateStreamError)
+
+ enum class PingState {
+ Ping,
+ PongSignatureIdentical,
+ PongSignatureChanged,
+ PongNoPingSent, // We got an ACKed ping but had not sent any
+ };
+
+ // For a pre-established connection:
+ [[nodiscard]] static QHttp2Connection *
+ createUpgradedConnection(QIODevice *socket, const QHttp2Configuration &config);
+ // For a new connection, potential TLS handshake must already be finished:
+ [[nodiscard]] static QHttp2Connection *createDirectConnection(QIODevice *socket,
+ const QHttp2Configuration &config);
+ [[nodiscard]] static QHttp2Connection *
+ createDirectServerConnection(QIODevice *socket, const QHttp2Configuration &config);
+ ~QHttp2Connection();
+
+ [[nodiscard]] QH2Expected<QHttp2Stream *, CreateStreamError> createStream();
+
+ QHttp2Stream *getStream(quint32 streamId) const;
+ QHttp2Stream *promisedStream(const QUrl &streamKey) const
+ {
+ if (quint32 id = m_promisedStreams.value(streamKey, 0); id)
+ return m_streams.value(id);
+ return nullptr;
+ }
+
+ void close() { sendGOAWAY(Http2::HTTP2_NO_ERROR); }
+
+ bool isGoingAway() const noexcept { return m_goingAway; }
+
+ quint32 maxConcurrentStreams() const noexcept { return m_maxConcurrentStreams; }
+ quint32 maxHeaderListSize() const noexcept { return m_maxHeaderListSize; }
+
+ bool isUpgradedConnection() const noexcept { return m_upgradedConnection; }
+
+Q_SIGNALS:
+ void newIncomingStream(QHttp2Stream *stream);
+ void newPromisedStream(QHttp2Stream *stream);
+ void errorReceived(/*@future: add as needed?*/); // Connection errors only, no stream-specific errors
+ void connectionClosed();
+ void settingsFrameReceived();
+ void pingFrameRecived(QHttp2Connection::PingState state);
+ void errorOccurred(Http2::Http2Error errorCode, const QString &errorString);
+ void receivedGOAWAY(quint32 errorCode, quint32 lastStreamID);
+public Q_SLOTS:
+ bool sendPing();
+ bool sendPing(QByteArrayView data);
+ void handleReadyRead();
+ void handleConnectionClosure();
+
+private:
+ friend class QHttp2Stream;
+ [[nodiscard]] QIODevice *getSocket() const { return qobject_cast<QIODevice *>(parent()); }
+
+ QH2Expected<QHttp2Stream *, QHttp2Connection::CreateStreamError> createStreamInternal();
+ QHttp2Stream *createStreamInternal_impl(quint32 streamID);
+
+ bool isInvalidStream(quint32 streamID) noexcept;
+ bool streamWasReset(quint32 streamID) noexcept;
+
+ void connectionError(Http2::Http2Error errorCode,
+ const char *message); // Connection failed to be established?
+ void setH2Configuration(QHttp2Configuration config);
+ void closeSession();
+ qsizetype numActiveStreamsImpl(quint32 mask) const noexcept;
+ qsizetype numActiveRemoteStreams() const noexcept;
+ qsizetype numActiveLocalStreams() const noexcept;
+
+ bool sendClientPreface();
+ bool sendSETTINGS();
+ bool sendServerPreface();
+ bool serverCheckClientPreface();
+ bool sendWINDOW_UPDATE(quint32 streamID, quint32 delta);
+ bool sendGOAWAY(quint32 errorCode);
+ bool sendSETTINGS_ACK();
+
+ void handleDATA();
+ void handleHEADERS();
+ void handlePRIORITY();
+ void handleRST_STREAM();
+ void handleSETTINGS();
+ void handlePUSH_PROMISE();
+ void handlePING();
+ void handleGOAWAY();
+ void handleWINDOW_UPDATE();
+ void handleCONTINUATION();
+
+ void handleContinuedHEADERS();
+
+ bool acceptSetting(Http2::Settings identifier, quint32 newValue);
+
+ bool readClientPreface();
+
+ explicit QHttp2Connection(QIODevice *socket);
+
+ enum class Type { Client, Server } m_connectionType = Type::Client;
+
+ bool waitingForSettingsACK = false;
+
+ static constexpr quint32 maxAcceptableTableSize = 16 * HPack::FieldLookupTable::DefaultSize;
+ // HTTP/2 4.3: Header compression is stateful. One compression context and
+ // one decompression context are used for the entire connection.
+ HPack::Decoder decoder = HPack::Decoder(HPack::FieldLookupTable::DefaultSize);
+ HPack::Encoder encoder = HPack::Encoder(HPack::FieldLookupTable::DefaultSize, true);
+
+ QHttp2Configuration m_config;
+ QHash<quint32, QPointer<QHttp2Stream>> m_streams;
+ QHash<QUrl, quint32> m_promisedStreams;
+ QVarLengthArray<quint32> m_resetStreamIDs;
+ std::optional<QByteArray> m_lastPingSignature = std::nullopt;
+ quint32 m_nextStreamID = 1;
+
+ // Peer's max frame size (this min is the default value
+ // we start with, that can be updated by SETTINGS frame):
+ quint32 maxFrameSize = Http2::minPayloadLimit;
+
+ Http2::FrameReader frameReader;
+ Http2::Frame inboundFrame;
+ Http2::FrameWriter frameWriter;
+
+ // Temporary storage to assemble HEADERS' block
+ // from several CONTINUATION frames ...
+ bool continuationExpected = false;
+ std::vector<Http2::Frame> continuedFrames;
+
+ // Control flow:
+
+ // This is how many concurrent streams our peer allows us, 100 is the
+ // initial value, can be updated by the server's SETTINGS frame(s):
+ quint32 m_maxConcurrentStreams = Http2::maxConcurrentStreams;
+ // While we allow sending SETTTINGS_MAX_CONCURRENT_STREAMS to limit our peer,
+ // it's just a hint and we do not actually enforce it (and we can continue
+ // sending requests and creating streams while maxConcurrentStreams allows).
+
+ // This is our (client-side) maximum possible receive window size, we set
+ // it in a ctor from QHttp2Configuration, it does not change after that.
+ // The default is 64Kb:
+ qint32 maxSessionReceiveWindowSize = Http2::defaultSessionWindowSize;
+
+ // Our session current receive window size, updated in a ctor from
+ // QHttp2Configuration. Signed integer since it can become negative
+ // (it's still a valid window size).
+ qint32 sessionReceiveWindowSize = Http2::defaultSessionWindowSize;
+ // Our per-stream receive window size, default is 64 Kb, will be updated
+ // from QHttp2Configuration. Again, signed - can become negative.
+ qint32 streamInitialReceiveWindowSize = Http2::defaultSessionWindowSize;
+
+ // These are our peer's receive window sizes, they will be updated by the
+ // peer's SETTINGS and WINDOW_UPDATE frames, defaults presumed to be 64Kb.
+ qint32 sessionSendWindowSize = Http2::defaultSessionWindowSize;
+ qint32 streamInitialSendWindowSize = Http2::defaultSessionWindowSize;
+
+ // Our peer's header size limitations. It's unlimited by default, but can
+ // be changed via peer's SETTINGS frame.
+ quint32 m_maxHeaderListSize = (std::numeric_limits<quint32>::max)();
+ // While we can send SETTINGS_MAX_HEADER_LIST_SIZE value (our limit on
+ // the headers size), we never enforce it, it's just a hint to our peer.
+
+ bool m_upgradedConnection = false;
+ bool m_goingAway = false;
+ bool pushPromiseEnabled = false;
+ quint32 m_lastIncomingStreamID = Http2::connectionStreamID;
+
+ // Server-side only:
+ bool m_waitingForClientPreface = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // HTTP2CONNECTION_P_H
diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp
index f41cde067a..d9341dc643 100644
--- a/src/network/access/qhttp2protocolhandler.cpp
+++ b/src/network/access/qhttp2protocolhandler.cpp
@@ -10,10 +10,12 @@
#include <private/qnoncontiguousbytedevice_p.h>
#include <QtNetwork/qabstractsocket.h>
+
#include <QtCore/qloggingcategory.h>
#include <QtCore/qendian.h>
#include <QtCore/qdebug.h>
#include <QtCore/qlist.h>
+#include <QtCore/qnumeric.h>
#include <QtCore/qurl.h>
#include <qhttp2configuration.h>
@@ -26,6 +28,7 @@
#include <algorithm>
#include <vector>
+#include <optional>
QT_BEGIN_NAMESPACE
@@ -45,10 +48,10 @@ HPack::HttpHeader build_headers(const QHttpNetworkRequest &request, quint32 maxH
// 1. Before anything - mandatory fields, if they do not fit into maxHeaderList -
// then stop immediately with error.
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(useProxy)));
- header.push_back(HeaderField(":scheme", request.url().scheme().toLatin1()));
+ header.emplace_back(":authority", auth);
+ header.emplace_back(":method", request.methodName());
+ header.emplace_back(":path", request.uri(useProxy));
+ header.emplace_back(":scheme", request.url().scheme().toLatin1());
HeaderSize size = header_size(header);
if (!size.first) // Ooops!
@@ -57,9 +60,11 @@ HPack::HttpHeader build_headers(const QHttpNetworkRequest &request, quint32 maxH
if (size.second > maxHeaderListSize)
return HttpHeader(); // Bad, we cannot send this request ...
- const auto requestHeader = request.header();
- for (const auto &field : requestHeader) {
- const HeaderSize delta = entry_size(field.first, field.second);
+ const QHttpHeaders requestHeader = request.header();
+ for (qsizetype i = 0; i < requestHeader.size(); ++i) {
+ const auto name = requestHeader.nameAt(i);
+ const auto value = requestHeader.valueAt(i);
+ const HeaderSize delta = entry_size(name, value);
if (!delta.first) // Overflow???
break;
if (std::numeric_limits<quint32>::max() - delta.second < size.second)
@@ -68,47 +73,22 @@ HPack::HttpHeader build_headers(const QHttpNetworkRequest &request, quint32 maxH
if (size.second > maxHeaderListSize)
break;
- if (field.first.compare("connection", Qt::CaseInsensitive) == 0 ||
- field.first.compare("host", Qt::CaseInsensitive) == 0 ||
- field.first.compare("keep-alive", Qt::CaseInsensitive) == 0 ||
- field.first.compare("proxy-connection", Qt::CaseInsensitive) == 0 ||
- field.first.compare("transfer-encoding", Qt::CaseInsensitive) == 0)
+ if (name == "connection"_L1 || name == "host"_L1 || name == "keep-alive"_L1
+ || name == "proxy-connection"_L1 || name == "transfer-encoding"_L1) {
continue; // Those headers are not valid (section 3.2.1) - from QSpdyProtocolHandler
+ }
// TODO: verify with specs, which fields are valid to send ....
- // toLower - 8.1.2 .... "header field names MUST be converted to lowercase prior
- // to their encoding in HTTP/2.
- // A request or response containing uppercase header field names
- // MUST be treated as malformed (Section 8.1.2.6)".
- header.push_back(HeaderField(field.first.toLower(), field.second));
+ //
+ // Note: RFC 7450 8.1.2 (HTTP/2) states that header field names must be lower-cased
+ // prior to their encoding in HTTP/2; header name fields in QHttpHeaders are already
+ // lower-cased
+ header.emplace_back(QByteArray{name.data(), name.size()},
+ QByteArray{value.data(), value.size()});
}
return header;
}
-std::vector<uchar> assemble_hpack_block(const std::vector<Http2::Frame> &frames)
-{
- std::vector<uchar> hpackBlock;
-
- quint32 total = 0;
- for (const auto &frame : frames)
- total += frame.hpackBlockSize();
-
- if (!total)
- return hpackBlock;
-
- hpackBlock.resize(total);
- auto dst = hpackBlock.begin();
- for (const auto &frame : frames) {
- if (const auto hpackBlockSize = frame.hpackBlockSize()) {
- const uchar *src = frame.hpackBlockBegin();
- std::copy(src, src + hpackBlockSize, dst);
- dst += hpackBlockSize;
- }
- }
-
- return hpackBlock;
-}
-
QUrl urlkey_from_request(const QHttpNetworkRequest &request)
{
QUrl url;
@@ -120,21 +100,11 @@ QUrl urlkey_from_request(const QHttpNetworkRequest &request)
return url;
}
-bool sum_will_overflow(qint32 windowSize, qint32 delta)
-{
- if (windowSize > 0)
- return std::numeric_limits<qint32>::max() - windowSize < delta;
- return std::numeric_limits<qint32>::min() - windowSize > delta;
-}
-
}// Unnamed namespace
// Since we anyway end up having this in every function definition:
using namespace Http2;
-const std::deque<quint32>::size_type QHttp2ProtocolHandler::maxRecycledStreams = 10000;
-const quint32 QHttp2ProtocolHandler::maxAcceptableTableSize;
-
QHttp2ProtocolHandler::QHttp2ProtocolHandler(QHttpNetworkConnectionChannel *channel)
: QAbstractProtocolHandler(channel),
decoder(HPack::FieldLookupTable::DefaultSize),
@@ -318,8 +288,7 @@ bool QHttp2ProtocolHandler::sendRequest()
auto &requests = m_channel->h2RequestsToSend;
for (auto it = requests.begin(), endIt = requests.end(); it != endIt;) {
const auto &pair = *it;
- const QString scheme(pair.first.url().scheme());
- if (scheme == "preconnect-http"_L1 || scheme == "preconnect-https"_L1) {
+ if (pair.first.isPreConnect()) {
m_connection->preConnectFinished();
emit pair.second->finished();
it = requests.erase(it);
@@ -357,11 +326,13 @@ bool QHttp2ProtocolHandler::sendRequest()
initReplyFromPushPromise(message, key);
}
- const auto streamsToUse = std::min<quint32>(maxConcurrentStreams > quint32(activeStreams.size())
- ? maxConcurrentStreams - quint32(activeStreams.size()) : 0,
- requests.size());
+ const auto isClientSide = [](const auto &pair) -> bool { return (pair.first & 1) == 1; };
+ const auto activeClientSideStreams = std::count_if(
+ activeStreams.constKeyValueBegin(), activeStreams.constKeyValueEnd(), isClientSide);
+ const qint64 streamsToUse = qBound(0, qint64(maxConcurrentStreams) - activeClientSideStreams,
+ requests.size());
auto it = requests.begin();
- for (quint32 i = 0; i < streamsToUse; ++i) {
+ for (qint64 i = 0; i < streamsToUse; ++i) {
const qint32 newStreamID = createNewStream(*it);
if (!newStreamID) {
// TODO: actually we have to open a new connection.
@@ -504,7 +475,7 @@ bool QHttp2ProtocolHandler::sendDATA(Stream &stream)
}
frameWriter.start(FrameType::DATA, FrameFlag::EMPTY, stream.streamID);
- const qint32 bytesWritten = std::min<qint32>(slot, chunkSize);
+ const qint32 bytesWritten = qint32(std::min<qint64>(slot, chunkSize));
if (!frameWriter.writeDATA(*m_socket, maxFrameSize, src, bytesWritten))
return false;
@@ -576,8 +547,9 @@ void QHttp2ProtocolHandler::handleDATA()
sessionReceiveWindowSize -= inboundFrame.payloadSize();
- if (activeStreams.contains(streamID)) {
- auto &stream = activeStreams[streamID];
+ auto it = activeStreams.find(streamID);
+ if (it != activeStreams.end()) {
+ Stream &stream = it.value();
if (qint32(inboundFrame.payloadSize()) > stream.recvWindow) {
finishStreamWithError(stream, QNetworkReply::ProtocolFailure, "flow control error"_L1);
@@ -883,16 +855,19 @@ void QHttp2ProtocolHandler::handleWINDOW_UPDATE()
const auto streamID = inboundFrame.streamID();
if (streamID == Http2::connectionStreamID) {
- if (!valid || sum_will_overflow(sessionSendWindowSize, delta))
+ qint32 sum = 0;
+ if (!valid || qAddOverflow(sessionSendWindowSize, qint32(delta), &sum))
return connectionError(PROTOCOL_ERROR, "WINDOW_UPDATE invalid delta");
- sessionSendWindowSize += delta;
+ sessionSendWindowSize = sum;
} else {
- if (!activeStreams.contains(streamID)) {
+ auto it = activeStreams.find(streamID);
+ if (it == activeStreams.end()) {
// WINDOW_UPDATE on closed streams can be ignored.
return;
}
- auto &stream = activeStreams[streamID];
- if (!valid || sum_will_overflow(stream.sendWindow, delta)) {
+ Stream &stream = it.value();
+ qint32 sum = 0;
+ if (!valid || qAddOverflow(stream.sendWindow, qint32(delta), &sum)) {
finishStreamWithError(stream, QNetworkReply::ProtocolFailure,
"invalid WINDOW_UPDATE delta"_L1);
sendRST_STREAM(streamID, PROTOCOL_ERROR);
@@ -900,7 +875,7 @@ void QHttp2ProtocolHandler::handleWINDOW_UPDATE()
deleteActiveStream(streamID);
return;
}
- stream.sendWindow += delta;
+ stream.sendWindow = sum;
}
// Since we're in _q_receiveReply at the moment, let's first handle other
@@ -939,9 +914,10 @@ void QHttp2ProtocolHandler::handleContinuedHEADERS()
const auto streamID = continuedFrames[0].streamID();
+ const auto streamIt = activeStreams.find(streamID);
if (firstFrameType == FrameType::HEADERS) {
- if (activeStreams.contains(streamID)) {
- Stream &stream = activeStreams[streamID];
+ if (streamIt != activeStreams.end()) {
+ Stream &stream = streamIt.value();
if (stream.state != Stream::halfClosedLocal
&& stream.state != Stream::remoteReserved
&& stream.state != Stream::open) {
@@ -963,8 +939,13 @@ void QHttp2ProtocolHandler::handleContinuedHEADERS()
// has yet to see the reset.
}
- std::vector<uchar> hpackBlock(assemble_hpack_block(continuedFrames));
- if (!hpackBlock.size()) {
+ std::vector<uchar> hpackBlock(Http2::assemble_hpack_block(continuedFrames));
+ const bool hasHeaderFields = !hpackBlock.empty();
+ if (hasHeaderFields) {
+ HPack::BitIStream inputStream{&hpackBlock[0], &hpackBlock[0] + hpackBlock.size()};
+ if (!decoder.decodeHeaderFields(inputStream))
+ return connectionError(COMPRESSION_ERROR, "HPACK decompression failed");
+ } else if (firstFrameType == FrameType::PUSH_PROMISE) {
// It could be a PRIORITY sent in HEADERS - already handled by this
// point in handleHEADERS. If it was PUSH_PROMISE (HTTP/2 8.2.1):
// "The header fields in PUSH_PROMISE and any subsequent CONTINUATION
@@ -973,21 +954,16 @@ void QHttp2ProtocolHandler::handleContinuedHEADERS()
// not include a complete and valid set of header fields or the :method
// pseudo-header field identifies a method that is not safe, it MUST
// respond with a stream error (Section 5.4.2) of type PROTOCOL_ERROR."
- if (firstFrameType == FrameType::PUSH_PROMISE)
- resetPromisedStream(continuedFrames[0], Http2::PROTOCOL_ERROR);
-
+ resetPromisedStream(continuedFrames[0], Http2::PROTOCOL_ERROR);
return;
}
- HPack::BitIStream inputStream{&hpackBlock[0], &hpackBlock[0] + hpackBlock.size()};
- if (!decoder.decodeHeaderFields(inputStream))
- return connectionError(COMPRESSION_ERROR, "HPACK decompression failed");
-
switch (firstFrameType) {
case FrameType::HEADERS:
- if (activeStreams.contains(streamID)) {
- Stream &stream = activeStreams[streamID];
- updateStream(stream, decoder.decodedHeader());
+ if (streamIt != activeStreams.end()) {
+ Stream &stream = streamIt.value();
+ if (hasHeaderFields)
+ updateStream(stream, decoder.decodedHeader());
// Needs to resend the request; we should finish and delete the current stream
const bool needResend = stream.request().d->needResendWithCredentials;
// No DATA frames. Or needs to resend.
@@ -1030,11 +1006,12 @@ bool QHttp2ProtocolHandler::acceptSetting(Http2::Settings identifier, quint32 ne
std::vector<quint32> brokenStreams;
brokenStreams.reserve(activeStreams.size());
for (auto &stream : activeStreams) {
- if (sum_will_overflow(stream.sendWindow, delta)) {
+ qint32 sum = 0;
+ if (qAddOverflow(stream.sendWindow, delta, &sum)) {
brokenStreams.push_back(stream.streamID);
continue;
}
- stream.sendWindow += delta;
+ stream.sendWindow = sum;
}
for (auto id : brokenStreams) {
@@ -1101,7 +1078,7 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader
int statusCode = 0;
for (const auto &pair : headers) {
const auto &name = pair.name;
- auto value = pair.value;
+ const auto value = QByteArrayView(pair.value);
// TODO: part of this code copies what SPDY protocol handler does when
// processing headers. Binary nature of HTTP/2 and SPDY saves us a lot
@@ -1121,68 +1098,16 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const HPack::HttpHeader
if (ok)
httpReply->setContentLength(length);
} else {
- QByteArray binder(", ");
- if (name == "set-cookie")
- binder = "\n";
- httpReply->appendHeaderField(name, value.replace('\0', binder));
+ const auto binder = name == "set-cookie" ? QByteArrayView("\n") : QByteArrayView(", ");
+ httpReply->appendHeaderField(name, QByteArray(pair.value).replace('\0', binder));
}
}
- const auto handleAuth = [&, this](const QByteArray &authField, bool isProxy) -> bool {
- Q_ASSERT(httpReply);
- const auto auth = authField.trimmed();
- if (auth.startsWith("Negotiate") || auth.startsWith("NTLM")) {
- // @todo: We're supposed to fall back to http/1.1:
- // https://docs.microsoft.com/en-us/iis/get-started/whats-new-in-iis-10/http2-on-iis#when-is-http2-not-supported
- // "Windows authentication (NTLM/Kerberos/Negotiate) is not supported with HTTP/2.
- // In this case IIS will fall back to HTTP/1.1."
- // Though it might be OK to ignore this. The server shouldn't let us connect with
- // HTTP/2 if it doesn't support us using it.
- } else if (!auth.isEmpty()) {
- // Somewhat mimics parts of QHttpNetworkConnectionChannel::handleStatus
- bool resend = false;
- const bool authenticateHandled = m_connection->d_func()->handleAuthenticateChallenge(
- m_socket, httpReply, isProxy, resend);
- if (authenticateHandled && resend) {
- httpReply->d_func()->eraseData();
- // Add the request back in queue, we'll retry later now that
- // we've gotten some username/password set on it:
- httpRequest.d->needResendWithCredentials = true;
- m_channel->h2RequestsToSend.insert(httpRequest.priority(), stream.httpPair);
- httpReply->d_func()->clearHeaders();
- // If we have data we were uploading we need to reset it:
- if (stream.data()) {
- stream.data()->reset();
- httpReplyPrivate->totallyUploadedData = 0;
- }
- return true;
- } // else: Authentication failed or was cancelled
- }
- return false;
- };
-
- if (httpReply) {
- // See Note further down. These statuses would in HTTP/1.1 be handled
- // by QHttpNetworkConnectionChannel::handleStatus. But because h2 has
- // multiple streams/requests in a single channel this structure does not
- // map properly to that function.
- if (httpReply->statusCode() == 401) {
- const auto wwwAuth = httpReply->headerField("www-authenticate");
- if (handleAuth(wwwAuth, false)) {
- sendRST_STREAM(stream.streamID, CANCEL);
- markAsReset(stream.streamID);
- // The stream is finalized and deleted after returning
- return;
- } // else: errors handled later
- } else if (httpReply->statusCode() == 407) {
- const auto proxyAuth = httpReply->headerField("proxy-authenticate");
- if (handleAuth(proxyAuth, true)) {
- sendRST_STREAM(stream.streamID, CANCEL);
- markAsReset(stream.streamID);
- // The stream is finalized and deleted after returning
- return;
- } // else: errors handled later
- }
+ // Discard all informational (1xx) replies with the exception of 101.
+ // Also see RFC 9110 (Chapter 15.2)
+ if (statusCode == 100 || (102 <= statusCode && statusCode <= 199)) {
+ httpReplyPrivate->clearHttpLayerInformation();
+ return;
}
if (QHttpNetworkReply::isHttpRedirect(statusCode) && httpRequest.isFollowRedirects()) {
@@ -1259,6 +1184,91 @@ void QHttp2ProtocolHandler::updateStream(Stream &stream, const Frame &frame,
}
}
+// After calling this function, either the request will be re-sent or
+// the reply will be finishedWithError! Do not emit finished() or similar on the
+// reply after this!
+void QHttp2ProtocolHandler::handleAuthorization(Stream &stream)
+{
+ auto *httpReply = stream.reply();
+ auto *httpReplyPrivate = httpReply->d_func();
+ auto &httpRequest = stream.request();
+
+ Q_ASSERT(httpReply && (httpReply->statusCode() == 401 || httpReply->statusCode() == 407));
+
+ const auto handleAuth = [&, this](QByteArrayView authField, bool isProxy) -> bool {
+ Q_ASSERT(httpReply);
+ const QByteArrayView auth = authField.trimmed();
+ if (auth.startsWith("Negotiate") || auth.startsWith("NTLM")) {
+ // @todo: We're supposed to fall back to http/1.1:
+ // https://docs.microsoft.com/en-us/iis/get-started/whats-new-in-iis-10/http2-on-iis#when-is-http2-not-supported
+ // "Windows authentication (NTLM/Kerberos/Negotiate) is not supported with HTTP/2.
+ // In this case IIS will fall back to HTTP/1.1."
+ // Though it might be OK to ignore this. The server shouldn't let us connect with
+ // HTTP/2 if it doesn't support us using it.
+ return false;
+ }
+ // Somewhat mimics parts of QHttpNetworkConnectionChannel::handleStatus
+ bool resend = false;
+ const bool authenticateHandled = m_connection->d_func()->handleAuthenticateChallenge(
+ m_socket, httpReply, isProxy, resend);
+ if (authenticateHandled) {
+ if (resend) {
+ httpReply->d_func()->eraseData();
+ // Add the request back in queue, we'll retry later now that
+ // we've gotten some username/password set on it:
+ httpRequest.d->needResendWithCredentials = true;
+ m_channel->h2RequestsToSend.insert(httpRequest.priority(), stream.httpPair);
+ httpReply->d_func()->clearHeaders();
+ // If we have data we were uploading we need to reset it:
+ if (stream.data()) {
+ stream.data()->reset();
+ httpReplyPrivate->totallyUploadedData = 0;
+ }
+ // We automatically try to send new requests when the stream is
+ // closed, so we don't need to call sendRequest ourselves.
+ return true;
+ } // else: we're just not resending the request.
+ // @note In the http/1.x case we (at time of writing) call close()
+ // for the connectionChannel (which is a bit weird, we could surely
+ // reuse the open socket outside "connection:close"?), but in http2
+ // we only have one channel, so we won't close anything.
+ } else {
+ // No authentication header or authentication isn't supported, but
+ // we got a 401/407 so we cannot succeed. We need to emit signals
+ // for headers and data, and then finishWithError.
+ emit httpReply->headerChanged();
+ emit httpReply->readyRead();
+ QNetworkReply::NetworkError error = httpReply->statusCode() == 401
+ ? QNetworkReply::AuthenticationRequiredError
+ : QNetworkReply::ProxyAuthenticationRequiredError;
+ finishStreamWithError(stream, QNetworkReply::AuthenticationRequiredError,
+ m_connection->d_func()->errorDetail(error, m_socket));
+ }
+ return false;
+ };
+
+ // These statuses would in HTTP/1.1 be handled by
+ // QHttpNetworkConnectionChannel::handleStatus. But because h2 has
+ // multiple streams/requests in a single channel this structure does not
+ // map properly to that function.
+ bool authOk = true;
+ switch (httpReply->statusCode()) {
+ case 401:
+ authOk = handleAuth(httpReply->headerField("www-authenticate"), false);
+ break;
+ case 407:
+ authOk = handleAuth(httpReply->headerField("proxy-authenticate"), true);
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ if (authOk) {
+ markAsReset(stream.streamID);
+ deleteActiveStream(stream.streamID);
+ } // else: errors handled inside handleAuth
+}
+
+// Called when we have received a frame with the END_STREAM flag set
void QHttp2ProtocolHandler::finishStream(Stream &stream, Qt::ConnectionType connectionType)
{
Q_ASSERT(stream.state == Stream::remoteReserved || stream.reply());
@@ -1266,6 +1276,15 @@ void QHttp2ProtocolHandler::finishStream(Stream &stream, Qt::ConnectionType conn
stream.state = Stream::closed;
auto httpReply = stream.reply();
if (httpReply) {
+ int statusCode = httpReply->statusCode();
+ if (statusCode == 401 || statusCode == 407) {
+ // handleAuthorization will either re-send the request or
+ // finishWithError. In either case we don't want to emit finished
+ // here.
+ handleAuthorization(stream);
+ return;
+ }
+
httpReply->disconnect(this);
if (stream.data())
stream.data()->disconnect(this);
@@ -1389,9 +1408,10 @@ quint32 QHttp2ProtocolHandler::popStreamToResume()
auto &queue = suspendedStreams[rank];
auto it = queue.begin();
for (; it != queue.end(); ++it) {
- if (!activeStreams.contains(*it))
+ auto stream = activeStreams.constFind(*it);
+ if (stream == activeStreams.cend())
continue;
- if (activeStreams[*it].sendWindow > 0)
+ if (stream->sendWindow > 0)
break;
}
@@ -1414,8 +1434,8 @@ void QHttp2ProtocolHandler::removeFromSuspended(quint32 streamID)
void QHttp2ProtocolHandler::deleteActiveStream(quint32 streamID)
{
- if (activeStreams.contains(streamID)) {
- auto &stream = activeStreams[streamID];
+ if (const auto it = activeStreams.constFind(streamID); it != activeStreams.cend()) {
+ const Stream &stream = it.value();
if (stream.reply()) {
stream.reply()->disconnect(this);
streamIDs.remove(stream.reply());
@@ -1424,7 +1444,7 @@ void QHttp2ProtocolHandler::deleteActiveStream(quint32 streamID)
stream.data()->disconnect(this);
streamIDs.remove(stream.data());
}
- activeStreams.remove(streamID);
+ activeStreams.erase(it);
}
removeFromSuspended(streamID);
@@ -1447,10 +1467,11 @@ void QHttp2ProtocolHandler::resumeSuspendedStreams()
if (!streamID)
return;
- if (!activeStreams.contains(streamID))
+ auto it = activeStreams.find(streamID);
+ if (it == activeStreams.end())
continue;
+ Stream &stream = it.value();
- Stream &stream = activeStreams[streamID];
if (!sendDATA(stream)) {
finishStreamWithError(stream, QNetworkReply::UnknownNetworkError,
"failed to send DATA"_L1);
@@ -1479,42 +1500,18 @@ bool QHttp2ProtocolHandler::tryReserveStream(const Http2::Frame &pushPromiseFram
{
Q_ASSERT(pushPromiseFrame.type() == FrameType::PUSH_PROMISE);
- QMap<QByteArray, QByteArray> pseudoHeaders;
- for (const auto &field : requestHeader) {
- if (field.name == ":scheme" || field.name == ":path"
- || field.name == ":authority" || field.name == ":method") {
- if (field.value.isEmpty() || pseudoHeaders.contains(field.name))
- return false;
- pseudoHeaders[field.name] = field.value;
- }
- }
-
- if (pseudoHeaders.size() != 4) {
- // All four required, HTTP/2 8.1.2.3.
- return false;
- }
-
- const QByteArray method = pseudoHeaders[":method"];
- if (method.compare("get", Qt::CaseInsensitive) != 0 &&
- method.compare("head", Qt::CaseInsensitive) != 0)
- return false;
-
- QUrl url;
- url.setScheme(QLatin1StringView(pseudoHeaders[":scheme"]));
- url.setAuthority(QLatin1StringView(pseudoHeaders[":authority"]));
- url.setPath(QLatin1StringView(pseudoHeaders[":path"]));
-
- if (!url.isValid())
+ const auto url = HPack::makePromiseKeyUrl(requestHeader);
+ if (!url.has_value())
return false;
Q_ASSERT(activeStreams.contains(pushPromiseFrame.streamID()));
const Stream &associatedStream = activeStreams[pushPromiseFrame.streamID()];
const auto associatedUrl = urlkey_from_request(associatedStream.request());
- if (url.adjusted(QUrl::RemovePath) != associatedUrl.adjusted(QUrl::RemovePath))
+ if (url->adjusted(QUrl::RemovePath) != associatedUrl.adjusted(QUrl::RemovePath))
return false;
- const auto urlKey = url.toString();
+ const auto urlKey = url->toString();
if (promisedData.contains(urlKey)) // duplicate push promise
return false;
@@ -1553,8 +1550,8 @@ void QHttp2ProtocolHandler::initReplyFromPushPromise(const HttpMessagePair &mess
bool replyFinished = false;
Stream *promisedStream = nullptr;
- if (activeStreams.contains(promise.reservedID)) {
- promisedStream = &activeStreams[promise.reservedID];
+ if (auto it = activeStreams.find(promise.reservedID); it != activeStreams.end()) {
+ promisedStream = &it.value();
// Ok, we have an active (not closed yet) stream waiting for more frames,
// let's pretend we requested it:
promisedStream->httpPair = message;
@@ -1564,8 +1561,8 @@ void QHttp2ProtocolHandler::initReplyFromPushPromise(const HttpMessagePair &mess
streamInitialSendWindowSize,
streamInitialReceiveWindowSize);
closedStream.state = Stream::halfClosedLocal;
- activeStreams.insert(promise.reservedID, closedStream);
- promisedStream = &activeStreams[promise.reservedID];
+ it = activeStreams.insert(promise.reservedID, closedStream);
+ promisedStream = &it.value();
replyFinished = true;
}
diff --git a/src/network/access/qhttp2protocolhandler_p.h b/src/network/access/qhttp2protocolhandler_p.h
index c4340d7eeb..3b818771a6 100644
--- a/src/network/access/qhttp2protocolhandler_p.h
+++ b/src/network/access/qhttp2protocolhandler_p.h
@@ -94,6 +94,7 @@ private:
bool acceptSetting(Http2::Settings identifier, quint32 newValue);
+ void handleAuthorization(Stream &stream);
void updateStream(Stream &stream, const HPack::HttpHeader &headers,
Qt::ConnectionType connectionType = Qt::DirectConnection);
void updateStream(Stream &stream, const Http2::Frame &dataFrame,
@@ -120,7 +121,7 @@ private:
// the client's preface 24-byte message.
bool waitingForSettingsACK = false;
- static const quint32 maxAcceptableTableSize = 16 * HPack::FieldLookupTable::DefaultSize;
+ inline static const quint32 maxAcceptableTableSize = 16 * HPack::FieldLookupTable::DefaultSize;
// HTTP/2 4.3: Header compression is stateful. One compression context and
// one decompression context are used for the entire connection.
HPack::Decoder decoder;
@@ -129,7 +130,7 @@ private:
QHash<QObject *, int> streamIDs;
QHash<quint32, Stream> activeStreams;
std::deque<quint32> suspendedStreams[3]; // 3 for priorities: High, Normal, Low.
- static const std::deque<quint32>::size_type maxRecycledStreams;
+ inline static const std::deque<quint32>::size_type maxRecycledStreams = 10000;
std::deque<quint32> recycledStreams;
// Peer's max frame size (this min is the default value
diff --git a/src/network/access/qhttpheaderparser.cpp b/src/network/access/qhttpheaderparser.cpp
index 489defa8d8..0b7882c18a 100644
--- a/src/network/access/qhttpheaderparser.cpp
+++ b/src/network/access/qhttpheaderparser.cpp
@@ -52,11 +52,11 @@ bool QHttpHeaderParser::parseHeaders(QByteArrayView header)
if (header.size() - (header.endsWith("\r\n") ? 2 : 1) > maxTotalSize)
return false;
- QList<QPair<QByteArray, QByteArray>> result;
+ QHttpHeaders result;
while (!header.empty()) {
const qsizetype colon = header.indexOf(':');
if (colon == -1) // if no colon check if empty headers
- return result.empty() && (header == "\n" || header == "\r\n");
+ return result.isEmpty() && (header == "\n" || header == "\r\n");
if (result.size() >= maxFieldCount)
return false;
QByteArrayView name = header.first(colon);
@@ -75,14 +75,14 @@ bool QHttpHeaderParser::parseHeaders(QByteArrayView header)
line = line.trimmed();
if (!line.empty()) {
if (value.size())
- value += ' ' + line.toByteArray();
+ value += ' ' + line;
else
value = line.toByteArray();
}
header = header.sliced(endLine + 1);
} while (hSpaceStart(header));
Q_ASSERT(name.size() + 1 + value.size() <= maxFieldSize);
- result.append(qMakePair(name.toByteArray(), value));
+ result.append(name, value);
}
fields = result;
@@ -128,22 +128,18 @@ bool QHttpHeaderParser::parseStatus(QByteArrayView status)
return ok && uint(majorVersion) <= 9 && uint(minorVersion) <= 9;
}
-const QList<QPair<QByteArray, QByteArray> >& QHttpHeaderParser::headers() const
+const QHttpHeaders& QHttpHeaderParser::headers() const
{
return fields;
}
-QByteArray QHttpHeaderParser::firstHeaderField(const QByteArray &name,
+QByteArray QHttpHeaderParser::firstHeaderField(QByteArrayView name,
const QByteArray &defaultValue) const
{
- for (auto it = fields.constBegin(); it != fields.constEnd(); ++it) {
- if (name.compare(it->first, Qt::CaseInsensitive) == 0)
- return it->second;
- }
- return defaultValue;
+ return fields.value(name, defaultValue).toByteArray();
}
-QByteArray QHttpHeaderParser::combinedHeaderValue(const QByteArray &name, const QByteArray &defaultValue) const
+QByteArray QHttpHeaderParser::combinedHeaderValue(QByteArrayView name, const QByteArray &defaultValue) const
{
const QList<QByteArray> allValues = headerFieldValues(name);
if (allValues.isEmpty())
@@ -151,38 +147,30 @@ QByteArray QHttpHeaderParser::combinedHeaderValue(const QByteArray &name, const
return allValues.join(", ");
}
-QList<QByteArray> QHttpHeaderParser::headerFieldValues(const QByteArray &name) const
+QList<QByteArray> QHttpHeaderParser::headerFieldValues(QByteArrayView name) const
{
- QList<QByteArray> result;
- for (auto it = fields.constBegin(); it != fields.constEnd(); ++it)
- if (name.compare(it->first, Qt::CaseInsensitive) == 0)
- result += it->second;
-
- return result;
+ return fields.values(name);
}
-void QHttpHeaderParser::removeHeaderField(const QByteArray &name)
+void QHttpHeaderParser::removeHeaderField(QByteArrayView name)
{
- auto firstEqualsName = [&name](const QPair<QByteArray, QByteArray> &header) {
- return name.compare(header.first, Qt::CaseInsensitive) == 0;
- };
- fields.removeIf(firstEqualsName);
+ fields.removeAll(name);
}
void QHttpHeaderParser::setHeaderField(const QByteArray &name, const QByteArray &data)
{
removeHeaderField(name);
- fields.append(qMakePair(name, data));
+ fields.append(name, data);
}
void QHttpHeaderParser::prependHeaderField(const QByteArray &name, const QByteArray &data)
{
- fields.prepend(qMakePair(name, data));
+ fields.insert(0, name, data);
}
void QHttpHeaderParser::appendHeaderField(const QByteArray &name, const QByteArray &data)
{
- fields.append(qMakePair(name, data));
+ fields.append(name, data);
}
void QHttpHeaderParser::clearHeaders()
diff --git a/src/network/access/qhttpheaderparser_p.h b/src/network/access/qhttpheaderparser_p.h
index 9b149570e0..5e8f3c8130 100644
--- a/src/network/access/qhttpheaderparser_p.h
+++ b/src/network/access/qhttpheaderparser_p.h
@@ -16,6 +16,7 @@
//
#include <QtNetwork/private/qtnetworkglobal_p.h>
+#include <QtNetwork/qhttpheaders.h>
#include <QByteArray>
#include <QList>
@@ -43,7 +44,7 @@ static constexpr int MAX_TOTAL_HEADER_SIZE = 256 * 1024;
}
-class Q_NETWORK_PRIVATE_EXPORT QHttpHeaderParser
+class Q_NETWORK_EXPORT QHttpHeaderParser
{
public:
QHttpHeaderParser();
@@ -52,7 +53,7 @@ public:
bool parseHeaders(QByteArrayView headers);
bool parseStatus(QByteArrayView status);
- const QList<QPair<QByteArray, QByteArray> >& headers() const;
+ const QHttpHeaders& headers() const;
void setStatusCode(int code);
int getStatusCode() const;
int getMajorVersion() const;
@@ -62,15 +63,15 @@ public:
QString getReasonPhrase() const;
void setReasonPhrase(const QString &reason);
- QByteArray firstHeaderField(const QByteArray &name,
+ QByteArray firstHeaderField(QByteArrayView name,
const QByteArray &defaultValue = QByteArray()) const;
- QByteArray combinedHeaderValue(const QByteArray &name,
+ QByteArray combinedHeaderValue(QByteArrayView name,
const QByteArray &defaultValue = QByteArray()) const;
- QList<QByteArray> headerFieldValues(const QByteArray &name) const;
+ QList<QByteArray> headerFieldValues(QByteArrayView name) const;
void setHeaderField(const QByteArray &name, const QByteArray &data);
void prependHeaderField(const QByteArray &name, const QByteArray &data);
void appendHeaderField(const QByteArray &name, const QByteArray &data);
- void removeHeaderField(const QByteArray &name);
+ void removeHeaderField(QByteArrayView name);
void clearHeaders();
void setMaxHeaderFieldSize(qsizetype size) { maxFieldSize = size; }
@@ -83,7 +84,7 @@ public:
qsizetype maxHeaderFields() const { return maxFieldCount; }
private:
- QList<QPair<QByteArray, QByteArray> > fields;
+ QHttpHeaders fields;
QString reasonPhrase;
int statusCode;
int majorVersion;
diff --git a/src/network/access/qhttpheaders.cpp b/src/network/access/qhttpheaders.cpp
new file mode 100644
index 0000000000..c63da899a8
--- /dev/null
+++ b/src/network/access/qhttpheaders.cpp
@@ -0,0 +1,1551 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qhttpheaders.h"
+
+#include <private/qoffsetstringarray_p.h>
+
+#include <QtCore/qcompare.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qset.h>
+#include <QtCore/qttypetraits.h>
+
+#include <q20algorithm.h>
+#include <string_view>
+#include <variant>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcQHttpHeaders, "qt.network.http.headers");
+
+/*!
+ \class QHttpHeaders
+ \since 6.7
+ \ingroup
+ \inmodule QtNetwork
+
+ \brief QHttpHeaders is a class for holding HTTP headers.
+
+ The class is an interface type for Qt networking APIs that
+ use or consume such headers.
+
+ \section1 Allowed field name and value characters
+
+ An HTTP header consists of \e name and \e value.
+ When setting these, QHttpHeaders validates \e name and \e value
+ to only contain characters allowed by the HTTP RFCs. For detailed
+ information see
+ \l {https://datatracker.ietf.org/doc/html/rfc9110#name-field-values}
+ {RFC 9110 Chapters 5.1 and 5.5}.
+
+ In all, this means:
+ \list
+ \li \c name must consist of visible ASCII characters, and must not be
+ empty
+ \li \c value may consist of arbitrary bytes, as long as header
+ and use case specific encoding rules are adhered to. \c value
+ may be empty
+ \endlist
+
+ The setters of this class automatically remove any leading or trailing
+ whitespaces from \e value, as they must be ignored during the
+ \e value processing.
+
+ \section1 Combining values
+
+ Most HTTP header values can be combined with a single comma \c {','}
+ plus an optional whitespace, and the semantic meaning is preserved.
+ As an example, these two should be semantically similar:
+ \badcode
+ // Values as separate header entries
+ myheadername: myheadervalue1
+ myheadername: myheadervalue2
+ // Combined value
+ myheadername: myheadervalue1, myheadervalue2
+ \endcode
+
+ However, there is a notable exception to this rule:
+ \l {https://datatracker.ietf.org/doc/html/rfc9110#name-field-order}
+ {Set-Cookie}. Due to this and the possibility of custom use cases,
+ QHttpHeaders does not automatically combine the values.
+
+ \section1 Performance
+
+ Most QHttpHeaders functions provide both
+ \l QHttpHeaders::WellKnownHeader and \l QAnyStringView overloads.
+ From a memory-usage and computation point of view it is recommended
+ to use the \l QHttpHeaders::WellKnownHeader overloads.
+*/
+
+// This list is from IANA HTTP Field Name Registry
+// https://www.iana.org/assignments/http-fields
+// It contains entries that are either "permanent"
+// or "deprecated" as of October 2023.
+// Usage relies on enum values keeping in same order.
+// ### Qt7 check if some of these headers have been obsoleted,
+// and also check if the enums benefit from reordering
+static constexpr auto headerNames = qOffsetStringArray(
+ // IANA Permanent status:
+ "a-im",
+ "accept",
+ "accept-additions",
+ "accept-ch",
+ "accept-datetime",
+ "accept-encoding",
+ "accept-features",
+ "accept-language",
+ "accept-patch",
+ "accept-post",
+ "accept-ranges",
+ "accept-signature",
+ "access-control-allow-credentials",
+ "access-control-allow-headers",
+ "access-control-allow-methods",
+ "access-control-allow-origin",
+ "access-control-expose-headers",
+ "access-control-max-age",
+ "access-control-request-headers",
+ "access-control-request-method",
+ "age",
+ "allow",
+ "alpn",
+ "alt-svc",
+ "alt-used",
+ "alternates",
+ "apply-to-redirect-ref",
+ "authentication-control",
+ "authentication-info",
+ "authorization",
+ "cache-control",
+ "cache-status",
+ "cal-managed-id",
+ "caldav-timezones",
+ "capsule-protocol",
+ "cdn-cache-control",
+ "cdn-loop",
+ "cert-not-after",
+ "cert-not-before",
+ "clear-site-data",
+ "client-cert",
+ "client-cert-chain",
+ "close",
+ "connection",
+ "content-digest",
+ "content-disposition",
+ "content-encoding",
+ "content-id",
+ "content-language",
+ "content-length",
+ "content-location",
+ "content-range",
+ "content-security-policy",
+ "content-security-policy-report-only",
+ "content-type",
+ "cookie",
+ "cross-origin-embedder-policy",
+ "cross-origin-embedder-policy-report-only",
+ "cross-origin-opener-policy",
+ "cross-origin-opener-policy-report-only",
+ "cross-origin-resource-policy",
+ "dasl",
+ "date",
+ "dav",
+ "delta-base",
+ "depth",
+ "destination",
+ "differential-id",
+ "dpop",
+ "dpop-nonce",
+ "early-data",
+ "etag",
+ "expect",
+ "expect-ct",
+ "expires",
+ "forwarded",
+ "from",
+ "hobareg",
+ "host",
+ "if",
+ "if-match",
+ "if-modified-since",
+ "if-none-match",
+ "if-range",
+ "if-schedule-tag-match",
+ "if-unmodified-since",
+ "im",
+ "include-referred-token-binding-id",
+ "keep-alive",
+ "label",
+ "last-event-id",
+ "last-modified",
+ "link",
+ "location",
+ "lock-token",
+ "max-forwards",
+ "memento-datetime",
+ "meter",
+ "mime-version",
+ "negotiate",
+ "nel",
+ "odata-entityid",
+ "odata-isolation",
+ "odata-maxversion",
+ "odata-version",
+ "optional-www-authenticate",
+ "ordering-type",
+ "origin",
+ "origin-agent-cluster",
+ "oscore",
+ "oslc-core-version",
+ "overwrite",
+ "ping-from",
+ "ping-to",
+ "position",
+ "prefer",
+ "preference-applied",
+ "priority",
+ "proxy-authenticate",
+ "proxy-authentication-info",
+ "proxy-authorization",
+ "proxy-status",
+ "public-key-pins",
+ "public-key-pins-report-only",
+ "range",
+ "redirect-ref",
+ "referer",
+ "refresh",
+ "replay-nonce",
+ "repr-digest",
+ "retry-after",
+ "schedule-reply",
+ "schedule-tag",
+ "sec-purpose",
+ "sec-token-binding",
+ "sec-websocket-accept",
+ "sec-websocket-extensions",
+ "sec-websocket-key",
+ "sec-websocket-protocol",
+ "sec-websocket-version",
+ "server",
+ "server-timing",
+ "set-cookie",
+ "signature",
+ "signature-input",
+ "slug",
+ "soapaction",
+ "status-uri",
+ "strict-transport-security",
+ "sunset",
+ "surrogate-capability",
+ "surrogate-control",
+ "tcn",
+ "te",
+ "timeout",
+ "topic",
+ "traceparent",
+ "tracestate",
+ "trailer",
+ "transfer-encoding",
+ "ttl",
+ "upgrade",
+ "urgency",
+ "user-agent",
+ "variant-vary",
+ "vary",
+ "via",
+ "want-content-digest",
+ "want-repr-digest",
+ "www-authenticate",
+ "x-content-type-options",
+ "x-frame-options",
+ // IANA Deprecated status:
+ "accept-charset",
+ "c-pep-info",
+ "pragma",
+ "protocol-info",
+ "protocol-query"
+ // If you append here, regenerate the index table
+);
+
+namespace {
+struct ByIndirectHeaderName
+{
+ constexpr bool operator()(quint8 lhs, quint8 rhs) const noexcept
+ {
+ return (*this)(map(lhs), map(rhs));
+ }
+ constexpr bool operator()(quint8 lhs, QByteArrayView rhs) const noexcept
+ {
+ return (*this)(map(lhs), rhs);
+ }
+ constexpr bool operator()(QByteArrayView lhs, quint8 rhs) const noexcept
+ {
+ return (*this)(lhs, map(rhs));
+ }
+ constexpr bool operator()(QByteArrayView lhs, QByteArrayView rhs) const noexcept
+ {
+ // ### just `lhs < rhs` when QByteArrayView relational operators are constexpr
+ return std::string_view(lhs) < std::string_view(rhs);
+ }
+private:
+ static constexpr QByteArrayView map(quint8 i) noexcept
+ {
+ return headerNames.viewAt(i);
+ }
+};
+} // unnamed namespace
+
+// This index table contains the indexes of 'headerNames' entries (above) in alphabetical order.
+// This allows a more efficient binary search for the names [O(logN)]. The 'headerNames' itself
+// cannot be guaranteed to be in alphabetical order, as it must keep the same order as the
+// WellKnownHeader enum, which may get appended over time.
+//
+// Note: when appending new enums, this must be regenerated
+static constexpr quint8 orderedHeaderNameIndexes[] = {
+ 0, // a-im
+ 1, // accept
+ 2, // accept-additions
+ 3, // accept-ch
+ 172, // accept-charset
+ 4, // accept-datetime
+ 5, // accept-encoding
+ 6, // accept-features
+ 7, // accept-language
+ 8, // accept-patch
+ 9, // accept-post
+ 10, // accept-ranges
+ 11, // accept-signature
+ 12, // access-control-allow-credentials
+ 13, // access-control-allow-headers
+ 14, // access-control-allow-methods
+ 15, // access-control-allow-origin
+ 16, // access-control-expose-headers
+ 17, // access-control-max-age
+ 18, // access-control-request-headers
+ 19, // access-control-request-method
+ 20, // age
+ 21, // allow
+ 22, // alpn
+ 23, // alt-svc
+ 24, // alt-used
+ 25, // alternates
+ 26, // apply-to-redirect-ref
+ 27, // authentication-control
+ 28, // authentication-info
+ 29, // authorization
+ 173, // c-pep-info
+ 30, // cache-control
+ 31, // cache-status
+ 32, // cal-managed-id
+ 33, // caldav-timezones
+ 34, // capsule-protocol
+ 35, // cdn-cache-control
+ 36, // cdn-loop
+ 37, // cert-not-after
+ 38, // cert-not-before
+ 39, // clear-site-data
+ 40, // client-cert
+ 41, // client-cert-chain
+ 42, // close
+ 43, // connection
+ 44, // content-digest
+ 45, // content-disposition
+ 46, // content-encoding
+ 47, // content-id
+ 48, // content-language
+ 49, // content-length
+ 50, // content-location
+ 51, // content-range
+ 52, // content-security-policy
+ 53, // content-security-policy-report-only
+ 54, // content-type
+ 55, // cookie
+ 56, // cross-origin-embedder-policy
+ 57, // cross-origin-embedder-policy-report-only
+ 58, // cross-origin-opener-policy
+ 59, // cross-origin-opener-policy-report-only
+ 60, // cross-origin-resource-policy
+ 61, // dasl
+ 62, // date
+ 63, // dav
+ 64, // delta-base
+ 65, // depth
+ 66, // destination
+ 67, // differential-id
+ 68, // dpop
+ 69, // dpop-nonce
+ 70, // early-data
+ 71, // etag
+ 72, // expect
+ 73, // expect-ct
+ 74, // expires
+ 75, // forwarded
+ 76, // from
+ 77, // hobareg
+ 78, // host
+ 79, // if
+ 80, // if-match
+ 81, // if-modified-since
+ 82, // if-none-match
+ 83, // if-range
+ 84, // if-schedule-tag-match
+ 85, // if-unmodified-since
+ 86, // im
+ 87, // include-referred-token-binding-id
+ 88, // keep-alive
+ 89, // label
+ 90, // last-event-id
+ 91, // last-modified
+ 92, // link
+ 93, // location
+ 94, // lock-token
+ 95, // max-forwards
+ 96, // memento-datetime
+ 97, // meter
+ 98, // mime-version
+ 99, // negotiate
+ 100, // nel
+ 101, // odata-entityid
+ 102, // odata-isolation
+ 103, // odata-maxversion
+ 104, // odata-version
+ 105, // optional-www-authenticate
+ 106, // ordering-type
+ 107, // origin
+ 108, // origin-agent-cluster
+ 109, // oscore
+ 110, // oslc-core-version
+ 111, // overwrite
+ 112, // ping-from
+ 113, // ping-to
+ 114, // position
+ 174, // pragma
+ 115, // prefer
+ 116, // preference-applied
+ 117, // priority
+ 175, // protocol-info
+ 176, // protocol-query
+ 118, // proxy-authenticate
+ 119, // proxy-authentication-info
+ 120, // proxy-authorization
+ 121, // proxy-status
+ 122, // public-key-pins
+ 123, // public-key-pins-report-only
+ 124, // range
+ 125, // redirect-ref
+ 126, // referer
+ 127, // refresh
+ 128, // replay-nonce
+ 129, // repr-digest
+ 130, // retry-after
+ 131, // schedule-reply
+ 132, // schedule-tag
+ 133, // sec-purpose
+ 134, // sec-token-binding
+ 135, // sec-websocket-accept
+ 136, // sec-websocket-extensions
+ 137, // sec-websocket-key
+ 138, // sec-websocket-protocol
+ 139, // sec-websocket-version
+ 140, // server
+ 141, // server-timing
+ 142, // set-cookie
+ 143, // signature
+ 144, // signature-input
+ 145, // slug
+ 146, // soapaction
+ 147, // status-uri
+ 148, // strict-transport-security
+ 149, // sunset
+ 150, // surrogate-capability
+ 151, // surrogate-control
+ 152, // tcn
+ 153, // te
+ 154, // timeout
+ 155, // topic
+ 156, // traceparent
+ 157, // tracestate
+ 158, // trailer
+ 159, // transfer-encoding
+ 160, // ttl
+ 161, // upgrade
+ 162, // urgency
+ 163, // user-agent
+ 164, // variant-vary
+ 165, // vary
+ 166, // via
+ 167, // want-content-digest
+ 168, // want-repr-digest
+ 169, // www-authenticate
+ 170, // x-content-type-options
+ 171, // x-frame-options
+};
+static_assert(std::size(orderedHeaderNameIndexes) == size_t(headerNames.count()));
+static_assert(q20::is_sorted(std::begin(orderedHeaderNameIndexes),
+ std::end(orderedHeaderNameIndexes),
+ ByIndirectHeaderName{}));
+
+/*!
+ \enum QHttpHeaders::WellKnownHeader
+
+ List of well known headers as per
+ \l {https://www.iana.org/assignments/http-fields}{IANA registry}.
+
+ \value AIM
+ \value Accept
+ \value AcceptAdditions
+ \value AcceptCH
+ \value AcceptDatetime
+ \value AcceptEncoding
+ \value AcceptFeatures
+ \value AcceptLanguage
+ \value AcceptPatch
+ \value AcceptPost
+ \value AcceptRanges
+ \value AcceptSignature
+ \value AccessControlAllowCredentials
+ \value AccessControlAllowHeaders
+ \value AccessControlAllowMethods
+ \value AccessControlAllowOrigin
+ \value AccessControlExposeHeaders
+ \value AccessControlMaxAge
+ \value AccessControlRequestHeaders
+ \value AccessControlRequestMethod
+ \value Age
+ \value Allow
+ \value ALPN
+ \value AltSvc
+ \value AltUsed
+ \value Alternates
+ \value ApplyToRedirectRef
+ \value AuthenticationControl
+ \value AuthenticationInfo
+ \value Authorization
+ \value CacheControl
+ \value CacheStatus
+ \value CalManagedID
+ \value CalDAVTimezones
+ \value CapsuleProtocol
+ \value CDNCacheControl
+ \value CDNLoop
+ \value CertNotAfter
+ \value CertNotBefore
+ \value ClearSiteData
+ \value ClientCert
+ \value ClientCertChain
+ \value Close
+ \value Connection
+ \value ContentDigest
+ \value ContentDisposition
+ \value ContentEncoding
+ \value ContentID
+ \value ContentLanguage
+ \value ContentLength
+ \value ContentLocation
+ \value ContentRange
+ \value ContentSecurityPolicy
+ \value ContentSecurityPolicyReportOnly
+ \value ContentType
+ \value Cookie
+ \value CrossOriginEmbedderPolicy
+ \value CrossOriginEmbedderPolicyReportOnly
+ \value CrossOriginOpenerPolicy
+ \value CrossOriginOpenerPolicyReportOnly
+ \value CrossOriginResourcePolicy
+ \value DASL
+ \value Date
+ \value DAV
+ \value DeltaBase
+ \value Depth
+ \value Destination
+ \value DifferentialID
+ \value DPoP
+ \value DPoPNonce
+ \value EarlyData
+ \value ETag
+ \value Expect
+ \value ExpectCT
+ \value Expires
+ \value Forwarded
+ \value From
+ \value Hobareg
+ \value Host
+ \value If
+ \value IfMatch
+ \value IfModifiedSince
+ \value IfNoneMatch
+ \value IfRange
+ \value IfScheduleTagMatch
+ \value IfUnmodifiedSince
+ \value IM
+ \value IncludeReferredTokenBindingID
+ \value KeepAlive
+ \value Label
+ \value LastEventID
+ \value LastModified
+ \value Link
+ \value Location
+ \value LockToken
+ \value MaxForwards
+ \value MementoDatetime
+ \value Meter
+ \value MIMEVersion
+ \value Negotiate
+ \value NEL
+ \value ODataEntityId
+ \value ODataIsolation
+ \value ODataMaxVersion
+ \value ODataVersion
+ \value OptionalWWWAuthenticate
+ \value OrderingType
+ \value Origin
+ \value OriginAgentCluster
+ \value OSCORE
+ \value OSLCCoreVersion
+ \value Overwrite
+ \value PingFrom
+ \value PingTo
+ \value Position
+ \value Prefer
+ \value PreferenceApplied
+ \value Priority
+ \value ProxyAuthenticate
+ \value ProxyAuthenticationInfo
+ \value ProxyAuthorization
+ \value ProxyStatus
+ \value PublicKeyPins
+ \value PublicKeyPinsReportOnly
+ \value Range
+ \value RedirectRef
+ \value Referer
+ \value Refresh
+ \value ReplayNonce
+ \value ReprDigest
+ \value RetryAfter
+ \value ScheduleReply
+ \value ScheduleTag
+ \value SecPurpose
+ \value SecTokenBinding
+ \value SecWebSocketAccept
+ \value SecWebSocketExtensions
+ \value SecWebSocketKey
+ \value SecWebSocketProtocol
+ \value SecWebSocketVersion
+ \value Server
+ \value ServerTiming
+ \value SetCookie
+ \value Signature
+ \value SignatureInput
+ \value SLUG
+ \value SoapAction
+ \value StatusURI
+ \value StrictTransportSecurity
+ \value Sunset
+ \value SurrogateCapability
+ \value SurrogateControl
+ \value TCN
+ \value TE
+ \value Timeout
+ \value Topic
+ \value Traceparent
+ \value Tracestate
+ \value Trailer
+ \value TransferEncoding
+ \value TTL
+ \value Upgrade
+ \value Urgency
+ \value UserAgent
+ \value VariantVary
+ \value Vary
+ \value Via
+ \value WantContentDigest
+ \value WantReprDigest
+ \value WWWAuthenticate
+ \value XContentTypeOptions
+ \value XFrameOptions
+ \value AcceptCharset
+ \value CPEPInfo
+ \value Pragma
+ \value ProtocolInfo
+ \value ProtocolQuery
+*/
+
+static QByteArray fieldToByteArray(QLatin1StringView s) noexcept
+{
+ return QByteArray(s.data(), s.size());
+}
+
+static QByteArray fieldToByteArray(QUtf8StringView s) noexcept
+{
+ return QByteArray(s.data(), s.size());
+}
+
+static QByteArray fieldToByteArray(QStringView s)
+{
+ return s.toLatin1();
+}
+
+static QByteArray normalizedName(QAnyStringView name)
+{
+ return name.visit([](auto name){ return fieldToByteArray(name); }).toLower();
+}
+
+struct HeaderName
+{
+ explicit HeaderName(QHttpHeaders::WellKnownHeader name) : data(name)
+ {
+ }
+
+ explicit HeaderName(QAnyStringView name)
+ {
+ auto nname = normalizedName(name);
+ if (auto h = HeaderName::toWellKnownHeader(nname))
+ data = *h;
+ else
+ data = std::move(nname);
+ }
+
+ // Returns an enum corresponding with the 'name' if possible. Uses binary search (O(logN)).
+ // The function doesn't normalize the data; needs to be done by the caller if needed
+ static std::optional<QHttpHeaders::WellKnownHeader> toWellKnownHeader(QByteArrayView name) noexcept
+ {
+ auto indexesBegin = std::cbegin(orderedHeaderNameIndexes);
+ auto indexesEnd = std::cend(orderedHeaderNameIndexes);
+
+ auto result = std::lower_bound(indexesBegin, indexesEnd, name, ByIndirectHeaderName{});
+
+ if (result != indexesEnd && name == headerNames[*result])
+ return static_cast<QHttpHeaders::WellKnownHeader>(*result);
+ return std::nullopt;
+ }
+
+ QByteArrayView asView() const noexcept
+ {
+ return std::visit([](const auto &arg) -> QByteArrayView {
+ using T = decltype(arg);
+ if constexpr (std::is_same_v<T, const QByteArray &>)
+ return arg;
+ else if constexpr (std::is_same_v<T, const QHttpHeaders::WellKnownHeader &>)
+ return headerNames.viewAt(qToUnderlying(arg));
+ else
+ static_assert(QtPrivate::type_dependent_false<T>());
+ }, data);
+ }
+
+ QByteArray asByteArray() const noexcept
+ {
+ return std::visit([](const auto &arg) -> QByteArray {
+ using T = decltype(arg);
+ if constexpr (std::is_same_v<T, const QByteArray &>) {
+ return arg;
+ } else if constexpr (std::is_same_v<T, const QHttpHeaders::WellKnownHeader &>) {
+ const auto view = headerNames.viewAt(qToUnderlying(arg));
+ return QByteArray::fromRawData(view.constData(), view.size());
+ } else {
+ static_assert(QtPrivate::type_dependent_false<T>());
+ }
+ }, data);
+ }
+
+private:
+ // Store the data as 'enum' whenever possible; more performant, and comparison relies on that
+ std::variant<QHttpHeaders::WellKnownHeader, QByteArray> data;
+
+ friend bool comparesEqual(const HeaderName &lhs, const HeaderName &rhs) noexcept
+ {
+ // Here we compare two std::variants, which will return false if the types don't match.
+ // That is beneficial here because we avoid unnecessary comparisons; but it also means
+ // we must always store the data as WellKnownHeader when possible (in other words, if
+ // we get a string that is mappable to a WellKnownHeader). To guard against accidental
+ // misuse, the 'data' is private and the constructors must be used.
+ return lhs.data == rhs.data;
+ }
+ Q_DECLARE_EQUALITY_COMPARABLE(HeaderName)
+};
+
+// A clarification on case-sensitivity:
+// - Header *names* are case-insensitive; Content-Type and content-type are considered equal
+// - Header *values* are case-sensitive
+// (In addition, the HTTP/2 and HTTP/3 standards mandate that all headers must be lower-cased when
+// encoded into transmission)
+struct Header {
+ HeaderName name;
+ QByteArray value;
+};
+
+auto headerNameMatches(const HeaderName &name)
+{
+ return [&name](const Header &header) { return header.name == name; };
+}
+
+class QHttpHeadersPrivate : public QSharedData
+{
+public:
+ QHttpHeadersPrivate() = default;
+
+ // The 'Self' is supplied as parameter to static functions so that
+ // we can define common methods which 'detach()' the private itself.
+ using Self = QExplicitlySharedDataPointer<QHttpHeadersPrivate>;
+ static void removeAll(Self &d, const HeaderName &name);
+ static void replaceOrAppend(Self &d, const HeaderName &name, const QByteArray &value);
+
+ void combinedValue(const HeaderName &name, QByteArray &result) const;
+ void values(const HeaderName &name, QList<QByteArray> &result) const;
+ QByteArrayView value(const HeaderName &name, QByteArrayView defaultValue) const noexcept;
+
+ QList<Header> headers;
+};
+
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QHttpHeadersPrivate)
+template <> void QExplicitlySharedDataPointer<QHttpHeadersPrivate>::detach()
+{
+ if (!d) {
+ d = new QHttpHeadersPrivate();
+ d->ref.ref();
+ } else if (d->ref.loadRelaxed() != 1) {
+ detach_helper();
+ }
+}
+
+void QHttpHeadersPrivate::removeAll(Self &d, const HeaderName &name)
+{
+ const auto it = std::find_if(d->headers.cbegin(), d->headers.cend(), headerNameMatches(name));
+
+ if (it != d->headers.cend()) {
+ // Found something to remove, calculate offset so we can proceed from the match-location
+ const auto matchOffset = it - d->headers.cbegin();
+ d.detach();
+ // Rearrange all matches to the end and erase them
+ d->headers.erase(std::remove_if(d->headers.begin() + matchOffset, d->headers.end(),
+ headerNameMatches(name)),
+ d->headers.end());
+ }
+}
+
+void QHttpHeadersPrivate::combinedValue(const HeaderName &name, QByteArray &result) const
+{
+ const char* separator = "";
+ for (const auto &h : std::as_const(headers)) {
+ if (h.name == name) {
+ result.append(separator);
+ result.append(h.value);
+ separator = ", ";
+ }
+ }
+}
+
+void QHttpHeadersPrivate::values(const HeaderName &name, QList<QByteArray> &result) const
+{
+ for (const auto &h : std::as_const(headers)) {
+ if (h.name == name)
+ result.append(h.value);
+ }
+}
+
+QByteArrayView QHttpHeadersPrivate::value(const HeaderName &name, QByteArrayView defaultValue) const noexcept
+{
+ for (const auto &h : std::as_const(headers)) {
+ if (h.name == name)
+ return h.value;
+ }
+ return defaultValue;
+}
+
+void QHttpHeadersPrivate::replaceOrAppend(Self &d, const HeaderName &name, const QByteArray &value)
+{
+ d.detach();
+ auto it = std::find_if(d->headers.begin(), d->headers.end(), headerNameMatches(name));
+ if (it != d->headers.end()) {
+ // Found something to replace => replace, and then rearrange any remaining
+ // matches to the end and erase them
+ it->value = value;
+ d->headers.erase(
+ std::remove_if(it + 1, d->headers.end(), headerNameMatches(name)),
+ d->headers.end());
+ } else {
+ // Found nothing to replace => append
+ d->headers.append(Header{name, value});
+ }
+}
+
+/*!
+ Creates a new QHttpHeaders object.
+*/
+QHttpHeaders::QHttpHeaders() noexcept : d()
+{
+}
+
+/*!
+ Creates a new QHttpHeaders object that is populated with
+ \a headers.
+
+ \sa {Allowed field name and value characters}
+*/
+QHttpHeaders QHttpHeaders::fromListOfPairs(const QList<std::pair<QByteArray, QByteArray>> &headers)
+{
+ QHttpHeaders h;
+ h.reserve(headers.size());
+ for (const auto &header : headers)
+ h.append(header.first, header.second);
+ return h;
+}
+
+/*!
+ Creates a new QHttpHeaders object that is populated with
+ \a headers.
+
+ \sa {Allowed field name and value characters}
+*/
+QHttpHeaders QHttpHeaders::fromMultiMap(const QMultiMap<QByteArray, QByteArray> &headers)
+{
+ QHttpHeaders h;
+ h.reserve(headers.size());
+ for (const auto &[name,value] : headers.asKeyValueRange())
+ h.append(name, value);
+ return h;
+}
+
+/*!
+ Creates a new QHttpHeaders object that is populated with
+ \a headers.
+
+ \sa {Allowed field name and value characters}
+*/
+QHttpHeaders QHttpHeaders::fromMultiHash(const QMultiHash<QByteArray, QByteArray> &headers)
+{
+ QHttpHeaders h;
+ h.reserve(headers.size());
+ for (const auto &[name,value] : headers.asKeyValueRange())
+ h.append(name, value);
+ return h;
+}
+
+/*!
+ Disposes of the headers object.
+*/
+QHttpHeaders::~QHttpHeaders()
+ = default;
+
+/*!
+ Creates a copy of \a other.
+*/
+QHttpHeaders::QHttpHeaders(const QHttpHeaders &other)
+ = default;
+
+/*!
+ Assigns the contents of \a other and returns a reference to this object.
+*/
+QHttpHeaders &QHttpHeaders::operator=(const QHttpHeaders &other)
+ = default;
+
+/*!
+ \fn QHttpHeaders::QHttpHeaders(QHttpHeaders &&other) noexcept
+
+ Move-constructs the object from \a other, which will be left
+ \l{isEmpty()}{empty}.
+*/
+
+/*!
+ \fn QHttpHeaders &QHttpHeaders::operator=(QHttpHeaders &&other) noexcept
+
+ Move-assigns \a other and returns a reference to this object.
+
+ \a other will be left \l{isEmpty()}{empty}.
+*/
+
+/*!
+ \fn void QHttpHeaders::swap(QHttpHeaders &other)
+
+ Swaps this QHttpHeaders with \a other. This function is very fast and
+ never fails.
+*/
+
+#ifndef QT_NO_DEBUG_STREAM
+/*!
+ \fn QDebug QHttpHeaders::operator<<(QDebug debug,
+ const QHttpHeaders &headers)
+
+ Writes \a headers into \a debug stream.
+*/
+QDebug operator<<(QDebug debug, const QHttpHeaders &headers)
+{
+ const QDebugStateSaver saver(debug);
+ debug.resetFormat().nospace();
+
+ debug << "QHttpHeaders(";
+ if (headers.d) {
+ debug << "headers = ";
+ const char *separator = "";
+ for (const auto &h : headers.d->headers) {
+ debug << separator << h.name.asView() << ':' << h.value;
+ separator = " | ";
+ }
+ }
+ debug << ")";
+ return debug;
+}
+#endif
+
+// A clarification on string encoding:
+// Setters and getters only accept names and values that are Latin-1 representable:
+// Either they are directly ASCII/Latin-1, or if they are UTF-X, they only use first 256
+// of the unicode points. For example using a '€' (U+20AC) in value would yield a warning
+// and the call is ignored.
+// Furthermore the 'name' has more strict rules than the 'value'
+
+// TODO FIXME REMOVEME once this is merged:
+// https://codereview.qt-project.org/c/qt/qtbase/+/508829
+static bool isUtf8Latin1Representable(QUtf8StringView s) noexcept
+{
+ // L1 encoded in UTF8 has at most the form
+ // - 0b0XXX'XXXX - US-ASCII
+ // - 0b1100'00XX 0b10XX'XXXX - at most 8 non-zero LSB bits allowed in L1
+ bool inMultibyte = false;
+ for (unsigned char c : s) {
+ if (c < 128) { // US-ASCII
+ if (inMultibyte)
+ return false; // invalid sequence
+ } else {
+ // decode as UTF-8:
+ if ((c & 0b1110'0000) == 0b1100'0000) { // two-octet UTF-8 leader
+ if (inMultibyte)
+ return false; // invalid sequence
+ inMultibyte = true;
+ const auto bits_7_to_11 = c & 0b0001'1111;
+ if (bits_7_to_11 < 0b10)
+ return false; // invalid sequence (US-ASCII encoded in two octets)
+ if (bits_7_to_11 > 0b11) // more than the two LSB
+ return false; // outside L1
+ } else if ((c & 0b1100'0000) == 0b1000'0000) { // trailing UTF-8 octet
+ if (!inMultibyte)
+ return false; // invalid sequence
+ inMultibyte = false; // only one continuation allowed
+ } else {
+ return false; // invalid sequence or outside of L1
+ }
+ }
+ }
+ if (inMultibyte)
+ return false; // invalid sequence: premature end
+ return true;
+}
+
+static constexpr auto isValidHttpHeaderNameChar = [](uchar c) noexcept
+{
+ // RFC 9110 Chapters "5.1 Field Names" and "5.6.2 Tokens"
+ // field-name = token
+ // token = 1*tchar
+ // tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" /
+ // "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
+ // / DIGIT / ALPHA
+ // ; any VCHAR, except delimiters
+ // (for explanation on VCHAR see isValidHttpHeaderValueChar)
+ return (('A' <= c && c <= 'Z')
+ || ('a' <= c && c <= 'z')
+ || ('0' <= c && c <= '9')
+ || ('#' <= c && c <= '\'')
+ || ('^' <= c && c <= '`')
+ || c == '|' || c == '~' || c == '!' || c == '*' || c == '+' || c == '-' || c == '.');
+};
+
+static bool headerNameValidImpl(QLatin1StringView name) noexcept
+{
+ return std::all_of(name.begin(), name.end(), isValidHttpHeaderNameChar);
+}
+
+static bool headerNameValidImpl(QUtf8StringView name) noexcept
+{
+ // Traversing the UTF-8 string char-by-char is fine in this case as
+ // the isValidHttpHeaderNameChar rejects any value above 0x7E. UTF-8
+ // only has bytes <= 0x7F if they truly represent that ASCII character.
+ return headerNameValidImpl(QLatin1StringView(QByteArrayView(name)));
+}
+
+static bool headerNameValidImpl(QStringView name) noexcept
+{
+ return std::all_of(name.begin(), name.end(), [](QChar c) {
+ return isValidHttpHeaderNameChar(c.toLatin1());
+ });
+}
+
+static bool isValidHttpHeaderNameField(QAnyStringView name) noexcept
+{
+ if (name.isEmpty()) {
+ qCWarning(lcQHttpHeaders, "HTTP header name cannot be empty");
+ return false;
+ }
+ const bool valid = name.visit([](auto name){ return headerNameValidImpl(name); });
+ if (!valid)
+ qCWarning(lcQHttpHeaders, "HTTP header name contained illegal character(s)");
+ return valid;
+}
+
+static constexpr auto isValidHttpHeaderValueChar = [](uchar c) noexcept
+{
+ // RFC 9110 Chapter 5.5, Field Values
+ // field-value = *field-content
+ // field-content = field-vchar
+ // [ 1*( SP / HTAB / field-vchar ) field-vchar ]
+ // field-vchar = VCHAR / obs-text
+ // obs-text = %x80-FF
+ // VCHAR is defined as "any visible US-ASCII character", and RFC 5234 B.1.
+ // defines it as %x21-7E
+ // Note: The ABNF above states that field-content and thus field-value cannot
+ // start or end with SP/HTAB. The caller should handle this.
+ return (c >= 0x80 // obs-text (extended ASCII)
+ || (0x20 <= c && c <= 0x7E) // SP (0x20) + VCHAR
+ || (c == 0x09)); // HTAB
+};
+
+static bool headerValueValidImpl(QLatin1StringView value) noexcept
+{
+ return std::all_of(value.begin(), value.end(), isValidHttpHeaderValueChar);
+}
+
+static bool headerValueValidImpl(QUtf8StringView value) noexcept
+{
+ if (!isUtf8Latin1Representable(value)) // TODO FIXME see the function
+ return false;
+ return std::all_of(value.begin(), value.end(), isValidHttpHeaderValueChar);
+}
+
+static bool headerValueValidImpl(QStringView value) noexcept
+{
+ return std::all_of(value.begin(), value.end(), [](QChar c) {
+ return isValidHttpHeaderValueChar(c.toLatin1());
+ });
+}
+
+static bool isValidHttpHeaderValueField(QAnyStringView value) noexcept
+{
+ const bool valid = value.visit([](auto value){ return headerValueValidImpl(value); });
+ if (!valid)
+ qCWarning(lcQHttpHeaders, "HTTP header value contained illegal character(s)");
+ return valid;
+}
+
+static QByteArray normalizedValue(QAnyStringView value)
+{
+ // Note on trimming away any leading or trailing whitespace of 'value':
+ // RFC 9110 (HTTP 1.1, 2022, Chapter 5.5) does not allow leading or trailing whitespace
+ // RFC 7230 (HTTP 1.1, 2014, Chapter 3.2) allows them optionally, but also mandates that
+ // they are ignored during processing
+ // RFC 7540 (HTTP/2) does not seem explicit about it
+ // => for maximum compatibility, trim away any leading or trailing whitespace
+ return value.visit([](auto value){ return fieldToByteArray(value); }).trimmed();
+}
+
+/*!
+ Appends a header entry with \a name and \a value and returns \c true
+ if successful.
+
+ \sa append(QHttpHeaders::WellKnownHeader, QAnyStringView)
+ \sa {Allowed field name and value characters}
+*/
+bool QHttpHeaders::append(QAnyStringView name, QAnyStringView value)
+{
+ if (!isValidHttpHeaderNameField(name) || !isValidHttpHeaderValueField(value))
+ return false;
+
+ d.detach();
+ d->headers.push_back({HeaderName{name}, normalizedValue(value)});
+ return true;
+}
+
+/*!
+ \overload append(QAnyStringView, QAnyStringView)
+*/
+bool QHttpHeaders::append(WellKnownHeader name, QAnyStringView value)
+{
+ if (!isValidHttpHeaderValueField(value))
+ return false;
+
+ d.detach();
+ d->headers.push_back({HeaderName{name}, normalizedValue(value)});
+ return true;
+}
+
+/*!
+ Inserts a header entry at index \a i, with \a name and \a value. The index
+ must be valid (see \l size()). Returns whether the insert succeeded.
+
+ \sa append(),
+ insert(qsizetype, QHttpHeaders::WellKnownHeader, QAnyStringView), size()
+ \sa {Allowed field name and value characters}
+*/
+bool QHttpHeaders::insert(qsizetype i, QAnyStringView name, QAnyStringView value)
+{
+ verify(i, 0);
+ if (!isValidHttpHeaderNameField(name) || !isValidHttpHeaderValueField(value))
+ return false;
+
+ d.detach();
+ d->headers.insert(i, {HeaderName{name}, normalizedValue(value)});
+ return true;
+}
+
+/*!
+ \overload insert(qsizetype, QAnyStringView, QAnyStringView)
+*/
+bool QHttpHeaders::insert(qsizetype i, WellKnownHeader name, QAnyStringView value)
+{
+ verify(i, 0);
+ if (!isValidHttpHeaderValueField(value))
+ return false;
+
+ d.detach();
+ d->headers.insert(i, {HeaderName{name}, normalizedValue(value)});
+ return true;
+}
+
+/*!
+ Replaces the header entry at index \a i, with \a name and \a newValue.
+ The index must be valid (see \l size()). Returns whether the replace
+ succeeded.
+
+ \sa append(),
+ replace(qsizetype, QHttpHeaders::WellKnownHeader, QAnyStringView), size()
+ \sa {Allowed field name and value characters}
+*/
+bool QHttpHeaders::replace(qsizetype i, QAnyStringView name, QAnyStringView newValue)
+{
+ verify(i);
+ if (!isValidHttpHeaderNameField(name) || !isValidHttpHeaderValueField(newValue))
+ return false;
+
+ d.detach();
+ d->headers.replace(i, {HeaderName{name}, normalizedValue(newValue)});
+ return true;
+}
+
+/*!
+ \overload replace(qsizetype, QAnyStringView, QAnyStringView)
+*/
+bool QHttpHeaders::replace(qsizetype i, WellKnownHeader name, QAnyStringView newValue)
+{
+ verify(i);
+ if (!isValidHttpHeaderValueField(newValue))
+ return false;
+
+ d.detach();
+ d->headers.replace(i, {HeaderName{name}, normalizedValue(newValue)});
+ return true;
+}
+
+/*!
+ \since 6.8
+
+ If QHttpHeaders already contains \a name, replaces its value with
+ \a newValue and removes possible additional \a name entries.
+ If \a name didn't exist, appends a new entry. Returns \c true
+ if successful.
+
+ This function is a convenience method for setting a unique
+ \a name : \a newValue header. For most headers the relative order does not
+ matter, which allows reusing an existing entry if one exists.
+
+ \sa replaceOrAppend(QAnyStringView, QAnyStringView)
+*/
+bool QHttpHeaders::replaceOrAppend(WellKnownHeader name, QAnyStringView newValue)
+{
+ if (isEmpty())
+ return append(name, newValue);
+
+ if (!isValidHttpHeaderValueField(newValue))
+ return false;
+
+ QHttpHeadersPrivate::replaceOrAppend(d, HeaderName{name}, normalizedValue(newValue));
+ return true;
+}
+
+/*!
+ \overload replaceOrAppend(WellKnownHeader, QAnyStringView)
+*/
+bool QHttpHeaders::replaceOrAppend(QAnyStringView name, QAnyStringView newValue)
+{
+ if (isEmpty())
+ return append(name, newValue);
+
+ if (!isValidHttpHeaderNameField(name) || !isValidHttpHeaderValueField(newValue))
+ return false;
+
+ QHttpHeadersPrivate::replaceOrAppend(d, HeaderName{name}, normalizedValue(newValue));
+ return true;
+}
+
+/*!
+ Returns whether the headers contain header with \a name.
+
+ \sa contains(QHttpHeaders::WellKnownHeader)
+*/
+bool QHttpHeaders::contains(QAnyStringView name) const
+{
+ if (isEmpty())
+ return false;
+
+ return std::any_of(d->headers.cbegin(), d->headers.cend(), headerNameMatches(HeaderName{name}));
+}
+
+/*!
+ \overload has(QAnyStringView)
+*/
+bool QHttpHeaders::contains(WellKnownHeader name) const
+{
+ if (isEmpty())
+ return false;
+
+ return std::any_of(d->headers.cbegin(), d->headers.cend(), headerNameMatches(HeaderName{name}));
+}
+
+/*!
+ Removes the header \a name.
+
+ \sa removeAt(), removeAll(QHttpHeaders::WellKnownHeader)
+*/
+void QHttpHeaders::removeAll(QAnyStringView name)
+{
+ if (isEmpty())
+ return;
+
+ return QHttpHeadersPrivate::removeAll(d, HeaderName(name));
+}
+
+/*!
+ \overload removeAll(QAnyStringView)
+*/
+void QHttpHeaders::removeAll(WellKnownHeader name)
+{
+ if (isEmpty())
+ return;
+
+ return QHttpHeadersPrivate::removeAll(d, HeaderName(name));
+}
+
+/*!
+ Removes the header at index \a i. The index \a i must be valid
+ (see \l size()).
+
+ \sa removeAll(QHttpHeaders::WellKnownHeader),
+ removeAll(QAnyStringView), size()
+*/
+void QHttpHeaders::removeAt(qsizetype i)
+{
+ verify(i);
+ d.detach();
+ d->headers.removeAt(i);
+}
+
+/*!
+ Returns the value of the (first) header \a name, or \a defaultValue if it
+ doesn't exist.
+
+ \sa value(QHttpHeaders::WellKnownHeader, QByteArrayView)
+*/
+QByteArrayView QHttpHeaders::value(QAnyStringView name, QByteArrayView defaultValue) const noexcept
+{
+ if (isEmpty())
+ return defaultValue;
+
+ return d->value(HeaderName{name}, defaultValue);
+}
+
+/*!
+ \overload value(QAnyStringView, QByteArrayView)
+*/
+QByteArrayView QHttpHeaders::value(WellKnownHeader name, QByteArrayView defaultValue) const noexcept
+{
+ if (isEmpty())
+ return defaultValue;
+
+ return d->value(HeaderName{name}, defaultValue);
+}
+
+/*!
+ Returns the values of header \a name in a list. Returns an empty
+ list if header with \a name doesn't exist.
+
+ \sa values(QHttpHeaders::WellKnownHeader)
+*/
+QList<QByteArray> QHttpHeaders::values(QAnyStringView name) const
+{
+ QList<QByteArray> result;
+ if (isEmpty())
+ return result;
+
+ d->values(HeaderName{name}, result);
+ return result;
+}
+
+/*!
+ \overload values(QAnyStringView)
+*/
+QList<QByteArray> QHttpHeaders::values(WellKnownHeader name) const
+{
+ QList<QByteArray> result;
+ if (isEmpty())
+ return result;
+
+ d->values(HeaderName{name}, result);
+ return result;
+}
+
+/*!
+ Returns the header value at index \a i. The index \a i must be valid
+ (see \l size()).
+
+ \sa size(), value(), values(), combinedValue(), nameAt()
+*/
+QByteArrayView QHttpHeaders::valueAt(qsizetype i) const noexcept
+{
+ verify(i);
+ return d->headers.at(i).value;
+}
+
+/*!
+ Returns the header name at index \a i. The index \a i must be valid
+ (see \l size()).
+
+ Header names are case-insensitive, and the returned names are lower-cased.
+
+ \sa size(), valueAt()
+*/
+QLatin1StringView QHttpHeaders::nameAt(qsizetype i) const noexcept
+{
+ verify(i);
+ return QLatin1StringView{d->headers.at(i).name.asView()};
+}
+
+/*!
+ Returns the values of header \a name in a comma-combined string.
+ Returns a \c null QByteArray if the header with \a name doesn't
+ exist.
+
+ \note Accessing the value(s) of 'Set-Cookie' header this way may not work
+ as intended. It is a notable exception in the
+ \l {https://datatracker.ietf.org/doc/html/rfc9110#name-field-order}{HTTP RFC}
+ in that its values cannot be combined this way. Prefer \l values() instead.
+
+ \sa values(QAnyStringView)
+*/
+QByteArray QHttpHeaders::combinedValue(QAnyStringView name) const
+{
+ QByteArray result;
+ if (isEmpty())
+ return result;
+
+ d->combinedValue(HeaderName{name}, result);
+ return result;
+}
+
+/*!
+ \overload combinedValue(QAnyStringView)
+*/
+QByteArray QHttpHeaders::combinedValue(WellKnownHeader name) const
+{
+ QByteArray result;
+ if (isEmpty())
+ return result;
+
+ d->combinedValue(HeaderName{name}, result);
+ return result;
+}
+
+/*!
+ Returns the number of header entries.
+*/
+qsizetype QHttpHeaders::size() const noexcept
+{
+ if (!d)
+ return 0;
+ return d->headers.size();
+}
+
+/*!
+ Attempts to allocate memory for at least \a size header entries.
+
+ If you know in advance how how many header entries there will
+ be, you may call this function to prevent reallocations
+ and memory fragmentation.
+*/
+void QHttpHeaders::reserve(qsizetype size)
+{
+ d.detach();
+ d->headers.reserve(size);
+}
+
+/*!
+ \fn bool QHttpHeaders::isEmpty() const noexcept
+
+ Returns \c true if the headers have size 0; otherwise returns \c false.
+
+ \sa size()
+*/
+
+/*!
+ Returns a header name corresponding to the provided \a name as a view.
+*/
+QByteArrayView QHttpHeaders::wellKnownHeaderName(WellKnownHeader name) noexcept
+{
+ return headerNames[qToUnderlying(name)];
+}
+
+/*!
+ Returns the header entries as a list of (name, value) pairs.
+ Header names are case-insensitive, and the returned names are lower-cased.
+*/
+QList<std::pair<QByteArray, QByteArray>> QHttpHeaders::toListOfPairs() const
+{
+ QList<std::pair<QByteArray, QByteArray>> list;
+ if (isEmpty())
+ return list;
+ list.reserve(size());
+ for (const auto & h : std::as_const(d->headers))
+ list.append({h.name.asByteArray(), h.value});
+ return list;
+}
+
+/*!
+ Returns the header entries as a map from name to value(s).
+ Header names are case-insensitive, and the returned names are lower-cased.
+*/
+QMultiMap<QByteArray, QByteArray> QHttpHeaders::toMultiMap() const
+{
+ QMultiMap<QByteArray, QByteArray> map;
+ if (isEmpty())
+ return map;
+ for (const auto &h : std::as_const(d->headers))
+ map.insert(h.name.asByteArray(), h.value);
+ return map;
+}
+
+/*!
+ Returns the header entries as a hash from name to value(s).
+ Header names are case-insensitive, and the returned names are lower-cased.
+*/
+QMultiHash<QByteArray, QByteArray> QHttpHeaders::toMultiHash() const
+{
+ QMultiHash<QByteArray, QByteArray> hash;
+ if (isEmpty())
+ return hash;
+ hash.reserve(size());
+ for (const auto &h : std::as_const(d->headers))
+ hash.insert(h.name.asByteArray(), h.value);
+ return hash;
+}
+
+/*!
+ Clears all header entries.
+
+ \sa size()
+*/
+void QHttpHeaders::clear()
+{
+ if (isEmpty())
+ return;
+ d.detach();
+ d->headers.clear();
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/access/qhttpheaders.h b/src/network/access/qhttpheaders.h
new file mode 100644
index 0000000000..260df1421b
--- /dev/null
+++ b/src/network/access/qhttpheaders.h
@@ -0,0 +1,282 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QHTTPHEADERS_H
+#define QHTTPHEADERS_H
+
+#include <QtNetwork/qtnetworkglobal.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qcontainerfwd.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDebug;
+
+class QHttpHeadersPrivate;
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QHttpHeadersPrivate, Q_NETWORK_EXPORT)
+class QHttpHeaders
+{
+ Q_GADGET_EXPORT(Q_NETWORK_EXPORT)
+public:
+ enum class WellKnownHeader {
+ // IANA Permanent status:
+ AIM,
+ Accept,
+ AcceptAdditions,
+ AcceptCH,
+ AcceptDatetime,
+ AcceptEncoding,
+ AcceptFeatures,
+ AcceptLanguage,
+ AcceptPatch,
+ AcceptPost,
+ AcceptRanges,
+ AcceptSignature,
+ AccessControlAllowCredentials,
+ AccessControlAllowHeaders,
+ AccessControlAllowMethods,
+ AccessControlAllowOrigin,
+ AccessControlExposeHeaders,
+ AccessControlMaxAge,
+ AccessControlRequestHeaders,
+ AccessControlRequestMethod,
+ Age,
+ Allow,
+ ALPN,
+ AltSvc,
+ AltUsed,
+ Alternates,
+ ApplyToRedirectRef,
+ AuthenticationControl,
+ AuthenticationInfo,
+ Authorization,
+ CacheControl,
+ CacheStatus,
+ CalManagedID,
+ CalDAVTimezones,
+ CapsuleProtocol,
+ CDNCacheControl,
+ CDNLoop,
+ CertNotAfter,
+ CertNotBefore,
+ ClearSiteData,
+ ClientCert,
+ ClientCertChain,
+ Close,
+ Connection,
+ ContentDigest,
+ ContentDisposition,
+ ContentEncoding,
+ ContentID,
+ ContentLanguage,
+ ContentLength,
+ ContentLocation,
+ ContentRange,
+ ContentSecurityPolicy,
+ ContentSecurityPolicyReportOnly,
+ ContentType,
+ Cookie,
+ CrossOriginEmbedderPolicy,
+ CrossOriginEmbedderPolicyReportOnly,
+ CrossOriginOpenerPolicy,
+ CrossOriginOpenerPolicyReportOnly,
+ CrossOriginResourcePolicy,
+ DASL,
+ Date,
+ DAV,
+ DeltaBase,
+ Depth,
+ Destination,
+ DifferentialID,
+ DPoP,
+ DPoPNonce,
+ EarlyData,
+ ETag,
+ Expect,
+ ExpectCT,
+ Expires,
+ Forwarded,
+ From,
+ Hobareg,
+ Host,
+ If,
+ IfMatch,
+ IfModifiedSince,
+ IfNoneMatch,
+ IfRange,
+ IfScheduleTagMatch,
+ IfUnmodifiedSince,
+ IM,
+ IncludeReferredTokenBindingID,
+ KeepAlive,
+ Label,
+ LastEventID,
+ LastModified,
+ Link,
+ Location,
+ LockToken,
+ MaxForwards,
+ MementoDatetime,
+ Meter,
+ MIMEVersion,
+ Negotiate,
+ NEL,
+ ODataEntityId,
+ ODataIsolation,
+ ODataMaxVersion,
+ ODataVersion,
+ OptionalWWWAuthenticate,
+ OrderingType,
+ Origin,
+ OriginAgentCluster,
+ OSCORE,
+ OSLCCoreVersion,
+ Overwrite,
+ PingFrom,
+ PingTo,
+ Position,
+ Prefer,
+ PreferenceApplied,
+ Priority,
+ ProxyAuthenticate,
+ ProxyAuthenticationInfo,
+ ProxyAuthorization,
+ ProxyStatus,
+ PublicKeyPins,
+ PublicKeyPinsReportOnly,
+ Range,
+ RedirectRef,
+ Referer,
+ Refresh,
+ ReplayNonce,
+ ReprDigest,
+ RetryAfter,
+ ScheduleReply,
+ ScheduleTag,
+ SecPurpose,
+ SecTokenBinding,
+ SecWebSocketAccept,
+ SecWebSocketExtensions,
+ SecWebSocketKey,
+ SecWebSocketProtocol,
+ SecWebSocketVersion,
+ Server,
+ ServerTiming,
+ SetCookie,
+ Signature,
+ SignatureInput,
+ SLUG,
+ SoapAction,
+ StatusURI,
+ StrictTransportSecurity,
+ Sunset,
+ SurrogateCapability,
+ SurrogateControl,
+ TCN,
+ TE,
+ Timeout,
+ Topic,
+ Traceparent,
+ Tracestate,
+ Trailer,
+ TransferEncoding,
+ TTL,
+ Upgrade,
+ Urgency,
+ UserAgent,
+ VariantVary,
+ Vary,
+ Via,
+ WantContentDigest,
+ WantReprDigest,
+ WWWAuthenticate,
+ XContentTypeOptions,
+ XFrameOptions,
+ // IANA Deprecated status:
+ AcceptCharset,
+ CPEPInfo,
+ Pragma,
+ ProtocolInfo,
+ ProtocolQuery,
+ };
+ Q_ENUM(WellKnownHeader)
+
+ Q_NETWORK_EXPORT QHttpHeaders() noexcept;
+ Q_NETWORK_EXPORT ~QHttpHeaders();
+
+ Q_NETWORK_EXPORT QHttpHeaders(const QHttpHeaders &other);
+ QHttpHeaders(QHttpHeaders &&other) noexcept = default;
+ Q_NETWORK_EXPORT QHttpHeaders &operator=(const QHttpHeaders &other);
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QHttpHeaders)
+ void swap(QHttpHeaders &other) noexcept { d.swap(other.d); }
+
+ Q_NETWORK_EXPORT bool append(QAnyStringView name, QAnyStringView value);
+ Q_NETWORK_EXPORT bool append(WellKnownHeader name, QAnyStringView value);
+
+ Q_NETWORK_EXPORT bool insert(qsizetype i, QAnyStringView name, QAnyStringView value);
+ Q_NETWORK_EXPORT bool insert(qsizetype i, WellKnownHeader name, QAnyStringView value);
+
+ Q_NETWORK_EXPORT bool replace(qsizetype i, QAnyStringView name, QAnyStringView newValue);
+ Q_NETWORK_EXPORT bool replace(qsizetype i, WellKnownHeader name, QAnyStringView newValue);
+
+ Q_NETWORK_EXPORT bool replaceOrAppend(QAnyStringView name, QAnyStringView newValue);
+ Q_NETWORK_EXPORT bool replaceOrAppend(WellKnownHeader name, QAnyStringView newValue);
+
+ Q_NETWORK_EXPORT bool contains(QAnyStringView name) const;
+ Q_NETWORK_EXPORT bool contains(WellKnownHeader name) const;
+
+ Q_NETWORK_EXPORT void clear();
+ Q_NETWORK_EXPORT void removeAll(QAnyStringView name);
+ Q_NETWORK_EXPORT void removeAll(WellKnownHeader name);
+ Q_NETWORK_EXPORT void removeAt(qsizetype i);
+
+ Q_NETWORK_EXPORT QByteArrayView value(QAnyStringView name, QByteArrayView defaultValue = {}) const noexcept;
+ Q_NETWORK_EXPORT QByteArrayView value(WellKnownHeader name, QByteArrayView defaultValue = {}) const noexcept;
+
+ Q_NETWORK_EXPORT QList<QByteArray> values(QAnyStringView name) const;
+ Q_NETWORK_EXPORT QList<QByteArray> values(WellKnownHeader name) const;
+
+ Q_NETWORK_EXPORT QByteArrayView valueAt(qsizetype i) const noexcept;
+ Q_NETWORK_EXPORT QLatin1StringView nameAt(qsizetype i) const noexcept;
+
+ Q_NETWORK_EXPORT QByteArray combinedValue(QAnyStringView name) const;
+ Q_NETWORK_EXPORT QByteArray combinedValue(WellKnownHeader name) const;
+
+ Q_NETWORK_EXPORT qsizetype size() const noexcept;
+ Q_NETWORK_EXPORT void reserve(qsizetype size);
+ bool isEmpty() const noexcept { return size() == 0; }
+
+ Q_NETWORK_EXPORT static QByteArrayView wellKnownHeaderName(WellKnownHeader name) noexcept;
+
+ Q_NETWORK_EXPORT static QHttpHeaders
+ fromListOfPairs(const QList<std::pair<QByteArray, QByteArray>> &headers);
+ Q_NETWORK_EXPORT static QHttpHeaders
+ fromMultiMap(const QMultiMap<QByteArray, QByteArray> &headers);
+ Q_NETWORK_EXPORT static QHttpHeaders
+ fromMultiHash(const QMultiHash<QByteArray, QByteArray> &headers);
+
+ Q_NETWORK_EXPORT QList<std::pair<QByteArray, QByteArray>> toListOfPairs() const;
+ Q_NETWORK_EXPORT QMultiMap<QByteArray, QByteArray> toMultiMap() const;
+ Q_NETWORK_EXPORT QMultiHash<QByteArray, QByteArray> toMultiHash() const;
+
+private:
+#ifndef QT_NO_DEBUG_STREAM
+ friend Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QHttpHeaders &headers);
+#endif
+ Q_ALWAYS_INLINE void verify([[maybe_unused]] qsizetype pos = 0,
+ [[maybe_unused]] qsizetype n = 1) const
+ {
+ Q_ASSERT(pos >= 0);
+ Q_ASSERT(pos <= size());
+ Q_ASSERT(n >= 0);
+ Q_ASSERT(n <= size() - pos);
+ }
+ QExplicitlySharedDataPointer<QHttpHeadersPrivate> d;
+};
+
+Q_DECLARE_SHARED(QHttpHeaders)
+
+QT_END_NAMESPACE
+
+#endif // QHTTPHEADERS_H
diff --git a/src/network/access/qhttpheadershelper.cpp b/src/network/access/qhttpheadershelper.cpp
new file mode 100644
index 0000000000..d3cc9e439f
--- /dev/null
+++ b/src/network/access/qhttpheadershelper.cpp
@@ -0,0 +1,25 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qhttpheadershelper_p.h"
+
+#include <QtNetwork/qhttpheaders.h>
+
+QT_BEGIN_NAMESPACE
+
+bool QHttpHeadersHelper::compareStrict(const QHttpHeaders &left, const QHttpHeaders &right)
+{
+ if (left.size() != right.size())
+ return false;
+
+ for (qsizetype i = 0; i < left.size(); ++i) {
+ if (left.nameAt(i) != right.nameAt(i))
+ return false;
+ if (left.valueAt(i) != right.valueAt(i))
+ return false;
+ }
+
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/access/qhttpheadershelper_p.h b/src/network/access/qhttpheadershelper_p.h
new file mode 100644
index 0000000000..d1e38a1a8e
--- /dev/null
+++ b/src/network/access/qhttpheadershelper_p.h
@@ -0,0 +1,30 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QHTTPHEADERSHELPER_H
+#define QHTTPHEADERSHELPER_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/private/qtnetworkglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QHttpHeaders;
+
+namespace QHttpHeadersHelper {
+ Q_NETWORK_EXPORT bool compareStrict(const QHttpHeaders &left, const QHttpHeaders &right);
+};
+
+QT_END_NAMESPACE
+
+#endif // QHTTPHEADERSHELPER_H
diff --git a/src/network/access/qhttpmultipart.cpp b/src/network/access/qhttpmultipart.cpp
index f24c06dda3..2b5f1163c8 100644
--- a/src/network/access/qhttpmultipart.cpp
+++ b/src/network/access/qhttpmultipart.cpp
@@ -386,10 +386,9 @@ void QHttpPartPrivate::checkHeaderCreated() const
{
if (!headerCreated) {
// copied from QHttpNetworkRequestPrivate::header() and adapted
- QList<QPair<QByteArray, QByteArray> > fields = allRawHeaders();
- QList<QPair<QByteArray, QByteArray> >::const_iterator it = fields.constBegin();
- for (; it != fields.constEnd(); ++it)
- header += it->first + ": " + it->second + "\r\n";
+ const auto fields = allRawHeaders();
+ for (const auto &[name, value] : fields)
+ header += name + ": " + value + "\r\n";
header += "\r\n";
headerCreated = true;
}
@@ -512,6 +511,48 @@ qint64 QHttpMultiPartIODevice::writeData(const char *data, qint64 maxSize)
return -1;
}
+#ifndef QT_NO_DEBUG_STREAM
+
+/*!
+ \fn QDebug QHttpPart::operator<<(QDebug debug, const QHttpPart &part)
+
+ Writes the \a part into the \a debug object for debugging purposes.
+ Unless a device is set, the size of the body is shown.
+
+ \sa {Debugging Techniques}
+ \since 6.8
+*/
+
+QDebug operator<<(QDebug debug, const QHttpPart &part)
+{
+ const QDebugStateSaver saver(debug);
+ debug.resetFormat().nospace().noquote();
+
+ debug << "QHttpPart(headers = ["
+ << part.d->cookedHeaders
+ << "], raw headers = ["
+ << part.d->rawHeaders
+ << "],";
+
+ if (part.d->bodyDevice) {
+ debug << " bodydevice = ["
+ << part.d->bodyDevice
+ << ", is open: "
+ << part.d->bodyDevice->isOpen()
+ << "]";
+ } else {
+ debug << " size of body = "
+ << part.d->body.size()
+ << " bytes";
+ }
+
+ debug << ")";
+
+ return debug;
+}
+
+#endif // QT_NO_DEBUG_STREAM
+
QT_END_NAMESPACE
diff --git a/src/network/access/qhttpmultipart.h b/src/network/access/qhttpmultipart.h
index 26e5fafdf2..9732bbd99d 100644
--- a/src/network/access/qhttpmultipart.h
+++ b/src/network/access/qhttpmultipart.h
@@ -19,6 +19,7 @@ QT_BEGIN_NAMESPACE
class QHttpPartPrivate;
class QHttpMultiPart;
+class QDebug;
class Q_NETWORK_EXPORT QHttpPart
{
@@ -45,6 +46,9 @@ private:
QSharedDataPointer<QHttpPartPrivate> d;
friend class QHttpMultiPartIODevice;
+#ifndef QT_NO_DEBUG_STREAM
+ friend Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QHttpPart &httpPart);
+#endif
};
Q_DECLARE_SHARED(QHttpPart)
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index dc9c9f610f..419491a711 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -13,10 +13,13 @@
#include <qauthenticator.h>
#include <qcoreapplication.h>
#include <private/qdecompresshelper_p.h>
+#include <private/qsocketabstraction_p.h>
#include <qbuffer.h>
#include <qpair.h>
#include <qdebug.h>
+#include <qspan.h>
+#include <qvarlengtharray.h>
#ifndef QT_NO_SSL
# include <private/qsslsocket_p.h>
@@ -32,56 +35,35 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-// Note: Only used from auto tests, normal usage is via QHttp1Configuration
-const int QHttpNetworkConnectionPrivate::defaultHttpChannelCount = 6;
-
// The pipeline length. So there will be 4 requests in flight.
const int QHttpNetworkConnectionPrivate::defaultPipelineLength = 3;
// Only re-fill the pipeline if there's defaultRePipelineLength slots free in the pipeline.
// This means that there are 2 requests in flight and 2 slots free that will be re-filled.
const int QHttpNetworkConnectionPrivate::defaultRePipelineLength = 2;
-
-QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &hostName,
- quint16 port, bool encrypt,
- QHttpNetworkConnection::ConnectionType type)
-: state(RunningState),
- networkLayerState(Unknown),
- hostName(hostName), port(port), encrypt(encrypt), delayIpv4(true)
- , activeChannelCount(type == QHttpNetworkConnection::ConnectionTypeHTTP2
- || type == QHttpNetworkConnection::ConnectionTypeHTTP2Direct
- ? 1 : defaultHttpChannelCount)
- , channelCount(defaultHttpChannelCount)
-#ifndef QT_NO_NETWORKPROXY
- , networkProxy(QNetworkProxy::NoProxy)
-#endif
- , preConnectRequests(0)
- , connectionType(type)
+static int getPreferredActiveChannelCount(QHttpNetworkConnection::ConnectionType type,
+ int defaultValue)
{
- // We allocate all 6 channels even if it's HTTP/2 enabled connection:
- // in case the protocol negotiation via NPN/ALPN fails, we will have
- // normally working HTTP/1.1.
- Q_ASSERT(channelCount >= activeChannelCount);
- channels = new QHttpNetworkConnectionChannel[channelCount];
+ return (type == QHttpNetworkConnection::ConnectionTypeHTTP2
+ || type == QHttpNetworkConnection::ConnectionTypeHTTP2Direct)
+ ? 1
+ : defaultValue;
}
-QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(quint16 connectionCount, const QString &hostName,
- quint16 port, bool encrypt,
- QHttpNetworkConnection::ConnectionType type)
-: state(RunningState), networkLayerState(Unknown),
- hostName(hostName), port(port), encrypt(encrypt), delayIpv4(true),
- channelCount(connectionCount)
+QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(
+ quint16 connectionCount, const QString &hostName, quint16 port, bool encrypt,
+ QHttpNetworkConnection::ConnectionType type)
+ : hostName(hostName),
+ port(port),
+ encrypt(encrypt),
+ activeChannelCount(getPreferredActiveChannelCount(type, connectionCount)),
+ channelCount(connectionCount),
+ channels(new QHttpNetworkConnectionChannel[channelCount]),
#ifndef QT_NO_NETWORKPROXY
- , networkProxy(QNetworkProxy::NoProxy)
+ networkProxy(QNetworkProxy::NoProxy),
#endif
- , preConnectRequests(0)
- , connectionType(type)
+ connectionType(type)
{
- channels = new QHttpNetworkConnectionChannel[channelCount];
-
- activeChannelCount = (type == QHttpNetworkConnection::ConnectionTypeHTTP2 ||
- type == QHttpNetworkConnection::ConnectionTypeHTTP2Direct)
- ? 1 : connectionCount;
// We allocate all 6 channels even if it's an HTTP/2-enabled
// connection: in case the protocol negotiation via NPN/ALPN fails,
// we will have normally working HTTP/1.1.
@@ -154,7 +136,7 @@ void QHttpNetworkConnectionPrivate::resumeConnection()
QMetaObject::invokeMethod(this->q_func(), "_q_startNextRequest", Qt::QueuedConnection);
}
-int QHttpNetworkConnectionPrivate::indexOf(QAbstractSocket *socket) const
+int QHttpNetworkConnectionPrivate::indexOf(QIODevice *socket) const
{
for (int i = 0; i < activeChannelCount; ++i)
if (channels[i].socket == socket)
@@ -168,7 +150,7 @@ int QHttpNetworkConnectionPrivate::indexOf(QAbstractSocket *socket) const
// emitted. This function will check the status of the connection channels if we
// have not decided the networkLayerState and will return true if the channel error
// should be emitted by the channel.
-bool QHttpNetworkConnectionPrivate::shouldEmitChannelError(QAbstractSocket *socket)
+bool QHttpNetworkConnectionPrivate::shouldEmitChannelError(QIODevice *socket)
{
Q_Q(QHttpNetworkConnection);
@@ -226,6 +208,17 @@ qint64 QHttpNetworkConnectionPrivate::uncompressedBytesAvailableNextBlock(const
return reply.d_func()->responseData.sizeNextBlock();
}
+static QByteArray makeAcceptLanguage()
+{
+ QString systemLocale = QLocale::system().name();
+ if (systemLocale == "C"_L1)
+ return "en,*"_ba;
+ systemLocale.replace('_'_L1, '-'_L1);
+ if (systemLocale.startsWith("en-"_L1))
+ return (systemLocale + ",*"_L1).toLatin1();
+ return (systemLocale + ",en,*"_L1).toLatin1();
+}
+
void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair)
{
QHttpNetworkRequest &request = messagePair.first;
@@ -276,8 +269,8 @@ void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair)
value = request.headerField("accept-encoding");
if (value.isEmpty()) {
#ifndef QT_NO_COMPRESS
- const QByteArrayList &acceptedEncoding = QDecompressHelper::acceptedEncoding();
- request.setHeaderField("Accept-Encoding", acceptedEncoding.join(", "));
+ const static QByteArray acceptedEncoding = QDecompressHelper::acceptedEncoding().join(", ");
+ request.setHeaderField("Accept-Encoding", acceptedEncoding);
request.d->autoDecompress = true;
#else
// if zlib is not available set this to false always
@@ -290,17 +283,8 @@ void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair)
// not with us, but we work around this by setting
// one always.
value = request.headerField("accept-language");
- if (value.isEmpty()) {
- QString systemLocale = QLocale::system().name().replace(QChar::fromLatin1('_'),QChar::fromLatin1('-'));
- QString acceptLanguage;
- if (systemLocale == "C"_L1)
- acceptLanguage = QString::fromLatin1("en,*");
- else if (systemLocale.startsWith("en-"_L1))
- acceptLanguage = systemLocale + ",*"_L1;
- else
- acceptLanguage = systemLocale + ",en,*"_L1;
- request.setHeaderField("Accept-Language", std::move(acceptLanguage).toLatin1());
- }
+ if (value.isEmpty())
+ request.setHeaderField("Accept-Language", makeAcceptLanguage());
// set the User Agent
value = request.headerField("user-agent");
@@ -313,7 +297,7 @@ void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair)
QByteArray host;
if (add.setAddress(hostName)) {
if (add.protocol() == QAbstractSocket::IPv6Protocol)
- host = '[' + hostName.toLatin1() + ']'; //format the ipv6 in the standard way
+ host = (u'[' + hostName + u']').toLatin1(); //format the ipv6 in the standard way
else
host = hostName.toLatin1();
@@ -336,7 +320,7 @@ void QHttpNetworkConnectionPrivate::prepareRequest(HttpMessagePair &messagePair)
-void QHttpNetworkConnectionPrivate::emitReplyError(QAbstractSocket *socket,
+void QHttpNetworkConnectionPrivate::emitReplyError(QIODevice *socket,
QHttpNetworkReply *reply,
QNetworkReply::NetworkError errorCode)
{
@@ -401,7 +385,7 @@ void QHttpNetworkConnectionPrivate::copyCredentials(int fromChannel, QAuthentica
// handles the authentication for one channel and eventually re-starts the other channels
-bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket *socket, QHttpNetworkReply *reply,
+bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QIODevice *socket, QHttpNetworkReply *reply,
bool isProxy, bool &resend)
{
Q_ASSERT(socket);
@@ -409,7 +393,7 @@ bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket
resend = false;
//create the response header to be used with QAuthenticatorPrivate.
- QList<QPair<QByteArray, QByteArray> > fields = reply->header();
+ const auto headers = reply->header();
// Check that any of the proposed authenticate methods are supported
const QByteArray header = isProxy ? "proxy-authenticate" : "www-authenticate";
@@ -425,14 +409,15 @@ bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket
if (auth->isNull())
auth->detach();
QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(*auth);
- priv->parseHttpResponse(fields, isProxy, reply->url().host());
+ priv->parseHttpResponse(headers, isProxy, reply->url().host());
// Update method in case it changed
if (priv->method == QAuthenticatorPrivate::None)
return false;
if (priv->phase == QAuthenticatorPrivate::Done ||
(priv->phase == QAuthenticatorPrivate::Start
- && priv->method == QAuthenticatorPrivate::Ntlm)) {
+ && (priv->method == QAuthenticatorPrivate::Ntlm
+ || priv->method == QAuthenticatorPrivate::Negotiate))) {
if (priv->phase == QAuthenticatorPrivate::Start)
priv->phase = QAuthenticatorPrivate::Phase1;
@@ -502,7 +487,7 @@ bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket
}
// Used by the HTTP1 code-path
-QUrl QHttpNetworkConnectionPrivate::parseRedirectResponse(QAbstractSocket *socket,
+QUrl QHttpNetworkConnectionPrivate::parseRedirectResponse(QIODevice *socket,
QHttpNetworkReply *reply)
{
ParseRedirectResult result = parseRedirectResponse(reply);
@@ -520,12 +505,9 @@ QHttpNetworkConnectionPrivate::parseRedirectResponse(QHttpNetworkReply *reply)
return {{}, QNetworkReply::NoError};
QUrl redirectUrl;
- const QList<QPair<QByteArray, QByteArray> > fields = reply->header();
- for (const QNetworkReply::RawHeaderPair &header : fields) {
- if (header.first.compare("location", Qt::CaseInsensitive) == 0) {
- redirectUrl = QUrl::fromEncoded(header.second);
- break;
- }
+ const QHttpHeaders fields = reply->header();
+ if (const auto h = fields.values(QHttpHeaders::WellKnownHeader::Location); !h.empty()) {
+ redirectUrl = QUrl::fromEncoded(h.first());
}
// If the location url is invalid/empty, we return ProtocolUnknownError
@@ -569,7 +551,7 @@ QHttpNetworkConnectionPrivate::parseRedirectResponse(QHttpNetworkReply *reply)
return {std::move(redirectUrl), QNetworkReply::NoError};
}
-void QHttpNetworkConnectionPrivate::createAuthorization(QAbstractSocket *socket, QHttpNetworkRequest &request)
+void QHttpNetworkConnectionPrivate::createAuthorization(QIODevice *socket, QHttpNetworkRequest &request)
{
Q_ASSERT(socket);
@@ -705,7 +687,7 @@ void QHttpNetworkConnectionPrivate::requeueRequest(const HttpMessagePair &pair)
QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
}
-bool QHttpNetworkConnectionPrivate::dequeueRequest(QAbstractSocket *socket)
+bool QHttpNetworkConnectionPrivate::dequeueRequest(QIODevice *socket)
{
int i = 0;
if (socket)
@@ -759,7 +741,7 @@ QHttpNetworkReply* QHttpNetworkConnectionPrivate::predictNextRequestsReply() con
}
// this is called from _q_startNextRequest and when a request has been sent down a socket from the channel
-void QHttpNetworkConnectionPrivate::fillPipeline(QAbstractSocket *socket)
+void QHttpNetworkConnectionPrivate::fillPipeline(QIODevice *socket)
{
// return fast if there is nothing to pipeline
if (highPriorityQueue.isEmpty() && lowPriorityQueue.isEmpty())
@@ -787,7 +769,7 @@ void QHttpNetworkConnectionPrivate::fillPipeline(QAbstractSocket *socket)
return;
// check if socket is connected
- if (socket->state() != QAbstractSocket::ConnectedState)
+ if (QSocketAbstraction::socketState(socket) != QAbstractSocket::ConnectedState)
return;
// check for resendCurrent
@@ -881,16 +863,15 @@ bool QHttpNetworkConnectionPrivate::fillPipeline(QList<HttpMessagePair> &queue,
}
-QString QHttpNetworkConnectionPrivate::errorDetail(QNetworkReply::NetworkError errorCode, QAbstractSocket *socket, const QString &extraDetail)
+QString QHttpNetworkConnectionPrivate::errorDetail(QNetworkReply::NetworkError errorCode, QIODevice *socket, const QString &extraDetail)
{
QString errorString;
switch (errorCode) {
- case QNetworkReply::HostNotFoundError:
- if (socket)
- errorString = QCoreApplication::translate("QHttp", "Host %1 not found").arg(socket->peerName());
- else
- errorString = QCoreApplication::translate("QHttp", "Host %1 not found").arg(hostName);
+ case QNetworkReply::HostNotFoundError: {
+ const QString peerName = socket ? QSocketAbstraction::socketPeerName(socket) : hostName;
+ errorString = QCoreApplication::translate("QHttp", "Host %1 not found").arg(peerName);
break;
+ }
case QNetworkReply::ConnectionRefusedError:
errorString = QCoreApplication::translate("QHttp", "Connection refused");
break;
@@ -915,7 +896,7 @@ QString QHttpNetworkConnectionPrivate::errorDetail(QNetworkReply::NetworkError e
case QNetworkReply::SslHandshakeFailedError:
errorString = QCoreApplication::translate("QHttp", "SSL handshake failed");
if (socket)
- errorString += QStringLiteral(": ") + socket->errorString();
+ errorString += ": "_L1 + socket->errorString();
break;
case QNetworkReply::TooManyRedirectsError:
errorString = QCoreApplication::translate("QHttp", "Too many redirects");
@@ -987,19 +968,18 @@ void QHttpNetworkConnectionPrivate::removeReply(QHttpNetworkReply *reply)
return;
}
}
-#ifndef QT_NO_SSL
// is the reply inside the H2 pipeline of this channel already?
- QMultiMap<int, HttpMessagePair>::iterator it = channels[i].h2RequestsToSend.begin();
- QMultiMap<int, HttpMessagePair>::iterator end = channels[i].h2RequestsToSend.end();
- for (; it != end; ++it) {
- if (it.value().second == reply) {
- channels[i].h2RequestsToSend.remove(it.key());
-
- QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
- return;
- }
+ const auto foundReply = [reply](const HttpMessagePair &pair) {
+ return pair.second == reply;
+ };
+ auto &seq = channels[i].h2RequestsToSend;
+ const auto end = seq.cend();
+ auto it = std::find_if(seq.cbegin(), end, foundReply);
+ if (it != end) {
+ seq.erase(it);
+ QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
+ return;
}
-#endif
}
// remove from the high priority queue
if (!highPriorityQueue.isEmpty()) {
@@ -1043,6 +1023,11 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
//resend the necessary ones.
for (int i = 0; i < activeChannelCount; ++i) {
if (channels[i].resendCurrent && (channels[i].state != QHttpNetworkConnectionChannel::ClosingState)) {
+ if (!channels[i].socket
+ || channels[i].socket->state() == QAbstractSocket::UnconnectedState) {
+ if (!channels[i].ensureConnection())
+ continue;
+ }
channels[i].resendCurrent = false;
// if this is not possible, error will be emitted and connection terminated
@@ -1130,7 +1115,7 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
if (neededOpenChannels <= 0)
return;
- QQueue<int> channelsToConnect;
+ QVarLengthArray<int> channelsToConnect;
// use previously used channels first
for (int i = 0; i < activeChannelCount && neededOpenChannels > 0; ++i) {
@@ -1146,7 +1131,7 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
if (!channels[i].reply && !channels[i].isSocketBusy()
&& (channels[i].socket->state() == QAbstractSocket::UnconnectedState)) {
- channelsToConnect.enqueue(i);
+ channelsToConnect.push_back(i);
neededOpenChannels--;
}
}
@@ -1156,12 +1141,14 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest()
if (channels[i].socket)
continue;
- channelsToConnect.enqueue(i);
+ channelsToConnect.push_back(i);
neededOpenChannels--;
}
- while (!channelsToConnect.isEmpty()) {
- const int channel = channelsToConnect.dequeue();
+ auto channelToConnectSpan = QSpan{channelsToConnect};
+ while (!channelToConnectSpan.isEmpty()) {
+ const int channel = channelToConnectSpan.front();
+ channelToConnectSpan = channelToConnectSpan.sliced(1);
if (networkLayerState == IPv4)
channels[channel].networkLayerPreference = QAbstractSocket::IPv4Protocol;
@@ -1265,8 +1252,16 @@ void QHttpNetworkConnectionPrivate::_q_hostLookupFinished(const QHostInfo &info)
networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
QMetaObject::invokeMethod(this->q_func(), "_q_startNextRequest", Qt::QueuedConnection);
} else {
+ auto lookupError = QNetworkReply::HostNotFoundError;
+#ifndef QT_NO_NETWORKPROXY
+ // if the proxy can lookup hostnames, all hostname lookups except for the lookup of the
+ // proxy hostname are delegated to the proxy.
+ auto proxyCapabilities = networkProxy.capabilities() | channels[0].proxy.capabilities();
+ if (proxyCapabilities & QNetworkProxy::HostNameLookupCapability)
+ lookupError = QNetworkReply::ProxyNotFoundError;
+#endif
if (dequeueRequest(channels[0].socket)) {
- emitReplyError(channels[0].socket, channels[0].reply, QNetworkReply::HostNotFoundError);
+ emitReplyError(channels[0].socket, channels[0].reply, lookupError);
networkLayerState = QHttpNetworkConnectionPrivate::Unknown;
} else if (connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2
|| connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
@@ -1274,7 +1269,7 @@ void QHttpNetworkConnectionPrivate::_q_hostLookupFinished(const QHostInfo &info)
// emit error for all replies
QHttpNetworkReply *currentReply = h2Pair.second;
Q_ASSERT(currentReply);
- emitReplyError(channels[0].socket, currentReply, QNetworkReply::HostNotFoundError);
+ emitReplyError(channels[0].socket, currentReply, lookupError);
}
} else {
// We can end up here if a request has been aborted or otherwise failed (e.g. timeout)
@@ -1333,18 +1328,6 @@ void QHttpNetworkConnectionPrivate::_q_connectDelayedChannel()
channels[1].ensureConnection();
}
-QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16 port, bool encrypt,
- QHttpNetworkConnection::ConnectionType connectionType, QObject *parent)
- : QObject(*(new QHttpNetworkConnectionPrivate(hostName, port, encrypt , connectionType)), parent)
-{
- Q_D(QHttpNetworkConnection);
- d->init();
- if (QNetworkConnectionMonitor::isEnabled()) {
- connect(&d->connectionMonitor, &QNetworkConnectionMonitor::reachabilityChanged,
- this, &QHttpNetworkConnection::onlineStateChanged, Qt::QueuedConnection);
- }
-}
-
QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QString &hostName,
quint16 port, bool encrypt, QObject *parent,
QHttpNetworkConnection::ConnectionType connectionType)
@@ -1432,9 +1415,9 @@ QNetworkProxy QHttpNetworkConnection::transparentProxy() const
}
#endif
-QHttpNetworkConnection::ConnectionType QHttpNetworkConnection::connectionType()
+QHttpNetworkConnection::ConnectionType QHttpNetworkConnection::connectionType() const
{
- Q_D(QHttpNetworkConnection);
+ Q_D(const QHttpNetworkConnection);
return d->connectionType;
}
@@ -1469,9 +1452,9 @@ void QHttpNetworkConnection::setSslConfiguration(const QSslConfiguration &config
d->channels[i].setSslConfiguration(config);
}
-std::shared_ptr<QSslContext> QHttpNetworkConnection::sslContext()
+std::shared_ptr<QSslContext> QHttpNetworkConnection::sslContext() const
{
- Q_D(QHttpNetworkConnection);
+ Q_D(const QHttpNetworkConnection);
return d->sslContext;
}
diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h
index c3556f6eff..c2d062fb16 100644
--- a/src/network/access/qhttpnetworkconnection_p.h
+++ b/src/network/access/qhttpnetworkconnection_p.h
@@ -52,7 +52,7 @@ class QSslContext;
#endif // !QT_NO_SSL
class QHttpNetworkConnectionPrivate;
-class Q_AUTOTEST_EXPORT QHttpNetworkConnection : public QObject
+class Q_NETWORK_EXPORT QHttpNetworkConnection : public QObject
{
Q_OBJECT
public:
@@ -63,9 +63,6 @@ public:
ConnectionTypeHTTP2Direct
};
- explicit QHttpNetworkConnection(const QString &hostName, quint16 port = 80, bool encrypt = false,
- ConnectionType connectionType = ConnectionTypeHTTP,
- QObject *parent = nullptr);
QHttpNetworkConnection(quint16 channelCount, const QString &hostName, quint16 port = 80,
bool encrypt = false, QObject *parent = nullptr,
ConnectionType connectionType = ConnectionTypeHTTP);
@@ -92,7 +89,7 @@ public:
QHttpNetworkConnectionChannel *channels() const;
- ConnectionType connectionType();
+ ConnectionType connectionType() const;
void setConnectionType(ConnectionType type);
QHttp2Configuration http2Parameters() const;
@@ -102,7 +99,7 @@ public:
void setSslConfiguration(const QSslConfiguration &config);
void ignoreSslErrors(int channel = -1);
void ignoreSslErrors(const QList<QSslError> &errors, int channel = -1);
- std::shared_ptr<QSslContext> sslContext();
+ std::shared_ptr<QSslContext> sslContext() const;
void setSslContext(std::shared_ptr<QSslContext> context);
#endif
@@ -137,8 +134,10 @@ typedef QPair<QHttpNetworkRequest, QHttpNetworkReply*> HttpMessagePair;
class QHttpNetworkConnectionPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QHttpNetworkConnection)
+ Q_DISABLE_COPY_MOVE(QHttpNetworkConnectionPrivate)
public:
- static const int defaultHttpChannelCount;
+ // Note: Only used from auto tests, normal usage is via QHttp1Configuration
+ static constexpr int defaultHttpChannelCount = 6;
static const int defaultPipelineLength;
static const int defaultRePipelineLength;
@@ -155,32 +154,30 @@ public:
IPv4or6
};
- QHttpNetworkConnectionPrivate(const QString &hostName, quint16 port, bool encrypt,
- QHttpNetworkConnection::ConnectionType type);
- QHttpNetworkConnectionPrivate(quint16 channelCount, const QString &hostName, quint16 port, bool encrypt,
- QHttpNetworkConnection::ConnectionType type);
+ QHttpNetworkConnectionPrivate(quint16 connectionCount, const QString &hostName, quint16 port,
+ bool encrypt, QHttpNetworkConnection::ConnectionType type);
~QHttpNetworkConnectionPrivate();
void init();
void pauseConnection();
void resumeConnection();
- ConnectionState state;
- NetworkLayerPreferenceState networkLayerState;
+ ConnectionState state = RunningState;
+ NetworkLayerPreferenceState networkLayerState = Unknown;
enum { ChunkSize = 4096 };
- int indexOf(QAbstractSocket *socket) const;
+ int indexOf(QIODevice *socket) const;
QHttpNetworkReply *queueRequest(const QHttpNetworkRequest &request);
void requeueRequest(const HttpMessagePair &pair); // e.g. after pipeline broke
void fillHttp2Queue();
- bool dequeueRequest(QAbstractSocket *socket);
+ bool dequeueRequest(QIODevice *socket);
void prepareRequest(HttpMessagePair &request);
void updateChannel(int i, const HttpMessagePair &messagePair);
QHttpNetworkRequest predictNextRequest() const;
QHttpNetworkReply* predictNextRequestsReply() const;
- void fillPipeline(QAbstractSocket *socket);
+ void fillPipeline(QIODevice *socket);
bool fillPipeline(QList<HttpMessagePair> &queue, QHttpNetworkConnectionChannel &channel);
// read more HTTP body after the next event loop spin
@@ -198,9 +195,9 @@ public:
void _q_hostLookupFinished(const QHostInfo &info);
void _q_connectDelayedChannel();
- void createAuthorization(QAbstractSocket *socket, QHttpNetworkRequest &request);
+ void createAuthorization(QIODevice *socket, QHttpNetworkRequest &request);
- QString errorDetail(QNetworkReply::NetworkError errorCode, QAbstractSocket *socket,
+ QString errorDetail(QNetworkReply::NetworkError errorCode, QIODevice *socket,
const QString &extraDetail = QString());
void removeReply(QHttpNetworkReply *reply);
@@ -208,29 +205,29 @@ public:
QString hostName;
quint16 port;
bool encrypt;
- bool delayIpv4;
+ bool delayIpv4 = true;
// Number of channels we are trying to use at the moment:
int activeChannelCount;
// The total number of channels we reserved:
const int channelCount;
QTimer delayedConnectionTimer;
- QHttpNetworkConnectionChannel *channels; // parallel connections to the server
- bool shouldEmitChannelError(QAbstractSocket *socket);
+ QHttpNetworkConnectionChannel * const channels; // parallel connections to the server
+ bool shouldEmitChannelError(QIODevice *socket);
qint64 uncompressedBytesAvailable(const QHttpNetworkReply &reply) const;
qint64 uncompressedBytesAvailableNextBlock(const QHttpNetworkReply &reply) const;
- void emitReplyError(QAbstractSocket *socket, QHttpNetworkReply *reply, QNetworkReply::NetworkError errorCode);
- bool handleAuthenticateChallenge(QAbstractSocket *socket, QHttpNetworkReply *reply, bool isProxy, bool &resend);
+ void emitReplyError(QIODevice *socket, QHttpNetworkReply *reply, QNetworkReply::NetworkError errorCode);
+ bool handleAuthenticateChallenge(QIODevice *socket, QHttpNetworkReply *reply, bool isProxy, bool &resend);
struct ParseRedirectResult {
QUrl redirectUrl;
QNetworkReply::NetworkError errorCode;
};
- ParseRedirectResult parseRedirectResponse(QHttpNetworkReply *reply);
+ static ParseRedirectResult parseRedirectResponse(QHttpNetworkReply *reply);
// Used by the HTTP1 code-path
- QUrl parseRedirectResponse(QAbstractSocket *socket, QHttpNetworkReply *reply);
+ QUrl parseRedirectResponse(QIODevice *socket, QHttpNetworkReply *reply);
#ifndef QT_NO_NETWORKPROXY
QNetworkProxy networkProxy;
@@ -241,7 +238,7 @@ public:
QList<HttpMessagePair> highPriorityQueue;
QList<HttpMessagePair> lowPriorityQueue;
- int preConnectRequests;
+ int preConnectRequests = 0;
QHttpNetworkConnection::ConnectionType connectionType;
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 1e036bdc45..71b880f6f8 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -7,7 +7,6 @@
#include "qhttp2configuration.h"
#include "private/qnoncontiguousbytedevice_p.h"
-#include <qpair.h>
#include <qdebug.h>
#include <private/qhttp2protocolhandler_p.h>
@@ -23,6 +22,7 @@
#include "private/qnetconmonitor_p.h"
#include <memory>
+#include <utility>
QT_BEGIN_NAMESPACE
@@ -91,14 +91,14 @@ void QHttpNetworkConnectionChannel::init()
// After some back and forth in all the last years, this is now a DirectConnection because otherwise
// the state inside the *Socket classes gets messed up, also in conjunction with the socket notifiers
// which behave slightly differently on Windows vs Linux
- QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
- this, SLOT(_q_bytesWritten(qint64)),
+ QObject::connect(socket, &QIODevice::bytesWritten,
+ this, &QHttpNetworkConnectionChannel::_q_bytesWritten,
Qt::DirectConnection);
- QObject::connect(socket, SIGNAL(connected()),
- this, SLOT(_q_connected()),
+ QObject::connect(socket, &QAbstractSocket::connected,
+ this, &QHttpNetworkConnectionChannel::_q_connected,
Qt::DirectConnection);
- QObject::connect(socket, SIGNAL(readyRead()),
- this, SLOT(_q_readyRead()),
+ QObject::connect(socket, &QIODevice::readyRead,
+ this, &QHttpNetworkConnectionChannel::_q_readyRead,
Qt::DirectConnection);
// The disconnected() and error() signals may already come
@@ -108,17 +108,17 @@ void QHttpNetworkConnectionChannel::init()
// but cannot be caught because the user did not have a chance yet
// to connect to QNetworkReply's signals.
qRegisterMetaType<QAbstractSocket::SocketError>();
- QObject::connect(socket, SIGNAL(disconnected()),
- this, SLOT(_q_disconnected()),
+ QObject::connect(socket, &QAbstractSocket::disconnected,
+ this, &QHttpNetworkConnectionChannel::_q_disconnected,
Qt::DirectConnection);
- QObject::connect(socket, SIGNAL(errorOccurred(QAbstractSocket::SocketError)),
- this, SLOT(_q_error(QAbstractSocket::SocketError)),
+ QObject::connect(socket, &QAbstractSocket::errorOccurred,
+ this, &QHttpNetworkConnectionChannel::_q_error,
Qt::DirectConnection);
#ifndef QT_NO_NETWORKPROXY
- QObject::connect(socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
- this, SLOT(_q_proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
+ QObject::connect(socket, &QAbstractSocket::proxyAuthenticationRequired,
+ this, &QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired,
Qt::DirectConnection);
#endif
@@ -126,17 +126,17 @@ void QHttpNetworkConnectionChannel::init()
QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket);
if (sslSocket) {
// won't be a sslSocket if encrypt is false
- QObject::connect(sslSocket, SIGNAL(encrypted()),
- this, SLOT(_q_encrypted()),
+ QObject::connect(sslSocket, &QSslSocket::encrypted,
+ this, &QHttpNetworkConnectionChannel::_q_encrypted,
Qt::DirectConnection);
- QObject::connect(sslSocket, SIGNAL(sslErrors(QList<QSslError>)),
- this, SLOT(_q_sslErrors(QList<QSslError>)),
+ QObject::connect(sslSocket, &QSslSocket::sslErrors,
+ this, &QHttpNetworkConnectionChannel::_q_sslErrors,
Qt::DirectConnection);
- QObject::connect(sslSocket, SIGNAL(preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)),
- this, SLOT(_q_preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator*)),
+ QObject::connect(sslSocket, &QSslSocket::preSharedKeyAuthenticationRequired,
+ this, &QHttpNetworkConnectionChannel::_q_preSharedKeyAuthenticationRequired,
Qt::DirectConnection);
- QObject::connect(sslSocket, SIGNAL(encryptedBytesWritten(qint64)),
- this, SLOT(_q_encryptedBytesWritten(qint64)),
+ QObject::connect(sslSocket, &QSslSocket::encryptedBytesWritten,
+ this, &QHttpNetworkConnectionChannel::_q_encryptedBytesWritten,
Qt::DirectConnection);
if (ignoreAllSslErrors)
@@ -325,8 +325,8 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
QHttpNetworkReply *potentialReply = connection->d_func()->predictNextRequestsReply();
if (potentialReply) {
QMetaObject::invokeMethod(potentialReply, "socketStartedConnecting", Qt::QueuedConnection);
- } else if (h2RequestsToSend.size() > 0) {
- QMetaObject::invokeMethod(h2RequestsToSend.values().at(0).second, "socketStartedConnecting", Qt::QueuedConnection);
+ } else if (!h2RequestsToSend.isEmpty()) {
+ QMetaObject::invokeMethod(std::as_const(h2RequestsToSend).first().second, "socketStartedConnecting", Qt::QueuedConnection);
}
#ifndef QT_NO_NETWORKPROXY
@@ -344,8 +344,8 @@ bool QHttpNetworkConnectionChannel::ensureConnection()
if (connection->connectionType()
== QHttpNetworkConnection::ConnectionTypeHTTP2Direct
|| (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
- && h2RequestsToSend.size() > 0)) {
- value = h2RequestsToSend.first().first.headerField("user-agent");
+ && !h2RequestsToSend.isEmpty())) {
+ value = std::as_const(h2RequestsToSend).first().first.headerField("user-agent");
} else {
value = connection->d_func()->predictNextRequest().headerField("user-agent");
}
@@ -856,6 +856,8 @@ void QHttpNetworkConnectionChannel::_q_connected()
connection->d_func()->networkLayerState = QHttpNetworkConnectionPrivate::IPv6;
}
connection->d_func()->networkLayerDetected(networkLayerPreference);
+ if (connection->d_func()->activeChannelCount > 1 && !connection->d_func()->encrypt)
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
} else {
bool anyProtocol = networkLayerPreference == QAbstractSocket::AnyIPProtocol;
if (((connection->d_func()->networkLayerState == QHttpNetworkConnectionPrivate::IPv4)
@@ -949,6 +951,10 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
break;
case QAbstractSocket::ConnectionRefusedError:
errorCode = QNetworkReply::ConnectionRefusedError;
+#ifndef QT_NO_NETWORKPROXY
+ if (connection->d_func()->networkProxy.type() != QNetworkProxy::NoProxy && !ssl)
+ errorCode = QNetworkReply::ProxyConnectionRefusedError;
+#endif
break;
case QAbstractSocket::RemoteHostClosedError:
// This error for SSL comes twice in a row, first from SSL layer ("The TLS/SSL connection has been closed") then from TCP layer.
@@ -1030,6 +1036,9 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
}
errorCode = QNetworkReply::TimeoutError;
break;
+ case QAbstractSocket::ProxyConnectionRefusedError:
+ errorCode = QNetworkReply::ProxyConnectionRefusedError;
+ break;
case QAbstractSocket::ProxyAuthenticationRequiredError:
errorCode = QNetworkReply::ProxyAuthenticationRequiredError;
break;
@@ -1087,16 +1096,15 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
|| connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
- QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
- for (int a = 0; a < h2Pairs.size(); ++a) {
+ const auto h2RequestsToSendCopy = std::exchange(h2RequestsToSend, {});
+ for (const auto &httpMessagePair : h2RequestsToSendCopy) {
// emit error for all replies
- QHttpNetworkReply *currentReply = h2Pairs.at(a).second;
+ QHttpNetworkReply *currentReply = httpMessagePair.second;
currentReply->d_func()->errorString = errorString;
currentReply->d_func()->httpErrorCode = errorCode;
Q_ASSERT(currentReply);
emit currentReply->finishedWithError(errorCode, errorString);
}
- h2RequestsToSend.clear();
}
// send the next request
@@ -1145,9 +1153,9 @@ void QHttpNetworkConnectionChannel::emitFinishedWithError(QNetworkReply::Network
{
if (reply)
emit reply->finishedWithError(error, QHttpNetworkConnectionChannel::tr(message));
- QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
- for (int a = 0; a < h2Pairs.size(); ++a) {
- QHttpNetworkReply *currentReply = h2Pairs.at(a).second;
+ const auto h2RequestsToSendCopy = h2RequestsToSend;
+ for (const auto &httpMessagePair : h2RequestsToSendCopy) {
+ QHttpNetworkReply *currentReply = httpMessagePair.second;
Q_ASSERT(currentReply);
emit currentReply->finishedWithError(error, QHttpNetworkConnectionChannel::tr(message));
}
@@ -1228,14 +1236,12 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2 ||
connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
- if (h2RequestsToSend.size() > 0) {
+ if (!h2RequestsToSend.isEmpty()) {
// Similar to HTTP/1.1 counterpart below:
- const auto &h2Pairs = h2RequestsToSend.values(); // (request, reply)
- const auto &pair = h2Pairs.first();
+ const auto &pair = std::as_const(h2RequestsToSend).first();
emit pair.second->encrypted();
// In case our peer has sent us its settings (window size, max concurrent streams etc.)
// let's give _q_receiveReply a chance to read them first ('invokeMethod', QueuedConnection).
- QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
}
} else { // HTTP
if (!reply)
@@ -1248,14 +1254,14 @@ void QHttpNetworkConnectionChannel::_q_encrypted()
if (reply)
sendRequestDelayed();
}
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
}
void QHttpNetworkConnectionChannel::requeueHttp2Requests()
{
- QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
- for (int a = 0; a < h2Pairs.size(); ++a)
- connection->d_func()->requeueRequest(h2Pairs.at(a));
- h2RequestsToSend.clear();
+ const auto h2RequestsToSendCopy = std::exchange(h2RequestsToSend, {});
+ for (const auto &httpMessagePair : h2RequestsToSendCopy)
+ connection->d_func()->requeueRequest(httpMessagePair);
}
void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
@@ -1274,10 +1280,10 @@ void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
}
#ifndef QT_NO_SSL
else { // HTTP/2
- QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
- for (int a = 0; a < h2Pairs.size(); ++a) {
+ const auto h2RequestsToSendCopy = h2RequestsToSend;
+ for (const auto &httpMessagePair : h2RequestsToSendCopy) {
// emit SSL errors for all replies
- QHttpNetworkReply *currentReply = h2Pairs.at(a).second;
+ QHttpNetworkReply *currentReply = httpMessagePair.second;
Q_ASSERT(currentReply);
emit currentReply->sslErrors(errors);
}
@@ -1297,10 +1303,10 @@ void QHttpNetworkConnectionChannel::_q_preSharedKeyAuthenticationRequired(QSslPr
if (reply)
emit reply->preSharedKeyAuthenticationRequired(authenticator);
} else {
- QList<HttpMessagePair> h2Pairs = h2RequestsToSend.values();
- for (int a = 0; a < h2Pairs.size(); ++a) {
+ const auto h2RequestsToSendCopy = h2RequestsToSend;
+ for (const auto &httpMessagePair : h2RequestsToSendCopy) {
// emit SSL errors for all replies
- QHttpNetworkReply *currentReply = h2Pairs.at(a).second;
+ QHttpNetworkReply *currentReply = httpMessagePair.second;
Q_ASSERT(currentReply);
emit currentReply->preSharedKeyAuthenticationRequired(authenticator);
}
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
index 0772a4452b..c42290feca 100644
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
@@ -40,6 +40,7 @@
# include <QtNetwork/qtcpsocket.h>
#endif
+#include <QtCore/qpointer.h>
#include <QtCore/qscopedpointer.h>
#include <memory>
diff --git a/src/network/access/qhttpnetworkheader.cpp b/src/network/access/qhttpnetworkheader.cpp
index e0a964d253..7f9c94dc9c 100644
--- a/src/network/access/qhttpnetworkheader.cpp
+++ b/src/network/access/qhttpnetworkheader.cpp
@@ -29,7 +29,7 @@ void QHttpNetworkHeaderPrivate::setContentLength(qint64 length)
setHeaderField("Content-Length", QByteArray::number(length));
}
-QByteArray QHttpNetworkHeaderPrivate::headerField(const QByteArray &name, const QByteArray &defaultValue) const
+QByteArray QHttpNetworkHeaderPrivate::headerField(QByteArrayView name, const QByteArray &defaultValue) const
{
QList<QByteArray> allValues = headerFieldValues(name);
if (allValues.isEmpty())
@@ -38,7 +38,7 @@ QByteArray QHttpNetworkHeaderPrivate::headerField(const QByteArray &name, const
return allValues.join(", ");
}
-QList<QByteArray> QHttpNetworkHeaderPrivate::headerFieldValues(const QByteArray &name) const
+QList<QByteArray> QHttpNetworkHeaderPrivate::headerFieldValues(QByteArrayView name) const
{
return parser.headerFieldValues(name);
}
@@ -53,7 +53,7 @@ void QHttpNetworkHeaderPrivate::prependHeaderField(const QByteArray &name, const
parser.prependHeaderField(name, data);
}
-QList<QPair<QByteArray, QByteArray> > QHttpNetworkHeaderPrivate::headers() const
+QHttpHeaders QHttpNetworkHeaderPrivate::headers() const
{
return parser.headers();
}
diff --git a/src/network/access/qhttpnetworkheader_p.h b/src/network/access/qhttpnetworkheader_p.h
index fc5d388ae5..afbc6cb6fe 100644
--- a/src/network/access/qhttpnetworkheader_p.h
+++ b/src/network/access/qhttpnetworkheader_p.h
@@ -17,6 +17,7 @@
#include <QtNetwork/private/qtnetworkglobal_p.h>
#include <QtNetwork/private/qhttpheaderparser_p.h>
+#include <QtNetwork/qhttpheaders.h>
#include <qshareddata.h>
#include <qurl.h>
@@ -40,8 +41,8 @@ public:
virtual qint64 contentLength() const = 0;
virtual void setContentLength(qint64 length) = 0;
- virtual QList<QPair<QByteArray, QByteArray> > header() const = 0;
- virtual QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue = QByteArray()) const = 0;
+ virtual QHttpHeaders header() const = 0;
+ virtual QByteArray headerField(QByteArrayView name, const QByteArray &defaultValue = QByteArray()) const = 0;
virtual void setHeaderField(const QByteArray &name, const QByteArray &data) = 0;
};
@@ -56,12 +57,12 @@ public:
qint64 contentLength() const;
void setContentLength(qint64 length);
- QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue = QByteArray()) const;
- QList<QByteArray> headerFieldValues(const QByteArray &name) const;
+ QByteArray headerField(QByteArrayView name, const QByteArray &defaultValue = QByteArray()) const;
+ QList<QByteArray> headerFieldValues(QByteArrayView name) const;
void setHeaderField(const QByteArray &name, const QByteArray &data);
void prependHeaderField(const QByteArray &name, const QByteArray &data);
void clearHeaders();
- QList<QPair<QByteArray, QByteArray> > headers() const;
+ QHttpHeaders headers() const;
bool operator==(const QHttpNetworkHeaderPrivate &other) const;
};
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
index 0d69dec980..5711c96b18 100644
--- a/src/network/access/qhttpnetworkreply.cpp
+++ b/src/network/access/qhttpnetworkreply.cpp
@@ -67,12 +67,12 @@ void QHttpNetworkReply::setContentLength(qint64 length)
d->setContentLength(length);
}
-QList<QPair<QByteArray, QByteArray> > QHttpNetworkReply::header() const
+QHttpHeaders QHttpNetworkReply::header() const
{
return d_func()->parser.headers();
}
-QByteArray QHttpNetworkReply::headerField(const QByteArray &name, const QByteArray &defaultValue) const
+QByteArray QHttpNetworkReply::headerField(QByteArrayView name, const QByteArray &defaultValue) const
{
return d_func()->headerField(name, defaultValue);
}
@@ -89,7 +89,7 @@ void QHttpNetworkReply::appendHeaderField(const QByteArray &name, const QByteArr
d->appendHeaderField(name, data);
}
-void QHttpNetworkReply::parseHeader(const QByteArray &header)
+void QHttpNetworkReply::parseHeader(QByteArrayView header)
{
Q_D(QHttpNetworkReply);
d->parseHeader(header);
@@ -368,7 +368,7 @@ void QHttpNetworkReplyPrivate::removeAutoDecompressHeader()
{
// The header "Content-Encoding = gzip" is retained.
// Content-Length is removed since the actual one sent by the server is for compressed data
- QByteArray name("content-length");
+ constexpr auto name = QByteArrayView("content-length");
QByteArray contentLength = parser.firstHeaderField(name);
bool parseOk = false;
qint64 value = contentLength.toLongLong(&parseOk);
@@ -378,23 +378,7 @@ void QHttpNetworkReplyPrivate::removeAutoDecompressHeader()
}
}
-bool QHttpNetworkReplyPrivate::findChallenge(bool forProxy, QByteArray &challenge) const
-{
- challenge.clear();
- // find out the type of authentication protocol requested.
- QByteArray header = forProxy ? "proxy-authenticate" : "www-authenticate";
- // pick the best protocol (has to match parsing in QAuthenticatorPrivate)
- QList<QByteArray> challenges = headerFieldValues(header);
- for (int i = 0; i<challenges.size(); i++) {
- QByteArray line = challenges.at(i);
- // todo use qstrincmp
- if (!line.toLower().startsWith("negotiate"))
- challenge = line;
- }
- return !challenge.isEmpty();
-}
-
-qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket)
+qint64 QHttpNetworkReplyPrivate::readStatus(QIODevice *socket)
{
if (fragment.isEmpty()) {
// reserve bytes for the status line. This is better than always append() which reallocs the byte array
@@ -443,12 +427,12 @@ qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket)
return bytes;
}
-bool QHttpNetworkReplyPrivate::parseStatus(const QByteArray &status)
+bool QHttpNetworkReplyPrivate::parseStatus(QByteArrayView status)
{
return parser.parseStatus(status);
}
-qint64 QHttpNetworkReplyPrivate::readHeader(QAbstractSocket *socket)
+qint64 QHttpNetworkReplyPrivate::readHeader(QIODevice *socket)
{
if (fragment.isEmpty()) {
// according to http://dev.opera.com/articles/view/mama-http-headers/ the average size of the header
@@ -510,7 +494,7 @@ qint64 QHttpNetworkReplyPrivate::readHeader(QAbstractSocket *socket)
return bytes;
}
-void QHttpNetworkReplyPrivate::parseHeader(const QByteArray &header)
+void QHttpNetworkReplyPrivate::parseHeader(QByteArrayView header)
{
parser.parseHeaders(header);
}
@@ -532,7 +516,7 @@ bool QHttpNetworkReplyPrivate::isConnectionCloseEnabled()
// note this function can only be used for non-chunked, non-compressed with
// known content length
-qint64 QHttpNetworkReplyPrivate::readBodyVeryFast(QAbstractSocket *socket, char *b)
+qint64 QHttpNetworkReplyPrivate::readBodyVeryFast(QIODevice *socket, char *b)
{
// This first read is to flush the buffer inside the socket
qint64 haveRead = 0;
@@ -551,7 +535,7 @@ qint64 QHttpNetworkReplyPrivate::readBodyVeryFast(QAbstractSocket *socket, char
// note this function can only be used for non-chunked, non-compressed with
// known content length
-qint64 QHttpNetworkReplyPrivate::readBodyFast(QAbstractSocket *socket, QByteDataBuffer *rb)
+qint64 QHttpNetworkReplyPrivate::readBodyFast(QIODevice *socket, QByteDataBuffer *rb)
{
qint64 toBeRead = qMin(socket->bytesAvailable(), bodyLength - contentRead);
@@ -581,7 +565,7 @@ qint64 QHttpNetworkReplyPrivate::readBodyFast(QAbstractSocket *socket, QByteData
}
-qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QByteDataBuffer *out)
+qint64 QHttpNetworkReplyPrivate::readBody(QIODevice *socket, QByteDataBuffer *out)
{
qint64 bytes = 0;
@@ -601,7 +585,7 @@ qint64 QHttpNetworkReplyPrivate::readBody(QAbstractSocket *socket, QByteDataBuff
return bytes;
}
-qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QAbstractSocket *socket, QByteDataBuffer *out, qint64 size)
+qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QIODevice *socket, QByteDataBuffer *out, qint64 size)
{
// FIXME get rid of this function and just use readBodyFast and give it socket->bytesAvailable()
qint64 bytes = 0;
@@ -634,7 +618,7 @@ qint64 QHttpNetworkReplyPrivate::readReplyBodyRaw(QAbstractSocket *socket, QByte
}
-qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QAbstractSocket *socket, QByteDataBuffer *out)
+qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QIODevice *socket, QByteDataBuffer *out)
{
qint64 bytes = 0;
while (socket->bytesAvailable()) {
@@ -696,7 +680,7 @@ qint64 QHttpNetworkReplyPrivate::readReplyBodyChunked(QAbstractSocket *socket, Q
return bytes;
}
-qint64 QHttpNetworkReplyPrivate::getChunkSize(QAbstractSocket *socket, qint64 *chunkSize)
+qint64 QHttpNetworkReplyPrivate::getChunkSize(QIODevice *socket, qint64 *chunkSize)
{
qint64 bytes = 0;
char crlf[2];
@@ -717,8 +701,8 @@ qint64 QHttpNetworkReplyPrivate::getChunkSize(QAbstractSocket *socket, qint64 *c
bytes += socket->read(crlf, 1); // read the \n
bool ok = false;
// ignore the chunk-extension
- fragment = fragment.mid(0, fragment.indexOf(';')).trimmed();
- *chunkSize = fragment.toLong(&ok, 16);
+ const auto fragmentView = QByteArrayView(fragment).mid(0, fragment.indexOf(';')).trimmed();
+ *chunkSize = fragmentView.toLong(&ok, 16);
fragment.clear();
break; // size done
} else {
diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h
index ed76fde1d6..caec82bd7e 100644
--- a/src/network/access/qhttpnetworkreply_p.h
+++ b/src/network/access/qhttpnetworkreply_p.h
@@ -41,6 +41,9 @@ Q_MOC_INCLUDE(<QtNetwork/QNetworkProxy>)
Q_MOC_INCLUDE(<QtNetwork/QAuthenticator>)
#include <private/qdecompresshelper_p.h>
+#include <QtNetwork/qhttpheaders.h>
+
+#include <QtCore/qpointer.h>
QT_REQUIRE_CONFIG(http);
@@ -51,7 +54,7 @@ class QHttpNetworkConnectionChannel;
class QHttpNetworkRequest;
class QHttpNetworkConnectionPrivate;
class QHttpNetworkReplyPrivate;
-class Q_AUTOTEST_EXPORT QHttpNetworkReply : public QObject, public QHttpNetworkHeader
+class Q_NETWORK_EXPORT QHttpNetworkReply : public QObject, public QHttpNetworkHeader
{
Q_OBJECT
public:
@@ -70,11 +73,11 @@ public:
qint64 contentLength() const override;
void setContentLength(qint64 length) override;
- QList<QPair<QByteArray, QByteArray> > header() const override;
- QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue = QByteArray()) const override;
+ QHttpHeaders header() const override;
+ QByteArray headerField(QByteArrayView name, const QByteArray &defaultValue = QByteArray()) const override;
void setHeaderField(const QByteArray &name, const QByteArray &data) override;
void appendHeaderField(const QByteArray &name, const QByteArray &data);
- void parseHeader(const QByteArray &header); // used for testing
+ void parseHeader(QByteArrayView header); // used for testing
QHttpNetworkRequest request() const;
void setRequest(const QHttpNetworkRequest &request);
@@ -169,21 +172,20 @@ class Q_AUTOTEST_EXPORT QHttpNetworkReplyPrivate : public QObjectPrivate, public
public:
QHttpNetworkReplyPrivate(const QUrl &newUrl = QUrl());
~QHttpNetworkReplyPrivate();
- qint64 readStatus(QAbstractSocket *socket);
- bool parseStatus(const QByteArray &status);
- qint64 readHeader(QAbstractSocket *socket);
- void parseHeader(const QByteArray &header);
+ qint64 readStatus(QIODevice *socket);
+ bool parseStatus(QByteArrayView status);
+ qint64 readHeader(QIODevice *socket);
+ void parseHeader(QByteArrayView header);
void appendHeaderField(const QByteArray &name, const QByteArray &data);
- qint64 readBody(QAbstractSocket *socket, QByteDataBuffer *out);
- qint64 readBodyVeryFast(QAbstractSocket *socket, char *b);
- qint64 readBodyFast(QAbstractSocket *socket, QByteDataBuffer *rb);
- bool findChallenge(bool forProxy, QByteArray &challenge) const;
+ qint64 readBody(QIODevice *socket, QByteDataBuffer *out);
+ qint64 readBodyVeryFast(QIODevice *socket, char *b);
+ qint64 readBodyFast(QIODevice *socket, QByteDataBuffer *rb);
void clear();
void clearHttpLayerInformation();
- qint64 readReplyBodyRaw(QAbstractSocket *in, QByteDataBuffer *out, qint64 size);
- qint64 readReplyBodyChunked(QAbstractSocket *in, QByteDataBuffer *out);
- qint64 getChunkSize(QAbstractSocket *in, qint64 *chunkSize);
+ qint64 readReplyBodyRaw(QIODevice *in, QByteDataBuffer *out, qint64 size);
+ qint64 readReplyBodyChunked(QIODevice *in, QByteDataBuffer *out);
+ qint64 getChunkSize(QIODevice *in, qint64 *chunkSize);
bool isRedirecting() const;
bool shouldEmitSignals();
diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp
index d5e529f6b9..7a4ffb1684 100644
--- a/src/network/access/qhttpnetworkrequest.cpp
+++ b/src/network/access/qhttpnetworkrequest.cpp
@@ -112,9 +112,9 @@ QByteArray QHttpNetworkRequest::uri(bool throughProxy) const
QByteArray QHttpNetworkRequestPrivate::header(const QHttpNetworkRequest &request, bool throughProxy)
{
- QList<QPair<QByteArray, QByteArray> > fields = request.header();
+ const QHttpHeaders headers = request.header();
QByteArray ba;
- ba.reserve(40 + fields.size()*25); // very rough lower bound estimation
+ ba.reserve(40 + headers.size() * 25); // very rough lower bound estimation
ba += request.methodName();
ba += ' ';
@@ -126,12 +126,10 @@ QByteArray QHttpNetworkRequestPrivate::header(const QHttpNetworkRequest &request
ba += QByteArray::number(request.minorVersion());
ba += "\r\n";
- QList<QPair<QByteArray, QByteArray> >::const_iterator it = fields.constBegin();
- QList<QPair<QByteArray, QByteArray> >::const_iterator endIt = fields.constEnd();
- for (; it != endIt; ++it) {
- ba += it->first;
+ for (qsizetype i = 0; i < headers.size(); ++i) {
+ ba += headers.nameAt(i);
ba += ": ";
- ba += it->second;
+ ba += headers.valueAt(i);
ba += "\r\n";
}
if (request.d->operation == QHttpNetworkRequest::Post) {
@@ -237,12 +235,12 @@ void QHttpNetworkRequest::setContentLength(qint64 length)
d->setContentLength(length);
}
-QList<QPair<QByteArray, QByteArray> > QHttpNetworkRequest::header() const
+QHttpHeaders QHttpNetworkRequest::header() const
{
return d->parser.headers();
}
-QByteArray QHttpNetworkRequest::headerField(const QByteArray &name, const QByteArray &defaultValue) const
+QByteArray QHttpNetworkRequest::headerField(QByteArrayView name, const QByteArray &defaultValue) const
{
return d->headerField(name, defaultValue);
}
diff --git a/src/network/access/qhttpnetworkrequest_p.h b/src/network/access/qhttpnetworkrequest_p.h
index e2014c4221..131885f6d2 100644
--- a/src/network/access/qhttpnetworkrequest_p.h
+++ b/src/network/access/qhttpnetworkrequest_p.h
@@ -65,8 +65,8 @@ public:
qint64 contentLength() const override;
void setContentLength(qint64 length) override;
- QList<QPair<QByteArray, QByteArray> > header() const override;
- QByteArray headerField(const QByteArray &name, const QByteArray &defaultValue = QByteArray()) const override;
+ QHttpHeaders header() const override;
+ QByteArray headerField(QByteArrayView name, const QByteArray &defaultValue = QByteArray()) const override;
void setHeaderField(const QByteArray &name, const QByteArray &data) override;
void prependHeaderField(const QByteArray &name, const QByteArray &data);
void clearHeaders();
diff --git a/src/network/access/qhttpprotocolhandler.cpp b/src/network/access/qhttpprotocolhandler.cpp
index b2576a85e6..fb584eb9cc 100644
--- a/src/network/access/qhttpprotocolhandler.cpp
+++ b/src/network/access/qhttpprotocolhandler.cpp
@@ -5,6 +5,7 @@
#include <private/qhttpprotocolhandler_p.h>
#include <private/qnoncontiguousbytedevice_p.h>
#include <private/qhttpnetworkconnectionchannel_p.h>
+#include <private/qsocketabstraction_p.h>
QT_BEGIN_NAMESPACE
@@ -34,10 +35,8 @@ void QHttpProtocolHandler::_q_receiveReply()
return;
}
- QAbstractSocket::SocketState socketState = m_socket->state();
-
// connection might be closed to signal the end of data
- if (socketState == QAbstractSocket::UnconnectedState) {
+ if (QSocketAbstraction::socketState(m_socket) == QAbstractSocket::UnconnectedState) {
if (m_socket->bytesAvailable() <= 0) {
if (m_reply->d_func()->state == QHttpNetworkReplyPrivate::ReadingDataState) {
// finish this reply. this case happens when the server did not send a content length
@@ -93,7 +92,8 @@ void QHttpProtocolHandler::_q_receiveReply()
} else {
replyPrivate->autoDecompress = false;
}
- if (m_reply->statusCode() == 100) {
+ const int statusCode = m_reply->statusCode();
+ if (statusCode == 100 || (102 <= statusCode && statusCode <= 199)) {
replyPrivate->clearHttpLayerInformation();
replyPrivate->state = QHttpNetworkReplyPrivate::ReadingStatusState;
break; // ignore
@@ -114,7 +114,7 @@ void QHttpProtocolHandler::_q_receiveReply()
}
case QHttpNetworkReplyPrivate::ReadingDataState: {
QHttpNetworkReplyPrivate *replyPrivate = m_reply->d_func();
- if (m_socket->state() == QAbstractSocket::ConnectedState &&
+ if (QSocketAbstraction::socketState(m_socket) == QAbstractSocket::ConnectedState &&
replyPrivate->downstreamLimited && !replyPrivate->responseData.isEmpty() && replyPrivate->shouldEmitSignals()) {
// (only do the following when still connected, not when we have already been disconnected and there is still data)
// We already have some HTTP body data. We don't read more from the socket until
@@ -192,7 +192,8 @@ void QHttpProtocolHandler::_q_receiveReply()
void QHttpProtocolHandler::_q_readyRead()
{
- if (m_socket->state() == QAbstractSocket::ConnectedState && m_socket->bytesAvailable() == 0) {
+ if (QSocketAbstraction::socketState(m_socket) == QAbstractSocket::ConnectedState
+ && m_socket->bytesAvailable() == 0) {
// We got a readyRead but no bytes are available..
// This happens for the Unbuffered QTcpSocket
// Also check if socket is in ConnectedState since
@@ -200,7 +201,7 @@ void QHttpProtocolHandler::_q_readyRead()
char c;
qint64 ret = m_socket->peek(&c, 1);
if (ret < 0) {
- m_channel->_q_error(m_socket->error());
+ m_channel->_q_error(QSocketAbstraction::socketError(m_socket));
// We still need to handle the reply so it emits its signals etc.
if (m_reply)
_q_receiveReply();
@@ -238,8 +239,7 @@ bool QHttpProtocolHandler::sendRequest()
// _q_connected or _q_encrypted
return false;
}
- QString scheme = m_channel->request.url().scheme();
- if (scheme == "preconnect-http"_L1 || scheme == "preconnect-https"_L1) {
+ if (m_channel->request.isPreConnect()) {
m_channel->state = QHttpNetworkConnectionChannel::IdleState;
m_reply->d_func()->state = QHttpNetworkReplyPrivate::AllDoneState;
m_channel->allDone();
diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp
index c5c35d522a..b0ae0dcf44 100644
--- a/src/network/access/qhttpthreaddelegate.cpp
+++ b/src/network/access/qhttpthreaddelegate.cpp
@@ -567,11 +567,6 @@ void QHttpThreadDelegate::synchronousFinishedWithErrorSlot(QNetworkReply::Networ
httpReply = nullptr;
}
-static void downloadBufferDeleter(char *ptr)
-{
- delete[] ptr;
-}
-
void QHttpThreadDelegate::headerChangedSlot()
{
if (!httpReply)
@@ -589,14 +584,11 @@ void QHttpThreadDelegate::headerChangedSlot()
// Is using a zerocopy buffer allowed by user and possible with this reply?
if (httpReply->supportsUserProvidedDownloadBuffer()
&& (downloadBufferMaximumSize > 0) && (httpReply->contentLength() <= downloadBufferMaximumSize)) {
- QT_TRY {
- char *buf = new char[httpReply->contentLength()]; // throws if allocation fails
- if (buf) {
- downloadBuffer = QSharedPointer<char>(buf, downloadBufferDeleter);
- httpReply->setUserProvidedDownloadBuffer(buf);
- }
- } QT_CATCH(const std::bad_alloc &) {
- // in out of memory situations, don't use downloadbuffer.
+ char *buf = new (std::nothrow) char[httpReply->contentLength()];
+ // in out of memory situations, don't use downloadBuffer.
+ if (buf) {
+ downloadBuffer = QSharedPointer<char>(buf, [](auto p) { delete[] p; });
+ httpReply->setUserProvidedDownloadBuffer(buf);
}
}
diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h
index c9202b61c4..38e9fb4d78 100644
--- a/src/network/access/qhttpthreaddelegate_p.h
+++ b/src/network/access/qhttpthreaddelegate_p.h
@@ -33,6 +33,7 @@
#include "private/qnoncontiguousbytedevice_p.h"
#include "qnetworkaccessauthenticationmanager_p.h"
#include <QtNetwork/private/http2protocol_p.h>
+#include <QtNetwork/qhttpheaders.h>
QT_REQUIRE_CONFIG(http);
@@ -74,7 +75,7 @@ public:
// outgoing, Retrieved in the synchronous HTTP case
QByteArray synchronousDownloadData;
- QList<QPair<QByteArray,QByteArray> > incomingHeaders;
+ QHttpHeaders incomingHeaders;
int incomingStatusCode;
QString incomingReasonPhrase;
bool isPipeliningUsed;
@@ -112,7 +113,7 @@ signals:
#endif
void socketStartedConnecting();
void requestSent();
- void downloadMetaData(const QList<QPair<QByteArray,QByteArray> > &, int, const QString &, bool,
+ void downloadMetaData(const QHttpHeaders &, int, const QString &, bool,
QSharedPointer<char>, qint64, qint64, bool, bool);
void downloadProgress(qint64, qint64);
void downloadData(const QByteArray &);
@@ -164,22 +165,18 @@ class QNonContiguousByteDeviceThreadForwardImpl : public QNonContiguousByteDevic
{
Q_OBJECT
protected:
- bool wantDataPending;
- qint64 m_amount;
- char *m_data;
+ bool wantDataPending = false;
+ qint64 m_amount = 0;
+ char *m_data = nullptr;
QByteArray m_dataArray;
- bool m_atEnd;
- qint64 m_size;
- qint64 m_pos; // to match calls of haveDataSlot with the expected position
+ bool m_atEnd = false;
+ qint64 m_size = 0;
+ qint64 m_pos = 0; // to match calls of haveDataSlot with the expected position
public:
QNonContiguousByteDeviceThreadForwardImpl(bool aE, qint64 s)
: QNonContiguousByteDevice(),
- wantDataPending(false),
- m_amount(0),
- m_data(nullptr),
m_atEnd(aE),
- m_size(s),
- m_pos(0)
+ m_size(s)
{
}
@@ -252,6 +249,7 @@ public:
if (b) {
// the reset succeeded, we're at pos 0 again
m_pos = 0;
+ m_atEnd = false;
// the HTTP code will anyway abort the request if !b.
}
return b;
diff --git a/src/network/access/qnetworkaccesscache.cpp b/src/network/access/qnetworkaccesscache.cpp
index 9a1a3d3806..2bc0e8fb70 100644
--- a/src/network/access/qnetworkaccesscache.cpp
+++ b/src/network/access/qnetworkaccesscache.cpp
@@ -14,9 +14,6 @@
QT_BEGIN_NAMESPACE
-QT_IMPL_METATYPE_EXTERN_TAGGED(QNetworkAccessCache::CacheableObject*,
- QNetworkAccessCache__CacheableObject_ptr)
-
enum ExpiryTimeEnum {
ExpiryTime = 120
};
diff --git a/src/network/access/qnetworkaccesscache_p.h b/src/network/access/qnetworkaccesscache_p.h
index d0c032de6f..3be7967ca1 100644
--- a/src/network/access/qnetworkaccesscache_p.h
+++ b/src/network/access/qnetworkaccesscache_p.h
@@ -87,7 +87,4 @@ private:
QT_END_NAMESPACE
-QT_DECL_METATYPE_EXTERN_TAGGED(QNetworkAccessCache::CacheableObject*,
- QNetworkAccessCache__CacheableObject_ptr, /* not exported */)
-
#endif
diff --git a/src/network/access/qnetworkaccesscachebackend.cpp b/src/network/access/qnetworkaccesscachebackend.cpp
index 99bef10488..fd8174c143 100644
--- a/src/network/access/qnetworkaccesscachebackend.cpp
+++ b/src/network/access/qnetworkaccesscachebackend.cpp
@@ -12,6 +12,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QNetworkAccessCacheBackend::QNetworkAccessCacheBackend()
: QNetworkAccessBackend(QNetworkAccessBackend::TargetType::Local)
{
@@ -51,10 +53,10 @@ bool QNetworkAccessCacheBackend::sendCacheContents()
// set the raw headers
const QNetworkCacheMetaData::RawHeaderList rawHeaders = item.rawHeaders();
for (const auto &header : rawHeaders) {
- if (header.first.toLower() == "cache-control") {
- const QByteArray cacheControlValue = header.second.toLower();
- if (cacheControlValue.contains("must-revalidate")
- || cacheControlValue.contains("no-cache")) {
+ if (header.first.compare("cache-control", Qt::CaseInsensitive) == 0) {
+ const QLatin1StringView cacheControlValue(header.second);
+ if (cacheControlValue.contains("must-revalidate"_L1, Qt::CaseInsensitive)
+ || cacheControlValue.contains("no-cache"_L1, Qt::CaseInsensitive)) {
return false;
}
}
diff --git a/src/network/access/qnetworkaccessdebugpipebackend.cpp b/src/network/access/qnetworkaccessdebugpipebackend.cpp
index 2df14289a4..4b12f9fe31 100644
--- a/src/network/access/qnetworkaccessdebugpipebackend.cpp
+++ b/src/network/access/qnetworkaccessdebugpipebackend.cpp
@@ -184,7 +184,7 @@ void QNetworkAccessDebugPipeBackend::possiblyFinish()
void QNetworkAccessDebugPipeBackend::close()
{
- qWarning("QNetworkAccessDebugPipeBackend::closeDownstreamChannel() %d",operation());;
+ qWarning("QNetworkAccessDebugPipeBackend::closeDownstreamChannel() %d",operation());
//if (operation() == QNetworkAccessManager::GetOperation)
// socket.disconnectFromHost();
}
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index e6fea590bd..4e13c9924b 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -68,12 +68,13 @@
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
+using namespace std::chrono_literals;
Q_LOGGING_CATEGORY(lcQnam, "qt.network.access.manager")
Q_APPLICATION_STATIC(QNetworkAccessFileBackendFactory, fileBackend)
-#ifdef QT_BUILD_INTERNAL
+#if QT_CONFIG(private_tests)
Q_GLOBAL_STATIC(QNetworkAccessDebugPipeBackendFactory, debugpipeBackend)
#endif
@@ -153,7 +154,7 @@ bool getProxyAuth(const QString& proxyHostname, const QString &scheme, QString&
static void ensureInitialized()
{
-#ifdef QT_BUILD_INTERNAL
+#if QT_CONFIG(private_tests)
(void) debugpipeBackend();
#endif
@@ -780,6 +781,46 @@ QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request)
}
/*!
+ \since 6.7
+
+ \overload
+
+ \note A GET request with a message body is not cached.
+
+ \note If the request is redirected, the message body will be kept only if the status code is
+ 307 or 308.
+*/
+
+QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request, QIODevice *data)
+{
+ QNetworkRequest newRequest(request);
+ return d_func()->postProcess(
+ createRequest(QNetworkAccessManager::GetOperation, newRequest, data));
+}
+
+/*!
+ \since 6.7
+
+ \overload
+
+ \note A GET request with a message body is not cached.
+
+ \note If the request is redirected, the message body will be kept only if the status code is
+ 307 or 308.
+*/
+
+QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request, const QByteArray &data)
+{
+ QBuffer *buffer = new QBuffer;
+ buffer->setData(data);
+ buffer->open(QIODevice::ReadOnly);
+
+ QNetworkReply *reply = get(request, buffer);
+ buffer->setParent(reply);
+ return reply;
+}
+
+/*!
Sends an HTTP POST request to the destination specified by \a request
and returns a new QNetworkReply object opened for reading that will
contain the reply sent by the server. The contents of the \a data
@@ -815,6 +856,24 @@ QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, const
return reply;
}
+/*!
+ \overload
+
+ \since 6.8
+
+ Sends the POST request specified by \a request without a body and returns
+ a new QNetworkReply object.
+*/
+QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, std::nullptr_t nptr)
+{
+ Q_UNUSED(nptr);
+ QIODevice *dev = nullptr;
+
+ return d_func()->postProcess(createRequest(QNetworkAccessManager::PostOperation,
+ request,
+ dev));
+}
+
#if QT_CONFIG(http) || defined(Q_OS_WASM)
/*!
\since 4.8
@@ -899,6 +958,23 @@ QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, const
}
/*!
+ \overload
+
+ \since 6.8
+
+ Sends the PUT request specified by \a request without a body and returns
+ a new QNetworkReply object.
+*/
+
+QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, std::nullptr_t nptr)
+{
+ Q_UNUSED(nptr);
+ QIODevice *dev = nullptr;
+
+ return d_func()->postProcess(createRequest(QNetworkAccessManager::PutOperation, request, dev));
+}
+
+/*!
\since 4.6
Sends a request to delete the resource identified by the URL of \a request.
@@ -1132,8 +1208,8 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera
}
#if QT_CONFIG(http) || defined (Q_OS_WASM)
- if (!req.transferTimeout())
- req.setTransferTimeout(transferTimeout());
+ if (req.transferTimeoutAsDuration() == 0ms)
+ req.setTransferTimeout(transferTimeoutAsDuration());
#endif
if (autoDeleteReplies()
@@ -1384,38 +1460,59 @@ void QNetworkAccessManager::setAutoDeleteReplies(bool shouldAutoDelete)
}
/*!
+ \fn int QNetworkAccessManager::transferTimeout() const
\since 5.15
Returns the timeout used for transfers, in milliseconds.
- This timeout is zero if setTransferTimeout() hasn't been
- called, which means that the timeout is not used.
+ \sa setTransferTimeout()
*/
-int QNetworkAccessManager::transferTimeout() const
+
+/*!
+ \fn void QNetworkAccessManager::setTransferTimeout(int timeout)
+ \since 5.15
+
+ Sets \a timeout as the transfer timeout in milliseconds.
+
+ \sa setTransferTimeout(std::chrono::milliseconds),
+ transferTimeout(), transferTimeoutAsDuration()
+*/
+
+/*!
+ \since 6.7
+
+ Returns the timeout duration after which the transfer is aborted if no
+ data is exchanged.
+
+ The default duration is zero, which means that the timeout is not used.
+
+ \sa setTransferTimeout(std::chrono::milliseconds)
+ */
+std::chrono::milliseconds QNetworkAccessManager::transferTimeoutAsDuration() const
{
return d_func()->transferTimeout;
}
/*!
- \since 5.15
+ \since 6.7
- Sets \a timeout as the transfer timeout in milliseconds.
+ Sets the timeout \a duration to abort the transfer if no data is exchanged.
Transfers are aborted if no bytes are transferred before
the timeout expires. Zero means no timer is set. If no
argument is provided, the timeout is
- QNetworkRequest::DefaultTransferTimeoutConstant. If this function
+ QNetworkRequest::DefaultTransferTimeout. If this function
is not called, the timeout is disabled and has the
value zero. The request-specific non-zero timeouts set for
the requests that are executed override this value. This means
that if QNetworkAccessManager has an enabled timeout, it needs
to be disabled to execute a request without a timeout.
- \sa transferTimeout()
-*/
-void QNetworkAccessManager::setTransferTimeout(int timeout)
+ \sa transferTimeoutAsDuration()
+ */
+void QNetworkAccessManager::setTransferTimeout(std::chrono::milliseconds duration)
{
- d_func()->transferTimeout = timeout;
+ d_func()->transferTimeout = duration;
}
void QNetworkAccessManagerPrivate::_q_replyFinished(QNetworkReply *reply)
@@ -1676,9 +1773,9 @@ QNetworkRequest QNetworkAccessManagerPrivate::prepareMultipart(const QNetworkReq
// add MIME-Version header if not there already (we must include the header
// if the message conforms to RFC 2045, see section 4 of that RFC)
- QByteArray mimeHeader("MIME-Version");
+ auto mimeHeader = "MIME-Version"_ba;
if (!request.hasRawHeader(mimeHeader))
- newRequest.setRawHeader(mimeHeader, QByteArray("1.0"));
+ newRequest.setRawHeader(mimeHeader, "1.0"_ba);
QIODevice *device = multiPart->d_func()->device;
if (!device->isReadable()) {
diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h
index f0c99c03b8..0d069b2a9b 100644
--- a/src/network/access/qnetworkaccessmanager.h
+++ b/src/network/access/qnetworkaccessmanager.h
@@ -80,10 +80,14 @@ public:
QNetworkReply *head(const QNetworkRequest &request);
QNetworkReply *get(const QNetworkRequest &request);
+ QNetworkReply *get(const QNetworkRequest &request, QIODevice *data);
+ QNetworkReply *get(const QNetworkRequest &request, const QByteArray &data);
QNetworkReply *post(const QNetworkRequest &request, QIODevice *data);
QNetworkReply *post(const QNetworkRequest &request, const QByteArray &data);
+ QNetworkReply *post(const QNetworkRequest &request, std::nullptr_t nptr);
QNetworkReply *put(const QNetworkRequest &request, QIODevice *data);
QNetworkReply *put(const QNetworkRequest &request, const QByteArray &data);
+ QNetworkReply *put(const QNetworkRequest &request, std::nullptr_t nptr);
QNetworkReply *deleteResource(const QNetworkRequest &request);
QNetworkReply *sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, QIODevice *data = nullptr);
QNetworkReply *sendCustomRequest(const QNetworkRequest &request, const QByteArray &verb, const QByteArray &data);
@@ -109,8 +113,14 @@ public:
bool autoDeleteReplies() const;
void setAutoDeleteReplies(bool autoDelete);
+ QT_NETWORK_INLINE_SINCE(6, 8)
int transferTimeout() const;
- void setTransferTimeout(int timeout = QNetworkRequest::DefaultTransferTimeoutConstant);
+ QT_NETWORK_INLINE_SINCE(6, 8)
+ void setTransferTimeout(int timeout);
+
+ std::chrono::milliseconds transferTimeoutAsDuration() const;
+ void setTransferTimeout(std::chrono::milliseconds duration =
+ QNetworkRequest::DefaultTransferTimeout);
Q_SIGNALS:
#ifndef QT_NO_NETWORKPROXY
@@ -147,6 +157,18 @@ private:
#endif
};
+#if QT_NETWORK_INLINE_IMPL_SINCE(6, 8)
+int QNetworkAccessManager::transferTimeout() const
+{
+ return int(transferTimeoutAsDuration().count());
+}
+
+void QNetworkAccessManager::setTransferTimeout(int timeout)
+{
+ setTransferTimeout(std::chrono::milliseconds(timeout));
+}
+#endif // INLINE_SINCE 6.8
+
QT_END_NAMESPACE
#endif
diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h
index 050da2060f..491a5acaa4 100644
--- a/src/network/access/qnetworkaccessmanager_p.h
+++ b/src/network/access/qnetworkaccessmanager_p.h
@@ -131,7 +131,7 @@ public:
bool autoDeleteReplies = false;
- int transferTimeout = 0;
+ std::chrono::milliseconds transferTimeout{0};
Q_DECLARE_PUBLIC(QNetworkAccessManager)
};
diff --git a/src/network/access/qnetworkcookie.cpp b/src/network/access/qnetworkcookie.cpp
index 44542057ca..8ea5fdbe57 100644
--- a/src/network/access/qnetworkcookie.cpp
+++ b/src/network/access/qnetworkcookie.cpp
@@ -376,7 +376,7 @@ void QNetworkCookie::setValue(const QByteArray &value)
}
// ### move this to qnetworkcookie_p.h and share with qnetworkaccesshttpbackend
-static QPair<QByteArray, QByteArray> nextField(const QByteArray &text, int &position, bool isNameValue)
+static QPair<QByteArray, QByteArray> nextField(QByteArrayView text, int &position, bool isNameValue)
{
// format is one of:
// (1) token
@@ -396,11 +396,11 @@ static QPair<QByteArray, QByteArray> nextField(const QByteArray &text, int &posi
equalsPosition = semiColonPosition; //no '=' means there is an attribute-name but no attribute-value
}
- QByteArray first = text.mid(position, equalsPosition - position).trimmed();
+ QByteArray first = text.mid(position, equalsPosition - position).trimmed().toByteArray();
QByteArray second;
int secondLength = semiColonPosition - equalsPosition - 1;
if (secondLength > 0)
- second = text.mid(equalsPosition + 1, secondLength).trimmed();
+ second = text.mid(equalsPosition + 1, secondLength).trimmed().toByteArray();
position = semiColonPosition;
return qMakePair(first, second);
@@ -443,29 +443,33 @@ static QPair<QByteArray, QByteArray> nextField(const QByteArray &text, int &posi
*/
namespace {
-QByteArray sameSiteToRawString(QNetworkCookie::SameSite samesite)
+
+constexpr QByteArrayView sameSiteNone() noexcept { return "None"; }
+constexpr QByteArrayView sameSiteLax() noexcept { return "Lax"; }
+constexpr QByteArrayView sameSiteStrict() noexcept { return "Strict"; }
+
+QByteArrayView sameSiteToRawString(QNetworkCookie::SameSite samesite) noexcept
{
switch (samesite) {
case QNetworkCookie::SameSite::None:
- return QByteArrayLiteral("None");
+ return sameSiteNone();
case QNetworkCookie::SameSite::Lax:
- return QByteArrayLiteral("Lax");
+ return sameSiteLax();
case QNetworkCookie::SameSite::Strict:
- return QByteArrayLiteral("Strict");
+ return sameSiteStrict();
case QNetworkCookie::SameSite::Default:
break;
}
- return QByteArray();
+ return QByteArrayView();
}
-QNetworkCookie::SameSite sameSiteFromRawString(QByteArray str)
+QNetworkCookie::SameSite sameSiteFromRawString(QByteArrayView str) noexcept
{
- str = str.toLower();
- if (str == QByteArrayLiteral("none"))
+ if (str.compare(sameSiteNone(), Qt::CaseInsensitive) == 0)
return QNetworkCookie::SameSite::None;
- if (str == QByteArrayLiteral("lax"))
+ if (str.compare(sameSiteLax(), Qt::CaseInsensitive) == 0)
return QNetworkCookie::SameSite::Lax;
- if (str == QByteArrayLiteral("strict"))
+ if (str.compare(sameSiteStrict(), Qt::CaseInsensitive) == 0)
return QNetworkCookie::SameSite::Strict;
return QNetworkCookie::SameSite::Default;
}
@@ -576,7 +580,7 @@ static inline bool isValueSeparator(char c)
static inline bool isWhitespace(char c)
{ return c == ' ' || c == '\t'; }
-static bool checkStaticArray(int &val, const QByteArray &dateString, int at, const char *array, int size)
+static bool checkStaticArray(int &val, QByteArrayView dateString, int at, const char *array, int size)
{
if (dateString[at] < 'a' || dateString[at] > 'z')
return false;
@@ -623,7 +627,7 @@ static bool checkStaticArray(int &val, const QByteArray &dateString, int at, con
Or in their own words:
"} // else what the hell is this."
*/
-static QDateTime parseDateString(const QByteArray &dateString)
+static QDateTime parseDateString(QByteArrayView dateString)
{
QTime time;
// placeholders for values when we are not sure it is a year, month or day
@@ -686,13 +690,13 @@ static QDateTime parseDateString(const QByteArray &dateString)
int hours = 0;
switch (end - 1) {
case 4:
- minutes = atoi(dateString.mid(at + 3, 2).constData());
+ minutes = dateString.mid(at + 3, 2).toInt();
Q_FALLTHROUGH();
case 2:
- hours = atoi(dateString.mid(at + 1, 2).constData());
+ hours = dateString.mid(at + 1, 2).toInt();
break;
case 1:
- hours = atoi(dateString.mid(at + 1, 1).constData());
+ hours = dateString.mid(at + 1, 1).toInt();
break;
default:
at += end;
@@ -743,7 +747,7 @@ static QDateTime parseDateString(const QByteArray &dateString)
if (isNumber(dateString[at + 1])
&& isNumber(dateString[at + 2])
&& isNumber(dateString[at + 3])) {
- year = atoi(dateString.mid(at, 4).constData());
+ year = dateString.mid(at, 4).toInt();
at += 4;
#ifdef PARSEDATESTRINGDEBUG
qDebug() << "Year:" << year;
@@ -759,7 +763,7 @@ static QDateTime parseDateString(const QByteArray &dateString)
if (dateString.size() > at + 1
&& isNumber(dateString[at + 1]))
++length;
- int x = atoi(dateString.mid(at, length).constData());
+ int x = dateString.mid(at, length).toInt();
if (year == -1 && (x > 31 || x == 0)) {
year = x;
} else {
@@ -928,19 +932,19 @@ static QDateTime parseDateString(const QByteArray &dateString)
cookie that is parsed.
\sa toRawForm()
+ \note In Qt versions prior to 6.7, this function took QByteArray only.
*/
-QList<QNetworkCookie> QNetworkCookie::parseCookies(const QByteArray &cookieString)
+QList<QNetworkCookie> QNetworkCookie::parseCookies(QByteArrayView cookieString)
{
// cookieString can be a number of set-cookie header strings joined together
// by \n, parse each line separately.
QList<QNetworkCookie> cookies;
- QList<QByteArray> list = cookieString.split('\n');
- for (int a = 0; a < list.size(); a++)
- cookies += QNetworkCookiePrivate::parseSetCookieHeaderLine(list.at(a));
+ for (auto s : QLatin1StringView(cookieString).tokenize('\n'_L1))
+ cookies += QNetworkCookiePrivate::parseSetCookieHeaderLine(s);
return cookies;
}
-QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByteArray &cookieString)
+QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(QByteArrayView cookieString)
{
// According to http://wp.netscape.com/newsref/std/cookie_spec.html,<
// the Set-Cookie response header is of the format:
@@ -973,28 +977,27 @@ QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByt
case ';':
// new field in the cookie
field = nextField(cookieString, position, false);
- field.first = field.first.toLower(); // everything but the NAME=VALUE is case-insensitive
- if (field.first == "expires") {
+ if (field.first.compare("expires", Qt::CaseInsensitive) == 0) {
position -= field.second.size();
int end;
for (end = position; end < length; ++end)
if (isValueSeparator(cookieString.at(end)))
break;
- QByteArray dateString = cookieString.mid(position, end - position).trimmed();
+ QByteArray dateString = cookieString.mid(position, end - position).trimmed().toByteArray().toLower();
position = end;
- QDateTime dt = parseDateString(dateString.toLower());
+ QDateTime dt = parseDateString(dateString);
if (dt.isValid())
cookie.setExpirationDate(dt);
//if unparsed, ignore the attribute but not the whole cookie (RFC6265 section 5.2.1)
- } else if (field.first == "domain") {
- QByteArray rawDomain = field.second;
+ } else if (field.first.compare("domain", Qt::CaseInsensitive) == 0) {
+ QByteArrayView rawDomain = field.second;
//empty domain should be ignored (RFC6265 section 5.2.3)
if (!rawDomain.isEmpty()) {
- QString maybeLeadingDot;
+ QLatin1StringView maybeLeadingDot;
if (rawDomain.startsWith('.')) {
- maybeLeadingDot = u'.';
+ maybeLeadingDot = "."_L1;
rawDomain = rawDomain.mid(1);
}
@@ -1009,7 +1012,7 @@ QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByt
return result;
}
}
- } else if (field.first == "max-age") {
+ } else if (field.first.compare("max-age", Qt::CaseInsensitive) == 0) {
bool ok = false;
int secs = field.second.toInt(&ok);
if (ok) {
@@ -1021,7 +1024,7 @@ QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByt
}
}
//if unparsed, ignore the attribute but not the whole cookie (RFC6265 section 5.2.2)
- } else if (field.first == "path") {
+ } else if (field.first.compare("path", Qt::CaseInsensitive) == 0) {
if (field.second.startsWith('/')) {
// ### we should treat cookie paths as an octet sequence internally
// However RFC6265 says we should assume UTF-8 for presentation as a string
@@ -1031,11 +1034,11 @@ QList<QNetworkCookie> QNetworkCookiePrivate::parseSetCookieHeaderLine(const QByt
// and also IETF test case path0030 which has valid and empty path in the same cookie
cookie.setPath(QString());
}
- } else if (field.first == "secure") {
+ } else if (field.first.compare("secure", Qt::CaseInsensitive) == 0) {
cookie.setSecure(true);
- } else if (field.first == "httponly") {
+ } else if (field.first.compare("httponly", Qt::CaseInsensitive) == 0) {
cookie.setHttpOnly(true);
- } else if (field.first == "samesite") {
+ } else if (field.first.compare("samesite", Qt::CaseInsensitive) == 0) {
cookie.setSameSitePolicy(sameSiteFromRawString(field.second));
} else {
// ignore unknown fields in the cookie (RFC6265 section 5.2, rule 6)
diff --git a/src/network/access/qnetworkcookie.h b/src/network/access/qnetworkcookie.h
index d4f4942288..aed9c8af12 100644
--- a/src/network/access/qnetworkcookie.h
+++ b/src/network/access/qnetworkcookie.h
@@ -75,7 +75,10 @@ public:
bool hasSameIdentifier(const QNetworkCookie &other) const;
void normalize(const QUrl &url);
+#if QT_NETWORK_REMOVED_SINCE(6, 7)
static QList<QNetworkCookie> parseCookies(const QByteArray &cookieString);
+#endif
+ static QList<QNetworkCookie> parseCookies(QByteArrayView cookieString);
private:
QSharedDataPointer<QNetworkCookiePrivate> d;
diff --git a/src/network/access/qnetworkcookie_p.h b/src/network/access/qnetworkcookie_p.h
index 7874b2c16a..ce4378fd64 100644
--- a/src/network/access/qnetworkcookie_p.h
+++ b/src/network/access/qnetworkcookie_p.h
@@ -25,7 +25,7 @@ class QNetworkCookiePrivate: public QSharedData
{
public:
QNetworkCookiePrivate() = default;
- static QList<QNetworkCookie> parseSetCookieHeaderLine(const QByteArray &cookieString);
+ static QList<QNetworkCookie> parseSetCookieHeaderLine(QByteArrayView cookieString);
QDateTime expirationDate;
QString domain;
@@ -43,7 +43,7 @@ static inline bool isLWS(char c)
return c == ' ' || c == '\t' || c == '\r' || c == '\n';
}
-static int nextNonWhitespace(const QByteArray &text, int from)
+static int nextNonWhitespace(QByteArrayView text, int from)
{
// RFC 2616 defines linear whitespace as:
// LWS = [CRLF] 1*( SP | HT )
diff --git a/src/network/access/qnetworkcookiejar.cpp b/src/network/access/qnetworkcookiejar.cpp
index bbb62455a5..82746f91b1 100644
--- a/src/network/access/qnetworkcookiejar.cpp
+++ b/src/network/access/qnetworkcookiejar.cpp
@@ -112,7 +112,7 @@ void QNetworkCookieJar::setAllCookies(const QList<QNetworkCookie> &cookieList)
d->allCookies = cookieList;
}
-static inline bool isParentPath(const QString &path, const QString &reference)
+static inline bool isParentPath(QStringView path, QStringView reference)
{
if ((path.isEmpty() && reference == "/"_L1) || path.startsWith(reference)) {
//The cookie-path and the request-path are identical.
@@ -131,12 +131,12 @@ static inline bool isParentPath(const QString &path, const QString &reference)
return false;
}
-static inline bool isParentDomain(const QString &domain, const QString &reference)
+static inline bool isParentDomain(QStringView domain, QStringView reference)
{
if (!reference.startsWith(u'.'))
return domain == reference;
- return domain.endsWith(reference) || domain == QStringView{reference}.mid(1);
+ return domain.endsWith(reference) || domain == reference.mid(1);
}
/*!
@@ -200,49 +200,38 @@ QList<QNetworkCookie> QNetworkCookieJar::cookiesForUrl(const QUrl &url) const
Q_D(const QNetworkCookieJar);
const QDateTime now = QDateTime::currentDateTimeUtc();
QList<QNetworkCookie> result;
- bool isEncrypted = url.scheme() == "https"_L1;
+ const bool isEncrypted = url.scheme() == "https"_L1;
// scan our cookies for something that matches
- QList<QNetworkCookie>::ConstIterator it = d->allCookies.constBegin(),
- end = d->allCookies.constEnd();
- for ( ; it != end; ++it) {
- if (!isParentDomain(url.host(), it->domain()))
+ for (const auto &cookie : std::as_const(d->allCookies)) {
+ if (!isEncrypted && cookie.isSecure())
continue;
- if (!isParentPath(url.path(), it->path()))
+ if (!cookie.isSessionCookie() && cookie.expirationDate() < now)
continue;
- if (!(*it).isSessionCookie() && (*it).expirationDate() < now)
+ const QString urlHost = url.host();
+ const QString cookieDomain = cookie.domain();
+ if (!isParentDomain(urlHost, cookieDomain))
continue;
- if ((*it).isSecure() && !isEncrypted)
+ if (!isParentPath(url.path(), cookie.path()))
continue;
- QString domain = it->domain();
+ QStringView domain = cookieDomain;
if (domain.startsWith(u'.')) /// Qt6?: remove when compliant with RFC6265
- domain = domain.mid(1);
+ domain = domain.sliced(1);
#if QT_CONFIG(topleveldomain)
- if (qIsEffectiveTLD(domain) && url.host() != domain)
+ if (urlHost != domain && qIsEffectiveTLD(domain))
continue;
#else
- if (!domain.contains(u'.') && url.host() != domain)
+ if (!domain.contains(u'.') && urlHost != domain)
continue;
#endif // topleveldomain
- // insert this cookie into result, sorted by path
- QList<QNetworkCookie>::Iterator insertIt = result.begin();
- while (insertIt != result.end()) {
- if (insertIt->path().size() < it->path().size()) {
- // insert here
- insertIt = result.insert(insertIt, *it);
- break;
- } else {
- ++insertIt;
- }
- }
-
- // this is the shortest path yet, just append
- if (insertIt == result.end())
- result += *it;
+ result += cookie;
}
+ auto longerPath = [](const auto &c1, const auto &c2)
+ { return c1.path().size() > c2.path().size(); };
+ std::sort(result.begin(), result.end(), longerPath);
return result;
}
@@ -299,12 +288,11 @@ bool QNetworkCookieJar::updateCookie(const QNetworkCookie &cookie)
bool QNetworkCookieJar::deleteCookie(const QNetworkCookie &cookie)
{
Q_D(QNetworkCookieJar);
- QList<QNetworkCookie>::Iterator it;
- for (it = d->allCookies.begin(); it != d->allCookies.end(); ++it) {
- if (it->hasSameIdentifier(cookie)) {
- d->allCookies.erase(it);
- return true;
- }
+ const auto it = std::find_if(d->allCookies.cbegin(), d->allCookies.cend(),
+ [&cookie](const auto &c) { return c.hasSameIdentifier(cookie); });
+ if (it != d->allCookies.cend()) {
+ d->allCookies.erase(it);
+ return true;
}
return false;
}
@@ -317,13 +305,14 @@ bool QNetworkCookieJar::deleteCookie(const QNetworkCookie &cookie)
*/
bool QNetworkCookieJar::validateCookie(const QNetworkCookie &cookie, const QUrl &url) const
{
- QString domain = cookie.domain();
+ const QString cookieDomain = cookie.domain();
+ QStringView domain = cookieDomain;
const QString host = url.host();
if (!isParentDomain(domain, host) && !isParentDomain(host, domain))
return false; // not accepted
if (domain.startsWith(u'.'))
- domain = domain.mid(1);
+ domain = domain.sliced(1);
// We shouldn't reject if:
// "[...] the domain-attribute is identical to the canonicalized request-host"
diff --git a/src/network/access/qnetworkdiskcache.cpp b/src/network/access/qnetworkdiskcache.cpp
index 0b0db2d3a1..b39924025e 100644
--- a/src/network/access/qnetworkdiskcache.cpp
+++ b/src/network/access/qnetworkdiskcache.cpp
@@ -12,7 +12,7 @@
#include <qdir.h>
#include <qdatastream.h>
#include <qdatetime.h>
-#include <qdiriterator.h>
+#include <qdirlisting.h>
#include <qurl.h>
#include <qcryptographichash.h>
#include <qdebug.h>
@@ -154,15 +154,11 @@ QIODevice *QNetworkDiskCache::prepare(const QNetworkCacheMetaData &metaData)
return nullptr;
}
- const auto headers = metaData.rawHeaders();
- for (const auto &header : headers) {
- if (header.first.compare("content-length", Qt::CaseInsensitive) == 0) {
- const qint64 size = header.second.toLongLong();
- if (size > (maximumCacheSize() * 3)/4)
- return nullptr;
- break;
- }
- }
+ const auto sizeValue = metaData.headers().value(QHttpHeaders::WellKnownHeader::ContentLength);
+ const qint64 size = sizeValue.toLongLong();
+ if (size > (maximumCacheSize() * 3)/4)
+ return nullptr;
+
std::unique_ptr<QCacheItem> cacheItem = std::make_unique<QCacheItem>();
cacheItem->metaData = metaData;
@@ -172,11 +168,7 @@ QIODevice *QNetworkDiskCache::prepare(const QNetworkCacheMetaData &metaData)
device = &(cacheItem->data);
} else {
QString fileName = d->cacheFileName(cacheItem->metaData.url());
- QT_TRY {
- cacheItem->file = new QSaveFile(fileName, &cacheItem->data);
- } QT_CATCH(...) {
- cacheItem->file = nullptr;
- }
+ cacheItem->file = new(std::nothrow) QSaveFile(fileName, &cacheItem->data);
if (!cacheItem->file || !cacheItem->file->open(QFileDevice::WriteOnly)) {
qWarning("QNetworkDiskCache::prepare() unable to open temporary file");
cacheItem.reset();
@@ -482,7 +474,6 @@ qint64 QNetworkDiskCache::expire()
d->lastItem.reset();
const QDir::Filters filters = QDir::AllDirs | QDir:: Files | QDir::NoDotAndDotDot;
- QDirIterator it(cacheDirectory(), filters, QDirIterator::Subdirectories);
struct CacheItem
{
@@ -492,11 +483,12 @@ qint64 QNetworkDiskCache::expire()
};
std::vector<CacheItem> cacheItems;
qint64 totalSize = 0;
- while (it.hasNext()) {
- QFileInfo info = it.nextFileInfo();
- if (!info.fileName().endsWith(CACHE_POSTFIX))
+ using F = QDirListing::IteratorFlag;
+ for (const auto &dirEntry : QDirListing(cacheDirectory(), filters, F::Recursive)) {
+ if (!dirEntry.fileName().endsWith(CACHE_POSTFIX))
continue;
+ const QFileInfo &info = dirEntry.fileInfo();
QDateTime fileTime = info.birthTime(QTimeZone::UTC);
if (!fileTime.isValid())
fileTime = info.metadataChangeTime(QTimeZone::UTC);
@@ -582,31 +574,27 @@ QString QNetworkDiskCachePrivate::cacheFileName(const QUrl &url) const
*/
bool QCacheItem::canCompress() const
{
- bool sizeOk = false;
- bool typeOk = false;
- const auto headers = metaData.rawHeaders();
- for (const auto &header : headers) {
- if (header.first.compare("content-length", Qt::CaseInsensitive) == 0) {
- qint64 size = header.second.toLongLong();
- if (size > MAX_COMPRESSION_SIZE)
- return false;
- else
- sizeOk = true;
- }
+ const auto h = metaData.headers();
- if (header.first.compare("content-type", Qt::CaseInsensitive) == 0) {
- QByteArray type = header.second;
- if (type.startsWith("text/")
- || (type.startsWith("application/")
- && (type.endsWith("javascript") || type.endsWith("ecmascript"))))
- typeOk = true;
- else
- return false;
- }
- if (sizeOk && typeOk)
- return true;
+ const auto sizeValue = h.value(QHttpHeaders::WellKnownHeader::ContentLength);
+ if (sizeValue.empty())
+ return false;
+
+ qint64 size = sizeValue.toLongLong();
+ if (size > MAX_COMPRESSION_SIZE)
+ return false;
+
+ const auto type = h.value(QHttpHeaders::WellKnownHeader::ContentType);
+ if (!type.empty())
+ return false;
+
+ if (!type.startsWith("text/")
+ && !(type.startsWith("application/")
+ && (type.endsWith("javascript") || type.endsWith("ecmascript")))) {
+ return false;
}
- return false;
+
+ return true;
}
enum
@@ -677,7 +665,7 @@ bool QCacheItem::read(QFileDevice *device, bool readData)
if (!device->fileName().endsWith(expectedFilename))
return false;
- return metaData.isValid() && !metaData.rawHeaders().isEmpty();
+ return metaData.isValid() && !metaData.headers().isEmpty();
}
QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp
index 335a0131ff..0613a65c34 100644
--- a/src/network/access/qnetworkreply.cpp
+++ b/src/network/access/qnetworkreply.cpp
@@ -612,8 +612,9 @@ QVariant QNetworkReply::header(QNetworkRequest::KnownHeaders header) const
the remote server
\sa rawHeader()
+ \note In Qt versions prior to 6.7, this function took QByteArray only.
*/
-bool QNetworkReply::hasRawHeader(const QByteArray &headerName) const
+bool QNetworkReply::hasRawHeader(QAnyStringView headerName) const
{
Q_D(const QNetworkReply);
return d->findRawHeader(headerName) != d->rawHeaders.constEnd();
@@ -627,13 +628,12 @@ bool QNetworkReply::hasRawHeader(const QByteArray &headerName) const
header field.
\sa setRawHeader(), hasRawHeader(), header()
+ \note In Qt versions prior to 6.7, this function took QByteArray only.
*/
-QByteArray QNetworkReply::rawHeader(const QByteArray &headerName) const
+QByteArray QNetworkReply::rawHeader(QAnyStringView headerName) const
{
Q_D(const QNetworkReply);
- QNetworkHeadersPrivate::RawHeadersList::ConstIterator it =
- d->findRawHeader(headerName);
- if (it != d->rawHeaders.constEnd())
+ if (const auto it = d->findRawHeader(headerName); it != d->rawHeaders.constEnd())
return it->second;
return QByteArray();
}
@@ -654,6 +654,19 @@ const QList<QNetworkReply::RawHeaderPair>& QNetworkReply::rawHeaderPairs() const
}
/*!
+ \since 6.8
+
+ Returns headers that were sent by the remote server.
+
+ \sa setHeaders(), QNetworkRequest::setAttribute(), QNetworkRequest::Attribute
+*/
+QHttpHeaders QNetworkReply::headers() const
+{
+ Q_D(const QNetworkReply);
+ return d->headers();
+}
+
+/*!
Returns a list of headers fields that were sent by the remote
server, in the order that they were sent. Duplicate headers are
merged together and take place of the latter duplicate.
@@ -888,6 +901,45 @@ void QNetworkReply::setUrl(const QUrl &url)
}
/*!
+ \since 6.8
+
+ Sets \a newHeaders as headers in this network reply, overriding
+ any previously set headers.
+
+ If some headers correspond to the known headers, they will be
+ parsed and the corresponding parsed form will also be set.
+
+ \sa headers(), QNetworkRequest::KnownHeaders
+*/
+void QNetworkReply::setHeaders(const QHttpHeaders &newHeaders)
+{
+ Q_D(QNetworkReply);
+ d->setHeaders(newHeaders);
+}
+
+/*!
+ \overload
+ \since 6.8
+*/
+void QNetworkReply::setHeaders(QHttpHeaders &&newHeaders)
+{
+ Q_D(QNetworkReply);
+ d->setHeaders(std::move(newHeaders));
+}
+
+/*!
+ \since 6.8
+
+ Sets the header \a name to be of value \a value. If \a
+ name was previously set, it is overridden.
+*/
+void QNetworkReply::setWellKnownHeader(QHttpHeaders::WellKnownHeader name, const QByteArray &value)
+{
+ Q_D(QNetworkReply);
+ d->setHeader(name, value);
+}
+
+/*!
Sets the known header \a header to be of value \a value. The
corresponding raw form of the header will be set as well.
diff --git a/src/network/access/qnetworkreply.h b/src/network/access/qnetworkreply.h
index 2a505b07c0..48ec0397c6 100644
--- a/src/network/access/qnetworkreply.h
+++ b/src/network/access/qnetworkreply.h
@@ -97,12 +97,19 @@ public:
QVariant header(QNetworkRequest::KnownHeaders header) const;
// raw headers:
+#if QT_NETWORK_REMOVED_SINCE(6, 7)
bool hasRawHeader(const QByteArray &headerName) const;
+#endif
+ bool hasRawHeader(QAnyStringView headerName) const;
QList<QByteArray> rawHeaderList() const;
+#if QT_NETWORK_REMOVED_SINCE(6, 7)
QByteArray rawHeader(const QByteArray &headerName) const;
+#endif
+ QByteArray rawHeader(QAnyStringView headerName) const;
typedef QPair<QByteArray, QByteArray> RawHeaderPair;
const QList<RawHeaderPair>& rawHeaderPairs() const;
+ QHttpHeaders headers() const;
// attributes
QVariant attribute(QNetworkRequest::Attribute code) const;
@@ -146,6 +153,9 @@ protected:
void setUrl(const QUrl &url);
void setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value);
void setRawHeader(const QByteArray &headerName, const QByteArray &value);
+ void setHeaders(const QHttpHeaders &newHeaders);
+ void setHeaders(QHttpHeaders &&newHeaders);
+ void setWellKnownHeader(QHttpHeaders::WellKnownHeader name, const QByteArray &value);
void setAttribute(QNetworkRequest::Attribute code, const QVariant &value);
#if QT_CONFIG(ssl)
diff --git a/src/network/access/qnetworkreplyfileimpl.cpp b/src/network/access/qnetworkreplyfileimpl.cpp
index 7d2ba39069..e6208a5c85 100644
--- a/src/network/access/qnetworkreplyfileimpl.cpp
+++ b/src/network/access/qnetworkreplyfileimpl.cpp
@@ -60,7 +60,7 @@ QNetworkReplyFileImpl::QNetworkReplyFileImpl(QNetworkAccessManager *manager, con
setFinished(true); // We're finished, will emit finished() after ctor is done.
QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection,
Q_ARG(QNetworkReply::NetworkError, QNetworkReply::ProtocolInvalidOperationError));
- QMetaObject::invokeMethod(this, [this](){ fileOpenFinished(false); }, Qt::QueuedConnection);
+ QMetaObject::invokeMethod(this, &QNetworkReplyFileImpl::fileOpenFinished, Qt::QueuedConnection, false);
return;
}
#endif
diff --git a/src/network/access/qnetworkreplyfileimpl_p.h b/src/network/access/qnetworkreplyfileimpl_p.h
index 20a09983ac..6413903d8f 100644
--- a/src/network/access/qnetworkreplyfileimpl_p.h
+++ b/src/network/access/qnetworkreplyfileimpl_p.h
@@ -1,8 +1,8 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QNETWORKREPLYFILEIMPL_H
-#define QNETWORKREPLYFILEIMPL_H
+#ifndef QNETWORKREPLYFILEIMPL_P_H
+#define QNETWORKREPLYFILEIMPL_P_H
//
// W A R N I N G
@@ -19,7 +19,9 @@
#include "qnetworkreply.h"
#include "qnetworkreply_p.h"
#include "qnetworkaccessmanager.h"
+
#include <QFile>
+#include <QtCore/qpointer.h>
#include <private/qabstractfileengine_p.h>
QT_BEGIN_NAMESPACE
@@ -65,4 +67,4 @@ QT_END_NAMESPACE
QT_DECL_METATYPE_EXTERN_TAGGED(QNetworkRequest::KnownHeaders,
QNetworkRequest__KnownHeaders, Q_NETWORK_EXPORT)
-#endif // QNETWORKREPLYFILEIMPL_H
+#endif // QNETWORKREPLYFILEIMPL_P_H
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
index 54e70fdcf3..1eee98f834 100644
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
@@ -34,17 +34,16 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
using namespace QtMiscUtils;
+using namespace std::chrono_literals;
class QNetworkProxy;
-static inline bool isSeparator(char c)
-{
- static const char separators[] = "()<>@,;:\\\"/[]?={}";
- return isLWS(c) || strchr(separators, c) != nullptr;
-}
+static inline QByteArray rangeName() { return "Range"_ba; }
+static inline QByteArray cacheControlName() { return "Cache-Control"_ba; }
+static constexpr QByteArrayView bytesEqualPrefix() noexcept { return "bytes="; }
// ### merge with nextField in cookiejar.cpp
-static QHash<QByteArray, QByteArray> parseHttpOptionHeader(const QByteArray &header)
+static QHash<QByteArray, QByteArray> parseHttpOptionHeader(QByteArrayView header)
{
// The HTTP header is of the form:
// header = #1(directives)
@@ -73,7 +72,7 @@ static QHash<QByteArray, QByteArray> parseHttpOptionHeader(const QByteArray &hea
end = header.size();
if (equal != -1 && end > equal)
end = equal; // equal sign comes before comma/end
- QByteArray key = QByteArray(header.constData() + pos, end - pos).trimmed().toLower();
+ const auto key = header.sliced(pos, end - pos).trimmed();
pos = end + 1;
if (uint(equal) < uint(comma)) {
@@ -109,6 +108,11 @@ static QHash<QByteArray, QByteArray> parseHttpOptionHeader(const QByteArray &hea
++pos;
}
} else {
+ const auto isSeparator = [](char c) {
+ static const char separators[] = "()<>@,;:\\\"/[]?={}";
+ return isLWS(c) || strchr(separators, c) != nullptr;
+ };
+
// case: token
while (pos < header.size()) {
char c = header.at(pos);
@@ -119,7 +123,7 @@ static QHash<QByteArray, QByteArray> parseHttpOptionHeader(const QByteArray &hea
}
}
- result.insert(key, value);
+ result.insert(key.toByteArray().toLower(), value);
// find the comma now:
comma = header.indexOf(',', pos);
@@ -129,7 +133,7 @@ static QHash<QByteArray, QByteArray> parseHttpOptionHeader(const QByteArray &hea
} else {
// case: token
// key is already set
- result.insert(key, QByteArray());
+ result.insert(key.toByteArray().toLower(), QByteArray());
}
}
}
@@ -154,6 +158,9 @@ QNetworkReplyHttpImpl::QNetworkReplyHttpImpl(QNetworkAccessManager* const manage
d->sslConfiguration.reset(new QSslConfiguration(request.sslConfiguration()));
#endif
+ QObjectPrivate::connect(this, &QNetworkReplyHttpImpl::redirectAllowed, d,
+ &QNetworkReplyHttpImplPrivate::followRedirect, Qt::QueuedConnection);
+
// FIXME Later maybe set to Unbuffered, especially if it is zerocopy or from cache?
QIODevice::open(QIODevice::ReadOnly);
@@ -474,16 +481,17 @@ bool QNetworkReplyHttpImplPrivate::loadFromCacheIfAllowed(QHttpNetworkRequest &h
if (CacheLoadControlAttribute == QNetworkRequest::AlwaysNetwork) {
// If the request does not already specify preferred cache-control
// force reload from the network and tell any caching proxy servers to reload too
- if (!request.rawHeaderList().contains("Cache-Control")) {
- httpRequest.setHeaderField("Cache-Control", "no-cache");
- httpRequest.setHeaderField("Pragma", "no-cache");
+ if (!request.rawHeaderList().contains(cacheControlName())) {
+ const auto noCache = "no-cache"_ba;
+ httpRequest.setHeaderField(cacheControlName(), noCache);
+ httpRequest.setHeaderField("Pragma"_ba, noCache);
}
return false;
}
// The disk cache API does not currently support partial content retrieval.
// That is why we don't use the disk cache for any such requests.
- if (request.hasRawHeader("Range"))
+ if (request.hasRawHeader(rangeName()))
return false;
QAbstractNetworkCache *nc = managerPrivate->networkCache;
@@ -503,24 +511,25 @@ bool QNetworkReplyHttpImplPrivate::loadFromCacheIfAllowed(QHttpNetworkRequest &h
it = cacheHeaders.findRawHeader("content-length");
if (it != cacheHeaders.rawHeaders.constEnd()) {
- if (nc->data(httpRequest.url())->size() < it->second.toLongLong())
+ std::unique_ptr<QIODevice> data(nc->data(httpRequest.url()));
+ if (!data || data->size() < it->second.toLongLong())
return false; // The data is smaller than the content-length specified
}
it = cacheHeaders.findRawHeader("etag");
if (it != cacheHeaders.rawHeaders.constEnd())
- httpRequest.setHeaderField("If-None-Match", it->second);
+ httpRequest.setHeaderField("If-None-Match"_ba, it->second);
QDateTime lastModified = metaData.lastModified();
if (lastModified.isValid())
- httpRequest.setHeaderField("If-Modified-Since", QNetworkHeadersPrivate::toHttpDate(lastModified));
+ httpRequest.setHeaderField("If-Modified-Since"_ba, QNetworkHeadersPrivate::toHttpDate(lastModified));
- it = cacheHeaders.findRawHeader("Cache-Control");
+ it = cacheHeaders.findRawHeader(cacheControlName());
if (it != cacheHeaders.rawHeaders.constEnd()) {
QHash<QByteArray, QByteArray> cacheControl = parseHttpOptionHeader(it->second);
- if (cacheControl.contains("must-revalidate"))
+ if (cacheControl.contains("must-revalidate"_ba))
return false;
- if (cacheControl.contains("no-cache"))
+ if (cacheControl.contains("no-cache"_ba))
return false;
}
@@ -575,10 +584,11 @@ bool QNetworkReplyHttpImplPrivate::loadFromCacheIfAllowed(QHttpNetworkRequest &h
if (lastModified.isValid() && dateHeader.isValid()) {
qint64 diff = lastModified.secsTo(dateHeader);
freshness_lifetime = diff / 10;
- if (httpRequest.headerField("Warning").isEmpty()) {
+ const auto warningHeader = "Warning"_ba;
+ if (httpRequest.headerField(warningHeader).isEmpty()) {
QDateTime dt = currentDateTime.addSecs(current_age);
if (currentDateTime.daysTo(dt) > 1)
- httpRequest.setHeaderField("Warning", "113");
+ httpRequest.setHeaderField(warningHeader, "113"_ba);
}
}
@@ -690,8 +700,13 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
switch (operation) {
case QNetworkAccessManager::GetOperation:
httpRequest.setOperation(QHttpNetworkRequest::Get);
- if (loadFromCacheIfAllowed(httpRequest))
+ // If the request has a body, createUploadByteDevice() and don't use caching
+ if (outgoingData) {
+ invalidateCache();
+ createUploadByteDevice();
+ } else if (loadFromCacheIfAllowed(httpRequest)) {
return; // no need to send the request! :)
+ }
break;
case QNetworkAccessManager::HeadOperation:
@@ -731,14 +746,15 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
QList<QByteArray> headers = newHttpRequest.rawHeaderList();
if (resumeOffset != 0) {
- const int rangeIndex = headers.indexOf("Range");
+ const int rangeIndex = headers.indexOf(rangeName());
if (rangeIndex != -1) {
// Need to adjust resume offset for user specified range
headers.removeAt(rangeIndex);
// We've already verified that requestRange starts with "bytes=", see canResume.
- QByteArray requestRange = newHttpRequest.rawHeader("Range").mid(6);
+ const auto rangeHeader = newHttpRequest.rawHeader(rangeName());
+ const auto requestRange = QByteArrayView(rangeHeader).mid(bytesEqualPrefix().size());
int index = requestRange.indexOf('-');
@@ -746,12 +762,12 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
quint64 requestEndOffset = requestRange.mid(index + 1).toULongLong();
// In case an end offset is not given it is skipped from the request range
- requestRange = "bytes=" + QByteArray::number(resumeOffset + requestStartOffset) +
+ QByteArray newRange = bytesEqualPrefix() + QByteArray::number(resumeOffset + requestStartOffset) +
'-' + (requestEndOffset ? QByteArray::number(requestEndOffset) : QByteArray());
- httpRequest.setHeaderField("Range", requestRange);
+ httpRequest.setHeaderField(rangeName(), newRange);
} else {
- httpRequest.setHeaderField("Range", "bytes=" + QByteArray::number(resumeOffset) + '-');
+ httpRequest.setHeaderField(rangeName(), bytesEqualPrefix() + QByteArray::number(resumeOffset) + '-');
}
}
@@ -870,9 +886,6 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
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)),
@@ -1232,13 +1245,18 @@ void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int htt
return;
}
+ // If the original operation was a GET with a body and the status code is either
+ // 307 or 308 then keep the message body
+ const bool getOperationKeepsBody = (operation == QNetworkAccessManager::GetOperation)
+ && (httpStatus == 307 || httpStatus == 308);
+
redirectRequest = createRedirectRequest(originalRequest, url, maxRedirectsRemaining);
operation = getRedirectOperation(operation, httpStatus);
// Clear stale headers, the relevant ones get set again later
httpRequest.clearHeaders();
- if (operation == QNetworkAccessManager::GetOperation
- || operation == QNetworkAccessManager::HeadOperation) {
+ if ((operation == QNetworkAccessManager::GetOperation
+ || operation == QNetworkAccessManager::HeadOperation) && !getOperationKeepsBody) {
// possibly changed from not-GET/HEAD to GET/HEAD, make sure to get rid of upload device
uploadByteDevice.reset();
uploadByteDevicePosition = 0;
@@ -1285,6 +1303,8 @@ void QNetworkReplyHttpImplPrivate::followRedirect()
q, [this]() { postRequest(redirectRequest); }, Qt::QueuedConnection);
}
+static constexpr QLatin1StringView locationHeader() noexcept { return "location"_L1; }
+
void QNetworkReplyHttpImplPrivate::checkForRedirect(const int statusCode)
{
Q_Q(QNetworkReplyHttpImpl);
@@ -1297,7 +1317,7 @@ void QNetworkReplyHttpImplPrivate::checkForRedirect(const int statusCode)
// What do we do about the caching of the HTML note?
// The response to a 303 MUST NOT be cached, while the response to
// all of the others is cacheable if the headers indicate it to be
- QByteArray header = q->rawHeader("location");
+ QByteArray header = q->rawHeader(locationHeader());
QUrl url = QUrl(QString::fromUtf8(header));
if (!url.isValid())
url = QUrl(QLatin1StringView(header));
@@ -1305,7 +1325,7 @@ void QNetworkReplyHttpImplPrivate::checkForRedirect(const int statusCode)
}
}
-void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByteArray,QByteArray> > &hm,
+void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QHttpHeaders &hm,
int sc, const QString &rp, bool pu,
QSharedPointer<char> db,
qint64 contentLength,
@@ -1344,25 +1364,23 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByte
const bool autoDecompress = request.rawHeader("accept-encoding").isEmpty();
const bool shouldDecompress = isCompressed && autoDecompress;
// reconstruct the HTTP header
- QList<QPair<QByteArray, QByteArray> > headerMap = hm;
- QList<QPair<QByteArray, QByteArray> >::ConstIterator it = headerMap.constBegin(),
- end = headerMap.constEnd();
- for (; it != end; ++it) {
- QByteArray value = q->rawHeader(it->first);
+ for (qsizetype i = 0; i < hm.size(); ++i) {
+ const auto key = hm.nameAt(i);
+ const auto originValue = hm.valueAt(i);
+
+ QByteArray value = q->rawHeader(key);
// Reset any previous "location" header set in the reply. In case of
// redirects, we don't want to 'append' multiple location header values,
// rather we keep only the latest one
- if (it->first.toLower() == "location")
+ if (key == locationHeader())
value.clear();
- if (shouldDecompress && !decompressHelper.isValid()
- && it->first.compare("content-encoding", Qt::CaseInsensitive) == 0) {
-
+ if (shouldDecompress && !decompressHelper.isValid() && key == "content-encoding"_L1) {
if (!synchronous) // with synchronous all the data is expected to be handled at once
decompressHelper.setCountingBytesEnabled(true);
- if (!decompressHelper.setEncoding(it->second)) {
+ if (!decompressHelper.setEncoding(originValue)) {
error(QNetworkReplyImpl::NetworkError::UnknownContentError,
QCoreApplication::translate("QHttp", "Failed to initialize decompression: %1")
.arg(decompressHelper.errorString()));
@@ -1375,13 +1393,13 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByte
if (!value.isEmpty()) {
// Why are we appending values for headers which are already
// present?
- if (it->first.compare("set-cookie", Qt::CaseInsensitive) == 0)
+ if (key == "set-cookie"_L1)
value += '\n';
else
value += ", ";
}
- value += it->second;
- q->setRawHeader(it->first, value);
+ value += originValue;
+ q->setRawHeader({key.data(), key.size()}, value);
}
q->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, statusCode);
@@ -1400,11 +1418,11 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData(const QList<QPair<QByte
QNetworkHeadersPrivate cacheHeaders;
cacheHeaders.setAllRawHeaders(metaData.rawHeaders());
QNetworkHeadersPrivate::RawHeadersList::ConstIterator it;
- it = cacheHeaders.findRawHeader("Cache-Control");
+ it = cacheHeaders.findRawHeader(cacheControlName());
bool mustReValidate = false;
if (it != cacheHeaders.rawHeaders.constEnd()) {
QHash<QByteArray, QByteArray> cacheControl = parseHttpOptionHeader(it->second);
- if (cacheControl.contains("must-revalidate"))
+ if (cacheControl.contains("must-revalidate"_ba))
mustReValidate = true;
}
if (!mustReValidate && sendCacheContents(metaData))
@@ -1648,7 +1666,7 @@ bool QNetworkReplyHttpImplPrivate::sendCacheContents(const QNetworkCacheMetaData
QUrl redirectUrl;
for ( ; it != end; ++it) {
if (httpRequest.isFollowRedirects() &&
- !it->first.compare("location", Qt::CaseInsensitive))
+ !it->first.compare(locationHeader(), Qt::CaseInsensitive))
redirectUrl = QUrl::fromEncoded(it->second);
setRawHeader(it->first, it->second);
}
@@ -1685,6 +1703,27 @@ bool QNetworkReplyHttpImplPrivate::sendCacheContents(const QNetworkCacheMetaData
return true;
}
+static auto caseInsensitiveCompare(QByteArrayView value)
+{
+ return [value](QByteArrayView element)
+ {
+ return value.compare(element, Qt::CaseInsensitive) == 0;
+ };
+}
+
+static bool isHopByHop(QByteArrayView header)
+{
+ constexpr QByteArrayView headers[] = { "connection",
+ "keep-alive",
+ "proxy-authenticate",
+ "proxy-authorization",
+ "te",
+ "trailers",
+ "transfer-encoding",
+ "upgrade"};
+ return std::any_of(std::begin(headers), std::end(headers), caseInsensitiveCompare(header));
+}
+
QNetworkCacheMetaData QNetworkReplyHttpImplPrivate::fetchCacheMetaData(const QNetworkCacheMetaData &oldMetaData) const
{
Q_Q(const QNetworkReplyHttpImpl);
@@ -1696,22 +1735,11 @@ QNetworkCacheMetaData QNetworkReplyHttpImplPrivate::fetchCacheMetaData(const QNe
QNetworkHeadersPrivate::RawHeadersList::ConstIterator it;
const QList<QByteArray> newHeaders = q->rawHeaderList();
- for (QByteArray header : newHeaders) {
- QByteArray originalHeader = header;
- header = header.toLower();
- bool hop_by_hop =
- (header == "connection"
- || header == "keep-alive"
- || header == "proxy-authenticate"
- || header == "proxy-authorization"
- || header == "te"
- || header == "trailers"
- || header == "transfer-encoding"
- || header == "upgrade");
- if (hop_by_hop)
+ for (const QByteArray& header : newHeaders) {
+ if (isHopByHop(header))
continue;
- if (header == "set-cookie")
+ if (header.compare("set-cookie", Qt::CaseInsensitive) == 0)
continue;
// for 4.6.0, we were planning to not store the date header in the
@@ -1724,8 +1752,8 @@ QNetworkCacheMetaData QNetworkReplyHttpImplPrivate::fetchCacheMetaData(const QNe
//continue;
// Don't store Warning 1xx headers
- if (header == "warning") {
- QByteArray v = q->rawHeader(header);
+ if (header.compare("warning", Qt::CaseInsensitive) == 0) {
+ const QByteArray v = q->rawHeader(header);
if (v.size() == 3
&& v[0] == '1'
&& isAsciiDigit(v[1])
@@ -1736,15 +1764,15 @@ QNetworkCacheMetaData QNetworkReplyHttpImplPrivate::fetchCacheMetaData(const QNe
it = cacheHeaders.findRawHeader(header);
if (it != cacheHeaders.rawHeaders.constEnd()) {
// Match the behavior of Firefox and assume Cache-Control: "no-transform"
- if (header == "content-encoding"
- || header == "content-range"
- || header == "content-type")
+ constexpr QByteArrayView headers[]=
+ {"content-encoding", "content-range", "content-type"};
+ if (std::any_of(std::begin(headers), std::end(headers), caseInsensitiveCompare(header)))
continue;
}
// IIS has been known to send "Content-Length: 0" on 304 responses, so
// ignore this too
- if (header == "content-length" && statusCode == 304)
+ if (statusCode == 304 && header.compare("content-length", Qt::CaseInsensitive) == 0)
continue;
#if defined(QNETWORKACCESSHTTPBACKEND_DEBUG)
@@ -1752,23 +1780,23 @@ QNetworkCacheMetaData QNetworkReplyHttpImplPrivate::fetchCacheMetaData(const QNe
QByteArray o;
if (it != cacheHeaders.rawHeaders.constEnd())
o = (*it).second;
- if (n != o && header != "date") {
+ if (n != o && headerheader.compare("date", Qt::CaseInsensitive) != 0) {
qDebug() << "replacing" << header;
qDebug() << "new" << n;
qDebug() << "old" << o;
}
#endif
- cacheHeaders.setRawHeader(originalHeader, q->rawHeader(header));
+ cacheHeaders.setRawHeader(header, q->rawHeader(header));
}
metaData.setRawHeaders(cacheHeaders.rawHeaders);
bool checkExpired = true;
QHash<QByteArray, QByteArray> cacheControl;
- it = cacheHeaders.findRawHeader("Cache-Control");
+ it = cacheHeaders.findRawHeader(cacheControlName());
if (it != cacheHeaders.rawHeaders.constEnd()) {
cacheControl = parseHttpOptionHeader(it->second);
- QByteArray maxAge = cacheControl.value("max-age");
+ QByteArray maxAge = cacheControl.value("max-age"_ba);
if (!maxAge.isEmpty()) {
checkExpired = false;
QDateTime dt = QDateTime::currentDateTimeUtc();
@@ -1795,7 +1823,7 @@ QNetworkCacheMetaData QNetworkReplyHttpImplPrivate::fetchCacheMetaData(const QNe
canDiskCache = true;
// HTTP/1.1. Check the Cache-Control header
- if (cacheControl.contains("no-store"))
+ if (cacheControl.contains("no-store"_ba))
canDiskCache = false;
// responses to POST might be cacheable
@@ -1804,7 +1832,7 @@ QNetworkCacheMetaData QNetworkReplyHttpImplPrivate::fetchCacheMetaData(const QNe
canDiskCache = false;
// some pages contain "expires:" and "cache-control: no-cache" field,
// so we only might cache POST requests if we get "cache-control: max-age ..."
- if (cacheControl.contains("max-age"))
+ if (cacheControl.contains("max-age"_ba))
canDiskCache = true;
// responses to PUT and DELETE are not cacheable
@@ -1835,14 +1863,14 @@ bool QNetworkReplyHttpImplPrivate::canResume() const
return false;
// Can only resume if server/resource supports Range header.
- QByteArray acceptRangesheaderName("Accept-Ranges");
+ constexpr auto acceptRangesheaderName = QByteArrayView("Accept-Ranges");
if (!q->hasRawHeader(acceptRangesheaderName) || q->rawHeader(acceptRangesheaderName) == "none")
return false;
// We only support resuming for byte ranges.
- if (request.hasRawHeader("Range")) {
- QByteArray range = request.rawHeader("Range");
- if (!range.startsWith("bytes="))
+ if (request.hasRawHeader(rangeName())) {
+ QByteArray range = request.rawHeader(rangeName());
+ if (!range.startsWith(bytesEqualPrefix()))
return false;
}
@@ -1861,7 +1889,9 @@ void QNetworkReplyHttpImplPrivate::setResumeOffset(quint64 offset)
void QNetworkReplyHttpImplPrivate::_q_startOperation()
{
- if (state == Working) // ensure this function is only being called once
+ // Ensure this function is only being called once, and not at all if we were
+ // cancelled
+ if (state >= Working)
return;
state = Working;
@@ -2021,9 +2051,9 @@ void QNetworkReplyHttpImplPrivate::setupTransferTimeout()
Qt::QueuedConnection);
}
transferTimeout->stop();
- if (request.transferTimeout()) {
+ if (request.transferTimeoutAsDuration() > 0ms) {
transferTimeout->setSingleShot(true);
- transferTimeout->setInterval(request.transferTimeout());
+ transferTimeout->setInterval(request.transferTimeoutAsDuration());
QMetaObject::invokeMethod(transferTimeout, "start",
Qt::QueuedConnection);
@@ -2129,7 +2159,9 @@ void QNetworkReplyHttpImplPrivate::error(QNetworkReplyImpl::NetworkError code, c
Q_Q(QNetworkReplyHttpImpl);
// Can't set and emit multiple errors.
if (errorCode != QNetworkReply::NoError) {
- qWarning("QNetworkReplyImplPrivate::error: Internal problem, this method must only be called once.");
+ // But somewhat unavoidable if we have cancelled the request:
+ if (errorCode != QNetworkReply::OperationCanceledError)
+ qWarning("QNetworkReplyImplPrivate::error: Internal problem, this method must only be called once.");
return;
}
diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h
index 11897d1420..e00c43bdb3 100644
--- a/src/network/access/qnetworkreplyhttpimpl_p.h
+++ b/src/network/access/qnetworkreplyhttpimpl_p.h
@@ -244,7 +244,7 @@ public:
// From HTTP thread:
void replyDownloadData(QByteArray);
void replyFinished();
- void replyDownloadMetaData(const QList<QPair<QByteArray,QByteArray> > &, int, const QString &,
+ void replyDownloadMetaData(const QHttpHeaders &, int, const QString &,
bool, QSharedPointer<char>, qint64, qint64, bool, bool);
void replyDownloadProgressSlot(qint64,qint64);
void httpAuthenticationRequired(const QHttpNetworkRequest &request, QAuthenticator *auth);
diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp
index 2c713e69fd..8b2acfdb4e 100644
--- a/src/network/access/qnetworkreplyimpl.cpp
+++ b/src/network/access/qnetworkreplyimpl.cpp
@@ -519,11 +519,6 @@ void QNetworkReplyImplPrivate::appendDownstreamData(QIODevice *data)
_q_copyReadyRead();
}
-static void downloadBufferDeleter(char *ptr)
-{
- delete[] ptr;
-}
-
char* QNetworkReplyImplPrivate::getDownloadBuffer(qint64 size)
{
Q_Q(QNetworkReplyImpl);
@@ -536,7 +531,7 @@ char* QNetworkReplyImplPrivate::getDownloadBuffer(qint64 size)
downloadBufferCurrentSize = 0;
downloadBufferMaximumSize = size;
downloadBuffer = new char[downloadBufferMaximumSize]; // throws if allocation fails
- downloadBufferPointer = QSharedPointer<char>(downloadBuffer, downloadBufferDeleter);
+ downloadBufferPointer = QSharedPointer<char>(downloadBuffer, [](auto p) { delete[] p; });
q->setAttribute(QNetworkRequest::DownloadBufferAttribute, QVariant::fromValue<QSharedPointer<char> > (downloadBufferPointer));
}
diff --git a/src/network/access/qnetworkreplywasmimpl.cpp b/src/network/access/qnetworkreplywasmimpl.cpp
index b7fec9345a..c02f0b4e61 100644
--- a/src/network/access/qnetworkreplywasmimpl.cpp
+++ b/src/network/access/qnetworkreplywasmimpl.cpp
@@ -62,7 +62,7 @@ QNetworkReplyWasmImplPrivate::QNetworkReplyWasmImplPrivate()
, downloadBufferCurrentSize(0)
, totalDownloadSize(0)
, percentFinished(0)
- , m_fetch(0)
+ , m_fetch(nullptr)
{
}
@@ -79,6 +79,9 @@ QNetworkReplyWasmImpl::QNetworkReplyWasmImpl(QObject *parent)
QNetworkReplyWasmImpl::~QNetworkReplyWasmImpl()
{
+ if (isRunning())
+ abort();
+ close();
}
QByteArray QNetworkReplyWasmImpl::methodName() const
@@ -131,7 +134,8 @@ void QNetworkReplyWasmImpl::abort()
void QNetworkReplyWasmImplPrivate::setCanceled()
{
Q_Q(QNetworkReplyWasmImpl);
- m_fetch->userData = nullptr;
+ if (m_fetch)
+ m_fetch->userData = nullptr;
emitReplyError(QNetworkReply::OperationCanceledError, QStringLiteral("Operation canceled"));
q->setFinished(true);
@@ -282,10 +286,8 @@ void QNetworkReplyWasmImplPrivate::doSendRequest()
request.attribute(QNetworkRequest::CacheSaveControlAttribute, false).toBool()) {
attr.attributes -= EMSCRIPTEN_FETCH_PERSIST_FILE;
}
- if (request.attribute(QNetworkRequest::UseCredentialsAttribute, true).toBool()) {
- attr.withCredentials = true;
- }
+ attr.withCredentials = request.attribute(QNetworkRequest::UseCredentialsAttribute, false).toBool();
attr.onsuccess = QNetworkReplyWasmImplPrivate::downloadSucceeded;
attr.onerror = QNetworkReplyWasmImplPrivate::downloadFailed;
attr.onprogress = QNetworkReplyWasmImplPrivate::downloadProgress;
@@ -293,11 +295,11 @@ void QNetworkReplyWasmImplPrivate::doSendRequest()
attr.timeoutMSecs = request.transferTimeout();
attr.userData = reinterpret_cast<void *>(this);
- QString dPath = QStringLiteral("/home/web_user/") + request.url().fileName();
+ QString dPath = "/home/web_user/"_L1 + request.url().fileName();
QByteArray destinationPath = dPath.toUtf8();
attr.destinationPath = destinationPath.constData();
- m_fetch = emscripten_fetch(&attr, request.url().toString().toUtf8());
+ m_fetch = emscripten_fetch(&attr, request.url().toString().toUtf8().constData());
state = Working;
}
@@ -315,15 +317,16 @@ void QNetworkReplyWasmImplPrivate::emitDataReadProgress(qint64 bytesReceived, qi
totalDownloadSize = bytesTotal;
- percentFinished = (bytesReceived / bytesTotal) * 100;
+ percentFinished = bytesTotal ? (bytesReceived / bytesTotal) * 100 : 100;
emit q->downloadProgress(bytesReceived, bytesTotal);
}
-void QNetworkReplyWasmImplPrivate::dataReceived(const QByteArray &buffer, int bufferSize)
+void QNetworkReplyWasmImplPrivate::dataReceived(const QByteArray &buffer)
{
Q_Q(QNetworkReplyWasmImpl);
+ const qsizetype bufferSize = buffer.size();
if (bufferSize > 0)
q->setReadBufferSize(bufferSize);
@@ -336,7 +339,7 @@ void QNetworkReplyWasmImplPrivate::dataReceived(const QByteArray &buffer, int bu
totalDownloadSize = downloadBufferCurrentSize;
- downloadBuffer.append(buffer, bufferSize);
+ downloadBuffer.append(buffer);
emit q->readyRead();
}
@@ -478,7 +481,7 @@ void QNetworkReplyWasmImplPrivate::downloadSucceeded(emscripten_fetch_t *fetch)
if (reply) {
if (reply->state != QNetworkReplyPrivate::Aborted) {
QByteArray buffer(fetch->data, fetch->numBytes);
- reply->dataReceived(buffer, buffer.size());
+ reply->dataReceived(buffer);
QByteArray statusText(fetch->statusText);
reply->setStatusCode(fetch->status, statusText);
reply->setReplyFinished();
@@ -491,6 +494,7 @@ void QNetworkReplyWasmImplPrivate::downloadSucceeded(emscripten_fetch_t *fetch)
void QNetworkReplyWasmImplPrivate::setReplyFinished()
{
Q_Q(QNetworkReplyWasmImpl);
+ state = QNetworkReplyPrivate::Finished;
q->setFinished(true);
emit q->readChannelFinished();
emit q->finished();
@@ -540,6 +544,8 @@ void QNetworkReplyWasmImplPrivate::downloadFailed(emscripten_fetch_t *fetch)
reasonStr = QStringLiteral("Operation canceled");
else
reasonStr = QString::fromUtf8(fetch->statusText);
+ QByteArray buffer(fetch->data, fetch->numBytes);
+ reply->dataReceived(buffer);
QByteArray statusText(fetch->statusText);
reply->setStatusCode(fetch->status, statusText);
reply->emitReplyError(reply->statusCodeFromHttp(fetch->status, reply->request.url()), reasonStr);
diff --git a/src/network/access/qnetworkreplywasmimpl_p.h b/src/network/access/qnetworkreplywasmimpl_p.h
index d8c814621b..ae167799d7 100644
--- a/src/network/access/qnetworkreplywasmimpl_p.h
+++ b/src/network/access/qnetworkreplywasmimpl_p.h
@@ -57,7 +57,7 @@ public:
Q_PRIVATE_SLOT(d_func(), void emitReplyError(QNetworkReply::NetworkError errorCode, const QString &errorString))
Q_PRIVATE_SLOT(d_func(), void emitDataReadProgress(qint64 done, qint64 total))
- Q_PRIVATE_SLOT(d_func(), void dataReceived(char *buffer, int bufferSize))
+ Q_PRIVATE_SLOT(d_func(), void dataReceived(const QByteArray &buffer))
private:
QByteArray methodName() const;
@@ -75,7 +75,7 @@ public:
void emitReplyError(QNetworkReply::NetworkError errorCode, const QString &);
void emitDataReadProgress(qint64 done, qint64 total);
- void dataReceived(const QByteArray &buffer, int bufferSize);
+ void dataReceived(const QByteArray &buffer);
void headersReceived(const QByteArray &buffer);
void setStatusCode(int status, const QByteArray &statusText);
diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp
index bf46e8a4b5..a59de42a44 100644
--- a/src/network/access/qnetworkrequest.cpp
+++ b/src/network/access/qnetworkrequest.cpp
@@ -6,7 +6,8 @@
#include "qplatformdefs.h"
#include "qnetworkcookie.h"
#include "qsslconfiguration.h"
-#if QT_CONFIG(http) || defined(Q_QDOC)
+#include "qhttpheadershelper_p.h"
+#if QT_CONFIG(http)
#include "qhttp1configuration.h"
#include "qhttp2configuration.h"
#include "private/http2protocol_p.h"
@@ -28,6 +29,9 @@
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
+using namespace std::chrono_literals;
+
+constexpr std::chrono::milliseconds QNetworkRequest::DefaultTransferTimeout;
QT_IMPL_METATYPE_EXTERN(QNetworkRequest)
QT_IMPL_METATYPE_EXTERN_TAGGED(QNetworkRequest::RedirectPolicy, QNetworkRequest__RedirectPolicy)
@@ -407,6 +411,16 @@ QT_IMPL_METATYPE_EXTERN_TAGGED(QNetworkRequest::RedirectPolicy, QNetworkRequest_
\value DefaultTransferTimeoutConstant The transfer timeout in milliseconds.
Used if setTimeout() is called
without an argument.
+
+ \sa QNetworkRequest::DefaultTransferTimeout
+ */
+
+/*!
+ \variable QNetworkRequest::DefaultTransferTimeout
+
+ The transfer timeout with \l {QNetworkRequest::TransferTimeoutConstant}
+ milliseconds. Used if setTransferTimeout() is called without an
+ argument.
*/
class QNetworkRequestPrivate: public QSharedData, public QNetworkHeadersPrivate
@@ -419,7 +433,6 @@ public:
, sslConfiguration(nullptr)
#endif
, maxRedirectsAllowed(maxRedirectCount)
- , transferTimeout(0)
{ qRegisterMetaType<QNetworkRequest>(); }
~QNetworkRequestPrivate()
{
@@ -463,6 +476,7 @@ public:
&& decompressedSafetyCheckThreshold == other.decompressedSafetyCheckThreshold
#endif
&& transferTimeout == other.transferTimeout
+ && QHttpHeadersHelper::compareStrict(httpHeaders, other.httpHeaders)
;
// don't compare cookedHeaders
}
@@ -479,7 +493,7 @@ public:
QHttp2Configuration h2Configuration;
qint64 decompressedSafetyCheckThreshold = 10ll * 1024ll * 1024ll;
#endif
- int transferTimeout;
+ std::chrono::milliseconds transferTimeout = 0ms;
};
/*!
@@ -589,6 +603,43 @@ void QNetworkRequest::setUrl(const QUrl &url)
}
/*!
+ \since 6.8
+
+ Returns headers that are set in this network request.
+
+ \sa setHeaders()
+*/
+QHttpHeaders QNetworkRequest::headers() const
+{
+ return d->headers();
+}
+
+/*!
+ \since 6.8
+
+ Sets \a newHeaders as headers in this network request, overriding
+ any previously set headers.
+
+ If some headers correspond to the known headers, the values will
+ be parsed and the corresponding parsed form will also be set.
+
+ \sa headers(), KnownHeaders
+*/
+void QNetworkRequest::setHeaders(QHttpHeaders &&newHeaders)
+{
+ d->setHeaders(std::move(newHeaders));
+}
+
+/*!
+ \overload
+ \since 6.8
+*/
+void QNetworkRequest::setHeaders(const QHttpHeaders &newHeaders)
+{
+ d->setHeaders(newHeaders);
+}
+
+/*!
Returns the value of the known network header \a header if it is
present in this request. If it is not present, returns QVariant()
(i.e., an invalid variant).
@@ -617,8 +668,9 @@ void QNetworkRequest::setHeader(KnownHeaders header, const QVariant &value)
network request.
\sa rawHeader(), setRawHeader()
+ \note In Qt versions prior to 6.7, this function took QByteArray only.
*/
-bool QNetworkRequest::hasRawHeader(const QByteArray &headerName) const
+bool QNetworkRequest::hasRawHeader(QAnyStringView headerName) const
{
return d->findRawHeader(headerName) != d->rawHeaders.constEnd();
}
@@ -632,12 +684,11 @@ bool QNetworkRequest::hasRawHeader(const QByteArray &headerName) const
Raw headers can be set with setRawHeader() or with setHeader().
\sa header(), setRawHeader()
+ \note In Qt versions prior to 6.7, this function took QByteArray only.
*/
-QByteArray QNetworkRequest::rawHeader(const QByteArray &headerName) const
+QByteArray QNetworkRequest::rawHeader(QAnyStringView headerName) const
{
- QNetworkHeadersPrivate::RawHeadersList::ConstIterator it =
- d->findRawHeader(headerName);
- if (it != d->rawHeaders.constEnd())
+ if (const auto it = d->findRawHeader(headerName); it != d->rawHeaders.constEnd())
return it->second;
return QByteArray();
}
@@ -859,7 +910,7 @@ void QNetworkRequest::setPeerVerifyName(const QString &peerName)
d->peerVerifyName = peerName;
}
-#if QT_CONFIG(http) || defined(Q_QDOC)
+#if QT_CONFIG(http)
/*!
\since 6.5
@@ -969,85 +1020,104 @@ void QNetworkRequest::setDecompressedSafetyCheckThreshold(qint64 threshold)
{
d->decompressedSafetyCheckThreshold = threshold;
}
-#endif // QT_CONFIG(http) || defined(Q_QDOC)
+#endif // QT_CONFIG(http)
-#if QT_CONFIG(http) || defined(Q_QDOC) || defined (Q_OS_WASM)
+#if QT_CONFIG(http) || defined (Q_OS_WASM)
/*!
+ \fn int QNetworkRequest::transferTimeout() const
\since 5.15
Returns the timeout used for transfers, in milliseconds.
- This timeout is zero if setTransferTimeout hasn't been
- called, which means that the timeout is not used.
+ \sa setTransferTimeout()
+*/
+
+/*!
+ \fn void QNetworkRequest::setTransferTimeout(int timeout)
+ \since 5.15
+
+ Sets \a timeout as the transfer timeout in milliseconds.
+
+ \sa setTransferTimeout(std::chrono::milliseconds),
+ transferTimeout(), transferTimeoutAsDuration()
+*/
+
+/*!
+ \since 6.7
+
+ Returns the timeout duration after which the transfer is aborted if no
+ data is exchanged.
+
+ The default duration is zero, which means that the timeout is not used.
- \sa setTransferTimeout
+ \sa setTransferTimeout(std::chrono::milliseconds)
*/
-int QNetworkRequest::transferTimeout() const
+std::chrono::milliseconds QNetworkRequest::transferTimeoutAsDuration() const
{
return d->transferTimeout;
}
/*!
- \since 5.15
+ \since 6.7
- Sets \a timeout as the transfer timeout in milliseconds.
+ Sets the timeout \a duration to abort the transfer if no data is exchanged.
Transfers are aborted if no bytes are transferred before
the timeout expires. Zero means no timer is set. If no
argument is provided, the timeout is
- QNetworkRequest::DefaultTransferTimeoutConstant. If this function
+ QNetworkRequest::DefaultTransferTimeout. If this function
is not called, the timeout is disabled and has the
value zero.
- \sa transferTimeout
+ \sa transferTimeoutAsDuration()
*/
-void QNetworkRequest::setTransferTimeout(int timeout)
+void QNetworkRequest::setTransferTimeout(std::chrono::milliseconds duration)
{
- d->transferTimeout = timeout;
+ d->transferTimeout = duration;
}
-#endif // QT_CONFIG(http) || defined(Q_QDOC) || defined (Q_OS_WASM)
+#endif // QT_CONFIG(http) || defined (Q_OS_WASM)
static QByteArray headerName(QNetworkRequest::KnownHeaders header)
{
switch (header) {
case QNetworkRequest::ContentTypeHeader:
- return "Content-Type";
+ return "Content-Type"_ba;
case QNetworkRequest::ContentLengthHeader:
- return "Content-Length";
+ return "Content-Length"_ba;
case QNetworkRequest::LocationHeader:
- return "Location";
+ return "Location"_ba;
case QNetworkRequest::LastModifiedHeader:
- return "Last-Modified";
+ return "Last-Modified"_ba;
case QNetworkRequest::IfModifiedSinceHeader:
- return "If-Modified-Since";
+ return "If-Modified-Since"_ba;
case QNetworkRequest::ETagHeader:
- return "ETag";
+ return "ETag"_ba;
case QNetworkRequest::IfMatchHeader:
- return "If-Match";
+ return "If-Match"_ba;
case QNetworkRequest::IfNoneMatchHeader:
- return "If-None-Match";
+ return "If-None-Match"_ba;
case QNetworkRequest::CookieHeader:
- return "Cookie";
+ return "Cookie"_ba;
case QNetworkRequest::SetCookieHeader:
- return "Set-Cookie";
+ return "Set-Cookie"_ba;
case QNetworkRequest::ContentDispositionHeader:
- return "Content-Disposition";
+ return "Content-Disposition"_ba;
case QNetworkRequest::UserAgentHeader:
- return "User-Agent";
+ return "User-Agent"_ba;
case QNetworkRequest::ServerHeader:
- return "Server";
+ return "Server"_ba;
// no default:
// if new values are added, this will generate a compiler warning
@@ -1056,6 +1126,22 @@ static QByteArray headerName(QNetworkRequest::KnownHeaders header)
return QByteArray();
}
+static QByteArray makeCookieHeader(const QVariant &value, QNetworkCookie::RawForm type, QByteArrayView separator)
+{
+ QList<QNetworkCookie> cookies = qvariant_cast<QList<QNetworkCookie> >(value);
+ if (cookies.isEmpty() && value.userType() == qMetaTypeId<QNetworkCookie>())
+ cookies << qvariant_cast<QNetworkCookie>(value);
+
+ QByteArray result;
+ for (const QNetworkCookie &cookie : std::as_const(cookies)) {
+ result += cookie.toRawForm(type);
+ result += separator;
+ }
+ if (!result.isEmpty())
+ result.chop(separator.size());
+ return result;
+}
+
static QByteArray headerValue(QNetworkRequest::KnownHeaders header, const QVariant &value)
{
switch (header) {
@@ -1091,49 +1177,23 @@ static QByteArray headerValue(QNetworkRequest::KnownHeaders header, const QVaria
return value.toByteArray();
}
- case QNetworkRequest::CookieHeader: {
- QList<QNetworkCookie> cookies = qvariant_cast<QList<QNetworkCookie> >(value);
- if (cookies.isEmpty() && value.userType() == qMetaTypeId<QNetworkCookie>())
- cookies << qvariant_cast<QNetworkCookie>(value);
-
- QByteArray result;
- bool first = true;
- for (const QNetworkCookie &cookie : std::as_const(cookies)) {
- if (!first)
- result += "; ";
- first = false;
- result += cookie.toRawForm(QNetworkCookie::NameAndValueOnly);
- }
- return result;
- }
+ case QNetworkRequest::CookieHeader:
+ return makeCookieHeader(value, QNetworkCookie::NameAndValueOnly, "; ");
- case QNetworkRequest::SetCookieHeader: {
- QList<QNetworkCookie> cookies = qvariant_cast<QList<QNetworkCookie> >(value);
- if (cookies.isEmpty() && value.userType() == qMetaTypeId<QNetworkCookie>())
- cookies << qvariant_cast<QNetworkCookie>(value);
-
- QByteArray result;
- bool first = true;
- for (const QNetworkCookie &cookie : std::as_const(cookies)) {
- if (!first)
- result += ", ";
- first = false;
- result += cookie.toRawForm(QNetworkCookie::Full);
- }
- return result;
- }
+ case QNetworkRequest::SetCookieHeader:
+ return makeCookieHeader(value, QNetworkCookie::Full, ", ");
}
return QByteArray();
}
-static int parseHeaderName(const QByteArray &headerName)
+static int parseHeaderName(QByteArrayView headerName)
{
if (headerName.isEmpty())
return -1;
- auto is = [&](const char *what) {
- return qstrnicmp(headerName.data(), headerName.size(), what) == 0;
+ auto is = [headerName](QByteArrayView what) {
+ return headerName.compare(what, Qt::CaseInsensitive) == 0;
};
switch (QtMiscUtils::toAsciiLower(headerName.front())) {
@@ -1193,11 +1253,10 @@ static QVariant parseHttpDate(const QByteArray &raw)
return QVariant(); // transform an invalid QDateTime into a null QVariant
}
-static QVariant parseCookieHeader(const QByteArray &raw)
+static QVariant parseCookieHeader(QByteArrayView raw)
{
QList<QNetworkCookie> result;
- const QList<QByteArray> cookieList = raw.split(';');
- for (const QByteArray &cookie : cookieList) {
+ for (auto cookie : QLatin1StringView(raw).tokenize(';'_L1)) {
QList<QNetworkCookie> parsed = QNetworkCookie::parseCookies(cookie.trimmed());
if (parsed.size() != 1)
return QVariant(); // invalid Cookie: header
@@ -1208,9 +1267,9 @@ static QVariant parseCookieHeader(const QByteArray &raw)
return QVariant::fromValue(result);
}
-static QVariant parseETag(const QByteArray &raw)
+static QVariant parseETag(QByteArrayView raw)
{
- const QByteArray trimmed = raw.trimmed();
+ const QByteArrayView trimmed = raw.trimmed();
if (!trimmed.startsWith('"') && !trimmed.startsWith(R"(W/")"))
return QVariant();
@@ -1220,46 +1279,34 @@ static QVariant parseETag(const QByteArray &raw)
return QString::fromLatin1(trimmed);
}
-static QVariant parseIfMatch(const QByteArray &raw)
+template<typename T>
+static QVariant parseMatchImpl(QByteArrayView raw, T op)
{
- const QByteArray trimmedRaw = raw.trimmed();
+ const QByteArrayView trimmedRaw = raw.trimmed();
if (trimmedRaw == "*")
return QStringList(QStringLiteral("*"));
QStringList tags;
- const QList<QByteArray> split = trimmedRaw.split(',');
- for (const QByteArray &element : split) {
- const QByteArray trimmed = element.trimmed();
- if (!trimmed.startsWith('"'))
- continue;
-
- if (!trimmed.endsWith('"'))
- continue;
-
- tags += QString::fromLatin1(trimmed);
+ for (auto &element : QLatin1StringView(trimmedRaw).tokenize(','_L1)) {
+ if (const auto trimmed = element.trimmed(); op(trimmed))
+ tags += QString::fromLatin1(trimmed);
}
return tags;
}
-static QVariant parseIfNoneMatch(const QByteArray &raw)
-{
- const QByteArray trimmedRaw = raw.trimmed();
- if (trimmedRaw == "*")
- return QStringList(QStringLiteral("*"));
- QStringList tags;
- const QList<QByteArray> split = trimmedRaw.split(',');
- for (const QByteArray &element : split) {
- const QByteArray trimmed = element.trimmed();
- if (!trimmed.startsWith('"') && !trimmed.startsWith(R"(W/")"))
- continue;
-
- if (!trimmed.endsWith('"'))
- continue;
+static QVariant parseIfMatch(QByteArrayView raw)
+{
+ return parseMatchImpl(raw, [](QByteArrayView element) {
+ return element.startsWith('"') && element.endsWith('"');
+ });
+}
- tags += QString::fromLatin1(trimmed);
- }
- return tags;
+static QVariant parseIfNoneMatch(QByteArrayView raw)
+{
+ return parseMatchImpl(raw, [](QByteArrayView element) {
+ return (element.startsWith('"') || element.startsWith(R"(W/")")) && element.endsWith('"');
+ });
}
@@ -1276,7 +1323,7 @@ static QVariant parseHeaderValue(QNetworkRequest::KnownHeaders header, const QBy
case QNetworkRequest::ContentLengthHeader: {
bool ok;
- qint64 result = value.trimmed().toLongLong(&ok);
+ qint64 result = QByteArrayView(value).trimmed().toLongLong(&ok);
if (ok)
return result;
return QVariant();
@@ -1315,15 +1362,14 @@ static QVariant parseHeaderValue(QNetworkRequest::KnownHeaders header, const QBy
}
QNetworkHeadersPrivate::RawHeadersList::ConstIterator
-QNetworkHeadersPrivate::findRawHeader(const QByteArray &key) const
+QNetworkHeadersPrivate::findRawHeader(QAnyStringView key) const
{
- RawHeadersList::ConstIterator it = rawHeaders.constBegin();
- RawHeadersList::ConstIterator end = rawHeaders.constEnd();
- for ( ; it != end; ++it)
- if (it->first.compare(key, Qt::CaseInsensitive) == 0)
- return it;
-
- return end; // not found
+ auto isKeyEqual = [key](const auto &headerPair)
+ {
+ QLatin1StringView name{headerPair.first};
+ return QAnyStringView::compare(name, key, Qt::CaseInsensitive) == 0;
+ };
+ return std::find_if(rawHeaders.begin(), rawHeaders.end(), isKeyEqual);
}
QNetworkHeadersPrivate::RawHeadersList QNetworkHeadersPrivate::allRawHeaders() const
@@ -1335,10 +1381,8 @@ QList<QByteArray> QNetworkHeadersPrivate::rawHeadersKeys() const
{
QList<QByteArray> result;
result.reserve(rawHeaders.size());
- RawHeadersList::ConstIterator it = rawHeaders.constBegin(),
- end = rawHeaders.constEnd();
- for ( ; it != end; ++it)
- result << it->first;
+ for (const auto &pair : rawHeaders)
+ result << pair.first;
return result;
}
@@ -1366,10 +1410,8 @@ void QNetworkHeadersPrivate::setAllRawHeaders(const RawHeadersList &list)
cookedHeaders.clear();
rawHeaders = list;
- RawHeadersList::ConstIterator it = rawHeaders.constBegin();
- RawHeadersList::ConstIterator end = rawHeaders.constEnd();
- for ( ; it != end; ++it)
- parseAndSetHeader(it->first, it->second);
+ for (const auto &[key, value] : std::as_const(rawHeaders))
+ parseAndSetHeader(key, value);
}
void QNetworkHeadersPrivate::setCookedHeader(QNetworkRequest::KnownHeaders header,
@@ -1398,6 +1440,33 @@ void QNetworkHeadersPrivate::setCookedHeader(QNetworkRequest::KnownHeaders heade
}
}
+QHttpHeaders QNetworkHeadersPrivate::headers() const
+{
+ return httpHeaders;
+}
+
+void QNetworkHeadersPrivate::setHeaders(const QHttpHeaders &newHeaders)
+{
+ httpHeaders = newHeaders;
+}
+
+void QNetworkHeadersPrivate::setHeaders(QHttpHeaders &&newHeaders)
+{
+ httpHeaders = std::move(newHeaders);
+}
+
+void QNetworkHeadersPrivate::setHeader(QHttpHeaders::WellKnownHeader name, QByteArrayView value)
+{
+ httpHeaders.replaceOrAppend(name, value);
+}
+
+void QNetworkHeadersPrivate::clearHeaders()
+{
+ httpHeaders.clear();
+ rawHeaders.clear();
+ cookedHeaders.clear();
+}
+
void QNetworkHeadersPrivate::setRawHeaderInternal(const QByteArray &key, const QByteArray &value)
{
auto firstEqualsKey = [&key](const RawHeaderPair &header) {
@@ -1533,4 +1602,59 @@ QByteArray QNetworkHeadersPrivate::toHttpDate(const QDateTime &dt)
return QLocale::c().toString(dt.toUTC(), u"ddd, dd MMM yyyy hh:mm:ss 'GMT'").toLatin1();
}
+QNetworkHeadersPrivate::RawHeadersList QNetworkHeadersPrivate::fromHttpToRaw(const QHttpHeaders &headers)
+{
+ if (headers.isEmpty())
+ return {};
+
+ QNetworkHeadersPrivate::RawHeadersList list;
+ QHash<QByteArray, qsizetype> nameToIndex;
+ list.reserve(headers.size());
+ nameToIndex.reserve(headers.size());
+
+ for (qsizetype i = 0; i < headers.size(); ++i) {
+ const auto nameL1 = headers.nameAt(i);
+ const auto value = headers.valueAt(i);
+
+ const bool isSetCookie = nameL1 == QHttpHeaders::wellKnownHeaderName(
+ QHttpHeaders::WellKnownHeader::SetCookie);
+
+ const auto name = QByteArray(nameL1.data(), nameL1.size());
+ if (auto it = nameToIndex.find(name); it != nameToIndex.end()) {
+ list[it.value()].second += isSetCookie ? "\n" : ", ";
+ list[it.value()].second += value;
+ } else {
+ nameToIndex[name] = list.size();
+ list.emplaceBack(name, value.toByteArray());
+ }
+ }
+
+ return list;
+}
+
+QHttpHeaders QNetworkHeadersPrivate::fromRawToHttp(const RawHeadersList &raw)
+{
+ if (raw.empty())
+ return {};
+
+ QHttpHeaders headers;
+ headers.reserve(raw.size());
+
+ for (const auto &[key, value] : raw) {
+ const bool isSetCookie = key.compare(QHttpHeaders::wellKnownHeaderName(
+ QHttpHeaders::WellKnownHeader::SetCookie),
+ Qt::CaseInsensitive) == 0;
+ if (isSetCookie) {
+ for (auto header : QLatin1StringView(value).tokenize('\n'_L1))
+ headers.append(key, header);
+ } else {
+ headers.append(key, value);
+ }
+ }
+
+ return headers;
+}
+
QT_END_NAMESPACE
+
+#include "moc_qnetworkrequest.cpp"
diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h
index 3476aa0273..875c787673 100644
--- a/src/network/access/qnetworkrequest.h
+++ b/src/network/access/qnetworkrequest.h
@@ -5,6 +5,7 @@
#define QNETWORKREQUEST_H
#include <QtNetwork/qtnetworkglobal.h>
+#include <QtNetwork/qhttpheaders.h>
#include <QtCore/QSharedDataPointer>
#include <QtCore/QString>
#include <QtCore/QUrl>
@@ -19,6 +20,7 @@ class QHttp1Configuration;
class QNetworkRequestPrivate;
class Q_NETWORK_EXPORT QNetworkRequest
{
+ Q_GADGET
public:
enum KnownHeaders {
ContentTypeHeader,
@@ -35,6 +37,8 @@ public:
IfMatchHeader,
IfNoneMatchHeader
};
+ Q_ENUM(KnownHeaders)
+
enum Attribute {
HttpStatusCodeAttribute,
HttpReasonPhraseAttribute,
@@ -97,6 +101,9 @@ public:
DefaultTransferTimeoutConstant = 30000
};
+ static constexpr auto DefaultTransferTimeout =
+ std::chrono::milliseconds(DefaultTransferTimeoutConstant);
+
QNetworkRequest();
explicit QNetworkRequest(const QUrl &url);
QNetworkRequest(const QNetworkRequest &other);
@@ -113,14 +120,24 @@ public:
QUrl url() const;
void setUrl(const QUrl &url);
+ QHttpHeaders headers() const;
+ void setHeaders(const QHttpHeaders &newHeaders);
+ void setHeaders(QHttpHeaders &&newHeaders);
+
// "cooked" headers
QVariant header(KnownHeaders header) const;
void setHeader(KnownHeaders header, const QVariant &value);
// raw headers:
+#if QT_NETWORK_REMOVED_SINCE(6, 7)
bool hasRawHeader(const QByteArray &headerName) const;
+#endif
+ bool hasRawHeader(QAnyStringView headerName) const;
QList<QByteArray> rawHeaderList() const;
+#if QT_NETWORK_REMOVED_SINCE(6, 7)
QByteArray rawHeader(const QByteArray &headerName) const;
+#endif
+ QByteArray rawHeader(QAnyStringView headerName) const;
void setRawHeader(const QByteArray &headerName, const QByteArray &value);
// attributes
@@ -144,7 +161,7 @@ public:
QString peerVerifyName() const;
void setPeerVerifyName(const QString &peerName);
-#if QT_CONFIG(http) || defined(Q_QDOC)
+#if QT_CONFIG(http)
QHttp1Configuration http1Configuration() const;
void setHttp1Configuration(const QHttp1Configuration &configuration);
@@ -153,12 +170,17 @@ public:
qint64 decompressedSafetyCheckThreshold() const;
void setDecompressedSafetyCheckThreshold(qint64 threshold);
-#endif // QT_CONFIG(http) || defined(Q_QDOC)
+#endif // QT_CONFIG(http)
-#if QT_CONFIG(http) || defined(Q_QDOC) || defined (Q_OS_WASM)
+#if QT_CONFIG(http) || defined (Q_OS_WASM)
+ QT_NETWORK_INLINE_SINCE(6, 8)
int transferTimeout() const;
- void setTransferTimeout(int timeout = DefaultTransferTimeoutConstant);
-#endif // QT_CONFIG(http) || defined(Q_QDOC) || defined (Q_OS_WASM)
+ QT_NETWORK_INLINE_SINCE(6, 8)
+ void setTransferTimeout(int timeout);
+
+ std::chrono::milliseconds transferTimeoutAsDuration() const;
+ void setTransferTimeout(std::chrono::milliseconds duration = DefaultTransferTimeout);
+#endif // QT_CONFIG(http) || defined (Q_OS_WASM)
private:
QSharedDataPointer<QNetworkRequestPrivate> d;
friend class QNetworkRequestPrivate;
@@ -166,6 +188,20 @@ private:
Q_DECLARE_SHARED(QNetworkRequest)
+#if QT_NETWORK_INLINE_IMPL_SINCE(6, 8)
+#if QT_CONFIG(http) || defined (Q_OS_WASM)
+int QNetworkRequest::transferTimeout() const
+{
+ return int(transferTimeoutAsDuration().count());
+}
+
+void QNetworkRequest::setTransferTimeout(int timeout)
+{
+ setTransferTimeout(std::chrono::milliseconds(timeout));
+}
+#endif // QT_CONFIG(http) || defined (Q_OS_WASM)
+#endif // INLINE_SINCE 6.8
+
QT_END_NAMESPACE
QT_DECL_METATYPE_EXTERN(QNetworkRequest, Q_NETWORK_EXPORT)
diff --git a/src/network/access/qnetworkrequest_p.h b/src/network/access/qnetworkrequest_p.h
index 57fb7b35be..a73d8f2162 100644
--- a/src/network/access/qnetworkrequest_p.h
+++ b/src/network/access/qnetworkrequest_p.h
@@ -16,6 +16,7 @@
//
#include <QtNetwork/private/qtnetworkglobal_p.h>
+#include <QtNetwork/qhttpheaders.h>
#include "qnetworkrequest.h"
#include "QtCore/qbytearray.h"
#include "QtCore/qlist.h"
@@ -36,20 +37,31 @@ public:
typedef QHash<QNetworkRequest::Attribute, QVariant> AttributesMap;
RawHeadersList rawHeaders;
+ QHttpHeaders httpHeaders;
CookedHeadersMap cookedHeaders;
AttributesMap attributes;
QPointer<QObject> originatingObject;
- RawHeadersList::ConstIterator findRawHeader(const QByteArray &key) const;
+ RawHeadersList::ConstIterator findRawHeader(QAnyStringView key) const;
RawHeadersList allRawHeaders() const;
QList<QByteArray> rawHeadersKeys() const;
void setRawHeader(const QByteArray &key, const QByteArray &value);
void setAllRawHeaders(const RawHeadersList &list);
void setCookedHeader(QNetworkRequest::KnownHeaders header, const QVariant &value);
+ QHttpHeaders headers() const;
+ void setHeaders(const QHttpHeaders &newHeaders);
+ void setHeaders(QHttpHeaders &&newHeaders);
+ void setHeader(QHttpHeaders::WellKnownHeader name, QByteArrayView value);
+
+ void clearHeaders();
+
static QDateTime fromHttpDate(const QByteArray &value);
static QByteArray toHttpDate(const QDateTime &dt);
+ static RawHeadersList fromHttpToRaw(const QHttpHeaders &headers);
+ static QHttpHeaders fromRawToHttp(const RawHeadersList &raw);
+
private:
void setRawHeaderInternal(const QByteArray &key, const QByteArray &value);
void parseAndSetHeader(const QByteArray &key, const QByteArray &value);
diff --git a/src/network/access/qnetworkrequestfactory.cpp b/src/network/access/qnetworkrequestfactory.cpp
new file mode 100644
index 0000000000..87738d9086
--- /dev/null
+++ b/src/network/access/qnetworkrequestfactory.cpp
@@ -0,0 +1,727 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qnetworkrequestfactory.h"
+#include "qnetworkrequestfactory_p.h"
+
+#if QT_CONFIG(ssl)
+#include <QtNetwork/qsslconfiguration.h>
+#endif
+
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qmap.h>
+
+QT_BEGIN_NAMESPACE
+
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QNetworkRequestFactoryPrivate)
+
+using namespace Qt::StringLiterals;
+
+Q_LOGGING_CATEGORY(lcQrequestfactory, "qt.network.access.request.factory")
+
+/*!
+ \class QNetworkRequestFactory
+ \since 6.7
+ \ingroup shared
+ \inmodule QtNetwork
+
+ \brief Convenience class for grouping remote server endpoints that share
+ common network request properties.
+
+ \preliminary
+
+ REST servers often have endpoints that require the same headers and other data.
+ Grouping such endpoints with a QNetworkRequestFactory makes it more
+ convenient to issue requests to these endpoints; only the typically
+ varying parts such as \e path and \e query parameters are provided
+ when creating a new request.
+
+ Basic usage steps of QNetworkRequestFactory are as follows:
+ \list
+ \li Instantiation
+ \li Setting the data common to all requests
+ \li Issuing requests
+ \endlist
+
+ An example of usage:
+
+ \snippet code/src_network_access_qnetworkrequestfactory.cpp 0
+*/
+
+/*!
+ Creates a new QNetworkRequestFactory object.
+ Use setBaseUrl() to set a valid base URL for the requests.
+
+ \sa QNetworkRequestFactory(const QUrl &baseUrl), setBaseUrl()
+*/
+
+QNetworkRequestFactory::QNetworkRequestFactory()
+ : d(new QNetworkRequestFactoryPrivate)
+{
+}
+
+/*!
+ Creates a new QNetworkRequestFactory object, initializing the base URL to
+ \a baseUrl. The base URL is used to populate subsequent network
+ requests.
+
+ If the URL contains a \e path component, it will be extracted and used
+ as a base path in subsequent network requests. This means that any
+ paths provided when requesting individual requests will be appended
+ to this base path, as illustrated below:
+
+ \snippet code/src_network_access_qnetworkrequestfactory.cpp 1
+ */
+QNetworkRequestFactory::QNetworkRequestFactory(const QUrl &baseUrl)
+ : d(new QNetworkRequestFactoryPrivate(baseUrl))
+{
+}
+
+/*!
+ Destroys this QNetworkRequestFactory object.
+ */
+QNetworkRequestFactory::~QNetworkRequestFactory()
+ = default;
+
+/*!
+ Creates a copy of \a other.
+ */
+QNetworkRequestFactory::QNetworkRequestFactory(const QNetworkRequestFactory &other)
+ = default;
+
+/*!
+ Creates a copy of \a other and returns a reference to this factory.
+ */
+QNetworkRequestFactory &QNetworkRequestFactory::operator=(const QNetworkRequestFactory &other)
+ = default;
+
+/*!
+ \fn QNetworkRequestFactory::QNetworkRequestFactory(QNetworkRequestFactory &&other) noexcept
+
+ Move-constructs the factory from \a other.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new value.
+*/
+
+/*!
+ \fn QNetworkRequestFactory &QNetworkRequestFactory::operator=(QNetworkRequestFactory &&other) noexcept
+
+ Move-assigns \a other and returns a reference to this factory.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new value.
+ */
+
+/*!
+ \fn void QNetworkRequestFactory::swap(QNetworkRequestFactory &other)
+
+ Swaps this factory with \a other. This operation is
+ very fast and never fails.
+ */
+
+/*!
+ Returns the base URL used for the individual requests.
+
+ The base URL may contain a path component. This path is used
+ as path "prefix" for the paths that are provided when generating
+ individual requests.
+
+ \sa setBaseUrl()
+ */
+QUrl QNetworkRequestFactory::baseUrl() const
+{
+ return d->baseUrl;
+}
+
+/*!
+ Sets the base URL used in individual requests to \a url.
+
+ \sa baseUrl()
+ */
+void QNetworkRequestFactory::setBaseUrl(const QUrl &url)
+{
+ if (d->baseUrl == url)
+ return;
+
+ d.detach();
+ d->baseUrl = url;
+}
+
+#if QT_CONFIG(ssl)
+/*!
+ Returns the SSL configuration set to this factory. The SSL configuration
+ is set to each individual request.
+
+ \sa setSslConfiguration()
+ */
+QSslConfiguration QNetworkRequestFactory::sslConfiguration() const
+{
+ return d->sslConfig;
+}
+
+/*!
+ Sets the SSL configuration to \a configuration.
+
+ \sa sslConfiguration()
+ */
+void QNetworkRequestFactory::setSslConfiguration(const QSslConfiguration &configuration)
+{
+ if (d->sslConfig == configuration)
+ return;
+
+ d.detach();
+ d->sslConfig = configuration;
+}
+#endif
+
+/*!
+ Returns a QNetworkRequest.
+
+ The returned request is filled with the data that this factory
+ has been configured with.
+
+ \sa createRequest(const QUrlQuery&), createRequest(const QString&, const QUrlQuery&)
+*/
+
+QNetworkRequest QNetworkRequestFactory::createRequest() const
+{
+ return d->newRequest(d->requestUrl());
+}
+
+/*!
+ Returns a QNetworkRequest.
+
+ The returned request's URL is formed by appending the provided \a path
+ to the baseUrl (which may itself have a path component).
+
+ \sa createRequest(const QString &, const QUrlQuery &), createRequest(), baseUrl()
+*/
+QNetworkRequest QNetworkRequestFactory::createRequest(const QString &path) const
+{
+ return d->newRequest(d->requestUrl(&path));
+}
+
+/*!
+ Returns a QNetworkRequest.
+
+ The returned request's URL is formed by appending the provided \a query
+ to the baseUrl.
+
+ \sa createRequest(const QString &, const QUrlQuery &), createRequest(), baseUrl()
+*/
+QNetworkRequest QNetworkRequestFactory::createRequest(const QUrlQuery &query) const
+{
+ return d->newRequest(d->requestUrl(nullptr, &query));
+}
+
+/*!
+ Returns a QNetworkRequest.
+
+ The returned requests URL is formed by appending the provided \a path
+ and \a query to the baseUrl (which may have a path component).
+
+ If the provided \a path contains query items, they will be combined
+ with the items in \a query.
+
+ \sa createRequest(const QUrlQuery&), createRequest(), baseUrl()
+ */
+QNetworkRequest QNetworkRequestFactory::createRequest(const QString &path, const QUrlQuery &query) const
+{
+ return d->newRequest(d->requestUrl(&path, &query));
+}
+
+/*!
+ Sets \a headers that are common to all requests.
+
+ These headers are added to individual requests' headers.
+ This is a convenience mechanism for setting headers that
+ repeat across requests.
+
+ \sa commonHeaders(), clearCommonHeaders(), createRequest()
+ */
+void QNetworkRequestFactory::setCommonHeaders(const QHttpHeaders &headers)
+{
+ d.detach();
+ d->headers = headers;
+}
+
+/*!
+ Returns the currently set headers.
+
+ \sa setCommonHeaders(), clearCommonHeaders()
+ */
+QHttpHeaders QNetworkRequestFactory::commonHeaders() const
+{
+ return d->headers;
+}
+
+/*!
+ Clears current headers.
+
+ \sa commonHeaders(), setCommonHeaders()
+*/
+void QNetworkRequestFactory::clearCommonHeaders()
+{
+ if (d->headers.isEmpty())
+ return;
+ d.detach();
+ d->headers.clear();
+}
+
+/*!
+ Returns the bearer token that has been set.
+
+ The bearer token, if present, is used to set the
+ \c {Authorization: Bearer my_token} header for requests. This is a common
+ authorization convention and is provided as an additional convenience.
+
+ The means to acquire the bearer token vary. Standard methods include \c OAuth2
+ and the service provider's website/dashboard. It is expected that the bearer
+ token changes over time. For example, when updated with a refresh token,
+ always setting the new token again ensures that subsequent requests have
+ the latest, valid token.
+
+ The presence of the bearer token does not impact the \l commonHeaders()
+ listing. If the \l commonHeaders() also lists \c Authorization header, it
+ will be overwritten.
+
+ \sa setBearerToken(), commonHeaders()
+ */
+QByteArray QNetworkRequestFactory::bearerToken() const
+{
+ return d->bearerToken;
+}
+
+/*!
+ Sets the bearer token to \a token.
+
+ \sa bearerToken(), clearBearerToken()
+*/
+void QNetworkRequestFactory::setBearerToken(const QByteArray &token)
+{
+ if (d->bearerToken == token)
+ return;
+
+ d.detach();
+ d->bearerToken = token;
+}
+
+/*!
+ Clears the bearer token.
+
+ \sa bearerToken()
+*/
+void QNetworkRequestFactory::clearBearerToken()
+{
+ if (d->bearerToken.isEmpty())
+ return;
+
+ d.detach();
+ d->bearerToken.clear();
+}
+
+/*!
+ Returns the username set to this factory.
+
+ \sa setUserName(), clearUserName(), password()
+*/
+QString QNetworkRequestFactory::userName() const
+{
+ return d->userName;
+}
+
+/*!
+ Sets the username of this factory to \a userName.
+
+ The username is set in the request URL when \l createRequest() is called.
+ The QRestAccessManager / QNetworkAccessManager will attempt to use
+ these credentials when the server indicates that authentication
+ is required.
+
+ \sa userName(), clearUserName(), password()
+*/
+void QNetworkRequestFactory::setUserName(const QString &userName)
+{
+ if (d->userName == userName)
+ return;
+ d.detach();
+ d->userName = userName;
+}
+
+/*!
+ Clears the username set to this factory.
+*/
+void QNetworkRequestFactory::clearUserName()
+{
+ if (d->userName.isEmpty())
+ return;
+ d.detach();
+ d->userName.clear();
+}
+
+/*!
+ Returns the password set to this factory.
+
+ \sa password(), clearPassword(), userName()
+*/
+QString QNetworkRequestFactory::password() const
+{
+ return d->password;
+}
+
+/*!
+ Sets the password of this factory to \a password.
+
+ The password is set in the request URL when \l createRequest() is called.
+ The QRestAccessManager / QNetworkAccessManager will attempt to use
+ these credentials when the server indicates that authentication
+ is required.
+
+ \sa password(), clearPassword(), userName()
+*/
+void QNetworkRequestFactory::setPassword(const QString &password)
+{
+ if (d->password == password)
+ return;
+ d.detach();
+ d->password = password;
+}
+
+/*!
+ Clears the password set to this factory.
+
+ \sa password(), setPassword(), userName()
+*/
+void QNetworkRequestFactory::clearPassword()
+{
+ if (d->password.isEmpty())
+ return;
+ d.detach();
+ d->password.clear();
+}
+
+/*!
+ Sets \a timeout used for transfers.
+
+ \sa transferTimeout(), QNetworkRequest::setTransferTimeout(),
+ QNetworkAccessManager::setTransferTimeout()
+*/
+void QNetworkRequestFactory::setTransferTimeout(std::chrono::milliseconds timeout)
+{
+ if (d->transferTimeout == timeout)
+ return;
+
+ d.detach();
+ d->transferTimeout = timeout;
+}
+
+/*!
+ Returns the timeout used for transfers.
+
+ \sa setTransferTimeout(), QNetworkRequest::transferTimeout(),
+ QNetworkAccessManager::transferTimeout()
+*/
+std::chrono::milliseconds QNetworkRequestFactory::transferTimeout() const
+{
+ return d->transferTimeout;
+}
+
+/*!
+ Returns query parameters that are added to individual requests' query
+ parameters. The query parameters are added to any potential query
+ parameters provided with the individual \l createRequest() calls.
+
+ Use cases for using repeating query parameters are server dependent,
+ but typical examples include language setting \c {?lang=en}, format
+ specification \c {?format=json}, API version specification
+ \c {?version=1.0} and API key authentication.
+
+ \sa setQueryParameters(), clearQueryParameters(), createRequest()
+*/
+QUrlQuery QNetworkRequestFactory::queryParameters() const
+{
+ return d->queryParameters;
+}
+
+/*!
+ Sets \a query parameters that are added to individual requests' query
+ parameters.
+
+ \sa queryParameters(), clearQueryParameters()
+ */
+void QNetworkRequestFactory::setQueryParameters(const QUrlQuery &query)
+{
+ if (d->queryParameters == query)
+ return;
+
+ d.detach();
+ d->queryParameters = query;
+}
+
+/*!
+ Clears the query parameters.
+
+ \sa queryParameters()
+*/
+void QNetworkRequestFactory::clearQueryParameters()
+{
+ if (d->queryParameters.isEmpty())
+ return;
+
+ d.detach();
+ d->queryParameters.clear();
+}
+
+/*!
+ \since 6.8
+
+ Sets the priority for any future requests created by this factory to
+ \a priority.
+
+ The default priority is \l QNetworkRequest::NormalPriority.
+
+ \sa priority(), QNetworkRequest::setPriority()
+*/
+void QNetworkRequestFactory::setPriority(QNetworkRequest::Priority priority)
+{
+ if (d->priority == priority)
+ return;
+ d.detach();
+ d->priority = priority;
+}
+
+/*!
+ \since 6.8
+
+ Returns the priority assigned to any future requests created by this
+ factory.
+
+ \sa setPriority(), QNetworkRequest::priority()
+*/
+QNetworkRequest::Priority QNetworkRequestFactory::priority() const
+{
+ return d->priority;
+}
+
+/*!
+ \since 6.8
+
+ Sets the value associated with \a attribute to \a value.
+ If the attribute is already set, the previous value is
+ replaced. The attributes are set to any future requests
+ created by this factory.
+
+ \sa attribute(), clearAttribute(), clearAttributes(),
+ QNetworkRequest::Attribute
+*/
+void QNetworkRequestFactory::setAttribute(QNetworkRequest::Attribute attribute,
+ const QVariant &value)
+{
+ if (attribute == QNetworkRequest::HttpStatusCodeAttribute
+ || attribute == QNetworkRequest::HttpReasonPhraseAttribute
+ || attribute == QNetworkRequest::RedirectionTargetAttribute
+ || attribute == QNetworkRequest::ConnectionEncryptedAttribute
+ || attribute == QNetworkRequest::SourceIsFromCacheAttribute
+ || attribute == QNetworkRequest::HttpPipeliningWasUsedAttribute
+ || attribute == QNetworkRequest::Http2WasUsedAttribute
+ || attribute == QNetworkRequest::OriginalContentLengthAttribute)
+ {
+ qCWarning(lcQrequestfactory, "%i is a reply-only attribute, ignoring.", attribute);
+ return;
+ }
+ d.detach();
+ d->attributes.insert(attribute, value);
+}
+
+/*!
+ \since 6.8
+
+ Returns the value associated with \a attribute. If the
+ attribute has not been set, returns a default-constructed \l QVariant.
+
+ \sa attribute(QNetworkRequest::Attribute, const QVariant &),
+ setAttribute(), clearAttributes(), QNetworkRequest::Attribute
+
+*/
+QVariant QNetworkRequestFactory::attribute(QNetworkRequest::Attribute attribute) const
+{
+ return d->attributes.value(attribute);
+}
+
+/*!
+ \since 6.8
+
+ Returns the value associated with \a attribute. If the
+ attribute has not been set, returns \a defaultValue.
+
+ \sa attribute(), setAttribute(), clearAttributes(),
+ QNetworkRequest::Attribute
+*/
+QVariant QNetworkRequestFactory::attribute(QNetworkRequest::Attribute attribute,
+ const QVariant &defaultValue) const
+{
+ return d->attributes.value(attribute, defaultValue);
+}
+
+/*!
+ \since 6.8
+
+ Clears \a attribute set to this factory.
+
+ \sa attribute(), setAttribute()
+*/
+void QNetworkRequestFactory::clearAttribute(QNetworkRequest::Attribute attribute)
+{
+ if (!d->attributes.contains(attribute))
+ return;
+ d.detach();
+ d->attributes.remove(attribute);
+}
+
+/*!
+ \since 6.8
+
+ Clears any attributes set to this factory.
+
+ \sa attribute(), setAttribute()
+*/
+void QNetworkRequestFactory::clearAttributes()
+{
+ if (d->attributes.isEmpty())
+ return;
+ d.detach();
+ d->attributes.clear();
+}
+
+QNetworkRequestFactoryPrivate::QNetworkRequestFactoryPrivate()
+ = default;
+
+QNetworkRequestFactoryPrivate::QNetworkRequestFactoryPrivate(const QUrl &baseUrl)
+ : baseUrl(baseUrl)
+{
+}
+
+QNetworkRequestFactoryPrivate::~QNetworkRequestFactoryPrivate()
+ = default;
+
+QNetworkRequest QNetworkRequestFactoryPrivate::newRequest(const QUrl &url) const
+{
+ QNetworkRequest request;
+ request.setUrl(url);
+#if QT_CONFIG(ssl)
+ if (!sslConfig.isNull())
+ request.setSslConfiguration(sslConfig);
+#endif
+ // Set the header entries to the request. Combine values as there
+ // may be multiple values per name. Note: this would not necessarily
+ // produce right result for 'Set-Cookie' header if it has multiple values,
+ // but since it is a purely server-side (response) header, not relevant here.
+ const auto headerNames = headers.toMultiMap().uniqueKeys(); // ### fixme: port QNR to QHH
+ for (const auto &name : headerNames)
+ request.setRawHeader(name, headers.combinedValue(name));
+
+ constexpr char Bearer[] = "Bearer ";
+ if (!bearerToken.isEmpty())
+ request.setRawHeader("Authorization"_ba, Bearer + bearerToken);
+
+ request.setTransferTimeout(transferTimeout);
+ request.setPriority(priority);
+
+ for (const auto &[attribute, value] : attributes.asKeyValueRange())
+ request.setAttribute(attribute, value);
+
+ return request;
+}
+
+QUrl QNetworkRequestFactoryPrivate::requestUrl(const QString *path,
+ const QUrlQuery *query) const
+{
+ const QUrl providedPath = path ? QUrl(*path) : QUrl{};
+ const QUrlQuery providedQuery = query ? *query : QUrlQuery();
+
+ if (!providedPath.scheme().isEmpty() || !providedPath.host().isEmpty()) {
+ qCWarning(lcQrequestfactory, "The provided path %ls may only contain path and query item "
+ "components, and other parts will be ignored. Set the baseUrl instead",
+ qUtf16Printable(providedPath.toDisplayString()));
+ }
+
+ QUrl resultUrl = baseUrl;
+ QUrlQuery resultQuery(providedQuery);
+ QString basePath = baseUrl.path();
+
+ resultUrl.setUserName(userName);
+ resultUrl.setPassword(password);
+
+ // Separate the path and query parameters components on the application-provided path
+ const QString requestPath{providedPath.path()};
+ const QUrlQuery pathQueryItems{providedPath};
+
+ if (!pathQueryItems.isEmpty()) {
+ // Add any query items provided as part of the path
+ const auto items = pathQueryItems.queryItems(QUrl::ComponentFormattingOption::FullyEncoded);
+ for (const auto &[key, value]: items)
+ resultQuery.addQueryItem(key, value);
+ }
+
+ if (!queryParameters.isEmpty()) {
+ // Add any query items set to this factory
+ const QList<std::pair<QString,QString>> items =
+ queryParameters.queryItems(QUrl::ComponentFormattingOption::FullyEncoded);
+ for (const auto &item: items)
+ resultQuery.addQueryItem(item.first, item.second);
+ }
+
+ if (!resultQuery.isEmpty())
+ resultUrl.setQuery(resultQuery);
+
+ if (requestPath.isEmpty())
+ return resultUrl;
+
+ // Ensure that the "base path" (the path that may be present
+ // in the baseUrl), and the request path are joined with one '/'
+ // If both have it, remove one, if neither has it, add one
+ if (basePath.endsWith(u'/') && requestPath.startsWith(u'/'))
+ basePath.chop(1);
+ else if (!requestPath.startsWith(u'/') && !basePath.endsWith(u'/'))
+ basePath.append(u'/');
+
+ resultUrl.setPath(basePath.append(requestPath));
+ return resultUrl;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+/*!
+ \fn QDebug QNetworkRequestFactory::operator<<(QDebug debug,
+ const QNetworkRequestFactory &factory)
+
+ Writes \a factory into \a debug stream.
+
+ \sa {Debugging Techniques}
+*/
+QDebug operator<<(QDebug debug, const QNetworkRequestFactory &factory)
+{
+ const QDebugStateSaver saver(debug);
+ debug.resetFormat().nospace();
+
+ debug << "QNetworkRequestFactory(baseUrl = " << factory.baseUrl()
+ << ", headers = " << factory.commonHeaders()
+ << ", queryParameters = " << factory.queryParameters().queryItems()
+ << ", bearerToken = " << (factory.bearerToken().isEmpty() ? "(empty)" : "(is set)")
+ << ", transferTimeout = " << factory.transferTimeout()
+ << ", userName = " << (factory.userName().isEmpty() ? "(empty)" : "(is set)")
+ << ", password = " << (factory.password().isEmpty() ? "(empty)" : "(is set)")
+#if QT_CONFIG(ssl)
+ << ", SSL configuration"
+ << (factory.sslConfiguration().isNull() ? " is not set (default)" : " is set")
+#else
+ << ", no SSL support"
+#endif
+ << ")";
+ return debug;
+}
+#endif // QT_NO_DEBUG_STREAM
+
+QT_END_NAMESPACE
diff --git a/src/network/access/qnetworkrequestfactory.h b/src/network/access/qnetworkrequestfactory.h
new file mode 100644
index 0000000000..9d955a51e7
--- /dev/null
+++ b/src/network/access/qnetworkrequestfactory.h
@@ -0,0 +1,100 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QNETWORKREQUESTFACTORY_H
+#define QNETWORKREQUESTFACTORY_H
+
+#include <QtNetwork/qnetworkrequest.h>
+#include <QtNetwork/qhttpheaders.h>
+
+#include <QtCore/qcompare.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qurlquery.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qvariant.h>
+
+#include <chrono>
+
+QT_BEGIN_NAMESPACE
+
+class QDebug;
+#if QT_CONFIG(ssl)
+class QSslConfiguration;
+#endif
+
+class QNetworkRequestFactoryPrivate;
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QNetworkRequestFactoryPrivate, Q_NETWORK_EXPORT)
+
+class QT_TECH_PREVIEW_API QNetworkRequestFactory
+{
+public:
+ Q_NETWORK_EXPORT QNetworkRequestFactory();
+ Q_NETWORK_EXPORT explicit QNetworkRequestFactory(const QUrl &baseUrl);
+ Q_NETWORK_EXPORT ~QNetworkRequestFactory();
+
+ Q_NETWORK_EXPORT QNetworkRequestFactory(const QNetworkRequestFactory &other);
+ QNetworkRequestFactory(QNetworkRequestFactory &&other) noexcept = default;
+ Q_NETWORK_EXPORT QNetworkRequestFactory &operator=(const QNetworkRequestFactory &other);
+
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QNetworkRequestFactory)
+ void swap(QNetworkRequestFactory &other) noexcept { d.swap(other.d); }
+
+ Q_NETWORK_EXPORT QUrl baseUrl() const;
+ Q_NETWORK_EXPORT void setBaseUrl(const QUrl &url);
+
+#if QT_CONFIG(ssl)
+ Q_NETWORK_EXPORT QSslConfiguration sslConfiguration() const;
+ Q_NETWORK_EXPORT void setSslConfiguration(const QSslConfiguration &configuration);
+#endif
+
+ Q_NETWORK_EXPORT QNetworkRequest createRequest() const;
+ Q_NETWORK_EXPORT QNetworkRequest createRequest(const QUrlQuery &query) const;
+ Q_NETWORK_EXPORT QNetworkRequest createRequest(const QString &path) const;
+ Q_NETWORK_EXPORT QNetworkRequest createRequest(const QString &path, const QUrlQuery &query) const;
+
+ Q_NETWORK_EXPORT void setCommonHeaders(const QHttpHeaders &headers);
+ Q_NETWORK_EXPORT QHttpHeaders commonHeaders() const;
+ Q_NETWORK_EXPORT void clearCommonHeaders();
+
+ Q_NETWORK_EXPORT QByteArray bearerToken() const;
+ Q_NETWORK_EXPORT void setBearerToken(const QByteArray &token);
+ Q_NETWORK_EXPORT void clearBearerToken();
+
+ Q_NETWORK_EXPORT QString userName() const;
+ Q_NETWORK_EXPORT void setUserName(const QString &userName);
+ Q_NETWORK_EXPORT void clearUserName();
+
+ Q_NETWORK_EXPORT QString password() const;
+ Q_NETWORK_EXPORT void setPassword(const QString &password);
+ Q_NETWORK_EXPORT void clearPassword();
+
+ Q_NETWORK_EXPORT void setTransferTimeout(std::chrono::milliseconds timeout);
+ Q_NETWORK_EXPORT std::chrono::milliseconds transferTimeout() const;
+
+ Q_NETWORK_EXPORT QUrlQuery queryParameters() const;
+ Q_NETWORK_EXPORT void setQueryParameters(const QUrlQuery &query);
+ Q_NETWORK_EXPORT void clearQueryParameters();
+
+ Q_NETWORK_EXPORT void setPriority(QNetworkRequest::Priority priority);
+ Q_NETWORK_EXPORT QNetworkRequest::Priority priority() const;
+
+ Q_NETWORK_EXPORT QVariant attribute(QNetworkRequest::Attribute attribute) const;
+ Q_NETWORK_EXPORT QVariant attribute(QNetworkRequest::Attribute attribute,
+ const QVariant &defaultValue) const;
+ Q_NETWORK_EXPORT void setAttribute(QNetworkRequest::Attribute attribute, const QVariant &value);
+ Q_NETWORK_EXPORT void clearAttribute(QNetworkRequest::Attribute attribute);
+ Q_NETWORK_EXPORT void clearAttributes();
+
+private:
+#ifndef QT_NO_DEBUG_STREAM
+ friend Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QNetworkRequestFactory &reply);
+#endif
+
+ QExplicitlySharedDataPointer<QNetworkRequestFactoryPrivate> d;
+};
+
+Q_DECLARE_SHARED(QNetworkRequestFactory)
+
+QT_END_NAMESPACE
+
+#endif // QNETWORKREQUESTFACTORY_H
diff --git a/src/network/access/qnetworkrequestfactory_p.h b/src/network/access/qnetworkrequestfactory_p.h
new file mode 100644
index 0000000000..4116669f21
--- /dev/null
+++ b/src/network/access/qnetworkrequestfactory_p.h
@@ -0,0 +1,56 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QNETWORKREQUESTFACTORY_P_H
+#define QNETWORKREQUESTFACTORY_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 framework. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtNetwork/qhttpheaders.h>
+#include <QtNetwork/qnetworkrequest.h>
+#if QT_CONFIG(ssl)
+#include <QtNetwork/qsslconfiguration.h>
+#endif
+#include <QtCore/qhash.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qurlquery.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkRequestFactoryPrivate : public QSharedData
+{
+public:
+ QNetworkRequestFactoryPrivate();
+ explicit QNetworkRequestFactoryPrivate(const QUrl &baseUrl);
+ ~QNetworkRequestFactoryPrivate();
+ QNetworkRequest newRequest(const QUrl &url) const;
+ QUrl requestUrl(const QString *path = nullptr, const QUrlQuery *query = nullptr) const;
+
+#if QT_CONFIG(ssl)
+ QSslConfiguration sslConfig;
+#endif
+ QUrl baseUrl;
+ QHttpHeaders headers;
+ QByteArray bearerToken;
+ QString userName;
+ QString password;
+ QUrlQuery queryParameters;
+ QNetworkRequest::Priority priority = QNetworkRequest::NormalPriority;
+ std::chrono::milliseconds transferTimeout{0};
+ QHash<QNetworkRequest::Attribute, QVariant> attributes;
+};
+
+QT_END_NAMESPACE
+
+#endif // QNETWORKREQUESTFACTORY_P_H
diff --git a/src/network/access/qrestaccessmanager.cpp b/src/network/access/qrestaccessmanager.cpp
new file mode 100644
index 0000000000..7ef682e955
--- /dev/null
+++ b/src/network/access/qrestaccessmanager.cpp
@@ -0,0 +1,828 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qrestaccessmanager.h"
+#include "qrestaccessmanager_p.h"
+#include "qrestreply.h"
+
+#include <QtNetwork/qhttpmultipart.h>
+#include <QtNetwork/qnetworkaccessmanager.h>
+#include <QtNetwork/qnetworkreply.h>
+
+#include <QtCore/qjsondocument.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qthread.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+Q_LOGGING_CATEGORY(lcQrest, "qt.network.access.rest")
+
+/*!
+
+ \class QRestAccessManager
+ \brief The QRestAccessManager is a convenience wrapper for
+ QNetworkAccessManager.
+ \since 6.7
+
+ \ingroup network
+ \inmodule QtNetwork
+ \reentrant
+
+ \preliminary
+
+ QRestAccessManager is a convenience wrapper on top of
+ QNetworkAccessManager. It amends datatypes and HTTP methods
+ that are useful for typical RESTful client applications.
+
+ The usual Qt networking features are accessible by configuring the
+ wrapped QNetworkAccessManager directly. QRestAccessManager does not
+ take ownership of the wrapped QNetworkAccessManager.
+
+ QRestAccessManager and related QRestReply classes can only be used in the
+ thread they live in. See \l {QObject#Thread Affinity}{QObject thread affinity}
+ for more information.
+
+ \section1 Issuing Network Requests and Handling Replies
+
+ Network requests are initiated with a function call corresponding to
+ the desired HTTP method, such as \c get() and \c post().
+
+ \section2 Using Signals and Slots
+
+ The function returns a QNetworkReply* object, whose signals can be used
+ to follow up on the completion of the request in a traditional
+ Qt-signals-and-slots way.
+
+ Here's an example of how you could send a GET request and handle the
+ response:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 0
+
+ \section2 Using Callbacks and Context Objects
+
+ The functions also take a context object of QObject (subclass) type
+ and a callback function as parameters. The callback takes one QRestReply&
+ as a parameter. The callback can be any callable, including a
+ pointer-to-member-function.
+
+ These callbacks are invoked when the reply has finished processing
+ (also in the case the processing finished due to an error).
+
+ The context object can be \c nullptr, although, generally speaking,
+ this is discouraged. Using a valid context object ensures that if the
+ context object is destroyed during request processing, the callback will
+ not be called. Stray callbacks which access a destroyed context is a source
+ of application misbehavior.
+
+ Here's an example of how you could send a GET request and check the
+ response:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 1
+
+ Many of the functions take in data for sending to a server. The data is
+ supplied as the second parameter after the request.
+
+ Here's an example of how you could send a POST request and check the
+ response:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 2
+
+ The provided QRestReply& is valid only while the callback
+ executes. If you need it for longer, you can either move it
+ to another QRestReply, or construct a new one and initialize
+ it with the QNetworkReply (see QRestReply::networkReply()).
+
+ \section2 Supported data types
+
+ The following table summarizes the methods and the supported data types.
+ \c X means support.
+
+ \table
+ \header
+ \li Data type
+ \li \c get()
+ \li \c post()
+ \li \c put()
+ \li \c head()
+ \li \c patch()
+ \li \c deleteResource()
+ \li \c sendCustomRequest()
+ \row
+ \li No data
+ \li X
+ \li -
+ \li -
+ \li X
+ \li -
+ \li X
+ \li -
+ \row
+ \li QByteArray
+ \li X
+ \li X
+ \li X
+ \li -
+ \li X
+ \li -
+ \li X
+ \row
+ \li QJsonDocument *)
+ \li X
+ \li X
+ \li X
+ \li -
+ \li X
+ \li -
+ \li -
+ \row
+ \li QVariantMap **)
+ \li -
+ \li X
+ \li X
+ \li -
+ \li X
+ \li -
+ \li -
+ \row
+ \li QHttpMultiPart
+ \li -
+ \li X
+ \li X
+ \li -
+ \li -
+ \li -
+ \li X
+ \row
+ \li QIODevice
+ \li X
+ \li X
+ \li X
+ \li -
+ \li X
+ \li -
+ \li X
+ \endtable
+
+ *) QJsonDocument is sent in \l QJsonDocument::Compact format,
+ and the \c Content-Type header is set to \c {application/json} if the
+ \c Content-Type header was not set
+
+ **) QVariantMap is converted to and treated as a QJsonObject
+
+ \sa QRestReply, QNetworkRequestFactory, QNetworkAccessManager
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::get(
+ const QNetworkRequest &request,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ Issues an \c {HTTP GET} based on \a request.
+
+ The optional \a callback and \a context object can be provided for
+ handling the request completion as illustrated below:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 3
+
+ Alternatively the signals of the returned QNetworkReply* object can be
+ used. For further information see
+ \l {Issuing Network Requests and Handling Replies}.
+
+ \sa QRestReply
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::get(
+ const QNetworkRequest &request, const QByteArray &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ Issues an \c {HTTP GET} based on \a request and provided \a data.
+
+ The optional \a callback and \a context object can be provided for
+ handling the request completion as illustrated below:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 4
+
+ Alternatively the signals of the returned QNetworkReply* object can be
+ used. For further information see
+ \l {Issuing Network Requests and Handling Replies}.
+
+ \sa QRestReply
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::get(
+ const QNetworkRequest &request, const QJsonDocument &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::get(
+ const QNetworkRequest &request, QIODevice *data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::post(
+ const QNetworkRequest &request, const QJsonDocument &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ Issues an \c {HTTP POST} based on \a request.
+
+ The optional \a callback and \a context object can be provided for
+ handling the request completion as illustrated below:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 5
+
+ Alternatively, the signals of the returned QNetworkReply* object can be
+ used. For further information see
+ \l {Issuing Network Requests and Handling Replies}.
+
+ The \c post() method always requires \a data parameter. The following
+ data types are supported:
+ \list
+ \li QByteArray
+ \li QJsonDocument *)
+ \li QVariantMap **)
+ \li QHttpMultiPart*
+ \li QIODevice*
+ \endlist
+
+ *) Sent in \l QJsonDocument::Compact format, and the
+ \c Content-Type header is set to \c {application/json} if the
+ \c Content-Type header was not set
+ **) QVariantMap is converted to and treated as a QJsonObject
+
+ \sa QRestReply
+*/
+
+/*!
+
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::post(
+ const QNetworkRequest &request, const QVariantMap &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::post(
+ const QNetworkRequest &request, const QByteArray &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::post(
+ const QNetworkRequest &request, QHttpMultiPart *data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::post(
+ const QNetworkRequest &request, QIODevice *data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::put(
+ const QNetworkRequest &request, const QJsonDocument &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ Issues an \c {HTTP PUT} based on \a request.
+
+ The optional \a callback and \a context object can be provided for
+ handling the request completion as illustrated below:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 6
+
+ Alternatively the signals of the returned QNetworkReply* object can be
+ used. For further information see
+ \l {Issuing Network Requests and Handling Replies}.
+
+ The \c put() method always requires \a data parameter. The following
+ data types are supported:
+ \list
+ \li QByteArray
+ \li QJsonDocument *)
+ \li QVariantMap **)
+ \li QHttpMultiPart*
+ \li QIODevice*
+ \endlist
+
+ *) Sent in \l QJsonDocument::Compact format, and the
+ \c Content-Type header is set to \c {application/json} if the
+ \c Content-Type header was not set
+ **) QVariantMap is converted to and treated as a QJsonObject
+
+ \sa QRestReply
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::put(
+ const QNetworkRequest &request, const QVariantMap &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::put(
+ const QNetworkRequest &request, const QByteArray &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::put(
+ const QNetworkRequest &request, QHttpMultiPart *data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::put(
+ const QNetworkRequest &request, QIODevice *data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::patch(
+ const QNetworkRequest &request, const QJsonDocument &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ Issues an \c {HTTP PATCH} based on \a request.
+
+ The optional \a callback and \a context object can be provided for
+ handling the request completion as illustrated below:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 10
+
+ Alternatively the signals of the returned QNetworkReply* object can be
+ used. For further information see
+ \l {Issuing Network Requests and Handling Replies}.
+
+ The \c patch() method always requires \a data parameter. The following
+ data types are supported:
+ \list
+ \li QByteArray
+ \li QJsonDocument *)
+ \li QVariantMap **)
+ \li QIODevice*
+ \endlist
+
+ *) Sent in \l QJsonDocument::Compact format, and the
+ \c Content-Type header is set to \c {application/json} if the
+ \c Content-Type header was not set
+ **) QVariantMap is converted to and treated as a QJsonObject
+
+ \sa QRestReply
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::patch(
+ const QNetworkRequest &request, const QVariantMap &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::patch(
+ const QNetworkRequest &request, const QByteArray &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::patch(
+ const QNetworkRequest &request, QIODevice *data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::head(
+ const QNetworkRequest &request,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ Issues an \c {HTTP HEAD} based on \a request.
+
+ The optional \a callback and \a context object can be provided for
+ handling the request completion as illustrated below:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 7
+
+ Alternatively the signals of the returned QNetworkReply* object can be
+ used. For further information see
+ \l {Issuing Network Requests and Handling Replies}.
+
+ \c head() request does not support providing data.
+
+ \sa QRestReply
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::deleteResource(
+ const QNetworkRequest &request,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ Issues an \c {HTTP DELETE} based on \a request.
+
+ The optional \a callback and \a context object can be provided for
+ handling the request completion as illustrated below:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 8
+
+ Alternatively the signals of the returned QNetworkReply* object can be
+ used. For further information see
+ \l {Issuing Network Requests and Handling Replies}.
+
+ \c deleteResource() request does not support providing data.
+
+ \sa QRestReply
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::sendCustomRequest(
+ const QNetworkRequest& request, const QByteArray &method, const QByteArray &data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ Issues \a request based HTTP request with custom \a method and the
+ provided \a data.
+
+ The optional \a callback and \a context object can be provided for
+ handling the request completion as illustrated below:
+
+ \snippet code/src_network_access_qrestaccessmanager.cpp 9
+
+ Alternatively the signals of the returned QNetworkReply* object can be
+ used. For further information see
+ \l {Issuing Network Requests and Handling Replies}.
+
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::sendCustomRequest(
+ const QNetworkRequest& request, const QByteArray &method, QIODevice *data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ \fn template<typename Functor, QRestAccessManager::if_compatible_callback<Functor>> QNetworkReply *QRestAccessManager::sendCustomRequest(
+ const QNetworkRequest& request, const QByteArray &method, QHttpMultiPart *data,
+ const ContextTypeForFunctor<Functor> *context,
+ Functor &&callback)
+
+ \overload
+*/
+
+/*!
+ Constructs a QRestAccessManager object and sets \a parent as the parent
+ object, and \a manager as the underlying QNetworkAccessManager which
+ is used for communication.
+
+ \sa networkAccessManager()
+*/
+
+QRestAccessManager::QRestAccessManager(QNetworkAccessManager *manager, QObject *parent)
+ : QObject(*new QRestAccessManagerPrivate, parent)
+{
+ Q_D(QRestAccessManager);
+ d->qnam = manager;
+ if (!d->qnam)
+ qCWarning(lcQrest, "QRestAccessManager: QNetworkAccesManager is nullptr");
+}
+
+/*!
+ Destroys the QRestAccessManager object.
+*/
+QRestAccessManager::~QRestAccessManager()
+ = default;
+
+/*!
+ Returns the underlying QNetworkAccessManager instance.
+
+ \sa QNetworkAccessManager
+*/
+QNetworkAccessManager *QRestAccessManager::networkAccessManager() const
+{
+ Q_D(const QRestAccessManager);
+ return d->qnam;
+}
+
+QRestAccessManagerPrivate::QRestAccessManagerPrivate()
+ = default;
+
+QRestAccessManagerPrivate::~QRestAccessManagerPrivate()
+{
+ if (!activeRequests.isEmpty()) {
+ qCWarning(lcQrest, "Access manager destroyed while %lld requests were still in progress",
+ qlonglong(activeRequests.size()));
+ }
+}
+
+QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
+ const QJsonDocument &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([](auto qnam, auto req, auto data) { return qnam->post(req, data); },
+ data, request, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
+ const QVariantMap &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ return postWithDataImpl(request, QJsonDocument::fromVariant(data), context, slot);
+}
+
+QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
+ const QByteArray &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->post(request, data); }, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
+ QHttpMultiPart *data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->post(request, data); }, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::postWithDataImpl(const QNetworkRequest &request,
+ QIODevice *data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->post(request, data); }, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::getNoDataImpl(const QNetworkRequest &request,
+ const QObject *context, QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->get(request); }, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::getWithDataImpl(const QNetworkRequest &request,
+ const QByteArray &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->get(request, data); }, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::getWithDataImpl(const QNetworkRequest &request,
+ const QJsonDocument &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([](auto qnam, auto req, auto data) { return qnam->get(req, data); },
+ data, request, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::getWithDataImpl(const QNetworkRequest &request,
+ QIODevice *data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->get(request, data); }, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::deleteResourceNoDataImpl(const QNetworkRequest &request,
+ const QObject *context, QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->deleteResource(request); }, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::headNoDataImpl(const QNetworkRequest &request,
+ const QObject *context, QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->head(request); }, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
+ const QJsonDocument &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([](auto qnam, auto req, auto data) { return qnam->put(req, data); },
+ data, request, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
+ const QVariantMap &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ return putWithDataImpl(request, QJsonDocument::fromVariant(data), context, slot);
+}
+
+QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
+ const QByteArray &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->put(request, data); }, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request,
+ QHttpMultiPart *data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->put(request, data); }, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::putWithDataImpl(const QNetworkRequest &request, QIODevice *data,
+ const QObject *context, QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->put(request, data); }, context, slot);
+}
+
+static const auto PATCH = "PATCH"_ba;
+
+QNetworkReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request,
+ const QJsonDocument &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest(
+ [](auto qnam, auto req, auto data) { return qnam->sendCustomRequest(req, PATCH, data); },
+ data, request, context, slot);
+}
+
+QNetworkReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request,
+ const QVariantMap &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ return patchWithDataImpl(request, QJsonDocument::fromVariant(data), context, slot);
+}
+
+QNetworkReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request,
+ const QByteArray &data, const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->sendCustomRequest(request, PATCH, data); },
+ context, slot);
+}
+
+QNetworkReply *QRestAccessManager::patchWithDataImpl(const QNetworkRequest &request, QIODevice *data,
+ const QObject *context, QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->sendCustomRequest(request, PATCH, data); },
+ context, slot);
+}
+
+QNetworkReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &request,
+ const QByteArray& method, const QByteArray &data,
+ const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->sendCustomRequest(request, method, data); },
+ context, slot);
+}
+
+QNetworkReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &request,
+ const QByteArray& method, QIODevice *data,
+ const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->sendCustomRequest(request, method, data); },
+ context, slot);
+}
+
+QNetworkReply *QRestAccessManager::customWithDataImpl(const QNetworkRequest &request,
+ const QByteArray& method, QHttpMultiPart *data,
+ const QObject *context,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_D(QRestAccessManager);
+ return d->executeRequest([&](auto qnam) { return qnam->sendCustomRequest(request, method, data); },
+ context, slot);
+}
+
+QNetworkReply *QRestAccessManagerPrivate::createActiveRequest(QNetworkReply *reply,
+ const QObject *contextObject,
+ QtPrivate::QSlotObjectBase *slot)
+{
+ Q_Q(QRestAccessManager);
+ Q_ASSERT(reply);
+ QtPrivate::SlotObjSharedPtr slotPtr(QtPrivate::SlotObjUniquePtr{slot}); // adopts
+ activeRequests.insert(reply, CallerInfo{contextObject, slotPtr});
+ // The signal connections below are made to 'q' to avoid stray signal
+ // handling upon its destruction while requests were still in progress
+
+ QObject::connect(reply, &QNetworkReply::finished, q, [reply, this]() {
+ handleReplyFinished(reply);
+ });
+ // Safe guard in case reply is destroyed before it's finished
+ QObject::connect(reply, &QObject::destroyed, q, [reply, this]() {
+ activeRequests.remove(reply);
+ });
+ // If context object is destroyed, clean up any possible replies it had associated with it
+ if (contextObject) {
+ QObject::connect(contextObject, &QObject::destroyed, q, [reply, this]() {
+ activeRequests.remove(reply);
+ });
+ }
+ return reply;
+}
+
+void QRestAccessManagerPrivate::verifyThreadAffinity(const QObject *contextObject)
+{
+ Q_Q(QRestAccessManager);
+ if (QThread::currentThread() != q->thread()) {
+ qCWarning(lcQrest, "QRestAccessManager can only be called in the thread it belongs to");
+ Q_ASSERT(false);
+ }
+ if (contextObject && (contextObject->thread() != q->thread())) {
+ qCWarning(lcQrest, "QRestAccessManager: the context object must reside in the same thread");
+ Q_ASSERT(false);
+ }
+}
+
+QNetworkReply* QRestAccessManagerPrivate::warnNoAccessManager()
+{
+ qCWarning(lcQrest, "QRestAccessManager: QNetworkAccessManager not set");
+ return nullptr;
+}
+
+void QRestAccessManagerPrivate::handleReplyFinished(QNetworkReply *reply)
+{
+ auto request = activeRequests.find(reply);
+ if (request == activeRequests.end()) {
+ qCDebug(lcQrest, "QRestAccessManager: Unexpected reply received, ignoring");
+ return;
+ }
+
+ CallerInfo caller = request.value();
+ activeRequests.erase(request);
+
+ if (caller.slot) {
+ // Callback was provided
+ QRestReply restReply(reply);
+ void *argv[] = { nullptr, &restReply };
+ // If we have context object, use it
+ QObject *context = caller.contextObject
+ ? const_cast<QObject*>(caller.contextObject.get()) : nullptr;
+ caller.slot->call(context, argv);
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qrestaccessmanager.cpp"
diff --git a/src/network/access/qrestaccessmanager.h b/src/network/access/qrestaccessmanager.h
new file mode 100644
index 0000000000..3245b41785
--- /dev/null
+++ b/src/network/access/qrestaccessmanager.h
@@ -0,0 +1,127 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QRESTACCESSMANAGER_H
+#define QRESTACCESSMANAGER_H
+
+#if 0
+#pragma qt_class(QRestAccessManager)
+#endif
+
+#include <QtNetwork/qnetworkaccessmanager.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDebug;
+class QRestReply;
+
+#define QREST_METHOD_WITH_DATA(METHOD, DATA) \
+public: \
+template <typename Functor, if_compatible_callback<Functor> = true> \
+QNetworkReply *METHOD(const QNetworkRequest &request, DATA data, \
+ const ContextTypeForFunctor<Functor> *context, \
+ Functor &&callback) \
+{ \
+ return METHOD##WithDataImpl(request, data, context, \
+ QtPrivate::makeCallableObject<CallbackPrototype>(std::forward<Functor>(callback))); \
+} \
+QNetworkReply *METHOD(const QNetworkRequest &request, DATA data) \
+{ \
+ return METHOD##WithDataImpl(request, data, nullptr, nullptr); \
+} \
+private: \
+QNetworkReply *METHOD##WithDataImpl(const QNetworkRequest &request, DATA data, \
+ const QObject *context, QtPrivate::QSlotObjectBase *slot); \
+/* end */
+
+#define QREST_METHOD_NO_DATA(METHOD) \
+public: \
+template <typename Functor, if_compatible_callback<Functor> = true> \
+QNetworkReply *METHOD(const QNetworkRequest &request, \
+ const ContextTypeForFunctor<Functor> *context, \
+ Functor &&callback) \
+{ \
+ return METHOD##NoDataImpl(request, context, \
+ QtPrivate::makeCallableObject<CallbackPrototype>(std::forward<Functor>(callback))); \
+} \
+QNetworkReply *METHOD(const QNetworkRequest &request) \
+{ \
+ return METHOD##NoDataImpl(request, nullptr, nullptr); \
+} \
+private: \
+QNetworkReply *METHOD##NoDataImpl(const QNetworkRequest &request, \
+ const QObject *context, QtPrivate::QSlotObjectBase *slot); \
+/* end */
+
+#define QREST_METHOD_CUSTOM_WITH_DATA(DATA) \
+public: \
+template <typename Functor, if_compatible_callback<Functor> = true> \
+QNetworkReply *sendCustomRequest(const QNetworkRequest& request, const QByteArray &method, DATA data, \
+ const ContextTypeForFunctor<Functor> *context, \
+ Functor &&callback) \
+{ \
+ return customWithDataImpl(request, method, data, context, \
+ QtPrivate::makeCallableObject<CallbackPrototype>(std::forward<Functor>(callback))); \
+} \
+QNetworkReply *sendCustomRequest(const QNetworkRequest& request, const QByteArray &method, DATA data) \
+{ \
+ return customWithDataImpl(request, method, data, nullptr, nullptr); \
+} \
+private: \
+QNetworkReply *customWithDataImpl(const QNetworkRequest& request, const QByteArray &method, \
+ DATA data, const QObject* context, \
+ QtPrivate::QSlotObjectBase *slot); \
+/* end */
+
+class QRestAccessManagerPrivate;
+class QT_TECH_PREVIEW_API Q_NETWORK_EXPORT QRestAccessManager : public QObject
+{
+ Q_OBJECT
+ using CallbackPrototype = void(*)(QRestReply&);
+ template <typename Functor>
+ using ContextTypeForFunctor = typename QtPrivate::ContextTypeForFunctor<Functor>::ContextType;
+ template <typename Functor>
+ using if_compatible_callback = std::enable_if_t<
+ QtPrivate::AreFunctionsCompatible<CallbackPrototype, Functor>::value, bool>;
+public:
+ explicit QRestAccessManager(QNetworkAccessManager *manager, QObject *parent = nullptr);
+ ~QRestAccessManager() override;
+
+ QNetworkAccessManager *networkAccessManager() const;
+
+ QREST_METHOD_NO_DATA(deleteResource)
+ QREST_METHOD_NO_DATA(head)
+ QREST_METHOD_NO_DATA(get)
+ QREST_METHOD_WITH_DATA(get, const QByteArray &)
+ QREST_METHOD_WITH_DATA(get, const QJsonDocument &)
+ QREST_METHOD_WITH_DATA(get, QIODevice *)
+ QREST_METHOD_WITH_DATA(post, const QJsonDocument &)
+ QREST_METHOD_WITH_DATA(post, const QVariantMap &)
+ QREST_METHOD_WITH_DATA(post, const QByteArray &)
+ QREST_METHOD_WITH_DATA(post, QHttpMultiPart *)
+ QREST_METHOD_WITH_DATA(post, QIODevice *)
+ QREST_METHOD_WITH_DATA(put, const QJsonDocument &)
+ QREST_METHOD_WITH_DATA(put, const QVariantMap &)
+ QREST_METHOD_WITH_DATA(put, const QByteArray &)
+ QREST_METHOD_WITH_DATA(put, QHttpMultiPart *)
+ QREST_METHOD_WITH_DATA(put, QIODevice *)
+ QREST_METHOD_WITH_DATA(patch, const QJsonDocument &)
+ QREST_METHOD_WITH_DATA(patch, const QVariantMap &)
+ QREST_METHOD_WITH_DATA(patch, const QByteArray &)
+ QREST_METHOD_WITH_DATA(patch, QIODevice *)
+ QREST_METHOD_CUSTOM_WITH_DATA(const QByteArray &)
+ QREST_METHOD_CUSTOM_WITH_DATA(QIODevice *)
+ QREST_METHOD_CUSTOM_WITH_DATA(QHttpMultiPart *)
+
+private:
+ Q_DECLARE_PRIVATE(QRestAccessManager)
+ Q_DISABLE_COPY(QRestAccessManager)
+};
+
+#undef QREST_METHOD_NO_DATA
+#undef QREST_METHOD_WITH_DATA
+#undef QREST_METHOD_CUSTOM_WITH_DATA
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/access/qrestaccessmanager_p.h b/src/network/access/qrestaccessmanager_p.h
new file mode 100644
index 0000000000..51af299f5c
--- /dev/null
+++ b/src/network/access/qrestaccessmanager_p.h
@@ -0,0 +1,89 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QRESTACCESSMANAGER_P_H
+#define QRESTACCESSMANAGER_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 "qrestaccessmanager.h"
+#include "private/qobject_p.h"
+
+#include <QtNetwork/qnetworkaccessmanager.h>
+
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qjsondocument.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qxpfunctional.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRestReply;
+class QRestAccessManagerPrivate : public QObjectPrivate
+{
+public:
+ QRestAccessManagerPrivate();
+ ~QRestAccessManagerPrivate() override;
+
+ QNetworkReply* createActiveRequest(QNetworkReply *reply, const QObject *contextObject,
+ QtPrivate::QSlotObjectBase *slot);
+ void handleReplyFinished(QNetworkReply *reply);
+
+ using ReqOpRef = qxp::function_ref<QNetworkReply*(QNetworkAccessManager*) const>;
+ QNetworkReply *executeRequest(ReqOpRef requestOperation,
+ const QObject *context, QtPrivate::QSlotObjectBase *slot)
+ {
+ if (!qnam)
+ return warnNoAccessManager();
+ verifyThreadAffinity(context);
+ QNetworkReply *reply = requestOperation(qnam);
+ return createActiveRequest(reply, context, slot);
+ }
+
+ using ReqOpRefJson = qxp::function_ref<QNetworkReply*(QNetworkAccessManager*,
+ const QNetworkRequest &,
+ const QByteArray &) const>;
+ QNetworkReply *executeRequest(ReqOpRefJson requestOperation, const QJsonDocument &jsonDoc,
+ const QNetworkRequest &request,
+ const QObject *context, QtPrivate::QSlotObjectBase *slot)
+ {
+ if (!qnam)
+ return warnNoAccessManager();
+ verifyThreadAffinity(context);
+ QNetworkRequest req(request);
+ if (!request.header(QNetworkRequest::ContentTypeHeader).isValid()) {
+ req.setHeader(QNetworkRequest::ContentTypeHeader,
+ QLatin1StringView{"application/json"});
+ }
+ QNetworkReply *reply = requestOperation(qnam, req, jsonDoc.toJson(QJsonDocument::Compact));
+ return createActiveRequest(reply, context, slot);
+ }
+
+ void verifyThreadAffinity(const QObject *contextObject);
+ Q_DECL_COLD_FUNCTION
+ QNetworkReply* warnNoAccessManager();
+
+ struct CallerInfo {
+ QPointer<const QObject> contextObject = nullptr;
+ QtPrivate::SlotObjSharedPtr slot;
+ };
+ QHash<QNetworkReply*, CallerInfo> activeRequests;
+
+ QNetworkAccessManager *qnam = nullptr;
+ bool deletesRepliesOnFinished = true;
+ Q_DECLARE_PUBLIC(QRestAccessManager)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/access/qrestreply.cpp b/src/network/access/qrestreply.cpp
new file mode 100644
index 0000000000..cdd264ba6e
--- /dev/null
+++ b/src/network/access/qrestreply.cpp
@@ -0,0 +1,608 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qrestreply.h"
+#include "qrestreply_p.h"
+
+#include <QtNetwork/private/qnetworkreply_p.h>
+
+#include <QtCore/qbytearrayview.h>
+#include <QtCore/qjsondocument.h>
+#include <QtCore/qlatin1stringmatcher.h>
+#include <QtCore/qlatin1stringview.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qstringconverter.h>
+
+#include <QtCore/qxpfunctional.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+Q_DECLARE_LOGGING_CATEGORY(lcQrest)
+
+/*!
+ \class QRestReply
+ \since 6.7
+ \brief QRestReply is a convenience wrapper for QNetworkReply.
+
+ \reentrant
+ \ingroup network
+ \inmodule QtNetwork
+
+ \preliminary
+
+ QRestReply wraps a QNetworkReply and provides convenience methods for data
+ and status handling. The methods provide convenience for typical RESTful
+ client applications.
+
+ QRestReply doesn't take ownership of the wrapped QNetworkReply, and the
+ lifetime and ownership of the reply is as defined by QNetworkAccessManager
+ documentation.
+
+ QRestReply object is not copyable, but is movable.
+
+ \sa QRestAccessManager, QNetworkReply, QNetworkAccessManager,
+ QNetworkAccessManager::setAutoDeleteReplies()
+*/
+
+/*!
+ Creates a QRestReply and initializes the wrapped QNetworkReply to \a reply.
+*/
+QRestReply::QRestReply(QNetworkReply *reply)
+ : wrapped(reply)
+{
+ if (!wrapped)
+ qCWarning(lcQrest, "QRestReply: QNetworkReply is nullptr");
+}
+
+/*!
+ Destroys this QRestReply object.
+*/
+QRestReply::~QRestReply()
+{
+ delete d;
+}
+
+/*!
+ \fn QRestReply::QRestReply(QRestReply &&other) noexcept
+
+ Move-constructs the reply from \a other.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new value.
+*/
+
+/*!
+ \fn QRestReply &QRestReply::operator=(QRestReply &&other) noexcept
+
+ Move-assigns \a other and returns a reference to this reply.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new value.
+*/
+
+/*!
+ Returns a pointer to the underlying QNetworkReply wrapped by this object.
+*/
+QNetworkReply *QRestReply::networkReply() const
+{
+ return wrapped;
+}
+
+/*!
+ Returns the received data as a QJsonDocument.
+
+ The returned value is wrapped in \c std::optional. If the conversion
+ from the received data fails (empty data or JSON parsing error),
+ \c std::nullopt is returned, and \a error is filled with details.
+
+ Calling this function consumes the received data, and any further calls
+ to get response data will return empty.
+
+ This function returns \c {std::nullopt} and will not consume
+ any data if the reply is not finished. If \a error is passed, it will be
+ set to QJsonParseError::NoError to distinguish this case from an actual
+ error.
+
+ \sa readBody(), readText()
+*/
+std::optional<QJsonDocument> QRestReply::readJson(QJsonParseError *error)
+{
+ if (!wrapped) {
+ if (error)
+ *error = {0, QJsonParseError::ParseError::NoError};
+ return std::nullopt;
+ }
+
+ if (!wrapped->isFinished()) {
+ qCWarning(lcQrest, "readJson() called on an unfinished reply, ignoring");
+ if (error)
+ *error = {0, QJsonParseError::ParseError::NoError};
+ return std::nullopt;
+ }
+ QJsonParseError parseError;
+ const QByteArray data = wrapped->readAll();
+ const QJsonDocument doc = QJsonDocument::fromJson(data, &parseError);
+ if (error)
+ *error = parseError;
+ if (parseError.error)
+ return std::nullopt;
+ return doc;
+}
+
+/*!
+ Returns the received data as a QByteArray.
+
+ Calling this function consumes the data received so far, and any further
+ calls to get response data will return empty until further data has been
+ received.
+
+ \sa readJson(), readText(), QNetworkReply::bytesAvailable(),
+ QNetworkReply::readyRead()
+*/
+QByteArray QRestReply::readBody()
+{
+ return wrapped ? wrapped->readAll() : QByteArray{};
+}
+
+/*!
+ Returns the received data as a QString.
+
+ The received data is decoded into a QString (UTF-16). If available, the decoding
+ uses the \e Content-Type header's \e charset parameter to determine the
+ source encoding. If the encoding information is not available or not supported
+ by \l QStringConverter, UTF-8 is used by default.
+
+ Calling this function consumes the data received so far. Returns
+ a default constructed value if no new data is available, or if the
+ decoding is not supported by \l QStringConverter, or if the decoding
+ has errors (for example invalid characters).
+
+ \sa readJson(), readBody(), QNetworkReply::readyRead()
+*/
+QString QRestReply::readText()
+{
+ QString result;
+ if (!wrapped)
+ return result;
+
+ QByteArray data = wrapped->readAll();
+ if (data.isEmpty())
+ return result;
+
+ // Text decoding needs to persist decoding state across calls to this function,
+ // so allocate decoder if not yet allocated.
+ if (!d)
+ d = new QRestReplyPrivate;
+
+ if (!d->decoder) {
+ const QByteArray charset = QRestReplyPrivate::contentCharset(wrapped);
+ d->decoder.emplace(charset.constData());
+ if (!d->decoder->isValid()) { // the decoder may not support the mimetype's charset
+ qCWarning(lcQrest, "readText(): Charset \"%s\" is not supported", charset.constData());
+ return result;
+ }
+ }
+ // Check if the decoder already had an error, or has errors after decoding current data chunk
+ if (d->decoder->hasError() || (result = (*d->decoder)(data), d->decoder->hasError())) {
+ qCWarning(lcQrest, "readText(): Decoding error occurred");
+ return {};
+ }
+ return result;
+}
+
+/*!
+ Returns the HTTP status received in the server response.
+ The value is \e 0 if not available (the status line has not been received,
+ yet).
+
+ \note The HTTP status is reported as indicated by the received HTTP
+ response. An error() may occur after receiving the status, for instance
+ due to network disconnection while receiving a long response.
+ These potential subsequent errors are not represented by the reported
+ HTTP status.
+
+ \sa isSuccess(), hasError(), error()
+*/
+int QRestReply::httpStatus() const
+{
+ return wrapped ? wrapped->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() : 0;
+}
+
+/*!
+ \fn bool QRestReply::isSuccess() const
+
+ Returns whether the HTTP status is between 200..299 and no
+ further errors have occurred while receiving the response (for example,
+ abrupt disconnection while receiving the body data). This function
+ is a convenient way to check whether the response is considered successful.
+
+ \sa httpStatus(), hasError(), error()
+*/
+
+/*!
+ Returns whether the HTTP status is between 200..299.
+
+ \sa isSuccess(), httpStatus(), hasError(), error()
+*/
+bool QRestReply::isHttpStatusSuccess() const
+{
+ const int status = httpStatus();
+ return status >= 200 && status < 300;
+}
+
+/*!
+ Returns whether an error has occurred. This includes errors such as
+ network and protocol errors, but excludes cases where the server
+ successfully responded with an HTTP error status (for example
+ \c {500 Internal Server Error}). Use \l httpStatus() or
+ \l isHttpStatusSuccess() to get the HTTP status information.
+
+ \sa httpStatus(), isSuccess(), error(), errorString()
+*/
+bool QRestReply::hasError() const
+{
+ if (!wrapped)
+ return false;
+
+ const int status = httpStatus();
+ if (status > 0) {
+ // The HTTP status is set upon receiving the response headers, but the
+ // connection might still fail later while receiving the body data.
+ return wrapped->error() == QNetworkReply::RemoteHostClosedError;
+ }
+ return wrapped->error() != QNetworkReply::NoError;
+}
+
+/*!
+ Returns the last error, if any. The errors include
+ errors such as network and protocol errors, but exclude
+ cases when the server successfully responded with an HTTP status.
+
+ \sa httpStatus(), isSuccess(), hasError(), errorString()
+*/
+QNetworkReply::NetworkError QRestReply::error() const
+{
+ if (!hasError())
+ return QNetworkReply::NetworkError::NoError;
+ return wrapped->error();
+}
+
+/*!
+ Returns a human-readable description of the last network error.
+
+ \sa httpStatus(), isSuccess(), hasError(), error()
+*/
+QString QRestReply::errorString() const
+{
+ if (hasError())
+ return wrapped->errorString();
+ return {};
+}
+
+QRestReplyPrivate::QRestReplyPrivate()
+ = default;
+
+QRestReplyPrivate::~QRestReplyPrivate()
+ = default;
+
+#ifndef QT_NO_DEBUG_STREAM
+static QLatin1StringView operationName(QNetworkAccessManager::Operation operation)
+{
+ switch (operation) {
+ case QNetworkAccessManager::Operation::GetOperation:
+ return "GET"_L1;
+ case QNetworkAccessManager::Operation::HeadOperation:
+ return "HEAD"_L1;
+ case QNetworkAccessManager::Operation::PostOperation:
+ return "POST"_L1;
+ case QNetworkAccessManager::Operation::PutOperation:
+ return "PUT"_L1;
+ case QNetworkAccessManager::Operation::DeleteOperation:
+ return "DELETE"_L1;
+ case QNetworkAccessManager::Operation::CustomOperation:
+ return "CUSTOM"_L1;
+ case QNetworkAccessManager::Operation::UnknownOperation:
+ return "UNKNOWN"_L1;
+ }
+ Q_UNREACHABLE_RETURN({});
+}
+
+/*!
+ \fn QDebug QRestReply::operator<<(QDebug debug, const QRestReply &reply)
+
+ Writes the \a reply into the \a debug object for debugging purposes.
+
+ \sa {Debugging Techniques}
+*/
+QDebug operator<<(QDebug debug, const QRestReply &reply)
+{
+ const QDebugStateSaver saver(debug);
+ debug.resetFormat().nospace();
+ if (!reply.networkReply()) {
+ debug << "QRestReply(no network reply)";
+ return debug;
+ }
+ debug << "QRestReply(isSuccess = " << reply.isSuccess()
+ << ", httpStatus = " << reply.httpStatus()
+ << ", isHttpStatusSuccess = " << reply.isHttpStatusSuccess()
+ << ", hasError = " << reply.hasError()
+ << ", errorString = " << reply.errorString()
+ << ", error = " << reply.error()
+ << ", isFinished = " << reply.networkReply()->isFinished()
+ << ", bytesAvailable = " << reply.networkReply()->bytesAvailable()
+ << ", url " << reply.networkReply()->url()
+ << ", operation = " << operationName(reply.networkReply()->operation())
+ << ", reply headers = " << reply.networkReply()->rawHeaderPairs()
+ << ")";
+ return debug;
+}
+#endif // QT_NO_DEBUG_STREAM
+
+static constexpr auto parse_OWS(QByteArrayView data) noexcept
+{
+ struct R {
+ QByteArrayView ows, tail;
+ };
+
+ constexpr auto is_OWS_char = [](auto ch) { return ch == ' ' || ch == '\t'; };
+
+ qsizetype i = 0;
+ while (i < data.size() && is_OWS_char(data[i]))
+ ++i;
+
+ return R{data.first(i), data.sliced(i)};
+}
+
+static constexpr void eat_OWS(QByteArrayView &data) noexcept
+{
+ data = parse_OWS(data).tail;
+}
+
+static constexpr auto parse_quoted_string(QByteArrayView data, qxp::function_ref<void(char) const> yield)
+{
+ struct R {
+ QByteArrayView quotedString, tail;
+ constexpr explicit operator bool() const noexcept { return !quotedString.isEmpty(); }
+ };
+
+ if (!data.startsWith('"'))
+ return R{{}, data};
+
+ qsizetype i = 1; // one past initial DQUOTE
+ while (i < data.size()) {
+ switch (auto ch = data[i++]) {
+ case '"': // final DQUOTE -> end of string
+ return R{data.first(i), data.sliced(i)};
+ case '\\': // quoted-pair
+ // https://www.rfc-editor.org/rfc/rfc9110.html#section-5.6.4-3:
+ // Recipients that process the value of a quoted-string MUST handle a
+ // quoted-pair as if it were replaced by the octet following the backslash.
+ if (i == data.size())
+ break; // premature end
+ ch = data[i++]; // eat '\\'
+ [[fallthrough]];
+ default:
+ // we don't validate quoted-string octets to be only qdtext (Postel's Law)
+ yield(ch);
+ }
+ }
+
+ return R{{}, data}; // premature end
+}
+
+static constexpr bool is_tchar(char ch) noexcept
+{
+ // ### optimize
+ switch (ch) {
+ case '!':
+ case '#':
+ case '$':
+ case '%':
+ case '&':
+ case '\'':
+ case '*':
+ case '+':
+ case '-':
+ case '.':
+ case '^':
+ case '_':
+ case '`':
+ case '|':
+ case '~':
+ return true;
+ default:
+ return (ch >= 'a' && ch <= 'z')
+ || (ch >= '0' && ch <= '9')
+ || (ch >= 'A' && ch <= 'Z');
+ }
+}
+
+static constexpr auto parse_comment(QByteArrayView data) noexcept
+{
+ struct R {
+ QByteArrayView comment, tail;
+ constexpr explicit operator bool() const noexcept { return !comment.isEmpty(); }
+ };
+
+ const auto invalid = R{{}, data}; // preserves original `data`
+
+ // comment = "(" *( ctext / quoted-pair / comment ) ")"
+ // ctext = HTAB / SP / %x21-27 / %x2A-5B / %x5D-7E / obs-text
+
+ if (!data.startsWith('('))
+ return invalid;
+
+ qsizetype i = 1;
+ qsizetype level = 1;
+ while (i < data.size()) {
+ switch (data[i++]) {
+ case '(': // nested comment
+ ++level;
+ break;
+ case ')': // end of comment
+ if (--level == 0)
+ return R{data.first(i), data.sliced(i)};
+ break;
+ case '\\': // quoted-pair
+ if (i == data.size())
+ return invalid; // premature end
+ ++i; // eat escaped character
+ break;
+ default:
+ ; // don't validate ctext - accept everything (Postel's Law)
+ }
+ }
+
+ return invalid; // premature end / unbalanced nesting levels
+}
+
+static constexpr void eat_CWS(QByteArrayView &data) noexcept
+{
+ eat_OWS(data);
+ while (const auto comment = parse_comment(data)) {
+ data = comment.tail;
+ eat_OWS(data);
+ }
+}
+
+static constexpr auto parse_token(QByteArrayView data) noexcept
+{
+ struct R {
+ QByteArrayView token, tail;
+ constexpr explicit operator bool() const noexcept { return !token.isEmpty(); }
+ };
+
+ qsizetype i = 0;
+ while (i < data.size() && is_tchar(data[i]))
+ ++i;
+
+ return R{data.first(i), data.sliced(i)};
+}
+
+static constexpr auto parse_parameter(QByteArrayView data, qxp::function_ref<void(char) const> yield)
+{
+ struct R {
+ QLatin1StringView name; QByteArrayView value; QByteArrayView tail;
+ constexpr explicit operator bool() const noexcept { return !name.isEmpty(); }
+ };
+
+ const auto invalid = R{{}, {}, data}; // preserves original `data`
+
+ // parameter = parameter-name "=" parameter-value
+ // parameter-name = token
+ // parameter-value = ( token / quoted-string )
+
+ const auto name = parse_token(data);
+ if (!name)
+ return invalid;
+ data = name.tail;
+
+ eat_CWS(data); // not in the grammar, but accepted under Postel's Law
+
+ if (!data.startsWith('='))
+ return invalid;
+ data = data.sliced(1);
+
+ eat_CWS(data); // not in the grammar, but accepted under Postel's Law
+
+ if (Q_UNLIKELY(data.startsWith('"'))) { // value is a quoted-string
+
+ const auto value = parse_quoted_string(data, yield);
+ if (!value)
+ return invalid;
+ data = value.tail;
+
+ return R{QLatin1StringView{name.token}, value.quotedString, data};
+
+ } else { // value is a token
+
+ const auto value = parse_token(data);
+ if (!value)
+ return invalid;
+ data = value.tail;
+
+ return R{QLatin1StringView{name.token}, value.token, data};
+ }
+}
+
+static auto parse_content_type(QByteArrayView data)
+{
+ struct R {
+ QLatin1StringView type, subtype;
+ std::string charset;
+ constexpr explicit operator bool() const noexcept { return !type.isEmpty(); }
+ };
+
+ eat_CWS(data); // not in the grammar, but accepted under Postel's Law
+
+ const auto type = parse_token(data);
+ if (!type)
+ return R{};
+ data = type.tail;
+
+ eat_CWS(data); // not in the grammar, but accepted under Postel's Law
+
+ if (!data.startsWith('/'))
+ return R{};
+ data = data.sliced(1);
+
+ eat_CWS(data); // not in the grammar, but accepted under Postel's Law
+
+ const auto subtype = parse_token(data);
+ if (!subtype)
+ return R{};
+ data = subtype.tail;
+
+ eat_CWS(data);
+
+ auto r = R{QLatin1StringView{type.token}, QLatin1StringView{subtype.token}, {}};
+
+ while (data.startsWith(';')) {
+
+ data = data.sliced(1); // eat ';'
+
+ eat_CWS(data);
+
+ const auto param = parse_parameter(data, [&](char ch) { r.charset.append(1, ch); });
+ if (param.name.compare("charset"_L1, Qt::CaseInsensitive) == 0) {
+ if (r.charset.empty() && !param.value.startsWith('"')) // wasn't a quoted-string
+ r.charset.assign(param.value.begin(), param.value.end());
+ return r; // charset found
+ }
+ r.charset.clear(); // wasn't an actual charset
+ if (param.tail.size() == data.size()) // no progress was made
+ break; // returns {type, subtype}
+ // otherwise, continue (accepting e.g. `;;`)
+ data = param.tail;
+
+ eat_CWS(data);
+ }
+
+ return r; // no charset found
+}
+
+QByteArray QRestReplyPrivate::contentCharset(const QNetworkReply* reply)
+{
+ // Content-type consists of mimetype and optional parameters, of which one may be 'charset'
+ // Example values and their combinations below are all valid, see RFC 7231 section 3.1.1.5
+ // and RFC 2045 section 5.1
+ //
+ // text/plain; charset=utf-8
+ // text/plain; charset=utf-8;version=1.7
+ // text/plain; charset = utf-8
+ // text/plain; charset ="utf-8"
+
+ const QByteArray contentTypeValue =
+ reply->header(QNetworkRequest::KnownHeaders::ContentTypeHeader).toByteArray();
+
+ const auto r = parse_content_type(contentTypeValue);
+ if (r && !r.charset.empty())
+ return QByteArrayView(r.charset).toByteArray();
+ else
+ return "UTF-8"_ba; // Default to the most commonly used UTF-8.
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/access/qrestreply.h b/src/network/access/qrestreply.h
new file mode 100644
index 0000000000..c32fff1d4e
--- /dev/null
+++ b/src/network/access/qrestreply.h
@@ -0,0 +1,71 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QRESTREPLY_H
+#define QRESTREPLY_H
+
+#include <QtNetwork/qnetworkreply.h>
+
+#include <QtCore/qpointer.h>
+
+#include <optional>
+#include <utility>
+
+QT_BEGIN_NAMESPACE
+
+class QByteArray;
+class QDebug;
+struct QJsonParseError;
+class QJsonDocument;
+class QString;
+
+class QRestReplyPrivate;
+class QT_TECH_PREVIEW_API QRestReply
+{
+public:
+ Q_NETWORK_EXPORT explicit QRestReply(QNetworkReply *reply);
+ Q_NETWORK_EXPORT ~QRestReply();
+
+ QRestReply(QRestReply &&other) noexcept
+ : wrapped(std::move(other.wrapped)),
+ d(std::exchange(other.d, nullptr))
+ {
+ }
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QRestReply)
+ void swap(QRestReply &other) noexcept
+ {
+ wrapped.swap(other.wrapped);
+ qt_ptr_swap(d, other.d);
+ }
+
+ Q_NETWORK_EXPORT QNetworkReply *networkReply() const;
+
+ Q_NETWORK_EXPORT std::optional<QJsonDocument> readJson(QJsonParseError *error = nullptr);
+ Q_NETWORK_EXPORT QByteArray readBody();
+ Q_NETWORK_EXPORT QString readText();
+
+ bool isSuccess() const
+ {
+ return !hasError() && isHttpStatusSuccess();
+ }
+ Q_NETWORK_EXPORT int httpStatus() const;
+ Q_NETWORK_EXPORT bool isHttpStatusSuccess() const;
+
+ Q_NETWORK_EXPORT bool hasError() const;
+ Q_NETWORK_EXPORT QNetworkReply::NetworkError error() const;
+ Q_NETWORK_EXPORT QString errorString() const;
+
+private:
+#ifndef QT_NO_DEBUG_STREAM
+ friend Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QRestReply &reply);
+#endif
+ QPointer<QNetworkReply> wrapped;
+ QRestReplyPrivate *d = nullptr;
+ Q_DISABLE_COPY(QRestReply)
+};
+
+Q_DECLARE_SHARED(QRestReply)
+
+QT_END_NAMESPACE
+
+#endif // QRESTREPLY_H
diff --git a/src/network/access/qrestreply_p.h b/src/network/access/qrestreply_p.h
new file mode 100644
index 0000000000..ec963cf168
--- /dev/null
+++ b/src/network/access/qrestreply_p.h
@@ -0,0 +1,40 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QRESTREPLY_P_H
+#define QRESTREPLY_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 <QtCore/private/qstringconverter_p.h>
+
+#include <optional>
+
+QT_BEGIN_NAMESPACE
+
+class QByteArray;
+class QNetworkReply;
+
+class QRestReplyPrivate
+{
+public:
+ QRestReplyPrivate();
+ ~QRestReplyPrivate();
+
+ std::optional<QStringDecoder> decoder;
+
+ static QByteArray contentCharset(const QNetworkReply *reply);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/access/qsocketabstraction_p.h b/src/network/access/qsocketabstraction_p.h
new file mode 100644
index 0000000000..2b40b80244
--- /dev/null
+++ b/src/network/access/qsocketabstraction_p.h
@@ -0,0 +1,91 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSOCKETABSTRACTION_P_H
+#define QSOCKETABSTRACTION_P_H
+
+#include <private/qtnetworkglobal_p.h>
+
+#include <QtNetwork/qabstractsocket.h>
+#include <QtNetwork/qlocalsocket.h>
+
+#include <QtCore/qxpfunctional.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.
+//
+
+QT_BEGIN_NAMESPACE
+
+// Helper functions to deal with a QIODevice that is either a socket or a local
+// socket.
+namespace QSocketAbstraction {
+template <typename Fn, typename... Args>
+auto visit(Fn &&fn, QIODevice *socket, Args &&...args)
+{
+ if (auto *s = qobject_cast<QAbstractSocket *>(socket))
+ return std::forward<Fn>(fn)(s, std::forward<Args>(args)...);
+ if (auto *s = qobject_cast<QLocalSocket *>(socket))
+ return std::forward<Fn>(fn)(s, std::forward<Args>(args)...);
+ Q_UNREACHABLE();
+}
+
+// Since QLocalSocket's LocalSocketState's values are defined as being equal
+// to some of QAbstractSocket's SocketState's values, we can use the superset
+// of the two as the return type.
+inline QAbstractSocket::SocketState socketState(QIODevice *device)
+{
+ auto getState = [](auto *s) {
+ using T = std::remove_pointer_t<decltype(s)>;
+ if constexpr (std::is_same_v<T, QAbstractSocket>) {
+ return s->state();
+ } else if constexpr (std::is_same_v<T, QLocalSocket>) {
+ QLocalSocket::LocalSocketState st = s->state();
+ return static_cast<QAbstractSocket::SocketState>(st);
+ }
+ Q_UNREACHABLE();
+ };
+ return visit(getState, device);
+}
+
+// Same as for socketState(), but for the errors
+inline QAbstractSocket::SocketError socketError(QIODevice *device)
+{
+ auto getError = [](auto *s) {
+ using T = std::remove_pointer_t<decltype(s)>;
+ if constexpr (std::is_same_v<T, QAbstractSocket>) {
+ return s->error();
+ } else if constexpr (std::is_same_v<T, QLocalSocket>) {
+ QLocalSocket::LocalSocketError st = s->error();
+ return static_cast<QAbstractSocket::SocketError>(st);
+ }
+ Q_UNREACHABLE();
+ };
+ return visit(getError, device);
+}
+
+inline QString socketPeerName(QIODevice *device)
+{
+ auto getPeerName = [](auto *s) {
+ using T = std::remove_pointer_t<decltype(s)>;
+ if constexpr (std::is_same_v<T, QAbstractSocket>) {
+ return s->peerName();
+ } else if constexpr (std::is_same_v<T, QLocalSocket>) {
+ return s->serverName();
+ }
+ Q_UNREACHABLE();
+ };
+ return visit(getPeerName, device);
+}
+} // namespace QSocketAbstraction
+
+QT_END_NAMESPACE
+
+#endif // QSOCKETABSTRACTION_P_H
diff --git a/src/network/android/jar/build.gradle b/src/network/android/jar/build.gradle
index c947852f79..68a9381ad2 100644
--- a/src/network/android/jar/build.gradle
+++ b/src/network/android/jar/build.gradle
@@ -7,7 +7,7 @@ buildscript {
}
dependencies {
- classpath 'com.android.tools.build:gradle:7.0.2'
+ classpath 'com.android.tools.build:gradle:8.0.2'
}
}
@@ -23,12 +23,10 @@ repositories {
}
android {
- compileSdkVersion 31
- buildToolsVersion "31.0.3"
+ compileSdk 34
defaultConfig {
minSdkVersion 23
- targetSdkVersion 31
}
sourceSets {
diff --git a/src/network/compat/removed_api.cpp b/src/network/compat/removed_api.cpp
new file mode 100644
index 0000000000..86951d9222
--- /dev/null
+++ b/src/network/compat/removed_api.cpp
@@ -0,0 +1,67 @@
+// Copyright (c) 2023 LLC «V Kontakte»
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#define QT_NETWORK_BUILD_REMOVED_API
+
+#include "qtnetworkglobal.h"
+
+QT_USE_NAMESPACE
+
+#if QT_NETWORK_REMOVED_SINCE(6, 7)
+
+#include "qhostinfo.h"
+
+// static
+int QHostInfo::lookupHost(const QString &name, QObject *receiver, const char *member)
+{
+ const auto *r = receiver;
+ return lookupHost(name, r, member);
+}
+
+
+#include "qnetworkreply.h"
+
+QByteArray QNetworkReply::rawHeader(const QByteArray &headerName) const
+{
+ return rawHeader(qToByteArrayViewIgnoringNull(headerName));
+}
+
+bool QNetworkReply::hasRawHeader(const QByteArray &headerName) const
+{
+ return hasRawHeader(qToByteArrayViewIgnoringNull(headerName));
+}
+
+#include "qnetworkrequest.h"
+
+QByteArray QNetworkRequest::rawHeader(const QByteArray &headerName) const
+{
+ return rawHeader(qToByteArrayViewIgnoringNull(headerName));
+}
+
+bool QNetworkRequest::hasRawHeader(const QByteArray &headerName) const
+{
+ return hasRawHeader(qToByteArrayViewIgnoringNull(headerName));
+}
+
+#include "qnetworkcookie.h"
+
+QList<QNetworkCookie> QNetworkCookie::parseCookies(const QByteArray &cookieString)
+{
+ return parseCookies(qToByteArrayViewIgnoringNull(cookieString));
+}
+
+// #include "qotherheader.h"
+// // implement removed functions from qotherheader.h
+// order sections alphabetically
+
+#endif // QT_NETWORK_REMOVED_SINCE(6, 7)
+
+#if QT_NETWORK_REMOVED_SINCE(6, 8)
+
+#include "qnetworkrequest.h" // inlined API
+
+// #include "qotherheader.h"
+// // implement removed functions from qotherheader.h
+// order sections alphabetically
+
+#endif // QT_NETWORK_REMOVED_SINCE(6, 8)
diff --git a/src/network/configure.cmake b/src/network/configure.cmake
index 32603dff95..cda444b873 100644
--- a/src/network/configure.cmake
+++ b/src/network/configure.cmake
@@ -12,7 +12,7 @@ qt_find_package(Libproxy PROVIDED_TARGETS PkgConfig::Libproxy MODULE_NAME networ
qt_find_package(GSSAPI PROVIDED_TARGETS GSSAPI::GSSAPI MODULE_NAME network QMAKE_LIB gssapi)
qt_find_package(GLIB2 OPTIONAL_COMPONENTS GOBJECT PROVIDED_TARGETS GLIB2::GOBJECT MODULE_NAME core QMAKE_LIB gobject)
qt_find_package(GLIB2 OPTIONAL_COMPONENTS GIO PROVIDED_TARGETS GLIB2::GIO MODULE_NAME core QMAKE_LIB gio)
-
+qt_find_package(WrapResolv PROVIDED_TARGETS WrapResolv::WrapResolv MODULE_NAME network QMAKE_LIB libresolv)
#### Tests
@@ -37,22 +37,6 @@ freeifaddrs(list);
"# FIXME: use: unmapped library: network
)
-# ifr_index
-qt_config_compile_test(ifr_index
- LABEL "ifr_index"
- CODE
-"#include <net/if.h>
-
-int main(void)
-{
- /* BEGIN TEST: */
-struct ifreq req;
-req.ifr_index = 0;
- /* END TEST: */
- return 0;
-}
-")
-
# ipv6ifname
qt_config_compile_test(ipv6ifname
LABEL "IPv6 ifname"
@@ -100,6 +84,25 @@ ci.ifa_prefered = ci.ifa_valid = 0;
}
")
+# res_setserver
+qt_config_compile_test(res_setservers
+ LABEL "res_setservers()"
+ LIBRARIES
+ WrapResolv::WrapResolv
+ CODE
+"#include <sys/types.h>
+#include <netinet/in.h>
+#include <resolv.h>
+int main()
+{
+ union res_sockaddr_union sa;
+ res_state s = nullptr;
+ res_setservers(s, &sa, 1);
+ return 0;
+}
+"
+)
+
# sctp
qt_config_compile_test(sctp
LABEL "SCTP support"
@@ -190,18 +193,19 @@ connectionPointContainer->FindConnectionPoint(IID_INetworkConnectionEvents, &con
qt_feature("getifaddrs" PUBLIC
LABEL "getifaddrs()"
- CONDITION TEST_getifaddrs
+ CONDITION VXWORKS OR UNIX AND NOT QT_FEATURE_linux_netlink AND TEST_getifaddrs
)
qt_feature_definition("getifaddrs" "QT_NO_GETIFADDRS" NEGATE VALUE "1")
-qt_feature("ifr_index" PRIVATE
- LABEL "ifr_index"
- CONDITION TEST_ifr_index
-)
qt_feature("ipv6ifname" PUBLIC
LABEL "IPv6 ifname"
- CONDITION TEST_ipv6ifname
+ CONDITION VXWORKS OR UNIX AND NOT QT_FEATURE_linux_netlink AND TEST_ipv6ifname
)
qt_feature_definition("ipv6ifname" "QT_NO_IPV6IFNAME" NEGATE VALUE "1")
+qt_feature("libresolv" PRIVATE
+ LABEL "libresolv"
+ CONDITION WrapResolv_FOUND
+ AUTODETECT UNIX
+)
qt_feature("libproxy" PRIVATE
LABEL "libproxy"
AUTODETECT OFF
@@ -211,6 +215,10 @@ qt_feature("linux-netlink" PRIVATE
LABEL "Linux AF_NETLINK"
CONDITION LINUX AND NOT ANDROID AND TEST_linux_netlink
)
+qt_feature("res_setservers" PRIVATE
+ LABEL "res_setservers()"
+ CONDITION QT_FEATURE_libresolv AND TEST_res_setservers
+)
qt_feature("securetransport" PUBLIC
LABEL "SecureTransport"
CONDITION APPLE
@@ -307,7 +315,7 @@ qt_feature("dnslookup" PUBLIC
SECTION "Networking"
LABEL "QDnsLookup"
PURPOSE "Provides API for DNS lookups."
- CONDITION NOT INTEGRITY
+ CONDITION QT_FEATURE_thread AND NOT INTEGRITY
)
qt_feature("gssapi" PUBLIC
SECTION "Networking"
diff --git a/src/network/doc/qtnetwork.qdocconf b/src/network/doc/qtnetwork.qdocconf
index ad6f5d2850..1e1162bdac 100644
--- a/src/network/doc/qtnetwork.qdocconf
+++ b/src/network/doc/qtnetwork.qdocconf
@@ -23,7 +23,7 @@ qhp.QtNetwork.subprojects.classes.sortPages = true
tagfile = ../../../doc/qtnetwork/qtnetwork.tags
-depends += qtcore qtgui qtdoc qmake qtcmake
+depends += qtcore qtgui qtdoc qmake qtcmake qtwidgets
headerdirs += ..
@@ -40,5 +40,12 @@ imagedirs += images \
navigation.landingpage = "Qt Network"
navigation.cppclassespage = "Qt Network C++ Classes"
-# Fail the documentation build if there are more warnings than the limit
+manifestmeta.highlighted.names = \
+ "QtNetwork/Fortune Client" \
+ "QtNetwork/Fortune Server" \
+ "QtNetwork/HTTP Client" \
+ "QtNetwork/Secure Socket Client" \
+ "QtNetwork/Torrent Example"
+
+# Enforce zero documentation warnings
warninglimit = 0
diff --git a/src/network/doc/snippets/CMakeLists.txt b/src/network/doc/snippets/CMakeLists.txt
index 97574156ad..05e5668e24 100644
--- a/src/network/doc/snippets/CMakeLists.txt
+++ b/src/network/doc/snippets/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
diff --git a/src/network/doc/snippets/code/doc_src_qtnetwork.cpp b/src/network/doc/snippets/code/doc_src_qtnetwork.cpp
deleted file mode 100644
index dae56d5db5..0000000000
--- a/src/network/doc/snippets/code/doc_src_qtnetwork.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-//! [1]
-#include <QtNetwork>
-//! [1]
diff --git a/src/network/doc/snippets/code/src_network_access_qhttpmultipart.cpp b/src/network/doc/snippets/code/src_network_access_qhttpmultipart.cpp
index cf51c68861..73308b5547 100644
--- a/src/network/doc/snippets/code/src_network_access_qhttpmultipart.cpp
+++ b/src/network/doc/snippets/code/src_network_access_qhttpmultipart.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
diff --git a/src/network/doc/snippets/code/src_network_access_qhttppart.cpp b/src/network/doc/snippets/code/src_network_access_qhttppart.cpp
index 38d1b7aff0..059a4c60e9 100644
--- a/src/network/doc/snippets/code/src_network_access_qhttppart.cpp
+++ b/src/network/doc/snippets/code/src_network_access_qhttppart.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
Content-Type: text/plain
diff --git a/src/network/doc/snippets/code/src_network_access_qnetworkrequestfactory.cpp b/src/network/doc/snippets/code/src_network_access_qnetworkrequestfactory.cpp
new file mode 100644
index 0000000000..f7994d442c
--- /dev/null
+++ b/src/network/doc/snippets/code/src_network_access_qnetworkrequestfactory.cpp
@@ -0,0 +1,27 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+using namespace Qt::StringLiterals;
+
+//! [0]
+// Instantiate a factory somewhere suitable in the application
+QNetworkRequestFactory api{{"https://example.com/v1"_L1}};
+
+// Set bearer token
+api.setBearerToken("my_token");
+
+// Issue requests (reply handling omitted for brevity)
+manager.get(api.createRequest("models"_L1)); // https://example.com/v1/models
+// The conventional leading '/' for the path can be used as well
+manager.get(api.createRequest("/models"_L1)); // https://example.com/v1/models
+//! [0]
+
+
+//! [1]
+// Here the API version v2 is used as the base path:
+QNetworkRequestFactory api{{"https://example.com/v2"_L1}};
+// ...
+manager.get(api.createRequest("models"_L1)); // https://example.com/v2/models
+// Equivalent with a leading '/'
+manager.get(api.createRequest("/models"_L1)); // https://example.com/v2/models
+//! [1]
+
diff --git a/src/network/doc/snippets/code/src_network_access_qrestaccessmanager.cpp b/src/network/doc/snippets/code/src_network_access_qrestaccessmanager.cpp
new file mode 100644
index 0000000000..8f9e00f4b6
--- /dev/null
+++ b/src/network/doc/snippets/code/src_network_access_qrestaccessmanager.cpp
@@ -0,0 +1,104 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [0]
+QNetworkReply *reply = manager->get(request);
+QObject::connect(reply, &QNetworkReply::finished, this, [reply]() {
+ // The reply may be wrapped in the finish handler:
+ QRestReply restReply(reply);
+ if (restReply.isSuccess())
+ // ...
+});
+//! [0]
+
+
+//! [1]
+// With lambda
+manager->get(request, this, [this](QRestReply &reply) {
+ if (reply.isSuccess()) {
+ // ...
+ }
+});
+// With member function
+manager->get(request, this, &MyClass::handleFinished);
+//! [1]
+
+
+//! [2]
+QJsonDocument myJson;
+// ...
+manager->post(request, myJson, this, [this](QRestReply &reply) {
+ if (!reply.isSuccess()) {
+ // ...
+ }
+ if (std::optional json = reply.readJson()) {
+ // use *json
+ }
+});
+//! [2]
+
+
+//! [3]
+manager->get(request, this, [this](QRestReply &reply) {
+ if (!reply.isSuccess())
+ // handle error
+ if (std::optional json = reply.readJson())
+ // use *json
+});
+//! [3]
+
+
+//! [4]
+manager->get(request, myData, this, [this](QRestReply &reply) {
+ if (reply.isSuccess())
+ // ...
+});
+//! [4]
+
+
+//! [5]
+manager->post(request, myData, this, [this](QRestReply &reply) {
+ if (reply.isSuccess())
+ // ...
+});
+//! [5]
+
+
+//! [6]
+manager->put(request, myData, this, [this](QRestReply &reply) {
+ if (reply.isSuccess())
+ // ...
+});
+//! [6]
+
+
+//! [7]
+manager->head(request, this, [this](QRestReply &reply) {
+ if (reply.isSuccess())
+ // ...
+});
+//! [7]
+
+
+//! [8]
+manager->deleteResource(request, this, [this](QRestReply &reply) {
+ if (reply.isSuccess())
+ // ...
+});
+//! [8]
+
+
+//! [9]
+manager->sendCustomRequest(request, "MYMETHOD", myData, this, [this](QRestReply &reply) {
+ if (reply.isSuccess())
+ // ...
+});
+//! [9]
+
+
+//! [10]
+manager->patch(request, myData, this, [this](QRestReply &reply) {
+ if (reply.isSuccess())
+ // ...
+});
+//! [10]
diff --git a/src/network/doc/snippets/code/src_network_kernel_qnetworkinterface.cpp b/src/network/doc/snippets/code/src_network_kernel_qnetworkinterface.cpp
index 4f3839532d..d34750aaaf 100644
--- a/src/network/doc/snippets/code/src_network_kernel_qnetworkinterface.cpp
+++ b/src/network/doc/snippets/code/src_network_kernel_qnetworkinterface.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
QNetworkInterface::interfaceFromName(name).index()
diff --git a/src/network/doc/snippets/code/src_network_ssl_qsslconfiguration.cpp b/src/network/doc/snippets/code/src_network_ssl_qsslconfiguration.cpp
index edc542ac3f..d9a493d1ce 100644
--- a/src/network/doc/snippets/code/src_network_ssl_qsslconfiguration.cpp
+++ b/src/network/doc/snippets/code/src_network_ssl_qsslconfiguration.cpp
@@ -6,10 +6,3 @@ QSslConfiguration config = sslSocket.sslConfiguration();
config.setProtocol(QSsl::TlsV1_2);
sslSocket.setSslConfiguration(config);
//! [0]
-
-
-//! [1]
-QSslConfiguration tlsConfig = QSslConfiguration::defaultConfiguration();
-tlsConfig.setCiphers(QStringLiteral("DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:AES256-SHA"));
-//! [1]
-
diff --git a/src/network/doc/snippets/code/src_network_ssl_qsslpresharedkeyauthenticator.cpp b/src/network/doc/snippets/code/src_network_ssl_qsslpresharedkeyauthenticator.cpp
index 1af356ee00..b3242e057d 100644
--- a/src/network/doc/snippets/code/src_network_ssl_qsslpresharedkeyauthenticator.cpp
+++ b/src/network/doc/snippets/code/src_network_ssl_qsslpresharedkeyauthenticator.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
connect(socket, &QSslSocket::preSharedKeyAuthenticationRequired,
diff --git a/src/network/doc/snippets/code/src_network_ssl_qsslsocket.cpp b/src/network/doc/snippets/code/src_network_ssl_qsslsocket.cpp
index 89d82d66f8..eed032589e 100644
--- a/src/network/doc/snippets/code/src_network_ssl_qsslsocket.cpp
+++ b/src/network/doc/snippets/code/src_network_ssl_qsslsocket.cpp
@@ -49,12 +49,6 @@ socket->write("1 CAPABILITY\r\n");
//! [3]
-//! [4]
-QSslSocket socket;
-socket.setCiphers("DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:AES256-SHA");
-//! [4]
-
-
//! [5]
socket->connectToHostEncrypted("imap", 993);
if (socket->waitForEncrypted(1000))
diff --git a/src/network/doc/snippets/network/CMakeLists.txt b/src/network/doc/snippets/network/CMakeLists.txt
index be403e79b1..b75aeafea0 100644
--- a/src/network/doc/snippets/network/CMakeLists.txt
+++ b/src/network/doc/snippets/network/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
add_library(network_cppsnippets OBJECT tcpwait.cpp)
diff --git a/src/network/doc/src/ssl.qdoc b/src/network/doc/src/ssl.qdoc
index ba13c97cfc..83549f61e8 100644
--- a/src/network/doc/src/ssl.qdoc
+++ b/src/network/doc/src/ssl.qdoc
@@ -16,6 +16,8 @@
From Qt version 5.15 onward, the officially supported version for OpenSSL
is 1.1.1 or later.
+ Qt version 5.15.1 onward is also compatible with OpenSSL 3.
+
\annotatedlist ssl
For Android applications see \l{Adding OpenSSL Support for Android}.
diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp
index 91660cf2f7..e42450d7e5 100644
--- a/src/network/kernel/qauthenticator.cpp
+++ b/src/network/kernel/qauthenticator.cpp
@@ -14,6 +14,7 @@
#include <qstring.h>
#include <qdatetime.h>
#include <qrandom.h>
+#include <QtNetwork/qhttpheaders.h>
#ifdef Q_OS_WIN
#include <qmutex.h>
@@ -444,13 +445,14 @@ static bool verifyDigestMD5(QByteArrayView value)
return true; // assume it's ok if algorithm is not specified
}
-void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByteArray>> &values,
+void QAuthenticatorPrivate::parseHttpResponse(const QHttpHeaders &headers,
bool isProxy, QStringView host)
{
#if !QT_CONFIG(gssapi)
Q_UNUSED(host);
#endif
- const char *search = isProxy ? "proxy-authenticate" : "www-authenticate";
+ const auto search = isProxy ? QHttpHeaders::WellKnownHeader::ProxyAuthenticate
+ : QHttpHeaders::WellKnownHeader::WWWAuthenticate;
method = None;
/*
@@ -463,26 +465,23 @@ void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByt
authentication parameters.
*/
- QByteArray headerVal;
- for (int i = 0; i < values.size(); ++i) {
- const QPair<QByteArray, QByteArray> &current = values.at(i);
- if (current.first.compare(search, Qt::CaseInsensitive) != 0)
- continue;
- QByteArray str = current.second.toLower();
- if (method < Basic && str.startsWith("basic")) {
+ QByteArrayView headerVal;
+ for (const auto &current : headers.values(search)) {
+ const QLatin1StringView str(current);
+ if (method < Basic && str.startsWith("basic"_L1, Qt::CaseInsensitive)) {
method = Basic;
- headerVal = current.second.mid(6);
- } else if (method < Ntlm && str.startsWith("ntlm")) {
+ headerVal = QByteArrayView(current).mid(6);
+ } else if (method < Ntlm && str.startsWith("ntlm"_L1, Qt::CaseInsensitive)) {
method = Ntlm;
- headerVal = current.second.mid(5);
- } else if (method < DigestMd5 && str.startsWith("digest")) {
+ headerVal = QByteArrayView(current).mid(5);
+ } else if (method < DigestMd5 && str.startsWith("digest"_L1, Qt::CaseInsensitive)) {
// Make sure the algorithm is actually MD5 before committing to it:
- if (!verifyDigestMD5(QByteArrayView(current.second).sliced(7)))
+ if (!verifyDigestMD5(QByteArrayView(current).sliced(7)))
continue;
method = DigestMd5;
- headerVal = current.second.mid(7);
- } else if (method < Negotiate && str.startsWith("negotiate")) {
+ headerVal = QByteArrayView(current).mid(7);
+ } else if (method < Negotiate && str.startsWith("negotiate"_L1, Qt::CaseInsensitive)) {
#if QT_CONFIG(sspi) || QT_CONFIG(gssapi) // if it's not supported then we shouldn't try to use it
#if QT_CONFIG(gssapi)
// For GSSAPI there needs to be a KDC set up for the host (afaict).
@@ -492,14 +491,14 @@ void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByt
continue;
#endif
method = Negotiate;
- headerVal = current.second.mid(10);
+ headerVal = QByteArrayView(current).mid(10);
#endif
}
}
// Reparse credentials since we know the method now
updateCredentials();
- challenge = headerVal.trimmed();
+ challenge = headerVal.trimmed().toByteArray();
QHash<QByteArray, QByteArray> options = parseDigestAuthenticationChallenge(challenge);
// Sets phase to Start if this updates our realm and sets the two locations where we store
@@ -547,16 +546,14 @@ QByteArray QAuthenticatorPrivate::calculateResponse(QByteArrayView requestMethod
Q_UNUSED(host);
#endif
QByteArray response;
- const char* methodString = nullptr;
+ QByteArrayView methodString;
switch(method) {
case QAuthenticatorPrivate::None:
- methodString = "";
phase = Done;
break;
case QAuthenticatorPrivate::Basic:
methodString = "Basic";
- response = user.toLatin1() + ':' + password.toLatin1();
- response = response.toBase64();
+ response = (user + ':'_L1 + password).toLatin1().toBase64();
phase = Done;
break;
case QAuthenticatorPrivate::DigestMd5:
@@ -645,12 +642,21 @@ QByteArray QAuthenticatorPrivate::calculateResponse(QByteArrayView requestMethod
break;
}
- return QByteArray::fromRawData(methodString, qstrlen(methodString)) + ' ' + response;
+ return methodString + ' ' + response;
}
// ---------------------------- Digest Md5 code ----------------------------------------
+static bool containsAuth(QByteArrayView data)
+{
+ for (auto element : QLatin1StringView(data).tokenize(','_L1)) {
+ if (element == "auth"_L1)
+ return true;
+ }
+ return false;
+}
+
QHash<QByteArray, QByteArray>
QAuthenticatorPrivate::parseDigestAuthenticationChallenge(QByteArrayView challenge)
{
@@ -664,7 +670,7 @@ QAuthenticatorPrivate::parseDigestAuthenticationChallenge(QByteArrayView challen
const char *start = d;
while (d < end && *d != '=')
++d;
- QByteArray key = QByteArray(start, d - start);
+ QByteArrayView key = QByteArrayView(start, d - start);
++d;
if (d >= end)
break;
@@ -695,13 +701,12 @@ QAuthenticatorPrivate::parseDigestAuthenticationChallenge(QByteArrayView challen
while (d < end && *d != ',')
++d;
++d;
- options[key] = value;
+ options[key.toByteArray()] = std::move(value);
}
QByteArray qop = options.value("qop");
if (!qop.isEmpty()) {
- QList<QByteArray> qopoptions = qop.split(',');
- if (!qopoptions.contains("auth"))
+ if (!containsAuth(qop))
return QHash<QByteArray, QByteArray>();
// #### can't do auth-int currently
// if (qop.contains("auth-int"))
diff --git a/src/network/kernel/qauthenticator.h b/src/network/kernel/qauthenticator.h
index 4d8e85c000..a05d359e93 100644
--- a/src/network/kernel/qauthenticator.h
+++ b/src/network/kernel/qauthenticator.h
@@ -16,6 +16,7 @@ class QUrl;
class Q_NETWORK_EXPORT QAuthenticator
{
+ Q_GADGET
public:
QAuthenticator();
~QAuthenticator();
diff --git a/src/network/kernel/qauthenticator_p.h b/src/network/kernel/qauthenticator_p.h
index 7c4fe736b5..bc16139941 100644
--- a/src/network/kernel/qauthenticator_p.h
+++ b/src/network/kernel/qauthenticator_p.h
@@ -26,6 +26,7 @@
QT_BEGIN_NAMESPACE
class QHttpResponseHeader;
+class QHttpHeaders;
#if QT_CONFIG(sspi) // SSPI
class QSSPIWindowsHandles;
#elif QT_CONFIG(gssapi) // GSSAPI
@@ -80,8 +81,7 @@ public:
static QHash<QByteArray, QByteArray>
parseDigestAuthenticationChallenge(QByteArrayView challenge);
- void parseHttpResponse(const QList<QPair<QByteArray, QByteArray>> &, bool isProxy,
- QStringView host);
+ void parseHttpResponse(const QHttpHeaders &headers, bool isProxy, QStringView host);
void updateCredentials();
static bool isMethodSupported(QByteArrayView method);
diff --git a/src/network/kernel/qdnslookup.cpp b/src/network/kernel/qdnslookup.cpp
index fb8a96a049..c310c7e28e 100644
--- a/src/network/kernel/qdnslookup.cpp
+++ b/src/network/kernel/qdnslookup.cpp
@@ -1,11 +1,14 @@
// Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
+// Copyright (C) 2023 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdnslookup.h"
#include "qdnslookup_p.h"
+#include <qapplicationstatic.h>
#include <qcoreapplication.h>
#include <qdatetime.h>
+#include <qloggingcategory.h>
#include <qrandom.h>
#include <qurl.h>
@@ -13,11 +16,20 @@
QT_BEGIN_NAMESPACE
-QT_IMPL_METATYPE_EXTERN(QDnsLookupReply)
+static Q_LOGGING_CATEGORY(lcDnsLookup, "qt.network.dnslookup", QtCriticalMsg)
-#if QT_CONFIG(thread)
-Q_GLOBAL_STATIC(QDnsLookupThreadPool, theDnsLookupThreadPool);
-#endif
+namespace {
+struct QDnsLookupThreadPool : QThreadPool
+{
+ QDnsLookupThreadPool()
+ {
+ // Run up to 5 lookups in parallel.
+ setMaxThreadCount(5);
+ }
+};
+}
+
+Q_APPLICATION_STATIC(QDnsLookupThreadPool, theDnsLookupThreadPool);
static bool qt_qdnsmailexchangerecord_less_than(const QDnsMailExchangeRecord &r1, const QDnsMailExchangeRecord &r2)
{
@@ -121,9 +133,6 @@ static void qt_qdnsservicerecord_sort(QList<QDnsServiceRecord> &records)
}
}
-const char *QDnsLookupPrivate::msgNoIpV6NameServerAdresses =
- QT_TRANSLATE_NOOP("QDnsLookupRunnable", "IPv6 addresses for nameservers are currently not supported");
-
/*!
\class QDnsLookup
\brief The QDnsLookup class represents a DNS lookup.
@@ -178,6 +187,9 @@ const char *QDnsLookupPrivate::msgNoIpV6NameServerAdresses =
\value NotFoundError the requested domain name does not exist
(NXDOMAIN).
+
+ \value TimeoutError the server was not reached or did not reply
+ in time (since 6.6).
*/
/*!
@@ -233,8 +245,8 @@ const char *QDnsLookupPrivate::msgNoIpV6NameServerAdresses =
QDnsLookup::QDnsLookup(QObject *parent)
: QObject(*new QDnsLookupPrivate, parent)
{
- qRegisterMetaType<QDnsLookupReply>();
}
+
/*!
Constructs a QDnsLookup object for the given \a type and \a name and sets
\a parent as the parent object.
@@ -244,7 +256,6 @@ QDnsLookup::QDnsLookup(Type type, const QString &name, QObject *parent)
: QObject(*new QDnsLookupPrivate, parent)
{
Q_D(QDnsLookup);
- qRegisterMetaType<QDnsLookupReply>();
d->name = name;
d->type = type;
}
@@ -252,17 +263,39 @@ QDnsLookup::QDnsLookup(Type type, const QString &name, QObject *parent)
/*!
\fn QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent)
\since 5.4
- Constructs a QDnsLookup object for the given \a type, \a name and
- \a nameserver and sets \a parent as the parent object.
+
+ Constructs a QDnsLookup object to issue a query for \a name of record type
+ \a type, using the DNS server \a nameserver running on the default DNS port,
+ and sets \a parent as the parent object.
*/
QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent)
+ : QDnsLookup(type, name, nameserver, DnsPort, parent)
+{
+}
+
+/*!
+ \fn QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, quint16 port, QObject *parent)
+ \since 6.6
+
+ Constructs a QDnsLookup object to issue a query for \a name of record type
+ \a type, using the DNS server \a nameserver running on port \a port, and
+ sets \a parent as the parent object.
+
+//! [nameserver-port]
+ \note Setting the port number to any value other than the default (53) can
+ cause the name resolution to fail, depending on the operating system
+ limitations and firewalls. Notably, the Windows API used by QDnsLookup is
+ unable to handle alternate port numbers.
+//! [nameserver-port]
+*/
+QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, quint16 port, QObject *parent)
: QObject(*new QDnsLookupPrivate, parent)
{
Q_D(QDnsLookup);
- qRegisterMetaType<QDnsLookupReply>();
d->name = name;
d->type = type;
+ d->port = port;
d->nameserver = nameserver;
}
@@ -310,6 +343,10 @@ bool QDnsLookup::isFinished() const
\property QDnsLookup::name
\brief the name to lookup.
+ If the name to look up is empty, QDnsLookup will attempt to resolve the
+ root domain of DNS. That query is usually performed with QDnsLookup::type
+ set to \l{QDnsLookup::Type}{NS}.
+
\note The name will be encoded using IDNA, which means it's unsuitable for
querying SRV records compatible with the DNS-SD specification.
*/
@@ -376,6 +413,46 @@ QBindable<QHostAddress> QDnsLookup::bindableNameserver()
}
/*!
+ \property QDnsLookup::nameserverPort
+ \since 6.6
+ \brief the port number of nameserver to use for DNS lookup.
+ \include qdnslookup.cpp nameserver-port
+*/
+
+quint16 QDnsLookup::nameserverPort() const
+{
+ return d_func()->port;
+}
+
+void QDnsLookup::setNameserverPort(quint16 nameserverPort)
+{
+ Q_D(QDnsLookup);
+ d->port = nameserverPort;
+}
+
+QBindable<quint16> QDnsLookup::bindableNameserverPort()
+{
+ Q_D(QDnsLookup);
+ return &d->port;
+}
+
+/*!
+ \since 6.6
+ Sets the nameserver to \a nameserver and the port to \a port.
+
+ \include qdnslookup.cpp nameserver-port
+
+ \sa QDnsLookup::nameserver, QDnsLookup::nameserverPort
+*/
+void QDnsLookup::setNameserver(const QHostAddress &nameserver, quint16 port)
+{
+ Qt::beginPropertyUpdateGroup();
+ setNameserver(nameserver);
+ setNameserverPort(port);
+ Qt::endPropertyUpdateGroup();
+}
+
+/*!
Returns the list of canonical name records associated with this lookup.
*/
@@ -476,13 +553,29 @@ void QDnsLookup::lookup()
Q_D(QDnsLookup);
d->isFinished = false;
d->reply = QDnsLookupReply();
- d->runnable = new QDnsLookupRunnable(d->type, QUrl::toAce(d->name), d->nameserver);
- connect(d->runnable, SIGNAL(finished(QDnsLookupReply)),
- this, SLOT(_q_lookupFinished(QDnsLookupReply)),
- Qt::BlockingQueuedConnection);
-#if QT_CONFIG(thread)
- theDnsLookupThreadPool()->start(d->runnable);
+ if (!QCoreApplication::instance()) {
+ // NOT qCWarning because this isn't a result of the lookup
+ qWarning("QDnsLookup requires a QCoreApplication");
+ return;
+ }
+
+ auto l = [this](const QDnsLookupReply &reply) {
+ Q_D(QDnsLookup);
+ if (d->runnable == sender()) {
+#ifdef QDNSLOOKUP_DEBUG
+ qDebug("DNS reply for %s: %i (%s)", qPrintable(d->name), reply.error, qPrintable(reply.errorString));
#endif
+ d->reply = reply;
+ d->runnable = nullptr;
+ d->isFinished = true;
+ emit finished();
+ }
+ };
+
+ d->runnable = new QDnsLookupRunnable(d);
+ connect(d->runnable, &QDnsLookupRunnable::finished, this, l,
+ Qt::BlockingQueuedConnection);
+ theDnsLookupThreadPool->start(d->runnable);
}
/*!
@@ -959,18 +1052,26 @@ QDnsTextRecord &QDnsTextRecord::operator=(const QDnsTextRecord &other)
very fast and never fails.
*/
-void QDnsLookupPrivate::_q_lookupFinished(const QDnsLookupReply &_reply)
+static QDnsLookupRunnable::EncodedLabel encodeLabel(const QString &label)
{
- Q_Q(QDnsLookup);
- if (runnable == q->sender()) {
-#ifdef QDNSLOOKUP_DEBUG
- qDebug("DNS reply for %s: %i (%s)", qPrintable(name), _reply.error, qPrintable(_reply.errorString));
+ QDnsLookupRunnable::EncodedLabel::value_type rootDomain = u'.';
+ if (label.isEmpty())
+ return QDnsLookupRunnable::EncodedLabel(1, rootDomain);
+
+ QString encodedLabel = qt_ACE_do(label, ToAceOnly, ForbidLeadingDot);
+#ifdef Q_OS_WIN
+ return encodedLabel;
+#else
+ return std::move(encodedLabel).toLatin1();
#endif
- reply = _reply;
- runnable = nullptr;
- isFinished = true;
- emit q->finished();
- }
+}
+
+inline QDnsLookupRunnable::QDnsLookupRunnable(const QDnsLookupPrivate *d)
+ : requestName(encodeLabel(d->name)),
+ nameserver(d->nameserver),
+ requestType(d->type),
+ port(d->port)
+{
}
void QDnsLookupRunnable::run()
@@ -978,60 +1079,53 @@ void QDnsLookupRunnable::run()
QDnsLookupReply reply;
// Validate input.
- if (requestName.isEmpty()) {
+ if (qsizetype n = requestName.size(); n > MaxDomainNameLength || n == 0) {
reply.error = QDnsLookup::InvalidRequestError;
- reply.errorString = tr("Invalid domain name");
- emit finished(reply);
- return;
+ reply.errorString = QDnsLookup::tr("Invalid domain name");
+ } else {
+ // Perform request.
+ query(&reply);
+
+ // Sort results.
+ qt_qdnsmailexchangerecord_sort(reply.mailExchangeRecords);
+ qt_qdnsservicerecord_sort(reply.serviceRecords);
}
- // Perform request.
- query(requestType, requestName, nameserver, &reply);
-
- // Sort results.
- qt_qdnsmailexchangerecord_sort(reply.mailExchangeRecords);
- qt_qdnsservicerecord_sort(reply.serviceRecords);
-
emit finished(reply);
-}
-
-#if QT_CONFIG(thread)
-QDnsLookupThreadPool::QDnsLookupThreadPool()
- : signalsConnected(false)
-{
- // Run up to 5 lookups in parallel.
- setMaxThreadCount(5);
-}
-
-void QDnsLookupThreadPool::start(QRunnable *runnable)
-{
- // Ensure threads complete at application destruction.
- if (!signalsConnected) {
- QMutexLocker signalsLocker(&signalsMutex);
- if (!signalsConnected) {
- QCoreApplication *app = QCoreApplication::instance();
- if (!app) {
- qWarning("QDnsLookup requires a QCoreApplication");
- delete runnable;
- return;
- }
- moveToThread(app->thread());
- connect(app, SIGNAL(destroyed()),
- SLOT(_q_applicationDestroyed()), Qt::DirectConnection);
- signalsConnected = true;
- }
+ // maybe print the lookup error as warning
+ switch (reply.error) {
+ case QDnsLookup::NoError:
+ case QDnsLookup::OperationCancelledError:
+ case QDnsLookup::NotFoundError:
+ case QDnsLookup::ServerFailureError:
+ case QDnsLookup::ServerRefusedError:
+ case QDnsLookup::TimeoutError:
+ break; // no warning for these
+
+ case QDnsLookup::ResolverError:
+ case QDnsLookup::InvalidRequestError:
+ case QDnsLookup::InvalidReplyError:
+ qCWarning(lcDnsLookup()).nospace()
+ << "DNS lookup failed (" << reply.error << "): "
+ << qUtf16Printable(reply.errorString)
+ << "; request was " << this; // continues below
}
-
- QThreadPool::start(runnable);
}
-void QDnsLookupThreadPool::_q_applicationDestroyed()
+inline QDebug operator<<(QDebug &d, QDnsLookupRunnable *r)
{
- waitForDone();
- signalsConnected = false;
+ // continued: print the information about the request
+ d << r->requestName.left(MaxDomainNameLength);
+ if (r->requestName.size() > MaxDomainNameLength)
+ d << "... (truncated)";
+ d << " type " << r->requestType;
+ if (!r->nameserver.isNull())
+ d << " to nameserver " << qUtf16Printable(r->nameserver.toString())
+ << " port " << (r->port ? r->port : DnsPort);
+ return d;
}
-#endif // QT_CONFIG(thread)
+
QT_END_NAMESPACE
#include "moc_qdnslookup.cpp"
diff --git a/src/network/kernel/qdnslookup.h b/src/network/kernel/qdnslookup.h
index bf31b81da1..ae89a0a11f 100644
--- a/src/network/kernel/qdnslookup.h
+++ b/src/network/kernel/qdnslookup.h
@@ -146,6 +146,8 @@ class Q_NETWORK_EXPORT QDnsLookup : public QObject
Q_PROPERTY(Type type READ type WRITE setType NOTIFY typeChanged BINDABLE bindableType)
Q_PROPERTY(QHostAddress nameserver READ nameserver WRITE setNameserver NOTIFY nameserverChanged
BINDABLE bindableNameserver)
+ Q_PROPERTY(quint16 nameserverPort READ nameserverPort WRITE setNameserverPort
+ NOTIFY nameserverPortChanged BINDABLE bindableNameserverPort)
public:
enum Error
@@ -157,7 +159,8 @@ public:
InvalidReplyError,
ServerFailureError,
ServerRefusedError,
- NotFoundError
+ NotFoundError,
+ TimeoutError,
};
Q_ENUM(Error)
@@ -178,6 +181,8 @@ public:
explicit QDnsLookup(QObject *parent = nullptr);
QDnsLookup(Type type, const QString &name, QObject *parent = nullptr);
QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent = nullptr);
+ QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, quint16 port,
+ QObject *parent = nullptr);
~QDnsLookup();
Error error() const;
@@ -195,6 +200,10 @@ public:
QHostAddress nameserver() const;
void setNameserver(const QHostAddress &nameserver);
QBindable<QHostAddress> bindableNameserver();
+ quint16 nameserverPort() const;
+ void setNameserverPort(quint16 port);
+ QBindable<quint16> bindableNameserverPort();
+ void setNameserver(const QHostAddress &nameserver, quint16 port);
QList<QDnsDomainNameRecord> canonicalNameRecords() const;
QList<QDnsHostAddressRecord> hostAddressRecords() const;
@@ -214,10 +223,10 @@ Q_SIGNALS:
void nameChanged(const QString &name);
void typeChanged(Type type);
void nameserverChanged(const QHostAddress &nameserver);
+ void nameserverPortChanged(quint16 port);
private:
Q_DECLARE_PRIVATE(QDnsLookup)
- Q_PRIVATE_SLOT(d_func(), void _q_lookupFinished(const QDnsLookupReply &reply))
};
QT_END_NAMESPACE
diff --git a/src/network/kernel/qdnslookup_android.cpp b/src/network/kernel/qdnslookup_android.cpp
deleted file mode 100644
index 8fc1265e80..0000000000
--- a/src/network/kernel/qdnslookup_android.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (C) 2012 Collabora Ltd, author <robin.burchell@collabora.co.uk>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include "qdnslookup_p.h"
-
-QT_BEGIN_NAMESPACE
-
-void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, const QHostAddress &nameserver, QDnsLookupReply *reply)
-{
- Q_UNUSED(requestType);
- Q_UNUSED(requestName);
- Q_UNUSED(nameserver);
- Q_UNUSED(reply);
- qWarning("Not yet supported on Android");
- reply->error = QDnsLookup::ResolverError;
- reply->errorString = tr("Not yet supported on Android");
- return;
-}
-
-QT_END_NAMESPACE
diff --git a/src/network/kernel/qdnslookup_dummy.cpp b/src/network/kernel/qdnslookup_dummy.cpp
new file mode 100644
index 0000000000..6cc6ed92c5
--- /dev/null
+++ b/src/network/kernel/qdnslookup_dummy.cpp
@@ -0,0 +1,15 @@
+// Copyright (C) 2012 Collabora Ltd, author <robin.burchell@collabora.co.uk>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qdnslookup_p.h"
+
+QT_BEGIN_NAMESPACE
+
+void QDnsLookupRunnable::query(QDnsLookupReply *reply)
+{
+ reply->error = QDnsLookup::ResolverError;
+ reply->errorString = tr("Not yet supported on this OS");
+ return;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/kernel/qdnslookup_p.h b/src/network/kernel/qdnslookup_p.h
index 995640362c..da4721411b 100644
--- a/src/network/kernel/qdnslookup_p.h
+++ b/src/network/kernel/qdnslookup_p.h
@@ -1,4 +1,5 @@
// Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
+// Copyright (C) 2023 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QDNSLOOKUP_P_H
@@ -24,6 +25,7 @@
#include "QtNetwork/qdnslookup.h"
#include "QtNetwork/qhostaddress.h"
#include "private/qobject_p.h"
+#include "private/qurl_p.h"
QT_REQUIRE_CONFIG(dnslookup);
@@ -31,16 +33,16 @@ QT_BEGIN_NAMESPACE
//#define QDNSLOOKUP_DEBUG
+constexpr qsizetype MaxDomainNameLength = 255;
+constexpr quint16 DnsPort = 53;
+
class QDnsLookupRunnable;
+QDebug operator<<(QDebug &, QDnsLookupRunnable *);
class QDnsLookupReply
{
public:
- QDnsLookupReply()
- : error(QDnsLookup::NoError)
- { }
-
- QDnsLookup::Error error;
+ QDnsLookup::Error error = QDnsLookup::NoError;
QString errorString;
QList<QDnsDomainNameRecord> canonicalNameRecords;
@@ -50,23 +52,86 @@ public:
QList<QDnsDomainNameRecord> pointerRecords;
QList<QDnsServiceRecord> serviceRecords;
QList<QDnsTextRecord> textRecords;
+
+ // helper methods
+ void setError(QDnsLookup::Error err, QString &&msg)
+ {
+ error = err;
+ errorString = std::move(msg);
+ }
+
+ void makeResolverSystemError(int code = -1)
+ {
+ Q_ASSERT(allAreEmpty());
+ setError(QDnsLookup::ResolverError, qt_error_string(code));
+ }
+
+ void makeTimeoutError()
+ {
+ Q_ASSERT(allAreEmpty());
+ setError(QDnsLookup::TimeoutError, QDnsLookup::tr("Request timed out"));
+ }
+
+ void makeDnsRcodeError(quint8 rcode)
+ {
+ Q_ASSERT(allAreEmpty());
+ switch (rcode) {
+ case 1: // FORMERR
+ error = QDnsLookup::InvalidRequestError;
+ errorString = QDnsLookup::tr("Server could not process query");
+ return;
+ case 2: // SERVFAIL
+ case 4: // NOTIMP
+ error = QDnsLookup::ServerFailureError;
+ errorString = QDnsLookup::tr("Server failure");
+ return;
+ case 3: // NXDOMAIN
+ error = QDnsLookup::NotFoundError;
+ errorString = QDnsLookup::tr("Non existent domain");
+ return;
+ case 5: // REFUSED
+ error = QDnsLookup::ServerRefusedError;
+ errorString = QDnsLookup::tr("Server refused to answer");
+ return;
+ default:
+ error = QDnsLookup::InvalidReplyError;
+ errorString = QDnsLookup::tr("Invalid reply received (rcode %1)")
+ .arg(rcode);
+ return;
+ }
+ }
+
+ void makeInvalidReplyError(QString &&msg = QString())
+ {
+ if (msg.isEmpty())
+ msg = QDnsLookup::tr("Invalid reply received");
+ else
+ msg = QDnsLookup::tr("Invalid reply received (%1)").arg(std::move(msg));
+ *this = QDnsLookupReply(); // empty our lists
+ setError(QDnsLookup::InvalidReplyError, std::move(msg));
+ }
+
+private:
+ bool allAreEmpty() const
+ {
+ return canonicalNameRecords.isEmpty()
+ && hostAddressRecords.isEmpty()
+ && mailExchangeRecords.isEmpty()
+ && nameServerRecords.isEmpty()
+ && pointerRecords.isEmpty()
+ && serviceRecords.isEmpty()
+ && textRecords.isEmpty();
+ }
};
class QDnsLookupPrivate : public QObjectPrivate
{
public:
QDnsLookupPrivate()
- : isFinished(false)
- , type(QDnsLookup::A)
- , runnable(nullptr)
+ : type(QDnsLookup::A)
+ , port(DnsPort)
{ }
- void _q_lookupFinished(const QDnsLookupReply &reply);
-
- static const char *msgNoIpV6NameServerAdresses;
-
- bool isFinished;
-
void nameChanged()
{
emit q_func()->nameChanged(name);
@@ -74,6 +139,13 @@ public:
Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, QString, name,
&QDnsLookupPrivate::nameChanged);
+ void nameserverChanged()
+ {
+ emit q_func()->nameserverChanged(nameserver);
+ }
+ Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, QHostAddress, nameserver,
+ &QDnsLookupPrivate::nameserverChanged);
+
void typeChanged()
{
emit q_func()->typeChanged(type);
@@ -82,15 +154,18 @@ public:
Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, QDnsLookup::Type,
type, &QDnsLookupPrivate::typeChanged);
- void nameserverChanged()
+ void nameserverPortChanged()
{
- emit q_func()->nameserverChanged(nameserver);
+ emit q_func()->nameserverPortChanged(port);
}
- Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, QHostAddress, nameserver,
- &QDnsLookupPrivate::nameserverChanged);
+
+ Q_OBJECT_BINDABLE_PROPERTY(QDnsLookupPrivate, quint16,
+ port, &QDnsLookupPrivate::nameserverPortChanged);
+
QDnsLookupReply reply;
- QDnsLookupRunnable *runnable;
+ QDnsLookupRunnable *runnable = nullptr;
+ bool isFinished = false;
Q_DECLARE_PUBLIC(QDnsLookup)
};
@@ -100,40 +175,31 @@ class QDnsLookupRunnable : public QObject, public QRunnable
Q_OBJECT
public:
- QDnsLookupRunnable(QDnsLookup::Type type, const QByteArray &name, const QHostAddress &nameserver)
- : requestType(type)
- , requestName(name)
- , nameserver(nameserver)
- { }
+#ifdef Q_OS_WIN
+ using EncodedLabel = QString;
+#else
+ using EncodedLabel = QByteArray;
+#endif
+
+ QDnsLookupRunnable(const QDnsLookupPrivate *d);
void run() override;
signals:
void finished(const QDnsLookupReply &reply);
private:
- static void query(const int requestType, const QByteArray &requestName, const QHostAddress &nameserver, QDnsLookupReply *reply);
- QDnsLookup::Type requestType;
- QByteArray requestName;
- QHostAddress nameserver;
-};
-
-#if QT_CONFIG(thread)
-class QDnsLookupThreadPool : public QThreadPool
-{
- Q_OBJECT
-
-public:
- QDnsLookupThreadPool();
- void start(QRunnable *runnable);
-
-private slots:
- void _q_applicationDestroyed();
+ template <typename T> static QString decodeLabel(T encodedLabel)
+ {
+ return qt_ACE_do(encodedLabel.toString(), NormalizeAce, ForbidLeadingDot);
+ }
+ void query(QDnsLookupReply *reply);
-private:
- QMutex signalsMutex;
- bool signalsConnected;
+ EncodedLabel requestName;
+ QHostAddress nameserver;
+ QDnsLookup::Type requestType;
+ quint16 port;
+ friend QDebug operator<<(QDebug &, QDnsLookupRunnable *);
};
-#endif // QT_CONFIG(thread)
class QDnsRecordPrivate : public QSharedData
{
@@ -201,6 +267,4 @@ public:
QT_END_NAMESPACE
-QT_DECL_METATYPE_EXTERN(QDnsLookupReply, Q_NETWORK_EXPORT)
-
#endif // QDNSLOOKUP_P_H
diff --git a/src/network/kernel/qdnslookup_unix.cpp b/src/network/kernel/qdnslookup_unix.cpp
index 75f7c6c440..5696a3ca70 100644
--- a/src/network/kernel/qdnslookup_unix.cpp
+++ b/src/network/kernel/qdnslookup_unix.cpp
@@ -1,387 +1,392 @@
// Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
+// Copyright (C) 2023 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qdnslookup_p.h"
-#if QT_CONFIG(library)
-#include <qlibrary.h>
-#endif
-#include <qvarlengtharray.h>
+#include <qendian.h>
#include <qscopedpointer.h>
#include <qurl.h>
-#include <private/qnativesocketengine_p.h>
+#include <qvarlengtharray.h>
+#include <private/qnativesocketengine_p.h> // for setSockAddr
+#include <private/qtnetwork-config_p.h>
+
+QT_REQUIRE_CONFIG(libresolv);
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
-#if !defined(Q_OS_OPENBSD)
+#if __has_include(<arpa/nameser_compat.h>)
# include <arpa/nameser_compat.h>
#endif
+#include <errno.h>
#include <resolv.h>
-#if defined(__GNU_LIBRARY__) && !defined(__UCLIBC__)
-# include <gnu/lib-names.h>
-#endif
+#include <array>
-#if defined(Q_OS_FREEBSD) || QT_CONFIG(dlopen)
-# include <dlfcn.h>
+#ifndef T_OPT
+// the older arpa/nameser_compat.h wasn't updated between 1999 and 2016 in glibc
+# define T_OPT ns_t_opt
#endif
-#include <cstring>
-
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-#if QT_CONFIG(library)
+// minimum IPv6 MTU (1280) minus the IPv6 (40) and UDP headers (8)
+static constexpr qsizetype ReplyBufferSize = 1280 - 40 - 8;
+
+// https://www.rfc-editor.org/rfc/rfc6891
+static constexpr unsigned char Edns0Record[] = {
+ 0x00, // root label
+ T_OPT >> 8, T_OPT & 0xff, // type OPT
+ ReplyBufferSize >> 8, ReplyBufferSize & 0xff, // payload size
+ NOERROR, // extended rcode
+ 0, // version
+ 0x00, 0x00, // flags
+ 0x00, 0x00, // option length
+};
-#if defined(Q_OS_OPENBSD)
-typedef struct __res_state* res_state;
-#endif
-typedef int (*dn_expand_proto)(const unsigned char *, const unsigned char *, const unsigned char *, char *, int);
-static dn_expand_proto local_dn_expand = nullptr;
-typedef void (*res_nclose_proto)(res_state);
-static res_nclose_proto local_res_nclose = nullptr;
-typedef int (*res_ninit_proto)(res_state);
-static res_ninit_proto local_res_ninit = nullptr;
-typedef int (*res_nquery_proto)(res_state, const char *, int, int, unsigned char *, int);
-static res_nquery_proto local_res_nquery = nullptr;
-
-// Custom deleter to close resolver state.
-
-struct QDnsLookupStateDeleter
+// maximum length of a EDNS0 query with a 255-character domain (rounded up to 16)
+static constexpr qsizetype QueryBufferSize =
+ HFIXEDSZ + QFIXEDSZ + MAXCDNAME + 1 + sizeof(Edns0Record);
+using QueryBuffer = std::array<unsigned char, (QueryBufferSize + 15) / 16 * 16>;
+
+namespace {
+struct QDnsCachedName
{
- static inline void cleanup(struct __res_state *pointer)
- {
- local_res_nclose(pointer);
- }
+ QString name;
+ int code = 0;
+ QDnsCachedName(const QString &name, int code) : name(name), code(code) {}
};
+}
+Q_DECLARE_TYPEINFO(QDnsCachedName, Q_RELOCATABLE_TYPE);
+using Cache = QList<QDnsCachedName>; // QHash or QMap are overkill
-static QFunctionPointer resolveSymbol(QLibrary &lib, const char *sym)
+#if QT_CONFIG(res_setservers)
+// https://www.ibm.com/docs/en/i/7.3?topic=ssw_ibm_i_73/apis/ressetservers.html
+// https://docs.oracle.com/cd/E86824_01/html/E54774/res-setservers-3resolv.html
+static bool applyNameServer(res_state state, const QHostAddress &nameserver, quint16 port)
{
- if (lib.isLoaded())
- return lib.resolve(sym);
-
-#if defined(RTLD_DEFAULT) && (defined(Q_OS_FREEBSD) || QT_CONFIG(dlopen))
- return reinterpret_cast<QFunctionPointer>(dlsym(RTLD_DEFAULT, sym));
+ if (!nameserver.isNull()) {
+ union res_sockaddr_union u;
+ setSockaddr(reinterpret_cast<sockaddr *>(&u.sin), nameserver, port);
+ res_setservers(state, &u, 1);
+ }
+ return true;
+}
#else
- return nullptr;
-#endif
+template <typename T> void setNsMap(T &ext, std::enable_if_t<sizeof(T::nsmap) != 0, uint16_t> v)
+{
+ // Set nsmap[] to indicate that nsaddrs[0] is an IPv6 address
+ // See: https://sourceware.org/ml/libc-hacker/2002-05/msg00035.html
+ // Unneeded since glibc 2.22 (2015), but doesn't hurt to set it
+ // See: https://sourceware.org/git/?p=glibc.git;a=commit;h=2212c1420c92a33b0e0bd9a34938c9814a56c0f7
+ ext.nsmap[0] = v;
}
-
-static bool resolveLibraryInternal()
+template <typename T> void setNsMap(T &, ...)
{
- QLibrary lib;
-#ifdef LIBRESOLV_SO
- lib.setFileName(QStringLiteral(LIBRESOLV_SO));
- if (!lib.load())
-#endif
- {
- lib.setFileName("resolv"_L1);
- lib.load();
- }
+ // fallback
+}
- local_dn_expand = dn_expand_proto(resolveSymbol(lib, "__dn_expand"));
- if (!local_dn_expand)
- local_dn_expand = dn_expand_proto(resolveSymbol(lib, "dn_expand"));
+template <bool Condition>
+using EnableIfIPv6 = std::enable_if_t<Condition, const QHostAddress *>;
- local_res_nclose = res_nclose_proto(resolveSymbol(lib, "__res_nclose"));
- if (!local_res_nclose)
- local_res_nclose = res_nclose_proto(resolveSymbol(lib, "res_9_nclose"));
- if (!local_res_nclose)
- local_res_nclose = res_nclose_proto(resolveSymbol(lib, "res_nclose"));
+template <typename State>
+bool setIpv6NameServer(State *state,
+ EnableIfIPv6<sizeof(std::declval<State>()._u._ext.nsaddrs) != 0> addr,
+ quint16 port)
+{
+ // glibc-like API to set IPv6 name servers
+ struct sockaddr_in6 *ns = state->_u._ext.nsaddrs[0];
+
+ // nsaddrs will be NULL if no nameserver is set in /etc/resolv.conf
+ if (!ns) {
+ // Memory allocated here will be free()'d in res_close() as we
+ // have done res_init() above.
+ ns = static_cast<struct sockaddr_in6*>(calloc(1, sizeof(struct sockaddr_in6)));
+ Q_CHECK_PTR(ns);
+ state->_u._ext.nsaddrs[0] = ns;
+ }
- local_res_ninit = res_ninit_proto(resolveSymbol(lib, "__res_ninit"));
- if (!local_res_ninit)
- local_res_ninit = res_ninit_proto(resolveSymbol(lib, "res_9_ninit"));
- if (!local_res_ninit)
- local_res_ninit = res_ninit_proto(resolveSymbol(lib, "res_ninit"));
+ setNsMap(state->_u._ext, MAXNS + 1);
+ state->_u._ext.nscount6 = 1;
+ setSockaddr(ns, *addr, port);
+ return true;
+}
- local_res_nquery = res_nquery_proto(resolveSymbol(lib, "__res_nquery"));
- if (!local_res_nquery)
- local_res_nquery = res_nquery_proto(resolveSymbol(lib, "res_9_nquery"));
- if (!local_res_nquery)
- local_res_nquery = res_nquery_proto(resolveSymbol(lib, "res_nquery"));
+template <typename State> bool setIpv6NameServer(State *, const void *, quint16)
+{
+ // fallback
+ return false;
+}
+static bool applyNameServer(res_state state, const QHostAddress &nameserver, quint16 port)
+{
+ if (nameserver.isNull())
+ return true;
+
+ state->nscount = 1;
+ state->nsaddr_list[0].sin_family = AF_UNSPEC;
+ if (nameserver.protocol() == QAbstractSocket::IPv6Protocol)
+ return setIpv6NameServer(state, &nameserver, port);
+ setSockaddr(&state->nsaddr_list[0], nameserver, port);
return true;
}
-Q_GLOBAL_STATIC_WITH_ARGS(bool, resolveLibrary, (resolveLibraryInternal()))
+#endif // !QT_CONFIG(res_setservers)
-void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, const QHostAddress &nameserver, QDnsLookupReply *reply)
+static int
+prepareQueryBuffer(res_state state, QueryBuffer &buffer, const char *label, ns_rcode type)
{
- // Load dn_expand, res_ninit and res_nquery on demand.
- resolveLibrary();
-
- // If dn_expand, res_ninit or res_nquery is missing, fail.
- if (!local_dn_expand || !local_res_nclose || !local_res_ninit || !local_res_nquery) {
- reply->error = QDnsLookup::ResolverError;
- reply->errorString = tr("Resolver functions not found");
- return;
- }
+ // Create header and our query
+ int queryLength = res_nmkquery(state, QUERY, label, C_IN, type, nullptr, 0, nullptr,
+ buffer.data(), buffer.size());
+ Q_ASSERT(queryLength < int(buffer.size()));
+ if (Q_UNLIKELY(queryLength < 0))
+ return queryLength;
+
+ // Append EDNS0 record and set the number of additional RRs to 1
+ Q_ASSERT(queryLength + sizeof(Edns0Record) < buffer.size());
+ std::copy_n(std::begin(Edns0Record), sizeof(Edns0Record), buffer.begin() + queryLength);
+ reinterpret_cast<HEADER *>(buffer.data())->arcount = qToBigEndian<quint16>(1);
+
+ return queryLength + sizeof(Edns0Record);
+}
+void QDnsLookupRunnable::query(QDnsLookupReply *reply)
+{
// Initialize state.
- struct __res_state state;
- std::memset(&state, 0, sizeof(state));
- if (local_res_ninit(&state) < 0) {
- reply->error = QDnsLookup::ResolverError;
- reply->errorString = tr("Resolver initialization failed");
- return;
+ std::remove_pointer_t<res_state> state = {};
+ if (res_ninit(&state) < 0) {
+ int error = errno;
+ qErrnoWarning(error, "QDnsLookup: Resolver initialization failed");
+ return reply->makeResolverSystemError(error);
}
+ auto guard = qScopeGuard([&] { res_nclose(&state); });
//Check if a nameserver was set. If so, use it
- if (!nameserver.isNull()) {
- if (nameserver.protocol() == QAbstractSocket::IPv4Protocol) {
- state.nsaddr_list[0].sin_addr.s_addr = htonl(nameserver.toIPv4Address());
- state.nscount = 1;
- } else if (nameserver.protocol() == QAbstractSocket::IPv6Protocol) {
-#if defined(Q_OS_LINUX)
- struct sockaddr_in6 *ns;
- ns = state._u._ext.nsaddrs[0];
- // nsaddrs will be NULL if no nameserver is set in /etc/resolv.conf
- if (!ns) {
- // Memory allocated here will be free'd in res_close() as we
- // have done res_init() above.
- ns = (struct sockaddr_in6*) calloc(1, sizeof(struct sockaddr_in6));
- Q_CHECK_PTR(ns);
- state._u._ext.nsaddrs[0] = ns;
- }
-#ifndef __UCLIBC__
- // Set nsmap[] to indicate that nsaddrs[0] is an IPv6 address
- // See: https://sourceware.org/ml/libc-hacker/2002-05/msg00035.html
- state._u._ext.nsmap[0] = MAXNS + 1;
-#endif
- state._u._ext.nscount6 = 1;
- ns->sin6_family = AF_INET6;
- ns->sin6_port = htons(53);
- SetSALen::set(ns, sizeof(*ns));
-
- Q_IPV6ADDR ipv6Address = nameserver.toIPv6Address();
- for (int i=0; i<16; i++) {
- ns->sin6_addr.s6_addr[i] = ipv6Address[i];
- }
-#else
- qWarning("%s", QDnsLookupPrivate::msgNoIpV6NameServerAdresses);
- reply->error = QDnsLookup::ResolverError;
- reply->errorString = tr(QDnsLookupPrivate::msgNoIpV6NameServerAdresses);
- return;
-#endif
- }
- }
+ if (!applyNameServer(&state, nameserver, port))
+ return reply->setError(QDnsLookup::ResolverError,
+ QDnsLookup::tr("IPv6 nameservers are currently not supported on this OS"));
#ifdef QDNSLOOKUP_DEBUG
state.options |= RES_DEBUG;
#endif
- QScopedPointer<struct __res_state, QDnsLookupStateDeleter> state_ptr(&state);
+
+ // Prepare the DNS query.
+ QueryBuffer qbuffer;
+ int queryLength = prepareQueryBuffer(&state, qbuffer, requestName.constData(), ns_rcode(requestType));
+ if (Q_UNLIKELY(queryLength < 0))
+ return reply->makeResolverSystemError();
// Perform DNS query.
- QVarLengthArray<unsigned char, PACKETSZ> buffer(PACKETSZ);
- std::memset(buffer.data(), 0, buffer.size());
- int responseLength = local_res_nquery(&state, requestName, C_IN, requestType, buffer.data(), buffer.size());
- if (Q_UNLIKELY(responseLength > PACKETSZ)) {
- buffer.resize(responseLength);
- std::memset(buffer.data(), 0, buffer.size());
- responseLength = local_res_nquery(&state, requestName, C_IN, requestType, buffer.data(), buffer.size());
+ QVarLengthArray<unsigned char, ReplyBufferSize> buffer(ReplyBufferSize);
+ auto attemptToSend = [&]() {
+ std::memset(buffer.data(), 0, HFIXEDSZ); // the header is enough
+ int responseLength = res_nsend(&state, qbuffer.data(), queryLength, buffer.data(), buffer.size());
+ if (responseLength >= 0)
+ return responseLength; // success
+
+ // libresolv uses ETIMEDOUT for resolver errors ("no answer")
+ if (errno == ECONNREFUSED)
+ reply->setError(QDnsLookup::ServerRefusedError, qt_error_string());
+ else if (errno != ETIMEDOUT)
+ reply->makeResolverSystemError(); // some other error
+
+ auto query = reinterpret_cast<HEADER *>(qbuffer.data());
+ auto header = reinterpret_cast<HEADER *>(buffer.data());
+ if (query->id == header->id && header->qr)
+ reply->makeDnsRcodeError(header->rcode);
+ else
+ reply->makeTimeoutError(); // must really be a timeout
+ return -1;
+ };
+
+ // strictly use UDP, we'll deal with truncated replies ourselves
+ state.options |= RES_IGNTC;
+ int responseLength = attemptToSend();
+ if (responseLength < 0)
+ return;
+
+ // check if we need to use the virtual circuit (TCP)
+ auto header = reinterpret_cast<HEADER *>(buffer.data());
+ if (header->rcode == NOERROR && header->tc) {
+ // yes, increase our buffer size
+ buffer.resize(std::numeric_limits<quint16>::max());
+ header = reinterpret_cast<HEADER *>(buffer.data());
+
+ // remove the EDNS record in the query
+ reinterpret_cast<HEADER *>(qbuffer.data())->arcount = 0;
+ queryLength -= sizeof(Edns0Record);
+
+ // send using the virtual circuit
+ state.options |= RES_USEVC;
+ responseLength = attemptToSend();
if (Q_UNLIKELY(responseLength > buffer.size())) {
// Ok, we give up.
- reply->error = QDnsLookup::ResolverError;
- reply->errorString.clear(); // We cannot be more specific, alas.
- return;
+ return reply->setError(QDnsLookup::ResolverError,
+ QDnsLookup::tr("Reply was too large"));
}
}
-
- unsigned char *response = buffer.data();
- // Check the response header. Though res_nquery returns -1 as a
- // responseLength in case of error, we still can extract the
- // exact error code from the response.
- HEADER *header = (HEADER*)response;
- const int answerCount = ntohs(header->ancount);
- switch (header->rcode) {
- case NOERROR:
- break;
- case FORMERR:
- reply->error = QDnsLookup::InvalidRequestError;
- reply->errorString = tr("Server could not process query");
- return;
- case SERVFAIL:
- reply->error = QDnsLookup::ServerFailureError;
- reply->errorString = tr("Server failure");
+ if (responseLength < 0)
return;
- case NXDOMAIN:
- reply->error = QDnsLookup::NotFoundError;
- reply->errorString = tr("Non existent domain");
- return;
- case REFUSED:
- reply->error = QDnsLookup::ServerRefusedError;
- reply->errorString = tr("Server refused to answer");
- return;
- default:
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Invalid reply received");
- return;
- }
// Check the reply is valid.
- if (responseLength < int(sizeof(HEADER))) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Invalid reply received");
- return;
- }
+ if (responseLength < int(sizeof(HEADER)))
+ return reply->makeInvalidReplyError();
- // Skip the query host, type (2 bytes) and class (2 bytes).
- char host[PACKETSZ], answer[PACKETSZ];
- unsigned char *p = response + sizeof(HEADER);
- int status = local_dn_expand(response, response + responseLength, p, host, sizeof(host));
- if (status < 0) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Could not expand domain name");
- return;
+ // Parse the reply.
+ if (header->rcode)
+ return reply->makeDnsRcodeError(header->rcode);
+
+ qptrdiff offset = sizeof(HEADER);
+ unsigned char *response = buffer.data();
+ int status;
+
+ auto expandHost = [&, cache = Cache{}](qptrdiff offset) mutable {
+ if (uchar n = response[offset]; n & NS_CMPRSFLGS) {
+ // compressed name, see if we already have it cached
+ if (offset + 1 < responseLength) {
+ int id = ((n & ~NS_CMPRSFLGS) << 8) | response[offset + 1];
+ auto it = std::find_if(cache.constBegin(), cache.constEnd(),
+ [id](const QDnsCachedName &n) { return n.code == id; });
+ if (it != cache.constEnd()) {
+ status = 2;
+ return it->name;
+ }
+ }
+ }
+
+ // uncached, expand it
+ char host[MAXCDNAME + 1];
+ status = dn_expand(response, response + responseLength, response + offset,
+ host, sizeof(host));
+ if (status >= 0)
+ return cache.emplaceBack(decodeLabel(QLatin1StringView(host)), offset).name;
+
+ // failed
+ reply->makeInvalidReplyError(QDnsLookup::tr("Could not expand domain name"));
+ return QString();
+ };
+
+ if (ntohs(header->qdcount) == 1) {
+ // Skip the query host, type (2 bytes) and class (2 bytes).
+ expandHost(offset);
+ if (status < 0)
+ return;
+ if (offset + status + 4 >= responseLength)
+ header->qdcount = 0xffff; // invalid reply below
+ else
+ offset += status + 4;
}
- p += status + 4;
+ if (ntohs(header->qdcount) > 1)
+ return reply->makeInvalidReplyError();
// Extract results.
+ const int answerCount = ntohs(header->ancount);
int answerIndex = 0;
- while ((p < response + responseLength) && (answerIndex < answerCount)) {
- status = local_dn_expand(response, response + responseLength, p, host, sizeof(host));
- if (status < 0) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Could not expand domain name");
+ while ((offset < responseLength) && (answerIndex < answerCount)) {
+ const QString name = expandHost(offset);
+ if (status < 0)
return;
- }
- const QString name = QUrl::fromAce(host);
- p += status;
- const quint16 type = (p[0] << 8) | p[1];
- p += 2; // RR type
- p += 2; // RR class
- const quint32 ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
- p += 4;
- const quint16 size = (p[0] << 8) | p[1];
- p += 2;
+ offset += status;
+ if (offset + RRFIXEDSZ > responseLength) {
+ // probably just a truncated reply, return what we have
+ return;
+ }
+ const quint16 type = qFromBigEndian<quint16>(response + offset);
+ const qint16 rrclass = qFromBigEndian<quint16>(response + offset + 2);
+ const quint32 ttl = qFromBigEndian<quint32>(response + offset + 4);
+ const quint16 size = qFromBigEndian<quint16>(response + offset + 8);
+ offset += RRFIXEDSZ;
+ if (offset + size > responseLength)
+ return; // truncated
+ if (rrclass != C_IN)
+ continue;
if (type == QDnsLookup::A) {
- if (size != 4) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Invalid IPv4 address record");
- return;
- }
- const quint32 addr = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+ if (size != 4)
+ return reply->makeInvalidReplyError(QDnsLookup::tr("Invalid IPv4 address record"));
+ const quint32 addr = qFromBigEndian<quint32>(response + offset);
QDnsHostAddressRecord record;
record.d->name = name;
record.d->timeToLive = ttl;
record.d->value = QHostAddress(addr);
reply->hostAddressRecords.append(record);
} else if (type == QDnsLookup::AAAA) {
- if (size != 16) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Invalid IPv6 address record");
- return;
- }
+ if (size != 16)
+ return reply->makeInvalidReplyError(QDnsLookup::tr("Invalid IPv6 address record"));
QDnsHostAddressRecord record;
record.d->name = name;
record.d->timeToLive = ttl;
- record.d->value = QHostAddress(p);
+ record.d->value = QHostAddress(response + offset);
reply->hostAddressRecords.append(record);
} else if (type == QDnsLookup::CNAME) {
- status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer));
- if (status < 0) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Invalid canonical name record");
- return;
- }
QDnsDomainNameRecord record;
record.d->name = name;
record.d->timeToLive = ttl;
- record.d->value = QUrl::fromAce(answer);
+ record.d->value = expandHost(offset);
+ if (status < 0)
+ return reply->makeInvalidReplyError(QDnsLookup::tr("Invalid canonical name record"));
reply->canonicalNameRecords.append(record);
} else if (type == QDnsLookup::NS) {
- status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer));
- if (status < 0) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Invalid name server record");
- return;
- }
QDnsDomainNameRecord record;
record.d->name = name;
record.d->timeToLive = ttl;
- record.d->value = QUrl::fromAce(answer);
+ record.d->value = expandHost(offset);
+ if (status < 0)
+ return reply->makeInvalidReplyError(QDnsLookup::tr("Invalid name server record"));
reply->nameServerRecords.append(record);
} else if (type == QDnsLookup::PTR) {
- status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer));
- if (status < 0) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Invalid pointer record");
- return;
- }
QDnsDomainNameRecord record;
record.d->name = name;
record.d->timeToLive = ttl;
- record.d->value = QUrl::fromAce(answer);
+ record.d->value = expandHost(offset);
+ if (status < 0)
+ return reply->makeInvalidReplyError(QDnsLookup::tr("Invalid pointer record"));
reply->pointerRecords.append(record);
} else if (type == QDnsLookup::MX) {
- const quint16 preference = (p[0] << 8) | p[1];
- status = local_dn_expand(response, response + responseLength, p + 2, answer, sizeof(answer));
- if (status < 0) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Invalid mail exchange record");
- return;
- }
+ const quint16 preference = qFromBigEndian<quint16>(response + offset);
QDnsMailExchangeRecord record;
- record.d->exchange = QUrl::fromAce(answer);
+ record.d->exchange = expandHost(offset + 2);
record.d->name = name;
record.d->preference = preference;
record.d->timeToLive = ttl;
+ if (status < 0)
+ return reply->makeInvalidReplyError(QDnsLookup::tr("Invalid mail exchange record"));
reply->mailExchangeRecords.append(record);
} else if (type == QDnsLookup::SRV) {
- const quint16 priority = (p[0] << 8) | p[1];
- const quint16 weight = (p[2] << 8) | p[3];
- const quint16 port = (p[4] << 8) | p[5];
- status = local_dn_expand(response, response + responseLength, p + 6, answer, sizeof(answer));
- if (status < 0) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Invalid service record");
- return;
- }
+ const quint16 priority = qFromBigEndian<quint16>(response + offset);
+ const quint16 weight = qFromBigEndian<quint16>(response + offset + 2);
+ const quint16 port = qFromBigEndian<quint16>(response + offset + 4);
QDnsServiceRecord record;
record.d->name = name;
- record.d->target = QUrl::fromAce(answer);
+ record.d->target = expandHost(offset + 6);
record.d->port = port;
record.d->priority = priority;
record.d->timeToLive = ttl;
record.d->weight = weight;
+ if (status < 0)
+ return reply->makeInvalidReplyError(QDnsLookup::tr("Invalid service record"));
reply->serviceRecords.append(record);
} else if (type == QDnsLookup::TXT) {
- unsigned char *txt = p;
QDnsTextRecord record;
record.d->name = name;
record.d->timeToLive = ttl;
- while (txt < p + size) {
- const unsigned char length = *txt;
+ qptrdiff txt = offset;
+ while (txt < offset + size) {
+ const unsigned char length = response[txt];
txt++;
- if (txt + length > p + size) {
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = tr("Invalid text record");
- return;
- }
- record.d->values << QByteArray((char*)txt, length);
+ if (txt + length > offset + size)
+ return reply->makeInvalidReplyError(QDnsLookup::tr("Invalid text record"));
+ record.d->values << QByteArrayView(response + txt, length).toByteArray();
txt += length;
}
reply->textRecords.append(record);
}
- p += size;
+ offset += size;
answerIndex++;
}
}
-#else
-void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, const QHostAddress &nameserver, QDnsLookupReply *reply)
-{
- Q_UNUSED(requestType);
- Q_UNUSED(requestName);
- Q_UNUSED(nameserver);
- reply->error = QDnsLookup::ResolverError;
- reply->errorString = tr("Resolver library can't be loaded: No runtime library loading support");
- return;
-}
-
-#endif /* QT_CONFIG(library) */
-
QT_END_NAMESPACE
diff --git a/src/network/kernel/qdnslookup_win.cpp b/src/network/kernel/qdnslookup_win.cpp
index 564966e395..72d5ae5c86 100644
--- a/src/network/kernel/qdnslookup_win.cpp
+++ b/src/network/kernel/qdnslookup_win.cpp
@@ -1,69 +1,115 @@
// Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
+// Copyright (C) 2023 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <winsock2.h>
#include "qdnslookup_p.h"
#include <qurl.h>
+#include <private/qnativesocketengine_p.h>
#include <private/qsystemerror_p.h>
#include <qt_windows.h>
#include <windns.h>
#include <memory.h>
+#ifndef DNS_ADDR_MAX_SOCKADDR_LENGTH
+// MinGW headers are missing almost all of this
+typedef struct Qt_DnsAddr {
+ CHAR MaxSa[32];
+ DWORD DnsAddrUserDword[8];
+} DNS_ADDR, *PDNS_ADDR;
+typedef struct Qt_DnsAddrArray {
+ DWORD MaxCount;
+ DWORD AddrCount;
+ DWORD Tag;
+ WORD Family;
+ WORD WordReserved;
+ DWORD Flags;
+ DWORD MatchFlag;
+ DWORD Reserved1;
+ DWORD Reserved2;
+ DNS_ADDR AddrArray[];
+} DNS_ADDR_ARRAY, *PDNS_ADDR_ARRAY;
+# ifndef DNS_QUERY_RESULTS_VERSION1
+typedef struct Qt_DNS_QUERY_RESULT {
+ ULONG Version;
+ DNS_STATUS QueryStatus;
+ ULONG64 QueryOptions;
+ PDNS_RECORD pQueryRecords;
+ PVOID Reserved;
+} DNS_QUERY_RESULT, *PDNS_QUERY_RESULT;
+typedef VOID WINAPI DNS_QUERY_COMPLETION_ROUTINE(PVOID pQueryContext,PDNS_QUERY_RESULT pQueryResults);
+typedef DNS_QUERY_COMPLETION_ROUTINE *PDNS_QUERY_COMPLETION_ROUTINE;
+# endif
+typedef struct Qt_DNS_QUERY_REQUEST {
+ ULONG Version;
+ PCWSTR QueryName;
+ WORD QueryType;
+ ULONG64 QueryOptions;
+ PDNS_ADDR_ARRAY pDnsServerList;
+ ULONG InterfaceIndex;
+ PDNS_QUERY_COMPLETION_ROUTINE pQueryCompletionCallback;
+ PVOID pQueryContext;
+} DNS_QUERY_REQUEST, *PDNS_QUERY_REQUEST;
+
+typedef void *PDNS_QUERY_CANCEL; // not really, but we don't need it
+extern "C" {
+DNS_STATUS WINAPI DnsQueryEx(PDNS_QUERY_REQUEST pQueryRequest,
+ PDNS_QUERY_RESULT pQueryResults,
+ PDNS_QUERY_CANCEL pCancelHandle);
+}
+#endif
+
QT_BEGIN_NAMESPACE
-void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, const QHostAddress &nameserver, QDnsLookupReply *reply)
+void QDnsLookupRunnable::query(QDnsLookupReply *reply)
{
// Perform DNS query.
- PDNS_RECORD dns_records = 0;
- const QString requestNameUtf16 = QString::fromUtf8(requestName.data(), requestName.size());
- IP4_ARRAY srvList;
- memset(&srvList, 0, sizeof(IP4_ARRAY));
+ alignas(DNS_ADDR_ARRAY) uchar dnsAddresses[sizeof(DNS_ADDR_ARRAY) + sizeof(DNS_ADDR)];
+ DNS_QUERY_REQUEST request = {};
+ request.Version = 1;
+ request.QueryName = reinterpret_cast<const wchar_t *>(requestName.constData());
+ request.QueryType = requestType;
+ request.QueryOptions = DNS_QUERY_STANDARD | DNS_QUERY_TREAT_AS_FQDN;
+
if (!nameserver.isNull()) {
- if (nameserver.protocol() == QAbstractSocket::IPv4Protocol) {
- // The below code is referenced from: http://support.microsoft.com/kb/831226
- srvList.AddrCount = 1;
- srvList.AddrArray[0] = htonl(nameserver.toIPv4Address());
- } else if (nameserver.protocol() == QAbstractSocket::IPv6Protocol) {
- // For supoprting IPv6 nameserver addresses, we'll need to switch
- // from DnsQuey() to DnsQueryEx() as it supports passing an IPv6
- // address in the nameserver list
- qWarning("%s", QDnsLookupPrivate::msgNoIpV6NameServerAdresses);
- reply->error = QDnsLookup::ResolverError;
- reply->errorString = tr(QDnsLookupPrivate::msgNoIpV6NameServerAdresses);
- return;
- }
- }
- const DNS_STATUS status = DnsQuery_W(reinterpret_cast<const wchar_t*>(requestNameUtf16.utf16()), requestType, DNS_QUERY_STANDARD, &srvList, &dns_records, NULL);
- switch (status) {
- case ERROR_SUCCESS:
- break;
- case DNS_ERROR_RCODE_FORMAT_ERROR:
- reply->error = QDnsLookup::InvalidRequestError;
- reply->errorString = tr("Server could not process query");
- return;
- case DNS_ERROR_RCODE_SERVER_FAILURE:
- reply->error = QDnsLookup::ServerFailureError;
- reply->errorString = tr("Server failure");
- return;
- case DNS_ERROR_RCODE_NAME_ERROR:
- reply->error = QDnsLookup::NotFoundError;
- reply->errorString = tr("Non existent domain");
- return;
- case DNS_ERROR_RCODE_REFUSED:
- reply->error = QDnsLookup::ServerRefusedError;
- reply->errorString = tr("Server refused to answer");
- return;
- default:
- reply->error = QDnsLookup::InvalidReplyError;
- reply->errorString = QSystemError(status, QSystemError::NativeError).toString();
- return;
+ memset(dnsAddresses, 0, sizeof(dnsAddresses));
+ request.pDnsServerList = new (dnsAddresses) DNS_ADDR_ARRAY;
+ auto addr = new (request.pDnsServerList->AddrArray) DNS_ADDR[1];
+ auto sa = new (addr[0].MaxSa) sockaddr;
+ request.pDnsServerList->MaxCount = sizeof(dnsAddresses);
+ request.pDnsServerList->AddrCount = 1;
+ // ### setting port 53 seems to cause some systems to fail
+ setSockaddr(sa, nameserver, port == DnsPort ? 0 : port);
+ request.pDnsServerList->Family = sa->sa_family;
}
+ DNS_QUERY_RESULT results = {};
+ results.Version = 1;
+ const DNS_STATUS status = DnsQueryEx(&request, &results, nullptr);
+ if (status >= DNS_ERROR_RCODE_FORMAT_ERROR && status <= DNS_ERROR_RCODE_LAST)
+ return reply->makeDnsRcodeError(status - DNS_ERROR_RCODE_FORMAT_ERROR + 1);
+ else if (status == ERROR_TIMEOUT)
+ return reply->makeTimeoutError();
+ else if (status != ERROR_SUCCESS)
+ return reply->makeResolverSystemError(status);
+
+ QStringView lastEncodedName;
+ QString cachedDecodedName;
+ auto extractAndCacheHost = [&](QStringView name) -> const QString & {
+ lastEncodedName = name;
+ cachedDecodedName = decodeLabel(name);
+ return cachedDecodedName;
+ };
+ auto extractMaybeCachedHost = [&](QStringView name) -> const QString & {
+ return lastEncodedName == name ? cachedDecodedName : extractAndCacheHost(name);
+ };
+
// Extract results.
- for (PDNS_RECORD ptr = dns_records; ptr != NULL; ptr = ptr->pNext) {
- const QString name = QUrl::fromAce( QString::fromWCharArray( ptr->pName ).toLatin1() );
+ for (PDNS_RECORD ptr = results.pQueryRecords; ptr != NULL; ptr = ptr->pNext) {
+ // warning: always assign name to the record before calling extractXxxHost() again
+ const QString &name = extractMaybeCachedHost(ptr->pName);
if (ptr->wType == QDnsLookup::A) {
QDnsHostAddressRecord record;
record.d->name = name;
@@ -83,12 +129,12 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN
QDnsDomainNameRecord record;
record.d->name = name;
record.d->timeToLive = ptr->dwTtl;
- record.d->value = QUrl::fromAce(QString::fromWCharArray(ptr->Data.Cname.pNameHost).toLatin1());
+ record.d->value = extractAndCacheHost(ptr->Data.Cname.pNameHost);
reply->canonicalNameRecords.append(record);
} else if (ptr->wType == QDnsLookup::MX) {
QDnsMailExchangeRecord record;
record.d->name = name;
- record.d->exchange = QUrl::fromAce(QString::fromWCharArray(ptr->Data.Mx.pNameExchange).toLatin1());
+ record.d->exchange = decodeLabel(QStringView(ptr->Data.Mx.pNameExchange));
record.d->preference = ptr->Data.Mx.wPreference;
record.d->timeToLive = ptr->dwTtl;
reply->mailExchangeRecords.append(record);
@@ -96,18 +142,18 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN
QDnsDomainNameRecord record;
record.d->name = name;
record.d->timeToLive = ptr->dwTtl;
- record.d->value = QUrl::fromAce(QString::fromWCharArray(ptr->Data.Ns.pNameHost).toLatin1());
+ record.d->value = decodeLabel(QStringView(ptr->Data.Ns.pNameHost));
reply->nameServerRecords.append(record);
} else if (ptr->wType == QDnsLookup::PTR) {
QDnsDomainNameRecord record;
record.d->name = name;
record.d->timeToLive = ptr->dwTtl;
- record.d->value = QUrl::fromAce(QString::fromWCharArray(ptr->Data.Ptr.pNameHost).toLatin1());
+ record.d->value = decodeLabel(QStringView(ptr->Data.Ptr.pNameHost));
reply->pointerRecords.append(record);
} else if (ptr->wType == QDnsLookup::SRV) {
QDnsServiceRecord record;
record.d->name = name;
- record.d->target = QUrl::fromAce(QString::fromWCharArray(ptr->Data.Srv.pNameTarget).toLatin1());
+ record.d->target = decodeLabel(QStringView(ptr->Data.Srv.pNameTarget));
record.d->port = ptr->Data.Srv.wPort;
record.d->priority = ptr->Data.Srv.wPriority;
record.d->timeToLive = ptr->dwTtl;
@@ -118,13 +164,13 @@ void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestN
record.d->name = name;
record.d->timeToLive = ptr->dwTtl;
for (unsigned int i = 0; i < ptr->Data.Txt.dwStringCount; ++i) {
- record.d->values << QString::fromWCharArray((ptr->Data.Txt.pStringArray[i])).toLatin1();;
+ record.d->values << QStringView(ptr->Data.Txt.pStringArray[i]).toLatin1();
}
reply->textRecords.append(record);
}
}
- DnsRecordListFree(dns_records, DnsFreeRecordList);
+ DnsRecordListFree(results.pQueryRecords, DnsFreeRecordList);
}
QT_END_NAMESPACE
diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp
index 8887c4f24a..0330fb091b 100644
--- a/src/network/kernel/qhostaddress.cpp
+++ b/src/network/kernel/qhostaddress.cpp
@@ -706,7 +706,7 @@ QString QHostAddress::toString() const
} else if (d->protocol == QHostAddress::IPv6Protocol) {
QIPAddressUtils::toString(s, d->a6.c);
if (!d->scopeId.isEmpty())
- s.append(u'%' + d->scopeId);
+ s += u'%' + d->scopeId;
}
return s;
}
diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp
index 2283766b97..62bb210ca1 100644
--- a/src/network/kernel/qhostinfo.cpp
+++ b/src/network/kernel/qhostinfo.cpp
@@ -72,6 +72,16 @@ Q_APPLICATION_STATIC(QHostInfoLookupManager, theHostInfoLookupManager)
}
+QHostInfoResult::QHostInfoResult(const QObject *receiver, QtPrivate::SlotObjUniquePtr slot)
+ : receiver{receiver ? receiver : this}, slotObj{std::move(slot)}
+{
+ Q_ASSERT(this->receiver);
+ moveToThread(this->receiver->thread());
+}
+
+QHostInfoResult::~QHostInfoResult()
+ = default;
+
/*
The calling thread is likely the one that executes the lookup via
QHostInfoRunnable. Unless we operate with a queued connection already,
@@ -80,8 +90,8 @@ Q_APPLICATION_STATIC(QHostInfoLookupManager, theHostInfoLookupManager)
the thread that made the call to lookupHost. That QHostInfoResult object
then calls the user code in the correct thread.
- The 'result' object deletes itself (via deleteLater) when the metacall
- event is received.
+ The 'result' object deletes itself (via deleteLater) when
+ finalizePostResultsReady is called.
*/
void QHostInfoResult::postResultsReady(const QHostInfo &info)
{
@@ -91,55 +101,33 @@ void QHostInfoResult::postResultsReady(const QHostInfo &info)
return;
}
// we used to have a context object, but it's already destroyed
- if (withContextObject && !receiver)
+ if (!receiver)
return;
- static const int signal_index = []() -> int {
- auto senderMetaObject = &QHostInfoResult::staticMetaObject;
- 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);
- }();
-
// a long-living version of this
auto result = new QHostInfoResult(this);
Q_CHECK_PTR(result);
- const int nargs = 2;
- auto metaCallEvent = new QMetaCallEvent(slotObj, nullptr, signal_index, nargs);
- Q_CHECK_PTR(metaCallEvent);
- void **args = metaCallEvent->args();
- QMetaType *types = metaCallEvent->types();
- auto voidType = QMetaType::fromType<void>();
- auto hostInfoType = QMetaType::fromType<QHostInfo>();
- types[0] = voidType;
- types[1] = hostInfoType;
- args[0] = nullptr;
- args[1] = hostInfoType.create(&info);
- Q_CHECK_PTR(args[1]);
- qApp->postEvent(result, metaCallEvent);
+ QMetaObject::invokeMethod(result,
+ &QHostInfoResult::finalizePostResultsReady,
+ Qt::QueuedConnection,
+ info);
}
/*
- Receives the event posted by postResultsReady, and calls the functor.
+ Receives the info from postResultsReady, and calls the functor.
*/
-bool QHostInfoResult::event(QEvent *event)
+void QHostInfoResult::finalizePostResultsReady(const QHostInfo &info)
{
- if (event->type() == QEvent::MetaCall) {
- Q_ASSERT(slotObj);
- auto metaCallEvent = static_cast<QMetaCallEvent *>(event);
- auto args = metaCallEvent->args();
- // we didn't have a context object, or it's still alive
- if (!withContextObject || receiver)
- slotObj->call(const_cast<QObject*>(receiver.data()), args);
- slotObj->destroyIfLastRef();
-
- deleteLater();
- return true;
+ Q_ASSERT(slotObj);
+
+ // we used to have a context object, but it's already destroyed
+ if (receiver) {
+ void *args[] = { nullptr, const_cast<QHostInfo *>(&info) };
+ slotObj->call(const_cast<QObject *>(receiver.data()), args);
}
- return QObject::event(event);
+
+ deleteLater();
}
/*!
@@ -233,10 +221,17 @@ static int nextId()
\note There is no guarantee on the order the signals will be emitted
if you start multiple requests with lookupHost().
+ \note In Qt versions prior to 6.7, this function took \a receiver as
+ (non-const) \c{QObject*}.
+
\sa abortHostLookup(), addresses(), error(), fromName()
*/
-int QHostInfo::lookupHost(const QString &name, QObject *receiver, const char *member)
+int QHostInfo::lookupHost(const QString &name, const QObject *receiver, const char *member)
{
+ if (!receiver || !member) {
+ qWarning("QHostInfo::lookupHost: both the receiver and the member to invoke must be non-null");
+ return -1;
+ }
return QHostInfo::lookupHostImpl(name, receiver, nullptr, member);
}
@@ -262,7 +257,7 @@ int QHostInfo::lookupHost(const QString &name, QObject *receiver, const char *me
*/
/*!
- \fn template<typename Functor> int QHostInfo::lookupHost(const QString &name, Functor functor)
+ \fn template<typename Functor> int QHostInfo::lookupHost(const QString &name, Functor &&functor)
\since 5.9
@@ -734,22 +729,25 @@ QString QHostInfo::localHostName()
\internal
Called by the various lookupHost overloads to perform the lookup.
- Signals either the functor encapuslated in the \a slotObj in the context
+ Signals either the functor encapuslated in the \a slotObjRaw in the context
of \a receiver, or the \a member slot of the \a receiver.
- \a receiver might be the nullptr, but only if a \a slotObj is provided.
+ \a receiver might be the nullptr, but only if a \a slotObjRaw is provided.
*/
int QHostInfo::lookupHostImpl(const QString &name,
const QObject *receiver,
- QtPrivate::QSlotObjectBase *slotObj,
+ QtPrivate::QSlotObjectBase *slotObjRaw,
const char *member)
{
+ QtPrivate::SlotObjUniquePtr slotObj{slotObjRaw};
#if defined QHOSTINFO_DEBUG
qDebug("QHostInfo::lookupHostImpl(\"%s\", %p, %p, %s)",
- name.toLatin1().constData(), receiver, slotObj, member ? member + 1 : 0);
+ name.toLatin1().constData(), receiver, slotObj.get(), member ? member + 1 : 0);
#endif
Q_ASSERT(!member != !slotObj); // one of these must be set, but not both
Q_ASSERT(receiver || slotObj);
+ Q_ASSERT(!member || receiver); // if member is set, also is receiver
+ const bool isUsingStringBasedSlot = static_cast<bool>(member);
if (!QAbstractEventDispatcher::instance(QThread::currentThread())) {
qWarning("QHostInfo::lookupHost() called with no event dispatcher");
@@ -765,10 +763,11 @@ int QHostInfo::lookupHostImpl(const QString &name,
hostInfo.setError(QHostInfo::HostNotFound);
hostInfo.setErrorString(QCoreApplication::translate("QHostInfo", "No host name given"));
- QHostInfoResult result(receiver, slotObj);
- if (receiver && member)
+ QHostInfoResult result(receiver, std::move(slotObj));
+ if (isUsingStringBasedSlot) {
QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)),
receiver, member, Qt::QueuedConnection);
+ }
result.postResultsReady(hostInfo);
return id;
@@ -782,10 +781,11 @@ int QHostInfo::lookupHostImpl(const QString &name,
QHostInfo hostInfo = QHostInfoAgent::lookup(name);
hostInfo.setLookupId(id);
- QHostInfoResult result(receiver, slotObj);
- if (receiver && member)
+ QHostInfoResult result(receiver, std::move(slotObj));
+ if (isUsingStringBasedSlot) {
QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)),
receiver, member, Qt::QueuedConnection);
+ }
result.postResultsReady(hostInfo);
#else
QHostInfoLookupManager *manager = theHostInfoLookupManager();
@@ -798,20 +798,22 @@ int QHostInfo::lookupHostImpl(const QString &name,
QHostInfo info = manager->cache.get(name, &valid);
if (valid) {
info.setLookupId(id);
- QHostInfoResult result(receiver, slotObj);
- if (receiver && member)
+ QHostInfoResult result(receiver, std::move(slotObj));
+ if (isUsingStringBasedSlot) {
QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)),
receiver, member, Qt::QueuedConnection);
+ }
result.postResultsReady(info);
return id;
}
}
// cache is not enabled or it was not in the cache, do normal lookup
- QHostInfoRunnable *runnable = new QHostInfoRunnable(name, id, receiver, slotObj);
- if (receiver && member)
+ QHostInfoRunnable *runnable = new QHostInfoRunnable(name, id, receiver, std::move(slotObj));
+ if (isUsingStringBasedSlot) {
QObject::connect(&runnable->resultEmitter, SIGNAL(resultsReady(QHostInfo)),
receiver, member, Qt::QueuedConnection);
+ }
manager->scheduleLookup(runnable);
}
#endif // Q_OS_WASM
@@ -819,12 +821,15 @@ int QHostInfo::lookupHostImpl(const QString &name,
}
QHostInfoRunnable::QHostInfoRunnable(const QString &hn, int i, const QObject *receiver,
- QtPrivate::QSlotObjectBase *slotObj) :
- toBeLookedUp(hn), id(i), resultEmitter(receiver, slotObj)
+ QtPrivate::SlotObjUniquePtr slotObj)
+ : toBeLookedUp{hn}, id{i}, resultEmitter{receiver, std::move(slotObj)}
{
setAutoDelete(true);
}
+QHostInfoRunnable::~QHostInfoRunnable()
+ = default;
+
// the QHostInfoLookupManager will at some point call this via a QThreadPool
void QHostInfoRunnable::run()
{
@@ -962,7 +967,7 @@ void QHostInfoLookupManager::rescheduleWithMutexHeld()
isAlreadyRunning).second,
scheduledLookups.end());
- const int availableThreads = threadPool.maxThreadCount() - currentLookups.size();
+ const int availableThreads = std::max(threadPool.maxThreadCount(), 1) - currentLookups.size();
if (availableThreads > 0) {
int readyToStartCount = qMin(availableThreads, scheduledLookups.size());
auto it = scheduledLookups.begin();
@@ -1000,6 +1005,9 @@ void QHostInfoLookupManager::abortLookup(int id)
if (wasDeleted)
return;
+ if (id == -1)
+ return;
+
#if QT_CONFIG(thread)
// is postponed? delete and return
for (int i = 0; i < postponedLookups.size(); i++) {
diff --git a/src/network/kernel/qhostinfo.h b/src/network/kernel/qhostinfo.h
index 47db075b44..3942e41498 100644
--- a/src/network/kernel/qhostinfo.h
+++ b/src/network/kernel/qhostinfo.h
@@ -17,6 +17,7 @@ class QHostInfoPrivate;
class Q_NETWORK_EXPORT QHostInfo
{
+ Q_GADGET
public:
enum HostInfoError {
NoError,
@@ -48,7 +49,10 @@ public:
void setLookupId(int id);
int lookupId() const;
+#if QT_NETWORK_REMOVED_SINCE(6, 7)
static int lookupHost(const QString &name, QObject *receiver, const char *member);
+#endif
+ static int lookupHost(const QString &name, const QObject *receiver, const char *member);
static void abortHostLookup(int lookupId);
static QHostInfo fromName(const QString &name);
@@ -57,59 +61,30 @@ public:
#ifdef Q_QDOC
template<typename Functor>
- static int lookupHost(const QString &name, Functor functor);
- template<typename Functor>
static int lookupHost(const QString &name, const QObject *context, Functor functor);
#else
- // lookupHost to a QObject slot
- template <typename Func>
+ // lookupHost to a callable (with context)
+ template <typename Functor>
static inline int lookupHost(const QString &name,
- const typename QtPrivate::FunctionPointer<Func>::Object *receiver,
- Func slot)
+ const typename QtPrivate::ContextTypeForFunctor<Functor>::ContextType *receiver,
+ Functor &&func)
{
- typedef QtPrivate::FunctionPointer<Func> SlotType;
-
- typedef QtPrivate::FunctionPointer<void (*)(QHostInfo)> SignalType;
- static_assert(int(SignalType::ArgumentCount) >= int(SlotType::ArgumentCount),
- "The slot requires more arguments than the signal provides.");
- static_assert((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments,
- typename SlotType::Arguments>::value),
- "Signal and slot arguments are not compatible.");
- static_assert((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, nullptr);
+ using Prototype = void(*)(QHostInfo);
+ QtPrivate::AssertCompatibleFunctions<Prototype, Functor>();
+ return lookupHostImpl(name, receiver,
+ QtPrivate::makeCallableObject<Prototype>(std::forward<Functor>(func)),
+ nullptr);
}
+#endif // Q_QDOC
+#ifndef QT_NO_CONTEXTLESS_CONNECT
// 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, std::move(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)
+ template <typename Functor>
+ static inline int lookupHost(const QString &name, Functor &&slot)
{
- typedef QtPrivate::FunctionPointer<Func1> SlotType;
-
- static_assert(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>(std::move(slot));
- return lookupHostImpl(name, context, slotObj, nullptr);
+ return lookupHost(name, nullptr, std::forward<Functor>(slot));
}
-#endif // Q_QDOC
+#endif // QT_NO_CONTEXTLESS_CONNECT
private:
QHostInfoPrivate *d_ptr;
diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h
index 2176b464ae..b229eb1cd8 100644
--- a/src/network/kernel/qhostinfo_p.h
+++ b/src/network/kernel/qhostinfo_p.h
@@ -43,26 +43,21 @@ class QHostInfoResult : public QObject
{
Q_OBJECT
public:
- QHostInfoResult(const QObject *receiver, QtPrivate::QSlotObjectBase *slotObj)
- : receiver(receiver), slotObj(slotObj),
- withContextObject(slotObj && receiver)
- {
- if (receiver)
- moveToThread(receiver->thread());
- }
+ explicit QHostInfoResult(const QObject *receiver, QtPrivate::SlotObjUniquePtr slot);
+ ~QHostInfoResult() override;
void postResultsReady(const QHostInfo &info);
Q_SIGNALS:
void resultsReady(const QHostInfo &info);
-protected:
- bool event(QEvent *event) override;
+private Q_SLOTS:
+ void finalizePostResultsReady(const QHostInfo &info);
private:
- QHostInfoResult(const QHostInfoResult *other)
- : receiver(other->receiver), slotObj(other->slotObj),
- withContextObject(other->withContextObject)
+ QHostInfoResult(QHostInfoResult *other)
+ : receiver(other->receiver.get() != other ? other->receiver.get() : this),
+ slotObj{std::move(other->slotObj)}
{
// cleanup if the application terminates before results are delivered
connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit,
@@ -71,9 +66,10 @@ private:
moveToThread(other->thread());
}
+ // receiver is either a QObject provided by the user,
+ // or it's set to `this` (to emulate the behavior of the contextless connect())
QPointer<const QObject> receiver = nullptr;
- QtPrivate::QSlotObjectBase *slotObj = nullptr;
- const bool withContextObject = false;
+ QtPrivate::SlotObjUniquePtr slotObj;
};
class QHostInfoAgent
@@ -141,8 +137,10 @@ private:
class QHostInfoRunnable : public QRunnable
{
public:
- QHostInfoRunnable(const QString &hn, int i, const QObject *receiver,
- QtPrivate::QSlotObjectBase *slotObj);
+ explicit QHostInfoRunnable(const QString &hn, int i, const QObject *receiver,
+ QtPrivate::SlotObjUniquePtr slotObj);
+ ~QHostInfoRunnable() override;
+
void run() override;
QString toBeLookedUp;
diff --git a/src/network/kernel/qhostinfo_unix.cpp b/src/network/kernel/qhostinfo_unix.cpp
index 12d8c04d10..80d386a13d 100644
--- a/src/network/kernel/qhostinfo_unix.cpp
+++ b/src/network/kernel/qhostinfo_unix.cpp
@@ -3,140 +3,78 @@
//#define QHOSTINFO_DEBUG
-#include "qplatformdefs.h"
-
#include "qhostinfo_p.h"
-#include "private/qnativesocketengine_p.h"
-#include "qiodevice.h"
+
#include <qbytearray.h>
-#if QT_CONFIG(library)
-#include <qlibrary.h>
-#endif
-#include <qbasicatomic.h>
-#include <qurl.h>
#include <qfile.h>
-#include <private/qnet_unix_p.h>
-
-#include "QtCore/qapplicationstatic.h"
+#include <qplatformdefs.h>
+#include <qurl.h>
#include <sys/types.h>
#include <netdb.h>
-#include <arpa/inet.h>
-#if defined(Q_OS_VXWORKS)
-# include <hostLib.h>
-#else
-# include <resolv.h>
-#endif
+#include <netinet/in.h>
-#if defined(__GNU_LIBRARY__) && !defined(__UCLIBC__)
-# include <gnu/lib-names.h>
+#if QT_CONFIG(libresolv)
+# include <resolv.h>
#endif
-#if defined(Q_OS_FREEBSD) || QT_CONFIG(dlopen)
-# include <dlfcn.h>
+#ifndef _PATH_RESCONF
+# define _PATH_RESCONF "/etc/resolv.conf"
#endif
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-enum LibResolvFeature {
- NeedResInit,
- NeedResNInit
-};
-
-typedef struct __res_state *res_state_ptr;
-
-typedef int (*res_init_proto)(void);
-static res_init_proto local_res_init = nullptr;
-typedef int (*res_ninit_proto)(res_state_ptr);
-static res_ninit_proto local_res_ninit = nullptr;
-typedef void (*res_nclose_proto)(res_state_ptr);
-static res_nclose_proto local_res_nclose = nullptr;
-static res_state_ptr local_res = nullptr;
-
-#if QT_CONFIG(library) && !defined(Q_OS_QNX)
-namespace {
-struct LibResolv
-{
- enum {
-#ifdef RES_NORELOAD
- // If RES_NORELOAD is defined, then the libc is capable of watching
- // /etc/resolv.conf for changes and reloading as necessary. So accept
- // whatever is configured.
- ReinitNecessary = false
-#else
- ReinitNecessary = true
-#endif
- };
-
- QLibrary lib;
- LibResolv();
- ~LibResolv() { lib.unload(); }
-};
-}
-
-static QFunctionPointer resolveSymbol(QLibrary &lib, const char *sym)
-{
- if (lib.isLoaded())
- return lib.resolve(sym);
-
-#if defined(RTLD_DEFAULT) && (defined(Q_OS_FREEBSD) || QT_CONFIG(dlopen))
- return reinterpret_cast<QFunctionPointer>(dlsym(RTLD_DEFAULT, sym));
-#else
- return nullptr;
-#endif
-}
-
-LibResolv::LibResolv()
+static void maybeRefreshResolver()
{
-#ifdef LIBRESOLV_SO
- lib.setFileName(QStringLiteral(LIBRESOLV_SO));
- if (!lib.load())
+#if defined(RES_NORELOAD)
+ // If RES_NORELOAD is defined, then the libc is capable of watching
+ // /etc/resolv.conf for changes and reloading as necessary. So accept
+ // whatever is configured.
+ return;
+#elif defined(Q_OS_DARWIN)
+ // Apple's libsystem_info.dylib:getaddrinfo() uses the
+ // libsystem_dnssd.dylib to resolve hostnames. Using res_init() has no
+ // effect on it and is thread-unsafe.
+ return;
+#elif defined(Q_OS_FREEBSD)
+ // FreeBSD automatically refreshes:
+ // https://github.com/freebsd/freebsd-src/blob/b3fe5d932264445cbf9a1c4eab01afb6179b499b/lib/libc/resolv/res_state.c#L69
+ return;
+#elif defined(Q_OS_OPENBSD)
+ // OpenBSD automatically refreshes:
+ // https://github.com/ligurio/openbsd-src/blob/b1ce0da17da254cc15b8aff25b3d55d3c7a82cec/lib/libc/asr/asr.c#L367
+ return;
+#elif defined(Q_OS_QNX)
+ // res_init() is not thread-safe; executing it leads to state corruption.
+ // Whether it reloads resolv.conf on its own is unknown.
+ return;
#endif
- {
- lib.setFileName("resolv"_L1);
- lib.load();
- }
-
- // res_ninit is required for localDomainName()
- local_res_ninit = res_ninit_proto(resolveSymbol(lib, "__res_ninit"));
- if (!local_res_ninit)
- local_res_ninit = res_ninit_proto(resolveSymbol(lib, "res_ninit"));
- if (local_res_ninit) {
- // we must now find res_nclose
- local_res_nclose = res_nclose_proto(resolveSymbol(lib, "res_nclose"));
- if (!local_res_nclose)
- local_res_nclose = res_nclose_proto(resolveSymbol(lib, "__res_nclose"));
- if (!local_res_nclose)
- local_res_ninit = nullptr;
- }
-
- if (ReinitNecessary || !local_res_ninit) {
- local_res_init = res_init_proto(resolveSymbol(lib, "__res_init"));
- if (!local_res_init)
- local_res_init = res_init_proto(resolveSymbol(lib, "res_init"));
- if (local_res_init && !local_res_ninit) {
- // if we can't get a thread-safe context, we have to use the global _res state
- local_res = res_state_ptr(resolveSymbol(lib, "_res"));
+#if QT_CONFIG(libresolv)
+ // OSes known or thought to reach here: AIX, NetBSD, Solaris,
+ // Linux with MUSL (though res_init() does nothing and is unnecessary)
+
+ Q_CONSTINIT static QT_STATBUF lastStat = {};
+ Q_CONSTINIT static QBasicMutex mutex = {};
+ if (QT_STATBUF st; QT_STAT(_PATH_RESCONF, &st) == 0) {
+ QMutexLocker locker(&mutex);
+ bool refresh = false;
+ if ((_res.options & RES_INIT) == 0)
+ refresh = true;
+ else if (lastStat.st_ctime != st.st_ctime)
+ refresh = true; // file was updated
+ else if (lastStat.st_dev != st.st_dev || lastStat.st_ino != st.st_ino)
+ refresh = true; // file was replaced
+ if (refresh) {
+ lastStat = st;
+ res_init();
}
}
+#endif
}
-Q_APPLICATION_STATIC(LibResolv, libResolv)
-
-static void resolveLibrary(LibResolvFeature f)
-{
- if (LibResolv::ReinitNecessary || f == NeedResNInit)
- libResolv();
-}
-#else // QT_CONFIG(library) || Q_OS_QNX
-static void resolveLibrary(LibResolvFeature)
-{
-}
-#endif // QT_CONFIG(library) || Q_OS_QNX
-
QHostInfo QHostInfoAgent::fromName(const QString &hostName)
{
QHostInfo results;
@@ -146,12 +84,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
hostName.toLatin1().constData());
#endif
- // Load res_init on demand.
- resolveLibrary(NeedResInit);
-
- // If res_init is available, poll it.
- if (local_res_init)
- local_res_init();
+ maybeRefreshResolver();
QHostAddress address;
if (address.setAddress(hostName))
@@ -162,56 +95,49 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
QString QHostInfo::localDomainName()
{
-#if !defined(Q_OS_VXWORKS) && !defined(Q_OS_ANDROID)
- resolveLibrary(NeedResNInit);
- if (local_res_ninit) {
- // using thread-safe version
- res_state_ptr state = res_state_ptr(malloc(sizeof(*state)));
- Q_CHECK_PTR(state);
- memset(state, 0, sizeof(*state));
- local_res_ninit(state);
- QString domainName = QUrl::fromAce(state->defdname);
+#if QT_CONFIG(libresolv)
+ auto domainNameFromRes = [](res_state r) {
+ QString domainName;
+ if (r->defdname[0])
+ domainName = QUrl::fromAce(r->defdname);
if (domainName.isEmpty())
- domainName = QUrl::fromAce(state->dnsrch[0]);
- local_res_nclose(state);
- free(state);
-
+ domainName = QUrl::fromAce(r->dnsrch[0]);
return domainName;
+ };
+ std::remove_pointer_t<res_state> state = {};
+ if (res_ninit(&state) == 0) {
+ // using thread-safe version
+ auto guard = qScopeGuard([&] { res_nclose(&state); });
+ return domainNameFromRes(&state);
}
- if (local_res_init && local_res) {
- // using thread-unsafe version
+ // using thread-unsafe version
+ maybeRefreshResolver();
+ return domainNameFromRes(&_res);
+#endif // !QT_CONFIG(libresolv)
- local_res_init();
- QString domainName = QUrl::fromAce(local_res->defdname);
- if (domainName.isEmpty())
- domainName = QUrl::fromAce(local_res->dnsrch[0]);
- return domainName;
- }
-#endif
// nothing worked, try doing it by ourselves:
QFile resolvconf;
-#if defined(_PATH_RESCONF)
- resolvconf.setFileName(QFile::decodeName(_PATH_RESCONF));
-#else
- resolvconf.setFileName("/etc/resolv.conf"_L1);
-#endif
+ resolvconf.setFileName(_PATH_RESCONF ""_L1);
if (!resolvconf.open(QIODevice::ReadOnly))
return QString(); // failure
QString domainName;
while (!resolvconf.atEnd()) {
- QByteArray line = resolvconf.readLine().trimmed();
- if (line.startsWith("domain "))
- return QUrl::fromAce(line.mid(sizeof "domain " - 1).trimmed());
+ const QByteArray lineArray = resolvconf.readLine();
+ QByteArrayView line = QByteArrayView(lineArray).trimmed();
+ constexpr QByteArrayView domainWithSpace = "domain ";
+ if (line.startsWith(domainWithSpace))
+ return QUrl::fromAce(line.mid(domainWithSpace.size()).trimmed().toByteArray());
// in case there's no "domain" line, fall back to the first "search" entry
- if (domainName.isEmpty() && line.startsWith("search ")) {
- QByteArray searchDomain = line.mid(sizeof "search " - 1).trimmed();
+ constexpr QByteArrayView searchWithSpace = "search ";
+ if (domainName.isEmpty() && line.startsWith(searchWithSpace)) {
+ QByteArrayView searchDomain = line.mid(searchWithSpace.size()).trimmed();
int pos = searchDomain.indexOf(' ');
if (pos != -1)
searchDomain.truncate(pos);
- domainName = QUrl::fromAce(searchDomain);
+ domainName = QUrl::fromAce(searchDomain.toByteArray());
}
}
diff --git a/src/network/kernel/qnetconmonitor_win.cpp b/src/network/kernel/qnetconmonitor_win.cpp
index 64bd90b0ad..bf6aff1e46 100644
--- a/src/network/kernel/qnetconmonitor_win.cpp
+++ b/src/network/kernel/qnetconmonitor_win.cpp
@@ -167,6 +167,12 @@ QNetworkConnectionEvents::~QNetworkConnectionEvents()
ComPtr<INetworkConnection> QNetworkConnectionEvents::getNetworkConnectionFromAdapterGuid(QUuid guid)
{
+ if (!networkListManager) {
+ qCDebug(lcNetMon) << "Failed to enumerate network connections:"
+ << "NetworkListManager was not instantiated";
+ return nullptr;
+ }
+
ComPtr<IEnumNetworkConnections> connections;
auto hr = networkListManager->GetNetworkConnections(connections.GetAddressOf());
if (FAILED(hr)) {
diff --git a/src/network/kernel/qnetworkdatagram.cpp b/src/network/kernel/qnetworkdatagram.cpp
index e9e3a67edf..a97eb25a51 100644
--- a/src/network/kernel/qnetworkdatagram.cpp
+++ b/src/network/kernel/qnetworkdatagram.cpp
@@ -481,7 +481,7 @@ void QNetworkDatagram::makeReply_helper_inplace(const QByteArray &data)
void QNetworkDatagram::destroy(QNetworkDatagramPrivate *d)
{
- Q_ASSUME(d);
+ Q_ASSERT(d);
delete d;
}
diff --git a/src/network/kernel/qnetworkinformation.cpp b/src/network/kernel/qnetworkinformation.cpp
index fc40787067..10d6b89e2c 100644
--- a/src/network/kernel/qnetworkinformation.cpp
+++ b/src/network/kernel/qnetworkinformation.cpp
@@ -47,14 +47,21 @@ static void networkInfoCleanup()
if (!instance)
return;
- auto needsReinvoke = instance->thread() && instance->thread() != QThread::currentThread();
- if (needsReinvoke) {
- QMetaObject::invokeMethod(dataHolder->instanceHolder.get(), []() { networkInfoCleanup(); });
- return;
- }
dataHolder->instanceHolder.reset();
}
+using namespace Qt::Literals::StringLiterals;
+
+class QNetworkInformationDummyBackend : public QNetworkInformationBackend {
+ Q_OBJECT
+public:
+ QString name() const override { return u"dummy"_s; }
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ return {};
+ }
+};
+
class QNetworkInformationPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QNetworkInformation)
@@ -65,6 +72,7 @@ public:
static QNetworkInformation *create(QNetworkInformation::Features features);
static QNetworkInformation *create(QStringView name);
+ static QNetworkInformation *createDummy();
static QNetworkInformation *instance()
{
if (!dataHolder())
@@ -188,7 +196,7 @@ QNetworkInformation *QNetworkInformationPrivate::create(QStringView name)
QString listNames;
listNames.reserve(8 * dataHolder->factories.count());
for (const auto *factory : std::as_const(dataHolder->factories))
- listNames += factory->name() + QStringLiteral(", ");
+ listNames += factory->name() + ", "_L1;
listNames.chop(2);
qDebug().nospace() << "Couldn't find " << name << " in list with names: { "
<< listNames << " }";
@@ -230,7 +238,7 @@ QNetworkInformation *QNetworkInformationPrivate::create(QNetworkInformation::Fea
return dataHolder->instanceHolder.get();
const auto supportsRequestedFeatures = [features](QNetworkInformationBackendFactory *factory) {
- return factory && (factory->featuresSupported() & features) == features;
+ return factory && factory->featuresSupported().testFlags(features);
};
for (auto it = dataHolder->factories.cbegin(), end = dataHolder->factories.cend(); it != end;
@@ -271,6 +279,20 @@ QNetworkInformation *QNetworkInformationPrivate::create(QNetworkInformation::Fea
return nullptr;
}
+QNetworkInformation *QNetworkInformationPrivate::createDummy()
+{
+ if (!dataHolder())
+ return nullptr;
+
+ QMutexLocker locker(&dataHolder->instanceMutex);
+ if (dataHolder->instanceHolder)
+ return dataHolder->instanceHolder.get();
+
+ QNetworkInformationBackend *backend = new QNetworkInformationDummyBackend;
+ dataHolder->instanceHolder.reset(new QNetworkInformation(backend));
+ return dataHolder->instanceHolder.get();
+}
+
/*!
\class QNetworkInformationBackend
\internal (Semi-private)
@@ -492,6 +514,14 @@ QNetworkInformation::QNetworkInformation(QNetworkInformationBackend *backend)
&QNetworkInformation::transportMediumChanged);
connect(backend, &QNetworkInformationBackend::isMeteredChanged, this,
&QNetworkInformation::isMeteredChanged);
+
+ QThread *main = nullptr;
+
+ if (QCoreApplication::instance())
+ main = QCoreApplication::instance()->thread();
+
+ if (main && thread() != main)
+ moveToThread(main);
}
/*!
@@ -599,6 +629,12 @@ QNetworkInformation::Features QNetworkInformation::supportedFeatures() const
Attempts to load the platform-default backend.
+ \note Starting with 6.7 this tries to load any backend that supports
+ \l{QNetworkInformation::Feature::Reachability}{Reachability} if the
+ platform-default backend is not available or fails to load.
+ If this also fails it will fall back to a backend that only returns
+ the default values for all properties.
+
This platform-to-plugin mapping is as follows:
\table
@@ -619,12 +655,14 @@ QNetworkInformation::Features QNetworkInformation::supportedFeatures() const
\li networkmanager
\endtable
- This function is provided for convenience where the default for a given
- platform is good enough. If you are not using the default plugins you must
- use one of the other load() overloads.
+ This function is provided for convenience where the logic earlier
+ is good enough. If you require a specific plugin then you should call
+ loadBackendByName() or loadBackendByFeatures() directly instead.
- Returns \c true if it managed to load the backend or if it was already
- loaded. Returns \c false otherwise.
+ Determines a suitable backend to load and returns \c true if this backend
+ is already loaded or on successful loading of it. Returns \c false if any
+ other backend has already been loaded, or if loading of the selected
+ backend fails.
\sa instance(), load()
*/
@@ -640,9 +678,15 @@ bool QNetworkInformation::loadDefaultBackend()
#elif defined(Q_OS_LINUX)
index = QNetworkInformationBackend::PluginNamesLinuxIndex;
#endif
- if (index == -1)
- return false;
- return loadBackendByName(QNetworkInformationBackend::PluginNames[index]);
+ if (index != -1 && loadBackendByName(QNetworkInformationBackend::PluginNames[index]))
+ return true;
+ // We assume reachability is the most commonly wanted feature, and try to
+ // load the backend that advertises the most features including that:
+ if (loadBackendByFeatures(Feature::Reachability))
+ return true;
+
+ // Fall back to the dummy backend
+ return loadBackendByName(u"dummy");
}
/*!
@@ -658,6 +702,9 @@ bool QNetworkInformation::loadDefaultBackend()
*/
bool QNetworkInformation::loadBackendByName(QStringView backend)
{
+ if (backend == u"dummy")
+ return QNetworkInformationPrivate::createDummy() != nullptr;
+
auto loadedBackend = QNetworkInformationPrivate::create(backend);
return loadedBackend && loadedBackend->backendName().compare(backend, Qt::CaseInsensitive) == 0;
}
@@ -724,3 +771,4 @@ QT_END_NAMESPACE
#include "moc_qnetworkinformation.cpp"
#include "moc_qnetworkinformation_p.cpp"
+#include "qnetworkinformation.moc"
diff --git a/src/network/kernel/qnetworkinformation.h b/src/network/kernel/qnetworkinformation.h
index 818da98aad..57a49f23c8 100644
--- a/src/network/kernel/qnetworkinformation.h
+++ b/src/network/kernel/qnetworkinformation.h
@@ -23,6 +23,7 @@ class Q_NETWORK_EXPORT QNetworkInformation : public QObject
NOTIFY isBehindCaptivePortalChanged)
Q_PROPERTY(TransportMedium transportMedium READ transportMedium NOTIFY transportMediumChanged)
Q_PROPERTY(bool isMetered READ isMetered NOTIFY isMeteredChanged)
+ Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
public:
enum class Reachability {
Unknown,
@@ -82,7 +83,6 @@ Q_SIGNALS:
private:
friend struct QNetworkInformationDeleter;
- friend class QNetworkInformationPrivate;
QNetworkInformation(QNetworkInformationBackend *backend);
~QNetworkInformation() override;
diff --git a/src/network/kernel/qnetworkinformation_p.h b/src/network/kernel/qnetworkinformation_p.h
index 40c12391c5..504955a6e1 100644
--- a/src/network/kernel/qnetworkinformation_p.h
+++ b/src/network/kernel/qnetworkinformation_p.h
@@ -20,6 +20,7 @@
#include <QtNetwork/qnetworkinformation.h>
#include <QtCore/qloggingcategory.h>
+#include <QtCore/qreadwritelock.h>
QT_BEGIN_NAMESPACE
@@ -48,10 +49,29 @@ public:
virtual QString name() const = 0;
virtual QNetworkInformation::Features featuresSupported() const = 0;
- Reachability reachability() const { return m_reachability; }
- bool behindCaptivePortal() const { return m_behindCaptivePortal; }
- TransportMedium transportMedium() const { return m_transportMedium; }
- bool isMetered() const { return m_metered; }
+ Reachability reachability() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_reachability;
+ }
+
+ bool behindCaptivePortal() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_behindCaptivePortal;
+ }
+
+ TransportMedium transportMedium() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_transportMedium;
+ }
+
+ bool isMetered() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_metered;
+ }
Q_SIGNALS:
void reachabilityChanged(Reachability reachability);
@@ -62,37 +82,46 @@ Q_SIGNALS:
protected:
void setReachability(QNetworkInformation::Reachability reachability)
{
+ QWriteLocker locker(&m_lock);
if (m_reachability != reachability) {
m_reachability = reachability;
+ locker.unlock();
emit reachabilityChanged(reachability);
}
}
void setBehindCaptivePortal(bool behindPortal)
{
+ QWriteLocker locker(&m_lock);
if (m_behindCaptivePortal != behindPortal) {
m_behindCaptivePortal = behindPortal;
+ locker.unlock();
emit behindCaptivePortalChanged(behindPortal);
}
}
void setTransportMedium(TransportMedium medium)
{
+ QWriteLocker locker(&m_lock);
if (m_transportMedium != medium) {
m_transportMedium = medium;
+ locker.unlock();
emit transportMediumChanged(medium);
}
}
void setMetered(bool isMetered)
{
+ QWriteLocker locker(&m_lock);
if (m_metered != isMetered) {
m_metered = isMetered;
+ locker.unlock();
emit isMeteredChanged(isMetered);
}
}
private:
+ mutable QReadWriteLock m_lock;
Reachability m_reachability = Reachability::Unknown;
TransportMedium m_transportMedium = TransportMedium::Unknown;
bool m_behindCaptivePortal = false;
diff --git a/src/network/kernel/qnetworkinterface_linux.cpp b/src/network/kernel/qnetworkinterface_linux.cpp
index 622cd2976b..67ed8006bb 100644
--- a/src/network/kernel/qnetworkinterface_linux.cpp
+++ b/src/network/kernel/qnetworkinterface_linux.cpp
@@ -111,7 +111,10 @@ struct NetlinkSocket
template <typename Lambda> struct ProcessNetlinkRequest
{
using FunctionTraits = QtPrivate::FunctionPointer<decltype(&Lambda::operator())>;
- using FirstArgument = typename FunctionTraits::Arguments::Car;
+ using FirstArgumentPointer = typename FunctionTraits::Arguments::Car;
+ using FirstArgument = std::remove_pointer_t<FirstArgumentPointer>;
+ static_assert(std::is_pointer_v<FirstArgumentPointer>);
+ static_assert(std::is_aggregate_v<FirstArgument>);
static int expectedTypeForRequest(int rtype)
{
@@ -136,7 +139,7 @@ template <typename Lambda> struct ProcessNetlinkRequest
if (!NLMSG_OK(hdr, quint32(len)))
return;
- auto arg = reinterpret_cast<FirstArgument>(NLMSG_DATA(hdr));
+ auto arg = static_cast<FirstArgument *>(NLMSG_DATA(hdr));
size_t payloadLen = NLMSG_PAYLOAD(hdr, 0);
// is this a multipart message?
@@ -156,7 +159,7 @@ template <typename Lambda> struct ProcessNetlinkRequest
// NLMSG_NEXT also updates the len variable
hdr = NLMSG_NEXT(hdr, len);
- arg = reinterpret_cast<FirstArgument>(NLMSG_DATA(hdr));
+ arg = static_cast<FirstArgument *>(NLMSG_DATA(hdr));
payloadLen = NLMSG_PAYLOAD(hdr, 0);
} while (NLMSG_OK(hdr, quint32(len)));
diff --git a/src/network/kernel/qnetworkinterface_unix.cpp b/src/network/kernel/qnetworkinterface_unix.cpp
index 082d83e9dc..c0a7d9e00d 100644
--- a/src/network/kernel/qnetworkinterface_unix.cpp
+++ b/src/network/kernel/qnetworkinterface_unix.cpp
@@ -17,11 +17,7 @@
# include "qdatetime.h"
#endif
-#if defined(QT_LINUXBASE)
-# define QT_NO_GETIFADDRS
-#endif
-
-#ifndef QT_NO_GETIFADDRS
+#if QT_CONFIG(getifaddrs)
# include <ifaddrs.h>
#endif
@@ -56,30 +52,38 @@ static QHostAddress addressFromSockaddr(sockaddr *sa, int ifindex = 0, const QSt
}
}
return address;
+}
+
+template <typename Req> [[maybe_unused]]
+static auto &ifreq_index(Req &req, std::enable_if_t<sizeof(std::declval<Req>().ifr_index) != 0, int> = 0)
+{
+ return req.ifr_index;
+}
+template <typename Req> [[maybe_unused]]
+static auto &ifreq_index(Req &req, std::enable_if_t<sizeof(std::declval<Req>().ifr_ifindex) != 0, int> = 0)
+{
+ return req.ifr_ifindex;
}
uint QNetworkInterfaceManager::interfaceIndexFromName(const QString &name)
{
-#ifndef QT_NO_IPV6IFNAME
- return ::if_nametoindex(name.toLatin1());
+#if QT_CONFIG(ipv6ifname)
+ return ::if_nametoindex(name.toLatin1().constData());
#elif defined(SIOCGIFINDEX)
struct ifreq req;
int socket = qt_safe_socket(AF_INET, SOCK_STREAM, 0);
if (socket < 0)
return 0;
- QByteArray name8bit = name.toLatin1();
+ const QByteArray name8bit = name.toLatin1();
memset(&req, 0, sizeof(ifreq));
- memcpy(req.ifr_name, name8bit, qMin<int>(name8bit.length() + 1, sizeof(req.ifr_name) - 1));
+ if (!name8bit.isNull())
+ memcpy(req.ifr_name, name8bit.data(), qMin(size_t(name8bit.length()) + 1, sizeof(req.ifr_name) - 1));
uint id = 0;
if (qt_safe_ioctl(socket, SIOCGIFINDEX, &req) >= 0)
-# if QT_CONFIG(ifr_index)
- id = req.ifr_index;
-# else
- id = req.ifr_ifindex;
-# endif
+ id = ifreq_index(req);
qt_safe_close(socket);
return id;
#else
@@ -90,7 +94,7 @@ uint QNetworkInterfaceManager::interfaceIndexFromName(const QString &name)
QString QNetworkInterfaceManager::interfaceNameFromIndex(uint index)
{
-#ifndef QT_NO_IPV6IFNAME
+#if QT_CONFIG(ipv6ifname)
char buf[IF_NAMESIZE];
if (::if_indextoname(index, buf))
return QString::fromLatin1(buf);
@@ -99,12 +103,7 @@ QString QNetworkInterfaceManager::interfaceNameFromIndex(uint index)
int socket = qt_safe_socket(AF_INET, SOCK_STREAM, 0);
if (socket >= 0) {
memset(&req, 0, sizeof(ifreq));
-# if QT_CONFIG(ifr_index)
- req.ifr_index = index;
-# else
- req.ifr_ifindex = index;
-# endif
-
+ ifreq_index(req) = index;
if (qt_safe_ioctl(socket, SIOCGIFNAME, &req) >= 0) {
qt_safe_close(socket);
return QString::fromLatin1(req.ifr_name);
@@ -124,13 +123,13 @@ static int getMtu(int socket, struct ifreq *req)
return 0;
}
-#ifdef QT_NO_GETIFADDRS
+#if !QT_CONFIG(getifaddrs)
// getifaddrs not available
static QSet<QByteArray> interfaceNames(int socket)
{
QSet<QByteArray> result;
-#ifdef QT_NO_IPV6IFNAME
+#if !QT_CONFIG(ipv6ifname)
QByteArray storageBuffer;
struct ifconf interfaceList;
static const int STORAGEBUFFER_GROWTH = 256;
@@ -185,15 +184,11 @@ static QNetworkInterfacePrivate *findInterface(int socket, QList<QNetworkInterfa
QNetworkInterfacePrivate *iface = nullptr;
int ifindex = 0;
-#if !defined(QT_NO_IPV6IFNAME) || defined(SIOCGIFINDEX)
+#if QT_CONFIG(ipv6ifname) || defined(SIOCGIFINDEX)
// Get the interface index
# ifdef SIOCGIFINDEX
if (qt_safe_ioctl(socket, SIOCGIFINDEX, &req) >= 0)
-# if QT_CONFIG(ifr_index)
- ifindex = req.ifr_index;
-# else
- ifindex = req.ifr_ifindex;
-# endif
+ ifindex = ifreq_index(req);
# else
ifindex = if_nametoindex(req.ifr_name);
# endif
@@ -241,7 +236,8 @@ static QList<QNetworkInterfacePrivate *> interfaceListing()
for ( ; it != names.constEnd(); ++it) {
ifreq req;
memset(&req, 0, sizeof(ifreq));
- memcpy(req.ifr_name, *it, qMin<int>(it->length() + 1, sizeof(req.ifr_name) - 1));
+ if (!it->isNull())
+ memcpy(req.ifr_name, it->constData(), qMin(size_t(it->length()) + 1, sizeof(req.ifr_name) - 1));
QNetworkInterfacePrivate *iface = findInterface(socket, interfaces, req);
@@ -252,7 +248,8 @@ static QList<QNetworkInterfacePrivate *> interfaceListing()
iface->name = QString::fromLatin1(req.ifr_name);
// reset the name:
- memcpy(req.ifr_name, oldName, qMin<int>(oldName.length() + 1, sizeof(req.ifr_name) - 1));
+ if (!oldName.isNull())
+ memcpy(req.ifr_name, oldName.constData(), qMin(size_t(oldName.length()) + 1, sizeof(req.ifr_name) - 1));
} else
#endif
{
diff --git a/src/network/kernel/qnetworkproxy.cpp b/src/network/kernel/qnetworkproxy.cpp
index 62bba24bce..6875e93581 100644
--- a/src/network/kernel/qnetworkproxy.cpp
+++ b/src/network/kernel/qnetworkproxy.cpp
@@ -752,6 +752,53 @@ QNetworkProxy QNetworkProxy::applicationProxy()
}
/*!
+ \since 6.8
+
+ Returns headers that are set in this network request.
+
+ If the proxy is not of type HttpProxy or HttpCachingProxy,
+ default constructed QHttpHeaders is returned.
+
+ \sa setHeaders()
+*/
+QHttpHeaders QNetworkProxy::headers() const
+{
+ if (d->type != HttpProxy && d->type != HttpCachingProxy)
+ return {};
+ return d->headers.headers();
+}
+
+/*!
+ \since 6.8
+
+ Sets \a newHeaders as headers in this network request, overriding
+ any previously set headers.
+
+ If some headers correspond to the known headers, the values will
+ be parsed and the corresponding parsed form will also be set.
+
+ If the proxy is not of type HttpProxy or HttpCachingProxy this has no
+ effect.
+
+ \sa headers(), QNetworkRequest::KnownHeaders
+*/
+void QNetworkProxy::setHeaders(QHttpHeaders &&newHeaders)
+{
+ if (d->type == HttpProxy || d->type == HttpCachingProxy)
+ d->headers.setHeaders(std::move(newHeaders));
+}
+
+/*!
+ \overload
+ \since 6.8
+*/
+void QNetworkProxy::setHeaders(const QHttpHeaders &newHeaders)
+{
+ if (d->type == HttpProxy || d->type == HttpCachingProxy)
+ d->headers.setHeaders(newHeaders);
+}
+
+/*!
\since 5.0
Returns the value of the known network header \a header if it is
in use for this proxy. If it is not present, returns QVariant()
diff --git a/src/network/kernel/qnetworkproxy.h b/src/network/kernel/qnetworkproxy.h
index c39fff5318..9f92ffeb12 100644
--- a/src/network/kernel/qnetworkproxy.h
+++ b/src/network/kernel/qnetworkproxy.h
@@ -77,6 +77,7 @@ class QNetworkProxyPrivate;
class Q_NETWORK_EXPORT QNetworkProxy
{
+ Q_GADGET
public:
enum ProxyType {
DefaultProxy,
@@ -135,6 +136,10 @@ public:
static void setApplicationProxy(const QNetworkProxy &proxy);
static QNetworkProxy applicationProxy();
+ QHttpHeaders headers() const;
+ void setHeaders(const QHttpHeaders &newHeaders);
+ void setHeaders(QHttpHeaders &&newHeaders);
+
// "cooked" headers
QVariant header(QNetworkRequest::KnownHeaders header) const;
void setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value);
diff --git a/src/network/kernel/qnetworkproxy_android.cpp b/src/network/kernel/qnetworkproxy_android.cpp
index 2e1fb50234..3d37266b70 100644
--- a/src/network/kernel/qnetworkproxy_android.cpp
+++ b/src/network/kernel/qnetworkproxy_android.cpp
@@ -24,7 +24,7 @@ Q_GLOBAL_STATIC(ProxyInfoObject, proxyInfoInstance)
static const char networkClass[] = "org/qtproject/qt/android/network/QtNetwork";
-Q_DECLARE_JNI_TYPE(ProxyInfo, "Landroid/net/ProxyInfo;")
+Q_DECLARE_JNI_CLASS(ProxyInfo, "android/net/ProxyInfo")
Q_DECLARE_JNI_TYPE(JStringArray, "[Ljava/lang/String;")
ProxyInfoObject::ProxyInfoObject()
diff --git a/src/network/kernel/qnetworkproxy_darwin.cpp b/src/network/kernel/qnetworkproxy_darwin.cpp
index 431228c934..d2bd4958dd 100644
--- a/src/network/kernel/qnetworkproxy_darwin.cpp
+++ b/src/network/kernel/qnetworkproxy_darwin.cpp
@@ -289,9 +289,9 @@ QList<QNetworkProxy> macQueryInternal(const QNetworkProxyQuery &query)
// No PAC, decide which proxy we're looking for based on the query
// try the protocol-specific proxy
- QString protocol = query.protocolTag().toLower();
+ const QString protocol = query.protocolTag();
QNetworkProxy protocolSpecificProxy;
- if (protocol == "http"_L1) {
+ if (protocol.compare("http"_L1, Qt::CaseInsensitive) == 0) {
protocolSpecificProxy =
proxyFromDictionary(dict, QNetworkProxy::HttpProxy,
kCFNetworkProxiesHTTPEnable,
@@ -318,13 +318,13 @@ QList<QNetworkProxy> macQueryInternal(const QNetworkProxyQuery &query)
}
#else
bool isHttps = false;
- if (protocol == "ftp"_L1) {
+ if (protocol.compare("ftp"_L1, Qt::CaseInsensitive) == 0) {
protocolSpecificProxy =
proxyFromDictionary(dict, QNetworkProxy::FtpCachingProxy,
kCFNetworkProxiesFTPEnable,
kCFNetworkProxiesFTPProxy,
kCFNetworkProxiesFTPPort);
- } else if (protocol == "https"_L1) {
+ } else if (protocol.compare("https"_L1, Qt::CaseInsensitive) == 0) {
isHttps = true;
protocolSpecificProxy =
proxyFromDictionary(dict, QNetworkProxy::HttpProxy,
diff --git a/src/network/kernel/qnetworkproxy_libproxy.cpp b/src/network/kernel/qnetworkproxy_libproxy.cpp
index 46066b86f7..da1e8fdbd4 100644
--- a/src/network/kernel/qnetworkproxy_libproxy.cpp
+++ b/src/network/kernel/qnetworkproxy_libproxy.cpp
@@ -12,6 +12,7 @@
#include <QtCore/QUrl>
#include <QtCore/private/qeventdispatcher_unix_p.h>
#include <QtCore/private/qthread_p.h>
+#include <QtCore/qapplicationstatic.h>
#include <proxy.h>
#include <dlfcn.h>
@@ -72,7 +73,7 @@ private:
Data *request;
};
-Q_GLOBAL_STATIC(QLibProxyWrapper, libProxyWrapper);
+Q_APPLICATION_STATIC(QLibProxyWrapper, libProxyWrapper)
QLibProxyWrapper::QLibProxyWrapper()
{
@@ -165,13 +166,15 @@ QList<QNetworkProxy> QNetworkProxyFactory::systemProxyForQuery(const QNetworkPro
break;
// fake URLs to get libproxy to tell us the SOCKS proxy
case QNetworkProxyQuery::TcpSocket:
- queryUrl.setScheme(QStringLiteral("tcp"));
+ if (queryUrl.scheme().isEmpty())
+ queryUrl.setScheme(QStringLiteral("tcp"));
queryUrl.setHost(query.peerHostName());
queryUrl.setPort(query.peerPort());
requiredCapabilities |= QNetworkProxy::TunnelingCapability;
break;
case QNetworkProxyQuery::UdpSocket:
- queryUrl.setScheme(QStringLiteral("udp"));
+ if (queryUrl.scheme().isEmpty())
+ queryUrl.setScheme(QStringLiteral("udp"));
queryUrl.setHost(query.peerHostName());
queryUrl.setPort(query.peerPort());
requiredCapabilities |= QNetworkProxy::UdpTunnelingCapability;
diff --git a/src/network/kernel/qtnetworkglobal_p.h b/src/network/kernel/qtnetworkglobal_p.h
index ff2b75e3a9..b90e675cb4 100644
--- a/src/network/kernel/qtnetworkglobal_p.h
+++ b/src/network/kernel/qtnetworkglobal_p.h
@@ -18,7 +18,6 @@
#include <QtNetwork/qtnetworkglobal.h>
#include <QtCore/private/qglobal_p.h>
#include <QtNetwork/private/qtnetwork-config_p.h>
-#include <QtNetwork/private/qtnetworkexports_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index 7d7db11e01..e456d00713 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -173,8 +173,9 @@
parameter describes the type of error that occurred.
When this signal is emitted, the socket may not be ready for a reconnect
- attempt. In that case, attempts to reconnect should be done from the event
- loop. For example, use a QTimer::singleShot() with 0 as the timeout.
+ attempt. In that case, attempts to reconnect should be done from the
+ event loop. For example, use QChronoTimer::singleShot() with 0ns as
+ the timeout.
QAbstractSocket::SocketError is not a registered metatype, so for queued
connections, you will have to register it with Q_DECLARE_METATYPE() and
@@ -439,7 +440,7 @@
#include <qmetaobject.h>
#include <qpointer.h>
#include <qtimer.h>
-#include <qelapsedtimer.h>
+#include <qdeadlinetimer.h>
#include <qscopedvaluerollback.h>
#include <qvarlengtharray.h>
@@ -465,11 +466,12 @@
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
+using namespace std::chrono_literals;
QT_IMPL_METATYPE_EXTERN_TAGGED(QAbstractSocket::SocketState, QAbstractSocket__SocketState)
QT_IMPL_METATYPE_EXTERN_TAGGED(QAbstractSocket::SocketError, QAbstractSocket__SocketError)
-static const int DefaultConnectTimeout = 30000;
+static constexpr auto DefaultConnectTimeout = 30s;
static bool isProxyError(QAbstractSocket::SocketError error)
{
@@ -636,11 +638,19 @@ bool QAbstractSocketPrivate::canReadNotification()
return !q->isReadable();
}
} else {
- if (hasPendingData) {
+ const bool isUdpSocket = (socketType == QAbstractSocket::UdpSocket);
+ if (hasPendingData && (!isUdpSocket || hasPendingDatagram)) {
socketEngine->setReadNotificationEnabled(false);
return true;
}
- hasPendingData = true;
+ if (!isUdpSocket
+#if QT_CONFIG(udpsocket)
+ || socketEngine->hasPendingDatagrams()
+#endif
+ ) {
+ hasPendingData = true;
+ hasPendingDatagram = isUdpSocket;
+ }
}
emitReadyRead();
@@ -1057,8 +1067,7 @@ void QAbstractSocketPrivate::_q_connectToNextAddress()
q, SLOT(_q_abortConnectionAttempt()),
Qt::DirectConnection);
}
- int connectTimeout = DefaultConnectTimeout;
- connectTimer->start(connectTimeout);
+ connectTimer->start(DefaultConnectTimeout);
}
// Wait for a write notification that will eventually call
@@ -2052,8 +2061,7 @@ bool QAbstractSocket::waitForConnected(int msecs)
bool wasPendingClose = d->pendingClose;
d->pendingClose = false;
- QElapsedTimer stopWatch;
- stopWatch.start();
+ QDeadlineTimer deadline{msecs};
if (d->state == HostLookupState) {
#if defined (QABSTRACTSOCKET_DEBUG)
@@ -2073,22 +2081,21 @@ bool QAbstractSocket::waitForConnected(int msecs)
if (state() == UnconnectedState)
return false; // connect not im progress anymore!
- int connectTimeout = DefaultConnectTimeout;
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 > connectTimeout)
- timeout = connectTimeout;
+ while (state() == ConnectingState && !deadline.hasExpired()) {
+ QDeadlineTimer timer = deadline;
+ if (!deadline.isForever() && deadline.remainingTimeAsDuration() > DefaultConnectTimeout)
+ timer = QDeadlineTimer(DefaultConnectTimeout);
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::waitForConnected(%i) waiting %.2f secs for connection attempt #%i",
- msecs, timeout / 1000.0, attempt++);
+ msecs, timer.remainingTime() / 1000.0, attempt++);
#endif
timedOut = false;
- if (d->socketEngine && d->socketEngine->waitForWrite(timeout, &timedOut) && !timedOut) {
+ if (d->socketEngine && d->socketEngine->waitForWrite(timer, &timedOut) && !timedOut) {
d->_q_testConnection();
} else {
d->_q_connectToNextAddress();
@@ -2143,8 +2150,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs)
return false;
}
- QElapsedTimer stopWatch;
- stopWatch.start();
+ QDeadlineTimer deadline{msecs};
// handle a socket in connecting state
if (state() == HostLookupState || state() == ConnectingState) {
@@ -2160,7 +2166,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs)
bool readyToRead = false;
bool readyToWrite = false;
if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, true, !d->writeBuffer.isEmpty(),
- qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
+ deadline)) {
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::waitForReadyRead(%i) failed (%i, %s)",
msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData());
@@ -2178,7 +2184,7 @@ bool QAbstractSocket::waitForReadyRead(int msecs)
if (readyToWrite)
d->canWriteNotification();
- } while (msecs == -1 || qt_subtract_from_timeout(msecs, stopWatch.elapsed()) > 0);
+ } while (!deadline.hasExpired());
return false;
}
@@ -2214,8 +2220,7 @@ bool QAbstractSocket::waitForBytesWritten(int msecs)
if (d->writeBuffer.isEmpty())
return false;
- QElapsedTimer stopWatch;
- stopWatch.start();
+ QDeadlineTimer deadline{msecs};
// handle a socket in connecting state
if (state() == HostLookupState || state() == ConnectingState) {
@@ -2223,13 +2228,13 @@ bool QAbstractSocket::waitForBytesWritten(int msecs)
return false;
}
- forever {
+ for (;;) {
bool readyToRead = false;
bool readyToWrite = false;
if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite,
!d->readBufferMaxSize || d->buffer.size() < d->readBufferMaxSize,
!d->writeBuffer.isEmpty(),
- qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
+ deadline)) {
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::waitForBytesWritten(%i) failed (%i, %s)",
msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData());
@@ -2293,8 +2298,7 @@ bool QAbstractSocket::waitForDisconnected(int msecs)
return false;
}
- QElapsedTimer stopWatch;
- stopWatch.start();
+ QDeadlineTimer deadline{msecs};
// handle a socket in connecting state
if (state() == HostLookupState || state() == ConnectingState) {
@@ -2304,12 +2308,12 @@ bool QAbstractSocket::waitForDisconnected(int msecs)
return true;
}
- forever {
+ for (;;) {
bool readyToRead = false;
bool readyToWrite = false;
if (!d->socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, state() == ConnectedState,
!d->writeBuffer.isEmpty(),
- qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
+ deadline)) {
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocket::waitForReadyRead(%i) failed (%i, %s)",
msecs, d->socketEngine->error(), d->socketEngine->errorString().toLatin1().constData());
diff --git a/src/network/socket/qabstractsocket_p.h b/src/network/socket/qabstractsocket_p.h
index 98d74dcfd4..cc5f53179c 100644
--- a/src/network/socket/qabstractsocket_p.h
+++ b/src/network/socket/qabstractsocket_p.h
@@ -110,6 +110,7 @@ public:
qint64 readBufferMaxSize = 0;
bool isBuffered = false;
bool hasPendingData = false;
+ bool hasPendingDatagram = false;
QTimer *connectTimer = nullptr;
diff --git a/src/network/socket/qabstractsocketengine_p.h b/src/network/socket/qabstractsocketengine_p.h
index 7b1ec85802..9ee79cebc1 100644
--- a/src/network/socket/qabstractsocketengine_p.h
+++ b/src/network/socket/qabstractsocketengine_p.h
@@ -19,8 +19,9 @@
#include <QtNetwork/private/qtnetworkglobal_p.h>
#include "QtNetwork/qhostaddress.h"
#include "QtNetwork/qabstractsocket.h"
-#include "private/qobject_p.h"
+#include <QtCore/qdeadlinetimer.h>
#include "private/qnetworkdatagram_p.h"
+#include "private/qobject_p.h"
QT_BEGIN_NAMESPACE
@@ -44,6 +45,8 @@ public:
#endif
};
+static constexpr std::chrono::seconds DefaultTimeout{30};
+
class Q_AUTOTEST_EXPORT QAbstractSocketEngine : public QObject
{
Q_OBJECT
@@ -128,11 +131,14 @@ public:
virtual int option(SocketOption option) const = 0;
virtual bool setOption(SocketOption option, int value) = 0;
- virtual bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) = 0;
- virtual bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) = 0;
+ virtual bool waitForRead(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) = 0;
+ virtual bool waitForWrite(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) = 0;
virtual bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
bool checkRead, bool checkWrite,
- int msecs = 30000, bool *timedOut = nullptr) = 0;
+ QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) = 0;
QAbstractSocket::SocketError error() const;
QString errorString() const;
diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp
index 6f93685d2a..a700023bd5 100644
--- a/src/network/socket/qhttpsocketengine.cpp
+++ b/src/network/socket/qhttpsocketengine.cpp
@@ -7,7 +7,7 @@
#include "qurl.h"
#include "private/qhttpnetworkreply_p.h"
#include "private/qiodevice_p.h"
-#include "qelapsedtimer.h"
+#include "qdeadlinetimer.h"
#include "qnetworkinterface.h"
#if !defined(QT_NO_NETWORKPROXY)
@@ -310,19 +310,16 @@ bool QHttpSocketEngine::setOption(SocketOption option, int value)
return false;
}
-bool QHttpSocketEngine::waitForRead(int msecs, bool *timedOut)
+bool QHttpSocketEngine::waitForRead(QDeadlineTimer deadline, bool *timedOut)
{
Q_D(const QHttpSocketEngine);
if (!d->socket || d->socket->state() == QAbstractSocket::UnconnectedState)
return false;
- QElapsedTimer stopWatch;
- stopWatch.start();
-
// Wait for more data if nothing is available.
if (!d->socket->bytesAvailable()) {
- if (!d->socket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
+ if (!d->socket->waitForReadyRead(deadline.remainingTime())) {
if (d->socket->state() == QAbstractSocket::UnconnectedState)
return true;
setError(d->socket->error(), d->socket->errorString());
@@ -332,11 +329,7 @@ bool QHttpSocketEngine::waitForRead(int msecs, bool *timedOut)
}
}
- // If we're not connected yet, wait until we are, or until an error
- // occurs.
- while (d->state != Connected && d->socket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
- // Loop while the protocol handshake is taking place.
- }
+ waitForProtocolHandshake(deadline);
// Report any error that may occur.
if (d->state != Connected) {
@@ -348,14 +341,14 @@ bool QHttpSocketEngine::waitForRead(int msecs, bool *timedOut)
return true;
}
-bool QHttpSocketEngine::waitForWrite(int msecs, bool *timedOut)
+bool QHttpSocketEngine::waitForWrite(QDeadlineTimer deadline, bool *timedOut)
{
Q_D(const QHttpSocketEngine);
// If we're connected, just forward the call.
if (d->state == Connected) {
if (d->socket->bytesToWrite()) {
- if (!d->socket->waitForBytesWritten(msecs)) {
+ if (!d->socket->waitForBytesWritten(deadline.remainingTime())) {
if (d->socket->error() == QAbstractSocket::SocketTimeoutError && timedOut)
*timedOut = true;
return false;
@@ -364,15 +357,7 @@ bool QHttpSocketEngine::waitForWrite(int msecs, bool *timedOut)
return true;
}
- QElapsedTimer stopWatch;
- stopWatch.start();
-
- // If we're not connected yet, wait until we are, and until bytes have
- // been received (i.e., the socket has connected, we have sent the
- // greeting, and then received the response).
- while (d->state != Connected && d->socket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
- // Loop while the protocol handshake is taking place.
- }
+ waitForProtocolHandshake(deadline);
// Report any error that may occur.
if (d->state != Connected) {
@@ -386,25 +371,37 @@ bool QHttpSocketEngine::waitForWrite(int msecs, bool *timedOut)
bool QHttpSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
bool checkRead, bool checkWrite,
- int msecs, bool *timedOut)
+ QDeadlineTimer deadline, bool *timedOut)
{
Q_UNUSED(checkRead);
if (!checkWrite) {
// Not interested in writing? Then we wait for read notifications.
- bool canRead = waitForRead(msecs, timedOut);
+ bool canRead = waitForRead(deadline, timedOut);
if (readyToRead)
*readyToRead = canRead;
return canRead;
}
// Interested in writing? Then we wait for write notifications.
- bool canWrite = waitForWrite(msecs, timedOut);
+ bool canWrite = waitForWrite(deadline, timedOut);
if (readyToWrite)
*readyToWrite = canWrite;
return canWrite;
}
+void QHttpSocketEngine::waitForProtocolHandshake(QDeadlineTimer deadline) const
+{
+ Q_D(const QHttpSocketEngine);
+
+ // If we're not connected yet, wait until we are (and until bytes have
+ // been received, i.e. the socket has connected, we have sent the
+ // greeting, and then received the response), or until an error occurs.
+ while (d->state != Connected && d->socket->waitForReadyRead(deadline.remainingTime())) {
+ // Loop while the protocol handshake is taking place.
+ }
+}
+
bool QHttpSocketEngine::isReadNotificationEnabled() const
{
Q_D(const QHttpSocketEngine);
@@ -556,16 +553,8 @@ void QHttpSocketEngine::slotSocketReadNotification()
d->authenticator.detach();
priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
- if (d->credentialsSent && priv->phase != QAuthenticatorPrivate::Phase2) {
- // Remember that (e.g.) NTLM is two-phase, so only reset when the authentication is not currently in progress.
- //407 response again means the provided username/password were invalid.
- d->authenticator = QAuthenticator(); //this is needed otherwise parseHttpResponse won't set the state, and then signal isn't emitted.
- d->authenticator.detach();
- priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
- priv->hasFailed = true;
- }
-
- priv->parseHttpResponse(d->reply->header(), true, d->proxy.hostName());
+ const auto headers = d->reply->header();
+ priv->parseHttpResponse(headers, true, d->proxy.hostName());
if (priv->phase == QAuthenticatorPrivate::Invalid) {
// problem parsing the reply
@@ -576,6 +565,29 @@ void QHttpSocketEngine::slotSocketReadNotification()
return;
}
+ if (priv->phase == QAuthenticatorPrivate::Done
+ || (priv->phase == QAuthenticatorPrivate::Start
+ && (priv->method == QAuthenticatorPrivate::Ntlm
+ || priv->method == QAuthenticatorPrivate::Negotiate))) {
+ if (priv->phase == QAuthenticatorPrivate::Start)
+ priv->phase = QAuthenticatorPrivate::Phase1;
+ bool credentialsWasSent = d->credentialsSent;
+ if (d->credentialsSent) {
+ // Remember that (e.g.) NTLM is two-phase, so only reset when the authentication is
+ // not currently in progress. 407 response again means the provided
+ // username/password were invalid.
+ d->authenticator.detach();
+ priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
+ priv->hasFailed = true;
+ d->credentialsSent = false;
+ priv->phase = QAuthenticatorPrivate::Done;
+ }
+ if ((priv->method != QAuthenticatorPrivate::Ntlm
+ && priv->method != QAuthenticatorPrivate::Negotiate)
+ || credentialsWasSent)
+ proxyAuthenticationRequired(d->proxy, &d->authenticator);
+ }
+
bool willClose;
QByteArray proxyConnectionHeader = d->reply->headerField("Proxy-Connection");
// Although most proxies use the unofficial Proxy-Connection header, the Connection header
@@ -603,10 +615,8 @@ void QHttpSocketEngine::slotSocketReadNotification()
d->reply = new QHttpNetworkReply(QUrl(), this);
}
- if (priv->phase == QAuthenticatorPrivate::Done)
- proxyAuthenticationRequired(d->proxy, &d->authenticator);
- // priv->phase will get reset to QAuthenticatorPrivate::Start if the authenticator got modified in the signal above.
if (priv->phase == QAuthenticatorPrivate::Done) {
+ d->authenticator = QAuthenticator();
setError(QAbstractSocket::ProxyAuthenticationRequiredError, tr("Authentication required"));
d->socket->disconnectFromHost();
} else {
diff --git a/src/network/socket/qhttpsocketengine_p.h b/src/network/socket/qhttpsocketengine_p.h
index 242f11122f..7926abf513 100644
--- a/src/network/socket/qhttpsocketengine_p.h
+++ b/src/network/socket/qhttpsocketengine_p.h
@@ -92,11 +92,16 @@ public:
int option(SocketOption option) const override;
bool setOption(SocketOption option, int value) override;
- bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) override;
- bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) override;
+ bool waitForRead(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) override;
+ bool waitForWrite(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) override;
bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
bool checkRead, bool checkWrite,
- int msecs = 30000, bool *timedOut = nullptr) override;
+ QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) override;
+
+ void waitForProtocolHandshake(QDeadlineTimer deadline) const;
bool isReadNotificationEnabled() const override;
void setReadNotificationEnabled(bool enable) override;
diff --git a/src/network/socket/qlocalserver.cpp b/src/network/socket/qlocalserver.cpp
index d96f540148..5ef2db6b94 100644
--- a/src/network/socket/qlocalserver.cpp
+++ b/src/network/socket/qlocalserver.cpp
@@ -265,9 +265,27 @@ bool QLocalServer::hasPendingConnections() const
*/
void QLocalServer::incomingConnection(quintptr socketDescriptor)
{
- Q_D(QLocalServer);
QLocalSocket *socket = new QLocalSocket(this);
socket->setSocketDescriptor(socketDescriptor);
+ addPendingConnection(socket);
+}
+
+/*!
+ This function is called by QLocalServer::incomingConnection()
+ to add the \a socket to the list of pending incoming connections.
+
+ \note Don't forget to call this member from reimplemented
+ incomingConnection() if you do not want to break the
+ Pending Connections mechanism. This function emits the
+ pendingConnectionAvailable() signal after the socket has been
+ added.
+
+ \sa incomingConnection(), pendingConnectionAvailable()
+ \since 6.8
+*/
+void QLocalServer::addPendingConnection(QLocalSocket *socket)
+{
+ Q_D(QLocalServer);
d->pendingConnections.enqueue(socket);
emit newConnection();
}
diff --git a/src/network/socket/qlocalserver.h b/src/network/socket/qlocalserver.h
index 81073450e2..685253e8be 100644
--- a/src/network/socket/qlocalserver.h
+++ b/src/network/socket/qlocalserver.h
@@ -68,6 +68,7 @@ public:
protected:
virtual void incomingConnection(quintptr socketDescriptor);
+ void addPendingConnection(QLocalSocket *socket);
private:
Q_DISABLE_COPY(QLocalServer)
diff --git a/src/network/socket/qlocalserver_unix.cpp b/src/network/socket/qlocalserver_unix.cpp
index dcd001a263..9aa9a5b86f 100644
--- a/src/network/socket/qlocalserver_unix.cpp
+++ b/src/network/socket/qlocalserver_unix.cpp
@@ -279,8 +279,7 @@ void QLocalServerPrivate::_q_onNewConnection()
void QLocalServerPrivate::waitForNewConnection(int msec, bool *timedOut)
{
pollfd pfd = qt_make_pollfd(listenSocket, POLLIN);
-
- switch (qt_poll_msecs(&pfd, 1, msec)) {
+ switch (qt_safe_poll(&pfd, 1, QDeadlineTimer(msec))) {
case 0:
if (timedOut)
*timedOut = true;
diff --git a/src/network/socket/qlocalsocket_unix.cpp b/src/network/socket/qlocalsocket_unix.cpp
index 626d46d7bf..af0dc988af 100644
--- a/src/network/socket/qlocalsocket_unix.cpp
+++ b/src/network/socket/qlocalsocket_unix.cpp
@@ -13,16 +13,17 @@
#include <errno.h>
#include <qdir.h>
+#include <qdeadlinetimer.h>
#include <qdebug.h>
-#include <qelapsedtimer.h>
#include <qstringconverter.h>
#ifdef Q_OS_VXWORKS
# include <selectLib.h>
#endif
-#define QT_CONNECT_TIMEOUT 30000
+using namespace std::chrono_literals;
+#define QT_CONNECT_TIMEOUT 30000
QT_BEGIN_NAMESPACE
@@ -585,21 +586,20 @@ bool QLocalSocket::waitForConnected(int msec)
if (state() != ConnectingState)
return (state() == ConnectedState);
- QElapsedTimer timer;
- timer.start();
-
pollfd pfd = qt_make_pollfd(d->connectingSocket, POLLIN);
- do {
- const int timeout = (msec > 0) ? qMax(msec - timer.elapsed(), Q_INT64_C(0)) : msec;
- const int result = qt_poll_msecs(&pfd, 1, timeout);
+ QDeadlineTimer deadline{msec};
+ auto remainingTime = deadline.remainingTimeAsDuration();
+ do {
+ const int result = qt_safe_poll(&pfd, 1, deadline);
if (result == -1)
d->setErrorAndEmit(QLocalSocket::UnknownSocketError,
"QLocalSocket::waitForConnected"_L1);
else if (result > 0)
d->_q_connectToSocket();
- } while (state() == ConnectingState && !timer.hasExpired(msec));
+ } while (state() == ConnectingState
+ && (remainingTime = deadline.remainingTimeAsDuration()) > 0ns);
return (state() == ConnectedState);
}
diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp
index e2726be781..4c8b3ebf3f 100644
--- a/src/network/socket/qnativesocketengine.cpp
+++ b/src/network/socket/qnativesocketengine.cpp
@@ -948,23 +948,23 @@ void QNativeSocketEngine::close()
d->peerAddress.clear();
d->inboundStreamCount = d->outboundStreamCount = 0;
if (d->readNotifier) {
- qDeleteInEventHandler(d->readNotifier);
+ delete d->readNotifier;
d->readNotifier = nullptr;
}
if (d->writeNotifier) {
- qDeleteInEventHandler(d->writeNotifier);
+ delete d->writeNotifier;
d->writeNotifier = nullptr;
}
if (d->exceptNotifier) {
- qDeleteInEventHandler(d->exceptNotifier);
+ delete d->exceptNotifier;
d->exceptNotifier = nullptr;
}
}
/*!
- Waits for \a msecs milliseconds or until the socket is ready for
- reading. If \a timedOut is not \nullptr and \a msecs milliseconds
- have passed, the value of \a timedOut is set to true.
+ Waits until \a deadline has expired or until the socket is ready for
+ reading. If \a timedOut is not \nullptr and \a deadline has expired,
+ the value of \a timedOut is set to true.
Returns \c true if data is available for reading; otherwise returns
false.
@@ -976,7 +976,7 @@ void QNativeSocketEngine::close()
is to create a QSocketNotifier, passing the socket descriptor
returned by socketDescriptor() to its constructor.
*/
-bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut)
+bool QNativeSocketEngine::waitForRead(QDeadlineTimer deadline, bool *timedOut)
{
Q_D(const QNativeSocketEngine);
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForRead(), false);
@@ -986,7 +986,7 @@ bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut)
if (timedOut)
*timedOut = false;
- int ret = d->nativeSelect(msecs, true);
+ int ret = d->nativeSelect(deadline, true);
if (ret == 0) {
if (timedOut)
*timedOut = true;
@@ -1002,9 +1002,9 @@ bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut)
}
/*!
- Waits for \a msecs milliseconds or until the socket is ready for
- writing. If \a timedOut is not \nullptr and \a msecs milliseconds
- have passed, the value of \a timedOut is set to true.
+ Waits until \a deadline has expired or until the socket is ready for
+ writing. If \a timedOut is not \nullptr and \a deadline has expired,
+ the value of \a timedOut is set to true.
Returns \c true if data is available for writing; otherwise returns
false.
@@ -1016,7 +1016,7 @@ bool QNativeSocketEngine::waitForRead(int msecs, bool *timedOut)
is to create a QSocketNotifier, passing the socket descriptor
returned by socketDescriptor() to its constructor.
*/
-bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut)
+bool QNativeSocketEngine::waitForWrite(QDeadlineTimer deadline, bool *timedOut)
{
Q_D(QNativeSocketEngine);
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForWrite(), false);
@@ -1026,7 +1026,7 @@ bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut)
if (timedOut)
*timedOut = false;
- int ret = d->nativeSelect(msecs, false);
+ int ret = d->nativeSelect(deadline, false);
// On Windows, the socket is in connected state if a call to
// select(writable) is successful. In this case we should not
// issue a second call to WSAConnect()
@@ -1074,14 +1074,14 @@ bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut)
bool QNativeSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
bool checkRead, bool checkWrite,
- int msecs, bool *timedOut)
+ QDeadlineTimer deadline, bool *timedOut)
{
Q_D(QNativeSocketEngine);
Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::waitForReadOrWrite(), false);
Q_CHECK_NOT_STATE(QNativeSocketEngine::waitForReadOrWrite(),
QAbstractSocket::UnconnectedState, false);
- int ret = d->nativeSelect(msecs, checkRead, checkWrite, readyToRead, readyToWrite);
+ int ret = d->nativeSelect(deadline, checkRead, checkWrite, readyToRead, readyToWrite);
// On Windows, the socket is in connected state if a call to
// select(writable) is successful. In this case we should not
// issue a second call to WSAConnect()
diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h
index 422e7da8f2..4c185b7a4a 100644
--- a/src/network/socket/qnativesocketengine_p.h
+++ b/src/network/socket/qnativesocketengine_p.h
@@ -20,8 +20,14 @@
#include "QtNetwork/qhostaddress.h"
#include "QtNetwork/qnetworkinterface.h"
#include "private/qabstractsocketengine_p.h"
+#include "qplatformdefs.h"
+
#ifndef Q_OS_WIN
-# include "qplatformdefs.h"
+# include <netinet/in.h>
+#else
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# include <mswsock.h>
#endif
QT_BEGIN_NAMESPACE
@@ -35,11 +41,57 @@ namespace {
namespace SetSALen {
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 *sa, typename std::enable_if<(&T::sin_len, true), QT_SOCKLEN_T>::type len)
+ { sa->sin_len = 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 *, ...) {}
}
+
+inline QT_SOCKLEN_T setSockaddr(sockaddr_in *sin, const QHostAddress &addr, quint16 port = 0)
+{
+ *sin = {};
+ SetSALen::set(sin, sizeof(*sin));
+ sin->sin_family = AF_INET;
+ sin->sin_port = htons(port);
+ sin->sin_addr.s_addr = htonl(addr.toIPv4Address());
+ return sizeof(*sin);
+}
+
+inline QT_SOCKLEN_T setSockaddr(sockaddr_in6 *sin6, const QHostAddress &addr, quint16 port = 0)
+{
+ *sin6 = {};
+ SetSALen::set(sin6, sizeof(*sin6));
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = htons(port);
+ memcpy(sin6->sin6_addr.s6_addr, addr.toIPv6Address().c, sizeof(sin6->sin6_addr));
+#if QT_CONFIG(networkinterface)
+ sin6->sin6_scope_id = QNetworkInterface::interfaceIndexFromName(addr.scopeId());
+#else
+ // it had better be a number then, if it is not empty
+ sin6->sin6_scope_id = addr.scopeId().toUInt();
+#endif
+ return sizeof(*sin6);
+}
+
+inline QT_SOCKLEN_T setSockaddr(sockaddr *sa, const QHostAddress &addr, quint16 port = 0)
+{
+ switch (addr.protocol()) {
+ case QHostAddress::IPv4Protocol:
+ return setSockaddr(reinterpret_cast<sockaddr_in *>(sa), addr, port);
+
+ case QHostAddress::IPv6Protocol:
+ case QHostAddress::AnyIPProtocol:
+ return setSockaddr(reinterpret_cast<sockaddr_in6 *>(sa), addr, port);
+
+ case QHostAddress::UnknownNetworkLayerProtocol:
+ break;
+ }
+ *sa = {};
+ sa->sa_family = AF_UNSPEC;
+ return 0;
}
+} // unnamed namespace
class QNativeSocketEnginePrivate;
#ifndef QT_NO_NETWORKINTERFACE
@@ -102,11 +154,14 @@ public:
int option(SocketOption option) const override;
bool setOption(SocketOption option, int value) override;
- bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) override;
- bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) override;
+ bool waitForRead(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) override;
+ bool waitForWrite(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) override;
bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
bool checkRead, bool checkWrite,
- int msecs = 30000, bool *timedOut = nullptr) override;
+ QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) override;
bool isReadNotificationEnabled() const override;
void setReadNotificationEnabled(bool enable) override;
diff --git a/src/network/socket/qnativesocketengine_p_p.h b/src/network/socket/qnativesocketengine_p_p.h
index 013b62ad29..189a4327fd 100644
--- a/src/network/socket/qnativesocketengine_p_p.h
+++ b/src/network/socket/qnativesocketengine_p_p.h
@@ -146,8 +146,8 @@ public:
qint64 nativeSendDatagram(const char *data, qint64 length, const QIpPacketHeader &header);
qint64 nativeRead(char *data, qint64 maxLength);
qint64 nativeWrite(const char *data, qint64 length);
- int nativeSelect(int timeout, bool selectForRead) const;
- int nativeSelect(int timeout, bool checkRead, bool checkWrite,
+ int nativeSelect(QDeadlineTimer deadline, bool selectForRead) const;
+ int nativeSelect(QDeadlineTimer deadline, bool checkRead, bool checkWrite,
bool *selectForRead, bool *selectForWrite) const;
void nativeClose();
@@ -155,39 +155,31 @@ 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.
The address \a is converted to IPv6 if the current socket protocol is also IPv6.
*/
void setPortAndAddress(quint16 port, const QHostAddress &address, qt_sockaddr *aa, QT_SOCKLEN_T *sockAddrSize)
{
- if (address.protocol() == QAbstractSocket::IPv6Protocol
- || address.protocol() == QAbstractSocket::AnyIPProtocol
- || socketProtocol == QAbstractSocket::IPv6Protocol
- || 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));
+ switch (socketProtocol) {
+ case QHostAddress::IPv6Protocol:
+ case QHostAddress::AnyIPProtocol:
+ // force to IPv6
+ setSockaddr(&aa->a6, address, port);
*sockAddrSize = sizeof(sockaddr_in6);
- SetSALen::set(&aa->a, sizeof(sockaddr_in6));
- } else {
- memset(&aa->a, 0, sizeof(sockaddr_in));
- aa->a4.sin_family = AF_INET;
- aa->a4.sin_port = htons(port);
- aa->a4.sin_addr.s_addr = htonl(address.toIPv4Address());
+ return;
+
+ case QHostAddress::IPv4Protocol:
+ // force to IPv4
+ setSockaddr(&aa->a4, address, port);
*sockAddrSize = sizeof(sockaddr_in);
- SetSALen::set(&aa->a, sizeof(sockaddr_in));
+ return;
+
+ case QHostAddress::UnknownNetworkLayerProtocol:
+ // don't force
+ break;
}
+ *sockAddrSize = setSockaddr(&aa->a, address, port);
}
};
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index dd3c57de1e..b6df412253 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -5,9 +5,9 @@
//#define QNATIVESOCKETENGINE_DEBUG
#include "qnativesocketengine_p_p.h"
#include "private/qnet_unix_p.h"
+#include "qdeadlinetimer.h"
#include "qiodevice.h"
#include "qhostaddress.h"
-#include "qelapsedtimer.h"
#include "qvarlengtharray.h"
#include "qnetworkinterface.h"
#include "qendian.h"
@@ -17,15 +17,6 @@
#include <time.h>
#include <errno.h>
#include <fcntl.h>
-#ifndef QT_NO_IPV6IFNAME
-#include <net/if.h>
-#endif
-#ifdef QT_LINUXBASE
-#include <arpa/inet.h>
-#endif
-#ifdef Q_OS_BSD4
-#include <net/if_dl.h>
-#endif
#ifdef Q_OS_INTEGRITY
#include <sys/uio.h>
#endif
@@ -40,6 +31,9 @@
#include <sys/socket.h>
#include <netinet/sctp.h>
#endif
+#ifdef Q_OS_BSD4
+# include <net/if_dl.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -442,6 +436,7 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16
case EFAULT:
case ENOTSOCK:
socketState = QAbstractSocket::UnconnectedState;
+ break;
default:
break;
}
@@ -799,7 +794,7 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const
// Peek 1 bytes into the next message.
ssize_t readBytes;
char c;
- EINTR_LOOP(readBytes, ::recv(socketDescriptor, &c, 1, MSG_PEEK));
+ QT_EINTR_LOOP(readBytes, ::recv(socketDescriptor, &c, 1, MSG_PEEK));
// If there's no error, or if our buffer was too small, there must be a
// pending datagram.
@@ -818,7 +813,7 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const
#ifdef Q_OS_LINUX
// Linux can return the actual datagram size if we use MSG_TRUNC
char c;
- EINTR_LOOP(recvResult, ::recv(socketDescriptor, &c, 1, MSG_PEEK | MSG_TRUNC));
+ QT_EINTR_LOOP(recvResult, ::recv(socketDescriptor, &c, 1, MSG_PEEK | MSG_TRUNC));
#elif defined(SO_NREAD)
// macOS can return the actual datagram size if we use SO_NREAD
int value;
@@ -1281,6 +1276,9 @@ qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len)
setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString);
q->close();
break;
+#if EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK:
+#endif
case EAGAIN:
writtenBytes = 0;
break;
@@ -1350,16 +1348,17 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize)
return qint64(r);
}
-int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const
+int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool selectForRead) const
{
bool dummy;
- return nativeSelect(timeout, selectForRead, !selectForRead, &dummy, &dummy);
+ return nativeSelect(deadline, selectForRead, !selectForRead, &dummy, &dummy);
}
#ifndef Q_OS_WASM
-int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite,
- bool *selectForRead, bool *selectForWrite) const
+int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool checkRead,
+ bool checkWrite, bool *selectForRead,
+ bool *selectForWrite) const
{
pollfd pfd = qt_make_pollfd(socketDescriptor, 0);
@@ -1369,7 +1368,7 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c
if (checkWrite)
pfd.events |= POLLOUT;
- const int ret = qt_poll_msecs(&pfd, 1, timeout);
+ const int ret = qt_safe_poll(&pfd, 1, deadline);
if (ret <= 0)
return ret;
@@ -1390,13 +1389,16 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c
#else
-int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite,
- bool *selectForRead, bool *selectForWrite) const
+int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool checkRead,
+ bool checkWrite, bool *selectForRead,
+ bool *selectForWrite) const
{
*selectForRead = checkRead;
*selectForWrite = checkWrite;
bool socketDisconnect = false;
- QEventDispatcherWasm::socketSelect(timeout, socketDescriptor, checkRead, checkWrite,selectForRead, selectForWrite, &socketDisconnect);
+ QEventDispatcherWasm::socketSelect(deadline.remainingTime(), socketDescriptor, checkRead,
+ checkWrite, selectForRead, selectForWrite,
+ &socketDisconnect);
// The disconnect/close handling code in QAbstractsScket::canReadNotification()
// does not detect remote disconnect properly; do that here as a workardound.
diff --git a/src/network/socket/qnativesocketengine_win.cpp b/src/network/socket/qnativesocketengine_win.cpp
index d578e5230f..6525f46e30 100644
--- a/src/network/socket/qnativesocketengine_win.cpp
+++ b/src/network/socket/qnativesocketengine_win.cpp
@@ -2,9 +2,6 @@
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-// Prevent windows system header files from defining min/max as macros.
-#define NOMINMAX 1
-
#include <winsock2.h>
#include <ws2tcpip.h>
@@ -19,6 +16,7 @@
#include <qvarlengtharray.h>
#include <algorithm>
+#include <chrono>
//#define QNATIVESOCKETENGINE_DEBUG
#if defined(QNATIVESOCKETENGINE_DEBUG)
@@ -1431,7 +1429,18 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxLength)
return ret;
}
-int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const
+inline timeval durationToTimeval(std::chrono::nanoseconds dur) noexcept
+{
+ using namespace std::chrono;
+ const auto secs = duration_cast<seconds>(dur);
+ const auto frac = duration_cast<microseconds>(dur - secs);
+ struct timeval tval;
+ tval.tv_sec = secs.count();
+ tval.tv_usec = frac.count();
+ return tval;
+}
+
+int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline, bool selectForRead) const
{
bool readEnabled = selectForRead && readNotifier && readNotifier->isEnabled();
if (readEnabled)
@@ -1445,12 +1454,10 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co
fds.fd_count = 1;
fds.fd_array[0] = (SOCKET)socketDescriptor;
- struct timeval tv;
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
+ struct timeval tv = durationToTimeval(deadline.remainingTimeAsDuration());
if (selectForRead) {
- ret = select(0, &fds, 0, 0, timeout < 0 ? 0 : &tv);
+ ret = select(0, &fds, 0, 0, &tv);
} else {
// select for write
@@ -1459,7 +1466,7 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co
FD_ZERO(&fdexception);
FD_SET((SOCKET)socketDescriptor, &fdexception);
- ret = select(0, 0, &fds, &fdexception, timeout < 0 ? 0 : &tv);
+ ret = select(0, 0, &fds, &fdexception, &tv);
// ... but if it is actually set, pretend it did not happen
if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception))
@@ -1472,7 +1479,7 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co
return ret;
}
-int QNativeSocketEnginePrivate::nativeSelect(int timeout,
+int QNativeSocketEnginePrivate::nativeSelect(QDeadlineTimer deadline,
bool checkRead, bool checkWrite,
bool *selectForRead, bool *selectForWrite) const
{
@@ -1501,11 +1508,9 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout,
FD_SET((SOCKET)socketDescriptor, &fdexception);
}
- struct timeval tv;
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
+ struct timeval tv = durationToTimeval(deadline.remainingTimeAsDuration());
- ret = select(socketDescriptor + 1, &fdread, &fdwrite, &fdexception, timeout < 0 ? 0 : &tv);
+ ret = select(socketDescriptor + 1, &fdread, &fdwrite, &fdexception, &tv);
//... but if it is actually set, pretend it did not happen
if (ret > 0 && FD_ISSET((SOCKET)socketDescriptor, &fdexception))
diff --git a/src/network/socket/qnet_unix_p.h b/src/network/socket/qnet_unix_p.h
index c72e5745b0..a172a14a10 100644
--- a/src/network/socket/qnet_unix_p.h
+++ b/src/network/socket/qnet_unix_p.h
@@ -108,7 +108,7 @@ static inline int qt_safe_connect(int sockfd, const struct sockaddr *addr, QT_SO
{
int ret;
// Solaris e.g. expects a non-const 2nd parameter
- EINTR_LOOP(ret, QT_SOCKET_CONNECT(sockfd, const_cast<struct sockaddr *>(addr), addrlen));
+ QT_EINTR_LOOP(ret, QT_SOCKET_CONNECT(sockfd, const_cast<struct sockaddr *>(addr), addrlen));
return ret;
}
#undef QT_SOCKET_CONNECT
@@ -124,15 +124,10 @@ static inline int qt_safe_connect(int sockfd, const struct sockaddr *addr, QT_SO
# undef listen
#endif
-// VxWorks' headers specify 'int' instead of '...' for the 3rd ioctl() parameter.
template <typename T>
static inline int qt_safe_ioctl(int sockfd, unsigned long request, T arg)
{
-#ifdef Q_OS_VXWORKS
- return ::ioctl(sockfd, request, (int) arg);
-#else
return ::ioctl(sockfd, request, arg);
-#endif
}
static inline int qt_safe_sendmsg(int sockfd, const struct msghdr *msg, int flags)
@@ -144,7 +139,7 @@ static inline int qt_safe_sendmsg(int sockfd, const struct msghdr *msg, int flag
#endif
int ret;
- EINTR_LOOP(ret, ::sendmsg(sockfd, msg, flags));
+ QT_EINTR_LOOP(ret, ::sendmsg(sockfd, msg, flags));
return ret;
}
@@ -152,7 +147,7 @@ static inline int qt_safe_recvmsg(int sockfd, struct msghdr *msg, int flags)
{
int ret;
- EINTR_LOOP(ret, ::recvmsg(sockfd, msg, flags));
+ QT_EINTR_LOOP(ret, ::recvmsg(sockfd, msg, flags));
return ret;
}
diff --git a/src/network/socket/qsctpsocket.cpp b/src/network/socket/qsctpsocket.cpp
index 27c6fc930c..868c9e3785 100644
--- a/src/network/socket/qsctpsocket.cpp
+++ b/src/network/socket/qsctpsocket.cpp
@@ -83,7 +83,6 @@
#include "qsctpsocket_p.h"
#include "qabstractsocketengine_p.h"
-#include "private/qbytearray_p.h"
#ifdef QSCTPSOCKET_DEBUG
#include <qdebug.h>
@@ -133,7 +132,7 @@ bool QSctpSocketPrivate::canReadNotification()
bytesToRead = 4096;
}
- Q_ASSERT((datagramSize + qsizetype(bytesToRead)) < MaxByteArraySize);
+ Q_ASSERT((datagramSize + qsizetype(bytesToRead)) < QByteArray::max_size());
incomingDatagram.resize(datagramSize + int(bytesToRead));
#if defined (QSCTPSOCKET_DEBUG)
diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp
index 2669614f3a..b0fdc63d66 100644
--- a/src/network/socket/qsocks5socketengine.cpp
+++ b/src/network/socket/qsocks5socketengine.cpp
@@ -9,6 +9,7 @@
#include "qdebug.h"
#include "qhash.h"
#include "qqueue.h"
+#include "qdeadlinetimer.h"
#include "qelapsedtimer.h"
#include "qmutex.h"
#include "qthread.h"
@@ -20,18 +21,21 @@
#include <qendian.h>
#include <qnetworkinterface.h>
+#include <QtCore/qpointer.h>
+
#include <memory>
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
+using namespace std::chrono_literals;
static const int MaxWriteBufferSize = 128*1024;
//#define QSOCKS5SOCKETLAYER_DEBUG
#define MAX_DATA_DUMP 256
-#define SOCKS5_BLOCKING_BIND_TIMEOUT 5000
+static constexpr auto Socks5BlockingBindTimeout = 5s;
#define Q_INIT_CHECK(returnValue) do { \
if (!d->data) { \
@@ -318,7 +322,6 @@ void QSocks5BindStore::add(qintptr socketDescriptor, QSocks5BindData *bindData)
bindData->timeStamp.start();
store.insert(socketDescriptor, bindData);
- using namespace std::chrono_literals;
// start sweep timer if not started
if (sweepTimerId == -1)
sweepTimerId = startTimer(1min);
@@ -1327,11 +1330,8 @@ bool QSocks5SocketEngine::bind(const QHostAddress &addr, quint16 port)
return false;
}
- int msecs = SOCKS5_BLOCKING_BIND_TIMEOUT;
- QElapsedTimer stopWatch;
- stopWatch.start();
d->data->controlSocket->connectToHost(d->proxyInfo.hostName(), d->proxyInfo.port());
- if (!d->waitForConnected(msecs, nullptr) ||
+ if (!d->waitForConnected(QDeadlineTimer{Socks5BlockingBindTimeout}, nullptr) ||
d->data->controlSocket->state() == QAbstractSocket::UnconnectedState) {
// waitForConnected sets the error state and closes the socket
QSOCKS5_Q_DEBUG << "waitForConnected to proxy server" << d->data->controlSocket->errorString();
@@ -1422,11 +1422,9 @@ void QSocks5SocketEngine::close()
Q_D(QSocks5SocketEngine);
if (d->data && d->data->controlSocket) {
if (d->data->controlSocket->state() == QAbstractSocket::ConnectedState) {
- int msecs = 100;
- QElapsedTimer stopWatch;
- stopWatch.start();
+ QDeadlineTimer deadline(100ms);
while (!d->data->controlSocket->bytesToWrite()) {
- if (!d->data->controlSocket->waitForBytesWritten(qt_subtract_from_timeout(msecs, stopWatch.elapsed())))
+ if (!d->data->controlSocket->waitForBytesWritten(deadline.remainingTime()))
break;
}
}
@@ -1447,7 +1445,7 @@ qint64 QSocks5SocketEngine::bytesAvailable() const
#ifndef QT_NO_UDPSOCKET
else if (d->mode == QSocks5SocketEnginePrivate::UdpAssociateMode
&& !d->udpData->pendingDatagrams.isEmpty())
- return d->udpData->pendingDatagrams.first().data.size();
+ return d->udpData->pendingDatagrams.constFirst().data.size();
#endif
return 0;
}
@@ -1462,7 +1460,7 @@ qint64 QSocks5SocketEngine::read(char *data, qint64 maxlen)
//imitate remote closed
close();
setError(QAbstractSocket::RemoteHostClosedError,
- "Remote host closed connection###"_L1);
+ "Remote host closed connection"_L1);
setState(QAbstractSocket::UnconnectedState);
return -1;
} else {
@@ -1679,7 +1677,7 @@ bool QSocks5SocketEngine::setOption(SocketOption option, int value)
return false;
}
-bool QSocks5SocketEnginePrivate::waitForConnected(int msecs, bool *timedOut)
+bool QSocks5SocketEnginePrivate::waitForConnected(QDeadlineTimer deadline, bool *timedOut)
{
if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
return false;
@@ -1689,11 +1687,8 @@ bool QSocks5SocketEnginePrivate::waitForConnected(int msecs, bool *timedOut)
mode == BindMode ? BindSuccess :
UdpAssociateSuccess;
- QElapsedTimer stopWatch;
- stopWatch.start();
-
while (socks5State != wantedState) {
- if (!data->controlSocket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
+ if (!data->controlSocket->waitForReadyRead(deadline.remainingTime())) {
if (data->controlSocket->state() == QAbstractSocket::UnconnectedState)
return true;
@@ -1707,18 +1702,15 @@ bool QSocks5SocketEnginePrivate::waitForConnected(int msecs, bool *timedOut)
return true;
}
-bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut)
+bool QSocks5SocketEngine::waitForRead(QDeadlineTimer deadline, bool *timedOut)
{
Q_D(QSocks5SocketEngine);
- QSOCKS5_DEBUG << "waitForRead" << msecs;
+ QSOCKS5_DEBUG << "waitForRead" << deadline.remainingTimeAsDuration();
d->readNotificationActivated = false;
- QElapsedTimer stopWatch;
- stopWatch.start();
-
// are we connected yet?
- if (!d->waitForConnected(msecs, timedOut))
+ if (!d->waitForConnected(deadline, timedOut))
return false;
if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
return true;
@@ -1732,7 +1724,7 @@ bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut)
if (d->mode == QSocks5SocketEnginePrivate::ConnectMode ||
d->mode == QSocks5SocketEnginePrivate::BindMode) {
while (!d->readNotificationActivated) {
- if (!d->data->controlSocket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
+ if (!d->data->controlSocket->waitForReadyRead(deadline.remainingTime())) {
if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
return true;
@@ -1745,7 +1737,7 @@ bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut)
#ifndef QT_NO_UDPSOCKET
} else {
while (!d->readNotificationActivated) {
- if (!d->udpData->udpSocket->waitForReadyRead(qt_subtract_from_timeout(msecs, stopWatch.elapsed()))) {
+ if (!d->udpData->udpSocket->waitForReadyRead(deadline.remainingTime())) {
setError(d->udpData->udpSocket->error(), d->udpData->udpSocket->errorString());
if (timedOut && d->udpData->udpSocket->error() == QAbstractSocket::SocketTimeoutError)
*timedOut = true;
@@ -1764,16 +1756,13 @@ bool QSocks5SocketEngine::waitForRead(int msecs, bool *timedOut)
}
-bool QSocks5SocketEngine::waitForWrite(int msecs, bool *timedOut)
+bool QSocks5SocketEngine::waitForWrite(QDeadlineTimer deadline, bool *timedOut)
{
Q_D(QSocks5SocketEngine);
- QSOCKS5_DEBUG << "waitForWrite" << msecs;
-
- QElapsedTimer stopWatch;
- stopWatch.start();
+ QSOCKS5_DEBUG << "waitForWrite" << deadline.remainingTimeAsDuration();
// are we connected yet?
- if (!d->waitForConnected(msecs, timedOut))
+ if (!d->waitForConnected(deadline, timedOut))
return false;
if (d->data->controlSocket->state() == QAbstractSocket::UnconnectedState)
return true;
@@ -1782,27 +1771,32 @@ bool QSocks5SocketEngine::waitForWrite(int msecs, bool *timedOut)
// flush any bytes we may still have buffered in the time that we have left
if (d->data->controlSocket->bytesToWrite())
- d->data->controlSocket->waitForBytesWritten(qt_subtract_from_timeout(msecs, stopWatch.elapsed()));
- while ((msecs == -1 || stopWatch.elapsed() < msecs)
- && d->data->controlSocket->state() == QAbstractSocket::ConnectedState
- && d->data->controlSocket->bytesToWrite() >= MaxWriteBufferSize)
- d->data->controlSocket->waitForBytesWritten(qt_subtract_from_timeout(msecs, stopWatch.elapsed()));
+ d->data->controlSocket->waitForBytesWritten(deadline.remainingTime());
+
+ auto shouldWriteBytes = [&]() {
+ return d->data->controlSocket->state() == QAbstractSocket::ConnectedState
+ && d->data->controlSocket->bytesToWrite() >= MaxWriteBufferSize;
+ };
+
+ qint64 remainingTime = deadline.remainingTime();
+ for (; remainingTime > 0 && shouldWriteBytes(); remainingTime = deadline.remainingTime())
+ d->data->controlSocket->waitForBytesWritten(remainingTime);
return d->data->controlSocket->bytesToWrite() < MaxWriteBufferSize;
}
bool QSocks5SocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
bool checkRead, bool checkWrite,
- int msecs, bool *timedOut)
+ QDeadlineTimer deadline, bool *timedOut)
{
Q_UNUSED(checkRead);
if (!checkWrite) {
- bool canRead = waitForRead(msecs, timedOut);
+ bool canRead = waitForRead(deadline, timedOut);
if (readyToRead)
*readyToRead = canRead;
return canRead;
}
- bool canWrite = waitForWrite(msecs, timedOut);
+ bool canWrite = waitForWrite(deadline, timedOut);
if (readyToWrite)
*readyToWrite = canWrite;
return canWrite;
diff --git a/src/network/socket/qsocks5socketengine_p.h b/src/network/socket/qsocks5socketengine_p.h
index 790c3077cf..3a169812df 100644
--- a/src/network/socket/qsocks5socketengine_p.h
+++ b/src/network/socket/qsocks5socketengine_p.h
@@ -78,11 +78,14 @@ public:
int option(SocketOption option) const override;
bool setOption(SocketOption option, int value) override;
- bool waitForRead(int msecs = 30000, bool *timedOut = nullptr) override;
- bool waitForWrite(int msecs = 30000, bool *timedOut = nullptr) override;
+ bool waitForRead(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) override;
+ bool waitForWrite(QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) override;
bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite,
bool checkRead, bool checkWrite,
- int msecs = 30000, bool *timedOut = nullptr) override;
+ QDeadlineTimer deadline = QDeadlineTimer{DefaultTimeout},
+ bool *timedOut = nullptr) override;
bool isReadNotificationEnabled() const override;
void setReadNotificationEnabled(bool enable) override;
@@ -208,7 +211,7 @@ public:
void parseRequestMethodReply();
void parseNewConnection();
- bool waitForConnected(int msecs, bool *timedOut);
+ bool waitForConnected(QDeadlineTimer deadline, bool *timedOut);
void _q_controlSocketConnected();
void _q_controlSocketReadNotification();
diff --git a/src/network/socket/qtcpserver.cpp b/src/network/socket/qtcpserver.cpp
index eb2d757a08..a0c0f00aaa 100644
--- a/src/network/socket/qtcpserver.cpp
+++ b/src/network/socket/qtcpserver.cpp
@@ -498,7 +498,7 @@ bool QTcpServer::waitForNewConnection(int msec, bool *timedOut)
if (d->state != QAbstractSocket::ListeningState)
return false;
- if (!d->socketEngine->waitForRead(msec, timedOut)) {
+ if (!d->socketEngine->waitForRead(QDeadlineTimer(msec), timedOut)) {
d->serverSocketError = d->socketEngine->error();
d->serverSocketErrorString = d->socketEngine->errorString();
return false;
diff --git a/src/network/socket/qudpsocket.cpp b/src/network/socket/qudpsocket.cpp
index 2a7982057e..bfeea307b2 100644
--- a/src/network/socket/qudpsocket.cpp
+++ b/src/network/socket/qudpsocket.cpp
@@ -382,7 +382,7 @@ qint64 QUdpSocket::writeDatagram(const QNetworkDatagram &datagram)
if (state() == UnconnectedState)
bind();
- qint64 sent = d->socketEngine->writeDatagram(datagram.d->data,
+ qint64 sent = d->socketEngine->writeDatagram(datagram.d->data.constData(),
datagram.d->data.size(),
datagram.d->header);
d->cachedSocketDescriptor = d->socketEngine->socketDescriptor();
@@ -430,6 +430,7 @@ QNetworkDatagram QUdpSocket::receiveDatagram(qint64 maxSize)
qint64 readBytes = d->socketEngine->readDatagram(result.d->data.data(), maxSize, &result.d->header,
QAbstractSocketEngine::WantAll);
d->hasPendingData = false;
+ d->hasPendingDatagram = false;
d->socketEngine->setReadNotificationEnabled(true);
if (readBytes < 0) {
d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString());
@@ -479,6 +480,7 @@ qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *addres
}
d->hasPendingData = false;
+ d->hasPendingDatagram = false;
d->socketEngine->setReadNotificationEnabled(true);
if (readBytes < 0) {
if (readBytes == -2) {
diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp
index 7525df8c87..dfd3745d3e 100644
--- a/src/network/ssl/qssl.cpp
+++ b/src/network/ssl/qssl.cpp
@@ -256,3 +256,5 @@ Q_LOGGING_CATEGORY(lcSsl, "qt.network.ssl");
*/
QT_END_NAMESPACE
+
+#include "moc_qssl.cpp"
diff --git a/src/network/ssl/qssl.h b/src/network/ssl/qssl.h
index 3d01168172..e52b8c6361 100644
--- a/src/network/ssl/qssl.h
+++ b/src/network/ssl/qssl.h
@@ -10,21 +10,26 @@
#endif
#include <QtNetwork/qtnetworkglobal.h>
+#include <QtCore/qobjectdefs.h>
#include <QtCore/QFlags>
QT_BEGIN_NAMESPACE
namespace QSsl {
+ Q_NAMESPACE_EXPORT(Q_NETWORK_EXPORT)
+
enum KeyType {
PrivateKey,
PublicKey
};
+ Q_ENUM_NS(KeyType)
enum EncodingFormat {
Pem,
Der
};
+ Q_ENUM_NS(EncodingFormat)
enum KeyAlgorithm {
Opaque,
@@ -33,12 +38,14 @@ namespace QSsl {
Ec,
Dh,
};
+ Q_ENUM_NS(KeyAlgorithm)
enum AlternativeNameEntryType {
EmailEntry,
DnsEntry,
IpAddressEntry
};
+ Q_ENUM_NS(AlternativeNameEntryType)
enum SslProtocol {
TlsV1_0 QT_DEPRECATED_VERSION_X_6_3("Use TlsV1_2OrLater instead."),
@@ -61,6 +68,7 @@ namespace QSsl {
UnknownProtocol = -1
};
+ Q_ENUM_NS(SslProtocol)
enum SslOption {
SslOptionDisableEmptyFragments = 0x01,
@@ -72,6 +80,7 @@ namespace QSsl {
SslOptionDisableSessionPersistence = 0x40,
SslOptionDisableServerCipherPreference = 0x80
};
+ Q_ENUM_NS(SslOption)
Q_DECLARE_FLAGS(SslOptions, SslOption)
enum class AlertLevel {
@@ -79,6 +88,7 @@ namespace QSsl {
Fatal,
Unknown
};
+ Q_ENUM_NS(AlertLevel)
enum class AlertType {
CloseNotify,
@@ -116,6 +126,7 @@ namespace QSsl {
NoApplicationProtocol = 120,
UnknownAlertMessage = 255
};
+ Q_ENUM_NS(AlertType)
enum class ImplementedClass
{
@@ -127,6 +138,7 @@ namespace QSsl {
Dtls,
DtlsCookie
};
+ Q_ENUM_NS(ImplementedClass)
enum class SupportedFeature
{
@@ -138,6 +150,7 @@ namespace QSsl {
SessionTicket,
Alerts
};
+ Q_ENUM_NS(SupportedFeature)
}
Q_DECLARE_OPERATORS_FOR_FLAGS(QSsl::SslOptions)
diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp
index 0f851ec7c9..9878c603b6 100644
--- a/src/network/ssl/qsslcertificate.cpp
+++ b/src/network/ssl/qsslcertificate.cpp
@@ -110,7 +110,7 @@
#endif
#include <QtCore/qdir.h>
-#include <QtCore/qdiriterator.h>
+#include <QtCore/qdirlisting.h>
#include <QtCore/qfile.h>
QT_BEGIN_NAMESPACE
@@ -186,7 +186,7 @@ QSslCertificate::QSslCertificate(const QByteArray &data, QSsl::EncodingFormat fo
return;
}
- QList<QSslCertificate> certs = X509Reader(data, 1);
+ const QList<QSslCertificate> certs = X509Reader(data, 1);
if (!certs.isEmpty())
d = certs.first().d;
}
@@ -624,7 +624,7 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
QString sourcePath = QDir::fromNativeSeparators(path);
// Find the path without the filename
- QString pathPrefix = sourcePath.left(sourcePath.lastIndexOf(u'/'));
+ QStringView pathPrefix = QStringView(sourcePath).left(sourcePath.lastIndexOf(u'/'));
// Check if the path contains any special chars
int pos = -1;
@@ -647,7 +647,7 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
if (lastIndexOfSlash != -1)
pathPrefix = pathPrefix.left(lastIndexOfSlash);
else
- pathPrefix.clear();
+ pathPrefix = {};
} else {
// Check if the path is a file.
if (QFileInfo(sourcePath).isFile()) {
@@ -664,10 +664,12 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
// Special case - if the prefix ends up being nothing, use "." instead.
int startIndex = 0;
if (pathPrefix.isEmpty()) {
- pathPrefix = "."_L1;
+ pathPrefix = u".";
startIndex = 2;
}
+ const QString pathPrefixString = pathPrefix.toString();
+
// The path can be a file or directory.
QList<QSslCertificate> certs;
@@ -678,9 +680,12 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
QRegularExpression pattern(QRegularExpression::anchoredPattern(sourcePath));
#endif
- QDirIterator it(pathPrefix, QDir::Files, QDirIterator::FollowSymlinks | QDirIterator::Subdirectories);
- while (it.hasNext()) {
- QString filePath = startIndex == 0 ? it.next() : it.next().mid(startIndex);
+ using F = QDirListing::IteratorFlag;
+ constexpr auto iterFlags = F::FollowSymlinks | F::Recursive;
+ for (const auto &dirEntry : QDirListing(pathPrefixString, QDir::Files, iterFlags)) {
+ QString filePath = dirEntry.filePath();
+ if (startIndex > 0)
+ filePath.remove(0, startIndex);
#if QT_CONFIG(regularexpression)
if (!pattern.match(filePath).hasMatch())
@@ -878,7 +883,7 @@ static const char *const certificate_blacklist[] = {
bool QSslCertificatePrivate::isBlacklisted(const QSslCertificate &certificate)
{
for (int a = 0; certificate_blacklist[a] != nullptr; a++) {
- QString blacklistedCommonName = QString::fromUtf8(certificate_blacklist[(a+1)]);
+ auto blacklistedCommonName = QAnyStringView(QUtf8StringView(certificate_blacklist[(a+1)]));
if (certificate.serialNumber() == certificate_blacklist[a++] &&
(certificate.subjectInfo(QSslCertificate::CommonName).contains(blacklistedCommonName) ||
certificate.issuerInfo(QSslCertificate::CommonName).contains(blacklistedCommonName)))
@@ -889,19 +894,18 @@ bool QSslCertificatePrivate::isBlacklisted(const QSslCertificate &certificate)
QByteArray QSslCertificatePrivate::subjectInfoToString(QSslCertificate::SubjectInfo info)
{
- QByteArray str;
switch (info) {
- case QSslCertificate::Organization: str = QByteArray("O"); break;
- case QSslCertificate::CommonName: str = QByteArray("CN"); break;
- case QSslCertificate::LocalityName: str = QByteArray("L"); break;
- case QSslCertificate::OrganizationalUnitName: str = QByteArray("OU"); break;
- case QSslCertificate::CountryName: str = QByteArray("C"); break;
- case QSslCertificate::StateOrProvinceName: str = QByteArray("ST"); break;
- case QSslCertificate::DistinguishedNameQualifier: str = QByteArray("dnQualifier"); break;
- case QSslCertificate::SerialNumber: str = QByteArray("serialNumber"); break;
- case QSslCertificate::EmailAddress: str = QByteArray("emailAddress"); break;
+ case QSslCertificate::Organization: return "O"_ba;
+ case QSslCertificate::CommonName: return "CN"_ba;
+ case QSslCertificate::LocalityName: return"L"_ba;
+ case QSslCertificate::OrganizationalUnitName: return "OU"_ba;
+ case QSslCertificate::CountryName: return "C"_ba;
+ case QSslCertificate::StateOrProvinceName: return "ST"_ba;
+ case QSslCertificate::DistinguishedNameQualifier: return "dnQualifier"_ba;
+ case QSslCertificate::SerialNumber: return "serialNumber"_ba;
+ case QSslCertificate::EmailAddress: return "emailAddress"_ba;
}
- return str;
+ return QByteArray();
}
/*!
@@ -918,13 +922,13 @@ QString QSslCertificate::issuerDisplayName() const
QStringList names;
names = issuerInfo(QSslCertificate::CommonName);
if (!names.isEmpty())
- return names.first();
+ return names.constFirst();
names = issuerInfo(QSslCertificate::Organization);
if (!names.isEmpty())
- return names.first();
+ return names.constFirst();
names = issuerInfo(QSslCertificate::OrganizationalUnitName);
if (!names.isEmpty())
- return names.first();
+ return names.constFirst();
return QString();
}
@@ -943,13 +947,13 @@ QString QSslCertificate::subjectDisplayName() const
QStringList names;
names = subjectInfo(QSslCertificate::CommonName);
if (!names.isEmpty())
- return names.first();
+ return names.constFirst();
names = subjectInfo(QSslCertificate::Organization);
if (!names.isEmpty())
- return names.first();
+ return names.constFirst();
names = subjectInfo(QSslCertificate::OrganizationalUnitName);
if (!names.isEmpty())
- return names.first();
+ return names.constFirst();
return QString();
}
@@ -974,15 +978,15 @@ QDebug operator<<(QDebug debug, const QSslCertificate &certificate)
QDebugStateSaver saver(debug);
debug.resetFormat().nospace();
debug << "QSslCertificate("
- << certificate.version()
- << ", " << certificate.serialNumber()
- << ", " << certificate.digest().toBase64()
- << ", " << certificate.issuerDisplayName()
- << ", " << certificate.subjectDisplayName()
- << ", " << certificate.subjectAlternativeNames()
+ << "Version=" << certificate.version()
+ << ", SerialNumber=" << certificate.serialNumber()
+ << ", Digest=" << certificate.digest().toBase64()
+ << ", Issuer=" << certificate.issuerDisplayName()
+ << ", Subject=" << certificate.subjectDisplayName()
+ << ", AlternativeSubjectNames=" << certificate.subjectAlternativeNames()
#if QT_CONFIG(datestring)
- << ", " << certificate.effectiveDate()
- << ", " << certificate.expiryDate()
+ << ", EffectiveDate=" << certificate.effectiveDate()
+ << ", ExpiryDate=" << certificate.expiryDate()
#endif
<< ')';
return debug;
diff --git a/src/network/ssl/qsslcertificate_p.h b/src/network/ssl/qsslcertificate_p.h
index 02cf002460..ca59abae82 100644
--- a/src/network/ssl/qsslcertificate_p.h
+++ b/src/network/ssl/qsslcertificate_p.h
@@ -35,8 +35,8 @@ public:
~QSslCertificatePrivate();
QList<QSslCertificateExtension> extensions() const;
- Q_NETWORK_PRIVATE_EXPORT static bool isBlacklisted(const QSslCertificate &certificate);
- Q_NETWORK_PRIVATE_EXPORT static QByteArray subjectInfoToString(QSslCertificate::SubjectInfo info);
+ Q_NETWORK_EXPORT static bool isBlacklisted(const QSslCertificate &certificate);
+ Q_NETWORK_EXPORT static QByteArray subjectInfoToString(QSslCertificate::SubjectInfo info);
QAtomicInt ref;
std::unique_ptr<QTlsPrivate::X509Certificate> backend;
diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp
index 63eaa6d092..fd308d7037 100644
--- a/src/network/ssl/qsslconfiguration.cpp
+++ b/src/network/ssl/qsslconfiguration.cpp
@@ -105,6 +105,12 @@ const char QSslConfiguration::NextProtocolHttp1_1[] = "http/1.1";
*/
/*!
+ \variable QSslConfiguration::ALPNProtocolHTTP2
+ \brief The value used for negotiating HTTP 2 during the Application-Layer
+ Protocol Negotiation.
+*/
+
+/*!
Constructs an empty SSL configuration. This configuration contains
no valid settings and the state will be empty. isNull() will
return true after this constructor is called.
@@ -550,8 +556,6 @@ void QSslConfiguration::setPrivateKey(const QSslKey &key)
ciphers. You can revert to using the entire set by calling
setCiphers() with the list returned by supportedCiphers().
- \note This is not currently supported in the Schannel backend.
-
\sa setCiphers(), supportedCiphers()
*/
QList<QSslCipher> QSslConfiguration::ciphers() const
@@ -567,8 +571,6 @@ QList<QSslCipher> QSslConfiguration::ciphers() const
Restricting the cipher suite must be done before the handshake
phase, where the session cipher is chosen.
- \note This is not currently supported in the Schannel backend.
-
\sa ciphers(), supportedCiphers()
*/
void QSslConfiguration::setCiphers(const QList<QSslCipher> &ciphers)
@@ -581,16 +583,14 @@ void QSslConfiguration::setCiphers(const QList<QSslCipher> &ciphers)
Sets the cryptographic cipher suite for this configuration to \a ciphers,
which is a colon-separated list of cipher suite names. The ciphers are listed
- in order of preference, starting with the most preferred cipher. For example:
-
- \snippet code/src_network_ssl_qsslconfiguration.cpp 1
-
+ in order of preference, starting with the most preferred cipher.
Each cipher name in \a ciphers must be the name of a cipher in the
list returned by supportedCiphers(). Restricting the cipher suite
must be done before the handshake phase, where the session cipher
is chosen.
- \note This is not currently supported in the Schannel backend.
+ \note With the Schannel backend the order of the ciphers is ignored and Schannel
+ picks the most secure one during the handshake.
\sa ciphers()
*/
@@ -922,7 +922,11 @@ void QSslConfiguration::setPreSharedKeyIdentityHint(const QByteArray &hint)
Retrieves the current set of Diffie-Hellman parameters.
If no Diffie-Hellman parameters have been set, the QSslConfiguration object
- defaults to using the 1024-bit MODP group from RFC 2409.
+ defaults to using the 2048-bit MODP group from RFC 3526.
+
+ \note The default parameters may change in future Qt versions.
+ Please check the documentation of the \e{exact Qt version} that you
+ are using in order to know what defaults that version uses.
*/
QSslDiffieHellmanParameters QSslConfiguration::diffieHellmanParameters() const
{
@@ -936,7 +940,14 @@ QSslDiffieHellmanParameters QSslConfiguration::diffieHellmanParameters() const
a server to \a dhparams.
If no Diffie-Hellman parameters have been set, the QSslConfiguration object
- defaults to using the 1024-bit MODP group from RFC 2409.
+ defaults to using the 2048-bit MODP group from RFC 3526.
+
+ Since 6.7 you can provide an empty Diffie-Hellman parameter to use auto selection
+ (see SSL_CTX_set_dh_auto of openssl) if the tls backend supports it.
+
+ \note The default parameters may change in future Qt versions.
+ Please check the documentation of the \e{exact Qt version} that you
+ are using in order to know what defaults that version uses.
*/
void QSslConfiguration::setDiffieHellmanParameters(const QSslDiffieHellmanParameters &dhparams)
{
diff --git a/src/network/ssl/qssldiffiehellmanparameters.cpp b/src/network/ssl/qssldiffiehellmanparameters.cpp
index b2c112bbf9..7da14f3536 100644
--- a/src/network/ssl/qssldiffiehellmanparameters.cpp
+++ b/src/network/ssl/qssldiffiehellmanparameters.cpp
@@ -33,17 +33,18 @@
QT_BEGIN_NAMESPACE
-// The 1024-bit MODP group from RFC 2459 (Second Oakley Group)
+// The 2048-bit MODP group from RFC 3526
Q_AUTOTEST_EXPORT const char *qssl_dhparams_default_base64 =
- "MIGHAoGBAP//////////yQ/aoiFowjTExmKLgNwc0SkCTgiKZ8x0Agu+pjsTmyJR"
- "Sgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHCReSFtXZiXn7G9ExC6aY37WsL"
- "/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7OZTgf//////////AgEC";
+ "MIIBCAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxObIlFKCHmO"
+ "NATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjftawv/XLb0Brft7jhr"
+ "+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXTmmkWP6j9JM9fg2VdI9yjrZYc"
+ "YvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhghfDKQXkYuNs474553LBgOhgObJ4Oi7Aei"
+ "j7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAg==";
/*!
Returns the default QSslDiffieHellmanParameters used by QSslSocket.
- This is currently the 1024-bit MODP group from RFC 2459, also
- known as the Second Oakley Group.
+ This is currently the 2048-bit MODP group from RFC 3526.
*/
QSslDiffieHellmanParameters QSslDiffieHellmanParameters::defaultParameters()
{
diff --git a/src/network/ssl/qsslpresharedkeyauthenticator.h b/src/network/ssl/qsslpresharedkeyauthenticator.h
index 98cfad19ed..a3912406d3 100644
--- a/src/network/ssl/qsslpresharedkeyauthenticator.h
+++ b/src/network/ssl/qsslpresharedkeyauthenticator.h
@@ -16,6 +16,7 @@ QT_BEGIN_NAMESPACE
class QSslPreSharedKeyAuthenticatorPrivate;
class QSslPreSharedKeyAuthenticator
{
+ Q_GADGET_EXPORT(Q_NETWORK_EXPORT)
public:
Q_NETWORK_EXPORT QSslPreSharedKeyAuthenticator();
Q_NETWORK_EXPORT ~QSslPreSharedKeyAuthenticator();
diff --git a/src/network/ssl/qsslserver.cpp b/src/network/ssl/qsslserver.cpp
index 967c478904..40a6a6f526 100644
--- a/src/network/ssl/qsslserver.cpp
+++ b/src/network/ssl/qsslserver.cpp
@@ -341,7 +341,7 @@ void QSslServerPrivate::initializeHandshakeProcess(QSslSocket *socket)
});
auto it = socketData.emplace(quintptr(socket), readyRead, destroyed, std::make_shared<QTimer>());
it->timeoutTimer->setSingleShot(true);
- it->timeoutTimer->callOnTimeout([this, socket]() { handleHandshakeTimedOut(socket); });
+ it->timeoutTimer->callOnTimeout(q, [this, socket]() { handleHandshakeTimedOut(socket); });
it->timeoutTimer->setInterval(handshakeTimeout);
it->timeoutTimer->start();
}
@@ -408,3 +408,5 @@ void QSslServerPrivate::handleHandshakeTimedOut(QSslSocket *socket)
}
QT_END_NAMESPACE
+
+#include "moc_qsslserver.cpp"
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
index 4eefe43929..395394d432 100644
--- a/src/network/ssl/qsslsocket.cpp
+++ b/src/network/ssl/qsslsocket.cpp
@@ -97,8 +97,7 @@
\list
\li The socket's cryptographic cipher suite can be customized before
- the handshake phase with QSslConfiguration::setCiphers()
- and QSslConfiguration::setDefaultCiphers().
+ the handshake phase with QSslConfiguration::setCiphers().
\li The socket's local certificate and private key can be customized
before the handshake phase with setLocalCertificate() and
setPrivateKey().
@@ -365,6 +364,12 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
+#ifdef Q_OS_VXWORKS
+constexpr auto isVxworks = true;
+#else
+constexpr auto isVxworks = false;
+#endif
+
class QSslSocketGlobalData
{
public:
@@ -1539,7 +1544,12 @@ QList<QString> QSslSocket::availableBackends()
from the list of available backends.
\note When selecting a default backend implicitly, QSslSocket prefers
- the OpenSSL backend if available.
+ the OpenSSL backend if available. If it's not available, the Schannel backend
+ is implicitly selected on Windows, and Secure Transport on Darwin platforms.
+ Failing these, if a custom TLS backend is found, it is used.
+ If no other backend is found, the "certificate only" backend is selected.
+ For more information about TLS plugins, please see
+ \l {Enabling and Disabling SSL Support when Building Qt from Source}.
\sa setActiveBackend(), availableBackends()
*/
@@ -1973,6 +1983,10 @@ QSslSocketPrivate::QSslSocketPrivate()
, flushTriggered(false)
{
QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration);
+ // If the global configuration doesn't allow root certificates to be loaded
+ // on demand then we have to disable it for this socket as well.
+ if (!configuration.allowRootCertOnDemandLoading)
+ allowRootCertOnDemandLoading = false;
const auto *tlsBackend = tlsBackendInUse();
if (!tlsBackend) {
@@ -2281,6 +2295,7 @@ void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPri
ptr->sessionProtocol = global->sessionProtocol;
ptr->ciphers = global->ciphers;
ptr->caCertificates = global->caCertificates;
+ ptr->allowRootCertOnDemandLoading = global->allowRootCertOnDemandLoading;
ptr->protocol = global->protocol;
ptr->peerVerifyMode = global->peerVerifyMode;
ptr->peerVerifyDepth = global->peerVerifyDepth;
@@ -2955,7 +2970,13 @@ QList<QByteArray> QSslSocketPrivate::unixRootCertDirectories()
ba("/opt/openssl/certs/"), // HP-UX
ba("/etc/ssl/"), // OpenBSD
};
- return QList<QByteArray>::fromReadOnlyData(dirs);
+ QList<QByteArray> result = QList<QByteArray>::fromReadOnlyData(dirs);
+ if constexpr (isVxworks) {
+ static QByteArray vxworksCertsDir = qgetenv("VXWORKS_CERTS_DIR");
+ if (!vxworksCertsDir.isEmpty())
+ result.push_back(vxworksCertsDir);
+ }
+ return result;
}
/*!
@@ -3086,10 +3107,11 @@ QTlsBackend *QSslSocketPrivate::tlsBackendInUse()
tlsBackend = QTlsBackend::findBackend(activeBackendName);
if (tlsBackend) {
- QObject::connect(tlsBackend, &QObject::destroyed, [] {
+ QObject::connect(tlsBackend, &QObject::destroyed, tlsBackend, [] {
const QMutexLocker locker(&backendMutex);
tlsBackend = nullptr;
- });
+ },
+ Qt::DirectConnection);
}
return tlsBackend;
}
diff --git a/src/network/ssl/qsslsocket.h b/src/network/ssl/qsslsocket.h
index 3174a68953..3ed1bc45cc 100644
--- a/src/network/ssl/qsslsocket.h
+++ b/src/network/ssl/qsslsocket.h
@@ -35,6 +35,7 @@ public:
SslClientMode,
SslServerMode
};
+ Q_ENUM(SslMode)
enum PeerVerifyMode {
VerifyNone,
@@ -42,6 +43,7 @@ public:
VerifyPeer,
AutoVerifyPeer
};
+ Q_ENUM(PeerVerifyMode)
explicit QSslSocket(QObject *parent = nullptr);
~QSslSocket();
diff --git a/src/network/ssl/qtlsbackend.cpp b/src/network/ssl/qtlsbackend.cpp
index 8ef82a8a8e..761ab33fbe 100644
--- a/src/network/ssl/qtlsbackend.cpp
+++ b/src/network/ssl/qtlsbackend.cpp
@@ -889,20 +889,28 @@ QSslCipher QTlsBackend::createCiphersuite(const QString &suiteName, QSsl::SslPro
/*!
\internal
- Auxiliary function. Creates a new QSslCipher from \a name (which is an implementation-specific
- string), \a protocol and \a protocolString, e.g.:
+ Auxiliary function. Creates a new QSslCipher from \a name, \a keyExchangeMethod, \a encryptionMethod,
+ \a authenticationMethod, \a bits, \a protocol version and \a protocolString.
+ For example:
\code
- createCipher(QStringLiteral("schannel"), QSsl::TlsV1_2, "TLSv1.2"_L1);
+ createCiphersuite("ECDHE-RSA-AES256-GCM-SHA256"_L1, "ECDH"_L1, "AES"_L1, "RSA"_L1, 256,
+ QSsl::TlsV1_2, "TLSv1.2"_L1);
\endcode
*/
-QSslCipher QTlsBackend::createCipher(const QString &name, QSsl::SslProtocol protocol,
- const QString &protocolString)
+QSslCipher QTlsBackend::createCiphersuite(const QString &name, const QString &keyExchangeMethod,
+ const QString &encryptionMethod,
+ const QString &authenticationMethod,
+ int bits, QSsl::SslProtocol protocol,
+ const QString &protocolString)
{
- // Note the name 'createCipher' (not 'ciphersuite'): we don't provide
- // information about Kx, Au, bits/supported etc.
QSslCipher cipher;
cipher.d->isNull = false;
cipher.d->name = name;
+ cipher.d->bits = bits;
+ cipher.d->supportedBits = bits;
+ cipher.d->keyExchangeMethod = keyExchangeMethod;
+ cipher.d->encryptionMethod = encryptionMethod;
+ cipher.d->authenticationMethod = authenticationMethod;
cipher.d->protocol = protocol;
cipher.d->protocolString = protocolString;
return cipher;
diff --git a/src/network/ssl/qtlsbackend_p.h b/src/network/ssl/qtlsbackend_p.h
index 76fa0994f5..090531014b 100644
--- a/src/network/ssl/qtlsbackend_p.h
+++ b/src/network/ssl/qtlsbackend_p.h
@@ -57,7 +57,7 @@ class QSslKey;
namespace QTlsPrivate {
-class Q_NETWORK_PRIVATE_EXPORT TlsKey {
+class Q_NETWORK_EXPORT TlsKey {
public:
virtual ~TlsKey();
@@ -94,7 +94,7 @@ public:
QByteArray pemFooter() const;
};
-class Q_NETWORK_PRIVATE_EXPORT X509Certificate
+class Q_NETWORK_EXPORT X509Certificate
{
public:
virtual ~X509Certificate();
@@ -151,7 +151,7 @@ using X509Pkcs12ReaderPtr = bool (*)(QIODevice *device, QSslKey *key, QSslCertif
#if QT_CONFIG(ssl)
// TLS over TCP. Handshake, encryption/decryption.
-class Q_NETWORK_PRIVATE_EXPORT TlsCryptograph : public QObject
+class Q_NETWORK_EXPORT TlsCryptograph : public QObject
{
public:
virtual ~TlsCryptograph();
@@ -187,7 +187,7 @@ class TlsCryptograph;
#if QT_CONFIG(dtls)
-class Q_NETWORK_PRIVATE_EXPORT DtlsBase
+class Q_NETWORK_EXPORT DtlsBase
{
public:
virtual ~DtlsBase();
@@ -217,7 +217,7 @@ public:
};
// TLS over UDP. Handshake, encryption/decryption.
-class Q_NETWORK_PRIVATE_EXPORT DtlsCryptograph : virtual public DtlsBase
+class Q_NETWORK_EXPORT DtlsCryptograph : virtual public DtlsBase
{
public:
@@ -346,8 +346,11 @@ public:
static QSslCipher createCiphersuite(const QString &description, int bits, int supportedBits);
static QSslCipher createCiphersuite(const QString &suiteName, QSsl::SslProtocol protocol,
const QString &protocolString);
- static QSslCipher createCipher(const QString &name, QSsl::SslProtocol protocol,
- const QString &protocolString);
+ static QSslCipher createCiphersuite(const QString &name, const QString &keyExchangeMethod,
+ const QString &encryptionMethod,
+ const QString &authenticationMethod,
+ int bits, QSsl::SslProtocol protocol,
+ const QString &protocolString);
// Those statics are implemented using QSslSocketPrivate (which is not exported,
// unlike QTlsBackend).
diff --git a/src/opengl/CMakeLists.txt b/src/opengl/CMakeLists.txt
index 1729f1b12d..825e4cb71b 100644
--- a/src/opengl/CMakeLists.txt
+++ b/src/opengl/CMakeLists.txt
@@ -33,9 +33,13 @@ qt_internal_add_module(OpenGL
qopenglvertexarrayobject.cpp qopenglvertexarrayobject.h qopenglvertexarrayobject_p.h
qopenglwindow.cpp qopenglwindow.h
qtopenglglobal.h
+ NO_UNITY_BUILD_SOURCES
+ qopengltextureblitter.cpp # qDebug()<< ambiguities
DEFINES
+ QT_NO_CONTEXTLESS_CONNECT
QT_NO_FOREACH
QT_NO_USING_NAMESPACE
+ QT_USE_NODISCARD_FILE_OPEN
LIBRARIES
Qt::CorePrivate
Qt::GuiPrivate
@@ -48,17 +52,14 @@ qt_internal_add_module(OpenGL
GENERATE_CPP_EXPORTS
)
-# qDebug()<< ambiguities
-set_source_files_properties(qopengltextureblitter.cpp PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
-
-if(APPLE)
- set_source_files_properties(qopenglversionfunctionsfactory.cpp
- PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
-endif()
-
## Scopes:
#####################################################################
+qt_internal_extend_target(OpenGL CONDITION APPLE
+ NO_UNITY_BUILD_SOURCES
+ qopenglversionfunctionsfactory.cpp
+)
+
qt_internal_extend_target(OpenGL CONDITION QT_FEATURE_opengles2
SOURCES
qopenglfunctions_es2.cpp qopenglfunctions_es2.h
diff --git a/src/opengl/doc/qtopengl.qdocconf b/src/opengl/doc/qtopengl.qdocconf
index 58f16e7d2e..7af173aac8 100644
--- a/src/opengl/doc/qtopengl.qdocconf
+++ b/src/opengl/doc/qtopengl.qdocconf
@@ -15,18 +15,17 @@ project = QtOpenGL
# <rootdir>/examples.
# Paths are relative to the location of this file.
-headerdirs += .. \
- ../../openglwidgets
-sourcedirs += .. \
- ../../openglwidgets \
- ../../../examples/opengl/doc/src
+{sourcedirs,headerdirs} += \
+ .. \
+ ../../openglwidgets
+
exampledirs += ../../../examples/opengl \
. \
snippets \
.. \
../../gui/doc/snippets
-imagedirs += images \
- ../../../examples/opengl/doc/images
+
+imagedirs += images
depends += qtcore qtgui qtwidgets qtdoc qmake qtcmake qtquick
@@ -65,5 +64,5 @@ qhp.QtOpenGL.subprojects.classes.sortPages = true
navigation.landingpage = "Qt OpenGL"
navigation.cppclassespage = "Qt OpenGL C++ Classes"
-# Fail the documentation build if there are more warnings than the limit
+# Enforce zero documentation warnings
warninglimit = 0
diff --git a/src/opengl/doc/snippets/CMakeLists.txt b/src/opengl/doc/snippets/CMakeLists.txt
index 6ee0eab722..419e0923e0 100644
--- a/src/opengl/doc/snippets/CMakeLists.txt
+++ b/src/opengl/doc/snippets/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#! [cmake_use]
find_package(Qt6 REQUIRED COMPONENTS OpenGL)
diff --git a/src/opengl/doc/src/qt6-changes.qdoc b/src/opengl/doc/src/qt6-changes.qdoc
index 1bde84fb62..e227476868 100644
--- a/src/opengl/doc/src/qt6-changes.qdoc
+++ b/src/opengl/doc/src/qt6-changes.qdoc
@@ -5,7 +5,7 @@
\page opengl-changes-qt6.html
\title Changes to Qt OpenGL
\ingroup changes-qt-5-to-6
- \brief Migrate Qt OpenGL to Qt 6.
+ \brief QOpenGL classes migrated, QOpenGLWidget class has been moved to Qt OpenGL Widgets.
Qt 6 is a result of the conscious effort to make the framework more
efficient and easy to use.
diff --git a/src/opengl/doc/src/qtopengl-examples.qdoc b/src/opengl/doc/src/qtopengl-examples.qdoc
index 4843407b0b..3a98c16c70 100644
--- a/src/opengl/doc/src/qtopengl-examples.qdoc
+++ b/src/opengl/doc/src/qtopengl-examples.qdoc
@@ -3,7 +3,7 @@
/*!
\ingroup all-examples
- \title OpenGL Examples from the Qt OpenGL module
+ \title Qt OpenGL Examples
\brief Accessing OpenGL from Qt.
\group examples-widgets-opengl
diff --git a/src/opengl/doc/src/qtopengl-index.qdoc b/src/opengl/doc/src/qtopengl-index.qdoc
index 0b0080edf0..7ea1635827 100644
--- a/src/opengl/doc/src/qtopengl-index.qdoc
+++ b/src/opengl/doc/src/qtopengl-index.qdoc
@@ -61,7 +61,7 @@
\section1 Examples
\list
- \li \l {OpenGL Window Example}
+ \li \l {Qt OpenGL Examples}
\endlist
\section1 Reference
diff --git a/src/opengl/qopenglcompositor.cpp b/src/opengl/qopenglcompositor.cpp
index 3e1b2aebed..3c5b1df905 100644
--- a/src/opengl/qopenglcompositor.cpp
+++ b/src/opengl/qopenglcompositor.cpp
@@ -4,7 +4,7 @@
#include <QtOpenGL/QOpenGLFramebufferObject>
#include <QtGui/QOpenGLContext>
#include <QtGui/QWindow>
-#include <QtGui/private/qrhi_p.h>
+#include <rhi/qrhi.h>
#include <qpa/qplatformbackingstore.h>
#include "qopenglcompositor_p.h"
@@ -85,10 +85,23 @@ void QOpenGLCompositor::update()
QImage QOpenGLCompositor::grab()
{
Q_ASSERT(m_context && m_targetWindow);
+ QOpenGLFramebufferObject fbo(m_nativeTargetGeometry.size());
+ grabToFrameBufferObject(&fbo);
+ return fbo.toImage();
+}
+
+bool QOpenGLCompositor::grabToFrameBufferObject(QOpenGLFramebufferObject *fbo, GrabOrientation orientation)
+{
+ Q_ASSERT(fbo);
+ if (fbo->size() != m_nativeTargetGeometry.size()
+ || fbo->format().textureTarget() != GL_TEXTURE_2D)
+ return false;
+
m_context->makeCurrent(m_targetWindow);
- QScopedPointer<QOpenGLFramebufferObject> fbo(new QOpenGLFramebufferObject(m_nativeTargetGeometry.size()));
- renderAll(fbo.data());
- return fbo->toImage();
+ renderAll(fbo,
+ orientation == Flipped ? QOpenGLTextureBlitter::OriginTopLeft
+ : QOpenGLTextureBlitter::OriginBottomLeft);
+ return true;
}
void QOpenGLCompositor::handleRenderAllRequest()
@@ -98,7 +111,7 @@ void QOpenGLCompositor::handleRenderAllRequest()
renderAll(0);
}
-void QOpenGLCompositor::renderAll(QOpenGLFramebufferObject *fbo)
+void QOpenGLCompositor::renderAll(QOpenGLFramebufferObject *fbo, QOpenGLTextureBlitter::Origin origin)
{
if (fbo)
fbo->bind();
@@ -115,7 +128,7 @@ void QOpenGLCompositor::renderAll(QOpenGLFramebufferObject *fbo)
m_windows.at(i)->beginCompositing();
for (int i = 0; i < m_windows.size(); ++i)
- render(m_windows.at(i));
+ render(m_windows.at(i), origin);
m_blitter.release();
if (!fbo)
@@ -156,9 +169,10 @@ static inline QRect toBottomLeftRect(const QRect &topLeftRect, int windowHeight)
topLeftRect.width(), topLeftRect.height());
}
-static void clippedBlit(const QPlatformTextureList *textures, int idx, const QRect &sourceWindowRect,
- const QRect &targetWindowRect,
- QOpenGLTextureBlitter *blitter, QMatrix4x4 *rotationMatrix)
+static void clippedBlit(const QPlatformTextureList *textures, int idx,
+ const QRect &sourceWindowRect, const QRect &targetWindowRect,
+ QOpenGLTextureBlitter *blitter, QMatrix4x4 *rotationMatrix,
+ QOpenGLTextureBlitter::Origin sourceOrigin)
{
const QRect clipRect = textures->clipRect(idx);
if (clipRect.isEmpty())
@@ -173,13 +187,13 @@ static void clippedBlit(const QPlatformTextureList *textures, int idx, const QRe
target = *rotationMatrix * target;
const QMatrix3x3 source = QOpenGLTextureBlitter::sourceTransform(srcRect, rectInWindow.size(),
- QOpenGLTextureBlitter::OriginBottomLeft);
+ sourceOrigin);
const uint textureId = textures->texture(idx)->nativeTexture().object;
blitter->blit(textureId, target, source);
}
-void QOpenGLCompositor::render(QOpenGLCompositorWindow *window)
+void QOpenGLCompositor::render(QOpenGLCompositorWindow *window, QOpenGLTextureBlitter::Origin origin)
{
const QPlatformTextureList *textures = window->textures();
if (!textures)
@@ -189,6 +203,9 @@ void QOpenGLCompositor::render(QOpenGLCompositorWindow *window)
float currentOpacity = 1.0f;
BlendStateBinder blend;
const QRect sourceWindowRect = window->sourceWindow()->geometry();
+ auto clippedBlitSourceOrigin = origin == QOpenGLTextureBlitter::OriginTopLeft
+ ? QOpenGLTextureBlitter::OriginBottomLeft
+ : QOpenGLTextureBlitter::OriginTopLeft;
for (int i = 0; i < textures->count(); ++i) {
const uint textureId = textures->texture(i)->nativeTexture().object;
const float opacity = window->sourceWindow()->opacity();
@@ -203,7 +220,7 @@ void QOpenGLCompositor::render(QOpenGLCompositorWindow *window)
QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect);
if (m_rotation)
target = m_rotationMatrix * target;
- m_blitter.blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft);
+ m_blitter.blit(textureId, target, origin);
} else if (textures->count() == 1) {
// A regular QWidget window
const bool translucent = window->sourceWindow()->requestedFormat().alphaBufferSize() > 0;
@@ -211,18 +228,20 @@ void QOpenGLCompositor::render(QOpenGLCompositorWindow *window)
QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(textures->geometry(i), targetWindowRect);
if (m_rotation)
target = m_rotationMatrix * target;
- m_blitter.blit(textureId, target, QOpenGLTextureBlitter::OriginTopLeft);
+ m_blitter.blit(textureId, target, origin);
} else if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) {
// Texture from an FBO belonging to a QOpenGLWidget or QQuickWidget
blend.set(false);
- clippedBlit(textures, i, sourceWindowRect, targetWindowRect, &m_blitter, m_rotation ? &m_rotationMatrix : nullptr);
+ clippedBlit(textures, i, sourceWindowRect, targetWindowRect, &m_blitter,
+ m_rotation ? &m_rotationMatrix : nullptr, clippedBlitSourceOrigin);
}
}
for (int i = 0; i < textures->count(); ++i) {
if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop)) {
blend.set(true);
- clippedBlit(textures, i, sourceWindowRect, targetWindowRect, &m_blitter, m_rotation ? &m_rotationMatrix : nullptr);
+ clippedBlit(textures, i, sourceWindowRect, targetWindowRect, &m_blitter,
+ m_rotation ? &m_rotationMatrix : nullptr, clippedBlitSourceOrigin);
}
}
diff --git a/src/opengl/qopenglcompositor_p.h b/src/opengl/qopenglcompositor_p.h
index abe8d4959e..86229b13ca 100644
--- a/src/opengl/qopenglcompositor_p.h
+++ b/src/opengl/qopenglcompositor_p.h
@@ -29,6 +29,7 @@ class QOpenGLFramebufferObject;
class QWindow;
class QPlatformTextureList;
+class QOpenGLCompositorBackingStore;
class QOpenGLCompositorWindow
{
public:
@@ -37,6 +38,8 @@ public:
virtual const QPlatformTextureList *textures() const = 0;
virtual void beginCompositing() { }
virtual void endCompositing() { }
+ virtual void setBackingStore(QOpenGLCompositorBackingStore *backingStore) = 0;
+ virtual QOpenGLCompositorBackingStore *backingStore() const = 0;
};
class Q_OPENGL_EXPORT QOpenGLCompositor : public QObject
@@ -44,6 +47,11 @@ class Q_OPENGL_EXPORT QOpenGLCompositor : public QObject
Q_OBJECT
public:
+ enum GrabOrientation {
+ Flipped,
+ NotFlipped,
+ };
+
static QOpenGLCompositor *instance();
static void destroy();
@@ -52,10 +60,13 @@ public:
void setRotation(int degrees);
QOpenGLContext *context() const { return m_context; }
QWindow *targetWindow() const { return m_targetWindow; }
+ QRect nativeTargetGeometry() const { return m_nativeTargetGeometry; }
void update();
QImage grab();
+ bool grabToFrameBufferObject(QOpenGLFramebufferObject *fbo, GrabOrientation orientation = Flipped);
+
QList<QOpenGLCompositorWindow *> windows() const { return m_windows; }
void addWindow(QOpenGLCompositorWindow *window);
void removeWindow(QOpenGLCompositorWindow *window);
@@ -72,8 +83,10 @@ private:
QOpenGLCompositor();
~QOpenGLCompositor();
- void renderAll(QOpenGLFramebufferObject *fbo);
- void render(QOpenGLCompositorWindow *window);
+ void renderAll(QOpenGLFramebufferObject *fbo,
+ QOpenGLTextureBlitter::Origin origin = QOpenGLTextureBlitter::OriginTopLeft);
+ void render(QOpenGLCompositorWindow *window,
+ QOpenGLTextureBlitter::Origin origin = QOpenGLTextureBlitter::OriginTopLeft);
void ensureCorrectZOrder();
QOpenGLContext *m_context;
diff --git a/src/opengl/qopenglcompositorbackingstore.cpp b/src/opengl/qopenglcompositorbackingstore.cpp
index a5cc391e48..931734cf60 100644
--- a/src/opengl/qopenglcompositorbackingstore.cpp
+++ b/src/opengl/qopenglcompositorbackingstore.cpp
@@ -6,7 +6,7 @@
#include <QtGui/QPainter>
#include <qpa/qplatformbackingstore.h>
#include <private/qwindow_p.h>
-#include <private/qrhi_p.h>
+#include <rhi/qrhi.h>
#include "qopenglcompositorbackingstore_p.h"
#include "qopenglcompositor_p.h"
@@ -137,6 +137,9 @@ void QOpenGLCompositorBackingStore::updateTexture()
void QOpenGLCompositorBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
{
// Called for ordinary raster windows.
+ auto *handle = dynamic_cast<QOpenGLCompositorWindow *>(window->handle());
+ if (handle && !handle->backingStore())
+ handle->setBackingStore(this);
Q_UNUSED(region);
Q_UNUSED(offset);
@@ -246,6 +249,8 @@ void QOpenGLCompositorBackingStore::resize(const QSize &size, const QRegion &sta
QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
QOpenGLContext *dstCtx = compositor->context();
+ if (!dstCtx)
+ return;
QWindow *dstWin = compositor->targetWindow();
if (!dstWin)
return;
diff --git a/src/opengl/qopenglcustomshaderstage.cpp b/src/opengl/qopenglcustomshaderstage.cpp
index d26bebfd61..1be8d783d6 100644
--- a/src/opengl/qopenglcustomshaderstage.cpp
+++ b/src/opengl/qopenglcustomshaderstage.cpp
@@ -6,6 +6,8 @@
#include "qopenglpaintengine_p.h"
#include <private/qpainter_p.h>
+#include <QtCore/qpointer.h>
+
QT_BEGIN_NAMESPACE
class QOpenGLCustomShaderStagePrivate
diff --git a/src/opengl/qopenglframebufferobject.cpp b/src/opengl/qopenglframebufferobject.cpp
index ccb4f7b0a8..5c8f769d39 100644
--- a/src/opengl/qopenglframebufferobject.cpp
+++ b/src/opengl/qopenglframebufferobject.cpp
@@ -550,8 +550,22 @@ void QOpenGLFramebufferObjectPrivate::initTexture(int idx)
else if (color.internalFormat == GL_RGB16F || color.internalFormat == GL_RGBA16F)
pixelType = GL_HALF_FLOAT;
+ bool isOpaque = false;
+ switch (color.internalFormat) {
+ case GL_RGB8:
+ case GL_RGB16:
+ case GL_RGB16F:
+ case GL_RGB32F:
+ isOpaque = true;
+ break;
+ case GL_RGB10:
+ // opaque but the pixel type (INT_2_10_10_10) has alpha and so requires RGBA texture format
+ break;
+ }
+ const GLuint textureFormat = isOpaque ? GL_RGB : GL_RGBA;
+
funcs.glTexImage2D(target, 0, color.internalFormat, color.size.width(), color.size.height(), 0,
- GL_RGBA, pixelType, nullptr);
+ textureFormat, pixelType, nullptr);
if (format.mipmap()) {
int width = color.size.width();
int height = color.size.height();
@@ -560,8 +574,8 @@ void QOpenGLFramebufferObjectPrivate::initTexture(int idx)
width = qMax(1, width >> 1);
height = qMax(1, height >> 1);
++level;
- funcs.glTexImage2D(target, level, color.internalFormat, width, height, 0,
- GL_RGBA, pixelType, nullptr);
+ funcs.glTexImage2D(target, level, color.internalFormat, width, height, 0, textureFormat,
+ pixelType, nullptr);
}
}
funcs.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + idx,
@@ -1344,7 +1358,8 @@ static inline QImage qt_gl_read_framebuffer_rgba8(const QSize &size, bool includ
bool isOpenGL12orBetter = !context->isOpenGLES() && (context->format().majorVersion() >= 2 || context->format().minorVersion() >= 2);
if (isOpenGL12orBetter) {
QImage img(size, include_alpha ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32);
- funcs->glReadPixels(0, 0, w, h, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, img.bits());
+ if (!img.isNull())
+ funcs->glReadPixels(0, 0, w, h, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, img.bits());
return img;
}
@@ -1354,7 +1369,8 @@ static inline QImage qt_gl_read_framebuffer_rgba8(const QSize &size, bool includ
// BGRA capable impl would return BGRA from there)
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());
+ if (!rgbaImage.isNull())
+ funcs->glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rgbaImage.bits());
return rgbaImage;
}
@@ -1362,7 +1378,8 @@ static inline QImage qt_gl_read_framebuffer_rgb10a2(const QSize &size, bool incl
{
// We assume OpenGL 1.2+ or ES 3.0+ here.
QImage img(size, include_alpha ? QImage::Format_A2BGR30_Premultiplied : QImage::Format_BGR30);
- context->functions()->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, img.bits());
+ if (!img.isNull())
+ context->functions()->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, img.bits());
return img;
}
@@ -1370,7 +1387,8 @@ static inline QImage qt_gl_read_framebuffer_rgba16(const QSize &size, bool inclu
{
// We assume OpenGL 1.2+ or ES 3.0+ here.
QImage img(size, include_alpha ? QImage::Format_RGBA64_Premultiplied : QImage::Format_RGBX64);
- context->functions()->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_SHORT, img.bits());
+ if (!img.isNull())
+ context->functions()->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_SHORT, img.bits());
return img;
}
@@ -1378,14 +1396,16 @@ static inline QImage qt_gl_read_framebuffer_rgba16f(const QSize &size, bool incl
{
// We assume OpenGL (ES) 3.0+ here.
QImage img(size, include_alpha ? QImage::Format_RGBA16FPx4_Premultiplied : QImage::Format_RGBX16FPx4);
- context->functions()->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_HALF_FLOAT, img.bits());
+ if (!img.isNull())
+ context->functions()->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_HALF_FLOAT, img.bits());
return img;
}
static inline QImage qt_gl_read_framebuffer_rgba32f(const QSize &size, bool include_alpha, QOpenGLContext *context)
{
QImage img(size, include_alpha ? QImage::Format_RGBA32FPx4_Premultiplied : QImage::Format_RGBX32FPx4);
- context->functions()->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_FLOAT, img.bits());
+ if (!img.isNull())
+ context->functions()->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_FLOAT, img.bits());
return img;
}
diff --git a/src/opengl/qopenglfunctions_2_0.cpp b/src/opengl/qopenglfunctions_2_0.cpp
index 834136d3dd..0641f41390 100644
--- a/src/opengl/qopenglfunctions_2_0.cpp
+++ b/src/opengl/qopenglfunctions_2_0.cpp
@@ -44,7 +44,6 @@ QOpenGLFunctions_2_0::QOpenGLFunctions_2_0()
, d_1_2_Deprecated(nullptr)
, d_1_3_Deprecated(nullptr)
, d_1_4_Deprecated(nullptr)
- , m_reserved_2_0_Deprecated(nullptr)
{
}
diff --git a/src/opengl/qopenglfunctions_2_0.h b/src/opengl/qopenglfunctions_2_0.h
index f45a56b4f3..cca8d590e7 100644
--- a/src/opengl/qopenglfunctions_2_0.h
+++ b/src/opengl/qopenglfunctions_2_0.h
@@ -656,7 +656,7 @@ private:
QOpenGLFunctions_1_2_DeprecatedBackend* d_1_2_Deprecated;
QOpenGLFunctions_1_3_DeprecatedBackend* d_1_3_Deprecated;
QOpenGLFunctions_1_4_DeprecatedBackend* d_1_4_Deprecated;
- void *m_reserved_2_0_Deprecated; // To maintain BC
+ Q_DECL_UNUSED_MEMBER void *m_reserved_2_0_Deprecated = nullptr; // To maintain BC
};
// OpenGL 1.0 core functions
diff --git a/src/opengl/qopenglfunctions_2_1.cpp b/src/opengl/qopenglfunctions_2_1.cpp
index 984bb16d11..28f8b29dab 100644
--- a/src/opengl/qopenglfunctions_2_1.cpp
+++ b/src/opengl/qopenglfunctions_2_1.cpp
@@ -45,7 +45,6 @@ QOpenGLFunctions_2_1::QOpenGLFunctions_2_1()
, d_1_2_Deprecated(nullptr)
, d_1_3_Deprecated(nullptr)
, d_1_4_Deprecated(nullptr)
- , m_reserved_2_0_Deprecated(nullptr)
{
}
diff --git a/src/opengl/qopenglfunctions_2_1.h b/src/opengl/qopenglfunctions_2_1.h
index 249ede3608..3b192e3b62 100644
--- a/src/opengl/qopenglfunctions_2_1.h
+++ b/src/opengl/qopenglfunctions_2_1.h
@@ -667,7 +667,7 @@ private:
QOpenGLFunctions_1_2_DeprecatedBackend* d_1_2_Deprecated;
QOpenGLFunctions_1_3_DeprecatedBackend* d_1_3_Deprecated;
QOpenGLFunctions_1_4_DeprecatedBackend* d_1_4_Deprecated;
- void *m_reserved_2_0_Deprecated; // To maintain BC
+ Q_DECL_UNUSED_MEMBER void *m_reserved_2_0_Deprecated = nullptr; // To maintain BC
};
// OpenGL 1.0 core functions
diff --git a/src/opengl/qopenglfunctions_3_0.cpp b/src/opengl/qopenglfunctions_3_0.cpp
index 5fcf1c9b2c..b186ff2a9f 100644
--- a/src/opengl/qopenglfunctions_3_0.cpp
+++ b/src/opengl/qopenglfunctions_3_0.cpp
@@ -46,8 +46,6 @@ QOpenGLFunctions_3_0::QOpenGLFunctions_3_0()
, d_1_2_Deprecated(nullptr)
, d_1_3_Deprecated(nullptr)
, d_1_4_Deprecated(nullptr)
- , m_reserved_2_0_Deprecated(nullptr)
- , m_reserved_3_0_Deprecated(nullptr)
{
}
diff --git a/src/opengl/qopenglfunctions_3_0.h b/src/opengl/qopenglfunctions_3_0.h
index 5276fc730a..01d6ccefaf 100644
--- a/src/opengl/qopenglfunctions_3_0.h
+++ b/src/opengl/qopenglfunctions_3_0.h
@@ -756,8 +756,8 @@ private:
QOpenGLFunctions_1_2_DeprecatedBackend* d_1_2_Deprecated;
QOpenGLFunctions_1_3_DeprecatedBackend* d_1_3_Deprecated;
QOpenGLFunctions_1_4_DeprecatedBackend* d_1_4_Deprecated;
- void *m_reserved_2_0_Deprecated; // To maintain BC
- void *m_reserved_3_0_Deprecated; // To maintain BC
+ Q_DECL_UNUSED_MEMBER void *m_reserved_2_0_Deprecated = nullptr; // To maintain BC
+ Q_DECL_UNUSED_MEMBER void *m_reserved_3_0_Deprecated = nullptr; // To maintain BC
};
// OpenGL 1.0 core functions
diff --git a/src/opengl/qopenglfunctions_3_2_compatibility.cpp b/src/opengl/qopenglfunctions_3_2_compatibility.cpp
index 6c90c569d7..c1b1806998 100644
--- a/src/opengl/qopenglfunctions_3_2_compatibility.cpp
+++ b/src/opengl/qopenglfunctions_3_2_compatibility.cpp
@@ -48,8 +48,6 @@ QOpenGLFunctions_3_2_Compatibility::QOpenGLFunctions_3_2_Compatibility()
, d_1_2_Deprecated(nullptr)
, d_1_3_Deprecated(nullptr)
, d_1_4_Deprecated(nullptr)
- , m_reserved_2_0_Deprecated(nullptr)
- , m_reserved_3_0_Deprecated(nullptr)
{
}
diff --git a/src/opengl/qopenglfunctions_3_2_compatibility.h b/src/opengl/qopenglfunctions_3_2_compatibility.h
index 416ceb2725..b01c232385 100644
--- a/src/opengl/qopenglfunctions_3_2_compatibility.h
+++ b/src/opengl/qopenglfunctions_3_2_compatibility.h
@@ -797,8 +797,8 @@ private:
QOpenGLFunctions_1_2_DeprecatedBackend* d_1_2_Deprecated;
QOpenGLFunctions_1_3_DeprecatedBackend* d_1_3_Deprecated;
QOpenGLFunctions_1_4_DeprecatedBackend* d_1_4_Deprecated;
- void *m_reserved_2_0_Deprecated; // To maintain BC
- void *m_reserved_3_0_Deprecated; // To maintain BC
+ Q_DECL_UNUSED_MEMBER void *m_reserved_2_0_Deprecated = nullptr; // To maintain BC
+ Q_DECL_UNUSED_MEMBER void *m_reserved_3_0_Deprecated = nullptr; // To maintain BC
};
// OpenGL 1.0 core functions
diff --git a/src/opengl/qopenglfunctions_3_3_compatibility.cpp b/src/opengl/qopenglfunctions_3_3_compatibility.cpp
index 0c61516ca1..60ef10553b 100644
--- a/src/opengl/qopenglfunctions_3_3_compatibility.cpp
+++ b/src/opengl/qopenglfunctions_3_3_compatibility.cpp
@@ -49,7 +49,6 @@ QOpenGLFunctions_3_3_Compatibility::QOpenGLFunctions_3_3_Compatibility()
, d_1_2_Deprecated(nullptr)
, d_1_3_Deprecated(nullptr)
, d_1_4_Deprecated(nullptr)
- , m_reserved_2_0_Deprecated(nullptr)
, d_3_3_Deprecated(nullptr)
{
}
diff --git a/src/opengl/qopenglfunctions_3_3_compatibility.h b/src/opengl/qopenglfunctions_3_3_compatibility.h
index 92f6bd8bde..25490648f3 100644
--- a/src/opengl/qopenglfunctions_3_3_compatibility.h
+++ b/src/opengl/qopenglfunctions_3_3_compatibility.h
@@ -860,7 +860,7 @@ private:
QOpenGLFunctions_1_2_DeprecatedBackend* d_1_2_Deprecated;
QOpenGLFunctions_1_3_DeprecatedBackend* d_1_3_Deprecated;
QOpenGLFunctions_1_4_DeprecatedBackend* d_1_4_Deprecated;
- void *m_reserved_2_0_Deprecated; // To maintain BC
+ Q_DECL_UNUSED_MEMBER void *m_reserved_2_0_Deprecated = nullptr; // To maintain BC
QOpenGLFunctions_3_3_DeprecatedBackend* d_3_3_Deprecated;
};
diff --git a/src/opengl/qopenglfunctions_4_0_compatibility.cpp b/src/opengl/qopenglfunctions_4_0_compatibility.cpp
index c380e73cb5..7074de5bde 100644
--- a/src/opengl/qopenglfunctions_4_0_compatibility.cpp
+++ b/src/opengl/qopenglfunctions_4_0_compatibility.cpp
@@ -50,7 +50,6 @@ QOpenGLFunctions_4_0_Compatibility::QOpenGLFunctions_4_0_Compatibility()
, d_1_2_Deprecated(nullptr)
, d_1_3_Deprecated(nullptr)
, d_1_4_Deprecated(nullptr)
- , m_reserved_2_0_Deprecated(nullptr)
, d_3_3_Deprecated(nullptr)
{
}
diff --git a/src/opengl/qopenglfunctions_4_0_compatibility.h b/src/opengl/qopenglfunctions_4_0_compatibility.h
index ba725464af..b72d01305a 100644
--- a/src/opengl/qopenglfunctions_4_0_compatibility.h
+++ b/src/opengl/qopenglfunctions_4_0_compatibility.h
@@ -911,7 +911,7 @@ private:
QOpenGLFunctions_1_2_DeprecatedBackend* d_1_2_Deprecated;
QOpenGLFunctions_1_3_DeprecatedBackend* d_1_3_Deprecated;
QOpenGLFunctions_1_4_DeprecatedBackend* d_1_4_Deprecated;
- void *m_reserved_2_0_Deprecated; // To maintain BC
+ Q_DECL_UNUSED_MEMBER void *m_reserved_2_0_Deprecated = nullptr; // To maintain BC
QOpenGLFunctions_3_3_DeprecatedBackend* d_3_3_Deprecated;
};
diff --git a/src/opengl/qopenglfunctions_4_1_compatibility.cpp b/src/opengl/qopenglfunctions_4_1_compatibility.cpp
index 399fd5c990..035cc79276 100644
--- a/src/opengl/qopenglfunctions_4_1_compatibility.cpp
+++ b/src/opengl/qopenglfunctions_4_1_compatibility.cpp
@@ -51,7 +51,6 @@ QOpenGLFunctions_4_1_Compatibility::QOpenGLFunctions_4_1_Compatibility()
, d_1_2_Deprecated(nullptr)
, d_1_3_Deprecated(nullptr)
, d_1_4_Deprecated(nullptr)
- , m_reserved_2_0_Deprecated(nullptr)
, d_3_3_Deprecated(nullptr)
{
}
diff --git a/src/opengl/qopenglfunctions_4_1_compatibility.h b/src/opengl/qopenglfunctions_4_1_compatibility.h
index ee8ab6be44..08b7c05232 100644
--- a/src/opengl/qopenglfunctions_4_1_compatibility.h
+++ b/src/opengl/qopenglfunctions_4_1_compatibility.h
@@ -1004,7 +1004,7 @@ private:
QOpenGLFunctions_1_2_DeprecatedBackend* d_1_2_Deprecated;
QOpenGLFunctions_1_3_DeprecatedBackend* d_1_3_Deprecated;
QOpenGLFunctions_1_4_DeprecatedBackend* d_1_4_Deprecated;
- void *m_reserved_2_0_Deprecated; // To maintain BC
+ Q_DECL_UNUSED_MEMBER void *m_reserved_2_0_Deprecated = nullptr; // To maintain BC
QOpenGLFunctions_3_3_DeprecatedBackend* d_3_3_Deprecated;
};
diff --git a/src/opengl/qopenglfunctions_4_2_compatibility.cpp b/src/opengl/qopenglfunctions_4_2_compatibility.cpp
index 5bf2eedbaf..faf0ca845f 100644
--- a/src/opengl/qopenglfunctions_4_2_compatibility.cpp
+++ b/src/opengl/qopenglfunctions_4_2_compatibility.cpp
@@ -52,7 +52,6 @@ QOpenGLFunctions_4_2_Compatibility::QOpenGLFunctions_4_2_Compatibility()
, d_1_2_Deprecated(nullptr)
, d_1_3_Deprecated(nullptr)
, d_1_4_Deprecated(nullptr)
- , m_reserved_2_0_Deprecated(nullptr)
, d_3_3_Deprecated(nullptr)
{
}
diff --git a/src/opengl/qopenglfunctions_4_2_compatibility.h b/src/opengl/qopenglfunctions_4_2_compatibility.h
index ca5b4127db..2bc4f8b228 100644
--- a/src/opengl/qopenglfunctions_4_2_compatibility.h
+++ b/src/opengl/qopenglfunctions_4_2_compatibility.h
@@ -1027,7 +1027,7 @@ private:
QOpenGLFunctions_1_2_DeprecatedBackend* d_1_2_Deprecated;
QOpenGLFunctions_1_3_DeprecatedBackend* d_1_3_Deprecated;
QOpenGLFunctions_1_4_DeprecatedBackend* d_1_4_Deprecated;
- void *m_reserved_2_0_Deprecated; // To maintain BC
+ Q_DECL_UNUSED_MEMBER void *m_reserved_2_0_Deprecated = nullptr; // To maintain BC
QOpenGLFunctions_3_3_DeprecatedBackend* d_3_3_Deprecated;
};
diff --git a/src/opengl/qopenglfunctions_4_3_compatibility.cpp b/src/opengl/qopenglfunctions_4_3_compatibility.cpp
index c401a93189..c3a3d5d32b 100644
--- a/src/opengl/qopenglfunctions_4_3_compatibility.cpp
+++ b/src/opengl/qopenglfunctions_4_3_compatibility.cpp
@@ -53,7 +53,6 @@ QOpenGLFunctions_4_3_Compatibility::QOpenGLFunctions_4_3_Compatibility()
, d_1_2_Deprecated(nullptr)
, d_1_3_Deprecated(nullptr)
, d_1_4_Deprecated(nullptr)
- , m_reserved_2_0_Deprecated(nullptr)
, d_3_3_Deprecated(nullptr)
{
}
diff --git a/src/opengl/qopenglfunctions_4_3_compatibility.h b/src/opengl/qopenglfunctions_4_3_compatibility.h
index e79cecb542..0370637653 100644
--- a/src/opengl/qopenglfunctions_4_3_compatibility.h
+++ b/src/opengl/qopenglfunctions_4_3_compatibility.h
@@ -1065,7 +1065,7 @@ private:
QOpenGLFunctions_1_2_DeprecatedBackend* d_1_2_Deprecated;
QOpenGLFunctions_1_3_DeprecatedBackend* d_1_3_Deprecated;
QOpenGLFunctions_1_4_DeprecatedBackend* d_1_4_Deprecated;
- void *m_reserved_2_0_Deprecated; // To maintain BC
+ Q_DECL_UNUSED_MEMBER void *m_reserved_2_0_Deprecated = nullptr; // To maintain BC
QOpenGLFunctions_3_3_DeprecatedBackend* d_3_3_Deprecated;
};
diff --git a/src/opengl/qopenglfunctions_4_5_compatibility.h b/src/opengl/qopenglfunctions_4_5_compatibility.h
index 229a0b4288..cca3eae9e2 100644
--- a/src/opengl/qopenglfunctions_4_5_compatibility.h
+++ b/src/opengl/qopenglfunctions_4_5_compatibility.h
@@ -700,25 +700,52 @@ public:
void glNamedFramebufferParameteri(GLuint framebuffer, GLenum pname, GLint param);
void glNamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
void glCreateFramebuffers(GLsizei n, GLuint *framebuffers);
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+ void glGetNamedBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, void *data);
+#else
void glGetNamedBufferSubData(GLuint buffer, GLintptr offset, GLsizei size, void *data);
+#endif
void glGetNamedBufferPointerv(GLuint buffer, GLenum pname, void * *params);
void glGetNamedBufferParameteri64v(GLuint buffer, GLenum pname, GLint64 *params);
void glGetNamedBufferParameteriv(GLuint buffer, GLenum pname, GLint *params);
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+ void glFlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length);
+#else
void glFlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, GLsizei length);
+#endif
GLboolean glUnmapNamedBuffer(GLuint buffer);
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+ void * glMapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access);
+#else
void * glMapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizei length, GLbitfield access);
+#endif
void * glMapNamedBuffer(GLuint buffer, GLenum access);
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+ void glClearNamedBufferSubData(GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
+#else
void glClearNamedBufferSubData(GLuint buffer, GLenum internalformat, GLintptr offset, GLsizei size, GLenum format, GLenum type, const void *data);
+#endif
void glClearNamedBufferData(GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data);
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+ void glCopyNamedBufferSubData(GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+ void glNamedBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);
+ void glNamedBufferData(GLuint buffer, GLsizeiptr size, const void *data, GLenum usage);
+ void glNamedBufferStorage(GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags);
+#else
void glCopyNamedBufferSubData(GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizei size);
void glNamedBufferSubData(GLuint buffer, GLintptr offset, GLsizei size, const void *data);
void glNamedBufferData(GLuint buffer, GLsizei size, const void *data, GLenum usage);
void glNamedBufferStorage(GLuint buffer, GLsizei size, const void *data, GLbitfield flags);
+#endif
void glCreateBuffers(GLsizei n, GLuint *buffers);
void glGetTransformFeedbacki64_v(GLuint xfb, GLenum pname, GLuint index, GLint64 *param);
void glGetTransformFeedbacki_v(GLuint xfb, GLenum pname, GLuint index, GLint *param);
void glGetTransformFeedbackiv(GLuint xfb, GLenum pname, GLint *param);
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+ void glTransformFeedbackBufferRange(GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+#else
void glTransformFeedbackBufferRange(GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizei size);
+#endif
void glTransformFeedbackBufferBase(GLuint xfb, GLuint index, GLuint buffer);
void glCreateTransformFeedbacks(GLsizei n, GLuint *ids);
void glClipControl(GLenum origin, GLenum depth);
@@ -4381,7 +4408,11 @@ inline void QOpenGLFunctions_4_5_Compatibility::glCreateFramebuffers(GLsizei n,
d_4_5_Core->f.CreateFramebuffers(n, framebuffers);
}
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+inline void QOpenGLFunctions_4_5_Compatibility::glGetNamedBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, void *data)
+#else
inline void QOpenGLFunctions_4_5_Compatibility::glGetNamedBufferSubData(GLuint buffer, GLintptr offset, GLsizei size, void *data)
+#endif
{
d_4_5_Core->f.GetNamedBufferSubData(buffer, offset, size, data);
}
@@ -4401,7 +4432,11 @@ inline void QOpenGLFunctions_4_5_Compatibility::glGetNamedBufferParameteriv(GLui
d_4_5_Core->f.GetNamedBufferParameteriv(buffer, pname, params);
}
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+inline void QOpenGLFunctions_4_5_Compatibility::glFlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length)
+#else
inline void QOpenGLFunctions_4_5_Compatibility::glFlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, GLsizei length)
+#endif
{
d_4_5_Core->f.FlushMappedNamedBufferRange(buffer, offset, length);
}
@@ -4411,7 +4446,11 @@ inline GLboolean QOpenGLFunctions_4_5_Compatibility::glUnmapNamedBuffer(GLuint b
return d_4_5_Core->f.UnmapNamedBuffer(buffer);
}
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+inline void * QOpenGLFunctions_4_5_Compatibility::glMapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access)
+#else
inline void * QOpenGLFunctions_4_5_Compatibility::glMapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizei length, GLbitfield access)
+#endif
{
return d_4_5_Core->f.MapNamedBufferRange(buffer, offset, length, access);
}
@@ -4421,7 +4460,11 @@ inline void * QOpenGLFunctions_4_5_Compatibility::glMapNamedBuffer(GLuint buffer
return d_4_5_Core->f.MapNamedBuffer(buffer, access);
}
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+inline void QOpenGLFunctions_4_5_Compatibility::glClearNamedBufferSubData(GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data)
+#else
inline void QOpenGLFunctions_4_5_Compatibility::glClearNamedBufferSubData(GLuint buffer, GLenum internalformat, GLintptr offset, GLsizei size, GLenum format, GLenum type, const void *data)
+#endif
{
d_4_5_Core->f.ClearNamedBufferSubData(buffer, internalformat, offset, size, format, type, data);
}
@@ -4431,22 +4474,38 @@ inline void QOpenGLFunctions_4_5_Compatibility::glClearNamedBufferData(GLuint bu
d_4_5_Core->f.ClearNamedBufferData(buffer, internalformat, format, type, data);
}
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+inline void QOpenGLFunctions_4_5_Compatibility::glCopyNamedBufferSubData(GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size)
+#else
inline void QOpenGLFunctions_4_5_Compatibility::glCopyNamedBufferSubData(GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizei size)
+#endif
{
d_4_5_Core->f.CopyNamedBufferSubData(readBuffer, writeBuffer, readOffset, writeOffset, size);
}
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+inline void QOpenGLFunctions_4_5_Compatibility::glNamedBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data)
+#else
inline void QOpenGLFunctions_4_5_Compatibility::glNamedBufferSubData(GLuint buffer, GLintptr offset, GLsizei size, const void *data)
+#endif
{
d_4_5_Core->f.NamedBufferSubData(buffer, offset, size, data);
}
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+inline void QOpenGLFunctions_4_5_Compatibility::glNamedBufferData(GLuint buffer, GLsizeiptr size, const void *data, GLenum usage)
+#else
inline void QOpenGLFunctions_4_5_Compatibility::glNamedBufferData(GLuint buffer, GLsizei size, const void *data, GLenum usage)
+#endif
{
d_4_5_Core->f.NamedBufferData(buffer, size, data, usage);
}
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+inline void QOpenGLFunctions_4_5_Compatibility::glNamedBufferStorage(GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags)
+#else
inline void QOpenGLFunctions_4_5_Compatibility::glNamedBufferStorage(GLuint buffer, GLsizei size, const void *data, GLbitfield flags)
+#endif
{
d_4_5_Core->f.NamedBufferStorage(buffer, size, data, flags);
}
@@ -4471,7 +4530,11 @@ inline void QOpenGLFunctions_4_5_Compatibility::glGetTransformFeedbackiv(GLuint
d_4_5_Core->f.GetTransformFeedbackiv(xfb, pname, param);
}
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+inline void QOpenGLFunctions_4_5_Compatibility::glTransformFeedbackBufferRange(GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size)
+#else
inline void QOpenGLFunctions_4_5_Compatibility::glTransformFeedbackBufferRange(GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizei size)
+#endif
{
d_4_5_Core->f.TransformFeedbackBufferRange(xfb, index, buffer, offset, size);
}
diff --git a/src/opengl/qopenglfunctions_4_5_core.h b/src/opengl/qopenglfunctions_4_5_core.h
index 24ad0fd544..e3944f0741 100644
--- a/src/opengl/qopenglfunctions_4_5_core.h
+++ b/src/opengl/qopenglfunctions_4_5_core.h
@@ -700,25 +700,52 @@ public:
void glNamedFramebufferParameteri(GLuint framebuffer, GLenum pname, GLint param);
void glNamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
void glCreateFramebuffers(GLsizei n, GLuint *framebuffers);
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+ void glGetNamedBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, void *data);
+#else
void glGetNamedBufferSubData(GLuint buffer, GLintptr offset, GLsizei size, void *data);
+#endif
void glGetNamedBufferPointerv(GLuint buffer, GLenum pname, void * *params);
void glGetNamedBufferParameteri64v(GLuint buffer, GLenum pname, GLint64 *params);
void glGetNamedBufferParameteriv(GLuint buffer, GLenum pname, GLint *params);
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+ void glFlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length);
+#else
void glFlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, GLsizei length);
+#endif
GLboolean glUnmapNamedBuffer(GLuint buffer);
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+ void * glMapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access);
+#else
void * glMapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizei length, GLbitfield access);
+#endif
void * glMapNamedBuffer(GLuint buffer, GLenum access);
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+ void glClearNamedBufferSubData(GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data);
+#else
void glClearNamedBufferSubData(GLuint buffer, GLenum internalformat, GLintptr offset, GLsizei size, GLenum format, GLenum type, const void *data);
+#endif
void glClearNamedBufferData(GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data);
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+ void glCopyNamedBufferSubData(GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+ void glNamedBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data);
+ void glNamedBufferData(GLuint buffer, GLsizeiptr size, const void *data, GLenum usage);
+ void glNamedBufferStorage(GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags);
+#else
void glCopyNamedBufferSubData(GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizei size);
void glNamedBufferSubData(GLuint buffer, GLintptr offset, GLsizei size, const void *data);
void glNamedBufferData(GLuint buffer, GLsizei size, const void *data, GLenum usage);
void glNamedBufferStorage(GLuint buffer, GLsizei size, const void *data, GLbitfield flags);
+#endif
void glCreateBuffers(GLsizei n, GLuint *buffers);
void glGetTransformFeedbacki64_v(GLuint xfb, GLenum pname, GLuint index, GLint64 *param);
void glGetTransformFeedbacki_v(GLuint xfb, GLenum pname, GLuint index, GLint *param);
void glGetTransformFeedbackiv(GLuint xfb, GLenum pname, GLint *param);
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+ void glTransformFeedbackBufferRange(GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+#else
void glTransformFeedbackBufferRange(GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizei size);
+#endif
void glTransformFeedbackBufferBase(GLuint xfb, GLuint index, GLuint buffer);
void glCreateTransformFeedbacks(GLsizei n, GLuint *ids);
void glClipControl(GLenum origin, GLenum depth);
@@ -3914,7 +3941,11 @@ inline void QOpenGLFunctions_4_5_Core::glCreateFramebuffers(GLsizei n, GLuint *f
d_4_5_Core->f.CreateFramebuffers(n, framebuffers);
}
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+inline void QOpenGLFunctions_4_5_Core::glGetNamedBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, void *data)
+#else
inline void QOpenGLFunctions_4_5_Core::glGetNamedBufferSubData(GLuint buffer, GLintptr offset, GLsizei size, void *data)
+#endif
{
d_4_5_Core->f.GetNamedBufferSubData(buffer, offset, size, data);
}
@@ -3934,7 +3965,11 @@ inline void QOpenGLFunctions_4_5_Core::glGetNamedBufferParameteriv(GLuint buffer
d_4_5_Core->f.GetNamedBufferParameteriv(buffer, pname, params);
}
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+inline void QOpenGLFunctions_4_5_Core::glFlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length)
+#else
inline void QOpenGLFunctions_4_5_Core::glFlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, GLsizei length)
+#endif
{
d_4_5_Core->f.FlushMappedNamedBufferRange(buffer, offset, length);
}
@@ -3944,7 +3979,11 @@ inline GLboolean QOpenGLFunctions_4_5_Core::glUnmapNamedBuffer(GLuint buffer)
return d_4_5_Core->f.UnmapNamedBuffer(buffer);
}
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+inline void * QOpenGLFunctions_4_5_Core::glMapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access)
+#else
inline void * QOpenGLFunctions_4_5_Core::glMapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizei length, GLbitfield access)
+#endif
{
return d_4_5_Core->f.MapNamedBufferRange(buffer, offset, length, access);
}
@@ -3954,7 +3993,11 @@ inline void * QOpenGLFunctions_4_5_Core::glMapNamedBuffer(GLuint buffer, GLenum
return d_4_5_Core->f.MapNamedBuffer(buffer, access);
}
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+inline void QOpenGLFunctions_4_5_Core::glClearNamedBufferSubData(GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data)
+#else
inline void QOpenGLFunctions_4_5_Core::glClearNamedBufferSubData(GLuint buffer, GLenum internalformat, GLintptr offset, GLsizei size, GLenum format, GLenum type, const void *data)
+#endif
{
d_4_5_Core->f.ClearNamedBufferSubData(buffer, internalformat, offset, size, format, type, data);
}
@@ -3964,22 +4007,38 @@ inline void QOpenGLFunctions_4_5_Core::glClearNamedBufferData(GLuint buffer, GLe
d_4_5_Core->f.ClearNamedBufferData(buffer, internalformat, format, type, data);
}
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+inline void QOpenGLFunctions_4_5_Core::glCopyNamedBufferSubData(GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size)
+#else
inline void QOpenGLFunctions_4_5_Core::glCopyNamedBufferSubData(GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizei size)
+#endif
{
d_4_5_Core->f.CopyNamedBufferSubData(readBuffer, writeBuffer, readOffset, writeOffset, size);
}
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+inline void QOpenGLFunctions_4_5_Core::glNamedBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data)
+#else
inline void QOpenGLFunctions_4_5_Core::glNamedBufferSubData(GLuint buffer, GLintptr offset, GLsizei size, const void *data)
+#endif
{
d_4_5_Core->f.NamedBufferSubData(buffer, offset, size, data);
}
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+inline void QOpenGLFunctions_4_5_Core::glNamedBufferData(GLuint buffer, GLsizeiptr size, const void *data, GLenum usage)
+#else
inline void QOpenGLFunctions_4_5_Core::glNamedBufferData(GLuint buffer, GLsizei size, const void *data, GLenum usage)
+#endif
{
d_4_5_Core->f.NamedBufferData(buffer, size, data, usage);
}
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+inline void QOpenGLFunctions_4_5_Core::glNamedBufferStorage(GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags)
+#else
inline void QOpenGLFunctions_4_5_Core::glNamedBufferStorage(GLuint buffer, GLsizei size, const void *data, GLbitfield flags)
+#endif
{
d_4_5_Core->f.NamedBufferStorage(buffer, size, data, flags);
}
@@ -4004,7 +4063,11 @@ inline void QOpenGLFunctions_4_5_Core::glGetTransformFeedbackiv(GLuint xfb, GLen
d_4_5_Core->f.GetTransformFeedbackiv(xfb, pname, param);
}
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+inline void QOpenGLFunctions_4_5_Core::glTransformFeedbackBufferRange(GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size)
+#else
inline void QOpenGLFunctions_4_5_Core::glTransformFeedbackBufferRange(GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizei size)
+#endif
{
d_4_5_Core->f.TransformFeedbackBufferRange(xfb, index, buffer, offset, size);
}
diff --git a/src/opengl/qopenglversionfunctions.h b/src/opengl/qopenglversionfunctions.h
index c1942548db..dc01b940bb 100644
--- a/src/opengl/qopenglversionfunctions.h
+++ b/src/opengl/qopenglversionfunctions.h
@@ -1179,25 +1179,25 @@ public:
F(void, NamedFramebufferParameteri, (GLuint framebuffer, GLenum pname, GLint param)) \
F(void, NamedFramebufferRenderbuffer, (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)) \
F(void, CreateFramebuffers, (GLsizei n, GLuint *framebuffers)) \
- F(void, GetNamedBufferSubData, (GLuint buffer, GLintptr offset, GLsizei size, void *data)) \
+ F(void, GetNamedBufferSubData, (GLuint buffer, GLintptr offset, GLsizeiptr size, void *data)) \
F(void, GetNamedBufferPointerv, (GLuint buffer, GLenum pname, GLvoid* *params)) \
F(void, GetNamedBufferParameteri64v, (GLuint buffer, GLenum pname, GLint64 *params)) \
F(void, GetNamedBufferParameteriv, (GLuint buffer, GLenum pname, GLint *params)) \
- F(void, FlushMappedNamedBufferRange, (GLuint buffer, GLintptr offset, GLsizei length)) \
+ F(void, FlushMappedNamedBufferRange, (GLuint buffer, GLintptr offset, GLsizeiptr length)) \
F(GLboolean, UnmapNamedBuffer, (GLuint buffer)) \
- F(GLvoid *, MapNamedBufferRange, (GLuint buffer, GLintptr offset, GLsizei length, GLbitfield access)) \
+ F(GLvoid *, MapNamedBufferRange, (GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access)) \
F(GLvoid *, MapNamedBuffer, (GLuint buffer, GLenum access)) \
- F(void, ClearNamedBufferSubData, (GLuint buffer, GLenum internalformat, GLintptr offset, GLsizei size, GLenum format, GLenum type, const void *data)) \
+ F(void, ClearNamedBufferSubData, (GLuint buffer, GLenum internalformat, GLintptr offset, GLsizeiptr size, GLenum format, GLenum type, const void *data)) \
F(void, ClearNamedBufferData, (GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data)) \
- F(void, CopyNamedBufferSubData, (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizei size)) \
- F(void, NamedBufferSubData, (GLuint buffer, GLintptr offset, GLsizei size, const void *data)) \
- F(void, NamedBufferData, (GLuint buffer, GLsizei size, const void *data, GLenum usage)) \
- F(void, NamedBufferStorage, (GLuint buffer, GLsizei size, const void *data, GLbitfield flags)) \
+ F(void, CopyNamedBufferSubData, (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size)) \
+ F(void, NamedBufferSubData, (GLuint buffer, GLintptr offset, GLsizeiptr size, const void *data)) \
+ F(void, NamedBufferData, (GLuint buffer, GLsizeiptr size, const void *data, GLenum usage)) \
+ F(void, NamedBufferStorage, (GLuint buffer, GLsizeiptr size, const void *data, GLbitfield flags)) \
F(void, CreateBuffers, (GLsizei n, GLuint *buffers)) \
F(void, GetTransformFeedbacki64_v,(GLuint xfb, GLenum pname, GLuint index, GLint64 *param)) \
F(void, GetTransformFeedbacki_v,(GLuint xfb, GLenum pname, GLuint index, GLint *param)) \
F(void, GetTransformFeedbackiv, (GLuint xfb, GLenum pname, GLint *param)) \
- F(void, TransformFeedbackBufferRange, (GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizei size)) \
+ F(void, TransformFeedbackBufferRange, (GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size)) \
F(void, TransformFeedbackBufferBase, (GLuint xfb, GLuint index, GLuint buffer)) \
F(void, CreateTransformFeedbacks, (GLsizei n, GLuint *ids)) \
F(void, ClipControl, (GLenum origin, GLenum depth)) \
diff --git a/src/opengl/qopenglversionfunctionsfactory.cpp b/src/opengl/qopenglversionfunctionsfactory.cpp
index aad4971fd3..12d00c0554 100644
--- a/src/opengl/qopenglversionfunctionsfactory.cpp
+++ b/src/opengl/qopenglversionfunctionsfactory.cpp
@@ -135,7 +135,7 @@ static QAbstractOpenGLFunctions *createFunctions(const QOpenGLVersionProfile &ve
*/
/*!
- \fn static T *QOpenGLVersionFunctionsFactory::get(QOpenGLContext *context)
+ \fn template <class T> static T *QOpenGLVersionFunctionsFactory::get(QOpenGLContext *context)
\overload get()
diff --git a/src/opengl/qopenglwindow.cpp b/src/opengl/qopenglwindow.cpp
index b2a1a35a90..a3677aa828 100644
--- a/src/opengl/qopenglwindow.cpp
+++ b/src/opengl/qopenglwindow.cpp
@@ -44,7 +44,7 @@ QT_BEGIN_NAMESPACE
immediately result in a call to paintGL(). Calling update() multiple times in
a row will not change the behavior in any way.
- This is a slot so it can be connected to a \l QTimer::timeout() signal to
+ This is a slot so it can be connected to a \l QChronoTimer::timeout() signal to
perform animation. Note however that in the modern OpenGL world it is a much
better choice to rely on synchronization to the vertical refresh rate of the
display. See \l{QSurfaceFormat::setSwapInterval()}{setSwapInterval()} on a
diff --git a/src/openglwidgets/CMakeLists.txt b/src/openglwidgets/CMakeLists.txt
index e28b30bd8e..af3efdf30f 100644
--- a/src/openglwidgets/CMakeLists.txt
+++ b/src/openglwidgets/CMakeLists.txt
@@ -10,8 +10,10 @@ qt_internal_add_module(OpenGLWidgets
qopenglwidget.cpp qopenglwidget.h
qtopenglwidgetsglobal.h
DEFINES
+ QT_NO_CONTEXTLESS_CONNECT
QT_NO_FOREACH
QT_NO_USING_NAMESPACE
+ QT_USE_NODISCARD_FILE_OPEN
LIBRARIES
Qt::OpenGLPrivate
Qt::WidgetsPrivate
diff --git a/src/openglwidgets/qopenglwidget.cpp b/src/openglwidgets/qopenglwidget.cpp
index d5f4e769d9..4a0bf7f492 100644
--- a/src/openglwidgets/qopenglwidget.cpp
+++ b/src/openglwidgets/qopenglwidget.cpp
@@ -23,8 +23,7 @@
#include <QtWidgets/private/qwidget_p.h>
#include <QtWidgets/private/qwidgetrepaintmanager_p.h>
-#include <QtGui/private/qrhi_p.h>
-#include <QtGui/private/qrhigles2_p.h>
+#include <rhi/qrhi.h>
QT_BEGIN_NAMESPACE
@@ -57,7 +56,7 @@ QT_BEGIN_NAMESPACE
\endlist
If you need to trigger a repaint from places other than paintGL() (a
- typical example is when using \l{QTimer}{timers} to animate scenes),
+ typical example is when using \l{QChronoTimer}{timers} to animate scenes),
you should call the widget's update() function to schedule an update.
Your widget's OpenGL rendering context is made current when
@@ -505,9 +504,8 @@ QT_BEGIN_NAMESPACE
benefits on certain hardware architectures common in the mobile and
embedded space when a framebuffer object is used as the rendering target.
The framebuffer object is invalidated between frames with
- glDiscardFramebufferEXT if supported or a glClear. Please see the
- documentation of EXT_discard_framebuffer for more information:
- https://www.khronos.org/registry/gles/extensions/EXT/EXT_discard_framebuffer.txt
+ glInvalidateFramebuffer (if supported), or, as fallbacks,
+ glDiscardFramebufferEXT (if supported) or a call to glClear.
\value PartialUpdate The framebuffer objects color buffer and ancillary
buffers are not invalidated between frames.
@@ -555,7 +553,13 @@ public:
void initialize();
void render();
- void invalidateFbo();
+ static constexpr GLenum gl_color_attachment0 = 0x8CE0; // GL_COLOR_ATTACHMENT0
+ static constexpr GLenum gl_depth_attachment = 0x8D00; // GL_DEPTH_ATTACHMENT
+ static constexpr GLenum gl_stencil_attachment = 0x8D20; // GL_STENCIL_ATTACHMENT
+ static constexpr GLenum gl_depth_stencil_attachment = 0x821A; // GL_DEPTH_STENCIL_ATTACHMENT
+
+ void invalidateFboBeforePainting();
+ void invalidateFboAfterPainting();
void destroyFbos();
@@ -691,8 +695,6 @@ void QOpenGLWidgetPrivate::reset()
destroyFbos();
- resetRhiDependentResources();
-
if (initialized)
q->doneCurrent();
@@ -782,9 +784,7 @@ void QOpenGLWidgetPrivate::ensureRhiDependentResources()
{
Q_Q(QOpenGLWidget);
- QRhi *rhi = nullptr;
- if (QWidgetRepaintManager *repaintManager = QWidgetPrivate::get(q->window())->maybeRepaintManager())
- rhi = repaintManager->rhi();
+ QRhi *rhi = QWidgetPrivate::rhi();
// If there is no rhi, because we are completely offscreen, then there's no wrapperTexture either
if (rhi && rhi->backend() == QRhi::OpenGLES2) {
@@ -830,7 +830,6 @@ void QOpenGLWidgetPrivate::initialize()
// If no global shared context get our toplevel's context with which we
// will share in order to make the texture usable by the underlying window's backingstore.
QWidget *tlw = q->window();
- QWidgetPrivate *tlwd = get(tlw);
// Do not include the sample count. Requesting a multisampled context is not necessary
// since we render into an FBO, never to an actual surface. What's more, attempting to
@@ -839,9 +838,7 @@ void QOpenGLWidgetPrivate::initialize()
requestedSamples = requestedFormat.samples();
requestedFormat.setSamples(0);
- QRhi *rhi = nullptr;
- if (QWidgetRepaintManager *repaintManager = tlwd->maybeRepaintManager())
- rhi = repaintManager->rhi();
+ QRhi *rhi = QWidgetPrivate::rhi();
// Could be that something else already initialized the window with some
// other graphics API for the QRhi, that's not good.
@@ -858,9 +855,11 @@ void QOpenGLWidgetPrivate::initialize()
context = new QOpenGLContext;
context->setFormat(requestedFormat);
- if (contextFromRhi) {
- context->setShareContext(contextFromRhi);
- context->setScreen(contextFromRhi->screen());
+
+ QOpenGLContext *shareContext = contextFromRhi ? contextFromRhi : qt_gl_global_share_context();
+ if (shareContext) {
+ context->setShareContext(shareContext);
+ context->setScreen(shareContext->screen());
}
if (Q_UNLIKELY(!context->create())) {
qWarning("QOpenGLWidget: Failed to create context");
@@ -950,11 +949,11 @@ void QOpenGLWidgetPrivate::render()
}
if (updateBehavior == QOpenGLWidget::NoPartialUpdate && hasBeenComposed) {
- invalidateFbo();
+ invalidateFboBeforePainting();
if (stereo && fbos[QOpenGLWidget::RightBuffer]) {
setCurrentTargetBuffer(QOpenGLWidget::RightBuffer);
- invalidateFbo();
+ invalidateFboBeforePainting();
setCurrentTargetBuffer(QOpenGLWidget::LeftBuffer);
}
@@ -965,13 +964,26 @@ void QOpenGLWidgetPrivate::render()
f->glViewport(0, 0, q->width() * q->devicePixelRatio(), q->height() * q->devicePixelRatio());
inPaintGL = true;
+#ifdef Q_OS_WASM
+ f->glDepthMask(GL_TRUE);
+#endif
+
QOpenGLContextPrivate::get(ctx)->defaultFboRedirect = fbos[currentTargetBuffer]->handle();
+
+ f->glUseProgram(0);
+ f->glBindBuffer(GL_ARRAY_BUFFER, 0);
+ f->glEnable(GL_BLEND);
+
q->paintGL();
+ if (updateBehavior == QOpenGLWidget::NoPartialUpdate)
+ invalidateFboAfterPainting();
if (stereo && fbos[QOpenGLWidget::RightBuffer]) {
setCurrentTargetBuffer(QOpenGLWidget::RightBuffer);
QOpenGLContextPrivate::get(ctx)->defaultFboRedirect = fbos[currentTargetBuffer]->handle();
q->paintGL();
+ if (updateBehavior == QOpenGLWidget::NoPartialUpdate)
+ invalidateFboAfterPainting();
}
QOpenGLContextPrivate::get(ctx)->defaultFboRedirect = 0;
@@ -979,32 +991,43 @@ void QOpenGLWidgetPrivate::render()
flushPending = true;
}
-void QOpenGLWidgetPrivate::invalidateFbo()
+void QOpenGLWidgetPrivate::invalidateFboBeforePainting()
{
QOpenGLExtensions *f = static_cast<QOpenGLExtensions *>(QOpenGLContext::currentContext()->functions());
if (f->hasOpenGLExtension(QOpenGLExtensions::DiscardFramebuffer)) {
- const int gl_color_attachment0 = 0x8CE0; // GL_COLOR_ATTACHMENT0
- const int gl_depth_attachment = 0x8D00; // GL_DEPTH_ATTACHMENT
- const int gl_stencil_attachment = 0x8D20; // GL_STENCIL_ATTACHMENT
-#ifdef Q_OS_WASM
- // webgl does not allow separate depth and stencil attachments
- // QTBUG-69913
- const int gl_depth_stencil_attachment = 0x821A; // GL_DEPTH_STENCIL_ATTACHMENT
-
const GLenum attachments[] = {
- gl_color_attachment0, gl_depth_attachment, gl_stencil_attachment, gl_depth_stencil_attachment
- };
-#else
- const GLenum attachments[] = {
- gl_color_attachment0, gl_depth_attachment, gl_stencil_attachment
- };
+ gl_color_attachment0,
+ gl_depth_attachment,
+ gl_stencil_attachment,
+#ifdef Q_OS_WASM
+ // webgl does not allow separate depth and stencil attachments
+ // QTBUG-69913
+ gl_depth_stencil_attachment
#endif
- f->glDiscardFramebufferEXT(GL_FRAMEBUFFER, sizeof attachments / sizeof *attachments, attachments);
+ };
+ f->discardFramebuffer(GL_FRAMEBUFFER, GLsizei(std::size(attachments)), attachments);
} else {
f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
}
+void QOpenGLWidgetPrivate::invalidateFboAfterPainting()
+{
+ QOpenGLExtensions *f = static_cast<QOpenGLExtensions *>(QOpenGLContext::currentContext()->functions());
+ if (f->hasOpenGLExtension(QOpenGLExtensions::DiscardFramebuffer)) {
+ const GLenum attachments[] = {
+ gl_depth_attachment,
+ gl_stencil_attachment,
+#ifdef Q_OS_WASM
+ // webgl does not allow separate depth and stencil attachments
+ // QTBUG-69913
+ gl_depth_stencil_attachment
+#endif
+ };
+ f->discardFramebuffer(GL_FRAMEBUFFER, GLsizei(std::size(attachments)), attachments);
+ }
+}
+
void QOpenGLWidgetPrivate::destroyFbos()
{
delete fbos[QOpenGLWidget::LeftBuffer];
@@ -1016,6 +1039,8 @@ void QOpenGLWidgetPrivate::destroyFbos()
fbos[QOpenGLWidget::RightBuffer] = nullptr;
delete resolvedFbos[QOpenGLWidget::RightBuffer];
resolvedFbos[QOpenGLWidget::RightBuffer] = nullptr;
+
+ resetRhiDependentResources();
}
QImage QOpenGLWidgetPrivate::grabFramebuffer()
@@ -1387,7 +1412,7 @@ GLuint QOpenGLWidget::defaultFramebufferObject(TargetBuffer targetBuffer) const
This virtual function is called once before the first call to
paintGL() or resizeGL(). Reimplement it in a subclass.
- This function should set up any required OpenGL resources and state.
+ This function should set up any required OpenGL resources.
There is no need to call makeCurrent() because this has already been
done when this function is called. Note however that the framebuffer
@@ -1429,6 +1454,17 @@ void QOpenGLWidget::resizeGL(int w, int h)
other state is set and no clearing or drawing is performed by the
framework.
+ The default implementation performs a glClear(). Subclasses are not expected
+ to invoke the base class implementation and should perform clearing on their
+ own.
+
+ \note To ensure portability, do not expect that state set in initializeGL()
+ persists. Rather, set all necessary state, for example, by calling
+ glEnable(), in paintGL(). This is because some platforms, such as WebAssembly
+ with WebGL, may have limitations on OpenGL contexts in some situations, which
+ can lead to using the context used with the QOpenGLWidget for other purposes
+ as well.
+
When \l QSurfaceFormat::StereoBuffers is enabled, this function
will be called twice - once for each buffer. Query what buffer is
currently bound by calling currentTargetBuffer().
@@ -1441,6 +1477,9 @@ void QOpenGLWidget::resizeGL(int w, int h)
*/
void QOpenGLWidget::paintGL()
{
+ Q_D(QOpenGLWidget);
+ if (d->initialized)
+ d->context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
/*!
@@ -1598,15 +1637,9 @@ int QOpenGLWidget::metric(QPaintDevice::PaintDeviceMetric metric) const
else
return qRound(dpmy * 0.0254);
case PdmDevicePixelRatio:
- if (window)
- return int(window->devicePixelRatio());
- else
- return 1.0;
+ return QWidget::metric(metric);
case PdmDevicePixelRatioScaled:
- if (window)
- return int(window->devicePixelRatio() * devicePixelRatioFScale());
- else
- return int(devicePixelRatioFScale());
+ return QWidget::metric(metric);
default:
qWarning("QOpenGLWidget::metric(): unknown metric %d", metric);
return 0;
@@ -1682,8 +1715,8 @@ bool QOpenGLWidget::event(QEvent *e)
if (!QCoreApplication::testAttribute(Qt::AA_ShareOpenGLContexts))
d->reset();
}
- if (QWidgetRepaintManager *repaintManager = QWidgetPrivate::get(window())->maybeRepaintManager()) {
- if (!d->initialized && !size().isEmpty() && repaintManager->rhi()) {
+ if (d->rhi()) {
+ if (!d->initialized && !size().isEmpty()) {
d->initialize();
if (d->initialized) {
d->recreateFbos();
diff --git a/src/platformsupport/devicediscovery/CMakeLists.txt b/src/platformsupport/devicediscovery/CMakeLists.txt
index 8a134ac0fa..19c35f6660 100644
--- a/src/platformsupport/devicediscovery/CMakeLists.txt
+++ b/src/platformsupport/devicediscovery/CMakeLists.txt
@@ -15,6 +15,7 @@ qt_internal_add_module(DeviceDiscoverySupportPrivate
QT_NO_CAST_FROM_ASCII
PUBLIC_LIBRARIES
Qt::CorePrivate
+ NO_GENERATE_CPP_EXPORTS
)
## Scopes:
diff --git a/src/platformsupport/fbconvenience/CMakeLists.txt b/src/platformsupport/fbconvenience/CMakeLists.txt
index fba69bce5a..7bd7daec0d 100644
--- a/src/platformsupport/fbconvenience/CMakeLists.txt
+++ b/src/platformsupport/fbconvenience/CMakeLists.txt
@@ -22,4 +22,5 @@ qt_internal_add_module(FbSupportPrivate
Qt::GuiPrivate
PRECOMPILED_HEADER
"../../corelib/global/qt_pch.h"
+ NO_GENERATE_CPP_EXPORTS
)
diff --git a/src/platformsupport/fbconvenience/qfbscreen.cpp b/src/platformsupport/fbconvenience/qfbscreen.cpp
index e804488005..85e2f57198 100644
--- a/src/platformsupport/fbconvenience/qfbscreen.cpp
+++ b/src/platformsupport/fbconvenience/qfbscreen.cpp
@@ -63,7 +63,7 @@ void QFbScreen::addWindow(QFbWindow *window)
}
setDirty(window->geometry());
QWindow *w = topWindow();
- QWindowSystemInterface::handleWindowActivated(w);
+ QWindowSystemInterface::handleFocusWindowChanged(w);
topWindowChanged(w);
}
@@ -72,7 +72,7 @@ void QFbScreen::removeWindow(QFbWindow *window)
mWindowStack.removeOne(window);
setDirty(window->geometry());
QWindow *w = topWindow();
- QWindowSystemInterface::handleWindowActivated(w);
+ QWindowSystemInterface::handleFocusWindowChanged(w);
topWindowChanged(w);
}
@@ -84,7 +84,7 @@ void QFbScreen::raise(QFbWindow *window)
mWindowStack.move(index, 0);
setDirty(window->geometry());
QWindow *w = topWindow();
- QWindowSystemInterface::handleWindowActivated(w);
+ QWindowSystemInterface::handleFocusWindowChanged(w);
topWindowChanged(w);
}
@@ -96,7 +96,7 @@ void QFbScreen::lower(QFbWindow *window)
mWindowStack.move(index, mWindowStack.size() - 1);
setDirty(window->geometry());
QWindow *w = topWindow();
- QWindowSystemInterface::handleWindowActivated(w);
+ QWindowSystemInterface::handleFocusWindowChanged(w);
topWindowChanged(w);
}
diff --git a/src/platformsupport/input/CMakeLists.txt b/src/platformsupport/input/CMakeLists.txt
index 1802c8b5a1..b7ff09d827 100644
--- a/src/platformsupport/input/CMakeLists.txt
+++ b/src/platformsupport/input/CMakeLists.txt
@@ -22,6 +22,7 @@ qt_internal_add_module(InputSupportPrivate
Qt::GuiPrivate
PRECOMPILED_HEADER
"../../corelib/global/qt_pch.h"
+ NO_GENERATE_CPP_EXPORTS
)
## Scopes:
diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h
index ed437c0060..1d991e2ba5 100644
--- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h
+++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h
@@ -101,7 +101,7 @@ class QFdContainer
int m_fd;
Q_DISABLE_COPY_MOVE(QFdContainer);
public:
- explicit QFdContainer(int fd = -1) noexcept : m_fd(fd) {}
+ Q_NODISCARD_CTOR explicit QFdContainer(int fd = -1) noexcept : m_fd(fd) {}
~QFdContainer() { reset(); }
int get() const noexcept { return m_fd; }
diff --git a/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp b/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp
index 112fc62209..55b127ef17 100644
--- a/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp
+++ b/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp
@@ -62,7 +62,7 @@ QEvdevMouseManager::QEvdevMouseManager(const QString &key, const QString &specif
}
QInputDeviceManager *manager = QGuiApplicationPrivate::inputDeviceManager();
- connect(manager, &QInputDeviceManager::cursorPositionChangeRequested, [this](const QPoint &pos) {
+ connect(manager, &QInputDeviceManager::cursorPositionChangeRequested, this, [this](const QPoint &pos) {
m_x = pos.x();
m_y = pos.y();
clampPosition();
diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp
index 09375393a8..1b0da6297b 100644
--- a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp
+++ b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp
@@ -15,6 +15,8 @@
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qpointingdevice_p.h>
+#include <QtCore/qpointer.h>
+
#include <mutex>
#ifdef Q_OS_FREEBSD
@@ -150,12 +152,12 @@ QEvdevTouchScreenData::QEvdevTouchScreenData(QEvdevTouchScreenHandler *q_ptr, co
m_filtered(false), m_prediction(0)
{
for (const QString &arg : args) {
- if (arg == QStringLiteral("force_window"))
+ if (arg == u"force_window")
m_forceToActiveWindow = true;
- else if (arg == QStringLiteral("filtered"))
+ else if (arg == u"filtered")
m_filtered = true;
- else if (arg.startsWith(QStringLiteral("prediction=")))
- m_prediction = arg.mid(11).toInt();
+ else if (const QStringView prefix = u"prediction="; arg.startsWith(prefix))
+ m_prediction = QStringView(arg).mid(prefix.size()).toInt();
}
}
@@ -192,6 +194,7 @@ QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &device, const
case 180:
case 270:
rotationAngle = argValue;
+ break;
default:
break;
}
diff --git a/src/platformsupport/input/libinput/qlibinputhandler.cpp b/src/platformsupport/input/libinput/qlibinputhandler.cpp
index 3b49438d0a..ef45533f1a 100644
--- a/src/platformsupport/input/libinput/qlibinputhandler.cpp
+++ b/src/platformsupport/input/libinput/qlibinputhandler.cpp
@@ -79,7 +79,7 @@ QLibInputHandler::QLibInputHandler(const QString &key, const QString &spec)
m_touch.reset(new QLibInputTouch);
QInputDeviceManager *manager = QGuiApplicationPrivate::inputDeviceManager();
- connect(manager, &QInputDeviceManager::cursorPositionChangeRequested, [this](const QPoint &pos) {
+ connect(manager, &QInputDeviceManager::cursorPositionChangeRequested, this, [this](const QPoint &pos) {
m_pointer->setPos(pos);
});
diff --git a/src/platformsupport/input/libinput/qlibinputkeyboard.cpp b/src/platformsupport/input/libinput/qlibinputkeyboard.cpp
index f6640171eb..25939cd510 100644
--- a/src/platformsupport/input/libinput/qlibinputkeyboard.cpp
+++ b/src/platformsupport/input/libinput/qlibinputkeyboard.cpp
@@ -79,7 +79,7 @@ void QLibInputKeyboard::processKey(libinput_event_keyboard *e)
xkb_state_update_key(m_state, keycode, pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
- Qt::KeyboardModifiers modifiersAfterStateChange = QXkbCommon::modifiers(m_state);
+ Qt::KeyboardModifiers modifiersAfterStateChange = QXkbCommon::modifiers(m_state, sym);
QGuiApplicationPrivate::inputDeviceManager()->setKeyboardModifiers(modifiersAfterStateChange);
QWindowSystemInterface::handleExtendedKeyEvent(nullptr,
diff --git a/src/platformsupport/input/libinput/qlibinputtouch.cpp b/src/platformsupport/input/libinput/qlibinputtouch.cpp
index 7e69f9e370..e3a483dc84 100644
--- a/src/platformsupport/input/libinput/qlibinputtouch.cpp
+++ b/src/platformsupport/input/libinput/qlibinputtouch.cpp
@@ -61,6 +61,33 @@ QPointF QLibInputTouch::getPos(libinput_event_touch *e)
return geom.topLeft() + QPointF(x, y);
}
+static void setMatrix(libinput_device *dev)
+{
+ if (libinput_device_config_calibration_has_matrix(dev)) {
+ QByteArray env = qgetenv("QT_QPA_LIBINPUT_TOUCH_MATRIX");
+ env = env.simplified();
+ if (env.size()) {
+ float matrix[6];
+ QList<QByteArray> list = env.split(' ');
+ if (list.length() != 6) {
+ qCWarning(qLcLibInput, "matrix length %lld wrong, should be 6", list.length());
+ return;
+ }
+ for (int i = 0; i < 6; i++) {
+ bool ok = true;
+ matrix[i] = list[i].toFloat(&ok);
+ if (!ok) {
+ qCWarning(qLcLibInput, "Invalid matrix entry %d %s ", i, list[i].constData());
+ return;
+ }
+ }
+ if (libinput_device_config_calibration_set_matrix(dev, matrix) != LIBINPUT_CONFIG_STATUS_SUCCESS)
+ qCWarning(qLcLibInput, "Failed to set libinput calibration matrix ");
+ }
+ } else {
+ qCWarning(qLcLibInput, "Touch device doesn't support matrix");
+ }
+}
void QLibInputTouch::registerDevice(libinput_device *dev)
{
struct udev_device *udev_device;
@@ -92,6 +119,7 @@ void QLibInputTouch::registerDevice(libinput_device *dev)
if (!geom.isNull())
devPriv->setAvailableVirtualGeometry(geom);
QWindowSystemInterface::registerInputDevice(td);
+ setMatrix(dev);
}
void QLibInputTouch::unregisterDevice(libinput_device *dev)
diff --git a/src/platformsupport/input/tslib/qtslib.cpp b/src/platformsupport/input/tslib/qtslib.cpp
index 299d7801ec..a84cc90dc2 100644
--- a/src/platformsupport/input/tslib/qtslib.cpp
+++ b/src/platformsupport/input/tslib/qtslib.cpp
@@ -79,9 +79,12 @@ void QTsLibMouseHandler::readMouseData()
}
QPoint pos(x, y);
- QWindowSystemInterface::handleMouseEvent(nullptr, pos, pos,
- pressed ? Qt::LeftButton : Qt::NoButton,
- Qt::NoButton, QEvent::None);
+ Qt::MouseButton button = pressed ^ m_pressed ? Qt::LeftButton : Qt::NoButton;
+ Qt::MouseButtons state = pressed ? Qt::LeftButton : Qt::NoButton;
+ QEvent::Type type = pressed ? (m_pressed ? QEvent::MouseMove : QEvent::MouseButtonPress)
+ : QEvent::MouseButtonRelease;
+
+ QWindowSystemInterface::handleMouseEvent(nullptr, pos, pos, state, button, type);
m_x = x;
m_y = y;
diff --git a/src/platformsupport/kmsconvenience/CMakeLists.txt b/src/platformsupport/kmsconvenience/CMakeLists.txt
index e97b398a63..9cd4eb1d33 100644
--- a/src/platformsupport/kmsconvenience/CMakeLists.txt
+++ b/src/platformsupport/kmsconvenience/CMakeLists.txt
@@ -19,4 +19,5 @@ qt_internal_add_module(KmsSupportPrivate
Libdrm::Libdrm
Qt::CorePrivate
Qt::GuiPrivate
+ NO_GENERATE_CPP_EXPORTS
)
diff --git a/src/platformsupport/kmsconvenience/qkmsdevice.cpp b/src/platformsupport/kmsconvenience/qkmsdevice.cpp
index 89b6df605b..421e9f05c0 100644
--- a/src/platformsupport/kmsconvenience/qkmsdevice.cpp
+++ b/src/platformsupport/kmsconvenience/qkmsdevice.cpp
@@ -716,6 +716,7 @@ void QKmsDevice::createScreens()
// 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()) {
+ qCDebug(qLcKmsDebug) << " virtual position is" << virtualPos;
siblings.append(s);
virtualPositions.append(virtualPos);
if (orderedScreen.vinfo.isPrimary)
diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt
index dc7c45c2d8..d26d2aae44 100644
--- a/src/plugins/CMakeLists.txt
+++ b/src/plugins/CMakeLists.txt
@@ -25,6 +25,6 @@ if (TARGET Qt::Network)
add_subdirectory(networkinformation)
add_subdirectory(tls)
endif()
-if (QT_FEATURE_ctf AND QT_FEATURE_library)
+if (QT_FEATURE_ctf AND TARGET Qt::Network)
add_subdirectory(tracing)
endif()
diff --git a/src/plugins/doc/snippets/code/src_plugins_platforms_qnx_qqnxwindow.cpp b/src/plugins/doc/snippets/code/src_plugins_platforms_qnx_qqnxwindow.cpp
index f0071aeafe..6b6e2966b2 100644
--- a/src/plugins/doc/snippets/code/src_plugins_platforms_qnx_qqnxwindow.cpp
+++ b/src/plugins/doc/snippets/code/src_plugins_platforms_qnx_qqnxwindow.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
QQuickView *view = new QQuickView(parent);
diff --git a/src/plugins/generic/CMakeLists.txt b/src/plugins/generic/CMakeLists.txt
index 313fafc15c..6d3cf2a925 100644
--- a/src/plugins/generic/CMakeLists.txt
+++ b/src/plugins/generic/CMakeLists.txt
@@ -19,6 +19,6 @@ if(QT_FEATURE_libinput)
add_subdirectory(libinput)
endif()
if(FREEBSD)
- # add_subdirectory(bsdkeyboard) # special case TODO
- # add_subdirectory(bsdmouse) # special case TODO
+ # add_subdirectory(bsdkeyboard) # TODO: QTBUG-112770
+ # add_subdirectory(bsdmouse) # TODO: QTBUG-112770
endif()
diff --git a/src/plugins/generic/tuiotouch/qtuiohandler.cpp b/src/plugins/generic/tuiotouch/qtuiohandler.cpp
index a304963669..2815368e84 100644
--- a/src/plugins/generic/tuiotouch/qtuiohandler.cpp
+++ b/src/plugins/generic/tuiotouch/qtuiohandler.cpp
@@ -59,6 +59,7 @@ QTuioHandler::QTuioHandler(const QString &specification)
case 180:
case 270:
rotationAngle = argValue;
+ break;
default:
break;
}
diff --git a/src/plugins/imageformats/ico/qicohandler.cpp b/src/plugins/imageformats/ico/qicohandler.cpp
index 3bcf30bfc6..18b39766f5 100644
--- a/src/plugins/imageformats/ico/qicohandler.cpp
+++ b/src/plugins/imageformats/ico/qicohandler.cpp
@@ -499,7 +499,7 @@ QImage ICOReader::iconAt(int index)
if (!image.isNull()) {
readBMP(image);
if (!image.isNull()) {
- if (icoAttrib.depth == 32) {
+ if (icoAttrib.nbits == 32) {
img = std::move(image).convertToFormat(QImage::Format_ARGB32_Premultiplied);
} else {
QImage mask(image.width(), image.height(), QImage::Format_Mono);
@@ -735,6 +735,8 @@ bool QtIcoHandler::supportsOption(ImageOption option) const
*/
bool QtIcoHandler::canRead() const
{
+ if (knownCanRead)
+ return true;
bool bCanRead = false;
QIODevice *device = QImageIOHandler::device();
if (device) {
@@ -744,6 +746,7 @@ bool QtIcoHandler::canRead() const
} else {
qCWarning(lcIco, "QtIcoHandler::canRead() called with no device");
}
+ knownCanRead = bCanRead;
return bCanRead;
}
diff --git a/src/plugins/imageformats/ico/qicohandler.h b/src/plugins/imageformats/ico/qicohandler.h
index 0fe251ab60..61c3eea465 100644
--- a/src/plugins/imageformats/ico/qicohandler.h
+++ b/src/plugins/imageformats/ico/qicohandler.h
@@ -30,7 +30,7 @@ public:
private:
int m_currentIconIndex;
ICOReader *m_pICOReader;
-
+ mutable bool knownCanRead = false;
};
QT_END_NAMESPACE
diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp
index 0d72ba01d0..59b73587c5 100644
--- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp
+++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp
@@ -172,9 +172,14 @@ inline static bool read_jpeg_format(QImage::Format &format, j_decompress_ptr cin
format = QImage::Format_Grayscale8;
break;
case 3:
- case 4:
format = QImage::Format_RGB32;
break;
+ case 4:
+ if (cinfo->out_color_space == JCS_CMYK)
+ format = QImage::Format_CMYK8888;
+ else
+ format = QImage::Format_RGB32;
+ break;
default:
result = false;
break;
@@ -192,9 +197,14 @@ static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info,
format = QImage::Format_Grayscale8;
break;
case 3:
- case 4:
format = QImage::Format_RGB32;
break;
+ case 4:
+ if (info->out_color_space == JCS_CMYK)
+ format = QImage::Format_CMYK8888;
+ else
+ format = QImage::Format_RGB32;
+ break;
default:
return false; // unsupported format
}
@@ -206,7 +216,7 @@ static bool read_jpeg_image(QImage *outImage,
QSize scaledSize, QRect scaledClipRect,
QRect clipRect, int quality,
Rgb888ToRgb32Converter converter,
- j_decompress_ptr info, struct my_error_mgr* err )
+ j_decompress_ptr info, struct my_error_mgr* err, bool invertCMYK)
{
if (!setjmp(err->setjmp_buffer)) {
// -1 means default quality.
@@ -348,14 +358,15 @@ static bool read_jpeg_image(QImage *outImage,
QRgb *out = (QRgb*)outImage->scanLine(y);
converter(out, in, clip.width());
} else if (info->out_color_space == JCS_CMYK) {
- // Convert CMYK->RGB.
uchar *in = rows[0] + clip.x() * 4;
- QRgb *out = (QRgb*)outImage->scanLine(y);
- for (int i = 0; i < clip.width(); ++i) {
- int k = in[3];
- *out++ = qRgb(k * in[0] / 255, k * in[1] / 255,
- k * in[2] / 255);
- in += 4;
+ quint32 *out = (quint32*)outImage->scanLine(y);
+ if (invertCMYK) {
+ for (int i = 0; i < clip.width(); ++i) {
+ *out++ = 0xffffffffu - (in[0] | in[1] << 8 | in[2] << 16 | in[3] << 24);
+ in += 4;
+ }
+ } else {
+ memcpy(out, in, clip.width() * 4);
}
} else if (info->output_components == 1) {
// Grayscale.
@@ -493,7 +504,8 @@ static bool do_write_jpeg_image(struct jpeg_compress_struct &cinfo,
int sourceQuality,
const QString &description,
bool optimize,
- bool progressive)
+ bool progressive,
+ bool invertCMYK)
{
bool success = false;
const QList<QRgb> cmap = image.colorTable();
@@ -538,6 +550,10 @@ static bool do_write_jpeg_image(struct jpeg_compress_struct &cinfo,
cinfo.input_components = 1;
cinfo.in_color_space = JCS_GRAYSCALE;
break;
+ case QImage::Format_CMYK8888:
+ cinfo.input_components = 4;
+ cinfo.in_color_space = JCS_CMYK;
+ break;
default:
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
@@ -570,7 +586,7 @@ static bool do_write_jpeg_image(struct jpeg_compress_struct &cinfo,
jpeg_start_compress(&cinfo, TRUE);
set_text(image, &cinfo, description);
- if (cinfo.in_color_space == JCS_RGB)
+ if (cinfo.in_color_space == JCS_RGB || cinfo.in_color_space == JCS_CMYK)
write_icc_profile(image, &cinfo);
row_pointer[0] = new uchar[cinfo.image_width*cinfo.input_components];
@@ -654,6 +670,17 @@ static bool do_write_jpeg_image(struct jpeg_compress_struct &cinfo,
}
}
break;
+ case QImage::Format_CMYK8888: {
+ auto *cmykIn = reinterpret_cast<const quint32 *>(image.constScanLine(cinfo.next_scanline));
+ auto *cmykOut = reinterpret_cast<quint32 *>(row);
+ if (invertCMYK) {
+ for (int i = 0; i < w; ++i)
+ cmykOut[i] = 0xffffffffu - cmykIn[i];
+ } else {
+ memcpy(cmykOut, cmykIn, w * 4);
+ }
+ break;
+ }
default:
{
// (Testing shows that this way is actually faster than converting to RGB888 + memcpy)
@@ -689,7 +716,8 @@ static bool write_jpeg_image(const QImage &image,
int sourceQuality,
const QString &description,
bool optimize,
- bool progressive)
+ bool progressive,
+ bool invertCMYK)
{
// protect these objects from the setjmp/longjmp pair inside
// do_write_jpeg_image (by making them non-local).
@@ -700,7 +728,7 @@ static bool write_jpeg_image(const QImage &image,
const bool success = do_write_jpeg_image(cinfo, row_pointer,
image, device,
sourceQuality, description,
- optimize, progressive);
+ optimize, progressive, invertCMYK);
delete [] row_pointer[0];
return success;
@@ -745,6 +773,21 @@ public:
QStringList readTexts;
QByteArray iccProfile;
+ // Photoshop historically invertes the quantities in CMYK JPEG files:
+ // 0 means 100% ink, 255 means no ink. Every reader does the same,
+ // for compatibility reasons.
+ // Use such an interpretation by default, but also offer the alternative
+ // of not inverting the channels.
+ // This is just a "fancy" API; it could be reduced to a boolean setting
+ // for CMYK files.
+ enum class SubType {
+ Automatic,
+ Inverted_CMYK,
+ CMYK,
+ NSubTypes
+ };
+ SubType subType = SubType::Automatic;
+
struct jpeg_decompress_struct info;
struct my_jpeg_source_mgr * iod_src;
struct my_error_mgr err;
@@ -759,6 +802,14 @@ public:
QJpegHandler *q;
};
+static const char SupportedJPEGSubtypes[][14] = {
+ "Automatic",
+ "Inverted_CMYK",
+ "CMYK"
+};
+
+static_assert(std::size(SupportedJPEGSubtypes) == size_t(QJpegHandlerPrivate::SubType::NSubTypes));
+
static bool readExifHeader(QDataStream &stream)
{
char prefix[6];
@@ -975,7 +1026,8 @@ bool QJpegHandlerPrivate::read(QImage *image)
if (state == ReadHeader)
{
- bool success = read_jpeg_image(image, scaledSize, scaledClipRect, clipRect, quality, rgb888ToRgb32ConverterPtr, &info, &err);
+ const bool invertCMYK = subType != QJpegHandlerPrivate::SubType::CMYK;
+ bool success = read_jpeg_image(image, scaledSize, scaledClipRect, clipRect, quality, rgb888ToRgb32ConverterPtr, &info, &err, invertCMYK);
if (success) {
for (int i = 0; i < readTexts.size()-1; i+=2)
image->setText(readTexts.at(i), readTexts.at(i+1));
@@ -1061,13 +1113,14 @@ extern void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orie
bool QJpegHandler::write(const QImage &image)
{
+ const bool invertCMYK = d->subType != QJpegHandlerPrivate::SubType::CMYK;
if (d->transformation != QImageIOHandler::TransformationNone) {
// We don't support writing EXIF headers so apply the transform to the data.
QImage img = image;
qt_imageTransform(img, d->transformation);
- return write_jpeg_image(img, device(), d->quality, d->description, d->optimize, d->progressive);
+ return write_jpeg_image(img, device(), d->quality, d->description, d->optimize, d->progressive, invertCMYK);
}
- return write_jpeg_image(image, device(), d->quality, d->description, d->optimize, d->progressive);
+ return write_jpeg_image(image, device(), d->quality, d->description, d->optimize, d->progressive, invertCMYK);
}
bool QJpegHandler::supportsOption(ImageOption option) const
@@ -1078,6 +1131,8 @@ bool QJpegHandler::supportsOption(ImageOption option) const
|| option == ClipRect
|| option == Description
|| option == Size
+ || option == SubType
+ || option == SupportedSubTypes
|| option == ImageFormat
|| option == OptimizedWrite
|| option == ProgressiveScanWrite
@@ -1101,6 +1156,13 @@ QVariant QJpegHandler::option(ImageOption option) const
case Size:
d->readJpegHeader(device());
return d->size;
+ case SubType:
+ return QByteArray(SupportedJPEGSubtypes[int(d->subType)]);
+ case SupportedSubTypes: {
+ QByteArrayList list(std::begin(SupportedJPEGSubtypes),
+ std::end(SupportedJPEGSubtypes));
+ return QVariant::fromValue(list);
+ }
case ImageFormat:
d->readJpegHeader(device());
return d->format;
@@ -1136,6 +1198,16 @@ void QJpegHandler::setOption(ImageOption option, const QVariant &value)
case Description:
d->description = value.toString();
break;
+ case SubType: {
+ const QByteArray subType = value.toByteArray();
+ for (size_t i = 0; i < std::size(SupportedJPEGSubtypes); ++i) {
+ if (subType == SupportedJPEGSubtypes[i]) {
+ d->subType = QJpegHandlerPrivate::SubType(i);
+ break;
+ }
+ }
+ break;
+ }
case OptimizedWrite:
d->optimize = value.toBool();
break;
@@ -1146,6 +1218,7 @@ void QJpegHandler::setOption(ImageOption option, const QVariant &value)
int transformation = value.toInt();
if (transformation > 0 && transformation < 8)
d->transformation = QImageIOHandler::Transformations(transformation);
+ break;
}
default:
break;
diff --git a/src/plugins/networkinformation/android/CMakeLists.txt b/src/plugins/networkinformation/android/CMakeLists.txt
index f9ed4913e3..07d9201bbb 100644
--- a/src/plugins/networkinformation/android/CMakeLists.txt
+++ b/src/plugins/networkinformation/android/CMakeLists.txt
@@ -29,8 +29,6 @@ qt_internal_add_plugin(QAndroidNetworkInformationPlugin
wrapper/androidconnectivitymanager.cpp wrapper/androidconnectivitymanager.h
LIBRARIES
Qt::NetworkPrivate
- DEFINES
- QT_USE_QSTRINGBUILDER
)
set_property(
diff --git a/src/plugins/networkinformation/android/jar/build.gradle b/src/plugins/networkinformation/android/jar/build.gradle
index c947852f79..68a9381ad2 100644
--- a/src/plugins/networkinformation/android/jar/build.gradle
+++ b/src/plugins/networkinformation/android/jar/build.gradle
@@ -7,7 +7,7 @@ buildscript {
}
dependencies {
- classpath 'com.android.tools.build:gradle:7.0.2'
+ classpath 'com.android.tools.build:gradle:8.0.2'
}
}
@@ -23,12 +23,10 @@ repositories {
}
android {
- compileSdkVersion 31
- buildToolsVersion "31.0.3"
+ compileSdk 34
defaultConfig {
minSdkVersion 23
- targetSdkVersion 31
}
sourceSets {
diff --git a/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp b/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp
index 203772971b..3c9f952968 100644
--- a/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp
+++ b/src/plugins/networkinformation/android/wrapper/androidconnectivitymanager.cpp
@@ -48,7 +48,7 @@ static void transportMediumChanged(JNIEnv *env, jobject obj, jint enumValue)
}
Q_DECLARE_JNI_NATIVE_METHOD(transportMediumChanged)
-Q_DECLARE_JNI_TYPE(ConnectivityManager, "Landroid/net/ConnectivityManager;")
+Q_DECLARE_JNI_CLASS(ConnectivityManager, "android/net/ConnectivityManager")
AndroidConnectivityManager::AndroidConnectivityManager()
{
@@ -93,3 +93,5 @@ bool AndroidConnectivityManager::registerNatives() const
}
QT_END_NAMESPACE
+
+#include "moc_androidconnectivitymanager.cpp"
diff --git a/src/plugins/networkinformation/glib/qglibnetworkinformationbackend.cpp b/src/plugins/networkinformation/glib/qglibnetworkinformationbackend.cpp
index 10ce5dbc60..0b45eb9ce3 100644
--- a/src/plugins/networkinformation/glib/qglibnetworkinformationbackend.cpp
+++ b/src/plugins/networkinformation/glib/qglibnetworkinformationbackend.cpp
@@ -51,7 +51,8 @@ public:
static QNetworkInformation::Features featuresSupportedStatic()
{
using Feature = QNetworkInformation::Feature;
- return QNetworkInformation::Features(Feature::Reachability | Feature::CaptivePortal);
+ return QNetworkInformation::Features(Feature::Reachability | Feature::CaptivePortal
+ | Feature::Metered);
}
bool isValid() const;
@@ -59,10 +60,12 @@ public:
private:
Q_DISABLE_COPY_MOVE(QGlibNetworkInformationBackend)
- static void updateInformation(QGlibNetworkInformationBackend *backend);
+ static void updateConnectivity(QGlibNetworkInformationBackend *backend);
+ static void updateMetered(QGlibNetworkInformationBackend *backend);
GNetworkMonitor *networkMonitor = nullptr;
- gulong handlerId = 0;
+ gulong connectivityHandlerId = 0;
+ gulong meteredHandlerId = 0;
};
class QGlibNetworkInformationBackendFactory : public QNetworkInformationBackendFactory
@@ -95,23 +98,28 @@ private:
QGlibNetworkInformationBackend::QGlibNetworkInformationBackend()
: networkMonitor(g_network_monitor_get_default())
{
- updateInformation(this);
+ updateConnectivity(this);
+ updateMetered(this);
- handlerId = g_signal_connect_swapped(networkMonitor, "notify::connectivity",
- G_CALLBACK(updateInformation), this);
+ connectivityHandlerId = g_signal_connect_swapped(networkMonitor, "notify::connectivity",
+ G_CALLBACK(updateConnectivity), this);
+
+ meteredHandlerId = g_signal_connect_swapped(networkMonitor, "notify::network-metered",
+ G_CALLBACK(updateMetered), this);
}
QGlibNetworkInformationBackend::~QGlibNetworkInformationBackend()
{
- g_signal_handler_disconnect(networkMonitor, handlerId);
+ g_signal_handler_disconnect(networkMonitor, meteredHandlerId);
+ g_signal_handler_disconnect(networkMonitor, connectivityHandlerId);
}
bool QGlibNetworkInformationBackend::isValid() const
{
- return G_OBJECT_TYPE_NAME(networkMonitor) != "GNetworkMonitorBase"_L1;
+ return QLatin1StringView(G_OBJECT_TYPE_NAME(networkMonitor)) != "GNetworkMonitorBase"_L1;
}
-void QGlibNetworkInformationBackend::updateInformation(QGlibNetworkInformationBackend *backend)
+void QGlibNetworkInformationBackend::updateConnectivity(QGlibNetworkInformationBackend *backend)
{
const auto connectivityState = g_network_monitor_get_connectivity(backend->networkMonitor);
const bool behindPortal = (connectivityState == G_NETWORK_CONNECTIVITY_PORTAL);
@@ -119,6 +127,11 @@ void QGlibNetworkInformationBackend::updateInformation(QGlibNetworkInformationBa
backend->setBehindCaptivePortal(behindPortal);
}
+void QGlibNetworkInformationBackend::updateMetered(QGlibNetworkInformationBackend *backend)
+{
+ backend->setMetered(g_network_monitor_get_network_metered(backend->networkMonitor));
+}
+
QT_END_NAMESPACE
#include "qglibnetworkinformationbackend.moc"
diff --git a/src/plugins/networkinformation/networklistmanager/CMakeLists.txt b/src/plugins/networkinformation/networklistmanager/CMakeLists.txt
index 77501d0e5c..acd3754f4e 100644
--- a/src/plugins/networkinformation/networklistmanager/CMakeLists.txt
+++ b/src/plugins/networkinformation/networklistmanager/CMakeLists.txt
@@ -14,9 +14,10 @@ qt_internal_add_plugin(QNLMNIPlugin
Qt::NetworkPrivate
)
-qt_internal_extend_target(QNLMNIPlugin CONDITION WIN32 AND MSVC AND NOT CLANG
+qt_internal_extend_target(QNLMNIPlugin CONDITION WIN32
LIBRARIES
runtimeobject
+ oleaut32
)
# Don't repeat the target name in AUTOGEN_BUILD_DIR to work around issues with overlong paths.
diff --git a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp
index 5b0a91df3e..caa5046751 100644
--- a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp
+++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagerevents.cpp
@@ -102,16 +102,22 @@ bool QNetworkListManagerEvents::start()
#if QT_CONFIG(cpp_winrt)
using namespace winrt::Windows::Networking::Connectivity;
using winrt::Windows::Foundation::IInspectable;
- // Register for changes in the network and store a token to unregister later:
- token = NetworkInformation::NetworkStatusChanged(
- [owner = QPointer(this)](const IInspectable sender) {
- Q_UNUSED(sender);
- if (owner) {
- std::scoped_lock locker(owner->winrtLock);
- if (owner->token)
- owner->emitWinRTUpdates();
- }
- });
+ try {
+ // Register for changes in the network and store a token to unregister later:
+ token = NetworkInformation::NetworkStatusChanged(
+ [owner = QPointer(this)](const IInspectable sender) {
+ Q_UNUSED(sender);
+ if (owner) {
+ std::scoped_lock locker(owner->winrtLock);
+ if (owner->token)
+ owner->emitWinRTUpdates();
+ }
+ });
+ } catch (const winrt::hresult_error &ex) {
+ qCWarning(lcNetInfoNLM) << "Failed to register network status changed callback:"
+ << QSystemError::windowsComString(ex.code());
+ }
+
// Emit initial state
emitWinRTUpdates();
#endif
@@ -197,7 +203,9 @@ QNetworkInformation::TransportMedium getTransportMedium(const ConnectionProfile
NetworkAdapter adapter(nullptr);
try {
adapter = profile.NetworkAdapter();
- } catch (...) {
+ } catch (const winrt::hresult_error &ex) {
+ qCWarning(lcNetInfoNLM) << "Failed to obtain network adapter:"
+ << QSystemError::windowsComString(ex.code());
// pass, we will return Unknown anyway
}
if (adapter == nullptr)
@@ -225,7 +233,9 @@ QNetworkInformation::TransportMedium getTransportMedium(const ConnectionProfile
ConnectionCost cost(nullptr);
try {
cost = profile.GetConnectionCost();
- } catch (...) {
+ } catch (const winrt::hresult_error &ex) {
+ qCWarning(lcNetInfoNLM) << "Failed to obtain connection cost:"
+ << QSystemError::windowsComString(ex.code());
// pass, we return false if we get an empty object back anyway
}
if (cost == nullptr)
@@ -241,7 +251,9 @@ void QNetworkListManagerEvents::emitWinRTUpdates()
ConnectionProfile profile = nullptr;
try {
profile = NetworkInformation::GetInternetConnectionProfile();
- } catch (...) {
+ } catch (const winrt::hresult_error &ex) {
+ qCWarning(lcNetInfoNLM) << "Failed to obtain connection profile:"
+ << QSystemError::windowsComString(ex.code());
// pass, we would just return early if we get an empty object back anyway
}
if (profile == nullptr)
@@ -252,3 +264,5 @@ void QNetworkListManagerEvents::emitWinRTUpdates()
#endif // QT_CONFIG(cpp_winrt)
QT_END_NAMESPACE
+
+#include "moc_qnetworklistmanagerevents.cpp"
diff --git a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp
index a5b0179e37..766648486e 100644
--- a/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp
+++ b/src/plugins/networkinformation/networklistmanager/qnetworklistmanagernetworkinformationbackend.cpp
@@ -72,6 +72,7 @@ public:
| QNetworkInformation::Feature::CaptivePortal
#if QT_CONFIG(cpp_winrt)
| QNetworkInformation::Feature::TransportMedium
+ | QNetworkInformation::Feature::Metered
#endif
);
}
diff --git a/src/plugins/networkinformation/networkmanager/CMakeLists.txt b/src/plugins/networkinformation/networkmanager/CMakeLists.txt
index e98ea84e3a..9d76dbe7b4 100644
--- a/src/plugins/networkinformation/networkmanager/CMakeLists.txt
+++ b/src/plugins/networkinformation/networkmanager/CMakeLists.txt
@@ -7,6 +7,7 @@ qt_internal_add_plugin(QNetworkManagerNetworkInformationPlugin
PLUGIN_TYPE networkinformation
DEFAULT_IF LINUX
SOURCES
+ qnetworkmanagernetworkinformationbackend.h
qnetworkmanagernetworkinformationbackend.cpp
qnetworkmanagerservice.h
qnetworkmanagerservice.cpp
diff --git a/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp b/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp
index 6ee84e06f8..f583d1dcf6 100644
--- a/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp
+++ b/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.cpp
@@ -1,9 +1,7 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <QtNetwork/private/qnetworkinformation_p.h>
-
-#include "qnetworkmanagerservice.h"
+#include "qnetworkmanagernetworkinformationbackend.h"
#include <QtCore/qglobal.h>
#include <QtCore/private/qobject_p.h>
@@ -100,39 +98,14 @@ bool isMeteredFromNMMetered(QNetworkManagerInterface::NMMetered metered)
static QString backendName()
{
- return QString::fromUtf16(QNetworkInformationBackend::PluginNames
- [QNetworkInformationBackend::PluginNamesLinuxIndex]);
+ return QStringView(QNetworkInformationBackend::PluginNames
+ [QNetworkInformationBackend::PluginNamesLinuxIndex]).toString();
}
-class QNetworkManagerNetworkInformationBackend : public QNetworkInformationBackend
+QString QNetworkManagerNetworkInformationBackend::name() const
{
- Q_OBJECT
-public:
- QNetworkManagerNetworkInformationBackend();
- ~QNetworkManagerNetworkInformationBackend() = default;
-
- QString name() const override { return backendName(); }
- QNetworkInformation::Features featuresSupported() const override
- {
- if (!isValid())
- return {};
- return featuresSupportedStatic();
- }
-
- static QNetworkInformation::Features featuresSupportedStatic()
- {
- using Feature = QNetworkInformation::Feature;
- return QNetworkInformation::Features(Feature::Reachability | Feature::CaptivePortal
- | Feature::TransportMedium | Feature::Metered);
- }
-
- bool isValid() const { return iface.isValid(); }
-
-private:
- Q_DISABLE_COPY_MOVE(QNetworkManagerNetworkInformationBackend)
-
- QNetworkManagerInterface iface;
-};
+ return backendName();
+}
class QNetworkManagerNetworkInformationBackendFactory : public QNetworkInformationBackendFactory
{
@@ -167,34 +140,42 @@ private:
QNetworkManagerNetworkInformationBackend::QNetworkManagerNetworkInformationBackend()
{
- auto updateReachability = [this](QNetworkManagerInterface::NMState newState) {
- setReachability(reachabilityFromNMState(newState));
- };
- updateReachability(iface.state());
- connect(&iface, &QNetworkManagerInterface::stateChanged, this, std::move(updateReachability));
-
- auto updateBehindCaptivePortal = [this](QNetworkManagerInterface::NMConnectivityState state) {
- const bool behindPortal = (state == QNetworkManagerInterface::NM_CONNECTIVITY_PORTAL);
- setBehindCaptivePortal(behindPortal);
- };
- updateBehindCaptivePortal(iface.connectivityState());
- connect(&iface, &QNetworkManagerInterface::connectivityChanged, this,
- std::move(updateBehindCaptivePortal));
-
- auto updateTransportMedium = [this](QNetworkManagerInterface::NMDeviceType newDevice) {
- setTransportMedium(transportMediumFromDeviceType(newDevice));
- };
- updateTransportMedium(iface.deviceType());
- connect(&iface, &QNetworkManagerInterface::deviceTypeChanged, this,
- std::move(updateTransportMedium));
-
- auto updateMetered = [this](QNetworkManagerInterface::NMMetered metered) {
- setMetered(isMeteredFromNMMetered(metered));
- };
- updateMetered(iface.meteredState());
- connect(&iface, &QNetworkManagerInterface::meteredChanged, this, std::move(updateMetered));
+ if (!iface.isValid())
+ return;
+ iface.setBackend(this);
+ onStateChanged(iface.state());
+ onConnectivityChanged(iface.connectivityState());
+ onDeviceTypeChanged(iface.deviceType());
+ onMeteredChanged(iface.meteredState());
+}
+
+void QNetworkManagerNetworkInformationBackend::onStateChanged(
+ QNetworkManagerInterface::NMState newState)
+{
+ setReachability(reachabilityFromNMState(newState));
}
+void QNetworkManagerNetworkInformationBackend::onConnectivityChanged(
+ QNetworkManagerInterface::NMConnectivityState connectivityState)
+{
+ const bool behindPortal =
+ (connectivityState == QNetworkManagerInterface::NM_CONNECTIVITY_PORTAL);
+ setBehindCaptivePortal(behindPortal);
+}
+
+void QNetworkManagerNetworkInformationBackend::onDeviceTypeChanged(
+ QNetworkManagerInterface::NMDeviceType newDevice)
+{
+ setTransportMedium(transportMediumFromDeviceType(newDevice));
+}
+
+void QNetworkManagerNetworkInformationBackend::onMeteredChanged(
+ QNetworkManagerInterface::NMMetered metered)
+{
+ setMetered(isMeteredFromNMMetered(metered));
+};
+
QT_END_NAMESPACE
#include "qnetworkmanagernetworkinformationbackend.moc"
+#include "moc_qnetworkmanagernetworkinformationbackend.cpp"
diff --git a/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.h b/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.h
new file mode 100644
index 0000000000..3b60f0949c
--- /dev/null
+++ b/src/plugins/networkinformation/networkmanager/qnetworkmanagernetworkinformationbackend.h
@@ -0,0 +1,60 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QNETWORKMANAGERINFORMATIONBACKEND_H
+#define QNETWORKMANAGERINFORMATIONBACKEND_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 <QtNetwork/private/qnetworkinformation_p.h>
+#include "qnetworkmanagerservice.h"
+
+QT_BEGIN_NAMESPACE
+
+class QNetworkManagerNetworkInformationBackend : public QNetworkInformationBackend
+{
+ Q_OBJECT
+public:
+ QNetworkManagerNetworkInformationBackend();
+ ~QNetworkManagerNetworkInformationBackend() = default;
+
+ QString name() const override;
+ QNetworkInformation::Features featuresSupported() const override
+ {
+ if (!isValid())
+ return {};
+ return featuresSupportedStatic();
+ }
+
+ static QNetworkInformation::Features featuresSupportedStatic()
+ {
+ using Feature = QNetworkInformation::Feature;
+ return QNetworkInformation::Features(Feature::Reachability | Feature::CaptivePortal
+ | Feature::TransportMedium | Feature::Metered);
+ }
+
+ bool isValid() const { return iface.isValid(); }
+
+ void onStateChanged(QNetworkManagerInterface::NMState state);
+ void onConnectivityChanged(QNetworkManagerInterface::NMConnectivityState connectivityState);
+ void onDeviceTypeChanged(QNetworkManagerInterface::NMDeviceType deviceType);
+ void onMeteredChanged(QNetworkManagerInterface::NMMetered metered);
+
+private:
+ Q_DISABLE_COPY_MOVE(QNetworkManagerNetworkInformationBackend)
+
+ QNetworkManagerInterface iface;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp b/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp
index 3a64c1892c..c055555cac 100644
--- a/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp
+++ b/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qnetworkmanagerservice.h"
+#include "qnetworkmanagernetworkinformationbackend.h"
#include <QObject>
#include <QList>
@@ -14,21 +15,40 @@
#include <QtDBus/QDBusObjectPath>
#include <QtDBus/QDBusPendingCall>
-#define DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
+#define DBUS_PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"_L1
-#define NM_DBUS_SERVICE "org.freedesktop.NetworkManager"
+#define NM_DBUS_INTERFACE "org.freedesktop.NetworkManager"
+#define NM_DBUS_SERVICE NM_DBUS_INTERFACE ""_L1
-#define NM_DBUS_PATH "/org/freedesktop/NetworkManager"
-#define NM_DBUS_INTERFACE NM_DBUS_SERVICE
-#define NM_CONNECTION_DBUS_INTERFACE NM_DBUS_SERVICE ".Connection.Active"
-#define NM_DEVICE_DBUS_INTERFACE NM_DBUS_SERVICE ".Device"
+#define NM_DBUS_PATH "/org/freedesktop/NetworkManager"_L1
+#define NM_CONNECTION_DBUS_INTERFACE NM_DBUS_SERVICE ".Connection.Active"_L1
+#define NM_DEVICE_DBUS_INTERFACE NM_DBUS_SERVICE ".Device"_L1
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
+namespace {
+constexpr QLatin1StringView propertiesChangedKey = "PropertiesChanged"_L1;
+const QString &stateKey()
+{
+ static auto key = u"State"_s;
+ return key;
+}
+const QString &connectivityKey()
+{
+ static auto key = u"Connectivity"_s;
+ return key;
+}
+const QString &primaryConnectionKey()
+{
+ static auto key = u"PrimaryConnection"_s;
+ return key;
+}
+}
+
QNetworkManagerInterfaceBase::QNetworkManagerInterfaceBase(QObject *parent)
- : QDBusAbstractInterface(NM_DBUS_SERVICE ""_L1, NM_DBUS_PATH ""_L1,
+ : QDBusAbstractInterface(NM_DBUS_SERVICE, NM_DBUS_PATH,
NM_DBUS_INTERFACE, QDBusConnection::systemBus(), parent)
{
}
@@ -41,45 +61,49 @@ bool QNetworkManagerInterfaceBase::networkManagerAvailable()
QNetworkManagerInterface::QNetworkManagerInterface(QObject *parent)
: QNetworkManagerInterfaceBase(parent)
{
- if (!isValid())
+ if (!QDBusAbstractInterface::isValid())
return;
PropertiesDBusInterface managerPropertiesInterface(
- NM_DBUS_SERVICE ""_L1, NM_DBUS_PATH ""_L1, DBUS_PROPERTIES_INTERFACE,
+ NM_DBUS_SERVICE, NM_DBUS_PATH, DBUS_PROPERTIES_INTERFACE,
QDBusConnection::systemBus());
QList<QVariant> argumentList;
- argumentList << NM_DBUS_INTERFACE ""_L1;
+ argumentList << NM_DBUS_SERVICE;
QDBusPendingReply<QVariantMap> propsReply = managerPropertiesInterface.callWithArgumentList(
QDBus::Block, "GetAll"_L1, argumentList);
- if (!propsReply.isError()) {
- propertyMap = propsReply.value();
- } else {
- qWarning() << "propsReply" << propsReply.error().message();
+ if (propsReply.isError()) {
+ validDBusConnection = false;
+ if (auto error = propsReply.error(); error.type() != QDBusError::AccessDenied)
+ qWarning() << "Failed to query NetworkManager properties:" << error.message();
+ return;
}
+ propertyMap = propsReply.value();
- QDBusConnection::systemBus().connect(NM_DBUS_SERVICE ""_L1, NM_DBUS_PATH ""_L1,
- DBUS_PROPERTIES_INTERFACE""_L1, "PropertiesChanged"_L1, this,
- SLOT(setProperties(QString, QMap<QString, QVariant>, QList<QString>)));
+ validDBusConnection = QDBusConnection::systemBus().connect(NM_DBUS_SERVICE, NM_DBUS_PATH,
+ DBUS_PROPERTIES_INTERFACE, propertiesChangedKey, this,
+ SLOT(setProperties(QString,QMap<QString,QVariant>,QList<QString>)));
}
QNetworkManagerInterface::~QNetworkManagerInterface()
{
- QDBusConnection::systemBus().disconnect(NM_DBUS_SERVICE ""_L1, NM_DBUS_PATH ""_L1,
- DBUS_PROPERTIES_INTERFACE ""_L1, "PropertiesChanged"_L1, this,
- SLOT(setProperties(QString, QMap<QString, QVariant>, QList<QString>)));
+ QDBusConnection::systemBus().disconnect(NM_DBUS_SERVICE, NM_DBUS_PATH,
+ DBUS_PROPERTIES_INTERFACE, propertiesChangedKey, this,
+ SLOT(setProperties(QString,QMap<QString,QVariant>,QList<QString>)));
}
QNetworkManagerInterface::NMState QNetworkManagerInterface::state() const
{
- if (propertyMap.contains("State"))
- return static_cast<QNetworkManagerInterface::NMState>(propertyMap.value("State").toUInt());
+ auto it = propertyMap.constFind(stateKey());
+ if (it != propertyMap.cend())
+ return static_cast<QNetworkManagerInterface::NMState>(it->toUInt());
return QNetworkManagerInterface::NM_STATE_UNKNOWN;
}
QNetworkManagerInterface::NMConnectivityState QNetworkManagerInterface::connectivityState() const
{
- if (propertyMap.contains("Connectivity"))
- return static_cast<NMConnectivityState>(propertyMap.value("Connectivity").toUInt());
+ auto it = propertyMap.constFind(connectivityKey());
+ if (it != propertyMap.cend())
+ return static_cast<NMConnectivityState>(it->toUInt());
return QNetworkManagerInterface::NM_CONNECTIVITY_UNKNOWN;
}
@@ -102,7 +126,7 @@ static std::optional<QDBusInterface> getPrimaryDevice(const QDBusObjectPath &dev
std::optional<QDBusObjectPath> QNetworkManagerInterface::primaryConnectionDevicePath() const
{
- auto it = propertyMap.constFind(u"PrimaryConnection"_s);
+ auto it = propertyMap.constFind(primaryConnectionKey());
if (it != propertyMap.cend())
return it->value<QDBusObjectPath>();
return std::nullopt;
@@ -150,6 +174,11 @@ auto QNetworkManagerInterface::extractDeviceMetered(const QDBusObjectPath &devic
return static_cast<NMMetered>(metered.toUInt());
}
+void QNetworkManagerInterface::setBackend(QNetworkManagerNetworkInformationBackend *ourBackend)
+{
+ backend = ourBackend;
+}
+
void QNetworkManagerInterface::setProperties(const QString &interfaceName,
const QMap<QString, QVariant> &map,
const QStringList &invalidatedProperties)
@@ -169,18 +198,18 @@ void QNetworkManagerInterface::setProperties(const QString &interfaceName,
}
if (valueChanged) {
- if (i.key() == "State"_L1) {
+ if (i.key() == stateKey()) {
quint32 state = i.value().toUInt();
- Q_EMIT stateChanged(static_cast<NMState>(state));
- } else if (i.key() == "Connectivity"_L1) {
+ backend->onStateChanged(static_cast<NMState>(state));
+ } else if (i.key() == connectivityKey()) {
quint32 state = i.value().toUInt();
- Q_EMIT connectivityChanged(static_cast<NMConnectivityState>(state));
- } else if (i.key() == "PrimaryConnection"_L1) {
+ backend->onConnectivityChanged(static_cast<NMConnectivityState>(state));
+ } else if (i.key() == primaryConnectionKey()) {
const QDBusObjectPath devicePath = i->value<QDBusObjectPath>();
- Q_EMIT deviceTypeChanged(extractDeviceType(devicePath));
- Q_EMIT meteredChanged(extractDeviceMetered(devicePath));
+ backend->onDeviceTypeChanged(extractDeviceType(devicePath));
+ backend->onMeteredChanged(extractDeviceMetered(devicePath));
} else if (i.key() == "Metered"_L1) {
- Q_EMIT meteredChanged(static_cast<NMMetered>(i->toUInt()));
+ backend->onMeteredChanged(static_cast<NMMetered>(i->toUInt()));
}
}
}
diff --git a/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h b/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h
index 9ca862d398..5201e8485b 100644
--- a/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h
+++ b/src/plugins/networkinformation/networkmanager/qnetworkmanagerservice.h
@@ -39,6 +39,7 @@ enum NMDeviceState {
QT_BEGIN_NAMESPACE
class QDBusObjectPath;
+class QNetworkManagerNetworkInformationBackend;
// This tiny class exists for the purpose of seeing if NetworkManager is available without
// initializing everything the derived/full class needs.
@@ -46,7 +47,7 @@ class QNetworkManagerInterfaceBase : public QDBusAbstractInterface
{
Q_OBJECT
public:
- QNetworkManagerInterfaceBase(QObject *parent = nullptr);
+ explicit QNetworkManagerInterfaceBase(QObject *parent = nullptr);
~QNetworkManagerInterfaceBase() = default;
static bool networkManagerAvailable();
@@ -128,19 +129,17 @@ public:
NM_METERED_GUESS_NO,
};
- QNetworkManagerInterface(QObject *parent = nullptr);
+ explicit QNetworkManagerInterface(QObject *parent = nullptr);
~QNetworkManagerInterface();
+ void setBackend(QNetworkManagerNetworkInformationBackend *ourBackend);
+
NMState state() const;
NMConnectivityState connectivityState() const;
NMDeviceType deviceType() const;
NMMetered meteredState() const;
-Q_SIGNALS:
- void stateChanged(NMState);
- void connectivityChanged(NMConnectivityState);
- void deviceTypeChanged(NMDeviceType);
- void meteredChanged(NMMetered);
+ bool isValid() const { return QDBusAbstractInterface::isValid() && validDBusConnection; }
private Q_SLOTS:
void setProperties(const QString &interfaceName, const QMap<QString, QVariant> &map,
@@ -155,6 +154,8 @@ private:
std::optional<QDBusObjectPath> primaryConnectionDevicePath() const;
QVariantMap propertyMap;
+ QNetworkManagerNetworkInformationBackend *backend = nullptr;
+ bool validDBusConnection = true;
};
class PropertiesDBusInterface : public QDBusAbstractInterface
diff --git a/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml b/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml
index 30c326d06f..30fa7431c3 100644
--- a/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml
+++ b/src/plugins/platforminputcontexts/ibus/interfaces/org.freedesktop.IBus.InputContext.xml
@@ -2,6 +2,12 @@
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.freedesktop.IBus.InputContext">
+ <property name="ClientCommitPreedit" type="(b)" access="readwrite">
+ <annotation name="org.qtproject.QtDBus.QtTypeName" value="QIBusPropTypeClientCommitPreedit"/>
+ </property>
+ <property name='ContentType' type='(uu)' access='readwrite'>
+ <annotation name="org.qtproject.QtDBus.QtTypeName" value="QIBusPropTypeContentType"/>
+ </property>
<method name="ProcessKeyEvent">
<arg name="keyval" direction="in" type="u"/>
<arg name="keycode" direction="in" type="u"/>
@@ -62,6 +68,12 @@
<arg name="cursor_pos" type="u"/>
<arg name="visible" type="b"/>
</signal>
+ <signal name="UpdatePreeditTextWithMode">
+ <arg name="text" type="v"/>
+ <arg name="cursor_pos" type="u"/>
+ <arg name="visible" type="b"/>
+ <arg name="mode" type="u"/>
+ </signal>
<signal name="ShowPreeditText"/>
<signal name="HidePreeditText"/>
<signal name="UpdateAuxiliaryText">
diff --git a/src/plugins/platforminputcontexts/ibus/main.cpp b/src/plugins/platforminputcontexts/ibus/main.cpp
index a0036db31e..d74be4bedf 100644
--- a/src/plugins/platforminputcontexts/ibus/main.cpp
+++ b/src/plugins/platforminputcontexts/ibus/main.cpp
@@ -28,6 +28,8 @@ QIBusPlatformInputContext *QIbusPlatformInputContextPlugin::create(const QString
qDBusRegisterMetaType<QIBusAttribute>();
qDBusRegisterMetaType<QIBusAttributeList>();
qDBusRegisterMetaType<QIBusText>();
+ qDBusRegisterMetaType<QIBusPropTypeClientCommitPreedit>();
+ qDBusRegisterMetaType<QIBusPropTypeContentType>();
return new QIBusPlatformInputContext;
}
diff --git a/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.cpp b/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.cpp
index 8e2027272a..248abbc32b 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.cpp
+++ b/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.cpp
@@ -2,7 +2,7 @@
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p qibusinputcontextproxy -c QIBusInputContextProxy interfaces/org.freedesktop.IBus.InputContext.xml
*
- * qdbusxml2cpp is Copyright (C) 2015 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2023 The Qt Company Ltd and other contributors.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
@@ -24,4 +24,3 @@ QIBusInputContextProxy::~QIBusInputContextProxy()
{
}
-#include "moc_qibusinputcontextproxy.cpp"
diff --git a/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h b/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h
index 31a181eec2..82e78aa35b 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h
+++ b/src/plugins/platforminputcontexts/ibus/qibusinputcontextproxy.h
@@ -2,25 +2,26 @@
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p qibusinputcontextproxy -c QIBusInputContextProxy interfaces/org.freedesktop.IBus.InputContext.xml
*
- * qdbusxml2cpp is Copyright (C) 2015 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2023 The Qt Company Ltd and other contributors.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
*/
-#ifndef QIBUSINPUTCONTEXTPROXY_H_1394889529
-#define QIBUSINPUTCONTEXTPROXY_H_1394889529
+#ifndef QIBUSINPUTCONTEXTPROXY_H
+#define QIBUSINPUTCONTEXTPROXY_H
-#include <QObject>
-#include <QByteArray>
-#include <QList>
-#include <QMap>
-#include <QString>
-#include <QStringList>
-#include <QVariant>
-#include <QDBusAbstractInterface>
-#include <QDBusPendingReply>
+#include <QtCore/QObject>
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+#include <QtDBus/QtDBus>
+// Added for QIBusPropTypeClientCommitPreedit and QIBusPropTypeContentType
+#include "qibustypes.h"
/*
* Proxy class for interface org.freedesktop.IBus.InputContext
@@ -37,102 +38,114 @@ public:
~QIBusInputContextProxy();
+ Q_PROPERTY(QIBusPropTypeClientCommitPreedit ClientCommitPreedit READ clientCommitPreedit WRITE setClientCommitPreedit)
+ inline QIBusPropTypeClientCommitPreedit clientCommitPreedit() const
+ { return qvariant_cast< QIBusPropTypeClientCommitPreedit >(property("ClientCommitPreedit")); }
+ inline void setClientCommitPreedit(const QIBusPropTypeClientCommitPreedit &value)
+ { setProperty("ClientCommitPreedit", QVariant::fromValue(value)); }
+
+ Q_PROPERTY(QIBusPropTypeContentType ContentType READ contentType WRITE setContentType)
+ inline QIBusPropTypeContentType contentType() const
+ { return qvariant_cast< QIBusPropTypeContentType >(property("ContentType")); }
+ inline void setContentType(const QIBusPropTypeContentType &value)
+ { setProperty("ContentType", QVariant::fromValue(value)); }
+
public Q_SLOTS: // METHODS
inline QDBusPendingReply<> Destroy()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("Destroy"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("Destroy"), argumentList);
}
inline QDBusPendingReply<> Disable()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("Disable"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("Disable"), argumentList);
}
inline QDBusPendingReply<> Enable()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("Enable"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("Enable"), argumentList);
}
inline QDBusPendingReply<> FocusIn()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("FocusIn"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("FocusIn"), argumentList);
}
inline QDBusPendingReply<> FocusOut()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("FocusOut"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("FocusOut"), argumentList);
}
inline QDBusPendingReply<QDBusVariant> GetEngine()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("GetEngine"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("GetEngine"), argumentList);
}
inline QDBusPendingReply<bool> IsEnabled()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("IsEnabled"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("IsEnabled"), argumentList);
}
inline QDBusPendingReply<bool> ProcessKeyEvent(uint keyval, uint keycode, uint state)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(keyval) << QVariant::fromValue(keycode) << QVariant::fromValue(state);
- return asyncCallWithArgumentList(QLatin1String("ProcessKeyEvent"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("ProcessKeyEvent"), argumentList);
}
inline QDBusPendingReply<> PropertyActivate(const QString &name, int state)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(name) << QVariant::fromValue(state);
- return asyncCallWithArgumentList(QLatin1String("PropertyActivate"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("PropertyActivate"), argumentList);
}
inline QDBusPendingReply<> Reset()
{
QList<QVariant> argumentList;
- return asyncCallWithArgumentList(QLatin1String("Reset"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("Reset"), argumentList);
}
inline QDBusPendingReply<> SetCapabilities(uint caps)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(caps);
- return asyncCallWithArgumentList(QLatin1String("SetCapabilities"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("SetCapabilities"), argumentList);
}
inline QDBusPendingReply<> SetCursorLocation(int x, int y, int w, int h)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(x) << QVariant::fromValue(y) << QVariant::fromValue(w) << QVariant::fromValue(h);
- return asyncCallWithArgumentList(QLatin1String("SetCursorLocation"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("SetCursorLocation"), argumentList);
}
inline QDBusPendingReply<> SetCursorLocationRelative(int x, int y, int w, int h)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(x) << QVariant::fromValue(y) << QVariant::fromValue(w) << QVariant::fromValue(h);
- return asyncCallWithArgumentList(QLatin1String("SetCursorLocationRelative"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("SetCursorLocationRelative"), argumentList);
}
inline QDBusPendingReply<> SetEngine(const QString &name)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(name);
- return asyncCallWithArgumentList(QLatin1String("SetEngine"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("SetEngine"), argumentList);
}
inline QDBusPendingReply<> SetSurroundingText(const QDBusVariant &text, uint cursor_pos, uint anchor_pos)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(text) << QVariant::fromValue(cursor_pos) << QVariant::fromValue(anchor_pos);
- return asyncCallWithArgumentList(QLatin1String("SetSurroundingText"), argumentList);
+ return asyncCallWithArgumentList(QStringLiteral("SetSurroundingText"), argumentList);
}
Q_SIGNALS: // SIGNALS
@@ -156,6 +169,7 @@ Q_SIGNALS: // SIGNALS
void UpdateAuxiliaryText(const QDBusVariant &text, bool visible);
void UpdateLookupTable(const QDBusVariant &table, bool visible);
void UpdatePreeditText(const QDBusVariant &text, uint cursor_pos, bool visible);
+ void UpdatePreeditTextWithMode(const QDBusVariant &text, uint cursor_pos, bool visible, uint mode);
void UpdateProperty(const QDBusVariant &prop);
};
diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
index 49a44519b6..00c7884cda 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
+++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
@@ -8,6 +8,7 @@
#include <QWindow>
#include <QEvent>
#include <QFile>
+#include <QFileInfo>
#include <QStandardPaths>
#include <QDBusVariant>
#include <QDBusPendingReply>
@@ -50,6 +51,13 @@ class QIBusPlatformInputContextPrivate
{
Q_DISABLE_COPY_MOVE(QIBusPlatformInputContextPrivate)
public:
+ // This enum might be synced with IBusPreeditFocusMode
+ // in ibustypes.h of IBUS project
+ enum PreeditFocusMode {
+ PREEDIT_CLEAR = 0,
+ PREEDIT_COMMIT = 1,
+ };
+
QIBusPlatformInputContextPrivate();
~QIBusPlatformInputContextPrivate()
{
@@ -79,6 +87,7 @@ public:
QList<QInputMethodEvent::Attribute> attributes;
bool needsSurroundingText;
QLocale locale;
+ PreeditFocusMode preeditFocusMode = PREEDIT_COMMIT; // for backward compatibility
};
@@ -170,10 +179,18 @@ void QIBusPlatformInputContext::commit()
return;
}
- if (!d->predit.isEmpty()) {
- QInputMethodEvent event;
- event.setCommitString(d->predit);
- QCoreApplication::sendEvent(input, &event);
+ if (d->preeditFocusMode == QIBusPlatformInputContextPrivate::PREEDIT_COMMIT) {
+ if (!d->predit.isEmpty()) {
+ QInputMethodEvent event;
+ event.setCommitString(d->predit);
+ QCoreApplication::sendEvent(input, &event);
+ }
+ } else {
+ if (!d->predit.isEmpty()) {
+ // Clear the existing preedit
+ QInputMethodEvent event;
+ QCoreApplication::sendEvent(input, &event);
+ }
}
d->context->Reset();
@@ -317,6 +334,15 @@ void QIBusPlatformInputContext::updatePreeditText(const QDBusVariant &text, uint
d->predit = t.text;
}
+void QIBusPlatformInputContext::updatePreeditTextWithMode(const QDBusVariant &text, uint cursorPos, bool visible, uint mode)
+{
+ updatePreeditText(text, cursorPos, visible);
+ if (mode > 0)
+ d->preeditFocusMode = QIBusPlatformInputContextPrivate::PreeditFocusMode::PREEDIT_COMMIT;
+ else
+ d->preeditFocusMode = QIBusPlatformInputContextPrivate::PreeditFocusMode::PREEDIT_CLEAR;
+}
+
void QIBusPlatformInputContext::forwardKeyEvent(uint keyval, uint keycode, uint state)
{
if (!qApp)
@@ -586,6 +612,7 @@ void QIBusPlatformInputContext::connectToContextSignals()
if (d->context) {
connect(d->context.get(), SIGNAL(CommitText(QDBusVariant)), SLOT(commitText(QDBusVariant)));
connect(d->context.get(), SIGNAL(UpdatePreeditText(QDBusVariant,uint,bool)), this, SLOT(updatePreeditText(QDBusVariant,uint,bool)));
+ connect(d->context.get(), SIGNAL(UpdatePreeditTextWithMode(QDBusVariant,uint,bool,uint)), this, SLOT(updatePreeditTextWithMode(QDBusVariant,uint,bool,uint)));
connect(d->context.get(), SIGNAL(ForwardKeyEvent(uint,uint,uint)), this, SLOT(forwardKeyEvent(uint,uint,uint)));
connect(d->context.get(), SIGNAL(DeleteSurroundingText(int,uint)), this, SLOT(deleteSurroundingText(int,uint)));
connect(d->context.get(), SIGNAL(RequireSurroundingText()), this, SLOT(surroundingTextRequired()));
@@ -596,8 +623,7 @@ void QIBusPlatformInputContext::connectToContextSignals()
static inline bool checkNeedPortalSupport()
{
- return !QStandardPaths::locate(QStandardPaths::RuntimeLocation, "flatpak-info"_L1).isEmpty()
- || qEnvironmentVariableIsSet("SNAP");
+ return QFileInfo::exists("/.flatpak-info"_L1) || qEnvironmentVariableIsSet("SNAP");
}
static bool shouldConnectIbusPortal()
@@ -692,6 +718,8 @@ void QIBusPlatformInputContextPrivate::createBusProxy()
};
context->SetCapabilities(IBUS_CAP_PREEDIT_TEXT|IBUS_CAP_FOCUS|IBUS_CAP_SURROUNDING_TEXT);
+ context->setClientCommitPreedit(QIBusPropTypeClientCommitPreedit(true));
+
if (debug)
qDebug(">>>> bus connected!");
busConnected = true;
diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h
index 33ddb7af5d..ef8c0b7c8f 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h
+++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.h
@@ -14,6 +14,8 @@
#include <QTimer>
#include <QWindow>
+#include "qibustypes.h"
+
QT_BEGIN_NAMESPACE
class QIBusPlatformInputContextPrivate;
@@ -66,6 +68,7 @@ public:
public Q_SLOTS:
void commitText(const QDBusVariant &text);
void updatePreeditText(const QDBusVariant &text, uint cursor_pos, bool visible);
+ void updatePreeditTextWithMode(const QDBusVariant &text, uint cursor_pos, bool visible, uint mode);
void forwardKeyEvent(uint keyval, uint keycode, uint state);
void cursorRectChanged();
void deleteSurroundingText(int offset, uint n_chars);
diff --git a/src/plugins/platforminputcontexts/ibus/qibusproxy.h b/src/plugins/platforminputcontexts/ibus/qibusproxy.h
index c66e900664..73aff1a3d9 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusproxy.h
+++ b/src/plugins/platforminputcontexts/ibus/qibusproxy.h
@@ -110,7 +110,7 @@ public Q_SLOTS: // METHODS
#endif
QIBusEngineDesc getGlobalEngine();
-private:
+private Q_SLOTS:
void globalEngineChanged(const QString &engine_name);
Q_SIGNALS: // SIGNALS
diff --git a/src/plugins/platforminputcontexts/ibus/qibusproxyportal.cpp b/src/plugins/platforminputcontexts/ibus/qibusproxyportal.cpp
index 54d8f731fb..dc5b37aa6e 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusproxyportal.cpp
+++ b/src/plugins/platforminputcontexts/ibus/qibusproxyportal.cpp
@@ -2,7 +2,7 @@
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p qibusproxyportal -c QIBusProxyPortal interfaces/org.freedesktop.IBus.Portal.xml
*
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2023 The Qt Company Ltd and other contributors.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
@@ -24,4 +24,3 @@ QIBusProxyPortal::~QIBusProxyPortal()
{
}
-#include "moc_qibusproxyportal.cpp"
diff --git a/src/plugins/platforminputcontexts/ibus/qibusproxyportal.h b/src/plugins/platforminputcontexts/ibus/qibusproxyportal.h
index 4b921db814..450205f12a 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusproxyportal.h
+++ b/src/plugins/platforminputcontexts/ibus/qibusproxyportal.h
@@ -2,7 +2,7 @@
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p qibusproxyportal -c QIBusProxyPortal interfaces/org.freedesktop.IBus.Portal.xml
*
- * qdbusxml2cpp is Copyright (C) 2017 The Qt Company Ltd.
+ * qdbusxml2cpp is Copyright (C) 2023 The Qt Company Ltd and other contributors.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
@@ -11,15 +11,14 @@
#ifndef QIBUSPROXYPORTAL_H
#define QIBUSPROXYPORTAL_H
-#include <QObject>
-#include <QByteArray>
-#include <QList>
-#include <QMap>
-#include <QString>
-#include <QStringList>
-#include <QVariant>
-#include <QDBusAbstractInterface>
-#include <QDBusPendingReply>
+#include <QtCore/QObject>
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+#include <QtDBus/QtDBus>
/*
* Proxy class for interface org.freedesktop.IBus.Portal
diff --git a/src/plugins/platforminputcontexts/ibus/qibustypes.cpp b/src/plugins/platforminputcontexts/ibus/qibustypes.cpp
index 9d61d61eb3..ab1a244b6d 100644
--- a/src/plugins/platforminputcontexts/ibus/qibustypes.cpp
+++ b/src/plugins/platforminputcontexts/ibus/qibustypes.cpp
@@ -322,4 +322,44 @@ newest:
argument.endStructure();
}
+QIBusPropTypeClientCommitPreedit::QIBusPropTypeClientCommitPreedit(bool inClientCommitPreedit)
+ : clientCommitPreedit(inClientCommitPreedit)
+{
+}
+
+void QIBusPropTypeClientCommitPreedit::serializeTo(QDBusArgument &argument) const
+{
+ argument.beginStructure();
+ argument << clientCommitPreedit;
+ argument.endStructure();
+}
+
+void QIBusPropTypeClientCommitPreedit::deserializeFrom(const QDBusArgument &argument)
+{
+ argument.beginStructure();
+ argument >> clientCommitPreedit;
+ argument.endStructure();
+}
+
+QIBusPropTypeContentType::QIBusPropTypeContentType(unsigned int inPurpose, unsigned int inHints)
+ : purpose(inPurpose)
+ , hints(inHints)
+{
+}
+
+void QIBusPropTypeContentType::serializeTo(QDBusArgument &argument) const
+{
+ argument.beginStructure();
+ argument << purpose << hints;
+ argument.endStructure();
+}
+
+void QIBusPropTypeContentType::deserializeFrom(const QDBusArgument &argument)
+{
+ argument.beginStructure();
+ argument >> purpose;
+ argument >> hints;
+ argument.endStructure();
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforminputcontexts/ibus/qibustypes.h b/src/plugins/platforminputcontexts/ibus/qibustypes.h
index 60f24bcf54..b697e432a0 100644
--- a/src/plugins/platforminputcontexts/ibus/qibustypes.h
+++ b/src/plugins/platforminputcontexts/ibus/qibustypes.h
@@ -133,6 +133,44 @@ inline QDBusArgument &operator<<(QDBusArgument &argument, const QIBusEngineDesc
inline const QDBusArgument &operator>>(const QDBusArgument &argument, QIBusEngineDesc &desc)
{ desc.deserializeFrom(argument); return argument; }
+class QIBusPropTypeClientCommitPreedit
+{
+public:
+ QIBusPropTypeClientCommitPreedit() {};
+
+ QIBusPropTypeClientCommitPreedit(bool inClientCommitPreedit);
+
+ void serializeTo(QDBusArgument &argument) const;
+ void deserializeFrom(const QDBusArgument &argument);
+
+ bool clientCommitPreedit;
+};
+inline QDBusArgument &operator<<(QDBusArgument &argument, const QIBusPropTypeClientCommitPreedit &data)
+{ data.serializeTo(argument); return argument; }
+inline const QDBusArgument &operator>>(const QDBusArgument &argument, QIBusPropTypeClientCommitPreedit &data)
+{ data.deserializeFrom(argument); return argument; }
+
+class QIBusPropTypeContentType
+{
+public:
+ QIBusPropTypeContentType() {};
+
+ QIBusPropTypeContentType(unsigned int inPurpose, unsigned int inHint);
+
+ void serializeTo(QDBusArgument &argument) const;
+ void deserializeFrom(const QDBusArgument &argument);
+
+ unsigned int purpose;
+ unsigned int hints;
+};
+inline QDBusArgument &operator<<(QDBusArgument &argument, const QIBusPropTypeContentType &data)
+{ data.serializeTo(argument); return argument; }
+inline const QDBusArgument &operator>>(const QDBusArgument &argument, QIBusPropTypeContentType &data)
+{ data.deserializeFrom(argument); return argument; }
+
+Q_DECLARE_TYPEINFO(QIBusPropTypeClientCommitPreedit, Q_RELOCATABLE_TYPE);
+Q_DECLARE_TYPEINFO(QIBusPropTypeContentType, Q_RELOCATABLE_TYPE);
+
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QIBusAttribute)
@@ -140,4 +178,6 @@ Q_DECLARE_METATYPE(QIBusAttributeList)
Q_DECLARE_METATYPE(QIBusText)
Q_DECLARE_METATYPE(QIBusEngineDesc)
+Q_DECLARE_METATYPE(QIBusPropTypeClientCommitPreedit)
+Q_DECLARE_METATYPE(QIBusPropTypeContentType)
#endif
diff --git a/src/plugins/platforms/CMakeLists.txt b/src/plugins/platforms/CMakeLists.txt
index bcf29dedd1..69071a22c2 100644
--- a/src/plugins/platforms/CMakeLists.txt
+++ b/src/plugins/platforms/CMakeLists.txt
@@ -42,16 +42,16 @@ if(QT_FEATURE_vnc AND TARGET Qt::Network)
add_subdirectory(vnc)
endif()
if(FREEBSD)
- # add_subdirectory(bsdfb) # special case TODO
+ # add_subdirectory(bsdfb) # TODO: QTBUG-112768
endif()
if(HAIKU)
- # add_subdirectory(haiku) # special case TODO
+ # add_subdirectory(haiku) # TODO: QTBUG-112768
endif()
if(WASM)
add_subdirectory(wasm)
endif()
if(QT_FEATURE_integrityfb)
- # add_subdirectory(integrity) # special case TODO
+ # add_subdirectory(integrity) # TODO: QTBUG-112768
endif()
if(QT_FEATURE_vkkhrdisplay)
add_subdirectory(vkkhrdisplay)
diff --git a/src/plugins/platforms/android/CMakeLists.txt b/src/plugins/platforms/android/CMakeLists.txt
index f352d5d2ac..d5a275a76c 100644
--- a/src/plugins/platforms/android/CMakeLists.txt
+++ b/src/plugins/platforms/android/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2022 The Qt Company Ltd.
+# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
@@ -14,22 +14,20 @@ qt_internal_add_plugin(QAndroidIntegrationPlugin
androidcontentfileengine.cpp androidcontentfileengine.h
androiddeadlockprotector.h
androidjniaccessibility.cpp androidjniaccessibility.h
- androidjniclipboard.cpp androidjniclipboard.h
androidjniinput.cpp androidjniinput.h
androidjnimain.cpp androidjnimain.h
androidjnimenu.cpp androidjnimenu.h
- androidsurfaceclient.h
main.cpp
qandroidassetsfileenginehandler.cpp qandroidassetsfileenginehandler.h
qandroideventdispatcher.cpp qandroideventdispatcher.h
qandroidinputcontext.cpp qandroidinputcontext.h
qandroidplatformaccessibility.cpp qandroidplatformaccessibility.h
- qandroidplatformbackingstore.cpp qandroidplatformbackingstore.h
qandroidplatformclipboard.cpp qandroidplatformclipboard.h
qandroidplatformdialoghelpers.cpp qandroidplatformdialoghelpers.h
qandroidplatformfiledialoghelper.cpp qandroidplatformfiledialoghelper.h
qandroidplatformfontdatabase.cpp qandroidplatformfontdatabase.h
qandroidplatformforeignwindow.cpp qandroidplatformforeignwindow.h
+ qandroidplatformiconengine.cpp qandroidplatformiconengine.h
qandroidplatformintegration.cpp qandroidplatformintegration.h
qandroidplatformmenu.cpp qandroidplatformmenu.h
qandroidplatformmenubar.cpp qandroidplatformmenubar.h
@@ -42,8 +40,19 @@ qt_internal_add_plugin(QAndroidIntegrationPlugin
qandroidplatformtheme.cpp qandroidplatformtheme.h
qandroidplatformwindow.cpp qandroidplatformwindow.h
qandroidsystemlocale.cpp qandroidsystemlocale.h
- DEFINES
- QT_USE_QSTRINGBUILDER
+ androidwindowembedding.cpp androidwindowembedding.h
+ NO_UNITY_BUILD_SOURCES
+ # Conflicting symbols and macros with androidjnimain.cpp
+ # TODO: Unify the usage of FIND_AND_CHECK_CLASS, and similar
+ # macros. Q_JNI_FIND_AND_CHECK_CLASS in `qjnihelpers_p.h`
+ # seems to be doing most of the work already.
+ androidjnimenu.cpp
+ qandroidinputcontext.cpp
+ androidjniaccessibility.cpp
+ qandroidplatformdialoghelpers.cpp
+ # Conflicting JNI classes, and types
+ androidcontentfileengine.cpp
+ qandroidplatformintegration.cpp
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR}
${QtBase_SOURCE_DIR}/src/3rdparty/android
@@ -75,4 +84,7 @@ qt_internal_extend_target(QAndroidIntegrationPlugin CONDITION QT_FEATURE_vulkan
SOURCES
qandroidplatformvulkaninstance.cpp qandroidplatformvulkaninstance.h
qandroidplatformvulkanwindow.cpp qandroidplatformvulkanwindow.h
+ NO_UNITY_BUILD_SOURCES
+ # To avoid undefined symbols due to missing VK_USE_PLATFORM_ANDROID_KHR
+ qandroidplatformvulkaninstance.cpp qandroidplatformvulkanwindow.cpp
)
diff --git a/src/plugins/platforms/android/androidcontentfileengine.cpp b/src/plugins/platforms/android/androidcontentfileengine.cpp
index 6486890018..db6c601f33 100644
--- a/src/plugins/platforms/android/androidcontentfileengine.cpp
+++ b/src/plugins/platforms/android/androidcontentfileengine.cpp
@@ -16,11 +16,11 @@ QT_BEGIN_NAMESPACE
using namespace QNativeInterface;
using namespace Qt::StringLiterals;
-Q_DECLARE_JNI_TYPE(ContentResolverType, "Landroid/content/ContentResolver;");
-Q_DECLARE_JNI_TYPE(UriType, "Landroid/net/Uri;");
+Q_DECLARE_JNI_CLASS(ContentResolverType, "android/content/ContentResolver");
+Q_DECLARE_JNI_CLASS(UriType, "android/net/Uri");
Q_DECLARE_JNI_CLASS(Uri, "android/net/Uri");
-Q_DECLARE_JNI_TYPE(ParcelFileDescriptorType, "Landroid/os/ParcelFileDescriptor;");
-Q_DECLARE_JNI_TYPE(CursorType, "Landroid/database/Cursor;");
+Q_DECLARE_JNI_CLASS(ParcelFileDescriptorType, "android/os/ParcelFileDescriptor");
+Q_DECLARE_JNI_CLASS(CursorType, "android/database/Cursor");
Q_DECLARE_JNI_TYPE(StringArray, "[Ljava/lang/String;");
static QJniObject &contentResolverInstance()
@@ -194,10 +194,10 @@ QByteArray AndroidContentFileEngine::id() const
return m_documentFile->id().toUtf8();
}
-QDateTime AndroidContentFileEngine::fileTime(FileTime time) const
+QDateTime AndroidContentFileEngine::fileTime(QFile::FileTime time) const
{
switch (time) {
- case FileTime::ModificationTime:
+ case QFile::FileModificationTime:
return m_documentFile->lastModified();
break;
default:
@@ -248,47 +248,37 @@ QString AndroidContentFileEngine::fileName(FileName f) const
return QString();
}
-QAbstractFileEngine::Iterator *AndroidContentFileEngine::beginEntryList(QDir::Filters filters,
- const QStringList &filterNames)
+QAbstractFileEngine::IteratorUniquePtr
+AndroidContentFileEngine::beginEntryList(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames)
{
- return new AndroidContentFileEngineIterator(filters, filterNames);
-}
-
-QAbstractFileEngine::Iterator *AndroidContentFileEngine::endEntryList()
-{
- return nullptr;
+ return std::make_unique<AndroidContentFileEngineIterator>(path, filters, filterNames);
}
AndroidContentFileEngineHandler::AndroidContentFileEngineHandler() = default;
AndroidContentFileEngineHandler::~AndroidContentFileEngineHandler() = default;
-QAbstractFileEngine* AndroidContentFileEngineHandler::create(const QString &fileName) const
+std::unique_ptr<QAbstractFileEngine>
+AndroidContentFileEngineHandler::create(const QString &fileName) const
{
- if (!fileName.startsWith("content"_L1))
- return nullptr;
+ if (fileName.startsWith("content"_L1))
+ return std::make_unique<AndroidContentFileEngine>(fileName);
- return new AndroidContentFileEngine(fileName);
-}
+ return {};
-AndroidContentFileEngineIterator::AndroidContentFileEngineIterator(QDir::Filters filters,
- const QStringList &filterNames)
- : QAbstractFileEngineIterator(filters, filterNames)
-{
}
-AndroidContentFileEngineIterator::~AndroidContentFileEngineIterator()
+AndroidContentFileEngineIterator::AndroidContentFileEngineIterator(
+ const QString &path, QDir::Filters filters, const QStringList &filterNames)
+ : QAbstractFileEngineIterator(path, filters, filterNames)
{
}
-QString AndroidContentFileEngineIterator::next()
+AndroidContentFileEngineIterator::~AndroidContentFileEngineIterator()
{
- if (!hasNext())
- return QString();
- ++m_index;
- return currentFilePath();
}
-bool AndroidContentFileEngineIterator::hasNext() const
+bool AndroidContentFileEngineIterator::advance()
{
if (m_index == -1 && m_files.isEmpty()) {
const auto currentPath = path();
@@ -299,23 +289,32 @@ bool AndroidContentFileEngineIterator::hasNext() const
if (iterDoc->isDirectory())
for (const auto &doc : iterDoc->listFiles())
m_files.append(doc);
+ if (m_files.isEmpty())
+ return false;
+ m_index = 0;
+ return true;
}
- return m_index < (m_files.size() - 1);
+ if (m_index < m_files.size() - 1) {
+ ++m_index;
+ return true;
+ }
+
+ return false;
}
QString AndroidContentFileEngineIterator::currentFileName() const
{
if (m_index < 0 || m_index > m_files.size())
return QString();
- // Returns a full path since contstructing a content path from the file name
- // and a tree URI only will not point to a valid file URI.
- return m_files.at(m_index)->uri().toString();
+ return m_files.at(m_index)->name();
}
QString AndroidContentFileEngineIterator::currentFilePath() const
{
- return currentFileName();
+ if (m_index < 0 || m_index > m_files.size())
+ return QString();
+ return m_files.at(m_index)->uri().toString();
}
// Start of Cursor
@@ -465,7 +464,7 @@ const QLatin1String MIME_TYPE_DIR("vnd.android.document/directory");
QString documentId(const QJniObject &uri)
{
return QJniObject::callStaticMethod<jstring, QtJniTypes::UriType>(
- QtJniTypes::className<QtJniTypes::DocumentsContract>(),
+ QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
"getDocumentId",
uri.object()).toString();
}
@@ -473,7 +472,7 @@ QString documentId(const QJniObject &uri)
QString treeDocumentId(const QJniObject &uri)
{
return QJniObject::callStaticMethod<jstring, QtJniTypes::UriType>(
- QtJniTypes::className<QtJniTypes::DocumentsContract>(),
+ QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
"getTreeDocumentId",
uri.object()).toString();
}
@@ -481,7 +480,7 @@ QString treeDocumentId(const QJniObject &uri)
QJniObject buildChildDocumentsUriUsingTree(const QJniObject &uri, const QString &parentDocumentId)
{
return QJniObject::callStaticMethod<QtJniTypes::UriType>(
- QtJniTypes::className<QtJniTypes::DocumentsContract>(),
+ QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
"buildChildDocumentsUriUsingTree",
uri.object<QtJniTypes::UriType>(),
QJniObject::fromString(parentDocumentId).object<jstring>());
@@ -491,7 +490,7 @@ QJniObject buildChildDocumentsUriUsingTree(const QJniObject &uri, const QString
QJniObject buildDocumentUriUsingTree(const QJniObject &treeUri, const QString &documentId)
{
return QJniObject::callStaticMethod<QtJniTypes::UriType>(
- QtJniTypes::className<QtJniTypes::DocumentsContract>(),
+ QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
"buildDocumentUriUsingTree",
treeUri.object<QtJniTypes::UriType>(),
QJniObject::fromString(documentId).object<jstring>());
@@ -500,7 +499,7 @@ QJniObject buildDocumentUriUsingTree(const QJniObject &treeUri, const QString &d
bool isDocumentUri(const QJniObject &uri)
{
return QJniObject::callStaticMethod<jboolean>(
- QtJniTypes::className<QtJniTypes::DocumentsContract>(),
+ QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
"isDocumentUri",
QNativeInterface::QAndroidApplication::context(),
uri.object<QtJniTypes::UriType>());
@@ -509,7 +508,7 @@ bool isDocumentUri(const QJniObject &uri)
bool isTreeUri(const QJniObject &uri)
{
return QJniObject::callStaticMethod<jboolean>(
- QtJniTypes::className<QtJniTypes::DocumentsContract>(),
+ QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
"isTreeUri",
uri.object<QtJniTypes::UriType>());
}
@@ -518,7 +517,7 @@ QJniObject createDocument(const QJniObject &parentDocumentUri, const QString &mi
const QString &displayName)
{
return QJniObject::callStaticMethod<QtJniTypes::UriType>(
- QtJniTypes::className<QtJniTypes::DocumentsContract>(),
+ QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
"createDocument",
contentResolverInstance().object<QtJniTypes::ContentResolverType>(),
parentDocumentUri.object<QtJniTypes::UriType>(),
@@ -533,7 +532,7 @@ bool deleteDocument(const QJniObject &documentUri)
return {};
return QJniObject::callStaticMethod<jboolean>(
- QtJniTypes::className<QtJniTypes::DocumentsContract>(),
+ QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
"deleteDocument",
contentResolverInstance().object<QtJniTypes::ContentResolverType>(),
documentUri.object<QtJniTypes::UriType>());
@@ -548,7 +547,7 @@ QJniObject moveDocument(const QJniObject &sourceDocumentUri,
return {};
return QJniObject::callStaticMethod<QtJniTypes::UriType>(
- QtJniTypes::className<QtJniTypes::DocumentsContract>(),
+ QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
"moveDocument",
contentResolverInstance().object<QtJniTypes::ContentResolverType>(),
sourceDocumentUri.object<QtJniTypes::UriType>(),
@@ -563,7 +562,7 @@ QJniObject renameDocument(const QJniObject &documentUri, const QString &displayN
return {};
return QJniObject::callStaticMethod<QtJniTypes::UriType>(
- QtJniTypes::className<QtJniTypes::DocumentsContract>(),
+ QtJniTypes::Traits<QtJniTypes::DocumentsContract>::className(),
"renameDocument",
contentResolverInstance().object<QtJniTypes::ContentResolverType>(),
documentUri.object<QtJniTypes::UriType>(),
@@ -593,33 +592,38 @@ DocumentFile::DocumentFile(const QJniObject &uri,
QJniObject parseUri(const QString &uri)
{
+ QString uriToParse = uri;
+ if (uriToParse.contains(' '))
+ uriToParse.replace(' ', QUrl::toPercentEncoding(" "));
+
return QJniObject::callStaticMethod<QtJniTypes::UriType>(
- QtJniTypes::className<QtJniTypes::Uri>(),
+ QtJniTypes::Traits<QtJniTypes::Uri>::className(),
"parse",
- QJniObject::fromString(uri).object<jstring>());
+ QJniObject::fromString(uriToParse).object<jstring>());
}
DocumentFilePtr DocumentFile::parseFromAnyUri(const QString &fileName)
{
- const QJniObject uri = parseUri(fileName);
+ const QString encodedUri = QUrl(fileName).toEncoded();
+ const QJniObject uri = parseUri(encodedUri);
- if (DocumentsContract::isDocumentUri(uri))
+ if (DocumentsContract::isDocumentUri(uri) || !DocumentsContract::isTreeUri(uri))
return fromSingleUri(uri);
const QString documentType = "/document/"_L1;
const QString treeType = "/tree/"_L1;
- const int treeIndex = fileName.indexOf(treeType);
- const int documentIndex = fileName.indexOf(documentType);
+ const int treeIndex = encodedUri.indexOf(treeType);
+ const int documentIndex = encodedUri.indexOf(documentType);
const int index = fileName.lastIndexOf("/");
if (index <= treeIndex + treeType.size() || index <= documentIndex + documentType.size())
return fromTreeUri(uri);
- const QString parentUrl = fileName.left(index);
+ const QString parentUrl = encodedUri.left(index);
DocumentFilePtr parentDocFile = fromTreeUri(parseUri(parentUrl));
- const QString baseName = fileName.mid(index);
+ const QString baseName = encodedUri.mid(index);
const QString fileUrl = parentUrl + QUrl::toPercentEncoding(baseName);
DocumentFilePtr docFile = std::make_shared<MakeableDocumentFile>(parseUri(fileUrl));
diff --git a/src/plugins/platforms/android/androidcontentfileengine.h b/src/plugins/platforms/android/androidcontentfileengine.h
index 35db7b44b6..a5dd1b30f3 100644
--- a/src/plugins/platforms/android/androidcontentfileengine.h
+++ b/src/plugins/platforms/android/androidcontentfileengine.h
@@ -27,11 +27,11 @@ public:
bool rmdir(const QString &dirName, bool recurseParentDirectories) const override;
QByteArray id() const override;
bool caseSensitive() const override { return true; }
- QDateTime fileTime(FileTime time) const override;
+ QDateTime fileTime(QFile::FileTime time) const override;
FileFlags fileFlags(FileFlags type = FileInfoAll) const override;
QString fileName(FileName file = DefaultName) const override;
- QAbstractFileEngine::Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override;
- QAbstractFileEngine::Iterator *endEntryList() override;
+ IteratorUniquePtr beginEntryList(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames) override;
private:
void closeNativeFileDescriptor();
@@ -43,19 +43,22 @@ private:
class AndroidContentFileEngineHandler : public QAbstractFileEngineHandler
{
+ Q_DISABLE_COPY_MOVE(AndroidContentFileEngineHandler)
public:
AndroidContentFileEngineHandler();
~AndroidContentFileEngineHandler();
- QAbstractFileEngine *create(const QString &fileName) const override;
+ std::unique_ptr<QAbstractFileEngine> create(const QString &fileName) const override;
};
class AndroidContentFileEngineIterator : public QAbstractFileEngineIterator
{
public:
- AndroidContentFileEngineIterator(QDir::Filters filters, const QStringList &filterNames);
+ AndroidContentFileEngineIterator(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames);
~AndroidContentFileEngineIterator();
- QString next() override;
- bool hasNext() const override;
+
+ bool advance() override;
+
QString currentFileName() const override;
QString currentFilePath() const override;
private:
diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp
index 8990289dc4..da5b63ef21 100644
--- a/src/plugins/platforms/android/androidjniaccessibility.cpp
+++ b/src/plugins/platforms/android/androidjniaccessibility.cpp
@@ -15,11 +15,12 @@
#include <QtCore/private/qjnihelpers_p.h>
#include <QtCore/QJniObject>
#include <QtGui/private/qhighdpiscaling_p.h>
+
#include <QtCore/QObject>
+#include <QtCore/qpointer.h>
#include <QtCore/qvarlengtharray.h>
static const char m_qtTag[] = "Qt A11Y";
-static const char m_classErrorMsg[] = "Can't find class \"%s\"";
QT_BEGIN_NAMESPACE
@@ -48,7 +49,7 @@ namespace QtAndroidAccessibility
// Because of that almost every method here is split into two parts.
// The _helper part is executed in the context of m_accessibilityContext
// on the main thread. The other part is executed in Java thread.
- static QPointer<QObject> m_accessibilityContext = nullptr;
+ Q_CONSTINIT static QPointer<QObject> m_accessibilityContext = {};
// This method is called from the Qt main thread, and normally a
// QGuiApplication instance will be used as a parent.
@@ -81,8 +82,7 @@ namespace QtAndroidAccessibility
void initialize()
{
- QJniObject::callStaticMethod<void>(QtAndroid::applicationClass(),
- "initializeAccessibility");
+ QtAndroid::qtActivityDelegate().callMethod<void>("initializeAccessibility");
}
bool isActive()
@@ -127,6 +127,12 @@ namespace QtAndroidAccessibility
QtAndroid::notifyObjectHide(accessibilityObjectId, parentObjectId);
}
+ void notifyObjectShow(uint accessibilityObjectId)
+ {
+ const auto parentObjectId = parentId_helper(accessibilityObjectId);
+ QtAndroid::notifyObjectShow(parentObjectId);
+ }
+
void notifyObjectFocus(uint accessibilityObjectId)
{
QtAndroid::notifyObjectFocus(accessibilityObjectId);
@@ -351,16 +357,6 @@ namespace QtAndroidAccessibility
return result && oldPosition != screenRect_helper(firstChildId, false);
}
-
-#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
-clazz = env->FindClass(CLASS_NAME); \
-if (!clazz) { \
- __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_classErrorMsg, CLASS_NAME); \
- return JNI_FALSE; \
-}
-
- //__android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE);
-
static QString textFromValue(QAccessibleInterface *iface)
{
QString valueStr;
@@ -557,7 +553,7 @@ if (!clazz) { \
return true;
}
- static JNINativeMethod methods[] = {
+ static const JNINativeMethod methods[] = {
{"setActive","(Z)V",(void*)setActive},
{"childIdListForAccessibleObject", "(I)[I", (jintArray)childIdListForAccessibleObject},
{"parentId", "(I)I", (void*)parentId},
@@ -577,13 +573,10 @@ if (!clazz) { \
return false; \
}
- bool registerNatives(JNIEnv *env)
+ bool registerNatives(QJniEnvironment &env)
{
- jclass clazz;
- FIND_AND_CHECK_CLASS("org/qtproject/qt/android/accessibility/QtNativeAccessibility");
- jclass appClass = static_cast<jclass>(env->NewGlobalRef(clazz));
-
- if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ if (!env.registerNativeMethods("org/qtproject/qt/android/QtNativeAccessibility",
+ methods, sizeof(methods) / sizeof(methods[0]))) {
__android_log_print(ANDROID_LOG_FATAL,"Qt A11y", "RegisterNatives failed");
return false;
}
diff --git a/src/plugins/platforms/android/androidjniaccessibility.h b/src/plugins/platforms/android/androidjniaccessibility.h
index 9bbbe80fe9..6e8e059334 100644
--- a/src/plugins/platforms/android/androidjniaccessibility.h
+++ b/src/plugins/platforms/android/androidjniaccessibility.h
@@ -9,14 +9,16 @@
QT_BEGIN_NAMESPACE
class QObject;
+class QJniEnvironment;
namespace QtAndroidAccessibility
{
void initialize();
bool isActive();
- bool registerNatives(JNIEnv *env);
+ bool registerNatives(QJniEnvironment &env);
void notifyLocationChange(uint accessibilityObjectId);
void notifyObjectHide(uint accessibilityObjectId);
+ void notifyObjectShow(uint accessibilityObjectId);
void notifyObjectFocus(uint accessibilityObjectId);
void notifyValueChanged(uint accessibilityObjectId);
void notifyScrolledEvent(uint accessibilityObjectId);
diff --git a/src/plugins/platforms/android/androidjniclipboard.cpp b/src/plugins/platforms/android/androidjniclipboard.cpp
deleted file mode 100644
index 81663cac0c..0000000000
--- a/src/plugins/platforms/android/androidjniclipboard.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include "androidjniclipboard.h"
-#include <QtCore/QUrl>
-#include <QtCore/QJniObject>
-#include <QtCore/QJniEnvironment>
-
-QT_BEGIN_NAMESPACE
-
-using namespace QtAndroid;
-namespace QtAndroidClipboard
-{
- QAndroidPlatformClipboard *m_manager = nullptr;
-
- static JNINativeMethod methods[] = {
- {"onClipboardDataChanged", "()V", (void *)onClipboardDataChanged}
- };
-
- void setClipboardManager(QAndroidPlatformClipboard *manager)
- {
- m_manager = manager;
- QJniObject::callStaticMethod<void>(applicationClass(), "registerClipboardManager");
- jclass appClass = QtAndroid::applicationClass();
- QJniEnvironment env;
- if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
- __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
- return;
- }
- }
- void clearClipboardData()
- {
- QJniObject::callStaticMethod<void>(applicationClass(), "clearClipData");
- }
- void setClipboardMimeData(QMimeData *data)
- {
- clearClipboardData();
- if (data->hasUrls()) {
- QList<QUrl> urls = data->urls();
- for (const auto &u : std::as_const(urls)) {
- QJniObject::callStaticMethod<void>(applicationClass(),
- "setClipboardUri",
- "(Ljava/lang/String;)V",
- QJniObject::fromString(u.toEncoded()).object());
- }
- } else if (data->hasText()) { // hasText || hasUrls, so the order matter here.
- QJniObject::callStaticMethod<void>(applicationClass(),
- "setClipboardText", "(Ljava/lang/String;)V",
- QJniObject::fromString(data->text()).object());
- } else if (data->hasHtml()) {
- QJniObject::callStaticMethod<void>(applicationClass(),
- "setClipboardHtml",
- "(Ljava/lang/String;Ljava/lang/String;)V",
- QJniObject::fromString(data->text()).object(),
- QJniObject::fromString(data->html()).object());
- }
- }
-
- QMimeData *getClipboardMimeData()
- {
- QMimeData *data = new QMimeData;
- if (QJniObject::callStaticMethod<jboolean>(applicationClass(), "hasClipboardText")) {
- data->setText(QJniObject::callStaticObjectMethod(applicationClass(),
- "getClipboardText",
- "()Ljava/lang/String;").toString());
- }
- if (QJniObject::callStaticMethod<jboolean>(applicationClass(), "hasClipboardHtml")) {
- data->setHtml(QJniObject::callStaticObjectMethod(applicationClass(),
- "getClipboardHtml",
- "()Ljava/lang/String;").toString());
- }
- if (QJniObject::callStaticMethod<jboolean>(applicationClass(), "hasClipboardUri")) {
- QJniObject uris = QJniObject::callStaticObjectMethod(applicationClass(),
- "getClipboardUris",
- "()[Ljava/lang/String;");
- if (uris.isValid()) {
- QList<QUrl> urls;
- QJniEnvironment env;
- jobjectArray juris = uris.object<jobjectArray>();
- const jint nUris = env->GetArrayLength(juris);
- urls.reserve(static_cast<int>(nUris));
- for (int i = 0; i < nUris; ++i)
- urls << QUrl(QJniObject(env->GetObjectArrayElement(juris, i)).toString());
- data->setUrls(urls);
- }
- }
- return data;
- }
-
- void onClipboardDataChanged(JNIEnv */*env*/, jobject /*thiz*/)
- {
- m_manager->emitChanged(QClipboard::Clipboard);
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/androidjniclipboard.h b/src/plugins/platforms/android/androidjniclipboard.h
deleted file mode 100644
index 24feeef9b3..0000000000
--- a/src/plugins/platforms/android/androidjniclipboard.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef ANDROIDJNICLIPBOARD_H
-#define ANDROIDJNICLIPBOARD_H
-
-#include <QString>
-#include "qandroidplatformclipboard.h"
-#include "androidjnimain.h"
-
-QT_BEGIN_NAMESPACE
-
-class QAndroidPlatformClipboard;
-namespace QtAndroidClipboard
-{
- // Clipboard support
- void setClipboardManager(QAndroidPlatformClipboard *manager);
- void setClipboardMimeData(QMimeData *data);
- QMimeData *getClipboardMimeData();
- void clearClipboardData();
- void onClipboardDataChanged(JNIEnv */*env*/, jobject /*thiz*/);
- // Clipboard support
-}
-
-QT_END_NAMESPACE
-
-#endif // ANDROIDJNICLIPBOARD_H
diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp
index fae8668f63..d074e73b9e 100644
--- a/src/plugins/platforms/android/androidjniinput.cpp
+++ b/src/plugins/platforms/android/androidjniinput.cpp
@@ -1,3 +1,4 @@
+// Copyright (C) 2023 The Qt Company Ltd.
// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
// Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
@@ -8,6 +9,7 @@
#include "androidjnimain.h"
#include "qandroidplatformintegration.h"
+#include <qpa/qplatformwindow.h>
#include <qpa/qwindowsysteminterface.h>
#include <QTouchEvent>
#include <QPointer>
@@ -17,25 +19,92 @@
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods");
+
using namespace QtAndroid;
+Q_DECLARE_JNI_CLASS(QtLayout, "org/qtproject/qt/android/QtLayout")
+
namespace QtAndroidInput
{
static bool m_ignoreMouseEvents = false;
+ static Qt::MouseButtons m_buttons = Qt::NoButton;
+
static QRect m_softwareKeyboardRect;
static QList<QWindowSystemInterface::TouchPoint> m_touchPoints;
static QPointer<QWindow> m_mouseGrabber;
+ GenericMotionEventListener::~GenericMotionEventListener() {}
+ namespace {
+ struct GenericMotionEventListeners {
+ QMutex mutex;
+ QList<QtAndroidInput::GenericMotionEventListener *> listeners;
+ };
+ }
+ Q_GLOBAL_STATIC(GenericMotionEventListeners, g_genericMotionEventListeners)
+
+ static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, jobject event)
+ {
+ jboolean ret = JNI_FALSE;
+ QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
+ for (auto *listener : std::as_const(g_genericMotionEventListeners()->listeners))
+ ret |= listener->handleGenericMotionEvent(event);
+ return ret;
+ }
+
+ KeyEventListener::~KeyEventListener() {}
+ namespace {
+ struct KeyEventListeners {
+ QMutex mutex;
+ QList<QtAndroidInput::KeyEventListener *> listeners;
+ };
+ }
+ Q_GLOBAL_STATIC(KeyEventListeners, g_keyEventListeners)
+
+ static jboolean dispatchKeyEvent(JNIEnv *, jclass, jobject event)
+ {
+ jboolean ret = JNI_FALSE;
+ QMutexLocker locker(&g_keyEventListeners()->mutex);
+ for (auto *listener : std::as_const(g_keyEventListeners()->listeners))
+ ret |= listener->handleKeyEvent(event);
+ return ret;
+ }
+
+ void registerGenericMotionEventListener(QtAndroidInput::GenericMotionEventListener *listener)
+ {
+ QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
+ g_genericMotionEventListeners()->listeners.push_back(listener);
+ }
+
+ void unregisterGenericMotionEventListener(QtAndroidInput::GenericMotionEventListener *listener)
+ {
+ QMutexLocker locker(&g_genericMotionEventListeners()->mutex);
+ g_genericMotionEventListeners()->listeners.removeOne(listener);
+ }
+
+ void registerKeyEventListener(QtAndroidInput::KeyEventListener *listener)
+ {
+ QMutexLocker locker(&g_keyEventListeners()->mutex);
+ g_keyEventListeners()->listeners.push_back(listener);
+ }
+
+ void unregisterKeyEventListener(QtAndroidInput::KeyEventListener *listener)
+ {
+ QMutexLocker locker(&g_keyEventListeners()->mutex);
+ g_keyEventListeners()->listeners.removeOne(listener);
+ }
+
+ QJniObject qtLayout()
+ {
+ return qtActivityDelegate().callMethod<QtJniTypes::QtLayout>("getQtLayout");
+ }
+
void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd)
{
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << ">>> UPDATESELECTION" << selStart << selEnd << candidatesStart << candidatesEnd;
-#endif
- QJniObject::callStaticMethod<void>(applicationClass(),
- "updateSelection",
- "(IIII)V",
+ qCDebug(lcQpaInputMethods) << ">>> UPDATESELECTION" << selStart << selEnd << candidatesStart << candidatesEnd;
+ qtInputDelegate().callMethod<void>("updateSelection",
selStart,
selEnd,
candidatesStart,
@@ -44,39 +113,33 @@ namespace QtAndroidInput
void showSoftwareKeyboard(int left, int top, int width, int height, int inputHints, int enterKeyType)
{
- QJniObject::callStaticMethod<void>(applicationClass(),
- "showSoftwareKeyboard",
- "(IIIIII)V",
+ qtInputDelegate().callMethod<void>("showSoftwareKeyboard",
+ QtAndroidPrivate::activity(),
+ qtLayout().object<QtJniTypes::QtLayout>(),
left,
top,
width,
height,
inputHints,
enterKeyType);
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints << enterKeyType;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ SHOWSOFTWAREKEYBOARD" << left << top << width << height << inputHints << enterKeyType;
}
void resetSoftwareKeyboard()
{
- QJniObject::callStaticMethod<void>(applicationClass(), "resetSoftwareKeyboard");
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@ RESETSOFTWAREKEYBOARD");
-#endif
+ qtInputDelegate().callMethod<void>("resetSoftwareKeyboard");
+ qCDebug(lcQpaInputMethods) << "@@@ RESETSOFTWAREKEYBOARD";
}
void hideSoftwareKeyboard()
{
- QJniObject::callStaticMethod<void>(applicationClass(), "hideSoftwareKeyboard");
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@ HIDESOFTWAREKEYBOARD");
-#endif
+ qtInputDelegate().callMethod<void>("hideSoftwareKeyboard");
+ qCDebug(lcQpaInputMethods) << "@@@ HIDESOFTWAREKEYBOARD";
}
bool isSoftwareKeyboardVisible()
{
- return QJniObject::callStaticMethod<jboolean>(applicationClass(), "isSoftwareKeyboardVisible");
+ return qtInputDelegate().callMethod<jboolean>("isSoftwareKeyboardVisible");
}
QRect softwareKeyboardRect()
@@ -86,81 +149,150 @@ namespace QtAndroidInput
int getSelectHandleWidth()
{
- return QJniObject::callStaticMethod<jint>(applicationClass(), "getSelectHandleWidth");
+ return qtInputDelegate().callMethod<jint>("getSelectHandleWidth");
}
void updateHandles(int mode, QPoint editMenuPos, uint32_t editButtons, QPoint cursor, QPoint anchor, bool rtl)
{
- QJniObject::callStaticMethod<void>(applicationClass(), "updateHandles", "(IIIIIIIIZ)V",
+ qtInputDelegate().callMethod<void>("updateHandles",
+ QtAndroidPrivate::activity(),
+ qtLayout().object<QtJniTypes::QtLayout>(),
mode, editMenuPos.x(), editMenuPos.y(), editButtons,
cursor.x(), cursor.y(),
anchor.x(), anchor.y(), rtl);
}
- static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
+ // from https://developer.android.com/reference/android/view/MotionEvent#getButtonState()
+ enum AndroidMouseButton {
+ BUTTON_PRIMARY = 0x00000001,
+ BUTTON_SECONDARY = 0x00000002,
+ BUTTON_TERTIARY = 0x00000004,
+ BUTTON_BACK = 0x00000008,
+ BUTTON_FORWARD = 0x00000010,
+ BUTTON_STYLUS_PRIMARY = 0x00000020,
+ BUTTON_STYLUS_SECONDARY = 0x00000040,
+ };
+ Q_DECLARE_FLAGS(AndroidMouseButtons, AndroidMouseButton)
+
+ static Qt::MouseButtons toMouseButtons(jint j_buttons)
+ {
+ const auto buttons = static_cast<AndroidMouseButtons>(j_buttons);
+ Qt::MouseButtons mouseButtons;
+ if (buttons.testFlag(BUTTON_PRIMARY))
+ mouseButtons.setFlag(Qt::LeftButton);
+
+ if (buttons.testFlag(BUTTON_SECONDARY))
+ mouseButtons.setFlag(Qt::RightButton);
+
+ if (buttons.testFlag(BUTTON_TERTIARY))
+ mouseButtons.setFlag(Qt::MiddleButton);
+
+ if (buttons.testFlag(BUTTON_BACK))
+ mouseButtons.setFlag(Qt::BackButton);
+
+ if (buttons.testFlag(BUTTON_FORWARD))
+ mouseButtons.setFlag(Qt::ForwardButton);
+
+ if (buttons.testFlag(BUTTON_STYLUS_PRIMARY))
+ mouseButtons.setFlag(Qt::LeftButton);
+
+ if (buttons.testFlag(BUTTON_STYLUS_SECONDARY))
+ mouseButtons.setFlag(Qt::RightButton);
+
+ // Fall back to left button
+ if (Q_UNLIKELY(buttons != 0 && mouseButtons == Qt::NoButton)) {
+ qWarning() << "Unhandled button value:" << buttons << "Falling back to Qt::LeftButton";
+ mouseButtons = Qt::LeftButton;
+ }
+ return mouseButtons;
+ }
+
+ static void sendMouseButtonEvents(QWindow *topLevel, QPoint localPos, QPoint globalPos,
+ jint mouseButtonState, QEvent::Type type)
+ {
+ const Qt::MouseButtons mouseButtons = toMouseButtons(mouseButtonState);
+ const Qt::MouseButtons changedButtons = mouseButtons & ~m_buttons;
+
+ if (changedButtons == Qt::NoButton)
+ return;
+
+ static_assert (sizeof(changedButtons) <= sizeof(uint), "Qt::MouseButtons size changed. Adapt code.");
+
+ for (uint buttonInt = 0x1; static_cast<uint>(changedButtons) >= buttonInt; buttonInt <<= 1) {
+ const auto button = static_cast<Qt::MouseButton>(buttonInt);
+ if (changedButtons.testFlag(button)) {
+ QWindowSystemInterface::handleMouseEvent(topLevel, localPos, globalPos,
+ mouseButtons, button, type);
+ }
+ }
+ }
+
+ static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y, jint mouseButtonState)
{
if (m_ignoreMouseEvents)
return;
- QPoint globalPos(x,y);
- QWindow *tlw = topLevelWindowAt(globalPos);
- m_mouseGrabber = tlw;
- QPoint localPos = tlw ? (globalPos - tlw->position()) : globalPos;
- QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos,
- Qt::MouseButtons(Qt::LeftButton),
- Qt::LeftButton, QEvent::MouseButtonPress);
- }
-
- static void mouseUp(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
- {
- QPoint globalPos(x,y);
- QWindow *tlw = m_mouseGrabber.data();
- if (!tlw)
- tlw = topLevelWindowAt(globalPos);
- QPoint localPos = tlw ? (globalPos -tlw->position()) : globalPos;
- QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos,
- Qt::MouseButtons(Qt::NoButton),
- Qt::LeftButton, QEvent::MouseButtonRelease);
+ const QPoint globalPos(x,y);
+ QWindow *window = windowFromId(winId);
+ m_mouseGrabber = window;
+ const QPoint localPos = window && window->handle() ?
+ window->handle()->mapFromGlobal(globalPos) : globalPos;
+ sendMouseButtonEvents(window, localPos, globalPos, mouseButtonState, QEvent::MouseButtonPress);
+ }
+
+ static void mouseUp(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y, jint mouseButtonState)
+ {
+ const QPoint globalPos(x,y);
+ QWindow *window = m_mouseGrabber.data();
+ if (!window)
+ window = windowFromId(winId);
+
+ const QPoint localPos = window && window->handle() ?
+ window->handle()->mapFromGlobal(globalPos) : globalPos;
+
+ sendMouseButtonEvents(window, localPos, globalPos, mouseButtonState, QEvent::MouseButtonRelease);
m_ignoreMouseEvents = false;
- m_mouseGrabber = 0;
+ m_mouseGrabber.clear();
}
- static void mouseMove(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
+ static void mouseMove(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y)
{
if (m_ignoreMouseEvents)
return;
- QPoint globalPos(x,y);
- QWindow *tlw = m_mouseGrabber.data();
- if (!tlw)
- tlw = topLevelWindowAt(globalPos);
- QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos;
- QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos,
+ const QPoint globalPos(x,y);
+ QWindow *window = m_mouseGrabber.data();
+ if (!window)
+ window = windowFromId(winId);
+ const QPoint localPos = window && window->handle() ?
+ window->handle()->mapFromGlobal(globalPos) : globalPos;
+ QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
Qt::MouseButtons(m_mouseGrabber ? Qt::LeftButton : Qt::NoButton),
Qt::NoButton, QEvent::MouseMove);
}
- static void mouseWheel(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y, jfloat hdelta, jfloat vdelta)
+ static void mouseWheel(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y, jfloat hdelta, jfloat vdelta)
{
if (m_ignoreMouseEvents)
return;
- QPoint globalPos(x,y);
- QWindow *tlw = m_mouseGrabber.data();
- if (!tlw)
- tlw = topLevelWindowAt(globalPos);
- QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos;
- QPoint angleDelta(hdelta * 120, vdelta * 120);
+ const QPoint globalPos(x,y);
+ QWindow *window = m_mouseGrabber.data();
+ if (!window)
+ window = windowFromId(winId);
+ const QPoint localPos = window && window->handle() ?
+ window->handle()->mapFromGlobal(globalPos) : globalPos;
+ const QPoint angleDelta(hdelta * 120, vdelta * 120);
- QWindowSystemInterface::handleWheelEvent(tlw,
+ QWindowSystemInterface::handleWheelEvent(window,
localPos,
globalPos,
QPoint(),
angleDelta);
}
- static void longPress(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
+ static void longPress(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint x, jint y)
{
QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
if (inputContext && qGuiApp)
@@ -171,16 +303,17 @@ namespace QtAndroidInput
if (!rightMouseFromLongPress)
return;
m_ignoreMouseEvents = true;
- QPoint globalPos(x,y);
- QWindow *tlw = topLevelWindowAt(globalPos);
- QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos;
+ const QPoint globalPos(x,y);
+ QWindow *window = windowFromId(winId);
+ const QPoint localPos = window && window->handle() ?
+ window->handle()->mapFromGlobal(globalPos) : globalPos;
// Click right button if no other button is already pressed.
if (!m_mouseGrabber) {
- QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos,
+ QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
Qt::MouseButtons(Qt::RightButton), Qt::RightButton,
QEvent::MouseButtonPress);
- QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos,
+ QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
Qt::MouseButtons(Qt::NoButton), Qt::RightButton,
QEvent::MouseButtonRelease);
}
@@ -218,12 +351,11 @@ namespace QtAndroidInput
touchPoint.rotation = qRadiansToDegrees(rotation);
touchPoint.normalPosition = QPointF(double(x / dw), double(y / dh));
touchPoint.state = state;
- touchPoint.area = QRectF(x - double(minor),
- y - double(major),
- double(minor * 2),
- double(major * 2));
+ touchPoint.area = QRectF(x - double(minor * 0.5f),
+ y - double(major * 0.5f),
+ double(minor),
+ double(major));
m_touchPoints.push_back(touchPoint);
-
if (state == QEventPoint::State::Pressed) {
QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
if (inputContext && qGuiApp)
@@ -254,31 +386,35 @@ namespace QtAndroidInput
return touchDevice;
}
- static void touchEnd(JNIEnv * /*env*/, jobject /*thiz*/, jint /*winId*/, jint /*action*/)
+ static void touchEnd(JNIEnv * /*env*/, jobject /*thiz*/, jint winId, jint /*action*/)
{
if (m_touchPoints.isEmpty())
return;
QMutexLocker lock(QtAndroid::platformInterfaceMutex());
- QPointingDevice *touchDevice = getTouchDevice();
+ const QPointingDevice *touchDevice = getTouchDevice();
if (!touchDevice)
return;
- QWindow *window = QtAndroid::topLevelWindowAt(m_touchPoints.at(0).area.center().toPoint());
+ QWindow *window = QtAndroid::windowFromId(winId);
+ if (!window)
+ return;
QWindowSystemInterface::handleTouchEvent(window, touchDevice, m_touchPoints);
}
- static void touchCancel(JNIEnv * /*env*/, jobject /*thiz*/, jint /*winId*/)
+ static void touchCancel(JNIEnv * /*env*/, jobject /*thiz*/, jint winId)
{
if (m_touchPoints.isEmpty())
return;
QMutexLocker lock(QtAndroid::platformInterfaceMutex());
- QPointingDevice *touchDevice = getTouchDevice();
+ const QPointingDevice *touchDevice = getTouchDevice();
if (!touchDevice)
return;
- QWindow *window = QtAndroid::topLevelWindowAt(m_touchPoints.at(0).area.center().toPoint());
+ QWindow *window = QtAndroid::windowFromId(winId);
+ if (!window)
+ return;
QWindowSystemInterface::handleTouchCancelEvent(window, touchDevice);
}
@@ -291,14 +427,14 @@ namespace QtAndroidInput
#endif // QT_CONFIG(tabletevent)
}
- static void tabletEvent(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint deviceId, jlong time, jint action,
+ static void tabletEvent(JNIEnv */*env*/, jobject /*thiz*/, jint winId, jint deviceId, jlong time, jint action,
jint pointerType, jint buttonState, jfloat x, jfloat y, jfloat pressure)
{
#if QT_CONFIG(tabletevent)
- QPointF globalPosF(x, y);
- QPoint globalPos((int)x, (int)y);
- QWindow *tlw = topLevelWindowAt(globalPos);
- QPointF localPos = tlw ? (globalPosF - tlw->position()) : globalPosF;
+ const QPointF globalPosF(x, y);
+ QWindow *window = windowFromId(winId);
+ const QPointF localPos = window && window->handle() ?
+ window->handle()->mapFromGlobalF(globalPosF) : globalPosF;
// Galaxy Note with plain Android:
// 0 1 0 stylus press
@@ -318,6 +454,7 @@ namespace QtAndroidInput
Qt::MouseButtons buttons = Qt::NoButton;
switch (action) {
case 1: // ACTION_UP
+ case 6: // ACTION_POINTER_UP, happens if stylus is not the primary pointer
case 212: // stylus release while side-button held on Galaxy Note 4
buttons = Qt::NoButton;
break;
@@ -329,11 +466,9 @@ namespace QtAndroidInput
break;
}
-#ifdef QT_DEBUG_ANDROID_STYLUS
- qDebug() << action << pointerType << buttonState << '@' << x << y << "pressure" << pressure << ": buttons" << buttons;
-#endif
+ qCDebug(lcQpaInputMethods) << action << pointerType << buttonState << '@' << x << y << "pressure" << pressure << ": buttons" << buttons;
- QWindowSystemInterface::handleTabletEvent(tlw, ulong(time),
+ QWindowSystemInterface::handleTabletEvent(window, ulong(time),
localPos, globalPosF, int(QInputDevice::DeviceType::Stylus), pointerType,
buttons, pressure, 0, 0, 0., 0., 0, deviceId, Qt::NoModifier);
#endif // QT_CONFIG(tabletevent)
@@ -797,9 +932,7 @@ namespace QtAndroidInput
QMetaObject::invokeMethod(inputContext, "hideSelectionHandles", Qt::QueuedConnection);
}
}
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ KEYBOARDVISIBILITYCHANGED" << inputContext;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ KEYBOARDVISIBILITYCHANGED" << inputContext;
}
static void keyboardGeometryChanged(JNIEnv */*env*/, jobject /*thiz*/, jint x, jint y, jint w, jint h)
@@ -812,16 +945,12 @@ namespace QtAndroidInput
if (inputContext && qGuiApp)
inputContext->emitKeyboardRectChanged();
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ KEYBOARDRECTCHANGED" << m_softwareKeyboardRect;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ KEYBOARDRECTCHANGED" << m_softwareKeyboardRect;
}
static void handleLocationChanged(JNIEnv */*env*/, jobject /*thiz*/, int id, int x, int y)
{
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ handleLocationChanged" << id << x << y;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ handleLocationChanged" << id << x << y;
QAndroidInputContext *inputContext = QAndroidInputContext::androidInputContext();
if (inputContext && qGuiApp)
QMetaObject::invokeMethod(inputContext, "handleLocationChanged", Qt::BlockingQueuedConnection,
@@ -829,13 +958,14 @@ namespace QtAndroidInput
}
- static JNINativeMethod methods[] = {
+
+ static const JNINativeMethod methods[] = {
{"touchBegin","(I)V",(void*)touchBegin},
{"touchAdd","(IIIZIIFFFF)V",(void*)touchAdd},
{"touchEnd","(II)V",(void*)touchEnd},
{"touchCancel", "(I)V", (void *)touchCancel},
- {"mouseDown", "(III)V", (void *)mouseDown},
- {"mouseUp", "(III)V", (void *)mouseUp},
+ {"mouseDown", "(IIII)V", (void *)mouseDown},
+ {"mouseUp", "(IIII)V", (void *)mouseUp},
{"mouseMove", "(III)V", (void *)mouseMove},
{"mouseWheel", "(IIIFF)V", (void *)mouseWheel},
{"longPress", "(III)V", (void *)longPress},
@@ -845,14 +975,15 @@ namespace QtAndroidInput
{"keyUp", "(IIIZ)V", (void *)keyUp},
{"keyboardVisibilityChanged", "(Z)V", (void *)keyboardVisibilityChanged},
{"keyboardGeometryChanged", "(IIII)V", (void *)keyboardGeometryChanged},
- {"handleLocationChanged", "(III)V", (void *)handleLocationChanged}
+ {"handleLocationChanged", "(III)V", (void *)handleLocationChanged},
+ {"dispatchGenericMotionEvent", "(Landroid/view/MotionEvent;)Z", reinterpret_cast<void *>(dispatchGenericMotionEvent)},
+ {"dispatchKeyEvent", "(Landroid/view/KeyEvent;)Z", reinterpret_cast<void *>(dispatchKeyEvent)},
};
- bool registerNatives(JNIEnv *env)
+ bool registerNatives(QJniEnvironment &env)
{
- jclass appClass = QtAndroid::applicationClass();
-
- if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ if (!env.registerNativeMethods(QtJniTypes::Traits<QtJniTypes::QtInputDelegate>::className(),
+ methods, sizeof(methods) / sizeof(methods[0]))) {
__android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
return false;
}
diff --git a/src/plugins/platforms/android/androidjniinput.h b/src/plugins/platforms/android/androidjniinput.h
index 7ef51ef9f7..28a2665bf6 100644
--- a/src/plugins/platforms/android/androidjniinput.h
+++ b/src/plugins/platforms/android/androidjniinput.h
@@ -6,10 +6,15 @@
#include <jni.h>
#include <QtCore/qglobal.h>
+#include <QtCore/QLoggingCategory>
#include <QtCore/QRect>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaInputMethods);
+
+class QJniEnvironment;
+
namespace QtAndroidInput
{
// Software keyboard support
@@ -26,7 +31,27 @@ namespace QtAndroidInput
QPoint cursor = QPoint(), QPoint anchor = QPoint(), bool rtl = false);
int getSelectHandleWidth();
- bool registerNatives(JNIEnv *env);
+ class GenericMotionEventListener
+ {
+ public:
+ virtual ~GenericMotionEventListener();
+ virtual bool handleGenericMotionEvent(jobject event) = 0;
+ };
+
+ class KeyEventListener
+ {
+ public:
+ virtual ~KeyEventListener();
+ virtual bool handleKeyEvent(jobject event) = 0;
+ };
+
+ void registerGenericMotionEventListener(GenericMotionEventListener *listener);
+ void unregisterGenericMotionEventListener(GenericMotionEventListener *listener);
+
+ void registerKeyEventListener(KeyEventListener *listener);
+ void unregisterKeyEventListener(KeyEventListener *listener);
+
+ bool registerNatives(QJniEnvironment &env);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp
index 5e4f383e61..9fdcf3936b 100644
--- a/src/plugins/platforms/android/androidjnimain.cpp
+++ b/src/plugins/platforms/android/androidjnimain.cpp
@@ -10,14 +10,16 @@
#include "androidcontentfileengine.h"
#include "androiddeadlockprotector.h"
#include "androidjniaccessibility.h"
-#include "androidjniclipboard.h"
#include "androidjniinput.h"
#include "androidjnimain.h"
#include "androidjnimenu.h"
+#include "androidwindowembedding.h"
#include "qandroidassetsfileenginehandler.h"
#include "qandroideventdispatcher.h"
#include "qandroidplatformdialoghelpers.h"
#include "qandroidplatformintegration.h"
+#include "qandroidplatformclipboard.h"
+#include "qandroidplatformwindow.h"
#include <android/api-level.h>
#include <android/asset_manager_jni.h>
@@ -29,12 +31,16 @@
#include <QtCore/qjniobject.h>
#include <QtCore/qprocess.h>
#include <QtCore/qresource.h>
+#include <QtCore/qscopeguard.h>
#include <QtCore/qthread.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qhighdpiscaling_p.h>
#include <qpa/qwindowsysteminterface.h>
+
+using namespace Qt::StringLiterals;
+
QT_BEGIN_NAMESPACE
static JavaVM *m_javaVM = nullptr;
@@ -44,11 +50,12 @@ static jmethodID m_loadClassMethodID = nullptr;
static AAssetManager *m_assetManager = nullptr;
static jobject m_assets = nullptr;
static jobject m_resourcesObj = nullptr;
-static QtJniTypes::Activity m_activityObject = nullptr;
-static jmethodID m_createSurfaceMethodID = nullptr;
-static QtJniTypes::Service m_serviceObject = nullptr;
-static jmethodID m_setSurfaceGeometryMethodID = nullptr;
-static jmethodID m_destroySurfaceMethodID = nullptr;
+
+static jclass m_qtActivityClass = nullptr;
+static jclass m_qtServiceClass = nullptr;
+
+static QtJniTypes::QtActivityDelegateBase m_activityDelegate = nullptr;
+static QtJniTypes::QtInputDelegate m_inputDelegate = nullptr;
static int m_pendingApplicationState = -1;
static QBasicMutex m_platformMutex;
@@ -67,10 +74,6 @@ static void *m_mainLibraryHnd = nullptr;
static QList<QByteArray> m_applicationParams;
static sem_t m_exitSemaphore, m_terminateSemaphore;
-QHash<int, AndroidSurfaceClient *> m_surfaces;
-
-Q_CONSTINIT static QBasicMutex m_surfacesMutex;
-
static QAndroidPlatformIntegration *m_androidPlatformIntegration = nullptr;
@@ -90,6 +93,8 @@ static const char m_methodErrorMsg[] = "Can't find method \"%s%s\"";
Q_CONSTINIT static QBasicAtomicInt startQtAndroidPluginCalled = Q_BASIC_ATOMIC_INITIALIZER(0);
+Q_DECLARE_JNI_CLASS(QtEmbeddedDelegateFactory, "org/qtproject/qt/android/QtEmbeddedDelegateFactory")
+
namespace QtAndroid
{
QBasicMutex *platformInterfaceMutex()
@@ -100,6 +105,7 @@ namespace QtAndroid
void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration)
{
m_androidPlatformIntegration = androidPlatformIntegration;
+ QtAndroid::notifyNativePluginIntegrationReady((bool)m_androidPlatformIntegration);
// flush the pending state if necessary.
if (m_androidPlatformIntegration && (m_pendingApplicationState != -1)) {
@@ -125,6 +131,21 @@ namespace QtAndroid
: 0;
}
+ QWindow *windowFromId(int windowId)
+ {
+ if (!qGuiApp)
+ return nullptr;
+
+ for (QWindow *w : qGuiApp->allWindows()) {
+ if (!w->handle())
+ continue;
+ QAndroidPlatformWindow *window = static_cast<QAndroidPlatformWindow *>(w->handle());
+ if (window->nativeViewId() == windowId)
+ return w;
+ }
+ return nullptr;
+ }
+
int availableWidthPixels()
{
return m_availableWidthPixels;
@@ -160,53 +181,96 @@ namespace QtAndroid
return m_applicationClass;
}
- QtJniTypes::Activity activity()
+ // TODO move calls from here to where they logically belong
+ void setSystemUiVisibility(SystemUiVisibility uiVisibility)
{
- return m_activityObject;
+ qtActivityDelegate().callMethod<void>("setSystemUiVisibility", jint(uiVisibility));
}
- QtJniTypes::Service service()
+ // FIXME: avoid direct access to QtActivityDelegate
+ QtJniTypes::QtActivityDelegateBase qtActivityDelegate()
{
- return m_serviceObject;
+ using namespace QtJniTypes;
+ if (!m_activityDelegate.isValid()) {
+ if (isQtApplication()) {
+ auto context = QtAndroidPrivate::activity();
+ m_activityDelegate = context.callMethod<QtActivityDelegateBase>("getActivityDelegate");
+ } else {
+ m_activityDelegate = QJniObject::callStaticMethod<QtActivityDelegateBase>(
+ Traits<QtEmbeddedDelegateFactory>::className(),
+ "getActivityDelegate",
+ QtAndroidPrivate::activity());
+ }
+ }
+
+ return m_activityDelegate;
}
- void setSystemUiVisibility(SystemUiVisibility uiVisibility)
+ QtJniTypes::QtInputDelegate qtInputDelegate()
{
- QJniObject::callStaticMethod<void>(m_applicationClass, "setSystemUiVisibility", "(I)V", jint(uiVisibility));
+ if (!m_inputDelegate.isValid()) {
+ m_inputDelegate = qtActivityDelegate().callMethod<QtJniTypes::QtInputDelegate>(
+ "getInputDelegate");
+ }
+
+ return m_inputDelegate;
+ }
+
+ bool isQtApplication()
+ {
+ // Returns true if the app is a Qt app, i.e. Qt controls the whole app and
+ // the Activity/Service is created by Qt. Returns false if instead Qt is
+ // embedded into a native Android app, where the Activity/Service is created
+ // by the user, outside of Qt, and Qt content is added as a view.
+ JNIEnv *env = QJniEnvironment::getJniEnv();
+ auto activity = QtAndroidPrivate::activity();
+ if (activity.isValid())
+ return env->IsInstanceOf(activity.object(), m_qtActivityClass);
+ auto service = QtAndroidPrivate::service();
+ if (service.isValid())
+ return env->IsInstanceOf(QtAndroidPrivate::service().object(), m_qtServiceClass);
+ // return true as default as Qt application is our default use case.
+ // famous last words: we should not end up here
+ return true;
}
void notifyAccessibilityLocationChange(uint accessibilityObjectId)
{
- QJniObject::callStaticMethod<void>(m_applicationClass, "notifyAccessibilityLocationChange",
- "(I)V", accessibilityObjectId);
+ qtActivityDelegate().callMethod<void>("notifyLocationChange", accessibilityObjectId);
}
void notifyObjectHide(uint accessibilityObjectId, uint parentObjectId)
{
- QJniObject::callStaticMethod<void>(m_applicationClass, "notifyObjectHide", "(II)V",
- accessibilityObjectId, parentObjectId);
+ qtActivityDelegate().callMethod<void>("notifyObjectHide",
+ accessibilityObjectId, parentObjectId);
+ }
+
+ void notifyObjectShow(uint parentObjectId)
+ {
+ qtActivityDelegate().callMethod<void>("notifyObjectShow",
+ parentObjectId);
}
void notifyObjectFocus(uint accessibilityObjectId)
{
- QJniObject::callStaticMethod<void>(m_applicationClass, "notifyObjectFocus","(I)V", accessibilityObjectId);
+ qtActivityDelegate().callMethod<void>("notifyObjectFocus", accessibilityObjectId);
}
void notifyValueChanged(uint accessibilityObjectId, jstring value)
{
- QJniObject::callStaticMethod<void>(m_applicationClass, "notifyValueChanged",
- "(ILjava/lang/String;)V", accessibilityObjectId, value);
+ qtActivityDelegate().callMethod<void>("notifyValueChanged", accessibilityObjectId, value);
}
void notifyScrolledEvent(uint accessibilityObjectId)
{
- QJniObject::callStaticMethod<void>(m_applicationClass, "notifyScrolledEvent", "(I)V",
- accessibilityObjectId);
+ qtActivityDelegate().callMethod<void>("notifyScrolledEvent", accessibilityObjectId);
}
- void notifyQtAndroidPluginRunning(bool running)
+ void notifyNativePluginIntegrationReady(bool ready)
{
- QJniObject::callStaticMethod<void>(m_applicationClass, "notifyQtAndroidPluginRunning","(Z)V", running);
+ QJniObject::callStaticMethod<void>(m_applicationClass,
+ "notifyNativePluginIntegrationReady",
+ ready);
}
jobject createBitmap(QImage img, JNIEnv *env)
@@ -215,7 +279,7 @@ namespace QtAndroid
return 0;
if (img.format() != QImage::Format_RGBA8888 && img.format() != QImage::Format_RGB16)
- img = img.convertToFormat(QImage::Format_RGBA8888);
+ img = std::move(img).convertToFormat(QImage::Format_RGBA8888);
jobject bitmap = env->CallStaticObjectMethod(m_bitmapClass,
m_createBitmapMethodID,
@@ -303,62 +367,6 @@ namespace QtAndroid
return manufacturer + u' ' + model;
}
- jint generateViewId()
- {
- return QJniObject::callStaticMethod<jint>("android/view/View", "generateViewId", "()I");
- }
-
- int createSurface(AndroidSurfaceClient *client, const QRect &geometry, bool onTop, int imageDepth)
- {
- QJniEnvironment env;
- if (!env.jniEnv())
- return -1;
-
- m_surfacesMutex.lock();
- jint surfaceId = generateViewId();
- m_surfaces[surfaceId] = client;
- m_surfacesMutex.unlock();
-
- jint x = 0, y = 0, w = -1, h = -1;
- if (!geometry.isNull()) {
- x = geometry.x();
- y = geometry.y();
- w = std::max(geometry.width(), 1);
- h = std::max(geometry.height(), 1);
- }
- env->CallStaticVoidMethod(m_applicationClass,
- m_createSurfaceMethodID,
- surfaceId,
- jboolean(onTop),
- x, y, w, h,
- imageDepth);
- return surfaceId;
- }
-
- int insertNativeView(jobject view, const QRect &geometry)
- {
- m_surfacesMutex.lock();
- jint surfaceId = generateViewId();
- m_surfaces[surfaceId] = nullptr; // dummy
- m_surfacesMutex.unlock();
-
- jint x = 0, y = 0, w = -1, h = -1;
- if (!geometry.isNull())
- geometry.getRect(&x, &y, &w, &h);
-
- QJniObject::callStaticMethod<void>(m_applicationClass,
- "insertNativeView",
- "(ILandroid/view/View;IIII)V",
- surfaceId,
- view,
- x,
- y,
- qMax(w, 1),
- qMax(h, 1));
-
- return surfaceId;
- }
-
void setViewVisibility(jobject view, bool visible)
{
QJniObject::callStaticMethod<void>(m_applicationClass,
@@ -368,69 +376,6 @@ namespace QtAndroid
visible);
}
- void setSurfaceGeometry(int surfaceId, const QRect &geometry)
- {
- if (surfaceId == -1)
- return;
-
- QJniEnvironment env;
- if (!env.jniEnv())
- return;
- jint x = 0, y = 0, w = -1, h = -1;
- if (!geometry.isNull()) {
- x = geometry.x();
- y = geometry.y();
- w = geometry.width();
- h = geometry.height();
- }
- env->CallStaticVoidMethod(m_applicationClass,
- m_setSurfaceGeometryMethodID,
- surfaceId,
- x, y, w, h);
- }
-
-
- void destroySurface(int surfaceId)
- {
- if (surfaceId == -1)
- return;
-
- {
- QMutexLocker lock(&m_surfacesMutex);
- const auto &it = m_surfaces.find(surfaceId);
- if (it != m_surfaces.end())
- m_surfaces.erase(it);
- }
-
- QJniEnvironment env;
- if (env.jniEnv())
- env->CallStaticVoidMethod(m_applicationClass,
- m_destroySurfaceMethodID,
- surfaceId);
- }
-
- void bringChildToFront(int surfaceId)
- {
- if (surfaceId == -1)
- return;
-
- QJniObject::callStaticMethod<void>(m_applicationClass,
- "bringChildToFront",
- "(I)V",
- surfaceId);
- }
-
- void bringChildToBack(int surfaceId)
- {
- if (surfaceId == -1)
- return;
-
- QJniObject::callStaticMethod<void>(m_applicationClass,
- "bringChildToBack",
- "(I)V",
- surfaceId);
- }
-
bool blockEventLoopsWhenSuspended()
{
static bool block = qEnvironmentVariableIntValue("QT_BLOCK_EVENT_LOOPS_WHEN_SUSPENDED");
@@ -446,14 +391,14 @@ namespace QtAndroid
static jboolean startQtAndroidPlugin(JNIEnv *env, jobject /*object*/, jstring paramsString)
{
+ Q_UNUSED(env)
+
m_androidPlatformIntegration = nullptr;
m_androidAssetsFileEngineHandler = new AndroidAssetsFileEngineHandler();
m_androidContentFileEngineHandler = new AndroidContentFileEngineHandler();
m_mainLibraryHnd = nullptr;
- const char *nativeString = env->GetStringUTFChars(paramsString, 0);
- const QStringList argsList = QProcess::splitCommand(QString::fromUtf8(nativeString));
- env->ReleaseStringUTFChars(paramsString, nativeString);
+ const QStringList argsList = QProcess::splitCommand(QJniObject(paramsString).toString());
for (const QString &arg : argsList)
m_applicationParams.append(arg.toUtf8());
@@ -496,7 +441,7 @@ static void waitForServiceSetup(JNIEnv *env, jclass /*clazz*/)
Q_UNUSED(env);
// The service must wait until the QCoreApplication starts otherwise onBind will be
// called too early
- if (m_serviceObject)
+ if (QtAndroidPrivate::service().isValid() && QtAndroid::isQtApplication())
QtAndroidPrivate::waitForServiceSetup();
}
@@ -527,7 +472,8 @@ static void startQtApplication(JNIEnv */*env*/, jclass /*clazz*/)
argv[argc] = nullptr;
startQtAndroidPluginCalled.fetchAndAddRelease(1);
- int ret = m_main(argc, argv.data());
+ const int ret = m_main(argc, argv.data());
+ qInfo() << "main() returned" << ret;
if (m_mainLibraryHnd) {
int res = dlclose(m_mainLibraryHnd);
@@ -535,10 +481,8 @@ static void startQtApplication(JNIEnv */*env*/, jclass /*clazz*/)
qWarning() << "dlclose failed:" << dlerror();
}
- if (m_applicationClass) {
- qWarning("exit app 0");
+ if (m_applicationClass)
QJniObject::callStaticMethod<void>(m_applicationClass, "quitApp", "()V");
- }
sem_post(&m_terminateSemaphore);
sem_wait(&m_exitSemaphore);
@@ -583,10 +527,6 @@ static void terminateQt(JNIEnv *env, jclass /*clazz*/)
env->DeleteGlobalRef(m_classLoaderObject);
if (m_resourcesObj)
env->DeleteGlobalRef(m_resourcesObj);
- if (m_activityObject)
- env->DeleteGlobalRef(m_activityObject);
- if (m_serviceObject)
- env->DeleteGlobalRef(m_serviceObject);
if (m_bitmapClass)
env->DeleteGlobalRef(m_bitmapClass);
if (m_ARGB_8888_BitmapConfigValue)
@@ -597,24 +537,16 @@ static void terminateQt(JNIEnv *env, jclass /*clazz*/)
env->DeleteGlobalRef(m_bitmapDrawableClass);
if (m_assets)
env->DeleteGlobalRef(m_assets);
+ if (m_qtActivityClass)
+ env->DeleteGlobalRef(m_qtActivityClass);
+ if (m_qtServiceClass)
+ env->DeleteGlobalRef(m_qtServiceClass);
m_androidPlatformIntegration = nullptr;
delete m_androidAssetsFileEngineHandler;
m_androidAssetsFileEngineHandler = nullptr;
sem_post(&m_exitSemaphore);
}
-static void setSurface(JNIEnv *env, jobject /*thiz*/, jint id, jobject jSurface, jint w, jint h)
-{
- QMutexLocker lock(&m_surfacesMutex);
- const auto &it = m_surfaces.find(id);
- if (it == m_surfaces.end())
- return;
-
- auto surfaceClient = it.value();
- if (surfaceClient)
- surfaceClient->surfaceChanged(env, jSurface, w, h);
-}
-
static void setDisplayMetrics(JNIEnv * /*env*/, jclass /*clazz*/, jint screenWidthPixels,
jint screenHeightPixels, jint availableLeftPixels,
jint availableTopPixels, jint availableWidthPixels,
@@ -647,6 +579,7 @@ static void setDisplayMetrics(JNIEnv * /*env*/, jclass /*clazz*/, jint screenWid
m_androidPlatformIntegration->setRefreshRate(refreshRate);
}
}
+Q_DECLARE_JNI_NATIVE_METHOD(setDisplayMetrics)
static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/)
{
@@ -666,10 +599,6 @@ static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/)
QWindowSystemInterface::handleExposeEvent(w, QRegion(QRect(QPoint(), w->geometry().size())));
}
}
-
- QAndroidPlatformScreen *screen = static_cast<QAndroidPlatformScreen *>(m_androidPlatformIntegration->screen());
- if (screen->rasterSurfaces())
- QMetaObject::invokeMethod(screen, "setDirty", Qt::QueuedConnection, Q_ARG(QRect,screen->geometry()));
}
static void updateApplicationState(JNIEnv */*env*/, jobject /*thiz*/, jint state)
@@ -748,36 +677,42 @@ static void handleOrientationChanged(JNIEnv */*env*/, jobject /*thiz*/, jint new
}
}
}
+Q_DECLARE_JNI_NATIVE_METHOD(handleOrientationChanged)
static void handleRefreshRateChanged(JNIEnv */*env*/, jclass /*cls*/, jfloat refreshRate)
{
if (m_androidPlatformIntegration)
m_androidPlatformIntegration->setRefreshRate(refreshRate);
}
+Q_DECLARE_JNI_NATIVE_METHOD(handleRefreshRateChanged)
static void handleScreenAdded(JNIEnv */*env*/, jclass /*cls*/, jint displayId)
{
if (m_androidPlatformIntegration)
m_androidPlatformIntegration->handleScreenAdded(displayId);
}
+Q_DECLARE_JNI_NATIVE_METHOD(handleScreenAdded)
static void handleScreenChanged(JNIEnv */*env*/, jclass /*cls*/, jint displayId)
{
if (m_androidPlatformIntegration)
m_androidPlatformIntegration->handleScreenChanged(displayId);
}
+Q_DECLARE_JNI_NATIVE_METHOD(handleScreenChanged)
static void handleScreenRemoved(JNIEnv */*env*/, jclass /*cls*/, jint displayId)
{
if (m_androidPlatformIntegration)
m_androidPlatformIntegration->handleScreenRemoved(displayId);
}
+Q_DECLARE_JNI_NATIVE_METHOD(handleScreenRemoved)
static void handleUiDarkModeChanged(JNIEnv */*env*/, jobject /*thiz*/, jint newUiMode)
{
- QAndroidPlatformIntegration::setColorScheme(
+ QAndroidPlatformIntegration::updateColorScheme(
(newUiMode == 1 ) ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light);
}
+Q_DECLARE_JNI_NATIVE_METHOD(handleUiDarkModeChanged)
static void onActivityResult(JNIEnv */*env*/, jclass /*cls*/,
jint requestCode,
@@ -804,116 +739,131 @@ static JNINativeMethod methods[] = {
{ "quitQtCoreApplication", "()V", (void *)quitQtCoreApplication },
{ "terminateQt", "()V", (void *)terminateQt },
{ "waitForServiceSetup", "()V", (void *)waitForServiceSetup },
- { "setDisplayMetrics", "(IIIIIIDDDDF)V", (void *)setDisplayMetrics },
- { "setSurface", "(ILjava/lang/Object;II)V", (void *)setSurface },
{ "updateWindow", "()V", (void *)updateWindow },
{ "updateApplicationState", "(I)V", (void *)updateApplicationState },
- { "handleUiDarkModeChanged", "(I)V", (void *)handleUiDarkModeChanged },
- { "handleOrientationChanged", "(II)V", (void *)handleOrientationChanged },
{ "onActivityResult", "(IILandroid/content/Intent;)V", (void *)onActivityResult },
{ "onNewIntent", "(Landroid/content/Intent;)V", (void *)onNewIntent },
- { "onBind", "(Landroid/content/Intent;)Landroid/os/IBinder;", (void *)onBind },
- { "handleRefreshRateChanged", "(F)V", (void *)handleRefreshRateChanged },
- { "handleScreenAdded", "(I)V", (void *)handleScreenAdded },
- { "handleScreenChanged", "(I)V", (void *)handleScreenChanged },
- { "handleScreenRemoved", "(I)V", (void *)handleScreenRemoved }
+ { "onBind", "(Landroid/content/Intent;)Landroid/os/IBinder;", (void *)onBind }
};
#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
clazz = env->FindClass(CLASS_NAME); \
if (!clazz) { \
__android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_classErrorMsg, CLASS_NAME); \
- return JNI_FALSE; \
+ return false; \
}
#define GET_AND_CHECK_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
VAR = env->GetMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
if (!VAR) { \
__android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); \
- return JNI_FALSE; \
+ return false; \
}
#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
if (!VAR) { \
__android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); \
- return JNI_FALSE; \
+ return false; \
}
#define GET_AND_CHECK_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \
VAR = env->GetFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \
if (!VAR) { \
__android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, FIELD_NAME, FIELD_SIGNATURE); \
- return JNI_FALSE; \
+ return false; \
}
#define GET_AND_CHECK_STATIC_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \
VAR = env->GetStaticFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \
if (!VAR) { \
__android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, FIELD_NAME, FIELD_SIGNATURE); \
- return JNI_FALSE; \
+ return false; \
}
-static int registerNatives(JNIEnv *env)
+Q_DECLARE_JNI_CLASS(QtDisplayManager, "org/qtproject/qt/android/QtDisplayManager")
+
+static bool registerNatives(QJniEnvironment &env)
{
jclass clazz;
FIND_AND_CHECK_CLASS("org/qtproject/qt/android/QtNative");
m_applicationClass = static_cast<jclass>(env->NewGlobalRef(clazz));
- if (env->RegisterNatives(m_applicationClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ if (!env.registerNativeMethods(m_applicationClass,
+ methods, sizeof(methods) / sizeof(methods[0]))) {
__android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
- return JNI_FALSE;
+ return false;
}
- GET_AND_CHECK_STATIC_METHOD(m_createSurfaceMethodID, m_applicationClass, "createSurface", "(IZIIIII)V");
- GET_AND_CHECK_STATIC_METHOD(m_setSurfaceGeometryMethodID, m_applicationClass, "setSurfaceGeometry", "(IIIII)V");
- GET_AND_CHECK_STATIC_METHOD(m_destroySurfaceMethodID, m_applicationClass, "destroySurface", "(I)V");
+ bool success = env.registerNativeMethods(
+ QtJniTypes::Traits<QtJniTypes::QtDisplayManager>::className(),
+ {
+ Q_JNI_NATIVE_METHOD(setDisplayMetrics),
+ Q_JNI_NATIVE_METHOD(handleOrientationChanged),
+ Q_JNI_NATIVE_METHOD(handleRefreshRateChanged),
+ Q_JNI_NATIVE_METHOD(handleScreenAdded),
+ Q_JNI_NATIVE_METHOD(handleScreenChanged),
+ Q_JNI_NATIVE_METHOD(handleScreenRemoved),
+ Q_JNI_NATIVE_METHOD(handleUiDarkModeChanged)
+ });
+
+ if (!success) {
+ qCritical() << "QtDisplayManager: registerNativeMethods() failed";
+ return JNI_FALSE;
+ }
jmethodID methodID;
GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "activity", "()Landroid/app/Activity;");
- jobject activityObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
- GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "service", "()Landroid/app/Service;");
- jobject serviceObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
+ jobject contextObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
+ if (!contextObject) {
+ GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "service", "()Landroid/app/Service;");
+ contextObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
+ }
+
+ if (!contextObject) {
+ __android_log_print(ANDROID_LOG_FATAL,"Qt", "Failed to get Activity or Service object");
+ return false;
+ }
+ const auto releaseContextObject = qScopeGuard([&env, contextObject]{
+ env->DeleteLocalRef(contextObject);
+ });
+
GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "classLoader", "()Ljava/lang/ClassLoader;");
m_classLoaderObject = env->NewGlobalRef(env->CallStaticObjectMethod(m_applicationClass, methodID));
clazz = env->GetObjectClass(m_classLoaderObject);
GET_AND_CHECK_METHOD(m_loadClassMethodID, clazz, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
- if (serviceObject)
- m_serviceObject = env->NewGlobalRef(serviceObject);
-
- if (activityObject)
- m_activityObject = env->NewGlobalRef(activityObject);
-
- jobject object = activityObject ? activityObject : serviceObject;
- if (object) {
- FIND_AND_CHECK_CLASS("android/content/ContextWrapper");
- GET_AND_CHECK_METHOD(methodID, clazz, "getAssets", "()Landroid/content/res/AssetManager;");
- m_assets = env->NewGlobalRef(env->CallObjectMethod(object, methodID));
- m_assetManager = AAssetManager_fromJava(env, m_assets);
-
- GET_AND_CHECK_METHOD(methodID, clazz, "getResources", "()Landroid/content/res/Resources;");
- m_resourcesObj = env->NewGlobalRef(env->CallObjectMethod(object, methodID));
-
- FIND_AND_CHECK_CLASS("android/graphics/Bitmap");
- m_bitmapClass = static_cast<jclass>(env->NewGlobalRef(clazz));
- GET_AND_CHECK_STATIC_METHOD(m_createBitmapMethodID, m_bitmapClass
- , "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
- FIND_AND_CHECK_CLASS("android/graphics/Bitmap$Config");
- jfieldID fieldId;
- GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "ARGB_8888", "Landroid/graphics/Bitmap$Config;");
- m_ARGB_8888_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId));
- GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "RGB_565", "Landroid/graphics/Bitmap$Config;");
- m_RGB_565_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId));
-
- FIND_AND_CHECK_CLASS("android/graphics/drawable/BitmapDrawable");
- m_bitmapDrawableClass = static_cast<jclass>(env->NewGlobalRef(clazz));
- GET_AND_CHECK_METHOD(m_bitmapDrawableConstructorMethodID,
- m_bitmapDrawableClass,
- "<init>",
- "(Landroid/content/res/Resources;Landroid/graphics/Bitmap;)V");
- }
-
- return JNI_TRUE;
+
+ FIND_AND_CHECK_CLASS("android/content/ContextWrapper");
+ GET_AND_CHECK_METHOD(methodID, clazz, "getAssets", "()Landroid/content/res/AssetManager;");
+ m_assets = env->NewGlobalRef(env->CallObjectMethod(contextObject, methodID));
+ m_assetManager = AAssetManager_fromJava(env.jniEnv(), m_assets);
+
+ GET_AND_CHECK_METHOD(methodID, clazz, "getResources", "()Landroid/content/res/Resources;");
+ m_resourcesObj = env->NewGlobalRef(env->CallObjectMethod(contextObject, methodID));
+
+ FIND_AND_CHECK_CLASS("android/graphics/Bitmap");
+ m_bitmapClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+ GET_AND_CHECK_STATIC_METHOD(m_createBitmapMethodID, m_bitmapClass,
+ "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
+ FIND_AND_CHECK_CLASS("android/graphics/Bitmap$Config");
+ jfieldID fieldId;
+ GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "ARGB_8888", "Landroid/graphics/Bitmap$Config;");
+ m_ARGB_8888_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId));
+ GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "RGB_565", "Landroid/graphics/Bitmap$Config;");
+ m_RGB_565_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId));
+
+ FIND_AND_CHECK_CLASS("android/graphics/drawable/BitmapDrawable");
+ m_bitmapDrawableClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+ GET_AND_CHECK_METHOD(m_bitmapDrawableConstructorMethodID,
+ m_bitmapDrawableClass,
+ "<init>", "(Landroid/content/res/Resources;Landroid/graphics/Bitmap;)V");
+
+ FIND_AND_CHECK_CLASS("org/qtproject/qt/android/QtActivityBase");
+ m_qtActivityClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+ FIND_AND_CHECK_CLASS("org/qtproject/qt/android/QtServiceBase");
+ m_qtServiceClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+
+ return true;
}
QT_END_NAMESPACE
@@ -926,36 +876,29 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/)
initialized = true;
QT_USE_NAMESPACE
- typedef union {
- JNIEnv *nativeEnvironment;
- void *venv;
- } UnionJNIEnvToVoid;
-
- UnionJNIEnvToVoid uenv;
- uenv.venv = nullptr;
- m_javaVM = nullptr;
-
- if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_6) != JNI_OK) {
- __android_log_print(ANDROID_LOG_FATAL, "Qt", "GetEnv failed");
+ m_javaVM = vm;
+ QJniEnvironment env;
+ if (!env.isValid()) {
+ m_javaVM = nullptr;
+ __android_log_print(ANDROID_LOG_FATAL, "Qt", "Failed to initialize the JNI Environment");
return -1;
}
- JNIEnv *env = uenv.nativeEnvironment;
if (!registerNatives(env)
|| !QtAndroidInput::registerNatives(env)
|| !QtAndroidMenu::registerNatives(env)
|| !QtAndroidAccessibility::registerNatives(env)
- || !QtAndroidDialogHelpers::registerNatives(env)) {
+ || !QtAndroidDialogHelpers::registerNatives(env)
+ || !QAndroidPlatformClipboard::registerNatives(env)
+ || !QAndroidPlatformWindow::registerNatives(env)
+ || !QtAndroidWindowEmbedding::registerNatives(env)) {
__android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed");
return -1;
}
QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
- m_javaVM = vm;
// attach qt main thread data to this thread
- QObject threadSetter;
- if (threadSetter.thread())
- threadSetter.thread()->setObjectName("QtMainLoopThread");
+ QThread::currentThread()->setObjectName("QtMainLoopThread");
__android_log_print(ANDROID_LOG_INFO, "Qt", "qt started");
return JNI_VERSION_1_6;
}
diff --git a/src/plugins/platforms/android/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h
index 4879d7e5b2..99fff96d2b 100644
--- a/src/plugins/platforms/android/androidjnimain.h
+++ b/src/plugins/platforms/android/androidjnimain.h
@@ -12,6 +12,7 @@
#include <QImage>
#include <private/qjnihelpers_p.h>
+#include <QtCore/QJniObject>
QT_BEGIN_NAMESPACE
@@ -22,26 +23,22 @@ class QAndroidPlatformIntegration;
class QWidget;
class QString;
class QWindow;
-class AndroidSurfaceClient;
+class QAndroidPlatformWindow;
class QBasicMutex;
+Q_DECLARE_JNI_CLASS(QtActivityDelegateBase, "org/qtproject/qt/android/QtActivityDelegateBase")
+Q_DECLARE_JNI_CLASS(QtInputDelegate, "org/qtproject/qt/android/QtInputDelegate")
+
namespace QtAndroid
{
QBasicMutex *platformInterfaceMutex();
QAndroidPlatformIntegration *androidPlatformIntegration();
void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration);
void setQtThread(QThread *thread);
-
-
- int createSurface(AndroidSurfaceClient * client, const QRect &geometry, bool onTop, int imageDepth);
- int insertNativeView(jobject view, const QRect &geometry);
void setViewVisibility(jobject view, bool visible);
- void setSurfaceGeometry(int surfaceId, const QRect &geometry);
- void destroySurface(int surfaceId);
- void bringChildToFront(int surfaceId);
- void bringChildToBack(int surfaceId);
QWindow *topLevelWindowAt(const QPoint &globalPos);
+ QWindow *windowFromId(int windowId);
int availableWidthPixels();
int availableHeightPixels();
double scaledDensity();
@@ -50,8 +47,9 @@ namespace QtAndroid
jobject assets();
AAssetManager *assetManager();
jclass applicationClass();
- QtJniTypes::Activity activity();
- QtJniTypes::Service service();
+
+ QtJniTypes::QtActivityDelegateBase qtActivityDelegate();
+ QtJniTypes::QtInputDelegate qtInputDelegate();
// Keep synchronized with flags in ActivityDelegate.java
enum SystemUiVisibility {
@@ -67,10 +65,11 @@ namespace QtAndroid
void notifyAccessibilityLocationChange(uint accessibilityObjectId);
void notifyObjectHide(uint accessibilityObjectId, uint parentObjectId);
+ void notifyObjectShow(uint parentObjectId);
void notifyObjectFocus(uint accessibilityObjectId);
void notifyValueChanged(uint accessibilityObjectId, jstring value);
void notifyScrolledEvent(uint accessibilityObjectId);
- void notifyQtAndroidPluginRunning(bool running);
+ void notifyNativePluginIntegrationReady(bool ready);
const char *classErrorMsgFmt();
const char *methodErrorMsgFmt();
@@ -78,6 +77,8 @@ namespace QtAndroid
QString deviceName();
bool blockEventLoopsWhenSuspended();
+
+ bool isQtApplication();
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/androidjnimenu.cpp b/src/plugins/platforms/android/androidjnimenu.cpp
index 7aaa5d921c..8bf37d1af2 100644
--- a/src/plugins/platforms/android/androidjnimenu.cpp
+++ b/src/plugins/platforms/android/androidjnimenu.cpp
@@ -31,8 +31,6 @@ namespace QtAndroidMenu
static QWindow *activeTopLevelWindow = nullptr;
Q_CONSTINIT static QRecursiveMutex menuBarMutex;
- static jmethodID openContextMenuMethodID = 0;
-
static jmethodID clearMenuMethodID = 0;
static jmethodID addMenuItemMethodID = 0;
static int menuNoneValue = 0;
@@ -46,29 +44,31 @@ namespace QtAndroidMenu
void resetMenuBar()
{
- QJniObject::callStaticMethod<void>(applicationClass(), "resetOptionsMenu");
+ qtActivityDelegate().callMethod<void>("resetOptionsMenu");
}
void openOptionsMenu()
{
- QJniObject::callStaticMethod<void>(applicationClass(), "openOptionsMenu");
+ qtActivityDelegate().callMethod<void>("openOptionsMenu");
}
- void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect, JNIEnv *env)
+ void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect)
{
QMutexLocker lock(&visibleMenuMutex);
if (visibleMenu)
pendingContextMenus.append(visibleMenu);
visibleMenu = menu;
menu->aboutToShow();
- env->CallStaticVoidMethod(applicationClass(), openContextMenuMethodID, anchorRect.x(), anchorRect.y(), anchorRect.width(), anchorRect.height());
+ qtActivityDelegate().callMethod<void>("openContextMenu",
+ anchorRect.x(), anchorRect.y(),
+ anchorRect.width(), anchorRect.height());
}
void hideContextMenu(QAndroidPlatformMenu *menu)
{
QMutexLocker lock(&visibleMenuMutex);
if (visibleMenu == menu) {
- QJniObject::callStaticMethod<void>(applicationClass(), "closeContextMenu");
+ qtActivityDelegate().callMethod<void>("closeContextMenu");
pendingContextMenus.clear();
} else {
pendingContextMenus.removeOne(menu);
@@ -211,8 +211,10 @@ namespace QtAndroidMenu
return order;
}
- static jboolean onPrepareOptionsMenu(JNIEnv *env, jobject /*thiz*/, jobject menu)
+ static jboolean onPrepareOptionsMenu(JNIEnv *env, jobject thiz, jobject menu)
{
+ Q_UNUSED(thiz)
+
env->CallVoidMethod(menu, clearMenuMethodID);
QMutexLocker lock(&menuBarMutex);
if (!visibleMenuBar)
@@ -249,8 +251,11 @@ namespace QtAndroidMenu
return order ? JNI_TRUE : JNI_FALSE;
}
- static jboolean onOptionsItemSelected(JNIEnv *env, jobject /*thiz*/, jint menuId, jboolean checked)
+ static jboolean onOptionsItemSelected(JNIEnv *env, jobject thiz, jint menuId, jboolean checked)
{
+ Q_UNUSED(env)
+ Q_UNUSED(thiz)
+
QMutexLocker lock(&menuBarMutex);
if (!visibleMenuBar)
return JNI_FALSE;
@@ -260,7 +265,7 @@ namespace QtAndroidMenu
QAndroidPlatformMenuItem *item = static_cast<QAndroidPlatformMenuItem *>(menus.front()->menuItemForId(menuId));
if (item) {
if (item->menu()) {
- showContextMenu(item->menu(), QRect(), env);
+ showContextMenu(item->menu(), QRect());
} else {
if (item->isCheckable())
item->setChecked(checked);
@@ -270,18 +275,23 @@ namespace QtAndroidMenu
} else {
QAndroidPlatformMenu *menu = static_cast<QAndroidPlatformMenu *>(visibleMenuBar->menuForId(menuId));
if (menu)
- showContextMenu(menu, QRect(), env);
+ showContextMenu(menu, QRect());
}
return JNI_TRUE;
}
- static void onOptionsMenuClosed(JNIEnv */*env*/, jobject /*thiz*/, jobject /*menu*/)
+ static void onOptionsMenuClosed(JNIEnv *env, jobject thiz, jobject menu)
{
+ Q_UNUSED(env)
+ Q_UNUSED(thiz)
+ Q_UNUSED(menu)
}
- static void onCreateContextMenu(JNIEnv *env, jobject /*thiz*/, jobject menu)
+ static void onCreateContextMenu(JNIEnv *env, jobject thiz, jobject menu)
{
+ Q_UNUSED(thiz)
+
env->CallVoidMethod(menu, clearMenuMethodID);
QMutexLocker lock(&visibleMenuMutex);
if (!visibleMenu)
@@ -295,8 +305,9 @@ namespace QtAndroidMenu
addAllMenuItemsToMenu(env, menu, visibleMenu);
}
- static void fillContextMenu(JNIEnv *env, jobject /*thiz*/, jobject menu)
+ static void fillContextMenu(JNIEnv *env, jobject thiz, jobject menu)
{
+ Q_UNUSED(thiz)
env->CallVoidMethod(menu, clearMenuMethodID);
QMutexLocker lock(&visibleMenuMutex);
if (!visibleMenu)
@@ -305,13 +316,16 @@ namespace QtAndroidMenu
addAllMenuItemsToMenu(env, menu, visibleMenu);
}
- static jboolean onContextItemSelected(JNIEnv *env, jobject /*thiz*/, jint menuId, jboolean checked)
+ static jboolean onContextItemSelected(JNIEnv *env, jobject thiz, jint menuId, jboolean checked)
{
+ Q_UNUSED(env)
+ Q_UNUSED(thiz)
+
QMutexLocker lock(&visibleMenuMutex);
QAndroidPlatformMenuItem * item = static_cast<QAndroidPlatformMenuItem *>(visibleMenu->menuItemForId(menuId));
if (item) {
if (item->menu()) {
- showContextMenu(item->menu(), QRect(), env);
+ showContextMenu(item->menu(), QRect());
} else {
if (item->isCheckable())
item->setChecked(checked);
@@ -328,8 +342,12 @@ namespace QtAndroidMenu
return JNI_TRUE;
}
- static void onContextMenuClosed(JNIEnv *env, jobject /*thiz*/, jobject /*menu*/)
+ static void onContextMenuClosed(JNIEnv *env, jobject thiz, jobject menu)
{
+ Q_UNUSED(env)
+ Q_UNUSED(thiz)
+ Q_UNUSED(menu)
+
QMutexLocker lock(&visibleMenuMutex);
if (!visibleMenu)
return;
@@ -337,7 +355,7 @@ namespace QtAndroidMenu
visibleMenu->aboutToHide();
visibleMenu = 0;
if (!pendingContextMenus.empty())
- showContextMenu(pendingContextMenus.takeLast(), QRect(), env);
+ showContextMenu(pendingContextMenus.takeLast(), QRect());
}
static JNINativeMethod methods[] = {
@@ -378,17 +396,15 @@ namespace QtAndroidMenu
return false; \
}
- bool registerNatives(JNIEnv *env)
+ bool registerNatives(QJniEnvironment &env)
{
jclass appClass = applicationClass();
- if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ if (!env.registerNativeMethods(appClass, methods, sizeof(methods) / sizeof(methods[0]))) {
__android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
return false;
}
- GET_AND_CHECK_STATIC_METHOD(openContextMenuMethodID, appClass, "openContextMenu", "(IIII)V");
-
jclass clazz;
FIND_AND_CHECK_CLASS("android/view/Menu");
GET_AND_CHECK_METHOD(clearMenuMethodID, clazz, "clear", "()V");
diff --git a/src/plugins/platforms/android/androidjnimenu.h b/src/plugins/platforms/android/androidjnimenu.h
index 1645ce750b..e10ad930d9 100644
--- a/src/plugins/platforms/android/androidjnimenu.h
+++ b/src/plugins/platforms/android/androidjnimenu.h
@@ -15,12 +15,13 @@ class QAndroidPlatformMenuItem;
class QWindow;
class QRect;
class QPoint;
+class QJniEnvironment;
namespace QtAndroidMenu
{
// Menu support
void openOptionsMenu();
- void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect, JNIEnv *env);
+ void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect);
void hideContextMenu(QAndroidPlatformMenu *menu);
void syncMenu(QAndroidPlatformMenu *menu);
void androidPlatformMenuDestroyed(QAndroidPlatformMenu *menu);
@@ -31,7 +32,7 @@ namespace QtAndroidMenu
void removeMenuBar(QAndroidPlatformMenuBar *menuBar);
// Menu support
- bool registerNatives(JNIEnv *env);
+ bool registerNatives(QJniEnvironment &env);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/androidsurfaceclient.h b/src/plugins/platforms/android/androidsurfaceclient.h
deleted file mode 100644
index dded9a1f66..0000000000
--- a/src/plugins/platforms/android/androidsurfaceclient.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef ANDROIDSURFACECLIENT_H
-#define ANDROIDSURFACECLIENT_H
-#include <QMutex>
-#include <jni.h>
-
-QT_BEGIN_NAMESPACE
-
-class AndroidSurfaceClient
-{
-public:
- virtual void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h) = 0;
- void lockSurface() { m_surfaceMutex.lock(); }
- void unlockSurface() { m_surfaceMutex.unlock(); }
-
-protected:
- QMutex m_surfaceMutex;
-};
-
-QT_END_NAMESPACE
-
-#endif // ANDROIDSURFACECLIENT_H
diff --git a/src/plugins/platforms/android/androidwindowembedding.cpp b/src/plugins/platforms/android/androidwindowembedding.cpp
new file mode 100644
index 0000000000..65dabcac66
--- /dev/null
+++ b/src/plugins/platforms/android/androidwindowembedding.cpp
@@ -0,0 +1,70 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "androidwindowembedding.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjniobject.h>
+#include <QtCore/qjnitypes.h>
+#include <QtGui/qwindow.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_JNI_CLASS(QtView, "org/qtproject/qt/android/QtView");
+
+namespace QtAndroidWindowEmbedding {
+ void createRootWindow(JNIEnv *, jclass, QtJniTypes::View rootView,
+ jint x, jint y, jint width, jint height)
+ {
+ // QWindow should be constructed on the Qt thread rather than directly in the caller thread
+ // To avoid hitting checkReceiverThread assert in QCoreApplication::doNotify
+ QMetaObject::invokeMethod(qApp, [rootView, x, y, width, height] {
+ QWindow *parentWindow = QWindow::fromWinId(reinterpret_cast<WId>(rootView.object()));
+ parentWindow->setGeometry(x, y, width, height);
+ rootView.callMethod<void>("createWindow", reinterpret_cast<jlong>(parentWindow));
+ });
+ }
+
+ void deleteWindow(JNIEnv *, jclass, jlong windowRef)
+ {
+ QWindow *window = reinterpret_cast<QWindow*>(windowRef);
+ window->deleteLater();
+ }
+
+ void setWindowVisible(JNIEnv *, jclass, jlong windowRef, jboolean visible)
+ {
+ QMetaObject::invokeMethod(qApp, [windowRef, visible] {
+ QWindow *window = reinterpret_cast<QWindow*>(windowRef);
+ if (visible) {
+ window->showNormal();
+ if (!window->parent()->isVisible())
+ window->parent()->showNormal();
+ } else {
+ window->hide();
+ }
+ });
+ }
+
+ void resizeWindow(JNIEnv *, jclass, jlong windowRef, jint x, jint y, jint width, jint height)
+ {
+ QMetaObject::invokeMethod(qApp, [windowRef, x, y, width, height] {
+ QWindow *window = reinterpret_cast<QWindow*>(windowRef);
+ QWindow *parent = window->parent();
+ if (parent)
+ parent->setGeometry(x, y, width, height);
+ window->setGeometry(0, 0, width, height);
+ });
+ }
+
+ bool registerNatives(QJniEnvironment& env) {
+ return env.registerNativeMethods(
+ QtJniTypes::Traits<QtJniTypes::QtView>::className(),
+ { Q_JNI_NATIVE_SCOPED_METHOD(createRootWindow, QtAndroidWindowEmbedding),
+ Q_JNI_NATIVE_SCOPED_METHOD(deleteWindow, QtAndroidWindowEmbedding),
+ Q_JNI_NATIVE_SCOPED_METHOD(setWindowVisible, QtAndroidWindowEmbedding),
+ Q_JNI_NATIVE_SCOPED_METHOD(resizeWindow, QtAndroidWindowEmbedding) });
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/androidwindowembedding.h b/src/plugins/platforms/android/androidwindowembedding.h
new file mode 100644
index 0000000000..b7b0e1205f
--- /dev/null
+++ b/src/plugins/platforms/android/androidwindowembedding.h
@@ -0,0 +1,41 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTANDROIDWINDOWEMBEDDING_H
+#define QTANDROIDWINDOWEMBEDDING_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/qjnienvironment.h>
+#include <QtCore/qjnitypes.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_JNI_CLASS(View, "android/view/View");
+
+namespace QtAndroidWindowEmbedding
+{
+ bool registerNatives(QJniEnvironment& env);
+ void createRootWindow(JNIEnv *, jclass, QtJniTypes::View rootView,
+ jint x, jint y,jint width, jint height);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(createRootWindow)
+ void deleteWindow(JNIEnv *, jclass, jlong window);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(deleteWindow)
+ void setWindowVisible(JNIEnv *, jclass, jlong window, jboolean visible);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(setWindowVisible)
+ void resizeWindow(JNIEnv *, jclass, jlong windowRef, jint x, jint y, jint width, jint height);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(resizeWindow)
+};
+
+QT_END_NAMESPACE
+
+#endif // QTANDROIDWINDOWEMBEDDING_H
diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp
index c7785486b0..4ea6536cef 100644
--- a/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp
+++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.cpp
@@ -142,17 +142,13 @@ public:
return m_path + at(m_index).name;
}
- bool hasNext() const
+ bool advance()
{
- return !empty() && m_index + 1 < size();
- }
-
- std::optional<std::pair<QString, AssetItem>> next()
- {
- if (!hasNext())
- return {};
- ++m_index;
- return std::pair<QString, AssetItem>(currentFileName(), at(m_index));
+ if (!empty() && m_index + 1 < size()) {
+ ++m_index;
+ return true;
+ }
+ return false;
}
private:
@@ -171,7 +167,7 @@ public:
AndroidAbstractFileEngineIterator(QDir::Filters filters,
const QStringList &nameFilters,
const QString &path)
- : QAbstractFileEngineIterator(filters, nameFilters)
+ : QAbstractFileEngineIterator(path, filters, nameFilters)
{
m_currentIterator = FolderIterator::fromCache(cleanedAssetPath(path), true);
}
@@ -195,21 +191,9 @@ public:
return m_currentIterator->currentFilePath();
}
- bool hasNext() const override
- {
- if (!m_currentIterator)
- return false;
- return m_currentIterator->hasNext();
- }
-
- QString next() override
+ bool advance() override
{
- if (!m_currentIterator)
- return {};
- auto res = m_currentIterator->next();
- if (!res)
- return {};
- return res->first;
+ return m_currentIterator ? m_currentIterator->advance() : false;
}
private:
@@ -307,9 +291,9 @@ public:
return prefixedPath(m_fileName);
case BaseName:
if ((pos = m_fileName.lastIndexOf(u'/')) != -1)
- return prefixedPath(m_fileName.mid(pos));
+ return m_fileName.mid(pos + 1);
else
- return prefixedPath(m_fileName);
+ return m_fileName;
case PathName:
case AbsolutePathName:
case CanonicalPathName:
@@ -367,10 +351,12 @@ public:
m_assetsInfoCache.insert(m_fileName, newAssetInfoPtr);
}
- Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override
+ IteratorUniquePtr
+ beginEntryList(const QString &, QDir::Filters filters, const QStringList &filterNames) override
{
+ // AndroidAbstractFileEngineIterator use `m_fileName` as the path
if (m_assetInfo && m_assetInfo->type == AssetItem::Type::Folder)
- return new AndroidAbstractFileEngineIterator(filters, filterNames, m_fileName);
+ return std::make_unique<AndroidAbstractFileEngineIterator>(filters, filterNames, m_fileName);
return nullptr;
}
@@ -393,13 +379,14 @@ AndroidAssetsFileEngineHandler::AndroidAssetsFileEngineHandler()
m_assetManager = QtAndroid::assetManager();
}
-QAbstractFileEngine * AndroidAssetsFileEngineHandler::create(const QString &fileName) const
+std::unique_ptr<QAbstractFileEngine>
+AndroidAssetsFileEngineHandler::create(const QString &fileName) const
{
if (fileName.isEmpty())
- return nullptr;
+ return {};
if (!fileName.startsWith(assetsPrefix))
- return nullptr;
+ return {};
QString path = fileName.mid(prefixSize);
path.replace("//"_L1, "/"_L1);
@@ -407,7 +394,7 @@ QAbstractFileEngine * AndroidAssetsFileEngineHandler::create(const QString &file
path.remove(0, 1);
if (path.endsWith(u'/'))
path.chop(1);
- return new AndroidAbstractFileEngine(m_assetManager, path);
+ return std::make_unique<AndroidAbstractFileEngine>(m_assetManager, path);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidassetsfileenginehandler.h b/src/plugins/platforms/android/qandroidassetsfileenginehandler.h
index 50c6914c24..973a61fbfa 100644
--- a/src/plugins/platforms/android/qandroidassetsfileenginehandler.h
+++ b/src/plugins/platforms/android/qandroidassetsfileenginehandler.h
@@ -15,9 +15,10 @@ QT_BEGIN_NAMESPACE
class AndroidAssetsFileEngineHandler: public QAbstractFileEngineHandler
{
+ Q_DISABLE_COPY_MOVE(AndroidAssetsFileEngineHandler)
public:
AndroidAssetsFileEngineHandler();
- QAbstractFileEngine *create(const QString &fileName) const override;
+ std::unique_ptr<QAbstractFileEngine> create(const QString &fileName) const override;
private:
AAssetManager *m_assetManager;
diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp
index 4c111be829..62212ff63d 100644
--- a/src/plugins/platforms/android/qandroidinputcontext.cpp
+++ b/src/plugins/platforms/android/qandroidinputcontext.cpp
@@ -80,9 +80,7 @@ static jboolean beginBatchEdit(JNIEnv */*env*/, jobject /*thiz*/)
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@ BEGINBATCH");
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ BEGINBATCH";
jboolean res = JNI_FALSE;
runOnQtThread([&res]{res = m_androidInputContext->beginBatchEdit();});
return res;
@@ -93,9 +91,7 @@ static jboolean endBatchEdit(JNIEnv */*env*/, jobject /*thiz*/)
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@ ENDBATCH");
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ ENDBATCH";
jboolean res = JNI_FALSE;
runOnQtThread([&res]{res = m_androidInputContext->endBatchEdit();});
@@ -113,9 +109,7 @@ static jboolean commitText(JNIEnv *env, jobject /*thiz*/, jstring text, jint new
QString str(reinterpret_cast<const QChar *>(jstr), env->GetStringLength(text));
env->ReleaseStringChars(text, jstr);
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ COMMIT" << str << newCursorPosition;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ COMMIT" << str << newCursorPosition;
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->commitText(str, newCursorPosition);});
return res;
@@ -126,9 +120,7 @@ static jboolean deleteSurroundingText(JNIEnv */*env*/, jobject /*thiz*/, jint le
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ DELETE" << leftLength << rightLength;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ DELETE" << leftLength << rightLength;
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->deleteSurroundingText(leftLength, rightLength);});
return res;
@@ -139,9 +131,7 @@ static jboolean finishComposingText(JNIEnv */*env*/, jobject /*thiz*/)
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@ FINISH");
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ FINISH";
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->finishComposingText();});
return res;
@@ -165,9 +155,7 @@ static jobject getExtractedText(JNIEnv *env, jobject /*thiz*/, int hintMaxChars,
QAndroidInputContext::ExtractedText extractedText;
runOnQtThread([&]{extractedText = m_androidInputContext->getExtractedText(hintMaxChars, hintMaxLines, flags);});
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ GETEX" << hintMaxChars << hintMaxLines << QString::fromLatin1("0x") + QString::number(flags,16) << extractedText.text << "partOff:" << extractedText.partialStartOffset << extractedText.partialEndOffset << "sel:" << extractedText.selectionStart << extractedText.selectionEnd << "offset:" << extractedText.startOffset;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ GETEX" << hintMaxChars << hintMaxLines << QString::fromLatin1("0x") + QString::number(flags,16) << extractedText.text << "partOff:" << extractedText.partialStartOffset << extractedText.partialEndOffset << "sel:" << extractedText.selectionStart << extractedText.selectionEnd << "offset:" << extractedText.startOffset;
jobject object = env->NewObject(m_extractedTextClass, m_classConstructorMethodID);
env->SetIntField(object, m_partialStartOffsetFieldID, extractedText.partialStartOffset);
@@ -190,9 +178,7 @@ static jstring getSelectedText(JNIEnv *env, jobject /*thiz*/, jint flags)
QString text;
runOnQtThread([&]{text = m_androidInputContext->getSelectedText(flags);});
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ GETSEL" << text;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ GETSEL" << text;
if (text.isEmpty())
return 0;
return env->NewString(reinterpret_cast<const jchar *>(text.constData()), jsize(text.length()));
@@ -205,9 +191,7 @@ static jstring getTextAfterCursor(JNIEnv *env, jobject /*thiz*/, jint length, ji
QString text;
runOnQtThread([&]{text = m_androidInputContext->getTextAfterCursor(length, flags);});
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ GETA" << length << text;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ GETA" << length << text;
return env->NewString(reinterpret_cast<const jchar *>(text.constData()), jsize(text.length()));
}
@@ -218,9 +202,7 @@ static jstring getTextBeforeCursor(JNIEnv *env, jobject /*thiz*/, jint length, j
QString text;
runOnQtThread([&]{text = m_androidInputContext->getTextBeforeCursor(length, flags);});
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ GETB" << length << text;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ GETB" << length << text;
return env->NewString(reinterpret_cast<const jchar *>(text.constData()), jsize(text.length()));
}
@@ -234,9 +216,7 @@ static jboolean setComposingText(JNIEnv *env, jobject /*thiz*/, jstring text, ji
QString str(reinterpret_cast<const QChar *>(jstr), env->GetStringLength(text));
env->ReleaseStringChars(text, jstr);
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ SET" << str << newCursorPosition;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ SET" << str << newCursorPosition;
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->setComposingText(str, newCursorPosition);});
return res;
@@ -247,9 +227,7 @@ static jboolean setComposingRegion(JNIEnv */*env*/, jobject /*thiz*/, jint start
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ SETR" << start << end;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ SETR" << start << end;
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->setComposingRegion(start, end);});
return res;
@@ -261,9 +239,7 @@ static jboolean setSelection(JNIEnv */*env*/, jobject /*thiz*/, jint start, jint
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ SETSEL" << start << end;
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ SETSEL" << start << end;
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->setSelection(start, end);});
return res;
@@ -275,9 +251,7 @@ static jboolean selectAll(JNIEnv */*env*/, jobject /*thiz*/)
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@ SELALL");
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ SELALL";
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->selectAll();});
return res;
@@ -288,9 +262,7 @@ static jboolean cut(JNIEnv */*env*/, jobject /*thiz*/)
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@");
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@";
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->cut();});
return res;
@@ -301,9 +273,7 @@ static jboolean copy(JNIEnv */*env*/, jobject /*thiz*/)
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@");
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@";
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->copy();});
return res;
@@ -314,9 +284,7 @@ static jboolean copyURL(JNIEnv */*env*/, jobject /*thiz*/)
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@");
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@";
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->copyURL();});
return res;
@@ -327,9 +295,7 @@ static jboolean paste(JNIEnv */*env*/, jobject /*thiz*/)
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@ PASTE");
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ PASTE";
jboolean res = JNI_FALSE;
runOnQtThread([&]{res = m_androidInputContext->paste();});
return res;
@@ -340,14 +306,24 @@ static jboolean updateCursorPosition(JNIEnv */*env*/, jobject /*thiz*/)
if (!m_androidInputContext)
return JNI_FALSE;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug("@@@ UPDATECURSORPOS");
-#endif
+ qCDebug(lcQpaInputMethods) << "@@@ UPDATECURSORPOS";
runOnQtThread([&]{m_androidInputContext->updateCursorPosition();});
return true;
}
+static void reportFullscreenMode(JNIEnv */*env*/, jobject /*thiz*/, jboolean enabled)
+{
+ if (!m_androidInputContext)
+ return;
+
+ runOnQtThread([&]{m_androidInputContext->reportFullscreenMode(enabled);});
+}
+
+static jboolean fullscreenMode(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ return m_androidInputContext ? m_androidInputContext->fullscreenMode() : false;
+}
static JNINativeMethod methods[] = {
{"beginBatchEdit", "()Z", (void *)beginBatchEdit},
@@ -368,7 +344,9 @@ static JNINativeMethod methods[] = {
{"copy", "()Z", (void *)copy},
{"copyURL", "()Z", (void *)copyURL},
{"paste", "()Z", (void *)paste},
- {"updateCursorPosition", "()Z", (void *)updateCursorPosition}
+ {"updateCursorPosition", "()Z", (void *)updateCursorPosition},
+ {"reportFullscreenMode", "(Z)V", (void *)reportFullscreenMode},
+ {"fullscreenMode", "()Z", (void *)fullscreenMode}
};
static QRect screenInputItemRectangle()
@@ -385,6 +363,7 @@ QAndroidInputContext::QAndroidInputContext()
, m_handleMode(Hidden)
, m_batchEditNestingLevel(0)
, m_focusObject(0)
+ , m_fullScreenMode(false)
{
QJniEnvironment env;
jclass clazz = env.findClass(QtNativeInputConnectionClassName);
@@ -567,12 +546,29 @@ void QAndroidInputContext::updateCursorPosition()
}
}
+bool QAndroidInputContext::isImhNoTextHandlesSet()
+{
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (query.isNull())
+ return false;
+ return query->value(Qt::ImHints).toUInt() & Qt::ImhNoTextHandles;
+}
+
void QAndroidInputContext::updateSelectionHandles()
{
+ if (m_fullScreenMode) {
+ QtAndroidInput::updateHandles(Hidden);
+ return;
+ }
static bool noHandles = qEnvironmentVariableIntValue("QT_QPA_NO_TEXT_HANDLES");
if (noHandles || !m_focusObject)
return;
+ if (isImhNoTextHandlesSet()) {
+ QtAndroidInput::updateHandles(Hidden);
+ return;
+ }
+
auto im = qGuiApp->inputMethod();
QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImEnabled
@@ -586,6 +582,11 @@ void QAndroidInputContext::updateSelectionHandles()
bool readOnly = readOnlyVariant.toBool();
QPlatformWindow *qPlatformWindow = qGuiApp->focusWindow()->handle();
+ if (!readOnly && ((m_handleMode & 0xff) == Hidden)) {
+ QtAndroidInput::updateHandles(Hidden);
+ return;
+ }
+
if ( cpos == anchor && (!readOnlyVariant.isValid() || readOnly)) {
QtAndroidInput::updateHandles(Hidden);
return;
@@ -612,9 +613,8 @@ void QAndroidInputContext::updateSelectionHandles()
if (!query.value(Qt::ImSurroundingText).toString().isEmpty())
buttons |= EditContext::SelectAllButton;
QtAndroidInput::updateHandles(m_handleMode, editMenuPoint, buttons, cursorPointGlobal);
- // The VK is hidden, reset the timer
- if (m_hideCursorHandleTimer.isActive())
- m_hideCursorHandleTimer.start();
+ m_hideCursorHandleTimer.start();
+
return;
}
@@ -788,7 +788,15 @@ void QAndroidInputContext::touchDown(int x, int y)
focusObjectStopComposing();
}
- updateSelectionHandles();
+ // Check if cursor is visible in focused window before updating handles
+ QPlatformWindow *window = qGuiApp->focusWindow()->handle();
+ const QRectF curRect = cursorRectangle();
+ const QPoint cursorGlobalPoint = window->mapToGlobal(QPoint(curRect.x(), curRect.y()));
+ const QRect windowRect = QPlatformInputContext::inputItemClipRectangle().toRect();
+ const QRect windowGlobalRect = QRect(window->mapToGlobal(windowRect.topLeft()), windowRect.size());
+
+ if (windowGlobalRect.contains(cursorGlobalPoint.x(), cursorGlobalPoint.y()))
+ updateSelectionHandles();
}
}
@@ -895,6 +903,9 @@ void QAndroidInputContext::showInputPanel()
if (query.isNull())
return;
+ if (!qGuiApp->focusWindow()->handle())
+ return; // not a real window, probably VR/XR
+
disconnect(m_updateCursorPosConnection);
m_updateCursorPosConnection = {};
@@ -1112,6 +1123,25 @@ jboolean QAndroidInputContext::finishComposingText()
return JNI_TRUE;
}
+void QAndroidInputContext::reportFullscreenMode(jboolean enabled)
+{
+ m_fullScreenMode = enabled;
+ BatchEditLock batchEditLock(this);
+ if (!focusObjectStopComposing())
+ return;
+
+ if (enabled)
+ m_handleMode = Hidden;
+
+ updateSelectionHandles();
+}
+
+// Called in calling thread's context
+jboolean QAndroidInputContext::fullscreenMode()
+{
+ return m_fullScreenMode;
+}
+
bool QAndroidInputContext::focusObjectIsComposing() const
{
return m_composingCursor != -1;
@@ -1534,9 +1564,7 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end)
}
if (start < textOffset || end - textOffset > text.length()) {
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qWarning("setComposingRegion: failed to retrieve text from composing region");
-#endif
+ qCDebug(lcQpaInputMethods) << "Warning: setComposingRegion: failed to retrieve text from composing region";
return JNI_TRUE;
}
diff --git a/src/plugins/platforms/android/qandroidinputcontext.h b/src/plugins/platforms/android/qandroidinputcontext.h
index c93aae142a..038286c4b8 100644
--- a/src/plugins/platforms/android/qandroidinputcontext.h
+++ b/src/plugins/platforms/android/qandroidinputcontext.h
@@ -9,6 +9,8 @@
#include <functional>
#include <jni.h>
#include <qevent.h>
+
+#include <QtCore/qpointer.h>
#include <QTimer>
QT_BEGIN_NAMESPACE
@@ -98,6 +100,8 @@ public:
jboolean copy();
jboolean copyURL();
jboolean paste();
+ void reportFullscreenMode(jboolean enabled);
+ jboolean fullscreenMode();
public slots:
void safeCall(const std::function<void()> &func, Qt::ConnectionType conType = Qt::BlockingQueuedConnection);
@@ -113,6 +117,7 @@ private slots:
void showInputPanelLater(Qt::ApplicationState);
private:
+ bool isImhNoTextHandlesSet();
void sendInputMethodEvent(QInputMethodEvent *event);
QSharedPointer<QInputMethodQueryEvent> focusObjectInputMethodQuery(Qt::InputMethodQueries queries = Qt::ImQueryAll);
bool focusObjectIsComposing() const;
@@ -129,6 +134,7 @@ private:
int m_batchEditNestingLevel;
QPointer<QObject> m_focusObject;
QTimer m_hideCursorHandleTimer;
+ bool m_fullScreenMode;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QAndroidInputContext::HandleModes)
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformaccessibility.cpp b/src/plugins/platforms/android/qandroidplatformaccessibility.cpp
index 61fc21a6bc..ea7f22295d 100644
--- a/src/plugins/platforms/android/qandroidplatformaccessibility.cpp
+++ b/src/plugins/platforms/android/qandroidplatformaccessibility.cpp
@@ -28,6 +28,8 @@ void QAndroidPlatformAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *
QtAndroidAccessibility::notifyLocationChange(event->uniqueId());
} else if (event->type() == QAccessible::ObjectHide) {
QtAndroidAccessibility::notifyObjectHide(event->uniqueId());
+ } else if (event->type() == QAccessible::ObjectShow) {
+ QtAndroidAccessibility::notifyObjectShow(event->uniqueId());
} else if (event->type() == QAccessible::Focus) {
QtAndroidAccessibility::notifyObjectFocus(event->uniqueId());
} else if (event->type() == QAccessible::ValueChanged) {
diff --git a/src/plugins/platforms/android/qandroidplatformbackingstore.cpp b/src/plugins/platforms/android/qandroidplatformbackingstore.cpp
deleted file mode 100644
index 07a1c835d3..0000000000
--- a/src/plugins/platforms/android/qandroidplatformbackingstore.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include "qandroidplatformbackingstore.h"
-#include "qandroidplatformscreen.h"
-#include "qandroidplatformwindow.h"
-#include <qpa/qplatformscreen.h>
-
-QT_BEGIN_NAMESPACE
-
-QAndroidPlatformBackingStore::QAndroidPlatformBackingStore(QWindow *window)
- : QPlatformBackingStore(window)
-{
- if (window->handle())
- setBackingStore(window);
-}
-
-QPaintDevice *QAndroidPlatformBackingStore::paintDevice()
-{
- return &m_image;
-}
-
-void QAndroidPlatformBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
-{
- Q_UNUSED(offset);
-
- if (!m_backingStoreSet)
- setBackingStore(window);
-
- (static_cast<QAndroidPlatformWindow *>(window->handle()))->repaint(region);
-}
-
-void QAndroidPlatformBackingStore::resize(const QSize &size, const QRegion &staticContents)
-{
- Q_UNUSED(staticContents);
-
- if (m_image.size() != size)
- m_image = QImage(size, window()->screen()->handle()->format());
-}
-
-void QAndroidPlatformBackingStore::setBackingStore(QWindow *window)
-{
- if (window->surfaceType() == QSurface::RasterSurface || window->surfaceType() == QSurface::RasterGLSurface) {
- (static_cast<QAndroidPlatformWindow *>(window->handle()))->setBackingStore(this);
- m_backingStoreSet = true;
- } else {
- qWarning("QAndroidPlatformBackingStore does not support OpenGL-only windows.");
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformbackingstore.h b/src/plugins/platforms/android/qandroidplatformbackingstore.h
deleted file mode 100644
index 810305ac45..0000000000
--- a/src/plugins/platforms/android/qandroidplatformbackingstore.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QANDROIDPLATFORMBACKINGSTORE_H
-#define QANDROIDPLATFORMBACKINGSTORE_H
-
-#include <qpa/qplatformbackingstore.h>
-#include <qpa/qwindowsysteminterface.h>
-
-QT_BEGIN_NAMESPACE
-
-class QAndroidPlatformBackingStore : public QPlatformBackingStore
-{
-public:
- explicit QAndroidPlatformBackingStore(QWindow *window);
- QPaintDevice *paintDevice() override;
- void flush(QWindow *window, const QRegion &region, const QPoint &offset) override;
- void resize(const QSize &size, const QRegion &staticContents) override;
- QImage toImage() const override { return m_image; }
- void setBackingStore(QWindow *window);
-protected:
- QImage m_image;
- bool m_backingStoreSet = false;
-};
-
-QT_END_NAMESPACE
-
-#endif // QANDROIDPLATFORMBACKINGSTORE_H
diff --git a/src/plugins/platforms/android/qandroidplatformclipboard.cpp b/src/plugins/platforms/android/qandroidplatformclipboard.cpp
index 39a508a1b3..e5ed33b9b0 100644
--- a/src/plugins/platforms/android/qandroidplatformclipboard.cpp
+++ b/src/plugins/platforms/android/qandroidplatformclipboard.cpp
@@ -1,15 +1,34 @@
+// Copyright (C) 2023 The Qt Company Ltd.
// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qandroidplatformclipboard.h"
-#include "androidjniclipboard.h"
+
+#include <QtCore/QUrl>
+#include <QtCore/QJniEnvironment>
+#include <QtCore/QJniObject>
+#include <QtCore/private/qjnihelpers_p.h>
+
#ifndef QT_NO_CLIPBOARD
+using namespace QtJniTypes;
+
QT_BEGIN_NAMESPACE
+void QAndroidPlatformClipboard::onClipboardDataChanged(JNIEnv *env, jobject obj, jlong nativePointer)
+{
+ Q_UNUSED(env)
+ Q_UNUSED(obj)
+
+ auto *clipboardManager = reinterpret_cast<QAndroidPlatformClipboard *>(nativePointer);
+ if (clipboardManager)
+ clipboardManager->emitChanged(QClipboard::Clipboard);
+}
+
QAndroidPlatformClipboard::QAndroidPlatformClipboard()
{
- QtAndroidClipboard::setClipboardManager(this);
+ m_clipboardManager = QtClipboardManager::construct(QtAndroidPrivate::context(),
+ reinterpret_cast<jlong>(this));
}
QAndroidPlatformClipboard::~QAndroidPlatformClipboard()
@@ -18,24 +37,66 @@ QAndroidPlatformClipboard::~QAndroidPlatformClipboard()
delete data;
}
+QMimeData *QAndroidPlatformClipboard::getClipboardMimeData()
+{
+ QMimeData *data = new QMimeData;
+ if (m_clipboardManager.callMethod<jboolean>("hasClipboardText")) {
+ data->setText(m_clipboardManager.callMethod<QString>("getClipboardText"));
+ }
+ if (m_clipboardManager.callMethod<jboolean>("hasClipboardHtml")) {
+ data->setHtml(m_clipboardManager.callMethod<QString>("getClipboardHtml"));
+ }
+ if (m_clipboardManager.callMethod<jboolean>("hasClipboardUri")) {
+ auto uris = m_clipboardManager.callMethod<QString[]>("getClipboardUris");
+ if (uris.isValid()) {
+ QList<QUrl> urls;
+ for (const QString &uri : uris)
+ urls << QUrl(uri);
+ data->setUrls(urls);
+ }
+ }
+ return data;
+}
+
QMimeData *QAndroidPlatformClipboard::mimeData(QClipboard::Mode mode)
{
Q_UNUSED(mode);
Q_ASSERT(supportsMode(mode));
if (data)
data->deleteLater();
- data = QtAndroidClipboard::getClipboardMimeData();
+ data = getClipboardMimeData();
return data;
}
+void QAndroidPlatformClipboard::clearClipboardData()
+{
+ m_clipboardManager.callMethod<void>("clearClipData");
+}
+
+void QAndroidPlatformClipboard::setClipboardMimeData(QMimeData *data)
+{
+ clearClipboardData();
+ auto context = QtAndroidPrivate::context();
+ if (data->hasUrls()) {
+ QList<QUrl> urls = data->urls();
+ for (const auto &u : std::as_const(urls))
+ m_clipboardManager.callMethod<void>("setClipboardUri", context, u.toEncoded());
+ } else if (data->hasHtml()) { // html can contain text
+ m_clipboardManager.callMethod<void>("setClipboardHtml",
+ context, data->text(), data->html());
+ } else if (data->hasText()) { // hasText must be the last (the order matter here)
+ m_clipboardManager.callMethod<void>("setClipboardText", context, data->text());
+ }
+}
+
void QAndroidPlatformClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
{
if (!data) {
- QtAndroidClipboard::clearClipboardData();
+ clearClipboardData();
return;
}
if (data && supportsMode(mode))
- QtAndroidClipboard::setClipboardMimeData(data);
+ setClipboardMimeData(data);
if (data != 0)
data->deleteLater();
}
@@ -45,6 +106,18 @@ bool QAndroidPlatformClipboard::supportsMode(QClipboard::Mode mode) const
return QClipboard::Clipboard == mode;
}
+bool QAndroidPlatformClipboard::registerNatives(QJniEnvironment &env)
+{
+ bool success = env.registerNativeMethods(Traits<QtClipboardManager>::className(),
+ { Q_JNI_NATIVE_SCOPED_METHOD(onClipboardDataChanged, QAndroidPlatformClipboard) });
+ if (!success) {
+ qCritical() << "QtClipboardManager: registerNativeMethods() failed";
+ return false;
+ }
+
+ return true;
+}
+
QT_END_NAMESPACE
#endif // QT_NO_CLIPBOARD
diff --git a/src/plugins/platforms/android/qandroidplatformclipboard.h b/src/plugins/platforms/android/qandroidplatformclipboard.h
index 1778ca5b28..ab5c527f88 100644
--- a/src/plugins/platforms/android/qandroidplatformclipboard.h
+++ b/src/plugins/platforms/android/qandroidplatformclipboard.h
@@ -1,3 +1,4 @@
+// Copyright (C) 2023 The Qt Company Ltd.
// Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
@@ -6,10 +7,14 @@
#include <qpa/qplatformclipboard.h>
#include <QMimeData>
+#include <QtCore/qjnitypes.h>
#ifndef QT_NO_CLIPBOARD
+
QT_BEGIN_NAMESPACE
+Q_DECLARE_JNI_CLASS(QtClipboardManager, "org/qtproject/qt/android/QtClipboardManager");
+
class QAndroidPlatformClipboard : public QPlatformClipboard
{
public:
@@ -18,8 +23,19 @@ public:
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;
+
+ static bool registerNatives(QJniEnvironment &env);
+
private:
+ QMimeData *getClipboardMimeData();
+ void setClipboardMimeData(QMimeData *data);
+ void clearClipboardData();
+
+ static void onClipboardDataChanged(JNIEnv *env, jobject obj, jlong nativePointer);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(onClipboardDataChanged)
+
QMimeData *data = nullptr;
+ QtJniTypes::QtClipboardManager m_clipboardManager = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp b/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp
index 25427d5ede..2b9a1194d2 100644
--- a/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp
+++ b/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp
@@ -19,7 +19,7 @@ static jclass g_messageDialogHelperClass = nullptr;
QAndroidPlatformMessageDialogHelper::QAndroidPlatformMessageDialogHelper()
: m_javaMessageDialog(g_messageDialogHelperClass, "(Landroid/app/Activity;)V",
- QtAndroid::activity())
+ QtAndroidPrivate::activity().object())
{
}
@@ -150,7 +150,7 @@ static void dialogResult(JNIEnv * /*env*/, jobject /*thiz*/, jlong handler, int
QMetaObject::invokeMethod(object, "dialogResult", Qt::QueuedConnection, Q_ARG(int, buttonID));
}
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
{"dialogResult", "(JI)V", (void *)dialogResult}
};
@@ -162,21 +162,19 @@ static JNINativeMethod methods[] = {
return false; \
}
-bool registerNatives(JNIEnv *env)
+bool registerNatives(QJniEnvironment &env)
{
const char QtMessageHandlerHelperClassName[] = "org/qtproject/qt/android/QtMessageDialogHelper";
- QJniEnvironment qenv;
- jclass clazz = qenv.findClass(QtMessageHandlerHelperClassName);
+ jclass clazz = env.findClass(QtMessageHandlerHelperClassName);
if (!clazz) {
__android_log_print(ANDROID_LOG_FATAL, QtAndroid::qtTagText(), QtAndroid::classErrorMsgFmt()
, QtMessageHandlerHelperClassName);
return false;
}
g_messageDialogHelperClass = static_cast<jclass>(env->NewGlobalRef(clazz));
- FIND_AND_CHECK_CLASS("org/qtproject/qt/android/QtNativeDialogHelper");
- jclass appClass = static_cast<jclass>(env->NewGlobalRef(clazz));
- if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ if (!env.registerNativeMethods("org/qtproject/qt/android/QtNativeDialogHelper",
+ methods, sizeof(methods) / sizeof(methods[0]))) {
__android_log_print(ANDROID_LOG_FATAL, "Qt", "RegisterNatives failed");
return false;
}
diff --git a/src/plugins/platforms/android/qandroidplatformdialoghelpers.h b/src/plugins/platforms/android/qandroidplatformdialoghelpers.h
index f06d2a9990..86f1cf77e7 100644
--- a/src/plugins/platforms/android/qandroidplatformdialoghelpers.h
+++ b/src/plugins/platforms/android/qandroidplatformdialoghelpers.h
@@ -8,12 +8,13 @@
#include <jni.h>
#include <QEventLoop>
-#include <QtCore/QJniEnvironment>
#include <QtCore/QJniObject>
#include <qpa/qplatformdialoghelper.h>
QT_BEGIN_NAMESPACE
+class QJniEnvironment;
+
namespace QtAndroidDialogHelpers {
class QAndroidPlatformMessageDialogHelper: public QPlatformMessageDialogHelper
@@ -41,7 +42,7 @@ private:
};
-bool registerNatives(JNIEnv *env);
+bool registerNatives(QJniEnvironment &env);
}
diff --git a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp
index 3723e33371..d8a5c58d2c 100644
--- a/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp
+++ b/src/plugins/platforms/android/qandroidplatformfiledialoghelper.cpp
@@ -25,7 +25,7 @@ const char JniIntentClass[] = "android/content/Intent";
QAndroidPlatformFileDialogHelper::QAndroidPlatformFileDialogHelper()
: QPlatformFileDialogHelper(),
- m_activity(QtAndroid::activity())
+ m_activity(QtAndroidPrivate::activity())
{
}
@@ -45,8 +45,8 @@ bool QAndroidPlatformFileDialogHelper::handleActivityResult(jint requestCode, ji
if (uri.isValid()) {
takePersistableUriPermission(uri);
m_selectedFile.append(QUrl(uri.toString()));
- Q_EMIT fileSelected(m_selectedFile.first());
- Q_EMIT currentChanged(m_selectedFile.first());
+ Q_EMIT fileSelected(m_selectedFile.constFirst());
+ Q_EMIT currentChanged(m_selectedFile.constFirst());
Q_EMIT accept();
return true;
@@ -65,7 +65,7 @@ bool QAndroidPlatformFileDialogHelper::handleActivityResult(jint requestCode, ji
m_selectedFile.append(itemUri.toString());
}
Q_EMIT filesSelected(m_selectedFile);
- Q_EMIT currentChanged(m_selectedFile.first());
+ Q_EMIT currentChanged(m_selectedFile.constFirst());
Q_EMIT accept();
}
@@ -146,12 +146,15 @@ void QAndroidPlatformFileDialogHelper::setMimeTypes()
{
QStringList mimeTypes = options()->mimeTypeFilters();
const QStringList nameFilters = options()->nameFilters();
- const QString nameFilter = nameFilters.isEmpty() ? QString() : nameFilters.first();
- if (!nameFilter.isEmpty()) {
+ if (!nameFilters.isEmpty()) {
QMimeDatabase db;
- for (const QString &filter : nameFilterExtensions(nameFilter))
- mimeTypes.append(db.mimeTypeForFile(filter, QMimeDatabase::MatchExtension).name());
+ for (auto filter : nameFilters) {
+ if (!filter.isEmpty()) {
+ for (const QString &filter : nameFilterExtensions(filter))
+ mimeTypes.append(db.mimeTypeForFile(filter, QMimeDatabase::MatchExtension).name());
+ }
+ }
}
const QString initialType = mimeTypes.size() == 1 ? mimeTypes.at(0) : "*/*"_L1;
diff --git a/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp b/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp
index 01636d2ba5..82a10dac07 100644
--- a/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp
+++ b/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QDir>
+#include <QLocale>
#include "qandroidplatformfontdatabase.h"
@@ -47,6 +48,38 @@ QStringList QAndroidPlatformFontDatabase::fallbacksForFamily(const QString &fami
QChar::Script script) const
{
QStringList result;
+
+ // Prepend CJK fonts by the locale.
+ QLocale locale = QLocale::system();
+ switch (locale.language()) {
+ case QLocale::Chinese: {
+ switch (locale.territory()) {
+ case QLocale::China:
+ case QLocale::Singapore:
+ result.append(QStringLiteral("Noto Sans Mono CJK SC"));
+ break;
+ case QLocale::Taiwan:
+ case QLocale::HongKong:
+ case QLocale::Macao:
+ result.append(QStringLiteral("Noto Sans Mono CJK TC"));
+ break;
+ default:
+ // no modifications.
+ break;
+ }
+ break;
+ }
+ case QLocale::Japanese:
+ result.append(QStringLiteral("Noto Sans Mono CJK JP"));
+ break;
+ case QLocale::Korean:
+ result.append(QStringLiteral("Noto Sans Mono CJK KR"));
+ break;
+ default:
+ // no modifications.
+ break;
+ }
+
if (styleHint == QFont::Monospace || styleHint == QFont::Courier)
result.append(QString(qgetenv("QT_ANDROID_FONTS_MONOSPACE")).split(u';'));
else if (styleHint == QFont::Serif)
diff --git a/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp b/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp
index c2ce2c84b2..e84a481a2b 100644
--- a/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp
+++ b/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp
@@ -6,84 +6,101 @@
#include <QtCore/qvariant.h>
#include <qpa/qwindowsysteminterface.h>
#include <QtCore/private/qjnihelpers_p.h>
+#include <QtCore/qjnitypes.h>
QT_BEGIN_NAMESPACE
QAndroidPlatformForeignWindow::QAndroidPlatformForeignWindow(QWindow *window, WId nativeHandle)
- : QAndroidPlatformWindow(window),
- m_surfaceId(-1)
+ : QAndroidPlatformWindow(window), m_view(nullptr), m_nativeViewInserted(false)
{
m_view = reinterpret_cast<jobject>(nativeHandle);
- if (m_view.isValid())
- QtAndroid::setViewVisibility(m_view.object(), false);
-}
+ if (isEmbeddingContainer()) {
+ m_nativeViewId = m_view.callMethod<jint>("getId");
+ return;
+ }
-QAndroidPlatformForeignWindow::~QAndroidPlatformForeignWindow()
-{
if (m_view.isValid())
QtAndroid::setViewVisibility(m_view.object(), false);
- if (m_surfaceId != -1)
- QtAndroid::destroySurface(m_surfaceId);
}
-void QAndroidPlatformForeignWindow::lower()
+QAndroidPlatformForeignWindow::~QAndroidPlatformForeignWindow()
{
- if (m_surfaceId == -1)
+ if (isEmbeddingContainer())
return;
- QAndroidPlatformWindow::lower();
- QtAndroid::bringChildToBack(m_surfaceId);
-}
+ if (m_view.isValid())
+ QtAndroid::setViewVisibility(m_view.object(), false);
-void QAndroidPlatformForeignWindow::raise()
-{
- if (m_surfaceId == -1)
- return;
+ m_nativeQtWindow.callMethod<void>("removeNativeView");
- QAndroidPlatformWindow::raise();
- QtAndroid::bringChildToFront(m_surfaceId);
}
void QAndroidPlatformForeignWindow::setGeometry(const QRect &rect)
{
QAndroidPlatformWindow::setGeometry(rect);
- if (m_surfaceId != -1)
- QtAndroid::setSurfaceGeometry(m_surfaceId, rect);
+ if (isEmbeddingContainer())
+ return;
+
+ if (m_nativeViewInserted)
+ setNativeGeometry(rect);
}
void QAndroidPlatformForeignWindow::setVisible(bool visible)
{
+ if (isEmbeddingContainer()) {
+ QAndroidPlatformWindow::setVisible(visible);
+ return;
+ }
+
if (!m_view.isValid())
return;
QtAndroid::setViewVisibility(m_view.object(), visible);
- QAndroidPlatformWindow::setVisible(visible);
- if (!visible && m_surfaceId != -1) {
- QtAndroid::destroySurface(m_surfaceId);
- m_surfaceId = -1;
- } else if (m_surfaceId == -1) {
- m_surfaceId = QtAndroid::insertNativeView(m_view.object(), geometry());
+ if (!visible && m_nativeViewInserted) {
+ m_nativeQtWindow.callMethod<void>("removeNativeView");
+ m_nativeViewInserted = false;
+ } else if (!m_nativeViewInserted) {
+ addViewToWindow();
}
}
void QAndroidPlatformForeignWindow::applicationStateChanged(Qt::ApplicationState state)
{
- if (state <= Qt::ApplicationHidden
- && m_surfaceId != -1) {
- QtAndroid::destroySurface(m_surfaceId);
- m_surfaceId = -1;
- } else if (m_view.isValid() && m_surfaceId == -1){
- m_surfaceId = QtAndroid::insertNativeView(m_view.object(), geometry());
+ if (!isEmbeddingContainer()) {
+ if (state <= Qt::ApplicationHidden
+ && m_nativeViewInserted) {
+ m_nativeQtWindow.callMethod<void>("removeNativeView");
+ m_nativeViewInserted = false;
+ } else if (m_view.isValid() && !m_nativeViewInserted){
+ addViewToWindow();
+ }
}
QAndroidPlatformWindow::applicationStateChanged(state);
}
-void QAndroidPlatformForeignWindow::setParent(const QPlatformWindow *window)
+WId QAndroidPlatformForeignWindow::winId() const
{
- Q_UNUSED(window);
+ if (isEmbeddingContainer() && m_view.isValid())
+ return reinterpret_cast<WId>(m_view.object());
+ if (m_nativeQtWindow.isValid())
+ return reinterpret_cast<WId>(m_nativeQtWindow.object());
+ return 0L;
+}
+
+void QAndroidPlatformForeignWindow::addViewToWindow()
+{
+ if (isEmbeddingContainer())
+ return;
+
+ jint x = 0, y = 0, w = -1, h = -1;
+ if (!geometry().isNull())
+ geometry().getRect(&x, &y, &w, &h);
+
+ m_nativeQtWindow.callMethod<void>("setNativeView", m_view, x, y, qMax(w, 1), qMax(h, 1));
+ m_nativeViewInserted = true;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformforeignwindow.h b/src/plugins/platforms/android/qandroidplatformforeignwindow.h
index 7b576ecec4..503524cced 100644
--- a/src/plugins/platforms/android/qandroidplatformforeignwindow.h
+++ b/src/plugins/platforms/android/qandroidplatformforeignwindow.h
@@ -4,29 +4,31 @@
#ifndef QANDROIDPLATFORMFOREIGNWINDOW_H
#define QANDROIDPLATFORMFOREIGNWINDOW_H
-#include "androidsurfaceclient.h"
#include "qandroidplatformwindow.h"
#include <QtCore/QJniObject>
QT_BEGIN_NAMESPACE
+Q_DECLARE_JNI_CLASS(View, "android/view/View")
+
class QAndroidPlatformForeignWindow : public QAndroidPlatformWindow
{
public:
explicit QAndroidPlatformForeignWindow(QWindow *window, WId nativeHandle);
~QAndroidPlatformForeignWindow();
- void lower() override;
- void raise() override;
void setGeometry(const QRect &rect) override;
void setVisible(bool visible) override;
void applicationStateChanged(Qt::ApplicationState state) override;
- void setParent(const QPlatformWindow *window) override;
bool isForeignWindow() const override { return true; }
+ WId winId() const override;
+
private:
- int m_surfaceId;
- QJniObject m_view;
+ void addViewToWindow();
+
+ QtJniTypes::View m_view;
+ bool m_nativeViewInserted;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformiconengine.cpp b/src/plugins/platforms/android/qandroidplatformiconengine.cpp
new file mode 100644
index 0000000000..faa63dcca1
--- /dev/null
+++ b/src/plugins/platforms/android/qandroidplatformiconengine.cpp
@@ -0,0 +1,616 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qandroidplatformiconengine.h"
+#include "androidjnimain.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qjniarray.h>
+#include <QtCore/qjniobject.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qset.h>
+
+#include <QtGui/qfontdatabase.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qpalette.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+Q_LOGGING_CATEGORY(lcIconEngineFontDownload, "qt.qpa.iconengine.fontdownload")
+
+// the primary types to work with the FontRequest API
+Q_DECLARE_JNI_CLASS(FontRequest, "androidx/core/provider/FontRequest")
+Q_DECLARE_JNI_CLASS(FontsContractCompat, "androidx/core/provider/FontsContractCompat")
+Q_DECLARE_JNI_CLASS(FontFamilyResult, "androidx/core/provider/FontsContractCompat$FontFamilyResult")
+Q_DECLARE_JNI_CLASS(FontInfo, "androidx/core/provider/FontsContractCompat$FontInfo")
+
+// various utility types
+Q_DECLARE_JNI_CLASS(List, "java/util/List"); // List is just an Interface
+Q_DECLARE_JNI_CLASS(ArrayList, "java/util/ArrayList");
+Q_DECLARE_JNI_CLASS(HashSet, "java/util/HashSet");
+Q_DECLARE_JNI_CLASS(Uri, "android/net/Uri")
+Q_DECLARE_JNI_CLASS(CancellationSignal, "android/os/CancellationSignal")
+Q_DECLARE_JNI_CLASS(ParcelFileDescriptor, "android/os/ParcelFileDescriptor")
+Q_DECLARE_JNI_CLASS(ContentResolver, "android/content/ContentResolver")
+Q_DECLARE_JNI_CLASS(PackageManager, "android/content/pm/PackageManager")
+Q_DECLARE_JNI_CLASS(ProviderInfo, "android/content/pm/ProviderInfo")
+Q_DECLARE_JNI_CLASS(PackageInfo, "android/content/pm/PackageInfo")
+Q_DECLARE_JNI_CLASS(Signature, "android/content/pm/Signature")
+
+namespace FontProvider {
+
+static QString fetchFont(const QString &query)
+{
+ using namespace QtJniTypes;
+
+ static QMap<QString, QString> triedFonts;
+ const auto it = triedFonts.find(query);
+ if (it != triedFonts.constEnd())
+ return it.value();
+
+ QString fontFamily;
+ triedFonts[query] = fontFamily; // mark as tried
+
+ QStringList loadedFamilies;
+ if (QFile file(query); file.open(QIODevice::ReadOnly)) {
+ qCDebug(lcIconEngineFontDownload) << "Loading font from resource" << query;
+ const QByteArray fontData = file.readAll();
+ int fontId = QFontDatabase::addApplicationFontFromData(fontData);
+ loadedFamilies << QFontDatabase::applicationFontFamilies(fontId);
+ } else if (!query.startsWith(u":/"_s)) {
+ const QString package = u"com.google.android.gms"_s;
+ const QString authority = u"com.google.android.gms.fonts"_s;
+
+ // First we access the content provider to get the signatures of the authority for the package
+ const auto context = QtAndroidPrivate::context();
+
+ auto packageManager = context.callMethod<PackageManager>("getPackageManager");
+ if (!packageManager.isValid()) {
+ qCWarning(lcIconEngineFontDownload, "Failed to instantiate PackageManager");
+ return fontFamily;
+ }
+ const int signaturesField = PackageManager::getStaticField<int>("GET_SIGNATURES");
+ auto providerInfo = packageManager.callMethod<ProviderInfo>("resolveContentProvider",
+ authority, 0);
+ if (!providerInfo.isValid()) {
+ qCWarning(lcIconEngineFontDownload, "Failed to resolve content provider");
+ return fontFamily;
+ }
+ const QString packageName = providerInfo.getField<QString>("packageName");
+ if (packageName != package) {
+ qCWarning(lcIconEngineFontDownload, "Mismatched provider package - expected '%s', got '%s'",
+ package.toUtf8().constData(), packageName.toUtf8().constData());
+ return fontFamily;
+ }
+ auto packageInfo = packageManager.callMethod<PackageInfo>("getPackageInfo",
+ package, signaturesField);
+ if (!packageInfo.isValid()) {
+ qCWarning(lcIconEngineFontDownload, "Failed to get package info with signature field %d",
+ signaturesField);
+ return fontFamily;
+ }
+ const auto signatures = packageInfo.getField<Signature[]>("signatures");
+ if (!signatures.isValid()) {
+ qCWarning(lcIconEngineFontDownload, "Failed to get signature array from package info");
+ return fontFamily;
+ }
+
+ // FontRequest wants a list of sets for the certificates
+ ArrayList outerList;
+ HashSet innerSet;
+ Q_ASSERT(outerList.isValid() && innerSet.isValid());
+
+ for (const auto &signature : signatures) {
+ const QJniArray<jbyte> byteArray = signature.callMethod<jbyte[]>("toByteArray");
+
+ // add takes an Object, not an Array
+ if (!innerSet.callMethod<jboolean>("add", byteArray.object<jobject>()))
+ qCWarning(lcIconEngineFontDownload, "Failed to add signature to set");
+ }
+ // Add the set to the list
+ if (!outerList.callMethod<jboolean>("add", innerSet.object()))
+ qCWarning(lcIconEngineFontDownload, "Failed to add set to certificate list");
+
+ // FontRequest constructor wants a List interface, not an ArrayList
+ FontRequest fontRequest(authority, package, query, outerList.object<List>());
+ if (!fontRequest.isValid()) {
+ qCWarning(lcIconEngineFontDownload, "Failed to create font request for '%s'",
+ query.toUtf8().constData());
+ return fontFamily;
+ }
+
+ // Call FontsContractCompat::fetchFonts with the FontRequest object
+ auto fontFamilyResult = FontsContractCompat::callStaticMethod<FontFamilyResult>(
+ "fetchFonts",
+ context,
+ CancellationSignal(nullptr),
+ fontRequest);
+ if (!fontFamilyResult.isValid()) {
+ qCWarning(lcIconEngineFontDownload, "Failed to fetch fonts for query '%s'",
+ query.toUtf8().constData());
+ return fontFamily;
+ }
+
+ enum class StatusCode {
+ OK = 0,
+ UNEXPECTED_DATA_PROVIDED = 1,
+ WRONG_CERTIFICATES = 2,
+ };
+
+ const StatusCode statusCode = fontFamilyResult.callMethod<StatusCode>("getStatusCode");
+ switch (statusCode) {
+ case StatusCode::OK:
+ break;
+ case StatusCode::UNEXPECTED_DATA_PROVIDED:
+ qCWarning(lcIconEngineFontDownload, "Provider returned unexpected data for query '%s'",
+ query.toUtf8().constData());
+ return fontFamily;
+ case StatusCode::WRONG_CERTIFICATES:
+ qCWarning(lcIconEngineFontDownload, "Wrong Certificates provided in query '%s'",
+ query.toUtf8().constData());
+ return fontFamily;
+ }
+
+ const auto fontInfos = fontFamilyResult.callMethod<FontInfo[]>("getFonts");
+ if (!fontInfos.isValid()) {
+ qCWarning(lcIconEngineFontDownload, "FontFamilyResult::getFonts returned null object for '%s'",
+ query.toUtf8().constData());
+ return fontFamily;
+ }
+
+ auto contentResolver = context.callMethod<ContentResolver>("getContentResolver");
+
+ for (QJniObject fontInfo : fontInfos) {
+ if (!fontInfo.isValid()) {
+ qCDebug(lcIconEngineFontDownload, "Received null-fontInfo object, skipping");
+ continue;
+ }
+ enum class ResultCode {
+ OK = 0,
+ FONT_NOT_FOUND = 1,
+ FONT_UNAVAILABLE = 2,
+ MALFORMED_QUERY = 3,
+ };
+ const ResultCode resultCode = fontInfo.callMethod<ResultCode>("getResultCode");
+ switch (resultCode) {
+ case ResultCode::OK:
+ break;
+ case ResultCode::FONT_NOT_FOUND:
+ qCWarning(lcIconEngineFontDownload, "Font '%s' could not be found",
+ query.toUtf8().constData());
+ return fontFamily;
+ case ResultCode::FONT_UNAVAILABLE:
+ qCWarning(lcIconEngineFontDownload, "Font '%s' is unavailable at",
+ query.toUtf8().constData());
+ return fontFamily;
+ case ResultCode::MALFORMED_QUERY:
+ qCWarning(lcIconEngineFontDownload, "Query string '%s' is malformed",
+ query.toUtf8().constData());
+ return fontFamily;
+ }
+ auto fontUri = fontInfo.callMethod<Uri>("getUri");
+ // in this case the Font URI is always a content scheme file, made
+ // so the app requesting it has permissions to open
+ auto fileDescriptor = contentResolver.callMethod<ParcelFileDescriptor>("openFileDescriptor",
+ fontUri, u"r"_s);
+ if (!fileDescriptor.isValid()) {
+ qCWarning(lcIconEngineFontDownload, "Font file '%s' not accessible",
+ fontUri.toString().toUtf8().constData());
+ continue;
+ }
+
+ int fd = fileDescriptor.callMethod<int>("detachFd");
+ QFile file;
+ file.open(fd, QFile::OpenModeFlag::ReadOnly, QFile::FileHandleFlag::AutoCloseHandle);
+ const QByteArray fontData = file.readAll();
+ qCDebug(lcIconEngineFontDownload) << "Font file read:" << fontData.size() << "bytes";
+ int fontId = QFontDatabase::addApplicationFontFromData(fontData);
+ loadedFamilies << QFontDatabase::applicationFontFamilies(fontId);
+ }
+ }
+
+ qCDebug(lcIconEngineFontDownload) << "Query '" << query << "' added families" << loadedFamilies;
+ if (!loadedFamilies.isEmpty())
+ fontFamily = loadedFamilies.first();
+ triedFonts[query] = fontFamily;
+ return fontFamily;
+}
+}
+
+QString QAndroidPlatformIconEngine::glyphs() const
+{
+ if (!QFontInfo(m_iconFont).exactMatch())
+ return {};
+
+ static constexpr std::pair<QLatin1StringView, QStringView> glyphMap[] = {
+ {"address-book-new"_L1, u"\ue0e0"},
+ {"application-exit"_L1, u"\ue5cd"},
+ {"appointment-new"_L1, u"\ue878"},
+ {"call-start"_L1, u"\ue0b0"},
+ {"call-stop"_L1, u"\ue0b1"},
+ {"contact-new"_L1, u"\uf22e"},
+ {"document-new"_L1, u"\ue89c"},
+ {"document-open"_L1, u"\ue2c8"},
+ {"document-open-recent"_L1, u"\ue4a7"},
+ {"document-page-setup"_L1, u"\uf88c"},
+ {"document-print"_L1, u"\ue8ad"},
+ {"document-print-preview"_L1, u"\uefb2"},
+ {"document-properties"_L1, u"\uf775"},
+ {"document-revert"_L1, u"\ue929"},
+ {"document-save"_L1, u"\ue161"},
+ {"document-save-as"_L1, u"\ueb60"},
+ {"document-send"_L1, u"\uf09b"},
+ {"edit-clear"_L1, u"\ue872"},
+ {"edit-copy"_L1, u"\ue14d"},
+ {"edit-cut"_L1, u"\ue14e"},
+ {"edit-delete"_L1, u"\ue14a"},
+ {"edit-find"_L1, u"\ue8b6"},
+ {"edit-find-replace"_L1, u"\ue881"},
+ {"edit-paste"_L1, u"\ue14f"},
+ {"edit-redo"_L1, u"\ue15a"},
+ {"edit-select-all"_L1, u"\ue162"},
+ {"edit-undo"_L1, u"\ue166"},
+ {"folder-new"_L1, u"\ue2cc"},
+ {"format-indent-less"_L1, u"\ue23d"},
+ {"format-indent-more"_L1, u"\ue23e"},
+ {"format-justify-center"_L1, u"\ue234"},
+ {"format-justify-fill"_L1, u"\ue235"},
+ {"format-justify-left"_L1, u"\ue236"},
+ {"format-justify-right"_L1, u"\ue237"},
+ {"format-text-direction-ltr"_L1, u"\ue247"},
+ {"format-text-direction-rtl"_L1, u"\ue248"},
+ {"format-text-bold"_L1, u"\ue238"},
+ {"format-text-italic"_L1, u"\ue23f"},
+ {"format-text-underline"_L1, u"\ue249"},
+ {"format-text-strikethrough"_L1, u"\ue246"},
+ {"go-bottom"_L1,u"\ue258"},
+ {"go-down"_L1,u"\uf1e3"},
+ {"go-first"_L1, u"\ue5dc"},
+ {"go-home"_L1, u"\ue88a"},
+ {"go-jump"_L1, u"\uf719"},
+ {"go-last"_L1, u"\ue5dd"},
+ {"go-next"_L1, u"\ue5c8"},
+ {"go-previous"_L1, u"\ue5c4"},
+ {"go-top"_L1, u"\ue25a"},
+ {"go-up"_L1, u"\uf1e0"},
+ {"help-about"_L1, u"\ue88e"},
+ {"help-contents"_L1, u"\ue8de"},
+ {"help-faq"_L1, u"\uf04c"},
+ {"insert-image"_L1, u"\ue43e"},
+ {"insert-link"_L1, u"\ue178"},
+ //{"insert-object"_L1, u"\u"},
+ {"insert-text"_L1, u"\uf827"},
+ {"list-add"_L1, u"\ue145"},
+ {"list-remove"_L1, u"\ue15b"},
+ {"mail-forward"_L1, u"\ue154"},
+ {"mail-mark-important"_L1, u"\ue937"},
+ //{"mail-mark-junk"_L1, u"\u"},
+ //{"mail-mark-notjunk"_L1, u"\u"},
+ {"mail-mark-read"_L1, u"\uf18c"},
+ {"mail-mark-unread"_L1, u"\ue9bc"},
+ {"mail-message-new"_L1, u"\ue3c9"},
+ {"mail-reply-all"_L1, u"\ue15f"},
+ {"mail-reply-sender"_L1, u"\ue15e"},
+ {"mail-send"_L1, u"\ue163"},
+ //{"mail-send-receive"_L1, u"\u"},
+ {"media-eject"_L1, u"\ue8fb"},
+ {"media-playback-pause"_L1, u"\ue034"},
+ {"media-playback-start"_L1, u"\ue037"},
+ {"media-playback-stop"_L1, u"\ue047"},
+ {"media-record"_L1, u"\uf679"},
+ {"media-seek-backward"_L1, u"\ue020"},
+ {"media-seek-forward"_L1, u"\ue01f"},
+ {"media-skip-backward"_L1, u"\ue045"},
+ {"media-skip-forward"_L1, u"\ue044"},
+ //{"object-flip-horizontal"_L1, u"\u"},
+ //{"object-flip-vertical"_L1, u"\u"},
+ {"object-rotate-left"_L1, u"\ue419"},
+ {"object-rotate-right"_L1, u"\ue41a"},
+ {"process-stop"_L1, u"\ue5c9"},
+ {"system-lock-screen"_L1, u"\ue897"},
+ {"system-log-out"_L1, u"\ue9ba"},
+ //{"system-run"_L1, u"\u"},
+ {"system-search"_L1, u"\uef70"},
+ {"system-reboot"_L1, u"\uf053"},
+ {"system-shutdown"_L1, u"\ue8ac"},
+ {"tools-check-spelling"_L1, u"\ue8ce"},
+ {"view-fullscreen"_L1, u"\ue5d0"},
+ {"view-refresh"_L1, u"\ue5d5"},
+ {"view-restore"_L1, u"\uf1cf"},
+ {"view-sort-ascending"_L1, u"\ue25a"},
+ {"view-sort-descending"_L1, u"\ue258"},
+ {"window-close"_L1, u"\ue5cd"},
+ {"window-new"_L1, u"\uf710"},
+ {"zoom-fit-best"_L1, u"\uea10"},
+ {"zoom-in"_L1, u"\ue8ff"},
+ {"zoom-original"_L1, u"\ue5d1"},
+ {"zoom-out"_L1, u"\ue900"},
+ {"process-working"_L1, u"\uef64"},
+ {"accessories-calculator"_L1, u"\uea5f"},
+ {"accessories-character-map"_L1, u"\uf8a3"},
+ {"accessories-dictionary"_L1, u"\uf539"},
+ {"accessories-text-editor"_L1, u"\ue262"},
+ {"help-browser"_L1, u"\ue887"},
+ {"multimedia-volume-control"_L1, u"\ue050"},
+ {"preferences-desktop-accessibility"_L1, u"\uf05d"},
+ {"preferences-desktop-font"_L1, u"\ue165"},
+ {"preferences-desktop-keyboard"_L1, u"\ue312"},
+ //{"preferences-desktop-locale"_L1, u"\u"},
+ {"preferences-desktop-multimedia"_L1, u"\uea75"},
+ //{"preferences-desktop-screensaver"_L1, u"\u"},
+ {"preferences-desktop-theme"_L1, u"\uf560"},
+ {"preferences-desktop-wallpaper"_L1, u"\ue1bc"},
+ {"system-file-manager"_L1, u"\ue2c7"},
+ {"system-software-install"_L1, u"\ueb71"},
+ {"system-software-update"_L1, u"\ue8d7"},
+ {"utilities-system-monitor"_L1, u"\uef5b"},
+ {"utilities-terminal"_L1, u"\ueb8e"},
+ //{"applications-accessories"_L1, u"\u"},
+ {"applications-development"_L1, u"\ue720"},
+ {"applications-engineering"_L1, u"\uea3d"},
+ {"applications-games"_L1, u"\uf135"},
+ //{"applications-graphics"_L1, u"\u"},
+ {"applications-internet"_L1, u"\ue80b"},
+ {"applications-multimedia"_L1, u"\uf06a"},
+ //{"applications-office"_L1, u"\u"},
+ //{"applications-other"_L1, u"\u"},
+ {"applications-science"_L1, u"\uea4b"},
+ //{"applications-system"_L1, u"\u"},
+ //{"applications-utilities"_L1, u"\u"},
+ {"preferences-desktop"_L1, u"\ueb97"},
+ //{"preferences-desktop-peripherals"_L1, u"\u"},
+ {"preferences-desktop-personal"_L1, u"\uf835"},
+ //{"preferences-other"_L1, u"\u"},
+ {"preferences-system"_L1, u"\ue8b8"},
+ {"preferences-system-network"_L1, u"\ue894"},
+ {"system-help"_L1, u"\ue887"},
+ //{"audio-card"_L1, u"\u"},
+ {"audio-input-microphone"_L1, u"\ue029"},
+ {"battery"_L1, u"\ue1a4"},
+ {"camera-photo"_L1, u"\ue412"},
+ {"camera-video"_L1, u"\ue04b"},
+ {"camera-web"_L1, u"\uf7a6"},
+ {"computer"_L1, u"\ue30a"},
+ {"drive-harddisk"_L1, u"\uf80e"},
+ {"drive-optical"_L1, u"\ue019"}, // same as media-optical
+ //{"drive-removable-media"_L1, u"\u"},
+ {"input-gaming"_L1, u"\uf5ee"},
+ {"input-keyboard"_L1, u"\ue312"},
+ {"input-mouse"_L1, u"\ue323"},
+ //{"input-tablet"_L1, u"\u"},
+ //{"media-flash"_L1, u"\u"},
+ //{"media-floppy"_L1, u"\u"},
+ {"media-optical"_L1, u"\ue019"},
+ //{"media-tape"_L1, u"\u"},
+ //{"modem"_L1, u"\u"},
+ //{"multimedia-player"_L1, u"\u"},
+ //{"network-wired"_L1, u"\u"},
+ {"network-wireless"_L1, u"\ue63e"},
+ //{"pda"_L1, u"\u"},
+ {"phone"_L1, u"\ue32c"},
+ {"printer"_L1, u"\ue8ad"},
+ {"scanner"_L1, u"\ue329"},
+ {"video-display"_L1, u"\uf06a"},
+ //{"emblem-default"_L1, u"\u"},
+ {"emblem-documents"_L1, u"\ue873"},
+ {"emblem-downloads"_L1, u"\uf090"},
+ {"emblem-favorite"_L1, u"\uf090"},
+ {"emblem-important"_L1, u"\ue645"},
+ {"emblem-mail"_L1, u"\ue158"},
+ {"emblem-photos"_L1, u"\ue413"},
+ //{"emblem-readonly"_L1, u"\u"},
+ {"emblem-shared"_L1, u"\ue413"},
+ //{"emblem-symbolic-link"_L1, u"\u"},
+ //{"emblem-synchronized"_L1, u"\u"},
+ {"emblem-system"_L1, u"\ue8b8"},
+ //{"emblem-unreadable"_L1, u"\u"},
+ {"folder"_L1, u"\ue2c7"},
+ //{"folder-remote"_L1, u"\u"},
+ {"network-server"_L1, u"\ue875"},
+ {"network-workgroup"_L1, u"\ue1a0"},
+ {"start-here"_L1, u"\ue089"},
+ {"user-bookmarks"_L1, u"\ue98b"},
+ {"user-desktop"_L1, u"\ue30a"},
+ {"user-home"_L1, u"\ue88a"},
+ {"user-trash"_L1, u"\ue872"},
+ {"appointment-missed"_L1, u"\ue615"},
+ {"appointment-soon"_L1, u"\uf540"},
+ {"audio-volume-high"_L1, u"\ue050"},
+ {"audio-volume-low"_L1, u"\ue04d"},
+ //{"audio-volume-medium"_L1, u"\u"},
+ {"audio-volume-muted"_L1, u"\ue04e"},
+ {"battery-caution"_L1, u"\ue19c"},
+ {"battery-low"_L1, u"\uf147"},
+ {"dialog-error"_L1, u"\ue000"},
+ {"dialog-information"_L1, u"\ue88e"},
+ {"dialog-password"_L1, u"\uf042"},
+ {"dialog-question"_L1, u"\ueb8b"},
+ {"dialog-warning"_L1, u"\ue002"},
+ {"folder-drag-accept"_L1, u"\ue9a3"},
+ {"folder-open"_L1, u"\ue2c8"},
+ {"folder-visiting"_L1, u"\ue8a7"},
+ {"image-loading"_L1, u"\ue41a"},
+ {"image-missing"_L1, u"\ue3ad"},
+ {"mail-attachment"_L1, u"\ue2bc"},
+ {"mail-unread"_L1, u"\uf18a"},
+ {"mail-read"_L1, u"\uf18c"},
+ //{"mail-replied"_L1, u"\u"},
+ //{"mail-signed"_L1, u"\u"},
+ //{"mail-signed-verified"_L1, u"\u"},
+ {"media-playlist-repeat"_L1, u"\ue040"},
+ {"media-playlist-shuffle"_L1, u"\ue043"},
+ {"network-error"_L1, u"\uead9"},
+ {"network-idle"_L1, u"\ue51f"},
+ {"network-offline"_L1, u"\uf239"},
+ {"network-receive"_L1, u"\ue2c0"},
+ {"network-transmit"_L1, u"\ue2c3"},
+ {"network-transmit-receive"_L1, u"\uea18"},
+ {"printer-error"_L1, u"\uf7a0"},
+ {"printer-printing"_L1, u"\uf7a1"},
+ {"security-high"_L1, u"\ue32a"},
+ {"security-medium"_L1, u"\ue9e0"},
+ {"security-low"_L1, u"\uf012"},
+ {"software-update-available"_L1, u"\ue923"},
+ {"software-update-urgent"_L1, u"\uf05a"},
+ {"sync-error"_L1, u"\ue629"},
+ {"sync-synchronizing"_L1, u"\ue627"},
+ //{"task-due"_L1, u"\u"},
+ //{"task-past-due"_L1, u"\u"},
+ {"user-available"_L1, u"\uf565"},
+ {"user-away"_L1, u"\ue510"},
+ //{"user-idle"_L1, u"\u"},
+ {"user-offline"_L1, u"\uf7b3"},
+ {"user-trash-full"_L1, u"\ue872"}, //delete
+ //{"user-trash-full"_L1, u"\ue92b"}, //delete_forever
+ {"weather-clear"_L1, u"\uf157"},
+ {"weather-clear-night"_L1, u"\uf159"},
+ {"weather-few-clouds"_L1, u"\uf172"},
+ {"weather-few-clouds-night"_L1, u"\uf174"},
+ {"weather-fog"_L1, u"\ue818"},
+ //{"weather-overcast"_L1, u"\u"},
+ {"weather-severe-alert"_L1, u"\ue002"}, //warning
+ //{"weather-severe-alert"_L1, u"\uebd3"},//severe_cold
+ {"weather-showers"_L1, u"\uf176"},
+ //{"weather-showers-scattered"_L1, u"\u"},
+ {"weather-snow"_L1, u"\ue80f"}, //snowing
+ //{"weather-snow"_L1, u"\ue2cd"}, //weather_snowy
+ //{"weather-snow"_L1, u"\ue810"},//cloudy_snowing
+ {"weather-storm"_L1, u"\uf070"},
+ };
+
+ const auto it = std::find_if(std::begin(glyphMap), std::end(glyphMap), [this](const auto &c){
+ return c.first == m_iconName;
+ });
+ return it != std::end(glyphMap) ? it->second.toString()
+ : (m_iconName.length() == 1 ? m_iconName : QString());
+}
+
+QAndroidPlatformIconEngine::QAndroidPlatformIconEngine(const QString &iconName)
+ : m_iconName(iconName)
+ , m_glyphs(glyphs())
+{
+ QString fontFamily;
+ // The MaterialIcons-*.ttf and MaterialSymbols* font files are available from
+ // https://github.com/google/material-design-icons/tree/master. If one of them is
+ // packaged as a resource with the application, then we use it. We prioritize
+ // a variable font.
+ const QStringList fontCandidates = {
+ "MaterialSymbolsOutlined[FILL,GRAD,opsz,wght].ttf",
+ "MaterialSymbolsRounded[FILL,GRAD,opsz,wght].ttf",
+ "MaterialSymbolsSharp[FILL,GRAD,opsz,wght].ttf",
+ "MaterialIcons-Regular.ttf",
+ "MaterialIconsOutlined-Regular.otf",
+ "MaterialIconsRound-Regular.otf",
+ "MaterialIconsSharp-Regular.otf",
+ "MaterialIconsTwoTone-Regular.otf",
+ };
+ for (const auto &fontCandidate : fontCandidates) {
+ fontFamily = FontProvider::fetchFont(u":/qt-project.org/icons/%1"_s.arg(fontCandidate));
+ if (!fontFamily.isEmpty())
+ break;
+ }
+
+ // Otherwise we try to download the Outlined version of Material Symbols
+ const QString key = qEnvironmentVariable("QT_GOOGLE_FONTS_KEY");
+ if (fontFamily.isEmpty() && !key.isEmpty())
+ fontFamily = FontProvider::fetchFont(u"key=%1&name=Material+Symbols+Outlined"_s.arg(key));
+
+ // last resort - use any Material Icons
+ if (fontFamily.isEmpty())
+ fontFamily = u"Material Icons"_s;
+ m_iconFont = QFont(fontFamily);
+}
+
+QAndroidPlatformIconEngine::~QAndroidPlatformIconEngine()
+{}
+
+QIconEngine *QAndroidPlatformIconEngine::clone() const
+{
+ return new QAndroidPlatformIconEngine(m_iconName);
+}
+
+QString QAndroidPlatformIconEngine::key() const
+{
+ return u"QAndroidPlatformIconEngine"_s;
+}
+
+QString QAndroidPlatformIconEngine::iconName()
+{
+ return m_iconName;
+}
+
+bool QAndroidPlatformIconEngine::isNull()
+{
+ if (m_glyphs.isEmpty())
+ return true;
+ const QChar c0 = m_glyphs.at(0);
+ const QFontMetrics fontMetrics(m_iconFont);
+ if (c0.category() == QChar::Other_Surrogate && m_glyphs.size() > 1)
+ return !fontMetrics.inFontUcs4(QChar::surrogateToUcs4(c0, m_glyphs.at(1)));
+ return !fontMetrics.inFont(c0);
+}
+
+QList<QSize> QAndroidPlatformIconEngine::availableSizes(QIcon::Mode, QIcon::State)
+{
+ return {{16, 16}, {24, 24}, {48, 48}, {128, 128}};
+}
+
+QSize QAndroidPlatformIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state)
+{
+ return QIconEngine::actualSize(size, mode, state);
+}
+
+QPixmap QAndroidPlatformIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
+{
+ return scaledPixmap(size, mode, state, 1.0);
+}
+
+QPixmap QAndroidPlatformIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
+{
+ const quint64 cacheKey = calculateCacheKey(mode, state);
+ if (cacheKey != m_cacheKey || m_pixmap.size() != size || m_pixmap.devicePixelRatio() != scale) {
+ m_pixmap = QPixmap(size * scale);
+ m_pixmap.fill(Qt::transparent);
+ m_pixmap.setDevicePixelRatio(scale);
+
+ QPainter painter(&m_pixmap);
+ paint(&painter, QRect(QPoint(), size), mode, state);
+
+ m_cacheKey = cacheKey;
+ }
+
+ return m_pixmap;
+}
+
+void QAndroidPlatformIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
+{
+ Q_UNUSED(state);
+
+ painter->save();
+ QFont renderFont(m_iconFont);
+ renderFont.setPixelSize(rect.height());
+ painter->setFont(renderFont);
+
+ QPalette palette;
+ switch (mode) {
+ case QIcon::Active:
+ painter->setPen(palette.color(QPalette::Active, QPalette::Text));
+ break;
+ case QIcon::Normal:
+ painter->setPen(palette.color(QPalette::Active, QPalette::Text));
+ break;
+ case QIcon::Disabled:
+ painter->setPen(palette.color(QPalette::Disabled, QPalette::Text));
+ break;
+ case QIcon::Selected:
+ painter->setPen(palette.color(QPalette::Active, QPalette::HighlightedText));
+ break;
+ }
+
+ painter->drawText(rect, Qt::AlignCenter, m_glyphs);
+ painter->restore();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformiconengine.h b/src/plugins/platforms/android/qandroidplatformiconengine.h
new file mode 100644
index 0000000000..cac54481d9
--- /dev/null
+++ b/src/plugins/platforms/android/qandroidplatformiconengine.h
@@ -0,0 +1,44 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QANDROIDPLATFORMICONENGINE_H
+#define QANDROIDPLATFORMICONENGINE_H
+
+#include <QtGui/qiconengine.h>
+#include <QtGui/qfont.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidPlatformIconEngine : public QIconEngine
+{
+public:
+ QAndroidPlatformIconEngine(const QString &iconName);
+ ~QAndroidPlatformIconEngine();
+ QIconEngine *clone() const override;
+ QString key() const override;
+ QString iconName() override;
+ bool isNull() override;
+
+ QList<QSize> availableSizes(QIcon::Mode, QIcon::State) override;
+ QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
+ QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
+ QPixmap scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale) override;
+ void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override;
+
+private:
+ static constexpr quint64 calculateCacheKey(QIcon::Mode mode, QIcon::State state)
+ {
+ return (quint64(mode) << 32) | state;
+ }
+ QString glyphs() const;
+
+ const QString m_iconName;
+ QFont m_iconFont;
+ const QString m_glyphs;
+ mutable QPixmap m_pixmap;
+ mutable quint64 m_cacheKey = {};
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDPLATFORMICONENGINE_H
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp
index 9f0b1c8b2f..6efd3fc631 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.cpp
+++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp
@@ -9,7 +9,6 @@
#include "qabstracteventdispatcher.h"
#include "qandroideventdispatcher.h"
#include "qandroidplatformaccessibility.h"
-#include "qandroidplatformbackingstore.h"
#include "qandroidplatformclipboard.h"
#include "qandroidplatformfontdatabase.h"
#include "qandroidplatformforeignwindow.h"
@@ -29,6 +28,7 @@
#include <QtGui/private/qeglpbuffer_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qoffscreensurface_p.h>
+#include <QtGui/private/qrhibackingstore_p.h>
#include <qpa/qplatformoffscreensurface.h>
#include <qpa/qplatformwindow.h>
#include <qpa/qwindowsysteminterface.h>
@@ -54,36 +54,44 @@ Qt::ScreenOrientation QAndroidPlatformIntegration::m_orientation = Qt::PrimaryOr
Qt::ScreenOrientation QAndroidPlatformIntegration::m_nativeOrientation = Qt::PrimaryOrientation;
bool QAndroidPlatformIntegration::m_showPasswordEnabled = false;
-static bool m_running = false;
Q_DECLARE_JNI_CLASS(QtNative, "org/qtproject/qt/android/QtNative")
+Q_DECLARE_JNI_CLASS(QtDisplayManager, "org/qtproject/qt/android/QtDisplayManager")
Q_DECLARE_JNI_CLASS(Display, "android/view/Display")
-Q_DECLARE_JNI_TYPE(List, "Ljava/util/List;")
+Q_DECLARE_JNI_CLASS(List, "java/util/List")
namespace {
QAndroidPlatformScreen* createScreenForDisplayId(int displayId)
{
- const QJniObject display = QJniObject::callStaticObjectMethod<QtJniTypes::Display>(
- QtJniTypes::className<QtJniTypes::QtNative>(),
- "getDisplay",
- displayId);
+ const QJniObject display = QtJniTypes::QtDisplayManager::callStaticMethod<QtJniTypes::Display>(
+ "getDisplay", QtAndroidPrivate::context(), displayId);
if (!display.isValid())
return nullptr;
return new QAndroidPlatformScreen(display);
}
+static bool isValidAndroidContextForRendering()
+{
+ return QtAndroid::isQtApplication() ? QtAndroidPrivate::activity().isValid()
+ : QtAndroidPrivate::context().isValid();
+}
+
} // anonymous namespace
void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteArray &resource)
{
if (resource=="JavaVM")
return QtAndroid::javaVM();
- if (resource == "QtActivity")
- return QtAndroid::activity();
- if (resource == "QtService")
- return QtAndroid::service();
+ if (resource == "QtActivity") {
+ extern Q_CORE_EXPORT jobject qt_androidActivity();
+ return qt_androidActivity();
+ }
+ if (resource == "QtService") {
+ extern Q_CORE_EXPORT jobject qt_androidService();
+ return qt_androidService();
+ }
if (resource == "AndroidStyleData") {
if (m_androidStyle) {
if (m_androidStyle->m_styleData.isEmpty())
@@ -156,10 +164,6 @@ void QAndroidPlatformNativeInterface::customEvent(QEvent *event)
api->accessibility()->setActive(QtAndroidAccessibility::isActive());
#endif // QT_CONFIG(accessibility)
- if (!m_running) {
- m_running = true;
- QtAndroid::notifyQtAndroidPluginRunning(m_running);
- }
api->flushPendingUpdates();
}
@@ -183,12 +187,10 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &para
if (Q_UNLIKELY(!eglBindAPI(EGL_OPENGL_ES_API)))
qFatal("Could not bind GL_ES API");
- m_primaryDisplayId = QJniObject::getStaticField<jint>(
- QtJniTypes::className<QtJniTypes::Display>(), "DEFAULT_DISPLAY");
-
- const QJniObject nativeDisplaysList = QJniObject::callStaticObjectMethod<QtJniTypes::List>(
- QtJniTypes::className<QtJniTypes::QtNative>(),
- "getAvailableDisplays");
+ using namespace QtJniTypes;
+ m_primaryDisplayId = Display::getStaticField<jint>("DEFAULT_DISPLAY");
+ const QJniObject nativeDisplaysList = QtDisplayManager::callStaticMethod<List>(
+ "getAvailableDisplays", QtAndroidPrivate::context());
const int numberOfAvailableDisplays = nativeDisplaysList.callMethod<jint>("size");
for (int i = 0; i < numberOfAvailableDisplays; ++i) {
@@ -227,9 +229,9 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &para
m_accessibility = new QAndroidPlatformAccessibility();
#endif // QT_CONFIG(accessibility)
- QJniObject javaActivity(QtAndroid::activity());
+ QJniObject javaActivity = QtAndroidPrivate::activity();
if (!javaActivity.isValid())
- javaActivity = QtAndroid::service();
+ javaActivity = QtAndroidPrivate::service();
if (javaActivity.isValid()) {
QJniObject resources = javaActivity.callObjectMethod("getResources", "()Landroid/content/res/Resources;");
@@ -269,6 +271,10 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &para
maxTouchPoints,
0);
QWindowSystemInterface::registerInputDevice(m_touchDevice);
+
+ QWindowSystemInterface::registerInputDevice(
+ new QInputDevice("Virtual keyboard"_L1, 0, QInputDevice::DeviceType::Keyboard,
+ {}, qApp));
}
auto contentResolver = javaActivity.callObjectMethod("getContentResolver", "()Landroid/content/ContentResolver;");
@@ -304,11 +310,11 @@ static bool needsBasicRenderloopWorkaround()
void QAndroidPlatformIntegration::initialize()
{
- const QString icStr = QPlatformInputContextFactory::requested();
- if (icStr.isNull())
+ const auto icStrs = QPlatformInputContextFactory::requested();
+ if (icStrs.isEmpty())
m_inputContext.reset(new QAndroidInputContext);
else
- m_inputContext.reset(QPlatformInputContextFactory::create(icStr));
+ m_inputContext.reset(QPlatformInputContextFactory::create(icStrs));
}
bool QAndroidPlatformIntegration::hasCapability(Capability cap) const
@@ -316,13 +322,19 @@ bool QAndroidPlatformIntegration::hasCapability(Capability cap) const
switch (cap) {
case ApplicationState: return true;
case ThreadedPixmaps: return true;
- case NativeWidgets: return QtAndroid::activity();
- case OpenGL: return QtAndroid::activity();
- case ForeignWindows: return QtAndroid::activity();
- case ThreadedOpenGL: return !needsBasicRenderloopWorkaround() && QtAndroid::activity();
- case RasterGLSurface: return QtAndroid::activity();
+ case NativeWidgets: return QtAndroidPrivate::activity().isValid();
+ case OpenGL:
+ return isValidAndroidContextForRendering();
+ case ForeignWindows:
+ return isValidAndroidContextForRendering();
+ case ThreadedOpenGL:
+ return !needsBasicRenderloopWorkaround() && isValidAndroidContextForRendering();
+ case RasterGLSurface: return QtAndroidPrivate::activity().isValid();
case TopStackedNativeChildWindows: return false;
case MaximizeUsingFullscreenGeometry: return true;
+ // FIXME QTBUG-118849 - we do not implement grabWindow() anymore, calling it will return
+ // a null QPixmap also for raster windows - for OpenGL windows this was always true
+ case ScreenWindowGrabbing: return false;
default:
return QPlatformIntegration::hasCapability(cap);
}
@@ -330,15 +342,15 @@ bool QAndroidPlatformIntegration::hasCapability(Capability cap) const
QPlatformBackingStore *QAndroidPlatformIntegration::createPlatformBackingStore(QWindow *window) const
{
- if (!QtAndroid::activity())
+ if (!QtAndroidPrivate::activity().isValid())
return nullptr;
- return new QAndroidPlatformBackingStore(window);
+ return new QRhiBackingStore(window);
}
QPlatformOpenGLContext *QAndroidPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
- if (!QtAndroid::activity())
+ if (!isValidAndroidContextForRendering())
return nullptr;
QSurfaceFormat format(context->format());
format.setAlphaBufferSize(8);
@@ -356,7 +368,7 @@ QOpenGLContext *QAndroidPlatformIntegration::createOpenGLContext(EGLContext cont
QPlatformOffscreenSurface *QAndroidPlatformIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
{
- if (!QtAndroid::activity())
+ if (!QtAndroidPrivate::activity().isValid())
return nullptr;
QSurfaceFormat format(surface->requestedFormat());
@@ -370,7 +382,7 @@ QPlatformOffscreenSurface *QAndroidPlatformIntegration::createPlatformOffscreenS
QOffscreenSurface *QAndroidPlatformIntegration::createOffscreenSurface(ANativeWindow *nativeSurface) const
{
- if (!QtAndroid::activity() || !nativeSurface)
+ if (!QtAndroidPrivate::activity().isValid() || !nativeSurface)
return nullptr;
auto *surface = new QOffscreenSurface;
@@ -381,7 +393,7 @@ QOffscreenSurface *QAndroidPlatformIntegration::createOffscreenSurface(ANativeWi
QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *window) const
{
- if (!QtAndroid::activity())
+ if (!isValidAndroidContextForRendering())
return nullptr;
#if QT_CONFIG(vulkan)
@@ -534,7 +546,7 @@ void QAndroidPlatformIntegration::setScreenSize(int width, int height)
Qt::ColorScheme QAndroidPlatformIntegration::m_colorScheme = Qt::ColorScheme::Light;
-void QAndroidPlatformIntegration::setColorScheme(Qt::ColorScheme colorScheme)
+void QAndroidPlatformIntegration::updateColorScheme(Qt::ColorScheme colorScheme)
{
if (m_colorScheme == colorScheme)
return;
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.h b/src/plugins/platforms/android/qandroidplatformintegration.h
index 5f1126fafc..b7bfb58d1d 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.h
+++ b/src/plugins/platforms/android/qandroidplatformintegration.h
@@ -110,7 +110,7 @@ public:
void flushPendingUpdates();
- static void setColorScheme(Qt::ColorScheme colorScheme);
+ static void updateColorScheme(Qt::ColorScheme colorScheme);
static Qt::ColorScheme colorScheme() { return m_colorScheme; }
#if QT_CONFIG(vulkan)
QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) const override;
diff --git a/src/plugins/platforms/android/qandroidplatformmenu.cpp b/src/plugins/platforms/android/qandroidplatformmenu.cpp
index 4ddd6ea29a..e59fd2089d 100644
--- a/src/plugins/platforms/android/qandroidplatformmenu.cpp
+++ b/src/plugins/platforms/android/qandroidplatformmenu.cpp
@@ -119,7 +119,7 @@ void QAndroidPlatformMenu::showPopup(const QWindow *parentWindow, const QRect &t
Q_UNUSED(parentWindow);
Q_UNUSED(item);
setVisible(true);
- QtAndroidMenu::showContextMenu(this, targetRect, QJniEnvironment().jniEnv());
+ QtAndroidMenu::showContextMenu(this, targetRect);
}
QPlatformMenuItem *QAndroidPlatformMenu::menuItemForTag(quintptr tag) const
diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp
index c1ec2fbdd6..13d14eb391 100644
--- a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp
+++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp
@@ -24,41 +24,19 @@ QT_BEGIN_NAMESPACE
QAndroidPlatformOpenGLWindow::QAndroidPlatformOpenGLWindow(QWindow *window, EGLDisplay display)
:QAndroidPlatformWindow(window), m_eglDisplay(display)
{
+ if (window->surfaceType() == QSurface::RasterSurface)
+ window->setSurfaceType(QSurface::OpenGLSurface);
}
QAndroidPlatformOpenGLWindow::~QAndroidPlatformOpenGLWindow()
{
m_surfaceWaitCondition.wakeOne();
lockSurface();
- if (m_nativeSurfaceId != -1)
- QtAndroid::destroySurface(m_nativeSurfaceId);
+ destroySurface();
clearEgl();
unlockSurface();
}
-void QAndroidPlatformOpenGLWindow::repaint(const QRegion &region)
-{
- // This is only for real raster top-level windows. Stop in all other cases.
- if ((window()->surfaceType() == QSurface::RasterGLSurface && qt_window_private(window())->compositing)
- || window()->surfaceType() == QSurface::OpenGLSurface
- || QAndroidPlatformWindow::parent())
- return;
-
- QRect currentGeometry = geometry();
-
- QRect dirtyClient = region.boundingRect();
- QRect dirtyRegion(currentGeometry.left() + dirtyClient.left(),
- currentGeometry.top() + dirtyClient.top(),
- dirtyClient.width(),
- dirtyClient.height());
- QRect mOldGeometryLocal = m_oldGeometry;
- m_oldGeometry = currentGeometry;
- // If this is a move, redraw the previous location
- if (mOldGeometryLocal != currentGeometry)
- platformScreen()->setDirty(mOldGeometryLocal);
- platformScreen()->setDirty(dirtyRegion);
-}
-
void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect)
{
if (rect == geometry())
@@ -67,8 +45,9 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect)
m_oldGeometry = geometry();
QAndroidPlatformWindow::setGeometry(rect);
- if (m_nativeSurfaceId != -1)
- QtAndroid::setSurfaceGeometry(m_nativeSurfaceId, rect);
+
+
+ setNativeGeometry(rect);
QRect availableGeometry = screen()->availableGeometry();
if (rect.width() > 0
@@ -77,25 +56,23 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect)
&& availableGeometry.height() > 0) {
QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), rect.size()));
}
-
- if (rect.topLeft() != m_oldGeometry.topLeft())
- repaint(QRegion(rect));
}
EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config)
{
- if (QAndroidEventDispatcherStopper::stopped() || QGuiApplication::applicationState() == Qt::ApplicationSuspended)
+ if (QAndroidEventDispatcherStopper::stopped() ||
+ QGuiApplication::applicationState() == Qt::ApplicationSuspended) {
return m_eglSurface;
+ }
QMutexLocker lock(&m_surfaceMutex);
- if (m_nativeSurfaceId == -1) {
+ if (!m_surfaceCreated) {
AndroidDeadlockProtector protector;
if (!protector.acquire())
return m_eglSurface;
- const bool windowStaysOnTop = bool(window()->flags() & Qt::WindowStaysOnTopHint);
- m_nativeSurfaceId = QtAndroid::createSurface(this, geometry(), windowStaysOnTop, 32);
+ createSurface();
m_surfaceWaitCondition.wait(&m_surfaceMutex);
}
@@ -110,7 +87,7 @@ EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config)
bool QAndroidPlatformOpenGLWindow::checkNativeSurface(EGLConfig config)
{
QMutexLocker lock(&m_surfaceMutex);
- if (m_nativeSurfaceId == -1 || !m_androidSurfaceObject.isValid())
+ if (!m_surfaceCreated || !m_androidSurfaceObject.isValid())
return false; // makeCurrent is NOT needed.
createEgl(config);
@@ -127,10 +104,7 @@ void QAndroidPlatformOpenGLWindow::applicationStateChanged(Qt::ApplicationState
QAndroidPlatformWindow::applicationStateChanged(state);
if (state <= Qt::ApplicationHidden) {
lockSurface();
- if (m_nativeSurfaceId != -1) {
- QtAndroid::destroySurface(m_nativeSurfaceId);
- m_nativeSurfaceId = -1;
- }
+ destroySurface();
clearEgl();
unlockSurface();
}
@@ -173,24 +147,4 @@ void QAndroidPlatformOpenGLWindow::clearEgl()
}
}
-void QAndroidPlatformOpenGLWindow::surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h)
-{
- Q_UNUSED(jniEnv);
- Q_UNUSED(w);
- Q_UNUSED(h);
-
- lockSurface();
- m_androidSurfaceObject = surface;
- if (surface) // wait until we have a valid surface to draw into
- m_surfaceWaitCondition.wakeOne();
- unlockSurface();
-
- if (surface) {
- // repaint the window, when we have a valid surface
- QRect availableGeometry = screen()->availableGeometry();
- if (geometry().width() > 0 && geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0)
- QWindowSystemInterface::handleExposeEvent(window(), QRegion(QRect(QPoint(), geometry().size())));
- }
-}
-
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.h b/src/plugins/platforms/android/qandroidplatformopenglwindow.h
index 8c31368b65..c1ae57fe85 100644
--- a/src/plugins/platforms/android/qandroidplatformopenglwindow.h
+++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.h
@@ -5,7 +5,6 @@
#ifndef QANDROIDPLATFORMOPENGLWINDOW_H
#define QANDROIDPLATFORMOPENGLWINDOW_H
-#include "androidsurfaceclient.h"
#include "qandroidplatformwindow.h"
#include <QWaitCondition>
@@ -16,7 +15,7 @@
QT_BEGIN_NAMESPACE
-class QAndroidPlatformOpenGLWindow : public QAndroidPlatformWindow, public AndroidSurfaceClient
+class QAndroidPlatformOpenGLWindow : public QAndroidPlatformWindow
{
public:
explicit QAndroidPlatformOpenGLWindow(QWindow *window, EGLDisplay display);
@@ -30,10 +29,7 @@ public:
void applicationStateChanged(Qt::ApplicationState) override;
- void repaint(const QRegion &region) override;
-
protected:
- void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h) override;
void createEgl(EGLConfig config);
void clearEgl();
@@ -42,9 +38,6 @@ private:
EGLSurface m_eglSurface = EGL_NO_SURFACE;
EGLNativeWindowType m_nativeWindow = nullptr;
- int m_nativeSurfaceId = -1;
- QJniObject m_androidSurfaceObject;
- QWaitCondition m_surfaceWaitCondition;
QSurfaceFormat m_format;
QRect m_oldGeometry;
};
diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp
index b2fa2ed3e5..9e20b7ac4b 100644
--- a/src/plugins/platforms/android/qandroidplatformscreen.cpp
+++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp
@@ -8,7 +8,6 @@
#include <qpa/qwindowsysteminterface.h>
#include "qandroidplatformscreen.h"
-#include "qandroidplatformbackingstore.h"
#include "qandroidplatformintegration.h"
#include "qandroidplatformwindow.h"
#include "androidjnimain.h"
@@ -53,8 +52,13 @@ private:
#endif
Q_DECLARE_JNI_CLASS(Display, "android/view/Display")
+Q_DECLARE_JNI_CLASS(DisplayMetrics, "android/util/DisplayMetrics")
+Q_DECLARE_JNI_CLASS(Resources, "android/content/res/Resources")
+Q_DECLARE_JNI_CLASS(Size, "android/util/Size")
+Q_DECLARE_JNI_CLASS(QtNative, "org/qtproject/qt/android/QtNative")
+Q_DECLARE_JNI_CLASS(QtDisplayManager, "org/qtproject/qt/android/QtDisplayManager")
-Q_DECLARE_JNI_TYPE(DisplayMode, "Landroid/view/Display$Mode;")
+Q_DECLARE_JNI_CLASS(DisplayMode, "android/view/Display$Mode")
QAndroidPlatformScreen::QAndroidPlatformScreen(const QJniObject &displayObject)
: QObject(), QPlatformScreen()
@@ -79,14 +83,33 @@ QAndroidPlatformScreen::QAndroidPlatformScreen(const QJniObject &displayObject)
if (!displayObject.isValid())
return;
- m_size = QSize(displayObject.callMethod<jint>("getWidth"), displayObject.callMethod<jint>("getHeight"));
m_name = displayObject.callObjectMethod<jstring>("getName").toString();
m_refreshRate = displayObject.callMethod<jfloat>("getRefreshRate");
m_displayId = displayObject.callMethod<jint>("getDisplayId");
+ const QJniObject context = QNativeInterface::QAndroidApplication::context();
+ const auto displayContext = context.callMethod<QtJniTypes::Context>("createDisplayContext",
+ displayObject.object<QtJniTypes::Display>());
+
+ const auto sizeObj = QtJniTypes::QtDisplayManager::callStaticMethod<QtJniTypes::Size>(
+ "getDisplaySize", displayContext,
+ displayObject.object<QtJniTypes::Display>());
+ m_size = QSize(sizeObj.callMethod<int>("getWidth"), sizeObj.callMethod<int>("getHeight"));
+
+ const auto resources = displayContext.callMethod<QtJniTypes::Resources>("getResources");
+ const auto metrics = resources.callMethod<QtJniTypes::DisplayMetrics>("getDisplayMetrics");
+ const float xdpi = metrics.getField<float>("xdpi");
+ const float ydpi = metrics.getField<float>("ydpi");
+
+ // Potentially densityDpi could be used instead of xpdi/ydpi to do the calculation,
+ // but the results are not consistent with devices specs.
+ // (https://issuetracker.google.com/issues/194120500)
+ m_physicalSize.setWidth(qRound(m_size.width() / xdpi * 25.4));
+ m_physicalSize.setHeight(qRound(m_size.height() / ydpi * 25.4));
+
if (QNativeInterface::QAndroidApplication::sdkVersion() >= 23) {
const QJniObject currentMode = displayObject.callObjectMethod<QtJniTypes::DisplayMode>("getMode");
- const jint currentModeId = currentMode.callMethod<jint>("getModeId");
+ m_currentMode = currentMode.callMethod<jint>("getModeId");
const QJniObject supportedModes = displayObject.callObjectMethod<QtJniTypes::DisplayMode[]>(
"getSupportedModes");
@@ -96,19 +119,9 @@ QAndroidPlatformScreen::QAndroidPlatformScreen(const QJniObject &displayObject)
const auto size = env->GetArrayLength(modeArray);
for (jsize i = 0; i < size; ++i) {
const auto mode = QJniObject::fromLocalRef(env->GetObjectArrayElement(modeArray, i));
- const int physicalWidth = mode.callMethod<jint>("getPhysicalWidth");
- const int physicalHeight = mode.callMethod<jint>("getPhysicalHeight");
-
- if (currentModeId == mode.callMethod<jint>("getModeId")) {
- m_currentMode = i;
- m_physicalSize = QSize {
- physicalWidth,
- physicalHeight
- };
- }
-
m_modes << QPlatformScreen::Mode {
- .size = QSize { physicalWidth, physicalHeight },
+ .size = QSize { mode.callMethod<jint>("getPhysicalWidth"),
+ mode.callMethod<jint>("getPhysicalHeight") },
.refreshRate = mode.callMethod<jfloat>("getRefreshRate")
};
}
@@ -117,23 +130,18 @@ QAndroidPlatformScreen::QAndroidPlatformScreen(const QJniObject &displayObject)
QAndroidPlatformScreen::~QAndroidPlatformScreen()
{
- if (m_surfaceId != -1) {
- QtAndroid::destroySurface(m_surfaceId);
- m_surfaceWaitCondition.wakeOne();
- releaseSurface();
- }
}
-QWindow *QAndroidPlatformScreen::topWindow() const
+QWindow *QAndroidPlatformScreen::topVisibleWindow() const
{
for (QAndroidPlatformWindow *w : m_windowStack) {
- if (w->window()->type() == Qt::Window ||
- w->window()->type() == Qt::Popup ||
- w->window()->type() == Qt::Dialog) {
+ Qt::WindowType type = w->window()->type();
+ if (w->window()->isVisible() &&
+ (type == Qt::Window || type == Qt::Popup || type == Qt::Dialog)) {
return w->window();
}
}
- return 0;
+ return nullptr;
}
QWindow *QAndroidPlatformScreen::topLevelAt(const QPoint &p) const
@@ -145,16 +153,6 @@ QWindow *QAndroidPlatformScreen::topLevelAt(const QPoint &p) const
return 0;
}
-bool QAndroidPlatformScreen::event(QEvent *event)
-{
- if (event->type() == QEvent::UpdateRequest) {
- doRedraw();
- m_updatePending = false;
- return true;
- }
- return QObject::event(event);
-}
-
void QAndroidPlatformScreen::addWindow(QAndroidPlatformWindow *window)
{
if (window->parent() && window->isRaster())
@@ -164,83 +162,45 @@ void QAndroidPlatformScreen::addWindow(QAndroidPlatformWindow *window)
return;
m_windowStack.prepend(window);
- if (window->isRaster()) {
- m_rasterSurfaces.ref();
- setDirty(window->geometry());
- }
+ QtAndroid::qtActivityDelegate().callMethod<void>("addTopLevelWindow", window->nativeWindow());
- QWindow *w = topWindow();
- QWindowSystemInterface::handleWindowActivated(w, Qt::ActiveWindowFocusReason);
- topWindowChanged(w);
+ if (window->window()->isVisible())
+ topVisibleWindowChanged();
}
void QAndroidPlatformScreen::removeWindow(QAndroidPlatformWindow *window)
{
- if (window->parent() && window->isRaster())
- return;
-
m_windowStack.removeOne(window);
if (m_windowStack.contains(window))
qWarning() << "Failed to remove window";
- if (window->isRaster()) {
- m_rasterSurfaces.deref();
- setDirty(window->geometry());
- }
+ QtAndroid::qtActivityDelegate().callMethod<void>("removeTopLevelWindow", window->nativeViewId());
- QWindow *w = topWindow();
- QWindowSystemInterface::handleWindowActivated(w, Qt::ActiveWindowFocusReason);
- topWindowChanged(w);
+ topVisibleWindowChanged();
}
void QAndroidPlatformScreen::raise(QAndroidPlatformWindow *window)
{
- if (window->parent() && window->isRaster())
- return;
-
int index = m_windowStack.indexOf(window);
- if (index <= 0)
+ if (index < 0)
return;
- m_windowStack.move(index, 0);
- if (window->isRaster()) {
- setDirty(window->geometry());
+ if (index > 0) {
+ m_windowStack.move(index, 0);
+ QtAndroid::qtActivityDelegate().callMethod<void>("bringChildToFront", window->nativeViewId());
}
- QWindow *w = topWindow();
- QWindowSystemInterface::handleWindowActivated(w, Qt::ActiveWindowFocusReason);
- topWindowChanged(w);
+ topVisibleWindowChanged();
}
void QAndroidPlatformScreen::lower(QAndroidPlatformWindow *window)
{
- if (window->parent() && window->isRaster())
- return;
-
int index = m_windowStack.indexOf(window);
if (index == -1 || index == (m_windowStack.size() - 1))
return;
m_windowStack.move(index, m_windowStack.size() - 1);
- if (window->isRaster()) {
- setDirty(window->geometry());
- }
- QWindow *w = topWindow();
- QWindowSystemInterface::handleWindowActivated(w, Qt::ActiveWindowFocusReason);
- topWindowChanged(w);
-}
-
-void QAndroidPlatformScreen::scheduleUpdate()
-{
- if (!m_updatePending) {
- m_updatePending = true;
- QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
- }
-}
+ QtAndroid::qtActivityDelegate().callMethod<void>("bringChildToBack", window->nativeViewId());
-void QAndroidPlatformScreen::setDirty(const QRect &rect)
-{
- QRect intersection = rect.intersected(m_availableGeometry);
- m_dirtyRect |= intersection;
- scheduleUpdate();
+ topVisibleWindowChanged();
}
void QAndroidPlatformScreen::setPhysicalSize(const QSize &size)
@@ -292,7 +252,6 @@ void QAndroidPlatformScreen::setOrientation(Qt::ScreenOrientation orientation)
void QAndroidPlatformScreen::setAvailableGeometry(const QRect &rect)
{
- QMutexLocker lock(&m_surfaceMutex);
if (m_availableGeometry == rect)
return;
@@ -313,165 +272,26 @@ void QAndroidPlatformScreen::setAvailableGeometry(const QRect &rect)
}
}
}
-
- if (m_surfaceId != -1) {
- releaseSurface();
- QtAndroid::setSurfaceGeometry(m_surfaceId, rect);
- }
}
void QAndroidPlatformScreen::applicationStateChanged(Qt::ApplicationState state)
{
for (QAndroidPlatformWindow *w : std::as_const(m_windowStack))
w->applicationStateChanged(state);
-
- if (state <= Qt::ApplicationHidden) {
- lockSurface();
- QtAndroid::destroySurface(m_surfaceId);
- m_surfaceId = -1;
- releaseSurface();
- unlockSurface();
- }
}
-void QAndroidPlatformScreen::topWindowChanged(QWindow *w)
+void QAndroidPlatformScreen::topVisibleWindowChanged()
{
+ QWindow *w = topVisibleWindow();
+ QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason);
QtAndroidMenu::setActiveTopLevelWindow(w);
-
- if (w != 0) {
+ if (w && w->handle()) {
QAndroidPlatformWindow *platformWindow = static_cast<QAndroidPlatformWindow *>(w->handle());
- if (platformWindow != 0)
+ if (platformWindow)
platformWindow->updateSystemUiVisibility();
}
}
-int QAndroidPlatformScreen::rasterSurfaces()
-{
- return m_rasterSurfaces;
-}
-
-void QAndroidPlatformScreen::doRedraw(QImage* screenGrabImage)
-{
- PROFILE_SCOPE;
- if (!QtAndroid::activity())
- return;
-
- if (m_dirtyRect.isEmpty())
- return;
-
- // Stop if there are no visible raster windows. If we only have RasterGLSurface
- // windows that have renderToTexture children (i.e. they need the OpenGL path) then
- // we do not need an overlay surface.
- bool hasVisibleRasterWindows = false;
- for (QAndroidPlatformWindow *window : std::as_const(m_windowStack)) {
- if (window->window()->isVisible() && window->isRaster() && !qt_window_private(window->window())->compositing) {
- hasVisibleRasterWindows = true;
- break;
- }
- }
- if (!hasVisibleRasterWindows) {
- lockSurface();
- if (m_surfaceId != -1) {
- QtAndroid::destroySurface(m_surfaceId);
- releaseSurface();
- m_surfaceId = -1;
- }
- unlockSurface();
- return;
- }
- QMutexLocker lock(&m_surfaceMutex);
- if (m_surfaceId == -1 && m_rasterSurfaces) {
- m_surfaceId = QtAndroid::createSurface(this, geometry(), true, m_depth);
- AndroidDeadlockProtector protector;
- if (!protector.acquire())
- return;
- m_surfaceWaitCondition.wait(&m_surfaceMutex);
- }
-
- if (!m_nativeSurface)
- return;
-
- ANativeWindow_Buffer nativeWindowBuffer;
- ARect nativeWindowRect;
- nativeWindowRect.top = m_dirtyRect.top();
- nativeWindowRect.left = m_dirtyRect.left();
- nativeWindowRect.bottom = m_dirtyRect.bottom() + 1; // for some reason that I don't understand the QRect bottom needs to +1 to be the same with ARect bottom
- nativeWindowRect.right = m_dirtyRect.right() + 1; // same for the right
-
- int ret;
- if ((ret = ANativeWindow_lock(m_nativeSurface, &nativeWindowBuffer, &nativeWindowRect)) < 0) {
- qWarning() << "ANativeWindow_lock() failed! error=" << ret;
- return;
- }
-
- int bpp = 4;
- if (nativeWindowBuffer.format == WINDOW_FORMAT_RGB_565) {
- bpp = 2;
- m_pixelFormat = QImage::Format_RGB16;
- }
-
- QImage screenImage(reinterpret_cast<uchar *>(nativeWindowBuffer.bits)
- , nativeWindowBuffer.width, nativeWindowBuffer.height
- , nativeWindowBuffer.stride * bpp , m_pixelFormat);
-
- QPainter compositePainter(&screenImage);
- compositePainter.setCompositionMode(QPainter::CompositionMode_Source);
-
- QRegion visibleRegion(m_dirtyRect);
- for (QAndroidPlatformWindow *window : std::as_const(m_windowStack)) {
- if (!window->window()->isVisible()
- || qt_window_private(window->window())->compositing
- || !window->isRaster())
- continue;
-
- for (const QRect &rect : std::vector<QRect>(visibleRegion.begin(), visibleRegion.end())) {
- QRect targetRect = window->geometry();
- targetRect &= rect;
-
- if (targetRect.isNull())
- continue;
-
- visibleRegion -= targetRect;
- QRect windowRect = targetRect.translated(-window->geometry().topLeft());
- QAndroidPlatformBackingStore *backingStore = static_cast<QAndroidPlatformWindow *>(window)->backingStore();
- if (backingStore)
- compositePainter.drawImage(targetRect.topLeft(), backingStore->toImage(), windowRect);
- }
- }
-
- for (const QRect &rect : visibleRegion)
- compositePainter.fillRect(rect, QColor(Qt::transparent));
-
- ret = ANativeWindow_unlockAndPost(m_nativeSurface);
- if (ret >= 0)
- m_dirtyRect = QRect();
-
- if (screenGrabImage) {
- if (screenGrabImage->size() != screenImage.size()) {
- uchar* bytes = static_cast<uchar*>(malloc(screenImage.height() * screenImage.bytesPerLine()));
- *screenGrabImage = QImage(bytes, screenImage.width(), screenImage.height(),
- screenImage.bytesPerLine(), m_pixelFormat,
- [](void* ptr){ if (ptr) free (ptr);});
- }
- memcpy(screenGrabImage->bits(),
- screenImage.bits(),
- screenImage.bytesPerLine() * screenImage.height());
- }
- m_repaintOccurred = true;
-}
-
-QPixmap QAndroidPlatformScreen::doScreenShot(QRect grabRect)
-{
- if (!m_repaintOccurred)
- return QPixmap::fromImage(m_lastScreenshot.copy(grabRect));
- QRect tmp = m_dirtyRect;
- m_dirtyRect = geometry();
- doRedraw(&m_lastScreenshot);
- m_dirtyRect = tmp;
- m_repaintOccurred = false;
- return QPixmap::fromImage(m_lastScreenshot.copy(grabRect));
-}
-
static const int androidLogicalDpi = 72;
QDpi QAndroidPlatformScreen::logicalDpi() const
@@ -494,67 +314,4 @@ Qt::ScreenOrientation QAndroidPlatformScreen::nativeOrientation() const
{
return QAndroidPlatformIntegration::m_nativeOrientation;
}
-
-void QAndroidPlatformScreen::surfaceChanged(JNIEnv *env, jobject surface, int w, int h)
-{
- lockSurface();
- if (surface && w > 0 && h > 0) {
- releaseSurface();
- m_nativeSurface = ANativeWindow_fromSurface(env, surface);
- QMetaObject::invokeMethod(this, "setDirty", Qt::QueuedConnection, Q_ARG(QRect, QRect(0, 0, w, h)));
- } else {
- releaseSurface();
- }
- unlockSurface();
- m_surfaceWaitCondition.wakeOne();
-}
-
-void QAndroidPlatformScreen::releaseSurface()
-{
- if (m_nativeSurface) {
- ANativeWindow_release(m_nativeSurface);
- m_nativeSurface = 0;
- }
-}
-
-/*!
- This function is called when Qt needs to be able to grab the content of a window.
-
- Returns the content of the window specified with the WId handle within the boundaries of
- QRect(x, y, width, height).
-*/
-QPixmap QAndroidPlatformScreen::grabWindow(WId window, int x, int y, int width, int height) const
-{
- QRectF screenshotRect(x, y, width, height);
- QWindow* wnd = 0;
- if (window)
- {
- const auto windowList = qApp->allWindows();
- for (QWindow *w : windowList)
- if (w->winId() == window) {
- wnd = w;
- break;
- }
- }
- if (wnd) {
- const qreal factor = logicalDpi().first / androidLogicalDpi; //HighDPI factor;
- QRectF wndRect = wnd->geometry();
- if (wnd->parent())
- wndRect.moveTopLeft(wnd->parent()->mapToGlobal(wndRect.topLeft().toPoint()));
- if (!qFuzzyCompare(factor, 1))
- wndRect = QRectF(wndRect.left() * factor, wndRect.top() * factor,
- wndRect.width() * factor, wndRect.height() * factor);
-
- if (!screenshotRect.isEmpty()) {
- screenshotRect.moveTopLeft(wndRect.topLeft() + screenshotRect.topLeft());
- screenshotRect = screenshotRect.intersected(wndRect);
- } else {
- screenshotRect = wndRect;
- }
- } else {
- screenshotRect = screenshotRect.isValid() ? screenshotRect : geometry();
- }
- return const_cast<QAndroidPlatformScreen *>(this)->doScreenShot(screenshotRect.toRect());
-}
-
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformscreen.h b/src/plugins/platforms/android/qandroidplatformscreen.h
index 076530613b..d850d0db09 100644
--- a/src/plugins/platforms/android/qandroidplatformscreen.h
+++ b/src/plugins/platforms/android/qandroidplatformscreen.h
@@ -5,25 +5,22 @@
#ifndef QANDROIDPLATFORMSCREEN_H
#define QANDROIDPLATFORMSCREEN_H
-#include "androidsurfaceclient.h"
-
#include <QList>
#include <QPainter>
#include <QTimer>
#include <QWaitCondition>
#include <QtCore/QJniObject>
#include <qpa/qplatformscreen.h>
-#include <qpa/qplatformscreen_p.h>
-
-#include <android/native_window.h>
+#include <QtGui/qscreen_platform.h>
QT_BEGIN_NAMESPACE
class QAndroidPlatformWindow;
-class QAndroidPlatformScreen: public QObject,
- public QPlatformScreen, public AndroidSurfaceClient,
- public QNativeInterface::Private::QAndroidScreen
+
+class QAndroidPlatformScreen : public QObject,
+ public QPlatformScreen,
+ public QNativeInterface::QAndroidScreen
{
Q_OBJECT
public:
@@ -41,22 +38,17 @@ public:
int currentMode() const override { return m_currentMode; }
int preferredMode() const override { return m_currentMode; }
qreal refreshRate() const override { return m_refreshRate; }
- inline QWindow *topWindow() const;
+ inline QWindow *topVisibleWindow() const;
QWindow *topLevelAt(const QPoint & p) const override;
- // compositor api
void addWindow(QAndroidPlatformWindow *window);
void removeWindow(QAndroidPlatformWindow *window);
void raise(QAndroidPlatformWindow *window);
void lower(QAndroidPlatformWindow *window);
-
- void scheduleUpdate();
- void topWindowChanged(QWindow *w);
- int rasterSurfaces();
+ void topVisibleWindowChanged();
int displayId() const override;
public slots:
- void setDirty(const QRect &rect);
void setPhysicalSize(const QSize &size);
void setAvailableGeometry(const QRect &rect);
void setSize(const QSize &size);
@@ -66,13 +58,8 @@ public slots:
void setOrientation(Qt::ScreenOrientation orientation);
protected:
- bool event(QEvent *event) override;
-
typedef QList<QAndroidPlatformWindow *> WindowStackType;
WindowStackType m_windowStack;
- QRect m_dirtyRect;
- bool m_updatePending = false;
-
QRect m_availableGeometry;
int m_depth;
QImage::Format m_format;
@@ -88,25 +75,9 @@ private:
QDpi logicalBaseDpi() const override;
Qt::ScreenOrientation orientation() const override;
Qt::ScreenOrientation nativeOrientation() const override;
- QPixmap grabWindow(WId window, int x, int y, int width, int height) const override;
- void surfaceChanged(JNIEnv *env, jobject surface, int w, int h) override;
- void releaseSurface();
void applicationStateChanged(Qt::ApplicationState);
- QPixmap doScreenShot(QRect grabRect = QRect());
-
-private slots:
- void doRedraw(QImage *screenGrabImage = nullptr);
-
private:
- int m_surfaceId = -1;
- QAtomicInt m_rasterSurfaces = 0;
- ANativeWindow* m_nativeSurface = nullptr;
- QWaitCondition m_surfaceWaitCondition;
QSize m_size;
-
- QImage m_lastScreenshot;
- QImage::Format m_pixelFormat = QImage::Format_RGBA8888_Premultiplied;
- bool m_repaintOccurred = false;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformservices.cpp b/src/plugins/platforms/android/qandroidplatformservices.cpp
index 5964236420..39287aa905 100644
--- a/src/plugins/platforms/android/qandroidplatformservices.cpp
+++ b/src/plugins/platforms/android/qandroidplatformservices.cpp
@@ -24,19 +24,22 @@ QAndroidPlatformServices::QAndroidPlatformServices()
QtAndroidPrivate::registerNewIntentListener(this);
- QMetaObject::invokeMethod(
- this,
- [this] {
- QJniObject context = QJniObject(QtAndroidPrivate::context());
- QJniObject intent =
- context.callObjectMethod("getIntent", "()Landroid/content/Intent;");
- handleNewIntent(nullptr, intent.object());
- },
- Qt::QueuedConnection);
+ // Qt applications without Activity contexts cannot retrieve intents from the Activity.
+ if (QNativeInterface::QAndroidApplication::isActivityContext()) {
+ QMetaObject::invokeMethod(
+ this,
+ [this] {
+ QJniObject context = QJniObject(QtAndroidPrivate::context());
+ QJniObject intent =
+ context.callObjectMethod("getIntent", "()Landroid/content/Intent;");
+ handleNewIntent(nullptr, intent.object());
+ },
+ Qt::QueuedConnection);
+ }
}
-Q_DECLARE_JNI_TYPE(UriType, "Landroid/net/Uri;")
-Q_DECLARE_JNI_TYPE(FileType, "Ljava/io/File;")
+Q_DECLARE_JNI_CLASS(UriType, "android/net/Uri")
+Q_DECLARE_JNI_CLASS(FileType, "java/io/File")
Q_DECLARE_JNI_CLASS(File, "java/io/File")
Q_DECLARE_JNI_CLASS(FileProvider, "androidx/core/content/FileProvider");
@@ -78,11 +81,11 @@ bool QAndroidPlatformServices::openUrl(const QUrl &theUrl)
const auto providerName = QJniObject::fromString(appId + ".qtprovider"_L1);
const auto urlPath = QJniObject::fromString(url.path());
- const auto urlFile = QJniObject(QtJniTypes::className<QtJniTypes::File>(),
+ const auto urlFile = QJniObject(QtJniTypes::Traits<QtJniTypes::File>::className(),
urlPath.object<jstring>());
const auto fileProviderUri = QJniObject::callStaticMethod<QtJniTypes::UriType>(
- QtJniTypes::className<QtJniTypes::FileProvider>(), "getUriForFile",
+ QtJniTypes::Traits<QtJniTypes::FileProvider>::className(), "getUriForFile",
QAndroidApplication::context(), providerName.object<jstring>(),
urlFile.object<QtJniTypes::FileType>());
diff --git a/src/plugins/platforms/android/qandroidplatformtheme.cpp b/src/plugins/platforms/android/qandroidplatformtheme.cpp
index f863529057..7b9072df69 100644
--- a/src/plugins/platforms/android/qandroidplatformtheme.cpp
+++ b/src/plugins/platforms/android/qandroidplatformtheme.cpp
@@ -4,6 +4,7 @@
#include "androidjnimain.h"
#include "androidjnimenu.h"
#include "qandroidplatformtheme.h"
+#include "qandroidplatformiconengine.h"
#include "qandroidplatformmenubar.h"
#include "qandroidplatformmenu.h"
#include "qandroidplatformmenuitem.h"
@@ -22,6 +23,8 @@
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaMenus, "qt.qpa.menus")
+
using namespace Qt::StringLiterals;
namespace {
@@ -163,13 +166,6 @@ QJsonObject AndroidStyle::loadStyleData()
Q_ASSERT(!stylePath.isEmpty());
- QString androidTheme = QLatin1StringView(qgetenv("QT_ANDROID_THEME"));
- if (!androidTheme.isEmpty() && !androidTheme.endsWith(slashChar))
- androidTheme += slashChar;
-
- if (!androidTheme.isEmpty() && QFileInfo::exists(stylePath + androidTheme + "style.json"_L1))
- stylePath += androidTheme;
-
QFile f(stylePath + "style.json"_L1);
if (!f.open(QIODevice::ReadOnly))
return QJsonObject();
@@ -400,21 +396,28 @@ void QAndroidPlatformTheme::updateStyle()
QPlatformMenuBar *QAndroidPlatformTheme::createPlatformMenuBar() const
{
- return new QAndroidPlatformMenuBar;
+ auto *menuBar = new QAndroidPlatformMenuBar;
+ qCDebug(lcQpaMenus) << "Created" << menuBar;
+ return menuBar;
}
QPlatformMenu *QAndroidPlatformTheme::createPlatformMenu() const
{
- return new QAndroidPlatformMenu;
+ auto *menu = new QAndroidPlatformMenu;
+ qCDebug(lcQpaMenus) << "Created" << menu;
+ return menu;
}
QPlatformMenuItem *QAndroidPlatformTheme::createPlatformMenuItem() const
{
- return new QAndroidPlatformMenuItem;
+ auto *menuItem = new QAndroidPlatformMenuItem;
+ qCDebug(lcQpaMenus) << "Created" << menuItem;
+ return menuItem;
}
void QAndroidPlatformTheme::showPlatformMenuBar()
{
+ qCDebug(lcQpaMenus) << "Showing platform menu bar";
QtAndroidMenu::openOptionsMenu();
}
@@ -488,6 +491,11 @@ const QFont *QAndroidPlatformTheme::font(Font type) const
return 0;
}
+QIconEngine *QAndroidPlatformTheme::createIconEngine(const QString &iconName) const
+{
+ return new QAndroidPlatformIconEngine(iconName);
+}
+
QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const
{
switch (hint) {
diff --git a/src/plugins/platforms/android/qandroidplatformtheme.h b/src/plugins/platforms/android/qandroidplatformtheme.h
index bb8c5c4869..ce3d6d5f73 100644
--- a/src/plugins/platforms/android/qandroidplatformtheme.h
+++ b/src/plugins/platforms/android/qandroidplatformtheme.h
@@ -9,13 +9,15 @@
#include <QtGui/qpalette.h>
#include <QtCore/qhash.h>
#include <QtCore/qbytearray.h>
-
+#include <QtCore/qloggingcategory.h>
#include <QJsonObject>
#include <memory>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaMenus)
+
struct AndroidStyle
{
static QJsonObject loadStyleData();
@@ -40,6 +42,7 @@ public:
Qt::ColorScheme colorScheme() const override;
const QPalette *palette(Palette type = SystemPalette) const override;
const QFont *font(Font type = SystemFont) const override;
+ QIconEngine *createIconEngine(const QString &iconName) const override;
QVariant themeHint(ThemeHint hint) const override;
QString standardButtonText(int button) const override;
bool usePlatformNativeDialog(DialogType type) const override;
diff --git a/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp b/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp
index cb6bb6d390..4bf4f44fa1 100644
--- a/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp
+++ b/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp
@@ -18,7 +18,6 @@ QT_BEGIN_NAMESPACE
QAndroidPlatformVulkanWindow::QAndroidPlatformVulkanWindow(QWindow *window)
: QAndroidPlatformWindow(window),
- m_nativeSurfaceId(-1),
m_nativeWindow(nullptr),
m_vkSurface(0),
m_createVkSurface(nullptr),
@@ -29,11 +28,7 @@ QAndroidPlatformVulkanWindow::QAndroidPlatformVulkanWindow(QWindow *window)
QAndroidPlatformVulkanWindow::~QAndroidPlatformVulkanWindow()
{
m_surfaceWaitCondition.wakeOne();
- lockSurface();
- if (m_nativeSurfaceId != -1)
- QtAndroid::destroySurface(m_nativeSurfaceId);
- clearSurface();
- unlockSurface();
+ destroyAndClearSurface();
}
void QAndroidPlatformVulkanWindow::setGeometry(const QRect &rect)
@@ -44,8 +39,8 @@ void QAndroidPlatformVulkanWindow::setGeometry(const QRect &rect)
m_oldGeometry = geometry();
QAndroidPlatformWindow::setGeometry(rect);
- if (m_nativeSurfaceId != -1)
- QtAndroid::setSurfaceGeometry(m_nativeSurfaceId, rect);
+ if (m_surfaceCreated)
+ setNativeGeometry(rect);
QRect availableGeometry = screen()->availableGeometry();
if (rect.width() > 0
@@ -54,22 +49,13 @@ void QAndroidPlatformVulkanWindow::setGeometry(const QRect &rect)
&& availableGeometry.height() > 0) {
QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), rect.size()));
}
-
- if (rect.topLeft() != m_oldGeometry.topLeft())
- repaint(QRegion(rect));
}
void QAndroidPlatformVulkanWindow::applicationStateChanged(Qt::ApplicationState state)
{
QAndroidPlatformWindow::applicationStateChanged(state);
if (state <= Qt::ApplicationHidden) {
- lockSurface();
- if (m_nativeSurfaceId != -1) {
- QtAndroid::destroySurface(m_nativeSurfaceId);
- m_nativeSurfaceId = -1;
- }
- clearSurface();
- unlockSurface();
+ destroyAndClearSurface();
}
}
@@ -91,27 +77,12 @@ void QAndroidPlatformVulkanWindow::clearSurface()
}
}
-void QAndroidPlatformVulkanWindow::sendExpose()
-{
- QRect availableGeometry = screen()->availableGeometry();
- if (geometry().width() > 0 && geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0)
- QWindowSystemInterface::handleExposeEvent(window(), QRegion(QRect(QPoint(), geometry().size())));
-}
-
-void QAndroidPlatformVulkanWindow::surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h)
+void QAndroidPlatformVulkanWindow::destroyAndClearSurface()
{
- Q_UNUSED(jniEnv);
- Q_UNUSED(w);
- Q_UNUSED(h);
-
lockSurface();
- m_androidSurfaceObject = surface;
- if (surface)
- m_surfaceWaitCondition.wakeOne();
+ destroySurface();
+ clearSurface();
unlockSurface();
-
- if (surface)
- sendExpose();
}
VkSurfaceKHR *QAndroidPlatformVulkanWindow::vkSurface()
@@ -124,16 +95,15 @@ VkSurfaceKHR *QAndroidPlatformVulkanWindow::vkSurface()
clearSurface();
QMutexLocker lock(&m_surfaceMutex);
- if (m_nativeSurfaceId == -1) {
+ if (!m_surfaceCreated) {
AndroidDeadlockProtector protector;
if (!protector.acquire())
return &m_vkSurface;
- const bool windowStaysOnTop = bool(window()->flags() & Qt::WindowStaysOnTopHint);
- m_nativeSurfaceId = QtAndroid::createSurface(this, geometry(), windowStaysOnTop, 32);
+ createSurface();
m_surfaceWaitCondition.wait(&m_surfaceMutex);
}
- if (m_nativeSurfaceId == -1 || !m_androidSurfaceObject.isValid())
+ if (!m_surfaceCreated || !m_androidSurfaceObject.isValid())
return &m_vkSurface;
QJniEnvironment env;
diff --git a/src/plugins/platforms/android/qandroidplatformvulkanwindow.h b/src/plugins/platforms/android/qandroidplatformvulkanwindow.h
index 14d5b7fc0e..fa959239d1 100644
--- a/src/plugins/platforms/android/qandroidplatformvulkanwindow.h
+++ b/src/plugins/platforms/android/qandroidplatformvulkanwindow.h
@@ -10,7 +10,6 @@
#define VK_USE_PLATFORM_ANDROID_KHR
-#include "androidsurfaceclient.h"
#include "qandroidplatformvulkaninstance.h"
#include "qandroidplatformwindow.h"
@@ -20,7 +19,7 @@
QT_BEGIN_NAMESPACE
-class QAndroidPlatformVulkanWindow : public QAndroidPlatformWindow, public AndroidSurfaceClient
+class QAndroidPlatformVulkanWindow : public QAndroidPlatformWindow
{
public:
explicit QAndroidPlatformVulkanWindow(QWindow *window);
@@ -32,17 +31,11 @@ public:
VkSurfaceKHR *vkSurface();
-protected:
- void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h) override;
-
private:
- void sendExpose();
void clearSurface();
+ void destroyAndClearSurface();
- int m_nativeSurfaceId;
ANativeWindow *m_nativeWindow;
- QJniObject m_androidSurfaceObject;
- QWaitCondition m_surfaceWaitCondition;
QSurfaceFormat m_format;
QRect m_oldGeometry;
VkSurfaceKHR m_vkSurface;
diff --git a/src/plugins/platforms/android/qandroidplatformwindow.cpp b/src/plugins/platforms/android/qandroidplatformwindow.cpp
index b1eba17d04..979f0fb98a 100644
--- a/src/plugins/platforms/android/qandroidplatformwindow.cpp
+++ b/src/plugins/platforms/android/qandroidplatformwindow.cpp
@@ -14,40 +14,95 @@
QT_BEGIN_NAMESPACE
-Q_CONSTINIT static QBasicAtomicInt winIdGenerator = Q_BASIC_ATOMIC_INITIALIZER(0);
+Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window")
QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window)
- : QPlatformWindow(window)
+ : QPlatformWindow(window), m_nativeQtWindow(nullptr),
+ m_surfaceContainerType(SurfaceContainer::TextureView), m_nativeParentQtWindow(nullptr),
+ m_androidSurfaceObject(nullptr)
{
m_windowFlags = Qt::Widget;
m_windowState = Qt::WindowNoState;
- m_windowId = winIdGenerator.fetchAndAddRelaxed(1) + 1;
+ // the surfaceType is overwritten in QAndroidPlatformOpenGLWindow ctor so let's save
+ // the fact that it's a raster window for now
+ m_isRaster = window->surfaceType() == QSurface::RasterSurface;
setWindowState(window->windowStates());
// the following is in relation to the virtual geometry
const bool forceMaximize = m_windowState & (Qt::WindowMaximized | Qt::WindowFullScreen);
- const QRect requestedNativeGeometry =
- forceMaximize ? QRect() : QHighDpi::toNativePixels(window->geometry(), window);
- const QRect availableDeviceIndependentGeometry = (window->parent())
- ? window->parent()->geometry()
- : QHighDpi::fromNativePixels(platformScreen()->availableGeometry(), window);
+ const QRect nativeScreenGeometry = platformScreen()->availableGeometry();
+ if (forceMaximize) {
+ setGeometry(nativeScreenGeometry);
+ } else {
+ const QRect requestedNativeGeometry = QHighDpi::toNativePixels(window->geometry(), window);
+ const QRect availableDeviceIndependentGeometry = (window->parent())
+ ? window->parent()->geometry()
+ : QHighDpi::fromNativePixels(nativeScreenGeometry, window);
+ // initialGeometry returns in native pixels
+ const QRect finalNativeGeometry = QPlatformWindow::initialGeometry(
+ window, requestedNativeGeometry, availableDeviceIndependentGeometry.width(),
+ availableDeviceIndependentGeometry.height());
+ if (requestedNativeGeometry != finalNativeGeometry)
+ setGeometry(finalNativeGeometry);
+ }
+
+ if (isEmbeddingContainer())
+ return;
+
+ if (parent()) {
+ QAndroidPlatformWindow *androidParent = static_cast<QAndroidPlatformWindow*>(parent());
+ if (!androidParent->isEmbeddingContainer())
+ m_nativeParentQtWindow = androidParent->nativeWindow();
+ }
+
+ m_nativeQtWindow = QJniObject::construct<QtJniTypes::QtWindow>(
+ QNativeInterface::QAndroidApplication::context(),
+ m_nativeParentQtWindow,
+ QtAndroid::qtInputDelegate());
+ m_nativeViewId = m_nativeQtWindow.callMethod<jint>("getId");
- // initialGeometry returns in native pixels
- const QRect finalNativeGeometry = QPlatformWindow::initialGeometry(
- window, requestedNativeGeometry, availableDeviceIndependentGeometry.width(),
- availableDeviceIndependentGeometry.height());
+ if (window->isTopLevel())
+ platformScreen()->addWindow(this);
- if (requestedNativeGeometry != finalNativeGeometry)
- setGeometry(finalNativeGeometry);
+ static bool ok = false;
+ static const int value = qEnvironmentVariableIntValue("QT_ANDROID_SURFACE_CONTAINER_TYPE", &ok);
+ if (ok) {
+ static const SurfaceContainer type = static_cast<SurfaceContainer>(value);
+ if (type == SurfaceContainer::SurfaceView || type == SurfaceContainer::TextureView)
+ m_surfaceContainerType = type;
+ } else if (platformScreen()->windows().size() <= 1) {
+ // TODO should handle case where this changes at runtime -> need to change existing window
+ // into TextureView (or perhaps not, if the parent window would be SurfaceView, as long as
+ // onTop was false it would stay below the children)
+ m_surfaceContainerType = SurfaceContainer::SurfaceView;
+ }
+ qCDebug(lcQpaWindow) << "Window" << m_nativeViewId << "using surface container type"
+ << static_cast<int>(m_surfaceContainerType);
}
+QAndroidPlatformWindow::~QAndroidPlatformWindow()
+{
+ if (window()->isTopLevel())
+ platformScreen()->removeWindow(this);
+}
+
+
void QAndroidPlatformWindow::lower()
{
+ if (m_nativeParentQtWindow.isValid()) {
+ m_nativeParentQtWindow.callMethod<void>("bringChildToBack", nativeViewId());
+ return;
+ }
platformScreen()->lower(this);
}
void QAndroidPlatformWindow::raise()
{
+ if (m_nativeParentQtWindow.isValid()) {
+ m_nativeParentQtWindow.callMethod<void>("bringChildToFront", nativeViewId());
+ QWindowSystemInterface::handleFocusWindowChanged(window(), Qt::ActiveWindowFocusReason);
+ return;
+ }
updateSystemUiVisibility();
platformScreen()->raise(this);
}
@@ -71,23 +126,25 @@ void QAndroidPlatformWindow::setGeometry(const QRect &rect)
void QAndroidPlatformWindow::setVisible(bool visible)
{
- if (visible)
- updateSystemUiVisibility();
+ if (isEmbeddingContainer())
+ return;
+ m_nativeQtWindow.callMethod<void>("setVisible", visible);
if (visible) {
- if ((m_windowState & Qt::WindowFullScreen)
- || ((m_windowState & Qt::WindowMaximized) && (window()->flags() & Qt::MaximizeUsingFullscreenGeometryHint))) {
- setGeometry(platformScreen()->geometry());
- } else if (m_windowState & Qt::WindowMaximized) {
- setGeometry(platformScreen()->availableGeometry());
+ if (window()->isTopLevel()) {
+ updateSystemUiVisibility();
+ if ((m_windowState & Qt::WindowFullScreen)
+ || ((m_windowState & Qt::WindowMaximized) && (window()->flags() & Qt::MaximizeUsingFullscreenGeometryHint))) {
+ setGeometry(platformScreen()->geometry());
+ } else if (m_windowState & Qt::WindowMaximized) {
+ setGeometry(platformScreen()->availableGeometry());
+ }
+ requestActivateWindow();
}
+ } else if (window()->isTopLevel() && window() == qGuiApp->focusWindow()) {
+ platformScreen()->topVisibleWindowChanged();
}
- if (visible)
- platformScreen()->addWindow(this);
- else
- platformScreen()->removeWindow(this);
-
QRect availableGeometry = screen()->availableGeometry();
if (geometry().width() > 0 && geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0)
QPlatformWindow::setVisible(visible);
@@ -120,7 +177,30 @@ Qt::WindowFlags QAndroidPlatformWindow::windowFlags() const
void QAndroidPlatformWindow::setParent(const QPlatformWindow *window)
{
- Q_UNUSED(window);
+ using namespace QtJniTypes;
+
+ if (window) {
+ auto androidWindow = static_cast<const QAndroidPlatformWindow*>(window);
+ if (androidWindow->isEmbeddingContainer())
+ return;
+ // If we were a top level window, remove from screen
+ if (!m_nativeParentQtWindow.isValid())
+ platformScreen()->removeWindow(this);
+
+ const QtWindow parentWindow = androidWindow->nativeWindow();
+ // If this was a child window of another window, the java method takes care of that
+ m_nativeQtWindow.callMethod<void, QtWindow>("setParent", parentWindow.object());
+ m_nativeParentQtWindow = parentWindow;
+ } else if (QtAndroid::isQtApplication()) {
+ m_nativeQtWindow.callMethod<void, QtWindow>("setParent", nullptr);
+ m_nativeParentQtWindow = QJniObject();
+ platformScreen()->addWindow(this);
+ }
+}
+
+WId QAndroidPlatformWindow::winId() const
+{
+ return m_nativeQtWindow.isValid() ? reinterpret_cast<WId>(m_nativeQtWindow.object()) : 0L;
}
QAndroidPlatformScreen *QAndroidPlatformWindow::platformScreen() const
@@ -135,7 +215,9 @@ void QAndroidPlatformWindow::propagateSizeHints()
void QAndroidPlatformWindow::requestActivateWindow()
{
- platformScreen()->topWindowChanged(window());
+ // raise() will handle differences between top level and child windows, and requesting focus
+ if (!blockedByModal())
+ raise();
}
void QAndroidPlatformWindow::updateSystemUiVisibility()
@@ -169,4 +251,134 @@ void QAndroidPlatformWindow::applicationStateChanged(Qt::ApplicationState)
QWindowSystemInterface::flushWindowSystemEvents();
}
+void QAndroidPlatformWindow::createSurface()
+{
+ const QRect rect = geometry();
+ jint x = 0, y = 0, w = -1, h = -1;
+ if (!rect.isNull()) {
+ x = rect.x();
+ y = rect.y();
+ w = std::max(rect.width(), 1);
+ h = std::max(rect.height(), 1);
+ }
+
+ const bool windowStaysOnTop = bool(window()->flags() & Qt::WindowStaysOnTopHint);
+ const bool isOpaque = !format().hasAlpha() && qFuzzyCompare(window()->opacity(), 1.0);
+
+ m_nativeQtWindow.callMethod<void>("createSurface", windowStaysOnTop, x, y, w, h, 32, isOpaque,
+ m_surfaceContainerType);
+ m_surfaceCreated = true;
+}
+
+void QAndroidPlatformWindow::destroySurface()
+{
+ if (m_surfaceCreated) {
+ m_nativeQtWindow.callMethod<void>("destroySurface");
+ m_surfaceCreated = false;
+ }
+}
+
+void QAndroidPlatformWindow::setNativeGeometry(const QRect &geometry)
+{
+ if (!m_surfaceCreated)
+ return;
+
+ jint x = 0;
+ jint y = 0;
+ jint w = -1;
+ jint h = -1;
+ if (!geometry.isNull()) {
+ x = geometry.x();
+ y = geometry.y();
+ w = geometry.width();
+ h = geometry.height();
+ }
+ m_nativeQtWindow.callMethod<void>("setGeometry", x, y, w, h);
+}
+
+void QAndroidPlatformWindow::onSurfaceChanged(QtJniTypes::Surface surface)
+{
+ lockSurface();
+ m_androidSurfaceObject = surface;
+ if (m_androidSurfaceObject.isValid()) // wait until we have a valid surface to draw into
+ m_surfaceWaitCondition.wakeOne();
+ unlockSurface();
+
+ if (m_androidSurfaceObject.isValid()) {
+ // repaint the window, when we have a valid surface
+ sendExpose();
+ }
+}
+
+void QAndroidPlatformWindow::sendExpose() const
+{
+ QRect availableGeometry = screen()->availableGeometry();
+ if (!geometry().isNull() && !availableGeometry.isNull()) {
+ QWindowSystemInterface::handleExposeEvent(window(),
+ QRegion(QRect(QPoint(), geometry().size())));
+ }
+}
+
+bool QAndroidPlatformWindow::blockedByModal() const
+{
+ QWindow *modalWindow = QGuiApplication::modalWindow();
+ return modalWindow && modalWindow != window();
+}
+
+bool QAndroidPlatformWindow::isEmbeddingContainer() const
+{
+ // Returns true if the window is a wrapper for a foreign window solely to allow embedding Qt
+ // into a native Android app, in which case we should not try to control it more than we "need" to
+ return !QtAndroid::isQtApplication() && window()->isTopLevel();
+}
+
+void QAndroidPlatformWindow::setSurface(JNIEnv *env, jobject object, jint windowId,
+ QtJniTypes::Surface surface)
+{
+ Q_UNUSED(env)
+ Q_UNUSED(object)
+
+ if (!qGuiApp)
+ return;
+
+ const QList<QWindow*> windows = qGuiApp->allWindows();
+ for (QWindow * window : windows) {
+ if (!window->handle())
+ continue;
+ QAndroidPlatformWindow *platformWindow =
+ static_cast<QAndroidPlatformWindow *>(window->handle());
+ if (platformWindow->nativeViewId() == windowId)
+ platformWindow->onSurfaceChanged(surface);
+ }
+}
+
+void QAndroidPlatformWindow::windowFocusChanged(JNIEnv *env, jobject object,
+ jboolean focus, jint windowId)
+{
+ Q_UNUSED(env)
+ Q_UNUSED(object)
+ QWindow* window = QtAndroid::windowFromId(windowId);
+ Q_ASSERT_X(window, "QAndroidPlatformWindow", "windowFocusChanged event window should exist");
+ if (focus) {
+ QWindowSystemInterface::handleFocusWindowChanged(window);
+ } else if (!focus && window == qGuiApp->focusWindow()) {
+ // Clear focus if current window has lost focus
+ QWindowSystemInterface::handleFocusWindowChanged(nullptr);
+ }
+}
+
+bool QAndroidPlatformWindow::registerNatives(QJniEnvironment &env)
+{
+ if (!env.registerNativeMethods(QtJniTypes::Traits<QtJniTypes::QtWindow>::className(),
+ {
+ Q_JNI_NATIVE_SCOPED_METHOD(setSurface, QAndroidPlatformWindow),
+ Q_JNI_NATIVE_SCOPED_METHOD(windowFocusChanged, QAndroidPlatformWindow)
+ })) {
+ qCCritical(lcQpaWindow) << "RegisterNatives failed for"
+ << QtJniTypes::Traits<QtJniTypes::QtWindow>::className();
+ return false;
+ }
+ return true;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h
index 6fccc2e7fe..3f1e8ac992 100644
--- a/src/plugins/platforms/android/qandroidplatformwindow.h
+++ b/src/plugins/platforms/android/qandroidplatformwindow.h
@@ -7,17 +7,32 @@
#include <qobject.h>
#include <qrect.h>
#include <qpa/qplatformwindow.h>
+#include <QtCore/qjnienvironment.h>
+#include <QtCore/qjniobject.h>
+#include <QtCore/qjnitypes.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qwaitcondition.h>
+#include <jni.h>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaWindow)
+Q_DECLARE_JNI_CLASS(QtWindow, "org/qtproject/qt/android/QtWindow")
+Q_DECLARE_JNI_CLASS(Surface, "android/view/Surface")
+
class QAndroidPlatformScreen;
-class QAndroidPlatformBackingStore;
class QAndroidPlatformWindow: public QPlatformWindow
{
public:
- explicit QAndroidPlatformWindow(QWindow *window);
+ enum class SurfaceContainer {
+ SurfaceView,
+ TextureView
+ };
+ explicit QAndroidPlatformWindow(QWindow *window);
+ ~QAndroidPlatformWindow();
void lower() override;
void raise() override;
@@ -27,7 +42,8 @@ public:
void setWindowFlags(Qt::WindowFlags flags) override;
Qt::WindowFlags windowFlags() const;
void setParent(const QPlatformWindow *window) override;
- WId winId() const override { return m_windowId; }
+
+ WId winId() const override;
bool setMouseGrabEnabled(bool grab) override { Q_UNUSED(grab); return false; }
bool setKeyboardGrabEnabled(bool grab) override { Q_UNUSED(grab); return false; }
@@ -39,32 +55,46 @@ public:
void propagateSizeHints() override;
void requestActivateWindow() override;
void updateSystemUiVisibility();
- inline bool isRaster() const {
- if (isForeignWindow())
- return false;
-
- return window()->surfaceType() == QSurface::RasterSurface
- || window()->surfaceType() == QSurface::RasterGLSurface;
- }
+ inline bool isRaster() const { return m_isRaster; }
bool isExposed() const override;
+ QtJniTypes::QtWindow nativeWindow() const { return m_nativeQtWindow; }
virtual void applicationStateChanged(Qt::ApplicationState);
+ int nativeViewId() const { return m_nativeViewId; }
- void setBackingStore(QAndroidPlatformBackingStore *store) { m_backingStore = store; }
- QAndroidPlatformBackingStore *backingStore() const { return m_backingStore; }
-
- virtual void repaint(const QRegion &) { }
+ static bool registerNatives(QJniEnvironment &env);
+ void onSurfaceChanged(QtJniTypes::Surface surface);
protected:
void setGeometry(const QRect &rect) override;
+ void lockSurface() { m_surfaceMutex.lock(); }
+ void unlockSurface() { m_surfaceMutex.unlock(); }
+ void createSurface();
+ void destroySurface();
+ void setNativeGeometry(const QRect &geometry);
+ void sendExpose() const;
+ bool blockedByModal() const;
+ bool isEmbeddingContainer() const;
-protected:
Qt::WindowFlags m_windowFlags;
Qt::WindowStates m_windowState;
-
- WId m_windowId;
-
- QAndroidPlatformBackingStore *m_backingStore = nullptr;
+ bool m_isRaster;
+
+ int m_nativeViewId = -1;
+ QtJniTypes::QtWindow m_nativeQtWindow;
+ SurfaceContainer m_surfaceContainerType = SurfaceContainer::SurfaceView;
+ QtJniTypes::QtWindow m_nativeParentQtWindow;
+ // The Android Surface, accessed from multiple threads, guarded by m_surfaceMutex
+ QtJniTypes::Surface m_androidSurfaceObject;
+ QWaitCondition m_surfaceWaitCondition;
+ bool m_surfaceCreated = false;
+ QMutex m_surfaceMutex;
+
+private:
+ static void setSurface(JNIEnv *env, jobject obj, jint windowId, QtJniTypes::Surface surface);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(setSurface)
+ static void windowFocusChanged(JNIEnv *env, jobject object, jboolean focus, jint windowId);
+ Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(windowFocusChanged)
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidsystemlocale.cpp b/src/plugins/platforms/android/qandroidsystemlocale.cpp
index 858934b1f8..c5f2e59097 100644
--- a/src/plugins/platforms/android/qandroidsystemlocale.cpp
+++ b/src/plugins/platforms/android/qandroidsystemlocale.cpp
@@ -12,34 +12,38 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_JNI_CLASS(Locale, "java/util/Locale")
+Q_DECLARE_JNI_CLASS(Resources, "android/content/res/Resources")
+Q_DECLARE_JNI_CLASS(Configuration, "android/content/res/Configuration")
+Q_DECLARE_JNI_CLASS(LocaleList, "android/os/LocaleList")
+
+using namespace QtJniTypes;
+
QAndroidSystemLocale::QAndroidSystemLocale() : m_locale(QLocale::C)
{
}
void QAndroidSystemLocale::getLocaleFromJava() const
{
- QWriteLocker locker(&m_lock);
-
- QJniObject javaLocaleObject;
- QJniObject javaActivity(QtAndroid::activity());
- if (!javaActivity.isValid())
- javaActivity = QtAndroid::service();
- if (javaActivity.isValid()) {
- QJniObject resources = javaActivity.callObjectMethod("getResources", "()Landroid/content/res/Resources;");
- QJniObject configuration = resources.callObjectMethod("getConfiguration", "()Landroid/content/res/Configuration;");
-
- javaLocaleObject = configuration.getObjectField("locale", "Ljava/util/Locale;");
- } else {
- javaLocaleObject = QJniObject::callStaticObjectMethod("java/util/Locale", "getDefault", "()Ljava/util/Locale;");
- }
+ const Locale javaLocaleObject = []{
+ const QJniObject javaContext = QtAndroidPrivate::context();
+ if (javaContext.isValid()) {
+ const QJniObject resources = javaContext.callMethod<Resources>("getResources");
+ const QJniObject configuration = resources.callMethod<Configuration>("getConfiguration");
+ return configuration.getField<Locale>("locale");
+ } else {
+ return Locale::callStaticMethod<Locale>("getDefault");
+ }
+ }();
- QString languageCode = javaLocaleObject.callObjectMethod("getLanguage", "()Ljava/lang/String;").toString();
- QString countryCode = javaLocaleObject.callObjectMethod("getCountry", "()Ljava/lang/String;").toString();
+ const QString languageCode = javaLocaleObject.callMethod<QString>("getLanguage");
+ const QString countryCode = javaLocaleObject.callMethod<QString>("getCountry");
+ QWriteLocker locker(&m_lock);
m_locale = QLocale(languageCode + u'_' + countryCode);
}
-QVariant QAndroidSystemLocale::query(QueryType type, QVariant in) const
+QVariant QAndroidSystemLocale::query(QueryType type, QVariant &&in) const
{
if (type == LocaleChanged) {
getLocaleFromJava();
@@ -142,12 +146,9 @@ QVariant QAndroidSystemLocale::query(QueryType type, QVariant in) const
Q_ASSERT_X(false, Q_FUNC_INFO, "This can't happen.");
case UILanguages: {
if (QtAndroidPrivate::androidSdkVersion() >= 24) {
- QJniObject localeListObject =
- QJniObject::callStaticObjectMethod("android/os/LocaleList", "getDefault",
- "()Landroid/os/LocaleList;");
+ LocaleList localeListObject = LocaleList::callStaticMethod<LocaleList>("getDefault");
if (localeListObject.isValid()) {
- QString lang = localeListObject.callObjectMethod("toLanguageTags",
- "()Ljava/lang/String;").toString();
+ QString lang = localeListObject.callMethod<QString>("toLanguageTags");
// Some devices return with it enclosed in []'s so check if both exists before
// removing to ensure it is formatted correctly
if (lang.startsWith(QChar('[')) && lang.endsWith(QChar(']')))
diff --git a/src/plugins/platforms/android/qandroidsystemlocale.h b/src/plugins/platforms/android/qandroidsystemlocale.h
index 48e1d94a56..cd37b48270 100644
--- a/src/plugins/platforms/android/qandroidsystemlocale.h
+++ b/src/plugins/platforms/android/qandroidsystemlocale.h
@@ -11,10 +11,11 @@ QT_BEGIN_NAMESPACE
class QAndroidSystemLocale : public QSystemLocale
{
+ Q_DISABLE_COPY_MOVE(QAndroidSystemLocale)
public:
QAndroidSystemLocale();
- QVariant query(QueryType type, QVariant in) const override;
+ QVariant query(QueryType type, QVariant &&in) const override;
QLocale fallbackLocale() const override;
private:
diff --git a/src/plugins/platforms/cocoa/CMakeLists.txt b/src/plugins/platforms/cocoa/CMakeLists.txt
index af8434daaa..92e681d8fb 100644
--- a/src/plugins/platforms/cocoa/CMakeLists.txt
+++ b/src/plugins/platforms/cocoa/CMakeLists.txt
@@ -56,6 +56,7 @@ qt_internal_add_plugin(QCocoaIntegrationPlugin
${FWIOSurface}
${FWMetal}
${FWQuartzCore}
+ ${FWUniformTypeIdentifiers}
Qt::Core
Qt::CorePrivate
Qt::Gui
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
index dc2baa6961..c5e40a4087 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
@@ -117,7 +117,6 @@ static void populateRoleMap()
roleMap[QAccessible::ColumnHeader] = NSAccessibilityColumnRole;
roleMap[QAccessible::Row] = NSAccessibilityRowRole;
roleMap[QAccessible::RowHeader] = NSAccessibilityRowRole;
- roleMap[QAccessible::Cell] = NSAccessibilityTextFieldRole;
roleMap[QAccessible::Button] = NSAccessibilityButtonRole;
roleMap[QAccessible::EditableText] = NSAccessibilityTextFieldRole;
roleMap[QAccessible::Link] = NSAccessibilityLinkRole;
@@ -125,7 +124,7 @@ static void populateRoleMap()
roleMap[QAccessible::Splitter] = NSAccessibilitySplitGroupRole;
roleMap[QAccessible::List] = NSAccessibilityListRole;
roleMap[QAccessible::ListItem] = NSAccessibilityStaticTextRole;
- roleMap[QAccessible::Cell] = NSAccessibilityStaticTextRole;
+ roleMap[QAccessible::Cell] = NSAccessibilityCellRole;
roleMap[QAccessible::Client] = NSAccessibilityGroupRole;
roleMap[QAccessible::Paragraph] = NSAccessibilityGroupRole;
roleMap[QAccessible::Section] = NSAccessibilityGroupRole;
@@ -137,6 +136,7 @@ static void populateRoleMap()
roleMap[QAccessible::Note] = NSAccessibilityGroupRole;
roleMap[QAccessible::ComplementaryContent] = NSAccessibilityGroupRole;
roleMap[QAccessible::Graphic] = NSAccessibilityImageRole;
+ roleMap[QAccessible::Tree] = NSAccessibilityOutlineRole;
}
/*
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
index 1f121e2fd8..a96ab55735 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
@@ -15,7 +15,9 @@ QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QMacAccessibilityElement, NSObject <NSAcces
- (instancetype)initWithId:(QAccessible::Id)anId;
- (instancetype)initWithId:(QAccessible::Id)anId role:(NSAccessibilityRole)role;
+ (instancetype)elementWithId:(QAccessible::Id)anId;
++ (instancetype)elementWithInterface:(QAccessibleInterface *)iface;
- (void)updateTableModel;
+- (QAccessibleInterface *)qtInterface;
)
#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
index 68e7947162..8d4d6d683d 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
@@ -9,12 +9,17 @@
#include "qcocoawindow.h"
#include "qcocoascreen.h"
+#include <QtCore/qlogging.h>
#include <QtGui/private/qaccessiblecache_p.h>
#include <QtGui/private/qaccessiblebridgeutils_p.h>
#include <QtGui/qaccessible.h>
QT_USE_NAMESPACE
+Q_LOGGING_CATEGORY(lcAccessibilityTable, "qt.accessibility.table")
+
+using namespace Qt::Literals::StringLiterals;
+
#if QT_CONFIG(accessibility)
/**
@@ -80,6 +85,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
@implementation QMacAccessibilityElement {
QAccessible::Id axid;
+ int m_rowIndex;
+ int m_columnIndex;
// used by NSAccessibilityTable
NSMutableArray<QMacAccessibilityElement *> *rows; // corresponds to accessibilityRows
@@ -105,12 +112,65 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
self = [super init];
if (self) {
axid = anId;
+ m_rowIndex = -1;
+ m_columnIndex = -1;
rows = nil;
columns = nil;
synthesizedRole = role;
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (iface && iface->tableInterface() && !synthesizedRole)
- [self updateTableModel];
+ // table: if this is not created as an element managed by the table, then
+ // it's either the table itself, or an element created for an already existing
+ // cell interface (or an element that's not at all related to a table).
+ if (!synthesizedRole) {
+ if (QAccessibleInterface *iface = QAccessible::accessibleInterface(axid)) {
+ if (iface->tableInterface()) {
+ [self updateTableModel];
+ } else if (const auto *cell = iface->tableCellInterface()) {
+ // If we create an element for a table cell, initialize it with row/column
+ // and insert it into the corresponding row's columns array.
+ m_rowIndex = cell->rowIndex();
+ m_columnIndex = cell->columnIndex();
+ QAccessibleInterface *table = cell->table();
+ Q_ASSERT(table);
+ QAccessibleTableInterface *tableInterface = table->tableInterface();
+ if (tableInterface) {
+ auto *tableElement = [QMacAccessibilityElement elementWithInterface:table];
+ Q_ASSERT(tableElement);
+ if (!tableElement->rows
+ || int(tableElement->rows.count) <= m_rowIndex
+ || int(tableElement->rows.count) != tableInterface->rowCount()) {
+ qCWarning(lcAccessibilityTable)
+ << "Cell requested for row" << m_rowIndex << "is out of"
+ << "bounds for table with" << (tableElement->rows ?
+ tableElement->rows.count : tableInterface->rowCount())
+ << "rows! Resizing table model.";
+ [tableElement updateTableModel];
+ }
+
+ Q_ASSERT(tableElement->rows);
+ Q_ASSERT(int(tableElement->rows.count) > m_rowIndex);
+
+ auto *rowElement = tableElement->rows[m_rowIndex];
+ if (!rowElement->columns || int(rowElement->columns.count) != tableInterface->columnCount()) {
+ if (rowElement->columns) {
+ qCWarning(lcAccessibilityTable)
+ << "Table representation column count is out of sync:"
+ << rowElement->columns.count << "!=" << tableInterface->columnCount();
+ }
+ rowElement->columns = [rowElement populateTableRow:rowElement->columns
+ count:tableInterface->columnCount()];
+ }
+
+ qCDebug(lcAccessibilityTable) << "Creating cell representation for"
+ << m_rowIndex << m_columnIndex
+ << "in table with"
+ << tableElement->rows.count << "rows and"
+ << rowElement->columns.count << "columns";
+
+ rowElement->columns[m_columnIndex] = self;
+ }
+ }
+ }
+ }
}
return self;
@@ -126,16 +186,23 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
QMacAccessibilityElement *element = cache->elementForId(anId);
if (!element) {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(anId);
- Q_ASSERT(iface);
- if (!iface || !iface->isValid())
- return nil;
+ Q_ASSERT(QAccessible::accessibleInterface(anId));
element = [[self alloc] initWithId:anId];
cache->insertElement(anId, element);
}
return element;
}
++ (instancetype)elementWithInterface:(QAccessibleInterface *)iface
+{
+ Q_ASSERT(iface);
+ if (!iface)
+ return nil;
+
+ const QAccessible::Id anId = QAccessible::uniqueId(iface);
+ return [self elementWithId:anId];
+}
+
- (void)invalidate {
axid = 0;
rows = nil;
@@ -173,8 +240,11 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
- (NSMutableArray *)populateTableArray:(NSMutableArray *)array role:(NSAccessibilityRole)role count:(int)count
{
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (iface && iface->isValid()) {
+ if (QAccessibleInterface *iface = self.qtInterface) {
+ if (array && int(array.count) != count) {
+ [array release];
+ array = nil;
+ }
if (!array) {
array = [NSMutableArray<QMacAccessibilityElement *> arrayWithCapacity:count];
[array retain];
@@ -187,6 +257,10 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
QMacAccessibilityElement *element =
[[QMacAccessibilityElement alloc] initWithId:axid role:role];
if (element) {
+ if (role == NSAccessibilityRowRole)
+ element->m_rowIndex = n;
+ else if (role == NSAccessibilityColumnRole)
+ element->m_columnIndex = n;
[array addObject:element];
[element release];
} else {
@@ -198,29 +272,99 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
return nil;
}
+- (NSMutableArray *)populateTableRow:(NSMutableArray *)array count:(int)count
+{
+ Q_ASSERT(synthesizedRole == NSAccessibilityRowRole);
+ if (array && int(array.count) != count) {
+ [array release];
+ array = nil;
+ }
+
+ if (!array) {
+ array = [NSMutableArray<QMacAccessibilityElement *> arrayWithCapacity:count];
+ [array retain];
+ // When macOS asks for the children of a row, then we populate the row's column
+ // array with synthetic elements as place holders. This way, we don't have to
+ // create QAccessibleInterfaces for every cell before they are really needed.
+ // We don't add those synthetic elements into the cache, and we give them the
+ // same axid as the table. This way, we can get easily to the table, and from
+ // there to the QAccessibleInterface for the cell, when we have to eventually
+ // associate such an interface with the element (at which point it is no longer
+ // a placeholder).
+ for (int n = 0; n < count; ++n) {
+ // columns will have same axid as table (but not inserted in cache)
+ QMacAccessibilityElement *cell =
+ [[QMacAccessibilityElement alloc] initWithId:axid role:NSAccessibilityCellRole];
+ if (cell) {
+ cell->m_rowIndex = m_rowIndex;
+ cell->m_columnIndex = n;
+ [array addObject:cell];
+ }
+ }
+ }
+ Q_ASSERT(array);
+ return array;
+}
- (void)updateTableModel
{
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (iface && iface->isValid()) {
+ if (QAccessibleInterface *iface = self.qtInterface) {
if (QAccessibleTableInterface *table = iface->tableInterface()) {
Q_ASSERT(!self.isManagedByParent);
+ qCDebug(lcAccessibilityTable) << "Updating table representation with"
+ << table->rowCount() << table->columnCount();
rows = [self populateTableArray:rows role:NSAccessibilityRowRole count:table->rowCount()];
columns = [self populateTableArray:columns role:NSAccessibilityColumnRole count:table->columnCount()];
}
}
}
+- (QAccessibleInterface *)qtInterface
+{
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface || !iface->isValid())
+ return nullptr;
+
+ // If this is a placeholder element for a table cell, associate it with the
+ // cell interface (which will be created now, if needed). The current axid is
+ // for the table to which the cell belongs, so iface is pointing at the table.
+ if (synthesizedRole == NSAccessibilityCellRole) {
+ // get the cell interface - there must be a valid one
+ QAccessibleTableInterface *table = iface->tableInterface();
+ Q_ASSERT(table);
+ QAccessibleInterface *cell = table->cellAt(m_rowIndex, m_columnIndex);
+ if (!cell)
+ return nullptr;
+ Q_ASSERT(cell->isValid());
+ iface = cell;
+
+ // no longer a placeholder
+ axid = QAccessible::uniqueId(cell);
+ synthesizedRole = nil;
+
+ QAccessibleCache *cache = QAccessibleCache::instance();
+ if (QMacAccessibilityElement *cellElement = cache->elementForId(axid)) {
+ // there already is another, non-placeholder element in the cache
+ Q_ASSERT(cellElement->synthesizedRole == nil);
+ // we have to release it if it's not us
+ if (cellElement != self) {
+ // for the same cell position
+ Q_ASSERT(cellElement->m_rowIndex == m_rowIndex && cellElement->m_columnIndex == m_columnIndex);
+ [cellElement release];
+ }
+ }
+
+ cache->insertElement(axid, self);
+ }
+ return iface;
+}
+
//
// accessibility protocol
//
- (BOOL)isAccessibilityFocused
{
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid()) {
- return false;
- }
// Just check if the app thinks we're focused.
id focusedElement = NSApp.accessibilityApplicationFocusedUIElement;
return [focusedElement isEqual:self];
@@ -240,31 +384,33 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (NSString *) accessibilityRole {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return NSAccessibilityUnknownRole;
+ // shortcut for cells, rows, and columns in a table
if (synthesizedRole)
return synthesizedRole;
- return QCocoaAccessible::macRole(iface);
+ if (QAccessibleInterface *iface = self.qtInterface)
+ return QCocoaAccessible::macRole(iface);
+ return NSAccessibilityUnknownRole;
}
- (NSString *) accessibilitySubRole {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return NSAccessibilityUnknownRole;
- return QCocoaAccessible::macSubrole(iface);
+ if (QAccessibleInterface *iface = self.qtInterface)
+ return QCocoaAccessible::macSubrole(iface);
+ return NSAccessibilityUnknownRole;
}
- (NSString *) accessibilityRoleDescription {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return NSAccessibilityUnknownRole;
- return NSAccessibilityRoleDescription(self.accessibilityRole, self.accessibilitySubRole);
+ if (QAccessibleInterface *iface = self.qtInterface)
+ return NSAccessibilityRoleDescription(self.accessibilityRole, self.accessibilitySubRole);
+ return NSAccessibilityUnknownRole;
}
- (NSArray *) accessibilityChildren {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ // shortcut for cells
+ if (synthesizedRole == NSAccessibilityCellRole)
+ return nil;
+
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return nil;
if (QAccessibleTableInterface *table = iface->tableInterface()) {
// either a table or table rows/columns
@@ -320,30 +466,39 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
} else if (synthesizedRole == NSAccessibilityRowRole) {
// axid matches the parent table axid so that we can easily find the parent table
// children of row are cell/any items
- QMacAccessibilityElement *tableElement = [QMacAccessibilityElement elementWithId:axid];
- Q_ASSERT(tableElement->rows);
- NSUInteger rowIndex = [tableElement->rows indexOfObjectIdenticalTo:self];
- Q_ASSERT(rowIndex != NSNotFound);
- int numColumns = table->columnCount();
- NSMutableArray<QMacAccessibilityElement *> *cells =
- [NSMutableArray<QMacAccessibilityElement *> arrayWithCapacity:numColumns];
- for (int i = 0; i < numColumns; ++i) {
- QAccessibleInterface *cell = table->cellAt(rowIndex, i);
- if (cell && cell->isValid()) {
- QAccessible::Id cellId = QAccessible::uniqueId(cell);
- QMacAccessibilityElement *element =
- [QMacAccessibilityElement elementWithId:cellId];
- if (element) {
- [cells addObject:element];
- }
- }
- }
- return NSAccessibilityUnignoredChildren(cells);
+ Q_ASSERT(m_rowIndex >= 0);
+ const int numColumns = table->columnCount();
+ columns = [self populateTableRow:columns count:numColumns];
+ return NSAccessibilityUnignoredChildren(columns);
}
}
return QCocoaAccessible::unignoredChildren(iface);
}
+- (NSArray *) accessibilitySelectedChildren {
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface || !iface->isValid())
+ return nil;
+
+ QAccessibleSelectionInterface *selection = iface->selectionInterface();
+ if (!selection)
+ return nil;
+
+ const QList<QAccessibleInterface *> selectedList = selection->selectedItems();
+ const qsizetype numSelected = selectedList.size();
+ NSMutableArray<QMacAccessibilityElement *> *selectedChildren =
+ [NSMutableArray<QMacAccessibilityElement *> arrayWithCapacity:numSelected];
+ for (QAccessibleInterface *selectedChild : selectedList) {
+ if (selectedChild && selectedChild->isValid()) {
+ QAccessible::Id id = QAccessible::uniqueId(selectedChild);
+ QMacAccessibilityElement *element = [QMacAccessibilityElement elementWithId:id];
+ if (element)
+ [selectedChildren addObject:element];
+ }
+ }
+ return NSAccessibilityUnignoredChildren(selectedChildren);
+}
+
- (id) accessibilityWindow {
// We're in the same window as our parent.
return [self.accessibilityParent accessibilityWindow];
@@ -355,26 +510,35 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (NSString *) accessibilityTitle {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return nil;
- if (iface->role() == QAccessible::StaticText)
- return nil;
- if (self.isManagedByParent)
- return nil;
- return iface->text(QAccessible::Name).toNSString();
+ if (QAccessibleInterface *iface = self.qtInterface) {
+ if (iface->role() == QAccessible::StaticText)
+ return nil;
+ if (self.isManagedByParent)
+ return nil;
+ return iface->text(QAccessible::Name).toNSString();
+ }
+ return nil;
}
- (BOOL) isAccessibilityEnabled {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return false;
- return !iface->state().disabled;
+ if (QAccessibleInterface *iface = self.qtInterface)
+ return !iface->state().disabled;
+ return false;
}
- (id)accessibilityParent {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ if (synthesizedRole == NSAccessibilityCellRole) {
+ // a synthetic cell without interface - shortcut to the row
+ QMacAccessibilityElement *tableElement =
+ [QMacAccessibilityElement elementWithId:axid];
+ Q_ASSERT(tableElement && tableElement->rows);
+ Q_ASSERT(int(tableElement->rows.count) > m_rowIndex);
+ QMacAccessibilityElement *rowElement = tableElement->rows[m_rowIndex];
+ return rowElement;
+ }
+
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return nil;
if (self.isManagedByParent) {
@@ -389,23 +553,23 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
if (QAccessibleInterface *parent = iface->parent()) {
if (parent->tableInterface()) {
- if (QAccessibleTableCellInterface *cell = iface->tableCellInterface()) {
- // parent of cell should be row
- QAccessible::Id parentId = QAccessible::uniqueId(parent);
- QMacAccessibilityElement *tableElement =
- [QMacAccessibilityElement elementWithId:parentId];
-
- const int rowIndex = cell->rowIndex();
- if (tableElement->rows && int([tableElement->rows count]) > rowIndex) {
- QMacAccessibilityElement *rowElement = tableElement->rows[rowIndex];
- return NSAccessibilityUnignoredAncestor(rowElement);
- }
- }
- }
- if (parent->role() != QAccessible::Application) {
- QAccessible::Id parentId = QAccessible::uniqueId(parent);
- return NSAccessibilityUnignoredAncestor([QMacAccessibilityElement elementWithId: parentId]);
+ QMacAccessibilityElement *tableElement =
+ [QMacAccessibilityElement elementWithInterface:parent];
+
+ // parent of cell should be row
+ int rowIndex = -1;
+ if (m_rowIndex >= 0 && m_columnIndex >= 0)
+ rowIndex = m_rowIndex;
+ else if (QAccessibleTableCellInterface *cell = iface->tableCellInterface())
+ rowIndex = cell->rowIndex();
+ Q_ASSERT(tableElement->rows);
+ if (rowIndex > int([tableElement->rows count]) || rowIndex == -1)
+ return nil;
+ QMacAccessibilityElement *rowElement = tableElement->rows[rowIndex];
+ return NSAccessibilityUnignoredAncestor(rowElement);
}
+ if (parent->role() != QAccessible::Application)
+ return NSAccessibilityUnignoredAncestor([QMacAccessibilityElement elementWithInterface: parent]);
}
if (QWindow *window = iface->window()) {
@@ -419,8 +583,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (NSRect)accessibilityFrame {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return NSZeroRect;
QRect rect;
@@ -437,10 +601,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
int &row = isRow ? cellPos.ry() : cellPos.rx();
int &col = isRow ? cellPos.rx() : cellPos.ry();
- QMacAccessibilityElement *tableElement =
- [QMacAccessibilityElement elementWithId:axid];
- NSArray *tracks = isRow ? tableElement->rows : tableElement->columns;
- NSUInteger trackIndex = [tracks indexOfObjectIdenticalTo:self];
+ NSUInteger trackIndex = self.accessibilityIndex;
if (trackIndex != NSNotFound) {
row = int(trackIndex);
if (QAccessibleInterface *firstCell = table->cellAt(cellPos.y(), cellPos.x())) {
@@ -463,71 +624,50 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (NSString*)accessibilityLabel {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid()) {
- qWarning() << "Called accessibilityLabel on invalid object: " << axid;
- return nil;
- }
- return iface->text(QAccessible::Description).toNSString();
-}
-
-- (void)setAccessibilityLabel:(NSString*)label{
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return;
- iface->setText(QAccessible::Description, QString::fromNSString(label));
-}
-
-- (id) accessibilityMinValue:(QAccessibleInterface*)iface {
- if (QAccessibleValueInterface *val = iface->valueInterface())
- return @(val->minimumValue().toDouble());
+ if (QAccessibleInterface *iface = self.qtInterface)
+ return iface->text(QAccessible::Description).toNSString();
+ qWarning() << "Called accessibilityLabel on invalid object: " << axid;
return nil;
}
-- (id) accessibilityMaxValue:(QAccessibleInterface*)iface {
- if (QAccessibleValueInterface *val = iface->valueInterface())
- return @(val->maximumValue().toDouble());
- return nil;
+- (void)setAccessibilityLabel:(NSString*)label{
+ if (QAccessibleInterface *iface = self.qtInterface)
+ iface->setText(QAccessible::Description, QString::fromNSString(label));
}
- (id) accessibilityValue {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return nil;
-
- // VoiceOver asks for the value attribute for all elements. Return nil
- // if we don't want the element to have a value attribute.
- if (!QCocoaAccessible::hasValueAttribute(iface))
- return nil;
-
- return QCocoaAccessible::getValueAttribute(iface);
+ if (QAccessibleInterface *iface = self.qtInterface) {
+ // VoiceOver asks for the value attribute for all elements. Return nil
+ // if we don't want the element to have a value attribute.
+ if (QCocoaAccessible::hasValueAttribute(iface))
+ return QCocoaAccessible::getValueAttribute(iface);
+ }
+ return nil;
}
- (NSInteger) accessibilityNumberOfCharacters {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return 0;
- if (QAccessibleTextInterface *text = iface->textInterface())
- return text->characterCount();
+ if (QAccessibleInterface *iface = self.qtInterface) {
+ if (QAccessibleTextInterface *text = iface->textInterface())
+ return text->characterCount();
+ }
return 0;
}
- (NSString *) accessibilitySelectedText {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return nil;
- if (QAccessibleTextInterface *text = iface->textInterface()) {
- int start = 0;
- int end = 0;
- text->selection(0, &start, &end);
- return text->text(start, end).toNSString();
+ if (QAccessibleInterface *iface = self.qtInterface) {
+ if (QAccessibleTextInterface *text = iface->textInterface()) {
+ int start = 0;
+ int end = 0;
+ text->selection(0, &start, &end);
+ return text->text(start, end).toNSString();
+ }
}
return nil;
}
- (NSRange) accessibilitySelectedTextRange {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return NSRange();
if (QAccessibleTextInterface *text = iface->textInterface()) {
int start = 0;
@@ -544,8 +684,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (NSInteger)accessibilityLineForIndex:(NSInteger)index {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return 0;
if (QAccessibleTextInterface *text = iface->textInterface()) {
QString textToPos = text->text(0, index);
@@ -555,8 +695,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (NSRange)accessibilityVisibleCharacterRange {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return NSRange();
// FIXME This is not correct and may impact performance for big texts
if (QAccessibleTextInterface *text = iface->textInterface())
@@ -565,8 +705,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (NSInteger) accessibilityInsertionPointLineNumber {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return 0;
if (QAccessibleTextInterface *text = iface->textInterface()) {
int position = text->cursorPosition();
@@ -577,8 +717,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
- (NSArray *)accessibilityParameterizedAttributeNames {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid()) {
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface) {
qWarning() << "Called attribute on invalid object: " << axid;
return nil;
}
@@ -601,8 +741,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (id)accessibilityAttributeValue:(NSString *)attribute forParameter:(id)parameter {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid()) {
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface) {
qWarning() << "Called attribute on invalid object: " << axid;
return nil;
}
@@ -642,7 +782,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
QRectF rect;
if (range.length > 0) {
NSUInteger position = range.location + range.length - 1;
- if (position > range.location && iface->textInterface()->text(position, position + 1) == QStringLiteral("\n"))
+ if (position > range.location && iface->textInterface()->text(position, position + 1) == "\n"_L1)
--position;
QRect lastRect = iface->textInterface()->characterRect(position);
rect = firstRect.united(lastRect);
@@ -670,8 +810,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (BOOL)accessibilityIsAttributeSettable:(NSString *)attribute {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return NO;
if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
@@ -689,8 +829,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (void)accessibilitySetValue:(id)value forAttribute:(NSString *)attribute {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return;
if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
if (QAccessibleActionInterface *action = iface->actionInterface())
@@ -718,8 +858,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
- (NSArray *)accessibilityActionNames {
NSMutableArray *nsActions = [[NSMutableArray new] autorelease];
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return nsActions;
const QStringList &supportedActionNames = QAccessibleBridgeUtils::effectiveActionNames(iface);
@@ -733,8 +873,8 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (NSString *)accessibilityActionDescription:(NSString *)action {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface)
return nil; // FIXME is that the right return type??
QString qtAction = QCocoaAccessible::translateAction(action, iface);
QString description;
@@ -751,8 +891,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (void)accessibilityPerformAction:(NSString *)action {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (iface && iface->isValid()) {
+ if (QAccessibleInterface *iface = self.qtInterface) {
const QString qtAction = QCocoaAccessible::translateAction(action, iface);
QAccessibleBridgeUtils::performEffectiveAction(iface, qtAction);
}
@@ -761,15 +900,20 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
// misc
- (BOOL)accessibilityIsIgnored {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid())
- return true;
- return QCocoaAccessible::shouldBeIgnored(iface);
+ // Short-cut for placeholders and synthesized elements. Working around a bug
+ // that corrups lists returned by NSAccessibilityUnignoredChildren, otherwise
+ // we could ignore rows and columns that are outside the table.
+ if (self.isManagedByParent)
+ return false;
+
+ if (QAccessibleInterface *iface = self.qtInterface)
+ return QCocoaAccessible::shouldBeIgnored(iface);
+ return true;
}
- (id)accessibilityHitTest:(NSPoint)point {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (!iface || !iface->isValid()) {
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface) {
// qDebug("Hit test: INVALID");
return NSAccessibilityUnignoredAncestor(self);
}
@@ -788,26 +932,23 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
childInterface = childOfChildInterface;
} while (childOfChildInterface && childOfChildInterface->isValid());
- QAccessible::Id childId = QAccessible::uniqueId(childInterface);
// hit a child, forward to child accessible interface.
- QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithId:childId];
+ QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithInterface:childInterface];
if (accessibleElement)
return NSAccessibilityUnignoredAncestor(accessibleElement);
return NSAccessibilityUnignoredAncestor(self);
}
- (id)accessibilityFocusedUIElement {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
-
- if (!iface || !iface->isValid()) {
+ QAccessibleInterface *iface = self.qtInterface;
+ if (!iface) {
qWarning("FocusedUIElement for INVALID");
return nil;
}
QAccessibleInterface *childInterface = iface->focusChild();
if (childInterface && childInterface->isValid()) {
- QAccessible::Id childAxid = QAccessible::uniqueId(childInterface);
- QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithId:childAxid];
+ QMacAccessibilityElement *accessibleElement = [QMacAccessibilityElement elementWithInterface:childInterface];
return NSAccessibilityUnignoredAncestor(accessibleElement);
}
@@ -815,8 +956,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (NSString *) accessibilityHelp {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (iface && iface->isValid()) {
+ if (QAccessibleInterface *iface = self.qtInterface) {
const QString helpText = iface->text(QAccessible::Help);
if (!helpText.isEmpty())
return helpText.toNSString();
@@ -829,19 +969,17 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
*/
- (NSInteger) accessibilityIndex {
NSInteger index = 0;
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (iface && iface->isValid()) {
+ if (synthesizedRole == NSAccessibilityCellRole)
+ return m_columnIndex;
+ if (QAccessibleInterface *iface = self.qtInterface) {
if (self.isManagedByParent) {
// axid matches the parent table axid so that we can easily find the parent table
// children of row are cell/any items
if (QAccessibleTableInterface *table = iface->tableInterface()) {
- QMacAccessibilityElement *tableElement = [QMacAccessibilityElement elementWithId:axid];
- NSArray *track = synthesizedRole == NSAccessibilityRowRole
- ? tableElement->rows : tableElement->columns;
- if (track) {
- NSUInteger trackIndex = [track indexOfObjectIdenticalTo:self];
- index = (NSInteger)trackIndex;
- }
+ if (m_rowIndex >= 0)
+ index = NSInteger(m_rowIndex);
+ else if (m_columnIndex >= 0)
+ index = NSInteger(m_columnIndex);
}
}
}
@@ -849,18 +987,18 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
}
- (NSArray *) accessibilityRows {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (iface && iface->isValid() && iface->tableInterface() && !synthesizedRole) {
- if (rows)
+ if (!synthesizedRole && rows) {
+ QAccessibleInterface *iface = self.qtInterface;
+ if (iface && iface->tableInterface())
return NSAccessibilityUnignoredChildren(rows);
}
return nil;
}
- (NSArray *) accessibilityColumns {
- QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
- if (iface && iface->isValid() && iface->tableInterface() && !synthesizedRole) {
- if (columns)
+ if (!synthesizedRole && columns) {
+ QAccessibleInterface *iface = self.qtInterface;
+ if (iface && iface->tableInterface())
return NSAccessibilityUnignoredChildren(columns);
}
return nil;
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
index bb7b5c3c0c..d642115926 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
@@ -148,7 +148,8 @@ QT_USE_NAMESPACE
- (void)applicationWillFinishLaunching:(NSNotification *)notification
{
- Q_UNUSED(notification);
+ if ([reflectionDelegate respondsToSelector:_cmd])
+ [reflectionDelegate applicationWillFinishLaunching:notification];
/*
From the Cocoa documentation: "A good place to install event handlers
@@ -185,15 +186,34 @@ QT_USE_NAMESPACE
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
- Q_UNUSED(aNotification);
+ if ([reflectionDelegate respondsToSelector:_cmd])
+ [reflectionDelegate applicationDidFinishLaunching:aNotification];
+
inLaunch = false;
if (qEnvironmentVariableIsEmpty("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM")) {
- // Move the application window to front to avoid launching behind the terminal.
- // Ignoring other apps is necessary (we must ignore the terminal), but makes
- // Qt apps play slightly less nice with other apps when lanching from Finder
- // (See the activateIgnoringOtherApps docs.)
- [[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
+ auto frontmostApplication = NSWorkspace.sharedWorkspace.frontmostApplication;
+ auto currentApplication = NSRunningApplication.currentApplication;
+ if (frontmostApplication != currentApplication) {
+ // Move the application to front to avoid launching behind the terminal.
+ // Ignoring other apps is necessary (we must ignore the terminal), but makes
+ // Qt apps play slightly less nice with other apps when launching from Finder
+ // (see the activateIgnoringOtherApps docs). FIXME: Try to distinguish between
+ // being non-active here because another application stole activation in the
+ // time it took us to launch from Finder, and being non-active because we were
+ // launched from Terminal or something that doesn't activate us at all.
+ qCDebug(lcQpaApplication) << "Launched with" << frontmostApplication
+ << "as frontmost application. Activating" << currentApplication << "instead.";
+ [NSApplication.sharedApplication activateIgnoringOtherApps:YES];
+ }
+
+ // Qt windows are typically shown in main(), at which point the application
+ // is not active yet. When the application is activated, either externally
+ // or via the override above, it will only bring the main and key windows
+ // forward, which differs from the behavior if these windows had been shown
+ // once the application was already active. To work around this, we explicitly
+ // activate the current application again, bringing all windows to the front.
+ [currentApplication activateWithOptions:NSApplicationActivateAllWindows];
}
QCocoaMenuBar::insertWindowMenu();
@@ -314,21 +334,72 @@ QT_USE_NAMESPACE
[self doesNotRecognizeSelector:invocationSelector];
}
+- (BOOL)application:(NSApplication *)application continueUserActivity:(NSUserActivity *)userActivity
+ restorationHandler:(void(^)(NSArray<id<NSUserActivityRestoring>> *restorableObjects))restorationHandler
+{
+ // Check if eg. user has installed an app delegate capable of handling this
+ if ([reflectionDelegate respondsToSelector:_cmd]
+ && [reflectionDelegate application:application continueUserActivity:userActivity
+ restorationHandler:restorationHandler] == YES) {
+ return YES;
+ }
+
+ if (!QGuiApplication::instance())
+ return NO;
+
+ if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
+ QCocoaIntegration *cocoaIntegration = QCocoaIntegration::instance();
+ Q_ASSERT(cocoaIntegration);
+ return cocoaIntegration->services()->handleUrl(QUrl::fromNSURL(userActivity.webpageURL));
+ }
+
+ return NO;
+}
+
- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{
Q_UNUSED(replyEvent);
+
NSString *urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
+ const QString qurlString = QString::fromNSString(urlString);
+
+ if (event.eventClass == kInternetEventClass && event.eventID == kAEGetURL) {
+ // 'GURL' (Get URL) event this application should handle
+ if (!QGuiApplication::instance())
+ return;
+ QCocoaIntegration *cocoaIntegration = QCocoaIntegration::instance();
+ Q_ASSERT(cocoaIntegration);
+ cocoaIntegration->services()->handleUrl(QUrl(qurlString));
+ return;
+ }
+
// The string we get from the requesting application might not necessarily meet
// QUrl's requirement for a IDN-compliant host. So if we can't parse into a QUrl,
// then we pass the string on to the application as the name of a file (and
// QFileOpenEvent::file is not guaranteed to be the path to a local, open'able
// file anyway).
- const QString qurlString = QString::fromNSString(urlString);
if (const QUrl url(qurlString); url.isValid())
QWindowSystemInterface::handleFileOpenEvent(url);
else
QWindowSystemInterface::handleFileOpenEvent(qurlString);
}
+
+- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)application
+{
+ if (@available(macOS 12, *)) {
+ if ([reflectionDelegate respondsToSelector:_cmd])
+ return [reflectionDelegate applicationSupportsSecureRestorableState:application];
+ }
+
+ // We don't support or implement state restorations via the AppKit
+ // state restoration APIs, but if we did, we would/should support
+ // secure state restoration. This is the default for apps linked
+ // against the macOS 14 SDK, but as we target versions below that
+ // as well we need to return YES here explicitly to silence a runtime
+ // warning.
+ return YES;
+}
+
@end
@implementation QCocoaApplicationDelegate (Menus)
@@ -371,7 +442,6 @@ QT_USE_NAMESPACE
if (!platformItem || platformItem->menu())
return;
- QScopedScopeLevelCounter scopeLevelCounter(QGuiApplicationPrivate::instance()->threadData.loadRelaxed());
QGuiApplicationPrivate::modifier_buttons = QAppleKeyMapper::fromCocoaModifiers([NSEvent modifierFlags]);
static QMetaMethod activatedSignal = QMetaMethod::fromSignal(&QCocoaMenuItem::activated);
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h
index 6db88f923c..71b6015a54 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.h
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h
@@ -54,6 +54,7 @@ private:
bool eventFilter(QObject *watched, QEvent *event) override;
QSize m_requestedSize;
+ QRegion m_staticContents;
class GraphicsBuffer : public QIOSurfaceGraphicsBuffer
{
@@ -78,7 +79,8 @@ private:
bool recreateBackBufferIfNeeded();
void finalizeBackBuffer();
- void preserveFromFrontBuffer(const QRegion &region, const QPoint &offset = QPoint());
+ void blitBuffer(GraphicsBuffer *sourceBuffer, const QRegion &sourceRegion,
+ GraphicsBuffer *destinationBuffer, const QPoint &destinationOffset = QPoint());
void backingPropertiesChanged();
QMacNotificationObserver m_backingPropertiesObserver;
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
index 8f50bc5834..b211b5d02d 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
@@ -23,8 +23,9 @@ QCocoaBackingStore::QCocoaBackingStore(QWindow *window)
QCFType<CGColorSpaceRef> QCocoaBackingStore::colorSpace() const
{
- NSView *view = static_cast<QCocoaWindow *>(window()->handle())->view();
- return QCFType<CGColorSpaceRef>::constructFromGet(view.window.colorSpace.CGColorSpace);
+ const auto *platformWindow = static_cast<QCocoaWindow *>(window()->handle());
+ const QNSView *view = qnsview_cast(platformWindow->view());
+ return QCFType<CGColorSpaceRef>::constructFromGet(view.colorSpace.CGColorSpace);
}
// ----------------------------------------------------------------------------
@@ -72,12 +73,11 @@ bool QCALayerBackingStore::eventFilter(QObject *watched, QEvent *event)
void QCALayerBackingStore::resize(const QSize &size, const QRegion &staticContents)
{
- qCDebug(lcQpaBackingStore) << "Resize requested to" << size;
-
- if (!staticContents.isNull())
- qCWarning(lcQpaBackingStore) << "QCALayerBackingStore does not support static contents";
+ qCDebug(lcQpaBackingStore) << "Resize requested to" << size
+ << "with static contents" << staticContents;
m_requestedSize = size;
+ m_staticContents = staticContents;
}
void QCALayerBackingStore::beginPaint(const QRegion &region)
@@ -189,11 +189,50 @@ bool QCALayerBackingStore::recreateBackBufferIfNeeded()
}
#endif
- qCInfo(lcQpaBackingStore) << "Creating surface of" << requestedBufferSize
- << "based on requested" << m_requestedSize << "and dpr =" << devicePixelRatio;
+ qCInfo(lcQpaBackingStore)<< "Creating surface of" << requestedBufferSize
+ << "for" << window() << "based on requested" << m_requestedSize
+ << "dpr =" << devicePixelRatio << "and color space" << colorSpace();
static auto pixelFormat = QImage::toPixelFormat(QImage::Format_ARGB32_Premultiplied);
- m_buffers.back().reset(new GraphicsBuffer(requestedBufferSize, devicePixelRatio, pixelFormat, colorSpace()));
+ auto *newBackBuffer = new GraphicsBuffer(requestedBufferSize, devicePixelRatio, pixelFormat, colorSpace());
+
+ if (!m_staticContents.isEmpty() && m_buffers.back()) {
+ // We implicitly support static backingstore content as a result of
+ // finalizing the back buffer on flush, where we copy any non-painted
+ // areas from the front buffer. But there is no guarantee that a resize
+ // will always come after a flush, where we have a pristine front buffer
+ // to copy from. It may come after a few begin/endPaints, where the back
+ // buffer then contains (part of) the latest state. We also have the case
+ // of single-buffered backingstore, where the front and back buffer is
+ // the same, which means we must do the copy from the old back buffer
+ // to the newly resized buffer now, before we replace it below.
+
+ // If the back buffer has been partially filled already, we need to
+ // copy parts of the static content from that. The rest we copy from
+ // the front buffer.
+ const QRegion backBufferRegion = m_staticContents - m_buffers.back()->dirtyRegion;
+ const QRegion frontBufferRegion = m_staticContents - backBufferRegion;
+
+ qCInfo(lcQpaBackingStore) << "Preserving static content" << backBufferRegion
+ << "from back buffer, and" << frontBufferRegion << "from front buffer";
+
+ newBackBuffer->lock(QPlatformGraphicsBuffer::SWWriteAccess);
+ blitBuffer(m_buffers.back().get(), backBufferRegion, newBackBuffer);
+ Q_ASSERT(frontBufferRegion.isEmpty() || m_buffers.front());
+ blitBuffer(m_buffers.front().get(), frontBufferRegion, newBackBuffer);
+ newBackBuffer->unlock();
+
+ // The new back buffer now is valid for the static contents region.
+ // We don't need to maintain the static contents region for resizes
+ // of any other buffers in the swap chain, as these will finalize
+ // their content on flush from the buffer we just filled, and we
+ // don't need to mark them dirty for the area we just filled, as
+ // new buffers are fully dirty when created.
+ newBackBuffer->dirtyRegion -= m_staticContents;
+ m_staticContents = {};
+ }
+
+ m_buffers.back().reset(newBackBuffer);
return true;
}
@@ -256,7 +295,7 @@ bool QCALayerBackingStore::scroll(const QRegion &region, int dx, int dy)
if (!frontBufferRegion.isEmpty()) {
qCDebug(lcQpaBackingStore) << "Scrolling" << frontBufferRegion << "by copying from front buffer";
- preserveFromFrontBuffer(frontBufferRegion, scrollDelta);
+ blitBuffer(m_buffers.front().get(), frontBufferRegion, m_buffers.back().get(), scrollDelta);
}
m_buffers.back()->unlock();
@@ -440,10 +479,11 @@ void QCALayerBackingStore::backingPropertiesChanged()
qCDebug(lcQpaBackingStore) << "Backing properties for" << window() << "did change";
- qCDebug(lcQpaBackingStore) << "Updating color space of existing buffers";
+ const auto newColorSpace = colorSpace();
+ qCDebug(lcQpaBackingStore) << "Updating color space of existing buffers to" << newColorSpace;
for (auto &buffer : m_buffers) {
if (buffer)
- buffer->setColorSpace(colorSpace());
+ buffer->setColorSpace(newColorSpace);
}
}
@@ -475,54 +515,76 @@ void QCALayerBackingStore::finalizeBackBuffer()
if (!m_buffers.back()->isDirty())
return;
- m_buffers.back()->lock(QPlatformGraphicsBuffer::SWWriteAccess);
- preserveFromFrontBuffer(m_buffers.back()->dirtyRegion);
- m_buffers.back()->unlock();
+ qCDebug(lcQpaBackingStore) << "Finalizing back buffer with dirty region" << m_buffers.back()->dirtyRegion;
+
+ if (m_buffers.back() != m_buffers.front()) {
+ m_buffers.back()->lock(QPlatformGraphicsBuffer::SWWriteAccess);
+ blitBuffer(m_buffers.front().get(), m_buffers.back()->dirtyRegion, m_buffers.back().get());
+ m_buffers.back()->unlock();
+ } else {
+ qCDebug(lcQpaBackingStore) << "Front and back buffer is the same. Can not finalize back buffer.";
+ }
// The back buffer is now completely in sync, ready to be presented
m_buffers.back()->dirtyRegion = QRegion();
}
-void QCALayerBackingStore::preserveFromFrontBuffer(const QRegion &region, const QPoint &offset)
+/*
+ \internal
+
+ Blits \a sourceRegion from \a sourceBuffer to \a destinationBuffer,
+ at offset \a destinationOffset.
+
+ The source buffer is automatically locked for read only access
+ during the blit.
+
+ The destination buffer has to be locked for write access by the
+ caller.
+*/
+
+void QCALayerBackingStore::blitBuffer(GraphicsBuffer *sourceBuffer, const QRegion &sourceRegion,
+ GraphicsBuffer *destinationBuffer, const QPoint &destinationOffset)
{
+ Q_ASSERT(sourceBuffer && destinationBuffer);
+ Q_ASSERT(sourceBuffer != destinationBuffer);
- if (m_buffers.front() == m_buffers.back())
- return; // Nothing to preserve from
+ if (sourceRegion.isEmpty())
+ return;
- qCDebug(lcQpaBackingStore) << "Preserving" << region << "of front buffer to"
- << region.translated(offset) << "of back buffer";
+ qCDebug(lcQpaBackingStore) << "Blitting" << sourceRegion << "of" << sourceBuffer
+ << "to" << sourceRegion.translated(destinationOffset) << "of" << destinationBuffer;
- Q_ASSERT(m_buffers.back()->isLocked() == QPlatformGraphicsBuffer::SWWriteAccess);
+ Q_ASSERT(destinationBuffer->isLocked() == QPlatformGraphicsBuffer::SWWriteAccess);
- m_buffers.front()->lock(QPlatformGraphicsBuffer::SWReadAccess);
- const QImage *frontBuffer = m_buffers.front()->asImage();
+ sourceBuffer->lock(QPlatformGraphicsBuffer::SWReadAccess);
+ const QImage *sourceImage = sourceBuffer->asImage();
- const QRect frontSurfaceBounds(QPoint(0, 0), m_buffers.front()->size());
- const qreal sourceDevicePixelRatio = frontBuffer->devicePixelRatio();
+ const QRect sourceBufferBounds(QPoint(0, 0), sourceBuffer->size());
+ const qreal sourceDevicePixelRatio = sourceImage->devicePixelRatio();
- QPainter painter(m_buffers.back()->asImage());
+ QPainter painter(destinationBuffer->asImage());
painter.setCompositionMode(QPainter::CompositionMode_Source);
// Let painter operate in device pixels, to make it easier to compare coordinates
- const qreal targetDevicePixelRatio = painter.device()->devicePixelRatio();
- painter.scale(1.0 / targetDevicePixelRatio, 1.0 / targetDevicePixelRatio);
+ const qreal destinationDevicePixelRatio = painter.device()->devicePixelRatio();
+ painter.scale(1.0 / destinationDevicePixelRatio, 1.0 / destinationDevicePixelRatio);
- for (const QRect &rect : region) {
+ for (const QRect &rect : sourceRegion) {
QRect sourceRect(rect.topLeft() * sourceDevicePixelRatio,
rect.size() * sourceDevicePixelRatio);
- QRect targetRect((rect.topLeft() + offset) * targetDevicePixelRatio,
- rect.size() * targetDevicePixelRatio);
+ QRect destinationRect((rect.topLeft() + destinationOffset) * destinationDevicePixelRatio,
+ rect.size() * destinationDevicePixelRatio);
#ifdef QT_DEBUG
- if (Q_UNLIKELY(!frontSurfaceBounds.contains(sourceRect.bottomRight()))) {
- qCWarning(lcQpaBackingStore) << "Front buffer too small to preserve"
- << QRegion(sourceRect).subtracted(frontSurfaceBounds);
+ if (Q_UNLIKELY(!sourceBufferBounds.contains(sourceRect.bottomRight()))) {
+ qCWarning(lcQpaBackingStore) << "Source buffer of size" << sourceBuffer->size()
+ << "is too small to blit" << sourceRect;
}
#endif
- painter.drawImage(targetRect, *frontBuffer, sourceRect);
+ painter.drawImage(destinationRect, *sourceImage, sourceRect);
}
- m_buffers.front()->unlock();
+ sourceBuffer->unlock();
}
// ----------------------------------------------------------------------------
diff --git a/src/plugins/platforms/cocoa/qcocoadrag.h b/src/plugins/platforms/cocoa/qcocoadrag.h
index 24485ac6ac..dedf8a7fd9 100644
--- a/src/plugins/platforms/cocoa/qcocoadrag.h
+++ b/src/plugins/platforms/cocoa/qcocoadrag.h
@@ -44,7 +44,7 @@ private:
NSEvent *m_lastEvent;
NSView *m_lastView;
Qt::DropAction m_executed_drop_action;
- QEventLoop internalDragLoop;
+ QEventLoop *m_internalDragLoop = nullptr;
bool maybeDragMultipleItems();
diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm
index 101a13e3c2..a8404889e9 100644
--- a/src/plugins/platforms/cocoa/qcocoadrag.mm
+++ b/src/plugins/platforms/cocoa/qcocoadrag.mm
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <AppKit/AppKit.h>
+#include <UniformTypeIdentifiers/UTCoreTypes.h>
#include "qcocoadrag.h"
#include "qmacclipboard.h"
@@ -161,8 +162,7 @@ bool QCocoaDrag::maybeDragMultipleItems()
for (NSPasteboardItem *item in dragBoard.pasteboardItems) {
bool isUrl = false;
for (NSPasteboardType type in item.types) {
- using NSStringRef = NSString *;
- if ([type isEqualToString:NSStringRef(kUTTypeFileURL)]) {
+ if ([type isEqualToString:UTTypeFileURL.identifier]) {
isUrl = true;
break;
}
@@ -213,7 +213,9 @@ bool QCocoaDrag::maybeDragMultipleItems()
}
[sourceView beginDraggingSessionWithItems:dragItems event:m_lastEvent source:sourceView];
- internalDragLoop.exec();
+ QEventLoop eventLoop;
+ QScopedValueRollback updateGuard(m_internalDragLoop, &eventLoop);
+ eventLoop.exec();
return true;
}
@@ -224,8 +226,10 @@ void QCocoaDrag::setAcceptedAction(Qt::DropAction act)
void QCocoaDrag::exitDragLoop()
{
- if (internalDragLoop.isRunning())
- internalDragLoop.exit();
+ if (m_internalDragLoop) {
+ Q_ASSERT(m_internalDragLoop->isRunning());
+ m_internalDragLoop->exit();
+ }
}
@@ -240,14 +244,14 @@ QPixmap QCocoaDrag::dragPixmap(QDrag *drag, QPoint &hotSpot) const
QFontMetrics fm(f);
if (data->hasImage()) {
- const QImage img = data->imageData().value<QImage>();
+ QImage img = data->imageData().value<QImage>();
if (!img.isNull()) {
- pm = QPixmap::fromImage(img).scaledToWidth(dragImageMaxChars *fm.averageCharWidth());
+ pm = QPixmap::fromImage(std::move(img)).scaledToWidth(dragImageMaxChars *fm.averageCharWidth());
}
}
if (pm.isNull() && (data->hasText() || data->hasUrls()) ) {
- QString s = data->hasText() ? data->text() : data->urls().first().toString();
+ QString s = data->hasText() ? data->text() : data->urls().constFirst().toString();
if (s.length() > dragImageMaxChars)
s = s.left(dragImageMaxChars -3) + QChar(0x2026);
if (!s.isEmpty()) {
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
index 787b23ec4d..96eb70dabc 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
@@ -56,9 +56,12 @@
#include <QtCore/private/qcfsocketnotifier_p.h>
#include <QtCore/private/qtimerinfo_unix_p.h>
#include <QtCore/qloggingcategory.h>
+#include <QtCore/qpointer.h>
#include <CoreFoundation/CoreFoundation.h>
+Q_FORWARD_DECLARE_OBJC_CLASS(NSWindow);
+
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcEventDispatcher);
@@ -67,11 +70,11 @@ typedef struct _NSModalSession *NSModalSession;
typedef struct _QCocoaModalSessionInfo {
QPointer<QWindow> window;
NSModalSession session;
- void *nswindow;
+ NSWindow *nswindow;
} QCocoaModalSessionInfo;
class QCocoaEventDispatcherPrivate;
-class QCocoaEventDispatcher : public QAbstractEventDispatcher
+class QCocoaEventDispatcher : public QAbstractEventDispatcherV2
{
Q_OBJECT
Q_DECLARE_PRIVATE(QCocoaEventDispatcher)
@@ -86,12 +89,12 @@ public:
void registerSocketNotifier(QSocketNotifier *notifier);
void unregisterSocketNotifier(QSocketNotifier *notifier);
- void registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object);
- bool unregisterTimer(int timerId);
- bool unregisterTimers(QObject *object);
- QList<TimerInfo> registeredTimers(QObject *object) const;
-
- int remainingTime(int timerId);
+ void registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType,
+ QObject *object) final;
+ bool unregisterTimer(Qt::TimerId timerId) final;
+ bool unregisterTimers(QObject *object) final;
+ QList<TimerInfoV2> timersForObject(QObject *object) const final;
+ Duration remainingTime(Qt::TimerId timerId) const final;
void wakeUp();
void interrupt();
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
index fd0a4b4717..739fbda4f5 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
@@ -115,6 +115,7 @@ void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer()
return;
}
+ using DoubleSeconds = std::chrono::duration<double, std::ratio<1>>;
if (!runLoopTimerRef) {
// start the CFRunLoopTimer
CFAbsoluteTime ttf = CFAbsoluteTimeGetCurrent();
@@ -122,10 +123,10 @@ void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer()
CFTimeInterval oneyear = CFTimeInterval(3600. * 24. * 365.);
// Q: when should the CFRunLoopTimer fire for the first time?
- struct timespec tv;
- if (timerInfoList.timerWait(tv)) {
+ if (auto opt = timerInfoList.timerWait()) {
// A: when we have timers to fire, of course
- interval = qMax(tv.tv_sec + tv.tv_nsec / 1000000000., 0.0000001);
+ DoubleSeconds secs{*opt};
+ interval = qMax(secs.count(), 0.0000001);
} else {
// this shouldn't really happen, but in case it does, set the timer to fire a some point in the distant future
interval = oneyear;
@@ -145,10 +146,10 @@ void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer()
CFTimeInterval interval;
// Q: when should the timer first next?
- struct timespec tv;
- if (timerInfoList.timerWait(tv)) {
+ if (auto opt = timerInfoList.timerWait()) {
// A: when we have timers to fire, of course
- interval = qMax(tv.tv_sec + tv.tv_nsec / 1000000000., 0.0000001);
+ DoubleSeconds secs{*opt};
+ interval = qMax(secs.count(), 0.0000001);
} else {
// no timers can fire, but we cannot stop the CFRunLoopTimer, set the timer to fire at some
// point in the distant future (the timer interval is one year)
@@ -170,10 +171,11 @@ void QCocoaEventDispatcherPrivate::maybeStopCFRunLoopTimer()
runLoopTimerRef = nullptr;
}
-void QCocoaEventDispatcher::registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *obj)
+void QCocoaEventDispatcher::registerTimer(Qt::TimerId timerId, Duration interval,
+ Qt::TimerType timerType, QObject *obj)
{
#ifndef QT_NO_DEBUG
- if (timerId < 1 || interval < 0 || !obj) {
+ if (qToUnderlying(timerId) < 1 || interval.count() < 0 || !obj) {
qWarning("QCocoaEventDispatcher::registerTimer: invalid arguments");
return;
} else if (obj->thread() != thread() || thread() != QThread::currentThread()) {
@@ -187,10 +189,10 @@ void QCocoaEventDispatcher::registerTimer(int timerId, qint64 interval, Qt::Time
d->maybeStartCFRunLoopTimer();
}
-bool QCocoaEventDispatcher::unregisterTimer(int timerId)
+bool QCocoaEventDispatcher::unregisterTimer(Qt::TimerId timerId)
{
#ifndef QT_NO_DEBUG
- if (timerId < 1) {
+ if (qToUnderlying(timerId) < 1) {
qWarning("QCocoaEventDispatcher::unregisterTimer: invalid argument");
return false;
} else if (thread() != QThread::currentThread()) {
@@ -229,13 +231,13 @@ bool QCocoaEventDispatcher::unregisterTimers(QObject *obj)
return returnValue;
}
-QList<QCocoaEventDispatcher::TimerInfo>
-QCocoaEventDispatcher::registeredTimers(QObject *object) const
+QList<QCocoaEventDispatcher::TimerInfoV2>
+QCocoaEventDispatcher::timersForObject(QObject *object) const
{
#ifndef QT_NO_DEBUG
if (!object) {
qWarning("QCocoaEventDispatcher:registeredTimers: invalid argument");
- return QList<TimerInfo>();
+ return {};
}
#endif
@@ -374,6 +376,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);
+ qCDebug(lcEventDispatcher) << "Running modal session" << session;
while ([NSApp runModalSession:session] == NSModalResponseContinue && !d->interrupt) {
qt_mac_waitForMoreEvents(NSModalPanelRunLoopMode);
if (session != d->currentModalSessionCached) {
@@ -417,6 +420,7 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
// to use cocoa's native way of running modal sessions:
if (flags & QEventLoop::WaitForMoreEvents)
qt_mac_waitForMoreEvents(NSModalPanelRunLoopMode);
+ qCDebug(lcEventDispatcher) << "Running modal session" << session;
NSInteger status = [NSApp runModalSession:session];
if (status != NSModalResponseContinue && session == d->currentModalSessionCached) {
// INVARIANT: Someone called [NSApp stopModal:] from outside the event
@@ -537,17 +541,17 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
return retVal;
}
-int QCocoaEventDispatcher::remainingTime(int timerId)
+auto QCocoaEventDispatcher::remainingTime(Qt::TimerId timerId) const -> Duration
{
#ifndef QT_NO_DEBUG
- if (timerId < 1) {
+ if (qToUnderlying(timerId) < 1) {
qWarning("QCocoaEventDispatcher::remainingTime: invalid argument");
- return -1;
+ return Duration::min();
}
#endif
- Q_D(QCocoaEventDispatcher);
- return d->timerInfoList.timerRemainingTime(timerId);
+ Q_D(const QCocoaEventDispatcher);
+ return d->timerInfoList.remainingDuration(timerId);
}
void QCocoaEventDispatcher::wakeUp()
@@ -617,6 +621,8 @@ void QCocoaEventDispatcherPrivate::temporarilyStopAllModalSessions()
for (int i=0; i<stackSize; ++i) {
QCocoaModalSessionInfo &info = cocoaModalSessionStack[i];
if (info.session) {
+ qCDebug(lcEventDispatcher) << "Temporarily ending modal session" << info.session
+ << "for" << info.nswindow;
[NSApp endModalSession:info.session];
info.session = nullptr;
[(NSWindow*) info.nswindow release];
@@ -656,6 +662,8 @@ NSModalSession QCocoaEventDispatcherPrivate::currentModalSession()
[(NSWindow*) info.nswindow retain];
QRect rect = cocoaWindow->geometry();
info.session = [NSApp beginModalSessionForWindow:nswindow];
+ qCDebug(lcEventDispatcher) << "Begun modal session" << info.session
+ << "for" << nswindow;
// The call to beginModalSessionForWindow above processes events and may
// have deleted or destroyed the window. Check if it's still valid.
@@ -704,6 +712,8 @@ void QCocoaEventDispatcherPrivate::cleanupModalSessions()
currentModalSessionCached = nullptr;
if (info.session) {
Q_ASSERT(info.nswindow);
+ qCDebug(lcEventDispatcher) << "Ending modal session" << info.session
+ << "for" << info.nswindow;
[NSApp endModalSession:info.session];
[(NSWindow *)info.nswindow release];
}
@@ -716,6 +726,14 @@ void QCocoaEventDispatcherPrivate::cleanupModalSessions()
void QCocoaEventDispatcherPrivate::beginModalSession(QWindow *window)
{
+ qCDebug(lcEventDispatcher) << "Adding modal session for" << window;
+
+ if (std::any_of(cocoaModalSessionStack.constBegin(), cocoaModalSessionStack.constEnd(),
+ [&](const auto &sessionInfo) { return sessionInfo.window == window; })) {
+ qCWarning(lcEventDispatcher) << "Modal session for" << window << "already exists!";
+ return;
+ }
+
// We need to start spinning the modal session. Usually this is done with
// QDialog::exec() for Qt Widgets based applications, but for others that
// just call show(), we need to interrupt().
@@ -736,6 +754,8 @@ void QCocoaEventDispatcherPrivate::beginModalSession(QWindow *window)
void QCocoaEventDispatcherPrivate::endModalSession(QWindow *window)
{
+ qCDebug(lcEventDispatcher) << "Removing modal session for" << window;
+
Q_Q(QCocoaEventDispatcher);
// Mark all sessions attached to window as pending to be stopped. We do this
@@ -782,7 +802,7 @@ void qt_mac_maybeCancelWaitForMoreEventsForwarder(QAbstractEventDispatcher *even
}
QCocoaEventDispatcher::QCocoaEventDispatcher(QObject *parent)
- : QAbstractEventDispatcher(*new QCocoaEventDispatcherPrivate, parent)
+ : QAbstractEventDispatcherV2(*new QCocoaEventDispatcherPrivate, parent)
{
Q_D(QCocoaEventDispatcher);
@@ -957,7 +977,7 @@ QCocoaEventDispatcher::~QCocoaEventDispatcher()
{
Q_D(QCocoaEventDispatcher);
- qDeleteAll(d->timerInfoList);
+ d->timerInfoList.clearTimers();
d->maybeStopCFRunLoopTimer();
CFRunLoopRemoveSource(mainRunLoop(), d->activateTimersSourceRef, kCFRunLoopCommonModes);
CFRelease(d->activateTimersSourceRef);
@@ -966,6 +986,8 @@ QCocoaEventDispatcher::~QCocoaEventDispatcher()
for (int i = 0; i < d->cocoaModalSessionStack.count(); ++i) {
QCocoaModalSessionInfo &info = d->cocoaModalSessionStack[i];
if (info.session) {
+ qCDebug(lcEventDispatcher) << "Ending modal session" << info.session
+ << "for" << info.nswindow << "during shutdown";
[NSApp endModalSession:info.session];
[(NSWindow *)info.nswindow release];
}
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h
index 85e317b8ef..3ffccb10fd 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.h
@@ -38,6 +38,7 @@ public:
public: // for QNSOpenSavePanelDelegate
void panelClosed(NSInteger result);
+ void panelDirectoryDidChange(NSString *path);
private:
void createNSOpenSavePanelDelegate();
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index 91d76fa254..044a282686 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -27,6 +27,8 @@
#include <qpa/qplatformtheme.h>
#include <qpa/qplatformnativeinterface.h>
+#include <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
+
QT_USE_NAMESPACE
using namespace Qt::StringLiterals;
@@ -55,12 +57,11 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
NSPopUpButton *m_popupButton;
NSTextField *m_textField;
QPointer<QCocoaFileDialogHelper> m_helper;
- NSString *m_currentDirectory;
SharedPointerFileDialogOptions m_options;
- QString *m_currentSelection;
- QStringList *m_nameFilterDropDownList;
- QStringList *m_selectedNameFilter;
+ QString m_currentSelection;
+ QStringList m_nameFilterDropDownList;
+ QStringList m_selectedNameFilter;
}
- (instancetype)initWithAcceptMode:(const QString &)selectFile
@@ -80,26 +81,56 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
m_helper = helper;
- m_nameFilterDropDownList = new QStringList(m_options->nameFilters());
+ m_nameFilterDropDownList = m_options->nameFilters();
QString selectedVisualNameFilter = m_options->initiallySelectedNameFilter();
- m_selectedNameFilter = new QStringList([self findStrippedFilterWithVisualFilterName:selectedVisualNameFilter]);
-
- QFileInfo sel(selectFile);
+ m_selectedNameFilter = [self findStrippedFilterWithVisualFilterName:selectedVisualNameFilter];
+
+ m_panel.extensionHidden = [&]{
+ for (const auto &nameFilter : m_nameFilterDropDownList) {
+ const auto extensions = QPlatformFileDialogHelper::cleanFilterList(nameFilter);
+ for (const auto &extension : extensions) {
+ // Explicitly show extensions if we detect a filter
+ // of "all files", as clicking a single file with
+ // extensions hidden will then populate the name
+ // field with only the file name, without any
+ // extension.
+ if (extension == "*"_L1 || extension == "*.*"_L1)
+ return false;
+
+ // Explicitly show extensions if we detect a filter
+ // that has a multi-part extension. This prevents
+ // confusing situations where the user clicks e.g.
+ // 'foo.tar.gz' and 'foo.tar' is populated in the
+ // file name box, but when then clicking save macOS
+ // will warn that the file needs to end in .gz,
+ // due to thinking the user tried to save the file
+ // as a 'tar' file instead. Unfortunately this
+ // property can only be set before the panel is
+ // shown, so we can't toggle it on and off based
+ // on the active filter.
+ if (extension.count('.') > 1)
+ return false;
+ }
+ }
+ return true;
+ }();
+
+ const QFileInfo sel(selectFile);
if (sel.isDir() && !sel.isBundle()){
- m_currentDirectory = [sel.absoluteFilePath().toNSString() retain];
- m_currentSelection = new QString;
+ m_panel.directoryURL = [NSURL fileURLWithPath:sel.absoluteFilePath().toNSString()];
+ m_currentSelection.clear();
} else {
- m_currentDirectory = [sel.absolutePath().toNSString() retain];
- m_currentSelection = new QString(sel.absoluteFilePath());
+ m_panel.directoryURL = [NSURL fileURLWithPath:sel.absolutePath().toNSString()];
+ m_currentSelection = sel.absoluteFilePath();
}
[self createPopUpButton:selectedVisualNameFilter hideDetails:options->testOption(QFileDialogOptions::HideNameFilterDetails)];
[self createTextField];
[self createAccessory];
- m_panel.accessoryView = m_nameFilterDropDownList->size() > 1 ? m_accessoryView : nil;
+ m_panel.accessoryView = m_nameFilterDropDownList.size() > 1 ? m_accessoryView : nil;
// -setAccessoryView: can result in -panel:directoryDidChange:
- // resetting our m_currentDirectory, set the delegate
+ // resetting our current directory. Set the delegate
// here to make sure it gets the correct value.
m_panel.delegate = self;
@@ -113,10 +144,6 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
- (void)dealloc
{
- delete m_nameFilterDropDownList;
- delete m_selectedNameFilter;
- delete m_currentSelection;
-
[m_panel orderOut:m_panel];
m_panel.accessoryView = nil;
[m_popupButton release];
@@ -124,19 +151,17 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
[m_accessoryView release];
m_panel.delegate = nil;
[m_panel release];
- [m_currentDirectory release];
[super dealloc];
}
- (bool)showPanel:(Qt::WindowModality) windowModality withParent:(QWindow *)parent
{
- QFileInfo info(*m_currentSelection);
+ const QFileInfo info(m_currentSelection);
NSString *filepath = info.filePath().toNSString();
NSURL *url = [NSURL fileURLWithPath:filepath isDirectory:info.isDir()];
bool selectable = (m_options->acceptMode() == QFileDialogOptions::AcceptSave)
|| [self panel:m_panel shouldEnableURL:url];
- m_panel.directoryURL = [NSURL fileURLWithPath:m_currentDirectory];
m_panel.nameFieldStringValue = selectable ? info.fileName().toNSString() : @"";
[self updateProperties];
@@ -184,7 +209,7 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
- (void)closePanel
{
- *m_currentSelection = QString::fromNSString(m_panel.URL.path).normalized(QString::NormalizationForm_C);
+ m_currentSelection = QString::fromNSString(m_panel.URL.path).normalized(QString::NormalizationForm_C);
if (m_panel.sheet)
[NSApp endSheet:m_panel];
@@ -194,19 +219,6 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
[m_panel close];
}
-- (BOOL)isHiddenFileAtURL:(NSURL *)url
-{
- BOOL hidden = NO;
- if (url) {
- CFBooleanRef isHiddenProperty;
- if (CFURLCopyResourcePropertyForKey((__bridge CFURLRef)url, kCFURLIsHiddenKey, &isHiddenProperty, nullptr)) {
- hidden = CFBooleanGetValue(isHiddenProperty);
- CFRelease(isHiddenProperty);
- }
- }
- return hidden;
-}
-
- (BOOL)panel:(id)sender shouldEnableURL:(NSURL *)url
{
Q_UNUSED(sender);
@@ -215,64 +227,140 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
if (!filename.length)
return NO;
- // Always accept directories regardless of their names (unless it is a bundle):
- NSFileManager *fm = NSFileManager.defaultManager;
- NSDictionary *fileAttrs = [fm attributesOfItemAtPath:filename error:nil];
- if (!fileAttrs)
- return NO; // Error accessing the file means 'no'.
- NSString *fileType = fileAttrs.fileType;
- bool isDir = [fileType isEqualToString:NSFileTypeDirectory];
- if (isDir) {
- if (!m_panel.treatsFilePackagesAsDirectories) {
- if ([NSWorkspace.sharedWorkspace isFilePackageAtPath:filename] == NO)
- return YES;
- }
+ const QFileInfo fileInfo(QString::fromNSString(filename));
+
+ // Always accept directories regardless of their names.
+ // This also includes symlinks and aliases to directories.
+ if (fileInfo.isDir()) {
+ // Unless it's a bundle, and we should treat bundles as files.
+ // FIXME: We'd like to use QFileInfo::isBundle() here, but the
+ // detection in QFileInfo goes deeper than NSWorkspace does
+ // (likely a bug), and as a result causes TCC permission
+ // dialogs to pop up when used.
+ bool treatBundlesAsFiles = !m_panel.treatsFilePackagesAsDirectories;
+ if (!(treatBundlesAsFiles && [NSWorkspace.sharedWorkspace isFilePackageAtPath:filename]))
+ return YES;
}
- // Treat symbolic links and aliases to directories like directories
- QFileInfo fileInfo(QString::fromNSString(filename));
- if (fileInfo.isSymLink() && QFileInfo(fileInfo.symLinkTarget()).isDir())
- return YES;
-
- QString qtFileName = fileInfo.fileName();
- // No filter means accept everything
- bool nameMatches = m_selectedNameFilter->isEmpty();
- // Check if the current file name filter accepts the file:
- for (int i = 0; !nameMatches && i < m_selectedNameFilter->size(); ++i) {
- if (QDir::match(m_selectedNameFilter->at(i), qtFileName))
- nameMatches = true;
- }
- if (!nameMatches)
+ if (![self fileInfoMatchesCurrentNameFilter:fileInfo])
return NO;
QDir::Filters filter = m_options->filter();
- if ((!(filter & (QDir::Dirs | QDir::AllDirs)) && isDir)
- || (!(filter & QDir::Files) && [fileType isEqualToString:NSFileTypeRegular])
- || ((filter & QDir::NoSymLinks) && [fileType isEqualToString:NSFileTypeSymbolicLink]))
+ if ((!(filter & (QDir::Dirs | QDir::AllDirs)) && fileInfo.isDir())
+ || (!(filter & QDir::Files) && (fileInfo.isFile() && !fileInfo.isSymLink()))
+ || ((filter & QDir::NoSymLinks) && fileInfo.isSymLink()))
return NO;
bool filterPermissions = ((filter & QDir::PermissionMask)
&& (filter & QDir::PermissionMask) != QDir::PermissionMask);
if (filterPermissions) {
- if ((!(filter & QDir::Readable) && [fm isReadableFileAtPath:filename])
- || (!(filter & QDir::Writable) && [fm isWritableFileAtPath:filename])
- || (!(filter & QDir::Executable) && [fm isExecutableFileAtPath:filename]))
+ if ((!(filter & QDir::Readable) && fileInfo.isReadable())
+ || (!(filter & QDir::Writable) && fileInfo.isWritable())
+ || (!(filter & QDir::Executable) && fileInfo.isExecutable()))
return NO;
}
- if (!(filter & QDir::Hidden)
- && (qtFileName.startsWith(u'.') || [self isHiddenFileAtURL:url]))
+
+ // We control the visibility of hidden files via the showsHiddenFiles
+ // property on the panel, based on QDir::Hidden being set. But the user
+ // can also toggle this via the Command+Shift+. keyboard shortcut,
+ // in which case they have explicitly requested to show hidden files,
+ // and we should enable them even if QDir::Hidden was not set. In
+ // effect, we don't need to filter on QDir::Hidden here.
+
+ return YES;
+}
+
+- (BOOL)panel:(id)sender validateURL:(NSURL *)url error:(NSError * _Nullable *)outError
+{
+ Q_ASSERT(sender == m_panel);
+
+ if (!m_panel.allowedFileTypes && !m_selectedNameFilter.isEmpty()) {
+ // The save panel hasn't done filtering on our behalf,
+ // either because we couldn't represent the filter via
+ // allowedFileTypes, or we opted out due to a multi part
+ // extension, so do the filtering/validation ourselves.
+ QFileInfo fileInfo(QString::fromNSString(url.path).normalized(QString::NormalizationForm_C));
+
+ if ([self fileInfoMatchesCurrentNameFilter:fileInfo])
+ return YES;
+
+ if (fileInfo.suffix().isEmpty()) {
+ // The filter requires a file name with an extension.
+ // We're going to add a default file name in selectedFiles,
+ // to match the native behavior. Check now that we can
+ // overwrite the file, if is already exists.
+ fileInfo = [self applyDefaultSuffixFromCurrentNameFilter:fileInfo];
+
+ if (!fileInfo.exists() || m_options->testOption(QFileDialogOptions::DontConfirmOverwrite))
+ return YES;
+
+ QMacAutoReleasePool pool;
+ auto *alert = [[NSAlert new] autorelease];
+ alert.alertStyle = NSAlertStyleCritical;
+
+ alert.messageText = [NSString stringWithFormat:qt_mac_AppKitString(@"SavePanel",
+ @"\\U201c%@\\U201d already exists. Do you want to replace it?"),
+ fileInfo.fileName().toNSString()];
+ alert.informativeText = [NSString stringWithFormat:qt_mac_AppKitString(@"SavePanel",
+ @"A file or folder with the same name already exists in the folder %@. "
+ "Replacing it will overwrite its current contents."),
+ fileInfo.absoluteDir().dirName().toNSString()];
+
+ auto *replaceButton = [alert addButtonWithTitle:qt_mac_AppKitString(@"SavePanel", @"Replace")];
+ replaceButton.hasDestructiveAction = YES;
+ replaceButton.tag = 1337;
+ [alert addButtonWithTitle:qt_mac_AppKitString(@"Common", @"Cancel")];
+
+ [alert beginSheetModalForWindow:m_panel
+ completionHandler:^(NSModalResponse returnCode) {
+ [NSApp stopModalWithCode:returnCode];
+ }];
+ return [NSApp runModalForWindow:alert.window] == replaceButton.tag;
+ } else {
+ QFileInfo firstFilter(m_selectedNameFilter.first());
+ auto *domain = qGuiApp->organizationDomain().toNSString();
+ *outError = [NSError errorWithDomain:domain code:0 userInfo:@{
+ NSLocalizedDescriptionKey:[NSString stringWithFormat:qt_mac_AppKitString(@"SavePanel",
+ @"You cannot save this document with extension \\U201c.%1$@\\U201d at the end "
+ "of the name. The required extension is \\U201c.%2$@\\U201d."),
+ fileInfo.completeSuffix().toNSString(), firstFilter.completeSuffix().toNSString()]
+ }];
return NO;
+ }
+ }
return YES;
}
+- (QFileInfo)applyDefaultSuffixFromCurrentNameFilter:(const QFileInfo &)fileInfo
+{
+ QFileInfo filterInfo(m_selectedNameFilter.first());
+ return QFileInfo(fileInfo.absolutePath(),
+ fileInfo.baseName() + '.' + filterInfo.completeSuffix());
+}
+
+- (bool)fileInfoMatchesCurrentNameFilter:(const QFileInfo &)fileInfo
+{
+ // No filter means accept everything
+ if (m_selectedNameFilter.isEmpty())
+ return true;
+
+ // Check if the current file name filter accepts the file
+ for (const auto &filter : m_selectedNameFilter) {
+ if (QDir::match(filter, fileInfo.fileName()))
+ return true;
+ }
+
+ return false;
+}
+
- (void)setNameFilters:(const QStringList &)filters hideDetails:(BOOL)hideDetails
{
[m_popupButton removeAllItems];
- *m_nameFilterDropDownList = filters;
+ m_nameFilterDropDownList = filters;
if (filters.size() > 0){
for (int i = 0; i < filters.size(); ++i) {
- QString filter = hideDetails ? [self removeExtensions:filters.at(i)] : filters.at(i);
+ const QString filter = hideDetails ? [self removeExtensions:filters.at(i)] : filters.at(i);
[m_popupButton.menu addItemWithTitle:filter.toNSString() action:nil keyEquivalent:@""];
}
[m_popupButton selectItemAtIndex:0];
@@ -290,8 +378,8 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
Q_UNUSED(sender);
if (!m_helper)
return;
- QString selection = m_nameFilterDropDownList->value([m_popupButton indexOfSelectedItem]);
- *m_selectedNameFilter = [self findStrippedFilterWithVisualFilterName:selection];
+ const QString selection = m_nameFilterDropDownList.value([m_popupButton indexOfSelectedItem]);
+ m_selectedNameFilter = [self findStrippedFilterWithVisualFilterName:selection];
[m_panel validateVisibleColumns];
[self updateProperties];
@@ -310,18 +398,25 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
}
return result;
} else {
- QList<QUrl> result;
QString filename = QString::fromNSString(m_panel.URL.path).normalized(QString::NormalizationForm_C);
- const QString defaultSuffix = m_options->defaultSuffix();
- const QFileInfo fileInfo(filename);
+ QFileInfo fileInfo(filename);
+
+ if (fileInfo.suffix().isEmpty() && ![self fileInfoMatchesCurrentNameFilter:fileInfo]) {
+ // We end up in this situation if we accept a file name without extension
+ // in panel:validateURL:error. If so, we match the behavior of the native
+ // save dialog and add the first of the accepted extension from the filter.
+ fileInfo = [self applyDefaultSuffixFromCurrentNameFilter:fileInfo];
+ }
// If neither the user or the NSSavePanel have provided a suffix, use
// the default suffix (if it exists).
- if (fileInfo.suffix().isEmpty() && !defaultSuffix.isEmpty())
- filename.append('.').append(defaultSuffix);
+ const QString defaultSuffix = m_options->defaultSuffix();
+ if (fileInfo.suffix().isEmpty() && !defaultSuffix.isEmpty()) {
+ fileInfo.setFile(fileInfo.absolutePath(),
+ fileInfo.baseName() + '.' + defaultSuffix);
+ }
- result << QUrl::fromLocalFile(filename);
- return result;
+ return { QUrl::fromLocalFile(fileInfo.filePath()) };
}
}
@@ -353,19 +448,25 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
m_panel.allowedFileTypes = [self computeAllowedFileTypes];
- // Explicitly show extensions if we detect a filter
- // that has a multi-part extension. This prevents
- // confusing situations where the user clicks e.g.
- // 'foo.tar.gz' and 'foo.tar' is populated in the
- // file name box, but when then clicking save macOS
- // will warn that the file needs to end in .gz,
- // due to thinking the user tried to save the file
- // as a 'tar' file instead. Unfortunately this
- // property can only be set before the panel is
- // shown, so it will not have any effect when
- // switching filters in an already opened dialog.
- if (m_panel.allowedFileTypes.count > 2)
- m_panel.extensionHidden = NO;
+ // Setting allowedFileTypes to nil is not enough to reset any
+ // automatically added extension based on a previous filter.
+ // This is problematic because extensions can in some cases
+ // be hidden from the user, resulting in confusion when the
+ // resulting file name doesn't match the current empty filter.
+ // We work around this by temporarily resetting the allowed
+ // content type to one without an extension, which forces
+ // the save panel to update and remove the extension.
+ const bool nameFieldHasExtension = m_panel.nameFieldStringValue.pathExtension.length > 0;
+ if (!m_panel.allowedFileTypes && !nameFieldHasExtension && !openpanel_cast(m_panel)) {
+ if (!UTTypeDirectory.preferredFilenameExtension) {
+ m_panel.allowedContentTypes = @[ UTTypeDirectory ];
+ m_panel.allowedFileTypes = nil;
+ } else {
+ qWarning() << "UTTypeDirectory unexpectedly reported an extension";
+ }
+ }
+
+ m_panel.showsHiddenFiles = m_options->filter().testFlag(QDir::Hidden);
if (m_panel.visible)
[m_panel validateVisibleColumns];
@@ -378,10 +479,18 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
if (!m_helper)
return;
+ // Save panels only allow you to select directories, which
+ // means currentChanged will only be emitted when selecting
+ // a directory, and if so, with the latest chosen file name,
+ // which is confusing and inconsistent. We choose to bail
+ // out entirely for save panels, to give consistent behavior.
+ if (!openpanel_cast(m_panel))
+ return;
+
if (m_panel.visible) {
- QString selection = QString::fromNSString(m_panel.URL.path);
- if (selection != *m_currentSelection) {
- *m_currentSelection = selection;
+ const QString selection = QString::fromNSString(m_panel.URL.path);
+ if (selection != m_currentSelection) {
+ m_currentSelection = selection;
emit m_helper->currentChanged(QUrl::fromLocalFile(selection));
}
}
@@ -394,14 +503,7 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
if (!m_helper)
return;
- if (!(path && path.length) || [path isEqualToString:m_currentDirectory])
- return;
-
- [m_currentDirectory release];
- m_currentDirectory = [path retain];
-
- // ### fixme: priv->setLastVisitedDirectory(newDir);
- emit m_helper->directoryEntered(QUrl::fromLocalFile(QString::fromNSString(m_currentDirectory)));
+ m_helper->panelDirectoryDidChange(path);
}
/*
@@ -409,11 +511,9 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
for the current name filter, and updates the save panel.
If a filter do not conform to the format *.xyz or * or *.*,
- all files types are allowed.
-
- Extensions with more than one part (e.g. "tar.gz") are
- reduced to their final part, as NSSavePanel does not deal
- well with multi-part extensions.
+ or contains an extensions with more than one part (e.g. "tar.gz")
+ we treat that as allowing all file types, and do our own
+ validation in panel:validateURL:error.
*/
- (NSArray<NSString*>*)computeAllowedFileTypes
{
@@ -421,7 +521,7 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
return nil; // panel:shouldEnableURL: does the file filtering for NSOpenPanel
QStringList fileTypes;
- for (const QString &filter : *m_selectedNameFilter) {
+ for (const QString &filter : std::as_const(m_selectedNameFilter)) {
if (!filter.startsWith("*."_L1))
continue;
@@ -432,6 +532,9 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
continue;
auto extensions = filter.split('.', Qt::SkipEmptyParts);
+ if (extensions.count() > 2)
+ return nil;
+
fileTypes += extensions.last();
}
@@ -468,10 +571,10 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
m_popupButton.target = self;
m_popupButton.action = @selector(filterChanged:);
- if (m_nameFilterDropDownList->size() > 0) {
+ if (!m_nameFilterDropDownList.isEmpty()) {
int filterToUse = -1;
- for (int i = 0; i < m_nameFilterDropDownList->size(); ++i) {
- QString currentFilter = m_nameFilterDropDownList->at(i);
+ for (int i = 0; i < m_nameFilterDropDownList.size(); ++i) {
+ const QString currentFilter = m_nameFilterDropDownList.at(i);
if (selectedFilter == currentFilter ||
(filterToUse == -1 && currentFilter.startsWith(selectedFilter)))
filterToUse = i;
@@ -485,9 +588,9 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
- (QStringList) findStrippedFilterWithVisualFilterName:(QString)name
{
- for (int i = 0; i < m_nameFilterDropDownList->size(); ++i) {
- if (m_nameFilterDropDownList->at(i).startsWith(name))
- return QPlatformFileDialogHelper::cleanFilterList(m_nameFilterDropDownList->at(i));
+ for (const QString &currentFilter : std::as_const(m_nameFilterDropDownList)) {
+ if (currentFilter.startsWith(name))
+ return QPlatformFileDialogHelper::cleanFilterList(currentFilter);
}
return QStringList();
}
@@ -528,21 +631,32 @@ void QCocoaFileDialogHelper::panelClosed(NSInteger result)
void QCocoaFileDialogHelper::setDirectory(const QUrl &directory)
{
+ m_directory = directory;
+
if (m_delegate)
m_delegate->m_panel.directoryURL = [NSURL fileURLWithPath:directory.toLocalFile().toNSString()];
- else
- m_directory = directory;
}
QUrl QCocoaFileDialogHelper::directory() const
{
- if (m_delegate) {
- QString path = QString::fromNSString(m_delegate->m_panel.directoryURL.path).normalized(QString::NormalizationForm_C);
- return QUrl::fromLocalFile(path);
- }
return m_directory;
}
+void QCocoaFileDialogHelper::panelDirectoryDidChange(NSString *path)
+{
+ if (!path || [path isEqual:NSNull.null] || !path.length)
+ return;
+
+ const auto oldDirectory = m_directory;
+ m_directory = QUrl::fromLocalFile(
+ QString::fromNSString(path).normalized(QString::NormalizationForm_C));
+
+ if (m_directory != oldDirectory) {
+ // FIXME: Plumb old directory back to QFileDialog's lastVisitedDir?
+ emit directoryEntered(m_directory);
+ }
+}
+
void QCocoaFileDialogHelper::selectFile(const QUrl &filename)
{
QString filePath = filename.toLocalFile();
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h
index 694e57e73d..c6862a9e65 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.h
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.h
@@ -56,16 +56,6 @@ NSDragOperation qt_mac_mapDropActions(Qt::DropActions actions);
Qt::DropAction qt_mac_mapNSDragOperation(NSDragOperation nsActions);
Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions);
-template <typename T>
-typename std::enable_if<std::is_pointer<T>::value, T>::type
-qt_objc_cast(id object)
-{
- if ([object isKindOfClass:[typename std::remove_pointer<T>::type class]])
- return static_cast<T>(object);
-
- return nil;
-}
-
QT_MANGLE_NAMESPACE(QNSView) *qnsview_cast(NSView *view);
// Misc
@@ -88,6 +78,9 @@ Qt::MouseButtons currentlyPressedMouseButtons();
// accelerators.
QString qt_mac_removeAmpersandEscapes(QString s);
+// Similar to __NXKitString for localized AppKit strings
+NSString *qt_mac_AppKitString(NSString *table, NSString *key);
+
enum {
QtCocoaEventSubTypeWakeup = SHRT_MAX,
QtCocoaEventSubTypePostMessage = SHRT_MAX-1
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index ec64c94d0b..1eba88d5e3 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -336,6 +336,15 @@ QString qt_mac_removeAmpersandEscapes(QString s)
return QPlatformTheme::removeMnemonics(s).trimmed();
}
+NSString *qt_mac_AppKitString(NSString *table, NSString *key)
+{
+ static const NSBundle *appKit = [NSBundle bundleForClass:NSApplication.class];
+ if (!appKit)
+ return key;
+
+ return [appKit localizedStringForKey:key value:nil table:table];
+}
+
QT_END_NAMESPACE
/*! \internal
diff --git a/src/plugins/platforms/cocoa/qcocoainputcontext.mm b/src/plugins/platforms/cocoa/qcocoainputcontext.mm
index b242cd69c6..70461376e2 100644
--- a/src/plugins/platforms/cocoa/qcocoainputcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoainputcontext.mm
@@ -150,11 +150,18 @@ void QCocoaInputContext::updateLocale()
QString language = QString::fromNSString(languages.firstObject);
QLocale locale(language);
- if (m_locale != locale) {
+
+ bool localeUpdated = m_locale != locale;
+ static bool firstUpdate = true;
+
+ m_locale = locale;
+
+ if (localeUpdated && !firstUpdate) {
qCDebug(lcQpaInputMethods) << "Reporting new locale" << locale;
- m_locale = locale;
emitLocaleChanged();
}
+
+ firstUpdate = false;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h
index 72e5798bd6..664700cf51 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.h
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.h
@@ -20,7 +20,9 @@
#include <QtCore/QScopedPointer>
#include <qpa/qplatformintegration.h>
#include <QtGui/private/qcoretextfontdatabase_p.h>
-#include <QtGui/private/qopenglcontext_p.h>
+#ifndef QT_NO_OPENGL
+# include <QtGui/private/qopenglcontext_p.h>
+#endif
#include <QtGui/private/qapplekeymapper_p.h>
Q_FORWARD_DECLARE_OBJC_CLASS(NSToolbar);
@@ -82,8 +84,7 @@ public:
QCocoaServices *services() const override;
QVariant styleHint(StyleHint hint) const override;
- Qt::KeyboardModifiers queryKeyboardModifiers() const override;
- QList<int> possibleKeys(const QKeyEvent *event) const override;
+ QPlatformKeyMapper *keyMapper() const override;
void setApplicationIcon(const QIcon &icon) const override;
void setApplicationBadge(qint64 number) override;
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index 6dd410ad22..2ce39ff897 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -33,11 +33,16 @@
#include <QtCore/private/qcore_mac_p.h>
#include <QtGui/private/qcoregraphics_p.h>
#include <QtGui/private/qmacmimeregistry_p.h>
-#include <QtGui/private/qopenglcontext_p.h>
+#ifndef QT_NO_OPENGL
+# include <QtGui/private/qopenglcontext_p.h>
+#endif
#include <QtGui/private/qrhibackingstore_p.h>
#include <QtGui/private/qfontengine_coretext_p.h>
#include <IOKit/graphics/IOGraphicsLib.h>
+#include <UniformTypeIdentifiers/UTCoreTypes.h>
+
+#include <inttypes.h>
static void initResources()
{
@@ -120,9 +125,9 @@ QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
#endif
mFontDb.reset(new QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>);
- QString icStr = QPlatformInputContextFactory::requested();
- icStr.isNull() ? mInputContext.reset(new QCocoaInputContext)
- : mInputContext.reset(QPlatformInputContextFactory::create(icStr));
+ auto icStrs = QPlatformInputContextFactory::requested();
+ icStrs.isEmpty() ? mInputContext.reset(new QCocoaInputContext)
+ : mInputContext.reset(QPlatformInputContextFactory::create(icStrs));
initResources();
QMacAutoReleasePool pool;
@@ -137,16 +142,6 @@ QCocoaIntegration::QCocoaIntegration(const QStringList &paramList)
// wants to be foreground applications so change the process type. (But
// see the function implementation for exceptions.)
qt_mac_transformProccessToForegroundApplication();
-
- // Move the application window to front to make it take focus, also when launching
- // from the terminal. On 10.12+ this call has been moved to applicationDidFinishLauching
- // to work around issues with loss of focus at startup.
- if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSSierra) {
- // Ignoring other apps is necessary (we must ignore the terminal), but makes
- // Qt apps play slightly less nice with other apps when lanching from Finder
- // (See the activateIgnoringOtherApps docs.)
- [cocoaApplication activateIgnoringOtherApps : YES];
- }
}
// Qt 4 also does not set the application delegate, so that behavior
@@ -190,6 +185,9 @@ QCocoaIntegration::~QCocoaIntegration()
[[NSApplication sharedApplication] setDelegate:nil];
}
+ // Stop global mouse event and app activation monitoring
+ QCocoaWindow::removePopupMonitor();
+
#ifndef QT_NO_CLIPBOARD
// Delete the clipboard integration and destroy mime type converters.
// Deleting the clipboard integration flushes promised pastes using
@@ -238,6 +236,7 @@ bool QCocoaIntegration::hasCapability(QPlatformIntegration::Capability cap) cons
case RasterGLSurface:
case ApplicationState:
case ApplicationIcon:
+ case BackingStoreStaticContents:
return true;
default:
return QPlatformIntegration::hasCapability(cap);
@@ -305,6 +304,18 @@ QPlatformBackingStore *QCocoaIntegration::createPlatformBackingStore(QWindow *wi
return new QCALayerBackingStore(window);
case QSurface::MetalSurface:
case QSurface::OpenGLSurface:
+ case QSurface::VulkanSurface:
+ // If the window is a widget window, we know that the QWidgetRepaintManager
+ // will explicitly use rhiFlush() for the window owning the backingstore,
+ // and any child window with the same surface format. This means we can
+ // safely return a QCALayerBackingStore here, to ensure that any plain
+ // flush() for child windows that don't have a matching surface format
+ // will still work, by setting the layer's contents property.
+ if (window->inherits("QWidgetWindow"))
+ return new QCALayerBackingStore(window);
+
+ // Otherwise we return a QRhiBackingStore, that implements flush() in
+ // terms of rhiFlush().
return new QRhiBackingStore(window);
default:
return nullptr;
@@ -395,14 +406,9 @@ QVariant QCocoaIntegration::styleHint(StyleHint hint) const
return QPlatformIntegration::styleHint(hint);
}
-Qt::KeyboardModifiers QCocoaIntegration::queryKeyboardModifiers() const
-{
- return QAppleKeyMapper::queryKeyboardModifiers();
-}
-
-QList<int> QCocoaIntegration::possibleKeys(const QKeyEvent *event) const
+QPlatformKeyMapper *QCocoaIntegration::keyMapper() const
{
- return mKeyboardMapper->possibleKeys(event);
+ return mKeyboardMapper.data();
}
void QCocoaIntegration::setApplicationIcon(const QIcon &icon) const
@@ -435,8 +441,8 @@ void QCocoaIntegration::focusWindowChanged(QWindow *focusWindow)
return;
static bool hasDefaultApplicationIcon = [](){
- NSImage *genericApplicationIcon = [[NSWorkspace sharedWorkspace]
- iconForFileType:NSFileTypeForHFSTypeCode(kGenericApplicationIcon)];
+ NSImage *genericApplicationIcon = [NSWorkspace.sharedWorkspace
+ iconForContentType:UTTypeApplicationBundle];
NSImage *applicationIcon = [NSImage imageNamed:NSImageNameApplicationIcon];
NSRect rect = NSMakeRect(0, 0, 32, 32);
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index 0f39246a43..fa88a19d45 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -19,6 +19,7 @@
#include "qcocoaapplicationdelegate.h"
#include <QtCore/private/qcore_mac_p.h>
+#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
@@ -42,6 +43,8 @@ QCocoaMenu::~QCocoaMenu()
item->setMenuParent(nullptr);
}
+ if (isOpen())
+ dismiss();
[m_nativeMenu release];
}
@@ -60,7 +63,7 @@ void QCocoaMenu::setMinimumWidth(int width)
void QCocoaMenu::setFont(const QFont &font)
{
if (font.resolveMask()) {
- NSFont *customMenuFont = [NSFont fontWithName:font.families().first().toNSString()
+ NSFont *customMenuFont = [NSFont fontWithName:font.families().constFirst().toNSString()
size:font.pointSize()];
m_nativeMenu.font = customMenuFont;
}
@@ -320,8 +323,12 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
{
QMacAutoReleasePool pool;
+ QPointer<QCocoaMenu> guard = this;
+
QPoint pos = QPoint(targetRect.left(), targetRect.top() + targetRect.height());
- QCocoaWindow *cocoaWindow = parentWindow ? static_cast<QCocoaWindow *>(parentWindow->handle()) : nullptr;
+ // If the app quits while the menu is open (e.g. through a timer that starts before the menu was opened),
+ // then the window will have been destroyed before this function finishes executing. Account for that with QPointer.
+ QPointer<QCocoaWindow> cocoaWindow = parentWindow ? static_cast<QCocoaWindow *>(parentWindow->handle()) : nullptr;
NSView *view = cocoaWindow ? cocoaWindow->view() : nil;
NSMenuItem *nsItem = item ? ((QCocoaMenuItem *)item)->nsItem() : nil;
@@ -404,6 +411,11 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
}
}
+ if (!guard) {
+ menuParentGuard.dismiss();
+ return;
+ }
+
// 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 (cocoaWindow && !cocoaWindow->isForeignWindow())
@@ -483,6 +495,10 @@ void QCocoaMenu::setAttachedItem(NSMenuItem *item)
if (m_attachedItem)
m_attachedItem.submenu = m_nativeMenu;
+ // NSMenuItems with a submenu and submenuAction: as the item's action
+ // will not take part in NSMenuValidation, so explicitly enable/disable
+ // the item here. See also QCocoaMenuItem::resolveTargetAction()
+ m_attachedItem.enabled = m_attachedItem.hasSubmenu;
}
NSMenuItem *QCocoaMenu::attachedItem() const
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.h b/src/plugins/platforms/cocoa/qcocoamenubar.h
index b30f8569ab..785de9c0f6 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.h
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.h
@@ -9,6 +9,8 @@
#include <qpa/qplatformmenu.h>
#include "qcocoamenu.h"
+#include <QtCore/qpointer.h>
+
QT_BEGIN_NAMESPACE
class QCocoaWindow;
@@ -45,14 +47,12 @@ private:
bool needsImmediateUpdate();
bool shouldDisable(QCocoaWindow *active) const;
- void insertDefaultEditItems(QCocoaMenu *menu);
NSMenuItem *nativeItemForMenu(QCocoaMenu *menu) const;
QList<QPointer<QCocoaMenu> > m_menus;
NSMenu *m_nativeMenu;
QPointer<QCocoaWindow> m_window;
- QList<QPointer<QCocoaMenuItem>> m_defaultEditMenuItems;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm
index c0f0f9e702..2493d90724 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm
@@ -36,7 +36,7 @@ QCocoaMenuBar::QCocoaMenuBar()
QCocoaMenuBar::~QCocoaMenuBar()
{
- qCDebug(lcQpaMenus) << "Destructing" << this << "with" << m_nativeMenu;;
+ qCDebug(lcQpaMenus) << "Destructing" << this << "with" << m_nativeMenu;
for (auto menu : std::as_const(m_menus)) {
if (!menu)
continue;
@@ -162,18 +162,6 @@ void QCocoaMenuBar::syncMenu_helper(QPlatformMenu *menu, bool menubarUpdate)
for (QCocoaMenuItem *item : cocoaMenu->items())
cocoaMenu->syncMenuItem_helper(item, menubarUpdate);
- const QString captionNoAmpersand = QString::fromNSString(cocoaMenu->nsMenu().title)
- .remove(u'&');
- if (captionNoAmpersand == QCoreApplication::translate("QCocoaMenu", "Edit")) {
- // prevent recursion from QCocoaMenu::insertMenuItem - when the menu is visible
- // it calls syncMenu again. QCocoaMenu::setVisible just sets the bool, which then
- // gets evaluated in the code after this block.
- const bool wasVisible = cocoaMenu->isVisible();
- cocoaMenu->setVisible(false);
- insertDefaultEditItems(cocoaMenu);
- cocoaMenu->setVisible(wasVisible);
- }
-
BOOL shouldHide = YES;
if (cocoaMenu->isVisible()) {
// If the NSMenu has no visible items, or only separators, we should hide it
@@ -186,10 +174,44 @@ void QCocoaMenuBar::syncMenu_helper(QPlatformMenu *menu, bool menubarUpdate)
}
}
- if (NSMenuItem *attachedItem = cocoaMenu->attachedItem()) {
- // Non-nil attached item means the item's submenu is set
- attachedItem.title = cocoaMenu->nsMenu().title;
- attachedItem.hidden = shouldHide;
+ if (NSMenuItem *menuItem = cocoaMenu->attachedItem()) {
+ // Non-nil menu item means the item's sub menu is set
+
+ NSString *menuTitle = cocoaMenu->nsMenu().title;
+
+ // The NSMenu's title is what's visible to the user, and AppKit uses this
+ // for some of its heuristics of when to add special items to the menus,
+ // such as 'Enter Full Screen' in the View menu, the search bare in the
+ // Help menu, and the "Send App feedback to Apple" in the Help menu.
+ // This relies on the title matching AppKit's localized value from the
+ // MenuCommands table, which in turn depends on the preferredLocalizations
+ // of the AppKit bundle. We don't do any automatic translation of menu
+ // titles visible to the user, so this relies on the application developer
+ // having chosen translated titles that match AppKit's, and that the Qt
+ // preferred UI languages match AppKit's preferredLocalizations.
+
+ // In the case of the Edit menu, AppKit uses the NSMenuItem's title
+ // for its heuristics of when to add the dictation and emoji entries,
+ // and this title is not visible to the user. But like above, the
+ // heuristics are based on the localized title of the menu, so we need
+ // to ensure the title matches AppKit's localization.
+
+ // Unfortunately, the title we have at this point may have gone through
+ // Qt's i18n machinery already, via e.g. tr("Edit") in the application,
+ // in which case we don't know the context of the translation, and can't
+ // do a reverse lookup to go back to the untranslated title to pass to
+ // AppKit. As a workaround we translate the title via a our context,
+ // and document that the user needs to ensure their application matches
+ // this translation.
+ if ([menuTitle isEqual:@"Edit"] || [menuTitle isEqual:tr("Edit").toNSString()]) {
+ menuItem.title = qt_mac_AppKitString(@"InputManager", @"Edit");
+ } else {
+ // The Edit menu is the only case we know of so far, but to be on
+ // the safe side we always sync the menu title.
+ menuItem.title = menuTitle;
+ }
+
+ menuItem.hidden = shouldHide;
}
}
@@ -304,7 +326,21 @@ void QCocoaMenuBar::updateMenuBarImmediately()
}
[mergedItems release];
- [NSApp setMainMenu:mb->nsMenu()];
+
+ NSMenu *newMainMenu = mb->nsMenu();
+ if (NSApp.mainMenu == newMainMenu) {
+ // NSApplication triggers _customizeMainMenu when the menu
+ // changes, which takes care of adding text input items to
+ // the edit menu e.g., but this doesn't happen if the menu
+ // is the same. In our case we might be re-using an existing
+ // menu, but the menu might have new sub menus that need to
+ // be customized. To ensure NSApplication does the right
+ // thing we reset the main menu first.
+ qCDebug(lcQpaMenus) << "Clearing main menu temporarily";
+ NSApp.mainMenu = nil;
+ }
+ NSApp.mainMenu = newMainMenu;
+
insertWindowMenu();
[loader qtTranslateApplicationMenu];
}
@@ -325,6 +361,15 @@ void QCocoaMenuBar::insertWindowMenu()
winMenuItem.hidden = YES;
winMenuItem.submenu = [[[NSMenu alloc] initWithTitle:@"QtWindowMenu"] autorelease];
+
+ // AppKit has a bug in [NSApplication setWindowsMenu:] where it will resolve
+ // the last item of the window menu's itemArray, but not account for the array
+ // being empty, resulting in a lookup of itemAtIndex:-1. To work around this,
+ // we insert a hidden dummy item into the menu. See FB13369198.
+ auto *dummyItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
+ dummyItem.hidden = YES;
+ [winMenuItem.submenu addItem:[dummyItem autorelease]];
+
[mainMenu insertItem:winMenuItem atIndex:mainMenu.itemArray.count];
app.windowsMenu = winMenuItem.submenu;
@@ -416,48 +461,6 @@ QCocoaWindow *QCocoaMenuBar::cocoaWindow() const
return m_window.data();
}
-void QCocoaMenuBar::insertDefaultEditItems(QCocoaMenu *menu)
-{
- if (menu->items().isEmpty())
- return;
-
- NSMenu *nsEditMenu = menu->nsMenu();
- if ([nsEditMenu itemAtIndex:nsEditMenu.numberOfItems - 1].action
- == @selector(orderFrontCharacterPalette:)) {
- for (auto defaultEditMenuItem : std::as_const(m_defaultEditMenuItems)) {
- if (menu->items().contains(defaultEditMenuItem))
- menu->removeMenuItem(defaultEditMenuItem);
- }
- qDeleteAll(m_defaultEditMenuItems);
- m_defaultEditMenuItems.clear();
- } else {
- if (m_defaultEditMenuItems.isEmpty()) {
- QCocoaMenuItem *separator = new QCocoaMenuItem;
- separator->setIsSeparator(true);
-
- QCocoaMenuItem *dictationItem = new QCocoaMenuItem;
- dictationItem->setText(QCoreApplication::translate("QCocoaMenuItem", "Start Dictation..."));
- QObject::connect(dictationItem, &QPlatformMenuItem::activated, this, []{
- [NSApplication.sharedApplication performSelector:@selector(startDictation:)];
- });
-
- QCocoaMenuItem *emojiItem = new QCocoaMenuItem;
- emojiItem->setText(QCoreApplication::translate("QCocoaMenuItem", "Emoji && Symbols"));
- emojiItem->setShortcut(QKeyCombination(Qt::MetaModifier|Qt::ControlModifier, Qt::Key_Space));
- QObject::connect(emojiItem, &QPlatformMenuItem::activated, this, []{
- [NSApplication.sharedApplication orderFrontCharacterPalette:nil];
- });
-
- m_defaultEditMenuItems << separator << dictationItem << emojiItem;
- }
- for (auto defaultEditMenuItem : std::as_const(m_defaultEditMenuItems)) {
- if (menu->items().contains(defaultEditMenuItem))
- menu->removeMenuItem(defaultEditMenuItem);
- menu->insertMenuItem(defaultEditMenuItem, nullptr);
- }
- }
-}
-
QT_END_NAMESPACE
#include "moc_qcocoamenubar.cpp"
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.h b/src/plugins/platforms/cocoa/qcocoamenuitem.h
index e438fd2a07..f677ffb7a7 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.h
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.h
@@ -8,6 +8,8 @@
#include <qpa/qplatformmenu.h>
#include <QtGui/QImage>
+#include <QtCore/qpointer.h>
+
Q_FORWARD_DECLARE_OBJC_CLASS(NSMenuItem);
Q_FORWARD_DECLARE_OBJC_CLASS(NSMenu);
Q_FORWARD_DECLARE_OBJC_CLASS(NSObject);
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
index 213326f892..3a0f71bc50 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
@@ -180,38 +180,71 @@ void QCocoaMenuItem::setNativeContents(WId item)
m_itemView.needsDisplay = YES;
}
-static QPlatformMenuItem::MenuRole detectMenuRole(const QString &caption)
+static QPlatformMenuItem::MenuRole detectMenuRole(const QString &captionWithPossibleMnemonic)
{
- QString captionNoAmpersand(caption);
- captionNoAmpersand.remove(u'&');
- const QString aboutString = QCoreApplication::translate("QCocoaMenuItem", "About");
- if (captionNoAmpersand.startsWith(aboutString, Qt::CaseInsensitive)
- || captionNoAmpersand.endsWith(aboutString, Qt::CaseInsensitive)) {
+ QString itemCaption(captionWithPossibleMnemonic);
+ itemCaption.remove(u'&');
+
+ static const std::tuple<QPlatformMenuItem::MenuRole, std::vector<std::tuple<Qt::MatchFlags, const char *>>> roleMap[] = {
+ { QPlatformMenuItem::AboutRole, {
+ { Qt::MatchStartsWith | Qt::MatchEndsWith, QT_TRANSLATE_NOOP("QCocoaMenuItem", "About") }
+ }},
+ { QPlatformMenuItem::PreferencesRole, {
+ { Qt::MatchStartsWith, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Config") },
+ { Qt::MatchStartsWith, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Preference") },
+ { Qt::MatchStartsWith, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Options") },
+ { Qt::MatchStartsWith, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Setting") },
+ { Qt::MatchStartsWith, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Setup") },
+ }},
+ { QPlatformMenuItem::QuitRole, {
+ { Qt::MatchStartsWith, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Quit") },
+ { Qt::MatchStartsWith, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Exit") },
+ }},
+ { QPlatformMenuItem::CutRole, {
+ { Qt::MatchExactly, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Cut") }
+ }},
+ { QPlatformMenuItem::CopyRole, {
+ { Qt::MatchExactly, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Copy") }
+ }},
+ { QPlatformMenuItem::PasteRole, {
+ { Qt::MatchExactly, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Paste") }
+ }},
+ { QPlatformMenuItem::SelectAllRole, {
+ { Qt::MatchExactly, QT_TRANSLATE_NOOP("QCocoaMenuItem", "Select All") }
+ }},
+ };
+
+ auto match = [](const QString &caption, const QString &itemCaption, Qt::MatchFlags matchFlags) {
+ if (matchFlags.testFlag(Qt::MatchExactly))
+ return !itemCaption.compare(caption, Qt::CaseInsensitive);
+ if (matchFlags.testFlag(Qt::MatchStartsWith) && itemCaption.startsWith(caption, Qt::CaseInsensitive))
+ return true;
+ if (matchFlags.testFlag(Qt::MatchEndsWith) && itemCaption.endsWith(caption, Qt::CaseInsensitive))
+ return true;
+ return false;
+ };
+
+ QPlatformMenuItem::MenuRole detectedRole = [&]{
+ for (const auto &[role, captions] : roleMap) {
+ for (const auto &[matchFlags, caption] : captions) {
+ // Check for untranslated match
+ if (match(caption, itemCaption, matchFlags))
+ return role;
+ // Then translated with the current Qt translation
+ if (match(QCoreApplication::translate("QCocoaMenuItem", caption), itemCaption, matchFlags))
+ return role;
+ }
+ }
+ return QPlatformMenuItem::NoRole;
+ }();
+
+ if (detectedRole == QPlatformMenuItem::AboutRole) {
static const QRegularExpression qtRegExp("qt$"_L1, QRegularExpression::CaseInsensitiveOption);
- if (captionNoAmpersand.contains(qtRegExp))
- return QPlatformMenuItem::AboutQtRole;
- return QPlatformMenuItem::AboutRole;
- }
- if (captionNoAmpersand.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Config"), Qt::CaseInsensitive)
- || captionNoAmpersand.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Preference"), Qt::CaseInsensitive)
- || captionNoAmpersand.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Options"), Qt::CaseInsensitive)
- || captionNoAmpersand.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Setting"), Qt::CaseInsensitive)
- || captionNoAmpersand.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Setup"), Qt::CaseInsensitive)) {
- return QPlatformMenuItem::PreferencesRole;
+ if (itemCaption.contains(qtRegExp))
+ detectedRole = QPlatformMenuItem::AboutQtRole;
}
- if (captionNoAmpersand.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Quit"), Qt::CaseInsensitive)
- || captionNoAmpersand.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Exit"), Qt::CaseInsensitive)) {
- return QPlatformMenuItem::QuitRole;
- }
- if (!captionNoAmpersand.compare(QCoreApplication::translate("QCocoaMenuItem", "Cut"), Qt::CaseInsensitive))
- return QPlatformMenuItem::CutRole;
- if (!captionNoAmpersand.compare(QCoreApplication::translate("QCocoaMenuItem", "Copy"), Qt::CaseInsensitive))
- return QPlatformMenuItem::CopyRole;
- if (!captionNoAmpersand.compare(QCoreApplication::translate("QCocoaMenuItem", "Paste"), Qt::CaseInsensitive))
- return QPlatformMenuItem::PasteRole;
- if (!captionNoAmpersand.compare(QCoreApplication::translate("QCocoaMenuItem", "Select All"), Qt::CaseInsensitive))
- return QPlatformMenuItem::SelectAllRole;
- return QPlatformMenuItem::NoRole;
+
+ return detectedRole;
}
NSMenuItem *QCocoaMenuItem::sync()
@@ -440,7 +473,20 @@ void QCocoaMenuItem::resolveTargetAction()
roleAction = @selector(selectAll:);
break;
default:
- roleAction = @selector(qt_itemFired:);
+ if (m_menu) {
+ // Menu items that represent sub menus should have submenuAction: as their
+ // action, so that clicking the menu item opens the sub menu without closing
+ // the entire menu hierarchy. A menu item with this action and a valid submenu
+ // will disable NSMenuValidation for the item, which is normally not an issue
+ // as NSMenuItems are enabled by default. But in our case, we haven't attached
+ // the submenu yet, which results in AppKit concluding that there's no validator
+ // for the item (the target is nil, and nothing responds to submenuAction:), and
+ // will in response disable the menu item. To work around this we explicitly
+ // enable the menu item in QCocoaMenu::setAttachedItem() once we have a submenu.
+ roleAction = @selector(submenuAction:);
+ } else {
+ roleAction = @selector(qt_itemFired:);
+ }
}
m_native.action = roleAction;
diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
index 6d3c668b87..b5ee3479aa 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
@@ -186,8 +186,8 @@
if (appMenu.supermenu)
unparentAppMenu(appMenu.supermenu);
- NSMenuItem *appMenuItem = [[NSMenuItem alloc] initWithTitle:@"Apple"
- action:nil keyEquivalent:@""];
+ NSMenuItem *appMenuItem = [[[NSMenuItem alloc] initWithTitle:@"Apple"
+ action:nil keyEquivalent:@""] autorelease];
appMenuItem.submenu = appMenu;
[menu insertItem:appMenuItem atIndex:0];
}
diff --git a/src/plugins/platforms/cocoa/qcocoamessagedialog.h b/src/plugins/platforms/cocoa/qcocoamessagedialog.h
index 564dd915c5..b8c273469a 100644
--- a/src/plugins/platforms/cocoa/qcocoamessagedialog.h
+++ b/src/plugins/platforms/cocoa/qcocoamessagedialog.h
@@ -28,6 +28,7 @@ private:
Qt::WindowModality modality() const;
NSAlert *m_alert = nullptr;
QEventLoop *m_eventLoop = nullptr;
+ NSModalResponse runModal() const;
void processResponse(NSModalResponse response);
};
diff --git a/src/plugins/platforms/cocoa/qcocoamessagedialog.mm b/src/plugins/platforms/cocoa/qcocoamessagedialog.mm
index f19146c60c..84525099c9 100644
--- a/src/plugins/platforms/cocoa/qcocoamessagedialog.mm
+++ b/src/plugins/platforms/cocoa/qcocoamessagedialog.mm
@@ -5,6 +5,7 @@
#include "qcocoawindow.h"
#include "qcocoahelpers.h"
+#include "qcocoaeventdispatcher.h"
#include <QtCore/qmetaobject.h>
#include <QtCore/qscopedvaluerollback.h>
@@ -90,8 +91,17 @@ bool QCocoaMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality w
if (!options())
return false;
- if (windowModality == Qt::ApplicationModal && QThread::currentThread()->loopLevel() > 1) {
- qCWarning(lcQpaDialogs, "Cannot use native application modal dialog from nested event loop");
+ // NSAlert doesn't have a section for detailed text
+ if (!options()->detailedText().isEmpty()) {
+ qCWarning(lcQpaDialogs, "Message box contains detailed text");
+ return false;
+ }
+
+ if (Qt::mightBeRichText(options()->text()) ||
+ Qt::mightBeRichText(options()->informativeText())) {
+ // Let's fallback to non-native message box,
+ // we only have plain NSString/text in NSAlert.
+ qCDebug(lcQpaDialogs, "Message box contains text in rich text format");
return false;
}
@@ -99,10 +109,7 @@ bool QCocoaMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality w
m_alert = [NSAlert new];
m_alert.window.title = options()->windowTitle().toNSString();
- QString text = toPlainText(options()->text());
- QString details = toPlainText(options()->detailedText());
- if (!details.isEmpty())
- text += u"\n\n"_s + details;
+ const QString text = toPlainText(options()->text());
m_alert.messageText = text.toNSString();
m_alert.informativeText = toPlainText(options()->informativeText()).toNSString();
@@ -130,8 +137,8 @@ bool QCocoaMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality w
break;
}
- bool defaultButtonAdded = false;
- bool cancelButtonAdded = false;
+ auto defaultButton = options()->defaultButton();
+ auto escapeButton = options()->escapeButton();
const auto addButton = [&](auto title, auto tag, auto role) {
title = QPlatformTheme::removeMnemonics(title);
@@ -141,17 +148,27 @@ bool QCocoaMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality w
// and going toward the left/bottom. By default, the first button has a key equivalent of
// Return, any button with a title of "Cancel" has a key equivalent of Escape, and any button
// with the title "Don't Save" has a key equivalent of Command-D (but only if it's not the first
- // button). Unfortunately QMessageBox does not currently plumb setDefaultButton/setEscapeButton
- // through the dialog options, so we can't forward this information directly. The closest we
- // can get right now is to use the role to set the button's key equivalent.
+ // button). If an explicit default or escape button has been set, we respect these,
+ // and otherwise we fall back to role-based default and escape buttons.
+
+ qCDebug(lcQpaDialogs).verbosity(0) << "Adding button" << title << "with" << role;
+
+ if (!defaultButton && role == AcceptRole)
+ defaultButton = tag;
- if (role == AcceptRole && !defaultButtonAdded) {
+ if (tag == defaultButton)
button.keyEquivalent = @"\r";
- defaultButtonAdded = true;
- } else if (role == RejectRole && !cancelButtonAdded) {
+ else if ([button.keyEquivalent isEqualToString:@"\r"])
+ button.keyEquivalent = @"";
+
+ if (!escapeButton && role == RejectRole)
+ escapeButton = tag;
+
+ // Don't override default button with escape button, to match AppKit default
+ if (tag == escapeButton && ![button.keyEquivalent isEqualToString:@"\r"])
button.keyEquivalent = @"\e";
- cancelButtonAdded = true;
- }
+ else if ([button.keyEquivalent isEqualToString:@"\e"])
+ button.keyEquivalent = @"";
if (@available(macOS 11, *))
button.hasDestructiveAction = role == DestructiveRole;
@@ -171,30 +188,69 @@ bool QCocoaMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality w
button.tag = tag;
};
+ // Resolve all dialog buttons from the options, both standard and custom
+
+ struct Button { QString title; int identifier; ButtonRole role; };
+ std::vector<Button> buttons;
+
const auto *platformTheme = QGuiApplicationPrivate::platformTheme();
if (auto standardButtons = options()->standardButtons()) {
- for (int standardButton = FirstButton; standardButton < LastButton; standardButton <<= 1) {
+ for (int standardButton = FirstButton; standardButton <= LastButton; standardButton <<= 1) {
if (standardButtons & standardButton) {
auto title = platformTheme->standardButtonText(standardButton);
- addButton(title, standardButton, buttonRole(StandardButton(standardButton)));
+ buttons.push_back({
+ title, standardButton, buttonRole(StandardButton(standardButton))
+ });
}
}
}
-
const auto customButtons = options()->customButtons();
for (auto customButton : customButtons)
- addButton(customButton.label, customButton.id, customButton.role);
+ buttons.push_back({customButton.label, customButton.id, customButton.role});
+
+ // Sort them according to the QPlatformDialogHelper::ButtonLayout for macOS
+
+ // The ButtonLayout adds one additional role, AlternateRole, which is used
+ // for any AcceptRole beyond the first one, and should be ordered before the
+ // AcceptRole. Set this up by fixing the roles up front.
+ bool seenAccept = false;
+ for (auto &button : buttons) {
+ if (button.role == AcceptRole) {
+ if (!seenAccept)
+ seenAccept = true;
+ else
+ button.role = AlternateRole;
+ }
+ }
+
+ std::vector<Button> orderedButtons;
+ const int *layoutEntry = buttonLayout(Qt::Horizontal, ButtonLayout::MacLayout);
+ while (*layoutEntry != QPlatformDialogHelper::EOL) {
+ const auto role = ButtonRole(*layoutEntry & ~ButtonRole::Reverse);
+ const bool reverse = *layoutEntry & ButtonRole::Reverse;
+
+ auto addButton = [&](const Button &button) {
+ if (button.role == role)
+ orderedButtons.push_back(button);
+ };
+ if (reverse)
+ std::for_each(std::crbegin(buttons), std::crend(buttons), addButton);
+ else
+ std::for_each(std::cbegin(buttons), std::cend(buttons), addButton);
- // QMessageDialog's logic for adding a fallback OK button if no other buttons
- // are added depends on QMessageBox::showEvent(), which is too late when
- // native dialogs are in use. To ensure there's always an OK button with a tag
- // we recognize we add it explicitly here as a fallback.
- if (!m_alert.buttons.count) {
- addButton(platformTheme->standardButtonText(StandardButton::Ok),
- StandardButton::Ok, ButtonRole::AcceptRole);
+ ++layoutEntry;
}
+ // Add them to the alert in reverse order, since buttons are added right to left
+ for (auto button = orderedButtons.crbegin(); button != orderedButtons.crend(); ++button)
+ addButton(button->title, button->identifier, button->role);
+
+ // If we didn't find a an explicit or implicit default button above
+ // we restore the AppKit behavior of making the first button default.
+ if (!defaultButton)
+ m_alert.buttons.firstObject.keyEquivalent = @"\r";
+
if (auto checkBoxLabel = options()->checkBoxLabel(); !checkBoxLabel.isNull()) {
checkBoxLabel = QPlatformTheme::removeMnemonics(checkBoxLabel);
m_alert.suppressionButton.title = checkBoxLabel.toNSString();
@@ -222,9 +278,10 @@ bool QCocoaMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality w
// but also make sure that if the user returns to the main runloop
// we'll run the modal dialog from there.
QTimer::singleShot(0, this, [this]{
- if (m_alert && NSApp.modalWindow != m_alert.window) {
+ if (m_alert && !m_alert.window.visible) {
qCDebug(lcQpaDialogs) << "Running deferred modal" << m_alert;
- processResponse([m_alert runModal]);
+ QCocoaEventDispatcher::clearCurrentThreadCocoaEventDispatcherInterruptFlag();
+ processResponse(runModal());
}
});
}
@@ -232,6 +289,20 @@ bool QCocoaMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality w
return true;
}
+// We shouldn't get NSModalResponseContinue as a response from NSAlert::runModal,
+// and processResponse must not be called with that value (if we are there, it's
+// too late to do anything about it.
+// However, as QTBUG-114546 shows, there are scenarios where we might get that
+// response anyway. We interpret it to keep the modal loop running, and we only
+// return if we got something else to pass to processResponse.
+NSModalResponse QCocoaMessageDialog::runModal() const
+{
+ NSModalResponse response = NSModalResponseContinue;
+ while (response == NSModalResponseContinue)
+ response = [m_alert runModal];
+ return response;
+}
+
void QCocoaMessageDialog::exec()
{
Q_ASSERT(m_alert);
@@ -243,7 +314,8 @@ void QCocoaMessageDialog::exec()
m_eventLoop->exec(QEventLoop::DialogExec);
} else {
qCDebug(lcQpaDialogs) << "Running modal" << m_alert;
- processResponse([m_alert runModal]);
+ QCocoaEventDispatcher::clearCurrentThreadCocoaEventDispatcherInterruptFlag();
+ processResponse(runModal());
}
}
diff --git a/src/plugins/platforms/cocoa/qcocoansmenu.mm b/src/plugins/platforms/cocoa/qcocoansmenu.mm
index 4bc9b0b5f9..ba222a3ef4 100644
--- a/src/plugins/platforms/cocoa/qcocoansmenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoansmenu.mm
@@ -16,6 +16,8 @@
#include <QtCore/qvarlengtharray.h>
#include <QtGui/private/qapplekeymapper_p.h>
+#include <QtCore/qpointer.h>
+
static NSString *qt_mac_removePrivateUnicode(NSString *string)
{
if (const int len = string.length) {
diff --git a/src/plugins/platforms/cocoa/qcocoascreen.h b/src/plugins/platforms/cocoa/qcocoascreen.h
index 435a6b95d8..7708dc1968 100644
--- a/src/plugins/platforms/cocoa/qcocoascreen.h
+++ b/src/plugins/platforms/cocoa/qcocoascreen.h
@@ -41,13 +41,14 @@ public:
QWindow *topLevelAt(const QPoint &point) const override;
QList<QPlatformScreen *> virtualSiblings() const override;
QPlatformScreen::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const override;
+ Qt::ScreenOrientation orientation() const override;
// ----------------------------------------------------
static NSScreen *nativeScreenForDisplayId(CGDirectDisplayID displayId);
NSScreen *nativeScreen() const;
- void requestUpdate();
+ bool requestUpdate();
void deliverUpdateRequests();
bool isRunningDisplayLink() const;
@@ -90,6 +91,7 @@ private:
QSizeF m_physicalSize;
QCocoaCursor *m_cursor;
qreal m_devicePixelRatio = 0;
+ qreal m_rotation = 0;
CVDisplayLinkRef m_displayLink = nullptr;
dispatch_source_t m_displayLinkSource = nullptr;
diff --git a/src/plugins/platforms/cocoa/qcocoascreen.mm b/src/plugins/platforms/cocoa/qcocoascreen.mm
index 078d8a1c72..be562e5455 100644
--- a/src/plugins/platforms/cocoa/qcocoascreen.mm
+++ b/src/plugins/platforms/cocoa/qcocoascreen.mm
@@ -15,6 +15,7 @@
#include <IOKit/graphics/IOGraphicsLib.h>
#include <QtGui/private/qwindow_p.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtCore/private/qcore_mac_p.h>
#include <QtCore/private/qeventdispatcher_cf_p.h>
@@ -199,7 +200,7 @@ QCocoaScreen::~QCocoaScreen()
static QString displayName(CGDirectDisplayID displayID)
{
QIOType<io_iterator_t> iterator;
- if (IOServiceGetMatchingServices(kIOMasterPortDefault,
+ if (IOServiceGetMatchingServices(kIOMainPortDefault,
IOServiceMatching("IODisplayConnect"), &iterator))
return QString();
@@ -247,6 +248,7 @@ void QCocoaScreen::update(CGDirectDisplayID displayId)
const QRect previousGeometry = m_geometry;
const QRect previousAvailableGeometry = m_availableGeometry;
const qreal previousRefreshRate = m_refreshRate;
+ const double previousRotation = m_rotation;
// The reference screen for the geometry is always the primary screen
QRectF primaryScreenGeometry = QRectF::fromCGRect(CGDisplayBounds(CGMainDisplayID()));
@@ -271,6 +273,7 @@ void QCocoaScreen::update(CGDirectDisplayID displayId)
QCFType<CGDisplayModeRef> displayMode = CGDisplayCopyDisplayMode(m_displayId);
float refresh = CGDisplayModeGetRefreshRate(displayMode);
m_refreshRate = refresh > 0 ? refresh : 60.0;
+ m_rotation = CGDisplayRotation(displayId);
if (@available(macOS 10.15, *))
m_name = QString::fromNSString(nsScreen.localizedName);
@@ -279,6 +282,9 @@ void QCocoaScreen::update(CGDirectDisplayID displayId)
const bool didChangeGeometry = m_geometry != previousGeometry || m_availableGeometry != previousAvailableGeometry;
+ if (m_rotation != previousRotation)
+ QWindowSystemInterface::handleScreenOrientationChange(screen(), orientation());
+
if (didChangeGeometry)
QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry());
if (m_refreshRate != previousRefreshRate)
@@ -289,24 +295,33 @@ void QCocoaScreen::update(CGDirectDisplayID displayId)
Q_LOGGING_CATEGORY(lcQpaScreenUpdates, "qt.qpa.screen.updates", QtCriticalMsg);
-void QCocoaScreen::requestUpdate()
+bool QCocoaScreen::requestUpdate()
{
Q_ASSERT(m_displayId);
if (!isOnline()) {
qCDebug(lcQpaScreenUpdates) << this << "is not online. Ignoring update request";
- return;
+ return false;
}
if (!m_displayLink) {
- CVDisplayLinkCreateWithCGDisplay(m_displayId, &m_displayLink);
+ qCDebug(lcQpaScreenUpdates) << "Creating display link for" << this;
+ if (CVDisplayLinkCreateWithCGDisplay(m_displayId, &m_displayLink) != kCVReturnSuccess) {
+ qCWarning(lcQpaScreenUpdates) << "Failed to create display link for" << this;
+ return false;
+ }
+ if (auto displayId = CVDisplayLinkGetCurrentCGDisplay(m_displayLink); displayId != m_displayId) {
+ qCWarning(lcQpaScreenUpdates) << "Unexpected display" << displayId << "for display link";
+ CVDisplayLinkRelease(m_displayLink);
+ m_displayLink = nullptr;
+ return false;
+ }
CVDisplayLinkSetOutputCallback(m_displayLink, [](CVDisplayLinkRef, const CVTimeStamp*,
const CVTimeStamp*, CVOptionFlags, CVOptionFlags*, void* displayLinkContext) -> int {
// FIXME: It would be nice if update requests would include timing info
static_cast<QCocoaScreen*>(displayLinkContext)->deliverUpdateRequests();
return kCVReturnSuccess;
}, this);
- qCDebug(lcQpaScreenUpdates) << "Display link created for" << this;
// During live window resizing -[NSWindow _resizeWithEvent:] will spin a local event loop
// in event-tracking mode, dequeuing only the mouse drag events needed to update the window's
@@ -361,6 +376,8 @@ void QCocoaScreen::requestUpdate()
qCDebug(lcQpaScreenUpdates) << "Starting display link for" << this;
CVDisplayLinkStart(m_displayLink);
}
+
+ return true;
}
// Helper to allow building up debug output in multiple steps
@@ -510,41 +527,56 @@ QPlatformScreen::SubpixelAntialiasingType QCocoaScreen::subpixelAntialiasingType
return type;
}
+Qt::ScreenOrientation QCocoaScreen::orientation() const
+{
+ if (m_rotation == 0)
+ return Qt::LandscapeOrientation;
+ if (m_rotation == 90)
+ return Qt::PortraitOrientation;
+ if (m_rotation == 180)
+ return Qt::InvertedLandscapeOrientation;
+ if (m_rotation == 270)
+ return Qt::InvertedPortraitOrientation;
+ return QPlatformScreen::orientation();
+}
+
QWindow *QCocoaScreen::topLevelAt(const QPoint &point) const
{
- NSPoint screenPoint = mapToNative(point);
-
- // Search (hit test) for the top-level window. [NSWidow windowNumberAtPoint:
- // belowWindowWithWindowNumber] may return windows that are not interesting
- // to Qt. The search iterates until a suitable window or no window is found.
- NSInteger topWindowNumber = 0;
- QWindow *window = nullptr;
- do {
- // Get the top-most window, below any previously rejected window.
- topWindowNumber = [NSWindow windowNumberAtPoint:screenPoint
- belowWindowWithWindowNumber:topWindowNumber];
-
- // Continue the search if the window does not belong to this process.
- NSWindow *nsWindow = [NSApp windowWithWindowNumber:topWindowNumber];
- if (!nsWindow)
- continue;
+ __block QWindow *window = nullptr;
+ [NSApp enumerateWindowsWithOptions:NSWindowListOrderedFrontToBack
+ usingBlock:^(NSWindow *nsWindow, BOOL *stop) {
+ if (!nsWindow)
+ return;
- // Continue the search if the window does not belong to Qt.
- if (![nsWindow conformsToProtocol:@protocol(QNSWindowProtocol)])
- continue;
+ // Continue the search if the window does not belong to Qt
+ if (![nsWindow conformsToProtocol:@protocol(QNSWindowProtocol)])
+ return;
- QCocoaWindow *cocoaWindow = qnsview_cast(nsWindow.contentView).platformWindow;
- if (!cocoaWindow)
- continue;
- window = cocoaWindow->window();
+ QCocoaWindow *cocoaWindow = qnsview_cast(nsWindow.contentView).platformWindow;
+ if (!cocoaWindow)
+ return;
+
+ QWindow *w = cocoaWindow->window();
+ if (!w->isVisible())
+ return;
- // Continue the search if the window is not a top-level window.
- if (!window->isTopLevel())
- continue;
+ auto nativeGeometry = QHighDpi::toNativePixels(w->geometry(), w);
+ if (!nativeGeometry.contains(point))
+ return;
- // Stop searching. The current window is the correct window.
- break;
- } while (topWindowNumber > 0);
+ QRegion mask = QHighDpi::toNativeLocalPosition(w->mask(), w);
+ if (!mask.isEmpty() && !mask.contains(point - nativeGeometry.topLeft()))
+ return;
+
+ window = w;
+
+ // Continue the search if the window is not a top-level window
+ if (!window->isTopLevel())
+ return;
+
+ *stop = true;
+ }
+ ];
return window;
}
diff --git a/src/plugins/platforms/cocoa/qcocoaservices.h b/src/plugins/platforms/cocoa/qcocoaservices.h
index 20d9b67760..b6299570e8 100644
--- a/src/plugins/platforms/cocoa/qcocoaservices.h
+++ b/src/plugins/platforms/cocoa/qcocoaservices.h
@@ -4,6 +4,8 @@
#ifndef QCOCOADESKTOPSERVICES_H
#define QCOCOADESKTOPSERVICES_H
+#include <QtCore/qurl.h>
+
#include <qpa/qplatformservices.h>
QT_BEGIN_NAMESPACE
@@ -11,8 +13,16 @@ QT_BEGIN_NAMESPACE
class QCocoaServices : public QPlatformServices
{
public:
+ bool hasCapability(Capability capability) const override;
+
bool openUrl(const QUrl &url) override;
bool openDocument(const QUrl &url) override;
+ bool handleUrl(const QUrl &url);
+
+ QPlatformServiceColorPicker *colorPicker(QWindow *parent) override;
+
+private:
+ QUrl m_handlingUrl;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoaservices.mm b/src/plugins/platforms/cocoa/qcocoaservices.mm
index 68daa660ef..87212c265c 100644
--- a/src/plugins/platforms/cocoa/qcocoaservices.mm
+++ b/src/plugins/platforms/cocoa/qcocoaservices.mm
@@ -4,14 +4,23 @@
#include "qcocoaservices.h"
#include <AppKit/NSWorkspace.h>
+#include <AppKit/NSColorSampler.h>
#include <Foundation/NSURL.h>
#include <QtCore/QUrl>
+#include <QtCore/qscopedvaluerollback.h>
+
+#include <QtGui/qdesktopservices.h>
+#include <QtGui/private/qcoregraphics_p.h>
QT_BEGIN_NAMESPACE
bool QCocoaServices::openUrl(const QUrl &url)
{
+ // avoid recursing back into self
+ if (url == m_handlingUrl)
+ return false;
+
return [[NSWorkspace sharedWorkspace] openURL:url.toNSURL()];
}
@@ -20,4 +29,45 @@ bool QCocoaServices::openDocument(const QUrl &url)
return openUrl(url);
}
+/* Callback from macOS that the application should handle a URL */
+bool QCocoaServices::handleUrl(const QUrl &url)
+{
+ QScopedValueRollback<QUrl> rollback(m_handlingUrl, url);
+ // FIXME: Add platform services callback from QDesktopServices::setUrlHandler
+ // so that we can warn the user if calling setUrlHandler without also setting
+ // up the matching keys in the Info.plist file (CFBundleURLTypes and friends).
+ return QDesktopServices::openUrl(url);
+}
+
+class QCocoaColorPicker : public QPlatformServiceColorPicker
+{
+public:
+ QCocoaColorPicker() : m_colorSampler([NSColorSampler new]) {}
+ ~QCocoaColorPicker() { [m_colorSampler release]; }
+
+ void pickColor() override
+ {
+ [m_colorSampler showSamplerWithSelectionHandler:^(NSColor *selectedColor) {
+ emit colorPicked(qt_mac_toQColor(selectedColor));
+ }];
+ }
+private:
+ NSColorSampler *m_colorSampler = nullptr;
+};
+
+
+QPlatformServiceColorPicker *QCocoaServices::colorPicker(QWindow *parent)
+{
+ Q_UNUSED(parent);
+ return new QCocoaColorPicker;
+}
+
+bool QCocoaServices::hasCapability(Capability capability) const
+{
+ switch (capability) {
+ case ColorPicking: return true;
+ default: return false;
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
index ec366f5483..cec8301cf6 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
@@ -184,7 +184,18 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
void QCocoaSystemTrayIcon::updateMenu(QPlatformMenu *menu)
{
- m_statusItem.menu = menu ? static_cast<QCocoaMenu *>(menu)->nsMenu() : nil;
+ auto *nsMenu = menu ? static_cast<QCocoaMenu *>(menu)->nsMenu() : nil;
+ if (m_statusItem.menu == nsMenu)
+ return;
+
+ if (m_statusItem.menu) {
+ [NSNotificationCenter.defaultCenter removeObserver:m_delegate
+ name:NSMenuDidBeginTrackingNotification
+ object:m_statusItem.menu
+ ];
+ }
+
+ m_statusItem.menu = nsMenu;
if (m_statusItem.menu) {
// When a menu is assigned, NSStatusBarButtonCell will intercept the mouse
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h
index a7c37a685c..c49d83feae 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.h
+++ b/src/plugins/platforms/cocoa/qcocoatheme.h
@@ -35,6 +35,7 @@ public:
const QFont *font(Font type = SystemFont) const override;
QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const override;
QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions options = {}) const override;
+ QIconEngine *createIconEngine(const QString &iconName) const override;
QVariant themeHint(ThemeHint hint) const override;
Qt::ColorScheme colorScheme() const override;
@@ -54,6 +55,9 @@ private:
QMacNotificationObserver m_systemColorObserver;
mutable QHash<QPlatformTheme::Palette, QPalette*> m_palettes;
QMacKeyValueObserver m_appearanceObserver;
+
+ Qt::ColorScheme m_colorScheme = Qt::ColorScheme::Unknown;
+ void updateColorScheme();
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm
index 594df204e5..f4fbfadbe4 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.mm
+++ b/src/plugins/platforms/cocoa/qcocoatheme.mm
@@ -22,6 +22,7 @@
#include <QtGui/qpainter.h>
#include <QtGui/qtextformat.h>
#include <QtGui/private/qcoretextfontdatabase_p.h>
+#include <QtGui/private/qappleiconengine_p.h>
#include <QtGui/private/qfontengine_coretext_p.h>
#include <QtGui/private/qabstractfileiconengine_p.h>
#include <qpa/qplatformdialoghelper.h>
@@ -94,6 +95,9 @@ static QPalette *qt_mac_createSystemPalette()
palette->setColor(QPalette::Inactive, QPalette::PlaceholderText, qc);
palette->setColor(QPalette::Disabled, QPalette::PlaceholderText, qc);
+ qc = qt_mac_toQColor([NSColor controlAccentColor]);
+ palette->setColor(QPalette::Accent, qc);
+
return palette;
}
@@ -221,6 +225,8 @@ QCocoaTheme::QCocoaTheme()
NSSystemColorsDidChangeNotification, [this] {
handleSystemThemeChange();
});
+
+ updateColorScheme();
}
QCocoaTheme::~QCocoaTheme()
@@ -239,6 +245,9 @@ void QCocoaTheme::reset()
void QCocoaTheme::handleSystemThemeChange()
{
reset();
+
+ updateColorScheme();
+
m_systemPalette = qt_mac_createSystemPalette();
m_palettes = qt_mac_createRolePalettes();
@@ -401,19 +410,8 @@ public:
QPlatformTheme::IconOptions opts) :
QAbstractFileIconEngine(info, opts) {}
- static QList<QSize> availableIconSizes()
- {
- const qreal devicePixelRatio = qGuiApp->devicePixelRatio();
- const int sizes[] = {
- qRound(16 * devicePixelRatio), qRound(32 * devicePixelRatio),
- qRound(64 * devicePixelRatio), qRound(128 * devicePixelRatio),
- qRound(256 * devicePixelRatio)
- };
- return QAbstractFileIconEngine::toSizeList(sizes, sizes + sizeof(sizes) / sizeof(sizes[0]));
- }
-
QList<QSize> availableSizes(QIcon::Mode = QIcon::Normal, QIcon::State = QIcon::Off) override
- { return QCocoaFileIconEngine::availableIconSizes(); }
+ { return QAppleIconEngine::availableIconSizes(); }
protected:
QPixmap filePixmap(const QSize &size, QIcon::Mode, QIcon::State) override
@@ -432,6 +430,11 @@ QIcon QCocoaTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptio
return QIcon(new QCocoaFileIconEngine(fileInfo, iconOptions));
}
+QIconEngine *QCocoaTheme::createIconEngine(const QString &iconName) const
+{
+ return new QAppleIconEngine(iconName);
+}
+
QVariant QCocoaTheme::themeHint(ThemeHint hint) const
{
switch (hint) {
@@ -445,7 +448,7 @@ QVariant QCocoaTheme::themeHint(ThemeHint hint) const
return QVariant([[NSApplication sharedApplication] isFullKeyboardAccessEnabled] ?
int(Qt::TabFocusAllControls) : int(Qt::TabFocusTextControls | Qt::TabFocusListControls));
case IconPixmapSizes:
- return QVariant::fromValue(QCocoaFileIconEngine::availableIconSizes());
+ return QVariant::fromValue(QAppleIconEngine::availableIconSizes());
case QPlatformTheme::PasswordMaskCharacter:
return QVariant(QChar(0x2022));
case QPlatformTheme::UiEffects:
@@ -472,7 +475,19 @@ QVariant QCocoaTheme::themeHint(ThemeHint hint) const
Qt::ColorScheme QCocoaTheme::colorScheme() const
{
- return qt_mac_applicationIsInDarkMode() ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light;
+ return m_colorScheme;
+}
+
+/*
+ Update the theme's color scheme based on the current appearance.
+
+ We can only reference the appearance on the main thread, but the
+ CoreText font engine needs to know the color scheme, and might be
+ used from secondary threads, so we cache the color scheme.
+*/
+void QCocoaTheme::updateColorScheme()
+{
+ m_colorScheme = qt_mac_applicationIsInDarkMode() ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light;
}
QString QCocoaTheme::standardButtonText(int button) const
@@ -490,12 +505,16 @@ QKeySequence QCocoaTheme::standardButtonShortcut(int button) const
QPlatformMenuItem *QCocoaTheme::createPlatformMenuItem() const
{
- return new QCocoaMenuItem();
+ auto *menuItem = new QCocoaMenuItem();
+ qCDebug(lcQpaMenus) << "Created" << menuItem;
+ return menuItem;
}
QPlatformMenu *QCocoaTheme::createPlatformMenu() const
{
- return new QCocoaMenu();
+ auto *menu = new QCocoaMenu();
+ qCDebug(lcQpaMenus) << "Created" << menu;
+ return menu;
}
QPlatformMenuBar *QCocoaTheme::createPlatformMenuBar() const
@@ -508,7 +527,9 @@ QPlatformMenuBar *QCocoaTheme::createPlatformMenuBar() const
SLOT(onAppFocusWindowChanged(QWindow*)));
}
- return new QCocoaMenuBar();
+ auto *menuBar = new QCocoaMenuBar();
+ qCDebug(lcQpaMenus) << "Created" << menuBar;
+ return menuBar;
}
#ifndef QT_NO_SHORTCUT
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 2083803c6d..4a245a0f8a 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -117,20 +117,26 @@ void QCocoaWindow::initialize()
if (!m_view)
m_view = [[QNSView alloc] initWithCocoaWindow:this];
- // Compute the initial geometry based on the geometry set on the
- // QWindow. This geometry has already been reflected to the
- // QPlatformWindow in the constructor, so to ensure that the
- // resulting setGeometry call does not think the geometry has
- // already been applied, we reset the QPlatformWindow's view
- // of the geometry first.
- auto initialGeometry = QPlatformWindow::initialGeometry(window(),
- windowGeometry(), defaultWindowWidth, defaultWindowHeight);
- QPlatformWindow::d_ptr->rect = QRect();
- setGeometry(initialGeometry);
+ if (!isForeignWindow()) {
+ // Compute the initial geometry based on the geometry set on the
+ // QWindow. This geometry has already been reflected to the
+ // QPlatformWindow in the constructor, so to ensure that the
+ // resulting setGeometry call does not think the geometry has
+ // already been applied, we reset the QPlatformWindow's view
+ // of the geometry first.
+ auto initialGeometry = QPlatformWindow::initialGeometry(window(),
+ windowGeometry(), defaultWindowWidth, defaultWindowHeight);
+ QPlatformWindow::d_ptr->rect = QRect();
+ setGeometry(initialGeometry);
+
+ setMask(QHighDpi::toNativeLocalRegion(window()->mask(), window()));
- recreateWindowIfNeeded();
+ } else {
+ // Pick up essential foreign window state
+ QPlatformWindow::setGeometry(QRectF::fromCGRect(m_view.frame).toRect());
+ }
- setMask(QHighDpi::toNativeLocalRegion(window()->mask(), window()));
+ recreateWindowIfNeeded();
m_initialized = true;
}
@@ -144,7 +150,10 @@ QCocoaWindow::~QCocoaWindow()
QMacAutoReleasePool pool;
[m_nsWindow makeFirstResponder:nil];
[m_nsWindow setContentView:nil];
- if ([m_view superview])
+
+ // Remove from superview only if we have a Qt window parent,
+ // as we don't want to affect window container foreign windows.
+ if (QPlatformWindow::parent())
[m_view removeFromSuperview];
// Make sure to disconnect observer in all case if view is valid
@@ -168,8 +177,7 @@ QCocoaWindow::~QCocoaWindow()
object:m_view];
[m_view release];
- [m_nsWindow close];
- [m_nsWindow release];
+ [m_nsWindow closeAndRelease];
}
QSurfaceFormat QCocoaWindow::format() const
@@ -300,6 +308,31 @@ void QCocoaWindow::setVisible(bool visible)
{
qCDebug(lcQpaWindow) << "QCocoaWindow::setVisible" << window() << visible;
+ // Our implementation of setVisible below is not idempotent, as for
+ // modal windows it calls beginSheet/endSheet or starts/ends modal
+ // sessions. However we can't simply guard for m_view.hidden already
+ // having the right state, as the behavior of this function differs
+ // based on whether the window has been initialized or not, as
+ // handleGeometryChange will bail out if the window is still
+ // initializing. Since we know we'll get a second setVisible
+ // call after creation, we can check for that case specifically,
+ // which means we can then safely guard on m_view.hidden changing.
+
+ if (!m_initialized) {
+ qCDebug(lcQpaWindow) << "Window still initializing, skipping setting visibility";
+ return; // We'll get another setVisible call after create is done
+ }
+
+ if (visible == !m_view.hidden && (!isContentView() || visible == m_view.window.visible)) {
+ qCDebug(lcQpaWindow) << "No change in visible status. Ignoring.";
+ return;
+ }
+
+ if (m_inSetVisible) {
+ qCWarning(lcQpaWindow) << "Already setting window visible!";
+ return;
+ }
+
QScopedValueRollback<bool> rollback(m_inSetVisible, true);
QMacAutoReleasePool pool;
@@ -338,6 +371,9 @@ void QCocoaWindow::setVisible(bool visible)
}
+ // Make the NSView visible first, before showing the NSWindow (in case of top level windows)
+ m_view.hidden = NO;
+
if (isContentView()) {
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
@@ -375,13 +411,6 @@ void QCocoaWindow::setVisible(bool visible)
}
}
}
-
- // In some cases, e.g. QDockWidget, the content view is hidden before moving to its own
- // Cocoa window, and then shown again. Therefore, we test for the view being hidden even
- // if it's attached to an NSWindow.
- if ([m_view isHidden])
- [m_view setHidden:NO];
-
} else {
// Window not visible, hide it
if (isContentView()) {
@@ -410,10 +439,28 @@ void QCocoaWindow::setVisible(bool visible)
if (mainWindow && [mainWindow canBecomeKeyWindow])
[mainWindow makeKeyWindow];
}
- } else {
- [m_view setHidden:YES];
}
+ // AppKit will in some cases set up the key view loop for child views, even if we
+ // don't set autorecalculatesKeyViewLoop, nor call recalculateKeyViewLoop ourselves.
+ // When a child window is promoted to a top level, AppKit will maintain the key view
+ // loop between the views, even if these views now cross NSWindows, even after we
+ // explicitly call recalculateKeyViewLoop. When the top level is then hidden, AppKit
+ // will complain when -[NSView _setHidden:setNeedsDisplay:] tries to transfer first
+ // responder by reading the nextValidKeyView, and it turns out to live in a different
+ // window. We mitigate this by a last second reset of the first responder, which is
+ // what AppKit also falls back to. It's unclear if the original situation of views
+ // having their nextKeyView pointing to views in other windows is kosher or not.
+ if (m_view.window.firstResponder == m_view && m_view.nextValidKeyView
+ && m_view.nextValidKeyView.window != m_view.window) {
+ qCDebug(lcQpaWindow) << "Detected nextValidKeyView" << m_view.nextValidKeyView
+ << "in different window" << m_view.nextValidKeyView.window
+ << "Resetting" << m_view.window << "first responder to nil.";
+ [m_view.window makeFirstResponder:nil];
+ }
+
+ m_view.hidden = YES;
+
if (parentCocoaWindow && window()->type() == Qt::Popup) {
NSWindow *nativeParentWindow = parentCocoaWindow->nativeWindow();
if (m_resizableTransientParent
@@ -551,10 +598,17 @@ void QCocoaWindow::updateTitleBarButtons(Qt::WindowFlags windowFlags)
bool hideButtons = true;
for (const auto &[button, buttonHint] : buttons) {
+ // Set up Qt defaults based on window type
bool enabled = true;
+ if (button == NSWindowMiniaturizeButton)
+ enabled = window()->type() != Qt::Dialog;
+
+ // Let users override via CustomizeWindowHint
if (windowFlags & Qt::CustomizeWindowHint)
enabled = windowFlags & buttonHint;
+ // Then do some final sanitizations
+
if (button == NSWindowZoomButton && isFixedSize())
enabled = false;
@@ -1192,32 +1246,33 @@ void QCocoaWindow::windowDidEndLiveResize()
void QCocoaWindow::windowDidBecomeKey()
{
- if (!isContentView())
+ // The NSWindow we're part of become key. Check if we're the first
+ // responder, and if so, deliver focus window change to our window.
+ if (m_view.window.firstResponder != m_view)
return;
- if (isForeignWindow())
- return;
+ qCDebug(lcQpaWindow) << m_view.window << "became key window."
+ << "Updating focus window to" << this << "with view" << m_view;
- QNSView *firstResponderView = qt_objc_cast<QNSView *>(m_view.window.firstResponder);
- if (!firstResponderView)
- return;
-
- const QCocoaWindow *focusCocoaWindow = firstResponderView.platformWindow;
- if (focusCocoaWindow->windowIsPopupType())
+ if (windowIsPopupType()) {
+ qCDebug(lcQpaWindow) << "Window is popup. Skipping focus window change.";
return;
+ }
// See also [QNSView becomeFirstResponder]
- QWindowSystemInterface::handleWindowActivated<QWindowSystemInterface::SynchronousDelivery>(
- focusCocoaWindow->window(), Qt::ActiveWindowFocusReason);
+ QWindowSystemInterface::handleFocusWindowChanged<QWindowSystemInterface::SynchronousDelivery>(
+ window(), Qt::ActiveWindowFocusReason);
}
void QCocoaWindow::windowDidResignKey()
{
- if (!isContentView())
+ // The NSWindow we're part of lost key. Check if we're the first
+ // responder, and if so, deliver window deactivation to our window.
+ if (m_view.window.firstResponder != m_view)
return;
- if (isForeignWindow())
- return;
+ qCDebug(lcQpaWindow) << m_view.window << "resigned key window."
+ << "Clearing focus window" << this << "with view" << m_view;
// Make sure popups are closed before we deliver activation changes, which are
// otherwise ignored by QApplication.
@@ -1229,12 +1284,14 @@ void QCocoaWindow::windowDidResignKey()
NSWindow *newKeyWindow = [NSApp keyWindow];
if (newKeyWindow && newKeyWindow != m_view.window
&& [newKeyWindow conformsToProtocol:@protocol(QNSWindowProtocol)]) {
+ qCDebug(lcQpaWindow) << "New key window" << newKeyWindow
+ << "is Qt window. Deferring focus window change.";
return;
}
// Lost key window, go ahead and set the active window to zero
if (!windowIsPopupType()) {
- QWindowSystemInterface::handleWindowActivated<QWindowSystemInterface::SynchronousDelivery>(
+ QWindowSystemInterface::handleFocusWindowChanged<QWindowSystemInterface::SynchronousDelivery>(
nullptr, Qt::ActiveWindowFocusReason);
}
}
@@ -1271,8 +1328,14 @@ void QCocoaWindow::windowDidOrderOffScreen()
void QCocoaWindow::windowDidChangeOcclusionState()
{
+ // Note, we don't take the view's hiddenOrHasHiddenAncestor state into
+ // account here, but instead leave that up to handleExposeEvent, just
+ // like all the other signals that could potentially change the exposed
+ // state of the window.
bool visible = m_view.window.occlusionState & NSWindowOcclusionStateVisible;
- qCDebug(lcQpaWindow) << "QCocoaWindow::windowDidChangeOcclusionState" << window() << "is now" << (visible ? "visible" : "occluded");
+ qCDebug(lcQpaWindow) << "Occlusion state of" << m_view.window << "for"
+ << window() << "changed to" << (visible ? "visible" : "occluded");
+
if (visible)
[m_view setNeedsDisplay:YES];
else
@@ -1440,14 +1503,30 @@ void QCocoaWindow::recreateWindowIfNeeded()
QMacAutoReleasePool pool;
QPlatformWindow *parentWindow = QPlatformWindow::parent();
-
- const bool isEmbeddedView = isEmbedded();
- RecreationReasons recreateReason = RecreationNotNeeded;
+ auto *parentCocoaWindow = static_cast<QCocoaWindow *>(parentWindow);
QCocoaWindow *oldParentCocoaWindow = nullptr;
if (QNSView *qnsView = qnsview_cast(m_view.superview))
oldParentCocoaWindow = qnsView.platformWindow;
+ if (isForeignWindow()) {
+ // A foreign window is created as such, and can never move between being
+ // foreign and not, so we don't need to get rid of any existing NSWindows,
+ // nor create new ones, as a foreign window is a single simple NSView.
+ qCDebug(lcQpaWindow) << "Skipping NSWindow management for foreign window" << this;
+
+ // We do however need to manage the parent relationship
+ if (parentCocoaWindow)
+ [parentCocoaWindow->m_view addSubview:m_view];
+ else if (oldParentCocoaWindow)
+ [m_view removeFromSuperview];
+
+ return;
+ }
+
+ const bool isEmbeddedView = isEmbedded();
+ RecreationReasons recreateReason = RecreationNotNeeded;
+
if (parentWindow != oldParentCocoaWindow)
recreateReason |= ParentChanged;
@@ -1478,8 +1557,6 @@ void QCocoaWindow::recreateWindowIfNeeded()
if (recreateReason == RecreationNotNeeded)
return;
- QCocoaWindow *parentCocoaWindow = static_cast<QCocoaWindow *>(parentWindow);
-
// Remove current window (if any)
if ((isContentView() && !shouldBeContentView) || (recreateReason & PanelChanged)) {
if (m_nsWindow) {
@@ -1509,20 +1586,9 @@ void QCocoaWindow::recreateWindowIfNeeded()
}
}
- if (isEmbeddedView) {
- // An embedded window doesn't have its own NSWindow.
- } else if (!parentWindow) {
- // QPlatformWindow subclasses must sync up with QWindow on creation:
- propagateSizeHints();
- setWindowFlags(window()->flags());
- setWindowTitle(window()->title());
- setWindowFilePath(window()->filePath()); // Also sets window icon
- setWindowState(window()->windowState());
- setOpacity(window()->opacity());
- } else {
+ if (parentCocoaWindow) {
// Child windows have no NSWindow, re-parent to superview instead
[parentCocoaWindow->m_view addSubview:m_view];
- [m_view setHidden:!window()->isVisible()];
}
}
@@ -1532,7 +1598,10 @@ void QCocoaWindow::requestUpdate()
<< "using" << (updatesWithDisplayLink() ? "display-link" : "timer");
if (updatesWithDisplayLink()) {
- static_cast<QCocoaScreen *>(screen())->requestUpdate();
+ if (!static_cast<QCocoaScreen *>(screen())->requestUpdate()) {
+ qCDebug(lcQpaDrawing) << "Falling back to timer-based update request";
+ QPlatformWindow::requestUpdate();
+ }
} else {
// Fall back to the un-throttled timer-based callback
QPlatformWindow::requestUpdate();
@@ -1726,8 +1795,9 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel)
// Qt::Tool windows hide on app deactivation, unless Qt::WA_MacAlwaysShowToolWindow is set
nsWindow.hidesOnDeactivate = ((type & Qt::Tool) == Qt::Tool) && !alwaysShowToolWindow();
- // Make popup windows show on the same desktop as the parent full-screen window
- nsWindow.collectionBehavior = NSWindowCollectionBehaviorFullScreenAuxiliary;
+ // Make popup windows show on the same desktop as the parent window
+ nsWindow.collectionBehavior = NSWindowCollectionBehaviorFullScreenAuxiliary
+ | NSWindowCollectionBehaviorMoveToActiveSpace;
if ((type & Qt::Popup) == Qt::Popup) {
nsWindow.hasShadow = YES;
@@ -1742,11 +1812,15 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel)
applyContentBorderThickness(nsWindow);
- if (QColorSpace colorSpace = format().colorSpace(); colorSpace.isValid()) {
- NSData *iccData = colorSpace.iccProfile().toNSData();
- nsWindow.colorSpace = [[[NSColorSpace alloc] initWithICCProfileData:iccData] autorelease];
- qCDebug(lcQpaDrawing) << "Set" << this << "color space to" << nsWindow.colorSpace;
- }
+ // We propagate the view's color space granulary to both the IOSurfaces
+ // used for QSurface::RasterSurface, as well as the CAMetalLayer used for
+ // QSurface::MetalSurface, but for QSurface::OpenGLSurface we don't have
+ // that option as we use NSOpenGLContext instead of CAOpenGLLayer. As a
+ // workaround we set the NSWindow's color space, which affects GL drawing
+ // with NSOpenGLContext as well. This does not conflict with the granular
+ // modifications we do to each surface for raster or Metal.
+ if (auto *qtView = qnsview_cast(m_view))
+ nsWindow.colorSpace = qtView.colorSpace;
return nsWindow;
}
@@ -1789,26 +1863,28 @@ void QCocoaWindow::setWindowCursor(NSCursor *cursor)
view.cursor = cursor;
+ // We're not using the the legacy cursor rects API to manage our
+ // cursor, but calling this function also invalidates AppKit's
+ // view of whether or not we need a cursorUpdate callback for
+ // our tracking area.
[m_view.window invalidateCursorRectsForView:m_view];
- if (QOperatingSystemVersion::current() <= QOperatingSystemVersion::MacOSMonterey) {
- // There's a bug in AppKit where calling invalidateCursorRectsForView when
- // there's an override cursor active (for example when hovering over the
- // window frame), will not result in a cursorUpdate: callback. To work around
- // this we synthesize a cursor update event and call the callback ourselves.
- // We only do this is if the window would normally receive cursor updates.
- auto locationInWindow = m_view.window.mouseLocationOutsideOfEventStream;
- auto locationInSuperview = [m_view.superview convertPoint:locationInWindow fromView:nil];
- bool mouseIsOverView = [m_view hitTest:locationInSuperview] == m_view;
- auto utilityMask = NSWindowStyleMaskUtilityWindow | NSWindowStyleMaskTitled;
- bool isUtilityWindow = (m_view.window.styleMask & utilityMask) == utilityMask;
- if (mouseIsOverView && (m_view.window.keyWindow || isUtilityWindow)) {
- qCDebug(lcQpaMouse) << "Synthesizing cursor update";
- [m_view cursorUpdate:[NSEvent enterExitEventWithType:NSEventTypeCursorUpdate
- location:locationInWindow modifierFlags:0 timestamp:0
- windowNumber:m_view.window.windowNumber context:nil
- eventNumber:0 trackingNumber:0 userData:0]];
- }
+ // We've informed AppKit that we need a cursorUpdate, but cursor
+ // updates for tracking areas are deferred in some cases, such as
+ // when the mouse is down, whereas we want a synchronous update.
+ // To ensure an updated cursor we synthesize a cursor update event
+ // now if the window is otherwise allowed to change the cursor.
+ auto locationInWindow = m_view.window.mouseLocationOutsideOfEventStream;
+ auto locationInSuperview = [m_view.superview convertPoint:locationInWindow fromView:nil];
+ bool mouseIsOverView = [m_view hitTest:locationInSuperview] == m_view;
+ auto utilityMask = NSWindowStyleMaskUtilityWindow | NSWindowStyleMaskTitled;
+ bool isUtilityWindow = (m_view.window.styleMask & utilityMask) == utilityMask;
+ if (mouseIsOverView && (m_view.window.keyWindow || isUtilityWindow)) {
+ qCDebug(lcQpaMouse) << "Synthesizing cursor update";
+ [m_view cursorUpdate:[NSEvent enterExitEventWithType:NSEventTypeCursorUpdate
+ location:locationInWindow modifierFlags:0 timestamp:0
+ windowNumber:m_view.window.windowNumber context:nil
+ eventNumber:0 trackingNumber:0 userData:0]];
}
}
@@ -1913,7 +1989,7 @@ qreal QCocoaWindow::devicePixelRatio() const
{
// The documented way to observe the relationship between device-independent
// and device pixels is to use one for the convertToBacking functions. Other
- // methods such as [NSWindow backingScaleFacor] might not give the correct
+ // methods such as [NSWindow backingScaleFactor] might not give the correct
// result, for example if setWantsBestResolutionOpenGLSurface is not set or
// or ignored by the OpenGL driver.
NSSize backingSize = [m_view convertSizeToBacking:NSMakeSize(1.0, 1.0)];
@@ -1940,8 +2016,21 @@ bool QCocoaWindow::shouldRefuseKeyWindowAndFirstResponder()
if (window()->flags() & (Qt::WindowDoesNotAcceptFocus | Qt::WindowTransparentForInput))
return true;
- if (QWindowPrivate::get(window())->blockedByModalWindow)
- return true;
+ // For application modal windows, as well as direct parent windows
+ // of window modal windows, AppKit takes care of blocking interaction.
+ // The Qt expectation however, is that all transient parents of a
+ // window modal window is blocked, as reflected by QGuiApplication.
+ // We reflect this by returning false from this function for transient
+ // parents blocked by a modal window, but limit it to the cases not
+ // covered by AppKit to avoid potential unwanted side effects.
+ QWindow *modalWindow = nullptr;
+ if (QGuiApplicationPrivate::instance()->isWindowBlocked(window(), &modalWindow)) {
+ if (modalWindow->modality() == Qt::WindowModal && modalWindow->transientParent() != window()) {
+ qCDebug(lcQpaWindow) << "Refusing key window for" << this << "due to being"
+ << "blocked by" << modalWindow;
+ return true;
+ }
+ }
if (m_inSetVisible) {
QVariant showWithoutActivating = window()->property("_q_showWithoutActivating");
diff --git a/src/plugins/platforms/cocoa/qmacclipboard.h b/src/plugins/platforms/cocoa/qmacclipboard.h
index 75c112a10b..95267565f2 100644
--- a/src/plugins/platforms/cocoa/qmacclipboard.h
+++ b/src/plugins/platforms/cocoa/qmacclipboard.h
@@ -7,6 +7,8 @@
#include <QtGui>
#include <QtGui/qutimimeconverter.h>
+#include <QtCore/qpointer.h>
+
#include <ApplicationServices/ApplicationServices.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h
index e41f5a7296..7f845a5c3b 100644
--- a/src/plugins/platforms/cocoa/qnsview.h
+++ b/src/plugins/platforms/cocoa/qnsview.h
@@ -32,6 +32,12 @@ QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QNSView, NSView
- (void)cancelComposingText;
@end
+Q_FORWARD_DECLARE_OBJC_CLASS(NSColorSpace);
+
+@interface QNSView (DrawingAPI)
+@property (nonatomic, readonly) NSColorSpace *colorSpace;
+@end
+
@interface QNSView (QtExtras)
@property (nonatomic, readonly) QCocoaWindow *platformWindow;
@end
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index f8c17e179d..48ffa5c1cc 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -5,6 +5,7 @@
#include <AppKit/AppKit.h>
#include <MetalKit/MetalKit.h>
+#include <UniformTypeIdentifiers/UTCoreTypes.h>
#include "qnsview.h"
#include "qcocoawindow.h"
@@ -36,13 +37,6 @@
#include "qcocoaintegration.h"
#include <QtGui/private/qmacmimeregistry_p.h>
-// Private interface
-@interface QNSView ()
-- (BOOL)isTransparentForUserInput;
-@property (assign) NSView* previousSuperview;
-@property (assign) NSWindow* previousWindow;
-@end
-
@interface QNSView (Drawing) <CALayerDelegate>
- (void)initDrawing;
@end
@@ -86,6 +80,20 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMouseMoveHelper);
@property (readonly) QObject* focusObject;
@end
+@interface QT_MANGLE_NAMESPACE(QNSViewMenuHelper) : NSObject
+- (instancetype)initWithView:(QNSView *)theView;
+@end
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMenuHelper);
+
+// Private interface
+@interface QNSView ()
+- (BOOL)isTransparentForUserInput;
+@property (assign) NSView* previousSuperview;
+@property (assign) NSWindow* previousWindow;
+@property (retain) QNSViewMenuHelper* menuHelper;
+@property (nonatomic, retain) NSColorSpace *colorSpace;
+@end
+
@implementation QNSView {
QPointer<QCocoaWindow> m_platformWindow;
@@ -113,11 +121,20 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMouseMoveHelper);
NSDraggingContext m_lastSeenContext;
}
+@synthesize colorSpace = m_colorSpace;
+
- (instancetype)initWithCocoaWindow:(QCocoaWindow *)platformWindow
{
if ((self = [super initWithFrame:NSZeroRect])) {
m_platformWindow = platformWindow;
+ // NSViews are by default visible, but QWindows are not.
+ // We should ideally pick up the actual QWindow state here,
+ // but QWindowPrivate::setVisible() expects to control the
+ // order of events tightly, so we need to wait for a call
+ // to QCocoaWindow::setVisible().
+ self.hidden = YES;
+
self.focusRingType = NSFocusRingTypeNone;
self.previousSuperview = nil;
@@ -133,6 +150,8 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMouseMoveHelper);
m_sendKeyEvent = false;
m_currentlyInterpretedKeyEvent = nil;
m_lastSeenContext = NSDraggingContextWithinApplication;
+
+ self.menuHelper = [[[QNSViewMenuHelper alloc] initWithView:self] autorelease];
}
return self;
}
@@ -258,15 +277,29 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMouseMoveHelper);
return focusWindow;
}
+/*
+ Invoked when the view is hidden, either directly,
+ or in response to an ancestor being hidden.
+*/
- (void)viewDidHide
{
+ qCDebug(lcQpaWindow) << "Did hide" << self;
+
if (!m_platformWindow->isExposed())
return;
m_platformWindow->handleExposeEvent(QRegion());
+}
+
+/*
+ Invoked when the view is unhidden, either directly,
+ or in response to an ancestor being unhidden.
+*/
+- (void)viewDidUnhide
+{
+ qCDebug(lcQpaWindow) << "Did unhide" << self;
- // Note: setNeedsDisplay is automatically called for
- // viewDidUnhide so no reason to override it here.
+ [self setNeedsDisplay:YES];
}
- (BOOL)isTransparentForUserInput
@@ -299,7 +332,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSViewMouseMoveHelper);
// QWindow activation from QCocoaWindow::windowDidBecomeKey instead. The only
// exception is if the window can never become key, in which case we naturally
// cannot wait for that to happen.
- QWindowSystemInterface::handleWindowActivated<QWindowSystemInterface::SynchronousDelivery>(
+ QWindowSystemInterface::handleFocusWindowChanged<QWindowSystemInterface::SynchronousDelivery>(
[self topLevelWindow], Qt::ActiveWindowFocusReason);
}
diff --git a/src/plugins/platforms/cocoa/qnsview_accessibility.mm b/src/plugins/platforms/cocoa/qnsview_accessibility.mm
index 3f3898fd18..e781f21a6c 100644
--- a/src/plugins/platforms/cocoa/qnsview_accessibility.mm
+++ b/src/plugins/platforms/cocoa/qnsview_accessibility.mm
@@ -13,6 +13,15 @@
@implementation QNSView (Accessibility)
+- (void)activateQtAccessibility
+{
+ // Activate the Qt accessibility machinery for all entry points
+ // below that may be triggered by system accessibility queries,
+ // as otherwise Qt is not aware that the system needs to know
+ // about all accessibility state changes in Qt.
+ QCocoaIntegration::instance()->accessibility()->setActive(true);
+}
+
- (id)childAccessibleElement
{
QCocoaWindow *platformWindow = self.platformWindow;
@@ -32,8 +41,7 @@
- (id)accessibilityAttributeValue:(NSString *)attribute
{
- // activate accessibility updates
- QCocoaIntegration::instance()->accessibility()->setActive(true);
+ [self activateQtAccessibility];
if ([attribute isEqualToString:NSAccessibilityChildrenAttribute])
return NSAccessibilityUnignoredChildrenForOnlyChild([self childAccessibleElement]);
@@ -43,11 +51,13 @@
- (id)accessibilityHitTest:(NSPoint)point
{
+ [self activateQtAccessibility];
return [[self childAccessibleElement] accessibilityHitTest:point];
}
- (id)accessibilityFocusedUIElement
{
+ [self activateQtAccessibility];
return [[self childAccessibleElement] accessibilityFocusedUIElement];
}
diff --git a/src/plugins/platforms/cocoa/qnsview_complextext.mm b/src/plugins/platforms/cocoa/qnsview_complextext.mm
index 3ccaf8269e..d7f8f4baf0 100644
--- a/src/plugins/platforms/cocoa/qnsview_complextext.mm
+++ b/src/plugins/platforms/cocoa/qnsview_complextext.mm
@@ -130,8 +130,8 @@
newlineEvent.key = isEnter ? Qt::Key_Enter : Qt::Key_Return;
newlineEvent.text = isEnter ? QLatin1Char(kEnterCharCode)
: QLatin1Char(kReturnCharCode);
- newlineEvent.nativeVirtualKey = isEnter ? kVK_ANSI_KeypadEnter
- : kVK_Return;
+ newlineEvent.nativeVirtualKey = isEnter ? quint32(kVK_ANSI_KeypadEnter)
+ : quint32(kVK_Return);
qCDebug(lcQpaKeys) << "Inserting newline via" << newlineEvent;
newlineEvent.sendWindowSystemEvent(m_platformWindow->window());
@@ -505,6 +505,32 @@
return NSNotFound;
}
+/*
+ Returns the window level of the text input.
+
+ This allows the input method to place its input panel
+ above the text input.
+*/
+- (NSInteger)windowLevel
+{
+ // The default level assumed by input methods is NSFloatingWindowLevel,
+ // but our NSWindow level could be higher than that for many reasons,
+ // including being set via QWindow::setFlags() or directly on the
+ // NSWindow, or because we're embedded into a native view hierarchy.
+ // Return the actual window level to account for this.
+ auto level = m_platformWindow ? m_platformWindow->nativeWindow().level
+ : NSNormalWindowLevel;
+
+ // The logic above only covers our own window though. In some cases,
+ // such as when a completer is active, the text input has a lower
+ // window level than another window that's also visible, and we don't
+ // want the input panel to be sandwiched between these two windows.
+ // Account for this by explicitly using NSPopUpMenuWindowLevel as
+ // the minimum window level, which corresponds to the highest level
+ // one can get via QWindow::setFlags(), except for Qt::ToolTip.
+ return qMax(level, NSPopUpMenuWindowLevel);
+}
+
// ------------- Helper functions -------------
/*
diff --git a/src/plugins/platforms/cocoa/qnsview_dragging.mm b/src/plugins/platforms/cocoa/qnsview_dragging.mm
index f5bb25c300..4f7d35a0d6 100644
--- a/src/plugins/platforms/cocoa/qnsview_dragging.mm
+++ b/src/plugins/platforms/cocoa/qnsview_dragging.mm
@@ -16,8 +16,8 @@
NSPasteboardTypeRTF, NSPasteboardTypeTabularText, NSPasteboardTypeFont,
NSPasteboardTypeRuler, NSFileContentsPboardType,
NSPasteboardTypeRTFD , NSPasteboardTypeHTML,
- NSPasteboardTypeURL, NSPasteboardTypePDF, (NSString *)kUTTypeVCard,
- (NSString *)kPasteboardTypeFileURLPromise, (NSString *)kUTTypeInkText,
+ NSPasteboardTypeURL, NSPasteboardTypePDF, UTTypeVCard.identifier,
+ (NSString *)kPasteboardTypeFileURLPromise,
NSPasteboardTypeMultipleTextSelection, mimeTypeGeneric]];
// Add custom types supported by the application
diff --git a/src/plugins/platforms/cocoa/qnsview_drawing.mm b/src/plugins/platforms/cocoa/qnsview_drawing.mm
index 472a5291e7..bf102e43f8 100644
--- a/src/plugins/platforms/cocoa/qnsview_drawing.mm
+++ b/src/plugins/platforms/cocoa/qnsview_drawing.mm
@@ -13,6 +13,14 @@
<< " QT_MAC_WANTS_LAYER/_q_mac_wantsLayer has no effect.";
}
+ // Pick up and persist requested color space from surface format
+ const QSurfaceFormat surfaceFormat = m_platformWindow->format();
+ if (QColorSpace colorSpace = surfaceFormat.colorSpace(); colorSpace.isValid()) {
+ NSData *iccData = colorSpace.iccProfile().toNSData();
+ self.colorSpace = [[[NSColorSpace alloc] initWithICCProfileData:iccData] autorelease];
+ }
+
+ // Trigger creation of the layer
self.wantsLayer = YES;
}
@@ -28,6 +36,12 @@
return YES;
}
+- (NSColorSpace*)colorSpace
+{
+ // If no explicit color space was set, use the NSWindow's color space
+ return m_colorSpace ? m_colorSpace : self.window.colorSpace;
+}
+
// ----------------------- Layer setup -----------------------
- (BOOL)shouldUseMetalLayer
@@ -93,12 +107,7 @@
[super setLayer:layer];
- // When adding a view to a view hierarchy the backing properties will change
- // which results in updating the contents scale, but in case of switching the
- // layer on a view that's already in a view hierarchy we need to manually ensure
- // the scale is up to date.
- if (self.superview)
- [self updateLayerContentsScale];
+ [self propagateBackingProperties];
if (self.opaque && lcQpaDrawing().isDebugEnabled()) {
// If the view claims to be opaque we expect it to fill the entire
@@ -131,8 +140,7 @@
{
qCDebug(lcQpaDrawing) << "Backing properties changed for" << self;
- if (self.layer)
- [self updateLayerContentsScale];
+ [self propagateBackingProperties];
// Ideally we would plumb this situation through QPA in a way that lets
// clients invalidate their own caches, recreate QBackingStore, etc.
@@ -141,8 +149,11 @@
[self setNeedsDisplay:YES];
}
-- (void)updateLayerContentsScale
+- (void)propagateBackingProperties
{
+ if (!self.layer)
+ return;
+
// We expect clients to fill the layer with retina aware content,
// based on the devicePixelRatio of the QWindow, so we set the
// layer's content scale to match that. By going via devicePixelRatio
@@ -153,6 +164,12 @@
auto devicePixelRatio = m_platformWindow->devicePixelRatio();
qCDebug(lcQpaDrawing) << "Updating" << self.layer << "content scale to" << devicePixelRatio;
self.layer.contentsScale = devicePixelRatio;
+
+ if ([self.layer isKindOfClass:CAMetalLayer.class]) {
+ CAMetalLayer *metalLayer = static_cast<CAMetalLayer *>(self.layer);
+ metalLayer.colorspace = self.colorSpace.CGColorSpace;
+ qCDebug(lcQpaDrawing) << "Set" << metalLayer << "color space to" << metalLayer.colorspace;
+ }
}
/*
@@ -178,8 +195,10 @@
- (void)drawRect:(NSRect)dirtyBoundingRect
{
Q_UNUSED(dirtyBoundingRect);
- Q_ASSERT_X(!self.layer, "QNSView",
- "The drawRect code path should not be hit when we are layer backed");
+ // As we are layer backed we shouldn't really end up here, but AppKit will
+ // in some cases call this method just because we implement it.
+ // FIXME: Remove drawRect and switch from displayLayer to updateLayer
+ qCWarning(lcQpaDrawing) << "[QNSView drawRect] called for layer backed view";
}
/*
diff --git a/src/plugins/platforms/cocoa/qnsview_keys.mm b/src/plugins/platforms/cocoa/qnsview_keys.mm
index 118678ffa5..abee622e65 100644
--- a/src/plugins/platforms/cocoa/qnsview_keys.mm
+++ b/src/plugins/platforms/cocoa/qnsview_keys.mm
@@ -30,8 +30,36 @@ static bool isSpecialKey(const QString &text)
return false;
}
+static bool sendAsShortcut(const KeyEvent &keyEvent, QWindow *window)
+{
+ KeyEvent shortcutEvent = keyEvent;
+ shortcutEvent.type = QEvent::Shortcut;
+ qCDebug(lcQpaKeys) << "Trying potential shortcuts in" << window
+ << "for" << shortcutEvent;
+
+ if (shortcutEvent.sendWindowSystemEvent(window)) {
+ qCDebug(lcQpaKeys) << "Found matching shortcut; will not send as key event";
+ return true;
+ }
+ qCDebug(lcQpaKeys) << "No matching shortcuts; continuing with key event delivery";
+ return false;
+}
+
@implementation QNSView (Keys)
+- (bool)performKeyEquivalent:(NSEvent *)nsevent
+{
+ // Implemented to handle shortcuts for modified Tab keys, which are
+ // handled by Cocoa and not delivered to your keyDown implementation.
+ if (nsevent.type == NSEventTypeKeyDown && m_composingText.isEmpty()) {
+ const bool ctrlDown = [nsevent modifierFlags] & NSEventModifierFlagControl;
+ const bool isTabKey = nsevent.keyCode == kVK_Tab;
+ if (ctrlDown && isTabKey && sendAsShortcut(KeyEvent(nsevent), [self topLevelWindow]))
+ return YES;
+ }
+ return NO;
+}
+
- (bool)handleKeyEvent:(NSEvent *)nsevent
{
qCDebug(lcQpaKeys) << "Handling" << nsevent;
@@ -52,17 +80,8 @@ static bool isSpecialKey(const QString &text)
if (keyEvent.type == QEvent::KeyPress) {
if (m_composingText.isEmpty()) {
- KeyEvent shortcutEvent = keyEvent;
- shortcutEvent.type = QEvent::Shortcut;
- qCDebug(lcQpaKeys) << "Trying potential shortcuts in" << window
- << "for" << shortcutEvent;
-
- if (shortcutEvent.sendWindowSystemEvent(window)) {
- qCDebug(lcQpaKeys) << "Found matching shortcut; will not send as key event";
+ if (sendAsShortcut(keyEvent, window))
return true;
- } else {
- qCDebug(lcQpaKeys) << "No matching shortcuts; continuing with key event delivery";
- }
}
QObject *focusObject = m_platformWindow ? m_platformWindow->window()->focusObject() : nullptr;
@@ -94,7 +113,10 @@ static bool isSpecialKey(const QString &text)
qCDebug(lcQpaKeys) << "Interpreting key event for focus object" << focusObject;
m_currentlyInterpretedKeyEvent = nsevent;
- [self interpretKeyEvents:@[nsevent]];
+ if (![self.inputContext handleEvent:nsevent]) {
+ qCDebug(lcQpaKeys) << "Input context did not consume event";
+ m_sendKeyEvent = true;
+ }
m_currentlyInterpretedKeyEvent = 0;
didInterpretKeyEvent = true;
diff --git a/src/plugins/platforms/cocoa/qnsview_menus.mm b/src/plugins/platforms/cocoa/qnsview_menus.mm
index 644f2139de..2840936975 100644
--- a/src/plugins/platforms/cocoa/qnsview_menus.mm
+++ b/src/plugins/platforms/cocoa/qnsview_menus.mm
@@ -9,23 +9,55 @@
#include "qcocoamenu.h"
#include "qcocoamenubar.h"
-static bool selectorIsCutCopyPaste(SEL selector)
+@implementation QNSView (Menus)
+
+// Qt does not (yet) have a mechanism for propagating generic actions,
+// so we can only support actions that originate from a QCocoaNSMenuItem,
+// where we can forward the action by emitting QPlatformMenuItem::activated().
+// But waiting for forwardInvocation to check that the sender is a
+// QCocoaNSMenuItem is too late, as AppKit has at that point chosen
+// our view as the target for the action, and if we can't handle it
+// the action will not propagate up the responder chain as it should.
+// Instead, we hook in early in the process of determining the target
+// via the supplementalTargetForAction API, and if we can support the
+// action we forward it to a helper. The helper must be tied to the
+// view, as the menu validation logic depends on the view's state.
+
+- (id)supplementalTargetForAction:(SEL)action sender:(id)sender
{
- return (selector == @selector(cut:)
- || selector == @selector(copy:)
- || selector == @selector(paste:)
- || selector == @selector(selectAll:));
+ qCDebug(lcQpaMenus) << "Resolving action target for" << action << "from" << sender << "via" << self;
+
+ if (qt_objc_cast<QCocoaNSMenuItem *>(sender)) {
+ // The supplemental target must support the selector, but we
+ // determine so dynamically, so check here before continuing.
+ if ([self.menuHelper respondsToSelector:action])
+ return self.menuHelper;
+ } else {
+ qCDebug(lcQpaMenus) << "Ignoring action for menu item we didn't create";
+ }
+
+ return [super supplementalTargetForAction:action sender:sender];
}
-@interface QNSView (Menus)
-- (void)qt_itemFired:(QCocoaNSMenuItem *)item;
@end
-@implementation QNSView (Menus)
+@interface QNSViewMenuHelper ()
+@property (assign) QNSView* view;
+@end
+
+@implementation QNSViewMenuHelper
+
+- (instancetype)initWithView:(QNSView *)theView
+{
+ if ((self = [super init]))
+ self.view = theView;
+
+ return self;
+}
- (BOOL)validateMenuItem:(NSMenuItem*)item
{
- qCDebug(lcQpaMenus) << "Validating" << item << "for" << self;
+ qCDebug(lcQpaMenus) << "Validating" << item << "for" << self.view;
auto *nativeItem = qt_objc_cast<QCocoaNSMenuItem *>(item);
if (!nativeItem)
@@ -53,7 +85,7 @@ static bool selectorIsCutCopyPaste(SEL selector)
}
if ((!menuWindow || menuWindow->window() != QGuiApplication::modalWindow())
- && (!menubar || menubar->cocoaWindow() != self.platformWindow))
+ && (!menubar || menubar->cocoaWindow() != self.view.platformWindow))
return NO;
}
@@ -62,54 +94,42 @@ static bool selectorIsCutCopyPaste(SEL selector)
- (BOOL)respondsToSelector:(SEL)selector
{
- // Not exactly true. Both copy: and selectAll: can work on non key views.
- if (selectorIsCutCopyPaste(selector))
- return ([NSApp keyWindow] == self.window) && (self.window.firstResponder == self);
+ // See QCocoaMenuItem::resolveTargetAction()
+
+ if (selector == @selector(cut:)
+ || selector == @selector(copy:)
+ || selector == @selector(paste:)
+ || selector == @selector(selectAll:)) {
+ // Not exactly true. Both copy: and selectAll: can work on non key views.
+ return NSApp.keyWindow == self.view.window
+ && self.view.window.firstResponder == self.view;
+ }
- return [super respondsToSelector:selector];
-}
+ if (selector == @selector(qt_itemFired:))
+ return YES;
-- (void)qt_itemFired:(QCocoaNSMenuItem *)item
-{
- auto *appDelegate = [QCocoaApplicationDelegate sharedDelegate];
- [appDelegate qt_itemFired:item];
+ return [super respondsToSelector:selector];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector
{
- if (selectorIsCutCopyPaste(selector)) {
- NSMethodSignature *itemFiredSign = [super methodSignatureForSelector:@selector(qt_itemFired:)];
- return itemFiredSign;
- }
+ // Double check, in case something has cached that we respond
+ // to the selector, but the result has changed since then.
+ if (![self respondsToSelector:selector])
+ return nil;
- return [super methodSignatureForSelector:selector];
+ auto *appDelegate = [QCocoaApplicationDelegate sharedDelegate];
+ return [appDelegate methodSignatureForSelector:@selector(qt_itemFired:)];
}
- (void)forwardInvocation:(NSInvocation *)invocation
{
- if (selectorIsCutCopyPaste(invocation.selector)) {
- NSObject *sender;
- [invocation getArgument:&sender atIndex:2];
- qCDebug(lcQpaMenus) << "Forwarding" << invocation.selector << "from" << sender;
-
- // We claim to respond to standard edit actions such as cut/copy/paste,
- // but these might not be exclusively coming from menu items that we
- // control. For example, when embedded into a native UI (as a plugin),
- // the menu items might be part of the host application, and if we're
- // the first responder, we'll be the target of these actions. As we
- // don't have a mechanism in Qt to trigger generic actions, we have
- // to bail out if we don't have a QCocoaNSMenuItem we can activate().
- // Note that we skip the call to super as well, as that would just
- // try to invoke the current action on ourselves again.
- if (auto *nativeItem = qt_objc_cast<QCocoaNSMenuItem *>(sender))
- [self qt_itemFired:nativeItem];
- else
- qCDebug(lcQpaMenus) << "Ignoring action for menu item we didn't create";
-
- return;
- }
-
- [super forwardInvocation:invocation];
+ NSObject *sender;
+ [invocation getArgument:&sender atIndex:2];
+ qCDebug(lcQpaMenus) << "Forwarding" << invocation.selector << "from" << sender;
+ Q_ASSERT(qt_objc_cast<QCocoaNSMenuItem *>(sender));
+ invocation.selector = @selector(qt_itemFired:);
+ [invocation invokeWithTarget:[QCocoaApplicationDelegate sharedDelegate]];
}
@end
diff --git a/src/plugins/platforms/cocoa/qnsview_mouse.mm b/src/plugins/platforms/cocoa/qnsview_mouse.mm
index 89125ca91f..2fd57fe68e 100644
--- a/src/plugins/platforms/cocoa/qnsview_mouse.mm
+++ b/src/plugins/platforms/cocoa/qnsview_mouse.mm
@@ -209,20 +209,19 @@ static const QPointingDevice *pointingDeviceFor(qint64 deviceID)
case NSEventTypeOtherMouseUp:
return QEvent::NonClientAreaMouseButtonRelease;
+ case NSEventTypeMouseMoved:
case NSEventTypeLeftMouseDragged:
case NSEventTypeRightMouseDragged:
case NSEventTypeOtherMouseDragged:
return QEvent::NonClientAreaMouseMove;
default:
- break;
+ Q_UNREACHABLE();
}
-
- return QEvent::None;
}();
qCInfo(lcQpaMouse) << eventType << "at" << qtWindowPoint << "with" << m_frameStrutButtons << "in" << self.window;
- QWindowSystemInterface::handleFrameStrutMouseEvent(m_platformWindow->window(),
+ QWindowSystemInterface::handleMouseEvent(m_platformWindow->window(),
timestamp, qtWindowPoint, qtScreenPoint, m_frameStrutButtons, button, eventType);
}
@end
@@ -484,10 +483,6 @@ static const QPointingDevice *pointingDeviceFor(qint64 deviceID)
- (void)cursorUpdate:(NSEvent *)theEvent
{
- // Note: We do not get this callback when moving from a subview that
- // uses the legacy cursorRect API, so the cursor is reset to the arrow
- // cursor. See rdar://34183708
-
if (!NSApp.active)
return;
@@ -548,6 +543,30 @@ static const QPointingDevice *pointingDeviceFor(qint64 deviceID)
[self handleMouseEvent: theEvent];
}
+- (BOOL)shouldPropagateMouseEnterExit
+{
+ Q_ASSERT(m_platformWindow);
+
+ // We send out enter and leave events mainly from mouse move events (mouseMovedImpl),
+ // but in some case (see mouseEnteredImpl:) we also want to propagate enter/leave
+ // events from the platform. We only do this for windows that themselves are not
+ // handled by another parent QWindow.
+
+ if (m_platformWindow->isContentView())
+ return true;
+
+ // Windows manually embedded into a native view does not have a QWindow parent
+ if (m_platformWindow->isEmbedded())
+ return true;
+
+ // Windows embedded via fromWinId do, but the parent isn't a QNSView
+ QPlatformWindow *parentWindow = m_platformWindow->QPlatformWindow::parent();
+ if (parentWindow && parentWindow->isForeignWindow())
+ return true;
+
+ return false;
+}
+
- (void)mouseEnteredImpl:(NSEvent *)theEvent
{
Q_UNUSED(theEvent);
@@ -571,8 +590,7 @@ static const QPointingDevice *pointingDeviceFor(qint64 deviceID)
// in time (s_windowUnderMouse). The latter is also used to also send out enter/leave
// events when the application is activated/deactivated.
- // Root (top level or embedded) windows generate enter events for sub-windows
- if (!m_platformWindow->isContentView() && !m_platformWindow->isEmbedded())
+ if (![self shouldPropagateMouseEnterExit])
return;
QPointF windowPoint;
@@ -598,8 +616,7 @@ static const QPointingDevice *pointingDeviceFor(qint64 deviceID)
if (!m_platformWindow)
return;
- // Root (top level or embedded) windows generate enter events for sub-windows
- if (!m_platformWindow->isContentView() && !m_platformWindow->isEmbedded())
+ if (![self shouldPropagateMouseEnterExit])
return;
QCocoaWindow *windowToLeave = QCocoaWindow::s_windowUnderMouse;
diff --git a/src/plugins/platforms/cocoa/qnsview_touch.mm b/src/plugins/platforms/cocoa/qnsview_touch.mm
index 6a147701fc..97ed5b7624 100644
--- a/src/plugins/platforms/cocoa/qnsview_touch.mm
+++ b/src/plugins/platforms/cocoa/qnsview_touch.mm
@@ -25,7 +25,10 @@ Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch")
const NSTimeInterval timestamp = [event timestamp];
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
qCDebug(lcQpaTouch) << "touchesBeganWithEvent" << points << "from device" << Qt::hex << [event deviceID];
- QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]), points);
+ QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(
+ m_platformWindow->window(), timestamp * 1000,
+ QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]),
+ points);
}
- (void)touchesMovedWithEvent:(NSEvent *)event
@@ -36,7 +39,10 @@ Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch")
const NSTimeInterval timestamp = [event timestamp];
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
qCDebug(lcQpaTouch) << "touchesMovedWithEvent" << points << "from device" << Qt::hex << [event deviceID];
- QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]), points);
+ QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(
+ m_platformWindow->window(), timestamp * 1000,
+ QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]),
+ points);
}
- (void)touchesEndedWithEvent:(NSEvent *)event
@@ -47,7 +53,10 @@ Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch")
const NSTimeInterval timestamp = [event timestamp];
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
qCDebug(lcQpaTouch) << "touchesEndedWithEvent" << points << "from device" << Qt::hex << [event deviceID];
- QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]), points);
+ QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(
+ m_platformWindow->window(), timestamp * 1000,
+ QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]),
+ points);
}
- (void)touchesCancelledWithEvent:(NSEvent *)event
@@ -58,7 +67,10 @@ Q_LOGGING_CATEGORY(lcQpaTouch, "qt.qpa.input.touch")
const NSTimeInterval timestamp = [event timestamp];
const QList<QWindowSystemInterface::TouchPoint> points = QCocoaTouch::getCurrentTouchPointList(event, [self shouldSendSingleTouch]);
qCDebug(lcQpaTouch) << "touchesCancelledWithEvent" << points << "from device" << Qt::hex << [event deviceID];
- QWindowSystemInterface::handleTouchEvent(m_platformWindow->window(), timestamp * 1000, QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]), points);
+ QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(
+ m_platformWindow->window(), timestamp * 1000,
+ QCocoaTouch::getTouchDevice(QInputDevice::DeviceType::TouchPad, [event deviceID]),
+ points);
}
@end
diff --git a/src/plugins/platforms/cocoa/qnswindow.h b/src/plugins/platforms/cocoa/qnswindow.h
index f69e809133..8f842eba85 100644
--- a/src/plugins/platforms/cocoa/qnswindow.h
+++ b/src/plugins/platforms/cocoa/qnswindow.h
@@ -36,6 +36,8 @@ QT_FORWARD_DECLARE_CLASS(QCocoaWindow)
typedef NSWindow<QNSWindowProtocol> QCocoaNSWindow;
+QCocoaNSWindow *qnswindow_cast(NSWindow *window);
+
#else
class QCocoaNSWindow;
#endif // __OBJC__
diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm
index d7418b8abf..74ba6f65ac 100644
--- a/src/plugins/platforms/cocoa/qnswindow.mm
+++ b/src/plugins/platforms/cocoa/qnswindow.mm
@@ -58,6 +58,15 @@ static bool isMouseEvent(NSEvent *ev)
}
@end
+
+NSWindow<QNSWindowProtocol> *qnswindow_cast(NSWindow *window)
+{
+ if ([window conformsToProtocol:@protocol(QNSWindowProtocol)])
+ return static_cast<QCocoaNSWindow *>(window);
+ else
+ return nil;
+}
+
@implementation QNSWindow
#define QNSWINDOW_PROTOCOL_IMPLMENTATION 1
#include "qnswindow.mm"
@@ -98,9 +107,10 @@ static bool isMouseEvent(NSEvent *ev)
continue;
if ([window conformsToProtocol:@protocol(QNSWindowProtocol)]) {
- QCocoaWindow *cocoaWindow = static_cast<QCocoaNSWindow *>(window).platformWindow;
- window.level = notification.name == NSApplicationWillResignActiveNotification ?
- NSNormalWindowLevel : cocoaWindow->windowLevel(cocoaWindow->window()->flags());
+ if (QCocoaWindow *cocoaWindow = static_cast<QCocoaNSWindow *>(window).platformWindow) {
+ window.level = notification.name == NSApplicationWillResignActiveNotification ?
+ NSNormalWindowLevel : cocoaWindow->windowLevel(cocoaWindow->window()->flags());
+ }
}
// The documentation says that "when a window enters a new level, it’s ordered
@@ -196,6 +206,29 @@ static bool isMouseEvent(NSEvent *ev)
return m_platformWindow;
}
+- (void)setContentView:(NSView*)view
+{
+ [super setContentView:view];
+
+ if (!qnsview_cast(self.contentView))
+ return;
+
+ // Now that we're the content view, we can apply the properties of
+ // the QWindow. We do this here, instead of in init, so that we can
+ // use the same code paths for setting these properties during
+ // NSWindow initialization as we do when setting them later on.
+ const QWindow *window = m_platformWindow->window();
+ qCDebug(lcQpaWindow) << "Reflecting" << window << "state to" << self;
+
+ m_platformWindow->propagateSizeHints();
+ m_platformWindow->setWindowFlags(window->flags());
+ m_platformWindow->setWindowTitle(window->title());
+ m_platformWindow->setWindowFilePath(window->filePath()); // Also sets window icon
+ m_platformWindow->setWindowState(window->windowState());
+ m_platformWindow->setOpacity(window->opacity());
+ m_platformWindow->setVisible(window->isVisible());
+}
+
- (NSString *)description
{
NSMutableString *description = [NSMutableString stringWithString:[super description]];
diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm
index 2d90fbf544..1db7772771 100644
--- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm
+++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm
@@ -23,9 +23,7 @@ static inline bool isWhiteSpace(const QString &s)
static QCocoaWindow *toPlatformWindow(NSWindow *window)
{
- if ([window conformsToProtocol:@protocol(QNSWindowProtocol)])
- return static_cast<QCocoaNSWindow *>(window).platformWindow;
- return nullptr;
+ return qnswindow_cast(window).platformWindow;
}
@implementation QNSWindowDelegate
diff --git a/src/plugins/platforms/direct2d/CMakeLists.txt b/src/plugins/platforms/direct2d/CMakeLists.txt
index 4cbc7ac986..54e96b09e5 100644
--- a/src/plugins/platforms/direct2d/CMakeLists.txt
+++ b/src/plugins/platforms/direct2d/CMakeLists.txt
@@ -12,11 +12,11 @@ qt_internal_add_plugin(QWindowsDirect2DIntegrationPlugin
../windows/qtwindowsglobal.h
../windows/qwin10helpers.cpp ../windows/qwin10helpers.h
../windows/qwindowsapplication.cpp ../windows/qwindowsapplication.h
- ../windows/qwindowscombase.h
../windows/qwindowscontext.cpp ../windows/qwindowscontext.h
../windows/qwindowscursor.cpp ../windows/qwindowscursor.h
../windows/qwindowsdialoghelpers.cpp ../windows/qwindowsdialoghelpers.h
../windows/qwindowsdropdataobject.cpp ../windows/qwindowsdropdataobject.h
+ ../windows/qwindowsiconengine.cpp ../windows/qwindowsiconengine.h
../windows/qwindowsinputcontext.cpp ../windows/qwindowsinputcontext.h
../windows/qwindowsintegration.cpp ../windows/qwindowsintegration.h
../windows/qwindowsinternalmimedata.cpp ../windows/qwindowsinternalmimedata.h
@@ -47,7 +47,6 @@ qt_internal_add_plugin(QWindowsDirect2DIntegrationPlugin
qwindowsdirect2dwindow.cpp qwindowsdirect2dwindow.h
NO_UNITY_BUILD_SOURCES
../windows/qwindowspointerhandler.cpp
- ../windows/qwindowsmousehandler.cpp
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_FOREACH
@@ -69,6 +68,7 @@ qt_internal_add_plugin(QWindowsDirect2DIntegrationPlugin
imm32
ole32
oleaut32
+ setupapi
shell32
shlwapi
user32
@@ -108,6 +108,8 @@ qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin CONDITION QT_FEATURE
qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin CONDITION MINGW
LIBRARIES
uuid
+ NO_PCH_SOURCES
+ ../windows/qwindowspointerhandler.cpp
)
qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin CONDITION QT_FEATURE_opengl
@@ -186,6 +188,7 @@ endif()
qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin CONDITION QT_FEATURE_accessibility
SOURCES
+ ../windows/uiautomation/qwindowsuiautomation.cpp ../windows/uiautomation/qwindowsuiautomation.h
../windows/uiautomation/qwindowsuiaaccessibility.cpp ../windows/uiautomation/qwindowsuiaaccessibility.h
../windows/uiautomation/qwindowsuiabaseprovider.cpp ../windows/uiautomation/qwindowsuiabaseprovider.h
../windows/uiautomation/qwindowsuiaexpandcollapseprovider.cpp ../windows/uiautomation/qwindowsuiaexpandcollapseprovider.h
@@ -207,11 +210,18 @@ qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin CONDITION QT_FEATURE
../windows/uiautomation/qwindowsuiawindowprovider.cpp ../windows/uiautomation/qwindowsuiawindowprovider.h
)
+if(QT_FEATURE_accessibility)
+ find_library(UI_AUTOMATION_LIBRARY uiautomationcore)
+ if(UI_AUTOMATION_LIBRARY)
+ qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin
+ LIBRARIES
+ ${UI_AUTOMATION_LIBRARY}
+ )
+ endif()
+endif()
+
qt_internal_extend_target(QWindowsDirect2DIntegrationPlugin CONDITION MINGW AND QT_FEATURE_accessibility
LIBRARIES
uuid
)
-if (MINGW)
- set_source_files_properties(../windows/qwindowspointerhandler.cpp PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
-endif()
diff --git a/src/plugins/platforms/directfb/qdirectfbblitter.cpp b/src/plugins/platforms/directfb/qdirectfbblitter.cpp
index aac0e3d800..c93e48ead7 100644
--- a/src/plugins/platforms/directfb/qdirectfbblitter.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbblitter.cpp
@@ -424,7 +424,7 @@ void QDirectFbBlitter::drawDebugRect(const QRect &rect, const QColor &color)
void QDirectFbTextureGlyphCache::resizeTextureData(int width, int height)
{
- m_surface.reset();;
+ m_surface.reset();
QImageTextureGlyphCache::resizeTextureData(width, height);
}
diff --git a/src/plugins/platforms/directfb/qdirectfbconvenience.h b/src/plugins/platforms/directfb/qdirectfbconvenience.h
index c013988fe2..dc657f384e 100644
--- a/src/plugins/platforms/directfb/qdirectfbconvenience.h
+++ b/src/plugins/platforms/directfb/qdirectfbconvenience.h
@@ -62,7 +62,7 @@ template <typename T>
class QDirectFBPointer : public QScopedPointer<T, QDirectFBInterfaceCleanupHandler<T> >
{
public:
- QDirectFBPointer(T *t = nullptr)
+ Q_NODISCARD_CTOR QDirectFBPointer(T *t = nullptr)
: QScopedPointer<T, QDirectFBInterfaceCleanupHandler<T> >(t)
{}
diff --git a/src/plugins/platforms/directfb/qdirectfbinput.cpp b/src/plugins/platforms/directfb/qdirectfbinput.cpp
index 516dc1e9d8..c5aacad6cc 100644
--- a/src/plugins/platforms/directfb/qdirectfbinput.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbinput.cpp
@@ -176,7 +176,7 @@ void QDirectFbInput::handleEnterLeaveEvents(const DFBEvent &event)
void QDirectFbInput::handleGotFocusEvent(const DFBEvent &event)
{
QWindow *tlw = m_tlwMap.value(event.window.window_id);
- QWindowSystemInterface::handleWindowActivated(tlw, Qt::ActiveWindowFocusReason);
+ QWindowSystemInterface::handleFocusWindowChanged(tlw, Qt::ActiveWindowFocusReason);
}
void QDirectFbInput::handleCloseEvent(const DFBEvent &event)
diff --git a/src/plugins/platforms/eglfs/CMakeLists.txt b/src/plugins/platforms/eglfs/CMakeLists.txt
index cebb0fe66e..a0a6116a45 100644
--- a/src/plugins/platforms/eglfs/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/CMakeLists.txt
@@ -34,6 +34,7 @@ qt_internal_add_module(EglFSDeviceIntegrationPrivate
DEFINES
QT_BUILD_EGL_DEVICE_LIB
QT_EGL_NO_X11
+ QT_NO_FOREACH
EGLFS_PREFERRED_PLUGIN=${QT_QPA_DEFAULT_EGLFS_INTEGRATION}
INCLUDE_DIRECTORIES
api
@@ -45,6 +46,7 @@ qt_internal_add_module(EglFSDeviceIntegrationPrivate
EGL::EGL
HEADER_SYNC_SOURCE_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}/api"
+ NO_GENERATE_CPP_EXPORTS
)
## Scopes:
diff --git a/src/plugins/platforms/eglfs/api/qeglfscursor.cpp b/src/plugins/platforms/eglfs/api/qeglfscursor.cpp
index 391442de71..1e1a7d8269 100644
--- a/src/plugins/platforms/eglfs/api/qeglfscursor.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfscursor.cpp
@@ -368,6 +368,8 @@ struct StateSaver
f->glGetIntegerv(GL_BLEND_SRC_ALPHA, blendFunc + 1);
f->glGetIntegerv(GL_BLEND_DST_RGB, blendFunc + 2);
f->glGetIntegerv(GL_BLEND_DST_ALPHA, blendFunc + 3);
+ scissor = f->glIsEnabled(GL_SCISSOR_TEST);
+ stencil = f->glIsEnabled(GL_STENCIL_TEST);
f->glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &arrayBuf);
if (vaoHelper->isValid())
f->glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &vao);
@@ -391,17 +393,15 @@ struct StateSaver
f->glFrontFace(frontFace);
if (cull)
f->glEnable(GL_CULL_FACE);
- else
- f->glDisable(GL_CULL_FACE);
if (depthTest)
f->glEnable(GL_DEPTH_TEST);
- else
- f->glDisable(GL_DEPTH_TEST);
- if (blend)
- f->glEnable(GL_BLEND);
- else
+ if (!blend)
f->glDisable(GL_BLEND);
f->glBlendFuncSeparate(blendFunc[0], blendFunc[1], blendFunc[2], blendFunc[3]);
+ if (scissor)
+ f->glEnable(GL_SCISSOR_TEST);
+ if (stencil)
+ f->glEnable(GL_STENCIL_TEST);
f->glBindBuffer(GL_ARRAY_BUFFER, arrayBuf);
if (vaoHelper->isValid())
vaoHelper->glBindVertexArray(vao);
@@ -426,6 +426,8 @@ struct StateSaver
bool depthTest;
bool blend;
GLint blendFunc[4];
+ bool scissor;
+ bool stencil;
GLint vao;
GLint arrayBuf;
struct { GLint enabled, type, size, normalized, stride, buffer; GLvoid *pointer; } va[2];
@@ -505,6 +507,8 @@ void QEglFSCursor::draw(const QRectF &r)
f->glEnable(GL_BLEND);
f->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
f->glDisable(GL_DEPTH_TEST); // disable depth testing to make sure cursor is always on top
+ f->glDisable(GL_SCISSOR_TEST);
+ f->glDisable(GL_STENCIL_TEST);
f->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
diff --git a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp
index 268b9aa093..56fda45e90 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfsdeviceintegration.cpp
@@ -65,7 +65,7 @@ static int framebuffer = -1;
QByteArray QEglFSDeviceIntegration::fbDeviceName() const
{
-#ifdef Q_OS_LINUX
+#if defined(Q_OS_LINUX) || defined(Q_OS_VXWORKS)
QByteArray fbDev = qgetenv("QT_QPA_EGLFS_FB");
if (fbDev.isEmpty())
fbDev = QByteArrayLiteral("/dev/fb0");
@@ -95,7 +95,7 @@ int QEglFSDeviceIntegration::framebufferIndex() const
void QEglFSDeviceIntegration::platformInit()
{
-#ifdef Q_OS_LINUX
+#if defined(Q_OS_LINUX) || defined(Q_OS_VXWORKS)
QByteArray fbDev = fbDeviceName();
framebuffer = qt_safe_open(fbDev, O_RDONLY);
@@ -113,7 +113,7 @@ void QEglFSDeviceIntegration::platformInit()
void QEglFSDeviceIntegration::platformDestroy()
{
-#ifdef Q_OS_LINUX
+#if defined(Q_OS_LINUX) || defined(Q_OS_VXWORKS)
if (framebuffer != -1)
close(framebuffer);
#endif
diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
index 42cbdf127c..f0b64c475c 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfsintegration.cpp
@@ -110,7 +110,8 @@ void QEglFSIntegration::initialize()
void QEglFSIntegration::destroy()
{
- foreach (QWindow *w, qGuiApp->topLevelWindows())
+ const auto toplevels = qGuiApp->topLevelWindows();
+ for (QWindow *w : toplevels)
w->destroy();
qt_egl_device_integration()->screenDestroy();
@@ -386,6 +387,14 @@ QFunctionPointer QEglFSIntegration::platformFunction(const QByteArray &function)
return qt_egl_device_integration()->platformFunction(function);
}
+QVariant QEglFSIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
+{
+ if (hint == QPlatformIntegration::ShowIsFullScreen)
+ return true;
+
+ return QPlatformIntegration::styleHint(hint);
+}
+
#if QT_CONFIG(evdev)
void QEglFSIntegration::loadKeymap(const QString &filename)
{
diff --git a/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h b/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h
index 3e4c57197e..8007167ec7 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h
+++ b/src/plugins/platforms/eglfs/api/qeglfsintegration_p.h
@@ -76,6 +76,8 @@ public:
QFunctionPointer platformFunction(const QByteArray &function) const override;
+ QVariant styleHint(QPlatformIntegration::StyleHint hint) const override;
+
QFbVtHandler *vtHandler() { return m_vtHandler.data(); }
QPointer<QWindow> pointerWindow() { return m_pointerWindow; }
diff --git a/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp
index 72c4a47dbb..c5108be04a 100644
--- a/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp
@@ -189,7 +189,7 @@ QPixmap QEglFSScreen::grabWindow(WId wid, int x, int y, int width, int height) c
return QPixmap::fromImage(img).copy(x, y, width, height);
}
- foreach (QOpenGLCompositorWindow *w, windows) {
+ for (QOpenGLCompositorWindow *w : windows) {
const QWindow *window = w->sourceWindow();
if (window->winId() == wid) {
const QRect geom = window->geometry();
diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
index 1a31f97d7b..306d121cfb 100644
--- a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
+++ b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp
@@ -263,7 +263,7 @@ void QEglFSWindow::requestActivateWindow()
QOpenGLCompositor::instance()->moveToTop(this);
#endif
QWindow *wnd = window();
- QWindowSystemInterface::handleWindowActivated(wnd, Qt::ActiveWindowFocusReason);
+ QWindowSystemInterface::handleFocusWindowChanged(wnd, Qt::ActiveWindowFocusReason);
QWindowSystemInterface::handleExposeEvent(wnd, QRect(QPoint(0, 0), wnd->geometry().size()));
}
diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow_p.h b/src/plugins/platforms/eglfs/api/qeglfswindow_p.h
index d111042040..e51cd69f3d 100644
--- a/src/plugins/platforms/eglfs/api/qeglfswindow_p.h
+++ b/src/plugins/platforms/eglfs/api/qeglfswindow_p.h
@@ -70,8 +70,8 @@ public:
bool isRaster() const;
#ifndef QT_NO_OPENGL
- QOpenGLCompositorBackingStore *backingStore() { return m_backingStore; }
- void setBackingStore(QOpenGLCompositorBackingStore *backingStore);
+ QOpenGLCompositorBackingStore *backingStore() const override { return m_backingStore; }
+ void setBackingStore(QOpenGLCompositorBackingStore *backingStore) override;
QWindow *sourceWindow() const override;
const QPlatformTextureList *textures() const override;
void endCompositing() override;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/CMakeLists.txt
index d6db171637..bb50216f23 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/deviceintegration/CMakeLists.txt
@@ -14,10 +14,10 @@ if(QT_FEATURE_eglfs_egldevice)
add_subdirectory(eglfs_kms_egldevice)
endif()
if(QT_FEATURE_eglfs_vsp2)
- # add_subdirectory(eglfs_kms_vsp2) # special case TODO
+ # add_subdirectory(eglfs_kms_vsp2) # TODO: QTBUG-112769
endif()
if(QT_FEATURE_eglfs_brcm)
- # add_subdirectory(eglfs_brcm) # special case TODO
+ # add_subdirectory(eglfs_brcm) # TODO: QTBUG-112769
endif()
if(QT_FEATURE_eglfs_mali)
add_subdirectory(eglfs_mali)
@@ -26,7 +26,7 @@ if(QT_FEATURE_eglfs_viv)
add_subdirectory(eglfs_viv)
endif()
if(QT_FEATURE_eglfs_rcar)
- # add_subdirectory(eglfs_rcar) # special case TODO
+ # add_subdirectory(eglfs_rcar) # TODO: QTBUG-112769
endif()
if(QT_FEATURE_eglfs_viv_wl)
add_subdirectory(eglfs_viv_wl)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/CMakeLists.txt
index d575ae9d4f..9f9d315202 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/CMakeLists.txt
@@ -24,6 +24,7 @@ qt_internal_add_module(EglFsKmsGbmSupportPrivate
Qt::GuiPrivate
Qt::KmsSupportPrivate
gbm::gbm
+ NO_GENERATE_CPP_EXPORTS
)
#####################################################################
## QEglFSKmsGbmIntegrationPlugin Plugin:
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
index e6fd627823..8dcfed04db 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
@@ -73,8 +73,9 @@ QEglFSKmsGbmScreen::FrameBuffer *QEglFSKmsGbmScreen::framebufferForBufferObject(
return nullptr;
}
- gbm_bo_set_user_data(bo, fb.get(), bufferDestroyedHandler);
- return fb.release();
+ auto res = fb.get();
+ gbm_bo_set_user_data(bo, fb.release(), bufferDestroyedHandler);
+ return res;
}
QEglFSKmsGbmScreen::QEglFSKmsGbmScreen(QEglFSKmsDevice *device, const QKmsOutput &output, bool headless)
@@ -142,11 +143,12 @@ gbm_surface *QEglFSKmsGbmScreen::createSurface(EGLConfig eglConfig)
}
}
+ const uint32_t gbmFormat = drmFormatToGbmFormat(m_output.drm_format);
+
// Fallback for older drivers, and when "format" is explicitly specified
// in the output config. (not guaranteed that the requested format works
// of course, but do what we are told to)
if (!m_gbm_surface) {
- uint32_t gbmFormat = drmFormatToGbmFormat(m_output.drm_format);
if (queryFromEgl)
qCDebug(qLcEglfsKmsDebug, "Could not create surface with EGL_NATIVE_VISUAL_ID, falling back to format %x", gbmFormat);
m_gbm_surface = gbm_surface_create(gbmDevice,
@@ -155,16 +157,39 @@ gbm_surface *QEglFSKmsGbmScreen::createSurface(EGLConfig eglConfig)
gbmFormat,
gbmFlags());
}
+
+ // Fallback for some drivers, its required to request with modifiers
+ if (!m_gbm_surface) {
+ uint64_t modifier = DRM_FORMAT_MOD_LINEAR;
+
+ m_gbm_surface = gbm_surface_create_with_modifiers(gbmDevice,
+ rawGeometry().width(),
+ rawGeometry().height(),
+ gbmFormat,
+ &modifier, 1);
+ }
+ // Fail here, as it would fail with the next usage of the GBM surface, which is very unexpected
+ if (!m_gbm_surface)
+ qFatal("Could not create GBM surface!");
}
return m_gbm_surface; // not owned, gets destroyed in QEglFSKmsGbmIntegration::destroyNativeWindow() via QEglFSKmsGbmWindow::invalidateSurface()
}
void QEglFSKmsGbmScreen::resetSurface()
{
- m_flipPending = false;
+ m_flipPending = false; // not necessarily true but enough to keep bo_next
m_gbm_bo_current = nullptr;
- m_gbm_bo_next = nullptr;
m_gbm_surface = nullptr;
+
+ // Leave m_gbm_bo_next untouched. waitForFlip() should
+ // still do its work, when called. Otherwise we end up
+ // in device-is-busy errors if there is a new QWindow
+ // created afterwards. (QTBUG-122663)
+
+ // If not using atomic, will need a new drmModeSetCrtc if a new window
+ // gets created later on (and so there's a new fb).
+ if (!device()->hasAtomicSupport())
+ needsNewModeSetForNextFb = true;
}
void QEglFSKmsGbmScreen::initCloning(QPlatformScreen *screenThisScreenClones,
@@ -194,8 +219,9 @@ void QEglFSKmsGbmScreen::ensureModeSet(uint32_t fb)
QKmsOutput &op(output());
const int fd = device()->fd();
- if (!op.mode_set) {
+ if (!op.mode_set || needsNewModeSetForNextFb) {
op.mode_set = true;
+ needsNewModeSetForNextFb = false;
bool doModeSet = true;
drmModeCrtcPtr currentMode = drmModeGetCrtc(fd, op.crtc_id);
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen_p.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen_p.h
index 3660f094d2..aca34fcae2 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen_p.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen_p.h
@@ -83,6 +83,8 @@ protected:
bool cloneFlipPending = false;
};
QList<CloneDestination> m_cloneDests;
+
+ bool needsNewModeSetForNextFb = false;
};
QT_END_NAMESPACE
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 9ada2de2b6..a213bc9bba 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
@@ -38,8 +38,11 @@ EGLDisplay QEglFSKmsEglDeviceIntegration::createDisplay(EGLNativeDisplayType nat
EGLDisplay display;
+ EGLint egldevice_fd = device()->fd();
+
+ const EGLint attribs[] = { EGL_DRM_MASTER_FD_EXT, egldevice_fd, EGL_NONE };
if (m_funcs->has_egl_platform_device) {
- display = m_funcs->get_platform_display(EGL_PLATFORM_DEVICE_EXT, nativeDisplay, nullptr);
+ display = m_funcs->get_platform_display(EGL_PLATFORM_DEVICE_EXT, nativeDisplay, attribs);
} else {
qWarning("EGL_EXT_platform_device not available, falling back to legacy path!");
display = eglGetDisplay(nativeDisplay);
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 d4e5f2f90c..3fc46cd224 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.cpp
@@ -13,11 +13,62 @@ Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
QEglFSKmsEglDeviceScreen::QEglFSKmsEglDeviceScreen(QEglFSKmsDevice *device, const QKmsOutput &output)
: QEglFSKmsScreen(device, output)
+ , m_default_fb_handle(uint32_t(-1))
+ , m_default_fb_id(uint32_t(-1))
{
+ const int fd = device->fd();
+
+ struct drm_mode_create_dumb createRequest;
+ createRequest.width = output.size.width();
+ createRequest.height = output.size.height();
+ createRequest.bpp = 32;
+ createRequest.flags = 0;
+
+ qCDebug(qLcEglfsKmsDebug, "Creating dumb fb %dx%d", createRequest.width, createRequest.height);
+
+ int ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &createRequest);
+ if (ret < 0)
+ qFatal("Unable to create dumb buffer.\n");
+
+ m_default_fb_handle = createRequest.handle;
+
+ uint32_t handles[4] = { 0, 0, 0, 0 };
+ uint32_t pitches[4] = { 0, 0, 0, 0 };
+ uint32_t offsets[4] = { 0, 0, 0, 0 };
+
+ handles[0] = createRequest.handle;
+ pitches[0] = createRequest.pitch;
+ offsets[0] = 0;
+
+ ret = drmModeAddFB2(fd, createRequest.width, createRequest.height, DRM_FORMAT_ARGB8888, handles,
+ pitches, offsets, &m_default_fb_id, 0);
+ if (ret)
+ qFatal("Unable to add fb\n");
+
+ qCDebug(qLcEglfsKmsDebug, "Added dumb fb %dx%d handle:%u pitch:%d id:%u", createRequest.width, createRequest.height,
+ createRequest.handle, createRequest.pitch, m_default_fb_id);
}
QEglFSKmsEglDeviceScreen::~QEglFSKmsEglDeviceScreen()
{
+ int ret;
+ const int fd = device()->fd();
+
+ if (m_default_fb_id != uint32_t(-1)) {
+ ret = drmModeRmFB(fd, m_default_fb_id);
+ if (ret)
+ qErrnoWarning("drmModeRmFB failed");
+ }
+
+ if (m_default_fb_handle != uint32_t(-1)) {
+ struct drm_mode_destroy_dumb destroyRequest;
+ destroyRequest.handle = m_default_fb_handle;
+
+ ret = drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroyRequest);
+ if (ret)
+ qErrnoWarning("DRM_IOCTL_MODE_DESTROY_DUMB failed");
+ }
+
const int remainingScreenCount = qGuiApp->screens().size();
qCDebug(qLcEglfsKmsDebug, "Screen dtor. Remaining screens: %d", remainingScreenCount);
if (!remainingScreenCount && !device()->screenConfig()->separateScreens())
@@ -53,8 +104,11 @@ void QEglFSKmsEglDeviceScreen::waitForFlip()
if (alreadySet) {
// Maybe detecting the DPMS mode could help here, but there are no properties
// exposed on the connector apparently. So rely on an env var for now.
- static bool alwaysDoSet = qEnvironmentVariableIntValue("QT_QPA_EGLFS_ALWAYS_SET_MODE");
- if (!alwaysDoSet) {
+ // Note that typically, we need to set crtc with the default fb even if the
+ // mode did not change, unless QT_QPA_EGLFS_ALWAYS_SET_MODE is explicitly specified.
+ static bool envVarSet = false;
+ static bool alwaysDoSet = qEnvironmentVariableIntValue("QT_QPA_EGLFS_ALWAYS_SET_MODE", &envVarSet);
+ if (envVarSet && !alwaysDoSet) {
qCDebug(qLcEglfsKmsDebug, "Mode already set");
return;
}
@@ -62,7 +116,7 @@ void QEglFSKmsEglDeviceScreen::waitForFlip()
qCDebug(qLcEglfsKmsDebug, "Setting mode");
int ret = drmModeSetCrtc(fd, op.crtc_id,
- uint32_t(-1), 0, 0,
+ m_default_fb_id, 0, 0,
&op.connector_id, 1,
&op.modes[op.mode]);
if (ret)
@@ -74,7 +128,7 @@ void QEglFSKmsEglDeviceScreen::waitForFlip()
if (op.wants_forced_plane) {
qCDebug(qLcEglfsKmsDebug, "Setting plane %u", op.forced_plane_id);
- int ret = drmModeSetPlane(fd, op.forced_plane_id, op.crtc_id, uint32_t(-1), 0,
+ int ret = drmModeSetPlane(fd, op.forced_plane_id, op.crtc_id, m_default_fb_id, 0,
0, 0, w, h,
0 << 16, 0 << 16, op.size.width() << 16, op.size.height() << 16);
if (ret == -1)
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 884a70093a..8779499bef 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicescreen.h
@@ -17,6 +17,9 @@ public:
QPlatformCursor *cursor() const override;
void waitForFlip() override;
+private:
+ uint32_t m_default_fb_handle;
+ uint32_t m_default_fb_id;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/CMakeLists.txt b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/CMakeLists.txt
index bffacb822e..5fcc0e1b18 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/CMakeLists.txt
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_support/CMakeLists.txt
@@ -24,4 +24,5 @@ qt_internal_add_module(EglFsKmsSupportPrivate
Qt::Gui
Qt::GuiPrivate
Qt::KmsSupportPrivate
+ NO_GENERATE_CPP_EXPORTS
)
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qlinuxmediadevice.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qlinuxmediadevice.cpp
index 44555b85b5..5d2900097e 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qlinuxmediadevice.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_vsp2/qlinuxmediadevice.cpp
@@ -200,7 +200,7 @@ bool QLinuxMediaDevice::resetLinks()
struct media_link *QLinuxMediaDevice::parseLink(const QString &link)
{
- char *endp = nullptr;;
+ char *endp = nullptr;
struct media_link *mediaLink = media_parse_link(m_mediaDevice, link.toStdString().c_str(), &endp);
if (!mediaLink)
diff --git a/src/plugins/platforms/haiku/qhaikuintegration.cpp b/src/plugins/platforms/haiku/qhaikuintegration.cpp
index 7a4ecbfcbf..2b0672e363 100644
--- a/src/plugins/platforms/haiku/qhaikuintegration.cpp
+++ b/src/plugins/platforms/haiku/qhaikuintegration.cpp
@@ -20,6 +20,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::Literals::StringLiterals;
+
static long int startApplicationThread(void *data)
{
QHaikuApplication *app = static_cast<QHaikuApplication*>(data);
@@ -32,7 +34,7 @@ QHaikuIntegration::QHaikuIntegration(const QStringList &parameters)
{
Q_UNUSED(parameters);
- const QString signature = QStringLiteral("application/x-vnd.Qt.%1").arg(QFileInfo(QCoreApplication::applicationFilePath()).fileName());
+ const QString signature = "application/x-vnd.Qt.%1"_L1.arg(QFileInfo(QCoreApplication::applicationFilePath()).fileName());
QHaikuApplication *app = new QHaikuApplication(signature.toLocal8Bit());
be_app = app;
diff --git a/src/plugins/platforms/haiku/qhaikuwindow.cpp b/src/plugins/platforms/haiku/qhaikuwindow.cpp
index 21bcad1749..3f2c6a889a 100644
--- a/src/plugins/platforms/haiku/qhaikuwindow.cpp
+++ b/src/plugins/platforms/haiku/qhaikuwindow.cpp
@@ -294,7 +294,7 @@ void QHaikuWindow::haikuWindowResized(const QSize &size, bool zoomInProgress)
void QHaikuWindow::haikuWindowActivated(bool activated)
{
- QWindowSystemInterface::handleWindowActivated(activated ? window() : nullptr);
+ QWindowSystemInterface::handleFocusWindowChanged(activated ? window() : nullptr);
}
void QHaikuWindow::haikuWindowMinimized(bool minimize)
diff --git a/src/plugins/platforms/ios/CMakeLists.txt b/src/plugins/platforms/ios/CMakeLists.txt
index e0473b3ce4..4cc3efc91e 100644
--- a/src/plugins/platforms/ios/CMakeLists.txt
+++ b/src/plugins/platforms/ios/CMakeLists.txt
@@ -27,7 +27,13 @@ qt_internal_add_plugin(QIOSIntegrationPlugin
qioswindow.h qioswindow.mm
quiaccessibilityelement.h quiaccessibilityelement.mm
quiview.h quiview.mm
+ quiwindow.mm quiwindow.h
uistrings_p.h uistrings.cpp
+ NO_PCH_SOURCES
+ qioscontext.mm # undef QT_NO_FOREACH
+ qiosintegration.mm # undef QT_NO_FOREACH
+ qiosplatformaccessibility.mm # undef QT_NO_FOREACH
+ qiosscreen.mm # undef QT_NO_FOREACH
LIBRARIES
${FWAudioToolbox}
${FWFoundation}
@@ -52,19 +58,31 @@ qt_internal_extend_target(QIOSIntegrationPlugin CONDITION QT_FEATURE_opengl
Qt::OpenGLPrivate
)
-qt_internal_extend_target(QIOSIntegrationPlugin CONDITION NOT TVOS
+qt_internal_extend_target(QIOSIntegrationPlugin CONDITION QT_FEATURE_clipboard
SOURCES
qiosclipboard.h qiosclipboard.mm
- qiosdocumentpickercontroller.h qiosdocumentpickercontroller.mm
+)
+
+qt_internal_extend_target(QIOSIntegrationPlugin CONDITION NOT TVOS
+ SOURCES
qiosfiledialog.h qiosfiledialog.mm
+ qiosdocumentpickercontroller.h qiosdocumentpickercontroller.mm
+ LIBRARIES
+ ${FWUniformTypeIdentifiers}
+ ${FWPhotos}
+)
+
+qt_internal_extend_target(QIOSIntegrationPlugin CONDITION NOT TVOS
+ SOURCES
qioscolordialog.h qioscolordialog.mm
qiosfontdialog.h qiosfontdialog.mm
- qiosmenu.h qiosmenu.mm
qiosmessagedialog.h qiosmessagedialog.mm
+)
+
+qt_internal_extend_target(QIOSIntegrationPlugin CONDITION NOT (TVOS OR VISIONOS)
+ SOURCES
+ qiosmenu.h qiosmenu.mm
qiostextinputoverlay.h qiostextinputoverlay.mm
- LIBRARIES
- ${FWAssetsLibrary}
- ${FWUniformTypeIdentifiers}
)
add_subdirectory(optional)
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h
index 90b62af56d..0ad54a9e11 100644
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h
+++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.h
@@ -29,8 +29,8 @@ public:
void setFileName(const QString &file) override;
#ifndef QT_NO_FILESYSTEMITERATOR
- Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override;
- Iterator *endEntryList() override;
+ IteratorUniquePtr beginEntryList(const QString &path, QDir::Filters filters,
+ const QStringList &filterNames) override;
#endif
void setError(QFile::FileError error, const QString &str) { QAbstractFileEngine::setError(error, str); }
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm
index 0ca911f68b..f7e112ab81 100644
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm
+++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileengineassetslibrary.mm
@@ -11,6 +11,8 @@
#include <QtCore/qurl.h>
#include <QtCore/qset.h>
#include <QtCore/qthreadstorage.h>
+#include <QtCore/qfileselector.h>
+#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
@@ -256,8 +258,8 @@ public:
QIOSAssetEnumerator *m_enumerator;
QIOSFileEngineIteratorAssetsLibrary(
- QDir::Filters filters, const QStringList &nameFilters)
- : QAbstractFileEngineIterator(filters, nameFilters)
+ const QString &path, QDir::Filters filters, const QStringList &nameFilters)
+ : QAbstractFileEngineIterator(path, filters, nameFilters)
, m_enumerator(new QIOSAssetEnumerator([[[ALAssetsLibrary alloc] init] autorelease], ALAssetsGroupAll))
{
}
@@ -268,8 +270,11 @@ public:
g_iteratorCurrentUrl.setLocalData(QString());
}
- QString next() override
+ bool advance() override
{
+ if (!m_enumerator->hasNext())
+ return false;
+
// Cache the URL that we are about to return, since QDir will immediately create a
// new file engine on the file and ask if it exists. Unless we do this, we end up
// creating a new ALAsset just to verify its existence, which will be especially
@@ -277,12 +282,7 @@ public:
ALAsset *asset = m_enumerator->next();
QString url = QUrl::fromNSURL([asset valueForProperty:ALAssetPropertyAssetURL]).toString();
g_iteratorCurrentUrl.setLocalData(url);
- return url;
- }
-
- bool hasNext() const override
- {
- return m_enumerator->hasNext();
+ return true;
}
QString currentFileName() const override
@@ -344,6 +344,17 @@ QAbstractFileEngine::FileFlags QIOSFileEngineAssetsLibrary::fileFlags(QAbstractF
{
QAbstractFileEngine::FileFlags flags;
const bool isDir = (m_assetUrl == "assets-library://"_L1);
+ if (!isDir) {
+ static const QFileSelector fileSelector;
+ static const auto selectors = fileSelector.allSelectors();
+ if (m_assetUrl.startsWith("assets-library://"_L1)) {
+ for (const auto &selector : selectors) {
+ if (m_assetUrl.endsWith(selector))
+ return flags;
+ }
+ }
+ }
+
const bool exists = isDir || m_assetUrl == g_iteratorCurrentUrl.localData() || loadAsset();
if (!exists)
@@ -427,15 +438,11 @@ void QIOSFileEngineAssetsLibrary::setFileName(const QString &file)
#ifndef QT_NO_FILESYSTEMITERATOR
-QAbstractFileEngine::Iterator *QIOSFileEngineAssetsLibrary::beginEntryList(
- QDir::Filters filters, const QStringList &filterNames)
-{
- return new QIOSFileEngineIteratorAssetsLibrary(filters, filterNames);
-}
-
-QAbstractFileEngine::Iterator *QIOSFileEngineAssetsLibrary::endEntryList()
+QAbstractFileEngine::IteratorUniquePtr
+QIOSFileEngineAssetsLibrary::beginEntryList(
+ const QString &path, QDir::Filters filters, const QStringList &filterNames)
{
- return 0;
+ return std::make_unique<QIOSFileEngineIteratorAssetsLibrary>(path, filters, filterNames);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileenginefactory.h b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileenginefactory.h
index f545a81bf2..dfffbb8990 100644
--- a/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileenginefactory.h
+++ b/src/plugins/platforms/ios/optional/nsphotolibrarysupport/qiosfileenginefactory.h
@@ -12,19 +12,22 @@ QT_BEGIN_NAMESPACE
class QIOSFileEngineFactory : public QAbstractFileEngineHandler
{
+ Q_DISABLE_COPY_MOVE(QIOSFileEngineFactory)
public:
- QAbstractFileEngine* create(const QString &fileName) const
+ QIOSFileEngineFactory() = default;
+
+ std::unique_ptr<QAbstractFileEngine> create(const QString &fileName) const
{
Q_CONSTINIT static QLatin1StringView assetsScheme("assets-library:");
#ifndef Q_OS_TVOS
if (fileName.toLower().startsWith(assetsScheme))
- return new QIOSFileEngineAssetsLibrary(fileName);
+ return std::make_unique<QIOSFileEngineAssetsLibrary>(fileName);
#else
Q_UNUSED(fileName);
#endif
- return 0;
+ return {};
}
};
diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.mm b/src/plugins/platforms/ios/qiosapplicationdelegate.mm
index a017fef457..c6e5a83874 100644
--- a/src/plugins/platforms/ios/qiosapplicationdelegate.mm
+++ b/src/plugins/platforms/ios/qiosapplicationdelegate.mm
@@ -3,15 +3,21 @@
#include "qiosapplicationdelegate.h"
+#include "qiosglobal.h"
#include "qiosintegration.h"
#include "qiosservices.h"
#include "qiosviewcontroller.h"
#include "qioswindow.h"
+#include "qiosscreen.h"
+#include "quiwindow.h"
#include <qpa/qplatformintegration.h>
#include <QtCore/QtCore>
+@interface QIOSWindowSceneDelegate : NSObject<UIWindowSceneDelegate>
+@end
+
@implementation QIOSApplicationDelegate
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring>> *restorableObjects))restorationHandler
@@ -50,5 +56,44 @@
return iosServices->handleUrl(QUrl::fromNSURL(url));
}
+- (UISceneConfiguration *)application:(UIApplication *)application
+ configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession
+ options:(UISceneConnectionOptions *)options
+{
+ qCDebug(lcQpaWindowScene) << "Configuring scene for" << connectingSceneSession
+ << "with options" << options;
+
+ auto *sceneConfig = connectingSceneSession.configuration;
+ sceneConfig.delegateClass = QIOSWindowSceneDelegate.class;
+ return sceneConfig;
+}
+
@end
+@implementation QIOSWindowSceneDelegate
+
+- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions
+{
+ qCDebug(lcQpaWindowScene) << "Connecting" << scene << "to" << session;
+
+ Q_ASSERT([scene isKindOfClass:UIWindowScene.class]);
+ UIWindowScene *windowScene = static_cast<UIWindowScene*>(scene);
+
+ QUIWindow *window = [[QUIWindow alloc] initWithWindowScene:windowScene];
+
+ QIOSScreen *screen = [&]{
+ for (auto *screen : qGuiApp->screens()) {
+ auto *platformScreen = static_cast<QIOSScreen*>(screen->handle());
+#if !defined(Q_OS_VISIONOS)
+ if (platformScreen->uiScreen() == windowScene.screen)
+#endif
+ return platformScreen;
+ }
+ Q_UNREACHABLE();
+ }();
+
+ window.rootViewController = [[[QIOSViewController alloc]
+ initWithWindow:window andScreen:screen] autorelease];
+}
+
+@end
diff --git a/src/plugins/platforms/ios/qiosclipboard.mm b/src/plugins/platforms/ios/qiosclipboard.mm
index f07391a369..de8ab69dff 100644
--- a/src/plugins/platforms/ios/qiosclipboard.mm
+++ b/src/plugins/platforms/ios/qiosclipboard.mm
@@ -11,18 +11,6 @@
#include <QtCore/QMimeData>
#include <QtGui/QGuiApplication>
-@interface UIPasteboard (QUIPasteboard)
-+ (instancetype)pasteboardWithQClipboardMode:(QClipboard::Mode)mode;
-@end
-
-@implementation UIPasteboard (QUIPasteboard)
-+ (instancetype)pasteboardWithQClipboardMode:(QClipboard::Mode)mode
-{
- NSString *name = (mode == QClipboard::Clipboard) ? UIPasteboardNameGeneral : UIPasteboardNameFind;
- return [UIPasteboard pasteboardWithName:name create:NO];
-}
-@end
-
// --------------------------------------------------------------------
@interface QUIClipboard : NSObject
@@ -31,7 +19,6 @@
@implementation QUIClipboard {
QIOSClipboard *m_qiosClipboard;
NSInteger m_changeCountClipboard;
- NSInteger m_changeCountFindBuffer;
}
- (instancetype)initWithQIOSClipboard:(QIOSClipboard *)qiosClipboard
@@ -39,8 +26,7 @@
self = [super init];
if (self) {
m_qiosClipboard = qiosClipboard;
- m_changeCountClipboard = [UIPasteboard pasteboardWithQClipboardMode:QClipboard::Clipboard].changeCount;
- m_changeCountFindBuffer = [UIPasteboard pasteboardWithQClipboardMode:QClipboard::FindBuffer].changeCount;
+ m_changeCountClipboard = UIPasteboard.generalPasteboard.changeCount;
[[NSNotificationCenter defaultCenter]
addObserver:self
@@ -77,18 +63,12 @@
- (void)updatePasteboardChanged:(NSNotification *)notification
{
Q_UNUSED(notification);
- NSInteger changeCountClipboard = [UIPasteboard pasteboardWithQClipboardMode:QClipboard::Clipboard].changeCount;
- NSInteger changeCountFindBuffer = [UIPasteboard pasteboardWithQClipboardMode:QClipboard::FindBuffer].changeCount;
+ NSInteger changeCountClipboard = UIPasteboard.generalPasteboard.changeCount;
if (m_changeCountClipboard != changeCountClipboard) {
m_changeCountClipboard = changeCountClipboard;
m_qiosClipboard->emitChanged(QClipboard::Clipboard);
}
-
- if (m_changeCountFindBuffer != changeCountFindBuffer) {
- m_changeCountFindBuffer = changeCountFindBuffer;
- m_qiosClipboard->emitChanged(QClipboard::FindBuffer);
- }
}
@end
@@ -99,20 +79,17 @@ QT_BEGIN_NAMESPACE
class QIOSMimeData : public QMimeData {
public:
- QIOSMimeData(QClipboard::Mode mode) : QMimeData(), m_mode(mode) { }
+ QIOSMimeData() : QMimeData() { }
~QIOSMimeData() { }
QStringList formats() const override;
QVariant retrieveData(const QString &mimeType, QMetaType type) const override;
-
-private:
- const QClipboard::Mode m_mode;
};
QStringList QIOSMimeData::formats() const
{
QStringList foundMimeTypes;
- UIPasteboard *pb = [UIPasteboard pasteboardWithQClipboardMode:m_mode];
+ UIPasteboard *pb = UIPasteboard.generalPasteboard;
NSArray<NSString *> *pasteboardTypes = [pb pasteboardTypes];
for (NSUInteger i = 0; i < [pasteboardTypes count]; ++i) {
@@ -127,7 +104,7 @@ QStringList QIOSMimeData::formats() const
QVariant QIOSMimeData::retrieveData(const QString &mimeType, QMetaType) const
{
- UIPasteboard *pb = [UIPasteboard pasteboardWithQClipboardMode:m_mode];
+ UIPasteboard *pb = UIPasteboard.generalPasteboard;
NSArray<NSString *> *pasteboardTypes = [pb pasteboardTypes];
const auto converters = QMacMimeRegistry::all(QUtiMimeConverter::HandlerScopeFlag::All);
@@ -164,7 +141,7 @@ QMimeData *QIOSClipboard::mimeData(QClipboard::Mode mode)
{
Q_ASSERT(supportsMode(mode));
if (!m_mimeData.contains(mode))
- return *m_mimeData.insert(mode, new QIOSMimeData(mode));
+ return *m_mimeData.insert(mode, new QIOSMimeData);
return m_mimeData[mode];
}
@@ -172,7 +149,7 @@ void QIOSClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
{
Q_ASSERT(supportsMode(mode));
- UIPasteboard *pb = [UIPasteboard pasteboardWithQClipboardMode:mode];
+ UIPasteboard *pb = UIPasteboard.generalPasteboard;
if (!mimeData) {
pb.items = [NSArray<NSDictionary<NSString *, id> *> array];
return;
@@ -193,15 +170,17 @@ void QIOSClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
if (mimeData->hasImage()) {
mimeDataAsVariant = mimeData->imageData();
} else if (mimeData->hasUrls()) {
+ const auto urls = mimeData->urls();
QVariantList urlList;
- for (QUrl url : mimeData->urls())
+ urlList.reserve(urls.size());
+ for (const QUrl& url : urls)
urlList << url;
mimeDataAsVariant = QVariant(urlList);
} else {
mimeDataAsVariant = QVariant(mimeData->data(mimeType));
}
- QByteArray byteArray = converter->convertFromMime(mimeType, mimeDataAsVariant, uti).first();
+ QByteArray byteArray = converter->convertFromMime(mimeType, mimeDataAsVariant, uti).constFirst();
NSData *nsData = [NSData dataWithBytes:byteArray.constData() length:byteArray.size()];
[pbItem setValue:nsData forKey:uti.toNSString()];
break;
@@ -213,7 +192,7 @@ void QIOSClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
bool QIOSClipboard::supportsMode(QClipboard::Mode mode) const
{
- return (mode == QClipboard::Clipboard || mode == QClipboard::FindBuffer);
+ return mode == QClipboard::Clipboard;
}
bool QIOSClipboard::ownsMode(QClipboard::Mode mode) const
diff --git a/src/plugins/platforms/ios/qioscolordialog.mm b/src/plugins/platforms/ios/qioscolordialog.mm
index 92c0f3e46c..6651b1791d 100644
--- a/src/plugins/platforms/ios/qioscolordialog.mm
+++ b/src/plugins/platforms/ios/qioscolordialog.mm
@@ -8,6 +8,7 @@
#include <QtCore/private/qcore_mac_p.h>
+#include "qiosglobal.h"
#include "qioscolordialog.h"
#include "qiosintegration.h"
@@ -117,8 +118,7 @@ bool QIOSColorDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality windo
if (windowModality == Qt::ApplicationModal || windowModality == Qt::WindowModal)
m_viewController.modalInPresentation = YES;
- UIWindow *window = parent ? reinterpret_cast<UIView *>(parent->winId()).window
- : qt_apple_sharedApplication().keyWindow;
+ UIWindow *window = presentationWindow(parent);
if (!window)
return false;
diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm
index 1649089841..499adea0fe 100644
--- a/src/plugins/platforms/ios/qioscontext.mm
+++ b/src/plugins/platforms/ios/qioscontext.mm
@@ -1,6 +1,8 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
+
#include "qioscontext.h"
#include "qiosintegration.h"
diff --git a/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm b/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm
index af866077cd..fca0432426 100644
--- a/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm
+++ b/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm
@@ -30,14 +30,14 @@
case QFileDialogOptions::AnyFile:
case QFileDialogOptions::ExistingFile:
case QFileDialogOptions::ExistingFiles:
- [docTypes addObject:[UTType typeWithIdentifier:(__bridge NSString *)kUTTypeContent]];
- [docTypes addObject:[UTType typeWithIdentifier:(__bridge NSString *)kUTTypeItem]];
- [docTypes addObject:[UTType typeWithIdentifier:(__bridge NSString *)kUTTypeData]];
+ [docTypes addObject:[UTType typeWithIdentifier:(__bridge NSString *)UTTypeContent]];
+ [docTypes addObject:[UTType typeWithIdentifier:(__bridge NSString *)UTTypeItem]];
+ [docTypes addObject:[UTType typeWithIdentifier:(__bridge NSString *)UTTypeData]];
break;
// Showing files is not supported in Directory mode in iOS
case QFileDialogOptions::Directory:
case QFileDialogOptions::DirectoryOnly:
- [docTypes addObject:[UTType typeWithIdentifier:(__bridge NSString *)kUTTypeFolder]];
+ [docTypes addObject:[UTType typeWithIdentifier:(__bridge NSString *)UTTypeFolder]];
break;
}
}
diff --git a/src/plugins/platforms/ios/qiosfiledialog.h b/src/plugins/platforms/ios/qiosfiledialog.h
index 12a3af7181..f00c154c03 100644
--- a/src/plugins/platforms/ios/qiosfiledialog.h
+++ b/src/plugins/platforms/ios/qiosfiledialog.h
@@ -39,6 +39,7 @@ private:
bool showImagePickerDialog(QWindow *parent);
bool showNativeDocumentPickerDialog(QWindow *parent);
+ void showImagePickerDialog_helper(QWindow *parent);
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosfiledialog.mm b/src/plugins/platforms/ios/qiosfiledialog.mm
index 526c040335..cf9580c17e 100644
--- a/src/plugins/platforms/ios/qiosfiledialog.mm
+++ b/src/plugins/platforms/ios/qiosfiledialog.mm
@@ -3,17 +3,22 @@
#import <UIKit/UIKit.h>
+#import <Photos/Photos.h>
+
#include <QtCore/qstandardpaths.h>
#include <QtGui/qwindow.h>
#include <QDebug>
#include <QtCore/private/qcore_mac_p.h>
+#include "qiosglobal.h"
#include "qiosfiledialog.h"
#include "qiosintegration.h"
#include "qiosoptionalplugininterface.h"
#include "qiosdocumentpickercontroller.h"
+#include <QtCore/qpointer.h>
+
using namespace Qt::StringLiterals;
QIOSFileDialog::QIOSFileDialog()
@@ -53,6 +58,12 @@ bool QIOSFileDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality window
return false;
}
+void QIOSFileDialog::showImagePickerDialog_helper(QWindow *parent)
+{
+ UIWindow *window = presentationWindow(parent);
+ [window.rootViewController presentViewController:m_viewController animated:YES completion:nil];
+}
+
bool QIOSFileDialog::showImagePickerDialog(QWindow *parent)
{
if (!m_viewController) {
@@ -71,9 +82,38 @@ bool QIOSFileDialog::showImagePickerDialog(QWindow *parent)
return false;
}
- UIWindow *window = parent ? reinterpret_cast<UIView *>(parent->winId()).window
- : qt_apple_sharedApplication().keyWindow;
- [window.rootViewController presentViewController:m_viewController animated:YES completion:nil];
+ // "Old style" authorization (deprecated, but we have to work with AssetsLibrary anyway).
+ //
+ // From the documentation:
+ // "The authorizationStatus and requestAuthorization: methods aren’t compatible with the
+ // limited library and return PHAuthorizationStatusAuthorized when the user authorizes your
+ // app for limited access only."
+ //
+ // This is good enough for us.
+
+ const auto authStatus = [PHPhotoLibrary authorizationStatus];
+ if (authStatus == PHAuthorizationStatusAuthorized) {
+ showImagePickerDialog_helper(parent);
+ } else if (authStatus == PHAuthorizationStatusNotDetermined) {
+ QPointer<QWindow> winGuard(parent);
+ QPointer<QIOSFileDialog> thisGuard(this);
+ [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ if (status == PHAuthorizationStatusAuthorized) {
+ if (thisGuard && winGuard)
+ thisGuard->showImagePickerDialog_helper(winGuard);
+
+ } else if (thisGuard) {
+ emit thisGuard->reject();
+ }
+ });
+ }];
+ } else {
+ // Treat 'Limited' (we don't know how to deal with anyway) and 'Denied' as errors.
+ // FIXME: logging category?
+ qWarning() << "QIOSFileDialog: insufficient permission, cannot pick images";
+ return false;
+ }
return true;
}
@@ -83,8 +123,7 @@ bool QIOSFileDialog::showNativeDocumentPickerDialog(QWindow *parent)
#ifndef Q_OS_TVOS
m_viewController = [[QIOSDocumentPickerController alloc] initWithQIOSFileDialog:this];
- UIWindow *window = parent ? reinterpret_cast<UIView *>(parent->winId()).window
- : qt_apple_sharedApplication().keyWindow;
+ UIWindow *window = presentationWindow(parent);
[window.rootViewController presentViewController:m_viewController animated:YES completion:nil];
return true;
diff --git a/src/plugins/platforms/ios/qiosfontdialog.mm b/src/plugins/platforms/ios/qiosfontdialog.mm
index 4cea1cb558..25d0197195 100644
--- a/src/plugins/platforms/ios/qiosfontdialog.mm
+++ b/src/plugins/platforms/ios/qiosfontdialog.mm
@@ -11,6 +11,7 @@
#include <QtGui/private/qfont_p.h>
#include <QtGui/private/qfontengine_p.h>
+#include "qiosglobal.h"
#include "qiosfontdialog.h"
#include "qiosintegration.h"
@@ -144,8 +145,7 @@ bool QIOSFontDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality window
if (windowModality == Qt::ApplicationModal || windowModality == Qt::WindowModal)
m_viewController.modalInPresentation = YES;
- UIWindow *window = parent ? reinterpret_cast<UIView *>(parent->winId()).window
- : qt_apple_sharedApplication().keyWindow;
+ UIWindow *window = presentationWindow(parent);
if (!window)
return false;
diff --git a/src/plugins/platforms/ios/qiosglobal.h b/src/plugins/platforms/ios/qiosglobal.h
index 022fa88c24..9428487a00 100644
--- a/src/plugins/platforms/ios/qiosglobal.h
+++ b/src/plugins/platforms/ios/qiosglobal.h
@@ -14,6 +14,7 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcQpaApplication);
Q_DECLARE_LOGGING_CATEGORY(lcQpaInputMethods);
Q_DECLARE_LOGGING_CATEGORY(lcQpaWindow);
+Q_DECLARE_LOGGING_CATEGORY(lcQpaWindowScene);
#if !defined(QT_NO_DEBUG)
#define qImDebug \
@@ -26,6 +27,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaWindow);
class QPlatformScreen;
bool isQtApplication();
+bool isRunningOnVisionOS();
#ifndef Q_OS_TVOS
Qt::ScreenOrientation toQtScreenOrientation(UIDeviceOrientation uiDeviceOrientation);
@@ -34,10 +36,15 @@ UIDeviceOrientation fromQtScreenOrientation(Qt::ScreenOrientation qtOrientation)
int infoPlistValue(NSString* key, int defaultValue);
+class QWindow;
+class QScreen;
+UIWindow *presentationWindow(QWindow *);
+UIView *rootViewForScreen(QScreen *);
+
QT_END_NAMESPACE
@interface UIResponder (QtFirstResponder)
-+ (id)currentFirstResponder;
++ (id)qt_currentFirstResponder;
@end
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm
index 0a6bc5bb62..25ccf2961b 100644
--- a/src/plugins/platforms/ios/qiosglobal.mm
+++ b/src/plugins/platforms/ios/qiosglobal.mm
@@ -13,6 +13,7 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcQpaApplication, "qt.qpa.application");
Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods");
Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window");
+Q_LOGGING_CATEGORY(lcQpaWindowScene, "qt.qpa.window.scene");
bool isQtApplication()
{
@@ -29,6 +30,15 @@ bool isQtApplication()
return isQt;
}
+bool isRunningOnVisionOS()
+{
+ static bool result = []{
+ // This class is documented to only be available on visionOS
+ return NSClassFromString(@"UIWindowSceneGeometryPreferencesVision");
+ }();
+ return result;
+}
+
#ifndef Q_OS_TVOS
Qt::ScreenOrientation toQtScreenOrientation(UIDeviceOrientation uiDeviceOrientation)
{
@@ -85,6 +95,47 @@ int infoPlistValue(NSString* key, int defaultValue)
return value ? [value intValue] : defaultValue;
}
+UIWindow *presentationWindow(QWindow *window)
+{
+ UIWindow *uiWindow = window ? reinterpret_cast<UIView *>(window->winId()).window : nullptr;
+ if (!uiWindow) {
+ auto *scenes = [qt_apple_sharedApplication().connectedScenes allObjects];
+ if (scenes.count > 0) {
+ auto *windowScene = static_cast<UIWindowScene*>(scenes[0]);
+ uiWindow = windowScene.keyWindow;
+ if (!uiWindow && windowScene.windows.count)
+ uiWindow = windowScene.windows[0];
+ }
+ }
+ return uiWindow;
+}
+
+UIView *rootViewForScreen(QScreen *screen)
+{
+ const auto *iosScreen = static_cast<QIOSScreen *>(screen->handle());
+ for (UIScene *scene in [qt_apple_sharedApplication().connectedScenes allObjects]) {
+ if (![scene isKindOfClass:UIWindowScene.class])
+ continue;
+
+ auto *windowScene = static_cast<UIWindowScene*>(scene);
+
+#if !defined(Q_OS_VISIONOS)
+ if (windowScene.screen != iosScreen->uiScreen())
+ continue;
+#else
+ Q_UNUSED(iosScreen);
+#endif
+
+ UIWindow *uiWindow = windowScene.keyWindow;
+ if (!uiWindow && windowScene.windows.count)
+ uiWindow = windowScene.windows[0];
+
+ return uiWindow.rootViewController.view;
+ }
+
+ return nullptr;
+}
+
QT_END_NAMESPACE
// -------------------------------------------------------------------------
@@ -119,7 +170,7 @@ QT_END_NAMESPACE
@implementation UIResponder (QtFirstResponder)
-+ (id)currentFirstResponder
++ (id)qt_currentFirstResponder
{
if (qt_apple_isApplicationExtension()) {
qWarning() << "can't get first responder in application extensions!";
diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm
index 7a76760638..5716ad041e 100644
--- a/src/plugins/platforms/ios/qiosinputcontext.mm
+++ b/src/plugins/platforms/ios/qiosinputcontext.mm
@@ -18,6 +18,8 @@
#include <QGuiApplication>
#include <QtGui/private/qwindow_p.h>
+#include <QtCore/qpointer.h>
+
// -------------------------------------------------------------------------
static QUIView *focusView()
@@ -119,7 +121,7 @@ static QUIView *focusView()
{
[self keyboardWillOrDidChange:notification];
- UIResponder *firstResponder = [UIResponder currentFirstResponder];
+ UIResponder *firstResponder = [UIResponder qt_currentFirstResponder];
if (![firstResponder isKindOfClass:[QIOSTextInputResponder class]])
return;
@@ -174,7 +176,11 @@ static QUIView *focusView()
{
[super touchesBegan:touches withEvent:event];
- Q_ASSERT(m_context->isInputPanelVisible());
+ if (!m_context->isInputPanelVisible()) {
+ qImDebug("keyboard was hidden by sliding it down, disabling hide-keyboard gesture");
+ self.enabled = NO;
+ return;
+ }
if ([touches count] != 1)
self.state = UIGestureRecognizerStateFailed;
@@ -228,7 +234,7 @@ static QUIView *focusView()
if (self.state == UIGestureRecognizerStateBegan) {
qImDebug("hide keyboard gesture was triggered");
- UIResponder *firstResponder = [UIResponder currentFirstResponder];
+ UIResponder *firstResponder = [UIResponder qt_currentFirstResponder];
Q_ASSERT([firstResponder isKindOfClass:[QIOSTextInputResponder class]]);
[firstResponder resignFirstResponder];
}
@@ -297,11 +303,7 @@ QIOSInputContext::QIOSInputContext()
, m_keyboardHideGesture([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this])
, m_textResponder(0)
{
- if (isQtApplication()) {
- QIOSScreen *iosScreen = static_cast<QIOSScreen*>(QGuiApplication::primaryScreen()->handle());
- [iosScreen->uiWindow() addGestureRecognizer:m_keyboardHideGesture];
- }
-
+ Q_ASSERT(!qGuiApp->focusWindow());
connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &QIOSInputContext::focusWindowChanged);
}
@@ -346,7 +348,7 @@ void QIOSInputContext::clearCurrentFocusObject()
void QIOSInputContext::updateKeyboardState(NSNotification *notification)
{
-#ifdef Q_OS_TVOS
+#if defined(Q_OS_TVOS) || defined(Q_OS_VISIONOS)
Q_UNUSED(notification);
#else
static CGRect currentKeyboardRect = CGRectZero;
@@ -436,6 +438,7 @@ UIView *QIOSInputContext::scrollableRootView()
void QIOSInputContext::scrollToCursor()
{
+#if !defined(Q_OS_VISIONOS)
if (!isQtApplication())
return;
@@ -492,6 +495,7 @@ void QIOSInputContext::scrollToCursor()
} else {
scroll(0);
}
+#endif
}
void QIOSInputContext::scroll(int y)
@@ -603,12 +607,15 @@ void QIOSInputContext::setFocusObject(QObject *focusObject)
void QIOSInputContext::focusWindowChanged(QWindow *focusWindow)
{
- Q_UNUSED(focusWindow);
-
qImDebug() << "new focus window =" << focusWindow;
reset();
+ if (isQtApplication()) {
+ [m_keyboardHideGesture.view removeGestureRecognizer:m_keyboardHideGesture];
+ [focusView().window addGestureRecognizer:m_keyboardHideGesture];
+ }
+
// The keyboard rectangle depend on the focus window, so
// we need to re-evaluate the keyboard state.
updateKeyboardState();
diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h
index 3de1fb4c57..2c7d33cc94 100644
--- a/src/plugins/platforms/ios/qiosintegration.h
+++ b/src/plugins/platforms/ios/qiosintegration.h
@@ -11,7 +11,8 @@
#include <QtCore/private/qfactoryloader_p.h>
#include "qiosapplicationstate.h"
-#ifndef Q_OS_TVOS
+
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
#include "qiostextinputoverlay.h"
#endif
@@ -31,6 +32,7 @@ public:
bool hasCapability(Capability cap) const override;
QPlatformWindow *createPlatformWindow(QWindow *window) const override;
+ QPlatformWindow *createForeignWindow(QWindow *window, WId nativeHandle) const override;
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
#if QT_CONFIG(opengl)
@@ -40,9 +42,11 @@ public:
QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override;
QPlatformFontDatabase *fontDatabase() const override;
-#ifndef QT_NO_CLIPBOARD
+
+#if QT_CONFIG(clipboard)
QPlatformClipboard *clipboard() const override;
#endif
+
QPlatformInputContext *inputContext() const override;
QPlatformServices *services() const override;
@@ -75,7 +79,7 @@ public:
private:
QPlatformFontDatabase *m_fontDatabase;
-#ifndef Q_OS_TVOS
+#if QT_CONFIG(clipboard)
QPlatformClipboard *m_clipboard;
#endif
QPlatformInputContext *m_inputContext;
@@ -83,7 +87,7 @@ private:
QIOSServices *m_platformServices;
mutable QPlatformAccessibility *m_accessibility;
QFactoryLoader *m_optionalPlugins;
-#ifndef Q_OS_TVOS
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
QIOSTextInputOverlay m_textInputOverlay;
#endif
};
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index 27d0f7f2ba..7cd21f83f6 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -1,13 +1,15 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
+
#include "qiosintegration.h"
#include "qioseventdispatcher.h"
#include "qiosglobal.h"
#include "qioswindow.h"
#include "qiosscreen.h"
#include "qiosplatformaccessibility.h"
-#ifndef Q_OS_TVOS
+#if QT_CONFIG(clipboard)
#include "qiosclipboard.h"
#endif
#include "qiosinputcontext.h"
@@ -49,7 +51,7 @@ QIOSIntegration *QIOSIntegration::instance()
QIOSIntegration::QIOSIntegration()
: m_fontDatabase(new QCoreTextFontDatabaseEngineFactory<QCoreTextFontEngine>)
-#if !defined(Q_OS_TVOS) && !defined(QT_NO_CLIPBOARD)
+#if QT_CONFIG(clipboard)
, m_clipboard(new QIOSClipboard)
#endif
, m_inputContext(0)
@@ -70,6 +72,10 @@ QIOSIntegration::QIOSIntegration()
void QIOSIntegration::initialize()
{
+#if defined(Q_OS_VISIONOS)
+ // Qt requires a screen, so let's give it a dummy one
+ QWindowSystemInterface::handleScreenAdded(new QIOSScreen);
+#else
UIScreen *mainScreen = [UIScreen mainScreen];
NSMutableArray<UIScreen *> *screens = [[[UIScreen screens] mutableCopy] autorelease];
if (![screens containsObject:mainScreen]) {
@@ -79,6 +85,7 @@ void QIOSIntegration::initialize()
for (UIScreen *screen in screens)
QWindowSystemInterface::handleScreenAdded(new QIOSScreen(screen));
+#endif
// Depends on a primary screen being present
m_inputContext = new QIOSInputContext;
@@ -86,8 +93,10 @@ void QIOSIntegration::initialize()
m_touchDevice = new QPointingDevice;
m_touchDevice->setType(QInputDevice::DeviceType::TouchScreen);
QPointingDevice::Capabilities touchCapabilities = QPointingDevice::Capability::Position | QPointingDevice::Capability::NormalizedPosition;
+#if !defined(Q_OS_VISIONOS)
if (mainScreen.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable)
touchCapabilities |= QPointingDevice::Capability::Pressure;
+#endif
m_touchDevice->setCapabilities(touchCapabilities);
QWindowSystemInterface::registerInputDevice(m_touchDevice);
#if QT_CONFIG(tabletevent)
@@ -105,7 +114,7 @@ QIOSIntegration::~QIOSIntegration()
delete m_fontDatabase;
m_fontDatabase = 0;
-#if !defined(Q_OS_TVOS) && !defined(QT_NO_CLIPBOARD)
+#if QT_CONFIG(clipboard)
delete m_clipboard;
m_clipboard = 0;
#endif
@@ -148,6 +157,8 @@ bool QIOSIntegration::hasCapability(Capability cap) const
return false;
case ApplicationState:
return true;
+ case ForeignWindows:
+ return true;
default:
return QPlatformIntegration::hasCapability(cap);
}
@@ -158,6 +169,11 @@ QPlatformWindow *QIOSIntegration::createPlatformWindow(QWindow *window) const
return new QIOSWindow(window);
}
+QPlatformWindow *QIOSIntegration::createForeignWindow(QWindow *window, WId nativeHandle) const
+{
+ return new QIOSWindow(window, nativeHandle);
+}
+
QPlatformBackingStore *QIOSIntegration::createPlatformBackingStore(QWindow *window) const
{
return new QRhiBackingStore(window);
@@ -199,14 +215,10 @@ QPlatformFontDatabase * QIOSIntegration::fontDatabase() const
return m_fontDatabase;
}
-#ifndef QT_NO_CLIPBOARD
+#if QT_CONFIG(clipboard)
QPlatformClipboard *QIOSIntegration::clipboard() const
{
-#ifndef Q_OS_TVOS
return m_clipboard;
-#else
- return QPlatformIntegration::clipboard();
-#endif
}
#endif
diff --git a/src/plugins/platforms/ios/qiosmenu.h b/src/plugins/platforms/ios/qiosmenu.h
index 1822c08b1a..b0c8e7e10c 100644
--- a/src/plugins/platforms/ios/qiosmenu.h
+++ b/src/plugins/platforms/ios/qiosmenu.h
@@ -11,6 +11,8 @@
#import "quiview.h"
+#include <QtCore/qpointer.h>
+
class QIOSMenu;
@class QUIMenuController;
@class QUIPickerView;
diff --git a/src/plugins/platforms/ios/qiosmenu.mm b/src/plugins/platforms/ios/qiosmenu.mm
index 5c9bbc276f..227ad2c7f5 100644
--- a/src/plugins/platforms/ios/qiosmenu.mm
+++ b/src/plugins/platforms/ios/qiosmenu.mm
@@ -491,7 +491,7 @@ QIOSMenuItemList QIOSMenu::filterFirstResponderActions(const QIOSMenuItemList &m
// In case of QIOSTextResponder, edit actions will be converted to key events that ends up
// triggering the shortcuts of the filtered menu items.
QIOSMenuItemList filteredMenuItems;
- UIResponder *responder = [UIResponder currentFirstResponder];
+ UIResponder *responder = [UIResponder qt_currentFirstResponder];
for (int i = 0; i < menuItems.count(); ++i) {
QIOSMenuItem *menuItem = menuItems.at(i);
diff --git a/src/plugins/platforms/ios/qiosmessagedialog.mm b/src/plugins/platforms/ios/qiosmessagedialog.mm
index b95cfada60..7fbd5d8729 100644
--- a/src/plugins/platforms/ios/qiosmessagedialog.mm
+++ b/src/plugins/platforms/ios/qiosmessagedialog.mm
@@ -30,7 +30,7 @@ inline QString QIOSMessageDialog::messageTextPlain()
{
// Concatenate text fragments, and remove HTML tags
const QSharedPointer<QMessageDialogOptions> &opt = options();
- const QString &lineShift = QStringLiteral("\n\n");
+ constexpr auto lineShift = "\n\n"_L1;
const QString &informativeText = opt->informativeText();
const QString &detailedText = opt->detailedText();
@@ -40,7 +40,7 @@ inline QString QIOSMessageDialog::messageTextPlain()
if (!detailedText.isEmpty())
text += lineShift + detailedText;
- text.replace("<p>"_L1, QStringLiteral("\n"), Qt::CaseInsensitive);
+ text.replace("<p>"_L1, "\n"_L1, Qt::CaseInsensitive);
text.remove(QRegularExpression(QStringLiteral("<[^>]*>")));
return text;
@@ -116,26 +116,18 @@ bool QIOSMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality win
[m_alertController addAction:createAction(NoButton)];
}
- UIWindow *window = parent ? reinterpret_cast<UIView *>(parent->winId()).window : qt_apple_sharedApplication().keyWindow;
- if (!window) {
- qCDebug(lcQpaWindow, "Attempting to exec a dialog without any window/widget visible.");
-
- auto *primaryScreen = static_cast<QIOSScreen*>(QGuiApplication::primaryScreen()->handle());
- Q_ASSERT(primaryScreen);
-
- window = primaryScreen->uiWindow();
- if (window.hidden) {
- // With a window hidden, an attempt to present view controller
- // below fails with a warning, that a view "is not a part of
- // any view hierarchy". The UIWindow is initially hidden,
- // as unhiding it is what hides the splash screen.
- window.hidden = NO;
- }
- }
-
+ UIWindow *window = presentationWindow(parent);
if (!window)
return false;
+ if (window.hidden) {
+ // With a window hidden, an attempt to present view controller
+ // below fails with a warning, that a view "is not a part of
+ // any view hierarchy". The UIWindow is initially hidden,
+ // as unhiding it is what hides the splash screen.
+ window.hidden = NO;
+ }
+
[window.rootViewController presentViewController:m_alertController animated:YES completion:nil];
return true;
}
diff --git a/src/plugins/platforms/ios/qiosplatformaccessibility.mm b/src/plugins/platforms/ios/qiosplatformaccessibility.mm
index d54b7db57a..eb18ee637e 100644
--- a/src/plugins/platforms/ios/qiosplatformaccessibility.mm
+++ b/src/plugins/platforms/ios/qiosplatformaccessibility.mm
@@ -1,12 +1,15 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
+
#include "qiosplatformaccessibility.h"
#if QT_CONFIG(accessibility)
#include <QtGui/QtGui>
#include "qioswindow.h"
+#include "quiaccessibilityelement.h"
QIOSPlatformAccessibility::QIOSPlatformAccessibility()
{}
@@ -25,8 +28,6 @@ void invalidateCache(QAccessibleInterface *iface)
// This will invalidate everything regardless of what window the
// interface belonged to. We might want to revisit this strategy later.
// (Therefore this function still takes the interface as argument)
- // It is also responsible for the bug that focus gets temporary lost
- // when items get added or removed from the screen
foreach (QWindow *win, QGuiApplication::topLevelWindows()) {
if (win && win->handle()) {
QT_PREPEND_NAMESPACE(QIOSWindow) *window = static_cast<QT_PREPEND_NAMESPACE(QIOSWindow) *>(win->handle());
@@ -38,14 +39,35 @@ void invalidateCache(QAccessibleInterface *iface)
void QIOSPlatformAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
{
- if (!isActive() || !event->accessibleInterface())
+ auto *accessibleInterface = event->accessibleInterface();
+ if (!isActive() || !accessibleInterface)
return;
switch (event->type()) {
+ case QAccessible::Focus: {
+ auto *element = [QMacAccessibilityElement elementWithId:event->uniqueId()];
+ Q_ASSERT(element);
+ // There's no NSAccessibilityFocusedUIElementChangedNotification, like we have on
+ // macOS. Instead, the documentation for UIAccessibilityLayoutChangedNotification
+ // specifies that the optional argument to UIAccessibilityPostNotification is the
+ // accessibility element for VoiceOver to move to after processing the notification.
+ UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, element);
+ break;
+ }
case QAccessible::ObjectCreated:
case QAccessible::ObjectShow:
case QAccessible::ObjectHide:
case QAccessible::ObjectDestroyed:
- invalidateCache(event->accessibleInterface());
+ invalidateCache(accessibleInterface);
+ switch (accessibleInterface->role()) {
+ case QAccessible::Window:
+ case QAccessible::Dialog:
+ // Bigger changes to the UI require a full reset of VoiceOver
+ UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
+ break;
+ default:
+ // While smaller changes can be handled by re-reading the layout
+ UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
+ }
break;
default:
break;
diff --git a/src/plugins/platforms/ios/qiosscreen.h b/src/plugins/platforms/ios/qiosscreen.h
index 21afb90c55..dd69428390 100644
--- a/src/plugins/platforms/ios/qiosscreen.h
+++ b/src/plugins/platforms/ios/qiosscreen.h
@@ -10,10 +10,6 @@
@class QIOSOrientationListener;
-@interface QUIWindow : UIWindow
-@property (nonatomic, readonly) BOOL sendingEvent;
-@end
-
QT_BEGIN_NAMESPACE
class QIOSScreen : public QObject, public QPlatformScreen
@@ -21,7 +17,11 @@ class QIOSScreen : public QObject, public QPlatformScreen
Q_OBJECT
public:
+#if !defined(Q_OS_VISIONOS)
QIOSScreen(UIScreen *screen);
+#else
+ QIOSScreen();
+#endif
~QIOSScreen();
QString name() const override;
@@ -40,8 +40,9 @@ public:
QPixmap grabWindow(WId window, int x, int y, int width, int height) const override;
+#if !defined(Q_OS_VISIONOS)
UIScreen *uiScreen() const;
- UIWindow *uiWindow() const;
+#endif
void setUpdatesPaused(bool);
@@ -50,15 +51,17 @@ public:
private:
void deliverUpdateRequests() const;
- UIScreen *m_uiScreen;
- UIWindow *m_uiWindow;
+#if !defined(Q_OS_VISIONOS)
+ UIScreen *m_uiScreen = nullptr;
+#endif
QRect m_geometry;
QRect m_availableGeometry;
int m_depth;
+#if !defined(Q_OS_VISIONOS)
uint m_physicalDpi;
+#endif
QSizeF m_physicalSize;
- QIOSOrientationListener *m_orientationListener;
- CADisplayLink *m_displayLink;
+ CADisplayLink *m_displayLink = nullptr;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm
index e968cafe1d..7559979f33 100644
--- a/src/plugins/platforms/ios/qiosscreen.mm
+++ b/src/plugins/platforms/ios/qiosscreen.mm
@@ -1,6 +1,8 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
+
#include "qiosglobal.h"
#include "qiosintegration.h"
#include "qiosscreen.h"
@@ -10,6 +12,7 @@
#include "qiosviewcontroller.h"
#include "quiview.h"
#include "qiostheme.h"
+#include "quiwindow.h"
#include <QtCore/private/qcore_mac_p.h>
@@ -44,6 +47,7 @@ typedef void (^DisplayLinkBlock)(CADisplayLink *displayLink);
// -------------------------------------------------------------------------
+#if !defined(Q_OS_VISIONOS)
static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
{
foreach (QScreen *screen, QGuiApplication::screens()) {
@@ -81,6 +85,9 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
+ (void)screenDisconnected:(NSNotification*)notification
{
+ if (!QIOSIntegration::instance())
+ return;
+
QIOSScreen *screen = qtPlatformScreenFor([notification object]);
Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen disconnected that we didn't know about");
@@ -89,6 +96,9 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
+ (void)screenModeChanged:(NSNotification*)notification
{
+ if (!QIOSIntegration::instance())
+ return;
+
QIOSScreen *screen = qtPlatformScreenFor([notification object]);
Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen changed that we didn't know about");
@@ -97,104 +107,7 @@ static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
@end
-// -------------------------------------------------------------------------
-
-@interface QIOSOrientationListener : NSObject
-@end
-
-@implementation QIOSOrientationListener {
- QIOSScreen *m_screen;
-}
-
-- (instancetype)initWithQIOSScreen:(QIOSScreen *)screen
-{
- self = [super init];
- if (self) {
- m_screen = screen;
-#ifndef Q_OS_TVOS
- [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
- [[NSNotificationCenter defaultCenter]
- addObserver:self
- selector:@selector(orientationChanged:)
- name:@"UIDeviceOrientationDidChangeNotification" object:nil];
-#endif
- }
- return self;
-}
-
-- (void)dealloc
-{
-#ifndef Q_OS_TVOS
- [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
- [[NSNotificationCenter defaultCenter]
- removeObserver:self
- name:@"UIDeviceOrientationDidChangeNotification" object:nil];
-#endif
- [super dealloc];
-}
-
-- (void)orientationChanged:(NSNotification *)notification
-{
- Q_UNUSED(notification);
- m_screen->updateProperties();
-}
-
-@end
-
-@interface UIScreen (Compatibility)
-@property (nonatomic, readonly) CGRect qt_applicationFrame;
-@end
-
-@implementation UIScreen (Compatibility)
-- (CGRect)qt_applicationFrame
-{
-#ifdef Q_OS_IOS
- return self.applicationFrame;
-#else
- return self.bounds;
-#endif
-}
-@end
-
-// -------------------------------------------------------------------------
-
-@implementation QUIWindow
-
-- (instancetype)initWithFrame:(CGRect)frame
-{
- if ((self = [super initWithFrame:frame]))
- self->_sendingEvent = NO;
-
- return self;
-}
-
-- (void)sendEvent:(UIEvent *)event
-{
- QScopedValueRollback<BOOL> sendingEvent(self->_sendingEvent, YES);
- [super sendEvent:event];
-}
-
-- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
-{
- [super traitCollectionDidChange:previousTraitCollection];
-
- Qt::ColorScheme colorScheme = self.traitCollection.userInterfaceStyle
- == UIUserInterfaceStyleDark
- ? Qt::ColorScheme::Dark
- : Qt::ColorScheme::Light;
-
- if (self.screen == UIScreen.mainScreen) {
- // Check if the current userInterfaceStyle reports a different appearance than
- // the platformTheme's appearance. We might have set that one based on the UIScreen
- if (previousTraitCollection.userInterfaceStyle != self.traitCollection.userInterfaceStyle
- || QGuiApplicationPrivate::platformTheme()->colorScheme() != colorScheme) {
- QIOSTheme::initializeSystemPalette();
- QWindowSystemInterface::handleThemeChange<QWindowSystemInterface::SynchronousDelivery>();
- }
- }
-}
-
-@end
+#endif // !defined(Q_OS_VISIONOS)
// -------------------------------------------------------------------------
@@ -202,6 +115,7 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
+#if !defined(Q_OS_VISIONOS)
/*!
Returns the model identifier of the device.
*/
@@ -221,12 +135,14 @@ static QString deviceModelIdentifier()
return QString::fromLatin1(QByteArrayView(value, qsizetype(size)));
#endif
}
+#endif // !defined(Q_OS_VISIONOS)
+#if defined(Q_OS_VISIONOS)
+QIOSScreen::QIOSScreen()
+{
+#else
QIOSScreen::QIOSScreen(UIScreen *screen)
- : QPlatformScreen()
- , m_uiScreen(screen)
- , m_uiWindow(0)
- , m_orientationListener(0)
+ : m_uiScreen(screen)
{
QString deviceIdentifier = deviceModelIdentifier();
@@ -260,44 +176,30 @@ QIOSScreen::QIOSScreen(UIScreen *screen)
m_physicalDpi = 96;
}
- if (!qt_apple_isApplicationExtension()) {
- for (UIWindow *existingWindow in qt_apple_sharedApplication().windows) {
- if (existingWindow.screen == m_uiScreen) {
- m_uiWindow = [existingWindow retain];
- break;
- }
- }
-
- if (!m_uiWindow) {
- // Create a window and associated view-controller that we can use
- m_uiWindow = [[QUIWindow alloc] initWithFrame:[m_uiScreen bounds]];
- m_uiWindow.rootViewController = [[[QIOSViewController alloc] initWithQIOSScreen:this] autorelease];
- }
- }
-
- m_orientationListener = [[QIOSOrientationListener alloc] initWithQIOSScreen:this];
-
- updateProperties();
-
m_displayLink = [m_uiScreen displayLinkWithBlock:^(CADisplayLink *) { deliverUpdateRequests(); }];
m_displayLink.paused = YES; // Enabled when clients call QWindow::requestUpdate()
[m_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
+
+#endif // !defined(Q_OS_VISIONOS))
+
+ updateProperties();
}
QIOSScreen::~QIOSScreen()
{
[m_displayLink invalidate];
-
- [m_orientationListener release];
- [m_uiWindow release];
}
QString QIOSScreen::name() const
{
+#if defined(Q_OS_VISIONOS)
+ return {};
+#else
if (m_uiScreen == [UIScreen mainScreen])
return QString::fromNSString([UIDevice currentDevice].model) + " built-in display"_L1;
else
return "External display"_L1;
+#endif
}
void QIOSScreen::updateProperties()
@@ -305,42 +207,13 @@ void QIOSScreen::updateProperties()
QRect previousGeometry = m_geometry;
QRect previousAvailableGeometry = m_availableGeometry;
+#if defined(Q_OS_VISIONOS)
+ // Based on what iPad app reports
+ m_geometry = QRect(0, 0, 1194, 834);
+ m_depth = 24;
+#else
m_geometry = QRectF::fromCGRect(m_uiScreen.bounds).toRect();
- // The application frame doesn't take safe area insets into account, and
- // the safe area insets are not available before the UIWindow is shown,
- // and do not take split-view constraints into account, so we have to
- // combine the two to get the correct available geometry.
- QRect applicationFrame = QRectF::fromCGRect(m_uiScreen.qt_applicationFrame).toRect();
- UIEdgeInsets safeAreaInsets = m_uiWindow.qt_safeAreaInsets;
- m_availableGeometry = m_geometry.adjusted(safeAreaInsets.left, safeAreaInsets.top,
- -safeAreaInsets.right, -safeAreaInsets.bottom).intersected(applicationFrame);
-
-#ifndef Q_OS_TVOS
- if (m_uiScreen == [UIScreen mainScreen]) {
- QIOSViewController *qtViewController = [m_uiWindow.rootViewController isKindOfClass:[QIOSViewController class]] ?
- static_cast<QIOSViewController *>(m_uiWindow.rootViewController) : nil;
-
- if (qtViewController.lockedOrientation) {
- Q_ASSERT(!qt_apple_isApplicationExtension());
-
- // Setting the statusbar orientation (content orientation) on will affect the screen geometry,
- // which is not what we want. We want to reflect the screen geometry based on the locked orientation,
- // and adjust the available geometry based on the repositioned status bar for the current status
- // bar orientation.
-
- Qt::ScreenOrientation statusBarOrientation = toQtScreenOrientation(
- UIDeviceOrientation(qt_apple_sharedApplication().statusBarOrientation));
-
- Qt::ScreenOrientation lockedOrientation = toQtScreenOrientation(UIDeviceOrientation(qtViewController.lockedOrientation));
- QTransform transform = transformBetween(lockedOrientation, statusBarOrientation, m_geometry).inverted();
-
- m_geometry = transform.mapRect(m_geometry);
- m_availableGeometry = transform.mapRect(m_availableGeometry);
- }
- }
-#endif
-
if (m_geometry != previousGeometry) {
// 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() ?
@@ -356,6 +229,14 @@ void QIOSScreen::updateProperties()
m_physicalSize = physicalGeometry.size() / m_physicalDpi * millimetersPerInch;
}
+#endif // defined(Q_OS_VISIONOS)
+
+ // UIScreen does not provide a consistent accessor for the safe area margins
+ // of the screen, and on visionOS we won't even have a UIScreen, so we report
+ // the available geometry of the screen to be the same as the full geometry.
+ // Safe area margins and maximized state is handled in QIOSWindow::setWindowState.
+ m_availableGeometry = m_geometry;
+
// At construction time, we don't yet have an associated QScreen, but we still want
// to compute the properties above so they are ready for when the QScreen attaches.
// Also, at destruction time the QScreen has already been torn down, so notifying
@@ -440,16 +321,28 @@ QDpi QIOSScreen::logicalBaseDpi() const
qreal QIOSScreen::devicePixelRatio() const
{
+#if defined(Q_OS_VISIONOS)
+ return 2.0; // Based on what iPad app reports
+#else
return [m_uiScreen scale];
+#endif
}
qreal QIOSScreen::refreshRate() const
{
+#if defined(Q_OS_VISIONOS)
+ return 120.0; // Based on what iPad app reports
+#else
return m_uiScreen.maximumFramesPerSecond;
+#endif
}
Qt::ScreenOrientation QIOSScreen::nativeOrientation() const
{
+#if defined(Q_OS_VISIONOS)
+ // Based on iPad app reporting native bounds 1668x2388
+ return Qt::PortraitOrientation;
+#else
CGRect nativeBounds =
#if defined(Q_OS_IOS)
m_uiScreen.nativeBounds;
@@ -461,38 +354,18 @@ Qt::ScreenOrientation QIOSScreen::nativeOrientation() const
// be on the safe side we compare the width and height of the bounds.
return nativeBounds.size.width >= nativeBounds.size.height ?
Qt::LandscapeOrientation : Qt::PortraitOrientation;
+#endif
}
Qt::ScreenOrientation QIOSScreen::orientation() const
{
-#ifdef Q_OS_TVOS
- return Qt::PrimaryOrientation;
-#else
- // Auxiliary screens are always the same orientation as their primary orientation
- if (m_uiScreen != [UIScreen mainScreen])
- return Qt::PrimaryOrientation;
-
- UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
-
- // At startup, iOS will report an unknown orientation for the device, even
- // if we've asked it to begin generating device orientation notifications.
- // In this case we fall back to the status bar orientation, which reflects
- // the orientation the application was started up in (which may not match
- // the physical orientation of the device, but typically does unless the
- // application has been locked to a subset of the available orientations).
- if (deviceOrientation == UIDeviceOrientationUnknown && !qt_apple_isApplicationExtension())
- deviceOrientation = UIDeviceOrientation(qt_apple_sharedApplication().statusBarOrientation);
-
- // If the device reports face up or face down orientations, we can't map
- // them to Qt orientations, so we pretend we're in the same orientation
- // as before.
- if (deviceOrientation == UIDeviceOrientationFaceUp || deviceOrientation == UIDeviceOrientationFaceDown) {
- Q_ASSERT(screen());
- return screen()->orientation();
- }
-
- return toQtScreenOrientation(deviceOrientation);
-#endif
+ // We don't report UIDevice.currentDevice.orientation here,
+ // as that would report the actual orientation of the device,
+ // even if the orientation of the UI was locked to a subset
+ // of the possible orientations via the app's Info.plist or
+ // via [UIViewController supportedInterfaceOrientations].
+ return m_geometry.width() >= m_geometry.height() ?
+ Qt::LandscapeOrientation : Qt::PortraitOrientation;
}
QPixmap QIOSScreen::grabWindow(WId window, int x, int y, int width, int height) const
@@ -500,26 +373,27 @@ QPixmap QIOSScreen::grabWindow(WId window, int x, int y, int width, int height)
if (window && ![reinterpret_cast<id>(window) isKindOfClass:[UIView class]])
return QPixmap();
- UIView *view = window ? reinterpret_cast<UIView *>(window) : m_uiWindow;
+ UIView *view = window ? reinterpret_cast<UIView *>(window)
+ : rootViewForScreen(screen());
if (width < 0)
width = qMax(view.bounds.size.width - x, CGFloat(0));
if (height < 0)
height = qMax(view.bounds.size.height - y, CGFloat(0));
- CGRect captureRect = [m_uiWindow convertRect:CGRectMake(x, y, width, height) fromView:view];
- captureRect = CGRectIntersection(captureRect, m_uiWindow.bounds);
+ CGRect captureRect = [view.window convertRect:CGRectMake(x, y, width, height) fromView:view];
+ captureRect = CGRectIntersection(captureRect, view.window.bounds);
UIGraphicsBeginImageContextWithOptions(captureRect.size, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, -captureRect.origin.x, -captureRect.origin.y);
- // Draws the complete view hierarchy of m_uiWindow into the given rect, which
- // needs to be the same aspect ratio as the m_uiWindow's size. Since we've
+ // Draws the complete view hierarchy of view.window into the given rect, which
+ // needs to be the same aspect ratio as the view.window's size. Since we've
// translated the graphics context, and are potentially drawing into a smaller
// context than the full window, the resulting image will be a subsection of the
// full screen.
- [m_uiWindow drawViewHierarchyInRect:m_uiWindow.bounds afterScreenUpdates:NO];
+ [view.window drawViewHierarchyInRect:view.window.bounds afterScreenUpdates:NO];
UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
@@ -527,15 +401,12 @@ QPixmap QIOSScreen::grabWindow(WId window, int x, int y, int width, int height)
return QPixmap::fromImage(qt_mac_toQImage(screenshot.CGImage));
}
+#if !defined(Q_OS_VISIONOS)
UIScreen *QIOSScreen::uiScreen() const
{
return m_uiScreen;
}
-
-UIWindow *QIOSScreen::uiWindow() const
-{
- return m_uiWindow;
-}
+#endif
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiostextinputoverlay.mm b/src/plugins/platforms/ios/qiostextinputoverlay.mm
index 512ab77bd2..01046334a1 100644
--- a/src/plugins/platforms/ios/qiostextinputoverlay.mm
+++ b/src/plugins/platforms/ios/qiostextinputoverlay.mm
@@ -947,7 +947,17 @@ static void executeBlockWithoutAnimation(Block block)
int cursorPosOnRelease = QPlatformInputContext::queryFocusObject(Qt::ImCursorPosition, touchPos).toInt();
if (cursorPosOnRelease == _cursorPosOnPress) {
+ // We've recognized a gesture to open the menu, but we don't know
+ // whether the user tapped a control that was overlaid our input
+ // area, since we don't do any granular hit-testing in touchesBegan.
+ // To ensure that the gesture doesn't eat touch events that should
+ // have reached another UI control we report the gesture as failed
+ // here, and then manually show the menu at the next runloop pass.
_menuShouldBeVisible = true;
+ self.state = UIGestureRecognizerStateFailed;
+ dispatch_async(dispatch_get_main_queue(), ^{
+ QIOSTextInputOverlay::s_editMenu.visible = _menuShouldBeVisible;
+ });
} else {
// The menu is hidden, and the cursor will change position once
// Qt receive the touch release. We therefore fail so that we
@@ -996,19 +1006,26 @@ QIOSTextInputOverlay::~QIOSTextInputOverlay()
void QIOSTextInputOverlay::updateFocusObject()
{
+ // Destroy old recognizers since they were created with
+ // dependencies to the old focus object (focus view).
if (m_cursorRecognizer) {
- // Destroy old recognizers since they were created with
- // dependencies to the old focus object (focus view).
m_cursorRecognizer.enabled = NO;
- m_selectionRecognizer.enabled = NO;
- m_openMenuOnTapRecognizer.enabled = NO;
[m_cursorRecognizer release];
- [m_selectionRecognizer release];
- [m_openMenuOnTapRecognizer release];
- [s_editMenu release];
m_cursorRecognizer = nullptr;
+ }
+ if (m_selectionRecognizer) {
+ m_selectionRecognizer.enabled = NO;
+ [m_selectionRecognizer release];
m_selectionRecognizer = nullptr;
+ }
+ if (m_openMenuOnTapRecognizer) {
+ m_openMenuOnTapRecognizer.enabled = NO;
+ [m_openMenuOnTapRecognizer release];
m_openMenuOnTapRecognizer = nullptr;
+ }
+
+ if (s_editMenu) {
+ [s_editMenu release];
s_editMenu = nullptr;
}
diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm
index f8bcf7fb25..5231a3adde 100644
--- a/src/plugins/platforms/ios/qiostextresponder.mm
+++ b/src/plugins/platforms/ios/qiostextresponder.mm
@@ -164,7 +164,7 @@
{
FirstResponderCandidate firstResponderCandidate(self);
- qImDebug() << "self:" << self << "first:" << [UIResponder currentFirstResponder];
+ qImDebug() << "self:" << self << "first:" << [UIResponder qt_currentFirstResponder];
if (![super becomeFirstResponder]) {
qImDebug() << self << "was not allowed to become first responder";
@@ -178,7 +178,7 @@
- (BOOL)resignFirstResponder
{
- qImDebug() << "self:" << self << "first:" << [UIResponder currentFirstResponder];
+ qImDebug() << "self:" << self << "first:" << [UIResponder qt_currentFirstResponder];
// Don't allow activation events of the window that we're doing text on behalf on
// to steal responder.
@@ -196,11 +196,11 @@
// a regular responder transfer to another window. In the former case, iOS
// will set the new first-responder to our next-responder, and in the latter
// case we'll have an active responder candidate.
- if (![UIResponder currentFirstResponder] && !FirstResponderCandidate::currentCandidate()) {
+ if (![UIResponder qt_currentFirstResponder] && !FirstResponderCandidate::currentCandidate()) {
// No first responder set anymore, sync this with Qt by clearing the
// focus object.
m_inputContext->clearCurrentFocusObject();
- } else if ([UIResponder currentFirstResponder] == [self nextResponder]) {
+ } else if ([UIResponder qt_currentFirstResponder] == [self nextResponder]) {
// We have resigned the keyboard, and transferred first responder back to the parent view
Q_ASSERT(!FirstResponderCandidate::currentCandidate());
if ([self currentImeState:Qt::ImEnabled].toBool()) {
@@ -222,8 +222,12 @@
- (UIResponder*)nextResponder
{
- return qApp->focusWindow() ?
- reinterpret_cast<QUIView *>(qApp->focusWindow()->handle()->winId()) : 0;
+ // Make sure we have a handle/platform window before getting the winId().
+ // In the dtor of QIOSWindow the platform window is set to null before calling
+ // removeFromSuperview which will end up calling nextResponder. That means it's
+ // possible that we can get here while the window is being torn down.
+ return (qApp->focusWindow() && qApp->focusWindow()->handle()) ?
+ reinterpret_cast<QUIView *>(qApp->focusWindow()->handle()->winId()) : 0;
}
// -------------------------------------------------------------------------
@@ -397,7 +401,7 @@
if (UIView *accessoryView = static_cast<UIView *>(platformData.value(kImePlatformDataInputAccessoryView).value<void *>()))
self.inputAccessoryView = [[[WrapperView alloc] initWithView:accessoryView] autorelease];
-#ifndef Q_OS_TVOS
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
if (platformData.value(kImePlatformDataHideShortcutsBar).toBool()) {
// According to the docs, leadingBarButtonGroups/trailingBarButtonGroups should be set to nil to hide the shortcuts bar.
// However, starting with iOS 10, the API has been surrounded with NS_ASSUME_NONNULL, which contradicts this and causes
@@ -898,7 +902,7 @@
QInputMethodEvent e(m_markedText, attrs);
[self sendEventToFocusObject:e];
}
- QRectF startRect = QPlatformInputContext::cursorRectangle();;
+ QRectF startRect = QPlatformInputContext::cursorRectangle();
attrs = QList<QInputMethodEvent::Attribute>();
attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, r.location + r.length, 0, 0);
@@ -906,7 +910,7 @@
QInputMethodEvent e(m_markedText, attrs);
[self sendEventToFocusObject:e];
}
- QRectF endRect = QPlatformInputContext::cursorRectangle();;
+ QRectF endRect = QPlatformInputContext::cursorRectangle();
if (cursorPos != int(r.location + r.length) || cursorPos != anchorPos) {
attrs = QList<QInputMethodEvent::Attribute>();
diff --git a/src/plugins/platforms/ios/qiostheme.h b/src/plugins/platforms/ios/qiostheme.h
index 9aa2ebaf82..f0a404a61a 100644
--- a/src/plugins/platforms/ios/qiostheme.h
+++ b/src/plugins/platforms/ios/qiostheme.h
@@ -23,13 +23,16 @@ public:
Qt::ColorScheme colorScheme() const override;
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
QPlatformMenuItem* createPlatformMenuItem() const override;
QPlatformMenu* createPlatformMenu() const override;
+#endif
bool usePlatformNativeDialog(DialogType type) const override;
QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const override;
const QFont *font(Font type = SystemFont) const override;
+ QIconEngine *createIconEngine(const QString &iconName) const override;
static const char *name;
diff --git a/src/plugins/platforms/ios/qiostheme.mm b/src/plugins/platforms/ios/qiostheme.mm
index d1356ab8f7..3853de9cf1 100644
--- a/src/plugins/platforms/ios/qiostheme.mm
+++ b/src/plugins/platforms/ios/qiostheme.mm
@@ -11,18 +11,24 @@
#include <QtGui/private/qcoregraphics_p.h>
#include <QtGui/private/qcoretextfontdatabase_p.h>
+#include <QtGui/private/qappleiconengine_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
#include <UIKit/UIFont.h>
#include <UIKit/UIInterface.h>
-#ifndef Q_OS_TVOS
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
#include "qiosmenu.h"
+#endif
+
+#if !defined(Q_OS_TVOS)
#include "qiosfiledialog.h"
-#include "qiosmessagedialog.h"
#include "qioscolordialog.h"
#include "qiosfontdialog.h"
+#include "qiosmessagedialog.h"
+#include "qiosscreen.h"
+#include "quiwindow.h"
#endif
QT_BEGIN_NAMESPACE
@@ -68,6 +74,9 @@ void QIOSTheme::initializeSystemPalette()
s_systemPalette.setBrush(QPalette::Highlight, QColor(11, 70, 150, 60));
s_systemPalette.setBrush(QPalette::HighlightedText, qt_mac_toQBrush(UIColor.labelColor.CGColor));
+
+ if (@available(ios 15.0, *))
+ s_systemPalette.setBrush(QPalette::Accent, qt_mac_toQBrush(UIColor.tintColor.CGColor));
}
const QPalette *QIOSTheme::palette(QPlatformTheme::Palette type) const
@@ -77,23 +86,17 @@ const QPalette *QIOSTheme::palette(QPlatformTheme::Palette type) const
return 0;
}
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
QPlatformMenuItem* QIOSTheme::createPlatformMenuItem() const
{
-#ifdef Q_OS_TVOS
- return 0;
-#else
- return new QIOSMenuItem();
-#endif
+ return new QIOSMenuItem;
}
QPlatformMenu* QIOSTheme::createPlatformMenu() const
{
-#ifdef Q_OS_TVOS
- return 0;
-#else
- return new QIOSMenu();
-#endif
+ return new QIOSMenu;
}
+#endif
bool QIOSTheme::usePlatformNativeDialog(QPlatformTheme::DialogType type) const
{
@@ -144,17 +147,28 @@ QVariant QIOSTheme::themeHint(ThemeHint hint) const
Qt::ColorScheme QIOSTheme::colorScheme() const
{
- UIUserInterfaceStyle appearance = UIUserInterfaceStyleUnspecified;
- // Set the appearance based on the UIWindow
+#if defined(Q_OS_VISIONOS)
+ // On visionOS the concept of light or dark mode does not
+ // apply, as the UI is constantly changing based on what
+ // the lighting conditions are outside the headset, but
+ // the OS reports itself as always being in dark mode.
+ return Qt::ColorScheme::Dark;
+#else
+ // Set the appearance based on the QUIWindow
// Fallback to the UIScreen if no window is created yet
- if (UIWindow *window = qt_apple_sharedApplication().windows.lastObject) {
- appearance = window.traitCollection.userInterfaceStyle;
- } else {
- appearance = UIScreen.mainScreen.traitCollection.userInterfaceStyle;
+ UIUserInterfaceStyle appearance = UIScreen.mainScreen.traitCollection.userInterfaceStyle;
+ NSArray<UIWindow *> *windows = qt_apple_sharedApplication().windows;
+ for (UIWindow *window in windows) {
+ if ([window isKindOfClass:[QUIWindow class]]) {
+ appearance = static_cast<QUIWindow*>(window).traitCollection.userInterfaceStyle;
+ break;
+ }
}
+
return appearance == UIUserInterfaceStyleDark
? Qt::ColorScheme::Dark
: Qt::ColorScheme::Light;
+#endif
}
const QFont *QIOSTheme::font(Font type) const
@@ -164,4 +178,9 @@ const QFont *QIOSTheme::font(Font type) const
return coreTextFontDatabase->themeFont(type);
}
+QIconEngine *QIOSTheme::createIconEngine(const QString &iconName) const
+{
+ return new QAppleIconEngine(iconName);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.h b/src/plugins/platforms/ios/qiosviewcontroller.h
index 237cd57edf..1f8da41ba4 100644
--- a/src/plugins/platforms/ios/qiosviewcontroller.h
+++ b/src/plugins/platforms/ios/qiosviewcontroller.h
@@ -12,14 +12,12 @@ QT_END_NAMESPACE
@interface QIOSViewController : UIViewController
-- (instancetype)initWithQIOSScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen;
+- (instancetype)initWithWindow:(UIWindow*)window andScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen;
- (void)updateProperties;
- (NSArray*)keyCommands;
- (void)handleShortcut:(UIKeyCommand*)keyCommand;
#ifndef Q_OS_TVOS
-@property (nonatomic, assign) UIInterfaceOrientation lockedOrientation;
-
// UIViewController
@property (nonatomic, assign) BOOL prefersStatusBarHidden;
@property (nonatomic, assign) UIStatusBarAnimation preferredStatusBarUpdateAnimation;
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm
index c4e8968232..436d1e7bed 100644
--- a/src/plugins/platforms/ios/qiosviewcontroller.mm
+++ b/src/plugins/platforms/ios/qiosviewcontroller.mm
@@ -21,9 +21,12 @@
#include "qioswindow.h"
#include "quiview.h"
+#include <QtCore/qpointer.h>
+
// -------------------------------------------------------------------------
@interface QIOSViewController ()
+@property (nonatomic, assign) UIWindow *window;
@property (nonatomic, assign) QPointer<QT_PREPEND_NAMESPACE(QIOSScreen)> platformScreen;
@property (nonatomic, assign) BOOL changingOrientation;
@end
@@ -88,27 +91,30 @@
{
Q_UNUSED(subview);
- QT_PREPEND_NAMESPACE(QIOSScreen) *screen = self.qtViewController.platformScreen;
-
- // The 'window' property of our view is not valid until the window
- // has been shown, so we have to access it through the QIOSScreen.
- UIWindow *uiWindow = screen->uiWindow();
+ // Track UIWindow via explicit property on QIOSViewController,
+ // as the window property of our own view is not valid until
+ // the window has been shown (below).
+ UIWindow *uiWindow = self.qtViewController.window;
if (uiWindow.hidden) {
- // Associate UIWindow to screen and show it the first time a QWindow
- // is mapped to the screen. For external screens this means disabling
- // mirroring mode and presenting alternate content on the screen.
- uiWindow.screen = screen->uiScreen();
+ // Show the UIWindow the first time a QWindow is mapped to the screen.
+ // For the main screen this hides the launch screen, while for external
+ // screens this disables mirroring of the main screen, so the external
+ // screen can be used for alternate content.
uiWindow.hidden = NO;
}
}
+#if !defined(Q_OS_VISIONOS)
- (void)willRemoveSubview:(UIView *)subview
{
Q_UNUSED(subview);
- Q_ASSERT(self.window);
UIWindow *uiWindow = self.window;
+ // uiWindow can be null when closing from the ios "app manager" and the app is
+ // showing a native window like UIDocumentBrowserViewController
+ if (!uiWindow)
+ return;
if (uiWindow.screen != [UIScreen mainScreen] && self.subviews.count == 1) {
// We're about to remove the last view of an external screen, so go back
@@ -116,10 +122,10 @@
// to ensure that we don't try to layout the view that's being removed.
dispatch_async(dispatch_get_main_queue(), ^{
uiWindow.hidden = YES;
- uiWindow.screen = [UIScreen mainScreen];
});
}
}
+#endif
- (void)layoutSubviews
{
@@ -225,15 +231,14 @@
@synthesize preferredStatusBarStyle;
#endif
-- (instancetype)initWithQIOSScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen
+- (instancetype)initWithWindow:(UIWindow*)window andScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen
{
if (self = [self init]) {
+ self.window = window;
self.platformScreen = screen;
self.changingOrientation = NO;
#ifndef Q_OS_TVOS
- self.lockedOrientation = UIInterfaceOrientationUnknown;
-
// Status bar may be initially hidden at startup through Info.plist
self.prefersStatusBarHidden = infoPlistValue(@"UIStatusBarHidden", false);
self.preferredStatusBarUpdateAnimation = UIStatusBarAnimationNone;
@@ -280,7 +285,7 @@
Q_ASSERT(!qt_apple_isApplicationExtension());
-#ifndef Q_OS_TVOS
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(willChangeStatusBarFrame:)
name:UIApplicationWillChangeStatusBarFrameNotification
@@ -290,6 +295,15 @@
name:UIApplicationDidChangeStatusBarOrientationNotification
object:qt_apple_sharedApplication()];
#endif
+
+ // Make sure any top level windows that have already been created
+ // for this screen are reparented into our desktop manager view.
+ for (auto *window : qGuiApp->topLevelWindows()) {
+ if (window->screen()->handle() != self.platformScreen)
+ continue;
+ if (auto *platformWindow = window->handle())
+ platformWindow->setParent(nullptr);
+ }
}
- (void)viewDidUnload
@@ -300,26 +314,6 @@
// -------------------------------------------------------------------------
-- (BOOL)shouldAutorotate
-{
-#ifndef Q_OS_TVOS
- return self.platformScreen && self.platformScreen->uiScreen() == [UIScreen mainScreen] && !self.lockedOrientation;
-#else
- return NO;
-#endif
-}
-
-- (NSUInteger)supportedInterfaceOrientations
-{
- // As documented by Apple in the iOS 6.0 release notes, setStatusBarOrientation:animated:
- // only works if the supportedInterfaceOrientations of the view controller is 0, making
- // us responsible for ensuring that the status bar orientation is consistent. We enter
- // this mode when auto-rotation is disabled due to an explicit content orientation being
- // set on the focus window. Note that this is counter to what the documentation for
- // supportedInterfaceOrientations says, which states that the method should not return 0.
- return [self shouldAutorotate] ? UIInterfaceOrientationMaskAll : 0;
-}
-
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration
{
self.changingOrientation = YES;
@@ -334,6 +328,7 @@
[super didRotateFromInterfaceOrientation:orientation];
}
+#if !defined(Q_OS_VISIONOS)
- (void)willChangeStatusBarFrame:(NSNotification*)notification
{
Q_UNUSED(notification);
@@ -377,6 +372,7 @@
[self.view setNeedsLayout];
}
+#endif
- (void)viewWillLayoutSubviews
{
@@ -397,10 +393,12 @@
if (!self.platformScreen || !self.platformScreen->screen())
return;
+#if !defined(Q_OS_VISIONOS)
// For now we only care about the main screen, as both the statusbar
// visibility and orientation is only appropriate for the main screen.
if (self.platformScreen->uiScreen() != [UIScreen mainScreen])
return;
+#endif
// Prevent recursion caused by updating the status bar appearance (position
// or visibility), which in turn may cause a layout of our subviews, and
@@ -427,7 +425,7 @@
// All decisions are based on the top level window
focusWindow = qt_window_private(focusWindow)->topLevelWindow();
-#ifndef Q_OS_TVOS
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
// -------------- Status bar style and visbility ---------------
@@ -447,51 +445,6 @@
[self setNeedsStatusBarAppearanceUpdate];
[self.view setNeedsLayout];
}
-
-
- // -------------- Content orientation ---------------
-
- UIApplication *uiApplication = qt_apple_sharedApplication();
-
- static BOOL kAnimateContentOrientationChanges = YES;
-
- Qt::ScreenOrientation contentOrientation = focusWindow->contentOrientation();
- if (contentOrientation != Qt::PrimaryOrientation) {
- // An explicit content orientation has been reported for the focus window,
- // so we keep the status bar in sync with content orientation. This will ensure
- // that the task bar (and associated gestures) are also rotated accordingly.
-
- if (!self.lockedOrientation) {
- // We are moving from Qt::PrimaryOrientation to an explicit orientation,
- // so we need to store the current statusbar orientation, as we need it
- // later when mapping screen coordinates for QScreen and for returning
- // to Qt::PrimaryOrientation.
- self.lockedOrientation = uiApplication.statusBarOrientation;
- }
-
- [uiApplication setStatusBarOrientation:
- UIInterfaceOrientation(fromQtScreenOrientation(contentOrientation))
- animated:kAnimateContentOrientationChanges];
-
- } else {
- // The content orientation is set to Qt::PrimaryOrientation, meaning
- // that auto-rotation should be enabled. But we may be coming out of
- // a state of locked orientation, which needs some cleanup before we
- // can enable auto-rotation again.
- if (self.lockedOrientation) {
- // First we need to restore the statusbar to what it was at the
- // time of locking the orientation, otherwise iOS will be very
- // confused when it starts doing auto-rotation again.
- [uiApplication setStatusBarOrientation:self.lockedOrientation
- animated:kAnimateContentOrientationChanges];
-
- // Then we can re-enable auto-rotation
- self.lockedOrientation = UIInterfaceOrientationUnknown;
-
- // And finally let iOS rotate the root view to match the device orientation
- [UIViewController attemptRotationToDeviceOrientation];
- }
- }
#endif
}
diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h
index 90380e4bb0..88afee80c3 100644
--- a/src/plugins/platforms/ios/qioswindow.h
+++ b/src/plugins/platforms/ios/qioswindow.h
@@ -21,14 +21,13 @@ class QIOSWindow : public QObject, public QPlatformWindow
Q_OBJECT
public:
- explicit QIOSWindow(QWindow *window);
+ explicit QIOSWindow(QWindow *window, WId nativeHandle = 0);
~QIOSWindow();
void setGeometry(const QRect &rect) override;
void setWindowState(Qt::WindowStates state) override;
void setParent(const QPlatformWindow *window) override;
- void handleContentOrientationChange(Qt::ScreenOrientation orientation) override;
void setVisible(bool visible) override;
void setOpacity(qreal level) override;
@@ -56,15 +55,20 @@ public:
void requestUpdate() override;
+ void setMask(const QRegion &region) override;
+
#if QT_CONFIG(opengl)
CAEAGLLayer *eaglLayer() const;
#endif
+ bool isForeignWindow() const override;
+ UIView *view() const;
+
private:
void applicationStateChanged(Qt::ApplicationState state);
void applyGeometry(const QRect &rect);
- QUIView *m_view;
+ UIView *m_view;
QRect m_normalGeometry;
int m_windowLevel;
@@ -80,6 +84,8 @@ private:
QDebug operator<<(QDebug debug, const QIOSWindow *window);
#endif
+QT_MANGLE_NAMESPACE(QUIView) *quiview_cast(UIView *view);
+
QT_END_NAMESPACE
#endif // QIOSWINDOW_H
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
index 99f9e38846..6a1080e238 100644
--- a/src/plugins/platforms/ios/qioswindow.mm
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -11,14 +11,17 @@
#include "quiview.h"
#include "qiosinputcontext.h"
+#include <QtCore/private/qcore_mac_p.h>
+
#include <QtGui/private/qwindow_p.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
#include <qpa/qplatformintegration.h>
#if QT_CONFIG(opengl)
#import <QuartzCore/CAEAGLLayer.h>
#endif
-#ifdef Q_OS_IOS
+#if QT_CONFIG(metal)
#import <QuartzCore/CAMetalLayer.h>
#endif
@@ -26,34 +29,48 @@
QT_BEGIN_NAMESPACE
-QIOSWindow::QIOSWindow(QWindow *window)
+enum {
+ defaultWindowWidth = 160,
+ defaultWindowHeight = 160
+};
+
+QIOSWindow::QIOSWindow(QWindow *window, WId nativeHandle)
: QPlatformWindow(window)
, m_windowLevel(0)
{
-#ifdef Q_OS_IOS
- if (window->surfaceType() == QSurface::RasterSurface)
- window->setSurfaceType(QSurface::MetalSurface);
+ if (nativeHandle) {
+ m_view = reinterpret_cast<UIView *>(nativeHandle);
+ [m_view retain];
+ } else {
+#if QT_CONFIG(metal)
+ if (window->surfaceType() == QSurface::RasterSurface)
+ window->setSurfaceType(QSurface::MetalSurface);
- if (window->surfaceType() == QSurface::MetalSurface)
- m_view = [[QUIMetalView alloc] initWithQIOSWindow:this];
- else
+ if (window->surfaceType() == QSurface::MetalSurface)
+ m_view = [[QUIMetalView alloc] initWithQIOSWindow:this];
+ else
#endif
- m_view = [[QUIView alloc] initWithQIOSWindow:this];
+ m_view = [[QUIView alloc] initWithQIOSWindow:this];
+ }
connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, &QIOSWindow::applicationStateChanged);
- setParent(QPlatformWindow::parent());
+ if (QPlatformWindow::parent())
+ setParent(QPlatformWindow::parent());
- // Resolve default window geometry in case it was not set before creating the
- // platform window. This picks up eg. minimum-size if set, and defaults to
- // the "maxmized" geometry (even though we're not in that window state).
- // FIXME: Detect if we apply a maximized geometry and send a window state
- // change event in that case.
- m_normalGeometry = initialGeometry(window, QPlatformWindow::geometry(),
- screen()->availableGeometry().width(), screen()->availableGeometry().height());
+ if (!isForeignWindow()) {
+ // Resolve default window geometry in case it was not set before creating the
+ // platform window. This picks up eg. minimum-size if set.
+ m_normalGeometry = initialGeometry(window, QPlatformWindow::geometry(),
+ defaultWindowWidth, defaultWindowHeight);
- setWindowState(window->windowStates());
- setOpacity(window->opacity());
+ setWindowState(window->windowStates());
+ setOpacity(window->opacity());
+ setMask(QHighDpi::toNativeLocalRegion(window->mask(), window));
+ } else {
+ // Pick up essential foreign window state
+ QPlatformWindow::setGeometry(QRectF::fromCGRect(m_view.frame).toRect());
+ }
Qt::ScreenOrientation initialOrientation = window->contentOrientation();
if (initialOrientation != Qt::PrimaryOrientation) {
@@ -75,8 +92,15 @@ QIOSWindow::~QIOSWindow()
[m_view touchesCancelled:[NSSet set] withEvent:0];
clearAccessibleCache();
- m_view.platformWindow = 0;
- [m_view removeFromSuperview];
+
+ quiview_cast(m_view).platformWindow = nullptr;
+
+ // Remove from superview, unless we're a foreign window without a
+ // Qt window parent, in which case the foreign window is used as
+ // a window container for a Qt UI hierarchy inside a native UI.
+ if (!(isForeignWindow() && !QPlatformWindow::parent()))
+ [m_view removeFromSuperview];
+
[m_view release];
}
@@ -115,7 +139,7 @@ void QIOSWindow::setVisible(bool visible)
if (visible && shouldAutoActivateWindow()) {
if (!window()->property("_q_showWithoutActivating").toBool())
requestActivateWindow();
- } else if (!visible && [m_view isActiveWindow]) {
+ } else if (!visible && [quiview_cast(m_view) isActiveWindow]) {
// Our window was active/focus window but now hidden, so relinquish
// focus to the next possible window in the stack.
NSArray<UIView *> *subviews = m_view.viewController.view.subviews;
@@ -204,7 +228,7 @@ void QIOSWindow::applyGeometry(const QRect &rect)
QMargins QIOSWindow::safeAreaMargins() const
{
- UIEdgeInsets safeAreaInsets = m_view.qt_safeAreaInsets;
+ UIEdgeInsets safeAreaInsets = m_view.safeAreaInsets;
return QMargins(safeAreaInsets.left, safeAreaInsets.top,
safeAreaInsets.right, safeAreaInsets.bottom);
}
@@ -228,22 +252,45 @@ void QIOSWindow::setWindowState(Qt::WindowStates state)
if (state & Qt::WindowMinimized) {
applyGeometry(QRect());
} else if (state & (Qt::WindowFullScreen | Qt::WindowMaximized)) {
- // When an application is in split-view mode, the UIScreen still has the
- // same geometry, but the UIWindow is resized to the area reserved for the
- // application. We use this to constrain the geometry used when applying the
- // fullscreen or maximized window states. Note that we do not do this
- // in applyGeometry(), as we don't want to artificially limit window
- // placement "outside" of the screen bounds if that's what the user wants.
-
QRect uiWindowBounds = QRectF::fromCGRect(m_view.window.bounds).toRect();
- QRect fullscreenGeometry = screen()->geometry().intersected(uiWindowBounds);
- QRect maximizedGeometry = window()->flags() & Qt::MaximizeUsingFullscreenGeometryHint ?
- fullscreenGeometry : screen()->availableGeometry().intersected(uiWindowBounds);
+ if (NSProcessInfo.processInfo.iOSAppOnMac) {
+ // iOS apps running as "Designed for iPad" on macOS do not match
+ // our current window management implementation where a single
+ // UIWindow is tied to a single screen. And even if we're on the
+ // right screen, the UIScreen does not account for the 77% scale
+ // of the UIUserInterfaceIdiomPad environment, so we can't use
+ // it to clamp the window geometry. Instead just use the UIWindow
+ // directly, which represents our "screen".
+ applyGeometry(uiWindowBounds);
+ } else if (isRunningOnVisionOS()) {
+ // On visionOS there is no concept of a screen, and hence no concept of
+ // screen-relative system UI that we should keep top level windows away
+ // from, so don't apply the UIWindow safe area insets to the screen.
+ applyGeometry(uiWindowBounds);
+ } else {
+ QRect fullscreenGeometry = screen()->geometry();
+ QRect maximizedGeometry = fullscreenGeometry;
+
+#if !defined(Q_OS_VISIONOS)
+ if (!(window()->flags() & Qt::MaximizeUsingFullscreenGeometryHint)) {
+ // If the safe area margins reflect the screen's outer edges,
+ // then reduce the maximized geometry accordingly. Otherwise
+ // leave it as is, and assume the client will take the safe
+ // are margins into account explicitly.
+ UIScreen *uiScreen = m_view.window.windowScene.screen;
+ UIEdgeInsets safeAreaInsets = m_view.window.safeAreaInsets;
+ if (m_view.window.bounds.size.width == uiScreen.bounds.size.width)
+ maximizedGeometry.adjust(safeAreaInsets.left, 0, -safeAreaInsets.right, 0);
+ if (m_view.window.bounds.size.height == uiScreen.bounds.size.height)
+ maximizedGeometry.adjust(0, safeAreaInsets.top, 0, -safeAreaInsets.bottom);
+ }
+#endif
- if (state & Qt::WindowFullScreen)
- applyGeometry(fullscreenGeometry);
- else
- applyGeometry(maximizedGeometry);
+ if (state & Qt::WindowFullScreen)
+ applyGeometry(fullscreenGeometry.intersected(uiWindowBounds));
+ else
+ applyGeometry(maximizedGeometry.intersected(uiWindowBounds));
+ }
} else {
applyGeometry(m_normalGeometry);
}
@@ -251,10 +298,16 @@ void QIOSWindow::setWindowState(Qt::WindowStates state)
void QIOSWindow::setParent(const QPlatformWindow *parentWindow)
{
- UIView *parentView = parentWindow ? reinterpret_cast<UIView *>(parentWindow->winId())
- : isQtApplication() ? static_cast<QIOSScreen *>(screen())->uiWindow().rootViewController.view : 0;
-
- [parentView addSubview:m_view];
+ UIView *superview = nullptr;
+ if (parentWindow)
+ superview = reinterpret_cast<UIView *>(parentWindow->winId());
+ else if (isQtApplication() && !isForeignWindow())
+ superview = rootViewForScreen(window()->screen());
+
+ if (superview)
+ [superview addSubview:m_view];
+ else if (quiview_cast(m_view.superview))
+ [m_view removeFromSuperview];
}
void QIOSWindow::requestActivateWindow()
@@ -265,7 +318,6 @@ void QIOSWindow::requestActivateWindow()
if (blockedByModal())
return;
- Q_ASSERT(m_view.window);
[m_view.window makeKeyWindow];
[m_view becomeFirstResponder];
@@ -275,8 +327,6 @@ void QIOSWindow::requestActivateWindow()
void QIOSWindow::raiseOrLower(bool raise)
{
- // Re-insert m_view at the correct index among its sibling views
- // (QWindows) according to their current m_windowLevel:
if (!isQtApplication())
return;
@@ -284,17 +334,27 @@ void QIOSWindow::raiseOrLower(bool raise)
if (subviews.count == 1)
return;
- for (int i = int(subviews.count) - 1; i >= 0; --i) {
- UIView *view = static_cast<UIView *>([subviews objectAtIndex:i]);
- if (view.hidden || view == m_view || !view.qwindow)
- continue;
- int level = static_cast<QIOSWindow *>(view.qwindow->handle())->m_windowLevel;
- if (m_windowLevel > level || (raise && m_windowLevel == level)) {
- [m_view.superview insertSubview:m_view aboveSubview:view];
- return;
+ if (m_view.superview == m_view.qtViewController.view) {
+ // We're a top level window, so we need to take window
+ // levels into account.
+ for (int i = int(subviews.count) - 1; i >= 0; --i) {
+ UIView *view = static_cast<UIView *>([subviews objectAtIndex:i]);
+ if (view.hidden || view == m_view || !view.qwindow)
+ continue;
+ int level = static_cast<QIOSWindow *>(view.qwindow->handle())->m_windowLevel;
+ if (m_windowLevel > level || (raise && m_windowLevel == level)) {
+ [m_view.superview insertSubview:m_view aboveSubview:view];
+ return;
+ }
}
+ [m_view.superview insertSubview:m_view atIndex:0];
+ } else {
+ // Child window, or embedded into a non-Qt view controller
+ if (raise)
+ [m_view.superview bringSubviewToFront:m_view];
+ else
+ [m_view.superview sendSubviewToBack:m_view];
}
- [m_view.superview insertSubview:m_view atIndex:0];
}
void QIOSWindow::updateWindowLevel()
@@ -323,20 +383,13 @@ void QIOSWindow::updateWindowLevel()
m_windowLevel = qMax(transientParentWindow->m_windowLevel, m_windowLevel);
}
-void QIOSWindow::handleContentOrientationChange(Qt::ScreenOrientation orientation)
-{
- // Update the QWindow representation straight away, so that
- // we can update the statusbar orientation based on the new
- // content orientation.
- qt_window_private(window())->contentOrientation = orientation;
-
- [m_view.qtViewController updateProperties];
-}
-
void QIOSWindow::applicationStateChanged(Qt::ApplicationState)
{
+ if (isForeignWindow())
+ return;
+
if (window()->isExposed() != isExposed())
- [m_view sendUpdatedExposeEvent];
+ [quiview_cast(m_view) sendUpdatedExposeEvent];
}
qreal QIOSWindow::devicePixelRatio() const
@@ -346,7 +399,10 @@ qreal QIOSWindow::devicePixelRatio() const
void QIOSWindow::clearAccessibleCache()
{
- [m_view clearAccessibleCache];
+ if (isForeignWindow())
+ return;
+
+ [quiview_cast(m_view) clearAccessibleCache];
}
void QIOSWindow::requestUpdate()
@@ -354,6 +410,20 @@ void QIOSWindow::requestUpdate()
static_cast<QIOSScreen *>(screen())->setUpdatesPaused(false);
}
+void QIOSWindow::setMask(const QRegion &region)
+{
+ if (!region.isEmpty()) {
+ QCFType<CGMutablePathRef> maskPath = CGPathCreateMutable();
+ for (const QRect &r : region)
+ CGPathAddRect(maskPath, nullptr, r.toCGRect());
+ CAShapeLayer *maskLayer = [CAShapeLayer layer];
+ maskLayer.path = maskPath;
+ m_view.layer.mask = maskLayer;
+ } else {
+ m_view.layer.mask = nil;
+ }
+}
+
#if QT_CONFIG(opengl)
CAEAGLLayer *QIOSWindow::eaglLayer() const
{
@@ -375,6 +445,37 @@ QDebug operator<<(QDebug debug, const QIOSWindow *window)
}
#endif // !QT_NO_DEBUG_STREAM
+/*!
+ Returns the view cast to a QUIview if possible.
+
+ If the view is not a QUIview, nil is returned, which is safe to
+ send messages to, effectively making [quiview_cast(view) message]
+ a no-op.
+
+ For extra verbosity and clearer code, please consider checking
+ that the platform window is not a foreign window before using
+ this cast, via QPlatformWindow::isForeignWindow().
+
+ Do not use this method solely to check for foreign windows, as
+ that will make the code harder to read for people not working
+ primarily on iOS, who do not know the difference between the
+ UIView and QUIView cases.
+*/
+QUIView *quiview_cast(UIView *view)
+{
+ return qt_objc_cast<QUIView *>(view);
+}
+
+bool QIOSWindow::isForeignWindow() const
+{
+ return ![m_view isKindOfClass:QUIView.class];
+}
+
+UIView *QIOSWindow::view() const
+{
+ return m_view;
+}
+
QT_END_NAMESPACE
#include "moc_qioswindow.cpp"
diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.h b/src/plugins/platforms/ios/quiaccessibilityelement.h
index e78fef6d30..8580325436 100644
--- a/src/plugins/platforms/ios/quiaccessibilityelement.h
+++ b/src/plugins/platforms/ios/quiaccessibilityelement.h
@@ -14,7 +14,7 @@
@property (readonly) QAccessible::Id axid;
- (instancetype)initWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view;
-+ (instancetype)elementWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view;
++ (instancetype)elementWithId:(QAccessible::Id)anId;
@end
diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.mm b/src/plugins/platforms/ios/quiaccessibilityelement.mm
index 08e366f32b..39b2cb8a50 100644
--- a/src/plugins/platforms/ios/quiaccessibilityelement.mm
+++ b/src/plugins/platforms/ios/quiaccessibilityelement.mm
@@ -8,6 +8,7 @@
#include "private/qaccessiblecache_p.h"
#include "private/qcore_mac_p.h"
#include "uistrings_p.h"
+#include "qioswindow.h"
QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
@@ -23,7 +24,7 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
return self;
}
-+ (instancetype)elementWithId:(QAccessible::Id)anId withAccessibilityContainer:(id)view
++ (instancetype)elementWithId:(QAccessible::Id)anId
{
Q_ASSERT(anId);
if (!anId)
@@ -33,9 +34,17 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAccessibilityElement);
QMacAccessibilityElement *element = cache->elementForId(anId);
if (!element) {
- Q_ASSERT(QAccessible::accessibleInterface(anId));
- element = [[self alloc] initWithId:anId withAccessibilityContainer:view];
- cache->insertElement(anId, element);
+ auto *a11yInterface = QAccessible::accessibleInterface(anId);
+ Q_ASSERT(a11yInterface);
+ auto *window = a11yInterface->window();
+ if (window && window->handle()) {
+ auto *platformWindow = static_cast<QIOSWindow*>(window->handle());
+ element = [[self alloc] initWithId:anId withAccessibilityContainer:platformWindow->view()];
+ cache->insertElement(anId, element);
+ } else {
+ qWarning() << "Could not create a11y element for" << window
+ << "with platform window" << (window ? window->handle() : nullptr);
+ }
}
return element;
}
diff --git a/src/plugins/platforms/ios/quiview.h b/src/plugins/platforms/ios/quiview.h
index 6d1d19fd3d..7899ec6e0e 100644
--- a/src/plugins/platforms/ios/quiview.h
+++ b/src/plugins/platforms/ios/quiview.h
@@ -32,10 +32,9 @@ QT_END_NAMESPACE
- (QWindow *)qwindow;
- (UIViewController *)viewController;
- (QIOSViewController*)qtViewController;
-@property (nonatomic, readonly) UIEdgeInsets qt_safeAreaInsets;
@end
-#ifdef Q_OS_IOS
+#if QT_CONFIG(metal)
@interface QUIMetalView : QUIView
@end
#endif
diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm
index 979de6a313..d5808db305 100644
--- a/src/plugins/platforms/ios/quiview.mm
+++ b/src/plugins/platforms/ios/quiview.mm
@@ -10,6 +10,7 @@
#include "qiosscreen.h"
#include "qioswindow.h"
#include "qiosinputcontext.h"
+#include "quiwindow.h"
#ifndef Q_OS_TVOS
#include "qiosmenu.h"
#endif
@@ -53,7 +54,6 @@ inline ulong getTimeStamp(UIEvent *event)
@implementation QUIView {
QHash<NSUInteger, QWindowSystemInterface::TouchPoint> m_activeTouches;
UITouch *m_activePencilTouch;
- int m_nextTouchId;
NSMutableArray<UIAccessibilityElement *> *m_accessibleElements;
UIPanGestureRecognizer *m_scrollGestureRecognizer;
CGPoint m_lastScrollCursorPos;
@@ -62,7 +62,7 @@ inline ulong getTimeStamp(UIEvent *event)
+ (void)load
{
-#ifndef Q_OS_TVOS
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
if (QOperatingSystemVersion::current() < QOperatingSystemVersion(QOperatingSystemVersion::IOS, 11)) {
// iOS 11 handles this though [UIView safeAreaInsetsDidChange], but there's no signal for
// the corresponding top and bottom layout guides that we use on earlier versions. Note
@@ -198,6 +198,7 @@ inline ulong getTimeStamp(UIEvent *event)
return description;
}
+#if !defined(Q_OS_VISIONOS)
- (void)willMoveToWindow:(UIWindow *)newWindow
{
// UIKIt will normally set the scale factor of a view to match the corresponding
@@ -207,6 +208,7 @@ inline ulong getTimeStamp(UIEvent *event)
// FIXME: Allow the scale factor to be customized through QSurfaceFormat.
}
+#endif
- (void)didAddSubview:(UIView *)subview
{
@@ -264,6 +266,9 @@ inline ulong getTimeStamp(UIEvent *event)
Q_UNUSED(layer);
Q_ASSERT(layer == self.layer);
+ if (!self.platformWindow)
+ return;
+
[self sendUpdatedExposeEvent];
}
@@ -305,7 +310,7 @@ inline ulong getTimeStamp(UIEvent *event)
// blocked by this guard.
FirstResponderCandidate firstResponderCandidate(self);
- qImDebug() << "self:" << self << "first:" << [UIResponder currentFirstResponder];
+ qImDebug() << "self:" << self << "first:" << [UIResponder qt_currentFirstResponder];
if (![super becomeFirstResponder]) {
qImDebug() << self << "was not allowed to become first responder";
@@ -316,7 +321,7 @@ inline ulong getTimeStamp(UIEvent *event)
}
if (qGuiApp->focusWindow() != self.platformWindow->window())
- QWindowSystemInterface::handleWindowActivated(self.platformWindow->window(), Qt::ActiveWindowFocusReason);
+ QWindowSystemInterface::handleFocusWindowChanged(self.platformWindow->window(), Qt::ActiveWindowFocusReason);
else
qImDebug() << self.platformWindow->window() << "already active, not sending window activation";
@@ -344,7 +349,7 @@ inline ulong getTimeStamp(UIEvent *event)
- (BOOL)resignFirstResponder
{
- qImDebug() << "self:" << self << "first:" << [UIResponder currentFirstResponder];
+ qImDebug() << "self:" << self << "first:" << [UIResponder qt_currentFirstResponder];
if (![super resignFirstResponder])
return NO;
@@ -353,7 +358,7 @@ inline ulong getTimeStamp(UIEvent *event)
UIResponder *newResponder = FirstResponderCandidate::currentCandidate();
if ([self responderShouldTriggerWindowDeactivation:newResponder])
- QWindowSystemInterface::handleWindowActivated(nullptr, Qt::ActiveWindowFocusReason);
+ QWindowSystemInterface::handleFocusWindowChanged(nullptr, Qt::ActiveWindowFocusReason);
return YES;
}
@@ -367,7 +372,7 @@ inline ulong getTimeStamp(UIEvent *event)
if ([self isFirstResponder])
return YES;
- UIResponder *firstResponder = [UIResponder currentFirstResponder];
+ UIResponder *firstResponder = [UIResponder qt_currentFirstResponder];
if ([firstResponder isKindOfClass:[QIOSTextInputResponder class]]
&& [firstResponder nextResponder] == self)
return YES;
@@ -518,7 +523,10 @@ inline ulong getTimeStamp(UIEvent *event)
{
Q_ASSERT(!m_activeTouches.contains(touch.hash));
#endif
- m_activeTouches[touch.hash].id = m_nextTouchId++;
+ // Use window-independent touch identifiers, so that
+ // multi-touch works across windows.
+ static quint16 nextTouchId = 0;
+ m_activeTouches[touch.hash].id = nextTouchId++;
#if QT_CONFIG(tabletevent)
}
#endif
@@ -560,9 +568,6 @@ inline ulong getTimeStamp(UIEvent *event)
// tvOS only supports single touch
m_activeTouches.clear();
#endif
-
- if (m_activeTouches.isEmpty() && !m_activePencilTouch)
- m_nextTouchId = 0;
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
@@ -595,7 +600,6 @@ inline ulong getTimeStamp(UIEvent *event)
qWarning("Subset of active touches cancelled by UIKit");
m_activeTouches.clear();
- m_nextTouchId = 0;
m_activePencilTouch = nil;
ulong timestamp = event ? getTimeStamp(event) : ([[NSProcessInfo processInfo] systemUptime] * 1000);
@@ -699,7 +703,7 @@ inline ulong getTimeStamp(UIEvent *event)
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
-#ifndef Q_OS_TVOS
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
// Check first if QIOSMenu should handle the action before continuing up the responder chain
return [QIOSMenu::menuActionTarget() targetForAction:action withSender:sender] != 0;
#else
@@ -712,7 +716,7 @@ inline ulong getTimeStamp(UIEvent *event)
- (id)forwardingTargetForSelector:(SEL)selector
{
Q_UNUSED(selector);
-#ifndef Q_OS_TVOS
+#if !defined(Q_OS_TVOS) && !defined(Q_OS_VISIONOS)
return QIOSMenu::menuActionTarget();
#else
return nil;
@@ -828,14 +832,9 @@ inline ulong getTimeStamp(UIEvent *event)
return nil;
}
-- (UIEdgeInsets)qt_safeAreaInsets
-{
- return self.safeAreaInsets;
-}
-
@end
-#ifdef Q_OS_IOS
+#if QT_CONFIG(metal)
@implementation QUIMetalView
+ (Class)layerClass
diff --git a/src/plugins/platforms/ios/quiview_accessibility.mm b/src/plugins/platforms/ios/quiview_accessibility.mm
index 366141ef81..04e1f8cfb3 100644
--- a/src/plugins/platforms/ios/quiview_accessibility.mm
+++ b/src/plugins/platforms/ios/quiview_accessibility.mm
@@ -54,7 +54,6 @@
- (void)clearAccessibleCache
{
[m_accessibleElements removeAllObjects];
- UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, @"");
}
// this is a container, returning yes here means the functions below will never be called
diff --git a/src/plugins/platforms/ios/quiwindow.h b/src/plugins/platforms/ios/quiwindow.h
new file mode 100644
index 0000000000..b5587411e4
--- /dev/null
+++ b/src/plugins/platforms/ios/quiwindow.h
@@ -0,0 +1,13 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QUIWINDOW_H
+#define QUIWINDOW_H
+
+#include <UIKit/UIWindow.h>
+
+@interface QUIWindow : UIWindow
+@property (nonatomic, readonly) BOOL sendingEvent;
+@end
+
+#endif // QUIWINDOW_H
diff --git a/src/plugins/platforms/ios/quiwindow.mm b/src/plugins/platforms/ios/quiwindow.mm
new file mode 100644
index 0000000000..7c910b6d9e
--- /dev/null
+++ b/src/plugins/platforms/ios/quiwindow.mm
@@ -0,0 +1,56 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "quiwindow.h"
+
+#include "qiostheme.h"
+
+#include <QtCore/qscopedvaluerollback.h>
+
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/qpa/qplatformtheme.h>
+
+#include <UIKit/UIKit.h>
+
+@implementation QUIWindow
+
+- (instancetype)initWithFrame:(CGRect)frame
+{
+ if ((self = [super initWithFrame:frame]))
+ self->_sendingEvent = NO;
+
+ return self;
+}
+
+- (void)sendEvent:(UIEvent *)event
+{
+ QScopedValueRollback<BOOL> sendingEvent(self->_sendingEvent, YES);
+ [super sendEvent:event];
+}
+
+#if !defined(Q_OS_VISIONOS)
+- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
+{
+ [super traitCollectionDidChange:previousTraitCollection];
+
+ if (!qGuiApp)
+ return;
+
+ Qt::ColorScheme colorScheme = self.traitCollection.userInterfaceStyle
+ == UIUserInterfaceStyleDark
+ ? Qt::ColorScheme::Dark
+ : Qt::ColorScheme::Light;
+
+ if (self.screen == UIScreen.mainScreen) {
+ // Check if the current userInterfaceStyle reports a different appearance than
+ // the platformTheme's appearance. We might have set that one based on the UIScreen
+ if (previousTraitCollection.userInterfaceStyle != self.traitCollection.userInterfaceStyle
+ || QGuiApplicationPrivate::platformTheme()->colorScheme() != colorScheme) {
+ QIOSTheme::initializeSystemPalette();
+ QWindowSystemInterface::handleThemeChange<QWindowSystemInterface::SynchronousDelivery>();
+ }
+ }
+}
+#endif
+
+@end
diff --git a/src/plugins/platforms/offscreen/qoffscreenwindow.cpp b/src/plugins/platforms/offscreen/qoffscreenwindow.cpp
index 20ed0ed91b..1a1471c687 100644
--- a/src/plugins/platforms/offscreen/qoffscreenwindow.cpp
+++ b/src/plugins/platforms/offscreen/qoffscreenwindow.cpp
@@ -86,7 +86,7 @@ void QOffscreenWindow::setVisible(bool visible)
if (visible) {
if (window()->type() != Qt::ToolTip)
- QWindowSystemInterface::handleWindowActivated(window(), Qt::ActiveWindowFocusReason);
+ QWindowSystemInterface::handleFocusWindowChanged(window(), Qt::ActiveWindowFocusReason);
if (m_pendingGeometryChangeOnShow) {
m_pendingGeometryChangeOnShow = false;
@@ -122,7 +122,7 @@ void QOffscreenWindow::setVisible(bool visible)
void QOffscreenWindow::requestActivateWindow()
{
if (m_visible)
- QWindowSystemInterface::handleWindowActivated(window(), Qt::ActiveWindowFocusReason);
+ QWindowSystemInterface::handleFocusWindowChanged(window(), Qt::ActiveWindowFocusReason);
}
WId QOffscreenWindow::winId() const
diff --git a/src/plugins/platforms/qnx/CMakeLists.txt b/src/plugins/platforms/qnx/CMakeLists.txt
index 3dfd006382..9fb412d8a4 100644
--- a/src/plugins/platforms/qnx/CMakeLists.txt
+++ b/src/plugins/platforms/qnx/CMakeLists.txt
@@ -31,6 +31,12 @@ qt_internal_add_plugin(QQnxIntegrationPlugin
qqnxscreeneventthread.cpp qqnxscreeneventthread.h
qqnxservices.cpp qqnxservices.h
qqnxwindow.cpp qqnxwindow.h
+ NO_PCH_SOURCES
+ qqnxclipboard.cpp # undef QT_NO_FOREACH
+ qqnxintegration.cpp # undef QT_NO_FOREACH
+ qqnxscreen.cpp # undef QT_NO_FOREACH
+ qqnxscreeneventhandler.cpp # undef QT_NO_FOREACH
+ qqnxwindow.cpp # undef QT_NO_FOREACH
LIBRARIES
Qt::Core
Qt::CorePrivate
diff --git a/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp b/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp
index 05389d3ea6..9b1107b7ec 100644
--- a/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp
+++ b/src/plugins/platforms/qnx/qqnxabstractnavigator.cpp
@@ -6,14 +6,10 @@
#include <QDebug>
#include <QUrl>
-#if defined(QQNXNAVIGATOR_DEBUG)
-#define qNavigatorDebug qDebug
-#else
-#define qNavigatorDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaQnxNavigator, "qt.qpa.qnx.navigator");
+
QQnxAbstractNavigator::QQnxAbstractNavigator(QObject *parent)
: QObject(parent)
{
@@ -32,7 +28,7 @@ bool QQnxAbstractNavigator::invokeUrl(const QUrl &url)
// which is not recognized by the navigator anymore
const bool result = requestInvokeUrl(url.toString().toUtf8());
- qNavigatorDebug() << "url=" << url << "result=" << result;
+ qCDebug(lcQpaQnxNavigator) << Q_FUNC_INFO << "url =" << url << "result =" << result;
return result;
}
diff --git a/src/plugins/platforms/qnx/qqnxabstractnavigator.h b/src/plugins/platforms/qnx/qqnxabstractnavigator.h
index b4e4dd9bf8..fc92592307 100644
--- a/src/plugins/platforms/qnx/qqnxabstractnavigator.h
+++ b/src/plugins/platforms/qnx/qqnxabstractnavigator.h
@@ -5,9 +5,12 @@
#define QQNXABSTRACTNAVIGATOR_H
#include <QObject>
+#include <QtCore/QLoggingCategory>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaQnxNavigator);
+
class QUrl;
class QQnxAbstractNavigator : public QObject
diff --git a/src/plugins/platforms/qnx/qqnxbuffer.cpp b/src/plugins/platforms/qnx/qqnxbuffer.cpp
index 1ea9a8b0d3..4d3b5256b2 100644
--- a/src/plugins/platforms/qnx/qqnxbuffer.cpp
+++ b/src/plugins/platforms/qnx/qqnxbuffer.cpp
@@ -10,24 +10,20 @@
#include <errno.h>
#include <sys/mman.h>
-#if defined(QQNXBUFFER_DEBUG)
-#define qBufferDebug qDebug
-#else
-#define qBufferDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaScreenBuffer, "qt.qpa.screen.buffer");
+
QQnxBuffer::QQnxBuffer()
: m_buffer(0)
{
- qBufferDebug("empty");
+ qCDebug(lcQpaScreenBuffer) << Q_FUNC_INFO << "Empty";
}
QQnxBuffer::QQnxBuffer(screen_buffer_t buffer)
: m_buffer(buffer)
{
- qBufferDebug("normal");
+ qCDebug(lcQpaScreenBuffer) << Q_FUNC_INFO << "Normal";
// Get size of buffer
int size[2];
@@ -77,7 +73,7 @@ QQnxBuffer::QQnxBuffer(screen_buffer_t buffer)
imageFormat = QImage::Format_ARGB32_Premultiplied;
break;
default:
- qFatal("QQNX: unsupported buffer format, format=%d", screenFormat);
+ qFatal(lcQpaScreenBuffer, "QQNX: unsupported buffer format, format=%d", screenFormat);
}
// wrap buffer in an image
@@ -88,27 +84,27 @@ QQnxBuffer::QQnxBuffer(const QQnxBuffer &other)
: m_buffer(other.m_buffer),
m_image(other.m_image)
{
- qBufferDebug("copy");
+ qCDebug(lcQpaScreenBuffer) << Q_FUNC_INFO << "Copy";
}
QQnxBuffer::~QQnxBuffer()
{
- qBufferDebug();
+ qCDebug(lcQpaScreenBuffer) << Q_FUNC_INFO;
}
void QQnxBuffer::invalidateInCache()
{
- qBufferDebug();
+ qCDebug(lcQpaScreenBuffer) << Q_FUNC_INFO;
// Verify native buffer exists
if (Q_UNLIKELY(!m_buffer))
- qFatal("QQNX: can't invalidate cache for null buffer");
+ qFatal(lcQpaScreenBuffer, "QQNX: can't invalidate cache for null buffer");
// Evict buffer's data from cache
errno = 0;
int result = msync(m_image.bits(), m_image.height() * m_image.bytesPerLine(), MS_INVALIDATE | MS_CACHE_ONLY);
if (Q_UNLIKELY(result != 0))
- qFatal("QQNX: failed to invalidate cache, errno=%d", errno);
+ qFatal(lcQpaScreenBuffer, "QQNX: failed to invalidate cache, errno=%d", errno);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxbuffer.h b/src/plugins/platforms/qnx/qqnxbuffer.h
index b8f1443ad1..b456eb2a62 100644
--- a/src/plugins/platforms/qnx/qqnxbuffer.h
+++ b/src/plugins/platforms/qnx/qqnxbuffer.h
@@ -5,11 +5,14 @@
#define QQNXBUFFER_H
#include <QtGui/QImage>
+#include <QtCore/QLoggingCategory>
#include <screen/screen.h>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaScreenBuffer)
+
class QQnxBuffer
{
public:
diff --git a/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp b/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp
index bf66d54bba..788cddea87 100644
--- a/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp
+++ b/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.cpp
@@ -13,16 +13,12 @@
#include <QtCore/QSocketNotifier>
#include <QtCore/private/qcore_unix_p.h>
-#if defined(QQNXBUTTON_DEBUG)
-#define qButtonDebug qDebug
-#else
-#define qButtonDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
-static const char *ppsPath = "/pps/system/buttons/status";
-static const int ppsBufferSize = 256;
+Q_LOGGING_CATEGORY(lcQpaInputHwButton, "qt.qpa.input.hwbutton");
+
+const char *QQnxButtonEventNotifier::ppsPath = "/pps/system/buttons/status";
+const size_t QQnxButtonEventNotifier::ppsBufferSize = 256;
QQnxButtonEventNotifier::QQnxButtonEventNotifier(QObject *parent)
: QObject(parent),
@@ -47,7 +43,7 @@ QQnxButtonEventNotifier::~QQnxButtonEventNotifier()
void QQnxButtonEventNotifier::start()
{
- qButtonDebug("starting hardware button event processing");
+ qCDebug(lcQpaInputHwButton) << "Starting hardware button event processing";
if (m_fd != -1)
return;
@@ -64,7 +60,7 @@ void QQnxButtonEventNotifier::start()
m_readNotifier = new QSocketNotifier(m_fd, QSocketNotifier::Read);
QObject::connect(m_readNotifier, SIGNAL(activated(QSocketDescriptor)), this, SLOT(updateButtonStates()));
- qButtonDebug("successfully connected to Navigator. fd = %d", m_fd);
+ qCDebug(lcQpaInputHwButton, "successfully connected to Navigator. fd = %d", m_fd);
}
void QQnxButtonEventNotifier::updateButtonStates()
@@ -75,7 +71,8 @@ void QQnxButtonEventNotifier::updateButtonStates()
// Attempt to read pps data
errno = 0;
int bytes = qt_safe_read(m_fd, buffer, ppsBufferSize - 1);
- qButtonDebug() << "Read" << bytes << "bytes of data";
+ qCDebug(lcQpaInputHwButton) << "Read" << bytes << "bytes of data";
+
if (bytes == -1) {
qWarning("QQNX: failed to read hardware buttons pps object, errno=%d", errno);
return;
@@ -88,7 +85,7 @@ void QQnxButtonEventNotifier::updateButtonStates()
// Ensure data is null terminated
buffer[bytes] = '\0';
- qButtonDebug("received PPS message:\n%s", buffer);
+ qCDebug(lcQpaInputHwButton, "Received PPS message:\n%s", buffer);
// Process received message
QByteArray ppsData = QByteArray::fromRawData(buffer, bytes);
@@ -104,7 +101,8 @@ void QQnxButtonEventNotifier::updateButtonStates()
// If state has changed, update our state and inject a keypress event
if (m_state[buttonId] != newState) {
- qButtonDebug() << "Hardware button event: button =" << key << "state =" << fields.value(key);
+ qCDebug(lcQpaInputHwButton) << "Hardware button event: button =" << key << "state =" << fields.value(key);
+
m_state[buttonId] = newState;
// Is it a key press or key release event?
@@ -129,7 +127,7 @@ void QQnxButtonEventNotifier::updateButtonStates()
break;
default:
- qButtonDebug("Unknown hardware button");
+ qCDebug(lcQpaInputHwButton) << "Unknown hardware button";
continue;
}
@@ -170,7 +168,7 @@ bool QQnxButtonEventNotifier::parsePPS(const QByteArray &ppsData, QHash<QByteArr
// tokenize current attribute
const QByteArray &attr = lines.at(i);
- qButtonDebug() << "attr=" << attr;
+ qCDebug(lcQpaInputHwButton) << Q_FUNC_INFO << "attr =" << attr;
int doubleColon = attr.indexOf(QByteArrayLiteral("::"));
if (doubleColon == -1) {
diff --git a/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.h b/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.h
index 987055f903..476119ae27 100644
--- a/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.h
+++ b/src/plugins/platforms/qnx/qqnxbuttoneventnotifier.h
@@ -5,9 +5,12 @@
#define QQNXBUTTONSEVENTNOTIFIER_H
#include <QObject>
+#include <QtCore/QLoggingCategory>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaInputHwButton);
+
class QSocketNotifier;
class QQnxButtonEventNotifier : public QObject
@@ -45,6 +48,9 @@ private:
QSocketNotifier *m_readNotifier;
ButtonState m_state[ButtonCount];
QList<QByteArray> m_buttonKeys;
+
+ static const char *ppsPath;
+ static const size_t ppsBufferSize;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxclipboard.cpp b/src/plugins/platforms/qnx/qqnxclipboard.cpp
index 80f9d73a3b..3f27ec8069 100644
--- a/src/plugins/platforms/qnx/qqnxclipboard.cpp
+++ b/src/plugins/platforms/qnx/qqnxclipboard.cpp
@@ -1,6 +1,8 @@
// Copyright (C) 2011 - 2012 Research In Motion
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
+
#if !defined(QT_NO_CLIPBOARD)
#include "qqnxclipboard.h"
@@ -15,14 +17,10 @@
#include <clipboard/clipboard.h>
#include <errno.h>
-#if defined(QQNXCLIPBOARD_DEBUG)
-#define qClipboardDebug qDebug
-#else
-#define qClipboardDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaClipboard, "qt.qpa.clipboard");
+
// null terminated array
static const char *typeList[] = {"text/html", "text/plain", "image/png", "image/jpeg", "application/x-color", 0};
@@ -64,13 +62,13 @@ public:
void addFormatToCheck(const QString &format) {
m_formatsToCheck << format;
- qClipboardDebug() << "formats=" << m_formatsToCheck;
+ qCDebug(lcQpaClipboard) << "formats=" << m_formatsToCheck;
}
bool hasFormat(const QString &mimetype) const override
{
const bool result = is_clipboard_format_present(mimetype.toUtf8().constData()) == 0;
- qClipboardDebug() << "mimetype=" << mimetype << "result=" << result;
+ qCDebug(lcQpaClipboard) << "mimetype=" << mimetype << "result=" << result;
return result;
}
@@ -83,7 +81,7 @@ public:
result << format;
}
- qClipboardDebug() << "result=" << result;
+ qCDebug(lcQpaClipboard) << "result=" << result;
return result;
}
@@ -107,7 +105,7 @@ public:
protected:
QVariant retrieveData(const QString &mimetype, QMetaType preferredType) const override
{
- qClipboardDebug() << "mimetype=" << mimetype << "preferredType=" << preferredType.name();
+ qCDebug(lcQpaClipboard) << "mimetype=" << mimetype << "preferredType=" << preferredType.name();
if (is_clipboard_format_present(mimetype.toUtf8().constData()) != 0)
return QMimeData::retrieveData(mimetype, preferredType);
@@ -119,7 +117,7 @@ private Q_SLOTS:
void releaseOwnership()
{
if (m_userMimeData) {
- qClipboardDebug() << "user data formats=" << m_userMimeData->formats() << "system formats=" << formats();
+ qCDebug(lcQpaClipboard) << "user data formats=" << m_userMimeData->formats() << "system formats=" << formats();
delete m_userMimeData;
m_userMimeData = 0;
m_clipboard->emitChanged(QClipboard::Clipboard);
@@ -165,7 +163,7 @@ void QQnxClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
}
const QStringList formats = data->formats();
- qClipboardDebug() << "formats=" << formats;
+ qCDebug(lcQpaClipboard) << "formats=" << formats;
Q_FOREACH (const QString &format, formats) {
const QByteArray buf = data->data(format);
@@ -174,7 +172,7 @@ void QQnxClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
continue;
int ret = set_clipboard_data(format.toUtf8().data(), buf.size(), buf.data());
- qClipboardDebug() << "set " << format << "to clipboard, size=" << buf.size() << ";ret=" << ret;
+ qCDebug(lcQpaClipboard) << "set " << format << "to clipboard, size=" << buf.size() << ";ret=" << ret;
if (ret)
m_mimeData->addFormatToCheck(format);
}
diff --git a/src/plugins/platforms/qnx/qqnxclipboard.h b/src/plugins/platforms/qnx/qqnxclipboard.h
index adc70b158a..66f862f0dc 100644
--- a/src/plugins/platforms/qnx/qqnxclipboard.h
+++ b/src/plugins/platforms/qnx/qqnxclipboard.h
@@ -11,6 +11,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaClipboard);
+
class QQnxClipboard : public QPlatformClipboard
{
public:
diff --git a/src/plugins/platforms/qnx/qqnxcursor.cpp b/src/plugins/platforms/qnx/qqnxcursor.cpp
index 03c4e16401..7c55dd79b3 100644
--- a/src/plugins/platforms/qnx/qqnxcursor.cpp
+++ b/src/plugins/platforms/qnx/qqnxcursor.cpp
@@ -5,14 +5,10 @@
#include <QtCore/QDebug>
-#if defined(QQNXCURSOR_DEBUG)
-#define qCursorDebug qDebug
-#else
-#define qCursorDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaQnx, "qt.qpa.qnx");
+
QQnxCursor::QQnxCursor()
{
}
@@ -27,13 +23,13 @@ void QQnxCursor::changeCursor(QCursor *windowCursor, QWindow *window)
void QQnxCursor::setPos(const QPoint &pos)
{
- qCursorDebug() << "QQnxCursor::setPos -" << pos;
+ qCDebug(lcQpaQnx) << "QQnxCursor::setPos -" << pos;
m_pos = pos;
}
QPoint QQnxCursor::pos() const
{
- qCursorDebug() << "QQnxCursor::pos -" << m_pos;
+ qCDebug(lcQpaQnx) << "QQnxCursor::pos -" << m_pos;
return m_pos;
}
diff --git a/src/plugins/platforms/qnx/qqnxcursor.h b/src/plugins/platforms/qnx/qqnxcursor.h
index 6592e0a5ee..707bdbaaa2 100644
--- a/src/plugins/platforms/qnx/qqnxcursor.h
+++ b/src/plugins/platforms/qnx/qqnxcursor.h
@@ -5,9 +5,12 @@
#define QQNXCURSOR_H
#include <qpa/qplatformcursor.h>
+#include <QtCore/QLoggingCategory>
QT_BEGIN_NAMESPACE
+// Q_DECLARE_LOGGING_CATEGORY(lcQpaQnx);
+
class QQnxCursor : public QPlatformCursor
{
public:
diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.cpp b/src/plugins/platforms/qnx/qqnxeglwindow.cpp
index ed53308216..854ad46c3d 100644
--- a/src/plugins/platforms/qnx/qqnxeglwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxeglwindow.cpp
@@ -10,14 +10,10 @@
#include <errno.h>
-#if defined(QQNXEGLWINDOW_DEBUG)
-#define qEglWindowDebug qDebug
-#else
-#define qEglWindowDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaWindowEgl, "qt.qpa.window.egl");
+
QQnxEglWindow::QQnxEglWindow(QWindow *window, screen_context_t context, bool needRootWindow) :
QQnxWindow(window, context, needRootWindow),
m_newSurfaceRequested(true),
@@ -96,8 +92,8 @@ void QQnxEglWindow::createEGLSurface(QQnxGLContext *context)
EGL_NONE
};
- qEglWindowDebug() << "Creating EGL surface from" << this << context
- << window()->surfaceType() << window()->type();
+ qCDebug(lcQpaWindowEgl) << "Creating EGL surface from" << this << context
+ << window()->surfaceType() << window()->type();
// Create EGL surface
EGLSurface eglSurface = eglCreateWindowSurface(
diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.h b/src/plugins/platforms/qnx/qqnxeglwindow.h
index 909a901d3c..548d9be1ee 100644
--- a/src/plugins/platforms/qnx/qqnxeglwindow.h
+++ b/src/plugins/platforms/qnx/qqnxeglwindow.h
@@ -6,9 +6,12 @@
#include "qqnxwindow.h"
#include <QtCore/QMutex>
+#include <QtCore/QLoggingCategory>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaWindowEgl);
+
class QQnxGLContext;
class QQnxEglWindow : public QQnxWindow
diff --git a/src/plugins/platforms/qnx/qqnxglcontext.cpp b/src/plugins/platforms/qnx/qqnxglcontext.cpp
index 7b5b11b2e4..3d8fecf88b 100644
--- a/src/plugins/platforms/qnx/qqnxglcontext.cpp
+++ b/src/plugins/platforms/qnx/qqnxglcontext.cpp
@@ -14,14 +14,10 @@
#include <dlfcn.h>
-#if defined(QQNXGLCONTEXT_DEBUG)
-#define qGLContextDebug qDebug
-#else
-#define qGLContextDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaGLContext, "qt.qpa.glcontext");
+
static QEGLPlatformContext::Flags makeFlags()
{
QEGLPlatformContext::Flags result = {};
@@ -51,13 +47,13 @@ EGLSurface QQnxGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface
bool QQnxGLContext::makeCurrent(QPlatformSurface *surface)
{
- qGLContextDebug();
+ qCDebug(lcQpaGLContext) << Q_FUNC_INFO;
return QEGLPlatformContext::makeCurrent(surface);
}
void QQnxGLContext::swapBuffers(QPlatformSurface *surface)
{
- qGLContextDebug();
+ qCDebug(lcQpaGLContext) << Q_FUNC_INFO;
QEGLPlatformContext::swapBuffers(surface);
diff --git a/src/plugins/platforms/qnx/qqnxglobal.cpp b/src/plugins/platforms/qnx/qqnxglobal.cpp
index 85642b44b3..9cfc328e8f 100644
--- a/src/plugins/platforms/qnx/qqnxglobal.cpp
+++ b/src/plugins/platforms/qnx/qqnxglobal.cpp
@@ -15,6 +15,8 @@ void qScreenCheckError(int rc, const char *funcInfo, const char *message, bool c
}
if (Q_UNLIKELY(rc)) {
+ qCDebug(lcQpaQnx, "%s - Screen: %s - Error: %s (%i)", funcInfo, message, strerror(errno), errno);
+
if (Q_UNLIKELY(critical))
qCritical("%s - Screen: %s - Error: %s (%i)", funcInfo, message, strerror(errno), errno);
else
diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp b/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp
index a1063444d1..cd41ebb8c2 100644
--- a/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp
+++ b/src/plugins/platforms/qnx/qqnxinputcontext_imf.cpp
@@ -25,17 +25,7 @@
#include <process.h>
#include <sys/keycodes.h>
-#if defined(QQNXINPUTCONTEXT_IMF_EVENT_DEBUG)
-#define qInputContextIMFRequestDebug qDebug
-#else
-#define qInputContextIMFRequestDebug QT_NO_QDEBUG_MACRO
-#endif
-
-#if defined(QQNXINPUTCONTEXT_DEBUG)
-#define qInputContextDebug qDebug
-#else
-#define qInputContextDebug QT_NO_QDEBUG_MACRO
-#endif
+Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods");
static QQnxInputContext *sInputContextInstance;
static QColor sSelectedColor(0,0xb8,0,85);
@@ -161,7 +151,7 @@ static int32_t ic_begin_batch_edit(input_session_t *ic)
// See comment at beginning of namespace declaration for general information
static int32_t ic_commit_text(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest event(ic, ImfCommitText);
event.ct.text = text;
@@ -176,7 +166,7 @@ static int32_t ic_commit_text(input_session_t *ic, spannable_string_t *text, int
// See comment at beginning of namespace declaration for general information
static int32_t ic_delete_surrounding_text(input_session_t *ic, int32_t left_length, int32_t right_length)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest event(ic, ImfDeleteSurroundingText);
event.dst.left_length = left_length;
@@ -200,7 +190,7 @@ static int32_t ic_end_batch_edit(input_session_t *ic)
// See comment at beginning of namespace declaration for general information
static int32_t ic_finish_composing_text(input_session_t *ic)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest event(ic, ImfFinishComposingText);
event.fct.result = -1;
@@ -213,7 +203,7 @@ static int32_t ic_finish_composing_text(input_session_t *ic)
// See comment at beginning of namespace declaration for general information
static int32_t ic_get_cursor_position(input_session_t *ic)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest event(ic, ImfGetCursorPosition);
event.gcp.result = -1;
@@ -226,7 +216,7 @@ static int32_t ic_get_cursor_position(input_session_t *ic)
// See comment at beginning of namespace declaration for general information
static spannable_string_t *ic_get_text_after_cursor(input_session_t *ic, int32_t n, int32_t flags)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest event(ic, ImfGetTextAfterCursor);
event.gtac.n = n;
@@ -241,7 +231,7 @@ static spannable_string_t *ic_get_text_after_cursor(input_session_t *ic, int32_t
// See comment at beginning of namespace declaration for general information
static spannable_string_t *ic_get_text_before_cursor(input_session_t *ic, int32_t n, int32_t flags)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest event(ic, ImfGetTextBeforeCursor);
event.gtac.n = n;
@@ -256,7 +246,7 @@ static spannable_string_t *ic_get_text_before_cursor(input_session_t *ic, int32_
// See comment at beginning of namespace declaration for general information
static int32_t ic_send_event(input_session_t *ic, event_t *event)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest imfEvent(ic, ImfSendEvent);
imfEvent.sae.event = event;
@@ -270,7 +260,7 @@ static int32_t ic_send_event(input_session_t *ic, event_t *event)
// See comment at beginning of namespace declaration for general information
static int32_t ic_send_async_event(input_session_t *ic, event_t *event)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
// There's no difference from our point of view between ic_send_event & ic_send_async_event
QQnxImfRequest imfEvent(ic, ImfSendEvent);
@@ -285,7 +275,7 @@ static int32_t ic_send_async_event(input_session_t *ic, event_t *event)
// See comment at beginning of namespace declaration for general information
static int32_t ic_set_composing_region(input_session_t *ic, int32_t start, int32_t end)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest event(ic, ImfSetComposingRegion);
event.scr.start = start;
@@ -301,7 +291,7 @@ static int32_t ic_set_composing_region(input_session_t *ic, int32_t start, int32
// See comment at beginning of namespace declaration for general information
static int32_t ic_set_composing_text(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest event(ic, ImfSetComposingText);
event.sct.text = text;
@@ -316,7 +306,7 @@ static int32_t ic_set_composing_text(input_session_t *ic, spannable_string_t *te
// See comment at beginning of namespace declaration for general information
static int32_t ic_is_text_selected(input_session_t* ic, int32_t* pIsSelected)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest event(ic, ImfIsTextSelected);
event.its.pIsSelected = pIsSelected;
@@ -330,7 +320,7 @@ static int32_t ic_is_text_selected(input_session_t* ic, int32_t* pIsSelected)
// See comment at beginning of namespace declaration for general information
static int32_t ic_is_all_text_selected(input_session_t* ic, int32_t* pIsSelected)
{
- qInputContextIMFRequestDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QQnxImfRequest event(ic, ImfIsAllTextSelected);
event.its.pIsSelected = pIsSelected;
@@ -466,7 +456,7 @@ initEvent(event_t *pEvent, const input_session_t *pSession, EventType eventType,
static spannable_string_t *toSpannableString(const QString &text)
{
- qInputContextDebug() << text;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "Text:" << text;
spannable_string_t *pString = static_cast<spannable_string_t *>(malloc(sizeof(spannable_string_t)));
pString->str = static_cast<wchar_t *>(malloc(sizeof(wchar_t) * text.length() + 1));
@@ -540,7 +530,7 @@ QQnxInputContext::QQnxInputContext(QQnxIntegration *integration, QQnxAbstractVir
m_integration(integration),
m_virtualKeyboard(keyboard)
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
if (!imfAvailable())
return;
@@ -563,7 +553,7 @@ QQnxInputContext::QQnxInputContext(QQnxIntegration *integration, QQnxAbstractVir
QQnxInputContext::~QQnxInputContext()
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
Q_ASSERT(sInputContextInstance == this);
sInputContextInstance = nullptr;
@@ -638,7 +628,7 @@ void QQnxInputContext::processImfEvent(QQnxImfRequest *imfEvent)
bool QQnxInputContext::filterEvent( const QEvent *event )
{
- qInputContextDebug() << event;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << event;
switch (event->type()) {
case QEvent::CloseSoftwareInputPanel:
@@ -661,19 +651,19 @@ QRectF QQnxInputContext::keyboardRect() const
void QQnxInputContext::reset()
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
endComposition();
}
void QQnxInputContext::commit()
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
endComposition();
}
void QQnxInputContext::update(Qt::InputMethodQueries queries)
{
- qInputContextDebug() << queries;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "Queries:" << queries;
if (queries & Qt::ImCursorPosition) {
int lastCaret = m_caretPosition;
@@ -685,7 +675,8 @@ void QQnxInputContext::update(Qt::InputMethodQueries queries)
initEvent(&caretEvent.event, sInputSession, EVENT_CARET, CARET_POS_CHANGED, sizeof(caretEvent));
caretEvent.old_pos = lastCaret;
caretEvent.new_pos = m_caretPosition;
- qInputContextDebug("ictrl_dispatch_event caret changed %d %d", lastCaret, m_caretPosition);
+ qCDebug(lcQpaInputMethods, "ictrl_dispatch_event caret changed %d %d", lastCaret, m_caretPosition);
+
p_ictrl_dispatch_event(&caretEvent.event);
}
}
@@ -693,7 +684,7 @@ void QQnxInputContext::update(Qt::InputMethodQueries queries)
void QQnxInputContext::closeSession()
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
if (!imfAvailable())
return;
@@ -715,7 +706,7 @@ bool QQnxInputContext::openSession()
closeSession();
sInputSession = p_ictrl_open_session(&ic_funcs);
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
return sInputSession != 0;
}
@@ -739,7 +730,7 @@ bool QQnxInputContext::hasSelectedText()
bool QQnxInputContext::dispatchRequestSoftwareInputPanel()
{
- qInputContextDebug() << "requesting keyboard" << m_inputPanelVisible;
+ qCDebug(lcQpaInputMethods) << "Requesting keyboard" << m_inputPanelVisible;
m_virtualKeyboard.showKeyboard();
return true;
@@ -747,7 +738,7 @@ bool QQnxInputContext::dispatchRequestSoftwareInputPanel()
bool QQnxInputContext::dispatchCloseSoftwareInputPanel()
{
- qInputContextDebug() << "hiding keyboard" << m_inputPanelVisible;
+ qCDebug(lcQpaInputMethods) << "Hiding keyboard" << m_inputPanelVisible;
m_virtualKeyboard.hideKeyboard();
return true;
@@ -793,7 +784,7 @@ bool QQnxInputContext::dispatchFocusGainEvent(int inputHints)
focusEvent.style |= IMF_EMAIL_TYPE;
}
- qInputContextDebug() << "ictrl_dispatch_event focus gain style:" << focusEvent.style;
+ qCDebug(lcQpaInputMethods) << "ictrl_dispatch_event focus gain style:" << focusEvent.style;
p_ictrl_dispatch_event((event_t *)&focusEvent);
@@ -803,7 +794,7 @@ bool QQnxInputContext::dispatchFocusGainEvent(int inputHints)
void QQnxInputContext::dispatchFocusLossEvent()
{
if (hasSession()) {
- qInputContextDebug("ictrl_dispatch_event focus lost");
+ qCDebug(lcQpaInputMethods) << "ictrl_dispatch_event focus lost";
focus_event_t focusEvent;
initEvent(&focusEvent.event, sInputSession, EVENT_FOCUS, FOCUS_LOST, sizeof(focusEvent));
@@ -878,7 +869,7 @@ bool QQnxInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan
navigation_event_t navEvent;
initEvent(&navEvent.event, sInputSession, EVENT_NAVIGATION, key, sizeof(navEvent));
navEvent.magnitude = 1;
- qInputContextDebug("ictrl_dispatch_even navigation %d", key);
+ qCDebug(lcQpaInputMethods, "ictrl_dispatch_even navigation %d", key);
p_ictrl_dispatch_event(&navEvent.event);
}
} else {
@@ -891,7 +882,8 @@ bool QQnxInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan
keyEvent.sequence_id = sequenceId;
p_ictrl_dispatch_event(&keyEvent.event);
- qInputContextDebug("ictrl_dispatch_even key %d", key);
+ qCDebug(lcQpaInputMethods, "ictrl_dispatch_even key %d", key);
+
}
return true;
@@ -907,7 +899,7 @@ void QQnxInputContext::updateCursorPosition()
QCoreApplication::sendEvent(input, &query);
m_caretPosition = query.value(Qt::ImCursorPosition).toInt();
- qInputContextDebug("%d", m_caretPosition);
+ qCDebug(lcQpaInputMethods, "ictrl_dispatch_even key %d", key);
}
void QQnxInputContext::endComposition()
@@ -920,7 +912,7 @@ void QQnxInputContext::endComposition()
if (hasSession()) {
action_event_t actionEvent;
initEvent(&actionEvent.event, sInputSession, EVENT_ACTION, ACTION_END_COMPOSITION, sizeof(actionEvent));
- qInputContextDebug("ictrl_dispatch_even end composition");
+ qCDebug(lcQpaInputMethods, "ictrl_dispatch_even end composition");
p_ictrl_dispatch_event(&actionEvent.event);
}
}
@@ -937,7 +929,7 @@ void QQnxInputContext::updateComposition(spannable_string_t *text, int32_t new_c
m_composingText = QString::fromWCharArray(text->str, text->length);
m_isComposing = true;
- qInputContextDebug() << m_composingText << new_cursor_position;
+ qCDebug(lcQpaInputMethods) << "Text =" << m_composingText << "Cursor position =" << new_cursor_position;
QList<QInputMethodEvent::Attribute> attributes;
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor,
@@ -967,7 +959,7 @@ void QQnxInputContext::updateComposition(spannable_string_t *text, int32_t new_c
format.setFontUnderline(true);
if (highlightColor.isValid())
format.setBackground(QBrush(highlightColor));
- qInputContextDebug() << " attrib: " << underline << highlightColor << text->spans[i].start << text->spans[i].end;
+ qCDebug(lcQpaInputMethods) << "attrib: " << underline << highlightColor << text->spans[i].start << text->spans[i].end;
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, text->spans[i].start,
text->spans[i].end - text->spans[i].start + 1, QVariant(format)));
@@ -986,7 +978,7 @@ void QQnxInputContext::finishComposingText()
QObject *input = qGuiApp->focusObject();
if (input) {
- qInputContextDebug() << m_composingText;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "Text =" << m_composingText;
QInputMethodEvent event;
event.setCommitString(m_composingText);
@@ -1051,13 +1043,13 @@ int32_t QQnxInputContext::processEvent(event_t *event)
int32_t result = -1;
switch (event->event_type) {
case EVENT_SPELL_CHECK: {
- qInputContextDebug("EVENT_SPELL_CHECK");
+ qCDebug(lcQpaInputMethods) << "EVENT_SPELL_CHECK";
result = handleSpellCheck(reinterpret_cast<spell_check_event_t *>(event));
break;
}
case EVENT_NAVIGATION: {
- qInputContextDebug("EVENT_NAVIGATION");
+ qCDebug(lcQpaInputMethods) << "EVENT_NAVIGATION";
int key = event->event_id == NAVIGATE_UP ? KEYCODE_UP :
event->event_id == NAVIGATE_DOWN ? KEYCODE_DOWN :
@@ -1080,7 +1072,7 @@ int32_t QQnxInputContext::processEvent(event_t *event)
int flags = KEY_SYM_VALID | KEY_CAP_VALID;
if (event->event_id == IMF_KEY_DOWN)
flags |= KEY_DOWN;
- qInputContextDebug("EVENT_KEY %d %d", flags, keySym);
+ qCDebug(lcQpaInputMethods, "EVENT_KEY %d %d", flags, keySym);
QQnxScreenEventHandler::injectKeyboardEvent(flags, keySym, modifiers, 0, keyCap);
result = 0;
break;
@@ -1120,7 +1112,7 @@ int32_t QQnxInputContext::onCommitText(spannable_string_t *text, int32_t new_cur
int32_t QQnxInputContext::onDeleteSurroundingText(int32_t left_length, int32_t right_length)
{
- qInputContextDebug("L: %d R: %d", int(left_length), int(right_length));
+ qCDebug(lcQpaInputMethods, "L: %d R: %d", int(left_length), int(right_length));
QObject *input = qGuiApp->focusObject();
if (!input)
@@ -1151,7 +1143,7 @@ int32_t QQnxInputContext::onFinishComposingText()
int32_t QQnxInputContext::onGetCursorPosition()
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QObject *input = qGuiApp->focusObject();
if (!input)
@@ -1165,7 +1157,7 @@ int32_t QQnxInputContext::onGetCursorPosition()
spannable_string_t *QQnxInputContext::onGetTextAfterCursor(int32_t n, int32_t flags)
{
Q_UNUSED(flags);
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QObject *input = qGuiApp->focusObject();
if (!input)
@@ -1182,7 +1174,7 @@ spannable_string_t *QQnxInputContext::onGetTextAfterCursor(int32_t n, int32_t fl
spannable_string_t *QQnxInputContext::onGetTextBeforeCursor(int32_t n, int32_t flags)
{
Q_UNUSED(flags);
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
QObject *input = qGuiApp->focusObject();
if (!input)
@@ -1201,7 +1193,7 @@ spannable_string_t *QQnxInputContext::onGetTextBeforeCursor(int32_t n, int32_t f
int32_t QQnxInputContext::onSendEvent(event_t *event)
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
return processEvent(event);
}
@@ -1217,7 +1209,7 @@ int32_t QQnxInputContext::onSetComposingRegion(int32_t start, int32_t end)
QString text = query.value(Qt::ImSurroundingText).toString();
m_caretPosition = query.value(Qt::ImCursorPosition).toInt();
- qInputContextDebug() << text;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "Text =" << text;
m_isUpdatingText = true;
@@ -1260,7 +1252,7 @@ int32_t QQnxInputContext::onIsTextSelected(int32_t* pIsSelected)
{
*pIsSelected = hasSelectedText();
- qInputContextDebug() << *pIsSelected;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << *pIsSelected;
return 0;
}
@@ -1276,20 +1268,20 @@ int32_t QQnxInputContext::onIsAllTextSelected(int32_t* pIsSelected)
*pIsSelected = query.value(Qt::ImSurroundingText).toString().length() == query.value(Qt::ImCurrentSelection).toString().length();
- qInputContextDebug() << *pIsSelected;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << *pIsSelected;
return 0;
}
void QQnxInputContext::showInputPanel()
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
dispatchRequestSoftwareInputPanel();
}
void QQnxInputContext::hideInputPanel()
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
dispatchCloseSoftwareInputPanel();
}
@@ -1305,7 +1297,7 @@ QLocale QQnxInputContext::locale() const
void QQnxInputContext::keyboardVisibilityChanged(bool visible)
{
- qInputContextDebug() << "visible=" << visible;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "visible=" << visible;
if (m_inputPanelVisible != visible) {
m_inputPanelVisible = visible;
emitInputPanelVisibleChanged();
@@ -1314,7 +1306,7 @@ void QQnxInputContext::keyboardVisibilityChanged(bool visible)
void QQnxInputContext::keyboardLocaleChanged(const QLocale &locale)
{
- qInputContextDebug() << "locale=" << locale;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "locale=" << locale;
if (m_inputPanelLocale != locale) {
m_inputPanelLocale = locale;
emitLocaleChanged();
@@ -1323,7 +1315,7 @@ void QQnxInputContext::keyboardLocaleChanged(const QLocale &locale)
void QQnxInputContext::setHighlightColor(int index, const QColor &color)
{
- qInputContextDebug() << "setHighlightColor" << index << color << qGuiApp->focusObject();
+ qCDebug(lcQpaInputMethods) << "setHighlightColor" << index << color << qGuiApp->focusObject();
if (!sInputContextInstance)
return;
@@ -1342,7 +1334,7 @@ void QQnxInputContext::setHighlightColor(int index, const QColor &color)
void QQnxInputContext::setFocusObject(QObject *object)
{
- qInputContextDebug() << "input item=" << object;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "input item=" << object;
// Ensure the colors are reset if we've a change in focus object
setHighlightColor(-1, QColor());
@@ -1372,7 +1364,7 @@ void QQnxInputContext::setFocusObject(QObject *object)
bool QQnxInputContext::checkSpelling(const QString &text, void *context, void (*spellCheckDone)(void *context, const QString &text, const QList<int> &indices))
{
- qInputContextDebug() << "text" << text;
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "Text =" << text;
if (!imfAvailable())
return false;
diff --git a/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp b/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp
index 2a4e5b509b..7789b2830a 100644
--- a/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp
+++ b/src/plugins/platforms/qnx/qqnxinputcontext_noimf.cpp
@@ -10,14 +10,10 @@
#include <QtGui/QGuiApplication>
#include <QtGui/QInputMethodEvent>
-#if defined(QQNXINPUTCONTEXT_DEBUG)
-#define qInputContextDebug qDebug
-#else
-#define qInputContextDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods");
+
QQnxInputContext::QQnxInputContext(QQnxIntegration *integration, QQnxAbstractVirtualKeyboard &keyboard) :
QPlatformInputContext(),
m_inputPanelVisible(false),
@@ -58,13 +54,13 @@ bool QQnxInputContext::filterEvent( const QEvent *event )
if (event->type() == QEvent::CloseSoftwareInputPanel) {
m_virtualKeyboard.hideKeyboard();
- qInputContextDebug("hiding virtual keyboard");
+ qCDebug(lcQpaInputMethods) << "hiding virtual keyboard";
return false;
}
if (event->type() == QEvent::RequestSoftwareInputPanel) {
m_virtualKeyboard.showKeyboard();
- qInputContextDebug("requesting virtual keyboard");
+ qCDebug(lcQpaInputMethods) << "requesting virtual keyboard";
return false;
}
@@ -91,13 +87,13 @@ bool QQnxInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan
void QQnxInputContext::showInputPanel()
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
m_virtualKeyboard.showKeyboard();
}
void QQnxInputContext::hideInputPanel()
{
- qInputContextDebug();
+ qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
m_virtualKeyboard.hideKeyboard();
}
@@ -118,7 +114,7 @@ void QQnxInputContext::keyboardHeightChanged()
void QQnxInputContext::keyboardVisibilityChanged(bool visible)
{
- qInputContextDebug() << "visible=" << visible;
+ qCDebug(lcQpaInputMethods) << "visible=" << visible;
if (m_inputPanelVisible != visible) {
m_inputPanelVisible = visible;
emitInputPanelVisibleChanged();
@@ -127,7 +123,7 @@ void QQnxInputContext::keyboardVisibilityChanged(bool visible)
void QQnxInputContext::keyboardLocaleChanged(const QLocale &locale)
{
- qInputContextDebug() << "locale=" << locale;
+ qCDebug(lcQpaInputMethods) << "locale=" << locale;
if (m_inputPanelLocale != locale) {
m_inputPanelLocale = locale;
emitLocaleChanged();
@@ -136,7 +132,7 @@ void QQnxInputContext::keyboardLocaleChanged(const QLocale &locale)
void QQnxInputContext::setFocusObject(QObject *object)
{
- qInputContextDebug() << "input item=" << object;
+ qCDebug(lcQpaInputMethods) << "input item=" << object;;
if (!inputMethodAccepted()) {
if (m_inputPanelVisible)
diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp
index ff6ce05aaa..cc10f6a00e 100644
--- a/src/plugins/platforms/qnx/qqnxintegration.cpp
+++ b/src/plugins/platforms/qnx/qqnxintegration.cpp
@@ -1,6 +1,8 @@
// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
+
#include "qqnxglobal.h"
#include "qqnxintegration.h"
@@ -62,14 +64,10 @@
#include <QtCore/QFile>
#include <errno.h>
-#if defined(QQNXINTEGRATION_DEBUG)
-#define qIntegrationDebug qDebug
-#else
-#define qIntegrationDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+// Q_LOGGING_CATEGORY(lcQpaQnx, "qt.qpa.qnx");
+
using namespace Qt::StringLiterals;
QQnxIntegration *QQnxIntegration::ms_instance;
@@ -98,7 +96,7 @@ static inline QQnxIntegration::Options parseOptions(const QStringList &paramList
static inline int getContextCapabilities(const QStringList &paramList)
{
- QString contextCapabilitiesPrefix = QStringLiteral("screen-context-capabilities=");
+ constexpr auto contextCapabilitiesPrefix = "screen-context-capabilities="_L1;
int contextCapabilities = SCREEN_APPLICATION_CONTEXT;
for (const QString &param : paramList) {
if (param.startsWith(contextCapabilitiesPrefix)) {
@@ -142,7 +140,7 @@ QQnxIntegration::QQnxIntegration(const QStringList &paramList)
{
ms_instance = this;
m_options = parseOptions(paramList);
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
// Open connection to QNX composition manager
if (screen_create_context(&m_screenContext, getContextCapabilities(paramList))) {
@@ -219,7 +217,7 @@ QQnxIntegration::QQnxIntegration(const QStringList &paramList)
QQnxIntegration::~QQnxIntegration()
{
- qIntegrationDebug("platform plugin shutdown begin");
+ qCDebug(lcQpaQnx) << "Platform plugin shutdown begin";
delete m_nativeInterface;
#if QT_CONFIG(draganddrop)
@@ -276,12 +274,12 @@ QQnxIntegration::~QQnxIntegration()
ms_instance = nullptr;
- qIntegrationDebug("platform plugin shutdown end");
+ qCDebug(lcQpaQnx) << "Platform plugin shutdown end";
}
bool QQnxIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
switch (cap) {
case MultipleWindows:
case ForeignWindows:
@@ -312,7 +310,7 @@ QPlatformWindow *QQnxIntegration::createForeignWindow(QWindow *window, WId nativ
QPlatformWindow *QQnxIntegration::createPlatformWindow(QWindow *window) const
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
QSurface::SurfaceType surfaceType = window->surfaceType();
const bool needRootWindow = options() & RootWindow;
switch (surfaceType) {
@@ -330,14 +328,14 @@ QPlatformWindow *QQnxIntegration::createPlatformWindow(QWindow *window) const
QPlatformBackingStore *QQnxIntegration::createPlatformBackingStore(QWindow *window) const
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
return new QQnxRasterBackingStore(window);
}
#if !defined(QT_NO_OPENGL)
QPlatformOpenGLContext *QQnxIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
// Get color channel sizes from window format
QSurfaceFormat format = context->format();
@@ -396,7 +394,7 @@ QPlatformOpenGLContext *QQnxIntegration::createPlatformOpenGLContext(QOpenGLCont
#if QT_CONFIG(qqnx_pps)
QPlatformInputContext *QQnxIntegration::inputContext() const
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
if (m_qpaInputContext)
return m_qpaInputContext;
return m_inputContext;
@@ -405,7 +403,7 @@ QPlatformInputContext *QQnxIntegration::inputContext() const
void QQnxIntegration::moveToScreen(QWindow *window, int screen)
{
- qIntegrationDebug() << "w =" << window << ", s =" << screen;
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO << "w =" << window << ", s =" << screen;
// get platform window used by widget
QQnxWindow *platformWindow = static_cast<QQnxWindow *>(window->handle());
@@ -419,7 +417,7 @@ void QQnxIntegration::moveToScreen(QWindow *window, int screen)
QAbstractEventDispatcher *QQnxIntegration::createEventDispatcher() const
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
// We transfer ownersip of the event-dispatcher to QtCoreApplication
QAbstractEventDispatcher *eventDispatcher = m_eventDispatcher;
@@ -436,7 +434,7 @@ QPlatformNativeInterface *QQnxIntegration::nativeInterface() const
#if !defined(QT_NO_CLIPBOARD)
QPlatformClipboard *QQnxIntegration::clipboard() const
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
#if QT_CONFIG(qqnx_pps)
if (!m_clipboard)
@@ -455,7 +453,7 @@ QPlatformDrag *QQnxIntegration::drag() const
QVariant QQnxIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
if ((hint == ShowIsFullScreen) && (m_options & FullScreenApplication))
return true;
@@ -469,7 +467,7 @@ QPlatformServices * QQnxIntegration::services() const
QWindow *QQnxIntegration::window(screen_window_t qnxWindow) const
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
QMutexLocker locker(&m_windowMapperMutex);
Q_UNUSED(locker);
return m_windowMapper.value(qnxWindow, 0);
@@ -477,7 +475,7 @@ QWindow *QQnxIntegration::window(screen_window_t qnxWindow) const
void QQnxIntegration::addWindow(screen_window_t qnxWindow, QWindow *window)
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
QMutexLocker locker(&m_windowMapperMutex);
Q_UNUSED(locker);
m_windowMapper.insert(qnxWindow, window);
@@ -485,7 +483,7 @@ void QQnxIntegration::addWindow(screen_window_t qnxWindow, QWindow *window)
void QQnxIntegration::removeWindow(screen_window_t qnxWindow)
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
QMutexLocker locker(&m_windowMapperMutex);
Q_UNUSED(locker);
m_windowMapper.remove(qnxWindow);
@@ -594,7 +592,7 @@ QList<screen_display_t *> QQnxIntegration::sortDisplays(screen_display_t *availa
void QQnxIntegration::createDisplays()
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
// Query number of displays
int displayCount = 0;
int result = screen_get_context_property_iv(m_screenContext, SCREEN_PROPERTY_DISPLAY_COUNT,
@@ -624,11 +622,12 @@ void QQnxIntegration::createDisplays()
Q_SCREEN_CHECKERROR(result, "Failed to query display attachment");
if (!isAttached) {
- qIntegrationDebug("Skipping non-attached display %d", i);
+ qCDebug(lcQpaQnx) << "Skipping non-attached display " << i;
continue;
}
- qIntegrationDebug("Creating screen for display %d", i);
+ qCDebug(lcQpaQnx) << "Creating screen for display " << i;
+
createDisplay(*orderedDisplays[i], /*isPrimary=*/false);
} // of displays iteration
}
@@ -662,7 +661,8 @@ void QQnxIntegration::removeDisplay(QQnxScreen *screen)
void QQnxIntegration::destroyDisplays()
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
+
Q_FOREACH (QQnxScreen *screen, m_screens) {
QWindowSystemInterface::handleScreenRemoved(screen);
}
@@ -713,7 +713,7 @@ bool QQnxIntegration::supportsNavigatorEvents() const
#if QT_CONFIG(opengl)
void QQnxIntegration::createEglDisplay()
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
// Initialize connection to EGL
m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
@@ -727,7 +727,7 @@ void QQnxIntegration::createEglDisplay()
void QQnxIntegration::destroyEglDisplay()
{
- qIntegrationDebug();
+ qCDebug(lcQpaQnx) << Q_FUNC_INFO;
// Close connection to EGL
eglTerminate(m_eglDisplay);
diff --git a/src/plugins/platforms/qnx/qqnxintegration.h b/src/plugins/platforms/qnx/qqnxintegration.h
index 590b9450c2..8a78d54ceb 100644
--- a/src/plugins/platforms/qnx/qqnxintegration.h
+++ b/src/plugins/platforms/qnx/qqnxintegration.h
@@ -6,9 +6,11 @@
#include <qpa/qplatformintegration.h>
#include <private/qtguiglobal_p.h>
+#include <QtCore/qhash.h>
#include <QtCore/qmutex.h>
#include <screen/screen.h>
+#include <QtCore/QLoggingCategory>
#if QT_CONFIG(opengl)
#include <EGL/egl.h>
@@ -16,6 +18,9 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaQnx);
+Q_DECLARE_LOGGING_CATEGORY(lcQpaGLContext);
+
class QQnxScreenEventThread;
class QQnxFileDialogHelper;
class QQnxNativeInterface;
@@ -39,8 +44,7 @@ class QQnxButtonEventNotifier;
class QQnxClipboard;
#endif
-template<class K, class V> class QHash;
-typedef QHash<screen_window_t, QWindow *> QQnxWindowMapper;
+using QQnxWindowMapper = QHash<screen_window_t, QWindow *>;
class QQnxIntegration : public QPlatformIntegration
{
diff --git a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp
index cee86a68a0..7580e560aa 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp
+++ b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp
@@ -10,11 +10,7 @@
#include <QGuiApplication>
#include <qpa/qwindowsysteminterface.h>
-#if defined(QQNXNAVIGATOREVENTHANDLER_DEBUG)
-#define qNavigatorEventHandlerDebug qDebug
-#else
-#define qNavigatorEventHandlerDebug QT_NO_QDEBUG_MACRO
-#endif
+Q_LOGGING_CATEGORY(lcQpaQnxNavigatorEvents, "qt.qpa.qnx.navigator.events");
QT_BEGIN_NAMESPACE
@@ -27,20 +23,20 @@ bool QQnxNavigatorEventHandler::handleOrientationCheck(int angle)
{
// reply to navigator that (any) orientation is acceptable
// TODO: check if top window flags prohibit orientation change
- qNavigatorEventHandlerDebug("angle=%d", angle);
+ qCDebug(lcQpaQnxNavigatorEvents, "angle=%d", angle);
return true;
}
void QQnxNavigatorEventHandler::handleOrientationChange(int angle)
{
// update screen geometry and reply to navigator that we're ready
- qNavigatorEventHandlerDebug("angle=%d", angle);
+ qCDebug(lcQpaQnxNavigatorEvents, "angle=%d", angle);
emit rotationChanged(angle);
}
void QQnxNavigatorEventHandler::handleSwipeDown()
{
- qNavigatorEventHandlerDebug();
+ qCDebug(lcQpaQnxNavigatorEvents) << Q_FUNC_INFO;
Q_EMIT swipeDown();
}
@@ -48,25 +44,25 @@ void QQnxNavigatorEventHandler::handleSwipeDown()
void QQnxNavigatorEventHandler::handleExit()
{
// shutdown everything
- qNavigatorEventHandlerDebug();
+ qCDebug(lcQpaQnxNavigatorEvents) << Q_FUNC_INFO;
QCoreApplication::quit();
}
void QQnxNavigatorEventHandler::handleWindowGroupActivated(const QByteArray &id)
{
- qNavigatorEventHandlerDebug() << id;
+ qCDebug(lcQpaQnxNavigatorEvents) << Q_FUNC_INFO << id;
Q_EMIT windowGroupActivated(id);
}
void QQnxNavigatorEventHandler::handleWindowGroupDeactivated(const QByteArray &id)
{
- qNavigatorEventHandlerDebug() << id;
+ qCDebug(lcQpaQnxNavigatorEvents) << Q_FUNC_INFO << id;
Q_EMIT windowGroupDeactivated(id);
}
void QQnxNavigatorEventHandler::handleWindowGroupStateChanged(const QByteArray &id, Qt::WindowState state)
{
- qNavigatorEventHandlerDebug() << id;
+ qCDebug(lcQpaQnxNavigatorEvents) << Q_FUNC_INFO << id;
Q_EMIT windowGroupStateChanged(id, state);
}
diff --git a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h
index 342b6c3ef6..826c9a0ff9 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h
+++ b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h
@@ -5,9 +5,12 @@
#define QQNXNAVIGATOREVENTHANDLER_H
#include <QObject>
+#include <QtCore/QLoggingCategory>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaQnxNavigatorEvents);
+
class QQnxNavigatorEventHandler : public QObject
{
Q_OBJECT
diff --git a/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp b/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp
index 5d099b7e46..44c71dad52 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp
+++ b/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.cpp
@@ -17,16 +17,12 @@
#include <sys/types.h>
#include <sys/stat.h>
-#if defined(QQNXNAVIGATOREVENTNOTIFIER_DEBUG)
-#define qNavigatorEventNotifierDebug qDebug
-#else
-#define qNavigatorEventNotifierDebug QT_NO_QDEBUG_MACRO
-#endif
+QT_BEGIN_NAMESPACE
-static const char *navigatorControlPath = "/pps/services/navigator/control";
-static const int ppsBufferSize = 4096;
+// Q_LOGGING_CATEGORY(lcQpaQnxNavigatorEvents, "qt.qpa.qnx.navigator.events");
-QT_BEGIN_NAMESPACE
+const char *QQnxNavigatorEventNotifier::navigatorControlPath = "/pps/services/navigator/control";
+const size_t QQnxNavigatorEventNotifier::ppsBufferSize = 4096;
QQnxNavigatorEventNotifier::QQnxNavigatorEventNotifier(QQnxNavigatorEventHandler *eventHandler, QObject *parent)
: QObject(parent),
@@ -44,18 +40,18 @@ QQnxNavigatorEventNotifier::~QQnxNavigatorEventNotifier()
if (m_fd != -1)
close(m_fd);
- qNavigatorEventNotifierDebug("navigator event notifier stopped");
+ qCDebug(lcQpaQnxNavigatorEvents) << "Navigator event notifier stopped";
}
void QQnxNavigatorEventNotifier::start()
{
- qNavigatorEventNotifierDebug("navigator event notifier started");
+ qCDebug(lcQpaQnxNavigatorEvents) << "Navigator event notifier started";
// open connection to navigator
errno = 0;
m_fd = open(navigatorControlPath, O_RDWR);
if (m_fd == -1) {
- qNavigatorEventNotifierDebug("failed to open navigator pps: %s", strerror(errno));
+ qCDebug(lcQpaQnxNavigatorEvents, "Failed to open navigator pps: %s", strerror(errno));
return;
}
@@ -65,7 +61,7 @@ void QQnxNavigatorEventNotifier::start()
void QQnxNavigatorEventNotifier::parsePPS(const QByteArray &ppsData, QByteArray &msg, QByteArray &dat, QByteArray &id)
{
- qNavigatorEventNotifierDebug() << "data=" << ppsData;
+ qCDebug(lcQpaQnxNavigatorEvents) << Q_FUNC_INFO << "data=" << ppsData;
// tokenize pps data into lines
QList<QByteArray> lines = ppsData.split('\n');
@@ -79,7 +75,7 @@ void QQnxNavigatorEventNotifier::parsePPS(const QByteArray &ppsData, QByteArray
// tokenize current attribute
const QByteArray &attr = lines.at(i);
- qNavigatorEventNotifierDebug() << "attr=" << attr;
+ qCDebug(lcQpaQnxNavigatorEvents) << Q_FUNC_INFO << "attr=" << attr;
int firstColon = attr.indexOf(':');
if (firstColon == -1) {
@@ -96,8 +92,7 @@ void QQnxNavigatorEventNotifier::parsePPS(const QByteArray &ppsData, QByteArray
QByteArray key = attr.left(firstColon);
QByteArray value = attr.mid(secondColon + 1);
- qNavigatorEventNotifierDebug() << "key=" << key;
- qNavigatorEventNotifierDebug() << "val=" << value;
+ qCDebug(lcQpaQnxNavigatorEvents) << Q_FUNC_INFO << "key =" << key << "value =" << value;
// save attribute value
if (key == "msg")
@@ -124,7 +119,7 @@ void QQnxNavigatorEventNotifier::replyPPS(const QByteArray &res, const QByteArra
}
ppsData += "\n";
- qNavigatorEventNotifierDebug() << "reply=" << ppsData;
+ qCDebug(lcQpaQnxNavigatorEvents) << Q_FUNC_INFO << "reply=" << ppsData;
// send pps message to navigator
errno = 0;
@@ -135,7 +130,7 @@ void QQnxNavigatorEventNotifier::replyPPS(const QByteArray &res, const QByteArra
void QQnxNavigatorEventNotifier::handleMessage(const QByteArray &msg, const QByteArray &dat, const QByteArray &id)
{
- qNavigatorEventNotifierDebug() << "msg=" << msg << ", dat=" << dat << ", id=" << id;
+ qCDebug(lcQpaQnxNavigatorEvents) << Q_FUNC_INFO << "msg=" << msg << ", dat=" << dat << ", id=" << id;
// check message type
if (msg == "orientationCheck") {
@@ -159,7 +154,7 @@ void QQnxNavigatorEventNotifier::handleMessage(const QByteArray &msg, const QByt
void QQnxNavigatorEventNotifier::readData()
{
- qNavigatorEventNotifierDebug("reading navigator data");
+ qCDebug(lcQpaQnxNavigatorEvents) << "Reading navigator data";
// allocate buffer for pps data
char buffer[ppsBufferSize];
diff --git a/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.h b/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.h
index 6ecf776f36..66100ece3f 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.h
+++ b/src/plugins/platforms/qnx/qqnxnavigatoreventnotifier.h
@@ -32,6 +32,9 @@ private:
int m_fd;
QSocketNotifier *m_readNotifier;
QQnxNavigatorEventHandler *m_eventHandler;
+
+ static const char *navigatorControlPath;
+ static const size_t ppsBufferSize;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp b/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp
index 9ca402822d..3a2fee0afb 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp
+++ b/src/plugins/platforms/qnx/qqnxnavigatorpps.cpp
@@ -8,17 +8,11 @@
#include <QByteArray>
#include <private/qcore_unix_p.h>
-#if defined(QQNXNAVIGATOR_DEBUG)
-#define qNavigatorDebug qDebug
-#else
-#define qNavigatorDebug QT_NO_QDEBUG_MACRO
-#endif
-
-static const char *navigatorControlPath = "/pps/services/navigator/control";
-static const int ppsBufferSize = 4096;
-
QT_BEGIN_NAMESPACE
+const char *QQnxNavigatorPps::navigatorControlPath = "/pps/services/navigator/control";
+const size_t QQnxNavigatorPps::ppsBufferSize = 4096;
+
QQnxNavigatorPps::QQnxNavigatorPps(QObject *parent)
: QQnxAbstractNavigator(parent)
, m_fd(-1)
@@ -45,7 +39,7 @@ bool QQnxNavigatorPps::openPpsConnection()
return false;
}
- qNavigatorDebug("successfully connected to Navigator. fd=%d", m_fd);
+ qCDebug(lcQpaQnxNavigator) << "successfully connected to Navigator. fd=" << m_fd;
return true;
}
@@ -67,7 +61,7 @@ bool QQnxNavigatorPps::sendPpsMessage(const QByteArray &message, const QByteArra
ppsMessage += "\n";
- qNavigatorDebug() << "sending PPS message:\n" << ppsMessage;
+ qCDebug(lcQpaQnxNavigator) << "sending PPS message:\n" << ppsMessage;
// send pps message to navigator
errno = 0;
@@ -89,7 +83,7 @@ bool QQnxNavigatorPps::sendPpsMessage(const QByteArray &message, const QByteArra
// ensure data is null terminated
buffer[bytes] = '\0';
- qNavigatorDebug() << "received PPS message:\n" << buffer;
+ qCDebug(lcQpaQnxNavigator) << "received PPS message:\n" << buffer;
// process received message
QByteArray ppsData(buffer);
@@ -108,7 +102,7 @@ bool QQnxNavigatorPps::sendPpsMessage(const QByteArray &message, const QByteArra
void QQnxNavigatorPps::parsePPS(const QByteArray &ppsData, QHash<QByteArray, QByteArray> &messageFields)
{
- qNavigatorDebug() << "data=" << ppsData;
+ qCDebug(lcQpaQnxNavigator) << "data=" << ppsData;
// tokenize pps data into lines
QList<QByteArray> lines = ppsData.split('\n');
@@ -123,7 +117,7 @@ void QQnxNavigatorPps::parsePPS(const QByteArray &ppsData, QHash<QByteArray, QBy
// tokenize current attribute
const QByteArray &attr = lines.at(i);
- qNavigatorDebug() << "attr=" << attr;
+ qCDebug(lcQpaQnxNavigator) << "attr=" << attr;
int firstColon = attr.indexOf(':');
if (firstColon == -1) {
@@ -140,8 +134,7 @@ void QQnxNavigatorPps::parsePPS(const QByteArray &ppsData, QHash<QByteArray, QBy
QByteArray key = attr.left(firstColon);
QByteArray value = attr.mid(secondColon + 1);
- qNavigatorDebug() << "key=" << key;
- qNavigatorDebug() << "val=" << value;
+ qCDebug(lcQpaQnxNavigator) << "key=" << key << "value=" << value;
messageFields[key] = value;
}
}
diff --git a/src/plugins/platforms/qnx/qqnxnavigatorpps.h b/src/plugins/platforms/qnx/qqnxnavigatorpps.h
index 7f23097bc9..889b9f62eb 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatorpps.h
+++ b/src/plugins/platforms/qnx/qqnxnavigatorpps.h
@@ -5,9 +5,12 @@
#define QQNXNAVIGATORPPS_H
#include "qqnxabstractnavigator.h"
+#include <QtCore/QLoggingCategory>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaQnxNavigator);
+
template <typename K, typename V> class QHash;
class QQnxNavigatorPps : public QQnxAbstractNavigator
@@ -26,8 +29,9 @@ private:
bool sendPpsMessage(const QByteArray &message, const QByteArray &data);
void parsePPS(const QByteArray &ppsData, QHash<QByteArray, QByteArray> &messageFields);
-private:
int m_fd;
+ static const char *navigatorControlPath;
+ static const size_t ppsBufferSize;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp b/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp
index cf80e44f84..b94c056a79 100644
--- a/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp
+++ b/src/plugins/platforms/qnx/qqnxrasterbackingstore.cpp
@@ -10,12 +10,6 @@
#include <errno.h>
-#if defined(QQNXRASTERBACKINGSTORE_DEBUG)
-#define qRasterBackingStoreDebug qDebug
-#else
-#define qRasterBackingStoreDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
QQnxRasterBackingStore::QQnxRasterBackingStore(QWindow *window)
@@ -23,14 +17,14 @@ QQnxRasterBackingStore::QQnxRasterBackingStore(QWindow *window)
m_needsPosting(false),
m_scrolled(false)
{
- qRasterBackingStoreDebug() << "w =" << window;
+ qCDebug(lcQpaBackingStore) << Q_FUNC_INFO << "w =" << window;
m_window = window;
}
QQnxRasterBackingStore::~QQnxRasterBackingStore()
{
- qRasterBackingStoreDebug() << "w =" << window();
+ qCDebug(lcQpaBackingStore) << Q_FUNC_INFO << "w =" << window();
}
QPaintDevice *QQnxRasterBackingStore::paintDevice()
@@ -45,7 +39,7 @@ void QQnxRasterBackingStore::flush(QWindow *window, const QRegion &region, const
{
Q_UNUSED(offset);
- qRasterBackingStoreDebug() << "w =" << this->window();
+ qCDebug(lcQpaBackingStore) << Q_FUNC_INFO << "w =" << this->window();
// Sometimes this method is called even though there is nothing to be
// flushed (posted in "screen" parlance), for instance, after an expose
@@ -67,7 +61,7 @@ void QQnxRasterBackingStore::resize(const QSize &size, const QRegion &staticCont
{
Q_UNUSED(size);
Q_UNUSED(staticContents);
- qRasterBackingStoreDebug() << "w =" << window() << ", s =" << size;
+ qCDebug(lcQpaBackingStore) << Q_FUNC_INFO << "w =" << window() << ", s =" << size;
// NOTE: defer resizing window buffers until next paint as
// resize() can be called multiple times before a paint occurs
@@ -75,7 +69,7 @@ void QQnxRasterBackingStore::resize(const QSize &size, const QRegion &staticCont
bool QQnxRasterBackingStore::scroll(const QRegion &area, int dx, int dy)
{
- qRasterBackingStoreDebug() << "w =" << window();
+ qCDebug(lcQpaBackingStore) << Q_FUNC_INFO << "w =" << window();
m_needsPosting = true;
@@ -91,7 +85,7 @@ void QQnxRasterBackingStore::beginPaint(const QRegion &region)
{
Q_UNUSED(region);
- qRasterBackingStoreDebug() << "w =" << window();
+ qCDebug(lcQpaBackingStore) << Q_FUNC_INFO << "w =" << window();
m_needsPosting = true;
platformWindow()->adjustBufferSize();
@@ -119,7 +113,7 @@ void QQnxRasterBackingStore::beginPaint(const QRegion &region)
void QQnxRasterBackingStore::endPaint()
{
- qRasterBackingStoreDebug() << "w =" << window();
+ qCDebug(lcQpaBackingStore) << Q_FUNC_INFO << "w =" << window();
}
QQnxRasterWindow *QQnxRasterBackingStore::platformWindow() const
diff --git a/src/plugins/platforms/qnx/qqnxrasterwindow.cpp b/src/plugins/platforms/qnx/qqnxrasterwindow.cpp
index fb7a1d3fd3..303c9e7c06 100644
--- a/src/plugins/platforms/qnx/qqnxrasterwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxrasterwindow.cpp
@@ -10,12 +10,6 @@
#include <errno.h>
-#if defined(QQNXRASTERWINDOW_DEBUG)
-#define qRasterWindowDebug qDebug
-#else
-#define qRasterWindowDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
QQnxRasterWindow::QQnxRasterWindow(QWindow *window, screen_context_t context, bool needRootWindow) :
@@ -61,7 +55,7 @@ void QQnxRasterWindow::post(const QRegion &dirty)
// Check if render buffer exists and something was rendered
if (m_currentBufferIndex != -1 && !dirty.isEmpty()) {
- qRasterWindowDebug() << "window =" << window();
+ qCDebug(lcQpaWindow) << Q_FUNC_INFO << "window = " << window();
QQnxBuffer &currentBuffer = m_buffers[m_currentBufferIndex];
// Copy unmodified region from old render buffer to new render buffer;
@@ -94,14 +88,14 @@ void QQnxRasterWindow::post(const QRegion &dirty)
void QQnxRasterWindow::scroll(const QRegion &region, int dx, int dy, bool flush)
{
- qRasterWindowDebug() << "window =" << window();
+ qCDebug(lcQpaWindow) << Q_FUNC_INFO << "window = " << window();
blitPreviousToCurrent(region, dx, dy, flush);
m_scrolled += region;
}
QQnxBuffer &QQnxRasterWindow::renderBuffer()
{
- qRasterWindowDebug() << "window =" << window();
+ qCDebug(lcQpaWindow) << Q_FUNC_INFO << "window = " << window();
// Check if render buffer is invalid
if (m_currentBufferIndex == -1) {
@@ -162,7 +156,7 @@ void QQnxRasterWindow::resetBuffers()
void QQnxRasterWindow::blitPreviousToCurrent(const QRegion &region, int dx, int dy, bool flush)
{
- qRasterWindowDebug() << "window =" << window();
+ qCDebug(lcQpaWindow) << Q_FUNC_INFO << "window = " << window();
// Abort if previous buffer is invalid or if nothing to copy
if (m_previousBufferIndex == -1 || region.isEmpty())
diff --git a/src/plugins/platforms/qnx/qqnxscreen.cpp b/src/plugins/platforms/qnx/qqnxscreen.cpp
index 66f8bfae01..f2c3b3847d 100644
--- a/src/plugins/platforms/qnx/qqnxscreen.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreen.cpp
@@ -1,6 +1,8 @@
// Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
+
#include "qqnxglobal.h"
#include "qqnxscreen.h"
@@ -13,12 +15,6 @@
#include <errno.h>
-#if defined(QQNXSCREEN_DEBUG)
-#define qScreenDebug qDebug
-#else
-#define qScreenDebug QT_NO_QDEBUG_MACRO
-#endif
-
#if defined(QQNX_PHYSICAL_SCREEN_WIDTH) && QQNX_PHYSICAL_SCREEN_WIDTH > 0 \
&& defined(QQNX_PHYSICAL_SCREEN_HEIGHT) && QQNX_PHYSICAL_SCREEN_HEIGHT > 0
#define QQNX_PHYSICAL_SCREEN_SIZE_DEFINED
@@ -32,6 +28,8 @@ static const int MAX_UNDERLAY_ZORDER = -1;
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen");
+
static QSize determineScreenSize(screen_display_t display, bool primaryScreen) {
int val[2];
@@ -44,9 +42,9 @@ static QSize determineScreenSize(screen_display_t display, bool primaryScreen) {
if (val[0] > 0 && val[1] > 0)
return QSize(val[0], val[1]);
- qScreenDebug("QQnxScreen: screen_get_display_property_iv() reported an invalid "
- "physical screen size (%dx%d). Falling back to QQNX_PHYSICAL_SCREEN_SIZE "
- "environment variable.", val[0], val[1]);
+ qCDebug(lcQpaScreen, "QQnxScreen: screen_get_display_property_iv() reported an invalid "
+ "physical screen size (%dx%d). Falling back to QQNX_PHYSICAL_SCREEN_SIZE "
+ "environment variable.", val[0], val[1]);
const QString envPhySizeStr = qgetenv("QQNX_PHYSICAL_SCREEN_SIZE");
if (!envPhySizeStr.isEmpty()) {
@@ -88,7 +86,7 @@ QQnxScreen::QQnxScreen(screen_context_t screenContext, screen_display_t display,
m_coverWindow(0),
m_cursor(new QQnxCursor())
{
- qScreenDebug();
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO;
// Cache initial orientation of this display
int result = screen_get_display_property_iv(m_display, SCREEN_PROPERTY_ROTATION,
&m_initialRotation);
@@ -125,7 +123,7 @@ QQnxScreen::QQnxScreen(screen_context_t screenContext, screen_display_t display,
QQnxScreen::~QQnxScreen()
{
- qScreenDebug();
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO;
Q_FOREACH (QQnxWindow *childWindow, m_childWindows)
childWindow->setScreen(0);
@@ -234,7 +232,7 @@ QPixmap QQnxScreen::grabWindow(WId window, int x, int y, int width, int height)
static int defaultDepth()
{
- qScreenDebug();
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO;
static int defaultDepth = 0;
if (defaultDepth == 0) {
// check if display depth was specified in environment variable;
@@ -248,7 +246,7 @@ static int defaultDepth()
QRect QQnxScreen::availableGeometry() const
{
- qScreenDebug();
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO;
// available geometry = total geometry - keyboard
return QRect(m_currentGeometry.x(), m_currentGeometry.y(),
m_currentGeometry.width(), m_currentGeometry.height() - m_keyboardHeight);
@@ -268,12 +266,12 @@ qreal QQnxScreen::refreshRate() const
qWarning("QQnxScreen: Failed to query screen mode. Using default value of 60Hz");
return 60.0;
}
- qScreenDebug("screen mode:\n"
- " width = %u\n"
- " height = %u\n"
- " refresh = %u\n"
- " interlaced = %u",
- uint(displayMode.width), uint(displayMode.height), uint(displayMode.refresh), uint(displayMode.interlaced));
+ qCDebug(lcQpaScreen, "screen mode:\n"
+ " width = %u\n"
+ " height = %u\n"
+ " refresh = %u\n"
+ " interlaced = %u",
+ uint(displayMode.width), uint(displayMode.height), uint(displayMode.refresh), uint(displayMode.interlaced));
return static_cast<qreal>(displayMode.refresh);
}
@@ -307,7 +305,7 @@ Qt::ScreenOrientation QQnxScreen::orientation() const
else
orient = Qt::InvertedLandscapeOrientation;
}
- qScreenDebug() << "orientation =" << orient;
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO << "Orientation =" << orient;
return orient;
}
@@ -331,7 +329,7 @@ static bool isOrthogonal(int angle1, int angle2)
void QQnxScreen::setRotation(int rotation)
{
- qScreenDebug("orientation = %d", rotation);
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO << "orientation =" << rotation;
// Check if rotation changed
// We only want to rotate if we are the primary screen
if (m_currentRotation != rotation && isPrimaryScreen()) {
@@ -352,7 +350,7 @@ void QQnxScreen::setRotation(int rotation)
// Resize root window if we've rotated 90 or 270 from previous orientation
if (isOrthogonal(m_currentRotation, rotation)) {
- qScreenDebug() << "resize, size =" << m_currentGeometry.size();
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO << "resize, size =" << m_currentGeometry.size();
if (rootWindow())
rootWindow()->setGeometry(QRect(QPoint(0,0), m_currentGeometry.size()));
@@ -499,7 +497,7 @@ QQnxWindow *QQnxScreen::findWindow(screen_window_t windowHandle) const
void QQnxScreen::addWindow(QQnxWindow *window)
{
- qScreenDebug() << "window =" << window;
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO << "Window =" << window;
if (m_childWindows.contains(window))
return;
@@ -522,7 +520,7 @@ void QQnxScreen::addWindow(QQnxWindow *window)
void QQnxScreen::removeWindow(QQnxWindow *window)
{
- qScreenDebug() << "window =" << window;
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO << "Window =" << window;
if (window != m_coverWindow) {
const int numWindowsRemoved = m_childWindows.removeAll(window);
@@ -537,7 +535,7 @@ void QQnxScreen::removeWindow(QQnxWindow *window)
void QQnxScreen::raiseWindow(QQnxWindow *window)
{
- qScreenDebug() << "window =" << window;
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO << "Window =" << window;
if (window != m_coverWindow) {
removeWindow(window);
@@ -547,7 +545,7 @@ void QQnxScreen::raiseWindow(QQnxWindow *window)
void QQnxScreen::lowerWindow(QQnxWindow *window)
{
- qScreenDebug() << "window =" << window;
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO << "Window =" << window;
if (window != m_coverWindow) {
removeWindow(window);
@@ -557,7 +555,7 @@ void QQnxScreen::lowerWindow(QQnxWindow *window)
void QQnxScreen::updateHierarchy()
{
- qScreenDebug();
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO;
QList<QQnxWindow*>::const_iterator it;
int result;
@@ -707,7 +705,7 @@ void QQnxScreen::windowClosed(void *window)
void QQnxScreen::windowGroupStateChanged(const QByteArray &id, Qt::WindowState state)
{
- qScreenDebug();
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO;
if (!rootWindow() || id != rootWindow()->groupName())
return;
@@ -722,7 +720,7 @@ void QQnxScreen::windowGroupStateChanged(const QByteArray &id, Qt::WindowState s
void QQnxScreen::activateWindowGroup(const QByteArray &id)
{
- qScreenDebug();
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO;
if (!rootWindow() || id != rootWindow()->groupName())
return;
@@ -741,7 +739,7 @@ void QQnxScreen::activateWindowGroup(const QByteArray &id)
void QQnxScreen::deactivateWindowGroup(const QByteArray &id)
{
- qScreenDebug();
+ qCDebug(lcQpaScreen) << Q_FUNC_INFO;
if (!rootWindow() || id != rootWindow()->groupName())
return;
diff --git a/src/plugins/platforms/qnx/qqnxscreen.h b/src/plugins/platforms/qnx/qqnxscreen.h
index f988b42ab4..17b282bdc1 100644
--- a/src/plugins/platforms/qnx/qqnxscreen.h
+++ b/src/plugins/platforms/qnx/qqnxscreen.h
@@ -30,6 +30,10 @@ const int SCREEN_PROPERTY_SYM = SCREEN_PROPERTY_KEY_SYM;
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen);
+Q_DECLARE_LOGGING_CATEGORY(lcQpaScreenEvents);
+Q_DECLARE_LOGGING_CATEGORY(lcQpaScreenBuffer);
+
class QQnxWindow;
class QQnxScreen : public QObject, public QPlatformScreen
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
index 525b22242c..6d923bc3a8 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.cpp
@@ -1,6 +1,8 @@
// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
+
#include "qqnxglobal.h"
#include "qqnxscreeneventhandler.h"
@@ -17,11 +19,7 @@
#include <errno.h>
#include <sys/keycodes.h>
-#if defined(QQNXSCREENEVENT_DEBUG)
-#define qScreenEventDebug qDebug
-#else
-#define qScreenEventDebug QT_NO_QDEBUG_MACRO
-#endif
+Q_LOGGING_CATEGORY(lcQpaScreenEvents, "qt.qpa.screen.events");
static int qtKey(int virtualKey, QChar::Category category)
{
@@ -195,7 +193,7 @@ bool QQnxScreenEventHandler::handleEvent(screen_event_t event, int qnxType)
default:
// event ignored
- qScreenEventDebug("unknown event %d", qnxType);
+ qCDebug(lcQpaScreenEvents) << Q_FUNC_INFO << "Unknown event" << qnxType;
return false;
}
@@ -233,7 +231,7 @@ void QQnxScreenEventHandler::injectKeyboardEvent(int flags, int sym, int modifie
QWindowSystemInterface::handleExtendedKeyEvent(QGuiApplication::focusWindow(), type, key, qtMod,
scan, virtualKey, modifiers, keyStr, flags & KEY_REPEAT);
- qScreenEventDebug() << "Qt key t=" << type << ", k=" << key << ", s=" << keyStr;
+ qCDebug(lcQpaScreenEvents) << "Qt key t=" << type << ", k=" << key << ", s=" << keyStr;
}
void QQnxScreenEventHandler::setScreenEventThread(QQnxScreenEventThread *eventThread)
@@ -362,12 +360,12 @@ void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event)
if (wOld) {
QWindowSystemInterface::handleLeaveEvent(wOld);
- qScreenEventDebug() << "Qt leave, w=" << wOld;
+ qCDebug(lcQpaScreenEvents) << "Qt leave, w=" << wOld;
}
if (w) {
QWindowSystemInterface::handleEnterEvent(w);
- qScreenEventDebug() << "Qt enter, w=" << w;
+ qCDebug(lcQpaScreenEvents) << "Qt enter, w=" << w;
}
}
@@ -410,8 +408,8 @@ void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event)
QWindowSystemInterface::handleMouseEvent(w, timestamp, m_mouseDevice, localPoint,
globalPoint, buttons, Qt::NoButton,
QEvent::MouseMove);
- qScreenEventDebug() << "Qt mouse move, w=" << w << ", (" << localPoint.x() << ","
- << localPoint.y() << "), b=" << static_cast<int>(buttons);
+ qCDebug(lcQpaScreenEvents) << "Qt mouse move, w=" << w << ", (" << localPoint.x() << ","
+ << localPoint.y() << "), b=" << static_cast<int>(buttons);
}
if (m_lastButtonState != buttons) {
@@ -426,8 +424,8 @@ void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event)
QWindowSystemInterface::handleMouseEvent(w, timestamp, m_mouseDevice,
localPoint, globalPoint, buttons,
button, QEvent::MouseButtonRelease);
- qScreenEventDebug() << "Qt mouse release, w=" << w << ", (" << localPoint.x()
- << "," << localPoint.y() << "), b=" << button;
+ qCDebug(lcQpaScreenEvents) << "Qt mouse release, w=" << w << ", (" << localPoint.x()
+ << "," << localPoint.y() << "), b=" << button;
}
}
@@ -441,8 +439,8 @@ void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event)
QWindowSystemInterface::handleMouseEvent(w, timestamp, m_mouseDevice,
localPoint, globalPoint, buttons,
button, QEvent::MouseButtonPress);
- qScreenEventDebug() << "Qt mouse press, w=" << w << ", (" << localPoint.x()
- << "," << localPoint.y() << "), b=" << button;
+ qCDebug(lcQpaScreenEvents) << "Qt mouse press, w=" << w << ", (" << localPoint.x()
+ << "," << localPoint.y() << "), b=" << button;
}
}
}
@@ -453,7 +451,7 @@ void QQnxScreenEventHandler::handlePointerEvent(screen_event_t event)
QPoint angleDelta(0, wheelDelta);
QWindowSystemInterface::handleWheelEvent(w, timestamp, m_mouseDevice, localPoint,
globalPoint, QPoint(), angleDelta);
- qScreenEventDebug() << "Qt wheel, w=" << w << ", (" << localPoint.x() << ","
+ qCDebug(lcQpaScreenEvents) << "Qt wheel, w=" << w << ", (" << localPoint.x() << ","
<< localPoint.y() << "), d=" << static_cast<int>(wheelDelta);
}
}
@@ -511,12 +509,12 @@ void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType)
if (wOld) {
QWindowSystemInterface::handleLeaveEvent(wOld);
- qScreenEventDebug() << "Qt leave, w=" << wOld;
+ qCDebug(lcQpaScreenEvents) << "Qt leave, w=" << wOld;
}
if (w) {
QWindowSystemInterface::handleEnterEvent(w);
- qScreenEventDebug() << "Qt enter, w=" << w;
+ qCDebug(lcQpaScreenEvents) << "Qt enter, w=" << w;
}
}
m_lastMouseWindow = qnxWindow;
@@ -583,9 +581,9 @@ void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType)
// inject event into Qt
QWindowSystemInterface::handleTouchEvent(w, m_touchDevice, pointList);
- qScreenEventDebug() << "Qt touch, w =" << w
- << ", p=" << m_touchPoints[touchId].area.topLeft()
- << ", t=" << type;
+ qCDebug(lcQpaScreenEvents) << "Qt touch, w =" << w
+ << ", p=" << m_touchPoints[touchId].area.topLeft()
+ << ", t=" << type;
}
}
}
@@ -629,7 +627,8 @@ void QQnxScreenEventHandler::handleDisplayEvent(screen_event_t event)
return;
}
- qScreenEventDebug() << "display attachment is now:" << isAttached;
+ qCDebug(lcQpaScreenEvents) << "display attachment is now:" << isAttached;
+
QQnxScreen *screen = m_qnxIntegration->screenForNative(nativeDisplay);
if (!screen) {
@@ -639,7 +638,7 @@ void QQnxScreenEventHandler::handleDisplayEvent(screen_event_t event)
if (val[0] == 0 && val[1] == 0) //If screen size is invalid, wait for the next event
return;
- qScreenEventDebug("creating new QQnxScreen for newly attached display");
+ qCDebug(lcQpaScreenEvents) << "Creating new QQnxScreen for newly attached display";
m_qnxIntegration->createDisplay(nativeDisplay, false /* not primary, we assume */);
}
} else if (!isAttached) {
@@ -652,7 +651,7 @@ void QQnxScreenEventHandler::handleDisplayEvent(screen_event_t event)
if (!screen->isPrimaryScreen()) {
// libscreen display is deactivated, let's remove the QQnxScreen / QScreen
- qScreenEventDebug("removing display");
+ qCDebug(lcQpaScreenEvents) << "Removing display";
m_qnxIntegration->removeDisplay(screen);
}
}
@@ -689,7 +688,7 @@ void QQnxScreenEventHandler::handlePropertyEvent(screen_event_t event)
break;
default:
// event ignored
- qScreenEventDebug() << "Ignore property event for property: " << property;
+ qCDebug(lcQpaScreenEvents) << "Ignore property event for property: " << property;
}
}
@@ -708,7 +707,7 @@ void QQnxScreenEventHandler::handleKeyboardFocusPropertyEvent(screen_window_t wi
}
if (focus && focusWindow != QGuiApplication::focusWindow())
- QWindowSystemInterface::handleWindowActivated(focusWindow, Qt::ActiveWindowFocusReason);
+ QWindowSystemInterface::handleFocusWindowChanged(focusWindow, Qt::ActiveWindowFocusReason);
else if (!focus && focusWindow == QGuiApplication::focusWindow())
m_focusLostTimer = startTimer(50);
}
@@ -732,7 +731,7 @@ void QQnxScreenEventHandler::handleGeometryPropertyEvent(screen_window_t window)
QWindowSystemInterface::handleGeometryChange(qtWindow, rect);
}
- qScreenEventDebug() << qtWindow << "moved to" << rect;
+ qCDebug(lcQpaScreenEvents) << qtWindow << "moved to" << rect;
}
void QQnxScreenEventHandler::timerEvent(QTimerEvent *event)
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventhandler.h b/src/plugins/platforms/qnx/qqnxscreeneventhandler.h
index d27186af9e..ba3579aaf7 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventhandler.h
+++ b/src/plugins/platforms/qnx/qqnxscreeneventhandler.h
@@ -5,11 +5,14 @@
#define QQNXSCREENEVENTHANDLER_H
#include <qpa/qwindowsysteminterface.h>
+#include <QtCore/QLoggingCategory>
#include <screen/screen.h>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaScreenEvents);
+
class QQnxIntegration;
class QQnxScreenEventFilter;
class QQnxScreenEventThread;
diff --git a/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp b/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp
index 69997e4ba0..6b4ffc3962 100644
--- a/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreeneventthread.cpp
@@ -14,12 +14,6 @@
#include <cctype>
-#if defined(QQNXSCREENEVENTTHREAD_DEBUG)
-#define qScreenEventThreadDebug qDebug
-#else
-#define qScreenEventThreadDebug QT_NO_QDEBUG_MACRO
-#endif
-
static const int c_screenCode = _PULSE_CODE_MINAVAIL + 0;
static const int c_armCode = _PULSE_CODE_MINAVAIL + 1;
static const int c_quitCode = _PULSE_CODE_MINAVAIL + 2;
@@ -74,7 +68,7 @@ QQnxScreenEventThread::~QQnxScreenEventThread()
void QQnxScreenEventThread::run()
{
- qScreenEventThreadDebug("screen event thread started");
+ qCDebug(lcQpaScreenEvents) << "Screen event thread started";
while (1) {
struct _pulse msg;
@@ -90,7 +84,7 @@ void QQnxScreenEventThread::run()
qWarning() << "MsgReceive error" << strerror(errno);
}
- qScreenEventThreadDebug("screen event thread stopped");
+ qCDebug(lcQpaScreenEvents) << "Screen event thread stopped";
}
void QQnxScreenEventThread::armEventsPending(int count)
@@ -134,10 +128,10 @@ void QQnxScreenEventThread::shutdown()
{
MsgSendPulse(m_connectionId, SIGEV_PULSE_PRIO_INHERIT, c_quitCode, 0);
- qScreenEventThreadDebug("screen event thread shutdown begin");
+ qCDebug(lcQpaScreenEvents) << "Screen event thread shutdown begin";
// block until thread terminates
wait();
- qScreenEventThreadDebug("screen event thread shutdown end");
+ qCDebug(lcQpaScreenEvents) << "Screen event thread shutdown end";
}
diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp
index b4650de315..5eceacef95 100644
--- a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp
+++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.cpp
@@ -18,14 +18,10 @@
#include <sys/types.h>
#include <unistd.h>
-#if defined(QQNXVIRTUALKEYBOARD_DEBUG)
-#define qVirtualKeyboardDebug qDebug
-#else
-#define qVirtualKeyboardDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaQnxVirtualKeyboard, "qt.qpa.qnx.virtualkeyboard");
+
const char *QQnxVirtualKeyboardPps::ms_PPSPath = "/pps/services/input/control";
const size_t QQnxVirtualKeyboardPps::ms_bufferSize = 2048;
@@ -45,7 +41,7 @@ QQnxVirtualKeyboardPps::~QQnxVirtualKeyboardPps()
void QQnxVirtualKeyboardPps::start()
{
- qVirtualKeyboardDebug("starting keyboard event processing");
+ qCDebug(lcQpaQnxVirtualKeyboard) << "Starting keyboard event processing";
if (!connect())
return;
}
@@ -90,8 +86,8 @@ bool QQnxVirtualKeyboardPps::connect()
m_fd = ::open(ms_PPSPath, O_RDWR);
if (m_fd == -1)
{
- qVirtualKeyboardDebug() << "Unable to open" << ms_PPSPath
- << ':' << strerror(errno);
+ qCDebug(lcQpaQnxVirtualKeyboard) << "Unable to open" << ms_PPSPath
+ << ':' << strerror(errno);
close();
return false;
}
@@ -128,7 +124,7 @@ void QQnxVirtualKeyboardPps::ppsDataReady()
{
qint64 nread = qt_safe_read(m_fd, m_buffer, ms_bufferSize - 1);
- qVirtualKeyboardDebug("keyboardMessage size: %lld", nread);
+ qCDebug(lcQpaQnxVirtualKeyboard, "keyboardMessage size: %lld", nread);
if (nread < 0){
connect(); // reconnect
return;
@@ -167,7 +163,7 @@ void QQnxVirtualKeyboardPps::ppsDataReady()
else if (strcmp(value, "info") == 0)
handleKeyboardInfoMessage();
else if (strcmp(value, "connect") == 0)
- qVirtualKeyboardDebug("Unhandled command 'connect'");
+ qCDebug(lcQpaQnxVirtualKeyboard, "Unhandled command 'connect'");
else
qCritical("QQnxVirtualKeyboard: Unexpected keyboard PPS msg value: %s", value ? value : "[null]");
} else if (pps_decoder_get_string(m_decoder, "res", &value) == PPS_DECODER_OK) {
@@ -194,12 +190,12 @@ void QQnxVirtualKeyboardPps::handleKeyboardInfoMessage()
}
setHeight(newHeight);
- qVirtualKeyboardDebug("size=%d", newHeight);
+ qCDebug(lcQpaQnxVirtualKeyboard, "size=%d", newHeight);
}
bool QQnxVirtualKeyboardPps::showKeyboard()
{
- qVirtualKeyboardDebug();
+ qCDebug(lcQpaQnxVirtualKeyboard) << Q_FUNC_INFO;
if (!prepareToSend())
return false;
@@ -221,7 +217,7 @@ bool QQnxVirtualKeyboardPps::showKeyboard()
bool QQnxVirtualKeyboardPps::hideKeyboard()
{
- qVirtualKeyboardDebug();
+ qCDebug(lcQpaQnxVirtualKeyboard) << Q_FUNC_INFO;
if (!prepareToSend())
return false;
diff --git a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h
index 88af284db3..8f1d390760 100644
--- a/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h
+++ b/src/plugins/platforms/qnx/qqnxvirtualkeyboardpps.h
@@ -5,11 +5,13 @@
#define VIRTUALKEYBOARDPPS_H
#include "qqnxabstractvirtualkeyboard.h"
+#include <QtCore/QLoggingCategory>
#include <sys/pps.h>
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaQnxVirtualKeyboard);
class QSocketNotifier;
diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp
index 5310ff3c65..3384932a8b 100644
--- a/src/plugins/platforms/qnx/qqnxwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxwindow.cpp
@@ -1,6 +1,8 @@
// Copyright (C) 2011 - 2013 BlackBerry Limited. All rights reserved.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
+
#include "qqnxglobal.h"
#include "qqnxwindow.h"
@@ -19,14 +21,10 @@
#include <errno.h>
-#if defined(QQNXWINDOW_DEBUG)
-#define qWindowDebug qDebug
-#else
-#define qWindowDebug QT_NO_QDEBUG_MACRO
-#endif
-
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window");
+
#define DECLARE_DEBUG_VAR(variable) \
static bool debug_ ## variable() \
{ static bool value = qgetenv("QNX_SCREEN_DEBUG").contains(QT_STRINGIFY(variable)); return value; }
@@ -123,7 +121,7 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW
m_windowState(Qt::WindowNoState),
m_firstActivateHandled(false)
{
- qWindowDebug() << "window =" << window << ", size =" << window->size();
+ qCDebug(lcQpaWindow) << "window =" << window << ", size =" << window->size();
QQnxScreen *platformScreen = static_cast<QQnxScreen *>(window->screen()->handle());
@@ -193,13 +191,13 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW
bool ok = false;
int pipeline = pipelineValue.toInt(&ok);
if (ok) {
- qWindowDebug() << "Set pipeline value to" << pipeline;
+ qCDebug(lcQpaWindow) << "Set pipeline value to" << pipeline;
Q_SCREEN_CHECKERROR(
screen_set_window_property_iv(m_window, SCREEN_PROPERTY_PIPELINE, &pipeline),
"Failed to set window pipeline");
} else {
- qWindowDebug() << "Invalid pipeline value:" << pipelineValue;
+ qCDebug(lcQpaWindow) << "Invalid pipeline value:" << pipelineValue;
}
}
@@ -229,7 +227,7 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, bool needRootW
if (debug > 0) {
Q_SCREEN_CHECKERROR(screen_set_window_property_iv(nativeHandle(), SCREEN_PROPERTY_DEBUG, &debug),
"Could not set SCREEN_PROPERTY_DEBUG");
- qWindowDebug() << "window SCREEN_PROPERTY_DEBUG= " << debug;
+ qCDebug(lcQpaWindow) << "window SCREEN_PROPERTY_DEBUG= " << debug;
}
}
@@ -246,7 +244,7 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, screen_window_
, m_parentGroupName(256, 0)
, m_isTopLevel(false)
{
- qWindowDebug() << "window =" << window << ", size =" << window->size();
+ qCDebug(lcQpaWindow) << "window =" << window << ", size =" << window->size();
collectWindowGroup();
@@ -267,7 +265,7 @@ QQnxWindow::QQnxWindow(QWindow *window, screen_context_t context, screen_window_
QQnxWindow::~QQnxWindow()
{
- qWindowDebug() << "window =" << window();
+ qCDebug(lcQpaWindow) << "window =" << window();
// Qt should have already deleted the children before deleting the parent.
Q_ASSERT(m_childWindows.size() == 0);
@@ -303,9 +301,9 @@ void QQnxWindow::setGeometry(const QRect &rect)
void QQnxWindow::setGeometryHelper(const QRect &rect)
{
- qWindowDebug() << "window =" << window()
- << ", (" << rect.x() << "," << rect.y()
- << "," << rect.width() << "," << rect.height() << ")";
+ qCDebug(lcQpaWindow) << "window =" << window()
+ << ", (" << rect.x() << "," << rect.y()
+ << "," << rect.width() << "," << rect.height() << ")";
// Call base class method
QPlatformWindow::setGeometry(rect);
@@ -333,7 +331,7 @@ void QQnxWindow::setGeometryHelper(const QRect &rect)
void QQnxWindow::setVisible(bool visible)
{
- qWindowDebug() << "window =" << window() << "visible =" << visible;
+ qCDebug(lcQpaWindow) << "window =" << window() << "visible =" << visible;
if (m_visible == visible || window()->type() == Qt::Desktop)
return;
@@ -372,7 +370,7 @@ void QQnxWindow::setVisible(bool visible)
void QQnxWindow::updateVisibility(bool parentVisible)
{
- qWindowDebug() << "parentVisible =" << parentVisible << "window =" << window();
+ qCDebug(lcQpaWindow) << "parentVisible =" << parentVisible << "window =" << window();
// Set window visibility
int val = (m_visible && parentVisible) ? 1 : 0;
Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_VISIBLE, &val),
@@ -384,7 +382,7 @@ void QQnxWindow::updateVisibility(bool parentVisible)
void QQnxWindow::setOpacity(qreal level)
{
- qWindowDebug() << "window =" << window() << "opacity =" << level;
+ qCDebug(lcQpaWindow) << "window =" << window() << "opacity =" << level;
// Set window global alpha
int val = (int)(level * 255);
Q_SCREEN_CHECKERROR(screen_set_window_property_iv(m_window, SCREEN_PROPERTY_GLOBAL_ALPHA, &val),
@@ -395,7 +393,7 @@ void QQnxWindow::setOpacity(qreal level)
void QQnxWindow::setExposed(bool exposed)
{
- qWindowDebug() << "window =" << window() << "expose =" << exposed;
+ qCDebug(lcQpaWindow) << "window =" << window() << "expose =" << exposed;
if (m_exposed != exposed) {
m_exposed = exposed;
@@ -410,7 +408,7 @@ bool QQnxWindow::isExposed() const
void QQnxWindow::setBufferSize(const QSize &size)
{
- qWindowDebug() << "window =" << window() << "size =" << size;
+ qCDebug(lcQpaWindow) << "window =" << window() << "size =" << size;
// libscreen fails when creating empty buffers
const QSize nonEmptySize = size.isEmpty() ? QSize(1, 1) : size;
@@ -477,7 +475,7 @@ void QQnxWindow::setBufferSize(const QSize &size)
void QQnxWindow::setScreen(QQnxScreen *platformScreen)
{
- qWindowDebug() << "window =" << window() << "platformScreen =" << platformScreen;
+ qCDebug(lcQpaWindow) << "window =" << window() << "platformScreen =" << platformScreen;
if (platformScreen == 0) { // The screen has been destroyed
m_screen = 0;
@@ -491,7 +489,7 @@ void QQnxWindow::setScreen(QQnxScreen *platformScreen)
return;
if (m_screen) {
- qWindowDebug("Moving window to different screen");
+ qCDebug(lcQpaWindow) << "Moving window to different screen";
m_screen->removeWindow(this);
if ((QQnxIntegration::instance()->options() & QQnxIntegration::RootWindow)) {
@@ -522,7 +520,7 @@ void QQnxWindow::setScreen(QQnxScreen *platformScreen)
void QQnxWindow::removeFromParent()
{
- qWindowDebug() << "window =" << window();
+ qCDebug(lcQpaWindow) << Q_FUNC_INFO << "window =" << window();
// Remove from old Hierarchy position
if (m_parentWindow) {
if (Q_UNLIKELY(!m_parentWindow->m_childWindows.removeAll(this)))
@@ -536,7 +534,7 @@ void QQnxWindow::removeFromParent()
void QQnxWindow::setParent(const QPlatformWindow *window)
{
- qWindowDebug() << "window =" << this->window() << "platformWindow =" << window;
+ qCDebug(lcQpaWindow) << "window =" << this->window() << "platformWindow =" << window;
// Cast away the const, we need to modify the hierarchy.
QQnxWindow* const newParent = static_cast<QQnxWindow*>(const_cast<QPlatformWindow*>(window));
@@ -568,7 +566,7 @@ void QQnxWindow::setParent(const QPlatformWindow *window)
void QQnxWindow::raise()
{
- qWindowDebug() << "window =" << window();
+ qCDebug(lcQpaWindow) << Q_FUNC_INFO << "window =" << window();
if (m_parentWindow) {
m_parentWindow->m_childWindows.removeAll(this);
@@ -582,7 +580,7 @@ void QQnxWindow::raise()
void QQnxWindow::lower()
{
- qWindowDebug() << "window =" << window();
+ qCDebug(lcQpaWindow) << Q_FUNC_INFO << "window =" << window();
if (m_parentWindow) {
m_parentWindow->m_childWindows.removeAll(this);
@@ -696,7 +694,7 @@ void QQnxWindow::setFocus(screen_window_t newFocusWindow)
void QQnxWindow::setWindowState(Qt::WindowStates state)
{
- qWindowDebug() << "state =" << state;
+ qCDebug(lcQpaWindow) << Q_FUNC_INFO << "state =" << state;
// Prevent two calls with Qt::WindowFullScreen from changing m_unmaximizedGeometry
if (m_windowState == state)
@@ -711,7 +709,7 @@ void QQnxWindow::setWindowState(Qt::WindowStates state)
void QQnxWindow::propagateSizeHints()
{
// nothing to do; silence base class warning
- qWindowDebug("ignored");
+ // qWindowDebug("ignored");
}
QPlatformScreen *QQnxWindow::screen() const
@@ -740,7 +738,7 @@ void QQnxWindow::minimize()
void QQnxWindow::setRotation(int rotation)
{
- qWindowDebug() << "angle =" << rotation;
+ qCDebug(lcQpaWindow) << Q_FUNC_INFO << "angle =" << rotation;
Q_SCREEN_CHECKERROR(
screen_set_window_property_iv(m_window, SCREEN_PROPERTY_ROTATION, &rotation),
"Failed to set window rotation");
@@ -816,7 +814,7 @@ void QQnxWindow::joinWindowGroup(const QByteArray &groupName)
{
bool changed = false;
- qWindowDebug() << "group:" << groupName;
+ qCDebug(lcQpaWindow) << Q_FUNC_INFO << "group:" << groupName;
// screen has this annoying habit of generating a CLOSE/CREATE when the owner context of
// the parent group moves a foreign window to another group that it also owns. The
diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h
index d302f22415..013ea342e4 100644
--- a/src/plugins/platforms/qnx/qqnxwindow.h
+++ b/src/plugins/platforms/qnx/qqnxwindow.h
@@ -8,6 +8,7 @@
#include "qqnxabstractcover.h"
#include <QtCore/QScopedPointer>
+#include <QtCore/QLoggingCategory>
#if !defined(QT_NO_OPENGL)
#include <EGL/egl.h>
@@ -17,6 +18,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaWindow);
+
// all surfaces double buffered
#define MAX_BUFFER_COUNT 2
diff --git a/src/plugins/platforms/vkkhrdisplay/qvkkhrdisplayvulkaninstance.cpp b/src/plugins/platforms/vkkhrdisplay/qvkkhrdisplayvulkaninstance.cpp
index 4d58e4154e..2e8d60209e 100644
--- a/src/plugins/platforms/vkkhrdisplay/qvkkhrdisplayvulkaninstance.cpp
+++ b/src/plugins/platforms/vkkhrdisplay/qvkkhrdisplayvulkaninstance.cpp
@@ -143,7 +143,7 @@ bool QVkKhrDisplayVulkanInstance::chooseDisplay()
j, (void *) mode.displayMode,
mode.parameters.visibleRegion.width, mode.parameters.visibleRegion.height,
mode.parameters.refreshRate);
- if (j == wantedModeIndex) {
+ if (j == wantedModeIndex && i == wantedDisplayIndex) {
m_displayMode = mode.displayMode;
m_width = mode.parameters.visibleRegion.width;
m_height = mode.parameters.visibleRegion.height;
diff --git a/src/plugins/platforms/wasm/CMakeLists.txt b/src/plugins/platforms/wasm/CMakeLists.txt
index d7c96afdaa..185b921a4f 100644
--- a/src/plugins/platforms/wasm/CMakeLists.txt
+++ b/src/plugins/platforms/wasm/CMakeLists.txt
@@ -32,9 +32,11 @@ qt_internal_add_plugin(QWasmIntegrationPlugin
qwasmtheme.cpp qwasmtheme.h
qwasmwindow.cpp qwasmwindow.h
qwasmwindowclientarea.cpp qwasmwindowclientarea.h
+ qwasmwindowtreenode.cpp qwasmwindowtreenode.h
qwasmwindownonclientarea.cpp qwasmwindownonclientarea.h
qwasminputcontext.cpp qwasminputcontext.h
qwasmwindowstack.cpp qwasmwindowstack.h
+ qwasmdrag.cpp qwasmdrag.h
DEFINES
QT_EGL_NO_X11
QT_NO_FOREACH
@@ -47,7 +49,6 @@ qt_internal_add_plugin(QWasmIntegrationPlugin
# Resources:
set(wasmfonts_resource_files
- "${QtBase_SOURCE_DIR}/src/3rdparty/wasm/Vera.ttf"
"${QtBase_SOURCE_DIR}/src/3rdparty/wasm/DejaVuSans.ttf"
"${QtBase_SOURCE_DIR}/src/3rdparty/wasm/DejaVuSansMono.ttf"
)
diff --git a/src/plugins/platforms/wasm/main.cpp b/src/plugins/platforms/wasm/main.cpp
index 1b430829ad..f32ef5aab8 100644
--- a/src/plugins/platforms/wasm/main.cpp
+++ b/src/plugins/platforms/wasm/main.cpp
@@ -6,6 +6,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::Literals::StringLiterals;
+
class QWasmIntegrationPlugin : public QPlatformIntegrationPlugin
{
Q_OBJECT
@@ -17,7 +19,7 @@ public:
QPlatformIntegration *QWasmIntegrationPlugin::create(const QString& system, const QStringList& paramList)
{
Q_UNUSED(paramList);
- if (!system.compare(QStringLiteral("wasm"), Qt::CaseInsensitive))
+ if (!system.compare("wasm"_L1, Qt::CaseInsensitive))
return new QWasmIntegration;
return nullptr;
diff --git a/src/plugins/platforms/wasm/qtloader.js b/src/plugins/platforms/wasm/qtloader.js
index 0419509098..8027dd8fa9 100644
--- a/src/plugins/platforms/wasm/qtloader.js
+++ b/src/plugins/platforms/wasm/qtloader.js
@@ -1,602 +1,301 @@
-// Copyright (C) 2018 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-// QtLoader provides javascript API for managing Qt application modules.
-//
-// QtLoader provides API on top of Emscripten which supports common lifecycle
-// tasks such as displaying placeholder content while the module downloads,
-// handing application exits, and checking for browser wasm support.
-//
-// There are two usage modes:
-// * Managed: QtLoader owns and manages the HTML display elements like
-// the loader and canvas.
-// * External: The embedding HTML page owns the display elements. QtLoader
-// provides event callbacks which the page reacts to.
-//
-// Managed mode usage:
-//
-// var config = {
-// containerElements : [$("container-id")];
-// }
-// var qtLoader = new QtLoader(config);
-// qtLoader.loadEmscriptenModule("applicationName");
-//
-// External mode usage:
-//
-// var config = {
-// canvasElements : [$("canvas-id")],
-// showLoader: function() {
-// loader.style.display = 'block'
-// canvas.style.display = 'hidden'
-// },
-// showCanvas: function() {
-// loader.style.display = 'hidden'
-// canvas.style.display = 'block'
-// return canvas;
-// }
-// }
-// var qtLoader = new QtLoader(config);
-// qtLoader.loadEmscriptenModule("applicationName");
-//
-// Config keys
-//
-// moduleConfig : {}
-// Emscripten module configuration
-// containerElements : [container-element, ...]
-// One or more HTML elements. QtLoader will display loader elements
-// on these while loading the application, and replace the loader with a
-// canvas on load complete.
-// canvasElements : [canvas-element, ...]
-// One or more canvas elements.
-// showLoader : function(status, containerElement)
-// Optional loading element constructor function. Implement to create
-// a custom loading screen. This function may be called multiple times,
-// while preparing the application binary. "status" is a string
-// containing the loading sub-status, and may be either "Downloading",
-// or "Compiling". The browser may be using streaming compilation, in
-// which case the wasm module is compiled during downloading and the
-// there is no separate compile step.
-// showCanvas : function(containerElement)
-// Optional canvas constructor function. Implement to create custom
-// canvas elements.
-// showExit : function(crashed, exitCode, containerElement)
-// Optional exited element constructor function.
-// showError : function(crashed, exitCode, containerElement)
-// Optional error element constructor function.
-// statusChanged : function(newStatus)
-// Optional callback called when the status of the app has changed
-//
-// path : <string>
-// Prefix path for wasm file, realative to the loading HMTL file.
-// restartMode : "DoNotRestart", "RestartOnExit", "RestartOnCrash"
-// Controls whether the application should be reloaded on exits. The default is "DoNotRestart"
-// restartType : "RestartModule", "ReloadPage"
-// restartLimit : <int>
-// Restart attempts limit. The default is 10.
-// stdoutEnabled : <bool>
-// stderrEnabled : <bool>
-// environment : <object>
-// key-value environment variable pairs.
-//
-// QtLoader object API
-//
-// webAssemblySupported : bool
-// webGLSupported : bool
-// canLoadQt : bool
-// Reports if WebAssembly and WebGL are supported. These are requirements for
-// running Qt applications.
-// loadEmscriptenModule(applicationName)
-// Loads the application from the given emscripten javascript module file and wasm file
-// status
-// One of "Created", "Loading", "Running", "Exited".
-// crashed
-// Set to true if there was an unclean exit.
-// exitCode
-// main()/emscripten_force_exit() return code. Valid on status change to
-// "Exited", iff crashed is false.
-// exitText
-// Abort/exit message.
-// addCanvasElement
-// Add canvas at run-time. Adds a corresponding QScreen,
-// removeCanvasElement
-// Remove canvas at run-time. Removes the corresponding QScreen.
-// resizeCanvasElement
-// Signals to the application that a canvas has been resized.
-// setFontDpi
-// Sets the logical font dpi for the application.
-// module
-// Returns the Emscripten module object, or undefined if the module
-// has not been created yet. Note that the module object becomes available
-// at the very end of the loading sequence, _after_ the transition from
-// Loading to Running occurs.
-
-
-// Forces the use of constructor on QtLoader instance.
-// This passthrough makes both the old-style:
-//
-// const loader = QtLoader(config);
-//
-// and the new-style:
-//
-// const loader = new QtLoader(config);
-//
-// instantiation types work.
-function QtLoader(config)
+/**
+ * Loads the instance of a WASM module.
+ *
+ * @param config May contain any key normally accepted by emscripten and the 'qt' extra key, with
+ * the following sub-keys:
+ * - environment: { [name:string] : string }
+ * environment variables set on the instance
+ * - onExit: (exitStatus: { text: string, code?: number, crashed: bool }) => void
+ * called when the application has exited for any reason. There are two cases:
+ * aborted: crashed is true, text contains an error message.
+ * exited: crashed is false, code contians the exit code.
+ *
+ * Note that by default Emscripten does not exit when main() returns. This behavior
+ * is controlled by the EXIT_RUNTIME linker flag; set "-s EXIT_RUNTIME=1" to make
+ * Emscripten tear down the runtime and exit when main() returns.
+ *
+ * - containerElements: HTMLDivElement[]
+ * Array of host elements for Qt screens. Each of these elements is mapped to a QScreen on
+ * launch.
+ * - fontDpi: number
+ * Specifies font DPI for the instance
+ * - onLoaded: () => void
+ * Called when the module has loaded, at the point in time where any loading placeholder
+ * should be hidden and the application window should be shown.
+ * - entryFunction: (emscriptenConfig: object) => Promise<EmscriptenModule>
+ * Qt always uses emscripten's MODULARIZE option. This is the MODULARIZE entry function.
+ * - module: Promise<WebAssembly.Module>
+ * The module to create the instance from (optional). Specifying the module allows optimizing
+ * use cases where several instances are created from a single WebAssembly source.
+ * - qtdir: string
+ * Path to Qt installation. This path will be used for loading Qt shared libraries and plugins.
+ * The path is set to 'qt' by default, and is relative to the path of the web page's html file.
+ * This property is not in use when static linking is used, since this build mode includes all
+ * libraries and plugins in the wasm file.
+ * - preload: [string]: Array of file paths to json-encoded files which specifying which files to preload.
+ * The preloaded files will be downloaded at application startup and copied to the in-memory file
+ * system provided by Emscripten.
+ *
+ * Each json file must contain an array of source, destination objects:
+ * [
+ * {
+ * "source": "path/to/source",
+ * "destination": "/path/to/destination"
+ * },
+ * ...
+ * ]
+ * The source path is relative to the html file path. The destination path must be
+ * an absolute path.
+ *
+ * $QTDIR may be used as a placeholder for the "qtdir" configuration property (see @qtdir), for instance:
+ * "source": "$QTDIR/plugins/imageformats/libqjpeg.so"
+ * - localFonts.requestPermission: bool
+ * Whether Qt should request for local fonts access permission on startup (default false).
+ * - localFonts.familiesCollection string
+ * Specifies a collection of local fonts to load. Possible values are:
+ * "NoFontFamilies" : Don't load any font families
+ * "DefaultFontFamilies" : A subset of available font families; currently the "web-safe" fonts (default).
+ * "AllFontFamilies" : All local font families (not reccomended)
+ * - localFonts.extraFamilies: [string]
+ * Adds additional font families to be loaded at startup.
+ *
+ * @return Promise<instance: EmscriptenModule>
+ * The promise is resolved when the module has been instantiated and its main function has been
+ * called.
+ *
+ * @see https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/emscripten for
+ * EmscriptenModule
+ */
+async function qtLoad(config)
{
- return new _QtLoader(config);
-}
-
-function _QtLoader(config)
-{
- const self = this;
-
- // The Emscripten module and module configuration object. The module
- // object is created in completeLoadEmscriptenModule().
- self.module = undefined;
- self.moduleConfig = config.moduleConfig || {};
-
- // Qt properties. These are propagated to the Emscripten module after
- // it has been created.
- self.qtContainerElements = undefined;
- self.qtFontDpi = 96;
-
- function webAssemblySupported() {
- return typeof WebAssembly !== "undefined"
- }
-
- function webGLSupported() {
- // We expect that WebGL is supported if WebAssembly is; however
- // the GPU may be blacklisted.
- try {
- var canvas = document.createElement("canvas");
- return !!(window.WebGLRenderingContext && (canvas.getContext("webgl") || canvas.getContext("experimental-webgl")));
- } catch (e) {
- return false;
+ const throwIfEnvUsedButNotExported = (instance, config) =>
+ {
+ const environment = config.environment;
+ if (!environment || Object.keys(environment).length === 0)
+ return;
+ const isEnvExported = typeof instance.ENV === 'object';
+ if (!isEnvExported)
+ throw new Error('ENV must be exported if environment variables are passed');
+ };
+
+ if (typeof config !== 'object')
+ throw new Error('config is required, expected an object');
+ if (typeof config.qt !== 'object')
+ throw new Error('config.qt is required, expected an object');
+ if (typeof config.qt.entryFunction !== 'function')
+ throw new Error('config.qt.entryFunction is required, expected a function');
+
+ config.qt.qtdir ??= 'qt';
+ config.qt.preload ??= [];
+
+ config.qtContainerElements = config.qt.containerElements;
+ delete config.qt.containerElements;
+ config.qtFontDpi = config.qt.fontDpi;
+ delete config.qt.fontDpi;
+
+ // Make Emscripten not call main(); this gives us more control over
+ // the startup sequence.
+ const originalNoInitialRun = config.noInitialRun;
+ const originalArguments = config.arguments;
+ config.noInitialRun = true;
+
+ // Used for rejecting a failed load's promise where emscripten itself does not allow it,
+ // like in instantiateWasm below. This allows us to throw in case of a load error instead of
+ // hanging on a promise to entry function, which emscripten unfortunately does.
+ let circuitBreakerReject;
+ const circuitBreaker = new Promise((_, reject) => { circuitBreakerReject = reject; });
+
+ // If module async getter is present, use it so that module reuse is possible.
+ if (config.qt.module) {
+ config.instantiateWasm = async (imports, successCallback) =>
+ {
+ try {
+ const module = await config.qt.module;
+ successCallback(
+ await WebAssembly.instantiate(module, imports), module);
+ } catch (e) {
+ circuitBreakerReject(e);
+ }
}
}
-
- function canLoadQt() {
- // The current Qt implementation requires WebAssembly (asm.js is not in use),
- // and also WebGL (there is no raster fallback).
- return webAssemblySupported() && webGLSupported();
- }
-
- function removeChildren(element) {
- while (element.firstChild) element.removeChild(element.firstChild);
- }
-
- function createCanvas() {
- var canvas = document.createElement("canvas");
- canvas.className = "QtCanvas";
- canvas.style.height = "100%";
- canvas.style.width = "100%";
-
- // Set contentEditable in order to enable clipboard events; hide the resulting focus frame.
- canvas.contentEditable = true;
- canvas.style.outline = "0px solid transparent";
- canvas.style.caretColor = "transparent";
- canvas.style.cursor = "default";
-
- return canvas;
- }
-
- // Set default state handler functions and create canvases if needed
- if (config.containerElements !== undefined) {
-
- config.canvasElements = config.containerElements.map(createCanvas);
-
- config.showError = config.showError || function(errorText, container) {
- removeChildren(container);
- var errorTextElement = document.createElement("text");
- errorTextElement.className = "QtError"
- errorTextElement.innerHTML = errorText;
- return errorTextElement;
+ const fetchJsonHelper = async path => (await fetch(path)).json();
+ const filesToPreload = (await Promise.all(config.qt.preload.map(fetchJsonHelper))).flat();
+ const qtPreRun = (instance) => {
+ // Copy qt.environment to instance.ENV
+ throwIfEnvUsedButNotExported(instance, config);
+ for (const [name, value] of Object.entries(config.qt.environment ?? {}))
+ instance.ENV[name] = value;
+
+ // Preload files from qt.preload
+ const makeDirs = (FS, filePath) => {
+ const parts = filePath.split("/");
+ let path = "/";
+ for (let i = 0; i < parts.length - 1; ++i) {
+ const part = parts[i];
+ if (part == "")
+ continue;
+ path += part + "/";
+ try {
+ FS.mkdir(path);
+ } catch (error) {
+ const EEXIST = 20;
+ if (error.errno != EEXIST)
+ throw error;
+ }
+ }
}
- config.showLoader = config.showLoader || function(loadingState, container) {
- removeChildren(container);
- var loadingText = document.createElement("text");
- loadingText.className = "QtLoading"
- loadingText.innerHTML = '<p><center> ${loadingState}...</center><p>';
- return loadingText;
- };
-
- config.showCanvas = config.showCanvas || function(canvas, container) {
- removeChildren(container);
+ const extractFilenameAndDir = (path) => {
+ const parts = path.split('/');
+ const filename = parts.pop();
+ const dir = parts.join('/');
+ return {
+ filename: filename,
+ dir: dir
+ };
}
-
- config.showExit = config.showExit || function(crashed, exitCode, container) {
- if (!crashed)
- return undefined;
-
- removeChildren(container);
- var fontSize = 54;
- var crashSymbols = ["\u{1F615}", "\u{1F614}", "\u{1F644}", "\u{1F928}", "\u{1F62C}",
- "\u{1F915}", "\u{2639}", "\u{1F62E}", "\u{1F61E}", "\u{1F633}"];
- var symbolIndex = Math.floor(Math.random() * crashSymbols.length);
- var errorHtml = `<font size='${fontSize}'> ${crashSymbols[symbolIndex]} </font>`
- var errorElement = document.createElement("text");
- errorElement.className = "QtExit"
- errorElement.innerHTML = errorHtml;
- return errorElement;
+ const preloadFile = (file) => {
+ makeDirs(instance.FS, file.destination);
+ const source = file.source.replace('$QTDIR', config.qt.qtdir);
+ const filenameAndDir = extractFilenameAndDir(file.destination);
+ instance.FS.createPreloadedFile(filenameAndDir.dir, filenameAndDir.filename, source, true, true);
}
+ const isFsExported = typeof instance.FS === 'object';
+ if (!isFsExported)
+ throw new Error('FS must be exported if preload is used');
+ filesToPreload.forEach(preloadFile);
}
- config.restartMode = config.restartMode || "DoNotRestart";
- config.restartLimit = config.restartLimit || 10;
-
- if (config.stdoutEnabled === undefined) config.stdoutEnabled = true;
- if (config.stderrEnabled === undefined) config.stderrEnabled = true;
-
- // Make sure config.path is defined and ends with "/" if needed
- if (config.path === undefined)
- config.path = "";
- if (config.path.length > 0 && !config.path.endsWith("/"))
- config.path = config.path.concat("/");
-
- if (config.environment === undefined)
- config.environment = {};
-
- var publicAPI = {};
- publicAPI.webAssemblySupported = webAssemblySupported();
- publicAPI.webGLSupported = webGLSupported();
- publicAPI.canLoadQt = canLoadQt();
- publicAPI.canLoadApplication = canLoadQt();
- publicAPI.status = undefined;
- publicAPI.loadEmscriptenModule = loadEmscriptenModule;
- publicAPI.addCanvasElement = addCanvasElement;
- publicAPI.removeCanvasElement = removeCanvasElement;
- publicAPI.resizeCanvasElement = resizeCanvasElement;
- publicAPI.setFontDpi = setFontDpi;
- publicAPI.fontDpi = fontDpi;
- publicAPI.module = module;
-
- self.restartCount = 0;
-
- function handleError(error) {
- self.error = error;
- setStatus("Error");
- console.error(error);
- }
-
- function fetchResource(filePath) {
- var fullPath = config.path + filePath;
- return fetch(fullPath).then(function(response) {
- if (!response.ok) {
- let err = response.status + " " + response.statusText + " " + response.url;
- handleError(err);
- return Promise.reject(err)
- } else {
- return response;
- }
- });
- }
-
- function fetchText(filePath) {
- return fetchResource(filePath).then(function(response) {
- return response.text();
- });
- }
+ if (!config.preRun)
+ config.preRun = [];
+ config.preRun.push(qtPreRun);
- function fetchThenCompileWasm(response) {
- return response.arrayBuffer().then(function(data) {
- self.loaderSubState = "Compiling";
- setStatus("Loading") // trigger loaderSubState update
- return WebAssembly.compile(data);
- });
- }
-
- function fetchCompileWasm(filePath) {
- return fetchResource(filePath).then(function(response) {
- if (typeof WebAssembly.compileStreaming !== "undefined") {
- self.loaderSubState = "Downloading/Compiling";
- setStatus("Loading");
- return WebAssembly.compileStreaming(response).catch(function(error) {
- // compileStreaming may/will fail if the server does not set the correct
- // mime type (application/wasm) for the wasm file. Fall back to fetch,
- // then compile in this case.
- return fetchThenCompileWasm(response);
- });
- } else {
- // Fall back to fetch, then compile if compileStreaming is not supported
- return fetchThenCompileWasm(response);
- }
- });
+ const originalOnRuntimeInitialized = config.onRuntimeInitialized;
+ config.onRuntimeInitialized = () => {
+ originalOnRuntimeInitialized?.();
+ config.qt.onLoaded?.();
}
- function loadEmscriptenModule(applicationName) {
-
- // Loading in qtloader.js goes through four steps:
- // 1) Check prerequisites
- // 2) Download resources
- // 3) Configure the emscripten Module object
- // 4) Start the emcripten runtime, after which emscripten takes over
-
- // Check for Wasm & WebGL support; set error and return before downloading resources if missing
- if (!webAssemblySupported()) {
- handleError("Error: WebAssembly is not supported");
- return;
- }
- if (!webGLSupported()) {
- handleError("Error: WebGL is not supported");
- return;
- }
-
- // Continue waiting if loadEmscriptenModule() is called again
- if (publicAPI.status == "Loading")
- return;
- self.loaderSubState = "Downloading";
- setStatus("Loading");
-
- // Fetch emscripten generated javascript runtime
- var emscriptenModuleSource = undefined
- var emscriptenModuleSourcePromise = fetchText(applicationName + ".js").then(function(source) {
- emscriptenModuleSource = source
- });
-
- // Fetch and compile wasm module
- var wasmModule = undefined;
- var wasmModulePromise = fetchCompileWasm(applicationName + ".wasm").then(function (module) {
- wasmModule = module;
- });
-
- // Wait for all resources ready
- Promise.all([emscriptenModuleSourcePromise, wasmModulePromise]).then(function(){
- completeLoadEmscriptenModule(applicationName, emscriptenModuleSource, wasmModule);
- }).catch(function(error) {
- handleError(error);
- // An error here is fatal, abort
- self.moduleConfig.onAbort(error)
- });
+ const originalLocateFile = config.locateFile;
+ config.locateFile = filename => {
+ const originalLocatedFilename = originalLocateFile ? originalLocateFile(filename) : filename;
+ if (originalLocatedFilename.startsWith('libQt6'))
+ return `${config.qt.qtdir}/lib/${originalLocatedFilename}`;
+ return originalLocatedFilename;
}
- function completeLoadEmscriptenModule(applicationName, emscriptenModuleSource, wasmModule) {
+ let onExitCalled = false;
+ const originalOnExit = config.onExit;
+ config.onExit = code => {
+ originalOnExit?.();
- // The wasm binary has been compiled into a module during resource download,
- // and is ready to be instantiated. Define the instantiateWasm callback which
- // emscripten will call to create the instance.
- self.moduleConfig.instantiateWasm = function(imports, successCallback) {
- WebAssembly.instantiate(wasmModule, imports).then(function(instance) {
- successCallback(instance, wasmModule);
- }, function(error) {
- handleError(error)
+ if (!onExitCalled) {
+ onExitCalled = true;
+ config.qt.onExit?.({
+ code,
+ crashed: false
});
- return {};
- };
-
- self.moduleConfig.locateFile = self.moduleConfig.locateFile || function(filename) {
- return config.path + filename;
- };
-
- // Attach status callbacks
- self.moduleConfig.setStatus = self.moduleConfig.setStatus || function(text) {
- // Currently the only usable status update from this function
- // is "Running..."
- if (text.startsWith("Running"))
- setStatus("Running");
- };
- self.moduleConfig.monitorRunDependencies = self.moduleConfig.monitorRunDependencies || function(left) {
- // console.log("monitorRunDependencies " + left)
- };
-
- // Attach standard out/err callbacks.
- self.moduleConfig.print = self.moduleConfig.print || function(text) {
- if (config.stdoutEnabled)
- console.log(text)
- };
- self.moduleConfig.printErr = self.moduleConfig.printErr || function(text) {
- if (config.stderrEnabled)
- console.warn(text)
- };
-
- // Error handling: set status to "Exited", update crashed and
- // exitCode according to exit type.
- // Emscripten will typically call printErr with the error text
- // as well. Note that emscripten may also throw exceptions from
- // async callbacks. These should be handled in window.onerror by user code.
- self.moduleConfig.onAbort = self.moduleConfig.onAbort || function(text) {
- publicAPI.crashed = true;
- publicAPI.exitText = text;
- setStatus("Exited");
- };
- self.moduleConfig.quit = self.moduleConfig.quit || function(code, exception) {
-
- // Emscripten (and Qt) supports exiting from main() while keeping the app
- // running. Don't transition into the "Exited" state for clean exits.
- if (code == 0)
- return;
-
- if (exception.name == "ExitStatus") {
- // Clean exit with code
- publicAPI.exitText = undefined
- publicAPI.exitCode = code;
- } else {
- publicAPI.exitText = exception.toString();
- publicAPI.crashed = true;
- // Print stack trace to console
- console.log(exception);
- }
- setStatus("Exited");
- };
-
- self.moduleConfig.preRun = self.moduleConfig.preRun || []
- self.moduleConfig.preRun.push(function(module) {
- // Set environment variables
- for (var [key, value] of Object.entries(config.environment)) {
- module.ENV[key.toUpperCase()] = value;
- }
- // Propagate Qt module properties
- module.qtContainerElements = self.qtContainerElements;
- module.qtFontDpi = self.qtFontDpi;
- });
-
- self.moduleConfig.mainScriptUrlOrBlob = new Blob([emscriptenModuleSource], {type: 'text/javascript'});
-
- self.qtContainerElements = config.canvasElements;
-
- config.restart = function() {
-
- // Restart by reloading the page. This will wipe all state which means
- // reload loops can't be prevented.
- if (config.restartType == "ReloadPage") {
- location.reload();
- }
-
- // Restart by readling the emscripten app module.
- ++self.restartCount;
- if (self.restartCount > config.restartLimit) {
- handleError("Error: This application has crashed too many times and has been disabled. Reload the page to try again.");
- return;
- }
- loadEmscriptenModule(applicationName);
- };
-
- publicAPI.exitCode = undefined;
- publicAPI.exitText = undefined;
- publicAPI.crashed = false;
-
- // Load the Emscripten application module. This is done by eval()'ing the
- // javascript runtime generated by Emscripten, and then calling
- // createQtAppInstance(), which was added to the global scope.
- eval(emscriptenModuleSource);
- createQtAppInstance(self.moduleConfig).then(function(module) {
- self.module = module;
- });
- }
-
- function setErrorContent() {
- if (config.containerElements === undefined) {
- if (config.showError !== undefined)
- config.showError(self.error);
- return;
- }
-
- for (container of config.containerElements) {
- var errorElement = config.showError(self.error, container);
- container.appendChild(errorElement);
}
}
- function setLoaderContent() {
- if (config.containerElements === undefined) {
- if (config.showLoader !== undefined)
- config.showLoader(self.loaderSubState);
- return;
- }
-
- for (container of config.containerElements) {
- var loaderElement = config.showLoader(self.loaderSubState, container);
- container.appendChild(loaderElement);
+ const originalOnAbort = config.onAbort;
+ config.onAbort = text =>
+ {
+ originalOnAbort?.();
+
+ if (!onExitCalled) {
+ onExitCalled = true;
+ config.qt.onExit?.({
+ text,
+ crashed: true
+ });
}
- }
-
- function setCanvasContent() {
- if (config.containerElements === undefined) {
- if (config.showCanvas !== undefined)
- config.showCanvas();
+ };
+
+ // Call app/emscripten module entry function. It may either come from the emscripten
+ // runtime script or be customized as needed.
+ let instance;
+ try {
+ instance = await Promise.race(
+ [circuitBreaker, config.qt.entryFunction(config)]);
+
+ // Call main after creating the instance. We've opted into manually
+ // calling main() by setting noInitialRun in the config. Thie Works around
+ // issue where Emscripten suppresses all exceptions thrown during main.
+ if (!originalNoInitialRun)
+ instance.callMain(originalArguments);
+ } catch (e) {
+ // If this is the exception thrown by app.exec() then that is a normal
+ // case and we suppress it.
+ if (e == "unwind") // not much to go on
return;
- }
- for (var i = 0; i < config.containerElements.length; ++i) {
- var container = config.containerElements[i];
- var canvas = config.canvasElements[i];
- config.showCanvas(canvas, container);
- container.appendChild(canvas);
+ if (!onExitCalled) {
+ onExitCalled = true;
+ config.qt.onExit?.({
+ text: e.message,
+ crashed: true
+ });
}
+ throw e;
}
- function setExitContent() {
-
- // publicAPI.crashed = true;
-
- if (publicAPI.status != "Exited")
- return;
-
- if (config.containerElements === undefined) {
- if (config.showExit !== undefined)
- config.showExit(publicAPI.crashed, publicAPI.exitCode);
- return;
- }
-
- if (!publicAPI.crashed)
- return;
+ return instance;
+}
- for (container of config.containerElements) {
- var loaderElement = config.showExit(publicAPI.crashed, publicAPI.exitCode, container);
- if (loaderElement !== undefined)
- container.appendChild(loaderElement);
- }
+// Compatibility API. This API is deprecated,
+// and will be removed in a future version of Qt.
+function QtLoader(qtConfig) {
+
+ const warning = 'Warning: The QtLoader API is deprecated and will be removed in ' +
+ 'a future version of Qt. Please port to the new qtLoad() API.';
+ console.warn(warning);
+
+ let emscriptenConfig = qtConfig.moduleConfig || {}
+ qtConfig.moduleConfig = undefined;
+ const showLoader = qtConfig.showLoader;
+ qtConfig.showLoader = undefined;
+ const showError = qtConfig.showError;
+ qtConfig.showError = undefined;
+ const showExit = qtConfig.showExit;
+ qtConfig.showExit = undefined;
+ const showCanvas = qtConfig.showCanvas;
+ qtConfig.showCanvas = undefined;
+ if (qtConfig.canvasElements) {
+ qtConfig.containerElements = qtConfig.canvasElements
+ qtConfig.canvasElements = undefined;
+ } else {
+ qtConfig.containerElements = qtConfig.containerElements;
+ qtConfig.containerElements = undefined;
}
-
- var committedStatus = undefined;
- function handleStatusChange() {
- if (publicAPI.status != "Loading" && committedStatus == publicAPI.status)
- return;
- committedStatus = publicAPI.status;
-
- if (publicAPI.status == "Error") {
- setErrorContent();
- } else if (publicAPI.status == "Loading") {
- setLoaderContent();
- } else if (publicAPI.status == "Running") {
- setCanvasContent();
- } else if (publicAPI.status == "Exited") {
- if (config.restartMode == "RestartOnExit" ||
- config.restartMode == "RestartOnCrash" && publicAPI.crashed) {
- committedStatus = undefined;
- config.restart();
- } else {
- setExitContent();
+ emscriptenConfig.qt = qtConfig;
+
+ let qtloader = {
+ exitCode: undefined,
+ exitText: "",
+ loadEmscriptenModule: _name => {
+ try {
+ qtLoad(emscriptenConfig);
+ } catch (e) {
+ showError?.(e.message);
}
}
-
- // Send status change notification
- if (config.statusChanged)
- config.statusChanged(publicAPI.status);
}
- function setStatus(status) {
- if (status != "Loading" && publicAPI.status == status)
- return;
- publicAPI.status = status;
-
- window.setTimeout(function() { handleStatusChange(); }, 0);
- }
-
- function addCanvasElement(element) {
- if (publicAPI.status == "Running")
- self.module.qtAddContainerElement(element);
- else
- console.log("Error: addCanvasElement can only be called in the Running state");
+ qtConfig.onLoaded = () => {
+ showCanvas?.();
}
- function removeCanvasElement(element) {
- if (publicAPI.status == "Running")
- self.module.qtRemoveContainerElement(element);
- else
- console.log("Error: removeCanvasElement can only be called in the Running state");
+ qtConfig.onExit = exit => {
+ qtloader.exitCode = exit.code
+ qtloader.exitText = exit.text;
+ showExit?.();
}
- function resizeCanvasElement(element) {
- if (publicAPI.status == "Running")
- self.module.qtResizeContainerElement(element);
- }
-
- function setFontDpi(dpi) {
- self.qtFontDpi = dpi;
- if (publicAPI.status == "Running")
- self.module.qtUpdateDpi();
- }
+ showLoader?.("Loading");
- function fontDpi() {
- return self.qtFontDpi;
- }
-
- function module() {
- return self.module;
- }
-
- setStatus("Created");
-
- return publicAPI;
-}
+ return qtloader;
+};
diff --git a/src/plugins/platforms/wasm/qwasmaccessibility.cpp b/src/plugins/platforms/wasm/qwasmaccessibility.cpp
index 072f65aa87..4c3cb46ba3 100644
--- a/src/plugins/platforms/wasm/qwasmaccessibility.cpp
+++ b/src/plugins/platforms/wasm/qwasmaccessibility.cpp
@@ -5,10 +5,12 @@
#include "qwasmscreen.h"
#include "qwasmwindow.h"
#include "qwasmintegration.h"
-#include <QtGui/private/qaccessiblebridgeutils_p.h>
-
#include <QtGui/qwindow.h>
+#if QT_CONFIG(accessibility)
+
+#include <QtGui/private/qaccessiblebridgeutils_p.h>
+
Q_LOGGING_CATEGORY(lcQpaAccessibility, "qt.qpa.accessibility")
// Qt WebAssembly a11y backend
@@ -21,13 +23,6 @@ Q_LOGGING_CATEGORY(lcQpaAccessibility, "qt.qpa.accessibility")
// events. In addition or alternatively, we could also walk the accessibility tree
// from setRootObject().
-namespace {
-QWasmWindow *asWasmWindow(QWindow *window)
-{
- return static_cast<QWasmWindow*>(window->handle());
-}
-} // namespace
-
QWasmAccessibility::QWasmAccessibility()
{
@@ -105,7 +100,8 @@ void QWasmAccessibility::enableAccessibility()
emscripten::val QWasmAccessibility::getContainer(QWindow *window)
{
- return window ? asWasmWindow(window)->a11yContainer() : emscripten::val::undefined();
+ return window ? static_cast<QWasmWindow *>(window->handle())->a11yContainer()
+ : emscripten::val::undefined();
}
emscripten::val QWasmAccessibility::getContainer(QAccessibleInterface *iface)
@@ -244,12 +240,21 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac
case QAccessible::Dialog: {
element = document.call<emscripten::val>("createElement", std::string("dialog"));
}break;
- case QAccessible::ToolBar:
- case QAccessible::ButtonMenu: {
+ case QAccessible::ToolBar:{
element = document.call<emscripten::val>("createElement", std::string("div"));
QString text = iface->text(QAccessible::Name);
- element.call<void>("setAttribute", std::string("role"), std::string("widget"));
+ element.call<void>("setAttribute", std::string("role"), std::string("toolbar"));
+ element.call<void>("setAttribute", std::string("title"), text.toStdString());
+ element.call<void>("addEventListener", emscripten::val("click"),
+ emscripten::val::module_property("qtEventReceived"), true);
+ }break;
+ case QAccessible::MenuItem:
+ case QAccessible::ButtonMenu: {
+ element = document.call<emscripten::val>("createElement", std::string("button"));
+ QString text = iface->text(QAccessible::Name);
+
+ element.call<void>("setAttribute", std::string("role"), std::string("menuitem"));
element.call<void>("setAttribute", std::string("title"), text.toStdString());
element.call<void>("addEventListener", emscripten::val("click"),
emscripten::val::module_property("qtEventReceived"), true);
@@ -258,12 +263,14 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac
case QAccessible::PopupMenu: {
element = document.call<emscripten::val>("createElement",std::string("div"));
QString text = iface->text(QAccessible::Name);
- element.call<void>("setAttribute", std::string("role"), std::string("widget"));
+ element.call<void>("setAttribute", std::string("role"), std::string("menubar"));
element.call<void>("setAttribute", std::string("title"), text.toStdString());
for (int i = 0; i < iface->childCount(); ++i) {
- ensureHtmlElement(iface->child(i));
- setHtmlElementTextName(iface->child(i));
- setHtmlElementGeometry(iface->child(i));
+ emscripten::val childElement = emscripten::val::undefined();
+ childElement= ensureHtmlElement(iface->child(i));
+ childElement.call<void>("setAttribute", std::string("aria-owns"), text.toStdString());
+ setHtmlElementTextName(iface->child(i));
+ setHtmlElementGeometry(iface->child(i));
}
}break;
case QAccessible::EditableText: {
@@ -367,12 +374,21 @@ void QWasmAccessibility::setHtmlElementTextNameLE(QAccessibleInterface *iface) {
element.set("innerHTML", value.toStdString());
}
+void QWasmAccessibility::setHtmlElementDescription(QAccessibleInterface *iface) {
+ emscripten::val element = ensureHtmlElement(iface);
+ QString desc = iface->text(QAccessible::Description);
+ element.call<void>("setAttribute", std::string("aria-description"), desc.toStdString());
+}
+
void QWasmAccessibility::handleStaticTextUpdate(QAccessibleEvent *event)
{
switch (event->type()) {
case QAccessible::NameChanged: {
setHtmlElementTextName(event->accessibleInterface());
} break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
default:
qCDebug(lcQpaAccessibility) << "TODO: implement handleStaticTextUpdate for event" << event->type();
break;
@@ -391,7 +407,9 @@ void QWasmAccessibility::handleLineEditUpdate(QAccessibleEvent *event) {
case QAccessible::TextCaretMoved: {
setHtmlElementTextNameLE(event->accessibleInterface());
} break;
-
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
default:
qCDebug(lcQpaAccessibility) << "TODO: implement handleLineEditUpdate for event" << event->type();
break;
@@ -402,13 +420,11 @@ void QWasmAccessibility::handleEventFromHtmlElement(const emscripten::val event)
{
QAccessibleInterface *iface = m_elements.key(event["target"]);
-
if (iface == nullptr) {
return;
} else {
QString eventType = QString::fromStdString(event["type"].as<std::string>());
const auto& actionNames = QAccessibleBridgeUtils::effectiveActionNames(iface);
-
if (actionNames.contains(QAccessibleActionInterface::pressAction())) {
iface->actionInterface()->doAction(QAccessibleActionInterface::pressAction());
@@ -426,8 +442,11 @@ void QWasmAccessibility::handleEventFromHtmlElement(const emscripten::val event)
} else if (eventType == "input") {
- if (iface->editableTextInterface()) {
- std::string insertText = event["target"]["value"].as<std::string>();
+ // as EditableTextInterface is not implemented in qml accessibility
+ // so we need to check the role for text to update in the textbox during accessibility
+
+ if (iface->editableTextInterface() || iface->role() == QAccessible::EditableText) {
+ std::string insertText = event["target"]["value"].as<std::string>();
iface->setText(QAccessible::Value, QString::fromStdString(insertText));
}
}
@@ -452,6 +471,9 @@ void QWasmAccessibility::handleCheckBoxUpdate(QAccessibleEvent *event)
bool checkedString = accessible->state().checked ? true : false;
element.call<void>("setAttribute", std::string("checked"), checkedString);
} break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
default:
qCDebug(lcQpaAccessibility) << "TODO: implement handleCheckBoxUpdate for event" << event->type();
break;
@@ -468,6 +490,9 @@ void QWasmAccessibility::handleToolUpdate(QAccessibleEvent *event)
emscripten::val element = ensureHtmlElement(iface);
element.call<void>("setAttribute", std::string("title"), text.toStdString());
} break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
default:
qCDebug(lcQpaAccessibility) << "TODO: implement handleToolUpdate for event" << event->type();
break;
@@ -479,6 +504,7 @@ void QWasmAccessibility::handleMenuUpdate(QAccessibleEvent *event)
QString text = iface->text(QAccessible::Name);
QString desc = iface->text(QAccessible::Description);
switch (event->type()) {
+ case QAccessible::Focus:
case QAccessible::NameChanged:
case QAccessible::MenuStart ://"TODO: To implement later
case QAccessible::PopupMenuStart://"TODO: To implement later
@@ -486,6 +512,9 @@ void QWasmAccessibility::handleMenuUpdate(QAccessibleEvent *event)
emscripten::val element = ensureHtmlElement(iface);
element.call<void>("setAttribute", std::string("title"), text.toStdString());
} break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
default:
qCDebug(lcQpaAccessibility) << "TODO: implement handleMenuUpdate for event" << event->type();
break;
@@ -500,7 +529,9 @@ void QWasmAccessibility::handleDialogUpdate(QAccessibleEvent *event) {
case QAccessible::StateChanged: {
setHtmlElementTextName(event->accessibleInterface());
} break;
-
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
default:
qCDebug(lcQpaAccessibility) << "TODO: implement handleLineEditUpdate for event" << event->type();
break;
@@ -518,6 +549,7 @@ void QWasmAccessibility::populateAccessibilityTree(QAccessibleInterface *iface)
setHtmlElementVisibility(iface, visible);
setHtmlElementGeometry(iface);
setHtmlElementTextName(iface);
+ setHtmlElementDescription(iface);
for (int i = 0; i < iface->childCount(); ++i)
populateAccessibilityTree(iface->child(i));
@@ -536,6 +568,9 @@ void QWasmAccessibility::handleRadioButtonUpdate(QAccessibleEvent *event)
std::string checkedString = accessible->state().checked ? "true" : "false";
element.call<void>("setAttribute", std::string("checked"), checkedString);
} break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
default:
qDebug() << "TODO: implement handleRadioButtonUpdate for event" << event->type();
break;
@@ -555,6 +590,9 @@ void QWasmAccessibility::handleSpinBoxUpdate(QAccessibleEvent *event)
std::string valueString = accessible->valueInterface()->currentValue().toString().toStdString();
element.call<void>("setAttribute", std::string("value"), valueString);
} break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
default:
qDebug() << "TODO: implement handleSpinBoxUpdate for event" << event->type();
break;
@@ -574,6 +612,9 @@ void QWasmAccessibility::handleSliderUpdate(QAccessibleEvent *event)
std::string valueString = accessible->valueInterface()->currentValue().toString().toStdString();
element.call<void>("setAttribute", std::string("value"), valueString);
} break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
default:
qDebug() << "TODO: implement handleSliderUpdate for event" << event->type();
break;
@@ -593,6 +634,9 @@ void QWasmAccessibility::handleScrollBarUpdate(QAccessibleEvent *event)
std::string valueString = accessible->valueInterface()->currentValue().toString().toStdString();
element.call<void>("setAttribute", std::string("aria-valuenow"), valueString);
} break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
default:
qDebug() << "TODO: implement handleSliderUpdate for event" << event->type();
break;
@@ -609,6 +653,9 @@ void QWasmAccessibility::handlePageTabUpdate(QAccessibleEvent *event)
case QAccessible::Focus: {
setHtmlElementTextName(event->accessibleInterface());
} break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
default:
qDebug() << "TODO: implement handlePageTabUpdate for event" << event->type();
break;
@@ -624,6 +671,9 @@ void QWasmAccessibility::handlePageTabListUpdate(QAccessibleEvent *event)
case QAccessible::Focus: {
setHtmlElementTextName(event->accessibleInterface());
} break;
+ case QAccessible::DescriptionChanged: {
+ setHtmlElementDescription(event->accessibleInterface());
+ } break;
default:
qDebug() << "TODO: implement handlePageTabUpdate for event" << event->type();
break;
@@ -645,12 +695,12 @@ void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
// https://doc.qt.io/qt-5/qaccessible.html#Event-enum
switch (event->type()) {
case QAccessible::ObjectShow:
-
setHtmlElementVisibility(iface, true);
// Sync up properties on show;
setHtmlElementGeometry(iface);
setHtmlElementTextName(iface);
+ setHtmlElementDescription(iface);
return;
break;
@@ -735,3 +785,5 @@ void QWasmAccessibility::onHtmlEventReceived(emscripten::val event)
EMSCRIPTEN_BINDINGS(qtButtonEvent) {
function("qtEventReceived", &QWasmAccessibility::onHtmlEventReceived);
}
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/wasm/qwasmaccessibility.h b/src/plugins/platforms/wasm/qwasmaccessibility.h
index dd9770179a..c4be7f0d72 100644
--- a/src/plugins/platforms/wasm/qwasmaccessibility.h
+++ b/src/plugins/platforms/wasm/qwasmaccessibility.h
@@ -4,6 +4,11 @@
#ifndef QWASMACCESIBILITY_H
#define QWASMACCESIBILITY_H
+#include <QtCore/qtconfigmacros.h>
+#include <QtGui/qtguiglobal.h>
+
+#if QT_CONFIG(accessibility)
+
#include <QtCore/qhash.h>
#include <private/qstdweb_p.h>
#include <qpa/qplatformaccessibility.h>
@@ -46,6 +51,7 @@ private:
void setHtmlElementGeometry(emscripten::val element, QRect geometry);
void setHtmlElementTextName(QAccessibleInterface *iface);
void setHtmlElementTextNameLE(QAccessibleInterface *iface);
+ void setHtmlElementDescription(QAccessibleInterface *iface);
void handleStaticTextUpdate(QAccessibleEvent *event);
void handleButtonUpdate(QAccessibleEvent *event);
@@ -81,4 +87,6 @@ private:
};
+#endif // QT_CONFIG(accessibility)
+
#endif
diff --git a/src/plugins/platforms/wasm/qwasmbackingstore.cpp b/src/plugins/platforms/wasm/qwasmbackingstore.cpp
index e962592862..a3c1ae8a50 100644
--- a/src/plugins/platforms/wasm/qwasmbackingstore.cpp
+++ b/src/plugins/platforms/wasm/qwasmbackingstore.cpp
@@ -4,6 +4,7 @@
#include "qwasmbackingstore.h"
#include "qwasmwindow.h"
#include "qwasmcompositor.h"
+#include "qwasmdom.h"
#include <QtGui/qpainter.h>
#include <QtGui/qbackingstore.h>
@@ -75,37 +76,8 @@ void QWasmBackingStore::updateTexture(QWasmWindow *window)
clippedDpiScaledRegion |= r;
}
- for (const QRect &dirtyRect : clippedDpiScaledRegion) {
- constexpr int BytesPerColor = 4;
- if (dirtyRect.width() == imageRect.width()) {
- // Copy a contiguous chunk of memory
- // ...............
- // OOOOOOOOOOOOOOO
- // OOOOOOOOOOOOOOO -> image data
- // OOOOOOOOOOOOOOO
- // ...............
- auto imageMemory = emscripten::typed_memory_view(dirtyRect.width() * dirtyRect.height()
- * BytesPerColor,
- m_image.constScanLine(dirtyRect.y()));
- m_webImageDataArray["data"].call<void>("set", imageMemory);
- } else {
- // Go through the scanlines manually to set the individual lines in bulk. This is
- // marginally less performant than the above.
- // ...............
- // ...OOOOOOOOO... r = 0 -> image data
- // ...OOOOOOOOO... r = 1 -> image data
- // ...OOOOOOOOO... r = 2 -> image data
- // ...............
- for (int r = 0; r < dirtyRect.height(); ++r) {
- auto scanlineMemory = emscripten::typed_memory_view(
- dirtyRect.width() * 4,
- m_image.constScanLine(r) + BytesPerColor * dirtyRect.x());
- m_webImageDataArray["data"].call<void>("set", scanlineMemory,
- (r * dirtyRect.width() + dirtyRect.x())
- * BytesPerColor);
- }
- }
- }
+ for (const QRect &dirtyRect : clippedDpiScaledRegion)
+ dom::drawImageToWebImageDataArray(m_image, m_webImageDataArray, dirtyRect);
m_dirty = QRegion();
}
diff --git a/src/plugins/platforms/wasm/qwasmbase64iconstore.h b/src/plugins/platforms/wasm/qwasmbase64iconstore.h
index 6150ea19da..89704f2d2c 100644
--- a/src/plugins/platforms/wasm/qwasmbase64iconstore.h
+++ b/src/plugins/platforms/wasm/qwasmbase64iconstore.h
@@ -4,6 +4,7 @@
#ifndef QWASMBASE64IMAGESTORE_H
#define QWASMBASE64IMAGESTORE_H
+#include <string>
#include <string_view>
#include <QtCore/qtconfigmacros.h>
diff --git a/src/plugins/platforms/wasm/qwasmclipboard.cpp b/src/plugins/platforms/wasm/qwasmclipboard.cpp
index c33f39d470..1aa3ffa5b3 100644
--- a/src/plugins/platforms/wasm/qwasmclipboard.cpp
+++ b/src/plugins/platforms/wasm/qwasmclipboard.cpp
@@ -27,10 +27,10 @@ static void commonCopyEvent(val event)
// doing it this way seems to sanitize the text better that calling data() like down below
if (_mimes->hasText()) {
event["clipboardData"].call<void>("setData", val("text/plain"),
- _mimes->text().toJsString());
+ _mimes->text().toEcmaString());
}
if (_mimes->hasHtml()) {
- event["clipboardData"].call<void>("setData", val("text/html"), _mimes->html().toJsString());
+ event["clipboardData"].call<void>("setData", val("text/html"), _mimes->html().toEcmaString());
}
for (auto mimetype : _mimes->formats()) {
@@ -38,7 +38,7 @@ static void commonCopyEvent(val event)
continue;
QByteArray ba = _mimes->data(mimetype);
if (!ba.isEmpty())
- event["clipboardData"].call<void>("setData", mimetype.toJsString(),
+ event["clipboardData"].call<void>("setData", mimetype.toEcmaString(),
val(ba.constData()));
}
@@ -70,25 +70,7 @@ static void qClipboardPasteTo(val event)
{
event.call<void>("preventDefault"); // prevent browser from handling drop event
- static std::shared_ptr<qstdweb::CancellationFlag> readDataCancellation = nullptr;
- readDataCancellation = qstdweb::readDataTransfer(
- event["clipboardData"],
- [](QByteArray fileContent) {
- QImage image;
- image.loadFromData(fileContent, nullptr);
- return image;
- },
- [event](std::unique_ptr<QMimeData> data) {
- if (data->formats().isEmpty())
- return;
-
- // Persist clipboard data so that the app can read it when handling the CTRL+V
- QWasmIntegration::get()->clipboard()->QPlatformClipboard::setMimeData(
- data.release(), QClipboard::Clipboard);
-
- QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress, Qt::Key_V,
- Qt::ControlModifier, "V");
- });
+ QWasmIntegration::get()->getWasmClipboard()->sendClipboardData(event);
}
EMSCRIPTEN_BINDINGS(qtClipboardModule) {
@@ -261,12 +243,12 @@ void QWasmClipboard::writeToClipboardApi()
// we have a blob, now create a ClipboardItem
emscripten::val type = emscripten::val::array();
- type.set("type", mimetype.toJsString());
+ type.set("type", mimetype.toEcmaString());
emscripten::val contentBlob = emscripten::val::global("Blob").new_(contentArray, type);
emscripten::val clipboardItemObject = emscripten::val::object();
- clipboardItemObject.set(mimetype.toJsString(), contentBlob);
+ clipboardItemObject.set(mimetype.toEcmaString(), contentBlob);
val clipboardItemData = val::global("ClipboardItem").new_(clipboardItemObject);
@@ -300,4 +282,23 @@ void QWasmClipboard::writeToClipboard()
val document = val::global("document");
document.call<val>("execCommand", val("copy"));
}
+
+void QWasmClipboard::sendClipboardData(emscripten::val event)
+{
+ qDebug() << "sendClipboardData";
+
+ dom::DataTransfer *transfer = new dom::DataTransfer(event["clipboardData"]);
+ const auto mimeCallback = std::function([transfer](QMimeData *data) {
+
+ // Persist clipboard data so that the app can read it when handling the CTRL+V
+ QWasmIntegration::get()->clipboard()->QPlatformClipboard::setMimeData(data, QClipboard::Clipboard);
+ QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress, Qt::Key_V,
+ Qt::ControlModifier, "V");
+ QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyRelease, Qt::Key_V,
+ Qt::ControlModifier, "V");
+ delete transfer;
+ });
+
+ transfer->toMimeDataWithFile(mimeCallback);
+}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmclipboard.h b/src/plugins/platforms/wasm/qwasmclipboard.h
index 4a21252c8e..86618dd560 100644
--- a/src/plugins/platforms/wasm/qwasmclipboard.h
+++ b/src/plugins/platforms/wasm/qwasmclipboard.h
@@ -7,6 +7,7 @@
#include <QObject>
#include <qpa/qplatformclipboard.h>
+#include <private/qstdweb_p.h>
#include <QMimeData>
#include <emscripten/bind.h>
@@ -37,6 +38,7 @@ public:
ProcessKeyboardResult processKeyboard(const KeyEvent &event);
static void installEventHandlers(const emscripten::val &target);
bool hasClipboardApi();
+ void sendClipboardData(emscripten::val event);
private:
void initClipboardPermissions();
diff --git a/src/plugins/platforms/wasm/qwasmcompositor.cpp b/src/plugins/platforms/wasm/qwasmcompositor.cpp
index 922e802732..ef460f666f 100644
--- a/src/plugins/platforms/wasm/qwasmcompositor.cpp
+++ b/src/plugins/platforms/wasm/qwasmcompositor.cpp
@@ -3,43 +3,18 @@
#include "qwasmcompositor.h"
#include "qwasmwindow.h"
-#include "qwasmeventdispatcher.h"
-#include "qwasmclipboard.h"
-#include "qwasmevent.h"
-#include <QtGui/private/qwindow_p.h>
-
-#include <private/qguiapplication_p.h>
+#include <private/qeventdispatcher_wasm_p.h>
#include <qpa/qwindowsysteminterface.h>
-#include <QtCore/qcoreapplication.h>
-#include <QtGui/qguiapplication.h>
-
-#include <emscripten/bind.h>
-
-namespace {
-QWasmWindow *asWasmWindow(QWindow *window)
-{
- return static_cast<QWasmWindow*>(window->handle());
-}
-
-QWasmWindowStack::PositionPreference positionPreferenceFromWindowFlags(Qt::WindowFlags flags)
-{
- if (flags.testFlag(Qt::WindowStaysOnTopHint))
- return QWasmWindowStack::PositionPreference::StayOnTop;
- if (flags.testFlag(Qt::WindowStaysOnBottomHint))
- return QWasmWindowStack::PositionPreference::StayOnBottom;
- return QWasmWindowStack::PositionPreference::Regular;
-}
-} // namespace
+#include <emscripten/html5.h>
using namespace emscripten;
-Q_GUI_EXPORT int qt_defaultDpiX();
+bool QWasmCompositor::m_requestUpdateHoldEnabled = true;
-QWasmCompositor::QWasmCompositor(QWasmScreen *screen)
- : QObject(screen), m_windowStack(std::bind(&QWasmCompositor::onTopWindowChanged, this))
+QWasmCompositor::QWasmCompositor(QWasmScreen *screen) : QObject(screen)
{
QWindowSystemInterface::setSynchronousWindowSystemEvents(true);
}
@@ -49,112 +24,35 @@ QWasmCompositor::~QWasmCompositor()
if (m_requestAnimationFrameId != -1)
emscripten_cancel_animation_frame(m_requestAnimationFrameId);
- destroy();
-}
-
-void QWasmCompositor::onScreenDeleting()
-{
- deregisterEventHandlers();
-}
-
-void QWasmCompositor::deregisterEventHandlers()
-{
- QByteArray screenElementSelector = screen()->eventTargetId().toUtf8();
-
- emscripten_set_touchstart_callback(screenElementSelector.constData(), 0, 0, NULL);
- emscripten_set_touchend_callback(screenElementSelector.constData(), 0, 0, NULL);
- emscripten_set_touchmove_callback(screenElementSelector.constData(), 0, 0, NULL);
-
- emscripten_set_touchcancel_callback(screenElementSelector.constData(), 0, 0, NULL);
-}
-
-void QWasmCompositor::destroy()
-{
// TODO(mikolaj.boc): Investigate if m_isEnabled is needed at all. It seems like a frame should
// not be generated after this instead.
m_isEnabled = false; // prevent frame() from creating a new m_context
}
-void QWasmCompositor::addWindow(QWasmWindow *window)
-{
- if (m_windowStack.empty())
- window->window()->setFlag(Qt::WindowStaysOnBottomHint);
- m_windowStack.pushWindow(window, positionPreferenceFromWindowFlags(window->window()->flags()));
- window->requestActivateWindow();
- setActive(window);
-
- updateEnabledState();
-}
-
-void QWasmCompositor::removeWindow(QWasmWindow *window)
-{
- m_requestUpdateWindows.remove(window);
- m_windowStack.removeWindow(window);
- if (m_windowStack.topWindow()) {
- m_windowStack.topWindow()->requestActivateWindow();
- setActive(m_windowStack.topWindow());
- }
-
- updateEnabledState();
-}
-
-void QWasmCompositor::setActive(QWasmWindow *window)
+void QWasmCompositor::onWindowTreeChanged(QWasmWindowTreeNodeChangeType changeType,
+ QWasmWindow *window)
{
- m_activeWindow = window;
-
- auto it = m_windowStack.begin();
- if (it == m_windowStack.end()) {
- return;
- }
- for (; it != m_windowStack.end(); ++it) {
- (*it)->onActivationChanged(*it == m_activeWindow);
- }
+ auto allWindows = screen()->allWindows();
+ setEnabled(std::any_of(allWindows.begin(), allWindows.end(), [](QWasmWindow *element) {
+ return !element->context2d().isUndefined();
+ }));
+ if (changeType == QWasmWindowTreeNodeChangeType::NodeRemoval)
+ m_requestUpdateWindows.remove(window);
}
-void QWasmCompositor::updateEnabledState()
+void QWasmCompositor::setEnabled(bool enabled)
{
- m_isEnabled = std::any_of(m_windowStack.begin(), m_windowStack.end(), [](QWasmWindow *window) {
- return !window->context2d().isUndefined();
- });
+ m_isEnabled = enabled;
}
-void QWasmCompositor::raise(QWasmWindow *window)
+// requestUpdate delivery is initially disabled at startup, while Qt completes
+// startup tasks such as font loading. This function enables requestUpdate delivery
+// again.
+bool QWasmCompositor::releaseRequestUpdateHold()
{
- m_windowStack.raise(window);
-}
-
-void QWasmCompositor::lower(QWasmWindow *window)
-{
- m_windowStack.lower(window);
-}
-
-void QWasmCompositor::windowPositionPreferenceChanged(QWasmWindow *window, Qt::WindowFlags flags)
-{
- m_windowStack.windowPositionPreferenceChanged(window, positionPreferenceFromWindowFlags(flags));
-}
-
-QWindow *QWasmCompositor::windowAt(QPoint targetPointInScreenCoords, int padding) const
-{
- const auto found = std::find_if(
- m_windowStack.begin(), m_windowStack.end(),
- [padding, &targetPointInScreenCoords](const QWasmWindow *window) {
- const QRect geometry = window->windowFrameGeometry().adjusted(-padding, -padding,
- padding, padding);
-
- return window->isVisible() && geometry.contains(targetPointInScreenCoords);
- });
- return found != m_windowStack.end() ? (*found)->window() : nullptr;
-}
-
-QWindow *QWasmCompositor::keyWindow() const
-{
- return m_activeWindow ? m_activeWindow->window() : nullptr;
-}
-
-void QWasmCompositor::requestUpdateAllWindows()
-{
- m_requestUpdateAllWindows = true;
- requestUpdate();
+ const bool wasEnabled = m_requestUpdateHoldEnabled;
+ m_requestUpdateHoldEnabled = false;
+ return wasEnabled;
}
void QWasmCompositor::requestUpdateWindow(QWasmWindow *window, UpdateRequestDeliveryType updateType)
@@ -178,6 +76,9 @@ void QWasmCompositor::requestUpdate()
if (m_requestAnimationFrameId != -1)
return;
+ if (m_requestUpdateHoldEnabled)
+ return;
+
static auto frame = [](double frameTime, void *context) -> int {
Q_UNUSED(frameTime);
@@ -198,40 +99,40 @@ void QWasmCompositor::deliverUpdateRequests()
// update set.
auto requestUpdateWindows = m_requestUpdateWindows;
m_requestUpdateWindows.clear();
- bool requestUpdateAllWindows = m_requestUpdateAllWindows;
- m_requestUpdateAllWindows = false;
// Update window content, either all windows or a spesific set of windows. Use the correct
// update type: QWindow subclasses expect that requested and delivered updateRequests matches
// exactly.
m_inDeliverUpdateRequest = true;
- if (requestUpdateAllWindows) {
- for (QWasmWindow *window : m_windowStack) {
- auto it = requestUpdateWindows.find(window);
- UpdateRequestDeliveryType updateType =
- (it == m_requestUpdateWindows.end() ? ExposeEventDelivery : it.value());
- deliverUpdateRequest(window, updateType);
- }
- } else {
- for (auto it = requestUpdateWindows.constBegin(); it != requestUpdateWindows.constEnd(); ++it) {
- auto *window = it.key();
- UpdateRequestDeliveryType updateType = it.value();
- deliverUpdateRequest(window, updateType);
- }
+ for (auto it = requestUpdateWindows.constBegin(); it != requestUpdateWindows.constEnd(); ++it) {
+ auto *window = it.key();
+ UpdateRequestDeliveryType updateType = it.value();
+ deliverUpdateRequest(window, updateType);
}
+
m_inDeliverUpdateRequest = false;
- frame(requestUpdateAllWindows, requestUpdateWindows.keys());
+ frame(requestUpdateWindows.keys());
}
void QWasmCompositor::deliverUpdateRequest(QWasmWindow *window, UpdateRequestDeliveryType updateType)
{
- // update by deliverUpdateRequest and expose event accordingly.
+ QWindow *qwindow = window->window();
+
+ // Make sure the DPR value for the window is up to date on expose/repaint.
+ // FIXME: listen to native DPR change events instead, if/when available.
+ QWindowSystemInterface::handleWindowDevicePixelRatioChanged(qwindow);
+
+ // Update by deliverUpdateRequest and expose event according to requested update
+ // type. If the window has not yet been exposed then we must expose it first regardless
+ // of update type. The deliverUpdateRequest must still be sent in this case in order
+ // to maintain correct window update state.
+ QRect updateRect(QPoint(0, 0), qwindow->geometry().size());
if (updateType == UpdateRequestDelivery) {
- window->QPlatformWindow::deliverUpdateRequest();
+ if (qwindow->isExposed() == false)
+ QWindowSystemInterface::handleExposeEvent(qwindow, updateRect);
+ window->deliverUpdateRequest();
} else {
- QWindow *qwindow = window->window();
- QWindowSystemInterface::handleExposeEvent(
- qwindow, QRect(QPoint(0, 0), qwindow->geometry().size()));
+ QWindowSystemInterface::handleExposeEvent(qwindow, updateRect);
}
}
@@ -240,33 +141,16 @@ void QWasmCompositor::handleBackingStoreFlush(QWindow *window)
// Request update to flush the updated backing store content, unless we are currently
// processing an update, in which case the new content will flushed as a part of that update.
if (!m_inDeliverUpdateRequest)
- requestUpdateWindow(asWasmWindow(window));
+ requestUpdateWindow(static_cast<QWasmWindow *>(window->handle()));
}
-int dpiScaled(qreal value)
+void QWasmCompositor::frame(const QList<QWasmWindow *> &windows)
{
- return value * (qreal(qt_defaultDpiX()) / 96.0);
-}
-
-void QWasmCompositor::frame(bool all, const QList<QWasmWindow *> &windows)
-{
- if (!m_isEnabled || m_windowStack.empty() || !screen())
+ if (!m_isEnabled || !screen())
return;
- if (all) {
- std::for_each(m_windowStack.rbegin(), m_windowStack.rend(),
- [](QWasmWindow *window) { window->paint(); });
- } else {
- std::for_each(windows.begin(), windows.end(), [](QWasmWindow *window) { window->paint(); });
- }
-}
-
-void QWasmCompositor::onTopWindowChanged()
-{
- constexpr int zOrderForElementInFrontOfScreen = 3;
- int z = zOrderForElementInFrontOfScreen;
- std::for_each(m_windowStack.rbegin(), m_windowStack.rend(),
- [&z](QWasmWindow *window) { window->setZOrder(z++); });
+ for (QWasmWindow *window : windows)
+ window->paint();
}
QWasmScreen *QWasmCompositor::screen()
diff --git a/src/plugins/platforms/wasm/qwasmcompositor.h b/src/plugins/platforms/wasm/qwasmcompositor.h
index 617d14eece..4953d65233 100644
--- a/src/plugins/platforms/wasm/qwasmcompositor.h
+++ b/src/plugins/platforms/wasm/qwasmcompositor.h
@@ -7,21 +7,15 @@
#include "qwasmwindowstack.h"
#include <qpa/qplatformwindow.h>
-#include <QMap>
-
-#include <QtGui/qinputdevice.h>
-#include <QtCore/private/qstdweb_p.h>
-#include <emscripten/html5.h>
-#include <emscripten/emscripten.h>
-#include <emscripten/bind.h>
+#include <QMap>
QT_BEGIN_NAMESPACE
class QWasmWindow;
class QWasmScreen;
-class QOpenGLContext;
-class QOpenGLTexture;
+
+enum class QWasmWindowTreeNodeChangeType;
class QWasmCompositor final : public QObject
{
@@ -30,54 +24,35 @@ public:
QWasmCompositor(QWasmScreen *screen);
~QWasmCompositor() final;
- void addWindow(QWasmWindow *window);
- void removeWindow(QWasmWindow *window);
-
void setVisible(QWasmWindow *window, bool visible);
- void setActive(QWasmWindow *window);
- void raise(QWasmWindow *window);
- void lower(QWasmWindow *window);
- void windowPositionPreferenceChanged(QWasmWindow *window, Qt::WindowFlags flags);
void onScreenDeleting();
- QWindow *windowAt(QPoint globalPoint, int padding = 0) const;
- QWindow *keyWindow() const;
-
QWasmScreen *screen();
+ void setEnabled(bool enabled);
+
+ static bool releaseRequestUpdateHold();
+ void requestUpdate();
enum UpdateRequestDeliveryType { ExposeEventDelivery, UpdateRequestDelivery };
- void requestUpdateAllWindows();
void requestUpdateWindow(QWasmWindow *window, UpdateRequestDeliveryType updateType = ExposeEventDelivery);
void handleBackingStoreFlush(QWindow *window);
+ void onWindowTreeChanged(QWasmWindowTreeNodeChangeType changeType, QWasmWindow *window);
private:
- void frame(bool all, const QList<QWasmWindow *> &windows);
-
- void onTopWindowChanged();
+ void frame(const QList<QWasmWindow *> &windows);
void deregisterEventHandlers();
- void destroy();
- void requestUpdate();
void deliverUpdateRequests();
void deliverUpdateRequest(QWasmWindow *window, UpdateRequestDeliveryType updateType);
- static int touchCallback(int eventType, const EmscriptenTouchEvent *ev, void *userData);
-
- bool processTouch(int eventType, const EmscriptenTouchEvent *touchEvent);
-
- void updateEnabledState();
-
- QWasmWindowStack m_windowStack;
- QWasmWindow *m_activeWindow = nullptr;
-
bool m_isEnabled = true;
QMap<QWasmWindow *, UpdateRequestDeliveryType> m_requestUpdateWindows;
- bool m_requestUpdateAllWindows = false;
int m_requestAnimationFrameId = -1;
bool m_inDeliverUpdateRequest = false;
+ static bool m_requestUpdateHoldEnabled;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmcssstyle.cpp b/src/plugins/platforms/wasm/qwasmcssstyle.cpp
index 6ac4c8d884..e0e1a99f48 100644
--- a/src/plugins/platforms/wasm/qwasmcssstyle.cpp
+++ b/src/plugins/platforms/wasm/qwasmcssstyle.cpp
@@ -35,6 +35,11 @@ const char *Style = R"css(
background-color: lightgray;
}
+.qt-window-contents {
+ overflow: hidden;
+ position: relative;
+}
+
.qt-window.transparent-for-input {
pointer-events: none;
}
@@ -135,7 +140,7 @@ const char *Style = R"css(
padding-bottom: 4px;
}
-.qt-window.has-border .title-bar {
+.qt-window.has-border > .title-bar {
display: flex;
}
diff --git a/src/plugins/platforms/wasm/qwasmcursor.cpp b/src/plugins/platforms/wasm/qwasmcursor.cpp
index b341a31b0c..c258befa77 100644
--- a/src/plugins/platforms/wasm/qwasmcursor.cpp
+++ b/src/plugins/platforms/wasm/qwasmcursor.cpp
@@ -5,7 +5,9 @@
#include "qwasmscreen.h"
#include "qwasmwindow.h"
+#include <QtCore/qbuffer.h>
#include <QtCore/qdebug.h>
+#include <QtCore/qstring.h>
#include <QtGui/qwindow.h>
#include <emscripten/emscripten.h>
@@ -15,10 +17,9 @@ QT_BEGIN_NAMESPACE
using namespace emscripten;
namespace {
-QByteArray cursorShapeToCss(Qt::CursorShape shape)
+QByteArray cursorToCss(const QCursor *cursor)
{
- QByteArray cursorName;
-
+ auto shape = cursor->shape();
switch (shape) {
case Qt::ArrowCursor:
return "default";
@@ -64,8 +65,24 @@ QByteArray cursorShapeToCss(Qt::CursorShape shape)
return "default";
case Qt::DragLinkCursor:
return "alias";
+ case Qt::BitmapCursor: {
+ auto pixmap = cursor->pixmap();
+ QByteArray cursorAsPng;
+ QBuffer buffer(&cursorAsPng);
+ buffer.open(QBuffer::WriteOnly);
+ pixmap.save(&buffer, "PNG");
+ buffer.close();
+ auto cursorAsBase64 = cursorAsPng.toBase64();
+ auto hotSpot = cursor->hotSpot();
+ auto encodedCursor =
+ QString("url(data:image/png;base64,%1) %2 %3, auto")
+ .arg(QString::fromUtf8(cursorAsBase64),
+ QString::number(hotSpot.x()),
+ QString::number(hotSpot.y()));
+ return encodedCursor.toUtf8();
+ }
default:
- static_assert(Qt::BitmapCursor == 24 && Qt::CustomCursor == 25,
+ static_assert(Qt::CustomCursor == 25,
"New cursor type added, handle it");
qWarning() << "QWasmCursor: " << shape << " unsupported";
return "default";
@@ -78,7 +95,7 @@ void QWasmCursor::changeCursor(QCursor *windowCursor, QWindow *window)
if (!window)
return;
if (QWasmWindow *wasmWindow = static_cast<QWasmWindow *>(window->handle()))
- wasmWindow->setWindowCursor(windowCursor ? cursorShapeToCss(windowCursor->shape()) : "default");
+ wasmWindow->setWindowCursor(windowCursor ? cursorToCss(windowCursor) : "default");
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmdom.cpp b/src/plugins/platforms/wasm/qwasmdom.cpp
index 9aca102b2e..6b2b3d0933 100644
--- a/src/plugins/platforms/wasm/qwasmdom.cpp
+++ b/src/plugins/platforms/wasm/qwasmdom.cpp
@@ -3,17 +3,239 @@
#include "qwasmdom.h"
-#include <QMimeData>
+#include <QtCore/qdir.h>
+#include <QtCore/qfile.h>
#include <QtCore/qpoint.h>
#include <QtCore/qrect.h>
#include <QtGui/qimage.h>
#include <private/qstdweb_p.h>
+#include <QtCore/qurl.h>
#include <utility>
+#include <emscripten/wire.h>
QT_BEGIN_NAMESPACE
namespace dom {
+namespace {
+std::string dropActionToDropEffect(Qt::DropAction action)
+{
+ switch (action) {
+ case Qt::DropAction::CopyAction:
+ return "copy";
+ case Qt::DropAction::IgnoreAction:
+ return "none";
+ case Qt::DropAction::LinkAction:
+ return "link";
+ case Qt::DropAction::MoveAction:
+ case Qt::DropAction::TargetMoveAction:
+ return "move";
+ case Qt::DropAction::ActionMask:
+ Q_ASSERT(false);
+ return "";
+ }
+}
+} // namespace
+
+DataTransfer::DataTransfer(emscripten::val webDataTransfer)
+ : webDataTransfer(webDataTransfer) {
+}
+
+DataTransfer::~DataTransfer() = default;
+
+DataTransfer::DataTransfer(const DataTransfer &other) = default;
+
+DataTransfer::DataTransfer(DataTransfer &&other) = default;
+
+DataTransfer &DataTransfer::operator=(const DataTransfer &other) = default;
+
+DataTransfer &DataTransfer::operator=(DataTransfer &&other) = default;
+
+void DataTransfer::setDragImage(emscripten::val element, const QPoint &hotspot)
+{
+ webDataTransfer.call<void>("setDragImage", element, emscripten::val(hotspot.x()),
+ emscripten::val(hotspot.y()));
+}
+
+void DataTransfer::setData(std::string format, std::string data)
+{
+ webDataTransfer.call<void>("setData", emscripten::val(std::move(format)),
+ emscripten::val(std::move(data)));
+}
+
+void DataTransfer::setDropAction(Qt::DropAction action)
+{
+ webDataTransfer.set("dropEffect", emscripten::val(dropActionToDropEffect(action)));
+}
+
+void DataTransfer::setDataFromMimeData(const QMimeData &mimeData)
+{
+ for (const auto &format : mimeData.formats()) {
+ auto data = mimeData.data(format);
+
+ auto encoded = format.startsWith("text/")
+ ? QString::fromLocal8Bit(data).toStdString()
+ : "QB64" + QString::fromLocal8Bit(data.toBase64()).toStdString();
+
+ setData(format.toStdString(), std::move(encoded));
+ }
+}
+
+// Converts a DataTransfer instance to a QMimeData instance. Invokes the
+// given callback when the conversion is complete. The callback takes ownership
+// of the QMimeData.
+void DataTransfer::toMimeDataWithFile(std::function<void(QMimeData *)> callback)
+{
+ enum class ItemKind {
+ File,
+ String,
+ };
+
+ class MimeContext {
+
+ public:
+ MimeContext(int itemCount, std::function<void(QMimeData *)> callback)
+ :m_remainingItemCount(itemCount), m_callback(callback)
+ {
+
+ }
+
+ void deref() {
+ if (--m_remainingItemCount > 0)
+ return;
+
+ mimeData->setUrls(fileUrls);
+
+ m_callback(mimeData);
+
+ // Delete files; we expect that the user callback reads/copies
+ // file content before returning.
+ // Fixme: tie file lifetime to lifetime of the QMimeData?
+ for (QUrl fileUrl: fileUrls)
+ QFile(fileUrl.toLocalFile()).remove();
+
+ delete this;
+ }
+
+ QMimeData *mimeData = new QMimeData();
+ QList<QUrl> fileUrls;
+
+ private:
+ int m_remainingItemCount;
+ std::function<void(QMimeData *)> m_callback;
+ };
+
+ const auto items = webDataTransfer["items"];
+ const int itemCount = items["length"].as<int>();
+ const int fileCount = webDataTransfer["files"]["length"].as<int>();
+ MimeContext *mimeContext = new MimeContext(itemCount, callback);
+
+ for (int i = 0; i < itemCount; ++i) {
+ const auto item = items[i];
+ const auto itemKind =
+ item["kind"].as<std::string>() == "string" ? ItemKind::String : ItemKind::File;
+ const auto itemMimeType = QString::fromStdString(item["type"].as<std::string>());
+
+ switch (itemKind) {
+ case ItemKind::File: {
+ qstdweb::File webfile(item.call<emscripten::val>("getAsFile"));
+
+ if (webfile.size() > 1e+9) { // limit file size to 1 GB
+ qWarning() << "File is too large (> 1GB) and will be skipped. File size is" << webfile.size();
+ mimeContext->deref();
+ continue;
+ }
+
+ QString mimeFormat = QString::fromStdString(webfile.type());
+ QString fileName = QString::fromStdString(webfile.name());
+
+ // there's a file, now read it
+ QByteArray fileContent(webfile.size(), Qt::Uninitialized);
+ webfile.stream(fileContent.data(), [=]() {
+
+ // If we get a single file, and that file is an image, then
+ // try to decode the image data. This handles the case where
+ // image data (i.e. not an image file) is pasted. The browsers
+ // will then create a fake "image.png" file which has the image
+ // data. As a side effect Qt will also decode the image for
+ // single-image-file drops, since there is no way to differentiate
+ // the fake "image.png" from a real one.
+ if (fileCount == 1 && mimeFormat.contains("image/")) {
+ QImage image;
+ if (image.loadFromData(fileContent))
+ mimeContext->mimeData->setImageData(image);
+ }
+
+ QDir qtTmpDir("/qt/tmp/"); // "tmp": indicate that these files won't stay around
+ qtTmpDir.mkpath(qtTmpDir.path());
+
+ QUrl fileUrl = QUrl::fromLocalFile(qtTmpDir.filePath(QString::fromStdString(webfile.name())));
+ mimeContext->fileUrls.append(fileUrl);
+
+ QFile file(fileUrl.toLocalFile());
+ if (!file.open(QFile::WriteOnly)) {
+ qWarning() << "File was not opened";
+ mimeContext->deref();
+ return;
+ }
+ if (file.write(fileContent) < 0) {
+ qWarning() << "Write failed";
+ file.close();
+ }
+ mimeContext->deref();
+ });
+ break;
+ }
+ case ItemKind::String:
+ if (itemMimeType.contains("STRING", Qt::CaseSensitive)
+ || itemMimeType.contains("TEXT", Qt::CaseSensitive)) {
+ mimeContext->deref();
+ break;
+ }
+ QString a;
+ QString data = QString::fromEcmaString(webDataTransfer.call<emscripten::val>(
+ "getData", emscripten::val(itemMimeType.toStdString())));
+
+ if (!data.isEmpty()) {
+ if (itemMimeType == "text/html")
+ mimeContext->mimeData->setHtml(data);
+ else if (itemMimeType.isEmpty() || itemMimeType == "text/plain")
+ mimeContext->mimeData->setText(data); // the type can be empty
+ else {
+ // TODO improve encoding
+ if (data.startsWith("QB64")) {
+ data.remove(0, 4);
+ mimeContext->mimeData->setData(itemMimeType,
+ QByteArray::fromBase64(QByteArray::fromStdString(
+ data.toStdString())));
+ } else {
+ mimeContext->mimeData->setData(itemMimeType, data.toLocal8Bit());
+ }
+ }
+ }
+ mimeContext->deref();
+ break;
+ }
+ } // for items
+}
+
+QMimeData *DataTransfer::toMimeDataPreview()
+{
+ auto data = new QMimeData();
+
+ QList<QUrl> uriList;
+ for (int i = 0; i < webDataTransfer["items"]["length"].as<int>(); ++i) {
+ const auto item = webDataTransfer["items"][i];
+ if (item["kind"].as<std::string>() == "file") {
+ uriList.append(QUrl("blob://placeholder"));
+ } else {
+ const auto itemMimeType = QString::fromStdString(item["type"].as<std::string>());
+ data->setData(itemMimeType, QByteArray());
+ }
+ }
+ data->setUrls(uriList);
+ return data;
+}
void syncCSSClassWith(emscripten::val element, std::string cssClassName, bool flag)
{
@@ -36,6 +258,46 @@ QPointF mapPoint(emscripten::val source, emscripten::val target, const QPointF &
return point + offset;
}
+void drawImageToWebImageDataArray(const QImage &sourceImage, emscripten::val destinationImageData,
+ const QRect &sourceRect)
+{
+ Q_ASSERT_X(destinationImageData["constructor"]["name"].as<std::string>() == "ImageData",
+ Q_FUNC_INFO, "The destination should be an ImageData instance");
+
+ constexpr int BytesPerColor = 4;
+ if (sourceRect.width() == sourceImage.width()) {
+ // Copy a contiguous chunk of memory
+ // ...............
+ // OOOOOOOOOOOOOOO
+ // OOOOOOOOOOOOOOO -> image data
+ // OOOOOOOOOOOOOOO
+ // ...............
+ auto imageMemory = emscripten::typed_memory_view(sourceRect.width() * sourceRect.height()
+ * BytesPerColor,
+ sourceImage.constScanLine(sourceRect.y()));
+ destinationImageData["data"].call<void>(
+ "set", imageMemory, sourceRect.y() * sourceImage.width() * BytesPerColor);
+ } else {
+ // Go through the scanlines manually to set the individual lines in bulk. This is
+ // marginally less performant than the above.
+ // ...............
+ // ...OOOOOOOOO... r = 0 -> image data
+ // ...OOOOOOOOO... r = 1 -> image data
+ // ...OOOOOOOOO... r = 2 -> image data
+ // ...............
+ for (int row = 0; row < sourceRect.height(); ++row) {
+ auto scanlineMemory =
+ emscripten::typed_memory_view(sourceRect.width() * BytesPerColor,
+ sourceImage.constScanLine(row + sourceRect.y())
+ + BytesPerColor * sourceRect.x());
+ destinationImageData["data"].call<void>("set", scanlineMemory,
+ (sourceRect.y() + row) * sourceImage.width()
+ * BytesPerColor
+ + sourceRect.x() * BytesPerColor);
+ }
+ }
+}
+
} // namespace dom
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmdom.h b/src/plugins/platforms/wasm/qwasmdom.h
index 074eea7061..0a520815a3 100644
--- a/src/plugins/platforms/wasm/qwasmdom.h
+++ b/src/plugins/platforms/wasm/qwasmdom.h
@@ -5,6 +5,9 @@
#define QWASMDOM_H
#include <QtCore/qtconfigmacros.h>
+#include <QtCore/QPointF>
+#include <private/qstdweb_p.h>
+#include <QtCore/qnamespace.h>
#include <emscripten/val.h>
@@ -12,11 +15,37 @@
#include <memory>
#include <string>
+#include <QMimeData>
QT_BEGIN_NAMESPACE
+namespace qstdweb {
+ struct CancellationFlag;
+}
+
+
class QPoint;
+class QRect;
namespace dom {
+struct DataTransfer
+{
+ explicit DataTransfer(emscripten::val webDataTransfer);
+ ~DataTransfer();
+ DataTransfer(const DataTransfer &other);
+ DataTransfer(DataTransfer &&other);
+ DataTransfer &operator=(const DataTransfer &other);
+ DataTransfer &operator=(DataTransfer &&other);
+
+ void toMimeDataWithFile(std::function<void(QMimeData *)> callback);
+ QMimeData *toMimeDataPreview();
+ void setDragImage(emscripten::val element, const QPoint &hotspot);
+ void setData(std::string format, std::string data);
+ void setDropAction(Qt::DropAction dropAction);
+ void setDataFromMimeData(const QMimeData &mimeData);
+
+ emscripten::val webDataTransfer;
+};
+
inline emscripten::val document()
{
return emscripten::val::global("document");
@@ -25,6 +54,9 @@ inline emscripten::val document()
void syncCSSClassWith(emscripten::val element, std::string cssClassName, bool flag);
QPointF mapPoint(emscripten::val source, emscripten::val target, const QPointF &point);
+
+void drawImageToWebImageDataArray(const QImage &source, emscripten::val destinationImageData,
+ const QRect &sourceRect);
} // namespace dom
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmdrag.cpp b/src/plugins/platforms/wasm/qwasmdrag.cpp
new file mode 100644
index 0000000000..d07a46618f
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmdrag.cpp
@@ -0,0 +1,291 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwasmdrag.h"
+
+#include "qwasmbase64iconstore.h"
+#include "qwasmdom.h"
+#include "qwasmevent.h"
+#include "qwasmintegration.h"
+
+#include <qpa/qwindowsysteminterface.h>
+
+#include <QtCore/private/qstdweb_p.h>
+#include <QtCore/qeventloop.h>
+#include <QtCore/qmimedata.h>
+#include <QtCore/qtimer.h>
+#include <QFile>
+
+#include <functional>
+#include <string>
+#include <utility>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+
+QWindow *windowForDrag(QDrag *drag)
+{
+ QWindow *window = qobject_cast<QWindow *>(drag->source());
+ if (window)
+ return window;
+ if (drag->source()->metaObject()->indexOfMethod("_q_closestWindowHandle()") == -1)
+ return nullptr;
+
+ QMetaObject::invokeMethod(drag->source(), "_q_closestWindowHandle",
+ Q_RETURN_ARG(QWindow *, window));
+ return window;
+}
+
+} // namespace
+
+struct QWasmDrag::DragState
+{
+ class DragImage
+ {
+ public:
+ DragImage(const QPixmap &pixmap, const QMimeData *mimeData, QWindow *window);
+ ~DragImage();
+
+ emscripten::val htmlElement();
+
+ private:
+ emscripten::val generateDragImage(const QPixmap &pixmap, const QMimeData *mimeData);
+ emscripten::val generateDragImageFromText(const QMimeData *mimeData);
+ emscripten::val generateDefaultDragImage();
+ emscripten::val generateDragImageFromPixmap(const QPixmap &pixmap);
+
+ emscripten::val m_imageDomElement;
+ emscripten::val m_temporaryImageElementParent;
+ };
+
+ DragState(QDrag *drag, QWindow *window, std::function<void()> quitEventLoopClosure);
+ ~DragState();
+ DragState(const QWasmDrag &other) = delete;
+ DragState(QWasmDrag &&other) = delete;
+ DragState &operator=(const QWasmDrag &other) = delete;
+ DragState &operator=(QWasmDrag &&other) = delete;
+
+ QDrag *drag;
+ QWindow *window;
+ std::function<void()> quitEventLoopClosure;
+ std::unique_ptr<DragImage> dragImage;
+ Qt::DropAction dropAction = Qt::DropAction::IgnoreAction;
+};
+
+QWasmDrag::QWasmDrag() = default;
+
+QWasmDrag::~QWasmDrag() = default;
+
+QWasmDrag *QWasmDrag::instance()
+{
+ return static_cast<QWasmDrag *>(QWasmIntegration::get()->drag());
+}
+
+Qt::DropAction QWasmDrag::drag(QDrag *drag)
+{
+ Q_ASSERT_X(!m_dragState, Q_FUNC_INFO, "Drag already in progress");
+
+ QWindow *window = windowForDrag(drag);
+ if (!window)
+ return Qt::IgnoreAction;
+
+ Qt::DropAction dragResult = Qt::IgnoreAction;
+ if (qstdweb::haveJspi()) {
+ QEventLoop loop;
+ m_dragState = std::make_unique<DragState>(drag, window, [&loop]() { loop.quit(); });
+ loop.exec();
+ dragResult = m_dragState->dropAction;
+ m_dragState.reset();
+ }
+
+ if (dragResult == Qt::IgnoreAction)
+ dragResult = QBasicDrag::drag(drag);
+
+ return dragResult;
+}
+
+void QWasmDrag::onNativeDragStarted(DragEvent *event)
+{
+ Q_ASSERT_X(event->type == EventType::DragStart, Q_FUNC_INFO,
+ "The event is not a DragStart event");
+ // It is possible for a drag start event to arrive from another window.
+ if (!m_dragState || m_dragState->window != event->targetWindow) {
+ event->cancelDragStart();
+ return;
+ }
+
+ m_dragState->dragImage = std::make_unique<DragState::DragImage>(
+ m_dragState->drag->pixmap(), m_dragState->drag->mimeData(), event->targetWindow);
+ event->dataTransfer.setDragImage(m_dragState->dragImage->htmlElement(),
+ m_dragState->drag->hotSpot());
+ event->dataTransfer.setDataFromMimeData(*m_dragState->drag->mimeData());
+}
+
+void QWasmDrag::onNativeDragOver(DragEvent *event)
+{
+ auto mimeDataPreview = event->dataTransfer.toMimeDataPreview();
+
+ const Qt::DropActions actions = m_dragState
+ ? m_dragState->drag->supportedActions()
+ : (Qt::DropAction::CopyAction | Qt::DropAction::MoveAction
+ | Qt::DropAction::LinkAction);
+
+ const auto dragResponse = QWindowSystemInterface::handleDrag(
+ event->targetWindow, &*mimeDataPreview, event->pointInPage.toPoint(), actions,
+ event->mouseButton, event->modifiers);
+ event->acceptDragOver();
+ if (dragResponse.isAccepted()) {
+ event->dataTransfer.setDropAction(dragResponse.acceptedAction());
+ } else {
+ event->dataTransfer.setDropAction(Qt::DropAction::IgnoreAction);
+ }
+}
+
+void QWasmDrag::onNativeDrop(DragEvent *event)
+{
+ QWasmWindow *wasmWindow = QWasmWindow::fromWindow(event->targetWindow);
+
+ const auto screenElementPos = dom::mapPoint(
+ event->target(), wasmWindow->platformScreen()->element(), event->localPoint);
+ const auto screenPos =
+ wasmWindow->platformScreen()->mapFromLocal(screenElementPos);
+ const QPoint targetWindowPos = event->targetWindow->mapFromGlobal(screenPos).toPoint();
+
+ const Qt::DropActions actions = m_dragState
+ ? m_dragState->drag->supportedActions()
+ : (Qt::DropAction::CopyAction | Qt::DropAction::MoveAction
+ | Qt::DropAction::LinkAction);
+ Qt::MouseButton mouseButton = event->mouseButton;
+ QFlags<Qt::KeyboardModifier> modifiers = event->modifiers;
+
+ // Accept the native drop event: We are going to async read any dropped
+ // files, but the browser expects that accepted state is set before any
+ // async calls.
+ event->acceptDrop();
+
+ const auto dropCallback = [&m_dragState = m_dragState, wasmWindow, targetWindowPos,
+ actions, mouseButton, modifiers](QMimeData *mimeData) {
+
+ auto dropResponse = std::make_shared<QPlatformDropQtResponse>(true, Qt::DropAction::CopyAction);
+ *dropResponse = QWindowSystemInterface::handleDrop(wasmWindow->window(), mimeData,
+ targetWindowPos, actions,
+ mouseButton, modifiers);
+
+ if (dropResponse->isAccepted())
+ m_dragState->dropAction = dropResponse->acceptedAction();
+
+ delete mimeData;
+ };
+
+ event->dataTransfer.toMimeDataWithFile(dropCallback);
+}
+
+void QWasmDrag::onNativeDragFinished(DragEvent *event)
+{
+ m_dragState->dropAction = event->dropAction;
+ m_dragState->quitEventLoopClosure();
+}
+
+QWasmDrag::DragState::DragImage::DragImage(const QPixmap &pixmap, const QMimeData *mimeData,
+ QWindow *window)
+ : m_temporaryImageElementParent(QWasmWindow::fromWindow(window)->containerElement())
+{
+ m_imageDomElement = generateDragImage(pixmap, mimeData);
+
+ m_imageDomElement.set("className", "hidden-drag-image");
+ m_temporaryImageElementParent.call<void>("appendChild", m_imageDomElement);
+}
+
+QWasmDrag::DragState::DragImage::~DragImage()
+{
+ m_temporaryImageElementParent.call<void>("removeChild", m_imageDomElement);
+}
+
+emscripten::val QWasmDrag::DragState::DragImage::generateDragImage(const QPixmap &pixmap,
+ const QMimeData *mimeData)
+{
+ if (!pixmap.isNull())
+ return generateDragImageFromPixmap(pixmap);
+ if (mimeData->hasFormat("text/plain"))
+ return generateDragImageFromText(mimeData);
+ return generateDefaultDragImage();
+}
+
+emscripten::val
+QWasmDrag::DragState::DragImage::generateDragImageFromText(const QMimeData *mimeData)
+{
+ emscripten::val dragImageElement =
+ emscripten::val::global("document")
+ .call<emscripten::val>("createElement", emscripten::val("span"));
+
+ constexpr qsizetype MaxCharactersInDragImage = 100;
+
+ const auto text = QString::fromUtf8(mimeData->data("text/plain"));
+ dragImageElement.set(
+ "innerText",
+ text.first(qMin(qsizetype(MaxCharactersInDragImage), text.length())).toStdString());
+ return dragImageElement;
+}
+
+emscripten::val QWasmDrag::DragState::DragImage::generateDefaultDragImage()
+{
+ emscripten::val dragImageElement =
+ emscripten::val::global("document")
+ .call<emscripten::val>("createElement", emscripten::val("div"));
+
+ auto innerImgElement = emscripten::val::global("document")
+ .call<emscripten::val>("createElement", emscripten::val("img"));
+ innerImgElement.set("src",
+ "data:image/" + std::string("svg+xml") + ";base64,"
+ + std::string(Base64IconStore::get()->getIcon(
+ Base64IconStore::IconType::QtLogo)));
+
+ constexpr char DragImageSize[] = "50px";
+
+ dragImageElement["style"].set("width", DragImageSize);
+ innerImgElement["style"].set("width", DragImageSize);
+ dragImageElement["style"].set("display", "flex");
+
+ dragImageElement.call<void>("appendChild", innerImgElement);
+ return dragImageElement;
+}
+
+emscripten::val QWasmDrag::DragState::DragImage::generateDragImageFromPixmap(const QPixmap &pixmap)
+{
+ emscripten::val dragImageElement =
+ emscripten::val::global("document")
+ .call<emscripten::val>("createElement", emscripten::val("canvas"));
+ dragImageElement.set("width", pixmap.width());
+ dragImageElement.set("height", pixmap.height());
+
+ dragImageElement["style"].set(
+ "width", std::to_string(pixmap.width() / pixmap.devicePixelRatio()) + "px");
+ dragImageElement["style"].set(
+ "height", std::to_string(pixmap.height() / pixmap.devicePixelRatio()) + "px");
+
+ auto context2d = dragImageElement.call<emscripten::val>("getContext", emscripten::val("2d"));
+ auto imageData = context2d.call<emscripten::val>(
+ "createImageData", emscripten::val(pixmap.width()), emscripten::val(pixmap.height()));
+
+ dom::drawImageToWebImageDataArray(pixmap.toImage().convertedTo(QImage::Format::Format_RGBA8888),
+ imageData, QRect(0, 0, pixmap.width(), pixmap.height()));
+ context2d.call<void>("putImageData", imageData, emscripten::val(0), emscripten::val(0));
+
+ return dragImageElement;
+}
+
+emscripten::val QWasmDrag::DragState::DragImage::htmlElement()
+{
+ return m_imageDomElement;
+}
+
+QWasmDrag::DragState::DragState(QDrag *drag, QWindow *window,
+ std::function<void()> quitEventLoopClosure)
+ : drag(drag), window(window), quitEventLoopClosure(std::move(quitEventLoopClosure))
+{
+}
+
+QWasmDrag::DragState::~DragState() = default;
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmdrag.h b/src/plugins/platforms/wasm/qwasmdrag.h
new file mode 100644
index 0000000000..146a69ebe8
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmdrag.h
@@ -0,0 +1,47 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWINDOWSDRAG_H
+#define QWINDOWSDRAG_H
+
+#include <private/qstdweb_p.h>
+#include <private/qsimpledrag_p.h>
+
+#include <qpa/qplatformdrag.h>
+#include <QtGui/qdrag.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+struct DragEvent;
+
+class QWasmDrag final : public QSimpleDrag
+{
+public:
+ QWasmDrag();
+ ~QWasmDrag() override;
+ QWasmDrag(const QWasmDrag &other) = delete;
+ QWasmDrag(QWasmDrag &&other) = delete;
+ QWasmDrag &operator=(const QWasmDrag &other) = delete;
+ QWasmDrag &operator=(QWasmDrag &&other) = delete;
+
+ static QWasmDrag *instance();
+
+ void onNativeDragOver(DragEvent *event);
+ void onNativeDrop(DragEvent *event);
+ void onNativeDragStarted(DragEvent *event);
+ void onNativeDragFinished(DragEvent *event);
+
+ // QPlatformDrag:
+ Qt::DropAction drag(QDrag *drag) final;
+
+private:
+ struct DragState;
+
+ std::unique_ptr<DragState> m_dragState;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSDRAG_H
diff --git a/src/plugins/platforms/wasm/qwasmevent.cpp b/src/plugins/platforms/wasm/qwasmevent.cpp
index 6353cce48f..c1d6ce3a2a 100644
--- a/src/plugins/platforms/wasm/qwasmevent.cpp
+++ b/src/plugins/platforms/wasm/qwasmevent.cpp
@@ -86,7 +86,10 @@ QFlags<Qt::KeyboardModifier> getForEvent<EmscriptenKeyboardEvent>(
}
} // namespace KeyboardModifier
-Event::Event(EventType type, emscripten::val target) : type(type), target(target) { }
+Event::Event(EventType type, emscripten::val webEvent)
+ : webEvent(webEvent), type(type)
+{
+}
Event::~Event() = default;
@@ -98,7 +101,7 @@ Event &Event::operator=(const Event &other) = default;
Event &Event::operator=(Event &&other) = default;
-KeyEvent::KeyEvent(EventType type, emscripten::val event) : Event(type, event["target"])
+KeyEvent::KeyEvent(EventType type, emscripten::val event) : Event(type, event)
{
const auto code = event["code"].as<std::string>();
const auto webKey = event["key"].as<std::string>();
@@ -110,6 +113,9 @@ KeyEvent::KeyEvent(EventType type, emscripten::val event) : Event(type, event["t
text = QString::fromUtf8(webKey);
if (text.size() > 1)
text.clear();
+
+ if (key == Qt::Key_Tab)
+ text = "\t";
}
KeyEvent::~KeyEvent() = default;
@@ -143,7 +149,7 @@ std::optional<KeyEvent> KeyEvent::fromWebWithDeadKeyTranslation(emscripten::val
return result;
}
-MouseEvent::MouseEvent(EventType type, emscripten::val event) : Event(type, event["target"])
+MouseEvent::MouseEvent(EventType type, emscripten::val event) : Event(type, event)
{
mouseButton = MouseEvent::buttonFromWeb(event["button"].as<int>());
mouseButtons = MouseEvent::buttonsFromWeb(event["buttons"].as<unsigned short>());
@@ -177,11 +183,17 @@ PointerEvent::PointerEvent(EventType type, emscripten::val event) : MouseEvent(t
return PointerType::Mouse;
if (type == "touch")
return PointerType::Touch;
+ if (type == "pen")
+ return PointerType::Pen;
return PointerType::Other;
})();
width = event["width"].as<qreal>();
height = event["height"].as<qreal>();
pressure = event["pressure"].as<qreal>();
+ tiltX = event["tiltX"].as<qreal>();
+ tiltY = event["tiltY"].as<qreal>();
+ tangentialPressure = event["tangentialPressure"].as<qreal>();
+ twist = event["twist"].as<qreal>();
isPrimary = event["isPrimary"].as<bool>();
}
@@ -218,8 +230,8 @@ std::optional<PointerEvent> PointerEvent::fromWeb(emscripten::val event)
return PointerEvent(*eventType, event);
}
-DragEvent::DragEvent(EventType type, emscripten::val event)
- : MouseEvent(type, event), dataTransfer(event["dataTransfer"])
+DragEvent::DragEvent(EventType type, emscripten::val event, QWindow *window)
+ : MouseEvent(type, event), dataTransfer(event["dataTransfer"]), targetWindow(window)
{
dropAction = ([event]() {
const std::string effect = event["dataTransfer"]["dropEffect"].as<std::string>();
@@ -244,18 +256,42 @@ DragEvent &DragEvent::operator=(const DragEvent &other) = default;
DragEvent &DragEvent::operator=(DragEvent &&other) = default;
-std::optional<DragEvent> DragEvent::fromWeb(emscripten::val event)
+std::optional<DragEvent> DragEvent::fromWeb(emscripten::val event, QWindow *targetWindow)
{
const auto eventType = ([&event]() -> std::optional<EventType> {
const auto eventTypeString = event["type"].as<std::string>();
+ if (eventTypeString == "dragend")
+ return EventType::DragEnd;
+ if (eventTypeString == "dragover")
+ return EventType::DragOver;
+ if (eventTypeString == "dragstart")
+ return EventType::DragStart;
if (eventTypeString == "drop")
return EventType::Drop;
return std::nullopt;
})();
if (!eventType)
return std::nullopt;
- return DragEvent(*eventType, event);
+ return DragEvent(*eventType, event, targetWindow);
+}
+
+void DragEvent::cancelDragStart()
+{
+ Q_ASSERT_X(type == EventType::DragStart, Q_FUNC_INFO, "Only supported for DragStart");
+ webEvent.call<void>("preventDefault");
+}
+
+void DragEvent::acceptDragOver()
+{
+ Q_ASSERT_X(type == EventType::DragOver, Q_FUNC_INFO, "Only supported for DragOver");
+ webEvent.call<void>("preventDefault");
+}
+
+void DragEvent::acceptDrop()
+{
+ Q_ASSERT_X(type == EventType::Drop, Q_FUNC_INFO, "Only supported for Drop");
+ webEvent.call<void>("preventDefault");
}
WheelEvent::WheelEvent(EventType type, emscripten::val event) : MouseEvent(type, event)
diff --git a/src/plugins/platforms/wasm/qwasmevent.h b/src/plugins/platforms/wasm/qwasmevent.h
index 012b1b235b..6ada5393e3 100644
--- a/src/plugins/platforms/wasm/qwasmevent.h
+++ b/src/plugins/platforms/wasm/qwasmevent.h
@@ -5,11 +5,12 @@
#define QWASMEVENT_H
#include "qwasmplatform.h"
+#include "qwasmdom.h"
#include <QtCore/qglobal.h>
#include <QtCore/qnamespace.h>
#include <QtGui/qevent.h>
-
+#include <private/qstdweb_p.h>
#include <QPoint>
#include <emscripten/html5.h>
@@ -18,8 +19,12 @@
QT_BEGIN_NAMESPACE
class QWasmDeadKeySupport;
+class QWindow;
enum class EventType {
+ DragEnd,
+ DragOver,
+ DragStart,
Drop,
KeyDown,
KeyUp,
@@ -35,6 +40,7 @@ enum class EventType {
enum class PointerType {
Mouse,
Touch,
+ Pen,
Other,
};
@@ -119,15 +125,16 @@ QFlags<Qt::KeyboardModifier> getForEvent<EmscriptenKeyboardEvent>(
struct Event
{
- Event(EventType type, emscripten::val target);
+ Event(EventType type, emscripten::val webEvent);
~Event();
Event(const Event &other);
Event(Event &&other);
Event &operator=(const Event &other);
Event &operator=(Event &&other);
+ emscripten::val webEvent;
EventType type;
- emscripten::val target = emscripten::val::undefined();
+ emscripten::val target() const { return webEvent["target"]; }
};
struct KeyEvent : public Event
@@ -214,6 +221,10 @@ struct PointerEvent : public MouseEvent
PointerType pointerType;
int pointerId;
qreal pressure;
+ qreal tiltX;
+ qreal tiltY;
+ qreal tangentialPressure;
+ qreal twist;
qreal width;
qreal height;
bool isPrimary;
@@ -221,17 +232,22 @@ struct PointerEvent : public MouseEvent
struct DragEvent : public MouseEvent
{
- static std::optional<DragEvent> fromWeb(emscripten::val webEvent);
+ static std::optional<DragEvent> fromWeb(emscripten::val webEvent, QWindow *targetQWindow);
- DragEvent(EventType type, emscripten::val webEvent);
+ DragEvent(EventType type, emscripten::val webEvent, QWindow *targetQWindow);
~DragEvent();
DragEvent(const DragEvent &other);
DragEvent(DragEvent &&other);
DragEvent &operator=(const DragEvent &other);
DragEvent &operator=(DragEvent &&other);
+ void cancelDragStart();
+ void acceptDragOver();
+ void acceptDrop();
+
Qt::DropAction dropAction;
- emscripten::val dataTransfer;
+ dom::DataTransfer dataTransfer;
+ QWindow *targetWindow;
};
struct WheelEvent : public MouseEvent
diff --git a/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp
index 2fd1a30401..1f2d3095d6 100644
--- a/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp
+++ b/src/plugins/platforms/wasm/qwasmeventdispatcher.cpp
@@ -2,16 +2,34 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qwasmeventdispatcher.h"
+#include "qwasmintegration.h"
#include <QtGui/qpa/qwindowsysteminterface.h>
QT_BEGIN_NAMESPACE
// Note: All event dispatcher functionality is implemented in QEventDispatcherWasm
-// in QtCore, except for processWindowSystemEvents() below which uses API from QtGui.
-void QWasmEventDispatcher::processWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
+// in QtCore, except for processPostedEvents() below which uses API from QtGui.
+bool QWasmEventDispatcher::processPostedEvents()
{
- QWindowSystemInterface::sendWindowSystemEvents(flags);
+ QEventDispatcherWasm::processPostedEvents();
+ return QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::AllEvents);
+}
+
+void QWasmEventDispatcher::onLoaded()
+{
+ // This function is called when the application is ready to paint
+ // the first frame. Send the qtlaoder onLoaded event first (via
+ // the base class implementation), and then enable/call requestUpdate
+ // to deliver a frame.
+ QEventDispatcherWasm::onLoaded();
+
+ // Make sure all screens have a defined size; and pick
+ // up size changes due to onLoaded event handling.
+ QWasmIntegration *wasmIntegration = QWasmIntegration::get();
+ wasmIntegration->resizeAllScreens();
+
+ wasmIntegration->releaseRequesetUpdateHold();
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmeventdispatcher.h b/src/plugins/platforms/wasm/qwasmeventdispatcher.h
index a28fa7263b..cbf10482e3 100644
--- a/src/plugins/platforms/wasm/qwasmeventdispatcher.h
+++ b/src/plugins/platforms/wasm/qwasmeventdispatcher.h
@@ -11,7 +11,8 @@ QT_BEGIN_NAMESPACE
class QWasmEventDispatcher : public QEventDispatcherWasm
{
protected:
- void processWindowSystemEvents(QEventLoop::ProcessEventsFlags flags) override;
+ bool processPostedEvents() override;
+ void onLoaded() override;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmfontdatabase.cpp b/src/plugins/platforms/wasm/qwasmfontdatabase.cpp
index 5fdaae8f84..3f3dc10f71 100644
--- a/src/plugins/platforms/wasm/qwasmfontdatabase.cpp
+++ b/src/plugins/platforms/wasm/qwasmfontdatabase.cpp
@@ -6,137 +6,315 @@
#include <QtCore/qfile.h>
#include <QtCore/private/qstdweb_p.h>
+#include <QtCore/private/qeventdispatcher_wasm_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <emscripten.h>
#include <emscripten/val.h>
#include <emscripten/bind.h>
+#include <map>
+#include <array>
+
QT_BEGIN_NAMESPACE
using namespace emscripten;
using namespace Qt::StringLiterals;
-void QWasmFontDatabase::populateFontDatabase()
+
+namespace {
+
+class FontData
{
- // Load font file from resources. Currently
- // all fonts needs to be bundled with the nexe
- // as Qt resources.
+public:
+ FontData(val fontData)
+ :m_fontData(fontData) {}
- const QString fontFileNames[] = {
- QStringLiteral(":/fonts/DejaVuSansMono.ttf"),
- QStringLiteral(":/fonts/Vera.ttf"),
- QStringLiteral(":/fonts/DejaVuSans.ttf"),
- };
- for (const QString &fontFileName : fontFileNames) {
- QFile theFont(fontFileName);
- if (!theFont.open(QIODevice::ReadOnly))
- break;
+ QString family() const
+ {
+ return QString::fromStdString(m_fontData["family"].as<std::string>());
+ }
- QFreeTypeFontDatabase::addTTFile(theFont.readAll(), fontFileName.toLatin1());
+ QString fullName() const
+ {
+ return QString::fromStdString(m_fontData["fullName"].as<std::string>());
}
- // check if local-fonts API is available in the browser
- val window = val::global("window");
- val fonts = window["queryLocalFonts"];
+ QString postscriptName() const
+ {
+ return QString::fromStdString(m_fontData["postscriptName"].as<std::string>());
+ }
- if (fonts.isUndefined())
- return;
+ QString style() const
+ {
+ return QString::fromStdString(m_fontData["style"].as<std::string>());
+ }
+
+ val value() const
+ {
+ return m_fontData;
+ }
+
+private:
+ val m_fontData;
+};
+
+val makeObject(const char *key, const char *value)
+{
+ val obj = val::object();
+ obj.set(key, std::string(value));
+ return obj;
+}
+
+void printError(val err) {
+ qCWarning(lcQpaFonts)
+ << QString::fromStdString(err["name"].as<std::string>())
+ << QString::fromStdString(err["message"].as<std::string>());
+ QWasmFontDatabase::endAllFontFileLoading();
+}
- val permissions = val::global("navigator")["permissions"];
- if (permissions["request"].isUndefined())
+void checkFontAccessPermitted(std::function<void(bool)> callback)
+{
+ const val permissions = val::global("navigator")["permissions"];
+ if (permissions.isUndefined()) {
+ callback(false);
return;
+ }
- val requestLocalFontsPermission = val::object();
- requestLocalFontsPermission.set("name", std::string("local-fonts"));
-
- qstdweb::PromiseCallbacks permissionRequestCallbacks {
- .thenFunc = [window](val status) {
- qCDebug(lcQpaFonts) << "onFontPermissionSuccess:"
- << QString::fromStdString(status["state"].as<std::string>());
-
- // query all available local fonts and call registerFontFamily for each of them
- qstdweb::Promise::make(window, "queryLocalFonts", {
- .thenFunc = [](val status) {
- const int count = status["length"].as<int>();
- for (int i = 0; i < count; ++i) {
- val font = status.call<val>("at", i);
- const std::string family = font["family"].as<std::string>();
- QFreeTypeFontDatabase::registerFontFamily(QString::fromStdString(family));
- }
- QWasmFontDatabase::notifyFontsChanged();
- },
- .catchFunc = [](val) {
- qCWarning(lcQpaFonts)
- << "Error while trying to query local-fonts API";
- }
- });
+ qstdweb::Promise::make(permissions, "query", {
+ .thenFunc = [callback](val status) {
+ callback(status["state"].as<std::string>() == "granted");
},
- .catchFunc = [](val error) {
- qCWarning(lcQpaFonts)
- << "Error while requesting local-fonts API permission: "
- << QString::fromStdString(error["name"].as<std::string>());
- }
- };
+ }, makeObject("name", "local-fonts"));
+}
- // request local fonts permission (currently supported only by Chrome 103+)
- qstdweb::Promise::make(permissions, "request", std::move(permissionRequestCallbacks), std::move(requestLocalFontsPermission));
+void queryLocalFonts(std::function<void(const QList<FontData> &)> callback)
+{
+ emscripten::val window = emscripten::val::global("window");
+ qstdweb::Promise::make(window, "queryLocalFonts", {
+ .thenFunc = [callback](emscripten::val fontArray) {
+ QList<FontData> fonts;
+ const int count = fontArray["length"].as<int>();
+ fonts.reserve(count);
+ for (int i = 0; i < count; ++i)
+ fonts.append(FontData(fontArray.call<emscripten::val>("at", i)));
+ callback(fonts);
+ },
+ .catchFunc = printError
+ });
}
-void QWasmFontDatabase::populateFamily(const QString &familyName)
+void readBlob(val blob, std::function<void(const QByteArray &)> callback)
{
- val window = val::global("window");
+ qstdweb::Promise::make(blob, "arrayBuffer", {
+ .thenFunc = [callback](emscripten::val fontArrayBuffer) {
+ QByteArray fontData = qstdweb::Uint8Array(qstdweb::ArrayBuffer(fontArrayBuffer)).copyToQByteArray();
+ callback(fontData);
+ },
+ .catchFunc = printError
+ });
+}
- auto queryFontsArgument = val::array(std::vector<val>({ val(familyName.toStdString()) }));
- val queryFont = val::object();
- queryFont.set("postscriptNames", std::move(queryFontsArgument));
+void readFont(FontData font, std::function<void(const QByteArray &)> callback)
+{
+ qstdweb::Promise::make(font.value(), "blob", {
+ .thenFunc = [callback](val blob) {
+ readBlob(blob, [callback](const QByteArray &data) {
+ callback(data);
+ });
+ },
+ .catchFunc = printError
+ });
+}
- qstdweb::PromiseCallbacks localFontsQueryCallback {
- .thenFunc = [](val status) {
- val font = status.call<val>("at", 0);
+emscripten::val getLocalFontsConfigProperty(const char *name) {
+ emscripten::val qt = val::module_property("qt");
+ if (qt.isUndefined())
+ return emscripten::val();
+ emscripten::val localFonts = qt["localFonts"];
+ if (localFonts.isUndefined())
+ return emscripten::val();
+ return localFonts[name];
+};
+
+bool getLocalFontsBoolConfigPropertyWithDefault(const char *name, bool defaultValue) {
+ emscripten::val prop = getLocalFontsConfigProperty(name);
+ if (prop.isUndefined())
+ return defaultValue;
+ return prop.as<bool>();
+};
+
+QString getLocalFontsStringConfigPropertyWithDefault(const char *name, QString defaultValue) {
+ emscripten::val prop = getLocalFontsConfigProperty(name);
+ if (prop.isUndefined())
+ return defaultValue;
+ return QString::fromStdString(prop.as<std::string>());
+};
+
+QStringList getLocalFontsStringListConfigPropertyWithDefault(const char *name, QStringList defaultValue) {
+ emscripten::val array = getLocalFontsConfigProperty(name);
+ if (array.isUndefined())
+ return defaultValue;
+
+ QStringList list;
+ int size = array["length"].as<int>();
+ for (int i = 0; i < size; ++i) {
+ emscripten::val element = array.call<emscripten::val>("at", i);
+ QString string = QString::fromStdString(element.as<std::string>());
+ if (!string.isEmpty())
+ list.append(string);
+ }
+ return list;
+};
- if (font.isUndefined())
- return;
+} // namespace
- qstdweb::PromiseCallbacks blobQueryCallback {
- .thenFunc = [](val status) {
- qCDebug(lcQpaFonts) << "onBlobQuerySuccess";
+QWasmFontDatabase::QWasmFontDatabase()
+:QFreeTypeFontDatabase()
+{
+ m_localFontsApiSupported = val::global("window")["queryLocalFonts"].isUndefined() == false;
+ if (m_localFontsApiSupported)
+ beginFontDatabaseStartupTask();
+}
- qstdweb::PromiseCallbacks arrayBufferCallback {
- .thenFunc = [](val status) {
- qCDebug(lcQpaFonts) << "onArrayBuffer" ;
+QWasmFontDatabase *QWasmFontDatabase::get()
+{
+ return static_cast<QWasmFontDatabase *>(QWasmIntegration::get()->fontDatabase());
+}
- QByteArray fontByteArray = QByteArray::fromEcmaUint8Array(status);
+// Populates the font database with local fonts. Will make the browser ask
+// the user for permission if needed. Does nothing if the Local Font Access API
+// is not supported.
+void QWasmFontDatabase::populateLocalfonts()
+{
+ // Decide which font families to populate based on user preferences
+ QStringList selectedLocalFontFamilies;
+ bool allFamilies = false;
+
+ switch (m_localFontFamilyLoadSet) {
+ case NoFontFamilies:
+ default:
+ // keep empty selectedLocalFontFamilies
+ break;
+ case DefaultFontFamilies: {
+ const QStringList webSafeFontFamilies =
+ {"Arial", "Verdana", "Tahoma", "Trebuchet", "Times New Roman",
+ "Georgia", "Garamond", "Courier New"};
+ selectedLocalFontFamilies = webSafeFontFamilies;
+ } break;
+ case AllFontFamilies:
+ allFamilies = true;
+ break;
+ }
- QFreeTypeFontDatabase::addTTFile(fontByteArray, QByteArray());
+ selectedLocalFontFamilies += m_extraLocalFontFamilies;
- QWasmFontDatabase::notifyFontsChanged();
- },
- .catchFunc = [](val) {
- qCWarning(lcQpaFonts) << "onArrayBufferError";
- }
- };
+ if (selectedLocalFontFamilies.isEmpty() && !allFamilies) {
+ endAllFontFileLoading();
+ return;
+ }
- qstdweb::Promise::make(status, "arrayBuffer", std::move(arrayBufferCallback));
- },
- .catchFunc = [](val) {
- qCWarning(lcQpaFonts) << "onBlobQueryError";
- }
- };
+ populateLocalFontFamilies(selectedLocalFontFamilies, allFamilies);
+}
- qstdweb::Promise::make(font, "blob", std::move(blobQueryCallback));
- },
- .catchFunc = [](val) {
- qCWarning(lcQpaFonts) << "onLocalFontsQueryError";
+namespace {
+ QStringList toStringList(emscripten::val array)
+ {
+ QStringList list;
+ int size = array["length"].as<int>();
+ for (int i = 0; i < size; ++i) {
+ emscripten::val element = array.call<emscripten::val>("at", i);
+ QString string = QString::fromStdString(element.as<std::string>());
+ if (!string.isEmpty())
+ list.append(string);
}
+ return list;
+ }
+}
+
+void QWasmFontDatabase::populateLocalFontFamilies(emscripten::val families)
+{
+ if (!m_localFontsApiSupported)
+ return;
+ populateLocalFontFamilies(toStringList(families), false);
+}
+
+void QWasmFontDatabase::populateLocalFontFamilies(const QStringList &fontFamilies, bool allFamilies)
+{
+ queryLocalFonts([fontFamilies, allFamilies](const QList<FontData> &fonts) {
+ refFontFileLoading();
+ QList<FontData> filteredFonts;
+ std::copy_if(fonts.begin(), fonts.end(), std::back_inserter(filteredFonts),
+ [fontFamilies, allFamilies](FontData fontData) {
+ return allFamilies || fontFamilies.contains(fontData.family());
+ });
+
+ for (const FontData &font: filteredFonts) {
+ refFontFileLoading();
+ readFont(font, [font](const QByteArray &fontData){
+ QFreeTypeFontDatabase::registerFontFamily(font.family());
+ QFreeTypeFontDatabase::addTTFile(fontData, QByteArray());
+ derefFontFileLoading();
+ });
+ }
+ derefFontFileLoading();
+ });
+
+}
+
+void QWasmFontDatabase::populateFontDatabase()
+{
+ // Load bundled font file from resources.
+ const QString fontFileNames[] = {
+ QStringLiteral(":/fonts/DejaVuSansMono.ttf"),
+ QStringLiteral(":/fonts/DejaVuSans.ttf"),
};
+ for (const QString &fontFileName : fontFileNames) {
+ QFile theFont(fontFileName);
+ if (!theFont.open(QIODevice::ReadOnly))
+ break;
+
+ QFreeTypeFontDatabase::addTTFile(theFont.readAll(), fontFileName.toLatin1());
+ }
- qstdweb::Promise::make(window, "queryLocalFonts", std::move(localFontsQueryCallback), std::move(queryFont));
+ // Get config options for controlling local fonts usage
+ m_queryLocalFontsPermission = getLocalFontsBoolConfigPropertyWithDefault("requestPermission", false);
+ QString fontFamilyLoadSet = getLocalFontsStringConfigPropertyWithDefault("familiesCollection", "DefaultFontFamilies");
+ m_extraLocalFontFamilies = getLocalFontsStringListConfigPropertyWithDefault("extraFamilies", QStringList());
+
+ if (fontFamilyLoadSet == "NoFontFamilies") {
+ m_localFontFamilyLoadSet = NoFontFamilies;
+ } else if (fontFamilyLoadSet == "DefaultFontFamilies") {
+ m_localFontFamilyLoadSet = DefaultFontFamilies;
+ } else if (fontFamilyLoadSet == "AllFontFamilies") {
+ m_localFontFamilyLoadSet = AllFontFamilies;
+ } else {
+ m_localFontFamilyLoadSet = NoFontFamilies;
+ qWarning() << "Unknown fontFamilyLoadSet value" << fontFamilyLoadSet;
+ }
+
+ if (!m_localFontsApiSupported)
+ return;
+
+ // Populate the font database with local fonts. Either try unconditianlly
+ // if displyaing a fonts permissions dialog at startup is allowed, or else
+ // only if we already have permission.
+ if (m_queryLocalFontsPermission) {
+ populateLocalfonts();
+ } else {
+ checkFontAccessPermitted([this](bool granted) {
+ if (granted)
+ populateLocalfonts();
+ else
+ endAllFontFileLoading();
+ });
+ }
}
QFontEngine *QWasmFontDatabase::fontEngine(const QFontDef &fontDef, void *handle)
{
- return QFreeTypeFontDatabase::fontEngine(fontDef, handle);
+ QFontEngine *fontEngine = QFreeTypeFontDatabase::fontEngine(fontDef, handle);
+ return fontEngine;
}
QStringList QWasmFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style,
@@ -146,9 +324,9 @@ QStringList QWasmFontDatabase::fallbacksForFamily(const QString &family, QFont::
QStringList fallbacks
= QFreeTypeFontDatabase::fallbacksForFamily(family, style, styleHint, script);
- // Add the vera.ttf and DejaVuSans.ttf fonts (loaded in populateFontDatabase above) as falback fonts
+ // Add the DejaVuSans.ttf font (loaded in populateFontDatabase above) as a falback font
// to all other fonts (except itself).
- static const QString wasmFallbackFonts[] = { "Bitstream Vera Sans", "DejaVu Sans" };
+ static const QString wasmFallbackFonts[] = { "DejaVu Sans" };
for (auto wasmFallbackFont : wasmFallbackFonts) {
if (family != wasmFallbackFont && !fallbacks.contains(wasmFallbackFont))
fallbacks.append(wasmFallbackFont);
@@ -164,13 +342,63 @@ void QWasmFontDatabase::releaseHandle(void *handle)
QFont QWasmFontDatabase::defaultFont() const
{
- return QFont("Bitstream Vera Sans"_L1);
+ return QFont("DejaVu Sans"_L1);
+}
+
+namespace {
+ int g_pendingFonts = 0;
+ bool g_fontStartupTaskCompleted = false;
+}
+
+// Registers font loading as a startup task, which makes Qt delay
+// sending onLoaded event until font loading has completed.
+void QWasmFontDatabase::beginFontDatabaseStartupTask()
+{
+ g_fontStartupTaskCompleted = false;
+ QEventDispatcherWasm::registerStartupTask();
+}
+
+// Ends the font loading startup task.
+void QWasmFontDatabase::endFontDatabaseStartupTask()
+{
+ if (!g_fontStartupTaskCompleted) {
+ g_fontStartupTaskCompleted = true;
+ QEventDispatcherWasm::completeStarupTask();
+ }
+}
+
+// Registers that a font file will be loaded.
+void QWasmFontDatabase::refFontFileLoading()
+{
+ g_pendingFonts += 1;
+}
+
+// Registers that one font file has been loaded, and sends notifactions
+// when all pending font files have been loaded.
+void QWasmFontDatabase::derefFontFileLoading()
+{
+ if (--g_pendingFonts <= 0) {
+ QFontCache::instance()->clear();
+ emit qGuiApp->fontDatabaseChanged();
+ endFontDatabaseStartupTask();
+ }
}
-void QWasmFontDatabase::notifyFontsChanged()
+// Unconditionally ends local font loading, for instance if there
+// are no fonts to load or if there was an unexpected error.
+void QWasmFontDatabase::endAllFontFileLoading()
{
- QFontCache::instance()->clear();
- emit qGuiApp->fontDatabaseChanged();
+ bool hadPandingfonts = g_pendingFonts > 0;
+ if (hadPandingfonts) {
+ // The hadPandingfonts counter might no longer be correct; disable counting
+ // and send notifications unconditionally.
+ g_pendingFonts = 0;
+ QFontCache::instance()->clear();
+ emit qGuiApp->fontDatabaseChanged();
+ }
+
+ endFontDatabaseStartupTask();
}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmfontdatabase.h b/src/plugins/platforms/wasm/qwasmfontdatabase.h
index 22c550f244..a1c8f1ff48 100644
--- a/src/plugins/platforms/wasm/qwasmfontdatabase.h
+++ b/src/plugins/platforms/wasm/qwasmfontdatabase.h
@@ -6,13 +6,17 @@
#include <QtGui/private/qfreetypefontdatabase_p.h>
+#include <emscripten/val.h>
+
QT_BEGIN_NAMESPACE
class QWasmFontDatabase : public QFreeTypeFontDatabase
{
public:
+ QWasmFontDatabase();
+ static QWasmFontDatabase *get();
+
void populateFontDatabase() override;
- void populateFamily(const QString &familyName) override;
QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override;
QStringList fallbacksForFamily(const QString &family, QFont::Style style,
QFont::StyleHint styleHint,
@@ -20,7 +24,26 @@ public:
void releaseHandle(void *handle) override;
QFont defaultFont() const override;
- static void notifyFontsChanged();
+ void populateLocalfonts();
+ void populateLocalFontFamilies(emscripten::val families);
+ void populateLocalFontFamilies(const QStringList &famliies, bool allFamilies);
+
+ static void beginFontDatabaseStartupTask();
+ static void endFontDatabaseStartupTask();
+ static void refFontFileLoading();
+ static void derefFontFileLoading();
+ static void endAllFontFileLoading();
+
+private:
+ bool m_localFontsApiSupported = false;
+ bool m_queryLocalFontsPermission = false;
+ enum FontFamilyLoadSet {
+ NoFontFamilies,
+ DefaultFontFamilies,
+ AllFontFamilies,
+ };
+ FontFamilyLoadSet m_localFontFamilyLoadSet;
+ QStringList m_extraLocalFontFamilies;
};
QT_END_NAMESPACE
#endif
diff --git a/src/plugins/platforms/wasm/qwasminputcontext.cpp b/src/plugins/platforms/wasm/qwasminputcontext.cpp
index 157f96fe49..ae72e7b7f9 100644
--- a/src/plugins/platforms/wasm/qwasminputcontext.cpp
+++ b/src/plugins/platforms/wasm/qwasminputcontext.cpp
@@ -30,7 +30,7 @@ static void inputCallback(emscripten::val event)
QString str = QString::fromStdString(_incomingCharVal.as<std::string>());
QWasmInputContext *wasmInput =
reinterpret_cast<QWasmInputContext*>(event["target"]["data-qinputcontext"].as<quintptr>());
- wasmInput->inputStringChanged(str, wasmInput);
+ wasmInput->inputStringChanged(str, EMSCRIPTEN_EVENT_KEYDOWN, wasmInput);
}
// this clears the input string, so backspaces do not send a character
// but stops suggestions
@@ -49,29 +49,24 @@ QWasmInputContext::QWasmInputContext()
m_inputElement.set("style", "position:absolute;left:-1000px;top:-1000px"); // offscreen
m_inputElement.set("contenteditable","true");
- if (platform() == Platform::Android || platform() == Platform::Windows) {
+ if (platform() == Platform::MacOS || platform() == Platform::iOS) {
+ auto callback = [=](emscripten::val) {
+ m_inputElement["parentElement"].call<void>("removeChild", m_inputElement);
+ inputPanelIsOpen = false;
+ };
+ m_blurEventHandler.reset(new EventCallback(m_inputElement, "blur", callback));
+
+ } else {
+
const std::string inputType = platform() == Platform::Windows ? "textInput" : "input";
document.call<void>("addEventListener", inputType,
- emscripten::val::module_property("qtInputContextCallback"),
- emscripten::val(false));
+ emscripten::val::module_property("qtInputContextCallback"),
+ emscripten::val(false));
m_inputElement.set("data-qinputcontext",
emscripten::val(quintptr(reinterpret_cast<void *>(this))));
emscripten::val body = document["body"];
body.call<void>("appendChild", m_inputElement);
-
- // Enter is sent through target window, let's just handle this here
- emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, (void *)this, 1,
- &androidKeyboardCallback);
-
- }
-
- if (platform() == Platform::MacOS || platform() == Platform::iPhone) {
- auto callback = [=](emscripten::val) {
- m_inputElement["parentElement"].call<void>("removeChild", m_inputElement);
- inputPanelIsOpen = false;
- };
- m_blurEventHandler.reset(new EventCallback(m_inputElement, "blur", callback));
}
QObject::connect(qGuiApp, &QGuiApplication::focusWindowChanged, this,
@@ -118,7 +113,7 @@ void QWasmInputContext::showInputPanel()
// screen element.
if (platform() == Platform::MacOS // keep for compatibility
- || platform() == Platform::iPhone
+ || platform() == Platform::iOS
|| platform() == Platform::Windows) {
emscripten::val inputWrapper = inputHandlerElementForFocusedWindow();
if (inputWrapper.isUndefined())
@@ -138,29 +133,29 @@ void QWasmInputContext::hideInputPanel()
inputPanelIsOpen = false;
}
-void QWasmInputContext::inputStringChanged(QString &inputString, QWasmInputContext *context)
+void QWasmInputContext::inputStringChanged(QString &inputString, int eventType, QWasmInputContext *context)
{
Q_UNUSED(context)
QKeySequence keys = QKeySequence::fromString(inputString);
+ Qt::Key thisKey = keys[0].key();
+
// synthesize this keyevent as android is not normal
+ if (inputString.size() > 2 && (thisKey < Qt::Key_F35
+ || thisKey > Qt::Key_Back)) {
+ inputString.clear();
+ }
+ if (inputString == QStringLiteral("Escape")) {
+ thisKey = Qt::Key_Escape;
+ inputString.clear();
+ } else if (thisKey == Qt::Key(0)) {
+ thisKey = Qt::Key_Return;
+ }
+
QWindowSystemInterface::handleKeyEvent(
- 0, QEvent::KeyPress,keys[0].key(), keys[0].keyboardModifiers(), inputString);
+ 0, eventType == EMSCRIPTEN_EVENT_KEYDOWN ? QEvent::KeyPress : QEvent::KeyRelease,
+ thisKey, keys[0].keyboardModifiers(),
+ eventType == EMSCRIPTEN_EVENT_KEYDOWN ? inputString : QStringLiteral(""));
}
-int QWasmInputContext::androidKeyboardCallback(int eventType,
- const EmscriptenKeyboardEvent *keyEvent,
- void *userData)
-{
- // we get Enter, Backspace and function keys via emscripten on target window
- Q_UNUSED(eventType)
- QString strKey(keyEvent->key);
- if (strKey == "Unidentified" || strKey == "Process")
- return false;
-
- QWasmInputContext *wasmInput = reinterpret_cast<QWasmInputContext*>(userData);
- wasmInput->inputStringChanged(strKey, wasmInput);
-
- return true;
-}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasminputcontext.h b/src/plugins/platforms/wasm/qwasminputcontext.h
index 086599bfb0..10dd1a0950 100644
--- a/src/plugins/platforms/wasm/qwasminputcontext.h
+++ b/src/plugins/platforms/wasm/qwasminputcontext.h
@@ -29,7 +29,8 @@ public:
bool isValid() const override { return true; }
void focusWindowChanged(QWindow *focusWindow);
- void inputStringChanged(QString &, QWasmInputContext *context);
+ void inputStringChanged(QString &, int eventType, QWasmInputContext *context);
+ emscripten::val m_inputElement = emscripten::val::null();
private:
emscripten::val inputHandlerElementForFocusedWindow();
@@ -37,11 +38,8 @@ private:
bool m_inputPanelVisible = false;
QPointer<QWindow> m_focusWindow;
- emscripten::val m_inputElement = emscripten::val::null();
std::unique_ptr<qstdweb::EventCallback> m_blurEventHandler;
std::unique_ptr<qstdweb::EventCallback> m_inputEventHandler;
- static int androidKeyboardCallback(int eventType,
- const EmscriptenKeyboardEvent *keyEvent, void *userData);
bool inputPanelIsOpen = false;
};
diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp
index 2bdb3b7c69..f5cc3e2eee 100644
--- a/src/plugins/platforms/wasm/qwasmintegration.cpp
+++ b/src/plugins/platforms/wasm/qwasmintegration.cpp
@@ -14,14 +14,14 @@
#include "qwasmwindow.h"
#include "qwasmbackingstore.h"
#include "qwasmfontdatabase.h"
-#if defined(Q_OS_UNIX)
-#include <QtGui/private/qgenericunixeventdispatcher_p.h>
-#endif
+#include "qwasmdrag.h"
+
#include <qpa/qplatformwindow.h>
#include <QtGui/qscreen.h>
#include <qpa/qwindowsysteminterface.h>
#include <QtCore/qcoreapplication.h>
#include <qpa/qplatforminputcontextfactory_p.h>
+#include <qpa/qwindowsysteminterface_p.h>
#include <emscripten/bind.h>
#include <emscripten/val.h>
@@ -38,14 +38,19 @@ using namespace emscripten;
using namespace Qt::StringLiterals;
+static void setContainerElements(emscripten::val elementArray)
+{
+ QWasmIntegration::get()->setContainerElements(elementArray);
+}
+
static void addContainerElement(emscripten::val element)
{
- QWasmIntegration::get()->addScreen(element);
+ QWasmIntegration::get()->addContainerElement(element);
}
static void removeContainerElement(emscripten::val element)
{
- QWasmIntegration::get()->removeScreen(element);
+ QWasmIntegration::get()->removeContainerElement(element);
}
static void resizeContainerElement(emscripten::val element)
@@ -64,22 +69,31 @@ static void resizeAllScreens(emscripten::val event)
QWasmIntegration::get()->resizeAllScreens();
}
+static void loadLocalFontFamilies(emscripten::val event)
+{
+ QWasmIntegration::get()->loadLocalFontFamilies(event);
+}
+
EMSCRIPTEN_BINDINGS(qtQWasmIntegraton)
{
+ function("qtSetContainerElements", &setContainerElements);
function("qtAddContainerElement", &addContainerElement);
function("qtRemoveContainerElement", &removeContainerElement);
function("qtResizeContainerElement", &resizeContainerElement);
function("qtUpdateDpi", &qtUpdateDpi);
function("qtResizeAllScreens", &resizeAllScreens);
+ function("qtLoadLocalFontFamilies", &loadLocalFontFamilies);
}
QWasmIntegration *QWasmIntegration::s_instance;
QWasmIntegration::QWasmIntegration()
- : m_fontDb(nullptr),
- m_desktopServices(nullptr),
- m_clipboard(new QWasmClipboard),
- m_accessibility(new QWasmAccessibility)
+ : m_fontDb(nullptr)
+ , m_desktopServices(nullptr)
+ , m_clipboard(new QWasmClipboard)
+#if QT_CONFIG(accessibility)
+ , m_accessibility(new QWasmAccessibility)
+#endif
{
s_instance = this;
@@ -87,11 +101,13 @@ QWasmIntegration::QWasmIntegration()
qt_set_sequence_auto_mnemonic(false);
touchPoints = emscripten::val::global("navigator")["maxTouchPoints"].as<int>();
+ QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
// Create screens for container elements. Each container element will ultimately become a
// div element. Qt historically supported supplying canvas for screen elements - these elements
// will be transformed into divs and warnings about deprecation will be printed. See
// QWasmScreen ctor.
+ emscripten::val filtered = emscripten::val::array();
emscripten::val qtContainerElements = val::module_property("qtContainerElements");
if (qtContainerElements.isArray()) {
for (int i = 0; i < qtContainerElements["length"].as<int>(); ++i) {
@@ -99,13 +115,14 @@ QWasmIntegration::QWasmIntegration()
if (element.isNull() || element.isUndefined())
qWarning() << "Skipping null or undefined element in qtContainerElements";
else
- addScreen(element);
+ filtered.call<void>("push", element);
}
} else {
// No screens, which may or may not be intended
qWarning() << "The qtContainerElements module property was not set or is invalid. "
"Proceeding with no screens.";
}
+ setContainerElements(filtered);
// install browser window resize handler
emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, EM_TRUE,
@@ -125,7 +142,7 @@ QWasmIntegration::QWasmIntegration()
visualViewport.call<void>("addEventListener", val("resize"),
val::module_property("qtResizeAllScreens"));
}
- m_drag = std::make_unique<QSimpleDrag>();
+ m_drag = std::make_unique<QWasmDrag>();
}
QWasmIntegration::~QWasmIntegration()
@@ -142,10 +159,12 @@ QWasmIntegration::~QWasmIntegration()
delete m_desktopServices;
if (m_platformInputContext)
delete m_platformInputContext;
+#if QT_CONFIG(accessibility)
delete m_accessibility;
+#endif
for (const auto &elementAndScreen : m_screens)
- elementAndScreen.second->deleteScreen();
+ elementAndScreen.wasmScreen->deleteScreen();
m_screens.clear();
@@ -187,6 +206,16 @@ void QWasmIntegration::removeBackingStore(QWindow* window)
m_backingStores.remove(window);
}
+void QWasmIntegration::releaseRequesetUpdateHold()
+{
+ if (QWasmCompositor::releaseRequestUpdateHold())
+ {
+ for (const auto &elementAndScreen : m_screens) {
+ elementAndScreen.wasmScreen->compositor()->requestUpdate();
+ }
+ }
+}
+
#ifndef QT_NO_OPENGL
QPlatformOpenGLContext *QWasmIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
@@ -196,12 +225,12 @@ QPlatformOpenGLContext *QWasmIntegration::createPlatformOpenGLContext(QOpenGLCon
void QWasmIntegration::initialize()
{
- if (qgetenv("QT_IM_MODULE").isEmpty() && touchPoints < 1)
+ auto icStrs = QPlatformInputContextFactory::requested();
+ if (icStrs.isEmpty() && touchPoints < 1)
return;
- QString icStr = QPlatformInputContextFactory::requested();
- if (!icStr.isNull())
- m_inputContext.reset(QPlatformInputContextFactory::create(icStr));
+ if (!icStrs.isEmpty())
+ m_inputContext.reset(QPlatformInputContextFactory::create(icStrs));
else
m_inputContext.reset(new QWasmInputContext());
}
@@ -281,37 +310,93 @@ QPlatformAccessibility *QWasmIntegration::accessibility() const
}
#endif
+void QWasmIntegration::setContainerElements(emscripten::val elementArray)
+{
+ const auto *primaryScreenBefore = m_screens.isEmpty() ? nullptr : m_screens[0].wasmScreen;
+ QList<ScreenMapping> newScreens;
+
+ QList<QWasmScreen *> screensToDelete;
+ std::transform(m_screens.begin(), m_screens.end(), std::back_inserter(screensToDelete),
+ [](const ScreenMapping &mapping) { return mapping.wasmScreen; });
+
+ for (int i = 0; i < elementArray["length"].as<int>(); ++i) {
+ const auto element = elementArray[i];
+ const auto it = std::find_if(
+ m_screens.begin(), m_screens.end(),
+ [&element](const ScreenMapping &screen) { return screen.emscriptenVal == element; });
+ QWasmScreen *screen;
+ if (it != m_screens.end()) {
+ screen = it->wasmScreen;
+ screensToDelete.erase(std::remove_if(screensToDelete.begin(), screensToDelete.end(),
+ [screen](const QWasmScreen *removedScreen) {
+ return removedScreen == screen;
+ }),
+ screensToDelete.end());
+ } else {
+ screen = new QWasmScreen(element);
+ QWindowSystemInterface::handleScreenAdded(screen);
+ }
+ newScreens.push_back({element, screen});
+ }
+
+ std::for_each(screensToDelete.begin(), screensToDelete.end(),
+ [](QWasmScreen *removed) { removed->deleteScreen(); });
-void QWasmIntegration::addScreen(const emscripten::val &element)
+ m_screens = newScreens;
+ auto *primaryScreenAfter = m_screens.isEmpty() ? nullptr : m_screens[0].wasmScreen;
+ if (primaryScreenAfter && primaryScreenAfter != primaryScreenBefore)
+ QWindowSystemInterface::handlePrimaryScreenChanged(primaryScreenAfter);
+}
+
+void QWasmIntegration::addContainerElement(emscripten::val element)
{
+ Q_ASSERT_X(m_screens.end()
+ == std::find_if(m_screens.begin(), m_screens.end(),
+ [&element](const ScreenMapping &screen) {
+ return screen.emscriptenVal == element;
+ }),
+ Q_FUNC_INFO, "Double-add of an element");
+
QWasmScreen *screen = new QWasmScreen(element);
- m_screens.append(qMakePair(element, screen));
QWindowSystemInterface::handleScreenAdded(screen);
+ m_screens.push_back({element, screen});
}
-void QWasmIntegration::removeScreen(const emscripten::val &element)
+void QWasmIntegration::removeContainerElement(emscripten::val element)
{
- auto it = std::find_if(m_screens.begin(), m_screens.end(),
- [&] (const QPair<emscripten::val, QWasmScreen *> &candidate) { return candidate.first.equals(element); });
+ const auto *primaryScreenBefore = m_screens.isEmpty() ? nullptr : m_screens[0].wasmScreen;
+
+ const auto it =
+ std::find_if(m_screens.begin(), m_screens.end(),
+ [&element](const ScreenMapping &screen) { return screen.emscriptenVal == element; });
if (it == m_screens.end()) {
- qWarning() << "Attempting to remove non-existing screen for element"
- << QString::fromJsString(element["id"]);
+ qWarning() << "Attempt to remove a nonexistent screen.";
return;
}
- it->second->deleteScreen();
- m_screens.erase(it);
+
+ QWasmScreen *removedScreen = it->wasmScreen;
+ removedScreen->deleteScreen();
+
+ m_screens.erase(std::remove_if(m_screens.begin(), m_screens.end(),
+ [removedScreen](const ScreenMapping &mapping) {
+ return removedScreen == mapping.wasmScreen;
+ }),
+ m_screens.end());
+ auto *primaryScreenAfter = m_screens.isEmpty() ? nullptr : m_screens[0].wasmScreen;
+ if (primaryScreenAfter && primaryScreenAfter != primaryScreenBefore)
+ QWindowSystemInterface::handlePrimaryScreenChanged(primaryScreenAfter);
}
void QWasmIntegration::resizeScreen(const emscripten::val &element)
{
auto it = std::find_if(m_screens.begin(), m_screens.end(),
- [&] (const QPair<emscripten::val, QWasmScreen *> &candidate) { return candidate.first.equals(element); });
+ [&] (const ScreenMapping &candidate) { return candidate.emscriptenVal.equals(element); });
if (it == m_screens.end()) {
qWarning() << "Attempting to resize non-existing screen for element"
- << QString::fromJsString(element["id"]);
+ << QString::fromEcmaString(element["id"]);
return;
}
- it->second->updateQScreenAndCanvasRenderSize();
+ it->wasmScreen->updateQScreenAndCanvasRenderSize();
}
void QWasmIntegration::updateDpi()
@@ -321,13 +406,18 @@ void QWasmIntegration::updateDpi()
return;
qreal dpiValue = dpi.as<qreal>();
for (const auto &elementAndScreen : m_screens)
- QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(elementAndScreen.second->screen(), dpiValue, dpiValue);
+ QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(elementAndScreen.wasmScreen->screen(), dpiValue, dpiValue);
}
void QWasmIntegration::resizeAllScreens()
{
for (const auto &elementAndScreen : m_screens)
- elementAndScreen.second->updateQScreenAndCanvasRenderSize();
+ elementAndScreen.wasmScreen->updateQScreenAndCanvasRenderSize();
+}
+
+void QWasmIntegration::loadLocalFontFamilies(emscripten::val families)
+{
+ m_fontDb->populateLocalFontFamilies(families);
}
quint64 QWasmIntegration::getTimestamp()
diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h
index decf25009e..870bd0d16b 100644
--- a/src/plugins/platforms/wasm/qwasmintegration.h
+++ b/src/plugins/platforms/wasm/qwasmintegration.h
@@ -14,7 +14,6 @@
#include <QtCore/qhash.h>
-#include <private/qsimpledrag_p.h>
#include <private/qstdweb_p.h>
#include <emscripten.h>
@@ -33,6 +32,7 @@ class QWasmBackingStore;
class QWasmClipboard;
class QWasmAccessibility;
class QWasmServices;
+class QWasmDrag;
class QWasmIntegration : public QObject, public QPlatformIntegration
{
@@ -70,21 +70,29 @@ public:
QWasmInputContext *getWasmInputContext() { return m_platformInputContext; }
static QWasmIntegration *get() { return s_instance; }
- void addScreen(const emscripten::val &canvas);
- void removeScreen(const emscripten::val &canvas);
+ void setContainerElements(emscripten::val elementArray);
+ void addContainerElement(emscripten::val elementArray);
+ void removeContainerElement(emscripten::val elementArray);
void resizeScreen(const emscripten::val &canvas);
- void resizeAllScreens();
void updateDpi();
+ void resizeAllScreens();
+ void loadLocalFontFamilies(emscripten::val families);
void removeBackingStore(QWindow* window);
+ void releaseRequesetUpdateHold();
static quint64 getTimestamp();
int touchPoints;
private:
+ struct ScreenMapping {
+ emscripten::val emscriptenVal;
+ QWasmScreen *wasmScreen;
+ };
+
mutable QWasmFontDatabase *m_fontDb;
mutable QWasmServices *m_desktopServices;
mutable QHash<QWindow *, QWasmBackingStore *> m_backingStores;
- QList<QPair<emscripten::val, QWasmScreen *>> m_screens;
+ QList<ScreenMapping> m_screens;
mutable QWasmClipboard *m_clipboard;
mutable QWasmAccessibility *m_accessibility;
@@ -95,7 +103,7 @@ private:
mutable QWasmInputContext *m_platformInputContext = nullptr;
#if QT_CONFIG(draganddrop)
- std::unique_ptr<QSimpleDrag> m_drag;
+ std::unique_ptr<QWasmDrag> m_drag;
#endif
};
diff --git a/src/plugins/platforms/wasm/qwasmoffscreensurface.cpp b/src/plugins/platforms/wasm/qwasmoffscreensurface.cpp
index 0191e0b216..dcfc4433e6 100644
--- a/src/plugins/platforms/wasm/qwasmoffscreensurface.cpp
+++ b/src/plugins/platforms/wasm/qwasmoffscreensurface.cpp
@@ -27,4 +27,9 @@ QWasmOffscreenSurface::~QWasmOffscreenSurface()
emscripten::val::module_property("specialHTMLTargets").delete_(m_specialTargetId);
}
+bool QWasmOffscreenSurface::isValid() const
+{
+ return !m_offscreenCanvas.isNull() && !m_offscreenCanvas.isUndefined();
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmoffscreensurface.h b/src/plugins/platforms/wasm/qwasmoffscreensurface.h
index 38a991f4ce..1c71310448 100644
--- a/src/plugins/platforms/wasm/qwasmoffscreensurface.h
+++ b/src/plugins/platforms/wasm/qwasmoffscreensurface.h
@@ -20,6 +20,7 @@ public:
~QWasmOffscreenSurface() final;
const std::string &id() const { return m_specialTargetId; }
+ bool isValid() const override;
private:
std::string m_specialTargetId;
diff --git a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp
index fe92f34eca..8a4664ec8c 100644
--- a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp
+++ b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp
@@ -21,16 +21,16 @@ EMSCRIPTEN_BINDINGS(qwasmopenglcontext)
QT_BEGIN_NAMESPACE
QWasmOpenGLContext::QWasmOpenGLContext(QOpenGLContext *context)
- : m_requestedFormat(context->format()), m_qGlContext(context)
+ : m_actualFormat(context->format()), m_qGlContext(context)
{
- m_requestedFormat.setRenderableType(QSurfaceFormat::OpenGLES);
+ m_actualFormat.setRenderableType(QSurfaceFormat::OpenGLES);
// if we set one, we need to set the other as well since in webgl, these are tied together
- if (m_requestedFormat.depthBufferSize() < 0 && m_requestedFormat.stencilBufferSize() > 0)
- m_requestedFormat.setDepthBufferSize(16);
+ if (m_actualFormat.depthBufferSize() < 0 && m_actualFormat.stencilBufferSize() > 0)
+ m_actualFormat.setDepthBufferSize(16);
- if (m_requestedFormat.stencilBufferSize() < 0 && m_requestedFormat.depthBufferSize() > 0)
- m_requestedFormat.setStencilBufferSize(8);
+ if (m_actualFormat.stencilBufferSize() < 0 && m_actualFormat.depthBufferSize() > 0)
+ m_actualFormat.setStencilBufferSize(8);
}
QWasmOpenGLContext::~QWasmOpenGLContext()
@@ -58,28 +58,19 @@ QWasmOpenGLContext::obtainEmscriptenContext(QPlatformSurface *surface)
return m_ownedWebGLContext.handle;
if (surface->surface()->surfaceClass() == QSurface::Offscreen) {
- if (const auto *shareContext = m_qGlContext->shareContext()) {
- // Since there are no resource sharing capabilities with WebGL whatsoever, we use the
- // same actual underlaying WebGL context. This is not perfect, but it works in most
- // cases.
- return static_cast<QWasmOpenGLContext *>(shareContext->handle())
- ->m_ownedWebGLContext.handle;
- } else {
- // Reuse the existing context for offscreen drawing, even if it happens to be a canvas
- // context. This is because it is impossible to re-home an existing context to the
- // new surface and works as an emulation measure.
- if (m_ownedWebGLContext.handle)
- return m_ownedWebGLContext.handle;
-
- // The non-shared offscreen context is heavily limited on WASM, but we provide it
- // anyway for potential pixel readbacks.
- m_ownedWebGLContext =
- QOpenGLContextData{ .surface = surface,
- .handle = createEmscriptenContext(
- static_cast<QWasmOffscreenSurface *>(surface)->id(),
- m_requestedFormat) };
+ // Reuse the existing context for offscreen drawing, even if it happens to be a canvas
+ // context. This is because it is impossible to re-home an existing context to the
+ // new surface and works as an emulation measure.
+ if (m_ownedWebGLContext.handle)
return m_ownedWebGLContext.handle;
- }
+
+ // The non-shared offscreen context is heavily limited on WASM, but we provide it
+ // anyway for potential pixel readbacks.
+ m_ownedWebGLContext =
+ QOpenGLContextData{ .surface = surface,
+ .handle = createEmscriptenContext(
+ static_cast<QWasmOffscreenSurface *>(surface)->id(),
+ m_actualFormat) };
} else {
destroyWebGLContext(m_ownedWebGLContext.handle);
@@ -87,11 +78,23 @@ QWasmOpenGLContext::obtainEmscriptenContext(QPlatformSurface *surface)
m_ownedWebGLContext = QOpenGLContextData{
.surface = surface,
.handle = createEmscriptenContext(static_cast<QWasmWindow *>(surface)->canvasSelector(),
- m_requestedFormat)
+ m_actualFormat)
};
+ }
- return m_ownedWebGLContext.handle;
+ EmscriptenWebGLContextAttributes actualAttributes;
+
+ EMSCRIPTEN_RESULT attributesResult = emscripten_webgl_get_context_attributes(m_ownedWebGLContext.handle, &actualAttributes);
+ if (attributesResult == EMSCRIPTEN_RESULT_SUCCESS) {
+ if (actualAttributes.majorVersion == 1) {
+ m_actualFormat.setMajorVersion(2);
+ } else if (actualAttributes.majorVersion == 2) {
+ m_actualFormat.setMajorVersion(3);
+ }
+ m_actualFormat.setMinorVersion(0);
}
+
+ return m_ownedWebGLContext.handle;
}
void QWasmOpenGLContext::destroyWebGLContext(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE contextHandle)
@@ -116,9 +119,8 @@ QWasmOpenGLContext::createEmscriptenContext(const std::string &canvasSelector,
attributes.failIfMajorPerformanceCaveat = false;
attributes.antialias = true;
attributes.enableExtensionsByDefault = true;
- attributes.majorVersion = format.majorVersion() - 1;
- attributes.minorVersion = format.minorVersion();
-
+ attributes.majorVersion = 2; // try highest supported version ES3.0 / WebGL 2.0
+ attributes.minorVersion = 0; // emscripten only supports minor version 0
// WebGL doesn't allow separate attach buffers to STENCIL_ATTACHMENT and DEPTH_ATTACHMENT
// we need both or none
const bool useDepthStencil = (format.depthBufferSize() > 0 || format.stencilBufferSize() > 0);
@@ -127,13 +129,20 @@ QWasmOpenGLContext::createEmscriptenContext(const std::string &canvasSelector,
attributes.alpha = format.alphaBufferSize() > 0;
attributes.depth = useDepthStencil;
attributes.stencil = useDepthStencil;
+ EMSCRIPTEN_RESULT contextResult = emscripten_webgl_create_context(canvasSelector.c_str(), &attributes);
- return emscripten_webgl_create_context(canvasSelector.c_str(), &attributes);
+ if (contextResult <= 0) {
+ // fallback to opengles2/webgl1
+ // for devices that do not support opengles3/webgl2
+ attributes.majorVersion = 1;
+ contextResult = emscripten_webgl_create_context(canvasSelector.c_str(), &attributes);
+ }
+ return contextResult;
}
QSurfaceFormat QWasmOpenGLContext::format() const
{
- return m_requestedFormat;
+ return m_actualFormat;
}
GLuint QWasmOpenGLContext::defaultFramebufferObject(QPlatformSurface *surface) const
@@ -143,6 +152,15 @@ GLuint QWasmOpenGLContext::defaultFramebufferObject(QPlatformSurface *surface) c
bool QWasmOpenGLContext::makeCurrent(QPlatformSurface *surface)
{
+ static bool sentSharingWarning = false;
+ if (!sentSharingWarning && isSharing()) {
+ qWarning() << "The functionality for sharing OpenGL contexts is limited, see documentation";
+ sentSharingWarning = true;
+ }
+
+ if (auto *shareContext = m_qGlContext->shareContext())
+ return shareContext->makeCurrent(surface->surface());
+
const auto context = obtainEmscriptenContext(surface);
if (!context)
return false;
@@ -170,7 +188,7 @@ bool QWasmOpenGLContext::isSharing() const
bool QWasmOpenGLContext::isValid() const
{
- if (!isOpenGLVersionSupported(m_requestedFormat))
+ if (!isOpenGLVersionSupported(m_actualFormat))
return false;
// Note: we get isValid() calls before we see the surface and can
diff --git a/src/plugins/platforms/wasm/qwasmopenglcontext.h b/src/plugins/platforms/wasm/qwasmopenglcontext.h
index 90863abdfe..2a8bcc5d9b 100644
--- a/src/plugins/platforms/wasm/qwasmopenglcontext.h
+++ b/src/plugins/platforms/wasm/qwasmopenglcontext.h
@@ -1,6 +1,9 @@
// Copyright (C) 2018 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+#ifndef QWASMOPENGLCONTEXT_H
+#define QWASMOPENGLCONTEXT_H
+
#include <qpa/qplatformopenglcontext.h>
#include <emscripten.h>
@@ -40,7 +43,7 @@ private:
static void destroyWebGLContext(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE contextHandle);
- QSurfaceFormat m_requestedFormat;
+ QSurfaceFormat m_actualFormat;
QOpenGLContext *m_qGlContext;
QOpenGLContextData m_ownedWebGLContext;
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE m_usedWebGLContextHandle = 0;
@@ -48,3 +51,4 @@ private:
QT_END_NAMESPACE
+#endif // QWASMOPENGLCONTEXT_H
diff --git a/src/plugins/platforms/wasm/qwasmplatform.cpp b/src/plugins/platforms/wasm/qwasmplatform.cpp
index c641e345e4..e54992be1d 100644
--- a/src/plugins/platforms/wasm/qwasmplatform.cpp
+++ b/src/plugins/platforms/wasm/qwasmplatform.cpp
@@ -13,8 +13,9 @@ Platform platform()
if (rawPlatform.call<bool>("includes", emscripten::val("Mac")))
return Platform::MacOS;
- if (rawPlatform.call<bool>("includes", emscripten::val("iPhone")))
- return Platform::iPhone;
+ if (rawPlatform.call<bool>("includes", emscripten::val("iPhone"))
+ || rawPlatform.call<bool>("includes", emscripten::val("iPad")))
+ return Platform::iOS;
if (rawPlatform.call<bool>("includes", emscripten::val("Win32")))
return Platform::Windows;
if (rawPlatform.call<bool>("includes", emscripten::val("Linux"))) {
diff --git a/src/plugins/platforms/wasm/qwasmplatform.h b/src/plugins/platforms/wasm/qwasmplatform.h
index 239efdeae9..5b32e43633 100644
--- a/src/plugins/platforms/wasm/qwasmplatform.h
+++ b/src/plugins/platforms/wasm/qwasmplatform.h
@@ -19,7 +19,7 @@ enum class Platform {
Windows,
Linux,
Android,
- iPhone,
+ iOS
};
Platform platform();
diff --git a/src/plugins/platforms/wasm/qwasmscreen.cpp b/src/plugins/platforms/wasm/qwasmscreen.cpp
index 6f8d1509ab..ddf8140c48 100644
--- a/src/plugins/platforms/wasm/qwasmscreen.cpp
+++ b/src/plugins/platforms/wasm/qwasmscreen.cpp
@@ -28,6 +28,7 @@ const char *QWasmScreen::m_canvasResizeObserverCallbackContextPropertyName =
QWasmScreen::QWasmScreen(const emscripten::val &containerOrCanvas)
: m_container(containerOrCanvas),
+ m_intermediateContainer(emscripten::val::undefined()),
m_shadowContainer(emscripten::val::undefined()),
m_compositor(new QWasmCompositor(this)),
m_deadKeySupport(std::make_unique<QWasmDeadKeySupport>())
@@ -43,9 +44,20 @@ QWasmScreen::QWasmScreen(const emscripten::val &containerOrCanvas)
m_container["parentNode"].call<void>("replaceChild", container, m_container);
m_container = container;
}
+
+ // Create an intermediate container which we can remove during cleanup in ~QWasmScreen().
+ // This is required due to the attachShadow() call below; there is no corresponding
+ // "detachShadow()" API to return the container to its previous state.
+ m_intermediateContainer = document.call<emscripten::val>("createElement", emscripten::val("div"));
+ m_intermediateContainer.set("id", std::string("qt-shadow-container"));
+ emscripten::val intermediateContainerStyle = m_intermediateContainer["style"];
+ intermediateContainerStyle.set("width", std::string("100%"));
+ intermediateContainerStyle.set("height", std::string("100%"));
+ m_container.call<void>("appendChild", m_intermediateContainer);
+
auto shadowOptions = emscripten::val::object();
shadowOptions.set("mode", "open");
- auto shadow = m_container.call<emscripten::val>("attachShadow", shadowOptions);
+ auto shadow = m_intermediateContainer.call<emscripten::val>("attachShadow", shadowOptions);
m_shadowContainer = document.call<emscripten::val>("createElement", emscripten::val("div"));
@@ -80,12 +92,24 @@ QWasmScreen::QWasmScreen(const emscripten::val &containerOrCanvas)
QPointingDevice::Capability::Position | QPointingDevice::Capability::Area
| QPointingDevice::Capability::NormalizedPosition,
10, 0);
+ m_tabletDevice = std::make_unique<QPointingDevice>(
+ "stylus", 2, QInputDevice::DeviceType::Stylus,
+ QPointingDevice::PointerType::Pen,
+ QPointingDevice::Capability::Position | QPointingDevice::Capability::Pressure
+ | QPointingDevice::Capability::NormalizedPosition
+ | QInputDevice::Capability::MouseEmulation
+ | QInputDevice::Capability::Hover | QInputDevice::Capability::Rotation
+ | QInputDevice::Capability::XTilt | QInputDevice::Capability::YTilt
+ | QInputDevice::Capability::TangentialPressure,
+ 0, 0);
QWindowSystemInterface::registerInputDevice(m_touchDevice.get());
}
QWasmScreen::~QWasmScreen()
{
+ m_intermediateContainer.call<void>("remove");
+
emscripten::val::module_property("specialHTMLTargets")
.set(eventTargetId().toStdString(), emscripten::val::undefined());
@@ -95,7 +119,6 @@ QWasmScreen::~QWasmScreen()
void QWasmScreen::deleteScreen()
{
- m_compositor->onScreenDeleting();
// Deletes |this|!
QWindowSystemInterface::handleScreenRemoved(this);
}
@@ -183,7 +206,7 @@ qreal QWasmScreen::devicePixelRatio() const
QString QWasmScreen::name() const
{
- return QString::fromJsString(m_shadowContainer["id"]);
+ return QString::fromEcmaString(m_shadowContainer["id"]);
}
QPlatformCursor *QWasmScreen::cursor() const
@@ -200,12 +223,18 @@ void QWasmScreen::resizeMaximizedWindows()
QWindow *QWasmScreen::topWindow() const
{
- return m_compositor->keyWindow();
+ return activeChild() ? activeChild()->window() : nullptr;
}
QWindow *QWasmScreen::topLevelAt(const QPoint &p) const
{
- return m_compositor->windowAt(p);
+ const auto found =
+ std::find_if(childStack().begin(), childStack().end(), [&p](const QWasmWindow *window) {
+ const QRect geometry = window->windowFrameGeometry();
+
+ return window->isVisible() && geometry.contains(p);
+ });
+ return found != childStack().end() ? (*found)->window() : nullptr;
}
QPointF QWasmScreen::mapFromLocal(const QPointF &p) const
@@ -233,6 +262,18 @@ void QWasmScreen::setGeometry(const QRect &rect)
resizeMaximizedWindows();
}
+void QWasmScreen::onSubtreeChanged(QWasmWindowTreeNodeChangeType changeType,
+ QWasmWindowTreeNode *parent, QWasmWindow *child)
+{
+ Q_UNUSED(parent);
+ if (changeType == QWasmWindowTreeNodeChangeType::NodeInsertion && parent == this
+ && childStack().size() == 1) {
+ child->window()->setFlag(Qt::WindowStaysOnBottomHint);
+ }
+ QWasmWindowTreeNode::onSubtreeChanged(changeType, parent, child);
+ m_compositor->onWindowTreeChanged(changeType, child);
+}
+
void QWasmScreen::updateQScreenAndCanvasRenderSize()
{
// The HTML canvas has two sizes: the CSS size and the canvas render size.
@@ -261,7 +302,6 @@ void QWasmScreen::updateQScreenAndCanvasRenderSize()
};
setGeometry(QRect(getElementBodyPosition(m_shadowContainer), cssSize.toSize()));
- m_compositor->requestUpdateAllWindows();
}
void QWasmScreen::canvasResizeObserverCallback(emscripten::val entries, emscripten::val)
@@ -307,4 +347,27 @@ void QWasmScreen::installCanvasResizeObserver()
resizeObserver.call<void>("observe", m_shadowContainer);
}
+emscripten::val QWasmScreen::containerElement()
+{
+ return m_shadowContainer;
+}
+
+QWasmWindowTreeNode *QWasmScreen::parentNode()
+{
+ return nullptr;
+}
+
+QList<QWasmWindow *> QWasmScreen::allWindows()
+{
+ QList<QWasmWindow *> windows;
+ for (auto *child : childStack()) {
+ QWindowList list = child->window()->findChildren<QWindow *>(Qt::FindChildrenRecursively);
+ std::transform(
+ list.begin(), list.end(), std::back_inserter(windows),
+ [](const QWindow *window) { return static_cast<QWasmWindow *>(window->handle()); });
+ windows.push_back(child);
+ }
+ return windows;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmscreen.h b/src/plugins/platforms/wasm/qwasmscreen.h
index 633cf853f7..da171d3f50 100644
--- a/src/plugins/platforms/wasm/qwasmscreen.h
+++ b/src/plugins/platforms/wasm/qwasmscreen.h
@@ -6,6 +6,8 @@
#include "qwasmcursor.h"
+#include "qwasmwindowtreenode.h"
+
#include <qpa/qplatformscreen.h>
#include <QtCore/qscopedpointer.h>
@@ -23,7 +25,7 @@ class QWasmCompositor;
class QWasmDeadKeySupport;
class QOpenGLContext;
-class QWasmScreen : public QObject, public QPlatformScreen
+class QWasmScreen : public QObject, public QPlatformScreen, public QWasmWindowTreeNode
{
Q_OBJECT
public:
@@ -37,10 +39,13 @@ public:
QString eventTargetId() const;
QString outerScreenId() const;
QPointingDevice *touchDevice() { return m_touchDevice.get(); }
+ QPointingDevice *tabletDevice() { return m_tabletDevice.get(); }
QWasmCompositor *compositor();
QWasmDeadKeySupport *deadKeySupport() { return m_deadKeySupport.get(); }
+ QList<QWasmWindow *> allWindows();
+
QRect geometry() const override;
int depth() const override;
QImage::Format format() const override;
@@ -53,6 +58,10 @@ public:
QWindow *topWindow() const;
QWindow *topLevelAt(const QPoint &p) const override;
+ // QWasmWindowTreeNode:
+ emscripten::val containerElement() final;
+ QWasmWindowTreeNode *parentNode() final;
+
QPointF mapFromLocal(const QPointF &p) const;
QPointF clipPoint(const QPointF &p) const;
@@ -65,10 +74,16 @@ public slots:
void setGeometry(const QRect &rect);
private:
+ // QWasmWindowTreeNode:
+ void onSubtreeChanged(QWasmWindowTreeNodeChangeType changeType, QWasmWindowTreeNode *parent,
+ QWasmWindow *child) final;
+
emscripten::val m_container;
+ emscripten::val m_intermediateContainer;
emscripten::val m_shadowContainer;
std::unique_ptr<QWasmCompositor> m_compositor;
std::unique_ptr<QPointingDevice> m_touchDevice;
+ std::unique_ptr<QPointingDevice> m_tabletDevice;
std::unique_ptr<QWasmDeadKeySupport> m_deadKeySupport;
QRect m_geometry = QRect(0, 0, 100, 100);
int m_depth = 32;
diff --git a/src/plugins/platforms/wasm/qwasmservices.cpp b/src/plugins/platforms/wasm/qwasmservices.cpp
index f5fd4e4790..e767295e41 100644
--- a/src/plugins/platforms/wasm/qwasmservices.cpp
+++ b/src/plugins/platforms/wasm/qwasmservices.cpp
@@ -12,7 +12,7 @@ QT_BEGIN_NAMESPACE
bool QWasmServices::openUrl(const QUrl &url)
{
- emscripten::val::global("window").call<void>("open", url.toString().toJsString(),
+ emscripten::val::global("window").call<void>("open", url.toString().toEcmaString(),
emscripten::val("_blank"));
return true;
}
diff --git a/src/plugins/platforms/wasm/qwasmwindow.cpp b/src/plugins/platforms/wasm/qwasmwindow.cpp
index 3772217cdb..b8197c5113 100644
--- a/src/plugins/platforms/wasm/qwasmwindow.cpp
+++ b/src/plugins/platforms/wasm/qwasmwindow.cpp
@@ -5,6 +5,7 @@
#include <private/qguiapplication_p.h>
#include <QtCore/qfile.h>
#include <QtGui/private/qwindow_p.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
#include <private/qpixmapcache_p.h>
#include <QtGui/qopenglfunctions.h>
#include <QBuffer>
@@ -32,6 +33,17 @@
QT_BEGIN_NAMESPACE
+namespace {
+QWasmWindowStack::PositionPreference positionPreferenceFromWindowFlags(Qt::WindowFlags flags)
+{
+ if (flags.testFlag(Qt::WindowStaysOnTopHint))
+ return QWasmWindowStack::PositionPreference::StayOnTop;
+ if (flags.testFlag(Qt::WindowStaysOnBottomHint))
+ return QWasmWindowStack::PositionPreference::StayOnBottom;
+ return QWasmWindowStack::PositionPreference::Regular;
+}
+} // namespace
+
Q_GUI_EXPORT int qt_defaultDpiX();
QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport,
@@ -56,6 +68,7 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport,
m_clientArea = std::make_unique<ClientArea>(this, compositor->screen(), m_windowContents);
+ m_windowContents.set("className", "qt-window-contents");
m_qtWindow.call<void>("appendChild", m_windowContents);
m_canvas["classList"].call<void>("add", emscripten::val("qt-window-content"));
@@ -67,9 +80,9 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport,
QWasmClipboard::installEventHandlers(m_canvas);
- // set inputmode to none to stop mobile keyboard opening
+ // set inputMode to none to stop mobile keyboard opening
// when user clicks anywhere on the canvas.
- m_canvas.set("inputmode", std::string("none"));
+ m_canvas.set("inputMode", std::string("none"));
// Hide the canvas from screen readers.
m_canvas.call<void>("setAttribute", std::string("aria-hidden"), std::string("true"));
@@ -82,8 +95,6 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport,
m_canvasContainer.call<void>("appendChild", m_a11yContainer);
m_a11yContainer["classList"].call<void>("add", emscripten::val("qt-window-a11y-container"));
- compositor->screen()->element().call<void>("appendChild", m_qtWindow);
-
const bool rendersTo2dContext = w->surfaceType() != QSurface::OpenGLSurface;
if (rendersTo2dContext)
m_context2d = m_canvas.call<emscripten::val>("getContext", emscripten::val("2d"));
@@ -92,7 +103,6 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport,
m_qtWindow.set("id", "qt-window-" + std::to_string(m_winId));
emscripten::val::module_property("specialHTMLTargets").set(canvasSelector(), m_canvas);
- m_compositor->addWindow(this);
m_flags = window()->flags();
const auto pointerCallback = std::function([this](emscripten::val event) {
@@ -105,12 +115,6 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport,
m_pointerLeaveCallback =
std::make_unique<qstdweb::EventCallback>(m_qtWindow, "pointerleave", pointerCallback);
- m_dropCallback = std::make_unique<qstdweb::EventCallback>(
- m_qtWindow, "drop", [this](emscripten::val event) {
- if (processDrop(*DragEvent::fromWeb(event)))
- event.call<void>("preventDefault");
- });
-
m_wheelEventCallback = std::make_unique<qstdweb::EventCallback>(
m_qtWindow, "wheel", [this](emscripten::val event) {
if (processWheel(*WheelEvent::fromWeb(event)))
@@ -120,21 +124,48 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport,
const auto keyCallback = std::function([this](emscripten::val event) {
if (processKey(*KeyEvent::fromWebWithDeadKeyTranslation(event, m_deadKeySupport)))
event.call<void>("preventDefault");
+ event.call<void>("stopPropagation");
});
+ emscripten::val keyFocusWindow;
+ if (QWasmIntegration::get()->inputContext()) {
+ QWasmInputContext *wasmContext =
+ static_cast<QWasmInputContext *>(QWasmIntegration::get()->inputContext());
+ // if there is an touchscreen input context,
+ // use that window for key input
+ keyFocusWindow = wasmContext->m_inputElement;
+ } else {
+ keyFocusWindow = m_qtWindow;
+ }
+
m_keyDownCallback =
- std::make_unique<qstdweb::EventCallback>(m_qtWindow, "keydown", keyCallback);
- m_keyUpCallback = std::make_unique<qstdweb::EventCallback>(m_qtWindow, "keyup", keyCallback);
+ std::make_unique<qstdweb::EventCallback>(keyFocusWindow, "keydown", keyCallback);
+ m_keyUpCallback = std::make_unique<qstdweb::EventCallback>(keyFocusWindow, "keyup", keyCallback);
+
+ setParent(parent());
}
QWasmWindow::~QWasmWindow()
{
emscripten::val::module_property("specialHTMLTargets").delete_(canvasSelector());
- destroy();
- m_compositor->removeWindow(this);
+ m_canvasContainer.call<void>("removeChild", m_canvas);
+ m_context2d = emscripten::val::undefined();
+ commitParent(nullptr);
if (m_requestAnimationFrameId > -1)
emscripten_cancel_animation_frame(m_requestAnimationFrameId);
+#if QT_CONFIG(accessibility)
QWasmAccessibility::removeAccessibilityEnableButton(window());
+#endif
+}
+
+QSurfaceFormat QWasmWindow::format() const
+{
+ return window()->requestedFormat();
+}
+
+QWasmWindow *QWasmWindow::fromWindow(QWindow *window)
+{
+ return static_cast<QWasmWindow *>(window->handle());
}
void QWasmWindow::onRestoreClicked()
@@ -160,15 +191,14 @@ void QWasmWindow::onCloseClicked()
void QWasmWindow::onNonClientAreaInteraction()
{
- if (!isActive())
- requestActivateWindow();
+ requestActivateWindow();
QGuiApplicationPrivate::instance()->closeAllPopups();
}
bool QWasmWindow::onNonClientEvent(const PointerEvent &event)
{
QPointF pointInScreen = platformScreen()->mapFromLocal(
- dom::mapPoint(event.target, platformScreen()->element(), event.localPoint));
+ dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint));
return QWindowSystemInterface::handleMouseEvent(
window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen),
pointInScreen, event.mouseButtons, event.mouseButton,
@@ -176,46 +206,27 @@ bool QWasmWindow::onNonClientEvent(const PointerEvent &event)
event.modifiers);
}
-void QWasmWindow::destroy()
-{
- m_qtWindow["parentElement"].call<emscripten::val>("removeChild", m_qtWindow);
-
- m_canvasContainer.call<void>("removeChild", m_canvas);
- m_context2d = emscripten::val::undefined();
-}
-
void QWasmWindow::initialize()
{
- QRect rect = windowGeometry();
-
- const auto windowFlags = window()->flags();
- const bool shouldRestrictMinSize =
- !windowFlags.testFlag(Qt::FramelessWindowHint) && !windowIsPopupType(windowFlags);
- const bool isMinSizeUninitialized = window()->minimumSize() == QSize(0, 0);
-
- if (shouldRestrictMinSize && isMinSizeUninitialized)
- window()->setMinimumSize(QSize(minSizeForRegularWindows, minSizeForRegularWindows));
-
-
- const QSize minimumSize = windowMinimumSize();
- const QSize maximumSize = windowMaximumSize();
- const QSize targetSize = !rect.isEmpty() ? rect.size() : minimumSize;
-
- rect.setWidth(qBound(minimumSize.width(), targetSize.width(), maximumSize.width()));
- rect.setHeight(qBound(minimumSize.width(), targetSize.height(), maximumSize.height()));
+ auto initialGeometry = QPlatformWindow::initialGeometry(window(),
+ windowGeometry(), defaultWindowSize, defaultWindowSize);
+ m_normalGeometry = initialGeometry;
setWindowState(window()->windowStates());
setWindowFlags(window()->flags());
setWindowTitle(window()->title());
+ setMask(QHighDpi::toNativeLocalRegion(window()->mask(), window()));
+
if (window()->isTopLevel())
setWindowIcon(window()->icon());
- m_normalGeometry = rect;
QPlatformWindow::setGeometry(m_normalGeometry);
+#if QT_CONFIG(accessibility)
// Add accessibility-enable button. The user can activate this
// button to opt-in to accessibility.
if (window()->isTopLevel())
QWasmAccessibility::addAccessibilityEnableButton(window());
+#endif
}
QWasmScreen *QWasmWindow::platformScreen() const
@@ -254,21 +265,34 @@ void QWasmWindow::setGeometry(const QRect &rect)
if (m_state.testFlag(Qt::WindowMaximized))
return platformScreen()->availableGeometry().marginsRemoved(frameMargins());
- const auto screenGeometry = screen()->geometry();
-
- QRect result(rect);
- result.moveTop(std::max(std::min(rect.y(), screenGeometry.bottom()),
- screenGeometry.y() + margins.top()));
- result.setSize(
- result.size().expandedTo(windowMinimumSize()).boundedTo(windowMaximumSize()));
- return result;
+ auto offset = rect.topLeft() - (!parent() ? screen()->geometry().topLeft() : QPoint());
+
+ // In viewport
+ auto containerGeometryInViewport =
+ QRectF::fromDOMRect(parentNode()->containerElement().call<emscripten::val>(
+ "getBoundingClientRect"))
+ .toRect();
+
+ auto rectInViewport = QRect(containerGeometryInViewport.topLeft() + offset, rect.size());
+
+ QRect cappedGeometry(rectInViewport);
+ if (!parent()) {
+ // Clamp top level windows top position to the screen bounds
+ cappedGeometry.moveTop(
+ std::max(std::min(rectInViewport.y(), containerGeometryInViewport.bottom()),
+ containerGeometryInViewport.y() + margins.top()));
+ }
+ cappedGeometry.setSize(
+ cappedGeometry.size().expandedTo(windowMinimumSize()).boundedTo(windowMaximumSize()));
+ return QRect(QPoint(rect.x(), rect.y() + cappedGeometry.y() - rectInViewport.y()),
+ rect.size());
})();
m_nonClientArea->onClientAreaWidthChange(clientAreaRect.width());
const auto frameRect =
clientAreaRect
.adjusted(-margins.left(), -margins.top(), margins.right(), margins.bottom())
- .translated(-screen()->geometry().topLeft());
+ .translated(!parent() ? -screen()->geometry().topLeft() : QPoint());
m_qtWindow["style"].set("left", std::to_string(frameRect.left()) + "px");
m_qtWindow["style"].set("top", std::to_string(frameRect.top()) + "px");
@@ -306,6 +330,8 @@ void QWasmWindow::setVisible(bool visible)
m_compositor->requestUpdateWindow(this, QWasmCompositor::ExposeEventDelivery);
m_qtWindow["style"].set("display", visible ? "block" : "none");
+ if (window()->isActive())
+ m_canvas.call<void>("focus");
if (visible)
applyWindowState();
}
@@ -329,13 +355,15 @@ QMargins QWasmWindow::frameMargins() const
void QWasmWindow::raise()
{
- m_compositor->raise(this);
+ bringToTop();
invalidate();
+ if (QWasmIntegration::get()->inputContext())
+ m_canvas.call<void>("focus");
}
void QWasmWindow::lower()
{
- m_compositor->lower(this);
+ sendToBottom();
invalidate();
}
@@ -346,12 +374,8 @@ WId QWasmWindow::winId() const
void QWasmWindow::propagateSizeHints()
{
- QRect rect = windowGeometry();
- if (rect.size().width() < windowMinimumSize().width()
- && rect.size().height() < windowMinimumSize().height()) {
- rect.setSize(windowMinimumSize());
- setGeometry(rect);
- }
+ // setGeometry() will take care of minimum and maximum size constraints
+ setGeometry(windowGeometry());
m_nonClientArea->propagateSizeHints();
}
@@ -372,13 +396,16 @@ void QWasmWindow::onActivationChanged(bool active)
void QWasmWindow::setWindowFlags(Qt::WindowFlags flags)
{
- if (flags.testFlag(Qt::WindowStaysOnTopHint) != m_flags.testFlag(Qt::WindowStaysOnTopHint))
- m_compositor->windowPositionPreferenceChanged(this, flags);
+ if (flags.testFlag(Qt::WindowStaysOnTopHint) != m_flags.testFlag(Qt::WindowStaysOnTopHint)
+ || flags.testFlag(Qt::WindowStaysOnBottomHint)
+ != m_flags.testFlag(Qt::WindowStaysOnBottomHint)) {
+ onPositionPreferenceChanged(positionPreferenceFromWindowFlags(flags));
+ }
m_flags = flags;
+ dom::syncCSSClassWith(m_qtWindow, "frameless", !hasFrame());
dom::syncCSSClassWith(m_qtWindow, "has-border", hasBorder());
dom::syncCSSClassWith(m_qtWindow, "has-shadow", hasShadow());
- dom::syncCSSClassWith(m_qtWindow, "has-title", flags.testFlag(Qt::WindowTitleHint));
- dom::syncCSSClassWith(m_qtWindow, "frameless", flags.testFlag(Qt::FramelessWindowHint));
+ dom::syncCSSClassWith(m_qtWindow, "has-title", hasTitleBar());
dom::syncCSSClassWith(m_qtWindow, "transparent-for-input",
flags.testFlag(Qt::WindowTransparentForInput));
@@ -455,6 +482,12 @@ void QWasmWindow::applyWindowState()
setGeometry(newGeom);
}
+void QWasmWindow::commitParent(QWasmWindowTreeNode *parent)
+{
+ onParentChanged(m_commitedParent, parent, positionPreferenceFromWindowFlags(window()->flags()));
+ m_commitedParent = parent;
+}
+
bool QWasmWindow::processKey(const KeyEvent &event)
{
constexpr bool ProceedToNativeEvent = false;
@@ -477,13 +510,13 @@ bool QWasmWindow::processKey(const KeyEvent &event)
bool QWasmWindow::processPointer(const PointerEvent &event)
{
- if (event.pointerType != PointerType::Mouse)
+ if (event.pointerType != PointerType::Mouse && event.pointerType != PointerType::Pen)
return false;
switch (event.type) {
case EventType::PointerEnter: {
const auto pointInScreen = platformScreen()->mapFromLocal(
- dom::mapPoint(event.target, platformScreen()->element(), event.localPoint));
+ dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint));
QWindowSystemInterface::handleEnterEvent(
window(), m_window->mapFromGlobal(pointInScreen), pointInScreen);
break;
@@ -498,30 +531,6 @@ bool QWasmWindow::processPointer(const PointerEvent &event)
return false;
}
-bool QWasmWindow::processDrop(const DragEvent &event)
-{
- m_dropDataReadCancellationFlag = qstdweb::readDataTransfer(
- event.dataTransfer,
- [](QByteArray fileContent) {
- QImage image;
- image.loadFromData(fileContent, nullptr);
- return image;
- },
- [this, event](std::unique_ptr<QMimeData> data) {
- QWindowSystemInterface::handleDrag(window(), data.get(),
- event.pointInPage.toPoint(), event.dropAction,
- event.mouseButton, event.modifiers);
-
- QWindowSystemInterface::handleDrop(window(), data.get(),
- event.pointInPage.toPoint(), event.dropAction,
- event.mouseButton, event.modifiers);
-
- QWindowSystemInterface::handleDrag(window(), nullptr, QPoint(), Qt::IgnoreAction,
- {}, {});
- });
- return true;
-}
-
bool QWasmWindow::processWheel(const WheelEvent &event)
{
// Web scroll deltas are inverted from Qt deltas - negate.
@@ -537,7 +546,7 @@ bool QWasmWindow::processWheel(const WheelEvent &event)
})();
const auto pointInScreen = platformScreen()->mapFromLocal(
- dom::mapPoint(event.target, platformScreen()->element(), event.localPoint));
+ dom::mapPoint(event.target(), platformScreen()->element(), event.localPoint));
return QWindowSystemInterface::handleWheelEvent(
window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen),
@@ -561,16 +570,25 @@ void QWasmWindow::requestUpdate()
m_compositor->requestUpdateWindow(this, QWasmCompositor::UpdateRequestDelivery);
}
+bool QWasmWindow::hasFrame() const
+{
+ return !m_flags.testFlag(Qt::FramelessWindowHint);
+}
+
bool QWasmWindow::hasBorder() const
{
- return !m_state.testFlag(Qt::WindowFullScreen) && !m_flags.testFlag(Qt::FramelessWindowHint)
- && !windowIsPopupType(m_flags);
+ return hasFrame() && !m_state.testFlag(Qt::WindowFullScreen) && !m_flags.testFlag(Qt::SubWindow)
+ && !windowIsPopupType(m_flags) && !parent();
+}
+
+bool QWasmWindow::hasTitleBar() const
+{
+ return hasBorder() && m_flags.testFlag(Qt::WindowTitleHint);
}
bool QWasmWindow::hasShadow() const
{
- return !m_flags.testFlag(Qt::NoDropShadowWindowHint)
- && !m_flags.testFlag(Qt::FramelessWindowHint);
+ return hasBorder() && !m_flags.testFlag(Qt::NoDropShadowWindowHint);
}
bool QWasmWindow::hasMaximizeButton() const
@@ -594,10 +612,8 @@ void QWasmWindow::requestActivateWindow()
return;
}
- if (window()->isTopLevel()) {
- raise();
- m_compositor->setActive(this);
- }
+ raise();
+ setAsActiveNode();
if (!QWasmIntegration::get()->inputContext())
m_canvas.call<void>("focus");
@@ -645,9 +661,41 @@ void QWasmWindow::setMask(const QRegion &region)
m_qtWindow["style"].set("clipPath", emscripten::val(cssClipPath.str()));
}
+void QWasmWindow::setParent(const QPlatformWindow *)
+{
+ commitParent(parentNode());
+}
+
std::string QWasmWindow::canvasSelector() const
{
return "!qtwindow" + std::to_string(m_winId);
}
+emscripten::val QWasmWindow::containerElement()
+{
+ return m_windowContents;
+}
+
+QWasmWindowTreeNode *QWasmWindow::parentNode()
+{
+ if (parent())
+ return static_cast<QWasmWindow *>(parent());
+ return platformScreen();
+}
+
+QWasmWindow *QWasmWindow::asWasmWindow()
+{
+ return this;
+}
+
+void QWasmWindow::onParentChanged(QWasmWindowTreeNode *previous, QWasmWindowTreeNode *current,
+ QWasmWindowStack::PositionPreference positionPreference)
+{
+ if (previous)
+ previous->containerElement().call<void>("removeChild", m_qtWindow);
+ if (current)
+ current->containerElement().call<void>("appendChild", m_qtWindow);
+ QWasmWindowTreeNode::onParentChanged(previous, current, positionPreference);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmwindow.h b/src/plugins/platforms/wasm/qwasmwindow.h
index 661a5160e8..ab0dc68e83 100644
--- a/src/plugins/platforms/wasm/qwasmwindow.h
+++ b/src/plugins/platforms/wasm/qwasmwindow.h
@@ -6,11 +6,14 @@
#include "qwasmintegration.h"
#include <qpa/qplatformwindow.h>
+#include <qpa/qplatformwindow_p.h>
#include <emscripten/html5.h>
#include "qwasmbackingstore.h"
#include "qwasmscreen.h"
#include "qwasmcompositor.h"
#include "qwasmwindownonclientarea.h"
+#include "qwasmwindowstack.h"
+#include "qwasmwindowtreenode.h"
#include <QtCore/private/qstdweb_p.h>
#include "QtGui/qopenglcontext.h"
@@ -23,28 +26,27 @@
QT_BEGIN_NAMESPACE
namespace qstdweb {
-struct CancellationFlag;
-}
-
-namespace qstdweb {
class EventCallback;
}
class ClientArea;
-struct DragEvent;
struct KeyEvent;
struct PointerEvent;
class QWasmDeadKeySupport;
struct WheelEvent;
-class QWasmWindow final : public QPlatformWindow
+class QWasmWindow final : public QPlatformWindow,
+ public QWasmWindowTreeNode,
+ public QNativeInterface::Private::QWasmWindow
{
public:
QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport, QWasmCompositor *compositor,
QWasmBackingStore *backingStore);
~QWasmWindow() final;
- void destroy();
+ static QWasmWindow *fromWindow(QWindow *window);
+ QSurfaceFormat format() const override;
+
void paint();
void setZOrder(int order);
void setWindowCursor(QByteArray cssCursorName);
@@ -80,6 +82,7 @@ public:
bool setMouseGrabEnabled(bool grab) final;
bool windowEvent(QEvent *event) final;
void setMask(const QRegion &region) final;
+ void setParent(const QPlatformWindow *window) final;
QWasmScreen *platformScreen() const;
void setBackingStore(QWasmBackingStore *store) { m_backingStore = store; }
@@ -87,23 +90,39 @@ public:
QWindow *window() const { return m_window; }
std::string canvasSelector() const;
+
emscripten::val context2d() const { return m_context2d; }
emscripten::val a11yContainer() const { return m_a11yContainer; }
emscripten::val inputHandlerElement() const { return m_windowContents; }
+ // QNativeInterface::Private::QWasmWindow
+ emscripten::val document() const override { return m_document; }
+ emscripten::val clientArea() const override { return m_qtWindow; }
+
+ // QWasmWindowTreeNode:
+ emscripten::val containerElement() final;
+ QWasmWindowTreeNode *parentNode() final;
+
private:
friend class QWasmScreen;
- static constexpr auto minSizeForRegularWindows = 100;
+ static constexpr auto defaultWindowSize = 160;
+
+ // QWasmWindowTreeNode:
+ QWasmWindow *asWasmWindow() final;
+ void onParentChanged(QWasmWindowTreeNode *previous, QWasmWindowTreeNode *current,
+ QWasmWindowStack::PositionPreference positionPreference) final;
void invalidate();
+ bool hasFrame() const;
+ bool hasTitleBar() const;
bool hasBorder() const;
bool hasShadow() const;
bool hasMaximizeButton() const;
void applyWindowState();
+ void commitParent(QWasmWindowTreeNode *parent);
bool processKey(const KeyEvent &event);
bool processPointer(const PointerEvent &event);
- bool processDrop(const DragEvent &event);
bool processWheel(const WheelEvent &event);
QWindow *m_window = nullptr;
@@ -123,6 +142,8 @@ private:
std::unique_ptr<NonClientArea> m_nonClientArea;
std::unique_ptr<ClientArea> m_clientArea;
+ QWasmWindowTreeNode *m_commitedParent = nullptr;
+
std::unique_ptr<qstdweb::EventCallback> m_keyDownCallback;
std::unique_ptr<qstdweb::EventCallback> m_keyUpCallback;
@@ -148,8 +169,6 @@ private:
friend class QWasmCompositor;
friend class QWasmEventTranslator;
bool windowIsPopupType(Qt::WindowFlags flags) const;
-
- std::shared_ptr<qstdweb::CancellationFlag> m_dropDataReadCancellationFlag;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmwindowclientarea.cpp b/src/plugins/platforms/wasm/qwasmwindowclientarea.cpp
index e3b681adb5..6da3e24c05 100644
--- a/src/plugins/platforms/wasm/qwasmwindowclientarea.cpp
+++ b/src/plugins/platforms/wasm/qwasmwindowclientarea.cpp
@@ -7,6 +7,7 @@
#include "qwasmevent.h"
#include "qwasmscreen.h"
#include "qwasmwindow.h"
+#include "qwasmdrag.h"
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/qpointingdevice.h>
@@ -19,8 +20,9 @@ ClientArea::ClientArea(QWasmWindow *window, QWasmScreen *screen, emscripten::val
: m_screen(screen), m_window(window), m_element(element)
{
const auto callback = std::function([this](emscripten::val event) {
- if (processPointer(*PointerEvent::fromWeb(event)))
- event.call<void>("preventDefault");
+ processPointer(*PointerEvent::fromWeb(event));
+ event.call<void>("preventDefault");
+ event.call<void>("stopPropagation");
});
m_pointerDownCallback =
@@ -30,34 +32,50 @@ ClientArea::ClientArea(QWasmWindow *window, QWasmScreen *screen, emscripten::val
m_pointerUpCallback = std::make_unique<qstdweb::EventCallback>(element, "pointerup", callback);
m_pointerCancelCallback =
std::make_unique<qstdweb::EventCallback>(element, "pointercancel", callback);
+
+ element.call<void>("setAttribute", emscripten::val("draggable"), emscripten::val("true"));
+
+ m_dragStartCallback = std::make_unique<qstdweb::EventCallback>(
+ element, "dragstart", [this](emscripten::val webEvent) {
+ webEvent.call<void>("preventDefault");
+ auto event = *DragEvent::fromWeb(webEvent, m_window->window());
+ QWasmDrag::instance()->onNativeDragStarted(&event);
+ });
+ m_dragOverCallback = std::make_unique<qstdweb::EventCallback>(
+ element, "dragover", [this](emscripten::val webEvent) {
+ webEvent.call<void>("preventDefault");
+ auto event = *DragEvent::fromWeb(webEvent, m_window->window());
+ QWasmDrag::instance()->onNativeDragOver(&event);
+ });
+ m_dropCallback = std::make_unique<qstdweb::EventCallback>(
+ element, "drop", [this](emscripten::val webEvent) {
+ webEvent.call<void>("preventDefault");
+ auto event = *DragEvent::fromWeb(webEvent, m_window->window());
+ QWasmDrag::instance()->onNativeDrop(&event);
+ });
+ m_dragEndCallback = std::make_unique<qstdweb::EventCallback>(
+ element, "dragend", [this](emscripten::val webEvent) {
+ webEvent.call<void>("preventDefault");
+ auto event = *DragEvent::fromWeb(webEvent, m_window->window());
+ QWasmDrag::instance()->onNativeDragFinished(&event);
+ });
+
}
bool ClientArea::processPointer(const PointerEvent &event)
{
- const auto localScreenPoint =
- dom::mapPoint(event.target, m_screen->element(), event.localPoint);
- const auto pointInScreen = m_screen->mapFromLocal(localScreenPoint);
-
- const QPointF pointInTargetWindowCoords = m_window->window()->mapFromGlobal(pointInScreen);
switch (event.type) {
case EventType::PointerDown:
m_element.call<void>("setPointerCapture", event.pointerId);
- m_window->window()->requestActivate();
+ if ((m_window->window()->flags() & Qt::WindowDoesNotAcceptFocus)
+ != Qt::WindowDoesNotAcceptFocus
+ && m_window->window()->isTopLevel())
+ m_window->window()->requestActivate();
break;
case EventType::PointerUp:
m_element.call<void>("releasePointerCapture", event.pointerId);
break;
- case EventType::PointerEnter:
- if (event.isPrimary) {
- QWindowSystemInterface::handleEnterEvent(m_window->window(), pointInTargetWindowCoords,
- pointInScreen);
- }
- break;
- case EventType::PointerLeave:
- if (event.isPrimary)
- QWindowSystemInterface::handleLeaveEvent(m_window->window());
- break;
default:
break;
};
@@ -71,7 +89,7 @@ bool ClientArea::processPointer(const PointerEvent &event)
bool ClientArea::deliverEvent(const PointerEvent &event)
{
const auto pointInScreen = m_screen->mapFromLocal(
- dom::mapPoint(event.target, m_screen->element(), event.localPoint));
+ dom::mapPoint(event.target(), m_screen->element(), event.localPoint));
const auto geometryF = m_screen->geometry().toRectF();
const QPointF targetPointClippedToScreen(
@@ -90,6 +108,31 @@ bool ClientArea::deliverEvent(const PointerEvent &event)
eventType, event.modifiers);
}
+ if (event.pointerType == PointerType::Pen) {
+ qreal pressure;
+ switch (event.type) {
+ case EventType::PointerDown :
+ case EventType::PointerMove :
+ pressure = event.pressure;
+ break;
+ case EventType::PointerUp :
+ pressure = 0.0;
+ break;
+ default:
+ return false;
+ }
+ // Tilt in the browser is in the range +-90, but QTabletEvent only goes to +-60.
+ qreal xTilt = qBound(-60.0, event.tiltX, 60.0);
+ qreal yTilt = qBound(-60.0, event.tiltY, 60.0);
+ // Barrel rotation is reported as 0 to 359, but QTabletEvent wants a signed value.
+ qreal rotation = event.twist > 180.0 ? 360.0 - event.twist : event.twist;
+ return QWindowSystemInterface::handleTabletEvent(
+ m_window->window(), QWasmIntegration::getTimestamp(), m_screen->tabletDevice(),
+ m_window->window()->mapFromGlobal(targetPointClippedToScreen),
+ targetPointClippedToScreen, event.mouseButtons, pressure, xTilt, yTilt,
+ event.tangentialPressure, rotation, event.modifiers);
+ }
+
QWindowSystemInterface::TouchPoint *touchPoint;
QPointF pointInTargetWindowCoords =
@@ -98,14 +141,17 @@ bool ClientArea::deliverEvent(const PointerEvent &event)
pointInTargetWindowCoords.y() / m_window->window()->height());
const auto tp = m_pointerIdToTouchPoints.find(event.pointerId);
- if (tp != m_pointerIdToTouchPoints.end()) {
+ if (event.pointerType != PointerType::Pen && tp != m_pointerIdToTouchPoints.end()) {
touchPoint = &tp.value();
} else {
touchPoint = &m_pointerIdToTouchPoints
.insert(event.pointerId, QWindowSystemInterface::TouchPoint())
.value();
- touchPoint->id = event.pointerId;
+ // Assign touch point id. TouchPoint::id is int, but QGuiApplicationPrivate::processTouchEvent()
+ // will not synthesize mouse events for touch points with negative id; use the absolute value for
+ // the touch point id.
+ touchPoint->id = qAbs(event.pointerId);
touchPoint->state = QEventPoint::State::Pressed;
}
diff --git a/src/plugins/platforms/wasm/qwasmwindowclientarea.h b/src/plugins/platforms/wasm/qwasmwindowclientarea.h
index 49f515a71a..ba745a59a8 100644
--- a/src/plugins/platforms/wasm/qwasmwindowclientarea.h
+++ b/src/plugins/platforms/wasm/qwasmwindowclientarea.h
@@ -6,6 +6,7 @@
#include <QtCore/qnamespace.h>
#include <qpa/qwindowsysteminterface.h>
+#include <QtCore/QMap>
#include <emscripten/val.h>
@@ -35,6 +36,11 @@ private:
std::unique_ptr<qstdweb::EventCallback> m_pointerUpCallback;
std::unique_ptr<qstdweb::EventCallback> m_pointerCancelCallback;
+ std::unique_ptr<qstdweb::EventCallback> m_dragOverCallback;
+ std::unique_ptr<qstdweb::EventCallback> m_dragStartCallback;
+ std::unique_ptr<qstdweb::EventCallback> m_dragEndCallback;
+ std::unique_ptr<qstdweb::EventCallback> m_dropCallback;
+
QMap<int, QWindowSystemInterface::TouchPoint> m_pointerIdToTouchPoints;
QWasmScreen *m_screen;
diff --git a/src/plugins/platforms/wasm/qwasmwindownonclientarea.cpp b/src/plugins/platforms/wasm/qwasmwindownonclientarea.cpp
index bc597069e7..00fa8fb236 100644
--- a/src/plugins/platforms/wasm/qwasmwindownonclientarea.cpp
+++ b/src/plugins/platforms/wasm/qwasmwindownonclientarea.cpp
@@ -187,9 +187,11 @@ ResizeConstraints Resizer::getResizeConstraints() {
const auto frameRect =
QRectF::fromDOMRect(m_windowElement.call<emscripten::val>("getBoundingClientRect"));
- const auto screenRect = QRectF::fromDOMRect(
- m_window->platformScreen()->element().call<emscripten::val>("getBoundingClientRect"));
- const int maxGrowTop = frameRect.top() - screenRect.top();
+ auto containerGeometry =
+ QRectF::fromDOMRect(m_window->parentNode()->containerElement().call<emscripten::val>(
+ "getBoundingClientRect"));
+
+ const int maxGrowTop = frameRect.top() - containerGeometry.top();
return ResizeConstraints{minShrink, maxGrow, maxGrowTop};
}
@@ -206,11 +208,12 @@ void Resizer::startResize(Qt::Edges resizeEdges, const PointerEvent &event)
m_currentResizeData.reset(new ResizeData{
.edges = resizeEdges,
.originInScreenCoords = dom::mapPoint(
- event.target, m_window->platformScreen()->element(), event.localPoint),
+ event.target(), m_window->platformScreen()->element(), event.localPoint),
});
const auto resizeConstraints = getResizeConstraints();
m_currentResizeData->minShrink = resizeConstraints.minShrink;
+
m_currentResizeData->maxGrow =
QPoint(resizeConstraints.maxGrow.x(),
std::min(resizeEdges & Qt::Edge::TopEdge ? resizeConstraints.maxGrowTop : INT_MAX,
@@ -222,7 +225,7 @@ void Resizer::startResize(Qt::Edges resizeEdges, const PointerEvent &event)
void Resizer::continueResize(const PointerEvent &event)
{
const auto pointInScreen =
- dom::mapPoint(event.target, m_window->platformScreen()->element(), event.localPoint);
+ dom::mapPoint(event.target(), m_window->platformScreen()->element(), event.localPoint);
const auto amount = (pointInScreen - m_currentResizeData->originInScreenCoords).toPoint();
const QPoint cappedGrowVector(
std::min(m_currentResizeData->maxGrow.x(),
@@ -415,9 +418,15 @@ bool TitleBar::onDoubleClick()
QPointF TitleBar::clipPointWithScreen(const QPointF &pointInTitleBarCoords) const
{
- auto *screen = m_window->platformScreen();
- return screen->clipPoint(screen->mapFromLocal(
- dom::mapPoint(m_element, screen->element(), pointInTitleBarCoords)));
+ auto containerRect =
+ QRectF::fromDOMRect(m_window->parentNode()->containerElement().call<emscripten::val>(
+ "getBoundingClientRect"));
+ const auto p = dom::mapPoint(m_element, m_window->parentNode()->containerElement(),
+ pointInTitleBarCoords);
+
+ auto result = QPointF(qBound(0., qreal(p.x()), containerRect.width()),
+ qBound(0., qreal(p.y()), containerRect.height()));
+ return m_window->parent() ? result : m_window->platformScreen()->mapFromLocal(result).toPoint();
}
NonClientArea::NonClientArea(QWasmWindow *window, emscripten::val qtWindowElement)
diff --git a/src/plugins/platforms/wasm/qwasmwindowtreenode.cpp b/src/plugins/platforms/wasm/qwasmwindowtreenode.cpp
new file mode 100644
index 0000000000..ea8d8dbcfa
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmwindowtreenode.cpp
@@ -0,0 +1,108 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwasmwindowtreenode.h"
+
+#include "qwasmwindow.h"
+
+QWasmWindowTreeNode::QWasmWindowTreeNode()
+ : m_childStack(std::bind(&QWasmWindowTreeNode::onTopWindowChanged, this))
+{
+}
+
+QWasmWindowTreeNode::~QWasmWindowTreeNode() = default;
+
+void QWasmWindowTreeNode::onParentChanged(QWasmWindowTreeNode *previousParent,
+ QWasmWindowTreeNode *currentParent,
+ QWasmWindowStack::PositionPreference positionPreference)
+{
+ auto *window = asWasmWindow();
+ if (previousParent) {
+ previousParent->m_childStack.removeWindow(window);
+ previousParent->onSubtreeChanged(QWasmWindowTreeNodeChangeType::NodeRemoval, previousParent,
+ window);
+ }
+
+ if (currentParent) {
+ currentParent->m_childStack.pushWindow(window, positionPreference);
+ currentParent->onSubtreeChanged(QWasmWindowTreeNodeChangeType::NodeInsertion, currentParent,
+ window);
+ }
+}
+
+QWasmWindow *QWasmWindowTreeNode::asWasmWindow()
+{
+ return nullptr;
+}
+
+void QWasmWindowTreeNode::onSubtreeChanged(QWasmWindowTreeNodeChangeType changeType,
+ QWasmWindowTreeNode *parent, QWasmWindow *child)
+{
+ if (changeType == QWasmWindowTreeNodeChangeType::NodeInsertion && parent == this
+ && m_childStack.topWindow()
+ && m_childStack.topWindow()->window()) {
+
+ const QVariant showWithoutActivating = m_childStack.topWindow()->window()->property("_q_showWithoutActivating");
+ if (!showWithoutActivating.isValid() || !showWithoutActivating.toBool())
+ m_childStack.topWindow()->requestActivateWindow();
+ }
+
+ if (parentNode())
+ parentNode()->onSubtreeChanged(changeType, parent, child);
+}
+
+void QWasmWindowTreeNode::setWindowZOrder(QWasmWindow *window, int z)
+{
+ window->setZOrder(z);
+}
+
+void QWasmWindowTreeNode::onPositionPreferenceChanged(
+ QWasmWindowStack::PositionPreference positionPreference)
+{
+ if (parentNode()) {
+ parentNode()->m_childStack.windowPositionPreferenceChanged(asWasmWindow(),
+ positionPreference);
+ }
+}
+
+void QWasmWindowTreeNode::setAsActiveNode()
+{
+ if (parentNode())
+ parentNode()->setActiveChildNode(asWasmWindow());
+}
+
+void QWasmWindowTreeNode::bringToTop()
+{
+ if (!parentNode())
+ return;
+ parentNode()->m_childStack.raise(asWasmWindow());
+ parentNode()->bringToTop();
+}
+
+void QWasmWindowTreeNode::sendToBottom()
+{
+ if (!parentNode())
+ return;
+ m_childStack.lower(asWasmWindow());
+}
+
+void QWasmWindowTreeNode::onTopWindowChanged()
+{
+ constexpr int zOrderForElementInFrontOfScreen = 3;
+ int z = zOrderForElementInFrontOfScreen;
+ std::for_each(m_childStack.rbegin(), m_childStack.rend(),
+ [this, &z](QWasmWindow *window) { setWindowZOrder(window, z++); });
+}
+
+void QWasmWindowTreeNode::setActiveChildNode(QWasmWindow *activeChild)
+{
+ m_activeChild = activeChild;
+
+ auto it = m_childStack.begin();
+ if (it == m_childStack.end())
+ return;
+ for (; it != m_childStack.end(); ++it)
+ (*it)->onActivationChanged(*it == m_activeChild);
+
+ setAsActiveNode();
+}
diff --git a/src/plugins/platforms/wasm/qwasmwindowtreenode.h b/src/plugins/platforms/wasm/qwasmwindowtreenode.h
new file mode 100644
index 0000000000..344fdb43cb
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmwindowtreenode.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWASMWINDOWTREENODE_H
+#define QWASMWINDOWTREENODE_H
+
+#include "qwasmwindowstack.h"
+
+namespace emscripten {
+class val;
+}
+
+class QWasmWindow;
+
+enum class QWasmWindowTreeNodeChangeType {
+ NodeInsertion,
+ NodeRemoval,
+};
+
+class QWasmWindowTreeNode
+{
+public:
+ QWasmWindowTreeNode();
+ virtual ~QWasmWindowTreeNode();
+
+ virtual emscripten::val containerElement() = 0;
+ virtual QWasmWindowTreeNode *parentNode() = 0;
+
+protected:
+ virtual void onParentChanged(QWasmWindowTreeNode *previous, QWasmWindowTreeNode *current,
+ QWasmWindowStack::PositionPreference positionPreference);
+ virtual QWasmWindow *asWasmWindow();
+ virtual void onSubtreeChanged(QWasmWindowTreeNodeChangeType changeType,
+ QWasmWindowTreeNode *parent, QWasmWindow *child);
+ virtual void setWindowZOrder(QWasmWindow *window, int z);
+
+ void onPositionPreferenceChanged(QWasmWindowStack::PositionPreference positionPreference);
+ void setAsActiveNode();
+ void bringToTop();
+ void sendToBottom();
+
+ const QWasmWindowStack &childStack() const { return m_childStack; }
+ QWasmWindow *activeChild() const { return m_activeChild; }
+
+private:
+ void onTopWindowChanged();
+ void setActiveChildNode(QWasmWindow *activeChild);
+
+ QWasmWindowStack m_childStack;
+ QWasmWindow *m_activeChild = nullptr;
+};
+
+#endif // QWASMWINDOWTREENODE_H
diff --git a/src/plugins/platforms/wasm/wasm_shell.html b/src/plugins/platforms/wasm/wasm_shell.html
index aaa121981d..702ea1f59d 100644
--- a/src/plugins/platforms/wasm/wasm_shell.html
+++ b/src/plugins/platforms/wasm/wasm_shell.html
@@ -27,42 +27,48 @@
</figure>
<div id="screen"></div>
- <script type='text/javascript'>
- let qtLoader = undefined;
- function init() {
- var spinner = document.querySelector('#qtspinner');
- var canvas = document.querySelector('#screen');
- var status = document.querySelector('#qtstatus')
+ <script type="text/javascript">
+ async function init()
+ {
+ const spinner = document.querySelector('#qtspinner');
+ const screen = document.querySelector('#screen');
+ const status = document.querySelector('#qtstatus');
- qtLoader = new QtLoader({
- canvasElements : [canvas],
- showLoader: function(loaderStatus) {
- spinner.style.display = 'block';
- canvas.style.display = 'none';
- status.innerHTML = loaderStatus + "...";
- },
- showError: function(errorText) {
- status.innerHTML = errorText;
- spinner.style.display = 'block';
- canvas.style.display = 'none';
- },
- showExit: function() {
- status.innerHTML = "Application exit";
- if (qtLoader.exitCode !== undefined)
- status.innerHTML += " with code " + qtLoader.exitCode;
- if (qtLoader.exitText !== undefined)
- status.innerHTML += " (" + qtLoader.exitText + ")";
- spinner.style.display = 'block';
- canvas.style.display = 'none';
- },
- showCanvas: function() {
- spinner.style.display = 'none';
- canvas.style.display = 'block';
- },
- });
- qtLoader.loadEmscriptenModule("@APPNAME@");
- }
+ const showUi = (ui) => {
+ [spinner, screen].forEach(element => element.style.display = 'none');
+ if (screen === ui)
+ screen.style.position = 'default';
+ ui.style.display = 'block';
+ }
+
+ try {
+ showUi(spinner);
+ status.innerHTML = 'Loading...';
+
+ const instance = await qtLoad({
+ qt: {
+ onLoaded: () => showUi(screen),
+ onExit: exitData =>
+ {
+ status.innerHTML = 'Application exit';
+ status.innerHTML +=
+ exitData.code !== undefined ? ` with code ${exitData.code}` : '';
+ status.innerHTML +=
+ exitData.text !== undefined ? ` (${exitData.text})` : '';
+ showUi(spinner);
+ },
+ entryFunction: window.@APPEXPORTNAME@,
+ containerElements: [screen],
+ @PRELOAD@
+ }
+ });
+ } catch (e) {
+ console.error(e);
+ console.error(e.stack);
+ }
+ }
</script>
+ <script src="@APPNAME@.js"></script>
<script type="text/javascript" src="qtloader.js"></script>
</body>
</html>
diff --git a/src/plugins/platforms/windows/CMakeLists.txt b/src/plugins/platforms/windows/CMakeLists.txt
index 4425e78b30..4b92317978 100644
--- a/src/plugins/platforms/windows/CMakeLists.txt
+++ b/src/plugins/platforms/windows/CMakeLists.txt
@@ -15,13 +15,13 @@ qt_internal_add_plugin(QWindowsIntegrationPlugin
qwin10helpers.cpp qwin10helpers.h
qwindowsapplication.cpp qwindowsapplication.h
qwindowsbackingstore.cpp qwindowsbackingstore.h
- qwindowscombase.h
qwindowscontext.cpp qwindowscontext.h
qwindowscursor.cpp qwindowscursor.h
qwindowsdialoghelpers.cpp qwindowsdialoghelpers.h
qwindowsdropdataobject.cpp qwindowsdropdataobject.h
qwindowsgdiintegration.cpp qwindowsgdiintegration.h
qwindowsgdinativeinterface.cpp qwindowsgdinativeinterface.h
+ qwindowsiconengine.cpp qwindowsiconengine.h
qwindowsinputcontext.cpp qwindowsinputcontext.h
qwindowsintegration.cpp qwindowsintegration.h
qwindowsinternalmimedata.cpp qwindowsinternalmimedata.h
@@ -38,6 +38,8 @@ qt_internal_add_plugin(QWindowsIntegrationPlugin
qwindowstheme.cpp qwindowstheme.h
qwindowsthreadpoolrunner.h
qwindowswindow.cpp qwindowswindow.h
+ NO_UNITY_BUILD_SOURCES
+ qwindowspointerhandler.cpp
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_FOREACH
@@ -54,6 +56,7 @@ qt_internal_add_plugin(QWindowsIntegrationPlugin
imm32
ole32
oleaut32
+ setupapi
shell32
shlwapi
user32
@@ -66,10 +69,6 @@ qt_internal_add_plugin(QWindowsIntegrationPlugin
runtimeobject
)
-# Duplicated symbols
-set_source_files_properties(qwindowspointerhandler.cpp qwindowsmousehandler.cpp
- PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
-
# Resources:
set_source_files_properties("openglblacklists/default.json"
PROPERTIES QT_RESOURCE_ALIAS "default.json"
@@ -104,6 +103,8 @@ qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_opengl
qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION MINGW
LIBRARIES
uuid
+ NO_PCH_SOURCES
+ qwindowspointerhandler.cpp
)
qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_systemtrayicon
@@ -174,6 +175,7 @@ endif()
qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_accessibility
SOURCES
+ uiautomation/qwindowsuiautomation.cpp uiautomation/qwindowsuiautomation.h
uiautomation/qwindowsuiaaccessibility.cpp uiautomation/qwindowsuiaaccessibility.h
uiautomation/qwindowsuiabaseprovider.cpp uiautomation/qwindowsuiabaseprovider.h
uiautomation/qwindowsuiaexpandcollapseprovider.cpp uiautomation/qwindowsuiaexpandcollapseprovider.h
@@ -195,11 +197,17 @@ qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION QT_FEATURE_accessi
uiautomation/qwindowsuiawindowprovider.cpp uiautomation/qwindowsuiawindowprovider.h
)
+if(QT_FEATURE_accessibility)
+ find_library(UI_AUTOMATION_LIBRARY uiautomationcore)
+ if(UI_AUTOMATION_LIBRARY)
+ qt_internal_extend_target(QWindowsIntegrationPlugin
+ LIBRARIES
+ ${UI_AUTOMATION_LIBRARY}
+ )
+ endif()
+endif()
+
qt_internal_extend_target(QWindowsIntegrationPlugin CONDITION MINGW AND QT_FEATURE_accessibility
LIBRARIES
uuid
)
-
-if (MINGW)
- set_source_files_properties(qwindowspointerhandler.cpp PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
-endif()
diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h
index 22787bd63e..96a72600eb 100644
--- a/src/plugins/platforms/windows/qtwindowsglobal.h
+++ b/src/plugins/platforms/windows/qtwindowsglobal.h
@@ -119,7 +119,7 @@ enum WindowsEventType // Simplify event types
NonClientPointerEvent = NonClientEventFlag + PointerEventFlag + 4,
KeyEvent = KeyEventFlag + 1,
KeyDownEvent = KeyEventFlag + KeyDownEventFlag + 1,
- KeyboardLayoutChangeEvent = KeyEventFlag + 2,
+ InputLanguageChangeEvent = KeyEventFlag + 2,
InputMethodKeyEvent = InputMethodEventFlag + KeyEventFlag + 1,
InputMethodKeyDownEvent = InputMethodEventFlag + KeyEventFlag + KeyDownEventFlag + 1,
ClipboardEvent = ClipboardEventFlag + 1,
@@ -230,7 +230,7 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
return QtWindows::InputMethodKeyDownEvent;
#ifdef WM_INPUTLANGCHANGE
case WM_INPUTLANGCHANGE:
- return QtWindows::KeyboardLayoutChangeEvent;
+ return QtWindows::InputLanguageChangeEvent;
#endif // WM_INPUTLANGCHANGE
case WM_TOUCH:
return QtWindows::TouchEvent;
diff --git a/src/plugins/platforms/windows/qwindowsapplication.cpp b/src/plugins/platforms/windows/qwindowsapplication.cpp
index 00477e2890..42e34ac99f 100644
--- a/src/plugins/platforms/windows/qwindowsapplication.cpp
+++ b/src/plugins/platforms/windows/qwindowsapplication.cpp
@@ -72,11 +72,6 @@ bool QWindowsApplication::setWinTabEnabled(bool enabled)
return enabled ? ctx->initTablet() : ctx->disposeTablet();
}
-bool QWindowsApplication::isDarkMode() const
-{
- return QWindowsContext::isDarkMode();
-}
-
QWindowsApplication::DarkModeHandling QWindowsApplication::darkModeHandling() const
{
return m_darkModeHandling;
@@ -143,9 +138,9 @@ QVariant QWindowsApplication::gpuList() const
return result;
}
-void QWindowsApplication::lightSystemPalette(QPalette &result) const
+void QWindowsApplication::populateLightSystemPalette(QPalette &result) const
{
- QWindowsTheme::populateLightSystemBasePalette(result);
+ result = QWindowsTheme::systemPalette(Qt::ColorScheme::Light);
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsapplication.h b/src/plugins/platforms/windows/qwindowsapplication.h
index 8b74b47f3d..0918df91af 100644
--- a/src/plugins/platforms/windows/qwindowsapplication.h
+++ b/src/plugins/platforms/windows/qwindowsapplication.h
@@ -24,7 +24,6 @@ public:
bool isWinTabEnabled() const override;
bool setWinTabEnabled(bool enabled) override;
- bool isDarkMode() const override;
DarkModeHandling darkModeHandling() const override;
void setDarkModeHandling(DarkModeHandling handling) override;
@@ -43,7 +42,7 @@ public:
QVariant gpu() const override;
QVariant gpuList() const override;
- void lightSystemPalette(QPalette &palette) const override;
+ void populateLightSystemPalette(QPalette &palette) const override;
private:
WindowActivationBehavior m_windowActivationBehavior = DefaultActivateWindow;
diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp
index 0f9d0172d9..07918f6094 100644
--- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp
+++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp
@@ -117,7 +117,7 @@ void QWindowsBackingStore::resize(const QSize &size, const QRegion &region)
if (QImage::toPixelFormat(format).alphaUsage() == QPixelFormat::UsesAlpha)
m_alphaNeedsFill = true;
else // upgrade but here we know app painting does not rely on alpha hence no need to fill
- format = qt_maybeAlphaVersionWithSameDepth(format);
+ format = qt_maybeDataCompatibleAlphaVersion(format);
QWindowsNativeImage *oldwni = m_image.data();
auto *newwni = new QWindowsNativeImage(size.width(), size.height(), format);
diff --git a/src/plugins/platforms/windows/qwindowscombase.h b/src/plugins/platforms/windows/qwindowscombase.h
deleted file mode 100644
index 04d4dc51cf..0000000000
--- a/src/plugins/platforms/windows/qwindowscombase.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QWINDOWSCOMBASE_H
-#define QWINDOWSCOMBASE_H
-
-#include <QtCore/qglobal.h>
-
-#include <unknwn.h>
-
-QT_BEGIN_NAMESPACE
-
-// The __uuidof operator of MinGW does not work for all interfaces (for example,
-// IAccessible2). Specializations of this function can be provides to work
-// around this.
-template <class DesiredInterface>
-static IID qUuidOf() { return __uuidof(DesiredInterface); }
-
-// Helper for implementing IUnknown::QueryInterface.
-template <class DesiredInterface, class Derived>
-bool qWindowsComQueryInterface(Derived *d, REFIID id, LPVOID *iface)
-{
- if (id == qUuidOf<DesiredInterface>()) {
- *iface = static_cast<DesiredInterface *>(d);
- d->AddRef();
- return true;
- }
- return false;
-}
-
-// Helper for implementing IUnknown::QueryInterface for IUnknown
-// in the case of multiple inheritance via the first inherited class.
-template <class FirstInheritedInterface, class Derived>
-bool qWindowsComQueryUnknownInterfaceMulti(Derived *d, REFIID id, LPVOID *iface)
-{
- if (id == __uuidof(IUnknown)) {
- *iface = static_cast<FirstInheritedInterface *>(d);
- d->AddRef();
- return true;
- }
- return false;
-}
-
-// Helper base class to provide IUnknown methods for COM classes (single inheritance)
-template <class ComInterface> class QWindowsComBase : public ComInterface
-{
- Q_DISABLE_COPY_MOVE(QWindowsComBase)
-public:
- explicit QWindowsComBase(ULONG initialRefCount = 1) : m_ref(initialRefCount) {}
- virtual ~QWindowsComBase() = default;
-
- HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface) override
- {
- *iface = nullptr;
- return qWindowsComQueryInterface<IUnknown>(this, id, iface) || qWindowsComQueryInterface<ComInterface>(this, id, iface)
- ? S_OK : E_NOINTERFACE;
- }
-
- ULONG STDMETHODCALLTYPE AddRef() override { return ++m_ref; }
-
- ULONG STDMETHODCALLTYPE Release() override
- {
- if (!--m_ref) {
- delete this;
- return 0;
- }
- return m_ref;
- }
-
-private:
- ULONG m_ref;
-};
-
-// Clang does not consider __declspec(nothrow) as nothrow
-QT_WARNING_DISABLE_CLANG("-Wmicrosoft-exception-spec")
-QT_WARNING_DISABLE_CLANG("-Wmissing-exception-spec")
-
-QT_END_NAMESPACE
-
-#endif // QWINDOWSCOMBASE_H
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index 5475e9707b..de65a2171d 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -45,10 +45,13 @@
#include <QtCore/qscopedpointer.h>
#include <QtCore/quuid.h>
#include <QtCore/private/qwinregistry_p.h>
-#include <QtCore/private/qfactorycacheregistration_p.h>
+#if QT_CONFIG(cpp_winrt)
+# include <QtCore/private/qfactorycacheregistration_p.h>
+#endif
#include <QtCore/private/qsystemerror_p.h>
#include <QtGui/private/qwindowsguieventdispatcher_p.h>
+#include <QtGui/private/qwindowsthemecache_p.h>
#include <stdlib.h>
#include <stdio.h>
@@ -151,11 +154,9 @@ struct QWindowsContextPrivate {
bool m_asyncExpose = false;
HPOWERNOTIFY m_powerNotification = nullptr;
HWND m_powerDummyWindow = nullptr;
- static bool m_darkMode;
static bool m_v2DpiAware;
};
-bool QWindowsContextPrivate::m_darkMode = false;
bool QWindowsContextPrivate::m_v2DpiAware = false;
QWindowsContextPrivate::QWindowsContextPrivate()
@@ -169,7 +170,6 @@ QWindowsContextPrivate::QWindowsContextPrivate()
m_systemInfo |= QWindowsContext::SI_RTL_Extensions;
m_keyMapper.setUseRTLExtensions(true);
}
- m_darkMode = QWindowsTheme::queryDarkMode();
if (FAILED(m_oleInitializeResult)) {
qWarning() << "QWindowsContext: OleInitialize() failed: "
<< QSystemError::windowsComString(m_oleInitializeResult);
@@ -461,11 +461,6 @@ bool QWindowsContext::setProcessDpiAwareness(QtWindows::DpiAwareness dpiAwarenes
return true;
}
-bool QWindowsContext::isDarkMode()
-{
- return QWindowsContextPrivate::m_darkMode;
-}
-
QWindowsContext *QWindowsContext::instance()
{
return m_instance;
@@ -481,9 +476,9 @@ bool QWindowsContext::useRTLExtensions() const
return d->m_keyMapper.useRTLExtensions();
}
-QList<int> QWindowsContext::possibleKeys(const QKeyEvent *e) const
+QPlatformKeyMapper *QWindowsContext::keyMapper() const
{
- return d->m_keyMapper.possibleKeys(e);
+ return &d->m_keyMapper;
}
QWindowsContext::HandleBaseWindowHash &QWindowsContext::windows()
@@ -535,6 +530,8 @@ QString QWindowsContext::classNamePrefix()
# define xstr(s) str(s)
# define str(s) #s
str << xstr(QT_NAMESPACE);
+# undef str
+# undef xstr
#endif
}
return result;
@@ -1001,9 +998,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
MSG msg;
msg.hwnd = hwnd; // re-create MSG structure
- msg.message = message; // time and pt fields ignored
+ msg.message = message;
msg.wParam = wParam;
msg.lParam = lParam;
+ msg.time = GetMessageTime();
msg.pt.x = msg.pt.y = 0;
if (et != QtWindows::CursorEvent && (et & (QtWindows::MouseEventFlag | QtWindows::NonClientEventFlag))) {
msg.pt.x = GET_X_LPARAM(lParam);
@@ -1087,21 +1085,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
// Only refresh the window theme if the user changes the personalize settings.
if ((wParam == 0) && (lParam != 0) // lParam sometimes may be NULL.
&& (wcscmp(reinterpret_cast<LPCWSTR>(lParam), L"ImmersiveColorSet") == 0)) {
- const bool darkMode = QWindowsTheme::queryDarkMode();
- const bool darkModeChanged = darkMode != QWindowsContextPrivate::m_darkMode;
- QWindowsContextPrivate::m_darkMode = darkMode;
- auto integration = QWindowsIntegration::instance();
- integration->updateApplicationBadge();
- if (integration->darkModeHandling().testFlag(QWindowsApplication::DarkModeStyle)) {
- QWindowsTheme::instance()->refresh();
- QWindowSystemInterface::handleThemeChange();
- }
- if (darkModeChanged) {
- if (integration->darkModeHandling().testFlag(QWindowsApplication::DarkModeWindowFrames)) {
- for (QWindowsWindow *w : d->m_windows)
- w->setDarkBorder(QWindowsContextPrivate::m_darkMode);
- }
- }
+ QWindowsTheme::handleSettingsChanged();
}
return d->m_screenManager.handleScreenChanges();
}
@@ -1118,7 +1102,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
d->m_creationContext->applyToMinMaxInfo(reinterpret_cast<MINMAXINFO *>(lParam));
return true;
case QtWindows::ResizeEvent:
- d->m_creationContext->obtainedSize = QSize(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
+ d->m_creationContext->obtainedSize = QSize(LOWORD(lParam), HIWORD(lParam));
return true;
case QtWindows::MoveEvent:
d->m_creationContext->obtainedPos = QPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
@@ -1161,7 +1145,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
if (wParam == DBT_DEVNODES_CHANGED)
initTouch();
break;
- case QtWindows::KeyboardLayoutChangeEvent:
+ case QtWindows::InputLanguageChangeEvent:
if (QWindowsInputContext *wic = windowsInputContext())
wic->handleInputLanguageChanged(wParam, lParam);
Q_FALLTHROUGH();
@@ -1205,21 +1189,29 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::ExposeEvent:
return platformWindow->handleWmPaint(hwnd, message, wParam, lParam, result);
case QtWindows::NonClientMouseEvent:
- if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled())
+ if (!platformWindow->frameStrutEventsEnabled())
+ break;
+ if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
else
return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
case QtWindows::NonClientPointerEvent:
- if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled())
+ if (!platformWindow->frameStrutEventsEnabled())
+ break;
+ if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result);
break;
case QtWindows::EnterSizeMoveEvent:
platformWindow->setFlag(QWindowsWindow::ResizeMoveActive);
+ if (!IsZoomed(hwnd))
+ platformWindow->updateRestoreGeometry();
return true;
case QtWindows::ExitSizeMoveEvent:
platformWindow->clearFlag(QWindowsWindow::ResizeMoveActive);
platformWindow->checkForScreenChanged();
handleExitSizeMove(platformWindow->window());
+ if (!IsZoomed(hwnd))
+ platformWindow->updateRestoreGeometry();
return true;
case QtWindows::ScrollEvent:
if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
@@ -1265,6 +1257,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
QWindowSystemInterface::handleCloseEvent(platformWindow->window());
return true;
case QtWindows::ThemeChanged: {
+ QWindowsThemeCache::clearThemeCache(platformWindow->handle());
// Switch from Aero to Classic changes margins.
if (QWindowsTheme *theme = QWindowsTheme::instance())
theme->windowsThemeChanged(platformWindow->window());
@@ -1403,7 +1396,7 @@ void QWindowsContext::handleFocusEvent(QtWindows::WindowsEventType et,
}
if (nextActiveWindow != d->m_lastActiveWindow) {
d->m_lastActiveWindow = nextActiveWindow;
- QWindowSystemInterface::handleWindowActivated(nextActiveWindow, Qt::ActiveWindowFocusReason);
+ QWindowSystemInterface::handleFocusWindowChanged(nextActiveWindow, Qt::ActiveWindowFocusReason);
}
}
@@ -1433,7 +1426,7 @@ bool QWindowsContext::handleContextMenuEvent(QWindow *window, const MSG &msg)
}
QWindowSystemInterface::handleContextMenuEvent(window, mouseTriggered, pos, globalPos,
- QWindowsKeyMapper::queryKeyboardModifiers());
+ keyMapper()->queryKeyboardModifiers());
return true;
}
#endif
@@ -1454,7 +1447,7 @@ void QWindowsContext::handleExitSizeMove(QWindow *window)
const Qt::MouseButtons appButtons = QGuiApplication::mouseButtons();
if (currentButtons == appButtons)
return;
- const Qt::KeyboardModifiers keyboardModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
+ const Qt::KeyboardModifiers keyboardModifiers = keyMapper()->queryKeyboardModifiers();
const QPoint globalPos = QWindowsCursor::mousePosition();
const QPlatformWindow *platWin = window->handle();
const QPoint localPos = platWin->mapFromGlobal(globalPos);
@@ -1463,8 +1456,7 @@ void QWindowsContext::handleExitSizeMove(QWindow *window)
for (Qt::MouseButton button : {Qt::LeftButton, Qt::RightButton, Qt::MiddleButton}) {
if (appButtons.testFlag(button) && !currentButtons.testFlag(button)) {
QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos,
- currentButtons, button, type,
- keyboardModifiers);
+ currentButtons, button, type, keyboardModifiers);
}
}
if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h
index 1a3b47be5e..0539a22afc 100644
--- a/src/plugins/platforms/windows/qwindowscontext.h
+++ b/src/plugins/platforms/windows/qwindowscontext.h
@@ -33,6 +33,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen)
class QWindow;
class QPlatformScreen;
class QPlatformWindow;
+class QPlatformKeyMapper;
class QWindowsMenuBar;
class QWindowsScreenManager;
class QWindowsTabletSupport;
@@ -43,7 +44,6 @@ struct QWindowsContextPrivate;
class QPoint;
class QKeyEvent;
class QPointingDevice;
-
class QWindowsContext
{
Q_DISABLE_COPY_MOVE(QWindowsContext)
@@ -120,15 +120,13 @@ public:
static QtWindows::DpiAwareness processDpiAwareness();
static QtWindows::DpiAwareness windowDpiAwareness(HWND hwnd);
- static bool isDarkMode();
-
void setDetectAltGrModifier(bool a);
// Returns a combination of SystemInfoFlags
unsigned systemInfo() const;
bool useRTLExtensions() const;
- QList<int> possibleKeys(const QKeyEvent *e) const;
+ QPlatformKeyMapper *keyMapper() const;
HandleBaseWindowHash &windows();
diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp
index 77903f6b6f..b416886120 100644
--- a/src/plugins/platforms/windows/qwindowscursor.cpp
+++ b/src/plugins/platforms/windows/qwindowscursor.cpp
@@ -30,6 +30,8 @@ static bool initResources()
QT_BEGIN_NAMESPACE
+using namespace Qt::Literals::StringLiterals;
+
/*!
\class QWindowsCursorCacheKey
\brief Cache key for storing values in a QHash with a QCursor as key.
@@ -103,14 +105,16 @@ static HCURSOR createBitmapCursor(const QImage &bbits, const QImage &mbits,
hotSpot.setX(width / 2);
if (hotSpot.y() < 0)
hotSpot.setY(height / 2);
- const int n = qMax(1, width / 8);
- QScopedArrayPointer<uchar> xBits(new uchar[height * n]);
- QScopedArrayPointer<uchar> xMask(new uchar[height * n]);
+ // a ddb is word aligned, QImage depends on bow it was created
+ const auto bplDdb = qMax(1, ((width + 15) >> 4) << 1);
+ const auto bplImg = int(bbits.bytesPerLine());
+ QScopedArrayPointer<uchar> xBits(new uchar[height * bplDdb]);
+ QScopedArrayPointer<uchar> xMask(new uchar[height * bplDdb]);
int x = 0;
for (int i = 0; i < height; ++i) {
const uchar *bits = bbits.constScanLine(i);
const uchar *mask = mbits.constScanLine(i);
- for (int j = 0; j < n; ++j) {
+ for (int j = 0; j < bplImg && j < bplDdb; ++j) {
uchar b = bits[j];
uchar m = mask[j];
if (invb)
@@ -121,6 +125,11 @@ static HCURSOR createBitmapCursor(const QImage &bbits, const QImage &mbits,
xMask[x] = b ^ m;
++x;
}
+ for (int i = bplImg; i < bplDdb; ++i) {
+ xBits[x] = 0;
+ xMask[x] = 0;
+ ++x;
+ }
}
return CreateCursor(GetModuleHandle(nullptr), hotSpot.x(), hotSpot.y(), width, height,
xBits.data(), xMask.data());
@@ -138,8 +147,8 @@ static HCURSOR createBitmapCursor(const QCursor &cursor, qreal scaleFactor = 1)
bbits = bbits.scaled(scaledSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
mbits = mbits.scaled(scaledSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
- bbits = bbits.convertToFormat(QImage::Format_Mono);
- mbits = mbits.convertToFormat(QImage::Format_Mono);
+ bbits = std::move(bbits).convertToFormat(QImage::Format_Mono);
+ mbits = std::move(mbits).convertToFormat(QImage::Format_Mono);
const bool invb = bbits.colorCount() > 1 && qGray(bbits.color(0)) < qGray(bbits.color(1));
const bool invm = mbits.colorCount() > 1 && qGray(mbits.color(0)) < qGray(mbits.color(1));
return createBitmapCursor(bbits, mbits, cursor.hotSpot(), invb, invm);
@@ -436,8 +445,8 @@ QWindowsCursor::PixmapCursor QWindowsCursor::customCursor(Qt::CursorShape cursor
if (!bestFit)
return PixmapCursor();
- const QPixmap rawImage(QStringLiteral(":/qt-project.org/windows/cursors/images/") +
- QString::fromLatin1(bestFit->fileName));
+ const QPixmap rawImage(":/qt-project.org/windows/cursors/images/"_L1 +
+ QLatin1StringView(bestFit->fileName));
return PixmapCursor(rawImage, QPoint(bestFit->hotSpotX, bestFit->hotSpotY));
}
#endif // !QT_NO_IMAGEFORMAT_PNG
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
index 51bd9f0c38..0ce0b0e2a7 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
@@ -4,7 +4,6 @@
#define QT_NO_URL_CAST_FROM_STRING 1
#include <QtCore/qt_windows.h>
-#include "qwindowscombase.h"
#include "qwindowsdialoghelpers.h"
#include "qwindowscontext.h"
@@ -33,6 +32,7 @@
#include <QtCore/qtemporaryfile.h>
#include <QtCore/private/qfunctions_win_p.h>
#include <QtCore/private/qsystemerror_p.h>
+#include <QtCore/private/qcomobject_p.h>
#include <algorithm>
#include <vector>
@@ -43,26 +43,6 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-#ifndef QT_NO_DEBUG_STREAM
-/* Output UID (IID, CLSID) as C++ constants.
- * The constants are contained in the Windows SDK libs, but not for MinGW. */
-static inline QString guidToString(const GUID &g)
-{
- QString rc;
- QTextStream str(&rc);
- str.setIntegerBase(16);
- str.setNumberFlags(str.numberFlags() | QTextStream::ShowBase);
- str << '{' << g.Data1 << ", " << g.Data2 << ", " << g.Data3;
- str.setFieldWidth(2);
- str.setFieldAlignment(QTextStream::AlignRight);
- str.setPadChar(u'0');
- str << ",{" << g.Data4[0] << ", " << g.Data4[1] << ", " << g.Data4[2] << ", " << g.Data4[3]
- << ", " << g.Data4[4] << ", " << g.Data4[5] << ", " << g.Data4[6] << ", " << g.Data4[7]
- << "}};";
- return rc;
-}
-#endif // !QT_NO_DEBUG_STREAM
-
// Return an allocated wchar_t array from a QString, reserve more memory if desired.
static wchar_t *qStringToWCharArray(const QString &s, size_t reserveSize = 0)
{
@@ -443,7 +423,7 @@ inline void QWindowsFileDialogSharedData::fromOptions(const QSharedPointer<QFile
class QWindowsNativeFileDialogBase;
-class QWindowsNativeFileDialogEventHandler : public QWindowsComBase<IFileDialogEvents>
+class QWindowsNativeFileDialogEventHandler : public QComObject<IFileDialogEvents>
{
Q_DISABLE_COPY_MOVE(QWindowsNativeFileDialogEventHandler)
public:
@@ -586,7 +566,7 @@ QUrl QWindowsShellItem::url() const
if (urlV.isValid())
return urlV;
// Last resort: encode the absolute desktop parsing id as data URL
- const QString data = QStringLiteral("data:text/plain;base64,")
+ const QString data = "data:text/plain;base64,"_L1
+ QLatin1StringView(desktopAbsoluteParsing().toLatin1().toBase64());
return QUrl(data);
}
@@ -1379,7 +1359,7 @@ QString tempFilePattern(QString name)
int lastDot = name.lastIndexOf(u'.');
if (lastDot < 0)
lastDot = name.size();
- name.insert(lastDot, QStringLiteral("_XXXXXX"));
+ name.insert(lastDot, "_XXXXXX"_L1);
for (int i = lastDot - 1; i >= 0; --i) {
if (!validFileNameCharacter(name.at(i)))
@@ -1571,7 +1551,7 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog()
if (!info.isDir())
result->selectFile(info.fileName());
} else {
- result->selectFile(url.path()); // TODO url.fileName() once it exists
+ result->selectFile(url.fileName());
}
}
// No need to select initialNameFilter if mode is Dir
@@ -1605,7 +1585,7 @@ void QWindowsFileDialogHelper::selectFile(const QUrl &fileName)
qCDebug(lcQpaDialogs) << __FUNCTION__ << fileName.toString();
if (hasNativeDialog()) // Might be invoked from the QFileDialog constructor.
- nativeFileDialog()->selectFile(fileName.toLocalFile()); // ## should use QUrl::fileName() once it exists
+ nativeFileDialog()->selectFile(fileName.fileName());
}
QList<QUrl> QWindowsFileDialogHelper::selectedFiles() const
@@ -1713,14 +1693,6 @@ static int QT_WIN_CALLBACK xpFileDialogGetExistingDirCallbackProc(HWND hwnd, UIN
return dialog->existingDirCallback(hwnd, uMsg, lParam);
}
-/* The correct declaration of the SHGetPathFromIDList symbol is
- * being used in mingw-w64 as of r6215, which is a v3 snapshot. */
-#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3)
-typedef ITEMIDLIST *qt_LpItemIdList;
-#else
-using qt_LpItemIdList = PIDLIST_ABSOLUTE;
-#endif
-
int QWindowsXpNativeFileDialog::existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam)
{
switch (uMsg) {
@@ -1734,7 +1706,7 @@ int QWindowsXpNativeFileDialog::existingDirCallback(HWND hwnd, UINT uMsg, LPARAM
break;
case BFFM_SELCHANGED: {
wchar_t path[MAX_PATH];
- const bool ok = SHGetPathFromIDList(reinterpret_cast<qt_LpItemIdList>(lParam), path)
+ const bool ok = SHGetPathFromIDList(reinterpret_cast<PIDLIST_ABSOLUTE>(lParam), path)
&& path[0];
SendMessage(hwnd, BFFM_ENABLEOK, ok ? 1 : 0, 1);
}
@@ -1756,7 +1728,7 @@ QList<QUrl> QWindowsXpNativeFileDialog::execExistingDir(HWND owner)
bi.lpfn = xpFileDialogGetExistingDirCallbackProc;
bi.lParam = LPARAM(this);
QList<QUrl> selectedFiles;
- if (qt_LpItemIdList pItemIDList = SHBrowseForFolder(&bi)) {
+ if (const auto pItemIDList = SHBrowseForFolder(&bi)) {
wchar_t path[MAX_PATH];
path[0] = 0;
if (SHGetPathFromIDList(pItemIDList, path) && path[0])
diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp
index 48e0bba41f..c6f55c3509 100644
--- a/src/plugins/platforms/windows/qwindowsdrag.cpp
+++ b/src/plugins/platforms/windows/qwindowsdrag.cpp
@@ -28,6 +28,8 @@
#include <QtCore/qdebug.h>
#include <QtCore/qbuffer.h>
#include <QtCore/qpoint.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/private/qcomobject_p.h>
#include <shlobj.h>
@@ -167,7 +169,7 @@ static Qt::MouseButtons lastButtons = Qt::NoButton;
\internal
*/
-class QWindowsOleDropSource : public QWindowsComBase<IDropSource>
+class QWindowsOleDropSource : public QComObject<IDropSource>
{
public:
enum Mode {
@@ -348,7 +350,7 @@ QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
} else {
if (buttons && !m_currentButtons) {
m_currentButtons = buttons;
- } else if (!(m_currentButtons & buttons)) { // Button changed: Complete Drop operation.
+ } else if (m_currentButtons != buttons) { // Button changed: Complete Drop operation.
result = DRAGDROP_S_DROP;
}
}
@@ -526,7 +528,8 @@ QWindowsOleDropTarget::DragLeave()
qCDebug(lcQpaMime) << __FUNCTION__ << ' ' << m_window;
- lastModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
+ const auto *keyMapper = QWindowsContext::instance()->keyMapper();
+ lastModifiers = keyMapper->queryKeyboardModifiers();
lastButtons = QWindowsMouseHandler::queryMouseButtons();
QWindowSystemInterface::handleDrag(m_window, nullptr, QPoint(), Qt::IgnoreAction,
@@ -611,7 +614,6 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState,
*/
bool QWindowsDrag::m_canceled = false;
-bool QWindowsDrag::m_dragging = false;
QWindowsDrag::QWindowsDrag() = default;
@@ -649,7 +651,8 @@ IDropTargetHelper* QWindowsDrag::dropHelper() {
static HRESULT startDoDragDrop(LPDATAOBJECT pDataObj, LPDROPSOURCE pDropSource, DWORD dwOKEffects, LPDWORD pdwEffect)
{
QWindow *underMouse = QWindowsContext::instance()->windowUnderMouse();
- const HWND hwnd = underMouse ? reinterpret_cast<HWND>(underMouse->winId()) : ::GetFocus();
+ const bool hasMouseCapture = underMouse && static_cast<QWindowsWindow *>(underMouse->handle())->hasMouseCapture();
+ const HWND hwnd = hasMouseCapture ? reinterpret_cast<HWND>(underMouse->winId()) : ::GetFocus();
bool starting = false;
for (;;) {
@@ -738,10 +741,7 @@ Qt::DropAction QWindowsDrag::drag(QDrag *drag)
const DWORD allowedEffects = translateToWinDragEffects(possibleActions);
qCDebug(lcQpaMime) << '>' << __FUNCTION__ << "possible Actions=0x"
<< Qt::hex << int(possibleActions) << "effects=0x" << allowedEffects << Qt::dec;
- // Indicate message handlers we are in DoDragDrop() event loop.
- QWindowsDrag::m_dragging = true;
const HRESULT r = startDoDragDrop(dropDataObject, windowDropSource, allowedEffects, &resultEffect);
- QWindowsDrag::m_dragging = false;
const DWORD reportedPerformedEffect = dropDataObject->reportedPerformedEffect();
if (r == DRAGDROP_S_DROP) {
if (reportedPerformedEffect == DROPEFFECT_MOVE && resultEffect != DROPEFFECT_MOVE) {
diff --git a/src/plugins/platforms/windows/qwindowsdrag.h b/src/plugins/platforms/windows/qwindowsdrag.h
index cf5d43fb84..a2d0e54044 100644
--- a/src/plugins/platforms/windows/qwindowsdrag.h
+++ b/src/plugins/platforms/windows/qwindowsdrag.h
@@ -4,12 +4,12 @@
#ifndef QWINDOWSDRAG_H
#define QWINDOWSDRAG_H
-#include "qwindowscombase.h"
#include "qwindowsinternalmimedata.h"
#include <qpa/qplatformdrag.h>
#include <QtGui/qpixmap.h>
#include <QtGui/qdrag.h>
+#include <QtCore/private/qcomobject_p.h>
struct IDropTargetHelper;
@@ -23,7 +23,7 @@ public:
IDataObject *retrieveDataObject() const override;
};
-class QWindowsOleDropTarget : public QWindowsComBase<IDropTarget>
+class QWindowsOleDropTarget : public QComObject<IDropTarget>
{
public:
explicit QWindowsOleDropTarget(QWindow *w);
@@ -58,7 +58,6 @@ public:
static QWindowsDrag *instance();
void cancelDrag() override { QWindowsDrag::m_canceled = true; }
static bool isCanceled() { return QWindowsDrag::m_canceled; }
- static bool isDragging() { return QWindowsDrag::m_dragging; }
IDataObject *dropDataObject() const { return m_dropDataObject; }
void setDropDataObject(IDataObject *dataObject) { m_dropDataObject = dataObject; }
@@ -69,7 +68,6 @@ public:
private:
static bool m_canceled;
- static bool m_dragging;
QWindowsDropMimeData m_dropData;
IDataObject *m_dropDataObject = nullptr;
diff --git a/src/plugins/platforms/windows/qwindowsdropdataobject.cpp b/src/plugins/platforms/windows/qwindowsdropdataobject.cpp
index fbb2b45e21..629291640f 100644
--- a/src/plugins/platforms/windows/qwindowsdropdataobject.cpp
+++ b/src/plugins/platforms/windows/qwindowsdropdataobject.cpp
@@ -9,6 +9,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::Literals::StringLiterals;
+
/*!
\class QWindowsDropDataObject
\brief QWindowsOleDataObject subclass specialized for handling Drag&Drop.
@@ -56,8 +58,8 @@ bool QWindowsDropDataObject::shouldIgnore(LPFORMATETC pformatetc) const
QString formatName = QWindowsMimeRegistry::clipboardFormatName(pformatetc->cfFormat);
if (pformatetc->cfFormat == CF_UNICODETEXT
|| pformatetc->cfFormat == CF_TEXT
- || formatName == QStringLiteral("UniformResourceLocator")
- || formatName == QStringLiteral("UniformResourceLocatorW")) {
+ || formatName == "UniformResourceLocator"_L1
+ || formatName == "UniformResourceLocatorW"_L1) {
const auto urls = dropData->urls();
return std::all_of(urls.cbegin(), urls.cend(), [] (const QUrl &u) { return u.isLocalFile(); });
}
diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp
index cfd73519fa..5ca52c2c19 100644
--- a/src/plugins/platforms/windows/qwindowsglcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp
@@ -1262,7 +1262,6 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface)
// Do we already have a DC entry for that window?
auto *window = static_cast<QWindowsWindow *>(surface);
- window->aboutToMakeCurrent();
const HWND hwnd = window->handle();
if (const QOpenGLContextData *contextData = findByHWND(m_windowContexts, hwnd)) {
// Repeated calls to wglMakeCurrent when vsync is enabled in the driver will
diff --git a/src/plugins/platforms/windows/qwindowsiconengine.cpp b/src/plugins/platforms/windows/qwindowsiconengine.cpp
new file mode 100644
index 0000000000..5e5ca22ec1
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsiconengine.cpp
@@ -0,0 +1,394 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwindowsiconengine.h"
+
+#include <QtCore/qoperatingsystemversion.h>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qpalette.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+QString QWindowsIconEngine::glyphs() const
+{
+ if (!QFontInfo(m_iconFont).exactMatch())
+ return {};
+
+ static constexpr std::pair<QLatin1StringView, QStringView> glyphMap[] = {
+ {"address-book-new"_L1, u"\ue780"},
+ {"application-exit"_L1, u"\ue8bb"},
+ {"appointment-new"_L1, u"\ue878"},
+ {"call-start"_L1, u"\uf715"},
+ {"call-stop"_L1, u"\uf405"},
+ {"contact-new"_L1, u"\ue8fa"},
+ {"document-new"_L1, u"\ue8a5"},
+ {"document-open"_L1, u"\ue8e5"},
+ {"document-open-recent"_L1, u"\ue823"},
+ {"document-page-setup"_L1, u"\ue7c3"},
+ {"document-print"_L1, u"\ue749"},
+ {"document-print-preview"_L1, u"\ue956"},
+ {"document-properties"_L1, u"\ue90f"},
+ {"document-revert"_L1, u"\ue7a7"}, // ?
+ {"document-save"_L1, u"\ue74e"}, // or e78c?
+ {"document-save-as"_L1, u"\ue792"},
+ {"document-send"_L1, u"\ue724"},
+ {"edit-clear"_L1, u"\ue894"},
+ {"edit-copy"_L1, u"\ue8c8"},
+ {"edit-cut"_L1, u"\ue8c6"},
+ {"edit-delete"_L1, u"\ue74d"},
+ {"edit-find"_L1, u"\ue721"},
+ //{"edit-find-replace"_L1, u"\u"},
+ {"edit-paste"_L1, u"\ue77f"},
+ {"edit-redo"_L1, u"\ue7a6"},
+ {"edit-select-all"_L1, u"\ue8b3"},
+ {"edit-undo"_L1, u"\ue7a7"},
+ {"folder-new"_L1, u"\ue8f4"},
+ //{"format-indent-less"_L1, u"\u"},
+ //{"format-indent-more"_L1, u"\u"},
+ {"format-justify-center"_L1, u"\ue8e3"},
+ //{"format-justify-fill"_L1, u"\ue235"},
+ {"format-justify-left"_L1, u"\ue8e4"},
+ {"format-justify-right"_L1, u"\ue8e2"},
+ //{"format-text-direction-ltr"_L1, u"\ue247"},
+ //{"format-text-direction-rtl"_L1, u"\ue248"},
+ {"format-text-bold"_L1, u"\ue8dd"},
+ {"format-text-italic"_L1, u"\ue8db"},
+ {"format-text-underline"_L1, u"\ue8dc"},
+ {"format-text-strikethrough"_L1, u"\uede0"},
+ //{"go-bottom"_L1,u"\ue258"},
+ {"go-down"_L1,u"\ue74b"},
+ //{"go-first"_L1, u"\ue5dc"},
+ {"go-home"_L1, u"\ue80f"},
+ // {"go-jump"_L1, u"\uf719"},
+ //{"go-last"_L1, u"\ue5dd"},
+ {"go-next"_L1, u"\ue893"},
+ {"go-previous"_L1, u"\ue892"},
+ //{"go-top"_L1, u"\ue25a"},
+ {"go-up"_L1, u"\ue74a"},
+ {"help-about"_L1, u"\ue946"},
+ //{"help-contents"_L1, u"\ue8de"},
+ {"help-faq"_L1, u"\ue897"},
+ {"insert-image"_L1, u"\ue946"},
+ {"insert-link"_L1, u"\ue71b"},
+ //{"insert-object"_L1, u"\u"},
+ //{"insert-text"_L1, u"\uf827"},
+ {"list-add"_L1, u"\ue710"},
+ {"list-remove"_L1, u"\ue738"},
+ {"mail-forward"_L1, u"\ue89c"},
+ //{"mail-mark-important"_L1, u"\ue937"},
+ //{"mail-mark-junk"_L1, u"\u"},
+ //{"mail-mark-notjunk"_L1, u"\u"},
+ {"mail-mark-read"_L1, u"\ue8c3"},
+ //{"mail-mark-unread"_L1, u"\ue9bc"},
+ {"mail-message-new"_L1, u"\ue70f"},
+ {"mail-reply-all"_L1, u"\ue8c2"},
+ {"mail-reply-sender"_L1, u"\ue8ca"},
+ {"mail-send"_L1, u"\ue724"},
+ //{"mail-send-receive"_L1, u"\u"},
+ {"media-eject"_L1, u"\uf847"},
+ {"media-playback-pause"_L1, u"\ue769"},
+ {"media-playback-start"_L1, u"\ue768"},
+ {"media-playback-stop"_L1, u"\ue71a"},
+ {"media-record"_L1, u"\ue7c8"},
+ {"media-seek-backward"_L1, u"\ueb9e"},
+ {"media-seek-forward"_L1, u"\ueb9d"},
+ {"media-skip-backward"_L1, u"\ue892"},
+ {"media-skip-forward"_L1, u"\ue893"},
+ //{"object-flip-horizontal"_L1, u"\u"},
+ //{"object-flip-vertical"_L1, u"\u"},
+ {"object-rotate-left"_L1, u"\ue80c"},
+ {"object-rotate-right"_L1, u"\ue80d"},
+ //{"process-stop"_L1, u"\ue5c9"},
+ {"system-lock-screen"_L1, u"\uee3f"},
+ {"system-log-out"_L1, u"\uf3b1"},
+ //{"system-run"_L1, u"\u"},
+ {"system-search"_L1, u"\ue721"},
+ {"system-reboot"_L1, u"\ue777"}, // unsure?
+ {"system-shutdown"_L1, u"\ue7e8"},
+ {"tools-check-spelling"_L1, u"\uf87b"},
+ {"view-fullscreen"_L1, u"\ue740"},
+ {"view-refresh"_L1, u"\ue72c"},
+ {"view-restore"_L1, u"\ue777"},
+ //{"view-sort-ascending"_L1, u"\ue25a"},
+ //{"view-sort-descending"_L1, u"\ue258"},
+ {"window-close"_L1, u"\ue8bb"},
+ {"window-new"_L1, u"\ue78b"},
+ {"zoom-fit-best"_L1, u"\ue9a6"},
+ {"zoom-in"_L1, u"\ue8a3"},
+ //{"zoom-original"_L1, u"\u"},
+ {"zoom-out"_L1, u"\ue71f"},
+
+ {"process-working"_L1, u"\ue9f3"},
+
+ {"accessories-calculator"_L1, u"\ue8ef"},
+ {"accessories-character-map"_L1, u"\uf2b7"},
+ {"accessories-dictionary"_L1, u"\ue82d"},
+ //{"accessories-text-editor"_L1, u"\ue262"},
+ {"help-browser"_L1, u"\ue897"},
+ {"multimedia-volume-control"_L1, u"\ue767"},
+ {"preferences-desktop-accessibility"_L1, u"\ue776"},
+ {"preferences-desktop-font"_L1, u"\ue8d2"},
+ {"preferences-desktop-keyboard"_L1, u"\ue765"},
+ {"preferences-desktop-locale"_L1, u"\uf2b7"},
+ //{"preferences-desktop-multimedia"_L1, u"\uea75"},
+ {"preferences-desktop-screensaver"_L1, u"\uf182"},
+ //{"preferences-desktop-theme"_L1, u"\uf560"},
+ //{"preferences-desktop-wallpaper"_L1, u"\ue1bc"},
+ {"system-file-manager"_L1, u"\uec50"},
+ //{"system-software-install"_L1, u"\ueb71"},
+ {"system-software-update"_L1, u"\uecc5"},
+ {"utilities-system-monitor"_L1, u"\ue7f4"},
+ //{"utilities-terminal"_L1, u"\ueb8e"},
+
+ //{"applications-accessories"_L1, u"\u"},
+ {"applications-development"_L1, u"\uec7a"},
+ //{"applications-engineering"_L1, u"\uea3d"},
+ {"applications-games"_L1, u"\ue7fc"},
+ //{"applications-graphics"_L1, u"\u"},
+ {"applications-internet"_L1, u"\ue774"},
+ {"applications-multimedia"_L1, u"\uea69"},
+ //{"applications-office"_L1, u"\u"},
+ //{"applications-other"_L1, u"\u"},
+ //{"applications-science"_L1, u"\uea4b"},
+ {"applications-system"_L1, u"\ue770"},
+ //{"applications-utilities"_L1, u"\u"},
+ //{"preferences-desktop"_L1, u"\ueb97"},
+ //{"preferences-desktop-peripherals"_L1, u"\u"},
+ //{"preferences-desktop-personal"_L1, u"\uf835"},
+ //{"preferences-other"_L1, u"\u"},
+ //{"preferences-system"_L1, u"\ue8b8"},
+ //{"preferences-system-network"_L1, u"\ue894"},
+ {"system-help"_L1, u"\ue946"},
+
+ {"audio-card"_L1, u"\ue8d6"},
+ {"audio-input-microphone"_L1, u"\ue720"},
+ {"battery"_L1, u"\ue83f"},
+ {"camera-photo"_L1, u"\ue722"},
+ {"camera-video"_L1, u"\ue714"},
+ {"camera-web"_L1, u"\ue8b8"},
+ {"computer"_L1, u"\ue7f8"}, // or e7fb?
+ {"drive-harddisk"_L1, u"\ueda2"},
+ {"drive-optical"_L1, u"\ue958"},
+ //{"drive-removable-media"_L1, u"\u"},
+ //{"input-gaming"_L1, u"\u"},
+ {"input-keyboard"_L1, u"\ue92e"},
+ {"input-mouse"_L1, u"\ue962"},
+ {"input-tablet"_L1, u"\ue70a"},
+ {"media-flash"_L1, u"\ue88e"},
+ //{"media-floppy"_L1, u"\u"},
+ {"media-optical"_L1, u"\ue958"},
+ {"media-tape"_L1, u"\ue96a"},
+ //{"modem"_L1, u"\u"},
+ //{"multimedia-player"_L1, u"\u"},
+ {"network-wired"_L1, u"\ue968"},
+ {"network-wireless"_L1, u"\ue701"},
+ //{"pda"_L1, u"\u"},
+ {"phone"_L1, u"\ue717"},
+ {"printer"_L1, u"\ue749"},
+ {"scanner"_L1, u"\ue8fe"},
+ //{"video-display"_L1, u"\uf06a"},
+
+ {"emblem-default"_L1, u"\uf56d"},
+ {"emblem-documents"_L1, u"\ue8a5"},
+ {"emblem-downloads"_L1, u"\ue896"},
+ {"emblem-favorite"_L1, u"\ue734"},
+ {"emblem-important"_L1, u"\ue8c9"},
+ {"emblem-mail"_L1, u"\ue715"},
+ {"emblem-photos"_L1, u"\ue91b"},
+ //{"emblem-readonly"_L1, u"\u"},
+ {"emblem-shared"_L1, u"\ue902"},
+ {"emblem-symbolic-link"_L1, u"\ue71b"},
+ {"emblem-synchronized"_L1, u"\uedab"},
+ {"emblem-system"_L1, u"\ue770"},
+ //{"emblem-unreadable"_L1, u"\u"},
+
+ {"folder"_L1, u"\ue8b7"},
+ //{"folder-remote"_L1, u"\u"},
+ //{"network-server"_L1, u"\ue875"},
+ //{"network-workgroup"_L1, u"\ue1a0"},
+ {"start-here"_L1, u"\ue8fc"}, // unsure
+ {"user-bookmarks"_L1, u"\ue8a4"},
+ //{"user-desktop"_L1, u"\ue30a"},
+ {"user-home"_L1, u"\ue80f"},
+ {"user-trash"_L1, u"\ue74d"},
+
+ //{"appointment-missed"_L1, u"\ue615"},
+ //{"appointment-soon"_L1, u"\uf540"},
+ {"audio-volume-high"_L1, u"\ue995"},
+ {"audio-volume-low"_L1, u"\ue993"},
+ {"audio-volume-medium"_L1, u"\ue994"},
+ {"audio-volume-muted"_L1, u"\ue992"},
+ //{"battery-caution"_L1, u"\ue19c"},
+ {"battery-low"_L1, u"\ue851"}, // ?
+ {"dialog-error"_L1, u"\ue783"},
+ {"dialog-information"_L1, u"\ue946"},
+ //{"dialog-password"_L1, u"\uf042"},
+ {"dialog-question"_L1, u"\uf142"}, // unsure
+ {"dialog-warning"_L1, u"\ue7ba"},
+ //{"folder-drag-accept"_L1, @u"\ue9a3"},
+ {"folder-open"_L1, u"\ue838"},
+ //{"folder-visiting"_L1, u"\ue8a7"},
+ //{"image-loading"_L1, u"\ue41a"},
+ //{"image-missing"_L1, u"\ue3ad"},
+ {"mail-attachment"_L1, u"\ue723"},
+ //{"mail-unread"_L1, u"\uf18a"},
+ //{"mail-read"_L1, u"\uf18c"},
+ {"mail-replied"_L1, u"\ue8ca"},
+ //{"mail-signed"_L1, u"\u"},
+ //{"mail-signed-verified"_L1, u"\u"},
+ {"media-playlist-repeat"_L1, u"\ue8ee"},
+ {"media-playlist-shuffle"_L1, u"\ue8b1"},
+ //{"network-error"_L1, u"\uead9"},
+ //{"network-idle"_L1, u"\ue51f"},
+ {"network-offline"_L1, u"\uf384"},
+ //{"network-receive"_L1, u"\ue2c0"},
+ //{"network-transmit"_L1, u"\ue2c3"},
+ //{"network-transmit-receive"_L1, u"\uca18"},
+ //{"printer-error"_L1, u"\uf7a0"},
+ //{"printer-printing"_L1, u"\uf7a1"},
+ //{"security-high"_L1, u"\ue32a"},
+ //{"security-medium"_L1, u"\ue9e0"},
+ //{"security-low"_L1, u"\uf012"},
+ //{"software-update-available"_L1, u"\ue923"},
+ //{"software-update-urgent"_L1, u"\uf05a"},
+ {"sync-error"_L1, u"\uea6a"},
+ {"sync-synchronizing"_L1, u"\ue895"},
+ //{"task-due"_L1, u"\u"},
+ //{"task-past-due"_L1, u"\u"},
+ {"user-available"_L1, u"\ue8cf"},
+ //{"user-away"_L1, u"\ue510"},
+ //{"user-idle"_L1, u"\u"},
+ //{"user-offline"_L1, u"\uf7b3"},
+ //{"user-trash-full"_L1, u"\ue872"}, //delete
+ //{"user-trash-full"_L1, u"\ue92b"}, //delete_forever
+ {"weather-clear"_L1, u"\ue706"},
+ //{"weather-clear-night"_L1, u"\uf159"},
+ //{"weather-few-clouds"_L1, u"\uf172"},
+ //{"weather-few-clouds-night"_L1, u"\uf174"},
+ //{"weather-fog"_L1, u"\ue818"},
+ {"weather-overcast"_L1, u"\ue753"},
+ //{"weather-severe-alert"_L1, u"\ue002"}, //warning
+ //{"weather-showers"_L1, u"\uf176"},
+ //{"weather-showers-scattered"_L1, u"\u"},
+ //{"weather-snow"_L1, u"\ue80f"}, //snowing
+ //{"weather-storm"_L1, u"\uf070"},
+ };
+
+ const auto it = std::find_if(std::begin(glyphMap), std::end(glyphMap), [this](const auto &c){
+ return c.first == m_iconName;
+ });
+
+ return it != std::end(glyphMap) ? it->second.toString()
+ : (m_iconName.length() == 1 ? m_iconName : QString());
+}
+
+namespace {
+auto iconFontFamily()
+{
+ static const bool isWindows11 = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows11;
+ return isWindows11 ? u"Segoe Fluent Icons"_s
+ : u"Segoe MDL2 Assets"_s;
+}
+}
+
+QWindowsIconEngine::QWindowsIconEngine(const QString &iconName)
+ : m_iconName(iconName), m_iconFont(iconFontFamily())
+ , m_glyphs(glyphs())
+{
+}
+
+QWindowsIconEngine::~QWindowsIconEngine()
+{}
+
+QIconEngine *QWindowsIconEngine::clone() const
+{
+ return new QWindowsIconEngine(m_iconName);
+}
+
+QString QWindowsIconEngine::key() const
+{
+ return u"QWindowsIconEngine"_s;
+}
+
+QString QWindowsIconEngine::iconName()
+{
+ return m_iconName;
+}
+
+bool QWindowsIconEngine::isNull()
+{
+ if (m_glyphs.isEmpty())
+ return true;
+
+ const QChar c0 = m_glyphs.at(0);
+ const QFontMetrics fontMetrics(m_iconFont);
+ if (c0.category() == QChar::Other_Surrogate && m_glyphs.size() > 1)
+ return !fontMetrics.inFontUcs4(QChar::surrogateToUcs4(c0, m_glyphs.at(1)));
+ return !fontMetrics.inFont(c0);
+}
+
+QList<QSize> QWindowsIconEngine::availableSizes(QIcon::Mode, QIcon::State)
+{
+ return {{16, 16}, {24, 24}, {48, 48}, {128, 128}};
+}
+
+QSize QWindowsIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state)
+{
+ return QIconEngine::actualSize(size, mode, state);
+}
+
+QPixmap QWindowsIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
+{
+ return scaledPixmap(size, mode, state, 1.0);
+}
+
+QPixmap QWindowsIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
+{
+ const quint64 cacheKey = calculateCacheKey(mode, state);
+ if (cacheKey != m_cacheKey || m_pixmap.size() != size || m_pixmap.devicePixelRatio() != scale) {
+ m_pixmap = QPixmap(size * scale);
+ m_pixmap.fill(Qt::transparent);
+ m_pixmap.setDevicePixelRatio(scale);
+
+ QPainter painter(&m_pixmap);
+ paint(&painter, QRect(QPoint(), size), mode, state);
+
+ m_cacheKey = cacheKey;
+ }
+
+ return m_pixmap;
+}
+
+void QWindowsIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
+{
+ Q_UNUSED(state);
+
+ painter->save();
+ QFont renderFont(m_iconFont);
+ renderFont.setPixelSize(rect.height());
+ painter->setFont(renderFont);
+
+ QPalette palette;
+ switch (mode) {
+ case QIcon::Active:
+ painter->setPen(palette.color(QPalette::Active, QPalette::Text));
+ break;
+ case QIcon::Normal:
+ painter->setPen(palette.color(QPalette::Active, QPalette::Text));
+ break;
+ case QIcon::Disabled:
+ painter->setPen(palette.color(QPalette::Disabled, QPalette::Text));
+ break;
+ case QIcon::Selected:
+ painter->setPen(palette.color(QPalette::Active, QPalette::HighlightedText));
+ break;
+ }
+
+ painter->drawText(rect, Qt::AlignCenter, m_glyphs);
+ painter->restore();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsiconengine.h b/src/plugins/platforms/windows/qwindowsiconengine.h
new file mode 100644
index 0000000000..3c6cbddb8b
--- /dev/null
+++ b/src/plugins/platforms/windows/qwindowsiconengine.h
@@ -0,0 +1,47 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWINDOWSICONENGINE_H
+#define QWINDOWSICONENGINE_H
+
+#include <QtCore/qt_windows.h>
+
+#include <QtGui/qfont.h>
+#include <QtGui/qiconengine.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsIconEngine : public QIconEngine
+{
+public:
+ QWindowsIconEngine(const QString &iconName);
+ ~QWindowsIconEngine();
+ QIconEngine *clone() const override;
+ QString key() const override;
+ QString iconName() override;
+ bool isNull() override;
+
+ QList<QSize> availableSizes(QIcon::Mode, QIcon::State) override;
+ QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
+ QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
+ QPixmap scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale) override;
+ void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override;
+
+private:
+ static constexpr quint64 calculateCacheKey(QIcon::Mode mode, QIcon::State state)
+ {
+ return (quint64(mode) << 32) | state;
+ }
+
+ QString glyphs() const;
+
+ const QString m_iconName;
+ const QFont m_iconFont;
+ const QString m_glyphs;
+ mutable QPixmap m_pixmap;
+ mutable quint64 m_cacheKey = {};
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSICONENGINE_H
diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
index 758490ffb7..0281025b5b 100644
--- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
@@ -676,7 +676,7 @@ int QWindowsInputContext::reconvertString(RECONVERTSTRING *reconv)
reconv->dwTargetStrOffset = reconv->dwCompStrOffset;
auto *pastReconv = reinterpret_cast<ushort *>(reconv + 1);
std::copy(surroundingText.utf16(), surroundingText.utf16() + surroundingText.size(),
- QT_MAKE_UNCHECKED_ARRAY_ITERATOR(pastReconv));
+ pastReconv);
return memSize;
}
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
index 628b2f3209..aa6be266da 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -80,31 +80,6 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-/*!
- \class QWindowsIntegration
- \brief QPlatformIntegration implementation for Windows.
- \internal
-
- \section1 Programming Considerations
-
- The platform plugin should run on Desktop Windows from Windows XP onwards
- and Windows Embedded.
-
- It should compile with:
- \list
- \li Microsoft Visual Studio 2013 or later (using the Microsoft Windows SDK,
- (\c Q_CC_MSVC).
- \li Stock \l{http://mingw.org/}{MinGW} (\c Q_CC_MINGW).
- This version ships with headers that are missing a lot of WinAPI.
- \li MinGW distributions using GCC 4.7 or higher and a recent MinGW-w64 runtime API,
- such as \l{http://tdm-gcc.tdragon.net/}{TDM-GCC}, or
- \l{http://mingwbuilds.sourceforge.net/}{MinGW-builds}
- (\c Q_CC_MINGW and \c __MINGW64_VERSION_MAJOR indicating the version).
- MinGW-w64 provides more complete headers (compared to stock MinGW from mingw.org),
- including a considerable part of the Windows SDK.
- \endlist
-*/
-
struct QWindowsIntegrationPrivate
{
Q_DISABLE_COPY_MOVE(QWindowsIntegrationPrivate)
@@ -167,8 +142,8 @@ static inline unsigned parseOptions(const QStringList &paramList,
unsigned options = 0;
for (const QString &param : paramList) {
if (param.startsWith(u"fontengine=")) {
- if (param.endsWith(u"directwrite")) {
- options |= QWindowsIntegration::FontDatabaseDirectWrite;
+ if (param.endsWith(u"gdi")) {
+ options |= QWindowsIntegration::FontDatabaseGDI;
} else if (param.endsWith(u"freetype")) {
options |= QWindowsIntegration::FontDatabaseFreeType;
} else if (param.endsWith(u"native")) {
@@ -281,9 +256,9 @@ QWindowsIntegration::~QWindowsIntegration()
void QWindowsIntegration::initialize()
{
- QString icStr = QPlatformInputContextFactory::requested();
- icStr.isNull() ? d->m_inputContext.reset(new QWindowsInputContext)
- : d->m_inputContext.reset(QPlatformInputContextFactory::create(icStr));
+ auto icStrs = QPlatformInputContextFactory::requested();
+ icStrs.isEmpty() ? d->m_inputContext.reset(new QWindowsInputContext)
+ : d->m_inputContext.reset(QPlatformInputContextFactory::create(icStrs));
}
bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) const
@@ -311,6 +286,8 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co
return true;
case SwitchableWidgetComposition:
return false; // QTBUG-68329 QTBUG-53515 QTBUG-54734
+ case BackingStoreStaticContents:
+ return true;
default:
return QPlatformIntegration::hasCapability(cap);
}
@@ -507,17 +484,17 @@ QWindowsStaticOpenGLContext *QWindowsIntegration::staticOpenGLContext()
QPlatformFontDatabase *QWindowsIntegration::fontDatabase() const
{
if (!d->m_fontDatabase) {
-#if QT_CONFIG(directwrite3)
- if (d->m_options & QWindowsIntegration::FontDatabaseDirectWrite)
- d->m_fontDatabase = new QWindowsDirectWriteFontDatabase;
- else
-#endif
#ifndef QT_NO_FREETYPE
if (d->m_options & QWindowsIntegration::FontDatabaseFreeType)
d->m_fontDatabase = new QWindowsFontDatabaseFT;
else
#endif // QT_NO_FREETYPE
- d->m_fontDatabase = new QWindowsFontDatabase();
+#if QT_CONFIG(directwrite3)
+ if (!(d->m_options & (QWindowsIntegration::FontDatabaseGDI | QWindowsIntegration::DontUseDirectWriteFonts)))
+ d->m_fontDatabase = new QWindowsDirectWriteFontDatabase;
+ else
+#endif
+ d->m_fontDatabase = new QWindowsFontDatabase;
}
return d->m_fontDatabase;
}
@@ -565,14 +542,9 @@ QVariant QWindowsIntegration::styleHint(QPlatformIntegration::StyleHint hint) co
return QPlatformIntegration::styleHint(hint);
}
-Qt::KeyboardModifiers QWindowsIntegration::queryKeyboardModifiers() const
+QPlatformKeyMapper *QWindowsIntegration::keyMapper() const
{
- return QWindowsKeyMapper::queryKeyboardModifiers();
-}
-
-QList<int> QWindowsIntegration::possibleKeys(const QKeyEvent *e) const
-{
- return d->m_context.possibleKeys(e);
+ return d->m_context.keyMapper();
}
#if QT_CONFIG(clipboard)
@@ -653,12 +625,16 @@ void QWindowsIntegration::setApplicationBadge(qint64 number)
// We prefer the native BadgeUpdater API, that allows us to set a number directly,
// but it requires that the application has a package identity, and also doesn't
// seem to work in all cases on < Windows 11.
- if (isWindows11 && qt_win_hasPackageIdentity()) {
- using namespace winrt::Windows::UI::Notifications;
- auto badgeXml = BadgeUpdateManager::GetTemplateContent(BadgeTemplateType::BadgeNumber);
- badgeXml.SelectSingleNode(L"//badge/@value").NodeValue(winrt::box_value(winrt::to_hstring(number)));
- BadgeUpdateManager::CreateBadgeUpdaterForApplication().Update(BadgeNotification(badgeXml));
- return;
+ QT_TRY {
+ if (isWindows11 && qt_win_hasPackageIdentity()) {
+ using namespace winrt::Windows::UI::Notifications;
+ auto badgeXml = BadgeUpdateManager::GetTemplateContent(BadgeTemplateType::BadgeNumber);
+ badgeXml.SelectSingleNode(L"//badge/@value").NodeValue(winrt::box_value(winrt::to_hstring(number)));
+ BadgeUpdateManager::CreateBadgeUpdaterForApplication().Update(BadgeNotification(badgeXml));
+ return;
+ }
+ } QT_CATCH(...) {
+ // fall back to win32 implementation
}
#endif
@@ -670,7 +646,8 @@ void QWindowsIntegration::setApplicationBadge(qint64 number)
return;
}
- const bool isDarkMode = QWindowsContext::isDarkMode();
+ const bool isDarkMode = QWindowsTheme::instance()->colorScheme()
+ == Qt::ColorScheme::Dark;
QColor badgeColor;
QColor textColor;
@@ -785,7 +762,8 @@ void QWindowsIntegration::updateApplicationBadge()
// to a task bar button being created for the fist time or after
// Explorer had crashed and re-started. In any case, re-apply the
// badge so that everything is up to date.
- setApplicationBadge(m_applicationBadgeNumber);
+ if (m_applicationBadgeNumber)
+ setApplicationBadge(m_applicationBadgeNumber);
}
#if QT_CONFIG(vulkan)
diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h
index 1f3c71c41b..c271207741 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.h
+++ b/src/plugins/platforms/windows/qwindowsintegration.h
@@ -45,7 +45,7 @@ public:
DontUseWMPointer = 0x400,
DetectAltGrModifier = 0x800,
RtlEnabled = 0x1000,
- FontDatabaseDirectWrite = 0x2000
+ FontDatabaseGDI = 0x2000
};
explicit QWindowsIntegration(const QStringList &paramList);
@@ -82,8 +82,7 @@ public:
QPlatformServices *services() const override;
QVariant styleHint(StyleHint hint) const override;
- Qt::KeyboardModifiers queryKeyboardModifiers() const override;
- QList<int> possibleKeys(const QKeyEvent *e) const override;
+ QPlatformKeyMapper *keyMapper() const override;
static QWindowsIntegration *instance() { return m_instance; }
diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp
index 3089e745d4..ba76cda40b 100644
--- a/src/plugins/platforms/windows/qwindowskeymapper.cpp
+++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp
@@ -88,9 +88,17 @@ QWindowsKeyMapper::~QWindowsKeyMapper()= default;
#define VK_OEM_3 0xC0
#endif
-// We not only need the scancode itself but also the extended bit of key messages. Thus we need
-// the additional bit when masking the scancode.
-enum { scancodeBitmask = 0x1ff };
+// Get scancode from the given message
+static constexpr quint32 getScancode(const MSG &msg)
+{
+ const auto keyFlags = HIWORD(msg.lParam);
+ quint32 scancode = LOBYTE(keyFlags);
+ // if extended-key flag is on, the scan code consists of a sequence of two bytes,
+ // where the first byte has a value of 0xe0.
+ if ((keyFlags & KF_EXTENDED) != 0)
+ scancode |= 0xE000;
+ return scancode;
+}
// Key recorder ------------------------------------------------------------------------[ start ] --
struct KeyRecord {
@@ -532,33 +540,6 @@ QDebug operator<<(QDebug d, const KeyboardLayoutItem &k)
d << ')';
return d;
}
-
-// Helpers to format a list of int as Qt key sequence
-class formatKeys
-{
-public:
- explicit formatKeys(const QList<int> &keys) : m_keys(keys) {}
-
-private:
- friend QDebug operator<<(QDebug d, const formatKeys &keys);
- const QList<int> &m_keys;
-};
-
-QDebug operator<<(QDebug d, const formatKeys &k)
-{
- QDebugStateSaver saver(d);
- d.nospace();
- d << '(';
- for (int i =0, size = k.m_keys.size(); i < size; ++i) {
- if (i)
- d << ", ";
- d << QKeySequence(k.m_keys.at(i));
- }
- d << ')';
- return d;
-}
-#else // !QT_NO_DEBUG_STREAM
-static int formatKeys(const QList<int> &) { return 0; }
#endif // QT_NO_DEBUG_STREAM
/**
@@ -656,7 +637,7 @@ void QWindowsKeyMapper::updateKeyMap(const MSG &msg)
{
unsigned char kbdBuffer[256]; // Will hold the complete keyboard state
GetKeyboardState(kbdBuffer);
- const quint32 scancode = (msg.lParam >> 16) & scancodeBitmask;
+ const quint32 scancode = getScancode(msg);
updatePossibleKeyCodes(kbdBuffer, scancode, quint32(msg.wParam));
}
@@ -820,7 +801,7 @@ static void showSystemMenu(QWindow* w)
qWindowsWndProc(topLevelHwnd, WM_SYSCOMMAND, WPARAM(ret), 0);
}
-static inline void sendExtendedPressRelease(QWindow *w, int k,
+static inline void sendExtendedPressRelease(QWindow *w, unsigned long timestamp, int k,
Qt::KeyboardModifiers mods,
quint32 nativeScanCode,
quint32 nativeVirtualKey,
@@ -829,8 +810,8 @@ static inline void sendExtendedPressRelease(QWindow *w, int k,
bool autorep = false,
ushort count = 1)
{
- QWindowSystemInterface::handleExtendedKeyEvent(w, QEvent::KeyPress, k, mods, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
- QWindowSystemInterface::handleExtendedKeyEvent(w, QEvent::KeyRelease, k, mods, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
+ QWindowSystemInterface::handleExtendedKeyEvent(w, timestamp, QEvent::KeyPress, k, mods, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
+ QWindowSystemInterface::handleExtendedKeyEvent(w, timestamp, QEvent::KeyRelease, k, mods, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
}
/*!
@@ -897,7 +878,7 @@ bool QWindowsKeyMapper::translateMultimediaKeyEventInternal(QWindow *window, con
const int qtKey = int(CmdTbl[cmd]);
if (!skipPressRelease)
- sendExtendedPressRelease(receiver, qtKey, Qt::KeyboardModifier(state), 0, 0, 0);
+ sendExtendedPressRelease(receiver, msg.time, qtKey, Qt::KeyboardModifier(state), 0, 0, 0);
// QTBUG-43343: Make sure to return false if Qt does not handle the key, otherwise,
// the keys are not passed to the active media player.
# if QT_CONFIG(shortcut)
@@ -942,7 +923,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
m_seenAltGr = true;
const UINT msgType = msg.message;
- const quint32 scancode = (msg.lParam >> 16) & scancodeBitmask;
+ const quint32 scancode = getScancode(msg);
auto vk_key = quint32(msg.wParam);
quint32 nModifiers = 0;
@@ -977,7 +958,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
// A multi-character key or a Input method character
// not found by our look-ahead
if (msgType == WM_CHAR || msgType == WM_IME_CHAR) {
- sendExtendedPressRelease(receiver, 0, Qt::KeyboardModifier(state), scancode, vk_key, nModifiers, messageKeyText(msg), false);
+ sendExtendedPressRelease(receiver, msg.time, 0, Qt::KeyboardModifier(state), scancode, 0, nModifiers, messageKeyText(msg), false);
return true;
}
@@ -1012,14 +993,14 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
if (dirStatus == VK_LSHIFT
&& ((msg.wParam == VK_SHIFT && GetKeyState(VK_LCONTROL))
|| (msg.wParam == VK_CONTROL && GetKeyState(VK_LSHIFT)))) {
- sendExtendedPressRelease(receiver, Qt::Key_Direction_L, {},
+ sendExtendedPressRelease(receiver, msg.time, Qt::Key_Direction_L, {},
scancode, vk_key, nModifiers, QString(), false);
result = true;
dirStatus = 0;
} else if (dirStatus == VK_RSHIFT
&& ( (msg.wParam == VK_SHIFT && GetKeyState(VK_RCONTROL))
|| (msg.wParam == VK_CONTROL && GetKeyState(VK_RSHIFT)))) {
- sendExtendedPressRelease(receiver, Qt::Key_Direction_R, {},
+ sendExtendedPressRelease(receiver, msg.time, Qt::Key_Direction_R, {},
scancode, vk_key, nModifiers, QString(), false);
result = true;
dirStatus = 0;
@@ -1232,9 +1213,9 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
// so, we have an auto-repeating key
if (rec) {
if (code < Qt::Key_Shift || code > Qt::Key_ScrollLock) {
- QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyRelease, code,
+ QWindowSystemInterface::handleExtendedKeyEvent(receiver, msg.time, QEvent::KeyRelease, code,
Qt::KeyboardModifier(state), scancode, quint32(msg.wParam), nModifiers, rec->text, true);
- QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyPress, code,
+ QWindowSystemInterface::handleExtendedKeyEvent(receiver, msg.time, QEvent::KeyPress, code,
Qt::KeyboardModifier(state), scancode, quint32(msg.wParam), nModifiers, rec->text, true);
result = true;
}
@@ -1260,7 +1241,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
if (msg.wParam == VK_PACKET)
code = asciiToKeycode(char(uch.cell()), state);
- QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyPress, code,
+ QWindowSystemInterface::handleExtendedKeyEvent(receiver, msg.time, QEvent::KeyPress, code,
modifiers, scancode, quint32(msg.wParam), nModifiers, text, false);
result =true;
bool store = true;
@@ -1302,10 +1283,10 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
if ((msg.lParam & 0x40000000) == 0 &&
Qt::KeyboardModifier(state) == Qt::NoModifier &&
((code == Qt::Key_F18) || (code == Qt::Key_F19) || (code == Qt::Key_F20))) {
- QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyPress, code,
+ QWindowSystemInterface::handleExtendedKeyEvent(receiver, msg.time, QEvent::KeyPress, code,
Qt::MetaModifier, scancode,
quint32(msg.wParam), MetaLeft);
- QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyRelease, code,
+ QWindowSystemInterface::handleExtendedKeyEvent(receiver, msg.time, QEvent::KeyRelease, code,
Qt::NoModifier, scancode,
quint32(msg.wParam), 0);
result = true;
@@ -1317,7 +1298,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
// Map SHIFT + Tab to SHIFT + BackTab, QShortcutMap knows about this translation
if (code == Qt::Key_Tab && (state & Qt::ShiftModifier) == Qt::ShiftModifier)
code = Qt::Key_Backtab;
- QWindowSystemInterface::handleExtendedKeyEvent(receiver, QEvent::KeyRelease, code,
+ QWindowSystemInterface::handleExtendedKeyEvent(receiver, msg.time, QEvent::KeyRelease, code,
Qt::KeyboardModifier(state), scancode, quint32(msg.wParam),
nModifiers,
(rec ? rec->text : QString()), false);
@@ -1339,7 +1320,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg,
return result;
}
-Qt::KeyboardModifiers QWindowsKeyMapper::queryKeyboardModifiers()
+Qt::KeyboardModifiers QWindowsKeyMapper::queryKeyboardModifiers() const
{
Qt::KeyboardModifiers modifiers = Qt::NoModifier;
if (GetKeyState(VK_SHIFT) < 0)
@@ -1353,9 +1334,9 @@ Qt::KeyboardModifiers QWindowsKeyMapper::queryKeyboardModifiers()
return modifiers;
}
-QList<int> QWindowsKeyMapper::possibleKeys(const QKeyEvent *e) const
+QList<QKeyCombination> QWindowsKeyMapper::possibleKeyCombinations(const QKeyEvent *e) const
{
- QList<int> result;
+ QList<QKeyCombination> result;
const quint32 nativeVirtualKey = e->nativeVirtualKey();
@@ -1369,31 +1350,34 @@ QList<int> QWindowsKeyMapper::possibleKeys(const QKeyEvent *e) const
quint32 baseKey = kbItem.qtKey[0];
Qt::KeyboardModifiers keyMods = e->modifiers();
if (baseKey == Qt::Key_Return && (e->nativeModifiers() & ExtendedKey)) {
- result << (Qt::Key_Enter | keyMods).toCombined();
+ result << (Qt::Key_Enter | keyMods);
return result;
}
- result << int(baseKey) + int(keyMods); // The base key is _always_ valid, of course
+
+ // The base key is _always_ valid, of course
+ result << QKeyCombination::fromCombined(int(baseKey) + int(keyMods));
for (size_t i = 1; i < NumMods; ++i) {
Qt::KeyboardModifiers neededMods = ModsTbl[i];
quint32 key = kbItem.qtKey[i];
if (key && key != baseKey && ((keyMods & neededMods) == neededMods)) {
const Qt::KeyboardModifiers missingMods = keyMods & ~neededMods;
- const int matchedKey = int(key) + int(missingMods);
- const auto it =
- std::find_if(result.begin(), result.end(),
- [key] (int k) { return (k & ~Qt::KeyboardModifierMask) == key; });
+ const auto matchedKey = QKeyCombination::fromCombined(int(key) + int(missingMods));
+ const auto it = std::find_if(result.begin(), result.end(),
+ [key](auto keyCombination) {
+ return keyCombination.key() == key;
+ });
// QTBUG-67200: Use the match with the least modifiers (prefer
// Shift+9 over Alt + Shift + 9) resulting in more missing modifiers.
if (it == result.end())
result << matchedKey;
- else if (missingMods > Qt::KeyboardModifiers(*it & Qt::KeyboardModifierMask))
+ else if (missingMods > it->keyboardModifiers())
*it = matchedKey;
}
}
qCDebug(lcQpaEvents) << __FUNCTION__ << e << "nativeVirtualKey="
<< Qt::showbase << Qt::hex << e->nativeVirtualKey() << Qt::dec << Qt::noshowbase
- << e->modifiers() << kbItem << "\n returns" << formatKeys(result);
+ << e->modifiers() << kbItem << "\n returns" << result;
return result;
}
diff --git a/src/plugins/platforms/windows/qwindowskeymapper.h b/src/plugins/platforms/windows/qwindowskeymapper.h
index 6e13c47323..72b2536ad7 100644
--- a/src/plugins/platforms/windows/qwindowskeymapper.h
+++ b/src/plugins/platforms/windows/qwindowskeymapper.h
@@ -8,6 +8,8 @@
#include <QtCore/qlocale.h>
+#include <qpa/qplatformkeymapper.h>
+
QT_BEGIN_NAMESPACE
class QKeyEvent;
@@ -33,7 +35,7 @@ struct KeyboardLayoutItem {
quint32 qtKey[NumQtKeys]; // Can by any Qt::Key_<foo>, or unicode character
};
-class QWindowsKeyMapper
+class QWindowsKeyMapper : public QPlatformKeyMapper
{
Q_DISABLE_COPY_MOVE(QWindowsKeyMapper)
public:
@@ -53,8 +55,8 @@ public:
QWindow *keyGrabber() const { return m_keyGrabber; }
void setKeyGrabber(QWindow *w) { m_keyGrabber = w; }
- static Qt::KeyboardModifiers queryKeyboardModifiers();
- QList<int> possibleKeys(const QKeyEvent *e) const;
+ Qt::KeyboardModifiers queryKeyboardModifiers() const override;
+ QList<QKeyCombination> possibleKeyCombinations(const QKeyEvent *e) const override;
private:
bool translateKeyEventInternal(QWindow *receiver, MSG msg, bool grab, LRESULT *lResult);
diff --git a/src/plugins/platforms/windows/qwindowsmenu.h b/src/plugins/platforms/windows/qwindowsmenu.h
index 646ab64894..6f66180d82 100644
--- a/src/plugins/platforms/windows/qwindowsmenu.h
+++ b/src/plugins/platforms/windows/qwindowsmenu.h
@@ -9,7 +9,6 @@
#include <qpa/qplatformmenu.h>
#include <QtCore/qlist.h>
-#include <QtCore/qpair.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsmimeregistry.cpp b/src/plugins/platforms/windows/qwindowsmimeregistry.cpp
index 2d1c42df91..8d147e8fa0 100644
--- a/src/plugins/platforms/windows/qwindowsmimeregistry.cpp
+++ b/src/plugins/platforms/windows/qwindowsmimeregistry.cpp
@@ -154,7 +154,7 @@ static bool qt_write_dibv5(QDataStream &s, QImage image)
return false;
if (image.format() != QImage::Format_ARGB32)
- image = image.convertToFormat(QImage::Format_ARGB32);
+ image = std::move(image).convertToFormat(QImage::Format_ARGB32);
auto *buf = new uchar[bpl_bmp];
@@ -870,7 +870,7 @@ bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeD
QByteArray ba;
if (cf == CF_DIB) {
if (img.format() > QImage::Format_ARGB32)
- img = img.convertToFormat(QImage::Format_RGB32);
+ img = std::move(img).convertToFormat(QImage::Format_RGB32);
const QByteArray ba = writeDib(img);
if (!ba.isEmpty())
return setData(ba, pmedium);
@@ -883,7 +883,7 @@ bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeD
} else {
QDataStream s(&ba, QIODevice::WriteOnly);
s.setByteOrder(QDataStream::LittleEndian);// Intel byte order ####
- if (qt_write_dibv5(s, img))
+ if (qt_write_dibv5(s, std::move(img)))
return setData(ba, pmedium);
}
}
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
index ceb33f6141..9af9fba408 100644
--- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
@@ -268,7 +268,8 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
}
}
- const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
+ const auto *keyMapper = QWindowsContext::instance()->keyMapper();
+ const Qt::KeyboardModifiers keyModifiers = keyMapper->queryKeyboardModifiers();
const MouseEvent mouseEvent = eventFromMsg(msg);
Qt::MouseButtons buttons;
@@ -286,19 +287,16 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
if (m_lastEventType == QEvent::NonClientAreaMouseButtonPress
&& (mouseEvent.type == QEvent::NonClientAreaMouseMove || mouseEvent.type == QEvent::MouseMove)
&& (m_lastEventButton & buttons) == 0) {
- if (mouseEvent.type == QEvent::NonClientAreaMouseMove) {
- QWindowSystemInterface::handleFrameStrutMouseEvent(window, device, clientPosition, globalPosition, buttons, m_lastEventButton,
- QEvent::NonClientAreaMouseButtonRelease, keyModifiers, source);
- } else {
- QWindowSystemInterface::handleMouseEvent(window, device, clientPosition, globalPosition, buttons, m_lastEventButton,
- QEvent::MouseButtonRelease, keyModifiers, source);
- }
+ auto releaseType = mouseEvent.type == QEvent::NonClientAreaMouseMove ?
+ QEvent::NonClientAreaMouseButtonRelease : QEvent::MouseButtonRelease;
+ QWindowSystemInterface::handleMouseEvent(window, msg.time, device, clientPosition, globalPosition, buttons, m_lastEventButton,
+ releaseType, keyModifiers, source);
}
m_lastEventType = mouseEvent.type;
m_lastEventButton = mouseEvent.button;
if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) {
- QWindowSystemInterface::handleFrameStrutMouseEvent(window, device, clientPosition,
+ QWindowSystemInterface::handleMouseEvent(window, msg.time, device, clientPosition,
globalPosition, buttons,
mouseEvent.button, mouseEvent.type,
keyModifiers, source);
@@ -448,7 +446,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
}
if (!discardEvent && mouseEvent.type != QEvent::None) {
- QWindowSystemInterface::handleMouseEvent(window, device, clientPosition, globalPosition, buttons,
+ QWindowSystemInterface::handleMouseEvent(window, msg.time, device, clientPosition, globalPosition, buttons,
mouseEvent.button, mouseEvent.type,
keyModifiers, source);
}
@@ -472,7 +470,7 @@ static bool isValidWheelReceiver(QWindow *candidate)
return false;
}
-static void redirectWheelEvent(QWindow *window, const QPoint &globalPos, int delta,
+static void redirectWheelEvent(QWindow *window, unsigned long timestamp, const QPoint &globalPos, int delta,
Qt::Orientation orientation, Qt::KeyboardModifiers mods)
{
// Redirect wheel event to one of the following, in order of preference:
@@ -493,6 +491,7 @@ static void redirectWheelEvent(QWindow *window, const QPoint &globalPos, int del
if (handleEvent) {
const QPoint point = (orientation == Qt::Vertical) ? QPoint(0, delta) : QPoint(delta, 0);
QWindowSystemInterface::handleWheelEvent(receiver,
+ timestamp,
QWindowsGeometryHint::mapFromGlobal(receiver, globalPos),
globalPos, QPoint(), point, mods);
}
@@ -521,7 +520,7 @@ bool QWindowsMouseHandler::translateMouseWheelEvent(QWindow *window, HWND,
delta = -delta;
const QPoint globalPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
- redirectWheelEvent(window, globalPos, delta, orientation, mods);
+ redirectWheelEvent(window, msg.time, globalPos, delta, orientation, mods);
return true;
}
@@ -552,7 +551,7 @@ bool QWindowsMouseHandler::translateScrollEvent(QWindow *window, HWND,
return false;
}
- redirectWheelEvent(window, QCursor::pos(), delta, Qt::Horizontal, Qt::NoModifier);
+ redirectWheelEvent(window, msg.time, QCursor::pos(), delta, Qt::Horizontal, Qt::NoModifier);
return true;
}
@@ -632,10 +631,12 @@ bool QWindowsMouseHandler::translateTouchEvent(QWindow *window, HWND,
if (allStates == QEventPoint::State::Released)
m_touchInputIDToTouchPointID.clear();
+ const auto *keyMapper = QWindowsContext::instance()->keyMapper();
QWindowSystemInterface::handleTouchEvent(window,
+ msg.time,
m_touchDevice.data(),
touchPoints,
- QWindowsKeyMapper::queryKeyboardModifiers());
+ keyMapper->queryKeyboardModifiers());
return true;
}
diff --git a/src/plugins/platforms/windows/qwindowsole.h b/src/plugins/platforms/windows/qwindowsole.h
index b687384684..016f9dd04c 100644
--- a/src/plugins/platforms/windows/qwindowsole.h
+++ b/src/plugins/platforms/windows/qwindowsole.h
@@ -4,12 +4,12 @@
#ifndef QWINDOWSOLE_H
#define QWINDOWSOLE_H
-#include "qwindowscombase.h"
#include <QtCore/qt_windows.h>
#include <QtCore/qlist.h>
#include <QtCore/qmap.h>
#include <QtCore/qpointer.h>
+#include <QtCore/private/qcomobject_p.h>
#include <objidl.h>
@@ -18,7 +18,7 @@ QT_BEGIN_NAMESPACE
class QMimeData;
class QWindow;
-class QWindowsOleDataObject : public QWindowsComBase<IDataObject>
+class QWindowsOleDataObject : public QComObject<IDataObject>
{
public:
explicit QWindowsOleDataObject(QMimeData *mimeData);
@@ -47,7 +47,7 @@ private:
DWORD performedEffect = DROPEFFECT_NONE;
};
-class QWindowsOleEnumFmtEtc : public QWindowsComBase<IEnumFORMATETC>
+class QWindowsOleEnumFmtEtc : public QComObject<IEnumFORMATETC>
{
public:
explicit QWindowsOleEnumFmtEtc(const QList<FORMATETC> &fmtetcs);
diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp
index 88f02347b3..71c7217671 100644
--- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp
+++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp
@@ -428,8 +428,9 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
return false;
if (msg.message == WM_POINTERCAPTURECHANGED) {
- QWindowSystemInterface::handleTouchCancelEvent(window, m_touchDevice.data(),
- QWindowsKeyMapper::queryKeyboardModifiers());
+ const auto *keyMapper = QWindowsContext::instance()->keyMapper();
+ QWindowSystemInterface::handleTouchCancelEvent(window, msg.time, m_touchDevice.data(),
+ keyMapper->queryKeyboardModifiers());
m_lastTouchPoints.clear();
return true;
}
@@ -441,6 +442,8 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
if (id != -1)
m_lastTouchPoints.remove(id);
}
+ // Send LeaveEvent to reset hover when the last finger leaves the touch screen (QTBUG-62912)
+ QWindowSystemInterface::handleEnterLeaveEvent(nullptr, window);
}
// Only handle down/up/update, ignore others like WM_POINTERENTER, WM_POINTERLEAVE, etc.
@@ -537,8 +540,9 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
if (allStates == QEventPoint::State::Released)
m_touchInputIDToTouchPointID.clear();
- QWindowSystemInterface::handleTouchEvent(window, m_touchDevice.data(), touchPoints,
- QWindowsKeyMapper::queryKeyboardModifiers());
+ const auto *keyMapper = QWindowsContext::instance()->keyMapper();
+ QWindowSystemInterface::handleTouchEvent(window, msg.time, m_touchDevice.data(), touchPoints,
+ keyMapper->queryKeyboardModifiers());
return false; // Allow mouse messages to be generated.
}
@@ -635,7 +639,7 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
switch (msg.message) {
case WM_POINTERENTER: {
- QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(window, device.data(), true);
+ QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(window, msg.time, device.data(), true);
m_windowUnderPointer = window;
// The local coordinates may fall outside the window.
// Wait until the next update to send the enter event.
@@ -648,7 +652,7 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
m_windowUnderPointer = nullptr;
m_currentWindow = nullptr;
}
- QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(window, device.data(), false);
+ QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(window, msg.time, device.data(), false);
break;
case WM_POINTERDOWN:
case WM_POINTERUP:
@@ -671,9 +675,10 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
wumPlatformWindow->applyCursor();
}
}
- const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
+ const auto *keyMapper = QWindowsContext::instance()->keyMapper();
+ const Qt::KeyboardModifiers keyModifiers = keyMapper->queryKeyboardModifiers();
- QWindowSystemInterface::handleTabletEvent(target, device.data(),
+ QWindowSystemInterface::handleTabletEvent(target, msg.time, device.data(),
localPos, hiResGlobalPos, mouseButtons,
pressure, xTilt, yTilt, tangentialPressure,
rotation, z, keyModifiers);
@@ -724,7 +729,7 @@ bool QWindowsPointerHandler::translateMouseWheelEvent(QWindow *window,
QPoint localPos = QWindowsGeometryHint::mapFromGlobal(receiver, globalPos);
- QWindowSystemInterface::handleWheelEvent(receiver, localPos, globalPos, QPoint(), angleDelta, keyModifiers);
+ QWindowSystemInterface::handleWheelEvent(receiver, msg.time, localPos, globalPos, QPoint(), angleDelta, keyModifiers);
return true;
}
@@ -737,20 +742,20 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
{
*result = 0;
- QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
- if ((et & QtWindows::NonClientEventFlag) == 0 && QWindowsBaseWindow::isRtlLayout(hwnd)) {
- RECT clientArea;
- GetClientRect(hwnd, &clientArea);
- eventPos.setX(clientArea.right - eventPos.x());
- }
-
QPoint localPos;
QPoint globalPos;
+ QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
if ((et == QtWindows::MouseWheelEvent) || (et & QtWindows::NonClientEventFlag)) {
globalPos = eventPos;
localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, eventPos);
} else {
+ if (QWindowsBaseWindow::isRtlLayout(hwnd)) {
+ RECT clientArea;
+ GetClientRect(hwnd, &clientArea);
+ eventPos.setX(clientArea.right - eventPos.x());
+ }
+
globalPos = QWindowsGeometryHint::mapToGlobal(hwnd, eventPos);
auto targetHwnd = hwnd;
if (auto *pw = window->handle())
@@ -760,7 +765,8 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
: QWindowsGeometryHint::mapFromGlobal(targetHwnd, globalPos);
}
- const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
+ const auto *keyMapper = QWindowsContext::instance()->keyMapper();
+ const Qt::KeyboardModifiers keyModifiers = keyMapper->queryKeyboardModifiers();
QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos);
if (et == QtWindows::MouseWheelEvent)
@@ -820,19 +826,16 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
if (m_lastEventType == QEvent::NonClientAreaMouseButtonPress
&& (mouseEvent.type == QEvent::NonClientAreaMouseMove || mouseEvent.type == QEvent::MouseMove)
&& (m_lastEventButton & mouseButtons) == 0) {
- if (mouseEvent.type == QEvent::NonClientAreaMouseMove) {
- QWindowSystemInterface::handleFrameStrutMouseEvent(window, device, localPos, globalPos, mouseButtons, m_lastEventButton,
- QEvent::NonClientAreaMouseButtonRelease, keyModifiers, source);
- } else {
- QWindowSystemInterface::handleMouseEvent(window, device, localPos, globalPos, mouseButtons, m_lastEventButton,
- QEvent::MouseButtonRelease, keyModifiers, source);
- }
+ auto releaseType = mouseEvent.type == QEvent::NonClientAreaMouseMove ?
+ QEvent::NonClientAreaMouseButtonRelease : QEvent::MouseButtonRelease;
+ QWindowSystemInterface::handleMouseEvent(window, msg.time, device, localPos, globalPos, mouseButtons, m_lastEventButton,
+ releaseType, keyModifiers, source);
}
m_lastEventType = mouseEvent.type;
m_lastEventButton = mouseEvent.button;
if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) {
- QWindowSystemInterface::handleFrameStrutMouseEvent(window, device, localPos, globalPos, mouseButtons,
+ QWindowSystemInterface::handleMouseEvent(window, msg.time, device, localPos, globalPos, mouseButtons,
mouseEvent.button, mouseEvent.type, keyModifiers, source);
return false; // Allow further event processing
}
@@ -852,7 +855,7 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
handleEnterLeave(window, currentWindowUnderPointer, globalPos);
if (!discardEvent && mouseEvent.type != QEvent::None) {
- QWindowSystemInterface::handleMouseEvent(window, device, localPos, globalPos, mouseButtons,
+ QWindowSystemInterface::handleMouseEvent(window, msg.time, device, localPos, globalPos, mouseButtons,
mouseEvent.button, mouseEvent.type, keyModifiers, source);
}
diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp
index 5414fc2778..a50f9fd4b0 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.cpp
+++ b/src/plugins/platforms/windows/qwindowsscreen.cpp
@@ -14,14 +14,22 @@
#include <QtGui/qpixmap.h>
#include <QtGui/qguiapplication.h>
#include <qpa/qwindowsysteminterface.h>
+#include <QtCore/private/qsystemerror_p.h>
+#include <QtGui/private/qedidparser_p.h>
#include <private/qhighdpiscaling_p.h>
#include <private/qwindowsfontdatabasebase_p.h>
#include <private/qpixmap_win_p.h>
+#include <private/quniquehandle_p.h>
#include <QtGui/qscreen.h>
#include <QtCore/qdebug.h>
+#include <memory>
+#include <type_traits>
+
+#include <cfgmgr32.h>
+#include <setupapi.h>
#include <shellscalingapi.h>
QT_BEGIN_NAMESPACE
@@ -42,7 +50,7 @@ static inline QDpi monitorDPI(HMONITOR hMonitor)
return {0, 0};
}
-static bool getPathInfo(const MONITORINFOEX &viewInfo, DISPLAYCONFIG_PATH_INFO *pathInfo)
+static std::vector<DISPLAYCONFIG_PATH_INFO> getPathInfo(const MONITORINFOEX &viewInfo)
{
// We might want to consider storing adapterId/id from DISPLAYCONFIG_PATH_TARGET_INFO.
std::vector<DISPLAYCONFIG_PATH_INFO> pathInfos;
@@ -58,7 +66,7 @@ static bool getPathInfo(const MONITORINFOEX &viewInfo, DISPLAYCONFIG_PATH_INFO *
// look up the needed buffer sizes.
if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements,
&numModeInfoArrayElements) != ERROR_SUCCESS) {
- return false;
+ return {};
}
pathInfos.resize(numPathArrayElements);
modeInfos.resize(numModeInfoArrayElements);
@@ -67,24 +75,25 @@ static bool getPathInfo(const MONITORINFOEX &viewInfo, DISPLAYCONFIG_PATH_INFO *
} while (result == ERROR_INSUFFICIENT_BUFFER);
if (result != ERROR_SUCCESS)
- return false;
-
- // Find path matching monitor name
- for (uint32_t p = 0; p < numPathArrayElements; p++) {
- DISPLAYCONFIG_SOURCE_DEVICE_NAME deviceName;
- deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
- deviceName.header.size = sizeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME);
- deviceName.header.adapterId = pathInfos[p].sourceInfo.adapterId;
- deviceName.header.id = pathInfos[p].sourceInfo.id;
- if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) {
- if (wcscmp(viewInfo.szDevice, deviceName.viewGdiDeviceName) == 0) {
- *pathInfo = pathInfos[p];
+ return {};
+
+ // Find paths matching monitor name
+ auto discardThese =
+ std::remove_if(pathInfos.begin(), pathInfos.end(), [&](const auto &path) -> bool {
+ DISPLAYCONFIG_SOURCE_DEVICE_NAME deviceName;
+ deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
+ deviceName.header.size = sizeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME);
+ deviceName.header.adapterId = path.sourceInfo.adapterId;
+ deviceName.header.id = path.sourceInfo.id;
+ if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) {
+ return wcscmp(viewInfo.szDevice, deviceName.viewGdiDeviceName) != 0;
+ }
return true;
- }
- }
- }
+ });
+
+ pathInfos.erase(discardThese, pathInfos.end());
- return false;
+ return pathInfos;
}
#if 0
@@ -108,6 +117,149 @@ static float getMonitorSDRWhiteLevel(DISPLAYCONFIG_PATH_TARGET_INFO *targetInfo)
using WindowsScreenDataList = QList<QWindowsScreenData>;
+namespace {
+
+struct DiRegKeyHandleTraits
+{
+ using Type = HKEY;
+ static Type invalidValue()
+ {
+ // The setupapi.h functions return INVALID_HANDLE_VALUE when failing to open a registry key
+ return reinterpret_cast<HKEY>(INVALID_HANDLE_VALUE);
+ }
+ static bool close(Type handle) { return RegCloseKey(handle) == ERROR_SUCCESS; }
+};
+
+using DiRegKeyHandle = QUniqueHandle<DiRegKeyHandleTraits>;
+
+}
+
+static void setMonitorDataFromSetupApi(QWindowsScreenData &data,
+ const std::vector<DISPLAYCONFIG_PATH_INFO> &pathGroup)
+{
+ if (pathGroup.empty()) {
+ return;
+ }
+
+ // The only property shared among monitors in a clone group is deviceName
+ {
+ DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName = {};
+ deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
+ deviceName.header.size = sizeof(DISPLAYCONFIG_TARGET_DEVICE_NAME);
+ // The first element in the clone group is the main monitor.
+ deviceName.header.adapterId = pathGroup[0].targetInfo.adapterId;
+ deviceName.header.id = pathGroup[0].targetInfo.id;
+ if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) {
+ data.devicePath = QString::fromWCharArray(deviceName.monitorDevicePath);
+ } else {
+ qCWarning(lcQpaScreen)
+ << u"Unable to get device information for %1:"_s.arg(pathGroup[0].targetInfo.id)
+ << QSystemError::windowsString();
+ }
+ }
+
+ // The rest must be concatenated into the resulting property
+ QStringList names;
+ QStringList manufacturers;
+ QStringList models;
+ QStringList serialNumbers;
+
+ for (const auto &path : pathGroup) {
+ DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName = {};
+ deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
+ deviceName.header.size = sizeof(DISPLAYCONFIG_TARGET_DEVICE_NAME);
+ deviceName.header.adapterId = path.targetInfo.adapterId;
+ deviceName.header.id = path.targetInfo.id;
+ if (DisplayConfigGetDeviceInfo(&deviceName.header) != ERROR_SUCCESS) {
+ qCWarning(lcQpaScreen)
+ << u"Unable to get device information for %1:"_s.arg(path.targetInfo.id)
+ << QSystemError::windowsString();
+ continue;
+ }
+
+ // https://learn.microsoft.com/en-us/windows-hardware/drivers/install/guid-devinterface-monitor
+ constexpr GUID GUID_DEVINTERFACE_MONITOR = {
+ 0xe6f07b5f, 0xee97, 0x4a90, { 0xb0, 0x76, 0x33, 0xf5, 0x7b, 0xf4, 0xea, 0xa7 }
+ };
+ const HDEVINFO devInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_MONITOR, nullptr, nullptr,
+ DIGCF_DEVICEINTERFACE);
+
+ SP_DEVICE_INTERFACE_DATA deviceInterfaceData{};
+ deviceInterfaceData.cbSize = sizeof(deviceInterfaceData);
+
+ if (!SetupDiOpenDeviceInterfaceW(devInfo, deviceName.monitorDevicePath, DIODI_NO_ADD,
+ &deviceInterfaceData)) {
+ qCWarning(lcQpaScreen)
+ << u"Unable to open monitor interface to %1:"_s.arg(data.deviceName)
+ << QSystemError::windowsString();
+ continue;
+ }
+
+ DWORD requiredSize{ 0 };
+ if (SetupDiGetDeviceInterfaceDetailW(devInfo, &deviceInterfaceData, nullptr, 0,
+ &requiredSize, nullptr)
+ || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ continue;
+ }
+
+ const std::unique_ptr<std::byte[]> storage(new std::byte[requiredSize]);
+ auto *devicePath = reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_W *>(storage.get());
+ devicePath->cbSize = sizeof(std::remove_pointer_t<decltype(devicePath)>);
+ SP_DEVINFO_DATA deviceInfoData{};
+ deviceInfoData.cbSize = sizeof(deviceInfoData);
+ if (!SetupDiGetDeviceInterfaceDetailW(devInfo, &deviceInterfaceData, devicePath,
+ requiredSize, nullptr, &deviceInfoData)) {
+ qCDebug(lcQpaScreen) << u"Unable to get monitor metadata for %1:"_s.arg(data.deviceName)
+ << QSystemError::windowsString();
+ continue;
+ }
+
+ const DiRegKeyHandle edidRegistryKey{ SetupDiOpenDevRegKey(
+ devInfo, &deviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ) };
+
+ if (!edidRegistryKey.isValid())
+ continue;
+
+ DWORD edidDataSize{ 0 };
+ if (RegQueryValueExW(edidRegistryKey.get(), L"EDID", nullptr, nullptr, nullptr,
+ &edidDataSize)
+ != ERROR_SUCCESS) {
+ continue;
+ }
+
+ QByteArray edidData;
+ edidData.resize(edidDataSize);
+
+ if (RegQueryValueExW(edidRegistryKey.get(), L"EDID", nullptr, nullptr,
+ reinterpret_cast<unsigned char *>(edidData.data()), &edidDataSize)
+ != ERROR_SUCCESS) {
+ qCDebug(lcQpaScreen) << u"Unable to get EDID from the Registry for %1:"_s.arg(
+ data.deviceName)
+ << QSystemError::windowsString();
+ continue;
+ }
+
+ QEdidParser edid;
+
+ if (!edid.parse(edidData)) {
+ qCDebug(lcQpaScreen) << "Invalid EDID blob for" << data.deviceName;
+ continue;
+ }
+
+ // We skip edid.identifier because it is unreliable, and a better option
+ // is already available through DisplayConfigGetDeviceInfo (see below).
+ names << QString::fromWCharArray(deviceName.monitorFriendlyDeviceName);
+ manufacturers << edid.manufacturer;
+ models << edid.model;
+ serialNumbers << edid.serialNumber;
+ }
+
+ data.name = names.join(u"|"_s);
+ data.manufacturer = manufacturers.join(u"|"_s);
+ data.model = models.join(u"|"_s);
+ data.serialNumber = serialNumbers.join(u"|"_s);
+}
+
static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data)
{
MONITORINFOEX info;
@@ -120,16 +272,9 @@ static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data)
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->deviceName = QString::fromWCharArray(info.szDevice);
- DISPLAYCONFIG_PATH_INFO pathInfo = {};
- const bool hasPathInfo = getPathInfo(info, &pathInfo);
- if (hasPathInfo) {
- DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName = {};
- deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
- deviceName.header.size = sizeof(DISPLAYCONFIG_TARGET_DEVICE_NAME);
- deviceName.header.adapterId = pathInfo.targetInfo.adapterId;
- deviceName.header.id = pathInfo.targetInfo.id;
- if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS)
- data->name = QString::fromWCharArray(deviceName.monitorFriendlyDeviceName);
+ const auto pathGroup = getPathInfo(info);
+ if (!pathGroup.empty()) {
+ setMonitorDataFromSetupApi(*data, pathGroup);
}
if (data->name.isEmpty())
data->name = data->deviceName;
@@ -155,7 +300,9 @@ static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data)
// ### We might want to consider storing adapterId/id from DISPLAYCONFIG_PATH_TARGET_INFO,
// if we are going to use DISPLAYCONFIG lookups more.
- if (hasPathInfo) {
+ if (!pathGroup.empty()) {
+ // The first element in the clone group is the main monitor.
+ const auto &pathInfo = pathGroup[0];
switch (pathInfo.targetInfo.rotation) {
case DISPLAYCONFIG_ROTATION_IDENTITY:
data->orientation = Qt::LandscapeOrientation;
@@ -231,15 +378,14 @@ static QDebug operator<<(QDebug dbg, const QWindowsScreenData &d)
QDebugStateSaver saver(dbg);
dbg.nospace();
dbg.noquote();
- dbg << "Screen \"" << d.name << "\" "
- << d.geometry.width() << 'x' << d.geometry.height() << '+' << d.geometry.x() << '+' << d.geometry.y()
- << " avail: "
- << d.availableGeometry.width() << 'x' << d.availableGeometry.height() << '+' << d.availableGeometry.x() << '+' << d.availableGeometry.y()
- << " physical: " << d.physicalSizeMM.width() << 'x' << d.physicalSizeMM.height()
- << " DPI: " << d.dpi.first << 'x' << d.dpi.second << " Depth: " << d.depth
- << " Format: " << d.format
- << " hMonitor: " << d.hMonitor
- << " device name: " << d.deviceName;
+ dbg << "Screen \"" << d.name << "\" " << d.geometry.width() << 'x' << d.geometry.height() << '+'
+ << d.geometry.x() << '+' << d.geometry.y() << " avail: " << d.availableGeometry.width()
+ << 'x' << d.availableGeometry.height() << '+' << d.availableGeometry.x() << '+'
+ << d.availableGeometry.y() << " physical: " << d.physicalSizeMM.width() << 'x'
+ << d.physicalSizeMM.height() << " DPI: " << d.dpi.first << 'x' << d.dpi.second
+ << " Depth: " << d.depth << " Format: " << d.format << " hMonitor: " << d.hMonitor
+ << " device name: " << d.deviceName << " manufacturer: " << d.manufacturer
+ << " model: " << d.model << " serial number: " << d.serialNumber;
if (d.flags & QWindowsScreenData::PrimaryScreen)
dbg << " primary";
if (d.flags & QWindowsScreenData::VirtualDesktop)
@@ -390,10 +536,14 @@ void QWindowsScreen::handleChanges(const QWindowsScreenData &newData)
const bool dpiChanged = !qFuzzyCompare(m_data.dpi.first, newData.dpi.first)
|| !qFuzzyCompare(m_data.dpi.second, newData.dpi.second);
const bool orientationChanged = m_data.orientation != newData.orientation;
+ const bool primaryChanged = (newData.flags & QWindowsScreenData::PrimaryScreen)
+ && !(m_data.flags & QWindowsScreenData::PrimaryScreen);
m_data.dpi = newData.dpi;
m_data.orientation = newData.orientation;
m_data.geometry = newData.geometry;
m_data.availableGeometry = newData.availableGeometry;
+ m_data.flags = (m_data.flags & ~QWindowsScreenData::PrimaryScreen)
+ | (newData.flags & QWindowsScreenData::PrimaryScreen);
if (dpiChanged) {
QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen(),
@@ -406,6 +556,8 @@ void QWindowsScreen::handleChanges(const QWindowsScreenData &newData)
QWindowSystemInterface::handleScreenGeometryChange(screen(),
newData.geometry, newData.availableGeometry);
}
+ if (primaryChanged)
+ QWindowSystemInterface::handlePrimaryScreenChanged(this);
}
HMONITOR QWindowsScreen::handle() const
@@ -517,7 +669,8 @@ extern "C" LRESULT QT_WIN_CALLBACK qDisplayChangeObserverWndProc(HWND hwnd, UINT
if (QWindowsTheme *t = QWindowsTheme::instance())
t->displayChanged();
QWindowsWindow::displayChanged();
- QWindowsContext::instance()->screenManager().handleScreenChanges();
+ if (auto *context = QWindowsContext::instance())
+ context->screenManager().handleScreenChanges();
}
return DefWindowProc(hwnd, message, wParam, lParam);
diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h
index b1c94d2204..0467ab2a0c 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.h
+++ b/src/plugins/platforms/windows/qwindowsscreen.h
@@ -7,10 +7,9 @@
#include "qtwindowsglobal.h"
#include <QtCore/qlist.h>
-#include <QtCore/qpair.h>
#include <QtCore/qscopedpointer.h>
#include <qpa/qplatformscreen.h>
-#include <qpa/qplatformscreen_p.h>
+#include <QtGui/qscreen_platform.h>
QT_BEGIN_NAMESPACE
@@ -31,15 +30,18 @@ struct QWindowsScreenData
QImage::Format format = QImage::Format_ARGB32_Premultiplied;
unsigned flags = VirtualDesktop;
QString name;
+ QString manufacturer;
+ QString model;
+ QString serialNumber;
Qt::ScreenOrientation orientation = Qt::LandscapeOrientation;
qreal refreshRateHz = 60;
HMONITOR hMonitor = nullptr;
- QString deviceName = {};
+ QString deviceName;
+ QString devicePath;
std::optional<int> deviceIndex = std::nullopt;
};
-class QWindowsScreen : public QPlatformScreen
- , public QNativeInterface::Private::QWindowsScreen
+class QWindowsScreen : public QPlatformScreen, public QNativeInterface::QWindowsScreen
{
public:
#ifndef QT_NO_CURSOR
@@ -58,6 +60,9 @@ public:
qreal devicePixelRatio() const override { return 1.0; }
qreal refreshRate() const override { return m_data.refreshRateHz; }
QString name() const override;
+ QString manufacturer() const override { return m_data.manufacturer; }
+ QString model() const override { return m_data.model; }
+ QString serialNumber() const override { return m_data.serialNumber; }
Qt::ScreenOrientation orientation() const override { return m_data.orientation; }
QList<QPlatformScreen *> virtualSiblings() const override;
QWindow *topLevelAt(const QPoint &point) const override;
diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp
index d9bb76d10a..89f93fd161 100644
--- a/src/plugins/platforms/windows/qwindowsservices.cpp
+++ b/src/plugins/platforms/windows/qwindowsservices.cpp
@@ -154,10 +154,15 @@ static inline bool launchMail(const QUrl &url)
qWarning("Cannot launch '%ls': There is no mail program installed.", qUtf16Printable(url.toString()));
return false;
}
+ // Fix mail launch if no param is expected in this command.
+ if (command.indexOf("%1"_L1) < 0) {
+ qWarning() << "The mail command lacks the '%1' parameter.";
+ return false;
+ }
//Make sure the path for the process is in quotes
const QChar doubleQuote = u'"';
if (!command.startsWith(doubleQuote)) {
- const int exeIndex = command.indexOf(QStringLiteral(".exe "), 0, Qt::CaseInsensitive);
+ const int exeIndex = command.indexOf(".exe "_L1, 0, Qt::CaseInsensitive);
if (exeIndex != -1) {
command.insert(exeIndex + 4, doubleQuote);
command.prepend(doubleQuote);
diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
index 3bad237f9e..6f0680ac23 100644
--- a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
+++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
@@ -24,6 +24,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::Literals::StringLiterals;
+
static const UINT q_uNOTIFYICONID = 0;
static uint MYWM_TASKBARCREATED = 0;
@@ -116,7 +118,7 @@ static inline HWND createTrayIconMessageWindow()
return nullptr;
// Register window class in the platform plugin.
const QString className =
- ctx->registerWindowClass(QWindowsContext::classNamePrefix() + QStringLiteral("TrayIconMessageWindowClass"),
+ ctx->registerWindowClass(QWindowsContext::classNamePrefix() + "TrayIconMessageWindowClass"_L1,
qWindowsTrayIconWndProc);
const wchar_t windowName[] = L"QTrayIconMessageWindow";
return CreateWindowEx(0, reinterpret_cast<const wchar_t *>(className.utf16()),
@@ -162,8 +164,6 @@ void QWindowsSystemTrayIcon::cleanup()
void QWindowsSystemTrayIcon::updateIcon(const QIcon &icon)
{
qCDebug(lcQpaTrayIcon) << __FUNCTION__ << '(' << icon << ')' << this;
- if (icon.cacheKey() == m_icon.cacheKey())
- return;
m_icon = icon;
const HICON hIconToDestroy = createIcon(icon);
if (ensureInstalled())
@@ -184,6 +184,9 @@ void QWindowsSystemTrayIcon::updateToolTip(const QString &tooltip)
QRect QWindowsSystemTrayIcon::geometry() const
{
+ if (!isIconVisible())
+ return QRect();
+
NOTIFYICONIDENTIFIER nid;
memset(&nid, 0, sizeof(nid));
nid.cbSize = sizeof(nid);
@@ -217,25 +220,19 @@ void QWindowsSystemTrayIcon::showMessage(const QString &title, const QString &me
qStringToLimitedWCharArray(title, tnd.szInfoTitle, 64);
tnd.uID = q_uNOTIFYICONID;
- tnd.dwInfoFlags = NIIF_USER;
-
- QSize size(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
- const QSize largeIcon(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
- const 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;
- }
+
+ const auto size = icon.actualSize(QSize(256, 256));
QPixmap pm = icon.pixmap(size);
+ if (m_hMessageIcon) {
+ DestroyIcon(m_hMessageIcon);
+ m_hMessageIcon = nullptr;
+ }
if (pm.isNull()) {
tnd.dwInfoFlags = NIIF_INFO;
} 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);
- }
- tnd.hBalloonIcon = qt_pixmapToWinHICON(pm);
+ tnd.dwInfoFlags = NIIF_USER | NIIF_LARGE_ICON;
+ m_hMessageIcon = qt_pixmapToWinHICON(pm);
+ tnd.hBalloonIcon = m_hMessageIcon;
}
tnd.hWnd = m_hwnd;
tnd.uTimeout = msecsIn <= 0 ? UINT(10000) : UINT(msecsIn); // 10s default
@@ -293,7 +290,10 @@ void QWindowsSystemTrayIcon::ensureCleanup()
}
if (m_hIcon != nullptr)
DestroyIcon(m_hIcon);
+ if (m_hMessageIcon != nullptr)
+ DestroyIcon(m_hMessageIcon);
m_hIcon = nullptr;
+ m_hMessageIcon = nullptr;
m_menu = nullptr; // externally owned
m_toolTip.clear();
}
@@ -310,6 +310,29 @@ bool QWindowsSystemTrayIcon::setIconVisible(bool visible)
return Shell_NotifyIcon(NIM_MODIFY, &tnd) == TRUE;
}
+bool QWindowsSystemTrayIcon::isIconVisible() const
+{
+ NOTIFYICONIDENTIFIER nid;
+ memset(&nid, 0, sizeof(nid));
+ nid.cbSize = sizeof(nid);
+ nid.hWnd = m_hwnd;
+ nid.uID = q_uNOTIFYICONID;
+ RECT rect;
+ const HRESULT hr = Shell_NotifyIconGetRect(&nid, &rect);
+ // Windows 10 returns S_FALSE if the icon is hidden
+ if (FAILED(hr) || hr == S_FALSE)
+ return false;
+
+ HMONITOR monitor = MonitorFromWindow(m_hwnd, MONITOR_DEFAULTTONEAREST);
+ MONITORINFO info;
+ info.cbSize = sizeof(MONITORINFO);
+ GetMonitorInfo(monitor, &info);
+ // Windows 11 seems to return a geometry outside of the current monitor's geometry in case of
+ // the icon being hidden. As it's impossible to change the alignment of the task bar on Windows
+ // 11 this check should be fine.
+ return rect.bottom <= info.rcMonitor.bottom;
+}
+
bool QWindowsSystemTrayIcon::sendTrayMessage(DWORD msg)
{
NOTIFYICONDATA tnd;
diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.h b/src/plugins/platforms/windows/qwindowssystemtrayicon.h
index 2545ae9101..3ad5feb125 100644
--- a/src/plugins/platforms/windows/qwindowssystemtrayicon.h
+++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.h
@@ -49,12 +49,14 @@ private:
void ensureCleanup();
bool sendTrayMessage(DWORD msg);
bool setIconVisible(bool visible);
+ bool isIconVisible() const;
HICON createIcon(const QIcon &icon);
QIcon m_icon;
QString m_toolTip;
HWND m_hwnd = nullptr;
HICON m_hIcon = nullptr;
+ HICON m_hMessageIcon = nullptr;
mutable QPointer<QWindowsPopupMenu> m_menu;
bool m_ignoreNextMouseRelease = false;
bool m_visible = false;
diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp
index b7cc2bf77b..ceebb483d2 100644
--- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp
+++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp
@@ -595,7 +595,8 @@ bool QWindowsTabletSupport::translateTabletPacketEvent()
<< "mode=" << m_mode;
}
- const Qt::KeyboardModifiers keyboardModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
+ const auto *keyMapper = QWindowsContext::instance()->keyMapper();
+ const Qt::KeyboardModifiers keyboardModifiers = keyMapper->queryKeyboardModifiers();
for (int i = 0; i < packetCount ; ++i) {
const PACKET &packet = localPacketBuf[i];
diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp
index 6fba9e55c1..e8a324aedb 100644
--- a/src/plugins/platforms/windows/qwindowstheme.cpp
+++ b/src/plugins/platforms/windows/qwindowstheme.cpp
@@ -7,26 +7,29 @@
#include "qwindowsmenu.h"
#include "qwindowsdialoghelpers.h"
#include "qwindowscontext.h"
+#include "qwindowsiconengine.h"
#include "qwindowsintegration.h"
#if QT_CONFIG(systemtrayicon)
# include "qwindowssystemtrayicon.h"
#endif
#include "qwindowsscreen.h"
+#include "qwindowswindow.h"
#include <commctrl.h>
#include <objbase.h>
-#ifndef Q_CC_MINGW
-# include <commoncontrols.h>
-#endif
+#include <commoncontrols.h>
#include <shellapi.h>
+#include <QtCore/qapplicationstatic.h>
#include <QtCore/qvariant.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qdebug.h>
#include <QtCore/qsysinfo.h>
#include <QtCore/qcache.h>
#include <QtCore/qthread.h>
+#include <QtCore/qqueue.h>
#include <QtCore/qmutex.h>
#include <QtCore/qwaitcondition.h>
+#include <QtCore/qoperatingsystemversion.h>
#include <QtGui/qcolor.h>
#include <QtGui/qpalette.h>
#include <QtGui/qguiapplication.h>
@@ -48,10 +51,6 @@
# include <winrt/Windows.UI.ViewManagement.h>
#endif // QT_CONFIG(cpp_winrt)
-#if defined(__IImageList_INTERFACE_DEFINED__) && defined(__IID_DEFINED__)
-# define USE_IIMAGELIST
-#endif
-
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
@@ -79,11 +78,11 @@ static inline QColor mixColors(const QColor &c1, const QColor &c2)
(c1.blue() + c2.blue()) / 2};
}
-static inline QColor getSysColor(int index)
-{
- COLORREF cr = GetSysColor(index);
- return QColor(GetRValue(cr), GetGValue(cr), GetBValue(cr));
-}
+enum AccentColorLevel {
+ AccentColorDarkest,
+ AccentColorNormal,
+ AccentColorLightest
+};
#if QT_CONFIG(cpp_winrt)
static constexpr QColor getSysColor(winrt::Windows::UI::Color &&color)
@@ -92,111 +91,146 @@ static constexpr QColor getSysColor(winrt::Windows::UI::Color &&color)
}
#endif
-// 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.
+[[maybe_unused]] [[nodiscard]] static inline QColor qt_accentColor(AccentColorLevel level)
+{
+#if QT_CONFIG(cpp_winrt)
+ using namespace winrt::Windows::UI::ViewManagement;
+ const auto settings = UISettings();
+ const QColor accent = getSysColor(settings.GetColorValue(UIColorType::Accent));
+ const QColor accentLight = getSysColor(settings.GetColorValue(UIColorType::AccentLight1));
+ const QColor accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3));
+#else
+ const QWinRegistryKey registry(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\DWM)");
+ if (!registry.isValid())
+ return {};
+ const QVariant value = registry.value(L"AccentColor");
+ if (!value.isValid())
+ return {};
+ // The retrieved value is in the #AABBGGRR format, we need to
+ // convert it to the #AARRGGBB format which Qt expects.
+ const QColor abgr = QColor::fromRgba(qvariant_cast<DWORD>(value));
+ if (!abgr.isValid())
+ return {};
+ const QColor accent = QColor::fromRgb(abgr.blue(), abgr.green(), abgr.red(), abgr.alpha());
+ const QColor accentLight = accent.lighter(120);
+ const QColor accentDarkest = accent.darker(120 * 120 * 120);
+#endif
+ if (level == AccentColorDarkest)
+ return accentDarkest;
+ else if (level == AccentColorLightest)
+ return accentLight;
+ return accent;
+}
-struct QShGetFileInfoParams
+static inline QColor getSysColor(int index)
{
- 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;
-};
+ COLORREF cr = GetSysColor(index);
+ return QColor(GetRValue(cr), GetGValue(cr), GetBValue(cr));
+}
+// 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 QShGetFileInfoThread : public QThread
{
public:
- explicit QShGetFileInfoThread()
- : QThread(), m_params(nullptr)
+ struct Task
{
- connect(this, &QThread::finished, this, &QObject::deleteLater);
+ Task(const QString &fn, DWORD a, UINT f)
+ : fileName(fn), attributes(a), flags(f)
+ {}
+ Q_DISABLE_COPY(Task)
+ ~Task()
+ {
+ DestroyIcon(hIcon);
+ hIcon = 0;
+ }
+ // Request
+ const QString fileName;
+ const DWORD attributes;
+ const UINT flags;
+ // Result
+ HICON hIcon = 0;
+ int iIcon = -1;
+ bool finished = false;
+ bool resultValid() const { return hIcon != 0 && iIcon >= 0 && finished; }
+ };
+
+ QShGetFileInfoThread()
+ : QThread()
+ {
+ start();
+ }
+
+ ~QShGetFileInfoThread()
+ {
+ cancel();
+ wait();
+ }
+
+ QSharedPointer<Task> getNextTask()
+ {
+ QMutexLocker l(&m_waitForTaskMutex);
+ while (!isInterruptionRequested()) {
+ if (!m_taskQueue.isEmpty())
+ return m_taskQueue.dequeue();
+ m_waitForTaskCondition.wait(&m_waitForTaskMutex);
+ }
+ return nullptr;
}
void run() override
{
QComHelper comHelper(COINIT_MULTITHREADED);
- QMutexLocker readyLocker(&m_readyMutex);
- while (!m_cancelled.loadRelaxed()) {
- if (!m_params && !m_cancelled.loadRelaxed()
- && !m_readyCondition.wait(&m_readyMutex, QDeadlineTimer(1000ll)))
- continue;
-
- if (m_params) {
- const QString fileName = m_params->fileName;
+ while (!isInterruptionRequested()) {
+ auto task = getNextTask();
+ if (task) {
SHFILEINFO info;
- const bool result = SHGetFileInfo(reinterpret_cast<const wchar_t *>(fileName.utf16()),
- m_params->attributes, &info, sizeof(SHFILEINFO),
- m_params->flags);
- m_doneMutex.lock();
- if (!m_cancelled.loadRelaxed()) {
- *m_params->result = result;
- memcpy(m_params->info, &info, sizeof(SHFILEINFO));
+ const bool result = SHGetFileInfo(reinterpret_cast<const wchar_t *>(task->fileName.utf16()),
+ task->attributes, &info, sizeof(SHFILEINFO),
+ task->flags);
+ if (result) {
+ task->hIcon = info.hIcon;
+ task->iIcon = info.iIcon;
}
- m_params = nullptr;
-
+ task->finished = true;
m_doneCondition.wakeAll();
- m_doneMutex.unlock();
}
}
}
- bool runWithParams(QShGetFileInfoParams *params, qint64 timeOutMSecs)
+ void runWithParams(const QSharedPointer<Task> &task,
+ std::chrono::milliseconds timeout = std::chrono::milliseconds(5000))
{
- QMutexLocker doneLocker(&m_doneMutex);
-
- m_readyMutex.lock();
- m_params = params;
- m_readyCondition.wakeAll();
- m_readyMutex.unlock();
+ {
+ QMutexLocker l(&m_waitForTaskMutex);
+ m_taskQueue.enqueue(task);
+ m_waitForTaskCondition.wakeAll();
+ }
- return m_doneCondition.wait(&m_doneMutex, QDeadlineTimer(timeOutMSecs));
+ QMutexLocker doneLocker(&m_doneMutex);
+ while (!task->finished && !isInterruptionRequested()) {
+ if (!m_doneCondition.wait(&m_doneMutex, QDeadlineTimer(timeout)))
+ return;
+ }
}
void cancel()
{
- QMutexLocker doneLocker(&m_doneMutex);
- m_cancelled.storeRelaxed(1);
- m_readyCondition.wakeAll();
+ requestInterruption();
+ m_doneCondition.wakeAll();
+ m_waitForTaskCondition.wakeAll();
}
private:
- QShGetFileInfoParams *m_params;
- QAtomicInt m_cancelled;
- QWaitCondition m_readyCondition;
+ QQueue<QSharedPointer<Task>> m_taskQueue;
QWaitCondition m_doneCondition;
- QMutex m_readyMutex;
+ QWaitCondition m_waitForTaskCondition;
QMutex m_doneMutex;
+ QMutex m_waitForTaskMutex;
};
-
-static bool shGetFileInfoBackground(const QString &fileName, DWORD attributes,
- SHFILEINFO *info, UINT flags,
- qint64 timeOutMSecs = 5000)
-{
- static QShGetFileInfoThread *getFileInfoThread = nullptr;
- if (!getFileInfoThread) {
- getFileInfoThread = new QShGetFileInfoThread;
- getFileInfoThread->start();
- }
-
- bool result = false;
- 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;
-}
+Q_APPLICATION_STATIC(QShGetFileInfoThread, s_shGetFileInfoThread)
// from QStyle::standardPalette
static inline QPalette standardPalette()
@@ -227,22 +261,17 @@ static QColor placeHolderColor(QColor textColor)
*/
void QWindowsTheme::populateLightSystemBasePalette(QPalette &result)
{
- QColor background = getSysColor(COLOR_BTNFACE);
- QColor textColor = getSysColor(COLOR_WINDOWTEXT);
- QColor accent = getSysColor(COLOR_HIGHLIGHT);
+ const QColor background = getSysColor(COLOR_BTNFACE);
+ const QColor textColor = getSysColor(COLOR_WINDOWTEXT);
-#if QT_CONFIG(cpp_winrt)
- // respect the Windows 11 accent color
- using namespace winrt::Windows::UI::ViewManagement;
- const auto settings = UISettings();
-
- accent = getSysColor(settings.GetColorValue(UIColorType::Accent));
-#endif
+ const QColor accent = qt_accentColor(AccentColorNormal);
+ const QColor accentDarkest = qt_accentColor(AccentColorDarkest);
+ const QColor linkColor = accent;
const QColor btnFace = background;
const QColor btnHighlight = getSysColor(COLOR_BTNHIGHLIGHT);
- result.setColor(QPalette::Highlight, accent);
+ result.setColor(QPalette::Highlight, getSysColor(COLOR_HIGHLIGHT));
result.setColor(QPalette::WindowText, getSysColor(COLOR_WINDOWTEXT));
result.setColor(QPalette::Button, btnFace);
result.setColor(QPalette::Light, btnHighlight);
@@ -257,9 +286,10 @@ void QWindowsTheme::populateLightSystemBasePalette(QPalette &result)
result.setColor(QPalette::Midlight, getSysColor(COLOR_3DLIGHT));
result.setColor(QPalette::Shadow, getSysColor(COLOR_3DDKSHADOW));
result.setColor(QPalette::HighlightedText, getSysColor(COLOR_HIGHLIGHTTEXT));
+ result.setColor(QPalette::Accent, accent);
- result.setColor(QPalette::Link, Qt::blue);
- result.setColor(QPalette::LinkVisited, Qt::magenta);
+ result.setColor(QPalette::Link, linkColor);
+ result.setColor(QPalette::LinkVisited, accentDarkest);
result.setColor(QPalette::Inactive, QPalette::Button, result.button().color());
result.setColor(QPalette::Inactive, QPalette::Window, result.window().color());
result.setColor(QPalette::Inactive, QPalette::Light, result.light().color());
@@ -269,7 +299,7 @@ void QWindowsTheme::populateLightSystemBasePalette(QPalette &result)
result.setColor(QPalette::Midlight, result.button().color().lighter(110));
}
-static void populateDarkSystemBasePalette(QPalette &result)
+void QWindowsTheme::populateDarkSystemBasePalette(QPalette &result)
{
#if QT_CONFIG(cpp_winrt)
using namespace winrt::Windows::UI::ViewManagement;
@@ -293,19 +323,18 @@ static void populateDarkSystemBasePalette(QPalette &result)
const QColor accentLight = getSysColor(settings.GetColorValue(UIColorType::AccentLight1));
const QColor accentLighter = getSysColor(settings.GetColorValue(UIColorType::AccentLight2));
const QColor accentLightest = getSysColor(settings.GetColorValue(UIColorType::AccentLight3));
- const QColor linkColor = accent;
#else
const QColor foreground = Qt::white;
const QColor background = QColor(0x1E, 0x1E, 0x1E);
- const QColor accent = QColor(0x00, 0x55, 0xff);
+ const QColor accent = qt_accentColor(AccentColorNormal);
const QColor accentDark = accent.darker(120);
const QColor accentDarker = accentDark.darker(120);
const QColor accentDarkest = accentDarker.darker(120);
const QColor accentLight = accent.lighter(120);
const QColor accentLighter = accentLight.lighter(120);
const QColor accentLightest = accentLighter.lighter(120);
- const QColor linkColor = Qt::blue;
#endif
+ const QColor linkColor = accent;
const QColor buttonColor = background.lighter(200);
result.setColor(QPalette::All, QPalette::WindowText, foreground);
@@ -331,36 +360,7 @@ static void populateDarkSystemBasePalette(QPalette &result)
result.setColor(QPalette::All, QPalette::ToolTipBase, buttonColor);
result.setColor(QPalette::All, QPalette::ToolTipText, foreground.darker(120));
result.setColor(QPalette::All, QPalette::PlaceholderText, placeHolderColor(foreground));
-}
-
-static QPalette systemPalette(bool light)
-{
- QPalette result = standardPalette();
- if (light)
- QWindowsTheme::populateLightSystemBasePalette(result);
- else
- populateDarkSystemBasePalette(result);
-
- if (result.window() != result.base()) {
- result.setColor(QPalette::Inactive, QPalette::Highlight,
- result.color(QPalette::Inactive, QPalette::Window));
- result.setColor(QPalette::Inactive, QPalette::HighlightedText,
- result.color(QPalette::Inactive, QPalette::Text));
- }
-
- const QColor disabled = mixColors(result.windowText().color(), result.button().color());
-
- result.setColorGroup(QPalette::Disabled, result.windowText(), result.button(),
- result.light(), result.dark(), result.mid(),
- result.text(), result.brightText(), result.base(),
- result.window());
- result.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
- result.setColor(QPalette::Disabled, QPalette::Text, disabled);
- result.setColor(QPalette::Disabled, QPalette::ButtonText, disabled);
- result.setColor(QPalette::Disabled, QPalette::Highlight, result.color(QPalette::Highlight));
- result.setColor(QPalette::Disabled, QPalette::HighlightedText, result.color(QPalette::HighlightedText));
- result.setColor(QPalette::Disabled, QPalette::Base, result.window().color());
- return result;
+ result.setColor(QPalette::All, QPalette::Accent, accent);
}
static inline QPalette toolTipPalette(const QPalette &systemPalette, bool light)
@@ -452,6 +452,7 @@ QWindowsTheme *QWindowsTheme::m_instance = nullptr;
QWindowsTheme::QWindowsTheme()
{
m_instance = this;
+ s_colorScheme = QWindowsTheme::queryColorScheme();
std::fill(m_fonts, m_fonts + NFonts, nullptr);
std::fill(m_palettes, m_palettes + NPalettes, nullptr);
refresh();
@@ -473,7 +474,10 @@ static inline QStringList iconThemeSearchPaths()
static inline QStringList styleNames()
{
- return { QStringLiteral("WindowsVista"), QStringLiteral("Windows") };
+ QStringList styles = { QStringLiteral("WindowsVista"), QStringLiteral("Windows") };
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows11)
+ styles.prepend(QStringLiteral("Windows11"));
+ return styles;
}
static inline int uiEffects()
@@ -538,7 +542,31 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const
Qt::ColorScheme QWindowsTheme::colorScheme() const
{
- return QWindowsContext::isDarkMode() ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light;
+ return QWindowsTheme::effectiveColorScheme();
+}
+
+Qt::ColorScheme QWindowsTheme::effectiveColorScheme()
+{
+ if (queryHighContrast())
+ return Qt::ColorScheme::Unknown;
+ return s_colorScheme;
+}
+
+void QWindowsTheme::handleSettingsChanged()
+{
+ const auto newColorScheme = QWindowsTheme::queryColorScheme();
+ const bool colorSchemeChanged = newColorScheme != QWindowsTheme::s_colorScheme;
+ s_colorScheme = newColorScheme;
+ auto integration = QWindowsIntegration::instance();
+ integration->updateApplicationBadge();
+ if (integration->darkModeHandling().testFlag(QWindowsApplication::DarkModeStyle)) {
+ QWindowsTheme::instance()->refresh();
+ QWindowSystemInterface::handleThemeChange<QWindowSystemInterface::SynchronousDelivery>();
+ }
+ if (colorSchemeChanged) {
+ for (QWindowsWindow *w : std::as_const(QWindowsContext::instance()->windows()))
+ w->setDarkBorder(s_colorScheme == Qt::ColorScheme::Dark);
+ }
}
void QWindowsTheme::clearPalettes()
@@ -549,41 +577,66 @@ void QWindowsTheme::clearPalettes()
void QWindowsTheme::refreshPalettes()
{
-
if (!QGuiApplication::desktopSettingsAware())
return;
const bool light =
- !QWindowsContext::isDarkMode()
+ effectiveColorScheme() != Qt::ColorScheme::Dark
|| !QWindowsIntegration::instance()->darkModeHandling().testFlag(QWindowsApplication::DarkModeStyle);
clearPalettes();
- m_palettes[SystemPalette] = new QPalette(systemPalette(light));
+ m_palettes[SystemPalette] = new QPalette(QWindowsTheme::systemPalette(s_colorScheme));
m_palettes[ToolTipPalette] = new QPalette(toolTipPalette(*m_palettes[SystemPalette], light));
m_palettes[MenuPalette] = new QPalette(menuPalette(*m_palettes[SystemPalette], light));
m_palettes[MenuBarPalette] = menuBarPalette(*m_palettes[MenuPalette], light);
if (!light) {
-#if QT_CONFIG(cpp_winrt)
- using namespace winrt::Windows::UI::ViewManagement;
- const auto settings = UISettings();
- const QColor accent = getSysColor(settings.GetColorValue(UIColorType::Accent));
- const QColor accentLight = getSysColor(settings.GetColorValue(UIColorType::AccentLight1));
- const QColor accentDarkest = getSysColor(settings.GetColorValue(UIColorType::AccentDark3));
- m_palettes[CheckBoxPalette] = new QPalette(*m_palettes[SystemPalette]);
- m_palettes[CheckBoxPalette]->setColor(QPalette::Active, QPalette::Base, accent);
- m_palettes[CheckBoxPalette]->setColor(QPalette::Active, QPalette::Button, accentLight);
- m_palettes[CheckBoxPalette]->setColor(QPalette::Inactive, QPalette::Base, accentDarkest);
-#else
- m_palettes[ButtonPalette] = new QPalette(*m_palettes[SystemPalette]);
- m_palettes[ButtonPalette]->setColor(QPalette::Button, QColor(0x666666u));
- const QColor checkBoxBlue(0x0078d7u);
m_palettes[CheckBoxPalette] = new QPalette(*m_palettes[SystemPalette]);
- m_palettes[CheckBoxPalette]->setColor(QPalette::Base, checkBoxBlue);
- m_palettes[CheckBoxPalette]->setColor(QPalette::Button, checkBoxBlue);
- m_palettes[CheckBoxPalette]->setColor(QPalette::ButtonText, Qt::white);
-#endif
+ m_palettes[CheckBoxPalette]->setColor(QPalette::Active, QPalette::Base, qt_accentColor(AccentColorNormal));
+ m_palettes[CheckBoxPalette]->setColor(QPalette::Active, QPalette::Button, qt_accentColor(AccentColorLightest));
+ m_palettes[CheckBoxPalette]->setColor(QPalette::Inactive, QPalette::Base, qt_accentColor(AccentColorDarkest));
m_palettes[RadioButtonPalette] = new QPalette(*m_palettes[CheckBoxPalette]);
}
}
+QPalette QWindowsTheme::systemPalette(Qt::ColorScheme colorScheme)
+{
+ QPalette result = standardPalette();
+
+ switch (colorScheme) {
+ case Qt::ColorScheme::Unknown:
+ // when a high-contrast theme is active or when we fail to read, assume light
+ Q_FALLTHROUGH();
+ case Qt::ColorScheme::Light:
+ populateLightSystemBasePalette(result);
+ break;
+ case Qt::ColorScheme::Dark:
+ populateDarkSystemBasePalette(result);
+ break;
+ }
+
+ if (result.window() != result.base()) {
+ result.setColor(QPalette::Inactive, QPalette::Highlight,
+ result.color(QPalette::Inactive, QPalette::Window));
+ result.setColor(QPalette::Inactive, QPalette::HighlightedText,
+ result.color(QPalette::Inactive, QPalette::Text));
+ result.setColor(QPalette::Inactive, QPalette::Accent,
+ result.color(QPalette::Inactive, QPalette::Window));
+ }
+
+ const QColor disabled = mixColors(result.windowText().color(), result.button().color());
+
+ result.setColorGroup(QPalette::Disabled, result.windowText(), result.button(),
+ result.light(), result.dark(), result.mid(),
+ result.text(), result.brightText(), result.base(),
+ result.window());
+ result.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
+ result.setColor(QPalette::Disabled, QPalette::Text, disabled);
+ result.setColor(QPalette::Disabled, QPalette::ButtonText, disabled);
+ result.setColor(QPalette::Disabled, QPalette::Highlight, result.color(QPalette::Highlight));
+ result.setColor(QPalette::Disabled, QPalette::HighlightedText, result.color(QPalette::HighlightedText));
+ result.setColor(QPalette::Disabled, QPalette::Accent, disabled);
+ result.setColor(QPalette::Disabled, QPalette::Base, result.window().color());
+ return result;
+}
+
void QWindowsTheme::clearFonts()
{
qDeleteAll(m_fonts, m_fonts + NFonts);
@@ -695,11 +748,7 @@ void QWindowsTheme::refreshIconPixmapSizes()
fileIconSizes[LargeFileIcon] + fileIconSizes[LargeFileIcon] / 2;
fileIconSizes[JumboFileIcon] = 8 * fileIconSizes[LargeFileIcon]; // empirical, has not been observed to work
-#ifdef USE_IIMAGELIST
int *availEnd = fileIconSizes + JumboFileIcon + 1;
-#else
- int *availEnd = fileIconSizes + LargeFileIcon + 1;
-#endif // USE_IIMAGELIST
m_fileIconSizes = QAbstractFileIconEngine::toSizeList(fileIconSizes, availEnd);
qCDebug(lcQpaWindow) << __FUNCTION__ << m_fileIconSizes;
}
@@ -812,15 +861,18 @@ QPixmap QWindowsTheme::standardPixmap(StandardPixmap sp, const QSizeF &pixmapSiz
}
if (stockId != SIID_INVALID) {
- QPixmap pixmap;
SHSTOCKICONINFO iconInfo;
memset(&iconInfo, 0, sizeof(iconInfo));
iconInfo.cbSize = sizeof(iconInfo);
- stockFlags |= (pixmapSize.width() > 16 ? SHGFI_LARGEICON : SHGFI_SMALLICON);
- if (SHGetStockIconInfo(stockId, SHGFI_ICON | stockFlags, &iconInfo) == S_OK) {
- pixmap = qt_pixmapFromWinHICON(iconInfo.hIcon);
- DestroyIcon(iconInfo.hIcon);
- return pixmap;
+ stockFlags |= SHGSI_ICONLOCATION;
+ if (SHGetStockIconInfo(stockId, stockFlags, &iconInfo) == S_OK) {
+ const auto iconSize = pixmapSize.width();
+ HICON icon;
+ if (SHDefExtractIcon(iconInfo.szPath, iconInfo.iIcon, 0, &icon, nullptr, iconSize) == S_OK) {
+ QPixmap pixmap = qt_pixmapFromWinHICON(icon);
+ DestroyIcon(icon);
+ return pixmap;
+ }
}
}
@@ -890,10 +942,9 @@ public:
// Shell image list helper functions.
-static QPixmap pixmapFromShellImageList(int iImageList, const SHFILEINFO &info)
+static QPixmap pixmapFromShellImageList(int iImageList, int iIcon)
{
QPixmap result;
-#ifdef USE_IIMAGELIST
// For MinGW:
static const IID iID_IImageList = {0x46eb5926, 0x582e, 0x4017, {0x9f, 0xdf, 0xe8, 0x99, 0x8d, 0xaa, 0x9, 0x50}};
@@ -902,16 +953,12 @@ static QPixmap pixmapFromShellImageList(int iImageList, const SHFILEINFO &info)
if (hr != S_OK)
return result;
HICON hIcon;
- hr = imageList->GetIcon(info.iIcon, ILD_TRANSPARENT, &hIcon);
+ hr = imageList->GetIcon(iIcon, ILD_TRANSPARENT, &hIcon);
if (hr == S_OK) {
result = qt_pixmapFromWinHICON(hIcon);
DestroyIcon(hIcon);
}
imageList->Release();
-#else
- Q_UNUSED(iImageList);
- Q_UNUSED(info);
-#endif // USE_IIMAGELIST
return result;
}
@@ -963,13 +1010,9 @@ QPixmap QWindowsFileIconEngine::filePixmap(const QSize &size, QIcon::Mode, QIcon
const int width = int(size.width());
const int iconSize = width > fileIconSizes[SmallFileIcon] ? SHGFI_LARGEICON : SHGFI_SMALLICON;
const int requestedImageListSize =
-#ifdef USE_IIMAGELIST
width > fileIconSizes[ExtraLargeFileIcon]
? sHIL_JUMBO
: (width > fileIconSizes[LargeFileIcon] ? sHIL_EXTRALARGE : 0);
-#else
- 0;
-#endif // !USE_IIMAGELIST
bool cacheableDirIcon = fileInfo().isDir() && !fileInfo().isRoot();
if (cacheableDirIcon) {
QMutexLocker locker(&mx);
@@ -985,7 +1028,6 @@ QPixmap QWindowsFileIconEngine::filePixmap(const QSize &size, QIcon::Mode, QIcon
}
}
- SHFILEINFO info;
unsigned int flags = SHGFI_ICON | iconSize | SHGFI_SYSICONINDEX | SHGFI_ADDOVERLAYS | SHGFI_OVERLAYINDEX;
DWORD attributes = 0;
QString path = filePath;
@@ -997,43 +1039,43 @@ QPixmap QWindowsFileIconEngine::filePixmap(const QSize &size, QIcon::Mode, QIcon
flags |= SHGFI_USEFILEATTRIBUTES;
attributes |= FILE_ATTRIBUTE_NORMAL;
}
- const bool val = shGetFileInfoBackground(path, attributes, &info, flags);
-
+ auto task = QSharedPointer<QShGetFileInfoThread::Task>(
+ new QShGetFileInfoThread::Task(path, attributes, flags));
+ s_shGetFileInfoThread()->runWithParams(task);
// Even if GetFileInfo returns a valid result, hIcon can be empty in some cases
- if (val && info.hIcon) {
+ if (task->resultValid()) {
QString key;
if (cacheableDirIcon) {
if (useDefaultFolderIcon && defaultFolderIIcon < 0)
- defaultFolderIIcon = info.iIcon;
+ defaultFolderIIcon = task->iIcon;
//using the unique icon index provided by windows save us from duplicate keys
- key = dirIconPixmapCacheKey(info.iIcon, iconSize, requestedImageListSize);
+ key = dirIconPixmapCacheKey(task->iIcon, iconSize, requestedImageListSize);
QPixmapCache::find(key, &pixmap);
if (!pixmap.isNull()) {
QMutexLocker locker(&mx);
- dirIconEntryCache.insert(filePath, FakePointer<int>::create(info.iIcon));
+ dirIconEntryCache.insert(filePath, FakePointer<int>::create(task->iIcon));
}
}
if (pixmap.isNull()) {
if (requestedImageListSize) {
- pixmap = pixmapFromShellImageList(requestedImageListSize, info);
+ pixmap = pixmapFromShellImageList(requestedImageListSize, task->iIcon);
if (pixmap.isNull() && requestedImageListSize == sHIL_JUMBO)
- pixmap = pixmapFromShellImageList(sHIL_EXTRALARGE, info);
+ pixmap = pixmapFromShellImageList(sHIL_EXTRALARGE, task->iIcon);
}
if (pixmap.isNull())
- pixmap = qt_pixmapFromWinHICON(info.hIcon);
+ pixmap = qt_pixmapFromWinHICON(task->hIcon);
if (!pixmap.isNull()) {
if (cacheableDirIcon) {
QMutexLocker locker(&mx);
QPixmapCache::insert(key, pixmap);
- dirIconEntryCache.insert(filePath, FakePointer<int>::create(info.iIcon));
+ dirIconEntryCache.insert(filePath, FakePointer<int>::create(task->iIcon));
}
} else {
qWarning("QWindowsTheme::fileIconPixmap() no icon found");
}
}
- DestroyIcon(info.hIcon);
}
return pixmap;
@@ -1044,6 +1086,11 @@ QIcon QWindowsTheme::fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOpt
return QIcon(new QWindowsFileIconEngine(fileInfo, iconOptions));
}
+QIconEngine *QWindowsTheme::createIconEngine(const QString &iconName) const
+{
+ return new QWindowsIconEngine(iconName);
+}
+
static inline bool doUseNativeMenus()
{
const unsigned options = QWindowsIntegration::instance()->options();
@@ -1068,19 +1115,23 @@ bool QWindowsTheme::useNativeMenus()
return result;
}
-bool QWindowsTheme::queryDarkMode()
+Qt::ColorScheme QWindowsTheme::queryColorScheme()
{
- if (queryHighContrast()) {
- return false;
- }
+ if (queryHighContrast())
+ return Qt::ColorScheme::Unknown;
+
const auto setting = QWinRegistryKey(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)")
.dwordValue(L"AppsUseLightTheme");
- return setting.second && setting.first == 0;
+ return setting.second && setting.first == 0 ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light;
}
bool QWindowsTheme::queryHighContrast()
{
- return booleanSystemParametersInfo(SPI_GETHIGHCONTRAST, false);
+ HIGHCONTRAST hcf = {};
+ hcf.cbSize = static_cast<UINT>(sizeof(HIGHCONTRAST));
+ if (SystemParametersInfo(SPI_GETHIGHCONTRAST, hcf.cbSize, &hcf, FALSE))
+ return hcf.dwFlags & HCF_HIGHCONTRASTON;
+ return false;
}
QPlatformMenuItem *QWindowsTheme::createPlatformMenuItem() const
diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h
index 7f320da967..6109122944 100644
--- a/src/plugins/platforms/windows/qwindowstheme.h
+++ b/src/plugins/platforms/windows/qwindowstheme.h
@@ -33,6 +33,8 @@ public:
Qt::ColorScheme colorScheme() const override;
+ static void handleSettingsChanged();
+
const QPalette *palette(Palette type = SystemPalette) const override
{ return m_palettes[type]; }
const QFont *font(Font type = SystemFont) const override
@@ -41,6 +43,7 @@ public:
QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const override;
QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions = {}) const override;
+ QIconEngine *createIconEngine(const QString &iconName) const override;
void windowsThemeChanged(QWindow *window);
void displayChanged() { refreshIconPixmapSizes(); }
@@ -53,15 +56,13 @@ public:
void showPlatformMenuBar() override;
static bool useNativeMenus();
- static bool queryDarkMode();
- static bool queryHighContrast();
void refreshFonts();
void refresh();
static const char *name;
- static void populateLightSystemBasePalette(QPalette &result);
+ static QPalette systemPalette(Qt::ColorScheme);
private:
void clearPalettes();
@@ -69,7 +70,15 @@ private:
void clearFonts();
void refreshIconPixmapSizes();
+ static void populateLightSystemBasePalette(QPalette &result);
+ static void populateDarkSystemBasePalette(QPalette &result);
+
+ static Qt::ColorScheme queryColorScheme();
+ static Qt::ColorScheme effectiveColorScheme();
+ static bool queryHighContrast();
+
static QWindowsTheme *m_instance;
+ static inline Qt::ColorScheme s_colorScheme = Qt::ColorScheme::Unknown;
QPalette *m_palettes[NPalettes];
QFont *m_fonts[NFonts];
QList<QSize> m_fileIconSizes;
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index d0107145af..5d96d40af5 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -5,6 +5,7 @@
#include "qwindowswindow.h"
#include "qwindowscontext.h"
+#include "qwindowstheme.h"
#if QT_CONFIG(draganddrop)
# include "qwindowsdrag.h"
#endif
@@ -27,11 +28,11 @@
#include <QtGui/qwindow.h>
#include <QtGui/qregion.h>
#include <QtGui/qopenglcontext.h>
+#include <QtGui/private/qwindowsthemecache_p.h>
#include <private/qwindow_p.h> // QWINDOWSIZE_MAX
#include <private/qguiapplication_p.h>
#include <private/qhighdpiscaling_p.h>
#include <qpa/qwindowsysteminterface.h>
-#include <qpa/qplatformtheme.h>
#include <QtCore/qdebug.h>
#include <QtCore/qlibraryinfo.h>
@@ -430,11 +431,7 @@ static inline bool windowIsAccelerated(const QWindow *w)
{
switch (w->surfaceType()) {
case QSurface::OpenGLSurface:
- return true;
- case QSurface::RasterGLSurface:
- return qt_window_private(const_cast<QWindow *>(w))->compositing;
case QSurface::VulkanSurface:
- return true;
case QSurface::Direct3DSurface:
return true;
default:
@@ -469,14 +466,21 @@ static bool shouldShowMaximizeButton(const QWindow *w, Qt::WindowFlags flags)
w->maximumSize() == QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX);
}
+bool QWindowsWindow::hasNoNativeFrame(HWND hwnd, Qt::WindowFlags flags)
+{
+ const LONG_PTR style = GetWindowLongPtr(hwnd, GWL_STYLE);
+ return (style & WS_CHILD) || (flags & Qt::FramelessWindowHint);
+}
+
// Set the WS_EX_LAYERED flag on a HWND if required. This is required for
// translucent backgrounds, not fully opaque windows and for
// Qt::WindowTransparentForInput (in combination with WS_EX_TRANSPARENT).
bool QWindowsWindow::setWindowLayered(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, qreal opacity)
{
const LONG_PTR exStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
+ // Native children are frameless by nature, so check for that as well.
const bool needsLayered = (flags & Qt::WindowTransparentForInput)
- || (hasAlpha && (flags & Qt::FramelessWindowHint)) || opacity < 1.0;
+ || (hasAlpha && hasNoNativeFrame(hwnd, flags)) || opacity < 1.0;
const bool isLayered = (exStyle & WS_EX_LAYERED);
if (needsLayered != isLayered) {
if (needsLayered) {
@@ -492,7 +496,7 @@ static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, bo
{
if (QWindowsWindow::setWindowLayered(hwnd, flags, hasAlpha, level)) {
const BYTE alpha = BYTE(qRound(255.0 * level));
- if (hasAlpha && !accelerated && (flags & Qt::FramelessWindowHint)) {
+ if (hasAlpha && !accelerated && QWindowsWindow::hasNoNativeFrame(hwnd, flags)) {
// Non-GL windows with alpha: Use blend function to update.
BLENDFUNCTION blend = {AC_SRC_OVER, 0, alpha, AC_SRC_ALPHA};
UpdateLayeredWindow(hwnd, nullptr, nullptr, nullptr, nullptr, nullptr, 0, &blend, ULW_ALPHA);
@@ -835,6 +839,10 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag
// NOTE: WS_EX_TRANSPARENT flag can make mouse inputs fall through a layered window
if (flagsIn & Qt::WindowTransparentForInput)
exStyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT;
+
+ // Currently only compatible with D3D surfaces, use it with care.
+ if (qEnvironmentVariableIntValue("QT_QPA_DISABLE_REDIRECTION_SURFACE"))
+ exStyle |= WS_EX_NOREDIRECTIONBITMAP;
}
}
@@ -922,7 +930,7 @@ QWindowsWindowData
return result;
}
- if (QWindowsContext::isDarkMode() && shouldApplyDarkFrame(w))
+ if (QWindowsTheme::instance()->colorScheme() == Qt::ColorScheme::Dark && shouldApplyDarkFrame(w))
QWindowsWindow::setDarkBorderToWindow(result.hwnd, true);
if (mirrorParentWidth != 0) {
@@ -933,6 +941,7 @@ QWindowsWindowData
QRect obtainedGeometry(context->obtainedPos, context->obtainedSize);
result.geometry = obtainedGeometry;
+ result.restoreGeometry = frameGeometry(result.hwnd, topLevel);
result.fullFrameMargins = context->margins;
result.embedded = embedded;
result.hasFrame = hasFrame;
@@ -1007,6 +1016,21 @@ static QSize toNativeSizeConstrained(QSize dip, const QScreen *s)
return dip;
}
+// Helper for checking if frame adjustment needs to be skipped
+// NOTE: Unmaximized frameless windows will skip margins calculation
+static bool shouldOmitFrameAdjustment(const Qt::WindowFlags flags, DWORD style)
+{
+ return flags.testFlag(Qt::FramelessWindowHint) && !(style & WS_MAXIMIZE);
+}
+
+// Helper for checking if frame adjustment needs to be skipped
+// NOTE: Unmaximized frameless windows will skip margins calculation
+static bool shouldOmitFrameAdjustment(const Qt::WindowFlags flags, HWND hwnd)
+{
+ DWORD style = hwnd != nullptr ? DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)) : 0;
+ return flags.testFlag(Qt::FramelessWindowHint) && !(style & WS_MAXIMIZE);
+}
+
/*!
\class QWindowsGeometryHint
\brief Stores geometry constraints and provides utility functions.
@@ -1019,7 +1043,7 @@ static QSize toNativeSizeConstrained(QSize dip, const QScreen *s)
QMargins QWindowsGeometryHint::frameOnPrimaryScreen(const QWindow *w, DWORD style, DWORD exStyle)
{
- if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
+ if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style))
return {};
RECT rect = {0,0,0,0};
style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs.
@@ -1035,15 +1059,13 @@ QMargins QWindowsGeometryHint::frameOnPrimaryScreen(const QWindow *w, DWORD styl
QMargins QWindowsGeometryHint::frameOnPrimaryScreen(const QWindow *w, HWND hwnd)
{
- if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
- return {};
return frameOnPrimaryScreen(w, DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)),
DWORD(GetWindowLongPtr(hwnd, GWL_EXSTYLE)));
}
QMargins QWindowsGeometryHint::frame(const QWindow *w, DWORD style, DWORD exStyle, qreal dpi)
{
- if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
+ if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style))
return {};
RECT rect = {0,0,0,0};
style &= ~DWORD(WS_OVERLAPPED); // Not permitted, see docs.
@@ -1061,7 +1083,7 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, DWORD style, DWORD exStyl
QMargins QWindowsGeometryHint::frame(const QWindow *w, HWND hwnd, DWORD style, DWORD exStyle)
{
- if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
+ if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style))
return {};
if (QWindowsScreenManager::isSingleScreen())
return frameOnPrimaryScreen(w, style, exStyle);
@@ -1075,8 +1097,6 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, HWND hwnd, DWORD style, D
QMargins QWindowsGeometryHint::frame(const QWindow *w, HWND hwnd)
{
- if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
- return {};
return frame(w, hwnd, DWORD(GetWindowLongPtr(hwnd, GWL_STYLE)),
DWORD(GetWindowLongPtr(hwnd, GWL_EXSTYLE)));
}
@@ -1085,7 +1105,7 @@ QMargins QWindowsGeometryHint::frame(const QWindow *w, HWND hwnd)
QMargins QWindowsGeometryHint::frame(const QWindow *w, const QRect &geometry,
DWORD style, DWORD exStyle)
{
- if (!w->isTopLevel() || w->flags().testFlag(Qt::FramelessWindowHint))
+ if (!w->isTopLevel() || shouldOmitFrameAdjustment(w->flags(), style))
return {};
if (QWindowsScreenManager::isSingleScreen()
|| !QWindowsContext::shouldHaveNonClientDpiScaling(w)) {
@@ -1338,6 +1358,8 @@ QWindowsForeignWindow::QWindowsForeignWindow(QWindow *window, HWND hwnd)
, m_hwnd(hwnd)
, m_topLevelStyle(0)
{
+ if (QPlatformWindow::parent())
+ setParent(QPlatformWindow::parent());
}
void QWindowsForeignWindow::setParent(const QPlatformWindow *newParentWindow)
@@ -1513,6 +1535,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data)
QWindowsWindow::~QWindowsWindow()
{
setFlag(WithinDestroy);
+ QWindowsThemeCache::clearThemeCache(m_data.hwnd);
if (testFlag(TouchRegistered))
UnregisterTouchWindow(m_data.hwnd);
destroyWindow();
@@ -1954,6 +1977,12 @@ void QWindowsWindow::handleCompositionSettingsChanged()
}
}
+qreal QWindowsWindow::dpiRelativeScale(const UINT dpi) const
+{
+ return QHighDpiScaling::roundScaleFactor(qreal(dpi) / QWindowsScreen::baseDpi) /
+ QHighDpiScaling::roundScaleFactor(qreal(savedDpi()) / QWindowsScreen::baseDpi);
+}
+
void QWindowsWindow::handleDpiScaledSize(WPARAM wParam, LPARAM lParam, LRESULT *result)
{
// We want to keep QWindow's device independent size constant across the
@@ -1961,10 +1990,9 @@ void QWindowsWindow::handleDpiScaledSize(WPARAM wParam, LPARAM lParam, LRESULT *
// by the change of DPI (e.g. 120 -> 144 = 1.2), also taking any scale
// factor rounding into account. The win32 window size includes the margins;
// add the margins for the new DPI to the window size.
- const int dpi = int(wParam);
- const qreal scale = QHighDpiScaling::roundScaleFactor(qreal(dpi) / QWindowsScreen::baseDpi) /
- QHighDpiScaling::roundScaleFactor(qreal(savedDpi()) / QWindowsScreen::baseDpi);
- const QMargins margins = QWindowsGeometryHint::frame(window(), style(), exStyle(), dpi);
+ const UINT dpi = UINT(wParam);
+ const qreal scale = dpiRelativeScale(dpi);
+ const QMargins margins = fullFrameMargins();
if (!(m_data.flags & Qt::FramelessWindowHint)) {
// We need to update the custom margins to match the current DPI, because
// we don't want our users manually hook into this message just to set a
@@ -1973,7 +2001,8 @@ void QWindowsWindow::handleDpiScaledSize(WPARAM wParam, LPARAM lParam, LRESULT *
// are currently doing.
m_data.customMargins *= scale;
}
- const QSize windowSize = (geometry().size() * scale).grownBy(margins + customMargins());
+
+ const QSize windowSize = (geometry().size() * scale).grownBy((margins * scale) + customMargins());
SIZE *size = reinterpret_cast<SIZE *>(lParam);
size->cx = windowSize.width();
size->cy = windowSize.height();
@@ -1983,11 +2012,17 @@ void QWindowsWindow::handleDpiScaledSize(WPARAM wParam, LPARAM lParam, LRESULT *
void QWindowsWindow::handleDpiChanged(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
const UINT dpi = HIWORD(wParam);
+ const qreal scale = dpiRelativeScale(dpi);
setSavedDpi(dpi);
+ QWindowsThemeCache::clearThemeCache(hwnd);
+
// Send screen change first, so that the new screen is set during any following resize
checkForScreenChanged(QWindowsWindow::FromDpiChange);
+ if (!IsZoomed(hwnd))
+ m_data.restoreGeometry.setSize(m_data.restoreGeometry.size() * scale);
+
// We get WM_DPICHANGED in one of two situations:
//
// 1. The DPI change is a "spontaneous" DPI change as a result of e.g.
@@ -2010,13 +2045,22 @@ void QWindowsWindow::handleDpiChanged(HWND hwnd, WPARAM wParam, LPARAM lParam)
SetWindowPos(hwnd, nullptr, prcNewWindow->left, prcNewWindow->top,
prcNewWindow->right - prcNewWindow->left,
prcNewWindow->bottom - prcNewWindow->top, SWP_NOZORDER | SWP_NOACTIVATE);
+ // If the window does not have a frame, WM_MOVE and WM_SIZE won't be
+ // called which prevents the content from being scaled appropriately
+ // after a DPI change.
+ if (shouldOmitFrameAdjustment(m_data.flags, m_data.hwnd))
+ handleGeometryChange();
}
+
+ // Re-apply mask now that we have a new DPI, which have resulted in
+ // a new scale factor.
+ setMask(QHighDpi::toNativeLocalRegion(window()->mask(), window()));
}
void QWindowsWindow::handleDpiChangedAfterParent(HWND hwnd)
{
const UINT dpi = GetDpiForWindow(hwnd);
- const qreal scale = qreal(dpi) / qreal(savedDpi());
+ const qreal scale = dpiRelativeScale(dpi);
setSavedDpi(dpi);
checkForScreenChanged(QWindowsWindow::FromDpiChange);
@@ -2220,10 +2264,10 @@ void QWindowsWindow::checkForScreenChanged(ScreenChangeMode mode)
return;
// For screens with different DPI: postpone until WM_DPICHANGE
// Check on currentScreen as it can be 0 when resuming a session (QTBUG-80436).
- if (mode == FromGeometryChange && currentScreen != nullptr
- && !equalDpi(currentScreen->logicalDpi(), newScreen->logicalDpi())) {
+ const bool changingDpi = !equalDpi(QDpi(savedDpi(), savedDpi()), newScreen->logicalDpi());
+ if (mode == FromGeometryChange && currentScreen != nullptr && changingDpi)
return;
- }
+
qCDebug(lcQpaWindow).noquote().nospace() << __FUNCTION__
<< ' ' << window() << " \"" << (currentScreen ? currentScreen->name() : QString())
<< "\"->\"" << newScreen->name() << '"';
@@ -2235,6 +2279,7 @@ void QWindowsWindow::handleGeometryChange()
{
const QRect previousGeometry = m_data.geometry;
m_data.geometry = geometry_sys();
+ updateFullFrameMargins();
QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry);
// QTBUG-32121: OpenGL/normal windows (with exception of ANGLE
// which we no longer support in Qt 6) do not receive expose
@@ -2252,6 +2297,9 @@ void QWindowsWindow::handleGeometryChange()
if (testFlag(SynchronousGeometryChangeEvent))
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
+ if (!testFlag(ResizeMoveActive))
+ updateRestoreGeometry();
+
if (!wasSync)
clearFlag(SynchronousGeometryChangeEvent);
qCDebug(lcQpaEvents) << __FUNCTION__ << this << window() << m_data.geometry;
@@ -2340,23 +2388,9 @@ static inline bool isSoftwareGl()
}
bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
- WPARAM wParam, LPARAM, LRESULT *result)
+ WPARAM, LPARAM, LRESULT *result)
{
if (message == WM_ERASEBKGND) { // Backing store - ignored.
- if (!m_firstBgDraw) {
- // Get window background from the default palette; this will
- // usually be the system background color.
- const QColor bgColor = QGuiApplication::palette().color(QPalette::Window);
- HBRUSH bgBrush = CreateSolidBrush(RGB(bgColor.red(), bgColor.green(), bgColor.blue()));
- // Fill rectangle with system background color
- RECT rc;
- auto hdc = reinterpret_cast<HDC>(wParam);
- GetClientRect(hwnd, &rc);
- FillRect(hdc, &rc, bgBrush);
- DeleteObject(bgBrush);
- // Brush the window with system background color only for first time
- m_firstBgDraw = true;
- }
*result = 1;
return true;
}
@@ -2441,6 +2475,14 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state)
handleHidden();
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); // Tell QQuickWindow to stop rendering now.
} else {
+ if (state & Qt::WindowMaximized) {
+ WINDOWPLACEMENT windowPlacement{};
+ windowPlacement.length = sizeof(WINDOWPLACEMENT);
+ GetWindowPlacement(m_data.hwnd, &windowPlacement);
+ const RECT geometry = RECTfromQRect(m_data.restoreGeometry);
+ windowPlacement.rcNormalPosition = geometry;
+ SetWindowPlacement(m_data.hwnd, &windowPlacement);
+ }
// QTBUG-17548: We send expose events when receiving WM_Paint, but for
// layered windows and transient children, we won't receive any WM_Paint.
QWindow *w = window();
@@ -2464,6 +2506,11 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowStates state)
}
}
+void QWindowsWindow::updateRestoreGeometry()
+{
+ m_data.restoreGeometry = normalFrameGeometry(m_data.hwnd);
+}
+
void QWindowsWindow::setWindowState(Qt::WindowStates state)
{
if (m_data.hwnd) {
@@ -2531,26 +2578,26 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowStates newState)
if (testFlag(HasBorderInFullScreen))
newStyle |= WS_BORDER;
setStyle(newStyle);
- // Use geometry of QWindow::screen() within creation or the virtual screen the
- // window is in (QTBUG-31166, QTBUG-30724).
- const QScreen *screen = window()->screen();
- if (!screen)
- screen = QGuiApplication::primaryScreen();
- const QRect r = screen ? QHighDpi::toNativePixels(screen->geometry(), window()) : m_savedFrameGeometry;
-
+ const HMONITOR monitor = MonitorFromWindow(m_data.hwnd, MONITOR_DEFAULTTONEAREST);
+ MONITORINFO monitorInfo = {};
+ monitorInfo.cbSize = sizeof(MONITORINFO);
+ GetMonitorInfoW(monitor, &monitorInfo);
+ const QRect screenGeometry(monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top,
+ monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left,
+ monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top);
if (newState & Qt::WindowMinimized) {
- setMinimizedGeometry(m_data.hwnd, r);
+ setMinimizedGeometry(m_data.hwnd, screenGeometry);
if (stateChange & Qt::WindowMaximized)
setRestoreMaximizedFlag(m_data.hwnd, newState & Qt::WindowMaximized);
} else {
const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE;
const bool wasSync = testFlag(SynchronousGeometryChangeEvent);
setFlag(SynchronousGeometryChangeEvent);
- SetWindowPos(m_data.hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf);
+ SetWindowPos(m_data.hwnd, HWND_TOP, screenGeometry.left(), screenGeometry.top(), screenGeometry.width(), screenGeometry.height(), swpf);
if (!wasSync)
clearFlag(SynchronousGeometryChangeEvent);
clearFlag(MaximizeToFullScreen);
- QWindowSystemInterface::handleGeometryChange(window(), r);
+ QWindowSystemInterface::handleGeometryChange(window(), screenGeometry);
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
}
} else {
@@ -2643,7 +2690,7 @@ bool QWindowsWindow::windowEvent(QEvent *event)
{
switch (event->type()) {
case QEvent::ApplicationPaletteChange:
- setDarkBorder(QWindowsContext::isDarkMode());
+ setDarkBorder(QWindowsTheme::instance()->colorScheme() == Qt::ColorScheme::Dark);
break;
case QEvent::WindowBlocked: // Blocked by another modal window.
setEnabled(false);
@@ -2670,10 +2717,17 @@ void QWindowsWindow::propagateSizeHints()
bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &margins)
{
auto *windowPos = reinterpret_cast<WINDOWPOS *>(message->lParam);
+ const QRect suggestedFrameGeometry(windowPos->x, windowPos->y,
+ windowPos->cx, windowPos->cy);
+ const QRect suggestedGeometry = suggestedFrameGeometry - margins;
// Tell Windows to discard the entire contents of the client area, as re-using
// parts of the client area would lead to jitter during resize.
- windowPos->flags |= SWP_NOCOPYBITS;
+ // Check the suggestedGeometry against the current one to only discard during
+ // resize, and not a plain move. We also look for SWP_NOSIZE since that, too,
+ // implies an identical size, and comparing QRects wouldn't work with null cx/cy
+ if (!(windowPos->flags & SWP_NOSIZE) && suggestedGeometry.size() != qWindow->geometry().size())
+ windowPos->flags |= SWP_NOCOPYBITS;
if ((windowPos->flags & SWP_NOZORDER) == 0) {
if (QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(qWindow)) {
@@ -2689,9 +2743,6 @@ bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow *
return false;
if (windowPos->flags & SWP_NOSIZE)
return false;
- const QRect suggestedFrameGeometry(windowPos->x, windowPos->y,
- windowPos->cx, windowPos->cy);
- const QRect suggestedGeometry = suggestedFrameGeometry - margins;
const QRectF correctedGeometryF = QPlatformWindow::closestAcceptableGeometry(qWindow, suggestedGeometry);
if (!correctedGeometryF.isValid())
return false;
@@ -2713,7 +2764,7 @@ bool QWindowsWindow::handleGeometryChanging(MSG *message) const
void QWindowsWindow::setFullFrameMargins(const QMargins &newMargins)
{
- if (m_data.flags & Qt::FramelessWindowHint)
+ if (shouldOmitFrameAdjustment(m_data.flags, m_data.hwnd))
return;
if (m_data.fullFrameMargins != newMargins) {
qCDebug(lcQpaWindow) << __FUNCTION__ << window() << m_data.fullFrameMargins << "->" << newMargins;
@@ -2732,14 +2783,46 @@ void QWindowsWindow::updateFullFrameMargins()
void QWindowsWindow::calculateFullFrameMargins()
{
- if (m_data.flags & Qt::FramelessWindowHint)
+ if (shouldOmitFrameAdjustment(m_data.flags, m_data.hwnd))
return;
+
+ // QTBUG-113736: systemMargins depends on AdjustWindowRectExForDpi. This doesn't take into
+ // account possible external modifications to the titlebar, as with ExtendsContentIntoTitleBar()
+ // from the Windows App SDK. We can fix this by comparing the WindowRect (which includes the
+ // frame) to the ClientRect. If a 'typical' frame is detected, i.e. only the titlebar has been
+ // modified, we can safely adjust the frame by deducting the bottom margin to the total Y
+ // difference between the two rects, to get the actual size of the titlebar and prevent
+ // unwanted client area slicing.
+
+ RECT windowRect{};
+ RECT clientRect{};
+ GetWindowRect(handle(), &windowRect);
+ GetClientRect(handle(), &clientRect);
+
+ // QTBUG-117704 It is also possible that the user has manually removed the frame (for example
+ // by handling WM_NCCALCSIZE). If that is the case, i.e., the client area and the window area
+ // have identical sizes, we don't want to override the user-defined margins.
+
+ if (qrectFromRECT(windowRect).size() == qrectFromRECT(clientRect).size())
+ return;
+
// Normally obtained from WM_NCCALCSIZE. This calculation only works
// when no native menu is present.
const auto systemMargins = testFlag(DisableNonClientScaling)
? QWindowsGeometryHint::frameOnPrimaryScreen(window(), m_data.hwnd)
: frameMargins_sys();
- setFullFrameMargins(systemMargins + customMargins());
+ const QMargins actualMargins = systemMargins + customMargins();
+
+ const int yDiff = (windowRect.bottom - windowRect.top) - (clientRect.bottom - clientRect.top);
+ const bool typicalFrame = (actualMargins.left() == actualMargins.right())
+ && (actualMargins.right() == actualMargins.bottom());
+
+ const QMargins adjustedMargins = typicalFrame ?
+ QMargins(actualMargins.left(), (yDiff - actualMargins.bottom()),
+ actualMargins.right(), actualMargins.bottom())
+ : actualMargins;
+
+ setFullFrameMargins(adjustedMargins);
}
QMargins QWindowsWindow::frameMargins() const
@@ -2752,7 +2835,7 @@ QMargins QWindowsWindow::frameMargins() const
QMargins QWindowsWindow::fullFrameMargins() const
{
- if (m_data.flags & Qt::FramelessWindowHint)
+ if (shouldOmitFrameAdjustment(m_data.flags, m_data.hwnd))
return {};
return m_data.fullFrameMargins;
}
@@ -3203,17 +3286,6 @@ enum : WORD {
DwmwaUseImmersiveDarkModeBefore20h1 = 19
};
-static bool queryDarkBorder(HWND hwnd)
-{
- BOOL result = FALSE;
- const bool ok =
- SUCCEEDED(DwmGetWindowAttribute(hwnd, DwmwaUseImmersiveDarkMode, &result, sizeof(result)))
- || SUCCEEDED(DwmGetWindowAttribute(hwnd, DwmwaUseImmersiveDarkModeBefore20h1, &result, sizeof(result)));
- if (!ok)
- qCWarning(lcQpaWindow, "%s: Unable to retrieve dark window border setting.", __FUNCTION__);
- return result == TRUE;
-}
-
bool QWindowsWindow::setDarkBorderToWindow(HWND hwnd, bool d)
{
const BOOL darkBorder = d ? TRUE : FALSE;
@@ -3229,8 +3301,6 @@ void QWindowsWindow::setDarkBorder(bool d)
{
// respect explicit opt-out and incompatible palettes or styles
d = d && shouldApplyDarkFrame(window());
- if (queryDarkBorder(m_data.hwnd) == d)
- return;
setDarkBorderToWindow(m_data.hwnd, d);
}
@@ -3359,24 +3429,6 @@ void QWindowsWindow::registerTouchWindow()
qErrnoWarning("RegisterTouchWindow() failed for window '%s'.", qPrintable(window()->objectName()));
}
-void QWindowsWindow::aboutToMakeCurrent()
-{
-#ifndef QT_NO_OPENGL
- // For RasterGLSurface windows, that become OpenGL windows dynamically, it might be
- // time to set up some GL specifics. This is particularly important for layered
- // windows (WS_EX_LAYERED due to alpha > 0).
- const bool isCompositing = qt_window_private(window())->compositing;
- if (isCompositing != testFlag(Compositing)) {
- if (isCompositing)
- setFlag(Compositing);
- else
- clearFlag(Compositing);
-
- updateGLWindowSettings(window(), m_data.hwnd, m_data.flags, m_opacity);
- }
-#endif
-}
-
void QWindowsWindow::setHasBorderInFullScreenStatic(QWindow *window, bool border)
{
if (QPlatformWindow *handle = window->handle())
diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h
index 38e9fb9a5b..024711e7f3 100644
--- a/src/plugins/platforms/windows/qwindowswindow.h
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -78,6 +78,7 @@ struct QWindowsWindowData
{
Qt::WindowFlags flags;
QRect geometry;
+ QRect restoreGeometry;
QMargins fullFrameMargins; // Do not use directly for windows, see FrameDirty.
QMargins customMargins; // User-defined, additional frame for NCCALCSIZE
HWND hwnd = nullptr;
@@ -218,6 +219,8 @@ public:
void setGeometry(const QRect &rect) override;
QRect geometry() const override { return m_data.geometry; }
QRect normalGeometry() const override;
+ QRect restoreGeometry() const { return m_data.restoreGeometry; }
+ void updateRestoreGeometry();
void setVisible(bool visible) override;
bool isVisible() const;
@@ -296,6 +299,7 @@ public:
static inline void *userDataOf(HWND hwnd);
static inline void setUserDataOf(HWND hwnd, void *ud);
+ static bool hasNoNativeFrame(HWND hwnd, Qt::WindowFlags flags);
static bool setWindowLayered(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, qreal opacity);
bool isLayered() const;
@@ -320,7 +324,6 @@ public:
void *surface(void *nativeConfig, int *err);
void invalidateSurface() override;
- void aboutToMakeCurrent();
void setAlertState(bool enabled) override;
bool isAlertState() const override { return testFlag(AlertState); }
@@ -342,6 +345,7 @@ public:
void setSavedDpi(int dpi) { m_savedDpi = dpi; }
int savedDpi() const { return m_savedDpi; }
+ qreal dpiRelativeScale(const UINT dpi) const;
private:
inline void show_sys() const;
@@ -377,7 +381,6 @@ private:
HICON m_iconBig = nullptr;
void *m_surface = nullptr;
int m_savedDpi = 96;
- bool m_firstBgDraw = false;
static bool m_screenForGLInitialized;
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
index 001cb8505b..1abb412ccd 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.cpp
@@ -5,6 +5,7 @@
#if QT_CONFIG(accessibility)
#include "qwindowsuiaaccessibility.h"
+#include "qwindowsuiautomation.h"
#include "qwindowsuiamainprovider.h"
#include "qwindowsuiautils.h"
@@ -14,13 +15,13 @@
#include <QtGui/private/qguiapplication_p.h>
#include <QtCore/qt_windows.h>
#include <qpa/qplatformintegration.h>
-#include <QtGui/private/qwindowsuiawrapper_p.h>
#include <QtCore/private/qwinregistry_p.h>
QT_BEGIN_NAMESPACE
using namespace QWindowsUiAutomation;
+using namespace Qt::Literals::StringLiterals;
bool QWindowsUiaAccessibility::m_accessibleActive = false;
@@ -46,7 +47,7 @@ bool QWindowsUiaAccessibility::handleWmGetObject(HWND hwnd, WPARAM wParam, LPARA
if (QWindow *window = QWindowsContext::instance()->findWindow(hwnd)) {
if (QAccessibleInterface *accessible = window->accessibleRoot()) {
QWindowsUiaMainProvider *provider = QWindowsUiaMainProvider::providerForAccessible(accessible);
- *lResult = QWindowsUiaWrapper::instance()->returnRawElementProvider(hwnd, wParam, lParam, provider);
+ *lResult = UiaReturnRawElementProvider(hwnd, wParam, lParam, provider);
return true;
}
}
@@ -78,8 +79,8 @@ static QString alertSound(const QObject *object)
static QString soundFileName(const QString &soundName)
{
- const QString key = QStringLiteral("AppEvents\\Schemes\\Apps\\.Default\\")
- + soundName + QStringLiteral("\\.Current");
+ const QString key = "AppEvents\\Schemes\\Apps\\.Default\\"_L1
+ + soundName + "\\.Current"_L1;
return QWinRegistryKey(HKEY_CURRENT_USER, key).stringValue(L"");
}
@@ -97,11 +98,7 @@ void QWindowsUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event
if (!event)
return;
- // Ignore events sent before the first UI Automation
- // request or while QAccessible is being activated.
- if (!m_accessibleActive)
- return;
-
+ // Always handle system sound events
switch (event->type()) {
case QAccessible::PopupMenuStart:
playSystemSound(QStringLiteral("MenuPopup"));
@@ -116,16 +113,17 @@ void QWindowsUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event
break;
}
- QAccessibleInterface *accessible = event->accessibleInterface();
- if (!isActive() || !accessible || !accessible->isValid())
+ // Ignore events sent before the first UI Automation
+ // request or while QAccessible is being activated.
+ if (!m_accessibleActive)
return;
- // Ensures QWindowsUiaWrapper is properly initialized.
- if (!QWindowsUiaWrapper::instance()->ready())
+ QAccessibleInterface *accessible = event->accessibleInterface();
+ if (!isActive() || !accessible || !accessible->isValid())
return;
// No need to do anything when nobody is listening.
- if (!QWindowsUiaWrapper::instance()->clientsAreListening())
+ if (!UiaClientsAreListening())
return;
switch (event->type()) {
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h
index 1813bb4d89..2e8ee585da 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaaccessibility.h
@@ -7,6 +7,7 @@
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
+#include <QtCore/qt_windows.h>
#include "qwindowscontext.h"
#include <qpa/qplatformaccessibility.h>
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h
index c899b4096e..032679ab10 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiabaseprovider.h
@@ -10,8 +10,8 @@
#include <QtGui/qaccessible.h>
#include <QtCore/qpointer.h>
-#include <qwindowscombase.h>
-#include <QtGui/private/qwindowsuiawrapper_p.h>
+#include "qwindowsuiautomation.h"
+#include <QtCore/private/qcomobject_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.h
index 49b37ba295..b384eb521c 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaexpandcollapseprovider.h
@@ -13,7 +13,7 @@ QT_BEGIN_NAMESPACE
// Implements the Expand/Collapse control pattern provider. Used for menu items with submenus.
class QWindowsUiaExpandCollapseProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<IExpandCollapseProvider>
+ public QComObject<IExpandCollapseProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaExpandCollapseProvider)
public:
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h
index b501616966..289a867869 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiagriditemprovider.h
@@ -13,7 +13,7 @@ QT_BEGIN_NAMESPACE
// Implements the Grid Item control pattern provider. Used by items within a table/tree.
class QWindowsUiaGridItemProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<IGridItemProvider>
+ public QComObject<IGridItemProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaGridItemProvider)
public:
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h
index b905133f6b..d33bbd0429 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiagridprovider.h
@@ -12,8 +12,7 @@
QT_BEGIN_NAMESPACE
// Implements the Grid control pattern provider. Used by tables/trees.
-class QWindowsUiaGridProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<IGridProvider>
+class QWindowsUiaGridProvider : public QWindowsUiaBaseProvider, public QComObject<IGridProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaGridProvider)
public:
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h
index eca7e73039..ec006c673e 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiainvokeprovider.h
@@ -12,8 +12,7 @@
QT_BEGIN_NAMESPACE
// Implements the Invoke control pattern provider.
-class QWindowsUiaInvokeProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<IInvokeProvider>
+class QWindowsUiaInvokeProvider : public QWindowsUiaBaseProvider, public QComObject<IInvokeProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaInvokeProvider)
public:
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
index 16f0a3f9a6..95ddbcced6 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
@@ -18,7 +18,6 @@
#include "qwindowsuiagriditemprovider.h"
#include "qwindowsuiawindowprovider.h"
#include "qwindowsuiaexpandcollapseprovider.h"
-#include "qwindowscombase.h"
#include "qwindowscontext.h"
#include "qwindowsuiautils.h"
#include "qwindowsuiaprovidercache.h"
@@ -27,6 +26,7 @@
#include <QtGui/qaccessible.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qwindow.h>
+#include <qpa/qplatforminputcontextfactory_p.h>
#if !defined(Q_CC_BOR) && !defined (Q_CC_GNU)
#include <comdef.h>
@@ -61,9 +61,8 @@ QWindowsUiaMainProvider *QWindowsUiaMainProvider::providerForAccessible(QAccessi
return provider;
}
-QWindowsUiaMainProvider::QWindowsUiaMainProvider(QAccessibleInterface *a, int initialRefCount)
- : QWindowsUiaBaseProvider(QAccessible::uniqueId(a)),
- m_ref(initialRefCount)
+QWindowsUiaMainProvider::QWindowsUiaMainProvider(QAccessibleInterface *a)
+ : QWindowsUiaBaseProvider(QAccessible::uniqueId(a))
{
}
@@ -80,7 +79,7 @@ void QWindowsUiaMainProvider::notifyFocusChange(QAccessibleEvent *event)
accessible = child;
}
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible))
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_AutomationFocusChangedEventId);
+ UiaRaiseAutomationEvent(provider, UIA_AutomationFocusChangedEventId);
}
}
@@ -97,7 +96,7 @@ void QWindowsUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *eve
if (accessible->state().checked)
toggleState = accessible->state().checkStateMixed ? ToggleState_Indeterminate : ToggleState_On;
setVariantI4(toggleState, &newVal);
- QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_ToggleToggleStatePropertyId, oldVal, newVal);
+ UiaRaiseAutomationPropertyChangedEvent(provider, UIA_ToggleToggleStatePropertyId, oldVal, newVal);
}
}
}
@@ -106,13 +105,13 @@ void QWindowsUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *eve
// Notifies window opened/closed.
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
if (accessible->state().active) {
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_Window_WindowOpenedEventId);
+ UiaRaiseAutomationEvent(provider, UIA_Window_WindowOpenedEventId);
if (QAccessibleInterface *focused = accessible->focusChild()) {
if (QWindowsUiaMainProvider *focusedProvider = providerForAccessible(focused))
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(focusedProvider, UIA_AutomationFocusChangedEventId);
+ UiaRaiseAutomationEvent(focusedProvider, UIA_AutomationFocusChangedEventId);
}
} else {
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_Window_WindowClosedEventId);
+ UiaRaiseAutomationEvent(provider, UIA_Window_WindowClosedEventId);
}
}
}
@@ -141,27 +140,11 @@ void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *eve
}
if (event->value().typeId() == QMetaType::QString) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
-
- // Tries to notify the change using UiaRaiseNotificationEvent(), which is only available on
- // Windows 10 version 1709 or newer. Otherwise uses UiaRaiseAutomationPropertyChangedEvent().
-
- BSTR displayString = bStrFromQString(event->value().toString());
- BSTR activityId = bStrFromQString(QString());
-
- HRESULT hr = QWindowsUiaWrapper::instance()->raiseNotificationEvent(provider, NotificationKind_Other,
- NotificationProcessing_ImportantMostRecent,
- displayString, activityId);
-
- ::SysFreeString(displayString);
- ::SysFreeString(activityId);
-
- if (hr == static_cast<HRESULT>(UIA_E_NOTSUPPORTED)) {
- VARIANT oldVal, newVal;
- clearVariant(&oldVal);
- setVariantString(event->value().toString(), &newVal);
- QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_ValueValuePropertyId, oldVal, newVal);
- ::SysFreeString(newVal.bstrVal);
- }
+ // Notifies changes in string values.
+ VARIANT oldVal, newVal;
+ clearVariant(&oldVal);
+ setVariantString(event->value().toString(), &newVal);
+ UiaRaiseAutomationPropertyChangedEvent(provider, UIA_ValueValuePropertyId, oldVal, newVal);
}
} else if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
@@ -169,7 +152,7 @@ void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *eve
VARIANT oldVal, newVal;
clearVariant(&oldVal);
setVariantDouble(valueInterface->currentValue().toDouble(), &newVal);
- QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_RangeValueValuePropertyId, oldVal, newVal);
+ UiaRaiseAutomationPropertyChangedEvent(provider, UIA_RangeValueValuePropertyId, oldVal, newVal);
}
}
}
@@ -185,7 +168,7 @@ void QWindowsUiaMainProvider::notifyNameChange(QAccessibleEvent *event)
VARIANT oldVal, newVal;
clearVariant(&oldVal);
setVariantString(accessible->text(QAccessible::Name), &newVal);
- QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_NamePropertyId, oldVal, newVal);
+ UiaRaiseAutomationPropertyChangedEvent(provider, UIA_NamePropertyId, oldVal, newVal);
::SysFreeString(newVal.bstrVal);
}
}
@@ -196,7 +179,7 @@ void QWindowsUiaMainProvider::notifySelectionChange(QAccessibleEvent *event)
{
if (QAccessibleInterface *accessible = event->accessibleInterface()) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_SelectionItem_ElementSelectedEventId);
+ UiaRaiseAutomationEvent(provider, UIA_SelectionItem_ElementSelectedEventId);
}
}
}
@@ -208,13 +191,13 @@ void QWindowsUiaMainProvider::notifyTextChange(QAccessibleEvent *event)
if (accessible->textInterface()) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
if (event->type() == QAccessible::TextSelectionChanged) {
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_Text_TextSelectionChangedEventId);
+ UiaRaiseAutomationEvent(provider, UIA_Text_TextSelectionChangedEventId);
} else if (event->type() == QAccessible::TextCaretMoved) {
if (!accessible->state().readOnly) {
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_Text_TextSelectionChangedEventId);
+ UiaRaiseAutomationEvent(provider, UIA_Text_TextSelectionChangedEventId);
}
} else {
- QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_Text_TextChangedEventId);
+ UiaRaiseAutomationEvent(provider, UIA_Text_TextChangedEventId);
}
}
}
@@ -223,33 +206,26 @@ void QWindowsUiaMainProvider::notifyTextChange(QAccessibleEvent *event)
HRESULT STDMETHODCALLTYPE QWindowsUiaMainProvider::QueryInterface(REFIID iid, LPVOID *iface)
{
- if (!iface)
- return E_INVALIDARG;
- *iface = nullptr;
-
- QAccessibleInterface *accessible = accessibleInterface();
+ HRESULT result = QComObject::QueryInterface(iid, iface);
- const bool result = qWindowsComQueryUnknownInterfaceMulti<IRawElementProviderSimple>(this, iid, iface)
- || qWindowsComQueryInterface<IRawElementProviderSimple>(this, iid, iface)
- || qWindowsComQueryInterface<IRawElementProviderFragment>(this, iid, iface)
- || (accessible && hwndForAccessible(accessible) && qWindowsComQueryInterface<IRawElementProviderFragmentRoot>(this, iid, iface));
- return result ? S_OK : E_NOINTERFACE;
-}
+ if (SUCCEEDED(result) && iid == __uuidof(IRawElementProviderFragmentRoot)) {
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (accessible && hwndForAccessible(accessible)) {
+ result = S_OK;
+ } else {
+ result = E_NOINTERFACE;
+ iface = nullptr;
+ }
+ }
-ULONG QWindowsUiaMainProvider::AddRef()
-{
- return ++m_ref;
+ return result;
}
ULONG STDMETHODCALLTYPE QWindowsUiaMainProvider::Release()
{
QMutexLocker locker(&m_mutex);
- if (!--m_ref) {
- delete this;
- return 0;
- }
- return m_ref;
+ return QComObject::Release();
}
HRESULT QWindowsUiaMainProvider::get_ProviderOptions(ProviderOptions *pRetVal)
@@ -304,15 +280,18 @@ HRESULT QWindowsUiaMainProvider::GetPatternProvider(PATTERNID idPattern, IUnknow
*pRetVal = new QWindowsUiaToggleProvider(id());
break;
case UIA_SelectionPatternId:
- // Lists of items.
- if (accessible->role() == QAccessible::List
+ case UIA_SelectionPattern2Id:
+ // Selections via QAccessibleSelectionInterface or lists of items.
+ if (accessible->selectionInterface()
+ || accessible->role() == QAccessible::List
|| accessible->role() == QAccessible::PageTabList) {
*pRetVal = new QWindowsUiaSelectionProvider(id());
}
break;
case UIA_SelectionItemPatternId:
- // Items within a list and radio buttons.
- if ((accessible->role() == QAccessible::RadioButton)
+ // Parent supports selection interface or items within a list and radio buttons.
+ if ((accessible->parent() && accessible->parent()->selectionInterface())
+ || (accessible->role() == QAccessible::RadioButton)
|| (accessible->role() == QAccessible::ListItem)
|| (accessible->role() == QAccessible::PageTab)) {
*pRetVal = new QWindowsUiaSelectionItemProvider(id());
@@ -369,6 +348,28 @@ HRESULT QWindowsUiaMainProvider::GetPatternProvider(PATTERNID idPattern, IUnknow
return S_OK;
}
+void QWindowsUiaMainProvider::fillVariantArrayForRelation(QAccessibleInterface* accessible,
+ QAccessible::Relation relation, VARIANT *pRetVal)
+{
+ Q_ASSERT(accessible);
+
+ typedef QPair<QAccessibleInterface*, QAccessible::Relation> RelationPair;
+ const QList<RelationPair> relationInterfaces = accessible->relations(relation);
+ if (relationInterfaces.empty())
+ return;
+
+ SAFEARRAY *elements = SafeArrayCreateVector(VT_UNKNOWN, 0, relationInterfaces.size());
+ for (LONG i = 0; i < relationInterfaces.size(); ++i) {
+ if (QWindowsUiaMainProvider *childProvider = QWindowsUiaMainProvider::providerForAccessible(relationInterfaces.at(i).first)) {
+ SafeArrayPutElement(elements, &i, static_cast<IRawElementProviderSimple*>(childProvider));
+ childProvider->Release();
+ }
+ }
+
+ pRetVal->vt = VT_UNKNOWN | VT_ARRAY;
+ pRetVal->parray = elements;
+}
+
HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pRetVal)
{
qCDebug(lcQpaUiAutomation) << __FUNCTION__ << idProp;
@@ -403,6 +404,15 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR
setVariantString(className, pRetVal);
}
break;
+ case UIA_DescribedByPropertyId:
+ fillVariantArrayForRelation(accessible, QAccessible::DescriptionFor, pRetVal);
+ break;
+ case UIA_FlowsFromPropertyId:
+ fillVariantArrayForRelation(accessible, QAccessible::FlowsTo, pRetVal);
+ break;
+ case UIA_FlowsToPropertyId:
+ fillVariantArrayForRelation(accessible, QAccessible::FlowsFrom, pRetVal);
+ break;
case UIA_FrameworkIdPropertyId:
setVariantString(QStringLiteral("Qt"), pRetVal);
break;
@@ -416,7 +426,7 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR
// The native OSK should be disabled if the Qt OSK is in use,
// or if disabled via application attribute.
- static bool imModuleEmpty = qEnvironmentVariableIsEmpty("QT_IM_MODULE");
+ static bool imModuleEmpty = QPlatformInputContextFactory::requested().isEmpty();
bool nativeVKDisabled = QCoreApplication::testAttribute(Qt::AA_DisableNativeVirtualKeyboard);
// If we want to disable the native OSK auto-showing
@@ -519,7 +529,7 @@ HRESULT QWindowsUiaMainProvider::get_HostRawElementProvider(IRawElementProviderS
// Returns a host provider only for controls associated with a native window handle. Others should return NULL.
if (QAccessibleInterface *accessible = accessibleInterface()) {
if (HWND hwnd = hwndForAccessible(accessible)) {
- return QWindowsUiaWrapper::instance()->hostProviderFromHwnd(hwnd, pRetVal);
+ return UiaHostProviderFromHwnd(hwnd, pRetVal);
}
}
return S_OK;
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
index fb5069f620..99db0ed318 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.h
@@ -20,15 +20,13 @@ QT_BEGIN_NAMESPACE
// The main UI Automation class.
class QWindowsUiaMainProvider :
public QWindowsUiaBaseProvider,
- public IRawElementProviderSimple,
- public IRawElementProviderFragment,
- public IRawElementProviderFragmentRoot
+ public QComObject<IRawElementProviderSimple, IRawElementProviderFragment, IRawElementProviderFragmentRoot>
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(QWindowsUiaMainProvider)
public:
static QWindowsUiaMainProvider *providerForAccessible(QAccessibleInterface *accessible);
- explicit QWindowsUiaMainProvider(QAccessibleInterface *a, int initialRefCount = 1);
+ explicit QWindowsUiaMainProvider(QAccessibleInterface *a);
virtual ~QWindowsUiaMainProvider();
static void notifyFocusChange(QAccessibleEvent *event);
static void notifyStateChange(QAccessibleStateChangeEvent *event);
@@ -39,7 +37,6 @@ public:
// IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface) override;
- ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
// IRawElementProviderSimple methods
@@ -62,7 +59,7 @@ public:
private:
QString automationIdForAccessible(const QAccessibleInterface *accessible);
- ULONG m_ref;
+ static void fillVariantArrayForRelation(QAccessibleInterface *accessible, QAccessible::Relation relation, VARIANT *pRetVal);
static QMutex m_mutex;
};
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h
index 3e06961a82..ffb5ae155b 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiarangevalueprovider.h
@@ -13,7 +13,7 @@ QT_BEGIN_NAMESPACE
// Implements the Range Value control pattern provider.
class QWindowsUiaRangeValueProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<IRangeValueProvider>
+ public QComObject<IRangeValueProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaRangeValueProvider)
public:
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp
index 7e829b24a7..95bc2f7570 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.cpp
@@ -36,6 +36,14 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::Select()
if (!accessible)
return UIA_E_ELEMENTNOTAVAILABLE;
+ if (QAccessibleInterface *parent = accessible->parent()) {
+ if (QAccessibleSelectionInterface *selectionInterface = parent->selectionInterface()) {
+ selectionInterface->clear();
+ bool ok = selectionInterface->select(accessible);
+ return ok ? S_OK : S_FALSE;
+ }
+ }
+
QAccessibleActionInterface *actionInterface = accessible->actionInterface();
if (!actionInterface)
return UIA_E_ELEMENTNOTAVAILABLE;
@@ -73,6 +81,13 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::AddToSelection()
if (!accessible)
return UIA_E_ELEMENTNOTAVAILABLE;
+ if (QAccessibleInterface *parent = accessible->parent()) {
+ if (QAccessibleSelectionInterface *selectionInterface = parent->selectionInterface()) {
+ bool ok = selectionInterface->select(accessible);
+ return ok ? S_OK : S_FALSE;
+ }
+ }
+
QAccessibleActionInterface *actionInterface = accessible->actionInterface();
if (!actionInterface)
return UIA_E_ELEMENTNOTAVAILABLE;
@@ -98,6 +113,13 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::RemoveFromSelection(
if (!accessible)
return UIA_E_ELEMENTNOTAVAILABLE;
+ if (QAccessibleInterface *parent = accessible->parent()) {
+ if (QAccessibleSelectionInterface *selectionInterface = parent->selectionInterface()) {
+ bool ok = selectionInterface->unselect(accessible);
+ return ok ? S_OK : S_FALSE;
+ }
+ }
+
QAccessibleActionInterface *actionInterface = accessible->actionInterface();
if (!actionInterface)
return UIA_E_ELEMENTNOTAVAILABLE;
@@ -124,6 +146,14 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::get_IsSelected(BOOL
if (!accessible)
return UIA_E_ELEMENTNOTAVAILABLE;
+ if (QAccessibleInterface *parent = accessible->parent()) {
+ if (QAccessibleSelectionInterface *selectionInterface = parent->selectionInterface()) {
+ bool selected = selectionInterface->isSelected(accessible);
+ *pRetVal = selected ? TRUE : FALSE;
+ return S_OK;
+ }
+ }
+
if (accessible->role() == QAccessible::RadioButton)
*pRetVal = accessible->state().checked;
else if (accessible->role() == QAccessible::PageTab)
@@ -146,12 +176,18 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionItemProvider::get_SelectionContain
if (!accessible)
return UIA_E_ELEMENTNOTAVAILABLE;
+ QAccessibleInterface *parent = accessible->parent();
+ if (parent && parent->selectionInterface()) {
+ *pRetVal = QWindowsUiaMainProvider::providerForAccessible(parent);
+ return S_OK;
+ }
+
QAccessibleActionInterface *actionInterface = accessible->actionInterface();
if (!actionInterface)
return UIA_E_ELEMENTNOTAVAILABLE;
// Radio buttons do not require a container.
- if (QAccessibleInterface *parent = accessible->parent()) {
+ if (parent) {
if ((accessible->role() == QAccessible::ListItem && parent->role() == QAccessible::List)
|| (accessible->role() == QAccessible::PageTab && parent->role() == QAccessible::PageTabList)) {
*pRetVal = QWindowsUiaMainProvider::providerForAccessible(parent);
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h
index b510ae951c..ee34fd9edd 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionitemprovider.h
@@ -13,7 +13,7 @@ QT_BEGIN_NAMESPACE
// Implements the Selection Item control pattern provider. Used for List items and radio buttons.
class QWindowsUiaSelectionItemProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<ISelectionItemProvider>
+ public QComObject<ISelectionItemProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaSelectionItemProvider)
public:
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp
index 45f3b20552..37148c655a 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.cpp
@@ -41,17 +41,23 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::GetSelection(SAFEARRAY *
if (!accessible)
return UIA_E_ELEMENTNOTAVAILABLE;
- // First put selected items in a list, then build a safe array with the right size.
+ // First get/create list of selected items, then build a safe array with the right size.
QList<QAccessibleInterface *> selectedList;
- for (int i = 0; i < accessible->childCount(); ++i) {
- if (QAccessibleInterface *child = accessible->child(i)) {
- if (accessible->role() == QAccessible::PageTabList) {
- if (child->role() == QAccessible::PageTab && child->state().focused) {
- selectedList.append(child);
- }
- } else {
- if (child->state().selected) {
- selectedList.append(child);
+ if (QAccessibleSelectionInterface *selectionInterface = accessible->selectionInterface()) {
+ selectedList = selectionInterface->selectedItems();
+ } else {
+ const int childCount = accessible->childCount();
+ selectedList.reserve(childCount);
+ for (int i = 0; i < childCount; ++i) {
+ if (QAccessibleInterface *child = accessible->child(i)) {
+ if (accessible->role() == QAccessible::PageTabList) {
+ if (child->role() == QAccessible::PageTab && child->state().focused) {
+ selectedList.append(child);
+ }
+ } else {
+ if (child->state().selected) {
+ selectedList.append(child);
+ }
}
}
}
@@ -102,11 +108,15 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::get_IsSelectionRequired(
// Initially returns false if none are selected. After the first selection, it may be required.
bool anySelected = false;
- for (int i = 0; i < accessible->childCount(); ++i) {
- if (QAccessibleInterface *child = accessible->child(i)) {
- if (child->state().selected) {
- anySelected = true;
- break;
+ if (QAccessibleSelectionInterface *selectionInterface = accessible->selectionInterface()) {
+ anySelected = selectionInterface->selectedItem(0) != nullptr;
+ } else {
+ for (int i = 0; i < accessible->childCount(); ++i) {
+ if (QAccessibleInterface *child = accessible->child(i)) {
+ if (child->state().selected) {
+ anySelected = true;
+ break;
+ }
}
}
}
@@ -116,6 +126,134 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::get_IsSelectionRequired(
return S_OK;
}
+HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::get_FirstSelectedItem(__RPC__deref_out_opt IRawElementProviderSimple **pRetVal)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!pRetVal)
+ return E_INVALIDARG;
+ *pRetVal = nullptr;
+
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (!accessible)
+ return UIA_E_ELEMENTNOTAVAILABLE;
+
+ QAccessibleInterface *firstSelectedChild = nullptr;
+ if (QAccessibleSelectionInterface *selectionInterface = accessible->selectionInterface()) {
+ firstSelectedChild = selectionInterface->selectedItem(0);
+ if (!firstSelectedChild)
+ return UIA_E_ELEMENTNOTAVAILABLE;
+ } else {
+ int i = 0;
+ while (!firstSelectedChild && i < accessible->childCount()) {
+ if (QAccessibleInterface *child = accessible->child(i)) {
+ if (accessible->role() == QAccessible::PageTabList) {
+ if (child->role() == QAccessible::PageTab && child->state().focused)
+ firstSelectedChild = child;
+ } else if (child->state().selected) {
+ firstSelectedChild = child;
+ }
+ }
+ i++;
+ }
+ }
+
+ if (!firstSelectedChild)
+ return UIA_E_ELEMENTNOTAVAILABLE;
+
+ if (QWindowsUiaMainProvider *childProvider = QWindowsUiaMainProvider::providerForAccessible(firstSelectedChild))
+ {
+ *pRetVal = static_cast<IRawElementProviderSimple *>(childProvider);
+ return S_OK;
+ }
+
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::get_LastSelectedItem(__RPC__deref_out_opt IRawElementProviderSimple **pRetVal)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!pRetVal)
+ return E_INVALIDARG;
+ *pRetVal = nullptr;
+
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (!accessible)
+ return UIA_E_ELEMENTNOTAVAILABLE;
+
+ QAccessibleInterface *lastSelectedChild = nullptr;
+ if (QAccessibleSelectionInterface *selectionInterface = accessible->selectionInterface()) {
+ const int selectedItemCount = selectionInterface->selectedItemCount();
+ if (selectedItemCount <= 0)
+ return UIA_E_ELEMENTNOTAVAILABLE;
+ lastSelectedChild = selectionInterface->selectedItem(selectedItemCount - 1);
+ } else {
+ int i = accessible->childCount() - 1;
+ while (!lastSelectedChild && i >= 0) {
+ if (QAccessibleInterface *child = accessible->child(i)) {
+ if (accessible->role() == QAccessible::PageTabList) {
+ if (child->role() == QAccessible::PageTab && child->state().focused)
+ lastSelectedChild = child;
+ } else if (child->state().selected) {
+ lastSelectedChild = child;
+ }
+ }
+ i--;
+ }
+ }
+
+ if (!lastSelectedChild)
+ return UIA_E_ELEMENTNOTAVAILABLE;
+
+ if (QWindowsUiaMainProvider *childProvider = QWindowsUiaMainProvider::providerForAccessible(lastSelectedChild))
+ {
+ *pRetVal = static_cast<IRawElementProviderSimple *>(childProvider);
+ return S_OK;
+ }
+
+ return S_FALSE;
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::get_CurrentSelectedItem(__RPC__deref_out_opt IRawElementProviderSimple **pRetVal)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+ return get_FirstSelectedItem(pRetVal);
+}
+
+HRESULT STDMETHODCALLTYPE QWindowsUiaSelectionProvider::get_ItemCount(__RPC__out int *pRetVal)
+{
+ qCDebug(lcQpaUiAutomation) << __FUNCTION__;
+
+ if (!pRetVal)
+ return E_INVALIDARG;
+ *pRetVal = -1;
+
+ QAccessibleInterface *accessible = accessibleInterface();
+ if (!accessible)
+ return UIA_E_ELEMENTNOTAVAILABLE;
+
+
+ if (QAccessibleSelectionInterface *selectionInterface = accessible->selectionInterface())
+ *pRetVal = selectionInterface->selectedItemCount();
+ else {
+ int selectedCount = 0;
+ for (int i = 0; i < accessible->childCount(); i++) {
+ if (QAccessibleInterface *child = accessible->child(i)) {
+ if (accessible->role() == QAccessible::PageTabList) {
+ if (child->role() == QAccessible::PageTab && child->state().focused)
+ selectedCount++;
+ } else if (child->state().selected) {
+ selectedCount++;
+ }
+ }
+ }
+ *pRetVal = selectedCount;
+ }
+
+ return S_OK;
+}
+
QT_END_NAMESPACE
#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h
index 9a187c9413..7a899e4261 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiaselectionprovider.h
@@ -11,9 +11,22 @@
QT_BEGIN_NAMESPACE
+namespace QtPrivate {
+
+template <>
+struct QComObjectTraits<ISelectionProvider2>
+{
+ static constexpr bool isGuidOf(REFIID riid) noexcept
+ {
+ return QComObjectTraits<ISelectionProvider2, ISelectionProvider>::isGuidOf(riid);
+ }
+};
+
+} // namespace QtPrivate
+
// Implements the Selection control pattern provider. Used for Lists.
class QWindowsUiaSelectionProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<ISelectionProvider>
+ public QComObject<ISelectionProvider2>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaSelectionProvider)
public:
@@ -24,6 +37,12 @@ public:
HRESULT STDMETHODCALLTYPE GetSelection(SAFEARRAY **pRetVal) override;
HRESULT STDMETHODCALLTYPE get_CanSelectMultiple(BOOL *pRetVal) override;
HRESULT STDMETHODCALLTYPE get_IsSelectionRequired(BOOL *pRetVal) override;
+
+ // ISelectionProvider2
+ HRESULT STDMETHODCALLTYPE get_FirstSelectedItem(__RPC__deref_out_opt IRawElementProviderSimple **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_LastSelectedItem(__RPC__deref_out_opt IRawElementProviderSimple **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_CurrentSelectedItem(__RPC__deref_out_opt IRawElementProviderSimple **pRetVal) override;
+ HRESULT STDMETHODCALLTYPE get_ItemCount(__RPC__out int *pRetVal) override;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h
index 8aed180671..3bb0e1027e 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableitemprovider.h
@@ -13,7 +13,7 @@ QT_BEGIN_NAMESPACE
// Implements the Table Item control pattern provider. Used by items within a table/tree.
class QWindowsUiaTableItemProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<ITableItemProvider>
+ public QComObject<ITableItemProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaTableItemProvider)
public:
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h
index 6454bb9441..8beb11decf 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatableprovider.h
@@ -12,8 +12,7 @@
QT_BEGIN_NAMESPACE
// Implements the Table control pattern provider. Used by tables/trees.
-class QWindowsUiaTableProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<ITableProvider>
+class QWindowsUiaTableProvider : public QWindowsUiaBaseProvider, public QComObject<ITableProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaTableProvider)
public:
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp
index e3b7c69b60..172836232e 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp
@@ -26,20 +26,6 @@ QWindowsUiaTextProvider::~QWindowsUiaTextProvider()
{
}
-HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::QueryInterface(REFIID iid, LPVOID *iface)
-{
- qCDebug(lcQpaUiAutomation) << __FUNCTION__ << this;
-
- if (!iface)
- return E_INVALIDARG;
- *iface = nullptr;
-
- const bool result = qWindowsComQueryUnknownInterfaceMulti<ITextProvider>(this, iid, iface)
- || qWindowsComQueryInterface<ITextProvider>(this, iid, iface)
- || qWindowsComQueryInterface<ITextProvider2>(this, iid, iface);
- return result ? S_OK : E_NOINTERFACE;
-}
-
// Returns an array of providers for the selected text ranges.
HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::GetSelection(SAFEARRAY **pRetVal)
{
@@ -146,9 +132,10 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::RangeFromPoint(UiaPoint point
nativeUiaPointToPoint(point, window, &pt);
int offset = textInterface->offsetAtPoint(pt);
- if ((offset >= 0) && (offset < textInterface->characterCount())) {
- *pRetVal = new QWindowsUiaTextRangeProvider(id(), offset, offset);
- }
+ if (offset < 0 || offset >= textInterface->characterCount())
+ return UIA_E_ELEMENTNOTAVAILABLE;
+
+ *pRetVal = new QWindowsUiaTextRangeProvider(id(), offset, offset);
return S_OK;
}
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h
index 5e6d430f1a..8f886510b4 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.h
@@ -12,18 +12,27 @@
QT_BEGIN_NAMESPACE
+namespace QtPrivate {
+
+template <>
+struct QComObjectTraits<ITextProvider2>
+{
+ static constexpr bool isGuidOf(REFIID riid) noexcept
+ {
+ return QComObjectTraits<ITextProvider2, ITextProvider>::isGuidOf(riid);
+ }
+};
+
+} // namespace QtPrivate
+
// Implements the Text control pattern provider. Used for text controls.
-class QWindowsUiaTextProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<ITextProvider2>
+class QWindowsUiaTextProvider : public QWindowsUiaBaseProvider, public QComObject<ITextProvider2>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaTextProvider)
public:
explicit QWindowsUiaTextProvider(QAccessible::Id id);
~QWindowsUiaTextProvider();
- // IUnknown overrides
- HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, LPVOID *iface) override;
-
// ITextProvider
HRESULT STDMETHODCALLTYPE GetSelection(SAFEARRAY **pRetVal) override;
HRESULT STDMETHODCALLTYPE GetVisibleRanges(SAFEARRAY **pRetVal) override;
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp
index 4d02036196..a62a33cfe2 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp
@@ -167,6 +167,15 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaTextRangeProvider::GetAttributeValue(TEXTAT
else
setVariantI4(CaretPosition_Unknown, pRetVal);
break;
+ case UIA_StrikethroughStyleAttributeId:
+ {
+ const QString value = valueForIA2Attribute(textInterface, QStringLiteral("text-line-through-type"));
+ if (value.isEmpty())
+ break;
+ const TextDecorationLineStyle uiaLineStyle = uiaLineStyleForIA2LineStyle(value);
+ setVariantI4(uiaLineStyle, pRetVal);
+ break;
+ }
default:
break;
}
@@ -307,14 +316,14 @@ HRESULT QWindowsUiaTextRangeProvider::Move(TextUnit unit, int count, int *pRetVa
int len = textInterface->characterCount();
- if (len < 1)
+ if (len < 1 || count == 0) // MSDN: "Zero has no effect."
return S_OK;
if (unit == TextUnit_Character) {
// Moves the start point, ensuring it lies within the bounds.
- int start = qBound(0, m_startOffset + count, len - 1);
+ int start = qBound(0, m_startOffset + count, len);
// If range was initially empty, leaves it as is; otherwise, normalizes it to one char.
- m_endOffset = (m_endOffset > m_startOffset) ? start + 1 : start;
+ m_endOffset = (m_endOffset > m_startOffset) ? qMin(start + 1, len) : start;
*pRetVal = start - m_startOffset; // Returns the actually moved distance.
m_startOffset = start;
} else {
@@ -385,7 +394,7 @@ HRESULT QWindowsUiaTextRangeProvider::MoveEndpointByUnit(TextPatternRangeEndpoin
if (unit == TextUnit_Character) {
if (endpoint == TextPatternRangeEndpoint_Start) {
- int boundedValue = qBound(0, m_startOffset + count, len - 1);
+ int boundedValue = qBound(0, m_startOffset + count, len);
*pRetVal = boundedValue - m_startOffset;
m_startOffset = boundedValue;
m_endOffset = qBound(m_startOffset, m_endOffset, len);
@@ -517,6 +526,42 @@ HRESULT QWindowsUiaTextRangeProvider::unselect()
return S_OK;
}
+// helper method to retrieve the value of the given IAccessible2 text attribute,
+// or an empty string if not set
+QString QWindowsUiaTextRangeProvider::valueForIA2Attribute(QAccessibleTextInterface *textInterface,
+ const QString &key)
+{
+ Q_ASSERT(textInterface);
+
+ int startOffset;
+ int endOffset;
+ const QString attributes = textInterface->attributes(m_startOffset, &startOffset, &endOffset);
+ // don't report if attributes don't apply for the whole range
+ if (startOffset > m_startOffset || endOffset < m_endOffset)
+ return {};
+
+ for (auto attr : QStringTokenizer{attributes, u';'})
+ {
+ const QList<QStringView> items = attr.split(u':', Qt::SkipEmptyParts, Qt::CaseSensitive);
+ if (items.count() == 2 && items[0] == key)
+ return items[1].toString();
+ }
+
+ return {};
+}
+
+TextDecorationLineStyle QWindowsUiaTextRangeProvider::uiaLineStyleForIA2LineStyle(const QString &ia2LineStyle)
+{
+ if (ia2LineStyle == QStringLiteral("none"))
+ return TextDecorationLineStyle_None;
+ if (ia2LineStyle == QStringLiteral("single"))
+ return TextDecorationLineStyle_Single;
+ if (ia2LineStyle == QStringLiteral("double"))
+ return TextDecorationLineStyle_Double;
+
+ return TextDecorationLineStyle_Other;
+}
+
QT_END_NAMESPACE
#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h
index f7d28a34d2..a37429a603 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.h
@@ -13,7 +13,7 @@ QT_BEGIN_NAMESPACE
// Implements the Text Range control pattern provider. Used for text controls.
class QWindowsUiaTextRangeProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<ITextRangeProvider>
+ public QComObject<ITextRangeProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaTextRangeProvider)
public:
@@ -42,6 +42,8 @@ public:
private:
HRESULT unselect();
+ QString valueForIA2Attribute(QAccessibleTextInterface *textInterface, const QString &key);
+ TextDecorationLineStyle uiaLineStyleForIA2LineStyle(const QString &ia2LineStyle);
int m_startOffset;
int m_endOffset;
};
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h
index 742e26f6d6..17150dfbe0 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatoggleprovider.h
@@ -12,8 +12,7 @@
QT_BEGIN_NAMESPACE
// Implements the Toggle control pattern provider. Used for checkboxes.
-class QWindowsUiaToggleProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<IToggleProvider>
+class QWindowsUiaToggleProvider : public QWindowsUiaBaseProvider, public QComObject<IToggleProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaToggleProvider)
public:
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp
index 9287e89084..78ab3e890e 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp
@@ -176,6 +176,9 @@ long roleToControlTypeId(QAccessible::Role role)
{QAccessible::PageTabList, UIA_TabControlTypeId},
{QAccessible::Clock, UIA_CustomControlTypeId},
{QAccessible::Splitter, UIA_CustomControlTypeId},
+ {QAccessible::Paragraph, UIA_TextControlTypeId},
+ {QAccessible::WebDocument, UIA_DocumentControlTypeId},
+ {QAccessible::Heading, UIA_TextControlTypeId},
};
return mapping.value(role, UIA_CustomControlTypeId);
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.h
index 8fe8b1c6d7..bf90211cec 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.h
@@ -12,7 +12,7 @@
#include <QtGui/qaccessible.h>
#include <QtGui/qwindow.h>
#include <QtCore/qrect.h>
-#include <QtGui/private/qwindowsuiawrapper_p.h>
+#include "qwindowsuiautomation.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp
new file mode 100644
index 0000000000..1593a07202
--- /dev/null
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.cpp
@@ -0,0 +1,74 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include "qwindowsuiautomation.h"
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+
+template<typename T, typename... TArg>
+struct winapi_func
+{
+ using func_t = T(WINAPI*)(TArg...);
+ const func_t func;
+ const T error_value;
+#ifdef __GNUC__
+# pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
+ winapi_func(const char *lib_name, const char *func_name, func_t func_proto,
+ T error_value = T(__HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND))) :
+ func(reinterpret_cast<func_t>(GetProcAddress(LoadLibraryA(lib_name), func_name))),
+ error_value(error_value)
+ {
+ std::ignore = func_proto;
+ }
+#ifdef __GNUC__
+# pragma GCC diagnostic pop
+#endif
+ T invoke(TArg... arg)
+ {
+ if (!func)
+ return error_value;
+ return func(arg...);
+ }
+};
+
+#define FN(fn) #fn,fn
+
+BOOL WINAPI UiaClientsAreListening()
+{
+ static auto func = winapi_func("uiautomationcore", FN(UiaClientsAreListening), BOOL(false));
+ return func.invoke();
+}
+
+LRESULT WINAPI UiaReturnRawElementProvider(
+ HWND hwnd, WPARAM wParam, LPARAM lParam, IRawElementProviderSimple *el)
+{
+ static auto func = winapi_func("uiautomationcore", FN(UiaReturnRawElementProvider));
+ return func.invoke(hwnd, wParam, lParam, el);
+}
+
+HRESULT WINAPI UiaHostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **ppProvider)
+{
+ static auto func = winapi_func("uiautomationcore", FN(UiaHostProviderFromHwnd));
+ return func.invoke(hwnd, ppProvider);
+}
+
+HRESULT WINAPI UiaRaiseAutomationPropertyChangedEvent(
+ IRawElementProviderSimple *pProvider, PROPERTYID id, VARIANT oldValue, VARIANT newValue)
+{
+ static auto func = winapi_func("uiautomationcore", FN(UiaRaiseAutomationPropertyChangedEvent));
+ return func.invoke(pProvider, id, oldValue, newValue);
+}
+
+HRESULT WINAPI UiaRaiseAutomationEvent(IRawElementProviderSimple *pProvider, EVENTID id)
+{
+ static auto func = winapi_func("uiautomationcore", FN(UiaRaiseAutomationEvent));
+ return func.invoke(pProvider, id);
+}
+
+#endif // defined(__MINGW32__) || defined(__MINGW64__)
+
+#endif // QT_CONFIG(accessibility)
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h
new file mode 100644
index 0000000000..a192b9b0fb
--- /dev/null
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautomation.h
@@ -0,0 +1,70 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWINDOWSUIAUTOMATION_H
+#define QWINDOWSUIAUTOMATION_H
+
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
+
+#include <uiautomation.h>
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+
+#define UIA_SelectionPattern2Id 10034
+#define UIA_IsReadOnlyAttributeId 40015
+#define UIA_StrikethroughStyleAttributeId 40026
+#define UIA_CaretPositionAttributeId 40038
+
+enum CaretPosition {
+ CaretPosition_Unknown = 0,
+ CaretPosition_EndOfLine = 1,
+ CaretPosition_BeginningOfLine = 2
+};
+
+enum TextDecorationLineStyle {
+ TextDecorationLineStyle_None = 0,
+ TextDecorationLineStyle_Single = 1,
+ TextDecorationLineStyle_WordsOnly = 2,
+ TextDecorationLineStyle_Double = 3,
+ TextDecorationLineStyle_Dot = 4,
+ TextDecorationLineStyle_Dash = 5,
+ TextDecorationLineStyle_DashDot = 6,
+ TextDecorationLineStyle_DashDotDot = 7,
+ TextDecorationLineStyle_Wavy = 8,
+ TextDecorationLineStyle_ThickSingle = 9,
+ TextDecorationLineStyle_DoubleWavy = 11,
+ TextDecorationLineStyle_ThickWavy = 12,
+ TextDecorationLineStyle_LongDash = 13,
+ TextDecorationLineStyle_ThickDash = 14,
+ TextDecorationLineStyle_ThickDashDot = 15,
+ TextDecorationLineStyle_ThickDashDotDot = 16,
+ TextDecorationLineStyle_ThickDot = 17,
+ TextDecorationLineStyle_ThickLongDash = 18,
+ TextDecorationLineStyle_Other = -1
+};
+
+BOOL WINAPI UiaClientsAreListening();
+
+#ifndef __ISelectionProvider2_INTERFACE_DEFINED__
+#define __ISelectionProvider2_INTERFACE_DEFINED__
+DEFINE_GUID(IID_ISelectionProvider2, 0x14f68475, 0xee1c, 0x44f6, 0xa8, 0x69, 0xd2, 0x39, 0x38, 0x1f, 0x0f, 0xe7);
+MIDL_INTERFACE("14f68475-ee1c-44f6-a869-d239381f0fe7")
+ISelectionProvider2 : public ISelectionProvider
+{
+public:
+ virtual HRESULT STDMETHODCALLTYPE get_FirstSelectedItem(__RPC__deref_out_opt IRawElementProviderSimple **retVal) = 0;
+ virtual HRESULT STDMETHODCALLTYPE get_LastSelectedItem(__RPC__deref_out_opt IRawElementProviderSimple **retVal) = 0;
+ virtual HRESULT STDMETHODCALLTYPE get_CurrentSelectedItem(__RPC__deref_out_opt IRawElementProviderSimple **retVal) = 0;
+ virtual HRESULT STDMETHODCALLTYPE get_ItemCount(__RPC__out int *retVal) = 0;
+};
+#ifdef __CRT_UUID_DECL
+__CRT_UUID_DECL(ISelectionProvider2, 0x14f68475, 0xee1c, 0x44f6, 0xa8, 0x69, 0xd2, 0x39, 0x38, 0x1f, 0x0f, 0xe7)
+#endif
+#endif // __ISelectionProvider2_INTERFACE_DEFINED__
+
+#endif // defined(__MINGW32__) || defined(__MINGW64__)
+
+#endif // QT_CONFIG(accessibility)
+
+#endif // QWINDOWSUIAUTOMATION_H
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h
index 2f52019d33..8c0a6b8ee7 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiavalueprovider.h
@@ -13,8 +13,7 @@ QT_BEGIN_NAMESPACE
// Implements the Value control pattern provider.
// Supported for all controls that can return text(QAccessible::Value).
-class QWindowsUiaValueProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<IValueProvider>
+class QWindowsUiaValueProvider : public QWindowsUiaBaseProvider, public QComObject<IValueProvider>
{
Q_DISABLE_COPY_MOVE(QWindowsUiaValueProvider)
public:
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.h
index e277b3f5c5..89a1655232 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.h
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.h
@@ -11,8 +11,7 @@
QT_BEGIN_NAMESPACE
-class QWindowsUiaWindowProvider : public QWindowsUiaBaseProvider,
- public QWindowsComBase<IWindowProvider>
+class QWindowsUiaWindowProvider : public QWindowsUiaBaseProvider, public QComObject<IWindowProvider>
{
Q_DISABLE_COPY(QWindowsUiaWindowProvider)
public:
diff --git a/src/plugins/platforms/xcb/CMakeLists.txt b/src/plugins/platforms/xcb/CMakeLists.txt
index 17e723d607..e8fb442dd4 100644
--- a/src/plugins/platforms/xcb/CMakeLists.txt
+++ b/src/plugins/platforms/xcb/CMakeLists.txt
@@ -5,6 +5,11 @@
## XcbQpaPrivate Module:
#####################################################################
+if(GCC)
+ # Work around GCC ABI issues
+ add_compile_options(-Wno-psabi)
+endif()
+
qt_internal_add_module(XcbQpaPrivate
CONFIG_MODULE_NAME xcb_qpa_lib
INTERNAL_MODULE
@@ -57,7 +62,6 @@ qt_internal_add_module(XcbQpaPrivate
XCB::SYNC
XCB::XCB
XCB::XFIXES
- # XCB::XINPUT # special case remove handled below
XCB::XKB
XKB::XKB
NO_UNITY_BUILD # X11 define clashes
@@ -68,11 +72,6 @@ qt_disable_apple_app_extension_api_only(XcbQpaPrivate)
## Scopes:
#####################################################################
-qt_internal_extend_target(XcbQpaPrivate CONDITION QT_FEATURE_opengl
- PUBLIC_LIBRARIES
- Qt::OpenGLPrivate
-)
-
qt_internal_extend_target(XcbQpaPrivate CONDITION QT_FEATURE_glib
LIBRARIES
GLIB2::GLIB2
@@ -178,5 +177,5 @@ qt_internal_add_plugin(QXcbIntegrationPlugin
add_subdirectory(gl_integrations)
if(OFF)
- add_subdirectory(xcb-static) # special case TODO: xcb-static sub folder
+ add_subdirectory(xcb-static)
endif()
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp
index 1e93ea6805..133b992cd9 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.cpp
@@ -58,6 +58,7 @@ std::optional<VisualInfo> getVisualInfo(xcb_screen_t *screen,
QXcbEglIntegration::QXcbEglIntegration()
: m_connection(nullptr)
, m_egl_display(EGL_NO_DISPLAY)
+ , m_using_platform_display(false)
{
qCDebug(lcQpaGl) << "Xcb EGL gl-integration created";
}
@@ -80,6 +81,7 @@ bool QXcbEglIntegration::initialize(QXcbConnection *connection)
m_egl_display = streamFuncs.get_platform_display(EGL_PLATFORM_X11_KHR,
m_connection->xlib_display(),
nullptr);
+ m_using_platform_display = true;
}
#if QT_CONFIG(egl_x11)
@@ -92,16 +94,19 @@ bool QXcbEglIntegration::initialize(QXcbConnection *connection)
m_egl_display = streamFuncs.get_platform_display(EGL_PLATFORM_XCB_KHR,
reinterpret_cast<void *>(connection->xcb_connection()),
nullptr);
+ m_using_platform_display = true;
}
#endif
EGLint major, minor;
bool success = eglInitialize(m_egl_display, &major, &minor);
+#if QT_CONFIG(egl_x11)
if (!success) {
m_egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
qCDebug(lcQpaGl) << "Xcb EGL gl-integration retrying with display" << m_egl_display;
success = eglInitialize(m_egl_display, &major, &minor);
}
+#endif
m_native_interface_handler.reset(new QXcbEglNativeInterfaceHandler(connection->nativeInterface()));
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.h b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.h
index ff0804678f..7caf4304bc 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.h
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglintegration.h
@@ -39,10 +39,13 @@ public:
EGLDisplay eglDisplay() const { return m_egl_display; }
+ bool usingPlatformDisplay() const { return m_using_platform_display; }
+
xcb_visualid_t getCompatibleVisualId(xcb_screen_t *screen, EGLConfig config) const;
private:
QXcbConnection *m_connection;
EGLDisplay m_egl_display;
+ bool m_using_platform_display;
QScopedPointer<QXcbEglNativeInterfaceHandler> m_native_interface_handler;
};
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp
index 4d87b08db8..bf2ceb96f4 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_egl/qxcbeglwindow.cpp
@@ -7,6 +7,10 @@
#include <QtGui/private/qeglconvenience_p.h>
+#ifndef EGL_EXT_platform_base
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
+#endif
+
QT_BEGIN_NAMESPACE
QXcbEglWindow::QXcbEglWindow(QWindow *window, QXcbEglIntegration *glIntegration)
@@ -42,7 +46,20 @@ void QXcbEglWindow::create()
{
QXcbWindow::create();
+ // this is always true without egl_x11
+ if (m_glIntegration->usingPlatformDisplay()) {
+ auto createPlatformWindowSurface = reinterpret_cast<PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC>(
+ eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT"));
+ m_surface = createPlatformWindowSurface(m_glIntegration->eglDisplay(),
+ m_config,
+ reinterpret_cast<void *>(&m_window),
+ nullptr);
+ return;
+ }
+
+#if QT_CONFIG(egl_x11)
m_surface = eglCreateWindowSurface(m_glIntegration->eglDisplay(), m_config, m_window, nullptr);
+#endif
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp
index 96a19552a5..d523eecc5a 100644
--- a/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp
+++ b/src/plugins/platforms/xcb/nativepainting/qbackingstore_x11.cpp
@@ -16,10 +16,6 @@
#include <X11/Xlib.h>
#undef register
-#ifndef None
-#define None 0L
-#endif
-
QT_BEGIN_NAMESPACE
QXcbNativeBackingStore::QXcbNativeBackingStore(QWindow *window)
@@ -78,11 +74,8 @@ void QXcbNativeBackingStore::flush(QWindow *window, const QRegion &region, const
XRenderSetPictureClipRectangles(display(), dstPic, 0, 0, clipRects.constData(), clipRects.size());
- XRenderComposite(display(), PictOpSrc, srcPic, None, dstPic,
- br.x() + offset.x(), br.y() + offset.y(),
- 0, 0,
- br.x(), br.y(),
- br.width(), br.height());
+ XRenderComposite(display(), PictOpSrc, srcPic, 0L /*None*/, dstPic, br.x() + offset.x(),
+ br.y() + offset.y(), 0, 0, br.x(), br.y(), br.width(), br.height());
XRenderFreePicture(display(), dstPic);
}
diff --git a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp
index f630f538aa..743ff92654 100644
--- a/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp
+++ b/src/plugins/platforms/xcb/nativepainting/qpaintengine_x11.cpp
@@ -2134,7 +2134,7 @@ void QX11PaintEngine::drawPixmap(const QRectF &r, const QPixmap &px, const QRect
XFillRectangle(d->dpy, d->hd, d->gc, x, y, sw, sh);
restore_clip = true;
} else if (mono_dst && !mono_src) {
- QBitmap bitmap(pixmap);
+ QBitmap bitmap = QBitmap::fromPixmap(pixmap);
XCopyArea(d->dpy, qt_x11PixmapHandle(bitmap), d->hd, d->gc, sx, sy, sw, sh, x, y);
} else {
XCopyArea(d->dpy, qt_x11PixmapHandle(pixmap), d->hd, d->gc, sx, sy, sw, sh, x, y);
diff --git a/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp b/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp
index 186a3cf9d7..a4e820ea92 100644
--- a/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp
+++ b/src/plugins/platforms/xcb/nativepainting/qpixmap_x11.cpp
@@ -1314,7 +1314,7 @@ QBitmap QX11PlatformPixmap::mask() const
#endif
if (d == 1) {
QX11PlatformPixmap *that = const_cast<QX11PlatformPixmap*>(this);
- mask = QPixmap(that);
+ mask = QBitmap::fromPixmap(QPixmap(that));
} else {
mask = mask_to_bitmap(xinfo.screen());
}
diff --git a/src/plugins/platforms/xcb/qxcbatom.cpp b/src/plugins/platforms/xcb/qxcbatom.cpp
index 09b1fe8a9d..dd5596653c 100644
--- a/src/plugins/platforms/xcb/qxcbatom.cpp
+++ b/src/plugins/platforms/xcb/qxcbatom.cpp
@@ -111,6 +111,7 @@ static const char *xcb_atomnames = {
"_NET_WM_WINDOW_TYPE_NORMAL\0"
"_KDE_NET_WM_WINDOW_TYPE_OVERRIDE\0"
+ "_KDE_NET_WM_DESKTOP_FILE\0"
"_KDE_NET_WM_FRAME_STRUT\0"
"_NET_FRAME_EXTENTS\0"
@@ -196,6 +197,7 @@ static const char *xcb_atomnames = {
"_COMPIZ_DECOR_REQUEST\0"
"_COMPIZ_DECOR_DELETE_PIXMAP\0"
"_COMPIZ_TOOLKIT_ACTION\0"
+ "_GTK_APPLICATION_ID\0"
"_GTK_LOAD_ICONTHEMES\0"
"AT_SPI_BUS\0"
"EDID\0"
@@ -230,8 +232,10 @@ void QXcbAtom::initializeAllAtoms(xcb_connection_t *connection) {
for (i = 0; i < QXcbAtom::NAtoms; ++i) {
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(connection, cookies[i], nullptr);
- m_allAtoms[i] = reply->atom;
- free(reply);
+ if (reply) {
+ m_allAtoms[i] = reply->atom;
+ free(reply);
+ }
}
}
diff --git a/src/plugins/platforms/xcb/qxcbatom.h b/src/plugins/platforms/xcb/qxcbatom.h
index 07dad31d45..bc677eaf3e 100644
--- a/src/plugins/platforms/xcb/qxcbatom.h
+++ b/src/plugins/platforms/xcb/qxcbatom.h
@@ -112,6 +112,7 @@ public:
Atom_NET_WM_WINDOW_TYPE_NORMAL,
Atom_KDE_NET_WM_WINDOW_TYPE_OVERRIDE,
+ Atom_KDE_NET_WM_DESKTOP_FILE,
Atom_KDE_NET_WM_FRAME_STRUT,
Atom_NET_FRAME_EXTENTS,
@@ -199,6 +200,7 @@ public:
Atom_COMPIZ_DECOR_REQUEST,
Atom_COMPIZ_DECOR_DELETE_PIXMAP,
Atom_COMPIZ_TOOLKIT_ACTION,
+ Atom_GTK_APPLICATION_ID,
Atom_GTK_LOAD_ICONTHEMES,
AtomAT_SPI_BUS,
diff --git a/src/plugins/platforms/xcb/qxcbbackingstore.cpp b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
index 0659cf9fc4..8353fac6a9 100644
--- a/src/plugins/platforms/xcb/qxcbbackingstore.cpp
+++ b/src/plugins/platforms/xcb/qxcbbackingstore.cpp
@@ -173,7 +173,7 @@ void QXcbBackingStoreImage::init(const QSize &size, uint depth, QImage::Format f
m_qimage_format = format;
m_hasAlpha = QImage::toPixelFormat(m_qimage_format).alphaUsage() == QPixelFormat::UsesAlpha;
if (!m_hasAlpha)
- m_qimage_format = qt_maybeAlphaVersionWithSameDepth(m_qimage_format);
+ m_qimage_format = qt_maybeDataCompatibleAlphaVersion(m_qimage_format);
memset(&m_shm_info, 0, sizeof m_shm_info);
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 2e103b0eb2..1056c6408f 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -92,9 +92,9 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
const int focusInDelay = 100;
m_focusInTimer.setSingleShot(true);
m_focusInTimer.setInterval(focusInDelay);
- m_focusInTimer.callOnTimeout([]() {
+ m_focusInTimer.callOnTimeout(this, []() {
// No FocusIn events for us, proceed with FocusOut normally.
- QWindowSystemInterface::handleWindowActivated(nullptr, Qt::ActiveWindowFocusReason);
+ QWindowSystemInterface::handleFocusWindowChanged(nullptr, Qt::ActiveWindowFocusReason);
});
sync();
@@ -1141,13 +1141,6 @@ Qt::MouseButtons QXcbConnection::queryMouseButtons() const
return translateMouseButtons(stateMask);
}
-Qt::KeyboardModifiers QXcbConnection::queryKeyboardModifiers() const
-{
- int stateMask = 0;
- QXcbCursor::queryPointer(connection(), nullptr, nullptr, &stateMask);
- return keyboard()->translateModifiers(stateMask);
-}
-
QXcbGlIntegration *QXcbConnection::glIntegration() const
{
if (m_glIntegrationInitialized)
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 24e684866d..527744fe81 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -183,7 +183,6 @@ public:
QXcbSystemTrayTracker *systemTrayTracker() const;
Qt::MouseButtons queryMouseButtons() const;
- Qt::KeyboardModifiers queryKeyboardModifiers() const;
bool isUserInputEvent(xcb_generic_event_t *event) const;
@@ -367,7 +366,7 @@ Q_DECLARE_TYPEINFO(QXcbConnection::TabletData, Q_RELOCATABLE_TYPE);
class QXcbConnectionGrabber
{
public:
- QXcbConnectionGrabber(QXcbConnection *connection);
+ Q_NODISCARD_CTOR QXcbConnectionGrabber(QXcbConnection *connection);
~QXcbConnectionGrabber();
void release();
private:
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index efcea4f93d..4f62a1880b 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -241,6 +241,7 @@ void QXcbConnection::xi2SetupSlavePointerDevice(void *info, bool removeExisting,
const QByteArray nameRaw = QByteArray(xcb_input_xi_device_info_name(deviceInfo),
xcb_input_xi_device_info_name_length(deviceInfo));
const QString name = QString::fromUtf8(nameRaw);
+ m_xiSlavePointerIds.append(deviceInfo->deviceid);
qCDebug(lcQpaXInputDevices) << "input device " << name << "ID" << deviceInfo->deviceid;
#if QT_CONFIG(tabletevent)
TabletData tabletData;
@@ -453,10 +454,6 @@ void QXcbConnection::xi2SetupSlavePointerDevice(void *info, bool removeExisting,
*/
void QXcbConnection::xi2SetupDevices()
{
-#if QT_CONFIG(tabletevent)
- m_tabletData.clear();
-#endif
- m_touchDevices.clear();
m_xiMasterPointerIds.clear();
auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, xcb_connection(), XCB_INPUT_DEVICE_ALL);
@@ -468,14 +465,13 @@ void QXcbConnection::xi2SetupDevices()
// Start with all known devices; remove the ones that still exist.
// Afterwards, previousDevices will be the list of those that we should delete.
QList<const QInputDevice *> previousDevices = QInputDevice::devices();
+ // Return true if the device with the given systemId is new;
+ // otherwise remove it from previousDevices and return false.
auto newOrKeep = [&previousDevices](qint64 systemId) {
- for (auto it = previousDevices.constBegin(); it != previousDevices.constEnd(); ++it) {
- if ((*it)->systemId() == systemId) {
- previousDevices.erase(it); // it's a keeper
- return false; // not new
- }
- }
- return true; // it's really new
+ // if nothing is removed from previousDevices, it's a new device
+ return !previousDevices.removeIf([systemId](const QInputDevice *dev) {
+ return dev->systemId() == systemId;
+ });
};
// XInput doesn't provide a way to identify "seats"; but each device has an attachment to another device.
@@ -540,6 +536,11 @@ void QXcbConnection::xi2SetupDevices()
// previousDevices is now the list of those that are no longer found
qCDebug(lcQpaXInputDevices) << "removed" << previousDevices;
+ for (auto it = previousDevices.constBegin(); it != previousDevices.constEnd(); ++it) {
+ const auto id = (*it)->systemId();
+ m_xiSlavePointerIds.removeAll(id);
+ m_touchDevices.remove(id);
+ }
qDeleteAll(previousDevices);
if (m_xiMasterPointerIds.size() > 1)
@@ -765,7 +766,7 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
if (auto device = QPointingDevicePrivate::pointingDeviceById(sourceDeviceId))
xi2HandleScrollEvent(event, device);
else
- qCWarning(lcQpaXInputEvents) << "scroll event from unregistered device" << Qt::hex << sourceDeviceId;
+ qCDebug(lcQpaXInputEvents) << "scroll event from unregistered device" << sourceDeviceId;
if (xiDeviceEvent) {
switch (xiDeviceEvent->event_type) {
@@ -812,7 +813,16 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo
{
auto *xiDeviceEvent = reinterpret_cast<xcb_input_touch_begin_event_t *>(xiDevEvent);
TouchDeviceData *dev = touchDeviceForId(xiDeviceEvent->sourceid);
- Q_ASSERT(dev);
+ if (!dev) {
+ qCDebug(lcQpaXInputEvents) << "didn't find the dev for given sourceid - " << xiDeviceEvent->sourceid
+ << ", try to repopulate xi2 devices";
+ xi2SetupDevices();
+ dev = touchDeviceForId(xiDeviceEvent->sourceid);
+ if (!dev) {
+ qCDebug(lcQpaXInputEvents) << "still can't find the dev for it, give up.";
+ return;
+ }
+ }
const bool firstTouch = dev->touchPoints.isEmpty();
if (xiDeviceEvent->event_type == XCB_INPUT_TOUCH_BEGIN) {
QWindowSystemInterface::TouchPoint tp;
@@ -1274,6 +1284,9 @@ void QXcbConnection::xi2HandleDeviceChangedEvent(void *event)
auto *xiEvent = reinterpret_cast<xcb_input_device_changed_event_t *>(event);
switch (xiEvent->reason) {
case XCB_INPUT_CHANGE_REASON_DEVICE_CHANGE: {
+ // Don't call xi2SetupSlavePointerDevice() again for an already-known device, and never for a master.
+ if (m_xiMasterPointerIds.contains(xiEvent->deviceid) || m_xiSlavePointerIds.contains(xiEvent->deviceid))
+ return;
auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, xcb_connection(), xiEvent->sourceid);
if (!reply || reply->num_infos <= 0)
return;
@@ -1525,6 +1538,7 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD
if (!tool && ptr[_WACSER_TOOL_SERIAL])
tool = ptr[_WACSER_TOOL_SERIAL];
+ QWindow *win = nullptr; // TODO QTBUG-111400 get the position somehow, then the window
// The property change event informs us which tool is in proximity or which one left proximity.
if (tool) {
const QPointingDevice *dev = tabletToolInstance(nullptr, tabletData->name,
@@ -1533,22 +1547,19 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD
tabletData->inProximity = true;
tabletData->tool = dev->type();
tabletData->serialId = qint64(ptr[_WACSER_TOOL_SERIAL]);
- QWindowSystemInterface::handleTabletEnterProximityEvent(ev->time,
- int(tabletData->tool), int(tabletData->pointerType), tabletData->serialId);
+ QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(win, ev->time, dev, true); // enter
} else {
tool = ptr[_WACSER_LAST_TOOL_ID];
// Workaround for http://sourceforge.net/p/linuxwacom/bugs/246/
// e.g. on Thinkpad Helix, tool ID will be 0 and serial will be 1
if (!tool)
tool = ptr[_WACSER_LAST_TOOL_SERIAL];
- const QInputDevice *dev = QInputDevicePrivate::fromId(tabletData->deviceId);
+ auto *dev = qobject_cast<const QPointingDevice *>(QInputDevicePrivate::fromId(tabletData->deviceId));
Q_ASSERT(dev);
tabletData->tool = dev->type();
tabletData->inProximity = false;
tabletData->serialId = qint64(ptr[_WACSER_LAST_TOOL_SERIAL]);
- // TODO why doesn't it just take QPointingDevice*
- QWindowSystemInterface::handleTabletLeaveProximityEvent(ev->time,
- int(tabletData->tool), int(tabletData->pointerType), tabletData->serialId);
+ QWindowSystemInterface::handleTabletEnterLeaveProximityEvent(win, ev->time, dev, false); // leave
}
// TODO maybe have a hash of tabletData->deviceId to device data so we can
// look up the tablet name here, and distinguish multiple tablets
diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp
index 8f087edc9b..dc9ed46956 100644
--- a/src/plugins/platforms/xcb/qxcbcursor.cpp
+++ b/src/plugins/platforms/xcb/qxcbcursor.cpp
@@ -10,6 +10,7 @@
#include <QtGui/QWindow>
#include <QtGui/QBitmap>
#include <QtGui/private/qguiapplication_p.h>
+#include <qpa/qplatformtheme.h>
#if QT_CONFIG(xcb_xlib)
#include <X11/cursorfont.h>
@@ -288,6 +289,13 @@ QXcbCursor::~QXcbCursor()
xcb_cursor_context_free(m_cursorContext);
}
+QSize QXcbCursor::size() const
+{
+ if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
+ return theme->themeHint(QPlatformTheme::MouseCursorSize).toSize();
+ return QSize(24, 24);
+}
+
void QXcbCursor::updateContext()
{
if (m_cursorContext)
diff --git a/src/plugins/platforms/xcb/qxcbcursor.h b/src/plugins/platforms/xcb/qxcbcursor.h
index 14958f824b..bf26861e8f 100644
--- a/src/plugins/platforms/xcb/qxcbcursor.h
+++ b/src/plugins/platforms/xcb/qxcbcursor.h
@@ -48,6 +48,8 @@ public:
QPoint pos() const override;
void setPos(const QPoint &pos) override;
+ QSize size() const override;
+
void updateContext();
static void queryPointer(QXcbConnection *c, QXcbVirtualDesktop **virtualDesktop, QPoint *pos, int *keybMask = nullptr);
diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp
index 3ef37e85c5..6e5dd770b9 100644
--- a/src/plugins/platforms/xcb/qxcbdrag.cpp
+++ b/src/plugins/platforms/xcb/qxcbdrag.cpp
@@ -5,6 +5,7 @@
#include <xcb/xcb.h>
#include "qxcbconnection.h"
#include "qxcbclipboard.h"
+#include "qxcbkeyboard.h"
#include "qxcbmime.h"
#include "qxcbwindow.h"
#include "qxcbscreen.h"
@@ -27,6 +28,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::Literals::StringLiterals;
+
const int xdnd_version = 5;
static inline xcb_window_t xcb_window(QPlatformWindow *w)
@@ -459,7 +462,7 @@ void QXcbDrag::move(const QPoint &globalPos, Qt::MouseButtons b, Qt::KeyboardMod
static const bool isUnity = qgetenv("XDG_CURRENT_DESKTOP").toLower() == "unity";
if (isUnity && xdndCollectionWindow == XCB_NONE) {
QString name = QXcbWindow::windowTitle(connection(), target);
- if (name == QStringLiteral("XdndCollectionWindowImp"))
+ if (name == "XdndCollectionWindowImp"_L1)
xdndCollectionWindow = target;
}
if (target == xdndCollectionWindow) {
@@ -766,7 +769,7 @@ void QXcbDrag::handle_xdnd_position(QPlatformWindow *w, const xcb_client_message
}
auto buttons = currentDrag() ? b : connection()->queryMouseButtons();
- auto modifiers = currentDrag() ? mods : connection()->queryKeyboardModifiers();
+ auto modifiers = currentDrag() ? mods : connection()->keyboard()->queryKeyboardModifiers();
QPlatformDragQtResponse qt_response = QWindowSystemInterface::handleDrag(
w->window(), dropData, p, supported_actions, buttons, modifiers);
@@ -1006,7 +1009,7 @@ void QXcbDrag::handleDrop(QPlatformWindow *, const xcb_client_message_event_t *e
return;
auto buttons = currentDrag() ? b : connection()->queryMouseButtons();
- auto modifiers = currentDrag() ? mods : connection()->queryKeyboardModifiers();
+ auto modifiers = currentDrag() ? mods : connection()->keyboard()->queryKeyboardModifiers();
QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(
currentWindow.data(), dropData, currentPosition, supported_drop_actions,
@@ -1231,7 +1234,7 @@ void QXcbDrag::handleSelectionRequest(const xcb_selection_request_event_t *event
bool QXcbDrag::dndEnable(QXcbWindow *w, bool on)
{
- qCDebug(lcQpaXDnd) << "dndEnable" << w << on;
+ qCDebug(lcQpaXDnd) << "dndEnable" << static_cast<QPlatformWindow *>(w) << on;
// Windows announce that they support the XDND protocol by creating a window property XdndAware.
if (on) {
QXcbWindow *window = nullptr;
diff --git a/src/plugins/platforms/xcb/qxcbimage.h b/src/plugins/platforms/xcb/qxcbimage.h
index e550102881..c022fae639 100644
--- a/src/plugins/platforms/xcb/qxcbimage.h
+++ b/src/plugins/platforms/xcb/qxcbimage.h
@@ -5,7 +5,6 @@
#define QXCBIMAGE_H
#include "qxcbscreen.h"
-#include <QtCore/QPair>
#include <QtGui/QImage>
#include <QtGui/QPixmap>
#include <xcb/xcb_image.h>
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index e32891e814..4dafae31e3 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -93,10 +93,17 @@ static bool runningUnderDebugger()
#endif
}
+class QXcbUnixServices : public QGenericUnixServices
+{
+public:
+ QString portalWindowIdentifier(QWindow *window) override;
+};
+
+
QXcbIntegration *QXcbIntegration::m_instance = nullptr;
QXcbIntegration::QXcbIntegration(const QStringList &parameters, int &argc, char **argv)
- : m_services(new QGenericUnixServices)
+ : m_services(new QXcbUnixServices)
, m_instanceName(nullptr)
, m_canGrab(true)
, m_defaultVisualId(UINT_MAX)
@@ -197,7 +204,7 @@ QPlatformPixmap *QXcbIntegration::createPlatformPixmap(QPlatformPixmap::PixelTyp
QPlatformWindow *QXcbIntegration::createPlatformWindow(QWindow *window) const
{
QXcbGlIntegration *glIntegration = nullptr;
- const bool isTrayIconWindow = QXcbWindow::isTrayIconWindow(window);;
+ const bool isTrayIconWindow = QXcbWindow::isTrayIconWindow(window);
if (window->type() != Qt::Desktop && !isTrayIconWindow) {
if (window->supportsOpenGL()) {
glIntegration = connection()->glIntegration();
@@ -337,11 +344,12 @@ void QXcbIntegration::initialize()
const auto defaultInputContext = "compose"_L1;
// Perform everything that may potentially need the event dispatcher (timers, socket
// notifiers) here instead of the constructor.
- QString icStr = QPlatformInputContextFactory::requested();
- if (icStr.isNull())
- icStr = defaultInputContext;
- m_inputContext.reset(QPlatformInputContextFactory::create(icStr));
- if (!m_inputContext && icStr != defaultInputContext && icStr != "none"_L1)
+ auto icStrs = QPlatformInputContextFactory::requested();
+ if (icStrs.isEmpty())
+ icStrs = { defaultInputContext };
+ m_inputContext.reset(QPlatformInputContextFactory::create(icStrs));
+ if (!m_inputContext && !icStrs.contains(defaultInputContext)
+ && icStrs != QStringList{"none"_L1})
m_inputContext.reset(QPlatformInputContextFactory::create(defaultInputContext));
connection()->keyboard()->initialize();
@@ -422,14 +430,9 @@ QPlatformServices *QXcbIntegration::services() const
return m_services.data();
}
-Qt::KeyboardModifiers QXcbIntegration::queryKeyboardModifiers() const
-{
- return m_connection->queryKeyboardModifiers();
-}
-
-QList<int> QXcbIntegration::possibleKeys(const QKeyEvent *e) const
+QPlatformKeyMapper *QXcbIntegration::keyMapper() const
{
- return m_connection->keyboard()->possibleKeys(e);
+ return m_connection->keyboard();
}
QStringList QXcbIntegration::themeNames() const
@@ -472,21 +475,23 @@ QVariant QXcbIntegration::styleHint(QPlatformIntegration::StyleHint hint) const
case QPlatformIntegration::StartDragVelocity:
case QPlatformIntegration::UseRtlExtensions:
case QPlatformIntegration::PasswordMaskCharacter:
+ case QPlatformIntegration::FlickMaximumVelocity:
+ case QPlatformIntegration::FlickDeceleration:
// TODO using various xcb, gnome or KDE settings
break; // Not implemented, use defaults
+ case QPlatformIntegration::FlickStartDistance:
case QPlatformIntegration::StartDragDistance: {
RETURN_VALID_XSETTINGS(xsNetDndDragThreshold);
-
// The default (in QPlatformTheme::defaultThemeHint) is 10 pixels, but
// on a high-resolution screen it makes sense to increase it.
- qreal dpi = 100.0;
+ qreal dpi = 100;
if (const QXcbScreen *screen = connection()->primaryScreen()) {
if (screen->logicalDpi().first > dpi)
dpi = screen->logicalDpi().first;
if (screen->logicalDpi().second > dpi)
dpi = screen->logicalDpi().second;
}
- return 10.0 * dpi / 100.0;
+ return (hint == QPlatformIntegration::FlickStartDistance ? qreal(15) : qreal(10)) * dpi / qreal(100);
}
case QPlatformIntegration::ShowIsFullScreen:
// X11 always has support for windows, but the
@@ -585,4 +590,15 @@ QPlatformVulkanInstance *QXcbIntegration::createPlatformVulkanInstance(QVulkanIn
}
#endif
+void QXcbIntegration::setApplicationBadge(qint64 number)
+{
+ auto unixServices = dynamic_cast<QGenericUnixServices *>(services());
+ unixServices->setApplicationBadge(number);
+}
+
+QString QXcbUnixServices::portalWindowIdentifier(QWindow *window)
+{
+ return "x11:"_L1 + QString::number(window->winId(), 16);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h
index abdfe7112c..a1e0c3f3e1 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.h
+++ b/src/plugins/platforms/xcb/qxcbintegration.h
@@ -74,8 +74,7 @@ public:
QPlatformServices *services() const override;
- Qt::KeyboardModifiers queryKeyboardModifiers() const override;
- QList<int> possibleKeys(const QKeyEvent *e) const override;
+ QPlatformKeyMapper *keyMapper() const override;
QStringList themeNames() const override;
QPlatformTheme *createPlatformTheme(const QString &name) const override;
@@ -102,6 +101,8 @@ public:
static QXcbIntegration *instance() { return m_instance; }
+ void setApplicationBadge(qint64 number) override;
+
private:
QXcbConnection *m_connection = nullptr;
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index 0666fac735..17da54bc7a 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -3,6 +3,7 @@
#include "qxcbkeyboard.h"
#include "qxcbwindow.h"
#include "qxcbscreen.h"
+#include "qxcbcursor.h"
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatforminputcontext.h>
@@ -377,9 +378,18 @@ void QXcbKeyboard::updateKeymap()
QXkbCommon::verifyHasLatinLayout(m_xkbKeymap.get());
}
-QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const
+QList<QKeyCombination> QXcbKeyboard::possibleKeyCombinations(const QKeyEvent *event) const
{
- return QXkbCommon::possibleKeys(m_xkbState.get(), event, m_superAsMeta, m_hyperAsMeta);
+ return QXkbCommon::possibleKeyCombinations(
+ m_xkbState.get(), event, m_superAsMeta, m_hyperAsMeta);
+}
+
+Qt::KeyboardModifiers QXcbKeyboard::queryKeyboardModifiers() const
+{
+ // FIXME: Should we base this on m_xkbState?
+ int stateMask = 0;
+ QXcbCursor::queryPointer(connection(), nullptr, nullptr, &stateMask);
+ return translateModifiers(stateMask);
}
void QXcbKeyboard::updateXKBState(xcb_xkb_state_notify_event_t *state)
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h
index 15b08fbead..62d9268c64 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.h
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.h
@@ -14,11 +14,13 @@
#include <QtGui/private/qxkbcommon_p.h>
#include <xkbcommon/xkbcommon-x11.h>
+#include <qpa/qplatformkeymapper.h>
+
#include <QEvent>
QT_BEGIN_NAMESPACE
-class QXcbKeyboard : public QXcbObject
+class QXcbKeyboard : public QXcbObject, public QPlatformKeyMapper
{
public:
QXcbKeyboard(QXcbConnection *connection);
@@ -34,7 +36,9 @@ public:
Qt::KeyboardModifiers translateModifiers(int s) const;
void updateKeymap(xcb_mapping_notify_event_t *event);
void updateKeymap();
- QList<int> possibleKeys(const QKeyEvent *event) const;
+
+ QList<QKeyCombination> possibleKeyCombinations(const QKeyEvent *event) const override;
+ Qt::KeyboardModifiers queryKeyboardModifiers() const override;
void updateXKBMods();
xkb_mod_mask_t xkbModMask(quint16 state);
diff --git a/src/plugins/platforms/xcb/qxcbmime.cpp b/src/plugins/platforms/xcb/qxcbmime.cpp
index 9d62423071..860d195d13 100644
--- a/src/plugins/platforms/xcb/qxcbmime.cpp
+++ b/src/plugins/platforms/xcb/qxcbmime.cpp
@@ -79,8 +79,7 @@ bool QXcbMime::mimeDataForAtom(QXcbConnection *connection, xcb_atom_t a, QMimeDa
if (atomName == "text/uri-list"_L1
&& connection->atomName(a) == "text/x-moz-url") {
const QString mozUri = QLatin1StringView(data->split('\n').constFirst()) + u'\n';
- *data = QByteArray(reinterpret_cast<const char *>(mozUri.data()),
- mozUri.size() * 2);
+ data->assign({reinterpret_cast<const char *>(mozUri.data()), mozUri.size() * 2});
} else if (atomName == "application/x-color"_L1)
*dataFormat = 16;
ret = true;
@@ -156,7 +155,7 @@ QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a,
const quint8 byte1 = data.at(1);
if ((byte0 == 0xff && byte1 == 0xfe) || (byte0 == 0xfe && byte1 == 0xff)
|| (byte0 != 0 && byte1 == 0) || (byte0 == 0 && byte1 != 0)) {
- const QString str = QString::fromUtf16(
+ const QStringView str(
reinterpret_cast<const char16_t *>(data.constData()), data.size() / 2);
if (!str.isNull()) {
if (format == "text/uri-list"_L1) {
@@ -175,7 +174,7 @@ QVariant QXcbMime::mimeConvertToFormat(QXcbConnection *connection, xcb_atom_t a,
return list.constFirst();
return list;
} else {
- return str;
+ return str.toString();
}
}
}
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 584f1e5406..d3e4fa9548 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -6,6 +6,7 @@
#include <QtDebug>
#include <QMetaEnum>
#include <QScreen>
+#include <QtCore/QFileInfo>
#include <QtGui/QIcon>
#include <QtGui/QRegion>
#include <QtGui/private/qhighdpiscaling_p.h>
@@ -59,6 +60,7 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window");
+Q_LOGGING_CATEGORY(lcQpaXcbWindow, "qt.qpa.xcb.window");
Q_DECLARE_TYPEINFO(xcb_rectangle_t, Q_PRIMITIVE_TYPE);
@@ -94,7 +96,7 @@ const quint32 XEMBED_VERSION = 0;
QXcbScreen *QXcbWindow::parentScreen()
{
- return parent() ? static_cast<QXcbWindow*>(parent())->parentScreen() : xcbScreen();
+ return QPlatformWindow::parent() ? static_cast<QXcbWindow*>(QPlatformWindow::parent())->parentScreen() : xcbScreen();
}
QXcbScreen *QXcbWindow::initialScreen() const
@@ -133,6 +135,7 @@ void QXcbWindow::setImageFormatForVisual(const xcb_visualtype_t *visual)
case 16:
qWarning("Using RGB16 fallback, if this works your X11 server is reporting a bad screen format.");
m_imageFormat = QImage::Format_RGB16;
+ break;
default:
break;
}
@@ -223,6 +226,7 @@ enum : quint32 {
void QXcbWindow::create()
{
+ xcb_window_t old_m_window = m_window;
destroy();
m_windowState = Qt::WindowNoState;
@@ -231,8 +235,8 @@ void QXcbWindow::create()
Qt::WindowType type = window()->type();
QXcbScreen *currentScreen = xcbScreen();
- QXcbScreen *platformScreen = parent() ? parentScreen() : initialScreen();
- QRect rect = parent()
+ QXcbScreen *platformScreen = QPlatformWindow::parent() ? parentScreen() : initialScreen();
+ QRect rect = QPlatformWindow::parent()
? QHighDpi::toNativeLocalPosition(window()->geometry(), platformScreen)
: QHighDpi::toNativePixels(window()->geometry(), platformScreen);
@@ -272,11 +276,11 @@ void QXcbWindow::create()
QWindowSystemInterface::handleWindowScreenChanged(window(), platformScreen->QPlatformScreen::screen());
xcb_window_t xcb_parent_id = platformScreen->root();
- if (parent()) {
- xcb_parent_id = static_cast<QXcbWindow *>(parent())->xcb_window();
- m_embedded = parent()->isForeignWindow();
+ if (QPlatformWindow::parent()) {
+ xcb_parent_id = static_cast<QXcbWindow *>(QPlatformWindow::parent())->xcb_window();
+ m_embedded = QPlatformWindow::parent()->isForeignWindow();
- QSurfaceFormat parentFormat = parent()->window()->requestedFormat();
+ QSurfaceFormat parentFormat = QPlatformWindow::parent()->window()->requestedFormat();
if (window()->surfaceType() != QSurface::OpenGLSurface && parentFormat.hasAlpha()) {
window()->setFormat(parentFormat);
}
@@ -294,16 +298,16 @@ void QXcbWindow::create()
qWarning() << "Failed to use requested visual id.";
}
- if (parent()) {
+ if (QPlatformWindow::parent()) {
// When using a Vulkan QWindow via QWidget::createWindowContainer() we
// must make sure the visuals are compatible. Now, the parent will be
// of RasterGLSurface which typically chooses a GLX/EGL compatible
// visual which may not be what the Vulkan window would choose.
// Therefore, take the parent's visual.
if (window()->surfaceType() == QSurface::VulkanSurface
- && parent()->window()->surfaceType() != QSurface::VulkanSurface)
+ && QPlatformWindow::parent()->window()->surfaceType() != QSurface::VulkanSurface)
{
- visual = platformScreen->visualForId(static_cast<QXcbWindow *>(parent())->visualId());
+ visual = platformScreen->visualForId(static_cast<QXcbWindow *>(QPlatformWindow::parent())->visualId());
}
}
@@ -388,6 +392,31 @@ void QXcbWindow::create()
XCB_ATOM_STRING, 8, wmClass.size(), wmClass.constData());
}
+ QString desktopFileName = QGuiApplication::desktopFileName();
+ if (QGuiApplication::desktopFileName().isEmpty()) {
+ QFileInfo fi = QFileInfo(QCoreApplication::instance()->applicationFilePath());
+ QStringList domainName =
+ QCoreApplication::instance()->organizationDomain().split(QLatin1Char('.'),
+ Qt::SkipEmptyParts);
+
+ if (domainName.isEmpty()) {
+ desktopFileName = fi.baseName();
+ } else {
+ for (int i = 0; i < domainName.size(); ++i)
+ desktopFileName.prepend(QLatin1Char('.')).prepend(domainName.at(i));
+ desktopFileName.append(fi.baseName());
+ }
+ }
+ if (!desktopFileName.isEmpty()) {
+ const QByteArray dfName = desktopFileName.toUtf8();
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE,
+ m_window, atom(QXcbAtom::Atom_KDE_NET_WM_DESKTOP_FILE),
+ atom(QXcbAtom::AtomUTF8_STRING), 8, dfName.size(), dfName.constData());
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE,
+ m_window, atom(QXcbAtom::Atom_GTK_APPLICATION_ID),
+ atom(QXcbAtom::AtomUTF8_STRING), 8, dfName.size(), dfName.constData());
+ }
+
if (connection()->hasXSync()) {
m_syncCounter = xcb_generate_id(xcb_connection());
xcb_sync_create_counter(xcb_connection(), m_syncCounter, m_syncValue);
@@ -465,6 +494,17 @@ void QXcbWindow::create()
if (m_trayIconWindow)
m_embedded = requestSystemTrayWindowDock();
+
+ if (m_window != old_m_window) {
+ if (!m_wmTransientForChildren.isEmpty()) {
+ QList<QPointer<QXcbWindow>> transientChildren = m_wmTransientForChildren;
+ m_wmTransientForChildren.clear();
+ for (auto transientChild : transientChildren) {
+ if (transientChild)
+ transientChild->updateWmTransientFor();
+ }
+ }
+ }
}
QXcbWindow::~QXcbWindow()
@@ -472,6 +512,22 @@ QXcbWindow::~QXcbWindow()
destroy();
}
+QXcbForeignWindow::QXcbForeignWindow(QWindow *window, WId nativeHandle)
+ : QXcbWindow(window)
+{
+ m_window = nativeHandle;
+
+ // Reflect the foreign window's geometry as our own
+ if (auto geometry = Q_XCB_REPLY(xcb_get_geometry, xcb_connection(), m_window)) {
+ QRect nativeGeometry(geometry->x, geometry->y, geometry->width, geometry->height);
+ QPlatformWindow::setGeometry(nativeGeometry);
+ }
+
+ // And reparent, if we have a parent already
+ if (QPlatformWindow::parent())
+ setParent(QPlatformWindow::parent());
+}
+
QXcbForeignWindow::~QXcbForeignWindow()
{
// Clear window so that destroy() does not affect it
@@ -489,6 +545,8 @@ void QXcbWindow::destroy()
doFocusOut();
if (connection()->mouseGrabber() == this)
connection()->setMouseGrabber(nullptr);
+ if (connection()->mousePressWindow() == this)
+ connection()->setMousePressWindow(nullptr);
if (m_syncCounter && connection()->hasXSync())
xcb_sync_destroy_counter(xcb_connection(), m_syncCounter);
@@ -522,7 +580,7 @@ void QXcbWindow::setGeometry(const QRect &rect)
propagateSizeHints();
QXcbScreen *currentScreen = xcbScreen();
- QXcbScreen *newScreen = parent() ? parentScreen() : static_cast<QXcbScreen*>(screenForGeometry(rect));
+ QXcbScreen *newScreen = QPlatformWindow::parent() ? parentScreen() : static_cast<QXcbScreen*>(screenForGeometry(rect));
if (!newScreen)
newScreen = xcbScreen();
@@ -641,6 +699,44 @@ void QXcbWindow::setVisible(bool visible)
hide();
}
+void QXcbWindow::updateWmTransientFor()
+{
+ xcb_window_t transientXcbParent = XCB_NONE;
+ if (isTransient(window())) {
+ QWindow *tp = window()->transientParent();
+ if (tp && tp->handle()) {
+ QXcbWindow *handle = static_cast<QXcbWindow *>(tp->handle());
+ transientXcbParent = tp->handle()->winId();
+ if (transientXcbParent) {
+ handle->registerWmTransientForChild(this);
+ qCDebug(lcQpaXcbWindow) << Q_FUNC_INFO << static_cast<QPlatformWindow *>(handle)
+ << " registerWmTransientForChild " << static_cast<QPlatformWindow *>(this);
+ }
+ }
+ // Default to client leader if there is no transient parent, else modal dialogs can
+ // be hidden by their parents.
+ if (!transientXcbParent)
+ transientXcbParent = connection()->clientLeader();
+ if (transientXcbParent) { // ICCCM 4.1.2.6
+ xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
+ XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32,
+ 1, &transientXcbParent);
+ qCDebug(lcQpaXcbWindow, "0x%x added XCB_ATOM_WM_TRANSIENT_FOR 0x%x", m_window, transientXcbParent);
+ }
+ }
+ if (!transientXcbParent)
+ xcb_delete_property(xcb_connection(), m_window, XCB_ATOM_WM_TRANSIENT_FOR);
+}
+
+void QXcbWindow::registerWmTransientForChild(QXcbWindow *child)
+{
+ if (!child)
+ return;
+
+ if (!m_wmTransientForChildren.contains(child))
+ m_wmTransientForChildren.append(child);
+}
+
void QXcbWindow::show()
{
if (window()->isTopLevel()) {
@@ -654,23 +750,7 @@ void QXcbWindow::show()
propagateSizeHints();
// update WM_TRANSIENT_FOR
- xcb_window_t transientXcbParent = 0;
- if (isTransient(window())) {
- const QWindow *tp = window()->transientParent();
- if (tp && tp->handle())
- transientXcbParent = tp->handle()->winId();
- // Default to client leader if there is no transient parent, else modal dialogs can
- // be hidden by their parents.
- if (!transientXcbParent)
- transientXcbParent = connection()->clientLeader();
- if (transientXcbParent) { // ICCCM 4.1.2.6
- xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
- XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32,
- 1, &transientXcbParent);
- }
- }
- if (!transientXcbParent)
- xcb_delete_property(xcb_connection(), m_window, XCB_ATOM_WM_TRANSIENT_FOR);
+ updateWmTransientFor();
// update _NET_WM_STATE
setNetWmStateOnUnmappedWindow();
@@ -781,7 +861,7 @@ void QXcbWindow::doFocusIn()
return;
QWindow *w = static_cast<QWindowPrivate *>(QObjectPrivate::get(window()))->eventReceiver();
connection()->setFocusWindow(w);
- QWindowSystemInterface::handleWindowActivated(w, Qt::ActiveWindowFocusReason);
+ QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason);
}
void QXcbWindow::doFocusOut()
@@ -1014,7 +1094,7 @@ void QXcbWindow::setNetWmState(Qt::WindowFlags flags)
void QXcbWindow::setNetWmStateOnUnmappedWindow()
{
if (Q_UNLIKELY(m_mapped))
- qCWarning(lcQpaXcb()) << "internal error: " << Q_FUNC_INFO << "called on mapped window";
+ qCDebug(lcQpaXcb()) << "internal info: " << Q_FUNC_INFO << "called on mapped window";
NetWmStates states;
const Qt::WindowFlags flags = window()->flags();
@@ -1091,18 +1171,21 @@ void QXcbWindow::setWindowState(Qt::WindowStates state)
if (state == m_windowState)
return;
+ Qt::WindowStates unsetState = m_windowState & ~state;
+ Qt::WindowStates newState = state & ~m_windowState;
+
// unset old state
- if (m_windowState & Qt::WindowMinimized)
+ if (unsetState & Qt::WindowMinimized)
xcb_map_window(xcb_connection(), m_window);
- if (m_windowState & Qt::WindowMaximized)
+ if (unsetState & Qt::WindowMaximized)
setNetWmState(false,
atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ),
atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT));
- if (m_windowState & Qt::WindowFullScreen)
+ if (unsetState & Qt::WindowFullScreen)
setNetWmState(false, atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN));
// set new state
- if (state & Qt::WindowMinimized) {
+ if (newState & Qt::WindowMinimized) {
{
xcb_client_message_event_t event;
@@ -1123,13 +1206,8 @@ void QXcbWindow::setWindowState(Qt::WindowStates state)
}
m_minimized = true;
}
- if (state & Qt::WindowMaximized)
- setNetWmState(true,
- atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_HORZ),
- atom(QXcbAtom::Atom_NET_WM_STATE_MAXIMIZED_VERT));
- if (state & Qt::WindowFullScreen)
- setNetWmState(true, atom(QXcbAtom::Atom_NET_WM_STATE_FULLSCREEN));
+ // set Maximized && FullScreen state if need
setNetWmState(state);
xcb_get_property_cookie_t cookie = xcb_icccm_get_wm_hints_unchecked(xcb_connection(), m_window);
@@ -1371,7 +1449,8 @@ void QXcbWindow::propagateSizeHints()
qMin(XCOORD_MAX, maximumSize.height()));
if (sizeIncrement.width() > 0 || sizeIncrement.height() > 0) {
- xcb_icccm_size_hints_set_base_size(&hints, baseSize.width(), baseSize.height());
+ if (!baseSize.isNull() && baseSize.isValid())
+ xcb_icccm_size_hints_set_base_size(&hints, baseSize.width(), baseSize.height());
xcb_icccm_size_hints_set_resize_inc(&hints, sizeIncrement.width(), sizeIncrement.height());
}
@@ -1389,14 +1468,22 @@ void QXcbWindow::requestActivateWindow()
return;
}
- if (!m_mapped) {
- m_deferredActivation = true;
- return;
+ {
+ QMutexLocker locker(&m_mappedMutex);
+ if (!m_mapped) {
+ m_deferredActivation = true;
+ return;
+ }
+ m_deferredActivation = false;
}
- m_deferredActivation = false;
updateNetWmUserTime(connection()->time());
QWindow *focusWindow = QGuiApplication::focusWindow();
+ xcb_window_t current = XCB_NONE;
+ if (focusWindow) {
+ if (QPlatformWindow *pw = focusWindow->handle())
+ current = pw->winId();
+ }
if (window()->isTopLevel()
&& !(window()->flags() & Qt::X11BypassWindowManagerHint)
@@ -1411,7 +1498,7 @@ void QXcbWindow::requestActivateWindow()
event.type = atom(QXcbAtom::Atom_NET_ACTIVE_WINDOW);
event.data.data32[0] = 1;
event.data.data32[1] = connection()->time();
- event.data.data32[2] = focusWindow ? focusWindow->winId() : XCB_NONE;
+ event.data.data32[2] = current;
event.data.data32[3] = 0;
event.data.data32[4] = 0;
@@ -1715,7 +1802,7 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
{
bool fromSendEvent = (event->response_type & 0x80);
QPoint pos(event->x, event->y);
- if (!parent() && !fromSendEvent) {
+ if (!QPlatformWindow::parent() && !fromSendEvent) {
// Do not trust the position, query it instead.
auto reply = Q_XCB_REPLY(xcb_translate_coordinates, xcb_connection(),
xcb_window(), xcbScreen()->root(), 0, 0);
@@ -1726,7 +1813,7 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
}
const QRect actualGeometry = QRect(pos, QSize(event->width, event->height));
- QPlatformScreen *newScreen = parent() ? parent()->screen() : screenForGeometry(actualGeometry);
+ QPlatformScreen *newScreen = QPlatformWindow::parent() ? QPlatformWindow::parent()->screen() : screenForGeometry(actualGeometry);
if (!newScreen)
return;
@@ -1802,8 +1889,11 @@ QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const
void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event)
{
if (event->window == m_window) {
+ m_mappedMutex.lock();
m_mapped = true;
- if (m_deferredActivation)
+ const bool deferredActivation = m_deferredActivation;
+ m_mappedMutex.unlock();
+ if (deferredActivation)
requestActivateWindow();
QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
@@ -1813,7 +1903,9 @@ void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event)
void QXcbWindow::handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event)
{
if (event->window == m_window) {
+ m_mappedMutex.lock();
m_mapped = false;
+ m_mappedMutex.unlock();
QWindowSystemInterface::handleExposeEvent(window(), QRegion());
}
}
@@ -1836,7 +1928,7 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in
if (m_embedded && !m_trayIconWindow) {
if (window() != QGuiApplication::focusWindow()) {
- const QXcbWindow *container = static_cast<const QXcbWindow *>(parent());
+ const QXcbWindow *container = static_cast<const QXcbWindow *>(QPlatformWindow::parent());
Q_ASSERT(container != nullptr);
sendXEmbedMessage(container->xcb_window(), XEMBED_REQUEST_FOCUS);
@@ -1880,8 +1972,10 @@ void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x,
return;
}
- if (connection()->buttonState() == Qt::NoButton)
+ if (connection()->buttonState() == Qt::NoButton) {
connection()->setMousePressWindow(nullptr);
+ m_ignorePressedWindowOnMouseLeave = false;
+ }
handleMouseEvent(timestamp, local, global, modifiers, type, source);
}
@@ -1901,10 +1995,10 @@ static inline bool doCheckUnGrabAncestor(QXcbConnection *conn)
return true;
}
-static bool ignoreLeaveEvent(quint8 mode, quint8 detail, QXcbConnection *conn = nullptr)
+static bool ignoreLeaveEvent(quint8 mode, quint8 detail, QXcbConnection *conn)
{
return ((doCheckUnGrabAncestor(conn)
- && mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR)
+ && mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR)
|| (mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_INFERIOR)
|| detail == XCB_NOTIFY_DETAIL_VIRTUAL
|| detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL);
@@ -1924,14 +2018,18 @@ void QXcbWindow::handleEnterNotifyEvent(int event_x, int event_y, int root_x, in
{
connection()->setTime(timestamp);
- const QPoint global = QPoint(root_x, root_y);
-
- if (ignoreEnterEvent(mode, detail, connection()) || connection()->mousePressWindow())
+ if (ignoreEnterEvent(mode, detail, connection())
+ || (connection()->mousePressWindow() && !m_ignorePressedWindowOnMouseLeave)) {
return;
+ }
// Updates scroll valuators, as user might have done some scrolling outside our X client.
connection()->xi2UpdateScrollingDevices();
+ if (mode == XCB_NOTIFY_MODE_UNGRAB && connection()->queryMouseButtons() != Qt::NoButton)
+ m_ignorePressedWindowOnMouseLeave = true;
+
+ const QPoint global = QPoint(root_x, root_y);
const QPoint local(event_x, event_y);
QWindowSystemInterface::handleEnterEvent(window(), local, global);
}
@@ -1941,8 +2039,11 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y,
{
connection()->setTime(timestamp);
- if (ignoreLeaveEvent(mode, detail, connection()) || connection()->mousePressWindow())
+ QXcbWindow *mousePressWindow = connection()->mousePressWindow();
+ if (ignoreLeaveEvent(mode, detail, connection())
+ || (mousePressWindow && !m_ignorePressedWindowOnMouseLeave)) {
return;
+ }
// check if enter event is buffered
auto event = connection()->eventQueue()->peek([](xcb_generic_event_t *event, int type) {
@@ -1960,6 +2061,8 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y,
QWindowSystemInterface::handleEnterLeaveEvent(enterWindow->window(), window(), local, global);
} else {
QWindowSystemInterface::handleLeaveEvent(window());
+ if (m_ignorePressedWindowOnMouseLeave)
+ connection()->setMousePressWindow(nullptr);
}
free(enter);
@@ -2285,7 +2388,7 @@ bool QXcbWindow::windowEvent(QEvent *event)
case Qt::BacktabFocusReason:
{
const QXcbWindow *container =
- static_cast<const QXcbWindow *>(parent());
+ static_cast<const QXcbWindow *>(QPlatformWindow::parent());
sendXEmbedMessage(container->xcb_window(),
focusEvent->reason() == Qt::TabFocusReason ?
XEMBED_FOCUS_NEXT : XEMBED_FOCUS_PREV);
@@ -2405,15 +2508,15 @@ void QXcbWindow::sendXEmbedMessage(xcb_window_t window, quint32 message,
xcb_send_event(xcb_connection(), false, window, XCB_EVENT_MASK_NO_EVENT, (const char *)&event);
}
-static bool activeWindowChangeQueued(const QWindow *window)
+static bool focusWindowChangeQueued(const QWindow *window)
{
/* Check from window system event queue if the next queued activation
* targets a window other than @window.
*/
- QWindowSystemInterfacePrivate::ActivatedWindowEvent *systemEvent =
- static_cast<QWindowSystemInterfacePrivate::ActivatedWindowEvent *>
- (QWindowSystemInterfacePrivate::peekWindowSystemEvent(QWindowSystemInterfacePrivate::ActivatedWindow));
- return systemEvent && systemEvent->activated != window;
+ QWindowSystemInterfacePrivate::FocusWindowEvent *systemEvent =
+ static_cast<QWindowSystemInterfacePrivate::FocusWindowEvent *>
+ (QWindowSystemInterfacePrivate::peekWindowSystemEvent(QWindowSystemInterfacePrivate::FocusWindow));
+ return systemEvent && systemEvent->focused != window;
}
void QXcbWindow::handleXEmbedMessage(const xcb_client_message_event_t *event)
@@ -2443,13 +2546,13 @@ void QXcbWindow::handleXEmbedMessage(const xcb_client_message_event_t *event)
break;
}
connection()->setFocusWindow(window());
- QWindowSystemInterface::handleWindowActivated(window(), reason);
+ QWindowSystemInterface::handleFocusWindowChanged(window(), reason);
break;
case XEMBED_FOCUS_OUT:
if (window() == QGuiApplication::focusWindow()
- && !activeWindowChangeQueued(window())) {
+ && !focusWindowChangeQueued(window())) {
connection()->setFocusWindow(nullptr);
- QWindowSystemInterface::handleWindowActivated(nullptr);
+ QWindowSystemInterface::handleFocusWindowChanged(nullptr);
}
break;
}
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 54a96a7a0a..0c047d569b 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -6,6 +6,8 @@
#include <qpa/qplatformwindow.h>
#include <qpa/qplatformwindow_p.h>
+#include <QtCore/QObject>
+#include <QtCore/QPointer>
#include <QtGui/QSurfaceFormat>
#include <QtGui/QImage>
@@ -20,9 +22,10 @@ class QXcbScreen;
class QXcbSyncWindowRequest;
class QIcon;
-class Q_XCB_EXPORT QXcbWindow : public QXcbObject, public QXcbWindowEventListener, public QPlatformWindow
+class Q_XCB_EXPORT QXcbWindow : public QObject, public QXcbObject, public QXcbWindowEventListener, public QPlatformWindow
, public QNativeInterface::Private::QXcbWindow
{
+ Q_OBJECT
public:
enum NetWmState {
NetWmStateAbove = 0x1,
@@ -118,6 +121,8 @@ public:
Qt::KeyboardModifiers modifiers, QEvent::Type type, Qt::MouseEventSource source);
void updateNetWmUserTime(xcb_timestamp_t timestamp);
+ void updateWmTransientFor();
+ void registerWmTransientForChild(QXcbWindow *);
WindowTypes wmWindowTypes() const;
void setWmWindowType(WindowTypes types, Qt::WindowFlags flags);
@@ -217,6 +222,7 @@ protected:
Qt::WindowStates m_windowState = Qt::WindowNoState;
+ QMutex m_mappedMutex;
bool m_mapped = false;
bool m_transparent = false;
bool m_deferredActivation = false;
@@ -224,6 +230,7 @@ protected:
bool m_alertState = false;
bool m_minimized = false;
bool m_trayIconWindow = false;
+ bool m_ignorePressedWindowOnMouseLeave = false;
xcb_window_t m_netWmUserTimeWindow = XCB_NONE;
QSurfaceFormat m_format;
@@ -253,13 +260,14 @@ protected:
qreal m_sizeHintsScaleFactor = 1.0;
RecreationReasons m_recreationReasons = RecreationNotNeeded;
+
+ QList<QPointer<QXcbWindow>> m_wmTransientForChildren;
};
class QXcbForeignWindow : public QXcbWindow
{
public:
- QXcbForeignWindow(QWindow *window, WId nativeHandle)
- : QXcbWindow(window) { m_window = nativeHandle; }
+ QXcbForeignWindow(QWindow *window, WId nativeHandle);
~QXcbForeignWindow();
bool isForeignWindow() const override { return true; }
diff --git a/src/plugins/platformthemes/gtk3/CMakeLists.txt b/src/plugins/platformthemes/gtk3/CMakeLists.txt
index 89acc84f07..6d3c7bf3a2 100644
--- a/src/plugins/platformthemes/gtk3/CMakeLists.txt
+++ b/src/plugins/platformthemes/gtk3/CMakeLists.txt
@@ -23,6 +23,8 @@ qt_internal_add_plugin(QGtk3ThemePlugin
qgtk3interface.cpp qgtk3interface_p.h
qgtk3storage.cpp qgtk3storage_p.h
qgtk3json.cpp qgtk3json_p.h
+ NO_PCH_SOURCES
+ qgtk3dialoghelpers.cpp # undef QT_NO_FOREACH
DEFINES
GDK_VERSION_MIN_REQUIRED=GDK_VERSION_3_6
LIBRARIES
@@ -33,6 +35,13 @@ qt_internal_add_plugin(QGtk3ThemePlugin
Qt::GuiPrivate
)
+qt_internal_extend_target(QGtk3ThemePlugin CONDITION QT_FEATURE_dbus
+ SOURCES
+ qgtk3portalinterface.cpp
+ LIBRARIES
+ Qt::DBus
+)
+
qt_internal_extend_target(QGtk3ThemePlugin CONDITION QT_FEATURE_xlib
LIBRARIES
X11::X11
diff --git a/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp b/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp
index b8ba58d30e..08419ec7dc 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp
+++ b/src/plugins/platformthemes/gtk3/qgtk3dialoghelpers.cpp
@@ -1,6 +1,8 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
+
#include "qgtk3dialoghelpers.h"
#include "qgtk3theme.h"
diff --git a/src/plugins/platformthemes/gtk3/qgtk3interface.cpp b/src/plugins/platformthemes/gtk3/qgtk3interface.cpp
index d802f2d1db..a35e211fbf 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3interface.cpp
+++ b/src/plugins/platformthemes/gtk3/qgtk3interface.cpp
@@ -289,15 +289,17 @@ QImage QGtk3Interface::qt_convert_gdk_pixbuf(GdkPixbuf *buf) const
const guint8 *gdata = gdk_pixbuf_read_pixels(buf);
static_assert(std::is_same<decltype(gdata), const uchar *>::value,
"guint8 has diverted from uchar. Code needs fixing.");
- Q_ASSUME(gdk_pixbuf_get_bits_per_sample(buf) == 8);
- Q_ASSUME(gdk_pixbuf_get_n_channels(buf) == 4);
+ Q_ASSERT(gdk_pixbuf_get_bits_per_sample(buf) == 8);
+ Q_ASSERT(gdk_pixbuf_get_n_channels(buf) == 4);
const uchar *data = static_cast<const uchar *>(gdata);
const int width = gdk_pixbuf_get_width(buf);
const int height = gdk_pixbuf_get_height(buf);
const int bpl = gdk_pixbuf_get_rowstride(buf);
- QImage converted(data, width, height, bpl, QImage::Format_ARGB32);
- return converted.copy(); // detatch to survive lifetime of buf
+ QImage converted(data, width, height, bpl, QImage::Format_RGBA8888);
+
+ // convert to more optimal format and detach to survive lifetime of buf
+ return converted.convertToFormat(QImage::Format_ARGB32_Premultiplied);
}
/*!
@@ -475,15 +477,18 @@ QBrush QGtk3Interface::brush(QGtkWidget wtype, QGtkColorSource source, GtkStateF
\internal
\brief Returns the name of the current GTK theme.
*/
-const QString QGtk3Interface::themeName() const
+QString QGtk3Interface::themeName() const
{
- gchar *theme_name;
- GtkSettings *settings = gtk_settings_get_default();
- if (!settings)
- return QString();
+ QString name;
- g_object_get(settings, "gtk-theme-name", &theme_name, nullptr);
- return QLatin1StringView(theme_name);
+ if (GtkSettings *settings = gtk_settings_get_default()) {
+ gchar *theme_name;
+ g_object_get(settings, "gtk-theme-name", &theme_name, nullptr);
+ name = QLatin1StringView(theme_name);
+ g_free(theme_name);
+ }
+
+ return name;
}
/*!
@@ -537,13 +542,13 @@ inline constexpr QGtk3Interface::QGtkWidget QGtk3Interface::toWidgetType(QPlatfo
case QPlatformTheme::ToolButtonFont: return QGtkWidget::gtk_button;
case QPlatformTheme::ItemViewFont: return QGtkWidget::gtk_entry;
case QPlatformTheme::ListViewFont: return QGtkWidget::gtk_tree_view;
- case QPlatformTheme::HeaderViewFont: return QGtkWidget::gtk_fixed;
+ case QPlatformTheme::HeaderViewFont: return QGtkWidget::gtk_combo_box;
case QPlatformTheme::ListBoxFont: return QGtkWidget::gtk_Default;
case QPlatformTheme::ComboMenuItemFont: return QGtkWidget::gtk_combo_box;
case QPlatformTheme::ComboLineEditFont: return QGtkWidget::gtk_combo_box_text;
case QPlatformTheme::SmallFont: return QGtkWidget::gtk_Default;
case QPlatformTheme::MiniFont: return QGtkWidget::gtk_Default;
- case QPlatformTheme::FixedFont: return QGtkWidget::gtk_fixed;
+ case QPlatformTheme::FixedFont: return QGtkWidget::gtk_Default;
case QPlatformTheme::GroupBoxTitleFont: return QGtkWidget::gtk_Default;
case QPlatformTheme::TabButtonFont: return QGtkWidget::gtk_button;
case QPlatformTheme::EditorFont: return QGtkWidget::gtk_entry;
@@ -604,6 +609,25 @@ QFont QGtk3Interface::font(QPlatformTheme::Font type) const
if (!con)
return QFont();
+ // explicitly add provider for fixed font
+ GtkCssProvider *cssProvider = nullptr;
+ if (type == QPlatformTheme::FixedFont) {
+ cssProvider = gtk_css_provider_new();
+ gtk_style_context_add_class (con, GTK_STYLE_CLASS_MONOSPACE);
+ const char *fontSpec = "* {font-family: monospace;}";
+ gtk_css_provider_load_from_data(cssProvider, fontSpec, -1, NULL);
+ gtk_style_context_add_provider(con, GTK_STYLE_PROVIDER(cssProvider),
+ GTK_STYLE_PROVIDER_PRIORITY_USER);
+ }
+
+ // remove monospace provider from style context and unref it
+ QScopeGuard guard([&](){
+ if (cssProvider) {
+ gtk_style_context_remove_provider(con, GTK_STYLE_PROVIDER(cssProvider));
+ g_object_unref(cssProvider);
+ }
+ });
+
const PangoFontDescription *gtkFont = gtk_style_context_get_font(con, GTK_STATE_FLAG_NORMAL);
if (!gtkFont)
return QFont();
@@ -630,6 +654,7 @@ QFont QGtk3Interface::font(QPlatformTheme::Font type) const
font.setFamily("monospace"_L1);
}
}
+
return font;
}
@@ -643,7 +668,7 @@ QIcon QGtk3Interface::fileIcon(const QFileInfo &fileInfo) const
if (!file)
return QIcon();
- GFileInfo *info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ GFileInfo *info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_ICON,
G_FILE_QUERY_INFO_NONE, nullptr, nullptr);
if (!info) {
g_object_unref(file);
@@ -658,12 +683,11 @@ QIcon QGtk3Interface::fileIcon(const QFileInfo &fileInfo) const
}
GtkIconTheme *theme = gtk_icon_theme_get_default();
- GtkIconInfo *iconInfo = gtk_icon_theme_lookup_by_gicon(theme, icon, GTK_ICON_SIZE_BUTTON,
+ GtkIconInfo *iconInfo = gtk_icon_theme_lookup_by_gicon(theme, icon, 16,
GTK_ICON_LOOKUP_FORCE_SIZE);
if (!iconInfo) {
g_object_unref(file);
g_object_unref(info);
- g_object_unref(icon);
return QIcon();
}
@@ -671,7 +695,6 @@ QIcon QGtk3Interface::fileIcon(const QFileInfo &fileInfo) const
QImage image = qt_convert_gdk_pixbuf(buf);
g_object_unref(file);
g_object_unref(info);
- g_object_unref(icon);
g_object_unref(buf);
return QIcon(QPixmap::fromImage(image));
}
diff --git a/src/plugins/platformthemes/gtk3/qgtk3interface_p.h b/src/plugins/platformthemes/gtk3/qgtk3interface_p.h
index b92adcd720..c43932a4fa 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3interface_p.h
+++ b/src/plugins/platformthemes/gtk3/qgtk3interface_p.h
@@ -134,7 +134,7 @@ public:
QIcon fileIcon(const QFileInfo &fileInfo) const;
// Return current GTK theme name
- const QString themeName() const;
+ QString themeName() const;
// Derive color scheme from default colors
Qt::ColorScheme colorSchemeByColors() const;
diff --git a/src/plugins/platformthemes/gtk3/qgtk3portalinterface.cpp b/src/plugins/platformthemes/gtk3/qgtk3portalinterface.cpp
new file mode 100644
index 0000000000..1ffdda74fa
--- /dev/null
+++ b/src/plugins/platformthemes/gtk3/qgtk3portalinterface.cpp
@@ -0,0 +1,123 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+//
+// 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 "qgtk3portalinterface_p.h"
+#include "qgtk3storage_p.h"
+
+#include <QtDBus/QDBusArgument>
+#include <QtDBus/QDBusConnection>
+#include <QtDBus/QDBusMessage>
+#include <QtDBus/QDBusPendingCall>
+#include <QtDBus/QDBusPendingCallWatcher>
+#include <QtDBus/QDBusPendingReply>
+#include <QtDBus/QDBusVariant>
+#include <QtDBus/QtDBus>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcQGtk3PortalInterface, "qt.qpa.gtk");
+
+using namespace Qt::StringLiterals;
+
+static constexpr QLatin1StringView appearanceInterface("org.freedesktop.appearance");
+static constexpr QLatin1StringView colorSchemeKey("color-scheme");
+
+const QDBusArgument &operator>>(const QDBusArgument &argument, QMap<QString, QVariantMap> &map)
+{
+ argument.beginMap();
+ map.clear();
+
+ while (!argument.atEnd()) {
+ QString key;
+ QVariantMap value;
+ argument.beginMapEntry();
+ argument >> key >> value;
+ argument.endMapEntry();
+ map.insert(key, value);
+ }
+
+ argument.endMap();
+ return argument;
+}
+
+QGtk3PortalInterface::QGtk3PortalInterface(QGtk3Storage *s)
+ : m_storage(s) {
+ qRegisterMetaType<QDBusVariant>();
+ qDBusRegisterMetaType<QMap<QString, QVariantMap>>();
+
+ queryColorScheme();
+
+ if (!s) {
+ qCDebug(lcQGtk3PortalInterface) << "QGtk3PortalInterface instantiated without QGtk3Storage."
+ << "No reaction to runtime theme changes.";
+ }
+}
+
+Qt::ColorScheme QGtk3PortalInterface::colorScheme() const
+{
+ return m_colorScheme;
+}
+
+void QGtk3PortalInterface::queryColorScheme() {
+ QDBusConnection connection = QDBusConnection::sessionBus();
+ QDBusMessage message = QDBusMessage::createMethodCall(
+ "org.freedesktop.portal.Desktop"_L1,
+ "/org/freedesktop/portal/desktop"_L1,
+ "org.freedesktop.portal.Settings"_L1, "ReadAll"_L1);
+ message << QStringList{ appearanceInterface };
+
+ QDBusPendingCall pendingCall = connection.asyncCall(message);
+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall, this);
+ QObject::connect(
+ watcher, &QDBusPendingCallWatcher::finished, this,
+ [this](QDBusPendingCallWatcher *watcher) {
+ QDBusPendingReply<QMap<QString, QVariantMap>> reply = *watcher;
+ if (reply.isValid()) {
+ QMap<QString, QVariantMap> settings = reply.value();
+ if (!settings.isEmpty()) {
+ settingChanged(appearanceInterface, colorSchemeKey,
+ QDBusVariant(settings.value(appearanceInterface).value(colorSchemeKey)));
+ }
+ } else {
+ qCDebug(lcQGtk3PortalInterface) << "Failed to query org.freedesktop.portal.Settings: "
+ << reply.error().message();
+ }
+ watcher->deleteLater();
+ });
+
+ QDBusConnection::sessionBus().connect(
+ "org.freedesktop.portal.Desktop"_L1, "/org/freedesktop/portal/desktop"_L1,
+ "org.freedesktop.portal.Settings"_L1, "SettingChanged"_L1, this,
+ SLOT(settingChanged(QString, QString, QDBusVariant)));
+}
+
+void QGtk3PortalInterface::settingChanged(const QString &group, const QString &key,
+ const QDBusVariant &value)
+{
+ if (group == appearanceInterface && key == colorSchemeKey) {
+ const uint colorScheme = value.variant().toUInt();
+ // From org.freedesktop.portal.Settings.xml
+ // "1" - Prefer dark appearance
+ Qt::ColorScheme newColorScheme = colorScheme == 1 ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light;
+ if (m_colorScheme != newColorScheme) {
+ m_colorScheme = newColorScheme;
+ if (m_storage)
+ m_storage->handleThemeChange();
+ }
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qgtk3portalinterface_p.cpp"
diff --git a/src/plugins/platformthemes/gtk3/qgtk3portalinterface_p.h b/src/plugins/platformthemes/gtk3/qgtk3portalinterface_p.h
new file mode 100644
index 0000000000..25a5f58ab1
--- /dev/null
+++ b/src/plugins/platformthemes/gtk3/qgtk3portalinterface_p.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QGTK3PORTALINTERFACE_H
+#define QGTK3PORTALINTERFACE_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/QObject>
+#include <QtCore/QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+class QDBusVariant;
+class QGtk3Storage;
+
+Q_DECLARE_LOGGING_CATEGORY(lcQGtk3PortalInterface);
+
+class QGtk3PortalInterface : public QObject
+{
+ Q_OBJECT
+public:
+ QGtk3PortalInterface(QGtk3Storage *s);
+ ~QGtk3PortalInterface() = default;
+
+ Qt::ColorScheme colorScheme() const;
+
+private Q_SLOTS:
+ void settingChanged(const QString &group, const QString &key,
+ const QDBusVariant &value);
+private:
+ void queryColorScheme();
+
+ Qt::ColorScheme m_colorScheme = Qt::ColorScheme::Unknown;
+ QGtk3Storage *m_storage = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGTK3PORTALINTERFACE_H
diff --git a/src/plugins/platformthemes/gtk3/qgtk3storage.cpp b/src/plugins/platformthemes/gtk3/qgtk3storage.cpp
index 8d6f3a4c14..2877b28590 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3storage.cpp
+++ b/src/plugins/platformthemes/gtk3/qgtk3storage.cpp
@@ -21,6 +21,9 @@ QT_BEGIN_NAMESPACE
QGtk3Storage::QGtk3Storage()
{
m_interface.reset(new QGtk3Interface(this));
+#if QT_CONFIG(dbus)
+ m_portalInterface.reset(new QGtk3PortalInterface(this));
+#endif
populateMap();
}
@@ -273,7 +276,6 @@ void QGtk3Storage::clear()
*/
void QGtk3Storage::handleThemeChange()
{
- clear();
populateMap();
QWindowSystemInterface::handleThemeChange();
}
@@ -331,21 +333,32 @@ void QGtk3Storage::populateMap()
static QString m_themeName;
// Distiguish initialization, theme change or call without theme change
+ Qt::ColorScheme newColorScheme = Qt::ColorScheme::Unknown;
const QString newThemeName = themeName();
- if (m_themeName == newThemeName)
+
+#if QT_CONFIG(dbus)
+ // Prefer color scheme we get from xdg-desktop-portal as this is what GNOME
+ // relies on these days
+ newColorScheme = m_portalInterface->colorScheme();
+#endif
+
+ if (newColorScheme == Qt::ColorScheme::Unknown) {
+ // Derive color scheme from theme name
+ newColorScheme = newThemeName.contains("dark"_L1, Qt::CaseInsensitive)
+ ? Qt::ColorScheme::Dark : m_interface->colorSchemeByColors();
+ }
+
+ if (m_themeName == newThemeName && m_colorScheme == newColorScheme)
return;
clear();
- // Derive color scheme from theme name
- m_colorScheme = newThemeName.contains("dark"_L1, Qt::CaseInsensitive)
- ? Qt::ColorScheme::Dark : m_interface->colorSchemeByColors();
-
if (m_themeName.isEmpty()) {
- qCDebug(lcQGtk3Interface) << "GTK theme initialized:" << newThemeName << m_colorScheme;
+ qCDebug(lcQGtk3Interface) << "GTK theme initialized:" << newThemeName << newColorScheme;
} else {
- qCDebug(lcQGtk3Interface) << "GTK theme changed to:" << newThemeName << m_colorScheme;
+ qCDebug(lcQGtk3Interface) << "GTK theme changed to:" << newThemeName << newColorScheme;
}
+ m_colorScheme = newColorScheme;
m_themeName = newThemeName;
// create standard mapping or load from Json file?
@@ -524,90 +537,140 @@ void QGtk3Storage::createMapping()
// System palette
- // background color and calculate derivates
- GTK(Default, Background, INSENSITIVE);
- ADD(Normal, Window);
- ADD(Normal, Button);
- ADD(Normal, Base);
- ADD(Inactive, Base);
- ADD(Inactive, Window);
- LIGHTER(Normal, Window, 125);
- ADD(Normal, Light);
- LIGHTER(Normal, Window, 70);
- ADD(Normal, Shadow);
- LIGHTER(Normal, Window, 80);
- ADD(Normal, Dark);
- GTK(button, Foreground, ACTIVE);
- ADD(Normal, WindowText);
- ADD(Inactive, WindowText);
- LIGHTER(Normal, WindowText, 50);
- ADD(Disabled, Text);
- ADD(Disabled, WindowText);
- ADD(Inactive, ButtonText);
- GTK(button, Text, NORMAL);
- ADD(Disabled, ButtonText);
- // special background colors
- GTK(Default, Background, SELECTED);
- ADD(Disabled, Highlight);
- ADD(Normal, Highlight);
- GTK(entry, Foreground, SELECTED);
- ADD(Normal, HighlightedText);
- GTK(entry, Background, ACTIVE);
- ADD(Inactive, HighlightedText);
- // text color and friends
- GTK(entry, Text, NORMAL);
- ADD(Normal, ButtonText);
- ADD(Normal, WindowText);
- ADD(Disabled, WindowText);
- ADD(Disabled, HighlightedText);
- GTK(Default, Text, NORMAL);
- ADD(Normal, Text);
- ADD(Inactive, Text);
- ADD(Normal, HighlightedText);
- LIGHTER(Normal, Base, 93);
- ADD(All, AlternateBase);
- GTK(Default, Foreground, NORMAL);
- ADD(All, ToolTipText);
- MODIFY(Normal, Text, 100, 100, 100);
- ADD(All, PlaceholderText, Light);
- MODIFY(Normal, Text, -100, -100, -100);
- ADD(All, PlaceholderText, Dark);
- SAVE(SystemPalette);
- CLEAR;
-
- // Checkbox and Radio Button
- GTK(button, Text, ACTIVE);
- ADD(Normal, Base, Dark);
- GTK(Default, Background, NORMAL);
- ADD(All, Base);
- GTK(button, Text, NORMAL);
- ADD(Normal, Base, Light);
- SAVE(CheckBoxPalette);
- SAVE(RadioButtonPalette);
- CLEAR;
-
- // ComboBox, GroupBox, Frame
- GTK(combo_box, Text, NORMAL);
- ADD(Normal, ButtonText, Dark);
- ADD(Normal, Text, Dark);
- GTK(combo_box, Text, ACTIVE);
- ADD(Normal, ButtonText, Light);
- ADD(Normal, Text, Light);
- SAVE(ComboBoxPalette);
- SAVE(GroupBoxPalette);
- CLEAR;
-
- // Menu bar
- GTK(Default, Text, ACTIVE);
- ADD(Normal, ButtonText);
- SAVE(MenuPalette);
- CLEAR;
-
- // LineEdit
- GTK(Default, Background, NORMAL);
- ADD(All, Base);
- SAVE(TextLineEditPalette);
- CLEAR;
+ {
+ // background color and calculate derivates
+ GTK(Default, Background, INSENSITIVE);
+ ADD(All, Window);
+ ADD(All, Button);
+ ADD(All, Base);
+ LIGHTER(Normal, Window, 125);
+ ADD(Normal, Light);
+ ADD(Inactive, Light);
+ LIGHTER(Normal, Window, 70);
+ ADD(Normal, Shadow);
+ LIGHTER(Normal, Window, 80);
+ ADD(Normal, Dark);
+ ADD(Inactive, Dark)
+
+ GTK(button, Foreground, ACTIVE);
+ ADD(Inactive, WindowText);
+ LIGHTER(Normal, WindowText, 50);
+ ADD(Disabled, Text);
+ ADD(Disabled, WindowText);
+ ADD(Disabled, ButtonText);
+
+ GTK(button, Text, NORMAL);
+ ADD(Inactive, ButtonText);
+
+ // special background colors
+ GTK(Default, Background, SELECTED);
+ ADD(Disabled, Highlight);
+ ADD(Normal, Highlight);
+ ADD(Inactive, Highlight);
+
+ GTK(entry, Foreground, SELECTED);
+ ADD(Normal, HighlightedText);
+ ADD(Inactive, HighlightedText);
+
+ // text color and friends
+ GTK(entry, Text, NORMAL);
+ ADD(Normal, ButtonText);
+ ADD(Normal, WindowText);
+ ADD(Disabled, HighlightedText);
+
+ GTK(Default, Text, NORMAL);
+ ADD(Normal, Text);
+ ADD(Inactive, Text);
+ ADD(Normal, HighlightedText);
+ LIGHTER(Normal, Base, 93);
+ ADD(All, AlternateBase);
+
+ GTK(Default, Foreground, NORMAL);
+ MODIFY(Normal, Text, 100, 100, 100);
+ ADD(All, PlaceholderText, Light);
+ MODIFY(Normal, Text, -100, -100, -100);
+ ADD(All, PlaceholderText, Dark);
+
+ // Light, midlight, dark, mid, shadow colors
+ LIGHTER(Normal, Button, 125);
+ ADD(All, Light)
+ LIGHTER(Normal, Button, 113);
+ ADD(All, Midlight)
+ LIGHTER(Normal, Button, 113);
+ ADD(All, Mid)
+ LIGHTER(Normal, Button, 87);
+ ADD(All, Dark)
+ LIGHTER(Normal, Button, 5);
+ ADD(All, Shadow)
+
+ SAVE(SystemPalette);
+ CLEAR;
+ }
+
+ // Label and TabBar Palette
+ {
+ GTK(entry, Text, NORMAL);
+ ADD(Normal, WindowText);
+ ADD(Inactive, WindowText);
+
+ SAVE(LabelPalette);
+ SAVE(TabBarPalette);
+ CLEAR;
+ }
+
+ // Checkbox and RadioButton Palette
+ {
+ GTK(button, Text, ACTIVE);
+ ADD(Normal, Base, Dark);
+ ADD(Inactive, WindowText, Dark);
+
+ GTK(Default, Foreground, NORMAL);
+ ADD(All, Text);
+
+ GTK(Default, Background, NORMAL);
+ ADD(All, Base);
+
+ GTK(button, Text, NORMAL);
+ ADD(Normal, Base, Light);
+ ADD(Inactive, WindowText, Light);
+
+ SAVE(CheckBoxPalette);
+ SAVE(RadioButtonPalette);
+ CLEAR;
+ }
+
+ // ComboBox, GroupBox & Frame Palette
+ {
+ GTK(combo_box, Text, NORMAL);
+ ADD(Normal, ButtonText, Dark);
+ ADD(Normal, Text, Dark);
+ ADD(Inactive, WindowText, Dark);
+
+ GTK(combo_box, Text, ACTIVE);
+ ADD(Normal, ButtonText, Light);
+ ADD(Normal, Text, Light);
+ ADD(Inactive, WindowText, Light);
+
+ SAVE(ComboBoxPalette);
+ SAVE(GroupBoxPalette);
+ CLEAR;
+ }
+
+ // MenuBar Palette
+ {
+ GTK(Default, Text, ACTIVE);
+ ADD(Normal, ButtonText);
+ SAVE(MenuPalette);
+ CLEAR;
+ }
+
+ // LineEdit Palette
+ {
+ GTK(Default, Background, NORMAL);
+ ADD(All, Base);
+ SAVE(TextLineEditPalette);
+ CLEAR;
+ }
#undef GTK
#undef REC
diff --git a/src/plugins/platformthemes/gtk3/qgtk3storage_p.h b/src/plugins/platformthemes/gtk3/qgtk3storage_p.h
index 37c5bf57ff..45192263a9 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3storage_p.h
+++ b/src/plugins/platformthemes/gtk3/qgtk3storage_p.h
@@ -16,6 +16,9 @@
//
#include "qgtk3interface_p.h"
+#if QT_CONFIG(dbus)
+#include "qgtk3portalinterface_p.h"
+#endif
#include <QtCore/QJsonDocument>
#include <QtCore/QCache>
@@ -205,7 +208,9 @@ private:
PaletteMap m_palettes;
std::unique_ptr<QGtk3Interface> m_interface;
-
+#if QT_CONFIG(dbus)
+ std::unique_ptr<QGtk3PortalInterface> m_portalInterface;
+#endif
Qt::ColorScheme m_colorScheme = Qt::ColorScheme::Unknown;
diff --git a/src/plugins/platformthemes/gtk3/qgtk3theme.cpp b/src/plugins/platformthemes/gtk3/qgtk3theme.cpp
index 1df4cf94a3..9d23ba7e48 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3theme.cpp
+++ b/src/plugins/platformthemes/gtk3/qgtk3theme.cpp
@@ -104,20 +104,6 @@ QGtk3Theme::QGtk3Theme()
SETTING_CONNECT("gtk-cursor-theme-size");
#undef SETTING_CONNECT
- /* Set XCURSOR_SIZE and XCURSOR_THEME for Wayland sessions */
- if (QGuiApplication::platformName().startsWith("wayland"_L1)) {
- if (qEnvironmentVariableIsEmpty("XCURSOR_SIZE")) {
- const int cursorSize = gtkSetting<gint>("gtk-cursor-theme-size");
- if (cursorSize > 0)
- qputenv("XCURSOR_SIZE", QByteArray::number(cursorSize));
- }
- if (qEnvironmentVariableIsEmpty("XCURSOR_THEME")) {
- const QString cursorTheme = gtkSetting("gtk-cursor-theme-name");
- if (!cursorTheme.isEmpty())
- qputenv("XCURSOR_THEME", cursorTheme.toUtf8());
- }
- }
-
m_storage.reset(new QGtk3Storage);
}
diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp
index ec3872f174..1c162be8fc 100644
--- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp
+++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportalfiledialog.cpp
@@ -169,19 +169,18 @@ void QXdgDesktopPortalFileDialog::openPortal(Qt::WindowFlags windowFlags, Qt::Wi
options.insert("multiple"_L1, d->multipleFiles);
options.insert("directory"_L1, d->directoryMode);
- if (d->saveFile) {
- if (!d->directory.isEmpty())
- options.insert("current_folder"_L1, QFile::encodeName(d->directory).append('\0'));
-
- if (!d->selectedFiles.isEmpty()) {
- // current_file for the file to be pre-selected, current_name for the file name to be pre-filled
- // current_file accepts absolute path and requires the file to exist
- // while current_name accepts just file name
- QFileInfo selectedFileInfo(d->selectedFiles.first());
- if (selectedFileInfo.exists())
- options.insert("current_file"_L1, QFile::encodeName(d->selectedFiles.first()).append('\0'));
- options.insert("current_name"_L1, selectedFileInfo.fileName());
- }
+ if (!d->directory.isEmpty())
+ options.insert("current_folder"_L1, QFile::encodeName(d->directory).append('\0'));
+
+ if (d->saveFile && !d->selectedFiles.isEmpty()) {
+ // current_file for the file to be pre-selected, current_name for the file name to be
+ // pre-filled current_file accepts absolute path and requires the file to exist while
+ // current_name accepts just file name
+ QFileInfo selectedFileInfo(d->selectedFiles.constFirst());
+ if (selectedFileInfo.exists())
+ options.insert("current_file"_L1,
+ QFile::encodeName(d->selectedFiles.constFirst()).append('\0'));
+ options.insert("current_name"_L1, selectedFileInfo.fileName());
}
// Insert filters
@@ -214,6 +213,9 @@ void QXdgDesktopPortalFileDialog::openPortal(Qt::WindowFlags windowFlags, Qt::Wi
filter.name = mimeType.comment();
filter.filterConditions = filterConditions;
+ if (filter.name.isEmpty())
+ filter.name = mimeTypefilter;
+
filterList << filter;
if (!d->selectedMimeTypeFilter.isEmpty() && d->selectedMimeTypeFilter == mimeTypefilter)
diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp
index 2f46b53297..355d3e6cc9 100644
--- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp
+++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp
@@ -20,8 +20,9 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-class QXdgDesktopPortalThemePrivate : public QPlatformThemePrivate
-{
+class QXdgDesktopPortalThemePrivate : public QObject
+ {
+ Q_OBJECT
public:
enum XdgColorschemePref {
None,
@@ -30,7 +31,7 @@ public:
};
QXdgDesktopPortalThemePrivate()
- : QPlatformThemePrivate()
+ : QObject()
{ }
~QXdgDesktopPortalThemePrivate()
@@ -62,6 +63,17 @@ public:
}
}
+public Q_SLOTS:
+ void settingChanged(const QString &group, const QString &key,
+ const QDBusVariant &value)
+ {
+ if (group == "org.freedesktop.appearance"_L1 && key == "color-scheme"_L1) {
+ colorScheme = colorSchemeFromXdgPref(static_cast<XdgColorschemePref>(value.variant().toUInt()));
+ QWindowSystemInterface::handleThemeChange();
+ }
+ }
+
+public:
QPlatformTheme *baseTheme = nullptr;
uint fileChooserPortalVersion = 0;
Qt::ColorScheme colorScheme = Qt::ColorScheme::Unknown;
@@ -104,7 +116,7 @@ QXdgDesktopPortalTheme::QXdgDesktopPortalTheme()
message << "org.freedesktop.portal.FileChooser"_L1 << "version"_L1;
QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message);
QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall);
- QObject::connect(watcher, &QDBusPendingCallWatcher::finished, [d] (QDBusPendingCallWatcher *watcher) {
+ QObject::connect(watcher, &QDBusPendingCallWatcher::finished, watcher, [d] (QDBusPendingCallWatcher *watcher) {
QDBusPendingReply<QVariant> reply = *watcher;
if (reply.isValid()) {
d->fileChooserPortalVersion = reply.value().toUInt();
@@ -126,6 +138,11 @@ QXdgDesktopPortalTheme::QXdgDesktopPortalTheme()
const QXdgDesktopPortalThemePrivate::XdgColorschemePref xdgPref = static_cast<QXdgDesktopPortalThemePrivate::XdgColorschemePref>(dbusVariant.variant().toUInt());
d->colorScheme = QXdgDesktopPortalThemePrivate::colorSchemeFromXdgPref(xdgPref);
}
+
+ QDBusConnection::sessionBus().connect(
+ "org.freedesktop.portal.Desktop"_L1, "/org/freedesktop/portal/desktop"_L1,
+ "org.freedesktop.portal.Settings"_L1, "SettingChanged"_L1, d_ptr.get(),
+ SLOT(settingChanged(QString, QString, QDBusVariant)));
}
QPlatformMenuItem* QXdgDesktopPortalTheme::createPlatformMenuItem() const
@@ -208,6 +225,8 @@ QVariant QXdgDesktopPortalTheme::themeHint(ThemeHint hint) const
Qt::ColorScheme QXdgDesktopPortalTheme::colorScheme() const
{
Q_D(const QXdgDesktopPortalTheme);
+ if (d->colorScheme == Qt::ColorScheme::Unknown)
+ return d->baseTheme->colorScheme();
return d->colorScheme;
}
@@ -245,3 +264,5 @@ QString QXdgDesktopPortalTheme::standardButtonText(int button) const
}
QT_END_NAMESPACE
+
+#include "qxdgdesktopportaltheme.moc"
diff --git a/src/plugins/printsupport/cups/qcupsprintengine.cpp b/src/plugins/printsupport/cups/qcupsprintengine.cpp
index b69d36ab8c..6c50c11c0f 100644
--- a/src/plugins/printsupport/cups/qcupsprintengine.cpp
+++ b/src/plugins/printsupport/cups/qcupsprintengine.cpp
@@ -144,7 +144,20 @@ bool QCupsPrintEnginePrivate::openPrintDevice()
}
cupsTempFile = QString::fromLocal8Bit(filename);
outDevice = new QFile();
- static_cast<QFile *>(outDevice)->open(fd, QIODevice::WriteOnly);
+ if (!static_cast<QFile *>(outDevice)->open(fd, QIODevice::WriteOnly)) {
+ qWarning("QPdfPrinter: Could not open CUPS temporary file descriptor: %s",
+ qPrintable(outDevice->errorString()));
+ delete outDevice;
+ outDevice = nullptr;
+
+#if defined(Q_OS_WIN) && defined(Q_CC_MSVC)
+ ::_close(fd);
+#else
+ ::close(fd);
+#endif
+ fd = -1;
+ return false;
+ }
}
return true;
@@ -249,9 +262,12 @@ void QCupsPrintEnginePrivate::changePrinter(const QString &newPrinter)
duplex = m_printDevice.defaultDuplexMode();
duplexRequestedExplicitly = false;
}
- QPrint::ColorMode colorMode = grayscale ? QPrint::GrayScale : QPrint::Color;
- if (!m_printDevice.supportedColorModes().contains(colorMode))
- grayscale = m_printDevice.defaultColorMode() == QPrint::GrayScale;
+ QPrint::ColorMode colorMode = static_cast<QPrint::ColorMode>(printerColorMode());
+ if (!m_printDevice.supportedColorModes().contains(colorMode)) {
+ colorModel = (m_printDevice.defaultColorMode() == QPrint::GrayScale)
+ ? QPdfEngine::ColorModel::Grayscale
+ : QPdfEngine::ColorModel::RGB;
+ }
// Get the equivalent page size for this printer as supported names may be different
if (m_printDevice.supportedPageSize(m_pageLayout.pageSize()).isValid())
diff --git a/src/plugins/sqldrivers/.cmake.conf b/src/plugins/sqldrivers/.cmake.conf
index 146dd2bd5a..10bc1fd407 100644
--- a/src/plugins/sqldrivers/.cmake.conf
+++ b/src/plugins/sqldrivers/.cmake.conf
@@ -1 +1 @@
-set(QT_REPO_MODULE_VERSION "6.6.0")
+set(QT_REPO_MODULE_VERSION "6.8.0")
diff --git a/src/plugins/sqldrivers/CMakeLists.txt b/src/plugins/sqldrivers/CMakeLists.txt
index 7f44072da0..43abb00ad1 100644
--- a/src/plugins/sqldrivers/CMakeLists.txt
+++ b/src/plugins/sqldrivers/CMakeLists.txt
@@ -4,6 +4,14 @@
cmake_minimum_required(VERSION 3.16)
if (NOT CMAKE_PROJECT_NAME STREQUAL "QtBase" AND NOT CMAKE_PROJECT_NAME STREQUAL "Qt")
include(.cmake.conf)
+ # Store initial build type (if any is specified) to be read by
+ # qt_internal_set_cmake_build_type().
+ # See qt_internal_set_cmake_build_type() for details.
+ if(DEFINED CACHE{CMAKE_BUILD_TYPE})
+ set(__qt_internal_standalone_project_cmake_build_type_before_project_call
+ "${CMAKE_BUILD_TYPE}")
+ endif()
+
project(QSQLiteDriverPlugins
VERSION "${QT_REPO_MODULE_VERSION}"
DESCRIPTION "Qt6 SQL driver plugins"
diff --git a/src/plugins/sqldrivers/db2/qsql_db2.cpp b/src/plugins/sqldrivers/db2/qsql_db2.cpp
index a18d7a84fa..9b6a06c378 100644
--- a/src/plugins/sqldrivers/db2/qsql_db2.cpp
+++ b/src/plugins/sqldrivers/db2/qsql_db2.cpp
@@ -305,7 +305,6 @@ static QSqlField qMakeFieldInfo(const QDB2ResultPrivate* d, int i)
// else required is unknown
f.setLength(colSize == 0 ? -1 : int(colSize));
f.setPrecision(colScale == 0 ? -1 : int(colScale));
- f.setSqlType(int(colType));
SQLTCHAR tableName[TABLENAMESIZE];
SQLSMALLINT tableNameLen;
r = SQLColAttribute(d->hStmt, i + 1, SQL_DESC_BASE_TABLE_NAME, tableName,
@@ -505,7 +504,6 @@ static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt)
// else we don't know.
f.setLength(qGetIntData(hStmt, 6, isNull)); // column size
f.setPrecision(qGetIntData(hStmt, 8, isNull)); // precision
- f.setSqlType(type);
return f;
}
@@ -1706,3 +1704,5 @@ QString QDB2Driver::escapeIdentifier(const QString &identifier, IdentifierType)
}
QT_END_NAMESPACE
+
+#include "moc_qsql_db2_p.cpp"
diff --git a/src/plugins/sqldrivers/ibase/CMakeLists.txt b/src/plugins/sqldrivers/ibase/CMakeLists.txt
index a21be56b07..b8f2d2561f 100644
--- a/src/plugins/sqldrivers/ibase/CMakeLists.txt
+++ b/src/plugins/sqldrivers/ibase/CMakeLists.txt
@@ -10,6 +10,7 @@ qt_internal_add_plugin(QIBaseDriverPlugin
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
+ QT_NO_CONTEXTLESS_CONNECT
LIBRARIES
Interbase::Interbase
Qt::Core
diff --git a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp
index 4284f9b811..f6eed5e227 100644
--- a/src/plugins/sqldrivers/ibase/qsql_ibase.cpp
+++ b/src/plugins/sqldrivers/ibase/qsql_ibase.cpp
@@ -8,6 +8,7 @@
#include <QtCore/qdeadlinetimer.h>
#include <QtCore/qdebug.h>
#include <QtCore/qlist.h>
+#include <QtCore/qloggingcategory.h>
#include <QtCore/qmap.h>
#include <QtCore/qmutex.h>
#include <QtCore/qvariant.h>
@@ -25,6 +26,8 @@
QT_BEGIN_NAMESPACE
+static Q_LOGGING_CATEGORY(lcIbase, "qt.sql.ibase")
+
using namespace Qt::StringLiterals;
#define FBVERSION SQL_DIALECT_V6
@@ -115,6 +118,7 @@ static void initDA(XSQLDA *sqlda)
default:
// not supported - do not bind.
sqlda->sqlvar[i].sqldata = 0;
+ qCWarning(lcIbase, "initDA: unknown sqltype: %d", sqlda->sqlvar[i].sqltype & ~1);
break;
}
if (sqlda->sqlvar[i].sqltype & 1) {
@@ -171,7 +175,7 @@ static QMetaType::Type qIBaseTypeName(int iType, bool hasScale)
case blr_boolean_dtype:
return QMetaType::Bool;
}
- qWarning("qIBaseTypeName: unknown datatype: %d", iType);
+ qCWarning(lcIbase, "qIBaseTypeName: unknown datatype: %d", iType);
return QMetaType::UnknownType;
}
@@ -205,8 +209,10 @@ static QMetaType::Type qIBaseTypeName2(int iType, bool hasScale)
case SQL_BOOLEAN:
return QMetaType::Bool;
default:
- return QMetaType::UnknownType;
+ break;
}
+ qCWarning(lcIbase, "qIBaseTypeName: unknown datatype: %d", iType);
+ return QMetaType::UnknownType;
}
static ISC_TIMESTAMP toTimeStamp(const QDateTime &dt)
@@ -400,6 +406,42 @@ protected:
int size() override;
int numRowsAffected() override;
QSqlRecord record() const override;
+
+ template<typename T>
+ QVariant applyScale(T val, int scale) const
+ {
+ if (scale >= 0)
+ return QVariant(val);
+
+ switch (numericalPrecisionPolicy()) {
+ case QSql::LowPrecisionInt32:
+ return QVariant(qint32(val * pow(10.0, scale)));
+ case QSql::LowPrecisionInt64:
+ return QVariant(qint64(val * pow(10.0, scale)));
+ case QSql::LowPrecisionDouble:
+ return QVariant(double(val * pow(10.0, scale)));
+ case QSql::HighPrecision: {
+ const bool negative = val < 0;
+ QString number;
+ if constexpr (std::is_signed_v<T> || negative)
+ number = QString::number(qAbs(val));
+ else
+ number = QString::number(val);
+ auto len = number.size();
+ scale *= -1;
+ if (scale >= len) {
+ number = QString(scale - len + 1, u'0') + number;
+ len = number.size();
+ }
+ const auto sepPos = len - scale;
+ number = number.left(sepPos) + u'.' + number.mid(sepPos);
+ if (negative)
+ number = u'-' + number;
+ return QVariant(number);
+ }
+ }
+ return QVariant(val);
+ }
};
class QIBaseResultPrivate: public QSqlCachedResultPrivate
@@ -941,7 +983,7 @@ QIBaseResult::QIBaseResult(const QIBaseDriver *db)
bool QIBaseResult::prepare(const QString& query)
{
Q_D(QIBaseResult);
-// qDebug("prepare: %s", qPrintable(query));
+// qDebug("prepare: %ls", qUtf16Printable(query));
if (!driver() || !driver()->isOpen() || driver()->isOpenError())
return false;
d->cleanup();
@@ -950,13 +992,13 @@ bool QIBaseResult::prepare(const QString& query)
createDA(d->sqlda);
if (d->sqlda == (XSQLDA*)0) {
- qWarning()<<"QIOBaseResult: createDA(): failed to allocate memory";
+ qCWarning(lcIbase) << "QIOBaseResult: createDA(): failed to allocate memory";
return false;
}
createDA(d->inda);
if (d->inda == (XSQLDA*)0){
- qWarning()<<"QIOBaseResult: createDA(): failed to allocate memory";
+ qCWarning(lcIbase) << "QIOBaseResult: createDA(): failed to allocate memory";
return false;
}
@@ -980,7 +1022,7 @@ bool QIBaseResult::prepare(const QString& query)
if (d->inda->sqld > d->inda->sqln) {
enlargeDA(d->inda, d->inda->sqld);
if (d->inda == (XSQLDA*)0) {
- qWarning()<<"QIOBaseResult: enlargeDA(): failed to allocate memory";
+ qCWarning(lcIbase) << "QIOBaseResult: enlargeDA(): failed to allocate memory";
return false;
}
@@ -994,7 +1036,7 @@ bool QIBaseResult::prepare(const QString& query)
// need more field descriptors
enlargeDA(d->sqlda, d->sqlda->sqld);
if (d->sqlda == (XSQLDA*)0) {
- qWarning()<<"QIOBaseResult: enlargeDA(): failed to allocate memory";
+ qCWarning(lcIbase) << "QIOBaseResult: enlargeDA(): failed to allocate memory";
return false;
}
@@ -1030,9 +1072,9 @@ bool QIBaseResult::exec()
if (d->inda) {
const QList<QVariant> &values = boundValues();
if (values.count() > d->inda->sqld) {
- qWarning() << "QIBaseResult::exec: Parameter mismatch, expected"_L1 <<
- d->inda->sqld << ", got"_L1 << values.count() <<
- "parameters"_L1;
+ qCWarning(lcIbase) << "QIBaseResult::exec: Parameter mismatch, expected"_L1
+ << d->inda->sqld << ", got"_L1 << values.count()
+ << "parameters"_L1;
return false;
}
for (qsizetype para = 0; para < values.count(); ++para) {
@@ -1051,6 +1093,12 @@ bool QIBaseResult::exec()
}
// a value of 0 means non-null.
*(d->inda->sqlvar[para].sqlind) = 0;
+ } else {
+ if (QSqlResultPrivate::isVariantNull(val)) {
+ qCWarning(lcIbase) << "QIBaseResult::exec: Null value replaced by default (zero)"_L1
+ << "value for type of column"_L1 << d->inda->sqlvar[para].ownname
+ << ", which is not nullable."_L1;
+ }
}
switch(d->inda->sqlvar[para].sqltype & ~1) {
case SQL_INT64:
@@ -1114,8 +1162,8 @@ bool QIBaseResult::exec()
*((bool*)d->inda->sqlvar[para].sqldata) = val.toBool();
break;
default:
- qWarning("QIBaseResult::exec: Unknown datatype %d",
- d->inda->sqlvar[para].sqltype & ~1);
+ qCWarning(lcIbase, "QIBaseResult::exec: Unknown datatype %d",
+ d->inda->sqlvar[para].sqltype & ~1);
break;
}
}
@@ -1227,27 +1275,27 @@ bool QIBaseResult::gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx)
// pascal strings - a short with a length information followed by the data
row[idx] = QString::fromUtf8(buf + sizeof(short), *(short*)buf);
break;
- case SQL_INT64:
- if (d->sqlda->sqlvar[i].sqlscale < 0)
- row[idx] = *(qint64*)buf * pow(10.0, d->sqlda->sqlvar[i].sqlscale);
- else
- row[idx] = QVariant(*(qint64*)buf);
+ case SQL_INT64: {
+ Q_ASSERT(d->sqlda->sqlvar[i].sqllen == sizeof(qint64));
+ const auto val = *(qint64 *)buf;
+ const auto scale = d->sqlda->sqlvar[i].sqlscale;
+ row[idx] = applyScale(val, scale);
break;
+ }
case SQL_LONG:
- if (d->sqlda->sqlvar[i].sqllen == 4)
- if (d->sqlda->sqlvar[i].sqlscale < 0)
- row[idx] = QVariant(*(qint32*)buf * pow(10.0, d->sqlda->sqlvar[i].sqlscale));
- else
- row[idx] = QVariant(*(qint32*)buf);
- else
+ if (d->sqlda->sqlvar[i].sqllen == 4) {
+ const auto val = *(qint32 *)buf;
+ const auto scale = d->sqlda->sqlvar[i].sqlscale;
+ row[idx] = applyScale(val, scale);
+ } else
row[idx] = QVariant(*(qint64*)buf);
break;
- case SQL_SHORT:
- if (d->sqlda->sqlvar[i].sqlscale < 0)
- row[idx] = QVariant(long((*(short*)buf)) * pow(10.0, d->sqlda->sqlvar[i].sqlscale));
- else
- row[idx] = QVariant(int((*(short*)buf)));
+ case SQL_SHORT: {
+ const auto val = *(short *)buf;
+ const auto scale = d->sqlda->sqlvar[i].sqlscale;
+ row[idx] = applyScale(val, scale);
break;
+ }
case SQL_FLOAT:
row[idx] = QVariant(double((*(float*)buf)));
break;
@@ -1282,30 +1330,11 @@ bool QIBaseResult::gotoNext(QSqlCachedResult::ValueCache& row, int rowIdx)
#endif
default:
// unknown type - don't even try to fetch
+ qCWarning(lcIbase, "gotoNext: unknown sqltype: %d",
+ d->sqlda->sqlvar[i].sqltype & ~1);
row[idx] = QVariant();
break;
}
- if (d->sqlda->sqlvar[i].sqlscale < 0) {
- QVariant v = row[idx];
- switch(numericalPrecisionPolicy()) {
- case QSql::LowPrecisionInt32:
- if (v.convert(QMetaType(QMetaType::Int)))
- row[idx]=v;
- break;
- case QSql::LowPrecisionInt64:
- if (v.convert(QMetaType(QMetaType::LongLong)))
- row[idx]=v;
- break;
- case QSql::LowPrecisionDouble:
- if (v.convert(QMetaType(QMetaType::Double)))
- row[idx]=v;
- break;
- case QSql::HighPrecision:
- if (v.convert(QMetaType(QMetaType::QString)))
- row[idx]=v;
- break;
- }
- }
}
return true;
@@ -1386,7 +1415,7 @@ int QIBaseResult::numRowsAffected()
bIsProcedure = true; // will sum all changes
break;
default:
- qWarning() << "numRowsAffected: Unknown statement type (" << d->queryType << ")";
+ qCWarning(lcIbase) << "numRowsAffected: Unknown statement type (" << d->queryType << ")";
return -1;
}
@@ -1452,7 +1481,6 @@ QSqlRecord QIBaseResult::record() const
f.setRequiredStatus(q.value(3).toBool() ? QSqlField::Required : QSqlField::Optional);
}
}
- f.setSqlType(v.sqltype);
rec.append(f);
}
return rec;
@@ -1700,13 +1728,9 @@ QSqlRecord QIBaseDriver::record(const QString& tablename) const
if (!isOpen())
return rec;
+ const QString table = stripDelimiters(tablename, QSqlDriver::TableName);
QSqlQuery q(createResult());
q.setForwardOnly(true);
- QString table = tablename;
- if (isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
- else
- table = table.toUpper();
q.exec("SELECT a.RDB$FIELD_NAME, b.RDB$FIELD_TYPE, b.RDB$FIELD_LENGTH, "
"b.RDB$FIELD_SCALE, b.RDB$FIELD_PRECISION, a.RDB$NULL_FLAG "
"FROM RDB$RELATION_FIELDS a, RDB$FIELDS b "
@@ -1726,7 +1750,6 @@ QSqlRecord QIBaseDriver::record(const QString& tablename) const
f.setPrecision(0);
}
f.setRequired(q.value(5).toInt() > 0);
- f.setSqlType(type);
rec.append(f);
}
@@ -1739,12 +1762,7 @@ QSqlIndex QIBaseDriver::primaryIndex(const QString &table) const
if (!isOpen())
return index;
- QString tablename = table;
- if (isIdentifierEscaped(tablename, QSqlDriver::TableName))
- tablename = stripDelimiters(tablename, QSqlDriver::TableName);
- else
- tablename = tablename.toUpper();
-
+ const QString tablename = stripDelimiters(table, QSqlDriver::TableName);
QSqlQuery q(createResult());
q.setForwardOnly(true);
q.exec("SELECT a.RDB$INDEX_NAME, b.RDB$FIELD_NAME, d.RDB$FIELD_TYPE, d.RDB$FIELD_SCALE "
@@ -1839,13 +1857,13 @@ bool QIBaseDriver::subscribeToNotification(const QString &name)
{
Q_D(QIBaseDriver);
if (!isOpen()) {
- qWarning("QIBaseDriver::subscribeFromNotificationImplementation: database not open.");
+ qCWarning(lcIbase, "QIBaseDriver::subscribeFromNotificationImplementation: database not open.");
return false;
}
if (d->eventBuffers.contains(name)) {
- qWarning("QIBaseDriver::subscribeToNotificationImplementation: already subscribing to '%s'.",
- qPrintable(name));
+ qCWarning(lcIbase, "QIBaseDriver::subscribeToNotificationImplementation: already subscribing to '%ls'.",
+ qUtf16Printable(name));
return false;
}
@@ -1886,13 +1904,13 @@ bool QIBaseDriver::unsubscribeFromNotification(const QString &name)
{
Q_D(QIBaseDriver);
if (!isOpen()) {
- qWarning("QIBaseDriver::unsubscribeFromNotificationImplementation: database not open.");
+ qCWarning(lcIbase, "QIBaseDriver::unsubscribeFromNotificationImplementation: database not open.");
return false;
}
if (!d->eventBuffers.contains(name)) {
- qWarning("QIBaseDriver::QIBaseSubscriptionState not subscribed to '%s'.",
- qPrintable(name));
+ qCWarning(lcIbase, "QIBaseDriver::QIBaseSubscriptionState not subscribed to '%ls'.",
+ qUtf16Printable(name));
return false;
}
@@ -1947,8 +1965,8 @@ void QIBaseDriver::qHandleEventNotification(void *updatedResultBuffer)
(&qEventCallback)),
eBuffer->resultBuffer);
if (Q_UNLIKELY(status[0] == 1 && status[1])) {
- qCritical("QIBaseDriver::qHandleEventNotification: could not resubscribe to '%s'",
- qPrintable(i.key()));
+ qCritical("QIBaseDriver::qHandleEventNotification: could not resubscribe to '%ls'",
+ qUtf16Printable(i.key()));
}
return;
@@ -1974,3 +1992,5 @@ int QIBaseDriver::maximumIdentifierLength(IdentifierType type) const
}
QT_END_NAMESPACE
+
+#include "moc_qsql_ibase_p.cpp"
diff --git a/src/plugins/sqldrivers/mimer/CMakeLists.txt b/src/plugins/sqldrivers/mimer/CMakeLists.txt
index fd160fe477..303af7120c 100644
--- a/src/plugins/sqldrivers/mimer/CMakeLists.txt
+++ b/src/plugins/sqldrivers/mimer/CMakeLists.txt
@@ -13,6 +13,7 @@ qt_internal_add_plugin(QMimerSQLDriverPlugin
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
+ QT_NO_CONTEXTLESS_CONNECT
LIBRARIES
MimerSQL::MimerSQL
Qt::Core
diff --git a/src/plugins/sqldrivers/mimer/qsql_mimer.cpp b/src/plugins/sqldrivers/mimer/qsql_mimer.cpp
index 3037f10473..7f89e0a0d5 100644
--- a/src/plugins/sqldrivers/mimer/qsql_mimer.cpp
+++ b/src/plugins/sqldrivers/mimer/qsql_mimer.cpp
@@ -5,6 +5,7 @@
#include <qvariant.h>
#include <qmetatype.h>
#include <qdatetime.h>
+#include <qloggingcategory.h>
#include <qsqlerror.h>
#include <qsqlfield.h>
#include <qsqlindex.h>
@@ -30,12 +31,15 @@ Q_DECLARE_METATYPE(MimerStatement)
QT_BEGIN_NAMESPACE
+static Q_LOGGING_CATEGORY(lcMimer, "qt.sql.mimer")
+
enum class MimerColumnTypes {
Binary,
Clob,
Blob,
String,
Int,
+ Numeric,
Long,
Float,
Double,
@@ -157,6 +161,20 @@ static QSqlError qMakeError(const QString &err, const int errCode, QSqlError::Er
return QSqlError("QMIMER: "_L1 + err, msg, type, QString::number(errCode));
}
+static QString msgCouldNotGet(const char *type, int column)
+{
+ //: Data type, column
+ return QCoreApplication::translate("QMimerSQLResult",
+ "Could not get %1, column %2").arg(QLatin1StringView(type)).arg(column);
+}
+
+static QString msgCouldNotSet(const char *type, int column)
+{
+ //: Data type, parameter
+ return QCoreApplication::translate("QMimerSQLResult",
+ "Could not set %1, parameter %2").arg(QLatin1StringView(type)).arg(column);
+}
+
QMimerSQLDriver::QMimerSQLDriver(QObject *parent) : QSqlDriver(*new QMimerSQLDriverPrivate, parent)
{
}
@@ -207,7 +225,6 @@ static MimerColumnTypes mimerMapColumnTypes(int32_t t)
case MIMER_TIMESTAMP:
return MimerColumnTypes::Timestamp;
case MIMER_INTERVAL_DAY:
- case MIMER_DECIMAL:
case MIMER_INTERVAL_DAY_TO_HOUR:
case MIMER_INTERVAL_DAY_TO_MINUTE:
case MIMER_INTERVAL_DAY_TO_SECOND:
@@ -227,6 +244,10 @@ static MimerColumnTypes mimerMapColumnTypes(int32_t t)
case MIMER_UTF8:
case MIMER_DEFAULT_DATATYPE:
return MimerColumnTypes::String;
+ case MIMER_INTEGER:
+ case MIMER_DECIMAL:
+ case MIMER_FLOAT:
+ return MimerColumnTypes::Numeric;
case MIMER_BOOLEAN:
return MimerColumnTypes::Boolean;
case MIMER_T_BIGINT:
@@ -234,19 +255,17 @@ static MimerColumnTypes mimerMapColumnTypes(int32_t t)
case MIMER_NATIVE_BIGINT_NULLABLE:
case MIMER_NATIVE_BIGINT:
return MimerColumnTypes::Long;
- case MIMER_T_FLOAT:
- case MIMER_FLOAT:
- return MimerColumnTypes::Float;
case MIMER_NATIVE_REAL_NULLABLE:
case MIMER_NATIVE_REAL:
case MIMER_T_REAL:
+ return MimerColumnTypes::Float;
+ case MIMER_T_FLOAT:
case MIMER_NATIVE_DOUBLE_NULLABLE:
case MIMER_NATIVE_DOUBLE:
case MIMER_T_DOUBLE:
return MimerColumnTypes::Double;
case MIMER_NATIVE_INTEGER:
case MIMER_NATIVE_INTEGER_NULLABLE:
- case MIMER_INTEGER:
case MIMER_NATIVE_SMALLINT_NULLABLE:
case MIMER_NATIVE_SMALLINT:
case MIMER_T_INTEGER:
@@ -255,7 +274,7 @@ static MimerColumnTypes mimerMapColumnTypes(int32_t t)
case MIMER_UUID:
return MimerColumnTypes::Uuid;
default:
- qWarning() << "QMimerSQLDriver::mimerMapColumnTypes: Unknown data type: " << t;
+ qCWarning(lcMimer) << "QMimerSQLDriver::mimerMapColumnTypes: Unknown data type:" << t;
}
return MimerColumnTypes::Unknown;
}
@@ -292,6 +311,8 @@ static QMetaType::Type qDecodeMSQLType(int32_t t)
case MIMER_NCHAR_VARYING:
case MIMER_UTF8:
case MIMER_DEFAULT_DATATYPE:
+ case MIMER_INTEGER:
+ case MIMER_FLOAT:
return QMetaType::QString;
case MIMER_BOOLEAN:
return QMetaType::Bool;
@@ -300,19 +321,18 @@ static QMetaType::Type qDecodeMSQLType(int32_t t)
case MIMER_NATIVE_BIGINT_NULLABLE:
case MIMER_NATIVE_BIGINT:
return QMetaType::LongLong;
- case MIMER_T_FLOAT:
- case MIMER_FLOAT:
- return QMetaType::Float;
case MIMER_NATIVE_REAL_NULLABLE:
case MIMER_NATIVE_REAL:
case MIMER_T_REAL:
+ return QMetaType::Float;
+ case MIMER_T_FLOAT:
case MIMER_NATIVE_DOUBLE_NULLABLE:
case MIMER_NATIVE_DOUBLE:
case MIMER_T_DOUBLE:
return QMetaType::Double;
case MIMER_NATIVE_INTEGER_NULLABLE:
case MIMER_T_INTEGER:
- case MIMER_INTEGER:
+ case MIMER_NATIVE_INTEGER:
return QMetaType::Int;
case MIMER_NATIVE_SMALLINT_NULLABLE:
case MIMER_T_SMALLINT:
@@ -327,7 +347,7 @@ static QMetaType::Type qDecodeMSQLType(int32_t t)
case MIMER_UUID:
return QMetaType::QUuid;
default:
- qWarning() << "QMimerSQLDriver::qDecodeMSQLType: Unknown data type: " << t;
+ qCWarning(lcMimer) << "QMimerSQLDriver::qDecodeMSQLType: Unknown data type:" << t;
return QMetaType::UnknownType;
}
}
@@ -393,7 +413,7 @@ static int32_t qLookupMimDataType(QStringView s)
if (s == u"DOUBLE PRECISION")
return MIMER_T_DOUBLE;
if (s == u"INTEGER")
- return MIMER_INTEGER;
+ return MIMER_T_INTEGER;
if (s == u"SMALLINT")
return MIMER_T_SMALLINT;
if (s == u"DATE")
@@ -406,7 +426,7 @@ static int32_t qLookupMimDataType(QStringView s)
return MIMER_UUID;
if (s == u"USER-DEFINED")
return MIMER_DEFAULT_DATATYPE;
- qWarning() << "QMimerSQLDriver::qLookupMimDataType: Unhandled data type: " << s;
+ qCWarning(lcMimer) << "QMimerSQLDriver::qLookupMimDataType: Unhandled data type:" << s;
return MIMER_DEFAULT_DATATYPE;
}
@@ -590,7 +610,7 @@ QVariant QMimerSQLResult::data(int i)
genericError, QSqlError::StatementError, nullptr));
return QVariant();
}
- mType = MimerParameterType(d->statementhandle, static_cast<std::int16_t>(i) + 1);
+ mType = MimerParameterType(d->statementhandle, static_cast<std::int16_t>(i + 1));
} else {
if (i >= MimerColumnCount(d->statementhandle)) {
setLastError(qMakeError(
@@ -599,23 +619,21 @@ QVariant QMimerSQLResult::data(int i)
genericError, QSqlError::StatementError, nullptr));
return QVariant();
}
- mType = MimerColumnType(d->statementhandle, static_cast<std::int16_t>(i) + 1);
+ mType = MimerColumnType(d->statementhandle, static_cast<std::int16_t>(i + 1));
}
const QMetaType::Type type = qDecodeMSQLType(mType);
const MimerColumnTypes mimDataType = mimerMapColumnTypes(mType);
- err = MimerIsNull(d->statementhandle, static_cast<std::int16_t>(i) + 1);
+ err = MimerIsNull(d->statementhandle, static_cast<std::int16_t>(i + 1));
if (err > 0) {
return QVariant(QMetaType(type), nullptr);
} else {
switch (mimDataType) {
case MimerColumnTypes::Date: {
wchar_t dateString_w[maxDateStringSize + 1];
- err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i) + 1, dateString_w,
+ err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i + 1), dateString_w,
sizeof(dateString_w) / sizeof(dateString_w[0]));
if (!MIMER_SUCCEEDED(err)) {
- setLastError(qMakeError(QCoreApplication::translate("QMimerSQLResult",
- "Could not get date, column %1")
- .arg(i),
+ setLastError(qMakeError(msgCouldNotGet("date", i),
err, QSqlError::StatementError, d->drv_d_func()));
return QVariant(QMetaType(type), nullptr);
}
@@ -623,12 +641,10 @@ QVariant QMimerSQLResult::data(int i)
}
case MimerColumnTypes::Time: {
wchar_t timeString_w[maxTimeStringSize + 1];
- err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i) + 1, timeString_w,
+ err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i + 1), timeString_w,
sizeof(timeString_w) / sizeof(timeString_w[0]));
if (!MIMER_SUCCEEDED(err)) {
- setLastError(qMakeError(QCoreApplication::translate("QMimerSQLResult",
- "Could not get time, column %1")
- .arg(i),
+ setLastError(qMakeError(msgCouldNotGet("time", i),
err, QSqlError::StatementError, d->drv_d_func()));
return QVariant(QMetaType(type), nullptr);
}
@@ -642,14 +658,12 @@ QVariant QMimerSQLResult::data(int i)
}
case MimerColumnTypes::Timestamp: {
wchar_t dateTimeString_w[maxTimestampStringSize + 1];
- err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i) + 1,
+ err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i + 1),
dateTimeString_w,
sizeof(dateTimeString_w) / sizeof(dateTimeString_w[0]));
if (!MIMER_SUCCEEDED(err)) {
setLastError(
- qMakeError(QCoreApplication::translate("QMimerSQLResult",
- "Could not get date time, column %1")
- .arg(i),
+ qMakeError(msgCouldNotGet("date time", i),
err, QSqlError::StatementError, d->drv_d_func()));
return QVariant(QMetaType(type), nullptr);
}
@@ -663,11 +677,9 @@ QVariant QMimerSQLResult::data(int i)
}
case MimerColumnTypes::Int: {
int resInt;
- err = MimerGetInt32(d->statementhandle, static_cast<std::int16_t>(i) + 1, &resInt);
+ err = MimerGetInt32(d->statementhandle, static_cast<std::int16_t>(i + 1), &resInt);
if (!MIMER_SUCCEEDED(err)) {
- setLastError(qMakeError(QCoreApplication::translate(
- "QMimerSQLResult", "Could not get int32, column %1")
- .arg(i),
+ setLastError(qMakeError(msgCouldNotGet("int32", i),
err, QSqlError::StatementError, d->drv_d_func()));
return QVariant(QMetaType(type), nullptr);
}
@@ -675,23 +687,19 @@ QVariant QMimerSQLResult::data(int i)
}
case MimerColumnTypes::Long: {
int64_t resLongLong;
- err = MimerGetInt64(d->statementhandle, static_cast<std::int16_t>(i) + 1, &resLongLong);
+ err = MimerGetInt64(d->statementhandle, static_cast<std::int16_t>(i + 1), &resLongLong);
if (!MIMER_SUCCEEDED(err)) {
- setLastError(qMakeError(QCoreApplication::translate(
- "QMimerSQLResult", "Could not get int64, column %1")
- .arg(i),
+ setLastError(qMakeError(msgCouldNotGet("int64", i),
err, QSqlError::StatementError, d->drv_d_func()));
return QVariant(QMetaType(type), nullptr);
}
- return QString::number(resLongLong).toLongLong();
+ return (qlonglong)resLongLong;
}
case MimerColumnTypes::Boolean: {
- err = MimerGetBoolean(d->statementhandle, static_cast<std::int16_t>(i) + 1);
+ err = MimerGetBoolean(d->statementhandle, static_cast<std::int16_t>(i + 1));
if (!MIMER_SUCCEEDED(err)) {
setLastError(
- qMakeError(QCoreApplication::translate("QMimerSQLResult",
- "Could not get boolean, column %1")
- .arg(i),
+ qMakeError(msgCouldNotGet("boolean", i),
err, QSqlError::StatementError, d->drv_d_func()));
return QVariant(QMetaType(type), nullptr);
}
@@ -699,11 +707,9 @@ QVariant QMimerSQLResult::data(int i)
}
case MimerColumnTypes::Float: {
float resFloat;
- err = MimerGetFloat(d->statementhandle, static_cast<std::int16_t>(i) + 1, &resFloat);
+ err = MimerGetFloat(d->statementhandle, static_cast<std::int16_t>(i + 1), &resFloat);
if (!MIMER_SUCCEEDED(err)) {
- setLastError(qMakeError(QCoreApplication::translate(
- "QMimerSQLResult", "Could not get float, column %1")
- .arg(i),
+ setLastError(qMakeError(msgCouldNotGet("float", i),
err, QSqlError::StatementError, d->drv_d_func()));
return QVariant(QMetaType(type), nullptr);
}
@@ -711,12 +717,10 @@ QVariant QMimerSQLResult::data(int i)
}
case MimerColumnTypes::Double: {
double resDouble;
- err = MimerGetDouble(d->statementhandle, static_cast<std::int16_t>(i) + 1, &resDouble);
+ err = MimerGetDouble(d->statementhandle, static_cast<std::int16_t>(i + 1), &resDouble);
if (!MIMER_SUCCEEDED(err)) {
setLastError(
- qMakeError(QCoreApplication::translate("QMimerSQLResult",
- "Could not get double, column %1")
- .arg(i),
+ qMakeError(msgCouldNotGet("double", i),
err, QSqlError::StatementError, d->drv_d_func()));
return QVariant(QMetaType(type), nullptr);
}
@@ -726,7 +730,7 @@ QVariant QMimerSQLResult::data(int i)
case QSql::LowPrecisionInt64:
return static_cast<qint64>(resDouble);
case QSql::LowPrecisionDouble:
- return resDouble;
+ return static_cast<qreal>(resDouble);
case QSql::HighPrecision:
return QString::number(resDouble, 'g', 17);
}
@@ -735,17 +739,15 @@ QVariant QMimerSQLResult::data(int i)
case MimerColumnTypes::Binary: {
QByteArray byteArray;
// Get size
- err = MimerGetBinary(d->statementhandle, static_cast<std::int16_t>(i) + 1, NULL, 0);
+ err = MimerGetBinary(d->statementhandle, static_cast<std::int16_t>(i + 1), NULL, 0);
if (MIMER_SUCCEEDED(err)) {
byteArray.resize(err);
- err = MimerGetBinary(d->statementhandle, static_cast<std::int16_t>(i) + 1,
+ err = MimerGetBinary(d->statementhandle, static_cast<std::int16_t>(i + 1),
byteArray.data(), err);
}
if (!MIMER_SUCCEEDED(err)) {
setLastError(
- qMakeError(QCoreApplication::translate("QMimerSQLResult",
- "Could not get binary, column %1")
- .arg(i),
+ qMakeError(msgCouldNotGet("binary", i),
err, QSqlError::StatementError, d->drv_d_func()));
return QVariant(QMetaType(type), nullptr);
}
@@ -754,7 +756,7 @@ QVariant QMimerSQLResult::data(int i)
case MimerColumnTypes::Blob: {
QByteArray byteArray;
size_t size;
- err = MimerGetLob(d->statementhandle, static_cast<std::int16_t>(i) + 1, &size,
+ err = MimerGetLob(d->statementhandle, static_cast<std::int16_t>(i + 1), &size,
&d->lobhandle);
if (MIMER_SUCCEEDED(err)) {
constexpr size_t maxSize = lobChunkMaxSizeFetch;
@@ -768,53 +770,48 @@ QVariant QMimerSQLResult::data(int i)
byteArray.append(QByteArray::fromRawData(blobchar.data(), bytesToReceive));
left_to_return -= bytesToReceive;
if (!MIMER_SUCCEEDED(err)) {
- setLastError(qMakeError(
- QCoreApplication::translate("QMimerSQLResult",
- "Could not get blob, column %1")
- .arg(i),
+ setLastError(qMakeError(msgCouldNotGet("BLOB", i),
err, QSqlError::StatementError, d->drv_d_func()));
return QVariant(QMetaType(type), nullptr);
}
}
} else {
- setLastError(qMakeError(QCoreApplication::translate("QMimerSQLResult",
- "Could not get blob, column %1")
- .arg(i),
+ setLastError(qMakeError(msgCouldNotGet("BLOB", i),
err, QSqlError::StatementError, d->drv_d_func()));
return QVariant(QMetaType(type), nullptr);
}
return byteArray;
}
+ case MimerColumnTypes::Numeric:
case MimerColumnTypes::String: {
wchar_t resString_w[maxStackStringSize + 1];
// Get size
- err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i) + 1, resString_w,
+ err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i + 1), resString_w,
0);
if (MIMER_SUCCEEDED(err)) {
int size = err;
if (err <= maxStackStringSize) { // For smaller strings, use a small buffer for
// efficiency
- err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i) + 1,
+ err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i + 1),
resString_w, maxStackStringSize + 1);
if (MIMER_SUCCEEDED(err))
return QString::fromWCharArray(resString_w);
} else { // For larger strings, dynamically allocate memory
QVarLengthArray<wchar_t> largeResString_w(size + 1);
- err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i) + 1,
+ err = MimerGetString(d->statementhandle, static_cast<std::int16_t>(i + 1),
largeResString_w.data(), size + 1);
if (MIMER_SUCCEEDED(err))
return QString::fromWCharArray(largeResString_w.data());
}
}
- setLastError(qMakeError(QCoreApplication::translate("QMimerSQLResult",
- "Could not get string, column %1")
- .arg(i),
- err, QSqlError::StatementError, d->drv_d_func()));
+ setLastError(qMakeError(msgCouldNotGet(
+ mimDataType == MimerColumnTypes::Numeric ? "numeric" : "string", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
return QVariant(QMetaType(type), nullptr);
}
case MimerColumnTypes::Clob: {
size_t size;
- err = MimerGetLob(d->statementhandle, static_cast<std::int16_t>(i) + 1, &size,
+ err = MimerGetLob(d->statementhandle, static_cast<std::int16_t>(i + 1), &size,
&d->lobhandle);
if (MIMER_SUCCEEDED(err)) {
constexpr size_t maxSize = lobChunkMaxSizeFetch;
@@ -829,29 +826,22 @@ QVariant QMimerSQLResult::data(int i)
returnString.append(QString::fromWCharArray(clobstring_w.data()));
left_to_return -= bytesToReceive;
if (!MIMER_SUCCEEDED(err)) {
- setLastError(qMakeError(
- QCoreApplication::translate("QMimerSQLResult",
- "Could not get clob, column %1")
- .arg(i),
+ setLastError(qMakeError(msgCouldNotGet("CLOB", i),
err, QSqlError::StatementError, d->drv_d_func()));
return QVariant(QMetaType(type), nullptr);
}
}
return returnString;
}
- setLastError(qMakeError(
- QCoreApplication::translate("QMimerSQLResult", "Could not get clob, column %1")
- .arg(i),
+ setLastError(qMakeError(msgCouldNotGet("CLOB", i),
err, QSqlError::StatementError, d->drv_d_func()));
return QVariant(QMetaType(type), nullptr);
}
case MimerColumnTypes::Uuid: {
unsigned char uuidChar[16];
- err = MimerGetUUID(d->statementhandle, static_cast<std::int16_t>(i) + 1, uuidChar);
+ err = MimerGetUUID(d->statementhandle, static_cast<std::int16_t>(i + 1), uuidChar);
if (!MIMER_SUCCEEDED(err)) {
- setLastError(qMakeError(QCoreApplication::translate("QMimerSQLResult",
- "Could not get uuid, column %1")
- .arg(i),
+ setLastError(qMakeError(msgCouldNotGet("UUID", i),
err, QSqlError::StatementError, d->drv_d_func()));
return QVariant(QMetaType(type), nullptr);
}
@@ -871,7 +861,7 @@ QVariant QMimerSQLResult::data(int i)
bool QMimerSQLResult::isNull(int index)
{
Q_D(const QMimerSQLResult);
- const int32_t rc = MimerIsNull(d->statementhandle, static_cast<std::int16_t>(index) + 1);
+ const int32_t rc = MimerIsNull(d->statementhandle, static_cast<std::int16_t>(index + 1));
if (!MIMER_SUCCEEDED(rc)) {
setLastError(qMakeError(
QCoreApplication::translate("QMimerSQLResult", "Could not check null, column %1")
@@ -924,12 +914,11 @@ QSqlRecord QMimerSQLResult::record() const
const int colSize = MimerColumnCount(d->statementhandle);
for (int i = 0; i < colSize; i++) {
wchar_t colName_w[100];
- MimerColumnName(d->statementhandle, static_cast<std::int16_t>(i) + 1, colName_w,
+ MimerColumnName(d->statementhandle, static_cast<std::int16_t>(i + 1), colName_w,
sizeof(colName_w) / sizeof(colName_w[0]));
field.setName(QString::fromWCharArray(colName_w));
- const int32_t mType = MimerColumnType(d->statementhandle, static_cast<std::int16_t>(i) + 1);
+ const int32_t mType = MimerColumnType(d->statementhandle, static_cast<std::int16_t>(i + 1));
const QMetaType::Type type = qDecodeMSQLType(mType);
- field.setSqlType(mType);
field.setMetaType(QMetaType(type));
field.setValue(QVariant(field.metaType()));
// field.setPrecision(); Should be implemented once the Mimer API can give this
@@ -1014,9 +1003,7 @@ bool QMimerSQLResult::exec()
err = MimerSetNull(d->statementhandle, i + 1);
if (!MIMER_SUCCEEDED(err)) {
setLastError(
- qMakeError(QCoreApplication::translate("QMimerSQLResult",
- "Could not set null, parameter %1")
- .arg(i),
+ qMakeError(msgCouldNotSet("null", i),
err, QSqlError::StatementError, d->drv_d_func()));
return false;
}
@@ -1031,9 +1018,7 @@ bool QMimerSQLResult::exec()
err = MimerSetInt32(d->statementhandle, i + 1, val.toInt(&convertOk));
if (!convertOk || !MIMER_SUCCEEDED(err)) {
setLastError(
- qMakeError(QCoreApplication::translate("QMimerSQLResult",
- "Could not set int32, parameter %1")
- .arg(i),
+ qMakeError(msgCouldNotSet("int32", i),
convertOk ? err : genericError, QSqlError::StatementError,
convertOk ? d->drv_d_func() : nullptr));
return false;
@@ -1045,9 +1030,7 @@ bool QMimerSQLResult::exec()
err = MimerSetInt64(d->statementhandle, i + 1, val.toLongLong(&convertOk));
if (!convertOk || !MIMER_SUCCEEDED(err)) {
setLastError(
- qMakeError(QCoreApplication::translate("QMimerSQLResult",
- "Could not set int64, parameter %1")
- .arg(i),
+ qMakeError(msgCouldNotSet("int64", i),
convertOk ? err : genericError, QSqlError::StatementError,
convertOk ? d->drv_d_func() : nullptr));
return false;
@@ -1059,9 +1042,7 @@ bool QMimerSQLResult::exec()
err = MimerSetFloat(d->statementhandle, i + 1, val.toFloat(&convertOk));
if (!convertOk || !MIMER_SUCCEEDED(err)) {
setLastError(
- qMakeError(QCoreApplication::translate("QMimerSQLResult",
- "Could not set float, parameter %1")
- .arg(i),
+ qMakeError(msgCouldNotSet("float", i),
convertOk ? err : genericError, QSqlError::StatementError,
convertOk ? d->drv_d_func() : nullptr));
return false;
@@ -1073,9 +1054,7 @@ bool QMimerSQLResult::exec()
err = MimerSetDouble(d->statementhandle, i + 1, val.toDouble(&convertOk));
if (!convertOk || !MIMER_SUCCEEDED(err)) {
setLastError(
- qMakeError(QCoreApplication::translate("QMimerSQLResult",
- "Could not set double, parameter %1")
- .arg(i),
+ qMakeError(msgCouldNotSet("double", i),
convertOk ? err : genericError, QSqlError::StatementError,
convertOk ? d->drv_d_func() : nullptr));
return false;
@@ -1088,9 +1067,7 @@ bool QMimerSQLResult::exec()
err = MimerSetBinary(d->statementhandle, i + 1, binArr.data(), size);
if (!MIMER_SUCCEEDED(err)) {
setLastError(
- qMakeError(QCoreApplication::translate("QMimerSQLResult",
- "Could not set binary, parameter %1")
- .arg(i),
+ qMakeError(msgCouldNotSet("binary", i),
err, QSqlError::StatementError, d->drv_d_func()));
return false;
}
@@ -1100,9 +1077,7 @@ bool QMimerSQLResult::exec()
err = MimerSetBoolean(d->statementhandle, i + 1, val.toBool() == true ? 1 : 0);
if (!MIMER_SUCCEEDED(err)) {
setLastError(
- qMakeError(QCoreApplication::translate(
- "QMimerSQLResult", "Could not set boolean, parameter %1")
- .arg(i),
+ qMakeError(msgCouldNotSet("boolean", i),
err, QSqlError::StatementError, d->drv_d_func()));
return false;
}
@@ -1116,24 +1091,22 @@ bool QMimerSQLResult::exec()
err = MimerSetUUID(d->statementhandle, i + 1, uuid);
if (!MIMER_SUCCEEDED(err)) {
setLastError(
- qMakeError(QCoreApplication::translate("QMimerSQLResult",
- "Could not set UUID, parameter %1")
- .arg(i),
+ qMakeError(msgCouldNotSet("UUID", i),
err, QSqlError::StatementError, d->drv_d_func()));
return false;
}
break;
}
+ case MimerColumnTypes::Numeric:
case MimerColumnTypes::String: {
QByteArray string_b = val.toString().trimmed().toUtf8();
const char *string_u = string_b.constData();
err = MimerSetString8(d->statementhandle, i + 1, string_u);
if (!MIMER_SUCCEEDED(err)) {
setLastError(
- qMakeError(QCoreApplication::translate("QMimerSQLResult",
- "Could not set string, parameter %1")
- .arg(i),
- err, QSqlError::StatementError, d->drv_d_func()));
+ qMakeError(msgCouldNotSet(
+ mimDataType == MimerColumnTypes::Numeric ? "numeric" : "string", i),
+ err, QSqlError::StatementError, d->drv_d_func()));
return false;
}
break;
@@ -1142,9 +1115,7 @@ bool QMimerSQLResult::exec()
err = MimerSetString8(d->statementhandle, i + 1, val.toString().toUtf8().constData());
if (!MIMER_SUCCEEDED(err)) {
setLastError(
- qMakeError(QCoreApplication::translate("QMimerSQLResult",
- "Could not set date, parameter %1")
- .arg(i),
+ qMakeError(msgCouldNotSet("date", i),
err, QSqlError::StatementError, d->drv_d_func()));
return false;
}
@@ -1159,9 +1130,7 @@ bool QMimerSQLResult::exec()
timeVal.toString(timeFormatString).toUtf8().constData());
if (!MIMER_SUCCEEDED(err)) {
setLastError(
- qMakeError(QCoreApplication::translate("QMimerSQLResult",
- "Could not set time, parameter %1")
- .arg(i),
+ qMakeError(msgCouldNotSet("time", i),
err, QSqlError::StatementError, d->drv_d_func()));
return false;
}
@@ -1176,10 +1145,7 @@ bool QMimerSQLResult::exec()
d->statementhandle, i + 1,
val.toDateTime().toString(dateTimeFormatString).toUtf8().constData());
if (!MIMER_SUCCEEDED(err)) {
- setLastError(qMakeError(
- QCoreApplication::translate("QMimerSQLResult",
- "Could not set datetime, parameter %1")
- .arg(i),
+ setLastError(qMakeError(msgCouldNotSet("datetime", i),
err, QSqlError::StatementError, d->drv_d_func()));
return false;
}
@@ -1206,10 +1172,7 @@ bool QMimerSQLResult::exec()
}
if (!MIMER_SUCCEEDED(err)) {
setLastError(
- qMakeError(QCoreApplication::translate(
- "QMimerSQLResult",
- "Could not set BLOB byte array, parameter %1")
- .arg(i),
+ qMakeError(msgCouldNotSet("BLOB byte array", i),
err, QSqlError::StatementError, d->drv_d_func()));
return false;
}
@@ -1218,10 +1181,7 @@ bool QMimerSQLResult::exec()
}
}
if (!MIMER_SUCCEEDED(err)) {
- setLastError(qMakeError(
- QCoreApplication::translate("QMimerSQLResult",
- "Could not set BLOB byte array, parameter %1")
- .arg(i),
+ setLastError(qMakeError(msgCouldNotSet("BLOB byte array", i),
err, QSqlError::StatementError, d->drv_d_func()));
return false;
}
@@ -1258,10 +1218,7 @@ bool QMimerSQLResult::exec()
pos += maxSize - step_back;
}
if (!MIMER_SUCCEEDED(err)) {
- setLastError(qMakeError(
- QCoreApplication::translate("QMimerSQLResult",
- "Could not set CLOB, parameter %1")
- .arg(i),
+ setLastError(qMakeError(msgCouldNotSet("CLOB", i),
err, QSqlError::StatementError, d->drv_d_func()));
return false;
}
@@ -1272,9 +1229,7 @@ bool QMimerSQLResult::exec()
}
if (!MIMER_SUCCEEDED(err)) {
setLastError(
- qMakeError(QCoreApplication::translate("QMimerSQLResult",
- "Could not set CLOB, parameter %1")
- .arg(i),
+ qMakeError(msgCouldNotSet("CLOB", i),
err, QSqlError::StatementError, d->drv_d_func()));
return false;
}
@@ -1335,7 +1290,7 @@ bool QMimerSQLResult::execBatch(bool arrayBind)
if (bindValueType(i) == QSql::Out || bindValueType(i) == QSql::InOut) {
setLastError(qMakeError(QCoreApplication::translate(
"QMimerSQLResult",
- "Only input parameter can be used in batch operations"),
+ "Only input parameters can be used in batch operations"),
genericError, QSqlError::StatementError, nullptr));
d->execBatch = false;
return false;
@@ -1349,6 +1304,7 @@ bool QMimerSQLResult::execBatch(bool arrayBind)
err = MimerAddBatch(d->statementhandle);
if (!MIMER_SUCCEEDED(err)) {
setLastError(qMakeError(
+ //: %1 is the batch number
QCoreApplication::translate("QMimerSQLResult", "Could not add batch %1")
.arg(i),
err, QSqlError::StatementError, d->drv_d_func()));
@@ -1650,3 +1606,5 @@ void QMimerSQLDriverPrivate::splitTableQualifier(const QString &qualifiedName, Q
}
QT_END_NAMESPACE
+
+#include "moc_qsql_mimer.cpp"
diff --git a/src/plugins/sqldrivers/mysql/CMakeLists.txt b/src/plugins/sqldrivers/mysql/CMakeLists.txt
index fb28abd91a..2e3d028584 100644
--- a/src/plugins/sqldrivers/mysql/CMakeLists.txt
+++ b/src/plugins/sqldrivers/mysql/CMakeLists.txt
@@ -14,6 +14,7 @@ qt_internal_add_plugin(QMYSQLDriverPlugin
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
+ QT_NO_CONTEXTLESS_CONNECT
LIBRARIES
MySQL::MySQL
Qt::Core
diff --git a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp
index 1cf6798cd9..cfd4931b46 100644
--- a/src/plugins/sqldrivers/mysql/qsql_mysql.cpp
+++ b/src/plugins/sqldrivers/mysql/qsql_mysql.cpp
@@ -10,12 +10,14 @@
#include <qdebug.h>
#include <qfile.h>
#include <qlist.h>
+#include <qloggingcategory.h>
#include <qsqlerror.h>
#include <qsqlfield.h>
#include <qsqlindex.h>
#include <qsqlquery.h>
#include <qsqlrecord.h>
#include <qstringlist.h>
+#include <qtimezone.h>
#include <QtSql/private/qsqldriver_p.h>
#include <QtSql/private/qsqlresult_p.h>
@@ -51,6 +53,8 @@ struct QT_MYSQL_TIME
QT_BEGIN_NAMESPACE
+static Q_LOGGING_CATEGORY(lcMysql, "qt.sql.mysql")
+
using namespace Qt::StringLiterals;
class QMYSQLDriverPrivate : public QSqlDriverPrivate
@@ -97,9 +101,15 @@ static inline QVariant qDateTimeFromString(QString &val)
#else
if (val.isEmpty())
return QVariant(QDateTime());
+
+ // TIMESTAMPS have either the format "yyyyMMddhhmmss" or "yyyy-MM-dd
+ // hh:mm:ss". QDateTime::fromString() can convert the latter, but not the
+ // former, so adapt it if necessary.
if (val.size() == 14)
- // TIMESTAMPS have the format yyyyMMddhhmmss
val.insert(4, u'-').insert(7, u'-').insert(10, u'T').insert(13, u':').insert(16, u':');
+
+ if (!val.endsWith(u'Z'))
+ val.append(u'Z'); // make UTC
return QVariant(QDateTime::fromString(val, Qt::ISODate));
#endif
}
@@ -118,6 +128,18 @@ static inline bool checkPreparedQueries(MYSQL *mysql)
return mysql_stmt_param_count(stmt.get()) == 2;
}
+// used with prepared queries and bound arguments
+static inline void setUtcTimeZone(MYSQL *mysql)
+{
+ std::unique_ptr<MYSQL_STMT, decltype(&mysql_stmt_close)> stmt(mysql_stmt_init(mysql), &mysql_stmt_close);
+ if (!stmt)
+ return;
+
+ static const char query[] = "SET time_zone = '+00:00'";
+ if (mysql_stmt_prepare(stmt.get(), query, sizeof(query) - 1))
+ mysql_stmt_execute(stmt.get());
+}
+
class QMYSQLResultPrivate;
class QMYSQLResult : public QSqlResult
@@ -266,7 +288,6 @@ static QSqlField qToField(MYSQL_FIELD *field)
f.setRequired(IS_NOT_NULL(field->flags));
f.setLength(field->length);
f.setPrecision(field->decimals);
- f.setSqlType(field->type);
f.setAutoValue(field->flags & AUTO_INCREMENT_FLAG);
return f;
}
@@ -407,7 +428,7 @@ void QMYSQLResult::cleanup()
if (d->stmt) {
if (mysql_stmt_close(d->stmt))
- qWarning("QMYSQLResult::cleanup: unable to free statement handle");
+ qCWarning(lcMysql, "QMYSQLResult::cleanup: unable to free statement handle");
d->stmt = 0;
}
@@ -543,7 +564,7 @@ QVariant QMYSQLResult::data(int field)
{
Q_D(QMYSQLResult);
if (!isSelect() || field >= d->fields.size()) {
- qWarning("QMYSQLResult::data: column %d out of range", field);
+ qCWarning(lcMysql, "QMYSQLResult::data: column %d out of range", field);
return QVariant();
}
@@ -575,7 +596,7 @@ QVariant QMYSQLResult::data(int field)
if (f.type.id() != QMetaType::QDate)
time = QTime(t->hour, t->minute, t->second, t->second_part / 1000);
if (f.type.id() == QMetaType::QDateTime)
- return QDateTime(date, time);
+ return QDateTime(date, time, QTimeZone::UTC);
else if (f.type.id() == QMetaType::QDate)
return date;
else
@@ -832,28 +853,6 @@ void QMYSQLResult::virtual_hook(int id, void *data)
QSqlResult::virtual_hook(id, data);
}
-static QT_MYSQL_TIME *toMySqlDate(QDate date, QTime time, int type)
-{
- Q_ASSERT(type == QMetaType::QTime || type == QMetaType::QDate
- || type == QMetaType::QDateTime);
-
- auto myTime = new QT_MYSQL_TIME{};
-
- if (type == QMetaType::QTime || type == QMetaType::QDateTime) {
- myTime->hour = time.hour();
- myTime->minute = time.minute();
- myTime->second = time.second();
- myTime->second_part = time.msec() * 1000;
- }
- if (type == QMetaType::QDate || type == QMetaType::QDateTime) {
- myTime->year = date.year();
- myTime->month = date.month();
- myTime->day = date.day();
- }
-
- return myTime;
-}
-
bool QMYSQLResult::prepare(const QString& query)
{
Q_D(QMYSQLResult);
@@ -886,9 +885,9 @@ bool QMYSQLResult::prepare(const QString& query)
return false;
}
- if (mysql_stmt_param_count(d->stmt) > 0) {// allocate memory for outvalues
- d->outBinds = new MYSQL_BIND[mysql_stmt_param_count(d->stmt)];
- }
+ const auto paramCount = mysql_stmt_param_count(d->stmt);
+ if (paramCount > 0) // allocate memory for outvalues
+ d->outBinds = new MYSQL_BIND[paramCount]();
setSelect(d->bindInValues());
d->preparedQuery = true;
@@ -919,9 +918,8 @@ bool QMYSQLResult::exec()
return false;
}
- if (mysql_stmt_param_count(d->stmt) > 0 &&
- mysql_stmt_param_count(d->stmt) == (uint)values.size()) {
-
+ const unsigned long paramCount = mysql_stmt_param_count(d->stmt);
+ if (paramCount > 0 && paramCount == static_cast<size_t>(values.size())) {
nullVector.resize(values.size());
for (qsizetype i = 0; i < values.size(); ++i) {
const QVariant &val = boundValues().at(i);
@@ -944,25 +942,39 @@ bool QMYSQLResult::exec()
case QMetaType::QTime:
case QMetaType::QDate:
case QMetaType::QDateTime: {
- QT_MYSQL_TIME *myTime = toMySqlDate(val.toDate(), val.toTime(), val.userType());
+ auto myTime = new QT_MYSQL_TIME{};
timeVector.append(myTime);
-
currBind->buffer = myTime;
- switch (val.userType()) {
- case QMetaType::QTime:
+
+ QDate date;
+ QTime time;
+ int type = val.userType();
+ if (type == QMetaType::QTime) {
+ time = val.toTime();
currBind->buffer_type = MYSQL_TYPE_TIME;
myTime->time_type = MYSQL_TIMESTAMP_TIME;
- break;
- case QMetaType::QDate:
+ } else if (type == QMetaType::QDate) {
+ date = val.toDate();
currBind->buffer_type = MYSQL_TYPE_DATE;
myTime->time_type = MYSQL_TIMESTAMP_DATE;
- break;
- case QMetaType::QDateTime:
+ } else {
+ QDateTime dt = val.toDateTime().toUTC();
+ date = dt.date();
+ time = dt.time();
currBind->buffer_type = MYSQL_TYPE_DATETIME;
myTime->time_type = MYSQL_TIMESTAMP_DATETIME;
- break;
- default:
- break;
+ }
+
+ if (type == QMetaType::QTime || type == QMetaType::QDateTime) {
+ myTime->hour = time.hour();
+ myTime->minute = time.minute();
+ myTime->second = time.second();
+ myTime->second_part = time.msec() * 1000;
+ }
+ if (type == QMetaType::QDate || type == QMetaType::QDateTime) {
+ myTime->year = date.year();
+ myTime->month = date.month();
+ myTime->day = date.day();
}
currBind->buffer_length = sizeof(QT_MYSQL_TIME);
currBind->length = 0;
@@ -1003,7 +1015,11 @@ bool QMYSQLResult::exec()
}
}
+#if defined(MARIADB_VERSION_ID) || MYSQL_VERSION_ID < 80300
r = mysql_stmt_bind_param(d->stmt, d->outBinds);
+#else
+ r = mysql_stmt_bind_named_param(d->stmt, d->outBinds, paramCount, nullptr);
+#endif
if (r != 0) {
setLastError(qMakeStmtError(QCoreApplication::translate("QMYSQLResult",
"Unable to bind value"), QSqlError::StatementError, d->stmt));
@@ -1074,7 +1090,7 @@ static void qLibraryInit()
return;
if (mysql_library_init(0, 0, 0)) {
- qWarning("QMYSQLDriver::qServerInit: unable to start server.");
+ qCWarning(lcMysql, "QMYSQLDriver::qServerInit: unable to start server.");
}
#endif // Q_NO_MYSQL_EMBEDDED
@@ -1181,9 +1197,11 @@ static void setOptionFlag(uint &optionFlags, QStringView opt)
else if (opt == "CLIENT_ODBC"_L1)
optionFlags |= CLIENT_ODBC;
else if (opt == "CLIENT_SSL"_L1)
- qWarning("QMYSQLDriver: MYSQL_OPT_SSL_KEY, MYSQL_OPT_SSL_CERT and MYSQL_OPT_SSL_CA should be used instead of CLIENT_SSL.");
+ qCWarning(lcMysql, "QMYSQLDriver: MYSQL_OPT_SSL_KEY, MYSQL_OPT_SSL_CERT "
+ "and MYSQL_OPT_SSL_CA should be used instead of CLIENT_SSL.");
else
- qWarning("QMYSQLDriver::open: Unknown connect option '%s'", opt.toLocal8Bit().constData());
+ qCWarning(lcMysql, "QMYSQLDriver::open: Unknown connect option '%ls'",
+ qUtf16Printable(QString(opt)));
}
static bool setOptionString(MYSQL *mysql, mysql_option option, QStringView v)
@@ -1204,6 +1222,28 @@ static bool setOptionBool(MYSQL *mysql, mysql_option option, QStringView v)
return mysql_options(mysql, option, &val) == 0;
}
+// MYSQL_OPT_SSL_MODE was introduced with MySQL 5.7.11
+#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 50711 && !defined(MARIADB_VERSION_ID)
+static bool setOptionSslMode(MYSQL *mysql, mysql_option option, QStringView v)
+{
+ mysql_ssl_mode sslMode = SSL_MODE_DISABLED;
+ if (v == "DISABLED"_L1 || v == "SSL_MODE_DISABLED"_L1)
+ sslMode = SSL_MODE_DISABLED;
+ else if (v == "PREFERRED"_L1 || v == "SSL_MODE_PREFERRED"_L1)
+ sslMode = SSL_MODE_PREFERRED;
+ else if (v == "REQUIRED"_L1 || v == "SSL_MODE_REQUIRED"_L1)
+ sslMode = SSL_MODE_REQUIRED;
+ else if (v == "VERIFY_CA"_L1 || v == "SSL_MODE_VERIFY_CA"_L1)
+ sslMode = SSL_MODE_VERIFY_CA;
+ else if (v == "VERIFY_IDENTITY"_L1 || v == "SSL_MODE_VERIFY_IDENTITY"_L1)
+ sslMode = SSL_MODE_VERIFY_IDENTITY;
+ else
+ qCWarning(lcMysql, "Unknown ssl mode '%ls' - using SSL_MODE_DISABLED",
+ qUtf16Printable(QString(v)));
+ return mysql_options(mysql, option, &sslMode) == 0;
+}
+#endif
+
static bool setOptionProtocol(MYSQL *mysql, mysql_option option, QStringView v)
{
mysql_protocol_type proto = MYSQL_PROTOCOL_DEFAULT;
@@ -1218,7 +1258,8 @@ static bool setOptionProtocol(MYSQL *mysql, mysql_option option, QStringView v)
else if (v == "DEFAULT"_L1 || v == "MYSQL_PROTOCOL_DEFAULT"_L1)
proto = MYSQL_PROTOCOL_DEFAULT;
else
- qWarning() << "Unknown protocol '" << v << "' - using MYSQL_PROTOCOL_DEFAULT";
+ qCWarning(lcMysql, "Unknown protocol '%ls' - using MYSQL_PROTOCOL_DEFAULT",
+ qUtf16Printable(QString(v)));
return mysql_options(mysql, option, &proto) == 0;
}
@@ -1259,6 +1300,12 @@ bool QMYSQLDriver::open(const QString &db,
{"MYSQL_OPT_SSL_CIPHER"_L1, MYSQL_OPT_SSL_CIPHER, setOptionString},
{"MYSQL_OPT_SSL_CRL"_L1, MYSQL_OPT_SSL_CRL, setOptionString},
{"MYSQL_OPT_SSL_CRLPATH"_L1, MYSQL_OPT_SSL_CRLPATH, setOptionString},
+#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 50710
+ {"MYSQL_OPT_TLS_VERSION"_L1, MYSQL_OPT_TLS_VERSION, setOptionString},
+#endif
+#if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 50711 && !defined(MARIADB_VERSION_ID)
+ {"MYSQL_OPT_SSL_MODE"_L1, MYSQL_OPT_SSL_MODE, setOptionSslMode},
+#endif
{"MYSQL_OPT_CONNECT_TIMEOUT"_L1, MYSQL_OPT_CONNECT_TIMEOUT, setOptionInt},
{"MYSQL_OPT_READ_TIMEOUT"_L1, MYSQL_OPT_READ_TIMEOUT, setOptionInt},
{"MYSQL_OPT_WRITE_TIMEOUT"_L1, MYSQL_OPT_WRITE_TIMEOUT, setOptionInt},
@@ -1271,8 +1318,9 @@ bool QMYSQLDriver::open(const QString &db,
for (const mysqloptions &opt : options) {
if (key == opt.key) {
if (!opt.func(d->mysql, opt.option, value)) {
- qWarning("QMYSQLDriver::open: Could not set connect option value '%s' to '%s'",
- key.toLocal8Bit().constData(), value.toLocal8Bit().constData());
+ qCWarning(lcMysql, "QMYSQLDriver::open: Could not set connect option value "
+ "'%ls' to '%ls'",
+ qUtf16Printable(QString(key)), qUtf16Printable(QString(value)));
}
return true;
}
@@ -1303,8 +1351,8 @@ bool QMYSQLDriver::open(const QString &db,
else if (val == "TRUE"_L1 || val == "1"_L1)
setOptionFlag(optionFlags, key);
else
- qWarning("QMYSQLDriver::open: Illegal connect option value '%s'",
- sv.toLocal8Bit().constData());
+ qCWarning(lcMysql, "QMYSQLDriver::open: Illegal connect option value '%ls'",
+ qUtf16Printable(QString(sv)));
} else {
setOptionFlag(optionFlags, sv);
}
@@ -1356,9 +1404,10 @@ bool QMYSQLDriver::open(const QString &db,
}
}
if (!ok)
- qWarning("MySQL: Unable to set the client character set to utf8 (\"%s\"). Using '%s' instead.",
- mysql_error(d->mysql),
- mysql_character_set_name(d->mysql));
+ qCWarning(lcMysql, "MySQL: Unable to set the client character set to utf8 (\"%s\"). "
+ "Using '%s' instead.",
+ mysql_error(d->mysql),
+ mysql_character_set_name(d->mysql));
}
if (!db.isEmpty() && mysql_select_db(d->mysql, db.toUtf8().constData())) {
@@ -1371,6 +1420,9 @@ bool QMYSQLDriver::open(const QString &db,
d->preparedQuerysEnabled = checkPreparedQueries(d->mysql);
d->dbName = db;
+ if (d->preparedQuerysEnabled)
+ setUtcTimeZone(d->mysql);
+
#if QT_CONFIG(thread)
mysql_thread_init();
#endif
@@ -1446,20 +1498,38 @@ QSqlIndex QMYSQLDriver::primaryIndex(const QString &tablename) const
QSqlRecord QMYSQLDriver::record(const QString &tablename) const
{
Q_D(const QMYSQLDriver);
- const QString table = stripDelimiters(tablename, QSqlDriver::TableName);
-
- QSqlRecord info;
if (!isOpen())
- return info;
- MYSQL_RES *r = mysql_list_fields(d->mysql, table.toUtf8().constData(), nullptr);
- if (!r)
- return info;
-
- MYSQL_FIELD *field;
- while ((field = mysql_fetch_field(r)))
- info.append(qToField(field));
- mysql_free_result(r);
- return info;
+ return {};
+ QSqlQuery i(createResult());
+ QString stmt("SELECT * FROM %1 LIMIT 0"_L1);
+ i.exec(stmt.arg(escapeIdentifier(tablename, QSqlDriver::TableName)));
+ auto r = i.record();
+ if (r.isEmpty())
+ return r;
+ // no binding of WHERE possible with MySQL
+ // escaping on WHERE clause does not work, so use mysql_real_escape_string()
+ stmt = "SELECT column_name, column_default FROM information_schema.columns WHERE table_name = '%1'"_L1;
+ const auto baTableName = tablename.toUtf8();
+ QVarLengthArray<char> tableNameQuoted(baTableName.size() * 2 + 1);
+#if defined(MARIADB_VERSION_ID)
+ const auto len = mysql_real_escape_string(d->mysql, tableNameQuoted.data(),
+ baTableName.data(), baTableName.size());
+#else
+ const auto len = mysql_real_escape_string_quote(d->mysql, tableNameQuoted.data(),
+ baTableName.data(), baTableName.size(), '\'');
+#endif
+ if (i.exec(stmt.arg(QString::fromUtf8(tableNameQuoted.data(), len)))) {
+ while (i.next()) {
+ const auto colName = i.value(0).toString();
+ const auto recordIdx = r.indexOf(colName);
+ if (recordIdx >= 0) {
+ auto field = r.field(recordIdx);
+ field.setDefaultValue(i.value(1));
+ r.replace(recordIdx, field);
+ }
+ }
+ }
+ return r;
}
QVariant QMYSQLDriver::handle() const
@@ -1472,7 +1542,7 @@ bool QMYSQLDriver::beginTransaction()
{
Q_D(QMYSQLDriver);
if (!isOpen()) {
- qWarning("QMYSQLDriver::beginTransaction: Database not open");
+ qCWarning(lcMysql, "QMYSQLDriver::beginTransaction: Database not open");
return false;
}
if (mysql_query(d->mysql, "BEGIN WORK")) {
@@ -1487,7 +1557,7 @@ bool QMYSQLDriver::commitTransaction()
{
Q_D(QMYSQLDriver);
if (!isOpen()) {
- qWarning("QMYSQLDriver::commitTransaction: Database not open");
+ qCWarning(lcMysql, "QMYSQLDriver::commitTransaction: Database not open");
return false;
}
if (mysql_query(d->mysql, "COMMIT")) {
@@ -1502,7 +1572,7 @@ bool QMYSQLDriver::rollbackTransaction()
{
Q_D(QMYSQLDriver);
if (!isOpen()) {
- qWarning("QMYSQLDriver::rollbackTransaction: Database not open");
+ qCWarning(lcMysql, "QMYSQLDriver::rollbackTransaction: Database not open");
return false;
}
if (mysql_query(d->mysql, "ROLLBACK")) {
@@ -1539,7 +1609,7 @@ QString QMYSQLDriver::formatValue(const QSqlField &field, bool trimStrings) cons
r = u'\'' + QString::fromUtf8(buffer.data(), escapedSize) + u'\'';
break;
} else {
- qWarning("QMYSQLDriver::formatValue: Database not open");
+ qCWarning(lcMysql, "QMYSQLDriver::formatValue: Database not open");
}
Q_FALLTHROUGH();
case QMetaType::QDateTime:
@@ -1548,7 +1618,6 @@ QString QMYSQLDriver::formatValue(const QSqlField &field, bool trimStrings) cons
// "+00:00" starting in version 8.0.19. However, if we got here,
// it's because the MySQL server is too old for prepared queries
// in the first place, so it won't understand timezones either.
- // Besides, MYSQL_TIME does not support timezones, so match it.
r = u'\'' +
dt.date().toString(Qt::ISODate) +
u'T' +
diff --git a/src/plugins/sqldrivers/oci/qsql_oci.cpp b/src/plugins/sqldrivers/oci/qsql_oci.cpp
index b670efc15b..68e303490d 100644
--- a/src/plugins/sqldrivers/oci/qsql_oci.cpp
+++ b/src/plugins/sqldrivers/oci/qsql_oci.cpp
@@ -7,6 +7,7 @@
#include <qdatetime.h>
#include <qdebug.h>
#include <qlist.h>
+#include <qloggingcategory.h>
#include <qmetatype.h>
#if QT_CONFIG(regularexpression)
#include <qregularexpression.h>
@@ -30,14 +31,7 @@
#define _int64 __int64
#endif
-
#include <oci.h>
-#ifdef max
-#undef max
-#endif
-#ifdef min
-#undef min
-#endif
#include <stdlib.h>
@@ -58,6 +52,8 @@ Q_DECLARE_METATYPE(OCIStmt*)
QT_BEGIN_NAMESPACE
+static Q_LOGGING_CATEGORY(lcOci, "qt.sql.oci")
+
using namespace Qt::StringLiterals;
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
@@ -280,7 +276,7 @@ public:
0);
#ifdef QOCI_DEBUG
if (r != 0)
- qWarning("QOCIResultPrivate::setCharset: Couldn't set OCI_ATTR_CHARSET_FORM.");
+ qCWarning(lcOci, "QOCIResultPrivate::setCharset: Couldn't set OCI_ATTR_CHARSET_FORM.");
#endif
#endif
@@ -440,7 +436,7 @@ int QOCIResultPrivate::bindValue(OCIStmt *sql, OCIBind **hbnd, OCIError *err, in
-1,
SQLT_RDD, indPtr, 0, 0, 0, 0, OCI_DEFAULT);
} else {
- qWarning("Unknown bind variable");
+ qCWarning(lcOci, "Unknown bind variable");
r = OCI_ERROR;
}
} else {
@@ -556,7 +552,7 @@ void QOCIDriverPrivate::allocErrorHandle()
OCI_HTYPE_ERROR,
0, nullptr);
if (r != OCI_SUCCESS)
- qWarning("QOCIDriver: unable to allocate error handle");
+ qCWarning(lcOci, "QOCIDriver: unable to allocate error handle");
}
struct OraFieldInfo
@@ -592,12 +588,7 @@ QString qOraWarn(OCIError *err, int *errorCode)
void qOraWarning(const char* msg, OCIError *err)
{
-#ifdef QOCI_DEBUG
- qWarning("%s %s", msg, qPrintable(qOraWarn(err)));
-#else
- Q_UNUSED(msg);
- Q_UNUSED(err);
-#endif
+ qCWarning(lcOci, "%s %ls", msg, qUtf16Printable(qOraWarn(err)));
}
static int qOraErrorNumber(OCIError *err)
@@ -660,7 +651,7 @@ QMetaType qDecodeOCIType(const QString& ocitype, QSql::NumericalPrecisionPolicy
else if (ocitype == "UNDEFINED"_L1)
type = QMetaType::UnknownType;
if (type == QMetaType::UnknownType)
- qWarning("qDecodeOCIType: unknown type: %s", ocitype.toLocal8Bit().constData());
+ qCWarning(lcOci, "qDecodeOCIType: unknown type: %ls", qUtf16Printable(ocitype));
return QMetaType(type);
}
@@ -728,7 +719,7 @@ QMetaType qDecodeOCIType(int ocitype, QSql::NumericalPrecisionPolicy precisionPo
type = QMetaType::QDateTime;
break;
default:
- qWarning("qDecodeOCIType: unknown OCI datatype: %d", ocitype);
+ qCWarning(lcOci, "qDecodeOCIType: unknown OCI datatype: %d", ocitype);
break;
}
return QMetaType(type);
@@ -745,7 +736,6 @@ static QSqlField qFromOraInf(const OraFieldInfo &ofi)
f.setLength(ofi.oraPrecision == 0 ? 38 : int(ofi.oraPrecision));
f.setPrecision(ofi.oraScale);
- f.setSqlType(int(ofi.oraType));
return f;
}
@@ -844,7 +834,7 @@ QOCICols::OraFieldInf::~OraFieldInf()
if (lob) {
int r = OCIDescriptorFree(lob, OCI_DTYPE_LOB);
if (r != 0)
- qWarning("QOCICols: Cannot free LOB descriptor");
+ qCWarning(lcOci, "QOCICols: Cannot free LOB descriptor");
}
if (dataPtr) {
switch (typ.id()) {
@@ -853,7 +843,7 @@ QOCICols::OraFieldInf::~OraFieldInf()
case QMetaType::QDateTime: {
int r = OCIDescriptorFree(dataPtr, OCI_DTYPE_TIMESTAMP_TZ);
if (r != OCI_SUCCESS)
- qWarning("QOCICols: Cannot free OCIDateTime descriptor");
+ qCWarning(lcOci, "QOCICols: Cannot free OCIDateTime descriptor");
break;
}
default:
@@ -908,7 +898,7 @@ QOCICols::QOCICols(int size, QOCIResultPrivate* dp)
case QMetaType::QDateTime:
r = OCIDescriptorAlloc(d->env, (void **)&fieldInf[idx].dataPtr, OCI_DTYPE_TIMESTAMP_TZ, 0, 0);
if (r != OCI_SUCCESS) {
- qWarning("QOCICols: Unable to allocate the OCIDateTime descriptor");
+ qCWarning(lcOci, "QOCICols: Unable to allocate the OCIDateTime descriptor");
break;
}
r = OCIDefineByPos(d->sql,
@@ -1079,7 +1069,7 @@ OCILobLocator **QOCICols::createLobLocator(int position, OCIEnv* env)
0,
0);
if (r != 0) {
- qWarning("QOCICols: Cannot create LOB locator");
+ qCWarning(lcOci, "QOCICols: Cannot create LOB locator");
lob = 0;
}
return &lob;
@@ -1317,7 +1307,7 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVariantList &boundValues, bool a
return false;
#ifdef QOCI_DEBUG
- qDebug() << "columnCount:" << columnCount << boundValues;
+ qCDebug(lcOci) << "columnCount:" << columnCount << boundValues;
#endif
int i;
@@ -1436,7 +1426,7 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVariantList &boundValues, bool a
// we may now populate column with data
for (uint row = 0; row < col.recordCount; ++row) {
- const QVariant &val = boundValues.at(i).toList().at(row);
+ const QVariant val = boundValues.at(i).toList().at(row);
if (QSqlResultPrivate::isVariantNull(val) && !d->isOutValue(i)) {
columns[i].indicators[row] = -1;
@@ -1514,13 +1504,13 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVariantList &boundValues, bool a
QOCIBatchColumn &bindColumn = columns[i];
#ifdef QOCI_DEBUG
- qDebug("OCIBindByPos(%p, %p, %p, %d, %p, %d, %d, %p, %p, 0, %d, %p, OCI_DEFAULT)",
+ qCDebug(lcOci, "OCIBindByPos(%p, %p, %p, %d, %p, %d, %d, %p, %p, 0, %d, %p, OCI_DEFAULT)",
d->sql, &bindColumn.bindh, d->err, i + 1, bindColumn.data,
bindColumn.maxLen, bindColumn.bindAs, bindColumn.indicators, bindColumn.lengths,
arrayBind ? bindColumn.maxarr_len : 0, arrayBind ? &bindColumn.curelep : 0);
for (int ii = 0; ii < (int)bindColumn.recordCount; ++ii) {
- qDebug(" record %d: indicator %d, length %d", ii, bindColumn.indicators[ii],
+ qCDebug(lcOci, " record %d: indicator %d, length %d", ii, bindColumn.indicators[ii],
bindColumn.lengths[ii]);
}
#endif
@@ -1540,7 +1530,7 @@ bool QOCICols::execBatch(QOCIResultPrivate *d, QVariantList &boundValues, bool a
OCI_DEFAULT);
#ifdef QOCI_DEBUG
- qDebug("After OCIBindByPos: r = %d, bindh = %p", r, bindColumn.bindh);
+ qCDebug(lcOci, "After OCIBindByPos: r = %d, bindh = %p", r, bindColumn.bindh);
#endif
if (r != OCI_SUCCESS && r != OCI_SUCCESS_WITH_INFO) {
@@ -1800,7 +1790,7 @@ void QOCICols::getValues(QVariantList &v, int index)
v[index + i] = QVariant(QMetaType(QMetaType::QByteArray));
break;
default:
- qWarning("QOCICols::value: unknown data type");
+ qCWarning(lcOci, "QOCICols::value: unknown data type");
break;
}
}
@@ -1821,7 +1811,7 @@ QOCIResultPrivate::QOCIResultPrivate(QOCIResult *q, const QOCIDriver *drv)
OCI_HTYPE_ERROR,
0, nullptr);
if (r != OCI_SUCCESS)
- qWarning("QOCIResult: unable to alloc error handle");
+ qCWarning(lcOci, "QOCIResult: unable to alloc error handle");
}
QOCIResultPrivate::~QOCIResultPrivate()
@@ -1829,10 +1819,10 @@ QOCIResultPrivate::~QOCIResultPrivate()
delete cols;
if (sql && OCIHandleFree(sql, OCI_HTYPE_STMT) != OCI_SUCCESS)
- qWarning("~QOCIResult: unable to free statement handle");
+ qCWarning(lcOci, "~QOCIResult: unable to free statement handle");
if (OCIHandleFree(err, OCI_HTYPE_ERROR) != OCI_SUCCESS)
- qWarning("~QOCIResult: unable to free error report handle");
+ qCWarning(lcOci, "~QOCIResult: unable to free error report handle");
}
@@ -1889,7 +1879,7 @@ bool QOCIResult::gotoNext(QSqlCachedResult::ValueCache &values, int index)
break;
case OCI_ERROR:
if (qOraErrorNumber(d->err) == 1406) {
- qWarning("QOCI Warning: data truncated for %s", lastQuery().toLocal8Bit().constData());
+ qCWarning(lcOci, "QOCI Warning: data truncated for %ls", qUtf16Printable(lastQuery()));
r = OCI_SUCCESS; /* ignore it */
break;
}
@@ -2003,7 +1993,7 @@ bool QOCIResult::exec()
setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
"Unable to get statement type"), QSqlError::StatementError, d->err));
#ifdef QOCI_DEBUG
- qDebug() << "lastQuery()" << lastQuery();
+ qCDebug(lcOci) << "lastQuery()" << lastQuery();
#endif
return false;
}
@@ -2018,7 +2008,7 @@ bool QOCIResult::exec()
setLastError(qMakeError(QCoreApplication::translate("QOCIResult", "Unable to bind value"),
QSqlError::StatementError, d->err));
#ifdef QOCI_DEBUG
- qDebug() << "lastQuery()" << lastQuery();
+ qCDebug(lcOci) << "lastQuery()" << lastQuery();
#endif
return false;
}
@@ -2037,7 +2027,7 @@ bool QOCIResult::exec()
setLastError(qMakeError(QCoreApplication::translate("QOCIResult",
"Unable to execute statement"), QSqlError::StatementError, d->err));
#ifdef QOCI_DEBUG
- qDebug() << "lastQuery()" << lastQuery();
+ qCDebug(lcOci) << "lastQuery()" << lastQuery();
#endif
return false;
}
@@ -2129,7 +2119,7 @@ QOCIDriver::QOCIDriver(QObject* parent)
0,
NULL);
if (r != 0) {
- qWarning("QOCIDriver: unable to create environment");
+ qCWarning(lcOci, "QOCIDriver: unable to create environment");
setLastError(qMakeError(tr("Unable to initialize", "QOCIDriver"),
QSqlError::ConnectionError, d->err));
return;
@@ -2160,10 +2150,10 @@ QOCIDriver::~QOCIDriver()
close();
int r = OCIHandleFree(d->err, OCI_HTYPE_ERROR);
if (r != OCI_SUCCESS)
- qWarning("Unable to free Error handle: %d", r);
+ qCWarning(lcOci, "Unable to free Error handle: %d", r);
r = OCIHandleFree(d->env, OCI_HTYPE_ENV);
if (r != OCI_SUCCESS)
- qWarning("Unable to free Environment handle: %d", r);
+ qCWarning(lcOci, "Unable to free Environment handle: %d", r);
}
bool QOCIDriver::hasFeature(DriverFeature f) const
@@ -2198,8 +2188,8 @@ static void qParseOpts(const QString &options, QOCIDriverPrivate *d)
for (const auto tmp : opts) {
qsizetype idx;
if ((idx = tmp.indexOf(u'=')) == -1) {
- qWarning("QOCIDriver::parseArgs: Invalid parameter: '%s'",
- tmp.toLocal8Bit().constData());
+ qCWarning(lcOci, "QOCIDriver::parseArgs: Invalid parameter: '%ls'",
+ qUtf16Printable(tmp.toString()));
continue;
}
const QStringView opt = tmp.left(idx);
@@ -2219,12 +2209,12 @@ static void qParseOpts(const QString &options, QOCIDriverPrivate *d)
} else if (val == "OCI_SYSOPER"_L1) {
d->authMode = OCI_SYSOPER;
} else if (val != "OCI_DEFAULT"_L1) {
- qWarning("QOCIDriver::parseArgs: Unsupported value for OCI_AUTH_MODE: '%s'",
- val.toLocal8Bit().constData());
+ qCWarning(lcOci, "QOCIDriver::parseArgs: Unsupported value for OCI_AUTH_MODE: '%ls'",
+ qUtf16Printable(val.toString()));
}
} else {
- qWarning("QOCIDriver::parseArgs: Invalid parameter: '%s'",
- opt.toLocal8Bit().constData());
+ qCWarning(lcOci, "QOCIDriver::parseArgs: Invalid parameter: '%ls'",
+ qUtf16Printable(opt.toString()));
}
}
}
@@ -2321,7 +2311,7 @@ bool QOCIDriver::open(const QString & db,
sizeof(vertxt),
OCI_HTYPE_SVCCTX);
if (r != 0) {
- qWarning("QOCIDriver::open: could not get Oracle server version.");
+ qCWarning(lcOci, "QOCIDriver::open: could not get Oracle server version.");
} else {
QString versionStr;
versionStr = QString(reinterpret_cast<const QChar *>(vertxt));
@@ -2370,7 +2360,7 @@ bool QOCIDriver::beginTransaction()
{
Q_D(QOCIDriver);
if (!isOpen()) {
- qWarning("QOCIDriver::beginTransaction: Database not open");
+ qCWarning(lcOci, "QOCIDriver::beginTransaction: Database not open");
return false;
}
int r = OCITransStart(d->svc,
@@ -2391,7 +2381,7 @@ bool QOCIDriver::commitTransaction()
{
Q_D(QOCIDriver);
if (!isOpen()) {
- qWarning("QOCIDriver::commitTransaction: Database not open");
+ qCWarning(lcOci, "QOCIDriver::commitTransaction: Database not open");
return false;
}
int r = OCITransCommit(d->svc,
@@ -2411,7 +2401,7 @@ bool QOCIDriver::rollbackTransaction()
{
Q_D(QOCIDriver);
if (!isOpen()) {
- qWarning("QOCIDriver::rollbackTransaction: Database not open");
+ qCWarning(lcOci, "QOCIDriver::rollbackTransaction: Database not open");
return false;
}
int r = OCITransRollback(d->svc,
@@ -2691,7 +2681,7 @@ QSqlIndex QOCIDriver::primaryIndex(const QString& tablename) const
QString QOCIDriver::formatValue(const QSqlField &field, bool trimStrings) const
{
- switch (field.typeID()) {
+ switch (field.metaType().id()) {
case QMetaType::QDateTime: {
QDateTime datetime = field.value().toDateTime();
QString datestring;
@@ -2767,3 +2757,5 @@ int QOCIDriver::maximumIdentifierLength(IdentifierType type) const
}
QT_END_NAMESPACE
+
+#include "moc_qsql_oci_p.cpp"
diff --git a/src/plugins/sqldrivers/odbc/CMakeLists.txt b/src/plugins/sqldrivers/odbc/CMakeLists.txt
index df091f9687..7812aced2c 100644
--- a/src/plugins/sqldrivers/odbc/CMakeLists.txt
+++ b/src/plugins/sqldrivers/odbc/CMakeLists.txt
@@ -16,6 +16,7 @@ qt_internal_add_plugin(QODBCDriverPlugin
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
+ QT_NO_CONTEXTLESS_CONNECT
LIBRARIES
ODBC::ODBC
Qt::Core
diff --git a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
index 1a57e8fcc6..976911d458 100644
--- a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
+++ b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
@@ -10,6 +10,7 @@
#include <qcoreapplication.h>
#include <qdatetime.h>
#include <qlist.h>
+#include <qloggingcategory.h>
#include <qmath.h>
#include <qsqlerror.h>
#include <qsqlfield.h>
@@ -26,6 +27,8 @@
QT_BEGIN_NAMESPACE
+static Q_LOGGING_CATEGORY(lcOdbc, "qt.sql.odbc")
+
using namespace Qt::StringLiterals;
// non-standard ODBC SQL data type from SQL Server sometimes used instead of SQL_TIME
@@ -41,6 +44,29 @@ static constexpr SQLSMALLINT TABLENAMESIZE = 128;
//Map Qt parameter types to ODBC types
static constexpr SQLSMALLINT qParamType[4] = { SQL_PARAM_INPUT, SQL_PARAM_INPUT, SQL_PARAM_OUTPUT, SQL_PARAM_INPUT_OUTPUT };
+class SqlStmtHandle
+{
+public:
+ SqlStmtHandle(SQLHANDLE hDbc)
+ {
+ SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &stmtHandle);
+ }
+ ~SqlStmtHandle()
+ {
+ if (stmtHandle != SQL_NULL_HSTMT)
+ SQLFreeHandle(SQL_HANDLE_STMT, stmtHandle);
+ }
+ SQLHANDLE handle() const
+ {
+ return stmtHandle;
+ }
+ bool isValid() const
+ {
+ return stmtHandle != SQL_NULL_HSTMT;
+ }
+ SQLHANDLE stmtHandle = SQL_NULL_HSTMT;
+};
+
template<typename C, int SIZE = sizeof(SQLTCHAR)>
inline static QString fromSQLTCHAR(const C &input, qsizetype size = -1)
{
@@ -73,7 +99,7 @@ QStringConverter::Encoding encodingForSqlTChar()
"Don't know how to handle sizeof(SQLTCHAR) != 1/2/4");
}
-inline static QVarLengthArray<SQLTCHAR> toSQLTCHAR(const QString &input)
+inline static QVarLengthArray<SQLTCHAR> toSQLTCHAR(QStringView input)
{
QVarLengthArray<SQLTCHAR> result;
QStringEncoder enc(encodingForSqlTChar());
@@ -88,7 +114,7 @@ class QODBCDriverPrivate : public QSqlDriverPrivate
Q_DECLARE_PUBLIC(QODBCDriver)
public:
- enum DefaultCase {Lower, Mixed, Upper, Sensitive};
+ enum class DefaultCase {Lower, Mixed, Upper, Sensitive};
using QSqlDriverPrivate::QSqlDriverPrivate;
SQLHANDLE hEnv = nullptr;
@@ -109,15 +135,18 @@ public:
void checkHasMultiResults();
void checkSchemaUsage();
void checkDateTimePrecision();
+ void checkDefaultCase();
bool setConnectionOptions(const QString& connOpts);
void splitTableQualifier(const QString &qualifier, QString &catalog,
QString &schema, QString &table) const;
- DefaultCase defaultCase() const;
QString adjustCase(const QString&) const;
QChar quoteChar();
+ SQLRETURN sqlFetchNext(const SqlStmtHandle &hStmt) const;
+ SQLRETURN sqlFetchNext(SQLHANDLE hStmt) const;
private:
bool isQuoteInitialized = false;
QChar quote = u'"';
+ DefaultCase m_defaultCase = DefaultCase::Mixed;
};
class QODBCResultPrivate;
@@ -228,7 +257,7 @@ static QList<DiagRecord> qWarnODBCHandle(int handleType, SQLHANDLE handle)
description.resize(msgLen + 1); // incl. \0 termination
continue;
}
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
+ if (SQL_SUCCEEDED(r)) {
result.push_back({fromSQLTCHAR(description, msgLen),
fromSQLTCHAR(state),
QString::number(nativeCode)});
@@ -268,6 +297,8 @@ static DiagRecord combineRecords(const QList<DiagRecord> &records)
a.sqlState + u';' + b.sqlState,
a.errorCode + u';' + b.errorCode};
};
+ if (records.isEmpty())
+ return {};
return std::accumulate(std::next(records.begin()), records.end(), records.front(), add);
}
@@ -291,7 +322,11 @@ static QString errorStringFromDiagRecords(const QList<DiagRecord>& records)
template<class T>
static void qSqlWarning(const QString &message, T &&val)
{
- qWarning() << message << "\tError:" << errorStringFromDiagRecords(qODBCWarn(val));
+ const auto addMsg = errorStringFromDiagRecords(qODBCWarn(val));
+ if (addMsg.isEmpty())
+ qCWarning(lcOdbc) << message;
+ else
+ qCWarning(lcOdbc) << message << "\tError:" << addMsg;
}
static QSqlError qMakeError(const QString &err,
@@ -385,7 +420,7 @@ static QVariant getStringDataImpl(SQLHANDLE hStmt, SQLUSMALLINT column, qsizetyp
targetType,
SQLPOINTER(buf.data()), SQLINTEGER(buf.size() * sizeof(CT)),
&lengthIndicator);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
+ if (SQL_SUCCEEDED(r)) {
if (lengthIndicator == SQL_NULL_DATA) {
return {};
}
@@ -415,7 +450,7 @@ static QVariant getStringDataImpl(SQLHANDLE hStmt, SQLUSMALLINT column, qsizetyp
} else if (r == SQL_NO_DATA) {
break;
} else {
- qSqlWarning("qGetStringData: Error while fetching data:"_L1, hStmt);
+ qSqlWarning("QODBC::getStringData: Error while fetching data"_L1, hStmt);
return {};
}
}
@@ -457,7 +492,8 @@ static QVariant qGetBinaryData(SQLHANDLE hStmt, int column)
&colScale,
&nullable);
if (r != SQL_SUCCESS)
- qWarning() << "qGetBinaryData: Unable to describe column" << column;
+ qSqlWarning(("QODBC::qGetBinaryData: Unable to describe column %1"_L1)
+ .arg(QString::number(column)), hStmt);
// SQLDescribeCol may return 0 if size cannot be determined
if (!colSize)
colSize = 255;
@@ -472,7 +508,7 @@ static QVariant qGetBinaryData(SQLHANDLE hStmt, int column)
const_cast<char *>(fieldVal.constData() + read),
colSize,
&lengthIndicator);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
+ if (!SQL_SUCCEEDED(r))
break;
if (lengthIndicator == SQL_NULL_DATA)
return QVariant(QMetaType(QMetaType::QByteArray));
@@ -501,7 +537,7 @@ static QVariant qGetIntData(SQLHANDLE hStmt, int column, bool isSigned = true)
(SQLPOINTER)&intbuf,
sizeof(intbuf),
&lengthIndicator);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
+ if (!SQL_SUCCEEDED(r))
return QVariant();
if (lengthIndicator == SQL_NULL_DATA)
return QVariant(QMetaType::fromType<int>());
@@ -521,7 +557,7 @@ static QVariant qGetDoubleData(SQLHANDLE hStmt, int column)
(SQLPOINTER) &dblbuf,
0,
&lengthIndicator);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ if (!SQL_SUCCEEDED(r)) {
return QVariant();
}
if (lengthIndicator == SQL_NULL_DATA)
@@ -541,7 +577,7 @@ static QVariant qGetBigIntData(SQLHANDLE hStmt, int column, bool isSigned = true
(SQLPOINTER) &lngbuf,
sizeof(lngbuf),
&lengthIndicator);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
+ if (!SQL_SUCCEEDED(r))
return QVariant();
if (lengthIndicator == SQL_NULL_DATA)
return QVariant(QMetaType::fromType<qlonglong>());
@@ -557,16 +593,14 @@ static bool isAutoValue(const SQLHANDLE hStmt, int column)
SQLLEN nNumericAttribute = 0; // Check for auto-increment
const SQLRETURN r = ::SQLColAttribute(hStmt, column + 1, SQL_DESC_AUTO_UNIQUE_VALUE,
0, 0, 0, &nNumericAttribute);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
- qSqlWarning(QStringLiteral("qMakeField: Unable to get autovalue attribute for column ")
- + QString::number(column), hStmt);
+ if (!SQL_SUCCEEDED(r)) {
+ qSqlWarning(("QODBC::isAutoValue: Unable to get autovalue attribute for column %1"_L1)
+ .arg(QString::number(column)), hStmt);
return false;
}
return nNumericAttribute != SQL_FALSE;
}
-static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, int i, QString *errorMessage);
-
// creates a QSqlField from a valid hStmt generated
// by SQLColumns. The hStmt has to point to a valid position.
static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, const QODBCDriverPrivate* p)
@@ -578,7 +612,6 @@ static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, const QODBCDriverPrivate*
f.setLength(var.isNull() ? -1 : var.toInt()); // column size
var = qGetIntData(hStmt, 8).toInt();
f.setPrecision(var.isNull() ? -1 : var.toInt()); // precision
- f.setSqlType(type);
int required = qGetIntData(hStmt, 10).toInt(); // nullable-flag
// required can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN
if (required == SQL_NO_NULLS)
@@ -589,16 +622,7 @@ static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, const QODBCDriverPrivate*
return f;
}
-static QSqlField qMakeFieldInfo(const QODBCResultPrivate* p, int i )
-{
- QString errorMessage;
- const QSqlField result = qMakeFieldInfo(p->hStmt, i, &errorMessage);
- if (!errorMessage.isEmpty())
- qSqlWarning(errorMessage, p);
- return result;
-}
-
-static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, int i, QString *errorMessage)
+static QSqlField qMakeFieldInfo(const QODBCResultPrivate *p, int i)
{
SQLSMALLINT colNameLen;
SQLSMALLINT colType;
@@ -607,8 +631,7 @@ static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, int i, QString *errorMess
SQLSMALLINT nullable;
SQLRETURN r = SQL_ERROR;
QVarLengthArray<SQLTCHAR, COLNAMESIZE> colName(COLNAMESIZE);
- errorMessage->clear();
- r = SQLDescribeCol(hStmt,
+ r = SQLDescribeCol(p->hStmt,
i+1,
colName.data(), SQLSMALLINT(colName.size()),
&colNameLen,
@@ -618,12 +641,13 @@ static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, int i, QString *errorMess
&nullable);
if (r != SQL_SUCCESS) {
- *errorMessage = QStringLiteral("qMakeField: Unable to describe column ") + QString::number(i);
+ qSqlWarning(("QODBC::qMakeFieldInfo: Unable to describe column %1"_L1)
+ .arg(QString::number(i)), p);
return QSqlField();
}
SQLLEN unsignedFlag = SQL_FALSE;
- r = SQLColAttribute (hStmt,
+ r = SQLColAttribute (p->hStmt,
i + 1,
SQL_DESC_UNSIGNED,
0,
@@ -631,15 +655,14 @@ static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, int i, QString *errorMess
0,
&unsignedFlag);
if (r != SQL_SUCCESS) {
- qSqlWarning(QStringLiteral("qMakeField: Unable to get column attributes for column ")
- + QString::number(i), hStmt);
+ qSqlWarning(("QODBC::qMakeFieldInfo: Unable to get column attributes for column %1"_L1)
+ .arg(QString::number(i)), p);
}
const QString qColName(fromSQLTCHAR(colName, colNameLen));
// nullable can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN
QMetaType type = qDecodeODBCType(colType, unsignedFlag == SQL_FALSE);
QSqlField f(qColName, type);
- f.setSqlType(colType);
f.setLength(colSize == 0 ? -1 : int(colSize));
f.setPrecision(colScale == 0 ? -1 : int(colScale));
if (nullable == SQL_NO_NULLS)
@@ -647,10 +670,10 @@ static QSqlField qMakeFieldInfo(const SQLHANDLE hStmt, int i, QString *errorMess
else if (nullable == SQL_NULLABLE)
f.setRequired(false);
// else we don't know
- f.setAutoValue(isAutoValue(hStmt, i));
+ f.setAutoValue(isAutoValue(p->hStmt, i));
QVarLengthArray<SQLTCHAR, TABLENAMESIZE> tableName(TABLENAMESIZE);
SQLSMALLINT tableNameLen;
- r = SQLColAttribute(hStmt,
+ r = SQLColAttribute(p->hStmt,
i + 1,
SQL_DESC_BASE_TABLE_NAME,
tableName.data(),
@@ -679,7 +702,7 @@ QChar QODBCDriverPrivate::quoteChar()
&driverResponse,
sizeof(driverResponse),
&length);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
+ if (SQL_SUCCEEDED(r))
quote = QChar(driverResponse[0]);
else
quote = u'"';
@@ -688,7 +711,19 @@ QChar QODBCDriverPrivate::quoteChar()
return quote;
}
-static SQLRETURN qt_string_SQLSetConnectAttr(SQLHDBC handle, SQLINTEGER attr, const QString &val)
+SQLRETURN QODBCDriverPrivate::sqlFetchNext(const SqlStmtHandle &hStmt) const
+{
+ return sqlFetchNext(hStmt.handle());
+}
+
+SQLRETURN QODBCDriverPrivate::sqlFetchNext(SQLHANDLE hStmt) const
+{
+ if (hasSQLFetchScroll)
+ return SQLFetchScroll(hStmt, SQL_FETCH_NEXT, 0);
+ return SQLFetch(hStmt);
+}
+
+static SQLRETURN qt_string_SQLSetConnectAttr(SQLHDBC handle, SQLINTEGER attr, QStringView val)
{
auto encoded = toSQLTCHAR(val);
return SQLSetConnectAttr(handle, attr,
@@ -697,101 +732,106 @@ static SQLRETURN qt_string_SQLSetConnectAttr(SQLHDBC handle, SQLINTEGER attr, co
}
-bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts)
+bool QODBCDriverPrivate::setConnectionOptions(const QString &connOpts)
{
// Set any connection attributes
- const QStringList opts(connOpts.split(u';', Qt::SkipEmptyParts));
SQLRETURN r = SQL_SUCCESS;
- for (int i = 0; i < opts.count(); ++i) {
- const QString tmp(opts.at(i));
+ for (const auto connOpt : QStringTokenizer{connOpts, u';'}) {
int idx;
- if ((idx = tmp.indexOf(u'=')) == -1) {
- qWarning() << "QODBCDriver::open: Illegal connect option value '" << tmp << '\'';
+ if ((idx = connOpt.indexOf(u'=')) == -1) {
+ qSqlWarning(("QODBCDriver::open: Illegal connect option value '%1'"_L1)
+ .arg(connOpt), this);
continue;
}
- const QString opt(tmp.left(idx));
- const QString val(tmp.mid(idx + 1).simplified());
+ const auto opt(connOpt.left(idx));
+ const auto val(connOpt.mid(idx + 1).trimmed());
SQLUINTEGER v = 0;
r = SQL_SUCCESS;
- if (opt.toUpper() == "SQL_ATTR_ACCESS_MODE"_L1) {
- if (val.toUpper() == "SQL_MODE_READ_ONLY"_L1) {
+ if (opt == "SQL_ATTR_ACCESS_MODE"_L1) {
+ if (val == "SQL_MODE_READ_ONLY"_L1) {
v = SQL_MODE_READ_ONLY;
- } else if (val.toUpper() == "SQL_MODE_READ_WRITE"_L1) {
+ } else if (val == "SQL_MODE_READ_WRITE"_L1) {
v = SQL_MODE_READ_WRITE;
} else {
- qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
+ qSqlWarning(("QODBCDriver::open: Unknown option value '%1'"_L1)
+ .arg(val), this);
continue;
}
r = SQLSetConnectAttr(hDbc, SQL_ATTR_ACCESS_MODE, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == "SQL_ATTR_CONNECTION_TIMEOUT"_L1) {
+ } else if (opt == "SQL_ATTR_CONNECTION_TIMEOUT"_L1) {
v = val.toUInt();
r = SQLSetConnectAttr(hDbc, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == "SQL_ATTR_LOGIN_TIMEOUT"_L1) {
+ } else if (opt == "SQL_ATTR_LOGIN_TIMEOUT"_L1) {
v = val.toUInt();
r = SQLSetConnectAttr(hDbc, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == "SQL_ATTR_CURRENT_CATALOG"_L1) {
+ } else if (opt == "SQL_ATTR_CURRENT_CATALOG"_L1) {
r = qt_string_SQLSetConnectAttr(hDbc, SQL_ATTR_CURRENT_CATALOG, val);
- } else if (opt.toUpper() == "SQL_ATTR_METADATA_ID"_L1) {
- if (val.toUpper() == "SQL_TRUE"_L1) {
+ } else if (opt == "SQL_ATTR_METADATA_ID"_L1) {
+ if (val == "SQL_TRUE"_L1) {
v = SQL_TRUE;
- } else if (val.toUpper() == "SQL_FALSE"_L1) {
+ } else if (val == "SQL_FALSE"_L1) {
v = SQL_FALSE;
} else {
- qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
+ qSqlWarning(("QODBCDriver::open: Unknown option value '%1'"_L1)
+ .arg(val), this);
continue;
}
r = SQLSetConnectAttr(hDbc, SQL_ATTR_METADATA_ID, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == "SQL_ATTR_PACKET_SIZE"_L1) {
+ } else if (opt == "SQL_ATTR_PACKET_SIZE"_L1) {
v = val.toUInt();
r = SQLSetConnectAttr(hDbc, SQL_ATTR_PACKET_SIZE, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == "SQL_ATTR_TRACEFILE"_L1) {
+ } else if (opt == "SQL_ATTR_TRACEFILE"_L1) {
r = qt_string_SQLSetConnectAttr(hDbc, SQL_ATTR_TRACEFILE, val);
- } else if (opt.toUpper() == "SQL_ATTR_TRACE"_L1) {
- if (val.toUpper() == "SQL_OPT_TRACE_OFF"_L1) {
+ } else if (opt == "SQL_ATTR_TRACE"_L1) {
+ if (val == "SQL_OPT_TRACE_OFF"_L1) {
v = SQL_OPT_TRACE_OFF;
- } else if (val.toUpper() == "SQL_OPT_TRACE_ON"_L1) {
+ } else if (val == "SQL_OPT_TRACE_ON"_L1) {
v = SQL_OPT_TRACE_ON;
} else {
- qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
+ qSqlWarning(("QODBCDriver::open: Unknown option value '%1'"_L1)
+ .arg(val), this);
continue;
}
r = SQLSetConnectAttr(hDbc, SQL_ATTR_TRACE, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == "SQL_ATTR_CONNECTION_POOLING"_L1) {
+ } else if (opt == "SQL_ATTR_CONNECTION_POOLING"_L1) {
if (val == "SQL_CP_OFF"_L1)
v = SQL_CP_OFF;
- else if (val.toUpper() == "SQL_CP_ONE_PER_DRIVER"_L1)
+ else if (val == "SQL_CP_ONE_PER_DRIVER"_L1)
v = SQL_CP_ONE_PER_DRIVER;
- else if (val.toUpper() == "SQL_CP_ONE_PER_HENV"_L1)
+ else if (val == "SQL_CP_ONE_PER_HENV"_L1)
v = SQL_CP_ONE_PER_HENV;
- else if (val.toUpper() == "SQL_CP_DEFAULT"_L1)
+ else if (val == "SQL_CP_DEFAULT"_L1)
v = SQL_CP_DEFAULT;
else {
- qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
+ qSqlWarning(("QODBCDriver::open: Unknown option value '%1'"_L1)
+ .arg(val), this);
continue;
}
r = SQLSetConnectAttr(hDbc, SQL_ATTR_CONNECTION_POOLING, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == "SQL_ATTR_CP_MATCH"_L1) {
- if (val.toUpper() == "SQL_CP_STRICT_MATCH"_L1)
+ } else if (opt == "SQL_ATTR_CP_MATCH"_L1) {
+ if (val == "SQL_CP_STRICT_MATCH"_L1)
v = SQL_CP_STRICT_MATCH;
- else if (val.toUpper() == "SQL_CP_RELAXED_MATCH"_L1)
+ else if (val == "SQL_CP_RELAXED_MATCH"_L1)
v = SQL_CP_RELAXED_MATCH;
- else if (val.toUpper() == "SQL_CP_MATCH_DEFAULT"_L1)
+ else if (val == "SQL_CP_MATCH_DEFAULT"_L1)
v = SQL_CP_MATCH_DEFAULT;
else {
- qWarning() << "QODBCDriver::open: Unknown option value '" << val << '\'';
+ qSqlWarning(("QODBCDriver::open: Unknown option value '%1'"_L1)
+ .arg(val), this);
continue;
}
r = SQLSetConnectAttr(hDbc, SQL_ATTR_CP_MATCH, (SQLPOINTER) size_t(v), 0);
- } else if (opt.toUpper() == "SQL_ATTR_ODBC_VERSION"_L1) {
+ } else if (opt == "SQL_ATTR_ODBC_VERSION"_L1) {
// Already handled in QODBCDriver::open()
continue;
} else {
- qWarning() << "QODBCDriver::open: Unknown connection attribute '" << opt << '\'';
+ qSqlWarning(("QODBCDriver::open: Unknown connection attribute '%1'"_L1)
+ .arg(opt), this);
}
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO)
- qSqlWarning(QString::fromLatin1("QODBCDriver::open: Unable to set connection attribute'%1'").arg(
- opt), this);
+ if (!SQL_SUCCEEDED(r))
+ qSqlWarning(("QODBCDriver::open: Unable to set connection attribute '%1'"_L1)
+ .arg(opt), this);
}
return true;
}
@@ -799,60 +839,65 @@ bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts)
void QODBCDriverPrivate::splitTableQualifier(const QString &qualifier, QString &catalog,
QString &schema, QString &table) const
{
+ Q_Q(const QODBCDriver);
+ const auto adjustName = [&](const QString &name) {
+ if (q->isIdentifierEscaped(name, QSqlDriver::TableName))
+ return q->stripDelimiters(name, QSqlDriver::TableName);
+ return adjustCase(name);
+ };
+ catalog.clear();
+ schema.clear();
+ table.clear();
if (!useSchema) {
- table = qualifier;
+ table = adjustName(qualifier);
return;
}
const QList<QStringView> l = QStringView(qualifier).split(u'.');
switch (l.count()) {
case 1:
- table = qualifier;
+ table = adjustName(qualifier);
break;
case 2:
- schema = l.at(0).toString();
- table = l.at(1).toString();
+ schema = adjustName(l.at(0).toString());
+ table = adjustName(l.at(1).toString());
break;
case 3:
- catalog = l.at(0).toString();
- schema = l.at(1).toString();
- table = l.at(2).toString();
+ catalog = adjustName(l.at(0).toString());
+ schema = adjustName(l.at(1).toString());
+ table = adjustName(l.at(2).toString());
break;
default:
- qSqlWarning(QString::fromLatin1("QODBCDriver::splitTableQualifier: Unable to split table qualifier '%1'")
+ qSqlWarning(("QODBCDriver::splitTableQualifier: Unable to split table qualifier '%1'"_L1)
.arg(qualifier), this);
break;
}
}
-QODBCDriverPrivate::DefaultCase QODBCDriverPrivate::defaultCase() const
+void QODBCDriverPrivate::checkDefaultCase()
{
- DefaultCase ret;
+ m_defaultCase = DefaultCase::Mixed; //arbitrary case if driver cannot be queried
SQLUSMALLINT casing;
- int r = SQLGetInfo(hDbc,
- SQL_IDENTIFIER_CASE,
- &casing,
- sizeof(casing),
- NULL);
- if ( r != SQL_SUCCESS)
- ret = Mixed;//arbitrary case if driver cannot be queried
- else {
+ SQLRETURN r = SQLGetInfo(hDbc,
+ SQL_IDENTIFIER_CASE,
+ &casing,
+ sizeof(casing),
+ NULL);
+ if (r == SQL_SUCCESS) {
switch (casing) {
- case (SQL_IC_UPPER):
- ret = Upper;
- break;
- case (SQL_IC_LOWER):
- ret = Lower;
- break;
- case (SQL_IC_SENSITIVE):
- ret = Sensitive;
- break;
- case (SQL_IC_MIXED):
- default:
- ret = Mixed;
- break;
+ case SQL_IC_UPPER:
+ m_defaultCase = DefaultCase::Upper;
+ break;
+ case SQL_IC_LOWER:
+ m_defaultCase = DefaultCase::Lower;
+ break;
+ case SQL_IC_SENSITIVE:
+ m_defaultCase = DefaultCase::Sensitive;
+ break;
+ case SQL_IC_MIXED:
+ m_defaultCase = DefaultCase::Mixed;
+ break;
}
}
- return ret;
}
/*
@@ -861,20 +906,16 @@ QODBCDriverPrivate::DefaultCase QODBCDriverPrivate::defaultCase() const
*/
QString QODBCDriverPrivate::adjustCase(const QString &identifier) const
{
- QString ret = identifier;
- switch(defaultCase()) {
- case (Lower):
- ret = identifier.toLower();
- break;
- case (Upper):
- ret = identifier.toUpper();
- break;
- case(Mixed):
- case(Sensitive):
- default:
- ret = identifier;
+ switch (m_defaultCase) {
+ case DefaultCase::Lower:
+ return identifier.toLower();
+ case DefaultCase::Upper:
+ return identifier.toUpper();
+ case DefaultCase::Mixed:
+ case DefaultCase::Sensitive:
+ break;
}
- return ret;
+ return identifier;
}
////////////////////////////////////////////////////////////////////////////
@@ -890,8 +931,7 @@ QODBCResult::~QODBCResult()
if (d->hStmt && d->isStmtHandleValid() && driver() && driver()->isOpen()) {
SQLRETURN r = SQLFreeHandle(SQL_HANDLE_STMT, d->hStmt);
if (r != SQL_SUCCESS)
- qSqlWarning("QODBCDriver: Unable to free statement handle "_L1
- + QString::number(r), d);
+ qSqlWarning(("QODBCResult: Unable to free statement handle "_L1), d);
}
}
@@ -935,7 +975,7 @@ bool QODBCResult::reset (const QString& query)
(SQLPOINTER)SQL_CURSOR_STATIC,
SQL_IS_UINTEGER);
}
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ if (!SQL_SUCCEEDED(r)) {
setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
"QODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. "
"Please check your ODBC driver configuration"), QSqlError::StatementError, d));
@@ -948,7 +988,7 @@ bool QODBCResult::reset (const QString& query)
encoded.data(),
SQLINTEGER(encoded.size()));
}
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r!= SQL_NO_DATA) {
+ if (!SQL_SUCCEEDED(r) && r!= SQL_NO_DATA) {
setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
"Unable to execute statement"), QSqlError::StatementError, d));
return false;
@@ -956,7 +996,7 @@ bool QODBCResult::reset (const QString& query)
SQLULEN isScrollable = 0;
r = SQLGetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, &isScrollable, SQL_IS_INTEGER, 0);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
+ if (SQL_SUCCEEDED(r))
setForwardOnly(isScrollable == SQL_NONSCROLLABLE);
SQLSMALLINT count = 0;
@@ -1025,7 +1065,7 @@ bool QODBCResult::fetchNext()
else
r = SQLFetch(d->hStmt);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ if (!SQL_SUCCEEDED(r)) {
if (r != SQL_NO_DATA)
setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
"Unable to fetch next"), QSqlError::ConnectionError, d));
@@ -1122,7 +1162,8 @@ QVariant QODBCResult::data(int field)
{
Q_D(QODBCResult);
if (field >= d->rInf.count() || field < 0) {
- qWarning() << "QODBCResult::data: column" << field << "out of range";
+ qSqlWarning(("QODBCResult::data: column %1 out of range"_L1)
+ .arg(QString::number(field)), d);
return QVariant();
}
if (field < d->fieldCacheIdx)
@@ -1158,7 +1199,7 @@ QVariant QODBCResult::data(int field)
(SQLPOINTER)&dbuf,
0,
&lengthIndicator);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA))
+ if (SQL_SUCCEEDED(r) && (lengthIndicator != SQL_NULL_DATA))
d->fieldCache[i] = QVariant(QDate(dbuf.year, dbuf.month, dbuf.day));
else
d->fieldCache[i] = QVariant(QMetaType::fromType<QDate>());
@@ -1171,7 +1212,7 @@ QVariant QODBCResult::data(int field)
(SQLPOINTER)&tbuf,
0,
&lengthIndicator);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA))
+ if (SQL_SUCCEEDED(r) && (lengthIndicator != SQL_NULL_DATA))
d->fieldCache[i] = QVariant(QTime(tbuf.hour, tbuf.minute, tbuf.second));
else
d->fieldCache[i] = QVariant(QMetaType::fromType<QTime>());
@@ -1184,7 +1225,7 @@ QVariant QODBCResult::data(int field)
(SQLPOINTER)&dtbuf,
0,
&lengthIndicator);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (lengthIndicator != SQL_NULL_DATA))
+ if (SQL_SUCCEEDED(r) && (lengthIndicator != SQL_NULL_DATA))
d->fieldCache[i] = QVariant(QDateTime(QDate(dtbuf.year, dtbuf.month, dtbuf.day),
QTime(dtbuf.hour, dtbuf.minute, dtbuf.second, dtbuf.fraction / 1000000)));
else
@@ -1248,8 +1289,7 @@ int QODBCResult::numRowsAffected()
SQLRETURN r = SQLRowCount(d->hStmt, &affectedRowCount);
if (r == SQL_SUCCESS)
return affectedRowCount;
- else
- qSqlWarning("QODBCResult::numRowsAffected: Unable to count affected rows"_L1, d);
+ qSqlWarning("QODBCResult::numRowsAffected: Unable to count affected rows"_L1, d);
return -1;
}
@@ -1289,7 +1329,7 @@ bool QODBCResult::prepare(const QString& query)
(SQLPOINTER)SQL_CURSOR_STATIC,
SQL_IS_UINTEGER);
}
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ if (!SQL_SUCCEEDED(r)) {
setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
"QODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. "
"Please check your ODBC driver configuration"), QSqlError::StatementError, d));
@@ -1621,7 +1661,7 @@ bool QODBCResult::exec()
}
}
r = SQLExecute(d->hStmt);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r != SQL_NO_DATA) {
+ if (!SQL_SUCCEEDED(r) && r != SQL_NO_DATA) {
qSqlWarning("QODBCResult::exec: Unable to execute statement:"_L1, d);
setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
"Unable to execute statement"), QSqlError::StatementError, d));
@@ -1630,7 +1670,7 @@ bool QODBCResult::exec()
SQLULEN isScrollable = 0;
r = SQLGetStmtAttr(d->hStmt, SQL_ATTR_CURSOR_SCROLLABLE, &isScrollable, SQL_IS_INTEGER, 0);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
+ if (SQL_SUCCEEDED(r))
setForwardOnly(isScrollable == SQL_NONSCROLLABLE);
SQLSMALLINT count = 0;
@@ -1762,8 +1802,7 @@ bool QODBCResult::nextResult()
SQLRETURN r = SQLMoreResults(d->hStmt);
if (r != SQL_SUCCESS) {
if (r == SQL_SUCCESS_WITH_INFO) {
- QString message = errorStringFromDiagRecords(qODBCWarn(d));
- qWarning() << "QODBCResult::nextResult():" << message;
+ qSqlWarning("QODBCResult::nextResult:"_L1, d);
} else {
if (r != SQL_NO_DATA)
setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
@@ -1882,6 +1921,18 @@ bool QODBCDriver::open(const QString & db,
int,
const QString& connOpts)
{
+ const auto ensureEscaped = [](QString arg) -> QString {
+ QChar quoteChar;
+ if (arg.startsWith(u'"'))
+ quoteChar = u'\'';
+ else if (arg.startsWith(u'\''))
+ quoteChar = u'"';
+ else if (arg.contains(u';'))
+ quoteChar = u'"';
+ else
+ return arg;
+ return quoteChar + arg + quoteChar;
+ };
Q_D(QODBCDriver);
if (isOpen())
close();
@@ -1889,7 +1940,7 @@ bool QODBCDriver::open(const QString & db,
r = SQLAllocHandle(SQL_HANDLE_ENV,
SQL_NULL_HANDLE,
&d->hEnv);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ if (!SQL_SUCCEEDED(r)) {
qSqlWarning("QODBCDriver::open: Unable to allocate environment"_L1, d);
setOpenError(true);
return false;
@@ -1901,7 +1952,7 @@ bool QODBCDriver::open(const QString & db,
r = SQLAllocHandle(SQL_HANDLE_DBC,
d->hEnv,
&d->hDbc);
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ if (!SQL_SUCCEEDED(r)) {
qSqlWarning("QODBCDriver::open: Unable to allocate connection"_L1, d);
setOpenError(true);
cleanup();
@@ -1917,17 +1968,17 @@ bool QODBCDriver::open(const QString & db,
QString connQStr;
// support the "DRIVER={SQL SERVER};SERVER=blah" syntax
if (db.contains(".dsn"_L1, Qt::CaseInsensitive))
- connQStr = "FILEDSN="_L1 + db;
+ connQStr = "FILEDSN="_L1 + ensureEscaped(db);
else if (db.contains("DRIVER="_L1, Qt::CaseInsensitive)
|| db.contains("SERVER="_L1, Qt::CaseInsensitive))
connQStr = db;
else
- connQStr = "DSN="_L1 + db;
+ connQStr = "DSN="_L1 + ensureEscaped(db);
if (!user.isEmpty())
- connQStr += ";UID="_L1 + user;
+ connQStr += ";UID="_L1 + ensureEscaped(user);
if (!password.isEmpty())
- connQStr += ";PWD="_L1 + password;
+ connQStr += ";PWD="_L1 + ensureEscaped(password);
SQLSMALLINT cb;
QVarLengthArray<SQLTCHAR, 1024> connOut(1024);
@@ -1941,7 +1992,7 @@ bool QODBCDriver::open(const QString & db,
/*SQL_DRIVER_NOPROMPT*/0);
}
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
+ if (!SQL_SUCCEEDED(r)) {
setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d));
setOpenError(true);
cleanup();
@@ -1962,6 +2013,7 @@ bool QODBCDriver::open(const QString & db,
d->checkHasSQLFetchScroll();
d->checkHasMultiResults();
d->checkDateTimePrecision();
+ d->checkDefaultCase();
setOpen(true);
setOpenError(false);
if (d->dbmsType == MSSqlServer) {
@@ -2020,7 +2072,7 @@ void QODBCDriverPrivate::checkUnicode()
(SQLPOINTER)&fFunc,
sizeof(fFunc),
NULL);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WCHAR)) {
+ if (SQL_SUCCEEDED(r) && (fFunc & SQL_CVT_WCHAR)) {
unicode = true;
return;
}
@@ -2030,7 +2082,7 @@ void QODBCDriverPrivate::checkUnicode()
(SQLPOINTER)&fFunc,
sizeof(fFunc),
NULL);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WVARCHAR)) {
+ if (SQL_SUCCEEDED(r) && (fFunc & SQL_CVT_WVARCHAR)) {
unicode = true;
return;
}
@@ -2040,39 +2092,36 @@ void QODBCDriverPrivate::checkUnicode()
(SQLPOINTER)&fFunc,
sizeof(fFunc),
NULL);
- if ((r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) && (fFunc & SQL_CVT_WLONGVARCHAR)) {
+ if (SQL_SUCCEEDED(r) && (fFunc & SQL_CVT_WLONGVARCHAR)) {
unicode = true;
return;
}
- SQLHANDLE hStmt;
- r = SQLAllocHandle(SQL_HANDLE_STMT,
- hDbc,
- &hStmt);
+ SqlStmtHandle hStmt(hDbc);
// for databases which do not return something useful in SQLGetInfo and are picky about a
// 'SELECT' statement without 'FROM' but support VALUE(foo) statement like e.g. DB2 or Oracle
- const auto statements = {
- "select 'test'"_L1,
- "values('test')"_L1,
- "select 'test' from dual"_L1,
+ const std::array<QStringView, 3> statements = {
+ u"select 'test'",
+ u"values('test')",
+ u"select 'test' from dual",
};
for (const auto &statement : statements) {
auto encoded = toSQLTCHAR(statement);
- r = SQLExecDirect(hStmt, encoded.data(), SQLINTEGER(encoded.size()));
+ r = SQLExecDirect(hStmt.handle(), encoded.data(), SQLINTEGER(encoded.size()));
if (r == SQL_SUCCESS)
break;
}
if (r == SQL_SUCCESS) {
- r = SQLFetch(hStmt);
+ r = SQLFetch(hStmt.handle());
if (r == SQL_SUCCESS) {
QVarLengthArray<SQLWCHAR, 10> buffer(10);
- r = SQLGetData(hStmt, 1, SQL_C_WCHAR, buffer.data(), buffer.size() * sizeof(SQLWCHAR), NULL);
+ r = SQLGetData(hStmt.handle(), 1, SQL_C_WCHAR, buffer.data(),
+ buffer.size() * sizeof(SQLWCHAR), NULL);
if (r == SQL_SUCCESS && fromSQLTCHAR(buffer) == "test"_L1) {
unicode = true;
}
}
}
- r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
}
bool QODBCDriverPrivate::checkDriver() const
@@ -2102,9 +2151,10 @@ bool QODBCDriverPrivate::checkDriver() const
return false;
}
if (sup == SQL_FALSE) {
- qWarning () << "QODBCDriver::open: Warning - Driver doesn't support all needed functionality ("
- << func
- << ").\nPlease look at the Qt SQL Module Driver documentation for more information.";
+ qSqlWarning(("QODBCDriver::checkDriver: Driver doesn't support all needed "
+ "functionality (func id %1).\nPlease look at the Qt SQL Module "
+ "Driver documentation for more information."_L1)
+ .arg(QString::number(func)), this);
return false;
}
}
@@ -2119,8 +2169,9 @@ bool QODBCDriverPrivate::checkDriver() const
return false;
}
if (sup == SQL_FALSE) {
- qWarning() << "QODBCDriver::checkDriver: Warning - Driver doesn't support some non-critical functions ("
- << func << ')';
+ qSqlWarning(("QODBCDriver::checkDriver: Driver doesn't support some "
+ "non-critical functions (func id %1)."_L1)
+ .arg(QString::number(func)), this);
return true;
}
}
@@ -2139,7 +2190,7 @@ void QODBCDriverPrivate::checkSchemaUsage()
(SQLPOINTER) &val,
sizeof(val),
NULL);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
+ if (SQL_SUCCEEDED(r))
useSchema = (val != 0);
}
@@ -2154,7 +2205,7 @@ void QODBCDriverPrivate::checkDBMS()
serverString.data(),
SQLSMALLINT(serverString.size() * sizeof(SQLTCHAR)),
&t);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
+ if (SQL_SUCCEEDED(r)) {
const QString serverType = fromSQLTCHAR(serverString, t / sizeof(SQLTCHAR));
if (serverType.contains("PostgreSQL"_L1, Qt::CaseInsensitive))
dbmsType = QSqlDriver::PostgreSQL;
@@ -2172,7 +2223,7 @@ void QODBCDriverPrivate::checkDBMS()
serverString.data(),
SQLSMALLINT(serverString.size() * sizeof(SQLTCHAR)),
&t);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
+ if (SQL_SUCCEEDED(r)) {
const QString serverType = fromSQLTCHAR(serverString, t / sizeof(SQLTCHAR));
isFreeTDSDriver = serverType.contains("tdsodbc"_L1, Qt::CaseInsensitive);
unicode = unicode && !isFreeTDSDriver;
@@ -2183,9 +2234,10 @@ void QODBCDriverPrivate::checkHasSQLFetchScroll()
{
SQLUSMALLINT sup;
SQLRETURN r = SQLGetFunctions(hDbc, SQL_API_SQLFETCHSCROLL, &sup);
- if ((r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) || sup != SQL_TRUE) {
+ if ((!SQL_SUCCEEDED(r)) || sup != SQL_TRUE) {
hasSQLFetchScroll = false;
- qWarning("QODBCDriver::checkHasSQLFetchScroll: Warning - Driver doesn't support scrollable result sets, use forward only mode for queries");
+ qSqlWarning("QODBCDriver::checkHasSQLFetchScroll: Driver doesn't support "
+ "scrollable result sets, use forward only mode for queries"_L1, this);
}
}
@@ -2198,31 +2250,26 @@ void QODBCDriverPrivate::checkHasMultiResults()
driverResponse.data(),
SQLSMALLINT(driverResponse.size() * sizeof(SQLTCHAR)),
&length);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO)
+ if (SQL_SUCCEEDED(r))
hasMultiResultSets = fromSQLTCHAR(driverResponse, length / sizeof(SQLTCHAR)).startsWith(u'Y');
}
void QODBCDriverPrivate::checkDateTimePrecision()
{
SQLINTEGER columnSize;
- SQLHANDLE hStmt;
+ SqlStmtHandle hStmt(hDbc);
- SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &hStmt);
- if (r != SQL_SUCCESS) {
+ if (!hStmt.isValid())
return;
- }
- r = SQLGetTypeInfo(hStmt, SQL_TIMESTAMP);
- if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) {
- r = SQLFetch(hStmt);
- if ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO )
- {
- if (SQLGetData(hStmt, 3, SQL_INTEGER, &columnSize, sizeof(columnSize), 0) == SQL_SUCCESS) {
+ SQLRETURN r = SQLGetTypeInfo(hStmt.handle(), SQL_TIMESTAMP);
+ if (SQL_SUCCEEDED(r)) {
+ r = SQLFetch(hStmt.handle());
+ if (SQL_SUCCEEDED(r)) {
+ if (SQLGetData(hStmt.handle(), 3, SQL_INTEGER, &columnSize, sizeof(columnSize), 0) == SQL_SUCCESS)
datetimePrecision = (int)columnSize;
- }
}
}
- SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
}
QSqlResult *QODBCDriver::createResult() const
@@ -2234,7 +2281,7 @@ bool QODBCDriver::beginTransaction()
{
Q_D(QODBCDriver);
if (!isOpen()) {
- qWarning("QODBCDriver::beginTransaction: Database not open");
+ qSqlWarning("QODBCDriver::beginTransaction: Database not open"_L1, d);
return false;
}
SQLUINTEGER ac(SQL_AUTOCOMMIT_OFF);
@@ -2254,7 +2301,7 @@ bool QODBCDriver::commitTransaction()
{
Q_D(QODBCDriver);
if (!isOpen()) {
- qWarning("QODBCDriver::commitTransaction: Database not open");
+ qSqlWarning("QODBCDriver::commitTransaction: Database not open"_L1, d);
return false;
}
SQLRETURN r = SQLEndTran(SQL_HANDLE_DBC,
@@ -2272,7 +2319,7 @@ bool QODBCDriver::rollbackTransaction()
{
Q_D(QODBCDriver);
if (!isOpen()) {
- qWarning("QODBCDriver::rollbackTransaction: Database not open");
+ qSqlWarning("QODBCDriver::rollbackTransaction: Database not open"_L1, d);
return false;
}
SQLRETURN r = SQLEndTran(SQL_HANDLE_DBC,
@@ -2307,19 +2354,16 @@ QStringList QODBCDriver::tables(QSql::TableType type) const
QStringList tl;
if (!isOpen())
return tl;
- SQLHANDLE hStmt;
- SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
- d->hDbc,
- &hStmt);
- if (r != SQL_SUCCESS) {
+ SqlStmtHandle hStmt(d->hDbc);
+ if (!hStmt.isValid()) {
qSqlWarning("QODBCDriver::tables: Unable to allocate handle"_L1, d);
return tl;
}
- r = SQLSetStmtAttr(hStmt,
- SQL_ATTR_CURSOR_TYPE,
- (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
- SQL_IS_UINTEGER);
+ SQLRETURN r = SQLSetStmtAttr(hStmt.handle(),
+ SQL_ATTR_CURSOR_TYPE,
+ (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
+ SQL_IS_UINTEGER);
QStringList tableType;
if (type & QSql::Tables)
tableType += "TABLE"_L1;
@@ -2333,7 +2377,7 @@ QStringList QODBCDriver::tables(QSql::TableType type) const
{
auto joinedTableTypeString = toSQLTCHAR(tableType.join(u','));
- r = SQLTables(hStmt,
+ r = SQLTables(hStmt.handle(),
nullptr, 0,
nullptr, 0,
nullptr, 0,
@@ -2341,36 +2385,21 @@ QStringList QODBCDriver::tables(QSql::TableType type) const
}
if (r != SQL_SUCCESS)
- qSqlWarning("QODBCDriver::tables Unable to execute table list"_L1, d);
-
- if (d->hasSQLFetchScroll)
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- else
- r = SQLFetch(hStmt);
+ qSqlWarning("QODBCDriver::tables Unable to execute table list"_L1,
+ hStmt.handle());
- if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r != SQL_NO_DATA) {
- qSqlWarning("QODBCDriver::tables failed to retrieve table/view list: ("_L1
- + QString::number(r) + u':',
- hStmt);
+ r = d->sqlFetchNext(hStmt);
+ if (!SQL_SUCCEEDED(r) && r != SQL_NO_DATA) {
+ qSqlWarning("QODBCDriver::tables failed to retrieve table/view list"_L1,
+ hStmt.handle());
return QStringList();
}
while (r == SQL_SUCCESS) {
- tl.append(qGetStringData(hStmt, 2, -1, d->unicode).toString());
-
- if (d->hasSQLFetchScroll)
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- else
- r = SQLFetch(hStmt);
+ tl.append(qGetStringData(hStmt.handle(), 2, -1, d->unicode).toString());
+ r = d->sqlFetchNext(hStmt);
}
- r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
- if (r!= SQL_SUCCESS)
- qSqlWarning("QODBCDriver: Unable to free statement handle"_L1 + QString::number(r), d);
return tl;
}
@@ -2383,41 +2412,23 @@ QSqlIndex QODBCDriver::primaryIndex(const QString& tablename) const
bool usingSpecialColumns = false;
QSqlRecord rec = record(tablename);
- SQLHANDLE hStmt;
- SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
- d->hDbc,
- &hStmt);
- if (r != SQL_SUCCESS) {
- qSqlWarning("QODBCDriver::primaryIndex: Unable to list primary key"_L1, d);
+ SqlStmtHandle hStmt(d->hDbc);
+ if (!hStmt.isValid()) {
+ qSqlWarning("QODBCDriver::primaryIndex: Unable to allocate handle"_L1, d);
return index;
}
QString catalog, schema, table;
d->splitTableQualifier(tablename, catalog, schema, table);
- if (isIdentifierEscaped(catalog, QSqlDriver::TableName))
- catalog = stripDelimiters(catalog, QSqlDriver::TableName);
- else
- catalog = d->adjustCase(catalog);
-
- if (isIdentifierEscaped(schema, QSqlDriver::TableName))
- schema = stripDelimiters(schema, QSqlDriver::TableName);
- else
- schema = d->adjustCase(schema);
-
- if (isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
- else
- table = d->adjustCase(table);
-
- r = SQLSetStmtAttr(hStmt,
- SQL_ATTR_CURSOR_TYPE,
- (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
- SQL_IS_UINTEGER);
+ SQLRETURN r = SQLSetStmtAttr(hStmt.handle(),
+ SQL_ATTR_CURSOR_TYPE,
+ (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
+ SQL_IS_UINTEGER);
{
auto c = toSQLTCHAR(catalog);
auto s = toSQLTCHAR(schema);
auto t = toSQLTCHAR(table);
- r = SQLPrimaryKeys(hStmt,
+ r = SQLPrimaryKeys(hStmt.handle(),
catalog.isEmpty() ? nullptr : c.data(), c.size(),
schema.isEmpty() ? nullptr : s.data(), s.size(),
t.data(), t.size());
@@ -2430,7 +2441,7 @@ QSqlIndex QODBCDriver::primaryIndex(const QString& tablename) const
auto c = toSQLTCHAR(catalog);
auto s = toSQLTCHAR(schema);
auto t = toSQLTCHAR(table);
- r = SQLSpecialColumns(hStmt,
+ r = SQLSpecialColumns(hStmt.handle(),
SQL_BEST_ROWID,
catalog.isEmpty() ? nullptr : c.data(), c.size(),
schema.isEmpty() ? nullptr : s.data(), s.size(),
@@ -2439,44 +2450,31 @@ QSqlIndex QODBCDriver::primaryIndex(const QString& tablename) const
SQL_NULLABLE);
if (r != SQL_SUCCESS) {
- qSqlWarning("QODBCDriver::primaryIndex: Unable to execute primary key list"_L1, d);
+ qSqlWarning("QODBCDriver::primaryIndex: Unable to execute primary key list"_L1,
+ hStmt.handle());
} else {
usingSpecialColumns = true;
}
}
- if (d->hasSQLFetchScroll)
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- else
- r = SQLFetch(hStmt);
+ r = d->sqlFetchNext(hStmt);
int fakeId = 0;
QString cName, idxName;
// Store all fields in a StringList because some drivers can't detail fields in this FETCH loop
while (r == SQL_SUCCESS) {
if (usingSpecialColumns) {
- cName = qGetStringData(hStmt, 1, -1, d->unicode).toString(); // column name
+ cName = qGetStringData(hStmt.handle(), 1, -1, d->unicode).toString(); // column name
idxName = QString::number(fakeId++); // invent a fake index name
} else {
- cName = qGetStringData(hStmt, 3, -1, d->unicode).toString(); // column name
- idxName = qGetStringData(hStmt, 5, -1, d->unicode).toString(); // pk index name
+ cName = qGetStringData(hStmt.handle(), 3, -1, d->unicode).toString(); // column name
+ idxName = qGetStringData(hStmt.handle(), 5, -1, d->unicode).toString(); // pk index name
}
index.append(rec.field(cName));
index.setName(idxName);
- if (d->hasSQLFetchScroll)
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- else
- r = SQLFetch(hStmt);
-
+ r = d->sqlFetchNext(hStmt);
}
- r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
- if (r!= SQL_SUCCESS)
- qSqlWarning("QODBCDriver: Unable to free statement handle"_L1 + QString::number(r), d);
return index;
}
@@ -2487,41 +2485,24 @@ QSqlRecord QODBCDriver::record(const QString& tablename) const
if (!isOpen())
return fil;
- SQLHANDLE hStmt;
- QString catalog, schema, table;
- d->splitTableQualifier(tablename, catalog, schema, table);
-
- if (isIdentifierEscaped(catalog, QSqlDriver::TableName))
- catalog = stripDelimiters(catalog, QSqlDriver::TableName);
- else
- catalog = d->adjustCase(catalog);
-
- if (isIdentifierEscaped(schema, QSqlDriver::TableName))
- schema = stripDelimiters(schema, QSqlDriver::TableName);
- else
- schema = d->adjustCase(schema);
-
- if (isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
- else
- table = d->adjustCase(table);
-
- SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT,
- d->hDbc,
- &hStmt);
- if (r != SQL_SUCCESS) {
+ SqlStmtHandle hStmt(d->hDbc);
+ if (!hStmt.isValid()) {
qSqlWarning("QODBCDriver::record: Unable to allocate handle"_L1, d);
return fil;
}
- r = SQLSetStmtAttr(hStmt,
- SQL_ATTR_CURSOR_TYPE,
- (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
- SQL_IS_UINTEGER);
+
+ QString catalog, schema, table;
+ d->splitTableQualifier(tablename, catalog, schema, table);
+
+ SQLRETURN r = SQLSetStmtAttr(hStmt.handle(),
+ SQL_ATTR_CURSOR_TYPE,
+ (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
+ SQL_IS_UINTEGER);
{
auto c = toSQLTCHAR(catalog);
auto s = toSQLTCHAR(schema);
auto t = toSQLTCHAR(table);
- r = SQLColumns(hStmt,
+ r = SQLColumns(hStmt.handle(),
catalog.isEmpty() ? nullptr : c.data(), c.size(),
schema.isEmpty() ? nullptr : s.data(), s.size(),
t.data(), t.size(),
@@ -2529,32 +2510,14 @@ QSqlRecord QODBCDriver::record(const QString& tablename) const
0);
}
if (r != SQL_SUCCESS)
- qSqlWarning("QODBCDriver::record: Unable to execute column list"_L1, d);
-
- if (d->hasSQLFetchScroll)
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- else
- r = SQLFetch(hStmt);
+ qSqlWarning("QODBCDriver::record: Unable to execute column list"_L1, hStmt.handle());
+ r = d->sqlFetchNext(hStmt);
// Store all fields in a StringList because some drivers can't detail fields in this FETCH loop
while (r == SQL_SUCCESS) {
-
- fil.append(qMakeFieldInfo(hStmt, d));
-
- if (d->hasSQLFetchScroll)
- r = SQLFetchScroll(hStmt,
- SQL_FETCH_NEXT,
- 0);
- else
- r = SQLFetch(hStmt);
+ fil.append(qMakeFieldInfo(hStmt.handle(), d));
+ r = d->sqlFetchNext(hStmt);
}
-
- r = SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
- if (r!= SQL_SUCCESS)
- qSqlWarning("QODBCDriver: Unable to free statement handle "_L1 + QString::number(r), d);
-
return fil;
}
@@ -2566,9 +2529,10 @@ QString QODBCDriver::formatValue(const QSqlField &field,
r = "NULL"_L1;
} else if (field.metaType().id() == QMetaType::QDateTime) {
// Use an escape sequence for the datetime fields
- if (field.value().toDateTime().isValid()){
- QDate dt = field.value().toDateTime().date();
- QTime tm = field.value().toDateTime().time();
+ const QDateTime dateTime = field.value().toDateTime();
+ if (dateTime.isValid()) {
+ const QDate dt = dateTime.date();
+ const QTime tm = dateTime.time();
// Dateformat has to be "yyyy-MM-dd hh:mm:ss", with leading zeroes if month or day < 10
r = "{ ts '"_L1 +
QString::number(dt.year()) + u'-' +
diff --git a/src/plugins/sqldrivers/psql/CMakeLists.txt b/src/plugins/sqldrivers/psql/CMakeLists.txt
index d392f4dfa5..2f55ab4950 100644
--- a/src/plugins/sqldrivers/psql/CMakeLists.txt
+++ b/src/plugins/sqldrivers/psql/CMakeLists.txt
@@ -16,6 +16,7 @@ qt_internal_add_plugin(QPSQLDriverPlugin
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
+ QT_NO_CONTEXTLESS_CONNECT
LIBRARIES
PostgreSQL::PostgreSQL
Qt::Core
diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp
index 81d7e14444..7b9521fec6 100644
--- a/src/plugins/sqldrivers/psql/qsql_psql.cpp
+++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp
@@ -6,6 +6,7 @@
#include <qcoreapplication.h>
#include <qvariant.h>
#include <qdatetime.h>
+#include <qloggingcategory.h>
#include <qregularexpression.h>
#include <qsqlerror.h>
#include <qsqlfield.h>
@@ -65,6 +66,8 @@ Q_DECLARE_METATYPE(PGresult*)
QT_BEGIN_NAMESPACE
+static Q_LOGGING_CATEGORY(lcPsql, "qt.sql.postgresql")
+
using namespace Qt::StringLiterals;
inline void qPQfreemem(void *buffer)
@@ -74,11 +77,11 @@ inline void qPQfreemem(void *buffer)
/* Missing declaration of PGRES_SINGLE_TUPLE for PSQL below 9.2 */
#if !defined PG_VERSION_NUM || PG_VERSION_NUM-0 < 90200
-static const int PGRES_SINGLE_TUPLE = 9;
+static constexpr int PGRES_SINGLE_TUPLE = 9;
#endif
typedef int StatementId;
-static const StatementId InvalidStatementId = 0;
+static constexpr StatementId InvalidStatementId = 0;
class QPSQLResultPrivate;
@@ -122,10 +125,9 @@ public:
QSocketNotifier *sn = nullptr;
QPSQLDriver::Protocol pro = QPSQLDriver::Version6;
StatementId currentStmtId = InvalidStatementId;
- int stmtCount = 0;
+ StatementId stmtCount = InvalidStatementId;
mutable bool pendingNotifyCheck = false;
bool hasBackslashEscape = false;
- bool isUtf8 = false;
void appendTables(QStringList &tl, QSqlQuery &t, QChar type);
PGresult *exec(const char *stmt);
@@ -141,6 +143,7 @@ public:
bool setEncodingUtf8();
void setDatestyle();
void setByteaOutput();
+ void setUtcTimeZone();
void detectBackslashEscape();
mutable QHash<int, QString> oidToTable;
};
@@ -175,7 +178,7 @@ PGresult *QPSQLDriverPrivate::exec(const char *stmt)
PGresult *QPSQLDriverPrivate::exec(const QString &stmt)
{
- return exec((isUtf8 ? stmt.toUtf8() : stmt.toLocal8Bit()).constData());
+ return exec(stmt.toUtf8().constData());
}
StatementId QPSQLDriverPrivate::sendQuery(const QString &stmt)
@@ -183,8 +186,7 @@ StatementId QPSQLDriverPrivate::sendQuery(const QString &stmt)
// Discard any prior query results that the application didn't eat.
// This is required for PQsendQuery()
discardResults();
- const int result = PQsendQuery(connection,
- (isUtf8 ? stmt.toUtf8() : stmt.toLocal8Bit()).constData());
+ const int result = PQsendQuery(connection, stmt.toUtf8().constData());
currentStmtId = result ? generateStatementId() : InvalidStatementId;
return currentStmtId;
}
@@ -209,8 +211,8 @@ PGresult *QPSQLDriverPrivate::getResult(StatementId stmtId) const
if (stmtId != currentStmtId) {
// If you change the following warning, remember to update it
// on sql-driver.html page too.
- qWarning("QPSQLDriver::getResult: Query results lost - "
- "probably discarded on executing another SQL query.");
+ qCWarning(lcPsql, "QPSQLDriver::getResult: Query results lost - "
+ "probably discarded on executing another SQL query.");
return nullptr;
}
PGresult *result = PQgetResult(connection);
@@ -234,7 +236,7 @@ void QPSQLDriverPrivate::discardResults() const
StatementId QPSQLDriverPrivate::generateStatementId()
{
- int stmtId = ++stmtCount;
+ StatementId stmtId = ++stmtCount;
if (stmtId <= 0)
stmtId = stmtCount = 1;
return stmtId;
@@ -245,18 +247,18 @@ void QPSQLDriverPrivate::checkPendingNotifications() const
Q_Q(const QPSQLDriver);
if (seid.size() && !pendingNotifyCheck) {
pendingNotifyCheck = true;
- QMetaObject::invokeMethod(const_cast<QPSQLDriver*>(q), "_q_handleNotification", Qt::QueuedConnection);
+ QMetaObject::invokeMethod(const_cast<QPSQLDriver*>(q), &QPSQLDriver::_q_handleNotification, Qt::QueuedConnection);
}
}
-class QPSQLResultPrivate : public QSqlResultPrivate
+class QPSQLResultPrivate final : public QSqlResultPrivate
{
Q_DECLARE_PUBLIC(QPSQLResult)
public:
Q_DECLARE_SQLDRIVER_PRIVATE(QPSQLDriver)
using QSqlResultPrivate::QSqlResultPrivate;
- QString fieldSerial(qsizetype i) const override { return u'$' + QString::number(i + 1); }
+ QString fieldSerial(qsizetype i) const override { return QString("$%1"_L1).arg(i + 1); }
void deallocatePreparedStmt();
std::queue<PGresult*> nextResultSets;
@@ -274,7 +276,7 @@ static QSqlError qMakeError(const QString &err, QSqlError::ErrorType type,
const QPSQLDriverPrivate *p, PGresult *result = nullptr)
{
const char *s = PQerrorMessage(p->connection);
- QString msg = p->isUtf8 ? QString::fromUtf8(s) : QString::fromLocal8Bit(s);
+ QString msg = QString::fromUtf8(s);
QString errorCode;
if (result) {
errorCode = QString::fromLatin1(PQresultErrorField(result, PG_DIAG_SQLSTATE));
@@ -382,8 +384,10 @@ void QPSQLResultPrivate::deallocatePreparedStmt()
const QString stmt = QStringLiteral("DEALLOCATE ") + preparedStmtId;
PGresult *result = drv_d_func()->exec(stmt);
- if (PQresultStatus(result) != PGRES_COMMAND_OK)
- qWarning("Unable to free statement: %s", PQerrorMessage(drv_d_func()->connection));
+ if (PQresultStatus(result) != PGRES_COMMAND_OK) {
+ const QString msg = QString::fromUtf8(PQerrorMessage(drv_d_func()->connection));
+ qCWarning(lcPsql, "Unable to free statement: %ls.", qUtf16Printable(msg));
+ }
PQclear(result);
}
preparedStmtId.clear();
@@ -593,7 +597,7 @@ QVariant QPSQLResult::data(int i)
{
Q_D(const QPSQLResult);
if (i >= PQnfields(d->result)) {
- qWarning("QPSQLResult::data: column %d out of range", i);
+ qCWarning(lcPsql, "QPSQLResult::data: column %d out of range.", i);
return QVariant();
}
const int currentRow = isForwardOnly() ? 0 : at();
@@ -606,7 +610,7 @@ QVariant QPSQLResult::data(int i)
case QMetaType::Bool:
return QVariant((bool)(val[0] == 't'));
case QMetaType::QString:
- return d->drv_d_func()->isUtf8 ? QString::fromUtf8(val) : QString::fromLatin1(val);
+ return QString::fromUtf8(val);
case QMetaType::LongLong:
if (val[0] == '-')
return QByteArray::fromRawData(val, qstrlen(val)).toLongLong();
@@ -641,23 +645,21 @@ QVariant QPSQLResult::data(int i)
}
return dbl;
}
- case QMetaType::QDate:
#if QT_CONFIG(datestring)
+ case QMetaType::QDate:
return QVariant(QDate::fromString(QString::fromLatin1(val), Qt::ISODate));
-#else
- return QVariant(QString::fromLatin1(val));
-#endif
case QMetaType::QTime:
-#if QT_CONFIG(datestring)
return QVariant(QTime::fromString(QString::fromLatin1(val), Qt::ISODate));
+ case QMetaType::QDateTime: {
+ QString tzString(QString::fromLatin1(val));
+ if (!tzString.endsWith(u'Z'))
+ tzString.append(u'Z'); // make UTC
+ return QVariant(QDateTime::fromString(tzString, Qt::ISODate));
+ }
#else
- return QVariant(QString::fromLatin1(val));
-#endif
+ case QMetaType::QDate:
+ case QMetaType::QTime:
case QMetaType::QDateTime:
-#if QT_CONFIG(datestring)
- return QVariant(QDateTime::fromString(QString::fromLatin1(val),
- Qt::ISODate).toLocalTime());
-#else
return QVariant(QString::fromLatin1(val));
#endif
case QMetaType::QByteArray: {
@@ -668,7 +670,7 @@ QVariant QPSQLResult::data(int i)
return QVariant(ba);
}
default:
- qWarning("QPSQLResult::data: unknown data type");
+ qCWarning(lcPsql, "QPSQLResult::data: unhandled data type %d.", type.id());
}
return QVariant();
}
@@ -747,10 +749,7 @@ QSqlRecord QPSQLResult::record() const
int count = PQnfields(d->result);
QSqlField f;
for (int i = 0; i < count; ++i) {
- if (d->drv_d_func()->isUtf8)
- f.setName(QString::fromUtf8(PQfname(d->result, i)));
- else
- f.setName(QString::fromLocal8Bit(PQfname(d->result, i)));
+ f.setName(QString::fromUtf8(PQfname(d->result, i)));
const int tableOid = PQftable(d->result, i);
// WARNING: We cannot execute any other SQL queries on
// the same db connection while forward-only mode is active
@@ -801,7 +800,6 @@ QSqlRecord QPSQLResult::record() const
f.setLength(len);
f.setPrecision(precision);
- f.setSqlType(ptype);
info.append(f);
}
return info;
@@ -918,7 +916,7 @@ void QPSQLDriverPrivate::setDatestyle()
PGresult *result = exec("SET DATESTYLE TO 'ISO'");
int status = PQresultStatus(result);
if (status != PGRES_COMMAND_OK)
- qWarning("%s", PQerrorMessage(connection));
+ qCWarning(lcPsql) << QString::fromUtf8(PQerrorMessage(connection));
PQclear(result);
}
@@ -931,11 +929,20 @@ void QPSQLDriverPrivate::setByteaOutput()
PGresult *result = exec("SET bytea_output TO escape");
int status = PQresultStatus(result);
if (status != PGRES_COMMAND_OK)
- qWarning("%s", PQerrorMessage(connection));
+ qCWarning(lcPsql) << QString::fromUtf8(PQerrorMessage(connection));
PQclear(result);
}
}
+void QPSQLDriverPrivate::setUtcTimeZone()
+{
+ PGresult *result = exec("SET TIME ZONE 'UTC'");
+ int status = PQresultStatus(result);
+ if (status != PGRES_COMMAND_OK)
+ qCWarning(lcPsql) << QString::fromUtf8(PQerrorMessage(connection));
+ PQclear(result);
+}
+
void QPSQLDriverPrivate::detectBackslashEscape()
{
// standard_conforming_strings option introduced in 8.2
@@ -1069,16 +1076,16 @@ QPSQLDriver::Protocol QPSQLDriverPrivate::getPSQLVersion()
if (serverVersion == QPSQLDriver::VersionUnknown) {
serverVersion = clientVersion;
if (serverVersion != QPSQLDriver::VersionUnknown)
- qWarning("The server version of this PostgreSQL is unknown, falling back to the client version.");
+ qCWarning(lcPsql, "The server version of this PostgreSQL is unknown, "
+ "falling back to the client version.");
}
// Keep the old behavior unchanged
if (serverVersion == QPSQLDriver::VersionUnknown)
serverVersion = QPSQLDriver::Version6;
- if (serverVersion < QPSQLDriver::Version7_3) {
- qWarning("This version of PostgreSQL is not supported and may not work.");
- }
+ if (serverVersion < QPSQLDriver::Version7_3)
+ qCWarning(lcPsql, "This version of PostgreSQL is not supported and may not work.");
return serverVersion;
}
@@ -1104,8 +1111,7 @@ QPSQLDriver::QPSQLDriver(PGconn *conn, QObject *parent)
QPSQLDriver::~QPSQLDriver()
{
Q_D(QPSQLDriver);
- if (d->connection)
- PQfinish(d->connection);
+ PQfinish(d->connection);
}
QVariant QPSQLDriver::handle() const
@@ -1125,6 +1131,7 @@ bool QPSQLDriver::hasFeature(DriverFeature f) const
case EventNotifications:
case MultipleResultSets:
case BLOB:
+ case Unicode:
return true;
case PreparedQueries:
case PositionalPlaceholders:
@@ -1135,8 +1142,6 @@ bool QPSQLDriver::hasFeature(DriverFeature f) const
case FinishQuery:
case CancelQuery:
return false;
- case Unicode:
- return d->isUtf8;
}
return false;
}
@@ -1194,9 +1199,16 @@ bool QPSQLDriver::open(const QString &db,
d->pro = d->getPSQLVersion();
d->detectBackslashEscape();
- d->isUtf8 = d->setEncodingUtf8();
+ if (!d->setEncodingUtf8()) {
+ setLastError(qMakeError(tr("Unable to set client encoding to 'UNICODE'"), QSqlError::ConnectionError, d));
+ setOpenError(true);
+ PQfinish(d->connection);
+ d->connection = nullptr;
+ return false;
+ }
d->setDatestyle();
d->setByteaOutput();
+ d->setUtcTimeZone();
setOpen(true);
setOpenError(false);
@@ -1209,13 +1221,12 @@ void QPSQLDriver::close()
d->seid.clear();
if (d->sn) {
- disconnect(d->sn, SIGNAL(activated(QSocketDescriptor)), this, SLOT(_q_handleNotification()));
+ disconnect(d->sn, &QSocketNotifier::activated, this, &QPSQLDriver::_q_handleNotification);
delete d->sn;
d->sn = nullptr;
}
- if (d->connection)
- PQfinish(d->connection);
+ PQfinish(d->connection);
d->connection = nullptr;
setOpen(false);
setOpenError(false);
@@ -1230,7 +1241,7 @@ bool QPSQLDriver::beginTransaction()
{
Q_D(QPSQLDriver);
if (!isOpen()) {
- qWarning("QPSQLDriver::beginTransaction: Database not open");
+ qCWarning(lcPsql, "QPSQLDriver::beginTransaction: Database not open.");
return false;
}
PGresult *res = d->exec("BEGIN");
@@ -1248,7 +1259,7 @@ bool QPSQLDriver::commitTransaction()
{
Q_D(QPSQLDriver);
if (!isOpen()) {
- qWarning("QPSQLDriver::commitTransaction: Database not open");
+ qCWarning(lcPsql, "QPSQLDriver::commitTransaction: Database not open.");
return false;
}
PGresult *res = d->exec("COMMIT");
@@ -1277,7 +1288,7 @@ bool QPSQLDriver::rollbackTransaction()
{
Q_D(QPSQLDriver);
if (!isOpen()) {
- qWarning("QPSQLDriver::rollbackTransaction: Database not open");
+ qCWarning(lcPsql, "QPSQLDriver::rollbackTransaction: Database not open.");
return false;
}
PGresult *res = d->exec("ROLLBACK");
@@ -1414,7 +1425,6 @@ QSqlRecord QPSQLDriver::record(const QString &tablename) const
f.setLength(len);
f.setPrecision(precision);
f.setDefaultValue(defVal);
- f.setSqlType(query.value(1).toInt());
info.append(f);
}
@@ -1439,32 +1449,28 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const
r = nullStr();
} else {
switch (field.metaType().id()) {
- case QMetaType::QDateTime:
-#if QT_CONFIG(datestring)
- if (field.value().toDateTime().isValid()) {
+ case QMetaType::QDateTime: {
+ const auto dt = field.value().toDateTime();
+ if (dt.isValid()) {
// we force the value to be considered with a timezone information, and we force it to be UTC
// this is safe since postgresql stores only the UTC value and not the timezone offset (only used
// while parsing), so we have correct behavior in both case of with timezone and without tz
r = QStringLiteral("TIMESTAMP WITH TIME ZONE ") + u'\'' +
- QLocale::c().toString(field.value().toDateTime().toUTC(), u"yyyy-MM-ddThh:mm:ss.zzz") +
+ QLocale::c().toString(dt.toUTC(), u"yyyy-MM-ddThh:mm:ss.zzz") +
u'Z' + u'\'';
} else {
r = nullStr();
}
-#else
- r = nullStr();
-#endif // datestring
break;
- case QMetaType::QTime:
-#if QT_CONFIG(datestring)
- if (field.value().toTime().isValid()) {
- r = u'\'' + field.value().toTime().toString(u"hh:mm:ss.zzz") + u'\'';
- } else
-#endif
- {
+ }
+ case QMetaType::QTime: {
+ const auto t = field.value().toTime();
+ if (t.isValid())
+ r = u'\'' + QLocale::c().toString(t, u"hh:mm:ss.zzz") + u'\'';
+ else
r = nullStr();
- }
break;
+ }
case QMetaType::QString:
r = QSqlDriver::formatValue(field, trimStrings);
if (d->hasBackslashEscape)
@@ -1538,7 +1544,7 @@ bool QPSQLDriver::subscribeToNotification(const QString &name)
{
Q_D(QPSQLDriver);
if (!isOpen()) {
- qWarning("QPSQLDriver::subscribeToNotificationImplementation: database not open.");
+ qCWarning(lcPsql, "QPSQLDriver::subscribeToNotification: Database not open.");
return false;
}
@@ -1563,11 +1569,12 @@ bool QPSQLDriver::subscribeToNotification(const QString &name)
PQclear(result);
if (!d->sn) {
- d->sn = new QSocketNotifier(socket, QSocketNotifier::Read);
- connect(d->sn, SIGNAL(activated(QSocketDescriptor)), this, SLOT(_q_handleNotification()));
+ d->sn = new QSocketNotifier(socket, QSocketNotifier::Read, this);
+ connect(d->sn, &QSocketNotifier::activated, this, &QPSQLDriver::_q_handleNotification);
}
} else {
- qWarning("QPSQLDriver::subscribeToNotificationImplementation: PQsocket didn't return a valid socket to listen on");
+ qCWarning(lcPsql, "QPSQLDriver::subscribeToNotificationImplementation: "
+ "PQsocket didn't return a valid socket to listen on.");
return false;
}
@@ -1578,13 +1585,13 @@ bool QPSQLDriver::unsubscribeFromNotification(const QString &name)
{
Q_D(QPSQLDriver);
if (!isOpen()) {
- qWarning("QPSQLDriver::unsubscribeFromNotificationImplementation: database not open.");
+ qCWarning(lcPsql, "QPSQLDriver::unsubscribeFromNotification: Database not open.");
return false;
}
if (!d->seid.contains(name)) {
- qWarning("QPSQLDriver::unsubscribeFromNotificationImplementation: not subscribed to '%s'.",
- qPrintable(name));
+ qCWarning(lcPsql, "QPSQLDriver::unsubscribeFromNotification: not subscribed to '%ls'.",
+ qUtf16Printable(name));
return false;
}
@@ -1600,7 +1607,7 @@ bool QPSQLDriver::unsubscribeFromNotification(const QString &name)
d->seid.removeAll(name);
if (d->seid.isEmpty()) {
- disconnect(d->sn, SIGNAL(activated(QSocketDescriptor)), this, SLOT(_q_handleNotification()));
+ disconnect(d->sn, &QSocketNotifier::activated, this, &QPSQLDriver::_q_handleNotification);
delete d->sn;
d->sn = nullptr;
}
@@ -1627,17 +1634,19 @@ void QPSQLDriver::_q_handleNotification()
QString payload;
#if defined PG_VERSION_NUM && PG_VERSION_NUM-0 >= 70400
if (notify->extra)
- payload = d->isUtf8 ? QString::fromUtf8(notify->extra) : QString::fromLatin1(notify->extra);
+ payload = QString::fromUtf8(notify->extra);
#endif
QSqlDriver::NotificationSource source = (notify->be_pid == PQbackendPID(d->connection)) ? QSqlDriver::SelfSource : QSqlDriver::OtherSource;
emit notification(name, source, payload);
}
else
- qWarning("QPSQLDriver: received notification for '%s' which isn't subscribed to.",
- qPrintable(name));
+ qCWarning(lcPsql, "QPSQLDriver: received notification for '%ls' which isn't subscribed to.",
+ qUtf16Printable(name));
qPQfreemem(notify);
}
}
QT_END_NAMESPACE
+
+#include "moc_qsql_psql_p.cpp"
diff --git a/src/plugins/sqldrivers/qt_cmdline.cmake b/src/plugins/sqldrivers/qt_cmdline.cmake
index 945de0e63b..2bb1fc64eb 100644
--- a/src/plugins/sqldrivers/qt_cmdline.cmake
+++ b/src/plugins/sqldrivers/qt_cmdline.cmake
@@ -3,7 +3,7 @@
qt_commandline_option(mysql_config TYPE string)
qt_commandline_option(psql_config TYPE string)
-qt_commandline_option(sqlite TYPE enum NAME system-sqlite MAPPING qt no system yes)
+qt_commandline_option(sqlite CONTROLS_FEATURE TYPE enum NAME system-sqlite MAPPING qt no system yes)
qt_commandline_option(sql-db2 TYPE boolean)
qt_commandline_option(sql-ibase TYPE boolean)
qt_commandline_option(sql-mysql TYPE boolean)
diff --git a/src/plugins/sqldrivers/sqlite/CMakeLists.txt b/src/plugins/sqldrivers/sqlite/CMakeLists.txt
index add9dff9fd..4203a5c437 100644
--- a/src/plugins/sqldrivers/sqlite/CMakeLists.txt
+++ b/src/plugins/sqldrivers/sqlite/CMakeLists.txt
@@ -10,10 +10,12 @@ qt_internal_add_plugin(QSQLiteDriverPlugin
PLUGIN_TYPE sqldrivers
SOURCES
qsql_sqlite.cpp qsql_sqlite_p.h
+ qsql_sqlite_vfs.cpp qsql_sqlite_vfs_p.h
smain.cpp
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
+ QT_NO_CONTEXTLESS_CONNECT
LIBRARIES
Qt::Core
Qt::CorePrivate
@@ -37,6 +39,11 @@ if(QT_FEATURE_system_sqlite)
qt_internal_force_macos_intel_arch(QSQLiteDriverPlugin)
endif()
+qt_internal_extend_target(QSQLiteDriverPlugin CONDITION NOT QT_FEATURE_system_sqlite AND VXWORKS
+ DEFINES
+ SQLITE_OS_UNIX=1
+)
+
qt_internal_extend_target(QSQLiteDriverPlugin CONDITION NOT QT_FEATURE_system_sqlite
SOURCES
../../../3rdparty/sqlite/sqlite3.c
diff --git a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp
index 2933c68a9d..c574772fd7 100644
--- a/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp
+++ b/src/plugins/sqldrivers/sqlite/qsql_sqlite.cpp
@@ -7,6 +7,7 @@
#include <qdatetime.h>
#include <qdebug.h>
#include <qlist.h>
+#include <qloggingcategory.h>
#include <qsqlerror.h>
#include <qsqlfield.h>
#include <qsqlindex.h>
@@ -38,23 +39,9 @@ Q_DECLARE_METATYPE(sqlite3_stmt*)
QT_BEGIN_NAMESPACE
-using namespace Qt::StringLiterals;
+static Q_LOGGING_CATEGORY(lcSqlite, "qt.sql.sqlite")
-static QString _q_escapeIdentifier(const QString &identifier, QSqlDriver::IdentifierType type)
-{
- QString res = identifier;
- // If it contains [ and ] then we assume it to be escaped properly already as this indicates
- // the syntax is exactly how it should be
- if (identifier.contains(u'[') && identifier.contains(u']'))
- return res;
- if (!identifier.isEmpty() && !identifier.startsWith(u'"') && !identifier.endsWith(u'"')) {
- res.replace(u'"', "\"\""_L1);
- if (type == QSqlDriver::TableName)
- res.replace(u'.', "\".\""_L1);
- res = u'"' + res + u'"';
- }
- return res;
-}
+using namespace Qt::StringLiterals;
static int qGetColumnType(const QString &tpName)
{
@@ -114,11 +101,64 @@ class QSQLiteDriverPrivate : public QSqlDriverPrivate
public:
inline QSQLiteDriverPrivate() : QSqlDriverPrivate(QSqlDriver::SQLite) {}
+ bool isIdentifierEscaped(QStringView identifier) const;
+ QSqlIndex getTableInfo(QSqlQuery &query, const QString &tableName,
+ bool onlyPIndex = false) const;
+
sqlite3 *access = nullptr;
QList<QSQLiteResult *> results;
QStringList notificationid;
};
+bool QSQLiteDriverPrivate::isIdentifierEscaped(QStringView identifier) const
+{
+ return identifier.size() > 2
+ && ((identifier.startsWith(u'"') && identifier.endsWith(u'"'))
+ || (identifier.startsWith(u'`') && identifier.endsWith(u'`'))
+ || (identifier.startsWith(u'[') && identifier.endsWith(u']')));
+}
+
+QSqlIndex QSQLiteDriverPrivate::getTableInfo(QSqlQuery &query, const QString &tableName,
+ bool onlyPIndex) const
+{
+ Q_Q(const QSQLiteDriver);
+ QString schema;
+ QString table = q->escapeIdentifier(tableName, QSqlDriver::TableName);
+ const auto indexOfSeparator = table.indexOf(u'.');
+ if (indexOfSeparator > -1) {
+ auto leftName = QStringView{table}.first(indexOfSeparator);
+ auto rightName = QStringView{table}.sliced(indexOfSeparator + 1);
+ if (isIdentifierEscaped(leftName) && isIdentifierEscaped(rightName)) {
+ schema = leftName.toString() + u'.';
+ table = rightName.toString();
+ }
+ }
+
+ query.exec("PRAGMA "_L1 + schema + "table_info ("_L1 + table + u')');
+ QSqlIndex ind;
+ while (query.next()) {
+ bool isPk = query.value(5).toInt();
+ if (onlyPIndex && !isPk)
+ continue;
+ QString typeName = query.value(2).toString().toLower();
+ QString defVal = query.value(4).toString();
+ if (!defVal.isEmpty() && defVal.at(0) == u'\'') {
+ const int end = defVal.lastIndexOf(u'\'');
+ if (end > 0)
+ defVal = defVal.mid(1, end - 1);
+ }
+
+ QSqlField fld(query.value(1).toString(), QMetaType(qGetColumnType(typeName)), tableName);
+ if (isPk && (typeName == "integer"_L1))
+ // INTEGER PRIMARY KEY fields are auto-generated in sqlite
+ // INT PRIMARY KEY is not the same as INTEGER PRIMARY KEY!
+ fld.setAutoValue(true);
+ fld.setRequired(query.value(3).toInt() != 0);
+ fld.setDefaultValue(defVal);
+ ind.append(fld);
+ }
+ return ind;
+}
class QSQLiteResultPrivate : public QSqlCachedResultPrivate
{
@@ -210,7 +250,6 @@ void QSQLiteResultPrivate::initColumns(bool emptyResultset)
}
QSqlField fld(colName, QMetaType(fieldType), tableName);
- fld.setSqlType(stp);
rInf.append(fld);
}
}
@@ -625,6 +664,30 @@ static void _q_regexp_cleanup(void *cache)
}
#endif
+static void _q_lower(sqlite3_context* context, int argc, sqlite3_value** argv)
+{
+ if (Q_UNLIKELY(argc != 1)) {
+ sqlite3_result_text(context, nullptr, 0, nullptr);
+ return;
+ }
+ const QString lower = QString::fromUtf8(
+ reinterpret_cast<const char*>(sqlite3_value_text(argv[0]))).toLower();
+ const QByteArray ba = lower.toUtf8();
+ sqlite3_result_text(context, ba.data(), ba.size(), SQLITE_TRANSIENT);
+}
+
+static void _q_upper(sqlite3_context* context, int argc, sqlite3_value** argv)
+{
+ if (Q_UNLIKELY(argc != 1)) {
+ sqlite3_result_text(context, nullptr, 0, nullptr);
+ return;
+ }
+ const QString upper = QString::fromUtf8(
+ reinterpret_cast<const char*>(sqlite3_value_text(argv[0]))).toUpper();
+ const QByteArray ba = upper.toUtf8();
+ sqlite3_result_text(context, ba.data(), ba.size(), SQLITE_TRANSIENT);
+}
+
QSQLiteDriver::QSQLiteDriver(QObject * parent)
: QSqlDriver(*new QSQLiteDriverPrivate, parent)
{
@@ -691,13 +754,16 @@ bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, c
bool openReadOnlyOption = false;
bool openUriOption = false;
bool useExtendedResultCodes = true;
+ bool useQtVfs = false;
+ bool useQtCaseFolding = false;
+ bool openNoFollow = false;
#if QT_CONFIG(regularexpression)
static const auto regexpConnectOption = "QSQLITE_ENABLE_REGEXP"_L1;
bool defineRegexp = false;
int regexpCacheSize = 25;
#endif
- const auto opts = QStringView{conOpts}.split(u';');
+ const auto opts = QStringView{conOpts}.split(u';', Qt::SkipEmptyParts);
for (auto option : opts) {
option = option.trimmed();
if (option.startsWith("QSQLITE_BUSY_TIMEOUT"_L1)) {
@@ -708,6 +774,8 @@ bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, c
if (ok)
timeOut = nt;
}
+ } else if (option == "QSQLITE_USE_QT_VFS"_L1) {
+ useQtVfs = true;
} else if (option == "QSQLITE_OPEN_READONLY"_L1) {
openReadOnlyOption = true;
} else if (option == "QSQLITE_OPEN_URI"_L1) {
@@ -716,6 +784,10 @@ bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, c
sharedCache = true;
} else if (option == "QSQLITE_NO_USE_EXTENDED_RESULT_CODES"_L1) {
useExtendedResultCodes = false;
+ } else if (option == "QSQLITE_ENABLE_NON_ASCII_CASE_FOLDING"_L1) {
+ useQtCaseFolding = true;
+ } else if (option == "QSQLITE_OPEN_NOFOLLOW"_L1) {
+ openNoFollow = true;
}
#if QT_CONFIG(regularexpression)
else if (option.startsWith(regexpConnectOption)) {
@@ -733,16 +805,25 @@ bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, c
}
}
#endif
+ else
+ qCWarning(lcSqlite, "Unsupported option '%ls'", qUtf16Printable(option.toString()));
}
int openMode = (openReadOnlyOption ? SQLITE_OPEN_READONLY : (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE));
openMode |= (sharedCache ? SQLITE_OPEN_SHAREDCACHE : SQLITE_OPEN_PRIVATECACHE);
if (openUriOption)
openMode |= SQLITE_OPEN_URI;
+ if (openNoFollow) {
+#if defined(SQLITE_OPEN_NOFOLLOW)
+ openMode |= SQLITE_OPEN_NOFOLLOW;
+#else
+ qCWarning(lcSqlite, "SQLITE_OPEN_NOFOLLOW not supported with the SQLite version %s", sqlite3_libversion());
+#endif
+ }
openMode |= SQLITE_OPEN_NOMUTEX;
- const int res = sqlite3_open_v2(db.toUtf8().constData(), &d->access, openMode, nullptr);
+ const int res = sqlite3_open_v2(db.toUtf8().constData(), &d->access, openMode, useQtVfs ? "QtVFS" : nullptr);
if (res == SQLITE_OK) {
sqlite3_busy_timeout(d->access, timeOut);
@@ -757,6 +838,12 @@ bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, c
nullptr, &_q_regexp_cleanup);
}
#endif
+ if (useQtCaseFolding) {
+ sqlite3_create_function_v2(d->access, "lower", 1, SQLITE_UTF8, nullptr,
+ &_q_lower, nullptr, nullptr, nullptr);
+ sqlite3_create_function_v2(d->access, "upper", 1, SQLITE_UTF8, nullptr,
+ &_q_upper, nullptr, nullptr, nullptr);
+ }
return true;
} else {
setLastError(qMakeError(d->access, tr("Error opening database"),
@@ -877,79 +964,26 @@ QStringList QSQLiteDriver::tables(QSql::TableType type) const
return res;
}
-static QSqlIndex qGetTableInfo(QSqlQuery &q, const QString &tableName, bool onlyPIndex = false)
-{
- QString schema;
- QString table(tableName);
- const qsizetype indexOfSeparator = tableName.indexOf(u'.');
- if (indexOfSeparator > -1) {
- const qsizetype indexOfCloseBracket = tableName.indexOf(u']');
- if (indexOfCloseBracket != tableName.size() - 1) {
- // Handles a case like databaseName.tableName
- schema = tableName.left(indexOfSeparator + 1);
- table = tableName.mid(indexOfSeparator + 1);
- } else {
- const qsizetype indexOfOpenBracket = tableName.lastIndexOf(u'[', indexOfCloseBracket);
- if (indexOfOpenBracket > 0) {
- // Handles a case like databaseName.[tableName]
- schema = tableName.left(indexOfOpenBracket);
- table = tableName.mid(indexOfOpenBracket);
- }
- }
- }
- q.exec("PRAGMA "_L1 + schema + "table_info ("_L1 +
- _q_escapeIdentifier(table, QSqlDriver::TableName) + u')');
- QSqlIndex ind;
- while (q.next()) {
- bool isPk = q.value(5).toInt();
- if (onlyPIndex && !isPk)
- continue;
- QString typeName = q.value(2).toString().toLower();
- QString defVal = q.value(4).toString();
- if (!defVal.isEmpty() && defVal.at(0) == u'\'') {
- const int end = defVal.lastIndexOf(u'\'');
- if (end > 0)
- defVal = defVal.mid(1, end - 1);
- }
-
- QSqlField fld(q.value(1).toString(), QMetaType(qGetColumnType(typeName)), tableName);
- if (isPk && (typeName == "integer"_L1))
- // INTEGER PRIMARY KEY fields are auto-generated in sqlite
- // INT PRIMARY KEY is not the same as INTEGER PRIMARY KEY!
- fld.setAutoValue(true);
- fld.setRequired(q.value(3).toInt() != 0);
- fld.setDefaultValue(defVal);
- ind.append(fld);
- }
- return ind;
-}
-
-QSqlIndex QSQLiteDriver::primaryIndex(const QString &tblname) const
+QSqlIndex QSQLiteDriver::primaryIndex(const QString &tablename) const
{
+ Q_D(const QSQLiteDriver);
if (!isOpen())
return QSqlIndex();
- QString table = tblname;
- if (isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
-
QSqlQuery q(createResult());
q.setForwardOnly(true);
- return qGetTableInfo(q, table, true);
+ return d->getTableInfo(q, tablename, true);
}
-QSqlRecord QSQLiteDriver::record(const QString &tbl) const
+QSqlRecord QSQLiteDriver::record(const QString &tablename) const
{
+ Q_D(const QSQLiteDriver);
if (!isOpen())
return QSqlRecord();
- QString table = tbl;
- if (isIdentifierEscaped(table, QSqlDriver::TableName))
- table = stripDelimiters(table, QSqlDriver::TableName);
-
QSqlQuery q(createResult());
q.setForwardOnly(true);
- return qGetTableInfo(q, table);
+ return d->getTableInfo(q, tablename);
}
QVariant QSQLiteDriver::handle() const
@@ -960,7 +994,52 @@ QVariant QSQLiteDriver::handle() const
QString QSQLiteDriver::escapeIdentifier(const QString &identifier, IdentifierType type) const
{
- return _q_escapeIdentifier(identifier, type);
+ Q_D(const QSQLiteDriver);
+ if (identifier.isEmpty() || isIdentifierEscaped(identifier, type))
+ return identifier;
+
+ const auto indexOfSeparator = identifier.indexOf(u'.');
+ if (indexOfSeparator > -1) {
+ auto leftName = QStringView{identifier}.first(indexOfSeparator);
+ auto rightName = QStringView{identifier}.sliced(indexOfSeparator + 1);
+ const QStringView leftEnclose = d->isIdentifierEscaped(leftName) ? u"" : u"\"";
+ const QStringView rightEnclose = d->isIdentifierEscaped(rightName) ? u"" : u"\"";
+ if (leftEnclose.isEmpty() || rightEnclose.isEmpty())
+ return (leftEnclose + leftName + leftEnclose + u'.' + rightEnclose + rightName
+ + rightEnclose);
+ }
+ return u'"' + identifier + u'"';
+}
+
+bool QSQLiteDriver::isIdentifierEscaped(const QString &identifier, IdentifierType type) const
+{
+ Q_D(const QSQLiteDriver);
+ Q_UNUSED(type);
+ return d->isIdentifierEscaped(QStringView{identifier});
+}
+
+QString QSQLiteDriver::stripDelimiters(const QString &identifier, IdentifierType type) const
+{
+ Q_D(const QSQLiteDriver);
+ const auto indexOfSeparator = identifier.indexOf(u'.');
+ if (indexOfSeparator > -1) {
+ auto leftName = QStringView{identifier}.first(indexOfSeparator);
+ auto rightName = QStringView{identifier}.sliced(indexOfSeparator + 1);
+ const auto leftEscaped = d->isIdentifierEscaped(leftName);
+ const auto rightEscaped = d->isIdentifierEscaped(rightName);
+ if (leftEscaped || rightEscaped) {
+ if (leftEscaped)
+ leftName = leftName.sliced(1).chopped(1);
+ if (rightEscaped)
+ rightName = rightName.sliced(1).chopped(1);
+ return leftName + u'.' + rightName;
+ }
+ }
+
+ if (isIdentifierEscaped(identifier, type))
+ return identifier.mid(1, identifier.size() - 2);
+
+ return identifier;
}
static void handle_sqlite_callback(void *qobj,int aoperation, char const *adbname, char const *atablename,
@@ -979,12 +1058,13 @@ bool QSQLiteDriver::subscribeToNotification(const QString &name)
{
Q_D(QSQLiteDriver);
if (!isOpen()) {
- qWarning("Database not open.");
+ qCWarning(lcSqlite, "QSQLiteDriver::subscribeToNotification: Database not open.");
return false;
}
if (d->notificationid.contains(name)) {
- qWarning("Already subscribing to '%s'.", qPrintable(name));
+ qCWarning(lcSqlite, "QSQLiteDriver::subscribeToNotification: Already subscribing to '%ls'.",
+ qUtf16Printable(name));
return false;
}
@@ -1000,12 +1080,13 @@ bool QSQLiteDriver::unsubscribeFromNotification(const QString &name)
{
Q_D(QSQLiteDriver);
if (!isOpen()) {
- qWarning("Database not open.");
+ qCWarning(lcSqlite, "QSQLiteDriver::unsubscribeFromNotification: Database not open.");
return false;
}
if (!d->notificationid.contains(name)) {
- qWarning("Not subscribed to '%s'.", qPrintable(name));
+ qCWarning(lcSqlite, "QSQLiteDriver::unsubscribeFromNotification: Not subscribed to '%ls'.",
+ qUtf16Printable(name));
return false;
}
diff --git a/src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h b/src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h
index 53ffb45f96..db6b76cb69 100644
--- a/src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h
+++ b/src/plugins/sqldrivers/sqlite/qsql_sqlite_p.h
@@ -54,9 +54,12 @@ public:
QStringList tables(QSql::TableType) const override;
QSqlRecord record(const QString& tablename) const override;
- QSqlIndex primaryIndex(const QString &table) const override;
+ QSqlIndex primaryIndex(const QString &tablename) const override;
QVariant handle() const override;
- QString escapeIdentifier(const QString &identifier, IdentifierType) const override;
+
+ QString escapeIdentifier(const QString &identifier, IdentifierType type) const override;
+ bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const override;
+ QString stripDelimiters(const QString &identifier, IdentifierType type) const override;
bool subscribeToNotification(const QString &name) override;
bool unsubscribeFromNotification(const QString &name) override;
diff --git a/src/plugins/sqldrivers/sqlite/qsql_sqlite_vfs.cpp b/src/plugins/sqldrivers/sqlite/qsql_sqlite_vfs.cpp
new file mode 100644
index 0000000000..bbba3cd14f
--- /dev/null
+++ b/src/plugins/sqldrivers/sqlite/qsql_sqlite_vfs.cpp
@@ -0,0 +1,258 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qsql_sqlite_vfs_p.h"
+
+#include <QFile>
+
+#include <limits.h> // defines PATH_MAX on unix
+#include <sqlite3.h>
+#include <stdio.h> // defines FILENAME_MAX everywhere
+
+#ifndef PATH_MAX
+# define PATH_MAX FILENAME_MAX
+#endif
+#if SQLITE_VERSION_NUMBER < 3040000
+typedef const char *sqlite3_filename;
+#endif
+
+namespace {
+struct Vfs : sqlite3_vfs {
+ sqlite3_vfs *pVfs;
+ sqlite3_io_methods ioMethods;
+};
+
+struct File : sqlite3_file {
+ class QtFile : public QFile {
+ public:
+ QtFile(const QString &name, bool removeOnClose)
+ : QFile(name)
+ , removeOnClose(removeOnClose)
+ {}
+
+ ~QtFile() override
+ {
+ if (removeOnClose)
+ remove();
+ }
+ private:
+ bool removeOnClose;
+ };
+ QtFile *pFile;
+};
+
+
+int xClose(sqlite3_file *sfile)
+{
+ auto file = static_cast<File *>(sfile);
+ delete file->pFile;
+ file->pFile = nullptr;
+ return SQLITE_OK;
+}
+
+int xRead(sqlite3_file *sfile, void *ptr, int iAmt, sqlite3_int64 iOfst)
+{
+ auto file = static_cast<File *>(sfile);
+ if (!file->pFile->seek(iOfst))
+ return SQLITE_IOERR_READ;
+
+ auto sz = file->pFile->read(static_cast<char *>(ptr), iAmt);
+ if (sz < iAmt) {
+ memset(static_cast<char *>(ptr) + sz, 0, size_t(iAmt - sz));
+ return SQLITE_IOERR_SHORT_READ;
+ }
+ return SQLITE_OK;
+}
+
+int xWrite(sqlite3_file *sfile, const void *data, int iAmt, sqlite3_int64 iOfst)
+{
+ auto file = static_cast<File *>(sfile);
+ if (!file->pFile->seek(iOfst))
+ return SQLITE_IOERR_SEEK;
+ return file->pFile->write(reinterpret_cast<const char*>(data), iAmt) == iAmt ? SQLITE_OK : SQLITE_IOERR_WRITE;
+}
+
+int xTruncate(sqlite3_file *sfile, sqlite3_int64 size)
+{
+ auto file = static_cast<File *>(sfile);
+ return file->pFile->resize(size) ? SQLITE_OK : SQLITE_IOERR_TRUNCATE;
+}
+
+int xSync(sqlite3_file *sfile, int /*flags*/)
+{
+ static_cast<File *>(sfile)->pFile->flush();
+ return SQLITE_OK;
+}
+
+int xFileSize(sqlite3_file *sfile, sqlite3_int64 *pSize)
+{
+ auto file = static_cast<File *>(sfile);
+ *pSize = file->pFile->size();
+ return SQLITE_OK;
+}
+
+// No lock/unlock for QFile, QLockFile doesn't work for me
+
+int xLock(sqlite3_file *, int) { return SQLITE_OK; }
+
+int xUnlock(sqlite3_file *, int) { return SQLITE_OK; }
+
+int xCheckReservedLock(sqlite3_file *, int *pResOut)
+{
+ *pResOut = 0;
+ return SQLITE_OK;
+}
+
+int xFileControl(sqlite3_file *, int, void *) { return SQLITE_NOTFOUND; }
+
+int xSectorSize(sqlite3_file *)
+{
+ return 4096;
+}
+
+int xDeviceCharacteristics(sqlite3_file *)
+{
+ return 0; // no SQLITE_IOCAP_XXX
+}
+
+int xOpen(sqlite3_vfs *svfs, sqlite3_filename zName, sqlite3_file *sfile,
+ int flags, int *pOutFlags)
+{
+ auto vfs = static_cast<Vfs *>(svfs);
+ auto file = static_cast<File *>(sfile);
+ memset(file, 0, sizeof(File));
+ QIODeviceBase::OpenMode mode = QIODeviceBase::NotOpen;
+ if (!zName || (flags & SQLITE_OPEN_MEMORY))
+ return SQLITE_PERM;
+ if ((flags & SQLITE_OPEN_READONLY) &&
+ !(flags & SQLITE_OPEN_READWRITE) &&
+ !(flags & SQLITE_OPEN_CREATE) &&
+ !(flags & SQLITE_OPEN_DELETEONCLOSE)) {
+ mode |= QIODeviceBase::OpenModeFlag::ReadOnly;
+ } else {
+ /*
+ ** ^The [SQLITE_OPEN_EXCLUSIVE] flag is always used in conjunction
+ ** with the [SQLITE_OPEN_CREATE] flag, which are both directly
+ ** analogous to the O_EXCL and O_CREAT flags of the POSIX open()
+ ** API. The SQLITE_OPEN_EXCLUSIVE flag, when paired with the
+ ** SQLITE_OPEN_CREATE, is used to indicate that file should always
+ ** be created, and that it is an error if it already exists.
+ ** It is <i>not</i> used to indicate the file should be opened
+ ** for exclusive access.
+ */
+ if ((flags & SQLITE_OPEN_CREATE) && (flags & SQLITE_OPEN_EXCLUSIVE))
+ mode |= QIODeviceBase::OpenModeFlag::NewOnly;
+
+ if (flags & SQLITE_OPEN_READWRITE)
+ mode |= QIODeviceBase::OpenModeFlag::ReadWrite;
+ }
+
+ file->pMethods = &vfs->ioMethods;
+ file->pFile = new File::QtFile(QString::fromUtf8(zName), bool(flags & SQLITE_OPEN_DELETEONCLOSE));
+ if (!file->pFile->open(mode))
+ return SQLITE_CANTOPEN;
+ if (pOutFlags)
+ *pOutFlags = flags;
+
+ return SQLITE_OK;
+}
+
+int xDelete(sqlite3_vfs *, const char *zName, int)
+{
+ return QFile::remove(QString::fromUtf8(zName)) ? SQLITE_OK : SQLITE_ERROR;
+}
+
+int xAccess(sqlite3_vfs */*svfs*/, const char *zName, int flags, int *pResOut)
+{
+ *pResOut = 0;
+ switch (flags) {
+ case SQLITE_ACCESS_EXISTS:
+ case SQLITE_ACCESS_READ:
+ *pResOut = QFile::exists(QString::fromUtf8(zName));
+ break;
+ default:
+ break;
+ }
+ return SQLITE_OK;
+}
+
+int xFullPathname(sqlite3_vfs *, const char *zName, int nOut, char *zOut)
+{
+ if (!zName)
+ return SQLITE_ERROR;
+
+ int i = 0;
+ for (;zName[i] && i < nOut; ++i)
+ zOut[i] = zName[i];
+
+ if (i >= nOut)
+ return SQLITE_ERROR;
+
+ zOut[i] = '\0';
+ return SQLITE_OK;
+}
+
+int xRandomness(sqlite3_vfs *svfs, int nByte, char *zOut)
+{
+ auto vfs = static_cast<Vfs *>(svfs)->pVfs;
+ return vfs->xRandomness(vfs, nByte, zOut);
+}
+
+int xSleep(sqlite3_vfs *svfs, int microseconds)
+{
+ auto vfs = static_cast<Vfs *>(svfs)->pVfs;
+ return vfs->xSleep(vfs, microseconds);
+}
+
+int xCurrentTime(sqlite3_vfs *svfs, double *zOut)
+{
+ auto vfs = static_cast<Vfs *>(svfs)->pVfs;
+ return vfs->xCurrentTime(vfs, zOut);
+}
+
+int xGetLastError(sqlite3_vfs *, int, char *)
+{
+ return 0;
+}
+
+int xCurrentTimeInt64(sqlite3_vfs *svfs, sqlite3_int64 *zOut)
+{
+ auto vfs = static_cast<Vfs *>(svfs)->pVfs;
+ return vfs->xCurrentTimeInt64(vfs, zOut);
+}
+} // namespace {
+
+void register_qt_vfs()
+{
+ static Vfs vfs;
+ memset(&vfs, 0, sizeof(Vfs));
+ vfs.iVersion = 1;
+ vfs.szOsFile = sizeof(File);
+ vfs.mxPathname = PATH_MAX;
+ vfs.zName = "QtVFS";
+ vfs.xOpen = &xOpen;
+ vfs.xDelete = &xDelete;
+ vfs.xAccess = &xAccess;
+ vfs.xFullPathname = &xFullPathname;
+ vfs.xRandomness = &xRandomness;
+ vfs.xSleep = &xSleep;
+ vfs.xCurrentTime = &xCurrentTime;
+ vfs.xGetLastError = &xGetLastError;
+ vfs.xCurrentTimeInt64 = &xCurrentTimeInt64;
+ vfs.pVfs = sqlite3_vfs_find(nullptr);
+ vfs.ioMethods.iVersion = 1;
+ vfs.ioMethods.xClose = &xClose;
+ vfs.ioMethods.xRead = &xRead;
+ vfs.ioMethods.xWrite = &xWrite;
+ vfs.ioMethods.xTruncate = &xTruncate;
+ vfs.ioMethods.xSync = &xSync;
+ vfs.ioMethods.xFileSize = &xFileSize;
+ vfs.ioMethods.xLock = &xLock;
+ vfs.ioMethods.xUnlock = &xUnlock;
+ vfs.ioMethods.xCheckReservedLock = &xCheckReservedLock;
+ vfs.ioMethods.xFileControl = &xFileControl;
+ vfs.ioMethods.xSectorSize = &xSectorSize;
+ vfs.ioMethods.xDeviceCharacteristics = &xDeviceCharacteristics;
+
+ sqlite3_vfs_register(&vfs, 0);
+}
diff --git a/src/plugins/sqldrivers/sqlite/qsql_sqlite_vfs_p.h b/src/plugins/sqldrivers/sqlite/qsql_sqlite_vfs_p.h
new file mode 100644
index 0000000000..56024b3ecb
--- /dev/null
+++ b/src/plugins/sqldrivers/sqlite/qsql_sqlite_vfs_p.h
@@ -0,0 +1,21 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QSQL_SQLITE_VFS_H
+#define QSQL_SQLITE_VFS_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.
+//
+
+void register_qt_vfs();
+
+
+#endif // QSQL_SQLITE_VFS_H
diff --git a/src/plugins/sqldrivers/sqlite/smain.cpp b/src/plugins/sqldrivers/sqlite/smain.cpp
index f84a256bc8..0d201c38d3 100644
--- a/src/plugins/sqldrivers/sqlite/smain.cpp
+++ b/src/plugins/sqldrivers/sqlite/smain.cpp
@@ -4,6 +4,7 @@
#include <qsqldriverplugin.h>
#include <qstringlist.h>
#include "qsql_sqlite_p.h"
+#include "qsql_sqlite_vfs_p.h"
QT_BEGIN_NAMESPACE
@@ -23,6 +24,7 @@ public:
QSQLiteDriverPlugin::QSQLiteDriverPlugin()
: QSqlDriverPlugin()
{
+ register_qt_vfs();
}
QSqlDriver* QSQLiteDriverPlugin::create(const QString &name)
diff --git a/src/plugins/styles/CMakeLists.txt b/src/plugins/styles/CMakeLists.txt
index a16c7c4c9a..b809042c14 100644
--- a/src/plugins/styles/CMakeLists.txt
+++ b/src/plugins/styles/CMakeLists.txt
@@ -8,5 +8,5 @@ if(QT_FEATURE_style_mac)
add_subdirectory(mac)
endif()
if(QT_FEATURE_style_windowsvista)
- add_subdirectory(windowsvista)
+ add_subdirectory(modernwindows)
endif()
diff --git a/src/plugins/styles/android/qandroidstyle.cpp b/src/plugins/styles/android/qandroidstyle.cpp
index ef625c6eb5..64940ed4d8 100644
--- a/src/plugins/styles/android/qandroidstyle.cpp
+++ b/src/plugins/styles/android/qandroidstyle.cpp
@@ -1209,7 +1209,7 @@ const QAndroidStyle::AndroidDrawable * QAndroidStyle::AndroidStateDrawable::best
int QAndroidStyle::AndroidStateDrawable::extractState(const QVariantMap &value)
{
- QStyle::State state = QStyle::State_Enabled | QStyle::State_Active;;
+ QStyle::State state = QStyle::State_Enabled | QStyle::State_Active;
for (auto it = value.cbegin(), end = value.cend(); it != end; ++it) {
const QString &key = it.key();
bool val = it.value().toString() == QLatin1String("true");
diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm
index 890dddbd1b..3f57f284e6 100644
--- a/src/plugins/styles/mac/qmacstyle_mac.mm
+++ b/src/plugins/styles/mac/qmacstyle_mac.mm
@@ -162,45 +162,6 @@ QVector<QPointer<QObject> > QMacStylePrivate::scrollBars;
bool isDarkMode() { return QGuiApplicationPrivate::platformTheme()->colorScheme() == Qt::ColorScheme::Dark; }
-// Title bar gradient colors for Lion were determined by inspecting PSDs exported
-// using CoreUI's CoreThemeDocument; there is no public API to retrieve them
-
-static QLinearGradient titlebarGradientActive()
-{
- static QLinearGradient darkGradient = [](){
- QLinearGradient gradient;
- // FIXME: colors are chosen somewhat arbitrarily and could be fine-tuned,
- // or ideally determined by calling a native API.
- gradient.setColorAt(0, QColor(47, 47, 47));
- return gradient;
- }();
- static QLinearGradient lightGradient = [](){
- QLinearGradient gradient;
- gradient.setColorAt(0, QColor(235, 235, 235));
- gradient.setColorAt(0.5, QColor(210, 210, 210));
- gradient.setColorAt(0.75, QColor(195, 195, 195));
- gradient.setColorAt(1, QColor(180, 180, 180));
- return gradient;
- }();
- return isDarkMode() ? darkGradient : lightGradient;
-}
-
-static QLinearGradient titlebarGradientInactive()
-{
- static QLinearGradient darkGradient = [](){
- QLinearGradient gradient;
- gradient.setColorAt(1, QColor(42, 42, 42));
- return gradient;
- }();
- static QLinearGradient lightGradient = [](){
- QLinearGradient gradient;
- gradient.setColorAt(0, QColor(250, 250, 250));
- gradient.setColorAt(1, QColor(225, 225, 225));
- return gradient;
- }();
- return isDarkMode() ? darkGradient : lightGradient;
-}
-
#if QT_CONFIG(tabwidget)
/*
Since macOS 10.14 AppKit is using transparency more extensively, especially for the
@@ -429,12 +390,7 @@ static bool setupSlider(NSSlider *slider, const QStyleOptionSlider *sl)
if (sl->minimum >= sl->maximum)
return false;
- // NSSlider seems to cache values based on tracking and the last layout of the
- // NSView, resulting in incorrect knob rects that break the interaction with
- // multiple sliders. So completely reinitialize the slider.
- const auto controlSize = slider.controlSize;
- [slider initWithFrame:sl->rect.toCGRect()];
- slider.controlSize = controlSize;
+ slider.frame = sl->rect.toCGRect();
slider.minValue = sl->minimum;
slider.maxValue = sl->maximum;
@@ -465,14 +421,6 @@ static bool setupSlider(NSSlider *slider, const QStyleOptionSlider *sl)
// the cell for its metrics and to draw itself.
[slider layoutSubtreeIfNeeded];
- if (sl->state & QStyle::State_Sunken) {
- const CGRect knobRect = [slider.cell knobRectFlipped:slider.isFlipped];
- CGPoint pressPoint;
- pressPoint.x = CGRectGetMidX(knobRect);
- pressPoint.y = CGRectGetMidY(knobRect);
- [slider.cell startTrackingAt:pressPoint inView:slider];
- }
-
return true;
}
@@ -2208,25 +2156,6 @@ int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QW
case PM_FocusFrameHMargin:
ret = qt_mac_aqua_get_metric(FocusRectOutset);
break;
- case PM_DialogButtonsSeparator:
- ret = -5;
- break;
- case PM_DialogButtonsButtonHeight: {
- QSize sz;
- ret = d->aquaSizeConstrain(opt, 0, QStyle::CT_PushButton, QSize(-1, -1), &sz);
- if (sz == QSize(-1, -1))
- ret = 32;
- else
- ret = sz.height();
- break; }
- case PM_DialogButtonsButtonWidth: {
- QSize sz;
- ret = d->aquaSizeConstrain(opt, 0, QStyle::CT_PushButton, QSize(-1, -1), &sz);
- if (sz == QSize(-1, -1))
- ret = 70;
- else
- ret = sz.width();
- break; }
case PM_MenuBarHMargin:
ret = 8;
@@ -3424,17 +3353,7 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
} break;
#endif // QT_CONFIG(tabbar)
case PE_PanelStatusBar: {
- // Fill the status bar with the titlebar gradient.
- QLinearGradient linearGrad;
- if (w ? qt_macWindowMainWindow(w->window()) : (opt->state & QStyle::State_Active)) {
- linearGrad = titlebarGradientActive();
- } else {
- linearGrad = titlebarGradientInactive();
- }
-
- linearGrad.setStart(0, opt->rect.top());
- linearGrad.setFinalStop(0, opt->rect.bottom());
- p->fillRect(opt->rect, linearGrad);
+ p->fillRect(opt->rect, opt->palette.window());
// Draw the black separator line at the top of the status bar.
if (w ? qt_macWindowMainWindow(w->window()) : (opt->state & QStyle::State_Active))
@@ -3915,6 +3834,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
frameRect = frameRect.adjusted(-1, 0, 1, 0);
}
break;
+ case QStyleOptionTab::Moving: // Moving tab treated like End
case QStyleOptionTab::End:
// Pressed state hack: tweak adjustments in preparation for flip below
if (isSelected || tabDirection == QMacStylePrivate::West)
@@ -4115,12 +4035,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
}
// fill title bar background
- QLinearGradient linearGrad;
- linearGrad.setStart(QPointF(0, 0));
- linearGrad.setFinalStop(QPointF(0, 2 * effectiveRect.height()));
- linearGrad.setColorAt(0, opt->palette.button().color());
- linearGrad.setColorAt(1, opt->palette.dark().color());
- p->fillRect(effectiveRect, linearGrad);
+ p->fillRect(effectiveRect, opt->palette.window());
// draw horizontal line at bottom
p->setPen(opt->palette.dark().color());
@@ -4135,7 +4050,7 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter
titleRect.width());
const auto text = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
- proxy()->drawItemText(p, titleRect, Qt::AlignCenter, dwOpt->palette,
+ proxy()->drawItemText(p, titleRect, Qt::AlignCenter | Qt::TextHideMnemonic, dwOpt->palette,
dwOpt->state & State_Enabled, text, QPalette::WindowText);
}
p->restore();
@@ -5385,6 +5300,15 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
const CGRect knobRect = [slider.cell knobRectFlipped:slider.isFlipped];
pressPoint.x = CGRectGetMidX(knobRect);
pressPoint.y = CGRectGetMidY(knobRect);
+
+ // The only way to tell a NSSlider/NSSliderCell to render as pressed
+ // is to start tracking. But this API has some weird behaviors that
+ // we have to account for. First of all, the pressed state will not
+ // be visually reflected unless we start tracking twice. And secondly
+ // if we don't track twice, the state of one render-pass will affect
+ // the render pass of other sliders, even if we set up the shared
+ // NSSlider with a new slider value.
+ [slider.cell startTrackingAt:pressPoint inView:slider];
[slider.cell startTrackingAt:pressPoint inView:slider];
}
@@ -5489,8 +5413,12 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
}
});
- if (isPressed)
+ if (isPressed) {
+ // We stop twice to be on the safe side, even if one seems to be enough.
+ // See startTracking above for why we do this.
+ [slider.cell stopTracking:pressPoint at:pressPoint inView:slider mouseIsUp:NO];
[slider.cell stopTracking:pressPoint at:pressPoint inView:slider mouseIsUp:NO];
+ }
}
break;
#if QT_CONFIG(spinbox)
@@ -5552,7 +5480,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
auto *cc = static_cast<NSControl *>(d->cocoaControl(cw));
cc.enabled = isEnabled;
- QRectF frameRect = cw.adjustedControlFrame(combo->rect);;
+ QRectF frameRect = cw.adjustedControlFrame(combo->rect);
if (cw.type == QMacStylePrivate::Button_PopupButton) {
// Non-editable QComboBox
auto *pb = static_cast<NSPopUpButton *>(cc);
@@ -5625,16 +5553,7 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex
const auto frameAdjust = 1.0 / p->device()->devicePixelRatio();
const auto innerFrameRect = outerFrameRect.adjusted(frameAdjust, frameAdjust, -frameAdjust, 0);
QPainterPath innerFramePath = d->windowPanelPath(innerFrameRect);
- if (isActive) {
- QLinearGradient g;
- g.setStart(QPointF(0, 0));
- g.setFinalStop(QPointF(0, 2 * opt->rect.height()));
- g.setColorAt(0, opt->palette.button().color());
- g.setColorAt(1, opt->palette.dark().color());
- p->fillPath(innerFramePath, g);
- } else {
- p->fillPath(innerFramePath, opt->palette.button());
- }
+ p->fillPath(innerFramePath, opt->palette.button());
if (titlebar->subControls & (SC_TitleBarCloseButton
| SC_TitleBarMaxButton
@@ -5981,7 +5900,7 @@ QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *op
qreal controlsSpacing = lastButtonRect.right() + titleBarButtonSpacing;
if (!titlebar->icon.isNull()) {
const auto iconSize = proxy()->pixelMetric(PM_SmallIconSize);
- const auto actualIconSize = titlebar->icon.actualSize(QSize(iconSize, iconSize)).width();;
+ const auto actualIconSize = titlebar->icon.actualSize(QSize(iconSize, iconSize)).width();
controlsSpacing += actualIconSize + titleBarIconTitleSpacing;
}
diff --git a/src/plugins/styles/mac/qmacstyle_mac_p_p.h b/src/plugins/styles/mac/qmacstyle_mac_p_p.h
index e3f1e39d19..0dcfce2f0c 100644
--- a/src/plugins/styles/mac/qmacstyle_mac_p_p.h
+++ b/src/plugins/styles/mac/qmacstyle_mac_p_p.h
@@ -12,7 +12,6 @@
#include <QtCore/qlist.h>
#include <QtCore/qmap.h>
#include <QtCore/qmath.h>
-#include <QtCore/qpair.h>
#include <QtCore/qpointer.h>
#include <QtCore/qtextstream.h>
diff --git a/src/plugins/styles/windowsvista/CMakeLists.txt b/src/plugins/styles/modernwindows/CMakeLists.txt
index 372a944638..985bce3a2d 100644
--- a/src/plugins/styles/windowsvista/CMakeLists.txt
+++ b/src/plugins/styles/modernwindows/CMakeLists.txt
@@ -5,12 +5,13 @@
## QWindowsVistaStylePlugin Plugin:
#####################################################################
-qt_internal_add_plugin(QWindowsVistaStylePlugin
- OUTPUT_NAME qwindowsvistastyle
+qt_internal_add_plugin(QModernWindowsStylePlugin
+ OUTPUT_NAME qmodernwindowsstyle
PLUGIN_TYPE styles
SOURCES
main.cpp
qwindowsvistastyle.cpp qwindowsvistastyle_p.h
+ qwindows11style.cpp qwindows11style_p.h
qwindowsvistastyle_p_p.h
qwindowsvistaanimation.cpp qwindowsvistaanimation_p.h
qwindowsthemedata.cpp qwindowsthemedata_p.h
@@ -21,5 +22,6 @@ qt_internal_add_plugin(QWindowsVistaStylePlugin
uxtheme
Qt::Core
Qt::Gui
+ Qt::GuiPrivate
Qt::WidgetsPrivate
)
diff --git a/src/plugins/styles/modernwindows/main.cpp b/src/plugins/styles/modernwindows/main.cpp
new file mode 100644
index 0000000000..a4d8e60385
--- /dev/null
+++ b/src/plugins/styles/modernwindows/main.cpp
@@ -0,0 +1,36 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtWidgets/private/qtwidgetsglobal_p.h>
+#include <QtWidgets/qstyleplugin.h>
+#include <QtCore/qoperatingsystemversion.h>
+#include "qwindowsvistastyle_p.h"
+#include "qwindows11style_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QModernWindowsStylePlugin : public QStylePlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QStyleFactoryInterface" FILE "modernwindowsstyles.json")
+public:
+ QStyle *create(const QString &key) override;
+};
+
+QStyle *QModernWindowsStylePlugin::create(const QString &key)
+{
+ bool isWin11OrAbove = QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows11;
+ if (isWin11OrAbove && key.compare(QLatin1String("windows11"), Qt::CaseInsensitive) == 0) {
+ return new QWindows11Style();
+ } else if (!isWin11OrAbove && key.compare(QLatin1String("windows11"), Qt::CaseInsensitive) == 0) {
+ qWarning("QWindows11Style: Style is only supported on Windows11 and above");
+ return new QWindowsVistaStyle();
+ } else if (key.compare(QLatin1String("windowsvista"), Qt::CaseInsensitive) == 0) {
+ return new QWindowsVistaStyle();
+ }
+ return nullptr;
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/styles/modernwindows/modernwindowsstyles.json b/src/plugins/styles/modernwindows/modernwindowsstyles.json
new file mode 100644
index 0000000000..e9cef558e8
--- /dev/null
+++ b/src/plugins/styles/modernwindows/modernwindowsstyles.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "windowsvista", "windows11" ]
+}
diff --git a/src/plugins/styles/modernwindows/qwindows11style.cpp b/src/plugins/styles/modernwindows/qwindows11style.cpp
new file mode 100644
index 0000000000..784f491681
--- /dev/null
+++ b/src/plugins/styles/modernwindows/qwindows11style.cpp
@@ -0,0 +1,2140 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwindows11style_p.h"
+#include <qstylehints.h>
+#include <private/qstyleanimation_p.h>
+#include <private/qstylehelper_p.h>
+#include <private/qapplication_p.h>
+#include <qstyleoption.h>
+#include <qpainter.h>
+#include <QGraphicsDropShadowEffect>
+#include <QtWidgets/qcombobox.h>
+#include <QtWidgets/qcommandlinkbutton.h>
+#include <QtWidgets/qgraphicsview.h>
+#include <QtWidgets/qlistview.h>
+#include <QtWidgets/qmenu.h>
+#include <QtWidgets/qmdiarea.h>
+#include <QtWidgets/qtextedit.h>
+#include <QtWidgets/qtreeview.h>
+
+#include "qdrawutil.h"
+#include <chrono>
+
+QT_BEGIN_NAMESPACE
+
+const static int topLevelRoundingRadius = 8; //Radius for toplevel items like popups for round corners
+const static int secondLevelRoundingRadius = 4; //Radius for second level items like hovered menu item round corners
+
+enum WINUI3Color {
+ subtleHighlightColor, //Subtle highlight based on alpha used for hovered elements
+ subtlePressedColor, //Subtle highlight based on alpha used for pressed elements
+ frameColorLight, //Color of frame around flyouts and controls except for Checkbox and Radiobutton
+ frameColorStrong, //Color of frame around Checkbox and Radiobuttons
+ controlStrongFill, //Color of controls with strong filling such as the right side of a slider
+ controlStrokeSecondary,
+ controlStrokePrimary,
+ controlFillTertiary, //Color of filled sunken controls
+ controlFillSecondary, //Color of filled hovered controls
+ menuPanelFill, //Color of menu panel
+ textOnAccentPrimary, //Color of text on controls filled in accent color
+ textOnAccentSecondary, //Color of text of sunken controls in accent color
+ controlTextSecondary, //Color of text of sunken controls
+ controlStrokeOnAccentSecondary, //Color of frame around Buttons in accent color
+ controlFillSolid, //Color for solid fill
+ surfaceStroke, //Color of MDI window frames
+};
+
+const static QColor WINUI3ColorsLight [] {
+ QColor(0x00,0x00,0x00,0x09), //subtleHighlightColor
+ QColor(0x00,0x00,0x00,0x06), //subtlePressedColor
+ QColor(0x00,0x00,0x00,0x0F), //frameColorLight
+ QColor(0x00,0x00,0x00,0x9c), //frameColorStrong
+ QColor(0x00,0x00,0x00,0x72), //controlStrongFill
+ QColor(0x00,0x00,0x00,0x29), //controlStrokeSecondary
+ QColor(0x00,0x00,0x00,0x14), //controlStrokePrimary
+ QColor(0xF9,0xF9,0xF9,0x00), //controlFillTertiary
+ QColor(0xF9,0xF9,0xF9,0x80), //controlFillSecondary
+ QColor(0xFF,0xFF,0xFF,0xFF), //menuPanelFill
+ QColor(0xFF,0xFF,0xFF,0xFF), //textOnAccentPrimary
+ QColor(0xFF,0xFF,0xFF,0x7F), //textOnAccentSecondary
+ QColor(0x00,0x00,0x00,0x7F), //controlTextSecondary
+ QColor(0x00,0x00,0x00,0x66), //controlStrokeOnAccentSecondary
+ QColor(0xFF,0xFF,0xFF,0xFF), //controlFillSolid
+ QColor(0x75,0x75,0x75,0x66), //surfaceStroke
+};
+
+const static QColor WINUI3ColorsDark[] {
+ QColor(0xFF,0xFF,0xFF,0x0F), //subtleHighlightColor
+ QColor(0xFF,0xFF,0xFF,0x0A), //subtlePressedColor
+ QColor(0xFF,0xFF,0xFF,0x12), //frameColorLight
+ QColor(0xFF,0xFF,0xFF,0x8B), //frameColorStrong
+ QColor(0xFF,0xFF,0xFF,0x8B), //controlStrongFill
+ QColor(0xFF,0xFF,0xFF,0x18), //controlStrokeSecondary
+ QColor(0xFF,0xFF,0xFF,0x12), //controlStrokePrimary
+ QColor(0xF9,0xF9,0xF9,0x00), //controlFillTertiary
+ QColor(0xF9,0xF9,0xF9,0x80), //controlFillSecondary
+ QColor(0x0F,0x0F,0x0F,0xFF), //menuPanelFill
+ QColor(0x00,0x00,0x00,0xFF), //textOnAccentPrimary
+ QColor(0x00,0x00,0x00,0x80), //textOnAccentSecondary
+ QColor(0xFF,0xFF,0xFF,0x87), //controlTextSecondary
+ QColor(0xFF,0xFF,0xFF,0x14), //controlStrokeOnAccentSecondary
+ QColor(0x45,0x45,0x45,0xFF), //controlFillSolid
+ QColor(0x75,0x75,0x75,0x66), //surfaceStroke
+};
+
+const static QColor* WINUI3Colors[] {
+ WINUI3ColorsLight,
+ WINUI3ColorsDark
+};
+
+const QColor shellCloseButtonColor(0xC4,0x2B,0x1C,0xFF); //Color of close Button in Titlebar
+
+#if QT_CONFIG(toolbutton)
+static void drawArrow(const QStyle *style, const QStyleOptionToolButton *toolbutton,
+ const QRect &rect, QPainter *painter, const QWidget *widget = nullptr)
+{
+ QStyle::PrimitiveElement pe;
+ switch (toolbutton->arrowType) {
+ case Qt::LeftArrow:
+ pe = QStyle::PE_IndicatorArrowLeft;
+ break;
+ case Qt::RightArrow:
+ pe = QStyle::PE_IndicatorArrowRight;
+ break;
+ case Qt::UpArrow:
+ pe = QStyle::PE_IndicatorArrowUp;
+ break;
+ case Qt::DownArrow:
+ pe = QStyle::PE_IndicatorArrowDown;
+ break;
+ default:
+ return;
+ }
+ QStyleOption arrowOpt = *toolbutton;
+ arrowOpt.rect = rect;
+ style->drawPrimitive(pe, &arrowOpt, painter, widget);
+}
+#endif // QT_CONFIG(toolbutton)
+/*!
+ \class QWindows11Style
+ \brief The QWindows11Style class provides a look and feel suitable for applications on Microsoft Windows 11.
+ \since 6.6
+ \ingroup appearance
+ \inmodule QtWidgets
+ \internal
+
+ \warning This style is only available on the Windows 11 platform and above.
+
+ \sa QWindows11Style QWindowsVistaStyle, QMacStyle, QFusionStyle
+*/
+
+/*!
+ Constructs a QWindows11Style object.
+*/
+QWindows11Style::QWindows11Style() : QWindowsVistaStyle(*new QWindows11StylePrivate)
+{
+}
+
+/*!
+ \internal
+ Constructs a QWindows11Style object.
+*/
+QWindows11Style::QWindows11Style(QWindows11StylePrivate &dd) : QWindowsVistaStyle(dd)
+{
+}
+
+/*!
+ Destructor.
+*/
+QWindows11Style::~QWindows11Style() = default;
+
+/*!
+ \internal
+ see drawPrimitive for comments on the animation support
+
+ */
+void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ QWindows11StylePrivate *d = const_cast<QWindows11StylePrivate*>(d_func());
+
+ State state = option->state;
+ SubControls sub = option->subControls;
+ State flags = option->state;
+ if (widget && widget->testAttribute(Qt::WA_UnderMouse) && widget->isActiveWindow())
+ flags |= State_MouseOver;
+
+ painter->save();
+ painter->setRenderHint(QPainter::Antialiasing);
+ if (d->transitionsEnabled()) {
+ if (control == CC_Slider) {
+ if (const auto *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ QObject *styleObject = option->styleObject; // Can be widget or qquickitem
+
+ QRectF thumbRect = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget);
+ auto center = thumbRect.center();
+ const qreal outerRadius = qMin(8.0, (slider->orientation == Qt::Horizontal ? thumbRect.height() / 2.0 : thumbRect.width() / 2.0) - 1);
+
+ thumbRect.setWidth(outerRadius);
+ thumbRect.setHeight(outerRadius);
+ thumbRect.moveCenter(center);
+ QPointF cursorPos = widget ? widget->mapFromGlobal(QCursor::pos()) : QPointF();
+ bool isInsideHandle = thumbRect.contains(cursorPos);
+
+ bool oldIsInsideHandle = styleObject->property("_q_insidehandle").toBool();
+ int oldState = styleObject->property("_q_stylestate").toInt();
+ int oldActiveControls = styleObject->property("_q_stylecontrols").toInt();
+
+ QRectF oldRect = styleObject->property("_q_stylerect").toRect();
+ styleObject->setProperty("_q_insidehandle", isInsideHandle);
+ styleObject->setProperty("_q_stylestate", int(option->state));
+ styleObject->setProperty("_q_stylecontrols", int(option->activeSubControls));
+ styleObject->setProperty("_q_stylerect", option->rect);
+ if (option->styleObject->property("_q_end_radius").isNull())
+ option->styleObject->setProperty("_q_end_radius", outerRadius * 0.43);
+
+ bool doTransition = (((state & State_Sunken) != (oldState & State_Sunken)
+ || ((oldIsInsideHandle) != (isInsideHandle))
+ || oldActiveControls != int(option->activeSubControls))
+ && state & State_Enabled);
+
+ if (oldRect != option->rect) {
+ doTransition = false;
+ d->stopAnimation(styleObject);
+ styleObject->setProperty("_q_inner_radius", outerRadius * 0.43);
+ }
+
+ if (doTransition) {
+ QNumberStyleAnimation *t = new QNumberStyleAnimation(styleObject);
+ t->setStartValue(styleObject->property("_q_inner_radius").toFloat());
+ if (state & State_Sunken)
+ t->setEndValue(outerRadius * 0.29);
+ else if (isInsideHandle)
+ t->setEndValue(outerRadius * 0.71);
+ else
+ t->setEndValue(outerRadius * 0.43);
+
+ styleObject->setProperty("_q_end_radius", t->endValue());
+
+ t->setStartTime(d->animationTime());
+ t->setDuration(150);
+ d->startAnimation(t);
+ }
+ }
+ }
+ }
+
+ switch (control) {
+#if QT_CONFIG(spinbox)
+ case CC_SpinBox:
+ if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
+ if (sb->frame && (sub & SC_SpinBoxFrame)) {
+ painter->save();
+ QRegion clipRegion = option->rect;
+ clipRegion -= option->rect.adjusted(2, 2, -2, -2);
+ painter->setClipRegion(clipRegion);
+ QColor lineColor = state & State_HasFocus ? option->palette.accent().color() : QColor(0,0,0);
+ painter->setPen(QPen(lineColor));
+ painter->drawLine(option->rect.bottomLeft() + QPointF(7,-0.5), option->rect.bottomRight() + QPointF(-7,-0.5));
+ painter->restore();
+ }
+ QRectF frameRect = option->rect;
+ frameRect.adjust(0.5,0.5,-0.5,-0.5);
+ QBrush fillColor = option->palette.brush(QPalette::Base);
+ painter->setBrush(fillColor);
+ painter->setPen(QPen(highContrastTheme == true ? sb->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]));
+ painter->drawRoundedRect(frameRect.adjusted(2,2,-2,-2), secondLevelRoundingRadius, secondLevelRoundingRadius);
+ QPoint mousePos = widget ? widget->mapFromGlobal(QCursor::pos()) : QPoint();
+ QColor hoverColor = WINUI3Colors[colorSchemeIndex][subtleHighlightColor];
+ if (sub & SC_SpinBoxEditField) {
+ QRect rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxEditField, widget).adjusted(0, 0, 0, 1);
+ if (rect.contains(mousePos) && !(state & State_HasFocus)) {
+ QBrush fillColor = QBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ painter->setBrush(fillColor);
+ painter->setPen(Qt::NoPen);
+ painter->drawRoundedRect(option->rect.adjusted(2,2,-2,-2), secondLevelRoundingRadius, secondLevelRoundingRadius);
+ }
+ }
+ if (sub & SC_SpinBoxUp) {
+ QRect rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxUp, widget).adjusted(0, 0, 0, 1);
+ float scale = rect.width() >= 16 ? 1.0 : rect.width()/16.0;
+ if (rect.contains(mousePos)) {
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(QBrush(hoverColor));
+ painter->drawRoundedRect(rect.adjusted(1,1,-1,-1),secondLevelRoundingRadius, secondLevelRoundingRadius);
+ }
+ painter->save();
+ painter->translate(rect.center());
+ painter->scale(scale,scale);
+ painter->translate(-rect.center());
+ painter->setFont(assetFont);
+ painter->setPen(sb->palette.buttonText().color());
+ painter->setBrush(Qt::NoBrush);
+ painter->drawText(rect,"\uE018", Qt::AlignVCenter | Qt::AlignHCenter);
+ painter->restore();
+ }
+ if (sub & SC_SpinBoxDown) {
+ QRect rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxDown, widget);
+ float scale = rect.width() >= 16 ? 1.0 : rect.width()/16.0;
+ if (rect.contains(mousePos)) {
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(QBrush(hoverColor));
+ painter->drawRoundedRect(rect.adjusted(1,1,-1,-1), secondLevelRoundingRadius, secondLevelRoundingRadius);
+ }
+ painter->save();
+ painter->translate(rect.center());
+ painter->scale(scale,scale);
+ painter->translate(-rect.center());
+ painter->setFont(assetFont);
+ painter->setPen(sb->palette.buttonText().color());
+ painter->setBrush(Qt::NoBrush);
+ painter->drawText(rect,"\uE019", Qt::AlignVCenter | Qt::AlignHCenter);
+ painter->restore();
+ }
+ }
+ break;
+#endif // QT_CONFIG(spinbox)
+#if QT_CONFIG(slider)
+ case CC_Slider:
+ if (const auto *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ QRectF slrect = slider->rect;
+ QRegion tickreg = slrect.toRect();
+
+ if (sub & SC_SliderGroove) {
+ QRectF rect = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget);
+ QRectF handleRect = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget);
+ QPointF handlePos = handleRect.center();
+ QRectF leftRect;
+ QRectF rightRect;
+
+ if (slider->orientation == Qt::Horizontal) {
+ rect = QRect(slrect.left(), rect.center().y() - 2, slrect.width() - 5, 4);
+ leftRect = QRect(rect.left(), rect.top(), (handlePos.x() - rect.left()), rect.height());
+ rightRect = QRect(handlePos.x(), rect.top(), (rect.width() - handlePos.x()), rect.height());
+ } else {
+ rect = QRect(rect.center().x() - 2, slrect.top(), 4, slrect.height() - 5);
+ rightRect = QRect(rect.left(), rect.top(), rect.width(), (handlePos.y() - rect.top()));
+ leftRect = QRect(rect.left(), handlePos.y(), rect.width(), (rect.height() - handlePos.y()));
+ }
+
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(option->palette.accent());
+ painter->drawRoundedRect(leftRect,1,1);
+ painter->setBrush(QBrush(WINUI3Colors[colorSchemeIndex][controlStrongFill]));
+ painter->drawRoundedRect(rightRect,1,1);
+
+ painter->setPen(QPen(highContrastTheme == true ? slider->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawRoundedRect(leftRect,1.5,1.5);
+ painter->drawRoundedRect(rightRect,1.5,1.5);
+
+ tickreg -= rect.toRect();
+ }
+ if (sub & SC_SliderTickmarks) {
+ int tickOffset = proxy()->pixelMetric(PM_SliderTickmarkOffset, slider, widget);
+ int ticks = slider->tickPosition;
+ int thickness = proxy()->pixelMetric(PM_SliderControlThickness, slider, widget);
+ int len = proxy()->pixelMetric(PM_SliderLength, slider, widget);
+ int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget);
+ int interval = slider->tickInterval;
+ if (interval <= 0) {
+ interval = slider->singleStep;
+ if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval,
+ available)
+ - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
+ 0, available) < 3)
+ interval = slider->pageStep;
+ }
+ if (!interval)
+ interval = 1;
+ int fudge = len / 2;
+ int pos;
+ int bothOffset = (ticks & QSlider::TicksAbove && ticks & QSlider::TicksBelow) ? 1 : 0;
+ painter->setPen(slider->palette.text().color());
+ QVarLengthArray<QLine, 32> lines;
+ int v = slider->minimum;
+ while (v <= slider->maximum + 1) {
+ if (v == slider->maximum + 1 && interval == 1)
+ break;
+ const int v_ = qMin(v, slider->maximum);
+ int tickLength = (v_ == slider->minimum || v_ >= slider->maximum) ? 4 : 3;
+ pos = QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
+ v_, available) + fudge;
+ if (slider->orientation == Qt::Horizontal) {
+ if (ticks & QSlider::TicksAbove) {
+ lines.append(QLine(pos, tickOffset - 1 - bothOffset,
+ pos, tickOffset - 1 - bothOffset - tickLength));
+ }
+
+ if (ticks & QSlider::TicksBelow) {
+ lines.append(QLine(pos, tickOffset + thickness + bothOffset,
+ pos, tickOffset + thickness + bothOffset + tickLength));
+ }
+ } else {
+ if (ticks & QSlider::TicksAbove) {
+ lines.append(QLine(tickOffset - 1 - bothOffset, pos,
+ tickOffset - 1 - bothOffset - tickLength, pos));
+ }
+
+ if (ticks & QSlider::TicksBelow) {
+ lines.append(QLine(tickOffset + thickness + bothOffset, pos,
+ tickOffset + thickness + bothOffset + tickLength, pos));
+ }
+ }
+ // in the case where maximum is max int
+ int nextInterval = v + interval;
+ if (nextInterval < v)
+ break;
+ v = nextInterval;
+ }
+ if (!lines.isEmpty()) {
+ painter->save();
+ painter->translate(slrect.topLeft());
+ painter->drawLines(lines.constData(), lines.size());
+ painter->restore();
+ }
+ }
+ if (sub & SC_SliderHandle) {
+ if (const auto *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ const QRectF rect = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget);
+ const QPointF center = rect.center();
+
+ const QNumberStyleAnimation* animation = qobject_cast<QNumberStyleAnimation*>(d->animation(option->styleObject));
+
+ if (animation != nullptr)
+ option->styleObject->setProperty("_q_inner_radius", animation->currentValue());
+ else
+ option->styleObject->setProperty("_q_inner_radius", option->styleObject->property("_q_end_radius"));
+
+ const qreal outerRadius = qMin(8.0,(slider->orientation == Qt::Horizontal ? rect.height() / 2.0 : rect.width() / 2.0) - 1);
+ const float innerRadius = option->styleObject->property("_q_inner_radius").toFloat();
+ painter->setRenderHint(QPainter::Antialiasing, true);
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(QBrush(WINUI3Colors[colorSchemeIndex][controlFillSolid]));
+ painter->drawEllipse(center, outerRadius, outerRadius);
+ painter->setBrush(option->palette.accent());
+ painter->drawEllipse(center, innerRadius, innerRadius);
+
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][controlStrokeSecondary]));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawEllipse(center, outerRadius + 0.5, outerRadius + 0.5);
+ painter->drawEllipse(center, innerRadius + 0.5, innerRadius + 0.5);
+ }
+ }
+ if (slider->state & State_HasFocus) {
+ QStyleOptionFocusRect fropt;
+ fropt.QStyleOption::operator=(*slider);
+ fropt.rect = subElementRect(SE_SliderFocusRect, slider, widget);
+ proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
+ }
+ }
+ break;
+#endif
+#if QT_CONFIG(combobox)
+ case CC_ComboBox:
+ if (const QStyleOptionComboBox *combobox = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
+ QBrush fillColor = combobox->palette.brush(QPalette::Base);
+ QRectF rect = option->rect.adjusted(2,2,-2,-2);
+ painter->setBrush(fillColor);
+ painter->setPen(Qt::NoPen);
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+
+ // In case the QComboBox is hovered overdraw the background with a alpha mask to
+ // highlight the QComboBox.
+ if (state & State_MouseOver) {
+ fillColor = QBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ painter->setBrush(fillColor);
+ painter->setPen(Qt::NoPen);
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ }
+
+ rect.adjust(0.5,0.5,-0.5,-0.5);
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(highContrastTheme == true ? combobox->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]);
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ if (sub & SC_ComboBoxArrow) {
+ QRectF rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget).adjusted(-4, 0, -4, 1);
+ painter->setFont(assetFont);
+ painter->setPen(combobox->palette.text().color());
+ painter->drawText(rect,"\uE019", Qt::AlignVCenter | Qt::AlignHCenter);
+ }
+ if (combobox->editable) {
+ QColor lineColor = state & State_HasFocus ? option->palette.accent().color() : QColor(0,0,0);
+ painter->setPen(QPen(lineColor));
+ painter->drawLine(rect.bottomLeft() + QPoint(2,1), rect.bottomRight() + QPoint(-2,1));
+ if (state & State_HasFocus)
+ painter->drawLine(rect.bottomLeft() + QPoint(3,2), rect.bottomRight() + QPoint(-3,2));
+ }
+ }
+ break;
+#endif // QT_CONFIG(combobox)
+ case QStyle::CC_ScrollBar:
+ if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ QRectF rect = scrollbar->rect;
+ QPointF center = rect.center();
+
+ if (scrollbar->orientation == Qt::Vertical && rect.width()>24)
+ rect.marginsRemoved(QMargins(0,2,2,2));
+ else if (scrollbar->orientation == Qt::Horizontal && rect.height()>24)
+ rect.marginsRemoved(QMargins(2,0,2,2));
+
+ if (state & State_MouseOver) {
+ if (scrollbar->orientation == Qt::Vertical && rect.width()>24)
+ rect.setWidth(rect.width()/2);
+ else if (scrollbar->orientation == Qt::Horizontal && rect.height()>24)
+ rect.setHeight(rect.height()/2);
+ rect.moveCenter(center);
+ painter->setBrush(scrollbar->palette.base());
+ painter->setPen(Qt::NoPen);
+ painter->drawRoundedRect(rect, topLevelRoundingRadius, topLevelRoundingRadius);
+
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(WINUI3Colors[colorSchemeIndex][frameColorLight]);
+ painter->drawRoundedRect(rect.marginsRemoved(QMarginsF(0.5,0.5,0.5,0.5)), topLevelRoundingRadius + 0.5, topLevelRoundingRadius + 0.5);
+ }
+ if (sub & SC_ScrollBarSlider) {
+ QRectF rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
+ QPointF center = rect.center();
+ if (flags & State_MouseOver) {
+ if (scrollbar->orientation == Qt::Vertical)
+ rect.setWidth(rect.width()/2);
+ else
+ rect.setHeight(rect.height()/2);
+ }
+ else {
+ if (scrollbar->orientation == Qt::Vertical)
+ rect.setWidth(1);
+ else
+ rect.setHeight(1);
+
+ }
+ rect.moveCenter(center);
+ painter->setBrush(Qt::gray);
+ painter->setPen(Qt::NoPen);
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ }
+ if (sub & SC_ScrollBarAddLine) {
+ QRectF rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddLine, widget);
+ if (flags & State_MouseOver) {
+ painter->setFont(QFont("Segoe Fluent Icons",6));
+ painter->setPen(Qt::gray);
+ if (scrollbar->orientation == Qt::Vertical)
+ painter->drawText(rect,"\uEDDC", Qt::AlignVCenter | Qt::AlignHCenter);
+ else
+ painter->drawText(rect,"\uEDDA", Qt::AlignVCenter | Qt::AlignHCenter);
+ }
+ }
+ if (sub & SC_ScrollBarSubLine) {
+ QRectF rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubLine, widget);
+ if (flags & State_MouseOver) {
+ painter->setPen(Qt::gray);
+ if (scrollbar->orientation == Qt::Vertical)
+ painter->drawText(rect,"\uEDDB", Qt::AlignVCenter | Qt::AlignHCenter);
+ else
+ painter->drawText(rect,"\uEDD9", Qt::AlignVCenter | Qt::AlignHCenter);
+ }
+ }
+ }
+ break;
+ case CC_TitleBar:
+ if (const auto* titlebar = qstyleoption_cast<const QStyleOptionTitleBar*>(option)) {
+ painter->setPen(Qt::NoPen);
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]));
+ painter->setBrush(titlebar->palette.button());
+ painter->drawRect(titlebar->rect);
+
+ // draw title
+ QRect textRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarLabel, widget);
+ painter->setPen(titlebar->palette.text().color());
+ // Note workspace also does elliding but it does not use the correct font
+ QString title = painter->fontMetrics().elidedText(titlebar->text, Qt::ElideRight, textRect.width() - 14);
+ painter->drawText(textRect.adjusted(1, 1, 1, 1), title, QTextOption(Qt::AlignHCenter | Qt::AlignVCenter));
+
+ QFont buttonFont = QFont(assetFont);
+ buttonFont.setPointSize(8);
+ // min button
+ if ((titlebar->subControls & SC_TitleBarMinButton) && (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint) &&
+ !(titlebar->titleBarState& Qt::WindowMinimized)) {
+ const QRect minButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarMinButton, widget);
+ if (minButtonRect.isValid()) {
+ bool hover = (titlebar->activeSubControls & SC_TitleBarMinButton) && (titlebar->state & State_MouseOver);
+ if (hover)
+ painter->fillRect(minButtonRect,WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ const QString textToDraw("\uE921");
+ painter->setPen(QPen(titlebar->palette.text().color()));
+ painter->setFont(buttonFont);
+ painter->drawText(minButtonRect, Qt::AlignVCenter | Qt::AlignHCenter, textToDraw);
+ }
+ }
+ // max button
+ if ((titlebar->subControls & SC_TitleBarMaxButton) && (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint) &&
+ !(titlebar->titleBarState & Qt::WindowMaximized)) {
+ const QRectF maxButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarMaxButton, widget);
+ if (maxButtonRect.isValid()) {
+ bool hover = (titlebar->activeSubControls & SC_TitleBarMaxButton) && (titlebar->state & State_MouseOver);
+ if (hover)
+ painter->fillRect(maxButtonRect,WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ const QString textToDraw("\uE922");
+ painter->setPen(QPen(titlebar->palette.text().color()));
+ painter->setFont(buttonFont);
+ painter->drawText(maxButtonRect, Qt::AlignVCenter | Qt::AlignHCenter, textToDraw);
+ }
+ }
+
+ // close button
+ if ((titlebar->subControls & SC_TitleBarCloseButton) && (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)) {
+ const QRect closeButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarCloseButton, widget);
+ if (closeButtonRect.isValid()) {
+ bool hover = (titlebar->activeSubControls & SC_TitleBarCloseButton) && (titlebar->state & State_MouseOver);
+ if (hover)
+ painter->fillRect(closeButtonRect,shellCloseButtonColor);
+ const QString textToDraw("\uE8BB");
+ painter->setPen(QPen(hover ? titlebar->palette.highlightedText().color() : titlebar->palette.text().color()));
+ painter->setFont(buttonFont);
+ painter->drawText(closeButtonRect, Qt::AlignVCenter | Qt::AlignHCenter, textToDraw);
+ }
+ }
+
+ // normalize button
+ if ((titlebar->subControls & SC_TitleBarNormalButton) &&
+ (((titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint) &&
+ (titlebar->titleBarState & Qt::WindowMinimized)) ||
+ ((titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint) &&
+ (titlebar->titleBarState & Qt::WindowMaximized)))) {
+ const QRect normalButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarNormalButton, widget);
+ if (normalButtonRect.isValid()) {
+ bool hover = (titlebar->activeSubControls & SC_TitleBarNormalButton) && (titlebar->state & State_MouseOver);
+ if (hover)
+ painter->fillRect(normalButtonRect,WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ const QString textToDraw("\uE923");
+ painter->setPen(QPen(titlebar->palette.text().color()));
+ painter->setFont(buttonFont);
+ painter->drawText(normalButtonRect, Qt::AlignVCenter | Qt::AlignHCenter, textToDraw);
+ }
+ }
+
+ // context help button
+ if (titlebar->subControls & SC_TitleBarContextHelpButton
+ && (titlebar->titleBarFlags & Qt::WindowContextHelpButtonHint)) {
+ const QRect contextHelpButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarContextHelpButton, widget);
+ if (contextHelpButtonRect.isValid()) {
+ bool hover = (titlebar->activeSubControls & SC_TitleBarCloseButton) && (titlebar->state & State_MouseOver);
+ if (hover)
+ painter->fillRect(contextHelpButtonRect,WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ const QString textToDraw("\uE897");
+ painter->setPen(QPen(titlebar->palette.text().color()));
+ painter->setFont(buttonFont);
+ painter->drawText(contextHelpButtonRect, Qt::AlignVCenter | Qt::AlignHCenter, textToDraw);
+ }
+ }
+
+ // shade button
+ if (titlebar->subControls & SC_TitleBarShadeButton && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint)) {
+ const QRect shadeButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarShadeButton, widget);
+ if (shadeButtonRect.isValid()) {
+ bool hover = (titlebar->activeSubControls & SC_TitleBarShadeButton) && (titlebar->state & State_MouseOver);
+ if (hover)
+ painter->fillRect(shadeButtonRect,WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ const QString textToDraw("\uE010");
+ painter->setPen(QPen(titlebar->palette.text().color()));
+ painter->setFont(buttonFont);
+ painter->drawText(shadeButtonRect, Qt::AlignVCenter | Qt::AlignHCenter, textToDraw);
+ }
+ }
+
+ // unshade button
+ if (titlebar->subControls & SC_TitleBarUnshadeButton && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint)) {
+ const QRect unshadeButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarUnshadeButton, widget);
+ if (unshadeButtonRect.isValid()) {
+ bool hover = (titlebar->activeSubControls & SC_TitleBarUnshadeButton) && (titlebar->state & State_MouseOver);
+ if (hover)
+ painter->fillRect(unshadeButtonRect,WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ const QString textToDraw("\uE011");
+ painter->setPen(QPen(titlebar->palette.text().color()));
+ painter->setFont(buttonFont);
+ painter->drawText(unshadeButtonRect, Qt::AlignVCenter | Qt::AlignHCenter, textToDraw);
+ }
+ }
+
+ // window icon for system menu
+ if ((titlebar->subControls & SC_TitleBarSysMenu) && (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)) {
+ const QRect iconRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarSysMenu, widget);
+ if (iconRect.isValid()) {
+ if (!titlebar->icon.isNull()) {
+ titlebar->icon.paint(painter, iconRect);
+ } else {
+ QStyleOption tool = *titlebar;
+ QPixmap pm = proxy()->standardIcon(SP_TitleBarMenuButton, &tool, widget).pixmap(16, 16);
+ tool.rect = iconRect;
+ painter->save();
+ proxy()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, pm);
+ painter->restore();
+ }
+ }
+ }
+ }
+ break;
+ default:
+ QWindowsVistaStyle::drawComplexControl(control, option, painter, widget);
+ }
+ painter->restore();
+}
+
+void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
+ QPainter *painter,
+ const QWidget *widget) const {
+ QWindows11StylePrivate *d = const_cast<QWindows11StylePrivate*>(d_func());
+
+ int state = option->state;
+ painter->save();
+ painter->setRenderHint(QPainter::Antialiasing);
+ if (d->transitionsEnabled() && (element == PE_IndicatorCheckBox || element == PE_IndicatorRadioButton)) {
+ QObject *styleObject = option->styleObject; // Can be widget or qquickitem
+ if (styleObject) {
+ int oldState = styleObject->property("_q_stylestate").toInt();
+ styleObject->setProperty("_q_stylestate", int(option->state));
+ styleObject->setProperty("_q_stylerect", option->rect);
+ bool doTransition = (((state & State_Sunken) != (oldState & State_Sunken)
+ || ((state & State_MouseOver) != (oldState & State_MouseOver))
+ || (state & State_On) != (oldState & State_On))
+ && state & State_Enabled);
+ if (doTransition) {
+ if (element == PE_IndicatorRadioButton) {
+ QNumberStyleAnimation *t = new QNumberStyleAnimation(styleObject);
+ t->setStartValue(styleObject->property("_q_inner_radius").toFloat());
+ t->setEndValue(7.0f);
+ if (option->state & State_Sunken)
+ t->setEndValue(2.0f);
+ else if (option->state & State_MouseOver && !(option->state & State_On))
+ t->setEndValue(7.0f);
+ else if (option->state & State_MouseOver && (option->state & State_On))
+ t->setEndValue(5.0f);
+ else if (option->state & State_On)
+ t->setEndValue(4.0f);
+ styleObject->setProperty("_q_end_radius", t->endValue());
+ t->setStartTime(d->animationTime());
+ t->setDuration(150);
+ d->startAnimation(t);
+ }
+ else if (element == PE_IndicatorCheckBox) {
+ if ((oldState & State_Off && state & State_On) || (oldState & State_NoChange && state & State_On)) {
+ QNumberStyleAnimation *t = new QNumberStyleAnimation(styleObject);
+ t->setStartValue(0.0f);
+ t->setEndValue(1.0f);
+ t->setStartTime(d->animationTime());
+ t->setDuration(150);
+ d->startAnimation(t);
+ }
+ }
+ }
+ }
+ } else if (!d->transitionsEnabled() && element == PE_IndicatorRadioButton) {
+ QObject *styleObject = option->styleObject; // Can be widget or qquickitem
+ if (styleObject) {
+ styleObject->setProperty("_q_end_radius",7.0);
+ if (option->state & State_Sunken)
+ styleObject->setProperty("_q_end_radius",2.0);
+ else if (option->state & State_MouseOver && !(option->state & State_On))
+ styleObject->setProperty("_q_end_radius",7.0);
+ else if (option->state & State_MouseOver && (option->state & State_On))
+ styleObject->setProperty("_q_end_radius",5.0);
+ else if (option->state & State_On)
+ styleObject->setProperty("_q_end_radius",4.0);
+ }
+ }
+
+ switch (element) {
+ case PE_PanelTipLabel: {
+ QRectF tipRect = option->rect.marginsRemoved(QMargins(1,1,1,1));
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(option->palette.toolTipBase());
+ painter->drawRoundedRect(tipRect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+
+ painter->setPen(highContrastTheme == true ? option->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]);
+ painter->setBrush(Qt::NoBrush);
+ painter->drawRoundedRect(tipRect.marginsAdded(QMarginsF(0.5,0.5,0.5,0.5)), secondLevelRoundingRadius, secondLevelRoundingRadius);
+ break;
+ }
+ case PE_FrameTabWidget:
+ if (const QStyleOptionTabWidgetFrame *frame = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option)) {
+ QRectF frameRect = frame->rect.marginsRemoved(QMargins(0,0,0,0));
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(frame->palette.base());
+ painter->drawRoundedRect(frameRect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+
+ painter->setPen(highContrastTheme == true ? frame->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]);
+ painter->setBrush(Qt::NoBrush);
+ painter->drawRoundedRect(frameRect.marginsRemoved(QMarginsF(0.5,0.5,0.5,0.5)), secondLevelRoundingRadius, secondLevelRoundingRadius);
+ }
+ break;
+ case PE_FrameGroupBox:
+ if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
+ QRectF frameRect = frame->rect;
+ frameRect.adjust(0.5,0.5,-0.5,-0.5);
+ painter->setPen(highContrastTheme == true ? frame->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorStrong]);
+ painter->setBrush(Qt::NoBrush);
+ if (frame->features & QStyleOptionFrame::Flat) {
+ QRect fr = frame->rect;
+ QPoint p1(fr.x(), fr.y() + 1);
+ QPoint p2(fr.x() + fr.width(), p1.y());
+ painter->drawLine(p1,p2);
+ } else {
+ painter->drawRoundedRect(frameRect.marginsRemoved(QMargins(1,1,1,1)), secondLevelRoundingRadius, secondLevelRoundingRadius);
+ }
+ }
+ break;
+ case PE_IndicatorCheckBox:
+ {
+ QNumberStyleAnimation* animation = qobject_cast<QNumberStyleAnimation*>(d->animation(option->styleObject));
+ QFontMetrics fm(assetFont);
+
+ QRectF rect = option->rect;
+ QPointF center = QPointF(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2);
+ rect.setWidth(15);
+ rect.setHeight(15);
+ rect.moveCenter(center);
+
+ float clipWidth = animation != nullptr ? animation->currentValue() : 1.0f;
+ QRectF clipRect = fm.boundingRect("\uE001");
+ clipRect.moveCenter(center);
+ clipRect.setLeft(rect.x() + (rect.width() - clipRect.width()) / 2.0);
+ clipRect.setWidth(clipWidth * clipRect.width());
+
+
+ QBrush fillBrush = (option->state & State_On || option->state & State_NoChange) ? option->palette.accent() : option->palette.window();
+ if (state & State_MouseOver && (option->state & State_On || option->state & State_NoChange))
+ fillBrush.setColor(fillBrush.color().lighter(107));
+ else if (state & State_MouseOver && !(option->state & State_On || option->state & State_NoChange))
+ fillBrush.setColor(fillBrush.color().darker(107));
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(fillBrush);
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius, Qt::AbsoluteSize);
+
+ painter->setPen(QPen(highContrastTheme == true ? option->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorStrong]));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius + 0.5, secondLevelRoundingRadius + 0.5, Qt::AbsoluteSize);
+
+ painter->setFont(assetFont);
+ painter->setPen(option->palette.highlightedText().color());
+ painter->setBrush(option->palette.highlightedText().color());
+ if (option->state & State_On)
+ painter->drawText(clipRect, Qt::AlignVCenter | Qt::AlignLeft,"\uE001");
+ else if (option->state & State_NoChange)
+ painter->drawText(rect, Qt::AlignVCenter | Qt::AlignHCenter,"\uE108");
+ }
+ break;
+
+ case PE_IndicatorRadioButton:
+ {
+ if (option->styleObject->property("_q_end_radius").isNull())
+ option->styleObject->setProperty("_q_end_radius", option->state & State_On ? 4.0f :7.0f);
+ QNumberStyleAnimation* animation = qobject_cast<QNumberStyleAnimation*>(d->animation(option->styleObject));
+ if (animation != nullptr)
+ option->styleObject->setProperty("_q_inner_radius", animation->currentValue());
+ else
+ option->styleObject->setProperty("_q_inner_radius", option->styleObject->property("_q_end_radius"));
+ int innerRadius = option->styleObject->property("_q_inner_radius").toFloat();
+
+ QRectF rect = option->rect;
+ QPointF center = QPoint(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2);
+ rect.setWidth(15);
+ rect.setHeight(15);
+ rect.moveCenter(center);
+ QRectF innerRect = rect;
+ innerRect.setWidth(8);
+ innerRect.setHeight(8);
+ innerRect.moveCenter(center);
+
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(option->palette.accent());
+ if (option->state & State_MouseOver && option->state & State_Enabled)
+ painter->setBrush(QBrush(option->palette.accent().color().lighter(107)));
+ painter->drawEllipse(center, 7, 7);
+
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][frameColorStrong]));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawEllipse(center, 7.5, 7.5);
+
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(QBrush(option->palette.window()));
+ painter->drawEllipse(center,innerRadius, innerRadius);
+
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][frameColorStrong]));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawEllipse(center,innerRadius + 0.5, innerRadius + 0.5);
+
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(QBrush(option->palette.window()));
+ if (option->state & State_MouseOver && option->state & State_Enabled)
+ painter->setBrush(QBrush(option->palette.window().color().darker(107)));
+ painter->drawEllipse(center,innerRadius, innerRadius);
+ }
+ break;
+ case PE_PanelButtonBevel:{
+ QRectF rect = option->rect.marginsRemoved(QMargins(2,2,2,2));
+ rect.adjust(-0.5,-0.5,0.5,0.5);
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][controlStrokePrimary]));
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+
+ rect = option->rect.marginsRemoved(QMargins(2,2,2,2));
+ painter->setPen(Qt::NoPen);
+ if (!(state & (State_Raised)))
+ painter->setBrush(WINUI3Colors[colorSchemeIndex][controlFillTertiary]);
+ else if (state & State_MouseOver)
+ painter->setBrush(WINUI3Colors[colorSchemeIndex][controlFillSecondary]);
+ else
+ painter->setBrush(option->palette.button());
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][controlStrokeSecondary]));
+ if (state & State_Raised)
+ painter->drawLine(rect.bottomLeft() + QPoint(2,1), rect.bottomRight() + QPoint(-2,1));
+ }
+ break;
+ case PE_FrameDefaultButton:
+ painter->setPen(option->palette.accent().color());
+ painter->setBrush(Qt::NoBrush);
+ painter->drawRoundedRect(option->rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ break;
+ case QStyle::PE_FrameMenu:
+ break;
+ case QStyle::PE_PanelMenu: {
+ QRect rect = option->rect;
+ QPen pen(WINUI3Colors[colorSchemeIndex][frameColorLight]);
+ painter->save();
+ painter->setPen(pen);
+ painter->setBrush(QBrush(WINUI3Colors[colorSchemeIndex][menuPanelFill]));
+ painter->setRenderHint(QPainter::Antialiasing);
+ painter->drawRoundedRect(rect.marginsRemoved(QMargins(2,2,12,2)), topLevelRoundingRadius, topLevelRoundingRadius);
+ painter->restore();
+ break;
+ }
+ case PE_PanelLineEdit:
+ if (widget && widget->objectName() == "qt_spinbox_lineedit")
+ break;
+ if (const auto *panel = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
+ QRectF frameRect = option->rect;
+ frameRect.adjust(0.5,0.5,-0.5,-0.5);
+ QBrush fillColor = option->palette.brush(QPalette::Base);
+ painter->setBrush(fillColor);
+ painter->setPen(Qt::NoPen);
+ painter->drawRoundedRect(frameRect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ // In case the QLineEdit is hovered overdraw the background with a alpha mask to
+ // highlight the QLineEdit.
+ if (state & State_MouseOver && !(state & State_HasFocus)) {
+ fillColor = QBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ painter->setBrush(fillColor);
+ painter->setPen(Qt::NoPen);
+ painter->drawRoundedRect(frameRect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ }
+ if (panel->lineWidth > 0)
+ proxy()->drawPrimitive(PE_FrameLineEdit, panel, painter, widget);
+ }
+ break;
+ case PE_FrameLineEdit: {
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(highContrastTheme == true ? option->palette.buttonText().color() : QPen(WINUI3Colors[colorSchemeIndex][frameColorLight]));
+ painter->drawRoundedRect(option->rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ QRegion clipRegion = option->rect;
+ clipRegion -= option->rect.adjusted(2, 2, -2, -2);
+ painter->setClipRegion(clipRegion);
+ QColor lineColor = state & State_HasFocus ? option->palette.accent().color() : QColor(0,0,0);
+ painter->setPen(QPen(lineColor));
+ painter->drawLine(option->rect.bottomLeft() + QPointF(1,0.5), option->rect.bottomRight() + QPointF(-1,0.5));
+ }
+ break;
+ case PE_Frame: {
+ if (const auto *frame = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
+ if (frame->frameShape == QFrame::NoFrame)
+ break;
+ QRectF rect = option->rect.adjusted(1,1,-1,-1);
+ if (widget && widget->inherits("QComboBoxPrivateContainer")) {
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(WINUI3Colors[colorSchemeIndex][menuPanelFill]);
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+
+ }
+ painter->setBrush(option->palette.base());
+ painter->setPen(Qt::NoPen);
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][frameColorLight]));
+ painter->drawRoundedRect(rect.marginsRemoved(QMarginsF(0.5,0.5,0.5,0.5)), secondLevelRoundingRadius, secondLevelRoundingRadius);
+
+ if (qobject_cast<const QTextEdit *>(widget)) {
+ QRegion clipRegion = option->rect;
+ QColor lineColor = state & State_HasFocus ? option->palette.accent().color() : QColor(0,0,0,255);
+ painter->setPen(QPen(lineColor));
+ painter->drawLine(option->rect.bottomLeft() + QPoint(1,-1), option->rect.bottomRight() + QPoint(-1,-1));
+ }
+ }
+ break;
+ }
+ case QStyle::PE_PanelItemViewRow:
+ if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) {
+ if ((vopt->state & State_Selected || vopt->state & State_MouseOver) && vopt->showDecorationSelected) {
+ painter->setBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ painter->setPen(Qt::NoPen);
+ painter->drawRoundedRect(vopt->rect.marginsRemoved(QMargins(0,2,-2,2)),2,2);
+ const int offset = qobject_cast<const QTreeView *>(widget) ? 2 : 0;
+ if (vopt->viewItemPosition == QStyleOptionViewItem::Beginning && option->state & State_Selected) {
+ painter->setPen(QPen(option->palette.accent().color()));
+ painter->drawLine(option->rect.x(),option->rect.y()+offset,option->rect.x(),option->rect.y() + option->rect.height()-2);
+ painter->drawLine(option->rect.x()+1,option->rect.y()+2,option->rect.x()+1,option->rect.y() + option->rect.height()-2);
+ }
+ }
+ }
+ break;
+ case QStyle::PE_Widget: {
+#if QT_CONFIG(dialogbuttonbox)
+ const QDialogButtonBox *buttonBox = nullptr;
+ if (qobject_cast<const QMessageBox *> (widget))
+ buttonBox = widget->findChild<const QDialogButtonBox *>(QLatin1String("qt_msgbox_buttonbox"));
+#if QT_CONFIG(inputdialog)
+ else if (qobject_cast<const QInputDialog *> (widget))
+ buttonBox = widget->findChild<const QDialogButtonBox *>(QLatin1String("qt_inputdlg_buttonbox"));
+#endif // QT_CONFIG(inputdialog)
+ if (buttonBox) {
+ painter->fillRect(option->rect,option->palette.window());
+ }
+#endif
+ break;
+ }
+ case QStyle::PE_FrameWindow:
+ if (const auto *frm = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
+
+ QRectF rect= option->rect;
+ int fwidth = int((frm->lineWidth + frm->midLineWidth) / QWindowsStylePrivate::nativeMetricScaleFactor(widget));
+
+ QRectF bottomLeftCorner = QRectF(rect.left() + 1.0,
+ rect.bottom() - 1.0 - secondLevelRoundingRadius,
+ secondLevelRoundingRadius,
+ secondLevelRoundingRadius);
+ QRectF bottomRightCorner = QRectF(rect.right() - 1.0 - secondLevelRoundingRadius,
+ rect.bottom() - 1.0 - secondLevelRoundingRadius,
+ secondLevelRoundingRadius,
+ secondLevelRoundingRadius);
+
+ //Draw Mask
+ if (widget != nullptr) {
+ QBitmap mask(widget->width(), widget->height());
+ mask.clear();
+
+ QPainter maskPainter(&mask);
+ maskPainter.setRenderHint(QPainter::Antialiasing);
+ maskPainter.setBrush(Qt::color1);
+ maskPainter.setPen(Qt::NoPen);
+ maskPainter.drawRoundedRect(option->rect,secondLevelRoundingRadius,secondLevelRoundingRadius);
+ const_cast<QWidget*>(widget)->setMask(mask);
+ }
+
+ //Draw Window
+ painter->setPen(QPen(frm->palette.base(), fwidth));
+ painter->drawLine(QPointF(rect.left(), rect.top()),
+ QPointF(rect.left(), rect.bottom() - fwidth));
+ painter->drawLine(QPointF(rect.left() + fwidth, rect.bottom()),
+ QPointF(rect.right() - fwidth, rect.bottom()));
+ painter->drawLine(QPointF(rect.right(), rect.top()),
+ QPointF(rect.right(), rect.bottom() - fwidth));
+
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]));
+ painter->drawLine(QPointF(rect.left() + 0.5, rect.top() + 0.5),
+ QPointF(rect.left() + 0.5, rect.bottom() - 0.5 - secondLevelRoundingRadius));
+ painter->drawLine(QPointF(rect.left() + 0.5 + secondLevelRoundingRadius, rect.bottom() - 0.5),
+ QPointF(rect.right() - 0.5 - secondLevelRoundingRadius, rect.bottom() - 0.5));
+ painter->drawLine(QPointF(rect.right() - 0.5, rect.top() + 1.5),
+ QPointF(rect.right() - 0.5, rect.bottom() - 0.5 - secondLevelRoundingRadius));
+
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(frm->palette.base());
+ painter->drawPie(bottomRightCorner.marginsAdded(QMarginsF(2.5,2.5,0.0,0.0)),
+ 270 * 16,90 * 16);
+ painter->drawPie(bottomLeftCorner.marginsAdded(QMarginsF(0.0,2.5,2.5,0.0)),
+ -90 * 16,-90 * 16);
+
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][surfaceStroke]));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawArc(bottomRightCorner,
+ 0 * 16,-90 * 16);
+ painter->drawArc(bottomLeftCorner,
+ -90 * 16,-90 * 16);
+ }
+ break;
+ default:
+ QWindowsVistaStyle::drawPrimitive(element, option, painter, widget);
+ }
+ painter->restore();
+}
+
+/*!
+ \internal
+*/
+void QWindows11Style::drawControl(ControlElement element, const QStyleOption *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ Q_D(const QWindows11Style);
+ QRect rect(option->rect);
+ State flags = option->state;
+
+ painter->save();
+ painter->setRenderHint(QPainter::Antialiasing);
+ switch (element) {
+ case QStyle::CE_TabBarTabShape:
+ if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(option)) {
+ QRectF tabRect = tab->rect.marginsRemoved(QMargins(2,2,0,0));
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(tab->palette.base());
+ if (tab->state & State_MouseOver){
+ painter->setBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ } else if (tab->state & State_Selected) {
+ painter->setBrush(tab->palette.base());
+ } else {
+ painter->setBrush(tab->palette.window());
+ }
+ painter->drawRoundedRect(tabRect,2,2);
+
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(highContrastTheme == true ? tab->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]);
+ painter->drawRoundedRect(tabRect.adjusted(0.5,0.5,-0.5,-0.5),2,2);
+
+ }
+ break;
+ case CE_ToolButtonLabel:
+ if (const QStyleOptionToolButton *toolbutton
+ = qstyleoption_cast<const QStyleOptionToolButton *>(option)) {
+ QRect rect = toolbutton->rect;
+ int shiftX = 0;
+ int shiftY = 0;
+ if (toolbutton->state & (State_Sunken | State_On)) {
+ shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, toolbutton, widget);
+ shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, toolbutton, widget);
+ }
+ // Arrow type always overrules and is always shown
+ bool hasArrow = toolbutton->features & QStyleOptionToolButton::Arrow;
+ if (((!hasArrow && toolbutton->icon.isNull()) && !toolbutton->text.isEmpty())
+ || toolbutton->toolButtonStyle == Qt::ToolButtonTextOnly) {
+ int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, toolbutton, widget))
+ alignment |= Qt::TextHideMnemonic;
+ rect.translate(shiftX, shiftY);
+ painter->setFont(toolbutton->font);
+ const QString text = d->toolButtonElideText(toolbutton, rect, alignment);
+ if (toolbutton->state & State_Raised || toolbutton->palette.isBrushSet(QPalette::Current, QPalette::ButtonText))
+ painter->setPen(QPen(toolbutton->palette.buttonText().color()));
+ else
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][controlTextSecondary]));
+ proxy()->drawItemText(painter, rect, alignment, toolbutton->palette,
+ toolbutton->state & State_Enabled, text);
+ } else {
+ QPixmap pm;
+ QSize pmSize = toolbutton->iconSize;
+ if (!toolbutton->icon.isNull()) {
+ QIcon::State state = toolbutton->state & State_On ? QIcon::On : QIcon::Off;
+ QIcon::Mode mode;
+ if (!(toolbutton->state & State_Enabled))
+ mode = QIcon::Disabled;
+ else if ((toolbutton->state & State_MouseOver) && (toolbutton->state & State_AutoRaise))
+ mode = QIcon::Active;
+ else
+ mode = QIcon::Normal;
+ pm = toolbutton->icon.pixmap(toolbutton->rect.size().boundedTo(toolbutton->iconSize), painter->device()->devicePixelRatio(),
+ mode, state);
+ pmSize = pm.size() / pm.devicePixelRatio();
+ }
+
+ if (toolbutton->toolButtonStyle != Qt::ToolButtonIconOnly) {
+ painter->setFont(toolbutton->font);
+ QRect pr = rect,
+ tr = rect;
+ int alignment = Qt::TextShowMnemonic;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, toolbutton, widget))
+ alignment |= Qt::TextHideMnemonic;
+
+ if (toolbutton->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
+ pr.setHeight(pmSize.height() + 4); //### 4 is currently hardcoded in QToolButton::sizeHint()
+ tr.adjust(0, pr.height() - 1, 0, -1);
+ pr.translate(shiftX, shiftY);
+ if (!hasArrow) {
+ proxy()->drawItemPixmap(painter, pr, Qt::AlignCenter, pm);
+ } else {
+ drawArrow(proxy(), toolbutton, pr, painter, widget);
+ }
+ alignment |= Qt::AlignCenter;
+ } else {
+ pr.setWidth(pmSize.width() + 4); //### 4 is currently hardcoded in QToolButton::sizeHint()
+ tr.adjust(pr.width(), 0, 0, 0);
+ pr.translate(shiftX, shiftY);
+ if (!hasArrow) {
+ proxy()->drawItemPixmap(painter, QStyle::visualRect(toolbutton->direction, rect, pr), Qt::AlignCenter, pm);
+ } else {
+ drawArrow(proxy(), toolbutton, pr, painter, widget);
+ }
+ alignment |= Qt::AlignLeft | Qt::AlignVCenter;
+ }
+ tr.translate(shiftX, shiftY);
+ const QString text = d->toolButtonElideText(toolbutton, tr, alignment);
+ if (toolbutton->state & State_Raised || toolbutton->palette.isBrushSet(QPalette::Current, QPalette::ButtonText))
+ painter->setPen(QPen(toolbutton->palette.buttonText().color()));
+ else
+ painter->setPen(QPen(WINUI3Colors[colorSchemeIndex][controlTextSecondary]));
+ proxy()->drawItemText(painter, QStyle::visualRect(toolbutton->direction, rect, tr), alignment, toolbutton->palette,
+ toolbutton->state & State_Enabled, text);
+ } else {
+ rect.translate(shiftX, shiftY);
+ if (hasArrow) {
+ drawArrow(proxy(), toolbutton, rect, painter, widget);
+ } else {
+ proxy()->drawItemPixmap(painter, rect, Qt::AlignCenter, pm);
+ }
+ }
+ }
+ }
+ break;
+ case QStyle::CE_ShapedFrame:
+ if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
+ int frameShape = f->frameShape;
+ int frameShadow = QFrame::Plain;
+ if (f->state & QStyle::State_Sunken)
+ frameShadow = QFrame::Sunken;
+ else if (f->state & QStyle::State_Raised)
+ frameShadow = QFrame::Raised;
+
+ int lw = f->lineWidth;
+ int mlw = f->midLineWidth;
+
+ switch (frameShape) {
+ case QFrame::Box:
+ if (frameShadow == QFrame::Plain)
+ qDrawPlainRoundedRect(painter, f->rect, secondLevelRoundingRadius, secondLevelRoundingRadius, highContrastTheme == true ? f->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorStrong], lw);
+ else
+ qDrawShadeRect(painter, f->rect, f->palette, frameShadow == QFrame::Sunken, lw, mlw);
+ break;
+ case QFrame::Panel:
+ if (frameShadow == QFrame::Plain)
+ qDrawPlainRoundedRect(painter, f->rect, secondLevelRoundingRadius, secondLevelRoundingRadius, highContrastTheme == true ? f->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorStrong], lw);
+ else
+ qDrawShadePanel(painter, f->rect, f->palette, frameShadow == QFrame::Sunken, lw);
+ break;
+ default:
+ QWindowsVistaStyle::drawControl(element, option, painter, widget);
+ }
+ }
+ break;
+ case QStyle::CE_ProgressBarGroove:{
+ if (const QStyleOptionProgressBar* progbaropt = qstyleoption_cast<const QStyleOptionProgressBar*>(option)) {
+ QRect rect = subElementRect(SE_ProgressBarContents, progbaropt, widget);
+ QPointF center = rect.center();
+ if (progbaropt->state & QStyle::State_Horizontal) {
+ rect.setHeight(1);
+ rect.moveTop(center.y());
+ } else {
+ rect.setWidth(1);
+ rect.moveLeft(center.x());
+ }
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(Qt::gray);
+ painter->drawRect(rect);
+ }
+ break;
+ }
+ case QStyle::CE_ProgressBarContents:
+ if (const QStyleOptionProgressBar* progbaropt = qstyleoption_cast<const QStyleOptionProgressBar*>(option)) {
+ const qreal progressBarThickness = 3;
+ const qreal progressBarHalfThickness = progressBarThickness / 2.0;
+ QRectF rect = subElementRect(SE_ProgressBarContents, progbaropt, widget);
+ QRectF originalRect = rect;
+ QPointF center = rect.center();
+ bool isIndeterminate = progbaropt->maximum == 0 && progbaropt->minimum == 0;
+ float fillPercentage = 0;
+ const Qt::Orientation orientation = (progbaropt->state & QStyle::State_Horizontal) ? Qt::Horizontal : Qt::Vertical;
+ const qreal offset = (orientation == Qt::Horizontal && int(rect.height()) % 2 == 0)
+ || (orientation == Qt::Vertical && int(rect.width()) % 2 == 0) ? 0.5 : 0.0;
+
+ if (!isIndeterminate) {
+ fillPercentage = ((float(progbaropt->progress) - float(progbaropt->minimum)) / (float(progbaropt->maximum) - float(progbaropt->minimum)));
+ if (orientation == Qt::Horizontal) {
+ rect.setHeight(progressBarThickness);
+ rect.moveTop(center.y() - progressBarHalfThickness - offset);
+ rect.setWidth(rect.width() * fillPercentage);
+ } else {
+ float oldHeight = rect.height();
+ rect.setWidth(progressBarThickness);
+ rect.moveLeft(center.x() - progressBarHalfThickness - offset);
+ rect.moveTop(oldHeight * (1.0f - fillPercentage));
+ rect.setHeight(oldHeight * fillPercentage);
+ }
+ } else {
+ auto elapsedTime = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
+ fillPercentage = (elapsedTime.time_since_epoch().count() % 5000)/(5000.0f*0.75);
+ if (orientation == Qt::Horizontal) {
+ float barBegin = qMin(qMax(fillPercentage-0.25,0.0) * rect.width(), float(rect.width()));
+ float barEnd = qMin(fillPercentage * rect.width(), float(rect.width()));
+ rect = QRect(QPoint(rect.left() + barBegin, rect.top()), QPoint(rect.left() + barEnd, rect.bottom()));
+ rect.setHeight(progressBarThickness);
+ rect.moveTop(center.y() - progressBarHalfThickness - offset);
+ } else {
+ float barBegin = qMin(qMax(fillPercentage-0.25,0.0) * rect.height(), float(rect.height()));
+ float barEnd = qMin(fillPercentage * rect.height(), float(rect.height()));
+ rect = QRect(QPoint(rect.left(), rect.bottom() - barEnd), QPoint(rect.right(), rect.bottom() - barBegin));
+ rect.setWidth(progressBarThickness);
+ rect.moveLeft(center.x() - progressBarHalfThickness - offset);
+ }
+ const_cast<QWidget*>(widget)->update();
+ }
+ if (progbaropt->invertedAppearance && orientation == Qt::Horizontal)
+ rect.moveLeft(originalRect.width() * (1.0 - fillPercentage));
+ else if (progbaropt->invertedAppearance && orientation == Qt::Vertical)
+ rect.moveBottom(originalRect.height() * fillPercentage);
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(progbaropt->palette.accent());
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ }
+ break;
+ case QStyle::CE_ProgressBarLabel:
+ if (const QStyleOptionProgressBar* progbaropt = qstyleoption_cast<const QStyleOptionProgressBar*>(option)) {
+ QRect rect = subElementRect(SE_ProgressBarLabel, progbaropt, widget);
+ painter->setPen(progbaropt->palette.text().color());
+ painter->drawText(rect, progbaropt->text,Qt::AlignVCenter|Qt::AlignLeft);
+ }
+ break;
+ case CE_PushButtonLabel:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) {
+ QRect textRect = btn->rect;
+
+ int tf = Qt::AlignVCenter|Qt::TextShowMnemonic;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, btn, widget))
+ tf |= Qt::TextHideMnemonic;
+
+ if (btn->features & QStyleOptionButton::HasMenu) {
+ int indicatorSize = proxy()->pixelMetric(PM_MenuButtonIndicator, btn, widget);
+ if (btn->direction == Qt::LeftToRight)
+ textRect = textRect.adjusted(0, 0, -indicatorSize, 0);
+ else
+ textRect = textRect.adjusted(indicatorSize, 0, 0, 0);
+ }
+ if (!btn->icon.isNull()) {
+ //Center both icon and text
+ QIcon::Mode mode = btn->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
+ if (mode == QIcon::Normal && btn->state & State_HasFocus)
+ mode = QIcon::Active;
+ QIcon::State state = QIcon::Off;
+ if (btn->state & State_On)
+ state = QIcon::On;
+
+ QPixmap pixmap = btn->icon.pixmap(btn->iconSize, painter->device()->devicePixelRatio(), mode, state);
+ int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio();
+ int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio();
+ int labelWidth = pixmapWidth;
+ int labelHeight = pixmapHeight;
+ int iconSpacing = 4;//### 4 is currently hardcoded in QPushButton::sizeHint()
+ if (!btn->text.isEmpty()) {
+ int textWidth = btn->fontMetrics.boundingRect(option->rect, tf, btn->text).width();
+ labelWidth += (textWidth + iconSpacing);
+ }
+
+ QRect iconRect = QRect(textRect.x() + (textRect.width() - labelWidth) / 2,
+ textRect.y() + (textRect.height() - labelHeight) / 2,
+ pixmapWidth, pixmapHeight);
+
+ iconRect = visualRect(btn->direction, textRect, iconRect);
+
+ if (btn->direction == Qt::RightToLeft) {
+ tf |= Qt::AlignRight;
+ textRect.setRight(iconRect.left() - iconSpacing / 2);
+ } else {
+ tf |= Qt::AlignLeft; //left align, we adjust the text-rect instead
+ textRect.setLeft(iconRect.left() + iconRect.width() + iconSpacing / 2);
+ }
+
+ if (btn->state & (State_On | State_Sunken))
+ iconRect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, option, widget),
+ proxy()->pixelMetric(PM_ButtonShiftVertical, option, widget));
+ painter->drawPixmap(iconRect, pixmap);
+ } else {
+ tf |= Qt::AlignHCenter;
+ }
+
+
+ if (btn->state & State_Sunken)
+ painter->setPen(flags & State_On ? QPen(WINUI3Colors[colorSchemeIndex][textOnAccentSecondary]) : QPen(WINUI3Colors[colorSchemeIndex][controlTextSecondary]));
+ else
+ painter->setPen(flags & State_On ? QPen(WINUI3Colors[colorSchemeIndex][textOnAccentPrimary]) : QPen(btn->palette.buttonText().color()));
+ proxy()->drawItemText(painter, textRect, tf, option->palette,btn->state & State_Enabled, btn->text);
+ }
+ break;
+ case CE_PushButtonBevel:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) {
+ if (btn->features.testFlag(QStyleOptionButton::Flat)) {
+ painter->setPen(Qt::NoPen);
+ if (flags & (State_Sunken | State_On)) {
+ painter->setBrush(WINUI3Colors[colorSchemeIndex][subtlePressedColor]);
+ }
+ else if (flags & State_MouseOver) {
+ painter->setBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ }
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ } else {
+ QRectF rect = btn->rect.marginsRemoved(QMargins(2,2,2,2));
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(flags & State_On ? option->palette.accent() : option->palette.button());
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ if (flags.testFlags(State_Sunken | State_MouseOver)) {
+ if (flags & (State_Sunken))
+ painter->setBrush(flags & State_On ? option->palette.accent().color().lighter(120) : WINUI3Colors[colorSchemeIndex][controlFillTertiary]);
+ else if (flags & State_MouseOver)
+ painter->setBrush(flags & State_On ? option->palette.accent().color().lighter(110) : WINUI3Colors[colorSchemeIndex][controlFillSecondary]);
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+ }
+
+ rect.adjust(0.5,0.5,-0.5,-0.5);
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(btn->features.testFlag(QStyleOptionButton::DefaultButton) ? QPen(option->palette.accent().color()) : QPen(WINUI3Colors[colorSchemeIndex][controlStrokePrimary]));
+ painter->drawRoundedRect(rect, secondLevelRoundingRadius, secondLevelRoundingRadius);
+
+ painter->setPen(btn->features.testFlag(QStyleOptionButton::DefaultButton) ? QPen(WINUI3Colors[colorSchemeIndex][controlStrokeOnAccentSecondary]) : QPen(WINUI3Colors[colorSchemeIndex][controlStrokeSecondary]));
+ if (flags & State_Raised)
+ painter->drawLine(rect.bottomLeft() + QPointF(4.0,0.0), rect.bottomRight() + QPointF(-4,0.0));
+ }
+ }
+ break;
+ case CE_MenuBarItem:
+ if (const auto *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
+ constexpr int hPadding = 11;
+ constexpr int topPadding = 4;
+ constexpr int bottomPadding = 6;
+ bool active = mbi->state & State_Selected;
+ bool hasFocus = mbi->state & State_HasFocus;
+ bool down = mbi->state & State_Sunken;
+ bool enabled = mbi->state & State_Enabled;
+ QStyleOptionMenuItem newMbi = *mbi;
+ newMbi.font.setPointSize(10);
+ if (enabled && (active || hasFocus)) {
+ if (active && down)
+ painter->setBrushOrigin(painter->brushOrigin() + QPoint(1, 1));
+ if (active && hasFocus) {
+ painter->setBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ painter->setPen(Qt::NoPen);
+ QRect rect = mbi->rect.marginsRemoved(QMargins(5,0,5,0));
+ painter->drawRoundedRect(rect,secondLevelRoundingRadius,secondLevelRoundingRadius,Qt::AbsoluteSize);
+ }
+ }
+ newMbi.rect.adjust(hPadding,topPadding,-hPadding,-bottomPadding);
+ painter->setFont(newMbi.font);
+ QCommonStyle::drawControl(element, &newMbi, painter, widget);
+ }
+ break;
+
+#if QT_CONFIG(menu)
+ case CE_MenuEmptyArea:
+ break;
+
+ case CE_MenuItem:
+ if (const auto *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
+ int x, y, w, h;
+ menuitem->rect.getRect(&x, &y, &w, &h);
+ int tab = menuitem->reservedShortcutWidth;
+ bool dis = !(menuitem->state & State_Enabled);
+ bool checked = menuitem->checkType != QStyleOptionMenuItem::NotCheckable
+ ? menuitem->checked : false;
+ bool act = menuitem->state & State_Selected;
+
+ // windows always has a check column, regardless whether we have an icon or not
+ int checkcol = qMax<int>(menuitem->maxIconWidth, 32);
+
+ QBrush fill = (act == true && dis == false) ? QBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]) : menuitem->palette.brush(QPalette::Button);
+ painter->setBrush(fill);
+ painter->setPen(Qt::NoPen);
+ QRect rect = menuitem->rect;
+ rect = rect.marginsRemoved(QMargins(2,2,2,2));
+ if (act && dis == false)
+ painter->drawRoundedRect(rect,secondLevelRoundingRadius,secondLevelRoundingRadius,Qt::AbsoluteSize);
+
+ if (menuitem->menuItemType == QStyleOptionMenuItem::Separator){
+ int yoff = 4;
+ painter->setPen(highContrastTheme == true ? menuitem->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]);
+ painter->drawLine(x, y + yoff, x + w, y + yoff );
+ break;
+ }
+
+ QRect vCheckRect = visualRect(option->direction, menuitem->rect, QRect(menuitem->rect.x(), menuitem->rect.y(), checkcol, menuitem->rect.height()));
+ if (!menuitem->icon.isNull() && checked) {
+ if (act) {
+ qDrawShadePanel(painter, vCheckRect,
+ menuitem->palette, true, 1,
+ &menuitem->palette.brush(QPalette::Button));
+ } else {
+ QBrush fill(menuitem->palette.light().color(), Qt::Dense4Pattern);
+ qDrawShadePanel(painter, vCheckRect, menuitem->palette, true, 1, &fill);
+ }
+ }
+ // On Windows Style, if we have a checkable item and an icon we
+ // draw the icon recessed to indicate an item is checked. If we
+ // have no icon, we draw a checkmark instead.
+ if (!menuitem->icon.isNull()) {
+ QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal;
+ if (act && !dis)
+ mode = QIcon::Active;
+ QPixmap pixmap;
+ if (checked)
+ pixmap = menuitem->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, option, widget), mode, QIcon::On);
+ else
+ pixmap = menuitem->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, option, widget), mode);
+ QRect pmr(QPoint(0, 0), pixmap.deviceIndependentSize().toSize());
+ pmr.moveCenter(vCheckRect.center());
+ painter->setPen(menuitem->palette.text().color());
+ painter->drawPixmap(pmr.topLeft(), pixmap);
+ } else if (checked) {
+ QStyleOptionMenuItem newMi = *menuitem;
+ newMi.state = State_None;
+ if (!dis)
+ newMi.state |= State_Enabled;
+ if (act)
+ newMi.state |= State_On | State_Selected;
+ newMi.rect = visualRect(option->direction, menuitem->rect, QRect(menuitem->rect.x() + QWindowsStylePrivate::windowsItemFrame,
+ menuitem->rect.y() + QWindowsStylePrivate::windowsItemFrame,
+ checkcol - 2 * QWindowsStylePrivate::windowsItemFrame,
+ menuitem->rect.height() - 2 * QWindowsStylePrivate::windowsItemFrame));
+
+ QColor discol;
+ if (dis) {
+ discol = menuitem->palette.text().color();
+ painter->setPen(discol);
+ }
+ int xm = int(QWindowsStylePrivate::windowsItemFrame) + checkcol / 4 + int(QWindowsStylePrivate::windowsItemHMargin);
+ int xpos = menuitem->rect.x() + xm;
+ QRect textRect(xpos, y + QWindowsStylePrivate::windowsItemVMargin,
+ w - xm - QWindowsStylePrivate::windowsRightBorder - tab + 1, h - 2 * QWindowsStylePrivate::windowsItemVMargin);
+ QRect vTextRect = visualRect(option->direction, menuitem->rect, textRect);
+
+ painter->save();
+ painter->setFont(assetFont);
+ int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
+ text_flags |= Qt::TextHideMnemonic;
+ text_flags |= Qt::AlignLeft;
+
+ const QString textToDraw("\uE001");
+ painter->setPen(option->palette.text().color());
+ painter->drawText(vTextRect, text_flags, textToDraw);
+ painter->restore();
+ }
+ painter->setPen(act ? menuitem->palette.highlightedText().color() : menuitem->palette.buttonText().color());
+
+ QColor discol = menuitem->palette.text().color();
+ if (dis) {
+ discol = menuitem->palette.color(QPalette::Disabled, QPalette::WindowText);
+ painter->setPen(discol);
+ }
+
+ int xm = int(QWindowsStylePrivate::windowsItemFrame) + checkcol + int(QWindowsStylePrivate::windowsItemHMargin);
+ int xpos = menuitem->rect.x() + xm;
+ QRect textRect(xpos, y + QWindowsStylePrivate::windowsItemVMargin,
+ w - xm - QWindowsStylePrivate::windowsRightBorder - tab + 1, h - 2 * QWindowsStylePrivate::windowsItemVMargin);
+ QRect vTextRect = visualRect(option->direction, menuitem->rect, textRect);
+ QStringView s(menuitem->text);
+ if (!s.isEmpty()) { // draw text
+ painter->save();
+ qsizetype t = s.indexOf(u'\t');
+ int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
+ text_flags |= Qt::TextHideMnemonic;
+ text_flags |= Qt::AlignLeft;
+ if (t >= 0) {
+ QRect vShortcutRect = visualRect(option->direction, menuitem->rect,
+ QRect(textRect.topRight(), QPoint(menuitem->rect.right(), textRect.bottom())));
+ const QString textToDraw = s.mid(t + 1).toString();
+ if (dis && !act && proxy()->styleHint(SH_EtchDisabledText, option, widget)) {
+ painter->setPen(menuitem->palette.light().color());
+ painter->drawText(vShortcutRect.adjusted(1, 1, 1, 1), text_flags, textToDraw);
+ painter->setPen(discol);
+ }
+ painter->setPen(menuitem->palette.color(QPalette::Disabled, QPalette::Text));
+ painter->drawText(vShortcutRect, text_flags, textToDraw);
+ s = s.left(t);
+ }
+ QFont font = menuitem->font;
+ if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem)
+ font.setBold(true);
+ painter->setFont(font);
+ const QString textToDraw = s.left(t).toString();
+ painter->setPen(discol);
+ painter->drawText(vTextRect, text_flags, textToDraw);
+ painter->restore();
+ }
+ if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow
+ int dim = (h - 2 * QWindowsStylePrivate::windowsItemFrame) / 2;
+ xpos = x + w - QWindowsStylePrivate::windowsArrowHMargin - QWindowsStylePrivate::windowsItemFrame - dim;
+ QRect vSubMenuRect = visualRect(option->direction, menuitem->rect, QRect(xpos, y + h / 2 - dim / 2, dim, dim));
+ QStyleOptionMenuItem newMI = *menuitem;
+ newMI.rect = vSubMenuRect;
+ newMI.state = dis ? State_None : State_Enabled;
+ if (act)
+ newMI.palette.setColor(QPalette::ButtonText,
+ newMI.palette.highlightedText().color());
+ painter->save();
+ painter->setFont(assetFont);
+ int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
+ text_flags |= Qt::TextHideMnemonic;
+ text_flags |= Qt::AlignLeft;
+ const QString textToDraw("\uE013");
+ painter->setPen(option->palette.text().color());
+ painter->drawText(vSubMenuRect, text_flags, textToDraw);
+ painter->restore();
+ }
+ }
+ break;
+#endif // QT_CONFIG(menu)
+ case CE_MenuBarEmptyArea: {
+ break;
+ }
+ case CE_HeaderEmptyArea:
+ break;
+ case CE_HeaderSection: {
+ if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(header->palette.button());
+ painter->drawRect(header->rect);
+
+ painter->setPen(highContrastTheme == true ? header->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]);
+ painter->setBrush(Qt::NoBrush);
+
+ if (header->position == QStyleOptionHeader::OnlyOneSection) {
+ break;
+ }
+ else if (header->position == QStyleOptionHeader::Beginning) {
+ painter->drawLine(QPointF(option->rect.topRight()) + QPointF(0.5,0.0),
+ QPointF(option->rect.bottomRight()) + QPointF(0.5,0.0));
+ }
+ else if (header->position == QStyleOptionHeader::End) {
+ painter->drawLine(QPointF(option->rect.topLeft()) - QPointF(0.5,0.0),
+ QPointF(option->rect.bottomLeft()) - QPointF(0.5,0.0));
+ } else {
+ painter->drawLine(QPointF(option->rect.topRight()) + QPointF(0.5,0.0),
+ QPointF(option->rect.bottomRight()) + QPointF(0.5,0.0));
+ painter->drawLine(QPointF(option->rect.topLeft()) - QPointF(0.5,0.0),
+ QPointF(option->rect.bottomLeft()) - QPointF(0.5,0.0));
+ }
+ painter->drawLine(QPointF(option->rect.bottomLeft()) + QPointF(0.0,0.5),
+ QPointF(option->rect.bottomRight()) + QPointF(0.0,0.5));
+ }
+ break;
+ }
+ case QStyle::CE_ItemViewItem: {
+ if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) {
+ if (const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget)) {
+ QRect checkRect = proxy()->subElementRect(SE_ItemViewItemCheckIndicator, vopt, widget);
+ QRect iconRect = proxy()->subElementRect(SE_ItemViewItemDecoration, vopt, widget);
+ QRect textRect = proxy()->subElementRect(SE_ItemViewItemText, vopt, widget);
+
+ QRect rect = vopt->rect;
+
+ painter->setPen(highContrastTheme == true ? vopt->palette.buttonText().color() : WINUI3Colors[colorSchemeIndex][frameColorLight]);
+ if (vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne || vopt->viewItemPosition == QStyleOptionViewItem::Invalid) {
+ } else if (vopt->viewItemPosition == QStyleOptionViewItem::Beginning) {
+ painter->drawLine(QPointF(option->rect.topRight()) + QPointF(0.5,0.0),
+ QPointF(option->rect.bottomRight()) + QPointF(0.5,0.0));
+ } else if (vopt->viewItemPosition == QStyleOptionViewItem::End) {
+ painter->drawLine(QPointF(option->rect.topLeft()) - QPointF(0.5,0.0),
+ QPointF(option->rect.bottomLeft()) - QPointF(0.5,0.0));
+ } else {
+ painter->drawLine(QPointF(option->rect.topRight()) + QPointF(0.5,0.0),
+ QPointF(option->rect.bottomRight()) + QPointF(0.5,0.0));
+ painter->drawLine(QPointF(option->rect.topLeft()) - QPointF(0.5,0.0),
+ QPointF(option->rect.bottomLeft()) - QPointF(0.5,0.0));
+ }
+ painter->setPen(QPen(option->palette.buttonText().color()));
+
+ const bool isTreeView = qobject_cast<const QTreeView *>(widget);
+
+ if ((vopt->state & State_Selected || vopt->state & State_MouseOver) && !(isTreeView && vopt->state & State_MouseOver) && vopt->showDecorationSelected) {
+ painter->setBrush(WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ QWidget *editorWidget = view ? view->indexWidget(view->currentIndex()) : nullptr;
+ if (editorWidget) {
+ QPalette pal = editorWidget->palette();
+ QColor editorBgColor = vopt->backgroundBrush == Qt::NoBrush ? vopt->palette.color(widget->backgroundRole()) : vopt->backgroundBrush.color();
+ editorBgColor.setAlpha(255);
+ pal.setColor(editorWidget->backgroundRole(),editorBgColor);
+ editorWidget->setPalette(pal);
+ }
+ } else {
+ painter->setBrush(vopt->backgroundBrush);
+ }
+ painter->setPen(Qt::NoPen);
+
+ if (vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne || vopt->viewItemPosition == QStyleOptionViewItem::Invalid) {
+ painter->drawRoundedRect(vopt->rect.marginsRemoved(QMargins(2,2,2,2)),secondLevelRoundingRadius,secondLevelRoundingRadius);
+ } else if (vopt->viewItemPosition == QStyleOptionViewItem::Beginning) {
+ painter->drawRoundedRect(rect.marginsRemoved(QMargins(2,2,0,2)),secondLevelRoundingRadius,secondLevelRoundingRadius);
+ } else if (vopt->viewItemPosition == QStyleOptionViewItem::End) {
+ painter->drawRoundedRect(vopt->rect.marginsRemoved(QMargins(0,2,2,2)),secondLevelRoundingRadius,secondLevelRoundingRadius);
+ } else {
+ painter->drawRect(vopt->rect.marginsRemoved(QMargins(0,2,0,2)));
+ }
+
+ // draw the check mark
+ if (vopt->features & QStyleOptionViewItem::HasCheckIndicator) {
+ QStyleOptionViewItem option(*vopt);
+ option.rect = checkRect;
+ option.state = option.state & ~QStyle::State_HasFocus;
+
+ switch (vopt->checkState) {
+ case Qt::Unchecked:
+ option.state |= QStyle::State_Off;
+ break;
+ case Qt::PartiallyChecked:
+ option.state |= QStyle::State_NoChange;
+ break;
+ case Qt::Checked:
+ option.state |= QStyle::State_On;
+ break;
+ }
+ proxy()->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &option, painter, widget);
+ }
+
+ // draw the icon
+ QIcon::Mode mode = QIcon::Normal;
+ if (!(vopt->state & QStyle::State_Enabled))
+ mode = QIcon::Disabled;
+ else if (vopt->state & QStyle::State_Selected)
+ mode = QIcon::Selected;
+ QIcon::State state = vopt->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
+ vopt->icon.paint(painter, iconRect, vopt->decorationAlignment, mode, state);
+
+ painter->setPen(QPen(option->palette.buttonText().color()));
+ if (!view || !view->isPersistentEditorOpen(vopt->index))
+ d->viewItemDrawText(painter, vopt, textRect);
+ if (vopt->state & State_Selected
+ && (vopt->viewItemPosition == QStyleOptionViewItem::Beginning
+ || vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne
+ || vopt->viewItemPosition == QStyleOptionViewItem::Invalid)) {
+ if (const QListView *lv = qobject_cast<const QListView *>(widget);
+ lv && lv->viewMode() != QListView::IconMode) {
+ painter->setPen(QPen(vopt->palette.accent().color()));
+ painter->drawLine(option->rect.x(), option->rect.y() + 2,
+ option->rect.x(),option->rect.y() + option->rect.height() - 2);
+ painter->drawLine(option->rect.x() + 1, option->rect.y() + 2,
+ option->rect.x() + 1,option->rect.y() + option->rect.height() - 2);
+ }
+ }
+ }
+ }
+ break;
+ }
+ default:
+ QWindowsVistaStyle::drawControl(element, option, painter, widget);
+ }
+ painter->restore();
+}
+
+int QWindows11Style::styleHint(StyleHint hint, const QStyleOption *opt,
+ const QWidget *widget, QStyleHintReturn *returnData) const {
+ switch (hint) {
+ case SH_GroupBox_TextLabelColor:
+ if (opt!=nullptr && widget!=nullptr)
+ return opt->palette.text().color().rgba();
+ return 0;
+ case QStyle::SH_ItemView_ShowDecorationSelected:
+ return 1;
+ default:
+ return QWindowsVistaStyle::styleHint(hint, opt, widget, returnData);
+ }
+}
+
+QRect QWindows11Style::subElementRect(QStyle::SubElement element, const QStyleOption *option,
+ const QWidget *widget) const
+{
+ QRect ret;
+ switch (element) {
+ case QStyle::SE_LineEditContents:
+ ret = option->rect.adjusted(8,0,-8,0);
+ break;
+ case QStyle::SE_ItemViewItemText:
+ if (const auto *item = qstyleoption_cast<const QStyleOptionViewItem *>(option)) {
+ const int decorationOffset = item->features.testFlag(QStyleOptionViewItem::HasDecoration) ? item->decorationSize.width() : 0;
+ if (widget && widget->parentWidget()
+ && widget->parentWidget()->inherits("QComboBoxPrivateContainer")) {
+ ret = option->rect.adjusted(decorationOffset + 5, 0, -5, 0);
+ } else {
+ ret = QWindowsVistaStyle::subElementRect(element, option, widget);
+ }
+ } else {
+ ret = QWindowsVistaStyle::subElementRect(element, option, widget);
+ }
+ break;
+ default:
+ ret = QWindowsVistaStyle::subElementRect(element, option, widget);
+ }
+ return ret;
+}
+
+/*!
+ \internal
+ */
+QRect QWindows11Style::subControlRect(ComplexControl control, const QStyleOptionComplex *option,
+ SubControl subControl, const QWidget *widget) const
+{
+ QRect ret;
+
+ switch (control) {
+#if QT_CONFIG(spinbox)
+ case CC_SpinBox:
+ if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
+ QSize bs;
+ int fw = spinbox->frame ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, spinbox, widget) : 0;
+ bs.setHeight(qMax(8, spinbox->rect.height() - fw));
+ bs.setWidth(qMin(24.0, spinbox->rect.width()*(1.0/4.0)));
+ int y = fw + spinbox->rect.y();
+ int x, lx, rx;
+ x = spinbox->rect.x() + spinbox->rect.width() - fw - 2 * bs.width();
+ lx = fw;
+ rx = x - fw;
+ switch (subControl) {
+ case SC_SpinBoxUp:
+ if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons)
+ return QRect();
+ ret = QRect(x, y, bs.width(), bs.height());
+ break;
+ case SC_SpinBoxDown:
+ if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons)
+ return QRect();
+ ret = QRect(x + bs.width(), y, bs.width(), bs.height());
+ break;
+ case SC_SpinBoxEditField:
+ if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) {
+ ret = QRect(lx, fw, spinbox->rect.width() - 2*fw, spinbox->rect.height() - 2*fw);
+ } else {
+ ret = QRect(lx, fw, rx, spinbox->rect.height() - 2*fw);
+ }
+ break;
+ case SC_SpinBoxFrame:
+ ret = spinbox->rect;
+ default:
+ break;
+ }
+ ret = visualRect(spinbox->direction, spinbox->rect, ret);
+ }
+ break;
+ case CC_TitleBar:
+ if (const QStyleOptionTitleBar *titlebar = qstyleoption_cast<const QStyleOptionTitleBar *>(option)) {
+ SubControl sc = subControl;
+ ret = QCommonStyle::subControlRect(control, option, subControl, widget);
+ static constexpr int indent = 3;
+ static constexpr int controlWidthMargin = 2;
+ const int controlHeight = titlebar->rect.height();
+ const int controlWidth = 46;
+ const int iconSize = proxy()->pixelMetric(QStyle::PM_TitleBarButtonIconSize, option, widget);
+ int offset = -(controlWidthMargin + indent);
+
+ bool isMinimized = titlebar->titleBarState & Qt::WindowMinimized;
+ bool isMaximized = titlebar->titleBarState & Qt::WindowMaximized;
+
+ switch (sc) {
+ case SC_TitleBarLabel:
+ if (titlebar->titleBarFlags & (Qt::WindowTitleHint | Qt::WindowSystemMenuHint)) {
+ ret = titlebar->rect;
+ if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)
+ ret.adjust(iconSize + controlWidthMargin + indent, 0, -controlWidth, 0);
+ if (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint)
+ ret.adjust(0, 0, -controlWidth, 0);
+ if (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint)
+ ret.adjust(0, 0, -controlWidth, 0);
+ if (titlebar->titleBarFlags & Qt::WindowShadeButtonHint)
+ ret.adjust(0, 0, -controlWidth, 0);
+ if (titlebar->titleBarFlags & Qt::WindowContextHelpButtonHint)
+ ret.adjust(0, 0, -controlWidth, 0);
+ }
+ break;
+ case SC_TitleBarContextHelpButton:
+ if (titlebar->titleBarFlags & Qt::WindowContextHelpButtonHint)
+ offset += controlWidth;
+ Q_FALLTHROUGH();
+ case SC_TitleBarMinButton:
+ if (!isMinimized && (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint))
+ offset += controlWidth;
+ else if (sc == SC_TitleBarMinButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarNormalButton:
+ if (isMinimized && (titlebar->titleBarFlags & Qt::WindowMinimizeButtonHint))
+ offset += controlWidth;
+ else if (isMaximized && (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint))
+ offset += controlWidth;
+ else if (sc == SC_TitleBarNormalButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarMaxButton:
+ if (!isMaximized && (titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint))
+ offset += controlWidth;
+ else if (sc == SC_TitleBarMaxButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarShadeButton:
+ if (!isMinimized && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint))
+ offset += controlWidth;
+ else if (sc == SC_TitleBarShadeButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarUnshadeButton:
+ if (isMinimized && (titlebar->titleBarFlags & Qt::WindowShadeButtonHint))
+ offset += controlWidth;
+ else if (sc == SC_TitleBarUnshadeButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarCloseButton:
+ if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint)
+ offset += controlWidth;
+ else if (sc == SC_TitleBarCloseButton)
+ break;
+ ret.setRect(titlebar->rect.right() - offset, titlebar->rect.top(),
+ controlWidth, controlHeight);
+ break;
+ case SC_TitleBarSysMenu:
+ if (titlebar->titleBarFlags & Qt::WindowSystemMenuHint) {
+ ret.setRect(titlebar->rect.left() + controlWidthMargin + indent, titlebar->rect.top() + iconSize/2,
+ iconSize, iconSize);
+ }
+ break;
+ default:
+ break;
+ }
+ if (widget && isMinimized && titlebar->rect.width() < offset)
+ const_cast<QWidget*>(widget)->resize(controlWidthMargin + indent + offset + iconSize + controlWidthMargin, controlWidth);
+ ret = visualRect(titlebar->direction, titlebar->rect, ret);
+ }
+ break;
+#endif // Qt_NO_SPINBOX
+ case CC_ScrollBar:
+ {
+ ret = QCommonStyle::subControlRect(control, option, subControl, widget);
+
+ switch (subControl) {
+ case QStyle::SC_ScrollBarAddLine:
+ if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ if (scrollbar->orientation == Qt::Vertical) {
+ ret = ret.adjusted(2,2,-2,-3);
+ } else {
+ ret = ret.adjusted(3,2,-2,-2);
+ }
+ }
+ break;
+ case QStyle::SC_ScrollBarSubLine:
+ if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ if (scrollbar->orientation == Qt::Vertical) {
+ ret = ret.adjusted(2,2,-2,-3);
+ } else {
+ ret = ret.adjusted(3,2,-2,-2);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
+ }
+ return ret;
+}
+
+/*!
+ \internal
+ */
+QSize QWindows11Style::sizeFromContents(ContentsType type, const QStyleOption *option,
+ const QSize &size, const QWidget *widget) const
+{
+ QSize contentSize(size);
+
+ switch (type) {
+
+ case CT_Menu:
+ contentSize += QSize(10, 0);
+ break;
+
+#if QT_CONFIG(menubar)
+ case CT_MenuBarItem:
+ if (!contentSize.isEmpty()) {
+ constexpr int hMargin = 2 * 6;
+ constexpr int hPadding = 2 * 11;
+ constexpr int itemHeight = 32;
+ contentSize.setWidth(contentSize.width() + hMargin + hPadding);
+ contentSize.setHeight(itemHeight);
+ }
+ break;
+#endif
+
+ default:
+ contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget);
+ break;
+ }
+
+ return contentSize;
+}
+
+
+/*!
+ \internal
+ */
+int QWindows11Style::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
+{
+ int res = 0;
+
+ switch (metric) {
+ case QStyle::PM_IndicatorWidth:
+ case QStyle::PM_IndicatorHeight:
+ case QStyle::PM_ExclusiveIndicatorWidth:
+ case QStyle::PM_ExclusiveIndicatorHeight:
+ res = 16;
+ break;
+ case QStyle::PM_SliderLength:
+ res = int(QStyleHelper::dpiScaled(16, option));
+ break;
+ case QStyle::PM_TitleBarButtonIconSize:
+ res = 16;
+ break;
+ case QStyle::PM_TitleBarButtonSize:
+ res = 32;
+ break;
+ case QStyle::PM_ScrollBarExtent:
+ res = 12;
+ break;
+ default:
+ res = QWindowsVistaStyle::pixelMetric(metric, option, widget);
+ }
+
+ return res;
+}
+
+void QWindows11Style::polish(QWidget* widget)
+{
+ QWindowsVistaStyle::polish(widget);
+ const bool isScrollBar = qobject_cast<QScrollBar *>(widget);
+ if (isScrollBar || qobject_cast<QMenu *>(widget) || widget->inherits("QComboBoxPrivateContainer")) {
+ bool wasCreated = widget->testAttribute(Qt::WA_WState_Created);
+ bool layoutDirection = widget->testAttribute(Qt::WA_RightToLeft);
+ widget->setAttribute(Qt::WA_OpaquePaintEvent,false);
+ widget->setAttribute(Qt::WA_TranslucentBackground);
+ widget->setWindowFlag(Qt::FramelessWindowHint);
+ widget->setWindowFlag(Qt::NoDropShadowWindowHint);
+ widget->setAttribute(Qt::WA_RightToLeft, layoutDirection);
+ widget->setAttribute(Qt::WA_WState_Created, wasCreated);
+ auto pal = widget->palette();
+ pal.setColor(widget->backgroundRole(), Qt::transparent);
+ widget->setPalette(pal);
+ if (!isScrollBar) { // for menus and combobox containers...
+ QGraphicsDropShadowEffect* dropshadow = new QGraphicsDropShadowEffect(widget);
+ dropshadow->setBlurRadius(3);
+ dropshadow->setXOffset(3);
+ dropshadow->setYOffset(3);
+ widget->setGraphicsEffect(dropshadow);
+ }
+ } else if (QComboBox* cb = qobject_cast<QComboBox*>(widget)) {
+ if (cb->isEditable()) {
+ QLineEdit *le = cb->lineEdit();
+ le->setFrame(false);
+ }
+ } else if (widget->inherits("QAbstractButton") || widget->inherits("QToolButton")) {
+ widget->setAutoFillBackground(false);
+ } else if (qobject_cast<QGraphicsView *>(widget) && !qobject_cast<QTextEdit *>(widget)) {
+ QPalette pal = widget->palette();
+ pal.setColor(QPalette::Base, pal.window().color());
+ widget->setPalette(pal);
+ } else if (const auto *scrollarea = qobject_cast<QAbstractScrollArea *>(widget);
+ scrollarea && !qobject_cast<QMdiArea *>(widget)) {
+ QPalette pal = scrollarea->viewport()->palette();
+ const QPalette originalPalette = pal;
+ pal.setColor(scrollarea->viewport()->backgroundRole(), Qt::transparent);
+ scrollarea->viewport()->setPalette(pal);
+ scrollarea->viewport()->setProperty("_q_original_background_palette", originalPalette);
+ } else if (qobject_cast<QCommandLinkButton *>(widget)) {
+ widget->setProperty("_qt_usingVistaStyle",false);
+ QPalette pal = widget->palette();
+ pal.setColor(QPalette::ButtonText, pal.text().color());
+ pal.setColor(QPalette::BrightText, pal.text().color());
+ widget->setPalette(pal);
+ }
+}
+
+void QWindows11Style::unpolish(QWidget *widget)
+{
+ QWindowsVistaStyle::unpolish(widget);
+ if (const auto *scrollarea = qobject_cast<QAbstractScrollArea *>(widget);
+ scrollarea && !qobject_cast<QMdiArea *>(widget)) {
+ const QPalette pal = scrollarea->viewport()->property("_q_original_background_palette").value<QPalette>();
+ scrollarea->viewport()->setPalette(pal);
+ scrollarea->viewport()->setProperty("_q_original_background_palette", QVariant());
+ }
+}
+
+/*
+The colors for Windows 11 are taken from the official WinUI3 Figma style at
+https://www.figma.com/community/file/1159947337437047524
+*/
+#define SET_IF_UNRESOLVED(GROUP, ROLE, VALUE) \
+ if (!result.isBrushSet(QPalette::Inactive, ROLE) || styleSheetChanged) \
+ result.setColor(GROUP, ROLE, VALUE)
+
+static void populateLightSystemBasePalette(QPalette &result)
+{
+ static QString oldStyleSheet;
+ const bool styleSheetChanged = oldStyleSheet != qApp->styleSheet();
+
+ const QColor textColor = QColor(0x00,0x00,0x00,0xE4);
+ const QColor btnFace = QColor(0xFF,0xFF,0xFF,0xB3);
+ const QColor btnHighlight = result.accent().color();
+ const QColor btnColor = result.button().color();
+
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::Highlight, btnHighlight);
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::WindowText, textColor);
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::Button, btnFace);
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::Light, btnColor.lighter(150));
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::Dark, btnColor.darker(200));
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::Mid, btnColor.darker(150));
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::Text, textColor);
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::BrightText, btnHighlight);
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::Base, btnFace);
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::Window, QColor(0xF3,0xF3,0xF3,0xFF));
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::ButtonText, textColor);
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::Midlight, btnColor.lighter(125));
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::Shadow, Qt::black);
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::ToolTipBase, result.window().color());
+ SET_IF_UNRESOLVED(QPalette::All, QPalette::ToolTipText, result.windowText().color());
+
+ if (result.midlight() == result.button())
+ result.setColor(QPalette::Midlight, btnColor.lighter(110));
+ oldStyleSheet = qApp->styleSheet();
+}
+
+/*!
+ \internal
+ */
+void QWindows11Style::polish(QPalette& result)
+{
+ highContrastTheme = QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Unknown;
+ colorSchemeIndex = QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Light ? 0 : 1;
+
+ if (!highContrastTheme && colorSchemeIndex == 0)
+ populateLightSystemBasePalette(result);
+
+ const bool styleSheetChanged = false; // so the macro works
+
+ SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Button, result.button().color());
+ SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Window, result.window().color());
+ SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Light, result.light().color());
+ SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Dark, result.dark().color());
+ SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Accent, result.accent().color());
+ SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Highlight, result.highlight().color());
+ SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::HighlightedText, result.highlightedText().color());
+ SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Text, result.text().color());
+ SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::WindowText, result.windowText().color());
+
+ if (highContrastTheme)
+ result.setColor(QPalette::Active, QPalette::HighlightedText, result.windowText().color());
+}
+
+#undef SET_IF_UNRESOLVED
+
+QT_END_NAMESPACE
diff --git a/src/plugins/styles/modernwindows/qwindows11style_p.h b/src/plugins/styles/modernwindows/qwindows11style_p.h
new file mode 100644
index 0000000000..9c54afd967
--- /dev/null
+++ b/src/plugins/styles/modernwindows/qwindows11style_p.h
@@ -0,0 +1,70 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWINDOWS11STYLE_P_H
+#define QWINDOWS11STYLE_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 <QtWidgets/private/qtwidgetsglobal_p.h>
+#include <qwindowsvistastyle_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWindows11StylePrivate;
+class QWindows11Style;
+
+class QWindows11Style : public QWindowsVistaStyle
+{
+ Q_OBJECT
+public:
+ QWindows11Style();
+ ~QWindows11Style() override;
+ void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option,
+ QPainter *painter, const QWidget *widget) const override;
+ void drawPrimitive(PrimitiveElement element, const QStyleOption *option,
+ QPainter *painter, const QWidget *widget) const override;
+ QRect subElementRect(QStyle::SubElement element, const QStyleOption *option,
+ const QWidget *widget = nullptr) const override;
+ QRect subControlRect(ComplexControl control, const QStyleOptionComplex *option,
+ SubControl subControl, const QWidget *widget) const override;
+ void drawControl(ControlElement element, const QStyleOption *option,
+ QPainter *painter, const QWidget *widget) const override;
+ int styleHint(StyleHint hint, const QStyleOption *opt = nullptr,
+ const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const override;
+ void polish(QWidget* widget) override;
+
+ QSize sizeFromContents(ContentsType type, const QStyleOption *option,
+ const QSize &size, const QWidget *widget) const override;
+ int pixelMetric(PixelMetric metric, const QStyleOption *option = nullptr,
+ const QWidget *widget = nullptr) const override;
+ void polish(QPalette &pal) override;
+ void unpolish(QWidget *widget) override;
+protected:
+ QWindows11Style(QWindows11StylePrivate &dd);
+private:
+ Q_DISABLE_COPY_MOVE(QWindows11Style)
+ Q_DECLARE_PRIVATE(QWindows11Style)
+ friend class QStyleFactory;
+
+ bool highContrastTheme = false;
+ int colorSchemeIndex = 0;
+ const QFont assetFont = QFont("Segoe Fluent Icons"); //Font to load icons from
+};
+
+class QWindows11StylePrivate : public QWindowsVistaStylePrivate {
+ Q_DECLARE_PUBLIC(QWindows11Style)
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWS11STYLE_P_H
diff --git a/src/plugins/styles/windowsvista/qwindowsthemedata.cpp b/src/plugins/styles/modernwindows/qwindowsthemedata.cpp
index 44569e054d..44569e054d 100644
--- a/src/plugins/styles/windowsvista/qwindowsthemedata.cpp
+++ b/src/plugins/styles/modernwindows/qwindowsthemedata.cpp
diff --git a/src/plugins/styles/windowsvista/qwindowsthemedata_p.h b/src/plugins/styles/modernwindows/qwindowsthemedata_p.h
index 5de2bcbdea..5de2bcbdea 100644
--- a/src/plugins/styles/windowsvista/qwindowsthemedata_p.h
+++ b/src/plugins/styles/modernwindows/qwindowsthemedata_p.h
diff --git a/src/plugins/styles/windowsvista/qwindowsvistaanimation.cpp b/src/plugins/styles/modernwindows/qwindowsvistaanimation.cpp
index ac9a5ad8c0..ac9a5ad8c0 100644
--- a/src/plugins/styles/windowsvista/qwindowsvistaanimation.cpp
+++ b/src/plugins/styles/modernwindows/qwindowsvistaanimation.cpp
diff --git a/src/plugins/styles/windowsvista/qwindowsvistaanimation_p.h b/src/plugins/styles/modernwindows/qwindowsvistaanimation_p.h
index 817fa5f4b5..817fa5f4b5 100644
--- a/src/plugins/styles/windowsvista/qwindowsvistaanimation_p.h
+++ b/src/plugins/styles/modernwindows/qwindowsvistaanimation_p.h
diff --git a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp
index 4ae2adde35..beee1d6f31 100644
--- a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp
+++ b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp
@@ -12,6 +12,8 @@
#include <private/qstylehelper_p.h>
#include <qpa/qplatformnativeinterface.h>
#include <private/qapplication_p.h>
+#include <private/qsystemlibrary_p.h>
+#include <private/qwindowsthemecache_p.h>
#include "qdrawutil.h" // for now
#include <qbackingstore.h>
@@ -19,6 +21,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
static const int windowsItemFrame = 2; // menu item frame width
static const int windowsItemHMargin = 3; // menu item hor text margin
static const int windowsItemVMargin = 4; // menu item ver text margin
@@ -48,23 +52,9 @@ static const int windowsRightBorder = 15; // right border on windows
# define CMDLGS_DISABLED 4
#endif
-/* \internal
- Checks if we should use Vista style , or if we should
- fall back to Windows style.
-*/
-// Theme names matching the QWindowsVistaStylePrivate::Theme enumeration.
-static const wchar_t *themeNames[QWindowsVistaStylePrivate::NThemes] =
-{
- L"BUTTON", L"COMBOBOX", L"EDIT", L"HEADER", L"LISTVIEW",
- L"MENU", L"PROGRESS", L"REBAR", L"SCROLLBAR", L"SPIN",
- L"TAB", L"TASKDIALOG", L"TOOLBAR", L"TOOLTIP", L"TRACKBAR",
- L"WINDOW", L"STATUS", L"TREEVIEW"
-};
-
// QWindowsVistaStylePrivate -------------------------------------------------------------------------
// Static initializations
HWND QWindowsVistaStylePrivate::m_vistaTreeViewHelper = nullptr;
-HTHEME QWindowsVistaStylePrivate::m_themes[NThemes];
bool QWindowsVistaStylePrivate::useVistaTheme = false;
Q_CONSTINIT QBasicAtomicInt QWindowsVistaStylePrivate::ref = Q_BASIC_ATOMIC_INITIALIZER(-1); // -1 based refcounting
@@ -181,7 +171,6 @@ void QWindowsVistaStylePrivate::init(bool force)
ref.ref();
useVista(true);
- std::fill(m_themes, m_themes + NThemes, nullptr);
}
/* \internal
@@ -237,11 +226,8 @@ int QWindowsVistaStylePrivate::pixelMetricFromSystemDp(QStyle::PixelMetric pm, c
: QWindowsThemeData::themeSize(widget, nullptr, QWindowsVistaStylePrivate::ProgressTheme, PP_CHUNKVERT).height();
case QStyle::PM_SliderThickness:
return QWindowsThemeData::themeSize(widget, nullptr, QWindowsVistaStylePrivate::TrackBarTheme, TKP_THUMB).height();
- case QStyle::PM_TitleBarHeight: {
- return widget && (widget->windowType() == Qt::Tool)
- ? GetSystemMetrics(SM_CYSMCAPTION) + GetSystemMetrics(SM_CXSIZEFRAME)
- : GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CXSIZEFRAME);
- }
+ case QStyle::PM_TitleBarHeight:
+ return QWindowsStylePrivate::pixelMetricFromSystemDp(QStyle::PM_TitleBarHeight, option, widget);
case QStyle::PM_MdiSubWindowFrameWidth:
return QWindowsThemeData::themeSize(widget, nullptr, QWindowsVistaStylePrivate::WindowTheme, WP_FRAMELEFT, FS_ACTIVE).width();
case QStyle::PM_DockWidgetFrameWidth:
@@ -304,31 +290,15 @@ void QWindowsVistaStylePrivate::cleanupVistaTreeViewTheming()
*/
void QWindowsVistaStylePrivate::cleanupHandleMap()
{
- for (auto &theme : m_themes) {
- if (theme) {
- CloseThemeData(theme);
- theme = nullptr;
- }
- }
+ QWindowsThemeCache::clearAllThemeCaches();
QWindowsVistaStylePrivate::cleanupVistaTreeViewTheming();
}
HTHEME QWindowsVistaStylePrivate::createTheme(int theme, HWND hwnd)
{
- if (Q_UNLIKELY(theme < 0 || theme >= NThemes || !hwnd)) {
- qWarning("Invalid parameters #%d, %p", theme, hwnd);
- return nullptr;
- }
- if (!m_themes[theme]) {
- const wchar_t *name = themeNames[theme];
- if (theme == VistaTreeViewTheme && QWindowsVistaStylePrivate::initVistaTreeViewTheming())
- hwnd = QWindowsVistaStylePrivate::m_vistaTreeViewHelper;
- m_themes[theme] = OpenThemeData(hwnd, name);
- if (Q_UNLIKELY(!m_themes[theme]))
- qErrnoWarning("OpenThemeData() failed for theme %d (%s).",
- theme, qPrintable(themeName(theme)));
- }
- return m_themes[theme];
+ if (theme == VistaTreeViewTheme && QWindowsVistaStylePrivate::initVistaTreeViewTheming())
+ hwnd = QWindowsVistaStylePrivate::m_vistaTreeViewHelper;
+ return QWindowsThemeCache::createTheme(theme, hwnd);
}
QBackingStore *QWindowsVistaStylePrivate::backingStoreForWidget(const QWidget *widget)
@@ -353,8 +323,7 @@ HDC QWindowsVistaStylePrivate::hdcForWidgetBackingStore(const QWidget *widget)
QString QWindowsVistaStylePrivate::themeName(int theme)
{
- return theme >= 0 && theme < NThemes
- ? QString::fromWCharArray(themeNames[theme]) : QString();
+ return QWindowsThemeCache::themeName(theme);
}
bool QWindowsVistaStylePrivate::isItemViewDelegateLineEdit(const QWidget *widget)
@@ -1305,6 +1274,14 @@ QWindowsVistaStyle::QWindowsVistaStyle() : QWindowsStyle(*new QWindowsVistaStyle
}
/*!
+ \internal
+ Constructs a QWindowsStyle object.
+*/
+QWindowsVistaStyle::QWindowsVistaStyle(QWindowsVistaStylePrivate &dd) : QWindowsStyle(dd)
+{
+}
+
+/*!
Destructor.
*/
QWindowsVistaStyle::~QWindowsVistaStyle() = default;
@@ -1422,17 +1399,17 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt
theme = OpenThemeData(nullptr, L"Edit");
partId = EP_EDITBORDER_NOSCROLL;
- if (oldState & State_MouseOver)
+ if (oldState & State_HasFocus)
+ fromState = ETS_SELECTED;
+ else if (oldState & State_MouseOver)
fromState = ETS_HOT;
- else if (oldState & State_HasFocus)
- fromState = ETS_FOCUSED;
else
fromState = ETS_NORMAL;
- if (state & State_MouseOver)
+ if (state & State_HasFocus)
+ toState = ETS_SELECTED;
+ else if (state & State_MouseOver)
toState = ETS_HOT;
- else if (state & State_HasFocus)
- toState = ETS_FOCUSED;
else
toState = ETS_NORMAL;
@@ -1937,10 +1914,10 @@ void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOpt
stateId = ETS_DISABLED;
else if (state & State_ReadOnly)
stateId = ETS_READONLY;
- else if (state & State_MouseOver)
- stateId = ETS_HOT;
else if (state & State_HasFocus)
stateId = ETS_SELECTED;
+ else if (state & State_MouseOver)
+ stateId = ETS_HOT;
QWindowsThemeData theme(widget, painter,
QWindowsVistaStylePrivate::EditTheme,
EP_EDITBORDER_NOSCROLL, stateId, option->rect);
@@ -2931,9 +2908,6 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption
else
theme.stateId = bullet ? MC_BULLETNORMAL: MC_CHECKMARKNORMAL;
d->drawBackground(theme);
- } else if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows11
- && !act) {
- painter->fillRect(checkRect, menuitem->palette.highlight().color().lighter(200));
}
}
@@ -3132,7 +3106,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption
QColor textShadow = qRgb(GetRValue(textShadowRef), GetGValue(textShadowRef), GetBValue(textShadowRef));
painter->setPen(textShadow);
drawItemText(painter, titleRect.adjusted(1, 1, 1, 1),
- Qt::AlignLeft | Qt::AlignBottom, dwOpt->palette,
+ Qt::AlignLeft | Qt::AlignBottom | Qt::TextHideMnemonic, dwOpt->palette,
dwOpt->state & State_Enabled, titleText);
}
@@ -3140,7 +3114,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption
QColor textColor = qRgb(GetRValue(captionText), GetGValue(captionText), GetBValue(captionText));
painter->setPen(textColor);
drawItemText(painter, titleRect,
- Qt::AlignLeft | Qt::AlignBottom, dwOpt->palette,
+ Qt::AlignLeft | Qt::AlignBottom | Qt::TextHideMnemonic, dwOpt->palette,
dwOpt->state & State_Enabled, titleText);
painter->setFont(oldFont);
painter->setPen(oldPen);
@@ -3155,7 +3129,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption
verticalTitleBar ? titleRect.height() : titleRect.width());
const int indent = 4;
drawItemText(painter, rect.adjusted(indent + 1, 1, -indent - 1, -1),
- Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic,
+ Qt::AlignLeft | Qt::AlignVCenter | Qt::TextHideMnemonic,
dwOpt->palette,
dwOpt->state & State_Enabled, titleText,
QPalette::WindowText);
@@ -4488,8 +4462,7 @@ QRect QWindowsVistaStyle::subControlRect(ComplexControl control, const QStyleOpt
#endif // QT_CONFIG(mdiarea)
default:
- return visualRect(option->direction, option->rect,
- QWindowsStyle::subControlRect(control, option, subControl, widget));
+ return QWindowsStyle::subControlRect(control, option, subControl, widget);
}
return visualRect(option->direction, option->rect, rect);
@@ -4642,8 +4615,8 @@ void QWindowsVistaStyle::polish(QWidget *widget)
buttonFont.setFamilies(QStringList{QLatin1String("Segoe UI")});
widget->setFont(buttonFont);
QPalette pal = widget->palette();
- pal.setColor(QPalette::ButtonText, QColor(21, 28, 85));
- pal.setColor(QPalette::BrightText, QColor(7, 64, 229));
+ pal.setColor(QPalette::Active, QPalette::ButtonText, QColor(21, 28, 85));
+ pal.setColor(QPalette::Active, QPalette::BrightText, QColor(7, 64, 229));
widget->setPalette(pal);
}
#endif // QT_CONFIG(commandlinkbutton)
@@ -4657,6 +4630,7 @@ void QWindowsVistaStyle::polish(QWidget *widget)
QColor textColor = QColor::fromRgb(bgRef);
QPalette pal;
pal.setColor(QPalette::All, QPalette::ToolTipText, textColor);
+ pal.setResolveMask(0);
widget->setPalette(pal);
}
} else if (qobject_cast<QMessageBox *> (widget)) {
@@ -4781,12 +4755,12 @@ void QWindowsVistaStyle::polish(QPalette &pal)
{
Q_D(QWindowsVistaStyle);
- if (qApp->styleHints()->colorScheme() == Qt::ColorScheme::Dark) {
+ if (QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Dark) {
// System runs in dark mode, but the Vista style cannot use a dark palette.
// Overwrite with the light system palette.
using QWindowsApplication = QNativeInterface::Private::QWindowsApplication;
if (auto nativeWindowsApp = dynamic_cast<QWindowsApplication *>(QGuiApplicationPrivate::platformIntegration()))
- nativeWindowsApp->lightSystemPalette(pal);
+ nativeWindowsApp->populateLightSystemPalette(pal);
}
QPixmapCache::clear();
diff --git a/src/plugins/styles/windowsvista/qwindowsvistastyle_p.h b/src/plugins/styles/modernwindows/qwindowsvistastyle_p.h
index c437b3e434..ff5300beca 100644
--- a/src/plugins/styles/windowsvista/qwindowsvistastyle_p.h
+++ b/src/plugins/styles/modernwindows/qwindowsvistastyle_p.h
@@ -59,7 +59,8 @@ public:
void unpolish(QWidget *widget) override;
void polish(QPalette &pal) override;
void polish(QApplication *app) override;
-
+protected:
+ QWindowsVistaStyle(QWindowsVistaStylePrivate &dd);
private:
Q_DISABLE_COPY_MOVE(QWindowsVistaStyle)
Q_DECLARE_PRIVATE(QWindowsVistaStyle)
diff --git a/src/plugins/styles/windowsvista/qwindowsvistastyle_p_p.h b/src/plugins/styles/modernwindows/qwindowsvistastyle_p_p.h
index 2c38ff4b3b..053e98b68d 100644
--- a/src/plugins/styles/windowsvista/qwindowsvistastyle_p_p.h
+++ b/src/plugins/styles/modernwindows/qwindowsvistastyle_p_p.h
@@ -77,6 +77,7 @@
#endif
#include <qlabel.h>
#include <qheaderview.h>
+#include <uxtheme.h>
QT_BEGIN_NAMESPACE
@@ -115,7 +116,6 @@ public:
static HTHEME createTheme(int theme, HWND hwnd);
static QString themeName(int theme);
- static inline bool hasTheme(int theme) { return theme >= 0 && theme < NThemes && m_themes[theme]; }
static bool isItemViewDelegateLineEdit(const QWidget *widget);
static int pixelMetricFromSystemDp(QStyle::PixelMetric pm, const QStyleOption *option = nullptr, const QWidget *widget = nullptr);
static int fixedPixelMetric(QStyle::PixelMetric pm);
@@ -169,7 +169,6 @@ private:
int bufferH = 0;
static HWND m_vistaTreeViewHelper;
- static HTHEME m_themes[NThemes];
};
QT_END_NAMESPACE
diff --git a/src/plugins/styles/windowsvista/main.cpp b/src/plugins/styles/windowsvista/main.cpp
deleted file mode 100644
index af832be0a8..0000000000
--- a/src/plugins/styles/windowsvista/main.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include <QtWidgets/private/qtwidgetsglobal_p.h>
-#include <QtWidgets/qstyleplugin.h>
-#include "qwindowsvistastyle_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class QWindowsVistaStylePlugin : public QStylePlugin
-{
- Q_OBJECT
- Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QStyleFactoryInterface" FILE "windowsvistastyle.json")
-public:
- QStyle *create(const QString &key) override;
-};
-
-QStyle *QWindowsVistaStylePlugin::create(const QString &key)
-{
- if (key.compare(QLatin1String("windowsvista"), Qt::CaseInsensitive) == 0)
- return new QWindowsVistaStyle();
-
- return nullptr;
-}
-
-QT_END_NAMESPACE
-
-#include "main.moc"
diff --git a/src/plugins/styles/windowsvista/windowsvistastyle.json b/src/plugins/styles/windowsvista/windowsvistastyle.json
deleted file mode 100644
index 771aa0c600..0000000000
--- a/src/plugins/styles/windowsvista/windowsvistastyle.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "Keys": [ "windowsvista" ]
-}
diff --git a/src/plugins/tls/openssl/qdtls_openssl.cpp b/src/plugins/tls/openssl/qdtls_openssl.cpp
index 78288d8dd1..fc07a29ec8 100644
--- a/src/plugins/tls/openssl/qdtls_openssl.cpp
+++ b/src/plugins/tls/openssl/qdtls_openssl.cpp
@@ -1,10 +1,6 @@
// Copyright (C) 2018 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef NOMINMAX
-#define NOMINMAX
-#endif // NOMINMAX
-
#include <QtNetwork/private/qnativesocketengine_p_p.h>
#include "qsslsocket_openssl_symbols_p.h"
diff --git a/src/plugins/tls/openssl/qsslcontext_openssl.cpp b/src/plugins/tls/openssl/qsslcontext_openssl.cpp
index ef0e63911a..75c192bd01 100644
--- a/src/plugins/tls/openssl/qsslcontext_openssl.cpp
+++ b/src/plugins/tls/openssl/qsslcontext_openssl.cpp
@@ -697,7 +697,9 @@ QT_WARNING_POP
return;
}
- if (!dhparams.isEmpty()) {
+ if (dhparams.isEmpty()) {
+ q_SSL_CTX_set_dh_auto(sslContext->ctx, 1);
+ } else {
#ifndef OPENSSL_NO_DEPRECATED_3_0
const QByteArray &params = dhparams.d->derData;
const char *ptr = params.constData();
diff --git a/src/plugins/tls/openssl/qssldiffiehellmanparameters_openssl.cpp b/src/plugins/tls/openssl/qssldiffiehellmanparameters_openssl.cpp
index 81cbc6a12d..16e31e605f 100644
--- a/src/plugins/tls/openssl/qssldiffiehellmanparameters_openssl.cpp
+++ b/src/plugins/tls/openssl/qssldiffiehellmanparameters_openssl.cpp
@@ -137,8 +137,9 @@ int QTlsBackendOpenSSL::dhParametersFromPem(const QByteArray &pem, QByteArray *d
if (isSafeDH(dh)) {
char *buf = nullptr;
const int len = q_i2d_DHparams(dh, reinterpret_cast<unsigned char **>(&buf));
+ const auto freeBuf = qScopeGuard([&] { q_OPENSSL_free(buf); });
if (len > 0)
- *data = QByteArray(buf, len);
+ data->assign({buf, len});
else
return DHParams::InvalidInputDataError;
} else {
diff --git a/src/plugins/tls/openssl/qsslsocket_openssl_symbols.cpp b/src/plugins/tls/openssl/qsslsocket_openssl_symbols.cpp
index 746a620d67..4aa9ca6fb1 100644
--- a/src/plugins/tls/openssl/qsslsocket_openssl_symbols.cpp
+++ b/src/plugins/tls/openssl/qsslsocket_openssl_symbols.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2017 The Qt Company Ltd.
// Copyright (C) 2014 BlackBerry Limited. All rights reserved.
// Copyright (C) 2016 Richard J. Moore <rich@kde.org>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
@@ -159,7 +159,6 @@ DEFINEFUNC3(int, CRYPTO_memcmp, const void * in_a, in_a, const void * in_b, in_b
DEFINEFUNC(long, OpenSSL_version_num, void, DUMMYARG, return 0, return)
DEFINEFUNC(const char *, OpenSSL_version, int a, a, return nullptr, return)
DEFINEFUNC(unsigned long, SSL_SESSION_get_ticket_lifetime_hint, const SSL_SESSION *session, session, return 0, return)
-DEFINEFUNC4(void, DH_get0_pqg, const DH *dh, dh, const BIGNUM **p, p, const BIGNUM **q, q, const BIGNUM **g, g, return, DUMMYARG)
#if QT_CONFIG(dtls)
DEFINEFUNC2(int, DTLSv1_listen, SSL *s, s, BIO_ADDR *c, c, return -1, return)
@@ -263,7 +262,6 @@ DEFINEFUNC4(int, OBJ_obj2txt, char *a, a, int b, b, ASN1_OBJECT *c, c, int d, d,
DEFINEFUNC(int, OBJ_obj2nid, const ASN1_OBJECT *a, a, return NID_undef, return)
DEFINEFUNC4(EVP_PKEY *, PEM_read_bio_PrivateKey, BIO *a, a, EVP_PKEY **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
-DEFINEFUNC4(DH *, PEM_read_bio_DHparams, BIO *a, a, DH **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
DEFINEFUNC7(int, PEM_write_bio_PrivateKey, BIO *a, a, EVP_PKEY *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
DEFINEFUNC7(int, PEM_write_bio_PrivateKey_traditional, BIO *a, a, EVP_PKEY *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
DEFINEFUNC4(EVP_PKEY *, PEM_read_bio_PUBKEY, BIO *a, a, EVP_PKEY **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
@@ -429,13 +427,21 @@ DEFINEFUNC2(void *, BIO_get_ex_data, BIO *b, b, int idx, idx, return nullptr, re
DEFINEFUNC3(int, BIO_set_ex_data, BIO *b, b, int idx, idx, void *data, data, return -1, return)
DEFINEFUNC3(void *, CRYPTO_malloc, size_t num, num, const char *file, file, int line, line, return nullptr, return)
+
+#ifndef OPENSSL_NO_DEPRECATED_3_0
DEFINEFUNC(DH *, DH_new, DUMMYARG, DUMMYARG, return nullptr, return)
DEFINEFUNC(void, DH_free, DH *dh, dh, return, DUMMYARG)
+DEFINEFUNC2(int, DH_check, DH *dh, dh, int *codes, codes, return 0, return)
+DEFINEFUNC4(void, DH_get0_pqg, const DH *dh, dh, const BIGNUM **p, p, const BIGNUM **q, q, const BIGNUM **g, g, return, DUMMYARG)
+
DEFINEFUNC3(DH *, d2i_DHparams, DH**a, a, const unsigned char **pp, pp, long length, length, return nullptr, return)
DEFINEFUNC2(int, i2d_DHparams, DH *a, a, unsigned char **p, p, return -1, return)
-DEFINEFUNC2(int, DH_check, DH *dh, dh, int *codes, codes, return 0, return)
+
+DEFINEFUNC4(DH *, PEM_read_bio_DHparams, BIO *a, a, DH **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
+#endif
DEFINEFUNC3(BIGNUM *, BN_bin2bn, const unsigned char *s, s, int len, len, BIGNUM *ret, ret, return nullptr, return)
+
#ifndef OPENSSL_NO_EC
DEFINEFUNC2(size_t, EC_get_builtin_curves, EC_builtin_curve * r, r, size_t nitems, nitems, return 0, return)
DEFINEFUNC(int, EC_curve_nist2nid, const char *name, name, return 0, return)
@@ -743,10 +749,22 @@ static LoadedOpenSsl loadOpenSsl()
#ifdef Q_OS_OPENBSD
libcrypto->setLoadHints(QLibrary::ExportExternalSymbolsHint);
#endif
-#if defined(SHLIB_VERSION_NUMBER) && !defined(Q_OS_QNX) // on QNX, the libs are always libssl.so and libcrypto.so
+
+#if !defined(Q_OS_QNX) // on QNX, the libs are always libssl.so and libcrypto.so
+
+#if defined(OPENSSL_SHLIB_VERSION)
+ // OpenSSL v.3 does not have SLIB_VERSION_NUMBER but has OPENSSL_SHLIB_VERSION.
+ // The comment about OPENSSL_SHLIB_VERSION in opensslv.h is a bit troublesome:
+ // "This is defined in free form."
+ auto shlibVersion = QString("%1"_L1).arg(OPENSSL_SHLIB_VERSION);
+ libssl->setFileNameAndVersion("ssl"_L1, shlibVersion);
+ libcrypto->setFileNameAndVersion("crypto"_L1, shlibVersion);
+#elif defined(SHLIB_VERSION_NUMBER)
// first attempt: the canonical name is libssl.so.<SHLIB_VERSION_NUMBER>
libssl->setFileNameAndVersion("ssl"_L1, SHLIB_VERSION_NUMBER ""_L1);
libcrypto->setFileNameAndVersion("crypto"_L1, SHLIB_VERSION_NUMBER ""_L1);
+#endif // OPENSSL_SHLIB_VERSION
+
if (libcrypto->load() && libssl->load()) {
// libssl.so.<SHLIB_VERSION_NUMBER> and libcrypto.so.<SHLIB_VERSION_NUMBER> found
return result;
@@ -754,7 +772,7 @@ static LoadedOpenSsl loadOpenSsl()
libssl->unload();
libcrypto->unload();
}
-#endif
+#endif // !defined(Q_OS_QNX)
#ifndef Q_OS_DARWIN
// second attempt: find the development files libssl.so and libcrypto.so
@@ -856,7 +874,6 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(OPENSSL_sk_num)
RESOLVEFUNC(OPENSSL_sk_pop_free)
RESOLVEFUNC(OPENSSL_sk_value)
- RESOLVEFUNC(DH_get0_pqg)
RESOLVEFUNC(SSL_CTX_set_options)
RESOLVEFUNC(SSL_set_info_callback)
RESOLVEFUNC(SSL_alert_type_string)
@@ -1015,7 +1032,6 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(OBJ_obj2txt)
RESOLVEFUNC(OBJ_obj2nid)
RESOLVEFUNC(PEM_read_bio_PrivateKey)
- RESOLVEFUNC(PEM_read_bio_DHparams)
RESOLVEFUNC(PEM_write_bio_PrivateKey)
RESOLVEFUNC(PEM_write_bio_PrivateKey_traditional)
RESOLVEFUNC(PEM_read_bio_PUBKEY)
@@ -1066,6 +1082,16 @@ bool q_resolveOpenSslSymbols()
#endif // OPENSSL_VERSION_MAJOR >= 3
#ifndef OPENSSL_NO_DEPRECATED_3_0
+ RESOLVEFUNC(DH_new)
+ RESOLVEFUNC(DH_free)
+ RESOLVEFUNC(DH_check)
+ RESOLVEFUNC(DH_get0_pqg)
+
+ RESOLVEFUNC(d2i_DHparams)
+ RESOLVEFUNC(i2d_DHparams)
+
+ RESOLVEFUNC(PEM_read_bio_DHparams)
+
RESOLVEFUNC(EVP_PKEY_assign)
RESOLVEFUNC(EVP_PKEY_cmp)
@@ -1210,11 +1236,6 @@ bool q_resolveOpenSslSymbols()
#endif // dtls
RESOLVEFUNC(CRYPTO_malloc)
- RESOLVEFUNC(DH_new)
- RESOLVEFUNC(DH_free)
- RESOLVEFUNC(d2i_DHparams)
- RESOLVEFUNC(i2d_DHparams)
- RESOLVEFUNC(DH_check)
RESOLVEFUNC(BN_bin2bn)
#ifndef OPENSSL_NO_EC
diff --git a/src/plugins/tls/openssl/qsslsocket_openssl_symbols_p.h b/src/plugins/tls/openssl/qsslsocket_openssl_symbols_p.h
index d020527476..a93c110b3f 100644
--- a/src/plugins/tls/openssl/qsslsocket_openssl_symbols_p.h
+++ b/src/plugins/tls/openssl/qsslsocket_openssl_symbols_p.h
@@ -233,7 +233,6 @@ void q_X509_STORE_set_verify_cb(X509_STORE *ctx, X509_STORE_CTX_verify_cb verify
int q_X509_STORE_set_ex_data(X509_STORE *ctx, int idx, void *data);
void *q_X509_STORE_get_ex_data(X509_STORE *r, int idx);
STACK_OF(X509) *q_X509_STORE_CTX_get0_chain(X509_STORE_CTX *ctx);
-void q_DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
# define q_SSL_load_error_strings() q_OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS \
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL)
@@ -391,7 +390,6 @@ int q_OBJ_obj2nid(const ASN1_OBJECT *a);
#define q_EVP_get_digestbynid(a) q_EVP_get_digestbyname(q_OBJ_nid2sn(a))
EVP_PKEY *q_PEM_read_bio_PrivateKey(BIO *a, EVP_PKEY **b, pem_password_cb *c, void *d);
-DH *q_PEM_read_bio_DHparams(BIO *a, DH **b, pem_password_cb *c, void *d);
int q_PEM_write_bio_PrivateKey(BIO *a, EVP_PKEY *b, const EVP_CIPHER *c, unsigned char *d,
int e, pem_password_cb *f, void *g);
int q_PEM_write_bio_PrivateKey_traditional(BIO *a, EVP_PKEY *b, const EVP_CIPHER *c, unsigned char *d,
@@ -504,14 +502,21 @@ X509 *q_X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx);
X509_STORE *q_X509_STORE_CTX_get0_store(X509_STORE_CTX *ctx);
// Diffie-Hellman support
+#ifndef OPENSSL_NO_DEPRECATED_3_0
DH *q_DH_new();
void q_DH_free(DH *dh);
+int q_DH_check(DH *dh, int *codes);
+void q_DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g);
+
DH *q_d2i_DHparams(DH **a, const unsigned char **pp, long length);
int q_i2d_DHparams(DH *a, unsigned char **p);
-int q_DH_check(DH *dh, int *codes);
+
+DH *q_PEM_read_bio_DHparams(BIO *a, DH **b, pem_password_cb *c, void *d);
+#endif // OPENSSL_NO_DEPRECATED_3_0
BIGNUM *q_BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
#define q_SSL_CTX_set_tmp_dh(ctx, dh) q_SSL_CTX_ctrl((ctx), SSL_CTRL_SET_TMP_DH, 0, (char *)dh)
+#define q_SSL_CTX_set_dh_auto(ctx, onoff) q_SSL_CTX_ctrl(ctx,SSL_CTRL_SET_DH_AUTO,onoff,NULL)
#ifndef OPENSSL_NO_EC
// EC Diffie-Hellman support
diff --git a/src/plugins/tls/openssl/qtls_openssl.cpp b/src/plugins/tls/openssl/qtls_openssl.cpp
index 031ccd9d15..57d09a649b 100644
--- a/src/plugins/tls/openssl/qtls_openssl.cpp
+++ b/src/plugins/tls/openssl/qtls_openssl.cpp
@@ -92,7 +92,7 @@ QSslCertificate findCertificateToFetch(const QList<QSslError> &tlsErrors, bool c
if (checkAIA) {
const auto extensions = certToFetch.extensions();
for (const auto &ext : extensions) {
- if (ext.oid() == QStringLiteral("1.3.6.1.5.5.7.1.1")) // See RFC 4325
+ if (ext.oid() == u"1.3.6.1.5.5.7.1.1") // See RFC 4325
return certToFetch;
}
//The only reason we check this extensions is because an application set trusted
diff --git a/src/plugins/tls/openssl/qtlsbackend_openssl.cpp b/src/plugins/tls/openssl/qtlsbackend_openssl.cpp
index 5ce5f45a5b..d73515724b 100644
--- a/src/plugins/tls/openssl/qtlsbackend_openssl.cpp
+++ b/src/plugins/tls/openssl/qtlsbackend_openssl.cpp
@@ -17,7 +17,7 @@
#include <QtNetwork/qssl.h>
#include <QtCore/qdir.h>
-#include <QtCore/qdiriterator.h>
+#include <QtCore/qdirlisting.h>
#include <QtCore/qlist.h>
#include <QtCore/qmutex.h>
#include <QtCore/qscopeguard.h>
@@ -204,11 +204,11 @@ void QTlsBackendOpenSSL::ensureCiphersAndCertsLoaded() const
#elif defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
// check whether we can enable on-demand root-cert loading (i.e. check whether the sym links are there)
const QList<QByteArray> dirs = QSslSocketPrivate::unixRootCertDirectories();
- QStringList symLinkFilter;
- symLinkFilter << "[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].[0-9]"_L1;
+ const QStringList symLinkFilter{
+ u"[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].[0-9]"_s};
for (const auto &dir : dirs) {
- QDirIterator iterator(QLatin1StringView(dir), symLinkFilter, QDir::Files);
- if (iterator.hasNext()) {
+ QDirListing dirList(QString::fromLatin1(dir), symLinkFilter, QDir::Files);
+ if (dirList.cbegin() != dirList.cend()) { // Not empty
QSslSocketPrivate::setRootCertOnDemandLoadingSupported(true);
break;
}
@@ -363,7 +363,9 @@ QList<QSslCertificate> systemCaCertificates()
QList<QSslCertificate> systemCerts;
#if defined(Q_OS_WIN)
HCERTSTORE hSystemStore;
- hSystemStore = CertOpenSystemStoreW(0, L"ROOT");
+ hSystemStore =
+ CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
+ CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER, L"ROOT");
if (hSystemStore) {
PCCERT_CONTEXT pc = nullptr;
while (1) {
@@ -392,10 +394,9 @@ QList<QSslCertificate> systemCaCertificates()
currentDir.setNameFilters(QStringList{QStringLiteral("*.pem"), QStringLiteral("*.crt")});
for (const auto &directory : directories) {
currentDir.setPath(QLatin1StringView(directory));
- QDirIterator it(currentDir);
- while (it.hasNext()) {
+ for (const auto &dirEntry : QDirListing(currentDir)) {
// use canonical path here to not load the same certificate twice if symlinked
- certFiles.insert(it.nextFileInfo().canonicalFilePath());
+ certFiles.insert(dirEntry.canonicalFilePath());
}
}
for (const QString& file : std::as_const(certFiles))
diff --git a/src/plugins/tls/openssl/qtlskey_openssl.cpp b/src/plugins/tls/openssl/qtlskey_openssl.cpp
index 8f54fda7fa..294fc2ffcd 100644
--- a/src/plugins/tls/openssl/qtlskey_openssl.cpp
+++ b/src/plugins/tls/openssl/qtlskey_openssl.cpp
@@ -222,7 +222,7 @@ Qt::HANDLE TlsKeyOpenSSL::handle() const
#else
qCWarning(lcTlsBackend,
"This version of OpenSSL disabled direct manipulation with RSA/DSA/DH/EC_KEY structures, consider using QSsl::Opaque instead.");
- return Qt::HANDLE(nullptr);
+ return Qt::HANDLE(genericKey);
#endif
}
diff --git a/src/plugins/tls/openssl/qwindowscarootfetcher.cpp b/src/plugins/tls/openssl/qwindowscarootfetcher.cpp
index 82ad3abfd0..a18aae0b71 100644
--- a/src/plugins/tls/openssl/qwindowscarootfetcher.cpp
+++ b/src/plugins/tls/openssl/qwindowscarootfetcher.cpp
@@ -245,3 +245,5 @@ QHCertStorePointer QWindowsCaRootFetcher::createAdditionalStore() const
}
QT_END_NAMESPACE
+
+#include "moc_qwindowscarootfetcher_p.cpp"
diff --git a/src/plugins/tls/schannel/CMakeLists.txt b/src/plugins/tls/schannel/CMakeLists.txt
index 9a53bf9ee6..a7f7fcd99f 100644
--- a/src/plugins/tls/schannel/CMakeLists.txt
+++ b/src/plugins/tls/schannel/CMakeLists.txt
@@ -29,4 +29,6 @@ qt_internal_add_plugin(QSchannelBackendPlugin
secur32
bcrypt
ncrypt
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
)
diff --git a/src/plugins/tls/schannel/qtls_schannel.cpp b/src/plugins/tls/schannel/qtls_schannel.cpp
index b230f2f787..a244a90ebc 100644
--- a/src/plugins/tls/schannel/qtls_schannel.cpp
+++ b/src/plugins/tls/schannel/qtls_schannel.cpp
@@ -26,17 +26,11 @@
#include <security.h>
#include <schnlsp.h>
-#if NTDDI_VERSION >= NTDDI_WINBLUE && !defined(Q_CC_MINGW)
+#if NTDDI_VERSION >= NTDDI_WINBLUE && defined(SECBUFFER_APPLICATION_PROTOCOLS)
// ALPN = Application Layer Protocol Negotiation
#define SUPPORTS_ALPN 1
#endif
-// Redstone 5/1809 has all the API available, but TLS 1.3 is not enabled until a later version of
-// Win 10, checked at runtime in supportsTls13()
-#if defined(NTDDI_WIN10_RS5) && NTDDI_VERSION >= NTDDI_WIN10_RS5
-#define SUPPORTS_TLS13 1
-#endif
-
// Not defined in MinGW
#ifndef SECBUFFER_ALERT
#define SECBUFFER_ALERT 17
@@ -93,6 +87,12 @@
#ifndef SP_PROT_TLS1_3
#define SP_PROT_TLS1_3 (SP_PROT_TLS1_3_CLIENT | SP_PROT_TLS1_3_SERVER)
#endif
+#ifndef BCRYPT_ECDH_ALGORITHM
+#define BCRYPT_ECDH_ALGORITHM L"ECDH"
+#endif
+#ifndef BCRYPT_ECDSA_ALGORITHM
+#define BCRYPT_ECDSA_ALGORITHM L"ECDSA"
+#endif
/*
@future!:
@@ -114,10 +114,6 @@
- Check if SEC_I_INCOMPLETE_CREDENTIALS is still returned for both "missing certificate" and
"missing PSK" when calling InitializeSecurityContext in "performHandshake".
- Medium priority:
- - Setting cipher-suites (or ALG_ID)
- - People have survived without it in WinRT
-
Low priority:
- Possibly make RAII wrappers for SecBuffer (which I commonly create QScopeGuards for)
@@ -133,39 +129,341 @@ Q_LOGGING_CATEGORY(lcTlsBackendSchannel, "qt.tlsbackend.schannel");
QByteArray _q_makePkcs12(const QList<QSslCertificate> &certs, const QSslKey &key,
const QString &passPhrase);
+namespace {
+bool supportsTls13();
+}
+
namespace QTlsPrivate {
-QList<QSslCipher> defaultCiphers()
+QList<QSslCipher> defaultCiphers();
+
+struct SchannelCipherInfo {
+ const char *openSslCipherSuite;
+ const char *schannelCipherSuite;
+ const char *keyExchangeMethod;
+ const char *authenticationMethod;
+ const char *encryptionMethod;
+ int encryptionBits;
+ const char *hashMethod;
+ QList<QSsl::SslProtocol> protocols;
+};
+
+// The list of supported ciphers according to
+// https://learn.microsoft.com/en-us/windows/win32/secauthn/tls-cipher-suites-in-windows-server-2022
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+std::array<SchannelCipherInfo, 44> schannelCipherInfo = {{
+ {"TLS_AES_256_GCM_SHA384", "TLS_AES_256_GCM_SHA384", "", "", "AES", 256, "SHA384", {QSsl::TlsV1_3}},
+ {"TLS_AES_128_GCM_SHA256", "TLS_AES_128_GCM_SHA256", "", "", "AES", 128, "SHA256", {QSsl::TlsV1_3}},
+ {"ECDHE-ECDSA-AES256-GCM-SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "ECDH", "ECDSA", "AES", 256, "SHA384", {QSsl::TlsV1_2}},
+ {"ECDHE-ECDSA-AES128-GCM-SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "ECDH", "ECDSA", "AES", 128, "SHA256", {QSsl::TlsV1_2}},
+ {"ECDHE-RSA-AES256-GCM-SHA384", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "ECDH", "RSA", "AES", 256, "SHA384", {QSsl::TlsV1_2}},
+ {"ECDHE-RSA-AES128-GCM-SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "ECDH", "RSA", "AES", 128, "SHA256", {QSsl::TlsV1_2}},
+ {"DHE-RSA-AES256-GCM-SHA384", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "DH", "RSA", "AES", 256, "SHA384", {QSsl::TlsV1_2}},
+ {"DHE-RSA-AES128-GCM-SHA256", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "DH", "RSA", "AES", 128, "SHA256", {QSsl::TlsV1_2}},
+ {"ECDHE-ECDSA-AES256-SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "ECDH", "ECDSA", "AES", 256, "SHA384", {QSsl::TlsV1_2}},
+ {"ECDHE-ECDSA-AES128-SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "ECDH", "ECDSA", "AES", 128, "SHA256", {QSsl::TlsV1_2}},
+ {"ECDHE-RSA-AES256-SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "ECDH", "RSA", "AES", 256, "SHA384", {QSsl::TlsV1_2}},
+ {"ECDHE-RSA-AES128-SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "ECDH", "RSA", "AES", 128, "SHA256", {QSsl::TlsV1_2}},
+ {"ECDHE-ECDSA-AES256-SHA", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "ECDH", "ECDSA", "AES", 256, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"ECDHE-ECDSA-AES128-SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "ECDH", "ECDSA", "AES", 128, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"ECDHE-RSA-AES256-SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "ECDH", "RSA", "AES", 256, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"ECDHE-RSA-AES128-SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "ECDH", "RSA", "AES", 128, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"AES256-GCM-SHA384", "TLS_RSA_WITH_AES_256_GCM_SHA384", "RSA", "RSA", "AES", 256, "SHA384", {QSsl::TlsV1_2}},
+ {"AES128-GCM-SHA256", "TLS_RSA_WITH_AES_128_GCM_SHA256", "RSA", "RSA", "AES", 128, "SHA256", {QSsl::TlsV1_2}},
+ {"AES256-SHA256", "TLS_RSA_WITH_AES_256_CBC_SHA256", "RSA", "RSA", "AES", 256, "SHA256", {QSsl::TlsV1_2}},
+ {"AES128-SHA256", "TLS_RSA_WITH_AES_128_CBC_SHA256", "RSA", "RSA", "AES", 128, "SHA256", {QSsl::TlsV1_2}},
+ {"AES256-SHA", "TLS_RSA_WITH_AES_256_CBC_SHA", "RSA", "RSA", "AES", 256, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"AES128-SHA", "TLS_RSA_WITH_AES_128_CBC_SHA", "RSA", "RSA", "AES", 128, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"DES-CBC3-SHA", "TLS_RSA_WITH_3DES_EDE_CBC_SHA", "RSA", "RSA", "3DES", 168, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"NULL-SHA256", "TLS_RSA_WITH_NULL_SHA256", "RSA", "RSA", "", 0, "SHA256", {QSsl::TlsV1_2}},
+ {"NULL-SHA", "TLS_RSA_WITH_NULL_SHA", "RSA", "RSA", "", 0, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+
+ // the following cipher suites are not enabled by default in schannel provider
+ {"TLS_CHACHA20_POLY1305_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "", "", "CHACHA20_POLY1305", 0, "", {QSsl::TlsV1_3}},
+ {"DHE-RSA-AES256-SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "DH", "RSA", "AES", 256, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"DHE-RSA-AES128-SHA", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "DH", "RSA", "AES", 128, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"DHE-DSS-AES256-SHA256", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "DH", "DSA", "AES", 256, "SHA256", {QSsl::TlsV1_2}},
+ {"DHE-DSS-AES128-SHA256", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "DH", "DSA", "AES", 128, "SHA256", {QSsl::TlsV1_2}},
+ {"DHE-DSS-AES256-SHA", "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "DH", "DSA", "AES", 256, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"DHE-DSS-AES128-SHA", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "DH", "DSA", "AES", 128, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"EDH-DSS-DES-CBC3-SHA", "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", "DH", "DSA", "3DES", 168, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"RC4-SHA", "TLS_RSA_WITH_RC4_128_SHA", "RSA", "RSA", "RC4", 128, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"RC4-MD5", "TLS_RSA_WITH_RC4_128_MD5", "RSA", "RSA", "RC4", 128, "MD5", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"DES-CBC-SHA", "TLS_RSA_WITH_DES_CBC_SHA", "RSA", "RSA", "DES", 56, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"EDH-DSS-DES-CBC-SHA", "TLS_DHE_DSS_WITH_DES_CBC_SHA", "DH", "DSA", "DES", 56, "SHA1", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+ {"NULL-MD5", "TLS_RSA_WITH_NULL_MD5", "RSA", "RSA", "", 0, "MD5", {QSsl::TlsV1_2, QSsl::TlsV1_1, QSsl::TlsV1_0}},
+
+ // PSK cipher suites
+ {"PSK-AES256-GCM-SHA384", "TLS_PSK_WITH_AES_256_GCM_SHA384", "PSK", "", "AES", 256, "SHA384", {QSsl::TlsV1_2}},
+ {"PSK-AES128-GCM-SHA256", "TLS_PSK_WITH_AES_128_GCM_SHA256", "PSK", "", "AES", 128, "SHA256", {QSsl::TlsV1_2}},
+ {"PSK-AES256-CBC-SHA384", "TLS_PSK_WITH_AES_256_CBC_SHA384", "PSK", "", "AES", 256, "SHA384", {QSsl::TlsV1_2}},
+ {"PSK-AES128-CBC-SHA256", "TLS_PSK_WITH_AES_128_CBC_SHA256", "PSK", "", "AES", 128, "SHA256", {QSsl::TlsV1_2}},
+ {"PSK-NULL-SHA384", "TLS_PSK_WITH_NULL_SHA384", "PSK", "", "", 0, "SHA384", {QSsl::TlsV1_2}},
+ {"PSK-NULL-SHA256", "TLS_PSK_WITH_NULL_SHA256", "PSK", "", "", 0, "SHA256", {QSsl::TlsV1_2}},
+}};
+QT_WARNING_POP
+
+const SchannelCipherInfo *cipherInfoByOpenSslName(const QString &name)
+{
+ for (const auto &cipherInfo : schannelCipherInfo) {
+ if (name == QLatin1StringView(cipherInfo.openSslCipherSuite))
+ return &cipherInfo;
+ }
+
+ return nullptr;
+}
+
+UNICODE_STRING cbcChainingMode = {
+ sizeof(BCRYPT_CHAIN_MODE_CBC) - 2,
+ sizeof(BCRYPT_CHAIN_MODE_CBC),
+ const_cast<PWSTR>(BCRYPT_CHAIN_MODE_CBC)
+};
+
+UNICODE_STRING gcmChainingMode = {
+ sizeof(BCRYPT_CHAIN_MODE_GCM) - 2,
+ sizeof(BCRYPT_CHAIN_MODE_GCM),
+ const_cast<PWSTR>(BCRYPT_CHAIN_MODE_GCM)
+};
+
+/**
+ Determines which algorithms are not used by the requested ciphers to build
+ up a black list that can be passed to SCH_CREDENTIALS.
+ */
+QList<CRYPTO_SETTINGS> cryptoSettingsForCiphers(const QList<QSslCipher> &ciphers)
+{
+ static const QList<QSslCipher> defaultCipherList = defaultCiphers();
+
+ if (defaultCipherList == ciphers) {
+ // the ciphers have not been restricted for this session, so no black listing needed
+ return {};
+ }
+
+ QList<const SchannelCipherInfo*> cipherInfo;
+
+ for (const auto &cipher : ciphers) {
+ if (cipher.isNull())
+ continue;
+
+ const auto *info = cipherInfoByOpenSslName(cipher.name());
+ if (!cipherInfo.contains(info))
+ cipherInfo.append(info);
+ }
+
+ QList<CRYPTO_SETTINGS> cryptoSettings;
+
+ const auto assignUnicodeString = [](UNICODE_STRING &unicodeString, const wchar_t *characters) {
+ unicodeString.Length = static_cast<USHORT>(wcslen(characters) * sizeof(WCHAR));
+ unicodeString.MaximumLength = unicodeString.Length + sizeof(UNICODE_NULL);
+ unicodeString.Buffer = const_cast<wchar_t*>(characters);
+ };
+
+ // black list of key exchange algorithms
+ const auto allKeyExchangeAlgorithms = {BCRYPT_RSA_ALGORITHM,
+ BCRYPT_ECDH_ALGORITHM,
+ BCRYPT_DH_ALGORITHM};
+
+ for (const auto &algorithm : allKeyExchangeAlgorithms) {
+ const auto method = QStringView(algorithm);
+
+ const auto usesMethod = [method](const SchannelCipherInfo *info) {
+ return QLatin1StringView(info->keyExchangeMethod) == method;
+ };
+
+ const bool exclude = std::none_of(cipherInfo.cbegin(), cipherInfo.cend(), usesMethod);
+
+ if (exclude) {
+ CRYPTO_SETTINGS settings = {};
+ settings.eAlgorithmUsage = TlsParametersCngAlgUsageKeyExchange;
+ assignUnicodeString(settings.strCngAlgId, algorithm);
+ cryptoSettings.append(settings);
+ }
+ }
+
+ // black list of authentication algorithms
+ const auto allAuthenticationAlgorithms = {BCRYPT_RSA_ALGORITHM,
+ BCRYPT_DSA_ALGORITHM,
+ BCRYPT_ECDSA_ALGORITHM,
+ BCRYPT_DH_ALGORITHM};
+
+ for (const auto &algorithm : allAuthenticationAlgorithms) {
+ const auto method = QStringView(algorithm);
+
+ const auto usesMethod = [method](const SchannelCipherInfo *info) {
+ return QLatin1StringView(info->authenticationMethod) == method;
+ };
+
+ const bool exclude = std::none_of(cipherInfo.begin(), cipherInfo.end(), usesMethod);
+
+ if (exclude) {
+ CRYPTO_SETTINGS settings = {};
+ settings.eAlgorithmUsage = TlsParametersCngAlgUsageSignature;
+ assignUnicodeString(settings.strCngAlgId, algorithm);
+ cryptoSettings.append(settings);
+ }
+ }
+
+
+ // black list of encryption algorithms
+ const auto allEncryptionAlgorithms = {BCRYPT_AES_ALGORITHM,
+ BCRYPT_RC4_ALGORITHM,
+ BCRYPT_DES_ALGORITHM,
+ BCRYPT_3DES_ALGORITHM};
+
+ for (const auto &algorithm : allEncryptionAlgorithms) {
+ const auto method = QStringView(algorithm);
+
+ if (method == QLatin1StringView("AES")) {
+ bool uses128Bit = false;
+ bool uses256Bit = false;
+ bool usesGcm = false;
+ bool usesCbc = false;
+ for (const auto *info : cipherInfo) {
+ if (QLatin1StringView(info->encryptionMethod) == method) {
+ uses128Bit = uses128Bit || (info->encryptionBits == 128);
+ uses256Bit = uses256Bit || (info->encryptionBits == 256);
+ usesGcm = usesGcm ||
+ QLatin1StringView(info->schannelCipherSuite).contains("_GCM_"_L1);
+ usesCbc = usesCbc ||
+ QLatin1StringView(info->schannelCipherSuite).contains("_CBC_"_L1);
+ }
+ }
+
+ CRYPTO_SETTINGS settings = {};
+ settings.eAlgorithmUsage = TlsParametersCngAlgUsageCipher;
+ assignUnicodeString(settings.strCngAlgId, algorithm);
+
+ if (usesGcm && !usesCbc) {
+ settings.cChainingModes = 1;
+ settings.rgstrChainingModes = &cbcChainingMode;
+ } else if (!usesGcm && usesCbc) {
+ settings.cChainingModes = 1;
+ settings.rgstrChainingModes = &gcmChainingMode;
+ }
+
+ if (!uses128Bit && uses256Bit) {
+ settings.dwMinBitLength = 256;
+ cryptoSettings.append(settings);
+ } else if (uses128Bit && !uses256Bit) {
+ settings.dwMaxBitLength = 128;
+ cryptoSettings.append(settings);
+ } else if (!uses128Bit && !uses256Bit) {
+ cryptoSettings.append(settings);
+ }
+ } else {
+ const auto usesMethod = [method](const SchannelCipherInfo *info) {
+ return QLatin1StringView(info->encryptionMethod) == method;
+ };
+
+ const bool exclude = std::none_of(cipherInfo.begin(), cipherInfo.end(), usesMethod);
+
+ if (exclude) {
+ CRYPTO_SETTINGS settings = {};
+ settings.eAlgorithmUsage = TlsParametersCngAlgUsageCipher;
+ assignUnicodeString(settings.strCngAlgId, algorithm);
+ cryptoSettings.append(settings);
+ }
+ }
+ }
+
+ // black list of hash algorithms
+ const auto allHashAlgorithms = {BCRYPT_MD5_ALGORITHM,
+ BCRYPT_SHA1_ALGORITHM,
+ BCRYPT_SHA256_ALGORITHM,
+ BCRYPT_SHA384_ALGORITHM};
+
+ for (const auto &algorithm : allHashAlgorithms) {
+ const auto method = QStringView(algorithm);
+
+ const auto usesMethod = [method](const SchannelCipherInfo *info) {
+ return QLatin1StringView(info->hashMethod) == method;
+ };
+
+ const bool exclude = std::none_of(cipherInfo.begin(), cipherInfo.end(), usesMethod);
+
+ if (exclude) {
+ CRYPTO_SETTINGS settings = {};
+ settings.eAlgorithmUsage = TlsParametersCngAlgUsageDigest;
+ assignUnicodeString(settings.strCngAlgId, algorithm);
+ cryptoSettings.append(settings);
+ }
+ }
+
+ return cryptoSettings;
+}
+
+QList<QSslCipher> ciphersByName(QStringView schannelSuiteName)
{
- // Previously the code was in QSslSocketBackendPrivate.
QList<QSslCipher> ciphers;
- const QString protocolStrings[] = { QStringLiteral("TLSv1"), QStringLiteral("TLSv1.1"),
- QStringLiteral("TLSv1.2"), QStringLiteral("TLSv1.3") };
+
+ for (const auto &cipher : schannelCipherInfo) {
+ if (QLatin1StringView(cipher.schannelCipherSuite) == schannelSuiteName) {
+ for (const auto &protocol : cipher.protocols) {
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
- const QSsl::SslProtocol protocols[] = { QSsl::TlsV1_0, QSsl::TlsV1_1,
- QSsl::TlsV1_2, QSsl::TlsV1_3 };
+ const QString protocolName = (
+ protocol == QSsl::TlsV1_0 ? QStringLiteral("TLSv1.0") :
+ protocol == QSsl::TlsV1_1 ? QStringLiteral("TLSv1.1") :
+ protocol == QSsl::TlsV1_2 ? QStringLiteral("TLSv1.2") :
+ protocol == QSsl::TlsV1_3 ? QStringLiteral("TLSv1.3") :
+ QString());
QT_WARNING_POP
- const int size = ARRAYSIZE(protocols);
- static_assert(size == ARRAYSIZE(protocolStrings));
- ciphers.reserve(size);
- for (int i = 0; i < size; ++i) {
- const QSslCipher cipher = QTlsBackend::createCipher(QStringLiteral("Schannel"),
- protocols[i], protocolStrings[i]);
- ciphers.append(cipher);
+ ciphers.append(QTlsBackend::createCiphersuite(QLatin1StringView(cipher.openSslCipherSuite),
+ QLatin1StringView(cipher.keyExchangeMethod),
+ QLatin1StringView(cipher.encryptionMethod),
+ QLatin1StringView(cipher.authenticationMethod),
+ cipher.encryptionBits,
+ protocol, protocolName));
+ }
+ }
}
return ciphers;
-
}
-} // namespace QTlsPrivate
+QList<QSslCipher> defaultCiphers()
+{
+ ULONG contextFunctionsCount = {};
+ PCRYPT_CONTEXT_FUNCTIONS contextFunctions = {};
-namespace {
-bool supportsTls13();
+ const auto status = BCryptEnumContextFunctions(CRYPT_LOCAL, L"SSL", NCRYPT_SCHANNEL_INTERFACE,
+ &contextFunctionsCount, &contextFunctions);
+ if (!NT_SUCCESS(status)) {
+ qCWarning(lcTlsBackendSchannel, "Failed to enumerate ciphers");
+ return {};
+ }
+
+ const bool supportsV13 = supportsTls13();
+
+ QList<QSslCipher> ciphers;
+
+ for (ULONG index = 0; index < contextFunctions->cFunctions; ++index) {
+ const auto suiteName = QStringView(contextFunctions->rgpszFunctions[index]);
+
+ const QList<QSslCipher> allCiphers = ciphersByName(suiteName);
+
+ for (const auto &cipher : allCiphers) {
+ if (!supportsV13 && (cipher.protocol() == QSsl::TlsV1_3))
+ continue;
+
+ ciphers.append(cipher);
+ }
+ }
+
+ BCryptFreeBuffer(contextFunctions);
+
+ return ciphers;
}
+bool containsTls13Cipher(const QList<QSslCipher> &ciphers)
+{
+ return std::any_of(ciphers.cbegin(), ciphers.cend(),
+ [](const QSslCipher &cipher) { return cipher.protocol() == QSsl::TlsV1_3; });
+}
+
+} // namespace QTlsPrivate
+
bool QSchannelBackend::s_loadedCiphersAndCerts = false;
Q_GLOBAL_STATIC(QRecursiveMutex, qt_schannel_mutex)
@@ -298,7 +596,11 @@ QList<QSslCertificate> QSchannelBackend::systemCaCertificatesImplementation()
// Similar to non-Darwin version found in qtlsbackend_openssl.cpp,
// QTlsPrivate::systemCaCertificates function.
QList<QSslCertificate> systemCerts;
- auto hSystemStore = QHCertStorePointer(CertOpenSystemStore(0, L"ROOT"));
+
+ auto hSystemStore = QHCertStorePointer(
+ CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
+ CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER, L"ROOT"));
+
if (hSystemStore) {
PCCERT_CONTEXT pc = nullptr;
while ((pc = CertFindCertificateInStore(hSystemStore.get(), X509_ASN_ENCODING, 0,
@@ -319,6 +621,11 @@ QTlsPrivate::X509DerReaderPtr QSchannelBackend::X509DerReader() const
return QTlsPrivate::X509CertificateGeneric::certificatesFromDer;
}
+QTlsPrivate::X509Pkcs12ReaderPtr QSchannelBackend::X509Pkcs12Reader() const
+{
+ return QTlsPrivate::X509CertificateSchannel::importPkcs12;
+}
+
namespace {
SecBuffer createSecBuffer(void *ptr, unsigned long length, unsigned long bufferType)
@@ -383,7 +690,6 @@ QString schannelErrorToString(qint32 status)
bool supportsTls13()
{
-#ifdef SUPPORTS_TLS13
static bool supported = []() {
const auto current = QOperatingSystemVersion::current();
// 20221 just happens to be the preview version I run on my laptop where I tested TLS 1.3.
@@ -391,10 +697,8 @@ bool supportsTls13()
QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 20221);
return current >= minimum;
}();
+
return supported;
-#else
- return false;
-#endif
}
DWORD toSchannelProtocol(QSsl::SslProtocol protocol)
@@ -459,17 +763,15 @@ QT_WARNING_POP
return protocols;
}
-#ifdef SUPPORTS_TLS13
// In the new API that descended down upon us we are not asked which protocols we want
// but rather which protocols we don't want. So now we have this function to disable
// anything that is not enabled.
-DWORD toSchannelProtocolNegated(QSsl::SslProtocol protocol)
+DWORD negatedSchannelProtocols(DWORD wantedProtocols)
{
DWORD protocols = SP_PROT_ALL; // all protocols
- protocols &= ~toSchannelProtocol(protocol); // minus the one(s) we want
+ protocols &= ~wantedProtocols; // minus the one(s) we want
return protocols;
}
-#endif
/*!
\internal
@@ -507,8 +809,7 @@ bool netscapeWrongCertType(const QList<QSslCertificateExtension> &extensions, bo
const auto netscapeIt = std::find_if(
extensions.cbegin(), extensions.cend(),
[](const QSslCertificateExtension &extension) {
- const auto netscapeCertType = QStringLiteral("2.16.840.1.113730.1.1");
- return extension.oid() == netscapeCertType;
+ return extension.oid() == u"2.16.840.1.113730.1.1";
});
if (netscapeIt != extensions.cend()) {
const QByteArray netscapeCertTypeByte = netscapeIt->value().toByteArray();
@@ -722,6 +1023,10 @@ bool TlsCryptographSchannel::sendToken(void *token, unsigned long tokenLength, b
Q_ASSERT(d);
auto *plainSocket = d->plainTcpSocket();
Q_ASSERT(plainSocket);
+ if (plainSocket->state() == QAbstractSocket::UnconnectedState || !plainSocket->isValid()
+ || !plainSocket->isOpen()) {
+ return false;
+ }
const qint64 written = plainSocket->write(static_cast<const char *>(token), tokenLength);
if (written != qint64(tokenLength)) {
@@ -784,7 +1089,7 @@ bool TlsCryptographSchannel::acquireCredentialsHandle()
Q_ASSERT(schannelState == SchannelState::InitializeHandshake);
const bool isClient = d->tlsMode() == QSslSocket::SslClientMode;
- const DWORD protocols = toSchannelProtocol(configuration.protocol());
+ DWORD protocols = toSchannelProtocol(configuration.protocol());
if (protocols == DWORD(-1)) {
setErrorAndEmit(d, QAbstractSocket::SslInvalidUserDataError,
QSslSocket::tr("Invalid protocol chosen"));
@@ -838,78 +1143,50 @@ bool TlsCryptographSchannel::acquireCredentialsHandle()
certsCount = 1;
Q_ASSERT(localCertContext);
}
- void *credentials = nullptr;
-#ifdef SUPPORTS_TLS13
+
+ const QList<QSslCipher> ciphers = configuration.ciphers();
+ if (!ciphers.isEmpty() && !containsTls13Cipher(ciphers))
+ protocols &= ~SP_PROT_TLS1_3;
+
+ QList<CRYPTO_SETTINGS> cryptoSettings;
+ if (!ciphers.isEmpty())
+ cryptoSettings = cryptoSettingsForCiphers(ciphers);
+
TLS_PARAMETERS tlsParameters = {
0,
nullptr,
- toSchannelProtocolNegated(configuration.protocol()), // what protocols to disable
+ negatedSchannelProtocols(protocols), // what protocols to disable
+ static_cast<DWORD>(cryptoSettings.size()),
+ (cryptoSettings.isEmpty() ? nullptr : cryptoSettings.data()),
+ 0
+ };
+
+ SCH_CREDENTIALS credentials = {
+ SCH_CREDENTIALS_VERSION,
0,
+ certsCount,
+ &localCertContext,
nullptr,
- 0
+ 0,
+ nullptr,
+ 0,
+ SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT | defaultCredsFlag(),
+ 1,
+ &tlsParameters
};
- if (supportsTls13()) {
- SCH_CREDENTIALS *cred = new SCH_CREDENTIALS{
- SCH_CREDENTIALS_VERSION,
- 0,
- certsCount,
- &localCertContext,
- nullptr,
- 0,
- nullptr,
- 0,
- SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT | defaultCredsFlag(),
- 1,
- &tlsParameters
- };
- credentials = cred;
- } else
-#endif // SUPPORTS_TLS13
- {
- SCHANNEL_CRED *cred = new SCHANNEL_CRED{
- SCHANNEL_CRED_VERSION, // dwVersion
- certsCount, // cCreds
- &localCertContext, // paCred (certificate(s) containing a private key for authentication)
- nullptr, // hRootStore
-
- 0, // cMappers (reserved)
- nullptr, // aphMappers (reserved)
-
- 0, // cSupportedAlgs
- nullptr, // palgSupportedAlgs (nullptr = system default)
-
- protocols, // grbitEnabledProtocols
- 0, // dwMinimumCipherStrength (0 = system default)
- 0, // dwMaximumCipherStrength (0 = system default)
- 0, // dwSessionLifespan (0 = schannel default, 10 hours)
- SCH_CRED_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT | defaultCredsFlag(), // dwFlags
- 0 // dwCredFormat (must be 0)
- };
- credentials = cred;
- }
- Q_ASSERT(credentials != nullptr);
TimeStamp expiration{};
auto status = AcquireCredentialsHandle(nullptr, // pszPrincipal (unused)
const_cast<wchar_t *>(UNISP_NAME), // pszPackage
isClient ? SECPKG_CRED_OUTBOUND : SECPKG_CRED_INBOUND, // fCredentialUse
nullptr, // pvLogonID (unused)
- credentials, // pAuthData
+ &credentials, // pAuthData
nullptr, // pGetKeyFn (unused)
nullptr, // pvGetKeyArgument (unused)
&credentialHandle, // phCredential
&expiration // ptsExpir
);
-#ifdef SUPPORTS_TLS13
- if (supportsTls13()) {
- delete static_cast<SCH_CREDENTIALS *>(credentials);
- } else
-#endif // SUPPORTS_TLS13
- {
- delete static_cast<SCHANNEL_CRED *>(credentials);
- }
-
if (status != SEC_E_OK) {
setErrorAndEmit(d, QAbstractSocket::SslInternalError, schannelErrorToString(status));
return false;
@@ -1114,7 +1391,8 @@ bool TlsCryptographSchannel::performHandshake()
auto *plainSocket = d->plainTcpSocket();
Q_ASSERT(plainSocket);
- if (plainSocket->state() == QAbstractSocket::UnconnectedState) {
+ if (plainSocket->state() == QAbstractSocket::UnconnectedState || !plainSocket->isValid()
+ || !plainSocket->isOpen()) {
setErrorAndEmit(d, QAbstractSocket::RemoteHostClosedError,
QSslSocket::tr("The TLS/SSL connection has been closed"));
return false;
@@ -1283,6 +1561,11 @@ bool TlsCryptographSchannel::verifyHandshake()
// Get session cipher info
status = QueryContextAttributes(&contextHandle,
+ SECPKG_ATTR_CIPHER_INFO,
+ &cipherInfo);
+ CHECK_STATUS(status);
+
+ status = QueryContextAttributes(&contextHandle,
SECPKG_ATTR_CONNECTION_INFO,
&connectionInfo);
CHECK_STATUS(status);
@@ -1435,6 +1718,7 @@ void TlsCryptographSchannel::reset()
deallocateContext();
freeCredentialsHandle(); // in case we already had one (@future: session resumption requires re-use)
+ cipherInfo = {};
connectionInfo = {};
streamSizes = {};
@@ -1484,8 +1768,10 @@ void TlsCryptographSchannel::transmit()
return; // This function should not have been called
// Can happen if called through QSslSocket::abort->QSslSocket::close->QSslSocket::flush->here
- if (plainSocket->state() == QAbstractSocket::SocketState::UnconnectedState)
+ if (plainSocket->state() == QAbstractSocket::UnconnectedState || !plainSocket->isValid()
+ || !plainSocket->isOpen()) {
return;
+ }
if (schannelState != SchannelState::Done) {
continueHandshake();
@@ -1637,8 +1923,12 @@ void TlsCryptographSchannel::transmit()
qCWarning(lcTlsBackendSchannel, "The internal SSPI handle is invalid!");
Q_UNREACHABLE();
} else if (status == SEC_E_INVALID_TOKEN) {
- qCWarning(lcTlsBackendSchannel, "Got SEC_E_INVALID_TOKEN!");
- Q_UNREACHABLE(); // Happened once due to a bug, but shouldn't generally happen(?)
+ // Supposedly we have an invalid token, it's under-documented what
+ // this means, so to be safe we disconnect.
+ shutdown = true;
+ disconnectFromHost();
+ setErrorAndEmit(d, QAbstractSocket::SslInternalError, schannelErrorToString(status));
+ break;
} else if (status == SEC_E_MESSAGE_ALTERED) {
// The message has been altered, disconnect now.
shutdown = true; // skips sending the shutdown alert
@@ -1809,8 +2099,17 @@ QSslCipher TlsCryptographSchannel::sessionCipher() const
Q_ASSERT(q);
if (!q->isEncrypted())
- return QSslCipher();
- return QSslCipher(QStringLiteral("Schannel"), sessionProtocol());
+ return {};
+
+ const auto sessionProtocol = toQtSslProtocol(connectionInfo.dwProtocol);
+
+ const auto ciphers = ciphersByName(QStringView(cipherInfo.szCipherSuite));
+ for (const auto& cipher : ciphers) {
+ if (cipher.protocol() == sessionProtocol)
+ return cipher;
+ }
+
+ return {};
}
QSsl::SslProtocol TlsCryptographSchannel::sessionProtocol() const
@@ -1994,7 +2293,10 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
// the Ca list, not just included during verification.
// That being said, it's not trivial to add the root certificates (if and only if they
// came from the system root store). And I don't see this mentioned in our documentation.
- auto rootStore = QHCertStorePointer(CertOpenSystemStore(0, L"ROOT"));
+ auto rootStore = QHCertStorePointer(
+ CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
+ CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER, L"ROOT"));
+
if (!rootStore) {
#ifdef QSSLSOCKET_DEBUG
qCWarning(lcTlsBackendSchannel, "Failed to open the system root CA certificate store!");
@@ -2108,10 +2410,40 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
verifyDepth = DWORD(q->peerVerifyDepth());
const auto &caCertificates = q->sslConfiguration().caCertificates();
+
+ if (!rootCertOnDemandLoadingAllowed()
+ && !(chain->TrustStatus.dwErrorStatus & CERT_TRUST_IS_PARTIAL_CHAIN)
+ && (q->peerVerifyMode() == QSslSocket::VerifyPeer
+ || (isClient && q->peerVerifyMode() == QSslSocket::AutoVerifyPeer))) {
+ // When verifying a peer Windows "helpfully" builds a chain that
+ // may include roots from the system store. But we don't want that if
+ // the user has set their own CA certificates.
+ // Since Windows claims this is not a partial chain the root is included
+ // and we have to check that it is one of our configured CAs.
+ CERT_CHAIN_ELEMENT *element = chain->rgpElement[chain->cElement - 1];
+ QSslCertificate certificate = getCertificateFromChainElement(element);
+ if (!caCertificates.contains(certificate)) {
+ auto error = QSslError(QSslError::CertificateUntrusted, certificate);
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ }
+
QList<QSslCertificate> peerCertificateChain;
for (DWORD i = 0; i < verifyDepth; i++) {
CERT_CHAIN_ELEMENT *element = chain->rgpElement[i];
QSslCertificate certificate = getCertificateFromChainElement(element);
+ if (certificate.isNull()) {
+ const auto &previousCert = !peerCertificateChain.isEmpty() ? peerCertificateChain.last()
+ : QSslCertificate();
+ auto error = QSslError(QSslError::SslError::UnableToGetIssuerCertificate, previousCert);
+ sslErrors += error;
+ emit q->peerVerifyError(error);
+ if (previousCert.isNull() || q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
const QList<QSslCertificateExtension> extensions = certificate.extensions();
#ifdef QSSLSOCKET_DEBUG
@@ -2259,7 +2591,7 @@ bool TlsCryptographSchannel::verifyCertContext(CERT_CONTEXT *certContext)
}
if (!peerCertificateChain.isEmpty())
- QTlsBackend::storePeerCertificate(d, peerCertificateChain.first());
+ QTlsBackend::storePeerCertificate(d, peerCertificateChain.constFirst());
const auto &configuration = q->sslConfiguration(); // Probably, updated by QTlsBackend::storePeerCertificate etc.
// @Note: Somewhat copied from qsslsocket_mac.cpp
diff --git a/src/plugins/tls/schannel/qtls_schannel_p.h b/src/plugins/tls/schannel/qtls_schannel_p.h
index f6bfdbc7cf..fab8777249 100644
--- a/src/plugins/tls/schannel/qtls_schannel_p.h
+++ b/src/plugins/tls/schannel/qtls_schannel_p.h
@@ -93,6 +93,7 @@ private:
QSslSocket *q = nullptr;
QSslSocketPrivate *d = nullptr;
+ SecPkgContext_CipherInfo cipherInfo = {};
SecPkgContext_ConnectionInfo connectionInfo = {};
SecPkgContext_StreamSizes streamSizes = {};
diff --git a/src/plugins/tls/schannel/qtlsbackend_schannel_p.h b/src/plugins/tls/schannel/qtlsbackend_schannel_p.h
index a70f8922a6..7c2d675e79 100644
--- a/src/plugins/tls/schannel/qtlsbackend_schannel_p.h
+++ b/src/plugins/tls/schannel/qtlsbackend_schannel_p.h
@@ -57,6 +57,7 @@ private:
QTlsPrivate::X509PemReaderPtr X509PemReader() const override;
QTlsPrivate::X509DerReaderPtr X509DerReader() const override;
+ QTlsPrivate::X509Pkcs12ReaderPtr X509Pkcs12Reader() const override;
static bool s_loadedCiphersAndCerts;
};
diff --git a/src/plugins/tls/schannel/qx509_schannel.cpp b/src/plugins/tls/schannel/qx509_schannel.cpp
index 5a5e625268..d9d82dce29 100644
--- a/src/plugins/tls/schannel/qx509_schannel.cpp
+++ b/src/plugins/tls/schannel/qx509_schannel.cpp
@@ -1,9 +1,11 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "qtlsbackend_schannel_p.h"
#include "qtlskey_schannel_p.h"
#include "qx509_schannel_p.h"
+#include <QtCore/private/qsystemerror_p.h>
#include <QtNetwork/private/qsslcertificate_p.h>
#include <memory>
@@ -39,13 +41,173 @@ QSslCertificate X509CertificateSchannel::QSslCertificate_from_CERT_CONTEXT(const
QByteArray derData = QByteArray((const char *)certificateContext->pbCertEncoded,
certificateContext->cbCertEncoded);
QSslCertificate certificate(derData, QSsl::Der);
-
- auto *certBackend = QTlsBackend::backend<X509CertificateSchannel>(certificate);
- Q_ASSERT(certBackend);
- certBackend->certificateContext = CertDuplicateCertificateContext(certificateContext);
+ if (!certificate.isNull()) {
+ auto *certBackend = QTlsBackend::backend<X509CertificateSchannel>(certificate);
+ Q_ASSERT(certBackend);
+ certBackend->certificateContext = CertDuplicateCertificateContext(certificateContext);
+ }
return certificate;
}
+bool X509CertificateSchannel::importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert,
+ QList<QSslCertificate> *caCertificates,
+ const QByteArray &passPhrase)
+{
+ // These are required
+ Q_ASSERT(device);
+ Q_ASSERT(key);
+ Q_ASSERT(cert);
+
+ QByteArray pkcs12data = device->readAll();
+ if (pkcs12data.size() == 0)
+ return false;
+
+ CRYPT_DATA_BLOB dataBlob;
+ dataBlob.cbData = pkcs12data.size();
+ dataBlob.pbData = reinterpret_cast<BYTE*>(pkcs12data.data());
+
+ const auto password = QString::fromUtf8(passPhrase);
+
+ const DWORD flags = (CRYPT_EXPORTABLE | PKCS12_NO_PERSIST_KEY | PKCS12_PREFER_CNG_KSP);
+
+ auto certStore = QHCertStorePointer(PFXImportCertStore(&dataBlob,
+ reinterpret_cast<LPCWSTR>(password.utf16()),
+ flags));
+
+ if (!certStore) {
+ qCWarning(lcTlsBackendSchannel, "Failed to import PFX data: %s",
+ qPrintable(QSystemError::windowsString()));
+ return false;
+ }
+
+ // first extract the certificate with the private key
+ const auto certContext = QPCCertContextPointer(CertFindCertificateInStore(certStore.get(),
+ X509_ASN_ENCODING |
+ PKCS_7_ASN_ENCODING,
+ 0,
+ CERT_FIND_HAS_PRIVATE_KEY,
+ nullptr, nullptr));
+
+ if (!certContext) {
+ qCWarning(lcTlsBackendSchannel, "Failed to find certificate in PFX store: %s",
+ qPrintable(QSystemError::windowsString()));
+ return false;
+ }
+
+ *cert = QSslCertificate_from_CERT_CONTEXT(certContext.get());
+
+ // retrieve the private key for the certificate
+ NCRYPT_KEY_HANDLE keyHandle = {};
+ DWORD keyHandleSize = sizeof(keyHandle);
+ if (!CertGetCertificateContextProperty(certContext.get(), CERT_NCRYPT_KEY_HANDLE_PROP_ID,
+ &keyHandle, &keyHandleSize)) {
+ qCWarning(lcTlsBackendSchannel, "Failed to find private key handle in certificate context: %s",
+ qPrintable(QSystemError::windowsString()));
+ return false;
+ }
+
+ SECURITY_STATUS securityStatus = ERROR_SUCCESS;
+
+ // we need the 'NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG' to make NCryptExportKey succeed
+ DWORD policy = (NCRYPT_ALLOW_EXPORT_FLAG | NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG);
+ DWORD policySize = sizeof(policy);
+
+ securityStatus = NCryptSetProperty(keyHandle, NCRYPT_EXPORT_POLICY_PROPERTY,
+ reinterpret_cast<BYTE*>(&policy), policySize, 0);
+ if (securityStatus != ERROR_SUCCESS) {
+ qCWarning(lcTlsBackendSchannel, "Failed to update export policy of private key: 0x%x",
+ static_cast<unsigned int>(securityStatus));
+ return false;
+ }
+
+ DWORD blobSize = {};
+ securityStatus = NCryptExportKey(keyHandle, {}, BCRYPT_RSAFULLPRIVATE_BLOB,
+ nullptr, nullptr, 0, &blobSize, 0);
+ if (securityStatus != ERROR_SUCCESS) {
+ qCWarning(lcTlsBackendSchannel, "Failed to retrieve private key size: 0x%x",
+ static_cast<unsigned int>(securityStatus));
+ return false;
+ }
+
+ std::vector<BYTE> blob(blobSize);
+ securityStatus = NCryptExportKey(keyHandle, {}, BCRYPT_RSAFULLPRIVATE_BLOB,
+ nullptr, blob.data(), blobSize, &blobSize, 0);
+ if (securityStatus != ERROR_SUCCESS) {
+ qCWarning(lcTlsBackendSchannel, "Failed to retrieve private key from certificate: 0x%x",
+ static_cast<unsigned int>(securityStatus));
+ return false;
+ }
+
+ DWORD privateKeySize = {};
+
+ if (!CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, CNG_RSA_PRIVATE_KEY_BLOB,
+ blob.data(), nullptr, &privateKeySize)) {
+ qCWarning(lcTlsBackendSchannel, "Failed to encode private key to key info: %s",
+ qPrintable(QSystemError::windowsString()));
+ return false;
+ }
+
+ std::vector<BYTE> privateKeyData(privateKeySize);
+
+ CRYPT_PRIVATE_KEY_INFO privateKeyInfo = {};
+ privateKeyInfo.Algorithm.pszObjId = const_cast<PSTR>(szOID_RSA_RSA);
+ privateKeyInfo.PrivateKey.cbData = privateKeySize;
+ privateKeyInfo.PrivateKey.pbData = privateKeyData.data();
+
+ if (!CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ CNG_RSA_PRIVATE_KEY_BLOB, blob.data(),
+ privateKeyInfo.PrivateKey.pbData, &privateKeyInfo.PrivateKey.cbData)) {
+ qCWarning(lcTlsBackendSchannel, "Failed to encode private key to key info: %s",
+ qPrintable(QSystemError::windowsString()));
+ return false;
+ }
+
+
+ DWORD derSize = {};
+
+ if (!CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO,
+ &privateKeyInfo, nullptr, &derSize)) {
+ qCWarning(lcTlsBackendSchannel, "Failed to encode key info to DER format: %s",
+ qPrintable(QSystemError::windowsString()));
+
+ return false;
+ }
+
+ QByteArray derData(derSize, Qt::Uninitialized);
+
+ if (!CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO,
+ &privateKeyInfo, reinterpret_cast<BYTE*>(derData.data()), &derSize)) {
+ qCWarning(lcTlsBackendSchannel, "Failed to encode key info to DER format: %s",
+ qPrintable(QSystemError::windowsString()));
+
+ return false;
+ }
+
+ *key = QSslKey(derData, QSsl::Rsa, QSsl::Der, QSsl::PrivateKey);
+ if (key->isNull()) {
+ qCWarning(lcTlsBackendSchannel, "Failed to parse private key from DER format");
+ return false;
+ }
+
+ // fetch all the remaining certificates as CA certificates
+ if (caCertificates) {
+ PCCERT_CONTEXT caCertContext = nullptr;
+ while ((caCertContext = CertFindCertificateInStore(certStore.get(),
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ 0, CERT_FIND_ANY, nullptr, caCertContext))) {
+ if (CertCompareCertificate(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ certContext->pCertInfo, caCertContext->pCertInfo))
+ continue; // ignore the certificate with private key
+
+ auto caCertificate = QSslCertificate_from_CERT_CONTEXT(caCertContext);
+
+ caCertificates->append(caCertificate);
+ }
+ }
+
+ return true;
+}
+
} // namespace QTlsPrivate
QT_END_NAMESPACE
diff --git a/src/plugins/tls/schannel/qx509_schannel_p.h b/src/plugins/tls/schannel/qx509_schannel_p.h
index 17b91983f2..4625c9584c 100644
--- a/src/plugins/tls/schannel/qx509_schannel_p.h
+++ b/src/plugins/tls/schannel/qx509_schannel_p.h
@@ -36,6 +36,10 @@ public:
Qt::HANDLE handle() const override;
static QSslCertificate QSslCertificate_from_CERT_CONTEXT(const CERT_CONTEXT *certificateContext);
+
+ static bool importPkcs12(QIODevice *device, QSslKey *key, QSslCertificate *cert,
+ QList<QSslCertificate> *caCertificates,
+ const QByteArray &passPhrase);
private:
const CERT_CONTEXT *certificateContext = nullptr;
diff --git a/src/plugins/tls/securetransport/qtlsbackend_st.cpp b/src/plugins/tls/securetransport/qtlsbackend_st.cpp
index 4c385b5af6..54e45d1720 100644
--- a/src/plugins/tls/securetransport/qtlsbackend_st.cpp
+++ b/src/plugins/tls/securetransport/qtlsbackend_st.cpp
@@ -357,3 +357,5 @@ QTlsPrivate::TlsCryptograph *QSecureTransportBackend::createTlsCryptograph() con
QT_END_NAMESPACE
+
+#include "moc_qtlsbackend_st_p.cpp"
diff --git a/src/plugins/tls/shared/qasn1element.cpp b/src/plugins/tls/shared/qasn1element.cpp
index 507a3a727a..97be46866d 100644
--- a/src/plugins/tls/shared/qasn1element.cpp
+++ b/src/plugins/tls/shared/qasn1element.cpp
@@ -6,6 +6,7 @@
#include <QtCore/qdatastream.h>
#include <QtCore/qdatetime.h>
+#include <QtCore/qtimezone.h>
#include <QtCore/qlist.h>
#include <QDebug>
#include <private/qtools_p.h>
@@ -224,31 +225,28 @@ QDateTime QAsn1Element::toDateTime() const
return result;
if (mType == UtcTimeType && mValue.size() == 13) {
- result = QDateTime::fromString(QString::fromLatin1(mValue),
- QStringLiteral("yyMMddHHmmsst"));
- if (!result.isValid())
- return result;
-
- Q_ASSERT(result.timeSpec() == Qt::UTC);
-
- QDate date = result.date();
-
// RFC 2459:
// Where YY is greater than or equal to 50, the year shall be
// interpreted as 19YY; and
//
// Where YY is less than 50, the year shall be interpreted as 20YY.
//
- // QDateTime interprets the 'yy' format as 19yy, so we may need to adjust
- // the year (bring it in the [1950, 2049] range).
- if (date.year() < 1950)
- result.setDate(date.addYears(100));
+ // so use 1950 as base year.
+ constexpr int rfc2459CenturyStart = 1950;
+ const QLatin1StringView inputView(mValue);
+ QDate date = QDate::fromString(inputView.first(6), u"yyMMdd", rfc2459CenturyStart);
+ if (!date.isValid())
+ return result;
+
+ Q_ASSERT(date.year() >= rfc2459CenturyStart);
+ Q_ASSERT(date.year() < 100 + rfc2459CenturyStart);
- Q_ASSERT(result.date().year() >= 1950);
- Q_ASSERT(result.date().year() <= 2049);
+ QTime time = QTime::fromString(inputView.sliced(6, 6), u"HHmmss");
+ if (!time.isValid())
+ return result;
+ result = QDateTime(date, time, QTimeZone::UTC);
} else if (mType == GeneralizedTimeType && mValue.size() == 15) {
- result = QDateTime::fromString(QString::fromLatin1(mValue),
- QStringLiteral("yyyyMMddHHmmsst"));
+ result = QDateTime::fromString(QString::fromLatin1(mValue), u"yyyyMMddHHmmsst");
}
return result;
diff --git a/src/plugins/tls/shared/qwincrypt_p.h b/src/plugins/tls/shared/qwincrypt_p.h
index 1b1f0f16c0..48ca4247fa 100644
--- a/src/plugins/tls/shared/qwincrypt_p.h
+++ b/src/plugins/tls/shared/qwincrypt_p.h
@@ -40,6 +40,16 @@ struct QHCertStoreDeleter {
// A simple RAII type used by Schannel code and Window CA fetcher class:
using QHCertStorePointer = std::unique_ptr<void, QHCertStoreDeleter>;
+struct QPCCertContextDeleter {
+ void operator()(PCCERT_CONTEXT context) const
+ {
+ CertFreeCertificateContext(context);
+ }
+};
+
+// A simple RAII type used by Schannel code
+using QPCCertContextPointer = std::unique_ptr<const CERT_CONTEXT, QPCCertContextDeleter>;
+
QT_END_NAMESPACE
#endif // QWINCRYPT_P_H
diff --git a/src/plugins/tls/shared/qx509_generic.cpp b/src/plugins/tls/shared/qx509_generic.cpp
index e700552c43..5006db1a72 100644
--- a/src/plugins/tls/shared/qx509_generic.cpp
+++ b/src/plugins/tls/shared/qx509_generic.cpp
@@ -118,7 +118,7 @@ QList<QSslCertificate> X509CertificateGeneric::certificatesFromPem(const QByteAr
QByteArray decoded = QByteArray::fromBase64(
QByteArray::fromRawData(pem.data() + startPos, endPos - startPos));
- certificates << certificatesFromDer(decoded, 1);;
+ certificates << certificatesFromDer(decoded, 1);
}
return certificates;
diff --git a/src/plugins/tracing/CMakeLists.txt b/src/plugins/tracing/CMakeLists.txt
index 9840b59ecd..823e11c174 100644
--- a/src/plugins/tracing/CMakeLists.txt
+++ b/src/plugins/tracing/CMakeLists.txt
@@ -12,12 +12,21 @@ endfunction(make_includable)
make_includable(metadata_template.txt metadata_template.h)
qt_internal_add_plugin(QCtfTracePlugin
- SHARED
CLASS_NAME QCtfTracePlugin
PLUGIN_TYPE tracing
SOURCES
qctflib_p.h qctflib.cpp metadata_template.txt qctfplugin.cpp qctfplugin_p.h
+ qctfserver_p.h qctfserver.cpp
LIBRARIES
- Qt6::Core Qt6::CorePrivate
+ Qt::Core Qt::CorePrivate Qt::Network
)
+qt_internal_extend_target(QCtfTracePlugin CONDITION QT_FEATURE_zstd
+ LIBRARIES
+ WrapZSTD::WrapZSTD
+)
+
+qt_internal_extend_target(QCtfTracePlugin CONDITION (QT_FEATURE_cxx17_filesystem) AND (GCC AND (QMAKE_GCC_MAJOR_VERSION LESS 9))
+ LINK_OPTIONS
+ "-lstdc++fs"
+)
diff --git a/src/plugins/tracing/qctflib.cpp b/src/plugins/tracing/qctflib.cpp
index e0f4db489a..fe3946d27c 100644
--- a/src/plugins/tracing/qctflib.cpp
+++ b/src/plugins/tracing/qctflib.cpp
@@ -12,14 +12,18 @@
#include <qsize.h>
#include <qmetaobject.h>
#include <qendian.h>
+#include <qplatformdefs.h>
#include "qctflib_p.h"
+
+#if QT_CONFIG(cxx17_filesystem)
#include <filesystem>
+#endif
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-Q_LOGGING_CATEGORY(lcDebugTrace, "qt.core.ctf");
+Q_LOGGING_CATEGORY(lcDebugTrace, "qt.core.ctf", QtWarningMsg)
static const size_t packetHeaderSize = 24 + 6 * 8 + 4;
static const size_t packetSize = 4096;
@@ -29,14 +33,27 @@ static const char traceMetadataTemplate[] =
;
static const size_t traceMetadataSize = sizeof(traceMetadataTemplate);
+static inline QString allLiteral() { return QStringLiteral("all"); }
+static inline QString defaultLiteral() { return QStringLiteral("default"); }
+
+
template <typename T>
-QByteArray &operator<<(QByteArray &arr, T val)
+static QByteArray &operator<<(QByteArray &arr, T val)
{
static_assert(std::is_arithmetic_v<T>);
- arr.append((char *)&val, sizeof(val));
+ arr.append(reinterpret_cast<char *>(&val), sizeof(val));
return arr;
}
+static FILE *openFile(const QString &filename, const QString &mode)
+{
+#ifdef Q_OS_WINDOWS
+ return _wfopen(qUtf16Printable(filename), qUtf16Printable(mode));
+#else
+ return fopen(qPrintable(filename), qPrintable(mode));
+#endif
+}
+
QCtfLibImpl *QCtfLibImpl::s_instance = nullptr;
QCtfLib *QCtfLibImpl::instance()
@@ -48,111 +65,182 @@ QCtfLib *QCtfLibImpl::instance()
void QCtfLibImpl::cleanup()
{
- if (s_instance)
- delete s_instance;
+ delete s_instance;
+ s_instance = nullptr;
}
-QCtfLibImpl::QCtfLibImpl()
+void QCtfLibImpl::handleSessionChange()
{
- QString location = QString::fromUtf8(qgetenv("QTRACE_LOCATION"));
- if (location.isEmpty()) {
- qCWarning (lcDebugTrace) << "QTRACE_LOCATION not set";
- return;
- }
-
- // Check if the location is writable
- FILE *file = nullptr;
- file = fopen(qPrintable(location + "/metadata"_L1), "w+b");
- if (!file) {
- qCWarning (lcDebugTrace) << "Unable to write to location";
- return;
- }
- fclose(file);
-
- const QString filename = location + QStringLiteral("/session.json");
- file = fopen(qPrintable(filename), "rb");
- if (!file) {
- qCWarning (lcDebugTrace) << "unable to open session file: " << filename;
- m_location = location;
- m_session.tracepoints.append(QStringLiteral("all"));
- m_session.name = QStringLiteral("default");
- } else {
- fseek(file, 0, SEEK_END);
- long pos = ftell(file);
- fseek(file, 0, SEEK_SET);
- QByteArray data(pos, Qt::Uninitialized);
- long size = (long)fread(data.data(), pos, 1, file);
- fclose(file);
- if (size != 1)
- return;
- QJsonDocument json(QJsonDocument::fromJson(data));
-
- QJsonObject obj = json.object();
- QJsonValue value = *obj.begin();
- if (value.isNull() || !value.isArray())
- return;
- m_session.name = obj.begin().key();
- QJsonArray arr = value.toArray();
- for (auto var : arr)
- m_session.tracepoints.append(var.toString());
+ m_sessionChanged = true;
+}
- m_location = location + QStringLiteral("/ust");
- std::filesystem::create_directory(qPrintable(m_location), qPrintable(location));
+void QCtfLibImpl::handleStatusChange(QCtfServer::ServerStatus status)
+{
+ switch (status) {
+ case QCtfServer::Error: {
+ m_serverClosed = true;
+ } break;
+ default:
+ break;
}
- m_session.all = m_session.tracepoints.contains(QStringLiteral("all"));
+}
- auto datetime = QDateTime::currentDateTime();
- QString mhn = QSysInfo::machineHostName();
+void QCtfLibImpl::buildMetadata()
+{
+ const QString mhn = QSysInfo::machineHostName();
QString metadata = QString::fromUtf8(traceMetadataTemplate, traceMetadataSize);
metadata.replace(QStringLiteral("$TRACE_UUID"), s_TraceUuid.toString(QUuid::WithoutBraces));
metadata.replace(QStringLiteral("$ARC_BIT_WIDTH"), QString::number(Q_PROCESSOR_WORDSIZE * 8));
metadata.replace(QStringLiteral("$SESSION_NAME"), m_session.name);
- metadata.replace(QStringLiteral("$CREATION_TIME"), datetime.toString());
+ metadata.replace(QStringLiteral("$CREATION_TIME"), m_datetime.toString(Qt::ISODate));
metadata.replace(QStringLiteral("$HOST_NAME"), mhn);
- metadata.replace(QStringLiteral("$CLOCK_FREQUENCY"), m_timer.isMonotonic() ? QStringLiteral("1000000000") : QStringLiteral("1000"));
- metadata.replace(QStringLiteral("$CLOCK_NAME"), m_timer.isMonotonic() ? QStringLiteral("monotonic") : QStringLiteral("system"));
- metadata.replace(QStringLiteral("$CLOCK_TYPE"), m_timer.isMonotonic() ? QStringLiteral("Monotonic clock") : QStringLiteral("System clock"));
- metadata.replace(QStringLiteral("$CLOCK_OFFSET"), QString::number(datetime.toMSecsSinceEpoch() * 1000000));
-#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- metadata.replace(QStringLiteral("$ENDIANNESS"), QStringLiteral("be"));
-#else
- metadata.replace(QStringLiteral("$ENDIANNESS"), QStringLiteral("le"));
-#endif
+ metadata.replace(QStringLiteral("$CLOCK_FREQUENCY"), QStringLiteral("1000000000"));
+ metadata.replace(QStringLiteral("$CLOCK_NAME"), QStringLiteral("monotonic"));
+ metadata.replace(QStringLiteral("$CLOCK_TYPE"), QStringLiteral("Monotonic clock"));
+ metadata.replace(QStringLiteral("$CLOCK_OFFSET"), QString::number(m_datetime.toMSecsSinceEpoch() * 1000000));
+ metadata.replace(QStringLiteral("$ENDIANNESS"), QSysInfo::ByteOrder == QSysInfo::BigEndian ? u"be"_s : u"le"_s);
writeMetadata(metadata, true);
+}
+
+QCtfLibImpl::QCtfLibImpl()
+{
+ QString location = qEnvironmentVariable("QTRACE_LOCATION");
+ if (location.isEmpty()) {
+ qCInfo(lcDebugTrace) << "QTRACE_LOCATION not set";
+ return;
+ }
+
+ if (location.startsWith(u"tcp")) {
+ QUrl url(location);
+ m_server.reset(new QCtfServer());
+ m_server->setCallback(this);
+ m_server->setHost(url.host());
+ m_server->setPort(url.port());
+ m_server->startServer();
+ m_streaming = true;
+ m_session.tracepoints.append(allLiteral());
+ m_session.name = defaultLiteral();
+ } else {
+#if !QT_CONFIG(cxx17_filesystem)
+ qCWarning(lcDebugTrace) << "Unable to use filesystem";
+ return;
+#endif
+ // Check if the location is writable
+ if (QT_ACCESS(qPrintable(location), W_OK) != 0) {
+ qCWarning(lcDebugTrace) << "Unable to write to location";
+ return;
+ }
+ const QString filename = location + u"/session.json";
+ FILE *file = openFile(qPrintable(filename), "rb"_L1);
+ if (!file) {
+ qCWarning(lcDebugTrace) << "unable to open session file: "
+ << filename << ", " << qt_error_string();
+ m_location = location;
+ m_session.tracepoints.append(allLiteral());
+ m_session.name = defaultLiteral();
+ } else {
+ QT_STATBUF stat;
+ if (QT_FSTAT(QT_FILENO(file), &stat) != 0) {
+ qCWarning(lcDebugTrace) << "Unable to stat session file, " << qt_error_string();
+ return;
+ }
+ qsizetype filesize = qMin(stat.st_size, std::numeric_limits<qsizetype>::max());
+ QByteArray data(filesize, Qt::Uninitialized);
+ qsizetype size = static_cast<qsizetype>(fread(data.data(), 1, filesize, file));
+ fclose(file);
+ if (size != filesize)
+ return;
+ QJsonDocument json(QJsonDocument::fromJson(data));
+ QJsonObject obj = json.object();
+ bool valid = false;
+ if (!obj.isEmpty()) {
+ const auto it = obj.begin();
+ if (it.value().isArray()) {
+ m_session.name = it.key();
+ for (auto var : it.value().toArray())
+ m_session.tracepoints.append(var.toString());
+ valid = true;
+ }
+ }
+ if (!valid) {
+ qCWarning(lcDebugTrace) << "Session file is not valid";
+ m_session.tracepoints.append(allLiteral());
+ m_session.name = defaultLiteral();
+ }
+ m_location = location + u"/ust";
+#if QT_CONFIG(cxx17_filesystem)
+ std::filesystem::create_directory(qPrintable(m_location), qPrintable(location));
+#endif
+ }
+ clearLocation();
+ }
+ m_session.all = m_session.tracepoints.contains(allLiteral());
+ // Get datetime to when the timer was started to store the offset to epoch time for the traces
+ m_datetime = QDateTime::currentDateTime().toUTC();
m_timer.start();
+ if (!m_streaming)
+ buildMetadata();
+}
+
+void QCtfLibImpl::clearLocation()
+{
+#if QT_CONFIG(cxx17_filesystem)
+ const std::filesystem::path location{qUtf16Printable(m_location)};
+ for (auto const& dirEntry : std::filesystem::directory_iterator{location})
+ {
+ const auto path = dirEntry.path();
+#if __cplusplus > 201703L
+ if (dirEntry.is_regular_file()
+ && path.filename().wstring().starts_with(std::wstring_view(L"channel_"))
+ && !path.has_extension()) {
+#else
+ const auto strview = std::wstring_view(L"channel_");
+ const auto sub = path.filename().wstring().substr(0, strview.length());
+ if (dirEntry.is_regular_file() && sub.compare(strview) == 0
+ && !path.has_extension()) {
+#endif
+ if (!std::filesystem::remove(path)) {
+ qCInfo(lcDebugTrace) << "Unable to clear output location.";
+ break;
+ }
+ }
+ }
+#endif
}
void QCtfLibImpl::writeMetadata(const QString &metadata, bool overwrite)
{
- FILE *file = nullptr;
- file = fopen(qPrintable(m_location + "/metadata"_L1), overwrite ? "w+b": "ab");
- if (!file)
- return;
+ if (m_streaming) {
+ auto mt = metadata.toUtf8();
+ mt.resize(mt.size() - 1);
+ m_server->bufferData(QStringLiteral("metadata"), mt, overwrite);
+ } else {
+ FILE *file = nullptr;
+ file = openFile(qPrintable(m_location + "/metadata"_L1), overwrite ? "w+b"_L1: "ab"_L1);
+ if (!file)
+ return;
- if (!overwrite)
- fputs("\n", file);
+ if (!overwrite)
+ fputs("\n", file);
- // data contains zero at the end, hence size - 1.
- const QByteArray data = metadata.toUtf8();
- fwrite(data.data(), data.size() - 1, 1, file);
- fclose(file);
+ // data contains zero at the end, hence size - 1.
+ const QByteArray data = metadata.toUtf8();
+ fwrite(data.data(), data.size() - 1, 1, file);
+ fclose(file);
+ }
}
void QCtfLibImpl::writeCtfPacket(QCtfLibImpl::Channel &ch)
{
FILE *file = nullptr;
- file = fopen(ch.channelName, "ab");
- if (file) {
+ if (!m_streaming)
+ file = openFile(ch.channelName, "ab"_L1);
+ if (file || m_streaming) {
/* Each packet contains header and context, which are defined in the metadata.txt */
QByteArray packet;
packet << s_CtfHeaderMagic;
- /* Uuid is array of bytes hence implicitely big endian. */
- packet << qToBigEndian(s_TraceUuid.data1);
- packet << qToBigEndian(s_TraceUuid.data2);
- packet << qToBigEndian(s_TraceUuid.data3);
- for (int i = 0; i < 8; i++)
- packet << s_TraceUuid.data4[i];
+ packet.append(QByteArrayView(s_TraceUuid.toBytes()));
packet << quint32(0);
packet << ch.minTimestamp;
@@ -168,27 +256,61 @@ void QCtfLibImpl::writeCtfPacket(QCtfLibImpl::Channel &ch)
Q_ASSERT(ch.data.size() + packetHeaderSize + ch.threadNameLength <= packetSize);
Q_ASSERT(packet.size() == qsizetype(packetHeaderSize + ch.threadNameLength));
- fwrite(packet.data(), packet.size(), 1, file);
- ch.data.resize(packetSize - packet.size(), 0);
- fwrite(ch.data.data(), ch.data.size(), 1, file);
- fclose(file);
+ if (m_streaming) {
+ ch.data.resize(packetSize - packet.size(), 0);
+ packet += ch.data;
+ m_server->bufferData(QString::fromLatin1(ch.channelName), packet, false);
+ } else {
+ fwrite(packet.data(), packet.size(), 1, file);
+ ch.data.resize(packetSize - packet.size(), 0);
+ fwrite(ch.data.data(), ch.data.size(), 1, file);
+ fclose(file);
+ }
}
}
+QCtfLibImpl::Channel::~Channel()
+{
+ impl->writeCtfPacket(*this);
+ impl->removeChannel(this);
+}
+
QCtfLibImpl::~QCtfLibImpl()
{
+ if (!m_server.isNull())
+ m_server->stopServer();
qDeleteAll(m_eventPrivs);
}
-bool QCtfLibImpl::tracepointEnabled(const QCtfTracePointEvent &point)
+void QCtfLibImpl::removeChannel(Channel *ch)
{
- return m_session.all || m_session.tracepoints.contains(point.provider.provider);
+ const QMutexLocker lock(&m_mutex);
+ m_channels.removeOne(ch);
}
-QCtfLibImpl::Channel::~Channel()
+bool QCtfLibImpl::tracepointEnabled(const QCtfTracePointEvent &point)
{
- if (data.size())
- QCtfLibImpl::writeCtfPacket(*this);
+ if (m_sessionChanged) {
+ const QMutexLocker lock(&m_mutex);
+ buildMetadata();
+ m_session.name = m_server->sessionName();
+ m_session.tracepoints = m_server->sessionTracepoints().split(';');
+ m_session.all = m_session.tracepoints.contains(allLiteral());
+ m_sessionChanged = false;
+ for (const auto &meta : m_additionalMetadata)
+ writeMetadata(meta->metadata);
+ for (auto *priv : m_eventPrivs)
+ writeMetadata(priv->metadata);
+ quint64 timestamp = m_timer.nsecsElapsed();
+ for (auto *ch : m_channels) {
+ writeCtfPacket(*ch);
+ ch->data.clear();
+ ch->minTimestamp = ch->maxTimestamp = timestamp;
+ }
+ }
+ if (m_streaming && (m_serverClosed || (!m_server->bufferOnIdle() && m_server->status() == QCtfServer::Idle)))
+ return false;
+ return m_session.all || m_session.tracepoints.contains(point.provider.provider);
}
static QString toMetadata(const QString &provider, const QString &name, const QString &metadata, quint32 eventId)
@@ -205,12 +327,10 @@ event {
};
};
*/
- QString ret;
- ret = QStringLiteral("event {\n name = \"") + provider + QLatin1Char(':') + name + QStringLiteral("\";\n");
- ret += QStringLiteral(" id = ") + QString::number(eventId) + QStringLiteral(";\n");
- ret += QStringLiteral(" stream_id = 0;\n loglevel = 13;\n fields := struct {\n ");
- ret += metadata + QStringLiteral("\n };\n};\n");
- return ret;
+ return QStringView(u"event {\n name = \"") + provider + QLatin1Char(':') + name + u"\";\n"
+ + u" id = " + QString::number(eventId) + u";\n"
+ + u" stream_id = 0;\n loglevel = 13;\n fields := struct {\n "
+ + metadata + u"\n };\n};\n";
}
QCtfTracePointPrivate *QCtfLibImpl::initializeTracepoint(const QCtfTracePointEvent &point)
@@ -235,6 +355,8 @@ void QCtfLibImpl::doTracepoint(const QCtfTracePointEvent &point, const QByteArra
QCtfTracePointPrivate *priv = point.d;
quint64 timestamp = 0;
QThread *thread = nullptr;
+ if (m_streaming && m_serverClosed)
+ return;
{
QMutexLocker lock(&m_mutex);
if (!priv->metadataWritten) {
@@ -267,12 +389,10 @@ void QCtfLibImpl::doTracepoint(const QCtfTracePointEvent &point, const QByteArra
Channel &ch = m_threadData.localData();
if (ch.channelName[0] == 0) {
+ ch.impl = this;
+ m_channels.append(&ch);
m_threadIndices.insert(thread, m_threadIndices.size());
sprintf(ch.channelName, "%s/channel_%d", qPrintable(m_location), m_threadIndices[thread]);
- FILE *f = nullptr;
- f = fopen(ch.channelName, "wb");
- if (f)
- fclose(f);
ch.minTimestamp = ch.maxTimestamp = timestamp;
ch.thread = thread;
ch.threadIndex = m_threadIndices[thread];
diff --git a/src/plugins/tracing/qctflib_p.h b/src/plugins/tracing/qctflib_p.h
index 081dda1d04..297d38ee50 100644
--- a/src/plugins/tracing/qctflib_p.h
+++ b/src/plugins/tracing/qctflib_p.h
@@ -25,8 +25,8 @@
#include <qset.h>
#include <qthreadstorage.h>
#include <qthread.h>
-#include <qmutex.h>
#include <qloggingcategory.h>
+#include "qctfserver_p.h"
QT_BEGIN_NAMESPACE
@@ -40,7 +40,7 @@ struct QCtfTracePointPrivate
bool metadataWritten = false;
};
-class QCtfLibImpl : public QCtfLib
+class QCtfLibImpl : public QCtfLib, public QCtfServer::ServerCallback
{
struct Session
{
@@ -60,6 +60,7 @@ class QCtfLibImpl : public QCtfLib
QByteArray threadName;
quint32 threadNameLength = 0;
bool locked = false;
+ QCtfLibImpl *impl = nullptr;
Channel()
{
memset(channelName, 0, sizeof(channelName));
@@ -78,15 +79,24 @@ public:
QCtfTracePointPrivate *initializeTracepoint(const QCtfTracePointEvent &point) override;
void registerMetadata(const QCtfTraceMetadata &metadata);
int eventId();
+ void shutdown(bool *) override
+ {
+
+ }
static QCtfLib *instance();
static void cleanup();
private:
static QCtfLibImpl *s_instance;
QHash<QString, QCtfTracePointPrivate *> m_eventPrivs;
+ void removeChannel(Channel *ch);
void updateMetadata(const QCtfTracePointEvent &point);
void writeMetadata(const QString &metadata, bool overwrite = false);
- static void writeCtfPacket(Channel &ch);
+ void clearLocation();
+ void handleSessionChange() override;
+ void handleStatusChange(QCtfServer::ServerStatus status) override;
+ void writeCtfPacket(Channel &ch);
+ void buildMetadata();
static constexpr QUuid s_TraceUuid = QUuid(0x3e589c95, 0xed11, 0xc159, 0x42, 0x02, 0x6a, 0x9b, 0x02, 0x00, 0x12, 0xac);
static constexpr quint32 s_CtfHeaderMagic = 0xC1FC1FC1;
@@ -98,9 +108,16 @@ private:
Session m_session;
QHash<QThread*, quint32> m_threadIndices;
QThreadStorage<Channel> m_threadData;
+ QList<Channel *> m_channels;
QHash<QString, const QCtfTraceMetadata *> m_additionalMetadata;
QSet<QString> m_newAdditionalMetadata;
+ QDateTime m_datetime;
int m_eventId = 0;
+ bool m_streaming = false;
+ std::atomic_bool m_sessionChanged = false;
+ std::atomic_bool m_serverClosed = false;
+ QScopedPointer<QCtfServer> m_server;
+ friend struct Channel;
};
QT_END_NAMESPACE
diff --git a/src/plugins/tracing/qctfplugin.cpp b/src/plugins/tracing/qctfplugin.cpp
index 8f2245bb28..93e508e199 100644
--- a/src/plugins/tracing/qctfplugin.cpp
+++ b/src/plugins/tracing/qctfplugin.cpp
@@ -22,9 +22,13 @@ public:
~QCtfTracePlugin()
{
m_cleanup = true;
+ *m_shutdown = true;
QCtfLibImpl::cleanup();
}
-
+ void shutdown(bool *shutdown) override
+ {
+ m_shutdown = shutdown;
+ }
bool tracepointEnabled(const QCtfTracePointEvent &point) override
{
if (m_cleanup)
@@ -51,8 +55,9 @@ public:
}
private:
bool m_cleanup = false;
+ bool *m_shutdown = nullptr;
};
-#include "qctfplugin.moc"
-
QT_END_NAMESPACE
+
+#include "qctfplugin.moc"
diff --git a/src/plugins/tracing/qctfserver.cpp b/src/plugins/tracing/qctfserver.cpp
new file mode 100644
index 0000000000..d97c345e11
--- /dev/null
+++ b/src/plugins/tracing/qctfserver.cpp
@@ -0,0 +1,404 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <qloggingcategory.h>
+#include "qctfserver_p.h"
+
+#if QT_CONFIG(zstd)
+#include <zstd.h>
+#endif
+
+using namespace Qt::Literals::StringLiterals;
+
+Q_LOGGING_CATEGORY(lcCtfInfoTrace, "qt.core.ctfserver", QtWarningMsg)
+
+#if QT_CONFIG(zstd)
+static QByteArray zstdCompress(ZSTD_CCtx *&context, const QByteArray &data, int compression)
+{
+ if (context == nullptr)
+ context = ZSTD_createCCtx();
+ qsizetype size = data.size();
+ size = ZSTD_COMPRESSBOUND(size);
+ QByteArray compressed(size, Qt::Uninitialized);
+ char *dst = compressed.data();
+ size_t n = ZSTD_compressCCtx(context, dst, size,
+ data.constData(), data.size(),
+ compression);
+ if (ZSTD_isError(n)) {
+ qCWarning(lcCtfInfoTrace) << "Compression with zstd failed: " << QString::fromUtf8(ZSTD_getErrorName(n));
+ return {};
+ }
+ compressed.truncate(n);
+ return compressed;
+}
+#endif
+
+QCtfServer::QCtfServer(QObject *parent)
+ : QThread(parent)
+{
+ m_keySet << "cliendId"_L1
+ << "clientVersion"_L1
+ << "sessionName"_L1
+ << "sessionTracepoints"_L1
+ << "flags"_L1
+ << "bufferSize"_L1
+ << "compressionScheme"_L1;
+}
+
+QCtfServer::~QCtfServer()
+{
+#if QT_CONFIG(zstd)
+ ZSTD_freeCCtx(m_zstdCCtx);
+#endif
+}
+
+void QCtfServer::setHost(const QString &address)
+{
+ m_address = address;
+}
+
+void QCtfServer::setPort(int port)
+{
+ m_port = port;
+}
+
+void QCtfServer::setCallback(ServerCallback *cb)
+{
+ m_cb = cb;
+}
+
+QString QCtfServer::sessionName() const
+{
+ return m_req.sessionName;
+}
+
+QString QCtfServer::sessionTracepoints() const
+{
+ return m_req.sessionTracepoints;
+}
+
+bool QCtfServer::bufferOnIdle() const
+{
+ return m_bufferOnIdle;
+}
+
+QCtfServer::ServerStatus QCtfServer::status() const
+{
+ return m_status;
+}
+
+void QCtfServer::setStatusAndNotify(ServerStatus status)
+{
+ m_status = status;
+ m_cb->handleStatusChange(status);
+}
+
+void QCtfServer::bytesWritten(qint64 size)
+{
+ m_writtenSize += size;
+ if (m_writtenSize >= m_waitWriteSize && m_eventLoop)
+ m_eventLoop->exit();
+}
+
+void QCtfServer::initWrite()
+{
+ m_waitWriteSize = 0;
+ m_writtenSize = 0;
+}
+
+bool QCtfServer::waitSocket()
+{
+ if (m_eventLoop)
+ m_eventLoop->exec();
+ return m_socket->state() == QTcpSocket::ConnectedState;
+}
+
+void QCtfServer::handleString(QCborStreamReader &cbor)
+{
+ const auto readString = [](QCborStreamReader &cbor) -> QString {
+ QString result;
+ auto r = cbor.readString();
+ while (r.status == QCborStreamReader::Ok) {
+ result += r.data;
+ r = cbor.readString();
+ }
+
+ if (r.status == QCborStreamReader::Error) {
+ // handle error condition
+ result.clear();
+ }
+ return result;
+ };
+ do {
+ if (m_currentKey.isEmpty()) {
+ m_currentKey = readString(cbor);
+ } else {
+ switch (m_keySet.indexOf(m_currentKey)) {
+ case RequestSessionName:
+ m_req.sessionName = readString(cbor);
+ break;
+ case RequestSessionTracepoints:
+ m_req.sessionTracepoints = readString(cbor);
+ break;
+ case RequestCompressionScheme:
+ m_requestedCompressionScheme = readString(cbor);
+ break;
+ default:
+ // handle error
+ break;
+ }
+ m_currentKey.clear();
+ }
+ if (cbor.lastError() == QCborError::EndOfFile) {
+ if (!waitSocket())
+ return;
+ cbor.reparse();
+ }
+ } while (cbor.lastError() == QCborError::EndOfFile);
+}
+
+void QCtfServer::handleFixedWidth(QCborStreamReader &cbor)
+{
+ switch (m_keySet.indexOf(m_currentKey)) {
+ case RequestClientId:
+ if (!cbor.isUnsignedInteger())
+ return;
+ m_req.clientId = cbor.toUnsignedInteger();
+ break;
+ case RequestClientVersion:
+ if (!cbor.isUnsignedInteger())
+ return;
+ m_req.clientVersion = cbor.toUnsignedInteger();
+ break;
+ case RequestFlags:
+ if (!cbor.isUnsignedInteger())
+ return;
+ m_req.flags = cbor.toUnsignedInteger();
+ break;
+ case RequestBufferSize:
+ if (!cbor.isUnsignedInteger())
+ return;
+ m_req.bufferSize = cbor.toUnsignedInteger();
+ break;
+ default:
+ // handle error
+ break;
+ }
+ m_currentKey.clear();
+}
+
+void QCtfServer::readCbor(QCborStreamReader &cbor)
+{
+ switch (cbor.type()) {
+ case QCborStreamReader::UnsignedInteger:
+ case QCborStreamReader::NegativeInteger:
+ case QCborStreamReader::SimpleType:
+ case QCborStreamReader::Float16:
+ case QCborStreamReader::Float:
+ case QCborStreamReader::Double:
+ handleFixedWidth(cbor);
+ cbor.next();
+ break;
+ case QCborStreamReader::ByteArray:
+ case QCborStreamReader::String:
+ handleString(cbor);
+ break;
+ case QCborStreamReader::Array:
+ case QCborStreamReader::Map:
+ cbor.enterContainer();
+ while (cbor.lastError() == QCborError::NoError && cbor.hasNext())
+ readCbor(cbor);
+ if (cbor.lastError() == QCborError::NoError)
+ cbor.leaveContainer();
+ default:
+ break;
+ }
+}
+
+void QCtfServer::writePacket(TracePacket &packet, QCborStreamWriter &cbor)
+{
+ cbor.startMap(4);
+ cbor.append("magic"_L1);
+ cbor.append(packet.PacketMagicNumber);
+ cbor.append("name"_L1);
+ cbor.append(QString::fromUtf8(packet.stream_name));
+ cbor.append("flags"_L1);
+ cbor.append(packet.flags);
+
+ cbor.append("data"_L1);
+ if (m_compression > 0) {
+ QByteArray compressed;
+#if QT_CONFIG(zstd)
+ if (m_requestedCompressionScheme == QStringLiteral("zstd"))
+ compressed = zstdCompress(m_zstdCCtx, packet.stream_data, m_compression);
+ else
+#endif
+ compressed = qCompress(packet.stream_data, m_compression);
+
+ cbor.append(compressed);
+ } else {
+ cbor.append(packet.stream_data);
+ }
+
+ cbor.endMap();
+}
+
+bool QCtfServer::recognizedCompressionScheme() const
+{
+ if (m_requestedCompressionScheme.isEmpty())
+ return true;
+#if QT_CONFIG(zstd)
+ if (m_requestedCompressionScheme == QStringLiteral("zstd"))
+ return true;
+#endif
+ if (m_requestedCompressionScheme == QStringLiteral("zlib"))
+ return true;
+ return false;
+}
+
+void QCtfServer::run()
+{
+ m_server = new QTcpServer();
+ QHostAddress addr;
+ if (m_address.isEmpty())
+ addr = QHostAddress(QHostAddress::Any);
+ else
+ addr = QHostAddress(m_address);
+
+ qCInfo(lcCtfInfoTrace) << "Starting CTF server: " << m_address << ", port: " << m_port;
+
+ while (m_stopping == 0) {
+ if (!m_server->isListening()) {
+ if (!m_server->listen(addr, m_port)) {
+ qCInfo(lcCtfInfoTrace) << "Unable to start server";
+ m_stopping = 1;
+ setStatusAndNotify(Error);
+ }
+ }
+ setStatusAndNotify(Idle);
+ if (m_server->waitForNewConnection(-1)) {
+ qCInfo(lcCtfInfoTrace) << "client connection";
+ m_eventLoop = new QEventLoop();
+ m_socket = m_server->nextPendingConnection();
+
+ QObject::connect(m_socket, &QTcpSocket::readyRead, [&](){
+ if (m_eventLoop) m_eventLoop->exit();
+ });
+ QObject::connect(m_socket, &QTcpSocket::bytesWritten, this, &QCtfServer::bytesWritten);
+ QObject::connect(m_socket, &QTcpSocket::disconnected, [&](){
+ if (m_eventLoop) m_eventLoop->exit();
+ });
+
+ m_server->close(); // Do not wait for more connections
+ setStatusAndNotify(Connected);
+
+ if (waitSocket())
+ {
+ QCborStreamReader cbor(m_socket);
+
+ m_req = {};
+ while (cbor.hasNext() && cbor.lastError() == QCborError::NoError)
+ readCbor(cbor);
+
+ if (!m_req.isValid()) {
+ qCInfo(lcCtfInfoTrace) << "Invalid trace request.";
+ m_socket->close();
+ } else {
+ m_compression = m_req.flags & CompressionMask;
+#if QT_CONFIG(zstd)
+ m_compression = qMin(m_compression, ZSTD_maxCLevel());
+#else
+ m_compression = qMin(m_compression, 9);
+#endif
+ m_bufferOnIdle = !(m_req.flags & DontBufferOnIdle);
+
+ m_maxPackets = qMax(m_req.bufferSize / TracePacket::PacketSize, 16u);
+
+ if (!recognizedCompressionScheme()) {
+ qCWarning(lcCtfInfoTrace) << "Client requested unrecognized compression scheme: " << m_requestedCompressionScheme;
+ m_requestedCompressionScheme.clear();
+ m_compression = 0;
+ }
+
+ qCInfo(lcCtfInfoTrace) << "request received: " << m_req.sessionName << ", " << m_req.sessionTracepoints;
+
+ m_cb->handleSessionChange();
+ {
+ TraceResponse resp;
+ resp.serverId = ServerId;
+ resp.serverVersion = 1;
+ resp.serverName = QStringLiteral("Ctf Server");
+
+ QCborStreamWriter cbor(m_socket);
+ cbor.startMap(m_compression ? 4 : 3);
+ cbor.append("serverId"_L1);
+ cbor.append(resp.serverId);
+ cbor.append("serverVersion"_L1);
+ cbor.append(resp.serverVersion);
+ cbor.append("serverName"_L1);
+ cbor.append(resp.serverName);
+ if (m_compression) {
+ cbor.append("compressionScheme"_L1);
+ cbor.append(m_requestedCompressionScheme);
+ }
+ cbor.endMap();
+ }
+
+ qCInfo(lcCtfInfoTrace) << "response sent, sending data";
+ if (waitSocket()) {
+ while (m_socket->state() == QTcpSocket::ConnectedState) {
+ QList<TracePacket> packets;
+ {
+ QMutexLocker lock(&m_mutex);
+ while (m_packets.size() == 0)
+ m_bufferHasData.wait(&m_mutex);
+ packets = std::exchange(m_packets, {});
+ }
+
+ {
+ QCborStreamWriter cbor(m_socket);
+ for (TracePacket &packet : packets) {
+ writePacket(packet, cbor);
+ if (!waitSocket())
+ break;
+ }
+ }
+ qCInfo(lcCtfInfoTrace) << packets.size() << " packets written";
+ }
+ }
+
+ qCInfo(lcCtfInfoTrace) << "client connection closed";
+ }
+ }
+ delete m_eventLoop;
+ m_eventLoop = nullptr;
+ } else {
+ qCInfo(lcCtfInfoTrace) << "error: " << m_server->errorString();
+ m_stopping = 1;
+ setStatusAndNotify(Error);
+ }
+ }
+}
+
+void QCtfServer::startServer()
+{
+ start();
+}
+void QCtfServer::stopServer()
+{
+ this->m_stopping = 1;
+ wait();
+}
+
+void QCtfServer::bufferData(const QString &stream, const QByteArray &data, quint32 flags)
+{
+ QMutexLocker lock(&m_mutex);
+ TracePacket packet;
+ packet.stream_name = stream.toUtf8();
+ packet.stream_data = data;
+ packet.flags = flags;
+ m_packets.append(packet);
+ if (m_packets.size() > m_maxPackets)
+ m_packets.pop_front();
+ m_bufferHasData.wakeOne();
+}
diff --git a/src/plugins/tracing/qctfserver_p.h b/src/plugins/tracing/qctfserver_p.h
new file mode 100644
index 0000000000..3660df7f09
--- /dev/null
+++ b/src/plugins/tracing/qctfserver_p.h
@@ -0,0 +1,194 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QT_CTFSERVER_H
+#define QT_CTFSERVER_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 <qbytearray.h>
+#include <qdatastream.h>
+#include <qthread.h>
+#include <qmutex.h>
+#include <qwaitcondition.h>
+#include <qeventloop.h>
+#include <QtNetwork/qtcpserver.h>
+#include <QtNetwork/qtcpsocket.h>
+#include <qcborstreamreader.h>
+#include <qcborstreamwriter.h>
+#include <qlist.h>
+
+typedef struct ZSTD_CCtx_s ZSTD_CCtx;
+
+QT_BEGIN_NAMESPACE
+
+class QCtfServer;
+struct TracePacket
+{
+ static constexpr quint32 PacketMagicNumber = 0x100924da;
+ static constexpr quint32 PacketSize = 4096 + 9;
+ QByteArray stream_name;
+ QByteArray stream_data;
+ quint32 flags = 0;
+
+ TracePacket() = default;
+
+ TracePacket(const TracePacket &t)
+ {
+ stream_name = t.stream_name;
+ stream_data = t.stream_data;
+ flags = t.flags;
+ }
+ TracePacket &operator = (const TracePacket &t)
+ {
+ stream_name = t.stream_name;
+ stream_data = t.stream_data;
+ flags = t.flags;
+ return *this;
+ }
+ TracePacket(TracePacket &&t)
+ {
+ stream_name = std::move(t.stream_name);
+ stream_data = std::move(t.stream_data);
+ flags = t.flags;
+ }
+ TracePacket &operator = (TracePacket &&t)
+ {
+ stream_name = std::move(t.stream_name);
+ stream_data = std::move(t.stream_data);
+ flags = t.flags;
+ return *this;
+ }
+};
+
+auto constexpr operator""_MB(quint64 s) -> quint64
+{
+ return s * 1024ul * 1024ul;
+}
+
+struct TraceRequest
+{
+ quint32 clientId;
+ quint32 clientVersion;
+ quint32 flags;
+ quint32 bufferSize;
+ QString sessionName;
+ QString sessionTracepoints;
+
+ static constexpr quint32 MaxBufferSize = 1024_MB;
+
+ bool isValid() const
+ {
+ if (clientId != 0 && clientVersion != 0 && !sessionName.isEmpty()
+ && !sessionTracepoints.isEmpty() && bufferSize < MaxBufferSize)
+ return true;
+ return false;
+ }
+};
+
+struct TraceResponse
+{
+ quint32 serverId;
+ quint32 serverVersion;
+ QString serverName;
+};
+
+class QCtfServer : public QThread
+{
+ Q_OBJECT
+public:
+ enum ServerStatus
+ {
+ Uninitialized,
+ Idle,
+ Connected,
+ Error,
+ };
+ enum ServerFlags
+ {
+ CompressionMask = 255,
+ DontBufferOnIdle = 256, // not set -> the server is buffering even without client connection
+ // set -> the server is buffering only when client is connected
+ };
+ enum RequestIds
+ {
+ RequestClientId = 0,
+ RequestClientVersion,
+ RequestSessionName,
+ RequestSessionTracepoints,
+ RequestFlags,
+ RequestBufferSize,
+ RequestCompressionScheme,
+ };
+
+ struct ServerCallback
+ {
+ virtual void handleSessionChange() = 0;
+ virtual void handleStatusChange(ServerStatus status) = 0;
+ };
+ QCtfServer(QObject *parent = nullptr);
+ ~QCtfServer();
+ void setCallback(ServerCallback *cb);
+ void setHost(const QString &address);
+ void setPort(int port);
+ void run() override;
+ void startServer();
+ void stopServer();
+ void bufferData(const QString &stream, const QByteArray &data, quint32 flags);
+ QString sessionName() const;
+ QString sessionTracepoints() const;
+ bool bufferOnIdle() const;
+ ServerStatus status() const;
+private:
+
+ void initWrite();
+ void bytesWritten(qint64 size);
+ bool waitSocket();
+ void readCbor(QCborStreamReader &cbor);
+ void handleString(QCborStreamReader &cbor);
+ void handleFixedWidth(QCborStreamReader &cbor);
+ bool recognizedCompressionScheme() const;
+ void setStatusAndNotify(ServerStatus status);
+ void writePacket(TracePacket &packet, QCborStreamWriter &cbor);
+
+ QMutex m_mutex;
+ QWaitCondition m_bufferHasData;
+ QList<TracePacket> m_packets;
+ QString m_address;
+ QTcpServer *m_server = nullptr;
+ QTcpSocket *m_socket = nullptr;
+ QEventLoop *m_eventLoop = nullptr;
+ QList<QString> m_keySet;
+ TraceRequest m_req;
+ ServerCallback *m_cb = nullptr;
+ ServerStatus m_status = Uninitialized;
+ qint64 m_waitWriteSize = 0;
+ qint64 m_writtenSize = 0;
+ int m_port;
+ int m_compression = 0;
+ int m_maxPackets = DefaultMaxPackets;
+ QAtomicInt m_stopping;
+ bool m_bufferOnIdle = true;
+ QString m_currentKey;
+ QString m_requestedCompressionScheme;
+#if QT_CONFIG(zstd)
+ ZSTD_CCtx *m_zstdCCtx = nullptr;
+#endif
+
+ static constexpr quint32 ServerId = 1;
+ static constexpr quint32 DefaultMaxPackets = 256; // 1 MB
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/printsupport/CMakeLists.txt b/src/printsupport/CMakeLists.txt
index 330f44c689..25aad04caf 100644
--- a/src/printsupport/CMakeLists.txt
+++ b/src/printsupport/CMakeLists.txt
@@ -20,8 +20,10 @@ qt_internal_add_module(PrintSupport
kernel/qprinterinfo.cpp kernel/qprinterinfo.h kernel/qprinterinfo_p.h
kernel/qtprintsupportglobal.h kernel/qtprintsupportglobal_p.h
DEFINES
+ QT_NO_CONTEXTLESS_CONNECT
QT_NO_FOREACH
QT_NO_USING_NAMESPACE
+ QT_USE_NODISCARD_FILE_OPEN
INCLUDE_DIRECTORIES
dialogs
widgets
@@ -59,7 +61,7 @@ qt_internal_extend_target(PrintSupport CONDITION MACOS
${FWApplicationServices}
Cups::Cups
NO_PCH_SOURCES
- "platform/macos/qcocoaprintersupport.mm"
+ platform/macos/qcocoaprintersupport.mm
)
qt_internal_extend_target(PrintSupport CONDITION WIN32
@@ -74,13 +76,9 @@ qt_internal_extend_target(PrintSupport CONDITION WIN32
comdlg32
winspool
NO_PCH_SOURCES
- "platform/windows/qwindowsprintersupport.cpp"
+ platform/windows/qwindowsprintersupport.cpp
)
-set_source_files_properties(platform/macos/qcocoaprintersupport.mm # NO_PCH_SOURCES
- platform/windows/qwindowsprintersupport.cpp
- PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
-
qt_internal_extend_target(PrintSupport CONDITION QT_FEATURE_printpreviewwidget
SOURCES
kernel/qpaintengine_preview.cpp kernel/qpaintengine_preview_p.h
@@ -188,15 +186,14 @@ qt_internal_extend_target(PrintSupport CONDITION QT_FEATURE_printdialog AND UNIX
dialogs/qprintpropertieswidget.ui
dialogs/qprintsettingsoutput.ui
dialogs/qprintwidget.ui
+ NO_UNITY_BUILD_SOURCES
+ dialogs/qprintdialog_unix.cpp # Clashes with CUPS headers
INCLUDE_DIRECTORIES
${QtBase_SOURCE_DIR}/src/plugins/printsupport/cups
ENABLE_AUTOGEN_TOOLS
uic
)
-# Clashes with CUPS headers
-set_source_files_properties(dialogs/qprintdialog_unix.cpp PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
-
qt_internal_extend_target(PrintSupport CONDITION QT_FEATURE_printpreviewdialog
SOURCES
dialogs/qprintpreviewdialog.cpp dialogs/qprintpreviewdialog.h
diff --git a/src/printsupport/dialogs/qabstractprintdialog_p.h b/src/printsupport/dialogs/qabstractprintdialog_p.h
index baf6027c10..40f25d454a 100644
--- a/src/printsupport/dialogs/qabstractprintdialog_p.h
+++ b/src/printsupport/dialogs/qabstractprintdialog_p.h
@@ -20,6 +20,8 @@
#include "private/qdialog_p.h"
#include "QtPrintSupport/qabstractprintdialog.h"
+#include <QtCore/qpointer.h>
+
QT_REQUIRE_CONFIG(printdialog);
QT_BEGIN_NAMESPACE
diff --git a/src/printsupport/dialogs/qpagesetupdialog_win.cpp b/src/printsupport/dialogs/qpagesetupdialog_win.cpp
index d7004ec3f1..1d2fdc98b7 100644
--- a/src/printsupport/dialogs/qpagesetupdialog_win.cpp
+++ b/src/printsupport/dialogs/qpagesetupdialog_win.cpp
@@ -20,7 +20,7 @@ QPageSetupDialog::QPageSetupDialog(QPrinter *printer, QWidget *parent)
}
QPageSetupDialog::QPageSetupDialog(QWidget *parent)
- : QDialog(*(new QPageSetupDialogPrivate(0)), parent)
+ : QDialog(*(new QPageSetupDialogPrivate(nullptr)), parent)
{
setWindowTitle(QCoreApplication::translate("QPrintPreviewDialog", "Page Setup"));
setAttribute(Qt::WA_DontShowOnScreen);
@@ -41,7 +41,7 @@ int QPageSetupDialog::exec()
psd.lStructSize = sizeof(PAGESETUPDLG);
// we need a temp DEVMODE struct if we don't have a global DEVMODE
- HGLOBAL hDevMode = 0;
+ HGLOBAL hDevMode = nullptr;
int devModeSize = 0;
if (!engine->globalDevMode()) {
devModeSize = sizeof(DEVMODE) + ep->devMode->dmDriverExtra;
@@ -63,9 +63,10 @@ int QPageSetupDialog::exec()
parent = parent ? parent->window() : QApplication::activeWindow();
Q_ASSERT(!parent ||parent->testAttribute(Qt::WA_WState_Created));
- QWindow *parentWindow = parent ? parent->windowHandle() : 0;
- psd.hwndOwner = parentWindow ? (HWND)QGuiApplication::platformNativeInterface()->nativeResourceForWindow("handle", parentWindow) : 0;
-
+ QWindow *parentWindow = parent ? parent->windowHandle() : nullptr;
+ psd.hwndOwner = parentWindow
+ ? HWND(QGuiApplication::platformNativeInterface()->nativeResourceForWindow("handle", parentWindow))
+ : nullptr;
psd.Flags = PSD_MARGINS;
QPageLayout layout = d->printer->pageLayout();
switch (layout.units()) {
@@ -122,10 +123,10 @@ int QPageSetupDialog::exec()
pageSize = QPageSize(unitSize, layout.units() == QPageLayout::Inch
? QPageSize::Inch : QPageSize::Millimeter);
}
- layout.setPageSize(pageSize);
+ layout.setPageSize(pageSize, layout.minimumMargins());
const QMarginsF margins(psd.rtMargin.left, psd.rtMargin.top, psd.rtMargin.right, psd.rtMargin.bottom);
- layout.setMargins(margins / multiplier);
+ layout.setMargins(margins / multiplier, QPageLayout::OutOfBoundsPolicy::Clamp);
d->printer->setPageLayout(layout);
// copy from our temp DEVMODE struct
@@ -133,7 +134,8 @@ int QPageSetupDialog::exec()
// Make sure memory is allocated
if (ep->ownsDevMode && ep->devMode)
free(ep->devMode);
- ep->devMode = (DEVMODE *) malloc(devModeSize);
+ ep->devMode = reinterpret_cast<DEVMODE *>(malloc(devModeSize));
+ QWin32PrintEnginePrivate::initializeDevMode(ep->devMode);
ep->ownsDevMode = true;
// Copy
diff --git a/src/printsupport/dialogs/qprintdialog_mac.mm b/src/printsupport/dialogs/qprintdialog_mac.mm
index b1b56dbf54..fa4fac1884 100644
--- a/src/printsupport/dialogs/qprintdialog_mac.mm
+++ b/src/printsupport/dialogs/qprintdialog_mac.mm
@@ -238,8 +238,8 @@ void QPrintDialogPrivate::openCocoaPrintPanel(Qt::WindowModality modality)
int rval = [printPanel runModalWithPrintInfo:printInfo];
[delegate printPanelDidEnd:printPanel returnCode:rval contextInfo:q];
} else {
- Q_ASSERT(q->parentWidget());
- QWindow *parentWindow = q->parentWidget()->windowHandle();
+ Q_ASSERT(q->window());
+ QWindow *parentWindow = q->window()->windowHandle();
NSWindow *window = static_cast<NSWindow *>(qApp->platformNativeInterface()->nativeResourceForWindow("nswindow", parentWindow));
[printPanel beginSheetWithPrintInfo:printInfo
modalForWindow:window
@@ -271,6 +271,7 @@ QPrintDialog::QPrintDialog(QWidget *parent)
QPrintDialog::~QPrintDialog()
{
+ hide();
}
int QPrintDialog::exec()
diff --git a/src/printsupport/dialogs/qprintdialog_unix.cpp b/src/printsupport/dialogs/qprintdialog_unix.cpp
index ae4ee193a0..aab5e2c7f0 100644
--- a/src/printsupport/dialogs/qprintdialog_unix.cpp
+++ b/src/printsupport/dialogs/qprintdialog_unix.cpp
@@ -1328,9 +1328,9 @@ QUnixPrintWidget::QUnixPrintWidget(QPrinter *printer, QWidget *parent)
cur = home;
else if (!cur.endsWith(u'/'))
cur += u'/';
- if (QGuiApplication::platformName() == QStringLiteral("xcb")) {
+ if (QGuiApplication::platformName() == "xcb"_L1) {
if (printer->docName().isEmpty()) {
- cur += QStringLiteral("print.pdf");
+ cur += "print.pdf"_L1;
} else {
#if QT_CONFIG(regularexpression)
const QRegularExpression re(QStringLiteral("(.*)\\.\\S+"));
@@ -1340,7 +1340,7 @@ QUnixPrintWidget::QUnixPrintWidget(QPrinter *printer, QWidget *parent)
else
#endif
cur += printer->docName();
- cur += QStringLiteral(".pdf");
+ cur += ".pdf"_L1;
}
} // xcb
diff --git a/src/printsupport/dialogs/qprintdialog_win.cpp b/src/printsupport/dialogs/qprintdialog_win.cpp
index 9d662d2e8e..6d8c2d0f4d 100644
--- a/src/printsupport/dialogs/qprintdialog_win.cpp
+++ b/src/printsupport/dialogs/qprintdialog_win.cpp
@@ -42,7 +42,7 @@ public:
QWin32PrintEnginePrivate *ep;
};
-static void qt_win_setup_PRINTDLGEX(PRINTDLGEX *pd, QWidget *parent,
+static void qt_win_setup_PRINTDLGEX(PRINTDLGEX *pd, QWindow *parentWindow,
QPrintDialog *pdlg,
QPrintDialogPrivate *d, HGLOBAL *tempDevNames)
{
@@ -101,9 +101,12 @@ static void qt_win_setup_PRINTDLGEX(PRINTDLGEX *pd, QWidget *parent,
if (d->ep->printToFile)
pd->Flags |= PD_PRINTTOFILE;
- Q_ASSERT(parent);
- QWindow *parentWindow = parent->windowHandle();
- pd->hwndOwner = parentWindow ? (HWND)QGuiApplication::platformNativeInterface()->nativeResourceForWindow("handle", parentWindow) : 0;
+
+ WId wId = parentWindow ? parentWindow->winId() : 0;
+ //QTBUG-118899 PrintDlg needs valid window handle in hwndOwner
+ //So in case there is no valid handle in the application,
+ //use the desktop as valid handle.
+ pd->hwndOwner = wId != 0 ? HWND(wId) : GetDesktopWindow();
pd->lpPageRanges[0].nFromPage = qMax(pdlg->fromPage(), pdlg->minPage());
pd->lpPageRanges[0].nToPage = (pdlg->toPage() > 0) ? qMin(pdlg->toPage(), pdlg->maxPage()) : 1;
pd->nCopies = d->printer->copyCount();
@@ -182,15 +185,20 @@ int QPrintDialog::exec()
int QPrintDialogPrivate::openWindowsPrintDialogModally()
{
Q_Q(QPrintDialog);
- QWidget *parent = q->parentWidget();
- if (parent)
- parent = parent->window();
- else
- parent = QApplication::activeWindow();
-
- // If there is no window, fall back to the print dialog itself
- if (parent == 0)
- parent = q;
+ QWindow *parentWindow = q->windowHandle() ? q->windowHandle()->transientParent() : nullptr;
+ if (!parentWindow) {
+ QWidget *parent = q->parentWidget();
+ if (parent)
+ parent = parent->window();
+ else
+ parent = QApplication::activeWindow();
+
+ // If there is no window, fall back to the print dialog itself
+ if (!parent)
+ parent = q;
+
+ parentWindow = parent->windowHandle();
+ }
q->QDialog::setVisible(true);
@@ -205,7 +213,7 @@ int QPrintDialogPrivate::openWindowsPrintDialogModally()
memset(&pd, 0, sizeof(PRINTDLGEX));
pd.lStructSize = sizeof(PRINTDLGEX);
pd.lpPageRanges = &pageRange;
- qt_win_setup_PRINTDLGEX(&pd, parent, q, this, tempDevNames);
+ qt_win_setup_PRINTDLGEX(&pd, parentWindow, q, this, tempDevNames);
do {
done = true;
diff --git a/src/printsupport/dialogs/qprintpreviewdialog.cpp b/src/printsupport/dialogs/qprintpreviewdialog.cpp
index abcc39ac19..2028287b55 100644
--- a/src/printsupport/dialogs/qprintpreviewdialog.cpp
+++ b/src/printsupport/dialogs/qprintpreviewdialog.cpp
@@ -28,6 +28,8 @@
#include <QtWidgets/qformlayout.h>
#include <QtWidgets/qlabel.h>
+#include <QtCore/qpointer.h>
+
static void _q_ppd_initResources()
{
static bool resourcesInitialized = false;
diff --git a/src/printsupport/doc/qtprintsupport.qdocconf b/src/printsupport/doc/qtprintsupport.qdocconf
index 1e72873e4d..f1b541bafb 100644
--- a/src/printsupport/doc/qtprintsupport.qdocconf
+++ b/src/printsupport/doc/qtprintsupport.qdocconf
@@ -41,5 +41,5 @@ imagedirs += images \
navigation.landingpage = "Qt Print Support"
navigation.cppclassespage = "Qt Print Support C++ Classes"
-# Fail the documentation build if there are more warnings than the limit
+# Enforce zero documentation warnings
warninglimit = 0
diff --git a/src/printsupport/doc/snippets/CMakeLists.txt b/src/printsupport/doc/snippets/CMakeLists.txt
index 02f71bc289..bedcdbb662 100644
--- a/src/printsupport/doc/snippets/CMakeLists.txt
+++ b/src/printsupport/doc/snippets/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#! [cmake_use]
find_package(Qt6 REQUIRED COMPONENTS PrintSupport)
diff --git a/src/printsupport/doc/src/qt6-changes.qdoc b/src/printsupport/doc/src/qt6-changes.qdoc
index 5706aa4c7c..958301c9c7 100644
--- a/src/printsupport/doc/src/qt6-changes.qdoc
+++ b/src/printsupport/doc/src/qt6-changes.qdoc
@@ -5,7 +5,7 @@
\page printsupport-changes-qt6.html
\title Changes to Qt Print Support
\ingroup changes-qt-5-to-6
- \brief Migrate Qt Print Support to Qt 6.
+ \brief General API consolidation.
Qt 6 is a result of the conscious effort to make the framework more
efficient and easy to use.
diff --git a/src/printsupport/kernel/qcups.cpp b/src/printsupport/kernel/qcups.cpp
index 051b1a8552..231b816499 100644
--- a/src/printsupport/kernel/qcups.cpp
+++ b/src/printsupport/kernel/qcups.cpp
@@ -109,9 +109,9 @@ QCUPSSupport::JobHoldUntilWithTime QCUPSSupport::parseJobHoldUntil(const QString
}
- QTime parsedTime = QTime::fromString(jobHoldUntil, QStringLiteral("h:m:s"));
+ QTime parsedTime = QTime::fromString(jobHoldUntil, u"h:m:s");
if (!parsedTime.isValid())
- parsedTime = QTime::fromString(jobHoldUntil, QStringLiteral("h:m"));
+ parsedTime = QTime::fromString(jobHoldUntil, u"h:m");
if (parsedTime.isValid()) {
// CUPS time is in UTC, user expects local time, so get the equivalent
QDateTime dateTimeUtc = QDateTime::currentDateTimeUtc();
diff --git a/src/printsupport/kernel/qplatformprintdevice.cpp b/src/printsupport/kernel/qplatformprintdevice.cpp
index 0ea0242edd..a2ee51f887 100644
--- a/src/printsupport/kernel/qplatformprintdevice.cpp
+++ b/src/printsupport/kernel/qplatformprintdevice.cpp
@@ -75,6 +75,10 @@ bool QPlatformPrintDevice::isValidPageLayout(const QPageLayout &layout, int reso
if (!supportedPageSize(layout.pageSize()).isValid())
return false;
+ // In fullpage mode, margins outside the printable area are valid
+ if (layout.mode() == QPageLayout::FullPageMode)
+ return true;
+
// Check the margins are valid
QMarginsF pointMargins = layout.margins(QPageLayout::Point);
QMarginsF printMargins = printableMargins(layout.pageSize(), layout.orientation(), resolution);
diff --git a/src/printsupport/kernel/qprint_p.h b/src/printsupport/kernel/qprint_p.h
index 6c30e388f6..0a94aa8db3 100644
--- a/src/printsupport/kernel/qprint_p.h
+++ b/src/printsupport/kernel/qprint_p.h
@@ -68,6 +68,7 @@ namespace QPrint {
DuplexShortSide
};
+ // Note: Keep in sync with QPrinter::ColorMode
enum ColorMode {
GrayScale,
Color
diff --git a/src/printsupport/kernel/qprintengine_pdf.cpp b/src/printsupport/kernel/qprintengine_pdf.cpp
index daf5010feb..3e50247186 100644
--- a/src/printsupport/kernel/qprintengine_pdf.cpp
+++ b/src/printsupport/kernel/qprintengine_pdf.cpp
@@ -104,7 +104,14 @@ void QPdfPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va
d->collate = value.toBool();
break;
case PPK_ColorMode:
- d->grayscale = (QPrinter::ColorMode(value.toInt()) == QPrinter::GrayScale);
+ switch (QPrinter::ColorMode(value.toInt())) {
+ case QPrinter::GrayScale:
+ d->colorModel = QPdfEngine::ColorModel::Grayscale;
+ break;
+ case QPrinter::Color:
+ d->colorModel = QPdfEngine::ColorModel::Auto;
+ break;
+ }
break;
case PPK_Creator:
d->creator = value.toString();
@@ -177,7 +184,8 @@ void QPdfPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va
Q_ASSERT(margins.size() == 4);
d->m_pageLayout.setUnits(QPageLayout::Point);
d->m_pageLayout.setMargins(QMarginsF(margins.at(0).toReal(), margins.at(1).toReal(),
- margins.at(2).toReal(), margins.at(3).toReal()));
+ margins.at(2).toReal(), margins.at(3).toReal()),
+ QPageLayout::OutOfBoundsPolicy::Clamp);
break;
}
case PPK_QPageSize: {
@@ -189,7 +197,7 @@ void QPdfPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va
case PPK_QPageMargins: {
QPair<QMarginsF, QPageLayout::Unit> pair = qvariant_cast<QPair<QMarginsF, QPageLayout::Unit> >(value);
d->m_pageLayout.setUnits(pair.second);
- d->m_pageLayout.setMargins(pair.first);
+ d->m_pageLayout.setMargins(pair.first, QPageLayout::OutOfBoundsPolicy::Clamp);
break;
}
case PPK_QPageLayout: {
@@ -221,7 +229,7 @@ QVariant QPdfPrintEngine::property(PrintEnginePropertyKey key) const
ret = d->collate;
break;
case PPK_ColorMode:
- ret = d->grayscale ? QPrinter::GrayScale : QPrinter::Color;
+ ret = d->printerColorMode();
break;
case PPK_Creator:
ret = d->creator;
@@ -367,6 +375,22 @@ QPdfPrintEnginePrivate::~QPdfPrintEnginePrivate()
{
}
+QPrinter::ColorMode QPdfPrintEnginePrivate::printerColorMode() const
+{
+ switch (colorModel) {
+ case QPdfEngine::ColorModel::RGB:
+ case QPdfEngine::ColorModel::CMYK:
+ case QPdfEngine::ColorModel::Auto:
+ return QPrinter::Color;
+ case QPdfEngine::ColorModel::Grayscale:
+ return QPrinter::GrayScale;
+ }
+
+ Q_UNREACHABLE();
+ return QPrinter::Color;
+}
+
+
QT_END_NAMESPACE
#endif // QT_NO_PRINTER
diff --git a/src/printsupport/kernel/qprintengine_pdf_p.h b/src/printsupport/kernel/qprintengine_pdf_p.h
index ccef8215e1..dbf50080a4 100644
--- a/src/printsupport/kernel/qprintengine_pdf_p.h
+++ b/src/printsupport/kernel/qprintengine_pdf_p.h
@@ -79,6 +79,8 @@ public:
QPdfPrintEnginePrivate(QPrinter::PrinterMode m);
~QPdfPrintEnginePrivate();
+ QPrinter::ColorMode printerColorMode() const;
+
virtual bool openPrintDevice();
virtual void closePrintDevice();
diff --git a/src/printsupport/kernel/qprinter.cpp b/src/printsupport/kernel/qprinter.cpp
index c4af319c0c..10c4c681ba 100644
--- a/src/printsupport/kernel/qprinter.cpp
+++ b/src/printsupport/kernel/qprinter.cpp
@@ -129,6 +129,11 @@ QList<const QPicture *> QPrinterPrivate::previewPages() const
return QList<const QPicture *>();
}
+bool QPrinterPrivate::previewMode() const
+{
+ return (previewEngine != nullptr) && (previewEngine == printEngine);
+}
+
void QPrinterPrivate::setPreviewMode(bool enable)
{
Q_Q(QPrinter);
diff --git a/src/printsupport/kernel/qprinter_p.h b/src/printsupport/kernel/qprinter_p.h
index 3c6cf711b0..77dd5fb4bc 100644
--- a/src/printsupport/kernel/qprinter_p.h
+++ b/src/printsupport/kernel/qprinter_p.h
@@ -70,6 +70,7 @@ public:
#if QT_CONFIG(printpreviewwidget)
QList<const QPicture *> previewPages() const;
void setPreviewMode(bool);
+ bool previewMode() const;
#endif
void setProperty(QPrintEngine::PrintEnginePropertyKey key, const QVariant &value);
diff --git a/src/printsupport/kernel/qprinterinfo.cpp b/src/printsupport/kernel/qprinterinfo.cpp
index 176c6d6428..59078b4df4 100644
--- a/src/printsupport/kernel/qprinterinfo.cpp
+++ b/src/printsupport/kernel/qprinterinfo.cpp
@@ -21,7 +21,7 @@ class QPrinterInfoPrivateDeleter
public:
static inline void cleanup(QPrinterInfoPrivate *d)
{
- if (d != shared_null)
+ if (d != &*shared_null)
delete d;
}
};
@@ -70,7 +70,7 @@ QPrinterInfo::QPrinterInfo()
Constructs a copy of \a other.
*/
QPrinterInfo::QPrinterInfo(const QPrinterInfo &other)
- : d_ptr((other.d_ptr.data() == shared_null) ? shared_null : new QPrinterInfoPrivate(*other.d_ptr))
+ : d_ptr((other.d_ptr.data() == shared_null) ? &*shared_null : new QPrinterInfoPrivate(*other.d_ptr))
{
}
diff --git a/src/printsupport/kernel/qprinterinfo.h b/src/printsupport/kernel/qprinterinfo.h
index 98b9f2940e..f1b16e7ccb 100644
--- a/src/printsupport/kernel/qprinterinfo.h
+++ b/src/printsupport/kernel/qprinterinfo.h
@@ -8,7 +8,6 @@
#include <QtPrintSupport/qprinter.h>
#include <QtCore/QList>
-#include <QtCore/QPair>
#include <QtGui/qpagesize.h>
QT_BEGIN_NAMESPACE
diff --git a/src/printsupport/platform/macos/qpaintengine_mac.mm b/src/printsupport/platform/macos/qpaintengine_mac.mm
index c38d8cdd66..27274f116e 100644
--- a/src/printsupport/platform/macos/qpaintengine_mac.mm
+++ b/src/printsupport/platform/macos/qpaintengine_mac.mm
@@ -48,7 +48,7 @@ CGImageRef qt_mac_create_imagemask(const QPixmap &pixmap, const QRectF &sr)
{
QImage image = pixmap.toImage();
if (image.format() != QImage::Format_ARGB32_Premultiplied)
- image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ image = std::move(image).convertToFormat(QImage::Format_ARGB32_Premultiplied);
const int sx = qRound(sr.x()), sy = qRound(sr.y()), sw = qRound(sr.width()), sh = qRound(sr.height());
const qsizetype sbpr = image.bytesPerLine();
diff --git a/src/printsupport/platform/macos/qprintengine_mac.mm b/src/printsupport/platform/macos/qprintengine_mac.mm
index 031f5b3146..d6eb71f66d 100644
--- a/src/printsupport/platform/macos/qprintengine_mac.mm
+++ b/src/printsupport/platform/macos/qprintengine_mac.mm
@@ -219,9 +219,9 @@ void QMacPrintEnginePrivate::initialize()
if (!resolutions.isEmpty() && mode != QPrinter::ScreenResolution) {
std::sort(resolutions.begin(), resolutions.end());
if (resolutions.count() > 1 && mode == QPrinter::HighResolution)
- resolution.hRes = resolution.vRes = resolutions.last();
+ resolution.hRes = resolution.vRes = resolutions.constLast();
else
- resolution.hRes = resolution.vRes = resolutions.first();
+ resolution.hRes = resolution.vRes = resolutions.constFirst();
if (resolution.hRes == 0)
resolution.hRes = resolution.vRes = 600;
} else {
@@ -576,7 +576,8 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va
QList<QVariant> margins(value.toList());
Q_ASSERT(margins.size() == 4);
d->m_pageLayout.setMargins(QMarginsF(margins.at(0).toReal(), margins.at(1).toReal(),
- margins.at(2).toReal(), margins.at(3).toReal()));
+ margins.at(2).toReal(), margins.at(3).toReal()),
+ QPageLayout::OutOfBoundsPolicy::Clamp);
break;
}
case PPK_QPageSize:
@@ -585,7 +586,7 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va
case PPK_QPageMargins: {
QPair<QMarginsF, QPageLayout::Unit> pair = value.value<QPair<QMarginsF, QPageLayout::Unit> >();
d->m_pageLayout.setUnits(pair.second);
- d->m_pageLayout.setMargins(pair.first);
+ d->m_pageLayout.setMargins(pair.first, QPageLayout::OutOfBoundsPolicy::Clamp);
break;
}
case PPK_QPageLayout: {
@@ -595,7 +596,7 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va
setProperty(PPK_FullPage, pageLayout.mode() == QPageLayout::FullPageMode);
setProperty(PPK_Orientation, QVariant::fromValue(pageLayout.orientation()));
d->m_pageLayout.setUnits(pageLayout.units());
- d->m_pageLayout.setMargins(pageLayout.margins());
+ d->m_pageLayout.setMargins(pageLayout.margins(), QPageLayout::OutOfBoundsPolicy::Clamp);
}
break;
}
diff --git a/src/printsupport/platform/windows/qprintengine_win.cpp b/src/printsupport/platform/windows/qprintengine_win.cpp
index 516ed0fc94..fa8d03a615 100644
--- a/src/printsupport/platform/windows/qprintengine_win.cpp
+++ b/src/printsupport/platform/windows/qprintengine_win.cpp
@@ -259,7 +259,7 @@ void QWin32PrintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem
if (!fallBack) {
bool deleteFont = false;
- HFONT hfont = NULL;
+ HFONT hfont = nullptr;
if (ti.fontEngine->type() == QFontEngine::Win) {
hfont = static_cast<HFONT>(ti.fontEngine->handle());
}
@@ -433,7 +433,7 @@ void QWin32PrintEngine::updateClipPath(const QPainterPath &clipPath, Qt::ClipOpe
bool doclip = true;
if (op == Qt::NoClip) {
- SelectClipRgn(d->hdc, 0);
+ SelectClipRgn(d->hdc, nullptr);
doclip = false;
}
@@ -561,9 +561,9 @@ void QWin32PrintEngine::drawPixmap(const QRectF &targetRect,
QImage img(QSize(imgw, imgh), QImage::Format_RGB32);
+ img.setDevicePixelRatio(pixmap.devicePixelRatio());
img.fill(Qt::white);
QPainter painter(&img);
- img.setDevicePixelRatio(pixmap.devicePixelRatio());
painter.drawPixmap(0,0, pixmap, tileSize * x, tileSize * y, imgw, imgh);
QPixmap p = QPixmap::fromImage(img);
@@ -722,7 +722,7 @@ void QWin32PrintEnginePrivate::strokePath_dev(const QPainterPath &path, const QC
joinStyle = PS_JOIN_ROUND;
HPEN pen = ExtCreatePen(PS_GEOMETRIC | PS_SOLID | capStyle | joinStyle,
- (penWidth == 0) ? 1 : penWidth, &brush, 0, 0);
+ (penWidth == 0) ? 1 : penWidth, &brush, 0, nullptr);
HGDIOBJ old_pen = SelectObject(hdc, pen);
StrokePath(hdc);
@@ -842,7 +842,8 @@ void QWin32PrintEnginePrivate::initialize()
txop = QTransform::TxNone;
QString printerName = m_printDevice.id();
- bool ok = OpenPrinter((LPWSTR)printerName.utf16(), (LPHANDLE)&hPrinter, 0);
+ bool ok = OpenPrinter(reinterpret_cast<LPWSTR>(const_cast<ushort *>(printerName.utf16())),
+ reinterpret_cast<LPHANDLE>(&hPrinter), nullptr);
if (!ok) {
qErrnoWarning("QWin32PrintEngine::initialize: OpenPrinter failed");
return;
@@ -851,10 +852,10 @@ void QWin32PrintEnginePrivate::initialize()
// Fetch the PRINTER_INFO_2 with DEVMODE data containing the
// printer settings.
DWORD infoSize, numBytes;
- GetPrinter(hPrinter, 2, NULL, 0, &infoSize);
+ GetPrinter(hPrinter, 2, nullptr, 0, &infoSize);
hMem = GlobalAlloc(GHND, infoSize);
- pInfo = (PRINTER_INFO_2*) GlobalLock(hMem);
- ok = GetPrinter(hPrinter, 2, (LPBYTE)pInfo, infoSize, &numBytes);
+ pInfo = reinterpret_cast<PRINTER_INFO_2*>(GlobalLock(hMem));
+ ok = GetPrinter(hPrinter, 2, reinterpret_cast<LPBYTE>(pInfo), infoSize, &numBytes);
if (!ok) {
qErrnoWarning("QWin32PrintEngine::initialize: GetPrinter failed");
@@ -872,23 +873,26 @@ void QWin32PrintEnginePrivate::initialize()
// Attempt to get the DEVMODE a different way.
// Allocate the required buffer
- LONG result = DocumentProperties(NULL, hPrinter, (LPWSTR)printerName.utf16(),
- NULL, NULL, 0);
- devMode = (DEVMODE *) malloc(result);
+ auto *lpwPrinterName = reinterpret_cast<LPWSTR>(const_cast<ushort *>(printerName.utf16()));
+ LONG result = DocumentProperties(nullptr, hPrinter, lpwPrinterName,
+ nullptr, nullptr, 0);
+ devMode = reinterpret_cast<DEVMODE *>(malloc(result));
+ initializeDevMode(devMode);
ownsDevMode = true;
// Get the default DevMode
- result = DocumentProperties(NULL, hPrinter, (LPWSTR)printerName.utf16(),
- devMode, NULL, DM_OUT_BUFFER);
+ result = DocumentProperties(nullptr, hPrinter, lpwPrinterName,
+ devMode, nullptr, DM_OUT_BUFFER);
if (result != IDOK) {
qErrnoWarning("QWin32PrintEngine::initialize: Failed to obtain devMode");
free(devMode);
- devMode = NULL;
+ devMode = nullptr;
ownsDevMode = false;
}
}
- hdc = CreateDC(NULL, (LPCWSTR)printerName.utf16(), 0, devMode);
+ hdc = CreateDC(nullptr, reinterpret_cast<LPCWSTR>(printerName.utf16()),
+ nullptr, devMode);
if (!hdc) {
qErrnoWarning("QWin32PrintEngine::initialize: CreateDC failed");
@@ -913,15 +917,22 @@ void QWin32PrintEnginePrivate::initialize()
#endif // QT_DEBUG_DRAW || QT_DEBUG_METRICS
}
+void QWin32PrintEnginePrivate::initializeDevMode(DEVMODE *devMode)
+{
+ memset(devMode, 0, sizeof(DEVMODE));
+ devMode->dmSize = sizeof(DEVMODE);
+ devMode->dmSpecVersion = DM_SPECVERSION;
+}
+
void QWin32PrintEnginePrivate::initHDC()
{
Q_ASSERT(hdc);
- HDC display_dc = GetDC(0);
+ HDC display_dc = GetDC(nullptr);
dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
dpi_display = GetDeviceCaps(display_dc, LOGPIXELSY);
- ReleaseDC(0, display_dc);
+ ReleaseDC(nullptr, display_dc);
if (dpi_display == 0) {
qWarning("QWin32PrintEngine::metric: GetDeviceCaps() failed, "
"might be a driver problem");
@@ -964,11 +975,11 @@ void QWin32PrintEnginePrivate::release()
if (ownsDevMode)
free(devMode);
- hdc = 0;
- hPrinter = 0;
- pInfo = 0;
- hMem = 0;
- devMode = 0;
+ hdc = nullptr;
+ hPrinter = nullptr;
+ pInfo = nullptr;
+ hMem = nullptr;
+ devMode = nullptr;
ownsDevMode = false;
}
@@ -1052,6 +1063,7 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &
if (!d->devMode)
break;
d->devMode->dmCollate = value.toBool() ? DMCOLLATE_TRUE : DMCOLLATE_FALSE;
+ d->devMode->dmFields |= DM_COLLATE;
d->doReinit();
}
break;
@@ -1061,6 +1073,7 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &
if (!d->devMode)
break;
d->devMode->dmColor = (value.toInt() == QPrinter::Color) ? DMCOLOR_COLOR : DMCOLOR_MONOCHROME;
+ d->devMode->dmFields |= DM_COLOR;
d->doReinit();
}
break;
@@ -1086,15 +1099,19 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &
switch (mode) {
case QPrint::DuplexNone:
d->devMode->dmDuplex = DMDUP_SIMPLEX;
+ d->devMode->dmFields |= DM_DUPLEX;
break;
case QPrint::DuplexAuto:
d->devMode->dmDuplex = d->m_pageLayout.orientation() == QPageLayout::Landscape ? DMDUP_HORIZONTAL : DMDUP_VERTICAL;
+ d->devMode->dmFields |= DM_DUPLEX;
break;
case QPrint::DuplexLongSide:
d->devMode->dmDuplex = DMDUP_VERTICAL;
+ d->devMode->dmFields |= DM_DUPLEX;
break;
case QPrint::DuplexShortSide:
d->devMode->dmDuplex = DMDUP_HORIZONTAL;
+ d->devMode->dmFields |= DM_DUPLEX;
break;
default:
// Don't change
@@ -1122,6 +1139,7 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &
break;
d->num_copies = value.toInt();
d->devMode->dmCopies = d->num_copies;
+ d->devMode->dmFields |= DM_COPIES;
d->doReinit();
break;
@@ -1130,9 +1148,10 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &
break;
QPageLayout::Orientation orientation = QPageLayout::Orientation(value.toInt());
d->devMode->dmOrientation = orientation == QPageLayout::Landscape ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT;
+ d->devMode->dmFields |= DM_ORIENTATION;
d->m_pageLayout.setOrientation(orientation);
- d->updateMetrics();
d->doReinit();
+ d->updateMetrics();
#ifdef QT_DEBUG_METRICS
qDebug() << "QWin32PrintEngine::setProperty(PPK_Orientation," << orientation << ')';
d->debugMetrics();
@@ -1266,7 +1285,8 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &
Q_ASSERT(margins.size() == 4);
d->m_pageLayout.setUnits(QPageLayout::Point);
d->m_pageLayout.setMargins(QMarginsF(margins.at(0).toReal(), margins.at(1).toReal(),
- margins.at(2).toReal(), margins.at(3).toReal()));
+ margins.at(2).toReal(), margins.at(3).toReal()),
+ QPageLayout::OutOfBoundsPolicy::Clamp);
d->updateMetrics();
#ifdef QT_DEBUG_METRICS
qDebug() << "QWin32PrintEngine::setProperty(PPK_PageMargins," << margins << ')';
@@ -1294,7 +1314,7 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &
case PPK_QPageMargins: {
QPair<QMarginsF, QPageLayout::Unit> pair = value.value<QPair<QMarginsF, QPageLayout::Unit> >();
d->m_pageLayout.setUnits(pair.second);
- d->m_pageLayout.setMargins(pair.first);
+ d->m_pageLayout.setMargins(pair.first, QPageLayout::OutOfBoundsPolicy::Clamp);
d->updateMetrics();
#ifdef QT_DEBUG_METRICS
qDebug() << "QWin32PrintEngine::setProperty(PPK_QPageMargins," << pair.first << pair.second << ')';
@@ -1310,7 +1330,7 @@ void QWin32PrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &
setProperty(PPK_FullPage, pageLayout.mode() == QPageLayout::FullPageMode);
setProperty(PPK_Orientation, QVariant::fromValue(pageLayout.orientation()));
d->m_pageLayout.setUnits(pageLayout.units());
- d->m_pageLayout.setMargins(pageLayout.margins());
+ d->m_pageLayout.setMargins(pageLayout.margins(), QPageLayout::OutOfBoundsPolicy::Clamp);
d->updateMetrics();
#ifdef QT_DEBUG_METRICS
qDebug() << "QWin32PrintEngine::setProperty(PPK_QPageLayout," << pageLayout << ')';
@@ -1572,7 +1592,7 @@ void QWin32PrintEngine::setGlobalDevMode(HGLOBAL globalDevNames, HGLOBAL globalD
d->ownsDevMode = false;
}
d->devMode = dm;
- d->hdc = CreateDC(NULL, reinterpret_cast<const wchar_t *>(d->m_printDevice.id().utf16()), 0, dm);
+ d->hdc = CreateDC(nullptr, reinterpret_cast<LPCWSTR>(d->m_printDevice.id().utf16()), nullptr, dm);
d->num_copies = d->devMode->dmCopies;
d->updatePageLayout();
@@ -1688,7 +1708,8 @@ void QWin32PrintEnginePrivate::updateMetrics()
m_paintSizeMM = QSize(qRound(sizeMM.width()), qRound(sizeMM.height()));
// Calculate the origin using the physical device pixels, not our paint pixels
// Origin is defined as User Margins - Device Margins
- QMarginsF margins = m_pageLayout.margins(QPageLayout::Millimeter) / 25.4;
+ const bool isFullPage = (m_pageLayout.mode() == QPageLayout::FullPageMode);
+ const QMarginsF margins = isFullPage ? QMarginsF() : (m_pageLayout.margins(QPageLayout::Millimeter) / 25.4);
origin_x = qRound(pageScaleX * margins.left() * dpi_x) - GetDeviceCaps(hdc, PHYSICALOFFSETX);
origin_y = qRound(pageScaleY * margins.top() * dpi_y) - GetDeviceCaps(hdc, PHYSICALOFFSETY);
}
@@ -1715,7 +1736,7 @@ static void draw_text_item_win(const QPointF &pos, const QTextItemInt &ti, HDC h
const bool has_kerning = ti.f && ti.f->kerning();
- HFONT hfont = 0;
+ HFONT hfont = nullptr;
bool deleteFont = false;
if (ti.fontEngine->type() == QFontEngine::Win) {
diff --git a/src/printsupport/platform/windows/qprintengine_win_p.h b/src/printsupport/platform/windows/qprintengine_win_p.h
index 54e3cf2814..995c31ff1e 100644
--- a/src/printsupport/platform/windows/qprintengine_win_p.h
+++ b/src/printsupport/platform/windows/qprintengine_win_p.h
@@ -83,25 +83,9 @@ class QWin32PrintEnginePrivate : public QAlphaPaintEnginePrivate
Q_DECLARE_PUBLIC(QWin32PrintEngine)
public:
QWin32PrintEnginePrivate() :
- hPrinter(0),
- globalDevMode(0),
- devMode(0),
- pInfo(0),
- hMem(0),
- hdc(0),
- ownsDevMode(false),
- mode(QPrinter::ScreenResolution),
- state(QPrinter::Idle),
- resolution(0),
- m_pageLayout(QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0, 0, 0, 0))),
- stretch_x(1), stretch_y(1), origin_x(0), origin_y(0),
- dpi_x(96), dpi_y(96), dpi_display(96),
- num_copies(1),
- printToFile(false),
- reinit(false),
+ printToFile(false), reinit(false),
complex_xform(false), has_pen(false), has_brush(false), has_custom_paper_size(false),
- embed_fonts(true),
- txop(0 /* QTransform::TxNone */)
+ embed_fonts(true)
{
}
@@ -127,6 +111,8 @@ public:
is handled in the next begin or newpage. */
void doReinit();
+ static void initializeDevMode(DEVMODE *);
+
bool resetDC();
void strokePath(const QPainterPath &path, const QColor &color);
@@ -142,19 +128,19 @@ public:
void debugMetrics() const;
// Windows GDI printer references.
- HANDLE hPrinter;
+ HANDLE hPrinter = nullptr;
- HGLOBAL globalDevMode;
- DEVMODE *devMode;
- PRINTER_INFO_2 *pInfo;
- HGLOBAL hMem;
+ HGLOBAL globalDevMode = nullptr;
+ DEVMODE *devMode = nullptr;
+ PRINTER_INFO_2 *pInfo = nullptr;
+ HGLOBAL hMem = nullptr;
- HDC hdc;
+ HDC hdc = nullptr;
// True if devMode was allocated separately from pInfo.
- bool ownsDevMode;
+ bool ownsDevMode = false;
- QPrinter::PrinterMode mode;
+ QPrinter::PrinterMode mode = QPrinter::ScreenResolution;
// Print Device
QPrintDevice m_printDevice;
@@ -164,26 +150,26 @@ public:
QString m_creator;
QString fileName;
- QPrinter::PrinterState state;
- int resolution;
+ QPrinter::PrinterState state = QPrinter::Idle;
+ int resolution = 0;
// Page Layout
- QPageLayout m_pageLayout;
-
+ QPageLayout m_pageLayout{QPageSize(QPageSize::A4),
+ QPageLayout::Portrait, QMarginsF{0, 0, 0, 0}};
// Page metrics cache
QRect m_paintRectPixels;
QSize m_paintSizeMM;
// Windows painting
- qreal stretch_x;
- qreal stretch_y;
- int origin_x;
- int origin_y;
+ qreal stretch_x = 1;
+ qreal stretch_y = 1;
+ int origin_x = 0;
+ int origin_y = 0;
- int dpi_x;
- int dpi_y;
- int dpi_display;
- int num_copies;
+ int dpi_x = 96;
+ int dpi_y = 96;
+ int dpi_display = 96;
+ int num_copies = 1;
uint printToFile : 1;
uint reinit : 1;
@@ -194,7 +180,7 @@ public:
uint has_custom_paper_size : 1;
uint embed_fonts : 1;
- uint txop;
+ uint txop = 0; // QTransform::TxNone
QColor brush_color;
QPen pen;
diff --git a/src/printsupport/platform/windows/qwindowsprintdevice.cpp b/src/printsupport/platform/windows/qwindowsprintdevice.cpp
index 65784e62ca..9445871ed7 100644
--- a/src/printsupport/platform/windows/qwindowsprintdevice.cpp
+++ b/src/printsupport/platform/windows/qwindowsprintdevice.cpp
@@ -328,7 +328,7 @@ void QWindowsPrintDevice::loadInputSlots() const
QPrint::InputSlot QWindowsPrintDevice::defaultInputSlot() const
{
- QPrint::InputSlot inputSlot = QPlatformPrintDevice::defaultInputSlot();;
+ QPrint::InputSlot inputSlot = QPlatformPrintDevice::defaultInputSlot();
if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) {
// Get the default input slot
diff --git a/src/printsupport/widgets/qprintpreviewwidget.cpp b/src/printsupport/widgets/qprintpreviewwidget.cpp
index 1b75e526d1..637eb42505 100644
--- a/src/printsupport/widgets/qprintpreviewwidget.cpp
+++ b/src/printsupport/widgets/qprintpreviewwidget.cpp
@@ -25,7 +25,6 @@ public:
qreal border = qMax(paperSize.height(), paperSize.width()) / 25;
brect = QRectF(QPointF(-border, -border),
QSizeF(paperSize)+QSizeF(2*border, 2*border));
- setCacheMode(DeviceCoordinateCache);
}
QRectF boundingRect() const override
@@ -362,6 +361,9 @@ void QPrintPreviewWidgetPrivate::generatePreview()
//### emit paintRequested() until the user changes some parameter
Q_Q(QPrintPreviewWidget);
+ // Avoid previewing a preview
+ if (printer->d_func()->previewMode())
+ return;
printer->d_func()->setPreviewMode(true);
emit q->paintRequested(printer);
printer->d_func()->setPreviewMode(false);
diff --git a/src/sql/CMakeLists.txt b/src/sql/CMakeLists.txt
index e69df530a9..0a51f62c4b 100644
--- a/src/sql/CMakeLists.txt
+++ b/src/sql/CMakeLists.txt
@@ -23,8 +23,10 @@ qt_internal_add_module(Sql
kernel/qtsqlglobal.h kernel/qtsqlglobal_p.h
DEFINES
QT_NO_CAST_FROM_ASCII
+ QT_NO_CONTEXTLESS_CONNECT
QT_NO_FOREACH
QT_NO_USING_NAMESPACE
+ QT_USE_NODISCARD_FILE_OPEN
LIBRARIES
Qt::CorePrivate
PUBLIC_LIBRARIES
@@ -38,9 +40,6 @@ qt_internal_add_module(Sql
GENERATE_CPP_EXPORTS
)
-set_source_files_properties(compat/removed_api.cpp # NO_PCH_SOURCES
- PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
-
## Scopes:
#####################################################################
diff --git a/src/sql/compat/removed_api.cpp b/src/sql/compat/removed_api.cpp
index ff223b9967..9da60eceda 100644
--- a/src/sql/compat/removed_api.cpp
+++ b/src/sql/compat/removed_api.cpp
@@ -9,10 +9,6 @@ QT_USE_NAMESPACE
#if QT_SQL_REMOVED_SINCE(6, 4)
-// #include <qotherheader.h>
-// // implement removed functions from qotherheader.h
-// order sections alphabetically to reduce chances of merge conflicts
-
#endif // QT_SQL_REMOVED_SINCE(6, 4)
#if QT_SQL_REMOVED_SINCE(6, 5)
@@ -36,8 +32,21 @@ void QSqlTableModel::setQuery(const QSqlQuery &query)
#endif // QT_CONFIG(sqlmodel)
+#endif // QT_SQL_REMOVED_SINCE(6, 5)
+
+#if QT_SQL_REMOVED_SINCE(6, 6)
+
+#include "qsqlresult.h"
+#include <QtSql/private/qsqlresult_p.h>
+
// #include <qotherheader.h>
// // implement removed functions from qotherheader.h
// order sections alphabetically to reduce chances of merge conflicts
-#endif // QT_SQL_REMOVED_SINCE(6, 5)
+QList<QVariant> &QSqlResult::boundValues() const
+{
+ Q_D(const QSqlResult);
+ return const_cast<QSqlResultPrivate *>(d)->values;
+}
+
+#endif // QT_SQL_REMOVED_SINCE(6, 6)
diff --git a/src/sql/doc/qtsql.qdocconf b/src/sql/doc/qtsql.qdocconf
index 877411d326..9f6e1a31e0 100644
--- a/src/sql/doc/qtsql.qdocconf
+++ b/src/sql/doc/qtsql.qdocconf
@@ -40,5 +40,10 @@ imagedirs += images \
navigation.landingpage = "Qt SQL"
navigation.cppclassespage = "Qt SQL C++ Classes"
-# Fail the documentation build if there are more warnings than the limit
+# Highlighted examples in Data Processing & IO category
+manifestmeta.highlighted.names = \
+ "QtSql/Master Detail Example" \
+ "QtSql/SQL Browser"
+
+# Enforce zero documentation warnings
warninglimit = 0
diff --git a/src/sql/doc/snippets/CMakeLists.txt b/src/sql/doc/snippets/CMakeLists.txt
index 780ee9261d..a5c34d5688 100644
--- a/src/sql/doc/snippets/CMakeLists.txt
+++ b/src/sql/doc/snippets/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#! [cmake_use]
find_package(Qt6 REQUIRED COMPONENTS Sql)
diff --git a/src/sql/doc/snippets/code/CMakeLists.txt b/src/sql/doc/snippets/code/CMakeLists.txt
index 54ced0e56d..b6899137fe 100644
--- a/src/sql/doc/snippets/code/CMakeLists.txt
+++ b/src/sql/doc/snippets/code/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
add_library(code_snippets OBJECT
doc_src_sql-driver.cpp
diff --git a/src/sql/doc/snippets/code/doc_src_sql-driver.cpp b/src/sql/doc/snippets/code/doc_src_sql-driver.cpp
index 92c1281aa9..efcb45c98e 100644
--- a/src/sql/doc/snippets/code/doc_src_sql-driver.cpp
+++ b/src/sql/doc/snippets/code/doc_src_sql-driver.cpp
@@ -47,10 +47,8 @@ if (q.next())
//! [26]
qDebug( \
-//! [31]
"QSqlDatabase: QMYSQL driver not loaded \
QSqlDatabase: available drivers: QMYSQL" \
-//! [31]
);
/* Commented because the following line is not compilable
diff --git a/src/sql/doc/snippets/code/doc_src_sql-driver.qdoc b/src/sql/doc/snippets/code/doc_src_sql-driver.qdoc
index 9c329aa2a4..896839a1d9 100644
--- a/src/sql/doc/snippets/code/doc_src_sql-driver.qdoc
+++ b/src/sql/doc/snippets/code/doc_src_sql-driver.qdoc
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
//! [0]
[...]
diff --git a/src/sql/doc/snippets/sqldatabase/CMakeLists.txt b/src/sql/doc/snippets/sqldatabase/CMakeLists.txt
index 2028cdac1d..5179c694d0 100644
--- a/src/sql/doc/snippets/sqldatabase/CMakeLists.txt
+++ b/src/sql/doc/snippets/sqldatabase/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
add_library(sqldatabase_snippets OBJECT
sqldatabase.cpp
diff --git a/src/sql/doc/snippets/sqldatabase/sqldatabase_snippet.cpp b/src/sql/doc/snippets/sqldatabase/sqldatabase_snippet.cpp
index e81436a247..48382bfee9 100644
--- a/src/sql/doc/snippets/sqldatabase/sqldatabase_snippet.cpp
+++ b/src/sql/doc/snippets/sqldatabase/sqldatabase_snippet.cpp
@@ -17,17 +17,13 @@
//! [20]
}
-//! [21]
QSqlQueryModel model;
model.setQuery("SELECT name, salary FROM employee");
int salary = model.record(4).value("salary").toInt();
-//! [21]
Q_UNUSED(salary);
{
-//! [22]
int salary = model.data(model.index(4, 1)).toInt();
-//! [22]
Q_UNUSED(salary);
}
@@ -47,7 +43,6 @@ public:
int m_specialColumnNo;
};
-//! [23]
QVariant MyModel::data(const QModelIndex &item, int role) const
{
if (item.column() == m_specialColumnNo) {
@@ -55,7 +50,6 @@ QVariant MyModel::data(const QModelIndex &item, int role) const
}
return QSqlQueryModel::data(item, role);
}
-//! [23]
void QSqlTableModel_snippets()
{
@@ -72,258 +66,8 @@ void QSqlTableModel_snippets()
view->hideColumn(0); // don't show the ID
view->show();
//! [24]
-
- {
-//! [25]
- QSqlTableModel model;
- model.setTable("employee");
- model.select();
- int salary = model.record(4).value("salary").toInt();
-//! [25]
- }
-}
-
-void sql_intro_snippets()
-{
- {
-//! [26]
- QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
- db.setHostName("bigblue");
- db.setDatabaseName("flightdb");
- db.setUserName("acarlson");
- db.setPassword("1uTbSbAs");
- bool ok = db.open();
-//! [26]
- Q_UNUSED(ok);
- }
-
- {
-//! [27]
- QSqlDatabase firstDB = QSqlDatabase::addDatabase("QMYSQL", "first");
- QSqlDatabase secondDB = QSqlDatabase::addDatabase("QMYSQL", "second");
-//! [27]
- }
-
- {
-//! [28]
- QSqlDatabase defaultDB = QSqlDatabase::database();
-//! [28] //! [29]
- QSqlDatabase firstDB = QSqlDatabase::database("first");
-//! [29] //! [30]
- QSqlDatabase secondDB = QSqlDatabase::database("second");
-//! [30]
- }
-
- {
- // SELECT1
-//! [31]
- QSqlQuery query;
- query.exec("SELECT name, salary FROM employee WHERE salary > 50000");
-//! [31]
-
-//! [32]
- while (query.next()) {
- QString name = query.value(0).toString();
- int salary = query.value(1).toInt();
- qDebug() << name << salary;
- }
-//! [32]
- }
-
- {
- // FEATURE
-//! [33]
- QSqlQuery query;
- int numRows;
- query.exec("SELECT name, salary FROM employee WHERE salary > 50000");
-
- QSqlDatabase defaultDB = QSqlDatabase::database();
- if (defaultDB.driver()->hasFeature(QSqlDriver::QuerySize)) {
- numRows = query.size();
- } else {
- // this can be very slow
- query.last();
- numRows = query.at() + 1;
- }
-//! [33]
- }
-
- {
- // INSERT1
-//! [34]
- QSqlQuery query;
- query.exec("INSERT INTO employee (id, name, salary) "
- "VALUES (1001, 'Thad Beaumont', 65000)");
-//! [34]
- }
-
- {
- // NAMED BINDING
-//! [35]
- QSqlQuery query;
- query.prepare("INSERT INTO employee (id, name, salary) "
- "VALUES (:id, :name, :salary)");
- query.bindValue(":id", 1001);
- query.bindValue(":name", "Thad Beaumont");
- query.bindValue(":salary", 65000);
- query.exec();
-//! [35]
- }
-
- {
- // POSITIONAL BINDING
-//! [36]
- QSqlQuery query;
- query.prepare("INSERT INTO employee (id, name, salary) "
- "VALUES (?, ?, ?)");
- query.addBindValue(1001);
- query.addBindValue("Thad Beaumont");
- query.addBindValue(65000);
- query.exec();
-//! [36]
- }
-
- {
- // UPDATE1
-//! [37]
- QSqlQuery query;
- query.exec("UPDATE employee SET salary = 70000 WHERE id = 1003");
-//! [37]
- }
-
- {
- // DELETE1
-//! [38]
- QSqlQuery query;
- query.exec("DELETE FROM employee WHERE id = 1007");
-//! [38]
- }
-
- {
- // TRANSACTION
-//! [39]
- QSqlDatabase::database().transaction();
- QSqlQuery query;
- query.exec("SELECT id FROM employee WHERE name = 'Torild Halvorsen'");
- if (query.next()) {
- int employeeId = query.value(0).toInt();
- query.exec("INSERT INTO project (id, name, ownerid) "
- "VALUES (201, 'Manhattan Project', "
- + QString::number(employeeId) + ')');
- }
- QSqlDatabase::database().commit();
-//! [39]
- }
-
- {
- // SQLQUERYMODEL1
-//! [40]
- QSqlQueryModel model;
- model.setQuery("SELECT * FROM employee");
-
- for (int i = 0; i < model.rowCount(); ++i) {
- int id = model.record(i).value("id").toInt();
- QString name = model.record(i).value("name").toString();
- qDebug() << id << name;
- }
-//! [40]
- }
-
- {
- // SQLTABLEMODEL1
-//! [41]
- QSqlTableModel model;
- model.setTable("employee");
- model.setFilter("salary > 50000");
- model.setSort(2, Qt::DescendingOrder);
- model.select();
-
- for (int i = 0; i < model.rowCount(); ++i) {
- QString name = model.record(i).value("name").toString();
- int salary = model.record(i).value("salary").toInt();
- qDebug() << name << salary;
- }
-//! [41]
- }
-
- {
- // SQLTABLEMODEL2
- QSqlTableModel model;
- model.setTable("employee");
-
-//! [42]
- for (int i = 0; i < model.rowCount(); ++i) {
- QSqlRecord record = model.record(i);
- double salary = record.value("salary").toInt();
- salary *= 1.1;
- record.setValue("salary", salary);
- model.setRecord(i, record);
- }
- model.submitAll();
-//! [42]
-
- // SQLTABLEMODEL3
- int row = 1;
- int column = 2;
-//! [43]
- model.setData(model.index(row, column), 75000);
- model.submitAll();
-//! [43]
-
- // SQLTABLEMODEL4
-//! [44]
- model.insertRows(row, 1);
- model.setData(model.index(row, 0), 1013);
- model.setData(model.index(row, 1), "Peter Gordon");
- model.setData(model.index(row, 2), 68500);
- model.submitAll();
-//! [44]
-
-//! [45]
- model.removeRows(row, 5);
-//! [45] //! [46]
- model.submitAll();
-//! [46]
- }
}
-//! [47]
-class XyzResult : public QSqlResult
-{
-public:
- XyzResult(const QSqlDriver *driver)
- : QSqlResult(driver) {}
- ~XyzResult() {}
-
-protected:
- QVariant data(int /* index */) override { return QVariant(); }
- bool isNull(int /* index */) override { return false; }
- bool reset(const QString & /* query */) override { return false; }
- bool fetch(int /* index */) override { return false; }
- bool fetchFirst() override { return false; }
- bool fetchLast() override { return false; }
- int size() override { return 0; }
- int numRowsAffected() override { return 0; }
- QSqlRecord record() const override { return QSqlRecord(); }
-};
-//! [47]
-
-//! [48]
-class XyzDriver : public QSqlDriver
-{
-public:
- XyzDriver() {}
- ~XyzDriver() {}
-
- bool hasFeature(DriverFeature /* feature */) const override { return false; }
- bool open(const QString & /* db */, const QString & /* user */,
- const QString & /* password */, const QString & /* host */,
- int /* port */, const QString & /* options */) override
- { return false; }
- void close() {}
- QSqlResult *createResult() const override { return new XyzResult(this); }
-};
-//! [48]
int main(int argc, char **argv)
{
diff --git a/src/sql/doc/src/qsqldatatype-table.qdoc b/src/sql/doc/src/qsqldatatype-table.qdoc
index 6eabf269c8..77aa56d21a 100644
--- a/src/sql/doc/src/qsqldatatype-table.qdoc
+++ b/src/sql/doc/src/qsqldatatype-table.qdoc
@@ -495,62 +495,80 @@
\li 32-bit signed integer
\li typedef qint32
\row
+ \li INTEGER(n)
+ \li Integer with up to 45 digits precision
+ \li Mapped to QString
+ \row
\li BIGINT
\li 64-bit signed integer
\li typedef qint64
\row
\li REAL
- \li 32-bit Single-precision floating point
- \li typedef qreal
+ \li 32-bit Single-precision IEEE floating point
+ \li typedef float
\row
\li DOUBLE PRECISION
- \li 64-bit Double-precision floating point
+ \li 64-bit Double-precision IEEE floating point
\li Mapped to QString for high precision doubles, otherwise qreal
\row
\li FLOAT
- \li 64-bit Double-precision floating point
- \li typedef qreal
+ \li 64-bit Double-precision IEEE floating point
+ \li Mapped to QString for high precision doubles, otherwise qreal
+ \row
+ \li FLOAT(n)
+ \li Floating point with up to 45 digits precision
+ \li Mapped to QString
+ \row
+ \li DECIMAL(p,s)
+ \li Decimal with up to 45 digits precision and scale
+ \li Mapped to QString
\row
\li CHAR
- \li Fixed-length, null-terminated character string
+ \li Fixed-length character Latin-1 string (CHAR or character)
\li Mapped to QString
\row
\li VARCHAR
- \li Null-terminated varying length string
+ \li Variable length Latin-1 string (VARCHAR or CHARACTER VARYING)
\li Mapped to QString
\row
\li NCHAR
- \li Fixed-length, null-terminated Unicode character string
+ \li Fixed-length Unicode string (NCHAR or NATIONAL CHARACTER)
\li Mapped to QString
\row
\li NVARCHAR
- \li Null-terminated varying length Unicode string
+ \li Variable length Unicode string (NVARCHAR or NATIONAL CHARACTER VARYING)
\li Mapped to QString
\row
+ \li BINARY
+ \li Fixed length binary data
+ \li Mapped to QByteArray
+ \row
+ \li VARBINARY
+ \li Variable length binary data (VARBINARY or BINARY VARYING)
+ \li Mapped to QByteArray
+ \row
\li BLOB
- \li Not null-terminated varying binary string with 4-byte string
- length indicator
+ \li Binary large object (BLOB or BINARY LARGE OBJECT)
\li Mapped to QByteArray
\row
\li CLOB
- \li Character large string object
+ \li Latin-1 character large object (CLOB or CHARACTER LARGE OBJECT)
\li Mapped to QString
\row
\li NCLOB
- \li National Character large string object
+ \li Unicode character large object (NCLOB or NATIONAL CHARACTER LARGE OBJECT)
\li Mapped to QString
\row
\li DATE
- \li Null-terminated character string of the following format:
- yyyy-mm-dd
+ \li Date consisting of year, month, and day
\li Mapped to QDate
\row
\li TIME
- \li Null-terminated character string of the following format: hh.mm.ss
+ \li Time consisting of hours, minute, seconds with optional fractional seconds
\li Mapped to QTime
\row
\li TIMESTAMP
- \li Null-terminated character string of the following format: yyyy-mm-dd-hh.mm.ss.nnnnnn
+ \li Date and time with optional fractional seconds
\li Mapped to QDateTime
\row
\li BUILTIN.UUID
@@ -561,7 +579,56 @@
\li Boolean
\li bool
\row
- \li DECIMAL(p,s)
- \li By default mapping to QString
+ \li INTERVAL YEAR(7)
+ \li Year, format '±yyyyyyy' (max precision)
+ \li Mapped to QString
+ \row
+ \li INTERVAL YEAR(7) TO MONTH
+ \li Year to month, format '±yyyyyyy-mm' (max precision)
+ \li Mapped to QString
+ \row
+ \li INTERVAL MONTH(7)
+ \li Month, format '±mmmmmmm' (max precision)
+ \li Mapped to QString
+ \row
+ \li INTERVAL DAY(7)
+ \li Day, format '±ddddddd' (max precision)
+ \li Mapped to QString
+ \row
+ \li INTERVAL DAY(7) TO HOUR
+ \li Day to hour, format '±ddddddd hh' (max precision)
+ \li Mapped to QString
+ \row
+ \li INTERVAL DAY(7) TO MINUTE
+ \li Day to minute, format '±ddddddd hh:mm' (max precision)
+ \li Mapped to QString
+ \row
+ \li INTERVAL DAY(7) TO SECOND(9)
+ \li Day to second, format '±ddddddd hh:mm:ss[.fffffffff]' (max precision)
+ \li Mapped to QString
+ \row
+ \li INTERVAL HOUR(8)
+ \li Hour, format '±hhhhhhhh' (max precision)
+ \li Mapped to QString
+ \row
+ \li INTERVAL HOUR(8) TO MINUTE
+ \li Hour to minute, format '±hhhhhhhh:mm' (max precision)
+ \li Mapped to QString
+ \row
+ \li INTERVAL HOUR(8) TO SECOND(9)
+ \li Hour to second, format '±hhhhhhhh:mm:ss[.fffffffff]' (max precision)
+ \li Mapped to QString
+ \row
+ \li INTERVAL MINUTE(10)
+ \li Minute, format '±mmmmmmmmmm' (max precision)
+ \li Mapped to QString
+ \row
+ \li INTERVAL MINUTE(10) TO SECOND(9)
+ \li Minute to second, format '±mmmmmmmmmm:ss[.fffffffff]' (max precision)
+ \li Mapped to QString
+ \row
+ \li INTERVAL SECOND(12,9)
+ \li Second, format '±ssssssssssss[.fffffffff]' (max precision)
+ \li Mapped to QString
\endtable
*/
diff --git a/src/sql/doc/src/qt6-changes.qdoc b/src/sql/doc/src/qt6-changes.qdoc
index a0ba654a38..28c4664fdd 100644
--- a/src/sql/doc/src/qt6-changes.qdoc
+++ b/src/sql/doc/src/qt6-changes.qdoc
@@ -5,7 +5,7 @@
\page qtsql-changes-qt6.html
\title Changes to Qt SQL
\ingroup changes-qt-5-to-6
- \brief Migrate Qt SQL to Qt 6.
+ \brief The return type for boundValues() has been changed in QSqlQuery class.
Qt 6 is a result of the conscious effort to make the framework more
efficient and easy to use.
diff --git a/src/sql/doc/src/sql-driver.qdoc b/src/sql/doc/src/sql-driver.qdoc
index 47880fa2ec..4cc5b0d050 100644
--- a/src/sql/doc/src/sql-driver.qdoc
+++ b/src/sql/doc/src/sql-driver.qdoc
@@ -23,7 +23,7 @@
\table
\header \li Driver name \li DBMS
\row \li \l{#QDB2}{QDB2} \li IBM DB2 (version 7.1 and above)
- \row \li \l{#QIBASE} \li Borland InterBase / Firebird
+ \row \li \l{#QIBASE}{QIBASE} \li Borland InterBase / Firebird
\row \li \l{#QMYSQL}{QMYSQL / MARIADB} \li MySQL or MariaDB (version 5.6 and above)
\row \li \l{#QOCI}{QOCI} \li Oracle Call Interface Driver (version 12.1 and above)
\row \li \l{#QODBC}{QODBC}
@@ -210,6 +210,16 @@
\l {https://dev.mysql.com/doc/refman/8.0/en/load-data.html} {LOAD_DATA},
disabled if not set or 0
\row
+ \li MYSQL_OPT_SSL_MODE
+ \li The security state to use for the connection to the server: SSL_MODE_DISABLED,
+ SSL_MODE_PREFERRED, SSL_MODE_REQUIRED, SSL_MODE_VERIFY_CA, SSL_MODE_VERIFY_IDENTITY.
+ \row
+ \li MYSQL_OPT_TLS_VERSION
+ \li A list of protocols the client permits for encrypted connections. The value can be
+ a combination of 'TLSv1' ,' TLSv1.1', 'TLSv1.2' or 'TLSv1.3' depending on the used \l
+ {https://dev.mysql.com/doc/refman/8.0/en/encrypted-connection-protocols-ciphers.html#encrypted-connection-protocol-configuration}
+ {MySQL server} version.
+ \row
\li MYSQL_OPT_SSL_KEY / SSL_KEY (deprecated)
\li The path name of the client private key file
\row
@@ -394,15 +404,20 @@
of the ODBC driver. ODBC support can be used as a fallback for compliant
databases if no native driver is available.
- On Windows, an ODBC driver manager should be installed by default.
+ On Windows, an ODBC driver manager is installed by default.
For Unix systems, there are some implementations which must be
installed first. Note that every end user of your application is
required to have an ODBC driver manager installed, otherwise the
QODBC plugin will not work.
When connecting to an ODBC datasource, you should pass the name
- of the ODBC datasource to the QSqlDatabase::setDatabaseName()
+ of the ODBC datasource (DSN) to the QSqlDatabase::setDatabaseName()
function, rather than the actual database name.
+ It's also possible to pass a FILEDSN (*.dsn) filename or a complete
+ ODBC driver string. When passing a driver string you must make sure,
+ that all parameters (username, password, ...) are properly escaped.
+ Passing the username or password through the QSqlDatabase functions,
+ the escaping is done by the QODBC plugin.
The QODBC Plugin needs an ODBC compliant driver manager version 2.0 or
later. Some ODBC drivers claim to be version-2.0-compliant,
@@ -713,6 +728,17 @@
\li Busy handler timeout in milliseconds (val <= 0: disabled),
see \l {https://www.sqlite.org/c3ref/busy_timeout.html}
{SQLite documentation} for more information
+
+ \row
+ \li QSQLITE_USE_QT_VFS
+ \li If set, the database is opened using Qt's VFS which allows to
+ open databases using QFile. This way it can open databases from
+ any read-write locations (e.g.android shared storage) but also
+ from read-only resources (e.g. qrc or android assets). Be aware
+ that when opening databases from read-only resources make sure
+ you add QSQLITE_OPEN_READONLY attribute as well.
+ Otherwise it will fail to open it.
+
\row
\li QSQLITE_OPEN_READONLY
\li If set, the database is open in read-only mode which will fail
@@ -735,7 +761,14 @@
\row
\li QSQLITE_NO_USE_EXTENDED_RESULT_CODES
\li Disables the usage of the \l {https://www.sqlite.org/c3ref/extended_result_codes.html}
- {extended result code} feature in SQLite (for backwards compatibility)
+ {extended result code} feature in SQLite
+ \row
+ \li QSQLITE_ENABLE_NON_ASCII_CASE_FOLDING
+ \li If set, the plugin replaces the functions 'lower' and 'upper' with
+ QString functions for correct case folding of non-ascii characters
+ \row
+ \li QSQLITE_OPEN_NOFOLLOW
+ \li If set, the database filename is not allowed to contain a symbolic link
\endtable
\section3 How to Build the QSQLITE Plugin
diff --git a/src/sql/doc/src/sql-programming.qdoc b/src/sql/doc/src/sql-programming.qdoc
index 3dfd005516..a7f87fe73f 100644
--- a/src/sql/doc/src/sql-programming.qdoc
+++ b/src/sql/doc/src/sql-programming.qdoc
@@ -496,11 +496,11 @@
submitted.
The items in the view are rendered using a delegate. The default
- delegate, QItemDelegate, handles the most common data types (\c
+ delegate, QStyledItemDelegate, handles the most common data types (\c
int, QString, QImage, etc.). The delegate is also responsible for
providing editor widgets (e.g., a combobox) when the user starts
editing an item in the view. You can create your own delegates by
- subclassing QAbstractItemDelegate or QItemDelegate. See
+ subclassing QAbstractItemDelegate or QStyledItemDelegate. See
\l{Model/View Programming} for more information.
QSqlTableModel is optimized to operate on a single table at a
diff --git a/src/sql/kernel/qsqldatabase.cpp b/src/sql/kernel/qsqldatabase.cpp
index 5a8d27a5d0..fdbb16a589 100644
--- a/src/sql/kernel/qsqldatabase.cpp
+++ b/src/sql/kernel/qsqldatabase.cpp
@@ -3,12 +3,14 @@
#include "qsqldatabase.h"
#include "qsqlquery.h"
-#include "qdebug.h"
+#include "qloggingcategory.h"
#include "qcoreapplication.h"
#include "qreadwritelock.h"
#include "qsqldriver.h"
+#include "qsqldriver_p.h"
#include "qsqldriverplugin.h"
#include "qsqlindex.h"
+#include "QtCore/qapplicationstatic.h"
#include "private/qfactoryloader_p.h"
#include "private/qsqlnulldriver_p.h"
#include "qhash.h"
@@ -16,32 +18,51 @@
QT_BEGIN_NAMESPACE
+static Q_LOGGING_CATEGORY(lcSqlDb, "qt.sql.qsqldatabase")
+
using namespace Qt::StringLiterals;
+#define CHECK_QCOREAPPLICATION \
+ if (Q_UNLIKELY(!QCoreApplication::instance())) { \
+ qCWarning(lcSqlDb, "QSqlDatabase requires a QCoreApplication"); \
+ return; \
+ }
+#define CHECK_QCOREAPPLICATION_RETVAL \
+ if (Q_UNLIKELY(!QCoreApplication::instance())) { \
+ qCWarning(lcSqlDb, "QSqlDatabase requires a QCoreApplication"); \
+ return {}; \
+ }
+
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
(QSqlDriverFactoryInterface_iid, "/sqldrivers"_L1))
const char *QSqlDatabase::defaultConnection = "qt_sql_default_connection";
-typedef QHash<QString, QSqlDriverCreatorBase*> DriverDict;
-
-class QConnectionDict: public QHash<QString, QSqlDatabase>
-{
-public:
- inline bool contains_ts(const QString &key)
+namespace {
+ struct QtSqlGlobals
{
- QReadLocker locker(&lock);
- return contains(key);
- }
- inline QStringList keys_ts() const
- {
- QReadLocker locker(&lock);
- return keys();
- }
-
- mutable QReadWriteLock lock;
-};
-Q_GLOBAL_STATIC(QConnectionDict, dbDict)
+ ~QtSqlGlobals();
+ QSqlDatabase connection(const QString &key) const
+ {
+ QReadLocker locker(&lock);
+ return connections.value(key);
+ }
+ bool connectionExists(const QString &key) const
+ {
+ QReadLocker locker(&lock);
+ return connections.contains(key);
+ }
+ QStringList connectionNames() const
+ {
+ QReadLocker locker(&lock);
+ return connections.keys();
+ }
+ mutable QReadWriteLock lock;
+ QHash<QString, QSqlDriverCreatorBase*> registeredDrivers;
+ QHash<QString, QSqlDatabase> connections;
+ };
+}
+Q_APPLICATION_STATIC(QtSqlGlobals, s_sqlGlobals)
class QSqlDatabasePrivate
{
@@ -76,8 +97,6 @@ public:
static void addDatabase(const QSqlDatabase &db, const QString & name);
static void removeDatabase(const QString& name);
static void invalidateDb(const QSqlDatabase &db, const QString &name, bool doWarn = true);
- static DriverDict &driverDict();
- static void cleanConnections();
};
QSqlDatabasePrivate::QSqlDatabasePrivate(const QSqlDatabasePrivate &other) : ref(1)
@@ -101,37 +120,11 @@ QSqlDatabasePrivate::~QSqlDatabasePrivate()
delete driver;
}
-void QSqlDatabasePrivate::cleanConnections()
-{
- QConnectionDict *dict = dbDict();
- Q_ASSERT(dict);
- QWriteLocker locker(&dict->lock);
-
- QConnectionDict::iterator it = dict->begin();
- while (it != dict->end()) {
- invalidateDb(it.value(), it.key(), false);
- ++it;
- }
- dict->clear();
-}
-
-static bool qDriverDictInit = false;
-static void cleanDriverDict()
-{
- qDeleteAll(QSqlDatabasePrivate::driverDict());
- QSqlDatabasePrivate::driverDict().clear();
- QSqlDatabasePrivate::cleanConnections();
- qDriverDictInit = false;
-}
-
-DriverDict &QSqlDatabasePrivate::driverDict()
+QtSqlGlobals::~QtSqlGlobals()
{
- static DriverDict dict;
- if (!qDriverDictInit) {
- qDriverDictInit = true;
- qAddPostRoutine(cleanDriverDict);
- }
- return dict;
+ qDeleteAll(registeredDrivers);
+ for (const auto &[k, v] : std::as_const(connections).asKeyValueRange())
+ QSqlDatabasePrivate::invalidateDb(v, k, false);
}
QSqlDatabasePrivate *QSqlDatabasePrivate::shared_null()
@@ -144,8 +137,8 @@ QSqlDatabasePrivate *QSqlDatabasePrivate::shared_null()
void QSqlDatabasePrivate::invalidateDb(const QSqlDatabase &db, const QString &name, bool doWarn)
{
if (db.d->ref.loadRelaxed() != 1 && doWarn) {
- qWarning("QSqlDatabasePrivate::removeDatabase: connection '%s' is still in use, "
- "all queries will cease to work.", name.toLocal8Bit().constData());
+ qCWarning(lcSqlDb, "QSqlDatabasePrivate::removeDatabase: connection '%ls' is still in use, "
+ "all queries will cease to work.", qUtf16Printable(name));
db.d->disable();
db.d->connName.clear();
}
@@ -153,28 +146,28 @@ void QSqlDatabasePrivate::invalidateDb(const QSqlDatabase &db, const QString &na
void QSqlDatabasePrivate::removeDatabase(const QString &name)
{
- QConnectionDict *dict = dbDict();
- Q_ASSERT(dict);
- QWriteLocker locker(&dict->lock);
+ CHECK_QCOREAPPLICATION
+ QtSqlGlobals *sqlGlobals = s_sqlGlobals();
+ QWriteLocker locker(&sqlGlobals->lock);
- if (!dict->contains(name))
+ if (!sqlGlobals->connections.contains(name))
return;
- invalidateDb(dict->take(name), name);
+ invalidateDb(sqlGlobals->connections.take(name), name);
}
void QSqlDatabasePrivate::addDatabase(const QSqlDatabase &db, const QString &name)
{
- QConnectionDict *dict = dbDict();
- Q_ASSERT(dict);
- QWriteLocker locker(&dict->lock);
-
- if (dict->contains(name)) {
- invalidateDb(dict->take(name), name);
- qWarning("QSqlDatabasePrivate::addDatabase: duplicate connection name '%s', old "
- "connection removed.", name.toLocal8Bit().data());
+ CHECK_QCOREAPPLICATION
+ QtSqlGlobals *sqlGlobals = s_sqlGlobals();
+ QWriteLocker locker(&sqlGlobals->lock);
+
+ if (sqlGlobals->connections.contains(name)) {
+ invalidateDb(sqlGlobals->connections.take(name), name);
+ qCWarning(lcSqlDb, "QSqlDatabasePrivate::addDatabase: duplicate connection name '%ls', old "
+ "connection removed.", qUtf16Printable(name));
}
- dict->insert(name, db);
+ sqlGlobals->connections.insert(name, db);
db.d->connName = name;
}
@@ -182,22 +175,18 @@ void QSqlDatabasePrivate::addDatabase(const QSqlDatabase &db, const QString &nam
*/
QSqlDatabase QSqlDatabasePrivate::database(const QString& name, bool open)
{
- const QConnectionDict *dict = dbDict();
- Q_ASSERT(dict);
-
- dict->lock.lockForRead();
- QSqlDatabase db = dict->value(name);
- dict->lock.unlock();
+ CHECK_QCOREAPPLICATION_RETVAL
+ QSqlDatabase db = s_sqlGlobals()->connection(name);
if (!db.isValid())
return db;
if (db.driver()->thread() != QThread::currentThread()) {
- qWarning("QSqlDatabasePrivate::database: requested database does not belong to the calling thread.");
+ qCWarning(lcSqlDb, "QSqlDatabasePrivate::database: requested database does not belong to the calling thread.");
return QSqlDatabase();
}
if (open && !db.isOpen()) {
if (!db.open())
- qWarning() << "QSqlDatabasePrivate::database: unable to open database:" << db.lastError().text();
+ qCWarning(lcSqlDb) << "QSqlDatabasePrivate::database: unable to open database:" << db.lastError().text();
}
return db;
@@ -294,6 +283,10 @@ void QSqlDatabasePrivate::disable()
QSqlDriver. Alternatively, you can subclass your own database
driver from QSqlDriver. See \l{How to Write Your Own Database
Driver} for more information.
+ A QSqlDatabase instance must only be accessed by the thread it
+ was created in. Therefore you have to make sure to create them
+ in the correct context. Alternatively you can change the context
+ with QSqlDatabase::moveToThread().
Create a connection (i.e., an instance of QSqlDatabase) by calling
one of the static addDatabase() functions, where you specify
@@ -488,6 +481,7 @@ void QSqlDatabase::removeDatabase(const QString& connectionName)
QStringList QSqlDatabase::drivers()
{
+ CHECK_QCOREAPPLICATION_RETVAL
QStringList list;
if (QFactoryLoader *fl = loader()) {
@@ -500,7 +494,9 @@ QStringList QSqlDatabase::drivers()
}
}
- const DriverDict dict = QSqlDatabasePrivate::driverDict();
+ QtSqlGlobals *sqlGlobals = s_sqlGlobals();
+ QReadLocker locker(&sqlGlobals->lock);
+ const auto &dict = sqlGlobals->registeredDrivers;
for (const auto &[k, _] : dict.asKeyValueRange()) {
if (!list.contains(k))
list << k;
@@ -524,9 +520,12 @@ QStringList QSqlDatabase::drivers()
*/
void QSqlDatabase::registerSqlDriver(const QString& name, QSqlDriverCreatorBase *creator)
{
- delete QSqlDatabasePrivate::driverDict().take(name);
+ CHECK_QCOREAPPLICATION
+ QtSqlGlobals *sqlGlobals = s_sqlGlobals();
+ QWriteLocker locker(&sqlGlobals->lock);
+ delete sqlGlobals->registeredDrivers.take(name);
if (creator)
- QSqlDatabasePrivate::driverDict().insert(name, creator);
+ sqlGlobals->registeredDrivers.insert(name, creator);
}
/*!
@@ -540,7 +539,8 @@ void QSqlDatabase::registerSqlDriver(const QString& name, QSqlDriverCreatorBase
bool QSqlDatabase::contains(const QString& connectionName)
{
- return dbDict()->contains_ts(connectionName);
+ CHECK_QCOREAPPLICATION_RETVAL
+ return s_sqlGlobals()->connectionExists(connectionName);
}
/*!
@@ -552,7 +552,8 @@ bool QSqlDatabase::contains(const QString& connectionName)
*/
QStringList QSqlDatabase::connectionNames()
{
- return dbDict()->keys_ts();
+ CHECK_QCOREAPPLICATION_RETVAL
+ return s_sqlGlobals()->connectionNames();
}
/*!
@@ -636,27 +637,27 @@ QSqlDatabase &QSqlDatabase::operator=(const QSqlDatabase &other)
void QSqlDatabasePrivate::init(const QString &type)
{
+ CHECK_QCOREAPPLICATION
drvName = type;
if (!driver) {
- DriverDict dict = QSqlDatabasePrivate::driverDict();
- for (DriverDict::const_iterator it = dict.constBegin();
- it != dict.constEnd() && !driver; ++it) {
- if (type == it.key()) {
- driver = ((QSqlDriverCreatorBase*)(*it))->createObject();
- }
- }
+ QtSqlGlobals *sqlGlobals = s_sqlGlobals();
+ QReadLocker locker(&sqlGlobals->lock);
+ const auto &dict = sqlGlobals->registeredDrivers;
+ auto it = dict.find(type);
+ if (it != dict.end())
+ driver = it.value()->createObject();
}
if (!driver && loader())
driver = qLoadPlugin<QSqlDriver, QSqlDriverPlugin>(loader(), type);
if (!driver) {
- qWarning("QSqlDatabase: %s driver not loaded", type.toLatin1().data());
- qWarning("QSqlDatabase: available drivers: %s",
- QSqlDatabase::drivers().join(u' ').toLatin1().data());
+ qCWarning(lcSqlDb, "QSqlDatabase: %ls driver not loaded", qUtf16Printable(type));
+ qCWarning(lcSqlDb, "QSqlDatabase: available drivers: %ls",
+ qUtf16Printable(QSqlDatabase::drivers().join(u' ')));
if (QCoreApplication::instance() == nullptr)
- qWarning("QSqlDatabase: an instance of QCoreApplication is required for loading driver plugins");
+ qCWarning(lcSqlDb, "QSqlDatabase: an instance of QCoreApplication is required for loading driver plugins");
driver = shared_null()->driver;
}
}
@@ -1133,6 +1134,7 @@ bool QSqlDatabase::isDriverAvailable(const QString& name)
}
/*! \fn QSqlDatabase QSqlDatabase::addDatabase(QSqlDriver* driver, const QString& connectionName)
+ \overload
This overload is useful when you want to create a database
connection with a \l{QSqlDriver} {driver} you instantiated
@@ -1249,6 +1251,8 @@ bool QSqlDatabase::isValid() const
\note The new connection has not been opened. Before using the new
connection, you must call open().
+
+ \reentrant
*/
QSqlDatabase QSqlDatabase::cloneDatabase(const QSqlDatabase &other, const QString &connectionName)
{
@@ -1280,24 +1284,11 @@ QSqlDatabase QSqlDatabase::cloneDatabase(const QSqlDatabase &other, const QStrin
QSqlDatabase QSqlDatabase::cloneDatabase(const QString &other, const QString &connectionName)
{
- const QConnectionDict *dict = dbDict();
- Q_ASSERT(dict);
-
- dict->lock.lockForRead();
- QSqlDatabase otherDb = dict->value(other);
- dict->lock.unlock();
- if (!otherDb.isValid())
- return QSqlDatabase();
-
- QSqlDatabase db(otherDb.driverName());
- db.d->copy(otherDb.d);
- QSqlDatabasePrivate::addDatabase(db, connectionName);
- return db;
+ CHECK_QCOREAPPLICATION_RETVAL
+ return cloneDatabase(s_sqlGlobals()->connection(other), connectionName);
}
/*!
- \since 4.4
-
Returns the connection name, which may be empty. \note The
connection name is not the \l{databaseName()} {database name}.
@@ -1309,10 +1300,11 @@ QString QSqlDatabase::connectionName() const
}
/*!
- \since 4.6
+ \property QSqlDatabase::numericalPrecisionPolicy
+ \since 6.8
- Sets the default numerical precision policy used by queries created
- on this database connection to \a precisionPolicy.
+ This property holds the default numerical precision policy used by
+ queries created on this database connection.
Note: Drivers that don't support fetching numerical values with low
precision will ignore the precision policy. You can use
@@ -1322,9 +1314,12 @@ QString QSqlDatabase::connectionName() const
Note: Setting the default precision policy to \a precisionPolicy
doesn't affect any currently active queries.
- \sa QSql::NumericalPrecisionPolicy, numericalPrecisionPolicy(),
- QSqlQuery::setNumericalPrecisionPolicy(), QSqlQuery::numericalPrecisionPolicy()
+ \sa QSql::NumericalPrecisionPolicy, QSqlQuery::numericalPrecisionPolicy,
+ QSqlDriver::numericalPrecisionPolicy
*/
+/*!
+ Sets \l numericalPrecisionPolicy to \a precisionPolicy.
+ */
void QSqlDatabase::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy)
{
if (driver())
@@ -1333,12 +1328,7 @@ void QSqlDatabase::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy pr
}
/*!
- \since 4.6
-
- Returns the current default precision policy for the database connection.
-
- \sa QSql::NumericalPrecisionPolicy, setNumericalPrecisionPolicy(),
- QSqlQuery::numericalPrecisionPolicy(), QSqlQuery::setNumericalPrecisionPolicy()
+ Returns the \l numericalPrecisionPolicy.
*/
QSql::NumericalPrecisionPolicy QSqlDatabase::numericalPrecisionPolicy() const
{
@@ -1348,6 +1338,50 @@ QSql::NumericalPrecisionPolicy QSqlDatabase::numericalPrecisionPolicy() const
return d->precisionPolicy;
}
+/*!
+ \since 6.8
+
+ Changes the thread affinity for QSqlDatabase and its associated driver.
+ This function returns \c true when the function succeeds. Event processing
+ will continue in the \a targetThread.
+
+ During this operation you have to make sure that there is no QSqlQuery
+ bound to this instance otherwise the QSqlDatabase will not be moved to
+ the given thread and the function returns \c false.
+
+ Since the associated driver is derived from QObject, all constraints for
+ moving a QObject to another thread also apply to this function.
+
+ \sa QObject::moveToThread(), {Threads and the SQL Module}
+*/
+bool QSqlDatabase::moveToThread(QThread *targetThread)
+{
+ if (auto drv = driver()) {
+ if (drv != QSqlDatabasePrivate::shared_null()->driver) {
+ // two instances are alive - the one here and the one in dbDict()
+ if (d->ref.loadRelaxed() > 2) {
+ qWarning("QSqlDatabasePrivate::moveToThread: connection '%ls' is still in use "
+ "in the current thread.", qUtf16Printable(d->connName));
+ return false;
+ }
+ return drv->moveToThread(targetThread);
+ }
+ }
+ return false;
+}
+
+/*!
+ \since 6.8
+
+ Returns a pointer to the associated QThread instance.
+*/
+QThread *QSqlDatabase::currentThread() const
+{
+ if (auto drv = driver())
+ return drv->thread();
+ return nullptr;
+}
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QSqlDatabase &d)
@@ -1368,3 +1402,5 @@ QDebug operator<<(QDebug dbg, const QSqlDatabase &d)
#endif
QT_END_NAMESPACE
+
+#include "moc_qsqldatabase.cpp"
diff --git a/src/sql/kernel/qsqldatabase.h b/src/sql/kernel/qsqldatabase.h
index 1fb1eb3966..5059dbba83 100644
--- a/src/sql/kernel/qsqldatabase.h
+++ b/src/sql/kernel/qsqldatabase.h
@@ -5,8 +5,10 @@
#define QSQLDATABASE_H
#include <QtSql/qtsqlglobal.h>
+#include <QtCore/qmetaobject.h>
#include <QtCore/qstring.h>
+// clazy:excludeall=qproperty-without-notify
QT_BEGIN_NAMESPACE
@@ -16,6 +18,7 @@ class QSqlIndex;
class QSqlRecord;
class QSqlQuery;
class QSqlDatabasePrivate;
+class QThread;
class Q_SQL_EXPORT QSqlDriverCreatorBase
{
@@ -33,7 +36,10 @@ public:
class Q_SQL_EXPORT QSqlDatabase
{
+ Q_GADGET
public:
+ Q_PROPERTY(QSql::NumericalPrecisionPolicy numericalPrecisionPolicy READ numericalPrecisionPolicy WRITE setNumericalPrecisionPolicy)
+
QSqlDatabase();
QSqlDatabase(const QSqlDatabase &other);
~QSqlDatabase();
@@ -49,7 +55,7 @@ public:
QSqlIndex primaryIndex(const QString& tablename) const;
QSqlRecord record(const QString& tablename) const;
#if QT_DEPRECATED_SINCE(6, 6)
- QT_DEPRECATED_VERSION_X_6_6("QSqlQuery::exec() instead.")
+ QT_DEPRECATED_VERSION_X_6_6("Use QSqlQuery::exec() instead.")
QSqlQuery exec(const QString& query = QString()) const;
#endif
QSqlError lastError() const;
@@ -75,6 +81,8 @@ public:
QString connectionName() const;
void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy);
QSql::NumericalPrecisionPolicy numericalPrecisionPolicy() const;
+ bool moveToThread(QThread *targetThread);
+ QThread *currentThread() const;
QSqlDriver* driver() const;
diff --git a/src/sql/kernel/qsqldriver.cpp b/src/sql/kernel/qsqldriver.cpp
index f629d8a941..c0cb0374a9 100644
--- a/src/sql/kernel/qsqldriver.cpp
+++ b/src/sql/kernel/qsqldriver.cpp
@@ -215,7 +215,7 @@ bool QSqlDriver::isOpenError() const
\value SQLite
\value Interbase
\value DB2
- \value MimerSQL
+ \value [since 6.6] MimerSQL
*/
/*!
@@ -404,7 +404,6 @@ bool QSqlDriver::isIdentifierEscaped(const QString &identifier, IdentifierType t
Reimplement this function if you want to provide your own implementation in your
QSqlDriver subclass,
- \since 4.5
\sa isIdentifierEscaped()
*/
QString QSqlDriver::stripDelimiters(const QString &identifier, IdentifierType type) const
@@ -680,7 +679,6 @@ QVariant QSqlDriver::handle() const
Reimplement this function if you want to provide event notification support in your
own QSqlDriver subclass,
- \since 4.4
\sa unsubscribeFromNotification(), subscribedToNotifications(), QSqlDriver::hasFeature()
*/
bool QSqlDriver::subscribeToNotification(const QString &name)
@@ -704,7 +702,6 @@ bool QSqlDriver::subscribeToNotification(const QString &name)
Reimplement this function if you want to provide event notification support in your
own QSqlDriver subclass,
- \since 4.4
\sa subscribeToNotification(), subscribedToNotifications()
*/
bool QSqlDriver::unsubscribeFromNotification(const QString &name)
@@ -719,7 +716,6 @@ bool QSqlDriver::unsubscribeFromNotification(const QString &name)
Reimplement this function if you want to provide event notification support in your
own QSqlDriver subclass,
- \since 4.4
\sa subscribeToNotification(), unsubscribeFromNotification()
*/
QStringList QSqlDriver::subscribedToNotifications() const
@@ -728,16 +724,7 @@ QStringList QSqlDriver::subscribedToNotifications() const
}
/*!
- \since 4.6
-
- Sets the default numerical precision policy used by queries created
- by this driver to \a precisionPolicy.
-
- Note: Setting the default precision policy to \a precisionPolicy
- doesn't affect any currently active queries.
-
- \sa QSql::NumericalPrecisionPolicy, numericalPrecisionPolicy(),
- QSqlQuery::setNumericalPrecisionPolicy(), QSqlQuery::numericalPrecisionPolicy()
+ Sets \l numericalPrecisionPolicy to \a precisionPolicy.
*/
void QSqlDriver::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy)
{
@@ -746,12 +733,17 @@ void QSqlDriver::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy prec
}
/*!
- \since 4.6
+ \property QSqlDriver::numericalPrecisionPolicy
+ \since 6.8
- Returns the current default precision policy for the database connection.
+ This property holds the precision policy for the database connection.
+ \note Setting the precision policy doesn't affect any currently active queries.
- \sa QSql::NumericalPrecisionPolicy, setNumericalPrecisionPolicy(),
- QSqlQuery::numericalPrecisionPolicy(), QSqlQuery::setNumericalPrecisionPolicy()
+ \sa QSql::NumericalPrecisionPolicy, QSqlQuery::numericalPrecisionPolicy,
+ QSqlDatabase::numericalPrecisionPolicy
+*/
+/*!
+ Returns the \l numericalPrecisionPolicy.
*/
QSql::NumericalPrecisionPolicy QSqlDriver::numericalPrecisionPolicy() const
{
diff --git a/src/sql/kernel/qsqldriver.h b/src/sql/kernel/qsqldriver.h
index 58ced82c47..a5fe40fa15 100644
--- a/src/sql/kernel/qsqldriver.h
+++ b/src/sql/kernel/qsqldriver.h
@@ -9,6 +9,7 @@
#include <QtCore/qstring.h>
#include <QtCore/qstringlist.h>
+// clazy:excludeall=qproperty-without-notify
QT_BEGIN_NAMESPACE
@@ -51,9 +52,11 @@ public:
SQLite,
Interbase,
DB2,
- MimerSQL
+ MimerSQL,
};
+ Q_PROPERTY(QSql::NumericalPrecisionPolicy numericalPrecisionPolicy READ numericalPrecisionPolicy WRITE setNumericalPrecisionPolicy)
+
explicit QSqlDriver(QObject *parent = nullptr);
~QSqlDriver();
virtual bool isOpen() const;
diff --git a/src/sql/kernel/qsqlerror.cpp b/src/sql/kernel/qsqlerror.cpp
index 7f56357c10..a52f209d53 100644
--- a/src/sql/kernel/qsqlerror.cpp
+++ b/src/sql/kernel/qsqlerror.cpp
@@ -19,7 +19,7 @@ QDebug operator<<(QDebug dbg, const QSqlError &s)
}
#endif
-class QSqlErrorPrivate
+class QSqlErrorPrivate : public QSharedData
{
public:
QString driverError;
@@ -27,7 +27,7 @@ public:
QSqlError::ErrorType errorType;
QString errorCode;
};
-
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QSqlErrorPrivate)
/*!
\class QSqlError
@@ -103,45 +103,38 @@ QSqlError::QSqlError(const QString &driverText, const QString &databaseText,
/*!
Creates a copy of \a other.
*/
-QSqlError::QSqlError(const QSqlError& other)
- : d(new QSqlErrorPrivate(*other.d))
-{
-}
+QSqlError::QSqlError(const QSqlError &other)
+ = default;
/*!
Assigns the \a other error's values to this error.
*/
-QSqlError& QSqlError::operator=(const QSqlError& other)
-{
- if (&other == this)
- return *this;
- if (d && other.d)
- *d = *other.d;
- else if (d)
- *d = QSqlErrorPrivate();
- else if (other.d)
- d = new QSqlErrorPrivate(*other.d);
- return *this;
-}
+QSqlError &QSqlError::operator=(const QSqlError &other)
+ = default;
+
/*!
- Compare the \a other error's values to this error and returns \c true, if it equal.
+ Compare the \a other error's type() and nativeErrorCode()
+ to this error and returns \c true, if it equal.
*/
-bool QSqlError::operator==(const QSqlError& other) const
+bool QSqlError::operator==(const QSqlError &other) const
{
- return (d->errorType == other.d->errorType);
+ return (d->errorType == other.d->errorType &&
+ d->errorCode == other.d->errorCode);
}
/*!
- Compare the \a other error's values to this error and returns \c true if it is not equal.
+ Compare the \a other error's type() and nativeErrorCode()
+ to this error and returns \c true if it is not equal.
*/
-bool QSqlError::operator!=(const QSqlError& other) const
+bool QSqlError::operator!=(const QSqlError &other) const
{
- return (d->errorType != other.d->errorType);
+ return (d->errorType != other.d->errorType ||
+ d->errorCode != other.d->errorCode);
}
@@ -150,9 +143,7 @@ bool QSqlError::operator!=(const QSqlError& other) const
*/
QSqlError::~QSqlError()
-{
- delete d;
-}
+ = default;
/*!
Returns the text of the error as reported by the driver. This may
@@ -209,7 +200,7 @@ QString QSqlError::nativeErrorCode() const
QString QSqlError::text() const
{
QString result = d->databaseError;
- if (!d->databaseError.isEmpty() && !d->driverError.isEmpty() && !d->databaseError.endsWith("\n"_L1))
+ if (!d->databaseError.isEmpty() && !d->driverError.isEmpty() && !d->databaseError.endsWith(u'\n'))
result += u' ';
result += d->driverError;
return result;
diff --git a/src/sql/kernel/qsqlerror.h b/src/sql/kernel/qsqlerror.h
index 6532f1af57..24f2921f5a 100644
--- a/src/sql/kernel/qsqlerror.h
+++ b/src/sql/kernel/qsqlerror.h
@@ -5,11 +5,13 @@
#define QSQLERROR_H
#include <QtSql/qtsqlglobal.h>
+#include <QtCore/qshareddata.h>
#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
class QSqlErrorPrivate;
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QSqlErrorPrivate, Q_SQL_EXPORT)
class Q_SQL_EXPORT QSqlError
{
@@ -25,16 +27,16 @@ public:
const QString &databaseText = QString(),
ErrorType type = NoError,
const QString &errorCode = QString());
- QSqlError(const QSqlError& other);
- QSqlError(QSqlError &&other) noexcept : d(other.d) { other.d = nullptr; }
- QSqlError& operator=(const QSqlError& other);
- QSqlError &operator=(QSqlError &&other) noexcept { swap(other); return *this; }
-
- bool operator==(const QSqlError& other) const;
- bool operator!=(const QSqlError& other) const;
+ QSqlError(const QSqlError &other);
+ QSqlError(QSqlError &&other) noexcept = default;
+ QSqlError& operator=(const QSqlError &other);
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QSqlError)
~QSqlError();
- void swap(QSqlError &other) noexcept { qt_ptr_swap(d, other.d); }
+ bool operator==(const QSqlError &other) const;
+ bool operator!=(const QSqlError &other) const;
+
+ void swap(QSqlError &other) noexcept { d.swap(other.d); }
QString driverText() const;
QString databaseText() const;
@@ -44,7 +46,7 @@ public:
bool isValid() const;
private:
- QSqlErrorPrivate *d = nullptr;
+ QExplicitlySharedDataPointer<QSqlErrorPrivate> d;
};
Q_DECLARE_SHARED(QSqlError)
diff --git a/src/sql/kernel/qsqlfield.cpp b/src/sql/kernel/qsqlfield.cpp
index c407137e7e..0bd0ca5161 100644
--- a/src/sql/kernel/qsqlfield.cpp
+++ b/src/sql/kernel/qsqlfield.cpp
@@ -2,36 +2,20 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsqlfield.h"
-#include "qatomic.h"
#include "qdebug.h"
QT_BEGIN_NAMESPACE
-class QSqlFieldPrivate
+class QSqlFieldPrivate : public QSharedData
{
public:
QSqlFieldPrivate(const QString &name,
QMetaType type, const QString &tableName) :
- ref(1), nm(name), table(tableName), def(QVariant()), type(type),
+ nm(name), table(tableName), def(QVariant()), type(type),
req(QSqlField::Unknown), len(-1), prec(-1), tp(-1),
ro(false), gen(true), autoval(false)
{}
- QSqlFieldPrivate(const QSqlFieldPrivate &other)
- : ref(1),
- nm(other.nm),
- table(other.table),
- def(other.def),
- type(other.type),
- req(other.req),
- len(other.len),
- prec(other.prec),
- tp(other.tp),
- ro(other.ro),
- gen(other.gen),
- autoval(other.autoval)
- {}
-
bool operator==(const QSqlFieldPrivate& other) const
{
return (nm == other.nm
@@ -46,7 +30,6 @@ public:
&& autoval == other.autoval);
}
- QAtomicInt ref;
QString nm;
QString table;
QVariant def;
@@ -59,6 +42,7 @@ public:
bool gen: 1;
bool autoval: 1;
};
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QSqlFieldPrivate)
/*!
@@ -115,7 +99,7 @@ public:
\value Unknown The database driver couldn't determine whether the field is required or
optional.
- \sa requiredStatus()
+ \sa requiredStatus
*/
/*!
@@ -125,9 +109,14 @@ public:
Constructs an empty field called \a fieldName of variant type \a
type in \a table.
+*/
- \sa setRequiredStatus(), setLength(), setPrecision(), setDefaultValue(),
- setGenerated(), setReadOnly()
+/*!
+ \fn void QSqlField::swap(QSqlField &other)
+ \since 6.6
+
+ Swaps this field with \a other. This function is very fast and
+ never fails.
*/
/*!
@@ -136,9 +125,6 @@ public:
\overload
Constructs an empty field called \a fieldName of type \a
type in \a table.
-
- \sa setRequiredStatus(), setLength(), setPrecision(), setDefaultValue(),
- setGenerated(), setReadOnly()
*/
QSqlField::QSqlField(const QString &fieldName, QMetaType type, const QString &table)
: val(QVariant(type, nullptr)),
@@ -151,23 +137,14 @@ QSqlField::QSqlField(const QString &fieldName, QMetaType type, const QString &ta
*/
QSqlField::QSqlField(const QSqlField &other)
- : val(other.val),
- d(other.d)
-{
- d->ref.ref();
-}
+ = default;
/*!
Sets the field equal to \a other.
*/
QSqlField& QSqlField::operator=(const QSqlField& other)
-{
- qAtomicAssign(d, other.d);
- val = other.val;
- return *this;
-}
-
+ = default;
/*! \fn bool QSqlField::operator!=(const QSqlField &other) const
Returns \c true if the field is unequal to \a other; otherwise returns
@@ -189,16 +166,10 @@ bool QSqlField::operator==(const QSqlField& other) const
*/
QSqlField::~QSqlField()
-{
- if (!d->ref.deref())
- delete d;
-}
+ = default;
/*!
- Sets the required status of this field to \a required.
-
- \sa requiredStatus(), setMetaType(), setLength(), setPrecision(),
- setDefaultValue(), setGenerated(), setReadOnly()
+ Sets \l requiredStatus to \a required.
*/
void QSqlField::setRequiredStatus(RequiredStatus required)
{
@@ -211,16 +182,11 @@ void QSqlField::setRequiredStatus(RequiredStatus required)
Sets the required status of this field to \l Required if \a
required is true; otherwise sets it to \l Optional.
- \sa setRequiredStatus(), requiredStatus()
+ \sa requiredStatus
*/
/*!
- Sets the field's length to \a fieldLength. For strings this is the
- maximum number of characters the string can hold; the meaning
- varies for other types.
-
- \sa length(), setMetaType(), setRequiredStatus(), setPrecision(),
- setDefaultValue(), setGenerated(), setReadOnly()
+ Sets \l length to \a fieldLength.
*/
void QSqlField::setLength(int fieldLength)
{
@@ -229,10 +195,7 @@ void QSqlField::setLength(int fieldLength)
}
/*!
- Sets the field's \a precision. This only affects numeric fields.
-
- \sa precision(), setMetaType(), setRequiredStatus(), setLength(),
- setDefaultValue(), setGenerated(), setReadOnly()
+ Sets \l precision to \a precision.
*/
void QSqlField::setPrecision(int precision)
{
@@ -241,10 +204,16 @@ void QSqlField::setPrecision(int precision)
}
/*!
- Sets the default value used for this field to \a value.
+ \property QSqlField::defaultValue
+ \since 6.8
- \sa defaultValue(), value(), setMetaType(), setRequiredStatus(),
- setLength(), setPrecision(), setGenerated(), setReadOnly()
+ This property holds the default value for this field.
+ Only some database drivers supports this property. Currently
+ those are SQLite, PostgreSQL, Oracle and MySQL/MariaDB.
+*/
+
+/*!
+ Sets \l defaultValue to \a value.
*/
void QSqlField::setDefaultValue(const QVariant &value)
{
@@ -252,23 +221,20 @@ void QSqlField::setDefaultValue(const QVariant &value)
d->def = value;
}
+#if QT_DEPRECATED_SINCE(6, 8)
/*!
\internal
+ \deprecated [6.8] This internal value is no longer used.
*/
void QSqlField::setSqlType(int type)
{
detach();
d->tp = type;
}
+#endif
/*!
- Sets the generated state. If \a gen is false, no SQL will
- be generated for this field; otherwise, Qt classes such as
- QSqlQueryModel and QSqlTableModel will generate SQL for this
- field.
-
- \sa isGenerated(), setMetaType(), setRequiredStatus(), setLength(),
- setPrecision(), setDefaultValue(), setReadOnly()
+ Sets \l generated to \a gen.
*/
void QSqlField::setGenerated(bool gen)
{
@@ -278,19 +244,28 @@ void QSqlField::setGenerated(bool gen)
/*!
- Sets the value of the field to \a value. If the field is read-only
- (isReadOnly() returns \c true), nothing happens.
+ \property QSqlField::value
+ \since 6.8
+ This property holds the \a value as a QVariant
+
+ Setting a \a value to a read-only QSqlField is a no-op.
If the data type of \a value differs from the field's current
data type, an attempt is made to cast it to the proper type. This
preserves the data type of the field in the case of assignment,
e.g. a QString to an integer data type.
To set the value to NULL, use clear().
-
- \sa value(), isReadOnly(), defaultValue()
*/
+/*!
+ \fn QVariant QSqlField::value() const
+
+ Returns the value of \l value.
+*/
+/*!
+ Sets \l value to \a value.
+*/
void QSqlField::setValue(const QVariant& value)
{
if (isReadOnly())
@@ -301,8 +276,6 @@ void QSqlField::setValue(const QVariant& value)
/*!
Clears the value of the field and sets it to NULL.
If the field is read-only, nothing happens.
-
- \sa setValue(), isReadOnly(), requiredStatus()
*/
void QSqlField::clear()
@@ -312,12 +285,10 @@ void QSqlField::clear()
val = QVariant(d->type, nullptr);
}
-/*!
- Sets the name of the field to \a name.
- \sa name()
+/*!
+ Sets \l name to \a name.
*/
-
void QSqlField::setName(const QString& name)
{
detach();
@@ -325,9 +296,7 @@ void QSqlField::setName(const QString& name)
}
/*!
- Sets the read only flag of the field's value to \a readOnly. A
- read-only field cannot have its value set with setValue() and
- cannot be cleared to NULL with clear().
+ Sets \l readOnly to \a readOnly.
*/
void QSqlField::setReadOnly(bool readOnly)
{
@@ -336,17 +305,14 @@ void QSqlField::setReadOnly(bool readOnly)
}
/*!
- \fn QVariant QSqlField::value() const
-
- Returns the value of the field as a QVariant.
+ \property QSqlField::name
- Use isNull() to check if the field's value is NULL.
+ This property holds the name of the field.
+ This can be the column name or a user given alias.
*/
/*!
- Returns the name of the field.
-
- \sa setName()
+ Returns the value of \l name.
*/
QString QSqlField::name() const
{
@@ -354,13 +320,20 @@ QString QSqlField::name() const
}
/*!
- Returns the field's type as stored in the database.
+ \property QSqlField::metaType
+ \since 6.8
+
+ This property holds the field's type as stored in the database.
Note that the actual value might have a different type,
Numerical values that are too large to store in a long
int or double are usually stored as strings to prevent
precision loss.
- \sa setMetaType()
+ \sa QSqlDatabase::numericalPrecisionPolicy
+*/
+
+/*!
+ Returns the value of \l metaType.
*/
QMetaType QSqlField::metaType() const
{
@@ -368,10 +341,7 @@ QMetaType QSqlField::metaType() const
}
/*!
- Set's the field's variant type to \a type.
-
- \sa metaType(), setRequiredStatus(), setLength(), setPrecision(),
- setDefaultValue(), setGenerated(), setReadOnly()
+ Sets \l metaType to \a type.
*/
void QSqlField::setMetaType(QMetaType type)
{
@@ -391,7 +361,7 @@ void QSqlField::setMetaType(QMetaType type)
int or double are usually stored as strings to prevent
precision loss.
- \sa metaType()
+ \sa metaType
*/
/*!
@@ -400,41 +370,56 @@ void QSqlField::setMetaType(QMetaType type)
Sets the field's variant type to \a type.
- \sa setMetaType()
+ \sa metaType
*/
/*!
- Returns \c true if the field's value is read-only; otherwise returns
- false.
+ \property QSqlField::readOnly
+ \since 6.8
+
+ When this property is \c true then this QSqlField cannot be modified.
+ A read-only field cannot have its value set with setValue() and
+ cannot be cleared to NULL with clear().
+*/
- \sa setReadOnly(), metaType(), requiredStatus(), length(), precision(),
- defaultValue(), isGenerated()
+/*!
+ Returns the value of \l readOnly.
*/
bool QSqlField::isReadOnly() const
-{ return d->ro; }
+{
+ return d->ro;
+}
/*!
Returns \c true if the field's value is NULL; otherwise returns
false.
- \sa value()
+ \sa value
*/
bool QSqlField::isNull() const
-{ return val.isNull(); }
+{
+ return val.isNull();
+}
/*! \internal
*/
void QSqlField::detach()
{
- qAtomicDetach(d);
+ d.detach();
}
/*!
- Returns \c true if this is a required field; otherwise returns \c false.
+ \property QSqlField::requiredStatus
+ \since 6.8
+
+ This property holds the RequiredStatus of the field.
An \c INSERT will fail if a required field does not have a value.
- \sa setRequiredStatus(), metaType(), length(), precision(), defaultValue(),
- isGenerated()
+ \sa RequiredStatus
+*/
+
+/*!
+ Returns the value of \l requiredStatus.
*/
QSqlField::RequiredStatus QSqlField::requiredStatus() const
{
@@ -442,13 +427,19 @@ QSqlField::RequiredStatus QSqlField::requiredStatus() const
}
/*!
- Returns the field's length.
+ \property QSqlField::length
+ \since 6.8
- If the returned value is negative, it means that the information
+ This property holds the field's length.
+
+ If the value is negative, it means that the information
is not available from the database.
+ For strings this is the maximum number of characters the string
+ can hold; the meaning varies for other types.
+*/
- \sa setLength(), metaType(), requiredStatus(), precision(), defaultValue(),
- isGenerated()
+/*!
+ Returns the value of \l length.
*/
int QSqlField::length() const
{
@@ -456,14 +447,17 @@ int QSqlField::length() const
}
/*!
- Returns the field's precision; this is only meaningful for numeric
- types.
+ \property QSqlField::precision
+ \since 6.8
+
+ This property holds the field's precision; this is only meaningful
+ for numeric types.
If the returned value is negative, it means that the information
is not available from the database.
-
- \sa setPrecision(), metaType(), requiredStatus(), length(), defaultValue(),
- isGenerated()
+*/
+/*!
+ Returns the value of \l precision.
*/
int QSqlField::precision() const
{
@@ -471,18 +465,17 @@ int QSqlField::precision() const
}
/*!
- Returns the field's default value (which may be NULL).
-
- \sa setDefaultValue(), metaType(), requiredStatus(), length(), precision(),
- isGenerated()
+ Sets the value of \l defaultValue.
*/
QVariant QSqlField::defaultValue() const
{
return d->def;
}
+#if QT_DEPRECATED_SINCE(6, 8)
/*!
\internal
+ \deprecated [6.8] This internal value is no longer used.
Returns the type ID for the field.
@@ -493,13 +486,19 @@ int QSqlField::typeID() const
{
return d->tp;
}
+#endif
/*!
- Returns \c true if the field is generated; otherwise returns
- false.
+ \property QSqlField::generated
+ \since 6.8
- \sa setGenerated(), metaType(), requiredStatus(), length(), precision(),
- defaultValue()
+ This property holds the generated state. If \a generated is \c false,
+ no SQL will be generated for this field; otherwise, Qt classes such as
+ QSqlQueryModel and QSqlTableModel will generate SQL for this field.
+*/
+
+/*!
+ Returns the value of \l generated.
*/
bool QSqlField::isGenerated() const
{
@@ -530,8 +529,6 @@ QDebug operator<<(QDebug dbg, const QSqlField &f)
dbg << ", required: "
<< (f.requiredStatus() == QSqlField::Required ? "yes" : "no");
dbg << ", generated: " << (f.isGenerated() ? "yes" : "no");
- if (f.typeID() >= 0)
- dbg << ", typeID: " << f.typeID();
if (!f.defaultValue().isNull())
dbg << ", defaultValue: \"" << f.defaultValue() << '\"';
dbg << ", autoValue: " << f.isAutoValue()
@@ -541,16 +538,21 @@ QDebug operator<<(QDebug dbg, const QSqlField &f)
#endif
/*!
- Returns \c true if the value is auto-generated by the database,
- for example auto-increment primary key values.
+ \property QSqlField::autoValue
+ \since 6.8
+
+ If the value is auto-generated by the database,
+ for example auto-increment primary key values, this value is \c true.
\note When using the ODBC driver, due to limitations in the ODBC API,
the \c isAutoValue() field is only populated in a QSqlField resulting from a
QSqlRecord obtained by executing a \c SELECT query. It is \c false in a QSqlField
resulting from a QSqlRecord returned from QSqlDatabase::record() or
QSqlDatabase::primaryIndex().
+*/
- \sa setAutoValue()
+/*!
+ Returns the value of \l autoValue.
*/
bool QSqlField::isAutoValue() const
{
@@ -558,11 +560,8 @@ bool QSqlField::isAutoValue() const
}
/*!
- Marks the field as an auto-generated value if \a autoVal
- is true.
-
- \sa isAutoValue()
- */
+ Sets \l autoValue to \a autoVal.
+*/
void QSqlField::setAutoValue(bool autoVal)
{
detach();
@@ -570,24 +569,26 @@ void QSqlField::setAutoValue(bool autoVal)
}
/*!
- Sets the tableName of the field to \a table.
-
- \sa tableName()
+ Sets \l tableName to \a tableName.
*/
-void QSqlField::setTableName(const QString &table)
+void QSqlField::setTableName(const QString &tableName)
{
detach();
- d->table = table;
+ d->table = tableName;
}
/*!
- Returns the tableName of the field.
+ \property QSqlField::tableName
+ \since 6.8
+
+ This property holds the tableName of the field.
\note When using the QPSQL driver, due to limitations in the libpq library,
the \c tableName() field is not populated in a QSqlField resulting
from a QSqlRecord obtained by QSqlQuery::record() of a forward-only query.
-
- \sa setTableName()
+*/
+/*!
+ Returns the \l tableName.
*/
QString QSqlField::tableName() const
{
@@ -595,3 +596,5 @@ QString QSqlField::tableName() const
}
QT_END_NAMESPACE
+
+#include "moc_qsqlfield.cpp"
diff --git a/src/sql/kernel/qsqlfield.h b/src/sql/kernel/qsqlfield.h
index 67aed772bd..451f70f3b6 100644
--- a/src/sql/kernel/qsqlfield.h
+++ b/src/sql/kernel/qsqlfield.h
@@ -5,6 +5,7 @@
#define QSQLFIELD_H
#include <QtSql/qtsqlglobal.h>
+#include <QtCore/qshareddata.h>
#include <QtCore/qvariant.h>
#include <QtCore/qstring.h>
@@ -12,19 +13,38 @@ QT_BEGIN_NAMESPACE
class QSqlFieldPrivate;
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QSqlFieldPrivate, Q_SQL_EXPORT)
class Q_SQL_EXPORT QSqlField
{
+ Q_GADGET
public:
enum RequiredStatus { Unknown = -1, Optional = 0, Required = 1 };
+ Q_PROPERTY(QVariant value READ value WRITE setValue)
+ Q_PROPERTY(QVariant defaultValue READ defaultValue WRITE setDefaultValue)
+ Q_PROPERTY(QString name READ name WRITE setName)
+ Q_PROPERTY(QString tableName READ tableName WRITE setTableName)
+ Q_PROPERTY(QMetaType metaType READ metaType WRITE setMetaType)
+ Q_PROPERTY(RequiredStatus requiredStatus READ requiredStatus WRITE setRequiredStatus)
+ Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly)
+ Q_PROPERTY(bool generated READ isGenerated WRITE setGenerated)
+ Q_PROPERTY(bool autoValue READ isAutoValue WRITE setAutoValue)
+ Q_PROPERTY(int length READ length WRITE setLength)
+ Q_PROPERTY(int precision READ precision WRITE setPrecision)
+
explicit QSqlField(const QString& fieldName = QString(), QMetaType type = QMetaType(), const QString &tableName = QString());
QSqlField(const QSqlField& other);
QSqlField& operator=(const QSqlField& other);
+ QSqlField(QSqlField &&other) noexcept = default;
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QSqlField)
+ ~QSqlField();
+
+ void swap(QSqlField &other) noexcept { val.swap(other.val); d.swap(other.d); }
+
bool operator==(const QSqlField& other) const;
inline bool operator!=(const QSqlField &other) const { return !operator==(other); }
- ~QSqlField();
void setValue(const QVariant& value);
inline QVariant value() const
@@ -62,7 +82,6 @@ public:
void setLength(int fieldLength);
void setPrecision(int precision);
void setDefaultValue(const QVariant &value);
- void setSqlType(int type);
void setGenerated(bool gen);
void setAutoValue(bool autoVal);
@@ -70,16 +89,24 @@ public:
int length() const;
int precision() const;
QVariant defaultValue() const;
- int typeID() const;
bool isGenerated() const;
bool isValid() const;
+#if QT_DEPRECATED_SINCE(6, 8)
+ QT_DEPRECATED_VERSION_X_6_8("This internal value is no longer used.")
+ void setSqlType(int type);
+ QT_DEPRECATED_VERSION_X_6_8("This internal value is no longer used.")
+ int typeID() const;
+#endif
private:
void detach();
+ // ### Qt7: move to private class
QVariant val;
- QSqlFieldPrivate* d;
+ QExplicitlySharedDataPointer<QSqlFieldPrivate> d;
};
+Q_DECLARE_SHARED(QSqlField)
+
#ifndef QT_NO_DEBUG_STREAM
Q_SQL_EXPORT QDebug operator<<(QDebug, const QSqlField &);
#endif
diff --git a/src/sql/kernel/qsqlindex.cpp b/src/sql/kernel/qsqlindex.cpp
index 25b032f336..15ee489928 100644
--- a/src/sql/kernel/qsqlindex.cpp
+++ b/src/sql/kernel/qsqlindex.cpp
@@ -41,6 +41,25 @@ QSqlIndex::QSqlIndex(const QSqlIndex& other)
{
}
+/*! \fn QSqlIndex::QSqlIndex(QSqlIndex &&other)
+ Move-constructs a new QSqlIndex from \a other.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new value.
+
+ \since 6.6
+*/
+/*! \fn QSqlIndex& QSqlIndex::operator=(QSqlIndex &&other)
+ Move-assigns \a other to this QSqlIndex instance.
+
+ \note The moved-from object \a other is placed in a
+ partially-formed state, in which the only valid operations are
+ destruction and assignment of a new value.
+
+ \since 6.6
+*/
+
/*!
Sets the index equal to \a other.
*/
@@ -54,6 +73,7 @@ QSqlIndex& QSqlIndex::operator=(const QSqlIndex& other)
return *this;
}
+
/*!
Destroys the object and frees any allocated resources.
*/
@@ -64,21 +84,23 @@ QSqlIndex::~QSqlIndex()
}
/*!
- Sets the name of the index to \a name.
+ \property QSqlIndex::name
+ \since 6.8
+ This property holds the name of the index.
+*/
+/*!
+ \fn QString QSqlIndex::name() const
+ Returns the \l name.
+*/
+/*!
+ Sets \l name to \a name.
*/
-
void QSqlIndex::setName(const QString& name)
{
nm = name;
}
/*!
- \fn QString QSqlIndex::name() const
-
- Returns the name of the index.
-*/
-
-/*!
Appends the field \a field to the list of indexed fields. The
field is appended with an ascending sort order.
*/
@@ -127,34 +149,18 @@ void QSqlIndex::setDescending(int i, bool desc)
sorts[i] = desc;
}
-/*! \internal
-
- Creates a string representing the field number \a i using prefix \a
- prefix. If \a verbose is true, ASC or DESC is included in the field
- description if the field is sorted in ASCending or DESCending order.
+/*!
+ \property QSqlIndex::cursorName
+ \since 6.8
+ This property holds the name of the cursor which the index
+ is associated with.
*/
-
-QString QSqlIndex::createField(int i, const QString& prefix, bool verbose) const
-{
- QString f;
- if (!prefix.isEmpty())
- f += prefix + u'.';
- f += field(i).name();
- if (verbose)
- f += u' ' + QString((isDescending(i) ? "DESC"_L1 : "ASC"_L1));
- return f;
-}
-
/*!
\fn QString QSqlIndex::cursorName() const
-
- Returns the name of the cursor which the index is associated with.
+ Returns the \l cursorName.
*/
-
-
/*!
- Sets the name of the cursor that the index is associated with to
- \a cursorName.
+ Sets \l cursorName to \a cursorName.
*/
void QSqlIndex::setCursorName(const QString& cursorName)
{
@@ -162,3 +168,5 @@ void QSqlIndex::setCursorName(const QString& cursorName)
}
QT_END_NAMESPACE
+
+#include "moc_qsqlindex.cpp"
diff --git a/src/sql/kernel/qsqlindex.h b/src/sql/kernel/qsqlindex.h
index 08ef14b614..3d5d95b373 100644
--- a/src/sql/kernel/qsqlindex.h
+++ b/src/sql/kernel/qsqlindex.h
@@ -7,18 +7,34 @@
#include <QtSql/qtsqlglobal.h>
#include <QtSql/qsqlrecord.h>
#include <QtCore/qlist.h>
+#include <QtCore/qmetaobject.h>
#include <QtCore/qstring.h>
+// clazy:excludeall=qproperty-without-notify
QT_BEGIN_NAMESPACE
class Q_SQL_EXPORT QSqlIndex : public QSqlRecord
{
+ Q_GADGET
public:
+ Q_PROPERTY(QString name READ name WRITE setName)
+ Q_PROPERTY(QString cursorName READ cursorName WRITE setCursorName)
+
explicit QSqlIndex(const QString &cursorName = QString(), const QString &name = QString());
QSqlIndex(const QSqlIndex &other);
+ QSqlIndex(QSqlIndex &&other) noexcept = default;
~QSqlIndex();
QSqlIndex &operator=(const QSqlIndex &other);
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QSqlIndex)
+
+ void swap(QSqlIndex &other) noexcept {
+ QSqlRecord::swap(other);
+ cursor.swap(other.cursor);
+ nm.swap(other.nm);
+ sorts.swap(other.sorts);
+ };
+
void setCursorName(const QString &cursorName);
inline QString cursorName() const { return cursor; }
void setName(const QString& name);
@@ -31,12 +47,14 @@ public:
void setDescending(int i, bool desc);
private:
- QString createField(int i, const QString& prefix, bool verbose) const;
+ // ### Qt7: move to d-ptr
QString cursor;
QString nm;
QList<bool> sorts;
};
+Q_DECLARE_SHARED(QSqlIndex)
+
QT_END_NAMESPACE
#endif // QSQLINDEX_H
diff --git a/src/sql/kernel/qsqlquery.cpp b/src/sql/kernel/qsqlquery.cpp
index 3a764c1361..14a1116531 100644
--- a/src/sql/kernel/qsqlquery.cpp
+++ b/src/sql/kernel/qsqlquery.cpp
@@ -7,6 +7,7 @@
#include "qatomic.h"
#include "qdebug.h"
+#include "qloggingcategory.h"
#include "qsqlrecord.h"
#include "qsqlresult.h"
#include "qsqldriver.h"
@@ -19,6 +20,8 @@
QT_BEGIN_NAMESPACE
+static Q_LOGGING_CATEGORY(lcSqlQuery, "qt.sql.qsqlquery")
+
class QSqlQueryPrivate
{
public:
@@ -327,19 +330,26 @@ bool QSqlQuery::isNull(int field) const
/*!
\overload
+*/
+bool QSqlQuery::isNull(const QString &name) const
+{
+ return isNull(QStringView(name));
+}
+
+/*!
+ \overload
Returns \c true if there is no field with this \a name; otherwise
returns isNull(int index) for the corresponding field index.
This overload is less efficient than \l{QSqlQuery::}{isNull()}
*/
-
-bool QSqlQuery::isNull(const QString &name) const
+bool QSqlQuery::isNull(QStringView name) const
{
qsizetype index = d->sqlResult->record().indexOf(name);
if (index > -1)
return isNull(index);
- qWarning("QSqlQuery::isNull: unknown field name '%s'", qPrintable(name));
+ qCWarning(lcSqlQuery, "QSqlQuery::isNull: unknown field name '%ls'", qUtf16Printable(name.toString()));
return true;
}
@@ -375,7 +385,7 @@ bool QSqlQuery::exec(const QString& query)
t.start();
#endif
if (!driver()) {
- qWarning("QSqlQuery::exec: called before driver has been set up");
+ qCWarning(lcSqlQuery, "QSqlQuery::exec: called before driver has been set up");
return false;
}
if (d->ref.loadRelaxed() != 1) {
@@ -392,19 +402,20 @@ bool QSqlQuery::exec(const QString& query)
}
d->sqlResult->setQuery(query.trimmed());
if (!driver()->isOpen() || driver()->isOpenError()) {
- qWarning("QSqlQuery::exec: database not open");
+ qCWarning(lcSqlQuery, "QSqlQuery::exec: database not open");
return false;
}
if (query.isEmpty()) {
- qWarning("QSqlQuery::exec: empty query");
+ qCWarning(lcSqlQuery, "QSqlQuery::exec: empty query");
return false;
}
bool retval = d->sqlResult->reset(query);
#ifdef QT_DEBUG_SQL
- qDebug().nospace() << "Executed query (" << t.elapsed() << "ms, " << d->sqlResult->size()
- << " results, " << d->sqlResult->numRowsAffected()
- << " affected): " << d->sqlResult->lastQuery();
+ qCDebug(lcSqlQuery()).nospace() << "Executed query (" << t.elapsed() << "ms, "
+ << d->sqlResult->size()
+ << " results, " << d->sqlResult->numRowsAffected()
+ << " affected): " << d->sqlResult->lastQuery();
#endif
return retval;
}
@@ -432,25 +443,32 @@ QVariant QSqlQuery::value(int index) const
{
if (isActive() && isValid() && (index > -1))
return d->sqlResult->data(index);
- qWarning("QSqlQuery::value: not positioned on a valid record");
+ qCWarning(lcSqlQuery, "QSqlQuery::value: not positioned on a valid record");
return QVariant();
}
/*!
\overload
+*/
+QVariant QSqlQuery::value(const QString &name) const
+{
+ return value(QStringView(name));
+}
+
+/*!
+ \overload
Returns the value of the field called \a name in the current record.
If field \a name does not exist an invalid variant is returned.
This overload is less efficient than \l{QSqlQuery::}{value()}
*/
-
-QVariant QSqlQuery::value(const QString& name) const
+QVariant QSqlQuery::value(QStringView name) const
{
qsizetype index = d->sqlResult->record().indexOf(name);
if (index > -1)
return value(index);
- qWarning("QSqlQuery::value: unknown field name '%s'", qPrintable(name));
+ qCWarning(lcSqlQuery, "QSqlQuery::value: unknown field name '%ls'", qUtf16Printable(name.toString()));
return QVariant();
}
@@ -596,7 +614,7 @@ bool QSqlQuery::seek(int index, bool relative)
}
// let drivers optimize
if (isForwardOnly() && actualIdx < at()) {
- qWarning("QSqlQuery::seek: cannot seek backwards in a forward only query");
+ qCWarning(lcSqlQuery, "QSqlQuery::seek: cannot seek backwards in a forward only query");
return false;
}
if (actualIdx == (at() + 1) && at() != QSql::BeforeFirstRow) {
@@ -702,7 +720,7 @@ bool QSqlQuery::previous()
if (!isSelect() || !isActive())
return false;
if (isForwardOnly()) {
- qWarning("QSqlQuery::seek: cannot seek backwards in a forward only query");
+ qCWarning(lcSqlQuery, "QSqlQuery::seek: cannot seek backwards in a forward only query");
return false;
}
@@ -735,7 +753,7 @@ bool QSqlQuery::first()
if (!isSelect() || !isActive())
return false;
if (isForwardOnly() && at() > QSql::BeforeFirstRow) {
- qWarning("QSqlQuery::seek: cannot seek backwards in a forward only query");
+ qCWarning(lcSqlQuery, "QSqlQuery::seek: cannot seek backwards in a forward only query");
return false;
}
return d->sqlResult->fetchFirst();
@@ -850,10 +868,9 @@ bool QSqlQuery::isSelect() const
}
/*!
- Returns \c true if you can only scroll forward through a result set;
- otherwise returns \c false.
+ Returns \l forwardOnly.
- \sa setForwardOnly(), next()
+ \sa forwardOnly, next(), seek()
*/
bool QSqlQuery::isForwardOnly() const
{
@@ -861,7 +878,10 @@ bool QSqlQuery::isForwardOnly() const
}
/*!
- Sets forward only mode to \a forward. If \a forward is true, only
+ \property QSqlQuery::forwardOnly
+ \since 6.8
+
+ This property holds the forward only mode. If \a forward is true, only
next() and seek() with positive values, are allowed for navigating
the results.
@@ -890,7 +910,11 @@ bool QSqlQuery::isForwardOnly() const
mode, do not execute any other SQL command on the same database
connection. This will cause the query results to be lost.
- \sa isForwardOnly(), next(), seek(), QSqlResult::setForwardOnly()
+ \sa next(), seek()
+*/
+/*!
+ Sets \l forwardOnly to \a forward.
+ \sa forwardOnly, next(), seek()
*/
void QSqlQuery::setForwardOnly(bool forward)
{
@@ -976,19 +1000,19 @@ bool QSqlQuery::prepare(const QString& query)
d->sqlResult->setNumericalPrecisionPolicy(d->sqlResult->numericalPrecisionPolicy());
}
if (!driver()) {
- qWarning("QSqlQuery::prepare: no driver");
+ qCWarning(lcSqlQuery, "QSqlQuery::prepare: no driver");
return false;
}
if (!driver()->isOpen() || driver()->isOpenError()) {
- qWarning("QSqlQuery::prepare: database not open");
+ qCWarning(lcSqlQuery, "QSqlQuery::prepare: database not open");
return false;
}
if (query.isEmpty()) {
- qWarning("QSqlQuery::prepare: empty query");
+ qCWarning(lcSqlQuery, "QSqlQuery::prepare: empty query");
return false;
}
#ifdef QT_DEBUG_SQL
- qDebug("\n QSqlQuery::prepare: %s", query.toLocal8Bit().constData());
+ qCDebug(lcSqlQuery, "\n QSqlQuery::prepare: %ls", qUtf16Printable(query));
#endif
return d->sqlResult->savePrepare(query);
}
@@ -1015,9 +1039,9 @@ bool QSqlQuery::exec()
bool retval = d->sqlResult->exec();
#ifdef QT_DEBUG_SQL
- qDebug().nospace() << "Executed prepared query (" << t.elapsed() << "ms, "
- << d->sqlResult->size() << " results, " << d->sqlResult->numRowsAffected()
- << " affected): " << d->sqlResult->lastQuery();
+ qCDebug(lcSqlQuery).nospace() << "Executed prepared query (" << t.elapsed() << "ms, "
+ << d->sqlResult->size() << " results, " << d->sqlResult->numRowsAffected()
+ << " affected): " << d->sqlResult->lastQuery();
#endif
return retval;
}
@@ -1029,8 +1053,6 @@ bool QSqlQuery::exec()
*/
/*!
- \since 4.2
-
Executes a previously prepared SQL query in a batch. All the bound
parameters have to be lists of variants. If the database doesn't
support batch executions, the driver will simulate it using
@@ -1138,6 +1160,7 @@ QVariant QSqlQuery::boundValue(const QString& placeholder) const
/*!
Returns the value for the placeholder at position \a pos.
+ \sa boundValues()
*/
QVariant QSqlQuery::boundValue(int pos) const
{
@@ -1156,7 +1179,7 @@ QVariant QSqlQuery::boundValue(int pos) const
\snippet sqldatabase/sqldatabase.cpp 14
- \sa boundValue(), bindValue(), addBindValue()
+ \sa boundValue(), bindValue(), addBindValue(), boundValueNames()
*/
QVariantList QSqlQuery::boundValues() const
@@ -1166,6 +1189,36 @@ QVariantList QSqlQuery::boundValues() const
}
/*!
+ \since 6.6
+
+ Returns the names of all bound values.
+
+ The order of the list is in binding order, irrespective of whether
+ named or positional binding is used.
+
+ \sa boundValues(), boundValueName()
+*/
+QStringList QSqlQuery::boundValueNames() const
+{
+ return d->sqlResult->boundValueNames();
+}
+
+/*!
+ \since 6.6
+
+ Returns the bound value name at position \a pos.
+
+ The order of the list is in binding order, irrespective of whether
+ named or positional binding is used.
+
+ \sa boundValueNames()
+*/
+QString QSqlQuery::boundValueName(int pos) const
+{
+ return d->sqlResult->boundValueName(pos);
+}
+
+/*!
Returns the last query that was successfully executed.
In most cases this function returns the same string as lastQuery().
@@ -1203,6 +1256,8 @@ QVariant QSqlQuery::lastInsertId() const
}
/*!
+ \property QSqlQuery::numericalPrecisionPolicy
+ \since 6.8
Instruct the database driver to return numerical values with a
precision specified by \a precisionPolicy.
@@ -1221,17 +1276,19 @@ QVariant QSqlQuery::lastInsertId() const
active query. Call \l{exec()}{exec(QString)} or prepare() in order
to activate the policy.
- \sa QSql::NumericalPrecisionPolicy, numericalPrecisionPolicy()
+ \sa QSql::NumericalPrecisionPolicy, QSqlDriver::numericalPrecisionPolicy,
+ QSqlDatabase::numericalPrecisionPolicy
*/
+/*!
+ Sets \l numericalPrecisionPolicy to \a precisionPolicy.
+ */
void QSqlQuery::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy)
{
d->sqlResult->setNumericalPrecisionPolicy(precisionPolicy);
}
/*!
- Returns the current precision policy.
-
- \sa QSql::NumericalPrecisionPolicy, setNumericalPrecisionPolicy()
+ Returns the \l numericalPrecisionPolicy.
*/
QSql::NumericalPrecisionPolicy QSqlQuery::numericalPrecisionPolicy() const
{
@@ -1239,8 +1296,41 @@ QSql::NumericalPrecisionPolicy QSqlQuery::numericalPrecisionPolicy() const
}
/*!
- \since 4.3.2
+ \property QSqlQuery::positionalBindingEnabled
+ \since 6.8
+ This property enables or disables the positional \l {Approaches to Binding Values}{binding}
+ for this query, depending on \a enable (default is \c true).
+ Disabling positional bindings is useful if the query itself contains a '?'
+ which must not be handled as a positional binding parameter but, for example,
+ as a JSON operator for a PostgreSQL database.
+
+ This property will have no effect when the database has native
+ support for positional bindings with question marks (see also
+ \l{QSqlDriver::PositionalPlaceholders}).
+*/
+
+/*!
+ Sets \l positionalBindingEnabled to \a enable.
+ \since 6.7
+ \sa positionalBindingEnabled
+*/
+void QSqlQuery::setPositionalBindingEnabled(bool enable)
+{
+ d->sqlResult->setPositionalBindingEnabled(enable);
+}
+/*!
+ Returns \l positionalBindingEnabled.
+ \since 6.7
+ \sa positionalBindingEnabled
+*/
+bool QSqlQuery::isPositionalBindingEnabled() const
+{
+ return d->sqlResult->isPositionalBindingEnabled();
+}
+
+
+/*!
Instruct the database driver that no more data will be fetched from
this query until it is re-executed. There is normally no need to
call this function, but it may be helpful in order to free resources
@@ -1262,8 +1352,6 @@ void QSqlQuery::finish()
}
/*!
- \since 4.4
-
Discards the current result set and navigates to the next if available.
Some databases are capable of returning multiple result sets for
@@ -1289,7 +1377,7 @@ void QSqlQuery::finish()
databases may have restrictions on which statements are allowed to
be used in a SQL batch.
- \sa QSqlDriver::hasFeature(), setForwardOnly(), next(), isSelect(),
+ \sa QSqlDriver::hasFeature(), forwardOnly, next(), isSelect(),
numRowsAffected(), isActive(), lastError()
*/
bool QSqlQuery::nextResult()
@@ -1300,3 +1388,5 @@ bool QSqlQuery::nextResult()
}
QT_END_NAMESPACE
+
+#include "moc_qsqlquery.cpp"
diff --git a/src/sql/kernel/qsqlquery.h b/src/sql/kernel/qsqlquery.h
index ad389fee7e..244b026205 100644
--- a/src/sql/kernel/qsqlquery.h
+++ b/src/sql/kernel/qsqlquery.h
@@ -9,6 +9,7 @@
#include <QtCore/qstring.h>
#include <QtCore/qvariant.h>
+// clazy:excludeall=qproperty-without-notify
QT_BEGIN_NAMESPACE
@@ -21,7 +22,12 @@ class QSqlQueryPrivate;
class Q_SQL_EXPORT QSqlQuery
{
+ Q_GADGET
public:
+ Q_PROPERTY(bool forwardOnly READ isForwardOnly WRITE setForwardOnly)
+ Q_PROPERTY(bool positionalBindingEnabled READ isPositionalBindingEnabled WRITE setPositionalBindingEnabled)
+ Q_PROPERTY(QSql::NumericalPrecisionPolicy numericalPrecisionPolicy READ numericalPrecisionPolicy WRITE setNumericalPrecisionPolicy)
+
explicit QSqlQuery(QSqlResult *r);
explicit QSqlQuery(const QString& query = QString(), const QSqlDatabase &db = QSqlDatabase());
explicit QSqlQuery(const QSqlDatabase &db);
@@ -50,6 +56,7 @@ public:
bool isActive() const;
bool isNull(int field) const;
bool isNull(const QString &name) const;
+ bool isNull(QStringView name) const;
int at() const;
QString lastQuery() const;
int numRowsAffected() const;
@@ -64,11 +71,15 @@ public:
void setForwardOnly(bool forward);
bool exec(const QString& query);
QVariant value(int i) const;
- QVariant value(const QString& name) const;
+ QVariant value(const QString &name) const;
+ QVariant value(QStringView name) const;
void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy);
QSql::NumericalPrecisionPolicy numericalPrecisionPolicy() const;
+ void setPositionalBindingEnabled(bool enable);
+ bool isPositionalBindingEnabled() const;
+
bool seek(int i, bool relative = false);
bool next();
bool previous();
@@ -89,6 +100,8 @@ public:
QVariant boundValue(const QString& placeholder) const;
QVariant boundValue(int pos) const;
QVariantList boundValues() const;
+ QStringList boundValueNames() const;
+ QString boundValueName(int pos) const;
QString executedQuery() const;
QVariant lastInsertId() const;
void finish();
diff --git a/src/sql/kernel/qsqlrecord.cpp b/src/sql/kernel/qsqlrecord.cpp
index c9f26e27a1..53b64c1464 100644
--- a/src/sql/kernel/qsqlrecord.cpp
+++ b/src/sql/kernel/qsqlrecord.cpp
@@ -11,23 +11,17 @@
QT_BEGIN_NAMESPACE
-class QSqlRecordPrivate
+class QSqlRecordPrivate : public QSharedData
{
public:
- QSqlRecordPrivate() = default;
- QSqlRecordPrivate(const QSqlRecordPrivate &other)
- : fields(other.fields)
- {
- }
-
inline bool contains(qsizetype index) const
{
return index >= 0 && index < fields.size();
}
QList<QSqlField> fields;
- QAtomicInt ref{1};
};
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QSqlRecordPrivate)
/*!
\class QSqlRecord
@@ -81,11 +75,8 @@ QSqlRecord::QSqlRecord()
of a record in \l{constant time}.
*/
-QSqlRecord::QSqlRecord(const QSqlRecord& other)
- : d(other.d)
-{
- d->ref.ref();
-}
+QSqlRecord::QSqlRecord(const QSqlRecord &other)
+ = default;
/*!
\fn QSqlRecord::QSqlRecord(QSqlRecord &&other)
@@ -125,21 +116,16 @@ QSqlRecord::QSqlRecord(const QSqlRecord& other)
of a record in \l{constant time}.
*/
-QSqlRecord& QSqlRecord::operator=(const QSqlRecord& other)
-{
- QSqlRecord(other).swap(*this);
- return *this;
-}
+QSqlRecord& QSqlRecord::operator=(const QSqlRecord &other)
+ = default;
/*!
Destroys the object and frees any allocated resources.
*/
QSqlRecord::~QSqlRecord()
-{
- if (d && !d->ref.deref())
- delete d;
-}
+ = default;
+
/*!
\fn bool QSqlRecord::operator!=(const QSqlRecord &other) const
@@ -176,14 +162,21 @@ QVariant QSqlRecord::value(int index) const
/*!
\overload
+*/
+QVariant QSqlRecord::value(const QString &name) const
+{
+ return value(QStringView(name));
+}
+
+/*!
+ \overload
Returns the value of the field called \a name in the record. If
field \a name does not exist an invalid variant is returned.
- \sa indexOf()
+ \sa indexOf(), isNull()
*/
-
-QVariant QSqlRecord::value(const QString& name) const
+QVariant QSqlRecord::value(QStringView name) const
{
return value(indexOf(name));
}
@@ -201,15 +194,22 @@ QString QSqlRecord::fieldName(int index) const
}
/*!
+ \overload
+*/
+int QSqlRecord::indexOf(const QString &name) const
+{
+ return indexOf(QStringView(name));
+}
+
+/*!
Returns the position of the field called \a name within the
record, or -1 if it cannot be found. Field names are not
case-sensitive. If more than one field matches, the first one is
returned.
\sa fieldName()
-*/
-
-int QSqlRecord::indexOf(const QString& name) const
+ */
+int QSqlRecord::indexOf(QStringView name) const
{
QStringView tableName;
QStringView fieldName(name);
@@ -243,11 +243,23 @@ QSqlField QSqlRecord::field(int index) const
return d->fields.value(index);
}
-/*! \overload
- Returns the field called \a name.
+/*!
+ \overload
*/
QSqlField QSqlRecord::field(const QString &name) const
{
+ return field(QStringView(name));
+}
+
+/*!
+ \overload
+
+ Returns the field called \a name. If the field called
+ \a name is not found, function returns
+ a \l{default-constructed value}.
+ */
+QSqlField QSqlRecord::field(QStringView name) const
+{
return field(indexOf(name));
}
@@ -258,7 +270,7 @@ QSqlField QSqlRecord::field(const QString &name) const
\sa insert(), replace(), remove()
*/
-void QSqlRecord::append(const QSqlField& field)
+void QSqlRecord::append(const QSqlField &field)
{
detach();
d->fields.append(field);
@@ -269,7 +281,7 @@ void QSqlRecord::append(const QSqlField& field)
\sa append(), replace(), remove()
*/
-void QSqlRecord::insert(int pos, const QSqlField& field)
+void QSqlRecord::insert(int pos, const QSqlField &field)
{
detach();
d->fields.insert(pos, field);
@@ -282,7 +294,7 @@ void QSqlRecord::insert(int pos, const QSqlField& field)
\sa append(), insert(), remove()
*/
-void QSqlRecord::replace(int pos, const QSqlField& field)
+void QSqlRecord::replace(int pos, const QSqlField &field)
{
if (!d->contains(pos))
return;
@@ -333,11 +345,18 @@ bool QSqlRecord::isEmpty() const
/*!
+ \overload
+*/
+bool QSqlRecord::contains(const QString &name) const
+{
+ return contains(QStringView(name));
+}
+
+/*!
Returns \c true if there is a field in the record called \a name;
otherwise returns \c false.
*/
-
-bool QSqlRecord::contains(const QString& name) const
+bool QSqlRecord::contains(QStringView name) const
{
return indexOf(name) >= 0;
}
@@ -357,6 +376,13 @@ void QSqlRecord::clearValues()
}
/*!
+ \overload
+*/
+void QSqlRecord::setGenerated(const QString &name, bool generated)
+{
+ setGenerated(QStringView(name), generated);
+}
+/*!
Sets the generated flag for the field called \a name to \a
generated. If the field does not exist, nothing happens. Only
fields that have \a generated set to true are included in the SQL
@@ -364,15 +390,12 @@ void QSqlRecord::clearValues()
\sa isGenerated()
*/
-
-void QSqlRecord::setGenerated(const QString& name, bool generated)
+void QSqlRecord::setGenerated(QStringView name, bool generated)
{
setGenerated(indexOf(name), generated);
}
/*!
- \overload
-
Sets the generated flag for the field \a index to \a generated.
\sa isGenerated()
@@ -387,10 +410,10 @@ void QSqlRecord::setGenerated(int index, bool generated)
}
/*!
- \overload
-
Returns \c true if the field \a index is null or if there is no field at
position \a index; otherwise returns \c false.
+
+ \sa setNull()
*/
bool QSqlRecord::isNull(int index) const
{
@@ -398,12 +421,22 @@ bool QSqlRecord::isNull(int index) const
}
/*!
+ \overload
+*/
+bool QSqlRecord::isNull(const QString &name) const
+{
+ return isNull(QStringView(name));
+}
+
+/*!
+ \overload
+
Returns \c true if the field called \a name is null or if there is no
field called \a name; otherwise returns \c false.
\sa setNull()
*/
-bool QSqlRecord::isNull(const QString& name) const
+bool QSqlRecord::isNull(QStringView name) const
{
return isNull(indexOf(name));
}
@@ -424,29 +457,45 @@ void QSqlRecord::setNull(int index)
/*!
\overload
+*/
+void QSqlRecord::setNull(const QString &name)
+{
+ setNull(QStringView(name));
+}
+
+/*!
+ \overload
Sets the value of the field called \a name to null. If the field
does not exist, nothing happens.
*/
-void QSqlRecord::setNull(const QString& name)
+void QSqlRecord::setNull(QStringView name)
{
setNull(indexOf(name));
}
+/*!
+ \overload
+*/
+bool QSqlRecord::isGenerated(const QString &name) const
+{
+ return isGenerated(QStringView(name));
+}
/*!
+ \overload
+
Returns \c true if the record has a field called \a name and this
field is to be generated (the default); otherwise returns \c false.
\sa setGenerated()
*/
-bool QSqlRecord::isGenerated(const QString& name) const
+bool QSqlRecord::isGenerated(QStringView name) const
{
return isGenerated(indexOf(name));
}
-/*! \overload
-
+/*!
Returns \c true if the record has a field at position \a index and this
field is to be generated (the default); otherwise returns \c false.
@@ -475,7 +524,7 @@ int QSqlRecord::count() const
\sa setNull()
*/
-void QSqlRecord::setValue(int index, const QVariant& val)
+void QSqlRecord::setValue(int index, const QVariant &val)
{
if (!d->contains(index))
return;
@@ -483,15 +532,22 @@ void QSqlRecord::setValue(int index, const QVariant& val)
d->fields[index].setValue(val);
}
-
+/*!
+ \overload
+*/
+void QSqlRecord::setValue(const QString &name, const QVariant &val)
+{
+ setValue(QStringView(name), val);
+}
/*!
\overload
Sets the value of the field called \a name to \a val. If the field
does not exist, nothing happens.
-*/
-void QSqlRecord::setValue(const QString& name, const QVariant& val)
+ \sa setNull()
+*/
+void QSqlRecord::setValue(QStringView name, const QVariant &val)
{
setValue(indexOf(name), val);
}
@@ -501,7 +557,7 @@ void QSqlRecord::setValue(const QString& name, const QVariant& val)
*/
void QSqlRecord::detach()
{
- qAtomicDetach(d);
+ d.detach();
}
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/sql/kernel/qsqlrecord.h b/src/sql/kernel/qsqlrecord.h
index 76e6ee982d..8f653ba5e1 100644
--- a/src/sql/kernel/qsqlrecord.h
+++ b/src/sql/kernel/qsqlrecord.h
@@ -5,6 +5,7 @@
#define QSQLRECORD_H
#include <QtSql/qtsqlglobal.h>
+#include <QtCore/qshareddata.h>
#include <QtCore/qstring.h>
QT_BEGIN_NAMESPACE
@@ -13,51 +14,60 @@ QT_BEGIN_NAMESPACE
class QSqlField;
class QVariant;
class QSqlRecordPrivate;
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QSqlRecordPrivate, Q_SQL_EXPORT)
class Q_SQL_EXPORT QSqlRecord
{
public:
QSqlRecord();
- QSqlRecord(const QSqlRecord& other);
- QSqlRecord(QSqlRecord &&other) noexcept
- : d{std::exchange(other.d, nullptr)} {}
- QSqlRecord& operator=(const QSqlRecord& other);
+ QSqlRecord(const QSqlRecord &other);
+ QSqlRecord(QSqlRecord &&other) noexcept = default;
+ QSqlRecord& operator=(const QSqlRecord &other);
QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QSqlRecord)
~QSqlRecord();
- void swap(QSqlRecord &other) noexcept { qt_ptr_swap(d, other.d); }
+ void swap(QSqlRecord &other) noexcept { d.swap(other.d); }
bool operator==(const QSqlRecord &other) const;
inline bool operator!=(const QSqlRecord &other) const { return !operator==(other); }
QVariant value(int i) const;
- QVariant value(const QString& name) const;
- void setValue(int i, const QVariant& val);
- void setValue(const QString& name, const QVariant& val);
+ QVariant value(const QString &name) const;
+ QVariant value(QStringView name) const;
+ void setValue(int i, const QVariant &val);
+ void setValue(const QString &name, const QVariant &val);
+ void setValue(QStringView name, const QVariant &val);
void setNull(int i);
- void setNull(const QString& name);
+ void setNull(const QString &name);
+ void setNull(QStringView name);
bool isNull(int i) const;
- bool isNull(const QString& name) const;
+ bool isNull(const QString &name) const;
+ bool isNull(QStringView name) const;
int indexOf(const QString &name) const;
+ int indexOf(QStringView name) const;
QString fieldName(int i) const;
QSqlField field(int i) const;
QSqlField field(const QString &name) const;
+ QSqlField field(QStringView name) const;
bool isGenerated(int i) const;
- bool isGenerated(const QString& name) const;
- void setGenerated(const QString& name, bool generated);
+ bool isGenerated(const QString &name) const;
+ bool isGenerated(QStringView name) const;
+ void setGenerated(const QString &name, bool generated);
+ void setGenerated(QStringView name, bool generated);
void setGenerated(int i, bool generated);
- void append(const QSqlField& field);
- void replace(int pos, const QSqlField& field);
- void insert(int pos, const QSqlField& field);
+ void append(const QSqlField &field);
+ void replace(int pos, const QSqlField &field);
+ void insert(int pos, const QSqlField &field);
void remove(int pos);
bool isEmpty() const;
- bool contains(const QString& name) const;
+ bool contains(const QString &name) const;
+ bool contains(QStringView name) const;
void clear();
void clearValues();
int count() const;
@@ -65,9 +75,11 @@ public:
private:
void detach();
- QSqlRecordPrivate* d;
+ QExplicitlySharedDataPointer<QSqlRecordPrivate> d;
};
+Q_DECLARE_SHARED(QSqlRecord)
+
#ifndef QT_NO_DEBUG_STREAM
Q_SQL_EXPORT QDebug operator<<(QDebug, const QSqlRecord &);
#endif
diff --git a/src/sql/kernel/qsqlresult.cpp b/src/sql/kernel/qsqlresult.cpp
index fb8bc3a1e5..59e9879cf0 100644
--- a/src/sql/kernel/qsqlresult.cpp
+++ b/src/sql/kernel/qsqlresult.cpp
@@ -37,6 +37,9 @@ static bool qIsAlnum(QChar ch)
QString QSqlResultPrivate::positionalToNamedBinding(const QString &query) const
{
+ if (!positionalBindingEnabled)
+ return query;
+
const qsizetype n = query.size();
QString result;
@@ -92,6 +95,7 @@ QString QSqlResultPrivate::namedToPositionalBinding(const QString &query)
int count = 0;
qsizetype i = 0;
bool ignoreBraces = (sqldriver->dbmsType() == QSqlDriver::PostgreSQL);
+ const bool qmarkNotationSupported = (sqldriver->dbmsType() != QSqlDriver::PostgreSQL);
while (i < n) {
QChar ch = query.at(i);
@@ -115,10 +119,16 @@ QString QSqlResultPrivate::namedToPositionalBinding(const QString &query)
int pos = i + 2;
while (pos < n && qIsAlnum(query.at(pos)))
++pos;
+ // if question mark notation is not supported we have to use
+ // the native binding. fieldSerial() should be renamed
+ // to toNativeBinding() and used unconditionally here
+ if (qmarkNotationSupported)
+ result += u'?';
+ else
+ result += fieldSerial(count);
QString holder(query.mid(i, pos - i));
indexes[holder].append(count++);
holders.append(QHolder(holder, i));
- result += u'?';
i = pos;
} else {
if (ch == u'\'' || ch == u'"' || ch == u'`')
@@ -784,17 +794,32 @@ int QSqlResult::boundValueCount() const
}
/*!
- Returns a vector of the result's bound values for the current
+ Returns a list of the result's bound values for the current
record (row).
\sa boundValueCount()
*/
-QList<QVariant> &QSqlResult::boundValues() const
+QVariantList QSqlResult::boundValues(QT6_IMPL_NEW_OVERLOAD) const
{
Q_D(const QSqlResult);
- return const_cast<QSqlResultPrivate *>(d)->values;
+ return d->values;
+}
+
+/*!
+ \overload
+
+ Returns a mutable reference to the list of the result's bound values
+ for the current record (row).
+
+ \sa boundValueCount()
+*/
+QVariantList &QSqlResult::boundValues(QT6_IMPL_NEW_OVERLOAD)
+{
+ Q_D(QSqlResult);
+ return d->values;
}
+
/*!
Returns the binding syntax used by prepared queries.
*/
@@ -838,10 +863,24 @@ void QSqlResult::resetBindCount()
}
/*!
+ Returns the names of all bound values.
+
+ \sa boundValue(), boundValueName()
+ */
+QStringList QSqlResult::boundValueNames() const
+{
+ Q_D(const QSqlResult);
+ QList<QString> ret;
+ for (const QHolder &holder : std::as_const(d->holders))
+ ret.push_back(holder.holderName);
+ return ret;
+}
+
+/*!
Returns the name of the bound value at position \a index in the
current record (row).
- \sa boundValue()
+ \sa boundValue(), boundValueNames()
*/
QString QSqlResult::boundValueName(int index) const
{
@@ -907,8 +946,6 @@ void QSqlResult::virtual_hook(int, void *)
}
/*! \internal
- \since 4.2
-
Executes a prepared query in batch mode if the driver supports it,
otherwise emulates a batch execution using bindValue() and exec().
QSqlDriver::hasFeature() can be used to find out whether a driver
@@ -976,6 +1013,23 @@ QSql::NumericalPrecisionPolicy QSqlResult::numericalPrecisionPolicy() const
}
/*! \internal
+ */
+void QSqlResult::setPositionalBindingEnabled(bool enable)
+{
+ Q_D(QSqlResult);
+ d->positionalBindingEnabled = enable;
+}
+
+/*! \internal
+ */
+bool QSqlResult::isPositionalBindingEnabled() const
+{
+ Q_D(const QSqlResult);
+ return d->positionalBindingEnabled;
+}
+
+
+/*! \internal
*/
bool QSqlResult::nextResult()
{
diff --git a/src/sql/kernel/qsqlresult.h b/src/sql/kernel/qsqlresult.h
index 2d157cbe87..4200bbde34 100644
--- a/src/sql/kernel/qsqlresult.h
+++ b/src/sql/kernel/qsqlresult.h
@@ -8,9 +8,6 @@
#include <QtCore/qvariant.h>
#include <QtCore/qcontainerfwd.h>
-// for testing:
-class tst_QSqlQuery;
-
QT_BEGIN_NAMESPACE
@@ -26,8 +23,6 @@ class Q_SQL_EXPORT QSqlResult
Q_DECLARE_PRIVATE(QSqlResult)
friend class QSqlQuery;
friend class QSqlTableModelPrivate;
- // for testing:
- friend class ::tst_QSqlQuery;
public:
virtual ~QSqlResult();
@@ -69,8 +64,14 @@ protected:
QSql::ParamType bindValueType(const QString& placeholder) const;
QSql::ParamType bindValueType(int pos) const;
int boundValueCount() const;
+#if QT_SQL_REMOVED_SINCE(6, 6)
QList<QVariant> &boundValues() const;
+#endif
+ QVariantList &boundValues(QT6_DECL_NEW_OVERLOAD);
+ QVariantList boundValues(QT6_DECL_NEW_OVERLOAD) const;
+
QString executedQuery() const;
+ QStringList boundValueNames() const;
QString boundValueName(int pos) const;
void clear();
bool hasOutValues() const;
@@ -96,6 +97,8 @@ protected:
virtual void detachFromResultSet();
virtual void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy policy);
QSql::NumericalPrecisionPolicy numericalPrecisionPolicy() const;
+ void setPositionalBindingEnabled(bool enable);
+ bool isPositionalBindingEnabled() const;
virtual bool nextResult();
void resetBindCount(); // HACK
diff --git a/src/sql/kernel/qsqlresult_p.h b/src/sql/kernel/qsqlresult_p.h
index 1e8e8a3033..6eebdaaba4 100644
--- a/src/sql/kernel/qsqlresult_p.h
+++ b/src/sql/kernel/qsqlresult_p.h
@@ -98,6 +98,7 @@ public:
bool active = false;
bool isSel = false;
bool forwardOnly = false;
+ bool positionalBindingEnabled = true;
static bool isVariantNull(const QVariant &variant);
};
diff --git a/src/sql/kernel/qtsqlglobal.h b/src/sql/kernel/qtsqlglobal.h
index b01010d653..977d97abbf 100644
--- a/src/sql/kernel/qtsqlglobal.h
+++ b/src/sql/kernel/qtsqlglobal.h
@@ -6,7 +6,6 @@
#if 0
#pragma qt_class(QSql)
-#pragma qt_deprecates(qsql.h)
#endif
#include <QtCore/qglobal.h>
diff --git a/src/sql/models/qsqlquerymodel.cpp b/src/sql/models/qsqlquerymodel.cpp
index 0a7470d5c8..6f91fb9739 100644
--- a/src/sql/models/qsqlquerymodel.cpp
+++ b/src/sql/models/qsqlquerymodel.cpp
@@ -139,8 +139,6 @@ QSqlQueryModel::~QSqlQueryModel()
}
/*!
- \since 4.1
-
Fetches more rows from a database.
This only affects databases that don't report back the size of a query
(see QSqlDriver::hasFeature()).
@@ -162,8 +160,6 @@ void QSqlQueryModel::fetchMore(const QModelIndex &parent)
}
/*!
- \since 4.1
-
Returns \c true if it is possible to read more rows from the database.
This only affects databases that don't report back the size of a query
(see QSqlDriver::hasFeature()).
@@ -295,7 +291,6 @@ void QSqlQueryModel::endResetModel()
}
/*! \fn int QSqlQueryModel::rowCount(const QModelIndex &parent) const
- \since 4.1
If the database supports returning the size of a query
(see QSqlDriver::hasFeature()), the number of rows of the current
@@ -388,8 +383,6 @@ void QSqlQueryModel::queryChange()
/*!
\deprecated [6.2] Use the \c{setQuery(QSqlQuery &&query)} overload instead.
\overload
- \since 4.5
-
*/
void QSqlQueryModel::setQuery(const QSqlQuery &query)
{
diff --git a/src/sql/models/qsqlrelationaltablemodel.cpp b/src/sql/models/qsqlrelationaltablemodel.cpp
index 88a08516a3..c086d88ffe 100644
--- a/src/sql/models/qsqlrelationaltablemodel.cpp
+++ b/src/sql/models/qsqlrelationaltablemodel.cpp
@@ -559,6 +559,7 @@ QString QSqlRelationalTableModel::selectStatement() const
QString alias = QString::fromLatin1("%1_%2_%3")
.arg(relTableName, displayColumn, QString::number(fieldNames.value(fieldList[i])));
alias.truncate(d->db.driver()->maximumIdentifierLength(QSqlDriver::FieldName));
+ alias = d->db.driver()->escapeIdentifier(alias, QSqlDriver::FieldName);
displayTableField = SqlrTm::as(displayTableField, alias);
--fieldNames[fieldList[i]];
}
@@ -643,7 +644,6 @@ void QSqlRelationalTableModel::clear()
\value LeftJoin - Left join mode, returns all rows from the left table (table_name1), even if there are no matches in the right table (table_name2).
\sa QSqlRelationalTableModel::setJoinMode()
- \since 4.8
*/
/*!
@@ -652,7 +652,6 @@ void QSqlRelationalTableModel::clear()
LeftJoin mode if you want to show them.
\sa QSqlRelationalTableModel::JoinMode
- \since 4.8
*/
void QSqlRelationalTableModel::setJoinMode( QSqlRelationalTableModel::JoinMode joinMode )
{
diff --git a/src/sql/models/qsqltablemodel.cpp b/src/sql/models/qsqltablemodel.cpp
index 989904c8a1..265d7782a0 100644
--- a/src/sql/models/qsqltablemodel.cpp
+++ b/src/sql/models/qsqltablemodel.cpp
@@ -205,7 +205,7 @@ bool QSqlTableModelPrivate::exec(const QString &stmt, bool prepStatement,
want to resolve foreign keys.
\sa QSqlRelationalTableModel, QSqlQuery, {Model/View Programming},
- {Table Model Example}, {Cached Table Example}
+ {Table Model Example}, {Cached SQL Table}
*/
/*!
diff --git a/src/testlib/3rdparty/linux_perf_event_p.h b/src/testlib/3rdparty/linux_perf_event_p.h
index 03b3700627..6f034f0e96 100644
--- a/src/testlib/3rdparty/linux_perf_event_p.h
+++ b/src/testlib/3rdparty/linux_perf_event_p.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
/*
* Performance events:
*
diff --git a/src/testlib/3rdparty/qt_attribution.json b/src/testlib/3rdparty/qt_attribution.json
index 08a5bcf1ec..77f58e7d75 100644
--- a/src/testlib/3rdparty/qt_attribution.json
+++ b/src/testlib/3rdparty/qt_attribution.json
@@ -4,16 +4,18 @@
"Name": "Valgrind",
"QDocModule": "qttestlib",
"QtUsage": "Used on Linux ond MacOS in the Qt Test module.",
- "Files": "valgrind_p.h callgrind_p.h",
+ "Comment": { "UpstreamFiles": [ "include/valgrind.h.in", "callgrind/callgrind.h" ],
+ "License": "These two files are BSD; the rest of valgrind is GPL" },
+ "Files": [ "valgrind_p.h", "callgrind_p.h" ],
"Description": "An instrumentation framework for building dynamic analysis tools.",
"Homepage": "http://valgrind.org/",
- "Version": "3.20.0",
+ "Version": "3.22.0",
"License": "BSD 4-clause \"Original\" or \"Old\" License",
"LicenseId": "BSD-4-Clause",
"LicenseFile": "VALGRIND_LICENSE.txt",
- "Copyright": "Copyright (C) 2000-2017 Julian Seward
-Copyright (C) 2003-2017 Josef Weidendorfer."
+ "Copyright": ["Copyright (C) 2000-2017 Julian Seward",
+ "Copyright (C) 2003-2017 Josef Weidendorfer."]
},
{
"Id": "cycle",
@@ -26,8 +28,8 @@ Copyright (C) 2003-2017 Josef Weidendorfer."
"License": "MIT License",
"LicenseId": "MIT",
"LicenseFile": "CYCLE_LICENSE.txt",
- "Copyright": "Copyright (c) 2003, 2006 Matteo Frigo
-Copyright (c) 2003, 2006 Massachusetts Institute of Technology"
+ "Copyright": ["Copyright (c) 2003, 2006 Matteo Frigo",
+ "Copyright (c) 2003, 2006 Massachusetts Institute of Technology"]
},
{
"Id": "linuxperf",
@@ -40,10 +42,10 @@ Copyright (c) 2003, 2006 Massachusetts Institute of Technology"
"Homepage": "https://www.kernel.org",
"Version": "3.7",
"License": "GNU General Public License v2.0 only with Linux Syscall Note",
- "LicenseId": "GPL-2.0 WITH Linux-syscall-note",
+ "LicenseId": "GPL-2.0-only WITH Linux-syscall-note",
"LicenseFile": "LINUX_LICENSE.txt",
- "Copyright": "Copyright (C) 2008-2009, Thomas Gleixner <tglx@linutronix.de>
-Copyright (C) 2008-2011, Red Hat, Inc., Ingo Molnar
-Copyright (C) 2008-2011, Red Hat, Inc., Peter Zijlstra"
+ "Copyright": ["Copyright (C) 2008-2009, Thomas Gleixner <tglx@linutronix.de>",
+ "Copyright (C) 2008-2011, Red Hat, Inc., Ingo Molnar",
+ "Copyright (C) 2008-2011, Red Hat, Inc., Peter Zijlstra"]
}
]
diff --git a/src/testlib/3rdparty/valgrind_p.h b/src/testlib/3rdparty/valgrind_p.h
index 3aaa76746c..f5e5518265 100644
--- a/src/testlib/3rdparty/valgrind_p.h
+++ b/src/testlib/3rdparty/valgrind_p.h
@@ -4748,7 +4748,7 @@ typedef
"lgr 1,%1\n\t" /* copy the argvec pointer in r1 */ \
"lgr 7,11\n\t" \
"lgr 11,%2\n\t" \
- ".cfi_def_cfa r11, 0\n\t"
+ ".cfi_def_cfa 11, 0\n\t"
# define VALGRIND_CFI_EPILOGUE \
"lgr 11, 7\n\t" \
".cfi_restore_state\n\t"
diff --git a/src/testlib/CMakeLists.txt b/src/testlib/CMakeLists.txt
index 6cdb8f3376..e956a47cf1 100644
--- a/src/testlib/CMakeLists.txt
+++ b/src/testlib/CMakeLists.txt
@@ -13,6 +13,7 @@ qt_internal_add_module(Test
EXCEPTIONS
SOURCES
3rdparty/cycle_p.h
+ removed_api.cpp # keep first
qabstracttestlogger.cpp qabstracttestlogger_p.h
qasciikey.cpp
qbenchmark.cpp qbenchmark.h qbenchmark_p.h
@@ -21,13 +22,14 @@ qt_internal_add_module(Test
qbenchmarkmetric.cpp qbenchmarkmetric.h qbenchmarkmetric_p.h
qbenchmarkperfevents.cpp qbenchmarkperfevents_p.h
qbenchmarktimemeasurers_p.h
+ qcomparisontesthelper.cpp qcomparisontesthelper_p.h
qcsvbenchmarklogger.cpp qcsvbenchmarklogger_p.h
qemulationdetector_p.h
qjunittestlogger.cpp qjunittestlogger_p.h
qplaintestlogger.cpp qplaintestlogger_p.h
qpropertytesthelper_p.h
qsignaldumper.cpp qsignaldumper_p.h
- qsignalspy.h
+ qsignalspy.cpp qsignalspy.h
qtaptestlogger.cpp qtaptestlogger_p.h
qteamcitylogger.cpp qteamcitylogger_p.h
qtest.h
@@ -39,6 +41,7 @@ qt_internal_add_module(Test
qtestblacklist.cpp qtestblacklist_p.h
qtestcase.cpp qtestcase.h qtestcase_p.h
qtestcoreelement_p.h
+ qtestcrashhandler.cpp qtestcrashhandler_p.h
qtestdata.cpp qtestdata.h
qtestelement.cpp qtestelement_p.h
qtestelementattribute.cpp qtestelementattribute_p.h
@@ -54,25 +57,35 @@ qt_internal_add_module(Test
qtestsystem.h
qtesttable.cpp qtesttable_p.h
qtesttouch.h
+ qtesttostring.h
+ qtestwheel.h
qttestglobal.h
qxmltestlogger.cpp qxmltestlogger_p.h
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
+ QT_NO_CONTEXTLESS_CONNECT
QT_NO_DATASTREAM
QT_NO_FOREACH
+ QT_USE_NODISCARD_FILE_OPEN
# Ensure uniform location info between release and debug builds
QT_NO_MESSAGELOGCONTEXT
LIBRARIES
Qt::CorePrivate
+ NO_PCH_SOURCES
+ removed_api.cpp
PUBLIC_LIBRARIES
Qt::Core
PRIVATE_MODULE_INTERFACE
Qt::CorePrivate
GENERATE_CPP_EXPORTS
- GENERATE_PRIVATE_CPP_EXPORTS
)
+if(TARGET Gui)
+ set_property(TARGET Test
+ APPEND PROPERTY _qt_internal_sync_headers_deps Gui_sync_headers)
+endif()
+
## Scopes:
#####################################################################
diff --git a/src/testlib/doc/qttestlib.qdocconf b/src/testlib/doc/qttestlib.qdocconf
index 4330fe197a..8b245a864f 100644
--- a/src/testlib/doc/qttestlib.qdocconf
+++ b/src/testlib/doc/qttestlib.qdocconf
@@ -56,5 +56,5 @@ manifestmeta.thumbnail.names = "QtTestLib/Chapter *"
navigation.landingpage = "Qt Test"
navigation.cppclassespage = "Qt Test C++ Classes"
-# Fail the documentation build if there are more warnings than the limit
+# Enforce zero documentation warnings
warninglimit = 0
diff --git a/src/testlib/doc/snippets/CMakeLists.txt b/src/testlib/doc/snippets/CMakeLists.txt
index 0982732843..77e4781c44 100644
--- a/src/testlib/doc/snippets/CMakeLists.txt
+++ b/src/testlib/doc/snippets/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#! [cmake_use]
find_package(Qt6 REQUIRED COMPONENTS Test)
diff --git a/src/testlib/doc/snippets/code/CMakeLists.txt b/src/testlib/doc/snippets/code/CMakeLists.txt
index 86057acde2..54c655a521 100644
--- a/src/testlib/doc/snippets/code/CMakeLists.txt
+++ b/src/testlib/doc/snippets/code/CMakeLists.txt
@@ -1,9 +1,8 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
add_library(testlib_code_snippets OBJECT
doc_src_qtqskip.cpp
- doc_src_qttest.cpp
src_corelib_kernel_qtestsupport_core.cpp
)
diff --git a/src/testlib/doc/snippets/code/doc_src_cmakelists.txt b/src/testlib/doc/snippets/code/doc_src_cmakelists.txt
index 6e19597775..946f09c09f 100644
--- a/src/testlib/doc/snippets/code/doc_src_cmakelists.txt
+++ b/src/testlib/doc/snippets/code/doc_src_cmakelists.txt
@@ -8,7 +8,7 @@ set(CMAKE_AUTOMOC ON)
enable_testing(true)
-add_executable(mytest tst_mytest.cpp)
+qt_add_executable(mytest tst_mytest.cpp)
add_test(NAME mytest COMMAND mytest)
target_link_libraries(mytest PRIVATE Qt::Test)
diff --git a/src/testlib/doc/snippets/code/doc_src_qsignalspy.cpp b/src/testlib/doc/snippets/code/doc_src_qsignalspy.cpp
index 20459f9eb4..99760ea730 100644
--- a/src/testlib/doc/snippets/code/doc_src_qsignalspy.cpp
+++ b/src/testlib/doc/snippets/code/doc_src_qsignalspy.cpp
@@ -43,9 +43,6 @@ SomeStruct result = qvariant_cast<SomeStruct>(spy.at(0).at(0));
QSignalSpy spy(myPushButton, SIGNAL(clicked(bool)));
//! [4]
-//! [5]
-QVERIFY(spy.wait(1000));
-//! [5]
//! [6]
QSignalSpy spy(myPushButton, &QPushButton::clicked);
diff --git a/src/testlib/doc/snippets/code/doc_src_qtestlib.qdoc b/src/testlib/doc/snippets/code/doc_src_qtestlib.qdoc
index 10d9cb5bee..9b592bdb6a 100644
--- a/src/testlib/doc/snippets/code/doc_src_qtestlib.qdoc
+++ b/src/testlib/doc/snippets/code/doc_src_qtestlib.qdoc
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
//! [2]
testname [options] [testfunctions[:testdata]]...
diff --git a/src/testlib/doc/snippets/code/doc_src_qttest.cpp b/src/testlib/doc/snippets/code/doc_src_qttest.cpp
deleted file mode 100644
index 06b4588268..0000000000
--- a/src/testlib/doc/snippets/code/doc_src_qttest.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-//! [0]
-#include <QTest>
-//! [0]
diff --git a/src/testlib/doc/snippets/code/src_corelib_kernel_qtestsupport_core.cpp b/src/testlib/doc/snippets/code/src_corelib_kernel_qtestsupport_core.cpp
index 906a88b20f..7faf40d9b7 100644
--- a/src/testlib/doc/snippets/code/src_corelib_kernel_qtestsupport_core.cpp
+++ b/src/testlib/doc/snippets/code/src_corelib_kernel_qtestsupport_core.cpp
@@ -5,8 +5,9 @@
// dummy class
class MyObject
{
- public:
- int isReady();
+public:
+ int isReady();
+ void startup() {}
};
// dummy function
@@ -18,9 +19,22 @@ int myNetworkServerNotResponding()
int MyObject::isReady()
{
//! [1]
+ using namespace std::chrono_literals;
int i = 0;
while (myNetworkServerNotResponding() && i++ < 50)
- QTest::qWait(250);
+ QTest::qWait(250ms);
//! [1]
return 1;
}
+
+[[maybe_unused]] static bool startup()
+{
+//! [2]
+ MyObject obj;
+ obj.startup();
+ using namespace std::chrono_literals;
+ const bool result = QTest::qWaitFor([&obj]() { return obj.isReady(); },
+ QDeadlineTimer(3s));
+//! [2]
+ return result;
+}
diff --git a/src/testlib/doc/snippets/code/src_corelib_kernel_qtestsupport_core_snippet.cpp b/src/testlib/doc/snippets/code/src_corelib_kernel_qtestsupport_core_snippet.cpp
deleted file mode 100644
index f2ba321a67..0000000000
--- a/src/testlib/doc/snippets/code/src_corelib_kernel_qtestsupport_core_snippet.cpp
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright (C) 2020 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-//! [0]
- MyObject obj;
- obj.startup();
- QTest::qWaitFor([&]() {
- return obj.isReady();
- }, 3000);
-//! [0]
diff --git a/src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp b/src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp
index 532b26b4f1..4716d06e55 100644
--- a/src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp
+++ b/src/testlib/doc/snippets/code/src_qtestlib_qtestcase.cpp
@@ -170,10 +170,11 @@ void MyTestClass::cleanup()
}
//! [22]
-void mySleep()
+void quarterSecondSleep()
{
//! [23]
-QTest::qSleep(250);
+using namespace std::chrono_literals;
+QTest::qSleep(250ms);
//! [23]
}
diff --git a/src/testlib/doc/src/qt6-changes.qdoc b/src/testlib/doc/src/qt6-changes.qdoc
index 03a5c8db03..77e7b04afd 100644
--- a/src/testlib/doc/src/qt6-changes.qdoc
+++ b/src/testlib/doc/src/qt6-changes.qdoc
@@ -5,7 +5,7 @@
\page testlib-changes-qt6.html
\title Changes to Qt Test
\ingroup changes-qt-5-to-6
- \brief Migrate Qt Test to Qt 6.
+ \brief Touch-related functionality changes.
Qt 6 is a result of the conscious effort to make the framework more
efficient and easy to use.
diff --git a/src/testlib/doc/src/qttest-best-practices.qdoc b/src/testlib/doc/src/qttest-best-practices.qdoc
index 54a51f4ace..cea5b3a8de 100644
--- a/src/testlib/doc/src/qttest-best-practices.qdoc
+++ b/src/testlib/doc/src/qttest-best-practices.qdoc
@@ -180,14 +180,19 @@
\section2 Select Appropriate Mechanisms to Exclude Tests
It is important to select the appropriate mechanism to exclude inapplicable
- tests: \l QSKIP(), using conditional statements to exclude parts of a test
- function, or not building the test for a particular platform.
-
- Use QSKIP() to handle cases where a whole test function is found at run-time
- to be inapplicable in the current test environment. When just a part of a
- test function is to be skipped, a conditional statement can be used,
- optionally with a \c qDebug() call to report the reason for skipping the
- inapplicable part.
+ tests.
+
+ Use \l QSKIP() to handle cases where a whole test function is found at
+ run-time to be inapplicable in the current test environment. When just a
+ part of a test function is to be skipped, a conditional statement can be
+ used, optionally with a \c qDebug() call to report the reason for skipping
+ the inapplicable part.
+
+ When there are known test failures that should eventually be fixed,
+ \l QEXPECT_FAIL is recommended, as it supports running the rest of the
+ test, when possible. It also verifies that the issue still exists, and
+ lets the code's maintainer know if they unwittingly fix it, a benefit
+ which is gained even when using the \l {QTest::}{Abort} flag.
Test functions or data rows of a data-driven test can be limited to
particular platforms, or to particular features being enabled using
diff --git a/src/testlib/doc/src/qttestlib-manual.qdoc b/src/testlib/doc/src/qttestlib-manual.qdoc
index 2d89693d35..1b6f534045 100644
--- a/src/testlib/doc/src/qttestlib-manual.qdoc
+++ b/src/testlib/doc/src/qttestlib-manual.qdoc
@@ -348,6 +348,16 @@
Disables the crash handler on Unix platforms.
On Windows, it re-enables the Windows Error Reporting dialog, which is
turned off by default. This is useful for debugging crashes.
+ \li \c -repeat \e n \br
+ Run the testsuite n times or until the test fails. Useful for finding
+ flaky tests. If negative, the tests are repeated forever. This is intended
+ as a developer tool, and is only supported with the plain text logger.
+ \li \c -skipblacklisted \br
+ Skip the blacklisted tests. This option is intended to allow more accurate
+ measurement of test coverage by preventing blacklisted tests from inflating
+ coverage statistics. When not measuring test coverage, it is recommended to
+ execute blacklisted tests to reveal any changes in their results, such as
+ a new crash or the issue that caused blacklisting being resolved.
\li \c -platform \e name \br
This command line argument applies to all Qt applications, but might be
@@ -405,6 +415,12 @@
to e.g. debug an unstable or intermittent failure in a test, by
launching the test in a debugger. Support for this variable was
added in Qt 6.1.
+ \li \c QTEST_THROW_ON_FAIL (since 6.8) \br
+ Setting this variable to a non-zero value will cause QCOMPARE()/QVERIFY()
+ etc to throw on failure (as opposed to just returning from the
+ immediately-surrounding function scope).
+ \li \c QTEST_THROW_ON_SKIP (since 6.8) \br
+ Same as \c QTEST_THROW_ON_FAIL, except affecting QSKIP().
\endlist
\section1 Creating a Benchmark
@@ -573,477 +589,5 @@
\li \l {Chapter 6: Skipping Tests with QSKIP}{Skipping Tests}
\endlist
- \note You can build and execute the tests from each chapter using the
- available source code, which is linked to at the end of each chapter.
*/
-
-
-/*!
- \example tutorial1
-
- \previouspage {Qt Test Tutorial}{Qt Test Tutorial Overview}
- \nextpage {Chapter 2: Data Driven Testing}{Chapter 2}
-
- \title Chapter 1: Writing a Unit Test
- \brief How to write a unit test.
-
- This first chapter demonstrates how to write a simple unit test and how to
- run the test case as a stand-alone executable.
-
- \section1 Writing a Test
-
- Let's assume you want to test the behavior of our QString class.
- First, you need a class that contains your test functions. This class
- has to inherit from QObject:
-
- \snippet tutorial1/testqstring.cpp 0
-
- \note You need to include the QTest header and declare the test functions as
- private slots so the test framework finds and executes it.
-
- Then you need to implement the test function itself. The
- implementation could look like this:
-
- \snippet code/doc_src_qtestlib.cpp 8
-
- The \l QVERIFY() macro evaluates the expression passed as its
- argument. If the expression evaluates to true, the execution of
- the test function continues. Otherwise, a message describing the
- failure is appended to the test log, and the test function stops
- executing.
-
- But if you want a more verbose output to the test log, you should
- use the \l QCOMPARE() macro instead:
-
- \snippet tutorial1/testqstring.cpp 1
-
- If the strings are not equal, the contents of both strings are
- appended to the test log, making it immediately visible why the
- comparison failed.
-
- \section1 Preparing the Stand-Alone Executable
-
- Finally, to make our test case a stand-alone executable, the
- following two lines are needed:
-
- \snippet tutorial1/testqstring.cpp 2
-
- The \l QTEST_MAIN() macro expands to a simple \c main()
- method that runs all the test functions. Note that if both the
- declaration and the implementation of our test class are in a \c
- .cpp file, we also need to include the generated moc file to make
- Qt's introspection work.
-
- \section1 Building the Executable
-
- \include {building-examples.qdocinc} {building the executable} {tutorial1}
-
- \note If you're using windows, replace \c make with \c
- nmake or whatever build tool you use.
-
- \section1 Running the Executable
-
- Running the resulting executable should give you the following
- output:
-
- \snippet code/doc_src_qtestlib.qdoc 10
-
- Congratulations! You just wrote and executed your first unit test
- using the Qt Test framework.
-*/
-
-/*!
- \example tutorial2
-
- \previouspage {Chapter 1: Writing a Unit Test}{Chapter 1}
- \nextpage {Chapter 3: Simulating Gui Events}{Chapter 3}
-
- \title Chapter 2: Data Driven Testing
- \brief How to create data driven tests.
-
- This chapter demonstrates how to execute a test multiple times with
- different test data.
-
- So far, we have hard coded the data we wanted to test into our
- test function. If we add more test data, the function might look like
- this:
-
- \snippet code/doc_src_qtestlib.cpp 11
-
- To prevent the function from being cluttered with repetitive code, Qt Test
- supports adding test data to a test function. All we need is to add another
- private slot to our test class:
-
- \snippet tutorial2/testqstring.cpp 0
-
- \section1 Writing the Data Function
-
- A test function's associated data function has \c _data appended to its
- name. Our data function looks like this:
-
- \snippet tutorial2/testqstring.cpp 1
-
- First, we define the two elements of our test table using the \l
- QTest::addColumn() function: a test string and the
- expected result of applying the QString::toUpper() function to
- that string.
-
- Then, we add some data to the table using the \l QTest::newRow()
- function. We can also use \l QTest::addRow() if we need to format some data
- in the row name, for example when generating many data rows iteratively.
- Each row of data will become a separate row in the test table.
-
- \l QTest::newRow() takes one argument: a name that will be associated with
- the data set and used in the test log to identify the data row. \l
- QTest::addRow() takes a (\c{printf}-style) format string followed by the
- parameters to be represented in place of the formatting tokens in the format
- string. Then, we stream the data set into the new table row. First an
- arbitrary string, and then the expected result of applying the
- QString::toUpper() function to that string.
-
- You can think of the test data as a two-dimensional table. In
- our case, it has two columns called \c string and \c result and
- three rows. In addition, a name and an index are associated
- with each row:
-
- \table
- \header
- \li index
- \li name
- \li string
- \li result
- \row
- \li 0
- \li all-lower
- \li "hello"
- \li HELLO
- \row
- \li 1
- \li mixed
- \li "Hello"
- \li HELLO
- \row
- \li 2
- \li all-upper
- \li "HELLO"
- \li HELLO
- \endtable
-
- When data is streamed into the row, each datum is asserted to match
- the type of the column whose value it supplies. If any assertion fails,
- the test is aborted.
-
- The names of rows and columns, in a given test function's data table, should
- be unique: if two rows share a name, or two columns share a name, a warning
- will (since Qt 6.5) be produced. See \l qWarning() for how you can cause
- warnings to be treated as errors and \l {Test for Warnings} for how to get
- your tests clear of other warnings.
-
- \section1 Rewriting the Test Function
-
- Our test function can now be rewritten:
-
- \snippet tutorial2/testqstring.cpp 2
-
- The TestQString::toUpper() function will be executed three times,
- once for each entry in the test table that we created in the
- associated TestQString::toUpper_data() function.
-
- First, we fetch the two elements of the data set using the \l
- QFETCH() macro. \l QFETCH() takes two arguments: The data type of
- the element and the element name. Then, we perform the test using
- the \l QCOMPARE() macro.
-
- This approach makes it very easy to add new data to the test
- without modifying the test itself.
-
- \section1 Preparing the Stand-Alone Executable
-
- And again, to make our test case a stand-alone executable,
- the following two lines are needed:
-
- \snippet tutorial2/testqstring.cpp 3
-
- As before, the QTEST_MAIN() macro expands to a simple main()
- method that runs all the test functions, and since both the
- declaration and the implementation of our test class are in a .cpp
- file, we also need to include the generated moc file to make Qt's
- introspection work.
-
- \section1 Building the Executable
-
- \include {building-examples.qdocinc} {building the executable} {tutorial2}
-
- \section1 Running the Executable
-
- Running the resulting executable should give you the following
- output:
-
- \snippet code/doc_src_qtestlib.qdoc 11
-*/
-
-/*!
- \example tutorial3
-
- \previouspage {Chapter 2: Data Driven Testing}{Chapter 2}
- \nextpage {Chapter 4: Replaying GUI Events}{Chapter 4}
-
- \title Chapter 3: Simulating GUI Events
- \brief Howe to simulate GUI events.
-
- Qt Test features some mechanisms to test graphical user
- interfaces. Instead of simulating native window system events,
- Qt Test sends internal Qt events. That means there are no
- side-effects on the machine the tests are running on.
-
- This chapter demonstrates how to write a simple GUI test.
-
- \section1 Writing a GUI Test
-
- This time, let's assume you want to test the behavior of our
- QLineEdit class. As before, you will need a class that contains
- your test function:
-
- \snippet tutorial3/testgui.cpp 0
-
- The only difference is that you need to include the Qt GUI class
- definitions in addition to the QTest namespace.
-
- \snippet tutorial3/testgui.cpp 1
-
- In the implementation of the test function, we first create a
- QLineEdit. Then, we simulate writing "hello world" in the line edit
- using the \l QTest::keyClicks() function.
-
- \note The widget must also be shown in order to correctly test keyboard
- shortcuts.
-
- QTest::keyClicks() simulates clicking a sequence of keys on a
- widget. Optionally, a keyboard modifier can be specified as well
- as a delay (in milliseconds) of the test after each key click. In
- a similar way, you can use the QTest::keyClick(),
- QTest::keyPress(), QTest::keyRelease(), QTest::mouseClick(),
- QTest::mouseDClick(), QTest::mouseMove(), QTest::mousePress()
- and QTest::mouseRelease() functions to simulate the associated
- GUI events.
-
- Finally, we use the \l QCOMPARE() macro to check if the line edit's
- text is as expected.
-
- \section1 Preparing the Stand-Alone Executable
-
- As before, to make our test case a stand-alone executable, the
- following two lines are needed:
-
- \snippet tutorial3/testgui.cpp 2
-
- The QTEST_MAIN() macro expands to a simple main() method that
- runs all the test functions, and since both the declaration and
- the implementation of our test class are in a .cpp file, we also
- need to include the generated moc file to make Qt's introspection
- work.
-
- \section1 Building the Executable
-
- \include {building-examples.qdocinc} {building the executable} {tutorial3}
-
- \section1 Running the Executable
-
- Running the resulting executable should give you the following
- output:
-
- \snippet code/doc_src_qtestlib.qdoc 12
-*/
-
-/*!
- \example tutorial4
-
- \previouspage {Chapter 3: Simulating GUI Events}{Chapter 3}
- \nextpage {Chapter 5: Writing a Benchmark}{Chapter 5}
-
- \title Chapter 4: Replaying GUI Events
- \brief How to replay GUI events.
-
- In this chapter, we will show how to simulate a GUI event,
- and how to store a series of GUI events as well as replay them on
- a widget.
-
- The approach to storing a series of events and replaying them is
- quite similar to the approach explained in \l {Chapter 2:
- Data Driven Testing}{chapter 2}. All you need to do is to add a data
- function to your test class:
-
- \snippet tutorial4/testgui.cpp 0
-
- \section1 Writing the Data Function
-
- As before, a test function's associated data function carries the
- same name, appended by \c{_data}.
-
- \snippet tutorial4/testgui.cpp 1
-
- First, we define the elements of the table using the
- QTest::addColumn() function: A list of GUI events, and the
- expected result of applying the list of events on a QWidget. Note
- that the type of the first element is \l QTestEventList.
-
- A QTestEventList can be populated with GUI events that can be
- stored as test data for later usage, or be replayed on any
- QWidget.
-
- In our current data function, we create two \l
- {QTestEventList} elements. The first list consists of a single click to
- the 'a' key. We add the event to the list using the
- QTestEventList::addKeyClick() function. Then we use the
- QTest::newRow() function to give the data set a name, and
- stream the event list and the expected result into the table.
-
- The second list consists of two key clicks: an 'a' with a
- following 'backspace'. Again we use the
- QTestEventList::addKeyClick() to add the events to the list, and
- QTest::newRow() to put the event list and the expected
- result into the table with an associated name.
-
- \section1 Rewriting the Test Function
-
- Our test can now be rewritten:
-
- \snippet tutorial4/testgui.cpp 2
-
- The TestGui::testGui() function will be executed two times,
- once for each entry in the test data that we created in the
- associated TestGui::testGui_data() function.
-
- First, we fetch the two elements of the data set using the \l
- QFETCH() macro. \l QFETCH() takes two arguments: the data type of
- the element and the element name. Then we create a QLineEdit, and
- apply the list of events on that widget using the
- QTestEventList::simulate() function.
-
- Finally, we use the QCOMPARE() macro to check if the line edit's
- text is as expected.
-
- \section1 Preparing the Stand-Alone Executable
-
- As before, to make our test case a stand-alone executable,
- the following two lines are needed:
-
- \snippet tutorial4/testgui.cpp 3
-
- The QTEST_MAIN() macro expands to a simple main() method that
- runs all the test functions, and since both the declaration and
- the implementation of our test class are in a .cpp file, we also
- need to include the generated moc file to make Qt's introspection
- work.
-
- \section1 Building the Executable
-
- \include {building-examples.qdocinc} {building the executable} {tutorial4}
-
- \section1 Running the Executable
-
- Running the resulting executable should give you the following
- output:
-
- \snippet code/doc_src_qtestlib.qdoc 13
-*/
-
-/*!
- \example tutorial5
-
- \previouspage {Chapter 4: Replaying GUI Events}{Chapter 4}
- \nextpage {Chapter 6: Skipping Tests with QSKIP}{Chapter 6}
-
- \title Chapter 5: Writing a Benchmark
- \brief How to write a benchmark.
-
- This final demonstrates how to write benchmarks using Qt Test.
-
- \section1 Writing a Benchmark
- To create a benchmark we extend a test function with a QBENCHMARK macro.
- A benchmark test function will then typically consist of setup code and
- a QBENCHMARK macro that contains the code to be measured. This test
- function benchmarks QString::localeAwareCompare().
-
- \snippet tutorial5/benchmarking.cpp 0
-
- Setup can be done at the beginning of the function. At this point, the clock
- is not running. The code inside the QBENCHMARK macro will be
- measured, and possibly repeated several times in order to get an
- accurate measurement.
-
- Several \l {testlib-benchmarking-measurement}{back-ends} are available
- and can be selected on the command line.
-
- \section1 Data Functions
-
- Data functions are useful for creating benchmarks that compare
- multiple data inputs, for example locale aware compare against standard
- compare.
-
- \snippet tutorial5/benchmarking.cpp 1
-
- The test function then uses the data to determine what to benchmark.
-
- \snippet tutorial5/benchmarking.cpp 2
-
- The \c{if (useLocaleCompare)} switch is placed outside the QBENCHMARK
- macro to avoid measuring its overhead. Each benchmark test function
- can have one active QBENCHMARK macro.
-
- \section1 Building the Executable
-
- \include {building-examples.qdocinc} {building the executable} {tutorial5}
-
- \section1 Running the Executable
-
- Running the resulting executable should give you the following
- output:
-
- \snippet code/doc_src_qtestlib.qdoc 14
-*/
-/*!
- \page qttestlib-tutorial6.html
-
- \previouspage {Chapter 5: Writing a Benchmark}{Chapter 5}
-
- \title Chapter 6: Skipping Tests with QSKIP
- \brief How to skip tests in certain cases.
-
- \section2 Using QSKIP(\a description) in a test function
-
- If the QSKIP() macro is called from a test function, it stops
- the execution of the test without adding a failure to the test log.
- It can be used to skip tests that are certain to fail. The text in
- the QSKIP \a description parameter is appended to the test log,
- and should explain why the test was not carried out.
-
- QSKIP can be used to skip testing when the implementation is not yet
- complete or not supported on a certain platform. When there are known
- failures, QEXPECT_FAIL is recommended, as it supports running the rest
- of the test, when possible.
-
- Example of QSKIP in a test function:
-
- \snippet code/doc_src_qtqskip_snippet.cpp 0
-
- In a data-driven test, each call to QSKIP() skips only the current
- row of test data. If the data-driven test contains an unconditional
- call to QSKIP, it produces a skip message for each row of test data.
-
- \section2 Using QSKIP in a _data function
-
- If called from a _data function, the QSKIP() macro stops
- execution of the _data function. This prevents execution of the
- associated test function.
-
- See below for an example:
-
- \snippet code/doc_src_qtqskip.cpp 1
-
- \section2 Using QSKIP from initTestCase() or initTestCase_data()
-
- If called from \c initTestCase() or \c initTestCase_data(), the
- QSKIP() macro will skip all test and _data functions.
-*/
diff --git a/src/testlib/doc/src/qttestlib-tutorial1.qdoc b/src/testlib/doc/src/qttestlib-tutorial1.qdoc
new file mode 100644
index 0000000000..41d9264c0d
--- /dev/null
+++ b/src/testlib/doc/src/qttestlib-tutorial1.qdoc
@@ -0,0 +1,76 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \page qttestlib-tutorial1-example.html
+ \previouspage {Qt Test Tutorial}{Qt Test Tutorial Overview}
+ \nextpage {Chapter 2: Data Driven Testing}{Chapter 2}
+
+ \title Chapter 1: Writing a Unit Test
+ \brief How to write a unit test.
+
+ This first chapter demonstrates how to write a simple unit test and how to
+ run the test case as a stand-alone executable.
+
+ \section1 Writing a Test
+
+ Let's assume you want to test the behavior of our QString class.
+ First, you need a class that contains your test functions. This class
+ has to inherit from QObject:
+
+ \snippet tutorial1/testqstring.cpp 0
+
+ \note You need to include the QTest header and declare the test functions as
+ private slots so the test framework finds and executes it.
+
+ Then you need to implement the test function itself. The
+ implementation could look like this:
+
+ \snippet code/doc_src_qtestlib.cpp 8
+
+ The \l QVERIFY() macro evaluates the expression passed as its
+ argument. If the expression evaluates to true, the execution of
+ the test function continues. Otherwise, a message describing the
+ failure is appended to the test log, and the test function stops
+ executing.
+
+ But if you want a more verbose output to the test log, you should
+ use the \l QCOMPARE() macro instead:
+
+ \snippet tutorial1/testqstring.cpp 1
+
+ If the strings are not equal, the contents of both strings are
+ appended to the test log, making it immediately visible why the
+ comparison failed.
+
+ \section1 Preparing the Stand-Alone Executable
+
+ Finally, to make our test case a stand-alone executable, the
+ following two lines are needed:
+
+ \snippet tutorial1/testqstring.cpp 2
+
+ The \l QTEST_MAIN() macro expands to a simple \c main()
+ method that runs all the test functions. Note that if both the
+ declaration and the implementation of our test class are in a \c
+ .cpp file, we also need to include the generated moc file to make
+ Qt's introspection work.
+
+ \section1 Building the Executable
+
+ \include {building-examples.qdocinc} {building the executable} {tutorial1}
+
+ \note If you're using windows, replace \c make with \c
+ nmake or whatever build tool you use.
+
+ \section1 Running the Executable
+
+ Running the resulting executable should give you the following
+ output:
+
+ \snippet code/doc_src_qtestlib.qdoc 10
+
+ Congratulations! You just wrote and executed your first unit test
+ using the Qt Test framework.
+*/
diff --git a/src/testlib/doc/src/qttestlib-tutorial2.qdoc b/src/testlib/doc/src/qttestlib-tutorial2.qdoc
new file mode 100644
index 0000000000..bd828b3963
--- /dev/null
+++ b/src/testlib/doc/src/qttestlib-tutorial2.qdoc
@@ -0,0 +1,132 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \page qttestlib-tutorial2-example.html
+ \previouspage {Chapter 1: Writing a Unit Test}{Chapter 1}
+ \nextpage {Chapter 3: Simulating Gui Events}{Chapter 3}
+
+ \title Chapter 2: Data Driven Testing
+ \brief How to create data driven tests.
+
+ This chapter demonstrates how to execute a test multiple times with
+ different test data.
+
+ So far, we have hard coded the data we wanted to test into our
+ test function. If we add more test data, the function might look like
+ this:
+
+ \snippet code/doc_src_qtestlib.cpp 11
+
+ To prevent the function from being cluttered with repetitive code, Qt Test
+ supports adding test data to a test function. All we need is to add another
+ private slot to our test class:
+
+ \snippet tutorial2/testqstring.cpp 0
+
+ \section1 Writing the Data Function
+
+ A test function's associated data function has \c _data appended to its
+ name. Our data function looks like this:
+
+ \snippet tutorial2/testqstring.cpp 1
+
+ First, we define the two elements of our test table using the \l
+ QTest::addColumn() function: a test string and the
+ expected result of applying the QString::toUpper() function to
+ that string.
+
+ Then, we add some data to the table using the \l QTest::newRow()
+ function. We can also use \l QTest::addRow() if we need to format some data
+ in the row name, for example when generating many data rows iteratively.
+ Each row of data will become a separate row in the test table.
+
+ \l QTest::newRow() takes one argument: a name that will be associated with
+ the data set and used in the test log to identify the data row. \l
+ QTest::addRow() takes a (\c{printf}-style) format string followed by the
+ parameters to be represented in place of the formatting tokens in the format
+ string. Then, we stream the data set into the new table row. First an
+ arbitrary string, and then the expected result of applying the
+ QString::toUpper() function to that string.
+
+ You can think of the test data as a two-dimensional table. In
+ our case, it has two columns called \c string and \c result and
+ three rows. In addition, a name and an index are associated
+ with each row:
+
+ \table
+ \header
+ \li index
+ \li name
+ \li string
+ \li result
+ \row
+ \li 0
+ \li all-lower
+ \li "hello"
+ \li HELLO
+ \row
+ \li 1
+ \li mixed
+ \li "Hello"
+ \li HELLO
+ \row
+ \li 2
+ \li all-upper
+ \li "HELLO"
+ \li HELLO
+ \endtable
+
+ When data is streamed into the row, each datum is asserted to match
+ the type of the column whose value it supplies. If any assertion fails,
+ the test is aborted.
+
+ The names of rows and columns, in a given test function's data table, should
+ be unique: if two rows share a name, or two columns share a name, a warning
+ will (since Qt 6.5) be produced. See \l qWarning() for how you can cause
+ warnings to be treated as errors and \l {Test for Warnings} for how to get
+ your tests clear of other warnings.
+
+ \section1 Rewriting the Test Function
+
+ Our test function can now be rewritten:
+
+ \snippet tutorial2/testqstring.cpp 2
+
+ The TestQString::toUpper() function will be executed three times,
+ once for each entry in the test table that we created in the
+ associated TestQString::toUpper_data() function.
+
+ First, we fetch the two elements of the data set using the \l
+ QFETCH() macro. \l QFETCH() takes two arguments: The data type of
+ the element and the element name. Then, we perform the test using
+ the \l QCOMPARE() macro.
+
+ This approach makes it very easy to add new data to the test
+ without modifying the test itself.
+
+ \section1 Preparing the Stand-Alone Executable
+
+ And again, to make our test case a stand-alone executable,
+ the following two lines are needed:
+
+ \snippet tutorial2/testqstring.cpp 3
+
+ As before, the QTEST_MAIN() macro expands to a simple main()
+ method that runs all the test functions, and since both the
+ declaration and the implementation of our test class are in a .cpp
+ file, we also need to include the generated moc file to make Qt's
+ introspection work.
+
+ \section1 Building the Executable
+
+ \include {building-examples.qdocinc} {building the executable} {tutorial2}
+
+ \section1 Running the Executable
+
+ Running the resulting executable should give you the following
+ output:
+
+ \snippet code/doc_src_qtestlib.qdoc 11
+*/
diff --git a/src/testlib/doc/src/qttestlib-tutorial3.qdoc b/src/testlib/doc/src/qttestlib-tutorial3.qdoc
new file mode 100644
index 0000000000..2b7fe25c96
--- /dev/null
+++ b/src/testlib/doc/src/qttestlib-tutorial3.qdoc
@@ -0,0 +1,75 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \page qttestlib-tutorial3-example.html
+ \previouspage {Chapter 2: Data Driven Testing}{Chapter 2}
+ \nextpage {Chapter 4: Replaying GUI Events}{Chapter 4}
+
+ \title Chapter 3: Simulating GUI Events
+ \brief How to simulate GUI events.
+
+ Qt Test features some mechanisms to test graphical user
+ interfaces. Instead of simulating native window system events,
+ Qt Test sends internal Qt events. That means there are no
+ side-effects on the machine the tests are running on.
+
+ This chapter demonstrates how to write a simple GUI test.
+
+ \section1 Writing a GUI Test
+
+ This time, let's assume you want to test the behavior of our
+ QLineEdit class. As before, you will need a class that contains
+ your test function:
+
+ \snippet tutorial3/testgui.cpp 0
+
+ The only difference is that you need to include the Qt GUI class
+ definitions in addition to the QTest namespace.
+
+ \snippet tutorial3/testgui.cpp 1
+
+ In the implementation of the test function, we first create a
+ QLineEdit. Then, we simulate writing "hello world" in the line edit
+ using the \l QTest::keyClicks() function.
+
+ \note The widget must also be shown in order to correctly test keyboard
+ shortcuts.
+
+ QTest::keyClicks() simulates clicking a sequence of keys on a
+ widget. Optionally, a keyboard modifier can be specified as well
+ as a delay (in milliseconds) of the test after each key click. In
+ a similar way, you can use the QTest::keyClick(),
+ QTest::keyPress(), QTest::keyRelease(), QTest::mouseClick(),
+ QTest::mouseDClick(), QTest::mouseMove(), QTest::mousePress()
+ and QTest::mouseRelease() functions to simulate the associated
+ GUI events.
+
+ Finally, we use the \l QCOMPARE() macro to check if the line edit's
+ text is as expected.
+
+ \section1 Preparing the Stand-Alone Executable
+
+ As before, to make our test case a stand-alone executable, the
+ following two lines are needed:
+
+ \snippet tutorial3/testgui.cpp 2
+
+ The QTEST_MAIN() macro expands to a simple main() method that
+ runs all the test functions, and since both the declaration and
+ the implementation of our test class are in a .cpp file, we also
+ need to include the generated moc file to make Qt's introspection
+ work.
+
+ \section1 Building the Executable
+
+ \include {building-examples.qdocinc} {building the executable} {tutorial3}
+
+ \section1 Running the Executable
+
+ Running the resulting executable should give you the following
+ output:
+
+ \snippet code/doc_src_qtestlib.qdoc 12
+*/
diff --git a/src/testlib/doc/src/qttestlib-tutorial4.qdoc b/src/testlib/doc/src/qttestlib-tutorial4.qdoc
new file mode 100644
index 0000000000..d5a0121f67
--- /dev/null
+++ b/src/testlib/doc/src/qttestlib-tutorial4.qdoc
@@ -0,0 +1,95 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \page qttestlib-tutorial4-example.html
+ \previouspage {Chapter 3: Simulating GUI Events}{Chapter 3}
+ \nextpage {Chapter 5: Writing a Benchmark}{Chapter 5}
+
+ \title Chapter 4: Replaying GUI Events
+ \brief How to replay GUI events.
+
+ In this chapter, we will show how to simulate a GUI event,
+ and how to store a series of GUI events as well as replay them on
+ a widget.
+
+ The approach to storing a series of events and replaying them is
+ quite similar to the approach explained in \l {Chapter 2:
+ Data Driven Testing}{chapter 2}. All you need to do is to add a data
+ function to your test class:
+
+ \snippet tutorial4/testgui.cpp 0
+
+ \section1 Writing the Data Function
+
+ As before, a test function's associated data function carries the
+ same name, appended by \c{_data}.
+
+ \snippet tutorial4/testgui.cpp 1
+
+ First, we define the elements of the table using the
+ QTest::addColumn() function: A list of GUI events, and the
+ expected result of applying the list of events on a QWidget. Note
+ that the type of the first element is \l QTestEventList.
+
+ A QTestEventList can be populated with GUI events that can be
+ stored as test data for later usage, or be replayed on any
+ QWidget.
+
+ In our current data function, we create two \l
+ {QTestEventList} elements. The first list consists of a single click to
+ the 'a' key. We add the event to the list using the
+ QTestEventList::addKeyClick() function. Then we use the
+ QTest::newRow() function to give the data set a name, and
+ stream the event list and the expected result into the table.
+
+ The second list consists of two key clicks: an 'a' with a
+ following 'backspace'. Again we use the
+ QTestEventList::addKeyClick() to add the events to the list, and
+ QTest::newRow() to put the event list and the expected
+ result into the table with an associated name.
+
+ \section1 Rewriting the Test Function
+
+ Our test can now be rewritten:
+
+ \snippet tutorial4/testgui.cpp 2
+
+ The TestGui::testGui() function will be executed two times,
+ once for each entry in the test data that we created in the
+ associated TestGui::testGui_data() function.
+
+ First, we fetch the two elements of the data set using the \l
+ QFETCH() macro. \l QFETCH() takes two arguments: the data type of
+ the element and the element name. Then we create a QLineEdit, and
+ apply the list of events on that widget using the
+ QTestEventList::simulate() function.
+
+ Finally, we use the QCOMPARE() macro to check if the line edit's
+ text is as expected.
+
+ \section1 Preparing the Stand-Alone Executable
+
+ As before, to make our test case a stand-alone executable,
+ the following two lines are needed:
+
+ \snippet tutorial4/testgui.cpp 3
+
+ The QTEST_MAIN() macro expands to a simple main() method that
+ runs all the test functions, and since both the declaration and
+ the implementation of our test class are in a .cpp file, we also
+ need to include the generated moc file to make Qt's introspection
+ work.
+
+ \section1 Building the Executable
+
+ \include {building-examples.qdocinc} {building the executable} {tutorial4}
+
+ \section1 Running the Executable
+
+ Running the resulting executable should give you the following
+ output:
+
+ \snippet code/doc_src_qtestlib.qdoc 13
+*/
diff --git a/src/testlib/doc/src/qttestlib-tutorial5.qdoc b/src/testlib/doc/src/qttestlib-tutorial5.qdoc
new file mode 100644
index 0000000000..7569019b4e
--- /dev/null
+++ b/src/testlib/doc/src/qttestlib-tutorial5.qdoc
@@ -0,0 +1,57 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \page qttestlib-tutorial5-example.html
+ \previouspage {Chapter 4: Replaying GUI Events}{Chapter 4}
+ \nextpage {Chapter 6: Skipping Tests with QSKIP}{Chapter 6}
+
+ \title Chapter 5: Writing a Benchmark
+ \brief How to write a benchmark.
+
+ This chapter demonstrates how to write benchmarks using Qt Test.
+
+ \section1 Writing a Benchmark
+ To create a benchmark we extend a test function with a QBENCHMARK macro.
+ A benchmark test function will then typically consist of setup code and
+ a QBENCHMARK macro that contains the code to be measured. This test
+ function benchmarks QString::localeAwareCompare().
+
+ \snippet tutorial5/benchmarking.cpp 0
+
+ Setup can be done at the beginning of the function. At this point, the clock
+ is not running. The code inside the QBENCHMARK macro will be
+ measured, and possibly repeated several times in order to get an
+ accurate measurement.
+
+ Several \l {testlib-benchmarking-measurement}{back-ends} are available
+ and can be selected on the command line.
+
+ \section1 Data Functions
+
+ Data functions are useful for creating benchmarks that compare
+ multiple data inputs, for example locale aware compare against standard
+ compare.
+
+ \snippet tutorial5/benchmarking.cpp 1
+
+ The test function then uses the data to determine what to benchmark.
+
+ \snippet tutorial5/benchmarking.cpp 2
+
+ The \c{if (useLocaleCompare)} switch is placed outside the QBENCHMARK
+ macro to avoid measuring its overhead. Each benchmark test function
+ can have one active QBENCHMARK macro.
+
+ \section1 Building the Executable
+
+ \include {building-examples.qdocinc} {building the executable} {tutorial5}
+
+ \section1 Running the Executable
+
+ Running the resulting executable should give you the following
+ output:
+
+ \snippet code/doc_src_qtestlib.qdoc 14
+*/
diff --git a/src/testlib/doc/src/qttestlib-tutorial6.qdoc b/src/testlib/doc/src/qttestlib-tutorial6.qdoc
new file mode 100644
index 0000000000..602ca0b28e
--- /dev/null
+++ b/src/testlib/doc/src/qttestlib-tutorial6.qdoc
@@ -0,0 +1,50 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \page qttestlib-tutorial6.html
+
+ \previouspage {Chapter 5: Writing a Benchmark}{Chapter 5}
+
+ \title Chapter 6: Skipping Tests with QSKIP
+ \brief How to skip tests in certain cases.
+
+ \section2 Using QSKIP(\a description) in a test function
+
+ If the \l QSKIP() macro is called from a test function, it stops
+ the execution of the test without adding a failure to the test log.
+ It can be used to skip tests that are certain to fail. The text in
+ the QSKIP \a description parameter is appended to the test log,
+ and should explain why the test was not carried out.
+
+ QSKIP can be used to skip testing when the implementation is not yet
+ complete or not supported on a certain platform. When there are known
+ failures, \l QEXPECT_FAIL is recommended, as it supports running the rest
+ of the test, when possible.
+
+ Example of QSKIP in a test function:
+
+ \snippet code/doc_src_qtqskip_snippet.cpp 0
+
+ In a data-driven test, each call to QSKIP() skips only the current
+ row of test data. If the data-driven test contains an unconditional
+ call to QSKIP, it produces a skip message for each row of test data.
+
+ \section2 Using QSKIP in a _data function
+
+ If called from a _data function, the QSKIP() macro stops
+ execution of the _data function. This prevents execution of the
+ associated test function.
+
+ See below for an example:
+
+ \snippet code/doc_src_qtqskip.cpp 1
+
+ \section2 Using QSKIP from initTestCase() or initTestCase_data()
+
+ If called from \c initTestCase() or \c initTestCase_data(), the
+ QSKIP() macro will skip all test and _data functions.
+
+ \sa {Select Appropriate Mechanisms to Exclude Tests}
+*/
diff --git a/src/testlib/qabstracttestlogger.cpp b/src/testlib/qabstracttestlogger.cpp
index 596799f5c4..de6fb63560 100644
--- a/src/testlib/qabstracttestlogger.cpp
+++ b/src/testlib/qabstracttestlogger.cpp
@@ -148,6 +148,19 @@ QAbstractTestLogger::~QAbstractTestLogger()
}
/*!
+ Returns true if the logger supports repeated test runs.
+
+ Repetition of test runs is disabled by default, and can be enabled only for
+ test loggers that support it. Even if the logger may create syntactically
+ correct test reports, log-file analyzers may assume that test names are
+ unique within one report file.
+*/
+bool QAbstractTestLogger::isRepeatSupported() const
+{
+ return false;
+}
+
+/*!
Returns true if the \c output stream is standard output.
*/
bool QAbstractTestLogger::isLoggingToStdout() const
diff --git a/src/testlib/qabstracttestlogger_p.h b/src/testlib/qabstracttestlogger_p.h
index 188967981c..b4a66cd12a 100644
--- a/src/testlib/qabstracttestlogger_p.h
+++ b/src/testlib/qabstracttestlogger_p.h
@@ -76,6 +76,8 @@ public:
virtual void addMessage(MessageTypes type, const QString &message,
const char *file = nullptr, int line = 0) = 0;
+ virtual bool isRepeatSupported() const;
+
bool isLoggingToStdout() const;
void outputString(const char *msg);
diff --git a/src/testlib/qappletestlogger.cpp b/src/testlib/qappletestlogger.cpp
index db4f17e03a..7517a95344 100644
--- a/src/testlib/qappletestlogger.cpp
+++ b/src/testlib/qappletestlogger.cpp
@@ -3,8 +3,6 @@
#include "qappletestlogger_p.h"
-#include <QPair>
-
QT_BEGIN_NAMESPACE
#if defined(QT_USE_APPLE_UNIFIED_LOGGING)
@@ -106,6 +104,14 @@ void QAppleTestLogger::addIncident(IncidentTypes type, const char *description,
if (qstrlen(description))
message += u'\n' % QString::fromLatin1(description);
+ // As long as the Apple logger doesn't propagate the context's file and
+ // line number we need to manually print it.
+ if (context.line && context.file) {
+ QTestCharBuffer line;
+ QTest::qt_asprintf(&line, "\n [Loc: %s:%d]", context.file, context.line);
+ message += QLatin1String(line.data());
+ }
+
AppleUnifiedLogger::messageHandler(messageData.messageType, context, message, subsystem());
}
diff --git a/src/testlib/qasciikey.cpp b/src/testlib/qasciikey.cpp
index a4b6a14f35..114b757dc4 100644
--- a/src/testlib/qasciikey.cpp
+++ b/src/testlib/qasciikey.cpp
@@ -141,7 +141,7 @@ Qt::Key QTest::asciiToKey(char ascii)
case 0xb2: return Qt::Key_twosuperior;
case 0xb3: return Qt::Key_threesuperior;
case 0xb4: return Qt::Key_acute;
- case 0xb5: return Qt::Key_mu;
+ case 0xb5: return Qt::Key_micro;
case 0xb6: return Qt::Key_paragraph;
case 0xb7: return Qt::Key_periodcentered;
case 0xb8: return Qt::Key_cedilla;
@@ -369,7 +369,7 @@ char QTest::keyToAscii(Qt::Key key)
case Qt::Key_twosuperior: return char(0xb2);
case Qt::Key_threesuperior: return char(0xb3);
case Qt::Key_acute: return char(0xb4);
- case Qt::Key_mu: return char(0xb5);
+ case Qt::Key_micro: return char(0xb5);
case Qt::Key_paragraph: return char(0xb6);
case Qt::Key_periodcentered: return char(0xb7);
case Qt::Key_cedilla: return char(0xb8);
diff --git a/src/testlib/qbenchmark.cpp b/src/testlib/qbenchmark.cpp
index 4a8bd72ee9..af6ee5f7c6 100644
--- a/src/testlib/qbenchmark.cpp
+++ b/src/testlib/qbenchmark.cpp
@@ -167,7 +167,7 @@ QTest::QBenchmarkIterationController::~QBenchmarkIterationController()
/*! \internal
*/
-bool QTest::QBenchmarkIterationController::isDone()
+bool QTest::QBenchmarkIterationController::isDone() const noexcept
{
if (QBenchmarkTestMethodData::current->runOnce)
return i > 0;
@@ -176,14 +176,14 @@ bool QTest::QBenchmarkIterationController::isDone()
/*! \internal
*/
-void QTest::QBenchmarkIterationController::next()
+void QTest::QBenchmarkIterationController::next() noexcept
{
++i;
}
/*! \internal
*/
-int QTest::iterationCount()
+int QTest::iterationCount() noexcept
{
return QBenchmarkTestMethodData::current->iterationCount;
}
diff --git a/src/testlib/qbenchmark.h b/src/testlib/qbenchmark.h
index 20c643b2c6..d0e8c78567 100644
--- a/src/testlib/qbenchmark.h
+++ b/src/testlib/qbenchmark.h
@@ -28,8 +28,8 @@ public:
QBenchmarkIterationController();
QBenchmarkIterationController(RunMode runMode);
~QBenchmarkIterationController();
- bool isDone();
- void next();
+ bool isDone() const noexcept;
+ void next() noexcept;
int i;
};
diff --git a/src/testlib/qbenchmark_p.h b/src/testlib/qbenchmark_p.h
index 09379aac0f..902b092b16 100644
--- a/src/testlib/qbenchmark_p.h
+++ b/src/testlib/qbenchmark_p.h
@@ -149,7 +149,7 @@ public:
// low-level API:
namespace QTest
{
- int iterationCount();
+ int iterationCount() noexcept;
void setIterationCountHint(int count);
void setIterationCount(int count);
diff --git a/src/testlib/qbenchmarkperfevents.cpp b/src/testlib/qbenchmarkperfevents.cpp
index 1b9101e854..c161879a7d 100644
--- a/src/testlib/qbenchmarkperfevents.cpp
+++ b/src/testlib/qbenchmarkperfevents.cpp
@@ -108,7 +108,8 @@ static QList<PerfEvent> defaultCounters()
static int perf_event_open(perf_event_attr *attr, pid_t pid, int cpu, int group_fd, unsigned long flags)
{
#ifdef SYS_perf_event_open
- return syscall(SYS_perf_event_open, attr, pid, cpu, group_fd, flags);
+ // syscall() returns long, but perf_event_open() is used to get a file descriptor
+ return int(syscall(SYS_perf_event_open, attr, pid, cpu, group_fd, flags));
#else
Q_UNUSED(attr);
Q_UNUSED(pid);
diff --git a/src/testlib/qbenchmarkvalgrind.cpp b/src/testlib/qbenchmarkvalgrind.cpp
index 253108bd9d..bea3066e66 100644
--- a/src/testlib/qbenchmarkvalgrind.cpp
+++ b/src/testlib/qbenchmarkvalgrind.cpp
@@ -45,7 +45,10 @@ bool QBenchmarkValgrindUtils::rerunThroughCallgrind(const QStringList &origAppAr
static void dumpOutput(const QByteArray &data, FILE *fh)
{
QFile file;
- file.open(fh, QIODevice::WriteOnly);
+ if (!file.open(fh, QIODevice::WriteOnly)) {
+ qFatal("Could not open filehandle for dumping output: %s",
+ qPrintable(file.errorString()));
+ }
file.write(data);
}
diff --git a/src/testlib/qcomparisontesthelper.cpp b/src/testlib/qcomparisontesthelper.cpp
new file mode 100644
index 0000000000..b71267b625
--- /dev/null
+++ b/src/testlib/qcomparisontesthelper.cpp
@@ -0,0 +1,22 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qcomparisontesthelper_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QTestPrivate {
+
+QByteArray formatTypeWithCRefImpl(QMetaType type, bool isConst, bool isRef, bool isRvalueRef)
+{
+ QByteArray res(type.name());
+ if (isConst)
+ res.append(" const");
+ if (isRef)
+ res.append(isRvalueRef ? " &&" : " &");
+ return res;
+}
+
+} // namespace QTestPrivate
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qcomparisontesthelper_p.h b/src/testlib/qcomparisontesthelper_p.h
new file mode 100644
index 0000000000..afeb1088c4
--- /dev/null
+++ b/src/testlib/qcomparisontesthelper_p.h
@@ -0,0 +1,373 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QCOMPARISONTESTHELPER_P_H
+#define QCOMPARISONTESTHELPER_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/q20type_traits.h>
+#include <QtCore/qxptype_traits.h>
+#include <QtTest/qtest.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTestPrivate {
+
+#ifdef __cpp_lib_three_way_comparison
+template <typename LT, typename RT>
+using HasThreeWayComparisonOp = decltype(std::declval<LT>() <=> std::declval<RT>());
+
+template <typename LT, typename RT>
+constexpr bool implementsThreeWayComparisonOp_v = qxp::is_detected_v<HasThreeWayComparisonOp,
+ LT, RT>;
+#endif
+
+Q_TESTLIB_EXPORT QByteArray formatTypeWithCRefImpl(QMetaType type, bool isConst,
+ bool isRef, bool isRvalueRef);
+
+template <typename T>
+QByteArray formatTypeWithCRef()
+{
+ return formatTypeWithCRefImpl(QMetaType::fromType<q20::remove_cvref_t<T>>(),
+ std::is_const_v<std::remove_reference_t<T>>,
+ std::is_reference_v<T>,
+ std::is_rvalue_reference_v<T>);
+}
+
+#define FOR_EACH_CREF(Func, Left, Right, Op, Result) \
+ Func(Left &, Right &, Op, Result) \
+ Func(Left &, Right const &, Op, Result) \
+ Func(Left &, Right &&, Op, Result) \
+ Func(Left &, Right const &&, Op, Result) \
+ Func(Left const &, Right &, Op, Result) \
+ Func(Left const &, Right const &, Op, Result) \
+ Func(Left const &, Right &&, Op, Result) \
+ Func(Left const &, Right const &&, Op, Result) \
+ Func(Left &&, Right &, Op, Result) \
+ Func(Left &&, Right const &, Op, Result) \
+ Func(Left &&, Right &&, Op, Result) \
+ Func(Left &&, Right const &&, Op, Result) \
+ Func(Left const &&, Right &, Op, Result) \
+ Func(Left const &&, Right const &, Op, Result) \
+ Func(Left const &&, Right &&, Op, Result) \
+ Func(Left const &&, Right const &&, Op, Result) \
+ /* END */
+
+#define CHECK_SINGLE_OPERATOR(Left, Right, Op, Result) \
+ do { \
+ constexpr bool qtest_op_check_isImplNoexcept \
+ = noexcept(std::declval<Left>() Op std::declval<Right>()); \
+ if constexpr (!qtest_op_check_isImplNoexcept) { \
+ QEXPECT_FAIL("", QByteArray("(" + formatTypeWithCRef<Left>() \
+ + " " #Op " " + formatTypeWithCRef<Right>() \
+ + ") is not noexcept").constData(), \
+ Continue); \
+ /* Ideally, operators should be noexcept, so warn if they are not. */ \
+ /* Do not make it a hard error, because the fix is not always trivial. */ \
+ QVERIFY(qtest_op_check_isImplNoexcept); \
+ } \
+ static_assert(std::is_convertible_v<decltype( \
+ std::declval<Left>() Op std::declval<Right>()), Result>); \
+ if constexpr (!std::is_same_v<Left, Right>) { \
+ static_assert(std::is_convertible_v<decltype( \
+ std::declval<Right>() Op std::declval<Left>()), Result>); \
+ } \
+ } while (false); \
+ /* END */
+
+/*!
+ \internal
+
+ This function checks that the types \c LeftType and \c RightType properly
+ define {in}equality operators (== and !=). The checks are performed for
+ all combinations of cvref-qualified lvalues and rvalues.
+*/
+template <typename LeftType, typename RightType = LeftType>
+void testEqualityOperatorsCompile()
+{
+ FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, ==, bool)
+ FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, !=, bool)
+}
+
+/*!
+ \internal
+
+ This function checks that the types \c LeftType and \c RightType properly
+ define all comparison operators (==, !=, <, >, <=, >=). The checks are
+ performed for all combinations of cvref-qualified lvalues and rvalues.
+
+ If compiled in C++20 mode, also checks \c {operator<=>()} if that is
+ implemented.
+*/
+template <typename LeftType, typename RightType = LeftType>
+void testAllComparisonOperatorsCompile()
+{
+ testEqualityOperatorsCompile<LeftType, RightType>();
+ if (QTest::currentTestFailed())
+ return;
+ FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, >, bool)
+ FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, <, bool)
+ FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, >=, bool)
+ FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, <=, bool)
+#ifdef __cpp_lib_three_way_comparison
+ if constexpr (implementsThreeWayComparisonOp_v<LeftType, RightType>) {
+ FOR_EACH_CREF(CHECK_SINGLE_OPERATOR, LeftType, RightType, <=>, std::partial_ordering)
+ }
+#endif
+}
+
+#undef CHECK_SINGLE_OPERATOR
+#undef FOR_EACH_CREF
+
+#define CHECK_RUNTIME_CREF(Func, Left, Right, Op, Expected) \
+ do { \
+ Func(Left, Right, Op, Expected); \
+ Func(std::as_const(Left), Right, Op, Expected); \
+ Func(Left, std::as_const(Right), Op, Expected); \
+ Func(std::as_const(Left), std::as_const(Right), Op, Expected); \
+ } while (false) \
+ /* END */
+
+#define CHECK_RUNTIME_LR(Left, Right, Op, Expected) \
+ do { \
+ QCOMPARE_EQ(Left Op Right, Expected); \
+ QCOMPARE_EQ(std::move(Left) Op Right, Expected); \
+ QCOMPARE_EQ(Left Op std::move(Right), Expected); \
+ QCOMPARE_EQ(std::move(Left) Op std::move(Right), Expected); \
+ } while (false) \
+ /* END */
+
+#ifdef __cpp_lib_three_way_comparison
+
+// Hide the macro under an ifdef, because it otherwise triggers a warning
+// in Clang C++17 build.
+#define CHECK_RUNTIME_3WAY(Left, Right, Op, Expected) \
+ do { \
+ QCOMPARE_EQ((Left <=> Right) Op 0, Expected); \
+ QCOMPARE_EQ((std::move(Left) <=> Right) Op 0, Expected); \
+ QCOMPARE_EQ((Left <=> std::move(Right)) Op 0, Expected); \
+ QCOMPARE_EQ((std::move(Left) <=> std::move(Right)) Op 0, Expected); \
+ } while (false) \
+ /* END */
+
+#endif // __cpp_lib_three_way_comparison
+
+/*!
+ \internal
+ Basic testing of equality operators.
+
+ The helper function tests {in}equality operators (== and !=) for the \a lhs
+ operand of type \c {LeftType} and the \a rhs operand of type \c {RightType},
+ plus the reverse order of the operands.
+
+ The \a expectedEqual parameter is an expected result for \c {operator==()}.
+
+ \note Any test calling this method will need to check the test state after
+ doing so, if there is any later code in the test.
+
+ \code
+ QTime early(12, 34, 56, 00);
+ QTime later(12, 34, 56, 01);
+ QTestPrivate::testEqualityOperators(early, later, false);
+ if (QTest:currentTestFailed())
+ return;
+ \endcode
+*/
+template <typename LeftType, typename RightType>
+void testEqualityOperators(LeftType lhs, RightType rhs, bool expectedEqual)
+{
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, ==, expectedEqual);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, !=, !expectedEqual);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, ==, expectedEqual);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, !=, !expectedEqual);
+}
+
+/*!
+ \internal
+ Basic testing of equality and relation operators.
+
+ The helper function tests all six relation and equality operators
+ (==, !=, <, >, <=, >=) for the \a lhs operand of type \c {LeftType} and
+ the \a rhs operand of type \c {RightType} and all six for the reverse
+ order of the operands.
+
+ If compiled in C++20 mode, also checks \c {operator<=>()} if that is
+ implemented.
+
+ When compiled in C++17 mode, the \c OrderingType must be one of
+ Qt::partial_ordering, Qt::strong_ordering, or Qt::weak_ordering.
+ In C++20 mode, also the \c {std::*_ordering} types can be used.
+
+ The \a expectedOrdering parameter provides the expected
+ relation between \a lhs and \a rhs.
+
+ \note Any test calling this method will need to check the test state after
+ doing so, if there is any later code in the test.
+
+ \code
+ QDateTime now = QDateTime::currentDateTime();
+ QDateTime later = now.addMSec(1);
+ QTestPrivate::testComparisonOperators(now, later, Qt::weak_ordering::less);
+ if (QTest:currentTestFailed())
+ return;
+ \endcode
+*/
+template <typename LeftType, typename RightType, typename OrderingType>
+void testAllComparisonOperators(LeftType lhs, RightType rhs, OrderingType expectedOrdering)
+{
+ constexpr bool isQOrderingType = std::is_same_v<OrderingType, Qt::partial_ordering>
+ || std::is_same_v<OrderingType, Qt::weak_ordering>
+ || std::is_same_v<OrderingType, Qt::strong_ordering>;
+#ifdef __cpp_lib_three_way_comparison
+ constexpr bool isStdOrderingType = std::is_same_v<OrderingType, std::partial_ordering>
+ || std::is_same_v<OrderingType, std::weak_ordering>
+ || std::is_same_v<OrderingType, std::strong_ordering>;
+#else
+ constexpr bool isStdOrderingType = false;
+#endif
+
+ static_assert(isQOrderingType || isStdOrderingType,
+ "Please provide, as the expectedOrdering parameter, a value "
+ "of one of the Qt::{partial,weak,strong}_ordering or "
+ "std::{partial,weak,strong}_ordering types.");
+
+ // We have all sorts of operator==() between Q*Ordering and std::*_ordering
+ // types, so we can just compare to Qt::partial_ordering.
+ const bool expectedEqual = expectedOrdering == Qt::partial_ordering::equivalent;
+ const bool expectedLess = expectedOrdering == Qt::partial_ordering::less;
+ const bool expectedUnordered = expectedOrdering == Qt::partial_ordering::unordered;
+
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, ==,
+ !expectedUnordered && expectedEqual);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, !=,
+ expectedUnordered || !expectedEqual);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, <,
+ !expectedUnordered && expectedLess);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, >,
+ !expectedUnordered && !expectedLess && !expectedEqual);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, <=,
+ !expectedUnordered && (expectedEqual || expectedLess));
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, lhs, rhs, >=,
+ !expectedUnordered && !expectedLess);
+#ifdef __cpp_lib_three_way_comparison
+ if constexpr (implementsThreeWayComparisonOp_v<LeftType, RightType>) {
+ if constexpr (std::is_convertible_v<OrderingType, std::strong_ordering>)
+ static_assert(std::is_same_v<decltype(lhs <=> rhs), std::strong_ordering>);
+ else if constexpr (std::is_convertible_v<OrderingType, std::weak_ordering>)
+ static_assert(std::is_same_v<decltype(lhs <=> rhs), std::weak_ordering>);
+ else
+ static_assert(std::is_same_v<decltype(lhs <=> rhs), std::partial_ordering>);
+
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, ==,
+ !expectedUnordered && expectedEqual);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, !=,
+ expectedUnordered || !expectedEqual);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, <,
+ !expectedUnordered && expectedLess);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, >,
+ !expectedUnordered && !expectedLess && !expectedEqual);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, <=,
+ !expectedUnordered && (expectedEqual || expectedLess));
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, lhs, rhs, >=,
+ !expectedUnordered && !expectedLess);
+ }
+#endif
+
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, ==,
+ !expectedUnordered && expectedEqual);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, !=,
+ expectedUnordered || !expectedEqual);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, <,
+ !expectedUnordered && !expectedLess && !expectedEqual);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, >,
+ !expectedUnordered && expectedLess);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, <=,
+ !expectedUnordered && !expectedLess);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_LR, rhs, lhs, >=,
+ !expectedUnordered && (expectedEqual || expectedLess));
+#ifdef __cpp_lib_three_way_comparison
+ if constexpr (implementsThreeWayComparisonOp_v<LeftType, RightType>) {
+ if constexpr (std::is_convertible_v<OrderingType, std::strong_ordering>)
+ static_assert(std::is_same_v<decltype(rhs <=> lhs), std::strong_ordering>);
+ else if constexpr (std::is_convertible_v<OrderingType, std::weak_ordering>)
+ static_assert(std::is_same_v<decltype(rhs <=> lhs), std::weak_ordering>);
+ else
+ static_assert(std::is_same_v<decltype(rhs <=> lhs), std::partial_ordering>);
+
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, ==,
+ !expectedUnordered && expectedEqual);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, !=,
+ expectedUnordered || !expectedEqual);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, <,
+ !expectedUnordered && !expectedLess && !expectedEqual);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, >,
+ !expectedUnordered && expectedLess);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, <=,
+ !expectedUnordered && !expectedLess);
+ CHECK_RUNTIME_CREF(CHECK_RUNTIME_3WAY, rhs, lhs, >=,
+ !expectedUnordered && (expectedEqual || expectedLess));
+ }
+#endif
+}
+
+#ifdef __cpp_lib_three_way_comparison
+#undef CHECK_RUNTIME_3WAY
+#endif
+#undef CHECK_RUNTIME_LR
+#undef CHECK_RUNTIME_CREF
+
+} // namespace QTestPrivate
+
+/*!
+ \internal
+
+ A helper macro that calls QTestPrivate::testEqualityOperators(), checks the
+ test's state after the function is executed, and generates a meaningful
+ debug message with the original file and line numbers if the test has
+ failed.
+*/
+#define QT_TEST_EQUALITY_OPS(Left, Right, Expected) \
+ do { \
+ auto report = qScopeGuard([] { \
+ qDebug("testEqualityOperators(" #Left ", " #Right ", " #Expected ") " \
+ "failed in " __FILE__ " on line %d", __LINE__); \
+ }); \
+ QTestPrivate::testEqualityOperators(Left, Right, Expected); \
+ if (QTest::currentTestFailed()) \
+ return; \
+ report.dismiss(); \
+ } while (false)
+
+/*!
+ \internal
+
+ A helper macro that calls QTestPrivate::testAllComparisonOperators(), checks
+ the test's state after the function is executed, and generates a meaningful
+ debug message with the original file and line numbers if the test has
+ failed.
+*/
+#define QT_TEST_ALL_COMPARISON_OPS(Left, Right, Expected) \
+ do { \
+ auto report = qScopeGuard([] { \
+ qDebug("testAllComparisonOperators(" #Left ", " #Right ", " #Expected ") " \
+ "failed in " __FILE__ " on line %d", __LINE__); \
+ }); \
+ QTestPrivate::testAllComparisonOperators(Left, Right, Expected); \
+ if (QTest::currentTestFailed()) \
+ return; \
+ report.dismiss(); \
+ } while (false)
+
+QT_END_NAMESPACE
+
+#endif // QCOMPARISONTESTHELPER_P_H
diff --git a/src/testlib/qemulationdetector_p.h b/src/testlib/qemulationdetector_p.h
index 85bc39d56a..a4b62818af 100644
--- a/src/testlib/qemulationdetector_p.h
+++ b/src/testlib/qemulationdetector_p.h
@@ -1,5 +1,5 @@
// Copyright (C) 2021 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QEMULATIONDETECTOR_P_H
#define QEMULATIONDETECTOR_P_H
diff --git a/src/testlib/qjunittestlogger.cpp b/src/testlib/qjunittestlogger.cpp
index 8e2b917055..4ee5788bee 100644
--- a/src/testlib/qjunittestlogger.cpp
+++ b/src/testlib/qjunittestlogger.cpp
@@ -9,13 +9,6 @@
#include <QtTest/private/qbenchmark_p.h>
#include <QtTest/private/qtestlog_p.h>
-#ifdef min // windows.h without NOMINMAX is included by the benchmark headers.
-# undef min
-#endif
-#ifdef max
-# undef max
-#endif
-
#include <QtCore/qlibraryinfo.h>
#include <string.h>
diff --git a/src/testlib/qplaintestlogger.cpp b/src/testlib/qplaintestlogger.cpp
index 9f61004c2c..58c7f6bf5b 100644
--- a/src/testlib/qplaintestlogger.cpp
+++ b/src/testlib/qplaintestlogger.cpp
@@ -16,13 +16,6 @@
#include <stdlib.h>
#include <string.h>
-#ifdef min // windows.h without NOMINMAX is included by the benchmark headers.
-# undef min
-#endif
-#ifdef max
-# undef max
-#endif
-
#include <QtCore/QByteArray>
#include <QtCore/qmath.h>
#include <QtCore/QLibraryInfo>
@@ -499,4 +492,13 @@ void QPlainTestLogger::addMessage(MessageTypes type, const QString &message,
printMessage(MessageSource::Other, QTest::ptMessageType2String(type), qPrintable(message), file, line);
}
+bool QPlainTestLogger::isRepeatSupported() const
+{
+ // The plain text logger creates unstructured reports. Such reports are not
+ // parser friendly, and are unlikely to be parsed by any test reporting
+ // tools. We can therefore allow repeated test runs with minimum risk that
+ // any parsers fails to handle repeated test names.
+ return true;
+}
+
QT_END_NAMESPACE
diff --git a/src/testlib/qplaintestlogger_p.h b/src/testlib/qplaintestlogger_p.h
index 13228a7631..819a54fd50 100644
--- a/src/testlib/qplaintestlogger_p.h
+++ b/src/testlib/qplaintestlogger_p.h
@@ -43,6 +43,8 @@ public:
void addMessage(MessageTypes type, const QString &message,
const char *file = nullptr, int line = 0) override;
+ bool isRepeatSupported() const override;
+
private:
enum class MessageSource {
Incident,
diff --git a/src/testlib/qpropertytesthelper_p.h b/src/testlib/qpropertytesthelper_p.h
index f2cb82cdd7..c691802a39 100644
--- a/src/testlib/qpropertytesthelper_p.h
+++ b/src/testlib/qpropertytesthelper_p.h
@@ -84,6 +84,14 @@ namespace QTestPrivate {
allocate its returned string using \c {new char[]}, so that it can be used
in place of \l {QTest::toString()}.
+ The \a helperConstructor method is used to create another instance of
+ \c TestedClass. This instance is used to test for binding loops. By default,
+ the method returns a default-constructed \c TestedClass. A custom
+ \a helperConstructor should be provided if \c TestedClass is not
+ default-constructible. Some very specific properties cannot be tested for
+ binding loops. Pass a lambda that returns an \c {std::nullptr} as
+ \a helperConstructor in such case.
+
\note Any test calling this method will need to call
\code
if (QTest::currentTestFailed())
@@ -100,7 +108,9 @@ void testReadWritePropertyBasics(
std::function<bool(const PropertyType &, const PropertyType &)> comparator =
[](const PropertyType &lhs, const PropertyType &rhs) { return lhs == rhs; },
std::function<char *(const PropertyType &)> represent =
- [](const PropertyType &val) { return QTest::toString(val); })
+ [](const PropertyType &val) { return QTest::toString(val); },
+ std::function<std::unique_ptr<TestedClass>(void)> helperConstructor =
+ []() { return std::make_unique<TestedClass>(); })
{
// get the property
const QMetaObject *metaObject = instance.metaObject();
@@ -189,6 +199,45 @@ void testReadWritePropertyBasics(
// value didn't change -> the signal should not be emitted
if (spy)
QCOMPARE(spy->size(), 4);
+
+ // test binding loop
+ if (std::unique_ptr<TestedClass> helperObj = helperConstructor()) {
+ // Reset to 'initial', so that the binding loop test could check the
+ // 'changed' value, because some tests already rely on the 'instance' to
+ // have the 'changed' value once this test passes
+ testedObj.setProperty(propertyName, QVariant::fromValue(initial));
+ const QPropertyBinding<PropertyType> binding([&]() {
+ QObject *obj = static_cast<QObject *>(helperObj.get());
+ obj->setProperty(propertyName, QVariant::fromValue(changed));
+ return obj->property(propertyName).template value<PropertyType>();
+ }, {});
+ bindable.setBinding(binding);
+ QPROPERTY_TEST_COMPARISON_HELPER(
+ testedObj.property(propertyName).template value<PropertyType>(), changed,
+ comparator, represent);
+ QVERIFY2(!binding.error().hasError(), qPrintable(binding.error().description()));
+ }
+}
+
+/*!
+ \internal
+ \overload
+
+ This overload supports the case where the caller only needs to override
+ the default for \a helperConstructor. It uses the defaults for all the other
+ parameters.
+*/
+template<typename TestedClass, typename PropertyType>
+void testReadWritePropertyBasics(
+ TestedClass &instance, const PropertyType &initial, const PropertyType &changed,
+ const char *propertyName,
+ std::function<std::unique_ptr<TestedClass>(void)> helperConstructor)
+{
+ testReadWritePropertyBasics<TestedClass, PropertyType>(
+ instance, initial, changed, propertyName,
+ [](const PropertyType &lhs, const PropertyType &rhs) { return lhs == rhs; },
+ [](const PropertyType &val) { return QTest::toString(val); },
+ helperConstructor);
}
/*!
@@ -224,6 +273,14 @@ void testReadWritePropertyBasics(
allocate its returned string using \c {new char[]}, so that it can be used
in place of \l {QTest::toString()}.
+ The \a helperConstructor method is used to create another instance of
+ \c TestedClass. This instance is used to test for binding loops. By default,
+ the method returns a default-constructed \c TestedClass. A custom
+ \a helperConstructor should be provided if \c TestedClass is not
+ default-constructible. Some very specific properties cannot be tested for
+ binding loops. Pass a lambda that returns an \c {std::nullptr} as
+ \a helperConstructor in such case.
+
\note Any test calling this method will need to call
\code
if (QTest::currentTestFailed())
@@ -242,7 +299,9 @@ void testWriteOncePropertyBasics(
std::function<bool(const PropertyType &, const PropertyType &)> comparator =
[](const PropertyType &lhs, const PropertyType &rhs) { return lhs == rhs; },
std::function<char *(const PropertyType &)> represent =
- [](const PropertyType &val) { return QTest::toString(val); })
+ [](const PropertyType &val) { return QTest::toString(val); },
+ std::function<std::unique_ptr<TestedClass>(void)> helperConstructor =
+ []() { return std::make_unique<TestedClass>(); })
{
// get the property
const QMetaObject *metaObject = instance.metaObject();
@@ -276,10 +335,19 @@ void testWriteOncePropertyBasics(
propObserver.setBinding(bindable.makeBinding());
QPROPERTY_TEST_COMPARISON_HELPER(propObserver.value(), prior, comparator, represent);
- // Create a binding that sets the 'changed' value to the property
- QProperty<PropertyType> propSetter(changed);
+ // Create a binding that sets the 'changed' value to the property.
+ // This also tests binding loops.
QVERIFY(!bindable.hasBinding());
- bindable.setBinding(Qt::makePropertyBinding(propSetter));
+ std::unique_ptr<TestedClass> helperObj = helperConstructor();
+ QProperty<PropertyType> propSetter(changed); // if the helperConstructor() returns nullptr
+ const QPropertyBinding<PropertyType> binding = helperObj
+ ? Qt::makePropertyBinding([&]() {
+ QObject *obj = static_cast<QObject *>(helperObj.get());
+ obj->setProperty(propertyName, QVariant::fromValue(changed));
+ return obj->property(propertyName).template value<PropertyType>();
+ })
+ : Qt::makePropertyBinding(propSetter);
+ bindable.setBinding(binding);
QVERIFY(bindable.hasBinding());
QPROPERTY_TEST_COMPARISON_HELPER(
@@ -303,6 +371,27 @@ void testWriteOncePropertyBasics(
QVERIFY(!bindable.hasBinding());
}
+/*!
+ \internal
+ \overload
+
+ This overload supports the case where the caller only needs to override
+ the default for \a helperConstructor. It uses the defaults for all the other
+ parameters.
+*/
+template<typename TestedClass, typename PropertyType>
+void testWriteOncePropertyBasics(
+ TestedClass &instance, const PropertyType &prior, const PropertyType &changed,
+ const char *propertyName,
+ bool bindingPreservedOnWrite,
+ std::function<std::unique_ptr<TestedClass>(void)> helperConstructor)
+{
+ testWriteOncePropertyBasics<TestedClass, PropertyType>(
+ instance, prior, changed, propertyName, bindingPreservedOnWrite,
+ [](const PropertyType &lhs, const PropertyType &rhs) { return lhs == rhs; },
+ [](const PropertyType &val) { return QTest::toString(val); },
+ helperConstructor);
+}
/*!
\internal
diff --git a/src/testlib/qsignaldumper.cpp b/src/testlib/qsignaldumper.cpp
index 86c6c521ff..9a6412ffc2 100644
--- a/src/testlib/qsignaldumper.cpp
+++ b/src/testlib/qsignaldumper.cpp
@@ -24,10 +24,21 @@ inline static void qPrintMessage(const QByteArray &ba)
}
Q_GLOBAL_STATIC(QList<QByteArray>, ignoreClasses)
-static int iLevel = 0;
-static int ignoreLevel = 0;
+Q_CONSTINIT static QBasicMutex ignoreClassesMutex;
+Q_CONSTINIT thread_local int iLevel = 0;
+Q_CONSTINIT thread_local int ignoreLevel = 0;
enum { IndentSpacesCount = 4 };
+static bool classIsIgnored(const char *className)
+{
+ if (Q_LIKELY(!ignoreClasses.exists()))
+ return false;
+ QMutexLocker locker(&ignoreClassesMutex);
+ if (ignoreClasses()->isEmpty())
+ return false;
+ return ignoreClasses()->contains(QByteArrayView(className));
+}
+
static void qSignalDumperCallback(QObject *caller, int signal_index, void **argv)
{
Q_ASSERT(caller);
@@ -38,7 +49,7 @@ static void qSignalDumperCallback(QObject *caller, int signal_index, void **argv
QMetaMethod member = QMetaObjectPrivate::signal(mo, signal_index);
Q_ASSERT(member.isValid());
- if (QTest::ignoreClasses() && QTest::ignoreClasses()->contains(mo->className())) {
+ if (classIsIgnored(mo->className())) {
++QTest::ignoreLevel;
return;
}
@@ -98,8 +109,7 @@ static void qSignalDumperCallbackSlot(QObject *caller, int method_index, void **
if (!member.isValid())
return;
- if (QTest::ignoreLevel ||
- (QTest::ignoreClasses() && QTest::ignoreClasses()->contains(mo->className())))
+ if (QTest::ignoreLevel || classIsIgnored(mo->className()))
return;
QByteArray str;
@@ -122,8 +132,7 @@ static void qSignalDumperCallbackSlot(QObject *caller, int method_index, void **
static void qSignalDumperCallbackEndSignal(QObject *caller, int /*signal_index*/)
{
Q_ASSERT(caller); Q_ASSERT(caller->metaObject());
- if (QTest::ignoreClasses()
- && QTest::ignoreClasses()->contains(caller->metaObject()->className())) {
+ if (classIsIgnored(caller->metaObject()->className())) {
--QTest::ignoreLevel;
Q_ASSERT(QTest::ignoreLevel >= 0);
return;
@@ -156,13 +165,15 @@ void QSignalDumper::endDump()
void QSignalDumper::ignoreClass(const QByteArray &klass)
{
+ QMutexLocker locker(&QTest::ignoreClassesMutex);
if (QTest::ignoreClasses())
QTest::ignoreClasses()->append(klass);
}
void QSignalDumper::clearIgnoredClasses()
{
- if (QTest::ignoreClasses())
+ QMutexLocker locker(&QTest::ignoreClassesMutex);
+ if (QTest::ignoreClasses.exists())
QTest::ignoreClasses()->clear();
}
diff --git a/src/testlib/qsignalspy.cpp b/src/testlib/qsignalspy.cpp
new file mode 100644
index 0000000000..a45ca59378
--- /dev/null
+++ b/src/testlib/qsignalspy.cpp
@@ -0,0 +1,318 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qsignalspy.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSignalSpy
+ \inmodule QtTest
+
+ \brief The QSignalSpy class enables introspection of signal emission.
+
+ QSignalSpy can connect to any signal of any object and records its emission.
+ QSignalSpy itself is a list of QVariant lists. Each emission of the signal
+ will append one item to the list, containing the arguments of the signal.
+
+ The following example records all signal emissions for the \c clicked() signal
+ of a QCheckBox:
+
+ \snippet code/doc_src_qsignalspy.cpp 0
+
+ \c{spy.takeFirst()} returns the arguments for the first emitted signal, as a
+ list of QVariant objects. The \c clicked() signal has a single bool argument,
+ which is stored as the first entry in the list of arguments.
+
+ The example below catches a signal from a custom object:
+
+ \snippet code/doc_src_qsignalspy.cpp 1
+
+ \note Non-standard data types need to be registered, using
+ the qRegisterMetaType() function, before you can create a
+ QSignalSpy. For example:
+
+ \snippet code/doc_src_qsignalspy.cpp 2
+
+ To retrieve the instance, you can use qvariant_cast:
+
+ \snippet code/doc_src_qsignalspy.cpp 3
+
+ \section1 Verifying Signal Emissions
+
+ The QSignalSpy class provides an elegant mechanism for capturing the list
+ of signals emitted by an object. However, you should verify its validity
+ after construction. The constructor does a number of sanity checks, such as
+ verifying that the signal to be spied upon actually exists. To make the
+ diagnosis of test failures easier, the results of these checks should be
+ checked by calling \c QVERIFY(spy.isValid()) before proceeding further with
+ a test.
+
+ \sa QVERIFY()
+ */
+
+/*! \fn QSignalSpy::QSignalSpy(const QObject *object, const char *signal)
+
+ Constructs a new QSignalSpy that listens for emissions of the \a signal
+ from the QObject \a object. If QSignalSpy is not able to listen for a
+ valid signal (for example, because \a object is \nullptr or \a signal does
+ not denote a valid signal of \a object), an explanatory warning message
+ will be output using qWarning() and subsequent calls to \c isValid() will
+ return false.
+
+ Example:
+ \snippet code/doc_src_qsignalspy.cpp 4
+*/
+
+/*! \fn template <typename PointerToMemberFunction> QSignalSpy::QSignalSpy(const QObject *object, PointerToMemberFunction signal)
+ \since 5.4
+
+ Constructs a new QSignalSpy that listens for emissions of the \a signal
+ from the QObject \a object. If QSignalSpy is not able to listen for a
+ valid signal (for example, because \a object is \nullptr or \a signal does
+ not denote a valid signal of \a object), an explanatory warning message
+ will be output using qWarning() and subsequent calls to \c isValid() will
+ return false.
+
+ Example:
+ \snippet code/doc_src_qsignalspy.cpp 6
+*/
+
+/*! \fn QSignalSpy::QSignalSpy(const QObject *obj, QMetaMethod signal)
+ \since 5.14
+
+ Constructs a new QSignalSpy that listens for emissions of the \a signal
+ from the QObject \a obj. If QSignalSpy is not able to listen for a
+ valid signal (for example, because \a obj is \nullptr or \a signal does
+ not denote a valid signal of \a obj), an explanatory warning message
+ will be output using qWarning() and subsequent calls to \c isValid() will
+ return false.
+
+ This constructor is convenient to use when Qt's meta-object system is
+ heavily used in a test.
+
+ Basic usage example:
+ \snippet code/doc_src_qsignalspy.cpp 7
+
+ Imagine we need to check whether all properties of the QWindow class
+ that represent minimum and maximum dimensions are properly writable.
+ The following example demonstrates one of the approaches:
+ \snippet code/doc_src_qsignalspy.cpp 8
+*/
+
+/*! \fn QSignalSpy::isValid() const
+
+ Returns \c true if the signal spy listens to a valid signal, otherwise false.
+*/
+
+/*! \fn QSignalSpy::signal() const
+
+ Returns the normalized signal the spy is currently listening to.
+*/
+
+/*! \fn bool QSignalSpy::wait(int timeout)
+ \since 5.0
+
+ This is an overloaded function, equivalent passing \a timeout to the
+ chrono overload:
+ \code
+ wait(std::chrono::milliseconds{timeout});
+ \endcode
+
+ Returns \c true if the signal was emitted at least once in \a timeout,
+ otherwise returns \c false.
+*/
+
+/*!
+ \since 6.6
+
+ Starts an event loop that runs until the given signal is received
+ or \a timeout has passed, whichever happens first.
+
+ \a timeout is any valid std::chrono::duration (std::chrono::seconds,
+ std::chrono::milliseconds ...etc).
+
+ Returns \c true if the signal was emitted at least once in \a timeout,
+ otherwise returns \c false.
+
+ Example:
+ \code
+ using namespace std::chrono_literals;
+ QSignalSpy spy(object, signal);
+ spy.wait(2s);
+ \endcode
+*/
+bool QSignalSpy::wait(std::chrono::milliseconds timeout)
+{
+ QMutexLocker locker(&m_mutex);
+ Q_ASSERT(!m_waiting);
+ const qsizetype origCount = size();
+ m_waiting = true;
+ locker.unlock();
+
+ m_loop.enterLoop(timeout);
+
+ locker.relock();
+ m_waiting = false;
+ return size() > origCount;
+}
+
+static bool isSignalMetaMethodValid(QMetaMethod signal)
+{
+ if (!signal.isValid()) {
+ qWarning("QSignalSpy: Null signal is not valid");
+ return false;
+ }
+
+ if (signal.methodType() != QMetaMethod::Signal) {
+ qWarning("QSignalSpy: Not a signal: '%s'", signal.methodSignature().constData());
+ return false;
+ }
+
+ return true;
+}
+
+static bool isObjectValid(const QObject *object)
+{
+ const bool valid = !!object;
+
+ if (!valid)
+ qWarning("QSignalSpy: Cannot spy on a null object");
+
+ return valid;
+}
+
+QSignalSpy::ObjectSignal QSignalSpy::verify(const QObject *obj, const char *aSignal)
+{
+ if (!isObjectValid(obj))
+ return {};
+
+ if (!aSignal) {
+ qWarning("QSignalSpy: Null signal name is not valid");
+ return {};
+ }
+
+ if (((aSignal[0] - '0') & 0x03) != QSIGNAL_CODE) {
+ qWarning("QSignalSpy: Not a valid signal, use the SIGNAL macro");
+ return {};
+ }
+
+ const QByteArray ba = QMetaObject::normalizedSignature(aSignal + 1);
+ const QMetaObject * const mo = obj->metaObject();
+ const int sigIndex = mo->indexOfMethod(ba.constData());
+ if (sigIndex < 0) {
+ qWarning("QSignalSpy: No such signal: '%s'", ba.constData());
+ return {};
+ }
+
+ return verify(obj, mo->method(sigIndex));
+}
+
+QSignalSpy::ObjectSignal QSignalSpy::verify(const QObject *obj, QMetaMethod signal)
+{
+ if (isObjectValid(obj) && isSignalMetaMethodValid(signal))
+ return {obj, signal};
+ else
+ return {};
+}
+
+QList<int> QSignalSpy::makeArgs(const QMetaMethod &member, const QObject *obj)
+{
+ QList<int> result;
+ result.reserve(member.parameterCount());
+ for (int i = 0; i < member.parameterCount(); ++i) {
+ QMetaType tp = member.parameterMetaType(i);
+ if (!tp.isValid() && obj) {
+ void *argv[] = { &tp, &i };
+ QMetaObject::metacall(const_cast<QObject*>(obj),
+ QMetaObject::RegisterMethodArgumentMetaType,
+ member.methodIndex(), argv);
+ }
+ if (!tp.isValid()) {
+ qWarning("QSignalSpy: Unable to handle parameter '%s' of type '%s' of method '%s',"
+ " use qRegisterMetaType to register it.",
+ member.parameterNames().at(i).constData(),
+ member.parameterTypes().at(i).constData(),
+ member.name().constData());
+ }
+ result.append(tp.id());
+ }
+ return result;
+}
+
+class QSignalSpyPrivate : public QObject
+{
+ QSignalSpy * const q;
+public:
+ explicit QSignalSpyPrivate(QSignalSpy *qq) : q(qq) {}
+
+ int qt_metacall(QMetaObject::Call call, int methodId, void **a) override;
+};
+
+QSignalSpy::QSignalSpy(ObjectSignal os)
+ : args(os.obj ? makeArgs(os.sig, os.obj) : QList<int>{})
+{
+ if (!os.obj)
+ return;
+
+ auto i = std::make_unique<QSignalSpyPrivate>(this);
+
+ const auto signalIndex = os.sig.methodIndex();
+ const auto slotIndex = QObject::staticMetaObject.methodCount();
+ if (!QMetaObject::connect(os.obj, signalIndex,
+ i.get(), slotIndex, Qt::DirectConnection)) {
+ qWarning("QSignalSpy: QMetaObject::connect returned false. Unable to connect.");
+ return;
+ }
+
+ d_ptr = std::move(i);
+
+ sig = os.sig.methodSignature();
+}
+
+/*!
+ Destructor.
+*/
+QSignalSpy::~QSignalSpy()
+ = default;
+
+void QSignalSpy::appendArgs(void **a)
+{
+ QList<QVariant> list;
+ list.reserve(args.size());
+ for (qsizetype i = 0; i < args.size(); ++i) {
+ const QMetaType::Type type = static_cast<QMetaType::Type>(args.at(i));
+ if (type == QMetaType::QVariant)
+ list << *reinterpret_cast<QVariant *>(a[i + 1]);
+ else
+ list << QVariant(QMetaType(type), a[i + 1]);
+ }
+ QMutexLocker locker(&m_mutex);
+ append(std::move(list));
+
+ if (m_waiting) {
+ locker.unlock();
+ m_loop.exitLoop();
+ }
+}
+
+/*!
+ \reimp
+ \internal
+*/
+int QSignalSpyPrivate::qt_metacall(QMetaObject::Call call, int methodId, void **a)
+{
+ methodId = QObject::qt_metacall(call, methodId, a);
+ if (methodId < 0)
+ return methodId;
+
+ if (call == QMetaObject::InvokeMetaMethod) {
+ if (methodId == 0) {
+ q->appendArgs(a);
+ }
+ --methodId;
+ }
+ return methodId;
+}
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qsignalspy.h b/src/testlib/qsignalspy.h
index b72c3b4b53..591545b4d5 100644
--- a/src/testlib/qsignalspy.h
+++ b/src/testlib/qsignalspy.h
@@ -6,90 +6,40 @@
#include <QtCore/qbytearray.h>
#include <QtCore/qlist.h>
-#include <QtCore/qobject.h>
#include <QtCore/qmetaobject.h>
#include <QtTest/qtesteventloop.h>
#include <QtCore/qvariant.h>
+#include <QtCore/qmutex.h>
+
+#include <memory>
QT_BEGIN_NAMESPACE
class QVariant;
-
-class QSignalSpy: public QObject, public QList<QList<QVariant> >
+class QSignalSpyPrivate;
+class QSignalSpy : public QList<QList<QVariant> >
{
+ struct ObjectSignal {
+ const QObject *obj;
+ QMetaMethod sig;
+ };
+ friend class QSignalSpyPrivate;
+ std::unique_ptr<QSignalSpyPrivate> d_ptr;
public:
explicit QSignalSpy(const QObject *obj, const char *aSignal)
- : m_waiting(false)
- {
- if (!isObjectValid(obj))
- return;
-
- if (!aSignal) {
- qWarning("QSignalSpy: Null signal name is not valid");
- return;
- }
-
- if (((aSignal[0] - '0') & 0x03) != QSIGNAL_CODE) {
- qWarning("QSignalSpy: Not a valid signal, use the SIGNAL macro");
- return;
- }
-
- const QByteArray ba = QMetaObject::normalizedSignature(aSignal + 1);
- const QMetaObject * const mo = obj->metaObject();
- const int sigIndex = mo->indexOfMethod(ba.constData());
- if (sigIndex < 0) {
- qWarning("QSignalSpy: No such signal: '%s'", ba.constData());
- return;
- }
-
- if (!connectToSignal(obj, sigIndex))
- return;
-
- sig = ba;
- initArgs(mo->method(sigIndex), obj);
- }
-
+ : QSignalSpy(verify(obj, aSignal)) {}
#ifdef Q_QDOC
template <typename PointerToMemberFunction>
QSignalSpy(const QObject *object, PointerToMemberFunction signal);
#else
template <typename Func>
QSignalSpy(const typename QtPrivate::FunctionPointer<Func>::Object *obj, Func signal0)
- : m_waiting(false)
- {
- if (!isObjectValid(obj))
- return;
-
- if (!signal0) {
- qWarning("QSignalSpy: Null signal name is not valid");
- return;
- }
-
- const QMetaObject * const mo = obj->metaObject();
- const QMetaMethod signalMetaMethod = QMetaMethod::fromSignal(signal0);
- const int sigIndex = signalMetaMethod.methodIndex();
-
- if (!isSignalMetaMethodValid(signalMetaMethod))
- return;
-
- if (!connectToSignal(obj, sigIndex))
- return;
-
- sig = signalMetaMethod.methodSignature();
- initArgs(mo->method(sigIndex), obj);
- }
+ : QSignalSpy(verify(obj, QMetaMethod::fromSignal(signal0))) {}
#endif // Q_QDOC
-
- QSignalSpy(const QObject *obj, const QMetaMethod &signal)
- : m_waiting(false)
- {
- if (isObjectValid(obj) && isSignalMetaMethodValid(signal) &&
- connectToSignal(obj, signal.methodIndex())) {
- sig = signal.methodSignature();
- initArgs(signal, obj);
- }
- }
+ QSignalSpy(const QObject *obj, QMetaMethod signal)
+ : QSignalSpy(verify(obj, signal)) {}
+ Q_TESTLIB_EXPORT ~QSignalSpy();
inline bool isValid() const { return !sig.isEmpty(); }
inline QByteArray signal() const { return sig; }
@@ -97,110 +47,25 @@ public:
bool wait(int timeout)
{ return wait(std::chrono::milliseconds{timeout}); }
- bool wait(std::chrono::milliseconds timeout = std::chrono::seconds{5})
- {
- Q_ASSERT(!m_waiting);
- const qsizetype origCount = size();
- m_waiting = true;
- m_loop.enterLoop(timeout);
- m_waiting = false;
- return size() > origCount;
- }
-
- int qt_metacall(QMetaObject::Call call, int methodId, void **a) override
- {
- methodId = QObject::qt_metacall(call, methodId, a);
- if (methodId < 0)
- return methodId;
-
- if (call == QMetaObject::InvokeMetaMethod) {
- if (methodId == 0) {
- appendArgs(a);
- }
- --methodId;
- }
- return methodId;
- }
+ Q_TESTLIB_EXPORT bool wait(std::chrono::milliseconds timeout = std::chrono::seconds{5});
private:
- bool connectToSignal(const QObject *sender, int sigIndex)
- {
- static const int memberOffset = QObject::staticMetaObject.methodCount();
- const bool connected = QMetaObject::connect(
- sender, sigIndex, this, memberOffset, Qt::DirectConnection, nullptr);
-
- if (!connected)
- qWarning("QSignalSpy: QMetaObject::connect returned false. Unable to connect.");
-
- return connected;
- }
-
- static bool isSignalMetaMethodValid(const QMetaMethod &signal)
- {
- const bool valid = signal.isValid() && signal.methodType() == QMetaMethod::Signal;
-
- if (!valid)
- qWarning("QSignalSpy: Not a valid signal: '%s'", signal.methodSignature().constData());
-
- return valid;
- }
-
- static bool isObjectValid(const QObject *object)
- {
- const bool valid = !!object;
-
- if (!valid)
- qWarning("QSignalSpy: Cannot spy on a null object");
-
- return valid;
- }
-
- void initArgs(const QMetaMethod &member, const QObject *obj)
- {
- args.reserve(member.parameterCount());
- for (int i = 0; i < member.parameterCount(); ++i) {
- QMetaType tp = member.parameterMetaType(i);
- if (!tp.isValid() && obj) {
- void *argv[] = { &tp, &i };
- QMetaObject::metacall(const_cast<QObject*>(obj),
- QMetaObject::RegisterMethodArgumentMetaType,
- member.methodIndex(), argv);
- }
- if (!tp.isValid()) {
- qWarning("QSignalSpy: Unable to handle parameter '%s' of type '%s' of method '%s',"
- " use qRegisterMetaType to register it.",
- member.parameterNames().at(i).constData(),
- member.parameterTypes().at(i).constData(),
- member.name().constData());
- }
- args << tp.id();
- }
- }
-
- void appendArgs(void **a)
- {
- QList<QVariant> list;
- list.reserve(args.size());
- for (int i = 0; i < args.size(); ++i) {
- const QMetaType::Type type = static_cast<QMetaType::Type>(args.at(i));
- if (type == QMetaType::QVariant)
- list << *reinterpret_cast<QVariant *>(a[i + 1]);
- else
- list << QVariant(QMetaType(type), a[i + 1]);
- }
- append(list);
-
- if (m_waiting)
- m_loop.exitLoop();
- }
+ Q_TESTLIB_EXPORT explicit QSignalSpy(ObjectSignal os);
+
+ Q_TESTLIB_EXPORT static ObjectSignal verify(const QObject *obj, QMetaMethod signal);
+ Q_TESTLIB_EXPORT static ObjectSignal verify(const QObject *obj, const char *aSignal);
+
+ Q_TESTLIB_EXPORT static QList<int> makeArgs(const QMetaMethod &member, const QObject *obj);
+ Q_TESTLIB_EXPORT void appendArgs(void **a);
// the full, normalized signal name
QByteArray sig;
// holds the QMetaType types for the argument list of the signal
- QList<int> args;
+ const QList<int> args;
QTestEventLoop m_loop;
- bool m_waiting;
+ bool m_waiting = false;
+ QMutex m_mutex; // protects m_waiting and the QList base class, between appendArgs() and wait()
};
QT_END_NAMESPACE
diff --git a/src/testlib/qsignalspy.qdoc b/src/testlib/qsignalspy.qdoc
deleted file mode 100644
index e9c213f781..0000000000
--- a/src/testlib/qsignalspy.qdoc
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright (C) 2019 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
-
-/*!
- \class QSignalSpy
- \inmodule QtTest
-
- \brief The QSignalSpy class enables introspection of signal emission.
-
- QSignalSpy can connect to any signal of any object and records its emission.
- QSignalSpy itself is a list of QVariant lists. Each emission of the signal
- will append one item to the list, containing the arguments of the signal.
-
- The following example records all signal emissions for the \c clicked() signal
- of a QCheckBox:
-
- \snippet code/doc_src_qsignalspy.cpp 0
-
- \c{spy.takeFirst()} returns the arguments for the first emitted signal, as a
- list of QVariant objects. The \c clicked() signal has a single bool argument,
- which is stored as the first entry in the list of arguments.
-
- The example below catches a signal from a custom object:
-
- \snippet code/doc_src_qsignalspy.cpp 1
-
- \note Non-standard data types need to be registered, using
- the qRegisterMetaType() function, before you can create a
- QSignalSpy. For example:
-
- \snippet code/doc_src_qsignalspy.cpp 2
-
- To retrieve the instance, you can use qvariant_cast:
-
- \snippet code/doc_src_qsignalspy.cpp 3
-
- \section1 Verifying Signal Emissions
-
- The QSignalSpy class provides an elegant mechanism for capturing the list
- of signals emitted by an object. However, you should verify its validity
- after construction. The constructor does a number of sanity checks, such as
- verifying that the signal to be spied upon actually exists. To make the
- diagnosis of test failures easier, the results of these checks should be
- checked by calling \c QVERIFY(spy.isValid()) before proceeding further with
- a test.
-
- \sa QVERIFY()
- */
-
-/*! \fn QSignalSpy::QSignalSpy(const QObject *object, const char *signal)
-
- Constructs a new QSignalSpy that listens for emissions of the \a signal
- from the QObject \a object. If QSignalSpy is not able to listen for a
- valid signal (for example, because \a object is \nullptr or \a signal does
- not denote a valid signal of \a object), an explanatory warning message
- will be output using qWarning() and subsequent calls to \c isValid() will
- return false.
-
- Example:
- \snippet code/doc_src_qsignalspy.cpp 4
-*/
-
-/*! \fn template <typename PointerToMemberFunction> QSignalSpy::QSignalSpy(const QObject *object, PointerToMemberFunction signal)
- \since 5.4
-
- Constructs a new QSignalSpy that listens for emissions of the \a signal
- from the QObject \a object. If QSignalSpy is not able to listen for a
- valid signal (for example, because \a object is \nullptr or \a signal does
- not denote a valid signal of \a object), an explanatory warning message
- will be output using qWarning() and subsequent calls to \c isValid() will
- return false.
-
- Example:
- \snippet code/doc_src_qsignalspy.cpp 6
-*/
-
-/*! \fn QSignalSpy::QSignalSpy(const QObject *obj, const QMetaMethod &signal)
- \since 5.14
-
- Constructs a new QSignalSpy that listens for emissions of the \a signal
- from the QObject \a obj. If QSignalSpy is not able to listen for a
- valid signal (for example, because \a obj is \nullptr or \a signal does
- not denote a valid signal of \a obj), an explanatory warning message
- will be output using qWarning() and subsequent calls to \c isValid() will
- return false.
-
- This constructor is convenient to use when Qt's meta-object system is
- heavily used in a test.
-
- Basic usage example:
- \snippet code/doc_src_qsignalspy.cpp 7
-
- Imagine we need to check whether all properties of the QWindow class
- that represent minimum and maximum dimensions are properly writable.
- The following example demonstrates one of the approaches:
- \snippet code/doc_src_qsignalspy.cpp 8
-*/
-
-/*! \fn QSignalSpy::isValid() const
-
- Returns \c true if the signal spy listens to a valid signal, otherwise false.
-*/
-
-/*! \fn QSignalSpy::signal() const
-
- Returns the normalized signal the spy is currently listening to.
-*/
-
-/*! \fn int QSignalSpy::qt_metacall(QMetaObject::Call call, int id, void **a)
- \internal
-*/
-
-/*! \fn bool QSignalSpy::wait(int timeout)
- \since 5.0
-
- This is an overloaded function, equivalent passing \a timeout to the
- chrono overload:
- \code
- wait(std::chrono::milliseconds{timeout});
- \endcode
-
- Returns \c true if the signal was emitted at least once in \a timeout,
- otherwise returns \c false.
-*/
-
-/*! \fn bool QSignalSpy::wait(std::chrono::milliseconds timeout)
- \since 6.6
-
- Starts an event loop that runs until the given signal is received
- or \a timeout has passed, whichever happens first.
-
- \a timeout is any valid std::chrono::duration (std::chrono::seconds,
- std::chrono::milliseconds ...etc).
-
- Returns \c true if the signal was emitted at least once in \a timeout,
- otherwise returns \c false.
-
- Example:
- \code
- using namespace std::chrono_literals;
- QSignalSpy spy(object, signal);
- spy.wait(2s);
- \endcode
-*/
diff --git a/src/testlib/qtest.h b/src/testlib/qtest.h
index 175affebcf..ff3744a48e 100644
--- a/src/testlib/qtest.h
+++ b/src/testlib/qtest.h
@@ -12,34 +12,13 @@
#include <QtTest/qttestglobal.h>
#include <QtTest/qtestcase.h>
#include <QtTest/qtestdata.h>
+#include <QtTest/qtesttostring.h>
#include <QtTest/qbenchmark.h>
-#include <QtCore/qbitarray.h>
-#include <QtCore/qbytearray.h>
-#include <QtCore/qcborarray.h>
-#include <QtCore/qcborcommon.h>
-#include <QtCore/qcbormap.h>
-#include <QtCore/qcborvalue.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qcborcommon.h>
-#include <QtCore/qdatetime.h>
-#if QT_CONFIG(itemmodel)
-#include <QtCore/qabstractitemmodel.h>
-#endif
-#include <QtCore/qobject.h>
-#include <QtCore/qvariant.h>
-#include <QtCore/qurl.h>
-#include <QtCore/quuid.h>
-
#if defined(TESTCASE_LOWDPI)
#include <QtCore/qcoreapplication.h>
#endif
-#include <QtCore/qpoint.h>
-#include <QtCore/qsize.h>
-#include <QtCore/qrect.h>
-
#include <initializer_list>
#include <memory>
@@ -48,346 +27,6 @@ QT_BEGIN_NAMESPACE
namespace QTest
{
-template <> inline char *toString(const QStringView &str)
-{
- return QTest::toPrettyUnicode(str);
-}
-
-template<> inline char *toString(const QString &str)
-{
- return toString(QStringView(str));
-}
-
-template<> inline char *toString(const QLatin1StringView &str)
-{
- return toString(QString(str));
-}
-
-template<> inline char *toString(const QByteArray &ba)
-{
- return QTest::toPrettyCString(ba.constData(), ba.size());
-}
-
-template<> inline char *toString(const QBitArray &ba)
-{
- qsizetype size = ba.size();
- char *str = new char[size + 1];
- for (qsizetype i = 0; i < size; ++i)
- str[i] = "01"[ba.testBit(i)];
- str[size] = '\0';
- return str;
-}
-
-#if QT_CONFIG(datestring)
-template<> inline char *toString(const QTime &time)
-{
- return time.isValid()
- ? qstrdup(qPrintable(time.toString(u"hh:mm:ss.zzz")))
- : qstrdup("Invalid QTime");
-}
-
-template<> inline char *toString(const QDate &date)
-{
- return date.isValid()
- ? qstrdup(qPrintable(date.toString(u"yyyy/MM/dd")))
- : qstrdup("Invalid QDate");
-}
-
-template<> inline char *toString(const QDateTime &dateTime)
-{
- return dateTime.isValid()
- ? qstrdup(qPrintable(dateTime.toString(u"yyyy/MM/dd hh:mm:ss.zzz[t]")))
- : qstrdup("Invalid QDateTime");
-}
-#endif // datestring
-
-template<> inline char *toString(const QCborError &c)
-{
- // use the Q_ENUM formatting
- return toString(c.c);
-}
-
-template<> inline char *toString(const QChar &c)
-{
- const ushort uc = c.unicode();
- if (uc < 128) {
- char msg[32] = {'\0'};
- qsnprintf(msg, sizeof(msg), "QChar: '%c' (0x%x)", char(uc), unsigned(uc));
- return qstrdup(msg);
- }
- return qstrdup(qPrintable(QString::fromLatin1("QChar: '%1' (0x%2)").arg(c).arg(QString::number(static_cast<int>(c.unicode()), 16))));
-}
-
-#if QT_CONFIG(itemmodel)
-template<> inline char *toString(const QModelIndex &idx)
-{
- char msg[128];
- qsnprintf(msg, sizeof(msg), "QModelIndex(%d,%d,%p,%p)", idx.row(), idx.column(), idx.internalPointer(), idx.model());
- return qstrdup(msg);
-}
-#endif
-
-template<> inline char *toString(const QPoint &p)
-{
- char msg[128] = {'\0'};
- qsnprintf(msg, sizeof(msg), "QPoint(%d,%d)", p.x(), p.y());
- return qstrdup(msg);
-}
-
-template<> inline char *toString(const QSize &s)
-{
- char msg[128] = {'\0'};
- qsnprintf(msg, sizeof(msg), "QSize(%dx%d)", s.width(), s.height());
- return qstrdup(msg);
-}
-
-template<> inline char *toString(const QRect &s)
-{
- char msg[256] = {'\0'};
- qsnprintf(msg, sizeof(msg), "QRect(%d,%d %dx%d) (bottomright %d,%d)",
- s.left(), s.top(), s.width(), s.height(), s.right(), s.bottom());
- return qstrdup(msg);
-}
-
-template<> inline char *toString(const QPointF &p)
-{
- char msg[64] = {'\0'};
- qsnprintf(msg, sizeof(msg), "QPointF(%g,%g)", p.x(), p.y());
- return qstrdup(msg);
-}
-
-template<> inline char *toString(const QSizeF &s)
-{
- char msg[64] = {'\0'};
- qsnprintf(msg, sizeof(msg), "QSizeF(%gx%g)", s.width(), s.height());
- return qstrdup(msg);
-}
-
-template<> inline char *toString(const QRectF &s)
-{
- char msg[256] = {'\0'};
- qsnprintf(msg, sizeof(msg), "QRectF(%g,%g %gx%g) (bottomright %g,%g)",
- s.left(), s.top(), s.width(), s.height(), s.right(), s.bottom());
- return qstrdup(msg);
-}
-
-template<> inline char *toString(const QUrl &uri)
-{
- if (!uri.isValid())
- return qstrdup(qPrintable(QLatin1StringView("Invalid URL: ") + uri.errorString()));
- 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(");
- if (v.isValid()) {
- QByteArray type(v.typeName());
- if (type.isEmpty()) {
- type = QByteArray::number(v.userType());
- }
- vstring.append(type);
- if (!v.isNull()) {
- vstring.append(',');
- if (v.canConvert<QString>()) {
- vstring.append(v.toString().toLocal8Bit());
- }
- else {
- vstring.append("<value not representable as string>");
- }
- }
- }
- vstring.append(')');
-
- return qstrdup(vstring.constData());
-}
-
-template<> inline char *toString(const QPartialOrdering &o)
-{
- if (o == QPartialOrdering::Less)
- return qstrdup("Less");
- if (o == QPartialOrdering::Equivalent)
- return qstrdup("Equivalent");
- if (o == QPartialOrdering::Greater)
- return qstrdup("Greater");
- if (o == QPartialOrdering::Unordered)
- return qstrdup("Unordered");
- return qstrdup("<invalid>");
-}
-
-namespace Internal {
-struct QCborValueFormatter
-{
- enum { BufferLen = 256 };
- static char *formatSimpleType(QCborSimpleType st)
- {
- char *buf = new char[BufferLen];
- qsnprintf(buf, BufferLen, "QCborValue(QCborSimpleType(%d))", int(st));
- return buf;
- }
-
- static char *formatTag(QCborTag tag, const QCborValue &taggedValue)
- {
- QScopedArrayPointer<char> hold(format(taggedValue));
- char *buf = new char[BufferLen];
- qsnprintf(buf, BufferLen, "QCborValue(QCborTag(%llu), %s)", tag, hold.get());
- return buf;
- }
-
- static char *innerFormat(QCborValue::Type t, const char *str)
- {
- static const QMetaEnum typeEnum = []() {
- int idx = QCborValue::staticMetaObject.indexOfEnumerator("Type");
- return QCborValue::staticMetaObject.enumerator(idx);
- }();
-
- char *buf = new char[BufferLen];
- const char *typeName = typeEnum.valueToKey(t);
- if (typeName)
- qsnprintf(buf, BufferLen, "QCborValue(%s, %s)", typeName, str);
- else
- qsnprintf(buf, BufferLen, "QCborValue(<unknown type 0x%02x>)", t);
- return buf;
- }
-
- template<typename T> static char *format(QCborValue::Type type, const T &t)
- {
- QScopedArrayPointer<char> hold(QTest::toString(t));
- return innerFormat(type, hold.get());
- }
-
- static char *format(const QCborValue &v)
- {
- switch (v.type()) {
- case QCborValue::Integer:
- return format(v.type(), v.toInteger());
- case QCborValue::ByteArray:
- return format(v.type(), v.toByteArray());
- case QCborValue::String:
- return format(v.type(), v.toString());
- case QCborValue::Array:
- return innerFormat(v.type(), QScopedArrayPointer<char>(format(v.toArray())).get());
- case QCborValue::Map:
- return innerFormat(v.type(), QScopedArrayPointer<char>(format(v.toMap())).get());
- case QCborValue::Tag:
- return formatTag(v.tag(), v.taggedValue());
- case QCborValue::SimpleType:
- break;
- case QCborValue::True:
- return qstrdup("QCborValue(true)");
- case QCborValue::False:
- return qstrdup("QCborValue(false)");
- case QCborValue::Null:
- return qstrdup("QCborValue(nullptr)");
- case QCborValue::Undefined:
- return qstrdup("QCborValue()");
- case QCborValue::Double:
- return format(v.type(), v.toDouble());
- case QCborValue::DateTime:
- case QCborValue::Url:
- case QCborValue::RegularExpression:
- return format(v.type(), v.taggedValue().toString());
- case QCborValue::Uuid:
- return format(v.type(), v.toUuid());
- case QCborValue::Invalid:
- return qstrdup("QCborValue(<invalid>)");
- }
-
- if (v.isSimpleType())
- return formatSimpleType(v.toSimpleType());
- return innerFormat(v.type(), "");
- }
-
- static char *format(const QCborArray &a)
- {
- QByteArray out(1, '[');
- const char *comma = "";
- for (QCborValueConstRef v : a) {
- QScopedArrayPointer<char> s(format(v));
- out += comma;
- out += s.get();
- comma = ", ";
- }
- out += ']';
- return qstrdup(out.constData());
- }
-
- static char *format(const QCborMap &m)
- {
- QByteArray out(1, '{');
- const char *comma = "";
- for (auto pair : m) {
- QScopedArrayPointer<char> key(format(pair.first));
- QScopedArrayPointer<char> value(format(pair.second));
- out += comma;
- out += key.get();
- out += ": ";
- out += value.get();
- comma = ", ";
- }
- out += '}';
- return qstrdup(out.constData());
- }
-};
-}
-
-template<> inline char *toString(const QCborValue &v)
-{
- return Internal::QCborValueFormatter::format(v);
-}
-
-template<> inline char *toString(const QCborValueRef &v)
-{
- return toString(QCborValue(v));
-}
-
-template<> inline char *toString(const QCborArray &a)
-{
- return Internal::QCborValueFormatter::format(a);
-}
-
-template<> inline char *toString(const QCborMap &m)
-{
- return Internal::QCborValueFormatter::format(m);
-}
-
-template <typename T1, typename T2>
-inline char *toString(const std::pair<T1, T2> &pair)
-{
- const QScopedArrayPointer<char> first(toString(pair.first));
- const QScopedArrayPointer<char> second(toString(pair.second));
- return formatString("std::pair(", ")", 2, first.data(), second.data());
-}
-
-template <typename Tuple, int... I>
-inline char *toString(const Tuple & tuple, QtPrivate::IndexesList<I...>) {
- using UP = std::unique_ptr<char[]>;
- // Generate a table of N + 1 elements where N is the number of
- // elements in the tuple.
- // The last element is needed to support the empty tuple use case.
- const UP data[] = {
- UP(toString(std::get<I>(tuple)))..., UP{}
- };
- return formatString("std::tuple(", ")", sizeof...(I), data[I].get()...);
-}
-
-template <class... Types>
-inline char *toString(const std::tuple<Types...> &tuple)
-{
- static const std::size_t params_count = sizeof...(Types);
- return toString(tuple, typename QtPrivate::Indexes<params_count>::Value());
-}
-
-inline char *toString(std::nullptr_t)
-{
- return toString(QStringLiteral("nullptr"));
-}
-
template<>
inline bool qCompare(QString const &t1, QLatin1StringView const &t2, const char *actual,
const char *expected, const char *file, int line)
diff --git a/src/testlib/qtest_gui.h b/src/testlib/qtest_gui.h
index 879b142a69..667debb3c4 100644
--- a/src/testlib/qtest_gui.h
+++ b/src/testlib/qtest_gui.h
@@ -17,6 +17,7 @@
#include <QtTest/qtestevent.h>
#include <QtTest/qtestmouse.h>
#include <QtTest/qtesttouch.h>
+#include <QtTest/qtestwheel.h>
#include <QtTest/qtestkeyboard.h>
#include <QtGui/qcolor.h>
diff --git a/src/testlib/qtest_network.h b/src/testlib/qtest_network.h
index 61f80a536c..403a663ae2 100644
--- a/src/testlib/qtest_network.h
+++ b/src/testlib/qtest_network.h
@@ -4,7 +4,7 @@
#ifndef QTEST_NETWORK_H
#define QTEST_NETWORK_H
-#include <QtTest/qtest.h>
+#include <QtTest/qtesttostring.h>
// enable NETWORK features
#ifndef QT_NETWORK_LIB
@@ -43,6 +43,7 @@ inline char *toString<QHostAddress>(const QHostAddress &addr)
return toString(addr.toString());
}
+} // namespace QTest
inline char *toString(QNetworkReply::NetworkError code)
{
@@ -57,7 +58,7 @@ inline char *toString(QNetworkReply::NetworkError code)
inline char *toString(const QNetworkCookie &cookie)
{
- return toString(cookie.toRawForm());
+ return QTest::toString(cookie.toRawForm());
}
inline char *toString(const QList<QNetworkCookie> &list)
@@ -69,11 +70,9 @@ inline char *toString(const QList<QNetworkCookie> &list)
result.chop(2); // remove trailing ", "
}
result.append(')');
- return toString(result);
+ return QTest::toString(result);
}
-} // namespace QTest
-
QT_END_NAMESPACE
#endif
diff --git a/src/testlib/qtest_widgets.h b/src/testlib/qtest_widgets.h
index 2b60d94fd7..90ee3aa6aa 100644
--- a/src/testlib/qtest_widgets.h
+++ b/src/testlib/qtest_widgets.h
@@ -62,15 +62,16 @@ inline QByteArray toString(QSizePolicy sp)
}
} // namespace Internal
+} // namespace QTest
inline char *toString(QSizePolicy::Policy p)
{
- return qstrdup(Internal::toString(p));
+ return qstrdup(QTest::Internal::toString(p));
}
inline char *toString(QSizePolicy::ControlTypes ct)
{
- return qstrdup(Internal::toString(ct).constData());
+ return qstrdup(QTest::Internal::toString(ct).constData());
}
inline char *toString(QSizePolicy::ControlType ct)
@@ -80,11 +81,9 @@ inline char *toString(QSizePolicy::ControlType ct)
inline char *toString(QSizePolicy sp)
{
- return qstrdup(Internal::toString(sp).constData());
+ return qstrdup(QTest::Internal::toString(sp).constData());
}
-} // namespace QTest
-
QT_END_NAMESPACE
#endif
diff --git a/src/testlib/qtestaccessible.h b/src/testlib/qtestaccessible.h
index a9b237bd5d..a4236aa5f3 100644
--- a/src/testlib/qtestaccessible.h
+++ b/src/testlib/qtestaccessible.h
@@ -108,7 +108,7 @@ public:
qWarning("Timeout waiting for accessibility event.");
return false;
}
- const bool res = *eventList().first() == *ev;
+ const bool res = *eventList().constFirst() == *ev;
if (!res)
qWarning("%s", qPrintable(msgAccessibilityEventListMismatch(eventList(), ev)));
delete eventList().takeFirst();
@@ -150,8 +150,8 @@ private:
static void updateHandler(QAccessibleEvent *event)
{
auto ev = copyEvent(event);
- if (ev->object()) {
- QObject::connect(ev->object(), &QObject::destroyed, [&, ev](){
+ if (auto obj = ev->object()) {
+ QObject::connect(obj, &QObject::destroyed, obj, [&, ev](){
auto index= eventList().indexOf(ev);
if (index == -1)
return;
diff --git a/src/testlib/qtestassert.h b/src/testlib/qtestassert.h
index f112d847ae..63ebbed71c 100644
--- a/src/testlib/qtestassert.h
+++ b/src/testlib/qtestassert.h
@@ -8,10 +8,9 @@
QT_BEGIN_NAMESPACE
+#define QTEST_ASSERT(cond) ((cond) ? static_cast<void>(0) : qt_assert(#cond, __FILE__, __LINE__))
-#define QTEST_ASSERT(cond) do { if (!(cond)) qt_assert(#cond,__FILE__,__LINE__); } while (false)
-
-#define QTEST_ASSERT_X(cond, where, what) do { if (!(cond)) qt_assert_x(where, what,__FILE__,__LINE__); } while (false)
+#define QTEST_ASSERT_X(cond, where, what) ((cond) ? static_cast<void>(0) : qt_assert_x(where, what, __FILE__, __LINE__))
QT_END_NAMESPACE
diff --git a/src/testlib/qtestblacklist.cpp b/src/testlib/qtestblacklist.cpp
index 868971fc17..4154f8f2a6 100644
--- a/src/testlib/qtestblacklist.cpp
+++ b/src/testlib/qtestblacklist.cpp
@@ -28,8 +28,7 @@ using namespace Qt::StringLiterals;
Each blacklist line is interpreted as a list of keywords in an AND-relationship.
To blacklist a test for multiple platforms (OR-relationship), use separate lines.
- The key "ci" applies only when run by COIN. The key "cmake" applies when Qt
- is built using CMake. Other keys name platforms, operating systems,
+ The key "ci" applies only when run by COIN. Other keys name platforms, operating systems,
distributions, tool-chains or architectures; a ! prefix reverses what it
checks. A version, joined to a key (at present, only for distributions and
for msvc) with a hyphen, limits the key to the specific version. A keyword
@@ -47,7 +46,8 @@ using namespace Qt::StringLiterals;
data row's name coincides with that of a local data row, some unintended
matches may result; try to keep your data-row tags distinct.)
- Subsequent lines give conditions for ignoring this test.
+ Subsequent lines give conditions for ignoring this test. You need at least
+ one or the group has no effect.
# See qtbase/src/testlib/qtestblacklist.cpp for format
# Test doesn't work on QNX at all
@@ -118,6 +118,9 @@ static QSet<QByteArray> keywords()
#ifdef Q_OS_WATCHOS
<< "watchos"
#endif
+#ifdef Q_OS_VISIONOS
+ << "visionos"
+#endif
#ifdef Q_OS_ANDROID
<< "android"
#endif
@@ -169,8 +172,6 @@ static QSet<QByteArray> keywords()
#ifdef QT_BUILD_INTERNAL
<< "developer-build"
#endif
-
- << "cmake"
;
QCoreApplication *app = QCoreApplication::instance();
@@ -278,7 +279,8 @@ void parseBlackList()
}
}
-void checkBlackLists(const char *slot, const char *data, const char *global)
+// Returns \c true if this test-case is blacklisted.
+bool checkBlackLists(const char *slot, const char *data, const char *global)
{
bool ignore = ignoreAll;
@@ -300,7 +302,7 @@ void checkBlackLists(const char *slot, const char *data, const char *global)
}
}
- QTestResult::setBlacklistCurrentTest(ignore);
+ return ignore;
}
} // QTestPrivate
diff --git a/src/testlib/qtestblacklist_p.h b/src/testlib/qtestblacklist_p.h
index 2bc9b684ab..3bba0e7672 100644
--- a/src/testlib/qtestblacklist_p.h
+++ b/src/testlib/qtestblacklist_p.h
@@ -23,7 +23,7 @@ QT_BEGIN_NAMESPACE
namespace QTestPrivate {
// Export functions so they can also be used by QQuickTest
Q_TESTLIB_EXPORT void parseBlackList();
- Q_TESTLIB_EXPORT void checkBlackLists(const char *slot, const char *data,
+ Q_TESTLIB_EXPORT bool checkBlackLists(const char *slot, const char *data,
const char *global = nullptr);
}
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp
index c6d9dc0340..2ab55cac36 100644
--- a/src/testlib/qtestcase.cpp
+++ b/src/testlib/qtestcase.cpp
@@ -10,7 +10,7 @@
#include <QtCore/qcoreapplication.h>
#include <QtCore/qdebug.h>
#include <QtCore/qdir.h>
-#include <QtCore/qdiriterator.h>
+#include <QtCore/qdirlisting.h>
#include <QtCore/qfile.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qfloat16.h>
@@ -39,6 +39,7 @@
#endif // QT_CONFIG(batch_test_support)
#include <QtTest/private/cycle_p.h>
#include <QtTest/private/qtestblacklist_p.h>
+#include <QtTest/private/qtestcrashhandler_p.h>
#if defined(HAVE_XCTEST)
#include <QtTest/private/qxctestlogger_p.h>
#endif
@@ -64,6 +65,7 @@
#include <memory>
#include <mutex>
#include <numeric>
+#include <optional>
#include <stdarg.h>
#include <stdio.h>
@@ -115,6 +117,10 @@
#include <CoreFoundation/CFPreferences.h>
#endif
+#if defined(Q_OS_WASM)
+#include <emscripten.h>
+#endif
+
#include <vector>
QT_BEGIN_NAMESPACE
@@ -124,335 +130,229 @@ using namespace Qt::StringLiterals;
using QtMiscUtils::toHexUpper;
using QtMiscUtils::fromHex;
-namespace {
-enum DebuggerProgram { None, Gdb, Lldb };
-
-#if defined(Q_OS_UNIX) && (!defined(Q_OS_WASM) || QT_CONFIG(thread))
-static struct iovec IoVec(struct iovec vec)
+static bool installCoverageTool(const char * appname, const char * testname)
{
- return vec;
+#if defined(__COVERAGESCANNER__) && !QT_CONFIG(testlib_selfcover)
+ if (!qEnvironmentVariableIsEmpty("QT_TESTCOCOON_ACTIVE"))
+ return false;
+ // Set environment variable QT_TESTCOCOON_ACTIVE to prevent an eventual subtest from
+ // being considered as a stand-alone test regarding the coverage analysis.
+ qputenv("QT_TESTCOCOON_ACTIVE", "1");
+
+ // Install Coverage Tool
+ __coveragescanner_install(appname);
+ __coveragescanner_testname(testname);
+ __coveragescanner_clear();
+ return true;
+#else
+ Q_UNUSED(appname);
+ Q_UNUSED(testname);
+ return false;
+#endif
}
-static struct iovec IoVec(const char *str)
+
+static bool isValidSlot(const QMetaMethod &sl)
{
- struct iovec r = {};
- r.iov_base = const_cast<char *>(str);
- r.iov_len = strlen(str);
- return r;
+ if (sl.access() != QMetaMethod::Private || sl.parameterCount() != 0
+ || sl.returnType() != QMetaType::Void || sl.methodType() != QMetaMethod::Slot)
+ return false;
+ const QByteArray name = sl.name();
+ return !(name.isEmpty() || name.endsWith("_data")
+ || name == "initTestCase" || name == "cleanupTestCase"
+ || name == "init" || name == "cleanup");
}
-template <typename... Args> static ssize_t writeToStderr(Args &&... args)
+namespace QTestPrivate
{
- struct iovec vec[] = { IoVec(std::forward<Args>(args))... };
- return ::writev(STDERR_FILENO, vec, std::size(vec));
+ Q_TESTLIB_EXPORT Qt::MouseButtons qtestMouseButtons = Qt::NoButton;
}
-// async-signal-safe conversion from int to string
-struct AsyncSafeIntBuffer
+namespace {
+
+class TestFailedException : public std::exception // clazy:exclude=copyable-polymorphic
{
- // digits10 + 1 for all possible digits
- // +1 for the sign
- // +1 for the terminating null
- static constexpr int Digits10 = std::numeric_limits<int>::digits10 + 3;
- std::array<char, Digits10> array;
- constexpr AsyncSafeIntBuffer() : array{} {} // initializes array
- AsyncSafeIntBuffer(Qt::Initialization) {} // leaves array uninitialized
+public:
+ TestFailedException() = default;
+ ~TestFailedException() override = default;
+
+ const char *what() const noexcept override { return "QtTest: test failed"; }
};
-static struct iovec asyncSafeToString(int n, AsyncSafeIntBuffer &&result = Qt::Uninitialized)
+class TestSkippedException : public std::exception // clazy:exclude=copyable-polymorphic
{
- char *ptr = result.array.data();
- if (false) {
-#ifdef __cpp_lib_to_chars
- } else if (auto r = std::to_chars(ptr, ptr + result.array.size(), n, 10); r.ec == std::errc{}) {
- ptr = r.ptr;
-#endif
- } else {
- // handle the sign
- if (n < 0) {
- *ptr++ = '-';
- n = -n;
- }
-
- // find the highest power of the base that is less than this number
- static constexpr int StartingDivider = ([]() {
- int divider = 1;
- for (int i = 0; i < std::numeric_limits<int>::digits10; ++i)
- divider *= 10;
- return divider;
- }());
- int divider = StartingDivider;
- while (divider && n < divider)
- divider /= 10;
-
- // now convert to string
- while (divider > 1) {
- int quot = n / divider;
- n = n % divider;
- divider /= 10;
- *ptr++ = quot + '0';
- }
- *ptr++ = n + '0';
- }
+public:
+ TestSkippedException() = default;
+ ~TestSkippedException() override = default;
-#ifndef QT_NO_DEBUG
- // this isn't necessary, it just helps in the debugger
- *ptr = '\0';
-#endif
- struct iovec r;
- r.iov_base = result.array.data();
- r.iov_len = ptr - result.array.data();
- return r;
+ const char *what() const noexcept override { return "QtTest: test was skipped"; }
};
-#elif defined(Q_OS_WIN)
-// Windows doesn't need to be async-safe
-template <typename... Args> static void writeToStderr(Args &&... args)
-{
- (std::cerr << ... << args);
-}
-static std::string asyncSafeToString(int n)
-{
- return std::to_string(n);
-}
-#endif // defined(Q_OS_UNIX)
} // unnamed namespace
-static bool alreadyDebugging()
+namespace QTest
{
-#if defined(Q_OS_LINUX)
- int fd = open("/proc/self/status", O_RDONLY);
- if (fd == -1)
- return false;
- char buffer[2048];
- ssize_t size = read(fd, buffer, sizeof(buffer) - 1);
- if (size == -1) {
- close(fd);
- return false;
- }
- buffer[size] = 0;
- const char tracerPidToken[] = "\nTracerPid:";
- char *tracerPid = strstr(buffer, tracerPidToken);
- if (!tracerPid) {
- close(fd);
- return false;
- }
- tracerPid += sizeof(tracerPidToken);
- long int pid = strtol(tracerPid, &tracerPid, 10);
- close(fd);
- return pid != 0;
-#elif defined(Q_OS_WIN)
- return IsDebuggerPresent();
-#elif defined(Q_OS_MACOS)
- // 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;
- }
- }
- }
- return false;
-#else
- // TODO
- return false;
-#endif
-}
-static bool hasSystemCrashReporter()
+void Internal::throwOnFail() { throw TestFailedException(); }
+void Internal::throwOnSkip() { throw TestSkippedException(); }
+
+Q_CONSTINIT static QBasicAtomicInt g_throwOnFail = Q_BASIC_ATOMIC_INITIALIZER(0);
+Q_CONSTINIT static QBasicAtomicInt g_throwOnSkip = Q_BASIC_ATOMIC_INITIALIZER(0);
+
+void Internal::maybeThrowOnFail()
{
-#if defined(Q_OS_MACOS)
- return QTestPrivate::macCrashReporterWillShowDialog();
-#else
- return false;
-#endif
+ if (g_throwOnFail.loadRelaxed() > 0)
+ Internal::throwOnFail();
}
-static void maybeDisableCoreDump()
+void Internal::maybeThrowOnSkip()
{
-#ifdef RLIMIT_CORE
- bool ok = false;
- const int disableCoreDump = qEnvironmentVariableIntValue("QTEST_DISABLE_CORE_DUMP", &ok);
- if (ok && disableCoreDump) {
- struct rlimit limit;
- limit.rlim_cur = 0;
- limit.rlim_max = 0;
- if (setrlimit(RLIMIT_CORE, &limit) != 0)
- qWarning("Failed to disable core dumps: %d", errno);
- }
-#endif
+ if (g_throwOnSkip.loadRelaxed() > 0)
+ Internal::throwOnSkip();
}
-static DebuggerProgram debugger = None;
-static void prepareStackTrace()
-{
+/*!
+ \since 6.8
+ \macro QTEST_THROW_ON_FAIL
+ \relates <QTest>
- bool ok = false;
- const int disableStackDump = qEnvironmentVariableIntValue("QTEST_DISABLE_STACK_DUMP", &ok);
- if (ok && disableStackDump)
- return;
+ When defined, QCOMPARE()/QVERIFY() etc always throw on failure.
+ QTest::throwOnFail() then no longer has any effect.
+*/
- if (hasSystemCrashReporter())
- return;
+/*!
+ \since 6.8
+ \macro QTEST_THROW_ON_SKIP
+ \relates <QTest>
-#if defined(Q_OS_MACOS)
- #define CSR_ALLOW_UNRESTRICTED_FS (1 << 1)
- std::optional<uint32_t> sipConfiguration = qt_mac_sipConfiguration();
- if (!sipConfiguration || !(*sipConfiguration & CSR_ALLOW_UNRESTRICTED_FS))
- return; // LLDB will fail to provide a valid stack trace
-#endif
+ When defined, QSKIP() always throws. QTest::throwOnSkip() then no longer
+ has any effect.
+*/
-#ifdef Q_OS_UNIX
- // like QStandardPaths::findExecutable(), but simpler
- auto hasExecutable = [](const char *execname) {
- std::string candidate;
- std::string path;
- if (const char *p = getenv("PATH"); p && *p)
- path = p;
- else
- path = _PATH_DEFPATH;
- for (const char *p = std::strtok(&path[0], ":'"); p; p = std::strtok(nullptr, ":")) {
- candidate = p;
- candidate += '/';
- candidate += execname;
- if (QT_ACCESS(candidate.data(), X_OK) == 0)
- return true;
- }
- return false;
- };
+/*!
+ \since 6.8
+ \class QTest::ThrowOnFailEnabler
+ \inmodule QtTestLib
- static constexpr DebuggerProgram debuggerSearchOrder[] = {
-# if defined(Q_OS_QNX) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
- Gdb, Lldb
-# else
- Lldb, Gdb
-# endif
- };
- for (DebuggerProgram candidate : debuggerSearchOrder) {
- switch (candidate) {
- case None:
- Q_UNREACHABLE();
- break;
- case Gdb:
- if (hasExecutable("gdb")) {
- debugger = Gdb;
- return;
- }
- break;
- case Lldb:
- if (hasExecutable("lldb")) {
- debugger = Lldb;
- return;
- }
- break;
- }
- }
-#endif // Q_OS_UNIX
-}
+ RAII class around setThrowOnFail().
+*/
+/*!
+ \fn QTest::ThrowOnFailEnabler::ThrowOnFailEnabler()
-#if !defined(Q_OS_WASM) || QT_CONFIG(thread)
-static void printTestRunTime()
-{
- const int msecsFunctionTime = qRound(QTestLog::msecsFunctionTime());
- const int msecsTotalTime = qRound(QTestLog::msecsTotalTime());
- const char *const name = QTest::currentTestFunction();
- writeToStderr("\n ", name ? name : "[Non-test]",
- " function time: ", asyncSafeToString(msecsFunctionTime),
- "ms, total time: ", asyncSafeToString(msecsTotalTime), "ms\n");
-}
+ Constructor. Calls \c{setThrowOnFail(true)}.
+*/
+/*!
+ \fn QTest::ThrowOnFailEnabler::~ThrowOnFailEnabler()
-static void generateStackTrace()
-{
- if (debugger == None || alreadyDebugging())
- return;
+ Destructor. Calls \c{setThrowOnFail(false)}.
+*/
-# if defined(Q_OS_UNIX) && !defined(Q_OS_WASM) && !defined(Q_OS_INTEGRITY)
- writeToStderr("\n=== Stack trace ===\n");
+/*!
+ \since 6.8
+ \class QTest::ThrowOnFailDisabler
+ \inmodule QtTestLib
- // execlp() requires null-termination, so call the default constructor
- AsyncSafeIntBuffer pidbuffer;
- asyncSafeToString(getpid(), std::move(pidbuffer));
+ RAII class around setThrowOnFail().
+*/
+/*!
+ \fn QTest::ThrowOnFailDisabler::ThrowOnFailDisabler()
- // Note: POSIX.1-2001 still has fork() in the list of async-safe functions,
- // but in a future edition, it might be removed. It would be safer to wake
- // up a babysitter thread to launch the debugger.
- pid_t pid = fork();
- if (pid == 0) {
- // child process
- (void) dup2(STDERR_FILENO, STDOUT_FILENO); // redirect stdout to stderr
+ Constructor. Calls \c{setThrowOnFail(false)}.
+*/
+/*!
+ \fn QTest::ThrowOnFailDisabler::~ThrowOnFailDisabler()
- switch (debugger) {
- case None:
- Q_UNREACHABLE();
- break;
- case Gdb:
- execlp("gdb", "gdb", "--nx", "--batch", "-ex", "thread apply all bt",
- "--pid", pidbuffer.array.data(), nullptr);
- break;
- case Lldb:
- execlp("lldb", "lldb", "--no-lldbinit", "--batch", "-o", "bt all",
- "--attach-pid", pidbuffer.array.data(), nullptr);
- break;
- }
- _exit(1);
- } else if (pid < 0) {
- writeToStderr("Failed to start debugger.\n");
- } else {
- int ret;
- EINTR_LOOP(ret, waitpid(pid, nullptr, 0));
- }
+ Destructor. Calls \c{setThrowOnFail(true)}.
+*/
- writeToStderr("=== End of stack trace ===\n");
-# endif // Q_OS_UNIX && !Q_OS_WASM
-}
-#endif // !defined(Q_OS_WASM) || QT_CONFIG(thread)
+/*!
+ \since 6.8
+ \class QTest::ThrowOnSkipEnabler
+ \inmodule QtTestLib
-static bool installCoverageTool(const char * appname, const char * testname)
-{
-#if defined(__COVERAGESCANNER__) && !QT_CONFIG(testlib_selfcover)
- if (!qEnvironmentVariableIsEmpty("QT_TESTCOCOON_ACTIVE"))
- return false;
- // Set environment variable QT_TESTCOCOON_ACTIVE to prevent an eventual subtest from
- // being considered as a stand-alone test regarding the coverage analysis.
- qputenv("QT_TESTCOCOON_ACTIVE", "1");
+ RAII class around setThrowOnSkip().
+*/
+/*!
+ \fn QTest::ThrowOnSkipEnabler::ThrowOnSkipEnabler()
- // Install Coverage Tool
- __coveragescanner_install(appname);
- __coveragescanner_testname(testname);
- __coveragescanner_clear();
- return true;
-#else
- Q_UNUSED(appname);
- Q_UNUSED(testname);
- return false;
-#endif
-}
+ Constructor. Calls \c{setThrowOnSkip(true)}.
+*/
+/*!
+ \fn QTest::ThrowOnSkipEnabler::~ThrowOnSkipEnabler()
-static bool isValidSlot(const QMetaMethod &sl)
-{
- if (sl.access() != QMetaMethod::Private || sl.parameterCount() != 0
- || sl.returnType() != QMetaType::Void || sl.methodType() != QMetaMethod::Slot)
- return false;
- const QByteArray name = sl.name();
- return !(name.isEmpty() || name.endsWith("_data")
- || name == "initTestCase" || name == "cleanupTestCase"
- || name == "init" || name == "cleanup");
-}
+ Destructor. Calls \c{setThrowOnSkip(false)}.
+*/
-namespace QTestPrivate
+/*!
+ \since 6.8
+ \class QTest::ThrowOnSkipDisabler
+ \inmodule QtTestLib
+
+ RAII class around setThrowOnSkip().
+*/
+/*!
+ \fn QTest::ThrowOnSkipDisabler::ThrowOnSkipDisabler()
+
+ Constructor. Calls \c{setThrowOnSkip(false)}.
+*/
+/*!
+ \fn QTest::ThrowOnSkipDisabler::~ThrowOnSkipDisabler()
+
+ Destructor. Calls \c{setThrowOnSkip(true)}.
+*/
+
+/*!
+ \since 6.8
+
+ Enables (\a enable = \c true) or disables (\ enable = \c false) throwing on
+ QCOMPARE()/QVERIFY() failures (as opposed to just returning from the
+ immediately-surrounding function context).
+
+ The feature is reference-counted: If you call this function \e{N} times
+ with \c{true}, you need to call it \e{N} times with \c{false} to get back
+ to where you started.
+
+ The default is \c{false}, unless the \l{Qt Test Environment Variables}
+ {QTEST_THROW_ON_FAIL environment variable} is set.
+
+ This call has no effect when the \l{QTEST_THROW_ON_FAIL} C++ macro is
+ defined.
+
+ \note You must compile your tests with exceptions enabled to use this
+ feature.
+
+ \sa setThrowOnSkip(), ThrowOnFailEnabler, ThrowOnFailDisabler, QTEST_THROW_ON_FAIL
+*/
+void setThrowOnFail(bool enable) noexcept
{
- Q_TESTLIB_EXPORT Qt::MouseButtons qtestMouseButtons = Qt::NoButton;
+ g_throwOnFail.fetchAndAddRelaxed(enable ? 1 : -1);
}
-namespace QTest
+/*!
+ \since 6.8
+
+ Enables (\a enable = \c true) or disables (\ enable = \c false) throwing on
+ QSKIP() (as opposed to just returning from the immediately-surrounding
+ function context).
+
+ The feature is reference-counted: If you call this function \e{N} times
+ with \c{true}, you need to call it \e{N} times with \c{false} to get back
+ to where you started.
+
+ The default is \c{false}, unless the \l{Qt Test Environment Variables}
+ {QTEST_THROW_ON_SKIP environment variable} is set.
+
+ This call has no effect when the \l{QTEST_THROW_ON_SKIP} C++ macro is
+ defined.
+
+ \note You must compile your tests with exceptions enabled to use this
+ feature.
+
+ \sa setThrowOnFail(), ThrowOnSkipEnabler, ThrowOnSkipDisabler, QTEST_THROW_ON_SKIP
+*/
+void setThrowOnSkip(bool enable) noexcept
{
+ g_throwOnSkip.fetchAndAddRelaxed(enable ? 1 : -1);
+}
QString Internal::formatTryTimeoutDebugMessage(q_no_char8_t::QUtf8StringView expr, int timeout, int actual)
{
@@ -487,7 +387,7 @@ public:
static QMetaMethod findMethod(const QObject *obj, const char *signature);
private:
- bool invokeTest(int index, QLatin1StringView tag, WatchDog *watchDog) const;
+ bool invokeTest(int index, QLatin1StringView tag, std::optional<WatchDog> &watchDog) const;
void invokeTestOnData(int index) const;
QMetaMethod m_initTestCaseMethod; // might not exist, check isValid().
@@ -532,19 +432,32 @@ static int eventDelay = -1;
#if QT_CONFIG(thread)
static int timeout = -1;
#endif
-static bool noCrashHandler = false;
+static int repetitions = 1;
+static bool repeatForever = false;
+static bool skipBlacklisted = false;
-/*! \internal
- Invoke a method of the object without generating warning if the method does not exist
-*/
-static void invokeMethod(QObject *obj, const char *methodName)
+namespace Internal {
+bool noCrashHandler = false;
+}
+
+static bool invokeTestMethodIfValid(QMetaMethod m, QObject *obj = QTest::currentTestObject)
+{
+ if (!m.isValid())
+ return false;
+ bool ok = true;
+ try { ok = m.invoke(obj, Qt ::DirectConnection); }
+ catch (const TestFailedException &) {} // ignore (used for control flow)
+ catch (const TestSkippedException &) {} // ditto
+ // every other exception is someone else's problem
+ return ok;
+}
+
+static void invokeTestMethodIfExists(const char *methodName, QObject *obj = QTest::currentTestObject)
{
const QMetaObject *metaObject = obj->metaObject();
int funcIndex = metaObject->indexOfMethod(methodName);
- if (funcIndex >= 0) {
- QMetaMethod method = metaObject->method(funcIndex);
- method.invoke(obj, Qt::DirectConnection);
- }
+ // doesn't generate a warning if it doesn't exist:
+ invokeTestMethodIfValid(metaObject->method(funcIndex), obj);
}
int defaultEventDelay()
@@ -628,7 +541,7 @@ static void qPrintDataTags(FILE *stream)
// Get global data tags:
QTestTable::globalTestTable();
- invokeMethod(QTest::currentTestObject, "initTestCase_data()");
+ invokeTestMethodIfExists("initTestCase_data()");
const QTestTable *gTable = QTestTable::globalTestTable();
const QMetaObject *currTestMetaObj = QTest::currentTestObject->metaObject();
@@ -647,7 +560,7 @@ static void qPrintDataTags(FILE *stream)
QByteArray member;
member.resize(qstrlen(slot) + qstrlen("_data()") + 1);
qsnprintf(member.data(), member.size(), "%s_data()", slot);
- invokeMethod(QTest::currentTestObject, member.constData());
+ invokeTestMethodIfExists(member.constData());
const int dataCount = table.dataCount();
localTags.reserve(dataCount);
for (int j = 0; j < dataCount; ++j)
@@ -704,9 +617,17 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, const char *const argv[], bool
int logFormat = -1; // Not set
const char *logFilename = nullptr;
+ repetitions = 1;
+ repeatForever = false;
+
QTest::testFunctions.clear();
QTest::testTags.clear();
+ if (qEnvironmentVariableIsSet("QTEST_THROW_ON_FAIL"))
+ QTest::setThrowOnFail(true);
+ if (qEnvironmentVariableIsSet("QTEST_THROW_ON_SKIP"))
+ QTest::setThrowOnSkip(true);
+
#if defined(Q_OS_DARWIN) && defined(HAVE_XCTEST)
if (QXcodeTestLogger::canLogTestProgress())
logFormat = QTestLog::XCTest;
@@ -758,6 +679,15 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, const char *const argv[], bool
" -maxwarnings n : Sets the maximum amount of messages to output.\n"
" 0 means unlimited, default: 2000\n"
" -nocrashhandler : Disables the crash handler. Useful for debugging crashes.\n"
+ " -repeat n : Run the testsuite n times or until the test fails.\n"
+ " Useful for finding flaky tests. If negative, the tests are\n"
+ " repeated forever. This is intended as a developer tool, and\n"
+ " is only supported with the plain text logger.\n"
+ " -skipblacklisted : Skip blacklisted tests. Useful for measuring test coverage.\n"
+ " -[no]throwonfail : Enables/disables throwing on QCOMPARE()/QVERIFY()/etc.\n"
+ " Default: off, unless QTEST_THROW_ON_FAIL is set."
+ " -[no]throwonskip : Enables/disables throwing on QSKIP().\n"
+ " Default: off, unless QTEST_THROW_ON_SKIP is set."
"\n"
" Benchmarking options:\n"
#if QT_CONFIG(valgrind)
@@ -907,8 +837,26 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, const char *const argv[], bool
} else {
QTestLog::setMaxWarnings(qToInt(argv[++i]));
}
+ } else if (strcmp(argv[i], "-repeat") == 0) {
+ if (i + 1 >= argc) {
+ fprintf(stderr, "-repeat needs an extra parameter for the number of repetitions\n");
+ exit(1);
+ } else {
+ repetitions = qToInt(argv[++i]);
+ repeatForever = repetitions < 0;
+ }
} else if (strcmp(argv[i], "-nocrashhandler") == 0) {
- QTest::noCrashHandler = true;
+ QTest::Internal::noCrashHandler = true;
+ } else if (strcmp(argv[i], "-skipblacklisted") == 0) {
+ QTest::skipBlacklisted = true;
+ } else if (strcmp(argv[i], "-throwonfail") == 0) {
+ QTest::setThrowOnFail(true);
+ } else if (strcmp(argv[i], "-nothrowonfail") == 0) {
+ QTest::setThrowOnFail(false);
+ } else if (strcmp(argv[i], "-throwonskip") == 0) {
+ QTest::setThrowOnSkip(true);
+ } else if (strcmp(argv[i], "-nothrowonskip") == 0) {
+ QTest::setThrowOnSkip(false);
#if QT_CONFIG(valgrind)
} else if (strcmp(argv[i], "-callgrind") == 0) {
if (!QBenchmarkValgrindUtils::haveValgrind()) {
@@ -1050,16 +998,21 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, const char *const argv[], bool
#if defined(QT_USE_APPLE_UNIFIED_LOGGING)
// Any explicitly requested loggers will be added by now, so we can check if they use stdout
- const bool safeToAddAppleLogger = !AppleUnifiedLogger::willMirrorToStderr() || !QTestLog::loggerUsingStdout();
+ const bool safeToAddAppleLogger = !AppleUnifiedLogger::preventsStderrLogging() || !QTestLog::loggerUsingStdout();
if (safeToAddAppleLogger && QAppleTestLogger::debugLoggingEnabled()) {
QTestLog::addLogger(QTestLog::Apple, nullptr);
- if (AppleUnifiedLogger::willMirrorToStderr() && !logFilename)
+ if (AppleUnifiedLogger::preventsStderrLogging() && !logFilename)
addFallbackLogger = false; // Prevent plain test logger fallback below
}
#endif
if (addFallbackLogger)
QTestLog::addLogger(QTestLog::Plain, logFilename);
+
+ if (repetitions != 1 && !QTestLog::isRepeatSupported()) {
+ fprintf(stderr, "-repeat is only supported with plain text logger\n");
+ exit(1);
+ }
}
// Temporary, backwards compatibility, until qtdeclarative's use of it is converted
@@ -1118,8 +1071,7 @@ void TestMethods::invokeTestOnData(int index) const
bool invokeOk;
do {
QTest::inTestFunction = true;
- if (m_initMethod.isValid())
- m_initMethod.invoke(QTest::currentTestObject, Qt::DirectConnection);
+ invokeTestMethodIfValid(m_initMethod);
const bool initQuit =
QTestResult::skipCurrentTest() || QTestResult::currentTestFailed();
@@ -1131,7 +1083,7 @@ void TestMethods::invokeTestOnData(int index) const
QBenchmarkGlobalData::current->context.tag = QLatin1StringView(
QTestResult::currentDataTag() ? QTestResult::currentDataTag() : "");
- invokeOk = m_methods[index].invoke(QTest::currentTestObject, Qt::DirectConnection);
+ invokeOk = invokeTestMethodIfValid(m_methods[index]);
if (!invokeOk)
QTestResult::addFailure("Unable to execute slot", __FILE__, __LINE__);
@@ -1144,8 +1096,7 @@ void TestMethods::invokeTestOnData(int index) const
QTestResult::finishedCurrentTestData();
if (!initQuit) {
- if (m_cleanupMethod.isValid())
- m_cleanupMethod.invoke(QTest::currentTestObject, Qt::DirectConnection);
+ invokeTestMethodIfValid(m_cleanupMethod);
// Process any deleteLater(), used by event-loop-based apps.
// Fixes memleak reports.
@@ -1231,7 +1182,7 @@ class WatchDog : public QThread
static constexpr Expectation combine(Expectation e, size_t gen) noexcept
{ return Expectation{e | (gen << GenerationShift)}; }
- bool waitFor(std::unique_lock<QtPrivate::mutex> &m, Expectation e)
+ bool waitFor(std::unique_lock<std::mutex> &m, Expectation e)
{
auto expectationChanged = [this, e] { return expecting.load(std::memory_order_relaxed) != e; };
switch (state(e)) {
@@ -1287,6 +1238,7 @@ public:
void run() override
{
+ CrashHandler::blockUnixSignals();
auto locker = qt_unique_lock(mutex);
expecting.store(TestFunctionStart, std::memory_order_release);
waitCondition.notify_all();
@@ -1301,8 +1253,8 @@ public:
case TestFunctionEnd:
if (Q_UNLIKELY(!waitFor(locker, e))) {
fflush(stderr);
- printTestRunTime();
- generateStackTrace();
+ CrashHandler::printTestRunTime();
+ CrashHandler::generateStackTrace();
qFatal("Test function timed out");
}
}
@@ -1310,8 +1262,8 @@ public:
}
private:
- QtPrivate::mutex mutex;
- QtPrivate::condition_variable waitCondition;
+ std::mutex mutex;
+ std::condition_variable waitCondition;
std::atomic<Expectation> expecting;
};
@@ -1356,7 +1308,7 @@ static void printUnknownDataTagError(QLatin1StringView name, QLatin1StringView t
If the function was successfully called, true is returned, otherwise
false.
*/
-bool TestMethods::invokeTest(int index, QLatin1StringView tag, WatchDog *watchDog) const
+bool TestMethods::invokeTest(int index, QLatin1StringView tag, std::optional<WatchDog> &watchDog) const
{
QBenchmarkTestMethodData benchmarkData;
QBenchmarkTestMethodData::current = &benchmarkData;
@@ -1388,6 +1340,7 @@ bool TestMethods::invokeTest(int index, QLatin1StringView tag, WatchDog *watchDo
tag[global.size()] == ':';
};
bool foundFunction = false;
+ bool blacklisted = false;
/* For each entry in the global data table, do: */
do {
@@ -1396,7 +1349,7 @@ bool TestMethods::invokeTest(int index, QLatin1StringView tag, WatchDog *watchDo
if (curGlobalDataIndex == 0) {
qsnprintf(member, 512, "%s_data()", name.constData());
- invokeMethod(QTest::currentTestObject, member);
+ invokeTestMethodIfExists(member);
if (QTestResult::skipCurrentTest())
break;
}
@@ -1414,18 +1367,28 @@ bool TestMethods::invokeTest(int index, QLatin1StringView tag, WatchDog *watchDo
if (dataTagMatches(tag, QLatin1StringView(dataTag(curDataIndex)),
QLatin1StringView(globalDataTag(curGlobalDataIndex)))) {
foundFunction = true;
- QTestPrivate::checkBlackLists(name.constData(), dataTag(curDataIndex),
- globalDataTag(curGlobalDataIndex));
-
- QTestDataSetter s(curDataIndex >= dataCount ? nullptr : table.testData(curDataIndex));
-
- QTestPrivate::qtestMouseButtons = Qt::NoButton;
- if (watchDog)
- watchDog->beginTest();
- QTest::lastMouseTimestamp += 500; // Maintain at least 500ms mouse event timestamps between each test function call
- invokeTestOnData(index);
- if (watchDog)
- watchDog->testFinished();
+ blacklisted = QTestPrivate::checkBlackLists(name.constData(), dataTag(curDataIndex),
+ globalDataTag(curGlobalDataIndex));
+ if (blacklisted)
+ QTestResult::setBlacklistCurrentTest(true);
+
+ if (blacklisted && skipBlacklisted) {
+ QTest::qSkip("Skipping blacklisted test since -skipblacklisted option is set.",
+ NULL, 0);
+ QTestResult::finishedCurrentTestData();
+ QTestResult::finishedCurrentTestDataCleanup();
+ } else {
+ QTestDataSetter s(
+ curDataIndex >= dataCount ? nullptr : table.testData(curDataIndex));
+
+ QTestPrivate::qtestMouseButtons = Qt::NoButton;
+ if (watchDog)
+ watchDog->beginTest();
+ QTest::lastMouseTimestamp += 500; // Maintain at least 500ms mouse event timestamps between each test function call
+ invokeTestOnData(index);
+ if (watchDog)
+ watchDog->testFinished();
+ }
if (!tag.isEmpty() && !globalDataCount)
break;
@@ -1644,65 +1607,77 @@ char *toPrettyCString(const char *p, qsizetype length)
}
/*!
+ \fn char *toPrettyUnicode(QStringView string)
\internal
Returns the same QString but with only the ASCII characters still shown;
everything else is replaced with \c {\uXXXX}.
Similar to QDebug::putString().
*/
+
+constexpr qsizetype PrettyUnicodeMaxOutputSize = 256;
+// escape sequence, closing quote, the three dots and NUL
+constexpr qsizetype PrettyUnicodeMaxIncrement = sizeof(R"(\uXXXX"...)"); // includes NUL
+
+static char *writePrettyUnicodeChar(char16_t ch, char * const buffer)
+{
+ auto dst = buffer;
+ auto first = [&](int n) { Q_ASSERT(dst - buffer == n); return dst; };
+ if (ch < 0x7f && ch >= 0x20 && ch != '\\' && ch != '"') {
+ *dst++ = ch;
+ return first(1);
+ }
+
+ // write as an escape sequence
+ *dst++ = '\\';
+ switch (ch) {
+ case 0x22:
+ case 0x5c:
+ *dst++ = uchar(ch);
+ break;
+ case 0x8:
+ *dst++ = 'b';
+ break;
+ case 0xc:
+ *dst++ = 'f';
+ break;
+ case 0xa:
+ *dst++ = 'n';
+ break;
+ case 0xd:
+ *dst++ = 'r';
+ break;
+ case 0x9:
+ *dst++ = 't';
+ break;
+ default:
+ *dst++ = 'u';
+ *dst++ = toHexUpper(ch >> 12);
+ *dst++ = toHexUpper(ch >> 8);
+ *dst++ = toHexUpper(ch >> 4);
+ *dst++ = toHexUpper(ch);
+ return first(6);
+ }
+ return first(2);
+}
+
char *toPrettyUnicode(QStringView string)
{
auto p = string.utf16();
auto length = string.size();
// keep it simple for the vast majority of cases
bool trimmed = false;
- auto buffer = std::make_unique<char[]>(256);
+ auto buffer = std::make_unique<char[]>(PrettyUnicodeMaxOutputSize);
const auto end = p + length;
char *dst = buffer.get();
*dst++ = '"';
for ( ; p != end; ++p) {
- if (dst - buffer.get() > 245) {
- // plus the quote, the three dots and NUL, it's 250, 251 or 255
+ if (dst - buffer.get() > PrettyUnicodeMaxOutputSize - PrettyUnicodeMaxIncrement) {
trimmed = true;
break;
}
-
- if (*p < 0x7f && *p >= 0x20 && *p != '\\' && *p != '"') {
- *dst++ = *p;
- continue;
- }
-
- // write as an escape sequence
- // this means we may advance dst to buffer.data() + 246 or 250
- *dst++ = '\\';
- switch (*p) {
- case 0x22:
- case 0x5c:
- *dst++ = uchar(*p);
- break;
- case 0x8:
- *dst++ = 'b';
- break;
- case 0xc:
- *dst++ = 'f';
- break;
- case 0xa:
- *dst++ = 'n';
- break;
- case 0xd:
- *dst++ = 'r';
- break;
- case 0x9:
- *dst++ = 't';
- break;
- default:
- *dst++ = 'u';
- *dst++ = toHexUpper(*p >> 12);
- *dst++ = toHexUpper(*p >> 8);
- *dst++ = toHexUpper(*p >> 4);
- *dst++ = toHexUpper(*p);
- }
+ dst = writePrettyUnicodeChar(*p, dst);
}
*dst++ = '"';
@@ -1720,23 +1695,21 @@ void TestMethods::invokeTests(QObject *testObject) const
const QMetaObject *metaObject = testObject->metaObject();
QTEST_ASSERT(metaObject);
QTestResult::setCurrentTestFunction("initTestCase");
- if (m_initTestCaseDataMethod.isValid())
- m_initTestCaseDataMethod.invoke(testObject, Qt::DirectConnection);
+ invokeTestMethodIfValid(m_initTestCaseDataMethod, testObject);
- QScopedPointer<WatchDog> watchDog;
- if (!alreadyDebugging()
+ std::optional<WatchDog> watchDog = std::nullopt;
+ if (!CrashHandler::alreadyDebugging()
#if QT_CONFIG(valgrind)
&& QBenchmarkGlobalData::current->mode() != QBenchmarkGlobalData::CallgrindChildProcess
#endif
) {
- watchDog.reset(new WatchDog);
+ watchDog.emplace();
}
QSignalDumper::startDump();
if (!QTestResult::skipCurrentTest() && !QTestResult::currentTestFailed()) {
- if (m_initTestCaseMethod.isValid())
- m_initTestCaseMethod.invoke(testObject, Qt::DirectConnection);
+ invokeTestMethodIfValid(m_initTestCaseMethod, testObject);
// finishedCurrentTestDataCleanup() resets QTestResult::currentTestFailed(), so use a local copy.
const bool previousFailed = QTestResult::currentTestFailed();
@@ -1749,7 +1722,7 @@ void TestMethods::invokeTests(QObject *testObject) const
const char *data = nullptr;
if (i < QTest::testTags.size() && !QTest::testTags.at(i).isEmpty())
data = qstrdup(QTest::testTags.at(i).toLatin1().constData());
- const bool ok = invokeTest(i, QLatin1StringView(data), watchDog.data());
+ const bool ok = invokeTest(i, QLatin1StringView(data), watchDog);
delete [] data;
if (!ok)
break;
@@ -1760,8 +1733,7 @@ void TestMethods::invokeTests(QObject *testObject) const
QTestResult::setSkipCurrentTest(false);
QTestResult::setBlacklistCurrentTest(false);
QTestResult::setCurrentTestFunction("cleanupTestCase");
- if (m_cleanupTestCaseMethod.isValid())
- m_cleanupTestCaseMethod.invoke(testObject, Qt::DirectConnection);
+ invokeTestMethodIfValid(m_cleanupTestCaseMethod, testObject);
QTestResult::finishedCurrentTestData();
// Restore skip state as it affects decision on whether we passed:
QTestResult::setSkipCurrentTest(wasSkipped || QTestResult::skipCurrentTest());
@@ -1773,430 +1745,34 @@ void TestMethods::invokeTests(QObject *testObject) const
QSignalDumper::endDump();
}
+#if QT_DEPRECATED_SINCE(6, 8)
+static const char *functionRefFormatter(const void *f)
+{
+ auto formatter = static_cast<const qxp::function_ref<const char *()> *>(f);
+ return (*formatter)();
+};
+
bool reportResult(bool success, qxp::function_ref<const char *()> lhs,
qxp::function_ref<const char *()> rhs,
const char *lhsExpr, const char *rhsExpr,
ComparisonOperation op, const char *file, int line)
{
- return QTestResult::reportResult(success, lhs, rhs, lhsExpr, rhsExpr, op, file, line);
+ return QTestResult::reportResult(success, &lhs, &rhs,
+ functionRefFormatter, functionRefFormatter,
+ lhsExpr, rhsExpr, op, file, line);
}
+#endif // QT_DEPRECATED_SINCE(6, 8)
-} // namespace QTest
-
-namespace {
-#if defined(Q_OS_WIN)
-
-// Helper class for resolving symbol names by dynamically loading "dbghelp.dll".
-class DebugSymbolResolver
-{
- Q_DISABLE_COPY_MOVE(DebugSymbolResolver)
-public:
- struct Symbol {
- Symbol() : name(nullptr), address(0) {}
-
- const char *name; // Must be freed by caller.
- DWORD64 address;
- };
-
- explicit DebugSymbolResolver(HANDLE process);
- ~DebugSymbolResolver() { cleanup(); }
-
- bool isValid() const { return m_symFromAddr; }
-
- Symbol resolveSymbol(DWORD64 address) const;
-
-private:
- // typedefs from DbgHelp.h/.dll
- struct DBGHELP_SYMBOL_INFO { // SYMBOL_INFO
- ULONG SizeOfStruct;
- ULONG TypeIndex; // Type Index of symbol
- ULONG64 Reserved[2];
- ULONG Index;
- ULONG Size;
- ULONG64 ModBase; // Base Address of module comtaining this symbol
- ULONG Flags;
- ULONG64 Value; // Value of symbol, ValuePresent should be 1
- ULONG64 Address; // Address of symbol including base address of module
- ULONG Register; // register holding value or pointer to value
- ULONG Scope; // scope of the symbol
- ULONG Tag; // pdb classification
- ULONG NameLen; // Actual length of name
- ULONG MaxNameLen;
- CHAR Name[1]; // Name of symbol
- };
-
- typedef BOOL (__stdcall *SymInitializeType)(HANDLE, PCSTR, BOOL);
- typedef BOOL (__stdcall *SymFromAddrType)(HANDLE, DWORD64, PDWORD64, DBGHELP_SYMBOL_INFO *);
-
- void cleanup();
-
- const HANDLE m_process;
- HMODULE m_dbgHelpLib;
- SymFromAddrType m_symFromAddr;
-};
-
-void DebugSymbolResolver::cleanup()
-{
- if (m_dbgHelpLib)
- FreeLibrary(m_dbgHelpLib);
- m_dbgHelpLib = 0;
- m_symFromAddr = nullptr;
-}
-
-DebugSymbolResolver::DebugSymbolResolver(HANDLE process)
- : m_process(process), m_dbgHelpLib(0), m_symFromAddr(nullptr)
-{
- bool success = false;
- m_dbgHelpLib = LoadLibraryW(L"dbghelp.dll");
- if (m_dbgHelpLib) {
- SymInitializeType symInitialize = reinterpret_cast<SymInitializeType>(
- reinterpret_cast<QFunctionPointer>(GetProcAddress(m_dbgHelpLib, "SymInitialize")));
- m_symFromAddr = reinterpret_cast<SymFromAddrType>(
- reinterpret_cast<QFunctionPointer>(GetProcAddress(m_dbgHelpLib, "SymFromAddr")));
- success = symInitialize && m_symFromAddr && symInitialize(process, NULL, TRUE);
- }
- if (!success)
- cleanup();
-}
-
-DebugSymbolResolver::Symbol DebugSymbolResolver::resolveSymbol(DWORD64 address) const
+bool reportResult(bool success, const void *lhs, const void *rhs,
+ const char *(*lhsFormatter)(const void*),
+ const char *(*rhsFormatter)(const void*),
+ const char *lhsExpr, const char *rhsExpr,
+ ComparisonOperation op, const char *file, int line)
{
- // reserve additional buffer where SymFromAddr() will store the name
- struct NamedSymbolInfo : public DBGHELP_SYMBOL_INFO {
- enum { symbolNameLength = 255 };
-
- char name[symbolNameLength + 1];
- };
-
- Symbol result;
- if (!isValid())
- return result;
- NamedSymbolInfo symbolBuffer;
- memset(&symbolBuffer, 0, sizeof(NamedSymbolInfo));
- symbolBuffer.MaxNameLen = NamedSymbolInfo::symbolNameLength;
- symbolBuffer.SizeOfStruct = sizeof(DBGHELP_SYMBOL_INFO);
- if (!m_symFromAddr(m_process, address, 0, &symbolBuffer))
- return result;
- result.name = qstrdup(symbolBuffer.Name);
- result.address = symbolBuffer.Address;
- return result;
+ return QTestResult::reportResult(success, lhs, rhs, lhsFormatter, rhsFormatter,
+ lhsExpr, rhsExpr, op, file, line);
}
-
-class WindowsFaultHandler
-{
-public:
- WindowsFaultHandler()
- {
-# if !defined(Q_CC_MINGW)
- _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
-# endif
- SetErrorMode(SetErrorMode(0) | SEM_NOGPFAULTERRORBOX);
- SetUnhandledExceptionFilter(windowsFaultHandler);
- }
-
-private:
- static LONG WINAPI windowsFaultHandler(struct _EXCEPTION_POINTERS *exInfo)
- {
- enum { maxStackFrames = 100 };
- char appName[MAX_PATH];
- if (!GetModuleFileNameA(NULL, appName, MAX_PATH))
- appName[0] = 0;
- const int msecsFunctionTime = qRound(QTestLog::msecsFunctionTime());
- const int msecsTotalTime = qRound(QTestLog::msecsTotalTime());
- const void *exceptionAddress = exInfo->ExceptionRecord->ExceptionAddress;
- fprintf(stderr, "A crash occurred in %s.\n", appName);
- if (const char *name = QTest::currentTestFunction())
- fprintf(stderr, "While testing %s\n", name);
- fprintf(stderr, "Function time: %dms Total time: %dms\n\n"
- "Exception address: 0x%p\n"
- "Exception code : 0x%lx\n",
- msecsFunctionTime, msecsTotalTime, exceptionAddress,
- exInfo->ExceptionRecord->ExceptionCode);
-
- DebugSymbolResolver resolver(GetCurrentProcess());
- if (resolver.isValid()) {
- DebugSymbolResolver::Symbol exceptionSymbol = resolver.resolveSymbol(DWORD64(exceptionAddress));
- if (exceptionSymbol.name) {
- fprintf(stderr, "Nearby symbol : %s\n", exceptionSymbol.name);
- delete [] exceptionSymbol.name;
- }
- void *stack[maxStackFrames];
- fputs("\nStack:\n", stderr);
- const unsigned frameCount = CaptureStackBackTrace(0, DWORD(maxStackFrames), stack, NULL);
- for (unsigned f = 0; f < frameCount; ++f) {
- DebugSymbolResolver::Symbol symbol = resolver.resolveSymbol(DWORD64(stack[f]));
- if (symbol.name) {
- fprintf(stderr, "#%3u: %s() - 0x%p\n", f + 1, symbol.name, (const void *)symbol.address);
- delete [] symbol.name;
- } else {
- fprintf(stderr, "#%3u: Unable to obtain symbol\n", f + 1);
- }
- }
- }
-
- fputc('\n', stderr);
-
- return EXCEPTION_EXECUTE_HANDLER;
- }
-};
-using FatalSignalHandler = WindowsFaultHandler;
-
-#elif defined(Q_OS_UNIX) && !defined(Q_OS_WASM)
-class FatalSignalHandler
-{
-public:
-# define OUR_SIGNALS(F) \
- F(HUP) \
- F(INT) \
- F(QUIT) \
- F(ABRT) \
- F(ILL) \
- F(BUS) \
- F(FPE) \
- F(SEGV) \
- F(PIPE) \
- F(TERM) \
- /**/
-# define CASE_LABEL(S) case SIG ## S: return QT_STRINGIFY(S);
-# define ENUMERATE_SIGNALS(S) SIG ## S,
- static const char *signalName(int signum) noexcept
- {
- switch (signum) {
- OUR_SIGNALS(CASE_LABEL)
- }
-
-# if defined(__GLIBC_MINOR__) && (__GLIBC_MINOR__ >= 32 || __GLIBC__ > 2)
- // get the other signal names from glibc 2.32
- // (accessing the sys_sigabbrev variable causes linker warnings)
- if (const char *p = sigabbrev_np(signum))
- return p;
-# endif
- return "???";
- }
- static constexpr std::array fatalSignals = {
- OUR_SIGNALS(ENUMERATE_SIGNALS)
- };
-# undef CASE_LABEL
-# undef ENUMERATE_SIGNALS
-
- static constexpr std::array crashingSignals = {
- // Crash signals are special, because if we return from the handler
- // without adjusting the machine state, the same instruction that
- // originally caused the crash will get re-executed and will thus cause
- // the same crash again. This is useful if our parent process logs the
- // exit result or if core dumps are enabled: the core file will point
- // to the actual instruction that crashed.
- SIGILL, SIGBUS, SIGFPE, SIGSEGV
- };
- using OldActionsArray = std::array<struct sigaction, fatalSignals.size()>;
-
- FatalSignalHandler()
- {
- pauseOnCrash = qEnvironmentVariableIsSet("QTEST_PAUSE_ON_CRASH");
- struct sigaction act;
- memset(&act, 0, sizeof(act));
- act.sa_handler = SIG_DFL;
- oldActions().fill(act);
-
- // Remove the handler after it is invoked.
- act.sa_flags = SA_RESETHAND | setupAlternateStack();
-
-# ifdef SA_SIGINFO
- act.sa_flags |= SA_SIGINFO;
- act.sa_sigaction = FatalSignalHandler::actionHandler;
-# else
- act.sa_handler = FatalSignalHandler::regularHandler;
-# endif
-
- // Block all fatal signals in our signal handler so we don't try to close
- // the testlog twice.
- sigemptyset(&act.sa_mask);
- for (int signal : fatalSignals)
- sigaddset(&act.sa_mask, signal);
-
- for (size_t i = 0; i < fatalSignals.size(); ++i)
- sigaction(fatalSignals[i], &act, &oldActions()[i]);
- }
-
- ~FatalSignalHandler()
- {
- // Restore the default signal handlers in place of ours.
- // If ours has been replaced, leave the replacement alone.
- auto isOurs = [](const struct sigaction &old) {
-# ifdef SA_SIGINFO
- return (old.sa_flags & SA_SIGINFO) && old.sa_sigaction == FatalSignalHandler::actionHandler;
-# else
- return old.sa_handler == FatalSignalHandler::regularHandler;
-# endif
- };
- struct sigaction action;
-
- for (size_t i = 0; i < fatalSignals.size(); ++i) {
- struct sigaction &act = oldActions()[i];
- if (act.sa_flags == 0 && act.sa_handler == SIG_DFL)
- continue; // Already the default
- if (sigaction(fatalSignals[i], nullptr, &action))
- continue; // Failed to query present handler
- if (isOurs(action))
- sigaction(fatalSignals[i], &act, nullptr);
- }
-
- freeAlternateStack();
- }
-
-private:
- Q_DISABLE_COPY_MOVE(FatalSignalHandler)
-
- static OldActionsArray &oldActions()
- {
- Q_CONSTINIT static OldActionsArray oldActions {};
- return oldActions;
- }
-
- auto alternateStackSize()
- {
- struct R { size_t size, pageSize; };
- static constexpr size_t MinStackSize = 32 * 1024;
- size_t pageSize = sysconf(_SC_PAGESIZE);
- size_t size = SIGSTKSZ;
- if (size < MinStackSize) {
- size = MinStackSize;
- } else {
- // round up to a page
- size = (size + pageSize - 1) & -pageSize;
- }
-
- return R{ size + pageSize, pageSize };
- }
-
- int setupAlternateStack()
- {
- // tvOS/watchOS both define SA_ONSTACK (in sys/signal.h) but mark sigaltstack() as
- // unavailable (__WATCHOS_PROHIBITED __TVOS_PROHIBITED in signal.h)
-# if defined(SA_ONSTACK) && !defined(Q_OS_TVOS) && !defined(Q_OS_WATCHOS)
- // Let the signal handlers use an alternate stack
- // This is necessary if SIGSEGV is to catch a stack overflow
- auto r = alternateStackSize();
- int flags = MAP_PRIVATE | MAP_ANONYMOUS;
-# ifdef MAP_STACK
- flags |= MAP_STACK;
-# endif
- alternateStackBase = mmap(nullptr, r.size, PROT_READ | PROT_WRITE, flags, -1, 0);
- if (alternateStackBase == MAP_FAILED)
- return 0;
-
- // mark the bottom page inaccessible, to catch a handler stack overflow
- (void) mprotect(alternateStackBase, r.pageSize, PROT_NONE);
-
- stack_t stack;
- stack.ss_flags = 0;
- stack.ss_size = r.size - r.pageSize;
- stack.ss_sp = static_cast<char *>(alternateStackBase) + r.pageSize;
- sigaltstack(&stack, nullptr);
- return SA_ONSTACK;
-# else
- return 0;
-# endif
- }
-
- void freeAlternateStack()
- {
-# if defined(SA_ONSTACK) && !defined(Q_OS_TVOS) && !defined(Q_OS_WATCHOS)
- if (alternateStackBase != MAP_FAILED) {
- stack_t stack = {};
- stack.ss_flags = SS_DISABLE;
- sigaltstack(&stack, nullptr);
- munmap(alternateStackBase, alternateStackSize().size);
- }
-# endif
- }
-
- template <typename T> static
- std::enable_if_t<sizeof(std::declval<T>().si_pid) + sizeof(std::declval<T>().si_uid) >= 1>
- printSentSignalInfo(T *info)
- {
- writeToStderr(" sent by PID ", asyncSafeToString(info->si_pid),
- " UID ", asyncSafeToString(info->si_uid));
- }
- static void printSentSignalInfo(...) {}
-
- template <typename T> static
- std::enable_if_t<sizeof(std::declval<T>().si_addr) >= 1> printCrashingSignalInfo(T *info)
- {
- using HexString = std::array<char, sizeof(quintptr) * 2>;
- auto toHexString = [](quintptr u, HexString &&r = {}) {
- int shift = sizeof(quintptr) * 8 - 4;
- for (size_t i = 0; i < sizeof(quintptr) * 2; ++i, shift -= 4)
- r[i] = QtMiscUtils::toHexLower(u >> shift);
- struct iovec vec;
- vec.iov_base = r.data();
- vec.iov_len = r.size();
- return vec;
- };
- writeToStderr(", code ", asyncSafeToString(info->si_code),
- ", for address 0x", toHexString(quintptr(info->si_addr)));
- }
- static void printCrashingSignalInfo(...) {}
-
- static void actionHandler(int signum, siginfo_t *info, void * /* ucontext */)
- {
- writeToStderr("Received signal ", asyncSafeToString(signum),
- " (SIG", signalName(signum), ")");
-
- bool isCrashingSignal =
- std::find(crashingSignals.begin(), crashingSignals.end(), signum) != crashingSignals.end();
- if (isCrashingSignal && (!info || info->si_code <= 0))
- isCrashingSignal = false; // wasn't sent by the kernel, so it's not really a crash
- if (isCrashingSignal)
- printCrashingSignalInfo(info);
- else if (info && (info->si_code == SI_USER || info->si_code == SI_QUEUE))
- printSentSignalInfo(info);
-
- printTestRunTime();
- if (signum != SIGINT) {
- generateStackTrace();
- if (pauseOnCrash) {
- writeToStderr("Pausing process ", asyncSafeToString(getpid()),
- " for debugging\n");
- raise(SIGSTOP);
- }
- }
-
- // chain back to the previous handler, if any
- for (size_t i = 0; i < fatalSignals.size(); ++i) {
- struct sigaction &act = oldActions()[i];
- if (signum != fatalSignals[i])
- continue;
-
- // restore the handler (if SA_RESETHAND hasn't done the job for us)
- if (SA_RESETHAND == 0 || act.sa_handler != SIG_DFL || act.sa_flags)
- (void) sigaction(signum, &act, nullptr);
-
- if (!isCrashingSignal)
- raise(signum);
-
- // signal is blocked, so it'll be delivered when we return
- return;
- }
-
- // we shouldn't reach here!
- std::abort();
- }
-
- [[maybe_unused]] static void regularHandler(int signum)
- {
- actionHandler(signum, nullptr, nullptr);
- }
-
- void *alternateStackBase = MAP_FAILED;
- static bool pauseOnCrash;
-};
-bool FatalSignalHandler::pauseOnCrash = false;
-#else // Q_OS_WASM or weird systems
-class FatalSignalHandler {};
-#endif // Q_OS_* choice
-
-} // unnamed namespace
+} // namespace QTest
static void initEnvironment()
{
@@ -2250,6 +1826,14 @@ int QTest::qExec(QObject *testObject, int argc, char **argv)
qInit(testObject, argc, argv);
int ret = qRun();
qCleanup();
+
+#if defined(Q_OS_WASM)
+ EM_ASM({
+ if (typeof Module != "undefined" && typeof Module.notifyTestFinished != "undefined")
+ Module.notifyTestFinished($0);
+ }, ret);
+#endif // Q_OS_WASM
+
return ret;
}
@@ -2258,7 +1842,7 @@ int QTest::qExec(QObject *testObject, int argc, char **argv)
void QTest::qInit(QObject *testObject, int argc, char **argv)
{
initEnvironment();
- maybeDisableCoreDump();
+ CrashHandler::maybeDisableCoreDump();
QBenchmarkGlobalData::current = new QBenchmarkGlobalData;
#if defined(Q_OS_MACOS)
@@ -2294,10 +1878,7 @@ void QTest::qInit(QObject *testObject, int argc, char **argv)
#if QT_CONFIG(valgrind)
if (QBenchmarkGlobalData::current->mode() != QBenchmarkGlobalData::CallgrindParentProcess)
#endif
- {
- QTestTable::globalTestTable();
QTestLog::startLogging();
- }
}
/*! \internal
@@ -2328,9 +1909,9 @@ int QTest::qRun()
} else
#endif
{
- std::optional<FatalSignalHandler> handler;
- prepareStackTrace();
- if (!noCrashHandler)
+ std::optional<CrashHandler::FatalSignalHandler> handler;
+ CrashHandler::prepareStackTrace();
+ if (!Internal::noCrashHandler)
handler.emplace();
bool seenBad = false;
@@ -2362,7 +1943,12 @@ int QTest::qRun()
return 1;
}
TestMethods test(currentTestObject, std::move(commandLineMethods));
- test.invokeTests(currentTestObject);
+
+ while (QTestLog::failCount() == 0 && (repeatForever || repetitions-- > 0)) {
+ QTestTable::globalTestTable();
+ test.invokeTests(currentTestObject);
+ QTestTable::clearGlobalTestTable();
+ }
}
#ifndef QT_NO_EXCEPTIONS
@@ -2399,10 +1985,7 @@ void QTest::qCleanup()
#if QT_CONFIG(valgrind)
if (QBenchmarkGlobalData::current->mode() != QBenchmarkGlobalData::CallgrindParentProcess)
#endif
- {
QTestLog::stopLogging();
- QTestTable::clearGlobalTestTable();
- }
delete QBenchmarkGlobalData::current;
QBenchmarkGlobalData::current = nullptr;
@@ -2530,6 +2113,39 @@ void QTest::qCaught(const char *expected, const char *what, const char *file, in
qFail(message().toUtf8().constData(), file, line);
}
+/*!
+ \internal
+
+ Contains the implementation of the catch(...) block of
+ QVERIFY_THROWS_EXCEPTION.
+
+ The function inspects std::current_exception() by rethrowing it using
+ std::rethrow_exception().
+
+ The function must be called from a catch handler.
+
+ If the exception inherits std::exception, its what() message is logged and
+ this function returns normally. The caller of this function must then
+ execute a \c{QTEST_FAIL_ACTION} to exit from the test function.
+
+ Otherwise, a message saying an unknown exception was caught is logged and
+ this function rethrows the exception, skipping the \c{QTEST_FAIL_ACTION}
+ that follows this function call in the caller.
+*/
+void QTest::qCaught(const char *expected, const char *file, int line)
+{
+ try {
+ // let's see what the cat brought us:
+ std::rethrow_exception(std::current_exception());
+ } catch (const std::exception &e) {
+ qCaught(expected, e.what(), file, line);
+ } catch (...) {
+ qCaught(expected, nullptr, file, line);
+ throw;
+ }
+ // caller shall invoke `QTEST_FAIL_ACTION` if control reached here
+}
+
#if QT_DEPRECATED_SINCE(6, 3)
/*!
@@ -2689,30 +2305,36 @@ QSharedPointer<QTemporaryDir> QTest::qExtractTestData(const QString &dirName)
return result;
}
- QDirIterator it(resourcePath, QDirIterator::Subdirectories);
- if (!it.hasNext()) {
- qWarning("Resource directory '%s' is empty.", qPrintable(resourcePath));
- return result;
- }
-
- while (it.hasNext()) {
- QFileInfo fileInfo = it.nextFileInfo();
-
- if (!fileInfo.isDir()) {
- const QString destination = dataPath + u'/' + QStringView{fileInfo.filePath()}.mid(resourcePath.size());
+ bool isResourceDirEmpty = true;
+ for (const auto &dirEntry : QDirListing(resourcePath, QDirListing::IteratorFlag::Recursive)) {
+ isResourceDirEmpty = false;
+ if (!dirEntry.isDir()) {
+ const QString &filePath = dirEntry.filePath();
+ const QString destination =
+ dataPath + u'/' + QStringView{filePath}.sliced(resourcePath.size());
QFileInfo destinationFileInfo(destination);
QDir().mkpath(destinationFileInfo.path());
- if (!QFile::copy(fileInfo.filePath(), destination)) {
- qWarning("Failed to copy '%s'.", qPrintable(fileInfo.filePath()));
+ QFile file(filePath);
+ if (!file.copy(destination)) {
+ qWarning("Failed to copy '%ls': %ls.", qUtf16Printable(filePath),
+ qUtf16Printable(file.errorString()));
return result;
}
- if (!QFile::setPermissions(destination, QFile::ReadUser | QFile::WriteUser | QFile::ReadGroup)) {
- qWarning("Failed to set permissions on '%s'.", qPrintable(destination));
+
+ file.setFileName(destination);
+ if (!file.setPermissions(QFile::ReadUser | QFile::WriteUser | QFile::ReadGroup)) {
+ qWarning("Failed to set permissions on '%ls': %ls.", qUtf16Printable(destination),
+ qUtf16Printable(file.errorString()));
return result;
}
}
}
+ if (isResourceDirEmpty) {
+ qWarning("Resource directory '%s' is empty.", qPrintable(resourcePath));
+ return result;
+ }
+
result = std::move(tempDir);
return result;
@@ -3126,6 +2748,7 @@ bool QTest::compare_helper(bool success, const char *failureMsg,
}
#endif // QT_DEPRECATED_SINCE(6, 4)
+#if QT_DEPRECATED_SINCE(6, 8)
/*! \internal
\since 6.4
This function is called by various specializations of QTest::qCompare
@@ -3145,7 +2768,34 @@ bool QTest::compare_helper(bool success, const char *failureMsg,
const char *actual, const char *expected,
const char *file, int line)
{
- return QTestResult::reportResult(success, actualVal, expectedVal, actual, expected,
+ return QTestResult::reportResult(success, &actualVal, &expectedVal,
+ QTest::functionRefFormatter,
+ QTest::functionRefFormatter, actual, expected,
+ QTest::ComparisonOperation::CustomCompare,
+ file, line, failureMsg);
+}
+#endif // QT_DEPRECATED_SINCE(6, 8)
+
+/*! \internal
+ \since 6.8
+ This function is called by various specializations of QTest::qCompare
+ to decide whether to report a failure and to produce verbose test output.
+
+ The \a failureMsg parameter can be \c {nullptr}, in which case a default
+ message will be output if the compare fails. If the comparison succeeds,
+ \a failureMsg will not be output.
+*/
+
+bool QTest::compare_helper(bool success, const char *failureMsg,
+ const void *actualPtr, const void *expectedPtr,
+ const char *(*actualFormatter)(const void *),
+ const char *(*expectedFormatter)(const void *),
+ const char *actual, const char *expected,
+ const char *file, int line)
+{
+ return QTestResult::reportResult(success, actualPtr, expectedPtr,
+ actualFormatter, expectedFormatter,
+ actual, expected,
QTest::ComparisonOperation::CustomCompare,
file, line, failureMsg);
}
@@ -3191,9 +2841,10 @@ static bool floatingCompare(const T &actual, const T &expected)
bool QTest::qCompare(qfloat16 const &t1, qfloat16 const &t2, const char *actual, const char *expected,
const char *file, int line)
{
+ auto formatter = Internal::genericToString<qfloat16>;
return compare_helper(floatingCompare(t1, t2),
"Compared qfloat16s are not the same (fuzzy compare)",
- [&t1] { return toString(t1); }, [&t2] { return toString(t2); },
+ &t1, &t2, formatter, formatter,
actual, expected, file, line);
}
@@ -3458,11 +3109,6 @@ char *QTest::toString(const char *str)
*/
char *QTest::toString(const volatile void *p) // Use volatile to match compare_ptr_helper()
{
- return QTest::toString(const_cast<const void *>(p));
-}
-
-char *QTest::toString(const void *p)
-{
char *msg = new char[128];
qsnprintf(msg, 128, "%p", p);
return msg;
@@ -3515,8 +3161,9 @@ char *QTest::toString(const volatile QObject *vo)
bool QTest::compare_string_helper(const char *t1, const char *t2, const char *actual,
const char *expected, const char *file, int line)
{
+ auto formatter = Internal::genericToString<const char *>;
return compare_helper(qstrcmp(t1, t2) == 0, "Compared strings are not the same",
- [t1] { return toString(t1); }, [t2] { return toString(t2); },
+ &t1, &t2, formatter, formatter,
actual, expected, file, line);
}
diff --git a/src/testlib/qtestcase.h b/src/testlib/qtestcase.h
index 3e0b2b3fb3..0ae1a787e2 100644
--- a/src/testlib/qtestcase.h
+++ b/src/testlib/qtestcase.h
@@ -5,6 +5,7 @@
#define QTESTCASE_H
#include <QtTest/qttestglobal.h>
+#include <QtTest/qtesttostring.h>
#include <QtCore/qstring.h>
#include <QtCore/qnamespace.h>
@@ -23,56 +24,70 @@
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_EXCEPTIONS
+
+#ifdef QTEST_THROW_ON_FAILURE
+# define QTEST_FAIL_ACTION QTest::Internal::throwOnFail()
+#else
+# define QTEST_FAIL_ACTION do { QTest::Internal::maybeThrowOnFail(); return; } while (false)
+#endif
+
+#ifdef QTEST_THROW_ON_SKIP
+# define QTEST_SKIP_ACTION QTest::Internal::throwOnSkip()
+#else
+# define QTEST_SKIP_ACTION do { QTest::Internal::maybeThrowOnSkip(); return; } while (false)
+#endif
+
+#else
+# if defined(QTEST_THROW_ON_FAILURE) || defined(QTEST_THROW_ON_SKIP)
+# error QTEST_THROW_ON_FAILURE/SKIP require exception support enabled.
+# endif
+#endif // QT_NO_EXCEPTIONS
+
+#ifndef QTEST_FAIL_ACTION
+# define QTEST_FAIL_ACTION return
+#endif
+
+#ifndef QTEST_SKIP_ACTION
+# define QTEST_SKIP_ACTION return
+#endif
+
class qfloat16;
class QRegularExpression;
#define QVERIFY(statement) \
do {\
if (!QTest::qVerify(static_cast<bool>(statement), #statement, "", __FILE__, __LINE__))\
- return;\
+ QTEST_FAIL_ACTION; \
} while (false)
#define QFAIL(message) \
do {\
QTest::qFail(static_cast<const char *>(message), __FILE__, __LINE__);\
- return;\
+ QTEST_FAIL_ACTION; \
} while (false)
#define QVERIFY2(statement, description) \
do {\
if (statement) {\
if (!QTest::qVerify(true, #statement, static_cast<const char *>(description), __FILE__, __LINE__))\
- return;\
+ QTEST_FAIL_ACTION; \
} else {\
if (!QTest::qVerify(false, #statement, static_cast<const char *>(description), __FILE__, __LINE__))\
- return;\
+ QTEST_FAIL_ACTION; \
}\
} while (false)
#define QCOMPARE(actual, expected) \
do {\
if (!QTest::qCompare(actual, expected, #actual, #expected, __FILE__, __LINE__))\
- return;\
+ QTEST_FAIL_ACTION; \
} while (false)
-// A wrapper lambda is introduced to extend the lifetime of lhs and rhs in
-// case they are temporary objects.
-// We also use IILE to prevent potential name clashes and shadowing of variables
-// from user code. A drawback of the approach is that it looks ugly :(
#define QCOMPARE_OP_IMPL(lhs, rhs, op, opId) \
do { \
- if (![](auto &&qt_lhs_arg, auto &&qt_rhs_arg) { \
- /* assumes that op does not actually move from qt_{lhs, rhs}_arg */ \
- return QTest::reportResult(std::forward<decltype(qt_lhs_arg)>(qt_lhs_arg) \
- op \
- std::forward<decltype(qt_rhs_arg)>(qt_rhs_arg), \
- [&qt_lhs_arg] { return QTest::toString(qt_lhs_arg); }, \
- [&qt_rhs_arg] { return QTest::toString(qt_rhs_arg); }, \
- #lhs, #rhs, QTest::ComparisonOperation::opId, \
- __FILE__, __LINE__); \
- }(lhs, rhs)) { \
- return; \
- } \
+ if (!QTest::qCompareOp<QTest::ComparisonOperation::opId>(lhs, rhs, #lhs, #rhs, __FILE__, __LINE__)) \
+ QTEST_FAIL_ACTION; \
} while (false)
#define QCOMPARE_EQ(computed, baseline) QCOMPARE_OP_IMPL(computed, baseline, ==, Equal)
@@ -89,12 +104,9 @@ do { \
QT_TRY { \
__VA_ARGS__; \
/* success */ \
- } QT_CATCH (const std::exception &e) { \
- QTest::qCaught(nullptr, e.what(), __FILE__, __LINE__); \
- return; \
} QT_CATCH (...) { \
- QTest::qCaught(nullptr, nullptr, __FILE__, __LINE__); \
- QT_RETHROW; \
+ QTest::qCaught(nullptr, __FILE__, __LINE__); \
+ QTEST_FAIL_ACTION; \
} \
} while (false) \
/* end */
@@ -111,22 +123,20 @@ inline void useVerifyThrowsException() {}
# define QVERIFY_THROWS_EXCEPTION(exceptiontype, ...) \
do {\
+ bool qverify_throws_exception_did_not_throw = false; \
QT_TRY {\
- QT_TRY {\
- __VA_ARGS__;\
- QTest::qFail("Expected exception of type " #exceptiontype " to be thrown" \
- " but no exception caught", __FILE__, __LINE__);\
- return;\
- } QT_CATCH (const exceptiontype &) {\
- /* success */\
- }\
- } QT_CATCH (const std::exception &e) {\
- QTest::qCaught(#exceptiontype, e.what(), __FILE__, __LINE__);\
- return;\
+ __VA_ARGS__; \
+ QTest::qFail("Expected exception of type " #exceptiontype " to be thrown" \
+ " but no exception caught", __FILE__, __LINE__); \
+ qverify_throws_exception_did_not_throw = true; \
+ } QT_CATCH (const exceptiontype &) { \
+ /* success */ \
} QT_CATCH (...) {\
- QTest::qCaught(#exceptiontype, nullptr, __FILE__, __LINE__);\
- QT_RETHROW;\
+ QTest::qCaught(#exceptiontype, __FILE__, __LINE__); \
+ QTEST_FAIL_ACTION; \
}\
+ if (qverify_throws_exception_did_not_throw) \
+ QTEST_FAIL_ACTION; \
} while (false)
#else // QT_NO_EXCEPTIONS
@@ -175,9 +185,14 @@ inline void useVerifyThrowsException() {}
} \
}
-#define QTRY_IMPL(expr, timeout)\
- const int qt_test_step = timeout < 350 ? timeout / 7 + 1 : 50; \
- const int qt_test_timeoutValue = timeout; \
+#define QTRY_IMPL(expr, timeoutAsGiven)\
+ const auto qt_test_timeoutAsMs = [&] { \
+ /* make 5s work w/o user action: */ \
+ using namespace std::chrono_literals; \
+ return std::chrono::milliseconds{timeoutAsGiven}; \
+ }(); \
+ const int qt_test_step = qt_test_timeoutAsMs.count() < 350 ? qt_test_timeoutAsMs.count() / 7 + 1 : 50; \
+ const int qt_test_timeoutValue = qt_test_timeoutAsMs.count(); \
{ QTRY_LOOP_IMPL(expr, qt_test_timeoutValue, qt_test_step) } \
QTRY_TIMEOUT_DEBUG_IMPL(expr, qt_test_timeoutValue, qt_test_step)
// Ends with an if-block, so doesn't want a following semicolon.
@@ -189,7 +204,7 @@ do { \
QVERIFY(expr); \
} while (false)
-#define QTRY_VERIFY(expr) QTRY_VERIFY_WITH_TIMEOUT(expr, 5000)
+#define QTRY_VERIFY(expr) QTRY_VERIFY_WITH_TIMEOUT(expr, 5s)
// Will try to wait for the expression to become true while allowing event processing
#define QTRY_VERIFY2_WITH_TIMEOUT(expr, messageExpression, timeout) \
@@ -198,7 +213,7 @@ do { \
QVERIFY2(expr, messageExpression); \
} while (false)
-#define QTRY_VERIFY2(expr, messageExpression) QTRY_VERIFY2_WITH_TIMEOUT(expr, messageExpression, 5000)
+#define QTRY_VERIFY2(expr, messageExpression) QTRY_VERIFY2_WITH_TIMEOUT(expr, messageExpression, 5s)
// Will try to wait for the comparison to become successful while allowing event processing
#define QTRY_COMPARE_WITH_TIMEOUT(expr, expected, timeout) \
@@ -207,48 +222,49 @@ do { \
QCOMPARE(expr, expected); \
} while (false)
-#define QTRY_COMPARE(expr, expected) QTRY_COMPARE_WITH_TIMEOUT(expr, expected, 5000)
+#define QTRY_COMPARE(expr, expected) QTRY_COMPARE_WITH_TIMEOUT(expr, expected, 5s)
#define QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, op, opId, timeout) \
do { \
- QTRY_IMPL(((computed) op (baseline)), timeout) \
+ using Q_Cmp = QTest::Internal::Compare<QTest::ComparisonOperation::opId>; \
+ QTRY_IMPL(Q_Cmp::compare((computed), (baseline)), timeout) \
QCOMPARE_OP_IMPL(computed, baseline, op, opId); \
} while (false)
#define QTRY_COMPARE_EQ_WITH_TIMEOUT(computed, baseline, timeout) \
QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, ==, Equal, timeout)
-#define QTRY_COMPARE_EQ(computed, baseline) QTRY_COMPARE_EQ_WITH_TIMEOUT(computed, baseline, 5000)
+#define QTRY_COMPARE_EQ(computed, baseline) QTRY_COMPARE_EQ_WITH_TIMEOUT(computed, baseline, 5s)
#define QTRY_COMPARE_NE_WITH_TIMEOUT(computed, baseline, timeout) \
QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, !=, NotEqual, timeout)
-#define QTRY_COMPARE_NE(computed, baseline) QTRY_COMPARE_NE_WITH_TIMEOUT(computed, baseline, 5000)
+#define QTRY_COMPARE_NE(computed, baseline) QTRY_COMPARE_NE_WITH_TIMEOUT(computed, baseline, 5s)
#define QTRY_COMPARE_LT_WITH_TIMEOUT(computed, baseline, timeout) \
QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, <, LessThan, timeout)
-#define QTRY_COMPARE_LT(computed, baseline) QTRY_COMPARE_LT_WITH_TIMEOUT(computed, baseline, 5000)
+#define QTRY_COMPARE_LT(computed, baseline) QTRY_COMPARE_LT_WITH_TIMEOUT(computed, baseline, 5s)
#define QTRY_COMPARE_LE_WITH_TIMEOUT(computed, baseline, timeout) \
QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, <=, LessThanOrEqual, timeout)
-#define QTRY_COMPARE_LE(computed, baseline) QTRY_COMPARE_LE_WITH_TIMEOUT(computed, baseline, 5000)
+#define QTRY_COMPARE_LE(computed, baseline) QTRY_COMPARE_LE_WITH_TIMEOUT(computed, baseline, 5s)
#define QTRY_COMPARE_GT_WITH_TIMEOUT(computed, baseline, timeout) \
QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, >, GreaterThan, timeout)
-#define QTRY_COMPARE_GT(computed, baseline) QTRY_COMPARE_GT_WITH_TIMEOUT(computed, baseline, 5000)
+#define QTRY_COMPARE_GT(computed, baseline) QTRY_COMPARE_GT_WITH_TIMEOUT(computed, baseline, 5s)
#define QTRY_COMPARE_GE_WITH_TIMEOUT(computed, baseline, timeout) \
QTRY_COMPARE_OP_WITH_TIMEOUT_IMPL(computed, baseline, >=, GreaterThanOrEqual, timeout)
-#define QTRY_COMPARE_GE(computed, baseline) QTRY_COMPARE_GE_WITH_TIMEOUT(computed, baseline, 5000)
+#define QTRY_COMPARE_GE(computed, baseline) QTRY_COMPARE_GE_WITH_TIMEOUT(computed, baseline, 5s)
#define QSKIP_INTERNAL(statement) \
do {\
QTest::qSkip(static_cast<const char *>(statement), __FILE__, __LINE__);\
- return;\
+ QTEST_SKIP_ACTION; \
} while (false)
#define QSKIP(statement, ...) QSKIP_INTERNAL(statement)
@@ -256,7 +272,7 @@ do {\
#define QEXPECT_FAIL(dataIndex, comment, mode)\
do {\
if (!QTest::qExpectFail(dataIndex, static_cast<const char *>(comment), QTest::mode, __FILE__, __LINE__))\
- return;\
+ QTEST_FAIL_ACTION; \
} while (false)
#define QFETCH(Type, name)\
@@ -268,7 +284,7 @@ do {\
#define QTEST(actual, testElement)\
do {\
if (!QTest::qTest(actual, testElement, #actual, #testElement, __FILE__, __LINE__))\
- return;\
+ QTEST_FAIL_ACTION; \
} while (false)
#ifdef QT_TESTCASE_BUILDDIR
@@ -290,83 +306,71 @@ do {\
class QObject;
class QTestData;
-#define QTEST_COMPARE_DECL(KLASS)\
- template<> Q_TESTLIB_EXPORT char *toString<KLASS >(const KLASS &);
-
namespace QTest
{
namespace Internal {
+ [[noreturn]] Q_TESTLIB_EXPORT void throwOnFail();
+ [[noreturn]] Q_TESTLIB_EXPORT void throwOnSkip();
+ Q_TESTLIB_EXPORT void maybeThrowOnFail();
+ Q_TESTLIB_EXPORT void maybeThrowOnSkip();
+
Q_TESTLIB_EXPORT QString formatTryTimeoutDebugMessage(q_no_char8_t::QUtf8StringView expr, int timeout, int actual);
- template<typename T> // Output registered enums
- inline typename std::enable_if<QtPrivate::IsQEnumHelper<T>::Value, char*>::type toString(T e)
+ template <ComparisonOperation> struct Compare;
+ template <> struct Compare<ComparisonOperation::Equal>
{
- QMetaEnum me = QMetaEnum::fromType<T>();
- return qstrdup(me.valueToKey(int(e))); // int cast is necessary to support enum classes
- }
-
- template <typename T>
- inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && std::is_enum_v<T>, char*>::type toString(const T &e)
+ template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs)
+ { return std::forward<T1>(lhs) == std::forward<T2>(rhs); }
+ };
+ template <> struct Compare<ComparisonOperation::NotEqual>
{
- return qstrdup(QByteArray::number(static_cast<std::underlying_type_t<T>>(e)).constData());
- }
-
- template <typename T> // Fallback; for built-in types debug streaming must be possible
- inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && !std::is_enum_v<T>, char *>::type toString(const T &t)
- {
-#ifndef QT_NO_DEBUG_STREAM
- if constexpr (QTypeTraits::has_ostream_operator_v<QDebug, T>) {
- return qstrdup(QDebug::toString(t).toUtf8().constData());
- } else {
- static_assert(!QMetaTypeId2<T>::IsBuiltIn,
- "Built-in type must implement debug streaming operator "
- "or provide QTest::toString specialization");
- }
-#endif
- return nullptr;
- }
+ template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs)
+ { return std::forward<T1>(lhs) != std::forward<T2>(rhs); }
+ };
+ template <> struct Compare<ComparisonOperation::LessThan>
+ {
+ template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs)
+ { return std::forward<T1>(lhs) < std::forward<T2>(rhs); }
+ };
+ template <> struct Compare<ComparisonOperation::LessThanOrEqual>
+ {
+ template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs)
+ { return std::forward<T1>(lhs) <= std::forward<T2>(rhs); }
+ };
+ template <> struct Compare<ComparisonOperation::GreaterThan>
+ {
+ template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs)
+ { return std::forward<T1>(lhs) > std::forward<T2>(rhs); }
+ };
+ template <> struct Compare<ComparisonOperation::GreaterThanOrEqual>
+ {
+ template <typename T1, typename T2> static bool compare(T1 &&lhs, T2 &&rhs)
+ { return std::forward<T1>(lhs) >= std::forward<T2>(rhs); }
+ };
- template<typename F> // Output QFlags of registered enumerations
- inline typename std::enable_if<QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f)
+ template <typename T1> const char *genericToString(const void *arg)
{
- const QMetaEnum me = QMetaEnum::fromType<F>();
- return qstrdup(me.valueToKeys(int(f.toInt())).constData());
+ using QTest::toString;
+ return toString(*static_cast<const T1 *>(arg));
}
- template <typename F> // Fallback: Output hex value
- inline typename std::enable_if<!QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f)
+ template <> inline const char *genericToString<char *>(const void *arg)
{
- const size_t space = 3 + 2 * sizeof(unsigned); // 2 for 0x, two hex digits per byte, 1 for '\0'
- char *msg = new char[space];
- qsnprintf(msg, space, "0x%x", unsigned(f.toInt()));
- return msg;
+ using QTest::toString;
+ return toString(static_cast<const char *>(arg));
}
- } // namespace Internal
-
- template<typename T>
- inline char *toString(const T &t)
+ template <typename T> const char *pointerToString(const void *arg)
{
- return Internal::toString(t);
+ using QTest::toString;
+ return toString(static_cast<const T *>(arg));
}
- template <typename T1, typename T2>
- inline char *toString(const QPair<T1, T2> &pair);
-
- template <typename T1, typename T2>
- inline char *toString(const std::pair<T1, T2> &pair);
-
- template <class... Types>
- inline char *toString(const std::tuple<Types...> &tuple);
+ // Exported so Qt Quick Test can also use it for generating backtraces upon crashes.
+ Q_TESTLIB_EXPORT extern bool noCrashHandler;
- Q_TESTLIB_EXPORT char *toHexRepresentation(const char *ba, qsizetype length);
- Q_TESTLIB_EXPORT char *toPrettyCString(const char *unicode, qsizetype length);
- Q_TESTLIB_EXPORT char *toPrettyUnicode(QStringView string);
- Q_TESTLIB_EXPORT char *toString(const char *);
- Q_TESTLIB_EXPORT char *toString(const volatile void *);
- Q_TESTLIB_EXPORT char *toString(const void *); // ### FIXME: Qt 7: Remove
- Q_TESTLIB_EXPORT char *toString(const volatile QObject *);
+ } // namespace Internal
Q_TESTLIB_EXPORT void qInit(QObject *testObject, int argc = 0, char **argv = nullptr);
Q_TESTLIB_EXPORT int qRun();
@@ -381,6 +385,36 @@ namespace QTest
#endif // QT_CONFIG(batch_test_support)
Q_TESTLIB_EXPORT void setMainSourcePath(const char *file, const char *builddir = nullptr);
+ Q_TESTLIB_EXPORT void setThrowOnFail(bool enable) noexcept;
+ Q_TESTLIB_EXPORT void setThrowOnSkip(bool enable) noexcept;
+
+ class ThrowOnFailEnabler {
+ Q_DISABLE_COPY_MOVE(ThrowOnFailEnabler)
+ public:
+ ThrowOnFailEnabler() { setThrowOnFail(true); }
+ ~ThrowOnFailEnabler() { setThrowOnFail(false); }
+ };
+
+ class ThrowOnSkipEnabler {
+ Q_DISABLE_COPY_MOVE(ThrowOnSkipEnabler)
+ public:
+ ThrowOnSkipEnabler() { setThrowOnSkip(true); }
+ ~ThrowOnSkipEnabler() { setThrowOnSkip(false); }
+ };
+
+ class ThrowOnFailDisabler {
+ Q_DISABLE_COPY_MOVE(ThrowOnFailDisabler)
+ public:
+ ThrowOnFailDisabler() { setThrowOnFail(false); }
+ ~ThrowOnFailDisabler() { setThrowOnFail(true); }
+ };
+
+ class ThrowOnSkipDisabler {
+ Q_DISABLE_COPY_MOVE(ThrowOnSkipDisabler)
+ public:
+ ThrowOnSkipDisabler() { setThrowOnSkip(false); }
+ ~ThrowOnSkipDisabler() { setThrowOnSkip(true); }
+ };
Q_TESTLIB_EXPORT bool qVerify(bool statement, const char *statementStr, const char *description,
const char *file, int line);
@@ -391,6 +425,8 @@ namespace QTest
const char *file, int line);
Q_DECL_COLD_FUNCTION
Q_TESTLIB_EXPORT void qCaught(const char *expected, const char *what, const char *file, int line);
+ Q_DECL_COLD_FUNCTION
+ Q_TESTLIB_EXPORT void qCaught(const char *expected, const char *file, int line);
#if QT_DEPRECATED_SINCE(6, 3)
QT_DEPRECATED_VERSION_X_6_3("Use qWarning() instead")
Q_TESTLIB_EXPORT void qWarn(const char *message, const char *file = nullptr, int line = 0);
@@ -426,10 +462,8 @@ namespace QTest
Q_TESTLIB_EXPORT Qt::Key asciiToKey(char ascii);
Q_TESTLIB_EXPORT char keyToAscii(Qt::Key key);
- // ### TODO: remove QTestResult::compare() overload that takes char * values
- // when this overload is removed.
#if QT_DEPRECATED_SINCE(6, 4)
- QT_DEPRECATED_VERSION_X_6_4("use an overload that takes function_ref as parameters, "
+ QT_DEPRECATED_VERSION_X_6_4("use an overload that takes a formatter callback, "
"or an overload that takes only failure message, if you "
"do not need to stringify the values")
Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg,
@@ -437,11 +471,22 @@ namespace QTest
const char *actual, const char *expected,
const char *file, int line);
#endif // QT_DEPRECATED_SINCE(6, 4)
+#if QT_DEPRECATED_SINCE(6, 8)
+ QT_DEPRECATED_VERSION_X_6_8("use an overload that takes a formatter callback, "
+ "or an overload that takes only failure message, if you "
+ "do not need to stringify the values")
Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg,
qxp::function_ref<const char*()> actualVal,
qxp::function_ref<const char*()> expectedVal,
const char *actual, const char *expected,
const char *file, int line);
+#endif // QT_DEPRECATED_SINCE(6, 8)
+ Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg,
+ const void *actualPtr, const void *expectedPtr,
+ const char *(*actualFormatter)(const void *),
+ const char *(*expectedFormatter)(const void *),
+ const char *actual, const char *expected,
+ const char *file, int line);
Q_TESTLIB_EXPORT bool compare_helper(bool success, const char *failureMsg,
const char *actual, const char *expected,
const char *file, int line);
@@ -509,81 +554,71 @@ namespace QTest
inline bool compare_ptr_helper(const volatile void *t1, const volatile void *t2, const char *actual,
const char *expected, const char *file, int line)
{
+ auto formatter = Internal::pointerToString<void>;
return compare_helper(t1 == t2, "Compared pointers are not the same",
- [t1] { return toString(t1); }, [t2] { return toString(t2); },
- actual, expected, file, line);
+ const_cast<const void *>(t1), const_cast<const void *>(t2),
+ formatter, formatter, actual, expected, file, line);
}
inline bool compare_ptr_helper(const volatile QObject *t1, const volatile QObject *t2, const char *actual,
const char *expected, const char *file, int line)
{
+ auto formatter = Internal::pointerToString<QObject>;
return compare_helper(t1 == t2, "Compared QObject pointers are not the same",
- [t1] { return toString(t1); }, [t2] { return toString(t2); },
- actual, expected, file, line);
+ const_cast<const QObject *>(t1), const_cast<const QObject *>(t2),
+ formatter, formatter, actual, expected, file, line);
}
inline bool compare_ptr_helper(const volatile QObject *t1, std::nullptr_t, const char *actual,
const char *expected, const char *file, int line)
{
+ auto lhsFormatter = Internal::pointerToString<QObject>;
+ auto rhsFormatter = Internal::genericToString<std::nullptr_t>;
return compare_helper(t1 == nullptr, "Compared QObject pointers are not the same",
- [t1] { return toString(t1); }, [] { return toString(nullptr); },
- actual, expected, file, line);
+ const_cast<const QObject *>(t1), nullptr,
+ lhsFormatter, rhsFormatter, actual, expected, file, line);
}
inline bool compare_ptr_helper(std::nullptr_t, const volatile QObject *t2, const char *actual,
const char *expected, const char *file, int line)
{
+ auto lhsFormatter = Internal::genericToString<std::nullptr_t>;
+ auto rhsFormatter = Internal::pointerToString<QObject>;
return compare_helper(nullptr == t2, "Compared QObject pointers are not the same",
- [] { return toString(nullptr); }, [t2] { return toString(t2); },
- actual, expected, file, line);
+ nullptr, const_cast<const QObject *>(t2),
+ lhsFormatter, rhsFormatter, actual, expected, file, line);
}
inline bool compare_ptr_helper(const volatile void *t1, std::nullptr_t, const char *actual,
const char *expected, const char *file, int line)
{
+ auto lhsFormatter = Internal::pointerToString<void>;
+ auto rhsFormatter = Internal::genericToString<std::nullptr_t>;
return compare_helper(t1 == nullptr, "Compared pointers are not the same",
- [t1] { return toString(t1); }, [] { return toString(nullptr); },
- actual, expected, file, line);
+ const_cast<const void *>(t1), nullptr,
+ lhsFormatter, rhsFormatter, actual, expected, file, line);
}
inline bool compare_ptr_helper(std::nullptr_t, const volatile void *t2, const char *actual,
const char *expected, const char *file, int line)
{
+ auto lhsFormatter = Internal::genericToString<std::nullptr_t>;
+ auto rhsFormatter = Internal::pointerToString<void>;
return compare_helper(nullptr == t2, "Compared pointers are not the same",
- [] { return toString(nullptr); }, [t2] { return toString(t2); },
- actual, expected, file, line);
+ nullptr, const_cast<const void *>(t2),
+ lhsFormatter, rhsFormatter, actual, expected, file, line);
}
- Q_TESTLIB_EXPORT bool compare_string_helper(const char *t1, const char *t2, const char *actual,
- const char *expected, const char *file, int line);
-
- Q_TESTLIB_EXPORT char *formatString(const char *prefix, const char *suffix, size_t numArguments, ...);
-
-#ifndef Q_QDOC
- QTEST_COMPARE_DECL(short)
- QTEST_COMPARE_DECL(ushort)
- QTEST_COMPARE_DECL(int)
- QTEST_COMPARE_DECL(uint)
- QTEST_COMPARE_DECL(long)
- QTEST_COMPARE_DECL(ulong)
- QTEST_COMPARE_DECL(qint64)
- QTEST_COMPARE_DECL(quint64)
-
- QTEST_COMPARE_DECL(float)
- QTEST_COMPARE_DECL(double)
- QTEST_COMPARE_DECL(qfloat16)
- QTEST_COMPARE_DECL(char)
- QTEST_COMPARE_DECL(signed char)
- QTEST_COMPARE_DECL(unsigned char)
- QTEST_COMPARE_DECL(bool)
-#endif
-
- template <typename T1, typename T2>
+ template <typename T1, typename T2 = T1>
inline bool qCompare(const T1 &t1, const T2 &t2, const char *actual, const char *expected,
const char *file, int line)
{
+ using D1 = std::decay_t<T1>;
+ using D2 = std::decay_t<T2>;
+ using Internal::genericToString;
return compare_helper(t1 == t2, "Compared values are not the same",
- [&t1] { return toString(t1); }, [&t2] { return toString(t2); },
+ std::addressof(t1), std::addressof(t2),
+ genericToString<D1>, genericToString<D2>,
actual, expected, file, line);
}
@@ -671,13 +706,38 @@ namespace QTest
qMetaTypeId<T>())), actualStr, expected, file, line);
}
+#if QT_DEPRECATED_SINCE(6, 8)
+ QT_DEPRECATED_VERSION_X_6_8("use the overload without qxp::function_ref")
Q_TESTLIB_EXPORT bool reportResult(bool success, qxp::function_ref<const char*()> lhs,
qxp::function_ref<const char*()> rhs,
const char *lhsExpr, const char *rhsExpr,
ComparisonOperation op, const char *file, int line);
+#endif // QT_DEPRECATED_SINCE(6, 8)
+
+ Q_TESTLIB_EXPORT bool reportResult(bool success, const void *lhs, const void *rhs,
+ const char *(*lhsFormatter)(const void*),
+ const char *(*rhsFormatter)(const void*),
+ const char *lhsExpr, const char *rhsExpr,
+ ComparisonOperation op, const char *file, int line);
+
+ template <ComparisonOperation op, typename T1, typename T2 = T1>
+ inline bool qCompareOp(T1 &&lhs, T2 &&rhs, const char *lhsExpr, const char *rhsExpr,
+ const char *file, int line)
+ {
+ using D1 = std::decay_t<T1>;
+ using D2 = std::decay_t<T2>;
+ using Internal::genericToString;
+ using Comparator = Internal::Compare<op>;
+
+ /* assumes that op does not actually move from lhs and rhs */
+ bool result = Comparator::compare(std::forward<T1>(lhs), std::forward<T2>(rhs));
+ return reportResult(result, std::addressof(lhs), std::addressof(rhs),
+ genericToString<D1>, genericToString<D2>,
+ lhsExpr, rhsExpr, op, file, line);
+
+ }
}
-#undef QTEST_COMPARE_DECL
#define QWARN(msg) QTest::qWarn(static_cast<const char *>(msg), __FILE__, __LINE__)
diff --git a/src/testlib/qtestcase.qdoc b/src/testlib/qtestcase.qdoc
index 823214a8c4..6a067c351f 100644
--- a/src/testlib/qtestcase.qdoc
+++ b/src/testlib/qtestcase.qdoc
@@ -359,6 +359,10 @@
is reached, a failure is recorded in the test log and the test won't be
executed further.
+ //![chrono-timeout]
+ Since Qt 6.8, the \a timeout can also be a \c{std::chrono} literal such as \c{2s}.
+ //![chrono-timeout]
+
\note This macro can only be used in a test function that is invoked
by the test framework.
@@ -390,9 +394,11 @@
except that it outputs a verbose \a message when \a condition is still false
after the specified \a timeout (in milliseconds). The \a message is a plain C string.
+ \include qtestcase.qdoc chrono-timeout
+
Example:
\code
- QTRY_VERIFY2_WITH_TIMEOUT(list.size() > 2, QByteArray::number(list.size()).constData(), 10000);
+ QTRY_VERIFY2_WITH_TIMEOUT(list.size() > 2, QByteArray::number(list.size()).constData(), 10s);
\endcode
\note This macro can only be used in a test function that is invoked
@@ -413,7 +419,7 @@
Example:
\code
- QTRY_VERIFY2_WITH_TIMEOUT(list.size() > 2, QByteArray::number(list.size()).constData());
+ QTRY_VERIFY2(list.size() > 2, QByteArray::number(list.size()).constData());
\endcode
\note This macro can only be used in a test function that is invoked
@@ -434,6 +440,8 @@
will be processed. If the timeout is reached, a failure is recorded in the
test log and the test won't be executed further.
+ \include qtestcase.qdoc chrono-timeout
+
\note This macro can only be used in a test function that is invoked
by the test framework.
@@ -465,6 +473,8 @@
comparison, events will be processed. If the timeout is reached, a failure
is recorded in the test log and the test won't be executed further.
+ \include qtestcase.qdoc chrono-timeout
+
\include qtestcase.qdoc macro-usage-limitation
\sa QCOMPARE_EQ(), QTRY_COMPARE_EQ()
@@ -492,6 +502,8 @@
comparison, events will be processed. If the timeout is reached, a failure
is recorded in the test log and the test won't be executed further.
+ \include qtestcase.qdoc chrono-timeout
+
\include qtestcase.qdoc macro-usage-limitation
\sa QCOMPARE_NE(), QTRY_COMPARE_NE()
@@ -519,6 +531,8 @@
comparison, events will be processed. If the timeout is reached, a failure
is recorded in the test log and the test won't be executed further.
+ \include qtestcase.qdoc chrono-timeout
+
\include qtestcase.qdoc macro-usage-limitation
\sa QCOMPARE_LT(), QTRY_COMPARE_LT()
@@ -546,6 +560,8 @@
comparison, events will be processed. If the timeout is reached, a failure
is recorded in the test log and the test won't be executed further.
+ \include qtestcase.qdoc chrono-timeout
+
\include qtestcase.qdoc macro-usage-limitation
\sa QCOMPARE_LE(), QTRY_COMPARE_LE()
@@ -573,6 +589,8 @@
comparison, events will be processed. If the timeout is reached, a failure
is recorded in the test log and the test won't be executed further.
+ \include qtestcase.qdoc chrono-timeout
+
\include qtestcase.qdoc macro-usage-limitation
\sa QCOMPARE_GT(), QTRY_COMPARE_GT()
@@ -600,6 +618,8 @@
comparison, events will be processed. If the timeout is reached, a failure
is recorded in the test log and the test won't be executed further.
+ \include qtestcase.qdoc chrono-timeout
+
\include qtestcase.qdoc macro-usage-limitation
\sa QCOMPARE_GE(), QTRY_COMPARE_GE()
@@ -782,7 +802,8 @@
failure will be reported.
If a \l QVERIFY() or \l QCOMPARE() is marked as an expected failure,
- but passes instead, an unexpected pass (XPASS) is written to the test log.
+ but passes instead, an unexpected pass (XPASS) is written to the test log
+ and will be counted as a test failure.
The parameter \a dataIndex describes for which entry in the test data the
failure is expected. Pass an empty string (\c{""}) if the failure
@@ -961,8 +982,8 @@
this macro.
Unlike QBENCHMARK, the contents of the contained code block is only run
- once. The elapsed time will be reported as "0" if it's to short to
- be measured by the selected backend. (Use)
+ once. The elapsed time will be reported as "0" if it's too short to
+ be measured by the selected backend.
\sa {Qt Test Overview#Creating a Benchmark}{Creating a Benchmark},
{Chapter 5: Writing a Benchmark}{Writing a Benchmark}
@@ -1230,7 +1251,7 @@
\sa QTest::keyClick()
*/
-/*! \fn void QTest::mousePress(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers modifier = 0, QPoint pos = QPoint(), int delay=-1)
+/*! \fn void QTest::mousePress(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers modifier, QPoint pos = QPoint(), int delay=-1)
Simulates pressing a mouse \a button with an optional \a modifier
on a \a widget. The position is defined by \a pos; the default
@@ -1241,7 +1262,7 @@
\sa QTest::mouseRelease(), QTest::mouseClick()
*/
-/*! \fn void QTest::mousePress(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0, QPoint pos = QPoint(), int delay=-1)
+/*! \fn void QTest::mousePress(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey, QPoint pos = QPoint(), int delay=-1)
\overload
\since 5.0
@@ -1254,7 +1275,7 @@
\sa QTest::mouseRelease(), QTest::mouseClick()
*/
-/*! \fn void QTest::mouseRelease(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers modifier = 0, QPoint pos = QPoint(), int delay=-1)
+/*! \fn void QTest::mouseRelease(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers modifier, QPoint pos = QPoint(), int delay=-1)
Simulates releasing a mouse \a button with an optional \a modifier
on a \a widget. The position of the release is defined by \a pos;
@@ -1274,7 +1295,7 @@
\sa QTest::mousePress(), QTest::mouseClick()
*/
-/*! \fn void QTest::mouseRelease(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0, QPoint pos = QPoint(), int delay=-1)
+/*! \fn void QTest::mouseRelease(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey, QPoint pos = QPoint(), int delay=-1)
\overload
\since 5.0
@@ -1296,7 +1317,7 @@
\sa QTest::mousePress(), QTest::mouseClick()
*/
-/*! \fn void QTest::mouseClick(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers modifier = 0, QPoint pos = QPoint(), int delay=-1)
+/*! \fn void QTest::mouseClick(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers modifier, QPoint pos = QPoint(), int delay=-1)
Simulates clicking a mouse \a button with an optional \a modifier
on a \a widget. The position of the click is defined by \a pos;
@@ -1307,7 +1328,7 @@
\sa QTest::mousePress(), QTest::mouseRelease()
*/
-/*! \fn void QTest::mouseClick(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0, QPoint pos = QPoint(), int delay=-1)
+/*! \fn void QTest::mouseClick(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey, QPoint pos = QPoint(), int delay=-1)
\overload
\since 5.0
@@ -1320,7 +1341,7 @@
\sa QTest::mousePress(), QTest::mouseRelease()
*/
-/*! \fn void QTest::mouseDClick(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers modifier = 0, QPoint pos = QPoint(), int delay=-1)
+/*! \fn void QTest::mouseDClick(QWidget *widget, Qt::MouseButton button, Qt::KeyboardModifiers modifier, QPoint pos = QPoint(), int delay=-1)
Simulates double clicking a mouse \a button with an optional \a
modifier on a \a widget. The position of the click is defined by
@@ -1331,7 +1352,7 @@
\sa QTest::mouseClick()
*/
-/*! \fn void QTest::mouseDClick(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = 0, QPoint pos = QPoint(), int delay=-1)
+/*! \fn void QTest::mouseDClick(QWindow *window, Qt::MouseButton button, Qt::KeyboardModifiers stateKey, QPoint pos = QPoint(), int delay=-1)
\overload
\since 5.0
@@ -1362,11 +1383,15 @@
moving the mouse pointer.
*/
-/*!
- \fn template <typename T1, typename T2> char *QTest::toString(const QPair<T1, T2> &pair)
- \overload
- \since 5.11
- Returns a textual representation of the \a pair.
+/*! \fn void QTest::wheelEvent(QWindow *window, QPointF pos, QPoint angleDelta, QPoint pixelDelta = QPoint(0, 0), Qt::KeyboardModifiers stateKey = Qt::NoModifier, Qt::ScrollPhase phase = Qt::NoScrollPhase)
+ \since 6.8
+
+ Simulates a wheel event within \a window at position \a pos in local
+ window coordinates. \a angleDelta contains the wheel rotation angle.
+ A positive value means forward rotation, and a negative one means backward.
+ \a pixelDelta contains the scrolling distance in pixels on screen. This value can be null.
+ The keyboard states at the time of the event are specified by \a stateKey.
+ The scrolling phase of the event is specified by \a phase.
*/
/*!
@@ -1398,7 +1423,7 @@
*/
/*!
- \fn template<typename T> char *QTest::toString(const T &value)
+ \fn template<typename T, QTest::Internal::is_suitable_type_v<T> = true> char *QTest::toString(const T &value)
Returns a textual representation of \a value. This function is used by
\l QCOMPARE() to output verbose information in case of a test failure.
@@ -1583,7 +1608,8 @@
*/
/*!
- \fn char *QTest::toString(QSizePolicy::ControlType ct)
+ \fn char *toString(QSizePolicy::ControlType ct)
+ \relates QTest
\overload
\since 5.5
@@ -1591,7 +1617,8 @@
*/
/*!
- \fn char *QTest::toString(QSizePolicy::ControlTypes cts)
+ \fn char *toString(QSizePolicy::ControlTypes cts)
+ \relates QTest
\overload
\since 5.5
@@ -1599,7 +1626,8 @@
*/
/*!
- \fn char *QTest::toString(QSizePolicy::Policy p)
+ \fn char *toString(QSizePolicy::Policy p)
+ \relates QTest
\overload
\since 5.5
@@ -1607,7 +1635,8 @@
*/
/*!
- \fn char *QTest::toString(QSizePolicy sp)
+ \fn char *toString(QSizePolicy sp)
+ \relates QTest
\overload
\since 5.5
@@ -1622,22 +1651,16 @@
*/
/*!
- \fn template <typename Tuple, int... I> char *QTest::toString(const Tuple &tuple, QtPrivate::IndexesList<I...> )
- \internal
- \since 5.12
-*/
-
-/*!
\fn QPointingDevice * QTest::createTouchDevice(QInputDevice::DeviceType devType = QInputDevice::DeviceType::TouchScreen, QInputDevice::Capabilities caps = QInputDevice::Capability::Position)
\since 5.8
Creates a dummy touch device of type \a devType with capabilities \a caps for
simulation of touch events.
- The touch device will be registered with the QPA window system interface,
- and deleted automatically when the QCoreApplication is deleted. So you
- should typically use createTouchDevice() to initialize a QPointingDevice
- member variable in your test case class, and use the same instance for all tests.
+ The touch device will be registered with the Qt window system interface.
+ You should typically use createTouchDevice() to initialize a QPointingDevice
+ member variable in your test case class, use the same instance for all tests and
+ delete it when no longer needed.
\sa QTest::QTouchEventSequence, touchEvent()
*/
diff --git a/src/testlib/qtestcase_p.h b/src/testlib/qtestcase_p.h
index 91a5314f97..ef3e083f88 100644
--- a/src/testlib/qtestcase_p.h
+++ b/src/testlib/qtestcase_p.h
@@ -16,7 +16,6 @@
//
#include <QtTest/qtestcase.h>
-#include <QtTest/private/qttestexports_p.h>
#include <QtTest/qttestglobal.h>
#include <QtCore/qstring.h>
@@ -26,8 +25,8 @@ QT_BEGIN_NAMESPACE
namespace QTest {
#if QT_CONFIG(batch_test_support)
- Q_TESTLIB_PRIVATE_EXPORT QList<QString> qGetTestCaseNames();
- Q_TESTLIB_PRIVATE_EXPORT TestEntryFunction qGetTestCaseEntryFunction(const QString &name);
+ Q_TESTLIB_EXPORT QList<QString> qGetTestCaseNames();
+ Q_TESTLIB_EXPORT TestEntryFunction qGetTestCaseEntryFunction(const QString &name);
#endif // QT_CONFIG(batch_test_support)
} // namespace QTest
diff --git a/src/testlib/qtestcrashhandler.cpp b/src/testlib/qtestcrashhandler.cpp
new file mode 100644
index 0000000000..aabac1c466
--- /dev/null
+++ b/src/testlib/qtestcrashhandler.cpp
@@ -0,0 +1,663 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// Copyright (C) 2024 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include <QtTest/qtestcase.h>
+#include <QtTest/private/qtestcrashhandler_p.h>
+#include <QtTest/qtestassert.h>
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qdiriterator.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qfloat16.h>
+#include <QtCore/qlibraryinfo.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qtemporarydir.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/private/qlocking_p.h>
+#include <QtCore/private/qtools_p.h>
+#include <QtCore/private/qwaitcondition_p.h>
+
+#include <QtCore/qtestsupport_core.h>
+
+#include <QtTest/private/qtestlog_p.h>
+#include <QtTest/private/qtesttable_p.h>
+#include <QtTest/qtestdata.h>
+#include <QtTest/private/qtestresult_p.h>
+#include <QtTest/private/qsignaldumper_p.h>
+#include <QtTest/private/qbenchmark_p.h>
+#if QT_CONFIG(batch_test_support)
+#include <QtTest/private/qtestregistry_p.h>
+#endif // QT_CONFIG(batch_test_support)
+#include <QtTest/private/cycle_p.h>
+#include <QtTest/private/qtestblacklist_p.h>
+#if defined(HAVE_XCTEST)
+#include <QtTest/private/qxctestlogger_p.h>
+#endif
+#if defined Q_OS_MACOS
+#include <QtTest/private/qtestutil_macos_p.h>
+#endif
+
+#if defined(Q_OS_DARWIN)
+#include <QtTest/private/qappletestlogger_p.h>
+#endif
+
+#if !defined(Q_OS_INTEGRITY) || __GHS_VERSION_NUMBER > 202014
+# include <charconv>
+#else
+// Broken implementation, causes link failures just by #include'ing!
+# undef __cpp_lib_to_chars // in case <version> was included
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined(Q_OS_LINUX)
+#include <sys/types.h>
+#include <fcntl.h>
+#endif
+
+#ifdef Q_OS_UNIX
+#include <QtCore/private/qcore_unix_p.h>
+
+#include <errno.h>
+#if __has_include(<paths.h>)
+# include <paths.h>
+#endif
+#include <signal.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <unistd.h>
+# if !defined(Q_OS_INTEGRITY)
+# include <sys/resource.h>
+# endif
+# ifndef _PATH_DEFPATH
+# define _PATH_DEFPATH "/usr/bin:/bin"
+# endif
+# ifndef SIGSTKSZ
+# define SIGSTKSZ 0 /* we have code to set the minimum */
+# endif
+# ifndef SA_RESETHAND
+# define SA_RESETHAND 0
+# endif
+#endif
+
+#if defined(Q_OS_MACOS)
+#include <IOKit/pwr_mgt/IOPMLib.h>
+#include <mach/task.h>
+#include <mach/mach_init.h>
+#include <CoreFoundation/CFPreferences.h>
+#endif
+
+#if defined(Q_OS_WASM)
+#include <emscripten.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+namespace QTest {
+namespace CrashHandler {
+#if defined(Q_OS_UNIX) && (!defined(Q_OS_WASM) || QT_CONFIG(thread))
+struct iovec IoVec(struct iovec vec)
+{
+ return vec;
+}
+struct iovec IoVec(const char *str)
+{
+ struct iovec r = {};
+ r.iov_base = const_cast<char *>(str);
+ r.iov_len = strlen(str);
+ return r;
+}
+
+struct iovec asyncSafeToString(int n, AsyncSafeIntBuffer &&result)
+{
+ char *ptr = result.array.data();
+ if (false) {
+#ifdef __cpp_lib_to_chars
+ } else if (auto r = std::to_chars(ptr, ptr + result.array.size(), n, 10); r.ec == std::errc{}) {
+ ptr = r.ptr;
+#endif
+ } else {
+ // handle the sign
+ if (n < 0) {
+ *ptr++ = '-';
+ n = -n;
+ }
+
+ // find the highest power of the base that is less than this number
+ static constexpr int StartingDivider = ([]() {
+ int divider = 1;
+ for (int i = 0; i < std::numeric_limits<int>::digits10; ++i)
+ divider *= 10;
+ return divider;
+ }());
+ int divider = StartingDivider;
+ while (divider && n < divider)
+ divider /= 10;
+
+ // now convert to string
+ while (divider > 1) {
+ int quot = n / divider;
+ n = n % divider;
+ divider /= 10;
+ *ptr++ = quot + '0';
+ }
+ *ptr++ = n + '0';
+ }
+
+#ifndef QT_NO_DEBUG
+ // this isn't necessary, it just helps in the debugger
+ *ptr = '\0';
+#endif
+ struct iovec r;
+ r.iov_base = result.array.data();
+ r.iov_len = ptr - result.array.data();
+ return r;
+};
+#endif // defined(Q_OS_UNIX) && (!defined(Q_OS_WASM) || QT_CONFIG(thread))
+
+bool alreadyDebugging()
+{
+#if defined(Q_OS_LINUX)
+ int fd = open("/proc/self/status", O_RDONLY);
+ if (fd == -1)
+ return false;
+ char buffer[2048];
+ ssize_t size = read(fd, buffer, sizeof(buffer) - 1);
+ if (size == -1) {
+ close(fd);
+ return false;
+ }
+ buffer[size] = 0;
+ const char tracerPidToken[] = "\nTracerPid:";
+ char *tracerPid = strstr(buffer, tracerPidToken);
+ if (!tracerPid) {
+ close(fd);
+ return false;
+ }
+ tracerPid += sizeof(tracerPidToken);
+ long int pid = strtol(tracerPid, &tracerPid, 10);
+ close(fd);
+ return pid != 0;
+#elif defined(Q_OS_WIN)
+ return IsDebuggerPresent();
+#elif defined(Q_OS_MACOS)
+ // 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;
+ }
+ }
+ }
+ return false;
+#else
+ // TODO
+ return false;
+#endif
+}
+
+namespace {
+enum DebuggerProgram { None, Gdb, Lldb };
+static bool hasSystemCrashReporter()
+{
+#if defined(Q_OS_MACOS)
+ return QTestPrivate::macCrashReporterWillShowDialog();
+#else
+ return false;
+#endif
+}
+} // unnamed namespaced
+
+void maybeDisableCoreDump()
+{
+#ifdef RLIMIT_CORE
+ bool ok = false;
+ const int disableCoreDump = qEnvironmentVariableIntValue("QTEST_DISABLE_CORE_DUMP", &ok);
+ if (ok && disableCoreDump) {
+ struct rlimit limit;
+ limit.rlim_cur = 0;
+ limit.rlim_max = 0;
+ if (setrlimit(RLIMIT_CORE, &limit) != 0)
+ qWarning("Failed to disable core dumps: %d", errno);
+ }
+#endif
+}
+
+static DebuggerProgram debugger = None;
+void prepareStackTrace()
+{
+
+ bool ok = false;
+ const int disableStackDump = qEnvironmentVariableIntValue("QTEST_DISABLE_STACK_DUMP", &ok);
+ if (ok && disableStackDump)
+ return;
+
+ if (hasSystemCrashReporter())
+ return;
+
+#if defined(Q_OS_MACOS)
+ #define CSR_ALLOW_UNRESTRICTED_FS (1 << 1)
+ std::optional<uint32_t> sipConfiguration = qt_mac_sipConfiguration();
+ if (!sipConfiguration || !(*sipConfiguration & CSR_ALLOW_UNRESTRICTED_FS))
+ return; // LLDB will fail to provide a valid stack trace
+#endif
+
+#ifdef Q_OS_UNIX
+ // like QStandardPaths::findExecutable(), but simpler
+ auto hasExecutable = [](const char *execname) {
+ std::string candidate;
+ std::string path;
+ if (const char *p = getenv("PATH"); p && *p)
+ path = p;
+ else
+ path = _PATH_DEFPATH;
+ for (const char *p = std::strtok(&path[0], ":'"); p; p = std::strtok(nullptr, ":")) {
+ candidate = p;
+ candidate += '/';
+ candidate += execname;
+ if (QT_ACCESS(candidate.data(), X_OK) == 0)
+ return true;
+ }
+ return false;
+ };
+
+ static constexpr DebuggerProgram debuggerSearchOrder[] = {
+# if defined(Q_OS_QNX) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
+ Gdb, Lldb
+# else
+ Lldb, Gdb
+# endif
+ };
+ for (DebuggerProgram candidate : debuggerSearchOrder) {
+ switch (candidate) {
+ case None:
+ Q_UNREACHABLE();
+ break;
+ case Gdb:
+ if (hasExecutable("gdb")) {
+ debugger = Gdb;
+ return;
+ }
+ break;
+ case Lldb:
+ if (hasExecutable("lldb")) {
+ debugger = Lldb;
+ return;
+ }
+ break;
+ }
+ }
+#endif // Q_OS_UNIX
+}
+
+#if !defined(Q_OS_WASM) || QT_CONFIG(thread)
+void printTestRunTime()
+{
+ const int msecsFunctionTime = qRound(QTestLog::msecsFunctionTime());
+ const int msecsTotalTime = qRound(QTestLog::msecsTotalTime());
+ const char *const name = QTest::currentTestFunction();
+ writeToStderr("\n ", name ? name : "[Non-test]",
+ " function time: ", asyncSafeToString(msecsFunctionTime),
+ "ms, total time: ", asyncSafeToString(msecsTotalTime), "ms\n");
+}
+
+void generateStackTrace()
+{
+ if (debugger == None || alreadyDebugging())
+ return;
+
+# if defined(Q_OS_UNIX) && !defined(Q_OS_WASM) && !defined(Q_OS_INTEGRITY) && !defined(Q_OS_VXWORKS)
+ writeToStderr("\n=== Stack trace ===\n");
+
+ // execlp() requires null-termination, so call the default constructor
+ AsyncSafeIntBuffer pidbuffer;
+ asyncSafeToString(getpid(), std::move(pidbuffer));
+
+ // Note: POSIX.1-2001 still has fork() in the list of async-safe functions,
+ // but in a future edition, it might be removed. It would be safer to wake
+ // up a babysitter thread to launch the debugger.
+ pid_t pid = fork();
+ if (pid == 0) {
+ // child process
+ (void) dup2(STDERR_FILENO, STDOUT_FILENO); // redirect stdout to stderr
+
+ switch (debugger) {
+ case None:
+ Q_UNREACHABLE();
+ break;
+ case Gdb:
+ execlp("gdb", "gdb", "--nx", "--batch", "-ex", "thread apply all bt",
+ "--pid", pidbuffer.array.data(), nullptr);
+ break;
+ case Lldb:
+ execlp("lldb", "lldb", "--no-lldbinit", "--batch", "-o", "bt all",
+ "--attach-pid", pidbuffer.array.data(), nullptr);
+ break;
+ }
+ _exit(1);
+ } else if (pid < 0) {
+ writeToStderr("Failed to start debugger.\n");
+ } else {
+ int ret;
+ QT_EINTR_LOOP(ret, waitpid(pid, nullptr, 0));
+ }
+
+ writeToStderr("=== End of stack trace ===\n");
+# endif // Q_OS_UNIX && !Q_OS_WASM && !Q_OS_INTEGRITY && !Q_OS_VXWORKS
+}
+#endif // !defined(Q_OS_WASM) || QT_CONFIG(thread)
+
+#if defined(Q_OS_WIN)
+void blockUnixSignals()
+{
+ // Windows does have C signals, but doesn't use them for the purposes we're
+ // talking about here
+}
+#elif defined(Q_OS_UNIX) && !defined(Q_OS_WASM)
+void blockUnixSignals()
+{
+ // Block most Unix signals so the WatchDog thread won't be called when
+ // external signals are delivered, thus avoiding interfering with the test
+ sigset_t set;
+ sigfillset(&set);
+
+ // we allow the crashing signals, in case we have bugs
+ for (int signo : FatalSignalHandler::fatalSignals)
+ sigdelset(&set, signo);
+
+ pthread_sigmask(SIG_BLOCK, &set, nullptr);
+}
+#endif // Q_OS_* choice
+
+#if defined(Q_OS_WIN)
+void DebugSymbolResolver::cleanup()
+{
+ if (m_dbgHelpLib)
+ FreeLibrary(m_dbgHelpLib);
+ m_dbgHelpLib = 0;
+ m_symFromAddr = nullptr;
+}
+
+DebugSymbolResolver::DebugSymbolResolver(HANDLE process)
+ : m_process(process), m_dbgHelpLib(0), m_symFromAddr(nullptr)
+{
+ bool success = false;
+ m_dbgHelpLib = LoadLibraryW(L"dbghelp.dll");
+ if (m_dbgHelpLib) {
+ SymInitializeType symInitialize = reinterpret_cast<SymInitializeType>(
+ reinterpret_cast<QFunctionPointer>(GetProcAddress(m_dbgHelpLib, "SymInitialize")));
+ m_symFromAddr = reinterpret_cast<SymFromAddrType>(
+ reinterpret_cast<QFunctionPointer>(GetProcAddress(m_dbgHelpLib, "SymFromAddr")));
+ success = symInitialize && m_symFromAddr && symInitialize(process, NULL, TRUE);
+ }
+ if (!success)
+ cleanup();
+}
+
+DebugSymbolResolver::Symbol DebugSymbolResolver::resolveSymbol(DWORD64 address) const
+{
+ // reserve additional buffer where SymFromAddr() will store the name
+ struct NamedSymbolInfo : public DBGHELP_SYMBOL_INFO {
+ enum { symbolNameLength = 255 };
+
+ char name[symbolNameLength + 1];
+ };
+
+ Symbol result;
+ if (!isValid())
+ return result;
+ NamedSymbolInfo symbolBuffer;
+ memset(&symbolBuffer, 0, sizeof(NamedSymbolInfo));
+ symbolBuffer.MaxNameLen = NamedSymbolInfo::symbolNameLength;
+ symbolBuffer.SizeOfStruct = sizeof(DBGHELP_SYMBOL_INFO);
+ if (!m_symFromAddr(m_process, address, 0, &symbolBuffer))
+ return result;
+ result.name = qstrdup(symbolBuffer.Name);
+ result.address = symbolBuffer.Address;
+ return result;
+}
+
+WindowsFaultHandler::WindowsFaultHandler()
+{
+# if !defined(Q_CC_MINGW)
+ _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
+# endif
+ SetErrorMode(SetErrorMode(0) | SEM_NOGPFAULTERRORBOX);
+ SetUnhandledExceptionFilter(windowsFaultHandler);
+}
+
+LONG WINAPI WindowsFaultHandler::windowsFaultHandler(struct _EXCEPTION_POINTERS *exInfo)
+{
+ enum { maxStackFrames = 100 };
+ char appName[MAX_PATH];
+ if (!GetModuleFileNameA(NULL, appName, MAX_PATH))
+ appName[0] = 0;
+ const int msecsFunctionTime = qRound(QTestLog::msecsFunctionTime());
+ const int msecsTotalTime = qRound(QTestLog::msecsTotalTime());
+ const void *exceptionAddress = exInfo->ExceptionRecord->ExceptionAddress;
+ fprintf(stderr, "A crash occurred in %s.\n", appName);
+ if (const char *name = QTest::currentTestFunction())
+ fprintf(stderr, "While testing %s\n", name);
+ fprintf(stderr, "Function time: %dms Total time: %dms\n\n"
+ "Exception address: 0x%p\n"
+ "Exception code : 0x%lx\n",
+ msecsFunctionTime, msecsTotalTime, exceptionAddress,
+ exInfo->ExceptionRecord->ExceptionCode);
+
+ DebugSymbolResolver resolver(GetCurrentProcess());
+ if (resolver.isValid()) {
+ DebugSymbolResolver::Symbol exceptionSymbol = resolver.resolveSymbol(DWORD64(exceptionAddress));
+ if (exceptionSymbol.name) {
+ fprintf(stderr, "Nearby symbol : %s\n", exceptionSymbol.name);
+ delete [] exceptionSymbol.name;
+ }
+ void *stack[maxStackFrames];
+ fputs("\nStack:\n", stderr);
+ const unsigned frameCount = CaptureStackBackTrace(0, DWORD(maxStackFrames), stack, NULL);
+ for (unsigned f = 0; f < frameCount; ++f) {
+ DebugSymbolResolver::Symbol symbol = resolver.resolveSymbol(DWORD64(stack[f]));
+ if (symbol.name) {
+ fprintf(stderr, "#%3u: %s() - 0x%p\n", f + 1, symbol.name, (const void *)symbol.address);
+ delete [] symbol.name;
+ } else {
+ fprintf(stderr, "#%3u: Unable to obtain symbol\n", f + 1);
+ }
+ }
+ }
+
+ fputc('\n', stderr);
+
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+#elif defined(Q_OS_UNIX) && !defined(Q_OS_WASM)
+bool FatalSignalHandler::pauseOnCrash = false;
+
+FatalSignalHandler::FatalSignalHandler()
+{
+ pauseOnCrash = qEnvironmentVariableIsSet("QTEST_PAUSE_ON_CRASH");
+ struct sigaction act;
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = SIG_DFL;
+ oldActions().fill(act);
+
+ // Remove the handler after it is invoked.
+ act.sa_flags = SA_RESETHAND | setupAlternateStack();
+
+# ifdef SA_SIGINFO
+ act.sa_flags |= SA_SIGINFO;
+ act.sa_sigaction = FatalSignalHandler::actionHandler;
+# else
+ act.sa_handler = FatalSignalHandler::regularHandler;
+# endif
+
+ // Block all fatal signals in our signal handler so we don't try to close
+ // the testlog twice.
+ sigemptyset(&act.sa_mask);
+ for (int signal : fatalSignals)
+ sigaddset(&act.sa_mask, signal);
+
+ for (size_t i = 0; i < fatalSignals.size(); ++i)
+ sigaction(fatalSignals[i], &act, &oldActions()[i]);
+}
+
+FatalSignalHandler::~FatalSignalHandler()
+{
+ // Restore the default signal handlers in place of ours.
+ // If ours has been replaced, leave the replacement alone.
+ auto isOurs = [](const struct sigaction &old) {
+# ifdef SA_SIGINFO
+ return (old.sa_flags & SA_SIGINFO) && old.sa_sigaction == FatalSignalHandler::actionHandler;
+# else
+ return old.sa_handler == FatalSignalHandler::regularHandler;
+# endif
+ };
+ struct sigaction action;
+
+ for (size_t i = 0; i < fatalSignals.size(); ++i) {
+ struct sigaction &act = oldActions()[i];
+ if (act.sa_flags == 0 && act.sa_handler == SIG_DFL)
+ continue; // Already the default
+ if (sigaction(fatalSignals[i], nullptr, &action))
+ continue; // Failed to query present handler
+ if (isOurs(action))
+ sigaction(fatalSignals[i], &act, nullptr);
+ }
+
+ freeAlternateStack();
+}
+
+FatalSignalHandler::OldActionsArray &FatalSignalHandler::oldActions()
+{
+ Q_CONSTINIT static OldActionsArray oldActions {};
+ return oldActions;
+}
+
+auto FatalSignalHandler::alternateStackSize()
+{
+ struct R { size_t size, pageSize; };
+ static constexpr size_t MinStackSize = 32 * 1024;
+ size_t pageSize = sysconf(_SC_PAGESIZE);
+ size_t size = SIGSTKSZ;
+ if (size < MinStackSize) {
+ size = MinStackSize;
+ } else {
+ // round up to a page
+ size = (size + pageSize - 1) & -pageSize;
+ }
+
+ return R{ size + pageSize, pageSize };
+}
+
+int FatalSignalHandler::setupAlternateStack()
+{
+ // tvOS/watchOS both define SA_ONSTACK (in sys/signal.h) but mark sigaltstack() as
+ // unavailable (__WATCHOS_PROHIBITED __TVOS_PROHIBITED in signal.h)
+# if defined(SA_ONSTACK) && !defined(Q_OS_TVOS) && !defined(Q_OS_WATCHOS)
+ // Let the signal handlers use an alternate stack
+ // This is necessary if SIGSEGV is to catch a stack overflow
+ auto r = alternateStackSize();
+ int flags = MAP_PRIVATE | MAP_ANONYMOUS;
+# ifdef MAP_STACK
+ flags |= MAP_STACK;
+# endif
+ alternateStackBase = mmap(nullptr, r.size, PROT_READ | PROT_WRITE, flags, -1, 0);
+ if (alternateStackBase == MAP_FAILED)
+ return 0;
+
+ // mark the bottom page inaccessible, to catch a handler stack overflow
+ (void) mprotect(alternateStackBase, r.pageSize, PROT_NONE);
+
+ stack_t stack;
+ stack.ss_flags = 0;
+ stack.ss_size = r.size - r.pageSize;
+ stack.ss_sp = static_cast<char *>(alternateStackBase) + r.pageSize;
+ sigaltstack(&stack, nullptr);
+ return SA_ONSTACK;
+# else
+ return 0;
+# endif
+}
+
+void FatalSignalHandler::freeAlternateStack()
+{
+# if defined(SA_ONSTACK) && !defined(Q_OS_TVOS) && !defined(Q_OS_WATCHOS)
+ if (alternateStackBase != MAP_FAILED) {
+ stack_t stack = {};
+ stack.ss_flags = SS_DISABLE;
+ sigaltstack(&stack, nullptr);
+ munmap(alternateStackBase, alternateStackSize().size);
+ }
+# endif
+}
+
+void FatalSignalHandler::actionHandler(int signum, siginfo_t *info, void *)
+{
+ writeToStderr("Received signal ", asyncSafeToString(signum),
+ " (SIG", signalName(signum), ")");
+
+ bool isCrashingSignal =
+ std::find(crashingSignals.begin(), crashingSignals.end(), signum) != crashingSignals.end();
+ if (isCrashingSignal && (!info || info->si_code <= 0))
+ isCrashingSignal = false; // wasn't sent by the kernel, so it's not really a crash
+ if (isCrashingSignal)
+ printCrashingSignalInfo(info);
+ else if (info && (info->si_code == SI_USER || info->si_code == SI_QUEUE))
+ printSentSignalInfo(info);
+
+ printTestRunTime();
+ if (signum != SIGINT) {
+ generateStackTrace();
+ if (pauseOnCrash) {
+ writeToStderr("Pausing process ", asyncSafeToString(getpid()),
+ " for debugging\n");
+ raise(SIGSTOP);
+ }
+ }
+
+ // chain back to the previous handler, if any
+ for (size_t i = 0; i < fatalSignals.size(); ++i) {
+ struct sigaction &act = oldActions()[i];
+ if (signum != fatalSignals[i])
+ continue;
+
+ // restore the handler (if SA_RESETHAND hasn't done the job for us)
+ if (SA_RESETHAND == 0 || act.sa_handler != SIG_DFL || act.sa_flags)
+ (void) sigaction(signum, &act, nullptr);
+
+ if (!isCrashingSignal)
+ raise(signum);
+
+ // signal is blocked, so it'll be delivered when we return
+ return;
+ }
+
+ // we shouldn't reach here!
+ std::abort();
+}
+#endif // defined(Q_OS_UNIX) && !defined(Q_OS_WASM)
+
+} // namespace CrashHandler
+} // namespace QTest
+
+QT_END_NAMESPACE
diff --git a/src/testlib/qtestcrashhandler_p.h b/src/testlib/qtestcrashhandler_p.h
new file mode 100644
index 0000000000..02e19bfaa9
--- /dev/null
+++ b/src/testlib/qtestcrashhandler_p.h
@@ -0,0 +1,251 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+//
+// 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.
+//
+
+#ifndef QTESTCRASHHANDLER_H
+#define QTESTCRASHHANDLER_H
+
+#include <QtTest/qttestglobal.h>
+
+#include <QtCore/private/qtools_p.h>
+
+#ifdef Q_OS_UNIX
+#include <signal.h>
+#include <sys/mman.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#endif
+
+#ifdef Q_OS_WIN
+#include <iostream>
+# if !defined(Q_CC_MINGW) || (defined(Q_CC_MINGW) && defined(__MINGW64_VERSION_MAJOR))
+# include <crtdbg.h>
+# endif
+#include <qt_windows.h> // for Sleep
+#endif
+
+QT_BEGIN_NAMESPACE
+namespace QTest {
+namespace CrashHandler {
+#if defined(Q_OS_UNIX) && (!defined(Q_OS_WASM) || QT_CONFIG(thread))
+ struct iovec IoVec(struct iovec vec);
+ struct iovec IoVec(const char *str);
+
+ template <typename... Args> static ssize_t writeToStderr(Args &&... args)
+ {
+ struct iovec vec[] = { IoVec(std::forward<Args>(args))... };
+ return ::writev(STDERR_FILENO, vec, std::size(vec));
+ }
+
+ // async-signal-safe conversion from int to string
+ struct AsyncSafeIntBuffer
+ {
+ // digits10 + 1 for all possible digits
+ // +1 for the sign
+ // +1 for the terminating null
+ static constexpr int Digits10 = std::numeric_limits<int>::digits10 + 3;
+ std::array<char, Digits10> array;
+ constexpr AsyncSafeIntBuffer() : array{} {} // initializes array
+ AsyncSafeIntBuffer(Qt::Initialization) {} // leaves array uninitialized
+ };
+
+ struct iovec asyncSafeToString(int n, AsyncSafeIntBuffer &&result = Qt::Uninitialized);
+#elif defined(Q_OS_WIN)
+ // Windows doesn't need to be async-safe
+ template <typename... Args> static void writeToStderr(Args &&... args)
+ {
+ (std::cerr << ... << args);
+ }
+
+ inline std::string asyncSafeToString(int n)
+ {
+ return std::to_string(n);
+ }
+#endif // defined(Q_OS_UNIX) && (!defined(Q_OS_WASM) || QT_CONFIG(thread))
+
+ bool alreadyDebugging();
+ void blockUnixSignals();
+
+#if !defined(Q_OS_WASM) || QT_CONFIG(thread)
+ void printTestRunTime();
+ void generateStackTrace();
+#endif
+
+ void maybeDisableCoreDump();
+ Q_TESTLIB_EXPORT void prepareStackTrace();
+
+#if defined(Q_OS_WIN)
+ // Helper class for resolving symbol names by dynamically loading "dbghelp.dll".
+ class DebugSymbolResolver
+ {
+ Q_DISABLE_COPY_MOVE(DebugSymbolResolver)
+ public:
+ struct Symbol
+ {
+ Symbol() : name(nullptr), address(0) {}
+
+ const char *name; // Must be freed by caller.
+ DWORD64 address;
+ };
+
+ explicit DebugSymbolResolver(HANDLE process);
+ ~DebugSymbolResolver() { cleanup(); }
+
+ bool isValid() const { return m_symFromAddr; }
+
+ Symbol resolveSymbol(DWORD64 address) const;
+
+ private:
+ // typedefs from DbgHelp.h/.dll
+ struct DBGHELP_SYMBOL_INFO { // SYMBOL_INFO
+ ULONG SizeOfStruct;
+ ULONG TypeIndex; // Type Index of symbol
+ ULONG64 Reserved[2];
+ ULONG Index;
+ ULONG Size;
+ ULONG64 ModBase; // Base Address of module comtaining this symbol
+ ULONG Flags;
+ ULONG64 Value; // Value of symbol, ValuePresent should be 1
+ ULONG64 Address; // Address of symbol including base address of module
+ ULONG Register; // register holding value or pointer to value
+ ULONG Scope; // scope of the symbol
+ ULONG Tag; // pdb classification
+ ULONG NameLen; // Actual length of name
+ ULONG MaxNameLen;
+ CHAR Name[1]; // Name of symbol
+ };
+
+ typedef BOOL (__stdcall *SymInitializeType)(HANDLE, PCSTR, BOOL);
+ typedef BOOL (__stdcall *SymFromAddrType)(HANDLE, DWORD64, PDWORD64, DBGHELP_SYMBOL_INFO *);
+
+ void cleanup();
+
+ const HANDLE m_process;
+ HMODULE m_dbgHelpLib;
+ SymFromAddrType m_symFromAddr;
+ };
+
+ class Q_TESTLIB_EXPORT WindowsFaultHandler
+ {
+ public:
+ WindowsFaultHandler();
+
+ private:
+ static LONG WINAPI windowsFaultHandler(struct _EXCEPTION_POINTERS *exInfo);
+ };
+ using FatalSignalHandler = WindowsFaultHandler;
+#elif defined(Q_OS_UNIX) && !defined(Q_OS_WASM)
+ class Q_TESTLIB_EXPORT FatalSignalHandler
+ {
+ public:
+ # define OUR_SIGNALS(F) \
+ F(HUP) \
+ F(INT) \
+ F(QUIT) \
+ F(ABRT) \
+ F(ILL) \
+ F(BUS) \
+ F(FPE) \
+ F(SEGV) \
+ F(PIPE) \
+ F(TERM) \
+ /**/
+ # define CASE_LABEL(S) case SIG ## S: return QT_STRINGIFY(S);
+ # define ENUMERATE_SIGNALS(S) SIG ## S,
+ static const char *signalName(int signum) noexcept
+ {
+ switch (signum) {
+ OUR_SIGNALS(CASE_LABEL)
+ }
+
+ # if defined(__GLIBC_MINOR__) && (__GLIBC_MINOR__ >= 32 || __GLIBC__ > 2)
+ // get the other signal names from glibc 2.32
+ // (accessing the sys_sigabbrev variable causes linker warnings)
+ if (const char *p = sigabbrev_np(signum))
+ return p;
+ # endif
+ return "???";
+ }
+ static constexpr std::array fatalSignals = {
+ OUR_SIGNALS(ENUMERATE_SIGNALS)
+ };
+ # undef CASE_LABEL
+ # undef ENUMERATE_SIGNALS
+
+ static constexpr std::array crashingSignals = {
+ // Crash signals are special, because if we return from the handler
+ // without adjusting the machine state, the same instruction that
+ // originally caused the crash will get re-executed and will thus cause
+ // the same crash again. This is useful if our parent process logs the
+ // exit result or if core dumps are enabled: the core file will point
+ // to the actual instruction that crashed.
+ SIGILL, SIGBUS, SIGFPE, SIGSEGV
+ };
+ using OldActionsArray = std::array<struct sigaction, fatalSignals.size()>;
+
+ FatalSignalHandler();
+ ~FatalSignalHandler();
+
+ private:
+ Q_DISABLE_COPY_MOVE(FatalSignalHandler)
+
+ static OldActionsArray &oldActions();
+ auto alternateStackSize();
+ int setupAlternateStack();
+ void freeAlternateStack();
+
+ template <typename T> static
+ std::enable_if_t<sizeof(std::declval<T>().si_pid) + sizeof(std::declval<T>().si_uid) >= 1>
+ printSentSignalInfo(T *info)
+ {
+ writeToStderr(" sent by PID ", asyncSafeToString(info->si_pid),
+ " UID ", asyncSafeToString(info->si_uid));
+ }
+ static void printSentSignalInfo(...) {}
+
+ template <typename T> static
+ std::enable_if_t<sizeof(std::declval<T>().si_addr) >= 1> printCrashingSignalInfo(T *info)
+ {
+ using HexString = std::array<char, sizeof(quintptr) * 2>;
+ auto toHexString = [](quintptr u, HexString &&r = {}) {
+ int shift = sizeof(quintptr) * 8 - 4;
+ for (size_t i = 0; i < sizeof(quintptr) * 2; ++i, shift -= 4)
+ r[i] = QtMiscUtils::toHexLower(u >> shift);
+ struct iovec vec;
+ vec.iov_base = r.data();
+ vec.iov_len = r.size();
+ return vec;
+ };
+ writeToStderr(", code ", asyncSafeToString(info->si_code),
+ ", for address 0x", toHexString(quintptr(info->si_addr)));
+ }
+ static void printCrashingSignalInfo(...) {}
+ static void actionHandler(int signum, siginfo_t *info, void * /* ucontext */);
+
+ [[maybe_unused]] static void regularHandler(int signum)
+ {
+ actionHandler(signum, nullptr, nullptr);
+ }
+
+ void *alternateStackBase = MAP_FAILED;
+ static bool pauseOnCrash;
+ };
+#else // Q_OS_WASM or weird systems
+class Q_TESTLIB_EXPORT FatalSignalHandler {};
+inline void blockUnixSignals() {}
+#endif // Q_OS_* choice
+} // namespace CrashHandler
+} // namespace QTest
+QT_END_NAMESPACE
+
+#endif // QTESTCRASHHANDLER_H
diff --git a/src/testlib/qtestevent.qdoc b/src/testlib/qtestevent.qdoc
index f71b99f8d7..a7af6d5592 100644
--- a/src/testlib/qtestevent.qdoc
+++ b/src/testlib/qtestevent.qdoc
@@ -118,25 +118,25 @@
For an example, please read the \l QTestEventList class documentation.
*/
-/*! \fn void QTestEventList::addMousePress(Qt::MouseButton button, Qt::KeyboardModifiers modifiers = 0, QPoint pos = QPoint(), int delay=-1)
+/*! \fn void QTestEventList::addMousePress(Qt::MouseButton button, Qt::KeyboardModifiers modifiers, QPoint pos = QPoint(), int delay=-1)
Add a mouse press to the list. The event will press the \a button with optional \a modifiers at the position \a pos with an optional \a delay. The default position is the center of the widget.
\sa QTest::mousePress()
*/
-/*! \fn void QTestEventList::addMouseRelease(Qt::MouseButton button, Qt::KeyboardModifiers modifiers = 0, QPoint pos = QPoint(), int delay=-1)
+/*! \fn void QTestEventList::addMouseRelease(Qt::MouseButton button, Qt::KeyboardModifiers modifiers, QPoint pos = QPoint(), int delay=-1)
Add a mouse release to the list. The event will release the \a button with optional \a modifiers at the position \a pos with an optional \a delay. The default position is the center of the widget.
\sa QTest::mouseRelease()
*/
-/*! \fn void QTestEventList::addMouseClick(Qt::MouseButton button, Qt::KeyboardModifiers modifiers = 0, QPoint pos = QPoint(), int delay=-1)
+/*! \fn void QTestEventList::addMouseClick(Qt::MouseButton button, Qt::KeyboardModifiers modifiers, QPoint pos = QPoint(), int delay=-1)
Add a mouse click to the list. The event will click the \a button with optional \a modifiers at the position \a pos with an optional \a delay. The default position is the center of the widget.
\sa QTest::mouseClick()
*/
-/*! \fn void QTestEventList::addMouseDClick(Qt::MouseButton button, Qt::KeyboardModifiers modifiers = 0, QPoint pos = QPoint(), int delay=-1)
+/*! \fn void QTestEventList::addMouseDClick(Qt::MouseButton button, Qt::KeyboardModifiers modifiers, QPoint pos = QPoint(), int delay=-1)
Add a double mouse click to the list. The event will double click the \a button with optional \a modifiers at the position \a pos with an optional \a delay. The default position is the center of the widget.
diff --git a/src/testlib/qtestlog.cpp b/src/testlib/qtestlog.cpp
index e01da37911..4b6df54e91 100644
--- a/src/testlib/qtestlog.cpp
+++ b/src/testlib/qtestlog.cpp
@@ -318,7 +318,6 @@ void QTestLog::clearIgnoreMessages()
QTest::IgnoreResultList::clearList(QTest::ignoreResultList);
}
-
void QTestLog::clearFailOnWarnings()
{
QTest::failOnWarningList.clear();
@@ -326,6 +325,8 @@ void QTestLog::clearFailOnWarnings()
void QTestLog::clearCurrentTestState()
{
+ clearIgnoreMessages();
+ clearFailOnWarnings();
QTest::currentTestState = QTest::Unresolved;
}
@@ -559,6 +560,21 @@ bool QTestLog::hasLoggers()
return !QTest::loggers()->empty();
}
+/*!
+ \internal
+
+ Returns true if all loggers support repeated test runs
+*/
+bool QTestLog::isRepeatSupported()
+{
+ FOREACH_TEST_LOGGER {
+ if (!logger->isRepeatSupported())
+ return false;
+ }
+
+ return true;
+}
+
bool QTestLog::loggerUsingStdout()
{
FOREACH_TEST_LOGGER {
diff --git a/src/testlib/qtestlog_p.h b/src/testlib/qtestlog_p.h
index 9717858afb..f9bbfa158d 100644
--- a/src/testlib/qtestlog_p.h
+++ b/src/testlib/qtestlog_p.h
@@ -91,6 +91,7 @@ public:
static void addLogger(QAbstractTestLogger *logger);
static bool hasLoggers();
+ static bool isRepeatSupported();
static bool loggerUsingStdout();
static void setVerboseLevel(int level);
diff --git a/src/testlib/qtestmouse.h b/src/testlib/qtestmouse.h
index 01a3c9c6b5..567d80c521 100644
--- a/src/testlib/qtestmouse.h
+++ b/src/testlib/qtestmouse.h
@@ -175,7 +175,7 @@ namespace QTest
stateKey &= Qt::KeyboardModifierMask;
- QEvent::Type meType;
+ QEvent::Type meType = QEvent::None;
using namespace QTestPrivate;
switch (action)
{
diff --git a/src/testlib/qtestresult.cpp b/src/testlib/qtestresult.cpp
index e3545802cb..7c5ce9ce54 100644
--- a/src/testlib/qtestresult.cpp
+++ b/src/testlib/qtestresult.cpp
@@ -149,13 +149,6 @@ void QTestResult::finishedCurrentTestData()
addFailure("QEXPECT_FAIL was called without any subsequent verification statements");
clearExpectFail();
-
- if (!QTest::hasFailed() && QTestLog::unhandledIgnoreMessages()) {
- QTestLog::printUnhandledIgnoreMessages();
- addFailure("Not all expected messages were received");
- }
- QTestLog::clearIgnoreMessages();
- QTestLog::clearFailOnWarnings();
}
/*!
@@ -175,6 +168,11 @@ void QTestResult::finishedCurrentTestData()
*/
void QTestResult::finishedCurrentTestDataCleanup()
{
+ if (!QTest::hasFailed() && QTestLog::unhandledIgnoreMessages()) {
+ QTestLog::printUnhandledIgnoreMessages();
+ addFailure("Not all expected messages were received");
+ }
+
// If the current test hasn't failed or been skipped, then it passes.
if (!QTest::hasFailed() && !QTest::skipCurrentTest) {
if (QTest::blacklistCurrentTest)
@@ -289,21 +287,27 @@ void QTestResult::fail(const char *msg, const char *file, int line)
checkStatement(false, msg, file, line);
}
+// QPalette's << operator produces 1363 characters. A comparison failure
+// involving two palettes can therefore require 2726 characters, not including
+// the other output produced by QTest. Users might also have their own types
+// with large amounts of output, so use a sufficiently high value here.
+static constexpr size_t maxMsgLen = 4096;
+
bool QTestResult::verify(bool statement, const char *statementStr,
const char *description, const char *file, int line)
{
QTEST_ASSERT(statementStr);
- char msg[1024];
+ char msg[maxMsgLen];
msg[0] = '\0';
if (QTestLog::verboseLevel() >= 2) {
- qsnprintf(msg, 1024, "QVERIFY(%s)", statementStr);
+ qsnprintf(msg, maxMsgLen, "QVERIFY(%s)", statementStr);
QTestLog::info(msg, file, line);
}
if (statement == !!QTest::expectFailMode) {
- qsnprintf(msg, 1024,
+ qsnprintf(msg, maxMsgLen,
statement ? "'%s' returned TRUE unexpectedly. (%s)" : "'%s' returned FALSE. (%s)",
statementStr, description ? description : "");
}
@@ -371,7 +375,6 @@ static bool compareHelper(bool success, const char *failureMsg,
const char *file, int line,
bool hasValues = true)
{
- const size_t maxMsgLen = 1024;
char msg[maxMsgLen];
msg[0] = '\0';
@@ -534,7 +537,8 @@ bool QTestResult::compare(bool success, const char *failureMsg,
void QTestResult::addFailure(const char *message, const char *file, int line)
{
clearExpectFail();
- QTestEventLoop::instance().exitLoop();
+ if (qApp && QThread::currentThread() == qApp->thread())
+ QTestEventLoop::instance().exitLoop();
if (QTest::blacklistCurrentTest)
QTestLog::addBFail(message, file, line);
@@ -624,13 +628,13 @@ static const char *failureMessageForOp(QTest::ComparisonOperation op)
Q_UNREACHABLE_RETURN("");
}
-bool QTestResult::reportResult(bool success, qxp::function_ref<const char *()> lhs,
- qxp::function_ref<const char *()> rhs,
+bool QTestResult::reportResult(bool success, const void *lhs, const void *rhs,
+ const char *(*lhsFormatter)(const void*),
+ const char *(*rhsFormatter)(const void*),
const char *lhsExpr, const char *rhsExpr,
QTest::ComparisonOperation op, const char *file, int line,
const char *failureMessage)
{
- const size_t maxMsgLen = 1024;
char msg[maxMsgLen];
msg[0] = '\0';
@@ -650,8 +654,8 @@ bool QTestResult::reportResult(bool success, qxp::function_ref<const char *()> l
return checkStatement(success, msg, file, line);
}
- const std::unique_ptr<const char[]> lhsPtr{ lhs() };
- const std::unique_ptr<const char[]> rhsPtr{ rhs() };
+ const std::unique_ptr<const char[]> lhsPtr{ lhsFormatter(lhs) };
+ const std::unique_ptr<const char[]> rhsPtr{ rhsFormatter(rhs) };
if (!failureMessage)
failureMessage = failureMessageForOp(op);
diff --git a/src/testlib/qtestresult_p.h b/src/testlib/qtestresult_p.h
index 48c2c34611..e94de64c06 100644
--- a/src/testlib/qtestresult_p.h
+++ b/src/testlib/qtestresult_p.h
@@ -17,7 +17,6 @@
#include <QtTest/qttestglobal.h>
#include <QtCore/qstringfwd.h>
-#include <QtCore/qxpfunctional.h>
#include <QtCore/private/qglobal_p.h>
QT_BEGIN_NAMESPACE
@@ -102,8 +101,9 @@ public:
static void setCurrentAppName(const char *appName);
static const char *currentAppName();
- static bool reportResult(bool success, qxp::function_ref<const char *()> lhs,
- qxp::function_ref<const char *()> rhs,
+ static bool reportResult(bool success, const void *lhs, const void *rhs,
+ const char *(*lhsFormatter)(const void *),
+ const char *(*rhsFormatter)(const void *),
const char *lhsExpr, const char *rhsExpr,
QTest::ComparisonOperation op, const char *file, int line,
const char *failureMessage = nullptr);
diff --git a/src/testlib/qtesttable.cpp b/src/testlib/qtesttable.cpp
index 5dc3a12661..2276365505 100644
--- a/src/testlib/qtesttable.cpp
+++ b/src/testlib/qtesttable.cpp
@@ -5,6 +5,7 @@
#include <QtTest/qtestdata.h>
#include <QtTest/qtestassert.h>
+#include <QtCore/private/qduplicatetracker_p.h>
#include <QtCore/qmetaobject.h>
#include <string.h>
@@ -35,9 +36,11 @@ public:
using DataList = std::vector<QTestData *>;
DataList dataList;
+ using TagSet = QDuplicateTracker<std::string>;
+ TagSet tagSet;
+
void addColumn(int elemType, const char *elemName) { elementList.push_back(Element(elemName, elemType)); }
void addRow(QTestData *data) { dataList.push_back(data); }
- bool hasRow(const char *name) const;
static QTestTable *currentTestTable;
static QTestTable *gTable;
@@ -73,7 +76,8 @@ bool QTestTable::isEmpty() const
QTestData *QTestTable::newData(const char *tag)
{
- if (d->hasRow(tag))
+ QTEST_ASSERT(tag);
+ if (d->tagSet.hasSeen(tag))
qWarning("Duplicate data tag \"%s\" - please rename.", tag);
QTestData *dt = new QTestData(tag, this);
@@ -123,12 +127,6 @@ private:
const char *m_needle;
};
-bool QTestTablePrivate::hasRow(const char *rowName) const
-{
- QTEST_ASSERT(rowName);
- return std::find_if(dataList.begin(), dataList.end(), NamePredicate(rowName)) != dataList.end();
-}
-
int QTestTable::indexOf(const char *elementName) const
{
QTEST_ASSERT(elementName);
diff --git a/src/testlib/qtesttostring.h b/src/testlib/qtesttostring.h
new file mode 100644
index 0000000000..18262332ba
--- /dev/null
+++ b/src/testlib/qtesttostring.h
@@ -0,0 +1,499 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2024 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTESTTOSTRING_H
+#define QTESTTOSTRING_H
+
+#include <QtTest/qttestglobal.h>
+
+#if QT_CONFIG(itemmodel)
+# include <QtCore/qabstractitemmodel.h>
+#endif
+#include <QtCore/qbitarray.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qcborarray.h>
+#include <QtCore/qcborcommon.h>
+#include <QtCore/qcbormap.h>
+#include <QtCore/qcborvalue.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qsize.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qurl.h>
+#include <QtCore/quuid.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QTest {
+namespace Internal {
+
+template<typename T> // Output registered enums
+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>
+inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && std::is_enum_v<T>, char*>::type toString(const T &e)
+{
+ return qstrdup(QByteArray::number(static_cast<std::underlying_type_t<T>>(e)).constData());
+}
+
+template <typename T> // Fallback; for built-in types debug streaming must be possible
+inline typename std::enable_if<!QtPrivate::IsQEnumHelper<T>::Value && !std::is_enum_v<T>, char *>::type toString(const T &t)
+{
+ char *result = nullptr;
+#ifndef QT_NO_DEBUG_STREAM
+ if constexpr (QTypeTraits::has_ostream_operator_v<QDebug, T>) {
+ result = qstrdup(QDebug::toString(t).toUtf8().constData());
+ } else {
+ static_assert(!QMetaTypeId2<T>::IsBuiltIn,
+ "Built-in type must implement debug streaming operator "
+ "or provide QTest::toString specialization");
+ }
+#endif
+ return result;
+}
+
+template<typename F> // Output QFlags of registered enumerations
+inline typename std::enable_if<QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f)
+{
+ const QMetaEnum me = QMetaEnum::fromType<F>();
+ return qstrdup(me.valueToKeys(int(f.toInt())).constData());
+}
+
+template <typename F> // Fallback: Output hex value
+inline typename std::enable_if<!QtPrivate::IsQEnumHelper<F>::Value, char*>::type toString(QFlags<F> f)
+{
+ const size_t space = 3 + 2 * sizeof(unsigned); // 2 for 0x, two hex digits per byte, 1 for '\0'
+ char *msg = new char[space];
+ qsnprintf(msg, space, "0x%x", unsigned(f.toInt()));
+ return msg;
+}
+
+template <typename T>
+constexpr bool is_suitable_type_helper_v = std::disjunction_v<std::is_same<T, char>,
+ std::is_same<T, void>,
+ std::is_same<T, QObject>
+ >;
+
+template <typename T>
+using is_suitable_type_v =
+ std::enable_if_t<!(std::is_pointer_v<T>
+ && is_suitable_type_helper_v<
+ std::remove_const_t<std::remove_pointer_t<T>>>),
+ bool>;
+
+} // namespace Internal
+
+Q_TESTLIB_EXPORT bool compare_string_helper(const char *t1, const char *t2, const char *actual,
+ const char *expected, const char *file, int line);
+Q_TESTLIB_EXPORT char *formatString(const char *prefix, const char *suffix, size_t numArguments, ...);
+Q_TESTLIB_EXPORT char *toHexRepresentation(const char *ba, qsizetype length);
+Q_TESTLIB_EXPORT char *toPrettyCString(const char *unicode, qsizetype length);
+Q_TESTLIB_EXPORT char *toPrettyUnicode(QStringView string);
+Q_TESTLIB_EXPORT char *toString(const char *);
+Q_TESTLIB_EXPORT char *toString(const volatile void *);
+Q_TESTLIB_EXPORT char *toString(const volatile QObject *);
+
+template<typename T, Internal::is_suitable_type_v<T> = true>
+inline char *toString(const T &t)
+{
+ return Internal::toString(t);
+}
+
+template <typename T1, typename T2>
+inline char *toString(const std::pair<T1, T2> &pair);
+
+template <class... Types>
+inline char *toString(const std::tuple<Types...> &tuple);
+
+template <typename Rep, typename Period>
+inline char *toString(std::chrono::duration<Rep, Period> duration);
+
+#define QTEST_COMPARE_DECL(KLASS)\
+ template<> Q_TESTLIB_EXPORT char *toString<KLASS >(const KLASS &);
+#ifndef Q_QDOC
+QTEST_COMPARE_DECL(short)
+QTEST_COMPARE_DECL(ushort)
+QTEST_COMPARE_DECL(int)
+QTEST_COMPARE_DECL(uint)
+QTEST_COMPARE_DECL(long)
+QTEST_COMPARE_DECL(ulong)
+QTEST_COMPARE_DECL(qint64)
+QTEST_COMPARE_DECL(quint64)
+
+QTEST_COMPARE_DECL(float)
+QTEST_COMPARE_DECL(double)
+QTEST_COMPARE_DECL(qfloat16)
+QTEST_COMPARE_DECL(char)
+QTEST_COMPARE_DECL(signed char)
+QTEST_COMPARE_DECL(unsigned char)
+QTEST_COMPARE_DECL(bool)
+#endif
+#undef QTEST_COMPARE_DECL
+
+template <> inline char *toString(const QStringView &str)
+{
+ return QTest::toPrettyUnicode(str);
+}
+
+template<> inline char *toString(const QString &str)
+{
+ return toString(QStringView(str));
+}
+
+template<> inline char *toString(const QLatin1StringView &str)
+{
+ return toString(QString(str));
+}
+
+template<> inline char *toString(const QByteArray &ba)
+{
+ return QTest::toPrettyCString(ba.constData(), ba.size());
+}
+
+template<> inline char *toString(const QBitArray &ba)
+{
+ qsizetype size = ba.size();
+ char *str = new char[size + 1];
+ for (qsizetype i = 0; i < size; ++i)
+ str[i] = "01"[ba.testBit(i)];
+ str[size] = '\0';
+ return str;
+}
+
+#if QT_CONFIG(datestring)
+template<> inline char *toString(const QTime &time)
+{
+ return time.isValid()
+ ? qstrdup(qPrintable(time.toString(u"hh:mm:ss.zzz")))
+ : qstrdup("Invalid QTime");
+}
+
+template<> inline char *toString(const QDate &date)
+{
+ return date.isValid()
+ ? qstrdup(qPrintable(date.toString(u"yyyy/MM/dd")))
+ : qstrdup("Invalid QDate");
+}
+
+template<> inline char *toString(const QDateTime &dateTime)
+{
+ return dateTime.isValid()
+ ? qstrdup(qPrintable(dateTime.toString(u"yyyy/MM/dd hh:mm:ss.zzz[t]")))
+ : qstrdup("Invalid QDateTime");
+}
+#endif // datestring
+
+template<> inline char *toString(const QCborError &c)
+{
+ // use the Q_ENUM formatting
+ return toString(c.c);
+}
+
+template<> inline char *toString(const QChar &c)
+{
+ const ushort uc = c.unicode();
+ if (uc < 128) {
+ char msg[32] = {'\0'};
+ qsnprintf(msg, sizeof(msg), "QChar: '%c' (0x%x)", char(uc), unsigned(uc));
+ return qstrdup(msg);
+ }
+ return qstrdup(qPrintable(QString::fromLatin1("QChar: '%1' (0x%2)").arg(c).arg(QString::number(static_cast<int>(c.unicode()), 16))));
+}
+
+#if QT_CONFIG(itemmodel)
+template<> inline char *toString(const QModelIndex &idx)
+{
+ char msg[128];
+ qsnprintf(msg, sizeof(msg), "QModelIndex(%d,%d,%p,%p)", idx.row(), idx.column(), idx.internalPointer(), idx.model());
+ return qstrdup(msg);
+}
+#endif
+
+template<> inline char *toString(const QPoint &p)
+{
+ char msg[128] = {'\0'};
+ qsnprintf(msg, sizeof(msg), "QPoint(%d,%d)", p.x(), p.y());
+ return qstrdup(msg);
+}
+
+template<> inline char *toString(const QSize &s)
+{
+ char msg[128] = {'\0'};
+ qsnprintf(msg, sizeof(msg), "QSize(%dx%d)", s.width(), s.height());
+ return qstrdup(msg);
+}
+
+template<> inline char *toString(const QRect &s)
+{
+ char msg[256] = {'\0'};
+ qsnprintf(msg, sizeof(msg), "QRect(%d,%d %dx%d) (bottomright %d,%d)",
+ s.left(), s.top(), s.width(), s.height(), s.right(), s.bottom());
+ return qstrdup(msg);
+}
+
+template<> inline char *toString(const QPointF &p)
+{
+ char msg[64] = {'\0'};
+ qsnprintf(msg, sizeof(msg), "QPointF(%g,%g)", p.x(), p.y());
+ return qstrdup(msg);
+}
+
+template<> inline char *toString(const QSizeF &s)
+{
+ char msg[64] = {'\0'};
+ qsnprintf(msg, sizeof(msg), "QSizeF(%gx%g)", s.width(), s.height());
+ return qstrdup(msg);
+}
+
+template<> inline char *toString(const QRectF &s)
+{
+ char msg[256] = {'\0'};
+ qsnprintf(msg, sizeof(msg), "QRectF(%g,%g %gx%g) (bottomright %g,%g)",
+ s.left(), s.top(), s.width(), s.height(), s.right(), s.bottom());
+ return qstrdup(msg);
+}
+
+template<> inline char *toString(const QUrl &uri)
+{
+ if (!uri.isValid())
+ return qstrdup(qPrintable(QLatin1StringView("Invalid URL: ") + uri.errorString()));
+ 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(");
+ if (v.isValid()) {
+ QByteArray type(v.typeName());
+ if (type.isEmpty()) {
+ type = QByteArray::number(v.userType());
+ }
+ vstring.append(type);
+ if (!v.isNull()) {
+ vstring.append(',');
+ if (v.canConvert<QString>()) {
+ vstring.append(v.toString().toLocal8Bit());
+ }
+ else {
+ vstring.append("<value not representable as string>");
+ }
+ }
+ }
+ vstring.append(')');
+
+ return qstrdup(vstring.constData());
+}
+
+template<> inline char *toString(const QPartialOrdering &o)
+{
+ if (o == QPartialOrdering::Less)
+ return qstrdup("Less");
+ if (o == QPartialOrdering::Equivalent)
+ return qstrdup("Equivalent");
+ if (o == QPartialOrdering::Greater)
+ return qstrdup("Greater");
+ if (o == QPartialOrdering::Unordered)
+ return qstrdup("Unordered");
+ return qstrdup("<invalid>");
+}
+
+namespace Internal {
+struct QCborValueFormatter
+{
+ enum { BufferLen = 256 };
+ static char *formatSimpleType(QCborSimpleType st)
+ {
+ char *buf = new char[BufferLen];
+ qsnprintf(buf, BufferLen, "QCborValue(QCborSimpleType(%d))", int(st));
+ return buf;
+ }
+
+ static char *formatTag(QCborTag tag, const QCborValue &taggedValue)
+ {
+ QScopedArrayPointer<char> hold(format(taggedValue));
+ char *buf = new char[BufferLen];
+ qsnprintf(buf, BufferLen, "QCborValue(QCborTag(%llu), %s)", tag, hold.get());
+ return buf;
+ }
+
+ static char *innerFormat(QCborValue::Type t, const char *str)
+ {
+ static const QMetaEnum typeEnum = []() {
+ int idx = QCborValue::staticMetaObject.indexOfEnumerator("Type");
+ return QCborValue::staticMetaObject.enumerator(idx);
+ }();
+
+ char *buf = new char[BufferLen];
+ const char *typeName = typeEnum.valueToKey(t);
+ if (typeName)
+ qsnprintf(buf, BufferLen, "QCborValue(%s, %s)", typeName, str);
+ else
+ qsnprintf(buf, BufferLen, "QCborValue(<unknown type 0x%02x>)", t);
+ return buf;
+ }
+
+ template<typename T> static char *format(QCborValue::Type type, const T &t)
+ {
+ QScopedArrayPointer<char> hold(QTest::toString(t));
+ return innerFormat(type, hold.get());
+ }
+
+ static char *format(const QCborValue &v)
+ {
+ switch (v.type()) {
+ case QCborValue::Integer:
+ return format(v.type(), v.toInteger());
+ case QCborValue::ByteArray:
+ return format(v.type(), v.toByteArray());
+ case QCborValue::String:
+ return format(v.type(), v.toString());
+ case QCborValue::Array:
+ return innerFormat(v.type(), QScopedArrayPointer<char>(format(v.toArray())).get());
+ case QCborValue::Map:
+ return innerFormat(v.type(), QScopedArrayPointer<char>(format(v.toMap())).get());
+ case QCborValue::Tag:
+ return formatTag(v.tag(), v.taggedValue());
+ case QCborValue::SimpleType:
+ break;
+ case QCborValue::True:
+ return qstrdup("QCborValue(true)");
+ case QCborValue::False:
+ return qstrdup("QCborValue(false)");
+ case QCborValue::Null:
+ return qstrdup("QCborValue(nullptr)");
+ case QCborValue::Undefined:
+ return qstrdup("QCborValue()");
+ case QCborValue::Double:
+ return format(v.type(), v.toDouble());
+ case QCborValue::DateTime:
+ case QCborValue::Url:
+ case QCborValue::RegularExpression:
+ return format(v.type(), v.taggedValue().toString());
+ case QCborValue::Uuid:
+ return format(v.type(), v.toUuid());
+ case QCborValue::Invalid:
+ return qstrdup("QCborValue(<invalid>)");
+ }
+
+ if (v.isSimpleType())
+ return formatSimpleType(v.toSimpleType());
+ return innerFormat(v.type(), "");
+ }
+
+ static char *format(const QCborArray &a)
+ {
+ QByteArray out(1, '[');
+ const char *comma = "";
+ for (QCborValueConstRef v : a) {
+ QScopedArrayPointer<char> s(format(v));
+ out += comma;
+ out += s.get();
+ comma = ", ";
+ }
+ out += ']';
+ return qstrdup(out.constData());
+ }
+
+ static char *format(const QCborMap &m)
+ {
+ QByteArray out(1, '{');
+ const char *comma = "";
+ for (auto pair : m) {
+ QScopedArrayPointer<char> key(format(pair.first));
+ QScopedArrayPointer<char> value(format(pair.second));
+ out += comma;
+ out += key.get();
+ out += ": ";
+ out += value.get();
+ comma = ", ";
+ }
+ out += '}';
+ return qstrdup(out.constData());
+ }
+};
+}
+
+template<> inline char *toString(const QCborValue &v)
+{
+ return Internal::QCborValueFormatter::format(v);
+}
+
+template<> inline char *toString(const QCborValueRef &v)
+{
+ return toString(QCborValue(v));
+}
+
+template<> inline char *toString(const QCborArray &a)
+{
+ return Internal::QCborValueFormatter::format(a);
+}
+
+template<> inline char *toString(const QCborMap &m)
+{
+ return Internal::QCborValueFormatter::format(m);
+}
+
+template <typename Rep, typename Period> char *toString(std::chrono::duration<Rep, Period> dur)
+{
+ QString r;
+ QDebug d(&r);
+ d.nospace() << qSetRealNumberPrecision(9) << dur;
+ if constexpr (Period::num != 1 || Period::den != 1) {
+ // include the equivalent value in seconds, in parentheses
+ using namespace std::chrono;
+ d << " (" << duration_cast<duration<qreal>>(dur).count() << "s)";
+ }
+ return qstrdup(std::move(r).toUtf8().constData());
+}
+
+template <typename T1, typename T2>
+inline char *toString(const std::pair<T1, T2> &pair)
+{
+ const QScopedArrayPointer<char> first(toString(pair.first));
+ const QScopedArrayPointer<char> second(toString(pair.second));
+ return formatString("std::pair(", ")", 2, first.data(), second.data());
+}
+
+template <typename Tuple, std::size_t... I>
+inline char *tupleToString(const Tuple &tuple, std::index_sequence<I...>) {
+ using UP = std::unique_ptr<char[]>;
+ // Generate a table of N + 1 elements where N is the number of
+ // elements in the tuple.
+ // The last element is needed to support the empty tuple use case.
+ const UP data[] = {
+ UP(toString(std::get<I>(tuple)))..., UP{}
+ };
+ return formatString("std::tuple(", ")", sizeof...(I), data[I].get()...);
+}
+
+template <class... Types>
+inline char *toString(const std::tuple<Types...> &tuple)
+{
+ return tupleToString(tuple, std::make_index_sequence<sizeof...(Types)>{});
+}
+
+inline char *toString(std::nullptr_t)
+{
+ return toString(QStringView(u"nullptr"));
+}
+} // namespace QTest
+
+QT_END_NAMESPACE
+
+#endif // QTESTTOSTRING_H
diff --git a/src/testlib/qtestwheel.h b/src/testlib/qtestwheel.h
new file mode 100644
index 0000000000..564a586b4b
--- /dev/null
+++ b/src/testlib/qtestwheel.h
@@ -0,0 +1,72 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTESTWHEEL_H
+#define QTESTWHEEL_H
+
+#if 0
+// inform syncqt
+#pragma qt_no_master_include
+#endif
+
+#include <QtTest/qttestglobal.h>
+#include <QtTest/qtestassert.h>
+#include <QtTest/qtestsystem.h>
+#include <QtTest/qtestspontaneevent.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qpointer.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qwindow.h>
+
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+Q_GUI_EXPORT void qt_handleWheelEvent(QWindow *window, const QPointF &local,
+ const QPointF &global, QPoint pixelDelta,
+ QPoint angleDelta, Qt::KeyboardModifiers mods, Qt::ScrollPhase phase);
+
+namespace QTest
+{
+ /*! \internal
+ This function creates a mouse wheel event and calls
+ QWindowSystemInterface::handleWheelEvent().
+ \a window is the window that should be receiving the event and \a pos
+ provides the location of the event in the window's local coordinates.
+ \a angleDelta contains the wheel rotation angle, while \a pixelDelta
+ contains the scrolling distance in pixels on screen.
+ The keyboard states at the time of the event are specified by \a stateKey.
+ The scrolling phase of the event is specified by \a phase.
+ */
+ [[maybe_unused]] static void wheelEvent(QWindow *window, QPointF pos,
+ QPoint angleDelta, QPoint pixelDelta = QPoint(0, 0),
+ Qt::KeyboardModifiers stateKey = Qt::NoModifier,
+ Qt::ScrollPhase phase = Qt::NoScrollPhase)
+ {
+ QTEST_ASSERT(window);
+
+ // pos is in window local coordinates
+ const QSize windowSize = window->geometry().size();
+ if (windowSize.width() <= pos.x() || windowSize.height() <= pos.y()) {
+ qWarning("Mouse event at %d, %d occurs outside target window (%dx%d).",
+ static_cast<int>(pos.x()), static_cast<int>(pos.y()), windowSize.width(), windowSize.height());
+ }
+
+ if (pos.isNull())
+ pos = QPoint(window->width() / 2, window->height() / 2);
+
+ QPointF global = window->mapToGlobal(pos);
+ QPointer<QWindow> w(window);
+
+ if (angleDelta.isNull() && pixelDelta.isNull())
+ qWarning("No angle or pixel delta specified.");
+
+ qt_handleWheelEvent(w, pos, global, pixelDelta, angleDelta, stateKey, phase);
+ qApp->processEvents();
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QTESTWHEEL_H
diff --git a/src/testlib/qttestglobal.h b/src/testlib/qttestglobal.h
index ee2f350b80..8ede78c2a2 100644
--- a/src/testlib/qttestglobal.h
+++ b/src/testlib/qttestglobal.h
@@ -4,10 +4,6 @@
#ifndef QTTESTGLOBAL_H
#define QTTESTGLOBAL_H
-#if 0
-#pragma qt_deprecates(qtest_global.h)
-#endif
-
#include <QtCore/qglobal.h>
#include <QtTest/qttestlib-config.h>
#include <QtTest/qttestexports.h>
diff --git a/src/testlib/removed_api.cpp b/src/testlib/removed_api.cpp
new file mode 100644
index 0000000000..00a53735a0
--- /dev/null
+++ b/src/testlib/removed_api.cpp
@@ -0,0 +1,29 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2024 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#define QT_TESTLIB_BUILD_REMOVED_API
+
+#include "qtest.h"
+
+#if QT_TESTLIB_REMOVED_SINCE(6, 8)
+
+QT_BEGIN_NAMESPACE
+
+namespace QTest {
+
+Q_TESTLIB_EXPORT char *toString(const void *p)
+{
+ const volatile void *ptr = p;
+ return toString(ptr);
+}
+
+} // namespace QTest
+
+QT_END_NAMESPACE
+
+// #include "qotherheader.h"
+// implement removed functions from qotherheader.h
+// order sections alphabetically to reduce chances of merge conflicts
+
+#endif // QT_TESTLIB_REMOVED_SINCE(6, 8)
diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt
index 834da98c98..df0d2c7016 100644
--- a/src/tools/CMakeLists.txt
+++ b/src/tools/CMakeLists.txt
@@ -19,7 +19,7 @@ endif()
if(QT_FEATURE_androiddeployqt)
add_subdirectory(androiddeployqt)
- if(QT_FEATURE_gui AND QT_FEATURE_systemsemaphore)
+ if(QT_FEATURE_gui AND QT_FEATURE_process AND QT_FEATURE_systemsemaphore)
add_subdirectory(androidtestrunner)
endif()
endif()
diff --git a/src/tools/androiddeployqt/CMakeLists.txt b/src/tools/androiddeployqt/CMakeLists.txt
index 2a0f1ae9af..041d883877 100644
--- a/src/tools/androiddeployqt/CMakeLists.txt
+++ b/src/tools/androiddeployqt/CMakeLists.txt
@@ -17,6 +17,7 @@ qt_internal_add_tool(${target_name}
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
QT_NO_FOREACH
+ QT_NO_QPAIR
LIBRARIES
Qt::Core
INCLUDE_DIRECTORIES
diff --git a/src/tools/androiddeployqt/doc/src/androiddeployqt.qdoc b/src/tools/androiddeployqt/doc/src/androiddeployqt.qdoc
index 76efce964b..b94d7f5c04 100644
--- a/src/tools/androiddeployqt/doc/src/androiddeployqt.qdoc
+++ b/src/tools/androiddeployqt/doc/src/androiddeployqt.qdoc
@@ -1,4 +1,4 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
@@ -7,64 +7,47 @@
\title The androiddeployqt Tool
\target androiddeployqt
- Building an application package is complex, so Qt comes with a tool which
- handles the work for you. The steps described in
- \l{Deploying an Application on Android} are handled by the androiddeployqt
- tool.
+ Building an Android package involves many steps, so Qt comes with a tool which
+ handles the work for you. The steps handled by the androiddeployqt
+ tool are described in \l{Deploying an Application on Android}.
\section1 Prerequisites Before Running androiddeployqt
- Before running the tool manually, you need to run \c qmake or \c CMake
- on your project to generate \c Makefiles and a \c JSON file (i.e.
- \c{android-project-deployment-settings.json}) containing important settings
+ Before running the tool manually, you need to configure your project with
+ \c CMake or \c qmake to generate \c Makefiles and a \c JSON file (i.e.
+ \c{android-<target_name>-deployment-settings.json}) containing important settings
used by \c androiddeployqt.
\note It is not recommended to modify the androiddeployqt JSON file.
- To prepare the build for androiddeployqt, it is recommended to build your
- project in a separate directory. Run the following commands:
-
-
- \badcode
- mkdir build-project
- cd build-project
- \endcode
-
- Followed by:
-
- For qmake:
- \badcode
- qmake ../project/project.pro
- make -j$(nproc)
- make -j$(nproc) apk_install_target
- \endcode
-
- For CMake:
- \badcode
- cmake --build
- \endcode
+ To prepare the environment for androiddeployqt, configure your project in
+ a separate directory than your source directory. For more information on
+ configuring your project, see \l {Building Qt for Android Projects from Command Line}.
\section1 Command Line Arguments
- The only required command line argument when running the tool is \c{--output}.
- Other command line arguments are optional but useful. The list below is available
- by passing the \c{--help} argument to androiddeployqt.
+ The only required command line arguments when running the tool are
+ \c {--input} and \c {--output}. Other command line arguments are optional but
+ useful. The list below is available by passing the \c {--help} argument to
+ androiddeployqt.
\quotefromfile main.cpp
\skipto Syntax: androiddeployqt --output <destination> [options]
\printuntil --help: Displays this information.
- With a project named \c project, to directly build the application package
- with \c androiddeployqt without deploying it the device, run the following:
+ With a \c project_name, to build the application package with \c androiddeployqt
+ without deploying it the device, run the following:
\badcode
- .androiddeployqt --input $BUILD_DIR/android-project-deployment-settings.json --output $ANDROID_BUILD_DIR
+ androiddeployqt --input <build_dir>/android-project_name-deployment-settings.json \
+ --output <build_dir>/android-build
\endcode
- To deploy the built package to the device:
+ To build and deploy the package to the device:
\badcode
- androiddeployqt --verbose --output $ANDROID_BUILD_DIR --no-build --input $BUILD_DIR/android-project-deployment-settings.json --gradle --reinstall --device <adb_device_id>
+ androiddeployqt --input <build_dir>/android-project_name-deployment-settings.json \
+ --output <build_dir>/android-build --install --device <device_serial_id>
\endcode
\section1 Dependencies Detection
@@ -76,11 +59,13 @@
dependencies based on the Qt dependencies of your application. If the plugin
has any Qt dependencies which are not also dependencies of your application,
it will not be included by default. For instance, in order to ensure that
- the SVG image format plugin is included, you will need to add \l{Qt SVG}
+ the SVG image format plugin is included, you will need to add \l {Qt SVG}
module to your project for it to become a dependency of your application:
\badcode
- QT += svg
+ find_package(Qt6 REQUIRED COMPONENTS Svg)
+ ...
+ target_link_libraries(target_name PRIVATE Qt6::Svg)
\endcode
If you are wondering why a particular plugin is not included automatically,
@@ -91,7 +76,7 @@
\uicontrol {Advanced Actions}.
It's also possible to manually specify the dependencies of your application.
- For more information, see \l{ANDROID_DEPLOYMENT_DEPENDENCIES} qmake variable.
+ For more information, see \l {QT_ANDROID_DEPLOYMENT_DEPENDENCIES} CMake variable.
\note androiddeployqt scans the QML files of the project to collect the QML imports.
However, if you are loading QML code as a QString from C++ at runtime, that might
@@ -99,62 +84,12 @@
To remedy that, you can add a dummy QML file that imports such QML modules that
are referenced at runtime.
- \section1 Android-specific qmake Variables
-
- Unless the project has special requirements such as third party libraries,
- it should be possible to run \l androiddeployqt on it with no modifications
- and get a working Qt for Android application.
-
- There are two important environment variables used by Qt:
-
- \list
- \li \c{ANDROID_SDK_ROOT}: specifies the path to the Android SDK used for
- building the application. The Android SDK contains the build-tools,
- Android NDK, and Android toolchains.
- \li \c{ANDROID_NDK_ROOT}: specifies the path to the Android NDK used to
- build the application. It is not recommended to hard-code this path,
- since different Qt for Android versions can depend on different
- Android NDK versions.
- \endlist
-
- \note Qt Creator sets these variables by default.
-
- There are a set of \c qmake or \c CMake variables that can be used to tailor
- your package. At some point during development, you will most likely want
- to look into these variables to customize your application.
-
- Here is a list of some variables that are particularly interesting when
- making Android applications:
-
- \list
- \li \l{ANDROID_PACKAGE_SOURCE_DIR}
- \li \l{ANDROID_VERSION_CODE}
- \li \l{ANDROID_VERSION_NAME}
- \li \l{ANDROID_EXTRA_LIBS}
- \li \l{ANDROID_EXTRA_PLUGINS}
- \li \l{ANDROID_ABIS}
- \li \l{ANDROID_API_VERSION}
- \li \l{ANDROID_DEPLOYMENT_DEPENDENCIES}
- \li \l{ANDROID_MIN_SDK_VERSION}
- \li \l{ANDROID_TARGET_SDK_VERSION}
- \li \l{JAVA_HOME}
- \endlist
-
- Also, the following \c qmake variables are primarily useful when writing a Qt module, and not
- normal applications:
-
- \list
- \li \l{ANDROID_BUNDLED_JAR_DEPENDENCIES}
- \li \l{ANDROID_LIB_DEPENDENCIES}
- \li \l{ANDROID_PERMISSIONS}
- \li \l{ANDROID_FEATURES}
- \endlist
-
- \note This list of variables can also be used with CMake.
-
\section1 Deployment in Qt Creator
- Qt Creator runs \c androiddeployqt by default, and provides easy
- and intuitive user interfaces to specify many of the options. For more
- information, see \l{Qt Creator: Deploying Applications to Android Devices}.
+ Qt Creator uses \c androiddeployqt under the hood, and provides easy
+ and intuitive user interfaces to specify various options. For more information,
+ see \l{Qt Creator: Deploying Applications to Android Devices}.
+
+ For more information about customizing and deploying a Qt for Android app,
+ see \l {Deploying an Application on Android}.
*/
diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp
index 9727f3f641..6125b405b5 100644
--- a/src/tools/androiddeployqt/main.cpp
+++ b/src/tools/androiddeployqt/main.cpp
@@ -13,7 +13,7 @@
#include <QXmlStreamReader>
#include <QStandardPaths>
#include <QUuid>
-#include <QDirIterator>
+#include <QDirListing>
#include <QElapsedTimer>
#include <QRegularExpression>
#include <QSettings>
@@ -144,6 +144,7 @@ struct Options
QString qtQmlDirectory;
QString qtHostDirectory;
std::vector<QString> extraPrefixDirs;
+ QStringList androidDeployPlugins;
// Unlike 'extraPrefixDirs', the 'extraLibraryDirs' key doesn't expect the 'lib' subfolder
// when looking for dependencies.
std::vector<QString> extraLibraryDirs;
@@ -163,7 +164,7 @@ struct Options
QString versionName;
QString versionCode;
QByteArray minSdkVersion{"23"};
- QByteArray targetSdkVersion{"31"};
+ QByteArray targetSdkVersion{"34"};
// lib c++ path
QString stdCppPath;
@@ -224,7 +225,7 @@ struct Options
qtPluginsDirectory = directories["qtPluginsDirectory"_L1];
qtQmlDirectory = directories["qtQmlDirectory"_L1];
}
- typedef QPair<QString, QString> BundledFile;
+ using BundledFile = std::pair<QString, QString>;
QHash<QString, QList<BundledFile>> bundledFiles;
QHash<QString, QList<QtDependency>> qtDependencies;
QHash<QString, QStringList> localLibs;
@@ -608,9 +609,9 @@ Optional arguments:
from keystore password.)
--sigfile <file>: Name of .SF/.DSA file.
--digestalg <name>: Name of digest algorithm. Default is
- "SHA1".
+ "SHA-256".
--sigalg <name>: Name of signature algorithm. Default is
- "SHA1withRSA".
+ "SHA256withRSA".
--tsa <url>: Location of the Time Stamping Authority.
--tsacert <alias>: Public key certificate for TSA.
--internalsf: Include the .SF file inside the signature block.
@@ -808,7 +809,7 @@ QString detectLatestAndroidPlatform(const QString &sdkPath)
std::sort(fileInfos.begin(), fileInfos.end(), quasiLexicographicalReverseLessThan);
- QFileInfo latestPlatform = fileInfos.first();
+ const QFileInfo& latestPlatform = fileInfos.constFirst();
return latestPlatform.baseName();
}
@@ -842,7 +843,7 @@ bool readInputFileDirectory(Options *options, QJsonObject &jsonObject, const QSt
if (qtDirectory.isUndefined()) {
for (auto it = options->architectures.constBegin(); it != options->architectures.constEnd(); ++it) {
if (keyName == "qtDataDirectory"_L1) {
- options->architectures[it.key()].qtDirectories[keyName] = it.value().qtInstallDirectory;
+ options->architectures[it.key()].qtDirectories[keyName] = "."_L1;
break;
} else if (keyName == "qtLibsDirectory"_L1) {
options->architectures[it.key()].qtDirectories[keyName] = "lib"_L1;
@@ -1011,6 +1012,11 @@ bool readInputFile(Options *options)
}
{
+ const auto androidDeployPlugins = jsonObject.value("android-deploy-plugins"_L1).toString();
+ options->androidDeployPlugins = androidDeployPlugins.split(";"_L1, Qt::SkipEmptyParts);
+ }
+
+ {
const auto extraLibraryDirs = jsonObject.value("extraLibraryDirs"_L1).toArray();
options->extraLibraryDirs.reserve(extraLibraryDirs.size());
for (const QJsonValue path : extraLibraryDirs) {
@@ -1216,6 +1222,7 @@ bool readInputFile(Options *options)
}
{
+ using ItFlag = QDirListing::IteratorFlag;
const QJsonValue deploymentDependencies = jsonObject.value("deployment-dependencies"_L1);
if (!deploymentDependencies.isUndefined()) {
QString deploymentDependenciesString = deploymentDependencies.toString();
@@ -1224,11 +1231,9 @@ bool readInputFile(Options *options)
QString path = options->qtInstallDirectory + QChar::fromLatin1('/');
path += dependency;
if (QFileInfo(path).isDir()) {
- QDirIterator iterator(path, QDirIterator::Subdirectories);
- while (iterator.hasNext()) {
- iterator.next();
- if (iterator.fileInfo().isFile()) {
- QString subPath = iterator.filePath();
+ for (const auto &dirEntry : QDirListing(path, ItFlag::Recursive)) {
+ if (dirEntry.isFile()) {
+ const QString subPath = dirEntry.filePath();
auto arch = fileArchitecture(*options, subPath);
if (!arch.isEmpty()) {
options->qtDependencies[arch].append(QtDependency(subPath.mid(options->qtInstallDirectory.size() + 1),
@@ -1240,12 +1245,24 @@ bool readInputFile(Options *options)
}
}
} else {
- auto arch = fileArchitecture(*options, path);
- if (!arch.isEmpty()) {
- options->qtDependencies[arch].append(QtDependency(dependency.toString(), path));
- } else if (options->verbose) {
- fprintf(stderr, "Skipping \"%s\", unknown architecture\n", qPrintable(path));
- fflush(stderr);
+ auto qtDependency = [options](const QStringView &dependency,
+ const QString &arch) {
+ const auto installDir = options->architectures[arch].qtInstallDirectory;
+ const auto absolutePath = "%1/%2"_L1.arg(installDir, dependency.toString());
+ return QtDependency(dependency.toString(), absolutePath);
+ };
+
+ if (dependency.endsWith(QLatin1String(".so"))) {
+ auto arch = fileArchitecture(*options, path);
+ if (!arch.isEmpty()) {
+ options->qtDependencies[arch].append(qtDependency(dependency, arch));
+ } else if (options->verbose) {
+ fprintf(stderr, "Skipping \"%s\", unknown architecture\n", qPrintable(path));
+ fflush(stderr);
+ }
+ } else {
+ for (auto arch : options->architectures.keys())
+ options->qtDependencies[arch].append(qtDependency(dependency, arch));
}
}
}
@@ -1591,7 +1608,7 @@ bool updateLibsXml(Options *options)
if (localLibs.isEmpty()) {
QString plugin;
for (const QtDependency &qtDependency : options->qtDependencies[it.key()]) {
- if (qtDependency.relativePath.endsWith("libqtforandroid.so"_L1))
+ if (qtDependency.relativePath.contains("libplugins_platforms_qtforandroid_"_L1))
plugin = qtDependency.relativePath;
if (qtDependency.relativePath.contains(
@@ -1599,14 +1616,13 @@ bool updateLibsXml(Options *options)
|| qtDependency.relativePath.contains(
QString::asprintf("libQt%dQuick", QT_VERSION_MAJOR))) {
options->usesOpenGL |= true;
- break;
}
}
if (plugin.isEmpty()) {
fflush(stdout);
- fprintf(stderr, "No platform plugin (libqtforandroid.so) included in "
- "the deployment. Make sure the app links to Qt Gui library.\n");
+ fprintf(stderr, "No platform plugin (libplugins_platforms_qtforandroid.so) included"
+ " in the deployment. Make sure the app links to Qt Gui library.\n");
fflush(stderr);
return false;
}
@@ -1797,6 +1813,11 @@ static QString absoluteFilePath(const Options *options, const QString &relativeF
}
if (relativeFileName.endsWith("-android-dependencies.xml"_L1)) {
+ for (const auto &dir : options->extraLibraryDirs) {
+ const QString path = dir + u'/' + relativeFileName;
+ if (QFile::exists(path))
+ return path;
+ }
return options->qtInstallDirectory + u'/' + options->qtLibsDirectory +
u'/' + relativeFileName;
}
@@ -1838,14 +1859,57 @@ QList<QtDependency> findFilesRecursively(const Options &options, const QFileInfo
QList<QtDependency> findFilesRecursively(const Options &options, const QString &fileName)
{
+ // We try to find the fileName in extraPrefixDirs first. The function behaves differently
+ // depending on what the fileName points to. If fileName is a file then we try to find the
+ // first occurrence in extraPrefixDirs and return this file. If fileName is directory function
+ // iterates over it and looks for deployment artifacts in each 'extraPrefixDirs' entry.
+ // Also we assume that if the fileName is recognized as a directory once it will be directory
+ // for every 'extraPrefixDirs' entry.
+ QList<QtDependency> deps;
for (const auto &prefix : options.extraPrefixDirs) {
QFileInfo info(prefix + u'/' + fileName);
- if (info.exists())
- return findFilesRecursively(options, info, prefix + u'/');
+ if (info.exists()) {
+ if (info.isDir())
+ deps.append(findFilesRecursively(options, info, prefix + u'/'));
+ else
+ return findFilesRecursively(options, info, prefix + u'/');
+ }
+ }
+
+ // Usually android deployment settings contain Qt install directory in extraPrefixDirs.
+ if (std::find(options.extraPrefixDirs.begin(), options.extraPrefixDirs.end(),
+ options.qtInstallDirectory) == options.extraPrefixDirs.end()) {
+ QFileInfo info(options.qtInstallDirectory + "/"_L1 + fileName);
+ QFileInfo rootPath(options.qtInstallDirectory + "/"_L1);
+ deps.append(findFilesRecursively(options, info, rootPath.absolutePath()));
+ }
+ return deps;
+}
+
+void readDependenciesFromFiles(Options *options, const QList<QtDependency> &files,
+ QSet<QString> &usedDependencies,
+ QSet<QString> &remainingDependencies)
+{
+ for (const QtDependency &fileName : files) {
+ if (usedDependencies.contains(fileName.absolutePath))
+ continue;
+
+ if (fileName.absolutePath.endsWith(".so"_L1)) {
+ if (!readDependenciesFromElf(options, fileName.absolutePath, &usedDependencies,
+ &remainingDependencies)) {
+ fprintf(stdout, "Skipping file dependency: %s\n",
+ qPrintable(fileName.relativePath));
+ continue;
+ }
+ }
+ usedDependencies.insert(fileName.absolutePath);
+
+ if (options->verbose) {
+ fprintf(stdout, "Appending file dependency: %s\n", qPrintable(fileName.relativePath));
+ }
+
+ options->qtDependencies[options->currentArchitecture].append(fileName);
}
- QFileInfo info(options.qtInstallDirectory + "/"_L1 + fileName);
- QFileInfo rootPath(options.qtInstallDirectory + "/"_L1);
- return findFilesRecursively(options, info, rootPath.absolutePath() + u'/');
}
bool readAndroidDependencyXml(Options *options,
@@ -1878,29 +1942,15 @@ bool readAndroidDependencyXml(Options *options,
QString file = reader.attributes().value("file"_L1).toString();
- const QList<QtDependency> fileNames = findFilesRecursively(*options, file);
-
- for (const QtDependency &fileName : fileNames) {
- if (usedDependencies->contains(fileName.absolutePath))
- continue;
-
- if (fileName.absolutePath.endsWith(".so"_L1)) {
- QSet<QString> remainingDependencies;
- if (!readDependenciesFromElf(options, fileName.absolutePath,
- usedDependencies,
- &remainingDependencies)) {
- fprintf(stdout, "Skipping dependencies from xml: %s\n",
- qPrintable(fileName.relativePath));
- continue;
- }
- }
- usedDependencies->insert(fileName.absolutePath);
-
- if (options->verbose)
- fprintf(stdout, "Appending dependency from xml: %s\n", qPrintable(fileName.relativePath));
-
- options->qtDependencies[options->currentArchitecture].append(fileName);
+ if (reader.attributes().hasAttribute("type"_L1)
+ && reader.attributes().value("type"_L1) == "plugin_dir"_L1
+ && !options->androidDeployPlugins.isEmpty()) {
+ continue;
}
+
+ const QList<QtDependency> fileNames = findFilesRecursively(*options, file);
+ readDependenciesFromFiles(options, fileNames, *usedDependencies,
+ *remainingDependencies);
} else if (reader.name() == "jar"_L1) {
int bundling = reader.attributes().value("bundling"_L1).toInt();
QString fileName = QDir::cleanPath(reader.attributes().value("file"_L1).toString());
@@ -1984,6 +2034,7 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
if (it == elfArchitectures.constEnd() || *it != options.currentArchitecture.toLatin1()) {
if (options.verbose)
fprintf(stdout, "Skipping \"%s\", architecture mismatch\n", qPrintable(fileName));
+ pclose(readElfCommand);
return {};
}
}
@@ -2151,6 +2202,7 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
QJsonDocument jsonDocument = QJsonDocument::fromJson(output);
if (jsonDocument.isNull()) {
fprintf(stderr, "Invalid json output from qmlimportscanner.\n");
+ pclose(qmlImportScannerCommand);
return false;
}
@@ -2159,6 +2211,7 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
QJsonValue value = jsonArray.at(i);
if (!value.isObject()) {
fprintf(stderr, "Invalid format of qmlimportscanner output.\n");
+ pclose(qmlImportScannerCommand);
return false;
}
@@ -2204,6 +2257,7 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
if (importPathOfThisImport.isEmpty()) {
fprintf(stderr, "Import found outside of import paths: %s.\n", qPrintable(info.absoluteFilePath()));
+ pclose(qmlImportScannerCommand);
return false;
}
@@ -2271,6 +2325,7 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
}
}
+ pclose(qmlImportScannerCommand);
return true;
}
@@ -2377,6 +2432,14 @@ bool readDependencies(Options *options)
if (!readDependenciesFromElf(options, "%1/libs/%2/lib%3_%2.so"_L1.arg(options->outputDirectory, options->currentArchitecture, options->applicationBinary), &usedDependencies, &remainingDependencies))
return false;
+ QList<QtDependency> pluginDeps;
+ for (const auto &pluginPath : options->androidDeployPlugins) {
+ pluginDeps.append(findFilesRecursively(*options, QFileInfo(pluginPath),
+ options->qtInstallDirectory + "/"_L1));
+ }
+
+ readDependenciesFromFiles(options, pluginDeps, usedDependencies, remainingDependencies);
+
while (!remainingDependencies.isEmpty()) {
QSet<QString>::iterator start = remainingDependencies.begin();
QString fileName = absoluteFilePath(options, *start);
@@ -2549,7 +2612,7 @@ bool copyQtFiles(Options *options)
*options)) {
return false;
}
- options->bundledFiles[options->currentArchitecture] += qMakePair(destinationFileName, qtDependency.relativePath);
+ options->bundledFiles[options->currentArchitecture] += std::make_pair(destinationFileName, qtDependency.relativePath);
}
return true;
@@ -2665,11 +2728,11 @@ static bool mergeGradleProperties(const QString &path, GradleProperties properti
void checkAndWarnGradleLongPaths(const QString &outputDirectory)
{
QStringList longFileNames;
- QDirIterator it(outputDirectory, QStringList(QStringLiteral("*.java")), QDir::Files,
- QDirIterator::Subdirectories);
- while (it.hasNext()) {
- if (it.next().size() >= MAX_PATH)
- longFileNames.append(it.next());
+ using F = QDirListing::IteratorFlag;
+ for (const auto &dirEntry : QDirListing(outputDirectory, QStringList(u"*.java"_s),
+ QDir::Files, F::Recursive)) {
+ if (dirEntry.size() >= MAX_PATH)
+ longFileNames.append(dirEntry.filePath());
}
if (!longFileNames.isEmpty()) {
@@ -2682,22 +2745,36 @@ void checkAndWarnGradleLongPaths(const QString &outputDirectory)
}
#endif
-bool gradleSetsLegacyPackagingProperty(const QString &path)
+struct GradleFlags {
+ bool setsLegacyPackaging = false;
+ bool usesIntegerCompileSdkVersion = false;
+};
+
+GradleFlags gradleBuildFlags(const QString &path)
{
+ GradleFlags flags;
+
QFile file(path);
if (!file.open(QIODevice::ReadOnly))
- return false;
+ return flags;
+
+ auto isComment = [](const QByteArray &line) {
+ const auto trimmed = line.trimmed();
+ return trimmed.startsWith("//") || trimmed.startsWith('*') || trimmed.startsWith("/*");
+ };
const auto lines = file.readAll().split('\n');
for (const auto &line : lines) {
+ if (isComment(line))
+ continue;
if (line.contains("useLegacyPackaging")) {
- const auto trimmed = line.trimmed();
- if (!trimmed.startsWith("//") && !trimmed.startsWith('*') && !trimmed.startsWith("/*"))
- return true;
+ flags.setsLegacyPackaging = true;
+ } else if (line.contains("compileSdkVersion androidCompileSdkVersion.toInteger()")) {
+ flags.usesIntegerCompileSdkVersion = true;
}
}
- return false;
+ return flags;
}
bool buildAndroidProject(const Options &options)
@@ -2712,7 +2789,8 @@ bool buildAndroidProject(const Options &options)
GradleProperties gradleProperties = readGradleProperties(gradlePropertiesPath);
const QString gradleBuildFilePath = options.outputDirectory + "build.gradle"_L1;
- if (!gradleSetsLegacyPackagingProperty(gradleBuildFilePath))
+ GradleFlags gradleFlags = gradleBuildFlags(gradleBuildFilePath);
+ if (!gradleFlags.setsLegacyPackaging)
gradleProperties["android.bundle.enableUncompressedNativeLibs"] = "false";
gradleProperties["buildDir"] = "build";
@@ -2727,7 +2805,26 @@ bool buildAndroidProject(const Options &options)
(options.qtInstallDirectory + u'/' + options.qtDataDirectory +
"/src/android/java"_L1)
.toUtf8();
- gradleProperties["androidCompileSdkVersion"] = options.androidPlatform.split(u'-').last().toLocal8Bit();
+
+ QByteArray sdkPlatformVersion;
+ // Provide the integer version only if build.gradle explicitly converts to Integer,
+ // to avoid regression to existing projects that build for sdk platform of form android-xx.
+ if (gradleFlags.usesIntegerCompileSdkVersion) {
+ const QByteArray tmp = options.androidPlatform.split(u'-').last().toLocal8Bit();
+ bool ok;
+ tmp.toInt(&ok);
+ if (ok) {
+ sdkPlatformVersion = tmp;
+ } else {
+ fprintf(stderr, "Warning: Gradle expects SDK platform version to be an integer, "
+ "but the set version is not convertible to an integer.");
+ }
+ }
+
+ if (sdkPlatformVersion.isEmpty())
+ sdkPlatformVersion = options.androidPlatform.toLocal8Bit();
+
+ gradleProperties["androidCompileSdkVersion"] = sdkPlatformVersion;
gradleProperties["qtMinSdkVersion"] = options.minSdkVersion;
gradleProperties["qtTargetSdkVersion"] = options.targetSdkVersion;
gradleProperties["androidNdkVersion"] = options.ndkVersion.toUtf8();
@@ -3243,7 +3340,7 @@ int main(int argc, char *argv[])
it.value().qtDirectories);
// All architectures have a copy of the gradle files but only one set needs to be copied.
- if (!androidTemplatetCopied && options.build && !options.auxMode && !options.copyDependenciesOnly) {
+ if (!androidTemplatetCopied && options.build && !options.copyDependenciesOnly) {
cleanAndroidFiles(options);
if (Q_UNLIKELY(options.timing))
fprintf(stdout, "[TIMING] %lld ns: Cleaned Android file\n", options.timer.nsecsElapsed());
@@ -3280,13 +3377,12 @@ int main(int argc, char *argv[])
if (Q_UNLIKELY(options.timing))
fprintf(stdout, "[TIMING] %lld ns: Copied extra resources\n", options.timer.nsecsElapsed());
- if (!options.auxMode) {
- if (!copyStdCpp(&options))
- return CannotCopyGnuStl;
+ if (!copyStdCpp(&options))
+ return CannotCopyGnuStl;
+
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %lld ns: Copied GNU STL\n", options.timer.nsecsElapsed());
- if (Q_UNLIKELY(options.timing))
- fprintf(stdout, "[TIMING] %lld ns: Copied GNU STL\n", options.timer.nsecsElapsed());
- }
// If Unbundled deployment is used, remove app lib as we don't want it packaged inside the APK
if (options.deploymentMechanism == Options::Unbundled) {
QString appLibPath = "%1/libs/%2/lib%3_%2.so"_L1.
diff --git a/src/tools/androidtestrunner/CMakeLists.txt b/src/tools/androidtestrunner/CMakeLists.txt
index 77157e29a3..7935753cff 100644
--- a/src/tools/androidtestrunner/CMakeLists.txt
+++ b/src/tools/androidtestrunner/CMakeLists.txt
@@ -17,8 +17,6 @@ qt_internal_add_tool(${target_name}
QT_NO_FOREACH
LIBRARIES
Qt::Core
- INCLUDE_DIRECTORIES
- ../shared
)
qt_internal_return_unless_building_tools()
set_target_properties(${target_name} PROPERTIES
diff --git a/src/tools/androidtestrunner/main.cpp b/src/tools/androidtestrunner/main.cpp
index 0a2c8e63b8..baad678ec0 100644
--- a/src/tools/androidtestrunner/main.cpp
+++ b/src/tools/androidtestrunner/main.cpp
@@ -1,27 +1,25 @@
// Copyright (C) 2019 BogDan Vatra <bogdan@kde.org>
-// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-#include <QCoreApplication>
-#include <QDir>
-#include <QHash>
-#include <QRegularExpression>
-#include <QSystemSemaphore>
-#include <QXmlStreamReader>
-
-#include <algorithm>
-#include <chrono>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDeadlineTimer>
+#include <QtCore/QDir>
+#include <QtCore/QHash>
+#include <QtCore/QProcess>
+#include <QtCore/QProcessEnvironment>
+#include <QtCore/QRegularExpression>
+#include <QtCore/QSystemSemaphore>
+#include <QtCore/QThread>
+#include <QtCore/QXmlStreamReader>
+
+#include <atomic>
+#include <csignal>
#include <functional>
-#include <thread>
-
-#include <shellquote_shared.h>
-
-#ifdef Q_CC_MSVC
-#define popen _popen
-#define QT_POPEN_READ "rb"
-#define pclose _pclose
+#if defined(Q_OS_WIN32)
+#include <process.h>
#else
-#define QT_POPEN_READ "r"
+#include <unistd.h>
#endif
using namespace Qt::StringLiterals;
@@ -34,12 +32,12 @@ static bool checkJunit(const QByteArray &data) {
if (!reader.isStartElement())
continue;
- if (reader.name() == QStringLiteral("error"))
+ if (reader.name() == "error"_L1)
return false;
- const QString type = reader.attributes().value(QStringLiteral("type")).toString();
- if (reader.name() == QStringLiteral("failure")) {
- if (type == QStringLiteral("fail") || type == QStringLiteral("xpass"))
+ const QString type = reader.attributes().value("type"_L1).toString();
+ if (reader.name() == "failure"_L1) {
+ if (type == "fail"_L1 || type == "xpass"_L1)
return false;
}
}
@@ -70,10 +68,10 @@ static bool checkXml(const QByteArray &data) {
QXmlStreamReader reader{data};
while (!reader.atEnd()) {
reader.readNext();
- const QString type = reader.attributes().value(QStringLiteral("type")).toString();
- const bool isIncident = (reader.name() == QStringLiteral("Incident"));
+ const QString type = reader.attributes().value("type"_L1).toString();
+ const bool isIncident = (reader.name() == "Incident"_L1);
if (reader.isStartElement() && isIncident) {
- if (type == QStringLiteral("fail") || type == QStringLiteral("xpass"))
+ if (type == "fail"_L1 || type == "xpass"_L1)
return false;
}
}
@@ -115,55 +113,88 @@ struct Options
bool helpRequested = false;
bool verbose = false;
bool skipAddInstallRoot = false;
- std::chrono::seconds timeout{480}; // 8 minutes
+ int timeoutSecs = 600; // 10 minutes
QString buildPath;
- QString adbCommand{QStringLiteral("adb")};
+ QString adbCommand{"adb"_L1};
QString makeCommand;
QString package;
QString activity;
QStringList testArgsList;
QHash<QString, QString> outFiles;
- QString testArgs;
+ QStringList amStarttestArgs;
QString apkPath;
- int sdkVersion = -1;
- int pid = -1;
+ QString ndkStackPath;
bool showLogcatOutput = false;
const QHash<QString, std::function<bool(const QByteArray &)>> checkFiles = {
- {QStringLiteral("txt"), checkTxt},
- {QStringLiteral("csv"), checkCsv},
- {QStringLiteral("xml"), checkXml},
- {QStringLiteral("lightxml"), checkLightxml},
- {QStringLiteral("xunitxml"), checkJunit},
- {QStringLiteral("junitxml"), checkJunit},
- {QStringLiteral("teamcity"), checkTeamcity},
- {QStringLiteral("tap"), checkTap},
+ {"txt"_L1, checkTxt},
+ {"csv"_L1, checkCsv},
+ {"xml"_L1, checkXml},
+ {"lightxml"_L1, checkLightxml},
+ {"xunitxml"_L1, checkJunit},
+ {"junitxml"_L1, checkJunit},
+ {"teamcity"_L1, checkTeamcity},
+ {"tap"_L1, checkTap},
};
};
static Options g_options;
-static bool execCommand(const QString &command, QByteArray *output = nullptr, bool verbose = false)
+struct TestInfo
+{
+ int sdkVersion = -1;
+ int pid = -1;
+
+ std::atomic<bool> isPackageInstalled { false };
+ std::atomic<bool> isTestRunnerInterrupted { false };
+};
+
+static TestInfo g_testInfo;
+
+static bool execCommand(const QString &program, const QStringList &args,
+ QByteArray *output = nullptr, bool verbose = false)
{
- if (verbose)
- fprintf(stdout, "Execute %s.\n", command.toUtf8().constData());
- FILE *process = popen(command.toUtf8().constData(), QT_POPEN_READ);
+ const auto command = program + " "_L1 + args.join(u' ');
- if (!process) {
- fprintf(stderr, "Cannot execute command %s.\n", qPrintable(command));
+ if (verbose && g_options.verbose)
+ qDebug("Execute %s.", command.toUtf8().constData());
+
+ QProcess process;
+ process.start(program, args);
+ if (!process.waitForStarted()) {
+ qCritical("Cannot execute command %s.", qPrintable(command));
return false;
}
- char buffer[512];
- while (fgets(buffer, sizeof(buffer), process)) {
- if (output)
- output->append(buffer);
- if (verbose)
- fprintf(stdout, "%s", buffer);
+
+ // If the command is not adb, for example, make or ninja, it can take more that
+ // QProcess::waitForFinished() 30 secs, so for that use a higher timeout.
+ const int FinishTimeout = program.endsWith("adb"_L1) ? 30000 : g_options.timeoutSecs * 1000;
+ if (!process.waitForFinished(FinishTimeout)) {
+ qCritical("Execution of command %s timed out.", qPrintable(command));
+ return false;
}
- fflush(stdout);
- fflush(stderr);
+ const auto stdOut = process.readAllStandardOutput();
+ if (output)
+ output->append(stdOut);
+
+ if (verbose && g_options.verbose)
+ qDebug() << stdOut.constData();
+
+ return process.exitCode() == 0;
+}
+
+static bool execAdbCommand(const QStringList &args, QByteArray *output = nullptr,
+ bool verbose = true)
+{
+ return execCommand(g_options.adbCommand, args, output, verbose);
+}
- return pclose(process) == 0;
+static bool execCommand(const QString &command, QByteArray *output = nullptr, bool verbose = true)
+{
+ auto args = QProcess::splitCommand(command);
+ const auto program = args.first();
+ args.removeOne(program);
+ return execCommand(program, args, output, verbose);
}
static bool parseOptions()
@@ -172,45 +203,50 @@ static bool parseOptions()
int i = 1;
for (; i < arguments.size(); ++i) {
const QString &argument = arguments.at(i);
- if (argument.compare(QStringLiteral("--adb"), Qt::CaseInsensitive) == 0) {
+ if (argument.compare("--adb"_L1, Qt::CaseInsensitive) == 0) {
if (i + 1 == arguments.size())
g_options.helpRequested = true;
else
g_options.adbCommand = arguments.at(++i);
- } else if (argument.compare(QStringLiteral("--path"), Qt::CaseInsensitive) == 0) {
+ } else if (argument.compare("--path"_L1, Qt::CaseInsensitive) == 0) {
if (i + 1 == arguments.size())
g_options.helpRequested = true;
else
g_options.buildPath = arguments.at(++i);
- } else if (argument.compare(QStringLiteral("--make"), Qt::CaseInsensitive) == 0) {
+ } else if (argument.compare("--make"_L1, Qt::CaseInsensitive) == 0) {
if (i + 1 == arguments.size())
g_options.helpRequested = true;
else
g_options.makeCommand = arguments.at(++i);
- } else if (argument.compare(QStringLiteral("--apk"), Qt::CaseInsensitive) == 0) {
+ } else if (argument.compare("--apk"_L1, Qt::CaseInsensitive) == 0) {
if (i + 1 == arguments.size())
g_options.helpRequested = true;
else
g_options.apkPath = arguments.at(++i);
- } else if (argument.compare(QStringLiteral("--activity"), Qt::CaseInsensitive) == 0) {
+ } else if (argument.compare("--activity"_L1, Qt::CaseInsensitive) == 0) {
if (i + 1 == arguments.size())
g_options.helpRequested = true;
else
g_options.activity = arguments.at(++i);
- } else if (argument.compare(QStringLiteral("--skip-install-root"), Qt::CaseInsensitive) == 0) {
+ } else if (argument.compare("--skip-install-root"_L1, Qt::CaseInsensitive) == 0) {
g_options.skipAddInstallRoot = true;
- } else if (argument.compare(QStringLiteral("--show-logcat"), Qt::CaseInsensitive) == 0) {
+ } else if (argument.compare("--show-logcat"_L1, Qt::CaseInsensitive) == 0) {
g_options.showLogcatOutput = true;
- } else if (argument.compare(QStringLiteral("--timeout"), Qt::CaseInsensitive) == 0) {
+ } else if (argument.compare("--ndk-stack"_L1, Qt::CaseInsensitive) == 0) {
if (i + 1 == arguments.size())
g_options.helpRequested = true;
else
- g_options.timeout = std::chrono::seconds{arguments.at(++i).toInt()};
- } else if (argument.compare(QStringLiteral("--help"), Qt::CaseInsensitive) == 0) {
+ g_options.ndkStackPath = arguments.at(++i);
+ } else if (argument.compare("--timeout"_L1, Qt::CaseInsensitive) == 0) {
+ if (i + 1 == arguments.size())
+ g_options.helpRequested = true;
+ else
+ g_options.timeoutSecs = arguments.at(++i).toInt();
+ } else if (argument.compare("--help"_L1, Qt::CaseInsensitive) == 0) {
g_options.helpRequested = true;
- } else if (argument.compare(QStringLiteral("--verbose"), Qt::CaseInsensitive) == 0) {
+ } else if (argument.compare("--verbose"_L1, Qt::CaseInsensitive) == 0) {
g_options.verbose = true;
- } else if (argument.compare(QStringLiteral("--"), Qt::CaseInsensitive) == 0) {
+ } else if (argument.compare("--"_L1, Qt::CaseInsensitive) == 0) {
++i;
break;
} else {
@@ -225,17 +261,24 @@ static bool parseOptions()
QString serial = qEnvironmentVariable("ANDROID_DEVICE_SERIAL");
if (!serial.isEmpty())
- g_options.adbCommand += QStringLiteral(" -s %1").arg(serial);
+ g_options.adbCommand += " -s %1"_L1.arg(serial);
+
+ if (g_options.ndkStackPath.isEmpty()) {
+ const QString ndkPath = qEnvironmentVariable("ANDROID_NDK_ROOT");
+ const QString ndkStackPath = ndkPath + QDir::separator() + "ndk-stack"_L1;
+ if (QFile::exists(ndkStackPath))
+ g_options.ndkStackPath = ndkStackPath;
+ }
+
return true;
}
static void printHelp()
{
- fprintf(stderr, "Syntax: %s <options> -- [TESTARGS] \n"
+ qWarning( "Syntax: %s <options> -- [TESTARGS] \n"
"\n"
- " Creates an Android package in a temp directory <destination> and\n"
- " runs it on the default emulator/device or on the one specified by\n"
- " \"ANDROID_DEVICE_SERIAL\" environment variable.\n"
+ " Runs an Android test on the default emulator/device or on the one\n"
+ " specified by \"ANDROID_DEVICE_SERIAL\" environment variable.\n"
"\n"
" Mandatory arguments:\n"
" --path <path>: The path where androiddeployqt builds the android package.\n"
@@ -245,7 +288,7 @@ static void printHelp()
"\n"
" Optional arguments:\n"
" --make <make cmd>: make command, needed to install the qt library.\n"
- " For Qt 5.14+ this can be \"make apk\".\n"
+ " For Qt 6, this can be \"cmake --build . --target <target>_make_apk\".\n"
"\n"
" --adb <adb cmd>: The Android ADB command. If missing the one from\n"
" $PATH will be used.\n"
@@ -253,17 +296,20 @@ static void printHelp()
" --activity <acitvity>: The Activity to run. If missing the first\n"
" activity from AndroidManifest.qml file will be used.\n"
"\n"
- " --timeout <seconds>: Timeout to run the test. Default is 5 minutes.\n"
+ " --timeout <seconds>: Timeout to run the test. Default is 10 minutes.\n"
"\n"
" --skip-install-root: Do not append INSTALL_ROOT=... to the make command.\n"
"\n"
" --show-logcat: Print Logcat output to stdout.\n"
"\n"
+ " --ndk-stack: Path to ndk-stack tool that symbolizes crash stacktraces.\n"
+ " By default, ANDROID_NDK_ROOT env var is used to deduce the tool path.\n"
+ "\n"
" -- Arguments that will be passed to the test application.\n"
"\n"
" --verbose: Prints out information during processing.\n"
"\n"
- " --help: Displays this information.\n\n",
+ " --help: Displays this information.\n",
qPrintable(QCoreApplication::arguments().at(0))
);
}
@@ -275,8 +321,8 @@ static QString packageNameFromAndroidManifest(const QString &androidManifestPath
QXmlStreamReader reader(&androidManifestXml);
while (!reader.atEnd()) {
reader.readNext();
- if (reader.isStartElement() && reader.name() == QStringLiteral("manifest"))
- return reader.attributes().value(QStringLiteral("package")).toString();
+ if (reader.isStartElement() && reader.name() == "manifest"_L1)
+ return reader.attributes().value("package"_L1).toString();
}
}
return {};
@@ -289,8 +335,8 @@ static QString activityFromAndroidManifest(const QString &androidManifestPath)
QXmlStreamReader reader(&androidManifestXml);
while (!reader.atEnd()) {
reader.readNext();
- if (reader.isStartElement() && reader.name() == QStringLiteral("activity"))
- return reader.attributes().value(QStringLiteral("android:name")).toString();
+ if (reader.isStartElement() && reader.name() == "activity"_L1)
+ return reader.attributes().value("android:name"_L1).toString();
}
}
return {};
@@ -299,26 +345,26 @@ static QString activityFromAndroidManifest(const QString &androidManifestPath)
static void setOutputFile(QString file, QString format)
{
if (file.isEmpty())
- file = QStringLiteral("-");
+ file = "-"_L1;
if (format.isEmpty())
- format = QStringLiteral("txt");
+ format = "txt"_L1;
g_options.outFiles[format] = file;
}
static bool parseTestArgs()
{
- QRegularExpression oldFormats{QStringLiteral("^-(txt|csv|xunitxml|junitxml|xml|lightxml|teamcity|tap)$")};
- QRegularExpression newLoggingFormat{QStringLiteral("^(.*),(txt|csv|xunitxml|junitxml|xml|lightxml|teamcity|tap)$")};
+ QRegularExpression oldFormats{"^-(txt|csv|xunitxml|junitxml|xml|lightxml|teamcity|tap)$"_L1};
+ QRegularExpression newLoggingFormat{"^(.*),(txt|csv|xunitxml|junitxml|xml|lightxml|teamcity|tap)$"_L1};
QString file;
QString logType;
QStringList unhandledArgs;
for (int i = 0; i < g_options.testArgsList.size(); ++i) {
const QString &arg = g_options.testArgsList[i].trimmed();
- if (arg == QStringLiteral("--"))
+ if (arg == "--"_L1)
continue;
- if (arg == QStringLiteral("-o")) {
+ if (arg == "-o"_L1) {
if (i >= g_options.testArgsList.size() - 1)
return false; // missing file argument
@@ -335,129 +381,157 @@ static bool parseTestArgs()
if (match.hasMatch()) {
logType = match.capturedTexts().at(1);
} else {
- unhandledArgs << QStringLiteral(" \\\"%1\\\"").arg(arg);
+ // Use triple literal quotes so that QProcess::splitCommand() in androidjnimain.cpp
+ // keeps quotes characters inside the string.
+ QString quotedArg = QString(arg).replace("\""_L1, "\\\"\\\"\\\""_L1);
+ // Escape single quotes so they don't interfere with the shell command,
+ // and so they get passed to the app as single quote inside the string.
+ quotedArg.replace("'"_L1, "\'"_L1);
+ // Add escaped double quote character so that args with spaces are treated as one.
+ unhandledArgs << " \\\"%1\\\""_L1.arg(quotedArg);
}
}
}
if (g_options.outFiles.isEmpty() || !file.isEmpty() || !logType.isEmpty())
setOutputFile(file, logType);
+ QString testAppArgs;
for (const auto &format : g_options.outFiles.keys())
- g_options.testArgs += QStringLiteral(" -o output.%1,%1").arg(format);
+ testAppArgs += "-o output.%1,%1 "_L1.arg(format);
+
+ testAppArgs += unhandledArgs.join(u' ').trimmed();
+ testAppArgs = "\"%1\""_L1.arg(testAppArgs.trimmed());
+ const QString activityName = "%1/%2"_L1.arg(g_options.package).arg(g_options.activity);
+
+ // Pass over any testlib env vars if set
+ QString testEnvVars;
+ const QStringList envVarsList = QProcessEnvironment::systemEnvironment().toStringList();
+ for (const QString &var : envVarsList) {
+ if (var.startsWith("QTEST_"_L1))
+ testEnvVars += "%1 "_L1.arg(var);
+ }
- g_options.testArgs += unhandledArgs.join(u' ');
+ if (!testEnvVars.isEmpty()) {
+ testEnvVars = QString::fromUtf8(testEnvVars.trimmed().toUtf8().toBase64());
+ testEnvVars = "-e extraenvvars \"%4\""_L1.arg(testEnvVars);
+ }
- g_options.testArgs = QStringLiteral("shell am start -e applicationArguments \"%1\" -n %2/%3")
- .arg(shellQuote(g_options.testArgs.trimmed()))
- .arg(g_options.package)
- .arg(g_options.activity);
+ g_options.amStarttestArgs = { "shell"_L1, "am"_L1, "start"_L1,
+ "-n"_L1, activityName,
+ "-e"_L1, "applicationArguments"_L1, testAppArgs,
+ testEnvVars
+ };
return true;
}
-static bool isRunning() {
+static bool obtainPid() {
QByteArray output;
- if (!execCommand(QStringLiteral("%1 shell \"ps | grep ' %2'\"").arg(g_options.adbCommand,
- shellQuote(g_options.package)), &output)) {
+ const QStringList psArgs = { "shell"_L1, "ps | grep ' %1'"_L1.arg(g_options.package) };
+ if (!execAdbCommand(psArgs, &output, false))
+ return false;
+
+ const QList<QByteArray> lines = output.split(u'\n');
+ if (lines.size() < 1)
+ return false;
+ QList<QByteArray> columns = lines.first().simplified().replace(u'\t', u' ').split(u' ');
+ if (columns.size() < 3)
return false;
+
+ if (g_testInfo.pid == -1) {
+ bool ok = false;
+ int pid = columns.at(1).toInt(&ok);
+ if (ok)
+ g_testInfo.pid = pid;
}
+
+ return true;
+}
+
+static bool isRunning() {
+ QByteArray output;
+ const QStringList psArgs = { "shell"_L1, "ps | grep ' %1'"_L1.arg(g_options.package) };
+ if (!execAdbCommand(psArgs, &output, false))
+ return false;
+
return output.indexOf(QLatin1StringView(" " + g_options.package.toUtf8())) > -1;
}
-static bool waitToFinish()
+static void waitForStartedAndFinished()
{
- using clock = std::chrono::system_clock;
- auto start = clock::now();
- // wait to start
- while (!isRunning()) {
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
- if ((clock::now() - start) > std::chrono::seconds{10})
- return false;
- }
-
- if (g_options.sdkVersion > 23) { // pidof is broken in SDK 23, non-existent before
- QByteArray output;
- const QString command(QStringLiteral("%1 shell pidof -s %2")
- .arg(g_options.adbCommand, shellQuote(g_options.package)));
- execCommand(command, &output, g_options.verbose);
- bool ok = false;
- int pid = output.toInt(&ok); // If we got more than one pid, fail.
- if (ok) {
- g_options.pid = pid;
- } else {
- fprintf(stderr,
- "Unable to obtain the PID of the running unit test. Command \"%s\" "
- "returned \"%s\"\n",
- command.toUtf8().constData(), output.constData());
- fflush(stderr);
- }
- }
+ // wait to start and set PID
+ QDeadlineTimer startDeadline(10000);
+ do {
+ if (obtainPid())
+ break;
+ QThread::msleep(100);
+ } while (!startDeadline.hasExpired() && !g_testInfo.isTestRunnerInterrupted.load());
// Wait to finish
- while (isRunning()) {
- std::this_thread::sleep_for(std::chrono::milliseconds(250));
- if (g_options.timeout >= std::chrono::seconds::zero()
- && (clock::now() - start) > g_options.timeout)
- return false;
- }
- return true;
+ QDeadlineTimer finishedDeadline(g_options.timeoutSecs * 1000);
+ do {
+ if (!isRunning())
+ break;
+ QThread::msleep(250);
+ } while (!finishedDeadline.hasExpired() && !g_testInfo.isTestRunnerInterrupted.load());
+
+ if (finishedDeadline.hasExpired())
+ qWarning() << "Timed out while waiting for the test to finish";
}
-static void obtainSDKVersion()
+static void obtainSdkVersion()
{
// SDK version is necessary, as in SDK 23 pidof is broken, so we cannot obtain the pid.
// Also, Logcat cannot filter by pid in SDK 23, so we don't offer the --show-logcat option.
QByteArray output;
- const QString command(
- QStringLiteral("%1 shell getprop ro.build.version.sdk").arg(g_options.adbCommand));
- execCommand(command, &output, g_options.verbose);
+ const QStringList versionArgs = { "shell"_L1, "getprop"_L1, "ro.build.version.sdk"_L1 };
+ execAdbCommand(versionArgs, &output, false);
bool ok = false;
int sdkVersion = output.toInt(&ok);
- if (ok) {
- g_options.sdkVersion = sdkVersion;
- } else {
- fprintf(stderr,
- "Unable to obtain the SDK version of the target. Command \"%s\" "
- "returned \"%s\"\n",
- command.toUtf8().constData(), output.constData());
- fflush(stderr);
- }
+ if (ok)
+ g_testInfo.sdkVersion = sdkVersion;
+ else
+ qCritical() << "Unable to obtain the SDK version of the target.";
}
static bool pullFiles()
{
bool ret = true;
+ QByteArray userId;
+ // adb get-current-user command is available starting from API level 26.
+ if (g_testInfo.sdkVersion >= 26) {
+ const QStringList userIdArgs = {"shell"_L1, "cmd"_L1, "activity"_L1, "get-current-user"_L1};
+ if (!execAdbCommand(userIdArgs, &userId, false)) {
+ qCritical() << "Error: failed to retrieve the user ID";
+ return false;
+ }
+ } else {
+ userId = "0";
+ }
+
for (auto it = g_options.outFiles.constBegin(); it != g_options.outFiles.end(); ++it) {
// Get only stdout from cat and get rid of stderr and fail later if the output is empty
- const QString catCmd = QStringLiteral("cat files/output.%1 2> /dev/null").arg(it.key());
+ const QString outSuffix = it.key();
+ const QString catCmd = "cat files/output.%1 2> /dev/null"_L1.arg(outSuffix);
+ const QStringList fullCatArgs = { "shell"_L1, "run-as %1 --user %2 %3"_L1.arg(
+ g_options.package, QString::fromUtf8(userId.simplified()), catCmd) };
QByteArray output;
- if (!execCommand(QStringLiteral("%1 shell 'run-as %2 %3'")
- .arg(g_options.adbCommand, g_options.package, catCmd), &output)) {
- // Cannot find output file. Check in path related to current user
- QByteArray userId;
- execCommand(QStringLiteral("%1 shell cmd activity get-current-user")
- .arg(g_options.adbCommand), &userId);
- const QString userIdSimplified(QString::fromUtf8(userId).simplified());
- if (!execCommand(QStringLiteral("%1 shell 'run-as %2 --user %3 %4'")
- .arg(g_options.adbCommand, g_options.package, userIdSimplified, catCmd),
- &output)) {
- return false;
- }
+ if (!execAdbCommand(fullCatArgs, &output, false)) {
+ qCritical() << "Error: failed to retrieve the test's output.%1 file."_L1.arg(outSuffix);
+ return false;
}
if (output.isEmpty()) {
- fprintf(stderr, "Failed to get the test output from the target. Either the output "
- "is empty or androidtestrunner failed to retrieve it.\n");
+ qCritical() << "Error: the test's output.%1 is empty."_L1.arg(outSuffix);
return false;
}
- auto checkerIt = g_options.checkFiles.find(it.key());
- ret = ret && checkerIt != g_options.checkFiles.end() && checkerIt.value()(output);
- if (it.value() == QStringLiteral("-")){
- fprintf(stdout, "%s", output.constData());
- fflush(stdout);
+ auto checkerIt = g_options.checkFiles.find(outSuffix);
+ ret &= (checkerIt != g_options.checkFiles.end() && checkerIt.value()(output));
+ if (it.value() == "-"_L1) {
+ qDebug() << output.constData();
} else {
QFile out{it.value()};
if (!out.open(QIODevice::WriteOnly))
@@ -468,22 +542,171 @@ static bool pullFiles()
return ret;
}
-struct RunnerLocker
+void printLogcat(const QString &formattedTime)
{
- RunnerLocker()
- {
- runner.acquire();
+ QStringList logcatArgs = { "logcat"_L1 };
+ if (g_testInfo.sdkVersion <= 23 || g_testInfo.pid == -1)
+ logcatArgs << "-t"_L1 << formattedTime;
+ else
+ logcatArgs << "-d"_L1 << "--pid=%1"_L1.arg(QString::number(g_testInfo.pid));
+
+ QByteArray logcat;
+ if (!execAdbCommand(logcatArgs, &logcat, false)) {
+ qCritical() << "Error: failed to fetch logcat of the test";
+ return;
}
- ~RunnerLocker()
+
+ if (logcat.isEmpty()) {
+ qWarning() << "The retrieved logcat is empty";
+ return;
+ }
+
+ qDebug() << "****** Begin logcat output ******";
+ qDebug().noquote() << logcat;
+ qDebug() << "****** End logcat output ******";
+}
+
+static QString getDeviceABI()
+{
+ const QStringList abiArgs = { "shell"_L1, "getprop"_L1, "ro.product.cpu.abi"_L1 };
+ QByteArray abi;
+ if (!execAdbCommand(abiArgs, &abi, false)) {
+ qWarning() << "Warning: failed to get the device abi, fallback to first libs dir";
+ return {};
+ }
+
+ return QString::fromUtf8(abi.simplified());
+}
+
+void printLogcatCrashBuffer(const QString &formattedTime)
+{
+ bool useNdkStack = false;
+ auto libsPath = "%1/libs/"_L1.arg(g_options.buildPath);
+
+ if (!g_options.ndkStackPath.isEmpty()) {
+ QString abi = getDeviceABI();
+ if (abi.isEmpty()) {
+ QStringList subDirs = QDir(libsPath).entryList(QDir::Dirs | QDir::NoDotAndDotDot);
+ if (!subDirs.isEmpty())
+ abi = subDirs.first();
+ }
+
+ if (!abi.isEmpty()) {
+ libsPath += abi;
+ useNdkStack = true;
+ } else {
+ qWarning() << "Warning: failed to get the libs abi, ndk-stack cannot be used.";
+ }
+ } else {
+ qWarning() << "Warning: ndk-stack path not provided and couldn't be deduced "
+ "using the ANDROID_NDK_ROOT environment variable.";
+ }
+
+ QProcess adbCrashProcess;
+ QProcess ndkStackProcess;
+
+ if (useNdkStack) {
+ adbCrashProcess.setStandardOutputProcess(&ndkStackProcess);
+ ndkStackProcess.start(g_options.ndkStackPath, { "-sym"_L1, libsPath });
+ }
+
+ const QStringList adbCrashArgs = { "logcat"_L1, "-b"_L1, "crash"_L1, "-t"_L1, formattedTime };
+ adbCrashProcess.start(g_options.adbCommand, adbCrashArgs);
+
+ if (!adbCrashProcess.waitForStarted()) {
+ qCritical() << "Error: failed to run adb logcat crash command.";
+ return;
+ }
+
+ if (useNdkStack && !ndkStackProcess.waitForStarted()) {
+ qCritical() << "Error: failed to run ndk-stack command.";
+ return;
+ }
+
+ if (!adbCrashProcess.waitForFinished()) {
+ qCritical() << "Error: adb command timed out.";
+ return;
+ }
+
+ if (useNdkStack && !ndkStackProcess.waitForFinished()) {
+ qCritical() << "Error: ndk-stack command timed out.";
+ return;
+ }
+
+ const QByteArray crash = useNdkStack ? ndkStackProcess.readAllStandardOutput()
+ : adbCrashProcess.readAllStandardOutput();
+ if (crash.isEmpty()) {
+ qWarning() << "The retrieved crash logcat is empty";
+ return;
+ }
+
+ qDebug() << "****** Begin logcat crash buffer output ******";
+ qDebug().noquote() << crash;
+ qDebug() << "****** End logcat crash buffer output ******";
+}
+
+static QString getCurrentTimeString()
+{
+ const QString timeFormat = (g_testInfo.sdkVersion <= 23) ?
+ "%m-%d %H:%M:%S.000"_L1 : "%Y-%m-%d %H:%M:%S.%3N"_L1;
+
+ QStringList dateArgs = { "shell"_L1, "date"_L1, "+'%1'"_L1.arg(timeFormat) };
+ QByteArray output;
+ if (!execAdbCommand(dateArgs, &output, false)) {
+ qWarning() << "Date/time adb command failed";
+ return {};
+ }
+
+ return QString::fromUtf8(output.simplified());
+}
+
+static bool uninstallTestPackage()
+{
+ return execAdbCommand({ "uninstall"_L1, g_options.package }, nullptr);
+}
+
+struct TestRunnerSystemSemaphore
+{
+ TestRunnerSystemSemaphore() { }
+ ~TestRunnerSystemSemaphore() { release(); }
+
+ void acquire() { isAcquired.store(semaphore.acquire()); }
+
+ void release()
{
- runner.release();
+ bool expected = true;
+ // NOTE: There's still could be tiny time gap between the compare_exchange_strong() call
+ // and release() call where the thread could be interrupted, if that's ever an issue,
+ // this code could be checked and improved further.
+ if (isAcquired.compare_exchange_strong(expected, false))
+ isAcquired.store(!semaphore.release());
}
- QSystemSemaphore runner{ QSystemSemaphore::platformSafeKey(u"androidtestrunner"_s),
- 1, QSystemSemaphore::Open };
+
+ std::atomic<bool> isAcquired { false };
+ QSystemSemaphore semaphore { QSystemSemaphore::platformSafeKey(u"androidtestrunner"_s),
+ 1, QSystemSemaphore::Open };
};
+TestRunnerSystemSemaphore testRunnerLock;
+
+void sigHandler(int signal)
+{
+ std::signal(signal, SIG_DFL);
+ testRunnerLock.release();
+ // Ideally we shouldn't be doing such calls from a signal handler,
+ // and we can't use QSocketNotifier because this tool doesn't spin
+ // a main event loop. Since, there's no other alternative to do this,
+ // let's do the cleanup anyway.
+ if (!g_testInfo.isPackageInstalled.load())
+ _exit(-1);
+ g_testInfo.isTestRunnerInterrupted.store(true);
+}
+
int main(int argc, char *argv[])
{
+ std::signal(SIGINT, sigHandler);
+ std::signal(SIGTERM, sigHandler);
+
QCoreApplication a(argc, argv);
if (!parseOptions()) {
printHelp();
@@ -491,43 +714,33 @@ int main(int argc, char *argv[])
}
if (g_options.makeCommand.isEmpty()) {
- fprintf(stderr,
- "It is required to provide a make command with the \"--make\" parameter "
- "to generate the apk.\n");
+ qCritical() << "It is required to provide a make command with the \"--make\" parameter "
+ "to generate the apk.";
return 1;
}
if (!execCommand(g_options.makeCommand, nullptr, true)) {
if (!g_options.skipAddInstallRoot) {
// we need to run make INSTALL_ROOT=path install to install the application file(s) first
- if (!execCommand(QStringLiteral("%1 INSTALL_ROOT=%2 install")
- .arg(g_options.makeCommand, QDir::toNativeSeparators(g_options.buildPath)), nullptr, g_options.verbose)) {
+ if (!execCommand("%1 INSTALL_ROOT=%2 install"_L1.arg(g_options.makeCommand,
+ QDir::toNativeSeparators(g_options.buildPath)), nullptr)) {
return 1;
}
} else {
- if (!execCommand(QStringLiteral("%1")
- .arg(g_options.makeCommand), nullptr, g_options.verbose)) {
+ if (!execCommand(g_options.makeCommand, nullptr))
return 1;
- }
}
}
if (!QFile::exists(g_options.apkPath)) {
- fprintf(stderr,
- "No apk \"%s\" found after running the make command. Check the provided path and "
- "the make command.\n",
- qPrintable(g_options.apkPath));
+ qCritical("No apk \"%s\" found after running the make command. "
+ "Check the provided path and the make command.",
+ qPrintable(g_options.apkPath));
return 1;
}
- obtainSDKVersion();
+ obtainSdkVersion();
- RunnerLocker lock; // do not install or run packages while another test is running
- if (!execCommand(QStringLiteral("%1 install -r -g %2")
- .arg(g_options.adbCommand, g_options.apkPath), nullptr, g_options.verbose)) {
- return 1;
- }
-
- QString manifest = g_options.buildPath + QStringLiteral("/AndroidManifest.xml");
+ QString manifest = g_options.buildPath + "/AndroidManifest.xml"_L1;
g_options.package = packageNameFromAndroidManifest(manifest);
if (g_options.activity.isEmpty())
g_options.activity = activityFromAndroidManifest(manifest);
@@ -536,30 +749,42 @@ int main(int argc, char *argv[])
if (!parseTestArgs())
return 1;
+ // do not install or run packages while another test is running
+ testRunnerLock.acquire();
+
+ const QStringList installArgs = { "install"_L1, "-r"_L1, "-g"_L1, g_options.apkPath };
+ g_testInfo.isPackageInstalled.store(execAdbCommand(installArgs, nullptr));
+ if (!g_testInfo.isPackageInstalled)
+ return 1;
+
+ const QString formattedTime = getCurrentTimeString();
+
// start the tests
- bool res = execCommand(QStringLiteral("%1 %2").arg(g_options.adbCommand, g_options.testArgs),
- nullptr, g_options.verbose)
- && waitToFinish();
-
- // get logcat output
- if (res && g_options.showLogcatOutput) {
- if (g_options.sdkVersion <= 23) {
- fprintf(stderr, "Cannot show logcat output on Android 23 and below.\n");
- fflush(stderr);
- } else if (g_options.pid > 0) {
- fprintf(stdout, "Logcat output:\n");
- res &= execCommand(QStringLiteral("%1 logcat -d --pid=%2")
- .arg(g_options.adbCommand)
- .arg(g_options.pid),
- nullptr, true);
- fprintf(stdout, "End Logcat output.\n");
- }
+ bool success = execAdbCommand(g_options.amStarttestArgs, nullptr);
+
+ waitForStartedAndFinished();
+
+ if (success) {
+ success &= pullFiles();
+ if (g_options.showLogcatOutput)
+ printLogcat(formattedTime);
+ }
+
+ // If we have a failure, attempt to print both logcat and the crash buffer which
+ // includes the crash stacktrace that is not included in the default logcat.
+ if (!success) {
+ printLogcat(formattedTime);
+ printLogcatCrashBuffer(formattedTime);
+ }
+
+ success &= uninstallTestPackage();
+
+ testRunnerLock.release();
+
+ if (g_testInfo.isTestRunnerInterrupted.load()) {
+ qCritical() << "The androidtestrunner was interrupted and the was test cleaned up.";
+ return 1;
}
- if (res)
- res &= pullFiles();
- res &= execCommand(QStringLiteral("%1 uninstall %2").arg(g_options.adbCommand, g_options.package),
- nullptr, g_options.verbose);
- fflush(stdout);
- return res ? 0 : 1;
+ return success ? 0 : 1;
}
diff --git a/src/tools/bootstrap/CMakeLists.txt b/src/tools/bootstrap/CMakeLists.txt
index e065fdf2cb..93e826fa22 100644
--- a/src/tools/bootstrap/CMakeLists.txt
+++ b/src/tools/bootstrap/CMakeLists.txt
@@ -14,20 +14,14 @@ qt_internal_add_sync_header_dependencies(Bootstrap Core)
qt_internal_extend_target(Bootstrap
SOURCES
../../corelib/global/qassert.cpp
- ../../corelib/global/qendian.cpp
../../corelib/global/qfloat16.cpp
- ../../corelib/global/qglobal.cpp
../../corelib/global/qlogging.cpp
../../corelib/global/qmalloc.cpp
- ../../corelib/global/qnumeric.cpp
- ../../corelib/global/qoperatingsystemversion.cpp
- ../../corelib/global/qrandom.cpp
../../corelib/global/qtenvironmentvariables.cpp
../../corelib/io/qabstractfileengine.cpp
../../corelib/io/qbuffer.cpp
../../corelib/io/qdebug.cpp
../../corelib/io/qdir.cpp
- ../../corelib/io/qdiriterator.cpp
../../corelib/io/qfile.cpp
../../corelib/io/qfiledevice.cpp
../../corelib/io/qfileinfo.cpp
@@ -36,23 +30,14 @@ qt_internal_extend_target(Bootstrap
../../corelib/io/qfsfileengine.cpp
../../corelib/io/qfsfileengine_iterator.cpp
../../corelib/io/qiodevice.cpp
- ../../corelib/io/qloggingcategory.cpp
- ../../corelib/io/qloggingregistry.cpp
- ../../corelib/io/qresource.cpp
- ../../corelib/io/qsavefile.cpp
../../corelib/io/qstandardpaths.cpp
- ../../corelib/io/qtemporaryfile.cpp
../../corelib/kernel/qcoreapplication.cpp
- ../../corelib/kernel/qiterable.cpp
- ../../corelib/kernel/qmetacontainer.cpp
../../corelib/kernel/qmetatype.cpp
../../corelib/kernel/qsystemerror.cpp
- ../../corelib/kernel/qvariant.cpp
../../corelib/plugin/quuid.cpp
../../corelib/serialization/qcborcommon.cpp
../../corelib/serialization/qcborstreamwriter.cpp
../../corelib/serialization/qcborvalue.cpp
- ../../corelib/serialization/qdatastream.cpp
../../corelib/serialization/qjsonarray.cpp
../../corelib/serialization/qjsoncbor.cpp
../../corelib/serialization/qjsondocument.cpp
@@ -80,13 +65,11 @@ qt_internal_extend_target(Bootstrap
../../corelib/time/qromancalendar.cpp
../../corelib/time/qtimezone.cpp
../../corelib/tools/qarraydata.cpp
- ../../corelib/tools/qbitarray.cpp
../../corelib/tools/qcommandlineoption.cpp
../../corelib/tools/qcommandlineparser.cpp
../../corelib/tools/qcryptographichash.cpp
../../corelib/tools/qhash.cpp
../../corelib/tools/qringbuffer.cpp
- ../../corelib/tools/qversionnumber.cpp
DEFINES
HAVE_CONFIG_H
QT_TYPESAFE_FLAGS
@@ -121,10 +104,15 @@ qt_internal_extend_target(Bootstrap CONDITION UNIX
../../corelib/io/qfsfileengine_unix.cpp
../../corelib/kernel/qcore_unix.cpp
)
+if(APPLE)
+ set_source_files_properties(../../corelib/io/qfilesystemengine_unix.cpp PROPERTIES LANGUAGE OBJCXX)
+ qt_internal_extend_target(Bootstrap CONDITION
+ PUBLIC_LIBRARIES ${FWUniformTypeIdentifiers}
+ )
+endif()
qt_internal_extend_target(Bootstrap CONDITION WIN32
SOURCES
- ../../corelib/global/qoperatingsystemversion_win.cpp
../../corelib/io/qfilesystemengine_win.cpp
../../corelib/io/qfilesystemiterator_win.cpp
../../corelib/io/qfsfileengine_win.cpp
@@ -143,10 +131,12 @@ qt_internal_extend_target(Bootstrap CONDITION WIN32
qt_internal_extend_target(Bootstrap CONDITION APPLE
SOURCES
+ ../../corelib/global/qoperatingsystemversion.cpp
../../corelib/global/qoperatingsystemversion_darwin.mm
../../corelib/kernel/qcore_foundation.mm
../../corelib/kernel/qcore_mac.mm
../../corelib/kernel/qcoreapplication_mac.cpp
+ ../../corelib/tools/qversionnumber.cpp
PUBLIC_LIBRARIES
${FWFoundation}
)
@@ -174,6 +164,7 @@ qt_internal_extend_target(Bootstrap CONDITION CMAKE_CROSSCOMPILING OR NOT QT_FEA
../../3rdparty/pcre2/src/pcre2.h
../../3rdparty/pcre2/src/pcre2_auto_possess.c
../../3rdparty/pcre2/src/pcre2_chartables.c
+ ../../3rdparty/pcre2/src/pcre2_chkdint.c
../../3rdparty/pcre2/src/pcre2_compile.c
../../3rdparty/pcre2/src/pcre2_config.c
../../3rdparty/pcre2/src/pcre2_context.c
diff --git a/src/tools/cmake_automoc_parser/CMakeLists.txt b/src/tools/cmake_automoc_parser/CMakeLists.txt
index 5822568877..a58c9c9ff1 100644
--- a/src/tools/cmake_automoc_parser/CMakeLists.txt
+++ b/src/tools/cmake_automoc_parser/CMakeLists.txt
@@ -8,6 +8,7 @@
qt_get_tool_target_name(target_name cmake_automoc_parser)
qt_internal_add_tool(${target_name}
CORE_LIBRARY Bootstrap
+ TARGET_DESCRIPTION "Qt CMake AUTOMOC Parser"
INSTALL_DIR "${INSTALL_LIBEXECDIR}"
TOOLS_TARGET Core
SOURCES
diff --git a/src/tools/cmake_automoc_parser/main.cpp b/src/tools/cmake_automoc_parser/main.cpp
index 86e10d48ad..de484b184b 100644
--- a/src/tools/cmake_automoc_parser/main.cpp
+++ b/src/tools/cmake_automoc_parser/main.cpp
@@ -185,11 +185,8 @@ static bool writeJsonFiles(const QList<QString> &fileList, const QString &fileLi
}
qint64 timestamp = std::numeric_limits<qint64>::min();
- QByteArray timestampBuffer = timestampFile.readAll();
- if (timestampBuffer.size() == sizeof(timestamp)) {
- QDataStream istream(&timestampBuffer, QIODevice::ReadOnly);
- istream >> timestamp;
- }
+ if (timestampFile.size() == sizeof(timestamp))
+ timestampFile.read(reinterpret_cast<char *>(&timestamp), sizeof(timestamp));
// Check if any of the metatype json files produced by automoc is newer than the last file
// processed by cmake_automoc parser
@@ -215,11 +212,8 @@ static bool writeJsonFiles(const QList<QString> &fileList, const QString &fileLi
textStream.flush();
// Update the timestamp according the newest json file timestamp.
- timestampBuffer.clear();
- QDataStream ostream(&timestampBuffer, QIODevice::WriteOnly);
- ostream << timestamp;
timestampFile.resize(0);
- timestampFile.write(timestampBuffer);
+ timestampFile.write(reinterpret_cast<char *>(&timestamp), sizeof(timestamp));
}
return true;
}
diff --git a/src/tools/configure.cmake b/src/tools/configure.cmake
index 2a198c899d..f813b727ba 100644
--- a/src/tools/configure.cmake
+++ b/src/tools/configure.cmake
@@ -12,12 +12,12 @@ qt_feature("macdeployqt" PRIVATE
LABEL "macOS deployment tool"
PURPOSE "The Mac deployment tool automates the process of creating a deployable application bundle that contains the Qt libraries as private frameworks."
AUTODETECT CMAKE_HOST_APPLE
- CONDITION MACOS)
+ CONDITION MACOS AND QT_FEATURE_thread)
qt_feature("windeployqt" PRIVATE
SECTION "Deployment"
LABEL "Windows deployment tool"
- PURPOSE "The Windows deployment tool is designed to automate the process of creating a deployable folder containing the Qt-related dependencies (libraries, QML imports, plugins, and translations) required to run the application from that folder. It creates a sandbox for Universal Windows Platform (UWP) or an installation tree for Windows desktop applications, which can be easily bundled into an installation package."
+ PURPOSE "The Windows deployment tool is designed to automate the process of creating a deployable folder containing the Qt-related dependencies (libraries, QML imports, plugins, and translations) required to run the application from that folder. The folder can be easily bundled into an installation package."
AUTODETECT CMAKE_HOST_WIN32
CONDITION WIN32)
diff --git a/src/tools/macdeployqt/macdeployqt/CMakeLists.txt b/src/tools/macdeployqt/macdeployqt/CMakeLists.txt
index 5c50fe7de0..6cd66adaa7 100644
--- a/src/tools/macdeployqt/macdeployqt/CMakeLists.txt
+++ b/src/tools/macdeployqt/macdeployqt/CMakeLists.txt
@@ -14,6 +14,8 @@ qt_internal_add_tool(${target_name}
SOURCES
../shared/shared.cpp
main.cpp
+ DEFINES
+ QT_NO_FOREACH
LIBRARIES
${FWCoreFoundation}
)
diff --git a/src/tools/macdeployqt/shared/shared.cpp b/src/tools/macdeployqt/shared/shared.cpp
index d4bfb4ce35..6ff269b36d 100644
--- a/src/tools/macdeployqt/shared/shared.cpp
+++ b/src/tools/macdeployqt/shared/shared.cpp
@@ -152,7 +152,7 @@ OtoolInfo findDependencyInfo(const QString &binaryPath)
LogDebug() << " inspecting" << binaryPath;
QProcess otool;
otool.start("otool", QStringList() << "-L" << binaryPath);
- otool.waitForFinished();
+ otool.waitForFinished(-1);
if (otool.exitStatus() != QProcess::NormalExit || otool.exitCode() != 0) {
LogError() << otool.readAllStandardError();
@@ -172,7 +172,7 @@ OtoolInfo findDependencyInfo(const QString &binaryPath)
outputLines.removeFirst(); // remove line containing the binary path
if (binaryPath.contains(".framework/") || binaryPath.endsWith(".dylib")) {
- const auto match = regexp.match(outputLines.first());
+ const auto match = regexp.match(outputLines.constFirst());
if (match.hasMatch()) {
QString installname = match.captured(1);
if (QFileInfo(binaryPath).fileName() == QFileInfo(installname).fileName()) {
@@ -184,7 +184,7 @@ OtoolInfo findDependencyInfo(const QString &binaryPath)
info.installName = binaryPath;
}
} else {
- LogDebug() << "Could not parse otool output line:" << outputLines.first();
+ LogDebug() << "Could not parse otool output line:" << outputLines.constFirst();
outputLines.removeFirst();
}
}
@@ -435,7 +435,7 @@ QStringList findAppLibraries(const QString &appBundlePath)
{
QStringList result;
// dylibs
- QDirIterator iter(appBundlePath, QStringList() << QString::fromLatin1("*.dylib"),
+ QDirIterator iter(appBundlePath, QStringList() << QString::fromLatin1("*.dylib") << QString::fromLatin1("*.so"),
QDir::Files | QDir::NoSymLinks, QDirIterator::Subdirectories);
while (iter.hasNext()) {
iter.next();
@@ -598,10 +598,14 @@ QStringList getBinaryDependencies(const QString executablePath,
QString binary = QDir::cleanPath(executablePath + trimmedLine.mid(QStringLiteral("@executable_path/").length()));
if (binary != path)
binaries.append(binary);
+ } else if (trimmedLine.startsWith("@loader_path/")) {
+ QString binary = QDir::cleanPath(QFileInfo(path).path() + "/" + trimmedLine.mid(QStringLiteral("@loader_path/").length()));
+ if (binary != path)
+ binaries.append(binary);
} else if (trimmedLine.startsWith("@rpath/")) {
if (!rpathsLoaded) {
rpaths = getBinaryRPaths(path, true, executablePath);
- foreach (const QString &binaryPath, additionalBinariesContainingRpaths)
+ for (const QString &binaryPath : additionalBinariesContainingRpaths)
rpaths += getBinaryRPaths(binaryPath, true);
rpaths.removeDuplicates();
rpathsLoaded = true;
@@ -630,15 +634,16 @@ QStringList getBinaryDependencies(const QString executablePath,
bool recursiveCopy(const QString &sourcePath, const QString &destinationPath,
const QRegularExpression &ignoreRegExp = QRegularExpression())
{
- if (!QDir(sourcePath).exists())
+ const QDir sourceDir(sourcePath);
+ if (!sourceDir.exists())
return false;
QDir().mkpath(destinationPath);
LogNormal() << "copy:" << sourcePath << destinationPath;
- QStringList files = QDir(sourcePath).entryList(QStringList() << "*", QDir::Files | QDir::NoDotAndDotDot);
+ const QStringList files = sourceDir.entryList(QStringList() << "*", QDir::Files | QDir::NoDotAndDotDot);
const bool hasValidRegExp = ignoreRegExp.isValid() && ignoreRegExp.pattern().length() > 0;
- foreach (QString file, files) {
+ for (const QString &file : files) {
if (hasValidRegExp && ignoreRegExp.match(file).hasMatch())
continue;
const QString fileSourcePath = sourcePath + "/" + file;
@@ -646,7 +651,7 @@ bool recursiveCopy(const QString &sourcePath, const QString &destinationPath,
copyFilePrintStatus(fileSourcePath, fileDestinationPath);
}
- QStringList subdirs = QDir(sourcePath).entryList(QStringList() << "*", QDir::Dirs | QDir::NoDotAndDotDot);
+ const QStringList subdirs = sourceDir.entryList(QStringList() << "*", QDir::Dirs | QDir::NoDotAndDotDot);
for (const QString &dir : subdirs) {
recursiveCopy(sourcePath + "/" + dir, destinationPath + "/" + dir);
}
@@ -660,7 +665,9 @@ void recursiveCopyAndDeploy(const QString &appBundlePath, const QList<QString> &
LogNormal() << "copy:" << sourcePath << destinationPath;
const bool isDwarfPath = sourcePath.endsWith("DWARF");
- QStringList files = QDir(sourcePath).entryList(QStringList() << QStringLiteral("*"), QDir::Files | QDir::NoDotAndDotDot);
+ const QDir sourceDir(sourcePath);
+
+ const QStringList files = sourceDir.entryList(QStringList() << QStringLiteral("*"), QDir::Files | QDir::NoDotAndDotDot);
for (const QString &file : files) {
const QString fileSourcePath = sourcePath + u'/' + file;
@@ -706,7 +713,7 @@ void recursiveCopyAndDeploy(const QString &appBundlePath, const QList<QString> &
}
}
- QStringList subdirs = QDir(sourcePath).entryList(QStringList() << QStringLiteral("*"), QDir::Dirs | QDir::NoDotAndDotDot);
+ const QStringList subdirs = sourceDir.entryList(QStringList() << QStringLiteral("*"), QDir::Dirs | QDir::NoDotAndDotDot);
for (const QString &dir : subdirs) {
recursiveCopyAndDeploy(appBundlePath, rpaths, sourcePath + u'/' + dir, destinationPath + u'/' + dir);
}
@@ -937,7 +944,10 @@ bool DeploymentInfo::containsModule(const QString &module, const QString &libInF
if (deployedFrameworks.contains("Qt"_L1 + module + libInFix + ".framework"_L1))
return true;
// Check for dylib
- const QRegularExpression dylibRegExp("libQt[0-9]+"_L1 + module + libInFix + ".[0-9]+.dylib"_L1);
+ const QRegularExpression dylibRegExp("libQt[0-9]+"_L1
+ + module + libInFix
+ + (isDebug ? "_debug" : "")
+ + ".[0-9]+.dylib"_L1);
return deployedFrameworks.filter(dylibRegExp).size() > 0;
}
diff --git a/src/tools/macdeployqt/shared/shared.h b/src/tools/macdeployqt/shared/shared.h
index 66c935539c..33384e868a 100644
--- a/src/tools/macdeployqt/shared/shared.h
+++ b/src/tools/macdeployqt/shared/shared.h
@@ -37,7 +37,10 @@ public:
bool isDebugLibrary() const
{
- return binaryName.endsWith(QStringLiteral("_debug"));
+ if (isDylib)
+ return binaryName.contains(QStringLiteral("_debug."));
+ else
+ return binaryName.endsWith(QStringLiteral("_debug"));
}
};
diff --git a/src/tools/moc/CMakeLists.txt b/src/tools/moc/CMakeLists.txt
index 4302992bad..b98b7ab4e9 100644
--- a/src/tools/moc/CMakeLists.txt
+++ b/src/tools/moc/CMakeLists.txt
@@ -7,6 +7,7 @@
qt_get_tool_target_name(target_name moc)
qt_internal_add_tool(${target_name}
+ TRY_RUN
CORE_LIBRARY Bootstrap
TARGET_DESCRIPTION "Qt Meta Object Compiler"
INSTALL_DIR "${INSTALL_LIBEXECDIR}"
@@ -20,7 +21,6 @@ qt_internal_add_tool(${target_name}
outputrevision.h
parser.cpp parser.h
preprocessor.cpp preprocessor.h
- # qdatetime_p.h special case remove
symbols.h
token.cpp token.h
utils.h
@@ -29,6 +29,8 @@ qt_internal_add_tool(${target_name}
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_FROM_BYTEARRAY
QT_NO_FOREACH
+ QT_NO_QPAIR
+ QT_USE_NODISCARD_FILE_OPEN
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR}
../../3rdparty/tinycbor/src
diff --git a/src/tools/moc/cbordevice.h b/src/tools/moc/cbordevice.h
index f221968911..7668e4c0be 100644
--- a/src/tools/moc/cbordevice.h
+++ b/src/tools/moc/cbordevice.h
@@ -4,6 +4,8 @@
#ifndef CBORDEVICE_H
#define CBORDEVICE_H
+#include <QtCore/qtypes.h>
+
#include <memory>
#include <stdio.h>
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp
index ca6a4181b6..1c6604a96e 100644
--- a/src/tools/moc/generator.cpp
+++ b/src/tools/moc/generator.cpp
@@ -23,6 +23,8 @@
QT_BEGIN_NAMESPACE
+using namespace QtMiscUtils;
+
uint nameToBuiltinType(const QByteArray &name)
{
if (name.isEmpty())
@@ -55,11 +57,12 @@ QT_FOR_EACH_STATIC_TYPE(RETURN_METATYPENAME_STRING)
return nullptr;
}
- Generator::Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes,
+ Generator::Generator(Moc *moc, ClassDef *classDef, const QList<QByteArray> &metaTypes,
const QHash<QByteArray, QByteArray> &knownQObjectClasses,
const QHash<QByteArray, QByteArray> &knownGadgets, FILE *outfile,
bool requireCompleteTypes)
- : out(outfile),
+ : parser(moc),
+ out(outfile),
cdef(classDef),
metaTypes(metaTypes),
knownQObjectClasses(knownQObjectClasses),
@@ -67,24 +70,24 @@ QT_FOR_EACH_STATIC_TYPE(RETURN_METATYPENAME_STRING)
requireCompleteTypes(requireCompleteTypes)
{
if (cdef->superclassList.size())
- purestSuperClass = cdef->superclassList.constFirst().first;
+ purestSuperClass = cdef->superclassList.constFirst().classname;
}
-static inline int lengthOfEscapeSequence(const QByteArray &s, int i)
+static inline qsizetype lengthOfEscapeSequence(const QByteArray &s, qsizetype i)
{
if (s.at(i) != '\\' || i >= s.size() - 1)
return 1;
- const int startPos = i;
+ const qsizetype startPos = i;
++i;
char ch = s.at(i);
if (ch == 'x') {
++i;
- while (i < s.size() && is_hex_char(s.at(i)))
+ while (i < s.size() && isHexDigit(s.at(i)))
++i;
- } else if (is_octal_char(ch)) {
+ } else if (isOctalDigit(ch)) {
while (i < startPos + 4
&& i < s.size()
- && is_octal_char(s.at(i))) {
+ && isOctalDigit(s.at(i))) {
++i;
}
} else { // single character escape sequence
@@ -93,36 +96,23 @@ static inline int lengthOfEscapeSequence(const QByteArray &s, int i)
return i - startPos;
}
-static inline uint lengthOfEscapedString(const QByteArray &str)
-{
- int extra = 0;
- for (int j = 0; j < str.size(); ++j) {
- if (str.at(j) == '\\') {
- int cnt = lengthOfEscapeSequence(str, j) - 1;
- extra += cnt;
- j += cnt;
- }
- }
- return str.size() - extra;
-}
-
// Prints \a s to \a out, breaking it into lines of at most ColumnWidth. The
// opening and closing quotes are NOT included (it's up to the caller).
static void printStringWithIndentation(FILE *out, const QByteArray &s)
{
static constexpr int ColumnWidth = 72;
- int len = s.size();
- int idx = 0;
+ const qsizetype len = s.size();
+ qsizetype idx = 0;
do {
- int spanLen = qMin(ColumnWidth - 2, len - idx);
+ qsizetype spanLen = qMin(ColumnWidth - 2, len - idx);
// don't cut escape sequences at the end of a line
- int backSlashPos = s.lastIndexOf('\\', idx + spanLen - 1);
+ const qsizetype backSlashPos = s.lastIndexOf('\\', idx + spanLen - 1);
if (backSlashPos >= idx) {
- int escapeLen = lengthOfEscapeSequence(s, backSlashPos);
+ const qsizetype escapeLen = lengthOfEscapeSequence(s, backSlashPos);
spanLen = qBound(spanLen, backSlashPos + escapeLen - idx, len - idx);
}
- fprintf(out, "\n \"%.*s\"", spanLen, s.constData() + idx);
+ fprintf(out, "\n \"%.*s\"", int(spanLen), s.constData() + idx);
idx += spanLen;
} while (idx < len);
}
@@ -135,7 +125,7 @@ void Generator::strreg(const QByteArray &s)
int Generator::stridx(const QByteArray &s)
{
- int i = strings.indexOf(s);
+ int i = int(strings.indexOf(s));
Q_ASSERT_X(i != -1, Q_FUNC_INFO, "We forgot to register some strings");
return i;
}
@@ -146,8 +136,8 @@ int Generator::stridx(const QByteArray &s)
static int aggregateParameterCount(const QList<FunctionDef> &list)
{
int sum = 0;
- for (int i = 0; i < list.size(); ++i)
- sum += list.at(i).arguments.size() + 1; // +1 for return type
+ for (const FunctionDef &def : list)
+ sum += int(def.arguments.size()) + 1; // +1 for return type
return sum;
}
@@ -184,14 +174,14 @@ bool Generator::registerableMetaType(const QByteArray &propertyType)
#undef STREAM_1ARG_TEMPLATE
;
for (const QByteArray &oneArgTemplateType : oneArgTemplates) {
- QByteArray ba = oneArgTemplateType + "<";
+ const QByteArray ba = oneArgTemplateType + "<";
if (propertyType.startsWith(ba) && propertyType.endsWith(">")) {
- const int argumentSize = propertyType.size() - oneArgTemplateType.size() - 1
+ const qsizetype argumentSize = propertyType.size() - ba.size()
// The closing '>'
- 1
// templates inside templates have an extra whitespace char to strip.
- (propertyType.at(propertyType.size() - 2) == ' ' ? 1 : 0 );
- const QByteArray templateArg = propertyType.mid(oneArgTemplateType.size() + 1, argumentSize);
+ const QByteArray templateArg = propertyType.sliced(ba.size(), argumentSize);
return isBuiltinType(templateArg) || registerableMetaType(templateArg);
}
}
@@ -204,7 +194,7 @@ static bool qualifiedNameEquals(const QByteArray &qualifiedName, const QByteArra
{
if (qualifiedName == name)
return true;
- int index = qualifiedName.indexOf("::");
+ const qsizetype index = qualifiedName.indexOf("::");
if (index == -1)
return false;
return qualifiedNameEquals(qualifiedName.mid(index+2), name);
@@ -234,8 +224,7 @@ void Generator::generateCode()
// filter out undeclared enumerators and sets
{
QList<EnumDef> enumList;
- for (int i = 0; i < cdef->enumList.size(); ++i) {
- EnumDef def = cdef->enumList.at(i);
+ for (EnumDef def : std::as_const(cdef->enumList)) {
if (cdef->enumDeclarations.contains(def.name)) {
enumList += def;
}
@@ -277,7 +266,7 @@ void Generator::generateCode()
fprintf(out, "\n#ifdef QT_MOC_HAS_STRINGDATA\n"
"struct qt_meta_stringdata_%s_t {};\n"
- "static constexpr auto qt_meta_stringdata_%s = QtMocHelpers::stringData(",
+ "constexpr auto qt_meta_stringdata_%s = QtMocHelpers::stringData(",
qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData());
{
char comma = 0;
@@ -289,61 +278,9 @@ void Generator::generateCode()
}
}
fprintf(out, "\n);\n"
- "#else // !QT_MOC_HAS_STRING_DATA\n");
-
-#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
+ "#else // !QT_MOC_HAS_STRINGDATA\n");
fprintf(out, "#error \"qtmochelpers.h not found or too old.\"\n");
-#else
-//
-// Build stringdata struct
-//
-
- fprintf(out, "struct qt_meta_stringdata_%s_t {\n", qualifiedClassNameIdentifier.constData());
- fprintf(out, " uint offsetsAndSizes[%d];\n", int(strings.size() * 2));
- for (int i = 0; i < strings.size(); ++i) {
- int thisLength = lengthOfEscapedString(strings.at(i)) + 1;
- fprintf(out, " char stringdata%d[%d];\n", i, thisLength);
- }
- fprintf(out, "};\n");
-
- // Macro that simplifies the string data listing. The offset is calculated
- // from the top of the stringdata object (i.e., past the uints).
- fprintf(out, "#define QT_MOC_LITERAL(ofs, len) \\\n"
- " uint(sizeof(qt_meta_stringdata_%s_t::offsetsAndSizes) + ofs), len \n",
- qualifiedClassNameIdentifier.constData());
-
- fprintf(out, "Q_CONSTINIT static const qt_meta_stringdata_%s_t qt_meta_stringdata_%s = {\n",
- qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData());
- fprintf(out, " {");
- {
- int idx = 0;
- for (int i = 0; i < strings.size(); ++i) {
- const QByteArray &str = strings.at(i);
- const QByteArray comment = str.size() > 32 ? str.left(29) + "..." : str;
- const char *comma = (i != strings.size() - 1 ? "," : " ");
- int len = lengthOfEscapedString(str);
- fprintf(out, "\n QT_MOC_LITERAL(%d, %d)%s // \"%s\"", idx, len, comma,
- comment.constData());
-
- idx += len + 1;
- }
- fprintf(out, "\n }");
- }
-
-//
-// Build stringdata arrays
-//
- for (const QByteArray &s : std::as_const(strings)) {
- fputc(',', out);
- printStringWithIndentation(out, s);
- }
-
-// Terminate stringdata struct
- fprintf(out, "\n};\n");
- fprintf(out, "#undef QT_MOC_LITERAL\n");
-#endif // Qt 6.9
-
- fprintf(out, "#endif // !QT_MOC_HAS_STRING_DATA\n");
+ fprintf(out, "#endif // !QT_MOC_HAS_STRINGDATA\n");
fprintf(out, "} // unnamed namespace\n\n");
//
@@ -358,8 +295,14 @@ void Generator::generateCode()
fprintf(out, " %4d, %4d, // classinfo\n", int(cdef->classInfoList.size()), int(cdef->classInfoList.size() ? index : 0));
index += cdef->classInfoList.size() * 2;
- int methodCount = cdef->signalList.size() + cdef->slotList.size() + cdef->methodList.size();
- fprintf(out, " %4d, %4d, // methods\n", methodCount, methodCount ? index : 0);
+ qsizetype methodCount = 0;
+ if (qAddOverflow(cdef->signalList.size(), cdef->slotList.size(), &methodCount)
+ || qAddOverflow(cdef->methodList.size(), methodCount, &methodCount)) {
+ parser->error("internal limit exceeded: the total number of member functions"
+ " (including signals and slots) is too big.");
+ }
+
+ fprintf(out, " %4" PRIdQSIZETYPE ", %4d, // methods\n", methodCount, methodCount ? index : 0);
index += methodCount * QMetaObjectPrivate::IntsPerMethod;
if (cdef->revisionedMethods)
index += methodCount;
@@ -370,15 +313,16 @@ void Generator::generateCode()
+ aggregateParameterCount(cdef->constructorList);
index += totalParameterCount * 2 // types and parameter names
- methodCount // return "parameters" don't have names
- - cdef->constructorList.size(); // "this" parameters don't have names
+ - int(cdef->constructorList.size()); // "this" parameters don't have names
fprintf(out, " %4d, %4d, // properties\n", int(cdef->propertyList.size()), int(cdef->propertyList.size() ? index : 0));
index += cdef->propertyList.size() * QMetaObjectPrivate::IntsPerProperty;
fprintf(out, " %4d, %4d, // enums/sets\n", int(cdef->enumList.size()), cdef->enumList.size() ? index : 0);
int enumsIndex = index;
- for (int i = 0; i < cdef->enumList.size(); ++i)
- index += 5 + (cdef->enumList.at(i).values.size() * 2);
+ for (const EnumDef &def : std::as_const(cdef->enumList))
+ index += QMetaObjectPrivate::IntsPerEnum + (def.values.size() * 2);
+
fprintf(out, " %4d, %4d, // constructors\n", isConstructible ? int(cdef->constructorList.size()) : 0,
isConstructible ? index : 0);
@@ -397,8 +341,14 @@ void Generator::generateCode()
//
generateClassInfos();
- // all property metatypes, + 1 for the type of the current class itself
- int initialMetaTypeOffset = cdef->propertyList.size() + 1;
+ qsizetype propEnumCount = 0;
+ // all property metatypes + all enum metatypes + 1 for the type of the current class itself
+ if (qAddOverflow(cdef->propertyList.size(), cdef->enumList.size(), &propEnumCount)
+ || qAddOverflow(propEnumCount, qsizetype(1), &propEnumCount)
+ || propEnumCount >= std::numeric_limits<int>::max()) {
+ parser->error("internal limit exceeded: number of property and enum metatypes is too big.");
+ }
+ int initialMetaTypeOffset = int(propEnumCount);
//
// Build signals array first, otherwise the signal indices would be wrong
@@ -461,15 +411,14 @@ void Generator::generateCode()
QMultiHash<QByteArray, QByteArray> knownExtraMetaObject(knownGadgets);
knownExtraMetaObject.unite(knownQObjectClasses);
- for (int i = 0; i < cdef->propertyList.size(); ++i) {
- const PropertyDef &p = cdef->propertyList.at(i);
+ for (const PropertyDef &p : std::as_const(cdef->propertyList)) {
if (isBuiltinType(p.type))
continue;
if (p.type.contains('*') || p.type.contains('<') || p.type.contains('>'))
continue;
- int s = p.type.lastIndexOf("::");
+ const qsizetype s = p.type.lastIndexOf("::");
if (s <= 0)
continue;
@@ -480,7 +429,7 @@ void Generator::generateCode()
QByteArray thisScope = cdef->qualified;
do {
- int s = thisScope.lastIndexOf("::");
+ const qsizetype s = thisScope.lastIndexOf("::");
thisScope = thisScope.left(s);
QByteArray currentScope = thisScope.isEmpty() ? unqualifiedScope : thisScope + "::" + unqualifiedScope;
scopeIt = knownExtraMetaObject.constFind(currentScope);
@@ -506,7 +455,7 @@ void Generator::generateCode()
for (auto it = cdef->enumDeclarations.keyBegin(),
end = cdef->enumDeclarations.keyEnd(); it != end; ++it) {
const QByteArray &enumKey = *it;
- int s = enumKey.lastIndexOf("::");
+ const qsizetype s = enumKey.lastIndexOf("::");
if (s > 0) {
QByteArray scope = enumKey.left(s);
if (scope != "Qt" && !qualifiedNameEquals(cdef->qualified, scope) && !extraList.contains(scope))
@@ -521,9 +470,9 @@ void Generator::generateCode()
if (!extraList.isEmpty()) {
fprintf(out, "Q_CONSTINIT static const QMetaObject::SuperData qt_meta_extradata_%s[] = {\n",
qualifiedClassNameIdentifier.constData());
- for (int i = 0; i < extraList.size(); ++i) {
- fprintf(out, " QMetaObject::SuperData::link<%s::staticMetaObject>(),\n", extraList.at(i).constData());
- }
+ for (const QByteArray &ba : std::as_const(extraList))
+ fprintf(out, " QMetaObject::SuperData::link<%s::staticMetaObject>(),\n", ba.constData());
+
fprintf(out, " nullptr\n};\n\n");
}
@@ -569,13 +518,19 @@ void Generator::generateCode()
fprintf(out, " qt_metaTypeArray<");
}
// metatypes for properties
- for (int i = 0; i < cdef->propertyList.size(); ++i) {
- const PropertyDef &p = cdef->propertyList.at(i);
+ for (const PropertyDef &p : std::as_const(cdef->propertyList)) {
fprintf(out, "%s\n // property '%s'\n %s",
comma, p.name.constData(), stringForType(p.type, true).constData());
comma = ",";
}
+ // metatypes for enums
+ for (const EnumDef &e : std::as_const(cdef->enumList)) {
+ fprintf(out, "%s\n // enum '%s'\n %s",
+ comma, e.name.constData(), stringForType(e.qualifiedType(cdef), true).constData());
+ comma = ",";
+ }
+
// type name for the Q_OJBECT/GADGET itself, void for namespaces
auto ownType = !cdef->hasQNamespace ? cdef->classname.data() : "void";
fprintf(out, "%s\n // Q_OBJECT / Q_GADGET\n %s",
@@ -584,10 +539,9 @@ void Generator::generateCode()
// metatypes for all exposed methods
// because we definitely printed something above, this section doesn't need comma control
- for (const QList<FunctionDef> &methodContainer :
- { cdef->signalList, cdef->slotList, cdef->methodList }) {
- for (int i = 0; i< methodContainer.size(); ++i) {
- const FunctionDef& fdef = methodContainer.at(i);
+ const auto allMethods = {&cdef->signalList, &cdef->slotList, &cdef->methodList};
+ for (const QList<FunctionDef> *methodContainer : allMethods) {
+ for (const FunctionDef &fdef : *methodContainer) {
fprintf(out, ",\n // method '%s'\n %s",
fdef.name.constData(), stringForType(fdef.type.name, false).constData());
for (const auto &argument: fdef.arguments)
@@ -596,8 +550,7 @@ void Generator::generateCode()
}
// but constructors have no return types, so this needs comma control again
- for (int i = 0; i< cdef->constructorList.size(); ++i) {
- const FunctionDef& fdef = cdef->constructorList.at(i);
+ for (const FunctionDef &fdef : std::as_const(cdef->constructorList)) {
if (fdef.arguments.isEmpty())
continue;
@@ -634,18 +587,24 @@ void Generator::generateCode()
fprintf(out, " if (!strcmp(_clname, qt_meta_stringdata_%s.stringdata0))\n"
" return static_cast<void*>(this);\n",
qualifiedClassNameIdentifier.constData());
- for (int i = 1; i < cdef->superclassList.size(); ++i) { // for all superclasses but the first one
- if (cdef->superclassList.at(i).second == FunctionDef::Private)
- continue;
- const char *cname = cdef->superclassList.at(i).first.constData();
- fprintf(out, " if (!strcmp(_clname, \"%s\"))\n return static_cast< %s*>(this);\n",
- cname, cname);
+
+ // for all superclasses but the first one
+ if (cdef->superclassList.size() > 1) {
+ auto it = cdef->superclassList.cbegin() + 1;
+ const auto end = cdef->superclassList.cend();
+ for (; it != end; ++it) {
+ if (it->access == FunctionDef::Private)
+ continue;
+ const char *cname = it->classname.constData();
+ fprintf(out, " if (!strcmp(_clname, \"%s\"))\n return static_cast< %s*>(this);\n",
+ cname, cname);
+ }
}
- for (int i = 0; i < cdef->interfaceList.size(); ++i) {
- const QList<ClassDef::Interface> &iface = cdef->interfaceList.at(i);
- for (int j = 0; j < iface.size(); ++j) {
+
+ for (const QList<ClassDef::Interface> &iface : std::as_const(cdef->interfaceList)) {
+ for (qsizetype j = 0; j < iface.size(); ++j) {
fprintf(out, " if (!strcmp(_clname, %s))\n return ", iface.at(j).interfaceId.constData());
- for (int k = j; k >= 0; --k)
+ for (qsizetype k = j; k >= 0; --k)
fprintf(out, "static_cast< %s*>(", iface.at(k).className.constData());
fprintf(out, "this%s;\n", QByteArray(j + 1, ')').constData());
}
@@ -666,8 +625,8 @@ void Generator::generateCode()
//
// Generate internal signal functions
//
- for (int signalindex = 0; signalindex < cdef->signalList.size(); ++signalindex)
- generateSignal(&cdef->signalList[signalindex], signalindex);
+ for (int signalindex = 0; signalindex < int(cdef->signalList.size()); ++signalindex)
+ generateSignal(&cdef->signalList.at(signalindex), signalindex);
//
// Generate plugin meta data
@@ -678,12 +637,29 @@ void Generator::generateCode()
// Generate function to make sure the non-class signals exist in the parent classes
//
if (!cdef->nonClassSignalList.isEmpty()) {
- fprintf(out, "// If you get a compile error in this function it can be because either\n");
- fprintf(out, "// a) You are using a NOTIFY signal that does not exist. Fix it.\n");
- fprintf(out, "// b) You are using a NOTIFY signal that does exist (in a parent class) but has a non-empty parameter list. This is a moc limitation.\n");
- fprintf(out, "[[maybe_unused]] static void checkNotifySignalValidity_%s(%s *t) {\n", qualifiedClassNameIdentifier.constData(), cdef->qualified.constData());
- for (const QByteArray &nonClassSignal : std::as_const(cdef->nonClassSignalList))
- fprintf(out, " t->%s();\n", nonClassSignal.constData());
+ fprintf(out, "namespace CheckNotifySignalValidity_%s {\n", qualifiedClassNameIdentifier.constData());
+ for (const QByteArray &nonClassSignal : std::as_const(cdef->nonClassSignalList)) {
+ const auto propertyIt = std::find_if(cdef->propertyList.constBegin(),
+ cdef->propertyList.constEnd(),
+ [&nonClassSignal](const PropertyDef &p) {
+ return nonClassSignal == p.notify;
+ });
+ // must find something, otherwise checkProperties wouldn't have inserted an entry into nonClassSignalList
+ Q_ASSERT(propertyIt != cdef->propertyList.constEnd());
+ fprintf(out, "template<typename T> using has_nullary_%s = decltype(std::declval<T>().%s());\n",
+ nonClassSignal.constData(),
+ nonClassSignal.constData());
+ const auto &propertyType = propertyIt->type;
+ fprintf(out, "template<typename T> using has_unary_%s = decltype(std::declval<T>().%s(std::declval<%s>()));\n",
+ nonClassSignal.constData(),
+ nonClassSignal.constData(),
+ propertyType.constData());
+ fprintf(out, "static_assert(qxp::is_detected_v<has_nullary_%s, %s> || qxp::is_detected_v<has_unary_%s, %s>,\n"
+ " \"NOTIFY signal %s does not exist in class (or is private in its parent)\");\n",
+ nonClassSignal.constData(), cdef->qualified.constData(),
+ nonClassSignal.constData(), cdef->qualified.constData(),
+ nonClassSignal.constData());
+ }
fprintf(out, "}\n");
}
}
@@ -691,8 +667,7 @@ void Generator::generateCode()
void Generator::registerClassInfoStrings()
{
- for (int i = 0; i < cdef->classInfoList.size(); ++i) {
- const ClassInfoDef &c = cdef->classInfoList.at(i);
+ for (const ClassInfoDef &c : std::as_const(cdef->classInfoList)) {
strreg(c.name);
strreg(c.value);
}
@@ -705,25 +680,19 @@ void Generator::generateClassInfos()
fprintf(out, "\n // classinfo: key, value\n");
- for (int i = 0; i < cdef->classInfoList.size(); ++i) {
- const ClassInfoDef &c = cdef->classInfoList.at(i);
+ for (const ClassInfoDef &c : std::as_const(cdef->classInfoList))
fprintf(out, " %4d, %4d,\n", stridx(c.name), stridx(c.value));
- }
}
void Generator::registerFunctionStrings(const QList<FunctionDef> &list)
{
- for (int i = 0; i < list.size(); ++i) {
- const FunctionDef &f = list.at(i);
-
+ for (const FunctionDef &f : list) {
strreg(f.name);
if (!isBuiltinType(f.normalizedType))
strreg(f.normalizedType);
strreg(f.tag);
- int argsCount = f.arguments.size();
- for (int j = 0; j < argsCount; ++j) {
- const ArgumentDef &a = f.arguments.at(j);
+ for (const ArgumentDef &a : f.arguments) {
if (!isBuiltinType(a.normalizedType))
strreg(a.normalizedType);
strreg(a.name);
@@ -744,9 +713,7 @@ void Generator::generateFunctions(const QList<FunctionDef> &list, const char *fu
return;
fprintf(out, "\n // %ss: name, argc, parameters, tag, flags, initial metatype offsets\n", functype);
- for (int i = 0; i < list.size(); ++i) {
- const FunctionDef &f = list.at(i);
-
+ for (const FunctionDef &f : list) {
QByteArray comment;
uint flags = type;
if (f.access == FunctionDef::Private) {
@@ -781,7 +748,7 @@ void Generator::generateFunctions(const QList<FunctionDef> &list, const char *fu
comment.append(" | MethodIsConst ");
}
- int argc = f.arguments.size();
+ const int argc = int(f.arguments.size());
fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x, %4d /* %s */,\n",
stridx(f.name), argc, paramsIndex, stridx(f.tag), flags, initialMetatypeOffset, comment.constData());
@@ -795,10 +762,8 @@ void Generator::generateFunctionRevisions(const QList<FunctionDef> &list, const
{
if (list.size())
fprintf(out, "\n // %ss: revision\n", functype);
- for (int i = 0; i < list.size(); ++i) {
- const FunctionDef &f = list.at(i);
+ for (const FunctionDef &f : list)
fprintf(out, " %4d,\n", f.revision);
- }
}
void Generator::generateFunctionParameters(const QList<FunctionDef> &list, const char *functype)
@@ -806,25 +771,22 @@ void Generator::generateFunctionParameters(const QList<FunctionDef> &list, const
if (list.isEmpty())
return;
fprintf(out, "\n // %ss: parameters\n", functype);
- for (int i = 0; i < list.size(); ++i) {
- const FunctionDef &f = list.at(i);
+ for (const FunctionDef &f : list) {
fprintf(out, " ");
// Types
- int argsCount = f.arguments.size();
- for (int j = -1; j < argsCount; ++j) {
- if (j > -1)
- fputc(' ', out);
- const QByteArray &typeName = (j < 0) ? f.normalizedType : f.arguments.at(j).normalizedType;
- generateTypeInfo(typeName, /*allowEmptyName=*/f.isConstructor);
+ const bool allowEmptyName = f.isConstructor;
+ generateTypeInfo(f.normalizedType, allowEmptyName);
+ fputc(',', out);
+ for (const ArgumentDef &arg : f.arguments) {
+ fputc(' ', out);
+ generateTypeInfo(arg.normalizedType, allowEmptyName);
fputc(',', out);
}
// Parameter names
- for (int j = 0; j < argsCount; ++j) {
- const ArgumentDef &arg = f.arguments.at(j);
+ for (const ArgumentDef &arg : f.arguments)
fprintf(out, " %4d,", stridx(arg.name));
- }
fprintf(out, "\n");
}
@@ -857,8 +819,7 @@ void Generator::generateTypeInfo(const QByteArray &typeName, bool allowEmptyName
void Generator::registerPropertyStrings()
{
- for (int i = 0; i < cdef->propertyList.size(); ++i) {
- const PropertyDef &p = cdef->propertyList.at(i);
+ for (const PropertyDef &p : std::as_const(cdef->propertyList)) {
strreg(p.name);
if (!isBuiltinType(p.type))
strreg(p.type);
@@ -872,9 +833,8 @@ void Generator::generateProperties()
//
if (cdef->propertyList.size())
- fprintf(out, "\n // properties: name, type, flags\n");
- for (int i = 0; i < cdef->propertyList.size(); ++i) {
- const PropertyDef &p = cdef->propertyList.at(i);
+ fprintf(out, "\n // properties: name, type, flags, notifyId, revision\n");
+ for (const PropertyDef &p : std::as_const(cdef->propertyList)) {
uint flags = Invalid;
if (!isBuiltinType(p.type))
flags |= EnumOrFlag;
@@ -918,7 +878,7 @@ void Generator::generateProperties()
int notifyId = p.notifyId;
if (p.notifyId < -1) {
// signal is in parent class
- const int indexInStrings = strings.indexOf(p.notify);
+ const int indexInStrings = int(strings.indexOf(p.notify));
notifyId = indexInStrings | IsUnresolvedSignal;
}
fprintf(out, ", 0x%.8x, uint(%d), %d,\n", flags, notifyId, p.revision);
@@ -927,13 +887,12 @@ void Generator::generateProperties()
void Generator::registerEnumStrings()
{
- for (int i = 0; i < cdef->enumList.size(); ++i) {
- const EnumDef &e = cdef->enumList.at(i);
+ for (const EnumDef &e : std::as_const(cdef->enumList)) {
strreg(e.name);
if (!e.enumName.isNull())
strreg(e.enumName);
- for (int j = 0; j < e.values.size(); ++j)
- strreg(e.values.at(j));
+ for (const QByteArray &val : e.values)
+ strreg(val);
}
}
@@ -943,7 +902,7 @@ void Generator::generateEnums(int index)
return;
fprintf(out, "\n // enums: name, alias, flags, count, data\n");
- index += 5 * cdef->enumList.size();
+ index += QMetaObjectPrivate::IntsPerEnum * cdef->enumList.size();
int i;
for (i = 0; i < cdef->enumList.size(); ++i) {
const EnumDef &e = cdef->enumList.at(i);
@@ -962,10 +921,8 @@ void Generator::generateEnums(int index)
}
fprintf(out, "\n // enum data: key, value\n");
- for (i = 0; i < cdef->enumList.size(); ++i) {
- const EnumDef &e = cdef->enumList.at(i);
- for (int j = 0; j < e.values.size(); ++j) {
- const QByteArray &val = e.values.at(j);
+ for (const EnumDef &e : std::as_const(cdef->enumList)) {
+ for (const QByteArray &val : e.values) {
QByteArray code = cdef->qualified.constData();
if (e.isEnumClass)
code += "::" + (e.enumName.isNull() ? e.name : e.enumName);
@@ -1042,7 +999,7 @@ void Generator::generateMetacall()
QMultiMap<QByteArray, int> Generator::automaticPropertyMetaTypesHelper()
{
QMultiMap<QByteArray, int> automaticPropertyMetaTypes;
- for (int i = 0; i < cdef->propertyList.size(); ++i) {
+ for (int i = 0; i < int(cdef->propertyList.size()); ++i) {
const QByteArray propertyType = cdef->propertyList.at(i).type;
if (registerableMetaType(propertyType) && !isBuiltinType(propertyType))
automaticPropertyMetaTypes.insert(propertyType, i);
@@ -1078,10 +1035,11 @@ void Generator::generateStaticMetacall()
Q_ASSERT(!f.isPrivateSignal); // That would be a strange ctor indeed
int offset = 1;
- int argsCount = f.arguments.size();
- for (int j = 0; j < argsCount; ++j) {
- const ArgumentDef &a = f.arguments.at(j);
- if (j)
+ const auto begin = f.arguments.cbegin();
+ const auto end = f.arguments.cend();
+ for (auto it = begin; it != end; ++it) {
+ const ArgumentDef &a = *it;
+ if (it != begin)
fprintf(out, ",");
fprintf(out, "(*reinterpret_cast<%s>(_a[%d]))",
a.typeNameForCast.constData(), offset++);
@@ -1091,7 +1049,7 @@ void Generator::generateStaticMetacall()
if (!cdef->constructorList.isEmpty()) {
fprintf(out, " if (_c == QMetaObject::CreateInstance) {\n");
fprintf(out, " switch (_id) {\n");
- const int ctorend = cdef->constructorList.size();
+ const int ctorend = int(cdef->constructorList.size());
for (int ctorindex = 0; ctorindex < ctorend; ++ctorindex) {
fprintf(out, " case %d: { %s *_r = new %s(", ctorindex,
cdef->classname.constData(), cdef->classname.constData());
@@ -1153,16 +1111,17 @@ void Generator::generateStaticMetacall()
if (f.isRawSlot) {
fprintf(out, "QMethodRawArguments{ _a }");
} else {
- int argsCount = f.arguments.size();
- for (int j = 0; j < argsCount; ++j) {
- const ArgumentDef &a = f.arguments.at(j);
- if (j)
+ const auto begin = f.arguments.cbegin();
+ const auto end = f.arguments.cend();
+ for (auto it = begin; it != end; ++it) {
+ const ArgumentDef &a = *it;
+ if (it != begin)
fprintf(out, ",");
fprintf(out, "(*reinterpret_cast< %s>(_a[%d]))",a.typeNameForCast.constData(), offset++);
isUsed_a = true;
}
if (f.isPrivateSignal) {
- if (argsCount > 0)
+ if (!f.arguments.isEmpty())
fprintf(out, ", ");
fprintf(out, "%s", "QPrivateSignal()");
}
@@ -1215,7 +1174,7 @@ void Generator::generateStaticMetacall()
fprintf(out, " else if (_c == QMetaObject::IndexOfMethod) {\n");
fprintf(out, " int *result = reinterpret_cast<int *>(_a[0]);\n");
bool anythingUsed = false;
- for (int methodindex = 0; methodindex < cdef->signalList.size(); ++methodindex) {
+ for (int methodindex = 0; methodindex < int(cdef->signalList.size()); ++methodindex) {
const FunctionDef &f = cdef->signalList.at(methodindex);
if (f.wasCloned || !f.inPrivateClass.isEmpty() || f.isStatic)
continue;
@@ -1223,15 +1182,16 @@ void Generator::generateStaticMetacall()
fprintf(out, " {\n");
fprintf(out, " using _t = %s (%s::*)(",f.type.rawName.constData() , cdef->classname.constData());
- int argsCount = f.arguments.size();
- for (int j = 0; j < argsCount; ++j) {
- const ArgumentDef &a = f.arguments.at(j);
- if (j)
+ const auto begin = f.arguments.cbegin();
+ const auto end = f.arguments.cend();
+ for (auto it = begin; it != end; ++it) {
+ const ArgumentDef &a = *it;
+ if (it != begin)
fprintf(out, ", ");
fprintf(out, "%s", QByteArray(a.type.name + ' ' + a.rightType).constData());
}
if (f.isPrivateSignal) {
- if (argsCount > 0)
+ if (!f.arguments.isEmpty())
fprintf(out, ", ");
fprintf(out, "%s", "QPrivateSignal");
}
@@ -1282,8 +1242,7 @@ void Generator::generateStaticMetacall()
bool needSet = false;
bool needReset = false;
bool hasBindableProperties = false;
- for (int i = 0; i < cdef->propertyList.size(); ++i) {
- const PropertyDef &p = cdef->propertyList.at(i);
+ for (const PropertyDef &p : std::as_const(cdef->propertyList)) {
needGet |= !p.read.isEmpty() || !p.member.isEmpty();
if (!p.read.isEmpty() || !p.member.isEmpty())
needTempVarForGet |= (p.gspec != PropertyDef::PointerSpec
@@ -1314,7 +1273,7 @@ void Generator::generateStaticMetacall()
if (needTempVarForGet)
fprintf(out, " void *_v = _a[0];\n");
fprintf(out, " switch (_id) {\n");
- for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
+ for (int propindex = 0; propindex < int(cdef->propertyList.size()); ++propindex) {
const PropertyDef &p = cdef->propertyList.at(propindex);
if (p.read.isEmpty() && p.member.isEmpty())
continue;
@@ -1355,7 +1314,7 @@ void Generator::generateStaticMetacall()
setupMemberAccess();
fprintf(out, " void *_v = _a[0];\n");
fprintf(out, " switch (_id) {\n");
- for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
+ for (int propindex = 0; propindex < int(cdef->propertyList.size()); ++propindex) {
const PropertyDef &p = cdef->propertyList.at(propindex);
if (p.constant)
continue;
@@ -1408,7 +1367,7 @@ void Generator::generateStaticMetacall()
if (needReset) {
setupMemberAccess();
fprintf(out, " switch (_id) {\n");
- for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
+ for (int propindex = 0; propindex < int(cdef->propertyList.size()); ++propindex) {
const PropertyDef &p = cdef->propertyList.at(propindex);
if (p.reset.isEmpty())
continue;
@@ -1429,7 +1388,7 @@ void Generator::generateStaticMetacall()
if (hasBindableProperties) {
setupMemberAccess();
fprintf(out, " switch (_id) {\n");
- for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
+ for (int propindex = 0; propindex < int(cdef->propertyList.size()); ++propindex) {
const PropertyDef &p = cdef->propertyList.at(propindex);
if (p.bind.isEmpty())
continue;
@@ -1465,7 +1424,7 @@ void Generator::generateStaticMetacall()
fprintf(out, "}\n");
}
-void Generator::generateSignal(FunctionDef *def,int index)
+void Generator::generateSignal(const FunctionDef *def, int index)
{
if (def->wasCloned || def->isAbstract)
return;
@@ -1489,9 +1448,11 @@ void Generator::generateSignal(FunctionDef *def,int index)
}
int offset = 1;
- for (int j = 0; j < def->arguments.size(); ++j) {
- const ArgumentDef &a = def->arguments.at(j);
- if (j)
+ const auto begin = def->arguments.cbegin();
+ const auto end = def->arguments.cend();
+ for (auto it = begin; it != end; ++it) {
+ const ArgumentDef &a = *it;
+ if (it != begin)
fputs(", ", out);
if (a.type.name.size())
fputs(a.type.name.constData(), out);
@@ -1633,7 +1594,7 @@ void Generator::generatePluginMetaData()
};
// 'Use' all namespaces.
- int pos = cdef->qualified.indexOf("::");
+ qsizetype pos = cdef->qualified.indexOf("::");
for ( ; pos != -1 ; pos = cdef->qualified.indexOf("::", pos + 2) )
fprintf(out, "using namespace %s;\n", cdef->qualified.left(pos).constData());
diff --git a/src/tools/moc/generator.h b/src/tools/moc/generator.h
index fa651f04a0..2d4d69ca05 100644
--- a/src/tools/moc/generator.h
+++ b/src/tools/moc/generator.h
@@ -10,16 +10,19 @@ QT_BEGIN_NAMESPACE
class Generator
{
+ Moc *parser = nullptr;
FILE *out;
ClassDef *cdef;
QList<uint> meta_data;
public:
- Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes,
+ Generator(Moc *moc, ClassDef *classDef, const QList<QByteArray> &metaTypes,
const QHash<QByteArray, QByteArray> &knownQObjectClasses,
const QHash<QByteArray, QByteArray> &knownGadgets, FILE *outfile = nullptr,
bool requireCompleteTypes = false);
void generateCode();
+ qsizetype registeredStringsCount() { return strings.size(); };
+
private:
bool registerableMetaType(const QByteArray &propertyType);
void registerClassInfoStrings();
@@ -37,7 +40,7 @@ private:
void generateProperties();
void generateMetacall();
void generateStaticMetacall();
- void generateSignal(FunctionDef *def, int index);
+ void generateSignal(const FunctionDef *def, int index);
void generatePluginMetaData();
QMultiMap<QByteArray, int> automaticPropertyMetaTypesHelper();
QMap<int, QMultiMap<QByteArray, int>>
diff --git a/src/tools/moc/main.cpp b/src/tools/moc/main.cpp
index eb359f4dbb..bb51352519 100644
--- a/src/tools/moc/main.cpp
+++ b/src/tools/moc/main.cpp
@@ -399,7 +399,7 @@ int runMoc(int argc, char **argv)
for (const QString &arg : defines) {
QByteArray name = arg.toLocal8Bit();
QByteArray value("1");
- int eq = name.indexOf('=');
+ const qsizetype eq = name.indexOf('=');
if (eq >= 0) {
value = name.mid(eq + 1);
name = name.left(eq);
@@ -449,11 +449,14 @@ int runMoc(int argc, char **argv)
if (filename.isEmpty()) {
filename = QStringLiteral("standard input");
- in.open(stdin, QIODevice::ReadOnly);
+ if (!in.open(stdin, QIODevice::ReadOnly)) {
+ fprintf(stderr, "moc: cannot open standard input: %s\n", qPrintable(in.errorString()));
+ return 1;
+ }
} else {
in.setFileName(filename);
if (!in.open(QIODevice::ReadOnly)) {
- fprintf(stderr, "moc: %s: No such file\n", qPrintable(filename));
+ fprintf(stderr, "moc: cannot open %s: %s\n", qPrintable(filename), qPrintable(in.errorString()));
return 1;
}
moc.filename = filename.toLocal8Bit();
@@ -536,7 +539,10 @@ int runMoc(int argc, char **argv)
if (!out)
#endif
{
- fprintf(stderr, "moc: Cannot create %s\n", QFile::encodeName(output).constData());
+ const auto fopen_errno = errno;
+ fprintf(stderr, "moc: Cannot create %s. Error: %s\n",
+ QFile::encodeName(output).constData(),
+ strerror(fopen_errno));
return 1;
}
@@ -549,9 +555,12 @@ int runMoc(int argc, char **argv)
f = fopen(QFile::encodeName(jsonOutputFileName).constData(), "w");
if (!f)
#endif
- fprintf(stderr, "moc: Cannot create JSON output file %s. %s\n",
+ {
+ const auto fopen_errno = errno;
+ fprintf(stderr, "moc: Cannot create JSON output file %s. Error: %s\n",
QFile::encodeName(jsonOutputFileName).constData(),
- strerror(errno));
+ strerror(fopen_errno));
+ }
jsonOutput.reset(f);
}
} else { // use stdout
@@ -596,9 +605,12 @@ int runMoc(int argc, char **argv)
depFileHandleRaw = fopen(QFile::encodeName(depOutputFileName).constData(), "w");
if (!depFileHandleRaw)
#endif
- fprintf(stderr, "moc: Cannot create dep output file '%s'. %s\n",
+ {
+ const auto fopen_errno = errno;
+ fprintf(stderr, "moc: Cannot create dep output file '%s'. Error: %s\n",
QFile::encodeName(depOutputFileName).constData(),
- strerror(errno));
+ strerror(fopen_errno));
+ }
depFileHandle.reset(depFileHandleRaw);
if (!depFileHandle.isNull()) {
diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp
index 64e98ae63b..3cbe331f14 100644
--- a/src/tools/moc/moc.cpp
+++ b/src/tools/moc/moc.cpp
@@ -26,6 +26,15 @@ static QByteArray normalizeType(const QByteArray &ba)
return ba.size() ? normalizeTypeInternal(ba.constBegin(), ba.constEnd()) : ba;
}
+const QByteArray &Moc::toFullyQualified(const QByteArray &name) const noexcept
+{
+ if (auto it = knownQObjectClasses.find(name); it != knownQObjectClasses.end())
+ return it.value();
+ if (auto it = knownGadgets.find(name); it != knownGadgets.end())
+ return it.value();
+ return name;
+}
+
bool Moc::parseClassHead(ClassDef *def)
{
// figure out whether this is a class declaration, or only a
@@ -87,17 +96,17 @@ bool Moc::parseClassHead(ClassDef *def)
else
test(PUBLIC);
test(VIRTUAL);
- const QByteArray type = parseType().name;
+ const Type type = parseType();
// ignore the 'class Foo : BAR(Baz)' case
if (test(LPAREN)) {
until(RPAREN);
} else {
- def->superclassList += qMakePair(type, access);
+ def->superclassList.push_back({type.name, toFullyQualified(type.name), access});
}
} while (test(COMMA));
if (!def->superclassList.isEmpty()
- && knownGadgets.contains(def->superclassList.constFirst().first)) {
+ && knownGadgets.contains(def->superclassList.constFirst().classname)) {
// Q_GADGET subclasses are treated as Q_GADGETs
knownGadgets.insert(def->classname, def->qualified);
knownGadgets.insert(def->qualified, def->qualified);
@@ -243,7 +252,7 @@ bool Moc::parseEnum(EnumDef *def)
}
if (test(COLON)) { // C++11 strongly typed enum
// enum Foo : unsigned long { ... };
- parseType(); //ignore the result
+ def->type = normalizeType(parseType().name);
}
if (!test(LBRACE))
return false;
@@ -318,6 +327,9 @@ void Moc::parseFunctionArguments(FunctionDef *def)
def->arguments.removeLast();
def->isRawSlot = true;
}
+
+ if (Q_UNLIKELY(def->arguments.size() >= std::numeric_limits<int>::max()))
+ error("number of function arguments exceeds std::numeric_limits<int>::max()");
}
bool Moc::testFunctionAttribute(FunctionDef *def)
@@ -409,8 +421,7 @@ bool Moc::parseFunction(FunctionDef *def, bool inMacro)
def->isVirtual = false;
def->isStatic = false;
//skip modifiers and attributes
- while (test(INLINE) || (test(STATIC) && (def->isStatic = true) == true) ||
- (test(VIRTUAL) && (def->isVirtual = true) == true) //mark as virtual
+ while (testForFunctionModifiers(def)
|| skipCxxAttributes() || testFunctionAttribute(def) || testFunctionRevision(def)) {}
bool templateFunction = (lookup() == TEMPLATE);
def->type = parseType();
@@ -421,31 +432,29 @@ bool Moc::parseFunction(FunctionDef *def, bool inMacro)
error();
}
bool scopedFunctionName = false;
- if (test(LPAREN)) {
- def->name = def->type.name;
- scopedFunctionName = def->type.isScoped;
- def->type = Type("int");
- } else {
- Type tempType = parseType();;
- while (!tempType.name.isEmpty() && lookup() != LPAREN) {
- if (testFunctionAttribute(def->type.firstToken, def))
- ; // fine
- else if (def->type.firstToken == Q_SIGNALS_TOKEN)
- error();
- else if (def->type.firstToken == Q_SLOTS_TOKEN)
- error();
- else {
- if (!def->tag.isEmpty())
- def->tag += ' ';
- def->tag += def->type.name;
- }
- def->type = tempType;
- tempType = parseType();
+ // we might have modifiers and attributes after a tag
+ // note that testFunctionAttribute is handled further below,
+ // and revisions and attributes must come first
+ while (testForFunctionModifiers(def)) {}
+ Type tempType = parseType();
+ while (!tempType.name.isEmpty() && lookup() != LPAREN) {
+ if (testFunctionAttribute(def->type.firstToken, def))
+ ; // fine
+ else if (def->type.firstToken == Q_SIGNALS_TOKEN)
+ error();
+ else if (def->type.firstToken == Q_SLOTS_TOKEN)
+ error();
+ else {
+ if (!def->tag.isEmpty())
+ def->tag += ' ';
+ def->tag += def->type.name;
}
- next(LPAREN, "Not a signal or slot declaration");
- def->name = tempType.name;
- scopedFunctionName = tempType.isScoped;
+ def->type = tempType;
+ tempType = parseType();
}
+ next(LPAREN, "Not a signal or slot declaration");
+ def->name = tempType.name;
+ scopedFunctionName = tempType.isScoped;
if (!test(RPAREN)) {
parseFunctionArguments(def);
@@ -509,14 +518,20 @@ bool Moc::parseFunction(FunctionDef *def, bool inMacro)
return true;
}
+bool Moc::testForFunctionModifiers(FunctionDef *def)
+{
+ return test(EXPLICIT) || test(INLINE) ||
+ (test(STATIC) && (def->isStatic = true)) ||
+ (test(VIRTUAL) && (def->isVirtual = true));
+}
+
// like parseFunction, but never aborts with an error
bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def)
{
def->isVirtual = false;
def->isStatic = false;
//skip modifiers and attributes
- while (test(EXPLICIT) || test(INLINE) || (test(STATIC) && (def->isStatic = true) == true) ||
- (test(VIRTUAL) && (def->isVirtual = true) == true) //mark as virtual
+ while (testForFunctionModifiers(def)
|| skipCxxAttributes() || testFunctionAttribute(def) || testFunctionRevision(def)) {}
bool tilde = test(TILDE);
def->type = parseType();
@@ -531,10 +546,15 @@ bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def)
def->isConstructor = !tilde;
def->type = Type();
} else {
- def->type = Type("int");
+ // missing type name? => Skip
+ return false;
}
} else {
- Type tempType = parseType();;
+ // ### TODO: The condition before testForFunctionModifiers shoulnd't be necessary,
+ // but otherwise we end up with misparses
+ if (def->isSlot || def->isSignal || def->isInvokable)
+ while (testForFunctionModifiers(def)) {}
+ Type tempType = parseType();
while (!tempType.name.isEmpty() && lookup() != LPAREN) {
if (testFunctionAttribute(def->type.firstToken, def))
; // fine
@@ -593,6 +613,52 @@ inline void handleDefaultArguments(QList<FunctionDef> *functionList, FunctionDef
}
}
+void Moc::prependNamespaces(BaseDef &def, const QList<NamespaceDef> &namespaceList) const
+{
+ auto it = namespaceList.crbegin();
+ const auto rend = namespaceList.crend();
+ for (; it != rend; ++it) {
+ if (inNamespace(&*it))
+ def.qualified.prepend(it->classname + "::");
+ }
+}
+
+void Moc::checkListSizes(const ClassDef &def)
+{
+ if (Q_UNLIKELY(def.nonClassSignalList.size() > std::numeric_limits<int>::max()))
+ error("number of signals defined in parent class(es) exceeds "
+ "std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.propertyList.size() > std::numeric_limits<int>::max()))
+ error("number of bindable properties exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.classInfoList.size() > std::numeric_limits<int>::max()))
+ error("number of times Q_CLASSINFO macro is used exceeds "
+ "std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.enumList.size() > std::numeric_limits<int>::max()))
+ error("number of enumerations exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.superclassList.size() > std::numeric_limits<int>::max()))
+ error("number of super classes exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.constructorList.size() > std::numeric_limits<int>::max()))
+ error("number of constructor parameters exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.signalList.size() > std::numeric_limits<int>::max()))
+ error("number of signals exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.slotList.size() > std::numeric_limits<int>::max()))
+ error("number of declared slots exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.methodList.size() > std::numeric_limits<int>::max()))
+ error("number of methods exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.publicList.size() > std::numeric_limits<int>::max()))
+ error("number of public functions declared in this class exceeds "
+ "std::numeric_limits<int>::max().");
+}
+
void Moc::parse()
{
QList<NamespaceDef> namespaceList;
@@ -601,7 +667,7 @@ void Moc::parse()
Token t = next();
switch (t) {
case NAMESPACE: {
- int rewind = index;
+ qsizetype rewind = index;
if (test(IDENTIFIER)) {
QByteArray nsName = lexem();
QByteArrayList nested;
@@ -633,11 +699,8 @@ void Moc::parse()
def.end = index;
index = def.begin + 1;
- for (int i = namespaceList.size() - 1; i >= 0; --i) {
- if (inNamespace(&namespaceList.at(i))) {
- def.qualified.prepend(namespaceList.at(i).classname + "::");
- }
- }
+ prependNamespaces(def, namespaceList);
+
for (const QByteArray &ns : nested) {
NamespaceDef parentNs;
parentNs.classname = ns;
@@ -652,8 +715,10 @@ void Moc::parse()
switch (next()) {
case NAMESPACE:
if (test(IDENTIFIER)) {
- while (test(SCOPE))
+ while (test(SCOPE)) {
+ test(INLINE); // ignore inline namespaces
next(IDENTIFIER);
+ }
if (test(EQ)) {
// namespace Foo = Bar::Baz;
until(SEMIC);
@@ -783,9 +848,7 @@ void Moc::parse()
if (!def.hasQObject && !def.hasQGadget)
continue;
- for (int i = namespaceList.size() - 1; i >= 0; --i)
- if (inNamespace(&namespaceList.at(i)))
- def.qualified.prepend(namespaceList.at(i).classname + "::");
+ prependNamespaces(def, namespaceList);
QHash<QByteArray, QByteArray> &classHash = def.hasQObject ? knownQObjectClasses : knownGadgets;
classHash.insert(def.classname, def.qualified);
@@ -798,10 +861,9 @@ void Moc::parse()
continue;
ClassDef def;
if (parseClassHead(&def)) {
+ prependNamespaces(def, namespaceList);
+
FunctionDef::Access access = FunctionDef::Private;
- for (int i = namespaceList.size() - 1; i >= 0; --i)
- if (inNamespace(&namespaceList.at(i)))
- def.qualified.prepend(namespaceList.at(i).classname + "::");
while (inClass(&def) && hasNext()) {
switch ((t = next())) {
case PRIVATE:
@@ -916,7 +978,7 @@ void Moc::parse()
default:
FunctionDef funcDef;
funcDef.access = access;
- int rewind = index--;
+ qsizetype rewind = index--;
if (parseMaybeFunction(&def, &funcDef)) {
if (funcDef.isConstructor) {
if ((access == FunctionDef::Public) && funcDef.isInvokable) {
@@ -965,9 +1027,13 @@ void Moc::parse()
if (!def.pluginData.iid.isEmpty())
def.pluginData.metaArgs = metaArgs;
- checkSuperClasses(&def);
+ if (def.hasQObject && !def.superclassList.isEmpty())
+ checkSuperClasses(&def);
+
checkProperties(&def);
+ checkListSizes(def);
+
classList += def;
QHash<QByteArray, QByteArray> &classHash = def.hasQObject ? knownQObjectClasses : knownGadgets;
classHash.insert(def.classname, def.qualified);
@@ -987,8 +1053,10 @@ void Moc::parse()
if (it != classList.end()) {
it->classInfoList += def.classInfoList;
+ Q_ASSERT(it->classInfoList.size() <= std::numeric_limits<int>::max());
it->enumDeclarations.insert(def.enumDeclarations);
it->enumList += def.enumList;
+ Q_ASSERT(it->enumList.size() <= std::numeric_limits<int>::max());
it->flagAliases.insert(def.flagAliases);
} else {
knownGadgets.insert(def.classname, def.qualified);
@@ -1066,12 +1134,13 @@ static QByteArrayList requiredQtContainers(const QList<ClassDef> &classes)
void Moc::generate(FILE *out, FILE *jsonOutput)
{
- QByteArray fn = filename;
- int i = filename.size()-1;
- while (i > 0 && filename.at(i - 1) != '/' && filename.at(i - 1) != '\\')
- --i; // skip path
- if (i >= 0)
- fn = filename.mid(i);
+ QByteArrayView fn = QByteArrayView(filename);
+
+ auto isSlash = [](char ch) { return ch == '/' || ch == '\\'; };
+ auto rit = std::find_if(fn.crbegin(), fn.crend(), isSlash);
+ if (rit != fn.crend())
+ fn = fn.last(rit - fn.crbegin());
+
fprintf(out, "/****************************************************************************\n"
"** Meta object code from reading C++ file '%s'\n**\n" , fn.constData());
fprintf(out, "** Created by: The Qt Meta Object Compiler version %d (Qt %s)\n**\n" , mocOutputRevision, QT_VERSION_STR);
@@ -1084,9 +1153,8 @@ void Moc::generate(FILE *out, FILE *jsonOutput)
if (!noInclude) {
if (includePath.size() && !includePath.endsWith('/'))
includePath += '/';
- for (int i = 0; i < includeFiles.size(); ++i) {
- QByteArray inc = includeFiles.at(i);
- if (inc.at(0) != '<' && inc.at(0) != '"') {
+ for (QByteArray inc : std::as_const(includeFiles)) {
+ if (!inc.isEmpty() && inc.at(0) != '<' && inc.at(0) != '"') {
if (includePath.size() && includePath != "./")
inc.prepend(includePath);
inc = '\"' + inc + '\"';
@@ -1105,18 +1173,10 @@ void Moc::generate(FILE *out, FILE *jsonOutput)
for (const QByteArray &qtContainer : qtContainers)
fprintf(out, "#include <QtCore/%s>\n", qtContainer.constData());
- fprintf(out, "\n%s#include <QtCore/qtmochelpers.h>\n%s\n",
-#if QT_VERSION <= QT_VERSION_CHECK(6, 9, 0)
- "#if __has_include(<QtCore/qtmochelpers.h>)\n",
- "#else\n"
- "QT_BEGIN_MOC_NAMESPACE\n"
- "#endif\n"
-#else
- "", ""
-#endif
- );
+ fprintf(out, "\n#include <QtCore/qtmochelpers.h>\n");
fprintf(out, "\n#include <memory>\n\n"); // For std::addressof
+ fprintf(out, "\n#include <QtCore/qxptype_traits.h>\n"); // is_detected
fprintf(out, "#if !defined(Q_MOC_OUTPUT_REVISION)\n"
"#error \"The header file '%s' doesn't include <QObject>.\"\n", fn.constData());
@@ -1138,9 +1198,16 @@ void Moc::generate(FILE *out, FILE *jsonOutput)
fprintf(out, "QT_WARNING_DISABLE_GCC(\"-Wuseless-cast\")\n");
fputs("", out);
- for (i = 0; i < classList.size(); ++i) {
- Generator generator(&classList[i], metaTypes, knownQObjectClasses, knownGadgets, out, requireCompleteTypes);
+ for (ClassDef &def : classList) {
+ Generator generator(this, &def, metaTypes, knownQObjectClasses, knownGadgets, out,
+ requireCompleteTypes);
generator.generateCode();
+
+ // generator.generateCode() should have already registered all strings
+ if (Q_UNLIKELY(generator.registeredStringsCount() >= std::numeric_limits<int>::max())) {
+ error("internal limit exceeded: number of parsed strings is too big.");
+ exit(EXIT_FAILURE);
+ }
}
fputs("", out);
@@ -1300,7 +1367,8 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef)
};
while (test(IDENTIFIER)) {
- const QByteArray l = lexem();
+ const Symbol &lsym = symbol();
+ const QByteArray l = lsym.lexem();
if (l[0] == 'C' && l == "CONSTANT") {
propDef.constant = true;
continue;
@@ -1327,11 +1395,11 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef)
} else if (test(INTEGER_LITERAL)) {
v = lexem();
if (l != "REVISION")
- error(1);
+ error(lsym);
} else if (test(DEFAULT)) {
v = lexem();
if (l != "READ" && l != "WRITE")
- error(1);
+ error(lsym);
} else {
next(IDENTIFIER);
v = lexem();
@@ -1345,7 +1413,7 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef)
if (l == "MEMBER")
propDef.member = v;
else
- error(2);
+ error(lsym);
break;
case 'R':
if (l == "READ")
@@ -1356,10 +1424,10 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef)
bool ok = false;
const int minor = v.toInt(&ok);
if (!ok || !QTypeRevision::isValidSegment(minor))
- error(1);
+ error(lsym);
propDef.revision = QTypeRevision::fromMinorVersion(minor).toEncodedVersion<int>();
} else
- error(2);
+ error(lsym);
break;
case 'S':
if (l == "SCRIPTABLE") {
@@ -1369,27 +1437,27 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef)
propDef.stored = v + v2;
checkIsFunction(propDef.stored, "STORED");
} else
- error(2);
+ error(lsym);
break;
- case 'W': if (l != "WRITE") error(2);
+ case 'W': if (l != "WRITE") error(lsym);
propDef.write = v;
break;
- case 'B': if (l != "BINDABLE") error(2);
+ case 'B': if (l != "BINDABLE") error(lsym);
propDef.bind = v;
break;
- case 'D': if (l != "DESIGNABLE") error(2);
+ case 'D': if (l != "DESIGNABLE") error(lsym);
propDef.designable = v + v2;
checkIsFunction(propDef.designable, "DESIGNABLE");
break;
- case 'N': if (l != "NOTIFY") error(2);
+ case 'N': if (l != "NOTIFY") error(lsym);
propDef.notify = v;
break;
- case 'U': if (l != "USER") error(2);
+ case 'U': if (l != "USER") error(lsym);
propDef.user = v + v2;
checkIsFunction(propDef.user, "USER");
break;
default:
- error(2);
+ error(lsym);
}
}
if (propDef.constant && !propDef.write.isNull()) {
@@ -1449,9 +1517,11 @@ void Moc::parsePluginData(ClassDef *def)
} else if (l == "FILE") {
next(STRING_LITERAL);
QByteArray metaDataFile = unquotedLexem();
- QFileInfo fi(QFileInfo(QString::fromLocal8Bit(currentFilenames.top().constData())).dir(), QString::fromLocal8Bit(metaDataFile.constData()));
- for (int j = 0; j < includes.size() && !fi.exists(); ++j) {
- const IncludePath &p = includes.at(j);
+ QFileInfo fi(QFileInfo(QString::fromLocal8Bit(currentFilenames.top())).dir(),
+ QString::fromLocal8Bit(metaDataFile));
+ for (const IncludePath &p : std::as_const(includes)) {
+ if (fi.exists())
+ break;
if (p.isFrameworkPath)
continue;
@@ -1620,7 +1690,7 @@ void Moc::parseInterfaces(ClassDef *def)
}
}
// resolve from classnames to interface ids
- for (int i = 0; i < iface.size(); ++i) {
+ for (qsizetype i = 0; i < iface.size(); ++i) {
const QByteArray iid = interface2IdMap.value(iface.at(i).className);
if (iid.isEmpty())
error("Undefined interface");
@@ -1697,7 +1767,7 @@ void Moc::parseSlotInPrivate(ClassDef *def, FunctionDef::Access access)
QByteArray Moc::lexemUntil(Token target)
{
- int from = index;
+ qsizetype from = index;
until(target);
QByteArray s;
while (from <= index) {
@@ -1733,7 +1803,7 @@ bool Moc::until(Token target) {
//when searching commas within the default argument, we should take care of template depth (anglecount)
// unfortunately, we do not have enough semantic information to know if '<' is the operator< or
// the beginning of a template type. so we just use heuristics.
- int possible = -1;
+ qsizetype possible = -1;
while (index < symbols.size()) {
Token t = symbols.at(index++).token;
@@ -1797,7 +1867,8 @@ bool Moc::until(Token target) {
void Moc::checkSuperClasses(ClassDef *def)
{
- const QByteArray firstSuperclass = def->superclassList.value(0).first;
+ Q_ASSERT(!def->superclassList.isEmpty());
+ const QByteArray &firstSuperclass = def->superclassList.at(0).classname;
if (!knownQObjectClasses.contains(firstSuperclass)) {
// enable once we /require/ include paths
@@ -1812,8 +1883,18 @@ void Moc::checkSuperClasses(ClassDef *def)
#endif
return;
}
- for (int i = 1; i < def->superclassList.size(); ++i) {
- const QByteArray superClass = def->superclassList.at(i).first;
+
+ auto isRegisteredInterface = [&def](QByteArrayView super) {
+ auto matchesSuperClass = [&super](const auto &ifaces) {
+ return !ifaces.isEmpty() && ifaces.first().className == super;
+ };
+ return std::any_of(def->interfaceList.cbegin(), def->interfaceList.cend(), matchesSuperClass);
+ };
+
+ const auto end = def->superclassList.cend();
+ auto it = def->superclassList.cbegin() + 1;
+ for (; it != end; ++it) {
+ const QByteArray &superClass = it->classname;
if (knownQObjectClasses.contains(superClass)) {
const QByteArray msg
= "Class "
@@ -1827,14 +1908,7 @@ void Moc::checkSuperClasses(ClassDef *def)
}
if (interface2IdMap.contains(superClass)) {
- bool registeredInterface = false;
- for (int i = 0; i < def->interfaceList.size(); ++i)
- if (def->interfaceList.at(i).constFirst().className == superClass) {
- registeredInterface = true;
- break;
- }
-
- if (!registeredInterface) {
+ if (!isRegisteredInterface(superClass)) {
const QByteArray msg
= "Class "
+ def->classname
@@ -1856,30 +1930,26 @@ void Moc::checkProperties(ClassDef *cdef)
// returning pointers, or const char * for QByteArray.
//
QDuplicateTracker<QByteArray> definedProperties(cdef->propertyList.size());
- for (int i = 0; i < cdef->propertyList.size(); ++i) {
- PropertyDef &p = cdef->propertyList[i];
+ auto hasNoAttributes = [&](const PropertyDef &p) {
if (definedProperties.hasSeen(p.name)) {
QByteArray msg = "The property '" + p.name + "' is defined multiple times in class " + cdef->classname + ".";
warning(msg.constData());
}
if (p.read.isEmpty() && p.member.isEmpty() && p.bind.isEmpty()) {
- const int rewind = index;
- if (p.location >= 0)
- index = p.location;
QByteArray msg = "Property declaration " + p.name + " has neither an associated QProperty<> member"
", nor a READ accessor function nor an associated MEMBER variable. The property will be invalid.";
- warning(msg.constData());
- index = rewind;
- if (p.write.isEmpty()) {
- cdef->propertyList.removeAt(i);
- --i;
- }
- continue;
+ const auto &sym = p.location >= 0 ? symbolAt(p.location) : Symbol();
+ warning(sym, msg.constData());
+ if (p.write.isEmpty())
+ return true;
}
+ return false;
+ };
+ cdef->propertyList.removeIf(hasNoAttributes);
- for (int j = 0; j < cdef->publicList.size(); ++j) {
- const FunctionDef &f = cdef->publicList.at(j);
+ for (PropertyDef &p : cdef->propertyList) {
+ for (const FunctionDef &f : std::as_const(cdef->publicList)) {
if (f.name != p.read)
continue;
if (!f.isConst) // get functions must be const
@@ -1905,7 +1975,7 @@ void Moc::checkProperties(ClassDef *cdef)
}
if (!p.notify.isEmpty()) {
int notifyId = -1;
- for (int j = 0; j < cdef->signalList.size(); ++j) {
+ for (int j = 0; j < int(cdef->signalList.size()); ++j) {
const FunctionDef &f = cdef->signalList.at(j);
if (f.name != p.notify) {
continue;
@@ -1916,12 +1986,12 @@ void Moc::checkProperties(ClassDef *cdef)
}
p.notifyId = notifyId;
if (notifyId == -1) {
- int index = cdef->nonClassSignalList.indexOf(p.notify);
+ const int index = int(cdef->nonClassSignalList.indexOf(p.notify));
if (index == -1) {
cdef->nonClassSignalList << p.notify;
- p.notifyId = -1 - cdef->nonClassSignalList.size();
+ p.notifyId = int(-1 - cdef->nonClassSignalList.size());
} else {
- p.notifyId = -2 - index;
+ p.notifyId = int(-2 - index);
}
}
}
@@ -1978,11 +2048,11 @@ QJsonObject ClassDef::toJson() const
QJsonArray superClasses;
for (const auto &super: std::as_const(superclassList)) {
- const auto name = super.first;
- const auto access = super.second;
QJsonObject superCls;
- superCls["name"_L1] = QString::fromUtf8(name);
- FunctionDef::accessToJson(&superCls, access);
+ superCls["name"_L1] = QString::fromUtf8(super.classname);
+ if (super.classname != super.qualified)
+ superCls["fullyQualifiedName"_L1] = QString::fromUtf8(super.qualified);
+ FunctionDef::accessToJson(&superCls, super.access);
superClasses.append(superCls);
}
@@ -2107,6 +2177,8 @@ QJsonObject EnumDef::toJson(const ClassDef &cdef) const
def["name"_L1] = QString::fromUtf8(name);
if (!enumName.isEmpty())
def["alias"_L1] = QString::fromUtf8(enumName);
+ if (!type.isEmpty())
+ def["type"_L1] = QString::fromUtf8(type);
def["isFlag"_L1] = cdef.enumDeclarations.value(name);
def["isClass"_L1] = isEnumClass;
@@ -2119,4 +2191,23 @@ QJsonObject EnumDef::toJson(const ClassDef &cdef) const
return def;
}
+QByteArray EnumDef::qualifiedType(const ClassDef *cdef) const
+{
+ if (name == cdef->classname) {
+ // The name of the enclosing namespace is the same as the enum class name
+ if (cdef->qualified.contains("::")) {
+ // QTBUG-112996, fully qualify by using cdef->qualified to disambiguate enum
+ // class name and enclosing namespace, e.g.:
+ // namespace A { namespace B { Q_NAMESPACE; enum class B { }; Q_ENUM_NS(B) } }
+ return cdef->qualified % "::" % name;
+ } else {
+ // Just "B"; otherwise the compiler complains about the type "B::B" inside
+ // "B::staticMetaObject" in the generated code; e.g.:
+ // namespace B { Q_NAMESPACE; enum class B { }; Q_ENUM_NS(B) }
+ return name;
+ }
+ }
+ return cdef->classname % "::" % name;
+}
+
QT_END_NAMESPACE
diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h
index edeac03b82..c1759fb0a3 100644
--- a/src/tools/moc/moc.h
+++ b/src/tools/moc/moc.h
@@ -7,11 +7,10 @@
#include "parser.h"
#include <qstringlist.h>
#include <qmap.h>
-#include <qpair.h>
#include <qjsondocument.h>
#include <qjsonarray.h>
#include <qjsonobject.h>
-#include <qversionnumber.h>
+#include <qtyperevision.h>
#include <stdio.h>
#include <private/qtools_p.h>
@@ -43,10 +42,12 @@ struct EnumDef
{
QByteArray name;
QByteArray enumName;
+ QByteArray type;
QList<QByteArray> values;
bool isEnumClass; // c++11 enum class
EnumDef() : isEnumClass(false) {}
QJsonObject toJson(const ClassDef &cdef) const;
+ QByteArray qualifiedType(const ClassDef *cdef) const;
};
Q_DECLARE_TYPEINFO(EnumDef, Q_RELOCATABLE_TYPE);
@@ -120,7 +121,7 @@ struct PropertyDef
bool required = false;
int relativeIndex = -1; // property index in current metaobject
- int location = -1; // token index, used for error reporting
+ qsizetype location = -1; // token index, used for error reporting
QJsonObject toJson() const;
};
@@ -150,12 +151,19 @@ struct BaseDef {
QMap<QByteArray, bool> enumDeclarations;
QList<EnumDef> enumList;
QMap<QByteArray, QByteArray> flagAliases;
- int begin = 0;
- int end = 0;
+ qsizetype begin = 0;
+ qsizetype end = 0;
};
+struct SuperClass {
+ QByteArray classname;
+ QByteArray qualified;
+ FunctionDef::Access access;
+};
+Q_DECLARE_TYPEINFO(SuperClass, Q_RELOCATABLE_TYPE);
+
struct ClassDef : BaseDef {
- QList<QPair<QByteArray, FunctionDef::Access>> superclassList;
+ QList<SuperClass> superclassList;
struct Interface
{
@@ -233,6 +241,10 @@ public:
return index > def->begin && index < def->end - 1;
}
+ const QByteArray &toFullyQualified(const QByteArray &name) const noexcept;
+
+ void prependNamespaces(BaseDef &def, const QList<NamespaceDef> &namespaceList) const;
+
Type parseType();
bool parseEnum(EnumDef *def);
@@ -277,6 +289,9 @@ public:
void checkSuperClasses(ClassDef *def);
void checkProperties(ClassDef* cdef);
+ bool testForFunctionModifiers(FunctionDef *def);
+
+ void checkListSizes(const ClassDef &def);
};
inline QByteArray noRef(const QByteArray &type)
diff --git a/src/tools/moc/parser.cpp b/src/tools/moc/parser.cpp
index 6fa0e645d3..1cfb8ce486 100644
--- a/src/tools/moc/parser.cpp
+++ b/src/tools/moc/parser.cpp
@@ -8,42 +8,80 @@
QT_BEGIN_NAMESPACE
-#ifdef USE_LEXEM_STORE
-Symbol::LexemStore Symbol::lexemStore;
-#endif
-
static const char *error_msg = nullptr;
+/*! \internal
+ Base implementation for printing diagnostic messages.
+
+ For example:
+ "/path/to/file:line:column: error: %s\n"
+ '%s' is replaced by \a msg. (Currently "column" is always 1).
+
+ If sym.lineNum is -1, the line and column parts aren't printed:
+ "/path/to/file: error: %s\n"
+
+ \a formatStringSuffix specifies the type of the message e.g.:
+ "error: %s\n"
+ "warning: %s\n"
+ "note: %s\n"
+ "Parse error at %s\n" (from defaultErrorMsg())
+*/
+void Parser::printMsg(QByteArrayView formatStringSuffix, QByteArrayView msg, const Symbol &sym)
+{
+ if (sym.lineNum != -1) {
#ifdef Q_CC_MSVC
-#define ErrorFormatString "%s(%d:%d): "
+ QByteArray formatString = "%s(%d:%d): " + formatStringSuffix;
#else
-#define ErrorFormatString "%s:%d:%d: "
+ QByteArray formatString = "%s:%d:%d: " + formatStringSuffix;
#endif
+ fprintf(stderr, formatString.constData(),
+ currentFilenames.top().constData(), sym.lineNum, 1, msg.data());
+ } else {
+ QByteArray formatString = "%s: " + formatStringSuffix;
+ fprintf(stderr, formatString.constData(),
+ currentFilenames.top().constData(), msg.data());
+ }
+}
+
+void Parser::defaultErrorMsg(const Symbol &sym)
+{
+ if (sym.lineNum != -1)
+ printMsg("error: Parse error at \"%s\"\n", sym.lexem().data(), sym);
+ else
+ printMsg("error: could not parse file\n", "", sym);
+}
-void Parser::error(int rollback) {
- index -= rollback;
- error();
+void Parser::error(const Symbol &sym)
+{
+ defaultErrorMsg(sym);
+ exit(EXIT_FAILURE);
}
-void Parser::error(const char *msg) {
+
+void Parser::error(const char *msg)
+{
if (msg || error_msg)
- fprintf(stderr, ErrorFormatString "error: %s\n",
- currentFilenames.top().constData(), symbol().lineNum, 1, msg?msg:error_msg);
+ printMsg("error: %s\n",
+ msg ? msg : error_msg,
+ index > 0 ? symbol() : Symbol{});
else
- fprintf(stderr, ErrorFormatString "error: Parse error at \"%s\"\n",
- currentFilenames.top().constData(), symbol().lineNum, 1, symbol().lexem().data());
+ defaultErrorMsg(symbol());
+
exit(EXIT_FAILURE);
}
+void Parser::warning(const Symbol &sym, QByteArrayView msg)
+{
+ if (displayWarnings)
+ printMsg("warning: %s\n", msg, sym);
+}
+
void Parser::warning(const char *msg) {
- if (displayWarnings && msg)
- fprintf(stderr, ErrorFormatString "warning: %s\n",
- currentFilenames.top().constData(), qMax(0, index > 0 ? symbol().lineNum : 0), 1, msg);
+ warning(index > 0 ? symbol() : Symbol{}, msg);
}
void Parser::note(const char *msg) {
if (displayNotes && msg)
- fprintf(stderr, ErrorFormatString "note: %s\n",
- currentFilenames.top().constData(), qMax(0, index > 0 ? symbol().lineNum : 0), 1, msg);
+ printMsg("note: %s\n", msg, index > 0 ? symbol() : Symbol{});
}
QT_END_NAMESPACE
diff --git a/src/tools/moc/parser.h b/src/tools/moc/parser.h
index 5f754d9b19..6fe982a1ce 100644
--- a/src/tools/moc/parser.h
+++ b/src/tools/moc/parser.h
@@ -5,6 +5,7 @@
#define PARSER_H
#include "symbols.h"
+#include <QtCore/qbytearrayview.h>
#include <stack>
@@ -15,7 +16,7 @@ class Parser
public:
Parser():index(0), displayWarnings(true), displayNotes(true) {}
Symbols symbols;
- int index;
+ qsizetype index;
bool displayWarnings;
bool displayNotes;
@@ -43,11 +44,15 @@ public:
inline QByteArray lexem() { return symbols.at(index-1).lexem();}
inline QByteArray unquotedLexem() { return symbols.at(index-1).unquotedLexem();}
inline const Symbol &symbol() { return symbols.at(index-1);}
+ inline const Symbol &symbolAt(qsizetype idx) { return symbols.at(idx); }
- Q_NORETURN void error(int rollback);
+ Q_NORETURN void error(const Symbol &symbol);
Q_NORETURN void error(const char *msg = nullptr);
void warning(const char * = nullptr);
+ void warning(const Symbol &sym, QByteArrayView msg);
void note(const char * = nullptr);
+ void defaultErrorMsg(const Symbol &sym);
+ void printMsg(QByteArrayView formatStringSuffix, QByteArrayView msg, const Symbol &sym);
};
@@ -62,7 +67,7 @@ inline bool Parser::test(Token token)
inline Token Parser::lookup(int k)
{
- const int l = index - 1 + k;
+ const qsizetype l = index - 1 + k;
return l < symbols.size() ? symbols.at(l).token : NOTOKEN;
}
diff --git a/src/tools/moc/preprocessor.cpp b/src/tools/moc/preprocessor.cpp
index 0958e26be3..11ea8d417e 100644
--- a/src/tools/moc/preprocessor.cpp
+++ b/src/tools/moc/preprocessor.cpp
@@ -12,6 +12,8 @@
QT_BEGIN_NAMESPACE
+using namespace QtMiscUtils;
+
#include "ppkeywords.cpp"
#include "keywords.cpp"
@@ -212,7 +214,9 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
data -= 2;
break;
case DIGIT:
- while (is_digit_char(*data) || *data == '\'')
+ {
+ bool hasSeenTokenSeparator = false;;
+ while (isAsciiDigit(*data) || (hasSeenTokenSeparator = *data == '\''))
++data;
if (!*data || *data != '.') {
token = INTEGER_LITERAL;
@@ -221,22 +225,30 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
|| *data == 'b' || *data == 'B')
&& *lexem == '0') {
++data;
- while (is_hex_char(*data) || *data == '\'')
+ while (isHexDigit(*data) || (hasSeenTokenSeparator = *data == '\''))
+ ++data;
+ } else if (*data == 'L') // TODO: handle other suffixes
+ ++data;
+ if (!hasSeenTokenSeparator) {
+ while (is_ident_char(*data)) {
++data;
+ token = IDENTIFIER;
+ }
}
break;
}
token = FLOATING_LITERAL;
++data;
Q_FALLTHROUGH();
+ }
case FLOATING_LITERAL:
- while (is_digit_char(*data) || *data == '\'')
+ while (isAsciiDigit(*data) || *data == '\'')
++data;
if (*data == '+' || *data == '-')
++data;
if (*data == 'e' || *data == 'E') {
++data;
- while (is_digit_char(*data) || *data == '\'')
+ while (isAsciiDigit(*data) || *data == '\'')
++data;
}
if (*data == 'f' || *data == 'F'
@@ -315,16 +327,7 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
continue; //ignore
}
}
-#ifdef USE_LEXEM_STORE
- if (!Preprocessor::preprocessOnly
- && token != IDENTIFIER
- && token != STRING_LITERAL
- && token != FLOATING_LITERAL
- && token != INTEGER_LITERAL)
- symbols += Symbol(lineNum, token);
- else
-#endif
- symbols += Symbol(lineNum, token, input, lexem-begin, data-lexem);
+ symbols += Symbol(lineNum, token, input, lexem-begin, data-lexem);
} else { // Preprocessor
@@ -390,7 +393,7 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
token = PP_CHARACTER_LITERAL;
break;
case PP_DIGIT:
- while (is_digit_char(*data) || *data == '\'')
+ while (isAsciiDigit(*data) || *data == '\'')
++data;
if (!*data || *data != '.') {
token = PP_INTEGER_LITERAL;
@@ -398,22 +401,23 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
(*data == 'x' || *data == 'X')
&& *lexem == '0') {
++data;
- while (is_hex_char(*data) || *data == '\'')
+ while (isHexDigit(*data) || *data == '\'')
++data;
- }
+ } else if (*data == 'L') // TODO: handle other suffixes
+ ++data;
break;
}
token = PP_FLOATING_LITERAL;
++data;
Q_FALLTHROUGH();
case PP_FLOATING_LITERAL:
- while (is_digit_char(*data) || *data == '\'')
+ while (isAsciiDigit(*data) || *data == '\'')
++data;
if (*data == '+' || *data == '-')
++data;
if (*data == 'e' || *data == 'E') {
++data;
- while (is_digit_char(*data) || *data == '\'')
+ while (isAsciiDigit(*data) || *data == '\'')
++data;
}
if (*data == 'f' || *data == 'F'
@@ -495,22 +499,14 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso
}
if (mode == PreparePreprocessorStatement)
continue;
-#ifdef USE_LEXEM_STORE
- if (token != PP_IDENTIFIER
- && token != PP_STRING_LITERAL
- && token != PP_FLOATING_LITERAL
- && token != PP_INTEGER_LITERAL)
- symbols += Symbol(lineNum, token);
- else
-#endif
- symbols += Symbol(lineNum, token, input, lexem-begin, data-lexem);
+ symbols += Symbol(lineNum, token, input, lexem-begin, data-lexem);
}
}
symbols += Symbol(); // eof symbol
return symbols;
}
-void Preprocessor::macroExpand(Symbols *into, Preprocessor *that, const Symbols &toExpand, int &index,
+void Preprocessor::macroExpand(Symbols *into, Preprocessor *that, const Symbols &toExpand, qsizetype &index,
int lineNum, bool one, const QSet<QByteArray> &excludeSymbols)
{
SymbolStack symbols;
@@ -618,19 +614,22 @@ Symbols Preprocessor::macroExpandIdentifier(Preprocessor *that, SymbolStack &sym
HashHash
} mode = Normal;
- for (int i = 0; i < macro.symbols.size(); ++i) {
- const Symbol &s = macro.symbols.at(i);
+ const auto end = macro.symbols.cend();
+ auto it = macro.symbols.cbegin();
+ const auto lastSym = std::prev(macro.symbols.cend(), !macro.symbols.isEmpty() ? 1 : 0);
+ for (; it != end; ++it) {
+ const Symbol &s = *it;
if (s.token == HASH || s.token == PP_HASHHASH) {
mode = (s.token == HASH ? Hash : HashHash);
continue;
}
- int index = macro.arguments.indexOf(s);
+ const qsizetype index = macro.arguments.indexOf(s);
if (mode == Normal) {
if (index >= 0 && index < arguments.size()) {
// each argument undoergoes macro expansion if it's not used as part of a # or ##
- if (i == macro.symbols.size() - 1 || macro.symbols.at(i + 1).token != PP_HASHHASH) {
+ if (it == lastSym || std::next(it)->token != PP_HASHHASH) {
Symbols arg = arguments.at(index);
- int idx = 1;
+ qsizetype idx = 1;
macroExpand(&expansion, that, arg, idx, lineNum, false, symbols.excludeSymbols());
} else {
expansion += arguments.at(index);
@@ -649,9 +648,9 @@ Symbols Preprocessor::macroExpandIdentifier(Preprocessor *that, SymbolStack &sym
const Symbols &arg = arguments.at(index);
QByteArray stringified;
- for (int i = 0; i < arg.size(); ++i) {
- stringified += arg.at(i).lexem();
- }
+ for (const Symbol &sym : arg)
+ stringified += sym.lexem();
+
stringified.replace('"', "\\\"");
stringified.prepend('"');
stringified.append('"');
@@ -685,8 +684,8 @@ Symbols Preprocessor::macroExpandIdentifier(Preprocessor *that, SymbolStack &sym
if (index >= 0 && index < arguments.size()) {
const Symbols &arg = arguments.at(index);
- for (int i = 1; i < arg.size(); ++i)
- expansion += arg.at(i);
+ if (!arg.isEmpty())
+ expansion.append(arg.cbegin() + 1, arg.cend());
}
}
mode = Normal;
@@ -927,7 +926,11 @@ int PP_Expression::primary_expression()
test(PP_RPAREN);
} else {
next();
- value = lexem().toInt(nullptr, 0);
+ const QByteArray &lex = lexem();
+ auto lexView = QByteArrayView(lex);
+ if (lex.endsWith('L'))
+ lexView.chop(1);
+ value = lexView.toInt(nullptr, 0);
}
return value;
}
@@ -966,7 +969,7 @@ static void mergeStringLiterals(Symbols *_symbols)
for (Symbols::iterator i = symbols.begin(); i != symbols.end(); ++i) {
if (i->token == STRING_LITERAL) {
Symbols::Iterator mergeSymbol = i;
- int literalsLength = mergeSymbol->len;
+ qsizetype literalsLength = mergeSymbol->len;
while (++i != symbols.end() && i->token == STRING_LITERAL)
literalsLength += i->len - 2; // no quotes
@@ -1000,10 +1003,12 @@ static QByteArray searchIncludePaths(const QList<Parser::IncludePath> &includepa
fprintf(stderr, "debug-includes: searching for '%s'\n", include.constData());
}
- for (int j = 0; j < includepaths.size() && !fi.exists(); ++j) {
- const Parser::IncludePath &p = includepaths.at(j);
+ for (const Parser::IncludePath &p : includepaths) {
+ if (fi.exists())
+ break;
+
if (p.isFrameworkPath) {
- const int slashPos = include.indexOf('/');
+ const qsizetype slashPos = include.indexOf('/');
if (slashPos == -1)
continue;
fi.setFile(QString::fromLocal8Bit(p.path + '/' + include.left(slashPos) + ".framework/Headers/"),
@@ -1099,7 +1104,7 @@ void Preprocessor::preprocess(const QByteArray &filename, Symbols &preprocessed)
continue;
Symbols saveSymbols = symbols;
- int saveIndex = index;
+ qsizetype saveIndex = index;
// phase 1: get rid of backslash-newlines
input = cleaned(input);
@@ -1134,14 +1139,14 @@ void Preprocessor::preprocess(const QByteArray &filename, Symbols &preprocessed)
} else {
macro.isFunction = false;
}
- int start = index;
+ qsizetype start = index;
until(PP_NEWLINE);
macro.symbols.reserve(index - start - 1);
// remove whitespace where there shouldn't be any:
// Before and after the macro, after a # and around ##
Token lastToken = HASH; // skip shitespace at the beginning
- for (int i = start; i < index - 1; ++i) {
+ for (qsizetype i = start; i < index - 1; ++i) {
Token token = symbols.at(i).token;
if (token == WHITESPACE) {
if (lastToken == PP_HASH || lastToken == HASH ||
diff --git a/src/tools/moc/preprocessor.h b/src/tools/moc/preprocessor.h
index 84186fec9e..3509e83dce 100644
--- a/src/tools/moc/preprocessor.h
+++ b/src/tools/moc/preprocessor.h
@@ -20,11 +20,7 @@ struct Macro
Symbols symbols;
};
-#ifdef USE_LEXEM_STORE
-typedef QByteArray MacroName;
-#else
typedef SubArray MacroName;
-#endif
typedef QHash<MacroName, Macro> Macros;
class QFile;
@@ -48,8 +44,9 @@ public:
void substituteUntilNewline(Symbols &substituted);
static Symbols macroExpandIdentifier(Preprocessor *that, SymbolStack &symbols, int lineNum, QByteArray *macroName);
- static void macroExpand(Symbols *into, Preprocessor *that, const Symbols &toExpand, int &index, int lineNum, bool one,
- const QSet<QByteArray> &excludeSymbols = QSet<QByteArray>());
+ static void macroExpand(Symbols *into, Preprocessor *that, const Symbols &toExpand,
+ qsizetype &index, int lineNum, bool one,
+ const QSet<QByteArray> &excludeSymbols = QSet<QByteArray>());
int evaluateCondition();
diff --git a/src/tools/moc/symbols.h b/src/tools/moc/symbols.h
index cde01cf11d..869f7c793f 100644
--- a/src/tools/moc/symbols.h
+++ b/src/tools/moc/symbols.h
@@ -7,7 +7,7 @@
#include "token.h"
#include <qdebug.h>
-#include <qhash.h>
+#include <qhashfunctions.h>
#include <qlist.h>
#include <qstack.h>
#include <qstring.h>
@@ -15,73 +15,48 @@
QT_BEGIN_NAMESPACE
-//#define USE_LEXEM_STORE
-
struct SubArray
{
- inline SubArray():from(0),len(-1){}
+ inline SubArray() = default;
inline SubArray(const QByteArray &a):array(a),from(0), len(a.size()){}
inline SubArray(const char *s):array(s),from(0) { len = array.size(); }
- inline SubArray(const QByteArray &a, int from, int len):array(a), from(from), len(len){}
+ SubArray(const QByteArray &a, qsizetype from, qsizetype len)
+ : array(a), from(from), len(len)
+ {
+ }
QByteArray array;
- int from, len;
+ qsizetype from = 0;
+ qsizetype len = -1;
inline bool operator==(const SubArray &other) const {
if (len != other.len)
return false;
- for (int i = 0; i < len; ++i)
- if (array.at(from + i) != other.array.at(other.from + i))
- return false;
- return true;
+ const auto begin = array.cbegin() + from;
+ const auto end = begin + len;
+ const auto other_begin = other.array.cbegin() + other.from;
+ return std::equal(begin, end, other_begin);
}
};
-inline size_t qHash(const SubArray &key)
+inline size_t qHash(const SubArray &key, size_t seed = 0)
{
- return qHash(QLatin1StringView(key.array.constData() + key.from, key.len));
+ return qHash(QLatin1StringView(key.array.constData() + key.from, key.len), seed);
}
struct Symbol
{
-
-#ifdef USE_LEXEM_STORE
- typedef QHash<SubArray, QHashDummyValue> LexemStore;
- static LexemStore lexemStore;
-
- inline Symbol() : lineNum(-1),token(NOTOKEN){}
- inline Symbol(int lineNum, Token token):
- lineNum(lineNum), token(token){}
- inline Symbol(int lineNum, Token token, const QByteArray &lexem):
- lineNum(lineNum), token(token),lex(lexem){}
- inline Symbol(int lineNum, Token token, const QByteArray &lexem, int from, int len):
- lineNum(lineNum), token(token){
- LexemStore::const_iterator it = lexemStore.constFind(SubArray(lexem, from, len));
-
- if (it != lexemStore.constEnd()) {
- lex = it.key().array;
- } else {
- lex = lexem.mid(from, len);
- lexemStore.insert(lex, QHashDummyValue());
- }
+ inline Symbol() = default;
+ inline Symbol(int lineNum, Token token) : lineNum(lineNum), token(token) { }
+ inline Symbol(int lineNum, Token token, const QByteArray &lexem)
+ : lineNum(lineNum), token(token), lex(lexem), len(lex.size())
+ {
}
- int lineNum;
- Token token;
- inline QByteArray unquotedLexem() const { return lex.mid(1, lex.length()-2); }
- inline QByteArray lexem() const { return lex; }
- inline operator QByteArray() const { return lex; }
- QByteArray lex;
-
-#else
-
- inline Symbol() : lineNum(-1),token(NOTOKEN), from(0),len(-1) {}
- inline Symbol(int lineNum, Token token):
- lineNum(lineNum), token(token), from(0), len(-1) {}
- inline Symbol(int lineNum, Token token, const QByteArray &lexem):
- lineNum(lineNum), token(token), lex(lexem), from(0) { len = lex.size(); }
- inline Symbol(int lineNum, Token token, const QByteArray &lexem, int from, int len):
- lineNum(lineNum), token(token),lex(lexem),from(from), len(len){}
- int lineNum;
- Token token;
+ Symbol(int lineNum, Token token, const QByteArray &lexem, qsizetype from, qsizetype len)
+ : lineNum(lineNum), token(token), lex(lexem), from(from), len(len)
+ {
+ }
+ int lineNum = -1;
+ Token token = NOTOKEN;
inline QByteArray lexem() const { return lex.mid(from, len); }
inline QByteArray unquotedLexem() const { return lex.mid(from+1, len-2); }
inline operator SubArray() const { return SubArray(lex, from, len); }
@@ -90,9 +65,8 @@ struct Symbol
return SubArray(lex, from, len) == SubArray(o.lex, o.from, o.len);
}
QByteArray lex;
- int from, len;
-
-#endif
+ qsizetype from = 0;
+ qsizetype len = -1;
};
Q_DECLARE_TYPEINFO(Symbol, Q_RELOCATABLE_TYPE);
@@ -102,7 +76,7 @@ struct SafeSymbols {
Symbols symbols;
QByteArray expandedMacro;
QSet<QByteArray> excludedSymbols;
- int index;
+ qsizetype index;
};
Q_DECLARE_TYPEINFO(SafeSymbols, Q_RELOCATABLE_TYPE);
@@ -127,13 +101,13 @@ public:
inline QByteArray lexem() const { return symbol().lexem(); }
inline QByteArray unquotedLexem() { return symbol().unquotedLexem(); }
- bool dontReplaceSymbol(const QByteArray &name);
- QSet<QByteArray> excludeSymbols();
+ bool dontReplaceSymbol(const QByteArray &name) const;
+ QSet<QByteArray> excludeSymbols() const;
};
inline bool SymbolStack::test(Token token)
{
- int stackPos = size() - 1;
+ qsizetype stackPos = size() - 1;
while (stackPos >= 0 && at(stackPos).index >= at(stackPos).symbols.size())
--stackPos;
if (stackPos < 0)
@@ -145,21 +119,20 @@ inline bool SymbolStack::test(Token token)
return false;
}
-inline bool SymbolStack::dontReplaceSymbol(const QByteArray &name)
+inline bool SymbolStack::dontReplaceSymbol(const QByteArray &name) const
{
- for (int i = 0; i < size(); ++i) {
- if (name == at(i).expandedMacro || at(i).excludedSymbols.contains(name))
- return true;
- }
- return false;
+ auto matchesName = [&name](const SafeSymbols &sf) {
+ return name == sf.expandedMacro || sf.excludedSymbols.contains(name);
+ };
+ return std::any_of(cbegin(), cend(), matchesName);
}
-inline QSet<QByteArray> SymbolStack::excludeSymbols()
+inline QSet<QByteArray> SymbolStack::excludeSymbols() const
{
QSet<QByteArray> set;
- for (int i = 0; i < size(); ++i) {
- set << at(i).expandedMacro;
- set += at(i).excludedSymbols;
+ for (const SafeSymbols &sf : *this) {
+ set << sf.expandedMacro;
+ set += sf.excludedSymbols;
}
return set;
}
diff --git a/src/tools/moc/util/generate.sh b/src/tools/moc/util/generate.sh
index 4514ca4930..6be06e5a91 100755
--- a/src/tools/moc/util/generate.sh
+++ b/src/tools/moc/util/generate.sh
@@ -6,7 +6,7 @@ set -ex
qmake
make
-cat licenseheader.txt > ../keywords.cpp
-cat licenseheader.txt > ../ppkeywords.cpp
+cat licenseheader.cpp.in > ../keywords.cpp
+cat licenseheader.cpp.in > ../ppkeywords.cpp
./generate_keywords >> ../keywords.cpp
./generate_keywords preprocessor >> ../ppkeywords.cpp
diff --git a/src/tools/moc/util/licenseheader.txt b/src/tools/moc/util/licenseheader.cpp.in
index 42958a66f5..42958a66f5 100644
--- a/src/tools/moc/util/licenseheader.txt
+++ b/src/tools/moc/util/licenseheader.cpp.in
diff --git a/src/tools/moc/utils.h b/src/tools/moc/utils.h
index 358780a33d..0b0d70f462 100644
--- a/src/tools/moc/utils.h
+++ b/src/tools/moc/utils.h
@@ -5,6 +5,9 @@
#define UTILS_H
#include <QtCore/qglobal.h>
+#include <private/qtools_p.h>
+
+#include <algorithm>
QT_BEGIN_NAMESPACE
@@ -20,49 +23,20 @@ inline bool is_space(char s)
inline bool is_ident_start(char s)
{
- return ((s >= 'a' && s <= 'z')
- || (s >= 'A' && s <= 'Z')
- || s == '_' || s == '$'
- );
+ using namespace QtMiscUtils;
+ return isAsciiLower(s) || isAsciiUpper(s) || s == '_' || s == '$';
}
inline bool is_ident_char(char s)
{
- return ((s >= 'a' && s <= 'z')
- || (s >= 'A' && s <= 'Z')
- || (s >= '0' && s <= '9')
- || s == '_' || s == '$'
- );
+ return QtMiscUtils::isAsciiLetterOrNumber(s) || s == '_' || s == '$';
}
-inline bool is_identifier(const char *s, int len)
+inline bool is_identifier(const char *s, qsizetype len)
{
if (len < 1)
return false;
- if (!is_ident_start(*s))
- return false;
- for (int i = 1; i < len; ++i)
- if (!is_ident_char(s[i]))
- return false;
- return true;
-}
-
-inline bool is_digit_char(char s)
-{
- return (s >= '0' && s <= '9');
-}
-
-inline bool is_octal_char(char s)
-{
- return (s >= '0' && s <= '7');
-}
-
-inline bool is_hex_char(char s)
-{
- return ((s >= 'a' && s <= 'f')
- || (s >= 'A' && s <= 'F')
- || (s >= '0' && s <= '9')
- );
+ return std::all_of(s, s + len, is_ident_char);
}
inline const char *skipQuote(const char *data)
diff --git a/src/tools/qdbuscpp2xml/CMakeLists.txt b/src/tools/qdbuscpp2xml/CMakeLists.txt
index 59677288c7..781c1835bc 100644
--- a/src/tools/qdbuscpp2xml/CMakeLists.txt
+++ b/src/tools/qdbuscpp2xml/CMakeLists.txt
@@ -7,6 +7,8 @@
qt_get_tool_target_name(target_name qdbuscpp2xml)
qt_internal_add_tool(${target_name}
+ TRY_RUN
+ TRY_RUN_FLAGS "-V"
TARGET_DESCRIPTION "Qt D-Bus C++ to XML Compiler"
TOOLS_TARGET DBus
SOURCES
diff --git a/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp
index 1a45685515..3b7d73894b 100644
--- a/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp
+++ b/src/tools/qdbuscpp2xml/qdbuscpp2xml.cpp
@@ -15,6 +15,7 @@
#include <qdbusconnection.h> // for the Export* flags
#include <private/qdbusconnection_p.h> // for the qDBusCheckAsyncTag
+#include <private/qdbusmetatype_p.h> // for QDBusMetaTypeId::init()
using namespace Qt::StringLiterals;
@@ -184,6 +185,8 @@ static QString generateInterfaceXml(const ClassDef *mo)
access |= 1;
if (!mp.write.isEmpty())
access |= 2;
+ if (!mp.member.isEmpty())
+ access |= 3;
int typeId = QMetaType::fromName(mp.type).id();
if (!typeId) {
@@ -429,16 +432,30 @@ int main(int argc, char **argv)
args.append(QString::fromLocal8Bit(argv[n]));
parseCmdLine(args);
+ QDBusMetaTypeId::init();
+
QList<ClassDef> classes;
+ if (args.isEmpty())
+ args << u"-"_s;
for (const auto &arg: std::as_const(args)) {
- if (arg.startsWith(u'-'))
+ if (arg.startsWith(u'-') && arg.size() > 1)
continue;
- QFile f(arg);
- if (!f.open(QIODevice::ReadOnly|QIODevice::Text)) {
+ QFile f;
+ bool fileIsOpen;
+ QString fileName;
+ if (arg == u'-') {
+ fileName = "stdin"_L1;
+ fileIsOpen = f.open(stdin, QIODevice::ReadOnly | QIODevice::Text);
+ } else {
+ fileName = arg;
+ f.setFileName(arg);
+ fileIsOpen = f.open(QIODevice::ReadOnly | QIODevice::Text);
+ }
+ if (!fileIsOpen) {
fprintf(stderr, PROGRAMNAME ": could not open '%s': %s\n",
- qPrintable(arg), qPrintable(f.errorString()));
+ qPrintable(fileName), qPrintable(f.errorString()));
return 1;
}
@@ -464,11 +481,15 @@ int main(int argc, char **argv)
QFile output;
if (outputFile.isEmpty()) {
- output.open(stdout, QIODevice::WriteOnly);
+ if (!output.open(stdout, QIODevice::WriteOnly)) {
+ fprintf(stderr, PROGRAMNAME ": could not open standard output: %s\n",
+ qPrintable(output.errorString()));
+ return 1;
+ }
} else {
output.setFileName(outputFile);
if (!output.open(QIODevice::WriteOnly)) {
- fprintf(stderr, PROGRAMNAME ": could not open output file '%s': %s",
+ fprintf(stderr, PROGRAMNAME ": could not open output file '%s': %s\n",
qPrintable(outputFile), qPrintable(output.errorString()));
return 1;
}
diff --git a/src/tools/qdbusxml2cpp/CMakeLists.txt b/src/tools/qdbusxml2cpp/CMakeLists.txt
index 05acd0329c..0da22ebfc6 100644
--- a/src/tools/qdbusxml2cpp/CMakeLists.txt
+++ b/src/tools/qdbusxml2cpp/CMakeLists.txt
@@ -7,6 +7,7 @@
qt_get_tool_target_name(target_name qdbusxml2cpp)
qt_internal_add_tool(${target_name}
+ TRY_RUN
TARGET_DESCRIPTION "Qt D-Bus XML to C++ Compiler"
TOOLS_TARGET DBus
SOURCES
diff --git a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp
index 76ed60402b..d637854d2b 100644
--- a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp
+++ b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp
@@ -27,18 +27,69 @@
using namespace Qt::StringLiterals;
-static QString globalClassName;
-static QString parentClassName;
-static QString proxyFile;
-static QString adaptorFile;
-static QString inputFile;
-static bool skipNamespaces;
-static bool verbose;
-static bool includeMocs;
-static QString commandLine;
-static QStringList includes;
-static QStringList globalIncludes;
-static QStringList wantedInterfaces;
+class QDBusXmlToCpp final
+{
+public:
+ int run(const QCoreApplication &app);
+
+private:
+ class DiagnosticsReporter final : public QDBusIntrospection::DiagnosticsReporter
+ {
+ public:
+ void setFileName(const QString &fileName) { m_fileName = fileName; }
+ bool hadErrors() const { return m_hadErrors; }
+
+ void warning(const QDBusIntrospection::SourceLocation &location, const char *msg,
+ ...) override;
+ void error(const QDBusIntrospection::SourceLocation &location, const char *msg,
+ ...) override;
+ void note(const QDBusIntrospection::SourceLocation &location, const char *msg, ...)
+ Q_ATTRIBUTE_FORMAT_PRINTF(3, 4);
+
+ private:
+ QString m_fileName;
+ bool m_hadErrors = false;
+
+ void report(const QDBusIntrospection::SourceLocation &location, const char *msg, va_list ap,
+ const char *severity);
+ };
+
+ enum ClassType { Proxy, Adaptor };
+
+ void writeAdaptor(const QString &filename, const QDBusIntrospection::Interfaces &interfaces);
+ void writeProxy(const QString &filename, const QDBusIntrospection::Interfaces &interfaces);
+
+ QDBusIntrospection::Interfaces readInput();
+ void cleanInterfaces(QDBusIntrospection::Interfaces &interfaces);
+ QTextStream &writeHeader(QTextStream &ts, bool changesWillBeLost);
+ QString classNameForInterface(const QString &interface, ClassType classType);
+ QByteArray qtTypeName(const QDBusIntrospection::SourceLocation &location,
+ const QString &signature,
+ const QDBusIntrospection::Annotations &annotations,
+ qsizetype paramId = -1, const char *direction = "Out");
+ void
+ writeArgList(QTextStream &ts, const QStringList &argNames,
+ const QDBusIntrospection::Annotations &annotations,
+ const QDBusIntrospection::Arguments &inputArgs,
+ const QDBusIntrospection::Arguments &outputArgs = QDBusIntrospection::Arguments());
+ void writeSignalArgList(QTextStream &ts, const QStringList &argNames,
+ const QDBusIntrospection::Annotations &annotations,
+ const QDBusIntrospection::Arguments &outputArgs);
+ QString propertyGetter(const QDBusIntrospection::Property &property);
+ QString propertySetter(const QDBusIntrospection::Property &property);
+
+ QString globalClassName;
+ QString parentClassName;
+ QString inputFile;
+ bool skipNamespaces = false;
+ bool includeMocs = false;
+ QString commandLine;
+ QStringList includes;
+ QStringList globalIncludes;
+ QStringList wantedInterfaces;
+
+ DiagnosticsReporter reporter;
+};
static const char includeList[] =
"#include <QtCore/QByteArray>\n"
@@ -51,29 +102,71 @@ static const char includeList[] =
static const char forwardDeclarations[] =
"#include <QtCore/qcontainerfwd.h>\n";
-static QDBusIntrospection::Interfaces readInput()
+void QDBusXmlToCpp::DiagnosticsReporter::warning(const QDBusIntrospection::SourceLocation &location,
+ const char *msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ report(location, msg, ap, "warning");
+ va_end(ap);
+}
+
+void QDBusXmlToCpp::DiagnosticsReporter::error(const QDBusIntrospection::SourceLocation &location,
+ const char *msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ report(location, msg, ap, "error");
+ va_end(ap);
+ m_hadErrors = true;
+}
+
+void QDBusXmlToCpp::DiagnosticsReporter::note(const QDBusIntrospection::SourceLocation &location,
+ const char *msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ report(location, msg, ap, "note");
+ va_end(ap);
+ m_hadErrors = true;
+}
+
+void QDBusXmlToCpp::DiagnosticsReporter::report(const QDBusIntrospection::SourceLocation &location,
+ const char *msg, va_list ap, const char *severity)
+{
+ fprintf(stderr, "%s:%lld:%lld: %s: ", qPrintable(m_fileName),
+ (long long int)location.lineNumber, (long long int)location.columnNumber + 1, severity);
+ vfprintf(stderr, msg, ap);
+}
+
+QDBusIntrospection::Interfaces QDBusXmlToCpp::readInput()
{
QFile input(inputFile);
- if (inputFile.isEmpty() || inputFile == "-"_L1)
- input.open(stdin, QIODevice::ReadOnly);
- else
- input.open(QIODevice::ReadOnly);
+ if (inputFile.isEmpty() || inputFile == "-"_L1) {
+ reporter.setFileName("<standard input>"_L1);
+ if (!input.open(stdin, QIODevice::ReadOnly)) {
+ fprintf(stderr, PROGRAMNAME ": could not open standard input: %s\n",
+ qPrintable(input.errorString()));
+ exit(1);
+ }
+ } else {
+ reporter.setFileName(inputFile);
+ if (!input.open(QIODevice::ReadOnly)) {
+ fprintf(stderr, PROGRAMNAME ": could not open input file '%s': %s\n",
+ qPrintable(inputFile), qPrintable(input.errorString()));
+ exit(1);
+ }
+ }
QByteArray data = input.readAll();
+ auto interfaces = QDBusIntrospection::parseInterfaces(QString::fromUtf8(data), &reporter);
+ if (reporter.hadErrors())
+ exit(1);
- // check if the input is already XML
- data = data.trimmed();
- if (data.startsWith("<!DOCTYPE ") || data.startsWith("<?xml") ||
- data.startsWith("<node") || data.startsWith("<interface"))
- // already XML
- return QDBusIntrospection::parseInterfaces(QString::fromUtf8(data));
-
- fprintf(stderr, "%s: Cannot process input: '%s'. Stop.\n",
- PROGRAMNAME, qPrintable(inputFile));
- exit(1);
+ return interfaces;
}
-static void cleanInterfaces(QDBusIntrospection::Interfaces &interfaces)
+void QDBusXmlToCpp::cleanInterfaces(QDBusIntrospection::Interfaces &interfaces)
{
if (!wantedInterfaces.isEmpty()) {
QDBusIntrospection::Interfaces::Iterator it = interfaces.begin();
@@ -179,30 +272,29 @@ static QString moc(const QString &name)
return retval;
}
-static QTextStream &writeHeader(QTextStream &ts, bool changesWillBeLost)
+QTextStream &QDBusXmlToCpp::writeHeader(QTextStream &ts, bool changesWillBeLost)
{
- ts << "/*" << Qt::endl
- << " * This file was generated by " PROGRAMNAME " version " PROGRAMVERSION << Qt::endl
- << " * Command line was: " << commandLine << Qt::endl
- << " *" << Qt::endl
- << " * " PROGRAMNAME " is " PROGRAMCOPYRIGHT << Qt::endl
- << " *" << Qt::endl
- << " * This is an auto-generated file." << Qt::endl;
+ ts << "/*\n"
+ " * This file was generated by " PROGRAMNAME " version " PROGRAMVERSION "\n"
+ " * Source file was " << QFileInfo(inputFile).fileName() << "\n"
+ " *\n"
+ " * " PROGRAMNAME " is " PROGRAMCOPYRIGHT "\n"
+ " *\n"
+ " * This is an auto-generated file.\n";
if (changesWillBeLost)
- ts << " * Do not edit! All changes made to it will be lost." << Qt::endl;
+ ts << " * Do not edit! All changes made to it will be lost.\n";
else
- ts << " * This file may have been hand-edited. Look for HAND-EDIT comments" << Qt::endl
- << " * before re-generating it." << Qt::endl;
+ ts << " * This file may have been hand-edited. Look for HAND-EDIT comments\n"
+ " * before re-generating it.\n";
- ts << " */" << Qt::endl
- << Qt::endl;
+ ts << " */\n\n";
return ts;
}
-enum ClassType { Proxy, Adaptor };
-static QString classNameForInterface(const QString &interface, ClassType classType)
+QString QDBusXmlToCpp::classNameForInterface(const QString &interface,
+ QDBusXmlToCpp::ClassType classType)
{
if (!globalClassName.isEmpty())
return globalClassName;
@@ -227,39 +319,39 @@ static QString classNameForInterface(const QString &interface, ClassType classTy
return retval;
}
-static QByteArray qtTypeName(const QString &where, const QString &signature,
- const QDBusIntrospection::Annotations &annotations, qsizetype paramId = -1,
- const char *direction = "Out")
+QByteArray QDBusXmlToCpp::qtTypeName(const QDBusIntrospection::SourceLocation &location,
+ const QString &signature,
+ const QDBusIntrospection::Annotations &annotations,
+ qsizetype paramId, const char *direction)
{
int type = QDBusMetaType::signatureToMetaType(signature.toLatin1()).id();
if (type == QMetaType::UnknownType) {
- QString annotationName = QString::fromLatin1("org.qtproject.QtDBus.QtTypeName");
+ QString annotationName = u"org.qtproject.QtDBus.QtTypeName"_s;
if (paramId >= 0)
- annotationName += QString::fromLatin1(".%1%2").arg(QLatin1StringView(direction)).arg(paramId);
- QString qttype = annotations.value(annotationName);
+ annotationName += ".%1%2"_L1.arg(QLatin1StringView(direction)).arg(paramId);
+ auto annotation = annotations.value(annotationName);
+ QString qttype = annotation.value;
if (!qttype.isEmpty())
return std::move(qttype).toLatin1();
- QString oldAnnotationName = QString::fromLatin1("com.trolltech.QtDBus.QtTypeName");
+ QString oldAnnotationName = u"com.trolltech.QtDBus.QtTypeName"_s;
if (paramId >= 0)
- oldAnnotationName += QString::fromLatin1(".%1%2").arg(QLatin1StringView(direction)).arg(paramId);
- qttype = annotations.value(oldAnnotationName);
+ oldAnnotationName += ".%1%2"_L1.arg(QLatin1StringView(direction)).arg(paramId);
+ annotation = annotations.value(oldAnnotationName);
+ qttype = annotation.value;
if (qttype.isEmpty()) {
- fprintf(stderr, "%s: Got unknown type `%s' processing '%s'\n",
- PROGRAMNAME, qPrintable(signature), qPrintable(inputFile));
- fprintf(stderr,
- "You should add <annotation name=\"%s\" value=\"<type>\"/> to the XML "
- "description for '%s'\n",
- qPrintable(annotationName), qPrintable(where));
+ reporter.error(location, "unknown type `%s'\n", qPrintable(signature));
+ reporter.note(location, "you should add <annotation name=\"%s\" value=\"<type>\"/>\n",
+ qPrintable(annotationName));
exit(1);
}
- fprintf(stderr, "%s: Warning: deprecated annotation '%s' found while processing '%s'; "
- "suggest updating to '%s'\n",
- PROGRAMNAME, qPrintable(oldAnnotationName), qPrintable(inputFile),
- qPrintable(annotationName));
+ reporter.warning(annotation.location, "deprecated annotation '%s' found\n",
+ qPrintable(oldAnnotationName));
+ reporter.note(annotation.location, "suggest updating to '%s'\n",
+ qPrintable(annotationName));
return std::move(qttype).toLatin1();
}
@@ -320,17 +412,17 @@ static QStringList makeArgNames(const QDBusIntrospection::Arguments &inputArgs,
return retval;
}
-static void writeArgList(QTextStream &ts, const QStringList &argNames,
- const QDBusIntrospection::Annotations &annotations,
- const QDBusIntrospection::Arguments &inputArgs,
- const QDBusIntrospection::Arguments &outputArgs = QDBusIntrospection::Arguments())
+void QDBusXmlToCpp::writeArgList(QTextStream &ts, const QStringList &argNames,
+ const QDBusIntrospection::Annotations &annotations,
+ const QDBusIntrospection::Arguments &inputArgs,
+ const QDBusIntrospection::Arguments &outputArgs)
{
// input args:
bool first = true;
qsizetype argPos = 0;
for (qsizetype i = 0; i < inputArgs.size(); ++i) {
const QDBusIntrospection::Argument &arg = inputArgs.at(i);
- QString type = constRefArg(qtTypeName(arg.name, arg.type, annotations, i, "In"));
+ QString type = constRefArg(qtTypeName(arg.location, arg.type, annotations, i, "In"));
if (!first)
ts << ", ";
@@ -347,22 +439,21 @@ static void writeArgList(QTextStream &ts, const QStringList &argNames,
if (!first)
ts << ", ";
- ts << nonConstRefArg(qtTypeName(arg.name, arg.type, annotations, i, "Out"))
+ ts << nonConstRefArg(qtTypeName(arg.location, arg.type, annotations, i, "Out"))
<< argNames.at(argPos++);
first = false;
}
}
-static void writeSignalArgList(QTextStream &ts, const QStringList &argNames,
- const QDBusIntrospection::Annotations &annotations,
- const QDBusIntrospection::Arguments &outputArgs)
+void QDBusXmlToCpp::writeSignalArgList(QTextStream &ts, const QStringList &argNames,
+ const QDBusIntrospection::Annotations &annotations,
+ const QDBusIntrospection::Arguments &outputArgs)
{
bool first = true;
qsizetype argPos = 0;
for (qsizetype i = 0; i < outputArgs.size(); ++i) {
const QDBusIntrospection::Argument &arg = outputArgs.at(i);
- QString type = constRefArg(
- qtTypeName(arg.name, arg.type, annotations, i, "Out"));
+ QString type = constRefArg(qtTypeName(arg.location, arg.type, annotations, i, "Out"));
if (!first)
ts << ", ";
@@ -371,49 +462,49 @@ static void writeSignalArgList(QTextStream &ts, const QStringList &argNames,
}
}
-static QString propertyGetter(const QDBusIntrospection::Property &property)
+QString QDBusXmlToCpp::propertyGetter(const QDBusIntrospection::Property &property)
{
- QString getter = property.annotations.value("org.qtproject.QtDBus.PropertyGetter"_L1);
- if (!getter.isEmpty())
- return getter;
-
- getter = property.annotations.value("com.trolltech.QtDBus.propertyGetter"_L1);
- if (!getter.isEmpty()) {
- fprintf(stderr, "%s: Warning: deprecated annotation 'com.trolltech.QtDBus.propertyGetter' found"
- " while processing '%s';"
- " suggest updating to 'org.qtproject.QtDBus.PropertyGetter'\n",
- PROGRAMNAME, qPrintable(inputFile));
- return getter;
+ auto annotation = property.annotations.value("org.qtproject.QtDBus.PropertyGetter"_L1);
+ if (!annotation.value.isEmpty())
+ return annotation.value;
+
+ annotation = property.annotations.value("com.trolltech.QtDBus.propertyGetter"_L1);
+ if (!annotation.value.isEmpty()) {
+ reporter.warning(annotation.location,
+ "deprecated annotation 'com.trolltech.QtDBus.propertyGetter' found\n");
+ reporter.note(annotation.location,
+ "suggest updating to 'org.qtproject.QtDBus.PropertyGetter'\n");
+ return annotation.value;
}
- getter = property.name;
+ QString getter = property.name;
getter[0] = getter[0].toLower();
return getter;
}
-static QString propertySetter(const QDBusIntrospection::Property &property)
+QString QDBusXmlToCpp::propertySetter(const QDBusIntrospection::Property &property)
{
- QString setter = property.annotations.value("org.qtproject.QtDBus.PropertySetter"_L1);
- if (!setter.isEmpty())
- return setter;
-
- setter = property.annotations.value("com.trolltech.QtDBus.propertySetter"_L1);
- if (!setter.isEmpty()) {
- fprintf(stderr, "%s: Warning: deprecated annotation 'com.trolltech.QtDBus.propertySetter' found"
- " while processing '%s';"
- " suggest updating to 'org.qtproject.QtDBus.PropertySetter'\n",
- PROGRAMNAME, qPrintable(inputFile));
- return setter;
+ auto annotation = property.annotations.value("org.qtproject.QtDBus.PropertySetter"_L1);
+ if (!annotation.value.isEmpty())
+ return annotation.value;
+
+ annotation = property.annotations.value("com.trolltech.QtDBus.propertySetter"_L1);
+ if (!annotation.value.isEmpty()) {
+ reporter.warning(annotation.location,
+ "deprecated annotation 'com.trolltech.QtDBus.propertySetter' found\n");
+ reporter.note(annotation.location,
+ "suggest updating to 'org.qtproject.QtDBus.PropertySetter'\n");
+ return annotation.value;
}
- setter = "set"_L1 + property.name;
+ QString setter = "set"_L1 + property.name;
setter[3] = setter[3].toUpper();
return setter;
}
static QString methodName(const QDBusIntrospection::Method &method)
{
- QString name = method.annotations.value(QStringLiteral("org.qtproject.QtDBus.MethodName"));
+ QString name = method.annotations.value(u"org.qtproject.QtDBus.MethodName"_s).value;
if (!name.isEmpty())
return name;
@@ -457,7 +548,8 @@ static bool openFile(const QString &fileName, QFile &file)
return isOk;
}
-static void writeProxy(const QString &filename, const QDBusIntrospection::Interfaces &interfaces)
+void QDBusXmlToCpp::writeProxy(const QString &filename,
+ const QDBusIntrospection::Interfaces &interfaces)
{
// open the file
QString headerName = header(filename);
@@ -484,81 +576,74 @@ static void writeProxy(const QString &filename, const QDBusIntrospection::Interf
includeGuard = u"QDBUSXML2CPP_PROXY"_s;
}
- hs << "#ifndef " << includeGuard << Qt::endl
- << "#define " << includeGuard << Qt::endl
- << Qt::endl;
+ hs << "#ifndef " << includeGuard << "\n"
+ "#define " << includeGuard << "\n\n";
// include our stuff:
- hs << "#include <QtCore/QObject>" << Qt::endl
+ hs << "#include <QtCore/QObject>\n"
<< includeList;
#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
- hs << "#include <QtDBus/QtDBus>" << Qt::endl;
+ hs << "#include <QtDBus/QtDBus>\n";
#else
- hs << "#include <QtDBus/QDBusAbstractInterface>" << Qt::endl;
- hs << "#include <QtDBus/QDBusPendingReply>" << Qt::endl;
+ hs << "#include <QtDBus/QDBusAbstractInterface>\n"
+ "#include <QtDBus/QDBusPendingReply>\n";
#endif
for (const QString &include : std::as_const(includes)) {
- hs << "#include \"" << include << "\"" << Qt::endl;
+ hs << "#include \"" << include << "\"\n";
if (headerName.isEmpty())
- cs << "#include \"" << include << "\"" << Qt::endl;
+ cs << "#include \"" << include << "\"\n";
}
for (const QString &include : std::as_const(globalIncludes)) {
- hs << "#include <" << include << ">" << Qt::endl;
+ hs << "#include <" << include << ">\n";
if (headerName.isEmpty())
- cs << "#include <" << include << ">" << Qt::endl;
+ cs << "#include <" << include << ">\n";
}
- hs << Qt::endl;
+ hs << "\n";
if (cppName != headerName) {
if (!headerName.isEmpty() && headerName != "-"_L1)
- cs << "#include \"" << headerName << "\"" << Qt::endl << Qt::endl;
+ cs << "#include \"" << headerName << "\"\n\n";
}
for (const QDBusIntrospection::Interface *interface : interfaces) {
QString className = classNameForInterface(interface->name, Proxy);
// comment:
- hs << "/*" << Qt::endl
- << " * Proxy class for interface " << interface->name << Qt::endl
- << " */" << Qt::endl;
- cs << "/*" << Qt::endl
- << " * Implementation of interface class " << className << Qt::endl
- << " */" << Qt::endl
- << Qt::endl;
+ hs << "/*\n"
+ " * Proxy class for interface " << interface->name << "\n"
+ " */\n";
+ cs << "/*\n"
+ " * Implementation of interface class " << className << "\n"
+ " */\n\n";
// class header:
- hs << "class " << className << ": public QDBusAbstractInterface" << Qt::endl
- << "{" << Qt::endl
- << " Q_OBJECT" << Qt::endl;
+ hs << "class " << className << ": public QDBusAbstractInterface\n"
+ "{\n"
+ " Q_OBJECT\n";
// the interface name
- hs << "public:" << Qt::endl
- << " static inline const char *staticInterfaceName()" << Qt::endl
- << " { return \"" << interface->name << "\"; }" << Qt::endl
- << Qt::endl;
+ hs << "public:\n"
+ " static inline const char *staticInterfaceName()\n"
+ " { return \"" << interface->name << "\"; }\n\n";
// constructors/destructors:
- hs << "public:" << Qt::endl
- << " " << className << "(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);" << Qt::endl
- << Qt::endl
- << " ~" << className << "();" << Qt::endl
- << Qt::endl;
- cs << className << "::" << className << "(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)" << Qt::endl
- << " : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)" << Qt::endl
- << "{" << Qt::endl
- << "}" << Qt::endl
- << Qt::endl
- << className << "::~" << className << "()" << Qt::endl
- << "{" << Qt::endl
- << "}" << Qt::endl
- << Qt::endl;
+ hs << "public:\n"
+ " " << className << "(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);\n\n"
+ " ~" << className << "();\n\n";
+ cs << className << "::" << className << "(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)\n"
+ " : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)\n"
+ "{\n"
+ "}\n\n"
+ << className << "::~" << className << "()\n"
+ "{\n"
+ "}\n\n";
// properties:
for (const QDBusIntrospection::Property &property : interface->properties) {
- QByteArray type = qtTypeName(property.name, property.type, property.annotations);
+ QByteArray type = qtTypeName(property.location, property.type, property.annotations);
QString getter = propertyGetter(property);
QString setter = propertySetter(property);
@@ -574,35 +659,36 @@ static void writeProxy(const QString &filename, const QDBusIntrospection::Interf
// it's writeable
hs << " WRITE " << setter;
- hs << ")" << Qt::endl;
+ hs << ")\n";
// getter:
if (property.access != QDBusIntrospection::Property::Write) {
- hs << " inline " << type << " " << getter << "() const" << Qt::endl
- << " { return qvariant_cast< " << type << " >(property(\""
- << property.name << "\")); }" << Qt::endl;
+ hs << " inline " << type << " " << getter << "() const\n"
+ " { return qvariant_cast< " << type << " >(property(\""
+ << property.name << "\")); }\n";
}
// setter:
if (property.access != QDBusIntrospection::Property::Read) {
- hs << " inline void " << setter << "(" << constRefArg(type) << "value)" << Qt::endl
- << " { setProperty(\"" << property.name
- << "\", QVariant::fromValue(value)); }" << Qt::endl;
+ hs << " inline void " << setter << "(" << constRefArg(type) << "value)\n"
+ " { setProperty(\"" << property.name
+ << "\", QVariant::fromValue(value)); }\n";
}
- hs << Qt::endl;
+ hs << "\n";
}
// methods:
- hs << "public Q_SLOTS: // METHODS" << Qt::endl;
+ hs << "public Q_SLOTS: // METHODS\n";
for (const QDBusIntrospection::Method &method : interface->methods) {
- bool isDeprecated = method.annotations.value("org.freedesktop.DBus.Deprecated"_L1) == "true"_L1;
- bool isNoReply =
- method.annotations.value(ANNOTATION_NO_WAIT ""_L1) == "true"_L1;
+ bool isDeprecated = method.annotations.value("org.freedesktop.DBus.Deprecated"_L1).value
+ == "true"_L1;
+ bool isNoReply = method.annotations.value(ANNOTATION_NO_WAIT ""_L1).value == "true"_L1;
if (isNoReply && !method.outputArgs.isEmpty()) {
- fprintf(stderr, "%s: warning while processing '%s': method %s in interface %s is marked 'no-reply' but has output arguments.\n",
- PROGRAMNAME, qPrintable(inputFile), qPrintable(method.name),
- qPrintable(interface->name));
+ reporter.warning(method.location,
+ "method %s in interface %s is marked 'no-reply' but has output "
+ "arguments.\n",
+ qPrintable(method.name), qPrintable(interface->name));
continue;
}
@@ -617,8 +703,9 @@ static void writeProxy(const QString &filename, const QDBusIntrospection::Interf
hs << "inline QDBusPendingReply<";
for (qsizetype i = 0; i < method.outputArgs.size(); ++i)
hs << (i > 0 ? ", " : "")
- << templateArg(qtTypeName(method.outputArgs.at(i).name, method.outputArgs.at(i).type,
- method.annotations, i, "Out"));
+ << templateArg(qtTypeName(method.outputArgs.at(i).location,
+ method.outputArgs.at(i).type, method.annotations,
+ i, "Out"));
hs << "> ";
}
@@ -627,75 +714,77 @@ static void writeProxy(const QString &filename, const QDBusIntrospection::Interf
QStringList argNames = makeArgNames(method.inputArgs);
writeArgList(hs, argNames, method.annotations, method.inputArgs);
- hs << ")" << Qt::endl
- << " {" << Qt::endl
- << " QList<QVariant> argumentList;" << Qt::endl;
+ hs << ")\n"
+ " {\n"
+ " QList<QVariant> argumentList;\n";
if (!method.inputArgs.isEmpty()) {
hs << " argumentList";
for (qsizetype argPos = 0; argPos < method.inputArgs.size(); ++argPos)
hs << " << QVariant::fromValue(" << argNames.at(argPos) << ')';
- hs << ";" << Qt::endl;
+ hs << ";\n";
}
if (isNoReply)
hs << " callWithArgumentList(QDBus::NoBlock, "
- << "QStringLiteral(\"" << method.name << "\"), argumentList);" << Qt::endl;
+ "QStringLiteral(\"" << method.name << "\"), argumentList);\n";
else
hs << " return asyncCallWithArgumentList(QStringLiteral(\""
- << method.name << "\"), argumentList);" << Qt::endl;
+ << method.name << "\"), argumentList);\n";
// close the function:
- hs << " }" << Qt::endl;
+ hs << " }\n";
if (method.outputArgs.size() > 1) {
// generate the old-form QDBusReply methods with multiple incoming parameters
hs << (isDeprecated ? " Q_DECL_DEPRECATED " : " ") << "inline QDBusReply<"
- << templateArg(qtTypeName(method.outputArgs.first().name, method.outputArgs.first().type,
- method.annotations, 0, "Out"))
+ << templateArg(qtTypeName(method.outputArgs.first().location,
+ method.outputArgs.first().type, method.annotations, 0,
+ "Out"))
<< "> ";
hs << method.name << "(";
QStringList argNames = makeArgNames(method.inputArgs, method.outputArgs);
writeArgList(hs, argNames, method.annotations, method.inputArgs, method.outputArgs);
- hs << ")" << Qt::endl
- << " {" << Qt::endl
- << " QList<QVariant> argumentList;" << Qt::endl;
+ hs << ")\n"
+ " {\n"
+ " QList<QVariant> argumentList;\n";
qsizetype argPos = 0;
if (!method.inputArgs.isEmpty()) {
hs << " argumentList";
for (argPos = 0; argPos < method.inputArgs.size(); ++argPos)
hs << " << QVariant::fromValue(" << argNames.at(argPos) << ')';
- hs << ";" << Qt::endl;
+ hs << ";\n";
}
hs << " QDBusMessage reply = callWithArgumentList(QDBus::Block, "
- << "QStringLiteral(\"" << method.name << "\"), argumentList);" << Qt::endl;
+ "QStringLiteral(\"" << method.name << "\"), argumentList);\n";
argPos++;
hs << " if (reply.type() == QDBusMessage::ReplyMessage && reply.arguments().size() == "
- << method.outputArgs.size() << ") {" << Qt::endl;
+ << method.outputArgs.size() << ") {\n";
// yes, starting from 1
for (qsizetype i = 1; i < method.outputArgs.size(); ++i)
hs << " " << argNames.at(argPos++) << " = qdbus_cast<"
- << templateArg(qtTypeName(method.outputArgs.at(i).name, method.outputArgs.at(i).type,
- method.annotations, i, "Out"))
- << ">(reply.arguments().at(" << i << "));" << Qt::endl;
- hs << " }" << Qt::endl
- << " return reply;" << Qt::endl
- << " }" << Qt::endl;
+ << templateArg(qtTypeName(method.outputArgs.at(i).location,
+ method.outputArgs.at(i).type, method.annotations,
+ i, "Out"))
+ << ">(reply.arguments().at(" << i << "));\n";
+ hs << " }\n"
+ " return reply;\n"
+ " }\n";
}
- hs << Qt::endl;
+ hs << "\n";
}
- hs << "Q_SIGNALS: // SIGNALS" << Qt::endl;
+ hs << "Q_SIGNALS: // SIGNALS\n";
for (const QDBusIntrospection::Signal &signal : interface->signals_) {
hs << " ";
- if (signal.annotations.value("org.freedesktop.DBus.Deprecated"_L1) == "true"_L1)
+ if (signal.annotations.value("org.freedesktop.DBus.Deprecated"_L1).value == "true"_L1)
hs << "Q_DECL_DEPRECATED ";
hs << "void " << signal.name << "(";
@@ -703,12 +792,11 @@ static void writeProxy(const QString &filename, const QDBusIntrospection::Interf
QStringList argNames = makeArgNames(signal.outputArgs);
writeSignalArgList(hs, argNames, signal.annotations, signal.outputArgs);
- hs << ");" << Qt::endl; // finished for header
+ hs << ");\n"; // finished for header
}
// close the class:
- hs << "};" << Qt::endl
- << Qt::endl;
+ hs << "};\n\n";
}
if (!skipNamespaces) {
@@ -730,17 +818,17 @@ static void writeProxy(const QString &filename, const QDBusIntrospection::Interf
// i parts matched
// close last.arguments().size() - i namespaces:
for (qsizetype j = i; j < last.size(); ++j)
- hs << QString((last.size() - j - 1 + i) * 2, u' ') << "}" << Qt::endl;
+ hs << QString((last.size() - j - 1 + i) * 2, u' ') << "}\n";
// open current.arguments().size() - i namespaces
for (qsizetype j = i; j < current.size(); ++j)
- hs << QString(j * 2, u' ') << "namespace " << current.at(j) << " {" << Qt::endl;
+ hs << QString(j * 2, u' ') << "namespace " << current.at(j) << " {\n";
// add this class:
if (!name.isEmpty()) {
hs << QString(current.size() * 2, u' ')
<< "using " << name << " = ::" << classNameForInterface(it->constData()->name, Proxy)
- << ";" << Qt::endl;
+ << ";\n";
}
if (it == interfaces.constEnd())
@@ -751,12 +839,12 @@ static void writeProxy(const QString &filename, const QDBusIntrospection::Interf
}
// close the include guard
- hs << "#endif" << Qt::endl;
+ hs << "#endif\n";
QString mocName = moc(filename);
if (includeMocs && !mocName.isEmpty())
- cs << Qt::endl
- << "#include \"" << mocName << "\"" << Qt::endl;
+ cs << "\n"
+ "#include \"" << mocName << "\"\n";
cs.flush();
hs.flush();
@@ -776,7 +864,8 @@ static void writeProxy(const QString &filename, const QDBusIntrospection::Interf
}
}
-static void writeAdaptor(const QString &filename, const QDBusIntrospection::Interfaces &interfaces)
+void QDBusXmlToCpp::writeAdaptor(const QString &filename,
+ const QDBusIntrospection::Interfaces &interfaces)
{
// open the file
QString headerName = header(filename);
@@ -803,47 +892,46 @@ static void writeAdaptor(const QString &filename, const QDBusIntrospection::Inte
includeGuard = u"QDBUSXML2CPP_ADAPTOR"_s;
}
- hs << "#ifndef " << includeGuard << Qt::endl
- << "#define " << includeGuard << Qt::endl
- << Qt::endl;
+ hs << "#ifndef " << includeGuard << "\n"
+ "#define " << includeGuard << "\n\n";
// include our stuff:
- hs << "#include <QtCore/QObject>" << Qt::endl;
+ hs << "#include <QtCore/QObject>\n";
if (cppName == headerName)
- hs << "#include <QtCore/QMetaObject>" << Qt::endl
- << "#include <QtCore/QVariant>" << Qt::endl;
+ hs << "#include <QtCore/QMetaObject>\n"
+ "#include <QtCore/QVariant>\n";
#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
- hs << "#include <QtDBus/QtDBus>" << Qt::endl;
+ hs << "#include <QtDBus/QtDBus>\n";
#else
- hs << "#include <QtDBus/QDBusAbstractAdaptor>" << Qt::endl;
- hs << "#include <QtDBus/QDBusObjectPath>" << Qt::endl;
+ hs << "#include <QtDBus/QDBusAbstractAdaptor>\n"
+ "#include <QtDBus/QDBusObjectPath>\n";
#endif
for (const QString &include : std::as_const(includes)) {
- hs << "#include \"" << include << "\"" << Qt::endl;
+ hs << "#include \"" << include << "\"\n";
if (headerName.isEmpty())
- cs << "#include \"" << include << "\"" << Qt::endl;
+ cs << "#include \"" << include << "\"\n";
}
for (const QString &include : std::as_const(globalIncludes)) {
- hs << "#include <" << include << ">" << Qt::endl;
+ hs << "#include <" << include << ">\n";
if (headerName.isEmpty())
- cs << "#include <" << include << ">" << Qt::endl;
+ cs << "#include <" << include << ">\n";
}
if (cppName != headerName) {
if (!headerName.isEmpty() && headerName != "-"_L1)
- cs << "#include \"" << headerName << "\"" << Qt::endl;
+ cs << "#include \"" << headerName << "\"\n";
- cs << "#include <QtCore/QMetaObject>" << Qt::endl
+ cs << "#include <QtCore/QMetaObject>\n"
<< includeList
- << Qt::endl;
+ << "\n";
hs << forwardDeclarations;
} else {
hs << includeList;
}
- hs << Qt::endl;
+ hs << "\n";
QString parent = parentClassName;
if (parentClassName.isEmpty())
@@ -853,49 +941,44 @@ static void writeAdaptor(const QString &filename, const QDBusIntrospection::Inte
QString className = classNameForInterface(interface->name, Adaptor);
// comment:
- hs << "/*" << Qt::endl
- << " * Adaptor class for interface " << interface->name << Qt::endl
- << " */" << Qt::endl;
- cs << "/*" << Qt::endl
- << " * Implementation of adaptor class " << className << Qt::endl
- << " */" << Qt::endl
- << Qt::endl;
+ hs << "/*\n"
+ " * Adaptor class for interface " << interface->name << "\n"
+ " */\n";
+ cs << "/*\n"
+ " * Implementation of adaptor class " << className << "\n"
+ " */\n\n";
// class header:
- hs << "class " << className << ": public QDBusAbstractAdaptor" << Qt::endl
- << "{" << Qt::endl
- << " Q_OBJECT" << Qt::endl
- << " Q_CLASSINFO(\"D-Bus Interface\", \"" << interface->name << "\")" << Qt::endl
- << " Q_CLASSINFO(\"D-Bus Introspection\", \"\"" << Qt::endl
+ hs << "class " << className << ": public QDBusAbstractAdaptor\n"
+ "{\n"
+ " Q_OBJECT\n"
+ " Q_CLASSINFO(\"D-Bus Interface\", \"" << interface->name << "\")\n"
+ " Q_CLASSINFO(\"D-Bus Introspection\", \"\"\n"
<< stringify(interface->introspection)
- << " \"\")" << Qt::endl
- << "public:" << Qt::endl
- << " " << className << "(" << parent << " *parent);" << Qt::endl
- << " virtual ~" << className << "();" << Qt::endl
- << Qt::endl;
+ << " \"\")\n"
+ "public:\n"
+ " " << className << "(" << parent << " *parent);\n"
+ " ~" << className << "() override;\n\n";
if (!parentClassName.isEmpty())
- hs << " inline " << parent << " *parent() const" << Qt::endl
- << " { return static_cast<" << parent << " *>(QObject::parent()); }" << Qt::endl
- << Qt::endl;
+ hs << " inline " << parent << " *parent() const\n"
+ " { return static_cast<" << parent << " *>(QObject::parent()); }\n\n";
// constructor/destructor
- cs << className << "::" << className << "(" << parent << " *parent)" << Qt::endl
- << " : QDBusAbstractAdaptor(parent)" << Qt::endl
- << "{" << Qt::endl
- << " // constructor" << Qt::endl
- << " setAutoRelaySignals(true);" << Qt::endl
- << "}" << Qt::endl
- << Qt::endl
- << className << "::~" << className << "()" << Qt::endl
- << "{" << Qt::endl
- << " // destructor" << Qt::endl
- << "}" << Qt::endl
- << Qt::endl;
-
- hs << "public: // PROPERTIES" << Qt::endl;
+ cs << className << "::" << className << "(" << parent << " *parent)\n"
+ " : QDBusAbstractAdaptor(parent)\n"
+ "{\n"
+ " // constructor\n"
+ " setAutoRelaySignals(true);\n"
+ "}\n\n"
+ << className << "::~" << className << "()\n"
+ "{\n"
+ " // destructor\n"
+ "}\n\n";
+
+ hs << "public: // PROPERTIES\n";
for (const QDBusIntrospection::Property &property : interface->properties) {
- QByteArray type = qtTypeName(property.name, property.type, property.annotations);
+ QByteArray type = qtTypeName(property.location, property.type, property.annotations);
QString constRefType = constRefArg(type);
QString getter = propertyGetter(property);
QString setter = propertySetter(property);
@@ -905,44 +988,43 @@ static void writeAdaptor(const QString &filename, const QDBusIntrospection::Inte
hs << " READ " << getter;
if (property.access != QDBusIntrospection::Property::Read)
hs << " WRITE " << setter;
- hs << ")" << Qt::endl;
+ hs << ")\n";
// getter:
if (property.access != QDBusIntrospection::Property::Write) {
- hs << " " << type << " " << getter << "() const;" << Qt::endl;
+ hs << " " << type << " " << getter << "() const;\n";
cs << type << " "
- << className << "::" << getter << "() const" << Qt::endl
- << "{" << Qt::endl
- << " // get the value of property " << property.name << Qt::endl
- << " return qvariant_cast< " << type <<" >(parent()->property(\"" << property.name << "\"));" << Qt::endl
- << "}" << Qt::endl
- << Qt::endl;
+ << className << "::" << getter << "() const\n"
+ "{\n"
+ " // get the value of property " << property.name << "\n"
+ " return qvariant_cast< " << type <<" >(parent()->property(\"" << property.name << "\"));\n"
+ "}\n\n";
}
// setter
if (property.access != QDBusIntrospection::Property::Read) {
- hs << " void " << setter << "(" << constRefType << "value);" << Qt::endl;
- cs << "void " << className << "::" << setter << "(" << constRefType << "value)" << Qt::endl
- << "{" << Qt::endl
- << " // set the value of property " << property.name << Qt::endl
- << " parent()->setProperty(\"" << property.name << "\", QVariant::fromValue(value";
+ hs << " void " << setter << "(" << constRefType << "value);\n";
+ cs << "void " << className << "::" << setter << "(" << constRefType << "value)\n"
+ "{\n"
+ " // set the value of property " << property.name << "\n"
+ " parent()->setProperty(\"" << property.name << "\", QVariant::fromValue(value";
if (constRefType.contains("QDBusVariant"_L1))
cs << ".variant()";
- cs << "));" << Qt::endl
- << "}" << Qt::endl
- << Qt::endl;
+ cs << "));\n"
+ "}\n\n";
}
- hs << Qt::endl;
+ hs << "\n";
}
- hs << "public Q_SLOTS: // METHODS" << Qt::endl;
+ hs << "public Q_SLOTS: // METHODS\n";
for (const QDBusIntrospection::Method &method : interface->methods) {
- bool isNoReply =
- method.annotations.value(ANNOTATION_NO_WAIT ""_L1) == "true"_L1;
+ bool isNoReply = method.annotations.value(ANNOTATION_NO_WAIT ""_L1).value == "true"_L1;
if (isNoReply && !method.outputArgs.isEmpty()) {
- fprintf(stderr, "%s: warning while processing '%s': method %s in interface %s is marked 'no-reply' but has output arguments.\n",
- PROGRAMNAME, qPrintable(inputFile), qPrintable(method.name), qPrintable(interface->name));
+ reporter.warning(method.location,
+ "method %s in interface %s is marked 'no-reply' but has output "
+ "arguments.\n",
+ qPrintable(method.name), qPrintable(interface->name));
continue;
}
@@ -955,8 +1037,9 @@ static void writeAdaptor(const QString &filename, const QDBusIntrospection::Inte
hs << "void ";
cs << "void ";
} else {
- returnType = qtTypeName(method.outputArgs.first().name, method.outputArgs.first().type,
- method.annotations, 0, "Out");
+ returnType =
+ qtTypeName(method.outputArgs.first().location,
+ method.outputArgs.first().type, method.annotations, 0, "Out");
hs << returnType << " ";
cs << returnType << " ";
}
@@ -969,10 +1052,10 @@ static void writeAdaptor(const QString &filename, const QDBusIntrospection::Inte
writeArgList(hs, argNames, method.annotations, method.inputArgs, method.outputArgs);
writeArgList(cs, argNames, method.annotations, method.inputArgs, method.outputArgs);
- hs << ");" << Qt::endl; // finished for header
- cs << ")" << Qt::endl
- << "{" << Qt::endl
- << " // handle method call " << interface->name << "." << methodName(method) << Qt::endl;
+ hs << ");\n"; // finished for header
+ cs << ")\n"
+ "{\n"
+ " // handle method call " << interface->name << "." << methodName(method) << "\n";
// make the call
bool usingInvokeMethod = false;
@@ -984,27 +1067,27 @@ static void writeAdaptor(const QString &filename, const QDBusIntrospection::Inte
// we are using QMetaObject::invokeMethod
if (!returnType.isEmpty())
cs << " " << returnType << " " << argNames.at(method.inputArgs.size())
- << ";" << Qt::endl;
+ << ";\n";
static const char invoke[] = " QMetaObject::invokeMethod(parent(), \"";
cs << invoke << name << "\"";
if (!method.outputArgs.isEmpty())
cs << ", Q_RETURN_ARG("
- << qtTypeName(method.outputArgs.at(0).name, method.outputArgs.at(0).type, method.annotations,
- 0, "Out")
+ << qtTypeName(method.outputArgs.at(0).location, method.outputArgs.at(0).type,
+ method.annotations, 0, "Out")
<< ", " << argNames.at(method.inputArgs.size()) << ")";
for (qsizetype i = 0; i < method.inputArgs.size(); ++i)
cs << ", Q_ARG("
- << qtTypeName(method.inputArgs.at(i).name, method.inputArgs.at(i).type, method.annotations,
- i, "In")
+ << qtTypeName(method.inputArgs.at(i).location, method.inputArgs.at(i).type,
+ method.annotations, i, "In")
<< ", " << argNames.at(i) << ")";
- cs << ");" << Qt::endl;
+ cs << ");\n";
if (!returnType.isEmpty())
- cs << " return " << argNames.at(method.inputArgs.size()) << ";" << Qt::endl;
+ cs << " return " << argNames.at(method.inputArgs.size()) << ";\n";
} else {
if (parentClassName.isEmpty())
cs << " //";
@@ -1032,34 +1115,32 @@ static void writeAdaptor(const QString &filename, const QDBusIntrospection::Inte
first = false;
}
- cs << ");" << Qt::endl;
+ cs << ");\n";
}
- cs << "}" << Qt::endl
- << Qt::endl;
+ cs << "}\n\n";
}
- hs << "Q_SIGNALS: // SIGNALS" << Qt::endl;
+ hs << "Q_SIGNALS: // SIGNALS\n";
for (const QDBusIntrospection::Signal &signal : interface->signals_) {
hs << " void " << signal.name << "(";
QStringList argNames = makeArgNames(signal.outputArgs);
writeSignalArgList(hs, argNames, signal.annotations, signal.outputArgs);
- hs << ");" << Qt::endl; // finished for header
+ hs << ");\n"; // finished for header
}
// close the class:
- hs << "};" << Qt::endl
- << Qt::endl;
+ hs << "};\n\n";
}
// close the include guard
- hs << "#endif" << Qt::endl;
+ hs << "#endif\n";
QString mocName = moc(filename);
if (includeMocs && !mocName.isEmpty())
- cs << Qt::endl
- << "#include \"" << mocName << "\"" << Qt::endl;
+ cs << "\n"
+ "#include \"" << mocName << "\"\n";
cs.flush();
hs.flush();
@@ -1079,12 +1160,8 @@ static void writeAdaptor(const QString &filename, const QDBusIntrospection::Inte
}
}
-int main(int argc, char **argv)
+int QDBusXmlToCpp::run(const QCoreApplication &app)
{
- QCoreApplication app(argc, argv);
- QCoreApplication::setApplicationName(QStringLiteral(PROGRAMNAME));
- QCoreApplication::setApplicationVersion(QStringLiteral(PROGRAMVERSION));
-
QCommandLineParser parser;
parser.setApplicationDescription(
"Produces the C++ code to implement the interfaces defined in the input file.\n\n"
@@ -1097,57 +1174,59 @@ int main(int argc, char **argv)
parser.addHelpOption();
parser.addVersionOption();
- parser.addPositionalArgument(QStringLiteral("xml-or-xml-file"), QStringLiteral("XML file to use."));
- parser.addPositionalArgument(QStringLiteral("interfaces"), QStringLiteral("List of interfaces to use."),
- QStringLiteral("[interfaces ...]"));
+ parser.addPositionalArgument(u"xml-or-xml-file"_s, u"XML file to use."_s);
+ parser.addPositionalArgument(u"interfaces"_s, u"List of interfaces to use."_s,
+ u"[interfaces ...]"_s);
- QCommandLineOption adapterCodeOption(QStringList() << QStringLiteral("a") << QStringLiteral("adaptor"),
- QStringLiteral("Write the adaptor code to <filename>"), QStringLiteral("filename"));
+ QCommandLineOption adapterCodeOption(QStringList{u"a"_s, u"adaptor"_s},
+ u"Write the adaptor code to <filename>"_s, u"filename"_s);
parser.addOption(adapterCodeOption);
- QCommandLineOption classNameOption(QStringList() << QStringLiteral("c") << QStringLiteral("classname"),
- QStringLiteral("Use <classname> as the class name for the generated classes"), QStringLiteral("classname"));
+ QCommandLineOption classNameOption(QStringList{u"c"_s, u"classname"_s},
+ u"Use <classname> as the class name for the generated classes. "
+ u"This option can only be used when processing a single interface."_s,
+ u"classname"_s);
parser.addOption(classNameOption);
- QCommandLineOption addIncludeOption(QStringList() << QStringLiteral("i") << QStringLiteral("include"),
- QStringLiteral("Add #include \"filename\" to the output"), QStringLiteral("filename"));
+ QCommandLineOption addIncludeOption(QStringList{u"i"_s, u"include"_s},
+ u"Add #include \"filename\" to the output"_s, u"filename"_s);
parser.addOption(addIncludeOption);
- QCommandLineOption addGlobalIncludeOption(QStringList() << QStringLiteral("I") << QStringLiteral("global-include"),
- QStringLiteral("Add #include <filename> to the output"), QStringLiteral("filename"));
+ QCommandLineOption addGlobalIncludeOption(QStringList{u"I"_s, u"global-include"_s},
+ u"Add #include <filename> to the output"_s, u"filename"_s);
parser.addOption(addGlobalIncludeOption);
- QCommandLineOption adapterParentOption(QStringLiteral("l"),
- QStringLiteral("When generating an adaptor, use <classname> as the parent class"), QStringLiteral("classname"));
+ QCommandLineOption adapterParentOption(u"l"_s,
+ u"When generating an adaptor, use <classname> as the parent class"_s, u"classname"_s);
parser.addOption(adapterParentOption);
- QCommandLineOption mocIncludeOption(QStringList() << QStringLiteral("m") << QStringLiteral("moc"),
- QStringLiteral("Generate #include \"filename.moc\" statements in the .cpp files"));
+ QCommandLineOption mocIncludeOption(QStringList{u"m"_s, u"moc"_s},
+ u"Generate #include \"filename.moc\" statements in the .cpp files"_s);
parser.addOption(mocIncludeOption);
- QCommandLineOption noNamespaceOption(QStringList() << QStringLiteral("N") << QStringLiteral("no-namespaces"),
- QStringLiteral("Don't use namespaces"));
+ QCommandLineOption noNamespaceOption(QStringList{u"N"_s, u"no-namespaces"_s},
+ u"Don't use namespaces"_s);
parser.addOption(noNamespaceOption);
- QCommandLineOption proxyCodeOption(QStringList() << QStringLiteral("p") << QStringLiteral("proxy"),
- QStringLiteral("Write the proxy code to <filename>"), QStringLiteral("filename"));
+ QCommandLineOption proxyCodeOption(QStringList{u"p"_s, u"proxy"_s},
+ u"Write the proxy code to <filename>"_s, u"filename"_s);
parser.addOption(proxyCodeOption);
- QCommandLineOption verboseOption(QStringList() << QStringLiteral("V") << QStringLiteral("verbose"),
- QStringLiteral("Be verbose."));
+ QCommandLineOption verboseOption(QStringList{u"V"_s, u"verbose"_s},
+ u"Be verbose."_s);
parser.addOption(verboseOption);
parser.process(app);
- adaptorFile = parser.value(adapterCodeOption);
+ QString adaptorFile = parser.value(adapterCodeOption);
globalClassName = parser.value(classNameOption);
includes = parser.values(addIncludeOption);
globalIncludes = parser.values(addGlobalIncludeOption);
parentClassName = parser.value(adapterParentOption);
includeMocs = parser.isSet(mocIncludeOption);
skipNamespaces = parser.isSet(noNamespaceOption);
- proxyFile = parser.value(proxyCodeOption);
- verbose = parser.isSet(verboseOption);
+ QString proxyFile = parser.value(proxyCodeOption);
+ bool verbose = parser.isSet(verboseOption);
wantedInterfaces = parser.positionalArguments();
if (!wantedInterfaces.isEmpty()) {
@@ -1161,11 +1240,16 @@ int main(int argc, char **argv)
}
if (verbose)
- QLoggingCategory::setFilterRules(QStringLiteral("dbus.parser.debug=true"));
+ QLoggingCategory::setFilterRules(u"dbus.parser.debug=true"_s);
QDBusIntrospection::Interfaces interfaces = readInput();
cleanInterfaces(interfaces);
+ if (!globalClassName.isEmpty() && interfaces.count() != 1) {
+ qCritical("Option -c/--classname can only be used with a single interface.\n");
+ return 1;
+ }
+
QStringList args = app.arguments();
args.removeFirst();
commandLine = PROGRAMNAME " "_L1 + args.join(u' ');
@@ -1179,3 +1263,11 @@ int main(int argc, char **argv)
return 0;
}
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+ QCoreApplication::setApplicationName(QStringLiteral(PROGRAMNAME));
+ QCoreApplication::setApplicationVersion(QStringLiteral(PROGRAMVERSION));
+
+ return QDBusXmlToCpp().run(app);
+}
diff --git a/src/tools/qlalr/CMakeLists.txt b/src/tools/qlalr/CMakeLists.txt
index f6e2077ef4..da8b351889 100644
--- a/src/tools/qlalr/CMakeLists.txt
+++ b/src/tools/qlalr/CMakeLists.txt
@@ -21,6 +21,8 @@ qt_internal_add_tool(${target_name}
recognizer.cpp recognizer.h
DEFINES
QT_NO_FOREACH
+ QT_NO_QPAIR
+ QT_USE_NODISCARD_FILE_OPEN
LIBRARIES
Qt::Core
Qt::CorePrivate
diff --git a/src/tools/qlalr/cppgenerator.cpp b/src/tools/qlalr/cppgenerator.cpp
index 3c4264737e..fd56de106d 100644
--- a/src/tools/qlalr/cppgenerator.cpp
+++ b/src/tools/qlalr/cppgenerator.cpp
@@ -193,7 +193,15 @@ void CppGenerator::operator () ()
{
if (shift_reduce_conflict_count != grammar.expected_shift_reduce
|| reduce_reduce_conflict_count != grammar.expected_reduce_reduce)
- qerr() << "*** Conflicts: " << shift_reduce_conflict_count << " shift/reduce, " << reduce_reduce_conflict_count << " reduce/reduce" << Qt::endl;
+ {
+ qerr() << "*** Conflicts: " << shift_reduce_conflict_count << " shift/reduce, " << reduce_reduce_conflict_count << " reduce/reduce" << Qt::endl;
+ if (warnings_are_errors)
+ {
+ qerr() << "qlalr: error: warning occurred, treating as error due to "
+ "--exit-on-warn." << Qt::endl;
+ exit(2);
+ }
+ }
if (verbose)
qout() << Qt::endl << "*** Conflicts: " << shift_reduce_conflict_count << " shift/reduce, " << reduce_reduce_conflict_count << " reduce/reduce" << Qt::endl
@@ -220,7 +228,15 @@ void CppGenerator::operator () ()
if (! used_rules.testBit (i))
{
if (rule != grammar.goal)
- qerr() << "*** Warning: Rule ``" << *rule << "'' is useless!" << Qt::endl;
+ {
+ qerr() << "*** Warning: Rule ``" << *rule << "'' is useless!" << Qt::endl;
+ if (warnings_are_errors)
+ {
+ qerr() << "qlalr: error: warning occurred, treating as error due to "
+ "--exit-on-warn." << Qt::endl;
+ exit(2);
+ }
+ }
}
}
@@ -332,7 +348,12 @@ void CppGenerator::operator () ()
{ // decls...
QFile f (declFileName);
- f.open (QFile::WriteOnly);
+ if (! f.open (QFile::WriteOnly))
+ {
+ fprintf (stderr, "*** cannot create %s: %s\n",
+ qPrintable(declFileName), qPrintable(f.errorString()));
+ return;
+ }
QTextStream out (&f);
QString prot = declFileName.toUpper ().replace (QLatin1Char ('.'), QLatin1Char ('_'));
@@ -364,7 +385,12 @@ void CppGenerator::operator () ()
{ // bits...
QFile f (bitsFileName);
- f.open (QFile::WriteOnly);
+ if (! f.open (QFile::WriteOnly))
+ {
+ fprintf (stderr, "*** cannot create %s: %s\n",
+ qPrintable(bitsFileName), qPrintable(f.errorString()));
+ return;
+ }
QTextStream out (&f);
// copyright headers must come first, otherwise the headers tests will fail
@@ -385,7 +411,12 @@ void CppGenerator::operator () ()
if (! grammar.decl_file_name.isEmpty ())
{
QFile f (grammar.decl_file_name);
- f.open (QFile::WriteOnly);
+ if (! f.open (QFile::WriteOnly))
+ {
+ fprintf (stderr, "*** cannot create %s: %s\n",
+ qPrintable(grammar.decl_file_name), qPrintable(f.errorString()));
+ return;
+ }
QTextStream out (&f);
out << p.decls();
}
@@ -393,7 +424,12 @@ void CppGenerator::operator () ()
if (! grammar.impl_file_name.isEmpty ())
{
QFile f (grammar.impl_file_name);
- f.open (QFile::WriteOnly);
+ if (! f.open (QFile::WriteOnly))
+ {
+ fprintf (stderr, "*** cannot create %s: %s\n",
+ qPrintable(grammar.impl_file_name), qPrintable(f.errorString()));
+ return;
+ }
QTextStream out (&f);
out << p.impls();
}
diff --git a/src/tools/qlalr/cppgenerator.h b/src/tools/qlalr/cppgenerator.h
index b83dc1396c..66ae781be4 100644
--- a/src/tools/qlalr/cppgenerator.h
+++ b/src/tools/qlalr/cppgenerator.h
@@ -20,7 +20,8 @@ public:
aut (aut),
verbose (verbose),
debug_info (false),
- copyright (false) {}
+ copyright (false),
+ warnings_are_errors(false) {}
void operator () ();
@@ -29,6 +30,8 @@ public:
void setCopyright (bool t) { copyright = t; }
+ void setWarningsAreErrors (bool e) { warnings_are_errors = e; }
+
private:
void generateDecl (QTextStream &out);
void generateImpl (QTextStream &out);
@@ -51,6 +54,7 @@ private:
int non_terminal_count;
bool debug_info;
bool copyright;
+ bool warnings_are_errors;
Compress compressed_action;
Compress compressed_goto;
QList<int> count;
diff --git a/src/tools/qlalr/examples/dummy-xml/ll/dummy-xml-ll.cpp b/src/tools/qlalr/examples/dummy-xml/ll/dummy-xml-ll.cpp
index c3aac8662d..24399d3786 100644
--- a/src/tools/qlalr/examples/dummy-xml/ll/dummy-xml-ll.cpp
+++ b/src/tools/qlalr/examples/dummy-xml/ll/dummy-xml-ll.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <cstdlib>
#include <cstdio>
diff --git a/src/tools/qlalr/examples/dummy-xml/xml.g b/src/tools/qlalr/examples/dummy-xml/xml.g
index 1999ebc35d..59472dc219 100644
--- a/src/tools/qlalr/examples/dummy-xml/xml.g
+++ b/src/tools/qlalr/examples/dummy-xml/xml.g
@@ -1,5 +1,5 @@
-- Copyright (C) 2016 The Qt Company Ltd.
--- SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+-- SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
%parser XMLTable
diff --git a/src/tools/qlalr/examples/glsl/build.sh b/src/tools/qlalr/examples/glsl/build.sh
index 5f6879737c..d43889bf72 100644
--- a/src/tools/qlalr/examples/glsl/build.sh
+++ b/src/tools/qlalr/examples/glsl/build.sh
@@ -1,6 +1,6 @@
#!/bin/sh
# Copyright (C) 2016 The Qt Company Ltd.
-# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
${FLEX-flex} -oglsl-lex.incl glsl-lex.l
${QLALR-qlalr} glsl.g
diff --git a/src/tools/qlalr/examples/glsl/glsl-lex.l b/src/tools/qlalr/examples/glsl/glsl-lex.l
index 505e1c14e0..f3f9bb4f50 100644
--- a/src/tools/qlalr/examples/glsl/glsl-lex.l
+++ b/src/tools/qlalr/examples/glsl/glsl-lex.l
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include <cassert>
#define YY_DECL int GLSLParser::nextToken()
diff --git a/src/tools/qlalr/examples/glsl/glsl.g b/src/tools/qlalr/examples/glsl/glsl.g
index e6a397aa70..223e90284d 100644
--- a/src/tools/qlalr/examples/glsl/glsl.g
+++ b/src/tools/qlalr/examples/glsl/glsl.g
@@ -1,5 +1,5 @@
-- Copyright (C) 2016 The Qt Company Ltd.
--- SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+-- SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
%parser GLSLParserTable
%merged_output glsl.cpp
diff --git a/src/tools/qlalr/examples/lambda/lambda.g b/src/tools/qlalr/examples/lambda/lambda.g
index 99fa215745..d4fd01ed4c 100644
--- a/src/tools/qlalr/examples/lambda/lambda.g
+++ b/src/tools/qlalr/examples/lambda/lambda.g
@@ -1,5 +1,5 @@
-- Copyright (C) 2016 The Qt Company Ltd.
--- SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+-- SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-- lambda calculus
diff --git a/src/tools/qlalr/examples/lambda/main.cpp b/src/tools/qlalr/examples/lambda/main.cpp
index 94b54e8d0b..c6a2695493 100644
--- a/src/tools/qlalr/examples/lambda/main.cpp
+++ b/src/tools/qlalr/examples/lambda/main.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "lambda.h"
diff --git a/src/tools/qlalr/examples/qparser/calc.g b/src/tools/qlalr/examples/qparser/calc.g
index 33b44a4f62..2be9fd55c0 100644
--- a/src/tools/qlalr/examples/qparser/calc.g
+++ b/src/tools/qlalr/examples/qparser/calc.g
@@ -1,5 +1,5 @@
-- Copyright (C) 2016 The Qt Company Ltd.
--- SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+-- SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
%parser calc_grammar
%decl calc_parser.h
diff --git a/src/tools/qlalr/examples/qparser/calc.l b/src/tools/qlalr/examples/qparser/calc.l
index 34792d0319..0f42987758 100644
--- a/src/tools/qlalr/examples/qparser/calc.l
+++ b/src/tools/qlalr/examples/qparser/calc.l
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "calc_parser.h"
#include <cstdlib>
diff --git a/src/tools/qlalr/examples/qparser/qparser.cpp b/src/tools/qlalr/examples/qparser/qparser.cpp
index 9c497b3559..354a778458 100644
--- a/src/tools/qlalr/examples/qparser/qparser.cpp
+++ b/src/tools/qlalr/examples/qparser/qparser.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "qparser.h"
diff --git a/src/tools/qlalr/examples/qparser/qparser.h b/src/tools/qlalr/examples/qparser/qparser.h
index bd135b7a26..80643616c4 100644
--- a/src/tools/qlalr/examples/qparser/qparser.h
+++ b/src/tools/qlalr/examples/qparser/qparser.h
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef QPARSER_H
#define QPARSER_H
diff --git a/src/tools/qlalr/lalr.cpp b/src/tools/qlalr/lalr.cpp
index e7496e94b5..51f1d94a40 100644
--- a/src/tools/qlalr/lalr.cpp
+++ b/src/tools/qlalr/lalr.cpp
@@ -139,24 +139,24 @@ State::State (Grammar *g):
{
}
-QPair<ItemPointer, bool> State::insert (const Item &item)
+std::pair<ItemPointer, bool> State::insert(const Item &item)
{
ItemPointer it = std::find (kernel.begin (), kernel.end (), item);
if (it != kernel.end ())
- return qMakePair (it, false);
+ return {it, false};
- return qMakePair (kernel.insert (it, item), true);
+ return {kernel.insert(it, item), true};
}
-QPair<ItemPointer, bool> State::insertClosure (const Item &item)
+std::pair<ItemPointer, bool> State::insertClosure(const Item &item)
{
ItemPointer it = std::find (closure.begin (), closure.end (), item);
if (it != closure.end ())
- return qMakePair (it, false);
+ return {it, false};
- return qMakePair (closure.insert (it, item), true);
+ return {closure.insert (it, item), true};
}
@@ -296,14 +296,14 @@ void Automaton::buildNullables ()
#endif
}
-QPair<StatePointer, bool> Automaton::internState (const State &state)
+std::pair<StatePointer, bool> Automaton::internState(const State &state)
{
StatePointer it = std::find (states.begin (), states.end (), state);
if (it != states.end ())
- return qMakePair (it, false);
+ return {it, false};
- return qMakePair (states.insert (it, state), true);
+ return {states.insert (it, state), true};
}
struct _Bucket
@@ -359,7 +359,7 @@ void Automaton::closure (StatePointer state)
ii.rule = rule;
ii.dot = rule->rhs.begin ();
- QPair<ItemPointer, bool> r = state->insertClosure (ii);
+ std::pair<ItemPointer, bool> r = state->insertClosure(ii);
if (r.second)
working_list.push (r.first);
@@ -371,7 +371,7 @@ void Automaton::closure (StatePointer state)
for (bucket_map_type::iterator bucket = buckets.begin (); bucket != buckets.end (); ++bucket)
{
- QPair<StatePointer, bool> r = internState (bucket->toState (this));
+ std::pair<StatePointer, bool> r = internState(bucket->toState(this));
StatePointer target = r.first;
diff --git a/src/tools/qlalr/lalr.h b/src/tools/qlalr/lalr.h
index 19dcdb626e..efa0a91a39 100644
--- a/src/tools/qlalr/lalr.h
+++ b/src/tools/qlalr/lalr.h
@@ -9,7 +9,6 @@
#include <QtCore/qmap.h>
#include <QtCore/qstring.h>
#include <QtCore/qtextstream.h>
-#include <QtCore/qpair.h>
#include <algorithm>
#include <functional>
@@ -117,8 +116,8 @@ public:
inline bool operator != (const State &other) const
{ return kernel != other.kernel; }
- QPair<ItemPointer, bool> insert (const Item &item);
- QPair<ItemPointer, bool> insertClosure (const Item &item);
+ std::pair<ItemPointer, bool> insert(const Item &item);
+ std::pair<ItemPointer, bool> insertClosure(const Item &item);
public: // attributes
ItemList kernel;
@@ -143,7 +142,7 @@ public:
public:
static iterator get (_Tp data);
- QPair<edge_iterator, bool> insertEdge (iterator other) const;
+ std::pair<edge_iterator, bool> insertEdge(iterator other) const;
inline edge_iterator begin () const
{ return outs.begin (); }
@@ -198,15 +197,15 @@ typename Node<_Tp>::iterator Node<_Tp>::get (_Tp data)
}
template <typename _Tp>
-QPair<typename std::list<typename Node<_Tp>::iterator>::iterator, bool> Node<_Tp>::insertEdge(typename Node<_Tp>::iterator other) const
+std::pair<typename std::list<typename Node<_Tp>::iterator>::iterator, bool> Node<_Tp>::insertEdge(typename Node<_Tp>::iterator other) const
{
edge_iterator it = std::find (outs.begin (), outs.end (), other);
if (it != outs.end ())
- return qMakePair (it, false);
+ return {it, false};
other->root = false;
- return qMakePair (outs.insert (outs.end (), other), true);
+ return {outs.insert (outs.end (), other), true};
}
/////////////////////////////////////////////////////////////
@@ -312,7 +311,7 @@ class Automaton
public:
Automaton (Grammar *g);
- QPair<StatePointer, bool> internState (const State &state);
+ std::pair<StatePointer, bool> internState (const State &state);
typedef Node<Read> ReadsGraph;
typedef ReadsGraph::iterator ReadNode;
diff --git a/src/tools/qlalr/main.cpp b/src/tools/qlalr/main.cpp
index 8d339173ec..04ae54d986 100644
--- a/src/tools/qlalr/main.cpp
+++ b/src/tools/qlalr/main.cpp
@@ -28,7 +28,8 @@ static void help_me ()
<< " --no-debug\t\tno debug information" << Qt::endl
<< " --no-lines\t\tno #line directives" << Qt::endl
<< " --dot\t\t\tgenerate a graph" << Qt::endl
- << " --qt\t\tadd the Qt copyright header and Qt-specific types and macros" << Qt::endl
+ << " --qt\t\t\tadd the Qt copyright header and Qt-specific types and macros" << Qt::endl
+ << " --exit-on-warn\texit with status code 2 on warning" << Qt::endl
<< Qt::endl;
exit (0);
}
@@ -42,6 +43,7 @@ int main (int argc, char *argv[])
bool no_lines = false;
bool debug_info = true;
bool qt_copyright = false;
+ bool warnings_are_errors = false;
QString file_name;
const QStringList args = app.arguments().mid(1);
@@ -64,6 +66,9 @@ int main (int argc, char *argv[])
else if (arg == "--qt"_L1)
qt_copyright = true;
+ else if (arg == "--exit-on-warn"_L1)
+ warnings_are_errors = true;
+
else if (file_name.isEmpty ())
file_name = arg;
@@ -104,6 +109,7 @@ int main (int argc, char *argv[])
CppGenerator gen (p, grammar, aut, generate_report);
gen.setDebugInfo (debug_info);
gen.setCopyright (qt_copyright);
+ gen.setWarningsAreErrors (warnings_are_errors);
gen ();
if (generate_dot)
diff --git a/src/tools/qtpaths/CMakeLists.txt b/src/tools/qtpaths/CMakeLists.txt
index eef33c588d..d64caeb3c2 100644
--- a/src/tools/qtpaths/CMakeLists.txt
+++ b/src/tools/qtpaths/CMakeLists.txt
@@ -7,15 +7,14 @@
qt_get_tool_target_name(target_name qtpaths)
qt_internal_add_tool(${target_name}
+ TRY_RUN
TARGET_DESCRIPTION "Qt tool that provides the standard paths of the Qt framework"
TOOLS_TARGET Core
INSTALL_VERSIONED_LINK
SOURCES
qtpaths.cpp
DEFINES
- QT_NO_FOREACH
QTPATHS_VERSION_STR="2.0"
- QT_VERSION_STR="${PROJECT_VERSION}"
)
qt_internal_return_unless_building_tools()
@@ -25,7 +24,6 @@ qt_internal_return_unless_building_tools()
qt_internal_extend_target(${target_name} CONDITION QT_FEATURE_settings
LIBRARIES
QtLibraryInfo
- Qt::CorePrivate
)
if(WIN32 AND TARGET ${target_name})
diff --git a/src/tools/qtpaths/qtpaths.cpp b/src/tools/qtpaths/qtpaths.cpp
index db101efca5..71f9fe4349 100644
--- a/src/tools/qtpaths/qtpaths.cpp
+++ b/src/tools/qtpaths/qtpaths.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 Sune Vuorela <sune@kde.org>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QCoreApplication>
#include <QCommandLineParser>
@@ -61,9 +61,6 @@ static const StringEnum lookupTableData[] = {
{ "ApplicationsLocation", QStandardPaths::ApplicationsLocation, false },
{ "CacheLocation", QStandardPaths::CacheLocation, true },
{ "ConfigLocation", QStandardPaths::ConfigLocation, false },
-#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
- { "DataLocation", QStandardPaths::DataLocation, true },
-#endif
{ "DesktopLocation", QStandardPaths::DesktopLocation, false },
{ "DocumentsLocation", QStandardPaths::DocumentsLocation, false },
{ "DownloadLocation", QStandardPaths::DownloadLocation, false },
@@ -71,12 +68,14 @@ static const StringEnum lookupTableData[] = {
{ "GenericCacheLocation", QStandardPaths::GenericCacheLocation, false },
{ "GenericConfigLocation", QStandardPaths::GenericConfigLocation, false },
{ "GenericDataLocation", QStandardPaths::GenericDataLocation, false },
+ { "GenericStateLocation", QStandardPaths::GenericStateLocation, false },
{ "HomeLocation", QStandardPaths::HomeLocation, false },
{ "MoviesLocation", QStandardPaths::MoviesLocation, false },
{ "MusicLocation", QStandardPaths::MusicLocation, false },
{ "PicturesLocation", QStandardPaths::PicturesLocation, false },
{ "PublicShareLocation", QStandardPaths::PublicShareLocation, false },
{ "RuntimeLocation", QStandardPaths::RuntimeLocation, false },
+ { "StateLocation", QStandardPaths::StateLocation, true },
{ "TemplatesLocation", QStandardPaths::TemplatesLocation, false },
{ "TempLocation", QStandardPaths::TempLocation, false }
};
@@ -222,7 +221,7 @@ int main(int argc, char **argv)
#if QT_CONFIG(settings)
if (parser.isSet(qtconf)) {
qtconfManualPath = parser.value(qtconf);
- QLibraryInfoPrivate::qtconfManualPath = &qtconfManualPath;
+ QLibraryInfoPrivate::setQtconfManualPath(&qtconfManualPath);
}
#endif
@@ -253,7 +252,7 @@ int main(int argc, char **argv)
}
QT_WARNING_PUSH
-#if defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 1300 && Q_CC_GNU < 1400
+#if defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 1300 && Q_CC_GNU < 1500
QT_WARNING_DISABLE_GCC("-Wdangling-reference")
#endif
if (parser.isSet(display)) {
@@ -345,7 +344,7 @@ int main(int argc, char **argv)
if (results.isEmpty()) {
parser.showHelp();
} else if (results.size() == 1) {
- const QString &item = results.first();
+ const QString &item = results.constFirst();
message(item);
if (item.isEmpty())
return EXIT_FAILURE;
diff --git a/src/tools/rcc/CMakeLists.txt b/src/tools/rcc/CMakeLists.txt
index c810537721..35a72c43fe 100644
--- a/src/tools/rcc/CMakeLists.txt
+++ b/src/tools/rcc/CMakeLists.txt
@@ -7,6 +7,7 @@
qt_get_tool_target_name(target_name rcc)
qt_internal_add_tool(${target_name}
+ TRY_RUN
TARGET_DESCRIPTION "Qt Resource Compiler"
INSTALL_DIR "${INSTALL_LIBEXECDIR}"
TOOLS_TARGET Core
@@ -17,6 +18,7 @@ qt_internal_add_tool(${target_name}
QT_NO_CAST_FROM_ASCII
QT_NO_FOREACH
QT_RCC
+ QT_USE_NODISCARD_FILE_OPEN
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR}
)
diff --git a/src/tools/rcc/main.cpp b/src/tools/rcc/main.cpp
index 2751bc39d6..03709ccbd4 100644
--- a/src/tools/rcc/main.cpp
+++ b/src/tools/rcc/main.cpp
@@ -303,7 +303,8 @@ int runRcc(int argc, char *argv[])
return 1;
}
QFile errorDevice;
- errorDevice.open(stderr, QIODevice::WriteOnly|QIODevice::Text);
+ if (!errorDevice.open(stderr, QIODevice::WriteOnly|QIODevice::Text))
+ return 1;
if (library.verbose())
errorDevice.write("Qt resource compiler\n");
@@ -341,7 +342,12 @@ int runRcc(int argc, char *argv[])
mode &= ~QIODevice::Text;
#endif // Q_OS_WIN
// using this overload close() only flushes.
- out.open(stdout, mode);
+ if (!out.open(stdout, mode)) {
+ const QString msg = QString::fromLatin1("Unable to open standard output for writing: %1\n")
+ .arg(out.errorString());
+ errorDevice.write(msg.toUtf8());
+ return 1;
+ }
} else {
out.setFileName(outFilename);
if (!out.open(mode)) {
diff --git a/src/tools/rcc/rcc.cpp b/src/tools/rcc/rcc.cpp
index e461ab6294..2bda7f2977 100644
--- a/src/tools/rcc/rcc.cpp
+++ b/src/tools/rcc/rcc.cpp
@@ -8,7 +8,7 @@
#include <qdatetime.h>
#include <qdebug.h>
#include <qdir.h>
-#include <qdiriterator.h>
+#include <qdirlisting.h>
#include <qfile.h>
#include <qiodevice.h>
#include <qlocale.h>
@@ -321,7 +321,7 @@ qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset,
// some info
if (text || pass1) {
lib.writeString(" // ");
- lib.writeByteArray(m_fileInfo.absoluteFilePath().toLocal8Bit());
+ lib.writeByteArray(m_fileInfo.fileName().toLocal8Bit());
lib.writeString("\n ");
}
@@ -634,12 +634,12 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice,
alias += slash;
QStringList filePaths;
- QDirIterator it(dir, QDirIterator::FollowSymlinks|QDirIterator::Subdirectories);
- while (it.hasNext()) {
- it.next();
- if (it.fileName() == "."_L1 || it.fileName() == ".."_L1)
+ using F = QDirListing::IteratorFlag;
+ for (const auto &entry : QDirListing(dir, F::FollowSymlinks | F::Recursive)) {
+ const QString &fileName = entry.fileName();
+ if (fileName == "."_L1 || fileName == ".."_L1)
continue;
- filePaths.append(it.filePath());
+ filePaths.emplace_back(entry.filePath());
}
// make rcc output deterministic
@@ -929,13 +929,17 @@ bool RCCResourceLibrary::output(QIODevice &outDevice, QIODevice &tempDevice, QIO
m_errorDevice->write("No data signature found\n");
return false;
}
+
+ if (c != pattern[i]) {
+ for (int k = 0; k < i; ++k)
+ outDevice.putChar(pattern[k]);
+ i = 0;
+ }
+
if (c == pattern[i]) {
++i;
} else {
- for (int k = 0; k < i; ++k)
- outDevice.putChar(pattern[k]);
outDevice.putChar(c);
- i = 0;
}
}
@@ -1094,6 +1098,10 @@ bool RCCResourceLibrary::writeHeader()
writeString("\n**\n");
writeString("** WARNING! All changes made in this file will be lost!\n");
writeString( "*****************************************************************************/\n\n");
+ writeString("#ifdef _MSC_VER\n"
+ "// disable informational message \"function ... selected for automatic inline expansion\"\n"
+ "#pragma warning (disable: 4711)\n"
+ "#endif\n\n");
break;
case Python_Code:
writeString("# Resource object code (Python 3)\n");
@@ -1374,7 +1382,9 @@ bool RCCResourceLibrary::writeInitializer()
"# define QT_RCC_MANGLE_NAMESPACE(name) name\n"
"#endif\n\n");
- writeString("#ifdef QT_NAMESPACE\n"
+ writeString("#if defined(QT_INLINE_NAMESPACE)\n"
+ "inline namespace QT_NAMESPACE {\n"
+ "#elif defined(QT_NAMESPACE)\n"
"namespace QT_NAMESPACE {\n"
"#endif\n\n");
}
diff --git a/src/tools/syncqt/CMakeLists.txt b/src/tools/syncqt/CMakeLists.txt
index 3740b1bd4d..b3ab091aa4 100644
--- a/src/tools/syncqt/CMakeLists.txt
+++ b/src/tools/syncqt/CMakeLists.txt
@@ -1,6 +1,24 @@
-# The tool should be optimized for maximum performance when working.
-if(NOT QT_USE_DEFAULT_CMAKE_OPTIMIZATION_FLAGS)
+if(NOT QT_INTERNAL_AVOID_OVERRIDING_SYNCQT_CONFIG)
+ qt_internal_get_configs_for_flag_manipulation(configs)
+ qt_internal_remove_known_optimization_flags(LANGUAGES CXX CONFIGS ${configs})
+ # The /RTC1 flag is present in the default DEBUG flags list and contradicts -O2 but is not
+ # removed by qt_internal_remove_known_optimization_flags
+ qt_internal_remove_compiler_flags("/RTC1" LANGUAGES CXX CONFIGS ${configs})
qt_internal_get_optimize_full_flags(optimize_full_flags)
+ qt_internal_add_compiler_flags(LANGUAGES CXX CONFIGS ${configs} FLAGS "${optimize_full_flags}")
+
+ if(MSVC)
+ qt_internal_add_compiler_flags(LANGUAGES CXX CONFIGS ${configs} FLAGS "/EHsc")
+ else()
+ qt_internal_add_compiler_flags(LANGUAGES CXX CONFIGS ${configs} FLAGS "-fexceptions")
+ endif()
+
+ # Replace all linker flags with those we use in the RelWithDebInfo configuration
+ list(REMOVE_ITEM configs RELWITHDEBINFO)
+ foreach(config IN LISTS configs)
+ set(CMAKE_EXE_LINKER_FLAGS_${config} "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
+ endforeach()
+ qt_internal_skip_sanitizer()
endif()
set(compile_definitions
@@ -11,29 +29,52 @@ set(compile_definitions
QT_NAMESPACE="${QT_NAMESPACE}"
)
-set(config_type "")
-if(NOT QT_INTERNAL_AVOID_OVERRIDING_SYNCQT_CONFIG)
- set(config_type CONFIG RelWithDebInfo)
+qt_get_tool_target_name(target_name syncqt)
+if(NOT QT_SYNC_HEADERS_AT_CONFIGURE_TIME)
+ qt_internal_add_tool(${target_name}
+ DEFINES ${compile_definitions}
+ EXCEPTIONS
+ TOOLS_TARGET Core
+ CORE_LIBRARY None
+ INSTALL_DIR "${INSTALL_LIBEXECDIR}"
+ SOURCES
+ "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
+ )
+else()
+ set(config_type "")
+ if(NOT QT_INTERNAL_AVOID_OVERRIDING_SYNCQT_CONFIG)
+ set(config_type CONFIG RelWithDebInfo)
+ endif()
+
+ if(CMAKE_OSX_ARCHITECTURES)
+ set(osx_architectures "-DCMAKE_OSX_ARCHITECTURES:STRING=${CMAKE_OSX_ARCHITECTURES}")
+ endif()
+
+ if(CMAKE_OSX_SYSROOT)
+ set(osx_sysroot "-DCMAKE_OSX_SYSROOT:STRING=${CMAKE_OSX_SYSROOT}")
+ endif()
+ # Note: configure-time tools reserve the original tool name for the imported executable.
+ # To re-build syncqt use 'syncqt_build' target.
+ qt_internal_add_configure_time_tool(${target_name}
+ DEFINES ${compile_definitions}
+ TOOLS_TARGET Core
+ INSTALL_DIRECTORY "${INSTALL_LIBEXECDIR}"
+ CMAKE_FLAGS
+ -DCMAKE_CXX_STANDARD_REQUIRED:BOOL=TRUE
+ -DCMAKE_CXX_STANDARD:STRING=17
+ # std::filesystem API is only available in macOS 10.15+
+ -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.15
+ "${osx_architectures}"
+ "${osx_sysroot}"
+ SOURCES
+ "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
+ ${config_type}
+ )
endif()
-if(CMAKE_OSX_ARCHITECTURES)
- set(osx_architectures "-DCMAKE_OSX_ARCHITECTURES:STRING=${CMAKE_OSX_ARCHITECTURES}")
+# Needs to be called at the end after all relevant target have created
+# when using qt_internal_add_tool.
+# Doesn't work if QT_SYNC_HEADERS_AT_CONFIGURE_TIME is TRUE.
+if(NOT QT_INTERNAL_AVOID_OVERRIDING_SYNCQT_CONFIG)
+ qt_internal_skip_linking_sanitizer()
endif()
-qt_get_tool_target_name(target_name syncqt)
-# Note: configure-time tools reserve the original tool name for the imported executable.
-# To re-build syncqt use 'syncqt_build' target.
-qt_internal_add_configure_time_tool(${target_name}
- DEFINES ${compile_definitions}
- COMPILE_OPTIONS ${optimize_full_flags}
- TOOLS_TARGET Core
- INSTALL_DIRECTORY "${INSTALL_LIBEXECDIR}"
- CMAKE_FLAGS
- -DCMAKE_CXX_STANDARD_REQUIRED:BOOL=TRUE
- -DCMAKE_CXX_STANDARD:STRING=${CMAKE_CXX_STANDARD}
- # std::filesystem API is only available in macOS 10.15+
- -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.15
- "${osx_architectures}"
- SOURCES
- "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
- ${config_type}
-)
diff --git a/src/tools/syncqt/main.cpp b/src/tools/syncqt/main.cpp
index 6785c0c7f0..5df7b03fd5 100644
--- a/src/tools/syncqt/main.cpp
+++ b/src/tools/syncqt/main.cpp
@@ -7,8 +7,7 @@
* - Header file that contains the module version information, and named as <module>Vesion
* - LD version script if applicable
* - Aliases or copies of the header files sorted by the generic Qt-types: public/private/qpa
- * and stored in the corresponding directories. Also copies the aliases to the framework-specific
- * directories.
+ * and stored in the corresponding directories.
* Also the tool executes conformity checks on each header file if applicable, to make sure they
* follow rules that are relevant for their header type.
* The tool can be run in two modes: with either '-all' or '-headers' options specified. Depending
@@ -28,6 +27,7 @@
#include <regex>
#include <map>
#include <set>
+#include <stdexcept>
#include <array>
enum ErrorCodes {
@@ -43,9 +43,10 @@ enum HeaderChecks {
PrivateHeaderChecks = 2, /* Checks if the public header includes a private header */
IncludeChecks = 4, /* Checks if the real header file but not an alias is included */
WeMeantItChecks = 8, /* Checks if private header files contains 'We meant it' disclaimer */
- CriticalChecks = PrivateHeaderChecks, /* Checks that lead to the fatal error of the sync
- process */
- AllChecks = NamespaceChecks | PrivateHeaderChecks | IncludeChecks | WeMeantItChecks,
+ PragmaOnceChecks = 16,
+ /* Checks that lead to the fatal error of the sync process: */
+ CriticalChecks = PrivateHeaderChecks | PragmaOnceChecks,
+ AllChecks = NamespaceChecks | CriticalChecks | IncludeChecks | WeMeantItChecks,
};
constexpr int LinkerScriptCommentAlignment = 55;
@@ -90,6 +91,33 @@ std::string asciiToUpper(std::string s)
return s;
}
+bool parseVersion(const std::string &version, int &major, int &minor)
+{
+ const size_t separatorPos = version.find('.');
+ if (separatorPos == std::string::npos || separatorPos == (version.size() - 1)
+ || separatorPos == 0)
+ return false;
+
+ try {
+ size_t pos = 0;
+ major = std::stoi(version.substr(0, separatorPos), &pos);
+ if (pos != separatorPos)
+ return false;
+
+ const size_t nextPart = separatorPos + 1;
+ pos = 0;
+ minor = std::stoi(version.substr(nextPart), &pos);
+ if (pos != (version.size() - nextPart))
+ return false;
+ } catch (const std::invalid_argument &) {
+ return false;
+ } catch (const std::out_of_range &) {
+ return false;
+ }
+
+ return true;
+}
+
class DummyOutputStream : public std::ostream
{
struct : public std::streambuf
@@ -108,12 +136,46 @@ void printInternalError()
<< std::endl;
}
+void printFilesystemError(const std::filesystem::filesystem_error &fserr, std::string_view errorMsg)
+{
+ std::cerr << errorMsg << ": " << fserr.path1() << ".\n"
+ << fserr.what() << "(" << fserr.code().value() << ")" << std::endl;
+}
+
std::filesystem::path normilizedPath(const std::string &path)
{
- return std::filesystem::path(std::filesystem::absolute(path).generic_string());
+ try {
+ auto result = std::filesystem::path(std::filesystem::weakly_canonical(path).generic_string());
+ return result;
+ } catch (const std::filesystem::filesystem_error &fserr) {
+ printFilesystemError(fserr, "Unable to normalize path");
+ throw;
+ }
}
+
+bool createDirectories(const std::string &path, std::string_view errorMsg, bool *exists = nullptr)
+{
+ bool result = true;
+ try {
+ if (!std::filesystem::exists(path)) {
+ if (exists)
+ *exists = false;
+ std::filesystem::create_directories(path);
+ } else {
+ if (exists)
+ *exists = true;
+ }
+ } catch (const std::filesystem::filesystem_error &fserr) {
+ result = false;
+ std::cerr << errorMsg << ": " << path << ".\n"
+ << fserr.code().message() << "(" << fserr.code().value() << "):" << fserr.what()
+ << std::endl;
+ }
+ return result;
}
+} // namespace utils
+
using FileStamp = std::filesystem::file_time_type;
class CommandLineOptions
@@ -145,10 +207,12 @@ public:
const std::string &privateIncludeDir() const { return m_privateIncludeDir; }
- const std::string &frameworkIncludeDir() const { return m_frameworkIncludeDir; }
-
const std::string &qpaIncludeDir() const { return m_qpaIncludeDir; }
+ const std::string &rhiIncludeDir() const { return m_rhiIncludeDir; }
+
+ const std::string &ssgIncludeDir() const { return m_ssgIncludeDir; }
+
const std::string &stagingDir() const { return m_stagingDir; }
const std::string &versionScriptFile() const { return m_versionScriptFile; }
@@ -157,6 +221,10 @@ public:
const std::regex &qpaHeadersRegex() const { return m_qpaHeadersRegex; }
+ const std::regex &rhiHeadersRegex() const { return m_rhiHeadersRegex; }
+
+ const std::regex &ssgHeadersRegex() const { return m_ssgHeadersRegex; }
+
const std::regex &privateHeadersRegex() const { return m_privateHeadersRegex; }
const std::regex &publicNamespaceRegex() const { return m_publicNamespaceRegex; }
@@ -167,8 +235,6 @@ public:
bool scanAllMode() const { return m_scanAllMode; }
- bool isFramework() const { return m_isFramework; }
-
bool isInternal() const { return m_isInternal; }
bool isNonQtModule() const { return m_isNonQtModule; }
@@ -188,10 +254,9 @@ public:
void printHelp() const
{
std::cout << "Usage: syncqt -sourceDir <dir> -binaryDir <dir> -module <module name>"
- " -includeDir <dir> -privateIncludeDir <dir> -qpaIncludeDir <dir>"
+ " -includeDir <dir> -privateIncludeDir <dir> -qpaIncludeDir <dir> -rhiIncludeDir <dir> -ssgIncludeDir <dir>"
" -stagingDir <dir> <-headers <header list>|-all> [-debug]"
- " [-versionScript <path>] [-qpaHeadersFilter <regex>]"
- " [-framework [-frameworkIncludeDir <dir>]]"
+ " [-versionScript <path>] [-qpaHeadersFilter <regex>] [-rhiHeadersFilter <regex>]"
" [-knownModules <module1> <module2>... <moduleN>]"
" [-nonQt] [-internal] [-copy]\n"
""
@@ -212,6 +277,10 @@ public:
" generated private header files.\n"
" -qpaIncludeDir Module include directory for the \n"
" generated QPA header files.\n"
+ " -rhiIncludeDir Module include directory for the \n"
+ " generated RHI header files.\n"
+ " -ssgIncludeDir Module include directory for the \n"
+ " generated SSG header files.\n"
" -stagingDir Temporary staging directory to collect\n"
" artifacts that need to be installed.\n"
" -knownModules list of known modules. syncqt uses the\n"
@@ -225,16 +294,16 @@ public:
" from the list of 'headers'.\n"
" -qpaHeadersFilter Regex that filters qpa header files from.\n"
" the list of 'headers'.\n"
+ " -rhiHeadersFilter Regex that filters rhi header files from.\n"
+ " the list of 'headers'.\n"
+ " -ssgHeadersFilter Regex that filters ssg files from.\n"
+ " the list of 'headers'.\n"
" -publicNamespaceFilter Symbols that are in the specified\n"
" namespace.\n"
" are treated as public symbols.\n"
" -versionScript Generate linker version script by\n"
" provided path.\n"
" -debug Enable debug output.\n"
- " -framework Indicates that module is framework.\n"
- " -frameworkIncludeDir The directory to store the framework\n"
- " header files.\n"
- " E.g. QtCore.framework/Versions/A/Headers\n"
" -copy Copy header files instead of creating\n"
" aliases.\n"
" -minimal Do not create CaMeL case headers for the\n"
@@ -262,6 +331,8 @@ private:
[[nodiscard]] bool parseArguments(int argc, char *argv[])
{
std::string qpaHeadersFilter;
+ std::string rhiHeadersFilter;
+ std::string ssgHeadersFilter;
std::string privateHeadersFilter;
std::string publicNamespaceFilter;
static std::unordered_map<std::string, CommandLineOption<std::string>> stringArgumentMap = {
@@ -270,12 +341,15 @@ private:
{ "-binaryDir", { &m_binaryDir } },
{ "-privateHeadersFilter", { &privateHeadersFilter, true } },
{ "-qpaHeadersFilter", { &qpaHeadersFilter, true } },
+ { "-rhiHeadersFilter", { &rhiHeadersFilter, true } },
+ { "-ssgHeadersFilter", { &ssgHeadersFilter, true } },
{ "-includeDir", { &m_includeDir } },
{ "-privateIncludeDir", { &m_privateIncludeDir } },
{ "-qpaIncludeDir", { &m_qpaIncludeDir } },
+ { "-rhiIncludeDir", { &m_rhiIncludeDir } },
+ { "-ssgIncludeDir", { &m_ssgIncludeDir } },
{ "-stagingDir", { &m_stagingDir, true } },
{ "-versionScript", { &m_versionScriptFile, true } },
- { "-frameworkIncludeDir", { &m_frameworkIncludeDir, true } },
{ "-publicNamespaceFilter", { &publicNamespaceFilter, true } },
};
@@ -288,7 +362,7 @@ private:
static const std::unordered_map<std::string, CommandLineOption<bool>> boolArgumentMap = {
{ "-nonQt", { &m_isNonQtModule, true } }, { "-debug", { &m_debug, true } },
- { "-help", { &m_printHelpOnly, true } }, { "-framework", { &m_isFramework, true } },
+ { "-help", { &m_printHelpOnly, true } },
{ "-internal", { &m_isInternal, true } }, { "-all", { &m_scanAllMode, true } },
{ "-copy", { &m_copy, true } }, { "-minimal", { &m_minimal, true } },
{ "-showonly", { &m_showOnly, true } }, { "-showOnly", { &m_showOnly, true } },
@@ -373,6 +447,7 @@ private:
if (!parseArgument(argFromFile))
return false;
}
+ ifs.close();
continue;
}
@@ -386,6 +461,12 @@ private:
if (!qpaHeadersFilter.empty())
m_qpaHeadersRegex = std::regex(qpaHeadersFilter);
+ if (!rhiHeadersFilter.empty())
+ m_rhiHeadersRegex = std::regex(rhiHeadersFilter);
+
+ if (!ssgHeadersFilter.empty())
+ m_ssgHeadersRegex = std::regex(ssgHeadersFilter);
+
if (!privateHeadersFilter.empty())
m_privateHeadersRegex = std::regex(privateHeadersFilter);
@@ -420,7 +501,8 @@ private:
{
static std::array<std::string *, 8> paths = {
&m_sourceDir, &m_binaryDir, &m_includeDir, &m_privateIncludeDir,
- &m_qpaIncludeDir, &m_stagingDir, &m_versionScriptFile, &m_frameworkIncludeDir
+ &m_qpaIncludeDir, &m_rhiIncludeDir, &m_stagingDir,
+ &m_versionScriptFile,
};
for (auto path : paths) {
if (!path->empty())
@@ -434,15 +516,15 @@ private:
std::string m_includeDir;
std::string m_privateIncludeDir;
std::string m_qpaIncludeDir;
+ std::string m_rhiIncludeDir;
+ std::string m_ssgIncludeDir;
std::string m_stagingDir;
std::string m_versionScriptFile;
- std::string m_frameworkIncludeDir;
std::set<std::string> m_knownModules;
std::set<std::string> m_headers;
std::set<std::string> m_generatedHeaders;
bool m_scanAllMode = false;
bool m_copy = false;
- bool m_isFramework = false;
bool m_isNonQtModule = false;
bool m_isInternal = false;
bool m_printHelpOnly = false;
@@ -451,6 +533,8 @@ private:
bool m_showOnly = false;
bool m_warningsAreErrors = false;
std::regex m_qpaHeadersRegex;
+ std::regex m_rhiHeadersRegex;
+ std::regex m_ssgHeadersRegex;
std::regex m_privateHeadersRegex;
std::regex m_publicNamespaceRegex;
@@ -522,7 +606,7 @@ class SyncScanner
size_t m_currentFileLineNumber = 0;
bool m_currentFileInSourceDir = false;
- enum FileType { PublicHeader = 0, PrivateHeader = 1, QpaHeader = 2, ExportHeader = 4 };
+ enum FileType { PublicHeader = 0, PrivateHeader = 1, QpaHeader = 2, ExportHeader = 4, RhiHeader = 8, SsgHeader = 16 };
unsigned int m_currentFileType = PublicHeader;
int m_criticalChecks = CriticalChecks;
@@ -560,13 +644,26 @@ public:
if (m_commandLineArgs->scanAllMode()) {
for (auto const &entry :
std::filesystem::recursive_directory_iterator(m_commandLineArgs->sourceDir())) {
- if (entry.is_regular_file() && isHeader(entry)
- && !isDocFileHeuristic(entry.path().generic_string())) {
- const std::string filePath = entry.path().generic_string();
- const std::string fileName = entry.path().filename().generic_string();
- scannerDebug() << "Checking: " << filePath << std::endl;
+
+ const bool isRegularFile = entry.is_regular_file();
+ const bool isHeaderFlag = isHeader(entry);
+ const bool isDocFileHeuristicFlag =
+ isDocFileHeuristic(entry.path().generic_string());
+ const bool shouldProcessHeader =
+ isRegularFile && isHeaderFlag && !isDocFileHeuristicFlag;
+ const std::string filePath = entry.path().generic_string();
+
+ if (shouldProcessHeader) {
+ scannerDebug() << "Processing header: " << filePath << std::endl;
if (!processHeader(makeHeaderAbsolute(filePath)))
error = SyncFailed;
+ } else {
+ scannerDebug()
+ << "Skipping processing header: " << filePath
+ << " isRegularFile: " << isRegularFile
+ << " isHeaderFlag: " << isHeaderFlag
+ << " isDocFileHeuristicFlag: " << isDocFileHeuristicFlag
+ << std::endl;
}
}
} else {
@@ -576,11 +673,13 @@ public:
const auto &headers = m_commandLineArgs->headers();
for (auto it = headers.begin(); it != headers.end(); ++it) {
const auto &header = *it;
+ scannerDebug() << "Processing header: " << header << std::endl;
if (!processHeader(makeHeaderAbsolute(header))) {
error = SyncFailed;
}
}
for (const auto &header : rspHeaders) {
+ scannerDebug() << "Processing header: " << header << std::endl;
if (!processHeader(makeHeaderAbsolute(header)))
error = SyncFailed;
}
@@ -654,13 +753,6 @@ public:
// process eaiser.
if (!copyGeneratedHeadersToStagingDirectory(m_commandLineArgs->stagingDir()))
error = SyncFailed;
- // We also need to have a copy of the generated header files in framework include
- // directories when building with '-framework'.
- if (m_commandLineArgs->isFramework()) {
- if (!copyGeneratedHeadersToStagingDirectory(
- m_commandLineArgs->frameworkIncludeDir(), true))
- error = SyncFailed;
- }
}
return error;
}
@@ -671,15 +763,37 @@ public:
bool skipCleanup = false)
{
bool result = true;
- if (!std::filesystem::exists(outputDirectory)) {
- std::filesystem::create_directories(outputDirectory);
- } else if (!skipCleanup) {
- for (const auto &entry :
- std::filesystem::recursive_directory_iterator(outputDirectory)) {
- if (m_producedHeaders.find(entry.path().filename().generic_string())
- == m_producedHeaders.end()) {
- std::filesystem::remove(entry.path());
+ bool outDirExists = false;
+ if (!utils::createDirectories(outputDirectory, "Unable to create staging directory",
+ &outDirExists))
+ return false;
+
+ if (outDirExists && !skipCleanup) {
+ try {
+ for (const auto &entry :
+ std::filesystem::recursive_directory_iterator(outputDirectory)) {
+ if (m_producedHeaders.find(entry.path().filename().generic_string())
+ == m_producedHeaders.end()) {
+ // Check if header file came from another module as result of the
+ // cross-module deprecation before removing it.
+ std::string firstLine;
+ {
+ std::ifstream input(entry.path(), std::ifstream::in);
+ if (input.is_open()) {
+ std::getline(input, firstLine);
+ input.close();
+ }
+ }
+ if (firstLine.find("#ifndef DEPRECATED_HEADER_"
+ + m_commandLineArgs->moduleName())
+ == 0
+ || firstLine.find("#ifndef DEPRECATED_HEADER_") != 0)
+ std::filesystem::remove(entry.path());
+ }
}
+ } catch (const std::filesystem::filesystem_error &fserr) {
+ utils::printFilesystemError(fserr, "Unable to clean the staging directory");
+ return false;
}
}
@@ -710,6 +824,12 @@ public:
if (isHeaderQpa(m_currentFilename))
m_currentFileType = QpaHeader | PrivateHeader;
+ if (isHeaderRhi(m_currentFilename))
+ m_currentFileType = RhiHeader | PrivateHeader;
+
+ if (isHeaderSsg(m_currentFilename))
+ m_currentFileType = SsgHeader | PrivateHeader;
+
if (std::regex_match(m_currentFilename, ExportsHeaderRegex))
m_currentFileType |= ExportHeader;
}
@@ -717,7 +837,7 @@ public:
[[nodiscard]] bool processHeader(const std::filesystem::path &headerFile)
{
// This regex filters any paths that contain the '3rdparty' directory.
- static const std::regex ThirdPartyFolderRegex(".+/3rdparty/.+");
+ static const std::regex ThirdPartyFolderRegex("(^|.+/)3rdparty/.+");
// This regex filters '-config.h' and '-config_p.h' header files.
static const std::regex ConfigHeaderRegex("^(q|.+-)config(_p)?\\.h");
@@ -747,29 +867,36 @@ public:
bool isPrivate = m_currentFileType & PrivateHeader;
bool isQpa = m_currentFileType & QpaHeader;
+ bool isRhi = m_currentFileType & RhiHeader;
+ bool isSsg = m_currentFileType & SsgHeader;
bool isExport = m_currentFileType & ExportHeader;
- scannerDebug() << headerFile << " m_currentFilename: " << m_currentFilename
- << " isPrivate: " << isPrivate << " isQpa: " << isQpa << std::endl;
+ scannerDebug()
+ << "processHeader:start: " << headerFile
+ << " m_currentFilename: " << m_currentFilename
+ << " isPrivate: " << isPrivate
+ << " isQpa: " << isQpa
+ << " isRhi: " << isRhi
+ << " isSsg: " << isSsg
+ << std::endl;
// Chose the directory where to generate the header aliases or to copy header file if
// the '-copy' argument is passed.
std::string outputDir = m_commandLineArgs->includeDir();
if (isQpa)
outputDir = m_commandLineArgs->qpaIncludeDir();
+ else if (isRhi)
+ outputDir = m_commandLineArgs->rhiIncludeDir();
+ else if (isSsg)
+ outputDir = m_commandLineArgs->ssgIncludeDir();
else if (isPrivate)
outputDir = m_commandLineArgs->privateIncludeDir();
- if (!std::filesystem::exists(outputDir))
- std::filesystem::create_directories(outputDir);
+ if (!utils::createDirectories(outputDir, "Unable to create output directory"))
+ return false;
bool headerFileExists = std::filesystem::exists(headerFile);
- std::filesystem::path headerFileRootName =
- std::filesystem::weakly_canonical(headerFile, ec).root_name();
- std::string aliasedFilepath = !ec && headerFileRootName == m_outputRootName
- ? std::filesystem::relative(headerFile, outputDir).generic_string()
- : headerFile.generic_string();
- ec.clear();
+ std::string aliasedFilepath = headerFile.generic_string();
std::string aliasPath = outputDir + '/' + m_currentFilename;
@@ -801,13 +928,20 @@ public:
}
bool isGenerated = isHeaderGenerated(m_currentFileString);
- bool is3rdParty = std::regex_match(m_currentFileString, ThirdPartyFolderRegex);
+
+ // Make sure that we detect the '3rdparty' directory inside the source directory only,
+ // since full path to the Qt sources might contain '/3rdparty/' too.
+ bool is3rdParty = std::regex_match(
+ std::filesystem::relative(headerFile, m_commandLineArgs->sourceDir())
+ .generic_string(),
+ ThirdPartyFolderRegex);
+
// No processing of generated Qt config header files.
if (!std::regex_match(m_currentFilename, ConfigHeaderRegex)) {
unsigned int skipChecks = m_commandLineArgs->scanAllMode() ? AllChecks : NoChecks;
// Collect checks that should skipped for the header file.
- if (m_commandLineArgs->isNonQtModule() || is3rdParty || isQpa
+ if (m_commandLineArgs->isNonQtModule() || is3rdParty || isQpa || isRhi || isSsg
|| !m_currentFileInSourceDir || isGenerated) {
skipChecks = AllChecks;
} else {
@@ -828,9 +962,11 @@ public:
ParsingResult parsingResult;
parsingResult.masterInclude = m_currentFileInSourceDir && !isExport && !is3rdParty
- && !isQpa && !isPrivate && !isGenerated;
- if (!parseHeader(headerFile, parsingResult, skipChecks))
+ && !isQpa && !isRhi && !isSsg && !isPrivate && !isGenerated;
+ if (!parseHeader(headerFile, parsingResult, skipChecks)) {
+ scannerDebug() << "parseHeader failed: " << headerFile << std::endl;
return false;
+ }
// Record the private header file inside the version script content.
if (isPrivate && !m_commandLineArgs->versionScriptFile().empty()
@@ -842,12 +978,22 @@ public:
// Add the '#if QT_CONFIG(<feature>)' check for header files that supposed to be
// included into the module master header only if corresponding feature is enabled.
- if (!isQpa && !isPrivate) {
+ bool willBeInModuleMasterHeader = false;
+ if (!isQpa && !isRhi && !isSsg && !isPrivate) {
if (m_currentFilename.find('_') == std::string::npos
&& parsingResult.masterInclude) {
m_masterHeaderContents[m_currentFilename] = parsingResult.requireConfig;
+ willBeInModuleMasterHeader = true;
}
}
+
+ scannerDebug()
+ << "processHeader:end: " << headerFile
+ << " is3rdParty: " << is3rdParty
+ << " isGenerated: " << isGenerated
+ << " m_currentFileInSourceDir: " << m_currentFileInSourceDir
+ << " willBeInModuleMasterHeader: " << willBeInModuleMasterHeader
+ << std::endl;
} else if (m_currentFilename == "qconfig.h") {
// Hardcode generating of QtConfig alias
updateSymbolDescriptor("QtConfig", "qconfig.h", SyncScanner::SymbolDescriptor::Pragma);
@@ -945,6 +1091,9 @@ public:
static const std::regex MacroRegex("^\\s*#.*");
// The regex's bellow check line for known pragmas:
+ //
+ // - 'once' is not allowed in installed headers, so error out.
+ //
// - 'qt_sync_skip_header_check' avoid any header checks.
//
// - 'qt_sync_stop_processing' stops the header proccesing from a moment when pragma is
@@ -960,13 +1109,19 @@ public:
// - 'qt_class(<symbol>)' manually declares the 'symbol' that should be used to generate
// the CaMeL case header alias.
//
- // - 'qt_deprecates(<deprecated header file>)' indicates that this header file replaces
- // the 'deprecated header file'. syncqt will create the deprecated header file' with
- // the special deprecation content. See the 'generateDeprecatedHeaders' function
- // for details.
+ // - 'qt_deprecates([module/]<deprecated header file>[,<major.minor>])' indicates that
+ // this header file replaces the 'deprecated header file'. syncqt will create the
+ // deprecated header file' with the special deprecation content. Pragma optionally
+ // accepts the Qt version where file should be removed. If the current Qt version is
+ // higher than the deprecation version, syncqt displays deprecation warning and skips
+ // generating the deprecated header. If the module is specified and is different from
+ // the one this header file belongs to, syncqt attempts to generate header files
+ // for the specified module. Cross-module deprecation only works within the same repo.
+ // See the 'generateDeprecatedHeaders' function for details.
//
// - 'qt_no_master_include' indicates that syncqt should avoid including this header
// files into the module master header file.
+ static const std::regex OnceRegex(R"(^#\s*pragma\s+once$)");
static const std::regex SkipHeaderCheckRegex("^#\\s*pragma qt_sync_skip_header_check$");
static const std::regex StopProcessingRegex("^#\\s*pragma qt_sync_stop_processing$");
static const std::regex SuspendProcessingRegex("^#\\s*pragma qt_sync_suspend_processing$");
@@ -1033,6 +1188,11 @@ public:
std::size_t linesProcessed = 0;
int faults = NoChecks;
+ const auto error = [&] () -> decltype(auto) {
+ return std::cerr << ErrorMessagePreamble << m_currentFileString
+ << ":" << m_currentFileLineNumber << " ";
+ };
+
// Read file line by line
while (std::getline(input, tmpLine)) {
++m_currentFileLineNumber;
@@ -1047,6 +1207,8 @@ public:
// - start-end of class/structures
// And avoid processing of the the data inside these blocks.
for (std::size_t i = 0; i < line.size(); ++i) {
+ if (line[i] == '\r')
+ continue;
if (bracesDepth == namespaceCount) {
if (line[i] == '/') {
if ((i + 1) < line.size()) {
@@ -1119,7 +1281,8 @@ public:
++linesProcessed;
bool skipSymbols =
- (m_currentFileType & PrivateHeader) || (m_currentFileType & QpaHeader);
+ (m_currentFileType & PrivateHeader) || (m_currentFileType & QpaHeader) || (m_currentFileType & RhiHeader)
+ || (m_currentFileType & SsgHeader);
// Parse pragmas
if (std::regex_match(buffer, MacroRegex)) {
@@ -1146,6 +1309,13 @@ public:
} else if (std::regex_match(buffer, match, DeprecatesPragmaRegex)) {
m_deprecatedHeaders[match[1].str()] =
m_commandLineArgs->moduleName() + '/' + m_currentFilename;
+ } else if (std::regex_match(buffer, OnceRegex)) {
+ if (!(skipChecks & PragmaOnceChecks)) {
+ faults |= PragmaOnceChecks;
+ error() << "\"#pragma once\" is not allowed in installed header files: "
+ "https://lists.qt-project.org/pipermail/development/2022-October/043121.html"
+ << std::endl;
+ }
} else if (std::regex_match(buffer, match, IncludeRegex) && !isSuspended) {
if (!(skipChecks & IncludeChecks)) {
std::string includedHeader = match[1].str();
@@ -1154,9 +1324,7 @@ public:
.filename()
.generic_string())) {
faults |= PrivateHeaderChecks;
- std::cerr << ErrorMessagePreamble << m_currentFileString
- << ":" << m_currentFileLineNumber
- << " includes private header " << includedHeader << std::endl;
+ error() << "includes private header " << includedHeader << std::endl;
}
for (const auto &module : m_commandLineArgs->knownModules()) {
std::string suggestedHeader = "Qt" + module + '/' + includedHeader;
@@ -1215,6 +1383,7 @@ public:
}
}
}
+ input.close();
// Error out if namespace checks are failed.
if (!(skipChecks & NamespaceChecks)) {
@@ -1300,6 +1469,16 @@ public:
return std::regex_match(headerFileName, m_commandLineArgs->qpaHeadersRegex());
}
+ [[nodiscard]] bool isHeaderRhi(const std::string &headerFileName)
+ {
+ return std::regex_match(headerFileName, m_commandLineArgs->rhiHeadersRegex());
+ }
+
+ [[nodiscard]] bool isHeaderSsg(const std::string &headerFileName)
+ {
+ return std::regex_match(headerFileName, m_commandLineArgs->ssgHeadersRegex());
+ }
+
[[nodiscard]] bool isHeaderPrivate(const std::string &headerFile)
{
return std::regex_match(headerFile, m_commandLineArgs->privateHeadersRegex());
@@ -1387,13 +1566,53 @@ public:
{
static std::regex cIdentifierSymbolsRegex("[^a-zA-Z0-9_]");
static std::string guard_base = "DEPRECATED_HEADER_" + m_commandLineArgs->moduleName();
+ bool result = true;
for (auto it = m_deprecatedHeaders.begin(); it != m_deprecatedHeaders.end(); ++it) {
- std::string &replacement = it->second;
+ const std::string &descriptor = it->first;
+ const std::string &replacement = it->second;
+
+ const auto separatorPos = descriptor.find(',');
+ std::string headerPath = descriptor.substr(0, separatorPos);
+ std::string versionDisclaimer;
+ if (separatorPos != std::string::npos) {
+ std::string version = descriptor.substr(separatorPos + 1);
+ versionDisclaimer = " and will be removed in Qt " + version;
+ int minor = 0;
+ int major = 0;
+ if (!utils::parseVersion(version, major, minor)) {
+ std::cerr << ErrorMessagePreamble
+ << "Invalid version format specified for the deprecated header file "
+ << headerPath << ": '" << version
+ << "'. Expected format: 'major.minor'.\n";
+ result = false;
+ continue;
+ }
+
+ if (QT_VERSION_MAJOR > major
+ || (QT_VERSION_MAJOR == major && QT_VERSION_MINOR >= minor)) {
+ std::cerr << WarningMessagePreamble << headerPath
+ << " is marked as deprecated and will not be generated in Qt "
+ << QT_VERSION_STR
+ << ". The respective qt_deprecates pragma needs to be removed.\n";
+ continue;
+ }
+ }
+
+ const auto moduleSeparatorPos = headerPath.find('/');
+ std::string headerName = moduleSeparatorPos != std::string::npos
+ ? headerPath.substr(moduleSeparatorPos + 1)
+ : headerPath;
+ const std::string moduleName = moduleSeparatorPos != std::string::npos
+ ? headerPath.substr(0, moduleSeparatorPos)
+ : m_commandLineArgs->moduleName();
+
+ bool isCrossModuleDeprecation = moduleName != m_commandLineArgs->moduleName();
+
std::string qualifiedHeaderName =
- std::regex_replace(it->first, cIdentifierSymbolsRegex, "_");
+ std::regex_replace(headerName, cIdentifierSymbolsRegex, "_");
std::string guard = guard_base + "_" + qualifiedHeaderName;
- std::string warningText = "Header <" + m_commandLineArgs->moduleName() + "/" + it->first
- + "> is deprecated. Please include <" + replacement + "> instead.";
+ std::string warningText = "Header <" + moduleName + "/" + headerName + "> is deprecated"
+ + versionDisclaimer + ". Please include <" + replacement + "> instead.";
std::stringstream buffer;
buffer << "#ifndef " << guard << "\n"
<< "#define " << guard << "\n"
@@ -1403,15 +1622,21 @@ public:
<< "# pragma message (\"" << warningText << "\")\n"
<< "#endif\n"
<< "#include <" << replacement << ">\n"
- << "#if 0\n"
- // TODO: Looks like qt_no_master_include is useless since deprecated headers are
- // generated by syncqt but are never scanned.
- << "#pragma qt_no_master_include\n"
- << "#endif\n"
<< "#endif\n";
- writeIfDifferent(m_commandLineArgs->includeDir() + '/' + it->first, buffer.str());
+
+ const std::string outputDir = isCrossModuleDeprecation
+ ? m_commandLineArgs->includeDir() + "/../" + moduleName
+ : m_commandLineArgs->includeDir();
+ writeIfDifferent(outputDir + '/' + headerName, buffer.str());
+
+ // Add header file to staging installation directory for cross-module deprecation case.
+ if (isCrossModuleDeprecation) {
+ const std::string stagingDir = outputDir + "/.syncqt_staging/";
+ writeIfDifferent(stagingDir + headerName, buffer.str());
+ }
+ m_producedHeaders.insert(headerName);
}
- return true;
+ return result;
}
[[nodiscard]] bool generateHeaderCheckExceptions()
@@ -1433,7 +1658,7 @@ public:
return writeIfDifferent(m_commandLineArgs->versionScriptFile(), buffer.str());
}
- bool updateOrCopy(const std::filesystem::path &src, const std::filesystem::path &dst);
+ bool updateOrCopy(const std::filesystem::path &src, const std::filesystem::path &dst) noexcept;
void updateSymbolDescriptor(const std::string &symbol, const std::string &file,
SymbolDescriptor::SourceType type);
};
@@ -1459,7 +1684,8 @@ SyncScanner::makeHeaderAbsolute(const std::string &filename) const
return utils::normilizedPath(filename);
}
-bool SyncScanner::updateOrCopy(const std::filesystem::path &src, const std::filesystem::path &dst)
+bool SyncScanner::updateOrCopy(const std::filesystem::path &src,
+ const std::filesystem::path &dst) noexcept
{
if (m_commandLineArgs->showOnly())
return true;
@@ -1506,7 +1732,7 @@ bool SyncScanner::generateQtCamelCaseFileIfContentChanged(const std::string &out
std::string buffer = "#include \"";
buffer += aliasedFilePath;
- buffer += "\"\n";
+ buffer += "\" // IWYU pragma: export\n";
return writeIfDifferent(outputFilePath, buffer);
}
@@ -1533,7 +1759,7 @@ bool SyncScanner::generateAliasedHeaderFileIfTimestampChanged(const std::string
std::cerr << "Unable to write header file alias: " << outputFilePath << std::endl;
return false;
}
- ofs << "#include \"" << aliasedFilePath << "\"\n";
+ ofs << "#include \"" << aliasedFilePath << "\" // IWYU pragma: export\n";
ofs.close();
return true;
}
@@ -1548,8 +1774,9 @@ bool SyncScanner::writeIfDifferent(const std::string &outputFile, const std::str
std::filesystem::path outputFilePath(outputFile);
std::string outputDirectory = outputFilePath.parent_path().string();
- if (!std::filesystem::exists(outputDirectory))
- std::filesystem::create_directories(outputDirectory);
+
+ if (!utils::createDirectories(outputDirectory, "Unable to create output directory"))
+ return false;
auto expectedSize = buffer.size();
#ifdef _WINDOWS
@@ -1563,6 +1790,10 @@ bool SyncScanner::writeIfDifferent(const std::string &outputFile, const std::str
memset(rdBuffer, 0, bufferSize);
std::ifstream ifs(outputFile, std::fstream::in);
+ if (!ifs.is_open()) {
+ std::cerr << "Unable to open " << outputFile << " for comparison." << std::endl;
+ return false;
+ }
std::streamsize currentPos = 0;
std::size_t bytesRead = 0;
diff --git a/src/tools/tracegen/ctf.cpp b/src/tools/tracegen/ctf.cpp
index 5a3902dd71..95ffcf89cc 100644
--- a/src/tools/tracegen/ctf.cpp
+++ b/src/tools/tracegen/ctf.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "ctf.h"
#include "provider.h"
@@ -15,6 +15,7 @@
static void writePrologue(QTextStream &stream, const QString &fileName, const Provider &provider)
{
+ writeCommonPrologue(stream);
const QString guard = includeGuard(fileName);
// include prefix text or qt headers only once
@@ -148,7 +149,7 @@ inline QString floatArrayToMetadata(const QString &size, const QString &name)
ret += QStringLiteral("double ");
else if (sizeof(T) == 4)
ret += QStringLiteral("float ");
- ret += name + QLatin1Char('[') + size + QStringLiteral("];");
+ ret += name + QLatin1Char('[') + size + QLatin1Char(']');
return ret + QLatin1Char(';');
}
diff --git a/src/tools/tracegen/ctf.h b/src/tools/tracegen/ctf.h
index 54f5e398c2..113e30919f 100644
--- a/src/tools/tracegen/ctf.h
+++ b/src/tools/tracegen/ctf.h
@@ -1,5 +1,5 @@
// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef CTF_H
#define CTF_H
diff --git a/src/tools/tracegen/etw.cpp b/src/tools/tracegen/etw.cpp
index 0bf8d0e2d2..f54a7896ea 100644
--- a/src/tools/tracegen/etw.cpp
+++ b/src/tools/tracegen/etw.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "etw.h"
#include "provider.h"
@@ -104,6 +104,7 @@ static QString createGuid(const QUuid &uuid)
static void writePrologue(QTextStream &stream, const QString &fileName, const Provider &provider)
{
+ writeCommonPrologue(stream);
QUuid uuid = QUuid::createUuidV5(QUuid(), provider.name.toLocal8Bit());
const QString providerV = providerVar(provider.name);
diff --git a/src/tools/tracegen/etw.h b/src/tools/tracegen/etw.h
index ad68fe08de..88508e2034 100644
--- a/src/tools/tracegen/etw.h
+++ b/src/tools/tracegen/etw.h
@@ -1,5 +1,5 @@
// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef ETW_H
#define ETW_H
diff --git a/src/tools/tracegen/helpers.cpp b/src/tools/tracegen/helpers.cpp
index db0fdb142e..0ea5848493 100644
--- a/src/tools/tracegen/helpers.cpp
+++ b/src/tools/tracegen/helpers.cpp
@@ -1,11 +1,20 @@
// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "helpers.h"
#include <qdebug.h>
using namespace Qt::StringLiterals;
+void writeCommonPrologue(QTextStream &stream)
+{
+ stream << R"CPP(
+#ifndef Q_TRACEPOINT
+#error "Q_TRACEPOINT not set for the module, Q_TRACE not enabled."
+#endif
+)CPP";
+}
+
QString typeToTypeName(const QString &name)
{
QString ret = name;
diff --git a/src/tools/tracegen/helpers.h b/src/tools/tracegen/helpers.h
index 00a1f99686..ea6db016a6 100644
--- a/src/tools/tracegen/helpers.h
+++ b/src/tools/tracegen/helpers.h
@@ -1,5 +1,5 @@
// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef HELPERS_H
#define HELPERS_H
@@ -8,6 +8,7 @@
#include <qlist.h>
#include <qstring.h>
+#include <qtextstream.h>
enum ParamType {
LTTNG,
@@ -20,6 +21,8 @@ QString includeGuard(const QString &filename);
QString formatFunctionSignature(const QList<Tracepoint::Argument> &args);
QString formatParameterList(const Provider &provider, const QList<Tracepoint::Argument> &args, const QList<Tracepoint::Field> &fields, ParamType type);
+void writeCommonPrologue(QTextStream &stream);
+
template <typename T>
static QString aggregateListValues(int value, const QList<T> &list)
{
diff --git a/src/tools/tracegen/lttng.cpp b/src/tools/tracegen/lttng.cpp
index b812682217..9711570874 100644
--- a/src/tools/tracegen/lttng.cpp
+++ b/src/tools/tracegen/lttng.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "lttng.h"
#include "provider.h"
@@ -20,8 +20,19 @@ static void writeCtfMacro(QTextStream &stream, const Provider &provider, const T
const int arrayLen = field.arrayLen;
if (arrayLen > 0) {
- stream << "ctf_array(" <<paramType << ", "
- << name << ", " << name << ", " << arrayLen << ")";
+ if (paramType == QStringLiteral("double") || paramType == QStringLiteral("float")) {
+ const char *newline = nullptr;
+ for (int i = 0; i < arrayLen; i++) {
+ stream << newline;
+ stream << "ctf_float(" <<paramType << ", " << name << "_" << QString::number(i) << ", "
+ << name << "[" << QString::number(i) << "]" << ")";
+ newline = "\n ";
+ }
+
+ } else {
+ stream << "ctf_array(" <<paramType << ", "
+ << name << ", " << name << ", " << arrayLen << ")";
+ }
return;
}
@@ -56,24 +67,24 @@ static void writeCtfMacro(QTextStream &stream, const Provider &provider, const T
stream << "ctf_string(" << name << ", " << name << ".toString().toUtf8().constData())";
return;
case Tracepoint::Field::QtRect:
- stream << "ctf_integer(int, x, " << name << ".x()) "
- << "ctf_integer(int, y, " << name << ".y()) "
- << "ctf_integer(int, width, " << name << ".width()) "
- << "ctf_integer(int, height, " << name << ".height()) ";
+ stream << "ctf_integer(int, QRect_" << name << "_x, " << name << ".x()) "
+ << "ctf_integer(int, QRect_" << name << "_y, " << name << ".y()) "
+ << "ctf_integer(int, QRect_" << name << "_width, " << name << ".width()) "
+ << "ctf_integer(int, QRect_" << name << "_height, " << name << ".height()) ";
return;
case Tracepoint::Field::QtSizeF:
- stream << "ctf_float(int, width, " << name << ".width()) "
- << "ctf_float(int, height, " << name << ".height()) ";
+ stream << "ctf_float(double, QSizeF_" << name << "_width, " << name << ".width()) "
+ << "ctf_float(double, QSizeF_" << name << "_height, " << name << ".height()) ";
return;
case Tracepoint::Field::QtRectF:
- stream << "ctf_float(int, x, " << name << ".x()) "
- << "ctf_float(int, y, " << name << ".y()) "
- << "ctf_float(int, width, " << name << ".width()) "
- << "ctf_float(int, height, " << name << ".height()) ";
+ stream << "ctf_float(double, QRectF_" << name << "_x, " << name << ".x()) "
+ << "ctf_float(double, QRectF_" << name << "_y, " << name << ".y()) "
+ << "ctf_float(double, QRectF_" << name << "_width, " << name << ".width()) "
+ << "ctf_float(double, QRectF_" << name << "_height, " << name << ".height()) ";
return;
case Tracepoint::Field::QtSize:
- stream << "ctf_integer(int, width, " << name << ".width()) "
- << "ctf_integer(int, height, " << name << ".height()) ";
+ stream << "ctf_integer(int, QSize_" << name << "_width, " << name << ".width()) "
+ << "ctf_integer(int, QSize_" << name << "_height, " << name << ".height()) ";
return;
case Tracepoint::Field::EnumeratedType:
stream << "ctf_enum(" << provider.name << ", " << typeToTypeName(paramType) << ", int, " << name << ", " << name << ") ";
@@ -90,6 +101,7 @@ static void writeCtfMacro(QTextStream &stream, const Provider &provider, const T
static void writePrologue(QTextStream &stream, const QString &fileName, const Provider &provider)
{
+ writeCommonPrologue(stream);
const QString guard = includeGuard(fileName);
stream << "#undef TRACEPOINT_PROVIDER\n";
diff --git a/src/tools/tracegen/lttng.h b/src/tools/tracegen/lttng.h
index d8fbd1291e..c36c70a1d4 100644
--- a/src/tools/tracegen/lttng.h
+++ b/src/tools/tracegen/lttng.h
@@ -1,5 +1,5 @@
// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef LTTNG_H
#define LTTNG_H
diff --git a/src/tools/tracegen/panic.cpp b/src/tools/tracegen/panic.cpp
index 5258b5ba9d..fa4e6b3ee3 100644
--- a/src/tools/tracegen/panic.cpp
+++ b/src/tools/tracegen/panic.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "panic.h"
diff --git a/src/tools/tracegen/panic.h b/src/tools/tracegen/panic.h
index 51cd96fba6..ee635a8aeb 100644
--- a/src/tools/tracegen/panic.h
+++ b/src/tools/tracegen/panic.h
@@ -1,5 +1,5 @@
// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef PANIC_H
#define PANIC_H
diff --git a/src/tools/tracegen/provider.cpp b/src/tools/tracegen/provider.cpp
index 0a0b033d84..bdd669c9cd 100644
--- a/src/tools/tracegen/provider.cpp
+++ b/src/tools/tracegen/provider.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "provider.h"
#include "panic.h"
diff --git a/src/tools/tracegen/provider.h b/src/tools/tracegen/provider.h
index 29d83f2a40..e5e99b868e 100644
--- a/src/tools/tracegen/provider.h
+++ b/src/tools/tracegen/provider.h
@@ -1,5 +1,5 @@
// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef PROVIDER_H
#define PROVIDER_H
diff --git a/src/tools/tracegen/qtheaders.cpp b/src/tools/tracegen/qtheaders.cpp
index a65ece5c5b..237c22b237 100644
--- a/src/tools/tracegen/qtheaders.cpp
+++ b/src/tools/tracegen/qtheaders.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qtheaders.h"
diff --git a/src/tools/tracegen/qtheaders.h b/src/tools/tracegen/qtheaders.h
index 6be4d15f4a..86405c9479 100644
--- a/src/tools/tracegen/qtheaders.h
+++ b/src/tools/tracegen/qtheaders.h
@@ -1,5 +1,5 @@
// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QTHEADERS_H
#define QTHEADERS_H
diff --git a/src/tools/tracegen/tracegen.cpp b/src/tools/tracegen/tracegen.cpp
index 46b354c520..776d81675d 100644
--- a/src/tools/tracegen/tracegen.cpp
+++ b/src/tools/tracegen/tracegen.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Rafael Roquetto <rafael.roquetto@kdab.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "provider.h"
#include "ctf.h"
diff --git a/src/tools/tracepointgen/parser.cpp b/src/tools/tracepointgen/parser.cpp
index 93adc13999..ad94b9a433 100644
--- a/src/tools/tracepointgen/parser.cpp
+++ b/src/tools/tracepointgen/parser.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "tracepointgen.h"
#include "parser.h"
@@ -11,7 +11,7 @@ static void removeOffsetRange(qsizetype begin, qsizetype end, QList<LineNumber>
{
qsizetype count = end - begin;
qsizetype i = 0;
- DEBUGPRINTF2(printf("tracepointgen: removeOffsetRange: %d %d\n", begin, end));
+ DEBUGPRINTF2(printf("tracepointgen: removeOffsetRange: %llu %llu\n", begin, end));
while (i < offsets.size()) {
LineNumber &cur = offsets[i];
if (begin > cur.end) {
@@ -21,7 +21,7 @@ static void removeOffsetRange(qsizetype begin, qsizetype end, QList<LineNumber>
i++;
} else if (begin < cur.begin && end > cur.end) {
offsets.remove(i);
- DEBUGPRINTF2(printf("tracepointgen: removeOffsetRange: %d, %d, %d\n", cur.begin, cur.end, cur.line));
+ DEBUGPRINTF2(printf("tracepointgen: removeOffsetRange: %llu, %llu, %d\n", cur.begin, cur.end, cur.line));
} else if (end >= cur.begin && end <= cur.end) {
cur.begin = begin;
cur.end -= count;
@@ -130,9 +130,9 @@ static QString preprocessMetadata(const QString &in)
int Parser::lineNumber(qsizetype offset) const
{
- DEBUGPRINTF(printf("tracepointgen: lineNumber: offset %u, line count: %u\n", offset , m_offsets.size()));
+ DEBUGPRINTF(printf("tracepointgen: lineNumber: offset %llu, line count: %llu\n", offset , m_offsets.size()));
for (const auto line : m_offsets) {
- DEBUGPRINTF(printf("tracepointgen: lineNumber: %d %d %d\n", line.begin, line.end, line.line));
+ DEBUGPRINTF(printf("tracepointgen: lineNumber: %llu %llu %d\n", line.begin, line.end, line.line));
if (offset >= line.begin && offset <= line.end)
return line.line;
}
@@ -147,7 +147,7 @@ void Parser::parseParamReplace(const QString &data, qsizetype offset, const QStr
QString params = data.mid(beginBrace + 1, endBrace - beginBrace -1);
int punc = params.indexOf(QLatin1Char(','));
if (punc < 0)
- panic("Syntax error in Q_TRACE_PARAM_REPLACE at file %s, line %d", qPrintable(name), lineNumber(offset));
+ panic("Syntax error in Q_TRACE_PARAM_REPLACE at file %s, line %llu", qPrintable(name), lineNumber(offset));
rep.in = params.left(punc).simplified();
rep.out = params.right(params.length() - punc - 1).simplified();
if (rep.in.endsWith(QLatin1Char('*')) || rep.out.endsWith(QLatin1Char(']')))
@@ -307,10 +307,9 @@ QStringList Parser::findEnumValues(const QString &name, const QStringList &inclu
ret << trimmed;
}
- break;
+ return ret;
}
}
- return ret;
}
}
return ret;
@@ -354,8 +353,11 @@ static QList<EnumNameValue> enumsToValues(const QStringList &values)
}
}
} else {
- r.name = value;
- r.value = cur++;
+ if (value.endsWith(QLatin1Char(',')))
+ r.name = value.left(value.length() - 1);
+ else
+ r.name = value;
+ r.value = ++cur;
ret << r;
}
}
@@ -385,7 +387,7 @@ void Parser::parseMetadata(const QString &data, qsizetype offset, const QStringL
qsizetype prev = 0;
while (i.hasNext()) {
QRegularExpressionMatch match = i.next();
- const QString values = match.captured(2).trimmed();
+ QString values = match.captured(2).trimmed();
int cur = match.capturedStart();
if (cur > prev)
m_metadata.append(preprocessed.mid(prev, cur - prev));
@@ -393,7 +395,7 @@ void Parser::parseMetadata(const QString &data, qsizetype offset, const QStringL
prev = match.capturedEnd() + 1;
DEBUGPRINTF2(printf("values: %s\n", qPrintable(values)));
if (values.isEmpty() || values.startsWith(QStringLiteral("AUTO"))) {
-
+ values.replace(QLatin1Char('\n'), QLatin1Char(' '));
QStringList ranges;
if (values.contains(QStringLiteral("RANGE"))) {
QRegularExpression rangeMacro(QStringLiteral("RANGE +([A-Za-z0-9_]*) +... +([A-Za-z0-9_]*)"));
@@ -422,16 +424,23 @@ void Parser::parseMetadata(const QString &data, qsizetype offset, const QStringL
auto moreValues = enumsToValues(values);
if (ranges.size()) {
for (int i = 0; i < ranges.size() / 2; i++) {
+ bool rangeFound = false;
for (auto &v : moreValues) {
if (v.name == ranges[2 * i]) {
+ rangeFound = true;
QString rangeEnd = ranges[2 * i + 1];
auto iter = std::find_if(moreValues.begin(), moreValues.end(), [&rangeEnd](const EnumNameValue &elem){
return elem.name == rangeEnd;
});
if (iter != moreValues.end())
v.valueStr = QStringLiteral("RANGE(%1, %2 ... %3)").arg(v.name).arg(v.value).arg(iter->value);
+ else
+ panic("Unable to find range end: %s\n", qPrintable(rangeEnd));
+ break;
}
}
+ if (rangeFound == false)
+ panic("Unable to find range begin: %s\n", qPrintable(ranges[2 * i]));
}
}
std::sort(moreValues.begin(), moreValues.end(), [](const EnumNameValue &a, const EnumNameValue &b) {
diff --git a/src/tools/tracepointgen/parser.h b/src/tools/tracepointgen/parser.h
index 1978e3aa6a..389734983d 100644
--- a/src/tools/tracepointgen/parser.h
+++ b/src/tools/tracepointgen/parser.h
@@ -1,5 +1,5 @@
// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef PARSER_H
#define PARSER_H
diff --git a/src/tools/tracepointgen/tracepointgen.cpp b/src/tools/tracepointgen/tracepointgen.cpp
index 873b9cbfca..d814c69873 100644
--- a/src/tools/tracepointgen/tracepointgen.cpp
+++ b/src/tools/tracepointgen/tracepointgen.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <qstring.h>
#include <qstringlist.h>
diff --git a/src/tools/tracepointgen/tracepointgen.h b/src/tools/tracepointgen/tracepointgen.h
index fe332ed03d..6aed3dc574 100644
--- a/src/tools/tracepointgen/tracepointgen.h
+++ b/src/tools/tracepointgen/tracepointgen.h
@@ -1,5 +1,5 @@
// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef TRACEPOINTGEN_H
#define TRACEPOINTGEN_H
diff --git a/src/tools/uic/CMakeLists.txt b/src/tools/uic/CMakeLists.txt
index 9f9ea93bea..9f47ec8b4b 100644
--- a/src/tools/uic/CMakeLists.txt
+++ b/src/tools/uic/CMakeLists.txt
@@ -7,6 +7,7 @@
qt_get_tool_target_name(target_name uic)
qt_internal_add_tool(${target_name}
+ TRY_RUN
TARGET_DESCRIPTION "Qt User Interface Compiler"
INSTALL_DIR "${INSTALL_LIBEXECDIR}"
TOOLS_TARGET Widgets
@@ -31,6 +32,7 @@ qt_internal_add_tool(${target_name}
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_FOREACH
+ QT_USE_NODISCARD_FILE_OPEN
QT_UIC
INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR}
diff --git a/src/tools/uic/cpp/cppwriteinitialization.cpp b/src/tools/uic/cpp/cppwriteinitialization.cpp
index d791f9cb54..205d6a50a9 100644
--- a/src/tools/uic/cpp/cppwriteinitialization.cpp
+++ b/src/tools/uic/cpp/cppwriteinitialization.cpp
@@ -24,6 +24,34 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
namespace {
+
+ // Expand "Horizontal", "Qt::Horizontal" to "Qt::Orientation::Horizontal"
+ QString expandEnum(QString value, const QString &prefix)
+ {
+ if (value.startsWith(prefix))
+ return value;
+ const auto pos = value.lastIndexOf("::"_L1);
+ if (pos == -1)
+ return prefix + "::"_L1 + value;
+ value.replace(0, pos, prefix);
+ return value;
+ }
+
+ inline QString expandSizePolicyEnum(const QString &value)
+ {
+ return expandEnum(value, "QSizePolicy::Policy"_L1);
+ }
+
+ inline QString expandToolBarArea(const QString &value)
+ {
+ return expandEnum(value, "Qt::ToolBarArea"_L1);
+ }
+
+ inline QString expandDockWidgetArea(const QString &value)
+ {
+ return expandEnum(value, "Qt::DockWidgetArea"_L1);
+ }
+
// 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.
QString toolBarAreaStringFromDOMAttributes(const CPP::WriteInitialization::DomPropertyMap &attributes) {
@@ -33,7 +61,7 @@ namespace {
return result;
switch (pstyle->kind()) {
case DomProperty::Number:
- result = QLatin1StringView(language::toolbarArea(pstyle->elementNumber()));
+ result = language::toolbarArea(pstyle->elementNumber());
break;
case DomProperty::Enum:
result = pstyle->elementEnum();
@@ -41,9 +69,7 @@ namespace {
default:
break;
}
- if (!result.startsWith("Qt::"_L1))
- result.prepend("Qt::"_L1);
- return result + ", "_L1;
+ return expandToolBarArea(result) + ", "_L1;
}
// Write a statement to create a spacer item.
@@ -62,27 +88,17 @@ namespace {
output << w << ", " << h << ", ";
// size type
- QString sizeType;
- if (const DomProperty *st = properties.value("sizeType"_L1)) {
- const QString value = st->elementEnum();
- if (value.startsWith("QSizePolicy::"_L1))
- sizeType = value;
- else
- sizeType = "QSizePolicy::"_L1 + value;
- } else {
- sizeType = QStringLiteral("QSizePolicy::Expanding");
- }
+ const DomProperty *st = properties.value("sizeType"_L1);
+ QString horizType = st != nullptr ? st->elementEnum() : "Expanding"_L1;
+ QString vertType = "Minimum"_L1;
// orientation
- bool isVspacer = false;
- if (const DomProperty *o = properties.value("orientation"_L1)) {
- const QString orientation = o->elementEnum();
- if (orientation == "Qt::Vertical"_L1 || orientation == "Vertical"_L1)
- isVspacer = true;
- }
- const QString horizType = isVspacer ? "QSizePolicy::Minimum"_L1 : sizeType;
- const QString vertType = isVspacer ? sizeType : "QSizePolicy::Minimum"_L1;
- output << language::enumValue(horizType) << ", " << language::enumValue(vertType) << ')';
+ const DomProperty *o = properties.value("orientation"_L1);
+ if (o != nullptr && o->elementEnum().endsWith("Vertical"_L1))
+ std::swap(horizType, vertType);
+
+ output << language::enumValue(expandSizePolicyEnum(horizType)) << ", "
+ << language::enumValue(expandSizePolicyEnum(vertType)) << ')';
}
@@ -180,6 +196,15 @@ FontHandle::FontHandle(const DomFont *domFont) :
{
}
+static QString fontWeight(const DomFont *domFont)
+{
+ if (domFont->hasElementFontWeight())
+ return domFont->elementFontWeight();
+ if (domFont->hasElementBold())
+ return domFont->elementBold() ? u"Bold"_s : u"Normal"_s;
+ return {};
+}
+
int FontHandle::compare(const FontHandle &rhs) const
{
const QString family = m_domFont->hasElementFamily() ? m_domFont->elementFamily() : QString();
@@ -194,10 +219,10 @@ int FontHandle::compare(const FontHandle &rhs) const
if (const int crc = compareInt(pointSize, rhsPointSize))
return crc;
- const int bold = m_domFont->hasElementBold() ? (m_domFont->elementBold() ? 1 : 0) : -1;
- const int rhsBold = rhs.m_domFont->hasElementBold() ? (rhs.m_domFont->elementBold() ? 1 : 0) : -1;
- if (const int crc = compareInt(bold, rhsBold))
- return crc;
+ const QString fontWeight = CPP::fontWeight(m_domFont);
+ const QString rhsFontWeight = CPP::fontWeight(rhs.m_domFont);
+ if (const int wrc = fontWeight.compare(rhsFontWeight))
+ return wrc;
const int italic = m_domFont->hasElementItalic() ? (m_domFont->elementItalic() ? 1 : 0) : -1;
const int rhsItalic = rhs.m_domFont->hasElementItalic() ? (rhs.m_domFont->elementItalic() ? 1 : 0) : -1;
@@ -209,11 +234,6 @@ int FontHandle::compare(const FontHandle &rhs) const
if (const int crc = compareInt(underline, rhsUnderline))
return crc;
- const int weight = m_domFont->hasElementWeight() ? m_domFont->elementWeight() : -1;
- const int rhsWeight = rhs.m_domFont->hasElementWeight() ? rhs.m_domFont->elementWeight() : -1;
- if (const int crc = compareInt(weight, rhsWeight))
- return crc;
-
const int strikeOut = m_domFont->hasElementStrikeOut() ? (m_domFont->elementStrikeOut() ? 1 : 0) : -1;
const int rhsStrikeOut = rhs.m_domFont->hasElementStrikeOut() ? (rhs.m_domFont->elementStrikeOut() ? 1 : 0) : -1;
if (const int crc = compareInt(strikeOut, rhsStrikeOut))
@@ -235,6 +255,13 @@ int FontHandle::compare(const FontHandle &rhs) const
if (const int src = styleStrategy.compare(rhsStyleStrategy))
return src;
+ const QString hintingPreference = m_domFont->hasElementHintingPreference()
+ ? m_domFont->elementHintingPreference() : QString();
+ const QString rhsHintingPreference = rhs.m_domFont->hasElementHintingPreference()
+ ? rhs.m_domFont->elementHintingPreference() : QString();
+ if (const int src = hintingPreference.compare(rhsHintingPreference))
+ return src;
+
return 0;
}
@@ -690,8 +717,8 @@ void WriteInitialization::acceptWidget(DomWidget *node)
} else if (cwi->extends(className, "QDockWidget")) {
m_output << m_indent << parentWidget << language::derefPointer << "addDockWidget(";
if (DomProperty *pstyle = attributes.value("dockWidgetArea"_L1)) {
- m_output << "Qt" << language::qualifier
- << language::dockWidgetArea(pstyle->elementNumber()) << ", ";
+ QString a = expandDockWidgetArea(language::dockWidgetArea(pstyle->elementNumber()));
+ m_output << language::enumValue(a) << ", ";
}
m_output << varName << ")" << language::eol;
} else if (m_uic->customWidgetsInfo()->extends(className, "QStatusBar")) {
@@ -1273,9 +1300,9 @@ void WriteInitialization::writeProperties(const QString &varName,
} else if (propertyName == "orientation"_L1
&& m_uic->customWidgetsInfo()->extends(className, "Line")) {
// Line support
- QString shape = u"QFrame::HLine"_s;
- if (p->elementEnum() == "Qt::Vertical"_L1)
- shape = u"QFrame::VLine"_s;
+ QString shape = u"QFrame::Shape::HLine"_s;
+ if (p->elementEnum().endsWith("::Vertical"_L1))
+ shape = u"QFrame::Shape::VLine"_s;
m_output << m_indent << varName << language::derefPointer << "setFrameShape("
<< language::enumValue(shape) << ')' << language::eol;
@@ -1283,7 +1310,7 @@ void WriteInitialization::writeProperties(const QString &varName,
if (!frameShadowEncountered) {
m_output << m_indent << varName << language::derefPointer
<< "setFrameShadow("
- << language::enumValue("QFrame::Sunken"_L1)
+ << language::enumValue("QFrame::Shadow::Sunken"_L1)
<< ')' << language::eol;
}
continue;
@@ -1366,8 +1393,8 @@ void WriteInitialization::writeProperties(const QString &varName,
case DomProperty::CursorShape:
if (p->hasAttributeStdset() && !p->attributeStdset())
varNewName += language::derefPointer + "viewport()"_L1;
- propertyValue = "QCursor(Qt"_L1 + language::qualifier
- + p->elementCursorShape() + u')';
+ propertyValue = "QCursor(Qt"_L1 + language::qualifier + "CursorShape"_L1
+ + language::qualifier + p->elementCursorShape() + u')';
break;
case DomProperty::Enum:
propertyValue = p->elementEnum();
@@ -1583,12 +1610,18 @@ QString WriteInitialization::writeSizePolicy(const DomSizePolicy *sp)
m_sizePolicyNameMap.insert(sizePolicyHandle, spName);
m_output << m_indent << language::stackVariableWithInitParameters("QSizePolicy", spName);
+ QString horizPolicy;
+ QString vertPolicy;
if (sp->hasElementHSizeType() && sp->hasElementVSizeType()) {
- m_output << "QSizePolicy" << language::qualifier << language::sizePolicy(sp->elementHSizeType())
- << ", QSizePolicy" << language::qualifier << language::sizePolicy(sp->elementVSizeType());
+ horizPolicy = language::sizePolicy(sp->elementHSizeType());
+ vertPolicy = language::sizePolicy(sp->elementVSizeType());
} else if (sp->hasAttributeHSizeType() && sp->hasAttributeVSizeType()) {
- m_output << "QSizePolicy" << language::qualifier << sp->attributeHSizeType()
- << ", QSizePolicy" << language::qualifier << sp->attributeVSizeType();
+ horizPolicy = sp->attributeHSizeType();
+ vertPolicy = sp->attributeVSizeType();
+ }
+ if (!horizPolicy.isEmpty() && !vertPolicy.isEmpty()) {
+ m_output << language::enumValue(expandSizePolicyEnum(horizPolicy))
+ << ", " << language::enumValue(expandSizePolicyEnum(vertPolicy));
}
m_output << ')' << language::eol;
@@ -1627,10 +1660,14 @@ QString WriteInitialization::writeFontProperties(const DomFont *f)
<< ")" << language::eol;
}
- if (f->hasElementBold()) {
+ if (f->hasElementFontWeight()) {
+ m_output << m_indent << fontName << ".setWeight(QFont"
+ << language::qualifier << f->elementFontWeight() << ')' << language::eol;
+ } else if (f->hasElementBold()) {
m_output << m_indent << fontName << ".setBold("
<< language::boolValue(f->elementBold()) << ')' << language::eol;
}
+
if (f->hasElementItalic()) {
m_output << m_indent << fontName << ".setItalic("
<< language::boolValue(f->elementItalic()) << ')' << language::eol;
@@ -1657,6 +1694,11 @@ QString WriteInitialization::writeFontProperties(const DomFont *f)
m_output << m_indent << fontName << ".setStyleStrategy(QFont"
<< language::qualifier << f->elementStyleStrategy() << ')' << language::eol;
}
+ if (f->hasElementHintingPreference()) {
+ m_output << m_indent << fontName << ".setHintingPreference(QFont"
+ << language::qualifier << f->elementHintingPreference() << ')' << language::eol;
+ }
+
return fontName;
}
@@ -1666,8 +1708,9 @@ static void writeIconAddFile(QTextStream &output, const QString &indent,
{
output << indent << iconName << ".addFile("
<< language::qstring(fileName, indent) << ", QSize(), QIcon"
- << language::qualifier << mode << ", QIcon" << language::qualifier
- << state << ')' << language::eol;
+ << language::qualifier << "Mode" << language::qualifier << mode
+ << ", QIcon" << language::qualifier << "State" << language::qualifier << state
+ << ')' << language::eol;
}
// Post 4.4 write resource icon
@@ -1715,7 +1758,8 @@ static void writeIconAddPixmap(QTextStream &output, const QString &indent,
const char *mode, const char *state)
{
output << indent << iconName << ".addPixmap(" << call << ", QIcon"
- << language::qualifier << mode << ", QIcon" << language::qualifier
+ << language::qualifier << "Mode" << language::qualifier << mode
+ << ", QIcon" << language::qualifier << "State" << language::qualifier
<< state << ')' << language::eol;
}
@@ -1766,6 +1810,59 @@ void WriteInitialization::writePixmapFunctionIcon(QTextStream &output,
}
}
+// Write QIcon::fromTheme() (value from enum or variable)
+struct iconFromTheme
+{
+ explicit iconFromTheme(const QString &theme) : m_theme(theme) {}
+
+ QString m_theme;
+};
+
+QTextStream &operator<<(QTextStream &str, const iconFromTheme &i)
+{
+ str << "QIcon" << language::qualifier << "fromTheme(" << i.m_theme << ')';
+ return str;
+}
+
+// Write QIcon::fromTheme() for an XDG icon from string literal
+struct iconFromThemeStringLiteral
+{
+ explicit iconFromThemeStringLiteral(const QString &theme) : m_theme(theme) {}
+
+ QString m_theme;
+};
+
+QTextStream &operator<<(QTextStream &str, const iconFromThemeStringLiteral &i)
+{
+ str << "QIcon" << language::qualifier << "fromTheme(" << language::qstring(i.m_theme) << ')';
+ return str;
+}
+
+// Write QIcon::fromTheme() with a path as fallback, add a check using
+// QIcon::hasThemeIcon().
+void WriteInitialization::writeThemeIconCheckAssignment(const QString &themeValue,
+ const QString &iconName,
+ const DomResourceIcon *i)
+
+{
+ const bool isCpp = language::language() == Language::Cpp;
+ m_output << m_indent << "if ";
+ if (isCpp)
+ m_output << '(';
+ m_output << "QIcon" << language::qualifier << "hasThemeIcon("
+ << themeValue << ')' << (isCpp ? ") {" : ":") << '\n'
+ << m_dindent << iconName << " = " << iconFromTheme(themeValue)
+ << language::eol;
+ m_output << m_indent << (isCpp ? "} else {" : "else:") << '\n';
+ if (m_uic->pixmapFunction().isEmpty())
+ writeResourceIcon(m_output, iconName, m_dindent, i);
+ else
+ writePixmapFunctionIcon(m_output, iconName, m_dindent, i);
+ if (isCpp)
+ m_output << m_indent << '}';
+ m_output << '\n';
+}
+
QString WriteInitialization::writeIconProperties(const DomResourceIcon *i)
{
// check cache
@@ -1790,7 +1887,8 @@ QString WriteInitialization::writeIconProperties(const DomResourceIcon *i)
}
// 4.4 onwards
- if (i->attributeTheme().isEmpty()) {
+ QString theme = i->attributeTheme();
+ if (theme.isEmpty()) {
// No theme: Write resource icon as is
m_output << m_indent << language::stackVariable("QIcon", iconName)
<< language::eol;
@@ -1801,12 +1899,21 @@ QString WriteInitialization::writeIconProperties(const DomResourceIcon *i)
return iconName;
}
+ const bool isThemeEnum = theme.startsWith("QIcon::"_L1);
+ if (isThemeEnum)
+ theme = language::enumValue(theme);
+
// Theme: Generate code to check the theme and default to resource
if (iconHasStatePixmaps(i)) {
// Theme + default state pixmaps:
// Generate code to check the theme and default to state pixmaps
m_output << m_indent << language::stackVariable("QIcon", iconName) << language::eol;
- const char themeNameStringVariableC[] = "iconThemeName";
+ if (isThemeEnum) {
+ writeThemeIconCheckAssignment(theme, iconName, i);
+ return iconName;
+ }
+
+ static constexpr auto themeNameStringVariableC = "iconThemeName"_L1;
// Store theme name in a variable
m_output << m_indent;
if (m_firstThemeIcon) { // Declare variable string
@@ -1815,31 +1922,19 @@ QString WriteInitialization::writeIconProperties(const DomResourceIcon *i)
m_firstThemeIcon = false;
}
m_output << themeNameStringVariableC << " = "
- << language::qstring(i->attributeTheme()) << language::eol;
- m_output << m_indent << "if ";
- if (isCpp)
- m_output << '(';
- m_output << "QIcon" << language::qualifier << "hasThemeIcon("
- << themeNameStringVariableC << ')' << (isCpp ? ") {" : ":") << '\n'
- << m_dindent << iconName << " = QIcon" << language::qualifier << "fromTheme("
- << themeNameStringVariableC << ')' << language::eol
- << m_indent << (isCpp ? "} else {" : "else:") << '\n';
- if (m_uic->pixmapFunction().isEmpty())
- writeResourceIcon(m_output, iconName, m_dindent, i);
- else
- writePixmapFunctionIcon(m_output, iconName, m_dindent, i);
- if (isCpp)
- m_output << m_indent << '}';
- m_output << '\n';
+ << language::qstring(theme) << language::eol;
+ writeThemeIconCheckAssignment(themeNameStringVariableC, iconName, i);
return iconName;
}
// Theme, but no state pixmaps: Construct from theme directly.
m_output << m_indent
- << language::stackVariableWithInitParameters("QIcon", iconName)
- << "QIcon" << language::qualifier << "fromTheme("
- << language::qstring(i->attributeTheme()) << "))"
- << language::eol;
+ << language::stackVariableWithInitParameters("QIcon", iconName);
+ if (isThemeEnum)
+ m_output << iconFromTheme(theme);
+ else
+ m_output << iconFromThemeStringLiteral(theme);
+ m_output << ')' << language::eol;
return iconName;
}
@@ -2605,10 +2700,6 @@ ConnectionSyntax WriteInitialization::connectionSyntax(const language::SignalSlo
return ConnectionSyntax::StringBased;
}
- // QTBUG-110952, ambiguous overloads of display()
- if (receiver.className == u"QLCDNumber" && receiver.signature.startsWith(u"display("))
- return ConnectionSyntax::StringBased;
-
if ((sender.name == m_mainFormVarName && m_customSignals.contains(sender.signature))
|| (receiver.name == m_mainFormVarName && m_customSlots.contains(receiver.signature))) {
return ConnectionSyntax::StringBased;
@@ -2636,14 +2727,21 @@ void WriteInitialization::acceptConnection(DomConnection *connection)
return;
}
const QString senderSignature = connection->elementSignal();
+ const QString slotSignature = connection->elementSlot();
+ const bool senderAmbiguous = m_uic->customWidgetsInfo()->isAmbiguousSignal(senderDecl.className,
+ senderSignature);
+ const bool slotAmbiguous = m_uic->customWidgetsInfo()->isAmbiguousSlot(receiverDecl.className,
+ slotSignature);
+
language::SignalSlotOptions signalOptions;
- if (m_uic->customWidgetsInfo()->isAmbiguousSignal(senderDecl.className, senderSignature))
- signalOptions.setFlag(language::SignalSlotOption::Ambiguous);
+ signalOptions.setFlag(language::SignalSlotOption::Ambiguous, senderAmbiguous);
+ language::SignalSlotOptions slotOptions;
+ slotOptions.setFlag(language::SignalSlotOption::Ambiguous, slotAmbiguous);
language::SignalSlot theSignal{senderDecl.name, senderSignature,
senderDecl.className, signalOptions};
- language::SignalSlot theSlot{receiverDecl.name, connection->elementSlot(),
- receiverDecl.className, {}};
+ language::SignalSlot theSlot{receiverDecl.name, slotSignature,
+ receiverDecl.className, slotOptions};
m_output << m_indent;
language::formatConnection(m_output, theSignal, theSlot,
diff --git a/src/tools/uic/cpp/cppwriteinitialization.h b/src/tools/uic/cpp/cppwriteinitialization.h
index 716af2e81d..0973def52d 100644
--- a/src/tools/uic/cpp/cppwriteinitialization.h
+++ b/src/tools/uic/cpp/cppwriteinitialization.h
@@ -5,7 +5,6 @@
#define CPPWRITEINITIALIZATION_H
#include "treewalker.h"
-#include <qpair.h>
#include <qhash.h>
#include <qset.h>
#include <qmap.h>
@@ -210,6 +209,8 @@ private:
private:
QString writeFontProperties(const DomFont *f);
QString writeIconProperties(const DomResourceIcon *i);
+ void writeThemeIconCheckAssignment(const QString &themeValue, const QString &iconName,
+ const DomResourceIcon *i);
void writePixmapFunctionIcon(QTextStream &output, const QString &iconName,
const QString &indent, const DomResourceIcon *i) const;
QString writeSizePolicy(const DomSizePolicy *sp);
diff --git a/src/tools/uic/customwidgetsinfo.cpp b/src/tools/uic/customwidgetsinfo.cpp
index 169cdad618..6ec418634c 100644
--- a/src/tools/uic/customwidgetsinfo.cpp
+++ b/src/tools/uic/customwidgetsinfo.cpp
@@ -78,19 +78,89 @@ bool CustomWidgetsInfo::isCustomWidgetContainer(const QString &className) const
return false;
}
+// FIXME in 7.0 - QTBUG-124241
+// Remove isAmbiguous logic when widget slots have been disambiguated.
+bool CustomWidgetsInfo::isAmbiguous(const QString &className, const QString &signature,
+ QMetaMethod::MethodType type) const
+{
+ using TypeMap = QHash<QString, QMetaMethod::MethodType>;
+ struct AmbiguousInClass {
+ QLatin1StringView className;
+ TypeMap methodMap;
+ };
+
+ static const QList<AmbiguousInClass> ambiguousList = {
+
+ {"QAction"_L1, {{"triggered"_L1, QMetaMethod::Signal}}},
+ {"QCommandLinkButton"_L1, {{"triggered"_L1, QMetaMethod::Signal},
+ {"clicked"_L1, QMetaMethod::Signal}}},
+ {"QPushButton"_L1, {{"triggered"_L1, QMetaMethod::Signal},
+ {"clicked"_L1, QMetaMethod::Signal}}},
+ {"QCheckBox"_L1, {{"triggered"_L1, QMetaMethod::Signal},
+ {"clicked"_L1, QMetaMethod::Signal}}},
+ {"QRadioButton"_L1, {{"triggered"_L1, QMetaMethod::Signal},
+ {"clicked"_L1, QMetaMethod::Signal}}},
+ {"QToolButton"_L1, {{"triggered"_L1, QMetaMethod::Signal},
+ {"clicked"_L1, QMetaMethod::Signal}}},
+ {"QLabel"_L1, {{"setNum"_L1, QMetaMethod::Slot}}},
+ {"QGraphicsView"_L1, {{"invalidateScene"_L1, QMetaMethod::Slot}}},
+ {"QListView"_L1, {{"dataChanged"_L1, QMetaMethod::Slot}}},
+ {"QColumnView"_L1, {{"dataChanged"_L1, QMetaMethod::Slot}}},
+ {"QListWidget"_L1, {{"dataChanged"_L1, QMetaMethod::Slot},
+ {"scrollToItem"_L1, QMetaMethod::Slot}}},
+ {"QTableView"_L1, {{"dataChanged"_L1, QMetaMethod::Slot}}},
+ {"QTableWidget"_L1, {{"dataChanged"_L1, QMetaMethod::Slot},
+ {"scrollToItem"_L1, QMetaMethod::Slot}}},
+ {"QTreeView"_L1, {{"dataChanged"_L1, QMetaMethod::Slot},
+ {"verticalScrollbarValueChanged"_L1, QMetaMethod::Slot},
+ {"expandRecursively"_L1, QMetaMethod::Slot}}},
+ {"QTreeWidget"_L1, {{"dataChanged"_L1, QMetaMethod::Slot},
+ {"verticalScrollbarValueChanged"_L1, QMetaMethod::Slot}
+ ,{"expandRecursively"_L1, QMetaMethod::Slot}
+ ,{"scrollToItem"_L1, QMetaMethod::Slot}}},
+ {"QUndoView"_L1, {{"dataChanged"_L1, QMetaMethod::Slot}}},
+ {"QLCDNumber"_L1, {{"display"_L1, QMetaMethod::Slot}}},
+ {"QMenuBar"_L1, {{"setVisible"_L1, QMetaMethod::Slot}}},
+ {"QTextBrowser"_L1, {{"setSource"_L1, QMetaMethod::Slot}}},
+
+ /*
+ The following widgets with ambiguities are not used in the widget designer:
+
+ {"QSplashScreen"_L1, {{"showMessage"_L1, QMetaMethod::Slot}}},
+ {"QCompleter"_L1, {{"activated"_L1, QMetaMethod::Signal},
+ {"highlighted"_L1, QMetaMethod::Signal}}},
+ {"QSystemTrayIcon"_L1, {{"showMessage"_L1, QMetaMethod::Slot}}},
+ {"QStyledItemDelegate"_L1, {{"closeEditor"_L1, QMetaMethod::Signal}}},
+ {"QErrorMessage"_L1, {{"showMessage"_L1, QMetaMethod::Slot}}},
+ {"QGraphicsDropShadowEffect"_L1, {{"setOffset"_L1, QMetaMethod::Slot}}},
+ {"QGraphicsScene"_L1, {{"invalidate"_L1, QMetaMethod::Slot}}},
+ {"QItemDelegate"_L1, {{"closeEditor"_L1, QMetaMethod::Signal}}}
+ */
+ };
+
+ for (auto it = ambiguousList.constBegin(); it != ambiguousList.constEnd(); ++it) {
+ if (extends(className, it->className)) {
+ const qsizetype pos = signature.indexOf(u'(');
+ const QString method = signature.left(pos);
+ const auto methodIterator = it->methodMap.find(method);
+ return methodIterator != it->methodMap.constEnd() && type == methodIterator.value();
+ }
+ }
+ return false;
+}
+
// Is it ambiguous, resulting in different signals for Python
// "QAbstractButton::clicked(checked=false)"
bool CustomWidgetsInfo::isAmbiguousSignal(const QString &className,
const QString &signalSignature) const
{
- if (signalSignature.startsWith(u"triggered") && extends(className, "QAction"))
- return true;
- if (signalSignature.startsWith(u"clicked(")
- && extendsOneOf(className, {u"QCommandLinkButton"_s, u"QCheckBox"_s,
- u"QPushButton"_s, u"QRadioButton"_s, u"QToolButton"_s})) {
- return true;
- }
- return false;
+ return isAmbiguous(className, signalSignature, QMetaMethod::Signal);
+}
+
+bool CustomWidgetsInfo::isAmbiguousSlot(const QString &className,
+ const QString &signalSignature) const
+{
+ return isAmbiguous(className, signalSignature, QMetaMethod::Slot);
}
QString CustomWidgetsInfo::realClassName(const QString &className) const
diff --git a/src/tools/uic/customwidgetsinfo.h b/src/tools/uic/customwidgetsinfo.h
index 4bd004bdc7..f336292f2a 100644
--- a/src/tools/uic/customwidgetsinfo.h
+++ b/src/tools/uic/customwidgetsinfo.h
@@ -7,6 +7,7 @@
#include "treewalker.h"
#include <qstringlist.h>
#include <qmap.h>
+#include <QtCore/qmetaobject.h>
QT_BEGIN_NAMESPACE
@@ -38,10 +39,14 @@ public:
bool isAmbiguousSignal(const QString &className,
const QString &signalSignature) const;
+ bool isAmbiguousSlot(const QString &className,
+ const QString &slotSignature) const;
private:
using NameCustomWidgetMap = QMap<QString, DomCustomWidget*>;
NameCustomWidgetMap m_customWidgets;
+ bool isAmbiguous(const QString &className, const QString &signature,
+ QMetaMethod::MethodType type) const;
};
QT_END_NAMESPACE
diff --git a/src/tools/uic/driver.cpp b/src/tools/uic/driver.cpp
index ab19f5a2b4..110764ee07 100644
--- a/src/tools/uic/driver.cpp
+++ b/src/tools/uic/driver.cpp
@@ -245,9 +245,10 @@ bool Driver::uic(const QString &fileName, DomUI *ui, QTextStream *out)
bool Driver::uic(const QString &fileName, QTextStream *out)
{
QFile f;
- if (fileName.isEmpty())
- f.open(stdin, QIODevice::ReadOnly);
- else {
+ if (fileName.isEmpty()) {
+ if (!f.open(stdin, QIODevice::ReadOnly))
+ return false;
+ } else {
f.setFileName(fileName);
if (!f.open(QIODevice::ReadOnly))
return false;
diff --git a/src/tools/uic/python/pythonwriteimports.cpp b/src/tools/uic/python/pythonwriteimports.cpp
index b122c0f895..74eeab8387 100644
--- a/src/tools/uic/python/pythonwriteimports.cpp
+++ b/src/tools/uic/python/pythonwriteimports.cpp
@@ -229,9 +229,13 @@ void WriteImports::addPythonCustomWidget(const QString &className, const DomCust
QString modulePath = node->elementHeader()->text();
// Replace the '/' by '.'
modulePath.replace(u'/', u'.');
- // '.h' is added by default on headers for <customwidget>
- if (modulePath.endsWith(".h"_L1))
+ // '.h' is added by default on headers for <customwidget>.
+ if (modulePath.endsWith(".h"_L1, Qt::CaseInsensitive))
modulePath.chop(2);
+ else if (modulePath.endsWith(".hh"_L1))
+ modulePath.chop(3);
+ else if (modulePath.endsWith(".hpp"_L1))
+ modulePath.chop(4);
insertClass(modulePath, className, &m_customWidgets);
}
}
diff --git a/src/tools/uic/shared/language.cpp b/src/tools/uic/shared/language.cpp
index 6567903000..d59688e346 100644
--- a/src/tools/uic/shared/language.cpp
+++ b/src/tools/uic/shared/language.cpp
@@ -4,6 +4,7 @@
#include "language.h"
#include <QtCore/qtextstream.h>
+#include <QtCore/QList>
namespace language {
@@ -83,19 +84,19 @@ QTextStream &operator<<(QTextStream &str, const closeQtConfig &c)
struct EnumLookup
{
int value;
- const char *valueString;
+ QLatin1StringView valueString;
};
template <int N>
-const char *lookupEnum(const EnumLookup(&array)[N], int value, int defaultIndex = 0)
+QLatin1StringView lookupEnum(const EnumLookup(&array)[N], int value, int defaultIndex = 0)
{
for (int i = 0; i < N; ++i) {
if (value == array[i].value)
return array[i].valueString;
}
- const char *defaultValue = array[defaultIndex].valueString;
+ auto defaultValue = array[defaultIndex].valueString;
qWarning("uic: Warning: Invalid enumeration value %d, defaulting to %s",
- value, defaultValue);
+ value, defaultValue.data());
return defaultValue;
}
@@ -106,74 +107,74 @@ QString fixClassName(QString className)
return className;
}
-const char *toolbarArea(int v)
+QLatin1StringView toolbarArea(int v)
{
static const EnumLookup toolBarAreas[] =
{
- {0, "NoToolBarArea"},
- {0x1, "LeftToolBarArea"},
- {0x2, "RightToolBarArea"},
- {0x4, "TopToolBarArea"},
- {0x8, "BottomToolBarArea"},
- {0xf, "AllToolBarAreas"}
+ {0, "NoToolBarArea"_L1},
+ {0x1, "LeftToolBarArea"_L1},
+ {0x2, "RightToolBarArea"_L1},
+ {0x4, "TopToolBarArea"_L1},
+ {0x8, "BottomToolBarArea"_L1},
+ {0xf, "AllToolBarAreas"_L1}
};
return lookupEnum(toolBarAreas, v);
}
-const char *sizePolicy(int v)
+QLatin1StringView sizePolicy(int v)
{
static const EnumLookup sizePolicies[] =
{
- {0, "Fixed"},
- {0x1, "Minimum"},
- {0x4, "Maximum"},
- {0x5, "Preferred"},
- {0x3, "MinimumExpanding"},
- {0x7, "Expanding"},
- {0xD, "Ignored"}
+ {0, "Fixed"_L1},
+ {0x1, "Minimum"_L1},
+ {0x4, "Maximum"_L1},
+ {0x5, "Preferred"_L1},
+ {0x3, "MinimumExpanding"_L1},
+ {0x7, "Expanding"_L1},
+ {0xD, "Ignored"_L1}
};
return lookupEnum(sizePolicies, v, 3);
}
-const char *dockWidgetArea(int v)
+QLatin1StringView dockWidgetArea(int v)
{
static const EnumLookup dockWidgetAreas[] =
{
- {0, "NoDockWidgetArea"},
- {0x1, "LeftDockWidgetArea"},
- {0x2, "RightDockWidgetArea"},
- {0x4, "TopDockWidgetArea"},
- {0x8, "BottomDockWidgetArea"},
- {0xf, "AllDockWidgetAreas"}
+ {0, "NoDockWidgetArea"_L1},
+ {0x1, "LeftDockWidgetArea"_L1},
+ {0x2, "RightDockWidgetArea"_L1},
+ {0x4, "TopDockWidgetArea"_L1},
+ {0x8, "BottomDockWidgetArea"_L1},
+ {0xf, "AllDockWidgetAreas"_L1}
};
return lookupEnum(dockWidgetAreas, v);
}
-const char *paletteColorRole(int v)
+QLatin1StringView paletteColorRole(int v)
{
static const EnumLookup colorRoles[] =
{
- {0, "WindowText"},
- {1, "Button"},
- {2, "Light"},
- {3, "Midlight"},
- {4, "Dark"},
- {5, "Mid"},
- {6, "Text"},
- {7, "BrightText"},
- {8, "ButtonText"},
- {9, "Base"},
- {10, "Window"},
- {11, "Shadow"},
- {12, "Highlight"},
- {13, "HighlightedText"},
- {14, "Link"},
- {15, "LinkVisited"},
- {16, "AlternateBase"},
- {17, "NoRole"},
- {18, "ToolTipBase"},
- {19, "ToolTipText"},
- {20, "PlaceholderText"},
+ {0, "WindowText"_L1},
+ {1, "Button"_L1},
+ {2, "Light"_L1},
+ {3, "Midlight"_L1},
+ {4, "Dark"_L1},
+ {5, "Mid"_L1},
+ {6, "Text"_L1},
+ {7, "BrightText"_L1},
+ {8, "ButtonText"_L1},
+ {9, "Base"_L1},
+ {10, "Window"_L1},
+ {11, "Shadow"_L1},
+ {12, "Highlight"_L1},
+ {13, "HighlightedText"_L1},
+ {14, "Link"_L1},
+ {15, "LinkVisited"_L1},
+ {16, "AlternateBase"_L1},
+ {17, "NoRole"_L1},
+ {18, "ToolTipBase"_L1},
+ {19, "ToolTipText"_L1},
+ {20, "PlaceholderText"_L1},
};
return lookupEnum(colorRoles, v);
}
@@ -370,17 +371,40 @@ void _formatStackVariable(QTextStream &str, const char *className, QStringView v
}
}
-enum OverloadUse {
- UseOverload,
- UseOverloadWhenNoArguments, // Use overload only when the argument list is empty,
- // in this case there is no chance of connecting
- // mismatching T against const T &
- DontUseOverload
+enum class OverloadUse {
+ Always,
+ WhenAmbiguousOrEmpty, // Use overload if
+ // - signal/slot is ambiguous
+ // - argument list is empty (chance of connecting mismatching T against const T &)
+ Never,
};
// Format a member function for a signal slot connection
-static void formatMemberFnPtr(QTextStream &str, const SignalSlot &s,
- OverloadUse useQOverload = DontUseOverload)
+static bool isConstRef(const QStringView &arg)
+{
+ return arg.startsWith(u'Q') && arg != "QPoint"_L1 && arg != "QSize"_L1;
+}
+
+static QString formatOverload(const QStringView &parameters)
+{
+ QString result = "qOverload<"_L1;
+ const auto args = QStringView{parameters}.split(u',');
+ for (qsizetype i = 0, size = args.size(); i < size; ++i) {
+ const auto &arg = args.at(i);
+ if (i > 0)
+ result += u',';
+ const bool constRef = isConstRef(arg);
+ if (constRef)
+ result += "const "_L1;
+ result += arg;
+ if (constRef)
+ result += u'&';
+ }
+ result += u'>';
+ return result;
+}
+
+static void formatMemberFnPtr(QTextStream &str, const SignalSlot &s, OverloadUse useQOverload)
{
const qsizetype parenPos = s.signature.indexOf(u'(');
Q_ASSERT(parenPos >= 0);
@@ -388,11 +412,24 @@ static void formatMemberFnPtr(QTextStream &str, const SignalSlot &s,
const auto parameters = QStringView{s.signature}.mid(parenPos + 1,
s.signature.size() - parenPos - 2);
- const bool withOverload = useQOverload == UseOverload ||
- (useQOverload == UseOverloadWhenNoArguments && parameters.isEmpty());
+
+ const bool isAmbiguous = s.options.testFlag(SignalSlotOption::Ambiguous);
+ bool withOverload = false; // just to silence the compiler
+
+ switch (useQOverload) {
+ case OverloadUse::Always:
+ withOverload = true;
+ break;
+ case OverloadUse::Never:
+ withOverload = false;
+ break;
+ case OverloadUse::WhenAmbiguousOrEmpty:
+ withOverload = parameters.empty() || isAmbiguous;
+ break;
+ }
if (withOverload)
- str << "qOverload<" << parameters << ">(";
+ str << formatOverload(parameters) << '(';
str << '&' << s.className << "::" << functionName;
@@ -405,9 +442,9 @@ static void formatMemberFnPtrConnection(QTextStream &str,
const SignalSlot &receiver)
{
str << "QObject::connect(" << sender.name << ", ";
- formatMemberFnPtr(str, sender);
+ formatMemberFnPtr(str, sender, OverloadUse::Never);
str << ", " << receiver.name << ", ";
- formatMemberFnPtr(str, receiver, UseOverloadWhenNoArguments);
+ formatMemberFnPtr(str, receiver, OverloadUse::WhenAmbiguousOrEmpty);
str << ')';
}
diff --git a/src/tools/uic/shared/language.h b/src/tools/uic/shared/language.h
index 52b3a0c201..de39122ee8 100644
--- a/src/tools/uic/shared/language.h
+++ b/src/tools/uic/shared/language.h
@@ -75,10 +75,10 @@ QTextStream &operator<<(QTextStream &, const closeQtConfig &c);
QString fixClassName(QString className);
-const char *toolbarArea(int v);
-const char *sizePolicy(int v);
-const char *dockWidgetArea(int v);
-const char *paletteColorRole(int v);
+QLatin1StringView toolbarArea(int v);
+QLatin1StringView sizePolicy(int v);
+QLatin1StringView dockWidgetArea(int v);
+QLatin1StringView paletteColorRole(int v);
enum class Encoding { Utf8, Unicode };
diff --git a/src/tools/uic/ui4.cpp b/src/tools/uic/ui4.cpp
index 42ee4fbefa..d65fc4a8c3 100644
--- a/src/tools/uic/ui4.cpp
+++ b/src/tools/uic/ui4.cpp
@@ -3121,6 +3121,14 @@ void DomFont::read(QXmlStreamReader &reader)
setElementKerning(reader.readElementText() == u"true"_s);
continue;
}
+ if (!tag.compare(u"hintingpreference"_s, Qt::CaseInsensitive)) {
+ setElementHintingPreference(reader.readElementText());
+ continue;
+ }
+ if (!tag.compare(u"fontweight"_s, Qt::CaseInsensitive)) {
+ setElementFontWeight(reader.readElementText());
+ continue;
+ }
reader.raiseError("Unexpected element "_L1 + tag);
}
break;
@@ -3166,6 +3174,12 @@ void DomFont::write(QXmlStreamWriter &writer, const QString &tagName) const
if (m_children & Kerning)
writer.writeTextElement(u"kerning"_s, (m_kerning ? u"true"_s : u"false"_s));
+ if (m_children & HintingPreference)
+ writer.writeTextElement(u"hintingpreference"_s, m_hintingPreference);
+
+ if (m_children & FontWeight)
+ writer.writeTextElement(u"fontweight"_s, m_fontWeight);
+
writer.writeEndElement();
}
@@ -3229,6 +3243,18 @@ void DomFont::setElementKerning(bool a)
m_kerning = a;
}
+void DomFont::setElementHintingPreference(const QString &a)
+{
+ m_children |= HintingPreference;
+ m_hintingPreference = a;
+}
+
+void DomFont::setElementFontWeight(const QString &a)
+{
+ m_children |= FontWeight;
+ m_fontWeight = a;
+}
+
void DomFont::clearElementFamily()
{
m_children &= ~Family;
@@ -3279,6 +3305,16 @@ void DomFont::clearElementKerning()
m_children &= ~Kerning;
}
+void DomFont::clearElementHintingPreference()
+{
+ m_children &= ~HintingPreference;
+}
+
+void DomFont::clearElementFontWeight()
+{
+ m_children &= ~FontWeight;
+}
+
DomPoint::~DomPoint() = default;
void DomPoint::read(QXmlStreamReader &reader)
diff --git a/src/tools/uic/ui4.h b/src/tools/uic/ui4.h
index 577baa3766..333f7f4e6a 100644
--- a/src/tools/uic/ui4.h
+++ b/src/tools/uic/ui4.h
@@ -1645,6 +1645,16 @@ public:
inline bool hasElementKerning() const { return m_children & Kerning; }
void clearElementKerning();
+ inline QString elementHintingPreference() const { return m_hintingPreference; }
+ void setElementHintingPreference(const QString &a);
+ inline bool hasElementHintingPreference() const { return m_children & HintingPreference; }
+ void clearElementHintingPreference();
+
+ inline QString elementFontWeight() const { return m_fontWeight; }
+ void setElementFontWeight(const QString &a);
+ inline bool hasElementFontWeight() const { return m_children & FontWeight; }
+ void clearElementFontWeight();
+
private:
// child element data
@@ -1659,6 +1669,8 @@ private:
bool m_antialiasing = false;
QString m_styleStrategy;
bool m_kerning = false;
+ QString m_hintingPreference;
+ QString m_fontWeight;
enum Child {
Family = 1,
@@ -1670,7 +1682,9 @@ private:
StrikeOut = 64,
Antialiasing = 128,
StyleStrategy = 256,
- Kerning = 512
+ Kerning = 512,
+ HintingPreference = 1024,
+ FontWeight = 2048
};
};
diff --git a/src/tools/uic/uic.cpp b/src/tools/uic/uic.cpp
index caf5ff4e1f..fb0a37d21d 100644
--- a/src/tools/uic/uic.cpp
+++ b/src/tools/uic/uic.cpp
@@ -38,9 +38,10 @@ bool Uic::printDependencies()
QString fileName = opt.inputFile;
QFile f;
- if (fileName.isEmpty())
- f.open(stdin, QIODevice::ReadOnly);
- else {
+ if (fileName.isEmpty()) {
+ if (!f.open(stdin, QIODevice::ReadOnly))
+ return false;
+ } else {
f.setFileName(fileName);
if (!f.open(QIODevice::ReadOnly))
return false;
diff --git a/src/tools/windeployqt/CMakeLists.txt b/src/tools/windeployqt/CMakeLists.txt
index 715c008831..2e50116484 100644
--- a/src/tools/windeployqt/CMakeLists.txt
+++ b/src/tools/windeployqt/CMakeLists.txt
@@ -12,15 +12,16 @@ qt_internal_add_tool(${target_name}
INSTALL_VERSIONED_LINK
TARGET_DESCRIPTION "Qt Windows Deployment Tool"
SOURCES
- elfreader.cpp elfreader.h
qmlutils.cpp qmlutils.h
qtmoduleinfo.cpp qtmoduleinfo.h
+ qtplugininfo.cpp qtplugininfo.h
utils.cpp utils.h
main.cpp
DEFINES
QT_NO_CAST_FROM_ASCII
QT_NO_CAST_TO_ASCII
QT_NO_FOREACH
+ QT_NO_QPAIR
LIBRARIES
Qt::CorePrivate
)
diff --git a/src/tools/windeployqt/elfreader.cpp b/src/tools/windeployqt/elfreader.cpp
deleted file mode 100644
index 9ef3b6bfa4..0000000000
--- a/src/tools/windeployqt/elfreader.cpp
+++ /dev/null
@@ -1,417 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#include "elfreader.h"
-
-#include <QDir>
-
-QT_BEGIN_NAMESPACE
-
-using namespace Qt::StringLiterals;
-
-/* This is a copy of the ELF reader contained in Qt Creator (src/libs/utils),
- * extended by the dependencies() function to read out the dependencies of a dynamic executable. */
-
-quint16 getHalfWord(const unsigned char *&s, const ElfData &context)
-{
- quint16 res;
- if (context.endian == Elf_ELFDATA2MSB)
- res = qFromBigEndian<quint16>(s);
- else
- res = qFromLittleEndian<quint16>(s);
- s += 2;
- return res;
-}
-
-quint32 getWord(const unsigned char *&s, const ElfData &context)
-{
- quint32 res;
- if (context.endian == Elf_ELFDATA2MSB)
- res = qFromBigEndian<quint32>(s);
- else
- res = qFromLittleEndian<quint32>(s);
- s += 4;
- return res;
-}
-
-quint64 getAddress(const unsigned char *&s, const ElfData &context)
-{
- quint64 res;
- if (context.elfclass == Elf_ELFCLASS32) {
- if (context.endian == Elf_ELFDATA2MSB)
- res = qFromBigEndian<quint32>(s);
- else
- res = qFromLittleEndian<quint32>(s);
- s += 4;
- } else {
- if (context.endian == Elf_ELFDATA2MSB)
- res = qFromBigEndian<quint64>(s);
- else
- res = qFromLittleEndian<quint64>(s);
- s += 8;
- }
- return res;
-}
-
-quint64 getOffset(const unsigned char *&s, const ElfData &context)
-{
- return getAddress(s, context);
-}
-
-static void parseSectionHeader(const uchar *s, ElfSectionHeader *sh, const ElfData &context)
-{
- sh->index = getWord(s, context);
- sh->type = getWord(s, context);
- sh->flags = quint32(getOffset(s, context));
- sh->addr = getAddress(s, context);
- sh->offset = getOffset(s, context);
- sh->size = getOffset(s, context);
-}
-
-static void parseProgramHeader(const uchar *s, ElfProgramHeader *sh, const ElfData &context)
-{
- sh->type = getWord(s, context);
- sh->offset = getOffset(s, context);
- /* p_vaddr = */ getAddress(s, context);
- /* p_paddr = */ getAddress(s, context);
- sh->filesz = getWord(s, context);
- sh->memsz = getWord(s, context);
-}
-
-class ElfMapper
-{
-public:
- ElfMapper(const ElfReader *reader) : file(reader->m_binary) {}
-
- bool map()
- {
- if (!file.open(QIODevice::ReadOnly))
- return false;
-
- fdlen = quint64(file.size());
- ustart = file.map(0, qint64(fdlen));
- if (ustart == 0) {
- // Try reading the data into memory instead.
- raw = file.readAll();
- start = raw.constData();
- fdlen = quint64(raw.size());
- }
- return true;
- }
-
-public:
- QFile file;
- QByteArray raw;
- union { const char *start; const uchar *ustart; };
- quint64 fdlen;
-};
-
-ElfReader::ElfReader(const QString &binary)
- : m_binary(binary)
-{
-}
-
-ElfData ElfReader::readHeaders()
-{
- readIt();
- return m_elfData;
-}
-
-static inline QString msgInvalidElfObject(const QString &binary, const QString &why)
-{
- return QStringLiteral("'%1' is an invalid ELF object (%2)")
- .arg(QDir::toNativeSeparators(binary), why);
-}
-
-ElfReader::Result ElfReader::readIt()
-{
- if (!m_elfData.sectionHeaders.isEmpty())
- return Ok;
- if (!m_elfData.programHeaders.isEmpty())
- return Ok;
-
- ElfMapper mapper(this);
- if (!mapper.map())
- return Corrupt;
-
- const quint64 fdlen = mapper.fdlen;
-
- if (fdlen < 64) {
- m_errorString = QStringLiteral("'%1' is not an ELF object (file too small)").arg(QDir::toNativeSeparators(m_binary));
- return NotElf;
- }
-
- if (strncmp(mapper.start, "\177ELF", 4) != 0) {
- m_errorString = QStringLiteral("'%1' is not an ELF object").arg(QDir::toNativeSeparators(m_binary));
- return NotElf;
- }
-
- // 32 or 64 bit
- m_elfData.elfclass = ElfClass(mapper.start[4]);
- const bool is64Bit = m_elfData.elfclass == Elf_ELFCLASS64;
- if (m_elfData.elfclass != Elf_ELFCLASS32 && m_elfData.elfclass != Elf_ELFCLASS64) {
- m_errorString = msgInvalidElfObject(m_binary, QStringLiteral("odd cpu architecture"));
- return Corrupt;
- }
-
- // int bits = (data[4] << 5);
- // If you remove this check to read ELF objects of a different arch,
- // please make sure you modify the typedefs
- // to match the _plugin_ architecture.
- // if ((sizeof(void*) == 4 && bits != 32)
- // || (sizeof(void*) == 8 && bits != 64)) {
- // if (errorString)
- // *errorString = QLibrary::QStringLiteral("'%1' is an invalid ELF object (%2)")
- // .arg(m_binary).arg("wrong cpu architecture"_L1);
- // return Corrupt;
- // }
-
- // Read Endianhness.
- m_elfData.endian = ElfEndian(mapper.ustart[5]);
- if (m_elfData.endian != Elf_ELFDATA2LSB && m_elfData.endian != Elf_ELFDATA2MSB) {
- m_errorString = msgInvalidElfObject(m_binary, QStringLiteral("odd endianness"));
- return Corrupt;
- }
-
- const uchar *data = mapper.ustart + 16; // e_ident
- m_elfData.elftype = ElfType(getHalfWord(data, m_elfData));
- m_elfData.elfmachine = ElfMachine(getHalfWord(data, m_elfData));
- /* e_version = */ getWord(data, m_elfData);
- m_elfData.entryPoint = getAddress(data, m_elfData);
-
- quint64 e_phoff = getOffset(data, m_elfData);
- quint64 e_shoff = getOffset(data, m_elfData);
- /* e_flags = */ getWord(data, m_elfData);
-
- quint32 e_shsize = getHalfWord(data, m_elfData);
-
- if (e_shsize > fdlen) {
- m_errorString = msgInvalidElfObject(m_binary, QStringLiteral("unexpected e_shsize"));
- return Corrupt;
- }
-
- quint32 e_phentsize = getHalfWord(data, m_elfData);
- if (e_phentsize != (is64Bit ? 56 : 32)) {
- m_errorString = msgInvalidElfObject(m_binary, QStringLiteral("invalid structure"));
- return ElfReader::Corrupt;
- }
- quint32 e_phnum = getHalfWord(data, m_elfData);
-
- quint32 e_shentsize = getHalfWord(data, m_elfData);
-
- if (e_shentsize % 4) {
- m_errorString = msgInvalidElfObject(m_binary, QStringLiteral("unexpected e_shentsize"));
- return Corrupt;
- }
-
- quint32 e_shnum = getHalfWord(data, m_elfData);
- quint32 e_shtrndx = getHalfWord(data, m_elfData);
- if (data != mapper.ustart + (is64Bit ? 64 : 52)) {
- m_errorString = msgInvalidElfObject(m_binary, QStringLiteral("unexpected e_phentsize"));
- return ElfReader::Corrupt;
- }
-
- if (quint64(e_shnum) * e_shentsize > fdlen) {
- const QString reason = QStringLiteral("announced %1 sections, each %2 bytes, exceed file size").arg(e_shnum).arg(e_shentsize);
- m_errorString = msgInvalidElfObject(m_binary, reason);
- return Corrupt;
- }
-
- quint64 soff = e_shoff + e_shentsize * e_shtrndx;
-
-// if ((soff + e_shentsize) > fdlen || soff % 4 || soff == 0) {
-// m_errorString = QLibrary::QStringLiteral("'%1' is an invalid ELF object (%2)")
-// .arg(m_binary)
-// .arg("shstrtab section header seems to be at %1"_L1)
-// .arg(QString::number(soff, 16));
-// return Corrupt;
-// }
-
- if (e_shoff) {
- ElfSectionHeader strtab;
- parseSectionHeader(mapper.ustart + soff, &strtab, m_elfData);
- const quint64 stringTableFileOffset = strtab.offset;
- if (quint32(stringTableFileOffset + e_shentsize) >= fdlen
- || stringTableFileOffset == 0) {
- const QString reason = QStringLiteral("string table seems to be at 0x%1").arg(soff, 0, 16);
- m_errorString = msgInvalidElfObject(m_binary, reason);
- return Corrupt;
- }
-
- for (quint32 i = 0; i < e_shnum; ++i) {
- const uchar *s = mapper.ustart + e_shoff + i * e_shentsize;
- ElfSectionHeader sh;
- parseSectionHeader(s, &sh, m_elfData);
-
- if (stringTableFileOffset + sh.index > fdlen) {
- const QString reason = QStringLiteral("section name %1 of %2 behind end of file")
- .arg(i).arg(e_shnum);
- m_errorString = msgInvalidElfObject(m_binary, reason);
- return Corrupt;
- }
-
- sh.name = mapper.start + stringTableFileOffset + sh.index;
- if (sh.name == ".gdb_index") {
- m_elfData.symbolsType = FastSymbols;
- } else if (sh.name == ".debug_info") {
- m_elfData.symbolsType = PlainSymbols;
- } else if (sh.name == ".gnu_debuglink") {
- m_elfData.debugLink = QByteArray(mapper.start + sh.offset);
- m_elfData.symbolsType = LinkedSymbols;
- } else if (sh.name == ".note.gnu.build-id") {
- m_elfData.symbolsType = BuildIdSymbols;
- if (sh.size > 16)
- m_elfData.buildId = QByteArray(mapper.start + sh.offset + 16,
- int(sh.size) - 16).toHex();
- }
- m_elfData.sectionHeaders.append(sh);
- }
- }
-
- if (e_phoff) {
- for (quint32 i = 0; i < e_phnum; ++i) {
- const uchar *s = mapper.ustart + e_phoff + i * e_phentsize;
- ElfProgramHeader ph;
- parseProgramHeader(s, &ph, m_elfData);
- m_elfData.programHeaders.append(ph);
- }
- }
- return Ok;
-}
-
-QByteArray ElfReader::readSection(const QByteArray &name)
-{
- readIt();
- int i = m_elfData.indexOf(name);
- if (i == -1)
- return QByteArray();
-
- ElfMapper mapper(this);
- if (!mapper.map())
- return QByteArray();
-
- const ElfSectionHeader &section = m_elfData.sectionHeaders.at(i);
- return QByteArray(mapper.start + section.offset, int(section.size));
-}
-
-static QByteArray cutout(const char *s)
-{
- QByteArray res(s, 80);
- const int pos = res.indexOf('\0');
- if (pos != -1)
- res.resize(pos - 1);
- return res;
-}
-
-QByteArray ElfReader::readCoreName(bool *isCore)
-{
- *isCore = false;
-
- readIt();
-
- ElfMapper mapper(this);
- if (!mapper.map())
- return QByteArray();
-
- if (m_elfData.elftype != Elf_ET_CORE)
- return QByteArray();
-
- *isCore = true;
-
- for (int i = 0, n = m_elfData.sectionHeaders.size(); i != n; ++i)
- if (m_elfData.sectionHeaders.at(i).type == Elf_SHT_NOTE) {
- const ElfSectionHeader &header = m_elfData.sectionHeaders.at(i);
- return cutout(mapper.start + header.offset + 0x40);
- }
-
- for (int i = 0, n = m_elfData.programHeaders.size(); i != n; ++i)
- if (m_elfData.programHeaders.at(i).type == Elf_PT_NOTE) {
- const ElfProgramHeader &header = m_elfData.programHeaders.at(i);
- return cutout(mapper.start + header.offset + 0xec);
- }
-
- return QByteArray();
-}
-
-int ElfData::indexOf(const QByteArray &name) const
-{
- for (int i = 0, n = sectionHeaders.size(); i != n; ++i)
- if (sectionHeaders.at(i).name == name)
- return i;
- return -1;
-}
-
-/* Helpers for reading out the .dynamic section containing the dependencies.
- * The ".dynamic" section is an array of
- * typedef struct {
- * Elf32_Sword d_tag;
- * union {
- * Elf32_Word d_val;
- * dElf32_Addr d_ptr;
- * } d_un;
- * } Elf32_Dyn
- * with entries where a tag DT_NEEDED indicates that m_val is an offset into
- * the string table ".dynstr". The documentation states that entries with the
- * tag DT_STRTAB contain an offset for the string table to be used, but that
- * has been found not to contain valid entries. */
-
-enum DynamicSectionTags {
- DT_NULL = 0,
- DT_NEEDED = 1,
- DT_STRTAB = 5,
- DT_SONAME = 14,
- DT_RPATH = 15
-};
-
-QList<QByteArray> ElfReader::dependencies()
-{
- QList<QByteArray> result;
-
- ElfMapper mapper(this);
- if (!mapper.map()) {
- m_errorString = QStringLiteral("Mapper failure");
- return result;
- }
- quint64 dynStrOffset = 0;
- quint64 dynamicOffset = 0;
- quint64 dynamicSize = 0;
-
- const QList<ElfSectionHeader> &headers = readHeaders().sectionHeaders;
- for (const ElfSectionHeader &eh : headers) {
- if (eh.name == QByteArrayLiteral(".dynstr")) {
- dynStrOffset = eh.offset;
- } else if (eh.name == QByteArrayLiteral(".dynamic")) {
- dynamicOffset = eh.offset;
- dynamicSize = eh.size;
- }
- if (dynStrOffset && dynamicOffset)
- break;
- }
-
- if (!dynStrOffset || !dynamicOffset) {
- m_errorString = QStringLiteral("Not a dynamically linked executable.");
- return result;
- }
-
- const unsigned char *dynamicData = mapper.ustart + dynamicOffset;
- const unsigned char *dynamicDataEnd = dynamicData + dynamicSize;
- while (dynamicData < dynamicDataEnd) {
- const quint32 tag = getWord(dynamicData, m_elfData);
- if (tag == DT_NULL)
- break;
- if (m_elfData.elfclass == Elf_ELFCLASS64)
- dynamicData += sizeof(quint32); // padding to d_val/d_ptr.
- if (tag == DT_NEEDED) {
- const quint32 offset = getWord(dynamicData, m_elfData);
- if (m_elfData.elfclass == Elf_ELFCLASS64)
- dynamicData += sizeof(quint32); // past d_ptr.
- const char *name = mapper.start + dynStrOffset + offset;
- result.push_back(name);
- } else {
- dynamicData += m_elfData.elfclass == Elf_ELFCLASS64 ? 8 : 4;
- }
- }
- return result;
-}
-
-QT_END_NAMESPACE
diff --git a/src/tools/windeployqt/elfreader.h b/src/tools/windeployqt/elfreader.h
deleted file mode 100644
index bea53c2ee4..0000000000
--- a/src/tools/windeployqt/elfreader.h
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#ifndef ELFREADER_H
-#define ELFREADER_H
-
-#include <QtCore/QList>
-#include <QtCore/QString>
-#include <QtCore/QtEndian>
-
-QT_BEGIN_NAMESPACE
-
-enum ElfProgramHeaderType
-{
- Elf_PT_NULL = 0,
- Elf_PT_LOAD = 1,
- Elf_PT_DYNAMIC = 2,
- Elf_PT_INTERP = 3,
- Elf_PT_NOTE = 4,
- Elf_PT_SHLIB = 5,
- Elf_PT_PHDR = 6,
- Elf_PT_TLS = 7,
- Elf_PT_NUM = 8
-};
-
-enum ElfSectionHeaderType
-{
- Elf_SHT_NULL = 0,
- Elf_SHT_PROGBITS = 1,
- Elf_SHT_SYMTAB = 2,
- Elf_SHT_STRTAB = 3,
- Elf_SHT_RELA = 4,
- Elf_SHT_HASH = 5,
- Elf_SHT_DYNAMIC = 6,
- Elf_SHT_NOTE = 7,
- Elf_SHT_NOBITS = 8,
- Elf_SHT_REL = 9,
- Elf_SHT_SHLIB = 10,
- Elf_SHT_DYNSYM = 11,
- Elf_SHT_INIT_ARRAY = 14,
- Elf_SHT_FINI_ARRAY = 15,
- Elf_SHT_PREINIT_ARRAY = 16,
- Elf_SHT_GROUP = 17,
- Elf_SHT_SYMTAB_SHNDX = 18
-};
-
-enum ElfEndian
-{
- Elf_ELFDATANONE = 0,
- Elf_ELFDATA2LSB = 1,
- Elf_ELFDATA2MSB = 2,
- Elf_ELFDATANUM = 3
-};
-
-enum ElfClass
-{
- Elf_ELFCLASS32 = 1,
- Elf_ELFCLASS64 = 2
-};
-
-enum ElfType
-{
- Elf_ET_NONE = 0,
- Elf_ET_REL = 1,
- Elf_ET_EXEC = 2,
- Elf_ET_DYN = 3,
- Elf_ET_CORE = 4
-};
-
-enum ElfMachine
-{
- Elf_EM_386 = 3,
- Elf_EM_ARM = 40,
- Elf_EM_X86_64 = 62
-};
-
-enum DebugSymbolsType
-{
- UnknownSymbols = 0, // Unknown.
- NoSymbols = 1, // No usable symbols.
- LinkedSymbols = 2, // Link to symbols available.
- BuildIdSymbols = 4, // BuildId available.
- PlainSymbols = 8, // Ordinary symbols available.
- FastSymbols = 16 // Dwarf index available.
-};
-
-class ElfSectionHeader
-{
-public:
- QByteArray name;
- quint32 index;
- quint32 type;
- quint32 flags;
- quint64 offset;
- quint64 size;
- quint64 addr;
-};
-
-class ElfProgramHeader
-{
-public:
- quint32 name;
- quint32 type;
- quint64 offset;
- quint64 filesz;
- quint64 memsz;
-};
-
-class ElfData
-{
-public:
- ElfData() : symbolsType(UnknownSymbols) {}
- int indexOf(const QByteArray &name) const;
-
-public:
- ElfEndian endian;
- ElfType elftype;
- ElfMachine elfmachine;
- ElfClass elfclass;
- quint64 entryPoint;
- QByteArray debugLink;
- QByteArray buildId;
- DebugSymbolsType symbolsType;
- QList<ElfSectionHeader> sectionHeaders;
- QList<ElfProgramHeader> programHeaders;
-};
-
-class ElfReader
-{
-public:
- explicit ElfReader(const QString &binary);
- enum Result { Ok, NotElf, Corrupt };
-
- ElfData readHeaders();
- QByteArray readSection(const QByteArray &sectionName);
- QString errorString() const { return m_errorString; }
- QByteArray readCoreName(bool *isCore);
- QList<QByteArray> dependencies();
-
-private:
- friend class ElfMapper;
- Result readIt();
-
- QString m_binary;
- QString m_errorString;
- ElfData m_elfData;
-};
-
-QT_END_NAMESPACE
-
-#endif // ELFREADER_H
diff --git a/src/tools/windeployqt/main.cpp b/src/tools/windeployqt/main.cpp
index bb661f6fcd..084345a4d8 100644
--- a/src/tools/windeployqt/main.cpp
+++ b/src/tools/windeployqt/main.cpp
@@ -4,6 +4,7 @@
#include "utils.h"
#include "qmlutils.h"
#include "qtmoduleinfo.h"
+#include "qtplugininfo.h"
#include <QtCore/QCommandLineOption>
#include <QtCore/QCommandLineParser>
@@ -79,10 +80,6 @@ static void assignKnownModuleIds()
#undef DECLARE_KNOWN_MODULE
#undef DEFINE_KNOWN_MODULE
-enum QtPlugin {
- QtVirtualKeyboardPlugin = 0x1
-};
-
static const char webEngineProcessC[] = "QtWebEngineProcess";
static inline QString webProcessBinary(const char *binaryName, Platform p)
@@ -111,6 +108,23 @@ static QByteArray formatQtModules(const ModuleBitset &mask, bool option = false)
result.append(option
? moduleNameToOptionName(qtModule.name).toUtf8()
: qtModule.name.toUtf8());
+ if (qtModule.internal)
+ result.append("Internal");
+ }
+ }
+ return result;
+}
+
+static QString formatQtPlugins(const PluginInformation &pluginInfo)
+{
+ QString result(u'\n');
+ for (const auto &pair : pluginInfo.typeMap()) {
+ result += pair.first;
+ result += u": \n";
+ for (const QString &plugin : pair.second) {
+ result += u" ";
+ result += plugin;
+ result += u'\n';
}
}
return result;
@@ -118,14 +132,15 @@ static QByteArray formatQtModules(const ModuleBitset &mask, bool option = false)
static Platform platformFromMkSpec(const QString &xSpec)
{
- if (xSpec == "linux-g++"_L1)
- return Unix;
if (xSpec.startsWith("win32-"_L1)) {
if (xSpec.contains("clang-g++"_L1))
return WindowsDesktopClangMinGW;
if (xSpec.contains("clang-msvc++"_L1))
return WindowsDesktopClangMsvc;
- return xSpec.contains("g++"_L1) ? WindowsDesktopMinGW : WindowsDesktopMsvc;
+ if (xSpec.contains("arm"_L1))
+ return WindowsDesktopMsvcArm;
+
+ return xSpec.contains("g++"_L1) ? WindowsDesktopMinGW : WindowsDesktopMsvcIntel;
}
return UnknownPlatform;
}
@@ -166,10 +181,12 @@ struct Options {
bool quickImports = true;
bool translations = true;
bool systemD3dCompiler = true;
+ bool systemDxc = true;
bool compilerRunTime = false;
- unsigned disabledPlugins = 0;
bool softwareRasterizer = true;
- Platform platform = WindowsDesktopMsvc;
+ bool ffmpeg = true;
+ PluginSelections pluginSelections;
+ Platform platform = WindowsDesktopMsvcIntel;
ModuleBitset additionalLibraries;
ModuleBitset disabledLibraries;
unsigned updateFileFlags = 0;
@@ -181,6 +198,7 @@ struct Options {
QStringList languages;
QString libraryDirectory;
QString pluginDirectory;
+ QString openSslRootDirectory;
QString qmlDirectory;
QStringList binaries;
JsonOutput *json = nullptr;
@@ -190,6 +208,8 @@ struct Options {
bool dryRun = false;
bool patchQt = true;
bool ignoreLibraryErrors = false;
+ bool deployInsightTrackerPlugin = false;
+ bool forceOpenSslPlugin = false;
};
// Return binary to be deployed from folder, ignore pre-existing web engine process.
@@ -215,7 +235,8 @@ static QString msgFileDoesNotExist(const QString & file)
enum CommandLineParseFlag {
CommandLineParseError = 0x1,
- CommandLineParseHelpRequested = 0x2
+ CommandLineParseHelpRequested = 0x2,
+ CommandLineVersionRequested = 0x4
};
static QCommandLineOption createQMakeOption()
@@ -269,7 +290,7 @@ static int parseEarlyArguments(const QStringList &arguments, Options *options,
}
if (parser.isSet(qmakeOption) && optVerboseLevel >= 1)
- std::wcerr << "Warning: -qmake option is deprecated. Use -qpaths instead.\n";
+ std::wcerr << "Warning: -qmake option is deprecated. Use -qtpaths instead.\n";
if (parser.isSet(qtpathsOption) || parser.isSet(qmakeOption)) {
const QString qtpathsArg = parser.isSet(qtpathsOption) ? parser.value(qtpathsOption)
@@ -316,7 +337,7 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
"installation (e.g. <QT_DIR\\bin>) to the PATH variable and then run:\n windeployqt <path-to-app-binary>\n\n"
"If your application uses Qt Quick, run:\n windeployqt --qmldir <path-to-app-qml-files> <path-to-app-binary>"_s);
const QCommandLineOption helpOption = parser->addHelpOption();
- parser->addVersionOption();
+ const QCommandLineOption versionOption = parser->addVersionOption();
QCommandLineOption dirOption(QStringLiteral("dir"),
QStringLiteral("Use directory instead of binary directory."),
@@ -383,6 +404,30 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
QStringLiteral("Skip plugin deployment."));
parser->addOption(noPluginsOption);
+ QCommandLineOption includeSoftPluginsOption(QStringLiteral("include-soft-plugins"),
+ QStringLiteral("Include in the deployment all relevant plugins by taking into account all soft dependencies."));
+ parser->addOption(includeSoftPluginsOption);
+
+ QCommandLineOption skipPluginTypesOption(QStringLiteral("skip-plugin-types"),
+ QStringLiteral("A comma-separated list of plugin types that are not deployed (qmltooling,generic)."),
+ QStringLiteral("plugin types"));
+ parser->addOption(skipPluginTypesOption);
+
+ QCommandLineOption addPluginTypesOption(QStringLiteral("add-plugin-types"),
+ QStringLiteral("A comma-separated list of plugin types that will be added to deployment (imageformats,iconengines)"),
+ QStringLiteral("plugin types"));
+ parser->addOption(addPluginTypesOption);
+
+ QCommandLineOption includePluginsOption(QStringLiteral("include-plugins"),
+ QStringLiteral("A comma-separated list of individual plugins that will be added to deployment (scene2d,qjpeg)"),
+ QStringLiteral("plugins"));
+ parser->addOption(includePluginsOption);
+
+ QCommandLineOption excludePluginsOption(QStringLiteral("exclude-plugins"),
+ QStringLiteral("A comma-separated list of individual plugins that will not be deployed (qsvg,qpdf)"),
+ QStringLiteral("plugins"));
+ parser->addOption(excludePluginsOption);
+
QCommandLineOption noLibraryOption(QStringLiteral("no-libraries"),
QStringLiteral("Skip library deployment."));
parser->addOption(noLibraryOption);
@@ -415,15 +460,15 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
QStringLiteral("Skip deployment of the system D3D compiler."));
parser->addOption(noSystemD3DCompilerOption);
+ QCommandLineOption noSystemDxcOption(QStringLiteral("no-system-dxc-compiler"),
+ QStringLiteral("Skip deployment of the system DXC (dxcompiler.dll, dxil.dll)."));
+ parser->addOption(noSystemDxcOption);
+
QCommandLineOption compilerRunTimeOption(QStringLiteral("compiler-runtime"),
QStringLiteral("Deploy compiler runtime (Desktop only)."));
parser->addOption(compilerRunTimeOption);
- QCommandLineOption noVirtualKeyboardOption(QStringLiteral("no-virtualkeyboard"),
- QStringLiteral("Disable deployment of the Virtual Keyboard."));
- parser->addOption(noVirtualKeyboardOption);
-
QCommandLineOption noCompilerRunTimeOption(QStringLiteral("no-compiler-runtime"),
QStringLiteral("Do not deploy compiler runtime (Desktop only)."));
parser->addOption(noCompilerRunTimeOption);
@@ -436,6 +481,20 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
QStringLiteral("Do not deploy the software rasterizer library."));
parser->addOption(suppressSoftwareRasterizerOption);
+ QCommandLineOption noFFmpegOption(QStringLiteral("no-ffmpeg"),
+ QStringLiteral("Do not deploy the FFmpeg libraries."));
+ parser->addOption(noFFmpegOption);
+
+ QCommandLineOption forceOpenSslOption(QStringLiteral("force-openssl"),
+ QStringLiteral("Deploy openssl plugin but ignore openssl library dependency"));
+ parser->addOption(forceOpenSslOption);
+
+ QCommandLineOption openSslRootOption(QStringLiteral("openssl-root"),
+ QStringLiteral("Directory containing openSSL libraries."),
+ QStringLiteral("directory"));
+ parser->addOption(openSslRootOption);
+
+
QCommandLineOption listOption(QStringLiteral("list"),
"Print only the names of the files copied.\n"
"Available options:\n"
@@ -455,6 +514,11 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
parser->addPositionalArgument(QStringLiteral("[files]"),
QStringLiteral("Binaries or directory containing the binary."));
+ QCommandLineOption deployInsightTrackerOption(QStringLiteral("deploy-insighttracker"),
+ QStringLiteral("Deploy insight tracker plugin."));
+ // The option will be added to the parser if the module is available (see block below)
+ bool insightTrackerModuleAvailable = false;
+
OptionPtrVector enabledModuleOptions;
OptionPtrVector disabledModuleOptions;
const size_t qtModulesCount = qtModuleEntries.size();
@@ -463,6 +527,10 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
for (const QtModule &module : qtModuleEntries) {
const QString option = moduleNameToOptionName(module.name);
const QString name = module.name;
+ if (name == u"InsightTracker") {
+ parser->addOption(deployInsightTrackerOption);
+ insightTrackerModuleAvailable = true;
+ }
const QString enabledDescription = QStringLiteral("Add ") + name + QStringLiteral(" module.");
CommandLineOptionPtr enabledOption(new QCommandLineOption(option, enabledDescription));
parser->addOption(*enabledOption.data());
@@ -477,6 +545,8 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
const bool success = parser->parse(arguments);
if (parser->isSet(helpOption))
return CommandLineParseHelpRequested;
+ if (parser->isSet(versionOption))
+ return CommandLineVersionRequested;
if (!success) {
*errorMessage = parser->errorText();
return CommandLineParseError;
@@ -492,22 +562,35 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
if (parser->isSet(translationOption))
options->languages = parser->value(translationOption).split(u',');
options->systemD3dCompiler = !parser->isSet(noSystemD3DCompilerOption);
+ options->systemDxc = !parser->isSet(noSystemDxcOption);
options->quickImports = !parser->isSet(noQuickImportOption);
// default to deployment of compiler runtime for windows desktop configurations
- if (options->platform == WindowsDesktopMinGW || options->platform == WindowsDesktopMsvc
+ if (options->platform == WindowsDesktopMinGW || options->platform.testFlags(WindowsDesktopMsvc)
|| parser->isSet(compilerRunTimeOption))
options->compilerRunTime = true;
if (parser->isSet(noCompilerRunTimeOption))
options->compilerRunTime = false;
- if (options->compilerRunTime && options->platform != WindowsDesktopMinGW && options->platform != WindowsDesktopMsvc) {
+ if (options->compilerRunTime && options->platform != WindowsDesktopMinGW
+ && !options->platform.testFlags(WindowsDesktopMsvc)) {
*errorMessage = QStringLiteral("Deployment of the compiler runtime is implemented for Desktop MSVC/g++ only.");
return CommandLineParseError;
}
- if (parser->isSet(noVirtualKeyboardOption))
- options->disabledPlugins |= QtVirtualKeyboardPlugin;
+ options->pluginSelections.includeSoftPlugins = parser->isSet(includeSoftPluginsOption);
+
+ if (parser->isSet(skipPluginTypesOption))
+ options->pluginSelections.disabledPluginTypes = parser->value(skipPluginTypesOption).split(u',');
+
+ if (parser->isSet(addPluginTypesOption))
+ options->pluginSelections.enabledPluginTypes = parser->value(addPluginTypesOption).split(u',');
+
+ if (parser->isSet(includePluginsOption))
+ options->pluginSelections.includedPlugins = parser->value(includePluginsOption).split(u',');
+
+ if (parser->isSet(excludePluginsOption))
+ options->pluginSelections.excludedPlugins = parser->value(excludePluginsOption).split(u',');
if (parser->isSet(releaseWithDebugInfoOption))
std::wcerr << "Warning: " << releaseWithDebugInfoOption.names().first() << " is obsolete.";
@@ -533,6 +616,20 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
if (parser->isSet(suppressSoftwareRasterizerOption))
options->softwareRasterizer = false;
+ if (parser->isSet(noFFmpegOption))
+ options->ffmpeg = false;
+
+ if (parser->isSet(forceOpenSslOption))
+ options->forceOpenSslPlugin = true;
+
+ if (parser->isSet(openSslRootOption))
+ options->openSslRootDirectory = parser->value(openSslRootOption);
+
+ if (options->forceOpenSslPlugin && !options->openSslRootDirectory.isEmpty()) {
+ *errorMessage = QStringLiteral("force-openssl and openssl-root are mutually exclusive");
+ return CommandLineParseError;
+ }
+
if (parser->isSet(forceOption))
options->updateFileFlags |= ForceUpdateFile;
if (parser->isSet(dryRunOption)) {
@@ -542,6 +639,8 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
options->patchQt = !parser->isSet(noPatchQtOption);
options->ignoreLibraryErrors = parser->isSet(ignoreErrorOption);
+ if (insightTrackerModuleAvailable)
+ options->deployInsightTrackerPlugin = parser->isSet(deployInsightTrackerOption);
for (const QtModule &module : qtModuleEntries) {
if (parser->isSet(*enabledModuleOptions.at(module.id)))
@@ -633,13 +732,15 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse
for (const QString &library : libraries)
options->binaries.append(path + u'/' + library);
} else {
- if (fi.absolutePath() != options->directory)
+ if (!parser->isSet(dirOption) && fi.absolutePath() != options->directory)
multipleDirs = true;
options->binaries.append(path);
}
}
- if (multipleDirs)
- std::wcerr << "Warning: using binaries from different directories\n";
+ if (multipleDirs) {
+ std::wcerr << "Warning: using binaries from different directories, deploying to following path: "
+ << options->directory << '\n' << "To disable this warning, use the --dir option\n";
+ }
if (options->translationsDirectory.isEmpty())
options->translationsDirectory = options->directory + "/translations"_L1;
return 0;
@@ -658,7 +759,7 @@ static inline QString lineBreak(QString s)
return s;
}
-static inline QString helpText(const QCommandLineParser &p)
+static inline QString helpText(const QCommandLineParser &p, const PluginInformation &pluginInfo)
{
QString result = p.helpText();
// Replace the default-generated text which is too long by a short summary
@@ -677,7 +778,18 @@ static inline QString helpText(const QCommandLineParser &p)
"the name prepended by --no- (--no-xml). Available libraries:\n"_L1;
ModuleBitset mask;
moduleHelp += lineBreak(QString::fromLatin1(formatQtModules(mask.set(), true)));
- moduleHelp += u'\n';
+ moduleHelp += u"\n\n";
+ moduleHelp +=
+ u"Qt plugins can be included or excluded individually or by type.\n"
+ u"To deploy or block plugins individually, use the --include-plugins\n"
+ u"and --exclude-plugins options (--include-plugins qjpeg,qsvgicon)\n"
+ u"You can also use the --skip-plugin-types or --add-plugin-types to\n"
+ u"achieve similar results with entire plugin groups, like imageformats, e.g.\n"
+ u"(--add-plugin-types imageformats,iconengines). Exclusion always takes\n"
+ u"precedence over inclusion, and types take precedence over specific plugins.\n"
+ u"For example, including qjpeg, but skipping imageformats, will NOT deploy qjpeg.\n"
+ u"\nDetected available plugins:\n";
+ moduleHelp += formatQtPlugins(pluginInfo);
result.replace(moduleStart, argumentsStart - moduleStart, moduleHelp);
return result;
}
@@ -701,7 +813,8 @@ static bool findDependentQtLibraries(const QString &qtBinDir, const QString &bin
QStringList dependentLibs;
if (directDependencyCount)
*directDependencyCount = 0;
- if (!readExecutable(binary, platform, errorMessage, &dependentLibs, wordSize, isDebug, machineArch)) {
+ if (!readPeExecutable(binary, errorMessage, &dependentLibs, wordSize, isDebug,
+ platform == WindowsDesktopMinGW, machineArch)) {
errorMessage->prepend("Unable to find dependent libraries of "_L1 +
QDir::toNativeSeparators(binary) + " :"_L1);
return false;
@@ -766,13 +879,19 @@ public:
SkipSources = 0x2
};
- explicit QmlDirectoryFileEntryFunction(Platform platform, DebugMatchMode debugMatchMode, unsigned flags)
+ explicit QmlDirectoryFileEntryFunction(
+ const QString &moduleSourcePath, Platform platform, DebugMatchMode debugMatchMode, unsigned flags)
: m_flags(flags), m_qmlNameFilter(QmlDirectoryFileEntryFunction::qmlNameFilters(flags))
- , m_dllFilter(platform, debugMatchMode)
+ , m_dllFilter(platform, debugMatchMode), m_moduleSourcePath(moduleSourcePath)
{}
QStringList operator()(const QDir &dir) const
{
+ if (moduleSourceDir(dir).canonicalPath() != m_moduleSourcePath) {
+ // If we're in a different module, return nothing.
+ return {};
+ }
+
QStringList result;
const QStringList &libraries = m_dllFilter(dir);
for (const QString &library : libraries) {
@@ -788,6 +907,17 @@ public:
}
private:
+ static QDir moduleSourceDir(const QDir &dir)
+ {
+ QDir moduleSourceDir = dir;
+ while (!moduleSourceDir.exists(QStringLiteral("qmldir"))) {
+ if (!moduleSourceDir.cdUp()) {
+ return {};
+ }
+ }
+ return moduleSourceDir;
+ }
+
static inline QStringList qmlNameFilters(unsigned flags)
{
QStringList result;
@@ -804,9 +934,10 @@ private:
const unsigned m_flags;
NameFilterFileEntryFunction m_qmlNameFilter;
DllDirectoryFileEntryFunction m_dllFilter;
+ QString m_moduleSourcePath;
};
-static quint64 qtModule(QString module, const QString &infix)
+static qint64 qtModule(QString module, const QString &infix)
{
// Match needle 'path/Qt6Core<infix><d>.dll' or 'path/libQt6Core<infix>.so.5.0'
const qsizetype lastSlashPos = module.lastIndexOf(u'/');
@@ -827,73 +958,124 @@ static quint64 qtModule(QString module, const QString &infix)
return qtModule.id;
}
}
- return 0;
+ std::wcerr << "Warning: module " << qPrintable(module) << " could not be found\n";
+ return -1;
}
// Return the path if a plugin is to be deployed
-static QString deployPlugin(const QString &plugin, const QDir &subDir,
- ModuleBitset *usedQtModules, const ModuleBitset &disabledQtModules,
- unsigned disabledPlugins,
- const QString &libraryLocation, const QString &infix,
- Platform platform)
+static QString deployPlugin(const QString &plugin, const QDir &subDir, const bool dueToModule,
+ const DebugMatchMode &debugMatchMode, ModuleBitset *pluginNeededQtModules,
+ const ModuleBitset &disabledQtModules,
+ const PluginSelections &pluginSelections, const QString &libraryLocation,
+ const QString &infix, Platform platform,
+ bool deployInsightTrackerPlugin, bool deployOpenSslPlugin)
{
+ const QString subDirName = subDir.dirName();
// Filter out disabled plugins
- if ((disabledPlugins & QtVirtualKeyboardPlugin)
- && plugin.startsWith("qtvirtualkeyboardplugin"_L1)) {
+ if (optVerboseLevel && pluginSelections.disabledPluginTypes.contains(subDirName)) {
+ std::wcout << "Skipping plugin " << plugin << " due to skipped plugin type " << subDirName << '\n';
+ return {};
+ }
+ if (optVerboseLevel && subDirName == u"generic" && plugin.contains(u"qinsighttracker")
+ && !deployInsightTrackerPlugin) {
+ std::wcout << "Skipping plugin " << plugin
+ << ". Use -deploy-insighttracker if you want to use it.\n";
+ return {};
+ }
+ if (optVerboseLevel && subDirName == u"tls" && plugin.contains(u"qopensslbackend")
+ && !deployOpenSslPlugin) {
+ std::wcout << "Skipping plugin " << plugin
+ << ". Use -force_openssl or specify -openssl-root if you want to use it.\n";
+ return {};
+ }
+
+ const int dotIndex = plugin.lastIndexOf(u'.');
+ // Strip the .dll from the name, and an additional 'd' if it's a debug library with the 'd'
+ // suffix
+ const int stripIndex = debugMatchMode == MatchDebug && platformHasDebugSuffix(platform)
+ ? dotIndex - 1
+ : dotIndex;
+ const QString pluginName = plugin.first(stripIndex);
+
+ if (optVerboseLevel && pluginSelections.excludedPlugins.contains(pluginName)) {
+ std::wcout << "Skipping plugin " << plugin << " due to exclusion option" << '\n';
+ return {};
+ }
+
+ // By default, only deploy qwindows.dll
+ if (subDirName == u"platforms"
+ && !(pluginSelections.includedPlugins.contains(pluginName)
+ || (pluginSelections.enabledPluginTypes.contains(subDirName)))
+ && !pluginName.startsWith(u"qwindows")) {
return {};
}
const QString pluginPath = subDir.absoluteFilePath(plugin);
+
+ // If dueToModule is false, check if the user included the plugin or the entire type. In the
+ // former's case, only deploy said plugin and not all plugins of that type.
+ const bool requiresPlugin = pluginSelections.includedPlugins.contains(pluginName)
+ || pluginSelections.enabledPluginTypes.contains(subDirName);
+ if (!dueToModule && !requiresPlugin)
+ return {};
+
// Deploy QUiTools plugins as is without further dependency checking.
// The user needs to ensure all required libraries are present (would
// otherwise pull QtWebEngine for its plugin).
- if (subDir.dirName() == u"designer")
+ if (subDirName == u"designer")
return pluginPath;
QStringList dependentQtLibs;
- ModuleBitset neededModules;
QString errorMessage;
if (findDependentQtLibraries(libraryLocation, pluginPath, platform,
&errorMessage, &dependentQtLibs)) {
- for (int d = 0; d < dependentQtLibs.size(); ++ d)
- neededModules[qtModule(dependentQtLibs.at(d), infix)] = 1;
+ for (int d = 0; d < dependentQtLibs.size(); ++d) {
+ const qint64 module = qtModule(dependentQtLibs.at(d), infix);
+ if (module >= 0)
+ (*pluginNeededQtModules)[module] = 1;
+ }
} else {
std::wcerr << "Warning: Cannot determine dependencies of "
<< QDir::toNativeSeparators(pluginPath) << ": " << errorMessage << '\n';
}
- ModuleBitset missingModules;
- missingModules = neededModules & disabledQtModules;
- if (missingModules.any()) {
+ ModuleBitset disabledNeededQtModules;
+ disabledNeededQtModules = *pluginNeededQtModules & disabledQtModules;
+ if (disabledNeededQtModules.any()) {
if (optVerboseLevel) {
std::wcout << "Skipping plugin " << plugin
<< " due to disabled dependencies ("
- << formatQtModules(missingModules).constData() << ").\n";
+ << formatQtModules(disabledNeededQtModules).constData() << ").\n";
}
return {};
}
- missingModules = (neededModules & ~*usedQtModules);
- if (missingModules.any()) {
- *usedQtModules |= missingModules;
- if (optVerboseLevel) {
- std::wcout << "Adding " << formatQtModules(missingModules).constData()
- << " for " << plugin << '\n';
- }
- }
return pluginPath;
}
+static bool needsPluginType(const QString &subDirName, const PluginInformation &pluginInfo,
+ const PluginSelections &pluginSelections)
+{
+ bool needsTypeForPlugin = false;
+ for (const QString &plugin: pluginSelections.includedPlugins) {
+ if (pluginInfo.isTypeForPlugin(subDirName, plugin))
+ needsTypeForPlugin = true;
+ }
+ return (pluginSelections.enabledPluginTypes.contains(subDirName) || needsTypeForPlugin);
+}
+
QStringList findQtPlugins(ModuleBitset *usedQtModules, const ModuleBitset &disabledQtModules,
- unsigned disabledPlugins,
+ const PluginInformation &pluginInfo, const PluginSelections &pluginSelections,
const QString &qtPluginsDirName, const QString &libraryLocation,
- const QString &infix,
- DebugMatchMode debugMatchModeIn, Platform platform, QString *platformPlugin)
+ const QString &infix, DebugMatchMode debugMatchModeIn, Platform platform,
+ QString *platformPlugin, bool deployInsightTrackerPlugin,
+ bool deployOpenSslPlugin)
{
if (qtPluginsDirName.isEmpty())
return QStringList();
QDir pluginsDir(qtPluginsDirName);
QStringList result;
+ bool missingQtModulesAdded = false;
const QFileInfoList &pluginDirs = pluginsDir.entryInfoList(QStringList(u"*"_s), QDir::Dirs | QDir::NoDotAndDotDot);
for (const QFileInfo &subDirFi : pluginDirs) {
const QString subDirName = subDirFi.fileName();
@@ -904,49 +1086,55 @@ QStringList findQtPlugins(ModuleBitset *usedQtModules, const ModuleBitset &disab
}
continue;
}
- if (usedQtModules->test(module)) {
+ const bool dueToModule = usedQtModules->test(module);
+ if (dueToModule || needsPluginType(subDirName, pluginInfo, pluginSelections)) {
const DebugMatchMode debugMatchMode = (module == QtWebEngineCoreModuleId)
? MatchDebugOrRelease // QTBUG-44331: Debug detection does not work for webengine, deploy all.
: debugMatchModeIn;
QDir subDir(subDirFi.absoluteFilePath());
- // Filter out disabled plugins
- if ((disabledPlugins & QtVirtualKeyboardPlugin) && subDirName == "virtualkeyboard"_L1)
- continue;
- if (disabledQtModules.test(QtQmlToolingModuleId) && subDirName == "qmltooling"_L1)
- continue;
- // Filter for platform or any.
- QString filter;
+ if (optVerboseLevel)
+ std::wcout << "Adding in plugin type " << subDirFi.baseName() << " for module: " << qtModuleEntries.moduleById(module).name << '\n';
+
const bool isPlatformPlugin = subDirName == "platforms"_L1;
- if (isPlatformPlugin) {
- switch (platform) {
- case WindowsDesktopMsvc:
- case WindowsDesktopMinGW:
- filter = QStringLiteral("qwindows");
- if (!infix.isEmpty())
- filter += infix;
- break;
- case Unix:
- filter = QStringLiteral("libqxcb");
- break;
- case UnknownPlatform:
- break;
- }
- } else {
- filter = u"*"_s;
- }
- const QStringList plugins = findSharedLibraries(subDir, platform, debugMatchMode, filter);
+ const QStringList plugins =
+ findSharedLibraries(subDir, platform, debugMatchMode, QString());
for (const QString &plugin : plugins) {
+ ModuleBitset pluginNeededQtModules;
const QString pluginPath =
- deployPlugin(plugin, subDir, usedQtModules, disabledQtModules,
- disabledPlugins, libraryLocation, infix, platform);
+ deployPlugin(plugin, subDir, dueToModule, debugMatchMode, &pluginNeededQtModules,
+ disabledQtModules, pluginSelections, libraryLocation, infix,
+ platform, deployInsightTrackerPlugin, deployOpenSslPlugin);
if (!pluginPath.isEmpty()) {
- if (isPlatformPlugin)
+ if (isPlatformPlugin && plugin.startsWith(u"qwindows"))
*platformPlugin = subDir.absoluteFilePath(plugin);
result.append(pluginPath);
+
+ const ModuleBitset missingModules = (pluginNeededQtModules & ~*usedQtModules);
+ if (missingModules.any()) {
+ *usedQtModules |= missingModules;
+ missingQtModulesAdded = true;
+ if (optVerboseLevel) {
+ std::wcout << "Adding " << formatQtModules(missingModules).constData()
+ << " for " << plugin << " from plugin type: " << subDirName << '\n';
+ }
+ }
}
} // for filter
} // type matches
} // for plugin folder
+
+ // If missing Qt modules were added during plugin deployment make additional pass, because we may need
+ // additional plugins.
+ if (pluginSelections.includeSoftPlugins && missingQtModulesAdded) {
+ if (optVerboseLevel) {
+ std::wcout << "Performing additional pass of finding Qt plugins due to updated Qt module list: "
+ << formatQtModules(*usedQtModules).constData() << "\n";
+ }
+ return findQtPlugins(usedQtModules, disabledQtModules, pluginInfo, pluginSelections, qtPluginsDirName,
+ libraryLocation, infix, debugMatchModeIn, platform, platformPlugin,
+ deployInsightTrackerPlugin, deployOpenSslPlugin);
+ }
+
return result;
}
@@ -995,7 +1183,12 @@ static bool deployTranslations(const QString &sourcePath, const ModuleBitset &us
if (options.json)
options.json->addFile(sourcePath + u'/' + targetFile, absoluteTarget);
arguments.append(QDir::toNativeSeparators(targetFilePath));
- const QFileInfoList &langQmFiles = sourceDir.entryInfoList(translationNameFilters(usedQtModules, prefix));
+ const QStringList translationFilters = translationNameFilters(usedQtModules, prefix);
+ if (translationFilters.isEmpty()){
+ std::wcerr << "Warning: translation catalogs are all empty, skipping translation deployment\n";
+ return true;
+ }
+ const QFileInfoList &langQmFiles = sourceDir.entryInfoList(translationFilters);
for (const QFileInfo &langQmFileFi : langQmFiles) {
if (options.json) {
options.json->addFile(langQmFileFi.absoluteFilePath(),
@@ -1015,6 +1208,62 @@ static bool deployTranslations(const QString &sourcePath, const ModuleBitset &us
return true;
}
+static QStringList findFFmpegLibs(const QString &qtBinDir, Platform platform)
+{
+ const std::vector<QLatin1StringView> ffmpegHints = { "avcodec"_L1, "avformat"_L1, "avutil"_L1,
+ "swresample"_L1, "swscale"_L1 };
+ const QStringList bundledLibs =
+ findSharedLibraries(qtBinDir, platform, MatchDebugOrRelease, {});
+
+ QStringList ffmpegLibs;
+ for (const QLatin1StringView &libHint : ffmpegHints) {
+ const QStringList ffmpegLib = bundledLibs.filter(libHint, Qt::CaseInsensitive);
+
+ if (ffmpegLib.empty()) {
+ std::wcerr << "Warning: Cannot find FFmpeg libraries. Multimedia features will not work as expected.\n";
+ return {};
+ } else if (ffmpegLib.size() != 1u) {
+ std::wcerr << "Warning: Multiple versions of FFmpeg libraries found. Multimedia features will not work as expected.\n";
+ return {};
+ }
+
+ const QChar slash(u'/');
+ QFileInfo ffmpegLibPath{ qtBinDir + slash + ffmpegLib.front() };
+ ffmpegLibs.append(ffmpegLibPath.absoluteFilePath());
+ }
+
+ return ffmpegLibs;
+}
+
+// Find the openssl libraries Qt executables depend on.
+static QStringList findOpenSslLibraries(const QString &openSslRootDir, Platform platform)
+{
+ const std::vector<QLatin1StringView> libHints = { "libcrypto"_L1, "libssl"_L1 };
+ const QChar slash(u'/');
+ const QString openSslBinDir = openSslRootDir + slash + "bin"_L1;
+ const QStringList openSslRootLibs =
+ findSharedLibraries(openSslBinDir, platform, MatchDebugOrRelease, {});
+
+ QStringList result;
+ for (const QLatin1StringView &libHint : libHints) {
+ const QStringList lib = openSslRootLibs.filter(libHint, Qt::CaseInsensitive);
+
+ if (lib.empty()) {
+ std::wcerr << "Warning: Cannot find openssl libraries.\n";
+ return {};
+ } else if (lib.size() != 1u) {
+ std::wcerr << "Warning: Multiple versions of openssl libraries found.\n";
+ return {};
+ }
+
+ QFileInfo libPath{ openSslBinDir + slash + lib.front() };
+ result.append(libPath.absoluteFilePath());
+ }
+
+ return result;
+}
+
+
struct DeployResult
{
operator bool() const { return success; }
@@ -1027,20 +1276,14 @@ struct DeployResult
};
static QString libraryPath(const QString &libraryLocation, const char *name,
- const QString &qtLibInfix, Platform platform, bool debug)
+ const QString &infix, Platform platform, bool debug)
{
QString result = libraryLocation + u'/';
- if (platform & WindowsBased) {
- result += QLatin1StringView(name);
- result += qtLibInfix;
- if (debug && platformHasDebugSuffix(platform))
- result += u'd';
- } else if (platform.testFlag(UnixBased)) {
- result += QStringLiteral("lib");
- result += QLatin1StringView(name);
- result += qtLibInfix;
- }
- result += sharedLibrarySuffix(platform);
+ result += QLatin1StringView(name);
+ result += infix;
+ if (debug && platformHasDebugSuffix(platform))
+ result += u'd';
+ result += sharedLibrarySuffix();
return result;
}
@@ -1081,29 +1324,51 @@ static QString vcRedistDir()
return QString();
}
-static QStringList compilerRunTimeLibs(Platform platform, bool isDebug, unsigned short machineArch)
+static QStringList findMinGWRuntimePaths(const QString &qtBinDir, Platform platform, const QStringList &runtimeFilters)
{
+ //MinGW: Add runtime libraries. Check first for the Qt binary directory, and default to path if nothing is found.
QStringList result;
- switch (platform) {
- case WindowsDesktopMinGW: { // MinGW: Add runtime libraries
- static const char *minGwRuntimes[] = {"*gcc_", "*stdc++", "*winpthread"};
- const QString gcc = findInPath(QStringLiteral("g++.exe"));
- if (gcc.isEmpty()) {
- std::wcerr << "Warning: Cannot find GCC installation directory. g++.exe must be in the path.\n";
- break;
+ const bool isClang = platform == WindowsDesktopClangMinGW;
+ QStringList filters;
+ const QString suffix = u'*' + sharedLibrarySuffix();
+ for (const auto &minGWRuntime : runtimeFilters)
+ filters.append(minGWRuntime + suffix);
+
+ QFileInfoList dlls = QDir(qtBinDir).entryInfoList(filters, QDir::Files);
+ if (dlls.isEmpty()) {
+ std::wcerr << "Warning: Runtime libraries not found in Qt binary folder, defaulting to looking in path\n";
+ const QString binaryPath = isClang ? findInPath("clang++.exe"_L1) : findInPath("g++.exe"_L1);
+ if (binaryPath.isEmpty()) {
+ std::wcerr << "Warning: Cannot find " << (isClang ? "Clang" : "GCC") << " installation directory, " << (isClang ? "clang++" : "g++") << ".exe must be in the path\n";
+ return {};
}
- const QString binPath = QFileInfo(gcc).absolutePath();
- QStringList filters;
- const QString suffix = u'*' + sharedLibrarySuffix(platform);
- for (auto minGwRuntime : minGwRuntimes)
- filters.append(QLatin1StringView(minGwRuntime) + suffix);
- const QFileInfoList &dlls = QDir(binPath).entryInfoList(filters, QDir::Files);
- for (const QFileInfo &dllFi : dlls)
- result.append(dllFi.absoluteFilePath());
+ const QString binaryFolder = QFileInfo(binaryPath).absolutePath();
+ dlls = QDir(binaryFolder).entryInfoList(filters, QDir::Files);
}
+
+ for (const QFileInfo &dllFi : dlls)
+ result.append(dllFi.absoluteFilePath());
+
+ return result;
+}
+
+static QStringList compilerRunTimeLibs(const QString &qtBinDir, Platform platform, bool isDebug, unsigned short machineArch)
+{
+ QStringList result;
+ switch (platform) {
+ case WindowsDesktopMinGW: {
+ const QStringList minGWRuntimes = { "*gcc_"_L1, "*stdc++"_L1, "*winpthread"_L1 };
+ result.append(findMinGWRuntimePaths(qtBinDir, platform, minGWRuntimes));
break;
+ }
+ case WindowsDesktopClangMinGW: {
+ const QStringList clangMinGWRuntimes = { "*unwind"_L1, "*c++"_L1 };
+ result.append(findMinGWRuntimePaths(qtBinDir, platform, clangMinGWRuntimes));
+ break;
+ }
#ifdef Q_OS_WIN
- case WindowsDesktopMsvc: { // MSVC/Desktop: Add redistributable packages.
+ case WindowsDesktopMsvcIntel:
+ case WindowsDesktopMsvcArm: { // MSVC/Desktop: Add redistributable packages.
QString vcRedistDirName = vcRedistDir();
if (vcRedistDirName.isEmpty())
break;
@@ -1159,16 +1424,6 @@ static inline int qtVersion(const QMap<QString, QString> &qtpathsVariables)
return (majorVersion << 16) | (minorVersion << 8) | patchVersion;
}
-// Determine the Qt lib infix from the library path of "Qt6Core<qtblibinfix>[d].dll".
-static inline QString qtlibInfixFromCoreLibName(const QString &path, bool isDebug, Platform platform)
-{
- const qsizetype startPos = path.lastIndexOf(u'/') + 8;
- qsizetype endPos = path.lastIndexOf(u'.');
- if (isDebug && (platform & WindowsBased))
- endPos--;
- return endPos > startPos ? path.mid(startPos, endPos - startPos) : QString();
-}
-
// Deploy a library along with its .pdb debug info file (MSVC) should it exist.
static bool updateLibrary(const QString &sourceFileName, const QString &targetDirectory,
const Options &options, QString *errorMessage)
@@ -1201,16 +1456,14 @@ static QString getIcuVersion(const QString &libName)
}
static DeployResult deploy(const Options &options, const QMap<QString, QString> &qtpathsVariables,
- QString *errorMessage)
+ const PluginInformation &pluginInfo, QString *errorMessage)
{
DeployResult result;
const QChar slash = u'/';
const QString qtBinDir = qtpathsVariables.value(QStringLiteral("QT_INSTALL_BINS"));
- const QString libraryLocation = options.platform == Unix
- ? qtpathsVariables.value(QStringLiteral("QT_INSTALL_LIBS"))
- : qtBinDir;
+ const QString libraryLocation = qtBinDir;
const QString infix = qtpathsVariables.value(QLatin1StringView(qmakeInfixKey));
const int version = qtVersion(qtpathsVariables);
Q_UNUSED(version);
@@ -1257,12 +1510,10 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
// Determine application type, check Quick2 is used by looking at the
// direct dependencies (do not be fooled by QtWebKit depending on it).
- QString qtLibInfix;
for (int m = 0; m < dependentQtLibs.size(); ++m) {
- const quint64 module = qtModule(dependentQtLibs.at(m), infix);
- result.directlyUsedQtLibraries[module] = 1;
- if (module == QtCoreModuleId)
- qtLibInfix = qtlibInfixFromCoreLibName(dependentQtLibs.at(m), detectedDebug, options.platform);
+ const qint64 module = qtModule(dependentQtLibs.at(m), infix);
+ if (module >= 0)
+ result.directlyUsedQtLibraries[module] = 1;
}
const bool usesQml = result.directlyUsedQtLibraries.test(QtQmlModuleId);
@@ -1291,7 +1542,7 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
const QStringList qtLibs = dependentQtLibs.filter(QStringLiteral("Qt6Core"), Qt::CaseInsensitive)
+ dependentQtLibs.filter(QStringLiteral("Qt5WebKit"), Qt::CaseInsensitive);
for (const QString &qtLib : qtLibs) {
- QStringList icuLibs = findDependentLibraries(qtLib, options.platform, errorMessage).filter(QStringLiteral("ICU"), Qt::CaseInsensitive);
+ QStringList icuLibs = findDependentLibraries(qtLib, errorMessage).filter(QStringLiteral("ICU"), Qt::CaseInsensitive);
if (!icuLibs.isEmpty()) {
// Find out the ICU version to add the data library icudtXX.dll, which does not show
// as a dependency.
@@ -1300,7 +1551,7 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
if (optVerboseLevel > 1)
std::wcout << "Adding ICU version " << icuVersion << '\n';
QString icuLib = QStringLiteral("icudt") + icuVersion
- + QLatin1StringView(windowsSharedLibrarySuffix);;
+ + QLatin1StringView(windowsSharedLibrarySuffix);
// Some packages contain debug dlls of ICU libraries even though it's a C
// library and the official packages do not differentiate (QTBUG-87677)
if (result.isDebug) {
@@ -1373,8 +1624,9 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
// QtModule enumeration (and thus controlled by flags) and others.
QStringList deployedQtLibraries;
for (int i = 0 ; i < dependentQtLibs.size(); ++i) {
- if (const quint64 qtm = qtModule(dependentQtLibs.at(i), infix))
- result.usedQtLibraries[qtm] = 1;
+ const qint64 module = qtModule(dependentQtLibs.at(i), infix);
+ if (module >= 0)
+ result.usedQtLibraries[module] = 1;
else
deployedQtLibraries.push_back(dependentQtLibs.at(i)); // Not represented by flag.
}
@@ -1385,19 +1637,34 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
disabled[QtQmlModuleId] = 1;
disabled[QtQuickModuleId] = 1;
}
+
+ QStringList openSslLibs;
+ if (!options.openSslRootDirectory.isEmpty()) {
+ openSslLibs = findOpenSslLibraries(options.openSslRootDirectory, options.platform);
+ if (openSslLibs.isEmpty()) {
+ *errorMessage = QStringLiteral("Unable to find openSSL libraries in ")
+ + options.openSslRootDirectory;
+ return result;
+ }
+
+ deployedQtLibraries.append(openSslLibs);
+ }
+ const bool deployOpenSslPlugin = options.forceOpenSslPlugin || !openSslLibs.isEmpty();
+
const QStringList plugins = findQtPlugins(
&result.deployedQtLibraries,
// For non-QML applications, disable QML to prevent it from being pulled in by the
// qtaccessiblequick plugin.
- disabled,
- options.disabledPlugins, qtpathsVariables.value(QStringLiteral("QT_INSTALL_PLUGINS")),
- libraryLocation, infix, debugMatchMode, options.platform, &platformPlugin);
+ disabled, pluginInfo,
+ options.pluginSelections, qtpathsVariables.value(QStringLiteral("QT_INSTALL_PLUGINS")),
+ libraryLocation, infix, debugMatchMode, options.platform, &platformPlugin,
+ options.deployInsightTrackerPlugin, deployOpenSslPlugin);
// Apply options flags and re-add library names.
QString qtGuiLibrary;
for (const auto &qtModule : qtModuleEntries) {
if (result.deployedQtLibraries.test(qtModule.id)) {
- const QString library = libraryPath(libraryLocation, qtModule.name.toUtf8(), qtLibInfix,
+ const QString library = libraryPath(libraryLocation, qtModule.name.toUtf8(), infix,
options.platform, result.isDebug);
deployedQtLibraries.append(library);
if (qtModule.id == QtGuiModuleId)
@@ -1420,7 +1687,7 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
}
if (options.platform.testFlag(WindowsBased) && !qtGuiLibrary.isEmpty()) {
- const QStringList guiLibraries = findDependentLibraries(qtGuiLibrary, options.platform, errorMessage);
+ const QStringList guiLibraries = findDependentLibraries(qtGuiLibrary, errorMessage);
const bool dependsOnOpenGl = !guiLibraries.filter(QStringLiteral("opengl32"), Qt::CaseInsensitive).isEmpty();
if (options.softwareRasterizer && !dependsOnOpenGl) {
const QFileInfo softwareRasterizer(qtBinDir + slash + QStringLiteral("opengl32sw") + QLatin1StringView(windowsSharedLibrarySuffix));
@@ -1435,15 +1702,28 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
deployedQtLibraries.push_back(d3dCompiler);
}
}
+ if (options.systemDxc) {
+ const QStringList dxcLibs = findDxc(options.platform, qtBinDir, wordSize);
+ if (!dxcLibs.isEmpty())
+ deployedQtLibraries.append(dxcLibs);
+ else
+ std::wcerr << "Warning: Cannot find any version of the dxcompiler.dll and dxil.dll.\n";
+ }
} // Windows
+ // Add FFmpeg if we deploy the FFmpeg backend
+ if (options.ffmpeg
+ && !plugins.filter(QStringLiteral("ffmpegmediaplugin"), Qt::CaseInsensitive).empty()) {
+ deployedQtLibraries.append(findFFmpegLibs(qtBinDir, options.platform));
+ }
+
// Update libraries
if (options.libraries) {
const QString targetPath = options.libraryDirectory.isEmpty() ?
options.directory : options.libraryDirectory;
QStringList libraries = deployedQtLibraries;
if (options.compilerRunTime)
- libraries.append(compilerRunTimeLibs(options.platform, result.isDebug, machineArch));
+ libraries.append(compilerRunTimeLibs(qtBinDir, options.platform, result.isDebug, machineArch));
for (const QString &qtLib : std::as_const(libraries)) {
if (!updateLibrary(qtLib, targetPath, options, errorMessage))
return result;
@@ -1451,7 +1731,7 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
#if !QT_CONFIG(relocatable)
if (options.patchQt && !options.dryRun) {
- const QString qt6CoreName = QFileInfo(libraryPath(libraryLocation, "Qt6Core", qtLibInfix,
+ const QString qt6CoreName = QFileInfo(libraryPath(libraryLocation, "Qt6Core", infix,
options.platform, result.isDebug)).fileName();
if (!patchQtCore(targetPath + u'/' + qt6CoreName, errorMessage)) {
std::wcerr << "Warning: " << *errorMessage << '\n';
@@ -1509,7 +1789,8 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
unsigned qmlDirectoryFileFlags = 0;
if (options.deployPdb)
qmlDirectoryFileFlags |= QmlDirectoryFileEntryFunction::DeployPdb;
- if (!updateFile(module.sourcePath, QmlDirectoryFileEntryFunction(options.platform,
+ if (!updateFile(module.sourcePath, QmlDirectoryFileEntryFunction(module.sourcePath,
+ options.platform,
debugMatchMode,
qmlDirectoryFileFlags),
installPath, updateFileFlags, options.json, errorMessage)) {
@@ -1533,7 +1814,8 @@ static DeployResult deploy(const Options &options, const QMap<QString, QString>
}
static bool deployWebProcess(const QMap<QString, QString> &qtpathsVariables, const char *binaryName,
- const Options &sourceOptions, QString *errorMessage)
+ const PluginInformation &pluginInfo, const Options &sourceOptions,
+ QString *errorMessage)
{
// Copy the web process and its dependencies
const QString webProcess = webProcessBinary(binaryName, sourceOptions.platform);
@@ -1545,23 +1827,26 @@ static bool deployWebProcess(const QMap<QString, QString> &qtpathsVariables, con
options.binaries.append(options.directory + u'/' + webProcess);
options.quickImports = false;
options.translations = false;
- return deploy(options, qtpathsVariables, errorMessage);
+ return deploy(options, qtpathsVariables, pluginInfo, errorMessage);
}
static bool deployWebEngineCore(const QMap<QString, QString> &qtpathsVariables,
- const Options &options, bool isDebug, QString *errorMessage)
+ const PluginInformation &pluginInfo, const Options &options,
+ bool isDebug, QString *errorMessage)
{
- static const char *installDataFiles[] = {"icudtl.dat",
- "qtwebengine_devtools_resources.pak",
- "qtwebengine_resources.pak",
- "qtwebengine_resources_100p.pak",
- "qtwebengine_resources_200p.pak"};
+ static const char *installDataFiles[] = { "icudtl.dat",
+ "qtwebengine_devtools_resources.pak",
+ "qtwebengine_resources.pak",
+ "qtwebengine_resources_100p.pak",
+ "qtwebengine_resources_200p.pak",
+ isDebug ? "v8_context_snapshot.debug.bin"
+ : "v8_context_snapshot.bin" };
QByteArray webEngineProcessName(webEngineProcessC);
if (isDebug && platformHasDebugSuffix(options.platform))
webEngineProcessName.append('d');
if (optVerboseLevel)
std::wcout << "Deploying: " << webEngineProcessName.constData() << "...\n";
- if (!deployWebProcess(qtpathsVariables, webEngineProcessName, options, errorMessage))
+ if (!deployWebProcess(qtpathsVariables, webEngineProcessName, pluginInfo, options, errorMessage))
return false;
const QString resourcesSubDir = QStringLiteral("/resources");
const QString resourcesSourceDir = qtpathsVariables.value(QStringLiteral("QT_INSTALL_DATA"))
@@ -1636,18 +1921,18 @@ int main(int argc, char **argv)
const QMap<QString, QString> qtpathsVariables =
queryQtPaths(options.qtpathsBinary, &errorMessage);
const QString xSpec = qtpathsVariables.value(QStringLiteral("QMAKE_XSPEC"));
- options.platform = platformFromMkSpec(xSpec);
- if (options.platform == UnknownPlatform) {
- std::wcerr << "Unsupported platform " << xSpec << '\n';
- return 1;
- }
-
if (qtpathsVariables.isEmpty() || xSpec.isEmpty()
|| !qtpathsVariables.contains(QStringLiteral("QT_INSTALL_BINS"))) {
std::wcerr << "Unable to query qtpaths: " << errorMessage << '\n';
return 1;
}
+ options.platform = platformFromMkSpec(xSpec);
+ if (options.platform == UnknownPlatform) {
+ std::wcerr << "Unsupported platform " << xSpec << '\n';
+ return 1;
+ }
+
// Read the Qt module information from the Qt installation directory.
const QString modulesDir
= qtpathsVariables.value(QLatin1String("QT_INSTALL_ARCHDATA"))
@@ -1661,6 +1946,10 @@ int main(int argc, char **argv)
}
assignKnownModuleIds();
+ // Read the Qt plugin types information from the Qt installation directory.
+ PluginInformation pluginInfo{};
+ pluginInfo.generateAvailablePlugins(qtpathsVariables, options.platform);
+
// Parse the full command line.
{
QCommandLineParser parser;
@@ -1668,8 +1957,12 @@ int main(int argc, char **argv)
const int result = parseArguments(QCoreApplication::arguments(), &parser, &options, &errorMessage);
if (result & CommandLineParseError)
std::wcerr << errorMessage << "\n\n";
+ if (result & CommandLineVersionRequested) {
+ std::fputs(QT_VERSION_STR "\n", stdout);
+ return 0;
+ }
if (result & CommandLineParseHelpRequested)
- std::fputs(qPrintable(helpText(parser)), stdout);
+ std::fputs(qPrintable(helpText(parser, pluginInfo)), stdout);
if (result & CommandLineParseError)
return 1;
if (result & CommandLineParseHelpRequested)
@@ -1687,14 +1980,15 @@ int main(int argc, char **argv)
return 1;
}
- const DeployResult result = deploy(options, qtpathsVariables, &errorMessage);
+ const DeployResult result = deploy(options, qtpathsVariables, pluginInfo, &errorMessage);
if (!result) {
std::wcerr << errorMessage << '\n';
return 1;
}
if (result.deployedQtLibraries.test(QtWebEngineCoreModuleId)) {
- if (!deployWebEngineCore(qtpathsVariables, options, result.isDebug, &errorMessage)) {
+ if (!deployWebEngineCore(qtpathsVariables, pluginInfo, options, result.isDebug,
+ &errorMessage)) {
std::wcerr << errorMessage << '\n';
return 1;
}
diff --git a/src/tools/windeployqt/qmlutils.cpp b/src/tools/windeployqt/qmlutils.cpp
index 5104af0194..a7e63e7470 100644
--- a/src/tools/windeployqt/qmlutils.cpp
+++ b/src/tools/windeployqt/qmlutils.cpp
@@ -67,7 +67,8 @@ static void findFileRecursion(const QDir &directory, Platform platform,
const QFileInfoList &subDirs = directory.entryInfoList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
for (const QFileInfo &subDirFi : subDirs) {
QDir subDirectory(subDirFi.absoluteFilePath());
- if (subDirectory.isReadable())
+ // Don't enter other QML modules when recursing!
+ if (subDirectory.isReadable() && !subDirectory.exists(QStringLiteral("qmldir")))
findFileRecursion(subDirectory, platform, debugMatchMode, matches);
}
}
diff --git a/src/tools/windeployqt/qtmoduleinfo.cpp b/src/tools/windeployqt/qtmoduleinfo.cpp
index 57aa8e54a0..b928a64478 100644
--- a/src/tools/windeployqt/qtmoduleinfo.cpp
+++ b/src/tools/windeployqt/qtmoduleinfo.cpp
@@ -4,7 +4,7 @@
#include "qtmoduleinfo.h"
#include "utils.h"
-#include <QDirIterator>
+#include <QDirListing>
#include <QJsonDocument>
#include <QJsonArray>
#include <QDebug>
@@ -134,14 +134,12 @@ bool QtModuleInfoStore::populate(const QString &modulesDir, const QString &trans
}
// Read modules, and assign a bit as ID.
- QDirIterator dit(modulesDir, { QLatin1String("*.json") }, QDir::Files);
- while (dit.hasNext()) {
- QString filePath = dit.next();
- QtModule module = moduleFromJsonFile(filePath, errorString);
+ for (const auto &dirEntry : QDirListing(modulesDir, {u"*.json"_s}, QDir::Files)) {
+ QtModule module = moduleFromJsonFile(dirEntry.filePath(), errorString);
if (!errorString->isEmpty())
return false;
- if (module.internal)
- continue;
+ if (module.internal && module.name.endsWith(QStringLiteral("Private")))
+ module.name.chop(7);
module.id = modules.size();
if (module.id == QtModule::InvalidId) {
*errorString = "Internal Error: too many modules for ModuleBitset to hold."_L1;
diff --git a/src/tools/windeployqt/qtplugininfo.cpp b/src/tools/windeployqt/qtplugininfo.cpp
new file mode 100644
index 0000000000..1deaa35f35
--- /dev/null
+++ b/src/tools/windeployqt/qtplugininfo.cpp
@@ -0,0 +1,100 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "qtplugininfo.h"
+
+#include <QDir>
+
+static PluginDetection determinePluginLibrary(const QDir &platformPluginDir, const QString &infix)
+{
+ // Use the platform plugin to determine which dlls are there (release/debug/both)
+ QString platformReleaseFilter(QStringLiteral("qwindows"));
+ if (!infix.isEmpty())
+ platformReleaseFilter += infix;
+ QString platformFilter = platformReleaseFilter + u'*';
+ platformFilter += sharedLibrarySuffix();
+
+ const QFileInfoList &dlls =
+ platformPluginDir.entryInfoList(QStringList(platformFilter), QDir::Files);
+ if (dlls.size() == 1) {
+ const QFileInfo dllFi = dlls.first();
+ const bool hasDebugDlls =
+ dllFi.fileName() == QString(platformReleaseFilter + sharedLibrarySuffix()) ? false
+ : true;
+ return (hasDebugDlls ? PluginDetection::DebugOnly : PluginDetection::ReleaseOnly);
+ } else {
+ return PluginDetection::DebugAndRelease;
+ }
+}
+
+static QStringList findPluginNames(const QDir &pluginDir, const PluginDetection libraryType,
+ const Platform &platform)
+{
+ QString errorMessage{};
+ QStringList result{};
+ QString filter{};
+ filter += u"*";
+ filter += sharedLibrarySuffix();
+
+ const QFileInfoList &dlls =
+ pluginDir.entryInfoList(QStringList(filter), QDir::Files, QDir::Name);
+
+ for (const QFileInfo &dllFi : dlls) {
+ QString plugin = dllFi.fileName();
+ const int dotIndex = plugin.lastIndexOf(u'.');
+ // We don't need the .dll for the name
+ plugin = plugin.first(dotIndex);
+
+ if (libraryType == PluginDetection::DebugAndRelease) {
+ bool isDebugDll{};
+ if (!readPeExecutable(dllFi.absoluteFilePath(), &errorMessage, 0, 0, &isDebugDll,
+ (platform == WindowsDesktopMinGW))) {
+ std::wcerr << "Warning: Unable to read "
+ << QDir::toNativeSeparators(dllFi.absoluteFilePath()) << ": "
+ << errorMessage;
+ }
+ if (isDebugDll && platformHasDebugSuffix(platform))
+ plugin.removeLast();
+ }
+ else if (libraryType == PluginDetection::DebugOnly)
+ plugin.removeLast();
+
+ if (!result.contains(plugin))
+ result.append(plugin);
+ }
+ return result;
+}
+
+bool PluginInformation::isTypeForPlugin(const QString &type, const QString &plugin) const
+{
+ return m_pluginMap.at(plugin) == type;
+}
+
+void PluginInformation::populatePluginToType(const QDir &pluginDir, const QStringList &plugins)
+{
+ for (const QString &plugin : plugins)
+ m_pluginMap.insert({ plugin, pluginDir.dirName() });
+}
+
+void PluginInformation::generateAvailablePlugins(const QMap<QString, QString> &qtPathsVariables,
+ const Platform &platform)
+{
+ const QDir pluginTypesDir(qtPathsVariables.value(QLatin1String("QT_INSTALL_PLUGINS")));
+ const QDir platformPluginDir(pluginTypesDir.absolutePath() + QStringLiteral("/platforms"));
+ const QString infix(qtPathsVariables.value(QLatin1String(qmakeInfixKey)));
+ const PluginDetection debugDetection = determinePluginLibrary(platformPluginDir, infix);
+
+ const QFileInfoList &pluginTypes =
+ pluginTypesDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
+ for (const QFileInfo &pluginType : pluginTypes) {
+ const QString pluginTypeName = pluginType.baseName();
+ m_typeMap.insert({ pluginTypeName, QStringList{} });
+ const QStringList plugins =
+ findPluginNames(pluginType.absoluteFilePath(), debugDetection, platform);
+ m_typeMap.at(pluginTypeName) = plugins;
+ populatePluginToType(pluginTypeName, plugins);
+ }
+ if (!m_typeMap.size() || !m_pluginMap.size())
+ std::wcerr << "Warning: could not parse available plugins properly, plugin "
+ "inclusion/exclusion options will not work\n";
+}
diff --git a/src/tools/windeployqt/qtplugininfo.h b/src/tools/windeployqt/qtplugininfo.h
new file mode 100644
index 0000000000..420b2b5e1a
--- /dev/null
+++ b/src/tools/windeployqt/qtplugininfo.h
@@ -0,0 +1,48 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef QTPLUGININFO_H
+#define QTPLUGININFO_H
+
+#include "utils.h"
+
+#include <QString>
+#include <QStringList>
+
+#include <unordered_map>
+
+enum class PluginDetection
+{
+ DebugOnly,
+ ReleaseOnly,
+ DebugAndRelease
+};
+
+struct PluginSelections
+{
+ QStringList disabledPluginTypes;
+ QStringList enabledPluginTypes;
+ QStringList excludedPlugins;
+ QStringList includedPlugins;
+ bool includeSoftPlugins = false;
+};
+
+class PluginInformation
+{
+public:
+ PluginInformation() = default;
+
+ bool isTypeForPlugin(const QString &type, const QString &plugin) const;
+
+ void generateAvailablePlugins(const QMap<QString, QString> &qtPathsVariables,
+ const Platform &platform);
+ void populatePluginToType(const QDir &pluginDir, const QStringList &plugins);
+
+ const std::unordered_map<QString, QStringList> &typeMap() const { return m_typeMap; }
+
+private:
+ std::unordered_map<QString, QStringList> m_typeMap;
+ std::unordered_map<QString, QString> m_pluginMap;
+};
+
+#endif
diff --git a/src/tools/windeployqt/utils.cpp b/src/tools/windeployqt/utils.cpp
index d54d075894..5141119254 100644
--- a/src/tools/windeployqt/utils.cpp
+++ b/src/tools/windeployqt/utils.cpp
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "utils.h"
-#include "elfreader.h"
#include <QtCore/QString>
#include <QtCore/QDebug>
@@ -95,7 +94,7 @@ QStringList findSharedLibraries(const QDir &directory, Platform platform,
nameFilter += u'*';
if (debugMatchMode == MatchDebug && platformHasDebugSuffix(platform))
nameFilter += u'd';
- nameFilter += sharedLibrarySuffix(platform);
+ nameFilter += sharedLibrarySuffix();
QStringList result;
QString errorMessage;
const QFileInfoList &dlls = directory.entryInfoList(QStringList(nameFilter), QDir::Files);
@@ -424,14 +423,18 @@ const char *qmakeInfixKey = "QT_INFIX";
QMap<QString, QString> queryQtPaths(const QString &qtpathsBinary, QString *errorMessage)
{
const QString binary = !qtpathsBinary.isEmpty() ? qtpathsBinary : QStringLiteral("qtpaths");
+ const QString colonSpace = QStringLiteral(": ");
QByteArray stdOut;
QByteArray stdErr;
unsigned long exitCode = 0;
- if (!runProcess(binary, QStringList(QStringLiteral("-query")), QString(), &exitCode, &stdOut, &stdErr, errorMessage))
+ if (!runProcess(binary, QStringList(QStringLiteral("-query")), QString(), &exitCode, &stdOut,
+ &stdErr, errorMessage)) {
+ *errorMessage = QStringLiteral("Error running binary ") + binary + colonSpace + *errorMessage;
return QMap<QString, QString>();
+ }
if (exitCode) {
*errorMessage = binary + QStringLiteral(" returns ") + QString::number(exitCode)
- + QStringLiteral(": ") + QString::fromLocal8Bit(stdErr);
+ + colonSpace + QString::fromLocal8Bit(stdErr);
return QMap<QString, QString>();
}
const QString output = QString::fromLocal8Bit(stdOut).trimmed().remove(u'\r');
@@ -467,7 +470,7 @@ QMap<QString, QString> queryQtPaths(const QString &qtpathsBinary, QString *error
}
} else {
std::wcerr << "Warning: Unable to read " << QDir::toNativeSeparators(qconfigPriFile.fileName())
- << ": " << qconfigPriFile.errorString()<< '\n';
+ << colonSpace << qconfigPriFile.errorString()<< '\n';
}
return result;
}
@@ -553,37 +556,6 @@ bool updateFile(const QString &sourceFileName, const QStringList &nameFilters,
return true;
}
-bool readElfExecutable(const QString &elfExecutableFileName, QString *errorMessage,
- QStringList *dependentLibraries, unsigned *wordSize,
- bool *isDebug)
-{
- ElfReader elfReader(elfExecutableFileName);
- const ElfData data = elfReader.readHeaders();
- if (data.sectionHeaders.isEmpty()) {
- *errorMessage = QStringLiteral("Unable to read ELF binary \"")
- + QDir::toNativeSeparators(elfExecutableFileName) + QStringLiteral("\": ")
- + elfReader.errorString();
- return false;
- }
- if (wordSize)
- *wordSize = data.elfclass == Elf_ELFCLASS64 ? 64 : 32;
- if (dependentLibraries) {
- dependentLibraries->clear();
- const QList<QByteArray> libs = elfReader.dependencies();
- if (libs.isEmpty()) {
- *errorMessage = QStringLiteral("Unable to read dependenices of ELF binary \"")
- + QDir::toNativeSeparators(elfExecutableFileName) + QStringLiteral("\": ")
- + elfReader.errorString();
- return false;
- }
- for (const QByteArray &l : libs)
- dependentLibraries->push_back(QString::fromLocal8Bit(l));
- }
- if (isDebug)
- *isDebug = data.symbolsType != UnknownSymbols && data.symbolsType != NoSymbols;
- return true;
-}
-
#ifdef Q_OS_WIN
static inline QString stringFromRvaPtr(const void *rvaPtr)
@@ -705,13 +677,23 @@ static inline MsvcDebugRuntimeResult checkMsvcDebugRuntime(const QStringList &de
qsizetype pos = 0;
if (lib.startsWith("MSVCR"_L1, Qt::CaseInsensitive)
|| lib.startsWith("MSVCP"_L1, Qt::CaseInsensitive)
- || lib.startsWith("VCRUNTIME"_L1, Qt::CaseInsensitive)) {
+ || lib.startsWith("VCRUNTIME"_L1, Qt::CaseInsensitive)
+ || lib.startsWith("VCCORLIB"_L1, Qt::CaseInsensitive)
+ || lib.startsWith("CONCRT"_L1, Qt::CaseInsensitive)
+ || lib.startsWith("UCRTBASE"_L1, Qt::CaseInsensitive)) {
qsizetype lastDotPos = lib.lastIndexOf(u'.');
pos = -1 == lastDotPos ? 0 : lastDotPos - 1;
}
- if (pos > 0 && lib.contains("_app"_L1, Qt::CaseInsensitive))
- pos -= 4;
+ if (pos > 0) {
+ const auto removeExtraSuffix = [&lib, &pos](const QString &suffix) -> void {
+ if (lib.contains(suffix, Qt::CaseInsensitive))
+ pos -= suffix.size();
+ };
+ removeExtraSuffix("_app"_L1);
+ removeExtraSuffix("_atomic_wait"_L1);
+ removeExtraSuffix("_codecvt_ids"_L1);
+ }
if (pos)
return lib.at(pos).toLower() == u'd' ? MsvcDebugRuntime : MsvcReleaseRuntime;
@@ -720,32 +702,43 @@ static inline MsvcDebugRuntimeResult checkMsvcDebugRuntime(const QStringList &de
}
template <class ImageNtHeader>
+inline QStringList determineDependentLibs(const ImageNtHeader *nth, const void *fileMemory,
+ QString *errorMessage)
+{
+ return readImportSections(nth, fileMemory, errorMessage);
+}
+
+template <class ImageNtHeader>
+inline bool determineDebug(const ImageNtHeader *nth, const void *fileMemory,
+ QStringList *dependentLibrariesIn, QString *errorMessage)
+{
+ if (nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED)
+ return false;
+
+ const QStringList dependentLibraries = dependentLibrariesIn != nullptr ?
+ *dependentLibrariesIn :
+ determineDependentLibs(nth, fileMemory, errorMessage);
+
+ const bool hasDebugEntry = nth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
+ // When an MSVC debug entry is present, check whether the debug runtime
+ // is actually used to detect -release / -force-debug-info builds.
+ const MsvcDebugRuntimeResult msvcrt = checkMsvcDebugRuntime(dependentLibraries);
+ if (msvcrt == NoMsvcRuntime)
+ return hasDebugEntry;
+ else
+ return hasDebugEntry && msvcrt == MsvcDebugRuntime;
+}
+
+template <class ImageNtHeader>
inline void determineDebugAndDependentLibs(const ImageNtHeader *nth, const void *fileMemory,
- bool isMinGW,
QStringList *dependentLibrariesIn,
bool *isDebugIn, QString *errorMessage)
{
- const bool hasDebugEntry = nth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size;
- QStringList dependentLibraries;
- if (dependentLibrariesIn || (isDebugIn != nullptr && hasDebugEntry && !isMinGW))
- dependentLibraries = readImportSections(nth, fileMemory, errorMessage);
-
if (dependentLibrariesIn)
- *dependentLibrariesIn = dependentLibraries;
- if (isDebugIn != nullptr) {
- if (isMinGW) {
- // Use logic that's used e.g. in objdump / pfd library
- *isDebugIn = !(nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED);
- } else {
- // When an MSVC debug entry is present, check whether the debug runtime
- // is actually used to detect -release / -force-debug-info builds.
- const MsvcDebugRuntimeResult msvcrt = checkMsvcDebugRuntime(dependentLibraries);
- if (msvcrt == NoMsvcRuntime)
- *isDebugIn = hasDebugEntry;
- else
- *isDebugIn = hasDebugEntry && msvcrt == MsvcDebugRuntime;
- }
- }
+ *dependentLibrariesIn = determineDependentLibs(nth, fileMemory, errorMessage);
+
+ if (isDebugIn)
+ *isDebugIn = determineDebug(nth, fileMemory, dependentLibrariesIn, errorMessage);
}
// Read a PE executable and determine dependent libraries, word size
@@ -799,10 +792,10 @@ bool readPeExecutable(const QString &peExecutableFileName, QString *errorMessage
*wordSizeIn = wordSize;
if (wordSize == 32) {
determineDebugAndDependentLibs(reinterpret_cast<const IMAGE_NT_HEADERS32 *>(ntHeaders),
- fileMemory, isMinGW, dependentLibrariesIn, isDebugIn, errorMessage);
+ fileMemory, dependentLibrariesIn, isDebugIn, errorMessage);
} else {
determineDebugAndDependentLibs(reinterpret_cast<const IMAGE_NT_HEADERS64 *>(ntHeaders),
- fileMemory, isMinGW, dependentLibrariesIn, isDebugIn, errorMessage);
+ fileMemory, dependentLibrariesIn, isDebugIn, errorMessage);
}
if (machineArchIn)
@@ -885,6 +878,53 @@ QString findD3dCompiler(Platform platform, const QString &qtBinDir, unsigned wor
return QString();
}
+QStringList findDxc(Platform platform, const QString &qtBinDir, unsigned wordSize)
+{
+ QStringList results;
+ const QString kitDir = QString::fromLocal8Bit(qgetenv("WindowsSdkDir"));
+ const QString suffix = QLatin1StringView(windowsSharedLibrarySuffix);
+ for (QString prefix : { QStringLiteral("dxcompiler"), QStringLiteral("dxil") }) {
+ QString name = prefix + suffix;
+ if (!kitDir.isEmpty()) {
+ QString redistDirPath = QDir::cleanPath(kitDir) + QStringLiteral("/Redist/D3D/");
+ if (platform.testFlag(ArmBased)) {
+ redistDirPath += wordSize == 32 ? QStringLiteral("arm") : QStringLiteral("arm64");
+ } else {
+ redistDirPath += wordSize == 32 ? QStringLiteral("x86") : QStringLiteral("x64");
+ }
+ QDir redistDir(redistDirPath);
+ if (redistDir.exists()) {
+ const QFileInfoList files = redistDir.entryInfoList(QStringList(prefix + u'*' + suffix), QDir::Files);
+ if (!files.isEmpty()) {
+ results.append(files.front().absoluteFilePath());
+ continue;
+ }
+ }
+ }
+ // Check the bin directory of the Qt SDK (in case it is shadowed by the
+ // Windows system directory in PATH).
+ const QFileInfo fi(qtBinDir + u'/' + name);
+ if (fi.isFile()) {
+ results.append(fi.absoluteFilePath());
+ continue;
+ }
+ // Try to find it in the PATH (e.g. the Vulkan SDK ships these, even if Windows itself doesn't).
+ if (platform.testFlag(IntelBased)) {
+ QString errorMessage;
+ unsigned detectedWordSize;
+ const QString dll = findInPath(name);
+ if (!dll.isEmpty()
+ && readPeExecutable(dll, &errorMessage, 0, &detectedWordSize, 0)
+ && detectedWordSize == wordSize)
+ {
+ results.append(dll);
+ continue;
+ }
+ }
+ }
+ return results;
+}
+
#else // Q_OS_WIN
bool readPeExecutable(const QString &, QString *errorMessage,
@@ -899,6 +939,11 @@ QString findD3dCompiler(Platform, const QString &, unsigned)
return QString();
}
+QStringList findDxc(Platform, const QString &, unsigned)
+{
+ return QStringList();
+}
+
#endif // !Q_OS_WIN
// Search for "qt_prfxpath=xxxx" in \a path, and replace it with "qt_prfxpath=."
diff --git a/src/tools/windeployqt/utils.h b/src/tools/windeployqt/utils.h
index 5bf2cde111..fb3ba0b40b 100644
--- a/src/tools/windeployqt/utils.h
+++ b/src/tools/windeployqt/utils.h
@@ -20,7 +20,6 @@ QT_BEGIN_NAMESPACE
enum PlatformFlag {
// OS
WindowsBased = 0x00001,
- UnixBased = 0x00002,
// CPU
IntelBased = 0x00010,
ArmBased = 0x00020,
@@ -30,11 +29,12 @@ enum PlatformFlag {
ClangMsvc = 0x00400,
ClangMinGW = 0x00800,
// Platforms
- WindowsDesktopMsvc = WindowsBased + IntelBased + Msvc,
+ WindowsDesktopMsvc = WindowsBased + Msvc,
+ WindowsDesktopMsvcIntel = WindowsDesktopMsvc + IntelBased,
+ WindowsDesktopMsvcArm = WindowsDesktopMsvc + ArmBased,
WindowsDesktopMinGW = WindowsBased + IntelBased + MinGW,
WindowsDesktopClangMsvc = WindowsBased + IntelBased + ClangMsvc,
WindowsDesktopClangMinGW = WindowsBased + IntelBased + ClangMinGW,
- Unix = UnixBased,
UnknownPlatform
};
@@ -68,7 +68,7 @@ inline std::wostream &operator<<(std::wostream &str, const QString &s)
// Container class for JSON output
class JsonOutput
{
- using SourceTargetMapping = QPair<QString, QString>;
+ using SourceTargetMapping = std::pair<QString, QString>;
using SourceTargetMappings = QList<SourceTargetMapping>;
public:
@@ -137,9 +137,8 @@ inline QString normalizeFileName(const QString &name) { return name; }
#endif // !Q_OS_WIN
static const char windowsSharedLibrarySuffix[] = ".dll";
-static const char unixSharedLibrarySuffix[] = ".so";
-inline QString sharedLibrarySuffix(Platform platform) { return QLatin1StringView((platform & WindowsBased) ? windowsSharedLibrarySuffix : unixSharedLibrarySuffix); }
+inline QString sharedLibrarySuffix() { return QLatin1StringView(windowsSharedLibrarySuffix); }
bool isBuildDirectory(Platform platform, const QString &dirName);
bool createSymbolicLink(const QFileInfo &source, const QString &target, QString *errorMessage);
@@ -170,19 +169,6 @@ bool runProcess(const QString &binary, const QStringList &args,
bool readPeExecutable(const QString &peExecutableFileName, QString *errorMessage,
QStringList *dependentLibraries = 0, unsigned *wordSize = 0,
bool *isDebug = 0, bool isMinGW = false, unsigned short *machineArch = nullptr);
-bool readElfExecutable(const QString &elfExecutableFileName, QString *errorMessage,
- QStringList *dependentLibraries = 0, unsigned *wordSize = 0,
- bool *isDebug = 0);
-
-inline bool readExecutable(const QString &executableFileName, Platform platform,
- QString *errorMessage, QStringList *dependentLibraries = 0,
- unsigned *wordSize = 0, bool *isDebug = 0, unsigned short *machineArch = nullptr)
-{
- return platform == Unix ?
- readElfExecutable(executableFileName, errorMessage, dependentLibraries, wordSize, isDebug) :
- readPeExecutable(executableFileName, errorMessage, dependentLibraries, wordSize, isDebug,
- (platform == WindowsDesktopMinGW), machineArch);
-}
#ifdef Q_OS_WIN
# if !defined(IMAGE_FILE_MACHINE_ARM64)
@@ -193,14 +179,15 @@ QString getArchString (unsigned short machineArch);
// Return dependent modules of executable files.
-inline QStringList findDependentLibraries(const QString &executableFileName, Platform platform, QString *errorMessage)
+inline QStringList findDependentLibraries(const QString &executableFileName, QString *errorMessage)
{
QStringList result;
- readExecutable(executableFileName, platform, errorMessage, &result);
+ readPeExecutable(executableFileName, errorMessage, &result);
return result;
}
QString findD3dCompiler(Platform platform, const QString &qtBinDir, unsigned wordSize);
+QStringList findDxc(Platform platform, const QString &qtBinDir, unsigned wordSize);
bool patchQtCore(const QString &path, QString *errorMessage);
diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt
index 417f6a2d8e..fdef309a4a 100644
--- a/src/widgets/CMakeLists.txt
+++ b/src/widgets/CMakeLists.txt
@@ -20,6 +20,7 @@ qt_internal_add_module(Widgets
kernel/qlayout.cpp kernel/qlayout.h kernel/qlayout_p.h
kernel/qlayoutengine.cpp kernel/qlayoutengine_p.h
kernel/qlayoutitem.cpp kernel/qlayoutitem.h
+ kernel/qrhiwidget.cpp kernel/qrhiwidget.h kernel/qrhiwidget_p.h
kernel/qsizepolicy.cpp kernel/qsizepolicy.h
kernel/qstackedlayout.cpp kernel/qstackedlayout.h
kernel/qstandardgestures.cpp kernel/qstandardgestures_p.h
@@ -51,7 +52,10 @@ qt_internal_add_module(Widgets
widgets/qframe.cpp widgets/qframe.h widgets/qframe_p.h
widgets/qwidgetanimator.cpp widgets/qwidgetanimator_p.h
DEFINES
+ QT_NO_CONTEXTLESS_CONNECT
QT_NO_USING_NAMESPACE
+ QT_NO_FOREACH
+ QT_USE_NODISCARD_FILE_OPEN
INCLUDE_DIRECTORIES
dialogs
LIBRARIES
@@ -65,19 +69,22 @@ qt_internal_add_module(Widgets
Qt::GuiPrivate
PRECOMPILED_HEADER
"kernel/qt_widgets_pch.h"
+ NO_PCH_SOURCES
+ compat/removed_api.cpp
GENERATE_CPP_EXPORTS
)
-if(APPLE)
- set_source_files_properties(kernel/qapplication.cpp
- PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
-endif()
+qt_internal_extend_target(Widgets CONDITION APPLE
+ NO_UNITY_BUILD_SOURCES
+ kernel/qapplication.cpp
+)
# Resources:
set(qstyle_resource_files
"styles/images/cdr-128.png"
"styles/images/cdr-16.png"
"styles/images/cdr-32.png"
+ "styles/images/cleartext-128.png"
"styles/images/cleartext-16.png"
"styles/images/cleartext-32.png"
"styles/images/closedock-10.png"
@@ -88,6 +95,9 @@ set(qstyle_resource_files
"styles/images/closedock-64.png"
"styles/images/computer-16.png"
"styles/images/computer-32.png"
+ "styles/images/critical-128.png"
+ "styles/images/critical-16.png"
+ "styles/images/critical-32.png"
"styles/images/desktop-16.png"
"styles/images/desktop-32.png"
"styles/images/dirclosed-128.png"
@@ -111,6 +121,12 @@ set(qstyle_resource_files
"styles/images/filecontents-128.png"
"styles/images/filecontents-16.png"
"styles/images/filecontents-32.png"
+ "styles/images/filedialog_end-128.png"
+ "styles/images/filedialog_end-16.png"
+ "styles/images/filedialog_end-32.png"
+ "styles/images/filedialog_start-128.png"
+ "styles/images/filedialog_start-16.png"
+ "styles/images/filedialog_start-32.png"
"styles/images/fileinfo-128.png"
"styles/images/fileinfo-16.png"
"styles/images/fileinfo-32.png"
@@ -126,21 +142,31 @@ set(qstyle_resource_files
"styles/images/harddrive-128.png"
"styles/images/harddrive-16.png"
"styles/images/harddrive-32.png"
+ "styles/images/information-128.png"
+ "styles/images/information-16.png"
+ "styles/images/information-32.png"
"styles/images/left-128.png"
"styles/images/left-16.png"
"styles/images/left-32.png"
+ "styles/images/media-pause-128.png"
"styles/images/media-pause-16.png"
"styles/images/media-pause-32.png"
+ "styles/images/media-play-128.png"
"styles/images/media-play-16.png"
"styles/images/media-play-32.png"
+ "styles/images/media-seek-backward-128.png"
"styles/images/media-seek-backward-16.png"
"styles/images/media-seek-backward-32.png"
+ "styles/images/media-seek-forward-128.png"
"styles/images/media-seek-forward-16.png"
"styles/images/media-seek-forward-32.png"
+ "styles/images/media-skip-backward-128.png"
"styles/images/media-skip-backward-16.png"
"styles/images/media-skip-backward-32.png"
+ "styles/images/media-skip-forward-128.png"
"styles/images/media-skip-forward-16.png"
"styles/images/media-skip-forward-32.png"
+ "styles/images/media-stop-128.png"
"styles/images/media-stop-16.png"
"styles/images/media-stop-32.png"
"styles/images/media-volume-16.png"
@@ -160,6 +186,9 @@ set(qstyle_resource_files
"styles/images/parentdir-128.png"
"styles/images/parentdir-16.png"
"styles/images/parentdir-32.png"
+ "styles/images/question-128.png"
+ "styles/images/question-16.png"
+ "styles/images/question-32.png"
"styles/images/refresh-24.png"
"styles/images/refresh-32.png"
"styles/images/right-128.png"
@@ -177,12 +206,15 @@ set(qstyle_resource_files
"styles/images/standardbutton-close-128.png"
"styles/images/standardbutton-close-16.png"
"styles/images/standardbutton-close-32.png"
- "styles/images/standardbutton-closetab-32.png"
+ "styles/images/standardbutton-closetab-128.png"
"styles/images/standardbutton-closetab-16.png"
- "styles/images/standardbutton-closetab-down-32.png"
+ "styles/images/standardbutton-closetab-32.png"
+ "styles/images/standardbutton-closetab-down-128.png"
"styles/images/standardbutton-closetab-down-16.png"
- "styles/images/standardbutton-closetab-hover-32.png"
+ "styles/images/standardbutton-closetab-down-32.png"
+ "styles/images/standardbutton-closetab-hover-128.png"
"styles/images/standardbutton-closetab-hover-16.png"
+ "styles/images/standardbutton-closetab-hover-32.png"
"styles/images/standardbutton-delete-128.png"
"styles/images/standardbutton-delete-16.png"
"styles/images/standardbutton-delete-32.png"
@@ -221,14 +253,17 @@ set(qstyle_resource_files
"styles/images/titlebar-unshade-16.png"
"styles/images/titlebar-unshade-32.png"
"styles/images/titlebar-unshade-48.png"
+ "styles/images/toolbar-ext-h-128.png"
"styles/images/toolbar-ext-h-16.png"
"styles/images/toolbar-ext-h-32.png"
"styles/images/toolbar-ext-h-8.png"
+ "styles/images/toolbar-ext-h-rtl-128.png"
"styles/images/toolbar-ext-h-rtl-16.png"
"styles/images/toolbar-ext-h-rtl-32.png"
"styles/images/toolbar-ext-h-rtl-8.png"
"styles/images/toolbar-ext-v-10.png"
"styles/images/toolbar-ext-v-20.png"
+ "styles/images/toolbar-ext-v-80.png"
"styles/images/toolbar-ext-v-5.png"
"styles/images/trash-128.png"
"styles/images/trash-16.png"
@@ -242,17 +277,11 @@ set(qstyle_resource_files
"styles/images/viewlist-128.png"
"styles/images/viewlist-16.png"
"styles/images/viewlist-32.png"
+ "styles/images/warning-128.png"
+ "styles/images/warning-16.png"
+ "styles/images/warning-32.png"
)
-set(widgets_no_pch_sources
- compat/removed_api.cpp
-)
-
-foreach(src ${widgets_no_pch_sources})
- qt_update_ignore_pch_source(Widgets ${src})
-endforeach()
-
-
qt_internal_add_resource(Widgets "qstyle"
PREFIX
"/qt-project.org/styles/commonstyle"
@@ -299,6 +328,36 @@ qt_internal_add_resource(Widgets "qstyle1"
${qstyle1_resource_files}
)
+set(qstyle_resource_fusion_files
+ "styles/images/fusion_closedock-10.png"
+ "styles/images/fusion_closedock-16.png"
+ "styles/images/fusion_closedock-20.png"
+ "styles/images/fusion_closedock-32.png"
+ "styles/images/fusion_closedock-48.png"
+ "styles/images/fusion_closedock-64.png"
+ "styles/images/fusion_normalizedockup_10.png"
+ "styles/images/fusion_normalizedockup-16.png"
+ "styles/images/fusion_normalizedockup_20.png"
+ "styles/images/fusion_normalizedockup-32.png"
+ "styles/images/fusion_normalizedockup_48.png"
+ "styles/images/fusion_normalizedockup_64.png"
+ "styles/images/fusion_titlebar-min-10.png"
+ "styles/images/fusion_titlebar-min-16.png"
+ "styles/images/fusion_titlebar-min-20.png"
+ "styles/images/fusion_titlebar-min-32.png"
+ "styles/images/fusion_titlebar-min-48.png"
+ "styles/images/fusion_titlebar-min-64.png"
+)
+
+qt_internal_add_resource(Widgets "qstyle_fusion"
+ PREFIX
+ "/qt-project.org/styles/fusionstyle"
+ BASE
+ "styles"
+ FILES
+ ${qstyle_resource_fusion_files}
+)
+
if(QT_FEATURE_reduce_relocations AND UNIX AND GCC)
target_link_options(Widgets PRIVATE
"LINKER:--dynamic-list=${CMAKE_CURRENT_LIST_DIR}/QtWidgets.dynlist")
@@ -510,7 +569,7 @@ qt_internal_extend_target(Widgets CONDITION QT_FEATURE_resizehandler
qt_internal_extend_target(Widgets CONDITION QT_FEATURE_dialogbuttonbox
SOURCES
- widgets/qdialogbuttonbox.cpp widgets/qdialogbuttonbox.h
+ widgets/qdialogbuttonbox.cpp widgets/qdialogbuttonbox.h widgets/qdialogbuttonbox_p.h
)
qt_internal_extend_target(Widgets CONDITION QT_FEATURE_rubberband
@@ -661,6 +720,8 @@ qt_internal_extend_target(Widgets CONDITION QT_FEATURE_inputdialog
qt_internal_extend_target(Widgets CONDITION QT_FEATURE_messagebox
SOURCES
dialogs/qmessagebox.cpp dialogs/qmessagebox.h
+ NO_UNITY_BUILD_SOURCES
+ dialogs/qmessagebox.cpp # error: ‘Old_Ok’ [etc] was not declared in this scope
)
if(QT_FEATURE_messagebox)
@@ -693,7 +754,7 @@ if(QT_FEATURE_wizard)
if(APPLE)
set_source_files_properties(dialogs/qwizard.cpp
PROPERTIES
- COMPILE_FLAGS "-x objective-c++"
+ LANGUAGE OBJCXX
SKIP_PRECOMPILE_HEADERS ON
)
endif()
@@ -851,6 +912,11 @@ qt_internal_add_docs(Widgets
doc/qtwidgets.qdocconf
)
+if(IOS)
+ qt_internal_set_apple_privacy_manifest(Widgets
+ "${CMAKE_CURRENT_SOURCE_DIR}/platform/ios/PrivacyInfo.xcprivacy")
+endif()
+
# include the snippet projects for developer-builds
if(QT_FEATURE_private_tests)
add_subdirectory(doc/snippets/customviewstyle)
diff --git a/src/widgets/accessible/complexwidgets.cpp b/src/widgets/accessible/complexwidgets.cpp
index 624090a2af..77bf8504fa 100644
--- a/src/widgets/accessible/complexwidgets.cpp
+++ b/src/widgets/accessible/complexwidgets.cpp
@@ -78,7 +78,9 @@ public:
}
QAccessible::State s = parent()->state();
+ s.selectable = true;
s.focused = (m_index == m_parent->currentIndex());
+ s.selected = s.focused;
return s;
}
QRect rect() const override {
@@ -181,6 +183,14 @@ QAccessibleTabBar::~QAccessibleTabBar()
QAccessible::deleteAccessibleInterface(id);
}
+void *QAccessibleTabBar::interface_cast(QAccessible::InterfaceType t)
+{
+ if (t == QAccessible::SelectionInterface) {
+ return static_cast<QAccessibleSelectionInterface*>(this);
+ }
+ return QAccessibleWidget::interface_cast(t);
+}
+
/*! Returns the QTabBar. */
QTabBar *QAccessibleTabBar::tabBar() const
{
@@ -258,6 +268,60 @@ QString QAccessibleTabBar::text(QAccessible::Text t) const
return QString();
}
+int QAccessibleTabBar::selectedItemCount() const
+{
+ if (tabBar()->currentIndex() >= 0)
+ return 1;
+ return 0;
+}
+
+QList<QAccessibleInterface*> QAccessibleTabBar::selectedItems() const
+{
+ QList<QAccessibleInterface*> items;
+ QAccessibleInterface *selected = selectedItem(0);
+ if (selected)
+ items.push_back(selected);
+ return items;
+}
+
+QAccessibleInterface* QAccessibleTabBar::selectedItem(int selectionIndex) const
+{
+ const int currentIndex = tabBar()->currentIndex();
+ if (selectionIndex != 0 || currentIndex < 0)
+ return nullptr;
+ return child(currentIndex);
+}
+
+bool QAccessibleTabBar::isSelected(QAccessibleInterface *childItem) const
+{
+ return childItem && selectedItem(0) == childItem;
+}
+
+bool QAccessibleTabBar::select(QAccessibleInterface *childItem)
+{
+ const int childIndex = indexOfChild(childItem);
+ if (childIndex >= 0) {
+ tabBar()->setCurrentIndex(childIndex);
+ return true;
+ }
+ return false;
+}
+
+bool QAccessibleTabBar::unselect(QAccessibleInterface *)
+{
+ return false;
+}
+
+bool QAccessibleTabBar::selectAll()
+{
+ return false;
+}
+
+bool QAccessibleTabBar::clear()
+{
+ return false;
+}
+
#endif // QT_CONFIG(tabbar)
#if QT_CONFIG(combobox)
@@ -283,17 +347,19 @@ QAccessibleComboBox::QAccessibleComboBox(QWidget *w)
*/
QComboBox *QAccessibleComboBox::comboBox() const
{
- return qobject_cast<QComboBox*>(object());
+ return qobject_cast<QComboBox *>(object());
}
QAccessibleInterface *QAccessibleComboBox::child(int index) const
{
- if (index == 0) {
- QAbstractItemView *view = comboBox()->view();
- //QWidget *parent = view ? view->parentWidget() : 0;
- return QAccessible::queryAccessibleInterface(view);
- } else if (index == 1 && comboBox()->isEditable()) {
- return QAccessible::queryAccessibleInterface(comboBox()->lineEdit());
+ if (QComboBox *cBox = comboBox()) {
+ if (index == 0) {
+ QAbstractItemView *view = cBox->view();
+ //QWidget *parent = view ? view->parentWidget() : 0;
+ return QAccessible::queryAccessibleInterface(view);
+ } else if (index == 1 && cBox->isEditable()) {
+ return QAccessible::queryAccessibleInterface(cBox->lineEdit());
+ }
}
return nullptr;
}
@@ -301,22 +367,28 @@ QAccessibleInterface *QAccessibleComboBox::child(int index) const
int QAccessibleComboBox::childCount() const
{
// list and text edit
- return comboBox()->isEditable() ? 2 : 1;
+ if (QComboBox *cBox = comboBox())
+ return (cBox->isEditable()) ? 2 : 1;
+ return 0;
}
QAccessibleInterface *QAccessibleComboBox::childAt(int x, int y) const
{
- if (comboBox()->isEditable() && comboBox()->lineEdit()->rect().contains(x, y))
- return child(1);
+ if (QComboBox *cBox = comboBox()) {
+ if (cBox->isEditable() && cBox->lineEdit()->rect().contains(x, y))
+ return child(1);
+ }
return nullptr;
}
int QAccessibleComboBox::indexOfChild(const QAccessibleInterface *child) const
{
- if (comboBox()->view() == child->object())
- return 0;
- if (comboBox()->isEditable() && comboBox()->lineEdit() == child->object())
- return 1;
+ if (QComboBox *cBox = comboBox()) {
+ if (cBox->view() == child->object())
+ return 0;
+ if (cBox->isEditable() && cBox->lineEdit() == child->object())
+ return 1;
+ }
return -1;
}
@@ -325,8 +397,10 @@ QAccessibleInterface *QAccessibleComboBox::focusChild() const
// The editable combobox is the focus proxy of its lineedit, so the
// lineedit itself never gets focus. But it is the accessible focus
// child of an editable combobox.
- if (comboBox()->isEditable())
- return child(1);
+ if (QComboBox *cBox = comboBox()) {
+ if (cBox->isEditable())
+ return child(1);
+ }
return nullptr;
}
@@ -334,29 +408,30 @@ QAccessibleInterface *QAccessibleComboBox::focusChild() const
QString QAccessibleComboBox::text(QAccessible::Text t) const
{
QString str;
-
- switch (t) {
- case QAccessible::Name:
+ if (QComboBox *cBox = comboBox()) {
+ switch (t) {
+ case QAccessible::Name:
#ifndef Q_OS_UNIX // on Linux we use relations for this, name is text (fall through to Value)
str = QAccessibleWidget::text(t);
break;
#endif
- case QAccessible::Value:
- if (comboBox()->isEditable())
- str = comboBox()->lineEdit()->text();
- else
- str = comboBox()->currentText();
- break;
+ case QAccessible::Value:
+ if (cBox->isEditable())
+ str = cBox->lineEdit()->text();
+ else
+ str = cBox->currentText();
+ break;
#ifndef QT_NO_SHORTCUT
- case QAccessible::Accelerator:
- str = QKeySequence(Qt::Key_Down).toString(QKeySequence::NativeText);
- break;
+ case QAccessible::Accelerator:
+ str = QKeySequence(Qt::Key_Down).toString(QKeySequence::NativeText);
+ break;
#endif
- default:
- break;
+ default:
+ break;
+ }
+ if (str.isEmpty())
+ str = QAccessibleWidget::text(t);
}
- if (str.isEmpty())
- str = QAccessibleWidget::text(t);
return str;
}
@@ -364,10 +439,11 @@ QAccessible::State QAccessibleComboBox::state() const
{
QAccessible::State s = QAccessibleWidget::state();
- s.expandable = true;
- s.expanded = isValid() && comboBox()->view()->isVisible();
- s.editable = comboBox()->isEditable();
-
+ if (QComboBox *cBox = comboBox()) {
+ s.expandable = true;
+ s.expanded = isValid() && cBox->view()->isVisible();
+ s.editable = cBox->isEditable();
+ }
return s;
}
@@ -385,26 +461,28 @@ QString QAccessibleComboBox::localizedActionDescription(const QString &actionNam
void QAccessibleComboBox::doAction(const QString &actionName)
{
- if (actionName == showMenuAction() || actionName == pressAction()) {
- if (comboBox()->view()->isVisible()) {
+ if (QComboBox *cBox = comboBox()) {
+ if (actionName == showMenuAction() || actionName == pressAction()) {
+ if (cBox->view()->isVisible()) {
#if defined(Q_OS_ANDROID)
- const auto list = child(0)->tableInterface();
- if (list && list->selectedRowCount() > 0) {
- comboBox()->setCurrentIndex(list->selectedRows().at(0));
- }
- comboBox()->setFocus();
+ const auto list = child(0)->tableInterface();
+ if (list && list->selectedRowCount() > 0) {
+ cBox->setCurrentIndex(list->selectedRows().at(0));
+ }
+ cBox->setFocus();
#endif
- comboBox()->hidePopup();
- } else {
- comboBox()->showPopup();
+ cBox->hidePopup();
+ } else {
+ cBox->showPopup();
#if defined(Q_OS_ANDROID)
- const auto list = child(0)->tableInterface();
- if (list && list->selectedRowCount() > 0) {
- auto selectedCells = list->selectedCells();
- QAccessibleEvent ev(selectedCells.at(0),QAccessible::Focus);
- QAccessible::updateAccessibility(&ev);
- }
+ const auto list = child(0)->tableInterface();
+ if (list && list->selectedRowCount() > 0) {
+ auto selectedCells = list->selectedCells();
+ QAccessibleEvent ev(selectedCells.at(0),QAccessible::Focus);
+ QAccessible::updateAccessibility(&ev);
+ }
#endif
+ }
}
}
}
@@ -477,13 +555,19 @@ QWidgetList QAccessibleAbstractScrollArea::accessibleChildren() const
// Horizontal scrollBar container.
QScrollBar *horizontalScrollBar = abstractScrollArea()->horizontalScrollBar();
if (horizontalScrollBar && horizontalScrollBar->isVisible()) {
- children.append(horizontalScrollBar->parentWidget());
+ QWidget *scrollBarParent = horizontalScrollBar->parentWidget();
+ // Add container only if scroll bar is in the container
+ if (elementType(scrollBarParent) == HorizontalContainer)
+ children.append(scrollBarParent);
}
// Vertical scrollBar container.
QScrollBar *verticalScrollBar = abstractScrollArea()->verticalScrollBar();
if (verticalScrollBar && verticalScrollBar->isVisible()) {
- children.append(verticalScrollBar->parentWidget());
+ QWidget *scrollBarParent = verticalScrollBar->parentWidget();
+ // Add container only if scroll bar is in the container
+ if (elementType(scrollBarParent) == VerticalContainer)
+ children.append(scrollBarParent);
}
// CornerWidget.
diff --git a/src/widgets/accessible/complexwidgets_p.h b/src/widgets/accessible/complexwidgets_p.h
index 12535f21a0..5169aa8243 100644
--- a/src/widgets/accessible/complexwidgets_p.h
+++ b/src/widgets/accessible/complexwidgets_p.h
@@ -70,12 +70,14 @@ public:
#endif // QT_CONFIG(scrollarea)
#if QT_CONFIG(tabbar)
-class QAccessibleTabBar : public QAccessibleWidget
+class QAccessibleTabBar : public QAccessibleWidget, public QAccessibleSelectionInterface
{
public:
explicit QAccessibleTabBar(QWidget *w);
~QAccessibleTabBar();
+ void *interface_cast(QAccessible::InterfaceType t) override;
+
QAccessibleInterface *focusChild() const override;
int childCount() const override;
QString text(QAccessible::Text t) const override;
@@ -83,6 +85,16 @@ public:
QAccessibleInterface* child(int index) const override;
int indexOfChild(const QAccessibleInterface *child) const override;
+ // QAccessibleSelectionInterface
+ int selectedItemCount() const override;
+ QList<QAccessibleInterface*> selectedItems() const override;
+ QAccessibleInterface* selectedItem(int selectionIndex) const override;
+ bool isSelected(QAccessibleInterface *childItem) const override;
+ bool select(QAccessibleInterface *childItem) override;
+ bool unselect(QAccessibleInterface *childItem) override;
+ bool selectAll() override;
+ bool clear() override;
+
protected:
QTabBar *tabBar() const;
mutable QHash<int, QAccessible::Id> m_childInterfaces;
diff --git a/src/widgets/accessible/itemviews.cpp b/src/widgets/accessible/itemviews.cpp
index ae1de6cab4..aa5f729820 100644
--- a/src/widgets/accessible/itemviews.cpp
+++ b/src/widgets/accessible/itemviews.cpp
@@ -39,11 +39,16 @@ QAbstractItemView *QAccessibleTable::view() const
int QAccessibleTable::logicalIndex(const QModelIndex &index) const
{
- if (!view()->model() || !index.isValid())
+ const QAbstractItemView *theView = view();
+ const QAbstractItemModel *theModel = index.model();
+ if (!theModel || !index.isValid())
return -1;
- int vHeader = verticalHeader() ? 1 : 0;
- int hHeader = horizontalHeader() ? 1 : 0;
- return (index.row() + hHeader)*(index.model()->columnCount() + vHeader) + (index.column() + vHeader);
+
+ const QModelIndex rootIndex = theView->rootIndex();
+ const int vHeader = verticalHeader() ? 1 : 0;
+ const int hHeader = horizontalHeader() ? 1 : 0;
+ return (index.row() + hHeader) * (theModel->columnCount(rootIndex) + vHeader)
+ + (index.column() + vHeader);
}
QAccessibleTable::QAccessibleTable(QWidget *w)
@@ -113,12 +118,14 @@ QHeaderView *QAccessibleTable::verticalHeader() const
QAccessibleInterface *QAccessibleTable::cellAt(int row, int column) const
{
- if (!view()->model())
+ const QAbstractItemView *theView = view();
+ const QAbstractItemModel *theModel = theView->model();
+ if (!theModel)
return nullptr;
Q_ASSERT(role() != QAccessible::Tree);
- QModelIndex index = view()->model()->index(row, column, view()->rootIndex());
+ QModelIndex index = theModel->index(row, column, theView->rootIndex());
if (Q_UNLIKELY(!index.isValid())) {
- qWarning() << "QAccessibleTable::cellAt: invalid index: " << index << " for " << view();
+ qWarning() << "QAccessibleTable::cellAt: invalid index: " << index << " for " << theView;
return nullptr;
}
return child(logicalIndex(index));
@@ -131,23 +138,29 @@ QAccessibleInterface *QAccessibleTable::caption() const
QString QAccessibleTable::columnDescription(int column) const
{
- if (!view()->model())
+ const QAbstractItemView *theView = view();
+ const QAbstractItemModel *theModel = theView->model();
+ if (!theModel)
return QString();
- return view()->model()->headerData(column, Qt::Horizontal).toString();
+ return theModel->headerData(column, Qt::Horizontal).toString();
}
int QAccessibleTable::columnCount() const
{
- if (!view()->model())
+ const QAbstractItemView *theView = view();
+ const QAbstractItemModel *theModel = theView->model();
+ if (!theModel)
return 0;
- return view()->model()->columnCount();
+ return theModel->columnCount(theView->rootIndex());
}
int QAccessibleTable::rowCount() const
{
- if (!view()->model())
+ const QAbstractItemView *theView = view();
+ const QAbstractItemModel *theModel = theView->model();
+ if (!theModel)
return 0;
- return view()->model()->rowCount();
+ return theModel->rowCount(theView->rootIndex());
}
int QAccessibleTable::selectedCellCount() const
@@ -173,9 +186,11 @@ int QAccessibleTable::selectedRowCount() const
QString QAccessibleTable::rowDescription(int row) const
{
- if (!view()->model())
+ const QAbstractItemView *theView = view();
+ const QAbstractItemModel *theModel = theView->model();
+ if (!theModel)
return QString();
- return view()->model()->headerData(row, Qt::Vertical).toString();
+ return theModel->headerData(row, Qt::Vertical).toString();
}
QList<QAccessibleInterface *> QAccessibleTable::selectedCells() const
@@ -237,9 +252,13 @@ bool QAccessibleTable::isRowSelected(int row) const
bool QAccessibleTable::selectRow(int row)
{
- if (!view()->model() || !view()->selectionModel())
+ QAbstractItemView *theView = view();
+ const QAbstractItemModel *theModel = theView->model();
+ if (!theModel || !view()->selectionModel())
return false;
- QModelIndex index = view()->model()->index(row, 0, view()->rootIndex());
+
+ const QModelIndex rootIndex = theView->rootIndex();
+ const QModelIndex index = theModel->index(row, 0, rootIndex);
if (!index.isValid() || view()->selectionBehavior() == QAbstractItemView::SelectColumns)
return false;
@@ -253,9 +272,10 @@ bool QAccessibleTable::selectRow(int row)
view()->clearSelection();
break;
case QAbstractItemView::ContiguousSelection:
- if ((!row || !view()->selectionModel()->isRowSelected(row - 1, view()->rootIndex()))
- && !view()->selectionModel()->isRowSelected(row + 1, view()->rootIndex()))
- view()->clearSelection();
+ if ((!row || !theView->selectionModel()->isRowSelected(row - 1, rootIndex))
+ && !theView->selectionModel()->isRowSelected(row + 1, rootIndex)) {
+ theView->clearSelection();
+ }
break;
default:
break;
@@ -267,45 +287,55 @@ bool QAccessibleTable::selectRow(int row)
bool QAccessibleTable::selectColumn(int column)
{
- if (!view()->model() || !view()->selectionModel())
+ QAbstractItemView *theView = view();
+ const QAbstractItemModel *theModel = theView->model();
+ auto *selectionModel = theView->selectionModel();
+ if (!theModel || !selectionModel)
return false;
- QModelIndex index = view()->model()->index(0, column, view()->rootIndex());
+
+ const QModelIndex rootIndex = theView->rootIndex();
+ const QModelIndex index = theModel->index(0, column, rootIndex);
if (!index.isValid() || view()->selectionBehavior() == QAbstractItemView::SelectRows)
return false;
- switch (view()->selectionMode()) {
+ switch (theView->selectionMode()) {
case QAbstractItemView::NoSelection:
return false;
case QAbstractItemView::SingleSelection:
- if (view()->selectionBehavior() != QAbstractItemView::SelectColumns && rowCount() > 1)
+ if (theView->selectionBehavior() != QAbstractItemView::SelectColumns && rowCount() > 1)
return false;
Q_FALLTHROUGH();
case QAbstractItemView::ContiguousSelection:
- if ((!column || !view()->selectionModel()->isColumnSelected(column - 1, view()->rootIndex()))
- && !view()->selectionModel()->isColumnSelected(column + 1, view()->rootIndex()))
- view()->clearSelection();
+ if ((!column || !selectionModel->isColumnSelected(column - 1, rootIndex))
+ && !selectionModel->isColumnSelected(column + 1, rootIndex)) {
+ theView->clearSelection();
+ }
break;
default:
break;
}
- view()->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Columns);
+ selectionModel->select(index, QItemSelectionModel::Select | QItemSelectionModel::Columns);
return true;
}
bool QAccessibleTable::unselectRow(int row)
{
- if (!view()->model() || !view()->selectionModel())
+ const QAbstractItemView *theView = view();
+ const QAbstractItemModel *theModel = theView->model();
+ auto *selectionModel = theView->selectionModel();
+ if (!theModel || !selectionModel)
return false;
- QModelIndex index = view()->model()->index(row, 0, view()->rootIndex());
+ const QModelIndex rootIndex = theView->rootIndex();
+ const QModelIndex index = view()->model()->index(row, 0, rootIndex);
if (!index.isValid())
return false;
QItemSelection selection(index, index);
- switch (view()->selectionMode()) {
+ switch (theView->selectionMode()) {
case QAbstractItemView::SingleSelection:
//In SingleSelection and ContiguousSelection once an item
//is selected, there's no way for the user to unselect all items
@@ -316,26 +346,31 @@ bool QAccessibleTable::unselectRow(int row)
if (selectedRowCount() == 1)
return false;
- if ((!row || view()->selectionModel()->isRowSelected(row - 1, view()->rootIndex()))
- && view()->selectionModel()->isRowSelected(row + 1, view()->rootIndex())) {
+ if ((!row || selectionModel->isRowSelected(row - 1, rootIndex))
+ && selectionModel->isRowSelected(row + 1, rootIndex)) {
//If there are rows selected both up the current row and down the current rown,
//the ones which are down the current row will be deselected
- selection = QItemSelection(index, view()->model()->index(rowCount() - 1, 0, view()->rootIndex()));
+ selection = QItemSelection(index, theModel->index(rowCount() - 1, 0, rootIndex));
}
+ break;
default:
break;
}
- view()->selectionModel()->select(selection, QItemSelectionModel::Deselect | QItemSelectionModel::Rows);
+ selectionModel->select(selection, QItemSelectionModel::Deselect | QItemSelectionModel::Rows);
return true;
}
bool QAccessibleTable::unselectColumn(int column)
{
- if (!view()->model() || !view()->selectionModel())
+ const QAbstractItemView *theView = view();
+ const QAbstractItemModel *theModel = theView->model();
+ auto *selectionModel = theView->selectionModel();
+ if (!theModel || !selectionModel)
return false;
- QModelIndex index = view()->model()->index(0, column, view()->rootIndex());
+ const QModelIndex rootIndex = theView->rootIndex();
+ const QModelIndex index = view()->model()->index(0, column, rootIndex);
if (!index.isValid())
return false;
@@ -352,17 +387,18 @@ bool QAccessibleTable::unselectColumn(int column)
if (selectedColumnCount() == 1)
return false;
- if ((!column || view()->selectionModel()->isColumnSelected(column - 1, view()->rootIndex()))
- && view()->selectionModel()->isColumnSelected(column + 1, view()->rootIndex())) {
+ if ((!column || selectionModel->isColumnSelected(column - 1, rootIndex))
+ && selectionModel->isColumnSelected(column + 1, rootIndex)) {
//If there are columns selected both at the left of the current row and at the right
//of the current rown, the ones which are at the right will be deselected
- selection = QItemSelection(index, view()->model()->index(0, columnCount() - 1, view()->rootIndex()));
+ selection = QItemSelection(index, theModel->index(0, columnCount() - 1, rootIndex));
}
+ break;
default:
break;
}
- view()->selectionModel()->select(selection, QItemSelectionModel::Deselect | QItemSelectionModel::Columns);
+ selectionModel->select(selection, QItemSelectionModel::Deselect | QItemSelectionModel::Columns);
return true;
}
@@ -481,10 +517,9 @@ QAccessibleInterface *QAccessibleTable::childAt(int x, int y) const
QPoint indexPosition = view()->mapFromGlobal(QPoint(x, y) - viewportOffset);
// FIXME: if indexPosition < 0 in one coordinate, return header
- QModelIndex index = view()->indexAt(indexPosition);
- if (index.isValid()) {
+ const QModelIndex index = view()->indexAt(indexPosition);
+ if (index.isValid())
return child(logicalIndex(index));
- }
return nullptr;
}
@@ -499,21 +534,27 @@ QAccessibleInterface *QAccessibleTable::focusChild() const
int QAccessibleTable::childCount() const
{
- if (!view()->model())
+ const QAbstractItemView *theView = view();
+ const QAbstractItemModel *theModel = theView->model();
+ if (!theModel)
return 0;
+ const QModelIndex rootIndex = theView->rootIndex();
int vHeader = verticalHeader() ? 1 : 0;
int hHeader = horizontalHeader() ? 1 : 0;
- return (view()->model()->rowCount()+hHeader) * (view()->model()->columnCount()+vHeader);
+ return (theModel->rowCount(rootIndex) + hHeader) * (theModel->columnCount(rootIndex) + vHeader);
}
int QAccessibleTable::indexOfChild(const QAccessibleInterface *iface) const
{
- if (!view()->model())
+ const QAbstractItemView *theView = view();
+ const QAbstractItemModel *theModel = theView->model();
+ if (!theModel)
return -1;
QAccessibleInterface *parent = iface->parent();
- if (parent->object() != view())
+ if (parent->object() != theView)
return -1;
+ const QModelIndex rootIndex = theView->rootIndex();
Q_ASSERT(iface->role() != QAccessible::TreeItem); // should be handled by tree class
if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) {
const QAccessibleTableCell* cell = static_cast<const QAccessibleTableCell*>(iface);
@@ -523,7 +564,7 @@ int QAccessibleTable::indexOfChild(const QAccessibleInterface *iface) const
return cell->index + (verticalHeader() ? 1 : 0);
} else if (iface->role() == QAccessible::RowHeader){
const QAccessibleTableHeaderCell* cell = static_cast<const QAccessibleTableHeaderCell*>(iface);
- return (cell->index + 1) * (view()->model()->columnCount() + 1);
+ return (cell->index + 1) * (theModel->columnCount(rootIndex) + 1);
} else if (iface->role() == QAccessible::Pane) {
return 0; // corner button
} else {
@@ -557,14 +598,17 @@ QAccessibleInterface *QAccessibleTable::parent() const
}
return QAccessible::queryAccessibleInterface(view()->parent());
}
- return nullptr;
+ return QAccessible::queryAccessibleInterface(qApp);
}
QAccessibleInterface *QAccessibleTable::child(int logicalIndex) const
{
- if (!view()->model())
+ QAbstractItemView *theView = view();
+ const QAbstractItemModel *theModel = theView->model();
+ if (!theModel)
return nullptr;
+ const QModelIndex rootIndex = theView->rootIndex();
auto id = childToId.constFind(logicalIndex);
if (id != childToId.constEnd())
return QAccessible::accessibleInterface(id.value());
@@ -572,7 +616,7 @@ QAccessibleInterface *QAccessibleTable::child(int logicalIndex) const
int vHeader = verticalHeader() ? 1 : 0;
int hHeader = horizontalHeader() ? 1 : 0;
- int columns = view()->model()->columnCount() + vHeader;
+ int columns = theModel->columnCount(rootIndex) + vHeader;
int row = logicalIndex / columns;
int column = logicalIndex % columns;
@@ -582,27 +626,27 @@ QAccessibleInterface *QAccessibleTable::child(int logicalIndex) const
if (vHeader) {
if (column == 0) {
if (hHeader && row == 0) {
- iface = new QAccessibleTableCornerButton(view());
+ iface = new QAccessibleTableCornerButton(theView);
} else {
- iface = new QAccessibleTableHeaderCell(view(), row - hHeader, Qt::Vertical);
+ iface = new QAccessibleTableHeaderCell(theView, row - hHeader, Qt::Vertical);
}
}
--column;
}
if (!iface && hHeader) {
if (row == 0) {
- iface = new QAccessibleTableHeaderCell(view(), column, Qt::Horizontal);
+ iface = new QAccessibleTableHeaderCell(theView, column, Qt::Horizontal);
}
--row;
}
if (!iface) {
- QModelIndex index = view()->model()->index(row, column, view()->rootIndex());
+ QModelIndex index = theModel->index(row, column, rootIndex);
if (Q_UNLIKELY(!index.isValid())) {
qWarning("QAccessibleTable::child: Invalid index at: %d %d", row, column);
return nullptr;
}
- iface = new QAccessibleTableCell(view(), index, cellRole());
+ iface = new QAccessibleTableCell(theView, index, cellRole());
}
QAccessible::registerAccessibleInterface(iface);
@@ -749,34 +793,39 @@ QModelIndex QAccessibleTree::indexFromLogical(int row, int column) const
QAccessibleInterface *QAccessibleTree::childAt(int x, int y) const
{
- if (!view()->model())
+ const QAbstractItemView *theView = view();
+ const QAbstractItemModel *theModel = theView->model();
+ if (!theModel)
return nullptr;
- QPoint viewportOffset = view()->viewport()->mapTo(view(), QPoint(0,0));
- QPoint indexPosition = view()->mapFromGlobal(QPoint(x, y) - viewportOffset);
- QModelIndex index = view()->indexAt(indexPosition);
+ const QPoint viewportOffset = theView->viewport()->mapTo(view(), QPoint(0, 0));
+ const QPoint indexPosition = theView->mapFromGlobal(QPoint(x, y) - viewportOffset);
+
+ const QModelIndex index = theView->indexAt(indexPosition);
if (!index.isValid())
return nullptr;
- const QTreeView *treeView = qobject_cast<const QTreeView*>(view());
+ const QTreeView *treeView = qobject_cast<const QTreeView *>(theView);
int row = treeView->d_func()->viewIndex(index) + (horizontalHeader() ? 1 : 0);
int column = index.column();
- int i = row * view()->model()->columnCount() + column;
+ int i = row * theModel->columnCount(theView->rootIndex()) + column;
return child(i);
}
QAccessibleInterface *QAccessibleTree::focusChild() const
{
- QModelIndex index = view()->currentIndex();
+ const QAbstractItemView *theView = view();
+ const QAbstractItemModel *theModel = theView->model();
+ const QModelIndex index = theView->currentIndex();
if (!index.isValid())
return nullptr;
- const QTreeView *treeView = qobject_cast<const QTreeView*>(view());
- int row = treeView->d_func()->viewIndex(index) + (horizontalHeader() ? 1 : 0);
- int column = index.column();
+ const QTreeView *treeView = qobject_cast<const QTreeView *>(theView);
+ const int row = treeView->d_func()->viewIndex(index) + (horizontalHeader() ? 1 : 0);
+ const int column = index.column();
- int i = row * view()->model()->columnCount() + column;
+ int i = row * theModel->columnCount(theView->rootIndex()) + column;
return child(i);
}
@@ -784,33 +833,37 @@ int QAccessibleTree::childCount() const
{
const QTreeView *treeView = qobject_cast<const QTreeView*>(view());
Q_ASSERT(treeView);
- if (!view()->model())
+ const QAbstractItemModel *theModel = treeView->model();
+ if (!theModel)
return 0;
int hHeader = horizontalHeader() ? 1 : 0;
- return (treeView->d_func()->viewItems.size() + hHeader)* view()->model()->columnCount();
+ return (treeView->d_func()->viewItems.size() + hHeader)
+ * theModel->columnCount(treeView->rootIndex());
}
QAccessibleInterface *QAccessibleTree::child(int logicalIndex) const
{
- if (logicalIndex < 0 || !view()->model() || !view()->model()->columnCount())
+ const QAbstractItemView *theView = view();
+ const QAbstractItemModel *theModel = theView->model();
+ const QModelIndex rootIndex = theView->rootIndex();
+ if (logicalIndex < 0 || !theModel || !theModel->columnCount(rootIndex))
return nullptr;
QAccessibleInterface *iface = nullptr;
int index = logicalIndex;
if (horizontalHeader()) {
- if (index < view()->model()->columnCount()) {
+ if (index < theModel->columnCount(rootIndex))
iface = new QAccessibleTableHeaderCell(view(), index, Qt::Horizontal);
- } else {
- index -= view()->model()->columnCount();
- }
+ else
+ index -= theModel->columnCount(rootIndex);
}
if (!iface) {
- int row = index / view()->model()->columnCount();
- int column = index % view()->model()->columnCount();
- QModelIndex modelIndex = indexFromLogical(row, column);
+ const int row = index / theModel->columnCount(rootIndex);
+ const int column = index % theModel->columnCount(rootIndex);
+ const QModelIndex modelIndex = indexFromLogical(row, column);
if (!modelIndex.isValid())
return nullptr;
iface = new QAccessibleTableCell(view(), modelIndex, cellRole());
@@ -829,7 +882,9 @@ int QAccessibleTree::rowCount() const
int QAccessibleTree::indexOfChild(const QAccessibleInterface *iface) const
{
- if (!view()->model())
+ const QAbstractItemView *theView = view();
+ const QAbstractItemModel *theModel = theView->model();
+ if (!theModel)
return -1;
QAccessibleInterface *parent = iface->parent();
if (parent->object() != view())
@@ -837,12 +892,12 @@ int QAccessibleTree::indexOfChild(const QAccessibleInterface *iface) const
if (iface->role() == QAccessible::TreeItem) {
const QAccessibleTableCell* cell = static_cast<const QAccessibleTableCell*>(iface);
- const QTreeView *treeView = qobject_cast<const QTreeView*>(view());
+ const QTreeView *treeView = qobject_cast<const QTreeView *>(theView);
Q_ASSERT(treeView);
int row = treeView->d_func()->viewIndex(cell->m_index) + (horizontalHeader() ? 1 : 0);
int column = cell->m_index.column();
- int index = row * view()->model()->columnCount() + column;
+ int index = row * theModel->columnCount(theView->rootIndex()) + column;
return index;
} else if (iface->role() == QAccessible::ColumnHeader){
const QAccessibleTableHeaderCell* cell = static_cast<const QAccessibleTableHeaderCell*>(iface);
@@ -1299,9 +1354,14 @@ void QAccessibleTableHeaderCell::setText(QAccessible::Text, const QString &)
bool QAccessibleTableHeaderCell::isValid() const
{
- return view && !qt_widget_private(view)->data.in_destructor
- && view->model() && (index >= 0)
- && ((orientation == Qt::Horizontal) ? (index < view->model()->columnCount()) : (index < view->model()->rowCount()));
+ const QAbstractItemModel *theModel = view && !qt_widget_private(view)->data.in_destructor
+ ? view->model() : nullptr;
+ if (!theModel)
+ return false;
+ const QModelIndex rootIndex = view->rootIndex();
+ return (index >= 0) && ((orientation == Qt::Horizontal)
+ ? (index < theModel->columnCount(rootIndex))
+ : (index < theModel->rowCount(rootIndex)));
}
QAccessibleInterface *QAccessibleTableHeaderCell::parent() const
diff --git a/src/widgets/accessible/itemviews_p.h b/src/widgets/accessible/itemviews_p.h
index ddc97baba1..077f14de1d 100644
--- a/src/widgets/accessible/itemviews_p.h
+++ b/src/widgets/accessible/itemviews_p.h
@@ -144,8 +144,6 @@ public:
private:
QModelIndex indexFromLogical(int row, int column = 0) const;
-
- inline int logicalIndex(const QModelIndex &index) const;
};
#endif
diff --git a/src/widgets/accessible/qaccessiblewidgetfactory.cpp b/src/widgets/accessible/qaccessiblewidgetfactory.cpp
index e13b7ebcf7..664e35a6e7 100644
--- a/src/widgets/accessible/qaccessiblewidgetfactory.cpp
+++ b/src/widgets/accessible/qaccessiblewidgetfactory.cpp
@@ -121,7 +121,6 @@ QAccessibleInterface *qAccessibleFactory(const QString &classname, QObject *obje
#if QT_CONFIG(itemviews)
} else if (classname == "QTableView"_L1 || classname == "QListView"_L1) {
iface = new QAccessibleTable(widget);
- // ### This should be cleaned up. We return the parent for the scrollarea to hide it.
#endif // QT_CONFIG(itemviews)
#if QT_CONFIG(tabbar)
} else if (classname == "QTabBar"_L1) {
diff --git a/src/widgets/accessible/qaccessiblewidgets.cpp b/src/widgets/accessible/qaccessiblewidgets.cpp
index ad41df3685..5c2a3bd02b 100644
--- a/src/widgets/accessible/qaccessiblewidgets.cpp
+++ b/src/widgets/accessible/qaccessiblewidgets.cpp
@@ -95,7 +95,7 @@ QWidgetList _q_ac_childWidgets(const QWidget *widget)
QAccessiblePlainTextEdit::QAccessiblePlainTextEdit(QWidget* o)
:QAccessibleTextWidget(o)
{
- Q_ASSERT(widget()->inherits("QPlainTextEdit"));
+ Q_ASSERT(qobject_cast<QPlainTextEdit *>(widget()));
}
QPlainTextEdit* QAccessiblePlainTextEdit::plainTextEdit() const
@@ -192,7 +192,7 @@ void QAccessiblePlainTextEdit::scrollToSubstring(int startIndex, int endIndex)
QAccessibleTextEdit::QAccessibleTextEdit(QWidget *o)
: QAccessibleTextWidget(o, QAccessible::EditableText)
{
- Q_ASSERT(widget()->inherits("QTextEdit"));
+ Q_ASSERT(qobject_cast<QTextEdit *>(widget()));
}
/*! Returns the text edit. */
@@ -839,6 +839,8 @@ QString QAccessibleTextWidget::attributes(int offset, int *startOffset, int *end
QFont::Style style = charFormatFont.style();
attrs["font-style"] = QString::fromLatin1((style == QFont::StyleItalic) ? "italic" : ((style == QFont::StyleOblique) ? "oblique": "normal"));
+ attrs["text-line-through-type"] = charFormatFont.strikeOut() ? "single"_L1 : "none"_L1;
+
QTextCharFormat::UnderlineStyle underlineStyle = charFormat.underlineStyle();
if (underlineStyle == QTextCharFormat::NoUnderline && charFormatFont.underline()) // underline could still be set in the default font
underlineStyle = QTextCharFormat::SingleUnderline;
@@ -868,7 +870,7 @@ QString QAccessibleTextWidget::attributes(int offset, int *startOffset, int *end
underlineStyleValue = QStringLiteral("wave"); // this is not correct, but provides good approximation at least
break;
default:
- qWarning() << "Unknown QTextCharFormat::​UnderlineStyle value " << underlineStyle << " could not be translated to IAccessible2 value";
+ qWarning() << "Unknown QTextCharFormat::UnderlineStyle value " << underlineStyle << " could not be translated to IAccessible2 value";
break;
}
if (!underlineStyleValue.isNull()) {
diff --git a/src/widgets/accessible/qaccessiblewidgets_p.h b/src/widgets/accessible/qaccessiblewidgets_p.h
index 69bd84ea23..6d06f294e8 100644
--- a/src/widgets/accessible/qaccessiblewidgets_p.h
+++ b/src/widgets/accessible/qaccessiblewidgets_p.h
@@ -21,7 +21,6 @@
#if QT_CONFIG(accessibility)
#include <QtCore/QPointer>
-#include <QtCore/QPair>
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/compat/removed_api.cpp b/src/widgets/compat/removed_api.cpp
index 691cc2cc7f..5fcbdba47b 100644
--- a/src/widgets/compat/removed_api.cpp
+++ b/src/widgets/compat/removed_api.cpp
@@ -78,7 +78,26 @@ QAction *QMenuBar::addAction(const QString &text, const QObject *receiver, const
}
#endif
+#endif // QT_WIDGETS_REMOVED_SINCE(6, 3)
+
+#if QT_WIDGETS_REMOVED_SINCE(6, 7)
+
+
+#if QT_CONFIG(filedialog)
+#include "qfiledialog.h"
+
+void QFileDialog::getOpenFileContent(const QString &nameFilter, const std::function<void(const QString &, const QByteArray &)> &fileOpenCompleted)
+{
+ QFileDialog::getOpenFileContent(nameFilter, fileOpenCompleted, nullptr);
+}
+
+void QFileDialog::saveFileContent(const QByteArray &fileContent, const QString &fileNameHint)
+{
+ saveFileContent(fileContent, fileNameHint, nullptr);
+}
+#endif
+
// #include <qotherheader.h>
// // implement removed functions from qotherheader.h
-#endif // QT_WIDGETS_REMOVED_SINCE(6, 3)
+#endif // QT_WIDGETS_REMOVED_SINCE(6, 7)
diff --git a/src/widgets/configure.cmake b/src/widgets/configure.cmake
index f71ebef9d9..745f2d1152 100644
--- a/src/widgets/configure.cmake
+++ b/src/widgets/configure.cmake
@@ -37,6 +37,10 @@ qt_feature("style-windowsvista" PRIVATE
LABEL "WindowsVista"
CONDITION QT_FEATURE_style_windows AND QT_FEATURE_animation AND WIN32
)
+qt_feature("style-windows11" PRIVATE
+ LABEL "Windows11"
+ CONDITION QT_FEATURE_style_windows AND QT_FEATURE_animation AND WIN32
+)
qt_feature("style-android" PRIVATE
LABEL "Android"
AUTODETECT ANDROID
diff --git a/src/widgets/dialogs/images/qtlogo-64.png b/src/widgets/dialogs/images/qtlogo-64.png
index 39a4a26f39..e40b5c6fc8 100644
--- a/src/widgets/dialogs/images/qtlogo-64.png
+++ b/src/widgets/dialogs/images/qtlogo-64.png
Binary files differ
diff --git a/src/widgets/dialogs/qcolordialog.cpp b/src/widgets/dialogs/qcolordialog.cpp
index 1bb65e6c24..22efecedc9 100644
--- a/src/widgets/dialogs/qcolordialog.cpp
+++ b/src/widgets/dialogs/qcolordialog.cpp
@@ -43,6 +43,8 @@
#include <qpa/qplatformservices.h>
#include <private/qguiapplication_p.h>
+#include <QtCore/qpointer.h>
+
#include <algorithm>
QT_BEGIN_NAMESPACE
@@ -102,16 +104,16 @@ public:
void retranslateStrings();
bool supportsColorPicking() const;
- void _q_addCustom();
+ void addCustom();
void _q_setCustom(int index, QRgb color);
- void _q_newHsv(int h, int s, int v);
- void _q_newColorTypedIn(QRgb rgb);
- void _q_nextCustom(int, int);
- void _q_newCustom(int, int);
- void _q_newStandard(int, int);
- void _q_pickScreenColor();
- void _q_updateColorPicking();
+ void newHsv(int h, int s, int v);
+ void newColorTypedIn(QRgb rgb);
+ void nextCustom(int, int);
+ void newCustom(int, int);
+ void newStandard(int, int);
+ void pickScreenColor();
+ void updateColorPicking();
void updateColorLabelText(const QPoint &);
void updateColorPicking(const QPoint &pos);
void releaseColorPicking();
@@ -120,6 +122,7 @@ public:
bool handleColorPickingKeyPress(QKeyEvent *e);
bool canBeNativeDialog() const override;
+ void setVisible(bool visible) override;
QWellArray *custom;
QWellArray *standard;
@@ -135,7 +138,7 @@ public:
QPushButton *ok;
QPushButton *cancel;
QPushButton *addCusBt;
- QPushButton *screenColorPickerButton;
+ QPushButton *eyeDropperButton = nullptr;
QColor selectedQColor;
int nextCust;
bool smallDisplay;
@@ -322,7 +325,7 @@ void QWellArray::paintCell(QPainter* p, int row, int col, const QRect &rect)
const QPalette & g = palette();
QStyleOptionFrame opt;
opt.initFrom(this);
- int dfw = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt);
+ int dfw = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &opt, this);
opt.lineWidth = dfw;
opt.midLineWidth = 1;
opt.rect = rect.adjusted(b, b, -b, -b);
@@ -780,6 +783,10 @@ QColorLuminancePicker::~QColorLuminancePicker()
void QColorLuminancePicker::mouseMoveEvent(QMouseEvent *m)
{
+ if (m->buttons() == Qt::NoButton) {
+ m->ignore();
+ return;
+ }
setVal(y2val(m->position().toPoint().y()));
}
void QColorLuminancePicker::mousePressEvent(QMouseEvent *m)
@@ -829,11 +836,10 @@ void QColorLuminancePicker::paintEvent(QPaintEvent *)
qDrawShadePanel(&p, r, g, true);
p.setPen(g.windowText().color());
p.setBrush(g.windowText());
- QPolygon a;
- int y = val2y(val);
- a.setPoints(3, w, y, w+5, y+5, w+5, y-5);
p.eraseRect(w, 0, 5, height());
- p.drawPolygon(a);
+ const int y = val2y(val);
+ const std::array<QPoint, 3> points = {QPoint(w, y), QPoint(w + 5, y + 5), QPoint(w + 5, y - 5)};
+ p.drawPolygon(points.data(), static_cast<int>(points.size()));
}
void QColorLuminancePicker::setCol(int h, int s , int v)
@@ -914,6 +920,10 @@ void QColorPicker::setCol(int h, int s)
void QColorPicker::mouseMoveEvent(QMouseEvent *m)
{
QPoint p = m->position().toPoint() - contentsRect().topLeft();
+ if (m->buttons() == Qt::NoButton) {
+ m->ignore();
+ return;
+ }
setCol(p);
emit newCol(hue, sat);
}
@@ -1316,7 +1326,7 @@ QColorShower::QColorShower(QColorDialog *parent)
connect(gEd, &QSpinBox::valueChanged, this, &QColorShower::rgbEd);
connect(bEd, &QSpinBox::valueChanged, this, &QColorShower::rgbEd);
connect(alphaEd, &QSpinBox::valueChanged, this, &QColorShower::rgbEd);
- connect(htEd, &QLineEdit::textChanged, this, &QColorShower::htmlEd);
+ connect(htEd, &QLineEdit::textEdited, this, &QColorShower::htmlEd);
retranslateStrings();
}
@@ -1388,8 +1398,8 @@ void QColorShower::htmlEd()
if (t.isEmpty())
return;
- if (!t.startsWith(QStringLiteral("#"))) {
- t = QStringLiteral("#") + t;
+ if (!t.startsWith(u"#")) {
+ t.prepend(u"#");
QSignalBlocker blocker(htEd);
htEd->setText(t);
}
@@ -1481,7 +1491,7 @@ void QColorShower::updateQColor()
}
//sets all widgets to display h,s,v
-void QColorDialogPrivate::_q_newHsv(int h, int s, int v)
+void QColorDialogPrivate::newHsv(int h, int s, int v)
{
if (!nativeDialogInUse) {
cs->setHsv(h, s, v);
@@ -1495,7 +1505,7 @@ void QColorDialogPrivate::setCurrentRgbColor(QRgb rgb)
{
if (!nativeDialogInUse) {
cs->setRgb(rgb);
- _q_newColorTypedIn(rgb);
+ newColorTypedIn(rgb);
}
}
@@ -1528,7 +1538,7 @@ bool QColorDialogPrivate::selectColor(const QColor &col)
const int index = int(match - standardColors);
const int column = index / standardColorRows;
const int row = index % standardColorRows;
- _q_newStandard(row, column);
+ newStandard(row, column);
standard->setCurrent(row, column);
standard->setSelected(row, column);
standard->setFocus();
@@ -1544,7 +1554,7 @@ bool QColorDialogPrivate::selectColor(const QColor &col)
const int index = int(match - customColors);
const int column = index / customColorRows;
const int row = index % customColorRows;
- _q_newCustom(row, column);
+ newCustom(row, column);
custom->setCurrent(row, column);
custom->setSelected(row, column);
custom->setFocus();
@@ -1567,7 +1577,7 @@ QColor QColorDialogPrivate::grabScreenColor(const QPoint &p)
}
//sets all widgets except cs to display rgb
-void QColorDialogPrivate::_q_newColorTypedIn(QRgb rgb)
+void QColorDialogPrivate::newColorTypedIn(QRgb rgb)
{
if (!nativeDialogInUse) {
int h, s, v;
@@ -1577,12 +1587,12 @@ void QColorDialogPrivate::_q_newColorTypedIn(QRgb rgb)
}
}
-void QColorDialogPrivate::_q_nextCustom(int r, int c)
+void QColorDialogPrivate::nextCustom(int r, int c)
{
nextCust = r + customColorRows * c;
}
-void QColorDialogPrivate::_q_newCustom(int r, int c)
+void QColorDialogPrivate::newCustom(int r, int c)
{
const int i = r + customColorRows * c;
setCurrentRgbColor(QColorDialogOptions::customColor(i));
@@ -1590,14 +1600,14 @@ void QColorDialogPrivate::_q_newCustom(int r, int c)
standard->setSelected(-1,-1);
}
-void QColorDialogPrivate::_q_newStandard(int r, int c)
+void QColorDialogPrivate::newStandard(int r, int c)
{
setCurrentRgbColor(QColorDialogOptions::standardColor(r + c * 6));
if (custom)
custom->setSelected(-1,-1);
}
-void QColorDialogPrivate::_q_pickScreenColor()
+void QColorDialogPrivate::pickScreenColor()
{
Q_Q(QColorDialog);
@@ -1642,8 +1652,8 @@ void QColorDialogPrivate::_q_pickScreenColor()
addCusBt->setDisabled(true);
buttons->setDisabled(true);
- if (screenColorPickerButton) {
- screenColorPickerButton->setDisabled(true);
+ if (eyeDropperButton) {
+ eyeDropperButton->setDisabled(true);
const QPoint globalPos = QCursor::pos();
q->setCurrentColor(grabScreenColor(globalPos));
updateColorLabelText(globalPos);
@@ -1673,7 +1683,7 @@ void QColorDialogPrivate::releaseColorPicking()
lblScreenColorInfo->setText("\n"_L1);
addCusBt->setDisabled(false);
buttons->setDisabled(false);
- screenColorPickerButton->setDisabled(false);
+ eyeDropperButton->setDisabled(false);
}
void QColorDialogPrivate::init(const QColor &initial)
@@ -1730,19 +1740,21 @@ void QColorDialogPrivate::initWidgets()
#ifndef QT_NO_SHORTCUT
lblBasicColors->setBuddy(standard);
#endif
- q->connect(standard, SIGNAL(selected(int,int)), SLOT(_q_newStandard(int,int)));
+ QObjectPrivate::connect(standard, &QColorWell::selected,
+ this, &QColorDialogPrivate::newStandard);
leftLay->addWidget(lblBasicColors);
leftLay->addWidget(standard);
#if !defined(QT_SMALL_COLORDIALOG)
if (supportsColorPicking()) {
- screenColorPickerButton = new QPushButton();
- leftLay->addWidget(screenColorPickerButton);
+ eyeDropperButton = new QPushButton();
+ leftLay->addWidget(eyeDropperButton);
lblScreenColorInfo = new QLabel("\n"_L1);
leftLay->addWidget(lblScreenColorInfo);
- q->connect(screenColorPickerButton, SIGNAL(clicked()), SLOT(_q_pickScreenColor()));
+ QObjectPrivate::connect(eyeDropperButton, &QPushButton::clicked,
+ this, &QColorDialogPrivate::pickScreenColor);
} else {
- screenColorPickerButton = nullptr;
+ eyeDropperButton = nullptr;
lblScreenColorInfo = nullptr;
}
#endif
@@ -1752,10 +1764,10 @@ void QColorDialogPrivate::initWidgets()
custom = new QColorWell(q, customColorRows, colorColumns, QColorDialogOptions::customColors());
custom->setAcceptDrops(true);
- q->connect(custom, SIGNAL(selected(int,int)), SLOT(_q_newCustom(int,int)));
- q->connect(custom, SIGNAL(currentChanged(int,int)), SLOT(_q_nextCustom(int,int)));
+ QObjectPrivate::connect(custom, &QColorWell::selected, this, &QColorDialogPrivate::newCustom);
+ QObjectPrivate::connect(custom, &QColorWell::currentChanged, this, &QColorDialogPrivate::nextCustom);
- q->connect(custom, &QWellArray::colorChanged, [this] (int index, QRgb color) {
+ QObject::connect(custom, &QWellArray::colorChanged, q, [this] (int index, QRgb color) {
QColorDialogOptions::setCustomColor(index, color);
if (custom)
custom->update();
@@ -1769,7 +1781,7 @@ void QColorDialogPrivate::initWidgets()
leftLay->addWidget(custom);
addCusBt = new QPushButton(q);
- QObject::connect(addCusBt, SIGNAL(clicked()), q, SLOT(_q_addCustom()));
+ QObjectPrivate::connect(addCusBt, &QPushButton::clicked, this, &QColorDialogPrivate::addCustom);
leftLay->addWidget(addCusBt);
} else {
// better color picker size for small displays
@@ -1817,16 +1829,17 @@ void QColorDialogPrivate::initWidgets()
pickLay->addStretch();
#endif
- QObject::connect(cp, SIGNAL(newCol(int,int)), lp, SLOT(setCol(int,int)));
- QObject::connect(lp, SIGNAL(newHsv(int,int,int)), q, SLOT(_q_newHsv(int,int,int)));
+ QObject::connect(cp, &QColorPicker::newCol, lp, qOverload<int, int>(&QColorLuminancePicker::setCol));
+ QObjectPrivate::connect(lp, &QColorLuminancePicker::newHsv, this, &QColorDialogPrivate::newHsv);
rightLay->addStretch();
cs = new QColorShower(q);
pickLay->setContentsMargins(cs->gl->contentsMargins());
- QObject::connect(cs, SIGNAL(newCol(QRgb)), q, SLOT(_q_newColorTypedIn(QRgb)));
- QObject::connect(cs, SIGNAL(currentColorChanged(QColor)),
- q, SIGNAL(currentColorChanged(QColor)));
+ QObjectPrivate::connect(cs, &QColorShower::newCol,
+ this, &QColorDialogPrivate::newColorTypedIn);
+ QObject::connect(cs, &QColorShower::currentColorChanged,
+ q, &QColorDialog::currentColorChanged);
#if defined(QT_SMALL_COLORDIALOG)
topLay->addWidget(cs);
#else
@@ -1839,14 +1852,15 @@ void QColorDialogPrivate::initWidgets()
mainLay->addWidget(buttons);
ok = buttons->addButton(QDialogButtonBox::Ok);
- QObject::connect(ok, SIGNAL(clicked()), q, SLOT(accept()));
+ QObject::connect(ok, &QPushButton::clicked, q, &QColorDialog::accept);
ok->setDefault(true);
cancel = buttons->addButton(QDialogButtonBox::Cancel);
- QObject::connect(cancel, SIGNAL(clicked()), q, SLOT(reject()));
+ QObject::connect(cancel, &QPushButton::clicked, q, &QColorDialog::reject);
#ifdef Q_OS_WIN32
updateTimer = new QTimer(q);
- QObject::connect(updateTimer, SIGNAL(timeout()), q, SLOT(_q_updateColorPicking()));
+ QObjectPrivate::connect(updateTimer, &QTimer::timeout,
+ this, qOverload<>(&QColorDialogPrivate::updateColorPicking));
#endif
retranslateStrings();
}
@@ -1854,9 +1868,12 @@ void QColorDialogPrivate::initWidgets()
void QColorDialogPrivate::initHelper(QPlatformDialogHelper *h)
{
QColorDialog *d = q_func();
- QObject::connect(h, SIGNAL(currentColorChanged(QColor)), d, SIGNAL(currentColorChanged(QColor)));
- QObject::connect(h, SIGNAL(colorSelected(QColor)), d, SIGNAL(colorSelected(QColor)));
- static_cast<QPlatformColorDialogHelper *>(h)->setOptions(options);
+ auto *colorDialogHelper = static_cast<QPlatformColorDialogHelper*>(h);
+ QObject::connect(colorDialogHelper, &QPlatformColorDialogHelper::currentColorChanged,
+ d, &QColorDialog::currentColorChanged);
+ QObject::connect(colorDialogHelper, &QPlatformColorDialogHelper::colorSelected,
+ d, &QColorDialog::colorSelected);
+ colorDialogHelper->setOptions(options);
}
void QColorDialogPrivate::helperPrepareShow(QPlatformDialogHelper *)
@@ -1864,7 +1881,7 @@ void QColorDialogPrivate::helperPrepareShow(QPlatformDialogHelper *)
options->setWindowTitle(q_func()->windowTitle());
}
-void QColorDialogPrivate::_q_addCustom()
+void QColorDialogPrivate::addCustom()
{
QColorDialogOptions::setCustomColor(nextCust, cs->currentColor());
if (custom)
@@ -1882,8 +1899,8 @@ void QColorDialogPrivate::retranslateStrings()
lblCustomColors->setText(QColorDialog::tr("&Custom colors"));
addCusBt->setText(QColorDialog::tr("&Add to Custom Colors"));
#if !defined(QT_SMALL_COLORDIALOG)
- if (screenColorPickerButton)
- screenColorPickerButton->setText(QColorDialog::tr("&Pick Screen Color"));
+ if (eyeDropperButton)
+ eyeDropperButton->setText(QColorDialog::tr("&Pick Screen Color"));
#endif
}
@@ -2079,6 +2096,8 @@ void QColorDialog::setOptions(ColorDialogOptions options)
if (!d->nativeDialogInUse) {
d->buttons->setVisible(!(options & NoButtons));
d->showAlpha(options & ShowAlphaChannel);
+ if (d->eyeDropperButton)
+ d->eyeDropperButton->setVisible(!(options & NoEyeDropperButton));
}
}
@@ -2098,6 +2117,7 @@ QColorDialog::ColorDialogOptions QColorDialog::options() const
\value ShowAlphaChannel Allow the user to select the alpha component of a color.
\value NoButtons Don't display \uicontrol{OK} and \uicontrol{Cancel} buttons. (Useful for "live dialogs".)
+ \value NoEyeDropperButton Hide the \uicontrol{Eye Dropper} button. This value was added in Qt 6.6.
\value DontUseNativeDialog Use Qt's standard color dialog instead of the operating system
native color dialog.
@@ -2128,30 +2148,37 @@ QColorDialog::ColorDialogOptions QColorDialog::options() const
*/
void QColorDialog::setVisible(bool visible)
{
- Q_D(QColorDialog);
+ // will call QColorDialogPrivate::setVisible override
+ QDialog::setVisible(visible);
+}
- if (visible){
- if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden))
- return;
- } else if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden))
- return;
+/*!
+ \internal
+
+ The implementation of QColorDialog::setVisible() has to live here so that the call
+ to hide() in ~QDialog calls this function; it wouldn't call the override of
+ QDialog::setVisible().
+*/
+void QColorDialogPrivate::setVisible(bool visible)
+{
+ Q_Q(QColorDialog);
if (visible)
- d->selectedQColor = QColor();
+ selectedQColor = QColor();
- if (d->nativeDialogInUse) {
- if (d->setNativeDialogVisible(visible)) {
+ if (nativeDialogInUse) {
+ if (setNativeDialogVisible(visible)) {
// Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below
// updates the state correctly, but skips showing the non-native version:
- setAttribute(Qt::WA_DontShowOnScreen);
+ q->setAttribute(Qt::WA_DontShowOnScreen);
} else {
- d->initWidgets();
+ initWidgets();
}
} else {
- setAttribute(Qt::WA_DontShowOnScreen, false);
+ q->setAttribute(Qt::WA_DontShowOnScreen, false);
}
- QDialog::setVisible(visible);
+ QDialogPrivate::setVisible(visible);
}
/*!
@@ -2199,7 +2226,6 @@ QColor QColorDialog::getColor(const QColor &initial, QWidget *parent, const QStr
QColorDialog::~QColorDialog()
{
-
}
/*!
@@ -2213,7 +2239,7 @@ void QColorDialog::changeEvent(QEvent *e)
QDialog::changeEvent(e);
}
-void QColorDialogPrivate::_q_updateColorPicking()
+void QColorDialogPrivate::updateColorPicking()
{
#ifndef QT_NO_CURSOR
Q_Q(QColorDialog);
diff --git a/src/widgets/dialogs/qcolordialog.h b/src/widgets/dialogs/qcolordialog.h
index 2031c413a9..824efa8f8c 100644
--- a/src/widgets/dialogs/qcolordialog.h
+++ b/src/widgets/dialogs/qcolordialog.h
@@ -26,7 +26,8 @@ public:
enum ColorDialogOption {
ShowAlphaChannel = 0x00000001,
NoButtons = 0x00000002,
- DontUseNativeDialog = 0x00000004
+ DontUseNativeDialog = 0x00000004,
+ NoEyeDropperButton = 0x00000008,
};
Q_ENUM(ColorDialogOption)
@@ -72,15 +73,6 @@ protected:
private:
Q_DISABLE_COPY(QColorDialog)
-
- Q_PRIVATE_SLOT(d_func(), void _q_addCustom())
- Q_PRIVATE_SLOT(d_func(), void _q_newHsv(int h, int s, int v))
- Q_PRIVATE_SLOT(d_func(), void _q_newColorTypedIn(QRgb rgb))
- Q_PRIVATE_SLOT(d_func(), void _q_nextCustom(int, int))
- Q_PRIVATE_SLOT(d_func(), void _q_newCustom(int, int))
- Q_PRIVATE_SLOT(d_func(), void _q_newStandard(int, int))
- Q_PRIVATE_SLOT(d_func(), void _q_pickScreenColor())
- Q_PRIVATE_SLOT(d_func(), void _q_updateColorPicking())
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QColorDialog::ColorDialogOptions)
diff --git a/src/widgets/dialogs/qdialog.cpp b/src/widgets/dialogs/qdialog.cpp
index f29f1dfded..27466d03d6 100644
--- a/src/widgets/dialogs/qdialog.cpp
+++ b/src/widgets/dialogs/qdialog.cpp
@@ -149,25 +149,6 @@ void QDialogPrivate::close(int resultCode)
resetModalitySetByOpen();
}
-/*!
- \internal
-
- Emits finished() signal with \a resultCode. If the \a dialogCode
- is equal to 0 emits rejected(), if the \a dialogCode is equal to
- 1 emits accepted().
- */
-void QDialogPrivate::finalize(int resultCode, int dialogCode)
-{
- Q_Q(QDialog);
-
- if (dialogCode == QDialog::Accepted)
- emit q->accepted();
- else if (dialogCode == QDialog::Rejected)
- emit q->rejected();
-
- emit q->finished(resultCode);
-}
-
QWindow *QDialogPrivate::transientParentWindow() const
{
Q_Q(const QDialog);
@@ -299,7 +280,8 @@ QVariant QDialogPrivate::styleHint(QPlatformDialogHelper::StyleHint hint) const
\section1 Escape Key
If the user presses the Esc key in a dialog, QDialog::reject()
- will be called. This will cause the window to close: The \l{QCloseEvent}{close event} cannot be \l{QEvent::ignore()}{ignored}.
+ will be called. This will cause the window to close:
+ The \l{QCloseEvent}{close event} cannot be \l{QEvent::ignore()}{ignored}.
\section1 Extensibility
@@ -307,9 +289,8 @@ QVariant QDialogPrivate::styleHint(QPlatformDialogHelper::StyleHint hint) const
partial dialog that shows the most commonly used options, and a
full dialog that shows all the options. Typically an extensible
dialog will initially appear as a partial dialog, but with a
- \uicontrol More toggle button. If the user presses the \uicontrol More button down,
- the dialog is expanded. The \l{Extension Example} shows how to achieve
- extensible dialogs using Qt.
+ \uicontrol More toggle button. If the user presses the
+ \uicontrol More button down, the dialog is expanded.
\target return
\section1 Return Value (Modal Dialogs)
@@ -339,7 +320,15 @@ QVariant QDialogPrivate::styleHint(QPlatformDialogHelper::StyleHint hint) const
\snippet dialogs/dialogs.cpp 0
- \sa QDialogButtonBox, QTabWidget, QWidget, QProgressDialog, {Extension Example},
+ A dialog with an extension:
+
+ \snippet dialogs/dialogs.cpp extension
+
+ By setting the \l{QLayout::}{sizeConstraint} property of the dialog's
+ layout to \l{QLayout::}{SetFixedSize}, the dialog will not be resizable
+ by the user, and will automatically shrink when the extension gets hidden.
+
+ \sa QDialogButtonBox, QTabWidget, QWidget, QProgressDialog,
{Standard Dialogs Example}
*/
@@ -612,9 +601,22 @@ int QDialog::exec()
void QDialog::done(int r)
{
+ QPointer<QDialog> guard(this);
+
Q_D(QDialog);
d->close(r);
- d->finalize(r, r);
+
+ if (!guard)
+ return;
+
+ int dialogCode = d->dialogCode();
+ if (dialogCode == QDialog::Accepted)
+ emit accepted();
+ else if (dialogCode == QDialog::Rejected)
+ emit rejected();
+
+ if (guard)
+ emit finished(r);
}
/*!
@@ -742,6 +744,10 @@ void QDialog::closeEvent(QCloseEvent *e)
void QDialog::setVisible(bool visible)
{
Q_D(QDialog);
+
+ if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden) != visible)
+ return;
+
d->setVisible(visible);
}
@@ -766,9 +772,6 @@ void QDialogPrivate::setVisible(bool visible)
}
if (visible) {
- if (q->testAttribute(Qt::WA_WState_ExplicitShowHide) && !q->testAttribute(Qt::WA_WState_Hidden))
- return;
-
q->QWidget::setVisible(visible);
// Window activation might be prevented. We can't test isActiveWindow here,
@@ -819,8 +822,6 @@ void QDialogPrivate::setVisible(bool visible)
#endif
} else {
- if (q->testAttribute(Qt::WA_WState_ExplicitShowHide) && q->testAttribute(Qt::WA_WState_Hidden))
- return;
#if QT_CONFIG(accessibility)
if (q->isVisible()) {
diff --git a/src/widgets/dialogs/qdialog.h b/src/widgets/dialogs/qdialog.h
index 4d11fe2d8d..22360bc358 100644
--- a/src/widgets/dialogs/qdialog.h
+++ b/src/widgets/dialogs/qdialog.h
@@ -28,6 +28,7 @@ public:
~QDialog();
enum DialogCode { Rejected, Accepted };
+ Q_ENUM(DialogCode)
int result() const;
diff --git a/src/widgets/dialogs/qdialog_p.h b/src/widgets/dialogs/qdialog_p.h
index 878049557a..bac33bdea9 100644
--- a/src/widgets/dialogs/qdialog_p.h
+++ b/src/widgets/dialogs/qdialog_p.h
@@ -88,7 +88,9 @@ public:
virtual bool canBeNativeDialog() const;
void close(int resultCode);
- void finalize(int resultCode, int dialogCode);
+
+protected:
+ virtual int dialogCode() const { return rescode; }
private:
virtual void initHelper(QPlatformDialogHelper *) {}
@@ -103,7 +105,7 @@ template <typename T>
class QAutoPointer {
QPointer<T> o;
public:
- explicit QAutoPointer(T *t) noexcept : o(t) {}
+ Q_NODISCARD_CTOR explicit QAutoPointer(T *t) noexcept : o(t) {}
~QAutoPointer() { delete o; }
T *operator->() const noexcept { return get(); }
diff --git a/src/widgets/dialogs/qerrormessage.cpp b/src/widgets/dialogs/qerrormessage.cpp
index 5a6d529fc2..2b5681f79b 100644
--- a/src/widgets/dialogs/qerrormessage.cpp
+++ b/src/widgets/dialogs/qerrormessage.cpp
@@ -257,7 +257,9 @@ QErrorMessage::QErrorMessage(QWidget * parent)
grid->setRowStretch(0, 42);
#if QT_CONFIG(messagebox)
- d->icon->setPixmap(style()->standardPixmap(QStyle::SP_MessageBoxInformation));
+ const auto iconSize = style()->pixelMetric(QStyle::PM_MessageBoxIconSize, nullptr, this);
+ const auto icon = style()->standardIcon(QStyle::SP_MessageBoxInformation, nullptr, this);
+ d->icon->setPixmap(icon.pixmap(QSize(iconSize, iconSize), devicePixelRatio()));
d->icon->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
#endif
d->again->setChecked(true);
@@ -407,8 +409,6 @@ void QErrorMessage::showMessage(const QString &message, const QString &type)
void QErrorMessagePrivate::setVisible(bool visible)
{
Q_Q(QErrorMessage);
- if (q->testAttribute(Qt::WA_WState_ExplicitShowHide) && q->testAttribute(Qt::WA_WState_Hidden) != visible)
- return;
if (canBeNativeDialog())
setNativeDialogVisible(visible);
diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp
index c83c5e64d8..22e6d44e6f 100644
--- a/src/widgets/dialogs/qfiledialog.cpp
+++ b/src/widgets/dialogs/qfiledialog.cpp
@@ -58,14 +58,17 @@ Q_GLOBAL_STATIC(QUrl, lastVisitedDir)
/*!
\class QFileDialog
- \brief The QFileDialog class provides a dialog that allow users to select files or directories.
+ \brief The QFileDialog class provides a dialog that allows users to select files or directories.
\ingroup standard-dialogs
\inmodule QtWidgets
- The QFileDialog class enables a user to traverse the file system in
- order to select one or many files or a directory.
+ The QFileDialog class enables a user to traverse the file system
+ to select one or many files or a directory.
- The easiest way to create a QFileDialog is to use the static functions.
+ \image qtquickdialogs-filedialog-gtk.png
+
+ The easiest way to create a QFileDialog is to use the static functions,
+ such as \l getOpenFileName().
\snippet code/src_gui_dialogs_qfiledialog.cpp 0
@@ -90,7 +93,7 @@ Q_GLOBAL_STATIC(QUrl, lastVisitedDir)
AnyFile, meaning that the user can select any file, or even specify a
file that doesn't exist. This mode is useful for creating a
"Save As" file dialog. Use ExistingFile if the user must select an
- existing file, or \l Directory if only a directory may be selected.
+ existing file, or \l Directory if only a directory can be selected.
See the \l QFileDialog::FileMode enum for the complete list of modes.
The fileMode property contains the mode of operation for the dialog;
@@ -99,9 +102,9 @@ Q_GLOBAL_STATIC(QUrl, lastVisitedDir)
\snippet code/src_gui_dialogs_qfiledialog.cpp 3
- In the above example, the filter is set to \c{"Images (*.png *.xpm *.jpg)"},
- this means that only files with the extension \c png, \c xpm,
- or \c jpg will be shown in the QFileDialog. You can apply
+ In the above example, the filter is set to \c{"Images (*.png *.xpm *.jpg)"}.
+ This means that only files with the extension \c png, \c xpm,
+ or \c jpg are shown in the QFileDialog. You can apply
several filters by using setNameFilters(). Use selectNameFilter() to select
one of the filters you've given as the file dialog's default filter.
@@ -115,7 +118,7 @@ Q_GLOBAL_STATIC(QUrl, lastVisitedDir)
\snippet code/src_gui_dialogs_qfiledialog.cpp 4
- The last important function you will need to use when creating your
+ The last important function you need to use when creating your
own file dialog is selectedFiles().
\snippet code/src_gui_dialogs_qfiledialog.cpp 5
@@ -130,16 +133,16 @@ Q_GLOBAL_STATIC(QUrl, lastVisitedDir)
The \l{dialogs/standarddialogs}{Standard Dialogs} example shows
how to use QFileDialog as well as other built-in Qt dialogs.
- By default, a platform-native file dialog will be used if the platform has
- one. In that case, the widgets which would otherwise be used to construct the
- dialog will not be instantiated, so related accessors such as layout() and
- itemDelegate() will return null. Also, not all platforms show file dialogs
+ By default, a platform-native file dialog is used if the platform has
+ one. In that case, the widgets that would otherwise be used to construct the
+ dialog are not instantiated, so related accessors such as layout() and
+ itemDelegate() return null. Also, not all platforms show file dialogs
with a title bar, so be aware that the caption text might not be visible to
- the user. You can set the \l DontUseNativeDialog option to ensure that the
- widget-based implementation will be used instead of the native dialog.
+ the user. You can set the \l DontUseNativeDialog option or set the
+ \l{Qt::AA_DontUseNativeDialogs}{AA_DontUseNativeDialogs} application attribute
+ to ensure that the widget-based implementation is used instead of the native dialog.
- \sa QDir, QFileInfo, QFile, QColorDialog, QFontDialog, {Standard Dialogs Example},
- {Qt Widgets - Application Example}
+ \sa QDir, QFileInfo, QFile, QColorDialog, QFontDialog, {Standard Dialogs Example}
*/
/*!
@@ -152,8 +155,8 @@ Q_GLOBAL_STATIC(QUrl, lastVisitedDir)
/*!
\enum QFileDialog::ViewMode
- This enum describes the view mode of the file dialog; i.e. what
- information about each file will be displayed.
+ This enum describes the view mode of the file dialog; that is, what
+ information about each file is displayed.
\value Detail Displays an icon, a name, and details for each item in
the directory.
@@ -167,7 +170,7 @@ Q_GLOBAL_STATIC(QUrl, lastVisitedDir)
\enum QFileDialog::FileMode
This enum is used to indicate what the user may select in the file
- dialog; i.e. what the dialog will return if the user clicks OK.
+ dialog; that is, what the dialog returns if the user clicks OK.
\value AnyFile The name of a file, whether it exists or not.
\value ExistingFile The name of a single existing file.
@@ -183,37 +186,43 @@ Q_GLOBAL_STATIC(QUrl, lastVisitedDir)
/*!
\enum QFileDialog::Option
- \value ShowDirsOnly Only show directories in the file dialog. By
- default both files and directories are shown. (Valid only in the
- \l Directory file mode.)
-
- \value DontResolveSymlinks Don't resolve symlinks in the file
- dialog. By default symlinks are resolved.
+ Options that influence the behavior of the dialog.
- \value DontConfirmOverwrite Don't ask for confirmation if an
- existing file is selected. By default confirmation is requested.
+ \value ShowDirsOnly Only show directories. By
+ default, both files and directories are shown.\br
+ This option is only effective in the \l Directory file mode.
- Note: This option is not supported on macOS when using the
- native file dialog.
+ \value DontResolveSymlinks Don't resolve symlinks.
+ By default, symlinks are resolved.
- \value DontUseNativeDialog Don't use the native file dialog. By
- default, the native file dialog is used unless you use a subclass
- of QFileDialog that contains the Q_OBJECT macro, or the platform
- does not have a native dialog of the type that you require.
+ \value DontConfirmOverwrite Don't ask for confirmation if an
+ existing file is selected. By default, confirmation is requested.\br
+ This option is only effective if \l acceptMode is \l {QFileDialog::}{AcceptSave}).
+ It is furthermore not used on macOS for native file dialogs.
- \b{Note:} This option must be set before changing dialog properties
- or showing the dialog.
+ \value DontUseNativeDialog Don't use a platform-native file dialog,
+ but the widget-based one provided by Qt.\br
+ By default, a native file dialog is shown unless you use a subclass
+ of QFileDialog that contains the Q_OBJECT macro, the global
+ \l{Qt::}{AA_DontUseNativeDialogs} application attribute is set, or the platform
+ does not have a native dialog of the type that you require.\br
+ For the option to be effective, you must set it before changing
+ other properties of the dialog, or showing the dialog.
- \value ReadOnly Indicates that the model is readonly.
+ \value ReadOnly Indicates that the model is read-only.
\value HideNameFilterDetails Indicates if the file name filter details are
hidden or not.
- \value DontUseCustomDirectoryIcons Always use the default directory icon.
- Some platforms allow the user to set a different icon. Custom icon lookup
- cause a big performance impact over network or removable drives.
- Setting this will enable the QFileIconProvider::DontUseCustomDirectoryIcons
- option in the icon provider. This enum value was added in Qt 5.2.
+ \value DontUseCustomDirectoryIcons Always use the default directory icon.\br
+ Some platforms allow the user to set a different icon, but custom icon lookup
+ might cause significant performance issues over network or removable drives.\br
+ Setting this will enable the
+ \l{QAbstractFileIconProvider::}{DontUseCustomDirectoryIcons}
+ option in \l{iconProvider()}.\br
+ This enum value was added in Qt 5.2.
+
+ \sa options, testOption
*/
/*!
@@ -380,7 +389,7 @@ QFileDialog::~QFileDialog()
\snippet filedialogurls/filedialogurls.cpp 0
- The file dialog will then look like this:
+ Then the file dialog looks like this:
\image filedialogurls.png
@@ -524,13 +533,19 @@ QFileDialogPrivate::~QFileDialogPrivate()
void QFileDialogPrivate::initHelper(QPlatformDialogHelper *h)
{
- QFileDialog *d = q_func();
- QObject::connect(h, SIGNAL(fileSelected(QUrl)), d, SLOT(_q_emitUrlSelected(QUrl)));
- QObject::connect(h, SIGNAL(filesSelected(QList<QUrl>)), d, SLOT(_q_emitUrlsSelected(QList<QUrl>)));
- QObject::connect(h, SIGNAL(currentChanged(QUrl)), d, SLOT(_q_nativeCurrentChanged(QUrl)));
- QObject::connect(h, SIGNAL(directoryEntered(QUrl)), d, SLOT(_q_nativeEnterDirectory(QUrl)));
- QObject::connect(h, SIGNAL(filterSelected(QString)), d, SIGNAL(filterSelected(QString)));
- static_cast<QPlatformFileDialogHelper *>(h)->setOptions(options);
+ Q_Q(QFileDialog);
+ auto *fileDialogHelper = static_cast<QPlatformFileDialogHelper *>(h);
+ QObjectPrivate::connect(fileDialogHelper, &QPlatformFileDialogHelper::fileSelected,
+ this, &QFileDialogPrivate::emitUrlSelected);
+ QObjectPrivate::connect(fileDialogHelper, &QPlatformFileDialogHelper::filesSelected,
+ this, &QFileDialogPrivate::emitUrlsSelected);
+ QObjectPrivate::connect(fileDialogHelper, &QPlatformFileDialogHelper::currentChanged,
+ this, &QFileDialogPrivate::nativeCurrentChanged);
+ QObjectPrivate::connect(fileDialogHelper, &QPlatformFileDialogHelper::directoryEntered,
+ this, &QFileDialogPrivate::nativeEnterDirectory);
+ QObject::connect(fileDialogHelper, &QPlatformFileDialogHelper::filterSelected,
+ q, &QFileDialog::filterSelected);
+ fileDialogHelper->setOptions(options);
}
void QFileDialogPrivate::helperPrepareShow(QPlatformDialogHelper *)
@@ -651,7 +666,7 @@ void QFileDialogPrivate::retranslateStrings()
if (proxyModel)
abstractModel = proxyModel;
#endif
- int total = qMin(abstractModel->columnCount(QModelIndex()), actions.size() + 1);
+ const int total = qMin(abstractModel->columnCount(QModelIndex()), int(actions.size() + 1));
for (int i = 1; i < total; ++i) {
actions.at(i - 1)->setText(QFileDialog::tr("Show ") + abstractModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString());
}
@@ -702,7 +717,7 @@ bool QFileDialogPrivate::usingWidgets() const
Sets the given \a option to be enabled if \a on is true; otherwise,
clears the given \a option.
- Options (particularly the DontUseNativeDialogs option) should be set
+ Options (particularly the \l DontUseNativeDialog option) should be set
before changing dialog properties or showing the dialog.
Setting options while the dialog is visible is not guaranteed to have
@@ -737,12 +752,12 @@ bool QFileDialog::testOption(Option option) const
/*!
\property QFileDialog::options
- \brief the various options that affect the look and feel of the dialog
+ \brief The various options that affect the look and feel of the dialog.
\since 4.5
By default, all options are disabled.
- Options (particularly the DontUseNativeDialogs option) should be set
+ Options (particularly the \l DontUseNativeDialog option) should be set
before changing dialog properties or showing the dialog.
Setting options while the dialog is visible is not guaranteed to have
@@ -811,11 +826,11 @@ QFileDialog::Options QFileDialog::options() const
/*!
\since 4.5
- This function connects one of its signals to the slot specified by \a receiver
- and \a member. The specific signal depends is filesSelected() if fileMode is
- ExistingFiles and fileSelected() if fileMode is anything else.
+ This function shows the dialog, and connects the slot specified by \a receiver
+ and \a member to the signal that informs about selection changes. If the fileMode is
+ ExistingFiles, this is the filesSelected() signal, otherwise it is the fileSelected() signal.
- The signal will be disconnected from the slot when the dialog is closed.
+ The signal is disconnected from the slot when the dialog is closed.
*/
void QFileDialog::open(QObject *receiver, const char *member)
{
@@ -836,54 +851,61 @@ void QFileDialog::open(QObject *receiver, const char *member)
*/
void QFileDialog::setVisible(bool visible)
{
- Q_D(QFileDialog);
- if (visible){
- if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden))
- return;
- } else if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden))
- return;
+ // will call QFileDialogPrivate::setVisible override
+ QDialog::setVisible(visible);
+}
+
+/*!
+ \internal
+
+ The logic has to live here so that the call to hide() in ~QDialog calls
+ this function; it wouldn't call an override of QDialog::setVisible().
+*/
+void QFileDialogPrivate::setVisible(bool visible)
+{
+ Q_Q(QFileDialog);
- if (d->canBeNativeDialog()){
- if (d->setNativeDialogVisible(visible)){
- // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below
+ if (canBeNativeDialog()){
+ if (setNativeDialogVisible(visible)){
+ // Set WA_DontShowOnScreen so that QDialogPrivate::setVisible(visible) below
// updates the state correctly, but skips showing the non-native version:
- setAttribute(Qt::WA_DontShowOnScreen);
+ q->setAttribute(Qt::WA_DontShowOnScreen);
#if QT_CONFIG(fscompleter)
// So the completer doesn't try to complete and therefore show a popup
- if (!d->nativeDialogInUse)
- d->completer->setModel(nullptr);
+ if (!nativeDialogInUse)
+ completer->setModel(nullptr);
#endif
} else {
- d->createWidgets();
- setAttribute(Qt::WA_DontShowOnScreen, false);
+ createWidgets();
+ q->setAttribute(Qt::WA_DontShowOnScreen, false);
#if QT_CONFIG(fscompleter)
- if (!d->nativeDialogInUse) {
- if (d->proxyModel != nullptr)
- d->completer->setModel(d->proxyModel);
+ if (!nativeDialogInUse) {
+ if (proxyModel != nullptr)
+ completer->setModel(proxyModel);
else
- d->completer->setModel(d->model);
+ completer->setModel(model);
}
#endif
}
}
- if (visible && d->usingWidgets())
- d->qFileDialogUi->fileNameEdit->setFocus();
+ if (visible && usingWidgets())
+ qFileDialogUi->fileNameEdit->setFocus();
- QDialog::setVisible(visible);
+ QDialogPrivate::setVisible(visible);
}
/*!
\internal
set the directory to url
*/
-void QFileDialogPrivate::_q_goToUrl(const QUrl &url)
+void QFileDialogPrivate::goToUrl(const QUrl &url)
{
//The shortcut in the side bar may have a parent that is not fetched yet (e.g. an hidden file)
//so we force the fetching
QFileSystemModelPrivate::QFileSystemNode *node = model->d_func()->node(url.toLocalFile(), true);
QModelIndex idx = model->d_func()->index(node);
- _q_enterDirectory(idx);
+ enterDirectory(idx);
}
/*!
@@ -897,7 +919,7 @@ void QFileDialogPrivate::_q_goToUrl(const QUrl &url)
\note On iOS, if you set \a directory to \l{QStandardPaths::standardLocations()}
{QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).last()},
- a native image picker dialog will be used for accessing the user's photo album.
+ a native image picker dialog is used for accessing the user's photo album.
The filename returned can be loaded using QFile and related APIs.
For this to be enabled, the Info.plist assigned to QMAKE_INFO_PLIST in the
project file must contain the key \c NSPhotoLibraryUsageDescription. See
@@ -1104,43 +1126,58 @@ void QFileDialog::selectUrl(const QUrl &url)
}
#ifdef Q_OS_UNIX
+static QString homeDirFromPasswdEntry(const QString &path, const QByteArray &userName)
+{
+#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) && !defined(Q_OS_WASM)
+ passwd pw;
+ passwd *tmpPw;
+ long bufSize = ::sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (bufSize == -1)
+ bufSize = 1024;
+ QVarLengthArray<char, 1024> buf(bufSize);
+ int err = 0;
+# if defined(Q_OS_SOLARIS) && (_POSIX_C_SOURCE - 0 < 199506L)
+ tmpPw = getpwnam_r(userName.constData(), &pw, buf.data(), buf.size());
+# else
+ err = getpwnam_r(userName.constData(), &pw, buf.data(), buf.size(), &tmpPw);
+# endif
+ if (err || !tmpPw)
+ return path;
+ return QFile::decodeName(pw.pw_dir);
+#else
+ passwd *pw = getpwnam(userName.constData());
+ if (!pw)
+ return path;
+ return QFile::decodeName(pw->pw_dir);
+#endif // defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) && !defined(Q_OS_WASM)
+}
+
Q_AUTOTEST_EXPORT QString qt_tildeExpansion(const QString &path)
{
if (!path.startsWith(u'~'))
return path;
- int separatorPosition = path.indexOf(QDir::separator());
- if (separatorPosition < 0)
- separatorPosition = path.size();
- if (separatorPosition == 1) {
- return QDir::homePath() + QStringView{path}.mid(1);
- } else {
+
+ if (path.size() == 1) // '~'
+ return QDir::homePath();
+
+ QStringView sv(path);
+ const qsizetype sepIndex = sv.indexOf(QDir::separator());
+ if (sepIndex == 1) // '~/' or '~/a/b/c'
+ return QDir::homePath() + sv.sliced(1);
+
#if defined(Q_OS_VXWORKS) || defined(Q_OS_INTEGRITY)
- const QString homePath = QDir::homePath();
+ if (sepIndex == -1)
+ return QDir::homePath();
+ return QDir::homePath() + sv.sliced(sepIndex);
#else
- const QByteArray userName = QStringView{path}.mid(1, separatorPosition - 1).toLocal8Bit();
-# if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) && !defined(Q_OS_WASM)
- passwd pw;
- passwd *tmpPw;
- char buf[200];
- const int bufSize = sizeof(buf);
- int err = 0;
-# if defined(Q_OS_SOLARIS) && (_POSIX_C_SOURCE - 0 < 199506L)
- tmpPw = getpwnam_r(userName.constData(), &pw, buf, bufSize);
-# else
- err = getpwnam_r(userName.constData(), &pw, buf, bufSize, &tmpPw);
-# endif
- if (err || !tmpPw)
- return path;
- const QString homePath = QString::fromLocal8Bit(pw.pw_dir);
-# else
- passwd *pw = getpwnam(userName.constData());
- if (!pw)
- return path;
- const QString homePath = QString::fromLocal8Bit(pw->pw_dir);
-# endif
-#endif
- return homePath + QStringView{path}.mid(separatorPosition);
- }
+ const qsizetype userNameLen = sepIndex != -1 ? sepIndex - strlen("~") // '~user/a/b'
+ : path.size() - strlen("~"); // '~user'
+ const QByteArray userName = sv.sliced(1, userNameLen).toLocal8Bit();
+ QString homePath = homeDirFromPasswdEntry(path, userName);
+ if (sepIndex == -1)
+ return homePath;
+ return homePath + sv.sliced(sepIndex);
+#endif // defined(Q_OS_VXWORKS) || defined(Q_OS_INTEGRITY)
}
#endif
@@ -1240,12 +1277,10 @@ QStringList QFileDialogPrivate::addDefaultSuffixToFiles(const QStringList &files
QList<QUrl> QFileDialogPrivate::addDefaultSuffixToUrls(const QList<QUrl> &urlsToFix) const
{
QList<QUrl> urls;
- const int numUrlsToFix = urlsToFix.size();
- urls.reserve(numUrlsToFix);
- for (int i = 0; i < numUrlsToFix; ++i) {
- QUrl url = urlsToFix.at(i);
- // if the filename has no suffix, add the default suffix
- const QString defaultSuffix = options->defaultSuffix();
+ urls.reserve(urlsToFix.size());
+ // if the filename has no suffix, add the default suffix
+ const QString defaultSuffix = options->defaultSuffix();
+ for (QUrl url : urlsToFix) {
if (!defaultSuffix.isEmpty()) {
const QString urlPath = url.path();
const auto idx = urlPath.lastIndexOf(u'/');
@@ -1353,11 +1388,10 @@ QStringList qt_strip_filters(const QStringList &filters)
#if QT_CONFIG(regularexpression)
QStringList strippedFilters;
static const QRegularExpression r(QString::fromLatin1(QPlatformFileDialogHelper::filterRegExp));
- const int numFilters = filters.size();
- strippedFilters.reserve(numFilters);
- for (int i = 0; i < numFilters; ++i) {
+ strippedFilters.reserve(filters.size());
+ for (const QString &filter : filters) {
QString filterName;
- auto match = r.match(filters[i]);
+ auto match = r.match(filter);
if (match.hasMatch())
filterName = match.captured(1);
strippedFilters.append(filterName.simplified());
@@ -1378,25 +1412,24 @@ QStringList qt_strip_filters(const QStringList &filters)
assumption that the file extension determines the file type is not
consistent on every operating system. It is possible to have a file with no
dot in its name (for example, \c Makefile). In a native Windows file
- dialog, \b{*.*} will match such files, while in other types of file dialogs
- it may not. So it is better to use \b{*} if you mean to select any file.
+ dialog, \b{*.*} matches such files, while in other types of file dialogs
+ it might not match. So, it's better to use \b{*} if you mean to select any file.
\snippet code/src_gui_dialogs_qfiledialog.cpp 7
\l setMimeTypeFilters() has the advantage of providing all possible name
filters for each file type. For example, JPEG images have three possible
extensions; if your application can open such files, selecting the
- \c image/jpeg mime type as a filter will allow you to open all of them.
+ \c image/jpeg mime type as a filter allows you to open all of them.
*/
void QFileDialog::setNameFilters(const QStringList &filters)
{
Q_D(QFileDialog);
QStringList cleanedFilters;
- const int numFilters = filters.size();
- cleanedFilters.reserve(numFilters);
- for (int i = 0; i < numFilters; ++i) {
- cleanedFilters << filters[i].simplified();
- }
+ cleanedFilters.reserve(filters.size());
+ for (const QString &filter : filters)
+ cleanedFilters << filter.simplified();
+
d->options->setNameFilters(cleanedFilters);
if (!d->usingWidgets())
@@ -1411,7 +1444,7 @@ void QFileDialog::setNameFilters(const QStringList &filters)
else
d->qFileDialogUi->fileTypeCombo->addItems(cleanedFilters);
- d->_q_useNameFilter(0);
+ d->useNameFilter(0);
}
/*!
@@ -1451,7 +1484,7 @@ void QFileDialog::selectNameFilter(const QString &filter)
}
if (i >= 0) {
d->qFileDialogUi->fileTypeCombo->setCurrentIndex(i);
- d->_q_useNameFilter(d->qFileDialogUi->fileTypeCombo->currentIndex());
+ d->useNameFilter(d->qFileDialogUi->fileTypeCombo->currentIndex());
}
}
@@ -1609,7 +1642,7 @@ QString QFileDialog::selectedMimeTypeFilter() const
for (const auto &mimeType: mimeTypes) {
QString filter = nameFilterForMime(mimeType);
if (testOption(HideNameFilterDetails))
- filter = qt_strip_filters({ filter }).first();
+ filter = qt_strip_filters({ filter }).constFirst();
if (filter == nameFilter) {
mimeTypeFilter = mimeType;
break;
@@ -1623,7 +1656,7 @@ QString QFileDialog::selectedMimeTypeFilter() const
/*!
\property QFileDialog::viewMode
- \brief the way files and directories are displayed in the dialog
+ \brief The way files and directories are displayed in the dialog.
By default, the \c Detail mode is used to display information about
files and directories.
@@ -1637,9 +1670,9 @@ void QFileDialog::setViewMode(QFileDialog::ViewMode mode)
if (!d->usingWidgets())
return;
if (mode == Detail)
- d->_q_showDetailsView();
+ d->showDetailsView();
else
- d->_q_showListView();
+ d->showListView();
}
QFileDialog::ViewMode QFileDialog::viewMode() const
@@ -1652,14 +1685,14 @@ QFileDialog::ViewMode QFileDialog::viewMode() const
/*!
\property QFileDialog::fileMode
- \brief the file mode of the dialog
+ \brief The file mode of the dialog.
The file mode defines the number and type of items that the user is
expected to select in the dialog.
By default, this property is set to AnyFile.
- This function will set the labels for the FileName and
+ This function sets the labels for the FileName and
\l{QFileDialog::}{Accept} \l{DialogLabel}s. It is possible to set
custom text after the call to setFileMode().
@@ -1693,7 +1726,7 @@ void QFileDialog::setFileMode(QFileDialog::FileMode mode)
d->updateFileNameLabel();
d->updateOkButtonText();
d->qFileDialogUi->fileTypeCombo->setEnabled(!testOption(ShowDirsOnly));
- d->_q_updateOkButton();
+ d->updateOkButton();
}
QFileDialog::FileMode QFileDialog::fileMode() const
@@ -1704,7 +1737,7 @@ QFileDialog::FileMode QFileDialog::fileMode() const
/*!
\property QFileDialog::acceptMode
- \brief the accept mode of the dialog
+ \brief The accept mode of the dialog.
The action mode defines whether the dialog is for opening or saving files.
@@ -1723,7 +1756,7 @@ void QFileDialog::setAcceptMode(QFileDialog::AcceptMode mode)
QDialogButtonBox::StandardButton button = (mode == AcceptOpen ? QDialogButtonBox::Open : QDialogButtonBox::Save);
d->qFileDialogUi->buttonBox->setStandardButtons(button | QDialogButtonBox::Cancel);
d->qFileDialogUi->buttonBox->button(button)->setEnabled(false);
- d->_q_updateOkButton();
+ d->updateOkButton();
if (mode == AcceptSave) {
d->qFileDialogUi->lookInCombo->setEditable(false);
}
@@ -1732,14 +1765,14 @@ void QFileDialog::setAcceptMode(QFileDialog::AcceptMode mode)
/*!
\property QFileDialog::supportedSchemes
- \brief the URL schemes that the file dialog should allow navigating to.
+ \brief The URL schemes that the file dialog should allow navigating to.
\since 5.6
Setting this property allows to restrict the type of URLs the
- user will be able to select. It is a way for the application to declare
- the protocols it will support to fetch the file content. An empty list
+ user can select. It is a way for the application to declare
+ the protocols it supports to fetch the file content. An empty list
means that no restriction is applied (the default).
- Supported for local files ("file" scheme) is implicit and always enabled;
+ Support for local files ("file" scheme) is implicit and always enabled;
it is not necessary to include it in the restriction.
*/
@@ -1774,7 +1807,7 @@ QLineEdit *QFileDialogPrivate::lineEdit() const {
return (QLineEdit*)qFileDialogUi->fileNameEdit;
}
-int QFileDialogPrivate::maxNameLength(const QString &path)
+long QFileDialogPrivate::maxNameLength(const QString &path)
{
#if defined(Q_OS_UNIX)
return ::pathconf(QFile::encodeName(path).data(), _PC_NAME_MAX);
@@ -1821,10 +1854,10 @@ QFileDialog::AcceptMode QFileDialog::acceptMode() const
/*!
\property QFileDialog::defaultSuffix
- \brief suffix added to the filename if no other suffix was specified
+ \brief Suffix added to the filename if no other suffix was specified.
- This property specifies a string that will be added to the
- filename if it has no suffix already. The suffix is typically
+ This property specifies a string that is added to the
+ filename if it has no suffix yet. The suffix is typically
used to indicate the file type (e.g. "txt" indicates a text
file).
@@ -2027,41 +2060,41 @@ QString QFileDialog::labelText(DialogLabel label) const
\snippet code/src_gui_dialogs_qfiledialog.cpp 8
The function creates a modal file dialog with the given \a parent widget.
- If \a parent is not \nullptr, the dialog will be shown centered over the
+ If \a parent is not \nullptr, the dialog is shown centered over the
parent widget.
- The file dialog's working directory will be set to \a dir. If \a dir
- includes a file name, the file will be selected. Only files that match the
- given \a filter are shown. The filter selected is set to \a selectedFilter.
+ The file dialog's working directory is set to \a dir. If \a dir
+ includes a file name, the file is selected. Only files that match the
+ given \a filter are shown. The selected filter is set to \a selectedFilter.
The parameters \a dir, \a selectedFilter, and \a filter may be empty
strings. If you want multiple filters, separate them with ';;', for
example:
\snippet code/src_gui_dialogs_qfiledialog.cpp 14
- The \a options argument holds various options about how to run the dialog,
- see the QFileDialog::Option enum for more information on the flags you can
+ The \a options argument holds various options about how to run the dialog.
+ See the QFileDialog::Option enum for more information on the flags you can
pass.
- The dialog's caption is set to \a caption. If \a caption is not specified
+ The dialog's caption is set to \a caption. If \a caption is not specified,
then a default caption will be used.
- On Windows, and \macos, this static function will use the
+ On Windows, and \macos, this static function uses the
native file dialog and not a QFileDialog. Note that the \macos native file
dialog does not show a title bar.
- On Windows the dialog will spin a blocking modal event loop that will not
- dispatch any QTimers, and if \a parent is not \nullptr then it will position
+ On Windows the dialog spins a blocking modal event loop that does not
+ dispatch any QTimers, and if \a parent is not \nullptr then it positions
the dialog just below the parent's title bar.
On Unix/X11, the normal behavior of the file dialog is to resolve and
follow symlinks. For example, if \c{/usr/tmp} is a symlink to \c{/var/tmp},
- the file dialog will change to \c{/var/tmp} after entering \c{/usr/tmp}. If
- \a options includes DontResolveSymlinks, the file dialog will treat
+ the file dialog changes to \c{/var/tmp} after entering \c{/usr/tmp}. If
+ \a options includes DontResolveSymlinks, the file dialog treats
symlinks as regular directories.
\warning Do not delete \a parent during the execution of the dialog. If you
- want to do this, you should create the dialog yourself using one of the
+ want to do this, you must create the dialog yourself using one of the
QFileDialog constructors.
\sa getOpenFileNames(), getSaveFileName(), getExistingDirectory()
@@ -2089,21 +2122,21 @@ QString QFileDialog::getOpenFileName(QWidget *parent,
The function is used similarly to QFileDialog::getOpenFileName(). In
particular \a parent, \a caption, \a dir, \a filter, \a selectedFilter
- and \a options are used in the exact same way.
+ and \a options are used in exactly the same way.
The main difference with QFileDialog::getOpenFileName() comes from
the ability offered to the user to select a remote file. That's why
the return type and the type of \a dir is QUrl.
The \a supportedSchemes argument allows to restrict the type of URLs the
- user will be able to select. It is a way for the application to declare
+ user is able to select. It is a way for the application to declare
the protocols it will support to fetch the file content. An empty list
means that no restriction is applied (the default).
- Supported for local files ("file" scheme) is implicit and always enabled;
+ Support for local files ("file" scheme) is implicit and always enabled;
it is not necessary to include it in the restriction.
- When possible, this static function will use the native file dialog and
- not a QFileDialog. On platforms which don't support selecting remote
+ When possible, this static function uses the native file dialog and
+ not a QFileDialog. On platforms that don't support selecting remote
files, Qt will allow to select only local files.
\sa getOpenFileName(), getOpenFileUrls(), getSaveFileUrl(), getExistingDirectoryUrl()
@@ -2137,33 +2170,33 @@ QUrl QFileDialog::getOpenFileUrl(QWidget *parent,
}
/*!
- This is a convenience static function that will return one or more existing
+ This is a convenience static function that returns one or more existing
files selected by the user.
\snippet code/src_gui_dialogs_qfiledialog.cpp 9
This function creates a modal file dialog with the given \a parent widget.
- If \a parent is not \nullptr, the dialog will be shown centered over the
+ If \a parent is not \nullptr, the dialog is shown centered over the
parent widget.
- The file dialog's working directory will be set to \a dir. If \a dir
- includes a file name, the file will be selected. The filter is set to
+ The file dialog's working directory is set to \a dir. If \a dir
+ includes a file name, the file is selected. The filter is set to
\a filter so that only those files which match the filter are shown. The
filter selected is set to \a selectedFilter. The parameters \a dir,
- \a selectedFilter and \a filter may be empty strings. If you need multiple
+ \a selectedFilter and \a filter can be empty strings. If you need multiple
filters, separate them with ';;', for instance:
\snippet code/src_gui_dialogs_qfiledialog.cpp 14
- The dialog's caption is set to \a caption. If \a caption is not specified
- then a default caption will be used.
+ The dialog's caption is set to \a caption. If \a caption is not specified,
+ then a default caption is used.
- On Windows, and \macos, this static function will use the
+ On Windows and \macos, this static function uses the
native file dialog and not a QFileDialog. Note that the \macos native file
dialog does not show a title bar.
- On Windows the dialog will spin a blocking modal event loop that will not
- dispatch any QTimers, and if \a parent is not \nullptr then it will position
+ On Windows the dialog spins a blocking modal event loop that does not
+ dispatch any QTimers, and if \a parent is not \nullptr then it positions
the dialog just below the parent's title bar.
On Unix/X11, the normal behavior of the file dialog is to resolve and
@@ -2174,7 +2207,7 @@ QUrl QFileDialog::getOpenFileUrl(QWidget *parent,
pass.
\warning Do not delete \a parent during the execution of the dialog. If you
- want to do this, you should create the dialog yourself using one of the
+ want to do this, you must create the dialog yourself using one of the
QFileDialog constructors.
\sa getOpenFileName(), getSaveFileName(), getExistingDirectory()
@@ -2197,13 +2230,13 @@ QStringList QFileDialog::getOpenFileNames(QWidget *parent,
}
/*!
- This is a convenience static function that will return one or more existing
+ This is a convenience static function that returns one or more existing
files selected by the user. If the user presses Cancel, it returns an
empty list.
The function is used similarly to QFileDialog::getOpenFileNames(). In
particular \a parent, \a caption, \a dir, \a filter, \a selectedFilter
- and \a options are used in the exact same way.
+ and \a options are used in exactly the same way.
The main difference with QFileDialog::getOpenFileNames() comes from
the ability offered to the user to select remote files. That's why
@@ -2211,14 +2244,14 @@ QStringList QFileDialog::getOpenFileNames(QWidget *parent,
and QUrl.
The \a supportedSchemes argument allows to restrict the type of URLs the
- user will be able to select. It is a way for the application to declare
- the protocols it will support to fetch the file content. An empty list
+ user can select. It is a way for the application to declare
+ the protocols it supports to fetch the file content. An empty list
means that no restriction is applied (the default).
- Supported for local files ("file" scheme) is implicit and always enabled;
+ Support for local files ("file" scheme) is implicit and always enabled;
it is not necessary to include it in the restriction.
- When possible, this static function will use the native file dialog and
- not a QFileDialog. On platforms which don't support selecting remote
+ When possible, this static function uses the native file dialog and
+ not a QFileDialog. On platforms that don't support selecting remote
files, Qt will allow to select only local files.
\sa getOpenFileNames(), getOpenFileUrl(), getSaveFileUrl(), getExistingDirectoryUrl()
@@ -2252,15 +2285,16 @@ QList<QUrl> QFileDialog::getOpenFileUrls(QWidget *parent,
}
/*!
- This is a convenience static function that will return the content of a file
+ This is a convenience static function that returns the content of a file
selected by the user.
- This function is used to access local files on Qt for WebAssembly, where the web
- sandbox places restrictions on how such access may happen. Its implementation will
- make the browser display a native file dialog, where the user makes the file selection
- based on the parameter \a nameFilter.
+ Use this function to access local files on Qt for WebAssembly, if the web sandbox
+ restricts file access. Its implementation enables displaying a native file dialog in
+ the browser, where the user selects a file based on the \a nameFilter parameter.
- It can also be used on other platforms, where it will fall back to using QFileDialog.
+ \a parent is ignored on Qt for WebAssembly. Pass \a parent on other platforms, to make
+ the popup a child of another widget. If the platform doesn't support native file
+ dialogs, the function falls back to QFileDialog.
The function is asynchronous and returns immediately. The \a fileOpenCompleted
callback will be called when a file has been selected and its contents have been
@@ -2269,9 +2303,10 @@ QList<QUrl> QFileDialog::getOpenFileUrls(QWidget *parent,
\snippet code/src_gui_dialogs_qfiledialog.cpp 15
\since 5.13
*/
-void QFileDialog::getOpenFileContent(const QString &nameFilter, const std::function<void(const QString &, const QByteArray &)> &fileOpenCompleted)
+void QFileDialog::getOpenFileContent(const QString &nameFilter, const std::function<void(const QString &, const QByteArray &)> &fileOpenCompleted, QWidget *parent)
{
#ifdef Q_OS_WASM
+ Q_UNUSED(parent);
auto openFileImpl = std::make_shared<std::function<void(void)>>();
QString fileName;
QByteArray fileContent;
@@ -2301,9 +2336,10 @@ void QFileDialog::getOpenFileContent(const QString &nameFilter, const std::funct
(*openFileImpl)();
#else
- QFileDialog *dialog = new QFileDialog();
+ QFileDialog *dialog = new QFileDialog(parent);
dialog->setFileMode(QFileDialog::ExistingFile);
dialog->setNameFilter(nameFilter);
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
auto fileSelected = [=](const QString &fileName) {
QByteArray fileContent;
@@ -2315,13 +2351,7 @@ void QFileDialog::getOpenFileContent(const QString &nameFilter, const std::funct
fileOpenCompleted(fileName, fileContent);
};
- auto dialogClosed = [=](int code) {
- Q_UNUSED(code);
- dialog->deleteLater();
- };
-
- connect(dialog, &QFileDialog::fileSelected, fileSelected);
- connect(dialog, &QFileDialog::finished, dialogClosed);
+ connect(dialog, &QFileDialog::fileSelected, dialog, fileSelected);
dialog->show();
#endif
}
@@ -2331,23 +2361,26 @@ void QFileDialog::getOpenFileContent(const QString &nameFilter, const std::funct
a file name and location chosen by the user. \a fileNameHint can be provided to
suggest a file name to the user.
- This function is used to save files to the local file system on Qt for WebAssembly, where
- the web sandbox places restrictions on how such access may happen. Its implementation will
- make the browser display a native file dialog, where the user makes the file selection.
+ Use this function to save content to local files on Qt for WebAssembly, if the web sandbox
+ restricts file access. Its implementation enables displaying a native file dialog in the
+ browser, where the user specifies an output file based on the \a fileNameHint argument.
- It can also be used on other platforms, where it will fall back to using QFileDialog.
+ \a parent is ignored on Qt for WebAssembly. Pass \a parent on other platforms, to make
+ the popup a child of another widget. If the platform doesn't support native file
+ dialogs, the function falls back to QFileDialog.
The function is asynchronous and returns immediately.
\snippet code/src_gui_dialogs_qfiledialog.cpp 16
\since 5.14
*/
-void QFileDialog::saveFileContent(const QByteArray &fileContent, const QString &fileNameHint)
+void QFileDialog::saveFileContent(const QByteArray &fileContent, const QString &fileNameHint, QWidget *parent)
{
#ifdef Q_OS_WASM
+ Q_UNUSED(parent);
QWasmLocalFileAccess::saveFile(fileContent, fileNameHint.toStdString());
#else
- QFileDialog *dialog = new QFileDialog();
+ QFileDialog *dialog = new QFileDialog(parent);
dialog->setAcceptMode(QFileDialog::AcceptSave);
dialog->setFileMode(QFileDialog::AnyFile);
dialog->selectFile(fileNameHint);
@@ -2360,19 +2393,14 @@ void QFileDialog::saveFileContent(const QByteArray &fileContent, const QString &
}
};
- auto dialogClosed = [=](int code) {
- Q_UNUSED(code);
- dialog->deleteLater();
- };
-
- connect(dialog, &QFileDialog::fileSelected, fileSelected);
- connect(dialog, &QFileDialog::finished, dialogClosed);
+ connect(dialog, &QFileDialog::fileSelected, dialog, fileSelected);
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->show();
#endif
}
/*!
- This is a convenience static function that will return a file name selected
+ This is a convenience static function that returns a file name selected
by the user. The file does not have to exist.
It creates a modal file dialog with the given \a parent widget. If
@@ -2381,8 +2409,8 @@ void QFileDialog::saveFileContent(const QByteArray &fileContent, const QString &
\snippet code/src_gui_dialogs_qfiledialog.cpp 11
- The file dialog's working directory will be set to \a dir. If \a dir
- includes a file name, the file will be selected. Only files that match the
+ The file dialog's working directory is set to \a dir. If \a dir
+ includes a file name, the file is selected. Only files that match the
\a filter are shown. The filter selected is set to \a selectedFilter. The
parameters \a dir, \a selectedFilter, and \a filter may be empty strings.
Multiple filters are separated with ';;'. For instance:
@@ -2397,24 +2425,24 @@ void QFileDialog::saveFileContent(const QByteArray &fileContent, const QString &
desired value.
The dialog's caption is set to \a caption. If \a caption is not specified,
- a default caption will be used.
+ a default caption is used.
- On Windows, and \macos, this static function will use the
+ On Windows, and \macos, this static function uses the
native file dialog and not a QFileDialog.
- On Windows the dialog will spin a blocking modal event loop that will not
- dispatch any QTimers, and if \a parent is not \nullptr then it will
- position the dialog just below the parent's title bar. On \macos, with its
+ On Windows the dialog spins a blocking modal event loop that does not
+ dispatch any QTimers, and if \a parent is not \nullptr then it
+ positions the dialog just below the parent's title bar. On \macos, with its
native file dialog, the filter argument is ignored.
On Unix/X11, the normal behavior of the file dialog is to resolve and
follow symlinks. For example, if \c{/usr/tmp} is a symlink to \c{/var/tmp},
- the file dialog will change to \c{/var/tmp} after entering \c{/usr/tmp}. If
- \a options includes DontResolveSymlinks the file dialog will treat symlinks
+ the file dialog changes to \c{/var/tmp} after entering \c{/usr/tmp}. If
+ \a options includes DontResolveSymlinks, the file dialog treats symlinks
as regular directories.
\warning Do not delete \a parent during the execution of the dialog. If you
- want to do this, you should create the dialog yourself using one of the
+ want to do this, you must create the dialog yourself using one of the
QFileDialog constructors.
\sa getOpenFileName(), getOpenFileNames(), getExistingDirectory()
@@ -2442,21 +2470,21 @@ QString QFileDialog::getSaveFileName(QWidget *parent,
The function is used similarly to QFileDialog::getSaveFileName(). In
particular \a parent, \a caption, \a dir, \a filter, \a selectedFilter
- and \a options are used in the exact same way.
+ and \a options are used in exactly the same way.
The main difference with QFileDialog::getSaveFileName() comes from
the ability offered to the user to select a remote file. That's why
the return type and the type of \a dir is QUrl.
The \a supportedSchemes argument allows to restrict the type of URLs the
- user will be able to select. It is a way for the application to declare
- the protocols it will support to save the file content. An empty list
+ user can select. It is a way for the application to declare
+ the protocols it supports to save the file content. An empty list
means that no restriction is applied (the default).
- Supported for local files ("file" scheme) is implicit and always enabled;
+ Support for local files ("file" scheme) is implicit and always enabled;
it is not necessary to include it in the restriction.
- When possible, this static function will use the native file dialog and
- not a QFileDialog. On platforms which don't support selecting remote
+ When possible, this static function uses the native file dialog and
+ not a QFileDialog. On platforms that don't support selecting remote
files, Qt will allow to select only local files.
\sa getSaveFileName(), getOpenFileUrl(), getOpenFileUrls(), getExistingDirectoryUrl()
@@ -2491,44 +2519,45 @@ QUrl QFileDialog::getSaveFileUrl(QWidget *parent,
}
/*!
- This is a convenience static function that will return an existing
+ This is a convenience static function that returns an existing
directory selected by the user.
\snippet code/src_gui_dialogs_qfiledialog.cpp 12
This function creates a modal file dialog with the given \a parent widget.
- If \a parent is not \nullptr, the dialog will be shown centered over the
+ If \a parent is not \nullptr, the dialog is shown centered over the
parent widget.
The dialog's working directory is set to \a dir, and the caption is set to
- \a caption. Either of these may be an empty string in which case the
- current directory and a default caption will be used respectively.
+ \a caption. Either of these can be an empty string in which case the
+ current directory and a default caption are used respectively.
- The \a options argument holds various options about how to run the dialog,
- see the QFileDialog::Option enum for more information on the flags you can
+ The \a options argument holds various options about how to run the dialog.
+ See the QFileDialog::Option enum for more information on the flags you can
pass. To ensure a native file dialog, \l{QFileDialog::}{ShowDirsOnly} must
be set.
- On Windows and \macos, this static function will use the
+ On Windows and \macos, this static function uses the
native file dialog and not a QFileDialog. However, the native Windows file
dialog does not support displaying files in the directory chooser. You need
- to pass \l{QFileDialog::}{DontUseNativeDialog} to display files using a
+ to pass the \l{QFileDialog::}{DontUseNativeDialog} option, or set the global
+ \\l{Qt::}{AA_DontUseNativeDialogs} application attribute to display files using a
QFileDialog.
Note that the \macos native file dialog does not show a title bar.
On Unix/X11, the normal behavior of the file dialog is to resolve and
follow symlinks. For example, if \c{/usr/tmp} is a symlink to \c{/var/tmp},
- the file dialog will change to \c{/var/tmp} after entering \c{/usr/tmp}. If
- \a options includes DontResolveSymlinks, the file dialog will treat
+ the file dialog changes to \c{/var/tmp} after entering \c{/usr/tmp}. If
+ \a options includes DontResolveSymlinks, the file dialog treats
symlinks as regular directories.
- On Windows, the dialog will spin a blocking modal event loop that will not
- dispatch any QTimers, and if \a parent is not \nullptr then it will position
+ On Windows, the dialog spins a blocking modal event loop that does not
+ dispatch any QTimers, and if \a parent is not \nullptr then it positions
the dialog just below the parent's title bar.
\warning Do not delete \a parent during the execution of the dialog. If you
- want to do this, you should create the dialog yourself using one of the
+ want to do this, you must create the dialog yourself using one of the
QFileDialog constructors.
\sa getOpenFileName(), getOpenFileNames(), getSaveFileName()
@@ -2548,28 +2577,28 @@ QString QFileDialog::getExistingDirectory(QWidget *parent,
}
/*!
- This is a convenience static function that will return an existing
+ This is a convenience static function that returns an existing
directory selected by the user. If the user presses Cancel, it
returns an empty url.
The function is used similarly to QFileDialog::getExistingDirectory().
In particular \a parent, \a caption, \a dir and \a options are used
- in the exact same way.
+ in exactly the same way.
The main difference with QFileDialog::getExistingDirectory() comes from
the ability offered to the user to select a remote directory. That's why
the return type and the type of \a dir is QUrl.
The \a supportedSchemes argument allows to restrict the type of URLs the
- user will be able to select. It is a way for the application to declare
- the protocols it will support to fetch the file content. An empty list
+ user is able to select. It is a way for the application to declare
+ the protocols it supports to fetch the file content. An empty list
means that no restriction is applied (the default).
- Supported for local files ("file" scheme) is implicit and always enabled;
+ Support for local files ("file" scheme) is implicit and always enabled;
it is not necessary to include it in the restriction.
- When possible, this static function will use the native file dialog and
- not a QFileDialog. On platforms which don't support selecting remote
- files, Qt will allow to select only local files.
+ When possible, this static function uses the native file dialog and
+ not a QFileDialog. On platforms that don't support selecting remote
+ files, Qt allows to select only local files.
\sa getExistingDirectory(), getOpenFileUrl(), getOpenFileUrls(), getSaveFileUrl()
\since 5.2
@@ -2697,9 +2726,9 @@ void QFileDialog::accept()
const QList<QUrl> urls = selectedUrls();
if (urls.isEmpty())
return;
- d->_q_emitUrlsSelected(urls);
+ d->emitUrlsSelected(urls);
if (urls.size() == 1)
- d->_q_emitUrlSelected(urls.first());
+ d->emitUrlSelected(urls.first());
QDialog::accept();
return;
}
@@ -2711,7 +2740,7 @@ void QFileDialog::accept()
// "hidden feature" type .. and then enter, and it will move up a dir
// special case for ".."
if (lineEditText == ".."_L1) {
- d->_q_navigateToParent();
+ d->navigateToParent();
const QSignalBlocker blocker(d->qFileDialogUi->fileNameEdit);
d->lineEdit()->selectAll();
return;
@@ -2744,7 +2773,7 @@ void QFileDialog::accept()
}
if (!info.exists()) {
- int maxNameLength = d->maxNameLength(info.path());
+ const long maxNameLength = d->maxNameLength(info.path());
if (maxNameLength >= 0 && info.fileName().size() > maxNameLength)
return;
}
@@ -2880,7 +2909,7 @@ bool QFileDialogPrivate::restoreWidgetState(QStringList &history, int splitterPo
if (proxyModel)
abstractModel = proxyModel;
#endif
- int total = qMin(abstractModel->columnCount(QModelIndex()), actions.size() + 1);
+ const int total = qMin(abstractModel->columnCount(QModelIndex()), int(actions.size() + 1));
for (int i = 1; i < total; ++i)
actions.at(i - 1)->setChecked(!headerView->isSectionHidden(i));
@@ -2965,11 +2994,12 @@ void QFileDialogPrivate::createWidgets()
else
model->setNameFilterDisables(false);
model->d_func()->disableRecursiveSort = true;
- QFileDialog::connect(model, SIGNAL(fileRenamed(QString,QString,QString)), q, SLOT(_q_fileRenamed(QString,QString,QString)));
- QFileDialog::connect(model, SIGNAL(rootPathChanged(QString)),
- q, SLOT(_q_pathChanged(QString)));
- QFileDialog::connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
- q, SLOT(_q_rowsInserted(QModelIndex)));
+ QObjectPrivate::connect(model, &QFileSystemModel::fileRenamed,
+ this, &QFileDialogPrivate::fileRenamed);
+ QObjectPrivate::connect(model, &QFileSystemModel::rootPathChanged,
+ this, &QFileDialogPrivate::pathChanged);
+ QObjectPrivate::connect(model, &QFileSystemModel::rowsInserted,
+ this, &QFileDialogPrivate::rowsInserted);
model->setReadOnly(false);
qFileDialogUi.reset(new Ui_QFileDialog());
@@ -2979,14 +3009,17 @@ void QFileDialogPrivate::createWidgets()
initialBookmarks << QUrl("file:"_L1)
<< QUrl::fromLocalFile(QDir::homePath());
qFileDialogUi->sidebar->setModelAndUrls(model, initialBookmarks);
- QFileDialog::connect(qFileDialogUi->sidebar, SIGNAL(goToUrl(QUrl)),
- q, SLOT(_q_goToUrl(QUrl)));
+ QObjectPrivate::connect(qFileDialogUi->sidebar, &QSidebar::goToUrl,
+ this, &QFileDialogPrivate::goToUrl);
- QObject::connect(qFileDialogUi->buttonBox, SIGNAL(accepted()), q, SLOT(accept()));
- QObject::connect(qFileDialogUi->buttonBox, SIGNAL(rejected()), q, SLOT(reject()));
+ QObject::connect(qFileDialogUi->buttonBox, &QDialogButtonBox::accepted,
+ q, &QFileDialog::accept);
+ QObject::connect(qFileDialogUi->buttonBox, &QDialogButtonBox::rejected,
+ q, &QFileDialog::reject);
qFileDialogUi->lookInCombo->setFileDialogPrivate(this);
- QObject::connect(qFileDialogUi->lookInCombo, SIGNAL(textActivated(QString)), q, SLOT(_q_goToDirectory(QString)));
+ QObjectPrivate::connect(qFileDialogUi->lookInCombo, &QComboBox::textActivated,
+ this, &QFileDialogPrivate::goToDirectory);
qFileDialogUi->lookInCombo->setInsertPolicy(QComboBox::NoInsert);
qFileDialogUi->lookInCombo->setDuplicatesEnabled(false);
@@ -3003,31 +3036,32 @@ void QFileDialogPrivate::createWidgets()
qFileDialogUi->fileNameEdit->setInputMethodHints(Qt::ImhNoPredictiveText);
- QObject::connect(qFileDialogUi->fileNameEdit, SIGNAL(textChanged(QString)),
- q, SLOT(_q_autoCompleteFileName(QString)));
- QObject::connect(qFileDialogUi->fileNameEdit, SIGNAL(textChanged(QString)),
- q, SLOT(_q_updateOkButton()));
-
- QObject::connect(qFileDialogUi->fileNameEdit, SIGNAL(returnPressed()), q, SLOT(accept()));
+ QObjectPrivate::connect(qFileDialogUi->fileNameEdit, &QLineEdit::textChanged,
+ this, &QFileDialogPrivate::autoCompleteFileName);
+ QObjectPrivate::connect(qFileDialogUi->fileNameEdit, &QLineEdit::textChanged,
+ this, &QFileDialogPrivate::updateOkButton);
+ QObject::connect(qFileDialogUi->fileNameEdit, &QLineEdit::returnPressed,
+ q, &QFileDialog::accept);
// filetype
qFileDialogUi->fileTypeCombo->setDuplicatesEnabled(false);
qFileDialogUi->fileTypeCombo->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow);
qFileDialogUi->fileTypeCombo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
- QObject::connect(qFileDialogUi->fileTypeCombo, SIGNAL(activated(int)),
- q, SLOT(_q_useNameFilter(int)));
- QObject::connect(qFileDialogUi->fileTypeCombo, SIGNAL(textActivated(QString)),
- q, SIGNAL(filterSelected(QString)));
+ QObjectPrivate::connect(qFileDialogUi->fileTypeCombo, &QComboBox::activated,
+ this, &QFileDialogPrivate::useNameFilter);
+ QObject::connect(qFileDialogUi->fileTypeCombo, &QComboBox::textActivated,
+ q, &QFileDialog::filterSelected);
qFileDialogUi->listView->setFileDialogPrivate(this);
qFileDialogUi->listView->setModel(model);
- QObject::connect(qFileDialogUi->listView, SIGNAL(activated(QModelIndex)),
- q, SLOT(_q_enterDirectory(QModelIndex)));
- QObject::connect(qFileDialogUi->listView, SIGNAL(customContextMenuRequested(QPoint)),
- q, SLOT(_q_showContextMenu(QPoint)));
+ QObjectPrivate::connect(qFileDialogUi->listView, &QAbstractItemView::activated,
+ this, &QFileDialogPrivate::enterDirectory);
+ QObjectPrivate::connect(qFileDialogUi->listView, &QAbstractItemView::customContextMenuRequested,
+ this, &QFileDialogPrivate::showContextMenu);
#ifndef QT_NO_SHORTCUT
QShortcut *shortcut = new QShortcut(QKeySequence::Delete, qFileDialogUi->listView);
- QObject::connect(shortcut, SIGNAL(activated()), q, SLOT(_q_deleteCurrent()));
+ QObjectPrivate::connect(shortcut, &QShortcut::activated,
+ this, &QFileDialogPrivate::deleteCurrent);
#endif
qFileDialogUi->treeView->setFileDialogPrivate(this);
@@ -3042,8 +3076,8 @@ void QFileDialogPrivate::createWidgets()
QActionGroup *showActionGroup = new QActionGroup(q);
showActionGroup->setExclusive(false);
- QObject::connect(showActionGroup, SIGNAL(triggered(QAction*)),
- q, SLOT(_q_showHeader(QAction*)));;
+ QObjectPrivate::connect(showActionGroup, &QActionGroup::triggered,
+ this, &QFileDialogPrivate::showHeader);
QAbstractItemModel *abstractModel = model;
#if QT_CONFIG(proxymodel)
@@ -3060,21 +3094,22 @@ void QFileDialogPrivate::createWidgets()
QScopedPointer<QItemSelectionModel> selModel(qFileDialogUi->treeView->selectionModel());
qFileDialogUi->treeView->setSelectionModel(qFileDialogUi->listView->selectionModel());
- QObject::connect(qFileDialogUi->treeView, SIGNAL(activated(QModelIndex)),
- q, SLOT(_q_enterDirectory(QModelIndex)));
- QObject::connect(qFileDialogUi->treeView, SIGNAL(customContextMenuRequested(QPoint)),
- q, SLOT(_q_showContextMenu(QPoint)));
+ QObjectPrivate::connect(qFileDialogUi->treeView, &QAbstractItemView::activated,
+ this, &QFileDialogPrivate::enterDirectory);
+ QObjectPrivate::connect(qFileDialogUi->treeView, &QAbstractItemView::customContextMenuRequested,
+ this, &QFileDialogPrivate::showContextMenu);
#ifndef QT_NO_SHORTCUT
shortcut = new QShortcut(QKeySequence::Delete, qFileDialogUi->treeView);
- QObject::connect(shortcut, SIGNAL(activated()), q, SLOT(_q_deleteCurrent()));
+ QObjectPrivate::connect(shortcut, &QShortcut::activated,
+ this, &QFileDialogPrivate::deleteCurrent);
#endif
// Selections
QItemSelectionModel *selections = qFileDialogUi->listView->selectionModel();
- QObject::connect(selections, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
- q, SLOT(_q_selectionChanged()));
- QObject::connect(selections, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
- q, SLOT(_q_currentChanged(QModelIndex)));
+ QObjectPrivate::connect(selections, &QItemSelectionModel::selectionChanged,
+ this, &QFileDialogPrivate::selectionChanged);
+ QObjectPrivate::connect(selections, &QItemSelectionModel::currentChanged,
+ this, &QFileDialogPrivate::currentChanged);
qFileDialogUi->splitter->setStretchFactor(qFileDialogUi->splitter->indexOf(qFileDialogUi->splitter->widget(1)), QSizePolicy::Expanding);
createToolButtons();
@@ -3113,17 +3148,18 @@ void QFileDialogPrivate::createWidgets()
for (const QUrl &url : initiallySelectedFiles)
q->selectUrl(url);
lineEdit()->selectAll();
- _q_updateOkButton();
+ updateOkButton();
retranslateStrings();
q->resize(preSize.isValid() ? preSize : q->sizeHint());
q->setWindowState(preState);
}
-void QFileDialogPrivate::_q_showHeader(QAction *action)
+void QFileDialogPrivate::showHeader(QAction *action)
{
Q_Q(QFileDialog);
QActionGroup *actionGroup = qobject_cast<QActionGroup*>(q->sender());
- qFileDialogUi->treeView->header()->setSectionHidden(actionGroup->actions().indexOf(action) + 1, !action->isChecked());
+ qFileDialogUi->treeView->header()->setSectionHidden(int(actionGroup->actions().indexOf(action) + 1),
+ !action->isChecked());
}
#if QT_CONFIG(proxymodel)
@@ -3134,8 +3170,8 @@ void QFileDialogPrivate::_q_showHeader(QAction *action)
want to modify the underlying model; for example, to add columns, filter
data or add drives.
- Any existing proxy model will be removed, but not deleted. The file dialog
- will take ownership of the \a proxyModel.
+ Any existing proxy model is removed, but not deleted. The file dialog
+ takes ownership of the \a proxyModel.
\sa proxyModel()
*/
@@ -3149,13 +3185,12 @@ void QFileDialog::setProxyModel(QAbstractProxyModel *proxyModel)
return;
QModelIndex idx = d->rootIndex();
- if (d->proxyModel) {
- disconnect(d->proxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(_q_rowsInserted(QModelIndex)));
- } else {
- disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(_q_rowsInserted(QModelIndex)));
- }
+ if (d->proxyModel)
+ QObjectPrivate::disconnect(d->proxyModel, &QAbstractProxyModel::rowsInserted,
+ d, &QFileDialogPrivate::rowsInserted);
+ else
+ QObjectPrivate::disconnect(d->model, &QAbstractItemModel::rowsInserted,
+ d, &QFileDialogPrivate::rowsInserted);
if (proxyModel != nullptr) {
proxyModel->setParent(this);
@@ -3167,8 +3202,8 @@ void QFileDialog::setProxyModel(QAbstractProxyModel *proxyModel)
d->completer->setModel(d->proxyModel);
d->completer->proxyModel = d->proxyModel;
#endif
- connect(d->proxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(_q_rowsInserted(QModelIndex)));
+ QObjectPrivate::connect(d->proxyModel, &QAbstractItemModel::rowsInserted,
+ d, &QFileDialogPrivate::rowsInserted);
} else {
d->proxyModel = nullptr;
d->qFileDialogUi->listView->setModel(d->model);
@@ -3178,8 +3213,8 @@ void QFileDialog::setProxyModel(QAbstractProxyModel *proxyModel)
d->completer->sourceModel = d->model;
d->completer->proxyModel = nullptr;
#endif
- connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(_q_rowsInserted(QModelIndex)));
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsInserted,
+ d, &QFileDialogPrivate::rowsInserted);
}
QScopedPointer<QItemSelectionModel> selModel(d->qFileDialogUi->treeView->selectionModel());
d->qFileDialogUi->treeView->setSelectionModel(d->qFileDialogUi->listView->selectionModel());
@@ -3188,10 +3223,10 @@ void QFileDialog::setProxyModel(QAbstractProxyModel *proxyModel)
// reconnect selection
QItemSelectionModel *selections = d->qFileDialogUi->listView->selectionModel();
- QObject::connect(selections, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
- this, SLOT(_q_selectionChanged()));
- QObject::connect(selections, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
- this, SLOT(_q_currentChanged(QModelIndex)));
+ QObjectPrivate::connect(selections, &QItemSelectionModel::selectionChanged,
+ d, &QFileDialogPrivate::selectionChanged);
+ QObjectPrivate::connect(selections, &QItemSelectionModel::currentChanged,
+ d, &QFileDialogPrivate::currentChanged);
}
/*!
@@ -3217,26 +3252,31 @@ void QFileDialogPrivate::createToolButtons()
qFileDialogUi->backButton->setIcon(q->style()->standardIcon(QStyle::SP_ArrowBack, nullptr, q));
qFileDialogUi->backButton->setAutoRaise(true);
qFileDialogUi->backButton->setEnabled(false);
- QObject::connect(qFileDialogUi->backButton, SIGNAL(clicked()), q, SLOT(_q_navigateBackward()));
+ QObjectPrivate::connect(qFileDialogUi->backButton, &QPushButton::clicked,
+ this, &QFileDialogPrivate::navigateBackward);
qFileDialogUi->forwardButton->setIcon(q->style()->standardIcon(QStyle::SP_ArrowForward, nullptr, q));
qFileDialogUi->forwardButton->setAutoRaise(true);
qFileDialogUi->forwardButton->setEnabled(false);
- QObject::connect(qFileDialogUi->forwardButton, SIGNAL(clicked()), q, SLOT(_q_navigateForward()));
+ QObjectPrivate::connect(qFileDialogUi->forwardButton, &QPushButton::clicked,
+ this, &QFileDialogPrivate::navigateForward);
qFileDialogUi->toParentButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogToParent, nullptr, q));
qFileDialogUi->toParentButton->setAutoRaise(true);
qFileDialogUi->toParentButton->setEnabled(false);
- QObject::connect(qFileDialogUi->toParentButton, SIGNAL(clicked()), q, SLOT(_q_navigateToParent()));
+ QObjectPrivate::connect(qFileDialogUi->toParentButton, &QPushButton::clicked,
+ this, &QFileDialogPrivate::navigateToParent);
qFileDialogUi->listModeButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogListView, nullptr, q));
qFileDialogUi->listModeButton->setAutoRaise(true);
qFileDialogUi->listModeButton->setDown(true);
- QObject::connect(qFileDialogUi->listModeButton, SIGNAL(clicked()), q, SLOT(_q_showListView()));
+ QObjectPrivate::connect(qFileDialogUi->listModeButton, &QPushButton::clicked,
+ this, &QFileDialogPrivate::showListView);
qFileDialogUi->detailModeButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogDetailedView, nullptr, q));
qFileDialogUi->detailModeButton->setAutoRaise(true);
- QObject::connect(qFileDialogUi->detailModeButton, SIGNAL(clicked()), q, SLOT(_q_showDetailsView()));
+ QObjectPrivate::connect(qFileDialogUi->detailModeButton, &QPushButton::clicked,
+ this, &QFileDialogPrivate::showDetailsView);
QSize toolSize(qFileDialogUi->fileNameEdit->sizeHint().height(), qFileDialogUi->fileNameEdit->sizeHint().height());
qFileDialogUi->backButton->setFixedSize(toolSize);
@@ -3249,7 +3289,8 @@ void QFileDialogPrivate::createToolButtons()
qFileDialogUi->newFolderButton->setFixedSize(toolSize);
qFileDialogUi->newFolderButton->setAutoRaise(true);
qFileDialogUi->newFolderButton->setEnabled(false);
- QObject::connect(qFileDialogUi->newFolderButton, SIGNAL(clicked()), q, SLOT(_q_createDirectory()));
+ QObjectPrivate::connect(qFileDialogUi->newFolderButton, &QPushButton::clicked,
+ this, &QFileDialogPrivate::createDirectory);
}
/*!
@@ -3265,7 +3306,8 @@ void QFileDialogPrivate::createMenuActions()
#ifndef QT_NO_SHORTCUT
goHomeAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_H);
#endif
- QObject::connect(goHomeAction, SIGNAL(triggered()), q, SLOT(_q_goHome()));
+ QObjectPrivate::connect(goHomeAction, &QAction::triggered,
+ this, &QFileDialogPrivate::goHome);
q->addAction(goHomeAction);
// ### TODO add Desktop & Computer actions
@@ -3275,30 +3317,35 @@ void QFileDialogPrivate::createMenuActions()
#ifndef QT_NO_SHORTCUT
goToParent->setShortcut(Qt::CTRL | Qt::Key_Up);
#endif
- QObject::connect(goToParent, SIGNAL(triggered()), q, SLOT(_q_navigateToParent()));
+ QObjectPrivate::connect(goToParent, &QAction::triggered,
+ this, &QFileDialogPrivate::navigateToParent);
q->addAction(goToParent);
renameAction = new QAction(q);
renameAction->setEnabled(false);
renameAction->setObjectName("qt_rename_action"_L1);
- QObject::connect(renameAction, SIGNAL(triggered()), q, SLOT(_q_renameCurrent()));
+ QObjectPrivate::connect(renameAction, &QAction::triggered,
+ this, &QFileDialogPrivate::renameCurrent);
deleteAction = new QAction(q);
deleteAction->setEnabled(false);
deleteAction->setObjectName("qt_delete_action"_L1);
- QObject::connect(deleteAction, SIGNAL(triggered()), q, SLOT(_q_deleteCurrent()));
+ QObjectPrivate::connect(deleteAction, &QAction::triggered,
+ this, &QFileDialogPrivate::deleteCurrent);
showHiddenAction = new QAction(q);
showHiddenAction->setObjectName("qt_show_hidden_action"_L1);
showHiddenAction->setCheckable(true);
- QObject::connect(showHiddenAction, SIGNAL(triggered()), q, SLOT(_q_showHidden()));
+ QObjectPrivate::connect(showHiddenAction, &QAction::triggered,
+ this, &QFileDialogPrivate::showHidden);
newFolderAction = new QAction(q);
newFolderAction->setObjectName("qt_new_folder_action"_L1);
- QObject::connect(newFolderAction, SIGNAL(triggered()), q, SLOT(_q_createDirectory()));
+ QObjectPrivate::connect(newFolderAction, &QAction::triggered,
+ this, &QFileDialogPrivate::createDirectory);
}
-void QFileDialogPrivate::_q_goHome()
+void QFileDialogPrivate::goHome()
{
Q_Q(QFileDialog);
q->setDirectory(QDir::homePath());
@@ -3321,7 +3368,7 @@ void QFileDialogPrivate::saveHistorySelection()
Update history with new path, buttons, and combo
*/
-void QFileDialogPrivate::_q_pathChanged(const QString &newPath)
+void QFileDialogPrivate::pathChanged(const QString &newPath)
{
Q_Q(QFileDialog);
qFileDialogUi->toParentButton->setEnabled(QFileInfo::exists(model->rootPath()));
@@ -3365,8 +3412,10 @@ void QFileDialogPrivate::navigate(HistoryItem &historyItem)
| QItemSelectionModel::Rows;
selectionModel->select(historyItem.selection.constFirst(),
flags | QItemSelectionModel::Clear | QItemSelectionModel::Current);
- for (int i = 1, size = historyItem.selection.size(); i < size; ++i)
- selectionModel->select(historyItem.selection.at(i), flags);
+ auto it = historyItem.selection.cbegin() + 1;
+ const auto end = historyItem.selection.cend();
+ for (; it != end; ++it)
+ selectionModel->select(*it, flags);
view->scrollTo(historyItem.selection.constFirst());
}
@@ -3376,7 +3425,7 @@ void QFileDialogPrivate::navigate(HistoryItem &historyItem)
Navigates to the last directory viewed in the dialog.
*/
-void QFileDialogPrivate::_q_navigateBackward()
+void QFileDialogPrivate::navigateBackward()
{
if (!currentHistory.isEmpty() && currentHistoryLocation > 0) {
saveHistorySelection();
@@ -3389,7 +3438,7 @@ void QFileDialogPrivate::_q_navigateBackward()
Navigates to the last directory viewed in the dialog.
*/
-void QFileDialogPrivate::_q_navigateForward()
+void QFileDialogPrivate::navigateForward()
{
if (!currentHistory.isEmpty() && currentHistoryLocation < currentHistory.size() - 1) {
saveHistorySelection();
@@ -3403,7 +3452,7 @@ void QFileDialogPrivate::_q_navigateForward()
Navigates to the parent directory of the currently displayed directory
in the dialog.
*/
-void QFileDialogPrivate::_q_navigateToParent()
+void QFileDialogPrivate::navigateToParent()
{
Q_Q(QFileDialog);
QDir dir(model->rootDirectory());
@@ -3423,7 +3472,7 @@ void QFileDialogPrivate::_q_navigateToParent()
Creates a new directory, first asking the user for a suitable name.
*/
-void QFileDialogPrivate::_q_createDirectory()
+void QFileDialogPrivate::createDirectory()
{
Q_Q(QFileDialog);
qFileDialogUi->listView->clearSelection();
@@ -3450,7 +3499,7 @@ void QFileDialogPrivate::_q_createDirectory()
}
}
-void QFileDialogPrivate::_q_showListView()
+void QFileDialogPrivate::showListView()
{
qFileDialogUi->listModeButton->setDown(true);
qFileDialogUi->detailModeButton->setDown(false);
@@ -3460,7 +3509,7 @@ void QFileDialogPrivate::_q_showListView()
qFileDialogUi->listView->doItemsLayout();
}
-void QFileDialogPrivate::_q_showDetailsView()
+void QFileDialogPrivate::showDetailsView()
{
qFileDialogUi->listModeButton->setDown(false);
qFileDialogUi->detailModeButton->setDown(true);
@@ -3475,7 +3524,7 @@ void QFileDialogPrivate::_q_showDetailsView()
Show the context menu for the file/dir under position
*/
-void QFileDialogPrivate::_q_showContextMenu(const QPoint &position)
+void QFileDialogPrivate::showContextMenu(const QPoint &position)
{
#if !QT_CONFIG(menu)
Q_UNUSED(position);
@@ -3515,7 +3564,7 @@ void QFileDialogPrivate::_q_showContextMenu(const QPoint &position)
/*!
\internal
*/
-void QFileDialogPrivate::_q_renameCurrent()
+void QFileDialogPrivate::renameCurrent()
{
Q_Q(QFileDialog);
QModelIndex index = qFileDialogUi->listView->currentIndex();
@@ -3537,14 +3586,14 @@ bool QFileDialogPrivate::removeDirectory(const QString &path)
Deletes the currently selected item in the dialog.
*/
-void QFileDialogPrivate::_q_deleteCurrent()
+void QFileDialogPrivate::deleteCurrent()
{
if (model->isReadOnly())
return;
- QModelIndexList list = qFileDialogUi->listView->selectionModel()->selectedRows();
- for (int i = list.size() - 1; i >= 0; --i) {
- QPersistentModelIndex index = list.at(i);
+ const QModelIndexList list = qFileDialogUi->listView->selectionModel()->selectedRows();
+ for (auto it = list.crbegin(), end = list.crend(); it != end; ++it) {
+ QPersistentModelIndex index = *it;
if (index == qFileDialogUi->listView->rootIndex())
continue;
@@ -3591,7 +3640,7 @@ void QFileDialogPrivate::_q_deleteCurrent()
}
}
-void QFileDialogPrivate::_q_autoCompleteFileName(const QString &text)
+void QFileDialogPrivate::autoCompleteFileName(const QString &text)
{
if (text.startsWith("//"_L1) || text.startsWith(u'\\')) {
qFileDialogUi->listView->selectionModel()->clearSelection();
@@ -3620,7 +3669,7 @@ void QFileDialogPrivate::_q_autoCompleteFileName(const QString &text)
/*!
\internal
*/
-void QFileDialogPrivate::_q_updateOkButton()
+void QFileDialogPrivate::updateOkButton()
{
Q_Q(QFileDialog);
QPushButton *button = qFileDialogUi->buttonBox->button((q->acceptMode() == QFileDialog::AcceptOpen)
@@ -3683,7 +3732,7 @@ void QFileDialogPrivate::_q_updateOkButton()
break;
}
if (!idx.isValid()) {
- int maxLength = maxNameLength(fileDir);
+ const long maxLength = maxNameLength(fileDir);
enableButton = maxLength < 0 || fileName.size() <= maxLength;
}
break;
@@ -3716,9 +3765,9 @@ void QFileDialogPrivate::_q_updateOkButton()
/*!
\internal
*/
-void QFileDialogPrivate::_q_currentChanged(const QModelIndex &index)
+void QFileDialogPrivate::currentChanged(const QModelIndex &index)
{
- _q_updateOkButton();
+ updateOkButton();
emit q_func()->currentChanged(index.data(QFileSystemModel::FilePathRole).toString());
}
@@ -3728,7 +3777,7 @@ void QFileDialogPrivate::_q_currentChanged(const QModelIndex &index)
This is called when the user double clicks on a file with the corresponding
model item \a index.
*/
-void QFileDialogPrivate::_q_enterDirectory(const QModelIndex &index)
+void QFileDialogPrivate::enterDirectory(const QModelIndex &index)
{
Q_Q(QFileDialog);
// My Computer or a directory
@@ -3745,8 +3794,9 @@ void QFileDialogPrivate::_q_enterDirectory(const QModelIndex &index)
}
} else {
// Do not accept when shift-clicking to multi-select a file in environments with single-click-activation (KDE)
- if (!q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, qFileDialogUi->treeView)
- || q->fileMode() != QFileDialog::ExistingFiles || !(QGuiApplication::keyboardModifiers() & Qt::CTRL)) {
+ if ((!q->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, qFileDialogUi->treeView)
+ || q->fileMode() != QFileDialog::ExistingFiles || !(QGuiApplication::keyboardModifiers() & Qt::CTRL))
+ && index.model()->flags(index) & Qt::ItemIsEnabled) {
q->accept();
}
}
@@ -3758,7 +3808,7 @@ void QFileDialogPrivate::_q_enterDirectory(const QModelIndex &index)
Changes the file dialog's current directory to the one specified
by \a path.
*/
-void QFileDialogPrivate::_q_goToDirectory(const QString &path)
+void QFileDialogPrivate::goToDirectory(const QString &path)
{
enum { UrlRole = Qt::UserRole + 1 };
@@ -3780,7 +3830,7 @@ void QFileDialogPrivate::_q_goToDirectory(const QString &path)
dir.setPath(getEnvironmentVariable(path2));
if (dir.exists() || path2.isEmpty() || path2 == model->myComputer().toString()) {
- _q_enterDirectory(index);
+ enterDirectory(index);
#if QT_CONFIG(messagebox)
} else {
QString message = QFileDialog::tr("%1\nDirectory not found.\nPlease verify the "
@@ -3796,7 +3846,7 @@ void QFileDialogPrivate::_q_goToDirectory(const QString &path)
Sets the current name filter to be nameFilter and
update the qFileDialogUi->fileNameEdit when in AcceptSave mode with the new extension.
*/
-void QFileDialogPrivate::_q_useNameFilter(int index)
+void QFileDialogPrivate::useNameFilter(int index)
{
QStringList nameFilters = options->nameFilters();
if (index == nameFilters.size()) {
@@ -3815,7 +3865,7 @@ void QFileDialogPrivate::_q_useNameFilter(int index)
QString fileName = lineEdit()->text();
const QString fileNameExtension = QFileInfo(fileName).suffix();
if (!fileNameExtension.isEmpty() && !newNameFilterExtension.isEmpty()) {
- const int fileNameExtensionLength = fileNameExtension.size();
+ const qsizetype fileNameExtensionLength = fileNameExtension.size();
fileName.replace(fileName.size() - fileNameExtensionLength,
fileNameExtensionLength, newNameFilterExtension);
qFileDialogUi->listView->clearSelection();
@@ -3832,7 +3882,7 @@ void QFileDialogPrivate::_q_useNameFilter(int index)
This is called when the model index corresponding to the current file is changed
from \a index to \a current.
*/
-void QFileDialogPrivate::_q_selectionChanged()
+void QFileDialogPrivate::selectionChanged()
{
const QFileDialog::FileMode fileMode = q_func()->fileMode();
const QModelIndexList indexes = qFileDialogUi->listView->selectionModel()->selectedRows();
@@ -3853,7 +3903,7 @@ void QFileDialogPrivate::_q_selectionChanged()
if (!finalFiles.isEmpty() && !lineEdit()->hasFocus() && lineEdit()->isVisible())
lineEdit()->setText(finalFiles);
else
- _q_updateOkButton();
+ updateOkButton();
}
/*!
@@ -3861,7 +3911,7 @@ void QFileDialogPrivate::_q_selectionChanged()
Includes hidden files and directories in the items displayed in the dialog.
*/
-void QFileDialogPrivate::_q_showHidden()
+void QFileDialogPrivate::showHidden()
{
Q_Q(QFileDialog);
QDir::Filters dirFilters = q->filter();
@@ -3875,7 +3925,7 @@ void QFileDialogPrivate::_q_showHidden()
When parent is root and rows have been inserted when none was there before
then select the first one.
*/
-void QFileDialogPrivate::_q_rowsInserted(const QModelIndex &parent)
+void QFileDialogPrivate::rowsInserted(const QModelIndex &parent)
{
if (!qFileDialogUi->treeView
|| parent != qFileDialogUi->treeView->rootIndex()
@@ -3885,7 +3935,7 @@ void QFileDialogPrivate::_q_rowsInserted(const QModelIndex &parent)
return;
}
-void QFileDialogPrivate::_q_fileRenamed(const QString &path, const QString &oldName, const QString &newName)
+void QFileDialogPrivate::fileRenamed(const QString &path, const QString &oldName, const QString &newName)
{
const QFileDialog::FileMode fileMode = q_func()->fileMode();
if (fileMode == QFileDialog::Directory) {
@@ -3894,7 +3944,7 @@ void QFileDialogPrivate::_q_fileRenamed(const QString &path, const QString &oldN
}
}
-void QFileDialogPrivate::_q_emitUrlSelected(const QUrl &file)
+void QFileDialogPrivate::emitUrlSelected(const QUrl &file)
{
Q_Q(QFileDialog);
emit q->urlSelected(file);
@@ -3902,7 +3952,7 @@ void QFileDialogPrivate::_q_emitUrlSelected(const QUrl &file)
emit q->fileSelected(file.toLocalFile());
}
-void QFileDialogPrivate::_q_emitUrlsSelected(const QList<QUrl> &files)
+void QFileDialogPrivate::emitUrlsSelected(const QList<QUrl> &files)
{
Q_Q(QFileDialog);
emit q->urlsSelected(files);
@@ -3914,7 +3964,7 @@ void QFileDialogPrivate::_q_emitUrlsSelected(const QList<QUrl> &files)
emit q->filesSelected(localFiles);
}
-void QFileDialogPrivate::_q_nativeCurrentChanged(const QUrl &file)
+void QFileDialogPrivate::nativeCurrentChanged(const QUrl &file)
{
Q_Q(QFileDialog);
emit q->currentUrlChanged(file);
@@ -3922,7 +3972,7 @@ void QFileDialogPrivate::_q_nativeCurrentChanged(const QUrl &file)
emit q->currentChanged(file.toLocalFile());
}
-void QFileDialogPrivate::_q_nativeEnterDirectory(const QUrl &directory)
+void QFileDialogPrivate::nativeEnterDirectory(const QUrl &directory)
{
Q_Q(QFileDialog);
emit q->directoryUrlEntered(directory);
@@ -3951,7 +4001,7 @@ bool QFileDialogPrivate::itemViewKeyboardEvent(QKeyEvent *event) {
#endif
switch (event->key()) {
case Qt::Key_Backspace:
- _q_navigateToParent();
+ navigateToParent();
return true;
case Qt::Key_Back:
#ifdef QT_KEYPAD_NAVIGATION
@@ -3960,7 +4010,7 @@ bool QFileDialogPrivate::itemViewKeyboardEvent(QKeyEvent *event) {
#endif
case Qt::Key_Left:
if (event->key() == Qt::Key_Back || event->modifiers() == Qt::AltModifier) {
- _q_navigateBackward();
+ navigateBackward();
return true;
}
break;
diff --git a/src/widgets/dialogs/qfiledialog.h b/src/widgets/dialogs/qfiledialog.h
index 970bddb359..d59392753a 100644
--- a/src/widgets/dialogs/qfiledialog.h
+++ b/src/widgets/dialogs/qfiledialog.h
@@ -213,8 +213,20 @@ public:
const QStringList &supportedSchemes = QStringList());
static void getOpenFileContent(const QString &nameFilter,
+ const std::function<void(const QString &, const QByteArray &)> &fileContentsReady,
+ QWidget *parent= nullptr);
+
+ static void saveFileContent(const QByteArray &fileContent,
+ const QString &fileNameHint,
+ QWidget *parent = nullptr);
+
+#if QT_WIDGETS_REMOVED_SINCE(6, 7)
+ static void getOpenFileContent(const QString &nameFilter,
const std::function<void(const QString &, const QByteArray &)> &fileContentsReady);
- static void saveFileContent(const QByteArray &fileContent, const QString &fileNameHint = QString());
+ static void saveFileContent(const QByteArray &fileContent,
+ const QString &fileNameHint = QString());
+#endif
+
protected:
QFileDialog(const QFileDialogArgs &args);
@@ -226,36 +238,6 @@ private:
Q_DECLARE_PRIVATE(QFileDialog)
Q_DISABLE_COPY(QFileDialog)
- Q_PRIVATE_SLOT(d_func(), void _q_pathChanged(const QString &))
-
- Q_PRIVATE_SLOT(d_func(), void _q_navigateBackward())
- Q_PRIVATE_SLOT(d_func(), void _q_navigateForward())
- Q_PRIVATE_SLOT(d_func(), void _q_navigateToParent())
- Q_PRIVATE_SLOT(d_func(), void _q_createDirectory())
- Q_PRIVATE_SLOT(d_func(), void _q_showListView())
- Q_PRIVATE_SLOT(d_func(), void _q_showDetailsView())
- Q_PRIVATE_SLOT(d_func(), void _q_showContextMenu(const QPoint &))
- Q_PRIVATE_SLOT(d_func(), void _q_renameCurrent())
- Q_PRIVATE_SLOT(d_func(), void _q_deleteCurrent())
- Q_PRIVATE_SLOT(d_func(), void _q_showHidden())
- Q_PRIVATE_SLOT(d_func(), void _q_updateOkButton())
- Q_PRIVATE_SLOT(d_func(), void _q_currentChanged(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_enterDirectory(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitUrlSelected(const QUrl &))
- Q_PRIVATE_SLOT(d_func(), void _q_emitUrlsSelected(const QList<QUrl> &))
- Q_PRIVATE_SLOT(d_func(), void _q_nativeCurrentChanged(const QUrl &))
- Q_PRIVATE_SLOT(d_func(), void _q_nativeEnterDirectory(const QUrl&))
- Q_PRIVATE_SLOT(d_func(), void _q_goToDirectory(const QString &path))
- Q_PRIVATE_SLOT(d_func(), void _q_useNameFilter(int index))
- Q_PRIVATE_SLOT(d_func(), void _q_selectionChanged())
- Q_PRIVATE_SLOT(d_func(), void _q_goToUrl(const QUrl &url))
- Q_PRIVATE_SLOT(d_func(), void _q_goHome())
- Q_PRIVATE_SLOT(d_func(), void _q_showHeader(QAction *))
- Q_PRIVATE_SLOT(d_func(), void _q_autoCompleteFileName(const QString &text))
- Q_PRIVATE_SLOT(d_func(), void _q_rowsInserted(const QModelIndex & parent))
- Q_PRIVATE_SLOT(d_func(), void _q_fileRenamed(const QString &path,
- const QString &oldName,
- const QString &newName))
friend class QPlatformDialogHelper;
};
diff --git a/src/widgets/dialogs/qfiledialog_p.h b/src/widgets/dialogs/qfiledialog_p.h
index c2111415f5..d5ee1c537b 100644
--- a/src/widgets/dialogs/qfiledialog_p.h
+++ b/src/widgets/dialogs/qfiledialog_p.h
@@ -120,11 +120,11 @@ public:
QLineEdit *lineEdit() const;
- static int maxNameLength(const QString &path);
+ static long maxNameLength(const QString &path);
QString basename(const QString &path) const
{
- int separator = QDir::toNativeSeparators(path).lastIndexOf(QDir::separator());
+ const qsizetype separator = QDir::toNativeSeparators(path).lastIndexOf(QDir::separator());
if (separator != -1)
return path.mid(separator + 1);
return path;
@@ -163,34 +163,34 @@ public:
void emitFilesSelected(const QStringList &files);
void saveHistorySelection();
- void _q_goHome();
- void _q_pathChanged(const QString &);
+ void goHome();
+ void pathChanged(const QString &);
void navigate(HistoryItem &);
- void _q_navigateBackward();
- void _q_navigateForward();
- void _q_navigateToParent();
- void _q_createDirectory();
- void _q_showListView();
- void _q_showDetailsView();
- void _q_showContextMenu(const QPoint &position);
- void _q_renameCurrent();
- void _q_deleteCurrent();
- void _q_showHidden();
- void _q_showHeader(QAction *);
- void _q_updateOkButton();
- void _q_currentChanged(const QModelIndex &index);
- void _q_enterDirectory(const QModelIndex &index);
- void _q_emitUrlSelected(const QUrl &file);
- void _q_emitUrlsSelected(const QList<QUrl> &files);
- void _q_nativeCurrentChanged(const QUrl &file);
- void _q_nativeEnterDirectory(const QUrl &directory);
- void _q_goToDirectory(const QString &);
- void _q_useNameFilter(int index);
- void _q_selectionChanged();
- void _q_goToUrl(const QUrl &url);
- void _q_autoCompleteFileName(const QString &);
- void _q_rowsInserted(const QModelIndex & parent);
- void _q_fileRenamed(const QString &path, const QString &oldName, const QString &newName);
+ void navigateBackward();
+ void navigateForward();
+ void navigateToParent();
+ void createDirectory();
+ void showListView();
+ void showDetailsView();
+ void showContextMenu(const QPoint &position);
+ void renameCurrent();
+ void deleteCurrent();
+ void showHidden();
+ void showHeader(QAction *);
+ void updateOkButton();
+ void currentChanged(const QModelIndex &index);
+ void enterDirectory(const QModelIndex &index);
+ void emitUrlSelected(const QUrl &file);
+ void emitUrlsSelected(const QList<QUrl> &files);
+ void nativeCurrentChanged(const QUrl &file);
+ void nativeEnterDirectory(const QUrl &directory);
+ void goToDirectory(const QString &);
+ void useNameFilter(int index);
+ void selectionChanged();
+ void goToUrl(const QUrl &url);
+ void autoCompleteFileName(const QString &);
+ void rowsInserted(const QModelIndex & parent);
+ void fileRenamed(const QString &path, const QString &oldName, const QString &newName);
// layout
#if QT_CONFIG(proxymodel)
@@ -221,6 +221,7 @@ public:
// dialog. Returning false means that a non-native dialog must be
// used instead.
bool canBeNativeDialog() const override;
+ void setVisible(bool visible) override;
inline bool usingWidgets() const;
inline void setDirectory_sys(const QUrl &directory);
diff --git a/src/widgets/dialogs/qfontdialog.cpp b/src/widgets/dialogs/qfontdialog.cpp
index 45853e153f..628297d22b 100644
--- a/src/widgets/dialogs/qfontdialog.cpp
+++ b/src/widgets/dialogs/qfontdialog.cpp
@@ -208,14 +208,21 @@ void QFontDialogPrivate::init()
size = 0;
smoothScalable = false;
- QObject::connect(writingSystemCombo, SIGNAL(activated(int)), q, SLOT(_q_writingSystemHighlighted(int)));
- QObject::connect(familyList, SIGNAL(highlighted(int)), q, SLOT(_q_familyHighlighted(int)));
- QObject::connect(styleList, SIGNAL(highlighted(int)), q, SLOT(_q_styleHighlighted(int)));
- QObject::connect(sizeList, SIGNAL(highlighted(int)), q, SLOT(_q_sizeHighlighted(int)));
- QObject::connect(sizeEdit, SIGNAL(textChanged(QString)), q, SLOT(_q_sizeChanged(QString)));
-
- QObject::connect(strikeout, SIGNAL(clicked()), q, SLOT(_q_updateSample()));
- QObject::connect(underline, SIGNAL(clicked()), q, SLOT(_q_updateSample()));
+ QObjectPrivate::connect(writingSystemCombo, &QComboBox::activated,
+ this, &QFontDialogPrivate::writingSystemHighlighted);
+ QObjectPrivate::connect(familyList, &QFontListView::highlighted,
+ this, &QFontDialogPrivate::familyHighlighted);
+ QObjectPrivate::connect(styleList, &QFontListView::highlighted,
+ this, &QFontDialogPrivate::styleHighlighted);
+ QObjectPrivate::connect(sizeList, &QFontListView::highlighted,
+ this, &QFontDialogPrivate::sizeHighlighted);
+ QObjectPrivate::connect(sizeEdit, &QLineEdit::textChanged,
+ this, &QFontDialogPrivate::sizeChanged);
+
+ QObjectPrivate::connect(strikeout, &QCheckBox::clicked,
+ this, &QFontDialogPrivate::updateSample);
+ QObjectPrivate::connect(underline, &QCheckBox::clicked, this,
+ &QFontDialogPrivate::updateSample);
for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
QFontDatabase::WritingSystem ws = QFontDatabase::WritingSystem(i);
@@ -277,11 +284,11 @@ void QFontDialogPrivate::init()
QPushButton *button
= static_cast<QPushButton *>(buttonBox->addButton(QDialogButtonBox::Ok));
- QObject::connect(buttonBox, SIGNAL(accepted()), q, SLOT(accept()));
+ QObject::connect(buttonBox, &QDialogButtonBox::accepted, q, &QDialog::accept);
button->setDefault(true);
buttonBox->addButton(QDialogButtonBox::Cancel);
- QObject::connect(buttonBox, SIGNAL(rejected()), q, SLOT(reject()));
+ QObject::connect(buttonBox, &QDialogButtonBox::rejected, q, &QDialog::reject);
q->resize(500, 360);
@@ -430,8 +437,10 @@ void QFontDialogPrivate::initHelper(QPlatformDialogHelper *h)
auto *fontDialogHelper = static_cast<QPlatformFontDialogHelper *>(h);
fontDialogHelper->setOptions(options);
fontDialogHelper->setCurrentFont(q->currentFont());
- QObject::connect(h, SIGNAL(currentFontChanged(QFont)), q, SIGNAL(currentFontChanged(QFont)));
- QObject::connect(h, SIGNAL(fontSelected(QFont)), q, SIGNAL(fontSelected(QFont)));
+ QObject::connect(fontDialogHelper, &QPlatformFontDialogHelper::currentFontChanged,
+ q, &QFontDialog::currentFontChanged);
+ QObject::connect(fontDialogHelper, &QPlatformFontDialogHelper::fontSelected,
+ q, &QFontDialog::fontSelected);
}
void QFontDialogPrivate::helperPrepareShow(QPlatformDialogHelper *)
@@ -500,9 +509,9 @@ void QFontDialogPrivate::updateFamilies()
//and try some fall backs
match_t type = MATCH_NONE;
- if (bestFamilyType <= MATCH_NONE && familyName2 == QStringLiteral("helvetica"))
+ if (bestFamilyType <= MATCH_NONE && familyName2 == "helvetica"_L1)
type = MATCH_LAST_RESORT;
- if (bestFamilyType <= MATCH_LAST_RESORT && familyName2 == f.families().first())
+ if (bestFamilyType <= MATCH_LAST_RESORT && familyName2 == f.families().constFirst())
type = MATCH_APP;
// ### add fallback for writingSystem
if (type != MATCH_NONE) {
@@ -622,10 +631,10 @@ void QFontDialogPrivate::updateSizes()
sizeEdit->clear();
}
- _q_updateSample();
+ updateSample();
}
-void QFontDialogPrivate::_q_updateSample()
+void QFontDialogPrivate::updateSample()
{
// compute new font
int pSize = sizeEdit->text().toInt();
@@ -651,7 +660,7 @@ void QFontDialogPrivate::updateSampleFont(const QFont &newFont)
/*!
\internal
*/
-void QFontDialogPrivate::_q_writingSystemHighlighted(int index)
+void QFontDialogPrivate::writingSystemHighlighted(int index)
{
writingSystem = QFontDatabase::WritingSystem(index);
sampleEdit->setText(QFontDatabase::writingSystemSample(writingSystem));
@@ -661,7 +670,7 @@ void QFontDialogPrivate::_q_writingSystemHighlighted(int index)
/*!
\internal
*/
-void QFontDialogPrivate::_q_familyHighlighted(int i)
+void QFontDialogPrivate::familyHighlighted(int i)
{
Q_Q(QFontDialog);
family = familyList->text(i);
@@ -678,7 +687,7 @@ void QFontDialogPrivate::_q_familyHighlighted(int i)
\internal
*/
-void QFontDialogPrivate::_q_styleHighlighted(int index)
+void QFontDialogPrivate::styleHighlighted(int index)
{
Q_Q(QFontDialog);
QString s = styleList->text(index);
@@ -697,7 +706,7 @@ void QFontDialogPrivate::_q_styleHighlighted(int index)
\internal
*/
-void QFontDialogPrivate::_q_sizeHighlighted(int index)
+void QFontDialogPrivate::sizeHighlighted(int index)
{
Q_Q(QFontDialog);
QString s = sizeList->text(index);
@@ -707,7 +716,7 @@ void QFontDialogPrivate::_q_sizeHighlighted(int index)
sizeEdit->selectAll();
size = s.toInt();
- _q_updateSample();
+ updateSample();
}
/*!
@@ -716,7 +725,7 @@ void QFontDialogPrivate::_q_sizeHighlighted(int index)
The size is passed in the \a s argument as a \e string.
*/
-void QFontDialogPrivate::_q_sizeChanged(const QString &s)
+void QFontDialogPrivate::sizeChanged(const QString &s)
{
// no need to check if the conversion is valid, since we have an QIntValidator in the size edit
int size = s.toInt();
@@ -736,7 +745,7 @@ void QFontDialogPrivate::_q_sizeChanged(const QString &s)
else
sizeList->clearSelection();
}
- _q_updateSample();
+ updateSample();
}
void QFontDialogPrivate::retranslateStrings()
@@ -960,19 +969,31 @@ void QFontDialog::open(QObject *receiver, const char *member)
*/
void QFontDialog::setVisible(bool visible)
{
- if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden) != visible)
- return;
- Q_D(QFontDialog);
- if (d->canBeNativeDialog())
- d->setNativeDialogVisible(visible);
- if (d->nativeDialogInUse) {
+ // will call QFontDialogPrivate::setVisible
+ QDialog::setVisible(visible);
+}
+
+/*!
+ \internal
+
+ The implementation of QFontDialog::setVisible() has to live here so that the call
+ to hide() in ~QDialog calls this function; it wouldn't call the override of
+ QDialog::setVisible().
+*/
+void QFontDialogPrivate::setVisible(bool visible)
+{
+ Q_Q(QFontDialog);
+
+ if (canBeNativeDialog())
+ setNativeDialogVisible(visible);
+ if (nativeDialogInUse) {
// Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below
// updates the state correctly, but skips showing the non-native version:
- setAttribute(Qt::WA_DontShowOnScreen, true);
+ q->setAttribute(Qt::WA_DontShowOnScreen, true);
} else {
- setAttribute(Qt::WA_DontShowOnScreen, false);
+ q->setAttribute(Qt::WA_DontShowOnScreen, false);
}
- QDialog::setVisible(visible);
+ QDialogPrivate::setVisible(visible);
}
/*!
diff --git a/src/widgets/dialogs/qfontdialog.h b/src/widgets/dialogs/qfontdialog.h
index 56f719796b..b2900d6a6b 100644
--- a/src/widgets/dialogs/qfontdialog.h
+++ b/src/widgets/dialogs/qfontdialog.h
@@ -70,13 +70,6 @@ protected:
private:
Q_DISABLE_COPY(QFontDialog)
-
- Q_PRIVATE_SLOT(d_func(), void _q_sizeChanged(const QString &))
- Q_PRIVATE_SLOT(d_func(), void _q_familyHighlighted(int))
- Q_PRIVATE_SLOT(d_func(), void _q_writingSystemHighlighted(int))
- Q_PRIVATE_SLOT(d_func(), void _q_styleHighlighted(int))
- Q_PRIVATE_SLOT(d_func(), void _q_sizeHighlighted(int))
- Q_PRIVATE_SLOT(d_func(), void _q_updateSample())
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QFontDialog::FontDialogOptions)
diff --git a/src/widgets/dialogs/qfontdialog_p.h b/src/widgets/dialogs/qfontdialog_p.h
index 4b3b45a9be..89b795f35e 100644
--- a/src/widgets/dialogs/qfontdialog_p.h
+++ b/src/widgets/dialogs/qfontdialog_p.h
@@ -21,6 +21,8 @@
#include "qfontdatabase.h"
#include "qfontdialog.h"
#include <qpa/qplatformdialoghelper.h>
+
+#include <QtCore/qpointer.h>
#include "qsharedpointer.h"
QT_REQUIRE_CONFIG(fontdialog);
@@ -55,12 +57,12 @@ public:
const QString &title, QFontDialog::FontDialogOptions options);
void init();
- void _q_sizeChanged(const QString &);
- void _q_familyHighlighted(int);
- void _q_writingSystemHighlighted(int);
- void _q_styleHighlighted(int);
- void _q_sizeHighlighted(int);
- void _q_updateSample();
+ void sizeChanged(const QString &);
+ void familyHighlighted(int);
+ void writingSystemHighlighted(int);
+ void styleHighlighted(int);
+ void sizeHighlighted(int);
+ void updateSample();
void updateSampleFont(const QFont &newFont);
void retranslateStrings();
@@ -105,6 +107,7 @@ public:
QByteArray memberToDisconnectOnClose;
bool canBeNativeDialog() const override;
+ void setVisible(bool visible) override;
void _q_runNativeAppModalPanel();
private:
diff --git a/src/widgets/dialogs/qinputdialog.cpp b/src/widgets/dialogs/qinputdialog.cpp
index 89ea6e6746..6d1a0b2873 100644
--- a/src/widgets/dialogs/qinputdialog.cpp
+++ b/src/widgets/dialogs/qinputdialog.cpp
@@ -18,6 +18,8 @@
#include "qevent.h"
#include "qdialog_p.h"
+#include <QtCore/qpointer.h>
+
QT_USE_NAMESPACE
enum CandidateSignal {
@@ -68,8 +70,10 @@ class QInputDialogSpinBox : public QSpinBox
public:
QInputDialogSpinBox(QWidget *parent)
: QSpinBox(parent) {
- connect(lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(notifyTextChanged()));
- connect(this, SIGNAL(editingFinished()), this, SLOT(notifyTextChanged()));
+ connect(lineEdit(), &QLineEdit::textChanged,
+ this, &QInputDialogSpinBox::notifyTextChanged);
+ connect(this, &QInputDialogSpinBox::editingFinished,
+ this, &QInputDialogSpinBox::notifyTextChanged);
}
signals:
@@ -101,8 +105,10 @@ class QInputDialogDoubleSpinBox : public QDoubleSpinBox
public:
QInputDialogDoubleSpinBox(QWidget *parent = nullptr)
: QDoubleSpinBox(parent) {
- connect(lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(notifyTextChanged()));
- connect(this, SIGNAL(editingFinished()), this, SLOT(notifyTextChanged()));
+ connect(lineEdit(), &QLineEdit::textChanged,
+ this, &QInputDialogDoubleSpinBox::notifyTextChanged);
+ connect(this, &QInputDialogDoubleSpinBox::editingFinished,
+ this, &QInputDialogDoubleSpinBox::notifyTextChanged);
}
signals:
@@ -161,9 +167,9 @@ public:
QString listViewText() const;
void ensureLayout() const { const_cast<QInputDialogPrivate *>(this)->ensureLayout(); }
bool useComboBoxOrListView() const { return comboBox && comboBox->count() > 0; }
- void _q_textChanged(const QString &text);
- void _q_plainTextEditTextChanged();
- void _q_currentRowChanged(const QModelIndex &newIndex, const QModelIndex &oldIndex);
+ void textChanged(const QString &text);
+ void plainTextEditTextChanged();
+ void currentRowChanged(const QModelIndex &newIndex, const QModelIndex &oldIndex);
mutable QLabel *label;
mutable QDialogButtonBox *buttonBox;
@@ -207,8 +213,8 @@ void QInputDialogPrivate::ensureLayout()
label->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, q);
- QObject::connect(buttonBox, SIGNAL(accepted()), q, SLOT(accept()));
- QObject::connect(buttonBox, SIGNAL(rejected()), q, SLOT(reject()));
+ QObject::connect(buttonBox, &QDialogButtonBox::accepted, q, &QDialog::accept);
+ QObject::connect(buttonBox, &QDialogButtonBox::rejected, q, &QDialog::reject);
mainLayout = new QVBoxLayout(q);
mainLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
@@ -228,8 +234,8 @@ void QInputDialogPrivate::ensureLineEdit()
qt_widget_private(lineEdit)->inheritsInputMethodHints = 1;
#endif
lineEdit->hide();
- QObject::connect(lineEdit, SIGNAL(textChanged(QString)),
- q, SLOT(_q_textChanged(QString)));
+ QObjectPrivate::connect(lineEdit, &QLineEdit::textChanged,
+ this, &QInputDialogPrivate::textChanged);
}
}
@@ -243,8 +249,8 @@ void QInputDialogPrivate::ensurePlainTextEdit()
qt_widget_private(plainTextEdit)->inheritsInputMethodHints = 1;
#endif
plainTextEdit->hide();
- QObject::connect(plainTextEdit, SIGNAL(textChanged()),
- q, SLOT(_q_plainTextEditTextChanged()));
+ QObjectPrivate::connect(plainTextEdit, &QPlainTextEdit::textChanged,
+ this, &QInputDialogPrivate::plainTextEditTextChanged);
}
}
@@ -257,10 +263,10 @@ void QInputDialogPrivate::ensureComboBox()
qt_widget_private(comboBox)->inheritsInputMethodHints = 1;
#endif
comboBox->hide();
- QObject::connect(comboBox, SIGNAL(editTextChanged(QString)),
- q, SLOT(_q_textChanged(QString)));
- QObject::connect(comboBox, SIGNAL(currentTextChanged(QString)),
- q, SLOT(_q_textChanged(QString)));
+ QObjectPrivate::connect(comboBox, &QComboBox::editTextChanged,
+ this, &QInputDialogPrivate::textChanged);
+ QObjectPrivate::connect(comboBox, &QComboBox::currentTextChanged,
+ this, &QInputDialogPrivate::textChanged);
}
}
@@ -275,9 +281,9 @@ void QInputDialogPrivate::ensureListView()
listView->setSelectionMode(QAbstractItemView::SingleSelection);
listView->setModel(comboBox->model());
listView->setCurrentIndex(QModelIndex()); // ###
- QObject::connect(listView->selectionModel(),
- SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
- q, SLOT(_q_currentRowChanged(QModelIndex,QModelIndex)));
+ QObjectPrivate::connect(listView->selectionModel(),
+ &QItemSelectionModel::currentRowChanged,
+ this, &QInputDialogPrivate::currentRowChanged);
}
}
@@ -287,8 +293,8 @@ void QInputDialogPrivate::ensureIntSpinBox()
if (!intSpinBox) {
intSpinBox = new QInputDialogSpinBox(q);
intSpinBox->hide();
- QObject::connect(intSpinBox, SIGNAL(valueChanged(int)),
- q, SIGNAL(intValueChanged(int)));
+ QObject::connect(intSpinBox, &QInputDialogSpinBox::valueChanged,
+ q, &QInputDialog::intValueChanged);
}
}
@@ -298,8 +304,8 @@ void QInputDialogPrivate::ensureDoubleSpinBox()
if (!doubleSpinBox) {
doubleSpinBox = new QInputDialogDoubleSpinBox(q);
doubleSpinBox->hide();
- QObject::connect(doubleSpinBox, SIGNAL(valueChanged(double)),
- q, SIGNAL(doubleValueChanged(double)));
+ QObject::connect(doubleSpinBox, &QInputDialogDoubleSpinBox::valueChanged,
+ q, &QInputDialog::doubleValueChanged);
}
}
@@ -374,9 +380,9 @@ void QInputDialogPrivate::chooseRightTextInputWidget()
setInputWidget(widget);
if (inputWidget == comboBox) {
- _q_textChanged(comboBox->currentText());
+ textChanged(comboBox->currentText());
} else if (inputWidget == listView) {
- _q_textChanged(listViewText());
+ textChanged(listViewText());
}
}
@@ -410,7 +416,7 @@ QString QInputDialogPrivate::listViewText() const
}
}
-void QInputDialogPrivate::_q_textChanged(const QString &text)
+void QInputDialogPrivate::textChanged(const QString &text)
{
Q_Q(QInputDialog);
if (textValue != text) {
@@ -419,7 +425,7 @@ void QInputDialogPrivate::_q_textChanged(const QString &text)
}
}
-void QInputDialogPrivate::_q_plainTextEditTextChanged()
+void QInputDialogPrivate::plainTextEditTextChanged()
{
Q_Q(QInputDialog);
QString text = plainTextEdit->toPlainText();
@@ -429,10 +435,10 @@ void QInputDialogPrivate::_q_plainTextEditTextChanged()
}
}
-void QInputDialogPrivate::_q_currentRowChanged(const QModelIndex &newIndex,
- const QModelIndex & /* oldIndex */)
+void QInputDialogPrivate::currentRowChanged(const QModelIndex &newIndex,
+ const QModelIndex & /* oldIndex */)
{
- _q_textChanged(comboBox->model()->data(newIndex).toString());
+ textChanged(comboBox->model()->data(newIndex).toString());
buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
}
diff --git a/src/widgets/dialogs/qinputdialog.h b/src/widgets/dialogs/qinputdialog.h
index 51264af76f..bbf757e6e6 100644
--- a/src/widgets/dialogs/qinputdialog.h
+++ b/src/widgets/dialogs/qinputdialog.h
@@ -161,9 +161,6 @@ public:
private:
Q_DISABLE_COPY(QInputDialog)
- Q_PRIVATE_SLOT(d_func(), void _q_textChanged(const QString&))
- Q_PRIVATE_SLOT(d_func(), void _q_plainTextEditTextChanged())
- Q_PRIVATE_SLOT(d_func(), void _q_currentRowChanged(const QModelIndex&, const QModelIndex&))
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QInputDialog::InputDialogOptions)
diff --git a/src/widgets/dialogs/qmessagebox.cpp b/src/widgets/dialogs/qmessagebox.cpp
index cb985ff145..bf56b17f55 100644
--- a/src/widgets/dialogs/qmessagebox.cpp
+++ b/src/widgets/dialogs/qmessagebox.cpp
@@ -30,11 +30,18 @@
#include "private/qabstractbutton_p.h"
#include <QtGui/qpa/qplatformtheme.h>
+#include <QtCore/qanystringview.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qversionnumber.h>
+
#ifdef Q_OS_WIN
# include <QtCore/qt_windows.h>
#include <qpa/qplatformnativeinterface.h>
#endif
+#include <optional>
+
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
@@ -49,6 +56,20 @@ HMENU qt_getWindowsSystemMenu(const QWidget *w)
}
#endif
+static_assert(qToUnderlying(QMessageBox::ButtonRole::NRoles) ==
+ qToUnderlying(QDialogButtonBox::ButtonRole::NRoles),
+ "QMessageBox::ButtonRole and QDialogButtonBox::ButtonRole out of sync!");
+
+static_assert(std::is_same_v<std::underlying_type_t<QMessageBox::ButtonRole>,
+ std::underlying_type_t<QDialogButtonBox::ButtonRole>>);
+
+// StandardButton enums have different underlying types
+// => qToUnderlying and std::is_same_v won't work
+// ### Qt 7: make them have the same underlying type
+static_assert(static_cast<int>(QMessageBox::StandardButton::LastButton) ==
+ static_cast<int>(QDialogButtonBox::StandardButton::LastButton),
+ "QMessageBox::StandardButton and QDialogButtonBox::StandardButton out of sync!");
+
enum Button { Old_Ok = 1, Old_Cancel = 2, Old_Yes = 3, Old_No = 4, Old_Abort = 5, Old_Retry = 6,
Old_Ignore = 7, Old_YesAll = 8, Old_NoAll = 9, Old_ButtonMask = 0xFF,
NewButtonMask = 0xFFFFFC00 };
@@ -91,8 +112,8 @@ public:
layout->addWidget(textEdit);
setLayout(layout);
- connect(textEdit, SIGNAL(copyAvailable(bool)),
- this, SLOT(textCopyAvailable(bool)));
+ connect(textEdit, &TextEdit::copyAvailable,
+ this, &QMessageBoxDetailsText::textCopyAvailable);
}
void setText(const QString &text) { textEdit->setPlainText(text); }
QString text() const { return textEdit->toPlainText(); }
@@ -171,8 +192,8 @@ public:
void init(const QString &title = QString(), const QString &text = QString());
void setupLayout();
- void _q_buttonClicked(QAbstractButton *);
- void _q_clicked(QPlatformDialogHelper::StandardButton button, QPlatformDialogHelper::ButtonRole role);
+ void buttonClicked(QAbstractButton *);
+ void helperClicked(QPlatformDialogHelper::StandardButton button, QPlatformDialogHelper::ButtonRole role);
void setClickedButton(QAbstractButton *button);
QAbstractButton *findButton(int button0, int button1, int button2, int flags);
@@ -181,14 +202,13 @@ public:
QAbstractButton *abstractButtonForId(int id) const;
int execReturnCode(QAbstractButton *button);
- int dialogCodeForButton(QAbstractButton *button) const;
-
void detectEscapeButton();
void updateSize();
int layoutMinimumWidth();
void retranslateStrings();
void setVisible(bool visible) override;
+ bool canBeNativeDialog() const override;
static int showOldMessageBox(QWidget *parent, QMessageBox::Icon icon,
const QString &title, const QString &text,
@@ -232,7 +252,7 @@ public:
private:
void initHelper(QPlatformDialogHelper *) override;
void helperPrepareShow(QPlatformDialogHelper *) override;
- void helperDone(QDialog::DialogCode, QPlatformDialogHelper *) override;
+ int dialogCode() const override;
};
void QMessageBoxPrivate::init(const QString &title, const QString &text)
@@ -251,8 +271,8 @@ void QMessageBoxPrivate::init(const QString &title, const QString &text)
buttonBox = new QDialogButtonBox;
buttonBox->setObjectName("qt_msgbox_buttonbox"_L1);
buttonBox->setCenterButtons(q->style()->styleHint(QStyle::SH_MessageBox_CenterButtons, nullptr, q));
- QObject::connect(buttonBox, SIGNAL(clicked(QAbstractButton*)),
- q, SLOT(_q_buttonClicked(QAbstractButton*)));
+ QObjectPrivate::connect(buttonBox, &QDialogButtonBox::clicked,
+ this, &QMessageBoxPrivate::buttonClicked);
setupLayout();
if (!title.isEmpty() || !text.isEmpty()) {
q->setWindowTitle(title);
@@ -427,37 +447,50 @@ static int oldButton(int button)
int QMessageBoxPrivate::execReturnCode(QAbstractButton *button)
{
- int ret = buttonBox->standardButton(button);
- if (ret == QMessageBox::NoButton) {
- ret = customButtonList.indexOf(button); // if button == 0, correctly sets ret = -1
- } else if (compatMode) {
- ret = oldButton(ret);
+ if (int standardButton = buttonBox->standardButton(button)) {
+ // When using a QMessageBox with standard buttons, the return
+ // code is a StandardButton value indicating the standard button
+ // that was clicked.
+ if (compatMode)
+ return oldButton(standardButton);
+ else
+ return standardButton;
+ } else {
+ // When using QMessageBox with custom buttons, the return code
+ // is an opaque value, and the user is expected to use clickedButton()
+ // to determine which button was clicked. We make sure to keep the opaque
+ // value out of the QDialog::DialogCode range, so we can distinguish them.
+ auto customButtonIndex = customButtonList.indexOf(button);
+ if (customButtonIndex >= 0)
+ return QDialog::DialogCode::Accepted + customButtonIndex + 1;
+ else
+ return customButtonIndex; // Not found, return -1
}
- return ret;
}
-/*!
- \internal
-
- Returns 0 for RejectedRole and NoRole, 1 for AcceptedRole and YesRole, -1 otherwise
- */
-int QMessageBoxPrivate::dialogCodeForButton(QAbstractButton *button) const
+int QMessageBoxPrivate::dialogCode() const
{
Q_Q(const QMessageBox);
- switch (q->buttonRole(button)) {
- case QMessageBox::AcceptRole:
- case QMessageBox::YesRole:
- return QDialog::Accepted;
- case QMessageBox::RejectRole:
- case QMessageBox::NoRole:
- return QDialog::Rejected;
- default:
- return -1;
+ if (rescode <= QDialog::Accepted) {
+ return rescode;
+ } else if (clickedButton) {
+ switch (q->buttonRole(clickedButton)) {
+ case QMessageBox::AcceptRole:
+ case QMessageBox::YesRole:
+ return QDialog::Accepted;
+ case QMessageBox::RejectRole:
+ case QMessageBox::NoRole:
+ return QDialog::Rejected;
+ default:
+ ;
+ }
}
+
+ return QDialogPrivate::dialogCode();
}
-void QMessageBoxPrivate::_q_buttonClicked(QAbstractButton *button)
+void QMessageBoxPrivate::buttonClicked(QAbstractButton *button)
{
Q_Q(QMessageBox);
#if QT_CONFIG(textedit)
@@ -488,23 +521,26 @@ void QMessageBoxPrivate::setClickedButton(QAbstractButton *button)
emit q->buttonClicked(clickedButton);
auto resultCode = execReturnCode(button);
- close(resultCode);
- finalize(resultCode, dialogCodeForButton(button));
+ q->done(resultCode);
}
-void QMessageBoxPrivate::_q_clicked(QPlatformDialogHelper::StandardButton button, QPlatformDialogHelper::ButtonRole role)
+void QMessageBoxPrivate::helperClicked(QPlatformDialogHelper::StandardButton helperButton, QPlatformDialogHelper::ButtonRole role)
{
+ Q_UNUSED(role);
Q_Q(QMessageBox);
- if (button > QPlatformDialogHelper::LastButton) {
- // It's a custom button, and the QPushButton in options is just a proxy
- // for the button on the platform dialog. Simulate the user clicking it.
- clickedButton = static_cast<QAbstractButton *>(options->customButton(button)->button);
- Q_ASSERT(clickedButton);
- clickedButton->click();
- q->done(role);
- } else {
- q->done(button);
- }
+
+ // Map back to QAbstractButton, so that the message box behaves the same from
+ // the outside, regardless of whether it's backed by a native helper or not.
+ QAbstractButton *dialogButton = helperButton > QPlatformDialogHelper::LastButton ?
+ static_cast<QAbstractButton *>(options->customButton(helperButton)->button) :
+ q->button(QMessageBox::StandardButton(helperButton));
+
+ Q_ASSERT(dialogButton);
+
+ // Simulate click by explicitly clicking the button. This will ensure that
+ // any logic of the button that responds to the click is respected, including
+ // plumbing back to buttonClicked above based on the clicked() signal.
+ dialogButton->click();
}
/*!
@@ -714,7 +750,7 @@ void QMessageBoxPrivate::_q_clicked(QPlatformDialogHelper::StandardButton button
When an escape button can't be determined using these rules,
pressing \uicontrol Esc has no effect.
- \sa QDialogButtonBox, {Standard Dialogs Example}, {Qt Widgets - Application Example}
+ \sa QDialogButtonBox, {Standard Dialogs Example}
*/
/*!
@@ -770,6 +806,12 @@ void QMessageBoxPrivate::_q_clicked(QPlatformDialogHelper::StandardButton button
*/
/*!
+ \enum QMessageBox::Option
+ \since 6.6
+ \value DontUseNativeDialog Don't use the native message dialog.
+*/
+
+/*!
\fn void QMessageBox::buttonClicked(QAbstractButton *button)
This signal is emitted whenever a button is clicked inside the QMessageBox.
@@ -864,12 +906,6 @@ void QMessageBox::addButton(QAbstractButton *button, ButtonRole role)
}
}
- // Add button to native dialog helper, unless it's the details button,
- // since we don't do any plumbing for the button's action in that case.
- if (button != d->detailsButton) {
- d->options->addButton(button->text(),
- static_cast<QPlatformDialogHelper::ButtonRole>(role), button);
- }
d->buttonBox->addButton(button, (QDialogButtonBox::ButtonRole)role);
d->customButtonList.append(button);
d->autoAddOkButton = false;
@@ -994,6 +1030,12 @@ QMessageBox::StandardButton QMessageBox::standardButton(QAbstractButton *button)
Returns a pointer corresponding to the standard button \a which,
or \nullptr if the standard button doesn't exist in this message box.
+ \note Modifying the properties of the returned button may not be reflected
+ in native implementations of the message dialog. To customize dialog
+ buttons add a \l{addButton(QAbstractButton *button, QMessageBox::ButtonRole role)}
+ {custom button} or \l{addButton(const QString &text, QMessageBox::ButtonRole role)}
+ {button title} instead, or set the \l Option::DontUseNativeDialog option.
+
\sa standardButtons, standardButton()
*/
QAbstractButton *QMessageBox::button(StandardButton which) const
@@ -1225,6 +1267,78 @@ QCheckBox* QMessageBox::checkBox() const
}
/*!
+ \since 6.6
+ Sets the given \a option to be enabled if \a on is true; otherwise,
+ clears the given \a option.
+
+ Options (particularly the \l Option::DontUseNativeDialog option) should be set
+ before showing the dialog.
+
+ Setting options while the dialog is visible is not guaranteed to have
+ an immediate effect on the dialog.
+
+ Setting options after changing other properties may cause these
+ values to have no effect.
+
+ \sa options, testOption()
+*/
+void QMessageBox::setOption(QMessageBox::Option option, bool on)
+{
+ const QMessageBox::Options previousOptions = options();
+ if (!(previousOptions & option) != !on)
+ setOptions(previousOptions ^ option);
+}
+
+/*!
+ \since 6.6
+
+ Returns \c true if the given \a option is enabled; otherwise, returns
+ false.
+
+ \sa options, setOption()
+*/
+bool QMessageBox::testOption(QMessageBox::Option option) const
+{
+ Q_D(const QMessageBox);
+ return d->options->testOption(static_cast<QMessageDialogOptions::Option>(option));
+}
+
+void QMessageBox::setOptions(QMessageBox::Options options)
+{
+ Q_D(QMessageBox);
+
+ if (QMessageBox::options() == options)
+ return;
+
+ d->options->setOptions(QMessageDialogOptions::Option(int(options)));
+}
+
+QMessageBox::Options QMessageBox::options() const
+{
+ Q_D(const QMessageBox);
+ return QMessageBox::Options(int(d->options->options()));
+}
+
+/*!
+ \property QMessageBox::options
+ \brief Options that affect the look and feel of the dialog.
+ \since 6.6
+
+ By default, these options are disabled.
+
+ The option \l Option::DontUseNativeDialog should be set
+ before changing dialog properties or showing the dialog.
+
+ Setting options while the dialog is visible is not guaranteed to have
+ an immediate effect on the dialog.
+
+ Setting options after changing other properties may cause these
+ values to have no effect.
+
+ \sa setOption(), testOption()
+*/
+
+/*!
\property QMessageBox::text
\brief the message box text to be displayed.
@@ -1363,6 +1477,8 @@ void QMessageBox::setTextFormat(Qt::TextFormat format)
d->label->setTextFormat(format);
d->label->setWordWrap(format == Qt::RichText
|| (format == Qt::AutoText && Qt::mightBeRichText(d->label->text())));
+ if (d->informativeLabel)
+ d->informativeLabel->setTextFormat(format);
d->updateSize();
}
@@ -1568,8 +1684,11 @@ void QMessageBox::open(QObject *receiver, const char *member)
void QMessageBoxPrivate::setVisible(bool visible)
{
Q_Q(QMessageBox);
- if (q->testAttribute(Qt::WA_WState_ExplicitShowHide) && q->testAttribute(Qt::WA_WState_Hidden) != visible)
- return;
+
+ // Last minute setup
+ if (autoAddOkButton)
+ q->addButton(QMessageBox::Ok);
+ detectEscapeButton();
if (canBeNativeDialog())
setNativeDialogVisible(visible);
@@ -1615,13 +1734,7 @@ QMessageBox::ButtonRole QMessageBox::buttonRole(QAbstractButton *button) const
void QMessageBox::showEvent(QShowEvent *e)
{
Q_D(QMessageBox);
- if (d->autoAddOkButton) {
- addButton(Ok);
- }
- if (d->detailsButton)
- addButton(d->detailsButton, QMessageBox::ActionRole);
d->clickedButton = nullptr;
- d->detectEscapeButton();
d->updateSize();
#if QT_CONFIG(accessibility)
@@ -1646,11 +1759,14 @@ static QMessageBox::StandardButton showNewMessageBox(QWidget *parent,
{
// necessary for source compatibility with Qt 4.0 and 4.1
// handles (Yes, No) and (Yes|Default, No)
- if (defaultButton && !(buttons & defaultButton))
- return (QMessageBox::StandardButton)
- QMessageBoxPrivate::showOldMessageBox(parent, icon, title,
- text, int(buttons),
- int(defaultButton), 0);
+ if (defaultButton && !(buttons & defaultButton)) {
+ const int defaultButtons = defaultButton | QMessageBox::Default;
+ const int otherButtons = buttons.toInt();
+ const int ret = QMessageBoxPrivate::showOldMessageBox(parent, icon, title,
+ text, otherButtons,
+ defaultButtons, 0);
+ return static_cast<QMessageBox::StandardButton>(ret);
+ }
QMessageBox msgBox(icon, title, text, QMessageBox::NoButton, parent);
QDialogButtonBox *buttonBox = msgBox.findChild<QDialogButtonBox*>();
@@ -1819,9 +1935,10 @@ QMessageBox::StandardButton QMessageBox::critical(QWidget *parent, const QString
\li As a last resort it uses the Information icon.
\endlist
- The about box has a single button labelled "OK". On \macos, the
- about box is popped up as a modeless window; on other platforms,
- it is currently application modal.
+ The about box has a single button labelled "OK".
+
+ On \macos, the about box is popped up as a modeless window; on
+ other platforms, it is currently application modal.
\sa QWidget::windowIcon(), QApplication::activeWindow()
*/
@@ -1851,13 +1968,13 @@ void QMessageBox::about(QWidget *parent, const QString &title, const QString &te
// should perhaps be a style hint
#ifdef Q_OS_MAC
oldMsgBox = msgBox;
-#if 0
- // ### doesn't work until close button is enabled in title bar
- msgBox->d_func()->autoAddOkButton = false;
+ auto *d = msgBox->d_func();
+ d->buttonBox->setCenterButtons(true);
+#ifdef Q_OS_IOS
+ msgBox->setModal(true);
#else
- msgBox->d_func()->buttonBox->setCenterButtons(true);
-#endif
msgBox->setModal(false);
+#endif
msgBox->show();
#else
msgBox->exec();
@@ -1874,7 +1991,7 @@ void QMessageBox::about(QWidget *parent, const QString &title, const QString &te
QApplication provides this functionality as a slot.
- On \macos, the about box is popped up as a modeless window; on
+ On \macos, the aboutQt box is popped up as a modeless window; on
other platforms, it is currently application modal.
\sa QApplication::aboutQt()
@@ -1914,15 +2031,14 @@ void QMessageBox::aboutQt(QWidget *parent, const QString &title)
"<p>Qt licensed under GNU (L)GPL is appropriate for the "
"development of Qt&nbsp;applications provided you can comply with the terms "
"and conditions of the respective licenses.</p>"
- "<p>Please see <a href=\"http://%2/\">%2</a> "
+ "<p>Please see <a href=\"https://%2/\">%2</a> "
"for an overview of Qt licensing.</p>"
- "<p>Copyright (C) %1 The Qt Company Ltd and other "
+ "<p>Copyright (C) The Qt Company Ltd. and other "
"contributors.</p>"
"<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(QLatin1String(QT_COPYRIGHT_YEAR),
- QStringLiteral("qt.io/licensing"),
+ "<p>Qt is The Qt Company Ltd. product developed as an open source "
+ "project. See <a href=\"https://%3/\">%3</a> for more information.</p>"
+ ).arg(QStringLiteral("qt.io/licensing"),
QStringLiteral("qt.io"));
QMessageBox *msgBox = new QMessageBox(parent);
msgBox->setAttribute(Qt::WA_DeleteOnClose);
@@ -1937,13 +2053,13 @@ void QMessageBox::aboutQt(QWidget *parent, const QString &title)
// should perhaps be a style hint
#ifdef Q_OS_MAC
oldMsgBox = msgBox;
-#if 0
- // ### doesn't work until close button is enabled in title bar
- msgBox->d_func()->autoAddOkButton = false;
+ auto *d = msgBox->d_func();
+ d->buttonBox->setCenterButtons(true);
+#ifdef Q_OS_IOS
+ msgBox->setModal(true);
#else
- msgBox->d_func()->buttonBox->setCenterButtons(true);
-#endif
msgBox->setModal(false);
+#endif
msgBox->show();
#else
msgBox->exec();
@@ -2165,7 +2281,7 @@ int QMessageBox::information(QWidget *parent, const QString &title, const QStrin
}
/*!
- \deprecated since 6.2. Use the overload taking StandardButtons instead.
+ \deprecated [6.2] Use the overload taking StandardButtons instead.
\overload
Displays an information message box with the given \a title and
@@ -2464,7 +2580,7 @@ int QMessageBox::critical(QWidget *parent, const QString &title, const QString&
/*!
- \deprecated
+ \deprecated [6.2]
Returns the text of the message box button \a button, or
an empty string if the message box does not contain the button.
@@ -2485,7 +2601,7 @@ QString QMessageBox::buttonText(int button) const
}
/*!
- \deprecated
+ \deprecated [6.2]
Sets the text of the message box button \a button to \a text.
Setting the text of a button that is not in the message box is
@@ -2568,9 +2684,14 @@ void QMessageBox::setDetailedText(const QString &text)
information to the user, for example describing the consequences of
the situation, or suggestion alternative solutions.
+ The text will be interpreted either as a plain text or as rich text,
+ depending on the text format setting (\l QMessageBox::textFormat).
+ The default setting is Qt::AutoText, i.e., the message box will try
+ to auto-detect the format of the text.
+
By default, this property contains an empty string.
- \sa QMessageBox::text, QMessageBox::detailedText
+ \sa textFormat, QMessageBox::text, QMessageBox::detailedText
*/
QString QMessageBox::informativeText() const
{
@@ -2594,12 +2715,12 @@ void QMessageBox::setInformativeText(const QString &text)
label->setTextInteractionFlags(Qt::TextInteractionFlags(style()->styleHint(QStyle::SH_MessageBox_TextInteractionFlags, nullptr, this)));
label->setAlignment(Qt::AlignTop | Qt::AlignLeft);
label->setOpenExternalLinks(true);
- label->setWordWrap(true);
#ifdef Q_OS_MAC
// apply a smaller font the information label on the mac
label->setFont(qt_app_fonts_hash()->value("QTipLabel"));
#endif
label->setWordWrap(true);
+ label->setTextFormat(d->label->textFormat());
d->informativeLabel = label;
}
d->informativeLabel->setText(text);
@@ -2667,6 +2788,7 @@ QPixmap QMessageBoxPrivate::standardIcon(QMessageBox::Icon icon, QMessageBox *mb
break;
case QMessageBox::Question:
tmpIcon = style->standardIcon(QStyle::SP_MessageBoxQuestion, nullptr, mb);
+ break;
default:
break;
}
@@ -2679,19 +2801,18 @@ QPixmap QMessageBoxPrivate::standardIcon(QMessageBox::Icon icon, QMessageBox *mb
void QMessageBoxPrivate::initHelper(QPlatformDialogHelper *h)
{
- Q_Q(QMessageBox);
- QObject::connect(h, SIGNAL(clicked(QPlatformDialogHelper::StandardButton,QPlatformDialogHelper::ButtonRole)),
- q, SLOT(_q_clicked(QPlatformDialogHelper::StandardButton,QPlatformDialogHelper::ButtonRole)));
-
auto *messageDialogHelper = static_cast<QPlatformMessageDialogHelper *>(h);
- QObject::connect(messageDialogHelper, &QPlatformMessageDialogHelper::checkBoxStateChanged, q,
- [this](Qt::CheckState state) {
+ QObjectPrivate::connect(messageDialogHelper, &QPlatformMessageDialogHelper::clicked,
+ this, &QMessageBoxPrivate::helperClicked);
+ // Forward state via lambda, so that we can handle addition and removal
+ // of checkbox via setCheckBox() after initializing helper.
+ QObject::connect(messageDialogHelper, &QPlatformMessageDialogHelper::checkBoxStateChanged,
+ q_ptr, [this](Qt::CheckState state) {
if (checkbox)
checkbox->setCheckState(state);
}
);
-
- static_cast<QPlatformMessageDialogHelper *>(h)->setOptions(options);
+ messageDialogHelper->setOptions(options);
}
static QMessageDialogOptions::StandardIcon helperIcon(QMessageBox::Icon i)
@@ -2717,6 +2838,36 @@ static QPlatformDialogHelper::StandardButtons helperStandardButtons(QMessageBox
return buttons;
}
+bool QMessageBoxPrivate::canBeNativeDialog() const
+{
+ // Don't use Q_Q here! This function is called from ~QDialog,
+ // so Q_Q calling q_func() invokes undefined behavior (invalid cast in q_func()).
+ const QDialog * const q = static_cast<const QMessageBox*>(q_ptr);
+ if (nativeDialogInUse)
+ return true;
+ if (QCoreApplication::testAttribute(Qt::AA_DontUseNativeDialogs)
+ || q->testAttribute(Qt::WA_DontShowOnScreen)
+ || q->testAttribute(Qt::WA_StyleSheet)
+ || (options->options() & QMessageDialogOptions::Option::DontUseNativeDialog)) {
+ return false;
+ }
+
+ if (strcmp(QMessageBox::staticMetaObject.className(), q->metaObject()->className()) != 0)
+ return false;
+
+#if QT_CONFIG(menu)
+ for (auto *customButton : buttonBox->buttons()) {
+ if (QPushButton *pushButton = qobject_cast<QPushButton *>(customButton)) {
+ // We can't support buttons with menus in native dialogs (yet)
+ if (pushButton->menu())
+ return false;
+ }
+ }
+#endif
+
+ return QDialogPrivate::canBeNativeDialog();
+}
+
void QMessageBoxPrivate::helperPrepareShow(QPlatformDialogHelper *)
{
Q_Q(QMessageBox);
@@ -2728,24 +2879,78 @@ void QMessageBoxPrivate::helperPrepareShow(QPlatformDialogHelper *)
#endif
options->setStandardIcon(helperIcon(q->icon()));
options->setIconPixmap(q->iconPixmap());
- options->setStandardButtons(helperStandardButtons(q));
+
+ // Clear up front, since we might have prepared earlier
+ options->clearCustomButtons();
+
+ // Add standard buttons and resolve default/escape button
+ auto standardButtons = helperStandardButtons(q);
+ for (int button = QDialogButtonBox::StandardButton::FirstButton;
+ button <= QDialogButtonBox::StandardButton::LastButton; button <<= 1) {
+ auto *standardButton = buttonBox->button(QDialogButtonBox::StandardButton(button));
+ if (!standardButton)
+ continue;
+
+ if (auto *platformTheme = QGuiApplicationPrivate::platformTheme()) {
+ if (standardButton->text() != platformTheme->standardButtonText(button)) {
+ // The standard button has been customized, so add it as
+ // a custom button instead.
+ const auto buttonRole = buttonBox->buttonRole(standardButton);
+ options->addButton(standardButton->text(),
+ static_cast<QPlatformDialogHelper::ButtonRole>(buttonRole),
+ standardButton, button);
+ standardButtons &= ~QPlatformDialogHelper::StandardButton(button);
+ }
+ }
+
+ if (standardButton == defaultButton)
+ options->setDefaultButton(button);
+ else if (standardButton == detectedEscapeButton)
+ options->setEscapeButton(button);
+ }
+ options->setStandardButtons(standardButtons);
+
+ // Add custom buttons and resolve default/escape button
+ for (auto *customButton : customButtonList) {
+ // Unless it's the details button, since we don't do any
+ // plumbing for the button's action in that case.
+ if (customButton == detailsButton)
+ continue;
+
+ const auto buttonRole = buttonBox->buttonRole(customButton);
+ const int buttonId = options->addButton(customButton->text(),
+ static_cast<QPlatformDialogHelper::ButtonRole>(buttonRole),
+ customButton);
+
+ if (customButton == defaultButton)
+ options->setDefaultButton(buttonId);
+ else if (customButton == detectedEscapeButton)
+ options->setEscapeButton(buttonId);
+ }
+
if (checkbox)
options->setCheckBox(checkbox->text(), checkbox->checkState());
}
-void QMessageBoxPrivate::helperDone(QDialog::DialogCode code, QPlatformDialogHelper *)
+void qRequireVersion(int argc, char *argv[], QAnyStringView req)
{
- Q_Q(QMessageBox);
- QAbstractButton *button = q->button(QMessageBox::StandardButton(code));
- // If it was a custom button, a custom ID was used, so we won't get a valid pointer here.
- // In that case, clickedButton has already been set in _q_buttonClicked.
- if (button)
- clickedButton = button;
+ const auto required = QVersionNumber::fromString(req).normalized();
+ const auto current = QVersionNumber::fromString(qVersion()).normalized();
+ if (current >= required)
+ return;
+ std::optional<QApplication> application;
+ if (!qApp)
+ application.emplace(argc, argv);
+ const QString message = QApplication::tr("Application \"%1\" requires Qt %2, found Qt %3.")
+ .arg(qAppName(), required.toString(), current.toString());
+ QMessageBox::critical(nullptr, QApplication::tr("Incompatible Qt Library Error"),
+ message, QMessageBox::Abort);
+ qFatal("%ls", qUtf16Printable(message));
}
#if QT_DEPRECATED_SINCE(6,2)
/*!
- \deprecated
+ \deprecated [6.2]
Returns the pixmap used for a standard icon. This allows the
pixmaps to be used in more complex message boxes. \a icon
@@ -2811,7 +3016,7 @@ QPixmap QMessageBox::standardIcon(Icon icon)
/*!
\macro QT_REQUIRE_VERSION(int argc, char **argv, const char *version)
- \relates <QMessageBox>
+ \relates QMessageBox
This macro can be used to ensure that the application is run
with a recent enough version of Qt. This is especially useful
diff --git a/src/widgets/dialogs/qmessagebox.h b/src/widgets/dialogs/qmessagebox.h
index cf8821bbd0..751674466c 100644
--- a/src/widgets/dialogs/qmessagebox.h
+++ b/src/widgets/dialogs/qmessagebox.h
@@ -5,13 +5,14 @@
#define QMESSAGEBOX_H
#include <QtWidgets/qtwidgetsglobal.h>
-
#include <QtWidgets/qdialog.h>
+#include <QtWidgets/qdialogbuttonbox.h>
QT_REQUIRE_CONFIG(messagebox);
QT_BEGIN_NAMESPACE
+class QAnyStringView;
class QLabel;
class QMessageBoxPrivate;
class QAbstractButton;
@@ -31,8 +32,14 @@ class Q_WIDGETS_EXPORT QMessageBox : public QDialog
Q_PROPERTY(QString informativeText READ informativeText WRITE setInformativeText)
Q_PROPERTY(Qt::TextInteractionFlags textInteractionFlags READ textInteractionFlags
WRITE setTextInteractionFlags)
-
+ Q_PROPERTY(Options options READ options WRITE setOptions)
public:
+ // Keep in sync with MessageBoxOption in qplatformdialoghelper.h
+ enum class Option {
+ DontUseNativeDialog = 0x00000001
+ };
+ Q_FLAG(Option)
+
enum Icon {
// keep this in sync with QMessageDialogOptions::StandardIcon
NoIcon = 0,
@@ -58,6 +65,7 @@ public:
NRoles
};
+ Q_ENUM(ButtonRole)
enum StandardButton {
// keep this in sync with QDialogButtonBox::StandardButton and QPlatformDialogHelper::StandardButton
@@ -92,11 +100,14 @@ public:
FlagMask = 0x00000300, // obsolete
ButtonMask = ~FlagMask // obsolete
};
+ Q_ENUM(StandardButton)
+
#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
typedef StandardButton Button;
#endif
-
+ Q_DECLARE_FLAGS(Options, Option)
Q_DECLARE_FLAGS(StandardButtons, StandardButton)
+
Q_FLAG(StandardButtons)
explicit QMessageBox(QWidget *parent = nullptr);
@@ -149,6 +160,11 @@ public:
void setCheckBox(QCheckBox *cb);
QCheckBox* checkBox() const;
+ void setOption(Option option, bool on = true);
+ bool testOption(Option option) const;
+ void setOptions(Options options);
+ Options options() const;
+
static StandardButton information(QWidget *parent, const QString &title,
const QString &text, StandardButtons buttons = Ok,
StandardButton defaultButton = NoButton);
@@ -291,29 +307,15 @@ protected:
void changeEvent(QEvent *event) override;
private:
- Q_PRIVATE_SLOT(d_func(), void _q_buttonClicked(QAbstractButton *))
- Q_PRIVATE_SLOT(d_func(), void _q_clicked(QPlatformDialogHelper::StandardButton, QPlatformDialogHelper::ButtonRole))
-
Q_DISABLE_COPY(QMessageBox)
Q_DECLARE_PRIVATE(QMessageBox)
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QMessageBox::StandardButtons)
-#define QT_REQUIRE_VERSION(argc, argv, str) { QString s = QString::fromLatin1(str);\
-QString sq = QString::fromLatin1(qVersion()); \
-if ((sq.section(QChar::fromLatin1('.'),0,0).toInt()<<16)+\
-(sq.section(QChar::fromLatin1('.'),1,1).toInt()<<8)+\
-sq.section(QChar::fromLatin1('.'),2,2).toInt()<(s.section(QChar::fromLatin1('.'),0,0).toInt()<<16)+\
-(s.section(QChar::fromLatin1('.'),1,1).toInt()<<8)+\
-s.section(QChar::fromLatin1('.'),2,2).toInt()) { \
-if (!qApp){ \
- new QApplication(argc,argv); \
-} \
-QString s = QApplication::tr("Executable '%1' requires Qt "\
- "%2, found Qt %3.").arg(qAppName()).arg(QString::fromLatin1(\
-str)).arg(QString::fromLatin1(qVersion())); QMessageBox::critical(0, QApplication::tr(\
-"Incompatible Qt Library Error"), s, QMessageBox::Abort, 0); qFatal("%s", s.toLatin1().data()); }}
+Q_WIDGETS_EXPORT void qRequireVersion(int argc, char *argv[], QAnyStringView req);
+
+#define QT_REQUIRE_VERSION(argc, argv, str) qRequireVersion(argc, argv, str);
QT_END_NAMESPACE
diff --git a/src/widgets/dialogs/qprogressdialog.cpp b/src/widgets/dialogs/qprogressdialog.cpp
index 59d44cd8d5..9761bcc828 100644
--- a/src/widgets/dialogs/qprogressdialog.cpp
+++ b/src/widgets/dialogs/qprogressdialog.cpp
@@ -17,15 +17,20 @@
#include "qelapsedtimer.h"
#include "qscopedvaluerollback.h"
#include <private/qdialog_p.h>
+
+#include <QtCore/qpointer.h>
+
#include <limits.h>
+using namespace std::chrono_literals;
+
QT_BEGIN_NAMESPACE
// If the operation is expected to take this long (as predicted by
// progress time), show the progress dialog.
-static const int defaultShowTime = 4000;
+static constexpr auto defaultShowTime = 4000ms;
// Wait at least this long before attempting to make a prediction.
-static const int minWaitTime = 50;
+static constexpr auto minWaitTime = 50ms;
class QProgressDialogPrivate : public QDialogPrivate
{
@@ -52,7 +57,7 @@ public:
QPointer<QObject> receiverToDisconnectOnClose;
QElapsedTimer starttime;
QByteArray memberToDisconnectOnClose;
- int showTime = defaultShowTime;
+ std::chrono::milliseconds showTime = defaultShowTime;
bool processingEvents = false;
bool shownOnce = false;
bool autoClose = true;
@@ -192,10 +197,11 @@ void QProgressDialogPrivate::_q_disconnectOnClose()
A modeless progress dialog is suitable for operations that take
place in the background, where the user is able to interact with the
- application. Such operations are typically based on QTimer (or
- QObject::timerEvent()) or QSocketNotifier; or performed
- in a separate thread. A QProgressBar in the status bar of your main window
- is often an alternative to a modeless progress dialog.
+ application. Such operations are typically based on a timer class,
+ such as QChronoTimer (or the more low-level QObject::timerEvent()) or
+ QSocketNotifier; or performed in a separate thread. A QProgressBar in
+ the status bar of your main window is often an alternative to a modeless
+ progress dialog.
You need to have an event loop to be running, connect the
canceled() signal to a slot that stops the operation, and call \l
@@ -215,7 +221,7 @@ void QProgressDialogPrivate::_q_disconnectOnClose()
\image fusion-progressdialog.png A progress dialog shown in the Fusion widget style.
- \sa QDialog, QProgressBar, {Pixelator Example}
+ \sa QDialog, QProgressBar
*/
@@ -625,23 +631,22 @@ void QProgressDialog::setValue(int progress)
return;
} else {
d->setValueCalled = true;
- bool need_show;
- int elapsed = d->starttime.elapsed();
+ bool need_show = false;
+ using namespace std::chrono;
+ nanoseconds elapsed = d->starttime.durationElapsed();
if (elapsed >= d->showTime) {
need_show = true;
} else {
if (elapsed > minWaitTime) {
- int estimate;
- int totalSteps = maximum() - minimum();
- int myprogress = progress - minimum();
- if (myprogress == 0) myprogress = 1;
- if ((totalSteps - myprogress) >= INT_MAX / elapsed)
- estimate = (totalSteps - myprogress) / myprogress * elapsed;
+ const int totalSteps = maximum() - minimum();
+ const int myprogress = std::max(progress - minimum(), 1);
+ const int remainingSteps = totalSteps - myprogress;
+ nanoseconds estimate;
+ if (remainingSteps >= INT_MAX / elapsed.count())
+ estimate = (remainingSteps / myprogress) * elapsed;
else
- estimate = elapsed * (totalSteps - myprogress) / myprogress;
+ estimate = (elapsed * remainingSteps) / myprogress;
need_show = estimate >= d->showTime;
- } else {
- need_show = false;
}
}
if (need_show) {
@@ -717,17 +722,18 @@ void QProgressDialog::changeEvent(QEvent *ev)
void QProgressDialog::setMinimumDuration(int ms)
{
Q_D(QProgressDialog);
- d->showTime = ms;
+ std::chrono::milliseconds msecs{ms};
+ d->showTime = msecs;
if (d->bar->value() == d->bar->minimum()) {
d->forceTimer->stop();
- d->forceTimer->start(ms);
+ d->forceTimer->start(msecs);
}
}
int QProgressDialog::minimumDuration() const
{
Q_D(const QProgressDialog);
- return d->showTime;
+ return int(d->showTime.count());
}
@@ -743,7 +749,7 @@ void QProgressDialog::closeEvent(QCloseEvent *e)
/*!
\property QProgressDialog::autoReset
- \brief whether the progress dialog calls reset() as soon as value() equals maximum()
+ \brief whether the progress dialog calls reset() as soon as value() equals maximum().
The default is true.
diff --git a/src/widgets/dialogs/qsidebar.cpp b/src/widgets/dialogs/qsidebar.cpp
index b52c7e8c9e..581e659a44 100644
--- a/src/widgets/dialogs/qsidebar.cpp
+++ b/src/widgets/dialogs/qsidebar.cpp
@@ -43,6 +43,12 @@ QUrlModel::QUrlModel(QObject *parent) : QStandardItemModel(parent), showFullPath
{
}
+QUrlModel::~QUrlModel()
+{
+ for (const auto &conn : std::as_const(modelConnections))
+ disconnect(conn);
+}
+
/*!
\reimp
*/
@@ -177,11 +183,14 @@ void QUrlModel::setUrl(const QModelIndex &index, const QUrl &url, const QModelIn
setData(index, true, EnabledRole);
}
+ // newIcon could be null if fileSystemModel->iconProvider() returns null
+ if (!newIcon.isNull()) {
// Make sure that we have at least 32x32 images
- const QSize size = newIcon.actualSize(QSize(32,32));
- if (size.width() < 32) {
- QPixmap smallPixmap = newIcon.pixmap(QSize(32, 32));
- newIcon.addPixmap(smallPixmap.scaledToWidth(32, Qt::SmoothTransformation));
+ const QSize size = newIcon.actualSize(QSize(32,32));
+ if (size.width() < 32) {
+ QPixmap smallPixmap = newIcon.pixmap(QSize(32, 32));
+ newIcon.addPixmap(smallPixmap.scaledToWidth(32, Qt::SmoothTransformation));
+ }
}
if (index.data().toString() != newName)
@@ -211,8 +220,9 @@ void QUrlModel::addUrls(const QList<QUrl> &list, int row, bool move)
if (row == -1)
row = rowCount();
row = qMin(row, rowCount());
- for (int i = list.size() - 1; i >= 0; --i) {
- QUrl url = list.at(i);
+ const auto rend = list.crend();
+ for (auto it = list.crbegin(); it != rend; ++it) {
+ QUrl url = *it;
if (!url.isValid() || url.scheme() != "file"_L1)
continue;
//this makes sure the url is clean
@@ -265,21 +275,19 @@ void QUrlModel::setFileSystemModel(QFileSystemModel *model)
if (model == fileSystemModel)
return;
if (fileSystemModel != nullptr) {
- disconnect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
- this, SLOT(dataChanged(QModelIndex,QModelIndex)));
- disconnect(model, SIGNAL(layoutChanged()),
- this, SLOT(layoutChanged()));
- disconnect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(layoutChanged()));
+ for (const auto &conn : std::as_const(modelConnections))
+ disconnect(conn);
}
fileSystemModel = model;
if (fileSystemModel != nullptr) {
- connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
- this, SLOT(dataChanged(QModelIndex,QModelIndex)));
- connect(model, SIGNAL(layoutChanged()),
- this, SLOT(layoutChanged()));
- connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(layoutChanged()));
+ modelConnections = {
+ connect(model, &QFileSystemModel::dataChanged,
+ this, &QUrlModel::dataChanged),
+ connect(model, &QFileSystemModel::layoutChanged,
+ this, &QUrlModel::layoutChanged),
+ connect(model, &QFileSystemModel::rowsRemoved,
+ this, &QUrlModel::layoutChanged),
+ };
}
clear();
insertColumns(0, 1);
@@ -312,13 +320,11 @@ void QUrlModel::dataChanged(const QModelIndex &topLeft, const QModelIndex &botto
void QUrlModel::layoutChanged()
{
QStringList paths;
- const int numPaths = watching.size();
- paths.reserve(numPaths);
- for (int i = 0; i < numPaths; ++i)
- paths.append(watching.at(i).path);
+ paths.reserve(watching.size());
+ for (const WatchItem &item : std::as_const(watching))
+ paths.append(item.path);
watching.clear();
- for (int i = 0; i < numPaths; ++i) {
- QString path = paths.at(i);
+ for (const auto &path : paths) {
QModelIndex newIndex = fileSystemModel->index(path);
watching.append({newIndex, path});
if (newIndex.isValid())
@@ -353,14 +359,16 @@ void QSidebar::setModelAndUrls(QFileSystemModel *model, const QList<QUrl> &newUr
setModel(urlModel);
setItemDelegate(new QSideBarDelegate(this));
- connect(selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
- this, SLOT(clicked(QModelIndex)));
+ connect(selectionModel(), &QItemSelectionModel::currentChanged,
+ this, &QSidebar::clicked);
#if QT_CONFIG(draganddrop)
setDragDropMode(QAbstractItemView::DragDrop);
#endif
+#if QT_CONFIG(menu)
setContextMenuPolicy(Qt::CustomContextMenu);
- connect(this, SIGNAL(customContextMenuRequested(QPoint)),
- this, SLOT(showContextMenu(QPoint)));
+ connect(this, &QSidebar::customContextMenuRequested,
+ this, &QSidebar::showContextMenu);
+#endif
urlModel->setUrls(newUrls);
setCurrentIndex(this->model()->index(0,0));
}
@@ -386,8 +394,8 @@ QSize QSidebar::sizeHint() const
void QSidebar::selectUrl(const QUrl &url)
{
- disconnect(selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
- this, SLOT(clicked(QModelIndex)));
+ disconnect(selectionModel(), &QItemSelectionModel::currentChanged,
+ this, &QSidebar::clicked);
selectionModel()->clear();
for (int i = 0; i < model()->rowCount(); ++i) {
@@ -397,8 +405,8 @@ void QSidebar::selectUrl(const QUrl &url)
}
}
- connect(selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
- this, SLOT(clicked(QModelIndex)));
+ connect(selectionModel(), &QItemSelectionModel::currentChanged,
+ this, &QSidebar::clicked);
}
#if QT_CONFIG(menu)
@@ -414,7 +422,7 @@ void QSidebar::showContextMenu(const QPoint &position)
QAction *action = new QAction(QFileDialog::tr("Remove"), this);
if (indexAt(position).data(QUrlModel::UrlRole).toUrl().path().isEmpty())
action->setEnabled(false);
- connect(action, SIGNAL(triggered()), this, SLOT(removeEntry()));
+ connect(action, &QAction::triggered, this, &QSidebar::removeEntry);
actions.append(action);
}
if (actions.size() > 0)
@@ -429,16 +437,13 @@ void QSidebar::showContextMenu(const QPoint &position)
*/
void QSidebar::removeEntry()
{
- QList<QModelIndex> idxs = selectionModel()->selectedIndexes();
- QList<QPersistentModelIndex> indexes;
- const int numIndexes = idxs.size();
- indexes.reserve(numIndexes);
- for (int i = 0; i < numIndexes; i++)
- indexes.append(idxs.at(i));
-
- for (int i = 0; i < numIndexes; ++i) {
- if (!indexes.at(i).data(QUrlModel::UrlRole).toUrl().path().isEmpty())
- model()->removeRow(indexes.at(i).row());
+ const QList<QModelIndex> idxs = selectionModel()->selectedIndexes();
+ // Create a list of QPersistentModelIndex as the removeRow() calls below could
+ // invalidate the indexes in "idxs"
+ const QList<QPersistentModelIndex> persIndexes(idxs.cbegin(), idxs.cend());
+ for (const QPersistentModelIndex &persistent : persIndexes) {
+ if (!persistent.data(QUrlModel::UrlRole).toUrl().path().isEmpty())
+ model()->removeRow(persistent.row());
}
}
diff --git a/src/widgets/dialogs/qsidebar_p.h b/src/widgets/dialogs/qsidebar_p.h
index 74805e4f2d..ed17a2ff31 100644
--- a/src/widgets/dialogs/qsidebar_p.h
+++ b/src/widgets/dialogs/qsidebar_p.h
@@ -47,6 +47,7 @@ public:
};
QUrlModel(QObject *parent = nullptr);
+ ~QUrlModel();
QStringList mimeTypes() const override;
QMimeData *mimeData(const QModelIndexList &indexes) const override;
@@ -80,6 +81,7 @@ private:
QList<WatchItem> watching;
QList<QUrl> invalidUrls;
+ std::array<QMetaObject::Connection, 3> modelConnections;
};
Q_DECLARE_TYPEINFO(QUrlModel::WatchItem, Q_RELOCATABLE_TYPE);
diff --git a/src/widgets/dialogs/qwizard.cpp b/src/widgets/dialogs/qwizard.cpp
index d6287717d9..ec082b9a85 100644
--- a/src/widgets/dialogs/qwizard.cpp
+++ b/src/widgets/dialogs/qwizard.cpp
@@ -691,8 +691,9 @@ void QWizardPrivate::reset()
if (current != -1) {
q->currentPage()->hide();
cleanupPagesNotInHistory();
- for (int i = history.size() - 1; i >= 0; --i)
- q->cleanupPage(history.at(i));
+ const auto end = history.crend();
+ for (auto it = history.crbegin(); it != end; ++it)
+ q->cleanupPage(*it);
history.clear();
for (QWizardPage *page : std::as_const(pageMap))
page->d_func()->initialized = false;
@@ -862,7 +863,7 @@ QWizardLayoutInfo QWizardPrivate::layoutInfoForCurrentPage()
QStyleOption option;
option.initFrom(q);
- const int layoutHorizontalSpacing = style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing, &option);
+ const int layoutHorizontalSpacing = style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing, &option, q);
info.topLevelMarginLeft = style->pixelMetric(QStyle::PM_LayoutLeftMargin, nullptr, q);
info.topLevelMarginRight = style->pixelMetric(QStyle::PM_LayoutRightMargin, nullptr, q);
info.topLevelMarginTop = style->pixelMetric(QStyle::PM_LayoutTopMargin, nullptr, q);
@@ -874,7 +875,7 @@ QWizardLayoutInfo QWizardPrivate::layoutInfoForCurrentPage()
info.hspacing = (layoutHorizontalSpacing == -1)
? style->layoutSpacing(QSizePolicy::DefaultType, QSizePolicy::DefaultType, Qt::Horizontal)
: layoutHorizontalSpacing;
- info.vspacing = style->pixelMetric(QStyle::PM_LayoutVerticalSpacing, &option);
+ info.vspacing = style->pixelMetric(QStyle::PM_LayoutVerticalSpacing, &option, q);
info.buttonSpacing = (layoutHorizontalSpacing == -1)
? style->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal)
: layoutHorizontalSpacing;
@@ -1420,10 +1421,9 @@ void QWizardPrivate::updateButtonTexts()
void QWizardPrivate::updateButtonLayout()
{
if (buttonsHaveCustomLayout) {
- QVarLengthArray<QWizard::WizardButton, QWizard::NButtons> array(buttonsCustomLayout.size());
- for (int i = 0; i < buttonsCustomLayout.size(); ++i)
- array[i] = buttonsCustomLayout.at(i);
- setButtonLayout(array.constData(), array.size());
+ QVarLengthArray<QWizard::WizardButton, QWizard::NButtons> array{
+ buttonsCustomLayout.cbegin(), buttonsCustomLayout.cend()};
+ setButtonLayout(array.constData(), int(array.size()));
} else {
// Positions:
// Help Stretch Custom1 Custom2 Custom3 Cancel Back Next Commit Finish Cancel Help
@@ -1761,9 +1761,8 @@ void QWizardAntiFlickerWidget::paintEvent(QPaintEvent *)
\section1 A Trivial Example
The following example illustrates how to create wizard pages and
- add them to a wizard. For more advanced examples, see
- \l{dialogs/classwizard}{Class Wizard} and \l{dialogs/licensewizard}{License
- Wizard}.
+ add them to a wizard. For more advanced examples, see the
+ \l{dialogs/licensewizard}{License Wizard}.
\snippet dialogs/trivialwizard/trivialwizard.cpp 1
\snippet dialogs/trivialwizard/trivialwizard.cpp 3
@@ -1892,12 +1891,7 @@ void QWizardAntiFlickerWidget::paintEvent(QPaintEvent *)
To register a field, call QWizardPage::registerField() field.
For example:
- \snippet dialogs/classwizard/classwizard.cpp 8
- \dots
- \snippet dialogs/classwizard/classwizard.cpp 10
- \snippet dialogs/classwizard/classwizard.cpp 11
- \dots
- \snippet dialogs/classwizard/classwizard.cpp 13
+ \snippet dialogs/licensewizard/licensewizard.cpp 21
The above code registers three fields, \c className, \c
baseClass, and \c qobjectMacro, which are associated with three
@@ -1908,11 +1902,11 @@ void QWizardAntiFlickerWidget::paintEvent(QPaintEvent *)
The fields of any page are accessible from any other page. For
example:
- \snippet dialogs/classwizard/classwizard.cpp 17
+ \snippet dialogs/licensewizard/licensewizard.cpp 27
Here, we call QWizardPage::field() to access the contents of the
- \c className field (which was defined in the \c ClassInfoPage)
- and use it to initialize the \c OutputFilePage. The field's
+ \c details.email field (which was defined in the \c DetailsPage)
+ and use it to initialize the \c ConclusionPage. The field's
contents is returned as a QVariant.
When we create a field using QWizardPage::registerField(), we
@@ -1955,15 +1949,13 @@ void QWizardAntiFlickerWidget::paintEvent(QPaintEvent *)
\section1 Creating Linear Wizards
Most wizards have a linear structure, with page 1 followed by
- page 2 and so on until the last page. The \l{dialogs/classwizard}{Class
- Wizard} example is such a wizard. With QWizard, linear wizards
+ page 2 and so on until the last page. The \l{dialogs/trivialwizard}
+ {Trivial Wizard} example is such a wizard. With QWizard, linear wizards
are created by instantiating the \l{QWizardPage}s and inserting
them using addPage(). By default, the pages are shown in the
order in which they were added. For example:
- \snippet dialogs/classwizard/classwizard.cpp 0
- \dots
- \snippet dialogs/classwizard/classwizard.cpp 2
+ \snippet dialogs/trivialwizard/trivialwizard.cpp linearAddPage
When a page is about to be shown, QWizard calls initializePage()
(which in turn calls QWizardPage::initializePage()) to fill the
@@ -2033,7 +2025,7 @@ void QWizardAntiFlickerWidget::paintEvent(QPaintEvent *)
\snippet dialogs/licensewizard/licensewizard.cpp 27
- \sa QWizardPage, {Class Wizard Example}, {License Wizard Example}
+ \sa QWizardPage, {Trivial Wizard Example}, {License Wizard Example}
*/
/*!
@@ -2196,8 +2188,8 @@ void QWizard::setPage(int theid, QWizardPage *page)
page->setParent(d->pageFrame);
QList<QWizardField> &pendingFields = page->d_func()->pendingFields;
- for (int i = 0; i < pendingFields.size(); ++i)
- d->addField(pendingFields.at(i));
+ for (const auto &field : std::as_const(pendingFields))
+ d->addField(field);
pendingFields.clear();
connect(page, SIGNAL(completeChanged()), this, SLOT(_q_updateButtonStates()));
@@ -3407,7 +3399,7 @@ int QWizard::nextId() const
using registerField() and can be accessed at any time using
field() and setField().
- \sa QWizard, {Class Wizard Example}, {License Wizard Example}
+ \sa QWizard, {Trivial Wizard Example}, {License Wizard Example}
*/
/*!
@@ -3550,7 +3542,7 @@ QPixmap QWizardPage::pixmap(QWizard::WizardPixmap which) const
fields are properly initialized based on fields from previous
pages. For example:
- \snippet dialogs/classwizard/classwizard.cpp 17
+ \snippet dialogs/licensewizard/licensewizard.cpp 27
The default implementation does nothing.
@@ -3627,8 +3619,9 @@ bool QWizardPage::isComplete() const
return true;
const QList<QWizardField> &wizardFields = d->wizard->d_func()->fields;
- for (int i = wizardFields.size() - 1; i >= 0; --i) {
- const QWizardField &field = wizardFields.at(i);
+ const auto end = wizardFields.crend();
+ for (auto it = wizardFields.crbegin(); it != end; ++it) {
+ const QWizardField &field = *it;
if (field.page == this && field.mandatory) {
QVariant value = field.object->property(field.property);
if (value == field.initialValue)
@@ -3854,7 +3847,7 @@ void QWizardPage::setField(const QString &name, const QVariant &value)
Example:
- \snippet dialogs/classwizard/classwizard.cpp 17
+ \snippet dialogs/licensewizard/licensewizard.cpp accessField
\sa QWizard::field(), setField(), registerField()
*/
diff --git a/src/widgets/dialogs/qwizard_win.cpp b/src/widgets/dialogs/qwizard_win.cpp
index b7788061f1..2c4f049e88 100644
--- a/src/widgets/dialogs/qwizard_win.cpp
+++ b/src/widgets/dialogs/qwizard_win.cpp
@@ -33,7 +33,7 @@ Q_DECLARE_METATYPE(QMargins)
QT_BEGIN_NAMESPACE
-int QVistaHelper::m_devicePixelRatio = 1;
+qreal QVistaHelper::m_devicePixelRatio = 1.0;
/******************************************************************************
** QVistaBackButton
@@ -82,7 +82,7 @@ void QVistaBackButton::paintEvent(QPaintEvent *)
RECT clipRect;
int xoffset = origin.x() + QWidget::mapToParent(r.topLeft()).x() - 1;
int yoffset = origin.y() + QWidget::mapToParent(r.topLeft()).y() - 1;
- const int dpr = devicePixelRatio();
+ const qreal dpr = devicePixelRatio();
const QRect rDp = QRect(r.topLeft() * dpr, r.size() * dpr);
const int xoffsetDp = xoffset * dpr;
const int yoffsetDp = yoffset * dpr;
@@ -589,7 +589,7 @@ void QVistaHelper::drawBlackRect(const QRect &rect, HDC hdc)
int QVistaHelper::frameSizeDp()
{
- return GetSystemMetrics(SM_CYSIZEFRAME);
+ return GetSystemMetrics(SM_CXSIZEFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER);
}
int QVistaHelper::captionSizeDp()
diff --git a/src/widgets/dialogs/qwizard_win_p.h b/src/widgets/dialogs/qwizard_win_p.h
index 45f26a1ebf..ce0f7b85b3 100644
--- a/src/widgets/dialogs/qwizard_win_p.h
+++ b/src/widgets/dialogs/qwizard_win_p.h
@@ -110,7 +110,7 @@ private:
int titleBarOffset; // Extra spacing above the text
int iconSpacing; // Space between button and icon
- static int m_devicePixelRatio;
+ static qreal m_devicePixelRatio;
};
diff --git a/src/widgets/doc/images/addressbook-tutorial-part1-labeled-layout.png b/src/widgets/doc/images/addressbook-tutorial-part1-labeled-layout.png
deleted file mode 100644
index b19cb360a1..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part1-labeled-layout.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-part1-labeled-screenshot.png b/src/widgets/doc/images/addressbook-tutorial-part1-labeled-screenshot.png
deleted file mode 100644
index f9b91eebe6..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part1-labeled-screenshot.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-part1-screenshot.png b/src/widgets/doc/images/addressbook-tutorial-part1-screenshot.png
deleted file mode 100644
index 454b0959e6..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part1-screenshot.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-part2-add-contact.png b/src/widgets/doc/images/addressbook-tutorial-part2-add-contact.png
deleted file mode 100644
index 6f2b947b21..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part2-add-contact.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-part2-add-flowchart.png b/src/widgets/doc/images/addressbook-tutorial-part2-add-flowchart.png
deleted file mode 100644
index ca9af3720d..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part2-add-flowchart.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-part2-add-successful.png b/src/widgets/doc/images/addressbook-tutorial-part2-add-successful.png
deleted file mode 100644
index 99a2154007..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part2-add-successful.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-part2-labeled-layout.png b/src/widgets/doc/images/addressbook-tutorial-part2-labeled-layout.png
deleted file mode 100644
index 1e000c8f31..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part2-labeled-layout.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-part2-signals-and-slots.png b/src/widgets/doc/images/addressbook-tutorial-part2-signals-and-slots.png
deleted file mode 100644
index e49f8dc262..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part2-signals-and-slots.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-part2-stretch-effects.png b/src/widgets/doc/images/addressbook-tutorial-part2-stretch-effects.png
deleted file mode 100644
index d9f7f31227..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part2-stretch-effects.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-part3-labeled-layout.png b/src/widgets/doc/images/addressbook-tutorial-part3-labeled-layout.png
deleted file mode 100644
index 1981ba8cb6..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part3-labeled-layout.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-part3-linkedlist.png b/src/widgets/doc/images/addressbook-tutorial-part3-linkedlist.png
deleted file mode 100644
index e7f4725dce..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part3-linkedlist.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-part3-screenshot.png b/src/widgets/doc/images/addressbook-tutorial-part3-screenshot.png
deleted file mode 100644
index 75159b4045..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part3-screenshot.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-part4-remove.png b/src/widgets/doc/images/addressbook-tutorial-part4-remove.png
deleted file mode 100644
index 8eb259ef02..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part4-remove.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-part5-finddialog.png b/src/widgets/doc/images/addressbook-tutorial-part5-finddialog.png
deleted file mode 100644
index 743d92ef6f..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part5-finddialog.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-part5-notfound.png b/src/widgets/doc/images/addressbook-tutorial-part5-notfound.png
deleted file mode 100644
index 2d35766ab5..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part5-notfound.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-part5-screenshot.png b/src/widgets/doc/images/addressbook-tutorial-part5-screenshot.png
deleted file mode 100644
index 3abe2775c2..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part5-screenshot.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-part5-signals-and-slots.png b/src/widgets/doc/images/addressbook-tutorial-part5-signals-and-slots.png
deleted file mode 100644
index 1771e7bbbf..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part5-signals-and-slots.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-part6-load.png b/src/widgets/doc/images/addressbook-tutorial-part6-load.png
deleted file mode 100644
index a027a1decb..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part6-load.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-part6-save.png b/src/widgets/doc/images/addressbook-tutorial-part6-save.png
deleted file mode 100644
index 757feeb9ac..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part6-save.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-part6-screenshot.png b/src/widgets/doc/images/addressbook-tutorial-part6-screenshot.png
deleted file mode 100644
index 7bb2f749bf..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part6-screenshot.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-part7-screenshot.png b/src/widgets/doc/images/addressbook-tutorial-part7-screenshot.png
deleted file mode 100644
index 3e7b3ca522..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-part7-screenshot.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/addressbook-tutorial-screenshot.png b/src/widgets/doc/images/addressbook-tutorial-screenshot.png
deleted file mode 100644
index 3fba6e849e..0000000000
--- a/src/widgets/doc/images/addressbook-tutorial-screenshot.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/collapsed_combobox.png b/src/widgets/doc/images/collapsed_combobox.png
new file mode 100644
index 0000000000..1400090f42
--- /dev/null
+++ b/src/widgets/doc/images/collapsed_combobox.png
Binary files differ
diff --git a/src/widgets/doc/images/cuberhiwidget-example.jpg b/src/widgets/doc/images/cuberhiwidget-example.jpg
new file mode 100644
index 0000000000..70baab8beb
--- /dev/null
+++ b/src/widgets/doc/images/cuberhiwidget-example.jpg
Binary files differ
diff --git a/src/widgets/doc/images/expanded_combobox.png b/src/widgets/doc/images/expanded_combobox.png
new file mode 100644
index 0000000000..6df0cecbbd
--- /dev/null
+++ b/src/widgets/doc/images/expanded_combobox.png
Binary files differ
diff --git a/src/widgets/doc/images/qrhiwidget-intro.jpg b/src/widgets/doc/images/qrhiwidget-intro.jpg
new file mode 100644
index 0000000000..20f931a723
--- /dev/null
+++ b/src/widgets/doc/images/qrhiwidget-intro.jpg
Binary files differ
diff --git a/src/widgets/doc/images/qtquickdialogs-filedialog-gtk.png b/src/widgets/doc/images/qtquickdialogs-filedialog-gtk.png
new file mode 100644
index 0000000000..9360d747a2
--- /dev/null
+++ b/src/widgets/doc/images/qtquickdialogs-filedialog-gtk.png
Binary files differ
diff --git a/src/widgets/doc/images/simplerhiwidget-example.jpg b/src/widgets/doc/images/simplerhiwidget-example.jpg
new file mode 100644
index 0000000000..3f0a1b355c
--- /dev/null
+++ b/src/widgets/doc/images/simplerhiwidget-example.jpg
Binary files differ
diff --git a/src/widgets/doc/images/spinboxdelegate-example.png b/src/widgets/doc/images/spinboxdelegate-example.png
deleted file mode 100644
index 5e57a9c12b..0000000000
--- a/src/widgets/doc/images/spinboxdelegate-example.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/spinboxdelegate-example.webp b/src/widgets/doc/images/spinboxdelegate-example.webp
new file mode 100644
index 0000000000..35b5770394
--- /dev/null
+++ b/src/widgets/doc/images/spinboxdelegate-example.webp
Binary files differ
diff --git a/src/widgets/doc/images/stylesheet-coffee-cleanlooks.png b/src/widgets/doc/images/stylesheet-coffee-cleanlooks.png
deleted file mode 100644
index e75df0d80a..0000000000
--- a/src/widgets/doc/images/stylesheet-coffee-cleanlooks.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/stylesheet-pagefold-mac.png b/src/widgets/doc/images/stylesheet-pagefold-mac.png
deleted file mode 100644
index 5c061b9cfd..0000000000
--- a/src/widgets/doc/images/stylesheet-pagefold-mac.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/system-tray.png b/src/widgets/doc/images/system-tray.png
deleted file mode 100644
index 298b193cf7..0000000000
--- a/src/widgets/doc/images/system-tray.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/system-tray.webp b/src/widgets/doc/images/system-tray.webp
new file mode 100644
index 0000000000..ae509ccad3
--- /dev/null
+++ b/src/widgets/doc/images/system-tray.webp
Binary files differ
diff --git a/src/widgets/doc/qtwidgets.qdocconf b/src/widgets/doc/qtwidgets.qdocconf
index a63a2f5f2d..5f68179a36 100644
--- a/src/widgets/doc/qtwidgets.qdocconf
+++ b/src/widgets/doc/qtwidgets.qdocconf
@@ -26,7 +26,21 @@ qhp.QtWidgets.subprojects.classes.sortPages = true
tagfile = ../../../doc/qtwidgets/qtwidgets.tags
-depends += qtcore qtgui qtdoc qtsql qtdesigner qtquick qmake qtcmake qtsvg qtlinguist qthelp
+depends += \
+ qtcore \
+ qtgui \
+ qtdoc \
+ qtsql \
+ qtdesigner \
+ qtquick \
+ qmake \
+ qtcmake \
+ qtsvg \
+ qtlinguist \
+ qthelp \
+ qtopengl \
+ qtshadertools \
+ qttestlib
headerdirs += ..
@@ -60,7 +74,16 @@ imagedirs += images \
navigation.landingpage = "Qt Widgets"
navigation.cppclassespage = "Qt Widgets C++ Classes"
-manifestmeta.highlighted.names = "QtWidgets/Qt Widgets - Application Example"
-# Fail the documentation build if there are more warnings than the limit
+# Highlighted examples for User Interface Components category
+manifestmeta.highlighted.names = \
+ "QtWidgets/Editable Tree Model Example" \
+ "QtWidgets/Menus Example"
+
+# Highlighted examples for Desktop category
+manifestmeta.highlighted.names += \
+ "QtWidgets/System Tray Icon Example" \
+ "QtWidgets/Taking a Screenshot"
+
+# Enforce zero documentation warnings
warninglimit = 0
diff --git a/src/widgets/doc/snippets/CMakeLists.txt b/src/widgets/doc/snippets/CMakeLists.txt
index b1a89e1f66..6274244db0 100644
--- a/src/widgets/doc/snippets/CMakeLists.txt
+++ b/src/widgets/doc/snippets/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#! [cmake_use]
find_package(Qt6 REQUIRED COMPONENTS Widgets)
diff --git a/src/widgets/doc/snippets/cmake-macros/examples.cmake b/src/widgets/doc/snippets/cmake-macros/examples.cmake
index d18f2fffb8..3c58509fdf 100644
--- a/src/widgets/doc/snippets/cmake-macros/examples.cmake
+++ b/src/widgets/doc/snippets/cmake-macros/examples.cmake
@@ -1,8 +1,8 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#! [qt_wrap_ui]
set(SOURCES mainwindow.cpp main.cpp)
qt_wrap_ui(SOURCES mainwindow.ui)
-add_executable(myapp ${SOURCES})
+qt_add_executable(myapp ${SOURCES})
#! [qt_wrap_ui]
diff --git a/src/widgets/doc/snippets/code/doc_src_qt4-mainwindow.cpp b/src/widgets/doc/snippets/code/doc_src_qt4-mainwindow.cpp
index 7ac3577648..2c8a892511 100644
--- a/src/widgets/doc/snippets/code/doc_src_qt4-mainwindow.cpp
+++ b/src/widgets/doc/snippets/code/doc_src_qt4-mainwindow.cpp
@@ -26,48 +26,3 @@ setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
QWidget *centralWidget = new QWidget(this);
setCentralWidget(centralWidget);
//! [3]
-
-
-//! [4]
-QPopupMenu *fileMenu = new QPopupMenu(this);
-openAction->addTo(fileMenu);
-saveAction->addTo(fileMenu);
-...
-menuBar()->insertItem(tr("&File"), fileMenu);
-//! [4]
-
-
-//! [5]
-QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
-fileMenu->addAction(openAction);
-fileMenu->addAction(saveAction);
-...
-//! [5]
-
-
-//! [6]
-QToolBar *fileTools = new QToolBar(this, "file toolbar");
-openAction->addTo(fileTools);
-saveAction->addTo(fileTools);
-...
-//! [6]
-
-
-//! [7]
-QToolBar *fileTools = addToolBar(tr("File Tool Bar"));
-fileTools->addAction(openAction);
-fileTools->addAction(saveAction);
-...
-//! [7]
-
-
-//! [8]
-QDockWidget *dockWidget = new QDockWidget(this);
-mainWin->moveDockWidget(dockWidget, Qt::DockLeft);
-//! [8]
-
-
-//! [9]
-QDockWidget *dockWidget = new QDockWidget(mainWindow);
-mainWindow->addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
-//! [9]
diff --git a/src/widgets/doc/snippets/code/doc_src_qt4-styles.cpp b/src/widgets/doc/snippets/code/doc_src_qt4-styles.cpp
index 3620c261a5..2ec3afba01 100644
--- a/src/widgets/doc/snippets/code/doc_src_qt4-styles.cpp
+++ b/src/widgets/doc/snippets/code/doc_src_qt4-styles.cpp
@@ -24,22 +24,3 @@ void MyWidget::paintEvent(QPaintEvent *event)
this);
}
//! [1]
-
-
-//! [2]
-void drawControl(ControlElement element,
- QPainter *painter,
- const QWidget *widget,
- const QRect &rect,
- const QColorGroup &colorGroup,
- SFlags how = Style_Default,
- const QStyleOption &option = QStyleOption::Default) const;
-//! [2]
-
-
-//! [3]
-void drawControl(ControlElement element,
- const QStyleOption *option,
- QPainter *painter,
- const QWidget *widget = nullptr) const;
-//! [3]
diff --git a/src/widgets/doc/snippets/code/doc_src_stylesheet.qdoc b/src/widgets/doc/snippets/code/doc_src_stylesheet.qdoc
index d505040590..388e9d1f7c 100644
--- a/src/widgets/doc/snippets/code/doc_src_stylesheet.qdoc
+++ b/src/widgets/doc/snippets/code/doc_src_stylesheet.qdoc
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
//! [0]
QLineEdit { background: yellow }
@@ -450,32 +450,48 @@ QDialog { etch-disabled-text: 1 }
//! [82]
-QLabel { border-color: red } /* red red red red */
-QLabel { border-color: red blue } /* red blue red blue */
-QLabel { border-color: red blue green } /* red blue green blue */
-QLabel { border-color: red blue green yellow }
+/* red red red red */
+QLabel { border-color: red }
+/* red blue red blue */
+QLabel { border-color: red blue }
+/* red blue green blue */
+QLabel { border-color: red blue green }
/* red blue green yellow */
+QLabel { border-color: red blue green yellow }
//! [82]
//! [83]
-QLabel { border-width: 1px } /* 1px 1px 1px 1px */
-QLabel { border-width: 1px 2px } /* 1px 2px 1px 2px */
-QLabel { border-width: 1px 2px 3px } /* 1px 2px 3px 2px */
-QLabel { border-width: 1px 2px 3px 4px } /* 1px 2px 3px 4px */
+/* 1px 1px 1px 1px */
+QLabel { border-width: 1px }
+/* 1px 2px 1px 2px */
+QLabel { border-width: 1px 2px }
+/* 1px 2px 3px 2px */
+QLabel { border-width: 1px 2px 3px }
+/* 1px 2px 3px 4px */
+QLabel { border-width: 1px 2px 3px 4px }
//! [83]
//! [84]
-QLabel { border-color: red } /* opaque red */
-QLabel { border-color: #FF0000 } /* opaque red */
-QLabel { border-color: rgba(255, 0, 0, 75%) } /* 75% opaque red */
-QLabel { border-color: rgb(255, 0, 0) } /* opaque red */
-QLabel { border-color: rgb(100%, 0%, 0%) } /* opaque red */
-QLabel { border-color: hsv(60, 100%, 100%) } /* opaque yellow */
-QLabel { border-color: hsva(240, 255, 255, 75%) } /* 75% blue */
-QLabel { border-color: hsl(60, 100%, 50%) } /* opaque yellow */
-QLabel { border-color: hsla(240, 255, 50%, 75%) } /* 75% blue */
+/* opaque red */
+QLabel { border-color: red }
+/* opaque red */
+QLabel { border-color: #FF0000 }
+/* 75% opaque red */
+QLabel { border-color: rgba(255, 0, 0, 75%) }
+/* opaque red */
+QLabel { border-color: rgb(255, 0, 0) }
+/* opaque red */
+QLabel { border-color: rgb(100%, 0%, 0%) }
+/* opaque yellow */
+QLabel { border-color: hsv(60, 100%, 100%) }
+/* 75% blue */
+QLabel { border-color: hsva(240, 255, 255, 75%) }
+/* opaque yellow */
+QLabel { border-color: hsl(60, 100%, 50%) }
+/* 75% blue */
+QLabel { border-color: hsla(240, 255, 50%, 75%) }
//! [84]
@@ -1223,7 +1239,7 @@ QScrollBar::sub-line:horizontal {
//! [135]
-QScrollBar:left-arrow:horizontal, QScrollBar::right-arrow:horizontal {
+QScrollBar::left-arrow:horizontal, QScrollBar::right-arrow:horizontal {
border: 2px solid grey;
width: 3px;
height: 3px;
@@ -1267,7 +1283,7 @@ QScrollBar::sub-line:horizontal {
right: 20px;
}
-QScrollBar:left-arrow:horizontal, QScrollBar::right-arrow:horizontal {
+QScrollBar::left-arrow:horizontal, QScrollBar::right-arrow:horizontal {
width: 3px;
height: 3px;
background: pink;
diff --git a/src/widgets/doc/snippets/code/src_gui_dialogs_qmessagebox.cpp b/src/widgets/doc/snippets/code/src_gui_dialogs_qmessagebox.cpp
index 014a9dfeb0..ebc07025ec 100644
--- a/src/widgets/doc/snippets/code/src_gui_dialogs_qmessagebox.cpp
+++ b/src/widgets/doc/snippets/code/src_gui_dialogs_qmessagebox.cpp
@@ -11,23 +11,6 @@ int ret = QMessageBox::warning(this, tr("My Application"),
//! [0]
-//! [1]
-QMessageBox msgBox;
-msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
-switch (msgBox.exec()) {
-case QMessageBox::Yes:
- // yes was clicked
- break;
-case QMessageBox::No:
- // no was clicked
- break;
-default:
- // should never be reached
- break;
-}
-//! [1]
-
-
//! [2]
QMessageBox msgBox;
QPushButton *connectButton = msgBox.addButton(tr("Connect"), QMessageBox::ActionRole);
@@ -100,12 +83,3 @@ switch (ret) {
break;
}
//! [7]
-
-//! [9]
-QMessageBox msgBox(this);
-msgBox.setText(tr("The document has been modified.\n"
- "Do you want to save your changes?"));
-msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard
- | QMessageBox::Cancel);
-msgBox.setDefaultButton(QMessageBox::Save);
-//! [9]
diff --git a/src/widgets/doc/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp b/src/widgets/doc/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp
index e9e8b95847..bcf675d8af 100644
--- a/src/widgets/doc/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp
+++ b/src/widgets/doc/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp
@@ -71,24 +71,6 @@ rect.deviceTransform(view->viewportTransform()).inverted().map(QPointF(100, 100)
//! [5]
-//! [6]
-// Rotate an item 45 degrees around (0, 0).
-item->rotate(45);
-
-// Rotate an item 45 degrees around (x, y).
-item->setTransform(QTransform().translate(x, y).rotate(45).translate(-x, -y));
-//! [6]
-
-
-//! [7]
-// Scale an item by 3x2 from its origin
-item->scale(3, 2);
-
-// Scale an item by 3x2 from (x, y)
-item->setTransform(QTransform().translate(x, y).scale(3, 2).translate(-x, -y));
-//! [7]
-
-
//! [8]
QRectF CircleItem::boundingRect() const
{
@@ -223,19 +205,3 @@ QTransform xform = item->deviceTransform(view->viewportTransform());
QRect deviceRect = xform.mapRect(rect).toAlignedRect();
view->viewport()->scroll(dx, dy, deviceRect);
//! [19]
-
-//! [20]
-item->setTransform(QTransform().rotate(angle), true);
-//! [20]
-
-//! [21]
-setTransform(QTransform::fromScale(sx, sy), true);
-//! [21]
-
-//! [22]
-setTransform(QTransform().shear(sh, sv), true);
-//! [22]
-
-//! [23]
-setTransform(QTransform::fromTranslate(dx, dy), true);
-//! [23]
diff --git a/src/widgets/doc/snippets/code/src_gui_graphicsview_qgraphicsview.cpp b/src/widgets/doc/snippets/code/src_gui_graphicsview_qgraphicsview.cpp
index 9f48c4e06b..0b757cf0a2 100644
--- a/src/widgets/doc/snippets/code/src_gui_graphicsview_qgraphicsview.cpp
+++ b/src/widgets/doc/snippets/code/src_gui_graphicsview_qgraphicsview.cpp
@@ -27,16 +27,6 @@ view.setCacheMode(QGraphicsView::CacheBackground);
//! [2]
-//! [3]
-QGraphicsScene scene;
-scene.addText("GraphicsView rotated clockwise");
-
-QGraphicsView view(&scene);
-view.rotate(90); // the text is rendered with a 90 degree clockwise rotation
-view.show();
-//! [3]
-
-
//! [4]
QGraphicsScene scene;
scene.addItem(...
diff --git a/src/widgets/doc/snippets/code/src_gui_itemviews_qitemeditorfactory.cpp b/src/widgets/doc/snippets/code/src_gui_itemviews_qitemeditorfactory.cpp
index d314c88fd9..1a311015c4 100644
--- a/src/widgets/doc/snippets/code/src_gui_itemviews_qitemeditorfactory.cpp
+++ b/src/widgets/doc/snippets/code/src_gui_itemviews_qitemeditorfactory.cpp
@@ -14,12 +14,16 @@ QItemEditorFactory *factory = new QItemEditorFactory;
//! [1]
+//! [setDefaultFactory]
//! [2]
QItemEditorFactory *editorFactory = new QItemEditorFactory;
QItemEditorCreatorBase *creator = new QStandardItemEditorCreator<MyFancyDateTimeEdit>();
editorFactory->registerEditor(QMetaType::QDateTime, creator);
//! [2]
+QItemEditorFactory::setDefaultFactory(editorFactory);
+//! [setDefaultFactory]
+
//! [3]
Q_PROPERTY(QColor color READ color WRITE setColor USER true)
diff --git a/src/widgets/doc/snippets/code/src_gui_kernel_qapplication.cpp b/src/widgets/doc/snippets/code/src_gui_kernel_qapplication.cpp
index a31e720fb1..0d14b086cc 100644
--- a/src/widgets/doc/snippets/code/src_gui_kernel_qapplication.cpp
+++ b/src/widgets/doc/snippets/code/src_gui_kernel_qapplication.cpp
@@ -31,26 +31,6 @@ QApplication::setStyle(QStyleFactory::create("Fusion"));
//! [1]
-// ### fixme: Qt 6: Remove [2]
-//! [2]
-int main(int argc, char *argv[])
-{
- QApplication::setColorSpec(QApplication::ManyColor);
- QApplication app(argc, argv);
- ...
- return app.exec();
-}
-//! [2]
-
-
-//! [3]
-QSize MyWidget::sizeHint() const
-{
- return QSize(80, 25);
-}
-//! [3]
-
-
//! [4]
void showAllHiddenTopLevelWidgets()
{
@@ -73,82 +53,8 @@ void updateAllWidgets()
//! [5]
-//! [6]
-int main(int argc, char *argv[])
-{
- QApplication::setDesktopSettingsAware(false);
- QApplication app(argc, argv);
- ...
- return app.exec();
-}
-//! [6]
-
-
//! [7]
if ((startPos - currentPos).manhattanLength() >=
QApplication::startDragDistance())
startTheDrag();
//! [7]
-
-
-//! [8]
-void MyApplication::commitData(QSessionManager& manager)
-{
- if (manager.allowsInteraction()) {
- int ret = QMessageBox::warning(
- mainWindow,
- tr("My Application"),
- tr("Save changes to document?"),
- QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
-
- switch (ret) {
- case QMessageBox::Save:
- manager.release();
- if (!saveDocument())
- manager.cancel();
- break;
- case QMessageBox::Discard:
- break;
- case QMessageBox::Cancel:
- default:
- manager.cancel();
- }
- } else {
- // we did not get permission to interact, then
- // do something reasonable instead
- }
-}
-//! [8]
-
-
-//! [9]
-appname -session id
-//! [9]
-
-
-//! [10]
-const QStringList commands = mySession.restartCommand();
-for (const QString &command : commands)
- do_something(command);
-//! [10]
-
-
-//! [11]
-const QStringList commands = mySession.discardCommand();
-for (const QString &command : commands)
- do_something(command);
-//! [11]
-
-
-//! [12]
-QWidget *widget = QApplication::widgetAt(x, y);
-if (widget)
- widget = widget->window();
-//! [12]
-
-
-//! [13]
-QWidget *widget = QApplication::widgetAt(point);
-if (widget)
- widget = widget->window();
-//! [13]
diff --git a/src/widgets/doc/snippets/code/src_gui_kernel_qformlayout.cpp b/src/widgets/doc/snippets/code/src_gui_kernel_qformlayout.cpp
index ab20b9da2e..cb90436462 100644
--- a/src/widgets/doc/snippets/code/src_gui_kernel_qformlayout.cpp
+++ b/src/widgets/doc/snippets/code/src_gui_kernel_qformlayout.cpp
@@ -1,6 +1,8 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+#include <QtCore/qpointer.h>
+
//! [0]
QFormLayout *formLayout = new QFormLayout(this);
formLayout->addRow(tr("&Name:"), nameLineEdit);
diff --git a/src/widgets/doc/snippets/code/src_gui_kernel_qwidget.cpp b/src/widgets/doc/snippets/code/src_gui_kernel_qwidget.cpp
index 8f0c296873..21703c7395 100644
--- a/src/widgets/doc/snippets/code/src_gui_kernel_qwidget.cpp
+++ b/src/widgets/doc/snippets/code/src_gui_kernel_qwidget.cpp
@@ -22,19 +22,6 @@ aWidget->window()->setWindowTitle("New Window Title");
//! [3]
-//! [4]
-QFont font("Helvetica", 12, QFont::Bold);
-setFont(font);
-//! [4]
-
-
-//! [5]
-QFont font;
-font.setBold(false);
-setFont(font);
-//! [5]
-
-
//! [6]
setCursor(Qt::IBeamCursor);
//! [6]
@@ -61,6 +48,11 @@ setTabOrder(c, d); // a to b to c to d
//! [9]
+//! [9.list]
+setTabOrder({a, b, c, d}); // a to b to c to d
+//! [9.list]
+
+
//! [10]
// WRONG
setTabOrder(c, d); // c to d
diff --git a/src/widgets/doc/snippets/code/src_gui_widgets_qgroupbox.cpp b/src/widgets/doc/snippets/code/src_gui_widgets_qgroupbox.cpp
index 1298147de1..cff537c862 100644
--- a/src/widgets/doc/snippets/code/src_gui_widgets_qgroupbox.cpp
+++ b/src/widgets/doc/snippets/code/src_gui_widgets_qgroupbox.cpp
@@ -4,3 +4,20 @@
//! [0]
g->setTitle("&User information");
//! [0]
+
+//! [Set up QGroupBox with layout]
+QGroupBox *groupBox = new QGroupBox(tr("Group Box with Layout"));
+
+QRadioButton *radio1 = new QRadioButton(tr("&Radio button 1"));
+QRadioButton *radio2 = new QRadioButton(tr("R&adio button 2"));
+QRadioButton *radio3 = new QRadioButton(tr("Ra&dio button 3"));
+
+radio1->setChecked(true);
+
+QVBoxLayout *vbox = new QVBoxLayout;
+vbox->addWidget(radio1);
+vbox->addWidget(radio2);
+vbox->addWidget(radio3);
+vbox->addStretch(1);
+groupBox->setLayout(vbox);
+//! [Set up QGroupBox with layout]
diff --git a/src/widgets/doc/snippets/code/src_gui_widgets_qmenu.cpp b/src/widgets/doc/snippets/code/src_gui_widgets_qmenu.cpp
index b0b0500fab..eb0897d5c5 100644
--- a/src/widgets/doc/snippets/code/src_gui_widgets_qmenu.cpp
+++ b/src/widgets/doc/snippets/code/src_gui_widgets_qmenu.cpp
@@ -12,7 +12,7 @@ exec(somewidget.mapToGlobal(QPoint(0,0)));
//! [2]
-exec(e->globalPos());
+exec(e->globalPosition().toPoint());
//! [2]
@@ -27,7 +27,7 @@ exec(somewidget.mapToGlobal(QPoint(0, 0)));
//! [5]
-exec(e->globalPos());
+exec(e->globalPosition().toPoint());
//! [5]
diff --git a/src/widgets/doc/snippets/code/src_gui_widgets_qspinbox.cpp b/src/widgets/doc/snippets/code/src_gui_widgets_qspinbox.cpp
index d660d605a1..ec4b5bf27f 100644
--- a/src/widgets/doc/snippets/code/src_gui_widgets_qspinbox.cpp
+++ b/src/widgets/doc/snippets/code/src_gui_widgets_qspinbox.cpp
@@ -41,3 +41,23 @@ setRange(minimum, maximum);
setMinimum(minimum);
setMaximum(maximum);
//! [7]
+
+//! [8]
+int IconSizeSpinBox::valueFromText(const QString &text) const
+{
+ static const QRegularExpression regExp(tr("(\\d+)(\\s*[xx]\\s*\\d+)?"));
+ Q_ASSERT(regExp.isValid());
+
+ const QRegularExpressionMatch match = regExp.match(text);
+ if (match.isValid())
+ return match.captured(1).toInt();
+ return 0;
+}
+//! [8]
+
+//! [9]
+QString IconSizeSpinBox::textFromValue(int value) const
+{
+ return tr("%1 x %1").arg(value);
+}
+//! [9]
diff --git a/src/widgets/doc/snippets/code/src_gui_widgets_qstatusbar.cpp b/src/widgets/doc/snippets/code/src_gui_widgets_qstatusbar.cpp
index 8f5db27c9f..e05d27353a 100644
--- a/src/widgets/doc/snippets/code/src_gui_widgets_qstatusbar.cpp
+++ b/src/widgets/doc/snippets/code/src_gui_widgets_qstatusbar.cpp
@@ -4,3 +4,11 @@
//! [0]
statusBar()->addWidget(new MyReadWriteIndication);
//! [0]
+
+//! [1]
+statusBar()->showMessage(tr("Ready"));
+//! [1]
+
+//! [2]
+statusBar()->showMessage(tr("Ready"), 2000);
+//! [2]
diff --git a/src/widgets/doc/snippets/code/src_widgets_util_qscroller.cpp b/src/widgets/doc/snippets/code/src_widgets_util_qscroller.cpp
index 03e2a710a4..36e77bf371 100644
--- a/src/widgets/doc/snippets/code/src_widgets_util_qscroller.cpp
+++ b/src/widgets/doc/snippets/code/src_widgets_util_qscroller.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
QWidget *w = ...;
diff --git a/src/widgets/doc/snippets/code/src_widgets_widgets_qmainwindow.cpp b/src/widgets/doc/snippets/code/src_widgets_widgets_qmainwindow.cpp
index f9f9c6c338..9734f2fed0 100644
--- a/src/widgets/doc/snippets/code/src_widgets_widgets_qmainwindow.cpp
+++ b/src/widgets/doc/snippets/code/src_widgets_widgets_qmainwindow.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
//! [0]
void MainWindow::createMenus()
diff --git a/src/widgets/doc/snippets/customviewstyle/CMakeLists.txt b/src/widgets/doc/snippets/customviewstyle/CMakeLists.txt
index 04f89b83b6..f37de58edc 100644
--- a/src/widgets/doc/snippets/customviewstyle/CMakeLists.txt
+++ b/src/widgets/doc/snippets/customviewstyle/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
add_library(widgets_customviewstyle_snippets OBJECT
../customstyle/customstyle.h
diff --git a/src/widgets/doc/snippets/dialogs/dialogs.cpp b/src/widgets/doc/snippets/dialogs/dialogs.cpp
index 441ca8f795..0990d7d7c4 100644
--- a/src/widgets/doc/snippets/dialogs/dialogs.cpp
+++ b/src/widgets/doc/snippets/dialogs/dialogs.cpp
@@ -227,6 +227,35 @@ void Operation::cancel()
}
//! [6]
+void extension()
+{
+ using ExtendedControls = QWidget;
+ QPushButton *findButton;
+ QPushButton *moreButton;
+ QWidget *extension;
+ QVBoxLayout *mainLayout;
+
+//! [extension]
+ mainLayout->setSizeConstraint(QLayout::SetFixedSize);
+
+ findButton = new QPushButton(tr("&Find"));
+ moreButton = new QPushButton(tr("&More..."));
+ moreButton->setCheckable(true);
+
+ extension = new ExtendedControls;
+ mainLayout->addWidget(extension);
+ extension->hide();
+
+ connect(moreButton, &QAbstractButton::toggled, extension, &QWidget::setVisible);
+//! [extension]
+
+//! [buttonbox]
+ QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Vertical);
+ buttonBox->addButton(findButton, QDialogButtonBox::ActionRole);
+ buttonBox->addButton(moreButton, QDialogButtonBox::ActionRole);
+//! [buttonbox]
+}
+
int main()
{
}
diff --git a/src/widgets/doc/snippets/filedialogurls/CMakeLists.txt b/src/widgets/doc/snippets/filedialogurls/CMakeLists.txt
index ed50d801c4..4c64ff3288 100644
--- a/src/widgets/doc/snippets/filedialogurls/CMakeLists.txt
+++ b/src/widgets/doc/snippets/filedialogurls/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
add_library(widgets_filedialogurl_snippets OBJECT
filedialogurls.cpp
diff --git a/src/widgets/doc/snippets/graphicssceneadditem/CMakeLists.txt b/src/widgets/doc/snippets/graphicssceneadditem/CMakeLists.txt
index ffb67a71d1..a2d391d629 100644
--- a/src/widgets/doc/snippets/graphicssceneadditem/CMakeLists.txt
+++ b/src/widgets/doc/snippets/graphicssceneadditem/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
add_library(widgets_graphicssceneadditem_snippets OBJECT
graphicssceneadditemsnippet.cpp
diff --git a/src/widgets/doc/snippets/graphicsview/CMakeLists.txt b/src/widgets/doc/snippets/graphicsview/CMakeLists.txt
index cb1e67068a..e395eda045 100644
--- a/src/widgets/doc/snippets/graphicsview/CMakeLists.txt
+++ b/src/widgets/doc/snippets/graphicsview/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
add_library(widgets_graphicsview_snippets OBJECT
graphicsview.cpp
diff --git a/src/widgets/doc/snippets/mdiarea/CMakeLists.txt b/src/widgets/doc/snippets/mdiarea/CMakeLists.txt
index 8185b1dbd3..3edb2d1b36 100644
--- a/src/widgets/doc/snippets/mdiarea/CMakeLists.txt
+++ b/src/widgets/doc/snippets/mdiarea/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
add_library(widgets_mdiarea_snippets OBJECT
mdiareasnippets.cpp
diff --git a/src/widgets/doc/snippets/myscrollarea/CMakeLists.txt b/src/widgets/doc/snippets/myscrollarea/CMakeLists.txt
index c6e13d533a..9e7e14dc8d 100644
--- a/src/widgets/doc/snippets/myscrollarea/CMakeLists.txt
+++ b/src/widgets/doc/snippets/myscrollarea/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
add_library(widgets_myscrollarea_snippets OBJECT
myscrollarea.cpp
diff --git a/src/widgets/doc/snippets/qitemdelegate/CMakeLists.txt b/src/widgets/doc/snippets/qitemdelegate/CMakeLists.txt
new file mode 100644
index 0000000000..9aad7026c7
--- /dev/null
+++ b/src/widgets/doc/snippets/qitemdelegate/CMakeLists.txt
@@ -0,0 +1,12 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+add_library(widgets_qitemdelegate_snippets OBJECT
+ spinbox-delegate.cpp
+)
+
+target_link_libraries(widgets_qitemdelegate_snippets PRIVATE
+ Qt::Core
+ Qt::Gui
+ Qt::Widgets
+)
diff --git a/src/widgets/doc/snippets/qitemdelegate/spinbox-delegate.cpp b/src/widgets/doc/snippets/qitemdelegate/spinbox-delegate.cpp
new file mode 100644
index 0000000000..efe8a16733
--- /dev/null
+++ b/src/widgets/doc/snippets/qitemdelegate/spinbox-delegate.cpp
@@ -0,0 +1,79 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QStyledItemDelegate>
+#include <QSpinBox>
+
+//! [declaration]
+class SpinBoxDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+
+public:
+ SpinBoxDelegate(QObject *parent = nullptr);
+
+ QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const override;
+
+ void setEditorData(QWidget *editor, const QModelIndex &index) const override;
+ void setModelData(QWidget *editor, QAbstractItemModel *model,
+ const QModelIndex &index) const override;
+
+ void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const override;
+};
+//! [declaration]
+
+//! [constructor]
+SpinBoxDelegate::SpinBoxDelegate(QObject *parent)
+ : QStyledItemDelegate(parent)
+{
+}
+//! [constructor]
+
+//! [createEditor]
+QWidget *SpinBoxDelegate::createEditor(QWidget *parent,
+ const QStyleOptionViewItem &/* option */,
+ const QModelIndex &/* index */) const
+{
+ QSpinBox *editor = new QSpinBox(parent);
+ editor->setFrame(false);
+ editor->setMinimum(0);
+ editor->setMaximum(100);
+
+ return editor;
+}
+//! [createEditor]
+
+//! [setEditorData]
+void SpinBoxDelegate::setEditorData(QWidget *editor,
+ const QModelIndex &index) const
+{
+ int value = index.model()->data(index, Qt::EditRole).toInt();
+
+ QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
+ spinBox->setValue(value);
+}
+//! [setEditorData]
+
+//! [setModelData]
+void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
+ const QModelIndex &index) const
+{
+ QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
+ spinBox->interpretText();
+ int value = spinBox->value();
+
+ model->setData(index, value, Qt::EditRole);
+}
+//! [setModelData]
+
+//! [updateEditorGeometry]
+void SpinBoxDelegate::updateEditorGeometry(QWidget *editor,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &/* index */) const
+{
+ editor->setGeometry(option.rect);
+}
+//! [updateEditorGeometry]
+
diff --git a/src/widgets/doc/snippets/qrhiwidget/rhiwidgetintro.cpp b/src/widgets/doc/snippets/qrhiwidget/rhiwidgetintro.cpp
new file mode 100644
index 0000000000..1cd583e294
--- /dev/null
+++ b/src/widgets/doc/snippets/qrhiwidget/rhiwidgetintro.cpp
@@ -0,0 +1,109 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QRhiWidget>
+#include <QFile>
+#include <rhi/qrhi.h>
+
+//![0]
+class ExampleRhiWidget : public QRhiWidget
+{
+public:
+ ExampleRhiWidget(QWidget *parent = nullptr) : QRhiWidget(parent) { }
+ void initialize(QRhiCommandBuffer *cb) override;
+ void render(QRhiCommandBuffer *cb) override;
+private:
+ QRhi *m_rhi = nullptr;
+ std::unique_ptr<QRhiBuffer> m_vbuf;
+ std::unique_ptr<QRhiBuffer> m_ubuf;
+ std::unique_ptr<QRhiShaderResourceBindings> m_srb;
+ std::unique_ptr<QRhiGraphicsPipeline> m_pipeline;
+ QMatrix4x4 m_viewProjection;
+ float m_rotation = 0.0f;
+};
+
+float vertexData[] = {
+ 0.0f, 0.5f, 1.0f, 0.0f, 0.0f,
+ -0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
+ 0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
+};
+
+QShader getShader(const QString &name)
+{
+ QFile f(name);
+ return f.open(QIODevice::ReadOnly) ? QShader::fromSerialized(f.readAll()) : QShader();
+}
+
+void ExampleRhiWidget::initialize(QRhiCommandBuffer *cb)
+{
+ if (m_rhi != rhi()) {
+ m_pipeline.reset();
+ m_rhi = rhi();
+ }
+
+ if (!m_pipeline) {
+ m_vbuf.reset(m_rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData)));
+ m_vbuf->create();
+
+ m_ubuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64));
+ m_ubuf->create();
+
+ m_srb.reset(m_rhi->newShaderResourceBindings());
+ m_srb->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, m_ubuf.get()),
+ });
+ m_srb->create();
+
+ m_pipeline.reset(m_rhi->newGraphicsPipeline());
+ m_pipeline->setShaderStages({
+ { QRhiShaderStage::Vertex, getShader(QLatin1String(":/shader_assets/color.vert.qsb")) },
+ { QRhiShaderStage::Fragment, getShader(QLatin1String(":/shader_assets/color.frag.qsb")) }
+ });
+ QRhiVertexInputLayout inputLayout;
+ inputLayout.setBindings({
+ { 5 * sizeof(float) }
+ });
+ inputLayout.setAttributes({
+ { 0, 0, QRhiVertexInputAttribute::Float2, 0 },
+ { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) }
+ });
+ m_pipeline->setVertexInputLayout(inputLayout);
+ m_pipeline->setShaderResourceBindings(m_srb.get());
+ m_pipeline->setRenderPassDescriptor(renderTarget()->renderPassDescriptor());
+ m_pipeline->create();
+
+ QRhiResourceUpdateBatch *resourceUpdates = m_rhi->nextResourceUpdateBatch();
+ resourceUpdates->uploadStaticBuffer(m_vbuf.get(), vertexData);
+ cb->resourceUpdate(resourceUpdates);
+ }
+
+ const QSize outputSize = colorTexture()->pixelSize();
+ m_viewProjection = m_rhi->clipSpaceCorrMatrix();
+ m_viewProjection.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 1000.0f);
+ m_viewProjection.translate(0, 0, -4);
+}
+
+void ExampleRhiWidget::render(QRhiCommandBuffer *cb)
+{
+ QRhiResourceUpdateBatch *resourceUpdates = m_rhi->nextResourceUpdateBatch();
+ m_rotation += 1.0f;
+ QMatrix4x4 modelViewProjection = m_viewProjection;
+ modelViewProjection.rotate(m_rotation, 0, 1, 0);
+ resourceUpdates->updateDynamicBuffer(m_ubuf.get(), 0, 64, modelViewProjection.constData());
+
+ const QColor clearColor = QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f);
+ cb->beginPass(renderTarget(), clearColor, { 1.0f, 0 }, resourceUpdates);
+
+ cb->setGraphicsPipeline(m_pipeline.get());
+ const QSize outputSize = colorTexture()->pixelSize();
+ cb->setViewport(QRhiViewport(0, 0, outputSize.width(), outputSize.height()));
+ cb->setShaderResources();
+ const QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf.get(), 0);
+ cb->setVertexInput(0, 1, &vbufBinding);
+ cb->draw(3);
+
+ cb->endPass();
+
+ update();
+}
+//![0]
diff --git a/src/widgets/doc/snippets/qrhiwidget/rhiwidgetintro.frag b/src/widgets/doc/snippets/qrhiwidget/rhiwidgetintro.frag
new file mode 100644
index 0000000000..d86bcf7386
--- /dev/null
+++ b/src/widgets/doc/snippets/qrhiwidget/rhiwidgetintro.frag
@@ -0,0 +1,10 @@
+//![0]
+#version 440
+layout(location = 0) in vec3 v_color;
+layout(location = 0) out vec4 fragColor;
+
+void main()
+{
+ fragColor = vec4(v_color, 1.0);
+}
+//![0]
diff --git a/src/widgets/doc/snippets/qrhiwidget/rhiwidgetintro.vert b/src/widgets/doc/snippets/qrhiwidget/rhiwidgetintro.vert
new file mode 100644
index 0000000000..610df304b1
--- /dev/null
+++ b/src/widgets/doc/snippets/qrhiwidget/rhiwidgetintro.vert
@@ -0,0 +1,15 @@
+//![0]
+#version 440
+layout(location = 0) in vec4 position;
+layout(location = 1) in vec3 color;
+layout(location = 0) out vec3 v_color;
+layout(std140, binding = 0) uniform buf {
+ mat4 mvp;
+};
+
+void main()
+{
+ v_color = color;
+ gl_Position = mvp * position;
+}
+//![0]
diff --git a/src/widgets/doc/snippets/splitter/splitter.cpp b/src/widgets/doc/snippets/splitter/splitter.cpp
index c3a36ba4c0..662ac30eda 100644
--- a/src/widgets/doc/snippets/splitter/splitter.cpp
+++ b/src/widgets/doc/snippets/splitter/splitter.cpp
@@ -37,11 +37,5 @@ int main()
//! [2]
}
-//! [3]
- QListIterator<int> it(splitter->sizes());
- while (it.hasNext())
- processSize(it.next());
-//! [3]
-
return 0;
}
diff --git a/src/widgets/doc/snippets/styles/qcustompixmapstyle.cpp b/src/widgets/doc/snippets/styles/qcustompixmapstyle.cpp
index 8a3a8555eb..67dedb147c 100644
--- a/src/widgets/doc/snippets/styles/qcustompixmapstyle.cpp
+++ b/src/widgets/doc/snippets/styles/qcustompixmapstyle.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "qcustompixmapstyle.h"
diff --git a/src/widgets/doc/snippets/tooltips/main.cpp b/src/widgets/doc/snippets/tooltips/main.cpp
new file mode 100644
index 0000000000..94cc71f711
--- /dev/null
+++ b/src/widgets/doc/snippets/tooltips/main.cpp
@@ -0,0 +1,74 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#include <QtWidgets>
+
+using SearchBar = QWidget;
+using Element = QWidget;
+
+class Window : public QMainWindow
+{
+public:
+ Window(QWidget *parent = nullptr);
+
+protected:
+ bool event(QEvent *event) override;
+
+private:
+ Element *elementAt(QPoint pos) const {
+ return nullptr;
+ }
+
+ QToolBar *fileToolBar;
+ QMenu *fileMenu;
+
+ SearchBar *searchBar;
+};
+
+
+Window::Window(QWidget *parent)
+ : QMainWindow(parent)
+{
+//! [action_tooltip]
+ QAction *openAction = new QAction(tr("&Open..."));
+ openAction->setToolTip(tr("Open an existing file"));
+
+ fileMenu = menuBar()->addMenu(tr("&File"));
+ fileToolBar = addToolBar(tr("&File"));
+
+ fileMenu->addAction(openAction);
+ fileToolBar->addAction(openAction);
+//! [action_tooltip]
+
+//! [static_tooltip]
+ searchBar = new SearchBar;
+ searchBar->setToolTip(tr("Search in the current document"));
+//! [static_tooltip]
+
+ fileToolBar->addWidget(searchBar);
+}
+
+//! [dynamic_tooltip]
+bool Window::event(QEvent *event)
+{
+ if (event->type() == QEvent::ToolTip) {
+ QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
+ if (Element *element = elementAt(helpEvent->pos())) {
+ QToolTip::showText(helpEvent->globalPos(), element->toolTip());
+ } else {
+ QToolTip::hideText();
+ event->ignore();
+ }
+
+ return true;
+ }
+ return QWidget::event(event);
+}
+//! [dynamic_tooltip]
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ Window w;
+ return 0;
+}
diff --git a/src/widgets/doc/src/model-view-programming.qdoc b/src/widgets/doc/src/model-view-programming.qdoc
index 5c09fd0445..5461619a4d 100644
--- a/src/widgets/doc/src/model-view-programming.qdoc
+++ b/src/widgets/doc/src/model-view-programming.qdoc
@@ -686,12 +686,8 @@
implementations of these functions.
Editors for delegates can be implemented either by using widgets to manage
- the editing process or by handling events directly.
- The first approach is covered later in this section, and it is also
- shown in the \l{Spin Box Delegate Example}{Spin Box Delegate} example.
-
- The \l{Pixelator Example}{Pixelator} example shows how to create a
- custom delegate that performs specialized rendering for a table view.
+ the editing process or by handling events directly. The first approach is
+ covered later in this section.
\section2 Using an existing delegate
@@ -721,13 +717,15 @@
data entry. We construct a table view to display the contents of
the model, and this will use the custom delegate for editing.
- \image spinboxdelegate-example.png
+ \image spinboxdelegate-example.webp
We subclass the delegate from \l QStyledItemDelegate because we do not want
to write custom display functions. However, we must still provide
functions to manage the editor widget:
- \snippet itemviews/spinboxdelegate/delegate.h 0
+ \snippet qitemdelegate/spinbox-delegate.cpp declaration
+ \codeline
+ \snippet qitemdelegate/spinbox-delegate.cpp constructor
Note that no editor widgets are set up when the delegate is
constructed. We only construct an editor widget when it is needed.
@@ -741,7 +739,7 @@
supplied with everything that the delegate needs to be able to set up
a suitable widget:
- \snippet itemviews/spinboxdelegate/delegate.cpp 1
+ \snippet qitemdelegate/spinbox-delegate.cpp createEditor
Note that we do not need to keep a pointer to the editor widget because
the view takes responsibility for destroying it when it is no longer
@@ -765,7 +763,7 @@
\l{Qt::ItemDataRole}{display role}, and set the value in the
spin box accordingly.
- \snippet itemviews/spinboxdelegate/delegate.cpp 2
+ \snippet qitemdelegate/spinbox-delegate.cpp setEditorData
In this example, we know that the editor widget is a spin box, but we
could have provided different editors for different types of data in
@@ -778,7 +776,7 @@
asks the delegate to store the edited value in the model by calling the
\l{QAbstractItemDelegate::setModelData()}{setModelData()} function.
- \snippet itemviews/spinboxdelegate/delegate.cpp 3
+ \snippet qitemdelegate/spinbox-delegate.cpp setModelData
Since the view manages the editor widgets for the delegate, we only
need to update the model with the contents of the editor supplied.
@@ -789,8 +787,8 @@
finished editing by emitting the
\l{QAbstractItemDelegate::closeEditor()}{closeEditor()} signal.
The view ensures that the editor widget is closed and destroyed. In
- this example, we only provide simple editing facilities, so we need
- never emit this signal.
+ this example, we only provide simple editing facilities, so we never
+ need to emit this signal.
All the operations on data are performed through the interface
provided by \l QAbstractItemModel. This makes the delegate mostly
@@ -809,7 +807,7 @@
the view provides all the necessary geometry information inside a
\l{QStyleOptionViewItem}{view option} object.
- \snippet itemviews/spinboxdelegate/delegate.cpp 4
+ \snippet qitemdelegate/spinbox-delegate.cpp updateEditorGeometry
In this case, we just use the geometry information provided by the
view option in the item rectangle. A delegate that renders items with
@@ -1818,8 +1816,6 @@
Note that the model will typically need to provide implementations of the
QAbstractItemModel::insertRows() and QAbstractItemModel::setData() functions.
- \sa {itemviews/puzzle}{Item Views Puzzle Example}
-
\section1 Proxy Models
In the model/view framework, items of data supplied by a single model can be shared
@@ -2313,10 +2309,6 @@
\section1 Related Examples
\list
- \li \l{itemviews/dirview}{Dir View}
- \li \l{itemviews/spinboxdelegate}{Spin Box Delegate}
- \li \l{itemviews/pixelator}{Pixelator}
\li \l{itemviews/simpletreemodel}{Simple Tree Model}
- \li \l{itemviews/chart}{Chart}
\endlist
*/
diff --git a/src/widgets/doc/src/modelview.qdoc b/src/widgets/doc/src/modelview.qdoc
index 6ae62ce7cd..7dd7503d29 100644
--- a/src/widgets/doc/src/modelview.qdoc
+++ b/src/widgets/doc/src/modelview.qdoc
@@ -534,7 +534,7 @@
Other references to delegates in Qt Documentation:
\list
- \li \l{Spin Box Delegate Example}
+ \li \l{Delegate Classes}
\li \l{QAbstractItemDelegate}{QAbstractItemDelegate Class Reference}
\li \l{QSqlRelationalDelegate}{QSqlRelationalDelegate Class Reference}
\li \l{QStyledItemDelegate}{QStyledItemDelegate Class Reference}
@@ -827,11 +827,6 @@
\li QStandardItemModel
\li Basic QDataWidgetMapper usage
\row
- \li Spin Box Delegate
- \li QTableView
- \li QStandardItemModel
- \li Custom delegate that uses a spin box as a cell editor
- \row
\li Spreadsheet
\li {2, 1} QTableView
\li Custom delegates
diff --git a/src/widgets/doc/src/qt6-changes.qdoc b/src/widgets/doc/src/qt6-changes.qdoc
index a334fd948c..c4d757fe6d 100644
--- a/src/widgets/doc/src/qt6-changes.qdoc
+++ b/src/widgets/doc/src/qt6-changes.qdoc
@@ -5,7 +5,7 @@
\page widgets-changes-qt6.html
\title Changes to Qt Widgets
\ingroup changes-qt-5-to-6
- \brief Migrate Qt Widgets to Qt 6.
+ \brief Changes in Kernel classes, Widgets, ItemViews, and Utility Classes.
Qt 6 is a result of the conscious effort to make the framework more
efficient and easy to use.
diff --git a/src/widgets/doc/src/qtwidgets-index.qdoc b/src/widgets/doc/src/qtwidgets-index.qdoc
index c0fa5cf3e0..3894467ccf 100644
--- a/src/widgets/doc/src/qtwidgets-index.qdoc
+++ b/src/widgets/doc/src/qtwidgets-index.qdoc
@@ -22,11 +22,10 @@ interfaces
\image parent-child-widgets.png A parent widget containing various child widgets.
The QWidget class provides the basic capability to render to the
- screen, and to handle user input events. All UI elements that Qt
- provides are either subclasses of QWidget, or are used in connection
- with a QWidget subclass. Creating custom widgets is done by
- subclassing QWidget or a suitable subclass and reimplementing the
- virtual event handlers.
+ screen and to handle user input events. All UI elements that Qt
+ provides are either subclasses of QWidget or are used in connection
+ with a QWidget subclass. To create custom widgets, subclass QWidget or a
+ suitable subclass and reimplement the virtual event handlers.
\list
\li \l{Window and Dialog Widgets}
@@ -49,8 +48,9 @@ interfaces
\li \image macos-tabwidget.png
\endtable
- \l{Qt Style Sheets} are a powerful mechanism that allows you to customize the
- appearance of widgets, in addition to what is already possible by subclassing QStyle.
+ \l{Qt Style Sheets} are a powerful mechanism that lets you customize
+ the appearance of widgets, in addition to what is already possible by
+ subclassing QStyle.
\section1 Layouts
@@ -67,7 +67,7 @@ interfaces
\li \image qformlayout-with-6-children.png
\endtable
- \l {Qt Designer} is a powerful tool for interactively creating and
+ \l {Qt Widgets Designer} is a powerful tool for interactively creating and
arranging widgets in layouts.
diff --git a/src/widgets/doc/src/widgets-and-layouts/focus.qdoc b/src/widgets/doc/src/widgets-and-layouts/focus.qdoc
index 6cd8e58543..b49fc89993 100644
--- a/src/widgets/doc/src/widgets-and-layouts/focus.qdoc
+++ b/src/widgets/doc/src/widgets-and-layouts/focus.qdoc
@@ -9,7 +9,7 @@
\keyword keyboard focus
- Qt's widgets handle keyboard focus in the ways that have become
+ Qt's widgets handle keyboard focus in ways that have become
customary in GUIs.
The basic issue is that the user's key strokes can be directed at any
@@ -22,7 +22,7 @@
\section1 Focus Motion
- The customs which have evolved for directing keyboard focus to a
+ The customs that have evolved for directing keyboard focus to a
particular widget are these:
\list 1
@@ -54,7 +54,7 @@
You can customize the tab order using QWidget::setTabOrder(). (If
you don't, \uicontrol Tab generally moves focus in the order of widget
- construction.) Qt Designer provides a means of visually
+ construction.) \QD provides a means of visually
changing the tab order.
Since pressing \uicontrol Tab is so common, most widgets that can have focus
@@ -63,7 +63,7 @@
handler that moves the focus.
For example, in a data entry dialog, there might be a field that
- is only necessary in one per cent of all cases. In such a dialog,
+ is only necessary in one percent of all cases. In such a dialog,
\uicontrol Tab could skip this field, and the dialog could use one of
these mechanisms:
diff --git a/src/widgets/doc/src/widgets-and-layouts/gallery.qdoc b/src/widgets/doc/src/widgets-and-layouts/gallery.qdoc
index 851461af1f..822cf1efff 100644
--- a/src/widgets/doc/src/widgets-and-layouts/gallery.qdoc
+++ b/src/widgets/doc/src/widgets-and-layouts/gallery.qdoc
@@ -15,21 +15,18 @@
integrating to the platform theme. Thus, the final appearance varies
depending on the active theme.
- \table
- \row
- \li The Windows style ("windows") is provided by QWindowsStyle.
- \li \image windows-style.png Windows Style
- \row
- \li \image windows-vista-style.png Windows Vista Style
- \li The Windows Vista style ("windowsvista") is provided by
- QWindowsVistaStyle.
- \row
- \li The macOS style ("macOS") is provided by QMacStyle.
- \li \image macos-style.png \macos Style
- \row
- \li \image fusion-style.png Fusion Style
- \li The Fusion style ("fusion") is provided by QFusionStyle.
- \endtable
+ \image windows-style.png Windows Style
+ \caption The Windows style ("windows") is provided by QWindowsStyle.
+
+ \image windows-vista-style.png Windows Vista Style
+ \caption The Windows Vista style ("windowsvista") is provided by
+ QWindowsVistaStyle.
+
+ \image macos-style.png \macos Style
+ \caption The macOS style ("macOS") is provided by QMacStyle.
+
+ \image fusion-style.png Fusion Style
+ \caption The Fusion style ("fusion") is provided by QFusionStyle.
The Styles example displays the following widgets:
diff --git a/src/widgets/doc/src/widgets-and-layouts/layout.qdoc b/src/widgets/doc/src/widgets-and-layouts/layout.qdoc
index 4a3ded1cb8..5f1d5a7ea9 100644
--- a/src/widgets/doc/src/widgets-and-layouts/layout.qdoc
+++ b/src/widgets/doc/src/widgets-and-layouts/layout.qdoc
@@ -48,8 +48,8 @@
Qt's layout classes were designed for hand-written C++ code, allowing
measurements to be specified in pixels for simplicity, so they are easy to
- understand and use. The code generated for forms created using Qt Designer also
- uses the layout classes. Qt Designer is useful to use when experimenting with the
+ understand and use. The code generated for forms created using \QD also
+ uses the layout classes. \QD is useful to use when experimenting with the
design of a form since it avoids the compile, link and run cycle usually
involved in user interface development.
@@ -263,8 +263,8 @@
\section1 How to Write A Custom Layout Manager
An alternative to manual layout is to write your own layout manager by
- subclassing QLayout. The \l{layouts/borderlayout}{Border Layout} and
- \l{layouts/flowlayout}{Flow Layout} examples show how to do this.
+ subclassing QLayout. The
+ \l{layouts/flowlayout}{Flow Layout} example shows how to do this.
Here we present an example in detail. The \c CardLayout class is inspired
by the Java layout manager of the same name. It lays out the items (widgets
diff --git a/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc b/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc
index fc7193c7bd..05000024e1 100644
--- a/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc
+++ b/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc
@@ -28,7 +28,7 @@
\list
\li \l{Overview}
\li \l{The Style Sheet Syntax}
- \li \l{Qt Designer Integration}
+ \li \l{Qt Widgets Designer Integration}
\li \l{Customizing Qt Widgets Using Style Sheets}
\li \l{Qt Style Sheets Reference}
\li \l{Qt Style Sheets Examples}
@@ -75,7 +75,7 @@
consideration. Unlike palette fiddling, style sheets offer
guarantees: If you set the background color of a QPushButton to be
red, you can be assured that the button will have a red background
- in all styles, on all platforms. In addition, Qt Designer
+ in all styles, on all platforms. In addition, \QD
provides style sheet integration, making it easy to view the effects
of a style sheet in different \l{QStyle}{widget styles}.
@@ -85,22 +85,7 @@
buttons and check boxes to make them stand out. Using this
technique, you can also achieve minor customizations that would
normally require subclassing several style classes, such as
- specifying a \l{QStyle::styleHint()}{style hint}. The
- \l{widgets/stylesheet}{Style Sheet} example depicted below defines
- two distinctive style sheets that you can try out and modify at
- will.
-
- \table
- \row \li \inlineimage stylesheet-pagefold.png
- \row \li Pagefold theme running on Windows
- \endtable
-
- \table
- \row \li \inlineimage stylesheet-coffee-cleanlooks.png
- \li \inlineimage stylesheet-pagefold-mac.png
- \row \li Coffee theme running on Ubuntu Linux
- \li Pagefold theme running on \macos
- \endtable
+ specifying a \l{QStyle::styleHint()}{style hint}.
When a style sheet is active, the QStyle returned by QWidget::style()
is a wrapper "style sheet" style, \e not the platform-specific style. The
@@ -115,7 +100,7 @@
/*!
\page stylesheet-syntax.html
\previouspage Qt Style Sheets
- \nextpage Qt Designer Integration
+ \nextpage Qt Widgets Designer Integration
\title The Style Sheet Syntax
Qt Style Sheet terminology and syntactic rules are almost
@@ -495,11 +480,20 @@
\snippet code/doc_src_stylesheet.cpp 96
When the widget-style font and palette propagation is enabled, font and
- palette changes made through Qt Style Sheets will behave as though the
- user had manually called the corresponding QWidget::setPalette() and
+ palette changes made through Qt Style Sheets will behave as if the user
+ had manually called the corresponding QWidget::setPalette() and
QWidget::setFont() methods on all of the QWidgets targeted by the style
- sheet. If this would have caused propagation in C++, it will cause
- propagation in style sheets and vice versa.
+ sheet.
+
+ \list
+ \li Changes made by a style sheet are propagated.
+ They are pushed to all widgets matching the style sheet once, at the time
+ the change is made.
+ \li Changes made by calling QWidget::setPalette() or QWidget::setFont() are
+ inherited.
+ They are inherited by all existing and future children, where the respective
+ brush or font hasn't been explicitly set.
+ \endlist
\section1 Widgets Inside C++ Namespaces
@@ -525,8 +519,8 @@
For example,
\snippet code/doc_src_stylesheet.qdoc 28
- If the property references an enum declared with Q_ENUMS, you should
- reference its constants by name, i.e., not their numeric value.
+ If the property references an enum declared with Q_ENUM, you should
+ reference its constants by name, not their numeric value.
\note Use the qproperty syntax with care, as it modifies the
widget that is being painted. Also, the qproperty syntax is evaluated only
@@ -538,22 +532,22 @@
\page stylesheet-designer.html
\previouspage The Style Sheet Syntax
\nextpage Customizing Qt Widgets Using Style Sheets
- \title Qt Designer Integration
+ \title Qt Widgets Designer Integration
- Qt Designer{Qt Designer} is an excellent tool
+ \l{Qt Widgets Designer Manual}{\QD} is an excellent tool
to preview style sheets. You can right-click on any widget in Designer
and select \uicontrol{Change styleSheet...} to set the style sheet.
\image designer-stylesheet-options.png
- In Qt 4.2 and later, Qt Designer also includes a
+ In Qt 4.2 and later, \QD also includes a
style sheet syntax highlighter and validator. The validator indicates
if the syntax is valid or invalid, at the bottom left of the \uicontrol{Edit
Style Sheet} dialog.
\image designer-validator-highlighter.png
- When you click \uicontrol{OK} or \uicontrol{Apply}, Qt Designer will automatically display
+ When you click \uicontrol{OK} or \uicontrol{Apply}, \QD will automatically display
the widget with its new stylesheet.
\image designer-stylesheet-usage.png
@@ -561,7 +555,7 @@
/*!
\page stylesheet-customizing.html
- \previouspage Qt Designer Integration
+ \previouspage Qt Widgets Designer Integration
\nextpage Qt Style Sheets Reference
\title Customizing Qt Widgets Using Style Sheets
@@ -687,7 +681,8 @@
\row
\li QAbstractScrollArea \target qabstractscrollarea-widget
\li Supports the \l{box model}.
-
+ \br
+ \br
All derivatives of QAbstractScrollArea, including QTextEdit,
and QAbstractItemView (all item view classes), support
scrollable backgrounds using
@@ -696,7 +691,8 @@
\c{fixed} provides a background-image that does not scroll with the
viewport. Setting the background-attachment to \c{scroll}, scrolls
the background-image when the scroll bars move.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QAbstractScrollArea}
{Customizing QAbstractScrollArea} for an example.
@@ -706,17 +702,21 @@
styled using the \l{#indicator-sub}{::indicator}
subcontrol. By default, the indicator is placed in the Top
Left corner of the Contents rectangle of the widget.
-
+ \br
+ \br
The \l{#spacing-prop}{spacing} property
specifies the spacing between the check indicator and
the text.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QCheckBox}
{Customizing QCheckBox} for an example.
\row
\li QColumnView \target qcolumnview-widget
- \li The grip can be styled be using the \l{image-prop}{image} property.
+ \li The grip can be styled by using the \l{image-prop}{image} property.
+ \br
+ \br
The arrow indicators can by styled using the
\l{left-arrow-sub}{::left-arrow} subcontrol and the
\l{right-arrow-sub}{::right-arrow} subcontrol.
@@ -724,17 +724,25 @@
\row
\li QComboBox \target qcombobox-widget
\li The frame around the combobox can be styled using the
- \l{box model}. The drop-down button can be styled using
+ \l{box model}.
+ \br
+ \br
+ The drop-down button can be styled using
the \l{#drop-down-sub}{::drop-down} subcontrol. By default, the
drop-down button is placed in the top right corner of the padding
- rectangle of the widget. The arrow mark inside the drop-down button
+ rectangle of the widget.
+ \br
+ \br
+ The arrow mark inside the drop-down button
can be styled using the \l{#down-arrow-sub}{::down-arrow}
subcontrol. By default, the arrow is placed in the center of the
contents rectangle of the drop-down subcontrol.
-
+ \br
+ \br
The color of the placeholder text can be set using the
\l{#placeholder-text-color-prop}{placeholder-text-color} property.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QComboBox}{Customizing QComboBox}
for an example.
@@ -763,14 +771,16 @@
\row
\li QDockWidget \target qdockwidget-widget
\li Supports styling of the title bar and the title bar buttons when docked.
-
+ \br
+ \br
The dock widget border can be styled using the \l{#border-prop}{border}
property. The \l{#title-sub}{::title} subcontrol can be used to customize
the title bar. The close and float buttons are positioned with respect
to the \l{title-sub}{::title} subcontrol using the
\l{#close-button-sub}{::close-button} and
\l{#float-button-sub}{::float-button} respectively.
-
+ \br
+ \br
When the title bar is vertical, the \l{#vertical-ps}{:vertical} pseudo
class is set. In addition, depending on QDockWidget::DockWidgetFeature,
the \l{#closable-ps}{:closable}, \l{#floatable-ps}{:floatable} and
@@ -791,31 +801,41 @@
\row
\li QFrame \target qframe-widget
\li Supports the \l{box model}.
-
+ \br
+ \br
Since 4.3, setting a stylesheet on a QLabel automatically
sets the QFrame::frameStyle property to QFrame::StyledPanel.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QFrame}{Customizing QFrame}
for an example.
\row
\li QGroupBox \target qgroupbox-widget
- \li Supports the \l{box model}. The title can be styled using the
+ \li Supports the \l{box model}.
+ \br
+ \br
+ The title can be styled using the
\l{#title-sub}{::title} subcontrol. By default, the title is placed
depending on QGroupBox::textAlignment.
-
+ \br
+ \br
In the case of a checkable QGroupBox, the title includes the
check indicator. The indicator is styled using the
\l{#indicator-sub}{::indicator} subcontrol. The
\l{#spacing-prop}{spacing} property can be used to control
the spacing between the text and indicator.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QGroupBox}{Customizing QGroupBox}
for an example.
\row
\li QHeaderView \target qheaderview-widget
- \li Supports the \l{box model}. The sections of the header view are
+ \li Supports the \l{box model}.
+ \br
+ \br
+ The sections of the header view are
styled using the \l{#section-sub}{::section} sub control. The
\c{section} Sub-control supports the \l{#middle-ps}{:middle},
\l{#first-ps}{:first}, \l{#last-ps}{:last},
@@ -823,11 +843,13 @@
\l{#previous-selected-ps}{:previous-selected},
\l{#selected-ps}{:selected},
and \l{#checked-ps}{:checked} pseudo states.
-
+ \br
+ \br
The sort indicator can be styled using the
\l{#up-arrow-sub}{::up-arrow} and the
\l{#down-arrow-sub}{::down-arrow} Sub-control.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QHeaderView}{Customizing QHeaderView}
for an example.
@@ -835,57 +857,72 @@
\li QLabel \target qlabel-widget
\li Supports the \l{box model}. Does not support the
\l{#hover-ps}{:hover} pseudo-state.
-
+ \br
+ \br
Since 4.3, setting a stylesheet on a QLabel automatically
sets the QFrame::frameStyle property to QFrame::StyledPanel.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QFrame}{Customizing QFrame} for an
example (a QLabel derives from QFrame).
\row
\li QLineEdit \target qlineedit-widget
\li Supports the \l{box model}.
-
+ \br
+ \br
The color and background of the selected item is styled using
\l{#selection-color-prop}{selection-color} and
\l{#selection-background-color-prop}{selection-background-color}
respectively.
-
+ \br
+ \br
The color of the placeholder text can be set using the
\l{#placeholder-text-color-prop}{placeholder-text-color} property.
-
+ \br
+ \br
The password character can be styled using the
\l{#lineedit-password-character-prop}{lineedit-password-character}
property.
-
+ \br
+ \br
The password mask delay can be changed using the
\l{#lineedit-password-mask-delay-prop}{lineedit-password-mask-delay}
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QLineEdit}{Customizing QLineEdit}
for an example.
\row
\li QListView \target qlistview-widget
- \li Supports the \l{box model}. When
+ \li Supports the \l{box model}.
+ \br
+ \br
+ When
\l{QAbstractItemView::alternatingRowColors}{alternating row colors}
is enabled, the alternating colors can be styled using the
\l{#alternate-background-color-prop}{alternate-background-color}
property.
-
+ \br
+ \br
The color and background of the selected item is styled using
\l{#selection-color-prop}{selection-color} and
\l{#selection-background-color-prop}{selection-background-color}
respectively.
-
+ \br
+ \br
The selection behavior is controlled by the
\l{#show-decoration-selected-prop}{show-decoration-selected} property.
-
+ \br
+ \br
Use the \l{#item-sub}{::item} subcontrol for more fine grained
control over the items in the QListView.
-
+ \br
+ \br
See \l{qabstractscrollarea-widget}{QAbsractScrollArea} to
style scrollable backgrounds.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QListView}
{Customzing QListView} for an example.
@@ -895,45 +932,57 @@
\row
\li QMainWindow \target qmainwindow-widget
- \li Supports styling of the separator
-
+ \li Supports styling of the separator.
+ \br
+ \br
The separator in a QMainWindow when using QDockWidget is styled
using the \l{#separator-sub}{::separator} subcontrol.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QMainWindow}{Customizing QMainWindow}
for an example.
\row
\li QMenu \target qmenu-widget
\li Supports the \l{box model}.
-
+ \br
+ \br
Individual items are styled using the \l{#item-sub}{::item}
subcontrol. In addition to the usually supported pseudo states,
\c{item} subcontrol supports the
\l{#selected-ps}{:selected}, \l{#default-ps}{:default},
\l{#exclusive-ps}{:exclusive} and the
\l{#non-exclusive-ps}{non-exclusive} pseudo states.
-
+ \br
+ \br
The indicator of checkable menu items is styled using the
\l{#indicator-sub}{::indicator} subcontrol.
-
+ \br
+ \br
The separator is styled using the \l{#separator-sub}{::separator}
subcontrol.
-
+ \br
+ \br
For items with a sub menu, the arrow marks are styled using the
\l{right-arrow-sub}{right-arrow} and
\l{left-arrow-sub}{left-arrow}.
-
+ \br
+ \br
The scroller is styled using the \l{#scroller-sub}{::scroller}.
-
+ \br
+ \br
The tear-off is styled using the \l{#tearoff-sub}{::tearoff}.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QMenu}{Customizing QMenu}
for an example.
\row
\li QMenuBar \target qmenubar-widget
- \li Supports the \l{box model}. The \l{#spacing-prop}{spacing}
+ \li Supports the \l{box model}.
+ \br
+ \br
+ The \l{#spacing-prop}{spacing}
property specifies the spacing between menu items.
Individual items are styled using the \l{#item-sub}{::item}
subcontrol.
@@ -952,27 +1001,38 @@
\row
\li QProgressBar \target qprogressbar-widget
- \li Supports the \l{box model}. The chunks of the progress bar
+ \li Supports the \l{box model}.
+ \br
+ \br
+ The chunks of the progress bar
can be styled using the \l{#chunk-sub}{::chunk} subcontrol.
The chunk is displayed on the Contents rectangle of the widget.
-
+ \br
+ \br
If the progress bar displays text, use the \l{text-align-prop}{text-align}
property to position the text.
-
+ \br
+ \br
Indeterminate progress bars have the
\l{#indeterminate-ps}{:indeterminate} pseudo state set.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QProgressBar}{Customizing QProgressBar}
for an example.
\row
\li QPushButton \target qpushbutton-widget
- \li Supports the \l{box model}. Supports the \l{#default-ps}{:default},
+ \li Supports the \l{box model}.
+ \br
+ \br
+ Supports the \l{#default-ps}{:default},
\l{#flat-ps}{:flat}, \l{#checked-ps}{:checked} pseudo states.
-
+ \br
+ \br
Since 5.15, the \l{#icon-prop}{icon} property can be set to
override the button icon.
-
+ \br
+ \br
For QPushButton with a menu, the menu indicator is styled
using the \l{#menu-indicator-sub}{::menu-indicator}
subcontrol. Appearance of checkable push buttons can be
@@ -991,50 +1051,63 @@
\row
\li QRadioButton \target qradiobutton-widget
- \li Supports the \l{box model}. The check indicator can be
+ \li Supports the \l{box model}.
+ \br
+ \br
+ The check indicator can be
styled using the \l{#indicator-sub}{::indicator}
subcontrol. By default, the indicator is placed in the Top
Left corner of the Contents rectangle of the widget.
-
+ \br
+ \br
The \l{#spacing-prop}{spacing} property
specifies the spacing between the check indicator and
the text.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QRadioButton}
{Customizing QRadioButton} for an example.
\row
\li QScrollBar \target qscrollbar-widget
- \li Supports the \l{box model}. The Contents rectangle of the widget
+ \li Supports the \l{box model}.
+ \br
+ \br
+ The Contents rectangle of the widget
is considered to be the groove over which the slider moves. The extent
of the QScrollBar (i.e the width or the height depending on the orientation)
is set using the \l{#width-prop}{width} or \l{#height-prop}{height} property
respectively. To determine the orientation, use the
\l{#horizontal-ps}{:horizontal} and the \l{vertical-ps}{:vertical}
pseudo states.
-
+ \br
+ \br
The slider can be styled using the \l{#handle-sub}{::handle} subcontrol.
Setting the \l{#min-width-prop}{min-width} or \l{#min-height-prop}{min-height}
provides size constraints for the slider depending on the orientation.
-
+ \br
+ \br
The \l{add-line-sub}{::add-line} subcontrol can be used to style the
button to add a line. By default, the add-line subcontrol is placed in
top right corner of the Border rectangle of the widget. Depending on the
orientation the \l{#right-arrow-sub}{::right-arrow} or
\l{#down-arrow-sub}{::down-arrow}. By default, the arrows are placed in
the center of the Contents rectangle of the add-line subcontrol.
-
+ \br
+ \br
The \l{sub-line-sub}{::sub-line} subcontrol can be used to style the
button to subtract a line. By default, the sub-line subcontrol is placed in
bottom right corner of the Border rectangle of the widget. Depending on the
orientation the \l{#left-arrow-sub}{::left-arrow} or
\l{#up-arrow-sub}{::up-arrow}. By default, the arrows are placed in
the center of the Contents rectangle of the sub-line subcontrol.
-
+ \br
+ \br
The \l{sub-page-sub}{::sub-page} subcontrol can be used to style the
region of the slider that subtracts a page. The \l{add-page-sub}{::add-page}
subcontrol can be used to style the region of the slider that adds a page.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QScrollBar}{Customizing QScrollBar}
for an example.
@@ -1043,25 +1116,31 @@
\li Supports the \l{#width-prop}{width},
\l{#height-prop}{height}, and \l{#image-prop}{image}
properties.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QSizeGrip}{Customizing QSizeGrip}
for an example.
\row
\li QSlider \target qslider-widget
- \li Supports the \l{box model}. For horizontal slides, the
+ \li Supports the \l{box model}.
+ \br
+ \br
+ For horizontal slides, the
\l{min-width-prop}{min-width} and \l{height-prop}{height}
properties must be provided. For vertical sliders, the
\l{min-height-prop}{min-height} and \l{width-prop}{width}
properties must be provided.
-
+ \br
+ \br
The groove of the slider is styled
using the \l{#groove-sub}{::groove}. The groove is
positioned by default in the Contents rectangle of the widget.
The thumb of the slider is styled using \l{#handle-sub}{::handle}
subcontrol. The subcontrol moves in the Contents rectangle of
the groove subcontrol.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QSlider}{Customizing QSlider}
for an example.
@@ -1069,7 +1148,8 @@
\li QSpinBox \target qspinbox-widget
\li The frame of the spin box can be styled using the \l{box
model}.
-
+ \br
+ \br
The up button and arrow can be styled using the
\l{#up-button-sub}{::up-button} and
\l{#up-arrow-sub}{::up-arrow} subcontrols. By default,
@@ -1078,7 +1158,8 @@
it occupies half the height of its reference rectangle.
The up-arrow is placed in the center of the Contents
rectangle of the up-button.
-
+ \br
+ \br
The down button and arrow can be styled using the
\l{#down-button-sub}{::down-button} and
\l{#down-arrow-sub}{::down-arrow} subcontrols. By default,
@@ -1087,7 +1168,8 @@
it occupies half the height of its reference rectangle.
The bottom-arrow is placed in the center of the Contents
rectangle of the bottom-button.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QSpinBox}{Customizing QSpinBox}
for an example.
@@ -1095,7 +1177,8 @@
\li QSplitter \target qsplitter-widget
\li Supports the \l{box model}. The handle of the splitter
is styled using the \l{#handle-sub}{::handle} subcontrol.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QSplitter}{Customizing QSplitter}
for an example.
@@ -1105,39 +1188,46 @@
{background} property.
The frame for individual items can be style using the
\l{#item-sub}{::item} subcontrol.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QStatusBar}{Customizing QStatusBar}
for an example.
\row
\li QTabBar \target qtabbar-widget
\li Individual tabs may be styled using the \l{#tab-sub}{::tab} subcontrol.
- Close buttons using the \l{#close-button-sub}{::close-button}
+ Close buttons using the \l{#close-button-sub}{::close-button}.
The tabs support the
\l{#only-one-ps}{:only-one}, \l{#first-ps}{:first},
\l{#last-ps}{:last}, \l{#middle-ps}{:middle},
\l{#previous-selected-ps}{:previous--selected},
\l{#next-selected-ps}{:next-selected},
\l{#selected-ps}{:selected} pseudo states.
-
+ \br
+ \br
The \l{#top-ps}{:top}, \l{#left-ps}{:left}, \l{#right-ps}{:right},
\l{#bottom-ps}{:bottom} pseudo states depending on the orientation
of the tabs.
-
+ \br
+ \br
Overlapping tabs for the selected state are created by using
negative margins or using the \c{absolute} position scheme.
-
+ \br
+ \br
The tear indicator of the QTabBar is styled using the
\l{#tear-sub}{::tear} subcontrol.
-
+ \br
+ \br
QTabBar used two QToolButtons for its scrollers that can be styled
using the \c{QTabBar QToolButton} selector. To specify the width
of the scroll button use the \l{#scroller-sub}{::scroller}
subcontrol.
-
+ \br
+ \br
The alignment of the tabs within the QTabBar is styled
- using the \l{#Alignment}{alignment} property. \warning
-
+ using the \l{#Alignment}{alignment} property.
+ \br
+ \warning
To change the position of the QTabBar within a QTabWidget, use the
\l{#tab-bar-sub}{tab-bar} subcontrol (and set subcontrol-position).
@@ -1152,15 +1242,18 @@
and \l{#right-corner-sub}{::right-corner} respectively.
The position of the tab bar is controlled using the
\l{#tab-bar-sub}{::tab-bar} subcontrol.
-
+ \br
+ \br
By default, the subcontrols have positions of a QTabWidget in
the QWindowsStyle. To place the QTabBar in the center, set the
subcontrol-position of the tab-bar subcontrol.
-
+ \br
+ \br
The \l{#top-ps}{:top}, \l{#left-ps}{:left}, \l{#right-ps}{:right},
\l{#bottom-ps}{:bottom} pseudo states depending on the orientation
of the tabs.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QTabWidget and QTabBar}
{Customizing QTabWidget} for an example.
@@ -1171,27 +1264,32 @@
is enabled, the alternating colors can be styled using the
\l{#alternate-background-color-prop}{alternate-background-color}
property.
-
+ \br
+ \br
The color and background of the selected item is styled using
\l{#selection-color-prop}{selection-color} and
\l{#selection-background-color-prop}{selection-background-color}
respectively.
-
+ \br
+ \br
The corner widget in a QTableView is implemented as a QAbstractButton
and can be styled using the "QTableView QTableCornerButton::section"
selector.
-
+ \br
\warning If you only set a background-color on a QTableCornerButton,
the background may not appear unless you set the border property to
some value. This is because, by default, the QTableCornerButton draws a
native border which completely overlaps the background-color.
+ \br
The color of the grid can be specified using the
\l{#gridline-color-prop}{gridline-color} property.
-
+ \br
+ \br
See \l{qabstractscrollarea-widget}{QAbsractScrollArea} to
style scrollable backgrounds.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QTableView}
{Customzing QTableView} for an example.
@@ -1202,15 +1300,18 @@
\row
\li QTextEdit \target qtextedit-widget
\li Supports the \l{box model}.
-
+ \br
+ \br
The color and background of selected text is styled using
\l{#selection-color-prop}{selection-color} and
\l{#selection-background-color-prop}{selection-background-color}
respectively.
-
+ \br
+ \br
The color of the placeholder text can be set using the
\l{#placeholder-text-color-prop}{placeholder-text-color} property.
-
+ \br
+ \br
See \l{qabstractscrollarea-widget}{QAbsractScrollArea} to
style scrollable backgrounds.
@@ -1221,45 +1322,53 @@
\row
\li QToolBar \target qtoolbar-widget
\li Supports the \l{box model}.
-
+ \br
+ \br
The \l{#top-ps}{:top}, \l{#left-ps}{:left}, \l{#right-ps}{:right},
\l{#bottom-ps}{:bottom} pseudo states depending on the area in
which the tool bar is grouped.
-
+ \br
+ \br
The \l{#first-ps}{:first}, \l{#last-ps}{:last}, \l{#middle-ps}{:middle},
\l{#only-one-ps}{:only-one} pseudo states indicator the position
of the tool bar within a line group (See
QStyleOptionToolBar::positionWithinLine).
-
+ \br
+ \br
The separator of a QToolBar is styled using the
\l{#separator-sub}{::separator} subcontrol.
-
+ \br
+ \br
The handle (to move the toolbar) is styled using the
\l{#handle-sub}{::handle} subcontrol.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QToolBar}{Customizing QToolBar}
for an example.
\row
\li QToolButton \target qtoolbutton-widget
\li Supports the \l{box model}.
-
+ \br
+ \br
If the QToolButton has a menu, is
\l{#menu-indicator-sub}{::menu-indicator} subcontrol can be used to
style the indicator. By default, the menu-indicator is positioned
at the bottom right of the Padding rectangle of the widget.
-
+ \br
+ \br
If the QToolButton is in QToolButton::MenuButtonPopup mode,
the \l{#menu-button-sub}{::menu-button} subcontrol is used to draw the
menu button. \l{#menu-arrow-sub}{::menu-arrow} subcontrol is used to
draw the menu arrow inside the menu-button. By default, it is
positioned in the center of the Contents rectangle of the
menu-button subcontrol.
-
+ \br
+ \br
When the QToolButton displays arrows, the \l{#up-arrow-sub}{::up-arrow},
\l{#down-arrow-sub}{::down-arrow}, \l{#left-arrow-sub}{::left-arrow}
and \l{#right-arrow-sub}{::right-arrow} subcontrols are used.
-
+ \br
\warning If you only set a background-color on a QToolButton, the background
will not appear unless you set the border property to some value. This is
because, by default, the QToolButton draws a native border which completely
@@ -1273,7 +1382,8 @@
\row
\li QToolBox \target qtoolbox-widget
\li Supports the \l{box model}.
-
+ \br
+ \br
The individual tabs can by styled using the
\l{#tab-sub}{::tab} subcontrol. The tabs support the
\l{#only-one-ps}{:only-one}, \l{#first-ps}{:first},
@@ -1286,7 +1396,8 @@
\li QToolTip \target qtooltip-widget
\li Supports the \l{box model}. The \l{#opacity-prop}{opacity}
property controls the opacity of the tooltip.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QFrame}{Customizing QFrame}
for an example (a QToolTip is a QFrame).
@@ -1297,27 +1408,33 @@
is enabled, the alternating colors can be styled using the
\l{#alternate-background-color-prop}{alternate-background-color}
property.
-
+ \br
+ \br
The color and background of the selected item is styled using
\l{#selection-color-prop}{selection-color} and
\l{#selection-background-color-prop}{selection-background-color}
respectively.
-
+ \br
+ \br
The selection behavior is controlled by the
\l{#show-decoration-selected-prop}{show-decoration-selected} property.
-
+ \br
+ \br
The branches of the tree view can be styled using the
\l{#branch-sub}{::branch} subcontrol. The
::branch Sub-control supports the \l{open-ps}{:open},
\l{closed-ps}{:closed}, \l{has-siblings-ps}{:has-sibling} and
\l{has-children-ps}{:has-children} pseudo states.
-
+ \br
+ \br
Use the \l{#item-sub}{::item} subcontrol for more fine grained
control over the items in the QTreeView.
-
+ \br
+ \br
See \l{qabstractscrollarea-widget}{QAbsractScrollArea} to
style scrollable backgrounds.
-
+ \br
+ \br
See \l{Qt Style Sheets Examples#Customizing QTreeView}{Customizing QTreeView}
for an example to style the branches.
@@ -1330,7 +1447,8 @@
\li Supports only the \l{Qt Style Sheets Reference#background-prop}{background},
\l{#background-clip-prop}{background-clip} and
\l{#background-origin-prop}{background-origin} properties.
-
+ \br
+ \br
If you subclass from QWidget, you need to provide a paintEvent for your
custom QWidget as below:
\snippet code/doc_src_stylesheet.cpp 32
@@ -1344,23 +1462,44 @@
\section1 List of Properties
- The table below lists all the properties supported by Qt Style
- Sheets. Which values can be given to an property depend on the
+ This section lists all the properties supported by Qt Style
+ Sheets. Which values can be given to a property depend on the
\l{List of Property Types}{property's type}. Unless otherwise
- specified, properties below apply to all widgets. Properties
+ specified, the following properties apply to all widgets. Properties
marked with an asterisk * are specific to Qt and have no equivalent
- in CSS2 or CSS3.
+ in CSS2 or CSS3. The Qt-specific properties are the following:
+ \list
+ \li \l{#gridline-color*}{gridline-color*}
+ \li \l{#image*}{image*}
+ \li \l{#lineedit-password-character*}{lineedit-password-character*}
+ \li \l{#lineedit-password-mask-delay*}{lineedit-password-mask-delay*}
+ \li \l{#messagebox-text-interaction-flags*}{messagebox-text-interaction-flags*}
+ \li \l{#opacity*}{opacity*}
+ \li \l{#placeholder-text-color*}{placeholder-text-color*}
+ \li \l{#selection-background-color*}{selection-background-color*}
+ \li \l{#selection-color*}{selection-color*}
+ \li \l{#show-decoration-selected*}{show-decoration-selected*}
+ \li \l{#spacing*}{spacing*}
+ \li \l{#subcontrol-origin*}{subcontrol-origin*}
+ \li \l{#subcontrol-position*}{subcontrol-position*}
+ \li \l{#widget-animation-duration*}{widget-animation-duration*}
+ \endlist
- \table 100%
- \header
- \li Property
- \li Type
- \li Description
+ \section2 accent-color
- \row
- \li \b{\c alternate-background-color} \target alternate-background-color-prop
- \li \l{#Brush}{Brush} \br
- \li The \l{QAbstractItemView::alternatingRowColors}
+ \table
+ \row \li \b Type \li \l{#Brush}{Brush}
+ \endtable
+
+ The property sets the \c Accent, which is used to emphasize
+ interactive UI elements. If this property is not set, it defaults to the \c highlight color.
+
+ \section2 alternate-background-color
+ \target alternate-background-color-prop
+ \table
+ \row \li \b Type \li \l{#Brush}{Brush}
+ \endtable
+ The \l{QAbstractItemView::alternatingRowColors}
{alternate background color} used in QAbstractItemView subclasses.
If this property is not set, the default value is
@@ -1374,10 +1513,12 @@
See also \l{Qt Style Sheets Reference#background-prop}{background} and
\l{#selection-background-color-prop}{selection-background-color}.
- \row
- \li \b{\c background} \target background-prop
- \li \l{#Background}{Background}
- \li Shorthand notation for setting the background. Equivalent
+ \section2 background
+ \target background-prop
+ \table
+ \row \li \b Type \li \l{#Background}{Background}
+ \endtable
+ Shorthand notation for setting the background. Equivalent
to specifying \c background-color, \c background-image, \c
background-repeat, and/or \c background-position.
@@ -1408,19 +1549,23 @@
\l{#background-attachment-prop}{background-attachment}
and \l{#alternate-background-color-prop}{alternate-background-color}.
- \row
- \li \c background-color \target background-color-prop
- \li \l{#Brush}{Brush} \br
- \li The background color used for the widget.
+ \section2 background-color
+ \target background-color-prop
+ \table
+ \row \li \b Type \li \l{#Brush}{Brush}
+ \endtable
+ The background color used for the widget.
Examples:
\snippet code/doc_src_stylesheet.qdoc 36
- \row
- \li \c background-image \target background-image-prop
- \li \l{#Url}{Url}
- \li The background image used for the widget. Semi-transparent
+ \section2 background-image
+ \target background-image-prop
+ \table
+ \row \li \b Type \li \l{#Url}{Url}
+ \endtable
+ The background image used for the widget. Semi-transparent
parts of the image let the \c background-color shine
through.
@@ -1428,10 +1573,13 @@
\snippet code/doc_src_stylesheet.qdoc 37
- \row
- \li \c background-repeat \target background-repeat-prop
- \li \l{#Repeat}{Repeat}
- \li Whether and how the background image is repeated to fill
+
+ \section2 background-repeat
+ \target background-repeat-prop
+ \table
+ \row \li \b Type \li \l{#Repeat}{Repeat}
+ \endtable
+ Whether and how the background image is repeated to fill
the \c background-origin rectangle.
If this property is not specified, the background image
@@ -1441,10 +1589,11 @@
\snippet code/doc_src_stylesheet.qdoc 38
- \row
- \li \c background-position
- \li \l{#Alignment}{Alignment}
- \li The alignment of the background image within the \c
+ \section2 background-position
+ \table
+ \row \li \b Type \li \l{#Alignment}{Alignment}
+ \endtable
+ The alignment of the background image within the \c
background-origin rectangle.
If this property is not specified, the alignment is \c
@@ -1454,10 +1603,12 @@
\snippet code/doc_src_stylesheet.qdoc 39
- \row
- \li \b{\c background-attachment} \target background-attachment-prop
- \li \l{#Attachment}{Attachment}
- \li Determines whether the background-image in a QAbstractScrollArea
+ \section2 background-attachment
+ \target background-attachment-prop
+ \table
+ \row \li \b Type \li \l{#Attachment}{Attachment}
+ \endtable
+ Determines whether the background-image in a QAbstractScrollArea
is scrolled or fixed with respect to the viewport.
By default, the background-image scrolls with the viewport.
@@ -1467,10 +1618,12 @@
See also \l{Qt Style Sheets Reference#background-prop}{background}
- \row
- \li \b{\c background-clip} \target background-clip-prop
- \li \l{#Origin}{Origin}
- \li The widget's rectangle, in which the \c background is drawn.
+ \section2 background-clip
+ \target background-clip-prop
+ \table
+ \row \li \b Type \li \l{#Origin}{Origin}
+ \endtable
+ The widget's rectangle, in which the \c background is drawn.
This property specifies the rectangle to which the \c background-color
and \c background-image are clipped.
@@ -1491,10 +1644,13 @@
See also \l{Qt Style Sheets Reference#background-prop}{background},
\l{#background-origin-prop}{background-origin} and \l{The Box Model}.
- \row
- \li \b{\c background-origin} \target background-origin-prop
- \li \l{#Origin}{Origin}
- \li The widget's background rectangle, to use in conjunction
+ \section2 background-origin
+ \target background-origin-prop
+ \table
+ \row \li \b Type \li \l{#Origin}{Origin}
+ \endtable
+
+ The widget's background rectangle, to use in conjunction
with \c background-position and \c background-image.
This property is supported by QAbstractItemView
@@ -1513,10 +1669,13 @@
See also \l{Qt Style Sheets Reference#background-prop}{background} and
\l{The Box Model}.
- \row
- \li \b{\c border} \target border-prop
- \li \l{#Border}{Border}
- \li Shorthand notation for setting the widget's border. Equivalent
+ \section2 border
+ \target border-prop
+ \table
+ \row \li \b Type \li \l{#Border}{Border}
+ \endtable
+
+ Shorthand notation for setting the widget's border. Equivalent
to specifying \c border-color, \c border-style, and/or
\c border-width.
@@ -1530,39 +1689,52 @@
\snippet code/doc_src_stylesheet.qdoc 43
- \row
- \li \c border-top
- \li \l{#Border}{Border}
- \li Shorthand notation for setting the widget's top border.
+ \section2 border-top
+
+ \table
+ \row \li \b Type \li \l{#Border}{Border}
+ \endtable
+
+ Shorthand notation for setting the widget's top border.
Equivalent to specifying \c border-top-color, \c
border-top-style, and/or \c border-top-width.
- \row
- \li \c border-right
- \li \l{#Border}{Border}
- \li Shorthand notation for setting the widget's right border.
+ \section2 border-right
+ \table
+ \row \li \b Type \li \l{#Border}{Border}
+ \endtable
+
+ Shorthand notation for setting the widget's right border.
Equivalent to specifying \c border-right-color, \c
border-right-style, and/or \c border-right-width.
- \row
- \li \c border-bottom
- \li \l{#Border}{Border}
- \li Shorthand notation for setting the widget's bottom border.
+ \section2 border-bottom
+ \table
+ \row \li \b Type \li \l{#Border}{Border}
+ \endtable
+
+ Shorthand notation for setting the widget's bottom border.
Equivalent to specifying \c border-bottom-color, \c
border-bottom-style, and/or \c border-bottom-width.
- \row
- \li \c border-left
- \li \l{#Border}{Border}
- \li Shorthand notation for setting the widget's left border.
+ \section2 border-left
+ \table
+ \row \li \b Type \li \l{#Border}{Border}
+ \endtable
+
+ Shorthand notation for setting the widget's left border.
Equivalent to specifying \c border-left-color, \c
border-left-style, and/or \c border-left-width.
- \row
- \li \b{\c border-color} \target border-attrs
- \target border-color-prop
- \li \l{#Box Colors}{Box Colors}
- \li The color of all the border's edges. Equivalent to
+
+ \section2 border-color
+ \target border-attrs
+ \target border-color-prop
+ \table
+ \row \li \b Type \li \l{#Box Colors}{Box Colors}
+ \endtable
+
+ The color of all the border's edges. Equivalent to
specifying \c border-top-color, \c border-right-color, \c
border-bottom-color, and \c border-left-color.
@@ -1584,30 +1756,41 @@
\l{Qt Style Sheets Reference#border-width-prop}{border-width},
\l{#border-image-prop}{border-image}, and \l{The Box Model}.
- \row
- \li \c border-top-color
- \li \l{#Brush}{Brush} \br
- \li The color of the border's top edge.
+ \section2 border-top-color
+ \table
+ \row \li \b Type \li \l{#Brush}{Brush}
+ \endtable
- \row
- \li \c border-right-color
- \li \l{#Brush}{Brush} \br
- \li The color of the border's right edge.
+ The color of the border's top edge.
- \row
- \li \c border-bottom-color
- \li \l{#Brush}{Brush} \br
- \li The color of the border's bottom edge.
+ \section2 border-right-color
+ \table
+ \row \li \b Type \li \l{#Brush}{Brush}
+ \endtable
- \row
- \li \c border-left-color
- \li \l{#Brush}{Brush} \br
- \li The color of the border's left edge.
+ The color of the border's right edge.
- \row
- \li \b{\c border-image} \target border-image-prop
- \li \l{#Border Image}{Border Image}
- \li The image used to fill the border. The image is cut into
+ \section2 border-bottom-color
+ \table
+ \row \li \b Type \li \l{#Brush}{Brush}
+ \endtable
+
+ The color of the border's bottom edge.
+
+ \section2 border-left-color
+ \table
+ \row \li \b Type \li \l{#Brush}{Brush}
+ \endtable
+
+ The color of the border's left edge.
+
+ \section2 border-image
+ \target border-image-prop
+ \table
+ \row \li \b Type \li \l{#Border Image}{Border Image}
+ \endtable
+
+ The image used to fill the border. The image is cut into
nine parts and stretched appropriately if necessary. See
\l{#Border Image}{Border Image} for details.
@@ -1622,10 +1805,13 @@
\l{Qt Style Sheets Reference#border-width-prop}{border-width}, and
\l{The Box Model}.
- \row
- \li \b{\c border-radius} \target border-radius-prop
- \li \l{#Radius}{Radius}
- \li The radius of the border's corners. Equivalent to
+ \section2 border-radius
+ \target border-radius-prop
+ \table
+ \row \li \b Type \li \l{#Radius}{Radius}
+ \endtable
+
+ The radius of the border's corners. Equivalent to
specifying \c border-top-left-radius, \c
border-top-right-radius, \c border-bottom-right-radius,
and \c border-bottom-left-radius.
@@ -1648,33 +1834,44 @@
See also \l{Qt Style Sheets Reference#border-width-prop}{border-width} and
\l{The Box Model}.
- \row
- \li \c border-top-left-radius
- \li \l{#Radius}{Radius}
- \li The radius of the border's top-left corner.
+ \section2 border-top-left-radius
+ \table
+ \row \li \b Type \li \l{#Radius}{Radius}
+ \endtable
- \row
- \li \c border-top-right-radius
- \li \l{#Radius}{Radius}
- \li The radius of the border's top-right corner.
+ The radius of the border's top-left corner.
- \row
- \li \c border-bottom-right-radius
- \li \l{#Radius}{Radius}
- \li The radius of the border's bottom-right corner. Setting
+ \section2 border-top-right-radius
+ \table
+ \row \li \b Type \li \l{#Radius}{Radius}
+ \endtable
+
+ The radius of the border's top-right corner.
+
+ \section2 border-bottom-right-radius
+ \table
+ \row \li \b Type \li \l{#Radius}{Radius}
+ \endtable
+
+ The radius of the border's bottom-right corner. Setting
this property to a positive value results in a rounded
corner.
- \row
- \li \c border-bottom-left-radius
- \li \l{#Radius}{Radius}
- \li The radius of the border's bottom-left corner. Setting this
+ \section2 border-bottom-left-radius
+ \table
+ \row \li \b Type \li \l{#Radius}{Radius}
+ \endtable
+
+ The radius of the border's bottom-left corner. Setting this
property to a positive value results in a rounded corner.
- \row
- \li \b{\c border-style} \target border-style-prop
- \li \l {Border Style}
- \li The style of all the border's edges.
+ \section2 border-style
+ \target border-style-prop
+ \table
+ \row \li \b Type \li \l{#Border Style}{Border Style}
+ \endtable
+
+ The style of all the border's edges.
This property is supported by QAbstractItemView
subclasses, QAbstractSpinBox subclasses, QCheckBox,
@@ -1692,30 +1889,41 @@
\l{Qt Style Sheets Reference#border-style-prop}{border-style},
\l{#border-image-prop}{border-image}, and \l{The Box Model}.
- \row
- \li \c border-top-style
- \li \l{#Border Style}{Border Style}
- \li The style of the border's top edge.
+ \section2 border-top-style
+ \table
+ \row \li \b Type \li \l{#Border Style}{Border Style}}
+ \endtable
- \row
- \li \c border-right-style
- \li \l{#Border Style}{Border Style}
- \li The style of the border's right edge/
+ The style of the border's top edge.
- \row
- \li \c border-bottom-style
- \li \l{#Border Style}{Border Style}
- \li The style of the border's bottom edge.
+ \section2 border-right-style
+ \table
+ \row \li \b Type \li \l{#Border Style}{Border Style}
+ \endtable
- \row
- \li \c border-left-style
- \li \l{#Border Style}{Border Style}
- \li The style of the border's left edge.
+ The style of the border's right edge.
- \row
- \li \b{\c border-width} \target border-width-prop
- \li \l{#Box Lengths}{Box Lengths}
- \li The width of the border. Equivalent to setting \c
+ \section2 border-bottom-style
+ \table
+ \row \li \b Type \li \l{#Border Style}{Border Style}
+ \endtable
+
+ The style of the border's bottom edge.
+
+ \section2 border-left-style
+ \table
+ \row \li \b Type \li \l{#Border Style}{Border Style}
+ \endtable
+
+ The style of the border's left edge.
+
+ \section2 border-width
+ \target border-width-prop
+ \table
+ \row \li \b Type \li \l{#Box Lengths}{Box Lengths}
+ \endtable
+
+ The width of the border. Equivalent to setting \c
border-top-width, \c border-right-width, \c
border-bottom-width, and \c border-left-width.
@@ -1735,30 +1943,41 @@
\l{#border-image-prop}{border-image}, and
\l{The Box Model}.
- \row
- \li \c border-top-width
- \li \l{#Length}{Length}
- \li The width of the border's top edge.
+ \section2 border-top-width
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
- \row
- \li \c border-right-width
- \li \l{#Length}{Length}
- \li The width of the border's right edge.
+ The width of the border's top edge.
- \row
- \li \c border-bottom-width
- \li \l{#Length}{Length}
- \li The width of the border's bottom edge.
+ \section2 border-right-width
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
- \row
- \li \c border-left-width
- \li \l{#Length}{Length}
- \li The width of the border's left edge.
+ The width of the border's right edge.
- \row
- \li \b{\c bottom} \target bottom-prop
- \li \l{#Length}{Length}
- \li If \l{#position-prop}{position} is \c relative (the
+ \section2 border-bottom-width
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
+
+ The width of the border's bottom edge.
+
+ \section2 border-left-width
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
+
+ The width of the border's left edge.
+
+ \section2 bottom
+ \target bottom-prop
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
+
+ If \l{#position-prop}{position} is \c relative (the
default), moves a subcontrol by a certain offset up;
specifying \tt{bottom: \e{y}} is then equivalent to
specifying \tt{\l{Qt Style Sheets Reference#top-prop}{top}: -\e{y}}.
@@ -1776,10 +1995,14 @@
See also \l{Qt Style Sheets Reference#left-prop}{left}, \l{#right-prop}{right}, and
\l{Qt Style Sheets Reference#top-prop}{top}.
- \row
- \li \b{\c button-layout} \target button-layout-prop
- \li \l{#Number}{Number}
- \li The layout of buttons in a QDialogButtonBox or
+
+ \section2 button-layout
+ \target button-layout-prop
+ \table
+ \row \li \b Type \li \l{#Number}{Number}
+ \endtable
+
+ The layout of buttons in a QDialogButtonBox or
a QMessageBox. The possible values are 0
(\l{QDialogButtonBox::}{WinLayout}), 1
(\l{QDialogButtonBox::}{MacLayout}), 2
@@ -1795,10 +2018,14 @@
\snippet code/doc_src_stylesheet.qdoc 49
- \row
- \li \b{\c color} \target color-prop
- \li \l{#Brush}{Brush} \br
- \li The color used to render text.
+
+ \section2 color
+ \target color-prop
+ \table
+ \row \li \b Type \li \l{#Brush}{Brush} \br
+ \endtable
+
+ The color used to render text.
This property is supported by all widgets that respect
the \l QWidget::palette.
@@ -1814,10 +2041,12 @@
See also \l{Qt Style Sheets Reference#background-prop}{background} and
\l{#selection-color-prop}{selection-color}.
- \row
- \li \b{\c dialogbuttonbox-buttons-have-icons}
- \li \l{#Boolean}{Boolean}
- \li Whether the buttons in a QDialogButtonBox show icons
+ \section2 dialogbuttonbox-buttons-have-icons
+ \table
+ \row \li \b Type \li \l{#Boolean}{Boolean}
+ \endtable
+
+ Whether the buttons in a QDialogButtonBox show icons
If this property is set to 1, the buttons of a QDialogButtonBox
show icons; if it is set to 0, the icons are not shown.
@@ -1846,10 +2075,13 @@
\snippet code/doc_src_stylesheet.qdoc 52
\endomit
- \row
- \li \b{\c font} \target font-prop
- \li \l{#Font}{Font}
- \li Shorthand notation for setting the text's font. Equivalent
+ \section2 font
+ \target font-prop
+ \table
+ \row \li \b Type \li \l{#Font}{Font}
+ \endtable
+
+ Shorthand notation for setting the text's font. Equivalent
to specifying \c font-family, \c font-size, \c font-style,
and/or \c font-weight.
@@ -1863,43 +2095,54 @@
\snippet code/doc_src_stylesheet.qdoc 53
- \row
- \li \c font-family
- \li String
- \li The font family.
+ \section2 font-family
+ \table
+ \row \li \b Type \li String
+ \endtable
+
+ The font family.
Example:
\snippet code/doc_src_stylesheet.qdoc 54
- \row
- \li \c font-size
- \li \l{#Font Size}{Font Size}
- \li The font size. In this version of Qt, only pt and px metrics are
+ \section2 font-size
+ \table
+ \row \li \b Type \li \l{#Font Size}{Font Size}
+ \endtable
+
+ The font size. In this version of Qt, only pt and px metrics are
supported.
Example:
\snippet code/doc_src_stylesheet.qdoc 55
- \row
- \li \c font-style
- \li \l {Font Style}
- \li The font style.
+ \section2 font-style
+ \table
+ \row \li \b Type \li \l {#Font Style} {Font Style}
+ \endtable
+
+ The font style.
Example:
\snippet code/doc_src_stylesheet.qdoc 56
- \row
- \li \c font-weight
- \li \l{#Font Weight}{Font Weight}
- \li The weight of the font.
+ \section2 font-weight
+ \table
+ \row \li \b Type \li \l{#Font Weight}{Font Weight}
+ \endtable
- \row
- \li \b{\c gridline-color}* \target gridline-color-prop
- \li \l{#Color}{Color} \br
- \li The color of the grid line in a QTableView.
+ The weight of the font.
+
+ \section2 gridline-color*
+ \target gridline-color-prop
+ \table
+ \row \li \b Type \li \l{#Color}{Color}
+ \endtable
+
+ The color of the grid line in a QTableView.
If this property is not specified, it defaults to the
value specified by the current style for the
@@ -1909,10 +2152,14 @@
\snippet code/doc_src_stylesheet.qdoc 57
- \row
- \li \b{\c height} \target height-prop
- \li \l{#Length}{Length}
- \li The height of a subcontrol (or in some case, a widget).
+
+ \section2 height
+ \target height-prop
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
+
+ The height of a subcontrol (or in some case, a widget).
If this property is not specified, it defaults to a value
that depends on the subcontrol/widget and on the current style.
@@ -1928,10 +2175,13 @@
See also \l{#width-prop}{width}.
- \row
- \li \b{\c icon} \target icon-prop
- \li \l{#Url}{Url}+
- \li The icon that is used, for widgets that have an icon.
+ \section2 icon
+ \target icon-prop
+ \table
+ \row \li \b Type \li \l{#Url}{Url}+
+ \endtable
+
+ The icon that is used, for widgets that have an icon.
The only widget currently supporting this property is QPushButton.
@@ -1942,10 +2192,13 @@
Available since 5.15.
- \row
- \li \b{\c icon-size} \target icon-size-prop
- \li \l{#Length}{Length}
- \li The width and height of the icon in a widget.
+ \section2 icon-size
+ \target icon-size-prop
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
+
+ The width and height of the icon in a widget.
The icon size of the following widgets can be set using this
property.
@@ -1960,10 +2213,13 @@
\li QTreeView
\endlist
- \row
- \li \b{\c image}* \target image-prop
- \li \l{#Url}{Url}+
- \li The image that is drawn in the contents rectangle of a
+ \section2 image*
+ \target image-prop
+ \table
+ \row \li \b Type \li \l{#Url}{Url}+
+ \endtable
+
+ The image that is drawn in the contents rectangle of a
subcontrol.
The image property accepts a list of \l{#Url}{Url}s or
@@ -1988,16 +2244,23 @@
\snippet code/doc_src_stylesheet.qdoc 59
- \row
- \li \b{\c image-position} \target image-position-prop
- \li \l{#Alignment}{alignment}
- \li In Qt 4.3 and later, the alignment of the image image's position can be specified
+
+ \section2 image-position
+ \target image-position-prop
+ \table
+ \row \li \b Type \li \l{#Alignment}{alignment}
+ \endtable
+
+ In Qt 4.3 and later, the alignment of the image image's position can be specified
using relative or absolute position.
- \row
- \li \b{\c left} \target left-prop
- \li \l{#Length}{Length}
- \li If \l{#position-prop}{position} is \c relative (the
+ \section2 left
+ \target left-prop
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
+
+ If \l{#position-prop}{position} is \c relative (the
default), moves a subcontrol by a certain offset to
the right.
@@ -2015,10 +2278,13 @@
See also \l{#right-prop}{right}, \l{Qt Style Sheets Reference#top-prop}{top}, and
\l{#bottom-prop}{bottom}.
- \row
- \li \b{\c lineedit-password-character*} \target lineedit-password-character-prop
- \li \l{#Number}{Number}
- \li The QLineEdit password character as a Unicode number.
+ \section2 lineedit-password-character*
+ \target lineedit-password-character-prop
+ \table
+ \row \li \b Type \li \l{#Number}{Number}
+ \endtable
+
+ The QLineEdit password character as a Unicode number.
If this property is not specified, it defaults to the
value specified by the current style for the
@@ -2028,27 +2294,33 @@
\snippet code/doc_src_stylesheet.qdoc 61
- \row
- \li \b{\c lineedit-password-mask-delay*} \target lineedit-password-mask-delay-prop
- \li \l{#Number}{Number}
- \li The QLineEdit password mask delay in milliseconds before
+
+ \section2 lineedit-password-mask-delay*
+ \target lineedit-password-mask-delay-prop
+ \table
+ \row \li \b Type \li \l{#Number}{Number}
+ \endtable
+
+ The QLineEdit password mask delay in milliseconds before
\l{#lineedit-password-character-prop}{lineedit-password-character} is applied to visible character.
If this property is not specified, it defaults to the
value specified by the current style for the
\l{QStyle::}{SH_LineEdit_PasswordMaskDelay} style hint.
- \b{This property was added in Qt 5.4.}
+ Available since Qt 5.4.
Example:
\snippet code/doc_src_stylesheet.qdoc 160
+ \section2 margin
+ \target margin-prop
+ \table
+ \row \li \b Type \li \l {#Box Lengths}{Box Lengths}
+ \endtable
- \row
- \li \b{\c margin} \target margin-prop
- \li \l {Box Lengths}
- \li The widget's margins. Equivalent to specifying \c
+ The widget's margins. Equivalent to specifying \c
margin-top, \c margin-right, \c margin-bottom, and \c
margin-left.
@@ -2067,30 +2339,37 @@
See also \l{Qt Style Sheets Reference#padding-prop}{padding},
\l{#spacing-prop}{spacing}, and \l{The Box Model}.
- \row
- \li \c margin-top
- \li \l{#Length}{Length}
- \li The widget's top margin.
+ \section2 margin-top
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
+ The widget's top margin.
- \row
- \li \c margin-right
- \li \l{#Length}{Length}
- \li The widget's right margin.
+ \section2 margin-right
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
+ The widget's right margin.
- \row
- \li \c margin-bottom
- \li \l{#Length}{Length}
- \li The widget's bottom margin.
+ \section2 margin-bottom
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
+ The widget's bottom margin.
- \row
- \li \c margin-left
- \li \l{#Length}{Length}
- \li The widget's left margin.
+ \section2 margin-left
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
+ The widget's left margin.
- \row
- \li \b{\c max-height} \target max-height-prop
- \li \l{#Length}{Length}
- \li The widget's or a subcontrol's maximum height.
+ \section2 max-height
+ \target max-height-prop
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
+
+ The widget's or a subcontrol's maximum height.
This property is supported by QAbstractItemView
subclasses, QAbstractSpinBox subclasses, QCheckBox,
@@ -2107,10 +2386,13 @@
See also \l{#max-width-prop}{max-width}.
- \row
- \li \b{\c max-width} \target max-width-prop
- \li \l{#Length}{Length}
- \li The widget's or a subcontrol's maximum width.
+ \section2 max-width
+ \target max-width-prop
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
+
+ The widget's or a subcontrol's maximum width.
This property is supported by QAbstractItemView
subclasses, QAbstractSpinBox subclasses, QCheckBox,
@@ -2127,11 +2409,13 @@
See also \l{#max-height-prop}{max-height}.
+ \section2 messagebox-text-interaction-flags*
+ \target messagebox-text-interaction-flags-prop
+ \table
+ \row \li \b Type \li \l{#Number}{Number}
+ \endtable
- \row
- \li \b{\c messagebox-text-interaction-flags*} \target messagebox-text-interaction-flags-prop
- \li \l{#Number}{Number}
- \li The interaction behavior for text in a message box.
+ The interaction behavior for text in a message box.
Possible values are based on Qt::TextInteractionFlags.
If this property is not specified, it defaults to the
@@ -2143,10 +2427,13 @@
\snippet code/doc_src_stylesheet.qdoc 65
- \row
- \li \b{\c min-height} \target min-height-prop
- \li \l{#Length}{Length}
- \li The widget's or a subcontrol's minimum height.
+ \section2 min-height
+ \target min-height-prop
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
+
+ The widget's or a subcontrol's minimum height.
This property is supported by QAbstractItemView
subclasses, QAbstractSpinBox subclasses, QCheckBox,
@@ -2169,10 +2456,13 @@
See also \l{#min-width-prop}{min-width}.
- \row
- \li \b{\c min-width} \target min-width-prop
- \li \l{#Length}{Length}
- \li The widget's or a subcontrol's minimum width.
+ \section2 min-width
+ \target min-width-prop
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
+
+ The widget's or a subcontrol's minimum width.
This property is supported by QAbstractItemView
subclasses, QAbstractSpinBox subclasses, QCheckBox,
@@ -2195,10 +2485,13 @@
See also \l{#min-height-prop}{min-height}.
- \row
- \li \b{\c opacity*} \target opacity-prop
- \li \l{#Number}{Number}
- \li The opacity for a widget. Possible values are from 0
+ \section2 opacity*
+ \target opacity-prop
+ \table
+ \row \li \b Type \li \l{#Number}{Number}
+ \endtable
+
+ The opacity for a widget. Possible values are from 0
(transparent) to 255 (opaque). For the moment, this is
only supported for \l{QToolTip}{tooltips}.
@@ -2210,58 +2503,69 @@
\snippet code/doc_src_stylesheet.qdoc 68
- \row
- \li \b outline
- \li
- \li The outline drawn around the object's border.
+ \section2 outline
- \row
- \li \b outline-color
- \li \l{#Color}{Color}
- \li The color of the outline.
+ The outline drawn around the object's border.
+
+ \section2 outline-color
+ \table
+ \row \li \b Type \li \l{#Color}{Color}
+ \endtable
+
+ The color of the outline.
See also \l{Qt Style Sheets Reference#border-color-prop}{border-color}
- \row
- \li \b outline-offset
- \li \l{#Length}{Length}
- \li The outline's offset from the border of the widget.
+ \section2 outline-offset
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
- \row
- \li \b outline-style
- \li
- \li Specifies the pattern used to draw the outline.
- See also \l{Qt Style Sheets Reference#border-style-prop}{border-style}
+ The outline's offset from the border of the widget.
- \row
- \li \b outline-radius
- \li
- \li Adds rounded corners to the outline
+ \section2 outline-style
- \row
- \li \b outline-bottom-left-radius
- \li \l{#Radius}{Radius}
- \li The radius for the bottom-left rounded corner of the outline.
+ Specifies the pattern used to draw the outline.
+ See also \l{Qt Style Sheets Reference#border-style-prop}{border-style}
- \row
- \li \b outline-bottom-right-radius
- \li \l{#Radius}{Radius}
- \li The radius for the bottom-right rounded corner of the outline.
+ \section2 outline-radius
- \row
- \li \b outline-top-left-radius
- \li \l{#Radius}{Radius}
- \li The radius for the top-left corner of the outline.
+ Adds rounded corners to the outline.
- \row
- \li \b outline-top-right-radius
- \li \l{#Radius}{Radius}
- \li The radius for the top-right rounded corner of the outline.
+ \section2 outline-bottom-left-radius
+ \table
+ \row \li \b Type \li \l{#Radius}{Radius}
+ \endtable
+ The radius for the bottom-left rounded corner of the outline.
- \row
- \li \b{\c padding} \target padding-prop
- \li \l{#Box Lengths}{Box Lengths}
- \li The widget's padding. Equivalent to specifying \c
+ \section2 outline-bottom-right-radius
+ \table
+ \row \li \b Type \li \l{#Radius}{Radius}
+ \endtable
+
+ The radius for the bottom-right rounded corner of the outline.
+
+ \section2 outline-top-left-radius
+ \table
+ \row \li \b Type \li \l{#Radius}{Radius}
+ \endtable
+
+ The radius for the top-left corner of the outline.
+
+ \section2 outline-top-right-radius
+ \table
+ \row \li \b Type \li \l{#Radius}{Radius}
+ \endtable
+
+ The radius for the top-right rounded corner of the outline.
+
+ \section2 padding
+ \target padding-prop
+ \table
+ \row \li \b Type \li \l{#Box Lengths}{Box Lengths}
+ \endtable
+
+ The widget's padding. Equivalent to specifying \c
padding-top, \c padding-right, \c padding-bottom, and \c
padding-left.
@@ -2280,37 +2584,50 @@
See also \l{#margin-prop}{margin},
\l{#spacing-prop}{spacing}, and \l{The Box Model}.
- \row
- \li \c padding-top
- \li \l{#Length}{Length}
- \li The widget's top padding.
+ \section2 padding-top
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
- \row
- \li \c padding-right
- \li \l{#Length}{Length}
- \li The widget's right padding.
+ The widget's top padding.
- \row
- \li \c padding-bottom
- \li \l{#Length}{Length}
- \li The widget's bottom padding.
+ \section2 padding-right
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
- \row
- \li \c padding-left
- \li \l{#Length}{Length}
- \li The widget's left padding.
+ The widget's right padding.
- \row
- \li \b{\c paint-alternating-row-colors-for-empty-area}
- \target paint-alternating-row-colors-for-empty-area-prop
- \li \c bool
- \li Whether the QTreeView paints alternating row colors for the empty
+ \section2 padding-bottom
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
+
+ The widget's bottom padding.
+
+ \section2 padding-left
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
+
+ The widget's left padding.
+
+ \section2 paint-alternating-row-colors-for-empty-area
+ \target paint-alternating-row-colors-for-empty-area-prop
+ \table
+ \row \li \b Type \li \c bool
+ \endtable
+
+ Whether the QTreeView paints alternating row colors for the empty
area (i.e the area where there are no items)
- \row
- \li \b{\c placeholder-text-color*} \target placeholder-text-color-prop
- \li \l{#Brush}{Brush} \br
- \li The color used for the placeholder text of text editing widgets.
+ \section2 placeholder-text-color*
+ \target placeholder-text-color-prop
+ \table
+ \row \li \b Type \li \l{#Brush}{Brush} \br
+ \endtable
+
+ The color used for the placeholder text of text editing widgets.
If this property is not set, the default value is whatever
is set for the palette's \l{QPalette::}{PlaceholderText}
@@ -2322,11 +2639,14 @@
Available since 6.5.
- \row
- \li \b{\c position} \target position-prop
- \li \c relative \br
- | \c absolute
- \li Whether offsets specified using \l{Qt Style Sheets Reference#left-prop}{left},
+ \section2 position
+ \target position-prop
+ \table
+ \row \li \b Type \li \c relative \br
+ | \c absolute
+ \endtable
+
+ Whether offsets specified using \l{Qt Style Sheets Reference#left-prop}{left},
\l{#right-prop}{right}, \l{Qt Style Sheets Reference#top-prop}{top}, and
\l{#bottom-prop}{bottom} are relative or absolute
coordinates.
@@ -2334,10 +2654,13 @@
If this property is not specified, it defaults to \c
relative.
- \row
- \li \b{\c right} \target right-prop
- \li \l{#Length}{Length}
- \li If \l{#position-prop}{position} is \c relative (the
+ \section2 right
+ \target right-prop
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
+
+ If \l{#position-prop}{position} is \c relative (the
default), moves a subcontrol by a certain offset to
the left; specifying \tt{right: \e{x}} is then equivalent
to specifying \tt{\l{Qt Style Sheets Reference#left-prop}{left}: -\e{x}}.
@@ -2354,10 +2677,13 @@
See also \l{Qt Style Sheets Reference#left-prop}{left}, \l{Qt Style Sheets Reference#top-prop}{top}, and
\l{#bottom-prop}{bottom}.
- \row
- \li \b{\c selection-background-color*} \target selection-background-color-prop
- \li \l{#Brush}{Brush} \br
- \li The background of selected text or items.
+ \section2 selection-background-color*
+ \target selection-background-color-prop
+ \table
+ \row \li \b Type \li \l{#Brush}{Brush}
+ \endtable
+
+ The background of selected text or items.
This property is supported by all widgets that respect
the \l QWidget::palette and that show selection text.
@@ -2373,10 +2699,14 @@
See also \l{#selection-color-prop}{selection-color} and
\l{Qt Style Sheets Reference#background-prop}{background}.
- \row
- \li \b{\c selection-color*} \target selection-color-prop
- \li \l{#Brush}{Brush} \br
- \li The foreground of selected text or items.
+
+ \section2 selection-color*
+ \target selection-color-prop
+ \table
+ \row \li \b Type \li \l{#Brush}{Brush} \br
+ \endtable
+
+ The foreground of selected text or items.
This property is supported by all widgets that respect
the \l QWidget::palette and that show selection text.
@@ -2393,10 +2723,14 @@
\l{#selection-background-color-prop}{selection-background-color}
and \l{#color-prop}{color}.
- \row
- \li \b{\c show-decoration-selected*} \target show-decoration-selected-prop
- \li \l{#Boolean}{Boolean}
- \li Controls whether selections in a QListView cover the
+
+ \section2 show-decoration-selected*
+ \target show-decoration-selected-prop
+ \table
+ \row \li \b Type \li \l{#Boolean}{Boolean}
+ \endtable
+
+ Controls whether selections in a QListView cover the
entire row or just the extent of the text.
If this property is not specified, it defaults to the
@@ -2408,10 +2742,13 @@
\snippet code/doc_src_stylesheet.qdoc 73
- \row
- \li \b{\c spacing*} \target spacing-prop
- \li \l{#Length}{Length}
- \li Internal spacing in the widget.
+ \section2 spacing*
+ \target spacing-prop
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
+
+ Internal spacing in the widget.
This property is supported by QCheckBox, checkable
\l{QGroupBox}es, QMenuBar, and QRadioButton.
@@ -2426,10 +2763,14 @@
See also \l{Qt Style Sheets Reference#padding-prop}{padding} and
\l{#margin-prop}{margin}.
- \row
- \li \b{\c subcontrol-origin*} \target subcontrol-origin-prop
- \li \l{#Origin}{Origin}
- \li The origin rectangle of the subcontrol within the
+
+ \section2 subcontrol-origin*
+ \target subcontrol-origin-prop
+ \table
+ \row \li \b Type \li \l{#Origin}{Origin}
+ \endtable
+
+ The origin rectangle of the subcontrol within the
parent element.
If this property is not specified, the default is \c
@@ -2442,10 +2783,13 @@
See also
\l{Qt Style Sheets Reference#subcontrol-position-prop}{subcontrol-position}.
- \row
- \li \b{\c subcontrol-position*} \target subcontrol-position-prop
- \li \l{#Alignment}{Alignment}
- \li The alignment of the subcontrol within the origin
+ \section2 subcontrol-position*
+ \target subcontrol-position-prop
+ \table
+ \row \li \b Type \li \l{#Alignment}{Alignment}
+ \endtable
+
+ The alignment of the subcontrol within the origin
rectangle specified by \l{Qt Style Sheets Reference#subcontrol-origin-prop}
{subcontrol-origin}.
@@ -2459,32 +2803,41 @@
See also
\l{Qt Style Sheets Reference#subcontrol-origin-prop}{subcontrol-origin}.
- \row
- \li \b{\c titlebar-show-tooltips-on-buttons}}
- \target titlebar-show-tooltips-on-buttons-prop
- \li \c bool
- \li Whether tool tips are shown on window title bar buttons.
+ \section2 titlebar-show-tooltips-on-buttons
+ \target titlebar-show-tooltips-on-buttons-prop
+ \table
+ \row \li \b Type \li \c bool
+ \endtable
- \row
- \li \b{\c widget-animation-duration*} \target widget-animation-duration
- \li \l{#Number}{Number}
- \li How much an animation should last (in milliseconds).
+ Whether tool tips are shown on window title bar buttons.
+
+
+ \section2 widget-animation-duration*
+ \target widget-animation-duration
+ \table
+ \row \li \b Type \li \l{#Number}{Number}
+ \endtable
+
+ How much an animation should last (in milliseconds).
A value equal to zero means that the animations will be disabled.
If this property is not specified, it defaults to the
value specified by the current style for the
\l{QStyle::}{SH_Widget_Animation_Duration} style hint.
- \b{This property was added in Qt 5.10.}
+ Available since Qt 5.10.
Example:
\snippet code/doc_src_stylesheet.qdoc 162
- \row
- \li \b{\c text-align} \target text-align-prop
- \li \l{#Alignment}{Alignment}
- \li The alignment of text and icon within the contents of the widget.
+ \section2 text-align
+ \target text-align-prop
+ \table
+ \row \li \b Type \li \l{#Alignment}{Alignment}
+ \endtable
+
+ The alignment of text and icon within the contents of the widget.
If this value is not specified, it defaults to the value
that depends on the native style.
@@ -2496,18 +2849,25 @@
This property is currently supported only by QPushButton
and QProgressBar.
- \row
- \li \b{\c text-decoration}
- \li \c none \br
+ \section2 text-decoration
+ \table
+ \row \li \b Type
+ \li \c none \br
\c underline \br
\c overline \br
\c line-through
- \li Additional text effects
+ \endtable
- \row
- \li \b{\c top} \target top-prop
- \li \l{#Length}{Length}
- \li If \l{#position-prop}{position} is \c relative (the
+ Additional text effects.
+
+
+ \section2 top
+ \target top-prop
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
+
+ If \l{#position-prop}{position} is \c relative (the
default), moves a subcontrol by a certain offset
down.
@@ -2525,10 +2885,13 @@
See also \l{Qt Style Sheets Reference#left-prop}{left}, \l{#right-prop}{right}, and
\l{#bottom-prop}{bottom}.
- \row
- \li \b{\c width} \target width-prop
- \li \l{#Length}{Length}
- \li The width of a subcontrol (or a widget in some cases).
+ \section2 width
+ \target width-prop
+ \table
+ \row \li \b Type \li \l{#Length}{Length}
+ \endtable
+
+ The width of a subcontrol (or a widget in some cases).
If this property is not specified, it defaults to a value
that depends on the subcontrol/widget and on the current style.
@@ -2544,19 +2907,24 @@
See also \l{#height-prop}{height}.
- \row
- \li \b -qt-background-role
- \li \l{#paletterole}{PaletteRole}
- \li The \c{background-color} for the subcontrol or widget based on the
+
+ \section2 -qt-background-role
+ \table
+ \row \li \b Type \li \l{#paletterole}{PaletteRole}
+ \endtable
+
+ The \c{background-color} for the subcontrol or widget based on the
chosen role.
- \row
- \li \b -qt-style-features
- \li \c list
- \li The list of CSS properties that you want to apply Qt-specific styles on.
+ \section2 -qt-style-features
+ \table
+ \row \li \b Type \li \c list
+ \endtable
+
+ The list of CSS properties that you want to apply Qt-specific styles on.
\note The \c list can only include properties that are not pixmap-based.
- \endtable
+
\target list of icons
\section1 List of Icons
@@ -3064,6 +3432,7 @@
\row
\li \b{PaletteRole} \target PaletteRole
\li \c alternate-base \br
+ | \c accent \br
| \c base \br
| \c bright-text \br
| \c button \br
@@ -4065,7 +4434,7 @@
\image stylesheet-treeview.png
- \sa {Style Sheet Example}, {Supported HTML Subset}, QStyle
+ \sa {Supported HTML Subset}, QStyle
\section1 Common Mistakes
diff --git a/src/widgets/doc/src/widgets-tutorial.qdoc b/src/widgets/doc/src/widgets-tutorial.qdoc
index c223340079..e0ad4d850c 100644
--- a/src/widgets/doc/src/widgets-tutorial.qdoc
+++ b/src/widgets/doc/src/widgets-tutorial.qdoc
@@ -101,6 +101,7 @@
/*!
\example tutorials/widgets/toplevel
\title Widgets Tutorial - Creating a Window
+ \examplecategory {User Interface Components}
If a widget is created without a parent, it is treated as a window, or
\e{top-level widget}, when it is shown. Since it has no parent object to
@@ -127,6 +128,7 @@
/*!
\example tutorials/widgets/childwidget
\title Widgets Tutorial - Child Widgets
+ \examplecategory {User Interface Components}
We can add a child widget to the window created in the previous example by
passing \c window as the parent to its constructor. In this case, we add a
@@ -149,6 +151,7 @@
/*!
\example tutorials/widgets/windowlayout
\title Widgets Tutorial - Using Layouts
+ \examplecategory {User Interface Components}
Usually, child widgets are arranged inside a window using layout objects
rather than by specifying positions and sizes explicitly. Here, we
@@ -183,6 +186,7 @@
/*!
\example tutorials/widgets/nestedlayouts
\title Widgets Tutorial - Nested Layouts
+ \examplecategory {User Interface Components}
Just as widgets can contain other widgets, layouts can be used to provide
different levels of grouping for widgets. Here, we want to display a
@@ -211,7 +215,7 @@
As well as QHBoxLayout and QVBoxLayout, Qt also provides QGridLayout
and QFormLayout classes to help with more complex user interfaces.
- These can be seen if you run Qt Designer.
+ These can be seen if you run \QD.
\section1 Setting up the Model
diff --git a/src/widgets/doc/src/windows-and-dialogs/mainwindow.qdoc b/src/widgets/doc/src/windows-and-dialogs/mainwindow.qdoc
index 827f7981ae..6b0315f10a 100644
--- a/src/widgets/doc/src/windows-and-dialogs/mainwindow.qdoc
+++ b/src/widgets/doc/src/windows-and-dialogs/mainwindow.qdoc
@@ -6,18 +6,20 @@
\brief Windows and Dialogs in Qt.
\ingroup qt-gui-concepts
- A \l{Widgets Tutorial}{widget} that is not embedded in a parent widget is called a window.
- (Usually, windows have a frame and a title bar, although it is also possible to create
- windows without such decoration using suitable window flags). In Qt, QMainWindow
- and the various subclasses of QDialog are the most common window types.
+ A \l{Widgets Tutorial}{widget} that is not embedded in a parent widget is
+ called a window. Usually, windows have a frame and a title bar, although it
+ is also possible to create windows without such decoration using suitable
+ window flags. In Qt, QMainWindow and the various subclasses of QDialog are
+ the most common window types.
In applications, windows provide the screen space upon which the user
interface is built. Windows separate applications visually from each other
- and usually provide a window decoration that allows the user to resize and
- position the applications according to his preferences. Windows are typically
- integrated into the desktop environment and to some degree managed by the
- window management system that the desktop environment provides. For instance,
- selected windows of an application are represented in the task bar.
+ and usually provide a window decoration that allows you to resize and
+ position the applications according to your preferences. Windows are
+ typically integrated into the desktop environment and to some degree managed
+ by the window management system that the desktop environment provides. For
+ instance, selected windows of an application are represented in the task
+ bar.
\section1 Primary and Secondary Windows
@@ -27,8 +29,8 @@
In addition, a QWidget that has a parent can become a window by setting the
Qt::Window flag. Depending on the window management system
- such \e{secondary windows} are usually stacked on top of their respective parent
- window, and not have a task bar entry of their own.
+ such \e{secondary windows} are usually stacked on top of their respective
+ parent window and do not have a task bar entry of their own.
The QMainWindow class sets the Qt::Window flag in its constructor,
as it is designed to be used as a window and provides facilities that are
@@ -37,20 +39,21 @@
\section1 Main Windows and Dialogs
The \l{Application Main Window} provides the framework for building the
- application's main user interface, and are created by subclassing QMainWindow.
+ application's main user interface and are created by subclassing
+ QMainWindow.
QMainWindow has its own layout to which you can add a \l{QMenuBar}{menu bar},
\l{QToolBar}{tool bars}, \l{QDockWidget}{dockable widgets} and a
\l{QStatusBar}{status bar}. The center area can be occupied by any kind of
QWidget.
- \l{Dialog Windows} are used as secondary windows that present the user with
+ \l{Dialog Windows} are used as secondary windows that present you with
options and choices. Dialogs are created by subclassing QDialog and using
\l{Widgets and Layouts}{widgets and layouts} to implement the user interface.
In addition, Qt provides a number of ready-made standard dialogs that can be
used for standard tasks like file or font selection.
- Both main windows and dialogs can be created with Qt Designer, Qt's visual design tool.
- Using Qt Designer is a lot faster than hand-coding, and makes it easy to test different
+ Both main windows and dialogs can be created with \QD, Qt's visual design tool.
+ Using \QD is a lot faster than hand-coding, and makes it easy to test different
design ideas. Creating designs visually and reading the code generated by
\l{uic} is a great way to learn Qt!
@@ -59,8 +62,8 @@
QWidget provides several functions that deal with a widget's
geometry. Some of these functions operate on the pure client area
- (i.e. the window excluding the window frame), others include the
- window frame. The differentiation is done in a way that covers the
+ (that is, the window excluding the window frame), others include the
+ window frame. QWidget differentiates in a way that covers the
most common usage transparently.
\list
@@ -99,9 +102,9 @@
Furthermore, a toolkit cannot simply place windows on the screen. All
Qt can do is to send certain hints to the window manager. The window
- manager, a separate process, may either obey, ignore or misunderstand
+ manager, a separate process, may either obey, ignore, or misunderstand
them. Due to the partially unclear Inter-Client Communication
- Conventions Manual (ICCCM), window placement is handled quite
+ Conventions Manual (ICCCM), window placement is handled
differently in existing window managers.
X11 provides no standard or easy way to get the frame geometry
@@ -137,8 +140,8 @@
\section1 Overview of the Main Window Classes
These classes provide everything you need for a typical modern main
- application window, like the main window itself, menu and tool bars,
- a status bar, etc.
+ application window, such as the main window itself, menu and tool bars,
+ and a status bar.
\annotatedlist mainwindow-classes
@@ -148,8 +151,8 @@
associated user interface components:
\list
- \li QMainWindow is the central class around which applications
- can be built. Along with the companion QDockWidget and QToolBar
+ \li QMainWindow is the central class around which applications can be
+ built. Along with the companion QDockWidget and QToolBar
classes, it represents the top-level user interface of the application.
\li QDockWidget provides a widget that can be used to create
@@ -166,11 +169,11 @@
\section1 Example Code
- Using QMainWindow is straightforward. Generally, we subclass
+ Using QMainWindow is straightforward. Generally, you subclass
QMainWindow and set up menus, toolbars, and dock widgets inside
the QMainWindow constructor.
- To add a menu bar to the main window, we simply create the menus, and
+ To add a menu bar to the main window, create the menus, and
add them to the main window's menu bar. Note that the
QMainWindow::menuBar() function will automatically create the menu bar
the first time it is called. You can also call
@@ -181,8 +184,8 @@
\snippet mainwindows/menus/mainwindow.cpp 5
\dots
- Once actions have been created, we can add them to the main window
- components. To begin with, we add them to the pop-up menus:
+ Once actions have been created, you can add them to the main window
+ components. To begin with, add them to the pop-up menus:
\snippet mainwindows/menus/mainwindow.cpp 10
\dots
@@ -195,7 +198,7 @@
provides this function, making it easy to reuse actions in different
parts of the main window. This avoids unnecessary duplication of work.
- We create a toolbar as a child of the main window, and add the desired
+ Create a toolbar as a child of the main window, and add the desired
actions to it:
\code
@@ -212,7 +215,7 @@
newAct and \c openAct will be displayed both on the toolbar and in
the file menu.
- QDockWidget is used in a similar way to QToolBar. We create a
+ QDockWidget is used in a similar way to QToolBar. You create a
dock widget as a child of the main window, and add widgets as children
of the dock widget:
@@ -221,7 +224,7 @@
In this example, the dock widget can only be placed in the left and
right dock areas, and it is initially placed in the left dock area.
- The QMainWindow API allows the programmer to customize which dock
+ The QMainWindow API lets you customize which dock
widget areas occupy the four corners of the dock widget area. If
required, the default can be changed with the
QMainWindow::setCorner() function:
@@ -234,7 +237,7 @@
\image mainwindow-docks-example.png
- Once all of the main window components have been set up, the central widget
+ Once all the main window components have been set up, the central widget
is created and installed by using code similar to the following:
\snippet code/doc_src_qt4-mainwindow.cpp 3
diff --git a/src/widgets/effects/qpixmapfilter.cpp b/src/widgets/effects/qpixmapfilter.cpp
index b433d49afc..fc3ea8bba3 100644
--- a/src/widgets/effects/qpixmapfilter.cpp
+++ b/src/widgets/effects/qpixmapfilter.cpp
@@ -15,7 +15,6 @@
#include "private/qpaintengine_raster_p.h"
#include "qmath.h"
#include "private/qmath_p.h"
-#include "private/qmemrotate_p.h"
#include "private/qdrawhelper_p.h"
#include <memory>
@@ -363,7 +362,7 @@ static void convolute(
(((cr*(255-a) >> 8)+r) << 16)+
(((cg*(255-a) >> 8)+g) << 8)+
(((cb*(255-a) >> 8)+b));
- *output++ = color;;
+ *output++ = color;
}
xk++;
}
@@ -555,314 +554,10 @@ QRectF QPixmapBlurFilter::boundingRectFor(const QRectF &rect) const
return rect.adjusted(-delta, -delta, delta, delta);
}
-template <int shift>
-inline int qt_static_shift(int value)
-{
- if (shift == 0)
- return value;
- else if (shift > 0)
- return value << (uint(shift) & 0x1f);
- else
- return value >> (uint(-shift) & 0x1f);
-}
-
-template<int aprec, int zprec>
-inline void qt_blurinner(uchar *bptr, int &zR, int &zG, int &zB, int &zA, int alpha)
-{
- QRgb *pixel = (QRgb *)bptr;
-
-#define Z_MASK (0xff << zprec)
- const int A_zprec = qt_static_shift<zprec - 24>(*pixel) & Z_MASK;
- const int R_zprec = qt_static_shift<zprec - 16>(*pixel) & Z_MASK;
- const int G_zprec = qt_static_shift<zprec - 8>(*pixel) & Z_MASK;
- const int B_zprec = qt_static_shift<zprec>(*pixel) & Z_MASK;
-#undef Z_MASK
-
- const int zR_zprec = zR >> aprec;
- const int zG_zprec = zG >> aprec;
- const int zB_zprec = zB >> aprec;
- const int zA_zprec = zA >> aprec;
-
- zR += alpha * (R_zprec - zR_zprec);
- zG += alpha * (G_zprec - zG_zprec);
- zB += alpha * (B_zprec - zB_zprec);
- zA += alpha * (A_zprec - zA_zprec);
-
-#define ZA_MASK (0xff << (zprec + aprec))
- *pixel =
- qt_static_shift<24 - zprec - aprec>(zA & ZA_MASK)
- | qt_static_shift<16 - zprec - aprec>(zR & ZA_MASK)
- | qt_static_shift<8 - zprec - aprec>(zG & ZA_MASK)
- | qt_static_shift<-zprec - aprec>(zB & ZA_MASK);
-#undef ZA_MASK
-}
-
-const int alphaIndex = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3);
-
-template<int aprec, int zprec>
-inline void qt_blurinner_alphaOnly(uchar *bptr, int &z, int alpha)
-{
- const int A_zprec = int(*(bptr)) << zprec;
- const int z_zprec = z >> aprec;
- z += alpha * (A_zprec - z_zprec);
- *(bptr) = z >> (zprec + aprec);
-}
-
-template<int aprec, int zprec, bool alphaOnly>
-inline void qt_blurrow(QImage & im, int line, int alpha)
-{
- uchar *bptr = im.scanLine(line);
-
- int zR = 0, zG = 0, zB = 0, zA = 0;
-
- if (alphaOnly && im.format() != QImage::Format_Indexed8)
- bptr += alphaIndex;
-
- const int stride = im.depth() >> 3;
- const int im_width = im.width();
- for (int index = 0; index < im_width; ++index) {
- if (alphaOnly)
- qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
- else
- qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
- bptr += stride;
- }
-
- bptr -= stride;
-
- for (int index = im_width - 2; index >= 0; --index) {
- bptr -= stride;
- if (alphaOnly)
- qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
- else
- qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
- }
-}
-
-/*
-* expblur(QImage &img, int radius)
-*
-* Based on exponential blur algorithm by Jani Huhtanen
-*
-* In-place blur of image 'img' with kernel
-* of approximate radius 'radius'.
-*
-* Blurs with two sided exponential impulse
-* response.
-*
-* aprec = precision of alpha parameter
-* in fixed-point format 0.aprec
-*
-* zprec = precision of state parameters
-* zR,zG,zB and zA in fp format 8.zprec
-*/
-template <int aprec, int zprec, bool alphaOnly>
-void expblur(QImage &img, qreal radius, bool improvedQuality = false, int transposed = 0)
-{
- // halve the radius if we're using two passes
- if (improvedQuality)
- radius *= qreal(0.5);
-
- Q_ASSERT(img.format() == QImage::Format_ARGB32_Premultiplied
- || img.format() == QImage::Format_RGB32
- || img.format() == QImage::Format_Indexed8
- || img.format() == QImage::Format_Grayscale8);
-
- // choose the alpha such that pixels at radius distance from a fully
- // saturated pixel will have an alpha component of no greater than
- // the cutOffIntensity
- const qreal cutOffIntensity = 2;
- int alpha = radius <= qreal(1e-5)
- ? ((1 << aprec)-1)
- : qRound((1<<aprec)*(1 - qPow(cutOffIntensity * (1 / qreal(255)), 1 / radius)));
-
- int img_height = img.height();
- for (int row = 0; row < img_height; ++row) {
- for (int i = 0; i <= int(improvedQuality); ++i)
- qt_blurrow<aprec, zprec, alphaOnly>(img, row, alpha);
- }
-
- QImage temp(img.height(), img.width(), img.format());
- temp.setDevicePixelRatio(img.devicePixelRatio());
- if (transposed >= 0) {
- if (img.depth() == 8) {
- qt_memrotate270(reinterpret_cast<const quint8*>(img.bits()),
- img.width(), img.height(), img.bytesPerLine(),
- reinterpret_cast<quint8*>(temp.bits()),
- temp.bytesPerLine());
- } else {
- qt_memrotate270(reinterpret_cast<const quint32*>(img.bits()),
- img.width(), img.height(), img.bytesPerLine(),
- reinterpret_cast<quint32*>(temp.bits()),
- temp.bytesPerLine());
- }
- } else {
- if (img.depth() == 8) {
- qt_memrotate90(reinterpret_cast<const quint8*>(img.bits()),
- img.width(), img.height(), img.bytesPerLine(),
- reinterpret_cast<quint8*>(temp.bits()),
- temp.bytesPerLine());
- } else {
- qt_memrotate90(reinterpret_cast<const quint32*>(img.bits()),
- img.width(), img.height(), img.bytesPerLine(),
- reinterpret_cast<quint32*>(temp.bits()),
- temp.bytesPerLine());
- }
- }
-
- img_height = temp.height();
- for (int row = 0; row < img_height; ++row) {
- for (int i = 0; i <= int(improvedQuality); ++i)
- qt_blurrow<aprec, zprec, alphaOnly>(temp, row, alpha);
- }
-
- if (transposed == 0) {
- if (img.depth() == 8) {
- qt_memrotate90(reinterpret_cast<const quint8*>(temp.bits()),
- temp.width(), temp.height(), temp.bytesPerLine(),
- reinterpret_cast<quint8*>(img.bits()),
- img.bytesPerLine());
- } else {
- qt_memrotate90(reinterpret_cast<const quint32*>(temp.bits()),
- temp.width(), temp.height(), temp.bytesPerLine(),
- reinterpret_cast<quint32*>(img.bits()),
- img.bytesPerLine());
- }
- } else {
- img = temp;
- }
-}
-#define AVG(a,b) ( ((((a)^(b)) & 0xfefefefeUL) >> 1) + ((a)&(b)) )
-#define AVG16(a,b) ( ((((a)^(b)) & 0xf7deUL) >> 1) + ((a)&(b)) )
-
-Q_WIDGETS_EXPORT QImage qt_halfScaled(const QImage &source)
-{
- if (source.width() < 2 || source.height() < 2)
- return QImage();
-
- QImage srcImage = source;
-
- if (source.format() == QImage::Format_Indexed8 || source.format() == QImage::Format_Grayscale8) {
- // assumes grayscale
- QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
- dest.setDevicePixelRatio(source.devicePixelRatio());
-
- const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits());
- qsizetype sx = srcImage.bytesPerLine();
- qsizetype sx2 = sx << 1;
-
- uchar *dst = reinterpret_cast<uchar*>(dest.bits());
- qsizetype dx = dest.bytesPerLine();
- int ww = dest.width();
- int hh = dest.height();
-
- for (int y = hh; y; --y, dst += dx, src += sx2) {
- const uchar *p1 = src;
- const uchar *p2 = src + sx;
- uchar *q = dst;
- for (int x = ww; x; --x, ++q, p1 += 2, p2 += 2)
- *q = ((int(p1[0]) + int(p1[1]) + int(p2[0]) + int(p2[1])) + 2) >> 2;
- }
-
- return dest;
- } else if (source.format() == QImage::Format_ARGB8565_Premultiplied) {
- QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
- dest.setDevicePixelRatio(source.devicePixelRatio());
-
- const uchar *src = reinterpret_cast<const uchar*>(const_cast<const QImage &>(srcImage).bits());
- qsizetype sx = srcImage.bytesPerLine();
- qsizetype sx2 = sx << 1;
-
- uchar *dst = reinterpret_cast<uchar*>(dest.bits());
- qsizetype dx = dest.bytesPerLine();
- int ww = dest.width();
- int hh = dest.height();
-
- for (int y = hh; y; --y, dst += dx, src += sx2) {
- const uchar *p1 = src;
- const uchar *p2 = src + sx;
- uchar *q = dst;
- for (int x = ww; x; --x, q += 3, p1 += 6, p2 += 6) {
- // alpha
- q[0] = AVG(AVG(p1[0], p1[3]), AVG(p2[0], p2[3]));
- // rgb
- const quint16 p16_1 = (p1[2] << 8) | p1[1];
- const quint16 p16_2 = (p1[5] << 8) | p1[4];
- const quint16 p16_3 = (p2[2] << 8) | p2[1];
- const quint16 p16_4 = (p2[5] << 8) | p2[4];
- const quint16 result = AVG16(AVG16(p16_1, p16_2), AVG16(p16_3, p16_4));
- q[1] = result & 0xff;
- q[2] = result >> 8;
- }
- }
-
- return dest;
- } else if (source.format() != QImage::Format_ARGB32_Premultiplied
- && source.format() != QImage::Format_RGB32)
- {
- srcImage = source.convertToFormat(QImage::Format_ARGB32_Premultiplied);
- }
-
- QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
- dest.setDevicePixelRatio(source.devicePixelRatio());
-
- const quint32 *src = reinterpret_cast<const quint32*>(const_cast<const QImage &>(srcImage).bits());
- qsizetype sx = srcImage.bytesPerLine() >> 2;
- qsizetype sx2 = sx << 1;
-
- quint32 *dst = reinterpret_cast<quint32*>(dest.bits());
- qsizetype dx = dest.bytesPerLine() >> 2;
- int ww = dest.width();
- int hh = dest.height();
-
- for (int y = hh; y; --y, dst += dx, src += sx2) {
- const quint32 *p1 = src;
- const quint32 *p2 = src + sx;
- quint32 *q = dst;
- for (int x = ww; x; --x, q++, p1 += 2, p2 += 2)
- *q = AVG(AVG(p1[0], p1[1]), AVG(p2[0], p2[1]));
- }
-
- return dest;
-}
-
-Q_WIDGETS_EXPORT void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0)
-{
- if (blurImage.format() != QImage::Format_ARGB32_Premultiplied
- && blurImage.format() != QImage::Format_RGB32)
- {
- blurImage = blurImage.convertToFormat(QImage::Format_ARGB32_Premultiplied);
- }
-
- qreal scale = 1;
- if (radius >= 4 && blurImage.width() >= 2 && blurImage.height() >= 2) {
- blurImage = qt_halfScaled(blurImage);
- scale = 2;
- radius *= qreal(0.5);
- }
-
- if (alphaOnly)
- expblur<12, 10, true>(blurImage, radius, quality, transposed);
- else
- expblur<12, 10, false>(blurImage, radius, quality, transposed);
-
- if (p) {
- p->scale(scale, scale);
- p->setRenderHint(QPainter::SmoothPixmapTransform);
- p->drawImage(QRect(QPoint(0, 0), blurImage.deviceIndependentSize().toSize()), blurImage);
- }
-}
-
-Q_WIDGETS_EXPORT void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0)
-{
- if (blurImage.format() == QImage::Format_Indexed8 || blurImage.format() == QImage::Format_Grayscale8)
- expblur<12, 10, true>(blurImage, radius, quality, transposed);
- else
- expblur<12, 10, false>(blurImage, radius, quality, transposed);
-}
-
Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale);
+Q_GUI_EXPORT extern void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0);
+
/*!
\internal
*/
diff --git a/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp b/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp
index 7b2e3fe734..8a5280d44c 100644
--- a/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp
+++ b/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp
@@ -459,9 +459,7 @@ void SequentialAnchorData::updateChildrenSizes()
// "from" or "to", that _contains_ one of them.
AnchorVertex *prev = from;
- for (int i = 0; i < m_edges.size(); ++i) {
- AnchorData *e = m_edges.at(i);
-
+ for (AnchorData *e : m_edges) {
const bool edgeIsForward = (e->from == prev);
if (edgeIsForward) {
e->sizeAtMinimum = interpolate(minFactor, e->minSize, e->minPrefSize,
@@ -496,9 +494,7 @@ void SequentialAnchorData::calculateSizeHints()
AnchorVertex *prev = from;
- for (int i = 0; i < m_edges.size(); ++i) {
- AnchorData *edge = m_edges.at(i);
-
+ for (AnchorData *edge : m_edges) {
const bool edgeIsForward = (edge->from == prev);
if (edgeIsForward) {
minSize += edge->minSize;
@@ -532,12 +528,10 @@ void AnchorData::dump(int indent) {
p->firstEdge->dump(indent+2);
p->secondEdge->dump(indent+2);
} else if (type == Sequential) {
- SequentialAnchorData *s = static_cast<SequentialAnchorData *>(this);
- int kids = s->m_edges.count();
- qDebug("%*s type: sequential(%d):", indent, "", kids);
- for (int i = 0; i < kids; ++i) {
- s->m_edges.at(i)->dump(indent+2);
- }
+ const auto *s = static_cast<SequentialAnchorData *>(this);
+ qDebug("%*s type: sequential(%lld):", indent, "", qint64(s->m_edges.size()));
+ for (AnchorData *e : s->m_edges)
+ e->dump(indent + 2);
} else {
qDebug("%*s type: Normal:", indent, "");
}
@@ -1153,12 +1147,10 @@ void QGraphicsAnchorLayoutPrivate::restoreSimplifiedAnchor(AnchorData *edge)
g.createEdge(edge->from, edge->to, edge);
} else if (edge->type == AnchorData::Sequential) {
- SequentialAnchorData *sequence = static_cast<SequentialAnchorData *>(edge);
+ const auto *sequence = static_cast<SequentialAnchorData *>(edge);
- for (int i = 0; i < sequence->m_edges.size(); ++i) {
- AnchorData *data = sequence->m_edges.at(i);
+ for (AnchorData *data : sequence->m_edges)
restoreSimplifiedAnchor(data);
- }
delete sequence;
@@ -2554,7 +2546,7 @@ void QGraphicsAnchorLayoutPrivate::identifyNonFloatItems_helper(const AnchorData
nonFloatingItemsIdentifiedSoFar->insert(ad->item);
break;
case AnchorData::Sequential:
- foreach (const AnchorData *d, static_cast<const SequentialAnchorData *>(ad)->m_edges)
+ for (const AnchorData *d : static_cast<const SequentialAnchorData *>(ad)->m_edges)
identifyNonFloatItems_helper(d, nonFloatingItemsIdentifiedSoFar);
break;
case AnchorData::Parallel:
diff --git a/src/widgets/graphicsview/qgraphicsanchorlayout_p.h b/src/widgets/graphicsview/qgraphicsanchorlayout_p.h
index 987d3847fd..880e262d34 100644
--- a/src/widgets/graphicsview/qgraphicsanchorlayout_p.h
+++ b/src/widgets/graphicsview/qgraphicsanchorlayout_p.h
@@ -155,20 +155,21 @@ inline QString AnchorData::toString() const
struct SequentialAnchorData : public AnchorData
{
SequentialAnchorData(const QList<AnchorVertex *> &vertices, const QList<AnchorData *> &edges)
- : AnchorData(), m_children(vertices), m_edges(edges)
+ : AnchorData(), m_edges(edges)
{
type = AnchorData::Sequential;
isVertical = m_edges.at(0)->isVertical;
#ifdef QT_DEBUG
name = QString::fromLatin1("%1 -- %2").arg(vertices.first()->toString(), vertices.last()->toString());
+#else
+ Q_UNUSED(vertices);
#endif
}
virtual void updateChildrenSizes() override;
void calculateSizeHints();
- QList<AnchorVertex *> m_children; // list of vertices in the sequence
- QList<AnchorData *> m_edges; // keep the list of edges too.
+ const QList<AnchorData *> m_edges; // keep the list of edges too.
};
struct ParallelAnchorData : public AnchorData
diff --git a/src/widgets/graphicsview/qgraphicsgridlayout.cpp b/src/widgets/graphicsview/qgraphicsgridlayout.cpp
index 139ccf3af8..e4599d20bb 100644
--- a/src/widgets/graphicsview/qgraphicsgridlayout.cpp
+++ b/src/widgets/graphicsview/qgraphicsgridlayout.cpp
@@ -146,7 +146,7 @@ void QGraphicsGridLayout::addItem(QGraphicsLayoutItem *item, int row, int column
}
/*!
- \fn QGraphicsGridLayout::addItem(QGraphicsLayoutItem *item, int row, int column, Qt::Alignment alignment = 0)
+ \fn QGraphicsGridLayout::addItem(QGraphicsLayoutItem *item, int row, int column, Qt::Alignment alignment)
Adds \a item to the grid on \a row and \a column. You can specify
an optional \a alignment for \a item.
diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp
index cf9e16e292..17ea830cab 100644
--- a/src/widgets/graphicsview/qgraphicsitem.cpp
+++ b/src/widgets/graphicsview/qgraphicsitem.cpp
@@ -6501,7 +6501,7 @@ void QGraphicsItem::setData(int key, const QVariant &value)
}
/*!
- \fn T qgraphicsitem_cast(QGraphicsItem *item)
+ \fn template <class T> qgraphicsitem_cast(QGraphicsItem *item)
\relates QGraphicsItem
\since 4.2
diff --git a/src/widgets/graphicsview/qgraphicslayout_p.h b/src/widgets/graphicsview/qgraphicslayout_p.h
index 2528949569..06eab2ba50 100644
--- a/src/widgets/graphicsview/qgraphicslayout_p.h
+++ b/src/widgets/graphicsview/qgraphicslayout_p.h
@@ -51,8 +51,8 @@ public:
Q_ASSERT(style);
if (widget) //###
m_styleOption.initFrom(widget);
- m_defaultSpacing[0] = style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing, &m_styleOption);
- m_defaultSpacing[1] = style->pixelMetric(QStyle::PM_LayoutVerticalSpacing, &m_styleOption);
+ m_defaultSpacing[0] = style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing, &m_styleOption, widget);
+ m_defaultSpacing[1] = style->pixelMetric(QStyle::PM_LayoutVerticalSpacing, &m_styleOption, widget);
}
inline void invalidate() { m_valid = false; m_style = nullptr; m_widget = nullptr; }
diff --git a/src/widgets/graphicsview/qgraphicslayoutstyleinfo.cpp b/src/widgets/graphicsview/qgraphicslayoutstyleinfo.cpp
index e1e71dfe85..6bd57470f3 100644
--- a/src/widgets/graphicsview/qgraphicslayoutstyleinfo.cpp
+++ b/src/widgets/graphicsview/qgraphicslayoutstyleinfo.cpp
@@ -46,7 +46,7 @@ qreal QGraphicsLayoutStyleInfo::spacing(Qt::Orientation orientation) const
Q_ASSERT(style());
return style()->pixelMetric(orientation == Qt::Horizontal
? QStyle::PM_LayoutHorizontalSpacing : QStyle::PM_LayoutVerticalSpacing,
- &m_styleOption);
+ &m_styleOption, widget());
}
qreal QGraphicsLayoutStyleInfo::windowMargin(Qt::Orientation orientation) const
diff --git a/src/widgets/graphicsview/qgraphicsproxywidget.cpp b/src/widgets/graphicsview/qgraphicsproxywidget.cpp
index 6e9b91a378..1ff4814142 100644
--- a/src/widgets/graphicsview/qgraphicsproxywidget.cpp
+++ b/src/widgets/graphicsview/qgraphicsproxywidget.cpp
@@ -340,10 +340,10 @@ QWidget *QGraphicsProxyWidgetPrivate::findFocusChild(QWidget *child, bool next)
// Run around the focus chain until we find a widget that can take tab focus.
if (!child) {
- child = next ? (QWidget *)widget : widget->d_func()->focus_prev;
+ child = next ? widget.data() : widget->previousInFocusChain();
} else {
- child = next ? child->d_func()->focus_next : child->d_func()->focus_prev;
- if ((next && child == widget) || (!next && child == widget->d_func()->focus_prev)) {
+ child = next ? child->nextInFocusChain() : child->previousInFocusChain();
+ if ((next && child == widget) || (!next && child == widget->previousInFocusChain())) {
return nullptr;
}
}
@@ -360,8 +360,8 @@ QWidget *QGraphicsProxyWidgetPrivate::findFocusChild(QWidget *child, bool next)
&& !(child->d_func()->extra && child->d_func()->extra->focus_proxy)) {
return child;
}
- child = next ? child->d_func()->focus_next : child->d_func()->focus_prev;
- } while (child != oldChild && !(next && child == widget) && !(!next && child == widget->d_func()->focus_prev));
+ child = next ? child->nextInFocusChain() : child->previousInFocusChain();
+ } while (child != oldChild && !(next && child == widget) && !(!next && child == widget->previousInFocusChain()));
return nullptr;
}
diff --git a/src/widgets/graphicsview/qgraphicsproxywidget_p.h b/src/widgets/graphicsview/qgraphicsproxywidget_p.h
index 902a66ee68..328faad0be 100644
--- a/src/widgets/graphicsview/qgraphicsproxywidget_p.h
+++ b/src/widgets/graphicsview/qgraphicsproxywidget_p.h
@@ -19,6 +19,8 @@
#include "qgraphicsproxywidget.h"
#include "private/qgraphicswidget_p.h"
+#include <QtCore/qpointer.h>
+
QT_REQUIRE_CONFIG(graphicsview);
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/graphicsview/qgraphicsscene.cpp b/src/widgets/graphicsview/qgraphicsscene.cpp
index 587ae2b955..c022af6fc0 100644
--- a/src/widgets/graphicsview/qgraphicsscene.cpp
+++ b/src/widgets/graphicsview/qgraphicsscene.cpp
@@ -216,6 +216,8 @@
#include <private/qgesturemanager_p.h>
#include <private/qpathclipper_p.h>
+#include <QtCore/qpointer.h>
+
// #define GESTURE_DEBUG
#ifndef GESTURE_DEBUG
# define DEBUG if (0) qDebug
@@ -1004,7 +1006,7 @@ void QGraphicsScenePrivate::ungrabMouse(QGraphicsItem *item, bool itemIsDying)
void QGraphicsScenePrivate::clearMouseGrabber()
{
if (!mouseGrabberItems.isEmpty())
- mouseGrabberItems.first()->ungrabMouse();
+ mouseGrabberItems.constFirst()->ungrabMouse();
lastMouseGrabberItem = nullptr;
}
@@ -3251,6 +3253,7 @@ bool QGraphicsScene::event(QEvent *event)
// ### this should only be cleared if we received a new mouse move event,
// which relies on us fixing the replay mechanism in QGraphicsView.
d->cachedItemsUnderMouse.clear();
+ break;
default:
break;
}
diff --git a/src/widgets/graphicsview/qgraphicsview.cpp b/src/widgets/graphicsview/qgraphicsview.cpp
index fba6d942f8..9505e2529a 100644
--- a/src/widgets/graphicsview/qgraphicsview.cpp
+++ b/src/widgets/graphicsview/qgraphicsview.cpp
@@ -483,8 +483,8 @@ void QGraphicsViewPrivate::centerView(QGraphicsView::ViewportAnchor anchor)
if (q->underMouse()) {
// Last scene pos: lastMouseMoveScenePoint
// Current mouse pos:
- QPointF transformationDiff = q->mapToScene(viewport->rect().center())
- - q->mapToScene(viewport->mapFromGlobal(QCursor::pos()));
+ QPointF transformationDiff = mapToScene(viewport->rect().toRectF().center())
+ - mapToScene(viewport->mapFromGlobal(QCursor::pos().toPointF()));
q->centerOn(lastMouseMoveScenePoint + transformationDiff);
} else {
q->centerOn(lastCenterPoint);
@@ -504,8 +504,7 @@ void QGraphicsViewPrivate::centerView(QGraphicsView::ViewportAnchor anchor)
*/
void QGraphicsViewPrivate::updateLastCenterPoint()
{
- Q_Q(QGraphicsView);
- lastCenterPoint = q->mapToScene(viewport->rect().center());
+ lastCenterPoint = mapToScene(viewport->rect().toRectF().center());
}
/*!
@@ -1559,7 +1558,7 @@ void QGraphicsView::setRubberBandSelectionMode(Qt::ItemSelectionMode mode)
is currently doing an itemselection with rubber band. When the user is not using the
rubber band this functions returns (a null) QRectF().
- Notice that part of this QRect can be outise the visual viewport. It can e.g
+ Notice that part of this QRect can be outside the visual viewport. It can e.g
contain negative values.
\sa rubberBandSelectionMode, rubberBandChanged()
@@ -1892,14 +1891,14 @@ void QGraphicsView::centerOn(const QPointF &pos)
qint64 horizontal = 0;
horizontal += horizontalScrollBar()->minimum();
horizontal += horizontalScrollBar()->maximum();
- horizontal -= int(viewPoint.x() - width / 2.0);
+ horizontal -= qRound(viewPoint.x() - width / 2.0);
horizontalScrollBar()->setValue(horizontal);
} else {
- horizontalScrollBar()->setValue(int(viewPoint.x() - width / 2.0));
+ horizontalScrollBar()->setValue(qRound(viewPoint.x() - width / 2.0));
}
}
if (!d->topIndent)
- verticalScrollBar()->setValue(int(viewPoint.y() - height / 2.0));
+ verticalScrollBar()->setValue(qRound(viewPoint.y() - height / 2.0));
d->lastCenterPoint = oldCenterPoint;
}
@@ -2343,7 +2342,7 @@ QGraphicsItem *QGraphicsView::itemAt(const QPoint &pos) const
if (!d->scene)
return nullptr;
const QList<QGraphicsItem *> itemsAtPos = items(pos);
- return itemsAtPos.isEmpty() ? 0 : itemsAtPos.first();
+ return itemsAtPos.isEmpty() ? nullptr : itemsAtPos.first();
}
/*!
diff --git a/src/widgets/graphicsview/qgraphicsview_p.h b/src/widgets/graphicsview/qgraphicsview_p.h
index a15defe621..7f1682beca 100644
--- a/src/widgets/graphicsview/qgraphicsview_p.h
+++ b/src/widgets/graphicsview/qgraphicsview_p.h
@@ -25,6 +25,8 @@
#include <private/qabstractscrollarea_p.h>
#include <private/qapplication_p.h>
+#include <QtCore/qpointer.h>
+
QT_REQUIRE_CONFIG(graphicsview);
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/itemviews/qabstractitemdelegate.cpp b/src/widgets/itemviews/qabstractitemdelegate.cpp
index 73af3b6b1d..23e8ef0901 100644
--- a/src/widgets/itemviews/qabstractitemdelegate.cpp
+++ b/src/widgets/itemviews/qabstractitemdelegate.cpp
@@ -81,7 +81,7 @@ QT_BEGIN_NAMESPACE
The second approach is to handle user events directly by reimplementing
editorEvent().
- \sa {model-view-programming}{Model/View Programming}, {Pixelator Example},
+ \sa {model-view-programming}{Model/View Programming},
QStyledItemDelegate, QStyle
*/
@@ -514,6 +514,14 @@ bool QAbstractItemDelegatePrivate::tryFixup(QWidget *editor)
return e->hasAcceptableInput();
}
}
+#endif
+#if QT_CONFIG(spinbox)
+ // Give a chance to the spinbox to interpret the text and emit
+ // the appropriate signals before committing data.
+ if (QAbstractSpinBox *sb = qobject_cast<QAbstractSpinBox *>(editor)) {
+ if (!sb->keyboardTracking())
+ sb->interpretText();
+ }
#else
Q_UNUSED(editor);
#endif // QT_CONFIG(lineedit)
diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp
index 0401379c38..85e478a71e 100644
--- a/src/widgets/itemviews/qabstractitemview.cpp
+++ b/src/widgets/itemviews/qabstractitemview.cpp
@@ -102,15 +102,16 @@ void QAbstractItemViewPrivate::init()
vbar->setRange(0, 0);
hbar->setRange(0, 0);
- QObject::connect(vbar, SIGNAL(actionTriggered(int)),
- q, SLOT(verticalScrollbarAction(int)));
- QObject::connect(hbar, SIGNAL(actionTriggered(int)),
- q, SLOT(horizontalScrollbarAction(int)));
- QObject::connect(vbar, SIGNAL(valueChanged(int)),
- q, SLOT(verticalScrollbarValueChanged(int)));
- QObject::connect(hbar, SIGNAL(valueChanged(int)),
- q, SLOT(horizontalScrollbarValueChanged(int)));
-
+ scrollbarConnections = {
+ QObject::connect(vbar, &QScrollBar::actionTriggered,
+ q, &QAbstractItemView::verticalScrollbarAction),
+ QObject::connect(hbar, &QScrollBar::actionTriggered,
+ q, &QAbstractItemView::horizontalScrollbarAction),
+ QObject::connect(vbar, &QScrollBar::valueChanged,
+ q, &QAbstractItemView::verticalScrollbarValueChanged),
+ QObject::connect(hbar, &QScrollBar::valueChanged,
+ q, &QAbstractItemView::horizontalScrollbarValueChanged)
+ };
viewport->setBackgroundRole(QPalette::Base);
q->setAttribute(Qt::WA_InputMethodEnabled);
@@ -129,8 +130,8 @@ void QAbstractItemViewPrivate::setHoverIndex(const QPersistentModelIndex &index)
q->update(hover); //update the old one
q->update(index); //update the new one
} else {
- QRect oldHoverRect = q->visualRect(hover);
- QRect newHoverRect = q->visualRect(index);
+ const QRect oldHoverRect = visualRect(hover);
+ const QRect newHoverRect = visualRect(index);
viewport->update(QRect(0, newHoverRect.y(), viewport->width(), newHoverRect.height()));
viewport->update(QRect(0, oldHoverRect.y(), viewport->width(), oldHoverRect.height()));
}
@@ -172,7 +173,7 @@ void QAbstractItemViewPrivate::checkMouseMove(const QPersistentModelIndex &index
#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
// stores and restores the selection and current item when flicking
-void QAbstractItemViewPrivate::_q_scrollerStateChanged()
+void QAbstractItemViewPrivate::scrollerStateChanged()
{
Q_Q(QAbstractItemView);
@@ -208,7 +209,7 @@ void QAbstractItemViewPrivate::_q_scrollerStateChanged()
#endif // QT_NO_GESTURES
-void QAbstractItemViewPrivate::_q_delegateSizeHintChanged(const QModelIndex &index)
+void QAbstractItemViewPrivate::delegateSizeHintChanged(const QModelIndex &index)
{
Q_Q(QAbstractItemView);
if (model) {
@@ -218,6 +219,63 @@ void QAbstractItemViewPrivate::_q_delegateSizeHintChanged(const QModelIndex &ind
QMetaObject::invokeMethod(q, &QAbstractItemView::doItemsLayout, Qt::QueuedConnection);
}
+void QAbstractItemViewPrivate::connectDelegate(QAbstractItemDelegate *delegate)
+{
+ if (!delegate)
+ return;
+ Q_Q(QAbstractItemView);
+ QObject::connect(delegate, &QAbstractItemDelegate::closeEditor,
+ q, &QAbstractItemView::closeEditor);
+ QObject::connect(delegate, &QAbstractItemDelegate::commitData,
+ q, &QAbstractItemView::commitData);
+ QObjectPrivate::connect(delegate, &QAbstractItemDelegate::sizeHintChanged,
+ this, &QAbstractItemViewPrivate::delegateSizeHintChanged);
+}
+
+void QAbstractItemViewPrivate::disconnectDelegate(QAbstractItemDelegate *delegate)
+{
+ if (!delegate)
+ return;
+ Q_Q(QAbstractItemView);
+ QObject::disconnect(delegate, &QAbstractItemDelegate::closeEditor,
+ q, &QAbstractItemView::closeEditor);
+ QObject::disconnect(delegate, &QAbstractItemDelegate::commitData,
+ q, &QAbstractItemView::commitData);
+ QObjectPrivate::disconnect(delegate, &QAbstractItemDelegate::sizeHintChanged,
+ this, &QAbstractItemViewPrivate::delegateSizeHintChanged);
+}
+
+void QAbstractItemViewPrivate::disconnectAll()
+{
+ Q_Q(QAbstractItemView);
+ for (const QMetaObject::Connection &connection : modelConnections)
+ QObject::disconnect(connection);
+ for (const QMetaObject::Connection &connection : scrollbarConnections)
+ QObject::disconnect(connection);
+ disconnectDelegate(itemDelegate);
+ for (QAbstractItemDelegate *delegate : std::as_const(rowDelegates))
+ disconnectDelegate(delegate);
+ for (QAbstractItemDelegate *delegate : std::as_const(columnDelegates))
+ disconnectDelegate(delegate);
+ if (model && selectionModel) {
+ QObject::disconnect(model, &QAbstractItemModel::destroyed,
+ selectionModel, &QItemSelectionModel::deleteLater);
+ }
+ if (selectionModel) {
+ QObject::disconnect(selectionModel, &QItemSelectionModel::selectionChanged,
+ q, &QAbstractItemView::selectionChanged);
+ QObject::disconnect(selectionModel, &QItemSelectionModel::currentChanged,
+ q, &QAbstractItemView::currentChanged);
+ }
+ for (const auto &info : std::as_const(indexEditorHash)) {
+ if (!info.isStatic && info.widget)
+ QObject::disconnect(info.widget, &QWidget::destroyed, q, &QAbstractItemView::editorDestroyed);
+ }
+#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
+ QObject::disconnect(scollerConnection);
+#endif
+}
+
/*!
\class QAbstractItemView
@@ -318,7 +376,7 @@ void QAbstractItemViewPrivate::_q_delegateSizeHintChanged(const QModelIndex &ind
\l{QWidget::update()}{update()} as all painting operations take place on the
viewport.
- \sa {View Classes}, {Model/View Programming}, QAbstractItemModel, {Chart Example}
+ \sa {View Classes}, {Model/View Programming}, QAbstractItemModel
*/
/*!
@@ -631,6 +689,7 @@ QAbstractItemView::~QAbstractItemView()
d->autoScrollTimer.stop();
d->delayedLayout.stop();
d->fetchMoreTimer.stop();
+ d->disconnectAll();
}
/*!
@@ -659,68 +718,47 @@ void QAbstractItemView::setModel(QAbstractItemModel *model)
if (model == d->model)
return;
if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
- disconnect(d->model, SIGNAL(destroyed()),
- this, SLOT(_q_modelDestroyed()));
- disconnect(d->model, SIGNAL(dataChanged(QModelIndex, QModelIndex, QList<int>)), this,
- SLOT(dataChanged(QModelIndex, QModelIndex, QList<int>)));
- disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
- this, SLOT(_q_headerDataChanged()));
- disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(rowsInserted(QModelIndex,int,int)));
- disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
- disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
- disconnect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
- disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
- disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int)));
- disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_columnsRemoved(QModelIndex,int,int)));
- disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
- this, SLOT(_q_columnsInserted(QModelIndex,int,int)));
- disconnect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_columnsMoved(QModelIndex,int,int,QModelIndex,int)));
-
- disconnect(d->model, SIGNAL(modelReset()), this, SLOT(reset()));
- disconnect(d->model, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
+ for (const QMetaObject::Connection &connection : d->modelConnections)
+ disconnect(connection);
}
d->model = (model ? model : QAbstractItemModelPrivate::staticEmptyModel());
if (d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
- connect(d->model, SIGNAL(destroyed()),
- this, SLOT(_q_modelDestroyed()));
- connect(d->model, SIGNAL(dataChanged(QModelIndex, QModelIndex, QList<int>)), this,
- SLOT(dataChanged(QModelIndex, QModelIndex, QList<int>)));
- connect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
- this, SLOT(_q_headerDataChanged()));
- connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(rowsInserted(QModelIndex,int,int)));
- connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
- connect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)));
- connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
- connect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
- connect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(_q_columnsAboutToBeRemoved(QModelIndex,int,int)));
- connect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_columnsRemoved(QModelIndex,int,int)));
- connect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
- this, SLOT(_q_columnsInserted(QModelIndex,int,int)));
- connect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_columnsMoved(QModelIndex,int,int,QModelIndex,int)));
-
- connect(d->model, SIGNAL(modelReset()), this, SLOT(reset()));
- connect(d->model, SIGNAL(layoutChanged()), this, SLOT(_q_layoutChanged()));
+ d->modelConnections = {
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::destroyed,
+ d, &QAbstractItemViewPrivate::modelDestroyed),
+ QObject::connect(d->model, &QAbstractItemModel::dataChanged,
+ this, &QAbstractItemView::dataChanged),
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::headerDataChanged,
+ d, &QAbstractItemViewPrivate::headerDataChanged),
+ QObject::connect(d->model, &QAbstractItemModel::rowsInserted,
+ this, &QAbstractItemView::rowsInserted),
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsInserted,
+ d, &QAbstractItemViewPrivate::rowsInserted),
+ QObject::connect(d->model, &QAbstractItemModel::rowsAboutToBeRemoved,
+ this, &QAbstractItemView::rowsAboutToBeRemoved),
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsRemoved,
+ d, &QAbstractItemViewPrivate::rowsRemoved),
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::rowsMoved,
+ d, &QAbstractItemViewPrivate::rowsMoved),
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsAboutToBeRemoved,
+ d, &QAbstractItemViewPrivate::columnsAboutToBeRemoved),
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsRemoved,
+ d, &QAbstractItemViewPrivate::columnsRemoved),
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsInserted,
+ d, &QAbstractItemViewPrivate::columnsInserted),
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::columnsMoved,
+ d, &QAbstractItemViewPrivate::columnsMoved),
+ QObject::connect(d->model, &QAbstractItemModel::modelReset,
+ this, &QAbstractItemView::reset),
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::layoutChanged,
+ d, &QAbstractItemViewPrivate::layoutChanged),
+ };
}
QItemSelectionModel *selection_model = new QItemSelectionModel(d->model, this);
- connect(d->model, SIGNAL(destroyed()), selection_model, SLOT(deleteLater()));
+ connect(d->model, &QAbstractItemModel::destroyed,
+ selection_model, &QItemSelectionModel::deleteLater);
setSelectionModel(selection_model);
reset(); // kill editors, set new root and do layout
@@ -770,20 +808,19 @@ void QAbstractItemView::setSelectionModel(QItemSelectionModel *selectionModel)
oldSelection = d->selectionModel->selection();
oldCurrentIndex = d->selectionModel->currentIndex();
}
-
- disconnect(d->selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
- this, SLOT(selectionChanged(QItemSelection,QItemSelection)));
- disconnect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
- this, SLOT(currentChanged(QModelIndex,QModelIndex)));
+ disconnect(d->selectionModel, &QItemSelectionModel::selectionChanged,
+ this, &QAbstractItemView::selectionChanged);
+ disconnect(d->selectionModel, &QItemSelectionModel::currentChanged,
+ this, &QAbstractItemView::currentChanged);
}
d->selectionModel = selectionModel;
if (d->selectionModel) {
- connect(d->selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
- this, SLOT(selectionChanged(QItemSelection,QItemSelection)));
- connect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
- this, SLOT(currentChanged(QModelIndex,QModelIndex)));
+ connect(d->selectionModel, &QItemSelectionModel::selectionChanged,
+ this, &QAbstractItemView::selectionChanged);
+ connect(d->selectionModel, &QItemSelectionModel::currentChanged,
+ this, &QAbstractItemView::currentChanged);
selectionChanged(d->selectionModel->selection(), oldSelection);
currentChanged(d->selectionModel->currentIndex(), oldCurrentIndex);
@@ -823,21 +860,13 @@ void QAbstractItemView::setItemDelegate(QAbstractItemDelegate *delegate)
return;
if (d->itemDelegate) {
- if (d->delegateRefCount(d->itemDelegate) == 1) {
- disconnect(d->itemDelegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
- this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
- disconnect(d->itemDelegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
- disconnect(d->itemDelegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(_q_delegateSizeHintChanged(QModelIndex)));
- }
+ if (d->delegateRefCount(d->itemDelegate) == 1)
+ d->disconnectDelegate(delegate);
}
if (delegate) {
- if (d->delegateRefCount(delegate) == 0) {
- connect(delegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
- this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
- connect(delegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
- connect(delegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(_q_delegateSizeHintChanged(QModelIndex)));
- }
+ if (d->delegateRefCount(delegate) == 0)
+ d->connectDelegate(delegate);
}
d->itemDelegate = delegate;
viewport()->update();
@@ -907,21 +936,13 @@ void QAbstractItemView::setItemDelegateForRow(int row, QAbstractItemDelegate *de
{
Q_D(QAbstractItemView);
if (QAbstractItemDelegate *rowDelegate = d->rowDelegates.value(row, nullptr)) {
- if (d->delegateRefCount(rowDelegate) == 1) {
- disconnect(rowDelegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
- this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
- disconnect(rowDelegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
- disconnect(rowDelegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(_q_delegateSizeHintChanged(QModelIndex)));
- }
+ if (d->delegateRefCount(rowDelegate) == 1)
+ d->disconnectDelegate(rowDelegate);
d->rowDelegates.remove(row);
}
if (delegate) {
- if (d->delegateRefCount(delegate) == 0) {
- connect(delegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
- this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
- connect(delegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
- connect(delegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(_q_delegateSizeHintChanged(QModelIndex)));
- }
+ if (d->delegateRefCount(delegate) == 0)
+ d->connectDelegate(delegate);
d->rowDelegates.insert(row, delegate);
}
viewport()->update();
@@ -967,21 +988,13 @@ void QAbstractItemView::setItemDelegateForColumn(int column, QAbstractItemDelega
{
Q_D(QAbstractItemView);
if (QAbstractItemDelegate *columnDelegate = d->columnDelegates.value(column, nullptr)) {
- if (d->delegateRefCount(columnDelegate) == 1) {
- disconnect(columnDelegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
- this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
- disconnect(columnDelegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
- disconnect(columnDelegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(_q_delegateSizeHintChanged(QModelIndex)));
- }
+ if (d->delegateRefCount(columnDelegate) == 1)
+ d->disconnectDelegate(columnDelegate);
d->columnDelegates.remove(column);
}
if (delegate) {
- if (d->delegateRefCount(delegate) == 0) {
- connect(delegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
- this, SLOT(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
- connect(delegate, SIGNAL(commitData(QWidget*)), this, SLOT(commitData(QWidget*)));
- connect(delegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SLOT(_q_delegateSizeHintChanged(QModelIndex)));
- }
+ if (d->delegateRefCount(delegate) == 0)
+ d->connectDelegate(delegate);
d->columnDelegates.insert(column, delegate);
}
viewport()->update();
@@ -1119,7 +1132,11 @@ void QAbstractItemView::reset()
{
Q_D(QAbstractItemView);
d->delayedReset.stop(); //make sure we stop the timer
- foreach (const QEditorInfo &info, d->indexEditorHash) {
+ // Taking a copy because releaseEditor() eventurally calls deleteLater() on the
+ // editor, which calls QCoreApplication::postEvent(), the latter may invoke unknown
+ // code that may modify d->indexEditorHash.
+ const auto copy = d->indexEditorHash;
+ for (const auto &[index, info] : copy.asKeyValueRange()) {
if (info.widget)
d->releaseEditor(info.widget.data(), d->indexForEditor(info.widget.data()));
}
@@ -1153,6 +1170,12 @@ void QAbstractItemView::setRootIndex(const QModelIndex &index)
return;
}
d->root = index;
+#if QT_CONFIG(accessibility)
+ if (QAccessible::isActive()) {
+ QAccessibleTableModelChangeEvent accessibleEvent(this, QAccessibleTableModelChangeEvent::ModelReset);
+ QAccessible::updateAccessibility(&accessibleEvent);
+ }
+#endif
d->doDelayedItemsLayout();
d->updateGeometry();
}
@@ -1545,7 +1568,7 @@ QAbstractItemView::DragDropMode QAbstractItemView::dragDropMode() const
/*!
\property QAbstractItemView::defaultDropAction
- \brief the drop action that will be used by default in QAbstractItemView::drag()
+ \brief the drop action that will be used by default in QAbstractItemView::drag().
If the property is not set, the drop action is CopyAction when the supported
actions support CopyAction.
@@ -1638,7 +1661,7 @@ Qt::TextElideMode QAbstractItemView::textElideMode() const
bool QAbstractItemView::focusNextPrevChild(bool next)
{
Q_D(QAbstractItemView);
- if (d->tabKeyNavigation && isEnabled() && d->viewport->isEnabled()) {
+ if (d->tabKeyNavigation && isVisible() && isEnabled() && d->viewport->isEnabled()) {
QKeyEvent event(QEvent::KeyPress, next ? Qt::Key_Tab : Qt::Key_Backtab, Qt::NoModifier);
keyPressEvent(&event);
if (event.isAccepted())
@@ -1762,7 +1785,10 @@ bool QAbstractItemView::viewportEvent(QEvent *event)
case QEvent::ScrollPrepare:
executeDelayedItemsLayout();
#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
- connect(QScroller::scroller(d->viewport), SIGNAL(stateChanged(QScroller::State)), this, SLOT(_q_scrollerStateChanged()), Qt::UniqueConnection);
+ d->scollerConnection = QObjectPrivate::connect(
+ QScroller::scroller(d->viewport), &QScroller::stateChanged,
+ d, &QAbstractItemViewPrivate::scrollerStateChanged,
+ Qt::UniqueConnection);
#endif
break;
@@ -1857,7 +1883,6 @@ void QAbstractItemView::mousePressEvent(QMouseEvent *event)
void QAbstractItemView::mouseMoveEvent(QMouseEvent *event)
{
Q_D(QAbstractItemView);
- QPoint topLeft;
QPoint bottomRight = event->position().toPoint();
d->draggedPosition = bottomRight + d->offset();
@@ -1867,13 +1892,7 @@ void QAbstractItemView::mouseMoveEvent(QMouseEvent *event)
#if QT_CONFIG(draganddrop)
if (state() == DraggingState) {
- topLeft = d->pressedPosition - d->offset();
- if ((topLeft - bottomRight).manhattanLength() > QApplication::startDragDistance()) {
- d->pressedIndex = QModelIndex();
- startDrag(d->model->supportedDragActions());
- setState(NoState); // the startDrag will return when the dnd operation is done
- stopAutoScroll();
- }
+ d->maybeStartDrag(bottomRight);
return;
}
#endif // QT_CONFIG(draganddrop)
@@ -1884,10 +1903,8 @@ void QAbstractItemView::mouseMoveEvent(QMouseEvent *event)
|| edit(index, NoEditTriggers, event))
return;
- if (d->selectionMode != SingleSelection)
- topLeft = d->pressedPosition - d->offset();
- else
- topLeft = bottomRight;
+ const QPoint topLeft =
+ d->selectionMode != SingleSelection ? d->pressedPosition - d->offset() : bottomRight;
d->checkMouseMove(index);
@@ -1898,6 +1915,7 @@ void QAbstractItemView::mouseMoveEvent(QMouseEvent *event)
&& (event->buttons() != Qt::NoButton)
&& !d->selectedDraggableIndexes().isEmpty()) {
setState(DraggingState);
+ d->maybeStartDrag(bottomRight);
return;
}
#endif
@@ -2918,41 +2936,50 @@ void QAbstractItemView::closeEditor(QWidget *editor, QAbstractItemDelegate::EndE
// Close the editor
if (editor) {
- bool isPersistent = d->persistent.contains(editor);
- bool hadFocus = editor->hasFocus();
- QModelIndex index = d->indexForEditor(editor);
+ const bool isPersistent = d->persistent.contains(editor);
+ const QModelIndex index = d->indexForEditor(editor);
if (!index.isValid()) {
- qWarning("QAbstractItemView::closeEditor called with an editor that does not belong to this view");
- return; // the editor was not registered
- }
-
- // start a timer that expires immediately when we return to the event loop
- // to identify whether this close was triggered by a mousepress-initiated
- // focus event
- d->pressClosedEditorWatcher.start(0, this);
- d->lastEditedIndex = index;
-
- if (!isPersistent) {
- setState(NoState);
- QModelIndex index = d->indexForEditor(editor);
- editor->removeEventFilter(itemDelegateForIndex(index));
- d->removeEditor(editor);
- }
- if (hadFocus) {
- if (focusPolicy() != Qt::NoFocus)
- setFocus(); // this will send a focusLost event to the editor
- else
- editor->clearFocus();
+ if (!editor->isVisible()) {
+ // The commit might have removed the index (e.g. it might get filtered), in
+ // which case the editor is already hidden and scheduled for deletion. We
+ // don't have to do anything, except reset the state, and continue with
+ // EndEditHint processing.
+ if (!isPersistent)
+ setState(NoState);
+ } else {
+ qWarning("QAbstractItemView::closeEditor called with an editor that does not belong to this view");
+ return;
+ }
} else {
- d->checkPersistentEditorFocus();
- }
+ const bool hadFocus = editor->hasFocus();
+ // start a timer that expires immediately when we return to the event loop
+ // to identify whether this close was triggered by a mousepress-initiated
+ // focus event
+ d->pressClosedEditorWatcher.start(0, this);
+ d->lastEditedIndex = index;
+
+ if (!isPersistent) {
+ setState(NoState);
+ QModelIndex index = d->indexForEditor(editor);
+ editor->removeEventFilter(itemDelegateForIndex(index));
+ d->removeEditor(editor);
+ }
+ if (hadFocus) {
+ if (focusPolicy() != Qt::NoFocus)
+ setFocus(); // this will send a focusLost event to the editor
+ else
+ editor->clearFocus();
+ } else {
+ d->checkPersistentEditorFocus();
+ }
- QPointer<QWidget> ed = editor;
- QCoreApplication::sendPostedEvents(editor, 0);
- editor = ed;
+ QPointer<QWidget> ed = editor;
+ QCoreApplication::sendPostedEvents(editor, 0);
+ editor = ed;
- if (!isPersistent && editor)
- d->releaseEditor(editor, index);
+ if (!isPersistent && editor)
+ d->releaseEditor(editor, index);
+ }
}
// The EndEditHint part
@@ -3354,7 +3381,7 @@ void QAbstractItemView::update(const QModelIndex &index)
{
Q_D(QAbstractItemView);
if (index.isValid()) {
- const QRect rect = visualRect(index);
+ const QRect rect = d->visualRect(index);
//this test is important for performance reason
//For example in dataChanged we simply update all the cells without checking
//it can be a major bottleneck to update rects that aren't even part of the viewport
@@ -3505,10 +3532,21 @@ void QAbstractItemView::rowsAboutToBeRemoved(const QModelIndex &parent, int star
}
// Remove all affected editors; this is more efficient than waiting for updateGeometries() to clean out editors for invalid indexes
+ const auto findDirectChildOf = [](const QModelIndex &parent, QModelIndex child)
+ {
+ while (child.isValid()) {
+ const auto parentIndex = child.parent();
+ if (parentIndex == parent)
+ return child;
+ child = parentIndex;
+ }
+ return QModelIndex();
+ };
QEditorIndexHash::iterator i = d->editorIndexHash.begin();
while (i != d->editorIndexHash.end()) {
const QModelIndex index = i.value();
- if (index.row() >= start && index.row() <= end && d->model->parent(index) == parent) {
+ const QModelIndex directChild = findDirectChildOf(parent, index);
+ if (directChild.isValid() && directChild.row() >= start && directChild.row() <= end) {
QWidget *editor = i.key();
QEditorInfo info = d->indexEditorHash.take(index);
i = d->editorIndexHash.erase(i);
@@ -3527,7 +3565,7 @@ void QAbstractItemView::rowsAboutToBeRemoved(const QModelIndex &parent, int star
rows are those under the given \a parent from \a start to \a end
inclusive.
*/
-void QAbstractItemViewPrivate::_q_rowsRemoved(const QModelIndex &index, int start, int end)
+void QAbstractItemViewPrivate::rowsRemoved(const QModelIndex &index, int start, int end)
{
Q_UNUSED(index);
Q_UNUSED(start);
@@ -3555,7 +3593,7 @@ void QAbstractItemViewPrivate::_q_rowsRemoved(const QModelIndex &index, int star
columns are those under the given \a parent from \a start to \a end
inclusive.
*/
-void QAbstractItemViewPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
+void QAbstractItemViewPrivate::columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
{
Q_Q(QAbstractItemView);
@@ -3618,7 +3656,7 @@ void QAbstractItemViewPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &par
rows are those under the given \a parent from \a start to \a end
inclusive.
*/
-void QAbstractItemViewPrivate::_q_columnsRemoved(const QModelIndex &index, int start, int end)
+void QAbstractItemViewPrivate::columnsRemoved(const QModelIndex &index, int start, int end)
{
Q_UNUSED(index);
Q_UNUSED(start);
@@ -3645,7 +3683,7 @@ void QAbstractItemViewPrivate::_q_columnsRemoved(const QModelIndex &index, int s
This slot is called when rows have been inserted.
*/
-void QAbstractItemViewPrivate::_q_rowsInserted(const QModelIndex &index, int start, int end)
+void QAbstractItemViewPrivate::rowsInserted(const QModelIndex &index, int start, int end)
{
Q_UNUSED(index);
Q_UNUSED(start);
@@ -3668,7 +3706,7 @@ void QAbstractItemViewPrivate::_q_rowsInserted(const QModelIndex &index, int sta
This slot is called when columns have been inserted.
*/
-void QAbstractItemViewPrivate::_q_columnsInserted(const QModelIndex &index, int start, int end)
+void QAbstractItemViewPrivate::columnsInserted(const QModelIndex &index, int start, int end)
{
Q_UNUSED(index);
Q_UNUSED(start);
@@ -3691,7 +3729,7 @@ void QAbstractItemViewPrivate::_q_columnsInserted(const QModelIndex &index, int
/*!
\internal
*/
-void QAbstractItemViewPrivate::_q_modelDestroyed()
+void QAbstractItemViewPrivate::modelDestroyed()
{
model = QAbstractItemModelPrivate::staticEmptyModel();
doDelayedReset();
@@ -3702,7 +3740,7 @@ void QAbstractItemViewPrivate::_q_modelDestroyed()
This slot is called when the layout is changed.
*/
-void QAbstractItemViewPrivate::_q_layoutChanged()
+void QAbstractItemViewPrivate::layoutChanged()
{
doDelayedItemsLayout();
#if QT_CONFIG(accessibility)
@@ -3714,14 +3752,14 @@ void QAbstractItemViewPrivate::_q_layoutChanged()
#endif
}
-void QAbstractItemViewPrivate::_q_rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)
+void QAbstractItemViewPrivate::rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)
{
- _q_layoutChanged();
+ layoutChanged();
}
-void QAbstractItemViewPrivate::_q_columnsMoved(const QModelIndex &, int, int, const QModelIndex &, int)
+void QAbstractItemViewPrivate::columnsMoved(const QModelIndex &, int, int, const QModelIndex &, int)
{
- _q_layoutChanged();
+ layoutChanged();
}
QRect QAbstractItemViewPrivate::intersectedRect(const QRect rect, const QModelIndex &topLeft, const QModelIndex &bottomRight) const
@@ -4263,6 +4301,7 @@ QItemSelectionModel::SelectionFlags QAbstractItemViewPrivate::extendedSelectionC
default:
break;
}
+ break;
}
default:
break;
@@ -4431,7 +4470,7 @@ QWidget *QAbstractItemViewPrivate::editor(const QModelIndex &index,
w = delegate->createEditor(viewport, options, index);
if (w) {
w->installEventFilter(delegate);
- QObject::connect(w, SIGNAL(destroyed(QObject*)), q, SLOT(editorDestroyed(QObject*)));
+ QObject::connect(w, &QWidget::destroyed, q, &QAbstractItemView::editorDestroyed);
delegate->updateEditorGeometry(w, options, index);
delegate->setEditorData(w, index);
addEditor(index, w, false);
@@ -4568,6 +4607,9 @@ QModelIndex QAbstractItemViewPrivate::indexForEditor(QWidget *editor) const
void QAbstractItemViewPrivate::removeEditor(QWidget *editor)
{
+ Q_Q(QAbstractItemView);
+ if (editor)
+ QObject::disconnect(editor, &QWidget::destroyed, q, &QAbstractItemView::editorDestroyed);
const auto it = editorIndexHash.constFind(editor);
if (it != editorIndexHash.cend()) {
indexEditorHash.remove(it.value());
@@ -4701,6 +4743,20 @@ QModelIndexList QAbstractItemViewPrivate::selectedDraggableIndexes() const
indexes.removeIf(isNotDragEnabled);
return indexes;
}
+
+void QAbstractItemViewPrivate::maybeStartDrag(QPoint eventPosition)
+{
+ Q_Q(QAbstractItemView);
+
+ const QPoint topLeft = pressedPosition - offset();
+ if ((topLeft - eventPosition).manhattanLength() > QApplication::startDragDistance()) {
+ pressedIndex = QModelIndex();
+ q->startDrag(model->supportedDragActions());
+ q->setState(QAbstractItemView::NoState); // the startDrag will return when the dnd operation
+ // is done
+ q->stopAutoScroll();
+ }
+}
#endif
/*!
diff --git a/src/widgets/itemviews/qabstractitemview.h b/src/widgets/itemviews/qabstractitemview.h
index d5a433943a..837419100a 100644
--- a/src/widgets/itemviews/qabstractitemview.h
+++ b/src/widgets/itemviews/qabstractitemview.h
@@ -326,20 +326,6 @@ protected:
private:
Q_DECLARE_PRIVATE(QAbstractItemView)
Q_DISABLE_COPY(QAbstractItemView)
- Q_PRIVATE_SLOT(d_func(), void _q_columnsAboutToBeRemoved(const QModelIndex&, int, int))
- Q_PRIVATE_SLOT(d_func(), void _q_columnsRemoved(const QModelIndex&, int, int))
- Q_PRIVATE_SLOT(d_func(), void _q_columnsInserted(const QModelIndex&, int, int))
- Q_PRIVATE_SLOT(d_func(), void _q_rowsInserted(const QModelIndex&, int, int))
- Q_PRIVATE_SLOT(d_func(), void _q_rowsRemoved(const QModelIndex&, int, int))
- Q_PRIVATE_SLOT(d_func(), void _q_columnsMoved(const QModelIndex&, int, int, const QModelIndex&, int))
- Q_PRIVATE_SLOT(d_func(), void _q_rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int))
- Q_PRIVATE_SLOT(d_func(), void _q_modelDestroyed())
- Q_PRIVATE_SLOT(d_func(), void _q_layoutChanged())
- Q_PRIVATE_SLOT(d_func(), void _q_headerDataChanged())
-#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
- Q_PRIVATE_SLOT(d_func(), void _q_scrollerStateChanged())
-#endif
- Q_PRIVATE_SLOT(d_func(), void _q_delegateSizeHintChanged(const QModelIndex&))
friend class ::tst_QAbstractItemView;
friend class ::tst_QTreeView;
diff --git a/src/widgets/itemviews/qabstractitemview_p.h b/src/widgets/itemviews/qabstractitemview_p.h
index 5475db2971..433429f48b 100644
--- a/src/widgets/itemviews/qabstractitemview_p.h
+++ b/src/widgets/itemviews/qabstractitemview_p.h
@@ -16,17 +16,22 @@
//
#include <QtWidgets/private/qtwidgetsglobal_p.h>
+#include "qabstractitemview.h"
#include "private/qabstractscrollarea_p.h"
#include "private/qabstractitemmodel_p.h"
#include "QtWidgets/qapplication.h"
#include "QtGui/qevent.h"
#include "QtCore/qmimedata.h"
#include "QtGui/qpainter.h"
-#include "QtCore/qpair.h"
#include "QtGui/qregion.h"
+
#include "QtCore/qdebug.h"
#include "QtCore/qbasictimer.h"
#include "QtCore/qelapsedtimer.h"
+#include <QtCore/qpointer.h>
+
+
+#include <array>
QT_REQUIRE_CONFIG(itemviews);
@@ -63,20 +68,20 @@ public:
void init();
- virtual void _q_rowsRemoved(const QModelIndex &parent, int start, int end);
- virtual void _q_rowsInserted(const QModelIndex &parent, int start, int end);
- virtual void _q_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
- virtual void _q_columnsRemoved(const QModelIndex &parent, int start, int end);
- virtual void _q_columnsInserted(const QModelIndex &parent, int start, int end);
- virtual void _q_modelDestroyed();
- virtual void _q_layoutChanged();
- virtual void _q_rowsMoved(const QModelIndex &source, int sourceStart, int sourceEnd, const QModelIndex &destination, int destinationStart);
- virtual void _q_columnsMoved(const QModelIndex &source, int sourceStart, int sourceEnd, const QModelIndex &destination, int destinationStart);
+ virtual void rowsRemoved(const QModelIndex &parent, int start, int end);
+ virtual void rowsInserted(const QModelIndex &parent, int start, int end);
+ virtual void columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
+ virtual void columnsRemoved(const QModelIndex &parent, int start, int end);
+ virtual void columnsInserted(const QModelIndex &parent, int start, int end);
+ virtual void modelDestroyed();
+ virtual void layoutChanged();
+ virtual void rowsMoved(const QModelIndex &source, int sourceStart, int sourceEnd, const QModelIndex &destination, int destinationStart);
+ virtual void columnsMoved(const QModelIndex &source, int sourceStart, int sourceEnd, const QModelIndex &destination, int destinationStart);
virtual QRect intersectedRect(const QRect rect, const QModelIndex &topLeft, const QModelIndex &bottomRight) const;
- void _q_headerDataChanged() { doDelayedItemsLayout(); }
- void _q_scrollerStateChanged();
- void _q_delegateSizeHintChanged(const QModelIndex &index);
+ void headerDataChanged() { doDelayedItemsLayout(); }
+ void scrollerStateChanged();
+ void delegateSizeHintChanged(const QModelIndex &index);
void fetchMore();
@@ -178,8 +183,8 @@ public:
inline void releaseEditor(QWidget *editor, const QModelIndex &index = QModelIndex()) const {
if (editor) {
Q_Q(const QAbstractItemView);
- QObject::disconnect(editor, SIGNAL(destroyed(QObject*)),
- q_func(), SLOT(editorDestroyed(QObject*)));
+ QObject::disconnect(editor, &QWidget::destroyed,
+ q, &QAbstractItemView::editorDestroyed);
editor->removeEventFilter(itemDelegate);
editor->hide();
QAbstractItemDelegate *delegate = q->itemDelegateForIndex(index);
@@ -308,13 +313,14 @@ public:
#if QT_CONFIG(draganddrop)
QModelIndexList selectedDraggableIndexes() const;
+ void maybeStartDrag(QPoint eventPoint);
#endif
void doDelayedReset()
{
//we delay the reset of the timer because some views (QTableView)
//with headers can't handle the fact that the model has been destroyed
- //all _q_modelDestroyed slots must have been called
+ //all modelDestroyed() slots must have been called
if (!delayedReset.isActive())
delayedReset.start(0, q_func());
}
@@ -415,7 +421,18 @@ public:
bool verticalScrollModeSet;
bool horizontalScrollModeSet;
+ virtual QRect visualRect(const QModelIndex &index) const { return q_func()->visualRect(index); }
+
+ std::array<QMetaObject::Connection, 14> modelConnections;
+ std::array<QMetaObject::Connection, 4> scrollbarConnections;
+#if QT_CONFIG(gestures) && QT_CONFIG(scroller)
+ QMetaObject::Connection scollerConnection;
+#endif
+
private:
+ void connectDelegate(QAbstractItemDelegate *delegate);
+ void disconnectDelegate(QAbstractItemDelegate *delegate);
+ void disconnectAll();
inline QAbstractItemDelegate *delegateForIndex(const QModelIndex &index) const {
QMap<int, QPointer<QAbstractItemDelegate> >::ConstIterator it;
diff --git a/src/widgets/itemviews/qcolumnview.cpp b/src/widgets/itemviews/qcolumnview.cpp
index 040bddb311..04bc8f5f88 100644
--- a/src/widgets/itemviews/qcolumnview.cpp
+++ b/src/widgets/itemviews/qcolumnview.cpp
@@ -68,7 +68,9 @@ void QColumnViewPrivate::initialize()
Q_Q(QColumnView);
q->setTextElideMode(Qt::ElideMiddle);
#if QT_CONFIG(animation)
- QObject::connect(&currentAnimation, SIGNAL(finished()), q, SLOT(_q_changeCurrentColumn()));
+ animationConnection =
+ QObjectPrivate::connect(&currentAnimation, &QPropertyAnimation::finished,
+ this, &QColumnViewPrivate::changeCurrentColumn);
currentAnimation.setTargetObject(hbar);
currentAnimation.setPropertyName("value");
currentAnimation.setEasingCurve(QEasingCurve::InOutQuad);
@@ -77,11 +79,26 @@ void QColumnViewPrivate::initialize()
q->setItemDelegate(new QColumnViewDelegate(q));
}
+void QColumnViewPrivate::clearConnections()
+{
+#if QT_CONFIG(animation)
+ QObject::disconnect(animationConnection);
+#endif
+ for (const QMetaObject::Connection &connection : gripConnections)
+ QObject::disconnect(connection);
+ const auto copy = viewConnections; // disconnectView modifies this container
+ for (auto it = copy.keyBegin(); it != copy.keyEnd(); ++it)
+ disconnectView(*it);
+}
+
+
/*!
Destroys the column view.
*/
QColumnView::~QColumnView()
{
+ Q_D(QColumnView);
+ d->clearConnections();
}
/*!
@@ -98,12 +115,15 @@ void QColumnView::setResizeGripsVisible(bool visible)
if (d->showResizeGrips == visible)
return;
d->showResizeGrips = visible;
- for (int i = 0; i < d->columns.size(); ++i) {
- QAbstractItemView *view = d->columns[i];
+ d->gripConnections.clear();
+ for (QAbstractItemView *view : std::as_const(d->columns)) {
if (visible) {
QColumnViewGrip *grip = new QColumnViewGrip(view);
view->setCornerWidget(grip);
- connect(grip, SIGNAL(gripMoved(int)), this, SLOT(_q_gripMoved(int)));
+ d->gripConnections.push_back(
+ QObjectPrivate::connect(grip, &QColumnViewGrip::gripMoved,
+ d, &QColumnViewPrivate::gripMoved)
+ );
} else {
QWidget *widget = view->cornerWidget();
view->setCornerWidget(nullptr);
@@ -267,7 +287,7 @@ void QColumnView::scrollTo(const QModelIndex &index, ScrollHint hint)
if (leftEdge > -horizontalOffset()
&& rightEdge <= ( -horizontalOffset() + viewport()->size().width())) {
d->columns.at(indexColumn)->scrollTo(index);
- d->_q_changeCurrentColumn();
+ d->changeCurrentColumn();
return;
}
@@ -486,7 +506,7 @@ QSize QColumnView::sizeHint() const
\internal
Move all widgets from the corner grip and to the right
*/
-void QColumnViewPrivate::_q_gripMoved(int offset)
+void QColumnViewPrivate::gripMoved(int offset)
{
Q_Q(QColumnView);
@@ -578,8 +598,10 @@ void QColumnViewPrivate::closeColumns(const QModelIndex &parent, bool build)
QAbstractItemView* notShownAnymore = columns.at(i);
columns.removeAt(i);
notShownAnymore->setVisible(false);
- if (notShownAnymore != previewColumn)
+ if (notShownAnymore != previewColumn) {
notShownAnymore->deleteLater();
+ disconnectView(notShownAnymore);
+ }
}
if (columns.isEmpty()) {
@@ -598,7 +620,17 @@ void QColumnViewPrivate::closeColumns(const QModelIndex &parent, bool build)
createColumn(parent, false);
}
-void QColumnViewPrivate::_q_clicked(const QModelIndex &index)
+void QColumnViewPrivate::disconnectView(QAbstractItemView *view)
+{
+ const auto it = viewConnections.find(view);
+ if (it == viewConnections.end())
+ return;
+ for (const QMetaObject::Connection &connection : it.value())
+ QObject::disconnect(connection);
+ viewConnections.erase(it);
+}
+
+void QColumnViewPrivate::clicked(const QModelIndex &index)
{
Q_Q(QColumnView);
QModelIndex parent = index.parent();
@@ -631,10 +663,11 @@ QAbstractItemView *QColumnViewPrivate::createColumn(const QModelIndex &index, bo
{
Q_Q(QColumnView);
QAbstractItemView *view = nullptr;
+ QMetaObject::Connection clickedConnection;
if (model->hasChildren(index)) {
view = q->createColumn(index);
- q->connect(view, SIGNAL(clicked(QModelIndex)),
- q, SLOT(_q_clicked(QModelIndex)));
+ clickedConnection = QObjectPrivate::connect(view, &QAbstractItemView::clicked,
+ this, &QColumnViewPrivate::clicked);
} else {
if (!previewColumn)
setPreviewWidget(new QWidget(q));
@@ -642,16 +675,14 @@ QAbstractItemView *QColumnViewPrivate::createColumn(const QModelIndex &index, bo
view->setMinimumWidth(qMax(view->minimumWidth(), previewWidget->minimumWidth()));
}
- q->connect(view, SIGNAL(activated(QModelIndex)),
- q, SIGNAL(activated(QModelIndex)));
- q->connect(view, SIGNAL(clicked(QModelIndex)),
- q, SIGNAL(clicked(QModelIndex)));
- q->connect(view, SIGNAL(doubleClicked(QModelIndex)),
- q, SIGNAL(doubleClicked(QModelIndex)));
- q->connect(view, SIGNAL(entered(QModelIndex)),
- q, SIGNAL(entered(QModelIndex)));
- q->connect(view, SIGNAL(pressed(QModelIndex)),
- q, SIGNAL(pressed(QModelIndex)));
+ viewConnections[view] = {
+ QObject::connect(view, &QAbstractItemView::activated, q, &QColumnView::activated),
+ QObject::connect(view, &QAbstractItemView::clicked, q, &QColumnView::clicked),
+ QObject::connect(view, &QAbstractItemView::doubleClicked, q, &QColumnView::doubleClicked),
+ QObject::connect(view, &QAbstractItemView::entered, q, &QColumnView::entered),
+ QObject::connect(view, &QAbstractItemView::pressed, q, &QColumnView::pressed),
+ clickedConnection
+ };
view->setFocusPolicy(Qt::NoFocus);
view->setParent(viewport);
@@ -661,7 +692,10 @@ QAbstractItemView *QColumnViewPrivate::createColumn(const QModelIndex &index, bo
if (showResizeGrips) {
QColumnViewGrip *grip = new QColumnViewGrip(view);
view->setCornerWidget(grip);
- q->connect(grip, SIGNAL(gripMoved(int)), q, SLOT(_q_gripMoved(int)));
+ gripConnections.push_back(
+ QObjectPrivate::connect(grip, &QColumnViewGrip::gripMoved,
+ this, &QColumnViewPrivate::gripMoved)
+ );
}
if (columnSizes.size() > columns.size()) {
@@ -915,7 +949,7 @@ void QColumnView::currentChanged(const QModelIndex &current, const QModelIndex &
We have change the current column and need to update focus and selection models
on the new current column.
*/
-void QColumnViewPrivate::_q_changeCurrentColumn()
+void QColumnViewPrivate::changeCurrentColumn()
{
Q_Q(QColumnView);
if (columns.isEmpty())
@@ -1022,9 +1056,9 @@ QColumnViewPrivate::~QColumnViewPrivate()
\internal
*/
-void QColumnViewPrivate::_q_columnsInserted(const QModelIndex &parent, int start, int end)
+void QColumnViewPrivate::columnsInserted(const QModelIndex &parent, int start, int end)
{
- QAbstractItemViewPrivate::_q_columnsInserted(parent, start, end);
+ QAbstractItemViewPrivate::columnsInserted(parent, start, end);
checkColumnCreation(parent);
}
diff --git a/src/widgets/itemviews/qcolumnview.h b/src/widgets/itemviews/qcolumnview.h
index 25b15b5273..c0c1398692 100644
--- a/src/widgets/itemviews/qcolumnview.h
+++ b/src/widgets/itemviews/qcolumnview.h
@@ -67,9 +67,6 @@ protected:
private:
Q_DECLARE_PRIVATE(QColumnView)
Q_DISABLE_COPY(QColumnView)
- Q_PRIVATE_SLOT(d_func(), void _q_gripMoved(int))
- Q_PRIVATE_SLOT(d_func(), void _q_changeCurrentColumn())
- Q_PRIVATE_SLOT(d_func(), void _q_clicked(const QModelIndex &))
};
QT_END_NAMESPACE
diff --git a/src/widgets/itemviews/qcolumnview_p.h b/src/widgets/itemviews/qcolumnview_p.h
index 7c68ab2314..f9b2f3baa4 100644
--- a/src/widgets/itemviews/qcolumnview_p.h
+++ b/src/widgets/itemviews/qcolumnview_p.h
@@ -31,6 +31,8 @@
#include <qevent.h>
#include <qscrollbar.h>
+#include <vector>
+
QT_REQUIRE_CONFIG(columnview);
QT_BEGIN_NAMESPACE
@@ -116,20 +118,22 @@ public:
QColumnViewPrivate();
~QColumnViewPrivate();
void initialize();
+ void clearConnections();
QAbstractItemView *createColumn(const QModelIndex &index, bool show);
void updateScrollbars();
void closeColumns(const QModelIndex &parent = QModelIndex(), bool build = false);
+ void disconnectView(QAbstractItemView *view);
void doLayout();
void setPreviewWidget(QWidget *widget);
void checkColumnCreation(const QModelIndex &parent);
- void _q_gripMoved(int offset);
- void _q_changeCurrentColumn();
- void _q_clicked(const QModelIndex &index);
- void _q_columnsInserted(const QModelIndex &parent, int start, int end) override;
+ void gripMoved(int offset);
+ void changeCurrentColumn();
+ void clicked(const QModelIndex &index);
+ void columnsInserted(const QModelIndex &parent, int start, int end) override;
QList<QAbstractItemView*> columns;
QList<int> columnSizes; // used during init and corner moving
@@ -137,7 +141,12 @@ public:
int offset;
#if QT_CONFIG(animation)
QPropertyAnimation currentAnimation;
+ QMetaObject::Connection animationConnection;
#endif
+ std::vector<QMetaObject::Connection> gripConnections;
+ using ViewConnections = std::vector<QMetaObject::Connection>;
+ QHash<QAbstractItemView *, ViewConnections> viewConnections;
+
QWidget *previewWidget;
QAbstractItemView *previewColumn;
};
diff --git a/src/widgets/itemviews/qdatawidgetmapper.cpp b/src/widgets/itemviews/qdatawidgetmapper.cpp
index 5160d06519..3b7e97eed9 100644
--- a/src/widgets/itemviews/qdatawidgetmapper.cpp
+++ b/src/widgets/itemviews/qdatawidgetmapper.cpp
@@ -4,13 +4,15 @@
#include "qdatawidgetmapper.h"
#include "qabstractitemmodel.h"
-#include "qitemdelegate.h"
#include "qmetaobject.h"
#include "qwidget.h"
#include "qstyleditemdelegate.h"
+
#include "private/qobject_p.h"
#include "private/qabstractitemmodel_p.h"
+#include <QtCore/qpointer.h>
+#include <array>
#include <iterator>
QT_BEGIN_NAMESPACE
@@ -67,11 +69,22 @@ public:
void populate();
// private slots
- void _q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
- const QList<int> &);
- void _q_commitData(QWidget *);
- void _q_closeEditor(QWidget *, QAbstractItemDelegate::EndEditHint);
- void _q_modelDestroyed();
+ void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
+ const QList<int> &);
+ void commitData(QWidget *);
+ void closeEditor(QWidget *, QAbstractItemDelegate::EndEditHint);
+ void modelDestroyed();
+
+ void disconnectModel()
+ {
+ for (const QMetaObject::Connection &connection : modelConnections)
+ QObject::disconnect(connection);
+ }
+ void disconnectDelegate()
+ {
+ for (const QMetaObject::Connection &connection : delegateConnections)
+ QObject::disconnect(connection);
+ }
struct WidgetMapper
{
@@ -87,6 +100,8 @@ public:
bool commit(const WidgetMapper &m);
std::vector<WidgetMapper> widgetMap;
+ std::array<QMetaObject::Connection, 2> modelConnections;
+ std::array<QMetaObject::Connection, 2> delegateConnections;
};
Q_DECLARE_TYPEINFO(QDataWidgetMapperPrivate::WidgetMapper, Q_RELOCATABLE_TYPE);
@@ -142,8 +157,8 @@ static bool qContainsIndex(const QModelIndex &idx, const QModelIndex &topLeft,
&& idx.column() >= topLeft.column() && idx.column() <= bottomRight.column();
}
-void QDataWidgetMapperPrivate::_q_dataChanged(const QModelIndex &topLeft,
- const QModelIndex &bottomRight, const QList<int> &)
+void QDataWidgetMapperPrivate::dataChanged(const QModelIndex &topLeft,
+ const QModelIndex &bottomRight, const QList<int> &)
{
if (topLeft.parent() != rootIndex)
return; // not in our hierarchy
@@ -154,7 +169,7 @@ void QDataWidgetMapperPrivate::_q_dataChanged(const QModelIndex &topLeft,
}
}
-void QDataWidgetMapperPrivate::_q_commitData(QWidget *w)
+void QDataWidgetMapperPrivate::commitData(QWidget *w)
{
if (submitPolicy == QDataWidgetMapper::ManualSubmit)
return;
@@ -166,7 +181,7 @@ void QDataWidgetMapperPrivate::_q_commitData(QWidget *w)
commit(widgetMap[idx]);
}
-void QDataWidgetMapperPrivate::_q_closeEditor(QWidget *w, QAbstractItemDelegate::EndEditHint hint)
+void QDataWidgetMapperPrivate::closeEditor(QWidget *w, QAbstractItemDelegate::EndEditHint hint)
{
int idx = findWidget(w);
if (idx == -1)
@@ -189,7 +204,7 @@ void QDataWidgetMapperPrivate::_q_closeEditor(QWidget *w, QAbstractItemDelegate:
}
}
-void QDataWidgetMapperPrivate::_q_modelDestroyed()
+void QDataWidgetMapperPrivate::modelDestroyed()
{
Q_Q(QDataWidgetMapper);
@@ -220,7 +235,7 @@ void QDataWidgetMapperPrivate::_q_modelDestroyed()
instead of the default user property.
It is possible to set an item delegate to support custom widgets. By default,
- a QItemDelegate is used to synchronize the model with the widgets.
+ a QStyledItemDelegate is used to synchronize the model with the widgets.
Let us assume that we have an item model named \c{model} with the following contents:
@@ -299,6 +314,9 @@ QDataWidgetMapper::QDataWidgetMapper(QObject *parent)
*/
QDataWidgetMapper::~QDataWidgetMapper()
{
+ Q_D(QDataWidgetMapper);
+ d->disconnectModel();
+ d->disconnectDelegate();
}
/*!
@@ -314,21 +332,19 @@ void QDataWidgetMapper::setModel(QAbstractItemModel *model)
if (d->model == model)
return;
- if (d->model) {
- disconnect(d->model, SIGNAL(dataChanged(QModelIndex, QModelIndex, QList<int>)), this,
- SLOT(_q_dataChanged(QModelIndex, QModelIndex, QList<int>)));
- disconnect(d->model, SIGNAL(destroyed()), this,
- SLOT(_q_modelDestroyed()));
- }
+ d->disconnectModel();
clearMapping();
d->rootIndex = QModelIndex();
d->currentTopLeft = QModelIndex();
d->model = model;
- connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex, QList<int>)),
- SLOT(_q_dataChanged(QModelIndex, QModelIndex, QList<int>)));
- connect(model, SIGNAL(destroyed()), SLOT(_q_modelDestroyed()));
+ d->modelConnections = {
+ QObjectPrivate::connect(model, &QAbstractItemModel::dataChanged,
+ d, &QDataWidgetMapperPrivate::dataChanged),
+ QObjectPrivate::connect(model, &QAbstractItemModel::destroyed,
+ d, &QDataWidgetMapperPrivate::modelDestroyed)
+ };
}
/*!
@@ -364,18 +380,17 @@ void QDataWidgetMapper::setItemDelegate(QAbstractItemDelegate *delegate)
{
Q_D(QDataWidgetMapper);
QAbstractItemDelegate *oldDelegate = d->delegate;
- if (oldDelegate) {
- disconnect(oldDelegate, SIGNAL(commitData(QWidget*)), this, SLOT(_q_commitData(QWidget*)));
- disconnect(oldDelegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
- this, SLOT(_q_closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
- }
+ d->disconnectDelegate();
d->delegate = delegate;
if (delegate) {
- connect(delegate, SIGNAL(commitData(QWidget*)), SLOT(_q_commitData(QWidget*)));
- connect(delegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)),
- SLOT(_q_closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)));
+ d->delegateConnections = {
+ QObjectPrivate::connect(delegate, &QAbstractItemDelegate::commitData,
+ d, &QDataWidgetMapperPrivate::commitData),
+ QObjectPrivate::connect(delegate, &QAbstractItemDelegate::closeEditor,
+ d, &QDataWidgetMapperPrivate::closeEditor)
+ };
}
d->flipEventFilters(oldDelegate, delegate);
diff --git a/src/widgets/itemviews/qdatawidgetmapper.h b/src/widgets/itemviews/qdatawidgetmapper.h
index 56243f1190..6c7beff7fc 100644
--- a/src/widgets/itemviews/qdatawidgetmapper.h
+++ b/src/widgets/itemviews/qdatawidgetmapper.h
@@ -72,12 +72,6 @@ Q_SIGNALS:
private:
Q_DECLARE_PRIVATE(QDataWidgetMapper)
Q_DISABLE_COPY(QDataWidgetMapper)
- Q_PRIVATE_SLOT(d_func(),
- void _q_dataChanged(const QModelIndex &, const QModelIndex &,
- const QList<int> &))
- Q_PRIVATE_SLOT(d_func(), void _q_commitData(QWidget *))
- Q_PRIVATE_SLOT(d_func(), void _q_closeEditor(QWidget *, QAbstractItemDelegate::EndEditHint))
- Q_PRIVATE_SLOT(d_func(), void _q_modelDestroyed())
};
QT_END_NAMESPACE
diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp
index b5b0f17f4a..9ce09dbacc 100644
--- a/src/widgets/itemviews/qheaderview.cpp
+++ b/src/widgets/itemviews/qheaderview.cpp
@@ -295,6 +295,8 @@ QHeaderView::QHeaderView(QHeaderViewPrivate &dd,
QHeaderView::~QHeaderView()
{
+ Q_D(QHeaderView);
+ d->disconnectModel();
}
/*!
@@ -322,68 +324,35 @@ void QHeaderView::setModel(QAbstractItemModel *model)
return;
Q_D(QHeaderView);
d->layoutChangePersistentSections.clear();
- if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
- if (d->orientation == Qt::Horizontal) {
- QObject::disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
- this, SLOT(sectionsInserted(QModelIndex,int,int)));
- QObject::disconnect(d->model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
- QObject::disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
- QObject::disconnect(d->model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sectionsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
- QObject::disconnect(d->model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sectionsMoved(QModelIndex,int,int,QModelIndex,int)));
- } else {
- QObject::disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(sectionsInserted(QModelIndex,int,int)));
- QObject::disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
- QObject::disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
- QObject::disconnect(d->model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sectionsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
- QObject::disconnect(d->model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sectionsMoved(QModelIndex,int,int,QModelIndex,int)));
- }
- QObject::disconnect(d->model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
- this, SLOT(headerDataChanged(Qt::Orientation,int,int)));
- QObject::disconnect(d->model, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- this, SLOT(_q_sectionsAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
- QObject::disconnect(d->model, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- this, SLOT(_q_sectionsChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
- }
+ if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel())
+ d->disconnectModel();
if (model && model != QAbstractItemModelPrivate::staticEmptyModel()) {
- if (d->orientation == Qt::Horizontal) {
- QObject::connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)),
- this, SLOT(sectionsInserted(QModelIndex,int,int)));
- QObject::connect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
- QObject::connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
- QObject::connect(model, SIGNAL(columnsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sectionsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
- QObject::connect(model, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sectionsMoved(QModelIndex,int,int,QModelIndex,int)));
- } else {
- QObject::connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(sectionsInserted(QModelIndex,int,int)));
- QObject::connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(sectionsAboutToBeRemoved(QModelIndex,int,int)));
- QObject::connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sectionsRemoved(QModelIndex,int,int)));
- QObject::connect(model, SIGNAL(rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sectionsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)));
- QObject::connect(model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
- this, SLOT(_q_sectionsMoved(QModelIndex,int,int,QModelIndex,int)));
- }
- QObject::connect(model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
- this, SLOT(headerDataChanged(Qt::Orientation,int,int)));
- QObject::connect(model, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- this, SLOT(_q_sectionsAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
- QObject::connect(model, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
- this, SLOT(_q_sectionsChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
+ const bool hor = d->orientation == Qt::Horizontal;
+ d->modelConnections = {
+ QObject::connect(model, hor ? &QAbstractItemModel::columnsInserted
+ : &QAbstractItemModel::rowsInserted,
+ this, &QHeaderView::sectionsInserted),
+ QObject::connect(model, hor ? &QAbstractItemModel::columnsAboutToBeRemoved
+ : &QAbstractItemModel::rowsAboutToBeRemoved,
+ this, &QHeaderView::sectionsAboutToBeRemoved),
+ QObjectPrivate::connect(model, hor ? &QAbstractItemModel::columnsRemoved
+ : &QAbstractItemModel::rowsRemoved,
+ d, &QHeaderViewPrivate::sectionsRemoved),
+ QObjectPrivate::connect(model, hor ? &QAbstractItemModel::columnsAboutToBeMoved
+ : &QAbstractItemModel::rowsAboutToBeMoved,
+ d, &QHeaderViewPrivate::sectionsAboutToBeMoved),
+ QObjectPrivate::connect(model, hor ? &QAbstractItemModel::columnsMoved
+ : &QAbstractItemModel::rowsMoved,
+ d, &QHeaderViewPrivate::sectionsMoved),
+
+ QObject::connect(model, &QAbstractItemModel::headerDataChanged,
+ this, &QHeaderView::headerDataChanged),
+ QObjectPrivate::connect(model, &QAbstractItemModel::layoutAboutToBeChanged,
+ d, &QHeaderViewPrivate::sectionsAboutToBeChanged),
+ QObjectPrivate::connect(model, &QAbstractItemModel::layoutChanged,
+ d, &QHeaderViewPrivate::sectionsChanged)
+ };
}
d->state = QHeaderViewPrivate::NoClear;
@@ -418,7 +387,7 @@ Qt::Orientation QHeaderView::orientation() const
int QHeaderView::offset() const
{
Q_D(const QHeaderView);
- return d->offset;
+ return d->headerOffset;
}
/*!
@@ -432,10 +401,10 @@ int QHeaderView::offset() const
void QHeaderView::setOffset(int newOffset)
{
Q_D(QHeaderView);
- if (d->offset == (int)newOffset)
+ if (d->headerOffset == newOffset)
return;
- int ndelta = d->offset - newOffset;
- d->offset = newOffset;
+ int ndelta = d->headerOffset - newOffset;
+ d->headerOffset = newOffset;
if (d->orientation == Qt::Horizontal)
d->viewport->scroll(isRightToLeft() ? -ndelta : ndelta, 0);
else
@@ -591,7 +560,7 @@ int QHeaderView::visualIndexAt(int position) const
if (d->reverse())
vposition = d->viewport->width() - vposition - 1;
- vposition += d->offset;
+ vposition += d->headerOffset;
if (vposition > d->length)
return -1;
@@ -681,7 +650,7 @@ int QHeaderView::sectionViewportPosition(int logicalIndex) const
int position = sectionPosition(logicalIndex);
if (position < 0)
return position; // the section was hidden
- int offsetPosition = position - d->offset;
+ int offsetPosition = position - d->headerOffset;
if (d->reverse())
return d->viewport->width() - (offsetPosition + sectionSize(logicalIndex));
return offsetPosition;
@@ -1087,19 +1056,22 @@ int QHeaderView::logicalIndex(int visualIndex) const
}
/*!
- \since 5.0
+ \property QHeaderView::sectionsMovable
- If \a movable is true, the header sections may be moved by the user;
+ If \a sectionsMovable is true, the header sections may be moved by the user;
otherwise they are fixed in place.
When used in combination with QTreeView, the first column is not
movable (since it contains the tree structure), by default.
You can make it movable with setFirstSectionMovable(true).
- \sa sectionsMovable(), sectionMoved()
+ \sa sectionMoved()
\sa setFirstSectionMovable()
*/
+/*!
+ Sets \l sectionsMovable to \a movable.
+ */
void QHeaderView::setSectionsMovable(bool movable)
{
Q_D(QHeaderView);
@@ -1107,17 +1079,8 @@ void QHeaderView::setSectionsMovable(bool movable)
}
/*!
- \since 5.0
-
- Returns \c true if the header can be moved by the user; otherwise returns
- false.
-
- By default, sections are movable in QTreeView (except for the first one),
- and not movable in QTableView.
-
- \sa setSectionsMovable()
+ Returns \l sectionsMovable.
*/
-
bool QHeaderView::sectionsMovable() const
{
Q_D(const QHeaderView);
@@ -1137,6 +1100,11 @@ bool QHeaderView::sectionsMovable() const
In such a scenario, it is recommended to call QTreeView::setRootIsDecorated(false)
as well.
+ \code
+ treeView->setRootIsDecorated(false);
+ treeView->header()->setFirstSectionMovable(true);
+ \endcode
+
Setting it to true has no effect unless setSectionsMovable(true) is called
as well.
@@ -1156,14 +1124,17 @@ bool QHeaderView::isFirstSectionMovable() const
}
/*!
- \since 5.0
+ \property QHeaderView::sectionsClickable
- If \a clickable is true, the header will respond to single clicks.
+ Holds \c true if the header is clickable; otherwise \c false. A
+ clickable header could be set up to allow the user to change the
+ representation of the data in the view related to the header.
- \sa sectionsClickable(), sectionClicked(), sectionPressed(),
- setSortIndicatorShown()
+ \sa sectionPressed(), setSortIndicatorShown()
+*/
+/*!
+ Set \l sectionsClickable to \a clickable.
*/
-
void QHeaderView::setSectionsClickable(bool clickable)
{
Q_D(QHeaderView);
@@ -1171,15 +1142,8 @@ void QHeaderView::setSectionsClickable(bool clickable)
}
/*!
- \since 5.0
-
- Returns \c true if the header is clickable; otherwise returns \c false. A
- clickable header could be set up to allow the user to change the
- representation of the data in the view related to the header.
-
- \sa setSectionsClickable()
+ Returns \l sectionsClickable.
*/
-
bool QHeaderView::sectionsClickable() const
{
Q_D(const QHeaderView);
@@ -1880,8 +1844,9 @@ void QHeaderView::sectionsInserted(const QModelIndex &parent,
int logicalFirst, int logicalLast)
{
Q_D(QHeaderView);
- if (parent != d->root)
- return; // we only handle changes in the root level
+ // only handle root level changes and return on no-op
+ if (parent != d->root || d->modelSectionCount() == d->sectionCount())
+ return;
int oldCount = d->sectionCount();
d->invalidateCachedSizeHint();
@@ -2004,8 +1969,8 @@ void QHeaderViewPrivate::updateHiddenSections(int logicalFirst, int logicalLast)
hiddenSectionSize = newHiddenSectionSize;
}
-void QHeaderViewPrivate::_q_sectionsRemoved(const QModelIndex &parent,
- int logicalFirst, int logicalLast)
+void QHeaderViewPrivate::sectionsRemoved(const QModelIndex &parent,
+ int logicalFirst, int logicalLast)
{
Q_Q(QHeaderView);
if (parent != root)
@@ -2090,28 +2055,32 @@ void QHeaderViewPrivate::_q_sectionsRemoved(const QModelIndex &parent,
viewport->update();
}
-void QHeaderViewPrivate::_q_sectionsAboutToBeMoved(const QModelIndex &sourceParent, int logicalStart, int logicalEnd, const QModelIndex &destinationParent, int logicalDestination)
+void QHeaderViewPrivate::sectionsAboutToBeMoved(const QModelIndex &sourceParent, int logicalStart,
+ int logicalEnd, const QModelIndex &destinationParent,
+ int logicalDestination)
{
if (sourceParent != root || destinationParent != root)
return; // we only handle changes in the root level
Q_UNUSED(logicalStart);
Q_UNUSED(logicalEnd);
Q_UNUSED(logicalDestination);
- _q_sectionsAboutToBeChanged();
+ sectionsAboutToBeChanged();
}
-void QHeaderViewPrivate::_q_sectionsMoved(const QModelIndex &sourceParent, int logicalStart, int logicalEnd, const QModelIndex &destinationParent, int logicalDestination)
+void QHeaderViewPrivate::sectionsMoved(const QModelIndex &sourceParent, int logicalStart,
+ int logicalEnd, const QModelIndex &destinationParent,
+ int logicalDestination)
{
if (sourceParent != root || destinationParent != root)
return; // we only handle changes in the root level
Q_UNUSED(logicalStart);
Q_UNUSED(logicalEnd);
Q_UNUSED(logicalDestination);
- _q_sectionsChanged();
+ sectionsChanged();
}
-void QHeaderViewPrivate::_q_sectionsAboutToBeChanged(const QList<QPersistentModelIndex> &,
- QAbstractItemModel::LayoutChangeHint hint)
+void QHeaderViewPrivate::sectionsAboutToBeChanged(const QList<QPersistentModelIndex> &,
+ QAbstractItemModel::LayoutChangeHint hint)
{
if ((hint == QAbstractItemModel::VerticalSortHint && orientation == Qt::Horizontal) ||
(hint == QAbstractItemModel::HorizontalSortHint && orientation == Qt::Vertical))
@@ -2156,8 +2125,8 @@ void QHeaderViewPrivate::_q_sectionsAboutToBeChanged(const QList<QPersistentMode
}
}
-void QHeaderViewPrivate::_q_sectionsChanged(const QList<QPersistentModelIndex> &,
- QAbstractItemModel::LayoutChangeHint hint)
+void QHeaderViewPrivate::sectionsChanged(const QList<QPersistentModelIndex> &,
+ QAbstractItemModel::LayoutChangeHint hint)
{
if ((hint == QAbstractItemModel::VerticalSortHint && orientation == Qt::Horizontal) ||
(hint == QAbstractItemModel::HorizontalSortHint && orientation == Qt::Vertical))
@@ -2187,7 +2156,7 @@ void QHeaderViewPrivate::_q_sectionsChanged(const QList<QPersistentModelIndex> &
}
// Though far from perfect we here try to retain earlier/existing behavior
- // ### See QHeaderViewPrivate::_q_layoutAboutToBeChanged()
+ // ### See QHeaderViewPrivate::layoutAboutToBeChanged()
// When we don't have valid hasPersistantIndexes it can be due to
// - all sections are default sections
// - the row/column 0 which is used for persistent indexes is gone
@@ -2513,9 +2482,9 @@ void QHeaderView::paintEvent(QPaintEvent *e)
for (int a = 0, i = 0; i < d->sectionItems.count(); ++i) {
QColor color((i & 4 ? 255 : 0), (i & 2 ? 255 : 0), (i & 1 ? 255 : 0));
if (d->orientation == Qt::Horizontal)
- painter.fillRect(a - d->offset, 0, d->sectionItems.at(i).size, 4, color);
+ painter.fillRect(a - d->headerOffset, 0, d->sectionItems.at(i).size, 4, color);
else
- painter.fillRect(0, a - d->offset, 4, d->sectionItems.at(i).size, color);
+ painter.fillRect(0, a - d->headerOffset, 4, d->sectionItems.at(i).size, color);
a += d->sectionItems.at(i).size;
}
@@ -2574,7 +2543,7 @@ void QHeaderView::mousePressEvent(QMouseEvent *e)
void QHeaderView::mouseMoveEvent(QMouseEvent *e)
{
Q_D(QHeaderView);
- int pos = d->orientation == Qt::Horizontal ? e->position().toPoint().x() : e->position().toPoint().y();
+ const int pos = d->orientation == Qt::Horizontal ? e->position().toPoint().x() : e->position().toPoint().y();
if (pos < 0 && d->state != QHeaderViewPrivate::SelectSections)
return;
if (e->buttons() == Qt::NoButton) {
@@ -2602,8 +2571,10 @@ void QHeaderView::mouseMoveEvent(QMouseEvent *e)
return;
}
case QHeaderViewPrivate::MoveSection: {
- if (d->shouldAutoScroll(e->position().toPoint()))
+ if (d->shouldAutoScroll(e->position().toPoint())) {
+ d->draggedPosition = e->pos() + d->offset();
d->startAutoScroll();
+ }
if (qAbs(pos - d->firstPos) >= QApplication::startDragDistance()
#if QT_CONFIG(label)
|| !d->sectionIndicator->isHidden()
@@ -2615,7 +2586,7 @@ void QHeaderView::mouseMoveEvent(QMouseEvent *e)
if (visual == 0 && logicalIndex(0) == 0 && !d->allowUserMoveOfSection0)
return;
- const int posThreshold = d->headerSectionPosition(visual) - d->offset + d->headerSectionSize(visual) / 2;
+ const int posThreshold = d->headerSectionPosition(visual) - d->headerOffset + d->headerSectionSize(visual) / 2;
const int checkPos = d->reverse() ? d->viewport->width() - pos : pos;
int moving = visualIndex(d->section);
int oldTarget = d->target;
@@ -2639,7 +2610,7 @@ void QHeaderView::mouseMoveEvent(QMouseEvent *e)
return;
}
case QHeaderViewPrivate::SelectSections: {
- int logical = logicalIndexAt(qMax(-d->offset, pos));
+ int logical = logicalIndexAt(qMax(-d->headerOffset, pos));
if (logical == -1 && pos > 0)
logical = logicalIndex(d->lastVisibleVisualIndex());
if (logical == d->pressed)
@@ -3061,7 +3032,7 @@ int QHeaderView::horizontalOffset() const
{
Q_D(const QHeaderView);
if (d->orientation == Qt::Horizontal)
- return d->offset;
+ return d->headerOffset;
return 0;
}
@@ -3076,7 +3047,7 @@ int QHeaderView::verticalOffset() const
{
Q_D(const QHeaderView);
if (d->orientation == Qt::Vertical)
- return d->offset;
+ return d->headerOffset;
return 0;
}
@@ -3800,12 +3771,9 @@ void QHeaderViewPrivate::cascadingResize(int visual, int newSize)
if (currentSectionSize <= minimumSize)
continue;
int newSectionSize = qMax(currentSectionSize - delta, minimumSize);
- //qDebug() << "### cascading to" << i << newSectionSize - currentSectionSize << delta;
resizeSectionItem(i, currentSectionSize, newSectionSize);
saveCascadingSectionSize(i, currentSectionSize);
delta = delta - (currentSectionSize - newSectionSize);
- //qDebug() << "new delta" << delta;
- //if (newSectionSize != minimumSize)
if (delta <= 0)
break;
}
@@ -3823,7 +3791,6 @@ void QHeaderViewPrivate::cascadingResize(int visual, int newSize)
int newSectionSize = currentSectionSize - delta;
resizeSectionItem(i, currentSectionSize, newSectionSize);
if (newSectionSize >= originalSectionSize && false) {
- //qDebug() << "section" << i << "restored to" << originalSectionSize;
cascadingSectionSize.remove(i); // the section is now restored
}
sectionResized = true;
diff --git a/src/widgets/itemviews/qheaderview.h b/src/widgets/itemviews/qheaderview.h
index 6118faa868..bd0050df5e 100644
--- a/src/widgets/itemviews/qheaderview.h
+++ b/src/widgets/itemviews/qheaderview.h
@@ -19,6 +19,8 @@ class Q_WIDGETS_EXPORT QHeaderView : public QAbstractItemView
Q_OBJECT
Q_PROPERTY(bool firstSectionMovable READ isFirstSectionMovable WRITE setFirstSectionMovable)
Q_PROPERTY(bool showSortIndicator READ isSortIndicatorShown WRITE setSortIndicatorShown)
+ Q_PROPERTY(bool sectionsMovable READ sectionsMovable WRITE setSectionsMovable)
+ Q_PROPERTY(bool sectionsClickable READ sectionsClickable WRITE setSectionsClickable)
Q_PROPERTY(bool highlightSections READ highlightSections WRITE setHighlightSections)
Q_PROPERTY(bool stretchLastSection READ stretchLastSection WRITE setStretchLastSection)
Q_PROPERTY(bool cascadingSectionResizes READ cascadingSectionResizes
@@ -211,14 +213,6 @@ protected:
private:
void initStyleOption(QStyleOptionFrame *option) const override;
- // ### Qt6: make them protected slots in QHeaderViewPrivate
- Q_PRIVATE_SLOT(d_func(), void _q_sectionsRemoved(const QModelIndex &parent, int logicalFirst, int logicalLast))
- Q_PRIVATE_SLOT(d_func(), void _q_sectionsAboutToBeMoved(const QModelIndex &sourceParent, int logicalStart, int logicalEnd, const QModelIndex &destinationParent, int logicalDestination))
- Q_PRIVATE_SLOT(d_func(), void _q_sectionsMoved(const QModelIndex &sourceParent, int logicalStart, int logicalEnd, const QModelIndex &destinationParent, int logicalDestination))
- Q_PRIVATE_SLOT(d_func(), void _q_sectionsAboutToBeChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(),
- QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint))
- Q_PRIVATE_SLOT(d_func(), void _q_sectionsChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(),
- QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint))
Q_DECLARE_PRIVATE(QHeaderView)
Q_DISABLE_COPY(QHeaderView)
};
diff --git a/src/widgets/itemviews/qheaderview_p.h b/src/widgets/itemviews/qheaderview_p.h
index c599aeff8d..8b214e1d03 100644
--- a/src/widgets/itemviews/qheaderview_p.h
+++ b/src/widgets/itemviews/qheaderview_p.h
@@ -16,6 +16,7 @@
//
#include <QtWidgets/private/qtwidgetsglobal_p.h>
+#include "qheaderview.h"
#include "private/qabstractitemview_p.h"
#include "QtCore/qbitarray.h"
@@ -24,6 +25,8 @@
#include "QtWidgets/qlabel.h"
#endif
+#include <array>
+
QT_REQUIRE_CONFIG(itemviews);
QT_BEGIN_NAMESPACE
@@ -37,7 +40,7 @@ public:
QHeaderViewPrivate()
: state(NoState),
- offset(0),
+ headerOffset(0),
sortIndicatorOrder(Qt::DescendingOrder),
sortIndicatorSection(0),
sortIndicatorShown(false),
@@ -85,13 +88,17 @@ public:
void updateSectionIndicator(int section, int position);
void updateHiddenSections(int logicalFirst, int logicalLast);
void resizeSections(QHeaderView::ResizeMode globalMode, bool useGlobalMode = false);
- void _q_sectionsRemoved(const QModelIndex &,int,int);
- void _q_sectionsAboutToBeMoved(const QModelIndex &sourceParent, int logicalStart, int logicalEnd, const QModelIndex &destinationParent, int logicalDestination);
- void _q_sectionsMoved(const QModelIndex &sourceParent, int logicalStart, int logicalEnd, const QModelIndex &destinationParent, int logicalDestination);
- void _q_sectionsAboutToBeChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(),
- QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint);
- void _q_sectionsChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(),
- QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint);
+ void sectionsRemoved(const QModelIndex &,int,int);
+ void sectionsAboutToBeMoved(const QModelIndex &sourceParent, int logicalStart,
+ int logicalEnd, const QModelIndex &destinationParent,
+ int logicalDestination);
+ void sectionsMoved(const QModelIndex &sourceParent, int logicalStart,
+ int logicalEnd, const QModelIndex &destinationParent,
+ int logicalDestination);
+ void sectionsAboutToBeChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(),
+ QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint);
+ void sectionsChanged(const QList<QPersistentModelIndex> &parents = QList<QPersistentModelIndex>(),
+ QAbstractItemModel::LayoutChangeHint hint = QAbstractItemModel::NoLayoutChangeHint);
bool isSectionSelected(int section) const;
bool isFirstVisibleSection(int section) const;
@@ -212,6 +219,12 @@ public:
}
}
+ inline void disconnectModel()
+ {
+ for (const QMetaObject::Connection &connection : modelConnections)
+ QObject::disconnect(connection);
+ }
+
void clear();
void flipSortIndicator(int section);
Qt::SortOrder defaultSortOrderForSection(int section) const;
@@ -219,7 +232,7 @@ public:
enum State { NoState, ResizeSection, MoveSection, SelectSections, NoClear } state;
- int offset;
+ int headerOffset;
Qt::Orientation orientation;
Qt::SortOrder sortIndicatorOrder;
int sortIndicatorSection;
@@ -304,6 +317,7 @@ public:
SectionItem section;
};
QList<LayoutChangeItem> layoutChangePersistentSections;
+ std::array<QMetaObject::Connection, 8> modelConnections;
void createSectionItems(int start, int end, int sectionSize, QHeaderView::ResizeMode mode);
void removeSectionsFromSectionItems(int start, int end);
diff --git a/src/widgets/itemviews/qitemdelegate.cpp b/src/widgets/itemviews/qitemdelegate.cpp
index 79ee203aca..d1c7bb3d58 100644
--- a/src/widgets/itemviews/qitemdelegate.cpp
+++ b/src/widgets/itemviews/qitemdelegate.cpp
@@ -257,17 +257,27 @@ QSizeF QItemDelegatePrivate::doTextLayout(int lineWidth) const
When subclassing QItemDelegate to create a delegate that displays items
using a custom renderer, it is important to ensure that the delegate can
- render items suitably for all the required states; e.g. selected,
+ render items suitably for all the required states; such as selected,
disabled, checked. The documentation for the paint() function contains
some hints to show how this can be achieved.
- You can provide custom editors by using a QItemEditorFactory. The
- \l{Color Editor Factory Example} shows how a custom editor can be
- made available to delegates with the default item editor
- factory. This way, there is no need to subclass QItemDelegate. An
- alternative is to reimplement createEditor(), setEditorData(),
- setModelData(), and updateEditorGeometry(). This process is
- described in the \l{Spin Box Delegate Example}.
+ You can provide custom editors by using a QItemEditorFactory. The following
+ code shows how a custom editor can be made available to delegates with the
+ default item editor factory.
+
+ \snippet code/src_gui_itemviews_qitemeditorfactory.cpp setDefaultFactory
+
+ After the default factory has been set, all standard item delegates
+ will use it (also the delegates that were created before setting the
+ default factory).
+
+ This way, you can avoid subclassing QItemDelegate, and all values of the
+ specified type (for example QMetaType::QDateTime) will be edited using the
+ provided editor (like \c{MyFancyDateTimeEdit} in the above example).
+
+ An alternative is to reimplement createEditor(), setEditorData(),
+ setModelData(), and updateEditorGeometry(). This process is described
+ in the \l{A simple delegate}{Model/View Programming overview documentation}.
\section1 QStyledItemDelegate vs. QItemDelegate
@@ -281,9 +291,7 @@ QSizeF QItemDelegatePrivate::doTextLayout(int lineWidth) const
for either class should be equal unless the custom delegate needs to use
the style for drawing.
- \sa {Delegate Classes}, QStyledItemDelegate, QAbstractItemDelegate,
- {Spin Box Delegate Example}, {Settings Editor Example},
- {Icons Example}
+ \sa {Delegate Classes}, QStyledItemDelegate, QAbstractItemDelegate
*/
/*!
@@ -343,8 +351,10 @@ QString QItemDelegatePrivate::valueToText(const QVariant &value, const QStyleOpt
For example, a selected item may need to be displayed differently to
unselected items, as shown in the following code:
- \snippet itemviews/pixelator/pixeldelegate.cpp 2
- \dots
+ \code
+ if (option.state & QStyle::State_Selected)
+ painter->fillRect(option.rect, option.palette.highlight());
+ \endcode
After painting, you should ensure that the painter is returned to its
the state it was supplied in when this function was called. For example,
diff --git a/src/widgets/itemviews/qitemeditorfactory.cpp b/src/widgets/itemviews/qitemeditorfactory.cpp
index 609df364cf..70d11e1b38 100644
--- a/src/widgets/itemviews/qitemeditorfactory.cpp
+++ b/src/widgets/itemviews/qitemeditorfactory.cpp
@@ -120,7 +120,7 @@ Q_SIGNALS:
Additional editors can be registered with the registerEditor() function.
- \sa QStyledItemDelegate, {Model/View Programming}, {Color Editor Factory Example}
+ \sa QStyledItemDelegate, {Model/View Programming}
*/
/*!
@@ -363,7 +363,7 @@ void QItemEditorFactory::setDefaultFactory(QItemEditorFactory *factory)
to register widgets without the need to subclass QItemEditorCreatorBase.
\sa QStandardItemEditorCreator, QItemEditorFactory,
- {Model/View Programming}, {Color Editor Factory Example}
+ {Model/View Programming}
*/
/*!
@@ -432,7 +432,7 @@ QItemEditorCreatorBase::~QItemEditorCreatorBase()
property, you should use QStandardItemEditorCreator instead.
\sa QItemEditorCreatorBase, QStandardItemEditorCreator,
- QItemEditorFactory, {Color Editor Factory Example}
+ QItemEditorFactory
*/
/*!
@@ -488,7 +488,7 @@ QItemEditorCreatorBase::~QItemEditorCreatorBase()
\snippet code/src_gui_itemviews_qitemeditorfactory.cpp 3
\sa QItemEditorCreatorBase, QItemEditorCreator,
- QItemEditorFactory, QStyledItemDelegate, {Color Editor Factory Example}
+ QItemEditorFactory, QStyledItemDelegate
*/
/*!
diff --git a/src/widgets/itemviews/qlistview.cpp b/src/widgets/itemviews/qlistview.cpp
index b03c1a47f5..a7f1931947 100644
--- a/src/widgets/itemviews/qlistview.cpp
+++ b/src/widgets/itemviews/qlistview.cpp
@@ -88,7 +88,7 @@ extern bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event);
that can be taken for views that are intended to display items with equal sizes
is to set the \l uniformItemSizes property to true.
- \sa {View Classes}, {Item Views Puzzle Example}, QTreeView, QTableView, QListWidget
+ \sa {View Classes}, QTreeView, QTableView, QListWidget
*/
/*!
@@ -352,7 +352,7 @@ int QListView::spacing() const
/*!
\property QListView::batchSize
\brief the number of items laid out in each batch if \l layoutMode is
- set to \l Batched
+ set to \l Batched.
The default value is 100.
@@ -755,7 +755,10 @@ void QListView::mouseMoveEvent(QMouseEvent *e)
&& d->selectionMode != NoSelection) {
QRect rect(d->pressedPosition, e->position().toPoint() + QPoint(horizontalOffset(), verticalOffset()));
rect = rect.normalized();
- d->viewport->update(d->mapToViewport(rect.united(d->elasticBand)));
+ const int margin = 2 * style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
+ const QRect viewPortRect = rect.united(d->elasticBand)
+ .adjusted(-margin, -margin, margin, margin);
+ d->viewport->update(d->mapToViewport(viewPortRect));
d->elasticBand = rect;
}
}
@@ -769,7 +772,9 @@ void QListView::mouseReleaseEvent(QMouseEvent *e)
QAbstractItemView::mouseReleaseEvent(e);
// #### move this implementation into a dynamic class
if (d->showElasticBand && d->elasticBand.isValid()) {
- d->viewport->update(d->mapToViewport(d->elasticBand));
+ const int margin = 2 * style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
+ const QRect viewPortRect = d->elasticBand.adjusted(-margin, -margin, margin, margin);
+ d->viewport->update(d->mapToViewport(viewPortRect));
d->elasticBand = QRect();
}
}
@@ -910,7 +915,8 @@ void QListView::dropEvent(QDropEvent *event)
bool dataMoved = false;
for (int i = 0; i < persIndexes.size(); ++i) {
const QPersistentModelIndex &pIndex = persIndexes.at(i);
- if (r != pIndex.row()) {
+ // only generate a move when not same row or behind itself
+ if (r != pIndex.row() && r != pIndex.row() + 1) {
// try to move (preserves selection)
dataMoved |= model()->moveRow(QModelIndex(), pIndex.row(), QModelIndex(), r);
if (!dataMoved) // can't move - abort and let QAbstractItemView handle this
@@ -1621,6 +1627,12 @@ void QListView::setModelColumn(int column)
return;
d->column = column;
d->doDelayedItemsLayout();
+#if QT_CONFIG(accessibility)
+ if (QAccessible::isActive()) {
+ QAccessibleTableModelChangeEvent event(this, QAccessibleTableModelChangeEvent::ModelReset);
+ QAccessible::updateAccessibility(&event);
+ }
+#endif
}
int QListView::modelColumn() const
@@ -1790,7 +1802,7 @@ void QListViewPrivate::prepareItemsLayout()
if (q->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents)) {
QStyleOption option;
option.initFrom(q);
- frameAroundContents = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &option) * 2;
+ frameAroundContents = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &option, q) * 2;
}
// maximumViewportSize() already takes scrollbar into account if policy is
@@ -3401,7 +3413,7 @@ void QListView::currentChanged(const QModelIndex &current, const QModelIndex &pr
QAbstractItemView::currentChanged(current, previous);
#if QT_CONFIG(accessibility)
if (QAccessible::isActive()) {
- if (current.isValid()) {
+ if (current.isValid() && hasFocus()) {
int entry = visualIndex(current);
QAccessibleEvent event(this, QAccessible::Focus);
event.setChild(entry);
diff --git a/src/widgets/itemviews/qlistview_p.h b/src/widgets/itemviews/qlistview_p.h
index de928bbb28..40dabf5656 100644
--- a/src/widgets/itemviews/qlistview_p.h
+++ b/src/widgets/itemviews/qlistview_p.h
@@ -16,6 +16,7 @@
//
#include <QtWidgets/private/qtwidgetsglobal_p.h>
+#include "qlistview.h"
#include "private/qabstractitemview_p.h"
#include "qbitarray.h"
#include "qbsptree_p.h"
diff --git a/src/widgets/itemviews/qlistwidget.cpp b/src/widgets/itemviews/qlistwidget.cpp
index cc0ccf84da..a91902813a 100644
--- a/src/widgets/itemviews/qlistwidget.cpp
+++ b/src/widgets/itemviews/qlistwidget.cpp
@@ -3,7 +3,6 @@
#include "qlistwidget.h"
-#include <qitemdelegate.h>
#include <private/qlistview_p.h>
#include <private/qwidgetitemdata_p.h>
#include <private/qlistwidget_p.h>
@@ -308,7 +307,7 @@ void QListModel::sort(int column, Qt::SortOrder order)
}
const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan);
- std::sort(sorting.begin(), sorting.end(), compare);
+ std::stable_sort(sorting.begin(), sorting.end(), compare);
QModelIndexList fromIndexes;
QModelIndexList toIndexes;
const int sortingCount = sorting.size();
@@ -328,76 +327,34 @@ void QListModel::sort(int column, Qt::SortOrder order)
/**
* This function assumes that all items in the model except the items that are between
* (inclusive) start and end are sorted.
- * With these assumptions, this function can ensure that the model is sorted in a
- * much more efficient way than doing a naive 'sort everything'.
- * (provided that the range is relatively small compared to the total number of items)
*/
void QListModel::ensureSorted(int column, Qt::SortOrder order, int start, int end)
{
if (column != 0)
return;
- const int count = end - start + 1;
- QList<QPair<QListWidgetItem *, int>> sorting(count);
- for (int i = 0; i < count; ++i) {
- sorting[i].first = items.at(start + i);
- sorting[i].second = start + i;
- }
+ const auto compareLt = [](const QListWidgetItem *left, const QListWidgetItem *right) -> bool {
+ return *left < *right;
+ };
- const auto compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan);
- std::sort(sorting.begin(), sorting.end(), compare);
-
- QModelIndexList oldPersistentIndexes = persistentIndexList();
- QModelIndexList newPersistentIndexes = oldPersistentIndexes;
- QList<QListWidgetItem*> tmp = items;
- QList<QListWidgetItem*>::iterator lit = tmp.begin();
- bool changed = false;
- for (int i = 0; i < count; ++i) {
- int oldRow = sorting.at(i).second;
- int tmpitepos = lit - tmp.begin();
- QListWidgetItem *item = tmp.takeAt(oldRow);
- if (tmpitepos > tmp.size())
- --tmpitepos;
- lit = tmp.begin() + tmpitepos;
- lit = sortedInsertionIterator(lit, tmp.end(), order, item);
- int newRow = qMax<qsizetype>(lit - tmp.begin(), 0);
- lit = tmp.insert(lit, item);
- if (newRow != oldRow) {
- if (!changed) {
- emit layoutAboutToBeChanged({}, QAbstractItemModel::VerticalSortHint);
- oldPersistentIndexes = persistentIndexList();
- newPersistentIndexes = oldPersistentIndexes;
- changed = true;
- }
- for (int j = i + 1; j < count; ++j) {
- int otherRow = sorting.at(j).second;
- if (oldRow < otherRow && newRow >= otherRow)
- --sorting[j].second;
- else if (oldRow > otherRow && newRow <= otherRow)
- ++sorting[j].second;
- }
- for (int k = 0; k < newPersistentIndexes.size(); ++k) {
- QModelIndex pi = newPersistentIndexes.at(k);
- int oldPersistentRow = pi.row();
- int newPersistentRow = oldPersistentRow;
- if (oldPersistentRow == oldRow)
- newPersistentRow = newRow;
- else if (oldRow < oldPersistentRow && newRow >= oldPersistentRow)
- newPersistentRow = oldPersistentRow - 1;
- else if (oldRow > oldPersistentRow && newRow <= oldPersistentRow)
- newPersistentRow = oldPersistentRow + 1;
- if (newPersistentRow != oldPersistentRow)
- newPersistentIndexes[k] = createIndex(newPersistentRow,
- pi.column(), pi.internalPointer());
- }
- }
- }
+ const auto compareGt = [](const QListWidgetItem *left, const QListWidgetItem *right) -> bool {
+ return *right < *left;
+ };
- if (changed) {
- items = tmp;
- changePersistentIndexList(oldPersistentIndexes, newPersistentIndexes);
- emit layoutChanged({}, QAbstractItemModel::VerticalSortHint);
- }
+ /** Check if range [start,end] is already in sorted position in list.
+ * Take for this the assumption, that outside [start,end] the list
+ * is already sorted. Therefore the sorted check has to be extended
+ * to the first element that is known to be sorted before the range
+ * [start, end], which is (start-1) and the first element after the
+ * range [start, end], which is (end+2) due to end being included.
+ */
+ const auto beginChangedIterator = items.constBegin() + qMax(start - 1, 0);
+ const auto endChangedIterator = items.constBegin() + qMin(end + 2, items.size());
+ const bool needsSorting = !std::is_sorted(beginChangedIterator, endChangedIterator,
+ order == Qt::AscendingOrder ? compareLt : compareGt);
+
+ if (needsSorting)
+ sort(column, order);
}
bool QListModel::itemLessThan(const QPair<QListWidgetItem*,int> &left,
@@ -1126,57 +1083,71 @@ void QListWidgetPrivate::setup()
Q_Q(QListWidget);
q->QListView::setModel(new QListModel(q));
// view signals
- QObject::connect(q, SIGNAL(pressed(QModelIndex)), q, SLOT(_q_emitItemPressed(QModelIndex)));
- QObject::connect(q, SIGNAL(clicked(QModelIndex)), q, SLOT(_q_emitItemClicked(QModelIndex)));
- QObject::connect(q, SIGNAL(doubleClicked(QModelIndex)),
- q, SLOT(_q_emitItemDoubleClicked(QModelIndex)));
- QObject::connect(q, SIGNAL(activated(QModelIndex)),
- q, SLOT(_q_emitItemActivated(QModelIndex)));
- QObject::connect(q, SIGNAL(entered(QModelIndex)), q, SLOT(_q_emitItemEntered(QModelIndex)));
- QObject::connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
- q, SLOT(_q_emitItemChanged(QModelIndex)));
- QObject::connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
- q, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
- QObject::connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)), q, SLOT(_q_sort()));
-}
-
-void QListWidgetPrivate::_q_emitItemPressed(const QModelIndex &index)
+ connections = {
+ QObjectPrivate::connect(q, &QListWidget::pressed,
+ this, &QListWidgetPrivate::emitItemPressed),
+ QObjectPrivate::connect(q, &QListWidget::clicked,
+ this, &QListWidgetPrivate::emitItemClicked),
+ QObjectPrivate::connect(q, &QListWidget::doubleClicked,
+ this, &QListWidgetPrivate::emitItemDoubleClicked),
+ QObjectPrivate::connect(q, &QListWidget::activated,
+ this, &QListWidgetPrivate::emitItemActivated),
+ QObjectPrivate::connect(q, &QListWidget::entered,
+ this, &QListWidgetPrivate::emitItemEntered),
+ QObjectPrivate::connect(model, &QAbstractItemModel::dataChanged,
+ this, &QListWidgetPrivate::emitItemChanged),
+ QObjectPrivate::connect(model, &QAbstractItemModel::dataChanged,
+ this, &QListWidgetPrivate::dataChanged),
+ QObjectPrivate::connect(model, &QAbstractItemModel::columnsRemoved,
+ this, &QListWidgetPrivate::sort)
+ };
+}
+
+void QListWidgetPrivate::clearConnections()
+{
+ for (const QMetaObject::Connection &connection : connections)
+ QObject::disconnect(connection);
+ for (const QMetaObject::Connection &connection : selectionModelConnections)
+ QObject::disconnect(connection);
+}
+
+void QListWidgetPrivate::emitItemPressed(const QModelIndex &index)
{
Q_Q(QListWidget);
emit q->itemPressed(listModel()->at(index.row()));
}
-void QListWidgetPrivate::_q_emitItemClicked(const QModelIndex &index)
+void QListWidgetPrivate::emitItemClicked(const QModelIndex &index)
{
Q_Q(QListWidget);
emit q->itemClicked(listModel()->at(index.row()));
}
-void QListWidgetPrivate::_q_emitItemDoubleClicked(const QModelIndex &index)
+void QListWidgetPrivate::emitItemDoubleClicked(const QModelIndex &index)
{
Q_Q(QListWidget);
emit q->itemDoubleClicked(listModel()->at(index.row()));
}
-void QListWidgetPrivate::_q_emitItemActivated(const QModelIndex &index)
+void QListWidgetPrivate::emitItemActivated(const QModelIndex &index)
{
Q_Q(QListWidget);
emit q->itemActivated(listModel()->at(index.row()));
}
-void QListWidgetPrivate::_q_emitItemEntered(const QModelIndex &index)
+void QListWidgetPrivate::emitItemEntered(const QModelIndex &index)
{
Q_Q(QListWidget);
emit q->itemEntered(listModel()->at(index.row()));
}
-void QListWidgetPrivate::_q_emitItemChanged(const QModelIndex &index)
+void QListWidgetPrivate::emitItemChanged(const QModelIndex &index)
{
Q_Q(QListWidget);
emit q->itemChanged(listModel()->at(index.row()));
}
-void QListWidgetPrivate::_q_emitCurrentItemChanged(const QModelIndex &current,
+void QListWidgetPrivate::emitCurrentItemChanged(const QModelIndex &current,
const QModelIndex &previous)
{
Q_Q(QListWidget);
@@ -1194,14 +1165,14 @@ void QListWidgetPrivate::_q_emitCurrentItemChanged(const QModelIndex &current,
emit q->currentRowChanged(persistentCurrent.row());
}
-void QListWidgetPrivate::_q_sort()
+void QListWidgetPrivate::sort()
{
if (sortingEnabled)
model->sort(0, sortOrder);
}
-void QListWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft,
- const QModelIndex &bottomRight)
+void QListWidgetPrivate::dataChanged(const QModelIndex &topLeft,
+ const QModelIndex &bottomRight)
{
if (sortingEnabled && topLeft.isValid() && bottomRight.isValid())
listModel()->ensureSorted(topLeft.column(), sortOrder,
@@ -1407,6 +1378,8 @@ QListWidget::QListWidget(QWidget *parent)
QListWidget::~QListWidget()
{
+ Q_D(QListWidget);
+ d->clearConnections();
}
/*!
@@ -1417,20 +1390,18 @@ void QListWidget::setSelectionModel(QItemSelectionModel *selectionModel)
{
Q_D(QListWidget);
- if (d->selectionModel) {
- QObject::disconnect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
- this, SLOT(_q_emitCurrentItemChanged(QModelIndex,QModelIndex)));
- QObject::disconnect(d->selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
- this, SIGNAL(itemSelectionChanged()));
- }
+ for (const QMetaObject::Connection &connection : d->selectionModelConnections)
+ disconnect(connection);
QListView::setSelectionModel(selectionModel);
if (d->selectionModel) {
- QObject::connect(d->selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
- this, SLOT(_q_emitCurrentItemChanged(QModelIndex,QModelIndex)));
- QObject::connect(d->selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
- this, SIGNAL(itemSelectionChanged()));
+ d->selectionModelConnections = {
+ QObjectPrivate::connect(d->selectionModel, &QItemSelectionModel::currentChanged,
+ d, &QListWidgetPrivate::emitCurrentItemChanged),
+ QObject::connect(d->selectionModel, &QItemSelectionModel::selectionChanged,
+ this, &QListWidget::itemSelectionChanged)
+ };
}
}
diff --git a/src/widgets/itemviews/qlistwidget.h b/src/widgets/itemviews/qlistwidget.h
index 516553b71b..c6ba714c43 100644
--- a/src/widgets/itemviews/qlistwidget.h
+++ b/src/widgets/itemviews/qlistwidget.h
@@ -258,16 +258,6 @@ private:
Q_DECLARE_PRIVATE(QListWidget)
Q_DISABLE_COPY(QListWidget)
-
- Q_PRIVATE_SLOT(d_func(), void _q_emitItemPressed(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitItemClicked(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitItemDoubleClicked(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitItemActivated(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitItemEntered(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitItemChanged(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitCurrentItemChanged(const QModelIndex &previous, const QModelIndex &current))
- Q_PRIVATE_SLOT(d_func(), void _q_sort())
- Q_PRIVATE_SLOT(d_func(), void _q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight))
};
inline void QListWidget::removeItemWidget(QListWidgetItem *aItem)
diff --git a/src/widgets/itemviews/qlistwidget_p.h b/src/widgets/itemviews/qlistwidget_p.h
index edcacf0436..1007542ddc 100644
--- a/src/widgets/itemviews/qlistwidget_p.h
+++ b/src/widgets/itemviews/qlistwidget_p.h
@@ -18,10 +18,11 @@
#include <QtCore/qabstractitemmodel.h>
#include <QtWidgets/qabstractitemview.h>
#include <QtWidgets/qlistwidget.h>
-#include <qitemdelegate.h>
#include <private/qlistview_p.h>
#include <private/qwidgetitemdata_p.h>
+#include <array>
+
QT_REQUIRE_CONFIG(listwidget);
QT_BEGIN_NAMESPACE
@@ -113,17 +114,21 @@ public:
QListWidgetPrivate() : QListViewPrivate(), sortOrder(Qt::AscendingOrder), sortingEnabled(false) {}
inline QListModel *listModel() const { return qobject_cast<QListModel*>(model); }
void setup();
- void _q_emitItemPressed(const QModelIndex &index);
- void _q_emitItemClicked(const QModelIndex &index);
- void _q_emitItemDoubleClicked(const QModelIndex &index);
- void _q_emitItemActivated(const QModelIndex &index);
- void _q_emitItemEntered(const QModelIndex &index);
- void _q_emitItemChanged(const QModelIndex &index);
- void _q_emitCurrentItemChanged(const QModelIndex &current, const QModelIndex &previous);
- void _q_sort();
- void _q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
+ void clearConnections();
+ void emitItemPressed(const QModelIndex &index);
+ void emitItemClicked(const QModelIndex &index);
+ void emitItemDoubleClicked(const QModelIndex &index);
+ void emitItemActivated(const QModelIndex &index);
+ void emitItemEntered(const QModelIndex &index);
+ void emitItemChanged(const QModelIndex &index);
+ void emitCurrentItemChanged(const QModelIndex &current, const QModelIndex &previous);
+ void sort();
+ void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
Qt::SortOrder sortOrder;
bool sortingEnabled;
+
+ std::array<QMetaObject::Connection, 8> connections;
+ std::array<QMetaObject::Connection, 2> selectionModelConnections;
};
class QListWidgetItemPrivate
diff --git a/src/widgets/itemviews/qstyleditemdelegate.cpp b/src/widgets/itemviews/qstyleditemdelegate.cpp
index 038b0bdcd0..54c1fb4f52 100644
--- a/src/widgets/itemviews/qstyleditemdelegate.cpp
+++ b/src/widgets/itemviews/qstyleditemdelegate.cpp
@@ -137,12 +137,17 @@ public:
instance provided by QItemEditorFactory is installed on all item
delegates. You can set a custom factory using
setItemEditorFactory() or set a new default factory with
- QItemEditorFactory::setDefaultFactory(). It is the data stored in
- the item model with the \l{Qt::}{EditRole} that is edited. See the
- QItemEditorFactory class for a more high-level introduction to
- item editor factories. The \l{Color Editor Factory Example}{Color
- Editor Factory} example shows how to create custom editors with a
- factory.
+ QItemEditorFactory::setDefaultFactory().
+
+ \snippet code/src_gui_itemviews_qitemeditorfactory.cpp setDefaultFactory
+
+ After the new factory has been set, all standard item delegates
+ will use it (i.e, also delegates that were created before the new
+ default factory was set).
+
+ It is the data stored in the item model with the \l{Qt::}{EditRole}
+ that is edited. See the QItemEditorFactory class for a more
+ high-level introduction to item editor factories.
\section1 Subclassing QStyledItemDelegate
@@ -204,8 +209,7 @@ public:
documentation for details.
\sa {Delegate Classes}, QItemDelegate, QAbstractItemDelegate, QStyle,
- {Spin Box Delegate Example}, {Star Delegate Example}, {Color
- Editor Factory Example}
+ {Star Delegate Example}
*/
@@ -477,15 +481,7 @@ void QStyledItemDelegate::updateEditorGeometry(QWidget *editor,
QStyleOptionViewItem opt = option;
initStyleOption(&opt, index);
- // let the editor take up all available space
- //if the editor is not a QLineEdit
- //or it is in a QTableView
-#if QT_CONFIG(tableview) && QT_CONFIG(lineedit)
- if (qobject_cast<QExpandingLineEdit*>(editor) && !qobject_cast<const QTableView*>(widget))
- opt.showDecorationSelected = editor->style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected, nullptr, editor);
- else
-#endif
- opt.showDecorationSelected = true;
+ opt.showDecorationSelected = editor->style()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected, nullptr, editor);
QStyle *style = widget ? widget->style() : QApplication::style();
QRect geom = style->subElementRect(QStyle::SE_ItemViewItemText, &opt, widget);
diff --git a/src/widgets/itemviews/qtableview.cpp b/src/widgets/itemviews/qtableview.cpp
index cfde93a477..5726348bc5 100644
--- a/src/widgets/itemviews/qtableview.cpp
+++ b/src/widgets/itemviews/qtableview.cpp
@@ -4,7 +4,7 @@
#include "qtableview.h"
#include <qheaderview.h>
-#include <qitemdelegate.h>
+#include <qabstractitemdelegate.h>
#include <qapplication.h>
#include <qpainter.h>
#include <qstyle.h>
@@ -170,6 +170,13 @@ QDebug operator<<(QDebug str, const QSpanCollection::Span &span)
str << '(' << span.top() << ',' << span.left() << ',' << span.bottom() << ',' << span.right() << ')';
return str;
}
+
+QDebug operator<<(QDebug debug, const QSpanCollection::SpanList &spans)
+{
+ for (const auto *span : spans)
+ debug << span << *span;
+ return debug;
+}
#endif
/** \internal
@@ -200,8 +207,7 @@ void QSpanCollection::updateInsertedRows(int start, int end)
#ifdef DEBUG_SPAN_UPDATE
qDebug("After");
- foreach (QSpanCollection::Span *span, spans)
- qDebug() << span << *span;
+ qDebug() << spans;
#endif
for (Index::iterator it_y = index.begin(); it_y != index.end(); ) {
@@ -247,8 +253,7 @@ void QSpanCollection::updateInsertedColumns(int start, int end)
#ifdef DEBUG_SPAN_UPDATE
qDebug("After");
- foreach (QSpanCollection::Span *span, spans)
- qDebug() << span << *span;
+ qDebug() << spans;
#endif
for (Index::iterator it_y = index.begin(); it_y != index.end(); ++it_y) {
@@ -352,8 +357,7 @@ void QSpanCollection::updateRemovedRows(int start, int end)
#ifdef DEBUG_SPAN_UPDATE
qDebug("After");
- foreach (QSpanCollection::Span *span, spans)
- qDebug() << span << *span;
+ qDebug() << spans;
#endif
if (spans.empty()) {
qDeleteAll(spansToBeDeleted);
@@ -420,8 +424,7 @@ void QSpanCollection::updateRemovedRows(int start, int end)
#ifdef DEBUG_SPAN_UPDATE
qDebug() << index;
qDebug("Deleted");
- foreach (QSpanCollection::Span *span, spansToBeDeleted)
- qDebug() << span << *span;
+ qDebug() << spansToBeDeleted;
#endif
qDeleteAll(spansToBeDeleted);
}
@@ -479,8 +482,7 @@ void QSpanCollection::updateRemovedColumns(int start, int end)
#ifdef DEBUG_SPAN_UPDATE
qDebug("After");
- foreach (QSpanCollection::Span *span, spans)
- qDebug() << span << *span;
+ qDebug() << spans;
#endif
if (spans.empty()) {
qDeleteAll(toBeDeleted);
@@ -499,8 +501,7 @@ void QSpanCollection::updateRemovedColumns(int start, int end)
#ifdef DEBUG_SPAN_UPDATE
qDebug() << index;
qDebug("Deleted");
- foreach (QSpanCollection::Span *span, toBeDeleted)
- qDebug() << span << *span;
+ qDebug() << toBeDeleted;
#endif
qDeleteAll(toBeDeleted);
}
@@ -592,7 +593,25 @@ void QTableViewPrivate::init()
#if QT_CONFIG(abstractbutton)
cornerWidget = new QTableCornerButton(q);
cornerWidget->setFocusPolicy(Qt::NoFocus);
- QObject::connect(cornerWidget, SIGNAL(clicked()), q, SLOT(selectAll()));
+ cornerWidgetConnection = QObject::connect(
+ cornerWidget, &QTableCornerButton::clicked,
+ q, &QTableView::selectAll);
+#endif
+}
+
+void QTableViewPrivate::clearConnections()
+{
+ for (const QMetaObject::Connection &connection : modelConnections)
+ QObject::disconnect(connection);
+ for (const QMetaObject::Connection &connection : verHeaderConnections)
+ QObject::disconnect(connection);
+ for (const QMetaObject::Connection &connection : horHeaderConnections)
+ QObject::disconnect(connection);
+ for (const QMetaObject::Connection &connection : dynHorHeaderConnections)
+ QObject::disconnect(connection);
+ QObject::disconnect(selectionmodelConnection);
+#if QT_CONFIG(abstractbutton)
+ QObject::disconnect(cornerWidgetConnection);
#endif
}
@@ -956,7 +975,7 @@ void QTableViewPrivate::drawAndClipSpans(const QRegion &area, QPainter *painter,
\internal
Updates spans after row insertion.
*/
-void QTableViewPrivate::_q_updateSpanInsertedRows(const QModelIndex &parent, int start, int end)
+void QTableViewPrivate::updateSpanInsertedRows(const QModelIndex &parent, int start, int end)
{
Q_UNUSED(parent);
spans.updateInsertedRows(start, end);
@@ -966,7 +985,7 @@ void QTableViewPrivate::_q_updateSpanInsertedRows(const QModelIndex &parent, int
\internal
Updates spans after column insertion.
*/
-void QTableViewPrivate::_q_updateSpanInsertedColumns(const QModelIndex &parent, int start, int end)
+void QTableViewPrivate::updateSpanInsertedColumns(const QModelIndex &parent, int start, int end)
{
Q_UNUSED(parent);
spans.updateInsertedColumns(start, end);
@@ -976,7 +995,7 @@ void QTableViewPrivate::_q_updateSpanInsertedColumns(const QModelIndex &parent,
\internal
Updates spans after row removal.
*/
-void QTableViewPrivate::_q_updateSpanRemovedRows(const QModelIndex &parent, int start, int end)
+void QTableViewPrivate::updateSpanRemovedRows(const QModelIndex &parent, int start, int end)
{
Q_UNUSED(parent);
spans.updateRemovedRows(start, end);
@@ -986,7 +1005,7 @@ void QTableViewPrivate::_q_updateSpanRemovedRows(const QModelIndex &parent, int
\internal
Updates spans after column removal.
*/
-void QTableViewPrivate::_q_updateSpanRemovedColumns(const QModelIndex &parent, int start, int end)
+void QTableViewPrivate::updateSpanRemovedColumns(const QModelIndex &parent, int start, int end)
{
Q_UNUSED(parent);
spans.updateRemovedColumns(start, end);
@@ -996,7 +1015,7 @@ void QTableViewPrivate::_q_updateSpanRemovedColumns(const QModelIndex &parent, i
\internal
Sort the model when the header sort indicator changed
*/
-void QTableViewPrivate::_q_sortIndicatorChanged(int column, Qt::SortOrder order)
+void QTableViewPrivate::sortIndicatorChanged(int column, Qt::SortOrder order)
{
model->sort(column, order);
}
@@ -1188,7 +1207,7 @@ int QTableViewPrivate::heightHintForIndex(const QModelIndex &index, int hint, QS
operations between x-coordinates and column indexes.
\sa QTableWidget, {View Classes}, QAbstractItemModel, QAbstractItemView,
- {Chart Example}, {Pixelator Example}, {Table Model Example}
+ {Table Model Example}
*/
/*!
@@ -1219,6 +1238,8 @@ QTableView::QTableView(QTableViewPrivate &dd, QWidget *parent)
*/
QTableView::~QTableView()
{
+ Q_D(QTableView);
+ d->clearConnections();
}
/*!
@@ -1242,28 +1263,23 @@ void QTableView::setModel(QAbstractItemModel *model)
return;
//let's disconnect from the old model
if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
- disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(_q_updateSpanInsertedRows(QModelIndex,int,int)));
- disconnect(d->model, SIGNAL(columnsInserted(QModelIndex,int,int)),
- this, SLOT(_q_updateSpanInsertedColumns(QModelIndex,int,int)));
- disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_updateSpanRemovedRows(QModelIndex,int,int)));
- disconnect(d->model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_updateSpanRemovedColumns(QModelIndex,int,int)));
+ for (const QMetaObject::Connection &connection : d->modelConnections)
+ disconnect(connection);
}
if (d->selectionModel) { // support row editing
- disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
- d->model, SLOT(submit()));
+ disconnect(d->selectionmodelConnection);
}
if (model) { //and connect to the new one
- connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(_q_updateSpanInsertedRows(QModelIndex,int,int)));
- connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)),
- this, SLOT(_q_updateSpanInsertedColumns(QModelIndex,int,int)));
- connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_updateSpanRemovedRows(QModelIndex,int,int)));
- connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_updateSpanRemovedColumns(QModelIndex,int,int)));
+ d->modelConnections = {
+ QObjectPrivate::connect(model, &QAbstractItemModel::rowsInserted,
+ d, &QTableViewPrivate::updateSpanInsertedRows),
+ QObjectPrivate::connect(model, &QAbstractItemModel::columnsInserted,
+ d, &QTableViewPrivate::updateSpanInsertedColumns),
+ QObjectPrivate::connect(model, &QAbstractItemModel::rowsRemoved,
+ d, &QTableViewPrivate::updateSpanRemovedRows),
+ QObjectPrivate::connect(model, &QAbstractItemModel::columnsRemoved,
+ d, &QTableViewPrivate::updateSpanRemovedColumns)
+ };
}
d->verticalHeader->setModel(model);
d->horizontalHeader->setModel(model);
@@ -1305,8 +1321,7 @@ void QTableView::setSelectionModel(QItemSelectionModel *selectionModel)
Q_ASSERT(selectionModel);
if (d->selectionModel) {
// support row editing
- disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
- d->model, SLOT(submit()));
+ disconnect(d->selectionmodelConnection);
}
d->verticalHeader->setSelectionModel(selectionModel);
@@ -1315,8 +1330,9 @@ void QTableView::setSelectionModel(QItemSelectionModel *selectionModel)
if (d->selectionModel) {
// support row editing
- connect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
- d->model, SLOT(submit()));
+ d->selectionmodelConnection =
+ connect(d->selectionModel, &QItemSelectionModel::currentRowChanged,
+ d->model, &QAbstractItemModel::submit);
}
}
@@ -1353,6 +1369,8 @@ void QTableView::setHorizontalHeader(QHeaderView *header)
if (!header || header == d->horizontalHeader)
return;
+ for (const QMetaObject::Connection &connection : d->horHeaderConnections)
+ disconnect(connection);
if (d->horizontalHeader && d->horizontalHeader->parent() == this)
delete d->horizontalHeader;
d->horizontalHeader = header;
@@ -1364,18 +1382,18 @@ void QTableView::setHorizontalHeader(QHeaderView *header)
d->horizontalHeader->setSelectionModel(d->selectionModel);
}
- connect(d->horizontalHeader,SIGNAL(sectionResized(int,int,int)),
- this, SLOT(columnResized(int,int,int)));
- connect(d->horizontalHeader, SIGNAL(sectionMoved(int,int,int)),
- this, SLOT(columnMoved(int,int,int)));
- connect(d->horizontalHeader, SIGNAL(sectionCountChanged(int,int)),
- this, SLOT(columnCountChanged(int,int)));
- connect(d->horizontalHeader, SIGNAL(sectionPressed(int)), this, SLOT(selectColumn(int)));
- connect(d->horizontalHeader, SIGNAL(sectionEntered(int)), this, SLOT(_q_selectColumn(int)));
- connect(d->horizontalHeader, SIGNAL(sectionHandleDoubleClicked(int)),
- this, SLOT(resizeColumnToContents(int)));
- connect(d->horizontalHeader, SIGNAL(geometriesChanged()), this, SLOT(updateGeometries()));
-
+ d->horHeaderConnections = {
+ connect(d->horizontalHeader,&QHeaderView::sectionResized,
+ this, &QTableView::columnResized),
+ connect(d->horizontalHeader, &QHeaderView::sectionMoved,
+ this, &QTableView::columnMoved),
+ connect(d->horizontalHeader, &QHeaderView::sectionCountChanged,
+ this, &QTableView::columnCountChanged),
+ connect(d->horizontalHeader, &QHeaderView::sectionHandleDoubleClicked,
+ this, &QTableView::resizeColumnToContents),
+ connect(d->horizontalHeader, &QHeaderView::geometriesChanged,
+ this, &QTableView::updateGeometries),
+ };
//update the sorting enabled states on the new header
setSortingEnabled(d->sortingEnabled);
}
@@ -1391,6 +1409,8 @@ void QTableView::setVerticalHeader(QHeaderView *header)
if (!header || header == d->verticalHeader)
return;
+ for (const QMetaObject::Connection &connection : d->verHeaderConnections)
+ disconnect(connection);
if (d->verticalHeader && d->verticalHeader->parent() == this)
delete d->verticalHeader;
d->verticalHeader = header;
@@ -1402,17 +1422,22 @@ void QTableView::setVerticalHeader(QHeaderView *header)
d->verticalHeader->setSelectionModel(d->selectionModel);
}
- connect(d->verticalHeader, SIGNAL(sectionResized(int,int,int)),
- this, SLOT(rowResized(int,int,int)));
- connect(d->verticalHeader, SIGNAL(sectionMoved(int,int,int)),
- this, SLOT(rowMoved(int,int,int)));
- connect(d->verticalHeader, SIGNAL(sectionCountChanged(int,int)),
- this, SLOT(rowCountChanged(int,int)));
- connect(d->verticalHeader, SIGNAL(sectionPressed(int)), this, SLOT(selectRow(int)));
- connect(d->verticalHeader, SIGNAL(sectionEntered(int)), this, SLOT(_q_selectRow(int)));
- connect(d->verticalHeader, SIGNAL(sectionHandleDoubleClicked(int)),
- this, SLOT(resizeRowToContents(int)));
- connect(d->verticalHeader, SIGNAL(geometriesChanged()), this, SLOT(updateGeometries()));
+ d->verHeaderConnections = {
+ connect(d->verticalHeader, &QHeaderView::sectionResized,
+ this, &QTableView::rowResized),
+ connect(d->verticalHeader, &QHeaderView::sectionMoved,
+ this, &QTableView::rowMoved),
+ connect(d->verticalHeader, &QHeaderView::sectionCountChanged,
+ this, &QTableView::rowCountChanged),
+ connect(d->verticalHeader, &QHeaderView::sectionPressed,
+ this, &QTableView::selectRow),
+ connect(d->verticalHeader, &QHeaderView::sectionHandleDoubleClicked,
+ this, &QTableView::resizeRowToContents),
+ connect(d->verticalHeader, &QHeaderView::geometriesChanged,
+ this, &QTableView::updateGeometries),
+ connect(d->verticalHeader, &QHeaderView::sectionEntered,
+ this, [d](int row) { d->selectRow(row, false); })
+ };
}
/*!
@@ -2407,12 +2432,12 @@ int QTableView::sizeHintForRow(int row) const
break;
}
- int actualRight = d->model->columnCount(d->root) - 1;
+ const int actualRight = d->model->columnCount(d->root) - 1;
int idxLeft = left;
int idxRight = column - 1;
- if (maximumProcessCols == 0)
- columnsProcessed = 0; // skip the while loop
+ if (maximumProcessCols == 0 || actualRight < idxLeft)
+ columnsProcessed = maximumProcessCols; // skip the while loop
while (columnsProcessed != maximumProcessCols && (idxLeft > 0 || idxRight < actualRight)) {
int logicalIdx = -1;
@@ -2436,11 +2461,10 @@ int QTableView::sizeHintForRow(int row) const
break;
}
}
- if (logicalIdx < 0)
- continue;
-
- index = d->model->index(row, logicalIdx, d->root);
- hint = d->heightHintForIndex(index, hint, option);
+ if (logicalIdx >= 0) {
+ index = d->model->index(row, logicalIdx, d->root);
+ hint = d->heightHintForIndex(index, hint, option);
+ }
++columnsProcessed;
}
@@ -2496,12 +2520,12 @@ int QTableView::sizeHintForColumn(int column) const
break;
}
- int actualBottom = d->model->rowCount(d->root) - 1;
+ const int actualBottom = d->model->rowCount(d->root) - 1;
int idxTop = top;
int idxBottom = row - 1;
- if (maximumProcessRows == 0)
- rowsProcessed = 0; // skip the while loop
+ if (maximumProcessRows == 0 || actualBottom < idxTop)
+ rowsProcessed = maximumProcessRows; // skip the while loop
while (rowsProcessed != maximumProcessRows && (idxTop > 0 || idxBottom < actualBottom)) {
int logicalIdx = -1;
@@ -2525,11 +2549,10 @@ int QTableView::sizeHintForColumn(int column) const
break;
}
}
- if (logicalIdx < 0)
- continue;
-
- index = d->model->index(logicalIdx, column, d->root);
- hint = d->widthHintForIndex(index, hint, option);
+ if (logicalIdx >= 0) {
+ index = d->model->index(logicalIdx, column, d->root);
+ hint = d->widthHintForIndex(index, hint, option);
+ }
++rowsProcessed;
}
@@ -2704,24 +2727,25 @@ void QTableView::setSortingEnabled(bool enable)
{
Q_D(QTableView);
horizontalHeader()->setSortIndicatorShown(enable);
+ for (const QMetaObject::Connection &connection : d->dynHorHeaderConnections)
+ disconnect(connection);
+ d->dynHorHeaderConnections.clear();
if (enable) {
- disconnect(d->horizontalHeader, SIGNAL(sectionEntered(int)),
- this, SLOT(_q_selectColumn(int)));
- disconnect(horizontalHeader(), SIGNAL(sectionPressed(int)),
- this, SLOT(selectColumn(int)));
//sortByColumn has to be called before we connect or set the sortingEnabled flag
// because otherwise it will not call sort on the model.
- sortByColumn(horizontalHeader()->sortIndicatorSection(),
- horizontalHeader()->sortIndicatorOrder());
- connect(horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
- this, SLOT(_q_sortIndicatorChanged(int,Qt::SortOrder)), Qt::UniqueConnection);
+ sortByColumn(d->horizontalHeader->sortIndicatorSection(),
+ d->horizontalHeader->sortIndicatorOrder());
+ d->dynHorHeaderConnections = {
+ QObjectPrivate::connect(d->horizontalHeader, &QHeaderView::sortIndicatorChanged,
+ d, &QTableViewPrivate::sortIndicatorChanged)
+ };
} else {
- connect(d->horizontalHeader, SIGNAL(sectionEntered(int)),
- this, SLOT(_q_selectColumn(int)), Qt::UniqueConnection);
- connect(horizontalHeader(), SIGNAL(sectionPressed(int)),
- this, SLOT(selectColumn(int)), Qt::UniqueConnection);
- disconnect(horizontalHeader(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
- this, SLOT(_q_sortIndicatorChanged(int,Qt::SortOrder)));
+ d->dynHorHeaderConnections = {
+ connect(d->horizontalHeader, &QHeaderView::sectionPressed,
+ this, &QTableView::selectColumn),
+ connect(d->horizontalHeader, &QHeaderView::sectionEntered,
+ this, [d](int column) {d->selectColumn(column, false); })
+ };
}
d->sortingEnabled = enable;
}
@@ -3381,16 +3405,6 @@ void QTableView::clearSpans()
d->viewport->update();
}
-void QTableViewPrivate::_q_selectRow(int row)
-{
- selectRow(row, false);
-}
-
-void QTableViewPrivate::_q_selectColumn(int column)
-{
- selectColumn(column, false);
-}
-
void QTableViewPrivate::selectRow(int row, bool anchor)
{
Q_Q(QTableView);
@@ -3478,7 +3492,7 @@ void QTableView::currentChanged(const QModelIndex &current, const QModelIndex &p
{
#if QT_CONFIG(accessibility)
if (QAccessible::isActive()) {
- if (current.isValid()) {
+ if (current.isValid() && hasFocus()) {
Q_D(QTableView);
int entry = d->accessibleTable2Index(current);
QAccessibleEvent event(this, QAccessible::Focus);
diff --git a/src/widgets/itemviews/qtableview.h b/src/widgets/itemviews/qtableview.h
index 955b29995c..eff0ea3502 100644
--- a/src/widgets/itemviews/qtableview.h
+++ b/src/widgets/itemviews/qtableview.h
@@ -145,13 +145,6 @@ private:
Q_DECLARE_PRIVATE(QTableView)
Q_DISABLE_COPY(QTableView)
- Q_PRIVATE_SLOT(d_func(), void _q_selectRow(int))
- Q_PRIVATE_SLOT(d_func(), void _q_selectColumn(int))
- Q_PRIVATE_SLOT(d_func(), void _q_updateSpanInsertedRows(QModelIndex,int,int))
- Q_PRIVATE_SLOT(d_func(), void _q_updateSpanInsertedColumns(QModelIndex,int,int))
- Q_PRIVATE_SLOT(d_func(), void _q_updateSpanRemovedRows(QModelIndex,int,int))
- Q_PRIVATE_SLOT(d_func(), void _q_updateSpanRemovedColumns(QModelIndex,int,int))
- Q_PRIVATE_SLOT(d_func(), void _q_sortIndicatorChanged(int column, Qt::SortOrder order))
};
QT_END_NAMESPACE
diff --git a/src/widgets/itemviews/qtableview_p.h b/src/widgets/itemviews/qtableview_p.h
index 582330c7b5..862a016d5f 100644
--- a/src/widgets/itemviews/qtableview_p.h
+++ b/src/widgets/itemviews/qtableview_p.h
@@ -16,13 +16,18 @@
//
#include <QtWidgets/private/qtwidgetsglobal_p.h>
+#include "qtableview.h"
+#include "qheaderview.h"
+
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QSet>
#include <QtCore/QDebug>
#include "private/qabstractitemview_p.h"
+#include <array>
#include <list>
+#include <vector>
QT_REQUIRE_CONFIG(tableview);
@@ -93,7 +98,9 @@ private:
Q_DECLARE_TYPEINFO ( QSpanCollection::Span, Q_RELOCATABLE_TYPE);
-
+#if QT_CONFIG(abstractbutton)
+class QTableCornerButton;
+#endif
class Q_AUTOTEST_EXPORT QTableViewPrivate : public QAbstractItemViewPrivate
{
Q_DECLARE_PUBLIC(QTableView)
@@ -111,6 +118,7 @@ public:
#endif
}
void init();
+ void clearConnections();
void trimHiddenSelections(QItemSelectionRange *range) const;
QRect intersectedRect(const QRect rect, const QModelIndex &topLeft, const QModelIndex &bottomRight) const override;
@@ -156,8 +164,15 @@ public:
QHeaderView *horizontalHeader;
QHeaderView *verticalHeader;
#if QT_CONFIG(abstractbutton)
- QWidget *cornerWidget;
+ QTableCornerButton *cornerWidget;
+ QMetaObject::Connection cornerWidgetConnection;
#endif
+ QMetaObject::Connection selectionmodelConnection;
+ std::array<QMetaObject::Connection, 4> modelConnections;
+ std::array<QMetaObject::Connection, 7> verHeaderConnections;
+ std::array<QMetaObject::Connection, 5> horHeaderConnections;
+ std::vector<QMetaObject::Connection> dynHorHeaderConnections;
+
bool sortingEnabled;
bool geometryRecursionBlock;
QPoint visualCursor; // (Row,column) cell coordinates to track through span navigation.
@@ -210,17 +225,14 @@ public:
QRect visualSpanRect(const QSpanCollection::Span &span) const;
- void _q_selectRow(int row);
- void _q_selectColumn(int column);
-
void selectRow(int row, bool anchor);
void selectColumn(int column, bool anchor);
- void _q_updateSpanInsertedRows(const QModelIndex &parent, int start, int end);
- void _q_updateSpanInsertedColumns(const QModelIndex &parent, int start, int end);
- void _q_updateSpanRemovedRows(const QModelIndex &parent, int start, int end);
- void _q_updateSpanRemovedColumns(const QModelIndex &parent, int start, int end);
- void _q_sortIndicatorChanged(int column, Qt::SortOrder order);
+ void updateSpanInsertedRows(const QModelIndex &parent, int start, int end);
+ void updateSpanInsertedColumns(const QModelIndex &parent, int start, int end);
+ void updateSpanRemovedRows(const QModelIndex &parent, int start, int end);
+ void updateSpanRemovedColumns(const QModelIndex &parent, int start, int end);
+ void sortIndicatorChanged(int column, Qt::SortOrder order);
};
QT_END_NAMESPACE
diff --git a/src/widgets/itemviews/qtablewidget.cpp b/src/widgets/itemviews/qtablewidget.cpp
index 67886be94f..6dd812f6fb 100644
--- a/src/widgets/itemviews/qtablewidget.cpp
+++ b/src/widgets/itemviews/qtablewidget.cpp
@@ -3,7 +3,6 @@
#include "qtablewidget.h"
-#include <qitemdelegate.h>
#include <qpainter.h>
#include <private/qtablewidget_p.h>
@@ -248,7 +247,7 @@ void QTableModel::setHorizontalHeaderItem(int section, QTableWidgetItem *item)
if (item) {
item->view = view;
- item->itemFlags = Qt::ItemFlags(int(item->itemFlags)|ItemIsHeaderItem);
+ item->d->headerItem = true;
}
horizontalHeaderItems[section] = item;
emit headerDataChanged(Qt::Horizontal, section, section);
@@ -270,7 +269,7 @@ void QTableModel::setVerticalHeaderItem(int section, QTableWidgetItem *item)
if (item) {
item->view = view;
- item->itemFlags = Qt::ItemFlags(int(item->itemFlags)|ItemIsHeaderItem);
+ item->d->headerItem = true;
}
verticalHeaderItems[section] = item;
emit headerDataChanged(Qt::Vertical, section, section);
@@ -283,7 +282,7 @@ QTableWidgetItem *QTableModel::takeHorizontalHeaderItem(int section)
QTableWidgetItem *itm = horizontalHeaderItems.at(section);
if (itm) {
itm->view = nullptr;
- itm->itemFlags &= ~ItemIsHeaderItem;
+ itm->d->headerItem = false;
horizontalHeaderItems[section] = 0;
}
return itm;
@@ -296,7 +295,7 @@ QTableWidgetItem *QTableModel::takeVerticalHeaderItem(int section)
QTableWidgetItem *itm = verticalHeaderItems.at(section);
if (itm) {
itm->view = nullptr;
- itm->itemFlags &= ~ItemIsHeaderItem;
+ itm->d->headerItem = false;
verticalHeaderItems[section] = 0;
}
return itm;
@@ -761,7 +760,7 @@ void QTableModel::itemChanged(QTableWidgetItem *item, const QList<int> &roles)
{
if (!item)
return;
- if (item->flags() & ItemIsHeaderItem) {
+ if (item->d->headerItem) {
int row = verticalHeaderItems.indexOf(item);
if (row >= 0) {
emit headerDataChanged(Qt::Vertical, row, row);
@@ -1592,28 +1591,41 @@ QTableWidgetItem &QTableWidgetItem::operator=(const QTableWidgetItem &other)
void QTableWidgetPrivate::setup()
{
Q_Q(QTableWidget);
- // view signals
- QObject::connect(q, SIGNAL(pressed(QModelIndex)), q, SLOT(_q_emitItemPressed(QModelIndex)));
- QObject::connect(q, SIGNAL(clicked(QModelIndex)), q, SLOT(_q_emitItemClicked(QModelIndex)));
- QObject::connect(q, SIGNAL(doubleClicked(QModelIndex)),
- q, SLOT(_q_emitItemDoubleClicked(QModelIndex)));
- QObject::connect(q, SIGNAL(activated(QModelIndex)), q, SLOT(_q_emitItemActivated(QModelIndex)));
- QObject::connect(q, SIGNAL(entered(QModelIndex)), q, SLOT(_q_emitItemEntered(QModelIndex)));
- // model signals
- QObject::connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
- q, SLOT(_q_emitItemChanged(QModelIndex)));
- // selection signals
- QObject::connect(q->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
- q, SLOT(_q_emitCurrentItemChanged(QModelIndex,QModelIndex)));
- QObject::connect(q->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
- q, SIGNAL(itemSelectionChanged()));
- // sorting
- QObject::connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
- q, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
- QObject::connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)), q, SLOT(_q_sort()));
-}
-
-void QTableWidgetPrivate::_q_emitItemPressed(const QModelIndex &index)
+ connections = {
+ // view signals
+ QObjectPrivate::connect(q, &QTableWidget::pressed,
+ this, &QTableWidgetPrivate::emitItemPressed),
+ QObjectPrivate::connect(q, &QTableWidget::clicked,
+ this, &QTableWidgetPrivate::emitItemClicked),
+ QObjectPrivate::connect(q, &QTableWidget::doubleClicked,
+ this, &QTableWidgetPrivate::emitItemDoubleClicked),
+ QObjectPrivate::connect(q, &QTableWidget::activated,
+ this, &QTableWidgetPrivate::emitItemActivated),
+ QObjectPrivate::connect(q, &QTableWidget::entered,
+ this, &QTableWidgetPrivate::emitItemEntered),
+ // model signals
+ QObjectPrivate::connect(model, &QAbstractItemModel::dataChanged,
+ this, &QTableWidgetPrivate::emitItemChanged),
+ // selection signals
+ QObjectPrivate::connect(q->selectionModel(), &QItemSelectionModel::currentChanged,
+ this, &QTableWidgetPrivate::emitCurrentItemChanged),
+ QObject::connect(q->selectionModel(), &QItemSelectionModel::selectionChanged,
+ q, &QTableWidget::itemSelectionChanged),
+ // sorting
+ QObjectPrivate::connect(model, &QAbstractItemModel::dataChanged,
+ this, &QTableWidgetPrivate::dataChanged),
+ QObjectPrivate::connect(model, &QAbstractItemModel::columnsRemoved,
+ this, &QTableWidgetPrivate::sort)
+ };
+}
+
+void QTableWidgetPrivate::clearConnections()
+{
+ for (const QMetaObject::Connection &connection : connections)
+ QObject::disconnect(connection);
+}
+
+void QTableWidgetPrivate::emitItemPressed(const QModelIndex &index)
{
Q_Q(QTableWidget);
if (QTableWidgetItem *item = tableModel()->item(index))
@@ -1621,7 +1633,7 @@ void QTableWidgetPrivate::_q_emitItemPressed(const QModelIndex &index)
emit q->cellPressed(index.row(), index.column());
}
-void QTableWidgetPrivate::_q_emitItemClicked(const QModelIndex &index)
+void QTableWidgetPrivate::emitItemClicked(const QModelIndex &index)
{
Q_Q(QTableWidget);
if (QTableWidgetItem *item = tableModel()->item(index))
@@ -1629,7 +1641,7 @@ void QTableWidgetPrivate::_q_emitItemClicked(const QModelIndex &index)
emit q->cellClicked(index.row(), index.column());
}
-void QTableWidgetPrivate::_q_emitItemDoubleClicked(const QModelIndex &index)
+void QTableWidgetPrivate::emitItemDoubleClicked(const QModelIndex &index)
{
Q_Q(QTableWidget);
if (QTableWidgetItem *item = tableModel()->item(index))
@@ -1637,7 +1649,7 @@ void QTableWidgetPrivate::_q_emitItemDoubleClicked(const QModelIndex &index)
emit q->cellDoubleClicked(index.row(), index.column());
}
-void QTableWidgetPrivate::_q_emitItemActivated(const QModelIndex &index)
+void QTableWidgetPrivate::emitItemActivated(const QModelIndex &index)
{
Q_Q(QTableWidget);
if (QTableWidgetItem *item = tableModel()->item(index))
@@ -1645,7 +1657,7 @@ void QTableWidgetPrivate::_q_emitItemActivated(const QModelIndex &index)
emit q->cellActivated(index.row(), index.column());
}
-void QTableWidgetPrivate::_q_emitItemEntered(const QModelIndex &index)
+void QTableWidgetPrivate::emitItemEntered(const QModelIndex &index)
{
Q_Q(QTableWidget);
if (QTableWidgetItem *item = tableModel()->item(index))
@@ -1653,7 +1665,7 @@ void QTableWidgetPrivate::_q_emitItemEntered(const QModelIndex &index)
emit q->cellEntered(index.row(), index.column());
}
-void QTableWidgetPrivate::_q_emitItemChanged(const QModelIndex &index)
+void QTableWidgetPrivate::emitItemChanged(const QModelIndex &index)
{
Q_Q(QTableWidget);
if (QTableWidgetItem *item = tableModel()->item(index))
@@ -1661,7 +1673,7 @@ void QTableWidgetPrivate::_q_emitItemChanged(const QModelIndex &index)
emit q->cellChanged(index.row(), index.column());
}
-void QTableWidgetPrivate::_q_emitCurrentItemChanged(const QModelIndex &current,
+void QTableWidgetPrivate::emitCurrentItemChanged(const QModelIndex &current,
const QModelIndex &previous)
{
Q_Q(QTableWidget);
@@ -1672,7 +1684,7 @@ void QTableWidgetPrivate::_q_emitCurrentItemChanged(const QModelIndex &current,
emit q->currentCellChanged(current.row(), current.column(), previous.row(), previous.column());
}
-void QTableWidgetPrivate::_q_sort()
+void QTableWidgetPrivate::sort()
{
if (sortingEnabled) {
int column = horizontalHeader->sortIndicatorSection();
@@ -1681,8 +1693,8 @@ void QTableWidgetPrivate::_q_sort()
}
}
-void QTableWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft,
- const QModelIndex &bottomRight)
+void QTableWidgetPrivate::dataChanged(const QModelIndex &topLeft,
+ const QModelIndex &bottomRight)
{
if (sortingEnabled && topLeft.isValid() && bottomRight.isValid()) {
int column = horizontalHeader->sortIndicatorSection();
@@ -1880,6 +1892,8 @@ QTableWidget::QTableWidget(int rows, int columns, QWidget *parent)
*/
QTableWidget::~QTableWidget()
{
+ Q_D(QTableWidget);
+ d->clearConnections();
}
/*!
diff --git a/src/widgets/itemviews/qtablewidget.h b/src/widgets/itemviews/qtablewidget.h
index c7545f13dd..303f4d5f5b 100644
--- a/src/widgets/itemviews/qtablewidget.h
+++ b/src/widgets/itemviews/qtablewidget.h
@@ -23,8 +23,10 @@ public:
friend bool operator==(const QTableWidgetSelectionRange &lhs,
const QTableWidgetSelectionRange &rhs) noexcept
- { return lhs.m_top == rhs.m_top && lhs.m_left == rhs.m_left
- && lhs.m_bottom == rhs.m_bottom && lhs.m_right == rhs.m_right; };
+ {
+ return lhs.m_top == rhs.m_top && lhs.m_left == rhs.m_left && lhs.m_bottom == rhs.m_bottom
+ && lhs.m_right == rhs.m_right;
+ }
friend bool operator!=(const QTableWidgetSelectionRange &lhs,
const QTableWidgetSelectionRange &rhs) noexcept
{ return !(lhs == rhs); }
@@ -310,16 +312,6 @@ private:
Q_DECLARE_PRIVATE(QTableWidget)
Q_DISABLE_COPY(QTableWidget)
-
- Q_PRIVATE_SLOT(d_func(), void _q_emitItemPressed(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitItemClicked(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitItemDoubleClicked(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitItemActivated(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitItemEntered(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitItemChanged(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitCurrentItemChanged(const QModelIndex &previous, const QModelIndex &current))
- Q_PRIVATE_SLOT(d_func(), void _q_sort())
- Q_PRIVATE_SLOT(d_func(), void _q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight))
};
inline void QTableWidget::removeCellWidget(int arow, int acolumn)
diff --git a/src/widgets/itemviews/qtablewidget_p.h b/src/widgets/itemviews/qtablewidget_p.h
index 1d893224c0..210910fc52 100644
--- a/src/widgets/itemviews/qtablewidget_p.h
+++ b/src/widgets/itemviews/qtablewidget_p.h
@@ -22,6 +22,8 @@
#include <private/qtableview_p.h>
#include <private/qwidgetitemdata_p.h>
+#include <array>
+
QT_REQUIRE_CONFIG(tablewidget);
QT_BEGIN_NAMESPACE
@@ -53,10 +55,6 @@ class QTableModel : public QAbstractTableModel
friend class QTableWidget;
public:
- enum ItemFlagsExtension {
- ItemIsHeaderItem = 128
- }; // we need this to separate header items from other items
-
QTableModel(int rows, int columns, QTableWidget *parent);
~QTableModel();
@@ -154,28 +152,32 @@ public:
QTableWidgetPrivate() : QTableViewPrivate() {}
inline QTableModel *tableModel() const { return qobject_cast<QTableModel*>(model); }
void setup();
+ void clearConnections();
// view signals
- void _q_emitItemPressed(const QModelIndex &index);
- void _q_emitItemClicked(const QModelIndex &index);
- void _q_emitItemDoubleClicked(const QModelIndex &index);
- void _q_emitItemActivated(const QModelIndex &index);
- void _q_emitItemEntered(const QModelIndex &index);
+ void emitItemPressed(const QModelIndex &index);
+ void emitItemClicked(const QModelIndex &index);
+ void emitItemDoubleClicked(const QModelIndex &index);
+ void emitItemActivated(const QModelIndex &index);
+ void emitItemEntered(const QModelIndex &index);
// model signals
- void _q_emitItemChanged(const QModelIndex &index);
+ void emitItemChanged(const QModelIndex &index);
// selection signals
- void _q_emitCurrentItemChanged(const QModelIndex &previous, const QModelIndex &current);
+ void emitCurrentItemChanged(const QModelIndex &previous, const QModelIndex &current);
// sorting
- void _q_sort();
- void _q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
+ void sort();
+ void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
+
+ std::array<QMetaObject::Connection, 10> connections;
};
class QTableWidgetItemPrivate
{
public:
- QTableWidgetItemPrivate(QTableWidgetItem *item) : q(item), id(-1) {}
+ QTableWidgetItemPrivate(QTableWidgetItem *item) : q(item), id(-1), headerItem(false) {}
QTableWidgetItem *q;
int id;
+ bool headerItem; // Qt 7 TODO: inline this stuff in the public class.
};
QT_END_NAMESPACE
diff --git a/src/widgets/itemviews/qtreeview.cpp b/src/widgets/itemviews/qtreeview.cpp
index 2280cdaa2e..744f29ca17 100644
--- a/src/widgets/itemviews/qtreeview.cpp
+++ b/src/widgets/itemviews/qtreeview.cpp
@@ -3,7 +3,7 @@
#include "qtreeview.h"
#include <qheaderview.h>
-#include <qitemdelegate.h>
+#include <qabstractitemdelegate.h>
#include <qapplication.h>
#include <qscrollbar.h>
#include <qpainter.h>
@@ -124,8 +124,7 @@ QT_BEGIN_NAMESPACE
that can be taken for views that are intended to display items with equal heights
is to set the \l uniformRowHeights property to true.
- \sa QListView, QTreeWidget, {View Classes}, QAbstractItemModel, QAbstractItemView,
- {Dir View Example}
+ \sa QListView, QTreeWidget, {View Classes}, QAbstractItemModel, QAbstractItemView
*/
@@ -170,6 +169,8 @@ QTreeView::QTreeView(QTreeViewPrivate &dd, QWidget *parent)
*/
QTreeView::~QTreeView()
{
+ Q_D(QTreeView);
+ d->clearConnections();
}
/*!
@@ -181,18 +182,12 @@ void QTreeView::setModel(QAbstractItemModel *model)
if (model == d->model)
return;
if (d->model && d->model != QAbstractItemModelPrivate::staticEmptyModel()) {
- disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(rowsRemoved(QModelIndex,int,int)));
-
- disconnect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_modelAboutToBeReset()));
+ for (const QMetaObject::Connection &connection : d->modelConnections)
+ QObject::disconnect(connection);
}
if (d->selectionModel) { // support row editing
- disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
- d->model, SLOT(submit()));
- disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(rowsRemoved(QModelIndex,int,int)));
- disconnect(d->model, SIGNAL(modelAboutToBeReset()), this, SLOT(_q_modelAboutToBeReset()));
+ QObject::disconnect(d->selectionmodelConnection);
}
d->viewItems.clear();
d->expandedIndexes.clear();
@@ -202,20 +197,24 @@ void QTreeView::setModel(QAbstractItemModel *model)
d->geometryRecursionBlock = false;
QAbstractItemView::setModel(model);
- // QAbstractItemView connects to a private slot
- disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
- // do header layout after the tree
- disconnect(d->model, SIGNAL(layoutChanged()),
- d->header, SLOT(_q_layoutChanged()));
- // QTreeView has a public slot for this
- connect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(rowsRemoved(QModelIndex,int,int)));
-
- connect(d->model, SIGNAL(modelAboutToBeReset()), SLOT(_q_modelAboutToBeReset()));
-
+ if (d->model) {
+ // QAbstractItemView connects to a private slot
+ QObjectPrivate::disconnect(d->model, &QAbstractItemModel::rowsRemoved,
+ d, &QAbstractItemViewPrivate::rowsRemoved);
+ // do header layout after the tree
+ QObjectPrivate::disconnect(d->model, &QAbstractItemModel::layoutChanged,
+ d->header->d_func(), &QAbstractItemViewPrivate::layoutChanged);
+
+ d->modelConnections = {
+ // QTreeView has a public slot for this
+ QObject::connect(d->model, &QAbstractItemModel::rowsRemoved,
+ this, &QTreeView::rowsRemoved),
+ QObjectPrivate::connect(d->model, &QAbstractItemModel::modelAboutToBeReset,
+ d, &QTreeViewPrivate::modelAboutToBeReset)
+ };
+ }
if (d->sortingEnabled)
- d->_q_sortIndicatorChanged(header()->sortIndicatorSection(), header()->sortIndicatorOrder());
+ d->sortIndicatorChanged(header()->sortIndicatorSection(), header()->sortIndicatorOrder());
}
/*!
@@ -237,8 +236,7 @@ void QTreeView::setSelectionModel(QItemSelectionModel *selectionModel)
Q_ASSERT(selectionModel);
if (d->selectionModel) {
// support row editing
- disconnect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
- d->model, SLOT(submit()));
+ QObject::disconnect(d->selectionmodelConnection);
}
d->header->setSelectionModel(selectionModel);
@@ -246,8 +244,9 @@ void QTreeView::setSelectionModel(QItemSelectionModel *selectionModel)
if (d->selectionModel) {
// support row editing
- connect(d->selectionModel, SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
- d->model, SLOT(submit()));
+ d->selectionmodelConnection =
+ connect(d->selectionModel, &QItemSelectionModel::currentRowChanged,
+ d->model, &QAbstractItemModel::submit);
}
}
@@ -287,16 +286,18 @@ void QTreeView::setHeader(QHeaderView *header)
d->header->setSelectionModel(d->selectionModel);
}
- connect(d->header, SIGNAL(sectionResized(int,int,int)),
- this, SLOT(columnResized(int,int,int)));
- connect(d->header, SIGNAL(sectionMoved(int,int,int)),
- this, SLOT(columnMoved()));
- connect(d->header, SIGNAL(sectionCountChanged(int,int)),
- this, SLOT(columnCountChanged(int,int)));
- connect(d->header, SIGNAL(sectionHandleDoubleClicked(int)),
- this, SLOT(resizeColumnToContents(int)));
- connect(d->header, SIGNAL(geometriesChanged()),
- this, SLOT(updateGeometries()));
+ d->headerConnections = {
+ connect(d->header, &QHeaderView::sectionResized,
+ this, &QTreeView::columnResized),
+ connect(d->header, &QHeaderView::sectionMoved,
+ this, &QTreeView::columnMoved),
+ connect(d->header, &QHeaderView::sectionCountChanged,
+ this, &QTreeView::columnCountChanged),
+ connect(d->header, &QHeaderView::sectionHandleDoubleClicked,
+ this, &QTreeView::resizeColumnToContents),
+ connect(d->header, &QHeaderView::geometriesChanged,
+ this, &QTreeView::updateGeometries)
+ };
setSortingEnabled(d->sortingEnabled);
d->updateGeometry();
@@ -840,11 +841,12 @@ void QTreeView::setSortingEnabled(bool enable)
//sortByColumn has to be called before we connect or set the sortingEnabled flag
// because otherwise it will not call sort on the model.
sortByColumn(header()->sortIndicatorSection(), header()->sortIndicatorOrder());
- connect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
- this, SLOT(_q_sortIndicatorChanged(int,Qt::SortOrder)), Qt::UniqueConnection);
+ d->sortHeaderConnection =
+ QObjectPrivate::connect(header(), &QHeaderView::sortIndicatorChanged,
+ d, &QTreeViewPrivate::sortIndicatorChanged,
+ Qt::UniqueConnection);
} else {
- disconnect(header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)),
- this, SLOT(_q_sortIndicatorChanged(int,Qt::SortOrder)));
+ QObject::disconnect(d->sortHeaderConnection);
}
d->sortingEnabled = enable;
}
@@ -1068,33 +1070,64 @@ void QTreeView::keyboardSearch(const QString &search)
QRect QTreeView::visualRect(const QModelIndex &index) const
{
Q_D(const QTreeView);
+ return d->visualRect(index, QTreeViewPrivate::SingleSection);
+}
+
+/*!
+ \internal
+ \return the visual rectangle at \param index, according to \param rule.
+ \list
+ \li SingleSection
+ The return value matches the section, which \a index points to.
+ \li FullRow
+ Return the rectangle of the entire row, no matter which section
+ \a index points to.
+ \li AddRowIndicatorToFirstSection
+ Like SingleSection. If \index points to the first section, add the
+ row indicator and its margins.
+ \endlist
+ */
+QRect QTreeViewPrivate::visualRect(const QModelIndex &index, RectRule rule) const
+{
+ Q_Q(const QTreeView);
- if (!d->isIndexValid(index) || isIndexHidden(index))
+ if (!isIndexValid(index))
return QRect();
- d->executePostedLayout();
+ // Calculate the entire row's rectangle, even if one of the elements is hidden
+ if (q->isIndexHidden(index) && rule != FullRow)
+ return QRect();
+
+ executePostedLayout();
- int vi = d->viewIndex(index);
- if (vi < 0)
+ const int viewIndex = this->viewIndex(index);
+ if (viewIndex < 0)
return QRect();
- bool spanning = d->viewItems.at(vi).spanning;
+ const bool spanning = viewItems.at(viewIndex).spanning;
+ const int column = index.column();
// if we have a spanning item, make the selection stretch from left to right
- int x = (spanning ? 0 : columnViewportPosition(index.column()));
- int w = (spanning ? d->header->length() : columnWidth(index.column()));
- // handle indentation
- if (d->isTreePosition(index.column())) {
- int i = d->indentationForItem(vi);
- w -= i;
- if (!isRightToLeft())
- x += i;
+ int x = (spanning ? 0 : q->columnViewportPosition(column));
+ int width = (spanning ? header->length() : q->columnWidth(column));
+
+ const bool addIndentation = isTreePosition(column) && (column > 0 || rule == SingleSection);
+
+ if (rule == FullRow) {
+ x = 0;
+ width = q->viewport()->width();
+ } else if (addIndentation) {
+ // calculate indentation
+ const int indentation = indentationForItem(viewIndex);
+ width -= indentation;
+ if (!q->isRightToLeft())
+ x += indentation;
}
- int y = d->coordinateForItem(vi);
- int h = d->itemHeight(vi);
+ const int y = coordinateForItem(viewIndex);
+ const int height = itemHeight(viewIndex);
- return QRect(x, y, w, h);
+ return QRect(x, y, width, height);
}
/*!
@@ -1277,16 +1310,13 @@ bool QTreeView::viewportEvent(QEvent *event)
case QEvent::HoverLeave:
case QEvent::HoverMove: {
QHoverEvent *he = static_cast<QHoverEvent*>(event);
- int oldBranch = d->hoverBranch;
+ const int oldBranch = d->hoverBranch;
d->hoverBranch = d->itemDecorationAt(he->position().toPoint());
QModelIndex newIndex = indexAt(he->position().toPoint());
if (d->hover != newIndex || d->hoverBranch != oldBranch) {
// Update the whole hovered over row. No need to update the old hovered
// row, that is taken care in superclass hover handling.
- QRect rect = visualRect(newIndex);
- rect.setX(0);
- rect.setWidth(viewport()->width());
- viewport()->update(rect);
+ viewport()->update(d->visualRect(newIndex, QTreeViewPrivate::FullRow));
}
break; }
default:
@@ -1369,18 +1399,16 @@ bool QTreeViewPrivate::expandOrCollapseItemAtPos(const QPoint &pos)
return false;
}
-void QTreeViewPrivate::_q_modelDestroyed()
+void QTreeViewPrivate::modelDestroyed()
{
//we need to clear the viewItems because it contains QModelIndexes to
//the model currently being destroyed
viewItems.clear();
- QAbstractItemViewPrivate::_q_modelDestroyed();
+ QAbstractItemViewPrivate::modelDestroyed();
}
QRect QTreeViewPrivate::intersectedRect(const QRect rect, const QModelIndex &topLeft, const QModelIndex &bottomRight) const
{
- Q_Q(const QTreeView);
-
const auto parentIdx = topLeft.parent();
executePostedLayout();
QRect updateRect;
@@ -1389,7 +1417,7 @@ QRect QTreeViewPrivate::intersectedRect(const QRect rect, const QModelIndex &top
continue;
for (int c = topLeft.column(); c <= bottomRight.column(); ++c) {
const QModelIndex idx(model->index(r, c, parentIdx));
- updateRect |= q->visualRect(idx);
+ updateRect |= visualRect(idx, SingleSection);
}
}
return rect.intersected(updateRect);
@@ -1496,8 +1524,9 @@ void QTreeView::drawTree(QPainter *painter, const QRegion &region) const
// paint the visible rows
for (; i < viewItems.size() && y <= area.bottom(); ++i) {
+ const QModelIndex &index = viewItems.at(i).index;
const int itemHeight = d->itemHeight(i);
- option.rect.setRect(0, y, viewportWidth, itemHeight);
+ option.rect = d->visualRect(index, QTreeViewPrivate::FullRow);
option.state = state | (viewItems.at(i).expanded ? QStyle::State_Open : QStyle::State_None)
| (viewItems.at(i).hasChildren ? QStyle::State_Children : QStyle::State_None)
| (viewItems.at(i).hasMoreSiblings ? QStyle::State_Sibling : QStyle::State_None);
@@ -2116,6 +2145,7 @@ void QTreeView::doItemsLayout()
}
QAbstractItemView::doItemsLayout();
d->header->doItemsLayout();
+ d->updateAccessibility();
}
/*!
@@ -2367,7 +2397,7 @@ QRegion QTreeView::visualRegionForSelection(const QItemSelection &selection) con
}
if (!leftIndex.isValid())
continue;
- const QRect leftRect = visualRect(leftIndex);
+ const QRect leftRect = d->visualRect(leftIndex, QTreeViewPrivate::SingleSection);
int top = leftRect.top();
QModelIndex rightIndex = range.bottomRight();
while (rightIndex.isValid() && isIndexHidden(rightIndex)) {
@@ -2378,7 +2408,7 @@ QRegion QTreeView::visualRegionForSelection(const QItemSelection &selection) con
}
if (!rightIndex.isValid())
continue;
- const QRect rightRect = visualRect(rightIndex);
+ const QRect rightRect = d->visualRect(rightIndex, QTreeViewPrivate::SingleSection);
int bottom = rightRect.bottom();
if (top > bottom)
qSwap<int>(top, bottom);
@@ -2554,7 +2584,7 @@ void QTreeView::rowsRemoved(const QModelIndex &parent, int start, int end)
d->viewItems.clear();
d->doDelayedItemsLayout();
d->hasRemovedItems = true;
- d->_q_rowsRemoved(parent, start, end);
+ d->rowsRemoved(parent, start, end);
}
/*!
@@ -2645,7 +2675,8 @@ QSize QTreeView::viewportSizeHint() const
return QAbstractItemView::viewportSizeHint();
// Get rect for last item
- const QRect deepestRect = visualRect(d->viewItems.last().index);
+ const QRect deepestRect = d->visualRect(d->viewItems.last().index,
+ QTreeViewPrivate::SingleSection);
if (!deepestRect.isValid())
return QAbstractItemView::viewportSizeHint();
@@ -2678,6 +2709,7 @@ void QTreeView::expandAll()
d->layout(-1, true);
updateGeometries();
d->viewport->update();
+ d->updateAccessibility();
}
/*!
@@ -2801,6 +2833,7 @@ void QTreeView::expandToDepth(int depth)
updateGeometries();
d->viewport->update();
+ d->updateAccessibility();
}
/*!
@@ -3061,10 +3094,25 @@ void QTreeViewPrivate::initialize()
q->setHeader(header);
#if QT_CONFIG(animation)
animationsEnabled = q->style()->styleHint(QStyle::SH_Widget_Animation_Duration, nullptr, q) > 0;
- QObject::connect(&animatedOperation, SIGNAL(finished()), q, SLOT(_q_endAnimatedOperation()));
+ animationConnection =
+ QObjectPrivate::connect(&animatedOperation, &QVariantAnimation::finished,
+ this, &QTreeViewPrivate::endAnimatedOperation);
#endif // animation
}
+void QTreeViewPrivate::clearConnections()
+{
+ for (const QMetaObject::Connection &connection : modelConnections)
+ QObject::disconnect(connection);
+ for (const QMetaObject::Connection &connection : headerConnections)
+ QObject::disconnect(connection);
+ QObject::disconnect(selectionmodelConnection);
+ QObject::disconnect(sortHeaderConnection);
+#if QT_CONFIG(animation)
+ QObject::disconnect(animationConnection);
+#endif
+}
+
void QTreeViewPrivate::expand(int item, bool emitSignal)
{
Q_Q(QTreeView);
@@ -3097,6 +3145,7 @@ void QTreeViewPrivate::expand(int item, bool emitSignal)
beginAnimatedOperation();
#endif // animation
}
+ updateAccessibility();
}
void QTreeViewPrivate::insertViewItems(int pos, int count, const QTreeViewItem &viewItem)
@@ -3257,7 +3306,7 @@ QPixmap QTreeViewPrivate::renderTreeToPixmapForAnimation(const QRect &rect) cons
for (QEditorIndexHash::const_iterator it = editorIndexHash.constBegin(); it != editorIndexHash.constEnd(); ++it) {
QWidget *editor = it.key();
const QModelIndex &index = it.value();
- option.rect = q->visualRect(index);
+ option.rect = visualRect(index, SingleSection);
if (option.rect.isValid()) {
if (QAbstractItemDelegate *delegate = q->itemDelegateForIndex(index))
@@ -3277,7 +3326,7 @@ QPixmap QTreeViewPrivate::renderTreeToPixmapForAnimation(const QRect &rect) cons
return pixmap;
}
-void QTreeViewPrivate::_q_endAnimatedOperation()
+void QTreeViewPrivate::endAnimatedOperation()
{
Q_Q(QTreeView);
q->setState(stateBeforeAnimation);
@@ -3286,25 +3335,40 @@ void QTreeViewPrivate::_q_endAnimatedOperation()
}
#endif // animation
-void QTreeViewPrivate::_q_modelAboutToBeReset()
+void QTreeViewPrivate::modelAboutToBeReset()
{
viewItems.clear();
}
-void QTreeViewPrivate::_q_columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
+void QTreeViewPrivate::columnsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
{
if (start <= 0 && 0 <= end)
viewItems.clear();
- QAbstractItemViewPrivate::_q_columnsAboutToBeRemoved(parent, start, end);
+ QAbstractItemViewPrivate::columnsAboutToBeRemoved(parent, start, end);
}
-void QTreeViewPrivate::_q_columnsRemoved(const QModelIndex &parent, int start, int end)
+void QTreeViewPrivate::columnsRemoved(const QModelIndex &parent, int start, int end)
{
if (start <= 0 && 0 <= end)
doDelayedItemsLayout();
- QAbstractItemViewPrivate::_q_columnsRemoved(parent, start, end);
+ QAbstractItemViewPrivate::columnsRemoved(parent, start, end);
}
+void QTreeViewPrivate::updateAccessibility()
+{
+#if QT_CONFIG(accessibility)
+ Q_Q(QTreeView);
+ if (pendingAccessibilityUpdate) {
+ pendingAccessibilityUpdate = false;
+ if (QAccessible::isActive()) {
+ QAccessibleTableModelChangeEvent event(q, QAccessibleTableModelChangeEvent::ModelReset);
+ QAccessible::updateAccessibility(&event);
+ }
+ }
+#endif
+}
+
+
/** \internal
creates and initialize the viewItem structure of the children of the element \li
@@ -3325,6 +3389,15 @@ void QTreeViewPrivate::layout(int i, bool recursiveExpanding, bool afterIsUninit
return;
}
+#if QT_CONFIG(accessibility)
+ // QAccessibleTree's rowCount implementation uses viewItems.size(), so
+ // we need to invalidate any cached accessibility data structures if
+ // that value changes during the run of this function.
+ const auto resetModelIfNeeded = qScopeGuard([oldViewItemsSize = viewItems.size(), this]{
+ pendingAccessibilityUpdate |= oldViewItemsSize != viewItems.size();
+ });
+#endif
+
int count = 0;
if (model->hasChildren(parent)) {
if (model->canFetchMore(parent)) {
@@ -3963,7 +4036,7 @@ bool QTreeViewPrivate::hasVisibleChildren(const QModelIndex& parent) const
return false;
}
-void QTreeViewPrivate::_q_sortIndicatorChanged(int column, Qt::SortOrder order)
+void QTreeViewPrivate::sortIndicatorChanged(int column, Qt::SortOrder order)
{
model->sort(column, order);
}
@@ -3987,24 +4060,17 @@ void QTreeViewPrivate::updateIndentationFromStyle()
*/
void QTreeView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
{
+ Q_D(QTreeView);
QAbstractItemView::currentChanged(current, previous);
if (allColumnsShowFocus()) {
- if (previous.isValid()) {
- QRect previousRect = visualRect(previous);
- previousRect.setX(0);
- previousRect.setWidth(viewport()->width());
- viewport()->update(previousRect);
- }
- if (current.isValid()) {
- QRect currentRect = visualRect(current);
- currentRect.setX(0);
- currentRect.setWidth(viewport()->width());
- viewport()->update(currentRect);
- }
+ if (previous.isValid())
+ viewport()->update(d->visualRect(previous, QTreeViewPrivate::FullRow));
+ if (current.isValid())
+ viewport()->update(d->visualRect(current, QTreeViewPrivate::FullRow));
}
#if QT_CONFIG(accessibility)
- if (QAccessible::isActive() && current.isValid()) {
+ if (QAccessible::isActive() && current.isValid() && hasFocus()) {
Q_D(QTreeView);
QAccessibleEvent event(this, QAccessible::Focus);
diff --git a/src/widgets/itemviews/qtreeview.h b/src/widgets/itemviews/qtreeview.h
index d73ca5e2cd..1dd4650c5d 100644
--- a/src/widgets/itemviews/qtreeview.h
+++ b/src/widgets/itemviews/qtreeview.h
@@ -195,11 +195,6 @@ private:
Q_DECLARE_PRIVATE(QTreeView)
Q_DISABLE_COPY(QTreeView)
-#if QT_CONFIG(animation)
- Q_PRIVATE_SLOT(d_func(), void _q_endAnimatedOperation())
-#endif // animation
- Q_PRIVATE_SLOT(d_func(), void _q_modelAboutToBeReset())
- Q_PRIVATE_SLOT(d_func(), void _q_sortIndicatorChanged(int column, Qt::SortOrder order))
};
QT_END_NAMESPACE
diff --git a/src/widgets/itemviews/qtreeview_p.h b/src/widgets/itemviews/qtreeview_p.h
index 22f6eaec22..d0afdf1223 100644
--- a/src/widgets/itemviews/qtreeview_p.h
+++ b/src/widgets/itemviews/qtreeview_p.h
@@ -23,6 +23,8 @@
#include <QtCore/qvariantanimation.h>
#endif
+#include <array>
+
QT_REQUIRE_CONFIG(treeview);
QT_BEGIN_NAMESPACE
@@ -62,6 +64,7 @@ public:
~QTreeViewPrivate() {}
void initialize();
+ void clearConnections();
int logicalIndexForTree() const;
inline bool isTreePosition(int logicalIndex) const
{
@@ -88,17 +91,17 @@ public:
void beginAnimatedOperation();
void drawAnimatedOperation(QPainter *painter) const;
QPixmap renderTreeToPixmapForAnimation(const QRect &rect) const;
- void _q_endAnimatedOperation();
+ void endAnimatedOperation();
#endif // animation
void expand(int item, bool emitSignal);
void collapse(int item, bool emitSignal);
- void _q_columnsAboutToBeRemoved(const QModelIndex &, int, int) override;
- void _q_columnsRemoved(const QModelIndex &, int, int) override;
- void _q_modelAboutToBeReset();
- void _q_sortIndicatorChanged(int column, Qt::SortOrder order);
- void _q_modelDestroyed() override;
+ void columnsAboutToBeRemoved(const QModelIndex &, int, int) override;
+ void columnsRemoved(const QModelIndex &, int, int) override;
+ void modelAboutToBeReset();
+ void sortIndicatorChanged(int column, Qt::SortOrder order);
+ void modelDestroyed() override;
QRect intersectedRect(const QRect rect, const QModelIndex &topLeft, const QModelIndex &bottomRight) const override;
void layout(int item, bool recusiveExpanding = false, bool afterIsUninitialized = false);
@@ -150,6 +153,21 @@ public:
QList<QStyleOptionViewItem::ViewItemPosition> *itemPositions, int left,
int right) const;
int widthHintForIndex(const QModelIndex &index, int hint, const QStyleOptionViewItem &option, int i) const;
+
+ enum RectRule {
+ FullRow,
+ SingleSection,
+ AddRowIndicatorToFirstSection
+ };
+
+ // Base class will get the first visual rect including row indicator
+ QRect visualRect(const QModelIndex &index) const override
+ {
+ return visualRect(index, AddRowIndicatorToFirstSection);
+ }
+
+ QRect visualRect(const QModelIndex &index, RectRule rule) const;
+
QHeaderView *header;
int indent;
@@ -239,6 +257,18 @@ public:
// tree position
int treePosition;
+
+ // pending accessibility update
+#if QT_CONFIG(accessibility)
+ bool pendingAccessibilityUpdate = false;
+#endif
+ void updateAccessibility();
+
+ QMetaObject::Connection animationConnection;
+ QMetaObject::Connection selectionmodelConnection;
+ std::array<QMetaObject::Connection, 2> modelConnections;
+ std::array<QMetaObject::Connection, 5> headerConnections;
+ QMetaObject::Connection sortHeaderConnection;
};
QT_END_NAMESPACE
diff --git a/src/widgets/itemviews/qtreewidget.cpp b/src/widgets/itemviews/qtreewidget.cpp
index 3fa8a7e1b9..8e46a0efbe 100644
--- a/src/widgets/itemviews/qtreewidget.cpp
+++ b/src/widgets/itemviews/qtreewidget.cpp
@@ -5,7 +5,6 @@
#include <qheaderview.h>
#include <qpainter.h>
-#include <qitemdelegate.h>
#include <qstack.h>
#include <qdebug.h>
#include <private/qtreewidget_p.h>
@@ -2301,37 +2300,43 @@ QDataStream &operator>>(QDataStream &in, QTreeWidgetItem &item)
#endif // QT_NO_DATASTREAM
-void QTreeWidgetPrivate::_q_emitItemPressed(const QModelIndex &index)
+void QTreeWidgetPrivate::clearConnections()
+{
+ for (const QMetaObject::Connection &connection : connections)
+ QObject::disconnect(connection);
+}
+
+void QTreeWidgetPrivate::emitItemPressed(const QModelIndex &index)
{
Q_Q(QTreeWidget);
emit q->itemPressed(item(index), index.column());
}
-void QTreeWidgetPrivate::_q_emitItemClicked(const QModelIndex &index)
+void QTreeWidgetPrivate::emitItemClicked(const QModelIndex &index)
{
Q_Q(QTreeWidget);
emit q->itemClicked(item(index), index.column());
}
-void QTreeWidgetPrivate::_q_emitItemDoubleClicked(const QModelIndex &index)
+void QTreeWidgetPrivate::emitItemDoubleClicked(const QModelIndex &index)
{
Q_Q(QTreeWidget);
emit q->itemDoubleClicked(item(index), index.column());
}
-void QTreeWidgetPrivate::_q_emitItemActivated(const QModelIndex &index)
+void QTreeWidgetPrivate::emitItemActivated(const QModelIndex &index)
{
Q_Q(QTreeWidget);
emit q->itemActivated(item(index), index.column());
}
-void QTreeWidgetPrivate::_q_emitItemEntered(const QModelIndex &index)
+void QTreeWidgetPrivate::emitItemEntered(const QModelIndex &index)
{
Q_Q(QTreeWidget);
emit q->itemEntered(item(index), index.column());
}
-void QTreeWidgetPrivate::_q_emitItemChanged(const QModelIndex &index)
+void QTreeWidgetPrivate::emitItemChanged(const QModelIndex &index)
{
Q_Q(QTreeWidget);
QTreeWidgetItem *indexItem = item(index);
@@ -2339,19 +2344,19 @@ void QTreeWidgetPrivate::_q_emitItemChanged(const QModelIndex &index)
emit q->itemChanged(indexItem, index.column());
}
-void QTreeWidgetPrivate::_q_emitItemExpanded(const QModelIndex &index)
+void QTreeWidgetPrivate::emitItemExpanded(const QModelIndex &index)
{
Q_Q(QTreeWidget);
emit q->itemExpanded(item(index));
}
-void QTreeWidgetPrivate::_q_emitItemCollapsed(const QModelIndex &index)
+void QTreeWidgetPrivate::emitItemCollapsed(const QModelIndex &index)
{
Q_Q(QTreeWidget);
emit q->itemCollapsed(item(index));
}
-void QTreeWidgetPrivate::_q_emitCurrentItemChanged(const QModelIndex &current,
+void QTreeWidgetPrivate::emitCurrentItemChanged(const QModelIndex &current,
const QModelIndex &previous)
{
Q_Q(QTreeWidget);
@@ -2360,7 +2365,7 @@ void QTreeWidgetPrivate::_q_emitCurrentItemChanged(const QModelIndex &current,
emit q->currentItemChanged(currentItem, previousItem);
}
-void QTreeWidgetPrivate::_q_sort()
+void QTreeWidgetPrivate::sort()
{
if (sortingEnabled) {
int column = header->sortIndicatorSection();
@@ -2369,7 +2374,7 @@ void QTreeWidgetPrivate::_q_sort()
}
}
-void QTreeWidgetPrivate::_q_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
+void QTreeWidgetPrivate::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
Q_Q(QTreeWidget);
QModelIndexList indices = selected.indexes();
@@ -2389,8 +2394,8 @@ void QTreeWidgetPrivate::_q_selectionChanged(const QItemSelection &selected, con
emit q->itemSelectionChanged();
}
-void QTreeWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft,
- const QModelIndex &bottomRight)
+void QTreeWidgetPrivate::dataChanged(const QModelIndex &topLeft,
+ const QModelIndex &bottomRight)
{
if (sortingEnabled && topLeft.isValid() && bottomRight.isValid()
&& !treeModel()->sortPendingTimer.isActive()) {
@@ -2448,7 +2453,7 @@ void QTreeWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft,
whether sorting is enabled.
\sa QTreeWidgetItem, QTreeWidgetItemIterator, QTreeView,
- {Model/View Programming}, {Settings Editor Example}
+ {Model/View Programming}
*/
/*!
@@ -2570,31 +2575,34 @@ void QTreeWidgetPrivate::_q_dataChanged(const QModelIndex &topLeft,
QTreeWidget::QTreeWidget(QWidget *parent)
: QTreeView(*new QTreeWidgetPrivate(), parent)
{
+ Q_D(QTreeWidget);
QTreeView::setModel(new QTreeModel(1, this));
- connect(this, SIGNAL(pressed(QModelIndex)),
- SLOT(_q_emitItemPressed(QModelIndex)));
- connect(this, SIGNAL(clicked(QModelIndex)),
- SLOT(_q_emitItemClicked(QModelIndex)));
- connect(this, SIGNAL(doubleClicked(QModelIndex)),
- SLOT(_q_emitItemDoubleClicked(QModelIndex)));
- connect(this, SIGNAL(activated(QModelIndex)),
- SLOT(_q_emitItemActivated(QModelIndex)));
- connect(this, SIGNAL(entered(QModelIndex)),
- SLOT(_q_emitItemEntered(QModelIndex)));
- connect(this, SIGNAL(expanded(QModelIndex)),
- SLOT(_q_emitItemExpanded(QModelIndex)));
- connect(this, SIGNAL(collapsed(QModelIndex)),
- SLOT(_q_emitItemCollapsed(QModelIndex)));
- connect(selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
- this, SLOT(_q_emitCurrentItemChanged(QModelIndex,QModelIndex)));
- connect(model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
- this, SLOT(_q_emitItemChanged(QModelIndex)));
- connect(model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
- this, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
- connect(model(), SIGNAL(columnsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_sort()));
- connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
- this, SLOT(_q_selectionChanged(QItemSelection,QItemSelection)));
+ d->connections = {
+ QObjectPrivate::connect(this, &QTreeWidget::pressed,
+ d, &QTreeWidgetPrivate::emitItemPressed),
+ QObjectPrivate::connect(this, &QTreeWidget::clicked,
+ d, &QTreeWidgetPrivate::emitItemClicked),
+ QObjectPrivate::connect(this, &QTreeWidget::doubleClicked,
+ d, &QTreeWidgetPrivate::emitItemDoubleClicked),
+ QObjectPrivate::connect(this, &QTreeWidget::activated,
+ d, &QTreeWidgetPrivate::emitItemActivated),
+ QObjectPrivate::connect(this, &QTreeWidget::entered,
+ d, &QTreeWidgetPrivate::emitItemEntered),
+ QObjectPrivate::connect(this, &QTreeWidget::expanded,
+ d, &QTreeWidgetPrivate::emitItemExpanded),
+ QObjectPrivate::connect(this, &QTreeWidget::collapsed,
+ d, &QTreeWidgetPrivate::emitItemCollapsed),
+ QObjectPrivate::connect(model(), &QAbstractItemModel::dataChanged,
+ d, &QTreeWidgetPrivate::emitItemChanged),
+ QObjectPrivate::connect(model(), &QAbstractItemModel::dataChanged,
+ d, &QTreeWidgetPrivate::dataChanged),
+ QObjectPrivate::connect(model(), &QAbstractItemModel::columnsRemoved,
+ d, &QTreeWidgetPrivate::sort),
+ QObjectPrivate::connect(selectionModel(), &QItemSelectionModel::currentChanged,
+ d, &QTreeWidgetPrivate::emitCurrentItemChanged),
+ QObjectPrivate::connect(selectionModel(), &QItemSelectionModel::selectionChanged,
+ d, &QTreeWidgetPrivate::selectionChanged)
+ };
header()->setSectionsClickable(false);
}
@@ -2604,6 +2612,8 @@ QTreeWidget::QTreeWidget(QWidget *parent)
QTreeWidget::~QTreeWidget()
{
+ Q_D(QTreeWidget);
+ d->clearConnections();
}
/*
@@ -3119,7 +3129,7 @@ void QTreeWidget::setSelectionModel(QItemSelectionModel *selectionModel)
QTreeView::setSelectionModel(selectionModel);
QItemSelection newSelection = selectionModel->selection();
if (!newSelection.isEmpty())
- d->_q_selectionChanged(newSelection, QItemSelection());
+ d->selectionChanged(newSelection, QItemSelection());
}
/*!
diff --git a/src/widgets/itemviews/qtreewidget.h b/src/widgets/itemviews/qtreewidget.h
index f83cf421ed..992f6cdb1c 100644
--- a/src/widgets/itemviews/qtreewidget.h
+++ b/src/widgets/itemviews/qtreewidget.h
@@ -323,19 +323,6 @@ private:
Q_DECLARE_PRIVATE(QTreeWidget)
Q_DISABLE_COPY(QTreeWidget)
-
- Q_PRIVATE_SLOT(d_func(), void _q_emitItemPressed(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitItemClicked(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitItemDoubleClicked(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitItemActivated(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitItemEntered(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitItemChanged(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitItemExpanded(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitItemCollapsed(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_emitCurrentItemChanged(const QModelIndex &previous, const QModelIndex &current))
- Q_PRIVATE_SLOT(d_func(), void _q_sort())
- Q_PRIVATE_SLOT(d_func(), void _q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight))
- Q_PRIVATE_SLOT(d_func(), void _q_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected))
};
inline void QTreeWidget::removeItemWidget(QTreeWidgetItem *item, int column)
diff --git a/src/widgets/itemviews/qtreewidget_p.h b/src/widgets/itemviews/qtreewidget_p.h
index fd7560ffd6..53fdea3ca8 100644
--- a/src/widgets/itemviews/qtreewidget_p.h
+++ b/src/widgets/itemviews/qtreewidget_p.h
@@ -23,6 +23,8 @@
#include <private/qtreeview_p.h>
#include <QtWidgets/qheaderview.h>
+#include <array>
+
QT_REQUIRE_CONFIG(treewidget);
QT_BEGIN_NAMESPACE
@@ -186,26 +188,29 @@ class QTreeWidgetPrivate : public QTreeViewPrivate
Q_DECLARE_PUBLIC(QTreeWidget)
public:
QTreeWidgetPrivate() : QTreeViewPrivate(), explicitSortColumn(-1) {}
+ void clearConnections();
inline QTreeModel *treeModel() const { return qobject_cast<QTreeModel*>(model); }
inline QModelIndex index(const QTreeWidgetItem *item, int column = 0) const
{ return treeModel()->index(item, column); }
inline QTreeWidgetItem *item(const QModelIndex &index) const
{ return treeModel()->item(index); }
- void _q_emitItemPressed(const QModelIndex &index);
- void _q_emitItemClicked(const QModelIndex &index);
- void _q_emitItemDoubleClicked(const QModelIndex &index);
- void _q_emitItemActivated(const QModelIndex &index);
- void _q_emitItemEntered(const QModelIndex &index);
- void _q_emitItemChanged(const QModelIndex &index);
- void _q_emitItemExpanded(const QModelIndex &index);
- void _q_emitItemCollapsed(const QModelIndex &index);
- void _q_emitCurrentItemChanged(const QModelIndex &previous, const QModelIndex &index);
- void _q_sort();
- void _q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
- void _q_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
+ void emitItemPressed(const QModelIndex &index);
+ void emitItemClicked(const QModelIndex &index);
+ void emitItemDoubleClicked(const QModelIndex &index);
+ void emitItemActivated(const QModelIndex &index);
+ void emitItemEntered(const QModelIndex &index);
+ void emitItemChanged(const QModelIndex &index);
+ void emitItemExpanded(const QModelIndex &index);
+ void emitItemCollapsed(const QModelIndex &index);
+ void emitCurrentItemChanged(const QModelIndex &previous, const QModelIndex &index);
+ void sort();
+ void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
+ void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
// used by QTreeWidgetItem::sortChildren to make sure the column argument is used
int explicitSortColumn;
+
+ std::array<QMetaObject::Connection, 12> connections;
};
QT_END_NAMESPACE
diff --git a/src/widgets/itemviews/qwidgetitemdata_p.h b/src/widgets/itemviews/qwidgetitemdata_p.h
index 0fbaae34bd..f8c2d47085 100644
--- a/src/widgets/itemviews/qwidgetitemdata_p.h
+++ b/src/widgets/itemviews/qwidgetitemdata_p.h
@@ -6,6 +6,7 @@
#include <QtWidgets/private/qtwidgetsglobal_p.h>
#include <QtCore/qdatastream.h>
+#include <QtCore/qvariant.h>
//
// W A R N I N G
diff --git a/src/widgets/kernel/qaction_widgets.cpp b/src/widgets/kernel/qaction_widgets.cpp
index 53b6e13b2d..ad282ab104 100644
--- a/src/widgets/kernel/qaction_widgets.cpp
+++ b/src/widgets/kernel/qaction_widgets.cpp
@@ -28,8 +28,9 @@ void QtWidgetsActionPrivate::destroy()
{
Q_Q(QAction);
const auto objects = associatedObjects;
- for (int i = objects.size()-1; i >= 0; --i) {
- QObject *object = objects.at(i);
+ const auto end = objects.crend();
+ for (auto it = objects.crbegin(); it != end; ++it) {
+ QObject *object = *it;
if (QWidget *widget = qobject_cast<QWidget*>(object))
widget->removeAction(q);
#if QT_CONFIG(graphicsview)
diff --git a/src/widgets/kernel/qaction_widgets_p.h b/src/widgets/kernel/qaction_widgets_p.h
index bc24ce3df1..77c3d8a680 100644
--- a/src/widgets/kernel/qaction_widgets_p.h
+++ b/src/widgets/kernel/qaction_widgets_p.h
@@ -20,6 +20,8 @@
#include <QtWidgets/qmenu.h>
#endif
+#include <QtCore/qpointer.h>
+
QT_REQUIRE_CONFIG(action);
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp
index d5af9ac278..a1392e10dc 100644
--- a/src/widgets/kernel/qapplication.cpp
+++ b/src/widgets/kernel/qapplication.cpp
@@ -310,7 +310,6 @@ QWidget *QApplication::topLevelAt(const QPoint &pos)
*/
void qt_init_tooltip_palette();
-void qt_cleanup();
QStyle *QApplicationPrivate::app_style = nullptr; // default application style
#ifndef QT_NO_STYLE_STYLESHEET
@@ -496,8 +495,11 @@ void QApplicationPrivate::init()
void qt_init_tooltip_palette()
{
#if QT_CONFIG(tooltip)
- if (const QPalette *toolTipPalette = QGuiApplicationPrivate::platformTheme()->palette(QPlatformTheme::ToolTipPalette))
- QToolTip::setPalette(*toolTipPalette);
+ if (const QPalette *toolTipPalette = QGuiApplicationPrivate::platformTheme()->palette(QPlatformTheme::ToolTipPalette)) {
+ QPalette toolTipPal = *toolTipPalette;
+ toolTipPal.setResolveMask(0);
+ QToolTip::setPalette(toolTipPal);
+ }
#endif
}
@@ -527,6 +529,8 @@ void QApplicationPrivate::initialize()
qWarning("QApplication: invalid style override '%s' passed, ignoring it.\n"
"\tAvailable styles: %s", qPrintable(styleOverride),
qPrintable(QStyleFactory::keys().join(", "_L1)));
+ // Clear styleOverride so it is not picked by Qt Quick Controls (QTBUG-100563)
+ styleOverride.clear();
}
}
@@ -703,7 +707,10 @@ QApplication::~QApplication()
d->cleanupMultitouch();
- qt_cleanup();
+ QPixmapCache::clear();
+ QColormap::cleanup();
+
+ QApplicationPrivate::active_window = nullptr; //### this should not be necessary
if (QApplicationPrivate::widgetCount)
qDebug("Widgets left: %i Max widgets: %i \n", QWidgetPrivate::instanceCounter, QWidgetPrivate::maxInstances);
@@ -714,14 +721,6 @@ QApplication::~QApplication()
QApplicationPrivate::widgetCount = false;
}
-void qt_cleanup()
-{
- QPixmapCache::clear();
- QColormap::cleanup();
-
- QApplicationPrivate::active_window = nullptr; //### this should not be necessary
-}
-
/*!
\fn QWidget *QApplication::widgetAt(const QPoint &point)
@@ -787,6 +786,7 @@ bool QApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventLis
const QEvent::Type type = event->type();
switch (type) {
case QEvent::UpdateRequest:
+ case QEvent::UpdateLater:
case QEvent::LayoutRequest:
case QEvent::Resize:
case QEvent::Move:
@@ -815,6 +815,10 @@ bool QApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventLis
static_cast<QMoveEvent *>(postedEvent.event)->m_pos =
static_cast<const QMoveEvent *>(event)->pos();
break;
+ case QEvent::UpdateLater:
+ static_cast<QUpdateLaterEvent *>(postedEvent.event)->m_region +=
+ static_cast<const QUpdateLaterEvent *>(event)->region();
+ break;
case QEvent::UpdateRequest:
case QEvent::LanguageChange:
case QEvent::LayoutRequest:
@@ -1090,6 +1094,12 @@ QPalette QApplicationPrivate::basePalette() const
if (const QPalette *themePalette = platformTheme() ? platformTheme()->palette() : nullptr)
palette = themePalette->resolve(palette);
+ // This palette now is Qt-generated, so reset the resolve mask. This allows
+ // QStyle::polish implementations to respect palettes that are user provided,
+ // by checking if the palette has a brush set for a color that the style might
+ // otherwise overwrite.
+ palette.setResolveMask(0);
+
// Finish off by letting the application style polish the palette. This will
// not result in the polished palette becoming a user-set palette, as the
// resulting base palette is only used as a fallback, with the resolve mask
@@ -1772,7 +1782,7 @@ void QApplicationPrivate::notifyLayoutDirectionChange()
/*!
\fn void QApplication::setActiveWindow(QWidget* active)
- \deprecated Use QWidget::activateWindow() instead.
+ \deprecated [6.5] Use QWidget::activateWindow() instead.
Sets the active window to the \a active widget in response to a system
event. The function is called from the platform specific event handlers.
@@ -1965,7 +1975,7 @@ QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool
f = toplevel;
QWidget *w = f;
- QWidget *test = f->d_func()->focus_next;
+ QWidget *test = f->nextInFocusChain();
bool seenWindow = false;
bool focusWidgetAfterWindow = false;
while (test && test != f) {
@@ -1996,7 +2006,7 @@ QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool
if (next)
break;
}
- test = test->d_func()->focus_next;
+ test = test->nextInFocusChain();
}
if (wrappingOccurred != nullptr)
@@ -2021,19 +2031,6 @@ QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool
*/
void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave, const QPointF &globalPosF)
{
-#if 0
- if (leave) {
- QEvent e(QEvent::Leave);
- QCoreApplication::sendEvent(leave, & e);
- }
- if (enter) {
- const QPoint windowPos = enter->window()->mapFromGlobal(globalPos);
- QEnterEvent e(enter->mapFromGlobal(globalPos), windowPos, globalPos);
- QCoreApplication::sendEvent(enter, & e);
- }
- return;
-#endif
-
if ((!enter && !leave) || (enter == leave))
return;
@@ -2544,8 +2541,9 @@ int QApplication::startDragDistance()
exec(), because modal widgets call exec() to start a local event loop.
To make your application perform idle processing, i.e., executing a special
- function whenever there are no pending events, use a QTimer with 0 timeout.
- More advanced idle processing schemes can be achieved using processEvents().
+ function whenever there are no pending events, use a QChronoTimer with 0ns
+ timeout. More advanced idle processing schemes can be achieved using
+ processEvents().
We recommend that you connect clean-up code to the
\l{QCoreApplication::}{aboutToQuit()} signal, instead of putting it in your
@@ -2654,6 +2652,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
Q_FALLTHROUGH();
case QEvent::Leave:
d->toolTipWakeUp.stop();
+ break;
default:
break;
}
@@ -2678,6 +2677,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
|| key == Qt::Key_Up
|| key == Qt::Key_Right
|| key == Qt::Key_Down);
+ break;
}
default:
break;
@@ -2939,6 +2939,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
tablet->tangentialPressure(), tablet->rotation(), tablet->z(),
tablet->modifiers(), tablet->button(), tablet->buttons());
te.m_spont = e->spontaneous();
+ te.setTimestamp(tablet->timestamp());
te.setAccepted(false);
res = d->notify_helper(w, w == receiver ? tablet : &te);
eventAccepted = ((w == receiver) ? tablet : &te)->isAccepted();
@@ -3034,8 +3035,16 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
#endif
w = qobject_cast<QWidget *>(QDragManager::self()->currentTarget());
- if (!w)
- break;
+ if (!w) {
+ // The widget that received DragEnter didn't accept the event, so we have no
+ // current drag target in the QDragManager. But DragLeave still needs to be
+ // dispatched so that enter/leave events are in balance (and so that UnderMouse
+ // gets cleared).
+ if (e->type() == QEvent::DragLeave)
+ w = static_cast<QWidget *>(receiver);
+ else
+ break;
+ }
if (e->type() == QEvent::DragMove || e->type() == QEvent::Drop) {
QDropEvent *dragEvent = static_cast<QDropEvent *>(e);
QWidget *origReceiver = static_cast<QWidget *>(receiver);
@@ -3060,7 +3069,8 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
bool eventAccepted = touchEvent->isAccepted();
bool acceptTouchEvents = w->testAttribute(Qt::WA_AcceptTouchEvents);
- if (acceptTouchEvents && e->spontaneous()) {
+ if (acceptTouchEvents && e->spontaneous()
+ && touchEvent->device()->type() != QInputDevice::DeviceType::TouchPad) {
const QPoint localPos = touchEvent->points()[0].position().toPoint();
QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, e, localPos);
}
diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h
index 4be35320d9..21b1605dfc 100644
--- a/src/widgets/kernel/qapplication_p.h
+++ b/src/widgets/kernel/qapplication_p.h
@@ -145,9 +145,7 @@ public:
static QWidget *main_widget;
static QWidget *focus_widget;
static QWidget *hidden_focus_widget;
- static QWidget *active_window;
#if QT_CONFIG(wheelevent)
- static int wheel_scroll_lines;
static QPointer<QWidget> wheel_widget;
#endif
@@ -228,6 +226,7 @@ private:
static void giveFocusAccordingToFocusPolicy(QWidget *w, QEvent *event, QPoint localPos);
static bool shouldSetFocus(QWidget *w, Qt::FocusPolicy policy);
+ static QWidget *active_window;
static bool isAlien(QWidget *);
};
diff --git a/src/widgets/kernel/qgesturemanager.cpp b/src/widgets/kernel/qgesturemanager.cpp
index 0108e01e5f..edb159bbbf 100644
--- a/src/widgets/kernel/qgesturemanager.cpp
+++ b/src/widgets/kernel/qgesturemanager.cpp
@@ -50,7 +50,7 @@ static inline int panTouchPoints()
#endif
QGestureManager::QGestureManager(QObject *parent)
- : QObject(parent), state(NotGesture), m_lastCustomGestureId(Qt::CustomGesture)
+ : QObject(parent), m_lastCustomGestureId(Qt::CustomGesture)
{
qRegisterMetaType<Qt::GestureState>();
@@ -98,25 +98,23 @@ void QGestureManager::unregisterGestureRecognizer(Qt::GestureType type)
{
QList<QGestureRecognizer *> list = m_recognizers.values(type);
m_recognizers.remove(type);
- foreach (QGesture *g, m_gestureToRecognizer.keys()) {
- QGestureRecognizer *recognizer = m_gestureToRecognizer.value(g);
+ for (const auto &[g, recognizer] : std::as_const(m_gestureToRecognizer).asKeyValueRange()) {
if (list.contains(recognizer)) {
m_deletedRecognizers.insert(g, recognizer);
}
}
- QMap<ObjectGesture, QList<QGesture *> >::const_iterator iter = m_objectGestures.constBegin();
- while (iter != m_objectGestures.constEnd()) {
- ObjectGesture objectGesture = iter.key();
+ for (const auto &[objectGesture, gestures] : std::as_const(m_objectGestures).asKeyValueRange()) {
if (objectGesture.gesture == type) {
- foreach (QGesture *g, iter.value()) {
- if (QGestureRecognizer *recognizer = m_gestureToRecognizer.value(g)) {
- m_gestureToRecognizer.remove(g);
+ for (QGesture *g : gestures) {
+ auto it = m_gestureToRecognizer.constFind(g);
+ if (it != m_gestureToRecognizer.cend() && it.value()) {
+ QGestureRecognizer *recognizer = it.value();
+ m_gestureToRecognizer.erase(it);
m_obsoleteGestures[recognizer].insert(g);
}
}
}
- ++iter;
}
}
@@ -282,18 +280,18 @@ bool QGestureManager::filterEventThroughContexts(const QMultiMap<QObject *,
}
if (!triggeredGestures.isEmpty() || !finishedGestures.isEmpty()
|| !newMaybeGestures.isEmpty() || !notGestures.isEmpty()) {
- QSet<QGesture *> startedGestures = triggeredGestures - m_activeGestures;
+ const QSet<QGesture *> startedGestures = triggeredGestures - m_activeGestures;
triggeredGestures &= m_activeGestures;
// check if a running gesture switched back to maybe state
- QSet<QGesture *> activeToMaybeGestures = m_activeGestures & newMaybeGestures;
+ const QSet<QGesture *> activeToMaybeGestures = m_activeGestures & newMaybeGestures;
// check if a maybe gesture switched to canceled - reset it but don't send an event
QSet<QGesture *> maybeToCanceledGestures = m_maybeGestures & notGestures;
// check if a running gesture switched back to not gesture state,
// i.e. were canceled
- QSet<QGesture *> canceledGestures = m_activeGestures & notGestures;
+ const QSet<QGesture *> canceledGestures = m_activeGestures & notGestures;
// new gestures in maybe state
m_maybeGestures += newMaybeGestures;
@@ -311,11 +309,11 @@ bool QGestureManager::filterEventThroughContexts(const QMultiMap<QObject *,
Q_ASSERT((finishedGestures & canceledGestures).isEmpty());
Q_ASSERT((canceledGestures & newMaybeGestures).isEmpty());
- QSet<QGesture *> notStarted = finishedGestures - m_activeGestures;
+ const QSet<QGesture *> notStarted = finishedGestures - m_activeGestures;
if (!notStarted.isEmpty()) {
// there are some gestures that claim to be finished, but never started.
// probably those are "singleshot" gestures so we'll fake the started state.
- foreach (QGesture *gesture, notStarted)
+ for (QGesture *gesture : notStarted)
gesture->d_func()->state = Qt::GestureStarted;
QSet<QGesture *> undeliveredGestures;
deliverEvents(notStarted, &undeliveredGestures);
@@ -330,15 +328,15 @@ bool QGestureManager::filterEventThroughContexts(const QMultiMap<QObject *,
m_activeGestures -= canceledGestures;
// set the proper gesture state on each gesture
- foreach (QGesture *gesture, startedGestures)
+ for (QGesture *gesture : startedGestures)
gesture->d_func()->state = Qt::GestureStarted;
- foreach (QGesture *gesture, triggeredGestures)
+ for (QGesture *gesture : std::as_const(triggeredGestures))
gesture->d_func()->state = Qt::GestureUpdated;
- foreach (QGesture *gesture, finishedGestures)
+ for (QGesture *gesture : std::as_const(finishedGestures))
gesture->d_func()->state = Qt::GestureFinished;
- foreach (QGesture *gesture, canceledGestures)
+ for (QGesture *gesture : canceledGestures)
gesture->d_func()->state = Qt::GestureCanceled;
- foreach (QGesture *gesture, activeToMaybeGestures)
+ for (QGesture *gesture : activeToMaybeGestures)
gesture->d_func()->state = Qt::GestureFinished;
if (!m_activeGestures.isEmpty() || !m_maybeGestures.isEmpty() ||
@@ -358,7 +356,7 @@ bool QGestureManager::filterEventThroughContexts(const QMultiMap<QObject *,
deliverEvents(startedGestures+triggeredGestures+finishedGestures+canceledGestures,
&undeliveredGestures);
- foreach (QGesture *g, startedGestures) {
+ for (QGesture *g : startedGestures) {
if (undeliveredGestures.contains(g))
continue;
if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) {
@@ -371,9 +369,9 @@ bool QGestureManager::filterEventThroughContexts(const QMultiMap<QObject *,
m_activeGestures -= undeliveredGestures;
// reset gestures that ended
- QSet<QGesture *> endedGestures =
+ const QSet<QGesture *> endedGestures =
finishedGestures + canceledGestures + undeliveredGestures + maybeToCanceledGestures;
- foreach (QGesture *gesture, endedGestures) {
+ for (QGesture *gesture : endedGestures) {
recycle(gesture);
m_gestureTargets.remove(gesture);
}
@@ -550,7 +548,7 @@ void QGestureManager::getGestureTargets(const QSet<QGesture*> &gestures,
GestureByTypes gestureByTypes;
// sort gestures by types
- foreach (QGesture *gesture, gestures) {
+ for (QGesture *gesture : gestures) {
QWidget *receiver = m_gestureTargets.value(gesture, nullptr);
Q_ASSERT(receiver);
if (receiver)
@@ -612,7 +610,8 @@ void QGestureManager::deliverEvents(const QSet<QGesture *> &gestures,
QWidget *child = topLevel->childAt(topLevel->mapFromGlobal(pt));
target = child ? child : topLevel;
}
- } else {
+ }
+ if (!target) {
// or use the context of the gesture
QObject *context = m_gestureOwners.value(gesture, 0);
if (context->isWidgetType())
@@ -651,7 +650,7 @@ void QGestureManager::deliverEvents(const QSet<QGesture *> &gestures,
for (GesturesPerWidget::const_iterator it = conflictedGestures.constBegin(),
e = conflictedGestures.constEnd(); it != e; ++it) {
QWidget *receiver = it.key();
- QList<QGesture *> gestures = it.value();
+ const QList<QGesture *> &gestures = it.value();
qCDebug(lcGestureManager) << "QGestureManager::deliverEvents: sending GestureOverride to"
<< receiver
<< "gestures:" << gestures;
@@ -659,7 +658,7 @@ void QGestureManager::deliverEvents(const QSet<QGesture *> &gestures,
event.t = QEvent::GestureOverride;
// mark event and individual gestures as ignored
event.ignore();
- foreach(QGesture *g, gestures)
+ for (QGesture *g : gestures)
event.setAccepted(g, false);
QCoreApplication::sendEvent(receiver, &event);
diff --git a/src/widgets/kernel/qgesturemanager_p.h b/src/widgets/kernel/qgesturemanager_p.h
index 1bf1358b13..02beb024f9 100644
--- a/src/widgets/kernel/qgesturemanager_p.h
+++ b/src/widgets/kernel/qgesturemanager_p.h
@@ -21,6 +21,8 @@
#include "private/qwidget_p.h"
#include "qgesturerecognizer.h"
+#include <QtCore/qpointer.h>
+
#ifndef QT_NO_GESTURES
#include <functional>
@@ -64,14 +66,6 @@ private:
QSet<QGesture *> m_activeGestures;
QSet<QGesture *> m_maybeGestures;
- enum State {
- Gesture,
- NotGesture,
- MaybeGesture // this means timers are up and waiting for some
- // more events, and input events are handled by
- // gesture recognizer explicitly
- } state;
-
struct ObjectGesture
{
QObject* object;
diff --git a/src/widgets/kernel/qlayout.cpp b/src/widgets/kernel/qlayout.cpp
index 7639803c8b..a826ea75bc 100644
--- a/src/widgets/kernel/qlayout.cpp
+++ b/src/widgets/kernel/qlayout.cpp
@@ -57,14 +57,13 @@ static int menuBarHeightForWidth(QWidget *menubar, int w)
resized to zero size if there is too little space. To support
children whose heights depend on their widths, implement
hasHeightForWidth() and heightForWidth(). See the
- \l{layouts/borderlayout}{Border Layout} and
- \l{layouts/flowlayout}{Flow Layout} examples for
+ \l{layouts/flowlayout}{Flow Layout} example for
more information about implementing custom layout managers.
Geometry management stops when the layout manager is deleted.
\sa QLayoutItem, {Layout Management}, {Basic Layouts Example},
- {Border Layout Example}, {Flow Layout Example}
+ {Flow Layout Example}
*/
@@ -521,10 +520,11 @@ void QLayoutPrivate::doResize()
void QLayout::widgetEvent(QEvent *e)
{
Q_D(QLayout);
- if (!d->enabled)
+ const QEvent::Type type = e->type();
+ if (!d->enabled && type != QEvent::ChildRemoved)
return;
- switch (e->type()) {
+ switch (type) {
case QEvent::Resize:
if (d->activated)
d->doResize();
@@ -773,7 +773,7 @@ void QLayoutPrivate::reparentChildWidgets(QWidget *mw)
w->metaObject()->className(), qUtf16Printable(w->objectName()));
}
#endif
- bool needShow = mwVisible && !(w->isHidden() && w->testAttribute(Qt::WA_WState_ExplicitShowHide));
+ bool needShow = mwVisible && !QWidgetPrivate::get(w)->isExplicitlyHidden();
if (pw != mw)
w->setParent(mw);
if (needShow)
@@ -859,7 +859,7 @@ void QLayout::addChildWidget(QWidget *w)
#endif
pw = nullptr;
}
- bool needShow = mw && mw->isVisible() && !(w->isHidden() && w->testAttribute(Qt::WA_WState_ExplicitShowHide));
+ bool needShow = mw && mw->isVisible() && !QWidgetPrivate::get(w)->isExplicitlyHidden();
if (!pw && mw)
w->setParent(mw);
w->setAttribute(Qt::WA_LaidOut);
@@ -1259,7 +1259,7 @@ QLayout::SizeConstraint QLayout::sizeConstraint() const
this layout is set to \a r, provided that this layout supports
setAlignment().
- The result is derived from sizeHint() and expanding(). It is never
+ The result is derived from sizeHint() and expandingDirections(). It is never
larger than \a r.
*/
QRect QLayout::alignmentRect(const QRect &r) const
diff --git a/src/widgets/kernel/qlayoutitem.cpp b/src/widgets/kernel/qlayoutitem.cpp
index eb53a3a120..246d090828 100644
--- a/src/widgets/kernel/qlayoutitem.cpp
+++ b/src/widgets/kernel/qlayoutitem.cpp
@@ -52,7 +52,7 @@ inline static QSize toLayoutItemSize(QWidgetPrivate *priv, const QSize &size)
Pure virtual functions are provided to return information about
the layout, including, sizeHint(), minimumSize(), maximumSize()
- and expanding().
+ and expandingDirections().
The layout's geometry can be set and retrieved with setGeometry()
and geometry(), and its alignment with setAlignment() and
diff --git a/src/widgets/kernel/qrhiwidget.cpp b/src/widgets/kernel/qrhiwidget.cpp
new file mode 100644
index 0000000000..bf56263113
--- /dev/null
+++ b/src/widgets/kernel/qrhiwidget.cpp
@@ -0,0 +1,1309 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qrhiwidget_p.h"
+#include <private/qguiapplication_p.h>
+#include <qpa/qplatformintegration.h>
+#include <private/qwidgetrepaintmanager_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QRhiWidget
+ \inmodule QtWidgets
+ \since 6.7
+
+ \brief The QRhiWidget class is a widget for rendering 3D graphics via an
+ accelerated grapics API, such as Vulkan, Metal, or Direct 3D.
+
+ \preliminary
+
+ \note QRhiWidget is in tech preview in Qt 6.7. \b {The API is under
+ development and subject to change.}
+
+ QRhiWidget provides functionality for displaying 3D content rendered
+ through the \l QRhi APIs within a QWidget-based application. In many ways
+ it is the portable equivalent of \l QOpenGLWidget that is not tied to a
+ single 3D graphics API, but rather can function with all the APIs QRhi
+ supports (such as, Direct 3D 11/12, Vulkan, Metal, and OpenGL).
+
+ QRhiWidget is expected to be subclassed. To render into the 2D texture that
+ is implicitly created and managed by the QRhiWidget, subclasses should
+ reimplement the virtual functions initialize() and render().
+
+ The size of the texture will by default adapt to the size of the widget. If
+ a fixed size is preferred, set a fixed size specified in pixels by calling
+ setFixedColorBufferSize().
+
+ In addition to the texture serving as the color buffer, a depth/stencil
+ buffer and a render target binding these together is maintained implicitly
+ as well.
+
+ The QRhi for the widget's top-level window is configured to use a
+ platform-specific backend and graphics API by default: Metal on macOS and
+ iOS, Direct 3D 11 on Windows, OpenGL otherwise. Call setApi() to override
+ this.
+
+ \note A single widget window can only use one QRhi backend, and so one
+ single 3D graphics API. If two QRhiWidget or QQuickWidget widgets in the
+ window's widget hierarchy request different APIs, only one of them will
+ function correctly.
+
+ \note While QRhiWidget is a public Qt API, the QRhi family of classes in
+ the Qt Gui module, including QRhi, QShader and QShaderDescription, offer
+ limited compatibility guarantees. There are no source or binary
+ compatibility guarantees for these classes, meaning the API is only
+ guaranteed to work with the Qt version the application was developed
+ against. Source incompatible changes are however aimed to be kept at a
+ minimum and will only be made in minor releases (6.7, 6.8, and so on).
+ \c{qrhiwidget.h} does not directly include any QRhi-related headers. To use
+ those classes when implementing a QRhiWidget subclass, link to
+ \c{Qt::GuiPrivate} (if using CMake), and include the appropriate headers
+ with the \c rhi prefix, for example \c{#include <rhi/qrhi.h>}.
+
+ An example of a simple QRhiWidget subclass rendering a triangle is the
+ following:
+
+ \snippet qrhiwidget/rhiwidgetintro.cpp 0
+
+ This is a widget that continuously requests updates, throttled by the
+ presentation rate (vsync, depending on the screen refresh rate). If
+ rendering continuously is not desired, the update() call in render() should
+ be removed, and rather issued only when updating the rendered content is
+ necessary. For example, if the rotation of the cube should be tied to the
+ value of a QSlider, then connecting the slider's value change signal to a
+ slot or lambda that forwards the new value and calls update() is
+ sufficient.
+
+ The vertex and fragment shaders are provided as Vulkan-style GLSL and must
+ be processed first by the Qt shader infrastructure first. This is achieved
+ either by running the \c qsb command-line tool manually, or by using the
+ \l{Qt Shader Tools Build System Integration}{qt_add_shaders()} function in
+ CMake. The QRhiWidget implementation loads these pre-processed \c{.qsb}
+ files that are shipped with the application. See \l{Qt Shader Tools} for
+ more information about Qt's shader translation infrastructure.
+
+ The source code for these shaders could be the following:
+
+ \c{color.vert}
+
+ \snippet qrhiwidget/rhiwidgetintro.vert 0
+
+ \c{color.frag}
+
+ \snippet qrhiwidget/rhiwidgetintro.frag 0
+
+ The result is a widget that shows the following:
+
+ \image qrhiwidget-intro.jpg
+
+ For a complete, minimal, introductory example check out the \l{Simple RHI
+ Widget Example}.
+
+ For an example with more functionality and demonstration of further
+ concepts, see the \l{Cube RHI Widget Example}.
+
+ QRhiWidget always involves rendering into a backing texture, not
+ directly to the window (the surface or layer provided by the windowing
+ system for the native window). This allows properly compositing the content
+ with the rest of the widget-based UI, and offering a simple and compact
+ API, making it easy to get started. All this comes at the expense of
+ additional resources and a potential effect on performance. This is often
+ perfectly acceptable in practice, but advanced users should keep in mind
+ the pros and cons of the different approaches. Refer to the \l{RHI Window
+ Example} and compare it with the \l{Simple RHI Widget Example} for details
+ about the two approaches.
+
+ Reparenting a QRhiWidget into a widget hierarchy that belongs to a
+ different window (top-level widget), or making the QRhiWidget itself a
+ top-level (by setting the parent to \nullptr), involves changing the
+ associated QRhi (and potentially destroying the old one) while the
+ QRhiWidget continues to stay alive and well. To support this, robust
+ QRhiWidget implementations are expected to reimplement the
+ releaseResources() virtual function as well, and drop their QRhi resources
+ just as they do in the destructor. The \l{Cube RHI Widget Example}
+ demonstrates this in practice.
+
+ While not a primary use case, QRhiWidget also allows incorporating
+ rendering code that directly uses a 3D graphics API such as Vulkan, Metal,
+ Direct 3D, or OpenGL. See \l QRhiCommandBuffer::beginExternal() for details
+ on recording native commands within a QRhi render pass, as well as
+ \l QRhiTexture::createFrom() for a way to wrap an existing native texture and
+ then use it with QRhi in a subsequent render pass. Note however that the
+ configurability of the underlying graphics API (its device or context
+ features, layers, extensions, etc.) is going to be limited since
+ QRhiWidget's primary goal is to provide an environment suitable for
+ QRhi-based rendering code, not to enable arbitrary, potentially complex,
+ foreign rendering engines.
+
+ \since 6.7
+
+ \sa QRhi, QShader, QOpenGLWidget, {Simple RHI Widget Example}, {Cube RHI Widget Example}
+ */
+
+/*!
+ \enum QRhiWidget::Api
+ Specifies the 3D API and QRhi backend to use
+
+ \value Null
+ \value OpenGL
+ \value Metal
+ \value Vulkan
+ \value Direct3D11
+ \value Direct3D12
+
+ \sa QRhi
+ */
+
+/*!
+ \enum QRhiWidget::TextureFormat
+ Specifies the format of the texture to which the QRhiWidget renders.
+
+ \value RGBA8 See QRhiTexture::RGBA8.
+ \value RGBA16F See QRhiTexture::RGBA16F.
+ \value RGBA32F See QRhiTexture::RGBA32F.
+ \value RGB10A2 See QRhiTexture::RGB10A2.
+
+ \sa QRhiTexture
+ */
+
+/*!
+ Constructs a widget which is a child of \a parent, with widget flags set to \a f.
+ */
+QRhiWidget::QRhiWidget(QWidget *parent, Qt::WindowFlags f)
+ : QWidget(*(new QRhiWidgetPrivate), parent, f)
+{
+ Q_D(QRhiWidget);
+ if (Q_UNLIKELY(!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::RhiBasedRendering)))
+ qWarning("QRhiWidget: QRhi is not supported on this platform.");
+ else
+ d->setRenderToTexture();
+
+ d->config.setEnabled(true);
+#if defined(Q_OS_DARWIN)
+ d->config.setApi(QPlatformBackingStoreRhiConfig::Metal);
+#elif defined(Q_OS_WIN)
+ d->config.setApi(QPlatformBackingStoreRhiConfig::D3D11);
+#else
+ d->config.setApi(QPlatformBackingStoreRhiConfig::OpenGL);
+#endif
+}
+
+/*!
+ Destructor.
+ */
+QRhiWidget::~QRhiWidget()
+{
+ Q_D(QRhiWidget);
+
+ if (d->rhi) {
+ d->rhi->removeCleanupCallback(this);
+ // rhi resources must be destroyed here, due to how QWidget teardown works;
+ // it should not be left to the private object's destruction.
+ d->resetRenderTargetObjects();
+ d->resetColorBufferObjects();
+ qDeleteAll(d->pendingDeletes);
+ }
+
+ d->offscreenRenderer.reset();
+}
+
+/*!
+ Handles resize events that are passed in the \a e event parameter. Calls
+ the virtual function initialize().
+
+ \note Avoid overriding this function in derived classes. If that is not
+ feasible, make sure that QRhiWidget's implementation is invoked too.
+ Otherwise the underlying texture object and related resources will not get
+ resized properly and will lead to incorrect rendering.
+ */
+void QRhiWidget::resizeEvent(QResizeEvent *e)
+{
+ Q_D(QRhiWidget);
+
+ if (e->size().isEmpty()) {
+ d->noSize = true;
+ return;
+ }
+ d->noSize = false;
+
+ d->sendPaintEvent(QRect(QPoint(0, 0), size()));
+}
+
+/*!
+ Handles paint events.
+
+ Calling QWidget::update() will lead to sending a paint event \a e, and thus
+ invoking this function. The sending of the event is asynchronous and will
+ happen at some point after returning from update(). This function will
+ then, after some preparation, call the virtual render() to update the
+ contents of the QRhiWidget's associated texture. The widget's top-level
+ window will then composite the texture with the rest of the window.
+ */
+void QRhiWidget::paintEvent(QPaintEvent *)
+{
+ Q_D(QRhiWidget);
+ if (!updatesEnabled() || d->noSize)
+ return;
+
+ d->ensureRhi();
+ if (!d->rhi) {
+ qWarning("QRhiWidget: No QRhi");
+ emit renderFailed();
+ return;
+ }
+
+ QRhiCommandBuffer *cb = nullptr;
+ if (d->rhi->beginOffscreenFrame(&cb) != QRhi::FrameOpSuccess)
+ return;
+
+ bool needsInit = false;
+ d->ensureTexture(&needsInit);
+ if (d->colorTexture || d->msaaColorBuffer) {
+ bool canRender = true;
+ if (needsInit)
+ canRender = d->invokeInitialize(cb);
+ if (canRender)
+ render(cb);
+ }
+
+ d->rhi->endOffscreenFrame();
+}
+
+/*!
+ \reimp
+*/
+bool QRhiWidget::event(QEvent *e)
+{
+ Q_D(QRhiWidget);
+ switch (e->type()) {
+ case QEvent::WindowAboutToChangeInternal:
+ // The QRhi will almost certainly change, prevent texture() from
+ // returning the existing QRhiTexture in the meantime.
+ d->textureInvalid = true;
+
+ if (d->rhi && d->rhi != d->offscreenRenderer.rhi()) {
+ // Drop the cleanup callback registered to the toplevel's rhi and
+ // do the early-release, there may not be another chance to do
+ // this, and the QRhi we have currently set may be destroyed by the
+ // time we get to ensureRhi() again.
+ d->rhi->removeCleanupCallback(this);
+ releaseResources(); // notify the user code about the early-release
+ d->releaseResources();
+ // must _not_ null out d->rhi here, for proper interaction with ensureRhi()
+ }
+
+ break;
+
+ case QEvent::Show:
+ if (isVisible())
+ d->sendPaintEvent(QRect(QPoint(0, 0), size()));
+ break;
+ default:
+ break;
+ }
+ return QWidget::event(e);
+}
+
+QWidgetPrivate::TextureData QRhiWidgetPrivate::texture() const
+{
+ // This is the only safe place to clear pendingDeletes, due to the
+ // possibility of the texture returned in the previous invocation of this
+ // function having been added to pendingDeletes, meaning the object then
+ // needs to be valid until the next (this) invocation of this function.
+ // (the exact object lifetime requirements depend on the
+ // QWidget/RepaintManager internal implementation; for now avoid relying on
+ // such details by clearing pendingDeletes only here, not in endCompose())
+ qDeleteAll(pendingDeletes);
+ pendingDeletes.clear();
+
+ TextureData td;
+ if (!textureInvalid)
+ td.textureLeft = resolveTexture ? resolveTexture : colorTexture;
+ return td;
+}
+
+QPlatformTextureList::Flags QRhiWidgetPrivate::textureListFlags()
+{
+ QPlatformTextureList::Flags flags = QWidgetPrivate::textureListFlags();
+ if (mirrorVertically)
+ flags |= QPlatformTextureList::MirrorVertically;
+ return flags;
+}
+
+QPlatformBackingStoreRhiConfig QRhiWidgetPrivate::rhiConfig() const
+{
+ return config;
+}
+
+void QRhiWidgetPrivate::endCompose()
+{
+ // This function is called by QWidgetRepaintManager right after the
+ // backingstore's QRhi-based flush returns. In practice that means after
+ // the begin-endFrame() on the top-level window's swapchain.
+
+ if (rhi) {
+ Q_Q(QRhiWidget);
+ emit q->frameSubmitted();
+ }
+}
+
+// This is reimplemented to enable calling QWidget::grab() on the widget or an
+// ancestor of it. At the same time, QRhiWidget provides its own
+// grabFramebuffer() as well, mirroring QQuickWidget and QOpenGLWidget for
+// consistency. In both types of grabs we end up in here.
+QImage QRhiWidgetPrivate::grabFramebuffer()
+{
+ Q_Q(QRhiWidget);
+ if (noSize)
+ return QImage();
+
+ ensureRhi();
+ if (!rhi) {
+ // The widget (and its parent chain, if any) may not be shown at
+ // all, yet one may still want to use it for grabs. This is
+ // ridiculous of course because the rendering infrastructure is
+ // tied to the top-level widget that initializes upon expose, but
+ // it has to be supported.
+ offscreenRenderer.setConfig(config);
+ // no window passed in, so no swapchain, but we get a functional QRhi which we own
+ offscreenRenderer.create();
+ rhi = offscreenRenderer.rhi();
+ if (!rhi) {
+ qWarning("QRhiWidget: Failed to create dedicated QRhi for grabbing");
+ emit q->renderFailed();
+ return QImage();
+ }
+ }
+
+ QRhiCommandBuffer *cb = nullptr;
+ if (rhi->beginOffscreenFrame(&cb) != QRhi::FrameOpSuccess)
+ return QImage();
+
+ QRhiReadbackResult readResult;
+ bool readCompleted = false;
+ bool needsInit = false;
+ ensureTexture(&needsInit);
+
+ if (colorTexture || msaaColorBuffer) {
+ bool canRender = true;
+ if (needsInit)
+ canRender = invokeInitialize(cb);
+ if (canRender)
+ q->render(cb);
+
+ QRhiResourceUpdateBatch *readbackBatch = rhi->nextResourceUpdateBatch();
+ readResult.completed = [&readCompleted] { readCompleted = true; };
+ readbackBatch->readBackTexture(resolveTexture ? resolveTexture : colorTexture, &readResult);
+ cb->resourceUpdate(readbackBatch);
+ }
+
+ rhi->endOffscreenFrame();
+
+ if (readCompleted) {
+ QImage::Format imageFormat = QImage::Format_RGBA8888;
+ switch (widgetTextureFormat) {
+ case QRhiWidget::TextureFormat::RGBA8:
+ break;
+ case QRhiWidget::TextureFormat::RGBA16F:
+ imageFormat = QImage::Format_RGBA16FPx4;
+ break;
+ case QRhiWidget::TextureFormat::RGBA32F:
+ imageFormat = QImage::Format_RGBA32FPx4;
+ break;
+ case QRhiWidget::TextureFormat::RGB10A2:
+ imageFormat = QImage::Format_BGR30;
+ break;
+ }
+ QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
+ readResult.pixelSize.width(), readResult.pixelSize.height(),
+ imageFormat);
+ QImage result;
+ if (rhi->isYUpInFramebuffer())
+ result = wrapperImage.mirrored();
+ else
+ result = wrapperImage.copy();
+ result.setDevicePixelRatio(q->devicePixelRatio());
+ return result;
+ } else {
+ Q_UNREACHABLE();
+ }
+
+ return QImage();
+}
+
+void QRhiWidgetPrivate::resetColorBufferObjects()
+{
+ if (colorTexture) {
+ pendingDeletes.append(colorTexture);
+ colorTexture = nullptr;
+ }
+ if (msaaColorBuffer) {
+ pendingDeletes.append(msaaColorBuffer);
+ msaaColorBuffer = nullptr;
+ }
+ if (resolveTexture) {
+ pendingDeletes.append(resolveTexture);
+ resolveTexture = nullptr;
+ }
+}
+
+void QRhiWidgetPrivate::resetRenderTargetObjects()
+{
+ if (renderTarget) {
+ renderTarget->deleteLater();
+ renderTarget = nullptr;
+ }
+ if (renderPassDescriptor) {
+ renderPassDescriptor->deleteLater();
+ renderPassDescriptor = nullptr;
+ }
+ if (depthStencilBuffer) {
+ depthStencilBuffer->deleteLater();
+ depthStencilBuffer = nullptr;
+ }
+}
+
+void QRhiWidgetPrivate::releaseResources()
+{
+ resetRenderTargetObjects();
+ resetColorBufferObjects();
+ qDeleteAll(pendingDeletes);
+ pendingDeletes.clear();
+}
+
+void QRhiWidgetPrivate::ensureRhi()
+{
+ Q_Q(QRhiWidget);
+ QRhi *currentRhi = QWidgetPrivate::rhi();
+ if (currentRhi && currentRhi->backend() != QBackingStoreRhiSupport::apiToRhiBackend(config.api())) {
+ qWarning("The top-level window is already using another graphics API for composition, "
+ "'%s' is not compatible with this widget",
+ currentRhi->backendName());
+ return;
+ }
+
+ // NB the rhi member may be an invalid object, the pointer can be used, but no deref
+ if (currentRhi && rhi != currentRhi) {
+ if (rhi) {
+ // if previously we created our own but now get a QRhi from the
+ // top-level, then drop what we have and start using the top-level's
+ if (rhi == offscreenRenderer.rhi()) {
+ q->releaseResources(); // notify the user code about the early-release
+ releaseResources();
+ offscreenRenderer.reset();
+ } else {
+ // rhi resources created by us all belong to the old rhi, drop them;
+ // due to nulling out colorTexture this is also what ensures that
+ // initialize() is going to be called again eventually
+ resetRenderTargetObjects();
+ resetColorBufferObjects();
+ }
+ }
+
+ // Normally the widget gets destroyed before the QRhi (which is managed by
+ // the top-level's backingstore). When reparenting between top-levels is
+ // involved, that is not always the case. Therefore we use a per-widget rhi
+ // cleanup callback to get notified when the QRhi is about to be destroyed
+ // while the QRhiWidget is still around.
+ currentRhi->addCleanupCallback(q, [q, this](QRhi *regRhi) {
+ if (!QWidgetPrivate::get(q)->data.in_destructor && this->rhi == regRhi) {
+ q->releaseResources(); // notify the user code about the early-release
+ releaseResources();
+ // must null out our ref, the QRhi object is going to be invalid
+ this->rhi = nullptr;
+ }
+ });
+ }
+
+ rhi = currentRhi;
+}
+
+void QRhiWidgetPrivate::ensureTexture(bool *changed)
+{
+ Q_Q(QRhiWidget);
+
+ QSize newSize = fixedSize;
+ if (newSize.isEmpty())
+ newSize = q->size() * q->devicePixelRatio();
+
+ const int minTexSize = rhi->resourceLimit(QRhi::TextureSizeMin);
+ const int maxTexSize = rhi->resourceLimit(QRhi::TextureSizeMax);
+ newSize.setWidth(qMin(maxTexSize, qMax(minTexSize, newSize.width())));
+ newSize.setHeight(qMin(maxTexSize, qMax(minTexSize, newSize.height())));
+
+ if (colorTexture) {
+ if (colorTexture->format() != rhiTextureFormat || colorTexture->sampleCount() != samples) {
+ resetColorBufferObjects();
+ // sample count change needs new depth-stencil, possibly a new
+ // render target; format change needs new renderpassdescriptor;
+ // therefore must drop the rest too
+ resetRenderTargetObjects();
+ }
+ }
+
+ if (msaaColorBuffer) {
+ if (msaaColorBuffer->backingFormat() != rhiTextureFormat || msaaColorBuffer->sampleCount() != samples) {
+ resetColorBufferObjects();
+ // sample count change needs new depth-stencil, possibly a new
+ // render target; format change needs new renderpassdescriptor;
+ // therefore must drop the rest too
+ resetRenderTargetObjects();
+ }
+ }
+
+ if (!colorTexture && samples <= 1) {
+ if (changed)
+ *changed = true;
+ if (!rhi->isTextureFormatSupported(rhiTextureFormat)) {
+ qWarning("QRhiWidget: The requested texture format (%d) is not supported by the "
+ "underlying 3D graphics API implementation", int(rhiTextureFormat));
+ }
+ colorTexture = rhi->newTexture(rhiTextureFormat, newSize, samples, QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource);
+ if (!colorTexture->create()) {
+ qWarning("Failed to create backing texture for QRhiWidget");
+ delete colorTexture;
+ colorTexture = nullptr;
+ return;
+ }
+ }
+
+ if (samples > 1) {
+ if (!msaaColorBuffer) {
+ if (changed)
+ *changed = true;
+ if (!rhi->isFeatureSupported(QRhi::MultisampleRenderBuffer)) {
+ qWarning("QRhiWidget: Multisample renderbuffers are reported as unsupported; "
+ "sample count %d will not work as expected", samples);
+ }
+ if (!rhi->isTextureFormatSupported(rhiTextureFormat)) {
+ qWarning("QRhiWidget: The requested texture format (%d) is not supported by the "
+ "underlying 3D graphics API implementation", int(rhiTextureFormat));
+ }
+ msaaColorBuffer = rhi->newRenderBuffer(QRhiRenderBuffer::Color, newSize, samples, {}, rhiTextureFormat);
+ if (!msaaColorBuffer->create()) {
+ qWarning("Failed to create multisample color buffer for QRhiWidget");
+ delete msaaColorBuffer;
+ msaaColorBuffer = nullptr;
+ return;
+ }
+ }
+ if (!resolveTexture) {
+ if (changed)
+ *changed = true;
+ resolveTexture = rhi->newTexture(rhiTextureFormat, newSize, 1, QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource);
+ if (!resolveTexture->create()) {
+ qWarning("Failed to create resolve texture for QRhiWidget");
+ delete resolveTexture;
+ resolveTexture = nullptr;
+ return;
+ }
+ }
+ } else if (resolveTexture) {
+ resolveTexture->deleteLater();
+ resolveTexture = nullptr;
+ }
+
+ if (colorTexture && colorTexture->pixelSize() != newSize) {
+ if (changed)
+ *changed = true;
+ colorTexture->setPixelSize(newSize);
+ if (!colorTexture->create())
+ qWarning("Failed to rebuild texture for QRhiWidget after resizing");
+ }
+
+ if (msaaColorBuffer && msaaColorBuffer->pixelSize() != newSize) {
+ if (changed)
+ *changed = true;
+ msaaColorBuffer->setPixelSize(newSize);
+ if (!msaaColorBuffer->create())
+ qWarning("Failed to rebuild multisample color buffer for QRhiWidget after resizing");
+ }
+
+ if (resolveTexture && resolveTexture->pixelSize() != newSize) {
+ if (changed)
+ *changed = true;
+ resolveTexture->setPixelSize(newSize);
+ if (!resolveTexture->create())
+ qWarning("Failed to rebuild resolve texture for QRhiWidget after resizing");
+ }
+
+ textureInvalid = false;
+}
+
+bool QRhiWidgetPrivate::invokeInitialize(QRhiCommandBuffer *cb)
+{
+ Q_Q(QRhiWidget);
+ if (!colorTexture && !msaaColorBuffer)
+ return false;
+
+ if (autoRenderTarget) {
+ const QSize pixelSize = colorTexture ? colorTexture->pixelSize() : msaaColorBuffer->pixelSize();
+ if (!depthStencilBuffer) {
+ depthStencilBuffer = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, pixelSize, samples);
+ if (!depthStencilBuffer->create()) {
+ qWarning("Failed to create depth-stencil buffer for QRhiWidget");
+ resetRenderTargetObjects();
+ return false;
+ }
+ } else if (depthStencilBuffer->pixelSize() != pixelSize) {
+ depthStencilBuffer->setPixelSize(pixelSize);
+ if (!depthStencilBuffer->create()) {
+ qWarning("Failed to rebuild depth-stencil buffer for QRhiWidget with new size");
+ return false;
+ }
+ }
+
+ if (!renderTarget) {
+ QRhiColorAttachment color0;
+ if (colorTexture)
+ color0.setTexture(colorTexture);
+ else
+ color0.setRenderBuffer(msaaColorBuffer);
+ if (samples > 1)
+ color0.setResolveTexture(resolveTexture);
+ QRhiTextureRenderTargetDescription rtDesc(color0, depthStencilBuffer);
+ renderTarget = rhi->newTextureRenderTarget(rtDesc);
+ renderPassDescriptor = renderTarget->newCompatibleRenderPassDescriptor();
+ renderTarget->setRenderPassDescriptor(renderPassDescriptor);
+ if (!renderTarget->create()) {
+ qWarning("Failed to create render target for QRhiWidget");
+ resetRenderTargetObjects();
+ return false;
+ }
+ }
+ } else {
+ resetRenderTargetObjects();
+ }
+
+ q->initialize(cb);
+
+ return true;
+}
+
+/*!
+ \return the currently set graphics API (QRhi backend).
+
+ \sa setApi()
+ */
+QRhiWidget::Api QRhiWidget::api() const
+{
+ Q_D(const QRhiWidget);
+ switch (d->config.api()) {
+ case QPlatformBackingStoreRhiConfig::OpenGL:
+ return Api::OpenGL;
+ case QPlatformBackingStoreRhiConfig::Metal:
+ return Api::Metal;
+ case QPlatformBackingStoreRhiConfig::Vulkan:
+ return Api::Vulkan;
+ case QPlatformBackingStoreRhiConfig::D3D11:
+ return Api::Direct3D11;
+ case QPlatformBackingStoreRhiConfig::D3D12:
+ return Api::Direct3D12;
+ case QPlatformBackingStoreRhiConfig::Null:
+ return Api::Null;
+ }
+ Q_UNREACHABLE_RETURN(Api::Null);
+}
+
+/*!
+ Sets the graphics API and QRhi backend to use to \a api.
+
+ \warning This function must be called early enough, before the widget is
+ added to a widget hierarchy and displayed on screen. For example, aim to
+ call the function for the subclass constructor. If called too late, the
+ function will have no effect.
+
+ The default value depends on the platform: Metal on macOS and iOS, Direct
+ 3D 11 on Windows, OpenGL otherwise.
+
+ The \a api can only be set once for the widget and its top-level window,
+ once it is done and takes effect, the window can only use that API and QRhi
+ backend to render. Attempting to set another value, or to add another
+ QRhiWidget with a different \a api will not function as expected.
+
+ \sa setColorBufferFormat(), setDebugLayerEnabled(), api()
+ */
+void QRhiWidget::setApi(Api api)
+{
+ Q_D(QRhiWidget);
+ switch (api) {
+ case Api::OpenGL:
+ d->config.setApi(QPlatformBackingStoreRhiConfig::OpenGL);
+ break;
+ case Api::Metal:
+ d->config.setApi(QPlatformBackingStoreRhiConfig::Metal);
+ break;
+ case Api::Vulkan:
+ d->config.setApi(QPlatformBackingStoreRhiConfig::Vulkan);
+ break;
+ case Api::Direct3D11:
+ d->config.setApi(QPlatformBackingStoreRhiConfig::D3D11);
+ break;
+ case Api::Direct3D12:
+ d->config.setApi(QPlatformBackingStoreRhiConfig::D3D12);
+ break;
+ case Api::Null:
+ d->config.setApi(QPlatformBackingStoreRhiConfig::Null);
+ break;
+ }
+}
+
+/*!
+ \return true if a debug or validation layer will be requested if applicable
+ to the graphics API in use.
+
+ \sa setDebugLayerEnabled()
+ */
+bool QRhiWidget::isDebugLayerEnabled() const
+{
+ Q_D(const QRhiWidget);
+ return d->config.isDebugLayerEnabled();
+}
+
+/*!
+ Requests the debug or validation layer of the underlying graphics API
+ when \a enable is true.
+
+ \warning This function must be called early enough, before the widget is added
+ to a widget hierarchy and displayed on screen. For example, aim to call the
+ function for the subclass constructor. If called too late, the function
+ will have no effect.
+
+ Applicable for Vulkan and Direct 3D.
+
+ By default this is disabled.
+
+ \sa setApi(), isDebugLayerEnabled()
+ */
+void QRhiWidget::setDebugLayerEnabled(bool enable)
+{
+ Q_D(QRhiWidget);
+ d->config.setDebugLayer(enable);
+}
+
+/*!
+ \property QRhiWidget::colorBufferFormat
+
+ This property controls the texture format of the texture (or renderbuffer)
+ used as the color buffer. The default value is TextureFormat::RGBA8.
+ QRhiWidget supports rendering to a subset of the formats supported by \l
+ QRhiTexture. Only formats that are reported as supported from \l
+ QRhi::isTextureFormatSupported() should be specified, rendering will not be
+ functional otherwise.
+
+ \note Setting a new format when the widget is already initialized and has
+ rendered implies that all QRhiGraphicsPipeline objects created by the
+ renderer may become unusable, if the associated QRhiRenderPassDescriptor is
+ now incompatible due to the different texture format. Similarly to changing
+ \l sampleCount dynamically, this means that initialize() or render()
+ implementations must then take care of releasing the existing pipelines and
+ creating new ones.
+ */
+
+QRhiWidget::TextureFormat QRhiWidget::colorBufferFormat() const
+{
+ Q_D(const QRhiWidget);
+ return d->widgetTextureFormat;
+}
+
+void QRhiWidget::setColorBufferFormat(TextureFormat format)
+{
+ Q_D(QRhiWidget);
+ if (d->widgetTextureFormat != format) {
+ d->widgetTextureFormat = format;
+ switch (format) {
+ case TextureFormat::RGBA8:
+ d->rhiTextureFormat = QRhiTexture::RGBA8;
+ break;
+ case TextureFormat::RGBA16F:
+ d->rhiTextureFormat = QRhiTexture::RGBA16F;
+ break;
+ case TextureFormat::RGBA32F:
+ d->rhiTextureFormat = QRhiTexture::RGBA32F;
+ break;
+ case TextureFormat::RGB10A2:
+ d->rhiTextureFormat = QRhiTexture::RGB10A2;
+ break;
+ }
+ emit colorBufferFormatChanged(format);
+ update();
+ }
+}
+
+/*!
+ \property QRhiWidget::sampleCount
+
+ This property controls for sample count for multisample antialiasing.
+ By default the value is \c 1 which means MSAA is disabled.
+
+ Valid values are 1, 4, 8, and sometimes 16 and 32.
+ \l QRhi::supportedSampleCounts() can be used to query the supported sample
+ counts at run time, but typically applications should request 1 (no MSAA),
+ 4x (normal MSAA) or 8x (high MSAA).
+
+ \note Setting a new value implies that all QRhiGraphicsPipeline objects
+ created by the renderer must use the same sample count from then on.
+ Existing QRhiGraphicsPipeline objects created with a different sample count
+ must not be used anymore. When the value changes, all color and
+ depth-stencil buffers are destroyed and recreated automatically, and
+ initialize() is invoked again. However, when
+ \l autoRenderTarget is \c false, it will be up to the application to
+ manage this with regards to the depth-stencil buffer or additional color
+ buffers.
+
+ Changing the sample count from the default 1 to a higher value implies that
+ colorTexture() becomes \nullptr and msaaColorBuffer() starts returning a
+ valid object. Switching back to 1 (or 0), implies the opposite: in the next
+ call to initialize() msaaColorBuffer() is going to return \nullptr, whereas
+ colorTexture() becomes once again valid. In addition, resolveTexture()
+ returns a valid (non-multisample) QRhiTexture whenever the sample count is
+ greater than 1 (i.e., MSAA is in use).
+
+ \sa msaaColorBuffer(), resolveTexture()
+ */
+
+int QRhiWidget::sampleCount() const
+{
+ Q_D(const QRhiWidget);
+ return d->samples;
+}
+
+void QRhiWidget::setSampleCount(int samples)
+{
+ Q_D(QRhiWidget);
+ if (d->samples != samples) {
+ d->samples = samples;
+ emit sampleCountChanged(samples);
+ update();
+ }
+}
+
+/*!
+ \property QRhiWidget::fixedColorBufferSize
+
+ The fixed size, in pixels, of the QRhiWidget's associated texture. Relevant
+ when a fixed texture size is desired that does not depend on the widget's
+ size. This size has no effect on the geometry of the widget (its size and
+ placement within the top-level window), which means the texture's content
+ will appear stretched (scaled up) or scaled down onto the widget's area.
+
+ For example, setting a size that is exactly twice the widget's (pixel) size
+ effectively performs 2x supersampling (rendering at twice the resolution
+ and then implicitly scaling down when texturing the quad corresponding to
+ the widget in the window).
+
+ By default the value is a null QSize. A null or empty QSize means that the
+ texture's size follows the QRhiWidget's size. (\c{texture size} = \c{widget
+ size} * \c{device pixel ratio}).
+ */
+
+QSize QRhiWidget::fixedColorBufferSize() const
+{
+ Q_D(const QRhiWidget);
+ return d->fixedSize;
+}
+
+void QRhiWidget::setFixedColorBufferSize(QSize pixelSize)
+{
+ Q_D(QRhiWidget);
+ if (d->fixedSize != pixelSize) {
+ d->fixedSize = pixelSize;
+ emit fixedColorBufferSizeChanged(pixelSize);
+ update();
+ }
+}
+
+/*!
+ \property QRhiWidget::mirrorVertically
+
+ When enabled, flips the image around the X axis when compositing the
+ QRhiWidget's backing texture with the rest of the widget content in the
+ top-level window.
+
+ The default value is \c false.
+ */
+
+bool QRhiWidget::isMirrorVerticallyEnabled() const
+{
+ Q_D(const QRhiWidget);
+ return d->mirrorVertically;
+}
+
+void QRhiWidget::setMirrorVertically(bool enabled)
+{
+ Q_D(QRhiWidget);
+ if (d->mirrorVertically != enabled) {
+ d->mirrorVertically = enabled;
+ emit mirrorVerticallyChanged(enabled);
+ update();
+ }
+}
+
+/*!
+ \property QRhiWidget::autoRenderTarget
+
+ The current setting for automatic depth-stencil buffer and render
+ target maintenance.
+
+ By default the value is \c true.
+ */
+bool QRhiWidget::isAutoRenderTargetEnabled() const
+{
+ Q_D(const QRhiWidget);
+ return d->autoRenderTarget;
+}
+
+/*!
+ Controls if a depth-stencil QRhiRenderBuffer and a QRhiTextureRenderTarget
+ is created and maintained automatically by the widget. The default value is
+ \c true.
+
+ In automatic mode, the size and sample count of the depth-stencil buffer
+ follows the color buffer texture's settings. In non-automatic mode,
+ renderTarget() and depthStencilBuffer() always return \nullptr and it is
+ then up to the application's implementation of initialize() to take care of
+ setting up and managing these objects.
+
+ Call this function with \a enabled set to \c false early on, for example in
+ the derived class' constructor, to disable the automatic mode.
+ */
+void QRhiWidget::setAutoRenderTarget(bool enabled)
+{
+ Q_D(QRhiWidget);
+ if (d->autoRenderTarget != enabled) {
+ d->autoRenderTarget = enabled;
+ update();
+ }
+}
+
+/*!
+ Renders a new frame, reads the contents of the texture back, and returns it
+ as a QImage.
+
+ When an error occurs, a null QImage is returned.
+
+ The returned QImage will have a format of QImage::Format_RGBA8888,
+ QImage::Format_RGBA16FPx4, QImage::Format_RGBA32FPx4, or
+ QImage::Format_BGR30, depending on colorBufferFormat().
+
+ QRhiWidget does not know the renderer's approach to blending and
+ composition, and therefore cannot know if the output has alpha
+ premultiplied in the RGB color values. Thus \c{_Premultiplied} QImage
+ formats are never used for the returned QImage, even when it would be
+ appropriate. It is up to the caller to reinterpret the resulting data as it
+ sees fit.
+
+ \note This function can also be called when the QRhiWidget is not added to
+ a widget hierarchy belonging to an on-screen top-level window. This allows
+ generating an image from a 3D rendering off-screen.
+
+ The function is named grabFramebuffer() for consistency with QOpenGLWidget
+ and QQuickWidget. It is not the only way to get CPU-side image data out of
+ the QRhiWidget's content: calling \l QWidget::grab() on a QRhiWidget, or an
+ ancestor of it, is functional as well (returning a QPixmap). Besides
+ working directly with QImage, another advantage of grabFramebuffer() is
+ that it may be slightly more performant, simply because it does not have to
+ go through the rest of QWidget infrastructure but can right away trigger
+ rendering a new frame and then do the readback.
+
+ \sa setColorBufferFormat()
+ */
+QImage QRhiWidget::grabFramebuffer() const
+{
+ return const_cast<QRhiWidgetPrivate *>(d_func())->grabFramebuffer();
+}
+
+/*!
+ Called when the widget is initialized for the first time, when the
+ associated texture's size, format, or sample count changes, or when the
+ QRhi and texture change for any reason. The function is expected to
+ maintain (create if not yet created, adjust and rebuild if the size has
+ changed) the graphics resources used by the rendering code in render().
+
+ To query the QRhi, QRhiTexture, and other related objects, call rhi(),
+ colorTexture(), depthStencilBuffer(), and renderTarget().
+
+ When the widget size changes, the QRhi object, the color buffer texture,
+ and the depth stencil buffer objects are all the same instances (so the
+ getters return the same pointers) as before, but the color and
+ depth/stencil buffers will likely have been rebuilt, meaning the
+ \l{QRhiTexture::pixelSize()}{size} and the underlying native texture
+ resource may be different than in the last invocation.
+
+ Reimplementations should also be prepared that the QRhi object and the
+ color buffer texture may change between invocations of this function. One
+ special case where the objects will be different is when performing a
+ grabFramebuffer() with a widget that is not yet shown, and then making the
+ widget visible on-screen within a top-level widget. There the grab will
+ happen with a dedicated QRhi that is then replaced with the top-level
+ window's associated QRhi in subsequent initialize() and render()
+ invocations. Another, more common case is when the widget is reparented so
+ that it belongs to a new top-level window. In this case the QRhi and all
+ related resources managed by the QRhiWidget will be different instances
+ than before in the subsequent call to this function. Is is then important
+ that all existing QRhi resources previously created by the subclass are
+ destroyed because they belong to the previous QRhi that should not be used
+ by the widget anymore.
+
+ When \l autoRenderTarget is \c true, which is the default, a
+ depth-stencil QRhiRenderBuffer and a QRhiTextureRenderTarget associated
+ with colorTexture() (or msaaColorBuffer()) and the depth-stencil buffer are
+ created and managed automatically. Reimplementations of initialize() and
+ render() can query those objects via depthStencilBuffer() and
+ renderTarget(). When \l autoRenderTarget is set to \c false, these
+ objects are no longer created and managed automatically. Rather, it will be
+ up the the initialize() implementation to create buffers and set up the
+ render target as it sees fit. When manually managing additional color or
+ depth-stencil attachments for the render target, their size and sample
+ count must always follow the size and sample count of colorTexture() /
+ msaaColorBuffer(), otherwise rendering or 3D API validation errors may
+ occur.
+
+ The subclass-created graphics resources are expected to be released in the
+ destructor implementation of the subclass.
+
+ \a cb is the QRhiCommandBuffer for the current frame of the widget. The
+ function is called with a frame being recorded, but without an active
+ render pass. The command buffer is provided primarily to allow enqueuing
+ \l{QRhiCommandBuffer::resourceUpdate()}{resource updates} without deferring
+ to render().
+
+ \sa render()
+ */
+void QRhiWidget::initialize(QRhiCommandBuffer *cb)
+{
+ Q_UNUSED(cb);
+}
+
+/*!
+ Called when the widget contents (i.e. the contents of the texture) need
+ updating.
+
+ There is always at least one call to initialize() before this function is
+ called.
+
+ To request updates, call QWidget::update(). Calling update() from within
+ render() will lead to updating continuously, throttled by vsync.
+
+ \a cb is the QRhiCommandBuffer for the current frame of the widget. The
+ function is called with a frame being recorded, but without an active
+ render pass.
+
+ \sa initialize()
+ */
+void QRhiWidget::render(QRhiCommandBuffer *cb)
+{
+ Q_UNUSED(cb);
+}
+
+/*!
+ Called when the need to early-release the graphics resources arises.
+
+ This normally does not happen for a QRhiWidget that is added to a top-level
+ widget's child hierarchy and it then stays there for the rest of its and
+ the top-level's lifetime. Thus in many cases there is no need to
+ reimplement this function, e.g. because the application only ever has a
+ single top-level widget (native window). However, when reparenting of the
+ widget (or an ancestor of it) is involved, reimplementing this function
+ will become necessary in robust, well-written QRhiWidget subclasses.
+
+ When this function is called, the implementation is expected to destroy all
+ QRhi resources (QRhiBuffer, QRhiTexture, etc. objects), similarly to how it
+ is expected to do this in the destructor. Nulling out, using a smart
+ pointer, or setting a \c{resources-invalid} flag is going to be required as
+ well, because initialize() will eventually get called afterwards. Note
+ however that deferring the releasing of resources to the subsequent
+ initialize() is wrong. If this function is called, the resource must be
+ dropped before returning. Also note that implementing this function does
+ not replace the class destructor (or smart pointers): the graphics
+ resources must still be released in both.
+
+ See the \l{Cube RHI Widget Example} for an example of this in action. There
+ the button that toggles the QRhiWidget between being a child widget (due to
+ having a parent widget) and being a top-level widget (due to having no
+ parent widget), will trigger invoking this function since the associated
+ top-level widget, native window, and QRhi all change during the lifetime of
+ the QRhiWidget, with the previously used QRhi getting destroyed which
+ implies an early-release of the associated resources managed by the
+ still-alive QRhiWidget.
+
+ Another case when this function is called is when grabFramebuffer() is used
+ with a QRhiWidget that is not added to a visible window, i.e. the rendering
+ is performed offscreen. If later on this QRhiWidget is made visible, or
+ added to a visible widget hierarchy, the associated QRhi will change from
+ the temporary one used for offscreen rendering to the window's dedicated
+ one, thus triggering this function as well.
+
+ \sa initialize()
+ */
+void QRhiWidget::releaseResources()
+{
+}
+
+/*!
+ \return the current QRhi object.
+
+ Must only be called from initialize() and render().
+ */
+QRhi *QRhiWidget::rhi() const
+{
+ Q_D(const QRhiWidget);
+ return d->rhi;
+}
+
+/*!
+ \return the texture serving as the color buffer for the widget.
+
+ Must only be called from initialize() and render().
+
+ Unlike the depth-stencil buffer and the QRhiRenderTarget, this texture is
+ always available and is managed by the QRhiWidget, independent of the value
+ of \l autoRenderTarget.
+
+ \note When \l sampleCount is larger than 1, and so multisample antialiasing
+ is enabled, the return value is \nullptr. Instead, query the
+ \l QRhiRenderBuffer by calling msaaColorBuffer().
+
+ \note The backing texture size and sample count can also be queried via the
+ QRhiRenderTarget returned from renderTarget(). This can be more convenient
+ and compact than querying from the QRhiTexture or QRhiRenderBuffer, because
+ it works regardless of multisampling is in use or not.
+
+ \sa msaaColorBuffer(), depthStencilBuffer(), renderTarget(), resolveTexture()
+ */
+QRhiTexture *QRhiWidget::colorTexture() const
+{
+ Q_D(const QRhiWidget);
+ return d->colorTexture;
+}
+
+/*!
+ \return the renderbuffer serving as the multisample color buffer for the widget.
+
+ Must only be called from initialize() and render().
+
+ When \l sampleCount is larger than 1, and so multisample antialising is
+ enabled, the returned QRhiRenderBuffer has a matching sample count and
+ serves as the color buffer. Graphics pipelines used to render into this
+ buffer must be created with the same sample count, and the depth-stencil
+ buffer's sample count must match as well. The multisample content is
+ expected to be resolved into the texture returned from resolveTexture().
+ When \l autoRenderTarget is
+ \c true, renderTarget() is set up automatically to do this, by setting up
+ msaaColorBuffer() as the \l{QRhiColorAttachment::renderBuffer()}{renderbuffer} of
+ color attachment 0 and resolveTexture() as its
+ \l{QRhiColorAttachment::resolveTexture()}{resolveTexture}.
+
+ When MSAA is not in use, the return value is \nullptr. Use colorTexture()
+ instead then.
+
+ Depending on the underlying 3D graphics API, there may be no practical
+ difference between multisample textures and color renderbuffers with a
+ sample count larger than 1 (QRhi may just map both to the same native
+ resource type). Some older APIs however may differentiate between textures
+ and renderbuffers. In order to support OpenGL ES 3.0, where multisample
+ renderbuffers are available, but multisample textures are not, QRhiWidget
+ always performs MSAA by using a multisample QRhiRenderBuffer as the color
+ attachment (and never a multisample QRhiTexture).
+
+ \note The backing texture size and sample count can also be queried via the
+ QRhiRenderTarget returned from renderTarget(). This can be more convenient
+ and compact than querying from the QRhiTexture or QRhiRenderBuffer, because
+ it works regardless of multisampling is in use or not.
+
+ \sa colorTexture(), depthStencilBuffer(), renderTarget(), resolveTexture()
+ */
+QRhiRenderBuffer *QRhiWidget::msaaColorBuffer() const
+{
+ Q_D(const QRhiWidget);
+ return d->msaaColorBuffer;
+}
+
+/*!
+ \return the non-multisample texture to which the multisample content is resolved.
+
+ The result is \nullptr when multisample antialiasing is not enabled.
+
+ Must only be called from initialize() and render().
+
+ With MSAA enabled, this is the texture that gets composited with the rest
+ of the QWidget content on-screen. However, the QRhiWidget's rendering must
+ target the (multisample) QRhiRenderBuffer returned from
+ msaaColorBuffer(). When
+ \l autoRenderTarget is \c true, this is taken care of by the
+ QRhiRenderTarget returned from renderTarget(). Otherwise, it is up to the
+ subclass code to correctly configure a render target object with both the
+ color buffer and resolve textures.
+
+ \sa colorTexture()
+ */
+QRhiTexture *QRhiWidget::resolveTexture() const
+{
+ Q_D(const QRhiWidget);
+ return d->resolveTexture;
+}
+
+/*!
+ \return the depth-stencil buffer used by the widget's rendering.
+
+ Must only be called from initialize() and render().
+
+ Available only when \l autoRenderTarget is \c true. Otherwise the
+ returned value is \nullptr and it is up the reimplementation of
+ initialize() to create and manage a depth-stencil buffer and a
+ QRhiTextureRenderTarget.
+
+ \sa colorTexture(), renderTarget()
+ */
+QRhiRenderBuffer *QRhiWidget::depthStencilBuffer() const
+{
+ Q_D(const QRhiWidget);
+ return d->depthStencilBuffer;
+}
+
+/*!
+ \return the render target object that must be used with
+ \l QRhiCommandBuffer::beginPass() in reimplementations of render().
+
+ Must only be called from initialize() and render().
+
+ Available only when \l autoRenderTarget is \c true. Otherwise the
+ returned value is \nullptr and it is up the reimplementation of
+ initialize() to create and manage a depth-stencil buffer and a
+ QRhiTextureRenderTarget.
+
+ When creating \l{QRhiGraphicsPipeline}{graphics pipelines}, a
+ QRhiRenderPassDescriptor is needed. This can be queried from the returned
+ QRhiTextureRenderTarget by calling
+ \l{QRhiTextureRenderTarget::renderPassDescriptor()}{renderPassDescriptor()}.
+
+ \sa colorTexture(), depthStencilBuffer()
+ */
+QRhiRenderTarget *QRhiWidget::renderTarget() const
+{
+ Q_D(const QRhiWidget);
+ return d->renderTarget;
+}
+
+/*!
+ \fn void QRhiWidget::frameSubmitted()
+
+ This signal is emitted after the widget's top-level window has finished
+ composition and has \l{QRhi::endFrame()}{submitted a frame}.
+*/
+
+/*!
+ \fn void QRhiWidget::renderFailed()
+
+ This signal is emitted whenever the widget is supposed to render to its
+ backing texture (either due to a \l{QWidget::update()}{widget update} or
+ due to a call to grabFramebuffer()), but there is no \l QRhi for the widget to
+ use, likely due to issues related to graphics configuration.
+
+ This signal may be emitted multiple times when a problem arises. Do not
+ assume it is emitted only once. Connect with Qt::SingleShotConnection if
+ the error handling code is to be notified only once.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/widgets/kernel/qrhiwidget.h b/src/widgets/kernel/qrhiwidget.h
new file mode 100644
index 0000000000..45fe7b7482
--- /dev/null
+++ b/src/widgets/kernel/qrhiwidget.h
@@ -0,0 +1,101 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QRHIWIDGET_H
+#define QRHIWIDGET_H
+
+#include <QtWidgets/qwidget.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRhiWidgetPrivate;
+class QRhi;
+class QRhiTexture;
+class QRhiRenderBuffer;
+class QRhiRenderTarget;
+class QRhiCommandBuffer;
+
+class Q_WIDGETS_EXPORT QRhiWidget : public QWidget
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QRhiWidget)
+ Q_PROPERTY(int sampleCount READ sampleCount WRITE setSampleCount NOTIFY sampleCountChanged)
+ Q_PROPERTY(TextureFormat colorBufferFormat READ colorBufferFormat WRITE setColorBufferFormat NOTIFY colorBufferFormatChanged)
+ Q_PROPERTY(QSize fixedColorBufferSize READ fixedColorBufferSize WRITE setFixedColorBufferSize NOTIFY fixedColorBufferSizeChanged)
+ Q_PROPERTY(bool mirrorVertically READ isMirrorVerticallyEnabled WRITE setMirrorVertically NOTIFY mirrorVerticallyChanged)
+ QDOC_PROPERTY(bool autoRenderTarget READ isAutoRenderTargetEnabled WRITE setAutoRenderTarget)
+
+public:
+ explicit QRhiWidget(QWidget *parent = nullptr, Qt::WindowFlags f = {});
+ ~QRhiWidget() override;
+
+ enum class Api {
+ Null,
+ OpenGL,
+ Metal,
+ Vulkan,
+ Direct3D11,
+ Direct3D12,
+ };
+ Q_ENUM(Api)
+
+ enum class TextureFormat {
+ RGBA8,
+ RGBA16F,
+ RGBA32F,
+ RGB10A2,
+ };
+ Q_ENUM(TextureFormat)
+
+ Api api() const;
+ void setApi(Api api);
+
+ bool isDebugLayerEnabled() const;
+ void setDebugLayerEnabled(bool enable);
+
+ int sampleCount() const;
+ void setSampleCount(int samples);
+
+ TextureFormat colorBufferFormat() const;
+ void setColorBufferFormat(TextureFormat format);
+
+ QSize fixedColorBufferSize() const;
+ void setFixedColorBufferSize(QSize pixelSize);
+ void setFixedColorBufferSize(int w, int h) { setFixedColorBufferSize(QSize(w, h)); }
+
+ bool isMirrorVerticallyEnabled() const;
+ void setMirrorVertically(bool enabled);
+
+ QImage grabFramebuffer() const;
+
+protected:
+ bool isAutoRenderTargetEnabled() const;
+ void setAutoRenderTarget(bool enabled);
+
+ virtual void initialize(QRhiCommandBuffer *cb);
+ virtual void render(QRhiCommandBuffer *cb);
+ virtual void releaseResources();
+
+ QRhi *rhi() const;
+ QRhiTexture *colorTexture() const;
+ QRhiRenderBuffer *msaaColorBuffer() const;
+ QRhiTexture *resolveTexture() const;
+ QRhiRenderBuffer *depthStencilBuffer() const;
+ QRhiRenderTarget *renderTarget() const;
+
+ void resizeEvent(QResizeEvent *e) override;
+ void paintEvent(QPaintEvent *e) override;
+ bool event(QEvent *e) override;
+
+Q_SIGNALS:
+ void frameSubmitted();
+ void renderFailed();
+ void sampleCountChanged(int samples);
+ void colorBufferFormatChanged(TextureFormat format);
+ void fixedColorBufferSizeChanged(const QSize &pixelSize);
+ void mirrorVerticallyChanged(bool enabled);
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/widgets/kernel/qrhiwidget_p.h b/src/widgets/kernel/qrhiwidget_p.h
new file mode 100644
index 0000000000..b594b67ec8
--- /dev/null
+++ b/src/widgets/kernel/qrhiwidget_p.h
@@ -0,0 +1,64 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QRHIWIDGET_P_H
+#define QRHIWIDGET_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 "qrhiwidget.h"
+#include <rhi/qrhi.h>
+#include <private/qwidget_p.h>
+#include <private/qbackingstorerhisupport_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRhiWidgetPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QRhiWidget)
+public:
+ TextureData texture() const override;
+ QPlatformTextureList::Flags textureListFlags() override;
+ QPlatformBackingStoreRhiConfig rhiConfig() const override;
+ void endCompose() override;
+ QImage grabFramebuffer() override;
+
+ void ensureRhi();
+ void ensureTexture(bool *changed);
+ bool invokeInitialize(QRhiCommandBuffer *cb);
+ void resetColorBufferObjects();
+ void resetRenderTargetObjects();
+ void releaseResources();
+
+ QRhi *rhi = nullptr;
+ bool noSize = false;
+ QPlatformBackingStoreRhiConfig config;
+ QRhiWidget::TextureFormat widgetTextureFormat = QRhiWidget::TextureFormat::RGBA8;
+ QRhiTexture::Format rhiTextureFormat = QRhiTexture::RGBA8;
+ int samples = 1;
+ QSize fixedSize;
+ bool autoRenderTarget = true;
+ bool mirrorVertically = false;
+ QBackingStoreRhiSupport offscreenRenderer;
+ bool textureInvalid = false;
+ QRhiTexture *colorTexture = nullptr;
+ QRhiRenderBuffer *msaaColorBuffer = nullptr;
+ QRhiTexture *resolveTexture = nullptr;
+ QRhiRenderBuffer *depthStencilBuffer = nullptr;
+ QRhiTextureRenderTarget *renderTarget = nullptr;
+ QRhiRenderPassDescriptor *renderPassDescriptor = nullptr;
+ mutable QVector<QRhiResource *> pendingDeletes;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/widgets/kernel/qshortcut_widgets.cpp b/src/widgets/kernel/qshortcut_widgets.cpp
index cb184ef07d..6e25d79bd6 100644
--- a/src/widgets/kernel/qshortcut_widgets.cpp
+++ b/src/widgets/kernel/qshortcut_widgets.cpp
@@ -65,9 +65,6 @@ bool qWidgetShortcutContextMatcher(QObject *object, Qt::ShortcutContext context)
}
}
- if (!active_window)
- return false;
-
#if QT_CONFIG(action)
if (auto a = qobject_cast<QAction *>(object))
return correctActionContext(context, a, active_window);
@@ -95,14 +92,17 @@ bool qWidgetShortcutContextMatcher(QObject *object, Qt::ShortcutContext context)
}
}
- if (!w)
- return false;
+ if (w)
+ return correctWidgetContext(context, w, active_window);
- return correctWidgetContext(context, w, active_window);
+ return QShortcutPrivate::simpleContextMatcher(object, context);
}
static bool correctWidgetContext(Qt::ShortcutContext context, QWidget *w, QWidget *active_window)
{
+ if (!active_window)
+ return false;
+
bool visible = w->isVisible();
#if QT_CONFIG(menubar)
if (auto menuBar = qobject_cast<QMenuBar *>(w)) {
@@ -188,6 +188,9 @@ static bool correctWidgetContext(Qt::ShortcutContext context, QWidget *w, QWidge
#if QT_CONFIG(graphicsview)
static bool correctGraphicsWidgetContext(Qt::ShortcutContext context, QGraphicsWidget *w, QWidget *active_window)
{
+ if (!active_window)
+ return false;
+
bool visible = w->isVisible();
#if defined(Q_OS_DARWIN) && QT_CONFIG(menubar)
if (!QCoreApplication::testAttribute(Qt::AA_DontUseNativeMenuBar) && qobject_cast<QMenuBar *>(w))
@@ -247,6 +250,9 @@ static bool correctGraphicsWidgetContext(Qt::ShortcutContext context, QGraphicsW
#if QT_CONFIG(action)
static bool correctActionContext(Qt::ShortcutContext context, QAction *a, QWidget *active_window)
{
+ if (!active_window)
+ return false;
+
const QObjectList associatedObjects = a->associatedObjects();
#if defined(DEBUG_QSHORTCUTMAP)
if (associatedObjects.isEmpty())
diff --git a/src/widgets/kernel/qstackedlayout.cpp b/src/widgets/kernel/qstackedlayout.cpp
index aca470fe1c..04eacf1d41 100644
--- a/src/widgets/kernel/qstackedlayout.cpp
+++ b/src/widgets/kernel/qstackedlayout.cpp
@@ -8,6 +8,8 @@
#include "private/qwidget_p.h"
#include "private/qlayoutengine_p.h"
+#include <QtCore/qpointer.h>
+
#include <memory>
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/kernel/qtestsupport_widgets.cpp b/src/widgets/kernel/qtestsupport_widgets.cpp
index 3aa13b2416..f7b25b6643 100644
--- a/src/widgets/kernel/qtestsupport_widgets.cpp
+++ b/src/widgets/kernel/qtestsupport_widgets.cpp
@@ -16,8 +16,8 @@
QT_BEGIN_NAMESPACE
-template <typename FunctorWindowGetter, typename FunctorPredicate>
-static bool qWaitForWidgetWindow(FunctorWindowGetter windowGetter, FunctorPredicate predicate, int timeout)
+template <typename FunctorWindowGetter, typename FunctorPredicate, typename Timeout>
+static bool qWaitForWidgetWindow(FunctorWindowGetter windowGetter, FunctorPredicate predicate, Timeout timeout)
{
if (!windowGetter())
return false;
@@ -60,6 +60,32 @@ Q_WIDGETS_EXPORT bool QTest::qWaitForWindowActive(QWidget *widget, int timeout)
timeout);
}
+
+/*!
+ \since 6.7
+
+ Returns \c true, if \a widget is the focus window within \a timeout. Otherwise returns \c false.
+
+ The method is useful in tests that call QWidget::show() and rely on the widget
+ having focus (for receiving keyboard events e.g.) before proceeding.
+
+ \note The method will time out and return \c false if another window prevents \a widget from
+ becoming focused.
+
+ \note Since focus is an exclusive property, \a widget may loose its focus to another window at
+ any time - even after the method has returned \c true.
+
+ \sa qWaitForWindowExposed(), qWaitForWindowActive(), QGuiApplication::focusWindow()
+*/
+Q_WIDGETS_EXPORT bool QTest::qWaitForWindowFocused(QWidget *widget, QDeadlineTimer timeout)
+{
+ return qWaitForWidgetWindow([&]() {
+ return widget->window()->windowHandle();
+ }, [&](QWindow *window) {
+ return qGuiApp->focusWindow() == window;
+ }, timeout);
+}
+
/*!
\since 5.0
diff --git a/src/widgets/kernel/qtestsupport_widgets.h b/src/widgets/kernel/qtestsupport_widgets.h
index 84b529ae31..b49e68db65 100644
--- a/src/widgets/kernel/qtestsupport_widgets.h
+++ b/src/widgets/kernel/qtestsupport_widgets.h
@@ -15,6 +15,7 @@ class QWidget;
namespace QTest {
[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowActive(QWidget *widget, int timeout = 5000);
+[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowFocused(QWidget *widget, QDeadlineTimer timeout = std::chrono::seconds{5});
[[nodiscard]] Q_WIDGETS_EXPORT bool qWaitForWindowExposed(QWidget *widget, int timeout = 5000);
class Q_WIDGETS_EXPORT QTouchEventWidgetSequence : public QTouchEventSequence
diff --git a/src/widgets/kernel/qtooltip.cpp b/src/widgets/kernel/qtooltip.cpp
index 2c68b029b0..35eaa8042a 100644
--- a/src/widgets/kernel/qtooltip.cpp
+++ b/src/widgets/kernel/qtooltip.cpp
@@ -45,15 +45,24 @@ using namespace Qt::StringLiterals;
Rich text displayed in a tool tip is implicitly word-wrapped unless
specified differently with \c{<p style='white-space:pre'>}.
- The simplest and most common way to set a widget's tool tip is by
- calling its QWidget::setToolTip() function.
+ UI elements that are created via \l{QAction} use the tooltip property
+ of the QAction, so for most interactive UI elements, setting that
+ property is the easiest way to provide tool tips.
+
+ \snippet tooltips/main.cpp action_tooltip
+
+ For any other widgets, the simplest and most common way to set
+ a widget's tool tip is by calling its QWidget::setToolTip() function.
+
+ \snippet tooltips/main.cpp static_tooltip
It is also possible to show different tool tips for different
regions of a widget, by using a QHelpEvent of type
QEvent::ToolTip. Intercept the help event in your widget's \l
{QWidget::}{event()} function and call QToolTip::showText() with
- the text you want to display. The \l{widgets/tooltips}{Tooltips}
- example illustrates this technique.
+ the text you want to display.
+
+ \snippet tooltips/main.cpp dynamic_tooltip
If you are calling QToolTip::hideText(), or QToolTip::showText()
with an empty string, as a result of a \l{QEvent::}{ToolTip}-event you
@@ -75,7 +84,7 @@ using namespace Qt::StringLiterals;
\note Tool tips use the inactive color group of QPalette, because tool
tips are not active windows.
- \sa QWidget::toolTip, QAction::toolTip, {Tool Tips Example}
+ \sa QWidget::toolTip, QAction::toolTip
*/
class QTipLabel : public QLabel
@@ -170,8 +179,8 @@ void QTipLabel::reuseTip(const QString &text, int msecDisplayTime, const QPoint
{
#ifndef QT_NO_STYLE_STYLESHEET
if (styleSheetParent){
- disconnect(styleSheetParent, SIGNAL(destroyed()),
- QTipLabel::instance, SLOT(styleSheetParentDestroyed()));
+ disconnect(styleSheetParent, &QWidget::destroyed,
+ this, &QTipLabel::styleSheetParentDestroyed);
styleSheetParent = nullptr;
}
#endif
@@ -320,6 +329,7 @@ bool QTipLabel::eventFilter(QObject *o, QEvent *e)
case QEvent::MouseMove:
if (o == widget && !rect.isNull() && !rect.contains(static_cast<QMouseEvent*>(e)->position().toPoint()))
hideTip();
+ break;
default:
break;
}
@@ -345,12 +355,14 @@ void QTipLabel::placeTip(const QPoint &pos, QWidget *w)
// Set up for cleaning up this later...
QTipLabel::instance->styleSheetParent = w;
if (w) {
- connect(w, SIGNAL(destroyed()),
- QTipLabel::instance, SLOT(styleSheetParentDestroyed()));
- // QTBUG-64550: A font inherited by the style sheet might change the size,
- // particular on Windows, where the tip is not parented on a window.
- QTipLabel::instance->updateSize(pos);
+ connect(w, &QWidget::destroyed,
+ QTipLabel::instance, &QTipLabel::styleSheetParentDestroyed);
}
+ // QTBUG-64550: A font inherited by the style sheet might change the size,
+ // particular on Windows, where the tip is not parented on a window.
+ // The updatesSize() also makes sure that the content size be updated with
+ // correct content margin.
+ QTipLabel::instance->updateSize(pos);
}
#endif //QT_NO_STYLE_STYLESHEET
diff --git a/src/widgets/kernel/qwhatsthis.cpp b/src/widgets/kernel/qwhatsthis.cpp
index 3548d26647..c80f37267f 100644
--- a/src/widgets/kernel/qwhatsthis.cpp
+++ b/src/widgets/kernel/qwhatsthis.cpp
@@ -97,8 +97,6 @@ QT_BEGIN_NAMESPACE
\sa QToolTip
*/
-Q_CORE_EXPORT void qDeleteInEventHandler(QObject *o);
-
class QWhatsThat : public QWidget
{
Q_OBJECT
@@ -110,7 +108,6 @@ public:
static QWhatsThat *instance;
protected:
- void showEvent(QShowEvent *e) override;
void mousePressEvent(QMouseEvent*) override;
void mouseReleaseEvent(QMouseEvent*) override;
void mouseMoveEvent(QMouseEvent*) override;
@@ -123,7 +120,6 @@ private:
QString text;
QTextDocument* doc;
QString anchor;
- QPixmap background;
};
QWhatsThat *QWhatsThat::instance = nullptr;
@@ -197,11 +193,6 @@ QWhatsThat::~QWhatsThat()
delete doc;
}
-void QWhatsThat::showEvent(QShowEvent *)
-{
- background = QGuiApplication::primaryScreen()->grabWindow(0, x(), y(), width(), height());
-}
-
void QWhatsThat::mousePressEvent(QMouseEvent* e)
{
pressed = true;
@@ -261,7 +252,6 @@ void QWhatsThat::paintEvent(QPaintEvent*)
if (drawShadow)
r.adjust(0, 0, -shadowWidth, -shadowWidth);
QPainter p(this);
- p.drawPixmap(0, 0, background);
p.setPen(QPen(palette().toolTipText(), 0));
p.setBrush(palette().toolTipBase());
p.drawRect(r);
@@ -472,7 +462,7 @@ QWhatsThisAction::QWhatsThisAction(QObject *parent) : QAction(tr("What's This?")
setIcon(p);
#endif
setCheckable(true);
- connect(this, SIGNAL(triggered()), this, SLOT(actionTriggered()));
+ connect(this, &QWhatsThisAction::triggered, this, &QWhatsThisAction::actionTriggered);
#ifndef QT_NO_SHORTCUT
setShortcut(Qt::ShiftModifier | Qt::Key_F1);
#endif
@@ -618,7 +608,7 @@ void QWhatsThis::showText(const QPoint &pos, const QString &text, QWidget *w)
*/
void QWhatsThis::hideText()
{
- qDeleteInEventHandler(QWhatsThat::instance);
+ delete QWhatsThat::instance;
}
/*!
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index cb432c84bc..e8342a4788 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -6,6 +6,7 @@
#include "qapplication_p.h"
#include "qbrush.h"
#include "qcursor.h"
+#include "private/qduplicatetracker_p.h"
#include "qevent.h"
#include "qlayout.h"
#if QT_CONFIG(menu)
@@ -82,6 +83,16 @@ using namespace QNativeInterface::Private;
using namespace Qt::StringLiterals;
Q_LOGGING_CATEGORY(lcWidgetPainting, "qt.widgets.painting", QtWarningMsg);
+Q_LOGGING_CATEGORY(lcWidgetShowHide, "qt.widgets.showhide", QtWarningMsg);
+Q_LOGGING_CATEGORY(lcWidgetWindow, "qt.widgets.window", QtWarningMsg);
+Q_LOGGING_CATEGORY(lcWidgetFocus, "qt.widgets.focus")
+
+#ifndef QT_NO_DEBUG_STREAM
+namespace {
+ struct WidgetAttributes { const QWidget *widget; };
+ QDebug operator<<(QDebug debug, const WidgetAttributes &attributes);
+}
+#endif
static inline bool qRectIntersects(const QRect &r1, const QRect &r2)
{
@@ -357,14 +368,14 @@ void QWidget::setAutoFillBackground(bool enabled)
If not, it will be a child of \e parent, and be constrained by
\e parent's geometry (unless you specify Qt::Window as window flag).
\li \c{Qt::WindowFlags f = { }} (where available) sets the window flags;
- the default is suitable for almost all widgets, but to get, for
+ the default is suitable for most widgets, but to get, for
example, a window without a window system frame, you must use
special flags.
\endlist
QWidget has many member functions, but some of them have little direct
functionality; for example, QWidget has a font property, but never uses
- this itself. There are many subclasses which provide real functionality,
+ this itself. There are many subclasses that provide real functionality,
such as QLabel, QPushButton, QListWidget, and QTabWidget.
@@ -372,7 +383,7 @@ void QWidget::setAutoFillBackground(bool enabled)
A widget without a parent widget is always an independent window (top-level
widget). For these widgets, setWindowTitle() and setWindowIcon() set the
- title bar and icon respectively.
+ title bar and icon, respectively.
Non-window widgets are child widgets, displayed within their parent
widgets. Most widgets in Qt are mainly useful as child widgets. For
@@ -385,7 +396,7 @@ void QWidget::setAutoFillBackground(bool enabled)
widgets in a layout provided by QGridLayout. The QLabel child widgets have
been outlined to indicate their full sizes.
- If you want to use a QWidget to hold child widgets you will usually want to
+ If you want to use a QWidget to hold child widgets, you will usually want to
add a layout to the parent QWidget. See \l{Layout Management} for more
information.
@@ -395,8 +406,7 @@ void QWidget::setAutoFillBackground(bool enabled)
When a widget is used as a container to group a number of child widgets, it
is known as a composite widget. These can be created by constructing a
widget with the required visual properties - a QFrame, for example - and
- adding child widgets to it, usually managed by a layout. The above diagram
- shows such a composite widget that was created using Qt Designer.
+ adding child widgets to it, usually managed by a layout.
Composite widgets can also be created by subclassing a standard widget,
such as QWidget or QFrame, and adding the necessary layout and child
@@ -416,7 +426,7 @@ void QWidget::setAutoFillBackground(bool enabled)
Each widget performs all painting operations from within its paintEvent()
function. This is called whenever the widget needs to be redrawn, either
- as a result of some external change or when requested by the application.
+ because of some external change or when requested by the application.
The \l{widgets/analogclock}{Analog Clock example} shows how a simple widget
can handle paint events.
@@ -428,7 +438,7 @@ void QWidget::setAutoFillBackground(bool enabled)
sizeHint() to provide a reasonable default size for the widget and to set
the correct size policy with setSizePolicy().
- By default, composite widgets which do not provide a size hint will be
+ By default, composite widgets that do not provide a size hint will be
sized according to the space requirements of their child widgets.
The size policy lets you supply good default behavior for the layout
@@ -448,9 +458,9 @@ void QWidget::setAutoFillBackground(bool enabled)
delivers events to widgets by calling specific event handler functions with
instances of QEvent subclasses containing information about each event.
- If your widget only contains child widgets, you probably do not need to
+ If your widget only contains child widgets, you probably don't need to
implement any event handlers. If you want to detect a mouse click in a
- child widget call the child's underMouse() function inside the widget's
+ child widget, call the child's underMouse() function inside the widget's
mousePressEvent().
The \l{widgets/scribble}{Scribble example} implements a wider set of
@@ -529,7 +539,7 @@ void QWidget::setAutoFillBackground(bool enabled)
space. (This excludes screen space owned by any of the widget's
children.)
\li leaveEvent() is called when the mouse leaves the widget's screen
- space. If the mouse enters a child widget it will not cause a
+ space. If the mouse enters a child widget, it will not cause a
leaveEvent().
\li moveEvent() is called when the widget has been moved relative to
its parent.
@@ -667,11 +677,11 @@ void QWidget::setAutoFillBackground(bool enabled)
\section1 Transparency and Double Buffering
- Since Qt 4.0, QWidget automatically double-buffers its painting, so there
+ QWidget automatically double-buffers its painting, so there
is no need to write double-buffering code in paintEvent() to avoid
flicker.
- Since Qt 4.1, the contents of parent widgets are propagated by
+ The contents of parent widgets are propagated by
default to each of their children as long as Qt::WA_PaintOnScreen is not
set. Custom widgets can be written to take advantage of this feature by
updating irregular regions (to create non-rectangular child widgets), or
@@ -688,7 +698,7 @@ void QWidget::setAutoFillBackground(bool enabled)
\list
\li The left widget has no additional properties or widget attributes
- set. This default state suits most custom widgets using
+ set. This default state suits most custom widgets that have
transparency, are irregularly-shaped, or do not paint over their
entire area with an opaque brush.
\li The center widget has the \l autoFillBackground property set. This
@@ -699,10 +709,7 @@ void QWidget::setAutoFillBackground(bool enabled)
set. This indicates that the widget will paint over its entire area
with opaque colors. The widget's area will initially be
\e{uninitialized}, represented in the diagram with a red diagonal
- grid pattern that shines through the overpainted area. The
- Qt::WA_OpaquePaintArea attribute is useful for widgets that need to
- paint their own specialized contents quickly and do not need a
- default filled background.
+ grid pattern that shines through the overpainted area.
\endlist
To rapidly update custom widgets with simple background colors, such as
@@ -712,19 +719,18 @@ void QWidget::setAutoFillBackground(bool enabled)
implement the necessary drawing functionality in the widget's paintEvent().
To rapidly update custom widgets that constantly paint over their entire
- areas with opaque content, e.g., video streaming widgets, it is better to
- set the widget's Qt::WA_OpaquePaintEvent, avoiding any unnecessary overhead
- associated with repainting the widget's background.
+ areas with opaque content, for example, video streaming widgets, it is
+ better to set the widget's Qt::WA_OpaquePaintEvent, avoiding any unnecessary
+ overhead associated with repainting the widget's background.
If a widget has both the Qt::WA_OpaquePaintEvent widget attribute \e{and}
the \l autoFillBackground property set, the Qt::WA_OpaquePaintEvent
attribute takes precedence. Depending on your requirements, you should
choose either one of them.
- Since Qt 4.1, the contents of parent widgets are also propagated to
- standard Qt widgets. This can lead to some unexpected results if the
- parent widget is decorated in a non-standard way, as shown in the diagram
- below.
+ The contents of parent widgets are also propagated to standard Qt widgets.
+ This can lead to some unexpected results if the parent widget is decorated
+ in a non-standard way, as shown in the diagram below.
\image propagation-standard.png
@@ -736,8 +742,8 @@ void QWidget::setAutoFillBackground(bool enabled)
\section1 Creating Translucent Windows
- Since Qt 4.5, it has been possible to create windows with translucent regions
- on window systems that support compositing.
+ You can create windows with translucent regions on window systems that
+ support compositing.
To enable this feature in a top-level widget, set its Qt::WA_TranslucentBackground
attribute with setAttribute() and ensure that its background is painted with
@@ -757,19 +763,19 @@ void QWidget::setAutoFillBackground(bool enabled)
\section1 Native Widgets vs Alien Widgets
- Introduced in Qt 4.4, alien widgets are widgets unknown to the windowing
- system. They do not have a native window handle associated with them. This
- feature significantly speeds up widget painting, resizing, and removes flicker.
+ Alien widgets are widgets unknown to the windowing system. They do not have
+ a native window handle associated with them. This feature significantly
+ speeds up widget painting, resizing, and removes flicker.
- Should you require the old behavior with native windows, you can choose
- one of the following options:
+ Should you require the old behavior with native windows, choose one of the
+ following options:
\list 1
\li Use the \c{QT_USE_NATIVE_WINDOWS=1} in your environment.
\li Set the Qt::AA_NativeWindows attribute on your application. All
widgets will be native widgets.
\li Set the Qt::WA_NativeWindow attribute on widgets: The widget itself
- and all of its ancestors will become native (unless
+ and all its ancestors will become native (unless
Qt::WA_DontCreateNativeAncestors is set).
\li Call QWidget::winId to enforce a native window (this implies 3).
\li Set the Qt::WA_PaintOnScreen attribute to enforce a native window
@@ -814,12 +820,7 @@ struct QWidgetExceptionCleaner
Q_UNUSED(d);
#else
QWidgetPrivate::allWidgets->remove(that);
- if (d->focus_next != that) {
- if (d->focus_next)
- d->focus_next->d_func()->focus_prev = d->focus_prev;
- if (d->focus_prev)
- d->focus_prev->d_func()->focus_next = d->focus_next;
- }
+ d->removeFromFocusChain();
#endif
}
};
@@ -987,7 +988,7 @@ void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f)
//give potential windows a bigger "pre-initial" size; create() will give them a new size later
data.crect = parentWidget ? QRect(0,0,100,30) : QRect(0,0,640,480);
- focus_next = focus_prev = q;
+ initFocusChain();
if ((f & Qt::WindowType_Mask) == Qt::Desktop)
q->create();
@@ -1026,6 +1027,31 @@ void QWidgetPrivate::createRecursively()
}
}
+QRhi *QWidgetPrivate::rhi() const
+{
+ if (QWidgetRepaintManager *repaintManager = maybeRepaintManager())
+ return repaintManager->rhi();
+ else
+ return nullptr;
+}
+
+/*!
+ \internal
+ Returns the closest parent widget that has a QWindow window handle
+
+ \note This behavior is different from nativeParentWidget(), which
+ returns the closest parent that has a QWindow window handle with
+ a created QPlatformWindow, and hence native window (winId).
+*/
+QWidget *QWidgetPrivate::closestParentWidgetWithWindowHandle() const
+{
+ Q_Q(const QWidget);
+ QWidget *parent = q->parentWidget();
+ while (parent && !parent->windowHandle())
+ parent = parent->parentWidget();
+ return parent;
+}
+
QWindow *QWidgetPrivate::windowHandle(WindowHandleMode mode) const
{
if (mode == WindowHandleMode::Direct || mode == WindowHandleMode::Closest) {
@@ -1035,6 +1061,7 @@ QWindow *QWidgetPrivate::windowHandle(WindowHandleMode mode) const
}
}
if (mode == WindowHandleMode::Closest) {
+ // FIXME: Use closestParentWidgetWithWindowHandle instead
if (auto nativeParent = q_func()->nativeParentWidget()) {
if (auto window = nativeParent->windowHandle())
return window;
@@ -1262,7 +1289,7 @@ void QWidgetPrivate::create()
Qt::WindowFlags &flags = data.window_flags;
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
+#if defined(QT_PLATFORM_UIKIT)
if (q->testAttribute(Qt::WA_ContentsMarginsRespectsSafeArea))
flags |= Qt::MaximizeUsingFullscreenGeometryHint;
#endif
@@ -1271,7 +1298,6 @@ void QWidgetPrivate::create()
win->setProperty("_q_showWithoutActivating", QVariant(true));
if (q->testAttribute(Qt::WA_MacAlwaysShowToolWindow))
win->setProperty("_q_macAlwaysShowToolWindow", QVariant(true));
- setNetWmWindowTypes(true); // do nothing if none of WA_X11NetWmWindowType* is set
win->setFlags(flags);
fixPosIncludesFrame();
if (q->testAttribute(Qt::WA_Moved)
@@ -1319,8 +1345,6 @@ void QWidgetPrivate::create()
}
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 QT_CONFIG(xcb)
if (!topData()->role.isNull()) {
@@ -1355,6 +1379,7 @@ void QWidgetPrivate::create()
Q_ASSERT(id != WId(0));
setWinId(id);
}
+ setNetWmWindowTypes(true); // do nothing if none of WA_X11NetWmWindowType* is set
// Check children and create windows for them if necessary
q_createNativeChildrenAndSetParent(q);
@@ -1449,17 +1474,9 @@ QWidget::~QWidget()
// delete layout while we still are a valid widget
delete d->layout;
d->layout = nullptr;
- // Remove myself from focus list
-
- Q_ASSERT(d->focus_next->d_func()->focus_prev == this);
- Q_ASSERT(d->focus_prev->d_func()->focus_next == this);
-
- if (d->focus_next != this) {
- d->focus_next->d_func()->focus_prev = d->focus_prev;
- d->focus_prev->d_func()->focus_next = d->focus_next;
- d->focus_next = d->focus_prev = nullptr;
- }
+ // Remove this from focus list
+ d->removeFromFocusChain(QWidgetPrivate::FocusChainRemovalRule::AssertConsistency);
QT_TRY {
#if QT_CONFIG(graphicsview)
@@ -1659,10 +1676,9 @@ void QWidgetPrivate::deleteExtra()
if (QStyleSheetStyle *proxy = qt_styleSheet(extra->style))
proxy->deref();
#endif
- if (extra->topextra) {
+ if (extra->topextra)
deleteTLSysExtra();
- // extra->topextra->backingStore destroyed in QWidgetPrivate::deleteTLSysExtra()
- }
+
// extra->xic destroyed in QWidget::destroy()
extra.reset();
}
@@ -1672,34 +1688,11 @@ void QWidgetPrivate::deleteSysExtra()
{
}
-static void deleteBackingStore(QWidgetPrivate *d)
-{
- QTLWExtra *topData = d->topData();
-
- delete topData->backingStore;
- topData->backingStore = nullptr;
-}
-
void QWidgetPrivate::deleteTLSysExtra()
{
if (extra && extra->topextra) {
- //the qplatformbackingstore may hold a reference to the window, so the backingstore
- //needs to be deleted first.
-
- extra->topextra->repaintManager.reset(nullptr);
- deleteBackingStore(this);
- extra->topextra->widgetTextures.clear();
-
- //the toplevel might have a context with a "qglcontext associated with it. We need to
- //delete the qglcontext before we delete the qplatformopenglcontext.
- //One unfortunate thing about this is that we potentially create a glContext just to
- //delete it straight afterwards.
- if (extra->topextra->window) {
- extra->topextra->window->destroy();
- }
delete extra->topextra->window;
extra->topextra->window = nullptr;
-
}
}
@@ -2925,7 +2918,7 @@ void QWidget::overrideWindowState(Qt::WindowStates newstate)
\snippet code/src_gui_kernel_qwidget.cpp 0
- In order to restore and activate a minimized window (while
+ To restore and activate a minimized window (while
preserving its maximized and/or full-screen state), use the following:
\snippet code/src_gui_kernel_qwidget.cpp 1
@@ -3001,7 +2994,7 @@ bool QWidget::isFullScreen() const
ICCCM protocol that specifies the communication between X11
clients and the window manager. ICCCM simply does not understand
the concept of non-decorated full-screen windows. Therefore, the
- best we can do is to request a borderless window and place and
+ best you can do is to request a borderless window and place and
resize it to fill the entire screen. Depending on the window
manager, this may or may not work. The borderless window is
requested using MOTIF hints, which are at least partially
@@ -3009,7 +3002,7 @@ bool QWidget::isFullScreen() const
An alternative would be to bypass the window manager entirely and
create a window with the Qt::X11BypassWindowManagerHint flag. This
- has other severe problems though, like totally broken keyboard focus
+ has other severe problems though, like broken keyboard focus
and very strange effects on desktop changes or when the user raises
other windows.
@@ -3109,7 +3102,7 @@ bool QWidget::isEnabledTo(const QWidget *ancestor) const
/*!
Appends the action \a action to this widget's list of actions.
- All QWidgets have a list of \l{QAction}s, however they can be
+ All QWidgets have a list of \l{QAction}s. However, they can be
represented graphically in many different ways. The default use of
the QAction list (as returned by actions()) is to create a context
QMenu.
@@ -3319,10 +3312,10 @@ QAction *QWidget::addAction(const QIcon &icon, const QString &text, const QKeySe
#endif // QT_CONFIG(shortcut)
/*!
- \fn template<typename...Args> QAction *QWidget::addAction(const QString &text, Args&&...args)
- \fn template<typename...Args> QAction *QWidget::addAction(const QString &text, const QKeySequence &shortcut, Args&&...args)
- \fn template<typename...Args> QAction *QWidget::addAction(const QIcon &icon, const QString &text, Args&&...args)
- \fn template<typename...Args> QAction *QWidget::addAction(const QIcon &icon, const QString &text, const QKeySequence &shortcut, Args&&...args)
+ \fn template<typename...Args, typename = compatible_action_slot_args<Args...>> QAction *QWidget::addAction(const QString &text, Args&&...args)
+ \fn template<typename...Args, typename = compatible_action_slot_args<Args...>> QAction *QWidget::addAction(const QString &text, const QKeySequence &shortcut, Args&&...args)
+ \fn template<typename...Args, typename = compatible_action_slot_args<Args...>> QAction *QWidget::addAction(const QIcon &icon, const QString &text, Args&&...args)
+ \fn template<typename...Args, typename = compatible_action_slot_args<Args...>> QAction *QWidget::addAction(const QIcon &icon, const QString &text, const QKeySequence &shortcut, Args&&...args)
\since 6.3
\overload
@@ -3748,7 +3741,7 @@ QRegion QWidget::childrenRegion() const
the current size is smaller.
The minimum size set by this function will override the minimum size
- defined by QLayout. In order to unset the minimum size, use a
+ defined by QLayout. To unset the minimum size, use a
value of \c{QSize(0, 0)}.
By default, this property contains a size with zero width and height.
@@ -4359,7 +4352,7 @@ QWidget *QWidget::nativeParentWidget() const
The background role defines the brush from the widget's \l palette that
is used to render the background.
- If no explicit background role is set, the widget inherts its parent
+ If no explicit background role is set, the widget inherits its parent
widget's background role.
\sa setBackgroundRole(), foregroundRole()
@@ -4503,7 +4496,7 @@ void QWidget::setForegroundRole(QPalette::ColorRole role)
QWidget's palette propagation is similar to its font propagation.
The current style, which is used to render the content of all standard Qt
- widgets, is free to choose colors and brushes from the widget palette, or
+ widgets, is free to choose colors and brushes from the widget palette, or,
in some cases, to ignore the palette (partially, or completely). In
particular, certain styles like GTK style, Mac style, and Windows Vista
style, depend on third party APIs to render the content of widgets,
@@ -6402,16 +6395,19 @@ void QWidget::setFocusProxy(QWidget * w)
break;
}
Q_ASSERT(firstChild); // can't be nullptr since w is a child
- QWidget *oldNext = d->focus_next;
- QWidget *oldPrev = d->focus_prev;
- oldNext->d_func()->focus_prev = oldPrev;
- oldPrev->d_func()->focus_next = oldNext;
-
- oldPrev = firstChild->d_func()->focus_prev;
- d->focus_next = firstChild;
- d->focus_prev = oldPrev;
- oldPrev->d_func()->focus_next = this;
- firstChild->d_func()->focus_prev = this;
+ d->insertIntoFocusChainBefore(firstChild);
+ } else if (w && w->isAncestorOf(this)) {
+ // If the focus proxy is a parent, 'this' has to be inserted directly after its parent in the focus chain
+ // remove it from the chain and insert this into the focus chain after its parent
+
+ // is this the case already?
+ QWidget *parentsNext = w->nextInFocusChain();
+ if (parentsNext == this) {
+ // nothing to do.
+ Q_ASSERT(previousInFocusChain() == w);
+ } else {
+ d->QWidgetPrivate::insertIntoFocusChainAfter(w);
+ }
}
if (moveFocusToProxy)
@@ -6620,7 +6616,9 @@ void QWidgetPrivate::setFocus_sys()
{
Q_Q(QWidget);
// Embedded native widget may have taken the focus; get it back to toplevel
- // if that is the case (QTBUG-25852)
+ // if that is the case (QTBUG-25852), unless widget is a window container.
+ if (extra && extra->hasWindowContainer)
+ return;
// Do not activate in case the popup menu opens another application (QTBUG-70810)
// unless the application is embedded (QTBUG-71991).
if (QWindow *nativeWindow = q->testAttribute(Qt::WA_WState_Created) ? q->window()->windowHandle() : nullptr) {
@@ -6672,8 +6670,8 @@ void QWidgetPrivate::updateFocusChild()
If the widget has active focus, a \l{focusOutEvent()}{focus out event} is sent to this widget to tell it that it has
lost the focus.
- This widget must enable focus setting in order to get the keyboard
- input focus, i.e. it must call setFocusPolicy().
+ This widget must enable focus setting to get the keyboard
+ input focus; that is, it must call setFocusPolicy().
\sa hasFocus(), setFocus(), focusInEvent(), focusOutEvent(),
setFocusPolicy(), QApplication::focusWidget()
@@ -6829,6 +6827,13 @@ QWidget *QWidget::focusWidget() const
return const_cast<QWidget *>(d_func()->focus_child);
}
+QObject *QWidgetPrivate::focusObject()
+{
+ Q_Q(QWidget);
+ QWidget *proxy = deepestFocusProxy();
+ return proxy ? proxy : q;
+}
+
/*!
Returns the next widget in this widget's focus chain.
@@ -6836,7 +6841,8 @@ QWidget *QWidget::focusWidget() const
*/
QWidget *QWidget::nextInFocusChain() const
{
- return const_cast<QWidget *>(d_func()->focus_next);
+ Q_D(const QWidget);
+ return d->nextPrevElementInFocusChain(QWidgetPrivate::FocusDirection::Next);
}
/*!
@@ -6849,7 +6855,8 @@ QWidget *QWidget::nextInFocusChain() const
*/
QWidget *QWidget::previousInFocusChain() const
{
- return const_cast<QWidget *>(d_func()->focus_prev);
+ Q_D(const QWidget);
+ return d->nextPrevElementInFocusChain(QWidgetPrivate::FocusDirection::Previous);
}
/*!
@@ -6919,6 +6926,30 @@ bool QWidget::isActiveWindow() const
}
/*!
+ \fn void QWidget::setTabOrder(std::initializer_list<QWidget *> widgets)
+ \overload
+ \since 6.6
+
+ Sets the tab order for the widgets in the \a widgets list by calling
+ \l{QWidget::setTabOrder(QWidget *, QWidget *)} for each consecutive
+ pair of widgets.
+
+ Instead of setting up each pair manually like this:
+
+ \snippet code/src_gui_kernel_qwidget.cpp 9
+
+ you can call:
+
+ \snippet code/src_gui_kernel_qwidget.cpp 9.list
+
+ The call does not create a closed tab focus loop. If there are more widgets
+ with \l{Qt::TabFocus} focus policy, tabbing on \c{d} will move focus to one
+ of those widgets, not back to \c{a}.
+
+ \sa setFocusPolicy(), setFocusProxy(), {Keyboard Focus in Widgets}
+*/
+
+/*!
Puts the \a second widget after the \a first widget in the focus order.
It effectively removes the \a second widget from its focus chain and
@@ -6980,9 +7011,9 @@ void QWidget::setTabOrder(QWidget* first, QWidget *second)
}
} else if (target->isAncestorOf(focusProxy)) {
lastFocusChild = focusProxy;
- for (QWidget *focusNext = lastFocusChild->d_func()->focus_next;
+ for (QWidget *focusNext = lastFocusChild->nextInFocusChain();
focusNext != focusProxy && target->isAncestorOf(focusNext) && focusNext->window() == focusProxy->window();
- focusNext = focusNext->d_func()->focus_next) {
+ focusNext = focusNext->nextInFocusChain()) {
if (focusNext == noFurtherThan)
break;
if (focusNext->focusPolicy() != Qt::NoFocus)
@@ -6991,13 +7022,6 @@ void QWidget::setTabOrder(QWidget* first, QWidget *second)
}
return lastFocusChild;
};
- auto setPrev = [](QWidget *w, QWidget *prev) {
- w->d_func()->focus_prev = prev;
- };
- auto setNext = [](QWidget *w, QWidget *next) {
- w->d_func()->focus_next = next;
- };
-
// detect inflection in case we have compound widgets
QWidget *lastFocusChildOfFirst = determineLastFocusChild(first, second);
if (lastFocusChildOfFirst == second)
@@ -7006,30 +7030,31 @@ void QWidget::setTabOrder(QWidget* first, QWidget *second)
if (lastFocusChildOfSecond == first)
lastFocusChildOfSecond = second;
- // remove the second widget from the chain
- {
- QWidget *oldPrev = second->d_func()->focus_prev;
- QWidget *prevWithFocus = oldPrev;
- while (prevWithFocus->focusPolicy() == Qt::NoFocus)
- prevWithFocus = prevWithFocus->d_func()->focus_prev;
- // only widgets between first and second -> all is fine
- if (prevWithFocus == first)
- return;
- QWidget *oldNext = lastFocusChildOfSecond->d_func()->focus_next;
- setPrev(oldNext, oldPrev);
- setNext(oldPrev, oldNext);
- }
+ // Return if only NoFocus widgets are between first and second
+ QWidget *oldPrev = second->previousInFocusChain();
+ QWidget *prevWithFocus = oldPrev;
+ while (prevWithFocus->focusPolicy() == Qt::NoFocus)
+ prevWithFocus = prevWithFocus->previousInFocusChain();
+ if (prevWithFocus == first)
+ return;
+ const QWidgetList chain = QWidgetPrivate::takeFromFocusChain(second, lastFocusChildOfSecond);
+ QWidgetPrivate::insertIntoFocusChain(chain, QWidgetPrivate::FocusDirection::Next, lastFocusChildOfFirst);
+}
- // insert the second widget into the chain
- {
- QWidget *oldNext = lastFocusChildOfFirst->d_func()->focus_next;
- setPrev(second, lastFocusChildOfFirst);
- setNext(lastFocusChildOfFirst, second);
- setPrev(oldNext, lastFocusChildOfSecond);
- setNext(lastFocusChildOfSecond, oldNext);
+void QWidget::setTabOrder(std::initializer_list<QWidget *> widgets)
+{
+ QWidget *prev = nullptr;
+ for (const auto &widget : widgets) {
+ if (!prev) {
+ prev = widget;
+ } else {
+ QWidget::setTabOrder(prev, widget);
+ prev = widget;
+ }
}
}
+
/*!\internal
Moves the relevant subwidgets of this widget from the \a oldtlw's
@@ -7051,67 +7076,8 @@ void QWidgetPrivate::reparentFocusWidgets(QWidget * oldtlw)
if (focus_child)
focus_child->clearFocus();
- // separate the focus chain into new (children of myself) and old (the rest)
- QWidget *firstOld = nullptr;
- //QWidget *firstNew = q; //invariant
- QWidget *o = nullptr; // last in the old list
- QWidget *n = q; // last in the new list
-
- bool prevWasNew = true;
- QWidget *w = focus_next;
-
- //Note: for efficiency, we do not maintain the list invariant inside the loop
- //we append items to the relevant list, and we optimize by not changing pointers
- //when subsequent items are going into the same list.
- while (w != q) {
- bool currentIsNew = q->isAncestorOf(w);
- if (currentIsNew) {
- if (!prevWasNew) {
- //prev was old -- append to new list
- n->d_func()->focus_next = w;
- w->d_func()->focus_prev = n;
- }
- n = w;
- } else {
- if (prevWasNew) {
- //prev was new -- append to old list, if there is one
- if (o) {
- o->d_func()->focus_next = w;
- w->d_func()->focus_prev = o;
- } else {
- // "create" the old list
- firstOld = w;
- }
- }
- o = w;
- }
- w = w->d_func()->focus_next;
- prevWasNew = currentIsNew;
- }
-
- //repair the old list:
- if (firstOld) {
- o->d_func()->focus_next = firstOld;
- firstOld->d_func()->focus_prev = o;
- }
-
- if (!q->isWindow()) {
- QWidget *topLevel = q->window();
- //insert new chain into toplevel's chain
-
- QWidget *prev = topLevel->d_func()->focus_prev;
-
- topLevel->d_func()->focus_prev = n;
- prev->d_func()->focus_next = q;
-
- focus_prev = prev;
- n->d_func()->focus_next = topLevel;
- } else {
- //repair the new list
- n->d_func()->focus_next = q;
- focus_prev = n;
- }
-
+ insertIntoFocusChain(QWidgetPrivate::FocusDirection::Previous, q->window());
+ reparentFocusChildren(QWidgetPrivate::FocusDirection::Next);
}
/*!
@@ -7539,7 +7505,7 @@ bool QWidget::restoreGeometry(const QByteArray &geometry)
}
const int frameHeight = QApplication::style()
- ? QApplication::style()->pixelMetric(QStyle::PM_TitleBarHeight)
+ ? QApplication::style()->pixelMetric(QStyle::PM_TitleBarHeight, nullptr, this)
: 20;
if (!restoredNormalGeometry.isValid())
@@ -7892,21 +7858,29 @@ void QWidget::setUpdatesEnabled(bool enable)
/*!
Shows the widget and its child widgets.
- This is equivalent to calling showFullScreen(), showMaximized(), or setVisible(true),
- depending on the platform's default behavior for the window flags.
+ For child windows, this is equivalent to calling setVisible(true).
+ Otherwise, it is equivalent to calling showFullScreen(), showMaximized(),
+ or setVisible(true), depending on the platform's default behavior for the window flags.
- \sa raise(), showEvent(), hide(), setVisible(), showMinimized(), showMaximized(),
+ \sa raise(), showEvent(), hide(), setVisible(), showMinimized(), showMaximized(),
showNormal(), isVisible(), windowFlags()
*/
void QWidget::show()
{
- Qt::WindowState defaultState = QGuiApplicationPrivate::platformIntegration()->defaultWindowState(data->window_flags);
- if (defaultState == Qt::WindowFullScreen)
- showFullScreen();
- else if (defaultState == Qt::WindowMaximized)
- showMaximized();
- else
- setVisible(true); // Don't call showNormal() as not to clobber Qt::Window(Max/Min)imized
+ // Note: We don't call showNormal() as not to clobber Qt::Window(Max/Min)imized
+
+ if (!isWindow()) {
+ setVisible(true);
+ } else {
+ const auto *platformIntegration = QGuiApplicationPrivate::platformIntegration();
+ Qt::WindowState defaultState = platformIntegration->defaultWindowState(data->window_flags);
+ if (defaultState == Qt::WindowFullScreen)
+ showFullScreen();
+ else if (defaultState == Qt::WindowMaximized)
+ showMaximized();
+ else
+ setVisible(true);
+ }
}
/*! \internal
@@ -8273,13 +8247,17 @@ void QWidgetPrivate::hide_sys()
void QWidget::setVisible(bool visible)
{
+ Q_D(QWidget);
+ qCDebug(lcWidgetShowHide) << "Setting visibility of" << this
+ << "with attributes" << WidgetAttributes{this}
+ << "to" << visible << "via QWidget";
+
if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden) == !visible)
return;
// Remember that setVisible was called explicitly
setAttribute(Qt::WA_WState_ExplicitShowHide);
- Q_D(QWidget);
d->setVisible(visible);
}
@@ -8289,6 +8267,10 @@ void QWidget::setVisible(bool visible)
void QWidgetPrivate::setVisible(bool visible)
{
Q_Q(QWidget);
+ qCDebug(lcWidgetShowHide) << "Setting visibility of" << q
+ << "with attributes" << WidgetAttributes{q}
+ << "to" << visible << "via QWidgetPrivate";
+
if (visible) { // show
// Designer uses a trick to make grabWidget work without showing
if (!q->isWindow() && q->parentWidget() && q->parentWidget()->isVisible()
@@ -8368,8 +8350,7 @@ void QWidgetPrivate::setVisible(bool visible)
if (!q->testAttribute(Qt::WA_WState_Hidden)) {
q->setAttribute(Qt::WA_WState_Hidden);
- if (q->testAttribute(Qt::WA_WState_Created))
- hide_helper();
+ hide_helper();
}
// invalidate layout similar to updateGeometry()
@@ -8393,23 +8374,35 @@ void QWidget::setHidden(bool hidden)
setVisible(!hidden);
}
+bool QWidgetPrivate::isExplicitlyHidden() const
+{
+ Q_Q(const QWidget);
+ return q->isHidden() && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
+}
+
void QWidgetPrivate::_q_showIfNotHidden()
{
Q_Q(QWidget);
- if ( !(q->isHidden() && q->testAttribute(Qt::WA_WState_ExplicitShowHide)) )
+ if (!isExplicitlyHidden())
q->setVisible(true);
}
void QWidgetPrivate::showChildren(bool spontaneous)
{
+ Q_Q(QWidget);
+ qCDebug(lcWidgetShowHide) << "Showing children of" << q
+ << "spontaneously" << spontaneous;
+
QList<QObject*> childList = children;
for (int i = 0; i < childList.size(); ++i) {
QWidget *widget = qobject_cast<QWidget*>(childList.at(i));
- if (widget && widget->windowHandle() && !widget->testAttribute(Qt::WA_WState_ExplicitShowHide))
+ if (!widget)
+ continue;
+ qCDebug(lcWidgetShowHide) << "Considering" << widget
+ << "with attributes" << WidgetAttributes{widget};
+ if (widget->windowHandle() && !widget->testAttribute(Qt::WA_WState_ExplicitShowHide))
widget->setAttribute(Qt::WA_WState_Hidden, false);
- if (!widget
- || widget->isWindow()
- || widget->testAttribute(Qt::WA_WState_Hidden))
+ if (widget->isWindow() || widget->testAttribute(Qt::WA_WState_Hidden))
continue;
if (spontaneous) {
widget->setAttribute(Qt::WA_Mapped);
@@ -8420,7 +8413,7 @@ void QWidgetPrivate::showChildren(bool spontaneous)
if (widget->testAttribute(Qt::WA_WState_ExplicitShowHide))
widget->d_func()->show_recursive();
else
- widget->show();
+ widget->d_func()->setVisible(true);
}
}
}
@@ -8428,10 +8421,17 @@ void QWidgetPrivate::showChildren(bool spontaneous)
void QWidgetPrivate::hideChildren(bool spontaneous)
{
Q_Q(QWidget);
+ qCDebug(lcWidgetShowHide) << "Hiding children of" << q
+ << "spontaneously" << spontaneous;
+
QList<QObject*> childList = children;
for (int i = 0; i < childList.size(); ++i) {
QWidget *widget = qobject_cast<QWidget*>(childList.at(i));
- if (!widget || widget->isWindow() || widget->testAttribute(Qt::WA_WState_Hidden))
+ if (!widget)
+ continue;
+ qCDebug(lcWidgetShowHide) << "Considering" << widget
+ << "with attributes" << WidgetAttributes{widget};
+ if (widget->isWindow() || widget->testAttribute(Qt::WA_WState_Hidden))
continue;
if (spontaneous)
@@ -8489,13 +8489,15 @@ void QWidgetPrivate::hideChildren(bool spontaneous)
*/
bool QWidgetPrivate::handleClose(CloseMode mode)
{
+ Q_Q(QWidget);
+ qCDebug(lcWidgetShowHide) << "Handling close event for" << q;
+
if (data.is_closing)
return true;
// We might not have initiated the close, so update the state now that we know
data.is_closing = true;
- Q_Q(QWidget);
QPointer<QWidget> that = q;
if (data.in_destructor)
@@ -8605,7 +8607,7 @@ bool QWidgetPrivate::close()
when the user minimizes the window, and a spontaneous show event
when the window is restored again.
- You almost never have to reimplement the setVisible() function. If
+ You seldom have to reimplement the setVisible() function. If
you need to change some settings before a widget is shown, use
showEvent() instead. If you need to do some delayed initialization
use the Polish event delivered to the event() function.
@@ -9591,7 +9593,7 @@ void QWidget::tabletEvent(QTabletEvent *event)
implementation if you act upon the key.
\sa keyReleaseEvent(), setFocusPolicy(),
- focusInEvent(), focusOutEvent(), event(), QKeyEvent, {Tetrix Example}
+ focusInEvent(), focusOutEvent(), event(), QKeyEvent
*/
void QWidget::keyPressEvent(QKeyEvent *event)
@@ -9642,7 +9644,7 @@ void QWidget::keyReleaseEvent(QKeyEvent *event)
is passed in the \a event parameter
A widget normally must setFocusPolicy() to something other than
- Qt::NoFocus in order to receive focus events. (Note that the
+ Qt::NoFocus to receive focus events. (Note that the
application programmer can call setFocus() on any widget, even
those that do not normally accept focus.)
@@ -9668,7 +9670,7 @@ void QWidget::focusInEvent(QFocusEvent *)
passed in the \a event parameter.
A widget normally must setFocusPolicy() to something other than
- Qt::NoFocus in order to receive focus events. (Note that the
+ Qt::NoFocus to receive focus events. (Note that the
application programmer can call setFocus() on any widget, even
those that do not normally accept focus.)
@@ -9840,13 +9842,8 @@ void QWidget::actionEvent(QActionEvent *)
Main window applications typically use reimplementations of this function to check
whether the user's work has been saved and ask for permission before closing.
- For example, the \l{Qt Widgets - Application Example} uses a helper function to
- determine whether or not to close the window:
-
- \snippet mainwindows/application/mainwindow.cpp 3
- \snippet mainwindows/application/mainwindow.cpp 4
- \sa event(), hide(), close(), QCloseEvent, {Qt Widgets - Application Example}
+ \sa event(), hide(), close(), QCloseEvent
*/
void QWidget::closeEvent(QCloseEvent *event)
@@ -9935,7 +9932,7 @@ QVariant QWidget::inputMethodQuery(Qt::InputMethodQuery query) const
is set, the input method may change its visual components to reflect
that only numbers can be entered.
- \warning Some widgets require certain flags in order to work as
+ \warning Some widgets require certain flags to work as
intended. To set a flag, do \c{w->setInputMethodHints(w->inputMethodHints()|f)}
instead of \c{w->setInputMethodHints(f)}.
@@ -10185,7 +10182,7 @@ void QWidget::ensurePolished() const
Returns the mask currently set on a widget. If no mask is set the
return value will be an empty region.
- \sa setMask(), clearMask(), QRegion::isEmpty(), {Shaped Clock Example}
+ \sa setMask(), clearMask(), QRegion::isEmpty()
*/
QRegion QWidget::mask() const
{
@@ -10616,9 +10613,15 @@ void qSendWindowChangeToTextureChildrenRecursively(QWidget *widget, QEvent::Type
for (int i = 0; i < d->children.size(); ++i) {
QWidget *w = qobject_cast<QWidget *>(d->children.at(i));
- if (w && !w->isWindow() && QWidgetPrivate::get(w)->textureChildSeen)
+ if (w && !w->isWindow())
qSendWindowChangeToTextureChildrenRecursively(w, eventType);
}
+
+ // Notify QWidgetWindow after we've notified all child QWidgets
+ if (auto *window = d->windowHandle(QWidgetPrivate::WindowHandleMode::Direct)) {
+ QEvent e(eventType);
+ QCoreApplication::sendEvent(window, &e);
+ }
}
/*!
@@ -10649,6 +10652,7 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f)
const bool resized = testAttribute(Qt::WA_Resized);
const bool wasCreated = testAttribute(Qt::WA_WState_Created);
QWidget *oldtlw = window();
+ Q_ASSERT(oldtlw);
if (f & Qt::Window) // Frame geometry likely changes, refresh.
d->data.fstrut_dirty = true;
@@ -10667,7 +10671,20 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f)
if (wasCreated) {
if (!testAttribute(Qt::WA_WState_Hidden)) {
+ // Hiding the widget will set WA_WState_Hidden as well, which would
+ // normally require the widget to be explicitly shown again to become
+ // visible, even as a child widget. But we refine this value later in
+ // setParent_sys(), applying WA_WState_Hidden based on whether the
+ // widget is a top level or not.
hide();
+
+ // We reset WA_WState_ExplicitShowHide here, likely as a remnant of
+ // when we only had QWidget::setVisible(), which is treated as an
+ // explicit show/hide. Nowadays we have QWidgetPrivate::setVisible(),
+ // that allows us to hide a widget without affecting ExplicitShowHide.
+ // Though it can be argued that ExplicitShowHide should reflect the
+ // last update of the widget's state, so if we hide the widget as a
+ // side effect of changing parent, perhaps we _should_ reset it?
setAttribute(Qt::WA_WState_ExplicitShowHide, false);
}
if (newParent) {
@@ -10678,7 +10695,7 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f)
// texture-based widgets need a pre-notification when their associated top-level window changes
// This is not under the wasCreated/newParent conditions above in order to also play nice with QDockWidget.
- if (d->textureChildSeen && ((!parent && parentWidget()) || (parent && parent->window() != oldtlw)))
+ if (oldtlw->d_func()->usesRhiFlush && ((!parent && parentWidget()) || (parent && parent->window() != oldtlw)))
qSendWindowChangeToTextureChildrenRecursively(this, QEvent::WindowAboutToChangeInternal);
// If we get parented into another window, children will be folded
@@ -10759,7 +10776,7 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f)
// texture-based widgets need another event when their top-level window
// changes (more precisely, has already changed at this point)
- if (d->textureChildSeen && oldtlw != window())
+ if (oldtlw->d_func()->usesRhiFlush && oldtlw != window())
qSendWindowChangeToTextureChildrenRecursively(this, QEvent::WindowChangeInternal);
if (!wasCreated) {
@@ -10794,12 +10811,26 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f)
// do it on newtlw instead, the performance implications of that are
// problematic when it comes to large widget trees.
if (q_evaluateRhiConfig(this, nullptr, &surfaceType)) {
+ const bool wasUsingRhiFlush = newtlw->d_func()->usesRhiFlush;
newtlw->d_func()->usesRhiFlush = true;
+ bool recreate = false;
if (QWindow *w = newtlw->windowHandle()) {
- if (w->surfaceType() != surfaceType) {
- newtlw->destroy();
- newtlw->create();
- }
+ if (w->surfaceType() != surfaceType || !wasUsingRhiFlush)
+ recreate = true;
+ }
+ // QTBUG-115652: Besides the toplevel the nativeParentWidget()'s QWindow must be checked as well.
+ if (QWindow *w = d->windowHandle(QWidgetPrivate::WindowHandleMode::Closest)) {
+ if (w->surfaceType() != surfaceType)
+ recreate = true;
+ }
+ if (recreate) {
+ const auto windowStateBeforeDestroy = newtlw->windowState();
+ const auto visibilityBeforeDestroy = newtlw->isVisible();
+ newtlw->destroy();
+ newtlw->create();
+ Q_ASSERT(newtlw->windowHandle());
+ newtlw->windowHandle()->setWindowStates(windowStateBeforeDestroy);
+ QWidgetPrivate::get(newtlw)->setVisible(visibilityBeforeDestroy);
}
}
}
@@ -10823,57 +10854,61 @@ void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f)
setWinId(0);
- if (parent != newparent) {
- QObjectPrivate::setParent_helper(newparent); //### why does this have to be done in the _sys function???
- if (q->windowHandle()) {
- q->windowHandle()->setFlags(f);
- QWidget *parentWithWindow =
- newparent ? (newparent->windowHandle() ? newparent : newparent->nativeParentWidget()) : nullptr;
- if (parentWithWindow) {
- QWidget *topLevel = parentWithWindow->window();
- if ((f & Qt::Window) && topLevel && topLevel->windowHandle()) {
- q->windowHandle()->setTransientParent(topLevel->windowHandle());
- q->windowHandle()->setParent(nullptr);
- } else {
- q->windowHandle()->setTransientParent(nullptr);
- q->windowHandle()->setParent(parentWithWindow->windowHandle());
- }
- } else {
- q->windowHandle()->setTransientParent(nullptr);
- q->windowHandle()->setParent(nullptr);
- }
- }
- }
-
if (!newparent) {
f |= Qt::Window;
if (parent)
targetScreen = q->parentWidget()->window()->screen();
}
- bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);
+ const bool destroyWindow = (
+ // Reparenting top level to child
+ (oldFlags & Qt::Window) && !(f & Qt::Window)
+ // And we can dispose of the window
+ && wasCreated && !q->testAttribute(Qt::WA_NativeWindow)
+ );
- // Reparenting toplevel to child
- if (wasCreated && !(f & Qt::Window) && (oldFlags & Qt::Window) && !q->testAttribute(Qt::WA_NativeWindow)) {
- if (extra && extra->hasWindowContainer)
- QWindowContainer::toplevelAboutToBeDestroyed(q);
+ if (parent != newparent) {
+ // Update object parent now, so we can resolve new parent window below
+ QObjectPrivate::setParent_helper(newparent);
- QWindow *newParentWindow = newparent->windowHandle();
- if (!newParentWindow)
- if (QWidget *npw = newparent->nativeParentWidget())
- newParentWindow = npw->windowHandle();
+ if (q->windowHandle())
+ q->windowHandle()->setFlags(f);
- for (QObject *child : q->windowHandle()->children()) {
- QWindow *childWindow = qobject_cast<QWindow *>(child);
- if (!childWindow)
- continue;
+ // If the widget itself or any of its children have been created,
+ // we need to reparent their QWindows as well.
+ QWidget *parentWithWindow = closestParentWidgetWithWindowHandle();
+ // But if the widget is about to be destroyed we must skip the
+ // widget itself, and only reparent children.
+ if (destroyWindow)
+ reparentWidgetWindowChildren(parentWithWindow);
+ else
+ reparentWidgetWindows(parentWithWindow, f);
+ }
+
+ bool explicitlyHidden = isExplicitlyHidden();
- QWidgetWindow *childWW = qobject_cast<QWidgetWindow *>(childWindow);
- QWidget *childWidget = childWW ? childWW->widget() : nullptr;
- if (!childWW || (childWidget && childWidget->testAttribute(Qt::WA_NativeWindow)))
- childWindow->setParent(newParentWindow);
+ if (destroyWindow) {
+ if (extra && extra->hasWindowContainer)
+ QWindowContainer::toplevelAboutToBeDestroyed(q);
+
+ // There shouldn't be any QWindow children left, but if there
+ // are, re-parent them now, before we destroy.
+ if (!q->windowHandle()->children().isEmpty()) {
+ QWidget *parentWithWindow = closestParentWidgetWithWindowHandle();
+ QWindow *newParentWindow = parentWithWindow ? parentWithWindow->windowHandle() : nullptr;
+ for (QObject *child : q->windowHandle()->children()) {
+ if (QWindow *childWindow = qobject_cast<QWindow *>(child)) {
+ qCWarning(lcWidgetWindow) << "Reparenting" << childWindow
+ << "before destroying" << this;
+ childWindow->setParent(newParentWindow);
+ }
+ }
}
- q->destroy();
+
+ // We have reparented any child windows of the widget we are
+ // about to destroy to the new parent window handle, so we can
+ // safely destroy this widget without destroying sub windows.
+ q->destroy(true, false);
}
adjustFlags(f, q);
@@ -10899,6 +10934,53 @@ void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f)
}
}
+void QWidgetPrivate::reparentWidgetWindows(QWidget *parentWithWindow, Qt::WindowFlags windowFlags)
+{
+ if (QWindow *window = windowHandle()) {
+ // Reparent this QWindow, and all QWindow children will follow
+ if (parentWithWindow) {
+ // The reparented widget has not updated its window flags yet,
+ // so we can't ask the widget directly. And we can't use the
+ // QWindow flags, as unlike QWidgets the QWindow flags always
+ // reflect Qt::Window, even for child windows. And we can't use
+ // QWindow::isTopLevel() either, as that depends on the parent,
+ // which we are in the process of updating. So we propagate the
+ // new flags of the reparented window from setParent_sys().
+ if (windowFlags & Qt::Window) {
+ // Top level windows can only have transient parents,
+ // and the transient parent must be another top level.
+ QWidget *topLevel = parentWithWindow->window();
+ auto *transientParent = topLevel->windowHandle();
+ Q_ASSERT(transientParent);
+ qCDebug(lcWidgetWindow) << "Setting" << window << "transient parent to" << transientParent;
+ window->setTransientParent(transientParent);
+ window->setParent(nullptr);
+ } else {
+ auto *parentWindow = parentWithWindow->windowHandle();
+ qCDebug(lcWidgetWindow) << "Reparenting" << window << "into" << parentWindow;
+ window->setTransientParent(nullptr);
+ window->setParent(parentWindow);
+ }
+ } else {
+ qCDebug(lcWidgetWindow) << "Making" << window << "top level window";
+ window->setTransientParent(nullptr);
+ window->setParent(nullptr);
+ }
+ } else {
+ reparentWidgetWindowChildren(parentWithWindow);
+ }
+}
+
+void QWidgetPrivate::reparentWidgetWindowChildren(QWidget *parentWithWindow)
+{
+ for (auto *child : std::as_const(children)) {
+ if (auto *childWidget = qobject_cast<QWidget*>(child)) {
+ auto *childPrivate = QWidgetPrivate::get(childWidget);
+ childPrivate->reparentWidgetWindows(parentWithWindow);
+ }
+ }
+}
+
/*!
Scrolls the widget including its children \a dx pixels to the
right and \a dy downward. Both \a dx and \a dy may be negative.
@@ -10993,7 +11075,7 @@ void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
unless updates are disabled or the widget is hidden.
We suggest only using repaint() if you need an immediate repaint,
- for example during animation. In almost all circumstances update()
+ for example during animation. In most circumstances update()
is better, as it permits Qt to optimize for speed and minimize
flicker.
@@ -11489,8 +11571,7 @@ void QWidgetPrivate::setWindowOpacity_sys(qreal level)
its parent because other children of the parent might have been
modified.
- \sa windowTitle, {Qt Widgets - Application Example},
- {MDI Example}
+ \sa windowTitle
*/
bool QWidget::isWindowModified() const
{
@@ -12181,7 +12262,7 @@ void QWidget::setBackingStore(QBackingStore *store)
return;
QBackingStore *oldStore = topData->backingStore;
- deleteBackingStore(d);
+ delete topData->backingStore;
topData->backingStore = store;
QWidgetRepaintManager *repaintManager = d->maybeRepaintManager();
@@ -12379,7 +12460,7 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
if ((windowType() == Qt::Popup) && qApp)
qApp->d_func()->closePopup(this);
- if (this == QApplicationPrivate::active_window)
+ if (this == qApp->activeWindow())
QApplicationPrivate::setActiveWindow(nullptr);
if (QWidget::mouseGrabber() == this)
releaseMouse();
@@ -12617,7 +12698,7 @@ static void releaseMouseGrabOfWidget(QWidget *widget)
terminal. Use this function with extreme caution, and consider
using the \c -nograb command line option while debugging.
- It is almost never necessary to grab the mouse when using Qt, as
+ It is seldom necessary to grab the mouse when using Qt, as
Qt grabs and releases it sensibly. In particular, Qt grabs the
mouse when a mouse button is pressed and keeps it until the last
button is released.
@@ -12916,8 +12997,16 @@ QPainter *QWidget::sharedPainter() const
widget, window system controls in that area may or may not be
visible, depending on the platform.
- Note that this effect can be slow if the region is particularly
- complex.
+ Since QRegion allows arbitrarily complex regions to be created, widget
+ masks can be made to suit the most unconventionally-shaped windows, and
+ even allow widgets to be displayed with holes in them. Note that this
+ effect can be slow if the region is particularly complex.
+
+ Widget masks are used to hint to the window system that the application
+ does not want mouse events for areas outside the mask. On most systems,
+ they also result in coarse visual clipping. To get smooth window edges, use
+ translucent background and anti-aliased painting instead, as shown in the
+ \l{Translucent Background} example.
\sa windowOpacity
*/
@@ -13003,7 +13092,7 @@ void QWidgetPrivate::setMask_sys(const QRegion &region)
Masked widgets receive mouse events only on their visible
portions.
- \sa clearMask(), windowOpacity(), {Shaped Clock Example}
+ \sa clearMask(), windowOpacity()
*/
void QWidget::setMask(const QBitmap &bitmap)
{
@@ -13098,22 +13187,47 @@ void QWidgetPrivate::setNetWmWindowTypes(bool skipIfMissing)
#endif
}
+/*!
+ \internal
+ \return \c true, if a child with \param policy exists and isn't a child of \param excludeChildrenOf.
+ Return false otherwise.
+ */
+bool QWidgetPrivate::hasChildWithFocusPolicy(Qt::FocusPolicy policy, const QWidget *excludeChildrenOf) const
+{
+ Q_Q(const QWidget);
+ const QWidgetList &children = q->findChildren<QWidget *>(Qt::FindChildrenRecursively);
+ for (const auto *child : children) {
+ if (child->focusPolicy() == policy && child->isEnabled()
+ && (!excludeChildrenOf || !excludeChildrenOf->isAncestorOf(child))) {
+ return true;
+ }
+ }
+ return false;
+}
+
#ifndef QT_NO_DEBUG_STREAM
-static inline void formatWidgetAttributes(QDebug debug, const QWidget *widget)
+namespace {
+QDebug operator<<(QDebug debug, const WidgetAttributes &attributes)
{
- const QMetaObject *qtMo = qt_getEnumMetaObject(Qt::WA_AttributeCount);
- const QMetaEnum me = qtMo->enumerator(qtMo->indexOfEnumerator("WidgetAttribute"));
- debug << ", attributes=[";
- int count = 0;
- for (int a = 0; a < Qt::WA_AttributeCount; ++a) {
- if (widget->testAttribute(static_cast<Qt::WidgetAttribute>(a))) {
- if (count++)
- debug << ',';
- debug << me.valueToKey(a);
+ const QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug << '[';
+ if (const QWidget *widget = attributes.widget) {
+ const QMetaObject *qtMo = qt_getEnumMetaObject(Qt::WA_AttributeCount);
+ const QMetaEnum me = qtMo->enumerator(qtMo->indexOfEnumerator("WidgetAttribute"));
+ int count = 0;
+ for (int a = 0; a < Qt::WA_AttributeCount; ++a) {
+ if (widget->testAttribute(static_cast<Qt::WidgetAttribute>(a))) {
+ if (count++)
+ debug << ',';
+ debug << me.valueToKey(a);
+ }
}
}
debug << ']';
+ return debug;
+}
}
QDebug operator<<(QDebug debug, const QWidget *widget)
@@ -13133,7 +13247,7 @@ QDebug operator<<(QDebug debug, const QWidget *widget)
debug << ", disabled";
debug << ", states=" << widget->windowState()
<< ", type=" << widget->windowType() << ", flags=" << widget->windowFlags();
- formatWidgetAttributes(debug, widget);
+ debug << ", attributes=" << WidgetAttributes{widget};
if (widget->isWindow())
debug << ", window";
debug << ", " << geometry.width() << 'x' << geometry.height()
@@ -13157,6 +13271,404 @@ QDebug operator<<(QDebug debug, const QWidget *widget)
}
#endif // !QT_NO_DEBUG_STREAM
+
+// *************************** Focus abstraction ************************************
+
+#define FOCUS_NEXT(w) w->d_func()->focus_next
+#define FOCUS_PREV(w) w->d_func()->focus_prev
+
+/*!
+ \internal
+ \return next or previous element in the focus chain, depending on
+ \param direction, irrespective of focus proxies or widgets with Qt::NoFocus.
+ */
+QWidget *QWidgetPrivate::nextPrevElementInFocusChain(FocusDirection direction) const
+{
+ Q_Q(const QWidget);
+ return direction == FocusDirection::Next ? FOCUS_NEXT(q) : FOCUS_PREV(q);
+}
+
+/*!
+ \internal
+ Removes a widget from the focus chain, respecting the flags set in \param rules.
+ \list
+ \li EnsureFocusOut: If the widget has input focus, transfer focus to the next or previous widget
+ in the focus chain, depending on \param direction.
+ \li RemoveInconsistent: Remove the widget, even if its focus chain is inconsistent.
+ \li AssertConsistency: qFatal, if the focus chain is inconsistent. This is used in the QWidget destructor.
+ \endlist
+ \return \c true if the widget has been removed, otherwise \c false.
+ */
+bool QWidgetPrivate::removeFromFocusChain(FocusChainRemovalRules rules, FocusDirection direction)
+{
+ Q_Q(QWidget);
+ if (!isFocusChainConsistent()) {
+#ifdef QT_DEBUG
+ if (rules.testFlag(FocusChainRemovalRule::AssertConsistency))
+ qFatal() << q << "has inconsistent focus chain.";
+#endif
+ qCDebug(lcWidgetFocus) << q << "wasn't removed, because of inconsistent focus chain.";
+ return false;
+ }
+
+ if (!isInFocusChain()) {
+ qCDebug(lcWidgetFocus) << q << "wasn't removed, because it is not part of a focus chain.";
+ return false;
+ }
+
+ if (rules.testFlag(FocusChainRemovalRule::EnsureFocusOut))
+ q->focusNextPrevChild(direction == FocusDirection::Next);
+
+ FOCUS_NEXT(FOCUS_PREV(q)) = FOCUS_NEXT(q);
+ FOCUS_PREV(FOCUS_NEXT(q)) = FOCUS_PREV(q);
+ initFocusChain();
+ qCDebug(lcWidgetFocus) << q << "removed from focus chain.";
+ return true;
+}
+
+/*!
+ \internal
+ Initialises the focus chain by making the widget point to itself.
+ */
+void QWidgetPrivate::initFocusChain()
+{
+ Q_Q(QWidget);
+ qCDebug(lcWidgetFocus) << "Initializing focus chain of" << q;
+ FOCUS_PREV(q) = q;
+ FOCUS_NEXT(q) = q;
+}
+
+/*!
+ \internal
+ Reads QWidget children, which are not part of a focus chain yet.
+ Inserts them into the focus chain before or after the widget,
+ depending on \param direction and in the order of their creation.
+ This is used, when QWidget::setParent() causes a widget to change toplevel windows.
+ */
+void QWidgetPrivate::reparentFocusChildren(FocusDirection direction)
+{
+ Q_Q(QWidget);
+ QWidgetList focusChildrenInsideChain;
+ QDuplicateTracker<QWidget *> seen;
+ QWidget *widget = q->nextInFocusChain();
+ while (q->isAncestorOf(widget)
+ && !seen.hasSeen(widget)
+ && widget != q->window()) {
+ if (widget->focusPolicy() != Qt::NoFocus)
+ focusChildrenInsideChain << widget;
+
+ widget = direction == FocusDirection::Next ? widget->nextInFocusChain()
+ : widget->previousInFocusChain();
+ }
+
+ const QWidgetList children = q->findChildren<QWidget *>(Qt::FindDirectChildrenOnly);
+ QWidgetList focusChildrenOutsideChain;
+ for (auto *child : children) {
+ if (!focusChildrenInsideChain.contains(child))
+ focusChildrenOutsideChain << child;
+ }
+ if (focusChildrenOutsideChain.isEmpty())
+ return;
+
+ QWidget *previous = q;
+ for (auto *child : focusChildrenOutsideChain) {
+ child->d_func()->insertIntoFocusChain(direction, previous);
+ previous = child;
+ }
+}
+
+/*!
+ \internal
+ Inserts a widget into the focus chain before or after \param position, depending on
+ \param direction.
+ \return \c true, if the insertion has changed the focus chain, otherwise \c false.
+ */
+bool QWidgetPrivate::insertIntoFocusChain(FocusDirection direction, QWidget *position)
+{
+ Q_Q(QWidget);
+ Q_ASSERT(position);
+ QWidget *next = FOCUS_NEXT(q);
+ QWidget *previous = FOCUS_PREV(q);
+
+ switch (direction) {
+ case FocusDirection::Next:
+ if (previous == position) {
+ qCDebug(lcWidgetFocus) << "No-op insertion." << q << "is already before" << position;
+ return false;
+ }
+
+ removeFromFocusChain(FocusChainRemovalRule::AssertConsistency);
+
+ FOCUS_NEXT(q) = FOCUS_NEXT(position);
+ FOCUS_PREV(FOCUS_NEXT(position)) = q;
+ FOCUS_NEXT(position) = q;
+ FOCUS_PREV(q) = position;
+ qCDebug(lcWidgetFocus) << q << "inserted after" << position;
+ break;
+
+ case FocusDirection::Previous:
+ if (next == position) {
+ qCDebug(lcWidgetFocus) << "No-op insertion." << q << "is already after" << position;
+ return false;
+ }
+
+ removeFromFocusChain(FocusChainRemovalRule::AssertConsistency);
+
+ FOCUS_PREV(q) = FOCUS_PREV(position);
+ FOCUS_NEXT(FOCUS_PREV(position)) = q;
+ FOCUS_PREV(position) = q;
+ FOCUS_NEXT(q) = position;
+ qCDebug(lcWidgetFocus) << q << "inserted before" << position;
+ break;
+ }
+
+ Q_ASSERT(isFocusChainConsistent());
+ return true;
+}
+
+/*!
+ \internal
+ Convenience override to insert a QWidgetList \param toBeInserted into the focus chain
+ before or after \param position, depending on \param direction.
+ \return \c true, if the insertion has changed the focus chain, otherwise \c false.
+ \note
+ \param toBeInserted must be a consistent focus chain.
+ */
+bool QWidgetPrivate::insertIntoFocusChain(const QWidgetList &toBeInserted,
+ FocusDirection direction, QWidget *position)
+{
+ if (toBeInserted.isEmpty()) {
+ qCDebug(lcWidgetFocus) << "No-op insertion of an empty list";
+ return false;
+ }
+
+ Q_ASSERT_X(!toBeInserted.contains(position),
+ Q_FUNC_INFO,
+ "Coding error: toBeInserted contains position");
+
+ QWidget *first = toBeInserted.constFirst();
+ QWidget *last = toBeInserted.constLast();
+
+ // Call QWidget override to log accordingly
+ if (toBeInserted.count() == 1)
+ return first->d_func()->insertIntoFocusChain(direction, position);
+
+ Q_ASSERT(first != last);
+ switch (direction) {
+ case FocusDirection::Previous:
+ if (FOCUS_PREV(position) == last) {
+ qCDebug(lcWidgetFocus) << "No-op insertion." << toBeInserted << "is already before"
+ << position;
+ return false;
+ }
+ FOCUS_NEXT(FOCUS_PREV(position)) = first;
+ FOCUS_PREV(first) = FOCUS_PREV(position);
+ FOCUS_NEXT(last) = position;
+ FOCUS_PREV(position) = last;
+ qCDebug(lcWidgetFocus) << toBeInserted << "inserted before" << position;
+ break;
+ case FocusDirection::Next:
+ if (FOCUS_PREV(position) == last) {
+ qCDebug(lcWidgetFocus) << "No-op insertion." << toBeInserted << "is already after"
+ << position;
+ return false;
+ }
+ FOCUS_PREV(FOCUS_NEXT(position)) = last;
+ FOCUS_NEXT(last) = FOCUS_NEXT(position);
+ FOCUS_PREV(first) = position;
+ FOCUS_NEXT(position) = first;
+ qCDebug(lcWidgetFocus) << toBeInserted << "inserted after" << position;
+ break;
+ }
+
+ Q_ASSERT(position->d_func()->isFocusChainConsistent());
+ return true;
+}
+
+/*!
+ \internal
+ \return a QWidgetList, representing the part of the focus chain,
+ starting with \param from and ending with \param to, in \param direction.
+ */
+QWidgetList focusPath(QWidget *from, QWidget *to, QWidgetPrivate::FocusDirection direction)
+{
+ QWidgetList path({from});
+ if (from == to)
+ return path;
+
+ QWidget *current = from;
+ do {
+ switch (direction) {
+ case QWidgetPrivate::FocusDirection::Previous:
+ current = current->previousInFocusChain();
+ break;
+ case QWidgetPrivate::FocusDirection::Next:
+ current = current->nextInFocusChain();
+ break;
+ }
+ if (path.contains(current))
+ return QWidgetList();
+ path << current;
+ } while (current != to);
+
+ return path;
+}
+
+/*!
+ \internal
+ Removes the part from the focus chain starting with \param from and ending with \param to,
+ in \param direction.
+ \return removed part as a QWidgetList.
+ */
+QWidgetList QWidgetPrivate::takeFromFocusChain(QWidget *from,
+ QWidget *to,
+ FocusDirection direction)
+{
+ // Check if there is a path from->to in direction
+ const QWidgetList path = focusPath(from, to , direction);
+ if (path.isEmpty()) {
+ qCDebug(lcWidgetFocus) << "No-op removal. Focus chain from" << from << "doesn't lead to " << to;
+ return QWidgetList();
+ }
+
+ QWidget *first = path.constFirst();
+ QWidget *last = path.constLast();
+ if (first == last) {
+ first->d_func()->removeFromFocusChain();
+ return QWidgetList({first});
+ }
+
+ FOCUS_NEXT(FOCUS_PREV(first)) = FOCUS_NEXT(last);
+ FOCUS_PREV(FOCUS_NEXT(last)) = FOCUS_PREV(first);
+ FOCUS_PREV(first) = last;
+ FOCUS_NEXT(last) = first;
+ qCDebug(lcWidgetFocus) << path << "removed from focus chain";
+ return path;
+}
+
+/*!
+ \internal
+ \return The last focus child of the widget, traversing the focus chain no further than
+ \param noFurtherThan.
+ */
+QWidget *QWidgetPrivate::determineLastFocusChild(QWidget *noFurtherThan)
+{
+ Q_Q(QWidget);
+ // Since we need to repeat the same logic for both 'first' and 'second', we add a function
+ // that determines the last focus child for a widget, taking proxies and compound widgets into
+ // account. If the target is not a compound widget (it doesn't have a focus proxy that points
+ // to a child), 'lastFocusChild' will be set to the target itself.
+ QWidget *lastFocusChild = q;
+
+ QWidget *focusProxy = deepestFocusProxy();
+ if (!focusProxy) {
+ // QTBUG-81097: Another case is possible here. We can have a child
+ // widget, that sets its focusProxy() to the parent (target).
+ // An example of such widget is a QLineEdit, nested into
+ // a QAbstractSpinBox. In this case such widget should be considered
+ // the last focus child.
+ for (auto *object : std::as_const(q->children())) {
+ QWidget *w = qobject_cast<QWidget *>(object);
+ if (w && w->focusProxy() == q) {
+ lastFocusChild = w;
+ break;
+ }
+ }
+ } else if (q->isAncestorOf(focusProxy)) {
+ lastFocusChild = focusProxy;
+ for (QWidget *focusNext = lastFocusChild->nextInFocusChain();
+ focusNext != focusProxy && q->isAncestorOf(focusNext)
+ && focusNext->window() == focusProxy->window();
+ focusNext = focusNext->nextInFocusChain()) {
+ if (focusNext == noFurtherThan)
+ break;
+ if (focusNext->focusPolicy() != Qt::NoFocus)
+ lastFocusChild = focusNext;
+ }
+ }
+ return lastFocusChild;
+};
+
+/*!
+ \internal
+ \return \c true, if the widget is part of a focus chain and \c false otherwise.
+ A widget is considered to be part of a focus chain, neither FOCUS_NEXT, nor FOCUS_PREV
+ are pointing to the widget itself.
+
+ \note
+ This method doesn't check the consistency of the focus chain.
+ If multiple widgets have been removed from the focus chain by takeFromFocusChain(),
+ isInFocusChain() will return \c true for all of those widgets, even if they represent
+ an inconsistent focus chain.
+ */
+bool QWidgetPrivate::isInFocusChain() const
+{
+ Q_Q(const QWidget);
+ return !(FOCUS_NEXT(q) == q && FOCUS_PREV(q) == q);
+}
+
+/*!
+ \internal
+ A focus chain is consistent, when it is circular: Following the chain in either direction
+ has to return to the beginning. This is why a newly constructed widget points to itself,
+ when the focus chain has been initialized. A newly constructed widget is considered to have
+ a consistent focus chain, while not being part of a focus chain.
+
+ The method always returns \c true, when the logging category "qt.widgets.focus" is disabled.
+ When it is enabled, the method returns \c true early, if a widget is pointing to itself.
+ It returns \c false, if one of the following is detected:
+ \list
+ \li nullptr found in a previous/next pointer.
+ \li broken chain: widget A is B's previous, but B isn't A's next.
+ \li chain isn't closed: starting at A doesn't lead back to A.
+ \endlist
+ It return \c true, if none of the above is observed.
+
+ \note
+ The focus chain is checked only in forward direction.
+ This is sufficient, because the check for a broken chain asserts consistent paths
+ in both directions.
+ */
+bool QWidgetPrivate::isFocusChainConsistent() const
+{
+ Q_Q(const QWidget);
+ const bool skip = !QLoggingCategory("qt.widgets.focus").isDebugEnabled();
+ if (skip)
+ return true;
+
+ if (!isInFocusChain())
+ return true;
+
+ const QWidget *position = q;
+
+ for (int i = 0; i < QApplication::allWidgets().count(); ++i) {
+ if (!FOCUS_PREV(position) || !FOCUS_NEXT(position)) {
+ qCDebug(lcWidgetFocus) << "Nullptr found at:" << position
+ << "Previous pointing to" << FOCUS_PREV(position)
+ << "Next pointing to" << FOCUS_NEXT(position);
+ return false;
+ }
+ if (!(FOCUS_PREV(FOCUS_NEXT(position)) == position
+ && FOCUS_NEXT(FOCUS_PREV(position)) == position)) {
+ qCDebug(lcWidgetFocus) << "Inconsistent focus chain at:" << position
+ << "Previous pointing to" << FOCUS_PREV(FOCUS_NEXT(position))
+ << "Next pointing to" << FOCUS_NEXT(FOCUS_PREV(position));
+ return false;
+ }
+ position = FOCUS_NEXT(position);
+ if (position == q)
+ return true;
+
+ }
+
+ qCDebug(lcWidgetFocus) << "Focus chain leading from" << q << "to" << position << "is not closed.";
+ return false;
+}
+
+#undef FOCUS_NEXT
+#undef FOCUS_PREV
+
+
QT_END_NAMESPACE
#include "moc_qwidget.cpp"
diff --git a/src/widgets/kernel/qwidget.h b/src/widgets/kernel/qwidget.h
index a0a1ca5300..e5e83a43f2 100644
--- a/src/widgets/kernel/qwidget.h
+++ b/src/widgets/kernel/qwidget.h
@@ -432,6 +432,7 @@ public:
void setFocusPolicy(Qt::FocusPolicy policy);
bool hasFocus() const;
static void setTabOrder(QWidget *, QWidget *);
+ static void setTabOrder(std::initializer_list<QWidget *> widgets);
void setFocusProxy(QWidget *);
QWidget *focusProxy() const;
Qt::ContextMenuPolicy contextMenuPolicy() const;
@@ -768,9 +769,6 @@ private:
#endif // QT_NO_GESTURES
friend class QWidgetEffectSourcePrivate;
-#ifdef Q_OS_MAC
- friend bool qt_mac_is_metal(const QWidget *w);
-#endif
friend Q_WIDGETS_EXPORT QWidgetData *qt_qwidget_data(QWidget *widget);
friend Q_WIDGETS_EXPORT QWidgetPrivate *qt_widget_private(QWidget *widget);
@@ -916,7 +914,6 @@ inline bool QWidget::testAttribute(Qt::WidgetAttribute attribute) const
return testAttribute_helper(attribute);
}
-
#define QWIDGETSIZE_MAX ((1<<24)-1)
#ifndef QT_NO_DEBUG_STREAM
diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h
index 2e1c4030f8..9fab9efa62 100644
--- a/src/widgets/kernel/qwidget_p.h
+++ b/src/widgets/kernel/qwidget_p.h
@@ -41,6 +41,9 @@
#include <private/qgesture_p.h>
#include <qpa/qplatformbackingstore.h>
#include <QtGui/private/qbackingstorerhisupport_p.h>
+#include <private/qapplication_p.h>
+
+#include <QtCore/qpointer.h>
#include <vector>
#include <memory>
@@ -48,6 +51,7 @@
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcWidgetPainting);
+Q_DECLARE_LOGGING_CATEGORY(lcWidgetShowHide);
// Extra QWidget data
// - to minimize memory usage for members that are seldom used.
@@ -75,13 +79,10 @@ public:
{
}
- ~QUpdateLaterEvent()
- {
- }
-
inline const QRegion &region() const { return m_region; }
protected:
+ friend class QApplication;
QRegion m_region;
};
@@ -221,6 +222,8 @@ public:
void setSharedPainter(QPainter *painter);
QWidgetRepaintManager *maybeRepaintManager() const;
+ QRhi *rhi() const;
+
enum class WindowHandleMode {
Direct,
Closest,
@@ -368,6 +371,8 @@ public:
void showChildren(bool spontaneous);
void hideChildren(bool spontaneous);
void setParent_sys(QWidget *parent, Qt::WindowFlags);
+ void reparentWidgetWindows(QWidget *parentWithWindow, Qt::WindowFlags windowFlags = {});
+ void reparentWidgetWindowChildren(QWidget *parentWithWindow);
void scroll_sys(int dx, int dy);
void scroll_sys(int dx, int dy, const QRect &r);
void deactivateWidgetCleanup();
@@ -380,6 +385,7 @@ public:
void show_sys();
void hide_sys();
void hide_helper();
+ bool isExplicitlyHidden() const;
void _q_showIfNotHidden();
void setVisible(bool);
@@ -579,7 +585,7 @@ public:
inline QRect mapFromWS(const QRect &r) const
{ return r.translated(data.wrect.topLeft()); }
- virtual QObject *focusObject() { return nullptr; }
+ virtual QObject *focusObject();
virtual QPlatformBackingStoreRhiConfig rhiConfig() const { return {}; }
@@ -634,6 +640,8 @@ public:
std::string flagsForDumping() const override;
+ QWidget *closestParentWidgetWithWindowHandle() const;
+
// Variables.
// Regular pointers (keep them together to avoid gaps on 64 bit architectures).
std::unique_ptr<QWExtra> extra;
@@ -726,6 +734,40 @@ public:
uint childrenHiddenByWState : 1;
uint childrenShownByExpose : 1;
+ // *************************** Focus abstraction ************************************
+ enum class FocusDirection {
+ Previous,
+ Next,
+ };
+
+ enum class FocusChainRemovalRule {
+ EnsureFocusOut = 0x01,
+ AssertConsistency = 0x02,
+ };
+ Q_DECLARE_FLAGS(FocusChainRemovalRules, FocusChainRemovalRule)
+
+ // Getters
+ QWidget *nextPrevElementInFocusChain(FocusDirection direction) const;
+
+ // manipulators
+ bool removeFromFocusChain(FocusChainRemovalRules rules = FocusChainRemovalRules(),
+ FocusDirection direction = FocusDirection::Next);
+ bool insertIntoFocusChain(FocusDirection direction, QWidget *position);
+ static bool insertIntoFocusChain(const QWidgetList &toBeInserted, FocusDirection direction, QWidget *position);
+ bool insertIntoFocusChainBefore(QWidget *position)
+ { return insertIntoFocusChain(FocusDirection::Previous, position); }
+ bool insertIntoFocusChainAfter(QWidget *position)
+ { return insertIntoFocusChain(FocusDirection::Next, position); }
+ static QWidgetList takeFromFocusChain(QWidget *from, QWidget *to,
+ FocusDirection direction = FocusDirection::Next);
+ void reparentFocusChildren(FocusDirection direction);
+ QWidget *determineLastFocusChild(QWidget *noFurtherThan);
+
+ // Initialization and tests
+ void initFocusChain();
+ bool isInFocusChain() const;
+ bool isFocusChainConsistent() const;
+
// *************************** Platform specific ************************************
#if defined(Q_OS_WIN)
uint noPaintOnScreen : 1; // see qwidget.cpp ::paintEngine()
@@ -736,6 +778,7 @@ public:
bool stealKeyboardGrab(bool grab);
bool stealMouseGrab(bool grab);
+ bool hasChildWithFocusPolicy(Qt::FocusPolicy policy, const QWidget *excludeChildrenOf = nullptr) const;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QWidgetPrivate::DrawWidgetFlags)
diff --git a/src/widgets/kernel/qwidgetaction.cpp b/src/widgets/kernel/qwidgetaction.cpp
index 4a3fb2be89..13f386d3ec 100644
--- a/src/widgets/kernel/qwidgetaction.cpp
+++ b/src/widgets/kernel/qwidgetaction.cpp
@@ -5,6 +5,8 @@
#include "qwidget.h"
#include "qdebug.h"
+#include <QtWidgets/private/qwidget_p.h>
+
#include "qwidgetaction_p.h"
QT_BEGIN_NAMESPACE
@@ -82,9 +84,9 @@ QWidgetAction::QWidgetAction(QObject *parent)
QWidgetAction::~QWidgetAction()
{
Q_D(QWidgetAction);
- for (int i = 0; i < d->createdWidgets.size(); ++i)
- disconnect(d->createdWidgets.at(i), SIGNAL(destroyed(QObject*)),
- this, SLOT(_q_widgetDestroyed(QObject*)));
+ for (QWidget *w : std::as_const(d->createdWidgets))
+ QObjectPrivate::disconnect(w, &QWidget::destroyed,
+ d, &QWidgetActionPrivate::widgetDestroyed);
QList<QWidget *> widgetsToDelete = d->createdWidgets;
d->createdWidgets.clear();
qDeleteAll(widgetsToDelete);
@@ -108,7 +110,7 @@ void QWidgetAction::setDefaultWidget(QWidget *widget)
if (!widget)
return;
- setVisible(!(widget->isHidden() && widget->testAttribute(Qt::WA_WState_ExplicitShowHide)));
+ setVisible(!QWidgetPrivate::get(widget)->isExplicitlyHidden());
d->defaultWidget->hide();
d->defaultWidget->setParent(nullptr);
d->defaultWidgetInUse = false;
@@ -147,8 +149,8 @@ QWidget *QWidgetAction::requestWidget(QWidget *parent)
return d->defaultWidget;
}
- connect(w, SIGNAL(destroyed(QObject*)),
- this, SLOT(_q_widgetDestroyed(QObject*)));
+ QObjectPrivate::connect(w, &QWidget::destroyed,
+ d, &QWidgetActionPrivate::widgetDestroyed);
d->createdWidgets.append(w);
return w;
}
@@ -175,8 +177,8 @@ void QWidgetAction::releaseWidget(QWidget *widget)
if (!d->createdWidgets.contains(widget))
return;
- disconnect(widget, SIGNAL(destroyed(QObject*)),
- this, SLOT(_q_widgetDestroyed(QObject*)));
+ QObjectPrivate::disconnect(widget, &QWidget::destroyed,
+ d, &QWidgetActionPrivate::widgetDestroyed);
d->createdWidgets.removeAll(widget);
deleteWidget(widget);
}
diff --git a/src/widgets/kernel/qwidgetaction.h b/src/widgets/kernel/qwidgetaction.h
index b8539f275b..296ff52d1e 100644
--- a/src/widgets/kernel/qwidgetaction.h
+++ b/src/widgets/kernel/qwidgetaction.h
@@ -37,7 +37,6 @@ protected:
private:
Q_DISABLE_COPY(QWidgetAction)
- Q_PRIVATE_SLOT(d_func(), void _q_widgetDestroyed(QObject *))
friend class QToolBar;
};
diff --git a/src/widgets/kernel/qwidgetaction_p.h b/src/widgets/kernel/qwidgetaction_p.h
index bd156241c6..6a1cd8c186 100644
--- a/src/widgets/kernel/qwidgetaction_p.h
+++ b/src/widgets/kernel/qwidgetaction_p.h
@@ -18,6 +18,8 @@
#include <QtWidgets/private/qtwidgetsglobal_p.h>
#include "private/qaction_widgets_p.h"
+#include <QtCore/qpointer.h>
+
QT_REQUIRE_CONFIG(action);
QT_BEGIN_NAMESPACE
@@ -32,7 +34,7 @@ public:
uint defaultWidgetInUse : 1;
uint autoCreated : 1; // created by QToolBar::addWidget and the like
- inline void _q_widgetDestroyed(QObject *o) {
+ inline void widgetDestroyed(QObject *o) {
createdWidgets.removeAll(static_cast<QWidget *>(o));
}
};
diff --git a/src/widgets/kernel/qwidgetrepaintmanager.cpp b/src/widgets/kernel/qwidgetrepaintmanager.cpp
index 718f904f93..607a767a20 100644
--- a/src/widgets/kernel/qwidgetrepaintmanager.cpp
+++ b/src/widgets/kernel/qwidgetrepaintmanager.cpp
@@ -1,7 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
#include "qplatformdefs.h"
#include "qwidgetrepaintmanager_p.h"
@@ -49,7 +48,7 @@ public:
}
bool isLocked() const {
- foreach (bool v, m_locked) {
+ for (const auto &[_, v] : m_locked.asKeyValueRange()) {
if (v)
return true;
}
@@ -340,9 +339,9 @@ void QWidgetRepaintManager::sendUpdateRequest(QWidget *widget, UpdateTime update
// compositing and waiting for vsync each and every time. Change to
// UpdateLater, except for approx. once per frame to prevent starvation in
// case the control does not get back to the event loop.
- QWidget *w = widget->window();
- if (updateTime == UpdateNow && w && w->windowHandle() && QWindowPrivate::get(w->windowHandle())->compositing) {
+ if (updateTime == UpdateNow && QWidgetPrivate::get(widget)->textureChildSeen) {
int refresh = 60;
+ QWidget *w = widget->window();
QScreen *ws = w->windowHandle()->screen();
if (ws)
refresh = ws->refreshRate();
@@ -351,12 +350,16 @@ void QWidgetRepaintManager::sendUpdateRequest(QWidget *widget, UpdateTime update
const qint64 elapsed = wd->lastComposeTime.elapsed();
if (elapsed <= qint64(1000.0f / refresh))
updateTime = UpdateLater;
- }
+ }
}
switch (updateTime) {
case UpdateLater:
- updateRequestSent = true;
+ // Prevent redundant update request events, unless it's a
+ // paint on screen widget, as these don't go through the
+ // normal backingstore sync machinery.
+ if (!widget->d_func()->shouldPaintOnScreen())
+ updateRequestSent = true;
QCoreApplication::postEvent(widget, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority);
break;
case UpdateNow: {
@@ -707,7 +710,9 @@ void QWidgetRepaintManager::paintAndFlush()
const QRect tlwRect = tlw->data->crect;
if (!updatesDisabled && store->size() != tlwRect.size()) {
- if (hasStaticContents() && !store->size().isEmpty() ) {
+ QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration();
+ if (hasStaticContents() && !store->size().isEmpty()
+ && integration->hasCapability(QPlatformIntegration::BackingStoreStaticContents)) {
// Repaint existing dirty area and newly visible area.
const QRect clipRect(QPoint(0, 0), store->size());
const QRegion staticRegion(staticContents(nullptr, clipRect));
@@ -800,7 +805,6 @@ void QWidgetRepaintManager::paintAndFlush()
QTLWExtra *tlwExtra = tlw->d_func()->topData();
tlwExtra->widgetTextures.clear();
findAllTextureWidgetsRecursively(tlw, tlw);
- qt_window_private(tlw->windowHandle())->compositing = false; // will get updated in flush()
if (toClean.isEmpty()) {
// Nothing to repaint. However renderToTexture widgets are handled
@@ -1033,7 +1037,36 @@ void QWidgetRepaintManager::flush(QWidget *widget, const QRegion &region, QPlatf
if (widget != tlw)
offset += widget->mapTo(tlw, QPoint());
- if (tlw->d_func()->usesRhiFlush) {
+ // Use a condition that tries to keep both QTBUG-108344 and QTBUG-113557
+ // happy, i.e. support both (A) "native rhi-based child in a rhi-based
+ // toplevel" and (B) "native raster child in a rhi-based toplevel".
+ //
+ // If the tlw and the backingstore are RHI-based, then there are two cases
+ // to consider:
+ //
+ // (1) widget is not a native child, i.e. the QWindow for widget and tlw are
+ // the same,
+ //
+ // (2) widget is a native child which we now attempt to flush with tlw's
+ // backingstore to widget's native window. This is the interesting one.
+ //
+ // Using the condition tlw->usesRhiFlush on its own is insufficient since
+ // it fails to capture the case of a raster-based native child widget
+ // within tlw. (which must hit the non-rhi flush path)
+ //
+ // Extending the condition with tlw->windowHandle() == widget->windowHandle()
+ // would be logical but wrong, when it comes to (A) since flushing a
+ // RHI-based native child with a given 3D API using a RHI-based
+ // tlw/backingstore with the same 3D API needs to be supported still. (this
+ // happens when e.g. someone calls winId() on a QOpenGLWidget)
+ //
+ // Different 3D APIs do not need to be supported since we do not allow to
+ // do things like having a QQuickWidget with Vulkan and a QOpenGLWidget in
+ // the same toplevel, regardless of the widgets being native children or
+ // not. Hence comparing the surfaceType() instead. This satisfies both (A)
+ // and (B) given that an RHI-based toplevel cannot be RasterSurface.
+ //
+ if (tlw->d_func()->usesRhiFlush && tlw->windowHandle()->surfaceType() == widget->windowHandle()->surfaceType()) {
QRhi *rhi = store->handle()->rhi();
qCDebug(lcWidgetPainting) << "Flushing" << region << "of" << widget
<< "with QRhi" << rhi
@@ -1041,7 +1074,6 @@ void QWidgetRepaintManager::flush(QWidget *widget, const QRegion &region, QPlatf
if (!widgetTextures)
widgetTextures = qt_dummy_platformTextureList;
- qt_window_private(tlw->windowHandle())->compositing = true;
QWidgetPrivate *widgetWindowPrivate = widget->window()->d_func();
widgetWindowPrivate->sendComposeStatus(widget->window(), false);
// A window may have alpha even when the app did not request
@@ -1112,11 +1144,7 @@ void QWidgetRepaintManager::removeStaticWidget(QWidget *widget)
bool QWidgetRepaintManager::hasStaticContents() const
{
-#if defined(Q_OS_WIN)
return !staticWidgets.isEmpty();
-#else
- return !staticWidgets.isEmpty() && false;
-#endif
}
/*!
diff --git a/src/widgets/kernel/qwidgetsvariant.cpp b/src/widgets/kernel/qwidgetsvariant.cpp
index f5d511abd2..17a19aa780 100644
--- a/src/widgets/kernel/qwidgetsvariant.cpp
+++ b/src/widgets/kernel/qwidgetsvariant.cpp
@@ -12,7 +12,8 @@ QT_BEGIN_NAMESPACE
namespace {
-static const struct : QMetaTypeModuleHelper
+// NOLINTNEXTLINE(cppcoreguidelines-virtual-class-destructor): this is not a base class
+static constexpr struct : QMetaTypeModuleHelper
{
const QtPrivate::QMetaTypeInterface *interfaceForType(int type) const override {
switch (type) {
diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp
index 7756893369..c5b045c8db 100644
--- a/src/widgets/kernel/qwidgetwindow.cpp
+++ b/src/widgets/kernel/qwidgetwindow.cpp
@@ -39,21 +39,25 @@ public:
void setVisible(bool visible) override
{
Q_Q(QWidgetWindow);
+ qCDebug(lcWidgetShowHide) << "Setting visibility of" << q->widget()
+ << "to" << visible << "via QWidgetWindowPrivate";
+
if (QWidget *widget = q->widget()) {
- // Check if the widget was already hidden, as this indicates it was done
- // explicitly and not because the parent window in this case made it hidden.
- // In which case do not automatically show the widget when the parent
- // window is shown.
- const bool wasExplicitShowHide = widget->testAttribute(Qt::WA_WState_ExplicitShowHide);
- const bool wasHidden = widget->testAttribute(Qt::WA_WState_Hidden);
- QWidgetPrivate::get(widget)->setVisible(visible);
- if (wasExplicitShowHide) {
- widget->setAttribute(Qt::WA_WState_ExplicitShowHide, wasExplicitShowHide);
- widget->setAttribute(Qt::WA_WState_Hidden, wasHidden);
- }
- } else {
- QWindowPrivate::setVisible(visible);
+ // If the widget's visible state is already matching the new QWindow
+ // visible state we assume the widget has already synced up.
+ if (visible != widget->isVisible())
+ QWidgetPrivate::get(widget)->setVisible(visible);
}
+
+ // If we end up calling QWidgetPrivate::setVisible() above, we will
+ // in most cases recurse back into setNativeWindowVisibility() to
+ // update the QWindow state. But during QWidget::destroy() this is
+ // not the case, as Qt::WA_WState_Created has been unset by the time
+ // we check if we should call hide_helper(). We handle this case, as
+ // well as the cases where we don't call QWidgetPrivate::setVisible(),
+ // by syncing up the QWindow state here if needed.
+ if (q->isVisible() != visible)
+ QWindowPrivate::setVisible(visible);
}
QWindow *eventReceiver() override {
@@ -73,6 +77,39 @@ public:
widget->focusWidget()->clearFocus();
}
+ void setFocusToTarget(QWindowPrivate::FocusTarget target) override
+ {
+ Q_Q(QWidgetWindow);
+ QWidget *widget = q->widget();
+ if (!widget)
+ return;
+ QWidget *newFocusWidget = nullptr;
+
+ switch (target) {
+ case FocusTarget::First:
+ newFocusWidget = q->getFocusWidget(QWidgetWindow::FirstFocusWidget);
+ break;
+ case FocusTarget::Last:
+ newFocusWidget = q->getFocusWidget(QWidgetWindow::LastFocusWidget);
+ break;
+ case FocusTarget::Next: {
+ QWidget *focusWidget = widget->focusWidget() ? widget->focusWidget() : widget;
+ newFocusWidget = focusWidget->nextInFocusChain() ? focusWidget->nextInFocusChain() : focusWidget;
+ break;
+ }
+ case FocusTarget::Prev: {
+ QWidget *focusWidget = widget->focusWidget() ? widget->focusWidget() : widget;
+ newFocusWidget = focusWidget->previousInFocusChain() ? focusWidget->previousInFocusChain() : focusWidget;
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (newFocusWidget)
+ newFocusWidget->setFocus();
+ }
+
QRectF closestAcceptableGeometry(const QRectF &rect) const override;
void processSafeAreaMarginsChanged() override
@@ -134,6 +171,21 @@ QWidgetWindow::QWidgetWindow(QWidget *widget)
QWidgetWindow::~QWidgetWindow()
{
+ if (!m_widget)
+ return;
+
+ QTLWExtra *topData = QWidgetPrivate::get(m_widget)->topData();
+ Q_ASSERT(topData);
+
+ // The QPlaformBackingStore may hold a reference to the window,
+ // so the backingstore needs to be deleted first.
+ topData->repaintManager.reset(nullptr);
+ delete topData->backingStore;
+ topData->backingStore = nullptr;
+ topData->widgetTextures.clear();
+
+ // Too late to do anything beyond this point
+ topData->window = nullptr;
}
#if QT_CONFIG(accessibility)
@@ -170,6 +222,9 @@ QObject *QWidgetWindow::focusObject() const
void QWidgetWindow::setNativeWindowVisibility(bool visible)
{
Q_D(QWidgetWindow);
+ qCDebug(lcWidgetShowHide) << "Setting visibility of" << this
+ << "to" << visible << "via QWidgetWindow::setNativeWindowVisibility";
+
// Call base class setVisible() implementation to run the QWindow
// visibility logic. Don't call QWidgetWindowPrivate::setVisible()
// since that will recurse back into QWidget code.
@@ -455,11 +510,11 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
QEvent::MouseButtonRelease : QEvent::MouseButtonPress;
if (QApplicationPrivate::inPopupMode()) {
QPointer<QWidget> activePopupWidget = QApplication::activePopupWidget();
- QPoint mapped = event->position().toPoint();
+ QPointF mapped = event->position();
if (activePopupWidget != m_widget)
- mapped = activePopupWidget->mapFromGlobal(event->globalPosition().toPoint());
+ mapped = activePopupWidget->mapFromGlobal(event->globalPosition());
bool releaseAfter = false;
- QWidget *popupChild = activePopupWidget->childAt(mapped);
+ QWidget *popupChild = activePopupWidget->childAt(mapped.toPoint());
if (activePopupWidget != qt_popup_down) {
qt_button_down = nullptr;
@@ -486,15 +541,15 @@ void QWidgetWindow::handleMouseEvent(QMouseEvent *event)
// deliver event
qt_replay_popup_mouse_event = false;
QPointer<QWidget> receiver = activePopupWidget;
- QPoint widgetPos = mapped;
+ QPointF widgetPos = mapped;
if (qt_button_down)
receiver = qt_button_down;
else if (popupChild)
receiver = popupChild;
if (receiver != activePopupWidget)
- widgetPos = receiver->mapFromGlobal(event->globalPosition().toPoint());
+ widgetPos = receiver->mapFromGlobal(event->globalPosition());
- const bool reallyUnderMouse = activePopupWidget->rect().contains(mapped);
+ const bool reallyUnderMouse = activePopupWidget->rect().contains(mapped.toPoint());
const bool underMouse = activePopupWidget->underMouse();
if (underMouse != reallyUnderMouse) {
if (reallyUnderMouse) {
diff --git a/src/widgets/kernel/qwidgetwindow_p.h b/src/widgets/kernel/qwidgetwindow_p.h
index 0eee3cd900..0ee6b71a79 100644
--- a/src/widgets/kernel/qwidgetwindow_p.h
+++ b/src/widgets/kernel/qwidgetwindow_p.h
@@ -22,6 +22,8 @@
#include <QtGui/private/qevent_p.h>
#include <QtWidgets/qwidget.h>
+#include <QtCore/qpointer.h>
+
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/kernel/qwindowcontainer.cpp b/src/widgets/kernel/qwindowcontainer.cpp
index 072a0bc5fa..376a93c758 100644
--- a/src/widgets/kernel/qwindowcontainer.cpp
+++ b/src/widgets/kernel/qwindowcontainer.cpp
@@ -3,7 +3,9 @@
#include "qwindowcontainer_p.h"
#include "qwidget_p.h"
+#include "qwidgetwindow_p.h"
#include <QtGui/qwindow.h>
+#include <QtGui/private/qwindow_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
#include <QDebug>
@@ -14,6 +16,8 @@
#include <QAbstractScrollArea>
#include <QPainter>
+#include <QtCore/qpointer.h>
+
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
@@ -25,7 +29,6 @@ public:
QWindowContainerPrivate()
: window(nullptr)
- , oldFocusWindow(nullptr)
, usesNativeWidgets(false)
{
}
@@ -100,7 +103,6 @@ public:
}
QPointer<QWindow> window;
- QWindow *oldFocusWindow;
QWindow fakeParent;
uint usesNativeWidgets : 1;
@@ -162,11 +164,31 @@ public:
application can greatly hurt the overall performance of the
application.
+ \li Since 6.7, if \a window belongs to a widget (that is, \a window
+ was received from calling \l windowHandle()), no container will be
+ created. Instead, this function will return the widget itself, after
+ being reparented to \l parent. Since no container will be created,
+ \a flags will be ignored. In other words, if \a window belongs to
+ a widget, consider just reparenting that widget to \a parent instead
+ of using this function.
+
\endlist
*/
QWidget *QWidget::createWindowContainer(QWindow *window, QWidget *parent, Qt::WindowFlags flags)
{
+ // Embedding a QWidget in a window container doesn't make sense,
+ // and has various issues in practice, so just return the widget
+ // itself.
+ if (auto *widgetWindow = qobject_cast<QWidgetWindow *>(window)) {
+ QWidget *widget = widgetWindow->widget();
+ if (flags != Qt::WindowFlags()) {
+ qWarning() << window << "refers to a widget:" << widget
+ << "WindowFlags" << flags << "will be ignored.";
+ }
+ widget->setParent(parent);
+ return widget;
+ }
return new QWindowContainer(window, parent, flags);
}
@@ -184,6 +206,7 @@ QWindowContainer::QWindowContainer(QWindow *embeddedWindow, QWidget *parent, Qt:
}
d->window = embeddedWindow;
+ d->window->installEventFilter(this);
QString windowName = d->window->objectName();
if (windowName.isEmpty())
@@ -196,7 +219,8 @@ QWindowContainer::QWindowContainer(QWindow *embeddedWindow, QWidget *parent, Qt:
setAcceptDrops(true);
- connect(QGuiApplication::instance(), SIGNAL(focusWindowChanged(QWindow*)), this, SLOT(focusWindowChanged(QWindow*)));
+ connect(containedWindow(), &QWindow::minimumHeightChanged, this, &QWindowContainer::updateGeometry);
+ connect(containedWindow(), &QWindow::minimumWidthChanged, this, &QWindowContainer::updateGeometry);
}
QWindow *QWindowContainer::containedWindow() const
@@ -217,29 +241,14 @@ QWindowContainer::~QWindowContainer()
// 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)
+ if (d->window) {
+ d->window->removeEventFilter(this);
d->window->destroy();
+ }
delete d->window;
}
-
-
-/*!
- \internal
- */
-
-void QWindowContainer::focusWindowChanged(QWindow *focusWindow)
-{
- Q_D(QWindowContainer);
- d->oldFocusWindow = focusWindow;
- if (focusWindow == d->window) {
- QWidget *widget = QApplication::focusWidget();
- if (widget)
- widget->clearFocus();
- }
-}
-
/*!
\internal
*/
@@ -254,8 +263,12 @@ bool QWindowContainer::eventFilter(QObject *o, QEvent *e)
QChildEvent *ce = static_cast<QChildEvent *>(e);
if (ce->child() == d->window) {
o->removeEventFilter(this);
+ d->window->removeEventFilter(this);
d->window = nullptr;
}
+ } else if (e->type() == QEvent::FocusIn) {
+ if (o == d->window)
+ setFocus(Qt::ActiveWindowFocusReason);
}
return false;
}
@@ -305,11 +318,16 @@ bool QWindowContainer::event(QEvent *e)
break;
case QEvent::FocusIn:
if (d->window->parent()) {
- if (d->oldFocusWindow != d->window) {
+ if (QGuiApplication::focusWindow() != d->window) {
+ QFocusEvent *event = static_cast<QFocusEvent *>(e);
+ const auto reason = event->reason();
+ QWindowPrivate::FocusTarget target = QWindowPrivate::FocusTarget::Current;
+ if (reason == Qt::TabFocusReason)
+ target = QWindowPrivate::FocusTarget::First;
+ else if (reason == Qt::BacktabFocusReason)
+ target = QWindowPrivate::FocusTarget::Last;
+ qt_window_private(d->window)->setFocusToTarget(target);
d->window->requestActivate();
- } else {
- QWidget *next = nextInFocusChain();
- next->setFocus();
}
}
break;
@@ -346,6 +364,11 @@ bool QWindowContainer::event(QEvent *e)
return QWidget::event(e);
}
+QSize QWindowContainer::minimumSizeHint() const
+{
+ return containedWindow() ? containedWindow()->minimumSize() : QSize(0, 0);
+}
+
typedef void (*qwindowcontainer_traverse_callback)(QWidget *parent);
static void qwindowcontainer_traverse(QWidget *parent, qwindowcontainer_traverse_callback callback)
{
diff --git a/src/widgets/kernel/qwindowcontainer_p.h b/src/widgets/kernel/qwindowcontainer_p.h
index 8dc5c64af4..0cbcc5321d 100644
--- a/src/widgets/kernel/qwindowcontainer_p.h
+++ b/src/widgets/kernel/qwindowcontainer_p.h
@@ -31,6 +31,7 @@ public:
explicit QWindowContainer(QWindow *embeddedWindow, QWidget *parent = nullptr, Qt::WindowFlags f = { });
~QWindowContainer();
QWindow *containedWindow() const;
+ QSize minimumSizeHint() const override;
static void toplevelAboutToBeDestroyed(QWidget *parent);
static void parentWasChanged(QWidget *parent);
@@ -41,9 +42,6 @@ public:
protected:
bool event(QEvent *ev) override;
bool eventFilter(QObject *, QEvent *ev) override;
-
-private slots:
- void focusWindowChanged(QWindow *focusWindow);
};
QT_END_NAMESPACE
diff --git a/src/widgets/platform/ios/PrivacyInfo.xcprivacy b/src/widgets/platform/ios/PrivacyInfo.xcprivacy
new file mode 100644
index 0000000000..819b868e1a
--- /dev/null
+++ b/src/widgets/platform/ios/PrivacyInfo.xcprivacy
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>NSPrivacyTracking</key>
+ <false/>
+ <key>NSPrivacyCollectedDataTypes</key>
+ <array/>
+ <key>NSPrivacyTrackingDomains</key>
+ <array/>
+ <key>NSPrivacyAccessedAPITypes</key>
+ <array>
+ <dict>
+ <key>NSPrivacyAccessedAPIType</key>
+ <string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
+ <key>NSPrivacyAccessedAPITypeReasons</key>
+ <array>
+ <string>DDA9.1</string> <!-- QFileDialog -->
+ <string>C617.1</string> <!-- QFileDialog -->
+ <string>3B52.1</string> <!-- QFileDialog -->
+ </array>
+ </dict>
+ </array>
+</dict>
+</plist>
diff --git a/src/widgets/styles/images/cleartext-128.png b/src/widgets/styles/images/cleartext-128.png
new file mode 100644
index 0000000000..b5a2ceb233
--- /dev/null
+++ b/src/widgets/styles/images/cleartext-128.png
Binary files differ
diff --git a/src/widgets/styles/images/cleartext-16.png b/src/widgets/styles/images/cleartext-16.png
index 74133bafff..53c42929cb 100644
--- a/src/widgets/styles/images/cleartext-16.png
+++ b/src/widgets/styles/images/cleartext-16.png
Binary files differ
diff --git a/src/widgets/styles/images/cleartext-32.png b/src/widgets/styles/images/cleartext-32.png
index ff5a2b5ec1..e7ecf70d6d 100644
--- a/src/widgets/styles/images/cleartext-32.png
+++ b/src/widgets/styles/images/cleartext-32.png
Binary files differ
diff --git a/src/widgets/styles/images/cleartext.svg b/src/widgets/styles/images/cleartext.svg
new file mode 100644
index 0000000000..d93c0c6b96
--- /dev/null
+++ b/src/widgets/styles/images/cleartext.svg
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="Layer_1"
+ x="0px"
+ y="0px"
+ viewBox="0 0 16 16"
+ style="enable-background:new 0 0 16 16;"
+ xml:space="preserve"
+ sodipodi:docname="cleartext.svg"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"><metadata
+ id="metadata15"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs13" /><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="918"
+ id="namedview11"
+ showgrid="false"
+ inkscape:zoom="33.14563"
+ inkscape:cx="1.0250743"
+ inkscape:cy="9.2813006"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="Layer_1" />
+<style
+ type="text/css"
+ id="style2">
+ .st0{fill:none;}
+</style>
+
+<circle
+ style="fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.0875;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path873"
+ cx="8"
+ cy="8"
+ r="7"
+ inkscape:label="circle" /><rect
+ id="rect19"
+ width="2.0723703"
+ height="9.2413387"
+ x="10.277523"
+ y="-4.6206694"
+ style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.101216;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ transform="rotate(44.999999)"
+ inkscape:label="rect2" /><rect
+ id="rect19-6"
+ width="2.0723705"
+ height="9.2413378"
+ x="-1.0361853"
+ y="6.6930394"
+ style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.101217;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ transform="rotate(-45)"
+ inkscape:label="rect1"
+ sodipodi:insensitive="true" /></svg>
diff --git a/src/widgets/styles/images/critical-128.png b/src/widgets/styles/images/critical-128.png
new file mode 100644
index 0000000000..329963cb38
--- /dev/null
+++ b/src/widgets/styles/images/critical-128.png
Binary files differ
diff --git a/src/widgets/styles/images/critical-16.png b/src/widgets/styles/images/critical-16.png
new file mode 100644
index 0000000000..d9da98beee
--- /dev/null
+++ b/src/widgets/styles/images/critical-16.png
Binary files differ
diff --git a/src/widgets/styles/images/critical-32.png b/src/widgets/styles/images/critical-32.png
new file mode 100644
index 0000000000..04d52591c3
--- /dev/null
+++ b/src/widgets/styles/images/critical-32.png
Binary files differ
diff --git a/src/widgets/styles/images/filedialog_end-128.png b/src/widgets/styles/images/filedialog_end-128.png
new file mode 100644
index 0000000000..f634792d2a
--- /dev/null
+++ b/src/widgets/styles/images/filedialog_end-128.png
Binary files differ
diff --git a/src/widgets/styles/images/filedialog_end-16.png b/src/widgets/styles/images/filedialog_end-16.png
new file mode 100644
index 0000000000..51fe8d1559
--- /dev/null
+++ b/src/widgets/styles/images/filedialog_end-16.png
Binary files differ
diff --git a/src/widgets/styles/images/filedialog_end-32.png b/src/widgets/styles/images/filedialog_end-32.png
new file mode 100644
index 0000000000..faa3a10293
--- /dev/null
+++ b/src/widgets/styles/images/filedialog_end-32.png
Binary files differ
diff --git a/src/widgets/styles/images/filedialog_start-128.png b/src/widgets/styles/images/filedialog_start-128.png
new file mode 100644
index 0000000000..f1272bd169
--- /dev/null
+++ b/src/widgets/styles/images/filedialog_start-128.png
Binary files differ
diff --git a/src/widgets/styles/images/filedialog_start-16.png b/src/widgets/styles/images/filedialog_start-16.png
new file mode 100644
index 0000000000..04430f53c9
--- /dev/null
+++ b/src/widgets/styles/images/filedialog_start-16.png
Binary files differ
diff --git a/src/widgets/styles/images/filedialog_start-32.png b/src/widgets/styles/images/filedialog_start-32.png
new file mode 100644
index 0000000000..c8b81a5ec7
--- /dev/null
+++ b/src/widgets/styles/images/filedialog_start-32.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_closedock-10.png b/src/widgets/styles/images/fusion_closedock-10.png
new file mode 100644
index 0000000000..d0c34d618b
--- /dev/null
+++ b/src/widgets/styles/images/fusion_closedock-10.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_closedock-16.png b/src/widgets/styles/images/fusion_closedock-16.png
new file mode 100644
index 0000000000..889c91e43f
--- /dev/null
+++ b/src/widgets/styles/images/fusion_closedock-16.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_closedock-20.png b/src/widgets/styles/images/fusion_closedock-20.png
new file mode 100644
index 0000000000..9076683d11
--- /dev/null
+++ b/src/widgets/styles/images/fusion_closedock-20.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_closedock-32.png b/src/widgets/styles/images/fusion_closedock-32.png
new file mode 100644
index 0000000000..a2a3328a50
--- /dev/null
+++ b/src/widgets/styles/images/fusion_closedock-32.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_closedock-48.png b/src/widgets/styles/images/fusion_closedock-48.png
new file mode 100644
index 0000000000..e915a1098b
--- /dev/null
+++ b/src/widgets/styles/images/fusion_closedock-48.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_closedock-64.png b/src/widgets/styles/images/fusion_closedock-64.png
new file mode 100644
index 0000000000..73c60feb6a
--- /dev/null
+++ b/src/widgets/styles/images/fusion_closedock-64.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_closedock.svg b/src/widgets/styles/images/fusion_closedock.svg
new file mode 100644
index 0000000000..eb5e472ce2
--- /dev/null
+++ b/src/widgets/styles/images/fusion_closedock.svg
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="Layer_1"
+ x="0px"
+ y="0px"
+ width="8px"
+ height="8px"
+ viewBox="0 0 8 8"
+ style="enable-background:new 0 0 8 8;"
+ xml:space="preserve"
+ sodipodi:docname="fusion_closedock.svg"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
+ inkscape:export-filename="/home/chehrlic/kde/qt.src/qtbase/src/widgets/styles/images/fusion_closedock-64.png"
+ inkscape:export-xdpi="768"
+ inkscape:export-ydpi="768"><metadata
+ id="metadata120"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
+ id="defs118">
+
+
+
+
+
+ </defs><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="917"
+ id="namedview116"
+ showgrid="false"
+ inkscape:zoom="63.727999"
+ inkscape:cx="5.1718865"
+ inkscape:cy="4.7238684"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="Layer_1"
+ inkscape:document-rotation="0" />
+<style
+ type="text/css"
+ id="style101">
+ .st0{fill:none;}
+ .st1{fill:#353637;}
+</style>
+<g
+ id="g105">
+
+ </g>
+<g
+ id="g981"><rect
+ x="5.1188383"
+ y="-2.9975181"
+ transform="rotate(45.000001)"
+ class="st1"
+ width="1.0760319"
+ height="5.9950356"
+ id="rect107"
+ style="fill:#6c6a67;fill-opacity:1;stroke-width:0.768594" /><rect
+ x="-0.53801638"
+ y="-8.6545134"
+ transform="rotate(135)"
+ class="st1"
+ width="1.0760319"
+ height="5.9950356"
+ id="rect109"
+ style="fill:#6c6a67;fill-opacity:1;stroke-width:0.768594" /><rect
+ style="fill:none;stroke:#6c6a67;stroke-width:0.469731;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect151"
+ width="6.5302691"
+ height="6.5302691"
+ x="0.73486549"
+ y="0.73486549" /></g></svg>
diff --git a/src/widgets/styles/images/fusion_normalizedockup-16.png b/src/widgets/styles/images/fusion_normalizedockup-16.png
new file mode 100644
index 0000000000..9e8d1f4716
--- /dev/null
+++ b/src/widgets/styles/images/fusion_normalizedockup-16.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_normalizedockup-32.png b/src/widgets/styles/images/fusion_normalizedockup-32.png
new file mode 100644
index 0000000000..453449cc7d
--- /dev/null
+++ b/src/widgets/styles/images/fusion_normalizedockup-32.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_normalizedockup.svg b/src/widgets/styles/images/fusion_normalizedockup.svg
new file mode 100644
index 0000000000..0d7068b563
--- /dev/null
+++ b/src/widgets/styles/images/fusion_normalizedockup.svg
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="Layer_1"
+ x="0px"
+ y="0px"
+ width="8px"
+ height="8px"
+ viewBox="0 0 8 8"
+ style="enable-background:new 0 0 8 8;"
+ xml:space="preserve"
+ sodipodi:docname="fusion_normalizedockup.svg"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
+ inkscape:export-filename="/home/chehrlic/kde/qt.src/qtbase/src/widgets/styles/images/fusion_normalizedockup_64.png"
+ inkscape:export-xdpi="768"
+ inkscape:export-ydpi="768"><metadata
+ id="metadata120"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
+ id="defs118">
+
+
+
+
+
+ </defs><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="917"
+ id="namedview116"
+ showgrid="false"
+ inkscape:zoom="63.727999"
+ inkscape:cx="3.979318"
+ inkscape:cy="4.7238684"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="g1123"
+ inkscape:document-rotation="0" />
+<style
+ type="text/css"
+ id="style101">
+ .st0{fill:none;}
+ .st1{fill:#353637;}
+</style>
+
+<rect
+ style="fill:none;stroke:#6c6a67;stroke-width:0.469731;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect151"
+ width="6.5302691"
+ height="6.5302691"
+ x="0.73486549"
+ y="0.73486549" /><g
+ id="g1123"
+ transform="matrix(0.85891433,0,0,0.86643038,0.5610817,0.55019701)"><path
+ id="rect151-3-6"
+ style="fill:none;stroke:#6c6a67;stroke-width:0.5;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 2.6347656,1.6347656 v 1 h 2.7304688 v 2.7304688 h 1 V 1.6347656 Z" /><path
+ style="fill:none;fill-opacity:1;stroke:#6c6a67;stroke-width:0.5;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1.634209,2.6342089 H 5.3657907 V 6.3657906 H 1.634209 Z"
+ id="rect151-3" /></g></svg>
diff --git a/src/widgets/styles/images/fusion_normalizedockup_10.png b/src/widgets/styles/images/fusion_normalizedockup_10.png
new file mode 100644
index 0000000000..7516e4ee4f
--- /dev/null
+++ b/src/widgets/styles/images/fusion_normalizedockup_10.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_normalizedockup_20.png b/src/widgets/styles/images/fusion_normalizedockup_20.png
new file mode 100644
index 0000000000..2bc9421d5a
--- /dev/null
+++ b/src/widgets/styles/images/fusion_normalizedockup_20.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_normalizedockup_48.png b/src/widgets/styles/images/fusion_normalizedockup_48.png
new file mode 100644
index 0000000000..6c497abdde
--- /dev/null
+++ b/src/widgets/styles/images/fusion_normalizedockup_48.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_normalizedockup_64.png b/src/widgets/styles/images/fusion_normalizedockup_64.png
new file mode 100644
index 0000000000..5ec620e5a0
--- /dev/null
+++ b/src/widgets/styles/images/fusion_normalizedockup_64.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_titlebar-min-10.png b/src/widgets/styles/images/fusion_titlebar-min-10.png
new file mode 100644
index 0000000000..97b1ab88c3
--- /dev/null
+++ b/src/widgets/styles/images/fusion_titlebar-min-10.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_titlebar-min-16.png b/src/widgets/styles/images/fusion_titlebar-min-16.png
new file mode 100644
index 0000000000..b318a232b3
--- /dev/null
+++ b/src/widgets/styles/images/fusion_titlebar-min-16.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_titlebar-min-20.png b/src/widgets/styles/images/fusion_titlebar-min-20.png
new file mode 100644
index 0000000000..4a6012bd2b
--- /dev/null
+++ b/src/widgets/styles/images/fusion_titlebar-min-20.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_titlebar-min-32.png b/src/widgets/styles/images/fusion_titlebar-min-32.png
new file mode 100644
index 0000000000..6e1c94827e
--- /dev/null
+++ b/src/widgets/styles/images/fusion_titlebar-min-32.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_titlebar-min-48.png b/src/widgets/styles/images/fusion_titlebar-min-48.png
new file mode 100644
index 0000000000..a79724f3ea
--- /dev/null
+++ b/src/widgets/styles/images/fusion_titlebar-min-48.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_titlebar-min-64.png b/src/widgets/styles/images/fusion_titlebar-min-64.png
new file mode 100644
index 0000000000..5dba9a0979
--- /dev/null
+++ b/src/widgets/styles/images/fusion_titlebar-min-64.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_titlebar-min.svg b/src/widgets/styles/images/fusion_titlebar-min.svg
new file mode 100644
index 0000000000..9f6350c8bf
--- /dev/null
+++ b/src/widgets/styles/images/fusion_titlebar-min.svg
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="Layer_1"
+ x="0px"
+ y="0px"
+ width="8px"
+ height="8px"
+ viewBox="0 0 8 8"
+ style="enable-background:new 0 0 8 8;"
+ xml:space="preserve"
+ sodipodi:docname="fusion_titlebar-min.svg"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
+ inkscape:export-filename="/home/chehrlic/kde/qt.src/qtbase/src/widgets/styles/images/fusion_titlebar-min-64.png"
+ inkscape:export-xdpi="768"
+ inkscape:export-ydpi="768"><metadata
+ id="metadata120"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
+ id="defs118">
+
+
+
+
+
+ </defs><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="917"
+ id="namedview116"
+ showgrid="false"
+ inkscape:zoom="45.0625"
+ inkscape:cx="-0.80217757"
+ inkscape:cy="6.6858335"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="Layer_1"
+ inkscape:document-rotation="0" />
+<style
+ type="text/css"
+ id="style101">
+ .st0{fill:none;}
+ .st1{fill:#353637;}
+</style>
+
+<rect
+ style="fill:#6c6a67;fill-opacity:1;stroke:none;stroke-width:0.529435;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect1157"
+ width="5.5"
+ height="1.5"
+ x="1"
+ y="5.5" /></svg>
diff --git a/src/widgets/styles/images/information-128.png b/src/widgets/styles/images/information-128.png
new file mode 100644
index 0000000000..2feebc4598
--- /dev/null
+++ b/src/widgets/styles/images/information-128.png
Binary files differ
diff --git a/src/widgets/styles/images/information-16.png b/src/widgets/styles/images/information-16.png
new file mode 100644
index 0000000000..deb24c71ab
--- /dev/null
+++ b/src/widgets/styles/images/information-16.png
Binary files differ
diff --git a/src/widgets/styles/images/information-32.png b/src/widgets/styles/images/information-32.png
new file mode 100644
index 0000000000..83b32b737a
--- /dev/null
+++ b/src/widgets/styles/images/information-32.png
Binary files differ
diff --git a/src/widgets/styles/images/media-pause-128.png b/src/widgets/styles/images/media-pause-128.png
new file mode 100644
index 0000000000..897ad3c80f
--- /dev/null
+++ b/src/widgets/styles/images/media-pause-128.png
Binary files differ
diff --git a/src/widgets/styles/images/media-pause-16.png b/src/widgets/styles/images/media-pause-16.png
index 6cb1fd7f63..862fd49746 100644
--- a/src/widgets/styles/images/media-pause-16.png
+++ b/src/widgets/styles/images/media-pause-16.png
Binary files differ
diff --git a/src/widgets/styles/images/media-pause-32.png b/src/widgets/styles/images/media-pause-32.png
index 3f172a04d6..ce9b706674 100644
--- a/src/widgets/styles/images/media-pause-32.png
+++ b/src/widgets/styles/images/media-pause-32.png
Binary files differ
diff --git a/src/widgets/styles/images/media-pause.svg b/src/widgets/styles/images/media-pause.svg
new file mode 100644
index 0000000000..c13a4ef400
--- /dev/null
+++ b/src/widgets/styles/images/media-pause.svg
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="Layer_1"
+ x="0px"
+ y="0px"
+ viewBox="0 0 16 16"
+ style="enable-background:new 0 0 16 16;"
+ xml:space="preserve"
+ sodipodi:docname="media-pause.svg"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
+ inkscape:export-filename="/home/chehrlic/kde/qt.src/qtbase/src/widgets/styles/images/media-pause-128.png"
+ inkscape:export-xdpi="768"
+ inkscape:export-ydpi="768"><metadata
+ id="metadata15"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
+ id="defs13" /><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="918"
+ id="namedview11"
+ showgrid="true"
+ inkscape:zoom="16.572815"
+ inkscape:cx="13.411945"
+ inkscape:cy="7.5009653"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="Layer_1"
+ inkscape:document-rotation="0"><inkscape:grid
+ type="xygrid"
+ id="grid925" /></sodipodi:namedview>
+<style
+ type="text/css"
+ id="style2">
+ .st0{fill:none;}
+</style>
+
+<g
+ id="g1774"><rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.0575"
+ id="rect1755"
+ width="3"
+ height="10"
+ x="3.5"
+ y="3" /><rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.0575"
+ id="rect1755-3"
+ width="3"
+ height="10"
+ x="9.5"
+ y="3" /></g></svg>
diff --git a/src/widgets/styles/images/media-play-128.png b/src/widgets/styles/images/media-play-128.png
new file mode 100644
index 0000000000..22b260891f
--- /dev/null
+++ b/src/widgets/styles/images/media-play-128.png
Binary files differ
diff --git a/src/widgets/styles/images/media-play-16.png b/src/widgets/styles/images/media-play-16.png
index d7ee3ccbe3..60e86d7fe8 100644
--- a/src/widgets/styles/images/media-play-16.png
+++ b/src/widgets/styles/images/media-play-16.png
Binary files differ
diff --git a/src/widgets/styles/images/media-play-32.png b/src/widgets/styles/images/media-play-32.png
index af8d2f7ba5..d51e130fec 100644
--- a/src/widgets/styles/images/media-play-32.png
+++ b/src/widgets/styles/images/media-play-32.png
Binary files differ
diff --git a/src/widgets/styles/images/media-play.svg b/src/widgets/styles/images/media-play.svg
new file mode 100644
index 0000000000..b0130735f1
--- /dev/null
+++ b/src/widgets/styles/images/media-play.svg
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="Layer_1"
+ x="0px"
+ y="0px"
+ viewBox="0 0 16 16"
+ style="enable-background:new 0 0 16 16;"
+ xml:space="preserve"
+ sodipodi:docname="media-play.svg"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
+ inkscape:export-filename="/home/chehrlic/kde/qt.src/qtbase/src/widgets/styles/images/media-play-128.png"
+ inkscape:export-xdpi="768"
+ inkscape:export-ydpi="768"><metadata
+ id="metadata15"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
+ id="defs13" /><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="918"
+ id="namedview11"
+ showgrid="true"
+ inkscape:zoom="33.14563"
+ inkscape:cx="11.425943"
+ inkscape:cy="9.1913339"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="Layer_1"
+ inkscape:document-rotation="0"><inkscape:grid
+ type="xygrid"
+ id="grid925" /></sodipodi:namedview>
+<style
+ type="text/css"
+ id="style2">
+ .st0{fill:none;}
+</style>
+
+<path
+ id="rect873"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.93347"
+ d="M 3 3 L 3 13 L 12.896484 8 L 3 3 z " /></svg>
diff --git a/src/widgets/styles/images/media-seek-backward-128.png b/src/widgets/styles/images/media-seek-backward-128.png
new file mode 100644
index 0000000000..3d4470bd5c
--- /dev/null
+++ b/src/widgets/styles/images/media-seek-backward-128.png
Binary files differ
diff --git a/src/widgets/styles/images/media-seek-backward-16.png b/src/widgets/styles/images/media-seek-backward-16.png
index b8a8ea42d1..8bfba869e0 100644
--- a/src/widgets/styles/images/media-seek-backward-16.png
+++ b/src/widgets/styles/images/media-seek-backward-16.png
Binary files differ
diff --git a/src/widgets/styles/images/media-seek-backward-32.png b/src/widgets/styles/images/media-seek-backward-32.png
index a21d1372fe..9148f8a0c6 100644
--- a/src/widgets/styles/images/media-seek-backward-32.png
+++ b/src/widgets/styles/images/media-seek-backward-32.png
Binary files differ
diff --git a/src/widgets/styles/images/media-seek-backward.svg b/src/widgets/styles/images/media-seek-backward.svg
new file mode 100644
index 0000000000..13e1e67e6b
--- /dev/null
+++ b/src/widgets/styles/images/media-seek-backward.svg
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="Layer_1"
+ x="0px"
+ y="0px"
+ viewBox="0 0 16 16"
+ style="enable-background:new 0 0 16 16;"
+ xml:space="preserve"
+ sodipodi:docname="media-seek-backward.svg"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
+ inkscape:export-filename="/home/chehrlic/kde/qt.src/qtbase/src/widgets/styles/images/media-seek-backward-128.png"
+ inkscape:export-xdpi="768"
+ inkscape:export-ydpi="768"><metadata
+ id="metadata15"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
+ id="defs13" /><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="918"
+ id="namedview11"
+ showgrid="true"
+ inkscape:zoom="33.14563"
+ inkscape:cx="12.532344"
+ inkscape:cy="7.584329"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="Layer_1"
+ inkscape:document-rotation="0"><inkscape:grid
+ type="xygrid"
+ id="grid925" /></sodipodi:namedview>
+<style
+ type="text/css"
+ id="style2">
+ .st0{fill:none;}
+</style>
+
+<g
+ id="g1560"
+ transform="rotate(180,8,7.9999997)"><path
+ id="rect873"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.45442"
+ d="m 2,4 v 8 L 9,7.9999998 Z" /><path
+ id="rect873-5"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.45442"
+ d="m 7,4 v 8 l 7,-4.0000002 z" /></g></svg>
diff --git a/src/widgets/styles/images/media-seek-forward-128.png b/src/widgets/styles/images/media-seek-forward-128.png
new file mode 100644
index 0000000000..786136b014
--- /dev/null
+++ b/src/widgets/styles/images/media-seek-forward-128.png
Binary files differ
diff --git a/src/widgets/styles/images/media-seek-forward-16.png b/src/widgets/styles/images/media-seek-forward-16.png
index 3c900dcb62..1ddd379adc 100644
--- a/src/widgets/styles/images/media-seek-forward-16.png
+++ b/src/widgets/styles/images/media-seek-forward-16.png
Binary files differ
diff --git a/src/widgets/styles/images/media-seek-forward-32.png b/src/widgets/styles/images/media-seek-forward-32.png
index 4f8d370fa1..aa0e4b36bd 100644
--- a/src/widgets/styles/images/media-seek-forward-32.png
+++ b/src/widgets/styles/images/media-seek-forward-32.png
Binary files differ
diff --git a/src/widgets/styles/images/media-seek-forward.svg b/src/widgets/styles/images/media-seek-forward.svg
new file mode 100644
index 0000000000..f3753b49a6
--- /dev/null
+++ b/src/widgets/styles/images/media-seek-forward.svg
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="Layer_1"
+ x="0px"
+ y="0px"
+ viewBox="0 0 16 16"
+ style="enable-background:new 0 0 16 16;"
+ xml:space="preserve"
+ sodipodi:docname="media-seek-forward.svg"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
+ inkscape:export-filename="/home/chehrlic/kde/qt.src/qtbase/src/widgets/styles/images/media-seek-forward-128.png"
+ inkscape:export-xdpi="768"
+ inkscape:export-ydpi="768"><metadata
+ id="metadata15"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
+ id="defs13" /><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="918"
+ id="namedview11"
+ showgrid="true"
+ inkscape:zoom="33.14563"
+ inkscape:cx="12.532344"
+ inkscape:cy="7.584329"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="Layer_1"
+ inkscape:document-rotation="0"><inkscape:grid
+ type="xygrid"
+ id="grid925" /></sodipodi:namedview>
+<style
+ type="text/css"
+ id="style2">
+ .st0{fill:none;}
+</style>
+
+<g
+ id="g1560"><path
+ id="rect873"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.45442"
+ d="m 2,4 v 8 L 9,7.9999998 Z" /><path
+ id="rect873-5"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.45442"
+ d="m 7,4 v 8 l 7,-4.0000002 z" /></g></svg>
diff --git a/src/widgets/styles/images/media-skip-backward-128.png b/src/widgets/styles/images/media-skip-backward-128.png
new file mode 100644
index 0000000000..f286da7769
--- /dev/null
+++ b/src/widgets/styles/images/media-skip-backward-128.png
Binary files differ
diff --git a/src/widgets/styles/images/media-skip-backward-16.png b/src/widgets/styles/images/media-skip-backward-16.png
index f5b3f4f56d..644dc4cc01 100644
--- a/src/widgets/styles/images/media-skip-backward-16.png
+++ b/src/widgets/styles/images/media-skip-backward-16.png
Binary files differ
diff --git a/src/widgets/styles/images/media-skip-backward-32.png b/src/widgets/styles/images/media-skip-backward-32.png
index 1d338035ef..ca405e3c01 100644
--- a/src/widgets/styles/images/media-skip-backward-32.png
+++ b/src/widgets/styles/images/media-skip-backward-32.png
Binary files differ
diff --git a/src/widgets/styles/images/media-skip-backward.svg b/src/widgets/styles/images/media-skip-backward.svg
new file mode 100644
index 0000000000..083a0a477e
--- /dev/null
+++ b/src/widgets/styles/images/media-skip-backward.svg
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="Layer_1"
+ x="0px"
+ y="0px"
+ viewBox="0 0 16 16"
+ style="enable-background:new 0 0 16 16;"
+ xml:space="preserve"
+ sodipodi:docname="media-skip-backward.svg"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
+ inkscape:export-filename="/home/chehrlic/kde/qt.src/qtbase/src/widgets/styles/images/media-skip-backward-128.png"
+ inkscape:export-xdpi="768"
+ inkscape:export-ydpi="768"><metadata
+ id="metadata15"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
+ id="defs13" /><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="918"
+ id="namedview11"
+ showgrid="true"
+ inkscape:zoom="33.14563"
+ inkscape:cx="5.5133468"
+ inkscape:cy="10.107665"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="Layer_1"
+ inkscape:document-rotation="0"><inkscape:grid
+ type="xygrid"
+ id="grid925" /></sodipodi:namedview>
+<style
+ type="text/css"
+ id="style2">
+ .st0{fill:none;}
+</style>
+
+<g
+ id="g1687"><path
+ id="rect873"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.45442"
+ d="M 14,11.999999 V 3.9999994 L 7,7.9999996 Z" /><path
+ id="rect873-5"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.45442"
+ d="M 9,11.999999 V 3.9999994 L 2,7.9999996 Z" /><rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.13809"
+ id="rect1594"
+ width="1"
+ height="8"
+ x="2"
+ y="4" /></g></svg>
diff --git a/src/widgets/styles/images/media-skip-forward-128.png b/src/widgets/styles/images/media-skip-forward-128.png
new file mode 100644
index 0000000000..d28fbc1708
--- /dev/null
+++ b/src/widgets/styles/images/media-skip-forward-128.png
Binary files differ
diff --git a/src/widgets/styles/images/media-skip-forward-16.png b/src/widgets/styles/images/media-skip-forward-16.png
index 27e205b02f..7e921f9a06 100644
--- a/src/widgets/styles/images/media-skip-forward-16.png
+++ b/src/widgets/styles/images/media-skip-forward-16.png
Binary files differ
diff --git a/src/widgets/styles/images/media-skip-forward-32.png b/src/widgets/styles/images/media-skip-forward-32.png
index a583fa1b11..19b22a5420 100644
--- a/src/widgets/styles/images/media-skip-forward-32.png
+++ b/src/widgets/styles/images/media-skip-forward-32.png
Binary files differ
diff --git a/src/widgets/styles/images/media-skip-forward.svg b/src/widgets/styles/images/media-skip-forward.svg
new file mode 100644
index 0000000000..f2f3c56a8e
--- /dev/null
+++ b/src/widgets/styles/images/media-skip-forward.svg
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="Layer_1"
+ x="0px"
+ y="0px"
+ viewBox="0 0 16 16"
+ style="enable-background:new 0 0 16 16;"
+ xml:space="preserve"
+ sodipodi:docname="media-skip-forward.svg"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
+ inkscape:export-filename="/home/chehrlic/kde/qt.src/qtbase/src/widgets/styles/images/media-skip-forward-128.png"
+ inkscape:export-xdpi="768"
+ inkscape:export-ydpi="768"><metadata
+ id="metadata15"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
+ id="defs13" /><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="918"
+ id="namedview11"
+ showgrid="true"
+ inkscape:zoom="33.14563"
+ inkscape:cx="12.532344"
+ inkscape:cy="7.584329"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="Layer_1"
+ inkscape:document-rotation="0"><inkscape:grid
+ type="xygrid"
+ id="grid925" /></sodipodi:namedview>
+<style
+ type="text/css"
+ id="style2">
+ .st0{fill:none;}
+</style>
+
+<g
+ id="g1659"><path
+ id="rect873"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.45442"
+ d="m 2,4 v 8 L 9,7.9999998 Z" /><path
+ id="rect873-5"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.45442"
+ d="m 7,4 v 8 l 7,-4.0000002 z" /><rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2"
+ id="rect1633"
+ width="1"
+ height="8"
+ x="13"
+ y="4" /></g></svg>
diff --git a/src/widgets/styles/images/media-stop-128.png b/src/widgets/styles/images/media-stop-128.png
new file mode 100644
index 0000000000..680d40697c
--- /dev/null
+++ b/src/widgets/styles/images/media-stop-128.png
Binary files differ
diff --git a/src/widgets/styles/images/media-stop-16.png b/src/widgets/styles/images/media-stop-16.png
index 9ce035d696..e047c2bf6b 100644
--- a/src/widgets/styles/images/media-stop-16.png
+++ b/src/widgets/styles/images/media-stop-16.png
Binary files differ
diff --git a/src/widgets/styles/images/media-stop-32.png b/src/widgets/styles/images/media-stop-32.png
index aae24ba925..6ba9d25d4b 100644
--- a/src/widgets/styles/images/media-stop-32.png
+++ b/src/widgets/styles/images/media-stop-32.png
Binary files differ
diff --git a/src/widgets/styles/images/media-stop.svg b/src/widgets/styles/images/media-stop.svg
new file mode 100644
index 0000000000..755755ab9a
--- /dev/null
+++ b/src/widgets/styles/images/media-stop.svg
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="Layer_1"
+ x="0px"
+ y="0px"
+ viewBox="0 0 16 16"
+ style="enable-background:new 0 0 16 16;"
+ xml:space="preserve"
+ sodipodi:docname="media-stop.svg"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
+ inkscape:export-filename="/home/chehrlic/kde/qt.src/qtbase/src/widgets/styles/images/media-stop-128.png"
+ inkscape:export-xdpi="768"
+ inkscape:export-ydpi="768"><metadata
+ id="metadata15"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
+ id="defs13" /><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="918"
+ id="namedview11"
+ showgrid="true"
+ inkscape:zoom="33.14563"
+ inkscape:cx="5.5133468"
+ inkscape:cy="10.107665"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="Layer_1"
+ inkscape:document-rotation="0"><inkscape:grid
+ type="xygrid"
+ id="grid925" /></sodipodi:namedview>
+<style
+ type="text/css"
+ id="style2">
+ .st0{fill:none;}
+</style>
+
+<rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.06992"
+ id="rect1703"
+ width="12"
+ height="12"
+ x="2"
+ y="2" /></svg>
diff --git a/src/widgets/styles/images/question-128.png b/src/widgets/styles/images/question-128.png
new file mode 100644
index 0000000000..67748522ad
--- /dev/null
+++ b/src/widgets/styles/images/question-128.png
Binary files differ
diff --git a/src/widgets/styles/images/question-16.png b/src/widgets/styles/images/question-16.png
new file mode 100644
index 0000000000..a907b3c485
--- /dev/null
+++ b/src/widgets/styles/images/question-16.png
Binary files differ
diff --git a/src/widgets/styles/images/question-32.png b/src/widgets/styles/images/question-32.png
new file mode 100644
index 0000000000..96c53c7ce0
--- /dev/null
+++ b/src/widgets/styles/images/question-32.png
Binary files differ
diff --git a/src/widgets/styles/images/standardbutton-closetab-128.png b/src/widgets/styles/images/standardbutton-closetab-128.png
new file mode 100644
index 0000000000..aca55c8424
--- /dev/null
+++ b/src/widgets/styles/images/standardbutton-closetab-128.png
Binary files differ
diff --git a/src/widgets/styles/images/standardbutton-closetab-16.png b/src/widgets/styles/images/standardbutton-closetab-16.png
index 540694eae3..26908feb2a 100644
--- a/src/widgets/styles/images/standardbutton-closetab-16.png
+++ b/src/widgets/styles/images/standardbutton-closetab-16.png
Binary files differ
diff --git a/src/widgets/styles/images/standardbutton-closetab-32.png b/src/widgets/styles/images/standardbutton-closetab-32.png
index 93e1246b47..effcc89eed 100644
--- a/src/widgets/styles/images/standardbutton-closetab-32.png
+++ b/src/widgets/styles/images/standardbutton-closetab-32.png
Binary files differ
diff --git a/src/widgets/styles/images/standardbutton-closetab-down-128.png b/src/widgets/styles/images/standardbutton-closetab-down-128.png
new file mode 100644
index 0000000000..2efdfd053f
--- /dev/null
+++ b/src/widgets/styles/images/standardbutton-closetab-down-128.png
Binary files differ
diff --git a/src/widgets/styles/images/standardbutton-closetab-down-16.png b/src/widgets/styles/images/standardbutton-closetab-down-16.png
index ccec241652..5228c1573b 100644
--- a/src/widgets/styles/images/standardbutton-closetab-down-16.png
+++ b/src/widgets/styles/images/standardbutton-closetab-down-16.png
Binary files differ
diff --git a/src/widgets/styles/images/standardbutton-closetab-down-32.png b/src/widgets/styles/images/standardbutton-closetab-down-32.png
index 343b72586e..dfd88920ab 100644
--- a/src/widgets/styles/images/standardbutton-closetab-down-32.png
+++ b/src/widgets/styles/images/standardbutton-closetab-down-32.png
Binary files differ
diff --git a/src/widgets/styles/images/standardbutton-closetab-down.svg b/src/widgets/styles/images/standardbutton-closetab-down.svg
new file mode 100644
index 0000000000..12aa6b21f7
--- /dev/null
+++ b/src/widgets/styles/images/standardbutton-closetab-down.svg
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="Layer_1"
+ x="0px"
+ y="0px"
+ width="32px"
+ height="32px"
+ viewBox="0 0 32 32"
+ style="enable-background:new 0 0 32 32;"
+ xml:space="preserve"
+ sodipodi:docname="standardbutton-closetab-down.svg"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"><metadata
+ id="metadata15"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs13" /><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="918"
+ id="namedview11"
+ showgrid="false"
+ inkscape:zoom="16.572815"
+ inkscape:cx="28.732573"
+ inkscape:cy="14.492458"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="g8" />
+<style
+ type="text/css"
+ id="style2">
+ .st0{fill:#46A2DA;}
+ .st1{fill:none;}
+</style>
+<g
+ id="g8">
+
+
+<rect
+ style="fill:#b17153;stroke:#b17153;stroke-width:1.99804;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
+ id="rect17-3"
+ width="22.001965"
+ height="22.001963"
+ x="4.9990177"
+ y="4.9990177"
+ rx="0"
+ ry="0" /><rect
+ style="fill:none;stroke:#ab493f;stroke-width:1.99992;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect17"
+ width="26.000072"
+ height="26.000076"
+ x="2.9999642"
+ y="2.9999642"
+ rx="1.792347"
+ ry="1.7923476" /><rect
+ style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.76951;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect1031"
+ width="3"
+ height="16"
+ x="21.127417"
+ y="-8"
+ transform="rotate(45)" /><rect
+ style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.76951;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect1031-6"
+ width="3"
+ height="16"
+ x="-1.5"
+ y="14.627417"
+ transform="rotate(-45)" /></g>
+</svg>
diff --git a/src/widgets/styles/images/standardbutton-closetab-hover-128.png b/src/widgets/styles/images/standardbutton-closetab-hover-128.png
new file mode 100644
index 0000000000..4f6b1bfde4
--- /dev/null
+++ b/src/widgets/styles/images/standardbutton-closetab-hover-128.png
Binary files differ
diff --git a/src/widgets/styles/images/standardbutton-closetab-hover-16.png b/src/widgets/styles/images/standardbutton-closetab-hover-16.png
index b22a0ffaf0..460411deeb 100644
--- a/src/widgets/styles/images/standardbutton-closetab-hover-16.png
+++ b/src/widgets/styles/images/standardbutton-closetab-hover-16.png
Binary files differ
diff --git a/src/widgets/styles/images/standardbutton-closetab-hover-32.png b/src/widgets/styles/images/standardbutton-closetab-hover-32.png
index 41ce0265c7..aa6afd72b2 100644
--- a/src/widgets/styles/images/standardbutton-closetab-hover-32.png
+++ b/src/widgets/styles/images/standardbutton-closetab-hover-32.png
Binary files differ
diff --git a/src/widgets/styles/images/standardbutton-closetab-hover.svg b/src/widgets/styles/images/standardbutton-closetab-hover.svg
new file mode 100644
index 0000000000..45dc8b8c46
--- /dev/null
+++ b/src/widgets/styles/images/standardbutton-closetab-hover.svg
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="Layer_1"
+ x="0px"
+ y="0px"
+ width="32px"
+ height="32px"
+ viewBox="0 0 32 32"
+ style="enable-background:new 0 0 32 32;"
+ xml:space="preserve"
+ sodipodi:docname="standardbutton-closetab-hover.svg"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"><metadata
+ id="metadata15"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs13" /><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="918"
+ id="namedview11"
+ showgrid="false"
+ inkscape:zoom="16.572815"
+ inkscape:cx="33.318396"
+ inkscape:cy="14.492458"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="g8"
+ inkscape:document-rotation="0" />
+<style
+ type="text/css"
+ id="style2">
+ .st0{fill:#46A2DA;}
+ .st1{fill:none;}
+</style>
+<g
+ id="g8">
+
+
+<rect
+ style="fill:#ea8f60;stroke:#f2b7a7;stroke-width:1.99804;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
+ id="rect17-3"
+ width="22.001965"
+ height="22.001963"
+ x="4.9990177"
+ y="4.9990177"
+ rx="0"
+ ry="0" /><rect
+ style="fill:none;stroke:#d73727;stroke-width:1.99992;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect17"
+ width="26.000072"
+ height="26.000076"
+ x="2.9999642"
+ y="2.9999642"
+ rx="1.792347"
+ ry="1.7923476" /><rect
+ style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.76951;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect1031"
+ width="3"
+ height="16"
+ x="21.127417"
+ y="-8"
+ transform="rotate(45)" /><rect
+ style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.76951;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect1031-6"
+ width="3"
+ height="16"
+ x="-1.5"
+ y="14.627417"
+ transform="rotate(-45)" /></g>
+</svg>
diff --git a/src/widgets/styles/images/standardbutton-closetab.svg b/src/widgets/styles/images/standardbutton-closetab.svg
new file mode 100644
index 0000000000..d3a9279538
--- /dev/null
+++ b/src/widgets/styles/images/standardbutton-closetab.svg
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="Layer_1"
+ x="0px"
+ y="0px"
+ width="32px"
+ height="32px"
+ viewBox="0 0 32 32"
+ style="enable-background:new 0 0 32 32;"
+ xml:space="preserve"
+ sodipodi:docname="standardbutton-closetab.svg"
+ inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"><metadata
+ id="metadata15"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
+ id="defs13" /><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="918"
+ id="namedview11"
+ showgrid="false"
+ inkscape:zoom="16.572815"
+ inkscape:cx="33.318396"
+ inkscape:cy="14.492458"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="g8"
+ inkscape:document-rotation="0" />
+<style
+ type="text/css"
+ id="style2">
+ .st0{fill:#46A2DA;}
+ .st1{fill:none;}
+</style>
+<g
+ id="g8">
+
+
+<rect
+ style="fill:#ea8f60;stroke:#ef9d8e;stroke-width:1.99804;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
+ id="rect17-3"
+ width="22.001965"
+ height="22.001963"
+ x="4.9990177"
+ y="4.9990177"
+ rx="0"
+ ry="0" /><rect
+ style="fill:none;stroke:#d73727;stroke-width:1.99992;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect17"
+ width="26.000072"
+ height="26.000076"
+ x="2.9999642"
+ y="2.9999642"
+ rx="1.792347"
+ ry="1.7923476" /><rect
+ style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.76951;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect1031"
+ width="3"
+ height="16"
+ x="21.127417"
+ y="-8"
+ transform="rotate(45)" /><rect
+ style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.76951;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect1031-6"
+ width="3"
+ height="16"
+ x="-1.5"
+ y="14.627417"
+ transform="rotate(-45)" /></g>
+</svg>
diff --git a/src/widgets/styles/images/toolbar-ext-h-128.png b/src/widgets/styles/images/toolbar-ext-h-128.png
new file mode 100644
index 0000000000..071c5b1353
--- /dev/null
+++ b/src/widgets/styles/images/toolbar-ext-h-128.png
Binary files differ
diff --git a/src/widgets/styles/images/toolbar-ext-h-rtl-128.png b/src/widgets/styles/images/toolbar-ext-h-rtl-128.png
new file mode 100644
index 0000000000..7aadfc2aea
--- /dev/null
+++ b/src/widgets/styles/images/toolbar-ext-h-rtl-128.png
Binary files differ
diff --git a/src/widgets/styles/images/toolbar-ext-v-80.png b/src/widgets/styles/images/toolbar-ext-v-80.png
new file mode 100644
index 0000000000..84d15ff064
--- /dev/null
+++ b/src/widgets/styles/images/toolbar-ext-v-80.png
Binary files differ
diff --git a/src/widgets/styles/images/warning-128.png b/src/widgets/styles/images/warning-128.png
new file mode 100644
index 0000000000..07f0251b8a
--- /dev/null
+++ b/src/widgets/styles/images/warning-128.png
Binary files differ
diff --git a/src/widgets/styles/images/warning-16.png b/src/widgets/styles/images/warning-16.png
new file mode 100644
index 0000000000..dce3ac9126
--- /dev/null
+++ b/src/widgets/styles/images/warning-16.png
Binary files differ
diff --git a/src/widgets/styles/images/warning-32.png b/src/widgets/styles/images/warning-32.png
new file mode 100644
index 0000000000..a7b822737d
--- /dev/null
+++ b/src/widgets/styles/images/warning-32.png
Binary files differ
diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp
index fb6b415f59..aab1192d50 100644
--- a/src/widgets/styles/qcommonstyle.cpp
+++ b/src/widgets/styles/qcommonstyle.cpp
@@ -96,6 +96,31 @@ static qreal qt_getDevicePixelRatio(const QWidget *widget)
return widget ? widget->devicePixelRatio() : qApp->devicePixelRatio();
}
+struct QPainterStateSaver
+{
+ QPainterStateSaver(QPainter *p, bool bSaveRestore = true)
+ : m_painter(p)
+ , m_bSaveRestore(bSaveRestore)
+ {
+ if (m_bSaveRestore)
+ m_painter->save();
+ }
+ ~QPainterStateSaver()
+ {
+ restore();
+ }
+ void restore()
+ {
+ if (m_bSaveRestore) {
+ m_bSaveRestore = false;
+ m_painter->restore();
+ }
+ }
+private:
+ QPainter *m_painter;
+ bool m_bSaveRestore;
+};
+
/*!
\class QCommonStyle
\brief The QCommonStyle class encapsulates the common Look and Feel of a GUI.
@@ -189,20 +214,19 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q
case PE_FrameFocusRect:
if (const QStyleOptionFocusRect *fropt = qstyleoption_cast<const QStyleOptionFocusRect *>(opt)) {
QColor bg = fropt->backgroundColor;
- QPen oldPen = p->pen();
+ QColor color;
if (bg.isValid()) {
int h, s, v;
bg.getHsv(&h, &s, &v);
if (v >= 128)
- p->setPen(Qt::black);
+ color = Qt::black;
else
- p->setPen(Qt::white);
+ color = Qt::white;
} else {
- p->setPen(opt->palette.windowText().color());
+ color = opt->palette.windowText().color();
}
- QRect focusRect = opt->rect.adjusted(1, 1, -1, -1);
- p->drawRect(focusRect.adjusted(0, 0, -1, -1)); //draw pen inclusive
- p->setPen(oldPen);
+ const QRect focusRect = opt->rect.adjusted(1, 1, -1, -1);
+ qDrawPlainRect(p, focusRect, color, 1);
}
break;
case PE_IndicatorMenuCheckMark: {
@@ -229,11 +253,10 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q
--yy;
}
if (!(opt->state & State_Enabled) && !(opt->state & State_On)) {
- p->save();
+ QPainterStateSaver pss(p);
p->translate(1, 1);
p->setPen(opt->palette.light().color());
p->drawLines(a);
- p->restore();
}
p->setPen((opt->state & State_On) ? opt->palette.highlightedText().color() : opt->palette.text().color());
p->drawLines(a);
@@ -355,7 +378,7 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q
case PE_FrameTabBarBase:
if (const QStyleOptionTabBarBase *tbb
= qstyleoption_cast<const QStyleOptionTabBarBase *>(opt)) {
- p->save();
+ QPainterStateSaver pss(p);
switch (tbb->shape) {
case QTabBar::RoundedNorth:
case QTabBar::TriangularNorth:
@@ -382,14 +405,13 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q
p->drawLine(tbb->rect.topRight(), tbb->rect.bottomRight());
break;
}
- p->restore();
}
break;
case PE_IndicatorTabClose: {
if (d->tabBarcloseButtonIcon.isNull())
d->tabBarcloseButtonIcon = proxy()->standardIcon(QStyle::SP_TabCloseButton, opt, widget);
- const int size = proxy()->pixelMetric(QStyle::PM_SmallIconSize, opt);
+ const int size = proxy()->pixelMetric(QStyle::PM_SmallIconSize, opt, widget);
QIcon::Mode mode = opt->state & State_Enabled ?
(opt->state & State_Raised ? QIcon::Active : QIcon::Normal)
: QIcon::Disabled;
@@ -435,15 +457,15 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q
if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
int lw = frame->lineWidth;
if (lw <= 0)
- lw = proxy()->pixelMetric(PM_DockWidgetFrameWidth, opt);
+ lw = proxy()->pixelMetric(PM_DockWidgetFrameWidth, opt, widget);
qDrawShadePanel(p, frame->rect, frame->palette, false, lw);
}
break;
#endif // QT_CONFIG(dockwidget)
#if QT_CONFIG(toolbar)
- case PE_IndicatorToolBarHandle:
- p->save();
+ case PE_IndicatorToolBarHandle: {
+ QPainterStateSaver pss(p);
p->translate(opt->rect.x(), opt->rect.y());
if (opt->state & State_Horizontal) {
int x = opt->rect.width() / 3;
@@ -464,8 +486,8 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q
opt->palette, false, 1, nullptr);
}
}
- p->restore();
break;
+ }
case PE_IndicatorToolBarSeparator:
{
QPoint p1, p2;
@@ -486,24 +508,58 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q
QRect r = opt->rect;
int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt, widget);
QRect br = r.adjusted(fw, fw, -fw, -fw);
-
- int offset = (opt->state & State_Sunken) ? 1 : 0;
- int step = (br.width() + 4) / 5;
- p->fillRect(br.x() + offset, br.y() + offset +br.height() / 2 - step / 2,
- br.width(), step,
- opt->palette.buttonText());
+ int x = br.x();
+ int y = br.y();
+ int w = br.width();
+ int h = br.height();
+ QPainterStateSaver pss(p);
+ const qreal devicePixelRatio = p->device()->devicePixelRatio();
+ if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
+ const qreal inverseScale = qreal(1) / devicePixelRatio;
+ p->scale(inverseScale, inverseScale);
+ x = qRound(devicePixelRatio * x);
+ y = qRound(devicePixelRatio * y);
+ w = qRound(devicePixelRatio * w);
+ h = qRound(devicePixelRatio * h);
+ p->translate(0.5, 0.5);
+ }
+ int len = std::min(w, h);
+ if (len & 1)
+ ++len;
+ int step = (len + 4) / 5;
+ if (step & 1)
+ ++step;
+ const int step2 = step / 2;
+ QPoint center(x + w / 2, y + h / 2);
+ if (opt->state & State_Sunken) {
+ center += QPoint(proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget),
+ proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget));
+ }
+ p->translate(center);
+ p->fillRect(-len / 2, -step2, len, step, opt->palette.buttonText());
if (pe == PE_IndicatorSpinPlus)
- p->fillRect(br.x() + br.width() / 2 - step / 2 + offset, br.y() + offset,
- step, br.height(),
- opt->palette.buttonText());
-
+ p->fillRect(-step2, -len / 2, step, len, opt->palette.buttonText());
break; }
case PE_IndicatorSpinUp:
case PE_IndicatorSpinDown: {
QRect r = opt->rect;
int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt, widget);
// QRect br = r.adjusted(fw, fw, -fw, -fw);
- int x = r.x(), y = r.y(), w = r.width(), h = r.height();
+ int x = r.x();
+ int y = r.y();
+ int w = r.width();
+ int h = r.height();
+ QPainterStateSaver pss(p);
+ const qreal devicePixelRatio = p->device()->devicePixelRatio();
+ if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
+ const qreal inverseScale = qreal(1) / devicePixelRatio;
+ p->scale(inverseScale, inverseScale);
+ x = qRound(devicePixelRatio * x);
+ y = qRound(devicePixelRatio * y);
+ w = qRound(devicePixelRatio * w);
+ h = qRound(devicePixelRatio * h);
+ p->translate(0.5, 0.5);
+ }
int sw = w-4;
if (sw < 3)
break;
@@ -521,10 +577,9 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q
int bsx = 0;
int bsy = 0;
if (opt->state & State_Sunken) {
- bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt);
- bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt);
+ bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget);
+ bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget);
}
- p->save();
p->translate(sx + bsx, sy + bsy);
p->setPen(opt->palette.buttonText().color());
p->setBrush(opt->palette.buttonText());
@@ -535,7 +590,6 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q
const QPoint points[] = { QPoint(0, sh-1), QPoint(sw-1, sh-1), QPoint(sh-2, 1) };
p->drawPolygon(points, sizeof points / sizeof *points);
}
- p->restore();
break; }
#endif // QT_CONFIG(spinbox)
case PE_PanelTipLabel: {
@@ -593,7 +647,7 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q
case PE_IndicatorColumnViewArrow: {
if (const QStyleOptionViewItem *viewOpt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
bool reverse = (viewOpt->direction == Qt::RightToLeft);
- p->save();
+ QPainterStateSaver pss(p);
QPainterPath path;
int x = viewOpt->rect.x() + 1;
int offset = (viewOpt->rect.height() / 3);
@@ -638,7 +692,6 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q
p->setPen(color);
p->drawPath(lines);
}
- p->restore();
}
break; }
#endif //QT_CONFIG(columnview)
@@ -697,71 +750,75 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q
case PE_IndicatorArrowRight:
case PE_IndicatorArrowLeft:
{
- if (opt->rect.width() <= 1 || opt->rect.height() <= 1)
+ const QRect &r = opt->rect;
+ if (r.width() <= 1 || r.height() <= 1)
break;
- QRect r = opt->rect;
int size = qMin(r.height(), r.width());
QPixmap pixmap;
- QString pixmapName =
- QStyleHelper::uniqueName("$qt_ia-"_L1
- % QLatin1StringView(metaObject()->className()),
- opt, QSize(size, size))
- % HexString<uint>(pe);
+ const qreal dpr = p->device()->devicePixelRatio();
+ const QString pixmapName = QStyleHelper::uniqueName("$qt_ia-"_L1
+ % QLatin1StringView(metaObject()->className())
+ % HexString<uint>(pe),
+ opt, QSize(size, size), dpr);
if (!QPixmapCache::find(pixmapName, &pixmap)) {
- qreal pixelRatio = p->device()->devicePixelRatio();
- int border = qRound(pixelRatio*(size/5));
- int sqsize = qRound(pixelRatio*(2*(size/2)));
- QImage image(sqsize, sqsize, QImage::Format_ARGB32_Premultiplied);
- image.fill(0);
- QPainter imagePainter(&image);
-
- QPolygon a;
+ // dpr scaling does not work well on such small pixel sizes, do it on our own
+ const int border = 1 * dpr;
+ const int sizeDpr = size * dpr;
+ int width = sizeDpr - 2 * border - 1;
+ int height = width / 2;
+ const int add = ((width & 1) == 1);
+ if (pe == PE_IndicatorArrowRight || pe == PE_IndicatorArrowLeft)
+ std::swap(width, height);
+ pixmap = styleCachePixmap(QSize(sizeDpr, sizeDpr), 1);
+
+ std::array<QPointF, 4> poly;
switch (pe) {
case PE_IndicatorArrowUp:
- a.setPoints(3, border, sqsize/2, sqsize/2, border, sqsize - border, sqsize/2);
+ poly = {QPointF(0, height), QPointF(width, height),
+ QPointF(width / 2 + add, 0), QPointF(width / 2, 0)};
break;
case PE_IndicatorArrowDown:
- a.setPoints(3, border, sqsize/2, sqsize/2, sqsize - border, sqsize - border, sqsize/2);
+ poly = {QPointF(0, 0), QPointF(width, 0),
+ QPointF(width / 2 + add, height), QPointF(width / 2, height)};
break;
case PE_IndicatorArrowRight:
- a.setPoints(3, sqsize - border, sqsize/2, sqsize/2, border, sqsize/2, sqsize - border);
+ poly = {QPointF(0, 0), QPointF(0, height),
+ QPointF(width, height / 2 + add), QPointF(width, height / 2)};
break;
case PE_IndicatorArrowLeft:
- a.setPoints(3, border, sqsize/2, sqsize/2, border, sqsize/2, sqsize - border);
+ poly = {QPointF(width, 0), QPointF(width, height),
+ QPointF(0, height / 2 + add), QPointF(0, height / 2)};
break;
default:
break;
}
- int bsx = 0;
- int bsy = 0;
-
+ QPainter imagePainter(&pixmap);
+ imagePainter.translate((sizeDpr - width) / 2, (sizeDpr - height) / 2);
if (opt->state & State_Sunken) {
- bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget);
- bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget);
+ const auto bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget);
+ const auto bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget);
+ imagePainter.translate(bsx, bsy);
}
-
- QRect bounds = a.boundingRect();
- int sx = sqsize / 2 - bounds.center().x() - 1;
- int sy = sqsize / 2 - bounds.center().y() - 1;
- imagePainter.translate(sx + bsx, sy + bsy);
imagePainter.setPen(opt->palette.buttonText().color());
imagePainter.setBrush(opt->palette.buttonText());
if (!(opt->state & State_Enabled)) {
- imagePainter.translate(1, 1);
+ const int ofs = qRound(1 * dpr);
+ imagePainter.translate(ofs, ofs);
imagePainter.setBrush(opt->palette.light().color());
imagePainter.setPen(opt->palette.light().color());
- imagePainter.drawPolygon(a);
- imagePainter.translate(-1, -1);
+ imagePainter.drawPolygon(poly.data(), int(poly.size()));
+ imagePainter.drawPoints(poly.data(), int(poly.size()));
+ imagePainter.translate(-ofs, -ofs);
imagePainter.setBrush(opt->palette.mid().color());
imagePainter.setPen(opt->palette.mid().color());
}
-
- imagePainter.drawPolygon(a);
+ imagePainter.drawPolygon(poly.data(), int(poly.size()));
+ // sometimes the corners are not drawn by drawPolygon for unknown reaons, so re-draw them again
+ imagePainter.drawPoints(poly.data(), int(poly.size()));
imagePainter.end();
- pixmap = QPixmap::fromImage(image);
- pixmap.setDevicePixelRatio(pixelRatio);
+ pixmap.setDevicePixelRatio(dpr);
QPixmapCache::insert(pixmapName, pixmap);
}
int xOffset = r.x() + (r.width() - size)/2;
@@ -961,7 +1018,7 @@ QSize QCommonStylePrivate::viewItemSize(const QStyleOptionViewItem *option, int
}
if (wrapText && option->features & QStyleOptionViewItem::HasCheckIndicator)
- bounds.setWidth(bounds.width() - proxyStyle->pixelMetric(QStyle::PM_IndicatorWidth, option) - 2 * textMargin);
+ bounds.setWidth(bounds.width() - proxyStyle->pixelMetric(QStyle::PM_IndicatorWidth, option, widget) - 2 * textMargin);
const int lineWidth = bounds.width();
const QSizeF size = viewItemTextLayout(textLayout, lineWidth);
@@ -1127,12 +1184,8 @@ void QCommonStylePrivate::viewItemLayout(const QStyleOptionViewItem *opt, QRect
checkRect->size(), check);
*pixmapRect = QStyle::alignedRect(opt->direction, opt->decorationAlignment,
pixmapRect->size(), decoration);
- // the text takes up all available space, unless the decoration is not shown as selected
- if (opt->showDecorationSelected)
- *textRect = display;
- else
- *textRect = QStyle::alignedRect(opt->direction, opt->displayAlignment,
- textRect->size().boundedTo(display.size()), display);
+ // the textRect takes up all remaining size
+ *textRect = display;
} else {
*checkRect = check;
*pixmapRect = decoration;
@@ -1207,7 +1260,7 @@ void QCommonStylePrivate::tabLayout(const QStyleOptionTab *opt, const QWidget *w
if (!opt->icon.isNull()) {
QSize iconSize = opt->iconSize;
if (!iconSize.isValid()) {
- int iconExtent = proxyStyle->pixelMetric(QStyle::PM_SmallIconSize, opt);
+ int iconExtent = proxyStyle->pixelMetric(QStyle::PM_SmallIconSize, opt, widget);
iconSize = QSize(iconExtent, iconExtent);
}
QSize tabIconSize = opt->icon.actualSize(iconSize,
@@ -1233,12 +1286,6 @@ void QCommonStylePrivate::tabLayout(const QStyleOptionTab *opt, const QWidget *w
#if QT_CONFIG(animation)
/*! \internal */
-QList<const QObject*> QCommonStylePrivate::animationTargets() const
-{
- return animations.keys();
-}
-
-/*! \internal */
QStyleAnimation * QCommonStylePrivate::animation(const QObject *target) const
{
return animations.value(target);
@@ -1248,9 +1295,11 @@ QStyleAnimation * QCommonStylePrivate::animation(const QObject *target) const
void QCommonStylePrivate::startAnimation(QStyleAnimation *animation) const
{
Q_Q(const QCommonStyle);
- stopAnimation(animation->target());
- q->connect(animation, SIGNAL(destroyed()), SLOT(_q_removeAnimation()), Qt::UniqueConnection);
- animations.insert(animation->target(), animation);
+ const auto target = animation->target();
+ stopAnimation(target);
+ QObject::connect(animation, &QStyleAnimation::destroyed,
+ q, [this, target]() { removeAnimation(target); });
+ animations.insert(target, animation);
animation->start();
}
@@ -1265,12 +1314,9 @@ void QCommonStylePrivate::stopAnimation(const QObject *target) const
}
/*! \internal */
-void QCommonStylePrivate::_q_removeAnimation()
+void QCommonStylePrivate::removeAnimation(const QObject *target) const
{
- Q_Q(QCommonStyle);
- QObject *animation = q->sender();
- if (animation)
- animations.remove(animation->parent());
+ animations.remove(target);
}
#endif
@@ -1363,13 +1409,16 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
iconRect = visualRect(button->direction, textRect, iconRect);
- if (button->direction == Qt::RightToLeft) {
- tf |= Qt::AlignRight;
+ if (button->direction == Qt::RightToLeft)
textRect.setRight(iconRect.left() - iconSpacing / 2);
- } else {
- tf |= Qt::AlignLeft; //left align, we adjust the text-rect instead
+ else
textRect.setLeft(iconRect.left() + iconRect.width() + iconSpacing / 2);
- }
+
+ // qt_format_text reverses again when painter->layoutDirection is also RightToLeft
+ if (p->layoutDirection() == button->direction)
+ tf |= Qt::AlignLeft;
+ else
+ tf |= Qt::AlignRight;
if (button->state & (State_On | State_Sunken))
iconRect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget),
@@ -1458,7 +1507,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
| Qt::TextSingleLine;
if (!proxy()->styleHint(SH_UnderlineShortcut, mbi, widget))
alignment |= Qt::TextHideMnemonic;
- int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, opt);
+ int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, opt, widget);
QPixmap pix = mbi->icon.pixmap(QSize(iconExtent, iconExtent), p->device()->devicePixelRatio(), (mbi->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled);
if (!pix.isNull())
proxy()->drawItemPixmap(p,mbi->rect, alignment, pix);
@@ -1614,7 +1663,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
QRect rect = header->rect;
if (!header->icon.isNull()) {
- int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, opt);
+ int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, opt, widget);
QPixmap pixmap
= header->icon.pixmap(QSize(iconExtent, iconExtent), p->device()->devicePixelRatio(), (header->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled);
int pixw = pixmap.width() / pixmap.devicePixelRatio();
@@ -1635,9 +1684,12 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
QFontMetrics fm(header->fontMetrics);
if (header->state & QStyle::State_On) {
QFont fnt = p->font();
- fnt.setBold(true);
- p->setFont(fnt);
- fm = QFontMetrics((p->font()));
+ // the font already has a weight set; don't override that
+ if (!(fnt.resolveMask() & QFont::WeightResolved)) {
+ fnt.setBold(true);
+ p->setFont(fnt);
+ fm = QFontMetrics((p->font()));
+ }
}
QString text = header->text;
if (const QStyleOptionHeaderV2 *headerV2 = qstyleoption_cast<const QStyleOptionHeaderV2 *>(header)) {
@@ -1794,8 +1846,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
break;
case CE_TabBarTabShape:
if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
- p->save();
-
+ QPainterStateSaver pss(p);
QRect rect(tab->rect);
bool selected = tab->state & State_Selected;
bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab;
@@ -1896,7 +1947,6 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
default:
break;
}
- p->restore();
}
break;
case CE_ToolBoxTabLabel:
@@ -1957,8 +2007,8 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
if (!proxy()->styleHint(SH_UnderlineShortcut, opt, widget))
alignment |= Qt::TextHideMnemonic;
+ QPainterStateSaver pss(p, verticalTabs);
if (verticalTabs) {
- p->save();
int newX, newY, newRot;
if (tab->shape == QTabBar::RoundedEast || tab->shape == QTabBar::TriangularEast) {
newX = tr.width() + tr.x();
@@ -1975,7 +2025,10 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
}
QRect iconRect;
d->tabLayout(tab, widget, &tr, &iconRect);
- tr = proxy()->subElementRect(SE_TabBarTabText, opt, widget); //we compute tr twice because the style may override subElementRect
+
+ // compute tr again, unless tab is moving, because the style may override subElementRect
+ if (tab->position != QStyleOptionTab::TabPosition::Moving)
+ tr = proxy()->subElementRect(SE_TabBarTabText, opt, widget);
if (!tab->icon.isNull()) {
QPixmap tabIcon = tab->icon.pixmap(tab->iconSize, p->device()->devicePixelRatio(),
@@ -1988,11 +2041,10 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
proxy()->drawItemText(p, tr, alignment, tab->palette, tab->state & State_Enabled, tab->text,
widget ? widget->foregroundRole() : QPalette::WindowText);
- if (verticalTabs)
- p->restore();
+ pss.restore();
if (tab->state & State_HasFocus) {
- const int OFFSET = 1 + pixelMetric(PM_DefaultFrameWidth);
+ const int OFFSET = 1 + pixelMetric(PM_DefaultFrameWidth, opt, widget);
int x1, x2;
x1 = tab->rect.left();
@@ -2009,7 +2061,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
#endif // QT_CONFIG(tabbar)
#if QT_CONFIG(sizegrip)
case CE_SizeGrip: {
- p->save();
+ QPainterStateSaver pss(p);
int x, y, w, h;
opt->rect.getRect(&x, &y, &w, &h);
@@ -2078,7 +2130,6 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
sy += s;
}
}
- p->restore();
break; }
#endif // QT_CONFIG(sizegrip)
#if QT_CONFIG(rubberband)
@@ -2095,7 +2146,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
// ### workaround for borked XRENDER
tiledPixmap = QPixmap::fromImage(tiledPixmap.toImage());
- p->save();
+ QPainterStateSaver pss(p);
QRect r = opt->rect;
QStyleHintReturnMask mask;
if (proxy()->styleHint(QStyle::SH_RubberBand_Mask, opt, widget, &mask))
@@ -2106,7 +2157,6 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
p->drawRect(r.adjusted(0, 0, -1, -1));
if (rbOpt->shape == QRubberBand::Rectangle)
p->drawRect(r.adjusted(3, 3, -4, -4));
- p->restore();
}
break; }
#endif // QT_CONFIG(rubberband)
@@ -2122,10 +2172,10 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
if (!dwOpt->title.isEmpty()) {
const bool verticalTitleBar = dwOpt->verticalTitleBar;
+ QPainterStateSaver pss(p, verticalTitleBar);
if (verticalTitleBar) {
r = r.transposed();
- p->save();
p->translate(r.left(), r.top() + r.width());
p->rotate(-90);
p->translate(-r.left(), -r.top());
@@ -2133,12 +2183,9 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
const int indent = p->fontMetrics().descent();
proxy()->drawItemText(p, r.adjusted(indent + 1, 1, -indent - 1, -1),
- Qt::AlignLeft | Qt::AlignVCenter, dwOpt->palette,
+ Qt::AlignLeft | Qt::AlignVCenter | Qt::TextHideMnemonic, dwOpt->palette,
dwOpt->state & State_Enabled, dwOpt->title,
QPalette::WindowText);
-
- if (verticalTitleBar)
- p->restore();
}
}
break;
@@ -2148,7 +2195,13 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
QRegion clipRegion = p->clipRegion();
p->setClipRect(opt->rect);
proxy()->drawControl(CE_HeaderSection, header, p, widget);
- QStyleOptionHeader subopt = *header;
+ // opt can be a QStyleOptionHeaderV2 and we must pass it to the subcontrol drawings
+ QStyleOptionHeaderV2 subopt;
+ QStyleOptionHeader &v1Copy = subopt;
+ if (auto v2 = qstyleoption_cast<const QStyleOptionHeaderV2 *>(opt))
+ subopt = *v2;
+ else
+ v1Copy = *header;
subopt.rect = subElementRect(SE_HeaderLabel, header, widget);
if (subopt.rect.isValid())
proxy()->drawControl(CE_HeaderLabel, &subopt, p, widget);
@@ -2174,7 +2227,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
case CE_ComboBoxLabel:
if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
QRect editRect = proxy()->subControlRect(CC_ComboBox, cb, SC_ComboBoxEditField, widget);
- p->save();
+ QPainterStateSaver pss(p);
p->setClipRect(editRect);
if (!cb->currentIcon.isNull()) {
QIcon::Mode mode = cb->state & State_Enabled ? QIcon::Normal
@@ -2199,7 +2252,6 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
visualAlignment(cb->direction, cb->textAlignment),
cb->palette, cb->state & State_Enabled, cb->currentText);
}
- p->restore();
}
break;
#endif // QT_CONFIG(combobox)
@@ -2245,7 +2297,7 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
#if QT_CONFIG(itemviews)
case CE_ItemViewItem:
if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
- p->save();
+ QPainterStateSaver pss(p);
// the style calling this might want to clip, so respect any region already set
const QRegion clipRegion = p->hasClipping() ? (p->clipRegion() & opt->rect) : opt->rect;
p->setClipRegion(clipRegion);
@@ -2319,8 +2371,6 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
? QPalette::Highlight : QPalette::Window);
proxy()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, p, widget);
}
-
- p->restore();
}
break;
@@ -3242,7 +3292,7 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl
int fudge = len / 2;
int pos;
// Since there is no subrect for tickmarks do a translation here.
- p->save();
+ QPainterStateSaver pss(p);
p->translate(slider->rect.x(), slider->rect.y());
p->setPen(slider->palette.windowText().color());
int v = slider->minimum;
@@ -3271,7 +3321,6 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl
break;
v = nextInterval;
}
- p->restore();
}
}
break;
@@ -3537,12 +3586,11 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl
tool.state = down ? State_Sunken : State_Raised;
proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p, widget);
- p->save();
+ QPainterStateSaver pss(p, down);
if (down)
p->translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb, widget),
proxy()->pixelMetric(PM_ButtonShiftVertical, tb, widget));
proxy()->drawItemPixmap(p, ir, Qt::AlignCenter, pm);
- p->restore();
}
if (tb->subControls & SC_TitleBarMaxButton
@@ -3556,12 +3604,11 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl
tool.state = down ? State_Sunken : State_Raised;
proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p, widget);
- p->save();
+ QPainterStateSaver pss(p, down);
if (down)
p->translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb, widget),
proxy()->pixelMetric(PM_ButtonShiftVertical, tb, widget));
proxy()->drawItemPixmap(p, ir, Qt::AlignCenter, pm);
- p->restore();
}
if (tb->subControls & SC_TitleBarMinButton
@@ -3574,12 +3621,11 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl
tool.state = down ? State_Sunken : State_Raised;
proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p, widget);
- p->save();
+ QPainterStateSaver pss(p, down);
if (down)
p->translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb, widget),
proxy()->pixelMetric(PM_ButtonShiftVertical, tb, widget));
proxy()->drawItemPixmap(p, ir, Qt::AlignCenter, pm);
- p->restore();
}
bool drawNormalButton = (tb->subControls & SC_TitleBarNormalButton)
@@ -3596,12 +3642,11 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl
tool.state = down ? State_Sunken : State_Raised;
proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p, widget);
- p->save();
+ QPainterStateSaver pss(p, down);
if (down)
p->translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb, widget),
proxy()->pixelMetric(PM_ButtonShiftVertical, tb, widget));
proxy()->drawItemPixmap(p, ir, Qt::AlignCenter, pm);
- p->restore();
}
if (tb->subControls & SC_TitleBarShadeButton
@@ -3613,12 +3658,11 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl
tool.rect = ir;
tool.state = down ? State_Sunken : State_Raised;
proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p, widget);
- p->save();
+ QPainterStateSaver pss(p, down);
if (down)
p->translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb, widget),
proxy()->pixelMetric(PM_ButtonShiftVertical, tb, widget));
proxy()->drawItemPixmap(p, ir, Qt::AlignCenter, pm);
- p->restore();
}
if (tb->subControls & SC_TitleBarUnshadeButton
@@ -3631,12 +3675,11 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl
tool.rect = ir;
tool.state = down ? State_Sunken : State_Raised;
proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p, widget);
- p->save();
+ QPainterStateSaver pss(p, down);
if (down)
p->translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb, widget),
proxy()->pixelMetric(PM_ButtonShiftVertical, tb, widget));
proxy()->drawItemPixmap(p, ir, Qt::AlignCenter, pm);
- p->restore();
}
if (tb->subControls & SC_TitleBarContextHelpButton
&& tb->titleBarFlags & Qt::WindowContextHelpButtonHint) {
@@ -3647,12 +3690,11 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl
tool.rect = ir;
tool.state = down ? State_Sunken : State_Raised;
proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p, widget);
- p->save();
+ QPainterStateSaver pss(p, down);
if (down)
p->translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb, widget),
proxy()->pixelMetric(PM_ButtonShiftVertical, tb, widget));
proxy()->drawItemPixmap(p, ir, Qt::AlignCenter, pm);
- p->restore();
}
if (tb->subControls & SC_TitleBarSysMenu && tb->titleBarFlags & Qt::WindowSystemMenuHint) {
ir = proxy()->subControlRect(CC_TitleBar, tb, SC_TitleBarSysMenu, widget);
@@ -3662,9 +3704,8 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl
int iconSize = proxy()->pixelMetric(PM_SmallIconSize, tb, widget);
pm = proxy()->standardIcon(SP_TitleBarMenuButton, &tool, widget).pixmap(QSize(iconSize, iconSize), p->device()->devicePixelRatio());
tool.rect = ir;
- p->save();
+ QPainterStateSaver pss(p);
proxy()->drawItemPixmap(p, ir, Qt::AlignCenter, pm);
- p->restore();
}
}
}
@@ -3673,7 +3714,7 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl
case CC_Dial:
if (const QStyleOptionSlider *dial = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
// OK, this is more a port of things over
- p->save();
+ QPainterStateSaver pss(p);
// avoid dithering
if (p->paintEngine()->hasFeature(QPaintEngine::Antialiasing))
@@ -3758,7 +3799,6 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl
fropt.rect = br.adjusted(-2, -2, 2, 2);
proxy()->drawPrimitive(QStyle::PE_FrameFocusRect, &fropt, p, widget);
}
- p->restore();
}
break;
#endif // QT_CONFIG(dial)
@@ -3775,7 +3815,7 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl
frame.lineWidth = groupBox->lineWidth;
frame.midLineWidth = groupBox->midLineWidth;
frame.rect = proxy()->subControlRect(CC_GroupBox, opt, SC_GroupBoxFrame, widget);
- p->save();
+ QPainterStateSaver pss(p);
QRegion region(groupBox->rect);
if (!groupBox->text.isEmpty()) {
bool ltr = groupBox->direction == Qt::LeftToRight;
@@ -3790,7 +3830,6 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl
}
p->setClipRegion(region);
proxy()->drawPrimitive(PE_FrameGroupBox, &frame, p, widget);
- p->restore();
}
// Draw title
@@ -3838,8 +3877,8 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl
if (opt->activeSubControls & QStyle::SC_MdiCloseButton && (opt->state & State_Sunken)) {
btnOpt.state |= State_Sunken;
btnOpt.state &= ~State_Raised;
- bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt);
- bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt);
+ bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget);
+ bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget);
} else {
btnOpt.state |= State_Raised;
btnOpt.state &= ~State_Sunken;
@@ -3855,8 +3894,8 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl
if (opt->activeSubControls & QStyle::SC_MdiNormalButton && (opt->state & State_Sunken)) {
btnOpt.state |= State_Sunken;
btnOpt.state &= ~State_Raised;
- bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt);
- bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt);
+ bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget);
+ bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget);
} else {
btnOpt.state |= State_Raised;
btnOpt.state &= ~State_Sunken;
@@ -3872,8 +3911,8 @@ void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCompl
if (opt->activeSubControls & QStyle::SC_MdiMinButton && (opt->state & State_Sunken)) {
btnOpt.state |= State_Sunken;
btnOpt.state &= ~State_Raised;
- bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt);
- bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt);
+ bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt, widget);
+ bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt, widget);
} else {
btnOpt.state |= State_Raised;
btnOpt.state &= ~State_Sunken;
@@ -4193,6 +4232,7 @@ QRect QCommonStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex
break;
case SC_SpinBoxFrame:
ret = spinbox->rect;
+ break;
default:
break;
}
@@ -4353,7 +4393,7 @@ QRect QCommonStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex
if (verticalAlignment & Qt::AlignVCenter)
topMargin = topHeight / 2;
else if (verticalAlignment & Qt::AlignTop)
- topMargin = topHeight;
+ topMargin = topHeight + proxy()->pixelMetric(PM_FocusFrameVMargin, groupBox, widget);
}
QRect frameRect = groupBox->rect;
@@ -4486,15 +4526,6 @@ int QCommonStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const QWid
case PM_MenuBarHMargin:
ret = 0;
break;
- case PM_DialogButtonsSeparator:
- ret = int(QStyleHelper::dpiScaled(5, opt));
- break;
- case PM_DialogButtonsButtonWidth:
- ret = int(QStyleHelper::dpiScaled(70, opt));
- break;
- case PM_DialogButtonsButtonHeight:
- ret = int(QStyleHelper::dpiScaled(30, opt));
- break;
case PM_TitleBarHeight:
{
if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
@@ -4912,7 +4943,7 @@ QSize QCommonStyle::sizeFromContents(ContentsType contentsType, const QStyleOpti
} else {
height = menuItemOpt->fontMetrics.height() + 8;
if (!menuItemOpt->icon.isNull()) {
- int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, opt);
+ int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, opt, widget);
height = qMax(height,
menuItemOpt->icon.actualSize(QSize(iconExtent,
iconExtent)).height() + 4);
@@ -4942,7 +4973,7 @@ QSize QCommonStyle::sizeFromContents(ContentsType contentsType, const QStyleOpti
const int frameWidth = comboBoxOpt->frame ? proxy()->pixelMetric(PM_ComboBoxFrameWidth,
opt,
widget) * 2 : 0;
- const int textMargins = 2*(proxy()->pixelMetric(PM_FocusFrameHMargin, opt) + 1);
+ const int textMargins = 2 * (proxy()->pixelMetric(PM_FocusFrameHMargin, opt, widget) + 1);
// QItemDelegate::sizeHint expands the textMargins two times, thus the 2*textMargins...
const int other = qMax(23, 2 * textMargins
@@ -5204,8 +5235,8 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget
if (widget) {
if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
mask->region = widget->rect();
- const int vmargin = proxy()->pixelMetric(QStyle::PM_FocusFrameVMargin, opt);
- const int hmargin = proxy()->pixelMetric(QStyle::PM_FocusFrameHMargin, opt);
+ const int vmargin = proxy()->pixelMetric(QStyle::PM_FocusFrameVMargin, opt, widget);
+ const int hmargin = proxy()->pixelMetric(QStyle::PM_FocusFrameHMargin, opt, widget);
mask->region -= QRect(widget->rect().adjusted(hmargin, vmargin, -hmargin, -vmargin));
}
}
@@ -5218,7 +5249,7 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget
ret = true;
if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
mask->region = opt->rect;
- const int margin = proxy()->pixelMetric(PM_DefaultFrameWidth, opt) * 2;
+ const int margin = proxy()->pixelMetric(PM_DefaultFrameWidth, opt, widget) * 2;
mask->region -= opt->rect.adjusted(margin, margin, -margin, -margin);
}
}
@@ -5468,647 +5499,313 @@ 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()
-{
- return QStringLiteral(":/qt-project.org/styles/commonstyle/images/cleartext-16.png");
-}
-#endif // !QT_NO_IMAGEFORMAT_PNG
+#if QT_CONFIG(imageformat_png)
+static constexpr QLatin1StringView iconResourcePrefix() noexcept { return ":/qt-project.org/styles/commonstyle/images/"_L1; }
+static constexpr QLatin1StringView iconPngSuffix() noexcept { return ".png"_L1; }
-#if defined(Q_OS_WIN) || QT_CONFIG(imageformat_png)
-static QIcon clearTextIcon(bool rtl)
+template <typename T>
+static void addIconFiles(QStringView prefix, std::initializer_list<T> sizes, QIcon &icon,
+ QIcon::Mode mode = QIcon::Normal, QIcon::State state = QIcon::Off)
{
- const QString directionalThemeName = rtl
- ? QStringLiteral("edit-clear-locationbar-ltr") : QStringLiteral("edit-clear-locationbar-rtl");
- if (QIcon::hasThemeIcon(directionalThemeName))
- return QIcon::fromTheme(directionalThemeName);
- const QString themeName = QStringLiteral("edit-clear");
- if (QIcon::hasThemeIcon(themeName))
- return QIcon::fromTheme(themeName);
-
- QIcon icon;
-#ifndef QT_NO_IMAGEFORMAT_PNG
- QPixmap clearText16(clearText16IconPath());
- Q_ASSERT(!clearText16.size().isEmpty());
- icon.addPixmap(clearText16);
- QPixmap clearText32(QStringLiteral(":/qt-project.org/styles/commonstyle/images/cleartext-32.png"));
- Q_ASSERT(!clearText32.size().isEmpty());
- icon.addPixmap(clearText32);
- clearText32.setDevicePixelRatio(2); // The 32x32 pixmap can also be used for 16x16/devicePixelRatio=2
- icon.addPixmap(clearText32);
-#endif // !QT_NO_IMAGEFORMAT_PNG
- return icon;
+ const auto fullPrefix = iconResourcePrefix() + prefix;
+ for (int size : sizes)
+ icon.addFile(fullPrefix + QString::number(size) + iconPngSuffix(),
+ QSize(size, size), mode, state);
}
-#endif
+
+static constexpr auto dockTitleIconSizes = {10, 16, 20, 32, 48, 64};
+static constexpr auto titleBarSizes = {16, 32, 48};
+static constexpr auto toolBarExtHSizes = {8, 16, 32, 128};
+static constexpr auto toolBarExtVSizes = {5, 10, 20, 80};
+static constexpr auto pngIconSizes = {16, 32, 128};
+#endif // imageformat_png
/*! \reimp */
QPixmap QCommonStyle::standardPixmap(StandardPixmap sp, const QStyleOption *option,
const QWidget *widget) const
{
- const bool rtl = (option && option->direction == Qt::RightToLeft) || (!option && QGuiApplication::isRightToLeft());
-#ifdef QT_NO_IMAGEFORMAT_PNG
- Q_UNUSED(widget);
- Q_UNUSED(sp);
-#else
- QPixmap pixmap;
+ Q_D(const QCommonStyle);
+ QIcon icon;
- if (QGuiApplication::desktopSettingsAware() && !QIcon::themeName().isEmpty()) {
- switch (sp) {
- case SP_DialogYesButton:
- case SP_DialogOkButton:
- pixmap = QIcon::fromTheme("dialog-ok"_L1).pixmap(16);
- break;
- case SP_DialogApplyButton:
- pixmap = QIcon::fromTheme("dialog-ok-apply"_L1).pixmap(16);
- break;
- case SP_DialogDiscardButton:
- pixmap = QIcon::fromTheme("edit-delete"_L1).pixmap(16);
- break;
- case SP_DialogCloseButton:
- pixmap = QIcon::fromTheme("dialog-close"_L1).pixmap(16);
- break;
- case SP_DirHomeIcon:
- pixmap = QIcon::fromTheme("user-home"_L1).pixmap(16);
- break;
- case SP_MessageBoxInformation:
- pixmap = QIcon::fromTheme("messagebox_info"_L1).pixmap(16);
- break;
- case SP_MessageBoxWarning:
- pixmap = QIcon::fromTheme("messagebox_warning"_L1).pixmap(16);
- break;
- case SP_MessageBoxCritical:
- pixmap = QIcon::fromTheme("messagebox_critical"_L1).pixmap(16);
- break;
- case SP_MessageBoxQuestion:
- pixmap = QIcon::fromTheme("help"_L1).pixmap(16);
- break;
- case SP_DialogOpenButton:
- case SP_DirOpenIcon:
- pixmap = QIcon::fromTheme("folder-open"_L1).pixmap(16);
- break;
- case SP_FileIcon:
- pixmap = QIcon::fromTheme("text-x-generic"_L1, QIcon::fromTheme("empty"_L1)).pixmap(16);
- break;
- case SP_DirClosedIcon:
- case SP_DirIcon:
- pixmap = QIcon::fromTheme("folder"_L1).pixmap(16);
- break;
- case SP_DriveFDIcon:
- pixmap = QIcon::fromTheme("media-floppy"_L1,
- QIcon::fromTheme("3floppy_unmount"_L1)).pixmap(16);
- break;
- case SP_ComputerIcon:
- pixmap = QIcon::fromTheme("computer"_L1, QIcon::fromTheme("system"_L1)).pixmap(16);
- break;
- case SP_DesktopIcon:
- pixmap = QIcon::fromTheme("user-desktop"_L1,
- QIcon::fromTheme("desktop"_L1)).pixmap(16);
- break;
- case SP_TrashIcon:
- pixmap = QIcon::fromTheme("user-trash"_L1,
- QIcon::fromTheme("trashcan_empty"_L1)).pixmap(16);
- break;
- case SP_DriveCDIcon:
- case SP_DriveDVDIcon:
- pixmap = QIcon::fromTheme("media-optical"_L1,
- QIcon::fromTheme("cdrom_unmount"_L1)).pixmap(16);
- break;
- case SP_DriveHDIcon:
- pixmap = QIcon::fromTheme("drive-harddisk"_L1,
- QIcon::fromTheme("hdd_unmount"_L1)).pixmap(16);
- break;
- case SP_FileDialogToParent:
- pixmap = QIcon::fromTheme("go-up"_L1, QIcon::fromTheme("up"_L1)).pixmap(16);
- break;
- case SP_FileDialogNewFolder:
- pixmap = QIcon::fromTheme("folder_new"_L1).pixmap(16);
- break;
- case SP_ArrowUp:
- pixmap = QIcon::fromTheme("go-up"_L1,
- QIcon::fromTheme("up"_L1)).pixmap(16);
- break;
- case SP_ArrowDown:
- pixmap = QIcon::fromTheme("go-down"_L1, QIcon::fromTheme("down"_L1)).pixmap(16);
- break;
- case SP_ArrowRight:
- pixmap = QIcon::fromTheme("go-next"_L1, QIcon::fromTheme("forward"_L1)).pixmap(16);
- break;
- case SP_ArrowLeft:
- pixmap = QIcon::fromTheme("go-previous"_L1, QIcon::fromTheme("back"_L1)).pixmap(16);
- break;
- case SP_FileDialogDetailedView:
- pixmap = QIcon::fromTheme("view_detailed"_L1).pixmap(16);
- break;
- case SP_FileDialogListView:
- pixmap = QIcon::fromTheme("view_icon"_L1).pixmap(16);
- break;
- case SP_BrowserReload:
- pixmap = QIcon::fromTheme("reload"_L1).pixmap(16);
- break;
- case SP_BrowserStop:
- pixmap = QIcon::fromTheme("process-stop"_L1).pixmap(16);
- break;
- case SP_MediaPlay:
- pixmap = QIcon::fromTheme("media-playback-start"_L1).pixmap(16);
- break;
- case SP_MediaPause:
- pixmap = QIcon::fromTheme("media-playback-pause"_L1).pixmap(16);
- break;
- case SP_MediaStop:
- pixmap = QIcon::fromTheme("media-playback-stop"_L1).pixmap(16);
- break;
- case SP_MediaSeekForward:
- pixmap = QIcon::fromTheme("media-seek-forward"_L1).pixmap(16);
- break;
- case SP_MediaSeekBackward:
- pixmap = QIcon::fromTheme("media-seek-backward"_L1).pixmap(16);
- break;
- case SP_MediaSkipForward:
- pixmap = QIcon::fromTheme("media-skip-forward"_L1).pixmap(16);
- break;
- case SP_MediaSkipBackward:
- pixmap = QIcon::fromTheme("media-skip-backward"_L1).pixmap(16);
- break;
- case SP_DialogResetButton:
- pixmap = QIcon::fromTheme("edit-clear"_L1).pixmap(24);
- break;
- case SP_DialogHelpButton:
- pixmap = QIcon::fromTheme("help-contents"_L1).pixmap(24);
- break;
- case SP_DialogNoButton:
- case SP_DialogCancelButton:
- pixmap = QIcon::fromTheme("dialog-cancel"_L1,
- QIcon::fromTheme("process-stop"_L1)).pixmap(24);
- break;
- case SP_DialogSaveButton:
- pixmap = QIcon::fromTheme("document-save"_L1).pixmap(24);
- break;
- case SP_FileLinkIcon:
- pixmap = QIcon::fromTheme("emblem-symbolic-link"_L1).pixmap(16);
- if (!pixmap.isNull()) {
- QPixmap fileIcon = QIcon::fromTheme("text-x-generic"_L1).pixmap(16);
- if (fileIcon.isNull())
- fileIcon = QIcon::fromTheme("empty"_L1).pixmap(16);
- if (!fileIcon.isNull()) {
- QPainter painter(&fileIcon);
- painter.drawPixmap(0, 0, 16, 16, pixmap);
- return fileIcon;
- }
- }
- break;
- case SP_DirLinkIcon:
- pixmap = QIcon::fromTheme("emblem-symbolic-link"_L1).pixmap(16);
- if (!pixmap.isNull()) {
- QPixmap dirIcon = QIcon::fromTheme("folder"_L1).pixmap(16);
- if (!dirIcon.isNull()) {
- QPainter painter(&dirIcon);
- painter.drawPixmap(0, 0, 16, 16, pixmap);
- return dirIcon;
- }
- }
- break;
- case SP_LineEditClearButton:
- pixmap = clearTextIcon(rtl).pixmap(16);
- break;
- default:
- break;
- }
- }
+ icon = d->iconFromWindowsTheme(sp, option, widget);
+ if (!icon.isNull())
+ return icon.pixmap(QSize(16, 16), qt_getDevicePixelRatio(widget));
+
+ icon = d->iconFromApplicationTheme(sp, option, widget);
+ if (!icon.isNull())
+ return icon.pixmap(QSize(16, 16), qt_getDevicePixelRatio(widget));
+
+ icon = d->iconFromMacTheme(sp, option, widget);
+ if (!icon.isNull())
+ return icon.pixmap(QSize(16, 16), qt_getDevicePixelRatio(widget));
+
+ icon = d->iconFromResourceTheme(sp, option, widget);
+ if (!icon.isNull())
+ return icon.pixmap(QSize(16, 16), qt_getDevicePixelRatio(widget));
- if (!pixmap.isNull())
- return pixmap;
-#endif //QT_NO_IMAGEFORMAT_PNG
- switch (sp) {
#ifndef QT_NO_IMAGEFORMAT_XPM
- case SP_ToolBarHorizontalExtensionButton:
- if (rtl) {
- QImage im(tb_extension_arrow_h_xpm);
- im = im.convertToFormat(QImage::Format_ARGB32).mirrored(true, false);
- return QPixmap::fromImage(im);
+ switch (sp) {
+ case QStyle::SP_ToolBarHorizontalExtensionButton:
+ if (d->rtl(option)) {
+ auto im = QImage(tb_extension_arrow_h_xpm).convertToFormat(QImage::Format_ARGB32).mirrored(true, false);
+ return QPixmap::fromImage(std::move(im));
}
return cachedPixmapFromXPM(tb_extension_arrow_h_xpm);
- case SP_ToolBarVerticalExtensionButton:
+ case QStyle::SP_ToolBarVerticalExtensionButton:
return cachedPixmapFromXPM(tb_extension_arrow_v_xpm);
- case SP_FileDialogStart:
+ case QStyle::SP_FileDialogStart:
return cachedPixmapFromXPM(filedialog_start_xpm);
- case SP_FileDialogEnd:
+ case QStyle::SP_FileDialogEnd:
return cachedPixmapFromXPM(filedialog_end_xpm);
-#endif
-#ifndef QT_NO_IMAGEFORMAT_PNG
- case SP_CommandLink:
- case SP_ArrowForward:
- if (rtl)
- return proxy()->standardPixmap(SP_ArrowLeft, option, widget);
- return proxy()->standardPixmap(SP_ArrowRight, option, widget);
- case SP_ArrowBack:
- if (rtl)
- return proxy()->standardPixmap(SP_ArrowRight, option, widget);
- return proxy()->standardPixmap(SP_ArrowLeft, option, widget);
- case SP_ArrowLeft:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/left-16.png"_L1);
- case SP_ArrowRight:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/right-16.png"_L1);
- case SP_ArrowUp:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/up-16.png"_L1);
- case SP_ArrowDown:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/down-16.png"_L1);
- case SP_FileDialogToParent:
- return proxy()->standardPixmap(SP_ArrowUp, option, widget);
- case SP_FileDialogNewFolder:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/newdirectory-16.png"_L1);
- case SP_FileDialogDetailedView:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/viewdetailed-16.png"_L1);
- case SP_FileDialogInfoView:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/fileinfo-16.png"_L1);
- case SP_FileDialogContentsView:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/filecontents-16.png"_L1);
- case SP_FileDialogListView:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/viewlist-16.png"_L1);
- case SP_FileDialogBack:
- return proxy()->standardPixmap(SP_ArrowBack, option, widget);
- case SP_DriveHDIcon:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/harddrive-16.png"_L1);
- case SP_TrashIcon:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/trash-16.png"_L1);
- case SP_DriveFDIcon:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/floppy-16.png"_L1);
- case SP_DriveNetIcon:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/networkdrive-16.png"_L1);
- case SP_DesktopIcon:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/desktop-16.png"_L1);
- case SP_ComputerIcon:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/computer-16.png"_L1);
- case SP_DriveCDIcon:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/cdr-16.png"_L1);
- case SP_DriveDVDIcon:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/dvd-16.png"_L1);
- case SP_DirHomeIcon:
- case SP_DirOpenIcon:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/diropen-16.png"_L1);
- case SP_DirIcon:
- case SP_DirClosedIcon:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/dirclosed-16.png"_L1);
- case SP_DirLinkIcon:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/dirlink-16.png"_L1);
- case SP_FileIcon:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/file-16.png"_L1);
- case SP_FileLinkIcon:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/filelink-16.png"_L1);
- case SP_DialogOkButton:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/standardbutton-ok-16.png"_L1);
- case SP_DialogCancelButton:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/standardbutton-cancel-16.png"_L1);
- case SP_DialogHelpButton:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/standardbutton-help-16.png"_L1);
- case SP_DialogOpenButton:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/standardbutton-open-16.png"_L1);
- case SP_DialogSaveButton:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/standardbutton-save-16.png"_L1);
- case SP_DialogCloseButton:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/standardbutton-close-16.png"_L1);
- case SP_DialogApplyButton:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/standardbutton-apply-16.png"_L1);
- case SP_DialogResetButton:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/standardbutton-clear-16.png"_L1);
- case SP_DialogDiscardButton:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/standardbutton-delete-16.png"_L1);
- case SP_DialogYesButton:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/standardbutton-yes-16.png"_L1);
- case SP_DialogNoButton:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/standardbutton-no-16.png"_L1);
- case SP_BrowserReload:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/refresh-24.png"_L1);
- case SP_BrowserStop:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/stop-24.png"_L1);
- case SP_MediaPlay:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/media-play-32.png"_L1);
- case SP_MediaPause:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/media-pause-32.png"_L1);
- case SP_MediaStop:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/media-stop-32.png"_L1);
- case SP_MediaSeekForward:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/media-seek-forward-32.png"_L1);
- case SP_MediaSeekBackward:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/media-seek-backward-32.png"_L1);
- case SP_MediaSkipForward:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/media-skip-forward-32.png"_L1);
- case SP_MediaSkipBackward:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/media-skip-backward-32.png"_L1);
- case SP_MediaVolume:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/media-volume-16.png"_L1);
- case SP_MediaVolumeMuted:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/media-volume-muted-16.png"_L1);
- case SP_LineEditClearButton:
- return QPixmap(clearText16IconPath());
- case SP_TabCloseButton:
- return QPixmap(":/qt-project.org/styles/commonstyle/images/standardbutton-closetab-16.png"_L1);
-#endif // QT_NO_IMAGEFORMAT_PNG
- default:
- break;
- }
-
-#ifndef QT_NO_IMAGEFORMAT_XPM
- switch (sp) {
- case SP_TitleBarMenuButton:
+ case QStyle::SP_TitleBarMenuButton:
return titleBarMenuCachedPixmapFromXPM();
- case SP_TitleBarShadeButton:
+ case QStyle::SP_TitleBarShadeButton:
return cachedPixmapFromXPM(qt_shade_xpm);
- case SP_TitleBarUnshadeButton:
+ case QStyle::SP_TitleBarUnshadeButton:
return cachedPixmapFromXPM(qt_unshade_xpm);
- case SP_TitleBarNormalButton:
+ case QStyle::SP_TitleBarNormalButton:
return cachedPixmapFromXPM(qt_normalizeup_xpm);
- case SP_TitleBarMinButton:
+ case QStyle::SP_TitleBarMinButton:
return cachedPixmapFromXPM(qt_minimize_xpm);
- case SP_TitleBarMaxButton:
+ case QStyle::SP_TitleBarMaxButton:
return cachedPixmapFromXPM(qt_maximize_xpm);
- case SP_TitleBarCloseButton:
+ case QStyle::SP_TitleBarCloseButton:
return cachedPixmapFromXPM(qt_close_xpm);
- case SP_TitleBarContextHelpButton:
+ case QStyle::SP_TitleBarContextHelpButton:
return cachedPixmapFromXPM(qt_help_xpm);
- case SP_DockWidgetCloseButton:
+ case QStyle::SP_DockWidgetCloseButton:
return cachedPixmapFromXPM(dock_widget_close_xpm);
- case SP_MessageBoxInformation:
+ case QStyle::SP_MessageBoxInformation:
return cachedPixmapFromXPM(information_xpm);
- case SP_MessageBoxWarning:
+ case QStyle::SP_MessageBoxWarning:
return cachedPixmapFromXPM(warning_xpm);
- case SP_MessageBoxCritical:
+ case QStyle::SP_MessageBoxCritical:
return cachedPixmapFromXPM(critical_xpm);
- case SP_MessageBoxQuestion:
+ case QStyle::SP_MessageBoxQuestion:
return cachedPixmapFromXPM(question_xpm);
default:
break;
}
#endif //QT_NO_IMAGEFORMAT_XPM
-#if !QT_CONFIG(imageformat_png) && !QT_CONFIG(imageformat_xpm) && !QT_CONFIG(imageformat_png)
- Q_UNUSED(rtl);
-#endif
-
return QPixmap();
}
-#if QT_CONFIG(imageformat_png)
-static inline QString iconResourcePrefix() { return QStringLiteral(":/qt-project.org/styles/commonstyle/images/"); }
-static inline QString iconPngSuffix() { return QStringLiteral(".png"); }
-
-static void addIconFiles(const QString &prefix, const int sizes[], size_t count, QIcon &icon)
-{
- for (size_t i = 0; i < count; ++i)
- icon.addFile(prefix + QString::number(sizes[i]) + iconPngSuffix());
-}
-
-static const int dockTitleIconSizes[] = {10, 16, 20, 32, 48, 64};
-static const int titleBarSizes[] = {16, 32, 48};
-static const int toolBarExtHSizes[] = {8, 16, 32};
-static const int toolBarExtVSizes[] = {5, 10, 20};
-#endif // imageformat_png
-
-/*!
- \internal
-*/
-QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option,
- const QWidget *widget) const
+QIcon QCommonStylePrivate::iconFromWindowsTheme(QCommonStyle::StandardPixmap standardIcon,
+ const QStyleOption *option,
+ const QWidget *widget) const
{
+ Q_UNUSED(option);
+ Q_UNUSED(widget);
QIcon icon;
- const bool rtl = (option && option->direction == Qt::RightToLeft) || (!option && QGuiApplication::isRightToLeft());
-
#ifdef Q_OS_WIN
switch (standardIcon) {
- case SP_DriveCDIcon:
- case SP_DriveDVDIcon:
- case SP_DriveNetIcon:
- case SP_DriveHDIcon:
- case SP_DriveFDIcon:
- case SP_FileIcon:
- case SP_FileLinkIcon:
- case SP_DesktopIcon:
- case SP_ComputerIcon:
- case SP_VistaShield:
- case SP_MessageBoxInformation:
- case SP_MessageBoxWarning:
- case SP_MessageBoxCritical:
- case SP_MessageBoxQuestion:
+ case QStyle::SP_DriveCDIcon:
+ case QStyle::SP_DriveDVDIcon:
+ case QStyle::SP_DriveNetIcon:
+ case QStyle::SP_DriveHDIcon:
+ case QStyle::SP_DriveFDIcon:
+ case QStyle::SP_FileIcon:
+ case QStyle::SP_FileLinkIcon:
+ case QStyle::SP_DesktopIcon:
+ case QStyle::SP_ComputerIcon:
+ case QStyle::SP_VistaShield:
+ case QStyle::SP_MessageBoxInformation:
+ case QStyle::SP_MessageBoxWarning:
+ case QStyle::SP_MessageBoxCritical:
+ case QStyle::SP_MessageBoxQuestion:
if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
QPlatformTheme::StandardPixmap sp = static_cast<QPlatformTheme::StandardPixmap>(standardIcon);
- for (int size = 16 ; size <= 32 ; size += 16) {
- QPixmap pixmap = theme->standardPixmap(sp, QSizeF(size, size));
+ const auto dpr = qt_getDevicePixelRatio(widget);
+ const QList<QSize> sizes = theme->themeHint(QPlatformTheme::IconPixmapSizes).value<QList<QSize>>();
+ for (const QSize &size : sizes) {
+ QPixmap pixmap = theme->standardPixmap(sp, size * dpr);
+ pixmap.setDevicePixelRatio(dpr);
icon.addPixmap(pixmap, QIcon::Normal);
}
}
break;
- case SP_DirIcon:
- case SP_DirLinkIcon:
+ case QStyle::SP_DirIcon:
+ case QStyle::SP_DirLinkIcon:
if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
QPlatformTheme::StandardPixmap spOff = static_cast<QPlatformTheme::StandardPixmap>(standardIcon);
- QPlatformTheme::StandardPixmap spOn = standardIcon == SP_DirIcon ? QPlatformTheme::DirOpenIcon :
- QPlatformTheme::DirLinkOpenIcon;
- for (int size = 16 ; size <= 32 ; size += 16) {
- QSizeF pixSize(size, size);
+ QPlatformTheme::StandardPixmap spOn = standardIcon == QStyle::SP_DirIcon ? QPlatformTheme::DirOpenIcon
+ : QPlatformTheme::DirLinkOpenIcon;
+ const auto dpr = qt_getDevicePixelRatio(widget);
+ const QList<QSize> sizes = theme->themeHint(QPlatformTheme::IconPixmapSizes).value<QList<QSize>>();
+ for (const QSize &size : sizes) {
+ const QSizeF pixSize = size * dpr;
QPixmap pixmap = theme->standardPixmap(spOff, pixSize);
+ pixmap.setDevicePixelRatio(dpr);
icon.addPixmap(pixmap, QIcon::Normal, QIcon::Off);
pixmap = theme->standardPixmap(spOn, pixSize);
+ pixmap.setDevicePixelRatio(dpr);
icon.addPixmap(pixmap, QIcon::Normal, QIcon::On);
}
}
break;
- case SP_LineEditClearButton:
- icon = clearTextIcon(rtl);
- break;
default:
break;
}
- if (!icon.isNull())
- return icon;
-
+#else
+ Q_UNUSED(standardIcon)
#endif
+ return icon;
+}
+QIcon QCommonStylePrivate::iconFromApplicationTheme(QCommonStyle::StandardPixmap standardIcon,
+ const QStyleOption *option,
+ const QWidget *widget) const
+{
if (QGuiApplication::desktopSettingsAware() && !QIcon::themeName().isEmpty()) {
switch (standardIcon) {
- case SP_DirHomeIcon:
- icon = QIcon::fromTheme("user-home"_L1);
- break;
- case SP_MessageBoxInformation:
- icon = QIcon::fromTheme("dialog-information"_L1);
- break;
- case SP_MessageBoxWarning:
- icon = QIcon::fromTheme("dialog-warning"_L1);
- break;
- case SP_MessageBoxCritical:
- icon = QIcon::fromTheme("dialog-error"_L1);
- break;
- case SP_MessageBoxQuestion:
- icon = QIcon::fromTheme("dialog-question"_L1);
- break;
- case SP_DialogOpenButton:
- case SP_DirOpenIcon:
- icon = QIcon::fromTheme("folder-open"_L1);
- break;
- case SP_DialogSaveButton:
- icon = QIcon::fromTheme("document-save"_L1);
- break;
- case SP_DialogApplyButton:
- icon = QIcon::fromTheme("dialog-ok-apply"_L1);
- break;
- case SP_DialogYesButton:
- case SP_DialogOkButton:
- icon = QIcon::fromTheme("dialog-ok"_L1);
- break;
- case SP_DialogDiscardButton:
- icon = QIcon::fromTheme("edit-delete"_L1);
- break;
- case SP_DialogResetButton:
- icon = QIcon::fromTheme("edit-clear"_L1);
- break;
- case SP_DialogHelpButton:
- icon = QIcon::fromTheme("help-contents"_L1);
- break;
- case SP_FileIcon:
- icon = QIcon::fromTheme("text-x-generic"_L1);
- break;
- case SP_DirClosedIcon:
- case SP_DirIcon:
- icon = QIcon::fromTheme("folder"_L1);
- break;
- case SP_DriveFDIcon:
- icon = QIcon::fromTheme("floppy_unmount"_L1);
- break;
- case SP_ComputerIcon:
- icon = QIcon::fromTheme("computer"_L1, QIcon::fromTheme("system"_L1));
- break;
- case SP_DesktopIcon:
- icon = QIcon::fromTheme("user-desktop"_L1);
- break;
- case SP_TrashIcon:
- icon = QIcon::fromTheme("user-trash"_L1);
- break;
- case SP_DriveCDIcon:
- case SP_DriveDVDIcon:
- icon = QIcon::fromTheme("media-optical"_L1);
- break;
- case SP_DriveHDIcon:
- icon = QIcon::fromTheme("drive-harddisk"_L1);
- break;
- case SP_FileDialogToParent:
- icon = QIcon::fromTheme("go-up"_L1);
- break;
- case SP_FileDialogNewFolder:
- icon = QIcon::fromTheme("folder-new"_L1);
- break;
- case SP_ArrowUp:
- icon = QIcon::fromTheme("go-up"_L1);
- break;
- case SP_ArrowDown:
- icon = QIcon::fromTheme("go-down"_L1);
- break;
- case SP_ArrowRight:
- icon = QIcon::fromTheme("go-next"_L1);
- break;
- case SP_ArrowLeft:
- icon = QIcon::fromTheme("go-previous"_L1);
- break;
- case SP_DialogNoButton:
- case SP_DialogCancelButton:
- icon = QIcon::fromTheme("dialog-cancel"_L1, QIcon::fromTheme("process-stop"_L1));
- break;
- case SP_DialogCloseButton:
- icon = QIcon::fromTheme("window-close"_L1);
- break;
- case SP_FileDialogDetailedView:
- icon = QIcon::fromTheme("view-list-details"_L1);
- break;
- case SP_FileDialogListView:
- icon = QIcon::fromTheme("view-list-icons"_L1);
- break;
- case SP_BrowserReload:
- icon = QIcon::fromTheme("view-refresh"_L1);
- break;
- case SP_BrowserStop:
- icon = QIcon::fromTheme("process-stop"_L1);
- break;
- case SP_MediaPlay:
- icon = QIcon::fromTheme("media-playback-start"_L1);
- break;
- case SP_MediaPause:
- icon = QIcon::fromTheme("media-playback-pause"_L1);
- break;
- case SP_MediaStop:
- icon = QIcon::fromTheme("media-playback-stop"_L1);
- break;
- case SP_MediaSeekForward:
- icon = QIcon::fromTheme("media-seek-forward"_L1);
- break;
- case SP_MediaSeekBackward:
- icon = QIcon::fromTheme("media-seek-backward"_L1);
- break;
- case SP_MediaSkipForward:
- icon = QIcon::fromTheme("media-skip-forward"_L1);
- break;
- case SP_MediaSkipBackward:
- icon = QIcon::fromTheme("media-skip-backward"_L1);
- break;
- case SP_MediaVolume:
- icon = QIcon::fromTheme("audio-volume-medium"_L1);
- break;
- case SP_MediaVolumeMuted:
- icon = QIcon::fromTheme("audio-volume-muted"_L1);
- break;
- case SP_ArrowForward:
- if (rtl)
- return QCommonStyle::standardIcon(SP_ArrowLeft, option, widget);
- return QCommonStyle::standardIcon(SP_ArrowRight, option, widget);
- case SP_ArrowBack:
- if (rtl)
- return QCommonStyle::standardIcon(SP_ArrowRight, option, widget);
- return QCommonStyle::standardIcon(SP_ArrowLeft, option, widget);
- case SP_FileLinkIcon:
- {
- QIcon linkIcon = QIcon::fromTheme("emblem-symbolic-link"_L1);
- if (!linkIcon.isNull()) {
- QIcon baseIcon = QCommonStyle::standardIcon(SP_FileIcon, option, widget);
- const QList<QSize> sizes = baseIcon.availableSizes(QIcon::Normal, QIcon::Off);
- for (int i = 0 ; i < sizes.size() ; ++i) {
- int size = sizes[i].width();
- QPixmap basePixmap = baseIcon.pixmap(QSize(size, size), qt_getDevicePixelRatio(widget));
- QPixmap linkPixmap = linkIcon.pixmap(QSize(size / 2, size / 2), qt_getDevicePixelRatio(widget));
+ case QStyle::SP_DirHomeIcon:
+ return QIcon::fromTheme("user-home"_L1);
+ case QStyle::SP_MessageBoxInformation:
+ return QIcon::fromTheme("dialog-information"_L1);
+ case QStyle::SP_MessageBoxWarning:
+ return QIcon::fromTheme("dialog-warning"_L1);
+ case QStyle::SP_MessageBoxCritical:
+ return QIcon::fromTheme("dialog-error"_L1);
+ case QStyle::SP_MessageBoxQuestion:
+ return QIcon::fromTheme("dialog-question"_L1);
+ case QStyle::SP_DialogOpenButton:
+ case QStyle::SP_DirOpenIcon:
+ return QIcon::fromTheme("folder-open"_L1);
+ case QStyle::SP_DialogSaveButton:
+ return QIcon::fromTheme("document-save"_L1);
+ case QStyle::SP_DialogApplyButton:
+ return QIcon::fromTheme("dialog-ok-apply"_L1);
+ case QStyle::SP_DialogYesButton:
+ case QStyle::SP_DialogOkButton:
+ return QIcon::fromTheme("dialog-ok"_L1);
+ case QStyle::SP_DialogDiscardButton:
+ return QIcon::fromTheme("edit-delete"_L1);
+ case QStyle::SP_DialogResetButton:
+ return QIcon::fromTheme("edit-clear"_L1);
+ case QStyle::SP_DialogHelpButton:
+ return QIcon::fromTheme("help-contents"_L1);
+ case QStyle::SP_FileIcon:
+ return QIcon::fromTheme("text-x-generic"_L1);
+ case QStyle::SP_DirClosedIcon:
+ case QStyle::SP_DirIcon:
+ return QIcon::fromTheme("folder"_L1);
+ case QStyle::SP_DriveFDIcon:
+ return QIcon::fromTheme("floppy_unmount"_L1);
+ case QStyle::SP_ComputerIcon:
+ return QIcon::fromTheme("computer"_L1, QIcon::fromTheme("system"_L1));
+ case QStyle::SP_DesktopIcon:
+ return QIcon::fromTheme("user-desktop"_L1);
+ case QStyle::SP_TrashIcon:
+ return QIcon::fromTheme("user-trash"_L1);
+ case QStyle::SP_DriveCDIcon:
+ case QStyle::SP_DriveDVDIcon:
+ return QIcon::fromTheme("media-optical"_L1);
+ case QStyle::SP_DriveHDIcon:
+ return QIcon::fromTheme("drive-harddisk"_L1);
+ case QStyle::SP_FileDialogToParent:
+ return QIcon::fromTheme("go-up"_L1);
+ case QStyle::SP_FileDialogNewFolder:
+ return QIcon::fromTheme("folder-new"_L1);
+ case QStyle::SP_ArrowUp:
+ return QIcon::fromTheme("go-up"_L1);
+ case QStyle::SP_ArrowDown:
+ return QIcon::fromTheme("go-down"_L1);
+ case QStyle::SP_ArrowRight:
+ return QIcon::fromTheme("go-next"_L1);
+ case QStyle::SP_ArrowLeft:
+ return QIcon::fromTheme("go-previous"_L1);
+ case QStyle::SP_DialogNoButton:
+ case QStyle::SP_DialogCancelButton:
+ return QIcon::fromTheme("dialog-cancel"_L1, QIcon::fromTheme("process-stop"_L1));
+ case QStyle::SP_DialogCloseButton:
+ return QIcon::fromTheme("window-close"_L1);
+ case QStyle::SP_FileDialogDetailedView:
+ return QIcon::fromTheme("view-list-details"_L1);
+ case QStyle::SP_FileDialogListView:
+ return QIcon::fromTheme("view-list-icons"_L1);
+ case QStyle::SP_BrowserReload:
+ return QIcon::fromTheme("view-refresh"_L1);
+ case QStyle::SP_BrowserStop:
+ return QIcon::fromTheme("process-stop"_L1);
+ case QStyle::SP_MediaPlay:
+ return QIcon::fromTheme("media-playback-start"_L1);
+ case QStyle::SP_MediaPause:
+ return QIcon::fromTheme("media-playback-pause"_L1);
+ case QStyle::SP_MediaStop:
+ return QIcon::fromTheme("media-playback-stop"_L1);
+ case QStyle::SP_MediaSeekForward:
+ return QIcon::fromTheme("media-seek-forward"_L1);
+ case QStyle::SP_MediaSeekBackward:
+ return QIcon::fromTheme("media-seek-backward"_L1);
+ case QStyle::SP_MediaSkipForward:
+ return QIcon::fromTheme("media-skip-forward"_L1);
+ case QStyle::SP_MediaSkipBackward:
+ return QIcon::fromTheme("media-skip-backward"_L1);
+ case QStyle::SP_MediaVolume:
+ return QIcon::fromTheme("audio-volume-medium"_L1);
+ case QStyle::SP_MediaVolumeMuted:
+ return QIcon::fromTheme("audio-volume-muted"_L1);
+ case QStyle::SP_ArrowForward:
+ return iconFromApplicationTheme(rtl(option) ? QStyle::SP_ArrowLeft
+ : QStyle::SP_ArrowRight,
+ option, widget);
+ case QStyle::SP_ArrowBack:
+ return iconFromApplicationTheme(rtl(option) ? QStyle::SP_ArrowRight
+ : QStyle::SP_ArrowLeft,
+ option, widget);
+ case QStyle::SP_DirLinkIcon:
+ case QStyle::SP_FileLinkIcon: {
+ const auto si = (standardIcon == QStyle::SP_DirLinkIcon)
+ ? QStyle::SP_DirIcon : QStyle::SP_FileIcon;
+ QIcon icon;
+ const QIcon linkIcon = QIcon::fromTheme("emblem-symbolic-link"_L1);
+ const QIcon baseIcon = iconFromApplicationTheme(si, option, widget);
+ if (!linkIcon.isNull() || !baseIcon.isNull()) {
+ const auto sizes = baseIcon.availableSizes(QIcon::Normal, QIcon::Off);
+ const auto dpr = qt_getDevicePixelRatio(widget);
+ for (const auto size : sizes) {
+ QPixmap basePixmap = baseIcon.pixmap(size, dpr);
+ QPixmap linkPixmap = linkIcon.pixmap(size / 2, dpr);
QPainter painter(&basePixmap);
- painter.drawPixmap(size/2, size/2, linkPixmap);
+ const auto w = size.width() / 2;
+ painter.drawPixmap(w, w, linkPixmap);
icon.addPixmap(basePixmap);
}
}
+ return icon;
}
break;
- case SP_DirLinkIcon:
- {
- QIcon linkIcon = QIcon::fromTheme("emblem-symbolic-link"_L1);
- if (!linkIcon.isNull()) {
- QIcon baseIcon = QCommonStyle::standardIcon(SP_DirIcon, option, widget);
- const QList<QSize> sizes = baseIcon.availableSizes(QIcon::Normal, QIcon::Off);
- for (int i = 0 ; i < sizes.size() ; ++i) {
- int size = sizes[i].width();
- QPixmap basePixmap = baseIcon.pixmap(QSize(size, size), qt_getDevicePixelRatio(widget));
- QPixmap linkPixmap = linkIcon.pixmap(QSize(size / 2, size / 2), qt_getDevicePixelRatio(widget));
- QPainter painter(&basePixmap);
- painter.drawPixmap(size/2, size/2, linkPixmap);
- icon.addPixmap(basePixmap);
- }
- }
+ case QStyle::SP_LineEditClearButton: {
+ const QString directionalThemeName = rtl(option)
+ ? QStringLiteral("edit-clear-locationbar-ltr") : QStringLiteral("edit-clear-locationbar-rtl");
+ if (QIcon::hasThemeIcon(directionalThemeName))
+ return QIcon::fromTheme(directionalThemeName);
+ const QString themeName = QStringLiteral("edit-clear");
+ if (QIcon::hasThemeIcon(themeName))
+ return QIcon::fromTheme(themeName);
+ break;
}
- break;
default:
break;
}
} // if (QGuiApplication::desktopSettingsAware() && !QIcon::themeName().isEmpty())
- if (!icon.isNull())
- return icon;
+ return {};
+}
-#if defined(Q_OS_MAC)
+QIcon QCommonStylePrivate::iconFromMacTheme(QCommonStyle::StandardPixmap standardIcon,
+ const QStyleOption *option,
+ const QWidget *widget) const
+{
+#ifdef Q_OS_DARWIN
+ Q_Q(const QCommonStyle);
if (QGuiApplication::desktopSettingsAware()) {
switch (standardIcon) {
- case SP_DirIcon: {
+ case QStyle::SP_DirIcon: {
// A rather special case
- QIcon closeIcon = QCommonStyle::standardIcon(SP_DirClosedIcon, option, widget);
- QIcon openIcon = QCommonStyle::standardIcon(SP_DirOpenIcon, option, widget);
+ QIcon closeIcon = q->standardIcon(QStyle::SP_DirClosedIcon, option, widget);
+ QIcon openIcon = q->standardIcon(QStyle::SP_DirOpenIcon, option, widget);
closeIcon.addPixmap(openIcon.pixmap(16, 16), QIcon::Normal, QIcon::On);
closeIcon.addPixmap(openIcon.pixmap(32, 32), QIcon::Normal, QIcon::On);
closeIcon.addPixmap(openIcon.pixmap(64, 64), QIcon::Normal, QIcon::On);
@@ -6116,38 +5813,39 @@ QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption
return closeIcon;
}
- case SP_TitleBarNormalButton:
- case SP_TitleBarCloseButton: {
+ case QStyle::SP_TitleBarNormalButton:
+ case QStyle::SP_TitleBarCloseButton: {
QIcon titleBarIcon;
- QString prefix = standardIcon == SP_TitleBarCloseButton
- ? QStringLiteral(":/qt-project.org/styles/macstyle/images/closedock-")
- : QStringLiteral(":/qt-project.org/styles/macstyle/images/dockdock-");
+ constexpr auto imagesPrefix = ":/qt-project.org/styles/macstyle/images/"_L1;
+ const auto namePrefix = standardIcon == QStyle::SP_TitleBarCloseButton
+ ? "closedock-"_L1
+ : "dockdock-"_L1;
for (const auto size : dockTitleIconSizes) {
- titleBarIcon.addFile(prefix + QStringLiteral("macstyle-") + QString::number(size) + iconPngSuffix(),
- QSize(size, size), QIcon::Normal, QIcon::Off);
- titleBarIcon.addFile(prefix + QStringLiteral("down-macstyle-") + QString::number(size) + iconPngSuffix(),
- QSize(size, size), QIcon::Normal, QIcon::On);
+ titleBarIcon.addFile(imagesPrefix + namePrefix + "macstyle-"_L1 + QString::number(size)
+ + iconPngSuffix(), QSize(size, size), QIcon::Normal, QIcon::Off);
+ titleBarIcon.addFile(imagesPrefix + namePrefix + "down-macstyle-"_L1 + QString::number(size)
+ + iconPngSuffix(), QSize(size, size), QIcon::Normal, QIcon::On);
}
return titleBarIcon;
}
- case SP_MessageBoxQuestion:
- case SP_MessageBoxInformation:
- case SP_MessageBoxWarning:
- case SP_MessageBoxCritical:
- case SP_DesktopIcon:
- case SP_TrashIcon:
- case SP_ComputerIcon:
- case SP_DriveFDIcon:
- case SP_DriveHDIcon:
- case SP_DriveCDIcon:
- case SP_DriveDVDIcon:
- case SP_DriveNetIcon:
- case SP_DirOpenIcon:
- case SP_DirClosedIcon:
- case SP_DirLinkIcon:
- case SP_FileLinkIcon:
- case SP_FileIcon:
+ case QStyle::SP_MessageBoxQuestion:
+ case QStyle::SP_MessageBoxInformation:
+ case QStyle::SP_MessageBoxWarning:
+ case QStyle::SP_MessageBoxCritical:
+ case QStyle::SP_DesktopIcon:
+ case QStyle::SP_TrashIcon:
+ case QStyle::SP_ComputerIcon:
+ case QStyle::SP_DriveFDIcon:
+ case QStyle::SP_DriveHDIcon:
+ case QStyle::SP_DriveCDIcon:
+ case QStyle::SP_DriveDVDIcon:
+ case QStyle::SP_DriveNetIcon:
+ case QStyle::SP_DirOpenIcon:
+ case QStyle::SP_DirClosedIcon:
+ case QStyle::SP_DirLinkIcon:
+ case QStyle::SP_FileLinkIcon:
+ case QStyle::SP_FileIcon:
if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
QPlatformTheme::StandardPixmap sp = static_cast<QPlatformTheme::StandardPixmap>(standardIcon);
QIcon retIcon;
@@ -6164,277 +5862,288 @@ QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption
retIcon.addPixmap(mainIcon);
}
- if (!retIcon.isNull())
- return retIcon;
+ return retIcon;
}
default:
break;
}
} // if (QGuiApplication::desktopSettingsAware())
-#endif // Q_OS_MAC
+#else // Q_OS_DARWIN
+ Q_UNUSED(standardIcon);
+ Q_UNUSED(option);
+ Q_UNUSED(widget);
+#endif // Q_OS_DARWIN
+ return {};
+}
- switch (standardIcon) {
+QIcon QCommonStylePrivate::iconFromResourceTheme(QCommonStyle::StandardPixmap standardIcon,
+ const QStyleOption *option,
+ const QWidget *widget) const
+{
+ Q_Q(const QCommonStyle);
+ QIcon icon;
#ifndef QT_NO_IMAGEFORMAT_PNG
- case SP_TitleBarMinButton:
- addIconFiles(iconResourcePrefix() + QStringLiteral("titlebar-min-"),
- titleBarSizes, sizeof(titleBarSizes)/sizeof(titleBarSizes[0]), icon);
- break;
- case SP_TitleBarMaxButton:
- addIconFiles(iconResourcePrefix() + QStringLiteral("titlebar-max-"),
- titleBarSizes, sizeof(titleBarSizes)/sizeof(titleBarSizes[0]), icon);
- break;
- case SP_TitleBarShadeButton:
- addIconFiles(iconResourcePrefix() + QStringLiteral("titlebar-shade-"),
- titleBarSizes, sizeof(titleBarSizes)/sizeof(titleBarSizes[0]), icon);
-
- break;
- case SP_TitleBarUnshadeButton:
- addIconFiles(iconResourcePrefix() + QStringLiteral("titlebar-unshade-"),
- titleBarSizes, sizeof(titleBarSizes)/sizeof(titleBarSizes[0]), icon);
- break;
- case SP_TitleBarContextHelpButton:
- addIconFiles(iconResourcePrefix() + QStringLiteral("titlebar-contexthelp-"),
- titleBarSizes, sizeof(titleBarSizes)/sizeof(titleBarSizes[0]), icon);
- break;
- case SP_FileDialogNewFolder:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/newdirectory-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/newdirectory-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/newdirectory-128.png"_L1, QSize(128, 128));
- break;
- case SP_FileDialogBack:
- return QCommonStyle::standardIcon(SP_ArrowBack, option, widget);
- case SP_FileDialogToParent:
- return QCommonStyle::standardIcon(SP_ArrowUp, option, widget);
- case SP_FileDialogDetailedView:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/viewdetailed-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/viewdetailed-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/viewdetailed-128.png"_L1, QSize(128, 128));
- break;
- case SP_FileDialogInfoView:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/fileinfo-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/fileinfo-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/fileinfo-128.png"_L1, QSize(128, 128));
- break;
- case SP_FileDialogContentsView:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/filecontents-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/filecontents-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/filecontents-128.png"_L1, QSize(128, 128));
- break;
- case SP_FileDialogListView:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/viewlist-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/viewlist-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/viewlist-128.png"_L1, QSize(128, 128));
- break;
- case SP_DialogOkButton:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-ok-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-ok-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-ok-128.png"_L1, QSize(128, 128));
- break;
- case SP_DialogCancelButton:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-cancel-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-cancel-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-cancel-128.png"_L1, QSize(128, 128));
- break;
- case SP_DialogHelpButton:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-help-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-help-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-help-128.png"_L1, QSize(128, 128));
- break;
- case SP_DialogOpenButton:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-open-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-open-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-open-128.png"_L1, QSize(128, 128));
- break;
- case SP_DialogSaveButton:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-save-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-save-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-save-128.png"_L1, QSize(128, 128));
- break;
- case SP_DialogCloseButton:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-close-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-close-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-close-128.png"_L1, QSize(128, 128));
- break;
- case SP_DialogApplyButton:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-apply-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-apply-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-apply-128.png"_L1, QSize(128, 128));
- break;
- case SP_DialogResetButton:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-clear-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-clear-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-clear-128.png"_L1, QSize(128, 128));
- break;
- case SP_DialogDiscardButton:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-delete-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-delete-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-delete-128.png"_L1, QSize(128, 128));
- break;
- case SP_DialogYesButton:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-yes-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-yes-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-yes-128.png"_L1, QSize(128, 128));
- break;
- case SP_DialogNoButton:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-no-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-no-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/standardbutton-no-128.png"_L1, QSize(128, 128));
- break;
- case SP_ArrowForward:
- if (rtl)
- return QCommonStyle::standardIcon(SP_ArrowLeft, option, widget);
- return QCommonStyle::standardIcon(SP_ArrowRight, option, widget);
- case SP_ArrowBack:
- if (rtl)
- return QCommonStyle::standardIcon(SP_ArrowRight, option, widget);
- return QCommonStyle::standardIcon(SP_ArrowLeft, option, widget);
- case SP_ArrowLeft:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/left-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/left-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/left-128.png"_L1, QSize(128, 128));
- break;
- case SP_ArrowRight:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/right-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/right-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/right-128.png"_L1, QSize(128, 128));
- break;
- case SP_ArrowUp:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/up-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/up-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/up-128.png"_L1, QSize(128, 128));
- break;
- case SP_ArrowDown:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/down-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/down-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/down-128.png"_L1, QSize(128, 128));
- break;
- case SP_DirHomeIcon:
- case SP_DirIcon:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/dirclosed-16.png"_L1,
- QSize(), QIcon::Normal, QIcon::Off);
- icon.addFile(":/qt-project.org/styles/commonstyle/images/diropen-16.png"_L1,
- QSize(), QIcon::Normal, QIcon::On);
- icon.addFile(":/qt-project.org/styles/commonstyle/images/dirclosed-32.png"_L1,
- QSize(32, 32), QIcon::Normal, QIcon::Off);
- icon.addFile(":/qt-project.org/styles/commonstyle/images/diropen-32.png"_L1,
- QSize(32, 32), QIcon::Normal, QIcon::On);
- icon.addFile(":/qt-project.org/styles/commonstyle/images/dirclosed-128.png"_L1,
- QSize(128, 128), QIcon::Normal, QIcon::Off);
- icon.addFile(":/qt-project.org/styles/commonstyle/images/diropen-128.png"_L1,
- QSize(128, 128), QIcon::Normal, QIcon::On);
- break;
- case SP_DriveCDIcon:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/cdr-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/cdr-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/cdr-128.png"_L1, QSize(128, 128));
- break;
- case SP_DriveDVDIcon:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/dvd-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/dvd-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/dvd-128.png"_L1, QSize(128, 128));
- break;
- case SP_FileIcon:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/file-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/file-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/file-128.png"_L1, QSize(128, 128));
- break;
- case SP_FileLinkIcon:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/filelink-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/filelink-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/filelink-128.png"_L1, QSize(128, 128));
- break;
- case SP_TrashIcon:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/trash-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/trash-32.png"_L1, QSize(32, 32));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/trash-128.png"_L1, QSize(128, 128));
- break;
- case SP_BrowserReload:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/refresh-24.png"_L1, QSize(24, 24));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/refresh-32.png"_L1, QSize(32, 32));
- break;
- case SP_BrowserStop:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/stop-24.png"_L1, QSize(24, 24));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/stop-32.png"_L1, QSize(32, 32));
- break;
- case SP_MediaPlay:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/media-play-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/media-play-32.png"_L1, QSize(32, 32));
- break;
- case SP_MediaPause:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/media-pause-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/media-pause-32.png"_L1, QSize(32, 32));
- break;
- case SP_MediaStop:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/media-stop-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/media-stop-32.png"_L1, QSize(32, 32));
- break;
- case SP_MediaSeekForward:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/media-seek-forward-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/media-seek-forward-32.png"_L1, QSize(32, 32));
- break;
- case SP_MediaSeekBackward:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/media-seek-backward-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/media-seek-backward-32.png"_L1, QSize(32, 32));
- break;
- case SP_MediaSkipForward:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/media-skip-forward-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/media-skip-forward-32.png"_L1, QSize(32, 32));
- break;
- case SP_MediaSkipBackward:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/media-skip-backward-16.png"_L1, QSize(16, 16));
- icon.addFile(":/qt-project.org/styles/commonstyle/images/media-skip-backward-32.png"_L1, QSize(32, 32));
- break;
- case SP_MediaVolume:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/media-volume-16.png"_L1, QSize(16, 16));
- break;
- case SP_MediaVolumeMuted:
- icon.addFile(":/qt-project.org/styles/commonstyle/images/media-volume-muted-16.png"_L1, QSize(16, 16));
- break;
- case SP_TitleBarCloseButton:
- addIconFiles(iconResourcePrefix() + QStringLiteral("closedock-"),
- dockTitleIconSizes, sizeof(dockTitleIconSizes)/sizeof(dockTitleIconSizes[0]), icon);
- break;
- case SP_TitleBarMenuButton:
+ switch (standardIcon) {
+ case QStyle::SP_MessageBoxInformation:
+ addIconFiles(u"information-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_MessageBoxWarning:
+ addIconFiles(u"warning-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_MessageBoxCritical:
+ addIconFiles(u"critical-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_MessageBoxQuestion:
+ addIconFiles(u"question-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_FileDialogStart:
+ addIconFiles(u"filedialog_start-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_FileDialogEnd:
+ addIconFiles(u"filedialog_end-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_TitleBarMinButton:
+ addIconFiles(u"titlebar-min-", titleBarSizes, icon);
+ break;
+ case QStyle::SP_TitleBarMaxButton:
+ addIconFiles(u"titlebar-max-", titleBarSizes, icon);
+ break;
+ case QStyle::SP_TitleBarShadeButton:
+ addIconFiles(u"titlebar-shade-", titleBarSizes, icon);
+ break;
+ case QStyle::SP_TitleBarUnshadeButton:
+ addIconFiles(u"titlebar-unshade-", titleBarSizes, icon);
+ break;
+ case QStyle::SP_TitleBarContextHelpButton:
+ addIconFiles(u"titlebar-contexthelp-", titleBarSizes, icon);
+ break;
+ case QStyle::SP_FileDialogNewFolder:
+ addIconFiles(u"newdirectory-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_FileDialogBack:
+ return q->proxy()->standardIcon(QStyle::SP_ArrowBack, option, widget);
+ case QStyle::SP_FileDialogToParent:
+ return q->proxy()->standardIcon(QStyle::SP_ArrowUp, option, widget);
+ case QStyle::SP_FileDialogDetailedView:
+ addIconFiles(u"viewdetailed-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_FileDialogInfoView:
+ addIconFiles(u"fileinfo-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_FileDialogContentsView:
+ addIconFiles(u"filecontents-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_FileDialogListView:
+ addIconFiles(u"viewlist-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_DialogOkButton:
+ addIconFiles(u"standardbutton-ok-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_DialogCancelButton:
+ addIconFiles(u"standardbutton-cancel-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_DialogHelpButton:
+ addIconFiles(u"standardbutton-help-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_DialogOpenButton:
+ addIconFiles(u"standardbutton-open-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_DialogSaveButton:
+ addIconFiles(u"standardbutton-save-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_DialogCloseButton:
+ addIconFiles(u"standardbutton-close-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_DialogApplyButton:
+ addIconFiles(u"standardbutton-apply-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_DialogResetButton:
+ addIconFiles(u"standardbutton-clear-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_DialogDiscardButton:
+ addIconFiles(u"standardbutton-delete-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_DialogYesButton:
+ addIconFiles(u"standardbutton-yes-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_DialogNoButton:
+ addIconFiles(u"standardbutton-no-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_CommandLink:
+ case QStyle::SP_ArrowForward:
+ return q->proxy()->standardIcon(rtl(option) ? QStyle::SP_ArrowLeft
+ : QStyle::SP_ArrowRight,
+ option, widget);
+ case QStyle::SP_ArrowBack:
+ return q->proxy()->standardIcon(rtl(option) ? QStyle::SP_ArrowRight
+ : QStyle::SP_ArrowLeft,
+ option, widget);
+ case QStyle::SP_ArrowLeft:
+ addIconFiles(u"left-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_ArrowRight:
+ addIconFiles(u"right-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_ArrowUp:
+ addIconFiles(u"up-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_ArrowDown:
+ addIconFiles(u"down-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_DirHomeIcon:
+ case QStyle::SP_DirIcon:
+ addIconFiles(u"dirclosed-", pngIconSizes, icon, QIcon::Normal, QIcon::Off);
+ addIconFiles(u"diropen-", pngIconSizes, icon, QIcon::Normal, QIcon::On);
+ break;
+ case QStyle::SP_DirOpenIcon:
+ addIconFiles(u"diropen-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_DirClosedIcon:
+ addIconFiles(u"dirclosed-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_DirLinkIcon:
+ addIconFiles(u"dirlink-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_DriveCDIcon:
+ addIconFiles(u"cdr-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_DriveFDIcon:
+ addIconFiles(u"floppy-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_DriveHDIcon:
+ addIconFiles(u"harddrive-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_DriveDVDIcon:
+ addIconFiles(u"dvd-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_DriveNetIcon:
+ addIconFiles(u"networkdrive-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_FileIcon:
+ addIconFiles(u"file-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_FileLinkIcon:
+ addIconFiles(u"filelink-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_DesktopIcon:
+ addIconFiles(u"desktop-", {16, 32}, icon);
+ break;
+ case QStyle::SP_TrashIcon:
+ addIconFiles(u"trash-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_ComputerIcon:
+ addIconFiles(u"computer-", {16, 32}, icon);
+ break;
+ case QStyle::SP_BrowserReload:
+ addIconFiles(u"refresh-", {24, 32}, icon);
+ break;
+ case QStyle::SP_BrowserStop:
+ addIconFiles(u"stop-", {24, 32}, icon);
+ break;
+ case QStyle::SP_MediaPlay:
+ addIconFiles(u"media-play-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_MediaPause:
+ addIconFiles(u"media-pause-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_MediaStop:
+ addIconFiles(u"media-stop-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_MediaSeekForward:
+ addIconFiles(u"media-seek-forward-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_MediaSeekBackward:
+ addIconFiles(u"media-seek-backward-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_MediaSkipForward:
+ addIconFiles(u"media-skip-forward-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_MediaSkipBackward:
+ addIconFiles(u"media-skip-backward-", pngIconSizes, icon);
+ break;
+ case QStyle::SP_MediaVolume:
+ addIconFiles(u"media-volume-", {16}, icon);
+ break;
+ case QStyle::SP_MediaVolumeMuted:
+ addIconFiles(u"media-volume-muted-", {16}, icon);
+ break;
+ case QStyle::SP_TitleBarCloseButton:
+ case QStyle::SP_DockWidgetCloseButton:
+ addIconFiles(u"closedock-", dockTitleIconSizes, icon);
+ break;
+ case QStyle::SP_TitleBarMenuButton:
# ifndef QT_NO_IMAGEFORMAT_XPM
icon.addPixmap(titleBarMenuCachedPixmapFromXPM());
# endif
icon.addFile(":/qt-project.org/qmessagebox/images/qtlogo-64.png"_L1);
break;
- case SP_TitleBarNormalButton:
- addIconFiles(iconResourcePrefix() + QStringLiteral("normalizedockup-"),
- dockTitleIconSizes, sizeof(dockTitleIconSizes)/sizeof(dockTitleIconSizes[0]), icon);
+ case QStyle::SP_TitleBarNormalButton:
+ addIconFiles(u"normalizedockup-", dockTitleIconSizes, icon);
break;
- case SP_ToolBarHorizontalExtensionButton: {
- QString prefix = iconResourcePrefix() + QStringLiteral("toolbar-ext-h-");
- if (rtl)
- prefix += QStringLiteral("rtl-");
- addIconFiles(prefix, toolBarExtHSizes, sizeof(toolBarExtHSizes)/sizeof(toolBarExtHSizes[0]), icon);
- }
+ case QStyle::SP_ToolBarHorizontalExtensionButton:
+ addIconFiles(rtl(option) ? u"toolbar-ext-h-rtl-" : u"toolbar-ext-h-", toolBarExtHSizes, icon);
+ break;
+ case QStyle::SP_ToolBarVerticalExtensionButton:
+ addIconFiles(u"toolbar-ext-v-", toolBarExtVSizes, icon);
+ break;
+ case QStyle::SP_TabCloseButton:
+ addIconFiles(u"standardbutton-closetab-", pngIconSizes, icon, QIcon::Normal, QIcon::Off);
+ addIconFiles(u"standardbutton-closetab-down-", pngIconSizes, icon, QIcon::Normal, QIcon::On);
+ addIconFiles(u"standardbutton-closetab-hover-", pngIconSizes, icon, QIcon::Active, QIcon::Off);
break;
- case SP_ToolBarVerticalExtensionButton:
- addIconFiles(iconResourcePrefix() + QStringLiteral("toolbar-ext-v-"),
- toolBarExtVSizes, sizeof(toolBarExtVSizes)/sizeof(toolBarExtVSizes[0]), icon);
- break;
- case SP_TabCloseButton:
- icon.addFile(iconResourcePrefix() + u"standardbutton-closetab-16.png", QSize(16, 16),
- QIcon::Normal, QIcon::Off);
- icon.addFile(iconResourcePrefix() + u"standardbutton-closetab-32.png", QSize(32, 32),
- QIcon::Normal, QIcon::Off);
- icon.addFile(iconResourcePrefix() + u"standardbutton-closetab-down-16.png", QSize(16, 16),
- QIcon::Normal, QIcon::On);
- icon.addFile(iconResourcePrefix() + u"standardbutton-closetab-down-32.png", QSize(32, 32),
- QIcon::Normal, QIcon::On);
- icon.addFile(iconResourcePrefix() + u"standardbutton-closetab-hover-16.png", QSize(16, 16),
- QIcon::Active, QIcon::Off);
- icon.addFile(iconResourcePrefix() + u"standardbutton-closetab-hover-32.png", QSize(32, 32),
- QIcon::Active, QIcon::Off);
+ case QStyle::SP_LineEditClearButton:
+ addIconFiles(u"cleartext-", pngIconSizes, icon);
+ break;
+ default:
break;
+ }
+#else // QT_NO_IMAGEFORMAT_PNG
+ Q_UNUSED(standardIcon);
+ Q_UNUSED(option);
+ Q_UNUSED(widget);
#endif // QT_NO_IMAGEFORMAT_PNG
+ return icon;
+}
+
+
+/*!
+ \internal
+*/
+QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option,
+ const QWidget *widget) const
+{
+ Q_D(const QCommonStyle);
+ QIcon icon;
+
+ icon = d->iconFromWindowsTheme(standardIcon, option, widget);
+ if (!icon.isNull())
+ return icon;
+
+ icon = d->iconFromApplicationTheme(standardIcon, option, widget);
+ if (!icon.isNull())
+ return icon;
+
+ icon = d->iconFromMacTheme(standardIcon, option, widget);
+ if (!icon.isNull())
+ return icon;
+
+ icon = d->iconFromResourceTheme(standardIcon, option, widget);
+ if (!icon.isNull())
+ return icon;
+
+#ifndef QT_NO_IMAGEFORMAT_XPM
+ switch (standardIcon) {
+ case QStyle::SP_TitleBarMenuButton:
+ icon.addPixmap(titleBarMenuCachedPixmapFromXPM());
+ break;
default:
- icon.addPixmap(proxy()->standardPixmap(standardIcon, option, widget));
break;
}
+ if (!icon.isNull())
+ return icon;
+#endif
+ icon = proxy()->standardPixmap(standardIcon, option, widget);
return icon;
}
@@ -6494,7 +6203,7 @@ QPixmap QCommonStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &p
}
}
- return QPixmap::fromImage(im);
+ return QPixmap::fromImage(std::move(im));
}
case QIcon::Selected: {
QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied);
@@ -6504,7 +6213,7 @@ QPixmap QCommonStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &p
painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
painter.fillRect(0, 0, img.width(), img.height(), color);
painter.end();
- return QPixmap::fromImage(img); }
+ return QPixmap::fromImage(std::move(img)); }
case QIcon::Active:
return pixmap;
default:
diff --git a/src/widgets/styles/qcommonstyle.h b/src/widgets/styles/qcommonstyle.h
index d6485c6015..40ed13d453 100644
--- a/src/widgets/styles/qcommonstyle.h
+++ b/src/widgets/styles/qcommonstyle.h
@@ -61,9 +61,6 @@ protected:
private:
Q_DECLARE_PRIVATE(QCommonStyle)
Q_DISABLE_COPY(QCommonStyle)
-#if QT_CONFIG(animation)
- Q_PRIVATE_SLOT(d_func(), void _q_removeAnimation())
-#endif
};
QT_END_NAMESPACE
diff --git a/src/widgets/styles/qcommonstyle_p.h b/src/widgets/styles/qcommonstyle_p.h
index bd35dd4cfc..2fa90a8949 100644
--- a/src/widgets/styles/qcommonstyle_p.h
+++ b/src/widgets/styles/qcommonstyle_p.h
@@ -92,13 +92,29 @@ public:
int animationFps;
#if QT_CONFIG(animation)
- void _q_removeAnimation();
-
- QList<const QObject*> animationTargets() const;
QStyleAnimation* animation(const QObject *target) const;
void startAnimation(QStyleAnimation *animation) const;
void stopAnimation(const QObject *target) const;
+ void removeAnimation(const QObject *target) const;
+#endif
+ QIcon iconFromWindowsTheme(QCommonStyle::StandardPixmap standardIcon,
+ const QStyleOption *option,
+ const QWidget *widget) const;
+ QIcon iconFromMacTheme(QCommonStyle::StandardPixmap standardIcon,
+ const QStyleOption *option,
+ const QWidget *widget) const;
+ QIcon iconFromApplicationTheme(QCommonStyle::StandardPixmap standardIcon,
+ const QStyleOption *option,
+ const QWidget *widget) const;
+ QIcon iconFromResourceTheme(QCommonStyle::StandardPixmap standardIcon,
+ const QStyleOption *option,
+ const QWidget *widget) const;
+ static bool inline rtl(const QStyleOption *option) {
+ return (option && option->direction == Qt::RightToLeft) ||
+ (!option && QGuiApplication::isRightToLeft());
+ }
+#if QT_CONFIG(animation)
private:
mutable QHash<const QObject*, QStyleAnimation*> animations;
#endif // animation
diff --git a/src/widgets/styles/qdrawutil.cpp b/src/widgets/styles/qdrawutil.cpp
index bfffeecb6b..5bdbdb1139 100644
--- a/src/widgets/styles/qdrawutil.cpp
+++ b/src/widgets/styles/qdrawutil.cpp
@@ -230,8 +230,8 @@ void qDrawShadeRect(QPainter *p, int x, int y, int w, int h,
p->scale(inverseScale, inverseScale);
x = qRound(devicePixelRatio * x);
y = qRound(devicePixelRatio * y);
- w = qRound(devicePixelRatio * w);
- h = qRound(devicePixelRatio * h);
+ w = devicePixelRatio * w;
+ h = devicePixelRatio * h;
lineWidth = qRound(devicePixelRatio * lineWidth);
midLineWidth = qRound(devicePixelRatio * midLineWidth);
p->translate(0.5, 0.5);
@@ -297,7 +297,6 @@ void qDrawShadeRect(QPainter *p, int x, int y, int w, int h,
p->setPen(oldPen); // restore pen
}
-
/*!
\fn void qDrawShadePanel(QPainter *painter, int x, int y, int width, int height,
const QPalette &palette, bool sunken,
@@ -346,8 +345,8 @@ void qDrawShadePanel(QPainter *p, int x, int y, int w, int h,
p->scale(inverseScale, inverseScale);
x = qRound(devicePixelRatio * x);
y = qRound(devicePixelRatio * y);
- w = qRound(devicePixelRatio * w);
- h = qRound(devicePixelRatio * h);
+ w = devicePixelRatio * w;
+ h = devicePixelRatio * h;
lineWidth = qRound(devicePixelRatio * lineWidth);
p->translate(0.5, 0.5);
isTranslated = true;
@@ -409,7 +408,6 @@ void qDrawShadePanel(QPainter *p, int x, int y, int w, int h,
p->setPen(oldPen); // restore pen
}
-
/*!
\internal
This function draws a rectangle with two pixel line width.
@@ -443,8 +441,8 @@ static void qDrawWinShades(QPainter *p,
p->scale(inverseScale, inverseScale);
x = qRound(devicePixelRatio * x);
y = qRound(devicePixelRatio * y);
- w = qRound(devicePixelRatio * w);
- h = qRound(devicePixelRatio * h);
+ w = devicePixelRatio * w;
+ h = devicePixelRatio * h;
p->translate(0.5, 0.5);
isTranslated = true;
}
@@ -590,8 +588,8 @@ void qDrawPlainRect(QPainter *p, int x, int y, int w, int h, const QColor &c,
p->scale(inverseScale, inverseScale);
x = qRound(devicePixelRatio * x);
y = qRound(devicePixelRatio * y);
- w = qRound(devicePixelRatio * w);
- h = qRound(devicePixelRatio * h);
+ w = devicePixelRatio * w;
+ h = devicePixelRatio * h;
lineWidth = qRound(devicePixelRatio * lineWidth);
p->translate(0.5, 0.5);
}
@@ -611,6 +609,74 @@ void qDrawPlainRect(QPainter *p, int x, int y, int w, int h, const QColor &c,
p->setBrush(oldBrush);
}
+/*!
+ \fn void qDrawPlainRoundedRect(QPainter *painter, int x, int y,
+ int width, int height, qreal rx, qreal ry,
+ const QColor &lineColor, int lineWidth,
+ const QBrush *fill)
+ \since 6.7
+ \relates <qdrawutil.h>
+
+ Draws the plain rounded rectangle beginning at (\a x, \a y)
+ with the given \a width and \a height,
+ using the horizontal \a rx and vertical radius \a ry,
+ specified \a painter, \a lineColor and \a lineWidth.
+ The rectangle's interior is filled with the \a
+ fill brush unless \a fill is \nullptr.
+
+ \warning This function does not look at QWidget::style() or
+ QApplication::style(). Use the drawing functions in QStyle to make
+ widgets that follow the current GUI style.
+
+ Alternatively you can use a QFrame widget and apply the
+ QFrame::setFrameStyle() function to display a plain rectangle:
+
+ \snippet code/src_gui_painting_qdrawutil.cpp 4
+
+ \sa qDrawShadeRect(), QStyle
+*/
+
+// ### Qt7: Pass QPen instead of QColor for frame drawing
+void qDrawPlainRoundedRect(QPainter *p, int x, int y, int w, int h,
+ qreal rx, qreal ry, const QColor &c,
+ int lineWidth, const QBrush *fill)
+{
+ if (w == 0 || h == 0)
+ return;
+ if (Q_UNLIKELY(w < 0 || h < 0 || lineWidth < 0)) {
+ qWarning("qDrawPlainRect: Invalid parameters");
+ }
+
+ PainterStateGuard painterGuard(p);
+ const qreal devicePixelRatio = p->device()->devicePixelRatio();
+ if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
+ painterGuard.save();
+ const qreal inverseScale = qreal(1) / devicePixelRatio;
+ p->scale(inverseScale, inverseScale);
+ x = qRound(devicePixelRatio * x);
+ y = qRound(devicePixelRatio * y);
+ w = devicePixelRatio * w;
+ h = devicePixelRatio * h;
+ lineWidth = qRound(devicePixelRatio * lineWidth);
+ p->translate(0.5, 0.5);
+ }
+
+ p->save();
+ p->setPen(c);
+ p->setBrush(Qt::NoBrush);
+ for (int i=0; i<lineWidth; i++) {
+ QRectF rect(x+i, y+i, w-i*2 - 1, h-i*2 - 1);
+ rect.marginsRemoved(QMarginsF(0.5,0.5,0.5,0.5));
+ p->drawRoundedRect(rect, rx, ry);
+ }
+ if (fill) { // fill with fill color
+ p->setPen(Qt::NoPen);
+ p->setBrush(*fill);
+ p->drawRoundedRect(x+lineWidth, y+lineWidth, w-lineWidth*2, h-lineWidth*2, rx, ry);
+ }
+ p->restore();
+}
+
/*****************************************************************************
Overloaded functions.
*****************************************************************************/
@@ -819,6 +885,32 @@ void qDrawPlainRect(QPainter *p, const QRect &r, const QColor &c,
lineWidth, fill);
}
+/*!
+ \fn void qDrawPlainRoundedRect(QPainter *painter, const QRect &rect,
+ qreal rx, qreal ry,
+ const QColor &lineColor, int lineWidth,
+ const QBrush *fill)
+ \since 6.7
+ \relates <qdrawutil.h>
+ \overload
+
+ Draws the plain rectangle specified by \a rect using
+ the horizontal \a rx and vertical radius \a ry,
+ the given \a painter, \a lineColor and \a lineWidth.
+ The rectangle's interior is filled with the
+ \a fill brush unless \a fill is \nullptr.
+
+ \warning This function does not look at QWidget::style() or
+ QApplication::style(). Use the drawing functions in QStyle to make
+ widgets that follow the current GUI style.
+
+ Alternatively you can use a QFrame widget and apply the
+ QFrame::setFrameStyle() function to display a plain rectangle:
+
+ \snippet code/src_gui_painting_qdrawutil.cpp 9
+
+ \sa qDrawShadeRect(), QStyle
+*/
/*!
\class QTileRules
diff --git a/src/widgets/styles/qdrawutil.h b/src/widgets/styles/qdrawutil.h
index 2fc957d493..26d8d5075f 100644
--- a/src/widgets/styles/qdrawutil.h
+++ b/src/widgets/styles/qdrawutil.h
@@ -71,6 +71,17 @@ Q_WIDGETS_EXPORT void qDrawPlainRect(QPainter *p, int x, int y, int w, int h, co
Q_WIDGETS_EXPORT void qDrawPlainRect(QPainter *p, const QRect &r, const QColor &,
int lineWidth = 1, const QBrush *fill = nullptr);
+Q_WIDGETS_EXPORT void qDrawPlainRoundedRect(QPainter *p, int x, int y, int w, int h,
+ qreal rx, qreal ry, const QColor &, int lineWidth = 1,
+ const QBrush *fill = nullptr);
+
+inline void qDrawPlainRoundedRect(QPainter *painter, const QRect& rect, qreal rx, qreal ry,
+ const QColor &lineColor, int lineWidth = 1,
+ const QBrush *fill = nullptr)
+{
+ qDrawPlainRoundedRect(painter, rect.x(), rect.y(), rect.width(), rect.height(),
+ rx, ry, lineColor, lineWidth, fill);
+}
struct QTileRules
diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp
index dccfbd8aac..34a0105b80 100644
--- a/src/widgets/styles/qfusionstyle.cpp
+++ b/src/widgets/styles/qfusionstyle.cpp
@@ -75,77 +75,6 @@ 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",
- " c None",
- ". c #D5CFCB",
- "+ c #8F8B88",
- "@ c #6C6A67",
- "# c #ABA6A3",
- "$ c #B5B0AC",
- "% c #A4A09D",
- " ",
- " +@@@@@@@+ ",
- "+# #+",
- "@ $@ @$ @",
- "@ @@@ @@@ @",
- "@ @@@@@ @",
- "@ @@@ @",
- "@ @@@@@ @",
- "@ @@@ @@@ @",
- "@ $@ @$ @",
- "+% #+",
- " +@@@@@@@+ ",
- " "};
-
-static const char * const dock_widget_restore_xpm[] = {
- "11 13 7 1",
- " c None",
- ". c #D5CFCB",
- "+ c #8F8B88",
- "@ c #6C6A67",
- "# c #ABA6A3",
- "$ c #B5B0AC",
- "% c #A4A09D",
- " ",
- " +@@@@@@@+ ",
- "+# #+",
- "@ #@@@# @",
- "@ @ @ @",
- "@ #@@@# @ @",
- "@ @ @ @ @",
- "@ @ @@@ @",
- "@ @ @ @",
- "@ #@@@# @",
- "+% #+",
- " +@@@@@@@+ ",
- " "};
-
-static const char * const workspace_minimize[] = {
- "11 13 7 1",
- " c None",
- ". c #D5CFCB",
- "+ c #8F8B88",
- "@ c #6C6A67",
- "# c #ABA6A3",
- "$ c #B5B0AC",
- "% c #A4A09D",
- " ",
- " +@@@@@@@+ ",
- "+# #+",
- "@ @",
- "@ @",
- "@ @",
- "@ @@@@@@@ @",
- "@ @@@@@@@ @",
- "@ @",
- "@ @",
- "+% #+",
- " +@@@@@@@+ ",
- " "};
-
-
static const char * const qt_titlebar_context_help[] = {
"10 10 3 1",
" c None",
@@ -216,6 +145,7 @@ static void qt_fusion_draw_arrow(Qt::ArrowType type, QPainter *painter, const QS
return;
const qreal dpi = QStyleHelper::dpi(option);
+ const qreal dpr = painter->device()->devicePixelRatio();
const int arrowWidth = int(QStyleHelper::dpiScaled(14, dpi));
const int arrowHeight = int(QStyleHelper::dpiScaled(8, dpi));
@@ -224,12 +154,12 @@ static void qt_fusion_draw_arrow(Qt::ArrowType type, QPainter *painter, const QS
const int size = qMin(arrowMax, rectMax);
QPixmap cachePixmap;
- QString cacheKey = QStyleHelper::uniqueName("fusion-arrow"_L1, option, rect.size())
- % HexString<uint>(type)
- % HexString<uint>(color.rgba());
+ const QString cacheKey = QStyleHelper::uniqueName("fusion-arrow"_L1
+ % HexString<uint>(type)
+ % HexString<uint>(color.rgba()),
+ option, rect.size(), dpr);
if (!QPixmapCache::find(cacheKey, &cachePixmap)) {
- cachePixmap = styleCachePixmap(rect.size());
- cachePixmap.fill(Qt::transparent);
+ cachePixmap = styleCachePixmap(rect.size(), dpr);
QPainter cachePainter(&cachePixmap);
QRectF arrowRect;
@@ -240,27 +170,26 @@ static void qt_fusion_draw_arrow(Qt::ArrowType type, QPainter *painter, const QS
arrowRect.moveTo((rect.width() - arrowRect.width()) / 2.0,
(rect.height() - arrowRect.height()) / 2.0);
- QPolygonF triangle;
- triangle.reserve(3);
+ std::array<QPointF, 3> triangle;
switch (type) {
case Qt::DownArrow:
- triangle << arrowRect.topLeft() << arrowRect.topRight() << QPointF(arrowRect.center().x(), arrowRect.bottom());
+ triangle = {arrowRect.topLeft(), arrowRect.topRight(), QPointF(arrowRect.center().x(), arrowRect.bottom())};
break;
case Qt::RightArrow:
- triangle << arrowRect.topLeft() << arrowRect.bottomLeft() << QPointF(arrowRect.right(), arrowRect.center().y());
+ triangle = {arrowRect.topLeft(), arrowRect.bottomLeft(), QPointF(arrowRect.right(), arrowRect.center().y())};
break;
case Qt::LeftArrow:
- triangle << arrowRect.topRight() << arrowRect.bottomRight() << QPointF(arrowRect.left(), arrowRect.center().y());
+ triangle = {arrowRect.topRight(), arrowRect.bottomRight(), QPointF(arrowRect.left(), arrowRect.center().y())};
break;
default:
- triangle << arrowRect.bottomLeft() << arrowRect.bottomRight() << QPointF(arrowRect.center().x(), arrowRect.top());
+ triangle = {arrowRect.bottomLeft(), arrowRect.bottomRight(), QPointF(arrowRect.center().x(), arrowRect.top())};
break;
}
cachePainter.setPen(Qt::NoPen);
cachePainter.setBrush(color);
cachePainter.setRenderHint(QPainter::Antialiasing);
- cachePainter.drawPolygon(triangle);
+ cachePainter.drawPolygon(triangle.data(), int(triangle.size()));
QPixmapCache::insert(cacheKey, cachePixmap);
}
@@ -375,37 +304,18 @@ QFusionStyle::~QFusionStyle()
}
/*!
- \fn void QFusionStyle::drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette,
- bool enabled, const QString& text, QPalette::ColorRole textRole) const
-
- Draws the given \a text in the specified \a rectangle using the
- provided \a painter and \a palette.
-
- Text is drawn using the painter's pen. If an explicit \a textRole
- is specified, then the text is drawn using the \a palette's color
- for the specified role. The \a enabled value indicates whether or
- not the item is enabled; when reimplementing, this value should
- influence how the item is drawn.
-
- The text is aligned and wrapped according to the specified \a
- alignment.
-
- \sa Qt::Alignment
+ \reimp
*/
void QFusionStyle::drawItemText(QPainter *painter, const QRect &rect, int alignment, const QPalette &pal,
bool enabled, const QString& text, QPalette::ColorRole textRole) const
{
+ Q_UNUSED(enabled);
if (text.isEmpty())
return;
QPen savedPen = painter->pen();
- if (textRole != QPalette::NoRole) {
+ if (textRole != QPalette::NoRole)
painter->setPen(QPen(pal.brush(textRole), savedPen.widthF()));
- }
- if (!enabled) {
- QPen pen = painter->pen();
- painter->setPen(pen);
- }
painter->drawText(rect, alignment, text);
painter->setPen(savedPen);
}
@@ -424,10 +334,10 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem,
QRect rect = option->rect;
int state = option->state;
- QColor outline = d->outline(option->palette);
- QColor highlightedOutline = d->highlightedOutline(option->palette);
+ const QColor outline = d->outline(option->palette);
+ const QColor highlightedOutline = d->highlightedOutline(option->palette);
- QColor tabFrameColor = d->tabFrameColor(option->palette);
+ const QColor tabFrameColor = d->tabFrameColor(option->palette);
switch (elem) {
@@ -436,16 +346,7 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem,
case PE_FrameGroupBox:
{
QPixmap pixmap(":/qt-project.org/styles/commonstyle/images/fusion_groupbox.png"_L1);
- int topMargin = 0;
- auto control = qobject_cast<const QGroupBox *>(widget);
- if (control && !control->isCheckable() && control->title().isEmpty()) {
- // Shrinking the topMargin if Not checkable AND title is empty
- topMargin = groupBoxTopMargin;
- } else {
- topMargin = qMax(pixelMetric(PM_ExclusiveIndicatorHeight), option->fontMetrics.height()) + groupBoxTopMargin;
- }
- QRect frame = option->rect.adjusted(0, topMargin, 0, 0);
- qDrawBorderPixmap(painter, frame, QMargins(6, 6, 6, 6), pixmap);
+ qDrawBorderPixmap(painter, option->rect, QMargins(6, 6, 6, 6), pixmap);
break;
}
#endif // QT_CONFIG(groupbox)
@@ -899,7 +800,7 @@ void QFusionStyle::drawPrimitive(PrimitiveElement elem,
if (isDefault)
buttonColor = mergedColors(buttonColor, highlightedOutline.lighter(130), 90);
- BEGIN_STYLE_PIXMAPCACHE(QStringLiteral("pushbutton-") + buttonColor.name(QColor::HexArgb))
+ BEGIN_STYLE_PIXMAPCACHE(u"pushbutton-" + buttonColor.name(QColor::HexArgb))
r = rect.adjusted(0, 1, -1, 0);
p->setRenderHint(QPainter::Antialiasing, true);
@@ -1224,7 +1125,7 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio
Qt::ElideRight, titleRect.width());
proxy()->drawItemText(painter,
titleRect,
- Qt::AlignLeft | Qt::AlignVCenter, dwOpt->palette,
+ Qt::AlignLeft | Qt::AlignVCenter | Qt::TextHideMnemonic, dwOpt->palette,
dwOpt->state & State_Enabled, titleText,
QPalette::WindowText);
}
@@ -1236,22 +1137,22 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio
// Draws the header in tables.
if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
const QStyleOptionHeaderV2 *headerV2 = qstyleoption_cast<const QStyleOptionHeaderV2 *>(option);
- QString pixmapName = QStyleHelper::uniqueName("headersection"_L1, option, option->rect.size());
- pixmapName += QString::number(- int(header->position));
- pixmapName += QString::number(- int(header->orientation));
- if (headerV2)
- pixmapName += QString::number(- int(headerV2->isSectionDragTarget));
-
+ const bool isSectionDragTarget = headerV2 ? headerV2->isSectionDragTarget : false;
+ const qreal dpr = painter->device()->devicePixelRatio();
+ const QString pixmapName = QStyleHelper::uniqueName("headersection-"_L1
+ % HexString(header->position)
+ % HexString(header->orientation)
+ % QLatin1Char(isSectionDragTarget ? '1' : '0'),
+ option, option->rect.size(), dpr);
QPixmap cache;
if (!QPixmapCache::find(pixmapName, &cache)) {
- cache = styleCachePixmap(rect.size());
- cache.fill(Qt::transparent);
+ cache = styleCachePixmap(rect.size(), dpr);
QRect pixmapRect(0, 0, rect.width(), rect.height());
QPainter cachePainter(&cache);
QColor buttonColor = d->buttonColor(option->palette);
QColor gradientStartColor = buttonColor.lighter(104);
QColor gradientStopColor = buttonColor.darker(102);
- if (headerV2 && headerV2->isSectionDragTarget) {
+ if (isSectionDragTarget) {
gradientStopColor = gradientStartColor.darker(130);
gradientStartColor = gradientStartColor.darker(130);
}
@@ -1318,36 +1219,39 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio
case CE_ProgressBarContents:
painter->save();
painter->setRenderHint(QPainter::Antialiasing, true);
- painter->translate(0.5, 0.5);
if (const QStyleOptionProgressBar *bar = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
- bool vertical = false;
- bool inverted = false;
- bool indeterminate = (bar->minimum == 0 && bar->maximum == 0);
- bool complete = bar->progress == bar->maximum;
-
- vertical = !(bar->state & QStyle::State_Horizontal);
- inverted = bar->invertedAppearance;
+ const auto indeterminate = (bar->minimum == 0 && bar->maximum == 0);
+ const auto complete = bar->progress == bar->maximum;
+ const auto vertical = !(bar->state & QStyle::State_Horizontal);
+ const auto inverted = bar->invertedAppearance;
+ const auto reverse = (bar->direction == Qt::RightToLeft) ^ inverted;
// If the orientation is vertical, we use a transform to rotate
- // the progress bar 90 degrees clockwise. This way we can use the
+ // the progress bar 90 degrees (counter)clockwise. This way we can use the
// same rendering code for both orientations.
if (vertical) {
rect = QRect(rect.left(), rect.top(), rect.height(), rect.width()); // flip width and height
- QTransform m = QTransform::fromTranslate(rect.height()-1, -1.0);
- m.rotate(90.0);
+ QTransform m;
+ if (inverted) {
+ m.rotate(90);
+ m.translate(0, -rect.height());
+ } else {
+ m.rotate(-90);
+ m.translate(-rect.width(), 0);
+ }
+ painter->setTransform(m, true);
+ } else if (reverse) {
+ QTransform m = QTransform::fromScale(-1, 1);
+ m.translate(-rect.width(), 0);
painter->setTransform(m, true);
}
+ painter->translate(0.5, 0.5);
- int maxWidth = rect.width();
const auto progress = qMax(bar->progress, bar->minimum); // workaround for bug in QProgressBar
const auto totalSteps = qMax(Q_INT64_C(1), qint64(bar->maximum) - bar->minimum);
const auto progressSteps = qint64(progress) - bar->minimum;
- const auto progressBarWidth = progressSteps * maxWidth / totalSteps;
- int width = indeterminate ? maxWidth : progressBarWidth;
-
- bool reverse = (!vertical && (bar->direction == Qt::RightToLeft)) || vertical;
- if (inverted)
- reverse = !reverse;
+ const auto progressBarWidth = progressSteps * rect.width() / totalSteps;
+ int width = indeterminate ? rect.width() : progressBarWidth;
int step = 0;
QRect progressBar;
@@ -1356,28 +1260,10 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio
if (qGray(outline.rgb()) > qGray(highlightedoutline.rgb()))
outline = highlightedoutline;
- if (!indeterminate) {
- QColor innerShadow(Qt::black);
- innerShadow.setAlpha(35);
- painter->setPen(innerShadow);
- if (!reverse) {
- progressBar.setRect(rect.left(), rect.top(), width - 1, rect.height() - 1);
- if (!complete) {
- painter->drawLine(progressBar.topRight() + QPoint(2, 1), progressBar.bottomRight() + QPoint(2, 0));
- painter->setPen(QPen(highlight.darker(140)));
- painter->drawLine(progressBar.topRight() + QPoint(1, 1), progressBar.bottomRight() + QPoint(1, 0));
- }
- } else {
- progressBar.setRect(rect.right() - width - 1, rect.top(), width + 2, rect.height() - 1);
- if (!complete) {
- painter->drawLine(progressBar.topLeft() + QPoint(-2, 1), progressBar.bottomLeft() + QPoint(-2, 0));
- painter->setPen(QPen(highlight.darker(140)));
- painter->drawLine(progressBar.topLeft() + QPoint(-1, 1), progressBar.bottomLeft() + QPoint(-1, 0));
- }
- }
- } else {
+ if (!indeterminate)
+ progressBar.setRect(rect.left(), rect.top(), width - 1, rect.height() - 1);
+ else
progressBar.setRect(rect.left(), rect.top(), rect.width() - 1, rect.height() - 1);
- }
if (indeterminate || bar->progress > bar->minimum) {
@@ -1392,10 +1278,13 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio
painter->setBrush(gradient);
painter->save();
+ // 0.5 - half the width of a cosmetic pen (for vertical line below)
if (!complete && !indeterminate)
- painter->setClipRect(progressBar.adjusted(-1, -1, -1, 1));
- QRect fillRect = progressBar.adjusted( !indeterminate && !complete && reverse ? -2 : 0, 0,
- indeterminate || complete || reverse ? 0 : 2, 0);
+ painter->setClipRect(QRectF(progressBar).adjusted(-1, -1, 0.5, 1));
+
+ QRect fillRect = progressBar;
+ if (!indeterminate && !complete)
+ fillRect.setWidth(std::min(fillRect.width() + 2, rect.width() - 1)); // avoid round borders at the right end
painter->drawRoundedRect(fillRect, 2, 2);
painter->restore();
@@ -1422,43 +1311,63 @@ void QFusionStyle::drawControl(ControlElement element, const QStyleOption *optio
x + rect.height() + step, progressBar.top() - 2);
}
}
+ if (!indeterminate && !complete) {
+ QColor innerShadow(Qt::black);
+ innerShadow.setAlpha(35);
+ painter->setPen(innerShadow);
+ painter->drawLine(progressBar.topRight() + QPoint(2, 1), progressBar.bottomRight() + QPoint(2, 0));
+ painter->setPen(QPen(highlight.darker(140)));
+ painter->drawLine(progressBar.topRight() + QPoint(1, 1), progressBar.bottomRight() + QPoint(1, 0));
+ }
}
painter->restore();
break;
case CE_ProgressBarLabel:
if (const QStyleOptionProgressBar *bar = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
- QRect leftRect;
QRect rect = bar->rect;
+ QRect leftRect = rect;
+ QRect rightRect = rect;
QColor textColor = option->palette.text().color();
QColor alternateTextColor = d->highlightedText(option->palette);
painter->save();
- bool vertical = false, inverted = false;
- vertical = !(bar->state & QStyle::State_Horizontal);
- inverted = bar->invertedAppearance;
- if (vertical)
- rect = QRect(rect.left(), rect.top(), rect.height(), rect.width()); // flip width and height
+ const auto vertical = !(bar->state & QStyle::State_Horizontal);
+ const auto inverted = bar->invertedAppearance;
+ const auto reverse = (bar->direction == Qt::RightToLeft) ^ inverted;
const auto totalSteps = qMax(Q_INT64_C(1), qint64(bar->maximum) - bar->minimum);
const auto progressSteps = qint64(bar->progress) - bar->minimum;
- const auto progressIndicatorPos = progressSteps * rect.width() / totalSteps;
- if (progressIndicatorPos >= 0 && progressIndicatorPos <= rect.width())
- leftRect = QRect(rect.left(), rect.top(), progressIndicatorPos, rect.height());
- if (vertical)
- leftRect.translate(rect.width() - progressIndicatorPos, 0);
-
- bool flip = (!vertical && (((bar->direction == Qt::RightToLeft) && !inverted) ||
- ((bar->direction == Qt::LeftToRight) && inverted)));
-
- QRegion rightRect = rect;
- rightRect = rightRect.subtracted(leftRect);
- painter->setClipRegion(rightRect);
- painter->setPen(flip ? alternateTextColor : textColor);
- painter->drawText(rect, bar->text, QTextOption(Qt::AlignAbsolute | Qt::AlignHCenter | Qt::AlignVCenter));
- if (!leftRect.isNull()) {
- painter->setPen(flip ? textColor : alternateTextColor);
- painter->setClipRect(leftRect);
- painter->drawText(rect, bar->text, QTextOption(Qt::AlignAbsolute | Qt::AlignHCenter | Qt::AlignVCenter));
+ const auto progressIndicatorPos = progressSteps * (vertical ? rect.height() : rect.width()) / totalSteps;
+
+ if (vertical) {
+ if (progressIndicatorPos >= 0 && progressIndicatorPos <= rect.height()) {
+ if (inverted) {
+ leftRect.setHeight(progressIndicatorPos);
+ rightRect.setY(progressIndicatorPos);
+ } else {
+ leftRect.setHeight(rect.height() - progressIndicatorPos);
+ rightRect.setY(rect.height() - progressIndicatorPos);
+ }
+ }
+ } else {
+ if (progressIndicatorPos >= 0 && progressIndicatorPos <= rect.width()) {
+ if (reverse) {
+ leftRect.setWidth(rect.width() - progressIndicatorPos);
+ rightRect.setX(rect.width() - progressIndicatorPos);
+ } else {
+ leftRect.setWidth(progressIndicatorPos);
+ rightRect.setX(progressIndicatorPos);
+ }
+ }
}
+
+ const auto firstIsAlternateColor = (vertical && !inverted) || (!vertical && reverse);
+ painter->setClipRect(rightRect);
+ painter->setPen(firstIsAlternateColor ? alternateTextColor : textColor);
+ painter->drawText(rect, bar->text, QTextOption(Qt::AlignAbsolute | Qt::AlignHCenter | Qt::AlignVCenter));
+ painter->setPen(firstIsAlternateColor ? textColor : alternateTextColor);
+ painter->setClipRect(leftRect);
+ painter->drawText(rect, bar->text, QTextOption(Qt::AlignAbsolute | Qt::AlignHCenter | Qt::AlignVCenter));
+
painter->restore();
}
break;
@@ -1919,7 +1828,23 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
frame.lineWidth = groupBox->lineWidth;
frame.midLineWidth = groupBox->midLineWidth;
frame.rect = proxy()->subControlRect(CC_GroupBox, option, SC_GroupBoxFrame, widget);
+ painter->save();
+ QRegion region(groupBox->rect);
+ if (!groupBox->text.isEmpty()) {
+ bool ltr = groupBox->direction == Qt::LeftToRight;
+ QRect finalRect;
+ if (groupBox->subControls & QStyle::SC_GroupBoxCheckBox) {
+ finalRect = checkBoxRect.united(textRect);
+ finalRect.adjust(ltr ? -4 : -2, 0, ltr ? 2 : 4, 0);
+ } else {
+ finalRect = textRect;
+ finalRect.adjust(-2, 0, 2, 0);
+ }
+ region -= finalRect.adjusted(0, 0, 0, 3 - textRect.height() / 2);
+ }
+ painter->setClipRegion(region);
proxy()->drawPrimitive(PE_FrameGroupBox, &frame, painter, widget);
+ painter->restore();
}
// Draw title
@@ -1954,12 +1879,12 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
#if QT_CONFIG(spinbox)
case CC_SpinBox:
if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
+ const qreal dpr = painter->device()->devicePixelRatio();
QPixmap cache;
- QString pixmapName = QStyleHelper::uniqueName("spinbox"_L1, spinBox, spinBox->rect.size());
+ QString pixmapName = QStyleHelper::uniqueName("spinbox"_L1, spinBox, spinBox->rect.size(), dpr);
if (!QPixmapCache::find(pixmapName, &cache)) {
- cache = styleCachePixmap(spinBox->rect.size());
- cache.fill(Qt::transparent);
+ cache = styleCachePixmap(spinBox->rect.size(), dpr);
QRect pixmapRect(0, 0, spinBox->rect.width(), spinBox->rect.height());
QRect rect = pixmapRect;
@@ -2044,9 +1969,9 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
// and a tiny rect painted in the corner.
cachePainter.setPen(outline);
if (spinBox->direction == Qt::RightToLeft)
- cachePainter.drawLine(upRect.right(), upRect.top() - 1, upRect.right(), downRect.bottom() + 1);
+ cachePainter.drawLine(QLineF(upRect.right(), upRect.top() - 0.5, upRect.right(), downRect.bottom() + 1.5));
else
- cachePainter.drawLine(upRect.left(), upRect.top() - 1, upRect.left(), downRect.bottom() + 1);
+ cachePainter.drawLine(QLineF(upRect.left(), upRect.top() - 0.5, upRect.left(), downRect.bottom() + 1.5));
}
if (upIsActive && sunken) {
@@ -2521,7 +2446,6 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
subtleEdge.setAlpha(40);
painter->setPen(subtleEdge);
painter->setBrush(Qt::NoBrush);
- painter->setClipRect(scrollBarGroove.adjusted(1, 0, -1, -3));
painter->drawRect(scrollBarGroove.adjusted(1, 0, -1, -1));
painter->restore();
}
@@ -2561,10 +2485,12 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
painter->setBrush(midColor2);
else if (option->state & State_MouseOver && scrollBar->activeSubControls & SC_ScrollBarSlider)
painter->setBrush(highlightedGradient);
- else
+ else if (!isDarkBg)
painter->setBrush(gradient);
+ else
+ painter->setBrush(midColor2);
- painter->drawRect(pixmapRect.adjusted(horizontal ? -1 : 0, horizontal ? 0 : -1, horizontal ? 0 : 1, horizontal ? 1 : 0));
+ painter->drawRect(pixmapRect.adjusted(horizontal ? -1 : 0, horizontal ? 0 : -1, horizontal ? 0 : -1, horizontal ? -1 : 0));
painter->setPen(d->innerContrastLine());
painter->drawRect(scrollBarSlider.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0, -1, -1));
@@ -2594,16 +2520,9 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
painter->drawRect(scrollBarSubLine.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0, 0, 0));
painter->setPen(QPen(alphaOutline));
if (option->state & State_Horizontal) {
- if (option->direction == Qt::RightToLeft) {
- pixmapRect.setLeft(scrollBarSubLine.left());
- painter->drawLine(pixmapRect.topLeft(), pixmapRect.bottomLeft());
- } else {
- pixmapRect.setRight(scrollBarSubLine.right());
- painter->drawLine(pixmapRect.topRight(), pixmapRect.bottomRight());
- }
+ painter->drawRect(scrollBarSubLine.adjusted(horizontal ? 0 : 1, 0, horizontal ? 1 : 0, horizontal ? -1 : 0));
} else {
- pixmapRect.setBottom(scrollBarSubLine.bottom());
- painter->drawLine(pixmapRect.bottomLeft(), pixmapRect.bottomRight());
+ painter->drawRect(scrollBarSubLine.adjusted(0, 0, horizontal ? 0 : -1, 0));
}
QRect upRect = scrollBarSubLine.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0, horizontal ? -2 : -1, horizontal ? -1 : -2);
@@ -2631,16 +2550,9 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
painter->drawRect(scrollBarAddLine.adjusted(horizontal ? 0 : 1, horizontal ? 1 : 0, 0, 0));
painter->setPen(QPen(alphaOutline, 1));
if (option->state & State_Horizontal) {
- if (option->direction == Qt::LeftToRight) {
- pixmapRect.setLeft(scrollBarAddLine.left());
- painter->drawLine(pixmapRect.topLeft(), pixmapRect.bottomLeft());
- } else {
- pixmapRect.setRight(scrollBarAddLine.right());
- painter->drawLine(pixmapRect.topRight(), pixmapRect.bottomRight());
- }
+ painter->drawRect(scrollBarAddLine.adjusted(horizontal ? -1 : 0, 0, horizontal ? -1 : 0, horizontal ? -1 : 0));
} else {
- pixmapRect.setTop(scrollBarAddLine.top());
- painter->drawLine(pixmapRect.topLeft(), pixmapRect.topRight());
+ painter->drawRect(scrollBarAddLine.adjusted(0, horizontal ? 0 : -1, horizontal ? 0 : -1, horizontal ? 0 : -1));
}
QRect downRect = scrollBarAddLine.adjusted(1, 1, -1, -1);
@@ -2656,7 +2568,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
}
painter->restore();
- break;;
+ break;
#endif // QT_CONFIG(slider)
case CC_ComboBox:
painter->save();
@@ -2664,20 +2576,16 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
bool hasFocus = option->state & State_HasFocus && option->state & State_KeyboardFocusChange;
bool sunken = comboBox->state & State_On; // play dead, if combobox has no items
bool isEnabled = (comboBox->state & State_Enabled);
+ const qreal dpr = painter->device()->devicePixelRatio();
QPixmap cache;
- QString pixmapName = QStyleHelper::uniqueName("combobox"_L1, option, comboBox->rect.size());
- if (sunken)
- pixmapName += "-sunken"_L1;
- if (comboBox->editable)
- pixmapName += "-editable"_L1;
- if (isEnabled)
- pixmapName += "-enabled"_L1;
- if (!comboBox->frame)
- pixmapName += "-frameless"_L1;
-
+ const QString pixmapName = QStyleHelper::uniqueName("combobox"_L1
+ % QLatin1StringView(sunken ? "-sunken" : "")
+ % QLatin1StringView(comboBox->editable ? "-editable" : "")
+ % QLatin1StringView(isEnabled ? "-enabled" : "")
+ % QLatin1StringView(!comboBox->frame ? "-frameless" : ""),
+ option, comboBox->rect.size(), dpr);
if (!QPixmapCache::find(pixmapName, &cache)) {
- cache = styleCachePixmap(comboBox->rect.size());
- cache.fill(Qt::transparent);
+ cache = styleCachePixmap(comboBox->rect.size(), dpr);
QPainter cachePainter(&cache);
QRect pixmapRect(0, 0, comboBox->rect.width(), comboBox->rect.height());
QStyleOptionComboBox comboBoxCopy = *comboBox;
@@ -2765,6 +2673,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
#if QT_CONFIG(slider)
case CC_Slider:
if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ const qreal dpr = painter->device()->devicePixelRatio();
QRect groove = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget);
QRect handle = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget);
@@ -2786,13 +2695,13 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
grooveColor.setHsv(buttonColor.hue(),
qMin(255, (int)(buttonColor.saturation())),
qMin(255, (int)(buttonColor.value()*0.9)));
- QString groovePixmapName = QStyleHelper::uniqueName("slider_groove"_L1, option, groove.size());
+ QString groovePixmapName = QStyleHelper::uniqueName("slider_groove"_L1, option,
+ groove.size(), dpr);
QRect pixmapRect(0, 0, groove.width(), groove.height());
// draw background groove
if (!QPixmapCache::find(groovePixmapName, &cache)) {
- cache = styleCachePixmap(pixmapRect.size());
- cache.fill(Qt::transparent);
+ cache = styleCachePixmap(pixmapRect.size(), dpr);
QPainter groovePainter(&cache);
groovePainter.setRenderHint(QPainter::Antialiasing, true);
groovePainter.translate(0.5, 0.5);
@@ -2817,10 +2726,10 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
// draw blue groove highlight
QRect clipRect;
- groovePixmapName += "_blue"_L1;
+ if (!groovePixmapName.isEmpty())
+ groovePixmapName += "_blue"_L1;
if (!QPixmapCache::find(groovePixmapName, &cache)) {
- cache = styleCachePixmap(pixmapRect.size());
- cache.fill(Qt::transparent);
+ cache = styleCachePixmap(pixmapRect.size(), dpr);
QPainter groovePainter(&cache);
QLinearGradient gradient;
if (horizontal) {
@@ -2833,13 +2742,13 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
}
QColor highlight = d->highlight(option->palette);
QColor highlightedoutline = highlight.darker(140);
- if (qGray(outline.rgb()) > qGray(highlightedoutline.rgb()))
- outline = highlightedoutline;
-
+ QColor grooveOutline = outline;
+ if (qGray(grooveOutline.rgb()) > qGray(highlightedoutline.rgb()))
+ grooveOutline = highlightedoutline;
groovePainter.setRenderHint(QPainter::Antialiasing, true);
groovePainter.translate(0.5, 0.5);
- groovePainter.setPen(QPen(outline));
+ groovePainter.setPen(QPen(grooveOutline));
gradient.setColorAt(0, activeHighlight);
gradient.setColorAt(1, activeHighlight.lighter(130));
groovePainter.setBrush(gradient);
@@ -2854,10 +2763,11 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
if (slider->upsideDown)
clipRect = QRect(handle.right(), groove.top(), groove.right() - handle.right(), groove.height());
else
- clipRect = QRect(groove.left(), groove.top(), handle.left(), groove.height());
+ clipRect = QRect(groove.left(), groove.top(),
+ handle.left() - slider->rect.left(), groove.height());
} else {
if (slider->upsideDown)
- clipRect = QRect(groove.left(), handle.bottom(), groove.width(), groove.height() - handle.bottom());
+ clipRect = QRect(groove.left(), handle.bottom(), groove.width(), groove.height() - (handle.bottom() - slider->rect.top()));
else
clipRect = QRect(groove.left(), groove.top(), groove.width(), handle.top() - groove.top());
}
@@ -2868,6 +2778,8 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
}
if (option->subControls & SC_SliderTickmarks) {
+ painter->save();
+ painter->translate(slider->rect.x(), slider->rect.y());
painter->setPen(outline);
int tickSize = proxy()->pixelMetric(PM_SliderTickmarkOffset, option, widget);
int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget);
@@ -2885,6 +2797,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
int v = slider->minimum;
int len = proxy()->pixelMetric(PM_SliderLength, slider, widget);
+ QVector<QLine> lines;
while (v <= slider->maximum + 1) {
if (v == slider->maximum + 1 && interval == 1)
break;
@@ -2898,21 +2811,21 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
if (horizontal) {
if (ticksAbove) {
- painter->drawLine(pos, slider->rect.top() + extra,
- pos, slider->rect.top() + tickSize);
+ lines += QLine(pos, slider->rect.top() + extra,
+ pos, slider->rect.top() + tickSize);
}
if (ticksBelow) {
- painter->drawLine(pos, slider->rect.bottom() - extra,
- pos, slider->rect.bottom() - tickSize);
+ lines += QLine(pos, slider->rect.bottom() - extra,
+ pos, slider->rect.bottom() - tickSize);
}
} else {
if (ticksAbove) {
- painter->drawLine(slider->rect.left() + extra, pos,
- slider->rect.left() + tickSize, pos);
+ lines += QLine(slider->rect.left() + extra, pos,
+ slider->rect.left() + tickSize, pos);
}
if (ticksBelow) {
- painter->drawLine(slider->rect.right() - extra, pos,
- slider->rect.right() - tickSize, pos);
+ lines += QLine(slider->rect.right() - extra, pos,
+ slider->rect.right() - tickSize, pos);
}
}
// in the case where maximum is max int
@@ -2921,13 +2834,15 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
break;
v = nextInterval;
}
+ painter->drawLines(lines);
+ painter->restore();
}
// draw handle
if ((option->subControls & SC_SliderHandle) ) {
- QString handlePixmapName = QStyleHelper::uniqueName("slider_handle"_L1, option, handle.size());
+ QString handlePixmapName = QStyleHelper::uniqueName("slider_handle"_L1, option,
+ handle.size(), dpr);
if (!QPixmapCache::find(handlePixmapName, &cache)) {
- cache = styleCachePixmap(handle.size());
- cache.fill(Qt::transparent);
+ cache = styleCachePixmap(handle.size(), dpr);
QRect pixmapRect(0, 0, handle.width(), handle.height());
QPainter handlePainter(&cache);
QRect gradRect = pixmapRect.adjusted(2, 2, -2, -2);
@@ -2941,7 +2856,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption
handlePainter.setPen(Qt::NoPen);
handlePainter.setBrush(QColor(0, 0, 0, 40));
- handlePainter.drawRect(r.adjusted(-1, 2, 1, -2));
+ handlePainter.drawRect(horizontal ? r.adjusted(-1, 2, 1, -2) : r.adjusted(2, -1, -2, 1));
handlePainter.setPen(QPen(d->outline(option->palette)));
if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange)
@@ -3011,7 +2926,6 @@ int QFusionStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, co
case PM_ListViewIconSize:
val = 24;
break;
- case PM_DialogButtonsSeparator:
case PM_ScrollBarSliderMin:
val = 26;
break;
@@ -3126,7 +3040,7 @@ QSize QFusionStyle::sizeFromContents(ContentsType type, const QStyleOption *opti
break;
case CT_GroupBox:
if (option) {
- int topMargin = qMax(pixelMetric(PM_ExclusiveIndicatorHeight), option->fontMetrics.height()) + groupBoxTopMargin;
+ int topMargin = qMax(pixelMetric(PM_IndicatorHeight, option, widget), option->fontMetrics.height()) + groupBoxTopMargin;
newSize += QSize(10, topMargin); // Add some space below the groupbox
}
break;
@@ -3308,23 +3222,28 @@ QRect QFusionStyle::subControlRect(ComplexControl control, const QStyleOptionCom
int tickSize = proxy()->pixelMetric(PM_SliderTickmarkOffset, option, widget);
switch (subControl) {
case SC_SliderHandle: {
+ const bool bothTicks = (slider->tickPosition & QSlider::TicksBothSides) == QSlider::TicksBothSides;
if (slider->orientation == Qt::Horizontal) {
- rect.setHeight(proxy()->pixelMetric(PM_SliderThickness, option));
- rect.setWidth(proxy()->pixelMetric(PM_SliderLength, option));
+ rect.setHeight(proxy()->pixelMetric(PM_SliderThickness, option, widget));
+ rect.setWidth(proxy()->pixelMetric(PM_SliderLength, option, widget));
int centerY = slider->rect.center().y() - rect.height() / 2;
- if (slider->tickPosition & QSlider::TicksAbove)
- centerY += tickSize;
- if (slider->tickPosition & QSlider::TicksBelow)
- centerY -= tickSize;
+ if (!bothTicks) {
+ if (slider->tickPosition & QSlider::TicksAbove)
+ centerY += tickSize;
+ if (slider->tickPosition & QSlider::TicksBelow)
+ centerY -= tickSize - 1;
+ }
rect.moveTop(centerY);
} else {
- rect.setWidth(proxy()->pixelMetric(PM_SliderThickness, option));
- rect.setHeight(proxy()->pixelMetric(PM_SliderLength, option));
+ rect.setWidth(proxy()->pixelMetric(PM_SliderThickness, option, widget));
+ rect.setHeight(proxy()->pixelMetric(PM_SliderLength, option, widget));
int centerX = slider->rect.center().x() - rect.width() / 2;
- if (slider->tickPosition & QSlider::TicksAbove)
- centerX += tickSize;
- if (slider->tickPosition & QSlider::TicksBelow)
- centerX -= tickSize;
+ if (!bothTicks) {
+ if (slider->tickPosition & QSlider::TicksAbove)
+ centerX += tickSize;
+ if (slider->tickPosition & QSlider::TicksBelow)
+ centerX -= tickSize - 1;
+ }
rect.moveLeft(centerX);
}
}
@@ -3332,18 +3251,23 @@ QRect QFusionStyle::subControlRect(ComplexControl control, const QStyleOptionCom
case SC_SliderGroove: {
QPoint grooveCenter = slider->rect.center();
const int grooveThickness = QStyleHelper::dpiScaled(7, option);
+ const bool bothTicks = (slider->tickPosition & QSlider::TicksBothSides) == QSlider::TicksBothSides;
if (slider->orientation == Qt::Horizontal) {
rect.setHeight(grooveThickness);
- if (slider->tickPosition & QSlider::TicksAbove)
- grooveCenter.ry() += tickSize;
- if (slider->tickPosition & QSlider::TicksBelow)
- grooveCenter.ry() -= tickSize;
+ if (!bothTicks) {
+ if (slider->tickPosition & QSlider::TicksAbove)
+ grooveCenter.ry() += tickSize;
+ if (slider->tickPosition & QSlider::TicksBelow)
+ grooveCenter.ry() -= tickSize - 1;
+ }
} else {
rect.setWidth(grooveThickness);
- if (slider->tickPosition & QSlider::TicksAbove)
- grooveCenter.rx() += tickSize;
- if (slider->tickPosition & QSlider::TicksBelow)
- grooveCenter.rx() -= tickSize;
+ if (!bothTicks) {
+ if (slider->tickPosition & QSlider::TicksAbove)
+ grooveCenter.rx() += tickSize;
+ if (slider->tickPosition & QSlider::TicksBelow)
+ grooveCenter.rx() -= tickSize - 1;
+ }
}
rect.moveCenter(grooveCenter);
break;
@@ -3386,6 +3310,7 @@ QRect QFusionStyle::subControlRect(ComplexControl control, const QStyleOptionCom
break;
case SC_SpinBoxFrame:
rect = spinbox->rect;
+ break;
default:
break;
}
@@ -3395,18 +3320,19 @@ QRect QFusionStyle::subControlRect(ComplexControl control, const QStyleOptionCom
#endif // QT_CONFIG(spinbox)
case CC_GroupBox:
if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(option)) {
- rect = option->rect;
+ const int groupBoxTextAlignment = groupBox->textAlignment;
+ const bool hasVerticalAlignment = (groupBoxTextAlignment & Qt::AlignVertical_Mask) == Qt::AlignVCenter;
+ const int fontMetricsHeight = groupBox->text.isEmpty() ? 0 : groupBox->fontMetrics.height();
+
if (subControl == SC_GroupBoxFrame)
- return rect.adjusted(0, 0, 0, 0);
+ return rect;
else if (subControl == SC_GroupBoxContents) {
QRect frameRect = option->rect.adjusted(0, 0, 0, -groupBoxBottomMargin);
int margin = 3;
int leftMarginExtension = 0;
- const int exclusiveIndicatorHeight = option->subControls.testFlag(SC_GroupBoxCheckBox) ?
- pixelMetric(PM_ExclusiveIndicatorHeight) : 0;
- const int fontMetricsHeight = groupBox->text.isEmpty() ? 0 :
- groupBox->fontMetrics.height();
- const int topMargin = qMax(exclusiveIndicatorHeight, fontMetricsHeight) +
+ const int indicatorHeight = option->subControls.testFlag(SC_GroupBoxCheckBox) ?
+ pixelMetric(PM_IndicatorHeight, option, widget) : 0;
+ const int topMargin = qMax(indicatorHeight, fontMetricsHeight) +
groupBoxTopMargin;
return frameRect.adjusted(leftMarginExtension + margin, margin + topMargin, -margin, -margin - groupBoxBottomMargin);
}
@@ -3421,12 +3347,17 @@ QRect QFusionStyle::subControlRect(ComplexControl control, const QStyleOptionCom
rect = QRect();
if (option->rect.width() > width) {
- switch (groupBox->textAlignment & Qt::AlignHorizontal_Mask) {
+ switch (groupBoxTextAlignment & Qt::AlignHorizontal_Mask) {
case Qt::AlignHCenter:
rect.moveLeft((option->rect.width() - width) / 2);
break;
case Qt::AlignRight:
- rect.moveLeft(option->rect.width() - width);
+ rect.moveLeft(option->rect.width() - width
+ - (hasVerticalAlignment ? proxy()->pixelMetric(PM_LayoutRightMargin, groupBox, widget) : 0));
+ break;
+ case Qt::AlignLeft:
+ if (hasVerticalAlignment)
+ rect.moveLeft(proxy()->pixelMetric(PM_LayoutLeftMargin, option, widget));
break;
}
}
@@ -3678,6 +3609,17 @@ int QFusionStyle::styleHint(StyleHint hint, const QStyleOption *option, const QW
mask->region -= QRect(option->rect.right() , option->rect.top() + 3, 1, 2);
return 1;
}
+ break;
+ case SH_GroupBox_TextLabelVerticalAlignment: {
+ if (const auto *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(option)) {
+ if (groupBox) {
+ const auto vAlign = groupBox->textAlignment & Qt::AlignVertical_Mask;
+ // default fusion style is AlignTop
+ return vAlign == 0 ? Qt::AlignTop : vAlign;
+ }
+ }
+ break;
+ }
default:
break;
}
@@ -3720,22 +3662,47 @@ QRect QFusionStyle::subElementRect(SubElement sr, const QStyleOption *opt, const
/*!
\reimp
*/
-QIcon QFusionStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option,
- const QWidget *widget) const
+QIcon QFusionStyle::iconFromTheme(StandardPixmap standardIcon) const
{
-#if QT_CONFIG(imageformat_xpm)
+ QIcon icon;
+#if QT_CONFIG(imageformat_png)
+ auto addIconFiles = [](QStringView prefix, QIcon &icon)
+ {
+ const auto fullPrefix = QStringLiteral(":/qt-project.org/styles/fusionstyle/images/") + prefix;
+ static constexpr auto dockTitleIconSizes = {10, 16, 20, 32, 48, 64};
+ for (int size : dockTitleIconSizes)
+ icon.addFile(fullPrefix + QString::number(size) + QStringLiteral(".png"),
+ QSize(size, size));
+ };
switch (standardIcon) {
case SP_TitleBarNormalButton:
- return QIcon(QPixmap(dock_widget_restore_xpm));
+ addIconFiles(u"fusion_normalizedockup-", icon);
+ break;
case SP_TitleBarMinButton:
- return QIcon(QPixmap(workspace_minimize));
+ addIconFiles(u"fusion_titlebar-min-", icon);
+ break;
case SP_TitleBarCloseButton:
case SP_DockWidgetCloseButton:
- return QIcon(QPixmap(dock_widget_close_xpm));
+ addIconFiles(u"fusion_closedock-", icon);
+ break;
default:
break;
}
-#endif // imageformat_xpm
+#else // imageformat_png
+ Q_UNUSED(standardIcon);
+#endif // imageformat_png
+ return icon;
+}
+
+/*!
+ \reimp
+*/
+QIcon QFusionStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option,
+ const QWidget *widget) const
+{
+ const auto icon = iconFromTheme(standardIcon);
+ if (!icon.availableSizes().isEmpty())
+ return icon;
return QCommonStyle::standardIcon(standardIcon, option, widget);
}
@@ -3745,21 +3712,13 @@ QIcon QFusionStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption
QPixmap QFusionStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt,
const QWidget *widget) const
{
-#ifndef QT_NO_IMAGEFORMAT_XPM
- switch (standardPixmap) {
- case SP_TitleBarNormalButton:
- return QPixmap(dock_widget_restore_xpm);
- case SP_TitleBarMinButton:
- return QPixmap(workspace_minimize);
- case SP_TitleBarCloseButton:
- case SP_DockWidgetCloseButton:
- return QPixmap(dock_widget_close_xpm);
-
- default:
- break;
- }
-#endif //QT_NO_IMAGEFORMAT_XPM
-
+ auto getDevicePixelRatio = [](const QWidget *widget)
+ {
+ return widget ? widget->devicePixelRatio() : qApp->devicePixelRatio();
+ };
+ const auto icon = iconFromTheme(standardPixmap);
+ if (!icon.availableSizes().isEmpty())
+ return icon.pixmap(QSize(16, 16), getDevicePixelRatio(widget));
return QCommonStyle::standardPixmap(standardPixmap, opt, widget);
}
diff --git a/src/widgets/styles/qfusionstyle_p.h b/src/widgets/styles/qfusionstyle_p.h
index d2a2e16b12..7dfeb34d7c 100644
--- a/src/widgets/styles/qfusionstyle_p.h
+++ b/src/widgets/styles/qfusionstyle_p.h
@@ -54,6 +54,7 @@ public:
int styleHint(StyleHint hint, const QStyleOption *option = nullptr, const QWidget *widget = nullptr,
QStyleHintReturn *returnData = nullptr) const override;
QRect itemPixmapRect(const QRect &r, int flags, const QPixmap &pixmap) const override;
+ QIcon iconFromTheme(StandardPixmap standardIcon) const;
QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option = nullptr,
const QWidget *widget = nullptr) const override;
QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt,
diff --git a/src/widgets/styles/qproxystyle_p.h b/src/widgets/styles/qproxystyle_p.h
index 1b9466bb17..6b686023a5 100644
--- a/src/widgets/styles/qproxystyle_p.h
+++ b/src/widgets/styles/qproxystyle_p.h
@@ -20,6 +20,8 @@
#include "qcommonstyle_p.h"
#include "qproxystyle.h"
+#include <QtCore/qpointer.h>
+
#ifndef QT_NO_STYLE_PROXY
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/styles/qstyle.cpp b/src/widgets/styles/qstyle.cpp
index 7352452487..60b2f51e95 100644
--- a/src/widgets/styles/qstyle.cpp
+++ b/src/widgets/styles/qstyle.cpp
@@ -249,9 +249,6 @@ static int unpackControlTypes(QSizePolicy::ControlTypes controls, QSizePolicy::C
widget is a QSpinBox just because the enum value is called
PE_IndicatorSpinUp or PE_IndicatorSpinDown.
- The documentation for the \l{widgets/styles}{Styles} example
- covers this topic in more detail.
-
\warning Qt style sheets are currently not supported for custom QStyle
subclasses. We plan to address this in some future release.
@@ -352,7 +349,7 @@ static int unpackControlTypes(QSizePolicy::ControlTypes controls, QSizePolicy::C
The drawing of item view headers is also done by the style, giving
control over size of header items and row and column sizes.
- \sa QStyleOption, QStylePainter, {Styles Example},
+ \sa QStyleOption, QStylePainter,
{Styles and Style Aware Widgets}, QStyledItemDelegate, {Styling}
*/
@@ -1497,8 +1494,7 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment,
Returns the value of the given pixel \a metric.
The specified \a option and \a widget can be used for calculating
- the metric. In general, the \a widget argument is not used. The \a
- option can be cast to the appropriate type using the
+ the metric. The \a option can be cast to the appropriate type using the
qstyleoption_cast() function. Note that the \a option may be zero
even for PixelMetrics that can make use of it. See the table below
for the appropriate \a option casts:
diff --git a/src/widgets/styles/qstyle.h b/src/widgets/styles/qstyle.h
index 23a5bd5ac2..198aea9557 100644
--- a/src/widgets/styles/qstyle.h
+++ b/src/widgets/styles/qstyle.h
@@ -464,11 +464,13 @@ public:
PM_ExclusiveIndicatorWidth,
PM_ExclusiveIndicatorHeight,
- PM_DialogButtonsSeparator,
- PM_DialogButtonsButtonWidth,
- PM_DialogButtonsButtonHeight,
+#if QT_DEPRECATED_SINCE(6, 8)
+ PM_DialogButtonsSeparator Q_DECL_ENUMERATOR_DEPRECATED_X("Not used and no effect since Qt 4"),
+ PM_DialogButtonsButtonWidth Q_DECL_ENUMERATOR_DEPRECATED_X("Not used and no effect since Qt 4"),
+ PM_DialogButtonsButtonHeight Q_DECL_ENUMERATOR_DEPRECATED_X("Not used and no effect since Qt 4"),
+#endif
- PM_MdiSubWindowFrameWidth,
+ PM_MdiSubWindowFrameWidth = 44,
PM_MdiSubWindowMinimizedWidth,
PM_HeaderMargin,
diff --git a/src/widgets/styles/qstyle_p.h b/src/widgets/styles/qstyle_p.h
index 5c1fd17130..59e87810c5 100644
--- a/src/widgets/styles/qstyle_p.h
+++ b/src/widgets/styles/qstyle_p.h
@@ -29,49 +29,36 @@ class QStylePrivate: public QObjectPrivate
{
Q_DECLARE_PUBLIC(QStyle)
public:
- inline QStylePrivate()
- : layoutSpacingIndex(-1), proxyStyle(nullptr) {}
-
static bool useFullScreenForPopup();
- mutable int layoutSpacingIndex;
QStyle *proxyStyle;
QString name;
};
-inline QImage styleCacheImage(const QSize &size)
-{
- const qreal pixelRatio = qApp->devicePixelRatio();
- QImage cacheImage = QImage(size * pixelRatio, QImage::Format_ARGB32_Premultiplied);
- cacheImage.setDevicePixelRatio(pixelRatio);
- return cacheImage;
-}
-
-inline QPixmap styleCachePixmap(const QSize &size)
+inline QPixmap styleCachePixmap(const QSize &size, qreal pixelRatio)
{
- const qreal pixelRatio = qApp->devicePixelRatio();
QPixmap cachePixmap = QPixmap(size * pixelRatio);
cachePixmap.setDevicePixelRatio(pixelRatio);
+ cachePixmap.fill(Qt::transparent);
return cachePixmap;
}
#define BEGIN_STYLE_PIXMAPCACHE(a) \
QRect rect = option->rect; \
QPixmap internalPixmapCache; \
- QImage imageCache; \
QPainter *p = painter; \
- QString unique = QStyleHelper::uniqueName((a), option, option->rect.size()); \
+ const auto dpr = p->device()->devicePixelRatio(); \
+ const QString unique = QStyleHelper::uniqueName((a), option, option->rect.size(), dpr); \
int txType = painter->deviceTransform().type() | painter->worldTransform().type(); \
- bool doPixmapCache = (!option->rect.isEmpty()) \
+ const bool doPixmapCache = (!option->rect.isEmpty()) \
&& ((txType <= QTransform::TxTranslate) || (painter->deviceTransform().type() == QTransform::TxScale)); \
if (doPixmapCache && QPixmapCache::find(unique, &internalPixmapCache)) { \
painter->drawPixmap(option->rect.topLeft(), internalPixmapCache); \
} else { \
if (doPixmapCache) { \
rect.setRect(0, 0, option->rect.width(), option->rect.height()); \
- imageCache = styleCacheImage(option->rect.size()); \
- imageCache.fill(0); \
- p = new QPainter(&imageCache); \
+ internalPixmapCache = styleCachePixmap(option->rect.size(), dpr); \
+ p = new QPainter(&internalPixmapCache); \
}
@@ -80,7 +67,6 @@ inline QPixmap styleCachePixmap(const QSize &size)
if (doPixmapCache) { \
p->end(); \
delete p; \
- internalPixmapCache = QPixmap::fromImage(imageCache); \
painter->drawPixmap(option->rect.topLeft(), internalPixmapCache); \
QPixmapCache::insert(unique, internalPixmapCache); \
} \
diff --git a/src/widgets/styles/qstyleanimation.cpp b/src/widgets/styles/qstyleanimation.cpp
index 32b77f1b53..8e71bb4fae 100644
--- a/src/widgets/styles/qstyleanimation.cpp
+++ b/src/widgets/styles/qstyleanimation.cpp
@@ -256,6 +256,7 @@ static QImage blendedImage(const QImage &start, const QImage &end, float alpha)
front_data += bpl;
}
}
+ break;
default:
break;
}
diff --git a/src/widgets/styles/qstylehelper.cpp b/src/widgets/styles/qstylehelper.cpp
index f79e83be61..02827de847 100644
--- a/src/widgets/styles/qstylehelper.cpp
+++ b/src/widgets/styles/qstylehelper.cpp
@@ -25,15 +25,26 @@ Q_GUI_EXPORT int qt_defaultDpiX();
namespace QStyleHelper {
-QString uniqueName(const QString &key, const QStyleOption *option, const QSize &size)
+static inline bool usePixmapCache(const QStyleOption *opt)
{
+ if (QWidget *widget = qobject_cast<QWidget *>(opt->styleObject))
+ return !widget->testAttribute(Qt::WA_StyleSheetTarget);
+ return true;
+}
+
+QString uniqueName(const QString &key, const QStyleOption *option, const QSize &size, qreal dpr)
+{
+ if (!usePixmapCache(option))
+ return {};
+
const QStyleOptionComplex *complexOption = qstyleoption_cast<const QStyleOptionComplex *>(option);
QString tmp = key % HexString<uint>(option->state)
% HexString<uint>(option->direction)
% HexString<uint>(complexOption ? uint(complexOption->activeSubControls) : 0u)
% HexString<quint64>(option->palette.cacheKey())
% HexString<uint>(size.width())
- % HexString<uint>(size.height());
+ % HexString<uint>(size.height())
+ % HexString<qreal>(dpr);
#if QT_CONFIG(spinbox)
if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
diff --git a/src/widgets/styles/qstylehelper_p.h b/src/widgets/styles/qstylehelper_p.h
index 524417e405..98470ad1ce 100644
--- a/src/widgets/styles/qstylehelper_p.h
+++ b/src/widgets/styles/qstylehelper_p.h
@@ -39,7 +39,7 @@ class QWindow;
namespace QStyleHelper
{
- QString uniqueName(const QString &key, const QStyleOption *option, const QSize &size);
+ QString uniqueName(const QString &key, const QStyleOption *option, const QSize &size, qreal dpr);
Q_WIDGETS_EXPORT qreal dpi(const QStyleOption *option);
diff --git a/src/widgets/styles/qstyleoption.cpp b/src/widgets/styles/qstyleoption.cpp
index de7cd482a3..d3a395246c 100644
--- a/src/widgets/styles/qstyleoption.cpp
+++ b/src/widgets/styles/qstyleoption.cpp
@@ -50,9 +50,6 @@ QT_BEGIN_NAMESPACE
The qstyleoption_cast() function will return 0 if the object to
which \c option points is not of the correct type.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyle, QStylePainter
*/
@@ -329,9 +326,6 @@ QStyleOption &QStyleOption::operator=(const QStyleOption &other)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption
*/
@@ -428,9 +422,6 @@ QStyleOptionFocusRect::QStyleOptionFocusRect(int version)
without breaking compatibility. If you use qstyleoption_cast(),
you normally do not need to check it.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption
*/
@@ -555,9 +546,6 @@ QStyleOptionFrame::QStyleOptionFrame(int version)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption, QStyleOptionComplex, QGroupBox
*/
@@ -688,9 +676,6 @@ QStyleOptionGroupBox::QStyleOptionGroupBox(int version)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption
*/
@@ -915,9 +900,6 @@ QStyleOptionHeaderV2::QStyleOptionHeaderV2(int version)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption, QStyleOptionToolButton
*/
@@ -1054,9 +1036,6 @@ QStyleOptionButton::QStyleOptionButton(int version)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption
*/
@@ -1238,9 +1217,6 @@ QStyleOptionToolBar::QStyleOptionToolBar(int version)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption
*/
@@ -1314,6 +1290,7 @@ QStyleOptionTab::QStyleOptionTab(int version)
\value Middle The tab is neither the first nor the last tab in the tab bar.
\value End The tab is the last tab in the tab bar.
\value OnlyOneTab The tab is both the first and the last tab in the tab bar.
+ \value [since 6.6] Moving The tab is moving by mouse drag or animation.
\sa position
*/
@@ -1365,7 +1342,7 @@ QStyleOptionTab::QStyleOptionTab(int version)
/*!
\variable QStyleOptionTab::shape
\brief the tab shape used to draw the tab; by default
- QTabBar::RoundedNorth
+ QTabBar::RoundedNorth.
\sa QTabBar::Shape
*/
@@ -1475,9 +1452,6 @@ QStyleOptionTab::QStyleOptionTab(int version)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption
*/
@@ -1583,7 +1557,7 @@ QStyleOptionProgressBar::QStyleOptionProgressBar(int version)
/*!
\variable QStyleOptionProgressBar::textAlignment
- \brief the text alignment for the text in the QProgressBar
+ \brief the text alignment for the text in the QProgressBar.
This can be used as a guide on where the text should be in the
progress bar. The default value is Qt::AlignLeft.
@@ -1636,9 +1610,6 @@ QStyleOptionProgressBar::QStyleOptionProgressBar(int version)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption
*/
@@ -1839,9 +1810,6 @@ QStyleOptionMenuItem::QStyleOptionMenuItem(int version)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption
*/
@@ -1932,9 +1900,6 @@ QStyleOptionComplex::QStyleOptionComplex(int version, int type)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOptionComplex, QSlider, QScrollBar
*/
@@ -2129,9 +2094,6 @@ QStyleOptionSlider::QStyleOptionSlider(int version)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption, QStyleOptionComplex
*/
@@ -2234,9 +2196,6 @@ QStyleOptionSpinBox::QStyleOptionSpinBox(int version)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption
*/
@@ -2340,9 +2299,6 @@ QStyleOptionDockWidget::QStyleOptionDockWidget(int version)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption, QStyleOptionComplex, QStyleOptionButton
*/
@@ -2504,9 +2460,6 @@ QStyleOptionToolButton::QStyleOptionToolButton(int version)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption, QStyleOptionComplex, QComboBox
*/
@@ -2640,9 +2593,6 @@ QStyleOptionComboBox::QStyleOptionComboBox(int version)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption, QToolBox
*/
@@ -2767,9 +2717,6 @@ QStyleOptionToolBox::QStyleOptionToolBox(int version)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption, QRubberBand
*/
@@ -2859,9 +2806,6 @@ QStyleOptionRubberBand::QStyleOptionRubberBand(int version)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption, QStyleOptionComplex, QMdiSubWindow
*/
@@ -2972,9 +2916,6 @@ QStyleOptionTitleBar::QStyleOptionTitleBar(int version)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption, {model-view-programming.html}{Model/View
Programming}
*/
@@ -3235,9 +3176,6 @@ QStyleOptionViewItem::QStyleOptionViewItem(int version)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption, QTabWidget
*/
@@ -3377,9 +3315,6 @@ QStyleOptionTabWidgetFrame::QStyleOptionTabWidgetFrame(int version)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption, QTabBar::drawBase()
*/
@@ -3487,9 +3422,6 @@ QStyleOptionTabBarBase::QStyleOptionTabBarBase(int version)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption, QStyleOptionComplex, QSizeGrip
*/
@@ -3567,9 +3499,6 @@ QStyleOptionSizeGrip::QStyleOptionSizeGrip(int version)
and emphasizes that these are simply parameters used by the style
functions.
- For an example demonstrating how style options can be used, see
- the \l {widgets/styles}{Styles} example.
-
\sa QStyleOption, QGraphicsItem::paint()
*/
diff --git a/src/widgets/styles/qstyleoption.h b/src/widgets/styles/qstyleoption.h
index c41256fe35..0e0118f6e9 100644
--- a/src/widgets/styles/qstyleoption.h
+++ b/src/widgets/styles/qstyleoption.h
@@ -193,6 +193,7 @@ protected:
QStyleOptionHeader(int version);
};
+// ### Qt7: merge with QStyleOptionHeader
class Q_WIDGETS_EXPORT QStyleOptionHeaderV2 : public QStyleOptionHeader
{
public:
@@ -243,7 +244,7 @@ public:
enum StyleOptionType { Type = SO_Tab };
enum StyleOptionVersion { Version = 1 };
- enum TabPosition { Beginning, Middle, End, OnlyOneTab };
+ enum TabPosition { Beginning, Middle, End, OnlyOneTab, Moving };
enum SelectedPosition { NotAdjacent, NextIsSelected, PreviousIsSelected };
enum CornerWidget { NoCornerWidgets = 0x00, LeftCornerWidget = 0x01,
RightCornerWidget = 0x02 };
diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp
index 70217127c3..655b224617 100644
--- a/src/widgets/styles/qstylesheetstyle.cpp
+++ b/src/widgets/styles/qstylesheetstyle.cpp
@@ -59,7 +59,7 @@
#include <private/qstyleanimation_p.h>
#endif
#if QT_CONFIG(tabbar)
-#include <qtabbar.h>
+#include <private/qtabbar_p.h>
#endif
#include <QMetaProperty>
#if QT_CONFIG(mainwindow)
@@ -138,8 +138,6 @@ class QStyleSheetStyleRecursionGuard
if (globalStyleSheetStyle != 0 && globalStyleSheetStyle != this) { RETURN; } \
QStyleSheetStyleRecursionGuard recursion_guard(this);
-#define ceil(x) ((int)(x) + ((x) > 0 && (x) != (int)(x)))
-
enum PseudoElement {
PseudoElement_None,
PseudoElement_DownArrow,
@@ -436,16 +434,26 @@ struct QStyleSheetBoxData : public QSharedData
struct QStyleSheetPaletteData : public QSharedData
{
- QStyleSheetPaletteData(const QBrush &fg, const QBrush &sfg, const QBrush &sbg,
- const QBrush &abg, const QBrush &pfg)
- : foreground(fg), selectionForeground(sfg), selectionBackground(sbg),
- alternateBackground(abg), placeholderForeground(pfg) { }
+ QStyleSheetPaletteData(const QBrush &foreground,
+ const QBrush &selectedForeground,
+ const QBrush &selectedBackground,
+ const QBrush &alternateBackground,
+ const QBrush &placeHolderTextForeground,
+ const QBrush &accent)
+ : foreground(foreground)
+ , selectionForeground(selectedForeground)
+ , selectionBackground(selectedBackground)
+ , alternateBackground(alternateBackground)
+ , placeholderForeground(placeHolderTextForeground)
+ , accent(accent)
+ { }
QBrush foreground;
QBrush selectionForeground;
QBrush selectionBackground;
QBrush alternateBackground;
QBrush placeholderForeground;
+ QBrush accent;
};
struct QStyleSheetGeometryData : public QSharedData
@@ -617,7 +625,7 @@ public:
Q_DECLARE_TYPEINFO(QRenderRule, Q_RELOCATABLE_TYPE);
///////////////////////////////////////////////////////////////////////////////////////////
-static const char knownStyleHints[][45] = {
+static constexpr std::array<const char*, 90> knownStyleHints = {
"activate-on-singleclick",
"alignment",
"arrow-keys-navigate-into-children",
@@ -710,13 +718,10 @@ static const char knownStyleHints[][45] = {
"widget-animation-duration"
};
-static const int numKnownStyleHints = sizeof(knownStyleHints)/sizeof(knownStyleHints[0]);
-
-static QList<QVariant> subControlLayout(const QString& layout)
+static QList<QVariant> subControlLayout(QByteArrayView layout)
{
QList<QVariant> buttons;
- for (int i = 0; i < layout.size(); i++) {
- int button = layout[i].toLatin1();
+ for (int button : layout) {
switch (button) {
case 'm':
buttons.append(PseudoElement_MdiMinButton);
@@ -778,10 +783,9 @@ QHash<QStyle::SubControl, QRect> QStyleSheetStyle::titleBarLayout(const QWidget
int offsets[3] = { 0, 0, 0 };
enum Where { Left, Right, Center, NoWhere } where = Left;
QList<ButtonInfo> infos;
- const int numLayouts = layout.size();
- infos.reserve(numLayouts);
- for (int i = 0; i < numLayouts; i++) {
- const int element = layout[i].toInt();
+ infos.reserve(layout.size());
+ for (const QVariant &val : std::as_const(layout)) {
+ const int element = val.toInt();
if (element == '(') {
where = Center;
} else if (element == ')') {
@@ -840,8 +844,7 @@ QHash<QStyle::SubControl, QRect> QStyleSheetStyle::titleBarLayout(const QWidget
}
}
- for (int i = 0; i < infos.size(); i++) {
- const ButtonInfo &info = infos[i];
+ for (const ButtonInfo &info : std::as_const(infos)) {
QRect lr = cr;
switch (info.where) {
case Center: {
@@ -957,10 +960,17 @@ QRenderRule::QRenderRule(const QList<Declaration> &declarations, const QObject *
bg = new QStyleSheetBackgroundData(brush, pixmap, repeat, alignment, origin, attachment, clip);
}
- QBrush sfg, fg, pfg;
- QBrush sbg, abg;
- if (v.extractPalette(&fg, &sfg, &sbg, &abg, &pfg))
- pal = new QStyleSheetPaletteData(fg, sfg, sbg, abg, pfg);
+ QBrush foreground;
+ QBrush selectedForeground;
+ QBrush selectedBackground;
+ QBrush alternateBackground;
+ QBrush placeHolderTextForeground;
+ QBrush accent;
+ if (v.extractPalette(&foreground, &selectedForeground, &selectedBackground,
+ &alternateBackground, &placeHolderTextForeground, &accent)) {
+ pal = new QStyleSheetPaletteData(foreground, selectedForeground, selectedBackground,
+ alternateBackground, placeHolderTextForeground, accent);
+ }
QIcon imgIcon;
alignment = Qt::AlignCenter;
@@ -1015,8 +1025,8 @@ QRenderRule::QRenderRule(const QList<Declaration> &declarations, const QObject *
// intentionally left blank...
} else if (decl.d->propertyId == UnknownProperty) {
bool knownStyleHint = false;
- for (int i = 0; i < numKnownStyleHints; i++) {
- QLatin1StringView styleHint(knownStyleHints[i]);
+ for (const auto sh : knownStyleHints) {
+ QLatin1StringView styleHint(sh);
if (decl.d->property.compare(styleHint) == 0) {
QString hintName = QString(styleHint);
QVariant hintValue;
@@ -1056,9 +1066,9 @@ QRenderRule::QRenderRule(const QList<Declaration> &declarations, const QObject *
}
} else if (hintName.endsWith("icon"_L1)) {
hintValue = decl.iconValue();
- } else if (hintName == "button-layout"_L1
- && decl.d->values.size() != 0 && decl.d->values.at(0).type == Value::String) {
- hintValue = subControlLayout(decl.d->values.at(0).variant.toString());
+ } else if (hintName == "button-layout"_L1 && decl.d->values.size() != 0
+ && decl.d->values.at(0).type == QCss::Value::String) {
+ hintValue = subControlLayout(decl.d->values.at(0).variant.toString().toLatin1());
} else {
int integer;
decl.intValue(&integer);
@@ -1450,6 +1460,16 @@ void QRenderRule::configurePalette(QPalette *p, QPalette::ColorRole fr, QPalette
p->setBrush(QPalette::AlternateBase, pal->alternateBackground);
}
+void setDefault(QPalette *palette, QPalette::ColorGroup group, QPalette::ColorRole role,
+ const QBrush &defaultBrush, const QWidget *widget)
+{
+ const QPalette &widgetPalette = widget->palette();
+ if (widgetPalette.isBrushSet(group, role))
+ palette->setBrush(group, role, widgetPalette.brush(group, role));
+ else
+ palette->setBrush(group, role, defaultBrush);
+}
+
void QRenderRule::configurePalette(QPalette *p, QPalette::ColorGroup cg, const QWidget *w, bool embedded)
{
if (bg && bg->brush.style() != Qt::NoBrush) {
@@ -1471,15 +1491,15 @@ void QRenderRule::configurePalette(QPalette *p, QPalette::ColorGroup cg, const Q
return;
if (pal->foreground.style() != Qt::NoBrush) {
- p->setBrush(cg, QPalette::ButtonText, pal->foreground);
- p->setBrush(cg, w->foregroundRole(), pal->foreground);
- p->setBrush(cg, QPalette::WindowText, pal->foreground);
- p->setBrush(cg, QPalette::Text, pal->foreground);
+ setDefault(p, cg, QPalette::ButtonText, pal->foreground, w);
+ setDefault(p, cg, w->foregroundRole(), pal->foreground, w);
+ setDefault(p, cg, QPalette::WindowText, pal->foreground, w);
+ setDefault(p, cg, QPalette::Text, pal->foreground, w);
QColor phColor(pal->foreground.color());
phColor.setAlpha((phColor.alpha() + 1) / 2);
QBrush placeholder = pal->foreground;
placeholder.setColor(phColor);
- p->setBrush(cg, QPalette::PlaceholderText, placeholder);
+ setDefault(p, cg, QPalette::PlaceholderText, placeholder, w);
}
if (pal->selectionBackground.style() != Qt::NoBrush)
p->setBrush(cg, QPalette::Highlight, pal->selectionBackground);
@@ -1489,6 +1509,8 @@ void QRenderRule::configurePalette(QPalette *p, QPalette::ColorGroup cg, const Q
p->setBrush(cg, QPalette::AlternateBase, pal->alternateBackground);
if (pal->placeholderForeground.style() != Qt::NoBrush)
p->setBrush(cg, QPalette::PlaceholderText, pal->placeholderForeground);
+ if (pal->accent.style() != Qt::NoBrush)
+ p->setBrush(cg, QPalette::Accent, pal->accent);
}
bool QRenderRule::hasModification() const
@@ -1654,7 +1676,8 @@ QList<QCss::StyleRule> QStyleSheetStyle::styleRules(const QObject *obj) const
defaultSs = getDefaultStyleSheet();
QStyle *bs = baseStyle();
styleSheetCaches->styleSheetCache.insert(bs, defaultSs);
- QObject::connect(bs, SIGNAL(destroyed(QObject*)), styleSheetCaches, SLOT(styleDestroyed(QObject*)), Qt::UniqueConnection);
+ QObject::connect(bs, &QStyle::destroyed, styleSheetCaches,
+ &QStyleSheetStyleCaches::styleDestroyed);
} else {
defaultSs = defaultCacheIt.value();
}
@@ -2877,7 +2900,9 @@ bool QStyleSheetStyle::initObject(const QObject *obj) const
const_cast<QWidget *>(w)->setAttribute(Qt::WA_StyleSheet, true);
}
- QObject::connect(obj, SIGNAL(destroyed(QObject*)), styleSheetCaches, SLOT(objectDestroyed(QObject*)), Qt::UniqueConnection);
+ connect(obj, &QObject::destroyed,
+ styleSheetCaches, &QStyleSheetStyleCaches::objectDestroyed,
+ Qt::UniqueConnection);
return true;
}
@@ -2921,10 +2946,10 @@ void QStyleSheetStyle::polish(QWidget *w)
QRenderRule rule = renderRule(sa, PseudoElement_None, PseudoClass_Enabled);
if ((rule.hasBorder() && rule.border()->hasBorderImage())
|| (rule.hasBackground() && !rule.background()->pixmap.isNull())) {
- QObject::connect(sa->horizontalScrollBar(), SIGNAL(valueChanged(int)),
- sa, SLOT(update()), Qt::UniqueConnection);
- QObject::connect(sa->verticalScrollBar(), SIGNAL(valueChanged(int)),
- sa, SLOT(update()), Qt::UniqueConnection);
+ connect(sa->horizontalScrollBar(), &QScrollBar::valueChanged,
+ sa, QOverload<>::of(&QAbstractScrollArea::update), Qt::UniqueConnection);
+ connect(sa->verticalScrollBar(), &QScrollBar::valueChanged,
+ sa, QOverload<>::of(&QAbstractScrollArea::update), Qt::UniqueConnection);
}
}
#endif
@@ -3027,13 +3052,13 @@ void QStyleSheetStyle::unpolish(QWidget *w)
setGeometry(w);
w->setAttribute(Qt::WA_StyleSheetTarget, false);
w->setAttribute(Qt::WA_StyleSheet, false);
- QObject::disconnect(w, nullptr, this, nullptr);
+ w->disconnect(this);
#if QT_CONFIG(scrollarea)
if (QAbstractScrollArea *sa = qobject_cast<QAbstractScrollArea *>(w)) {
- QObject::disconnect(sa->horizontalScrollBar(), SIGNAL(valueChanged(int)),
- sa, SLOT(update()));
- QObject::disconnect(sa->verticalScrollBar(), SIGNAL(valueChanged(int)),
- sa, SLOT(update()));
+ disconnect(sa->horizontalScrollBar(), &QScrollBar::valueChanged,
+ sa, QOverload<>::of(&QAbstractScrollArea::update));
+ disconnect(sa->verticalScrollBar(), &QScrollBar::valueChanged,
+ sa, QOverload<>::of(&QAbstractScrollArea::update));
}
#endif
baseStyle()->unpolish(w);
@@ -3049,16 +3074,6 @@ void QStyleSheetStyle::unpolish(QApplication *app)
styleSheetCaches->styleSheetCache.remove(qApp);
}
-#if QT_CONFIG(tabbar)
-inline static bool verticalTabs(QTabBar::Shape shape)
-{
- return shape == QTabBar::RoundedWest
- || shape == QTabBar::RoundedEast
- || shape == QTabBar::TriangularWest
- || shape == QTabBar::TriangularEast;
-}
-#endif // QT_CONFIG(tabbar)
-
void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p,
const QWidget *w) const
{
@@ -3488,12 +3503,12 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC
|| hasStyleRule(w, PseudoElement_MdiMinButton)) {
QList<QVariant> layout = rule.styleHint("button-layout"_L1).toList();
if (layout.isEmpty())
- layout = subControlLayout("mNX"_L1);
+ layout = subControlLayout("mNX");
QStyleOptionComplex optCopy(*opt);
optCopy.subControls = { };
- for (int i = 0; i < layout.size(); i++) {
- int layoutButton = layout[i].toInt();
+ for (const QVariant &val : std::as_const(layout)) {
+ int layoutButton = val.toInt();
if (layoutButton < PseudoElement_MdiCloseButton
|| layoutButton > PseudoElement_MdiNormalButton)
continue;
@@ -3524,6 +3539,7 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC
break;
subRule.drawRule(p, opt->rect);
QHash<QStyle::SubControl, QRect> layout = titleBarLayout(w, tb);
+ const auto paintDeviceDpr = p->device()->devicePixelRatio();
QRect ir;
ir = layout[SC_TitleBarLabel];
@@ -3534,8 +3550,6 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC
p->drawText(ir.x(), ir.y(), ir.width(), ir.height(), Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, tb->text);
}
- QPixmap pm;
-
ir = layout[SC_TitleBarSysMenu];
if (ir.isValid()) {
QRenderRule subSubRule = renderRule(w, opt, PseudoElement_TitleBarSysMenu);
@@ -3545,7 +3559,9 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC
tb->icon.paint(p, ir);
} else {
int iconSize = pixelMetric(PM_SmallIconSize, tb, w);
- pm = standardIcon(SP_TitleBarMenuButton, nullptr, w).pixmap(iconSize, iconSize);
+ const QSize sz(iconSize, iconSize);
+ const auto pm = standardIcon(SP_TitleBarMenuButton, nullptr, w)
+ .pixmap(sz, paintDeviceDpr);
drawItemPixmap(p, ir, Qt::AlignCenter, pm);
}
}
@@ -3555,15 +3571,14 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC
QRenderRule subSubRule = renderRule(w, opt, PseudoElement_TitleBarCloseButton);
subSubRule.drawRule(p, ir);
- QSize sz = subSubRule.contentsRect(ir).size();
- if ((tb->titleBarFlags & Qt::WindowType_Mask) == Qt::Tool)
- pm = standardIcon(SP_DockWidgetCloseButton, nullptr, w).pixmap(sz);
- else
- pm = standardIcon(SP_TitleBarCloseButton, nullptr, w).pixmap(sz);
+ const QSize sz = subSubRule.contentsRect(ir).size();
+ const auto type = ((tb->titleBarFlags & Qt::WindowType_Mask) == Qt::Tool)
+ ? SP_DockWidgetCloseButton : SP_TitleBarCloseButton;
+ const auto pm = standardIcon(type, nullptr, w).pixmap(sz, paintDeviceDpr);
drawItemPixmap(p, ir, Qt::AlignCenter, pm);
}
- int pes[] = {
+ constexpr std::array<int, 6> pes = {
PseudoElement_TitleBarMaxButton,
PseudoElement_TitleBarMinButton,
PseudoElement_TitleBarNormalButton,
@@ -3572,15 +3587,15 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC
PseudoElement_TitleBarContextHelpButton
};
- for (unsigned int i = 0; i < sizeof(pes)/sizeof(int); i++) {
- int pe = pes[i];
+ for (int pe : pes) {
QStyle::SubControl sc = knownPseudoElements[pe].subControl;
ir = layout[sc];
if (!ir.isValid())
continue;
QRenderRule subSubRule = renderRule(w, opt, pe);
subSubRule.drawRule(p, ir);
- pm = standardIcon(subControlIcon(pe), nullptr, w).pixmap(subSubRule.contentsRect(ir).size());
+ const QSize sz = subSubRule.contentsRect(ir).size();
+ const auto pm = standardIcon(subControlIcon(pe), nullptr, w).pixmap(sz, paintDeviceDpr);
drawItemPixmap(p, ir, Qt::AlignCenter, pm);
}
@@ -3603,7 +3618,9 @@ void QStyleSheetStyle::renderMenuItemIcon(const QStyleOptionMenuItem *mi, QPaint
? (mi->state & QStyle::State_Selected ? QIcon::Active : QIcon::Normal)
: QIcon::Disabled;
const bool checked = mi->checkType != QStyleOptionMenuItem::NotCheckable && mi->checked;
- const QPixmap pixmap(mi->icon.pixmap(pixelMetric(PM_SmallIconSize), mode,
+ const auto iconSize = pixelMetric(PM_SmallIconSize, mi, w);
+ const QSize sz(iconSize, iconSize);
+ const QPixmap pixmap(mi->icon.pixmap(sz, p->device()->devicePixelRatio(), mode,
checked ? QIcon::On : QIcon::Off));
const int pixw = pixmap.width() / pixmap.devicePixelRatio();
const int pixh = pixmap.height() / pixmap.devicePixelRatio();
@@ -3738,7 +3755,8 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q
if (button->state & State_On)
state = QIcon::On;
- QPixmap pixmap = icon.pixmap(button->iconSize, mode, state);
+ const auto paintDeviceDpr = p->device()->devicePixelRatio();
+ QPixmap pixmap = icon.pixmap(button->iconSize, paintDeviceDpr, mode, state);
int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio();
int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio();
int labelWidth = pixmapWidth;
@@ -4040,7 +4058,8 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q
if (spacing == -1)
spacing = 6;
QIcon::Mode mode = cb->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
- QPixmap pixmap = cb->currentIcon.pixmap(cb->iconSize, mode);
+ const auto paintDeviceDpr = p->device()->devicePixelRatio();
+ QPixmap pixmap = cb->currentIcon.pixmap(cb->iconSize, paintDeviceDpr, mode);
QRect iconRect(editRect);
iconRect.setWidth(cb->iconSize.width());
iconRect = alignedRect(cb->direction,
@@ -4101,15 +4120,22 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q
case CE_HeaderLabel:
if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
- QStyleOptionHeader hdr(*header);
+ QStyleOptionHeaderV2 hdr;
+ QStyleOptionHeader &v1Copy = hdr;
+ if (auto v2 = qstyleoption_cast<const QStyleOptionHeaderV2 *>(opt))
+ hdr = *v2;
+ else
+ v1Copy = *header;
QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewSection);
if (hasStyleRule(w, PseudoElement_HeaderViewUpArrow)
|| hasStyleRule(w, PseudoElement_HeaderViewDownArrow)) {
- const QRect arrowRect = subElementRect(SE_HeaderArrow, opt, w);
- if (hdr.orientation == Qt::Horizontal)
- hdr.rect.setWidth(hdr.rect.width() - arrowRect.width());
- else
- hdr.rect.setHeight(hdr.rect.height() - arrowRect.height());
+ if (hdr.sortIndicator != QStyleOptionHeader::None) {
+ const QRect arrowRect = subElementRect(SE_HeaderArrow, opt, w);
+ if (hdr.orientation == Qt::Horizontal)
+ hdr.rect.setWidth(hdr.rect.width() - arrowRect.width());
+ else
+ hdr.rect.setHeight(hdr.rect.height() - arrowRect.height());
+ }
}
subRule.configurePalette(&hdr.palette, QPalette::ButtonText, QPalette::Button);
if (subRule.hasFont) {
@@ -4209,6 +4235,7 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q
--chunkCount;
};
} else if (chunkWidth > 0) {
+ const auto ceil = [](qreal x) { return int(x) + (x > 0 && x != int(x)); };
const int chunkCount = ceil(qreal(fillWidth)/chunkWidth);
int x = reverse ? r.left() + r.width() - chunkWidth : r.x();
@@ -4249,12 +4276,11 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q
if (rule.hasDrawable()) {
rule.drawFrame(p, opt->rect);
p->save();
- switch (sgOpt->corner) {
- case Qt::BottomRightCorner: break;
- case Qt::BottomLeftCorner: p->rotate(90); break;
- case Qt::TopLeftCorner: p->rotate(180); break;
- case Qt::TopRightCorner: p->rotate(270); break;
- default: break;
+ static constexpr int rotation[] = { 180, 270, 90, 0 };
+ if (rotation[sgOpt->corner]) {
+ p->translate(opt->rect.center());
+ p->rotate(rotation[sgOpt->corner]);
+ p->translate(-opt->rect.center());
}
rule.drawImage(p, opt->rect);
p->restore();
@@ -4357,19 +4383,23 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q
vopt->state & QStyle::State_Selected
? QPalette::Highlight
: QPalette::Base);
- // only draw the indicator; no text or background
+ // only draw the indicator; no text, icon or background
optIndicator.backgroundBrush = Qt::NoBrush; // no background
optIndicator.text.clear();
+ optIndicator.icon = QIcon();
QWindowsStyle::drawControl(ce, &optIndicator, p, w);
- // Now draw text, background, and highlight, but not the indicator with the
- // base style. Since we can't turn off HasCheckIndicator to prevent the base
+
+ // Now draw text, background,icon, and highlight, but not the indicator with
+ // the base style. Since we can't turn off HasCheckIndicator to prevent the base
// style from drawing the check indicator again (it would change how the item
// gets laid out) we have to clip the indicator that's already been painted.
- const QRect checkRect = subElementRect(QStyle::SE_ItemViewItemCheckIndicator,
- &optIndicator, w);
+ const QRect crStyle = subElementRect(QStyle::SE_ItemViewItemCheckIndicator,
+ &optIndicator, w);
+ const QRect crBase = baseStyle()->subElementRect(QStyle::SE_ItemViewItemCheckIndicator,
+ &optIndicator, w);
const QRegion clipRegion = QRegion(p->hasClipping() ? p->clipRegion()
: QRegion(optIndicator.rect))
- - checkRect;
+ - crStyle.united(crBase);
p->setClipRegion(clipRegion);
}
subRule.configurePalette(&optCopy.palette, QPalette::Text, QPalette::NoRole);
@@ -4458,7 +4488,7 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q
QString titleText = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, r.width());
drawItemText(p, r,
- alignment, dwOpt->palette,
+ alignment | Qt::TextHideMnemonic, dwOpt->palette,
dwOpt->state & State_Enabled, titleText,
QPalette::WindowText);
@@ -4843,6 +4873,7 @@ void QStyleSheetStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *op
w = w->parentWidget(); //match on the QTabBar instead of the CloseButton
}
pseudoElement = PseudoElement_TabBarTabCloseButton;
+ break;
#endif
default:
@@ -5470,11 +5501,11 @@ QSize QStyleSheetStyle::sizeFromContents(ContentsType ct, const QStyleOption *op
QList<QVariant> layout = rule.styleHint("button-layout"_L1).toList();
if (layout.isEmpty())
- layout = subControlLayout("mNX"_L1);
+ layout = subControlLayout("mNX");
int width = 0, height = 0;
- for (int i = 0; i < layout.size(); i++) {
- int layoutButton = layout[i].toInt();
+ for (const QVariant &val : std::as_const(layout)) {
+ int layoutButton = val.toInt();
if (layoutButton < PseudoElement_MdiCloseButton
|| layoutButton > PseudoElement_MdiNormalButton)
continue;
@@ -5601,7 +5632,8 @@ QPixmap QStyleSheetStyle::standardPixmap(StandardPixmap standardPixmap, const QS
QRenderRule rule = renderRule(w, opt);
if (rule.hasStyleHint(s)) {
QIcon icon = qvariant_cast<QIcon>(rule.styleHint(s));
- return icon.pixmap(16, 16); // ###: unhard-code this if someone complains
+ const auto dpr = w ? w->devicePixelRatio() : qApp->devicePixelRatio();
+ return icon.pixmap(QSize(16, 16), dpr);
}
}
return baseStyle()->standardPixmap(standardPixmap, opt, w);
@@ -6036,12 +6068,12 @@ QRect QStyleSheetStyle::subControlRect(ComplexControl cc, const QStyleOptionComp
|| hasStyleRule(w, PseudoElement_MdiMinButton)) {
QList<QVariant> layout = rule.styleHint("button-layout"_L1).toList();
if (layout.isEmpty())
- layout = subControlLayout("mNX"_L1);
+ layout = subControlLayout("mNX");
int x = 0, width = 0;
QRenderRule subRule;
- for (int i = 0; i < layout.size(); i++) {
- int layoutButton = layout[i].toInt();
+ for (const QVariant &val : std::as_const(layout)) {
+ int layoutButton = val.toInt();
if (layoutButton < PseudoElement_MdiCloseButton
|| layoutButton > PseudoElement_MdiNormalButton)
continue;
@@ -6197,8 +6229,22 @@ QRect QStyleSheetStyle::subElementRect(SubElement se, const QStyleOption *opt, c
case SE_HeaderLabel: {
QRenderRule subRule = renderRule(w, opt, PseudoElement_HeaderViewSection);
- if (subRule.hasBox() || !subRule.hasNativeBorder())
- return subRule.contentsRect(opt->rect);
+ if (subRule.hasBox() || !subRule.hasNativeBorder()) {
+ auto r = subRule.contentsRect(opt->rect);
+ if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
+ // Subtract width needed for arrow, if there is one
+ if (header->sortIndicator != QStyleOptionHeader::None) {
+ const auto arrowRect = subElementRect(SE_HeaderArrow, opt, w);
+ if (arrowRect.isValid()) {
+ if (opt->state & State_Horizontal)
+ r.setWidth(r.width() - arrowRect.width());
+ else
+ r.setHeight(r.height() - arrowRect.height());
+ }
+ }
+ }
+ return r;
+ }
}
break;
@@ -6466,6 +6512,9 @@ bool QStyleSheetStyle::isNaturalChild(const QObject *obj)
QPixmap QStyleSheetStyle::loadPixmap(const QString &fileName, const QObject *context)
{
+ if (fileName.isEmpty())
+ return {};
+
qreal ratio = -1.0;
if (const QWidget *widget = qobject_cast<const QWidget *>(context)) {
if (QScreen *screen = QApplication::screenAt(widget->mapToGlobal(QPoint(0, 0))))
diff --git a/src/widgets/styles/qstylesheetstyle_default.cpp b/src/widgets/styles/qstylesheetstyle_default.cpp
index b665ab17cf..6356835ff4 100644
--- a/src/widgets/styles/qstylesheetstyle_default.cpp
+++ b/src/widgets/styles/qstylesheetstyle_default.cpp
@@ -122,7 +122,8 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const
// pixmap based style doesn't support any features
bool styleIsPixmapBased = baseStyle()->inherits("QMacStyle")
- || baseStyle()->inherits("QWindowsVistaStyle");
+ || (baseStyle()->inherits("QWindowsVistaStyle")
+ && !baseStyle()->inherits("QWindows11Style"));
/*QLineEdit {
@@ -136,15 +137,15 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const
ADD_SELECTOR;
SET_PROPERTY("-qt-background-role"_L1, QtBackgroundRole);
- ADD_VALUE(Value::KnownIdentifier, Value_Base);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_Base);
ADD_DECLARATION;
SET_PROPERTY("border"_L1, Border);
- ADD_VALUE(Value::KnownIdentifier, Value_Native);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_Native);
ADD_DECLARATION;
SET_PROPERTY("-qt-style-features"_L1, QtStyleFeatures);
- ADD_VALUE(Value::Identifier, QString::fromLatin1("background-color"));
+ ADD_VALUE(QCss::Value::Identifier, QString::fromLatin1("background-color"));
ADD_DECLARATION;
ADD_STYLE_RULE;
@@ -160,7 +161,7 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const
ADD_SELECTOR;
SET_PROPERTY("border"_L1, Border);
- ADD_VALUE(Value::KnownIdentifier, Value_None);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_None);
ADD_DECLARATION;
ADD_STYLE_RULE;
@@ -175,7 +176,7 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const
ADD_SELECTOR;
SET_PROPERTY("border"_L1, Border);
- ADD_VALUE(Value::KnownIdentifier, Value_Native);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_Native);
ADD_DECLARATION;
ADD_STYLE_RULE;
@@ -195,11 +196,11 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const
ADD_SELECTOR;
SET_PROPERTY("background"_L1, Background);
- ADD_VALUE(Value::KnownIdentifier, Value_None);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_None);
ADD_DECLARATION;
SET_PROPERTY("border-image"_L1, BorderImage);
- ADD_VALUE(Value::KnownIdentifier, Value_None);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_None);
ADD_DECLARATION;
ADD_STYLE_RULE;
@@ -214,7 +215,7 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const
ADD_SELECTOR;
SET_PROPERTY("border"_L1, Border);
- ADD_VALUE(Value::KnownIdentifier, Value_Native);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_Native);
ADD_DECLARATION;
ADD_STYLE_RULE;
@@ -231,11 +232,11 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const
ADD_SELECTOR;
SET_PROPERTY("-qt-background-role"_L1, QtBackgroundRole);
- ADD_VALUE(Value::KnownIdentifier, Value_Window);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_Window);
ADD_DECLARATION;
SET_PROPERTY("border"_L1, Border);
- ADD_VALUE(Value::KnownIdentifier, Value_Native);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_Native);
ADD_DECLARATION;
ADD_STYLE_RULE;
@@ -255,12 +256,12 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const
ADD_SELECTOR;
SET_PROPERTY("border-style"_L1, BorderStyles);
- ADD_VALUE(Value::KnownIdentifier, Value_Native);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_Native);
ADD_DECLARATION;
if (!styleIsPixmapBased) {
SET_PROPERTY("-qt-style-features"_L1, QtStyleFeatures);
- ADD_VALUE(Value::Identifier, QString::fromLatin1("background-color"));
+ ADD_VALUE(QCss::Value::Identifier, QString::fromLatin1("background-color"));
ADD_DECLARATION;
}
@@ -281,18 +282,18 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const
ADD_SELECTOR;
SET_PROPERTY("border"_L1, Border);
- ADD_VALUE(Value::KnownIdentifier, Value_Native);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_Native);
ADD_DECLARATION;
if (!styleIsPixmapBased) {
SET_PROPERTY("-qt-style-features"_L1, QtStyleFeatures);
- ADD_VALUE(Value::Identifier, QString::fromLatin1("background-color"));
- ADD_VALUE(Value::Identifier, QString::fromLatin1("background-gradient"));
+ ADD_VALUE(QCss::Value::Identifier, QString::fromLatin1("background-color"));
+ ADD_VALUE(QCss::Value::Identifier, QString::fromLatin1("background-gradient"));
ADD_DECLARATION;
}
SET_PROPERTY("-qt-background-role"_L1, QtBackgroundRole);
- ADD_VALUE(Value::KnownIdentifier, Value_Base);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_Base);
ADD_DECLARATION;
ADD_STYLE_RULE;
@@ -312,7 +313,7 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const
ADD_SELECTOR;
SET_PROPERTY("-qt-background-role"_L1, QtBackgroundRole);
- ADD_VALUE(Value::KnownIdentifier, Value_Button);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_Button);
ADD_DECLARATION;
ADD_STYLE_RULE;
@@ -329,15 +330,15 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const
ADD_SELECTOR;
SET_PROPERTY("border"_L1, Border);
- ADD_VALUE(Value::KnownIdentifier, Value_Native);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_Native);
ADD_DECLARATION;
SET_PROPERTY("-qt-style-features"_L1, QtStyleFeatures);
- ADD_VALUE(Value::Identifier, QString::fromLatin1("background-color"));
+ ADD_VALUE(QCss::Value::Identifier, QString::fromLatin1("background-color"));
ADD_DECLARATION;
SET_PROPERTY("-qt-background-role"_L1, QtBackgroundRole);
- ADD_VALUE(Value::KnownIdentifier, Value_Base);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_Base);
ADD_DECLARATION;
ADD_STYLE_RULE;
@@ -352,7 +353,7 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const
ADD_SELECTOR;
SET_PROPERTY("-qt-background-role"_L1, QtBackgroundRole);
- ADD_VALUE(Value::KnownIdentifier, Value_Window);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_Window);
ADD_DECLARATION;
ADD_STYLE_RULE;
@@ -367,7 +368,7 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const
ADD_SELECTOR;
SET_PROPERTY("-qt-style-features"_L1, QtStyleFeatures);
- ADD_VALUE(Value::Identifier, QString::fromLatin1("background-color"));
+ ADD_VALUE(QCss::Value::Identifier, QString::fromLatin1("background-color"));
ADD_DECLARATION;
ADD_STYLE_RULE;
@@ -382,7 +383,7 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const
ADD_SELECTOR;
SET_PROPERTY("-qt-background-role"_L1, QtBackgroundRole);
- ADD_VALUE(Value::KnownIdentifier, Value_Window);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_Window);
ADD_DECLARATION;
ADD_STYLE_RULE;
@@ -405,17 +406,17 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const
ADD_SELECTOR;
SET_PROPERTY("-qt-background-role"_L1, QtBackgroundRole);
- ADD_VALUE(Value::KnownIdentifier, Value_Button);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_Button);
ADD_DECLARATION;
if (!styleIsPixmapBased) {
SET_PROPERTY("-qt-style-features"_L1, QtStyleFeatures);
- ADD_VALUE(Value::Identifier, QString::fromLatin1("background-color"));
+ ADD_VALUE(QCss::Value::Identifier, QString::fromLatin1("background-color"));
ADD_DECLARATION;
}
SET_PROPERTY("border"_L1, Border);
- ADD_VALUE(Value::KnownIdentifier, Value_Native);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_Native);
ADD_DECLARATION;
ADD_STYLE_RULE;
@@ -430,7 +431,7 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const
ADD_SELECTOR;
SET_PROPERTY("-qt-background-role"_L1, QtBackgroundRole);
- ADD_VALUE(Value::KnownIdentifier, Value_Base);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_Base);
ADD_DECLARATION;
ADD_STYLE_RULE;
@@ -445,7 +446,7 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const
ADD_SELECTOR;
SET_PROPERTY("-qt-background-role"_L1, QtBackgroundRole);
- ADD_VALUE(Value::KnownIdentifier, Value_Window);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_Window);
ADD_DECLARATION;
ADD_STYLE_RULE;
@@ -460,7 +461,7 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const
ADD_SELECTOR;
SET_PROPERTY("border"_L1, Border);
- ADD_VALUE(Value::KnownIdentifier, Value_Native);
+ ADD_VALUE(QCss::Value::KnownIdentifier, Value_Native);
ADD_DECLARATION;
ADD_STYLE_RULE;
diff --git a/src/widgets/styles/qwindowsstyle.cpp b/src/widgets/styles/qwindowsstyle.cpp
index e48e17ed3b..bae182b467 100644
--- a/src/widgets/styles/qwindowsstyle.cpp
+++ b/src/widgets/styles/qwindowsstyle.cpp
@@ -88,11 +88,6 @@ enum QSliderDirection { SlUp, SlDown, SlLeft, SlRight };
QWindowsStylePrivate::QWindowsStylePrivate() = default;
-qreal QWindowsStylePrivate::appDevicePixelRatio()
-{
- return qApp->devicePixelRatio();
-}
-
// Returns \c true if the toplevel parent of \a widget has seen the Alt-key
bool QWindowsStylePrivate::hasSeenAlt(const QWidget *widget) const
{
@@ -117,19 +112,20 @@ bool QWindowsStyle::eventFilter(QObject *o, QEvent *e)
widget = widget->window();
// Alt has been pressed - find all widgets that care
- QList<QWidget *> l = widget->findChildren<QWidget *>();
+ const QList<QWidget *> children = widget->findChildren<QWidget *>();
auto ignorable = [](QWidget *w) {
return w->isWindow() || !w->isVisible()
|| w->style()->styleHint(SH_UnderlineShortcut, nullptr, w);
};
- l.removeIf(ignorable);
// Update states before repainting
d->seenAlt.append(widget);
d->alt_down = true;
// Repaint all relevant widgets
- for (int pos = 0; pos < l.size(); ++pos)
- l.at(pos)->update();
+ for (QWidget *w : children) {
+ if (!ignorable(w))
+ w->update();
+ }
}
break;
case QEvent::KeyRelease:
@@ -139,9 +135,9 @@ bool QWindowsStyle::eventFilter(QObject *o, QEvent *e)
// Update state and repaint the menu bars.
d->alt_down = false;
#if QT_CONFIG(menubar)
- QList<QMenuBar *> l = widget->findChildren<QMenuBar *>();
- for (int i = 0; i < l.size(); ++i)
- l.at(i)->update();
+ const QList<QMenuBar *> menuBars = widget->findChildren<QMenuBar *>();
+ for (QWidget *w : menuBars)
+ w->update();
#endif
}
break;
@@ -261,28 +257,33 @@ void QWindowsStyle::polish(QPalette &pal)
int QWindowsStylePrivate::pixelMetricFromSystemDp(QStyle::PixelMetric pm, const QStyleOption *, const QWidget *widget)
{
#if defined(Q_OS_WIN)
+ // The pixel metrics are in device indepentent pixels;
+ // hardcode DPI to 1x 96 DPI.
+ const int dpi = 96;
+
switch (pm) {
case QStyle::PM_DockWidgetFrameWidth:
- return GetSystemMetrics(SM_CXFRAME);
-
- case QStyle::PM_TitleBarHeight:
- if (widget && (widget->windowType() == Qt::Tool)) {
- // MS always use one less than they say
- return GetSystemMetrics(SM_CYSMCAPTION) - 1;
- }
- return GetSystemMetrics(SM_CYCAPTION) - 1;
+ return GetSystemMetricsForDpi(SM_CXFRAME, dpi);
+
+ case QStyle::PM_TitleBarHeight: {
+ const int resizeBorderThickness =
+ GetSystemMetricsForDpi(SM_CXSIZEFRAME, dpi) + GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
+ if (widget && (widget->windowType() == Qt::Tool))
+ return GetSystemMetricsForDpi(SM_CYSMCAPTION, dpi) + resizeBorderThickness;
+ return GetSystemMetricsForDpi(SM_CYCAPTION, dpi) + resizeBorderThickness;
+ }
case QStyle::PM_ScrollBarExtent:
{
NONCLIENTMETRICS ncm;
- ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONT);
- if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0))
+ ncm.cbSize = sizeof(NONCLIENTMETRICS);
+ if (SystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0, dpi))
return qMax(ncm.iScrollHeight, ncm.iScrollWidth);
}
break;
case QStyle::PM_MdiSubWindowFrameWidth:
- return GetSystemMetrics(SM_CYFRAME);
+ return GetSystemMetricsForDpi(SM_CYFRAME, dpi);
default:
break;
@@ -354,25 +355,10 @@ static QScreen *screenOf(const QWidget *w)
}
// Calculate the overall scale factor to obtain Qt Device Independent
-// Pixels from a native Windows size. Divide by devicePixelRatio
-// and account for secondary screens with differing logical DPI.
+// Pixels from a native Windows size.
qreal QWindowsStylePrivate::nativeMetricScaleFactor(const QWidget *widget)
{
- const QPlatformScreen *screen = screenOf(widget)->handle();
- const qreal scale = screen ? (screen->logicalDpi().first / screen->logicalBaseDpi().first)
- : QWindowsStylePrivate::appDevicePixelRatio();
- qreal result = qreal(1) / scale;
- if (QGuiApplicationPrivate::screen_list.size() > 1) {
- const QScreen *primaryScreen = QGuiApplication::primaryScreen();
- const QScreen *screen = screenOf(widget);
- if (screen != primaryScreen) {
- const qreal primaryLogicalDpi = primaryScreen->handle()->logicalDpi().first;
- const qreal logicalDpi = screen->handle()->logicalDpi().first;
- if (!qFuzzyCompare(primaryLogicalDpi, logicalDpi))
- result *= logicalDpi / primaryLogicalDpi;
- }
- }
- return result;
+ return qreal(1) / QHighDpiScaling::factor(screenOf(widget));
}
/*!
@@ -382,7 +368,7 @@ int QWindowsStyle::pixelMetric(PixelMetric pm, const QStyleOption *opt, const QW
{
int ret = QWindowsStylePrivate::pixelMetricFromSystemDp(pm, opt, widget);
if (ret != QWindowsStylePrivate::InvalidMetric)
- return qRound(qreal(ret) * QWindowsStylePrivate::nativeMetricScaleFactor(widget));
+ return ret;
ret = QWindowsStylePrivate::fixedPixelMetric(pm);
if (ret != QWindowsStylePrivate::InvalidMetric)
@@ -392,7 +378,7 @@ int QWindowsStyle::pixelMetric(PixelMetric pm, const QStyleOption *opt, const QW
switch (pm) {
case PM_MaximumDragDistance:
- ret = QCommonStyle::pixelMetric(PM_MaximumDragDistance);
+ ret = QCommonStyle::pixelMetric(PM_MaximumDragDistance, opt, widget);
if (ret == -1)
ret = 60;
break;
@@ -449,46 +435,6 @@ int QWindowsStyle::pixelMetric(PixelMetric pm, const QStyleOption *opt, const QW
QPixmap QWindowsStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt,
const QWidget *widget) const
{
-#if defined(Q_OS_WIN)
- QPixmap desktopIcon;
- switch(standardPixmap) {
- case SP_DriveCDIcon:
- case SP_DriveDVDIcon:
- case SP_DriveNetIcon:
- case SP_DriveHDIcon:
- case SP_DriveFDIcon:
- case SP_FileIcon:
- case SP_FileLinkIcon:
- case SP_DirLinkIcon:
- case SP_DirClosedIcon:
- case SP_DesktopIcon:
- case SP_ComputerIcon:
- case SP_DirOpenIcon:
- case SP_FileDialogNewFolder:
- case SP_DirHomeIcon:
- case SP_TrashIcon:
- case SP_VistaShield:
- if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
- QPlatformTheme::StandardPixmap sp = static_cast<QPlatformTheme::StandardPixmap>(standardPixmap);
- desktopIcon = theme->standardPixmap(sp, QSizeF(16, 16));
- }
- break;
- case SP_MessageBoxInformation:
- case SP_MessageBoxWarning:
- case SP_MessageBoxCritical:
- case SP_MessageBoxQuestion:
- if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
- QPlatformTheme::StandardPixmap sp = static_cast<QPlatformTheme::StandardPixmap>(standardPixmap);
- desktopIcon = theme->standardPixmap(sp, QSizeF());
- }
- break;
- default:
- break;
- }
- if (!desktopIcon.isNull()) {
- return desktopIcon;
- }
-#endif // Q_OS_WIN
return QCommonStyle::standardPixmap(standardPixmap, opt, widget);
}
@@ -810,7 +756,7 @@ void QWindowsStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt,
}
#endif // QT_CONFIG(itemviews)
if (!(opt->state & State_Off)) {
- QPointF points[6];
+ std::array<QPointF, 6> points;
qreal scaleh = opt->rect.width() / 12.0;
qreal scalev = opt->rect.height() / 12.0;
points[0] = { opt->rect.x() + qreal(3.5) * scaleh, opt->rect.y() + qreal(5.5) * scalev };
@@ -821,7 +767,7 @@ void QWindowsStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt,
points[5] = { points[4].x() - 4 * scaleh, points[4].y() + 4 * scalev };
p->setPen(QPen(opt->palette.text().color(), 0));
p->setBrush(opt->palette.text().color());
- p->drawPolygon(points, 6);
+ p->drawPolygon(points.data(), static_cast<int>(points.size()));
}
if (doRestore)
p->restore();
@@ -1573,11 +1519,8 @@ void QWindowsStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPai
default:
break;
}
- if (opt->direction == Qt::RightToLeft){ //reverse layout changes the order of Beginning/end
- bool tmp = paintLeftBorder;
- paintRightBorder=paintLeftBorder;
- paintLeftBorder=tmp;
- }
+ if (opt->direction == Qt::RightToLeft) //reverse layout changes the order of Beginning/end
+ std::swap(paintLeftBorder, paintRightBorder);
break;
case Qt::RightToolBarArea :
switch (toolbar->positionOfLine){
@@ -1789,7 +1732,7 @@ void QWindowsStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPai
titleRect.height(), titleRect.width());
}
proxy()->drawItemText(p, titleRect,
- Qt::AlignLeft | Qt::AlignVCenter, palette,
+ Qt::AlignLeft | Qt::AlignVCenter | Qt::TextHideMnemonic, palette,
dwOpt->state & State_Enabled, dwOpt->title,
floating ? (active ? QPalette::BrightText : QPalette::Window) : QPalette::WindowText);
p->setFont(oldFont);
@@ -1952,39 +1895,36 @@ void QWindowsStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComp
QSliderDirection dir;
if (orient == Qt::Horizontal)
- if (tickAbove)
- dir = SlUp;
- else
- dir = SlDown;
+ dir = tickAbove ? SlUp : SlDown;
else
- if (tickAbove)
- dir = SlLeft;
- else
- dir = SlRight;
-
- QPolygon a;
+ dir = tickAbove ? SlLeft : SlRight;
+ std::array<QPoint, 5> points;
int d = 0;
switch (dir) {
case SlUp:
- y1 = y1 + wi/2;
+ y1 = y1 + wi / 2;
d = (wi + 1) / 2 - 1;
- a.setPoints(5, x1,y1, x1,y2, x2,y2, x2,y1, x1+d,y1-d);
+ points = {QPoint(x1, y1), QPoint(x1, y2), QPoint(x2, y2),
+ QPoint(x2, y1), QPoint(x1 + d, y1 - d)};
break;
case SlDown:
- y2 = y2 - wi/2;
+ y2 = y2 - wi / 2;
d = (wi + 1) / 2 - 1;
- a.setPoints(5, x1,y1, x1,y2, x1+d,y2+d, x2,y2, x2,y1);
+ points = {QPoint(x1, y1), QPoint(x1, y2), QPoint(x1 + d, y2 + d),
+ QPoint(x2, y2), QPoint(x2, y1)};
break;
case SlLeft:
d = (he + 1) / 2 - 1;
- x1 = x1 + he/2;
- a.setPoints(5, x1,y1, x1-d,y1+d, x1,y2, x2,y2, x2,y1);
+ x1 = x1 + he / 2;
+ points = {QPoint(x1, y1), QPoint(x1 - d, y1 + d), QPoint(x1,y2),
+ QPoint(x2, y2), QPoint(x2, y1)};
break;
case SlRight:
d = (he + 1) / 2 - 1;
- x2 = x2 - he/2;
- a.setPoints(5, x1,y1, x1,y2, x2,y2, x2+d,y1+d, x2,y1);
+ x2 = x2 - he / 2;
+ points = {QPoint(x1, y1), QPoint(x1, y2), QPoint(x2, y2),
+ QPoint(x2 + d, y1 + d), QPoint(x2, y1)};
break;
}
@@ -1994,7 +1934,7 @@ void QWindowsStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComp
Qt::BGMode oldMode = p->backgroundMode();
p->setBackgroundMode(Qt::OpaqueMode);
p->drawRect(x1, y1, x2-x1+1, y2-y1+1);
- p->drawPolygon(a);
+ p->drawPolygon(points.data(), static_cast<int>(points.size()));
p->setBrush(oldBrush);
p->setBackgroundMode(oldMode);
diff --git a/src/widgets/styles/qwindowsstyle_p_p.h b/src/widgets/styles/qwindowsstyle_p_p.h
index 0c0350c3d2..dce60cbf8d 100644
--- a/src/widgets/styles/qwindowsstyle_p_p.h
+++ b/src/widgets/styles/qwindowsstyle_p_p.h
@@ -24,8 +24,6 @@
QT_BEGIN_NAMESPACE
-class QTime;
-
class Q_WIDGETS_EXPORT QWindowsStylePrivate : public QCommonStylePrivate
{
Q_DECLARE_PUBLIC(QWindowsStyle)
@@ -35,15 +33,12 @@ public:
QWindowsStylePrivate();
static int pixelMetricFromSystemDp(QStyle::PixelMetric pm, const QStyleOption *option = nullptr, const QWidget *widget = nullptr);
static int fixedPixelMetric(QStyle::PixelMetric pm);
- static qreal devicePixelRatio(const QWidget *widget = nullptr)
- { return widget ? widget->devicePixelRatio() : QWindowsStylePrivate::appDevicePixelRatio(); }
static qreal nativeMetricScaleFactor(const QWidget *widget = nullptr);
bool hasSeenAlt(const QWidget *widget) const;
bool altDown() const { return alt_down; }
bool alt_down = false;
QList<const QWidget *> seenAlt;
- int menuBarTimer = 0;
QColor inactiveCaptionText;
QColor activeCaptionColor;
@@ -60,9 +55,6 @@ public:
windowsRightBorder = 15, // right border on windows
windowsCheckMarkWidth = 12 // checkmarks width on windows
};
-
-private:
- static qreal appDevicePixelRatio();
};
QT_END_NAMESPACE
diff --git a/src/widgets/util/qcompleter.cpp b/src/widgets/util/qcompleter.cpp
index 9664004455..f52321a3e1 100644
--- a/src/widgets/util/qcompleter.cpp
+++ b/src/widgets/util/qcompleter.cpp
@@ -840,8 +840,8 @@ void QCompleterPrivate::setCurrentIndex(QModelIndex index, bool select)
void QCompleterPrivate::_q_completionSelected(const QItemSelection& selection)
{
QModelIndex index;
- if (!selection.indexes().isEmpty())
- index = selection.indexes().first();
+ if (const auto indexes = selection.indexes(); !indexes.isEmpty())
+ index = indexes.first();
_q_complete(index, true);
}
@@ -1296,10 +1296,21 @@ bool QCompleter::eventFilter(QObject *o, QEvent *e)
{
Q_D(QCompleter);
- if (d->eatFocusOut && o == d->widget && e->type() == QEvent::FocusOut) {
- d->hiddenBecauseNoMatch = false;
- if (d->popup && d->popup->isVisible())
- return true;
+ if (o == d->widget) {
+ switch (e->type()) {
+ case QEvent::FocusOut:
+ if (d->eatFocusOut) {
+ d->hiddenBecauseNoMatch = false;
+ if (d->popup && d->popup->isVisible())
+ return true;
+ }
+ break;
+ case QEvent::Hide:
+ if (d->popup)
+ d->popup->hide();
+ default:
+ break;
+ }
}
if (o != d->popup)
diff --git a/src/widgets/util/qcompleter_p.h b/src/widgets/util/qcompleter_p.h
index b74de04031..a88996f180 100644
--- a/src/widgets/util/qcompleter_p.h
+++ b/src/widgets/util/qcompleter_p.h
@@ -25,7 +25,9 @@
#include "qcompleter.h"
#include "qstyleditemdelegate.h"
#include "QtGui/qpainter.h"
+
#include "private/qabstractproxymodel_p.h"
+#include <QtCore/qpointer.h>
QT_REQUIRE_CONFIG(completer);
diff --git a/src/widgets/util/qflickgesture_p.h b/src/widgets/util/qflickgesture_p.h
index b1ae770753..e8306b77e8 100644
--- a/src/widgets/util/qflickgesture_p.h
+++ b/src/widgets/util/qflickgesture_p.h
@@ -20,6 +20,8 @@
#include "qgesturerecognizer.h"
#include "private/qgesture_p.h"
#include "qscroller.h"
+
+#include <QtCore/qpointer.h>
#include "qscopedpointer.h"
#ifndef QT_NO_GESTURES
diff --git a/src/widgets/util/qscroller.cpp b/src/widgets/util/qscroller.cpp
index 385f3b3594..1192a0be60 100644
--- a/src/widgets/util/qscroller.cpp
+++ b/src/widgets/util/qscroller.cpp
@@ -221,9 +221,6 @@ private:
The scroller uses the global QAbstractAnimation timer to generate its QScrollEvents. This
can be changed with QScrollerProperties::FrameRate on a per-QScroller basis.
- The \l {Dir View Example} shows one way to use a QScroller with a QTreeView.
- An example in the \c scroller examples directory also demonstrates QScroller.
-
Even though this kinetic scroller has a large number of settings available via
QScrollerProperties, we recommend that you leave them all at their default, platform optimized
values. Before changing them you can experiment with the \c plot example in
diff --git a/src/widgets/util/qsystemtrayicon.cpp b/src/widgets/util/qsystemtrayicon.cpp
index 7acbf27345..2a55f014e1 100644
--- a/src/widgets/util/qsystemtrayicon.cpp
+++ b/src/widgets/util/qsystemtrayicon.cpp
@@ -61,7 +61,7 @@ static QIcon messageIcon2qIcon(QSystemTrayIcon::MessageIcon icon)
called the \e{system tray} or \e{notification area}, where long-running
applications can display icons and short messages.
- \image system-tray.png The system tray on Windows XP.
+ \image system-tray.webp The system tray on Windows 10.
The QSystemTrayIcon class can be used on the following platforms:
@@ -162,12 +162,16 @@ void QSystemTrayIcon::setContextMenu(QMenu *menu)
{
Q_D(QSystemTrayIcon);
QMenu *oldMenu = d->menu.data();
+ if (oldMenu == menu)
+ return;
+
d->menu = menu;
d->updateMenu_sys();
- if (oldMenu != menu && d->qpa_sys) {
+
+ if (d->qpa_sys) {
// Show the QMenu-based menu for QPA plugins that do not provide native menus
if (oldMenu && !oldMenu->platformMenu())
- QObject::disconnect(d->qpa_sys, &QPlatformSystemTrayIcon::contextMenuRequested, menu, nullptr);
+ QObject::disconnect(d->qpa_sys, &QPlatformSystemTrayIcon::contextMenuRequested, oldMenu, nullptr);
if (menu && !menu->platformMenu()) {
QObject::connect(d->qpa_sys, &QPlatformSystemTrayIcon::contextMenuRequested,
menu,
diff --git a/src/widgets/util/qsystemtrayicon_qpa.cpp b/src/widgets/util/qsystemtrayicon_qpa.cpp
index e156cb1e57..63b24873db 100644
--- a/src/widgets/util/qsystemtrayicon_qpa.cpp
+++ b/src/widgets/util/qsystemtrayicon_qpa.cpp
@@ -59,9 +59,13 @@ void QSystemTrayIconPrivate::updateIcon_sys()
void QSystemTrayIconPrivate::updateMenu_sys()
{
#if QT_CONFIG(menu)
- if (qpa_sys && menu) {
- addPlatformMenu(menu);
- qpa_sys->updateMenu(menu->platformMenu());
+ if (qpa_sys) {
+ if (menu) {
+ addPlatformMenu(menu);
+ qpa_sys->updateMenu(menu->platformMenu());
+ } else {
+ qpa_sys->updateMenu(nullptr);
+ }
}
#endif
}
diff --git a/src/widgets/widgets/qabstractbutton.cpp b/src/widgets/widgets/qabstractbutton.cpp
index 218ec88f53..3a5fbe1b90 100644
--- a/src/widgets/widgets/qabstractbutton.cpp
+++ b/src/widgets/widgets/qabstractbutton.cpp
@@ -21,6 +21,8 @@
#endif
#include <qpa/qplatformtheme.h>
+#include <QtCore/qpointer.h>
+
#include <algorithm>
QT_BEGIN_NAMESPACE
@@ -613,12 +615,13 @@ void QAbstractButton::setChecked(bool checked)
if (guard)
d->emitToggled(checked);
-
#if QT_CONFIG(accessibility)
- QAccessible::State s;
- s.checked = true;
- QAccessibleStateChangeEvent event(this, s);
- QAccessible::updateAccessibility(&event);
+ if (guard) {
+ QAccessible::State s;
+ s.checked = true;
+ QAccessibleStateChangeEvent event(this, s);
+ QAccessible::updateAccessibility(&event);
+ }
#endif
}
diff --git a/src/widgets/widgets/qabstractscrollarea.cpp b/src/widgets/widgets/qabstractscrollarea.cpp
index d741a70d54..f6f8e8b795 100644
--- a/src/widgets/widgets/qabstractscrollarea.cpp
+++ b/src/widgets/widgets/qabstractscrollarea.cpp
@@ -535,15 +535,13 @@ scrolling range.
QSize QAbstractScrollArea::maximumViewportSize() const
{
Q_D(const QAbstractScrollArea);
- int hsbExt = d->hbar->sizeHint().height();
- int vsbExt = d->vbar->sizeHint().width();
-
int f = 2 * d->frameWidth;
QSize max = size() - QSize(f + d->left + d->right, f + d->top + d->bottom);
+ // Count the sizeHint of the bar only if it is displayed.
if (d->vbarpolicy == Qt::ScrollBarAlwaysOn)
- max.rwidth() -= vsbExt;
+ max.rwidth() -= d->vbar->sizeHint().width();
if (d->hbarpolicy == Qt::ScrollBarAlwaysOn)
- max.rheight() -= hsbExt;
+ max.rheight() -= d->hbar->sizeHint().height();
return max;
}
@@ -1102,7 +1100,7 @@ void QAbstractScrollArea::resizeEvent(QResizeEvent *)
This event handler can be reimplemented in a subclass to receive
paint events (passed in \a event), for the viewport() widget.
- \note If you open a painter, make sure to open it on the viewport().
+ \note If you create a QPainter, it must operate on the viewport().
\sa QWidget::paintEvent()
*/
@@ -1433,9 +1431,9 @@ QSize QAbstractScrollArea::sizeHint() const
if (!d->sizeHint.isValid() || d->sizeAdjustPolicy == QAbstractScrollArea::AdjustToContents) {
const int f = 2 * d->frameWidth;
- const QSize frame( f, f );
- const bool vbarHidden = d->vbar->isHidden() || d->vbarpolicy == Qt::ScrollBarAlwaysOff;
- const bool hbarHidden = d->hbar->isHidden() || d->hbarpolicy == Qt::ScrollBarAlwaysOff;
+ const QSize frame(f, f);
+ const bool vbarHidden = !d->vbar->isVisibleTo(this) || d->vbarpolicy == Qt::ScrollBarAlwaysOff;
+ const bool hbarHidden = !d->vbar->isVisibleTo(this) || d->hbarpolicy == Qt::ScrollBarAlwaysOff;
const QSize scrollbars(vbarHidden ? 0 : d->vbar->sizeHint().width(),
hbarHidden ? 0 : d->hbar->sizeHint().height());
d->sizeHint = frame + scrollbars + viewportSizeHint();
diff --git a/src/widgets/widgets/qabstractspinbox.cpp b/src/widgets/widgets/qabstractspinbox.cpp
index 10aea1da3c..f377275d23 100644
--- a/src/widgets/widgets/qabstractspinbox.cpp
+++ b/src/widgets/widgets/qabstractspinbox.cpp
@@ -26,6 +26,7 @@
# include <qaccessible.h>
#endif
+#include <QtCore/qpointer.h>
//#define QABSTRACTSPINBOX_QSBDEBUG
#ifdef QABSTRACTSPINBOX_QSBDEBUG
@@ -691,14 +692,14 @@ void QAbstractSpinBox::setLineEdit(QLineEdit *lineEdit)
d->edit->setAcceptDrops(false);
if (d->type != QMetaType::UnknownType) {
- connect(d->edit, SIGNAL(textChanged(QString)),
- 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()));
+ QObjectPrivate::connect(d->edit, &QLineEdit::textChanged,
+ d, &QAbstractSpinBoxPrivate::editorTextChanged);
+ QObjectPrivate::connect(d->edit, &QLineEdit::cursorPositionChanged,
+ d, &QAbstractSpinBoxPrivate::editorCursorPositionChanged);
+ connect(d->edit, &QLineEdit::cursorPositionChanged,
+ this, [this]() { updateMicroFocus(); });
+ connect(d->edit->d_func()->control, &QWidgetLineControl::updateMicroFocus,
+ this, [this]() { updateMicroFocus(); });
}
d->updateEditFieldGeometry();
d->edit->setContextMenuPolicy(Qt::NoContextMenu);
@@ -1510,7 +1511,7 @@ void QAbstractSpinBoxPrivate::emitSignals(EmitPolicy, const QVariant &)
signal.
*/
-void QAbstractSpinBoxPrivate::_q_editorTextChanged(const QString &t)
+void QAbstractSpinBoxPrivate::editorTextChanged(const QString &t)
{
Q_Q(QAbstractSpinBox);
@@ -1540,7 +1541,7 @@ void QAbstractSpinBoxPrivate::_q_editorTextChanged(const QString &t)
the different sections etc.
*/
-void QAbstractSpinBoxPrivate::_q_editorCursorPositionChanged(int oldpos, int newpos)
+void QAbstractSpinBoxPrivate::editorCursorPositionChanged(int oldpos, int newpos)
{
if (!edit->hasSelectedText() && !ignoreCursorPositionChanged && !specialValue()) {
ignoreCursorPositionChanged = true;
@@ -2042,6 +2043,7 @@ QVariant operator-(const QVariant &arg1, const QVariant &arg2)
dt.setTime(dt.time().addMSecs(msecs));
ret = QVariant(dt);
}
+ break;
}
default: break;
}
diff --git a/src/widgets/widgets/qabstractspinbox.h b/src/widgets/widgets/qabstractspinbox.h
index 6707db45c8..91d3dcb8fc 100644
--- a/src/widgets/widgets/qabstractspinbox.h
+++ b/src/widgets/widgets/qabstractspinbox.h
@@ -136,9 +136,6 @@ protected:
QAbstractSpinBox(QAbstractSpinBoxPrivate &dd, QWidget *parent = nullptr);
private:
- Q_PRIVATE_SLOT(d_func(), void _q_editorTextChanged(const QString &))
- Q_PRIVATE_SLOT(d_func(), void _q_editorCursorPositionChanged(int, int))
-
Q_DECLARE_PRIVATE(QAbstractSpinBox)
Q_DISABLE_COPY(QAbstractSpinBox)
friend class QAccessibleAbstractSpinBox;
diff --git a/src/widgets/widgets/qabstractspinbox_p.h b/src/widgets/widgets/qabstractspinbox_p.h
index efc23586cf..4252a01423 100644
--- a/src/widgets/widgets/qabstractspinbox_p.h
+++ b/src/widgets/widgets/qabstractspinbox_p.h
@@ -74,8 +74,8 @@ public:
virtual QString textFromValue(const QVariant &n) const;
virtual QVariant valueFromText(const QString &input) const;
- void _q_editorTextChanged(const QString &);
- virtual void _q_editorCursorPositionChanged(int oldpos, int newpos);
+ void editorTextChanged(const QString &);
+ virtual void editorCursorPositionChanged(int oldpos, int newpos);
virtual QStyle::SubControl newHoverControl(const QPoint &pos);
bool updateHoverControl(const QPoint &pos);
diff --git a/src/widgets/widgets/qcalendarwidget.cpp b/src/widgets/widgets/qcalendarwidget.cpp
index 6058fc1f47..034127b4f3 100644
--- a/src/widgets/widgets/qcalendarwidget.cpp
+++ b/src/widgets/widgets/qcalendarwidget.cpp
@@ -2200,7 +2200,7 @@ QSize QCalendarWidget::minimumSizeHint() const
QStyleOption option;
option.initFrom(this);
- const int marginH = (style()->pixelMetric(QStyle::PM_FocusFrameHMargin, &option) + 1) * 2;
+ const int marginH = (style()->pixelMetric(QStyle::PM_FocusFrameHMargin, &option, this) + 1) * 2;
if (horizontalHeaderFormat() == QCalendarWidget::NoHorizontalHeader) {
rows = 6;
@@ -2492,14 +2492,14 @@ void QCalendarWidget::showToday()
\snippet code/src_gui_widgets_qcalendarwidget.cpp 1
\endtable
- By default, the minimum date is the earliest date that the QDate
- class can handle.
-
When setting a minimum date, the maximumDate and selectedDate
properties are adjusted if the selection range becomes invalid. If
the provided date is not a valid QDate object, the
setMinimumDate() function does nothing.
+ The default minimum date is November 25, 4714 BCE.
+ You can restore this default by calling clearMinimumDate() (since Qt 6.6).
+
\sa setDateRange()
*/
@@ -2548,14 +2548,14 @@ void QCalendarWidget::clearMinimumDate()
\snippet code/src_gui_widgets_qcalendarwidget.cpp 2
\endtable
- By default, the maximum date is the last day the QDate class can
- handle.
-
When setting a maximum date, the minimumDate and selectedDate
properties are adjusted if the selection range becomes invalid. If
the provided date is not a valid QDate object, the
setMaximumDate() function does nothing.
+ The default maximum date is December 31, 9999 CE.
+ You can restore this default by calling clearMaximumDate() (since Qt 6.6).
+
\sa setDateRange()
*/
@@ -3099,6 +3099,7 @@ bool QCalendarWidget::event(QEvent *event)
case QEvent::StyleChange:
d->cachedSizeHint = QSize();
d->m_view->updateGeometry();
+ break;
default:
break;
}
diff --git a/src/widgets/widgets/qcheckbox.cpp b/src/widgets/widgets/qcheckbox.cpp
index cc013c8c7e..88cd603d70 100644
--- a/src/widgets/widgets/qcheckbox.cpp
+++ b/src/widgets/widgets/qcheckbox.cpp
@@ -28,7 +28,7 @@ public:
uint tristate : 1;
uint noChange : 1;
uint hovering : 1;
- Qt::CheckState publishedState : 2;
+ Qt::CheckState publishedState : 3;
void init();
};
@@ -59,7 +59,7 @@ public:
\endtable
Whenever a checkbox is checked or cleared, it emits the signal
- stateChanged(). Connect to this signal if you want to trigger an action
+ checkStateChanged(). Connect to this signal if you want to trigger an action
each time the checkbox changes state. You can use isChecked() to query
whether or not a checkbox is checked.
@@ -84,30 +84,26 @@ public:
setPixmap(), accel(), setAccel(), isToggleButton(), setDown(), isDown(),
isOn(), checkState(), autoRepeat(), isExclusiveToggle(), group(),
setAutoRepeat(), toggle(), pressed(), released(), clicked(), toggled(),
- checkState(), and stateChanged().
+ checkState(), and checkStateChanged().
\sa QAbstractButton, QRadioButton
*/
-#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
/*!
\fn void QCheckBox::stateChanged(int state)
- This signal is emitted whenever the checkbox's state changes, i.e.,
- whenever the user checks or unchecks it.
-
- \a state contains the checkbox's new Qt::CheckState.
+ \deprecated [6.9] Use checkStateChanged(Qt::CheckState) instead.
*/
-#else
+
/*!
- \fn void QCheckBox::stateChanged(Qt::CheckState state)
+ \fn void QCheckBox::checkStateChanged(Qt::CheckState state)
+ \since 6.7
This signal is emitted whenever the checkbox's state changes, i.e.,
whenever the user checks or unchecks it.
\a state contains the checkbox's new Qt::CheckState.
*/
-#endif
/*!
\property QCheckBox::tristate
@@ -237,7 +233,12 @@ void QCheckBox::setCheckState(Qt::CheckState state)
d->refresh();
if (state != d->publishedState) {
d->publishedState = state;
+ emit checkStateChanged(state);
+#if QT_DEPRECATED_SINCE(6, 9)
+ QT_IGNORE_DEPRECATIONS(
emit stateChanged(state);
+ )
+#endif
}
#if QT_CONFIG(accessibility)
@@ -332,7 +333,12 @@ void QCheckBox::checkStateSet()
Qt::CheckState state = checkState();
if (state != d->publishedState) {
d->publishedState = state;
+ emit checkStateChanged(state);
+#if QT_DEPRECATED_SINCE(6, 9)
+ QT_IGNORE_DEPRECATIONS(
emit stateChanged(state);
+ )
+#endif
}
}
diff --git a/src/widgets/widgets/qcheckbox.h b/src/widgets/widgets/qcheckbox.h
index e385dadbb8..de623b7b9e 100644
--- a/src/widgets/widgets/qcheckbox.h
+++ b/src/widgets/widgets/qcheckbox.h
@@ -36,11 +36,11 @@ public:
void setCheckState(Qt::CheckState state);
Q_SIGNALS:
-#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+#if QT_DEPRECATED_SINCE(6, 9)
+ QT_MOC_COMPAT QT_DEPRECATED_VERSION_X_6_9("Use checkStateChanged() instead")
void stateChanged(int);
-#else
- void stateChanged(Qt::CheckState);
#endif
+ void checkStateChanged(Qt::CheckState);
protected:
bool event(QEvent *e) override;
diff --git a/src/widgets/widgets/qcombobox.cpp b/src/widgets/widgets/qcombobox.cpp
index 7bfce05d68..1fe9a8d7be 100644
--- a/src/widgets/widgets/qcombobox.cpp
+++ b/src/widgets/widgets/qcombobox.cpp
@@ -12,7 +12,7 @@
#if QT_CONFIG(tableview)
#include <qtableview.h>
#endif
-#include <qitemdelegate.h>
+#include <qabstractitemdelegate.h>
#include <qmap.h>
#if QT_CONFIG(menu)
#include <qmenu.h>
@@ -48,6 +48,9 @@
#if QT_CONFIG(accessibility)
#include "qaccessible.h"
#endif
+#include <array>
+
+#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
@@ -65,6 +68,7 @@ QComboBoxPrivate::QComboBoxPrivate()
QComboBoxPrivate::~QComboBoxPrivate()
{
+ disconnectModel();
#ifdef Q_OS_MAC
cleanupNativePopup();
#endif
@@ -200,7 +204,7 @@ bool QComboMenuDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
}
#if QT_CONFIG(completer)
-void QComboBoxPrivate::_q_completerActivated(const QModelIndex &index)
+void QComboBoxPrivate::completerActivated(const QModelIndex &index)
{
Q_Q(QComboBox);
#if QT_CONFIG(proxymodel)
@@ -240,7 +244,7 @@ void QComboBoxPrivate::updateArrow(QStyle::StateFlag state)
q->update(q->rect());
}
-void QComboBoxPrivate::_q_modelReset()
+void QComboBoxPrivate::modelReset()
{
Q_Q(QComboBox);
if (lineEdit) {
@@ -252,7 +256,7 @@ void QComboBoxPrivate::_q_modelReset()
q->update();
}
-void QComboBoxPrivate::_q_modelDestroyed()
+void QComboBoxPrivate::modelDestroyed()
{
model = QAbstractItemModelPrivate::staticEmptyModel();
}
@@ -490,11 +494,13 @@ QComboBoxPrivateContainer::QComboBoxPrivateContainer(QAbstractItemView *itemView
if (top) {
layout->insertWidget(0, top);
- connect(top, SIGNAL(doScroll(int)), this, SLOT(scrollItemView(int)));
+ connect(top, &QComboBoxPrivateScroller::doScroll,
+ this, &QComboBoxPrivateContainer::scrollItemView);
}
if (bottom) {
layout->addWidget(bottom);
- connect(bottom, SIGNAL(doScroll(int)), this, SLOT(scrollItemView(int)));
+ connect(bottom, &QComboBoxPrivateScroller::doScroll,
+ this, &QComboBoxPrivateContainer::scrollItemView);
}
// Some styles (Mac) have a margin at the top and bottom of the popup.
@@ -503,6 +509,12 @@ QComboBoxPrivateContainer::QComboBoxPrivateContainer(QAbstractItemView *itemView
updateStyleSettings();
}
+QComboBoxPrivateContainer::~QComboBoxPrivateContainer()
+{
+ disconnect(view, &QAbstractItemView::destroyed,
+ this, &QComboBoxPrivateContainer::viewDestroyed);
+}
+
void QComboBoxPrivateContainer::scrollItemView(int action)
{
#if QT_CONFIG(scrollbar)
@@ -583,13 +595,13 @@ void QComboBoxPrivateContainer::setItemView(QAbstractItemView *itemView)
view->removeEventFilter(this);
view->viewport()->removeEventFilter(this);
#if QT_CONFIG(scrollbar)
- disconnect(view->verticalScrollBar(), SIGNAL(valueChanged(int)),
- this, SLOT(updateScrollers()));
- disconnect(view->verticalScrollBar(), SIGNAL(rangeChanged(int,int)),
- this, SLOT(updateScrollers()));
+ disconnect(view->verticalScrollBar(), &QScrollBar::valueChanged,
+ this, &QComboBoxPrivateContainer::updateScrollers);
+ disconnect(view->verticalScrollBar(), &QScrollBar::rangeChanged,
+ this, &QComboBoxPrivateContainer::updateScrollers);
#endif
- disconnect(view, SIGNAL(destroyed()),
- this, SLOT(viewDestroyed()));
+ disconnect(view, &QAbstractItemView::destroyed,
+ this, &QComboBoxPrivateContainer::viewDestroyed);
if (isAncestorOf(view))
delete view;
@@ -620,13 +632,13 @@ void QComboBoxPrivateContainer::setItemView(QAbstractItemView *itemView)
view->setLineWidth(0);
view->setEditTriggers(QAbstractItemView::NoEditTriggers);
#if QT_CONFIG(scrollbar)
- connect(view->verticalScrollBar(), SIGNAL(valueChanged(int)),
- this, SLOT(updateScrollers()));
- connect(view->verticalScrollBar(), SIGNAL(rangeChanged(int,int)),
- this, SLOT(updateScrollers()));
+ connect(view->verticalScrollBar(), &QScrollBar::valueChanged,
+ this, &QComboBoxPrivateContainer::updateScrollers);
+ connect(view->verticalScrollBar(), &QScrollBar::rangeChanged,
+ this, &QComboBoxPrivateContainer::updateScrollers);
#endif
- connect(view, SIGNAL(destroyed()),
- this, SLOT(viewDestroyed()));
+ connect(view, &QAbstractItemView::destroyed,
+ this, &QComboBoxPrivateContainer::viewDestroyed);
}
/*!
@@ -715,6 +727,7 @@ bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e)
#endif
if (view->currentIndex().isValid() && view->currentIndex().flags().testFlag(Qt::ItemIsEnabled)) {
combo->hidePopup();
+ keyEvent->accept();
emit itemSelected(view->currentIndex());
}
return true;
@@ -724,6 +737,8 @@ bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e)
Q_FALLTHROUGH();
case Qt::Key_F4:
combo->hidePopup();
+ keyEvent->accept();
+ emit itemSelected(view->currentIndex());
return true;
default:
#if QT_CONFIG(shortcut)
@@ -904,8 +919,11 @@ QStyleOptionComboBox QComboBoxPrivateContainer::comboStyleOption() const
\fn void QComboBox::currentTextChanged(const QString &text)
\since 5.0
- This signal is sent whenever currentText changes. The new value
- is passed as \a text.
+ This signal is emitted whenever currentText changes.
+ The new value is passed as \a text.
+
+ \note It is not emitted, if currentText remains the same,
+ even if currentIndex changes.
*/
/*!
@@ -931,39 +949,34 @@ QComboBox::QComboBox(QComboBoxPrivate &dd, QWidget *parent)
/*!
\class QComboBox
- \brief The QComboBox widget is a combined button and popup list.
+ \brief The QComboBox widget combines a button with a dropdown list.
\ingroup basicwidgets
\inmodule QtWidgets
- \image windows-combobox.png
-
- A QComboBox provides a means of presenting a list of options to the user
- in a way that takes up the minimum amount of screen space.
-
- A combobox is a selection widget that displays the current item,
- and can pop up a list of selectable items. A combobox may be editable,
- allowing the user to modify each item in the list.
-
- Comboboxes can contain pixmaps as well as strings; the
- insertItem() and setItemText() functions are suitably overloaded.
- For editable comboboxes, the function clearEditText() is provided,
+ \table
+ \row
+ \li \inlineimage collapsed_combobox.png
+ \caption Collapsed QCombobox
+ \li
+ \inlineimage expanded_combobox.png
+ \caption Expanded QCombobox
+ \endtable
+
+ \section1 Display Features
+ A QComboBox is a compact way to present a list of options to the user.
+
+ A combobox is a selection widget that shows the current item,
+ and pops up a list of selectable items when clicked. Comboboxes can
+ contain pixmaps as well as strings if the insertItem() and setItemText()
+ functions are suitably overloaded.
+
+ \section1 Editing Features
+ A combobox may be editable, allowing the user to modify each item in the
+ list. For editable comboboxes, the function clearEditText() is provided,
to clear the displayed string without changing the combobox's
contents.
- There are three signals emitted if the current item of a combobox
- changes, currentIndexChanged(), currentTextChanged() and activated().
- currentIndexChanged() and currentTextChanged() are always emitted
- regardless if the change
- was done programmatically or by user interaction, while
- activated() is only emitted when the change is caused by user
- interaction. The highlighted() signal is emitted when the user
- highlights an item in the combobox popup list. All three signals
- exist in two versions, one with a QString argument and one with an
- \c int argument. If the user selects or highlights a pixmap, only
- the \c int signals are emitted. Whenever the text of an editable
- combobox is changed the editTextChanged() signal is emitted.
-
When the user enters a new string in an editable combobox, the
widget may or may not insert it, and it can insert it in several
locations. The default policy is \l InsertAtBottom but you can change
@@ -986,17 +999,33 @@ QComboBox::QComboBox(QComboBoxPrivate &dd, QWidget *parent)
setCompleter() and whether or not the user can add duplicates
is set with setDuplicatesEnabled().
- QComboBox uses the \l{Model/View Programming}{model/view
- framework} for its popup list and to store its items. By default
- a QStandardItemModel stores the items and a QListView subclass
- displays the popuplist. You can access the model and view directly
- (with model() and view()), but QComboBox also provides functions
- to set and get item data (e.g., setItemData() and itemText()). You
- can also set a new model and view (with setModel() and setView()).
- For the text and icon in the combobox label, the data in the model
- that has the Qt::DisplayRole and Qt::DecorationRole is used. Note
- that you cannot alter the \l{QAbstractItemView::}{SelectionMode}
- of the view(), e.g., by using
+ \section1 Signals
+ There are three signals emitted if the current item of a combobox
+ changes: currentIndexChanged(), currentTextChanged(), and activated().
+ currentIndexChanged() and currentTextChanged() are always emitted
+ regardless if the change
+ was done programmatically or by user interaction, while
+ activated() is only emitted when the change is caused by user
+ interaction. The highlighted() signal is emitted when the user
+ highlights an item in the combobox popup list. All three signals
+ exist in two versions, one with a QString argument and one with an
+ \c int argument. If the user selects or highlights a pixmap, only
+ the \c int signals are emitted. Whenever the text of an editable
+ combobox is changed, the editTextChanged() signal is emitted.
+
+ \section1 Model/View Framework
+
+ QComboBox uses the \l{Model/View Programming}{model/view framework} for its
+ popup list and to store its items. By default a QStandardItemModel stores
+ the items and a QListView subclass displays the popuplist. You can access
+ the model and view directly (with model() and view()), but QComboBox also
+ provides functions to set and get item data, for example, setItemData() and
+ itemText(). You can also set a new model and view (with setModel()
+ and setView()). For the text and icon in the combobox label, the data in
+ the model that has the Qt::DisplayRole and Qt::DecorationRole is used.
+
+ \note You cannot alter the \l{QAbstractItemView::}{SelectionMode}
+ of the view(), for example, by using
\l{QAbstractItemView::}{setSelectionMode()}.
\sa QLineEdit, QSpinBox, QRadioButton, QButtonGroup
@@ -1033,27 +1062,30 @@ QComboBoxPrivateContainer* QComboBoxPrivate::viewContainer()
Q_Q(QComboBox);
container = new QComboBoxPrivateContainer(new QComboBoxListView(q), q);
+ disconnectModel();
container->itemView()->setModel(model);
+ connectModel();
container->itemView()->setTextElideMode(Qt::ElideMiddle);
updateDelegate(true);
updateLayoutDirection();
updateViewContainerPaletteAndOpacity();
- QObject::connect(container, SIGNAL(itemSelected(QModelIndex)),
- q, SLOT(_q_itemSelected(QModelIndex)));
- QObject::connect(container->itemView()->selectionModel(),
- SIGNAL(currentChanged(QModelIndex,QModelIndex)),
- q, SLOT(_q_emitHighlighted(QModelIndex)));
- QObject::connect(container, SIGNAL(resetButton()), q, SLOT(_q_resetButton()));
+ QObjectPrivate::connect(container, &QComboBoxPrivateContainer::itemSelected,
+ this, &QComboBoxPrivate::itemSelected);
+ QObjectPrivate::connect(container->itemView()->selectionModel(),
+ &QItemSelectionModel::currentChanged,
+ this, &QComboBoxPrivate::emitHighlighted);
+ QObjectPrivate::connect(container, &QComboBoxPrivateContainer::resetButton,
+ this, &QComboBoxPrivate::resetButton);
return container;
}
-void QComboBoxPrivate::_q_resetButton()
+void QComboBoxPrivate::resetButton()
{
updateArrow(QStyle::State_None);
}
-void QComboBoxPrivate::_q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
+void QComboBoxPrivate::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
Q_Q(QComboBox);
if (inserting || topLeft.parent() != root)
@@ -1071,7 +1103,7 @@ void QComboBoxPrivate::_q_dataChanged(const QModelIndex &topLeft, const QModelIn
lineEdit->setText(text);
updateLineEditGeometry();
} else {
- emit q->currentTextChanged(text);
+ updateCurrentText(text);
}
q->update();
#if QT_CONFIG(accessibility)
@@ -1081,7 +1113,7 @@ void QComboBoxPrivate::_q_dataChanged(const QModelIndex &topLeft, const QModelIn
}
}
-void QComboBoxPrivate::_q_rowsInserted(const QModelIndex &parent, int start, int end)
+void QComboBoxPrivate::rowsInserted(const QModelIndex &parent, int start, int end)
{
Q_Q(QComboBox);
if (inserting || parent != root)
@@ -1096,20 +1128,31 @@ void QComboBoxPrivate::_q_rowsInserted(const QModelIndex &parent, int start, int
// set current index if combo was previously empty and there is no placeholderText
if (start == 0 && (end - start + 1) == q->count() && !currentIndex.isValid() &&
placeholderText.isEmpty()) {
+#if QT_CONFIG(accessibility)
+ // This might have been called by the model emitting rowInserted(), at which
+ // point the view won't have updated the accessibility bridge yet about its new
+ // dimensions. Do it now so that the change of the selection matches the row
+ // indexes of the accessibility bridge's representation.
+ if (container && container->itemView()) {
+ QAccessibleTableModelChangeEvent event(container->itemView(),
+ QAccessibleTableModelChangeEvent::ModelReset);
+ QAccessible::updateAccessibility(&event);
+ }
+#endif
q->setCurrentIndex(0);
// need to emit changed if model updated index "silently"
} else if (currentIndex.row() != indexBeforeChange) {
q->update();
- _q_emitCurrentIndexChanged(currentIndex);
+ emitCurrentIndexChanged(currentIndex);
}
}
-void QComboBoxPrivate::_q_updateIndexBeforeChange()
+void QComboBoxPrivate::updateIndexBeforeChange()
{
indexBeforeChange = currentIndex.row();
}
-void QComboBoxPrivate::_q_rowsRemoved(const QModelIndex &parent, int /*start*/, int /*end*/)
+void QComboBoxPrivate::rowsRemoved(const QModelIndex &parent, int /*start*/, int /*end*/)
{
Q_Q(QComboBox);
if (parent != root)
@@ -1121,6 +1164,12 @@ void QComboBoxPrivate::_q_rowsRemoved(const QModelIndex &parent, int /*start*/,
q->updateGeometry();
}
+ // model has removed the last row
+ if (model->rowCount(root) == 0) {
+ setCurrentIndex(QModelIndex());
+ return;
+ }
+
// model has changed the currentIndex
if (currentIndex.row() != indexBeforeChange) {
if (!currentIndex.isValid() && q->count()) {
@@ -1132,7 +1181,7 @@ void QComboBoxPrivate::_q_rowsRemoved(const QModelIndex &parent, int /*start*/,
updateLineEditGeometry();
}
q->update();
- _q_emitCurrentIndexChanged(currentIndex);
+ emitCurrentIndexChanged(currentIndex);
}
}
@@ -1241,7 +1290,7 @@ Qt::MatchFlags QComboBoxPrivate::matchFlags() const
}
-void QComboBoxPrivate::_q_editingFinished()
+void QComboBoxPrivate::editingFinished()
{
Q_Q(QComboBox);
if (!lineEdit)
@@ -1273,13 +1322,13 @@ void QComboBoxPrivate::_q_editingFinished()
}
-void QComboBoxPrivate::_q_returnPressed()
+void QComboBoxPrivate::returnPressed()
{
Q_Q(QComboBox);
// The insertion code below does not apply when the policy is QComboBox::NoInsert.
// In case a completer is installed, item activation via the completer is handled
- // in _q_completerActivated(). Otherwise _q_editingFinished() updates the current
+ // in completerActivated(). Otherwise editingFinished() updates the current
// index as appropriate.
if (insertPolicy == QComboBox::NoInsert)
return;
@@ -1337,7 +1386,7 @@ void QComboBoxPrivate::_q_returnPressed()
}
}
-void QComboBoxPrivate::_q_itemSelected(const QModelIndex &item)
+void QComboBoxPrivate::itemSelected(const QModelIndex &item)
{
Q_Q(QComboBox);
if (item != currentIndex) {
@@ -1359,7 +1408,7 @@ void QComboBoxPrivate::emitActivated(const QModelIndex &index)
emit q->textActivated(text);
}
-void QComboBoxPrivate::_q_emitHighlighted(const QModelIndex &index)
+void QComboBoxPrivate::emitHighlighted(const QModelIndex &index)
{
Q_Q(QComboBox);
if (!index.isValid())
@@ -1369,14 +1418,14 @@ void QComboBoxPrivate::_q_emitHighlighted(const QModelIndex &index)
emit q->textHighlighted(text);
}
-void QComboBoxPrivate::_q_emitCurrentIndexChanged(const QModelIndex &index)
+void QComboBoxPrivate::emitCurrentIndexChanged(const QModelIndex &index)
{
Q_Q(QComboBox);
const QString text = itemText(index);
emit q->currentIndexChanged(index.row());
// signal lineEdit.textChanged already connected to signal currentTextChanged, so don't emit double here
if (!lineEdit)
- emit q->currentTextChanged(text);
+ updateCurrentText(text);
#if QT_CONFIG(accessibility)
QAccessibleValueChangeEvent event(q, text);
QAccessible::updateAccessibility(&event);
@@ -1402,11 +1451,13 @@ QComboBox::~QComboBox()
Q_D(QComboBox);
QT_TRY {
- disconnect(d->model, SIGNAL(destroyed()),
- this, SLOT(_q_modelDestroyed()));
+ d->disconnectModel();
} QT_CATCH(...) {
; // objects can't throw in destructor
}
+
+ // Dispose of container before QComboBox goes away
+ delete d->container;
}
/*!
@@ -1437,7 +1488,7 @@ void QComboBox::setMaxVisibleItems(int maxItems)
/*!
\property QComboBox::count
- \brief the number of items in the combobox
+ \brief the number of items in the combobox.
By default, for an empty combo box, this property has a value of 0.
*/
@@ -1449,7 +1500,7 @@ int QComboBox::count() const
/*!
\property QComboBox::maxCount
- \brief the maximum number of items allowed in the combobox
+ \brief the maximum number of items allowed in the combobox.
\note If you set the maximum number to be less then the current
amount of items in the combobox, the extra items will be
@@ -1482,7 +1533,7 @@ int QComboBox::maxCount() const
/*!
\property QComboBox::duplicatesEnabled
- \brief whether the user can enter duplicate items into the combobox
+ \brief whether the user can enter duplicate items into the combobox.
Note that it is always possible to programmatically insert duplicate items into the
combobox.
@@ -1528,7 +1579,7 @@ int QComboBox::findData(const QVariant &data, int role, Qt::MatchFlags flags) co
/*!
\property QComboBox::insertPolicy
\brief the policy used to determine where user-inserted items should
- appear in the combobox
+ appear in the combobox.
The default value is \l InsertAtBottom, indicating that new items will appear
at the bottom of the list of items.
@@ -1551,7 +1602,7 @@ void QComboBox::setInsertPolicy(InsertPolicy policy)
/*!
\property QComboBox::sizeAdjustPolicy
\brief the policy describing how the size of the combobox changes
- when the content changes
+ when the content changes.
The default value is \l AdjustToContentsOnFirstShow.
@@ -1642,7 +1693,7 @@ void QComboBox::setIconSize(const QSize &size)
/*!
\property QComboBox::placeholderText
- \brief Sets a \a placeholderText text shown when no valid index is set
+ \brief Sets a \a placeholderText text shown when no valid index is set.
The \a placeholderText will be shown when an invalid index is set. The
text is not accessible in the dropdown list. When this function is called
@@ -1681,7 +1732,7 @@ QString QComboBox::placeholderText() const
/*!
\property QComboBox::editable
- \brief whether the combo box can be edited by the user
+ \brief whether the combo box can be edited by the user.
By default, this property is \c false. The effect of editing depends
on the insert policy.
@@ -1720,6 +1771,8 @@ void QComboBoxPrivate::updateDelegate(bool force)
QIcon QComboBoxPrivate::itemIcon(const QModelIndex &index) const
{
+ if (!index.isValid())
+ return {};
QVariant decoration = model->data(index, Qt::DecorationRole);
if (decoration.userType() == QMetaType::QPixmap)
return QIcon(qvariant_cast<QPixmap>(decoration));
@@ -1790,13 +1843,18 @@ void QComboBox::setLineEdit(QLineEdit *edit)
#endif
if (d->lineEdit->parent() != this)
d->lineEdit->setParent(this);
- connect(d->lineEdit, SIGNAL(returnPressed()), this, SLOT(_q_returnPressed()));
- connect(d->lineEdit, SIGNAL(editingFinished()), this, SLOT(_q_editingFinished()));
- connect(d->lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(editTextChanged(QString)));
- 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()));
+ QObjectPrivate::connect(d->lineEdit, &QLineEdit::returnPressed,
+ d, &QComboBoxPrivate::returnPressed);
+ QObjectPrivate::connect(d->lineEdit, &QLineEdit::editingFinished,
+ d, &QComboBoxPrivate::editingFinished);
+ connect(d->lineEdit, &QLineEdit::textChanged, this, &QComboBox::editTextChanged);
+ connect(d->lineEdit, &QLineEdit::textChanged, this, &QComboBox::currentTextChanged);
+ QObjectPrivate::connect(d->lineEdit, &QLineEdit::cursorPositionChanged,
+ d, &QComboBoxPrivate::updateMicroFocus);
+ QObjectPrivate::connect(d->lineEdit, &QLineEdit::selectionChanged,
+ d, &QComboBoxPrivate::updateMicroFocus);
+ QObjectPrivate::connect(d->lineEdit->d_func()->control, &QWidgetLineControl::updateMicroFocus,
+ d, &QComboBoxPrivate::updateMicroFocus);
d->lineEdit->setFrame(false);
d->lineEdit->setContextMenuPolicy(Qt::NoContextMenu);
d->updateFocusPolicy();
@@ -1898,7 +1956,8 @@ void QComboBox::setCompleter(QCompleter *c)
}
d->lineEdit->setCompleter(c);
if (c) {
- connect(c, SIGNAL(activated(QModelIndex)), this, SLOT(_q_completerActivated(QModelIndex)));
+ QObjectPrivate::connect(c, QOverload<const QModelIndex &>::of(&QCompleter::activated),
+ d, &QComboBoxPrivate::completerActivated);
c->setWidget(this);
}
}
@@ -1992,59 +2051,60 @@ void QComboBox::setModel(QAbstractItemModel *model)
if (d->lineEdit && d->lineEdit->completer())
d->lineEdit->completer()->setModel(model);
#endif
- if (d->model) {
- disconnect(d->model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
- this, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
- disconnect(d->model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
- this, SLOT(_q_updateIndexBeforeChange()));
- disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
- disconnect(d->model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(_q_updateIndexBeforeChange()));
- disconnect(d->model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
- disconnect(d->model, SIGNAL(destroyed()),
- this, SLOT(_q_modelDestroyed()));
- disconnect(d->model, SIGNAL(modelAboutToBeReset()),
- this, SLOT(_q_updateIndexBeforeChange()));
- disconnect(d->model, SIGNAL(modelReset()),
- this, SLOT(_q_modelReset()));
- if (d->model->QObject::parent() == this)
- delete d->model;
+ d->disconnectModel();
+ if (d->model && d->model->QObject::parent() == this) {
+ delete d->model;
+ d->model = nullptr;
}
d->model = model;
- connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
- this, SLOT(_q_dataChanged(QModelIndex,QModelIndex)));
- connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
- this, SLOT(_q_updateIndexBeforeChange()));
- connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
- this, SLOT(_q_rowsInserted(QModelIndex,int,int)));
- connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
- this, SLOT(_q_updateIndexBeforeChange()));
- connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
- this, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
- connect(model, SIGNAL(destroyed()),
- this, SLOT(_q_modelDestroyed()));
- connect(model, SIGNAL(modelAboutToBeReset()),
- this, SLOT(_q_updateIndexBeforeChange()));
- connect(model, SIGNAL(modelReset()),
- this, SLOT(_q_modelReset()));
-
if (d->container) {
d->container->itemView()->setModel(model);
- connect(d->container->itemView()->selectionModel(),
- SIGNAL(currentChanged(QModelIndex,QModelIndex)),
- this, SLOT(_q_emitHighlighted(QModelIndex)), Qt::UniqueConnection);
+ QObjectPrivate::connect(d->container->itemView()->selectionModel(),
+ &QItemSelectionModel::currentChanged,
+ d, &QComboBoxPrivate::emitHighlighted, Qt::UniqueConnection);
}
+ d->connectModel();
+
setRootModelIndex(QModelIndex());
d->trySetValidIndex();
d->modelChanged();
}
+void QComboBoxPrivate::connectModel()
+{
+ if (!model)
+ return;
+
+ modelConnections = {
+ QObjectPrivate::connect(model, &QAbstractItemModel::dataChanged,
+ this, &QComboBoxPrivate::dataChanged),
+ QObjectPrivate::connect(model, &QAbstractItemModel::rowsAboutToBeInserted,
+ this, &QComboBoxPrivate::updateIndexBeforeChange),
+ QObjectPrivate::connect(model, &QAbstractItemModel::rowsInserted,
+ this, &QComboBoxPrivate::rowsInserted),
+ QObjectPrivate::connect(model, &QAbstractItemModel::rowsAboutToBeRemoved,
+ this, &QComboBoxPrivate::updateIndexBeforeChange),
+ QObjectPrivate::connect(model, &QAbstractItemModel::rowsRemoved,
+ this, &QComboBoxPrivate::rowsRemoved),
+ QObjectPrivate::connect(model, &QObject::destroyed,
+ this, &QComboBoxPrivate::modelDestroyed),
+ QObjectPrivate::connect(model, &QAbstractItemModel::modelAboutToBeReset,
+ this, &QComboBoxPrivate::updateIndexBeforeChange),
+ QObjectPrivate::connect(model, &QAbstractItemModel::modelReset,
+ this, &QComboBoxPrivate::modelReset)
+ };
+}
+
+void QComboBoxPrivate::disconnectModel()
+{
+ for (auto &connection : modelConnections)
+ QObject::disconnect(connection);
+}
+
/*!
Returns the root model item index for the items in the combobox.
@@ -2090,7 +2150,7 @@ int QComboBox::currentIndex() const
void QComboBox::setCurrentIndex(int index)
{
Q_D(QComboBox);
- QModelIndex mi = d->model->index(index, d->modelColumn, d->root);
+ QModelIndex mi = index >= 0 ? d->model->index(index, d->modelColumn, d->root) : QModelIndex();
d->setCurrentIndex(mi);
}
@@ -2127,13 +2187,24 @@ void QComboBoxPrivate::setCurrentIndex(const QModelIndex &mi)
}
updateLineEditGeometry();
}
- // If the model was reset to an empty, currentIndex will be invalidated
+ // If the model was reset to an empty one, currentIndex will be invalidated
// (because it's a QPersistentModelIndex), but the index change will never
- // be advertised. So we need an explicit check for such condition.
+ // be advertised. So an explicit check for this condition is needed.
+ // The variable used for that check has to be reset when a previously valid
+ // index becomes invalid.
const bool modelResetToEmpty = !normalized.isValid() && indexBeforeChange != -1;
+ if (modelResetToEmpty)
+ indexBeforeChange = -1;
+
if (indexChanged || modelResetToEmpty) {
+ QItemSelectionModel::SelectionFlags selectionMode = QItemSelectionModel::ClearAndSelect;
+ if (q->view()->selectionBehavior() == QAbstractItemView::SelectRows)
+ selectionMode.setFlag(QItemSelectionModel::Rows);
+ if (auto *model = q->view()->selectionModel())
+ model->setCurrentIndex(currentIndex, selectionMode);
+
q->update();
- _q_emitCurrentIndexChanged(currentIndex);
+ emitCurrentIndexChanged(currentIndex);
}
}
@@ -2262,7 +2333,7 @@ void QComboBox::insertItem(int index, const QIcon &icon, const QString &text, co
if (!values.isEmpty()) d->model->setItemData(item, values);
}
d->inserting = false;
- d->_q_rowsInserted(d->root, index, index);
+ d->rowsInserted(d->root, index, index);
++itemCount;
} else {
d->inserting = false;
@@ -2310,7 +2381,7 @@ void QComboBox::insertItems(int index, const QStringList &list)
d->model->setData(item, list.at(i), Qt::EditRole);
}
d->inserting = false;
- d->_q_rowsInserted(d->root, index, index + insertCount - 1);
+ d->rowsInserted(d->root, index, index + insertCount - 1);
} else {
d->inserting = false;
}
@@ -2420,8 +2491,11 @@ void QComboBox::setView(QAbstractItemView *itemView)
return;
}
- if (itemView->model() != d->model)
+ if (itemView->model() != d->model) {
+ d->disconnectModel();
itemView->setModel(d->model);
+ d->connectModel();
+ }
d->viewContainer()->setItemView(itemView);
}
@@ -2453,12 +2527,13 @@ void QComboBoxPrivate::cleanupNativePopup()
if (!m_platformMenu)
return;
+ m_platformMenu->setVisible(false);
int count = int(m_platformMenu->tag());
for (int i = 0; i < count; ++i)
m_platformMenu->menuItemAt(i)->deleteLater();
delete m_platformMenu;
- m_platformMenu = 0;
+ m_platformMenu = nullptr;
}
/*!
@@ -2490,15 +2565,17 @@ bool QComboBoxPrivate::showNativePopup()
QVariant textVariant = model->data(rowIndex, Qt::EditRole);
item->setText(textVariant.toString());
QVariant iconVariant = model->data(rowIndex, Qt::DecorationRole);
+ const Qt::ItemFlags itemFlags = model->flags(rowIndex);
if (iconVariant.canConvert<QIcon>())
item->setIcon(iconVariant.value<QIcon>());
item->setCheckable(true);
item->setChecked(i == currentIndex);
+ item->setEnabled(itemFlags & Qt::ItemIsEnabled);
if (!currentItem || i == currentIndex)
currentItem = item;
IndexSetter setter = { i, q };
- QObject::connect(item, &QPlatformMenuItem::activated, setter);
+ QObject::connect(item, &QPlatformMenuItem::activated, q, setter);
m_platformMenu->insertMenuItem(item, 0);
m_platformMenu->syncMenuItem(item);
@@ -2513,15 +2590,18 @@ bool QComboBoxPrivate::showNativePopup()
else if (q->testAttribute(Qt::WA_MacMiniSize))
offset = QPoint(-2, 6);
+ [[maybe_unused]] QPointer<QComboBox> guard(q);
const QRect targetRect = QRect(tlw->mapFromGlobal(q->mapToGlobal(offset)), QSize());
m_platformMenu->showPopup(tlw, QHighDpi::toNativePixels(targetRect, tlw), currentItem);
#ifdef Q_OS_MACOS
- // The Cocoa popup will swallow any mouse release event.
- // We need to fake one here to un-press the button.
- QMouseEvent mouseReleased(QEvent::MouseButtonRelease, q->pos(), q->mapToGlobal(QPoint(0, 0)),
- Qt::LeftButton, Qt::MouseButtons(Qt::LeftButton), {});
- QCoreApplication::sendEvent(q, &mouseReleased);
+ if (guard) {
+ // The Cocoa popup will swallow any mouse release event.
+ // We need to fake one here to un-press the button.
+ QMouseEvent mouseReleased(QEvent::MouseButtonRelease, q->pos(), q->mapToGlobal(QPoint(0, 0)),
+ Qt::LeftButton, Qt::MouseButtons(Qt::LeftButton), {});
+ QCoreApplication::sendEvent(q, &mouseReleased);
+ }
#endif
return true;
@@ -2559,11 +2639,6 @@ void QComboBox::showPopup()
return;
#endif // Q_OS_MAC
- // set current item and select it
- QItemSelectionModel::SelectionFlags selectionMode = QItemSelectionModel::ClearAndSelect;
- if (view()->selectionBehavior() == QAbstractItemView::SelectRows)
- selectionMode.setFlag(QItemSelectionModel::Rows);
- view()->selectionModel()->setCurrentIndex(d->currentIndex, selectionMode);
QComboBoxPrivateContainer* container = d->viewContainer();
QRect listRect(style->subControlRect(QStyle::CC_ComboBox, &opt,
QStyle::SC_ComboBoxListBoxPopup, this));
@@ -2574,6 +2649,7 @@ void QComboBox::showPopup()
QPoint above = mapToGlobal(listRect.topLeft());
int aboveHeight = above.y() - screen.y();
bool boundToScreen = !window()->testAttribute(Qt::WA_DontShowOnScreen);
+ const auto listView = qobject_cast<QListView *>(d->viewContainer()->itemView());
{
int listHeight = 0;
@@ -2588,6 +2664,8 @@ void QComboBox::showPopup()
while (!toCheck.isEmpty()) {
QModelIndex parent = toCheck.pop();
for (int i = 0, end = d->model->rowCount(parent); i < end; ++i) {
+ if (listView && listView->isRowHidden(i))
+ continue;
QModelIndex idx = d->model->index(i, d->modelColumn, parent);
if (!idx.isValid())
continue;
@@ -2661,7 +2739,13 @@ void QComboBox::showPopup()
listRect.moveLeft(above.x());
// Position vertically so the currently selected item lines up
- // with the combo box.
+ // with the combo box. In order to do that, make sure that the item
+ // view is scrolled to the top first, otherwise calls to view()->visualRect()
+ // will return the geometry the selected item had the last time the popup
+ // was visible (and perhaps scrolled). And this will not match the geometry
+ // it will actually have when we resize the container to fit all the items
+ // further down in this function.
+ view()->scrollToTop();
const QRect currentItemRect = view()->visualRect(view()->currentIndex());
const int offset = listRect.top() - currentItemRect.top();
listRect.moveTop(above.y() + offset - listRect.top());
@@ -2794,31 +2878,30 @@ void QComboBox::hidePopup()
return;
#if QT_CONFIG(effects)
- // Flash selected/triggered item (if any).
- if (style()->styleHint(QStyle::SH_Menu_FlashTriggeredItem)) {
- QItemSelectionModel *selectionModel = d->container->itemView()
- ? d->container->itemView()->selectionModel() : nullptr;
- if (selectionModel && selectionModel->hasSelection()) {
- const QItemSelection selection = selectionModel->selection();
-
- QTimer::singleShot(0, d->container, [d, selection, selectionModel]{
+ QItemSelectionModel *selectionModel = d->container->itemView()
+ ? d->container->itemView()->selectionModel() : nullptr;
+ // Flash selected/triggered item (if any) before hiding the popup.
+ if (style()->styleHint(QStyle::SH_Menu_FlashTriggeredItem) &&
+ selectionModel && selectionModel->hasSelection()) {
+ const QItemSelection selection = selectionModel->selection();
+
+ QTimer::singleShot(0, d->container, [d, selection, selectionModel]{
+ QSignalBlocker modelBlocker(d->model);
+ QSignalBlocker viewBlocker(d->container->itemView());
+ QSignalBlocker containerBlocker(d->container);
+
+ // Deselect item and wait 60 ms.
+ selectionModel->select(selection, QItemSelectionModel::Toggle);
+ QTimer::singleShot(60, d->container, [d, selection, selectionModel]{
QSignalBlocker modelBlocker(d->model);
QSignalBlocker viewBlocker(d->container->itemView());
QSignalBlocker containerBlocker(d->container);
-
- // Deselect item and wait 60 ms.
selectionModel->select(selection, QItemSelectionModel::Toggle);
- QTimer::singleShot(60, d->container, [d, selection, selectionModel]{
- QSignalBlocker modelBlocker(d->model);
- QSignalBlocker viewBlocker(d->container->itemView());
- QSignalBlocker containerBlocker(d->container);
- selectionModel->select(selection, QItemSelectionModel::Toggle);
- QTimer::singleShot(20, d->container, [d] {
- d->doHidePopup();
- });
+ QTimer::singleShot(20, d->container, [d] {
+ d->doHidePopup();
});
});
- }
+ });
} else
#endif // QT_CONFIG(effects)
{
@@ -2831,7 +2914,16 @@ void QComboBoxPrivate::doHidePopup()
if (container && container->isVisible())
container->hide();
- _q_resetButton();
+ resetButton();
+}
+
+void QComboBoxPrivate::updateCurrentText(const QString &text)
+{
+ if (text == currentText)
+ return;
+
+ currentText = text;
+ emit q_func()->currentTextChanged(text);
}
/*!
@@ -2914,6 +3006,7 @@ void QComboBox::changeEvent(QEvent *e)
if (d->container)
d->container->updateStyleSettings();
d->updateDelegate();
+
#ifdef Q_OS_MAC
case QEvent::MacSizeChange:
#endif
@@ -3084,7 +3177,10 @@ void QComboBoxPrivate::showPopupFromMouseEvent(QMouseEvent *e)
// viewContainer(), we avoid creating the QComboBoxPrivateContainer.
viewContainer()->initialClickPosition = q->mapToGlobal(e->position().toPoint());
}
+ QPointer<QComboBox> guard = q;
q->showPopup();
+ if (!guard)
+ return;
// The code below ensures that regular mousepress and pick item still works
// If it was not called the viewContainer would ignore event since it didn't have
// a mousePressEvent first.
@@ -3224,8 +3320,9 @@ void QComboBox::keyPressEvent(QKeyEvent *e)
#endif
if (!d->lineEdit) {
- if (!e->text().isEmpty())
- d->keyboardSearchString(e->text());
+ const auto text = e->text();
+ if (!text.isEmpty() && text.at(0).isPrint())
+ d->keyboardSearchString(text);
else
e->ignore();
}
@@ -3423,7 +3520,7 @@ QVariant QComboBox::inputMethodQuery(Qt::InputMethodQuery query, const QVariant
/*!
\property QComboBox::frame
- \brief whether the combo box draws itself with a frame
+ \brief whether the combo box draws itself with a frame.
If enabled (the default) the combo box draws itself inside a
diff --git a/src/widgets/widgets/qcombobox.h b/src/widgets/widgets/qcombobox.h
index be28ce7173..1689d0fa1e 100644
--- a/src/widgets/widgets/qcombobox.h
+++ b/src/widgets/widgets/qcombobox.h
@@ -204,21 +204,6 @@ protected:
private:
Q_DECLARE_PRIVATE(QComboBox)
Q_DISABLE_COPY(QComboBox)
- Q_PRIVATE_SLOT(d_func(), void _q_itemSelected(const QModelIndex &item))
- Q_PRIVATE_SLOT(d_func(), void _q_emitHighlighted(const QModelIndex &))
- Q_PRIVATE_SLOT(d_func(), void _q_emitCurrentIndexChanged(const QModelIndex &index))
- Q_PRIVATE_SLOT(d_func(), void _q_editingFinished())
- Q_PRIVATE_SLOT(d_func(), void _q_returnPressed())
- Q_PRIVATE_SLOT(d_func(), void _q_resetButton())
- Q_PRIVATE_SLOT(d_func(), void _q_dataChanged(const QModelIndex &, const QModelIndex &))
- Q_PRIVATE_SLOT(d_func(), void _q_updateIndexBeforeChange())
- Q_PRIVATE_SLOT(d_func(), void _q_rowsInserted(const QModelIndex & parent, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_rowsRemoved(const QModelIndex & parent, int start, int end))
- Q_PRIVATE_SLOT(d_func(), void _q_modelDestroyed())
- Q_PRIVATE_SLOT(d_func(), void _q_modelReset())
-#if QT_CONFIG(completer)
- Q_PRIVATE_SLOT(d_func(), void _q_completerActivated(const QModelIndex &index))
-#endif
};
inline void QComboBox::addItem(const QString &atext, const QVariant &auserData)
diff --git a/src/widgets/widgets/qcombobox_p.h b/src/widgets/widgets/qcombobox_p.h
index 8e686ac79a..723d637ae2 100644
--- a/src/widgets/widgets/qcombobox_p.h
+++ b/src/widgets/widgets/qcombobox_p.h
@@ -27,7 +27,6 @@
#include "QtGui/qpainter.h"
#include "QtWidgets/qstyle.h"
#include "QtWidgets/qstyleoption.h"
-#include "QtCore/qpair.h"
#include "QtCore/qtimer.h"
#include "private/qwidget_p.h"
#include "QtCore/qpointer.h"
@@ -49,7 +48,11 @@ class QComboBoxListView : public QListView
{
Q_OBJECT
public:
- QComboBoxListView(QComboBox *cmb = nullptr) : combo(cmb) {}
+ QComboBoxListView(QComboBox *cmb = nullptr) : combo(cmb)
+ {
+ if (cmb)
+ setScreen(cmb->screen());
+ }
protected:
void resizeEvent(QResizeEvent *event) override
@@ -180,6 +183,7 @@ class Q_WIDGETS_EXPORT QComboBoxPrivateContainer : public QFrame
public:
QComboBoxPrivateContainer(QAbstractItemView *itemView, QComboBox *parent);
+ ~QComboBoxPrivateContainer();
QAbstractItemView *itemView() const;
void setItemView(QAbstractItemView *itemView);
int spacing() const;
@@ -315,24 +319,25 @@ public:
QComboBoxPrivateContainer* viewContainer();
void updateLineEditGeometry();
Qt::MatchFlags matchFlags() const;
- void _q_editingFinished();
- void _q_returnPressed();
- void _q_complete();
- void _q_itemSelected(const QModelIndex &item);
+ void editingFinished();
+ void returnPressed();
+ void complete();
+ void itemSelected(const QModelIndex &item);
bool contains(const QString &text, int role);
void emitActivated(const QModelIndex &index);
- void _q_emitHighlighted(const QModelIndex &index);
- void _q_emitCurrentIndexChanged(const QModelIndex &index);
- void _q_modelDestroyed();
- void _q_modelReset();
+ void emitHighlighted(const QModelIndex &index);
+ void emitCurrentIndexChanged(const QModelIndex &index);
+ void modelDestroyed();
+ void modelReset();
+ void updateMicroFocus() { q_func()->updateMicroFocus(); } // PMF connect doesn't handle default args
#if QT_CONFIG(completer)
- void _q_completerActivated(const QModelIndex &index);
+ void completerActivated(const QModelIndex &index);
#endif
- void _q_resetButton();
- void _q_dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
- void _q_updateIndexBeforeChange();
- void _q_rowsInserted(const QModelIndex &parent, int start, int end);
- void _q_rowsRemoved(const QModelIndex &parent, int start, int end);
+ void resetButton();
+ void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
+ void updateIndexBeforeChange();
+ void rowsInserted(const QModelIndex &parent, int start, int end);
+ void rowsRemoved(const QModelIndex &parent, int start, int end);
void updateArrow(QStyle::StateFlag state);
bool updateHoverControl(const QPoint &pos);
void trySetValidIndex();
@@ -353,6 +358,9 @@ public:
void updateFocusPolicy();
void showPopupFromMouseEvent(QMouseEvent *e);
void doHidePopup();
+ void updateCurrentText(const QString &text);
+ void connectModel();
+ void disconnectModel();
#ifdef Q_OS_MAC
void cleanupNativePopup();
@@ -369,15 +377,17 @@ public:
};
#endif
+ std::array<QMetaObject::Connection, 8> modelConnections;
QAbstractItemModel *model = nullptr;
QLineEdit *lineEdit = nullptr;
- QComboBoxPrivateContainer *container = nullptr;
+ QPointer<QComboBoxPrivateContainer> container;
#ifdef Q_OS_MAC
QPlatformMenu *m_platformMenu = nullptr;
#endif
QPersistentModelIndex currentIndex;
QPersistentModelIndex root;
QString placeholderText;
+ QString currentText;
QRect hoverRect;
QSize iconSize;
mutable QSize minimumSizeHint;
diff --git a/src/widgets/widgets/qcommandlinkbutton.cpp b/src/widgets/widgets/qcommandlinkbutton.cpp
index 2c59e78c1a..5c7d2601d9 100644
--- a/src/widgets/widgets/qcommandlinkbutton.cpp
+++ b/src/widgets/widgets/qcommandlinkbutton.cpp
@@ -172,7 +172,7 @@ bool QCommandLinkButtonPrivate::usingVistaStyle() const
//### This is a hack to detect if we are indeed running Vista style themed and not in classic
// When we add api to query for this, we should change this implementation to use it.
return q->property("_qt_usingVistaStyle").toBool()
- && q->style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal, nullptr) == 0;
+ && q->style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal, nullptr, q) == 0;
}
void QCommandLinkButtonPrivate::init()
@@ -189,7 +189,7 @@ void QCommandLinkButtonPrivate::init()
q->setIconSize(QSize(20, 20));
QStyleOptionButton opt;
q->initStyleOption(&opt);
- q->setIcon(q->style()->standardIcon(QStyle::SP_CommandLink, &opt));
+ q->setIcon(q->style()->standardIcon(QStyle::SP_CommandLink, &opt, q));
}
// Calculates the height of the description text based on widget width
@@ -325,9 +325,9 @@ void QCommandLinkButton::paintEvent(QPaintEvent *)
QSize pixmapSize = icon().actualSize(iconSize());
const int vOffset = isDown()
- ? style()->pixelMetric(QStyle::PM_ButtonShiftVertical, &option) : 0;
+ ? style()->pixelMetric(QStyle::PM_ButtonShiftVertical, &option, this) : 0;
const int hOffset = isDown()
- ? style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal, &option) : 0;
+ ? style()->pixelMetric(QStyle::PM_ButtonShiftHorizontal, &option, this) : 0;
//Draw icon
p.drawControl(QStyle::CE_PushButton, option);
diff --git a/src/widgets/widgets/qdatetimeedit.cpp b/src/widgets/widgets/qdatetimeedit.cpp
index 61cf20891b..01e52b2fa6 100644
--- a/src/widgets/widgets/qdatetimeedit.cpp
+++ b/src/widgets/widgets/qdatetimeedit.cpp
@@ -219,7 +219,7 @@ QDateTimeEdit::~QDateTimeEdit()
widget's date-range to start and end on the date of the new value of this
property.
- \sa date, time, minimumDateTime, maximumDateTime
+ \sa date, time, minimumDateTime, maximumDateTime, timeZone
*/
QDateTime QDateTimeEdit::dateTime() const
@@ -948,7 +948,7 @@ void QDateTimeEdit::setDisplayFormat(const QString &format)
d->value = d->value.toDate().startOfDay(d->timeZone);
}
d->updateEdit();
- d->_q_editorCursorPositionChanged(-1, 0);
+ d->editorCursorPositionChanged(-1, 0);
}
}
@@ -984,10 +984,16 @@ void QDateTimeEdit::setCalendarPopup(bool enable)
update();
}
+#if QT_DEPRECATED_SINCE(6, 10)
/*!
\property QDateTimeEdit::timeSpec
- \brief The current timespec used by the date time edit.
\since 4.4
+ \deprecated[6.10] Use QDateTimeEdit::timeZone instead.
+ \brief The current timespec used by the date time edit.
+
+ Since Qt 6.7 this is an indirect accessor for the timeZone property.
+
+ \sa QDateTimeEdit::timeZone
*/
Qt::TimeSpec QDateTimeEdit::timeSpec() const
@@ -1002,17 +1008,45 @@ void QDateTimeEdit::setTimeSpec(Qt::TimeSpec spec)
if (spec != d->timeZone.timeSpec()) {
switch (spec) {
case Qt::UTC:
- d->timeZone = QTimeZone::UTC;
+ setTimeZone(QTimeZone::UTC);
break;
case Qt::LocalTime:
- d->timeZone = QTimeZone::LocalTime;
+ setTimeZone(QTimeZone::LocalTime);
break;
default:
qWarning() << "Ignoring attempt to set time-spec" << spec
- << "which is not yet supported by QDateTimeEdit";
- // TODO: fix that QTBUG-80417.
+ << "which needs ancillary data: see setTimeZone()";
return;
}
+ }
+}
+#endif // 6.10 deprecation
+
+// TODO: enable user input to control timeZone, when the format includes it.
+/*!
+ \property QDateTimeEdit::timeZone
+ \since 6.7
+ \brief The current timezone used by the datetime editing widget
+
+ If the datetime format in use includes a timezone indicator - that is, a
+ \c{t}, \c{tt}, \c{ttt} or \c{tttt} format specifier - the user's input is
+ re-expressed in this timezone whenever it is parsed, overriding any timezone
+ the user may have specified.
+
+ \sa QDateTimeEdit::displayFormat
+*/
+
+QTimeZone QDateTimeEdit::timeZone() const
+{
+ Q_D(const QDateTimeEdit);
+ return d->timeZone;
+}
+
+void QDateTimeEdit::setTimeZone(const QTimeZone &zone)
+{
+ Q_D(QDateTimeEdit);
+ if (zone != d->timeZone) {
+ d->timeZone = zone;
d->updateTimeZone();
}
}
@@ -1297,6 +1331,7 @@ void QDateTimeEdit::focusInEvent(QFocusEvent *event)
case Qt::ActiveWindowFocusReason:
if (oldHasHadFocus)
return;
+ break;
case Qt::ShortcutFocusReason:
case Qt::TabFocusReason:
default:
@@ -1421,8 +1456,6 @@ QDateTime QDateTimeEdit::dateTimeFromText(const QString &text) const
QString copy = text;
int pos = d->edit->cursorPosition();
QValidator::State state = QValidator::Acceptable;
- // TODO: if the format specifies time-zone, d->timeZone should change as
- // determined by the parsed text.
return d->validateAndInterpret(copy, pos, state);
}
@@ -1450,16 +1483,11 @@ void QDateTimeEdit::fixup(QString &input) const
int copy = d->edit->cursorPosition();
QDateTime value = d->validateAndInterpret(input, copy, state, true);
- /*
- String was valid, but the datetime still is not; use the time that
- has the same distance from epoch.
- CorrectToPreviousValue correction is handled by QAbstractSpinBox.
- */
- if (!value.isValid() && d->correctionMode == QAbstractSpinBox::CorrectToNearestValue) {
- value = QDateTime::fromMSecsSinceEpoch(value.toMSecsSinceEpoch(),
- value.timeRepresentation());
+ // CorrectToPreviousValue correction is handled by QAbstractSpinBox.
+ // The value might not match the input if the input represents a date-time
+ // skipped over by its time representation, such as a spring-forward.
+ if (d->correctionMode == QAbstractSpinBox::CorrectToNearestValue)
input = textFromDateTime(value);
- }
}
@@ -1727,11 +1755,7 @@ QDateTime QDateTimeEditPrivate::convertTimeZone(const QDateTime &datetime)
QDateTime QDateTimeEditPrivate::dateTimeValue(QDate date, QTime time) const
{
- QDateTime when = QDateTime(date, time, timeZone);
- if (when.isValid())
- return when;
- // Hit a spring-forward gap
- return QDateTime::fromMSecsSinceEpoch(when.toMSecsSinceEpoch(), timeZone);
+ return QDateTime(date, time, timeZone);
}
void QDateTimeEditPrivate::updateTimeZone()
@@ -2013,6 +2037,8 @@ QDateTime QDateTimeEditPrivate::validateAndInterpret(QString &input, int &positi
StateNode tmp = parse(input, position, value.toDateTime(), fixup);
// Take note of any corrections imposed during parsing:
input = m_text;
+ // TODO: if the format specifies time-zone, update timeZone to match the
+ // parsed text; but we're in const context, so can't - QTBUG-118393.
// Impose this widget's time system:
tmp.value = tmp.value.toTimeZone(timeZone);
// ... but that might turn a valid datetime into an invalid one:
@@ -2135,11 +2161,10 @@ QDateTime QDateTimeEditPrivate::stepBy(int sectionIndex, int steps, bool test) c
true when date and time are valid, even if the date-time returned
isn't), so use the time that has the same distance from epoch.
*/
- if (setDigit(v, sectionIndex, val) && !v.isValid()) {
- auto msecsSinceEpoch = v.toMSecsSinceEpoch();
+ if (setDigit(v, sectionIndex, val) && getDigit(v, sectionIndex) != val
+ && sn.type & HourSectionMask && steps < 0) {
// decreasing from e.g 3am to 2am would get us back to 3am, but we want 1am
- if (steps < 0 && sn.type & HourSectionMask)
- msecsSinceEpoch -= 3600 * 1000;
+ auto msecsSinceEpoch = v.toMSecsSinceEpoch() - 3600 * 1000;
v = QDateTime::fromMSecsSinceEpoch(msecsSinceEpoch, v.timeRepresentation());
}
// if this sets year or month it will make
@@ -2272,7 +2297,7 @@ void QDateTimeEditPrivate::emitSignals(EmitPolicy ep, const QVariant &old)
\internal
*/
-void QDateTimeEditPrivate::_q_editorCursorPositionChanged(int oldpos, int newpos)
+void QDateTimeEditPrivate::editorCursorPositionChanged(int oldpos, int newpos)
{
if (ignoreCursorPositionChanged || specialValue())
return;
@@ -2330,7 +2355,7 @@ void QDateTimeEditPrivate::_q_editorCursorPositionChanged(int oldpos, int newpos
currentSectionIndex = s;
Q_ASSERT_X(currentSectionIndex < sectionNodes.size(),
- "QDateTimeEditPrivate::_q_editorCursorPositionChanged()",
+ "QDateTimeEditPrivate::editorCursorPositionChanged()",
qPrintable(QString::fromLatin1("Internal error (%1 %2)").
arg(currentSectionIndex).
arg(sectionNodes.size())));
diff --git a/src/widgets/widgets/qdatetimeedit.h b/src/widgets/widgets/qdatetimeedit.h
index acef0c5359..f7c0dd7374 100644
--- a/src/widgets/widgets/qdatetimeedit.h
+++ b/src/widgets/widgets/qdatetimeedit.h
@@ -5,7 +5,7 @@
#define QDATETIMEEDIT_H
#include <QtWidgets/qtwidgetsglobal.h>
-#include <QtCore/qdatetime.h>
+#include <QtCore/qtimezone.h>
#include <QtCore/qcalendar.h>
#include <QtCore/qvariant.h>
#include <QtWidgets/qabstractspinbox.h>
@@ -39,7 +39,10 @@ class Q_WIDGETS_EXPORT QDateTimeEdit : public QAbstractSpinBox
Q_PROPERTY(bool calendarPopup READ calendarPopup WRITE setCalendarPopup)
Q_PROPERTY(int currentSectionIndex READ currentSectionIndex WRITE setCurrentSectionIndex)
Q_PROPERTY(int sectionCount READ sectionCount)
+#if QT_DEPRECATED_SINCE(6, 10)
Q_PROPERTY(Qt::TimeSpec timeSpec READ timeSpec WRITE setTimeSpec)
+#endif
+ Q_PROPERTY(QTimeZone timeZone READ timeZone WRITE setTimeZone)
public:
enum Section { // a sub-type of QDateTimeParser's like-named enum.
NoSection = 0x0000,
@@ -125,8 +128,14 @@ public:
bool calendarPopup() const;
void setCalendarPopup(bool enable);
+#if QT_DEPRECATED_SINCE(6, 10)
+ QT_DEPRECATED_VERSION_X_6_10("Use timeZone() instead")
Qt::TimeSpec timeSpec() const;
+ QT_DEPRECATED_VERSION_X_6_10("Use setTimeZone() instead")
void setTimeSpec(Qt::TimeSpec spec);
+#endif
+ QTimeZone timeZone() const;
+ void setTimeZone(const QTimeZone &zone);
QSize sizeHint() const override;
diff --git a/src/widgets/widgets/qdatetimeedit_p.h b/src/widgets/widgets/qdatetimeedit_p.h
index cfabf65dda..215ee75bfe 100644
--- a/src/widgets/widgets/qdatetimeedit_p.h
+++ b/src/widgets/widgets/qdatetimeedit_p.h
@@ -28,6 +28,7 @@
#include "private/qdatetimeparser_p.h"
#include "qdebug.h"
+#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
@@ -49,7 +50,7 @@ public:
void emitSignals(EmitPolicy ep, const QVariant &old) override;
QString textFromValue(const QVariant &f) const override;
QVariant valueFromText(const QString &f) const override;
- void _q_editorCursorPositionChanged(int oldpos, int newpos) override;
+ void editorCursorPositionChanged(int oldpos, int newpos) override;
void interpret(EmitPolicy ep) override;
void clearCache() const override;
QStyle::SubControl newHoverControl(const QPoint &pos) override;
diff --git a/src/widgets/widgets/qdial.cpp b/src/widgets/widgets/qdial.cpp
index e16b6eadaf..14e96f8dc3 100644
--- a/src/widgets/widgets/qdial.cpp
+++ b/src/widgets/widgets/qdial.cpp
@@ -58,6 +58,8 @@ int QDialPrivate::bound(int val) const
if (wrapping) {
if ((val >= minimum) && (val <= maximum))
return val;
+ if (minimum == maximum)
+ return minimum;
val = minimum + ((val - minimum) % (maximum - minimum));
if (val < minimum)
val += maximum - minimum;
diff --git a/src/widgets/widgets/qdialogbuttonbox.cpp b/src/widgets/widgets/qdialogbuttonbox.cpp
index 1f8bdc0f94..30c68ad18b 100644
--- a/src/widgets/widgets/qdialogbuttonbox.cpp
+++ b/src/widgets/widgets/qdialogbuttonbox.cpp
@@ -14,6 +14,9 @@
#include <QtGui/qaction.h>
#include "qdialogbuttonbox.h"
+#include "qdialogbuttonbox_p.h"
+
+#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
@@ -53,7 +56,7 @@ QT_BEGIN_NAMESPACE
the buttons (or button texts) yourself and add them to the button box,
specifying their role.
- \snippet dialogs/extension/finddialog.cpp 1
+ \snippet dialogs/dialogs.cpp buttonbox
Alternatively, QDialogButtonBox provides several standard buttons (e.g. OK, Cancel, Save)
that you can use. They exist as flags so you can OR them together in the constructor.
@@ -111,39 +114,25 @@ QT_BEGIN_NAMESPACE
\sa QMessageBox, QPushButton, QDialog
*/
-
-class QDialogButtonBoxPrivate : public QWidgetPrivate
+QDialogButtonBoxPrivate::QDialogButtonBoxPrivate(Qt::Orientation orient)
+ : orientation(orient), buttonLayout(nullptr), center(false)
{
- Q_DECLARE_PUBLIC(QDialogButtonBox)
-
-public:
- QDialogButtonBoxPrivate(Qt::Orientation orient);
-
- QList<QAbstractButton *> buttonLists[QDialogButtonBox::NRoles];
- QHash<QPushButton *, QDialogButtonBox::StandardButton> standardButtonHash;
-
- Qt::Orientation orientation;
- QDialogButtonBox::ButtonLayout layoutPolicy;
- QBoxLayout *buttonLayout;
- bool internalRemove;
- bool center;
+ struct EventFilter : public QObject
+ {
+ EventFilter(QDialogButtonBoxPrivate *d) : d(d) {};
+
+ bool eventFilter(QObject *obj, QEvent *event) override
+ {
+ QAbstractButton *button = qobject_cast<QAbstractButton *>(obj);
+ return button ? d->handleButtonShowAndHide(button, event) : false;
+ }
- void createStandardButtons(QDialogButtonBox::StandardButtons buttons);
+ private:
+ QDialogButtonBoxPrivate *d;
- void layoutButtons();
- void initLayout();
- void resetLayout();
- QPushButton *createButton(QDialogButtonBox::StandardButton button, bool doLayout = true);
- void addButton(QAbstractButton *button, QDialogButtonBox::ButtonRole role, bool doLayout = true);
- void _q_handleButtonDestroyed();
- void _q_handleButtonClicked();
- void addButtonsToLayout(const QList<QAbstractButton *> &buttonList, bool reverse);
- void retranslateStrings();
-};
+ };
-QDialogButtonBoxPrivate::QDialogButtonBoxPrivate(Qt::Orientation orient)
- : orientation(orient), buttonLayout(nullptr), internalRemove(false), center(false)
-{
+ filter.reset(new EventFilter(this));
}
void QDialogButtonBoxPrivate::initLayout()
@@ -177,7 +166,6 @@ void QDialogButtonBoxPrivate::initLayout()
void QDialogButtonBoxPrivate::resetLayout()
{
- //delete buttonLayout;
initLayout();
layoutButtons();
}
@@ -201,6 +189,7 @@ void QDialogButtonBoxPrivate::layoutButtons()
Q_Q(QDialogButtonBox);
const int MacGap = 36 - 8; // 8 is the default gap between a widget and a spacer item
+ QBoolBlocker blocker(ignoreShowAndHide);
for (int i = buttonLayout->count() - 1; i >= 0; --i) {
QLayoutItem *item = buttonLayout->takeAt(i);
if (QWidget *widget = item->widget())
@@ -293,16 +282,20 @@ void QDialogButtonBoxPrivate::layoutButtons()
++currentLayout;
}
- QWidget *lastWidget = nullptr;
- q->setFocusProxy(nullptr);
+ QWidgetList layoutWidgets;
for (int i = 0; i < buttonLayout->count(); ++i) {
- QLayoutItem *item = buttonLayout->itemAt(i);
- if (QWidget *widget = item->widget()) {
- if (lastWidget)
- QWidget::setTabOrder(lastWidget, widget);
- else
- q->setFocusProxy(widget);
- lastWidget = widget;
+ if (auto *widget = buttonLayout->itemAt(i)->widget())
+ layoutWidgets << widget;
+ }
+
+ q->setFocusProxy(nullptr);
+ if (!layoutWidgets.isEmpty()) {
+ QWidget *prev = layoutWidgets.constLast();
+ for (QWidget *here : layoutWidgets) {
+ QWidget::setTabOrder(prev, here);
+ prev = here;
+ if (auto *pushButton = qobject_cast<QPushButton *>(prev); pushButton && pushButton->isDefault())
+ q->setFocusProxy(pushButton);
}
}
@@ -311,7 +304,7 @@ void QDialogButtonBoxPrivate::layoutButtons()
}
QPushButton *QDialogButtonBoxPrivate::createButton(QDialogButtonBox::StandardButton sbutton,
- bool doLayout)
+ LayoutRule layoutRule)
{
Q_Q(QDialogButtonBox);
int icon = 0;
@@ -386,7 +379,7 @@ QPushButton *QDialogButtonBoxPrivate::createButton(QDialogButtonBox::StandardBut
if (Q_UNLIKELY(role == QPlatformDialogHelper::InvalidRole))
qWarning("QDialogButtonBox::createButton: Invalid ButtonRole, button not added");
else
- addButton(button, static_cast<QDialogButtonBox::ButtonRole>(role), doLayout);
+ addButton(button, static_cast<QDialogButtonBox::ButtonRole>(role), layoutRule);
#if QT_CONFIG(shortcut)
const QKeySequence standardShortcut = QGuiApplicationPrivate::platformTheme()->standardButtonShortcut(sbutton);
if (!standardShortcut.isEmpty())
@@ -396,23 +389,36 @@ QPushButton *QDialogButtonBoxPrivate::createButton(QDialogButtonBox::StandardBut
}
void QDialogButtonBoxPrivate::addButton(QAbstractButton *button, QDialogButtonBox::ButtonRole role,
- bool doLayout)
+ LayoutRule layoutRule, AddRule addRule)
{
- Q_Q(QDialogButtonBox);
- QObject::connect(button, SIGNAL(clicked()), q, SLOT(_q_handleButtonClicked()));
- QObject::connect(button, SIGNAL(destroyed()), q, SLOT(_q_handleButtonDestroyed()));
buttonLists[role].append(button);
- if (doLayout)
+ switch (addRule) {
+ case AddRule::Connect:
+ QObjectPrivate::connect(button, &QAbstractButton::clicked,
+ this, &QDialogButtonBoxPrivate::handleButtonClicked);
+ QObjectPrivate::connect(button, &QAbstractButton::destroyed,
+ this, &QDialogButtonBoxPrivate::handleButtonDestroyed);
+ button->installEventFilter(filter.get());
+ break;
+ case AddRule::SkipConnect:
+ break;
+ }
+
+ switch (layoutRule) {
+ case LayoutRule::DoLayout:
layoutButtons();
+ break;
+ case LayoutRule::SkipLayout:
+ break;
+ }
}
void QDialogButtonBoxPrivate::createStandardButtons(QDialogButtonBox::StandardButtons buttons)
{
uint i = QDialogButtonBox::FirstButton;
while (i <= QDialogButtonBox::LastButton) {
- if (i & buttons) {
- createButton(QDialogButtonBox::StandardButton(i), false);
- }
+ if (i & buttons)
+ createButton(QDialogButtonBox::StandardButton(i), LayoutRule::SkipLayout);
i = i << 1;
}
layoutButtons();
@@ -420,13 +426,10 @@ void QDialogButtonBoxPrivate::createStandardButtons(QDialogButtonBox::StandardBu
void QDialogButtonBoxPrivate::retranslateStrings()
{
- typedef QHash<QPushButton *, QDialogButtonBox::StandardButton>::iterator Iterator;
-
- const Iterator end = standardButtonHash.end();
- for (Iterator it = standardButtonHash.begin(); it != end; ++it) {
- const QString text = QGuiApplicationPrivate::platformTheme()->standardButtonText(it.value());
+ for (auto &&[key, value] : std::as_const(standardButtonHash).asKeyValueRange()) {
+ const QString text = QGuiApplicationPrivate::platformTheme()->standardButtonText(value);
if (!text.isEmpty())
- it.key()->setText(text);
+ key->setText(text);
}
}
@@ -482,6 +485,14 @@ QDialogButtonBox::QDialogButtonBox(StandardButtons buttons, Qt::Orientation orie
*/
QDialogButtonBox::~QDialogButtonBox()
{
+ Q_D(QDialogButtonBox);
+
+ d->ignoreShowAndHide = true;
+
+ // QObjectPrivate::connect requires explicit disconnect in destructor
+ // otherwise the connection may kick in on child destruction and reach
+ // the parent's destroyed private object
+ d->disconnectAll();
}
/*!
@@ -636,31 +647,42 @@ void QDialogButtonBox::clear()
d->standardButtonHash.clear();
for (int i = 0; i < NRoles; ++i) {
QList<QAbstractButton *> &list = d->buttonLists[i];
- while (list.size()) {
- QAbstractButton *button = list.takeAt(0);
- QObject::disconnect(button, SIGNAL(destroyed()), this, SLOT(_q_handleButtonDestroyed()));
+ for (auto button : std::as_const(list)) {
+ QObjectPrivate::disconnect(button, &QAbstractButton::destroyed,
+ d, &QDialogButtonBoxPrivate::handleButtonDestroyed);
delete button;
}
+ list.clear();
}
}
/*!
- Returns a list of all the buttons that have been added to the button box.
+ Returns a list of all buttons that have been added to the button box.
\sa buttonRole(), addButton(), removeButton()
*/
QList<QAbstractButton *> QDialogButtonBox::buttons() const
{
Q_D(const QDialogButtonBox);
+ return d->allButtons();
+}
+
+QList<QAbstractButton *> QDialogButtonBoxPrivate::visibleButtons() const
+{
QList<QAbstractButton *> finalList;
- for (int i = 0; i < NRoles; ++i) {
- const QList<QAbstractButton *> &list = d->buttonLists[i];
+ for (int i = 0; i < QDialogButtonBox::NRoles; ++i) {
+ const QList<QAbstractButton *> &list = buttonLists[i];
for (int j = 0; j < list.size(); ++j)
finalList.append(list.at(j));
}
return finalList;
}
+QList<QAbstractButton *> QDialogButtonBoxPrivate::allButtons() const
+{
+ return visibleButtons() << hiddenButtons.keys();
+}
+
/*!
Returns the button role for the specified \a button. This function returns
\l InvalidRole if \a button is \nullptr or has not been added to the button box.
@@ -677,7 +699,7 @@ QDialogButtonBox::ButtonRole QDialogButtonBox::buttonRole(QAbstractButton *butto
return ButtonRole(i);
}
}
- return InvalidRole;
+ return d->hiddenButtons.value(button, InvalidRole);
}
/*!
@@ -688,27 +710,45 @@ QDialogButtonBox::ButtonRole QDialogButtonBox::buttonRole(QAbstractButton *butto
void QDialogButtonBox::removeButton(QAbstractButton *button)
{
Q_D(QDialogButtonBox);
+ d->removeButton(button, QDialogButtonBoxPrivate::RemoveReason::ManualRemove);
+}
+/*!
+ \internal
+ Removes \param button.
+ \param reason determines the behavior following the removal:
+ \list
+ \li \c ManualRemove disconnects all signals and removes the button from standardButtonHash.
+ \li \c HideEvent keeps connections alive, standard buttons remain in standardButtonHash.
+ \li \c Destroyed removes the button from standardButtonHash. Signals remain untouched, because
+ the button might already be only a QObject, the destructor of which handles disconnecting.
+ \endlist
+ */
+void QDialogButtonBoxPrivate::removeButton(QAbstractButton *button, RemoveReason reason)
+{
if (!button)
return;
- // Remove it from the standard button hash first and then from the roles
- d->standardButtonHash.remove(reinterpret_cast<QPushButton *>(button));
- for (int i = 0; i < NRoles; ++i) {
- QList<QAbstractButton *> &list = d->buttonLists[i];
- for (int j = 0; j < list.size(); ++j) {
- if (list.at(j) == button) {
- list.takeAt(j);
- if (!d->internalRemove) {
- disconnect(button, SIGNAL(clicked()), this, SLOT(_q_handleButtonClicked()));
- disconnect(button, SIGNAL(destroyed()), this, SLOT(_q_handleButtonDestroyed()));
- }
- break;
- }
- }
- }
- if (!d->internalRemove)
+ // Remove button from hidden buttons and roles
+ hiddenButtons.remove(button);
+ for (int i = 0; i < QDialogButtonBox::NRoles; ++i)
+ buttonLists[i].removeOne(button);
+
+ switch (reason) {
+ case RemoveReason::ManualRemove:
button->setParent(nullptr);
+ QObjectPrivate::disconnect(button, &QAbstractButton::clicked,
+ this, &QDialogButtonBoxPrivate::handleButtonClicked);
+ QObjectPrivate::disconnect(button, &QAbstractButton::destroyed,
+ this, &QDialogButtonBoxPrivate::handleButtonDestroyed);
+ button->removeEventFilter(filter.get());
+ Q_FALLTHROUGH();
+ case RemoveReason::Destroyed:
+ standardButtonHash.remove(reinterpret_cast<QPushButton *>(button));
+ break;
+ case RemoveReason::HideEvent:
+ break;
+ }
}
/*!
@@ -778,8 +818,8 @@ void QDialogButtonBox::setStandardButtons(StandardButtons buttons)
{
Q_D(QDialogButtonBox);
// Clear out all the old standard buttons, then recreate them.
- qDeleteAll(d->standardButtonHash.keys());
- d->standardButtonHash.clear();
+ const auto toDelete = std::exchange(d->standardButtonHash, {});
+ qDeleteAll(toDelete.keyBegin(), toDelete.keyEnd());
d->createStandardButtons(buttons);
}
@@ -820,7 +860,7 @@ QDialogButtonBox::StandardButton QDialogButtonBox::standardButton(QAbstractButto
return d->standardButtonHash.value(static_cast<QPushButton *>(button));
}
-void QDialogButtonBoxPrivate::_q_handleButtonClicked()
+void QDialogButtonBoxPrivate::handleButtonClicked()
{
Q_Q(QDialogButtonBox);
if (QAbstractButton *button = qobject_cast<QAbstractButton *>(q->sender())) {
@@ -854,13 +894,44 @@ void QDialogButtonBoxPrivate::_q_handleButtonClicked()
}
}
-void QDialogButtonBoxPrivate::_q_handleButtonDestroyed()
+void QDialogButtonBoxPrivate::handleButtonDestroyed()
+{
+ Q_Q(QDialogButtonBox);
+ if (QObject *object = q->sender())
+ removeButton(reinterpret_cast<QAbstractButton *>(object), RemoveReason::Destroyed);
+}
+
+bool QDialogButtonBoxPrivate::handleButtonShowAndHide(QAbstractButton *button, QEvent *event)
{
Q_Q(QDialogButtonBox);
- if (QObject *object = q->sender()) {
- QBoolBlocker skippy(internalRemove);
- q->removeButton(reinterpret_cast<QAbstractButton *>(object));
+
+ const QEvent::Type type = event->type();
+
+ if ((type != QEvent::HideToParent && type != QEvent::ShowToParent) || ignoreShowAndHide)
+ return false;
+
+ switch (type) {
+ case QEvent::HideToParent: {
+ const QDialogButtonBox::ButtonRole role = q->buttonRole(button);
+ if (role != QDialogButtonBox::ButtonRole::InvalidRole) {
+ removeButton(button, RemoveReason::HideEvent);
+ hiddenButtons.insert(button, role);
+ layoutButtons();
+ }
+ break;
+ }
+ case QEvent::ShowToParent:
+ if (hiddenButtons.contains(button)) {
+ const auto role = hiddenButtons.take(button);
+ addButton(button, role, LayoutRule::DoLayout, AddRule::SkipConnect);
+ if (role == QDialogButtonBox::AcceptRole)
+ ensureFirstAcceptIsDefault();
+ }
+ break;
+ default: break;
}
+
+ return false;
}
/*!
@@ -918,36 +989,80 @@ void QDialogButtonBox::changeEvent(QEvent *event)
}
}
+void QDialogButtonBoxPrivate::ensureFirstAcceptIsDefault()
+{
+ Q_Q(QDialogButtonBox);
+ const QList<QAbstractButton *> &acceptRoleList = buttonLists[QDialogButtonBox::AcceptRole];
+ QPushButton *firstAcceptButton = acceptRoleList.isEmpty()
+ ? nullptr
+ : qobject_cast<QPushButton *>(acceptRoleList.at(0));
+
+ if (!firstAcceptButton)
+ return;
+
+ bool hasDefault = false;
+ QWidget *dialog = nullptr;
+ QWidget *p = q;
+ while (p && !p->isWindow()) {
+ p = p->parentWidget();
+ if ((dialog = qobject_cast<QDialog *>(p)))
+ break;
+ }
+
+ QWidget *parent = dialog ? dialog : q;
+ Q_ASSERT(parent);
+
+ const auto pushButtons = parent->findChildren<QPushButton *>();
+ for (QPushButton *pushButton : pushButtons) {
+ if (pushButton->isDefault() && pushButton != firstAcceptButton) {
+ hasDefault = true;
+ break;
+ }
+ }
+ if (!hasDefault && firstAcceptButton) {
+ firstAcceptButton->setDefault(true);
+ // When the QDialogButtonBox is focused, and it doesn't have an
+ // explicit focus widget, it will transfer focus to its focus
+ // proxy, which is the first button in the layout. This behavior,
+ // combined with the behavior that QPushButtons in a QDialog will
+ // by default have their autoDefault set to true, results in the
+ // focus proxy/first button stealing the default button status
+ // immediately when the button box is focused, which is not what
+ // we want. Account for this by explicitly making the firstAcceptButton
+ // focused as well, unless an explicit focus widget has been set, or
+ // a dialog child has Qt::StrongFocus.
+ if (dialog && !(QWidgetPrivate::get(dialog)->hasChildWithFocusPolicy(Qt::StrongFocus, q)
+ || dialog->focusWidget()))
+ firstAcceptButton->setFocus();
+ }
+}
+
+void QDialogButtonBoxPrivate::disconnectAll()
+{
+ Q_Q(QDialogButtonBox);
+ const auto buttons = q->findChildren<QAbstractButton *>();
+ for (auto *button : buttons)
+ button->disconnect(q);
+}
+
/*!
\reimp
*/
bool QDialogButtonBox::event(QEvent *event)
{
Q_D(QDialogButtonBox);
- if (event->type() == QEvent::Show) {
- QList<QAbstractButton *> acceptRoleList = d->buttonLists[AcceptRole];
- QPushButton *firstAcceptButton = acceptRoleList.isEmpty() ? 0 : qobject_cast<QPushButton *>(acceptRoleList.at(0));
- bool hasDefault = false;
- QWidget *dialog = nullptr;
- QWidget *p = this;
- while (p && !p->isWindow()) {
- p = p->parentWidget();
- if ((dialog = qobject_cast<QDialog *>(p)))
- break;
- }
+ switch (event->type()) {
+ case QEvent::Show:
+ d->ensureFirstAcceptIsDefault();
+ break;
- const auto pbs = (dialog ? dialog : this)->findChildren<QPushButton *>();
- for (QPushButton *pb : pbs) {
- if (pb->isDefault() && pb != firstAcceptButton) {
- hasDefault = true;
- break;
- }
- }
- if (!hasDefault && firstAcceptButton)
- firstAcceptButton->setDefault(true);
- }else if (event->type() == QEvent::LanguageChange) {
+ case QEvent::LanguageChange:
d->retranslateStrings();
+ break;
+
+ default: break;
}
+
return QWidget::event(event);
}
diff --git a/src/widgets/widgets/qdialogbuttonbox.h b/src/widgets/widgets/qdialogbuttonbox.h
index f6a0371d6c..d967494d0d 100644
--- a/src/widgets/widgets/qdialogbuttonbox.h
+++ b/src/widgets/widgets/qdialogbuttonbox.h
@@ -120,8 +120,6 @@ protected:
private:
Q_DISABLE_COPY(QDialogButtonBox)
Q_DECLARE_PRIVATE(QDialogButtonBox)
- Q_PRIVATE_SLOT(d_func(), void _q_handleButtonClicked())
- Q_PRIVATE_SLOT(d_func(), void _q_handleButtonDestroyed())
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QDialogButtonBox::StandardButtons)
diff --git a/src/widgets/widgets/qdialogbuttonbox_p.h b/src/widgets/widgets/qdialogbuttonbox_p.h
new file mode 100644
index 0000000000..c3d7e03489
--- /dev/null
+++ b/src/widgets/widgets/qdialogbuttonbox_p.h
@@ -0,0 +1,80 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QDIALOGBUTTONBOX_P_H
+#define QDIALOGBUTTONBOX_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 <private/qwidget_p.h>
+#include <qdialogbuttonbox.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QDialogButtonBoxPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QDialogButtonBox)
+
+public:
+ enum class RemoveReason {
+ HideEvent,
+ ManualRemove,
+ Destroyed,
+ };
+ enum class LayoutRule {
+ DoLayout,
+ SkipLayout,
+ };
+ enum class AddRule {
+ Connect,
+ SkipConnect,
+ };
+
+ QDialogButtonBoxPrivate(Qt::Orientation orient);
+
+ QList<QAbstractButton *> buttonLists[QDialogButtonBox::NRoles];
+ QHash<QPushButton *, QDialogButtonBox::StandardButton> standardButtonHash;
+ QHash<QAbstractButton *, QDialogButtonBox::ButtonRole> hiddenButtons;
+
+ Qt::Orientation orientation;
+ QDialogButtonBox::ButtonLayout layoutPolicy;
+ QBoxLayout *buttonLayout;
+ std::unique_ptr<QObject> filter;
+ bool center;
+ bool ignoreShowAndHide = false;
+
+ void createStandardButtons(QDialogButtonBox::StandardButtons buttons);
+
+ void removeButton(QAbstractButton *button, RemoveReason reason);
+ void layoutButtons();
+ void initLayout();
+ void resetLayout();
+ QPushButton *createButton(QDialogButtonBox::StandardButton button,
+ LayoutRule layoutRule = LayoutRule::DoLayout);
+ void addButton(QAbstractButton *button, QDialogButtonBox::ButtonRole role,
+ LayoutRule layoutRule = LayoutRule::DoLayout,
+ AddRule addRule = AddRule::Connect);
+ void handleButtonDestroyed();
+ void handleButtonClicked();
+ bool handleButtonShowAndHide(QAbstractButton *button, QEvent *event);
+ void addButtonsToLayout(const QList<QAbstractButton *> &buttonList, bool reverse);
+ void ensureFirstAcceptIsDefault();
+ void retranslateStrings();
+ void disconnectAll();
+ QList<QAbstractButton *> allButtons() const;
+ QList<QAbstractButton *> visibleButtons() const;
+ QDialogButtonBox::ButtonRole buttonRole(QAbstractButton *button) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDIALOGBUTTONBOX_P_H
diff --git a/src/widgets/widgets/qdockarealayout.cpp b/src/widgets/widgets/qdockarealayout.cpp
index 2e3602e47a..da0e987171 100644
--- a/src/widgets/widgets/qdockarealayout.cpp
+++ b/src/widgets/widgets/qdockarealayout.cpp
@@ -171,6 +171,38 @@ QDockAreaLayoutItem
return *this;
}
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QDockAreaLayoutItem *item)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace();
+ return item ? dbg << *item : dbg << "QDockAreaLayoutItem(0x0)";
+}
+
+QDebug operator<<(QDebug dbg, const QDockAreaLayoutItem &item)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace();
+ dbg << "QDockAreaLayoutItem(" << static_cast<const void *>(&item) << "->";
+ if (item.widgetItem) {
+ QWidget *widget = item.widgetItem->widget();
+ if (auto *dockWidget = qobject_cast<QDockWidget *>(widget)) {
+ dbg << "widgetItem(" << dockWidget << ")";
+ } else if (auto *groupWindow = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
+ dbg << "widgetItem(" << groupWindow << "->(" << groupWindow->dockWidgets() << "))";
+ } else {
+ dbg << "widgetItem(" << widget << ")";
+ }
+ } else if (item.subinfo) {
+ dbg << "subInfo(" << item.subinfo << "->(" << item.subinfo->item_list << ")";
+ } else if (item.placeHolderItem) {
+ dbg << "placeHolderItem(" << item.placeHolderItem << ")";
+ }
+ dbg << ")";
+ return dbg;
+}
+#endif // QT_NO_DEBUG_STREAM
+
/******************************************************************************
** QDockAreaLayoutInfo
*/
@@ -986,6 +1018,14 @@ void QDockAreaLayoutInfo::remove(const QList<int> &path)
}
}
+void QDockAreaLayoutInfo::remove(QWidget *widget)
+{
+ const QList<int> path = indexOf(widget);
+ if (path.isEmpty())
+ return;
+ remove(path);
+}
+
QLayoutItem *QDockAreaLayoutInfo::plug(const QList<int> &path)
{
Q_ASSERT(!path.isEmpty());
@@ -1090,6 +1130,21 @@ static QRect dockedGeometry(QWidget *widget)
return result;
}
+bool QDockAreaLayoutInfo::hasGapItem(const QList<int> &path) const
+{
+ // empty path has no gap item
+ if (path.isEmpty())
+ return false;
+
+ // Index -1 isn't a gap
+ // Index out of range points at a position to be created. That isn't a gap either.
+ const int index = path.constFirst();
+ if (index < 0 || index >= item_list.count())
+ return false;
+
+ return item_list[index].flags & QDockAreaLayoutItem::GapItem;
+}
+
bool QDockAreaLayoutInfo::insertGap(const QList<int> &path, QLayoutItem *dockWidgetItem)
{
Q_ASSERT(!path.isEmpty());
@@ -1101,8 +1156,6 @@ bool QDockAreaLayoutInfo::insertGap(const QList<int> &path, QLayoutItem *dockWid
index = -index - 1;
}
-// dump(qDebug() << "insertGap() before:" << index << tabIndex, *this, QString());
-
if (path.size() > 1) {
QDockAreaLayoutItem &item = item_list[index];
@@ -1731,6 +1784,26 @@ QLayoutItem *QDockAreaLayoutInfo::takeAt(int *x, int index)
return nullptr;
}
+// Add a dock widget or dock widget group window to the item list
+void QDockAreaLayoutInfo::add(QWidget *widget)
+{
+ // Do not add twice
+ if (!indexOf(widget).isEmpty())
+ return;
+
+ if (auto *dockWidget = qobject_cast<QDockWidget *>(widget)) {
+ item_list.append(QDockAreaLayoutItem(new QDockWidgetItem(dockWidget)));
+ return;
+ }
+
+ if (auto *groupWindow = qobject_cast<QDockWidgetGroupWindow *>(widget)) {
+ item_list.append(QDockAreaLayoutItem(new QDockWidgetGroupWindowItem(groupWindow)));
+ return;
+ }
+
+ qFatal("Coding error. Add supports only QDockWidget and QDockWidgetGroupWindow");
+}
+
void QDockAreaLayoutInfo::deleteAllLayoutItems()
{
for (int i = 0; i < item_list.size(); ++i) {
@@ -1924,6 +1997,7 @@ bool QDockAreaLayoutInfo::restoreState(QDataStream &stream, QList<QDockWidget*>
if (testing) {
//was it is not really added to the layout, we need to delete the object here
delete item.widgetItem;
+ item.widgetItem = nullptr;
}
}
} else if (nextMarker == SequenceMarker) {
@@ -1989,14 +2063,20 @@ void QDockAreaLayoutInfo::updateSeparatorWidgets() const
break;
QWidget *sepWidget;
- if (j < separatorWidgets.size() && separatorWidgets.at(j)) {
+ if (j < separatorWidgets.size()) {
sepWidget = separatorWidgets.at(j);
+ if (!sepWidget) {
+ qWarning("QDockAreaLayoutInfo::updateSeparatorWidgets: null separator widget");
+ sepWidget = mainWindowLayout()->getSeparatorWidget();
+ separatorWidgets[j] = sepWidget;
+ }
} else {
sepWidget = mainWindowLayout()->getSeparatorWidget();
separatorWidgets.append(sepWidget);
}
j++;
+ Q_ASSERT(sepWidget);
sepWidget->raise();
QRect sepRect = separatorRect(i).adjusted(-2, -2, 2, 2);
@@ -2009,7 +2089,6 @@ void QDockAreaLayoutInfo::updateSeparatorWidgets() const
separatorWidgets[k]->hide();
}
separatorWidgets.resize(j);
- Q_ASSERT(separatorWidgets.size() == j);
}
/*! \internal
@@ -3271,12 +3350,18 @@ void QDockAreaLayout::updateSeparatorWidgets() const
QWidget *sepWidget;
if (j < separatorWidgets.size()) {
sepWidget = separatorWidgets.at(j);
+ if (!sepWidget) {
+ qWarning("QDockAreaLayout::updateSeparatorWidgets: null separator widget");
+ sepWidget = qt_mainwindow_layout(mainWindow)->getSeparatorWidget();
+ separatorWidgets[j] = sepWidget;
+ }
} else {
sepWidget = qt_mainwindow_layout(mainWindow)->getSeparatorWidget();
separatorWidgets.append(sepWidget);
}
j++;
+ Q_ASSERT(sepWidget);
sepWidget->raise();
QRect sepRect = separatorRect(i).adjusted(-2, -2, 2, 2);
diff --git a/src/widgets/widgets/qdockarealayout_p.h b/src/widgets/widgets/qdockarealayout_p.h
index cf998cf665..aa39bf9913 100644
--- a/src/widgets/widgets/qdockarealayout_p.h
+++ b/src/widgets/widgets/qdockarealayout_p.h
@@ -18,7 +18,6 @@
#include <QtWidgets/private/qtwidgetsglobal_p.h>
#include "QtWidgets/qlayout.h"
#include "QtCore/qlist.h"
-#include "QtCore/qpair.h"
#include "QtCore/qrect.h"
QT_REQUIRE_CONFIG(dockwidget);
@@ -73,6 +72,10 @@ struct Q_AUTOTEST_EXPORT QDockAreaLayoutItem
int pos;
int size;
uint flags;
+#ifndef QT_NO_DEBUG_STREAM
+ friend Q_AUTOTEST_EXPORT QDebug operator<<(QDebug dbg, const QDockAreaLayoutItem &item);
+ friend Q_AUTOTEST_EXPORT QDebug operator<<(QDebug dbg, const QDockAreaLayoutItem *item);
+#endif
};
class Q_AUTOTEST_EXPORT QPlaceHolderItem
@@ -105,6 +108,7 @@ public:
QList<int> gapIndex(const QPoint &pos, bool nestingEnabled,
TabMode tabMode) const;
void remove(const QList<int> &path);
+ void remove(QWidget *widget);
void unnest(int index);
void split(int index, Qt::Orientation orientation, QLayoutItem *dockWidgetItem);
#if QT_CONFIG(tabbar)
@@ -132,6 +136,7 @@ public:
void clear();
bool isEmpty() const;
+ bool hasGapItem(const QList<int> &path) const;
bool onlyHasPlaceholders() const;
bool hasFixedSize() const;
QList<int> findSeparator(const QPoint &pos) const;
@@ -151,6 +156,7 @@ public:
QLayoutItem *itemAt(int *x, int index) const;
QLayoutItem *takeAt(int *x, int index);
+ void add(QWidget *widget);
void deleteAllLayoutItems();
QMainWindowLayout *mainWindowLayout() const;
diff --git a/src/widgets/widgets/qdockwidget.cpp b/src/widgets/widgets/qdockwidget.cpp
index 375bd3daae..706306000c 100644
--- a/src/widgets/widgets/qdockwidget.cpp
+++ b/src/widgets/widgets/qdockwidget.cpp
@@ -128,33 +128,12 @@ bool QDockWidgetTitleButton::event(QEvent *event)
return QAbstractButton::event(event);
}
-static inline bool isWindowsStyle(const QStyle *style)
-{
- // Note: QStyleSheetStyle inherits QWindowsStyle
- const QStyle *effectiveStyle = style;
-
-#if QT_CONFIG(style_stylesheet)
- if (style->inherits("QStyleSheetStyle"))
- effectiveStyle = static_cast<const QStyleSheetStyle *>(style)->baseStyle();
-#endif
-#if !defined(QT_NO_STYLE_PROXY)
- if (style->inherits("QProxyStyle"))
- effectiveStyle = static_cast<const QProxyStyle *>(style)->baseStyle();
-#endif
-
- return effectiveStyle->inherits("QWindowsStyle");
-}
-
QSize QDockWidgetTitleButton::dockButtonIconSize() const
{
if (m_iconSize < 0) {
m_iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, this);
- // Dock Widget title buttons on Windows where historically limited to size 10
- // (from small icon size 16) since only a 10x10 XPM was provided.
- // Adding larger pixmaps to the icons thus caused the icons to grow; limit
- // this to qpiScaled(10) here.
- if (isWindowsStyle(style()))
- m_iconSize = qMin((10 * logicalDpiX()) / 96, m_iconSize);
+ if (style()->styleHint(QStyle::SH_DockWidget_ButtonsHaveFrame, nullptr, this))
+ m_iconSize = (m_iconSize * 5) / 8; // 16 -> 10
}
return QSize(m_iconSize, m_iconSize);
}
@@ -253,7 +232,9 @@ bool QDockWidgetLayout::wmSupportsNativeWindowDeco()
return false;
#else
static const bool xcb = !QGuiApplication::platformName().compare("xcb"_L1, Qt::CaseInsensitive);
- return !xcb;
+ static const bool wayland =
+ QGuiApplication::platformName().startsWith("wayland"_L1, Qt::CaseInsensitive);
+ return !(xcb || wayland);
#endif
}
@@ -627,12 +608,13 @@ void QDockWidgetPrivate::init()
QAbstractButton *button = new QDockWidgetTitleButton(q);
button->setObjectName("qt_dockwidget_floatbutton"_L1);
- QObject::connect(button, SIGNAL(clicked()), q, SLOT(_q_toggleTopLevel()));
+ QObjectPrivate::connect(button, &QAbstractButton::clicked,
+ this, &QDockWidgetPrivate::toggleTopLevel);
layout->setWidgetForRole(QDockWidgetLayout::FloatButton, button);
button = new QDockWidgetTitleButton(q);
button->setObjectName("qt_dockwidget_closebutton"_L1);
- QObject::connect(button, SIGNAL(clicked()), q, SLOT(close()));
+ QObject::connect(button, &QAbstractButton::clicked, q, &QDockWidget::close);
layout->setWidgetForRole(QDockWidgetLayout::CloseButton, button);
font = QApplication::font("QDockWidgetTitle");
@@ -643,8 +625,8 @@ void QDockWidgetPrivate::init()
toggleViewAction->setMenuRole(QAction::NoRole);
fixedWindowTitle = qt_setWindowTitle_helperHelper(q->windowTitle(), q);
toggleViewAction->setText(fixedWindowTitle);
- QObject::connect(toggleViewAction, SIGNAL(triggered(bool)),
- q, SLOT(_q_toggleView(bool)));
+ QObjectPrivate::connect(toggleViewAction, &QAction::triggered,
+ this, &QDockWidgetPrivate::toggleView);
#endif
updateButtons();
@@ -679,7 +661,7 @@ void QDockWidget::initStyleOption(QStyleOptionDockWidget *option) const
option->verticalTitleBar = l->verticalTitleBar;
}
-void QDockWidgetPrivate::_q_toggleView(bool b)
+void QDockWidgetPrivate::toggleView(bool b)
{
Q_Q(QDockWidget);
if (b == q->isHidden()) {
@@ -727,7 +709,7 @@ void QDockWidgetPrivate::updateButtons()
layout->invalidate();
}
-void QDockWidgetPrivate::_q_toggleTopLevel()
+void QDockWidgetPrivate::toggleTopLevel()
{
Q_Q(QDockWidget);
q->setFloating(!q->isFloating());
@@ -768,7 +750,7 @@ void QDockWidgetPrivate::initDrag(const QPoint &pos, bool nca)
tabbed widgets, and false if the dock widget should always be dragged
alone.
*/
-void QDockWidgetPrivate::startDrag(bool group)
+void QDockWidgetPrivate::startDrag(DragScope scope)
{
Q_Q(QDockWidget);
@@ -778,7 +760,11 @@ void QDockWidgetPrivate::startDrag(bool group)
QMainWindowLayout *layout = qt_mainwindow_layout_from_dock(q);
Q_ASSERT(layout != nullptr);
- state->widgetItem = layout->unplug(q, group);
+#if QT_CONFIG(draganddrop)
+ bool wasFloating = q->isFloating();
+#endif
+
+ state->widgetItem = layout->unplug(q, scope);
if (state->widgetItem == nullptr) {
/* Dock widget has a QMainWindow parent, but was never inserted with
QMainWindow::addDockWidget, so the QMainWindowLayout has no
@@ -796,6 +782,20 @@ void QDockWidgetPrivate::startDrag(bool group)
layout->restore();
state->dragging = true;
+
+#if QT_CONFIG(draganddrop)
+ if (QMainWindowLayout::needsPlatformDrag()) {
+ Qt::DropAction result =
+ layout->performPlatformWidgetDrag(state->widgetItem, state->pressPos);
+ if (result == Qt::IgnoreAction && !wasFloating) {
+ layout->revert(state->widgetItem);
+ delete state;
+ state = nullptr;
+ } else {
+ endDrag(QDockWidgetPrivate::EndDragMode::LocationChange);
+ }
+ }
+#endif
}
/*! \internal
@@ -803,7 +803,7 @@ void QDockWidgetPrivate::startDrag(bool group)
The \a abort parameter specifies that it ends because of programmatic state
reset rather than mouse release event.
*/
-void QDockWidgetPrivate::endDrag(bool abort)
+void QDockWidgetPrivate::endDrag(EndDragMode mode)
{
Q_Q(QDockWidget);
Q_ASSERT(state != nullptr);
@@ -815,7 +815,11 @@ void QDockWidgetPrivate::endDrag(bool abort)
Q_ASSERT(mainWindow != nullptr);
QMainWindowLayout *mwLayout = qt_mainwindow_layout(mainWindow);
- if (abort || !mwLayout->plug(state->widgetItem)) {
+ // if mainWindow is being deleted in an ongoing drag, make it a no-op instead of crashing
+ if (!mwLayout)
+ return;
+
+ if (mode == EndDragMode::Abort || !mwLayout->plug(state->widgetItem)) {
if (hasFeature(this, QDockWidget::DockWidgetFloatable)) {
// This QDockWidget will now stay in the floating state.
if (state->ownWidgetItem) {
@@ -847,6 +851,11 @@ void QDockWidgetPrivate::endDrag(bool abort)
tabPosition = mwLayout->tabPosition(toDockWidgetArea(dwgw->layoutInfo()->dockPos));
}
#endif
+ // Reparent, if the drag was out of a dock widget group window
+ if (mode == EndDragMode::LocationChange) {
+ if (auto *groupWindow = qobject_cast<QDockWidgetGroupWindow *>(q->parentWidget()))
+ groupWindow->reparent(q);
+ }
}
q->activateWindow();
} else {
@@ -875,6 +884,10 @@ Qt::DockWidgetArea QDockWidgetPrivate::toDockWidgetArea(QInternal::DockPosition
void QDockWidgetPrivate::setResizerActive(bool active)
{
Q_Q(QDockWidget);
+ const auto *dwLayout = qobject_cast<QDockWidgetLayout *>(layout);
+ if (dwLayout->nativeWindowDeco(q->isFloating()))
+ return;
+
if (active && !resizer)
resizer = new QWidgetResizeHandler(q);
if (resizer)
@@ -937,13 +950,22 @@ bool QDockWidgetPrivate::mouseDoubleClickEvent(QMouseEvent *event)
if (event->button() == Qt::LeftButton && titleArea.contains(event->position().toPoint()) &&
hasFeature(this, QDockWidget::DockWidgetFloatable)) {
- _q_toggleTopLevel();
+ toggleTopLevel();
return true;
}
}
return false;
}
+bool QDockWidgetPrivate::isTabbed() const
+{
+ Q_Q(const QDockWidget);
+ QDockWidget *that = const_cast<QDockWidget *>(q);
+ auto *mwLayout = qt_mainwindow_layout_from_dock(that);
+ Q_ASSERT(mwLayout);
+ return mwLayout->isDockWidgetTabbed(q);
+}
+
bool QDockWidgetPrivate::mouseMoveEvent(QMouseEvent *event)
{
bool ret = false;
@@ -974,7 +996,8 @@ bool QDockWidgetPrivate::mouseMoveEvent(QMouseEvent *event)
} else
#endif
{
- startDrag();
+ const DragScope scope = isTabbed() ? DragScope::Group : DragScope::Widget;
+ startDrag(scope);
q->grabMouse();
ret = true;
}
@@ -1038,9 +1061,15 @@ bool QDockWidgetPrivate::mouseMoveEvent(QMouseEvent *event)
bool QDockWidgetPrivate::mouseReleaseEvent(QMouseEvent *event)
{
#if QT_CONFIG(mainwindow)
+#if QT_CONFIG(draganddrop)
+ // if we are peforming a platform drag ignore the release here and end the drag when the actual
+ // drag ends.
+ if (QMainWindowLayout::needsPlatformDrag())
+ return false;
+#endif
if (event->button() == Qt::LeftButton && state && !state->nca) {
- endDrag();
+ endDrag(EndDragMode::LocationChange);
return true; //filter out the event
}
@@ -1079,26 +1108,25 @@ void QDockWidgetPrivate::nonClientAreaMouseEvent(QMouseEvent *event)
break;
state->ctrlDrag = (event->modifiers() & Qt::ControlModifier) ||
(!hasFeature(this, QDockWidget::DockWidgetMovable) && q->isFloating());
- startDrag();
+ startDrag(DragScope::Group);
break;
case QEvent::NonClientAreaMouseMove:
if (state == nullptr || !state->dragging)
break;
#if !defined(Q_OS_MAC) && !defined(Q_OS_WASM)
- if (state->nca) {
- endDrag();
- }
+ if (state->nca)
+ endDrag(EndDragMode::LocationChange);
#endif
break;
case QEvent::NonClientAreaMouseButtonRelease:
#if defined(Q_OS_MAC) || defined(Q_OS_WASM)
if (state)
- endDrag();
+ endDrag(EndDragMode::LocationChange);
#endif
break;
case QEvent::NonClientAreaMouseButtonDblClick:
- _q_toggleTopLevel();
+ toggleTopLevel();
break;
default:
break;
@@ -1164,10 +1192,10 @@ void QDockWidgetPrivate::setWindowState(bool floating, bool unplug, const QRect
return; // this dockwidget can't be redocked
}
- bool wasFloating = q->isFloating();
+ const bool wasFloating = q->isFloating();
if (wasFloating) // Prevent repetitive unplugging from nested invocations (QTBUG-42818)
unplug = false;
- bool hidden = q->isHidden();
+ const bool hidden = q->isHidden();
if (q->isVisible())
q->hide();
@@ -1185,8 +1213,12 @@ void QDockWidgetPrivate::setWindowState(bool floating, bool unplug, const QRect
flags |= Qt::FramelessWindowHint;
}
- if (unplug)
+#if QT_CONFIG(draganddrop)
+ // If we are performing a platform drag the flag is not needed and we want to avoid recreating
+ // the platform window when it would be removed later
+ if (unplug && !QMainWindowLayout::needsPlatformDrag())
flags |= Qt::X11BypassWindowManagerHint;
+#endif
q->setWindowFlags(flags);
@@ -1262,15 +1294,13 @@ void QDockWidgetPrivate::setWindowState(bool floating, bool unplug, const QRect
possible to drag the dock widget when undocking. Starting the drag will undock
the dock widget, but a second drag will be needed to move the dock widget itself.
- \sa QMainWindow, {Dock Widgets Example}
+ \sa QMainWindow
*/
/*!
\enum QDockWidget::DockWidgetFeature
- \value DockWidgetClosable The dock widget can be closed. On some systems the dock
- widget always has a close button when it's floating
- (for example on MacOS 10.5).
+ \value DockWidgetClosable The dock widget can be closed.
\value DockWidgetMovable The dock widget can be moved between docks
by the user.
\value DockWidgetFloatable The dock widget can be detached from the
@@ -1402,9 +1432,12 @@ QDockWidget::DockWidgetFeatures QDockWidget::features() const
\property QDockWidget::floating
\brief whether the dock widget is floating
- A floating dock widget is presented to the user as an independent
- window "on top" of its parent QMainWindow, instead of being
- docked in the QMainWindow.
+ A floating dock widget is presented to the user as a single, independent
+ window "on top" of its parent QMainWindow, instead of being docked
+ either in the QMainWindow, or in a group of tabbed dock widgets.
+
+ Floating dock widgets can be individually positioned and resized, both
+ programmatically or by mouse interaction.
By default, this property is \c true.
@@ -1418,7 +1451,7 @@ void QDockWidget::setFloating(bool floating)
// the initial click of a double-click may have started a drag...
if (d->state != nullptr)
- d->endDrag(true);
+ d->endDrag(QDockWidgetPrivate::EndDragMode::Abort);
QRect r = d->undockedGeometry;
// Keep position when undocking for the first time.
@@ -1473,8 +1506,14 @@ void QDockWidget::changeEvent(QEvent *event)
QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(this->layout());
switch (event->type()) {
- case QEvent::ModifiedChange:
case QEvent::WindowTitleChange:
+ if (isFloating() && windowHandle() && d->topData() && windowHandle()->isVisible()) {
+ // From QWidget::setWindowTitle(): Propagate window title without signal emission
+ d->topData()->caption = windowHandle()->title();
+ d->setWindowTitle_helper(windowHandle()->title());
+ }
+ Q_FALLTHROUGH();
+ case QEvent::ModifiedChange:
update(layout->titleArea());
#ifndef QT_NO_ACTION
d->fixedWindowTitle = qt_setWindowTitle_helperHelper(windowTitle(), this);
@@ -1500,8 +1539,14 @@ void QDockWidget::closeEvent(QCloseEvent *event)
{
Q_D(QDockWidget);
if (d->state)
- d->endDrag(true);
- QWidget::closeEvent(event);
+ d->endDrag(QDockWidgetPrivate::EndDragMode::Abort);
+
+ // For non-closable widgets, don't allow closing, except when the mainwindow
+ // is hidden, as otherwise an application wouldn't be able to be shut down.
+ const QMainWindow *win = qobject_cast<QMainWindow*>(parentWidget());
+ const bool canClose = (d->features & DockWidgetClosable)
+ || (!win || !win->isVisible());
+ event->setAccepted(canClose);
}
/*! \reimp */
@@ -1691,6 +1736,10 @@ QAction * QDockWidget::toggleViewAction() const
invisible). This happens when the widget is hidden or shown, as
well as when it is docked in a tabbed dock area and its tab
becomes selected or unselected.
+
+ \note The signal can differ from QWidget::isVisible(). This can be the case, if
+ a dock widget is minimized or tabified and associated to a non-selected or
+ inactive tab.
*/
/*!
@@ -1772,6 +1821,26 @@ QWidget *QDockWidget::titleBarWidget() const
return layout->widgetForRole(QDockWidgetLayout::TitleBar);
}
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QDockWidget *dockWidget)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace();
+
+ if (!dockWidget) {
+ dbg << "QDockWidget(0x0)";
+ return dbg;
+ }
+
+ dbg << "QDockWidget(" << static_cast<const void *>(dockWidget);
+ dbg << "->(ObjectName=" << dockWidget->objectName();
+ dbg << "; floating=" << dockWidget->isFloating();
+ dbg << "; features=" << dockWidget->features();
+ dbg << ";))";
+ return dbg;
+}
+#endif // QT_NO_DEBUG_STREAM
+
QT_END_NAMESPACE
#include "qdockwidget.moc"
diff --git a/src/widgets/widgets/qdockwidget.h b/src/widgets/widgets/qdockwidget.h
index f524a88423..2efa1d3c2f 100644
--- a/src/widgets/widgets/qdockwidget.h
+++ b/src/widgets/widgets/qdockwidget.h
@@ -20,7 +20,7 @@ class Q_WIDGETS_EXPORT QDockWidget : public QWidget
{
Q_OBJECT
- Q_PROPERTY(bool floating READ isFloating WRITE setFloating)
+ Q_PROPERTY(bool floating READ isFloating WRITE setFloating NOTIFY topLevelChanged)
Q_PROPERTY(DockWidgetFeatures features READ features WRITE setFeatures NOTIFY featuresChanged)
Q_PROPERTY(Qt::DockWidgetAreas allowedAreas READ allowedAreas
WRITE setAllowedAreas NOTIFY allowedAreasChanged)
@@ -64,6 +64,10 @@ public:
inline bool isAreaAllowed(Qt::DockWidgetArea area) const
{ return (allowedAreas() & area) == area; }
+#ifndef QT_NO_DEBUG_STREAM
+ friend Q_WIDGETS_EXPORT QDebug operator<<(QDebug dbg, const QDockWidget *dockWidget);
+#endif
+
#ifndef QT_NO_ACTION
QAction *toggleViewAction() const;
#endif
@@ -72,7 +76,7 @@ Q_SIGNALS:
void featuresChanged(QDockWidget::DockWidgetFeatures features);
void topLevelChanged(bool topLevel);
void allowedAreasChanged(Qt::DockWidgetAreas allowedAreas);
- void visibilityChanged(bool visible);
+ void visibilityChanged(bool visible); // ### Qt7: Deprecate this. Better listen to hide/show events
void dockLocationChanged(Qt::DockWidgetArea area);
protected:
@@ -85,8 +89,6 @@ protected:
private:
Q_DECLARE_PRIVATE(QDockWidget)
Q_DISABLE_COPY(QDockWidget)
- Q_PRIVATE_SLOT(d_func(), void _q_toggleView(bool))
- Q_PRIVATE_SLOT(d_func(), void _q_toggleTopLevel())
friend class QDockAreaLayout;
friend class QDockWidgetItem;
friend class QMainWindowLayout;
diff --git a/src/widgets/widgets/qdockwidget_p.h b/src/widgets/widgets/qdockwidget_p.h
index 326c55cc78..fa936599c6 100644
--- a/src/widgets/widgets/qdockwidget_p.h
+++ b/src/widgets/widgets/qdockwidget_p.h
@@ -51,9 +51,19 @@ class QDockWidgetPrivate : public QWidgetPrivate
};
public:
+ enum class DragScope {
+ Group,
+ Widget
+ };
+
+ enum class EndDragMode {
+ LocationChange,
+ Abort
+ };
+
void init();
- void _q_toggleView(bool); // private slot
- void _q_toggleTopLevel(); // private slot
+ void toggleView(bool);
+ void toggleTopLevel();
void updateButtons();
static Qt::DockWidgetArea toDockWidgetArea(QInternal::DockPosition pos);
@@ -86,8 +96,8 @@ public:
void setWindowState(bool floating, bool unplug = false, const QRect &rect = QRect());
void nonClientAreaMouseEvent(QMouseEvent *event);
void initDrag(const QPoint &pos, bool nca);
- void startDrag(bool group = true);
- void endDrag(bool abort = false);
+ void startDrag(DragScope scope);
+ void endDrag(EndDragMode mode);
void moveEvent(QMoveEvent *event);
void recalculatePressPos(QResizeEvent *event);
@@ -96,6 +106,7 @@ public:
void setResizerActive(bool active);
bool isAnimating() const;
+ bool isTabbed() const;
private:
QWidgetResizeHandler *resizer = nullptr;
diff --git a/src/widgets/widgets/qeffects.cpp b/src/widgets/widgets/qeffects.cpp
index eaf8deca69..74ac24a2b0 100644
--- a/src/widgets/widgets/qeffects.cpp
+++ b/src/widgets/widgets/qeffects.cpp
@@ -115,7 +115,7 @@ void QAlphaWidget::run(int time)
qApp->installEventFilter(this);
widget->setWindowOpacity(0.0);
widget->show();
- connect(&anim, SIGNAL(timeout()), this, SLOT(render()));
+ connect(&anim, &QTimer::timeout, this, &QAlphaWidget::render);
anim.start(1);
#else
//This is roughly equivalent to calling setVisible(true) without actually showing the widget
@@ -138,7 +138,7 @@ void QAlphaWidget::run(int time)
show();
setEnabled(false);
- connect(&anim, SIGNAL(timeout()), this, SLOT(render()));
+ connect(&anim, &QTimer::timeout, this, &QAlphaWidget::render);
anim.start(1);
} else {
duration = 0;
@@ -292,6 +292,7 @@ void QAlphaWidget::alphaBlend()
back_data += bpl;
front_data += bpl;
}
+ break;
}
default:
break;
@@ -428,7 +429,7 @@ void QRollEffect::run(int time)
duration = qMin(qMax(dist/3, 50), 120);
}
- connect(&anim, SIGNAL(timeout()), this, SLOT(scroll()));
+ connect(&anim, &QTimer::timeout, this, &QRollEffect::scroll);
move(widget->geometry().x(),widget->geometry().y());
resize(qMin(currentWidth, totalWidth), qMin(currentHeight, totalHeight));
diff --git a/src/widgets/widgets/qfocusframe.cpp b/src/widgets/widgets/qfocusframe.cpp
index 396f7fca14..d66faedbac 100644
--- a/src/widgets/widgets/qfocusframe.cpp
+++ b/src/widgets/widgets/qfocusframe.cpp
@@ -52,8 +52,8 @@ void QFocusFramePrivate::updateSize()
QStyleOption opt;
q->initStyleOption(&opt);
- int vmargin = q->style()->pixelMetric(QStyle::PM_FocusFrameVMargin, &opt),
- hmargin = q->style()->pixelMetric(QStyle::PM_FocusFrameHMargin, &opt);
+ int vmargin = q->style()->pixelMetric(QStyle::PM_FocusFrameVMargin, &opt, q),
+ hmargin = q->style()->pixelMetric(QStyle::PM_FocusFrameHMargin, &opt, q);
QPoint pos(widget->x(), widget->y());
if (q->parentWidget() != widget->parentWidget())
pos = widget->parentWidget()->mapTo(q->parentWidget(), pos);
@@ -229,8 +229,8 @@ QFocusFrame::paintEvent(QPaintEvent *)
QStylePainter p(this);
QStyleOption option;
initStyleOption(&option);
- const int vmargin = style()->pixelMetric(QStyle::PM_FocusFrameVMargin, &option);
- const int hmargin = style()->pixelMetric(QStyle::PM_FocusFrameHMargin, &option);
+ const int vmargin = style()->pixelMetric(QStyle::PM_FocusFrameVMargin, &option, this);
+ const int hmargin = style()->pixelMetric(QStyle::PM_FocusFrameHMargin, &option, this);
QWidgetPrivate *wd = qt_widget_private(d->widget);
QRect rect = wd->clipRect().adjusted(0, 0, hmargin*2, vmargin*2);
p.setClipRect(rect);
diff --git a/src/widgets/widgets/qfontcombobox.cpp b/src/widgets/widgets/qfontcombobox.cpp
index a7f31995e1..c80687c7ed 100644
--- a/src/widgets/widgets/qfontcombobox.cpp
+++ b/src/widgets/widgets/qfontcombobox.cpp
@@ -3,8 +3,9 @@
#include "qfontcombobox.h"
+#include <qabstractitemdelegate.h>
+#include <qaccessible.h>
#include <qstringlistmodel.h>
-#include <qitemdelegate.h>
#include <qlistview.h>
#include <qpainter.h>
#include <qevent.h>
@@ -12,6 +13,8 @@
#include <private/qcombobox_p.h>
#include <qdebug.h>
+#include <array>
+
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
@@ -100,7 +103,7 @@ static QFontDatabase::WritingSystem writingSystemFromLocale()
static QFontDatabase::WritingSystem writingSystemForFont(const QFont &font, bool *hasLatin)
{
- QList<QFontDatabase::WritingSystem> writingSystems = QFontDatabase::writingSystems(font.families().first());
+ QList<QFontDatabase::WritingSystem> writingSystems = QFontDatabase::writingSystems(font.families().constFirst());
// qDebug() << font.families().first() << writingSystems;
// this just confuses the algorithm below. Vietnamese is Latin with lots of special chars
@@ -147,16 +150,15 @@ static QFontDatabase::WritingSystem writingSystemForFont(const QFont &font, bool
class QFontComboBoxPrivate : public QComboBoxPrivate
{
public:
- inline QFontComboBoxPrivate() { filters = QFontComboBox::AllFonts; }
-
- QFontComboBox::FontFilters filters;
+ QFontComboBox::FontFilters filters = QFontComboBox::AllFonts;
QFont currentFont;
QHash<QFontDatabase::WritingSystem, QString> sampleTextForWritingSystem;
QHash<QString, QString> sampleTextForFontFamily;
QHash<QString, QFont> displayFontForFontFamily;
+ std::array<QMetaObject::Connection, 2> connections;
- void _q_updateModel();
- void _q_currentChanged(const QString &);
+ void updateModel();
+ void currentChanged(const QString &);
Q_DECLARE_PUBLIC(QFontComboBox)
};
@@ -281,7 +283,7 @@ QSize QFontFamilyDelegate::sizeHint(const QStyleOptionViewItem &option,
}
-void QFontComboBoxPrivate::_q_updateModel()
+void QFontComboBoxPrivate::updateModel()
{
Q_Q(QFontComboBox);
@@ -297,29 +299,28 @@ void QFontComboBoxPrivate::_q_updateModel()
QFontFamilyDelegate *delegate = qobject_cast<QFontFamilyDelegate *>(q->view()->itemDelegate());
QFontDatabase::WritingSystem system = delegate ? delegate->writingSystem : QFontDatabase::Any;
- QStringList list = QFontDatabase::families(system);
+ const QStringList list = QFontDatabase::families(system);
QStringList result;
int offset = 0;
QFontInfo fi(currentFont);
- for (int i = 0; i < list.size(); ++i) {
- if (QFontDatabase::isPrivateFamily(list.at(i)))
+ for (const auto &family : list) {
+ if (QFontDatabase::isPrivateFamily(family))
continue;
if ((filters & scalableMask) && (filters & scalableMask) != scalableMask) {
- if (bool(filters & QFontComboBox::ScalableFonts) != QFontDatabase::isSmoothlyScalable(list.at(i)))
+ if (bool(filters & QFontComboBox::ScalableFonts) != QFontDatabase::isSmoothlyScalable(family))
continue;
}
if ((filters & spacingMask) && (filters & spacingMask) != spacingMask) {
- if (bool(filters & QFontComboBox::MonospacedFonts) != QFontDatabase::isFixedPitch(list.at(i)))
+ if (bool(filters & QFontComboBox::MonospacedFonts) != QFontDatabase::isFixedPitch(family))
continue;
}
- result += list.at(i);
- if (list.at(i) == fi.family() || list.at(i).startsWith(fi.family() + " ["_L1))
+ result += family;
+ if (family == fi.family() || family.startsWith(fi.family() + " ["_L1))
offset = result.size() - 1;
}
- list = result;
//we need to block the signals so that the model doesn't emit reset
//this prevents the current index from changing
@@ -327,10 +328,17 @@ void QFontComboBoxPrivate::_q_updateModel()
///TODO: we should finda way to avoid blocking signals and have a real update of the model
{
const QSignalBlocker blocker(m);
- m->setStringList(list);
+ m->setStringList(result);
+ // Since the modelReset signal is blocked the view will not emit an accessibility event
+ #if QT_CONFIG(accessibility)
+ if (QAccessible::isActive()) {
+ QAccessibleTableModelChangeEvent accessibleEvent(q->view(), QAccessibleTableModelChangeEvent::ModelReset);
+ QAccessible::updateAccessibility(&accessibleEvent);
+ }
+ #endif
}
- if (list.isEmpty()) {
+ if (result.isEmpty()) {
if (currentFont != QFont()) {
currentFont = QFont();
emit q->currentFontChanged(currentFont);
@@ -341,10 +349,10 @@ void QFontComboBoxPrivate::_q_updateModel()
}
-void QFontComboBoxPrivate::_q_currentChanged(const QString &text)
+void QFontComboBoxPrivate::currentChanged(const QString &text)
{
Q_Q(QFontComboBox);
- QStringList families = currentFont.families();
+ const QStringList families = currentFont.families();
if (families.isEmpty() || families.first() != text) {
currentFont.setFamilies(QStringList{text});
emit q->currentFontChanged(currentFont);
@@ -381,7 +389,7 @@ void QFontComboBoxPrivate::_q_currentChanged(const QString &text)
\image windowsvista-fontcombobox.png Screenshot of QFontComboBox on Windows Vista
- \sa QComboBox, QFont, QFontInfo, QFontMetrics, QFontDatabase, {Character Map Example}
+ \sa QComboBox, QFont, QFontInfo, QFontMetrics, QFontDatabase
*/
/*!
@@ -402,11 +410,12 @@ QFontComboBox::QFontComboBox(QWidget *parent)
lview->setUniformItemSizes(true);
setWritingSystem(QFontDatabase::Any);
- connect(this, SIGNAL(currentTextChanged(QString)),
- this, SLOT(_q_currentChanged(QString)));
-
- connect(qApp, SIGNAL(fontDatabaseChanged()),
- this, SLOT(_q_updateModel()));
+ d->connections = {
+ QObjectPrivate::connect(this, &QFontComboBox::currentTextChanged,
+ d, &QFontComboBoxPrivate::currentChanged),
+ QObjectPrivate::connect(qApp, &QGuiApplication::fontDatabaseChanged,
+ d, &QFontComboBoxPrivate::updateModel),
+ };
}
@@ -415,6 +424,9 @@ QFontComboBox::QFontComboBox(QWidget *parent)
*/
QFontComboBox::~QFontComboBox()
{
+ Q_D(const QFontComboBox);
+ for (const QMetaObject::Connection &connection : d->connections)
+ QObject::disconnect(connection);
}
/*!
@@ -433,7 +445,7 @@ void QFontComboBox::setWritingSystem(QFontDatabase::WritingSystem script)
QFontFamilyDelegate *delegate = qobject_cast<QFontFamilyDelegate *>(view()->itemDelegate());
if (delegate)
delegate->writingSystem = script;
- d->_q_updateModel();
+ d->updateModel();
}
QFontDatabase::WritingSystem QFontComboBox::writingSystem() const
@@ -469,7 +481,7 @@ void QFontComboBox::setFontFilters(FontFilters filters)
{
Q_D(QFontComboBox);
d->filters = filters;
- d->_q_updateModel();
+ d->updateModel();
}
QFontComboBox::FontFilters QFontComboBox::fontFilters() const
@@ -495,8 +507,8 @@ void QFontComboBox::setCurrentFont(const QFont &font)
Q_D(QFontComboBox);
if (font != d->currentFont) {
d->currentFont = font;
- d->_q_updateModel();
- if (d->currentFont == font) { //else the signal has already be emitted by _q_updateModel
+ d->updateModel();
+ if (d->currentFont == font) { //else the signal has already be emitted by updateModel
emit currentFontChanged(d->currentFont);
}
}
diff --git a/src/widgets/widgets/qfontcombobox.h b/src/widgets/widgets/qfontcombobox.h
index 8c4bad2ae0..9c5432b332 100644
--- a/src/widgets/widgets/qfontcombobox.h
+++ b/src/widgets/widgets/qfontcombobox.h
@@ -65,8 +65,6 @@ protected:
private:
Q_DISABLE_COPY(QFontComboBox)
Q_DECLARE_PRIVATE(QFontComboBox)
- Q_PRIVATE_SLOT(d_func(), void _q_currentChanged(const QString &))
- Q_PRIVATE_SLOT(d_func(), void _q_updateModel())
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QFontComboBox::FontFilters)
diff --git a/src/widgets/widgets/qgroupbox.cpp b/src/widgets/widgets/qgroupbox.cpp
index 8fd90f8b77..eb37599382 100644
--- a/src/widgets/widgets/qgroupbox.cpp
+++ b/src/widgets/widgets/qgroupbox.cpp
@@ -22,6 +22,7 @@
#include <qpa/qplatformtheme.h>
#include "qdebug.h"
+#include <QtCore/qpointer.h>
QT_BEGIN_NAMESPACE
@@ -132,9 +133,9 @@ void QGroupBoxPrivate::click()
widgets). The following example shows how we can set up a
QGroupBox with a layout:
- \snippet widgets/groupbox/window.cpp 2
+ \snippet code/src_gui_widgets_qgroupbox.cpp Set up QGroupBox with layout
- \sa QButtonGroup, {Group Box Example}
+ \sa QButtonGroup
*/
@@ -463,9 +464,9 @@ QSize QGroupBox::minimumSizeHint() const
int baseWidth = metrics.horizontalAdvance(d->title) + metrics.horizontalAdvance(u' ');
int baseHeight = metrics.height();
if (d->checkable) {
- baseWidth += style()->pixelMetric(QStyle::PM_IndicatorWidth, &option);
- baseWidth += style()->pixelMetric(QStyle::PM_CheckBoxLabelSpacing, &option);
- baseHeight = qMax(baseHeight, style()->pixelMetric(QStyle::PM_IndicatorHeight, &option));
+ baseWidth += style()->pixelMetric(QStyle::PM_IndicatorWidth, &option, this);
+ baseWidth += style()->pixelMetric(QStyle::PM_CheckBoxLabelSpacing, &option, this);
+ baseHeight = qMax(baseHeight, style()->pixelMetric(QStyle::PM_IndicatorHeight, &option, this));
}
QSize size = style()->sizeFromContents(QStyle::CT_GroupBox, &option, QSize(baseWidth, baseHeight), this);
diff --git a/src/widgets/widgets/qkeysequenceedit.cpp b/src/widgets/widgets/qkeysequenceedit.cpp
index 9a9bf25668..65ed7a465a 100644
--- a/src/widgets/widgets/qkeysequenceedit.cpp
+++ b/src/widgets/widgets/qkeysequenceedit.cpp
@@ -20,7 +20,7 @@ void QKeySequenceEditPrivate::init()
lineEdit = new QLineEdit(q);
lineEdit->setObjectName(QStringLiteral("qt_keysequenceedit_lineedit"));
lineEdit->setClearButtonEnabled(false);
- q->connect(lineEdit, &QLineEdit::textChanged, [q](const QString& text) {
+ q->connect(lineEdit, &QLineEdit::textChanged, q, [q](const QString& text) {
// Clear the shortcut if the user clicked on the clear icon
if (text.isEmpty())
q->clear();
@@ -344,22 +344,23 @@ void QKeySequenceEdit::keyPressEvent(QKeyEvent *e)
return;
if (e->modifiers() & Qt::ShiftModifier) {
- QList<int> possibleKeys = QKeyMapper::possibleKeys(e);
+ const QList<QKeyCombination> possibleKeys = QKeyMapper::possibleKeys(e);
int pkTotal = possibleKeys.size();
if (!pkTotal)
return;
bool found = false;
for (int i = 0; i < possibleKeys.size(); ++i) {
- if (possibleKeys.at(i) - nextKey == int(e->modifiers())
- || (possibleKeys.at(i) == nextKey && e->modifiers() == Qt::ShiftModifier)) {
- nextKey = possibleKeys.at(i);
+ const int key = possibleKeys.at(i).toCombined();
+ if (key - nextKey == int(e->modifiers())
+ || (key == nextKey && e->modifiers() == Qt::ShiftModifier)) {
+ nextKey = key;
found = true;
break;
}
}
// Use as fallback
if (!found)
- nextKey = possibleKeys.first();
+ nextKey = possibleKeys.first().toCombined();
} else {
nextKey |= d->translateModifiers(e->modifiers(), e->text());
}
@@ -414,7 +415,8 @@ void QKeySequenceEdit::timerEvent(QTimerEvent *e)
void QKeySequenceEdit::focusOutEvent(QFocusEvent *e)
{
Q_D(QKeySequenceEdit);
- d->finishEditing();
+ if (e->reason() != Qt::PopupFocusReason)
+ d->finishEditing();
QWidget::focusOutEvent(e);
}
diff --git a/src/widgets/widgets/qlabel.cpp b/src/widgets/widgets/qlabel.cpp
index 4d1c4ebb74..f4155de0a0 100644
--- a/src/widgets/widgets/qlabel.cpp
+++ b/src/widgets/widgets/qlabel.cpp
@@ -1171,12 +1171,14 @@ void QLabel::setBuddy(QWidget *buddy)
Q_D(QLabel);
if (d->buddy)
- disconnect(d->buddy, SIGNAL(destroyed()), this, SLOT(_q_buddyDeleted()));
+ QObjectPrivate::disconnect(d->buddy, &QObject::destroyed,
+ d, &QLabelPrivate::buddyDeleted);
d->buddy = buddy;
if (buddy)
- connect(buddy, SIGNAL(destroyed()), this, SLOT(_q_buddyDeleted()));
+ QObjectPrivate::connect(buddy, &QObject::destroyed,
+ d, &QLabelPrivate::buddyDeleted);
if (d->isTextLabel) {
if (d->shortcutId)
@@ -1219,7 +1221,7 @@ void QLabelPrivate::updateShortcut()
}
-void QLabelPrivate::_q_buddyDeleted()
+void QLabelPrivate::buddyDeleted()
{
Q_Q(QLabel);
q->setBuddy(nullptr);
@@ -1228,7 +1230,7 @@ void QLabelPrivate::_q_buddyDeleted()
#endif // QT_NO_SHORTCUT
#if QT_CONFIG(movie)
-void QLabelPrivate::_q_movieUpdated(const QRect& rect)
+void QLabelPrivate::movieUpdated(const QRect &rect)
{
Q_Q(QLabel);
if (movie && movie->isValid()) {
@@ -1251,12 +1253,12 @@ void QLabelPrivate::_q_movieUpdated(const QRect& rect)
}
}
-void QLabelPrivate::_q_movieResized(const QSize& size)
+void QLabelPrivate::movieResized(const QSize &size)
{
Q_Q(QLabel);
q->update(); //we need to refresh the whole background in case the new size is smaller
valid_hints = false;
- _q_movieUpdated(QRect(QPoint(0,0), size));
+ movieUpdated(QRect(QPoint(0,0), size));
q->updateGeometry();
}
@@ -1278,8 +1280,10 @@ void QLabel::setMovie(QMovie *movie)
return;
d->movie = movie;
- connect(movie, SIGNAL(resized(QSize)), this, SLOT(_q_movieResized(QSize)));
- connect(movie, SIGNAL(updated(QRect)), this, SLOT(_q_movieUpdated(QRect)));
+ d->movieConnections = {
+ QObjectPrivate::connect(movie, &QMovie::resized, d, &QLabelPrivate::movieResized),
+ QObjectPrivate::connect(movie, &QMovie::updated, d, &QLabelPrivate::movieUpdated),
+ };
// Assume that if the movie is running,
// resize/update signals will come soon enough
@@ -1317,10 +1321,8 @@ void QLabelPrivate::clearContents()
shortcutId = 0;
#endif
#if QT_CONFIG(movie)
- if (movie) {
- QObject::disconnect(movie, SIGNAL(resized(QSize)), q, SLOT(_q_movieResized(QSize)));
- QObject::disconnect(movie, SIGNAL(updated(QRect)), q, SLOT(_q_movieUpdated(QRect)));
- }
+ for (const auto &conn : std::as_const(movieConnections))
+ QObject::disconnect(conn);
movie = nullptr;
#endif
#ifndef QT_NO_CURSOR
@@ -1580,12 +1582,12 @@ void QLabelPrivate::ensureTextControl() const
control->setOpenExternalLinks(openExternalLinks);
control->setPalette(q->palette());
control->setFocus(q->hasFocus());
- QObject::connect(control, SIGNAL(updateRequest(QRectF)),
- q, SLOT(update()));
- QObject::connect(control, SIGNAL(linkHovered(QString)),
- q, SLOT(_q_linkHovered(QString)));
- QObject::connect(control, SIGNAL(linkActivated(QString)),
- q, SIGNAL(linkActivated(QString)));
+ QObject::connect(control, &QWidgetTextControl::updateRequest,
+ q, qOverload<>(&QLabel::update));
+ QObject::connect(control, &QWidgetTextControl::linkActivated,
+ q, &QLabel::linkActivated);
+ QObjectPrivate::connect(control, &QWidgetTextControl::linkHovered,
+ this, &QLabelPrivate::linkHovered);
textLayoutDirty = true;
textDirty = true;
}
@@ -1601,7 +1603,7 @@ void QLabelPrivate::sendControlEvent(QEvent *e)
control->processEvent(e, -layoutRect().topLeft(), q);
}
-void QLabelPrivate::_q_linkHovered(const QString &anchor)
+void QLabelPrivate::linkHovered(const QString &anchor)
{
Q_Q(QLabel);
#ifndef QT_NO_CURSOR
@@ -1652,15 +1654,10 @@ QPoint QLabelPrivate::layoutPoint(const QPoint& p) const
#ifndef QT_NO_CONTEXTMENU
QMenu *QLabelPrivate::createStandardContextMenu(const QPoint &pos)
{
- if (!control || effectiveTextFormat == Qt::PlainText)
+ if (!control)
return nullptr;
const QPoint p = layoutPoint(pos);
- QString linkToCopy = control->document()->documentLayout()->anchorAt(p);
-
- if (linkToCopy.isEmpty())
- return nullptr;
-
return control->createStandardContextMenu(p, q_func());
}
#endif
diff --git a/src/widgets/widgets/qlabel.h b/src/widgets/widgets/qlabel.h
index ddbe05e82a..3749ec366a 100644
--- a/src/widgets/widgets/qlabel.h
+++ b/src/widgets/widgets/qlabel.h
@@ -130,15 +130,6 @@ protected:
private:
Q_DISABLE_COPY(QLabel)
Q_DECLARE_PRIVATE(QLabel)
-#if QT_CONFIG(movie)
- Q_PRIVATE_SLOT(d_func(), void _q_movieUpdated(const QRect&))
- Q_PRIVATE_SLOT(d_func(), void _q_movieResized(const QSize&))
-#endif
- Q_PRIVATE_SLOT(d_func(), void _q_linkHovered(const QString &))
-
-#ifndef QT_NO_SHORTCUT
- Q_PRIVATE_SLOT(d_func(), void _q_buddyDeleted())
-#endif
friend class QTipLabel;
friend class QMessageBoxPrivate;
friend class QBalloonTip;
diff --git a/src/widgets/widgets/qlabel_p.h b/src/widgets/widgets/qlabel_p.h
index 4718a07614..fb6ccb04eb 100644
--- a/src/widgets/widgets/qlabel_p.h
+++ b/src/widgets/widgets/qlabel_p.h
@@ -33,6 +33,9 @@
#include "qmenu.h"
#endif
+#include <QtCore/qpointer.h>
+
+#include <array>
#include <optional>
QT_BEGIN_NAMESPACE
@@ -50,12 +53,12 @@ public:
QSize sizeForWidth(int w) const;
#if QT_CONFIG(movie)
- void _q_movieUpdated(const QRect&);
- void _q_movieResized(const QSize&);
+ void movieUpdated(const QRect &rect);
+ void movieResized(const QSize &size);
#endif
#ifndef QT_NO_SHORTCUT
void updateShortcut();
- void _q_buddyDeleted();
+ void buddyDeleted();
#endif
inline bool needTextControl() const {
Q_Q(const QLabel);
@@ -70,7 +73,7 @@ public:
void ensureTextControl() const;
void sendControlEvent(QEvent *e);
- void _q_linkHovered(const QString &link);
+ void linkHovered(const QString &link);
QRectF layoutRect() const;
QRect documentRect() const;
@@ -91,6 +94,7 @@ public:
#endif
#if QT_CONFIG(movie)
QPointer<QMovie> movie;
+ std::array<QMetaObject::Connection, 2> movieConnections;
#endif
mutable QWidgetTextControl *control;
mutable QTextCursor shortcutCursor;
diff --git a/src/widgets/widgets/qlcdnumber.cpp b/src/widgets/widgets/qlcdnumber.cpp
index eef2685569..3a65b06415 100644
--- a/src/widgets/widgets/qlcdnumber.cpp
+++ b/src/widgets/widgets/qlcdnumber.cpp
@@ -69,7 +69,7 @@ public:
Incidentally, QLCDNumber is the very oldest part of Qt, tracing
its roots back to a BASIC program on the \l{Sinclair Spectrum}{Sinclair Spectrum}.
- \sa QLabel, QFrame, {Digital Clock Example}, {Tetrix Example}
+ \sa QLabel, QFrame
*/
/*!
@@ -1123,7 +1123,7 @@ void QLCDNumberPrivate::drawSegment(const QPoint &pos, char segmentNo, QPainter
/*!
\property QLCDNumber::segmentStyle
- \brief the style of the LCDNumber
+ \brief the style of the LCDNumber.
\table
\header \li Style \li Result
diff --git a/src/widgets/widgets/qlineedit.cpp b/src/widgets/widgets/qlineedit.cpp
index aad75207a1..8909ac80d9 100644
--- a/src/widgets/widgets/qlineedit.cpp
+++ b/src/widgets/widgets/qlineedit.cpp
@@ -100,55 +100,66 @@ void QLineEdit::initStyleOption(QStyleOptionFrame *option) const
\image windows-lineedit.png
- A line edit allows the user to enter and edit a single line of
- plain text with a useful collection of editing functions,
- including undo and redo, cut and paste, and drag and drop (see
- \l setDragEnabled()).
+ A line edit allows users to enter and edit a single line of
+ plain text with useful editing functions, including undo and redo, cut and
+ paste, and drag and drop.
By changing the echoMode() of a line edit, it can also be used as
- a "write-only" field, for inputs such as passwords.
+ a write-only field for inputs such as passwords.
- The length of the text can be constrained to maxLength(). The text
- can be arbitrarily constrained using a validator() or an
- inputMask(), or both. When switching between a validator and an input mask
- on the same line edit, it is best to clear the validator or input mask to
- prevent undefined behavior.
-
- A related class is QTextEdit which allows multi-line, rich text
+ QTextEdit is a related class that allows multi-line, rich text
editing.
- You can change the text with setText() or insert(). The text is
- retrieved with text(); the displayed text (which may be different,
- see \l{EchoMode}) is retrieved with displayText(). Text can be
- selected with setSelection() or selectAll(), and the selection can
- be cut(), copy()ied and paste()d. The text can be aligned with
- setAlignment().
-
- When the text changes the textChanged() signal is emitted; when
- the text changes other than by calling setText() the textEdited()
- signal is emitted; when the cursor is moved the
- cursorPositionChanged() signal is emitted; and when the Return or
- Enter key is pressed the returnPressed() signal is emitted.
-
- When editing is finished, either because the line edit lost focus
- or Return/Enter is pressed the editingFinished() signal is
- emitted. Note that if focus is lost without any changes done,
- the editingFinished() signal won't be emitted.
-
- Note that if there is a validator set on the line edit, the
- returnPressed()/editingFinished() signals will only be emitted if
- the validator returns QValidator::Acceptable.
-
- By default, QLineEdits have a frame as specified by platform
- style guides; you can turn it off by calling
- setFrame(false).
-
- The default key bindings are described below. The line edit also
- provides a context menu (usually invoked by a right mouse click)
- that presents some of these editing options.
+ \section1 Constraining Text
+
+ Use \l maxLength to define the maximum permitted length of a text. You can
+ use a \l inputMask and \l setValidator() to further constrain the text
+ content.
+
+ \section1 Editing Text
+
+ You can change the text with setText() or insert(). Use text() to retrieve
+ the text and displayText() to retrieve the displayed text (which may be
+ different, see \l{EchoMode}). You can select the text with setSelection() or
+ selectAll(), and you can cut(), copy(), and paste() the selection. To align
+ the text, use setAlignment().
+
+ When the text changes, the textChanged() signal is emitted. When the text
+ changes in some other way than by calling setText(), the textEdited() signal
+ is emitted. When the cursor is moved, the cursorPositionChanged() signal is
+ emitted. And when the Return or Enter key is selected, the returnPressed()
+ signal is emitted.
+
+ When text editing is finished, either because the line edit lost focus
+ or Return/Enter was selected, the editingFinished() signal is emitted.
+
+ If the line edit focus is lost without any text changes, the
+ editingFinished() signal won't be emitted.
+
+ If there is a validator set on the line edit, the
+ returnPressed()/editingFinished() signals will only be emitted if the
+ validator returns QValidator::Acceptable.
+
+ For more information on the many ways that QLineEdit can be used, see
+ \l {Line Edits Example}, which also provides a selection of line edit
+ examples that show the effects of various properties and validators on the
+ input and output supplied by the user.
+
+ \section1 Setting a Frame
+
+ By default, QLineEdits have a frame as specified in the platform
+ style guides. You can turn the frame off by calling setFrame(false).
+
+ \section1 Default Key Bindings
+
+ The table below describes the default key bindings.
+
+ \note The line edit also provides a context menu (usually invoked by a
+ right-click) that presents some of the editing options listed below.
+
\target desc
\table
- \header \li Keypress \li Action
+ \header \li Keystroke \li Action
\row \li Left Arrow \li Moves the cursor one character to the left.
\row \li Shift+Left Arrow \li Moves and selects text one character to the left.
\row \li Right Arrow \li Moves the cursor one character to the right.
@@ -159,7 +170,7 @@ void QLineEdit::initStyleOption(QStyleOptionFrame *option) const
\row \li Ctrl+Backspace \li Deletes the word to the left of the cursor.
\row \li Delete \li Deletes the character to the right of the cursor.
\row \li Ctrl+Delete \li Deletes the word to the right of the cursor.
- \row \li Ctrl+A \li Select all.
+ \row \li Ctrl+A \li Selects all.
\row \li Ctrl+C \li Copies the selected text to the clipboard.
\row \li Ctrl+Insert \li Copies the selected text to the clipboard.
\row \li Ctrl+K \li Deletes to the end of the line.
@@ -171,8 +182,8 @@ void QLineEdit::initStyleOption(QStyleOptionFrame *option) const
\row \li Ctrl+Y \li Redoes the last undone operation.
\endtable
- Any other key sequence that represents a valid character, will
- cause the character to be inserted into the line edit.
+ Any other keystroke that represents a valid character, will cause the
+ character to be inserted into the line edit.
\sa QTextEdit, QLabel, QComboBox, {Line Edits Example}
*/
@@ -230,13 +241,11 @@ QLineEdit::QLineEdit(QWidget* parent)
}
/*!
- Constructs a line edit containing the text \a contents.
-
- The cursor position is set to the end of the line and the maximum
- text length to 32767 characters.
+ Constructs a line edit containing the text \a contents as a child of
+ \a parent.
- The \a parent and argument is sent to the QWidget
- constructor.
+ The cursor position is set to the end of the line and the maximum text
+ length to 32767 characters.
\sa text(), setMaxLength()
*/
@@ -260,10 +269,10 @@ QLineEdit::~QLineEdit()
/*!
\property QLineEdit::text
- \brief the line edit's text.
+ \brief The line edit's text.
Setting this property clears the selection, clears the undo/redo
- history, moves the cursor to the end of the line and resets the
+ history, moves the cursor to the end of the line, and resets the
\l modified property to false. The text is not validated when
inserted with setText().
@@ -289,7 +298,7 @@ void QLineEdit::setText(const QString& text)
\since 4.7
\property QLineEdit::placeholderText
- \brief the line edit's placeholder text.
+ \brief The line edit's placeholder text.
Setting this property makes the line edit display a grayed-out
placeholder text as long as the line edit is empty.
@@ -321,12 +330,12 @@ void QLineEdit::setPlaceholderText(const QString& placeholderText)
/*!
\property QLineEdit::displayText
- \brief the displayed text.
+ \brief The displayed text.
- If \l echoMode is \l Normal this returns the same as text(); if
- \l EchoMode is \l Password or \l PasswordEchoOnEdit it returns a string of
- platform-dependent password mask characters text().length() in size,
- e.g. "******"; if \l EchoMode is \l NoEcho returns an empty string, "".
+ If \l echoMode is \l Normal, this returns the same as text(). If
+ \l EchoMode is \l Password or \l PasswordEchoOnEdit, it returns a string of
+ platform-dependent password mask characters (e.g. "******"). If \l EchoMode
+ is \l NoEcho, it returns an empty string.
By default, this property contains an empty string.
@@ -342,12 +351,12 @@ QString QLineEdit::displayText() const
/*!
\property QLineEdit::maxLength
- \brief the maximum permitted length of the text.
+ \brief The maximum permitted length of the text.
If the text is too long, it is truncated at the limit.
- If truncation occurs any selected text will be unselected, the
- cursor position is set to 0 and the first part of the string is
+ If truncation occurs, any selected text will be unselected, the
+ cursor position is set to 0, and the first part of the string is
shown.
If the line edit has an input mask, the mask defines the maximum
@@ -372,10 +381,10 @@ void QLineEdit::setMaxLength(int maxLength)
/*!
\property QLineEdit::frame
- \brief whether the line edit draws itself with a frame.
+ \brief Whether the line edit draws itself with a frame.
- If enabled (the default) the line edit draws itself inside a
- frame, otherwise the line edit draws itself without any frame.
+ If enabled (the default), the line edit draws itself inside a
+ frame. Otherwise, the line edit draws itself without any frame.
*/
bool QLineEdit::hasFrame() const
{
@@ -435,9 +444,9 @@ QAction *QLineEdit::addAction(const QIcon &icon, ActionPosition position)
\property QLineEdit::clearButtonEnabled
\brief Whether the line edit displays a clear button when it is not empty.
- If enabled, the line edit displays a trailing \e clear button when it contains
- some text, otherwise the line edit does not show a clear button (the
- default).
+ If enabled, the line edit displays a trailing \uicontrol clear button when
+ it contains some text. Otherwise, the line edit does not show a
+ \uicontrol clear button (the default).
\sa addAction(), removeAction()
\since 5.2
@@ -501,9 +510,8 @@ void QLineEdit::setFrame(bool enable)
password should be kept secret.
\value Password Display platform-dependent password mask characters instead
of the characters actually entered.
- \value PasswordEchoOnEdit Display characters as they are entered
- while editing otherwise display characters as with
- \c Password.
+ \value PasswordEchoOnEdit Display characters only while they are entered.
+ Otherwise, display characters as with \c Password.
\sa setEchoMode(), echoMode()
*/
@@ -511,13 +519,13 @@ void QLineEdit::setFrame(bool enable)
/*!
\property QLineEdit::echoMode
- \brief the line edit's echo mode.
+ \brief The line edit's echo mode.
The echo mode determines how the text entered in the line edit is
displayed (or echoed) to the user.
The most common setting is \l Normal, in which the text entered by the
- user is displayed verbatim, but QLineEdit also supports modes that allow
+ user is displayed verbatim. QLineEdit also supports modes that allow
the entered text to be suppressed or obscured: these include \l NoEcho,
\l Password and \l PasswordEchoOnEdit.
@@ -574,15 +582,15 @@ const QValidator * QLineEdit::validator() const
value during editing, but will be prevented from editing the text to a
value that \a v validates as \l{QValidator::}{Invalid}.
- This allows you to constrain the text that shall finally be entered when editing is
- done, while leaving users with enough freedom to edit the text from one valid state
- to another.
+ This allows you to constrain the text that will be stored when editing is
+ done while leaving users with enough freedom to edit the text from one valid
+ state to another.
- If \a v == 0, setValidator() removes the current input validator.
- The initial setting is to have no input validator (i.e. any input
- is accepted up to maxLength()).
+ To remove the current input validator, pass \c nullptr. The initial setting
+ is to have no input validator (any input is accepted up to maxLength()).
- \sa validator(), hasAcceptableInput(), QIntValidator, QDoubleValidator, QRegularExpressionValidator
+ \sa validator(), hasAcceptableInput(), QIntValidator, QDoubleValidator,
+ QRegularExpressionValidator
*/
void QLineEdit::setValidator(const QValidator *v)
@@ -604,8 +612,7 @@ void QLineEdit::setValidator(const QValidator *v)
use the QSortFilterProxyModel to ensure that the QCompleter's model contains
only valid entries.
- If \a c == 0, setCompleter() removes the current completer, effectively
- disabling auto completion.
+ To remove the completer and disable auto-completion, pass a \c nullptr.
\sa QCompleter
*/
@@ -615,7 +622,7 @@ void QLineEdit::setCompleter(QCompleter *c)
if (c == d->control->completer())
return;
if (d->control->completer()) {
- disconnect(d->control->completer(), nullptr, this, nullptr);
+ d->disconnectCompleter();
d->control->completer()->setWidget(nullptr);
if (d->control->completer()->parent() == this)
delete d->control->completer();
@@ -625,12 +632,8 @@ void QLineEdit::setCompleter(QCompleter *c)
return;
if (c->widget() == nullptr)
c->setWidget(this);
- if (hasFocus()) {
- QObject::connect(d->control->completer(), SIGNAL(activated(QString)),
- this, SLOT(setText(QString)));
- QObject::connect(d->control->completer(), SIGNAL(highlighted(QString)),
- this, SLOT(_q_completionHighlighted(QString)));
- }
+ if (hasFocus())
+ d->connectCompleter();
}
/*!
@@ -698,7 +701,7 @@ QSize QLineEdit::minimumSizeHint() const
/*!
\property QLineEdit::cursorPosition
- \brief the current cursor position for this line edit.
+ \brief The current cursor position for this line edit.
Setting the cursor position causes a repaint when appropriate.
@@ -731,7 +734,7 @@ int QLineEdit::cursorPositionAt(const QPoint &pos)
/*!
\property QLineEdit::alignment
- \brief the alignment of the line edit.
+ \brief The alignment of the line edit.
Both horizontal and vertical alignment is allowed here, Qt::AlignJustify
will map to Qt::AlignLeft.
@@ -756,9 +759,9 @@ void QLineEdit::setAlignment(Qt::Alignment alignment)
/*!
- Moves the cursor forward \a steps characters. If \a mark is true
- each character moved over is added to the selection; if \a mark is
- false the selection is cleared.
+ Moves the cursor forward \a steps characters. If \a mark is true,
+ each character moved over is added to the selection. If \a mark is
+ false, the selection is cleared.
\sa cursorBackward()
*/
@@ -771,9 +774,9 @@ void QLineEdit::cursorForward(bool mark, int steps)
/*!
- Moves the cursor back \a steps characters. If \a mark is true each
- character moved over is added to the selection; if \a mark is
- false the selection is cleared.
+ Moves the cursor back \a steps characters. If \a mark is true, each
+ character moved over is added to the selection. If \a mark is
+ false, the selection is cleared.
\sa cursorForward()
*/
@@ -810,9 +813,9 @@ void QLineEdit::cursorWordBackward(bool mark)
/*!
If no text is selected, deletes the character to the left of the
- text cursor and moves the cursor one position to the left. If any
+ text cursor, and moves the cursor one position to the left. If any
text is selected, the cursor is moved to the beginning of the
- selected text and the selected text is deleted.
+ selected text, and the selected text is deleted.
\sa del()
*/
@@ -825,7 +828,7 @@ void QLineEdit::backspace()
/*!
If no text is selected, deletes the character to the right of the
text cursor. If any text is selected, the cursor is moved to the
- beginning of the selected text and the selected text is deleted.
+ beginning of the selected text, and the selected text is deleted.
\sa backspace()
*/
@@ -839,7 +842,7 @@ void QLineEdit::del()
/*!
Moves the text cursor to the beginning of the line unless it is
already there. If \a mark is true, text is selected towards the
- first position; otherwise, any selected text is unselected if the
+ first position. Otherwise, any selected text is unselected if the
cursor is moved.
\sa end()
@@ -854,7 +857,7 @@ void QLineEdit::home(bool mark)
/*!
Moves the text cursor to the end of the line unless it is already
there. If \a mark is true, text is selected towards the last
- position; otherwise, any selected text is unselected if the cursor
+ position. Otherwise, any selected text is unselected if the cursor
is moved.
\sa home()
@@ -869,14 +872,14 @@ void QLineEdit::end(bool mark)
/*!
\property QLineEdit::modified
- \brief whether the line edit's contents has been modified by the user.
+ \brief Whether the line edit's contents has been modified by the user.
The modified flag is never read by QLineEdit; it has a default value
of false and is changed to true whenever the user changes the line
edit's contents.
This is useful for things that need to provide a default value but
- do not start out knowing what the default should be (perhaps it
+ do not start out knowing what the default should be (for example, it
depends on other fields on the form). Start the line edit without
the best default, and when the default is known, if modified()
returns \c false (the user hasn't entered any text), insert the
@@ -899,10 +902,10 @@ void QLineEdit::setModified(bool modified)
/*!
\property QLineEdit::hasSelectedText
- \brief whether there is any text selected.
+ \brief Whether there is any text selected.
hasSelectedText() returns \c true if some or all of the text has been
- selected by the user; otherwise returns \c false.
+ selected by the user. Otherwise, it returns \c false.
By default, this property is \c false.
@@ -918,9 +921,9 @@ bool QLineEdit::hasSelectedText() const
/*!
\property QLineEdit::selectedText
- \brief the selected text.
+ \brief The selected text.
- If there is no selected text this property's value is
+ If there is no selected text, this property's value is
an empty string.
By default, this property contains an empty string.
@@ -936,7 +939,7 @@ QString QLineEdit::selectedText() const
/*!
Returns the index of the first selected character in the
- line edit or -1 if no text is selected.
+ line edit (or -1 if no text is selected).
\sa selectedText()
\sa selectionEnd()
@@ -951,7 +954,7 @@ int QLineEdit::selectionStart() const
/*!
Returns the index of the character directly after the selection
- in the line edit or -1 if no text is selected.
+ in the line edit (or -1 if no text is selected).
\since 5.10
\sa selectedText()
@@ -1005,7 +1008,7 @@ void QLineEdit::setSelection(int start, int length)
/*!
\property QLineEdit::undoAvailable
- \brief whether undo is available.
+ \brief Whether undo is available.
Undo becomes available once the user has modified the text in the line edit.
@@ -1020,10 +1023,10 @@ bool QLineEdit::isUndoAvailable() const
/*!
\property QLineEdit::redoAvailable
- \brief whether redo is available.
+ \brief Whether redo is available.
Redo becomes available once the user has performed one or more undo operations
- on text in the line edit.
+ on the text in the line edit.
By default, this property is \c false.
*/
@@ -1036,7 +1039,7 @@ bool QLineEdit::isRedoAvailable() const
/*!
\property QLineEdit::dragEnabled
- \brief whether the lineedit starts a drag if the user presses and
+ \brief Whether the line edit starts a drag if the user presses and
moves the mouse on some selected text.
Dragging is disabled by default.
@@ -1056,17 +1059,18 @@ void QLineEdit::setDragEnabled(bool b)
/*!
\property QLineEdit::cursorMoveStyle
- \brief the movement style of cursor in this line edit.
+ \brief The movement style of the cursor in this line edit.
\since 4.8
- When this property is set to Qt::VisualMoveStyle, the line edit will use visual
- movement style. Pressing the left arrow key will always cause the cursor to move
- left, regardless of the text's writing direction. The same behavior applies to
- right arrow key.
+ When this property is set to Qt::VisualMoveStyle, the line edit will use a
+ visual movement style. Using the left arrow key will always cause the
+ cursor to move left, regardless of the text's writing direction. The same
+ behavior applies to the right arrow key.
- When the property is Qt::LogicalMoveStyle (the default), within a LTR text block,
- increase cursor position when pressing left arrow key, decrease cursor position
- when pressing the right arrow key. If the text block is right to left, the opposite
+ When the property is set to Qt::LogicalMoveStyle (the default), within a
+ left-to-right (LTR) text block, using the left arrow key will increase
+ the cursor position, whereas using the right arrow key will decrease the
+ cursor position. If the text block is right-to-left (RTL), the opposite
behavior applies.
*/
@@ -1084,7 +1088,7 @@ void QLineEdit::setCursorMoveStyle(Qt::CursorMoveStyle style)
/*!
\property QLineEdit::acceptableInput
- \brief whether the input satisfies the inputMask and the
+ \brief Whether the input satisfies the inputMask and the
validator.
By default, this property is \c true.
@@ -1098,11 +1102,11 @@ bool QLineEdit::hasAcceptableInput() const
}
/*!
+ \since 4.5
Sets the margins around the text inside the frame to have the
sizes \a left, \a top, \a right, and \a bottom.
- \since 4.5
- See also textMargins().
+ \sa textMargins()
*/
void QLineEdit::setTextMargins(int left, int top, int right, int bottom)
{
@@ -1113,7 +1117,7 @@ void QLineEdit::setTextMargins(int left, int top, int right, int bottom)
\since 4.6
Sets the \a margins around the text inside the frame.
- See also textMargins().
+ \sa textMargins()
*/
void QLineEdit::setTextMargins(const QMargins &margins)
{
@@ -1139,41 +1143,47 @@ QMargins QLineEdit::textMargins() const
\property QLineEdit::inputMask
\brief The validation input mask.
- If no mask is set, inputMask() returns an empty string.
-
Sets the QLineEdit's validation mask. Validators can be used
- instead of, or in conjunction with masks; see setValidator().
+ instead of, or in conjunction with masks; see setValidator(). The default is
+ an empty string, which means that no input mask is used.
- Unset the mask and return to normal QLineEdit operation by passing
- an empty string ("").
+ To unset the mask and return to normal QLineEdit operation, pass an empty
+ string.
- The input mask is an input template string. It can contain the following elements:
+ The input mask is an input template string. It can contain the following
+ elements:
\table
- \row \li Mask Characters \li Defines the \l {QChar::} {Category} of input characters
- that are considered valid in this position
- \row \li Meta Characters \li Various special meanings
- \row \li Separators \li All other characters are regarded as immutable separators
+ \row \li Mask Characters \li Defines the \l {QChar::} {Category} of input
+ characters that are considered valid in this position.
+ \row \li Meta Characters \li Various special meanings (see details below).
+ \row \li Separators \li All other characters are regarded as immutable
+ separators.
\endtable
- The following table shows the mask and meta characters that can be used in an input mask.
+ The following table shows the mask and meta characters that can be used in
+ an input mask.
\table
\header \li Mask Character \li Meaning
- \row \li \c A \li character of the Letter category required, such as A-Z, a-z.
- \row \li \c a \li character of the Letter category permitted but not required.
- \row \li \c N \li character of the Letter or Number category required, such as
- A-Z, a-z, 0-9.
- \row \li \c n \li character of the Letter or Number category permitted but not required.
+ \row \li \c A \li Character of the Letter category required, such as A-Z,
+ a-z.
+ \row \li \c a \li Character of the Letter category permitted but not
+ required.
+ \row \li \c N \li Character of the Letter or Number category required, such
+ as A-Z, a-z, 0-9.
+ \row \li \c n \li Character of the Letter or Number category permitted but
+ not required.
\row \li \c X \li Any non-blank character required.
\row \li \c x \li Any non-blank character permitted but not required.
- \row \li \c 9 \li character of the Number category required, e.g 0-9.
- \row \li \c 0 \li character of the Number category permitted but not required.
- \row \li \c D \li character of the Number category and larger than zero required,
- such as 1-9
- \row \li \c d \li character of the Number category and larger than zero permitted but not
- required, such as 1-9.
- \row \li \c # \li character of the Number category, or plus/minus sign permitted but not
+ \row \li \c 9 \li Character of the Number category required, such as 0-9.
+ \row \li \c 0 \li Character of the Number category permitted but not
required.
+ \row \li \c D \li Character of the Number category and larger than zero
+ required, such as 1-9.
+ \row \li \c d \li Character of the Number category and larger than zero
+ permitted but not required, such as 1-9.
+ \row \li \c # \li Character of the Number category, or plus/minus sign
+ permitted but not required.
\row \li \c H \li Hexadecimal character required. A-F, a-f, 0-9.
\row \li \c h \li Hexadecimal character permitted but not required.
\row \li \c B \li Binary character required. 0-1.
@@ -1182,11 +1192,11 @@ QMargins QLineEdit::textMargins() const
\row \li \c > \li All following alphabetic characters are uppercased.
\row \li \c < \li All following alphabetic characters are lowercased.
\row \li \c ! \li Switch off case conversion.
- \row \li \c {;c} \li Terminates the input mask and sets the \e{blank} character to \e{c}.
+ \row \li \c {;c} \li Terminates the input mask and sets the \e{blank}
+ character to \e{c}.
\row \li \c {[ ] { }} \li Reserved.
- \row \li \tt{\\} \li Use \tt{\\} to escape the special
- characters listed above to use them as
- separators.
+ \row \li \tt{\\} \li Use \tt{\\} to escape the special characters listed
+ above to use them as separators.
\endtable
When created or cleared, the line edit will be filled with a copy of the
@@ -1199,7 +1209,7 @@ QMargins QLineEdit::textMargins() const
unmodified content can be read using displayText().
The hasAcceptableInput() method returns false if the current content of the
- line edit does not fulfil the requirements of the input mask.
+ line edit does not fulfill the requirements of the input mask.
Examples:
\table
@@ -1230,8 +1240,10 @@ void QLineEdit::setInputMask(const QString &inputMask)
}
/*!
- Selects all the text (i.e. highlights it) and moves the cursor to
- the end. This is useful when a default value has been inserted
+ Selects all the text (highlights it) and moves the cursor to
+ the end.
+
+ \note This is useful when a default value has been inserted
because if the user types before clicking on the widget, the
selected text will be deleted.
@@ -1259,7 +1271,7 @@ void QLineEdit::deselect()
/*!
Deletes any selected text, inserts \a newText, and validates the
- result. If it is valid, it sets it as the new contents of the line
+ result. If it is valid, it sets the new text as the new contents of the line
edit.
\sa setText(), clear()
@@ -1308,7 +1320,7 @@ void QLineEdit::redo()
/*!
\property QLineEdit::readOnly
- \brief whether the line edit is read only.
+ \brief Whether the line edit is read-only.
In read-only mode, the user can still copy the text to the
clipboard, or drag and drop the text (if echoMode() is \l Normal),
@@ -1431,7 +1443,10 @@ bool QLineEdit::event(QEvent * e)
#endif
//d->separate();
} else if (e->type() == QEvent::WindowActivate) {
- QTimer::singleShot(0, this, SLOT(_q_handleWindowActivate()));
+ QTimer::singleShot(0, this, [this]() {
+ Q_D(QLineEdit);
+ d->handleWindowActivate();
+ });
#ifndef QT_NO_SHORTCUT
} else if (e->type() == QEvent::ShortcutOverride) {
QKeyEvent *ke = static_cast<QKeyEvent*>(e);
@@ -1447,6 +1462,8 @@ bool QLineEdit::event(QEvent * e)
|| style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected, &opt, this))
d->setCursorVisible(true);
}
+ } else if (e->type() == QEvent::Hide) {
+ d->control->setBlinkingCursorEnabled(false);
#if QT_CONFIG(action)
} else if (e->type() == QEvent::ActionRemoved) {
d->removeAction(static_cast<QActionEvent *>(e)->action());
@@ -1647,8 +1664,9 @@ void QLineEdit::mouseDoubleClickEvent(QMouseEvent* e)
/*!
\fn void QLineEdit::returnPressed()
- This signal is emitted when the Return or Enter key is pressed.
- Note that if there is a validator() or inputMask() set on the line
+ This signal is emitted when the Return or Enter key is used.
+
+ \note If there is a validator() or inputMask() set on the line
edit, the returnPressed() signal will only be emitted if the input
follows the inputMask() and the validator() returns
QValidator::Acceptable.
@@ -1657,41 +1675,39 @@ void QLineEdit::mouseDoubleClickEvent(QMouseEvent* e)
/*!
\fn void QLineEdit::editingFinished()
- This signal is emitted when the Return or Enter key is pressed, or
- if the line edit loses focus and its contents have changed since the
- last time this signal was emitted.
+ This signal is emitted when the Return or Enter key is used, or if the line
+ edit loses focus and its contents have changed since the last time this
+ signal was emitted.
- Note that if there is a validator() or
- inputMask() set on the line edit and enter/return is pressed, the
- editingFinished() signal will only be emitted if the input follows
- the inputMask() and the validator() returns QValidator::Acceptable.
+ \note If there is a validator() or inputMask() set on the line edit and
+ enter/return is used, the editingFinished() signal will only be emitted
+ if the input follows the inputMask() and the validator() returns
+ QValidator::Acceptable.
*/
/*!
\fn void QLineEdit::inputRejected()
\since 5.12
- This signal is emitted when the user presses a key that is not
- considered to be acceptable input. For example, if a key press
- results in a validator's validate() call to return Invalid.
- Another case is when trying to enter in more characters beyond the
- maximum length of the line edit.
+ This signal is emitted when the user uses a key that is not
+ considered to be valid input. For example, if using a key results in a
+ validator's \l {QValidator::validate()}{validate()} call to return
+ \l {QValidator::Invalid}{Invalid}. Another case is when trying
+ to enter more characters beyond the maximum length of the line edit.
- Note: This signal will still be emitted in a case where part of
- the text is accepted but not all of it is. For example, if there
- is a maximum length set and the clipboard text is longer than the
- maximum length when it is pasted.
+ \note This signal will still be emitted when only a part of the text is
+ accepted. For example, if there is a maximum length set and the clipboard
+ text is longer than the maximum length when it is pasted.
*/
/*!
Converts the given key press \a event into a line edit action.
- If Return or Enter is pressed and the current text is valid (or
+ If Return or Enter is used and the current text is valid (or
can be \l{QValidator::fixup()}{made valid} by the
validator), the signal returnPressed() is emitted.
- The default key bindings are listed in the class's detailed
- description.
+ \sa {Default Key Bindings}
*/
void QLineEdit::keyPressEvent(QKeyEvent *event)
@@ -1747,18 +1763,19 @@ void QLineEdit::keyPressEvent(QKeyEvent *event)
/*!
\reimp
*/
-void QLineEdit::keyReleaseEvent(QKeyEvent *)
+void QLineEdit::keyReleaseEvent(QKeyEvent *e)
{
Q_D(QLineEdit);
if (!isReadOnly())
d->handleSoftwareInputPanel();
d->control->updateCursorBlinking();
+ QWidget::keyReleaseEvent(e);
}
/*!
\since 4.4
- Returns a rectangle that includes the lineedit cursor.
+ Returns a rectangle that includes the line edit cursor.
*/
QRect QLineEdit::cursorRect() const
{
@@ -1828,7 +1845,7 @@ QVariant QLineEdit::inputMethodQuery(Qt::InputMethodQuery property, QVariant arg
Q_D(const QLineEdit);
switch(property) {
case Qt::ImEnabled:
- return isEnabled();
+ return isEnabled() && !isReadOnly();
case Qt::ImCursorRectangle:
return d->cursorRect();
case Qt::ImAnchorRectangle:
@@ -1908,10 +1925,7 @@ void QLineEdit::focusInEvent(QFocusEvent *e)
#if QT_CONFIG(completer)
if (d->control->completer()) {
d->control->completer()->setWidget(this);
- QObject::connect(d->control->completer(), SIGNAL(activated(QString)),
- this, SLOT(setText(QString)));
- QObject::connect(d->control->completer(), SIGNAL(highlighted(QString)),
- this, SLOT(_q_completionHighlighted(QString)));
+ d->connectCompleter();
}
#endif
update();
@@ -1950,9 +1964,8 @@ void QLineEdit::focusOutEvent(QFocusEvent *e)
d->control->setCancelText(QString());
#endif
#if QT_CONFIG(completer)
- if (d->control->completer()) {
- QObject::disconnect(d->control->completer(), nullptr, this, nullptr);
- }
+ if (d->control->completer())
+ d->disconnectCompleter();
#endif
QWidget::focusOutEvent(e);
}
@@ -2083,7 +2096,7 @@ void QLineEdit::paintEvent(QPaintEvent *)
if (d->cursorVisible && !d->control->isReadOnly() && d->control->inputMask().isEmpty())
flags |= QWidgetLineControl::DrawCursor;
- d->control->setCursorWidth(style()->pixelMetric(QStyle::PM_TextCursorWidth, &panel));
+ d->control->setCursorWidth(style()->pixelMetric(QStyle::PM_TextCursorWidth, &panel, this));
d->control->draw(&p, topLeft, r, flags);
}
@@ -2162,10 +2175,10 @@ void QLineEdit::dropEvent(QDropEvent* e)
createStandardContextMenu().
If you do not want the line edit to have a context menu, you can set
- its \l contextMenuPolicy to Qt::NoContextMenu. If you want to
- customize the context menu, reimplement this function. If you want
- to extend the standard context menu, reimplement this function, call
- createStandardContextMenu() and extend the menu returned.
+ its \l contextMenuPolicy to Qt::NoContextMenu. To customize the context
+ menu, reimplement this function. To extend the standard context menu,
+ reimplement this function, call createStandardContextMenu(), and extend the
+ menu returned.
\snippet code/src_gui_widgets_qlineedit.cpp 0
@@ -2182,14 +2195,7 @@ void QLineEdit::contextMenuEvent(QContextMenuEvent *event)
}
}
-static inline void setActionIcon(QAction *action, const QString &name)
-{
- const QIcon icon = QIcon::fromTheme(name);
- if (!icon.isNull())
- action->setIcon(icon);
-}
-
-/*! This function creates the standard context menu which is shown
+/*! Creates the standard context menu, which is shown
when the user clicks on the line edit with the right mouse
button. It is called from the default contextMenuEvent() handler.
The popup menu's ownership is transferred to the caller.
@@ -2206,12 +2212,12 @@ QMenu *QLineEdit::createStandardContextMenu()
action = popup->addAction(QLineEdit::tr("&Undo") + ACCEL_KEY(QKeySequence::Undo));
action->setEnabled(d->control->isUndoAvailable());
setActionIcon(action, QStringLiteral("edit-undo"));
- connect(action, SIGNAL(triggered()), SLOT(undo()));
+ connect(action, &QAction::triggered, this, &QLineEdit::undo);
action = popup->addAction(QLineEdit::tr("&Redo") + ACCEL_KEY(QKeySequence::Redo));
action->setEnabled(d->control->isRedoAvailable());
setActionIcon(action, QStringLiteral("edit-redo"));
- connect(action, SIGNAL(triggered()), SLOT(redo()));
+ connect(action, &QAction::triggered, this, &QLineEdit::redo);
popup->addSeparator();
}
@@ -2222,20 +2228,20 @@ QMenu *QLineEdit::createStandardContextMenu()
action->setEnabled(!d->control->isReadOnly() && d->control->hasSelectedText()
&& d->control->echoMode() == QLineEdit::Normal);
setActionIcon(action, QStringLiteral("edit-cut"));
- connect(action, SIGNAL(triggered()), SLOT(cut()));
+ connect(action, &QAction::triggered, this, &QLineEdit::cut);
}
action = popup->addAction(QLineEdit::tr("&Copy") + ACCEL_KEY(QKeySequence::Copy));
action->setEnabled(d->control->hasSelectedText()
&& d->control->echoMode() == QLineEdit::Normal);
setActionIcon(action, QStringLiteral("edit-copy"));
- connect(action, SIGNAL(triggered()), SLOT(copy()));
+ connect(action, &QAction::triggered, this, &QLineEdit::copy);
if (!isReadOnly()) {
action = popup->addAction(QLineEdit::tr("&Paste") + ACCEL_KEY(QKeySequence::Paste));
action->setEnabled(!d->control->isReadOnly() && !QGuiApplication::clipboard()->text().isEmpty());
setActionIcon(action, QStringLiteral("edit-paste"));
- connect(action, SIGNAL(triggered()), SLOT(paste()));
+ connect(action, &QAction::triggered, this, &QLineEdit::paste);
}
#endif
@@ -2243,7 +2249,8 @@ QMenu *QLineEdit::createStandardContextMenu()
action = popup->addAction(QLineEdit::tr("Delete"));
action->setEnabled(!d->control->isReadOnly() && !d->control->text().isEmpty() && d->control->hasSelectedText());
setActionIcon(action, QStringLiteral("edit-delete"));
- connect(action, SIGNAL(triggered()), d->control, SLOT(_q_deleteSelected()));
+ connect(action, &QAction::triggered,
+ d->control, &QWidgetLineControl::_q_deleteSelected);
}
if (!popup->isEmpty())
@@ -2253,7 +2260,7 @@ QMenu *QLineEdit::createStandardContextMenu()
action->setEnabled(!d->control->text().isEmpty() && !d->control->allSelected());
setActionIcon(action, QStringLiteral("edit-select-all"));
d->selectAllAction = action;
- connect(action, SIGNAL(triggered()), SLOT(selectAll()));
+ connect(action, &QAction::triggered, this, &QLineEdit::selectAll);
if (!d->control->isReadOnly() && QGuiApplication::styleHints()->useRtlExtensions()) {
popup->addSeparator();
diff --git a/src/widgets/widgets/qlineedit.h b/src/widgets/widgets/qlineedit.h
index e0729f0929..8955a67895 100644
--- a/src/widgets/widgets/qlineedit.h
+++ b/src/widgets/widgets/qlineedit.h
@@ -214,20 +214,6 @@ private:
#endif
Q_DISABLE_COPY(QLineEdit)
Q_DECLARE_PRIVATE(QLineEdit)
- Q_PRIVATE_SLOT(d_func(), void _q_handleWindowActivate())
- Q_PRIVATE_SLOT(d_func(), void _q_textEdited(const QString &))
- Q_PRIVATE_SLOT(d_func(), void _q_cursorPositionChanged(int, int))
-#if QT_CONFIG(completer)
- Q_PRIVATE_SLOT(d_func(), void _q_completionHighlighted(const QString &))
-#endif
-#ifdef QT_KEYPAD_NAVIGATION
- Q_PRIVATE_SLOT(d_func(), void _q_editFocusChange(bool))
-#endif
- Q_PRIVATE_SLOT(d_func(), void _q_selectionChanged())
- Q_PRIVATE_SLOT(d_func(), void _q_updateNeeded(const QRect &))
- Q_PRIVATE_SLOT(d_func(), void _q_textChanged(const QString &))
- Q_PRIVATE_SLOT(d_func(), void _q_clearButtonClicked())
- Q_PRIVATE_SLOT(d_func(), void _q_controlEditingFinished())
};
QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qlineedit_p.cpp b/src/widgets/widgets/qlineedit_p.cpp
index d1b95da00a..fdd6a3aa4f 100644
--- a/src/widgets/widgets/qlineedit_p.cpp
+++ b/src/widgets/widgets/qlineedit_p.cpp
@@ -74,8 +74,25 @@ QRect QLineEditPrivate::cursorRect() const
}
#if QT_CONFIG(completer)
+void QLineEditPrivate::connectCompleter()
+{
+ Q_Q(const QLineEdit);
+ QObject::connect(control->completer(), qOverload<const QString &>(&QCompleter::activated),
+ q, &QLineEdit::setText);
+ QObjectPrivate::connect(control->completer(), qOverload<const QString &>(&QCompleter::highlighted),
+ this, &QLineEditPrivate::completionHighlighted);
+}
+
+void QLineEditPrivate::disconnectCompleter()
+{
+ Q_Q(const QLineEdit);
+ QObject::disconnect(control->completer(), qOverload<const QString &>(&QCompleter::activated),
+ q, &QLineEdit::setText);
+ QObjectPrivate::disconnect(control->completer(), qOverload<const QString &>(&QCompleter::highlighted),
+ this, &QLineEditPrivate::completionHighlighted);
+}
-void QLineEditPrivate::_q_completionHighlighted(const QString &newText)
+void QLineEditPrivate::completionHighlighted(const QString &newText)
{
Q_Q(QLineEdit);
if (control->completer()->completionMode() != QCompleter::InlineCompletion) {
@@ -96,14 +113,14 @@ void QLineEditPrivate::_q_completionHighlighted(const QString &newText)
#endif // QT_CONFIG(completer)
-void QLineEditPrivate::_q_handleWindowActivate()
+void QLineEditPrivate::handleWindowActivate()
{
Q_Q(QLineEdit);
if (!q->hasFocus() && control->hasSelectedText())
control->deselect();
}
-void QLineEditPrivate::_q_textEdited(const QString &text)
+void QLineEditPrivate::textEdited(const QString &text)
{
Q_Q(QLineEdit);
edited = true;
@@ -115,7 +132,7 @@ void QLineEditPrivate::_q_textEdited(const QString &text)
#endif
}
-void QLineEditPrivate::_q_cursorPositionChanged(int from, int to)
+void QLineEditPrivate::cursorPositionChanged(int from, int to)
{
Q_Q(QLineEdit);
q->update();
@@ -123,14 +140,14 @@ void QLineEditPrivate::_q_cursorPositionChanged(int from, int to)
}
#ifdef QT_KEYPAD_NAVIGATION
-void QLineEditPrivate::_q_editFocusChange(bool e)
+void QLineEditPrivate::editFocusChange(bool e)
{
Q_Q(QLineEdit);
q->setEditFocus(e);
}
#endif
-void QLineEditPrivate::_q_selectionChanged()
+void QLineEditPrivate::selectionChanged()
{
Q_Q(QLineEdit);
if (control->preeditAreaText().isEmpty()) {
@@ -150,7 +167,7 @@ void QLineEditPrivate::_q_selectionChanged()
#endif
}
-void QLineEditPrivate::_q_updateNeeded(const QRect &rect)
+void QLineEditPrivate::updateNeeded(const QRect &rect)
{
q_func()->update(adjustedControlRect(rect));
}
@@ -158,45 +175,51 @@ void QLineEditPrivate::_q_updateNeeded(const QRect &rect)
void QLineEditPrivate::init(const QString& txt)
{
Q_Q(QLineEdit);
+
+ const auto qUpdateMicroFocus = [q]()
+ {
+ q->updateMicroFocus();
+ };
control = new QWidgetLineControl(txt);
control->setParent(q);
control->setFont(q->font());
- QObject::connect(control, SIGNAL(textChanged(QString)),
- q, SIGNAL(textChanged(QString)));
- QObject::connect(control, SIGNAL(textEdited(QString)),
- q, SLOT(_q_textEdited(QString)));
- QObject::connect(control, SIGNAL(cursorPositionChanged(int,int)),
- q, SLOT(_q_cursorPositionChanged(int,int)));
- QObject::connect(control, SIGNAL(selectionChanged()),
- q, SLOT(_q_selectionChanged()));
- QObject::connect(control, SIGNAL(editingFinished()),
- q, SLOT(_q_controlEditingFinished()));
+ QObject::connect(control, &QWidgetLineControl::textChanged,
+ q, &QLineEdit::textChanged);
+ QObjectPrivate::connect(control, &QWidgetLineControl::textEdited,
+ this, &QLineEditPrivate::textEdited);
+ QObjectPrivate::connect(control, &QWidgetLineControl::cursorPositionChanged,
+ this, &QLineEditPrivate::cursorPositionChanged);
+ QObjectPrivate::connect(control, &QWidgetLineControl::selectionChanged,
+ this, &QLineEditPrivate::selectionChanged);
+ QObjectPrivate::connect(control, &QWidgetLineControl::editingFinished,
+ this, &QLineEditPrivate::controlEditingFinished);
#ifdef QT_KEYPAD_NAVIGATION
- QObject::connect(control, SIGNAL(editFocusChange(bool)),
- q, SLOT(_q_editFocusChange(bool)));
+ QObject::connect(control, &QWidgetLineControl::editFocusChange,
+ this, &QLineEditPrivate::editFocusChange);
#endif
- QObject::connect(control, SIGNAL(cursorPositionChanged(int,int)),
- q, SLOT(updateMicroFocus()));
+ QObject::connect(control, &QWidgetLineControl::cursorPositionChanged,
+ q, qUpdateMicroFocus);
- QObject::connect(control, SIGNAL(textChanged(QString)),
- q, SLOT(updateMicroFocus()));
+ QObject::connect(control, &QWidgetLineControl::textChanged,
+ q, qUpdateMicroFocus);
- QObject::connect(control, SIGNAL(updateMicroFocus()),
- q, SLOT(updateMicroFocus()));
+ QObject::connect(control, &QWidgetLineControl::updateMicroFocus,
+ q, qUpdateMicroFocus);
// for now, going completely overboard with updates.
- QObject::connect(control, SIGNAL(selectionChanged()),
- q, SLOT(update()));
+ QObject::connect(control, &QWidgetLineControl::selectionChanged,
+ q, qOverload<>(&QLineEdit::update));
- QObject::connect(control, SIGNAL(selectionChanged()),
- q, SLOT(updateMicroFocus()));
+ QObject::connect(control, &QWidgetLineControl::selectionChanged,
+ q, qUpdateMicroFocus);
- QObject::connect(control, SIGNAL(displayTextChanged(QString)),
- q, SLOT(update()));
+ QObject::connect(control, &QWidgetLineControl::displayTextChanged,
+ q, qOverload<>(&QLineEdit::update));
- QObject::connect(control, SIGNAL(updateNeeded(QRect)),
- q, SLOT(_q_updateNeeded(QRect)));
- QObject::connect(control, SIGNAL(inputRejected()), q, SIGNAL(inputRejected()));
+ QObjectPrivate::connect(control, &QWidgetLineControl::updateNeeded,
+ this, &QLineEditPrivate::updateNeeded);
+ QObject::connect(control, &QWidgetLineControl::inputRejected,
+ q, &QLineEdit::inputRejected);
QStyleOptionFrame opt;
q->initStyleOption(&opt);
@@ -409,7 +432,7 @@ void QLineEditIconButton::animateShow(bool visible)
void QLineEditIconButton::startOpacityAnimation(qreal endValue)
{
- QPropertyAnimation *animation = new QPropertyAnimation(this, QByteArrayLiteral("opacity"));
+ QPropertyAnimation *animation = new QPropertyAnimation(this, QByteArrayLiteral("opacity"), this);
connect(animation, &QPropertyAnimation::finished, this, &QLineEditIconButton::onAnimationFinished);
animation->setDuration(160);
@@ -436,7 +459,7 @@ static void displayWidgets(const QLineEditPrivate::SideWidgetEntryList &widgets,
}
#endif
-void QLineEditPrivate::_q_textChanged(const QString &text)
+void QLineEditPrivate::textChanged(const QString &text)
{
if (hasSideWidgets()) {
const int newTextSize = text.size();
@@ -451,16 +474,16 @@ void QLineEditPrivate::_q_textChanged(const QString &text)
}
}
-void QLineEditPrivate::_q_clearButtonClicked()
+void QLineEditPrivate::clearButtonClicked()
{
Q_Q(QLineEdit);
if (!q->text().isEmpty()) {
q->clear();
- _q_textEdited(QString());
+ textEdited(QString());
}
}
-void QLineEditPrivate::_q_controlEditingFinished()
+void QLineEditPrivate::controlEditingFinished()
{
Q_Q(QLineEdit);
edited = false;
@@ -554,7 +577,8 @@ QWidget *QLineEditPrivate::addAction(QAction *newAction, QAction *before, QLineE
if (!newAction)
return nullptr;
if (!hasSideWidgets()) { // initial setup.
- QObject::connect(q, SIGNAL(textChanged(QString)), q, SLOT(_q_textChanged(QString)));
+ QObjectPrivate::connect(q, &QLineEdit::textChanged,
+ this, &QLineEditPrivate::textChanged);
lastTextSize = q->text().size();
}
QWidget *w = nullptr;
@@ -570,7 +594,8 @@ QWidget *QLineEditPrivate::addAction(QAction *newAction, QAction *before, QLineE
toolButton->setIcon(newAction->icon());
toolButton->setOpacity(lastTextSize > 0 || !(flags & SideWidgetFadeInWithText) ? 1 : 0);
if (flags & SideWidgetClearButton) {
- QObject::connect(toolButton, SIGNAL(clicked()), q, SLOT(_q_clearButtonClicked()));
+ QObjectPrivate::connect(toolButton, &QToolButton::clicked,
+ this, &QLineEditPrivate::clearButtonClicked);
#if QT_CONFIG(animation)
// The clear button is handled only by this widget. The button should be really
@@ -633,7 +658,8 @@ void QLineEditPrivate::removeAction(QAction *action)
delete entry.widget;
positionSideWidgets();
if (!hasSideWidgets()) // Last widget, remove connection
- QObject::disconnect(q, SIGNAL(textChanged(QString)), q, SLOT(_q_textChanged(QString)));
+ QObjectPrivate::connect(q, &QLineEdit::textChanged,
+ this, &QLineEditPrivate::textChanged);
q->update();
}
#endif // QT_CONFIG(action)
diff --git a/src/widgets/widgets/qlineedit_p.h b/src/widgets/widgets/qlineedit_p.h
index 64350ae39a..3737ac8fe6 100644
--- a/src/widgets/widgets/qlineedit_p.h
+++ b/src/widgets/widgets/qlineedit_p.h
@@ -190,25 +190,27 @@ public:
QRect adjustedContentsRect() const;
- void _q_handleWindowActivate();
- void _q_textEdited(const QString &);
- void _q_cursorPositionChanged(int, int);
+ void handleWindowActivate();
+ void textEdited(const QString &);
+ void cursorPositionChanged(int, int);
#ifdef QT_KEYPAD_NAVIGATION
- void _q_editFocusChange(bool);
+ void editFocusChange(bool);
#endif
- void _q_selectionChanged();
- void _q_updateNeeded(const QRect &);
+ void selectionChanged();
+ void updateNeeded(const QRect &);
#if QT_CONFIG(completer)
- void _q_completionHighlighted(const QString &);
+ void connectCompleter();
+ void disconnectCompleter();
+ void completionHighlighted(const QString &);
#endif
QPoint mousePressPos;
#if QT_CONFIG(draganddrop)
QBasicTimer dndTimer;
void drag();
#endif
- void _q_textChanged(const QString &);
- void _q_clearButtonClicked();
- void _q_controlEditingFinished();
+ void textChanged(const QString &);
+ void clearButtonClicked();
+ void controlEditingFinished();
QMargins textMargins; // use effectiveTextMargins() in case of icon.
diff --git a/src/widgets/widgets/qmainwindow.cpp b/src/widgets/widgets/qmainwindow.cpp
index a5f7973994..4534058d45 100644
--- a/src/widgets/widgets/qmainwindow.cpp
+++ b/src/widgets/widgets/qmainwindow.cpp
@@ -25,6 +25,7 @@
#include <qstyle.h>
#include <qdebug.h>
#include <qpainter.h>
+#include <qmimedata.h>
#include <private/qwidget_p.h>
#if QT_CONFIG(toolbar)
@@ -36,6 +37,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
class QMainWindowPrivate : public QWidgetPrivate
{
Q_DECLARE_PUBLIC(QMainWindow)
@@ -46,7 +49,7 @@ public:
, useUnifiedToolBar(false)
#endif
{ }
- QMainWindowLayout *layout;
+ QPointer<QMainWindowLayout> layout;
QSize iconSize;
bool explicitIconSize;
Qt::ToolButtonStyle toolButtonStyle;
@@ -57,7 +60,7 @@ public:
static inline QMainWindowLayout *mainWindowLayout(const QMainWindow *mainWindow)
{
- return mainWindow ? mainWindow->d_func()->layout : static_cast<QMainWindowLayout *>(nullptr);
+ return mainWindow ? mainWindow->d_func()->layout.data() : static_cast<QMainWindowLayout *>(nullptr);
}
};
@@ -121,6 +124,7 @@ void QMainWindowPrivate::init()
const int metric = q->style()->pixelMetric(QStyle::PM_ToolBarIconSize, nullptr, q);
iconSize = QSize(metric, metric);
q->setAttribute(Qt::WA_Hover);
+ q->setAcceptDrops(true);
}
/*
@@ -276,9 +280,7 @@ void QMainWindowPrivate::init()
is the position and size (relative to the size of the main window)
of the toolbars and dock widgets that are stored.
- \sa QMenuBar, QToolBar, QStatusBar, QDockWidget,
- {Qt Widgets - Application Example}, {Dock Widgets Example},
- {MDI Example}, {Menus Example}
+ \sa QMenuBar, QToolBar, QStatusBar, QDockWidget, {Menus Example}
*/
/*!
@@ -1121,21 +1123,8 @@ void QMainWindow::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
QList<QDockWidget*> QMainWindow::tabifiedDockWidgets(QDockWidget *dockwidget) const
{
- QList<QDockWidget*> ret;
- const QDockAreaLayoutInfo *info = d_func()->layout->layoutState.dockAreaLayout.info(dockwidget);
- if (info && info->tabbed && info->tabBar) {
- for(int i = 0; i < info->item_list.size(); ++i) {
- const QDockAreaLayoutItem &item = info->item_list.at(i);
- if (item.widgetItem) {
- if (QDockWidget *dock = qobject_cast<QDockWidget*>(item.widgetItem->widget())) {
- if (dock != dockwidget) {
- ret += dock;
- }
- }
- }
- }
- }
- return ret;
+ Q_D(const QMainWindow);
+ return d->layout ? d->layout->tabifiedDockWidgets(dockwidget) : QList<QDockWidget *>();
}
#endif // QT_CONFIG(tabbar)
@@ -1296,6 +1285,28 @@ bool QMainWindow::event(QEvent *event)
if (!d->explicitIconSize)
setIconSize(QSize());
break;
+#if QT_CONFIG(draganddrop)
+ case QEvent::DragEnter:
+ case QEvent::Drop:
+ if (!d->layout->draggingWidget)
+ break;
+ event->accept();
+ return true;
+ case QEvent::DragMove: {
+ if (!d->layout->draggingWidget)
+ break;
+ auto dragMoveEvent = static_cast<QDragMoveEvent *>(event);
+ d->layout->hover(d->layout->draggingWidget,
+ mapToGlobal(dragMoveEvent->position()).toPoint());
+ event->accept();
+ return true;
+ }
+ case QEvent::DragLeave:
+ if (!d->layout->draggingWidget)
+ break;
+ d->layout->hover(d->layout->draggingWidget, pos() - QPoint(-1, -1));
+ return true;
+#endif
default:
break;
}
diff --git a/src/widgets/widgets/qmainwindow.h b/src/widgets/widgets/qmainwindow.h
index 90e37d7283..a050093417 100644
--- a/src/widgets/widgets/qmainwindow.h
+++ b/src/widgets/widgets/qmainwindow.h
@@ -178,6 +178,7 @@ protected:
private:
Q_DECLARE_PRIVATE(QMainWindow)
Q_DISABLE_COPY(QMainWindow)
+ friend class QDockWidgetGroupWindow;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QMainWindow::DockOptions)
diff --git a/src/widgets/widgets/qmainwindowlayout.cpp b/src/widgets/widgets/qmainwindowlayout.cpp
index a1b1b20869..85c58fd70f 100644
--- a/src/widgets/widgets/qmainwindowlayout.cpp
+++ b/src/widgets/widgets/qmainwindowlayout.cpp
@@ -24,6 +24,10 @@
#endif
#include <qapplication.h>
+#if QT_CONFIG(draganddrop)
+#include <qdrag.h>
+#endif
+#include <qmimedata.h>
#if QT_CONFIG(statusbar)
#include <qstatusbar.h>
#endif
@@ -46,6 +50,8 @@
#include <private/qlayoutengine_p.h>
#include <private/qwidgetresizehandler_p.h>
+#include <QScopedValueRollback>
+
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
@@ -145,18 +151,57 @@ QDebug operator<<(QDebug debug, const QMainWindowLayout *layout)
return debug;
}
+// Use this to dump item lists of all populated main window docks.
+// Use DUMP macro inside QMainWindowLayout
+#if 0
+static void dumpItemLists(const QMainWindowLayout *layout, const char *function, const char *comment)
+{
+ for (int i = 0; i < QInternal::DockCount; ++i) {
+ const auto &list = layout->layoutState.dockAreaLayout.docks[i].item_list;
+ if (list.isEmpty())
+ continue;
+ qDebug() << function << comment << "Dock" << i << list;
+ }
+}
+#define DUMP(comment) dumpItemLists(this, __FUNCTION__, comment)
+#endif // 0
+
#endif // QT_CONFIG(dockwidget) && !defined(QT_NO_DEBUG)
-/******************************************************************************
- ** QDockWidgetGroupWindow
- */
-// QDockWidgetGroupWindow is the floating window containing several QDockWidgets floating together.
-// (QMainWindow::GroupedDragging feature)
-// QDockWidgetGroupLayout is the layout of that window and use a QDockAreaLayoutInfo to layout
-// the QDockWidgets inside it.
-// If there is only one QDockWidgets, or all QDockWidgets are tabbed together, it is equivalent
-// of a floating QDockWidget (the title of the QDockWidget is the title of the window). But if there
-// are nested QDockWidget, an additional title bar is there.
+
+/*!
+ \internal
+ QDockWidgetGroupWindow is a floating window, containing several QDockWidgets floating together.
+ This requires QMainWindow::GroupedDragging to be enabled.
+ QDockWidgets floating jointly in a QDockWidgetGroupWindow are considered to be docked.
+ Their \c isFloating property is \c false.
+ QDockWidget children of a QDockWidgetGroupWindow are either:
+ \list
+ \li tabbed (as long as Qt is compiled with the \c tabbar feature), or
+ \li arranged next to each other, equivalent to the default on a main window dock.
+ \endlist
+
+ QDockWidgetGroupWindow uses QDockWidgetGroupLayout to lay out its QDockWidget children.
+ It stores layout information in a QDockAreaLayoutInfo, including temporary spacer items
+ and rubber bands.
+
+ If its QDockWidget children are tabbed, the QDockWidgetGroupWindow shows the active QDockWidget's
+ title as its own window title.
+
+ QDockWidgetGroupWindow is designed to hold more than one QDockWidget.
+ A QDockWidgetGroupWindow with only one QDockWidget child may occur only temporarily
+ \list
+ \li in its construction phase, or
+ \li during a hover: While QDockWidget A is hovered over B, B is converted into a QDockWidgetGroupWindow.
+ \endlist
+
+ A QDockWidgetGroupWindow with only one QDockWidget child must never get focus, be dragged or dropped.
+ To enforce this restriction, QDockWidgetGrouWindow will remove itself after its second QDockWidget
+ child has been removed. It will make its last QDockWidget child a single, floating QDockWidget.
+ Eventually, the empty QDockWidgetGroupWindow will call deleteLater() on itself.
+*/
+
+
#if QT_CONFIG(dockwidget)
class QDockWidgetGroupLayout : public QLayout,
public QMainWindowLayoutSeparatorHelper<QDockWidgetGroupLayout>
@@ -293,6 +338,7 @@ bool QDockWidgetGroupWindow::event(QEvent *e)
case QEvent::Resize:
updateCurrentGapRect();
emit resized();
+ break;
default:
break;
}
@@ -397,8 +443,8 @@ void QDockWidgetGroupWindow::destroyOrHideIfEmpty()
}
// Make sure to reparent the possibly floating or hidden QDockWidgets to the parent
- const auto dockWidgets = findChildren<QDockWidget *>(Qt::FindDirectChildrenOnly);
- for (QDockWidget *dw : dockWidgets) {
+ const auto dockWidgetsList = dockWidgets();
+ for (QDockWidget *dw : dockWidgetsList) {
const bool wasFloating = dw->isFloating();
const bool wasHidden = dw->isHidden();
dw->setParent(parentWidget());
@@ -418,14 +464,28 @@ void QDockWidgetGroupWindow::destroyOrHideIfEmpty()
if (!wasHidden)
dw->show();
}
-#if QT_CONFIG(tabbar)
- const auto tabBars = findChildren<QTabBar *>(Qt::FindDirectChildrenOnly);
- for (QTabBar *tb : tabBars)
- tb->setParent(parentWidget());
-#endif
deleteLater();
}
+/*!
+ \internal
+ \return \c true if the group window has at least one visible QDockWidget child,
+ otherwise false.
+ */
+bool QDockWidgetGroupWindow::hasVisibleDockWidgets() const
+{
+ const auto &children = findChildren<QDockWidget *>(Qt::FindChildrenRecursively);
+ for (auto child : children) {
+ // WA_WState_Visible is set on the dock widget, associated to the active tab
+ // and unset on all others.
+ // WA_WState_Hidden is set if the dock widgets have been explicitly hidden.
+ // This is the relevant information to check (equivalent to !child->isHidden()).
+ if (!child->testAttribute(Qt::WA_WState_Hidden))
+ return true;
+ }
+ return false;
+}
+
/*! \internal
Sets the flags of this window in accordance to the capabilities of the dock widgets
*/
@@ -474,7 +534,7 @@ void QDockWidgetGroupWindow::adjustFlags()
m_removedFrameSize = QSize();
}
- show(); // setWindowFlags hides the window
+ setVisible(hasVisibleDockWidgets());
}
QWidget *titleBarOf = top ? top : parentWidget();
@@ -535,8 +595,12 @@ bool QDockWidgetGroupWindow::hover(QLayoutItem *widgetItem, const QPoint &mouseP
auto newGapPos = newState.gapIndex(mousePos, nestingEnabled, tabMode);
Q_ASSERT(!newGapPos.isEmpty());
- if (newGapPos == currentGapPos)
- return false; // gap is already there
+
+ // Do not insert a new gap item, if the current position already is a gap,
+ // or if the group window contains one
+ if (newGapPos == currentGapPos || newState.hasGapItem(newGapPos))
+ return false;
+
currentGapPos = newGapPos;
newState.insertGap(currentGapPos, widgetItem);
newState.fitItems();
@@ -583,6 +647,108 @@ void QDockWidgetGroupWindow::apply()
layoutInfo()->apply(false);
}
+void QDockWidgetGroupWindow::childEvent(QChildEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::ChildRemoved:
+ if (auto *dockWidget = qobject_cast<QDockWidget *>(event->child()))
+ dockWidget->removeEventFilter(this);
+ destroyIfSingleItemLeft();
+ break;
+ case QEvent::ChildAdded:
+ if (auto *dockWidget = qobject_cast<QDockWidget *>(event->child()))
+ dockWidget->installEventFilter(this);
+ break;
+ default:
+ break;
+ }
+}
+
+bool QDockWidgetGroupWindow::eventFilter(QObject *obj, QEvent *event)
+{
+ auto *dockWidget = qobject_cast<QDockWidget *>(obj);
+ if (!dockWidget)
+ return QWidget::eventFilter(obj, event);
+
+ switch (event->type()) {
+ case QEvent::Close:
+ // We don't want closed dock widgets in a floating tab
+ // => dock it to the main dock, before closing;
+ reparent(dockWidget);
+ dockWidget->setFloating(false);
+ break;
+
+ case QEvent::Hide:
+ // if the dock widget is not an active tab, it is hidden anyway.
+ // if it is the active tab, hide the whole group.
+ if (dockWidget->isVisible())
+ hide();
+ break;
+
+ default:
+ break;
+ }
+ return QWidget::eventFilter(obj, event);
+}
+
+void QDockWidgetGroupWindow::destroyIfSingleItemLeft()
+{
+ const auto &dockWidgets = this->dockWidgets();
+
+ // Handle only the last dock
+ if (dockWidgets.count() != 1)
+ return;
+
+ auto *lastDockWidget = dockWidgets.at(0);
+
+ // If the last remaining dock widget is not in the group window's item_list,
+ // a group window is being docked on a main window docking area.
+ // => don't interfere
+ if (layoutInfo()->indexOf(lastDockWidget).isEmpty())
+ return;
+
+ auto *mainWindow = qobject_cast<QMainWindow *>(parentWidget());
+ QMainWindowLayout *mwLayout = qt_mainwindow_layout(mainWindow);
+
+ // Unplug the last remaining dock widget and hide the group window, to avoid flickering
+ mwLayout->unplug(lastDockWidget, QDockWidgetPrivate::DragScope::Widget);
+ lastDockWidget->setGeometry(geometry());
+ hide();
+
+ // Get the layout info for the main window dock, where dock widgets need to go
+ QDockAreaLayoutInfo &parentInfo = mwLayout->layoutState.dockAreaLayout.docks[layoutInfo()->dockPos];
+
+ // Re-parent last dock widget
+ reparent(lastDockWidget);
+
+ // the group window could still have placeholder items => clear everything
+ layoutInfo()->item_list.clear();
+
+ // remove the group window and the dock's item_list pointing to it.
+ parentInfo.remove(this);
+ destroyOrHideIfEmpty();
+}
+
+void QDockWidgetGroupWindow::reparent(QDockWidget *dockWidget)
+{
+ // reparent a dockWidget to the main window
+ // - remove it from the floating dock's layout info
+ // - insert it to the main dock's layout info
+ // Finally, set draggingDock to nullptr, since the drag is finished.
+ auto *mainWindow = qobject_cast<QMainWindow *>(parentWidget());
+ Q_ASSERT(mainWindow);
+ QMainWindowLayout *mwLayout = qt_mainwindow_layout(mainWindow);
+ Q_ASSERT(mwLayout);
+ QDockAreaLayoutInfo &parentInfo = mwLayout->layoutState.dockAreaLayout.docks[layoutInfo()->dockPos];
+ dockWidget->removeEventFilter(this);
+ parentInfo.add(dockWidget);
+ layoutInfo()->remove(dockWidget);
+ const bool wasFloating = dockWidget->isFloating();
+ const bool wasVisible = dockWidget->isVisible();
+ dockWidget->setParent(mainWindow);
+ dockWidget->setFloating(wasFloating);
+ dockWidget->setVisible(wasVisible);
+}
#endif
/******************************************************************************
@@ -1195,7 +1361,7 @@ bool QMainWindowLayoutState::restoreState(QDataStream &_stream,
if (info == nullptr) {
continue;
}
- info->item_list.append(QDockAreaLayoutItem(new QDockWidgetItem(w)));
+ info->add(w);
}
}
}
@@ -1265,17 +1431,18 @@ bool QMainWindowLayoutState::restoreState(QDataStream &_stream,
#if QT_CONFIG(toolbar)
-static inline void validateToolBarArea(Qt::ToolBarArea &area)
+static constexpr Qt::ToolBarArea validateToolBarArea(Qt::ToolBarArea area)
{
switch (area) {
case Qt::LeftToolBarArea:
case Qt::RightToolBarArea:
case Qt::TopToolBarArea:
case Qt::BottomToolBarArea:
- break;
+ return area;
default:
- area = Qt::TopToolBarArea;
+ break;
}
+ return Qt::TopToolBarArea;
}
static QInternal::DockPosition toDockPos(Qt::ToolBarArea area)
@@ -1311,7 +1478,7 @@ static inline Qt::ToolBarArea toToolBarArea(int pos)
void QMainWindowLayout::addToolBarBreak(Qt::ToolBarArea area)
{
- validateToolBarArea(area);
+ area = validateToolBarArea(area);
layoutState.toolBarAreaLayout.addToolBarBreak(toDockPos(area));
if (savedState.isValid())
@@ -1365,7 +1532,7 @@ void QMainWindowLayout::addToolBar(Qt::ToolBarArea area,
QToolBar *toolbar,
bool)
{
- validateToolBarArea(area);
+ area = validateToolBarArea(area);
// let's add the toolbar to the layout
addChildWidget(toolbar);
QLayoutItem *item = layoutState.toolBarAreaLayout.addToolBar(toDockPos(area), toolbar);
@@ -1467,7 +1634,6 @@ inline static Qt::DockWidgetArea toDockWidgetArea(int pos)
// Checks if QDockWidgetGroupWindow or QDockWidget can be plugged the area indicated by path.
// Returns false if called with invalid widget type or if compiled without dockwidget support.
-#if QT_CONFIG(dockwidget)
static bool isAreaAllowed(QWidget *widget, const QList<int> &path)
{
Q_ASSERT_X((path.size() > 1), "isAreaAllowed", "invalid path size");
@@ -1502,7 +1668,6 @@ static bool isAreaAllowed(QWidget *widget, const QList<int> &path)
qCDebug(lcQpaDockWidgets) << "Docking requested for invalid widget type (coding error)." << widget << area;
return false;
}
-#endif
void QMainWindowLayout::setCorner(Qt::Corner corner, Qt::DockWidgetArea area)
{
@@ -1522,7 +1687,6 @@ Qt::DockWidgetArea QMainWindowLayout::corner(Qt::Corner corner) const
// Returns the rectangle of a dockWidgetArea
// if max is true, the maximum possible rectangle for dropping is returned
// the current visible rectangle otherwise
-#if QT_CONFIG(dockwidget)
QRect QMainWindowLayout::dockWidgetAreaRect(const Qt::DockWidgetArea area, DockWidgetAreaSize size) const
{
const QInternal::DockPosition dockPosition = toDockPos(area);
@@ -1538,7 +1702,6 @@ QRect QMainWindowLayout::dockWidgetAreaRect(const Qt::DockWidgetArea area, DockW
// Return maximum or visible rectangle
return (size == Maximum) ? dl.gapRect(dockPosition) : dl.docks[dockPosition].rect;
}
-#endif
void QMainWindowLayout::addDockWidget(Qt::DockWidgetArea area,
QDockWidget *dockwidget,
@@ -1569,6 +1732,7 @@ bool QMainWindowLayout::restoreDockWidget(QDockWidget *dockwidget)
#if QT_CONFIG(tabbar)
void QMainWindowLayout::tabifyDockWidget(QDockWidget *first, QDockWidget *second)
{
+ applyRestoredState();
addChildWidget(second);
layoutState.dockAreaLayout.tabifyDockWidget(first, second);
emit second->dockLocationChanged(dockWidgetArea(first));
@@ -1690,6 +1854,7 @@ void QMainWindowLayout::splitDockWidget(QDockWidget *after,
QDockWidget *dockwidget,
Qt::Orientation orientation)
{
+ applyRestoredState();
addChildWidget(dockwidget);
layoutState.dockAreaLayout.splitDockWidget(after, dockwidget, orientation);
emit dockwidget->dockLocationChanged(dockWidgetArea(after));
@@ -1714,10 +1879,15 @@ void QMainWindowLayout::keepSize(QDockWidget *w)
// Handle custom tooltip, and allow to drag tabs away.
class QMainWindowTabBar : public QTabBar
{
+ Q_OBJECT
QMainWindow *mainWindow;
QPointer<QDockWidget> draggingDock; // Currently dragging (detached) dock widget
public:
QMainWindowTabBar(QMainWindow *parent);
+ ~QMainWindowTabBar();
+ QDockWidget *dockAt(int index) const;
+ QList<QDockWidget *> dockWidgets() const;
+ bool contains(const QDockWidget *dockWidget) const;
protected:
bool event(QEvent *e) override;
void mouseReleaseEvent(QMouseEvent*) override;
@@ -1725,12 +1895,65 @@ protected:
};
+QMainWindowTabBar *QMainWindowLayout::findTabBar(const QDockWidget *dockWidget) const
+{
+ for (auto *bar : usedTabBars) {
+ Q_ASSERT(qobject_cast<QMainWindowTabBar *>(bar));
+ auto *tabBar = static_cast<QMainWindowTabBar *>(bar);
+ if (tabBar->contains(dockWidget))
+ return tabBar;
+ }
+ return nullptr;
+}
+
QMainWindowTabBar::QMainWindowTabBar(QMainWindow *parent)
: QTabBar(parent), mainWindow(parent)
{
setExpanding(false);
}
+QList<QDockWidget *> QMainWindowTabBar::dockWidgets() const
+{
+ QList<QDockWidget *> docks;
+ for (int i = 0; i < count(); ++i) {
+ if (QDockWidget *dock = dockAt(i))
+ docks << dock;
+ }
+ return docks;
+}
+
+bool QMainWindowTabBar::contains(const QDockWidget *dockWidget) const
+{
+ for (int i = 0; i < count(); ++i) {
+ if (dockAt(i) == dockWidget)
+ return true;
+ }
+ return false;
+}
+
+// When a dock widget is removed from a floating tab,
+// Events need to be processed for the tab bar to realize that the dock widget is gone.
+// In this case count() counts the dock widget in transition and accesses dockAt
+// with an out-of-bounds index.
+// => return nullptr in contrast to other xxxxxAt() functions
+QDockWidget *QMainWindowTabBar::dockAt(int index) const
+{
+ QMainWindowTabBar *that = const_cast<QMainWindowTabBar *>(this);
+ QMainWindowLayout* mlayout = qt_mainwindow_layout(mainWindow);
+ QDockAreaLayoutInfo *info = mlayout->dockInfo(that);
+ if (!info)
+ return nullptr;
+
+ const int itemIndex = info->tabIndexToListIndex(index);
+ if (itemIndex >= 0) {
+ Q_ASSERT(itemIndex < info->item_list.count());
+ const QDockAreaLayoutItem &item = info->item_list.at(itemIndex);
+ return item.widgetItem ? qobject_cast<QDockWidget *>(item.widgetItem->widget()) : nullptr;
+ }
+
+ return nullptr;
+}
+
void QMainWindowTabBar::mouseMoveEvent(QMouseEvent *e)
{
// The QTabBar handles the moving (reordering) of tabs.
@@ -1744,13 +1967,8 @@ void QMainWindowTabBar::mouseMoveEvent(QMouseEvent *e)
offset *= 3;
QRect r = rect().adjusted(-offset, -offset, offset, offset);
if (d->dragInProgress && !r.contains(e->position().toPoint()) && d->validIndex(d->pressedIndex)) {
- QMainWindowLayout* mlayout = qt_mainwindow_layout(mainWindow);
- QDockAreaLayoutInfo *info = mlayout->dockInfo(this);
- Q_ASSERT(info);
- int idx = info->tabIndexToListIndex(d->pressedIndex);
- const QDockAreaLayoutItem &item = info->item_list.at(idx);
- if (item.widgetItem
- && (draggingDock = qobject_cast<QDockWidget *>(item.widgetItem->widget()))) {
+ draggingDock = dockAt(d->pressedIndex);
+ if (draggingDock) {
// We should drag this QDockWidget away by unpluging it.
// First cancel the QTabBar's internal move
d->moveTabFinished(d->pressedIndex);
@@ -1763,7 +1981,7 @@ void QMainWindowTabBar::mouseMoveEvent(QMouseEvent *e)
QDockWidgetPrivate *dockPriv = static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
QDockWidgetLayout *dwlayout = static_cast<QDockWidgetLayout *>(draggingDock->layout());
dockPriv->initDrag(dwlayout->titleArea().center(), true);
- dockPriv->startDrag(false);
+ dockPriv->startDrag(QDockWidgetPrivate::DragScope::Widget);
if (dockPriv->state)
dockPriv->state->ctrlDrag = e->modifiers() & Qt::ControlModifier;
}
@@ -1781,13 +1999,28 @@ void QMainWindowTabBar::mouseMoveEvent(QMouseEvent *e)
QTabBar::mouseMoveEvent(e);
}
+QMainWindowTabBar::~QMainWindowTabBar()
+{
+ if (!mainWindow || mainWindow == parentWidget())
+ return;
+
+ // tab bar is not parented to the main window
+ // => can only be a dock widget group window
+ // => remove itself from used and unused tab bar containers
+ auto *mwLayout = qt_mainwindow_layout(mainWindow);
+ if (!mwLayout)
+ return;
+ mwLayout->unusedTabBars.removeOne(this);
+ mwLayout->usedTabBars.remove(this);
+}
+
void QMainWindowTabBar::mouseReleaseEvent(QMouseEvent *e)
{
if (draggingDock && e->button() == Qt::LeftButton) {
QDockWidgetPrivate *dockPriv = static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
- if (dockPriv->state && dockPriv->state->dragging) {
- dockPriv->endDrag();
- }
+ if (dockPriv->state && dockPriv->state->dragging)
+ dockPriv->endDrag(QDockWidgetPrivate::EndDragMode::LocationChange);
+
draggingDock = nullptr;
}
QTabBar::mouseReleaseEvent(e);
@@ -1811,9 +2044,31 @@ bool QMainWindowTabBar::event(QEvent *e)
return true;
}
+QList<QDockWidget *> QMainWindowLayout::tabifiedDockWidgets(const QDockWidget *dockWidget) const
+{
+ const auto *bar = findTabBar(dockWidget);
+ if (!bar)
+ return {};
+
+ QList<QDockWidget *> buddies = bar->dockWidgets();
+ // Return only other dock widgets associated with dockWidget in a tab bar.
+ // If dockWidget is alone in a tab bar, return an empty list.
+ buddies.removeOne(dockWidget);
+ return buddies;
+}
+
+bool QMainWindowLayout::isDockWidgetTabbed(const QDockWidget *dockWidget) const
+{
+ // A single dock widget in a tab bar is not considered to be tabbed.
+ // This is to make sure, we don't drag an empty QDockWidgetGroupWindow around.
+ // => only consider tab bars with two or more tabs.
+ const auto *bar = findTabBar(dockWidget);
+ return bar && bar->count() > 1;
+}
+
QTabBar *QMainWindowLayout::getTabBar()
{
- if (!usedTabBars.isEmpty()) {
+ if (!usedTabBars.isEmpty() && !isInRestoreState) {
/*
If dock widgets have been removed and added while the main window was
hidden, then the layout hasn't been activated yet, and tab bars from empty
@@ -1985,9 +2240,37 @@ QLayoutItem *QMainWindowLayout::takeAt(int index)
return nullptr;
}
+
+/*!
+ \internal
+
+ restoredState stores what we earlier read from storage, but it couldn't
+ be applied as the mainwindow wasn't large enough (yet) to fit the state.
+ Usually, the restored state would be applied lazily in setGeometry below.
+ However, if the mainwindow's layout is modified (e.g. by a call to tabify or
+ splitDockWidgets), then we have to forget the restored state as it might contain
+ dangling pointers (QDockWidgetLayoutItem has a copy constructor that copies the
+ layout item pointer, and splitting or tabify might have to delete some of those
+ layout structures).
+
+ Functions that might result in the QMainWindowLayoutState storing dangling pointers
+ have to call this function first, so that the restoredState becomes the actual state
+ first, and is forgotten afterwards.
+*/
+void QMainWindowLayout::applyRestoredState()
+{
+ if (restoredState) {
+ layoutState = *restoredState;
+ restoredState.reset();
+ discardRestoredStateTimer.stop();
+ }
+}
+
void QMainWindowLayout::setGeometry(const QRect &_r)
{
- if (savedState.isValid())
+ // Check if the state is valid, and avoid replacing it again if it is currently used
+ // in applyState
+ if (savedState.isValid() || (restoredState && isInApplyState))
return;
QRect r = _r;
@@ -2523,25 +2806,25 @@ static QTabBar::Shape tabwidgetPositionToTabBarShape(QWidget *w)
Returns the QLayoutItem of the dragged element.
The layout item is kept in the layout but set as a gap item.
*/
-QLayoutItem *QMainWindowLayout::unplug(QWidget *widget, bool group)
+QLayoutItem *QMainWindowLayout::unplug(QWidget *widget, QDockWidgetPrivate::DragScope scope)
{
#if QT_CONFIG(dockwidget) && QT_CONFIG(tabwidget)
auto *groupWindow = qobject_cast<const QDockWidgetGroupWindow *>(widget->parentWidget());
if (!widget->isWindow() && groupWindow) {
- if (group && groupWindow->tabLayoutInfo()) {
+ if (scope == QDockWidgetPrivate::DragScope::Group && groupWindow->tabLayoutInfo()) {
// We are just dragging a floating window as it, not need to do anything, we just have to
// look up the corresponding QWidgetItem* if it exists
if (QDockAreaLayoutInfo *info = dockInfo(widget->parentWidget())) {
QList<int> groupWindowPath = info->indexOf(widget->parentWidget());
return groupWindowPath.isEmpty() ? nullptr : info->item(groupWindowPath).widgetItem;
}
- qCDebug(lcQpaDockWidgets) << "Drag only:" << widget << "Group:" << group;
+ qCDebug(lcQpaDockWidgets) << "Drag only:" << widget << "Group:" << (scope == QDockWidgetPrivate::DragScope::Group);
return nullptr;
}
QList<int> path = groupWindow->layoutInfo()->indexOf(widget);
QDockAreaLayoutItem parentItem = groupWindow->layoutInfo()->item(path);
QLayoutItem *item = parentItem.widgetItem;
- if (group && path.size() > 1
+ if (scope == QDockWidgetPrivate::DragScope::Group && path.size() > 1
&& unplugGroup(this, &item, parentItem)) {
qCDebug(lcQpaDockWidgets) << "Unplugging:" << widget << "from" << item;
return item;
@@ -2549,73 +2832,10 @@ QLayoutItem *QMainWindowLayout::unplug(QWidget *widget, bool group)
// We are unplugging a single dock widget from a floating window.
QDockWidget *dockWidget = qobject_cast<QDockWidget *>(widget);
Q_ASSERT(dockWidget); // cannot be a QDockWidgetGroupWindow because it's not floating.
-
- // unplug the widget first
dockWidget->d_func()->unplug(widget->geometry());
- // Create a floating tab, copy properties and generate layout info
- QDockWidgetGroupWindow *floatingTabs = createTabbedDockWindow();
- const QInternal::DockPosition dockPos = groupWindow->layoutInfo()->dockPos;
- QDockAreaLayoutInfo *info = floatingTabs->layoutInfo();
-
- const QTabBar::Shape shape = tabwidgetPositionToTabBarShape(dockWidget);
-
- // Populate newly created DockAreaLayoutInfo of floating tabs
- *info = QDockAreaLayoutInfo(&layoutState.dockAreaLayout.sep, dockPos,
- Qt::Horizontal, shape,
- layoutState.mainWindow);
-
- // Create tab and hide it as group window contains only one widget
- info->tabbed = true;
- info->tabBar = getTabBar();
- info->tabBar->hide();
- updateGapIndicator();
-
- // Reparent it to a QDockWidgetGroupLayout
- floatingTabs->setGeometry(dockWidget->geometry());
-
- // Append reference to floatingTabs to the dock's item_list
- parentItem.widgetItem = new QDockWidgetGroupWindowItem(floatingTabs);
- layoutState.dockAreaLayout.docks[dockPos].item_list.append(parentItem);
-
- // use populated parentItem to set reference to dockWidget as the first item in own list
- parentItem.widgetItem = new QDockWidgetItem(dockWidget);
- info->item_list = {parentItem};
-
- // Add non-gap items of the dock to the tab bar
- for (const auto &listItem : layoutState.dockAreaLayout.docks[dockPos].item_list) {
- if (listItem.GapItem || !listItem.widgetItem)
- continue;
- info->tabBar->addTab(listItem.widgetItem->widget()->objectName());
- }
-
- // Re-parent and fit
- floatingTabs->setParent(layoutState.mainWindow);
- floatingTabs->layoutInfo()->fitItems();
- floatingTabs->layoutInfo()->apply(dockOptions & QMainWindow::AnimatedDocks);
- groupWindow->layoutInfo()->fitItems();
- groupWindow->layoutInfo()->apply(dockOptions & QMainWindow::AnimatedDocks);
- dockWidget->d_func()->tabPosition = layoutState.mainWindow->tabPosition(toDockWidgetArea(dockPos));
- info->reparentWidgets(floatingTabs);
- dockWidget->setParent(floatingTabs);
- info->updateTabBar();
-
- // Show the new item
- const QList<int> path = layoutState.indexOf(floatingTabs);
- QRect r = layoutState.itemRect(path);
- savedState = layoutState;
- savedState.fitLayout();
-
- // Update gap, fix orientation, raise and show
- currentGapPos = path;
- currentGapRect = r;
- updateGapIndicator();
- fixToolBarOrientation(parentItem.widgetItem, currentGapPos.at(1));
- floatingTabs->show();
- floatingTabs->raise();
-
qCDebug(lcQpaDockWidgets) << "Unplugged from floating dock:" << widget << "from" << parentItem.widgetItem;
- return parentItem.widgetItem;
+ return item;
}
}
#endif
@@ -2634,7 +2854,7 @@ QLayoutItem *QMainWindowLayout::unplug(QWidget *widget, bool group)
if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) {
Q_ASSERT(path.constFirst() == 1);
#if QT_CONFIG(tabwidget)
- if (group && (dockOptions & QMainWindow::GroupedDragging) && path.size() > 3
+ if (scope == QDockWidgetPrivate::DragScope::Group && (dockOptions & QMainWindow::GroupedDragging) && path.size() > 3
&& unplugGroup(this, &item,
layoutState.dockAreaLayout.item(path.mid(1, path.size() - 2)))) {
path.removeLast();
@@ -2665,7 +2885,7 @@ QLayoutItem *QMainWindowLayout::unplug(QWidget *widget, bool group)
const auto *layout = qobject_cast<QDockWidgetLayout *>(dw->layout());
const bool verticalTitleBar = layout ? layout->verticalTitleBar : false;
const int tbHeight = QApplication::style()
- ? QApplication::style()->pixelMetric(QStyle::PixelMetric::PM_TitleBarHeight)
+ ? QApplication::style()->pixelMetric(QStyle::PixelMetric::PM_TitleBarHeight, nullptr, dw)
: 20;
const int minHeight = verticalTitleBar ? 2 * tbHeight : tbHeight;
const int minWidth = verticalTitleBar ? tbHeight : 2 * tbHeight;
@@ -2683,7 +2903,7 @@ QLayoutItem *QMainWindowLayout::unplug(QWidget *widget, bool group)
#endif
#if !QT_CONFIG(dockwidget) || !QT_CONFIG(tabbar)
- Q_UNUSED(group);
+ Q_UNUSED(scope);
#endif
layoutState.unplug(path ,&savedState);
@@ -2751,6 +2971,7 @@ void QMainWindowLayout::hover(QLayoutItem *hoverTarget,
QWidget *widget = hoverTarget->widget();
#if QT_CONFIG(dockwidget)
+ widget->raise();
if ((dockOptions & QMainWindow::GroupedDragging) && (qobject_cast<QDockWidget*>(widget)
|| qobject_cast<QDockWidgetGroupWindow *>(widget))) {
@@ -2767,7 +2988,7 @@ void QMainWindowLayout::hover(QLayoutItem *hoverTarget,
continue;
// Check permission to dock on another dock widget or floating dock
- // FIXME in 6.4
+ // FIXME in Qt 7
if (w != widget && w->isWindow() && w->isVisible() && !w->isMinimized())
candidates << w;
@@ -2805,16 +3026,26 @@ void QMainWindowLayout::hover(QLayoutItem *hoverTarget,
floatingTabs->setGeometry(dropTo->geometry());
QDockAreaLayoutInfo *info = floatingTabs->layoutInfo();
const QTabBar::Shape shape = tabwidgetPositionToTabBarShape(dropTo);
- const QInternal::DockPosition dockPosition = toDockPos(dockWidgetArea(dropTo));
+
+ // dropTo and widget may be in a state where they transition
+ // from being a group window child to a single floating dock widget.
+ // In that case, their path to a main window dock may not have been
+ // updated yet.
+ // => ask both and fall back to dock 1 (right dock)
+ QInternal::DockPosition dockPosition = toDockPos(dockWidgetArea(dropTo));
+ if (dockPosition == QInternal::DockPosition::DockCount)
+ dockPosition = toDockPos(dockWidgetArea(widget));
+ if (dockPosition == QInternal::DockPosition::DockCount)
+ dockPosition = QInternal::DockPosition::RightDock;
+
*info = QDockAreaLayoutInfo(&layoutState.dockAreaLayout.sep, dockPosition,
Qt::Horizontal, shape,
static_cast<QMainWindow *>(parentWidget()));
info->tabBar = getTabBar();
info->tabbed = true;
- QLayout *parentLayout = dropTo->parentWidget()->layout();
- info->item_list.append(
- QDockAreaLayoutItem(parentLayout->takeAt(parentLayout->indexOf(dropTo))));
-
+ info->add(dropTo);
+ QDockAreaLayoutInfo &parentInfo = layoutState.dockAreaLayout.docks[dockPosition];
+ parentInfo.add(floatingTabs);
dropTo->setParent(floatingTabs);
qCDebug(lcQpaDockWidgets) << "Wrapping" << widget << "into floating tabs" << floatingTabs;
w = floatingTabs;
@@ -2827,15 +3058,21 @@ void QMainWindowLayout::hover(QLayoutItem *hoverTarget,
qCDebug(lcQpaDockWidgets) << "Raising" << widget;
}
#endif
- auto group = qobject_cast<QDockWidgetGroupWindow *>(w);
- Q_ASSERT(group);
- if (group->hover(hoverTarget, group->mapFromGlobal(mousePos))) {
- setCurrentHoveredFloat(group);
+ auto *groupWindow = qobject_cast<QDockWidgetGroupWindow *>(w);
+ Q_ASSERT(groupWindow);
+ if (groupWindow->hover(hoverTarget, groupWindow->mapFromGlobal(mousePos))) {
+ setCurrentHoveredFloat(groupWindow);
applyState(layoutState); // update the tabbars
}
return;
}
}
+
+ // If a temporary group window has been created during a hover,
+ // remove it, if it has only one dockwidget child
+ if (currentHoveredFloat)
+ currentHoveredFloat->destroyIfSingleItemLeft();
+
setCurrentHoveredFloat(nullptr);
layoutState.dockAreaLayout.fallbackToSizeHints = false;
#endif // QT_CONFIG(dockwidget)
@@ -2960,6 +3197,7 @@ void QMainWindowLayout::saveState(QDataStream &stream) const
bool QMainWindowLayout::restoreState(QDataStream &stream)
{
+ QScopedValueRollback<bool> guard(isInRestoreState, true);
savedState = layoutState;
layoutState.clear();
layoutState.rect = savedState.rect;
@@ -3005,6 +3243,42 @@ bool QMainWindowLayout::restoreState(QDataStream &stream)
return true;
}
+#if QT_CONFIG(draganddrop)
+bool QMainWindowLayout::needsPlatformDrag()
+{
+ static const bool wayland =
+ QGuiApplication::platformName().startsWith("wayland"_L1, Qt::CaseInsensitive);
+ return wayland;
+}
+
+Qt::DropAction QMainWindowLayout::performPlatformWidgetDrag(QLayoutItem *widgetItem,
+ const QPoint &pressPosition)
+{
+ draggingWidget = widgetItem;
+ QWidget *widget = widgetItem->widget();
+ auto drag = QDrag(widget);
+ auto mimeData = new QMimeData();
+ auto window = widgetItem->widget()->windowHandle();
+
+ auto serialize = [](const auto &object) {
+ QByteArray data;
+ QDataStream dataStream(&data, QIODevice::WriteOnly);
+ dataStream << object;
+ return data;
+ };
+ mimeData->setData("application/x-qt-mainwindowdrag-window"_L1,
+ serialize(reinterpret_cast<qintptr>(window)));
+ mimeData->setData("application/x-qt-mainwindowdrag-position"_L1, serialize(pressPosition));
+ drag.setMimeData(mimeData);
+
+ auto result = drag.exec();
+
+ draggingWidget = nullptr;
+ return result;
+}
+#endif
+
QT_END_NAMESPACE
+#include "qmainwindowlayout.moc"
#include "moc_qmainwindowlayout_p.cpp"
diff --git a/src/widgets/widgets/qmainwindowlayout_p.h b/src/widgets/widgets/qmainwindowlayout_p.h
index 394a052a09..55a27e4849 100644
--- a/src/widgets/widgets/qmainwindowlayout_p.h
+++ b/src/widgets/widgets/qmainwindowlayout_p.h
@@ -1,8 +1,8 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QDYNAMICMAINWINDOWLAYOUT_P_H
-#define QDYNAMICMAINWINDOWLAYOUT_P_H
+#ifndef QMAINWINDOWLAYOUT_P_H
+#define QMAINWINDOWLAYOUT_P_H
//
// W A R N I N G
@@ -29,15 +29,24 @@
#include "QtCore/qset.h"
#include "private/qlayoutengine_p.h"
#include "private/qwidgetanimator_p.h"
-
#if QT_CONFIG(dockwidget)
+#include "private/qdockwidget_p.h"
+
#include "qdockarealayout_p.h"
#include "qdockwidget.h"
+#else
+struct QDockWidgetPrivate {
+ enum class DragScope {
+ Group
+ };
+};
#endif
#if QT_CONFIG(toolbar)
#include "qtoolbararealayout_p.h"
#endif
+
#include <QtCore/qloggingcategory.h>
+#include <QtCore/qpointer.h>
QT_REQUIRE_CONFIG(mainwindow);
@@ -306,14 +315,17 @@ class Q_AUTOTEST_EXPORT QDockWidgetGroupWindow : public QWidget
{
Q_OBJECT
public:
- explicit QDockWidgetGroupWindow(QWidget* parent = nullptr, Qt::WindowFlags f = { })
- : QWidget(parent, f) {}
+ explicit QDockWidgetGroupWindow(QWidget *parent = nullptr, Qt::WindowFlags f = {})
+ : QWidget(parent, f)
+ {
+ }
QDockAreaLayoutInfo *layoutInfo() const;
#if QT_CONFIG(tabbar)
const QDockAreaLayoutInfo *tabLayoutInfo() const;
QDockWidget *activeTabbedDockWidget() const;
#endif
void destroyOrHideIfEmpty();
+ bool hasVisibleDockWidgets() const;
void adjustFlags();
bool hasNativeDecos() const;
@@ -321,6 +333,10 @@ public:
void updateCurrentGapRect();
void restore();
void apply();
+ void childEvent(QChildEvent *event) override;
+ void reparent(QDockWidget *dockWidget);
+ void destroyIfSingleItemLeft();
+ QList<QDockWidget *> dockWidgets() const { return findChildren<QDockWidget *>(); }
QRect currentGapRect;
QList<int> currentGapPos;
@@ -330,6 +346,7 @@ signals:
protected:
bool event(QEvent *) override;
+ bool eventFilter(QObject *obj, QEvent *event) override;
void paintEvent(QPaintEvent*) override;
private:
@@ -433,6 +450,7 @@ public:
bool restoreState(QDataStream &stream, const QMainWindowLayoutState &oldState);
};
+class QMainWindowTabBar;
class Q_AUTOTEST_EXPORT QMainWindowLayout
: public QLayout,
public QMainWindowLayoutSeparatorHelper<QMainWindowLayout>
@@ -560,17 +578,29 @@ public:
#if QT_CONFIG(dockwidget)
QPointer<QDockWidgetGroupWindow> currentHoveredFloat; // set when dragging over a floating dock widget
void setCurrentHoveredFloat(QDockWidgetGroupWindow *w);
+#if QT_CONFIG(tabbar)
+ bool isDockWidgetTabbed(const QDockWidget *dockWidget) const;
+ QList<QDockWidget *> tabifiedDockWidgets(const QDockWidget *dockWidget) const;
+ QMainWindowTabBar *findTabBar(const QDockWidget *dockWidget) const;
+#endif
#endif
bool isInApplyState = false;
void hover(QLayoutItem *hoverTarget, const QPoint &mousePos);
bool plug(QLayoutItem *widgetItem);
- QLayoutItem *unplug(QWidget *widget, bool group = false);
+ QLayoutItem *unplug(QWidget *widget, QDockWidgetPrivate::DragScope scope);
void revert(QLayoutItem *widgetItem);
void applyState(QMainWindowLayoutState &newState, bool animate = true);
+ void applyRestoredState();
void restore(bool keepSavedState = false);
void animationFinished(QWidget *widget);
+#if QT_CONFIG(draganddrop)
+ static bool needsPlatformDrag();
+ Qt::DropAction performPlatformWidgetDrag(QLayoutItem *widgetItem, const QPoint &pressPosition);
+ QLayoutItem *draggingWidget = nullptr;
+#endif
+
protected:
void timerEvent(QTimerEvent *e) override;
@@ -586,6 +616,7 @@ private:
#if QT_CONFIG(tabbar)
void updateTabBarShapes();
#endif
+ bool isInRestoreState = false;
};
#if QT_CONFIG(dockwidget) && !defined(QT_NO_DEBUG_STREAM)
@@ -596,4 +627,4 @@ QDebug operator<<(QDebug debug, const QMainWindowLayout *layout);
QT_END_NAMESPACE
-#endif // QDYNAMICMAINWINDOWLAYOUT_P_H
+#endif // QMAINWINDOWLAYOUT_P_H
diff --git a/src/widgets/widgets/qmdiarea.cpp b/src/widgets/widgets/qmdiarea.cpp
index 3b4505688b..79b83453ac 100644
--- a/src/widgets/widgets/qmdiarea.cpp
+++ b/src/widgets/widgets/qmdiarea.cpp
@@ -671,7 +671,11 @@ void QMdiAreaPrivate::_q_deactivateAllWindows(QMdiSubWindow *aboutToActivate)
aboutToBecomeActive = aboutToActivate;
Q_ASSERT(aboutToBecomeActive);
- foreach (QMdiSubWindow *child, childWindows) {
+ // Take a copy because child->showNormal() could indirectly call
+ // QCoreApplication::sendEvent(), which could call unknown code that e.g.
+ // recurses into the class modifying childWindows.
+ const auto subWindows = childWindows;
+ for (QMdiSubWindow *child : subWindows) {
if (!sanityCheck(child, "QMdiArea::deactivateAllWindows") || aboutToBecomeActive == child)
continue;
// We don't want to handle signals caused by child->showNormal().
@@ -846,7 +850,7 @@ void QMdiAreaPrivate::place(Placer *placer, QMdiSubWindow *child)
QList<QRect> rects;
rects.reserve(childWindows.size());
QRect parentRect = q->rect();
- foreach (QMdiSubWindow *window, childWindows) {
+ for (QMdiSubWindow *window : std::as_const(childWindows)) {
if (!sanityCheck(window, "QMdiArea::place") || window == child || !window->isVisibleTo(q)
|| !window->testAttribute(Qt::WA_Moved)) {
continue;
@@ -888,7 +892,7 @@ void QMdiAreaPrivate::rearrange(Rearranger *rearranger)
const bool reverseList = rearranger->type() == Rearranger::RegularTiler;
const QList<QMdiSubWindow *> subWindows = subWindowList(activationOrder, reverseList);
QSize minSubWindowSize;
- foreach (QMdiSubWindow *child, subWindows) {
+ for (QMdiSubWindow *child : subWindows) {
if (!sanityCheck(child, "QMdiArea::rearrange") || !child->isVisible())
continue;
if (rearranger->type() == Rearranger::IconTiler) {
@@ -1302,7 +1306,7 @@ bool QMdiAreaPrivate::lastWindowAboutToBeDestroyed() const
*/
void QMdiAreaPrivate::setChildActivationEnabled(bool enable, bool onlyNextActivationEvent) const
{
- foreach (QMdiSubWindow *subWindow, childWindows) {
+ for (QMdiSubWindow *subWindow : childWindows) {
if (!subWindow || !subWindow->isVisible())
continue;
if (onlyNextActivationEvent)
@@ -1324,7 +1328,11 @@ void QMdiAreaPrivate::scrollBarPolicyChanged(Qt::Orientation orientation, Qt::Sc
const QMdiSubWindow::SubWindowOption option = orientation == Qt::Horizontal ?
QMdiSubWindow::AllowOutsideAreaHorizontally : QMdiSubWindow::AllowOutsideAreaVertically;
const bool enable = policy != Qt::ScrollBarAlwaysOff;
- foreach (QMdiSubWindow *child, childWindows) {
+ // Take a copy because child->setOption() may indirectly call QCoreApplication::sendEvent(),
+ // the latter could call unknown code that could e.g. recurse into the class
+ // modifying childWindows.
+ const auto subWindows = childWindows;
+ for (QMdiSubWindow *child : subWindows) {
if (!sanityCheck(child, "QMdiArea::scrollBarPolicyChanged"))
continue;
child->setOption(option, enable);
@@ -1340,7 +1348,7 @@ QMdiAreaPrivate::subWindowList(QMdiArea::WindowOrder order, bool reversed) const
return list;
if (order == QMdiArea::CreationOrder) {
- foreach (QMdiSubWindow *child, childWindows) {
+ for (QMdiSubWindow *child : childWindows) {
if (!child)
continue;
if (!reversed)
@@ -1526,7 +1534,12 @@ void QMdiAreaPrivate::setViewMode(QMdiArea::ViewMode mode)
isSubWindowsTiled = false;
- foreach (QMdiSubWindow *subWindow, childWindows)
+ // Take a copy as tabBar->addTab() will (indirectly) create a connection between
+ // the tab close button clicked() signal and the _q_closeTab() slot, which may
+ // indirectly call QCoreApplication::sendEvent(), the latter could result in
+ // invoking unknown code that could e.g. recurse into the class modifying childWindows.
+ const auto subWindows = childWindows;
+ for (QMdiSubWindow *subWindow : subWindows)
tabBar->addTab(subWindow->windowIcon(), tabTextFor(subWindow));
QMdiSubWindow *current = q->currentSubWindow();
@@ -1848,7 +1861,11 @@ void QMdiArea::closeAllSubWindows()
return;
d->isSubWindowsTiled = false;
- foreach (QMdiSubWindow *child, d->childWindows) {
+ // Take a copy because the child->close() call below may end up indirectly calling
+ // QCoreApplication::send{Spontaneous}Event(), which may call unknown code that
+ // could e.g. recurse into the class modifying d->childWindows.
+ const auto subWindows = d->childWindows;
+ for (QMdiSubWindow *child : subWindows) {
if (!sanityCheck(child, "QMdiArea::closeAllSubWindows"))
continue;
child->close();
@@ -1987,7 +2004,11 @@ void QMdiArea::removeSubWindow(QWidget *widget)
}
bool found = false;
- foreach (QMdiSubWindow *child, d->childWindows) {
+ // Take a copy because child->setWidget(nullptr) will indirectly
+ // QCoreApplication::sendEvent(); the latter could call unknown code that could
+ // e.g. recurse into the class modifying d->childWindows.
+ const auto subWindows = d->childWindows;
+ for (QMdiSubWindow *child : subWindows) {
if (!sanityCheck(child, "QMdiArea::removeSubWindow"))
continue;
if (child->widget() == widget) {
@@ -2268,7 +2289,11 @@ void QMdiArea::resizeEvent(QResizeEvent *resizeEvent)
// Resize maximized views.
bool hasMaximizedSubWindow = false;
- foreach (QMdiSubWindow *child, d->childWindows) {
+ // Take a copy because child->resize() may call QCoreApplication::sendEvent()
+ // which may invoke unknown code, that could e.g. recurse into the class
+ // modifying d->childWindows.
+ const auto subWindows = d->childWindows;
+ for (QMdiSubWindow *child : subWindows) {
if (sanityCheck(child, "QMdiArea::resizeEvent") && child->isMaximized()
&& child->size() != resizeEvent->size()) {
auto realSize = resizeEvent->size();
@@ -2327,7 +2352,9 @@ void QMdiArea::showEvent(QShowEvent *showEvent)
Q_D(QMdiArea);
if (!d->pendingRearrangements.isEmpty()) {
bool skipPlacement = false;
- foreach (Rearranger *rearranger, d->pendingRearrangements) {
+ // Take a copy because d->rearrange() may modify d->pendingRearrangements
+ const auto pendingRearrange = d->pendingRearrangements;
+ for (Rearranger *rearranger : pendingRearrange) {
// If this is the case, we don't have to lay out pending child windows
// since the rearranger will find a placement for them.
if (rearranger->type() != Rearranger::IconTiler && !skipPlacement)
@@ -2341,9 +2368,19 @@ void QMdiArea::showEvent(QShowEvent *showEvent)
}
if (!d->pendingPlacements.isEmpty()) {
- foreach (QMdiSubWindow *window, d->pendingPlacements) {
+ // Nothing obvious in the loop body changes the container (in this code path)
+ // during iteration, this is calling into a non-const method that does change
+ // the container when called from other places. So take a copy anyway for good
+ // measure.
+ const auto copy = d->pendingPlacements;
+ for (QMdiSubWindow *window : copy) {
if (!window)
continue;
+ if (d->viewMode == TabbedView && window->d_func()->isActive && !d->active) {
+ d->showActiveWindowMaximized = true;
+ d->emitWindowActivated(window); // Also maximizes the window
+ continue;
+ }
if (!window->testAttribute(Qt::WA_Resized)) {
QSize newSize(window->sizeHint().boundedTo(viewport()->size()));
window->resize(newSize.expandedTo(qSmartMinSize(window)));
@@ -2477,12 +2514,16 @@ bool QMdiArea::event(QEvent *event)
d->isSubWindowsTiled = true;
}
break;
- case QEvent::WindowIconChange:
- foreach (QMdiSubWindow *window, d->childWindows) {
+ case QEvent::WindowIconChange: {
+ // Take a copy because QCoreApplication::sendEvent() may call unknown code,
+ // that may cause recursing into the class
+ const auto subWindows = d->childWindows;
+ for (QMdiSubWindow *window : subWindows) {
if (sanityCheck(window, "QMdiArea::WindowIconChange"))
QCoreApplication::sendEvent(window, event);
}
break;
+ }
case QEvent::Hide:
d->setActive(d->active, false, false);
d->setChildActivationEnabled(false);
@@ -2637,7 +2678,10 @@ void QMdiArea::setupViewport(QWidget *viewport)
Q_D(QMdiArea);
if (viewport)
viewport->setAttribute(Qt::WA_OpaquePaintEvent, d->background.isOpaque());
- foreach (QMdiSubWindow *child, d->childWindows) {
+ // Take a copy because the child->setParent() call below may call QCoreApplication::sendEvent()
+ // which may call unknown code that could e.g. recurse into the class modifying d->childWindows.
+ const auto subWindows = d->childWindows;
+ for (QMdiSubWindow *child : subWindows) {
if (!sanityCheck(child, "QMdiArea::setupViewport"))
continue;
child->setParent(viewport, child->windowFlags());
diff --git a/src/widgets/widgets/qmdiarea_p.h b/src/widgets/widgets/qmdiarea_p.h
index 2e66a31fbc..e57b9772ca 100644
--- a/src/widgets/widgets/qmdiarea_p.h
+++ b/src/widgets/widgets/qmdiarea_p.h
@@ -29,6 +29,8 @@ QT_REQUIRE_CONFIG(mdiarea);
#include <private/qmdisubwindow_p.h>
#include <private/qabstractscrollarea_p.h>
+#include <QtCore/qpointer.h>
+
QT_BEGIN_NAMESPACE
namespace QMdi {
diff --git a/src/widgets/widgets/qmdisubwindow.h b/src/widgets/widgets/qmdisubwindow.h
index a34c0249ec..4227f02dac 100644
--- a/src/widgets/widgets/qmdisubwindow.h
+++ b/src/widgets/widgets/qmdisubwindow.h
@@ -101,6 +101,7 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_enterInteractiveMode())
Q_PRIVATE_SLOT(d_func(), void _q_processFocusChanged(QWidget *, QWidget *))
friend class QMdiAreaPrivate;
+ friend class QMdiArea;
#if QT_CONFIG(tabbar)
friend class QMdiAreaTabBar;
#endif
diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp
index 987dce71d9..db00f8a650 100644
--- a/src/widgets/widgets/qmenu.cpp
+++ b/src/widgets/widgets/qmenu.cpp
@@ -93,7 +93,9 @@ public:
Q_D(QTornOffMenu);
// make the torn-off menu a sibling of p (instead of a child)
QWidget *parentWidget = d->causedStack.isEmpty() ? p : d->causedStack.constLast();
- if (parentWidget->parentWidget())
+ if (!parentWidget && p)
+ parentWidget = p;
+ if (parentWidget && parentWidget->parentWidget())
parentWidget = parentWidget->parentWidget();
setParent(parentWidget, Qt::Window | Qt::Tool);
setAttribute(Qt::WA_DeleteOnClose, true);
@@ -163,7 +165,7 @@ void QMenuPrivate::init()
defaultMenuAction = menuAction = new QAction(q);
menuAction->setMenu(q); // this calls setOverrideMenuAction
setOverrideMenuAction(nullptr);
- QObject::connect(menuAction, &QAction::changed, [this] {
+ QObject::connect(menuAction, &QAction::changed, q, [this] {
if (!tornPopup.isNull())
tornPopup->updateWindowTitle();
});
@@ -290,6 +292,13 @@ inline bool QMenuPrivate::useFullScreenForPopup() const
QRect QMenuPrivate::popupGeometry(QScreen *screen) const
{
Q_Q(const QMenu);
+ if (screen == nullptr
+#if QT_CONFIG(graphicsview)
+ && q->graphicsProxyWidget() == nullptr
+#endif
+ ) {
+ screen = q->isVisible() ? q->screen() : popupScreen.data();
+ }
if (useFullScreenForPopup())
return screen ? screen->geometry()
: QWidgetPrivate::screenGeometry(q);
@@ -567,10 +576,16 @@ void QMenuPrivate::hideMenu(QMenu *menu)
};
#if QT_CONFIG(effects)
- QSignalBlocker blocker(menu);
+ // If deleteLater has been called and the event loop spins, while waiting
+ // for visual effects to happen, menu might become stale.
+ // To prevent a QSignalBlocker from restoring a stale object, block and restore signals manually.
+ QPointer<QMenu> stillAlive(menu);
+ const bool signalsBlocked = menu->signalsBlocked();
+ menu->blockSignals(true);
+
aboutToHide = true;
// Flash item which is about to trigger (if any).
- if (menu->style()->styleHint(QStyle::SH_Menu_FlashTriggeredItem)
+ if (menu && menu->style()->styleHint(QStyle::SH_Menu_FlashTriggeredItem)
&& currentAction && currentAction == actionAboutToTrigger
&& menu->actions().contains(currentAction)) {
QEventLoop eventLoop;
@@ -581,6 +596,9 @@ void QMenuPrivate::hideMenu(QMenu *menu)
QTimer::singleShot(60, &eventLoop, SLOT(quit()));
eventLoop.exec();
+ if (!stillAlive)
+ return;
+
// Select and wait 20 ms.
menu->setActiveAction(activeAction);
QTimer::singleShot(20, &eventLoop, SLOT(quit()));
@@ -588,10 +606,16 @@ void QMenuPrivate::hideMenu(QMenu *menu)
}
aboutToHide = false;
- blocker.unblock();
+
+ if (stillAlive)
+ menu->blockSignals(signalsBlocked);
+ else
+ return;
+
#endif // QT_CONFIG(effects)
if (activeMenu == menu)
activeMenu = nullptr;
+
menu->d_func()->causedPopup.action = nullptr;
menu->close();
menu->d_func()->causedPopup.widget = nullptr;
@@ -1708,7 +1732,7 @@ void QMenu::initStyleOption(QStyleOptionMenuItem *option, const QAction *action)
\b{Important inherited functions:} addAction(), removeAction(), clear(),
addSeparator(), and addMenu().
- \sa QMenuBar, {Qt Widgets - Application Example}, {Menus Example}
+ \sa QMenuBar, {Menus Example}
*/
@@ -2292,6 +2316,9 @@ void QMenu::popup(const QPoint &p, QAction *atAction)
void QMenuPrivate::popup(const QPoint &p, QAction *atAction, PositionFunction positionFunction)
{
Q_Q(QMenu);
+ popupScreen = QGuiApplication::screenAt(p);
+ QScopeGuard popupScreenGuard([this](){ popupScreen.clear(); });
+
if (scroll) { // reset scroll state from last popup
if (scroll->scrollOffset)
itemsDirty = 1; // sizeHint will be incorrect if there is previous scroll
@@ -2367,6 +2394,7 @@ void QMenuPrivate::popup(const QPoint &p, QAction *atAction, PositionFunction po
pos = QPushButtonPrivate::get(causedButton)->adjustedMenuPosition();
else
pos = p;
+ popupScreen = QGuiApplication::screenAt(pos);
const QSize menuSizeHint(q->sizeHint());
QSize size = menuSizeHint;
@@ -2505,6 +2533,7 @@ void QMenuPrivate::popup(const QPoint &p, QAction *atAction, PositionFunction po
}
}
}
+ popupScreen = QGuiApplication::screenAt(pos);
q->setGeometry(QRect(pos, size));
#if QT_CONFIG(effects)
int hGuess = q->isRightToLeft() ? QEffects::LeftScroll : QEffects::RightScroll;
@@ -2645,6 +2674,7 @@ QAction *QMenuPrivate::exec(const QPoint &p, QAction *action, PositionFunction p
action = syncAction;
syncAction = nullptr;
eventLoop = nullptr;
+ popupScreen.clear();
return action;
}
@@ -2822,7 +2852,7 @@ void QMenu::paintEvent(QPaintEvent *e)
frame.rect = rect();
frame.palette = palette();
frame.state = QStyle::State_None;
- frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuPanelWidth, &frame);
+ frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuPanelWidth, &frame, this);
frame.midLineWidth = 0;
p.drawPrimitive(QStyle::PE_FrameMenu, frame);
}
diff --git a/src/widgets/widgets/qmenu_p.h b/src/widgets/widgets/qmenu_p.h
index 0d849e5eed..1e32fbcdfa 100644
--- a/src/widgets/widgets/qmenu_p.h
+++ b/src/widgets/widgets/qmenu_p.h
@@ -29,6 +29,8 @@
#include <qpa/qplatformmenu.h>
+#include <QtCore/qpointer.h>
+
#include <functional>
QT_REQUIRE_CONFIG(menu);
@@ -471,6 +473,11 @@ public:
mutable quint8 ncols = 0; // "255cols ought to be enough for anybody."
+ // Contains the screen of the popup point during popup(QPoint).
+ // This is to make sure the screen is remembered,
+ // when the menu contains many items on multiple screens
+ QPointer<QScreen> popupScreen;
+
mutable bool itemsDirty : 1;
mutable bool hasCheckableItems : 1;
bool lastContextMenu : 1;
diff --git a/src/widgets/widgets/qmenubar.cpp b/src/widgets/widgets/qmenubar.cpp
index a53bc97516..c9c9191c17 100644
--- a/src/widgets/widgets/qmenubar.cpp
+++ b/src/widgets/widgets/qmenubar.cpp
@@ -281,17 +281,28 @@ void QMenuBarPrivate::popupAction(QAction *action, bool activateFirst)
if (action->isEnabled() && action->menu()->isEnabled()) {
closePopupMode = 0;
activeMenu = action->menu();
- activeMenu->d_func()->causedPopup.widget = q;
- activeMenu->d_func()->causedPopup.action = action;
+ auto *activeMenuPriv = activeMenu->d_func();
+ activeMenuPriv->causedPopup.widget = q;
+ activeMenuPriv->causedPopup.action = action;
QRect adjustedActionRect = actionRect(action);
- QPoint pos(q->mapToGlobal(QPoint(adjustedActionRect.left(), adjustedActionRect.bottom() + 1)));
- QSize popup_size = activeMenu->sizeHint();
+ QPoint popupPos = adjustedActionRect.bottomLeft() + QPoint(0, 1);
+
//we put the popup menu on the screen containing the bottom-center of the action rect
QScreen *menubarScreen = q->window()->windowHandle()->screen();
- QScreen *popupScreen = menubarScreen->virtualSiblingAt(pos + QPoint(adjustedActionRect.width() / 2, 0));
+ QPoint screenTestPos = q->mapToGlobal(popupPos + QPoint(adjustedActionRect.width() / 2, 0));
+ QPointer<QScreen> popupScreen = menubarScreen->virtualSiblingAt(screenTestPos);
if (!popupScreen)
popupScreen = menubarScreen;
+ std::swap(popupScreen, activeMenuPriv->popupScreen);
+ const QSize popup_size = activeMenu->sizeHint();
+ std::swap(popupScreen, activeMenuPriv->popupScreen);
+
+ // Use screenTestPos.y() for the popup y position. This is the correct global y
+ // consistent with the selected screen in cases where the action rect spans
+ // multiple screens with different scale factors.
+ QPoint pos(q->mapToGlobal(popupPos).x(), screenTestPos.y());
+
QRect screenRect = popupScreen->geometry();
pos = QPoint(qMax(pos.x(), screenRect.x()), qMax(pos.y(), screenRect.y()));
const bool fitUp = (pos.y() - popup_size.height() >= screenRect.top());
@@ -596,11 +607,13 @@ void QMenuBar::initStyleOption(QStyleOptionMenuItem *option, const QAction *acti
Qt for \macos also provides a menu bar merging feature to make
QMenuBar conform more closely to accepted \macos menu bar layout.
- The merging functionality is based on string matching the title of
- a QMenu entry. These strings are translated (using QObject::tr())
- in the "QMenuBar" context. If an entry is moved its slots will still
- fire as if it was in the original place. The table below outlines
- the strings looked for and where the entry is placed if matched:
+ If an entry is moved its slots will still fire as if it was in the
+ original place.
+
+ The merging functionality is based on the QAction::menuRole() of
+ the menu entries. If an item has QAction::TextHeuristicRole,
+ the role is determined by string matching the title using the
+ following heuristics:
\table
\header \li String matches \li Placement \li Notes
@@ -618,8 +631,8 @@ void QMenuBar::initStyleOption(QStyleOptionMenuItem *option, const QAction *acti
created to call QCoreApplication::quit()
\endtable
- You can override this behavior by using the QAction::menuRole()
- property.
+ You can override this behavior by setting the QAction::menuRole()
+ property to QAction::NoRole.
If you want all windows in a Mac application to share one menu
bar, you must create a menu bar that does not have a parent.
@@ -912,7 +925,7 @@ void QMenuBar::paintEvent(QPaintEvent *e)
frame.rect = rect();
frame.palette = palette();
frame.state = QStyle::State_None;
- frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, &frame);
+ frame.lineWidth = style()->pixelMetric(QStyle::PM_MenuBarPanelWidth, &frame, this);
frame.midLineWidth = 0;
style()->drawPrimitive(QStyle::PE_PanelMenuBar, &frame, &p, this);
}
@@ -1285,7 +1298,12 @@ void QMenuBarPrivate::handleReparent()
QList<QPointer<QWidget>> newParents;
// Remove event filters on ex-parents, keep them on still-parents
// The parents are always ordered in the vector
- foreach (const QPointer<QWidget> &w, oldParents) {
+ //
+ // Take a copy because this method is called from changeEvent() and eventFilter(),
+ // which might cause recursion into the class due to event processing, which might
+ // modify oldParents.
+ const auto copy = oldParents;
+ for (const QPointer<QWidget> &w : copy) {
if (w) {
if (newParent == w) {
newParents.append(w);
diff --git a/src/widgets/widgets/qmenubar_p.h b/src/widgets/widgets/qmenubar_p.h
index ee524c3acb..549a4c7a1f 100644
--- a/src/widgets/widgets/qmenubar_p.h
+++ b/src/widgets/widgets/qmenubar_p.h
@@ -20,6 +20,8 @@
#include <private/qmenu_p.h> // Mac needs what in this file!
#include <qpa/qplatformmenu.h>
+#include <QtCore/qpointer.h>
+
QT_REQUIRE_CONFIG(menubar);
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/widgets/qplaintextedit.cpp b/src/widgets/widgets/qplaintextedit.cpp
index 9ca2a84d07..8362c6c629 100644
--- a/src/widgets/widgets/qplaintextedit.cpp
+++ b/src/widgets/widgets/qplaintextedit.cpp
@@ -418,7 +418,7 @@ QPlainTextEditControl::QPlainTextEditControl(QPlainTextEdit *parent)
setAcceptRichText(false);
}
-void QPlainTextEditPrivate::_q_cursorPositionChanged()
+void QPlainTextEditPrivate::cursorPositionChanged()
{
pageUpDownLastCursorYIsValid = false;
Q_Q(QPlainTextEdit);
@@ -429,7 +429,7 @@ void QPlainTextEditPrivate::_q_cursorPositionChanged()
emit q->cursorPositionChanged();
}
-void QPlainTextEditPrivate::_q_verticalScrollbarActionTriggered(int action) {
+void QPlainTextEditPrivate::verticalScrollbarActionTriggered(int action) {
const auto a = static_cast<QAbstractSlider::SliderAction>(action);
switch (a) {
@@ -725,9 +725,14 @@ void QPlainTextEditPrivate::updateViewport()
}
QPlainTextEditPrivate::QPlainTextEditPrivate()
- : tabChangesFocus(false), showCursorOnInitialShow(false), backgroundVisible(false),
- centerOnScroll(false), inDrag(false), clickCausedFocus(false), placeholderVisible(true),
- pageUpDownLastCursorYIsValid(false)
+ : tabChangesFocus(false)
+ , showCursorOnInitialShow(false)
+ , backgroundVisible(false)
+ , centerOnScroll(false)
+ , inDrag(false)
+ , clickCausedFocus(false)
+ , pageUpDownLastCursorYIsValid(false)
+ , placeholderTextShown(false)
{
}
@@ -744,15 +749,15 @@ void QPlainTextEditPrivate::init(const QString &txt)
control->setPalette(q->palette());
QObjectPrivate::connect(vbar, &QAbstractSlider::actionTriggered,
- this, &QPlainTextEditPrivate::_q_verticalScrollbarActionTriggered);
+ this, &QPlainTextEditPrivate::verticalScrollbarActionTriggered);
QObject::connect(control, &QWidgetTextControl::microFocusChanged, q,
[q](){q->updateMicroFocus(); });
QObjectPrivate::connect(control, &QWidgetTextControl::documentSizeChanged,
- this, &QPlainTextEditPrivate::_q_adjustScrollbars);
+ this, &QPlainTextEditPrivate::adjustScrollbars);
QObject::connect(control, &QWidgetTextControl::blockCountChanged,
q, &QPlainTextEdit::blockCountChanged);
QObjectPrivate::connect(control, &QWidgetTextControl::updateRequest,
- this, &QPlainTextEditPrivate::_q_repaintContents);
+ this, &QPlainTextEditPrivate::repaintContents);
QObject::connect(control, &QWidgetTextControl::modificationChanged,
q, &QPlainTextEdit::modificationChanged);
QObject::connect(control, &QWidgetTextControl::textChanged, q, &QPlainTextEdit::textChanged);
@@ -761,9 +766,9 @@ void QPlainTextEditPrivate::init(const QString &txt)
QObject::connect(control, &QWidgetTextControl::copyAvailable, q, &QPlainTextEdit::copyAvailable);
QObject::connect(control, &QWidgetTextControl::selectionChanged, q, &QPlainTextEdit::selectionChanged);
QObjectPrivate::connect(control, &QWidgetTextControl::cursorPositionChanged,
- this, &QPlainTextEditPrivate::_q_cursorPositionChanged);
+ this, &QPlainTextEditPrivate::cursorPositionChanged);
QObjectPrivate::connect(control, &QWidgetTextControl::textChanged,
- this, &QPlainTextEditPrivate::_q_updatePlaceholderVisibility);
+ this, &QPlainTextEditPrivate::updatePlaceholderVisibility);
QObject::connect(control, &QWidgetTextControl::textChanged, q, [q](){q->updateMicroFocus(); });
// set a null page size initially to avoid any relayouting until the textedit
@@ -792,26 +797,19 @@ void QPlainTextEditPrivate::init(const QString &txt)
#endif
}
-void QPlainTextEditPrivate::_q_updatePlaceholderVisibility()
+void QPlainTextEditPrivate::updatePlaceholderVisibility()
{
- Q_Q(QPlainTextEdit);
-
// We normally only repaint the part of view that contains text in the
- // document that has changed (in _q_repaintContents). But the placeholder
+ // document that has changed (in repaintContents). But the placeholder
// text is not a part of the document, but is drawn on separately. So whenever
// we either show or hide the placeholder text, we issue a full update.
- bool placeholderCurrentyVisible = placeholderVisible;
-
- placeholderVisible = !placeholderText.isEmpty()
- && q->document()->isEmpty()
- && (!q->firstVisibleBlock().isValid() ||
- q->firstVisibleBlock().layout()->preeditAreaText().isEmpty());
-
- if (placeholderCurrentyVisible != placeholderVisible)
+ if (placeholderTextShown != placeHolderTextToBeShown()) {
viewport->update();
+ placeholderTextShown = placeHolderTextToBeShown();
+ }
}
-void QPlainTextEditPrivate::_q_repaintContents(const QRectF &contentsRect)
+void QPlainTextEditPrivate::repaintContents(const QRectF &contentsRect)
{
Q_Q(QPlainTextEdit);
if (!contentsRect.isValid()) {
@@ -944,7 +942,7 @@ void QPlainTextEditPrivate::pageUpDown(QTextCursor::MoveOperation op, QTextCurso
#if QT_CONFIG(scrollbar)
-void QPlainTextEditPrivate::_q_adjustScrollbars()
+void QPlainTextEditPrivate::adjustScrollbars()
{
Q_Q(QPlainTextEdit);
QTextDocument *doc = control->document();
@@ -1186,8 +1184,7 @@ void QPlainTextEditPrivate::ensureViewportLayouted()
editor with line wrap enabled in real time. It also makes for a
fast log viewer (see setMaximumBlockCount()).
-
- \sa QTextDocument, QTextCursor, {Qt Widgets - Application Example},
+ \sa QTextDocument, QTextCursor
{Syntax Highlighter Example}, {Rich Text Processing}
*/
@@ -1300,7 +1297,7 @@ void QPlainTextEdit::setDocument(QTextDocument *document)
d->documentLayoutPtr = documentLayout;
d->updateDefaultTextOption();
d->relayoutDocument();
- d->_q_adjustScrollbars();
+ d->adjustScrollbars();
}
/*!
@@ -1332,7 +1329,7 @@ void QPlainTextEdit::setPlaceholderText(const QString &placeholderText)
Q_D(QPlainTextEdit);
if (d->placeholderText != placeholderText) {
d->placeholderText = placeholderText;
- d->_q_updatePlaceholderVisibility();
+ d->updatePlaceholderVisibility();
}
}
@@ -1560,6 +1557,10 @@ bool QPlainTextEdit::event(QEvent *e)
}
return true;
#endif // QT_NO_GESTURES
+ case QEvent::WindowActivate:
+ case QEvent::WindowDeactivate:
+ d->control->setPalette(palette());
+ break;
default:
break;
}
@@ -1845,7 +1846,7 @@ void QPlainTextEdit::resizeEvent(QResizeEvent *e)
Q_D(QPlainTextEdit);
if (e->oldSize().width() != e->size().width())
d->relayoutDocument();
- d->_q_adjustScrollbars();
+ d->adjustScrollbars();
}
void QPlainTextEditPrivate::relayoutDocument()
@@ -1911,7 +1912,7 @@ void QPlainTextEdit::paintEvent(QPaintEvent *e)
er.setRight(qMin(er.right(), maxX));
painter.setClipRect(er);
- if (d->placeholderVisible) {
+ if (d->placeHolderTextToBeShown()) {
const QColor col = d->control->palette().placeholderText().color();
painter.setPen(col);
painter.setClipRect(e->rect());
@@ -2211,7 +2212,7 @@ QVariant QPlainTextEdit::inputMethodQuery(Qt::InputMethodQuery query, QVariant a
Q_D(const QPlainTextEdit);
switch (query) {
case Qt::ImEnabled:
- return isEnabled();
+ return isEnabled() && !isReadOnly();
case Qt::ImHints:
case Qt::ImInputItemClipRectangle:
return QWidget::inputMethodQuery(query);
@@ -2285,7 +2286,7 @@ void QPlainTextEdit::showEvent(QShowEvent *)
d->showCursorOnInitialShow = false;
ensureCursorVisible();
}
- d->_q_adjustScrollbars();
+ d->adjustScrollbars();
}
/*! \reimp
@@ -2602,7 +2603,7 @@ void QPlainTextEdit::insertFromMimeData(const QMimeData *source)
bool QPlainTextEdit::isReadOnly() const
{
Q_D(const QPlainTextEdit);
- return !(d->control->textInteractionFlags() & Qt::TextEditable);
+ return !d->control || !(d->control->textInteractionFlags() & Qt::TextEditable);
}
void QPlainTextEdit::setReadOnly(bool ro)
@@ -2787,7 +2788,7 @@ void QPlainTextEdit::setLineWrapMode(LineWrapMode wrap)
d->lineWrap = wrap;
d->updateDefaultTextOption();
d->relayoutDocument();
- d->_q_adjustScrollbars();
+ d->adjustScrollbars();
ensureCursorVisible();
}
@@ -2873,7 +2874,7 @@ void QPlainTextEdit::setCenterOnScroll(bool enabled)
if (enabled == d->centerOnScroll)
return;
d->centerOnScroll = enabled;
- d->_q_adjustScrollbars();
+ d->adjustScrollbars();
}
@@ -2896,11 +2897,14 @@ bool QPlainTextEdit::find(const QString &exp, QTextDocument::FindFlags options)
\overload
Finds the next occurrence, matching the regular expression, \a exp, using the given
- \a options. The QTextDocument::FindCaseSensitively option is ignored for this overload,
- use QRegularExpression::CaseInsensitiveOption instead.
+ \a options.
Returns \c true if a match was found and changes the cursor to select the match;
otherwise returns \c false.
+
+ \warning For historical reasons, the case sensitivity option set on
+ \a exp is ignored. Instead, the \a options are used to determine
+ if the search is case sensitive or not.
*/
#if QT_CONFIG(regularexpression)
bool QPlainTextEdit::find(const QRegularExpression &exp, QTextDocument::FindFlags options)
@@ -3033,7 +3037,7 @@ void QPlainTextEditPrivate::append(const QString &text, Qt::TextFormat format)
}
documentLayout->priv()->blockDocumentSizeChanged = documentSizeChangedBlocked;
- _q_adjustScrollbars();
+ adjustScrollbars();
if (atBottom) {
diff --git a/src/widgets/widgets/qplaintextedit.h b/src/widgets/widgets/qplaintextedit.h
index d42b67fa69..89a4d3ab04 100644
--- a/src/widgets/widgets/qplaintextedit.h
+++ b/src/widgets/widgets/qplaintextedit.h
@@ -240,11 +240,6 @@ protected:
private:
Q_DISABLE_COPY(QPlainTextEdit)
- Q_PRIVATE_SLOT(d_func(), void _q_repaintContents(const QRectF &r))
- Q_PRIVATE_SLOT(d_func(), void _q_updatePlaceholderVisibility())
- Q_PRIVATE_SLOT(d_func(), void _q_adjustScrollbars())
- Q_PRIVATE_SLOT(d_func(), void _q_verticalScrollbarActionTriggered(int))
- Q_PRIVATE_SLOT(d_func(), void _q_cursorPositionChanged())
friend class QPlainTextEditControl;
};
diff --git a/src/widgets/widgets/qplaintextedit_p.h b/src/widgets/widgets/qplaintextedit_p.h
index 541011cc7e..9ca1cdcc67 100644
--- a/src/widgets/widgets/qplaintextedit_p.h
+++ b/src/widgets/widgets/qplaintextedit_p.h
@@ -32,6 +32,8 @@
#include "private/qwidgettextcontrol_p.h"
+#include <QtCore/qpointer.h>
+
QT_REQUIRE_CONFIG(textedit);
QT_BEGIN_NAMESPACE
@@ -84,14 +86,14 @@ public:
QPlainTextEditPrivate();
void init(const QString &txt = QString());
- void _q_repaintContents(const QRectF &contentsRect);
- void _q_updatePlaceholderVisibility();
+ void repaintContents(const QRectF &contentsRect);
+ void updatePlaceholderVisibility();
inline QPoint mapToContents(const QPoint &point) const
{ return QPoint(point.x() + horizontalOffset(), point.y() + verticalOffset()); }
- void _q_adjustScrollbars();
- void _q_verticalScrollbarActionTriggered(int action);
+ void adjustScrollbars();
+ void verticalScrollbarActionTriggered(int action);
void ensureViewportLayouted();
void relayoutDocument();
@@ -128,8 +130,8 @@ public:
uint centerOnScroll : 1;
uint inDrag : 1;
uint clickCausedFocus : 1;
- uint placeholderVisible : 1;
uint pageUpDownLastCursorYIsValid : 1;
+ uint placeholderTextShown : 1;
void setTopLine(int visualTopLine, int dx = 0);
void setTopBlock(int newTopBlock, int newTopLine, int dx = 0);
@@ -142,8 +144,13 @@ public:
void append(const QString &text, Qt::TextFormat format = Qt::AutoText);
- void _q_cursorPositionChanged();
- void _q_modificationChanged(bool);
+ void cursorPositionChanged();
+ void modificationChanged(bool);
+ inline bool placeHolderTextToBeShown() const
+ {
+ Q_Q(const QPlainTextEdit);
+ return q->document()->isEmpty() && !q->placeholderText().isEmpty();
+ }
};
QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qpushbutton.cpp b/src/widgets/widgets/qpushbutton.cpp
index ec882db175..c180a08d62 100644
--- a/src/widgets/widgets/qpushbutton.cpp
+++ b/src/widgets/widgets/qpushbutton.cpp
@@ -525,7 +525,8 @@ void QPushButton::setMenu(QMenu* menu)
return;
if (menu && !d->menu) {
- connect(this, SIGNAL(pressed()), this, SLOT(_q_popupPressed()), Qt::UniqueConnection);
+ QObjectPrivate::connect(this, &QPushButton::pressed,
+ d, &QPushButtonPrivate::popupPressed, Qt::UniqueConnection);
}
if (d->menu)
removeAction(d->menu->menuAction());
@@ -562,10 +563,10 @@ void QPushButton::showMenu()
if (!d || !d->menu)
return;
setDown(true);
- d->_q_popupPressed();
+ d->popupPressed();
}
-void QPushButtonPrivate::_q_popupPressed()
+void QPushButtonPrivate::popupPressed()
{
Q_Q(QPushButton);
if (!down || !menu)
@@ -575,17 +576,14 @@ void QPushButtonPrivate::_q_popupPressed()
QPoint menuPos = adjustedMenuPosition();
- QPointer<QPushButton> guard(q);
- QMenuPrivate::get(menu)->causedPopup.widget = guard;
+ QMenuPrivate::get(menu)->causedPopup.widget = q;
//Because of a delay in menu effects, we must keep track of the
//menu visibility to avoid flicker on button release
menuOpen = true;
- menu->exec(menuPos);
- if (guard) {
- menuOpen = false;
- q->setDown(false);
- }
+ QObject::connect(menu, &QMenu::aboutToHide,
+ q, [q, this]{ menuOpen = false; q->setDown(false); }, Qt::SingleShotConnection);
+ menu->popup(menuPos);
}
QPoint QPushButtonPrivate::adjustedMenuPosition()
diff --git a/src/widgets/widgets/qpushbutton.h b/src/widgets/widgets/qpushbutton.h
index 6162d6dc80..3c420b5313 100644
--- a/src/widgets/widgets/qpushbutton.h
+++ b/src/widgets/widgets/qpushbutton.h
@@ -62,14 +62,9 @@ protected:
bool hitButton(const QPoint &pos) const override;
QPushButton(QPushButtonPrivate &dd, QWidget* parent = nullptr);
-public:
-
private:
Q_DISABLE_COPY(QPushButton)
Q_DECLARE_PRIVATE(QPushButton)
-#if QT_CONFIG(menu)
- Q_PRIVATE_SLOT(d_func(), void _q_popupPressed())
-#endif
};
QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qpushbutton_p.h b/src/widgets/widgets/qpushbutton_p.h
index 4c97663343..0817589baf 100644
--- a/src/widgets/widgets/qpushbutton_p.h
+++ b/src/widgets/widgets/qpushbutton_p.h
@@ -7,6 +7,8 @@
#include <QtWidgets/private/qtwidgetsglobal_p.h>
#include "private/qabstractbutton_p.h"
+#include <QtCore/qpointer.h>
+
QT_REQUIRE_CONFIG(pushbutton);
//
@@ -43,7 +45,7 @@ public:
QPoint adjustedMenuPosition();
#endif
void resetLayoutItemMargins();
- void _q_popupPressed();
+ void popupPressed();
#if QT_CONFIG(dialog)
QDialog *dialogParent() const;
#else
diff --git a/src/widgets/widgets/qradiobutton.cpp b/src/widgets/widgets/qradiobutton.cpp
index e34b04e5ee..af1bd3f649 100644
--- a/src/widgets/widgets/qradiobutton.cpp
+++ b/src/widgets/widgets/qradiobutton.cpp
@@ -82,7 +82,7 @@ void QRadioButtonPrivate::init()
setDown(), isDown(), autoRepeat(), group(), setAutoRepeat(),
toggle(), pressed(), released(), clicked(), and toggled().
- \sa QPushButton, QToolButton, QCheckBox, {Group Box Example}
+ \sa QPushButton, QToolButton, QCheckBox
*/
diff --git a/src/widgets/widgets/qscrollarea.cpp b/src/widgets/widgets/qscrollarea.cpp
index 00e2f42a81..efbf4da07f 100644
--- a/src/widgets/widgets/qscrollarea.cpp
+++ b/src/widgets/widgets/qscrollarea.cpp
@@ -91,11 +91,7 @@ QT_BEGIN_NAMESPACE
cause the size of the scroll area to be updated whenever the
contents of the layout changes.
- For a complete example using the QScrollArea class, see the \l
- {widgets/imageviewer}{Image Viewer} example. The example shows how
- to combine QLabel and QScrollArea to display an image.
-
- \sa QAbstractScrollArea, QScrollBar, {Image Viewer Example}
+ \sa QAbstractScrollArea, QScrollBar
*/
diff --git a/src/widgets/widgets/qscrollarea_p.h b/src/widgets/widgets/qscrollarea_p.h
index 8d066e9e17..a599fa8c36 100644
--- a/src/widgets/widgets/qscrollarea_p.h
+++ b/src/widgets/widgets/qscrollarea_p.h
@@ -20,6 +20,8 @@
#include "private/qabstractscrollarea_p.h"
#include <QtWidgets/qscrollbar.h>
+#include <QtCore/qpointer.h>
+
QT_REQUIRE_CONFIG(scrollarea);
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/widgets/qscrollbar.cpp b/src/widgets/widgets/qscrollbar.cpp
index 28794bfdcc..789cffba99 100644
--- a/src/widgets/widgets/qscrollbar.cpp
+++ b/src/widgets/widgets/qscrollbar.cpp
@@ -12,7 +12,10 @@
#if QT_CONFIG(menu)
#include "qmenu.h"
#endif
+
#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qpointer.h>
+
#if QT_CONFIG(accessibility)
#include "qaccessible.h"
diff --git a/src/widgets/widgets/qsizegrip.cpp b/src/widgets/widgets/qsizegrip.cpp
index 8ffcb0081b..2500983450 100644
--- a/src/widgets/widgets/qsizegrip.cpp
+++ b/src/widgets/widgets/qsizegrip.cpp
@@ -18,6 +18,8 @@
#include <qpa/qplatformtheme.h>
#include <QtWidgets/qabstractscrollarea.h>
+#include <QtCore/qpointer.h>
+
QT_BEGIN_NAMESPACE
static QWidget *qt_sizegrip_topLevelWidget(QWidget* w)
@@ -73,7 +75,7 @@ public:
void _q_showIfNotHidden()
{
Q_Q(QSizeGrip);
- bool showSizeGrip = !(q->isHidden() && q->testAttribute(Qt::WA_WState_ExplicitShowHide));
+ bool showSizeGrip = !isExplicitlyHidden();
updateTopLevelWidget();
if (tlw && showSizeGrip) {
Qt::WindowStates sizeGripNotVisibleState = Qt::WindowFullScreen;
@@ -449,7 +451,7 @@ void QSizeGrip::setVisible(bool visible)
bool QSizeGrip::eventFilter(QObject *o, QEvent *e)
{
Q_D(QSizeGrip);
- if ((isHidden() && testAttribute(Qt::WA_WState_ExplicitShowHide))
+ if (d->isExplicitlyHidden()
|| e->type() != QEvent::WindowStateChange
|| o != d->tlw) {
return QWidget::eventFilter(o, e);
diff --git a/src/widgets/widgets/qspinbox.cpp b/src/widgets/widgets/qspinbox.cpp
index 5178763bc1..73946d54a9 100644
--- a/src/widgets/widgets/qspinbox.cpp
+++ b/src/widgets/widgets/qspinbox.cpp
@@ -132,12 +132,9 @@ public:
for a custom spin box that allows the user to enter icon sizes
(e.g., "32 x 32"):
- \snippet widgets/icons/iconsizespinbox.cpp 1
+ \snippet code/src_gui_widgets_qspinbox.cpp 8
\codeline
- \snippet widgets/icons/iconsizespinbox.cpp 2
-
- See the \l{widgets/icons}{Icons} example for the full source
- code.
+ \snippet code/src_gui_widgets_qspinbox.cpp 9
\sa QDoubleSpinBox, QDateTimeEdit, QSlider, {Spin Boxes Example}
*/
diff --git a/src/widgets/widgets/qsplashscreen.cpp b/src/widgets/widgets/qsplashscreen.cpp
index 040b7424cf..fcd09908cd 100644
--- a/src/widgets/widgets/qsplashscreen.cpp
+++ b/src/widgets/widgets/qsplashscreen.cpp
@@ -32,6 +32,8 @@ public:
int currAlign;
inline QSplashScreenPrivate();
+
+ void handlePaintEvent();
};
/*!
@@ -67,9 +69,9 @@ public:
\snippet qsplashscreen/main.cpp 1
The user can hide the splash screen by clicking on it with the
- mouse. Since the splash screen is typically displayed before the
- event loop has started running, it is necessary to periodically
- call QCoreApplication::processEvents() to receive the mouse clicks.
+ mouse. For mouse handling to work, call QApplication::processEvents()
+ periodically during startup.
+
It is sometimes useful to update the splash screen with messages,
for example, announcing connections established or modules loaded
@@ -201,18 +203,21 @@ void QSplashScreen::clearMessage()
repaint();
}
-// A copy of Qt Test's qWaitForWindowExposed() and qSleep().
-inline static bool waitForWindowExposed(QWindow *window, int timeout = 1000)
+static bool waitForWidgetMapped(QWidget *widget, int timeout = 1000)
{
enum { TimeOutMs = 10 };
+ auto isMapped = [widget](){
+ return widget->windowHandle() && widget->windowHandle()->isVisible();
+ };
+
QElapsedTimer timer;
timer.start();
- while (!window->isExposed()) {
+ while (!isMapped()) {
const int remaining = timeout - int(timer.elapsed());
if (remaining <= 0)
break;
QCoreApplication::processEvents(QEventLoop::AllEvents, remaining);
- QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
+ QCoreApplication::sendPostedEvents();
#if defined(Q_OS_WIN)
Sleep(uint(TimeOutMs));
#else
@@ -220,7 +225,7 @@ inline static bool waitForWindowExposed(QWindow *window, int timeout = 1000)
nanosleep(&ts, nullptr);
#endif
}
- return window->isExposed();
+ return isMapped();
}
/*!
@@ -233,7 +238,7 @@ void QSplashScreen::finish(QWidget *mainWin)
if (mainWin) {
if (!mainWin->windowHandle())
mainWin->createWinId();
- waitForWindowExposed(mainWin->windowHandle());
+ waitForWidgetMapped(mainWin);
}
close();
}
@@ -311,18 +316,33 @@ void QSplashScreen::drawContents(QPainter *painter)
}
}
+void QSplashScreenPrivate::handlePaintEvent()
+{
+ Q_Q(QSplashScreen);
+ QPainter painter(q);
+ painter.setRenderHints(QPainter::SmoothPixmapTransform);
+ painter.setLayoutDirection(q->layoutDirection());
+ if (!pixmap.isNull())
+ painter.drawPixmap(QPoint(), pixmap);
+ q->drawContents(&painter);
+}
+
/*! \reimp */
bool QSplashScreen::event(QEvent *e)
{
- if (e->type() == QEvent::Paint) {
- Q_D(QSplashScreen);
- QPainter painter(this);
- painter.setRenderHints(QPainter::SmoothPixmapTransform);
- painter.setLayoutDirection(layoutDirection());
- if (!d->pixmap.isNull())
- painter.drawPixmap(QPoint(), d->pixmap);
- drawContents(&painter);
+ Q_D(QSplashScreen);
+
+ switch (e->type()) {
+ case QEvent::Paint:
+ d->handlePaintEvent();
+ break;
+ case QEvent::Show:
+ waitForWidgetMapped(this);
+ break;
+ default:
+ break;
}
+
return QWidget::event(e);
}
diff --git a/src/widgets/widgets/qsplitter.cpp b/src/widgets/widgets/qsplitter.cpp
index 84c3799494..d0519a56a2 100644
--- a/src/widgets/widgets/qsplitter.cpp
+++ b/src/widgets/widgets/qsplitter.cpp
@@ -709,7 +709,7 @@ void QSplitterPrivate::setSizes_helper(const QList<int> &sizes, bool clampNegati
bool QSplitterPrivate::shouldShowWidget(const QWidget *w) const
{
Q_Q(const QSplitter);
- return q->isVisible() && !(w->isHidden() && w->testAttribute(Qt::WA_WState_ExplicitShowHide));
+ return q->isVisible() && !QWidgetPrivate::get(w)->isExplicitlyHidden();
}
void QSplitterPrivate::setGeo(QSplitterLayoutStruct *sls, int p, int s, bool allowCollapse)
diff --git a/src/widgets/widgets/qsplitter_p.h b/src/widgets/widgets/qsplitter_p.h
index 9fbd3ea520..5d5723a957 100644
--- a/src/widgets/widgets/qsplitter_p.h
+++ b/src/widgets/widgets/qsplitter_p.h
@@ -18,6 +18,8 @@
#include <QtWidgets/private/qtwidgetsglobal_p.h>
#include "private/qframe_p.h"
+#include <QtCore/qpointer.h>
+
QT_REQUIRE_CONFIG(splitter);
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/widgets/qstackedwidget.cpp b/src/widgets/widgets/qstackedwidget.cpp
index 754744cf67..9cecee2ef8 100644
--- a/src/widgets/widgets/qstackedwidget.cpp
+++ b/src/widgets/widgets/qstackedwidget.cpp
@@ -98,8 +98,10 @@ QStackedWidget::QStackedWidget(QWidget *parent)
{
Q_D(QStackedWidget);
d->layout = new QStackedLayout(this);
- connect(d->layout, SIGNAL(widgetRemoved(int)), this, SIGNAL(widgetRemoved(int)));
- connect(d->layout, SIGNAL(currentChanged(int)), this, SIGNAL(currentChanged(int)));
+ connect(d->layout, &QStackedLayout::widgetRemoved,
+ this, &QStackedWidget::widgetRemoved);
+ connect(d->layout, &QStackedLayout::currentChanged,
+ this, &QStackedWidget::currentChanged);
}
/*!
diff --git a/src/widgets/widgets/qstatusbar.cpp b/src/widgets/widgets/qstatusbar.cpp
index 6aae10e1ab..e398f52ac4 100644
--- a/src/widgets/widgets/qstatusbar.cpp
+++ b/src/widgets/widgets/qstatusbar.cpp
@@ -151,12 +151,12 @@ QRect QStatusBarPrivate::messageRect() const
Use the showMessage() slot to display a \e temporary message:
- \snippet mainwindows/dockwidgets/mainwindow.cpp 8
+ \snippet code/src_gui_widgets_qstatusbar.cpp 1
To remove a temporary message, use the clearMessage() slot, or set
a time limit when calling showMessage(). For example:
- \snippet mainwindows/dockwidgets/mainwindow.cpp 3
+ \snippet code/src_gui_widgets_qstatusbar.cpp 2
Use the currentMessage() function to retrieve the temporary
message currently shown. The QStatusBar class also provide the
@@ -179,7 +179,7 @@ QRect QStatusBarPrivate::messageRect() const
\image fusion-statusbar-sizegrip.png A status bar shown in the Fusion widget style
- \sa QMainWindow, QStatusTipEvent, {Qt Widgets - Application Example}
+ \sa QMainWindow, QStatusTipEvent
*/
@@ -271,7 +271,7 @@ int QStatusBar::insertWidget(int index, QWidget *widget, int stretch)
widget->hide();
reformat();
- if (!widget->isHidden() || !widget->testAttribute(Qt::WA_WState_ExplicitShowHide))
+ if (!QWidgetPrivate::get(widget)->isExplicitlyHidden())
widget->show();
return index;
@@ -332,7 +332,7 @@ int QStatusBar::insertPermanentWidget(int index, QWidget *widget, int stretch)
d->items.insert(index, item);
reformat();
- if (!widget->isHidden() || !widget->testAttribute(Qt::WA_WState_ExplicitShowHide))
+ if (!QWidgetPrivate::get(widget)->isExplicitlyHidden())
widget->show();
return index;
@@ -494,7 +494,7 @@ void QStatusBar::showMessage(const QString &message, int timeout)
if (timeout > 0) {
if (!d->timer) {
d->timer = new QTimer(this);
- connect(d->timer, SIGNAL(timeout()), this, SLOT(clearMessage()));
+ connect(d->timer, &QTimer::timeout, this, &QStatusBar::clearMessage);
}
d->timer->start(timeout);
} else if (d->timer) {
@@ -520,7 +520,7 @@ void QStatusBar::clearMessage()
if (d->tempItem.isEmpty())
return;
if (d->timer) {
- qDeleteInEventHandler(d->timer);
+ delete d->timer;
d->timer = nullptr;
}
d->tempItem.clear();
diff --git a/src/widgets/widgets/qtabbar.cpp b/src/widgets/widgets/qtabbar.cpp
index 0b1190ebf1..0b463840ae 100644
--- a/src/widgets/widgets/qtabbar.cpp
+++ b/src/widgets/widgets/qtabbar.cpp
@@ -71,14 +71,6 @@ void QMovableTabWidget::paintEvent(QPaintEvent *e)
p.drawPixmap(0, 0, m_pixmap);
}
-inline static bool verticalTabs(QTabBar::Shape shape)
-{
- return shape == QTabBar::RoundedWest
- || shape == QTabBar::RoundedEast
- || shape == QTabBar::TriangularWest
- || shape == QTabBar::TriangularEast;
-}
-
void QTabBarPrivate::updateMacBorderMetrics()
{
#if defined(Q_OS_MACOS)
@@ -283,9 +275,9 @@ void QTabBar::initStyleOption(QStyleOptionTab *option, int tabIndex) const
returns the visual geometry of a single tab.
\table 100%
- \row \li \inlineimage fusion-tabbar.png Screenshot of a Fusion style tab bar
+ \row \li \inlineimage {fusion-tabbar.png} {Screenshot of a Fusion style tab bar}
\li A tab bar shown in the \l{Qt Widget Gallery}{Fusion widget style}.
- \row \li \inlineimage fusion-tabbar-truncated.png Screenshot of a truncated Fusion tab bar
+ \row \li \inlineimage {fusion-tabbar-truncated.png} {Screenshot of a truncated Fusion tab bar}
\li A truncated tab bar shown in the Fusion widget style.
\endtable
@@ -374,12 +366,14 @@ void QTabBarPrivate::init()
leftB = new QToolButton(q);
leftB->setObjectName(u"ScrollLeftButton"_s);
leftB->setAutoRepeat(true);
- QObject::connect(leftB, SIGNAL(clicked()), q, SLOT(_q_scrollTabs()));
+ QObjectPrivate::connect(leftB, &QToolButton::clicked,
+ this, &QTabBarPrivate::scrollTabs);
leftB->hide();
rightB = new QToolButton(q);
rightB->setObjectName(u"ScrollRightButton"_s);
rightB->setAutoRepeat(true);
- QObject::connect(rightB, SIGNAL(clicked()), q, SLOT(_q_scrollTabs()));
+ QObjectPrivate::connect(rightB, &QToolButton::clicked,
+ this, &QTabBarPrivate::scrollTabs);
rightB->hide();
#ifdef QT_KEYPAD_NAVIGATION
if (QApplicationPrivate::keypadNavigationEnabled()) {
@@ -534,7 +528,6 @@ void QTabBarPrivate::layoutTabs()
if (useScrollButtons && tabList.size() && last > available) {
const QRect scrollRect = normalizedScrollRect(0);
- scrollOffset = -scrollRect.left();
Q_Q(QTabBar);
QStyleOption opt;
@@ -571,10 +564,9 @@ void QTabBarPrivate::layoutTabs()
leftB->show();
rightB->setGeometry(scrollButtonRightRect);
- rightB->setEnabled(last - scrollOffset > scrollRect.x() + scrollRect.width());
+ rightB->setEnabled(last + scrollRect.left() > scrollRect.x() + scrollRect.width());
rightB->show();
} else {
- scrollOffset = 0;
rightB->hide();
leftB->hide();
}
@@ -591,6 +583,11 @@ QRect QTabBarPrivate::normalizedScrollRect(int index)
// tab bar itself is in a different orientation.
Q_Q(QTabBar);
+ // If scrollbuttons are not visible, then there's no tear either, and
+ // the entire widget is the scroll rect.
+ if (leftB->isHidden())
+ return verticalTabs(shape) ? q->rect().transposed() : q->rect();
+
QStyleOptionTab opt;
q->initStyleOption(&opt, currentIndex);
opt.rect = q->rect();
@@ -670,25 +667,33 @@ int QTabBarPrivate::hoveredTabIndex() const
void QTabBarPrivate::makeVisible(int index)
{
Q_Q(QTabBar);
- if (!validIndex(index) || leftB->isHidden())
+ if (!validIndex(index))
return;
const QRect tabRect = tabList.at(index)->rect;
const int oldScrollOffset = scrollOffset;
const bool horiz = !verticalTabs(shape);
+ const int available = horiz ? q->width() : q->height();
const int tabStart = horiz ? tabRect.left() : tabRect.top();
const int tabEnd = horiz ? tabRect.right() : tabRect.bottom();
const int lastTabEnd = horiz ? tabList.constLast()->rect.right() : tabList.constLast()->rect.bottom();
const QRect scrollRect = normalizedScrollRect(index);
+ const QRect entireScrollRect = normalizedScrollRect(0); // ignore tears
const int scrolledTabBarStart = qMax(1, scrollRect.left() + scrollOffset);
const int scrolledTabBarEnd = qMin(lastTabEnd - 1, scrollRect.right() + scrollOffset);
- if (tabStart < scrolledTabBarStart) {
+ if (available >= lastTabEnd) {
+ // the entire tabbar fits, reset scroll
+ scrollOffset = 0;
+ } else if (tabStart < scrolledTabBarStart) {
// Tab is outside on the left, so scroll left.
scrollOffset = tabStart - scrollRect.left();
} else if (tabEnd > scrolledTabBarEnd) {
// Tab is outside on the right, so scroll right.
- scrollOffset = tabEnd - scrollRect.right();
+ scrollOffset = qMax(0, tabEnd - scrollRect.right());
+ } else if (scrollOffset + entireScrollRect.width() > lastTabEnd + 1) {
+ // fill any free space on the right without overshooting
+ scrollOffset = qMax(0, lastTabEnd - entireScrollRect.width() + 1);
}
leftB->setEnabled(scrollOffset > -scrollRect.left());
@@ -762,7 +767,7 @@ void QTabBarPrivate::autoHideTabs()
q->setVisible(q->count() > 1);
}
-void QTabBarPrivate::_q_closeTab()
+void QTabBarPrivate::closeTab()
{
Q_Q(QTabBar);
QObject *object = q->sender();
@@ -785,7 +790,7 @@ void QTabBarPrivate::_q_closeTab()
emit q->tabCloseRequested(tabToClose);
}
-void QTabBarPrivate::_q_scrollTabs()
+void QTabBarPrivate::scrollTabs()
{
Q_Q(QTabBar);
const QObject *sender = q->sender();
@@ -975,7 +980,8 @@ int QTabBar::insertTab(int index, const QIcon& icon, const QString &text)
initStyleOption(&opt, index);
ButtonPosition closeSide = (ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, nullptr, this);
QAbstractButton *closeButton = new CloseButton(this);
- connect(closeButton, SIGNAL(clicked()), this, SLOT(_q_closeTab()));
+ QObjectPrivate::connect(closeButton, &CloseButton::clicked,
+ d, &QTabBarPrivate::closeTab);
setTabButton(index, closeSide, closeButton);
}
@@ -1410,7 +1416,10 @@ void QTabBar::setCurrentIndex(int index)
if (tabRect(index).size() != tabSizeHint(index))
d->layoutTabs();
update();
- d->makeVisible(index);
+ if (!isVisible())
+ d->layoutDirty = true;
+ else
+ d->makeVisible(index);
if (d->validIndex(oldIndex)) {
tab->lastTab = oldIndex;
d->layoutTab(oldIndex);
@@ -1645,6 +1654,8 @@ void QTabBar::showEvent(QShowEvent *)
d->refresh();
if (!d->validIndex(d->currentIndex))
setCurrentIndex(0);
+ else
+ d->makeVisible(d->currentIndex);
d->updateMacBorderMetrics();
}
@@ -1778,6 +1789,8 @@ void QTabBar::resizeEvent(QResizeEvent *)
Q_D(QTabBar);
if (d->layoutDirty)
updateGeometry();
+
+ // when resizing, we want to keep the scroll offset as much as possible
d->layoutTabs();
d->makeVisible(d->currentIndex);
@@ -1873,21 +1886,30 @@ void QTabBar::paintEvent(QPaintEvent *)
QStyleOptionTab tabOption;
const auto tab = d->tabList.at(selected);
initStyleOption(&tabOption, selected);
+
if (d->paintWithOffsets && tab->dragOffset != 0) {
+ // if the drag offset is != 0, a move is in progress (drag or animation)
+ // => set the tab position to Moving to preserve the rect
+ tabOption.position = QStyleOptionTab::TabPosition::Moving;
+
if (vertical)
tabOption.rect.moveTop(tabOption.rect.y() + tab->dragOffset);
else
tabOption.rect.moveLeft(tabOption.rect.x() + tab->dragOffset);
}
- if (!d->dragInProgress)
- p.drawControl(QStyle::CE_TabBarTab, tabOption);
- else {
- int taboverlap = style()->pixelMetric(QStyle::PM_TabBarTabOverlap, nullptr, this);
- if (verticalTabs(d->shape))
- d->movingTab->setGeometry(tabOption.rect.adjusted(0, -taboverlap, 0, taboverlap));
- else
- d->movingTab->setGeometry(tabOption.rect.adjusted(-taboverlap, 0, taboverlap, 0));
- }
+
+ // Calculate the rect of a moving tab
+ const int taboverlap = style()->pixelMetric(QStyle::PM_TabBarTabOverlap, nullptr, this);
+ const QRect &movingRect = verticalTabs(d->shape)
+ ? tabOption.rect.adjusted(0, -taboverlap, 0, taboverlap)
+ : tabOption.rect.adjusted(-taboverlap, 0, taboverlap, 0);
+
+ // If a drag is in process, set the moving tab's geometry here
+ // (in an animation, it is already set)
+ if (d->dragInProgress)
+ d->movingTab->setGeometry(movingRect);
+
+ p.drawControl(QStyle::CE_TabBarTab, tabOption);
}
// Only draw the tear indicator if necessary. Most of the time we don't need too.
@@ -2194,7 +2216,8 @@ void QTabBar::mouseMoveEvent(QMouseEvent *event)
}
}
// Buttons needs to follow the dragged tab
- d->layoutTab(d->pressedIndex);
+ if (d->pressedIndex != -1)
+ d->layoutTab(d->pressedIndex);
update();
}
@@ -2226,7 +2249,7 @@ void QTabBarPrivate::setupMovableTab()
QStyleOptionTab tab;
q->initStyleOption(&tab, pressedIndex);
- tab.position = QStyleOptionTab::OnlyOneTab;
+ tab.position = QStyleOptionTab::Moving;
if (verticalTabs(shape))
tab.rect.moveTopLeft(QPoint(0, taboverlap));
else
@@ -2416,7 +2439,7 @@ void QTabBarPrivate::setCurrentNextEnabledIndex(int offset)
{
Q_Q(QTabBar);
for (int index = currentIndex + offset; validIndex(index); index += offset) {
- if (tabList.at(index)->enabled) {
+ if (tabList.at(index)->enabled && tabList.at(index)->visible) {
q->setCurrentIndex(index);
break;
}
@@ -2562,7 +2585,8 @@ void QTabBar::setTabsClosable(bool closable)
continue;
newButtons = true;
QAbstractButton *closeButton = new CloseButton(this);
- connect(closeButton, SIGNAL(clicked()), this, SLOT(_q_closeTab()));
+ QObjectPrivate::connect(closeButton, &CloseButton::clicked,
+ d, &QTabBarPrivate::closeTab);
setTabButton(i, closeSide, closeButton);
}
if (newButtons)
diff --git a/src/widgets/widgets/qtabbar.h b/src/widgets/widgets/qtabbar.h
index 2d3179e2d0..2759d5a318 100644
--- a/src/widgets/widgets/qtabbar.h
+++ b/src/widgets/widgets/qtabbar.h
@@ -185,8 +185,6 @@ protected:
private:
Q_DISABLE_COPY(QTabBar)
Q_DECLARE_PRIVATE(QTabBar)
- Q_PRIVATE_SLOT(d_func(), void _q_scrollTabs())
- Q_PRIVATE_SLOT(d_func(), void _q_closeTab())
};
QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qtabbar_p.h b/src/widgets/widgets/qtabbar_p.h
index a421836b93..d76f439bd7 100644
--- a/src/widgets/widgets/qtabbar_p.h
+++ b/src/widgets/widgets/qtabbar_p.h
@@ -187,8 +187,8 @@ public:
inline bool validIndex(int index) const { return index >= 0 && index < tabList.size(); }
void setCurrentNextEnabledIndex(int offset);
- void _q_scrollTabs();
- void _q_closeTab();
+ void scrollTabs();
+ void closeTab();
void moveTab(int index, int offset);
void moveTabFinished(int index);
@@ -245,6 +245,14 @@ public:
};
+constexpr inline bool verticalTabs(QTabBar::Shape shape) noexcept
+{
+ return shape == QTabBar::RoundedWest
+ || shape == QTabBar::RoundedEast
+ || shape == QTabBar::TriangularWest
+ || shape == QTabBar::TriangularEast;
+}
+
QT_END_NAMESPACE
#endif
diff --git a/src/widgets/widgets/qtabwidget.cpp b/src/widgets/widgets/qtabwidget.cpp
index 8db76db7c7..5e7c266ef6 100644
--- a/src/widgets/widgets/qtabwidget.cpp
+++ b/src/widgets/widgets/qtabwidget.cpp
@@ -156,9 +156,9 @@ public:
QTabWidgetPrivate();
~QTabWidgetPrivate();
void updateTabBarPosition();
- void _q_showTab(int);
- void _q_removeTab(int);
- void _q_tabMoved(int from, int to);
+ void showTab(int);
+ void removeTab(int);
+ void tabMoved(int from, int to);
void init();
bool isAutoHidden() const
{
@@ -197,7 +197,7 @@ void QTabWidgetPrivate::init()
// hack so that QMacStyle::layoutSpacing() can detect tab widget pages
stack->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred, QSizePolicy::TabWidget));
- QObject::connect(stack, SIGNAL(widgetRemoved(int)), q, SLOT(_q_removeTab(int)));
+ QObjectPrivate::connect(stack, &QStackedWidget::widgetRemoved, this, &QTabWidgetPrivate::removeTab);
QTabBar *tabBar = new QTabBar(q);
tabBar->setObjectName("qt_tabwidget_tabbar"_L1);
tabBar->setDrawBase(false);
@@ -720,17 +720,17 @@ void QTabWidget::setTabBar(QTabBar* tb)
delete d->tabs;
d->tabs = tb;
setFocusProxy(d->tabs);
- connect(d->tabs, SIGNAL(currentChanged(int)),
- this, SLOT(_q_showTab(int)));
- connect(d->tabs, SIGNAL(tabMoved(int,int)),
- this, SLOT(_q_tabMoved(int,int)));
- connect(d->tabs, SIGNAL(tabBarClicked(int)),
- this, SIGNAL(tabBarClicked(int)));
- connect(d->tabs, SIGNAL(tabBarDoubleClicked(int)),
- this, SIGNAL(tabBarDoubleClicked(int)));
+ QObjectPrivate::connect(d->tabs, &QTabBar::currentChanged,
+ d, &QTabWidgetPrivate::showTab);
+ QObjectPrivate::connect(d->tabs, &QTabBar::tabMoved,
+ d, &QTabWidgetPrivate::tabMoved);
+ connect(d->tabs, &QTabBar::tabBarClicked,
+ this, &QTabWidget::tabBarClicked);
+ connect(d->tabs, &QTabBar::tabBarDoubleClicked,
+ this, &QTabWidget::tabBarDoubleClicked);
if (d->tabs->tabsClosable())
- connect(d->tabs, SIGNAL(tabCloseRequested(int)),
- this, SIGNAL(tabCloseRequested(int)));
+ connect(d->tabs, &QTabBar::tabCloseRequested,
+ this, &QTabWidget::tabCloseRequested);
tb->setExpanding(!documentMode());
setUpLayout();
}
@@ -752,7 +752,7 @@ QTabBar* QTabWidget::tabBar() const
sized.
*/
-void QTabWidgetPrivate::_q_showTab(int index)
+void QTabWidgetPrivate::showTab(int index)
{
Q_Q(QTabWidget);
if (index < stack->count() && index >= 0)
@@ -760,7 +760,7 @@ void QTabWidgetPrivate::_q_showTab(int index)
emit q->currentChanged(index);
}
-void QTabWidgetPrivate::_q_removeTab(int index)
+void QTabWidgetPrivate::removeTab(int index)
{
Q_Q(QTabWidget);
tabs->removeTab(index);
@@ -768,7 +768,7 @@ void QTabWidgetPrivate::_q_removeTab(int index)
q->tabRemoved(index);
}
-void QTabWidgetPrivate::_q_tabMoved(int from, int to)
+void QTabWidgetPrivate::tabMoved(int from, int to)
{
const QSignalBlocker blocker(stack);
QWidget *w = stack->widget(from);
@@ -1139,7 +1139,7 @@ void QTabWidget::keyPressEvent(QKeyEvent *e)
) {
page = 0;
}
- if (d->tabs->isTabEnabled(page)) {
+ if (d->tabs->isTabEnabled(page) && d->tabs->isTabVisible(page)) {
setCurrentIndex(page);
break;
}
diff --git a/src/widgets/widgets/qtabwidget.h b/src/widgets/widgets/qtabwidget.h
index 6188ea4999..c813f8d921 100644
--- a/src/widgets/widgets/qtabwidget.h
+++ b/src/widgets/widgets/qtabwidget.h
@@ -141,9 +141,6 @@ protected:
private:
Q_DECLARE_PRIVATE(QTabWidget)
Q_DISABLE_COPY(QTabWidget)
- Q_PRIVATE_SLOT(d_func(), void _q_showTab(int))
- Q_PRIVATE_SLOT(d_func(), void _q_removeTab(int))
- Q_PRIVATE_SLOT(d_func(), void _q_tabMoved(int, int))
void setUpLayout(bool = false);
};
diff --git a/src/widgets/widgets/qtextbrowser.cpp b/src/widgets/widgets/qtextbrowser.cpp
index 1cac46e8a8..2c01ed2b26 100644
--- a/src/widgets/widgets/qtextbrowser.cpp
+++ b/src/widgets/widgets/qtextbrowser.cpp
@@ -46,6 +46,11 @@ public:
, lastKeypadScrollValue(-1)
#endif
{}
+ ~QTextBrowserPrivate()
+ {
+ for (const QMetaObject::Connection &connection : connections)
+ QObject::disconnect(connection);
+ }
void init();
@@ -103,14 +108,14 @@ public:
QString findFile(const QUrl &name) const;
- inline void _q_documentModified()
+ inline void documentModified()
{
textOrSourceChanged = true;
forceLoadOnSourceChange = !currentURL.path().isEmpty();
}
- void _q_activateAnchor(const QString &href);
- void _q_highlightLink(const QString &href);
+ void activateAnchor(const QString &href);
+ void highlightLink(const QString &href);
void setSource(const QUrl &url, QTextDocument::ResourceType type);
@@ -129,6 +134,7 @@ public:
Q_Q(QTextBrowser);
emit q->highlighted(url);
}
+ std::array<QMetaObject::Connection, 3> connections;
};
Q_DECLARE_TYPEINFO(QTextBrowserPrivate::HistoryEntry, Q_RELOCATABLE_TYPE);
@@ -190,7 +196,7 @@ QUrl QTextBrowserPrivate::resolveUrl(const QUrl &url) const
return url;
}
-void QTextBrowserPrivate::_q_activateAnchor(const QString &href)
+void QTextBrowserPrivate::activateAnchor(const QString &href)
{
if (href.isEmpty())
return;
@@ -231,7 +237,7 @@ void QTextBrowserPrivate::_q_activateAnchor(const QString &href)
q->setSource(url);
}
-void QTextBrowserPrivate::_q_highlightLink(const QString &anchor)
+void QTextBrowserPrivate::highlightLink(const QString &anchor)
{
if (anchor.isEmpty()) {
#ifndef QT_NO_CURSOR
@@ -670,11 +676,14 @@ void QTextBrowserPrivate::init()
q->setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(q));
q->setUndoRedoEnabled(false);
viewport->setMouseTracking(true);
- QObject::connect(q->document(), SIGNAL(contentsChanged()), q, SLOT(_q_documentModified()));
- QObject::connect(control, SIGNAL(linkActivated(QString)),
- q, SLOT(_q_activateAnchor(QString)));
- QObject::connect(control, SIGNAL(linkHovered(QString)),
- q, SLOT(_q_highlightLink(QString)));
+ connections = {
+ QObjectPrivate::connect(q->document(), &QTextDocument::contentsChanged,
+ this, &QTextBrowserPrivate::documentModified),
+ QObjectPrivate::connect(control, &QWidgetTextControl::linkActivated,
+ this, &QTextBrowserPrivate::activateAnchor),
+ QObjectPrivate::connect(control, &QWidgetTextControl::linkHovered,
+ this, &QTextBrowserPrivate::highlightLink),
+ };
}
/*!
diff --git a/src/widgets/widgets/qtextbrowser.h b/src/widgets/widgets/qtextbrowser.h
index 1a6cd412d1..f8e9c0c301 100644
--- a/src/widgets/widgets/qtextbrowser.h
+++ b/src/widgets/widgets/qtextbrowser.h
@@ -82,9 +82,6 @@ protected:
private:
Q_DISABLE_COPY(QTextBrowser)
Q_DECLARE_PRIVATE(QTextBrowser)
- Q_PRIVATE_SLOT(d_func(), void _q_documentModified())
- Q_PRIVATE_SLOT(d_func(), void _q_activateAnchor(const QString &))
- Q_PRIVATE_SLOT(d_func(), void _q_highlightLink(const QString &))
};
QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qtextedit.cpp b/src/widgets/widgets/qtextedit.cpp
index 6782b37911..90884dd438 100644
--- a/src/widgets/widgets/qtextedit.cpp
+++ b/src/widgets/widgets/qtextedit.cpp
@@ -88,8 +88,7 @@ QTextEditPrivate::QTextEditPrivate()
: control(nullptr),
autoFormatting(QTextEdit::AutoNone), tabChangesFocus(false),
lineWrap(QTextEdit::WidgetWidth), lineWrapColumnOrWidth(0),
- wordWrap(QTextOption::WrapAtWordBoundaryOrAnywhere), clickCausedFocus(0),
- textFormat(Qt::AutoText)
+ wordWrap(QTextOption::WrapAtWordBoundaryOrAnywhere), clickCausedFocus(0)
{
ignoreAutomaticScrollbarAdjustment = false;
preferRichText = false;
@@ -97,6 +96,12 @@ QTextEditPrivate::QTextEditPrivate()
inDrag = false;
}
+QTextEditPrivate::~QTextEditPrivate()
+{
+ for (const QMetaObject::Connection &connection : connections)
+ QObject::disconnect(connection);
+}
+
void QTextEditPrivate::createAutoBulletList()
{
QTextCursor cursor = control->textCursor();
@@ -123,24 +128,34 @@ void QTextEditPrivate::init(const QString &html)
control = new QTextEditControl(q);
control->setPalette(q->palette());
- QObject::connect(control, SIGNAL(microFocusChanged()), q, SLOT(updateMicroFocus()));
- QObject::connect(control, SIGNAL(documentSizeChanged(QSizeF)), q, SLOT(_q_adjustScrollbars()));
- QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(_q_repaintContents(QRectF)));
- QObject::connect(control, SIGNAL(visibilityRequest(QRectF)), q, SLOT(_q_ensureVisible(QRectF)));
- QObject::connect(control, SIGNAL(currentCharFormatChanged(QTextCharFormat)),
- q, SLOT(_q_currentCharFormatChanged(QTextCharFormat)));
-
- QObject::connect(control, SIGNAL(textChanged()), q, SIGNAL(textChanged()));
- QObject::connect(control, SIGNAL(undoAvailable(bool)), q, SIGNAL(undoAvailable(bool)));
- QObject::connect(control, SIGNAL(redoAvailable(bool)), q, SIGNAL(redoAvailable(bool)));
- QObject::connect(control, SIGNAL(copyAvailable(bool)), q, SIGNAL(copyAvailable(bool)));
- QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged()));
- QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(_q_cursorPositionChanged()));
-#if QT_CONFIG(cursor)
- QObject::connect(control, SIGNAL(blockMarkerHovered(QTextBlock)), q, SLOT(_q_hoveredBlockWithMarkerChanged(QTextBlock)));
-#endif
-
- QObject::connect(control, SIGNAL(textChanged()), q, SLOT(updateMicroFocus()));
+ connections = {
+ QObjectPrivate::connect(control, &QTextEditControl::documentSizeChanged,
+ this, &QTextEditPrivate::adjustScrollbars),
+ QObjectPrivate::connect(control, &QTextEditControl::updateRequest,
+ this, &QTextEditPrivate::repaintContents),
+ QObjectPrivate::connect(control, &QTextEditControl::visibilityRequest,
+ this, &QTextEditPrivate::ensureVisible),
+ QObjectPrivate::connect(control, &QTextEditControl::blockMarkerHovered,
+ this, &QTextEditPrivate::hoveredBlockWithMarkerChanged),
+ QObjectPrivate::connect(control, &QTextEditControl::cursorPositionChanged,
+ this, &QTextEditPrivate::cursorPositionChanged),
+ QObject::connect(control, &QTextEditControl::microFocusChanged,
+ q, [q]() { q->updateMicroFocus(); }),
+ QObject::connect(control, &QTextEditControl::currentCharFormatChanged,
+ q, &QTextEdit::currentCharFormatChanged),
+ QObject::connect(control, &QTextEditControl::textChanged,
+ q, &QTextEdit::textChanged),
+ QObject::connect(control, &QTextEditControl::undoAvailable,
+ q, &QTextEdit::undoAvailable),
+ QObject::connect(control, &QTextEditControl::redoAvailable,
+ q, &QTextEdit::redoAvailable),
+ QObject::connect(control, &QTextEditControl::copyAvailable,
+ q, &QTextEdit::copyAvailable),
+ QObject::connect(control, &QTextEditControl::selectionChanged,
+ q, &QTextEdit::selectionChanged),
+ QObject::connect(control, &QTextEditControl::textChanged,
+ q, [q]() { q->updateMicroFocus(); }),
+ };
QTextDocument *doc = control->document();
// set a null page size initially to avoid any relayouting until the textedit
@@ -170,7 +185,7 @@ void QTextEditPrivate::init(const QString &html)
#endif
}
-void QTextEditPrivate::_q_repaintContents(const QRectF &contentsRect)
+void QTextEditPrivate::repaintContents(const QRectF &contentsRect)
{
if (!contentsRect.isValid()) {
viewport->update();
@@ -188,7 +203,7 @@ void QTextEditPrivate::_q_repaintContents(const QRectF &contentsRect)
viewport->update(r);
}
-void QTextEditPrivate::_q_cursorPositionChanged()
+void QTextEditPrivate::cursorPositionChanged()
{
Q_Q(QTextEdit);
emit q->cursorPositionChanged();
@@ -198,9 +213,9 @@ void QTextEditPrivate::_q_cursorPositionChanged()
#endif
}
-#if QT_CONFIG(cursor)
-void QTextEditPrivate::_q_hoveredBlockWithMarkerChanged(const QTextBlock &block)
+void QTextEditPrivate::hoveredBlockWithMarkerChanged(const QTextBlock &block)
{
+#if QT_CONFIG(cursor)
Q_Q(QTextEdit);
Qt::CursorShape cursor = cursorToRestoreAfterHover;
if (block.isValid() && !q->isReadOnly()) {
@@ -212,8 +227,8 @@ void QTextEditPrivate::_q_hoveredBlockWithMarkerChanged(const QTextBlock &block)
}
}
viewport->setCursor(cursor);
-}
#endif
+}
void QTextEditPrivate::pageUpDown(QTextCursor::MoveOperation op, QTextCursor::MoveMode moveMode)
{
@@ -262,7 +277,7 @@ static QSize documentSize(QWidgetTextControl *control)
return docSize;
}
-void QTextEditPrivate::_q_adjustScrollbars()
+void QTextEditPrivate::adjustScrollbars()
{
if (ignoreAutomaticScrollbarAdjustment)
return;
@@ -312,12 +327,12 @@ void QTextEditPrivate::_q_adjustScrollbars()
#endif
// rect is in content coordinates
-void QTextEditPrivate::_q_ensureVisible(const QRectF &_rect)
+void QTextEditPrivate::ensureVisible(const QRectF &_rect)
{
const QRect rect = _rect.toRect();
if ((vbar->isVisible() && vbar->maximum() < rect.bottom())
|| (hbar->isVisible() && hbar->maximum() < rect.right()))
- _q_adjustScrollbars();
+ adjustScrollbars();
const int visibleWidth = viewport->width();
const int visibleHeight = viewport->height();
const bool rtl = q_func()->isRightToLeft();
@@ -540,7 +555,7 @@ void QTextEditPrivate::_q_ensureVisible(const QRectF &_rect)
of the movement keystrokes, for example, \e{Shift+Right}
will select the character to the right, and \e{Shift+Ctrl+Right} will select the word to the right, etc.
- \sa QTextDocument, QTextCursor, {Qt Widgets - Application Example},
+ \sa QTextDocument, QTextCursor,
{Syntax Highlighter Example}, {Rich Text Processing}
*/
@@ -1065,30 +1080,38 @@ void QTextEdit::selectAll()
bool QTextEdit::event(QEvent *e)
{
Q_D(QTextEdit);
-#ifndef QT_NO_CONTEXTMENU
- if (e->type() == QEvent::ContextMenu
- && static_cast<QContextMenuEvent *>(e)->reason() == QContextMenuEvent::Keyboard) {
- Q_D(QTextEdit);
- ensureCursorVisible();
- const QPoint cursorPos = cursorRect().center();
- QContextMenuEvent ce(QContextMenuEvent::Keyboard, cursorPos, d->viewport->mapToGlobal(cursorPos));
- ce.setAccepted(e->isAccepted());
- const bool result = QAbstractScrollArea::event(&ce);
- e->setAccepted(ce.isAccepted());
- return result;
- } else if (e->type() == QEvent::ShortcutOverride
- || e->type() == QEvent::ToolTip) {
+ switch (e->type()) {
+ case QEvent::ShortcutOverride:
+ case QEvent::ToolTip:
d->sendControlEvent(e);
- }
-#else
- Q_UNUSED(d);
+ break;
+ case QEvent::WindowActivate:
+ case QEvent::WindowDeactivate:
+ d->control->setPalette(palette());
+ break;
+#ifndef QT_NO_CONTEXTMENU
+ case QEvent::ContextMenu:
+ if (static_cast<QContextMenuEvent *>(e)->reason() == QContextMenuEvent::Keyboard) {
+ ensureCursorVisible();
+ const QPoint cursorPos = cursorRect().center();
+ QContextMenuEvent ce(QContextMenuEvent::Keyboard, cursorPos, d->viewport->mapToGlobal(cursorPos));
+ ce.setAccepted(e->isAccepted());
+ const bool result = QAbstractScrollArea::event(&ce);
+ e->setAccepted(ce.isAccepted());
+ return result;
+ }
+ break;
#endif // QT_NO_CONTEXTMENU
#ifdef QT_KEYPAD_NAVIGATION
- if (e->type() == QEvent::EnterEditFocus || e->type() == QEvent::LeaveEditFocus) {
+ case QEvent::EnterEditFocus:
+ case QEvent::LeaveEditFocus:
if (QApplicationPrivate::keypadNavigationEnabled())
d->sendControlEvent(e);
- }
+ break;
#endif
+ default:
+ break;
+ }
return QAbstractScrollArea::event(e);
}
@@ -1478,7 +1501,7 @@ void QTextEdit::resizeEvent(QResizeEvent *e)
&& alignmentProperty.userType() == QMetaType::Bool
&& !alignmentProperty.toBool()) {
- d->_q_adjustScrollbars();
+ d->adjustScrollbars();
return;
}
}
@@ -1487,7 +1510,7 @@ void QTextEdit::resizeEvent(QResizeEvent *e)
&& e->oldSize().width() != e->size().width())
d->relayoutDocument();
else
- d->_q_adjustScrollbars();
+ d->adjustScrollbars();
}
void QTextEditPrivate::relayoutDocument()
@@ -1509,7 +1532,7 @@ void QTextEditPrivate::relayoutDocument()
else
lastUsedSize = layout->documentSize().toSize();
- // ignore calls to _q_adjustScrollbars caused by an emission of the
+ // ignore calls to adjustScrollbars caused by an emission of the
// usedSizeChanged() signal in the layout, as we're calling it
// later on our own anyway (or deliberately not) .
const bool oldIgnoreScrollbarAdjustment = ignoreAutomaticScrollbarAdjustment;
@@ -1548,7 +1571,7 @@ void QTextEditPrivate::relayoutDocument()
// its size. So a layout with less width _can_ take up less vertical space, too.
// If the wider case causes a vertical scroll bar to appear and the narrower one
// (narrower because the vertical scroll bar takes up horizontal space)) to disappear
- // again then we have an endless loop, as _q_adjustScrollBars sets new ranges on the
+ // again then we have an endless loop, as adjustScrollbars sets new ranges on the
// scroll bars, the QAbstractScrollArea will find out about it and try to show/hide
// the scroll bars again. That's why we try to detect this case here and break out.
//
@@ -1561,7 +1584,7 @@ void QTextEditPrivate::relayoutDocument()
&& usedSize.height() <= viewport->height())
return;
- _q_adjustScrollbars();
+ adjustScrollbars();
}
void QTextEditPrivate::paint(QPainter *p, QPaintEvent *e)
@@ -1599,6 +1622,8 @@ void QTextEditPrivate::paint(QPainter *p, QPaintEvent *e)
This event handler can be reimplemented in a subclass to receive paint events passed in \a event.
It is usually unnecessary to reimplement this function in a subclass of QTextEdit.
+\note If you create a QPainter, it must operate on the \l{QAbstractScrollArea::}{viewport()}.
+
\warning The underlying text document must not be modified from within a reimplementation
of this function.
*/
@@ -1609,12 +1634,6 @@ void QTextEdit::paintEvent(QPaintEvent *e)
d->paint(&p, e);
}
-void QTextEditPrivate::_q_currentCharFormatChanged(const QTextCharFormat &fmt)
-{
- Q_Q(QTextEdit);
- emit q->currentCharFormatChanged(fmt);
-}
-
void QTextEditPrivate::updateDefaultTextOption()
{
QTextDocument *doc = control->document();
@@ -1805,7 +1824,7 @@ QVariant QTextEdit::inputMethodQuery(Qt::InputMethodQuery query, QVariant argume
Q_D(const QTextEdit);
switch (query) {
case Qt::ImEnabled:
- return isEnabled();
+ return isEnabled() && !isReadOnly();
case Qt::ImHints:
case Qt::ImInputItemClipRectangle:
return QWidget::inputMethodQuery(query);
@@ -2210,7 +2229,7 @@ void QTextEdit::insertFromMimeData(const QMimeData *source)
bool QTextEdit::isReadOnly() const
{
Q_D(const QTextEdit);
- return !(d->control->textInteractionFlags() & Qt::TextEditable);
+ return !d->control || !(d->control->textInteractionFlags() & Qt::TextEditable);
}
void QTextEdit::setReadOnly(bool ro)
@@ -2367,7 +2386,7 @@ void QTextEdit::scrollToAnchor(const QString &name)
QPointF p = d->control->anchorPosition(name);
const int newPosition = qRound(p.y());
if ( d->vbar->maximum() < newPosition )
- d->_q_adjustScrollbars();
+ d->adjustScrollbars();
d->vbar->setValue(newPosition);
}
@@ -2581,11 +2600,14 @@ bool QTextEdit::find(const QString &exp, QTextDocument::FindFlags options)
\overload
Finds the next occurrence, matching the regular expression, \a exp, using the given
- \a options. The QTextDocument::FindCaseSensitively option is ignored for this overload,
- use QRegularExpression::CaseInsensitiveOption instead.
+ \a options.
Returns \c true if a match was found and changes the cursor to select the match;
otherwise returns \c false.
+
+ \warning For historical reasons, the case sensitivity option set on
+ \a exp is ignored. Instead, the \a options are used to determine
+ if the search is case sensitive or not.
*/
#if QT_CONFIG(regularexpression)
bool QTextEdit::find(const QRegularExpression &exp, QTextDocument::FindFlags options)
@@ -2649,10 +2671,7 @@ bool QTextEdit::find(const QRegularExpression &exp, QTextDocument::FindFlags opt
*/
void QTextEdit::setText(const QString &text)
{
- Q_D(QTextEdit);
- Qt::TextFormat format = d->textFormat;
- if (d->textFormat == Qt::AutoText)
- format = Qt::mightBeRichText(text) ? Qt::RichText : Qt::PlainText;
+ Qt::TextFormat format = Qt::mightBeRichText(text) ? Qt::RichText : Qt::PlainText;
#ifndef QT_NO_TEXTHTMLPARSER
if (format == Qt::RichText)
setHtml(text);
diff --git a/src/widgets/widgets/qtextedit.h b/src/widgets/widgets/qtextedit.h
index eed0d4e7e9..421eb9136b 100644
--- a/src/widgets/widgets/qtextedit.h
+++ b/src/widgets/widgets/qtextedit.h
@@ -280,14 +280,6 @@ protected:
private:
Q_DISABLE_COPY(QTextEdit)
- Q_PRIVATE_SLOT(d_func(), void _q_repaintContents(const QRectF &r))
- Q_PRIVATE_SLOT(d_func(), void _q_currentCharFormatChanged(const QTextCharFormat &))
- Q_PRIVATE_SLOT(d_func(), void _q_adjustScrollbars())
- Q_PRIVATE_SLOT(d_func(), void _q_ensureVisible(const QRectF &))
- Q_PRIVATE_SLOT(d_func(), void _q_cursorPositionChanged())
-#if QT_CONFIG(cursor)
- Q_PRIVATE_SLOT(d_func(), void _q_hoveredBlockWithMarkerChanged(const QTextBlock &))
-#endif
friend class QTextEditControl;
friend class QTextDocument;
friend class QWidgetTextControl;
diff --git a/src/widgets/widgets/qtextedit_p.h b/src/widgets/widgets/qtextedit_p.h
index 1200b7470e..7dd7d9c107 100644
--- a/src/widgets/widgets/qtextedit_p.h
+++ b/src/widgets/widgets/qtextedit_p.h
@@ -33,6 +33,8 @@
#include "private/qwidgettextcontrol_p.h"
+#include <array>
+
QT_REQUIRE_CONFIG(textedit);
QT_BEGIN_NAMESPACE
@@ -43,16 +45,17 @@ class QTextEditPrivate : public QAbstractScrollAreaPrivate
Q_DECLARE_PUBLIC(QTextEdit)
public:
QTextEditPrivate();
+ ~QTextEditPrivate();
void init(const QString &html = QString());
void paint(QPainter *p, QPaintEvent *e);
- void _q_repaintContents(const QRectF &contentsRect);
+ void repaintContents(const QRectF &contentsRect);
inline QPoint mapToContents(const QPoint &point) const
{ return QPoint(point.x() + horizontalOffset(), point.y() + verticalOffset()); }
- void _q_adjustScrollbars();
- void _q_ensureVisible(const QRectF &rect);
+ void adjustScrollbars();
+ void ensureVisible(const QRectF &rect);
void relayoutDocument();
void createAutoBulletList();
@@ -66,9 +69,8 @@ public:
inline void sendControlEvent(QEvent *e)
{ control->processEvent(e, QPointF(horizontalOffset(), verticalOffset()), viewport); }
- void _q_currentCharFormatChanged(const QTextCharFormat &format);
- void _q_cursorPositionChanged();
- void _q_hoveredBlockWithMarkerChanged(const QTextBlock &block);
+ void cursorPositionChanged();
+ void hoveredBlockWithMarkerChanged(const QTextBlock &block);
void updateDefaultTextOption();
@@ -94,15 +96,14 @@ public:
uint inDrag : 1;
uint clickCausedFocus : 1;
- // Qt3 COMPAT only, for setText
- Qt::TextFormat textFormat;
-
QString anchorToScrollToWhenVisible;
QString placeholderText;
Qt::CursorShape cursorToRestoreAfterHover = Qt::IBeamCursor;
+ std::array<QMetaObject::Connection, 13> connections;
+
#ifdef QT_KEYPAD_NAVIGATION
QBasicTimer deleteAllTimer;
#endif
diff --git a/src/widgets/widgets/qtoolbar.cpp b/src/widgets/widgets/qtoolbar.cpp
index b5950fdf23..5e5ef8e8d5 100644
--- a/src/widgets/widgets/qtoolbar.cpp
+++ b/src/widgets/widgets/qtoolbar.cpp
@@ -7,6 +7,9 @@
#if QT_CONFIG(combobox)
#include <qcombobox.h>
#endif
+#if QT_CONFIG(draganddrop)
+#include <qdrag.h>
+#endif
#include <qevent.h>
#include <qlayout.h>
#include <qmainwindow.h>
@@ -14,6 +17,7 @@
#if QT_CONFIG(menubar)
#include <qmenubar.h>
#endif
+#include <qmimedata.h>
#if QT_CONFIG(rubberband)
#include <qrubberband.h>
#endif
@@ -40,6 +44,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
// qmainwindow.cpp
extern QMainWindowLayout *qt_mainwindow_layout(const QMainWindow *window);
@@ -105,8 +111,12 @@ void QToolBarPrivate::updateWindowFlags(bool floating, bool unplug)
flags |= Qt::FramelessWindowHint;
- if (unplug)
+#if QT_CONFIG(draganddrop)
+ // If we are performing a platform drag the flag is not needed and we want to avoid recreating
+ // the platform window when it would be removed later
+ if (unplug && !QMainWindowLayout::needsPlatformDrag())
flags |= Qt::X11BypassWindowManagerHint;
+#endif
q->setWindowFlags(flags);
}
@@ -117,8 +127,6 @@ void QToolBarPrivate::setWindowState(bool floating, bool unplug, const QRect &re
bool visible = !q->isHidden();
bool wasFloating = q->isFloating(); // ...is also currently using popup menus
- q->hide();
-
updateWindowFlags(floating, unplug);
if (floating != wasFloating)
@@ -172,12 +180,29 @@ void QToolBarPrivate::startDrag(bool moving)
QMainWindowLayout *layout = qt_mainwindow_layout(win);
Q_ASSERT(layout != nullptr);
+#if QT_CONFIG(draganddrop)
+ const bool wasFloating = q->isFloating();
+#endif
+
if (!moving) {
- state->widgetItem = layout->unplug(q);
+ state->widgetItem = layout->unplug(q, QDockWidgetPrivate::DragScope::Group);
Q_ASSERT(state->widgetItem != nullptr);
}
state->dragging = !moving;
state->moving = moving;
+
+#if QT_CONFIG(draganddrop)
+ if (QMainWindowLayout::needsPlatformDrag() && state->dragging) {
+ auto result = layout->performPlatformWidgetDrag(state->widgetItem, state->pressPos);
+ if (result == Qt::IgnoreAction && !wasFloating) {
+ layout->revert(state->widgetItem);
+ delete state;
+ state = nullptr;
+ } else {
+ endDrag();
+ }
+ }
+#endif
}
void QToolBarPrivate::endDrag()
@@ -243,6 +268,13 @@ bool QToolBarPrivate::mousePressEvent(QMouseEvent *event)
bool QToolBarPrivate::mouseReleaseEvent(QMouseEvent*)
{
+#if QT_CONFIG(draganddrop)
+ // if we are peforming a platform drag ignore the release here and end the drag when the actual
+ // drag ends.
+ if (QMainWindowLayout::needsPlatformDrag())
+ return false;
+#endif
+
if (state != nullptr) {
endDrag();
return true;
@@ -293,6 +325,11 @@ bool QToolBarPrivate::mouseMoveEvent(QMouseEvent *event)
q->grabMouse();
}
+ if (!state) {
+ q->releaseMouse();
+ return true;
+ }
+
if (state->dragging) {
QPoint pos = event->globalPosition().toPoint();
// if we are right-to-left, we move so as to keep the right edge the same distance
@@ -358,6 +395,10 @@ void QToolBarPrivate::plug(const QRect &r)
\ingroup mainwindow-classes
\inmodule QtWidgets
+ A toolbar is typically created by calling
+ \l QMainWindow::addToolBar(const QString &title), but it can also
+ be added as the first widget in a QVBoxLayout, for example.
+
Toolbar buttons are added by adding \e actions, using addAction()
or insertAction(). Groups of buttons can be separated using
addSeparator() or insertSeparator(). If a toolbar button is not
@@ -381,7 +422,7 @@ void QToolBarPrivate::plug(const QRect &r)
addWidget(). Please use widget actions created by inheriting QWidgetAction
and implementing QWidgetAction::createWidget() instead.
- \sa QToolButton, QMenu, QAction, {Qt Widgets - Application Example}
+ \sa QToolButton, QMenu, QAction
*/
/*!
@@ -1043,6 +1084,7 @@ bool QToolBar::event(QEvent *event)
d->layout->setExpanded(false);
break;
}
+ break;
default:
break;
}
diff --git a/src/widgets/widgets/qtoolbarextension.cpp b/src/widgets/widgets/qtoolbarextension.cpp
index 9df3cfbda0..350a900457 100644
--- a/src/widgets/widgets/qtoolbarextension.cpp
+++ b/src/widgets/widgets/qtoolbarextension.cpp
@@ -27,9 +27,9 @@ void QToolBarExtension::setOrientation(Qt::Orientation o)
QStyleOption opt;
opt.initFrom(this);
if (o == Qt::Horizontal) {
- setIcon(style()->standardIcon(QStyle::SP_ToolBarHorizontalExtensionButton, &opt));
+ setIcon(style()->standardIcon(QStyle::SP_ToolBarHorizontalExtensionButton, &opt, this));
} else {
- setIcon(style()->standardIcon(QStyle::SP_ToolBarVerticalExtensionButton, &opt));
+ setIcon(style()->standardIcon(QStyle::SP_ToolBarVerticalExtensionButton, &opt, this));
}
m_orientation = o;
}
@@ -49,7 +49,7 @@ QSize QToolBarExtension::sizeHint() const
{
QStyleOption opt;
opt.initFrom(this);
- const int ext = style()->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt);
+ const int ext = style()->pixelMetric(QStyle::PM_ToolBarExtensionExtent, &opt, this);
return QSize(ext, ext);
}
diff --git a/src/widgets/widgets/qtoolbutton.cpp b/src/widgets/widgets/qtoolbutton.cpp
index e6ec9ec0bc..e0775afd26 100644
--- a/src/widgets/widgets/qtoolbutton.cpp
+++ b/src/widgets/widgets/qtoolbutton.cpp
@@ -39,14 +39,14 @@ class QToolButtonPrivate : public QAbstractButtonPrivate
public:
void init();
#if QT_CONFIG(menu)
- void _q_buttonPressed();
- void _q_buttonReleased();
+ void onButtonPressed();
+ void onButtonReleased();
void popupTimerDone();
- void _q_updateButtonDown();
- void _q_menuTriggered(QAction *);
+ void updateButtonDown();
+ void onMenuTriggered(QAction *);
#endif
bool updateHoverControl(const QPoint &pos);
- void _q_actionTriggered();
+ void onActionTriggered();
QStyle::SubControl newHoverControl(const QPoint &pos);
QStyle::SubControl hoverControl;
QRect hoverRect;
@@ -187,8 +187,10 @@ void QToolButtonPrivate::init()
QSizePolicy::ToolButton));
#if QT_CONFIG(menu)
- QObject::connect(q, SIGNAL(pressed()), q, SLOT(_q_buttonPressed()));
- QObject::connect(q, SIGNAL(released()), q, SLOT(_q_buttonReleased()));
+ QObjectPrivate::connect(q, &QAbstractButton::pressed,
+ this, &QToolButtonPrivate::onButtonPressed);
+ QObjectPrivate::connect(q, &QAbstractButton::released,
+ this, &QToolButtonPrivate::onButtonReleased);
#endif
setLayoutItemMargins(QStyle::SE_ToolButtonLayoutItem);
@@ -435,7 +437,8 @@ void QToolButton::actionEvent(QActionEvent *event)
setDefaultAction(action); // update button state
break;
case QEvent::ActionAdded:
- connect(action, SIGNAL(triggered()), this, SLOT(_q_actionTriggered()));
+ QObjectPrivate::connect(action, &QAction::triggered, d,
+ &QToolButtonPrivate::onActionTriggered);
break;
case QEvent::ActionRemoved:
if (d->defaultAction == action)
@@ -480,7 +483,7 @@ bool QToolButtonPrivate::updateHoverControl(const QPoint &pos)
return !doesHover;
}
-void QToolButtonPrivate::_q_actionTriggered()
+void QToolButtonPrivate::onActionTriggered()
{
Q_Q(QToolButton);
if (QAction *action = qobject_cast<QAction *>(q->sender()))
@@ -581,8 +584,10 @@ void QToolButton::mousePressEvent(QMouseEvent *e)
void QToolButton::mouseReleaseEvent(QMouseEvent *e)
{
Q_D(QToolButton);
+ QPointer<QAbstractButton> guard(this);
QAbstractButton::mouseReleaseEvent(e);
- d->buttonPressed = QToolButtonPrivate::NoButtonPressed;
+ if (guard)
+ d->buttonPressed = QToolButtonPrivate::NoButtonPressed;
}
/*!
@@ -667,7 +672,7 @@ void QToolButton::showMenu()
d->popupTimerDone();
}
-void QToolButtonPrivate::_q_buttonPressed()
+void QToolButtonPrivate::onButtonPressed()
{
Q_Q(QToolButton);
if (!hasMenu())
@@ -680,7 +685,7 @@ void QToolButtonPrivate::_q_buttonPressed()
q->showMenu();
}
-void QToolButtonPrivate::_q_buttonReleased()
+void QToolButtonPrivate::onButtonReleased()
{
popupTimer.stop();
}
@@ -722,8 +727,13 @@ static QPoint positionMenu(const QToolButton *q, bool horizontal,
}
}
}
+
+ // QTBUG-118695 Force point inside the current screen. If the returned point
+ // is not found inside any screen, QMenu's positioning logic kicks in without
+ // taking the QToolButton's screen into account. This can cause the menu to
+ // end up on primary monitor, even if the QToolButton is on a non-primary monitor.
p.rx() = qMax(screen.left(), qMin(p.x(), screen.right() - sh.width()));
- p.ry() += 1;
+ p.ry() = qMax(screen.top(), qMin(p.y() + 1, screen.bottom()));
return p;
}
@@ -757,9 +767,12 @@ void QToolButtonPrivate::popupTimerDone()
#endif
QPointer<QToolButton> that = q;
actualMenu->setNoReplayFor(q);
- if (!mustDeleteActualMenu) //only if action are not in this widget
- QObject::connect(actualMenu, SIGNAL(triggered(QAction*)), q, SLOT(_q_menuTriggered(QAction*)));
- QObject::connect(actualMenu, SIGNAL(aboutToHide()), q, SLOT(_q_updateButtonDown()));
+ if (!mustDeleteActualMenu) { //only if action are not in this widget
+ QObjectPrivate::connect(actualMenu, &QMenu::triggered,
+ this, &QToolButtonPrivate::onMenuTriggered);
+ }
+ QObjectPrivate::connect(actualMenu, &QMenu::aboutToHide,
+ this, &QToolButtonPrivate::updateButtonDown);
actualMenu->d_func()->causedPopup.widget = q;
actualMenu->d_func()->causedPopup.action = defaultAction;
actionsCopy = q->actions(); //(the list of action may be modified in slots)
@@ -773,11 +786,14 @@ void QToolButtonPrivate::popupTimerDone()
if (!that)
return;
- QObject::disconnect(actualMenu, SIGNAL(aboutToHide()), q, SLOT(_q_updateButtonDown()));
- if (mustDeleteActualMenu)
+ QObjectPrivate::disconnect(actualMenu, &QMenu::aboutToHide,
+ this, &QToolButtonPrivate::updateButtonDown);
+ if (mustDeleteActualMenu) {
delete actualMenu;
- else
- QObject::disconnect(actualMenu, SIGNAL(triggered(QAction*)), q, SLOT(_q_menuTriggered(QAction*)));
+ } else {
+ QObjectPrivate::disconnect(actualMenu, &QMenu::triggered,
+ this, &QToolButtonPrivate::onMenuTriggered);
+ }
actionsCopy.clear();
@@ -785,7 +801,7 @@ void QToolButtonPrivate::popupTimerDone()
q->setAutoRepeat(true);
}
-void QToolButtonPrivate::_q_updateButtonDown()
+void QToolButtonPrivate::updateButtonDown()
{
Q_Q(QToolButton);
menuButtonDown = false;
@@ -795,7 +811,7 @@ void QToolButtonPrivate::_q_updateButtonDown()
q->repaint();
}
-void QToolButtonPrivate::_q_menuTriggered(QAction *action)
+void QToolButtonPrivate::onMenuTriggered(QAction *action)
{
Q_Q(QToolButton);
if (action && !actionsCopy.contains(action))
diff --git a/src/widgets/widgets/qtoolbutton.h b/src/widgets/widgets/qtoolbutton.h
index 68b04c42bf..72429620ad 100644
--- a/src/widgets/widgets/qtoolbutton.h
+++ b/src/widgets/widgets/qtoolbutton.h
@@ -89,14 +89,6 @@ protected:
private:
Q_DISABLE_COPY(QToolButton)
Q_DECLARE_PRIVATE(QToolButton)
-#if QT_CONFIG(menu)
- Q_PRIVATE_SLOT(d_func(), void _q_buttonPressed())
- Q_PRIVATE_SLOT(d_func(), void _q_buttonReleased())
- Q_PRIVATE_SLOT(d_func(), void _q_updateButtonDown())
- Q_PRIVATE_SLOT(d_func(), void _q_menuTriggered(QAction*))
-#endif
- Q_PRIVATE_SLOT(d_func(), void _q_actionTriggered())
-
};
QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qwidgetanimator.cpp b/src/widgets/widgets/qwidgetanimator.cpp
index b7abd1f0dc..d45215dee3 100644
--- a/src/widgets/widgets/qwidgetanimator.cpp
+++ b/src/widgets/widgets/qwidgetanimator.cpp
@@ -73,7 +73,8 @@ void QWidgetAnimator::animate(QWidget *widget, const QRect &_final_geometry, boo
anim->setEasingCurve(QEasingCurve::InOutQuad);
anim->setEndValue(final_geometry);
m_animation_map[widget] = anim;
- connect(anim, SIGNAL(finished()), SLOT(animationFinished()));
+ connect(anim, &QPropertyAnimation::finished,
+ this, &QWidgetAnimator::animationFinished);
anim->start(QPropertyAnimation::DeleteWhenStopped);
} else
#endif // animation
diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp
index 4b5d8a237f..ce1b8706ae 100644
--- a/src/widgets/widgets/qwidgetlinecontrol.cpp
+++ b/src/widgets/widgets/qwidgetlinecontrol.cpp
@@ -1638,6 +1638,7 @@ void QWidgetLineControl::processKeyEvent(QKeyEvent* event)
setText(m_completer->currentCompletion());
inlineCompletionAccepted = true;
}
+ break;
default:
break; // normal key processing
}
@@ -1809,13 +1810,18 @@ void QWidgetLineControl::processKeyEvent(QKeyEvent* event)
}
else if (event == QKeySequence::DeleteEndOfWord) {
if (!isReadOnly()) {
- cursorWordForward(true);
- del();
+ if (!hasSelectedText())
+ cursorWordForward(true);
+
+ if (hasSelectedText())
+ del();
}
}
else if (event == QKeySequence::DeleteStartOfWord) {
if (!isReadOnly()) {
- cursorWordBackward(true);
+ if (!hasSelectedText())
+ cursorWordBackward(true);
+
if (hasSelectedText())
del();
}
diff --git a/src/widgets/widgets/qwidgetlinecontrol_p.h b/src/widgets/widgets/qwidgetlinecontrol_p.h
index 838a46fff6..2ce0fe7d94 100644
--- a/src/widgets/widgets/qwidgetlinecontrol_p.h
+++ b/src/widgets/widgets/qwidgetlinecontrol_p.h
@@ -516,6 +516,8 @@ private:
// accessibility events are sent for this object
QObject *m_accessibleObject;
+
+ friend class QLineEdit;
};
QT_END_NAMESPACE
diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp
index a4679402dc..6dcaeee0c8 100644
--- a/src/widgets/widgets/qwidgettextcontrol.cpp
+++ b/src/widgets/widgets/qwidgettextcontrol.cpp
@@ -967,9 +967,12 @@ void QWidgetTextControl::selectAll()
{
Q_D(QWidgetTextControl);
const int selectionLength = qAbs(d->cursor.position() - d->cursor.anchor());
+ const int oldCursorPos = d->cursor.position();
d->cursor.select(QTextCursor::Document);
d->selectionChanged(selectionLength != qAbs(d->cursor.position() - d->cursor.anchor()));
d->cursorIsFocusIndicator = false;
+ if (d->cursor.position() != oldCursorPos)
+ emit cursorPositionChanged();
emit updateRequest();
}
@@ -2032,6 +2035,11 @@ void QWidgetTextControlPrivate::inputMethodEvent(QInputMethodEvent *e)
|| e->preeditString() != cursor.block().layout()->preeditAreaText()
|| e->replacementLength() > 0;
+ if (!isGettingInput && e->attributes().isEmpty()) {
+ e->ignore();
+ return;
+ }
+
int oldCursorPos = cursor.position();
cursor.beginEditBlock();
@@ -2296,7 +2304,7 @@ void QWidgetTextControlPrivate::editFocusEvent(QEvent *e)
#endif
#ifndef QT_NO_CONTEXTMENU
-static inline void setActionIcon(QAction *action, const QString &name)
+void setActionIcon(QAction *action, const QString &name)
{
const QIcon icon = QIcon::fromTheme(name);
if (!icon.isNull())
@@ -2462,7 +2470,7 @@ void QWidgetTextControl::setCursorWidth(int width)
{
Q_D(QWidgetTextControl);
if (width == -1)
- width = QApplication::style()->pixelMetric(QStyle::PM_TextCursorWidth, nullptr);
+ width = QApplication::style()->pixelMetric(QStyle::PM_TextCursorWidth, nullptr, qobject_cast<QWidget *>(parent()));
d->doc->documentLayout()->setProperty("cursorWidth", width);
d->repaintCursor();
}
diff --git a/src/widgets/widgets/qwidgettextcontrol_p.h b/src/widgets/widgets/qwidgettextcontrol_p.h
index 67812dda57..9df4c0c810 100644
--- a/src/widgets/widgets/qwidgettextcontrol_p.h
+++ b/src/widgets/widgets/qwidgettextcontrol_p.h
@@ -276,6 +276,11 @@ private:
mutable QTextDocumentFragment fragment;
};
+#ifndef QT_NO_CONTEXTMENU
+// also used by QLineEdit
+void setActionIcon(QAction *action, const QString &name);
+#endif // QT_NO_CONTEXTMENU
+
QT_END_NAMESPACE
#endif // QWidgetTextControl_H
diff --git a/src/xml/CMakeLists.txt b/src/xml/CMakeLists.txt
index 6c5c0c2755..38b52e3a08 100644
--- a/src/xml/CMakeLists.txt
+++ b/src/xml/CMakeLists.txt
@@ -11,8 +11,10 @@ qt_internal_add_module(Xml
dom/qdomhelpers.cpp dom/qdomhelpers_p.h
qtxmlglobal.h
DEFINES
+ QT_NO_CONTEXTLESS_CONNECT
QT_NO_FOREACH
QT_NO_USING_NAMESPACE
+ QT_USE_NODISCARD_FILE_OPEN
LIBRARIES
Qt::CorePrivate
PUBLIC_LIBRARIES
diff --git a/src/xml/doc/qtxml.qdocconf b/src/xml/doc/qtxml.qdocconf
index 0121cba668..63d934943b 100644
--- a/src/xml/doc/qtxml.qdocconf
+++ b/src/xml/doc/qtxml.qdocconf
@@ -39,5 +39,5 @@ navigation.cppclassespage = "Qt XML C++ Classes"
# Add a thumbnail for examples that do not have images
manifestmeta.thumbnail.names = "QtXml/XML Stream Lint Example"
-# Fail the documentation build if there are more warnings than the limit
+# Enforce zero documentation warnings
warninglimit = 0
diff --git a/src/xml/doc/snippets/CMakeLists.txt b/src/xml/doc/snippets/CMakeLists.txt
index 5aba2d1c3e..57b98440d4 100644
--- a/src/xml/doc/snippets/CMakeLists.txt
+++ b/src/xml/doc/snippets/CMakeLists.txt
@@ -1,5 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
-# SPDX-License-Identifier: BSD-3-Clause
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#! [cmake_use]
find_package(Qt6 REQUIRED COMPONENTS Xml)
diff --git a/src/xml/doc/snippets/code/doc_src_qtxml.qdoc b/src/xml/doc/snippets/code/doc_src_qtxml.qdoc
index 31d260a7ca..b1f24df7e1 100644
--- a/src/xml/doc/snippets/code/doc_src_qtxml.qdoc
+++ b/src/xml/doc/snippets/code/doc_src_qtxml.qdoc
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
//! [3]
<quote>A quotation.</quote>
diff --git a/src/xml/doc/snippets/code/src_xml_dom_qdom.cpp b/src/xml/doc/snippets/code/src_xml_dom_qdom.cpp
index a97a5afcf6..7c7a59745b 100644
--- a/src/xml/doc/snippets/code/src_xml_dom_qdom.cpp
+++ b/src/xml/doc/snippets/code/src_xml_dom_qdom.cpp
@@ -89,17 +89,6 @@ for(QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling())
//! [10]
}
-void FirstElement()
-{
-//! [11]
-QDomDocument doc;
-QDomElement root = doc.firstChildElement("database");
-QDomElement elt = root.firstChildElement("entry");
-for (; !elt.isNull(); elt = elt.nextSiblingElement("entry")) {
- // ...
-}
-//! [11]
-}
void FileContent()
{
diff --git a/src/xml/doc/snippets/code/src_xml_sax_qxml.cpp b/src/xml/doc/snippets/code/src_xml_sax_qxml.cpp
deleted file mode 100644
index f64a6b8b1b..0000000000
--- a/src/xml/doc/snippets/code/src_xml_sax_qxml.cpp
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-//! [0]
-xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
-//! [0]
diff --git a/src/xml/doc/snippets/rsslisting/handler.cpp b/src/xml/doc/snippets/rsslisting/handler.cpp
deleted file mode 100644
index ef2df04653..0000000000
--- a/src/xml/doc/snippets/rsslisting/handler.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-/*
-handler.cpp
-
-Provides a handler for processing XML elements found by the reader.
-
-The handler looks for <title> and <link> elements within <item> elements,
-and records the text found within them. Link information stored within
-rdf:about attributes of <item> elements is also recorded when it is
-available.
-
-For each item found, a signal is emitted which specifies its title and
-link information. This may be used by user interfaces for the purpose of
-displaying items as they are read.
-*/
-
-#include <QtGui>
-
-#include "handler.h"
-
-/*
- Reset the state of the handler to ensure that new documents are
- read correctly.
-
- We return true to indicate that parsing should continue.
-*/
-
-bool Handler::startDocument()
-{
- inItem = false;
- inTitle = false;
- inLink = false;
-
- return true;
-}
-
-/*
- Process each starting element in the XML document.
-
- Nested item, title, or link elements are not allowed, so we return false
- if we encounter any of these. We also prohibit multiple definitions of
- title strings.
-
- Link destinations are read by this function if they are specified as
- attributes in item elements.
-
- For all cases not explicitly checked for, we return true to indicate that
- the element is acceptable, and that parsing should continue. By doing
- this, we can ignore elements in which we are not interested.
-*/
-
-bool Handler::startElement(const QString &, const QString &,
- const QString & qName, const QXmlAttributes &attr)
-{
- if (qName == "item") {
-
- if (inItem)
- return false;
- else {
- inItem = true;
- linkString = attr.value("rdf:about");
- }
- }
- else if (qName == "title") {
-
- if (inTitle)
- return false;
- else if (!titleString.isEmpty())
- return false;
- else if (inItem)
- inTitle = true;
- }
- else if (qName == "link") {
-
- if (inLink)
- return false;
- else if (inItem)
- inLink = true;
- }
-
- return true;
-}
-
-/*
- Process each ending element in the XML document.
-
- For recognized elements, we reset flags to ensure that we can read new
- instances of these elements. If we have read an item element, emit a
- signal to indicate that a new item is available for display.
-
- We return true to indicate that parsing should continue.
-*/
-
-bool Handler::endElement(const QString &, const QString &,
- const QString & qName)
-{
- if (qName == "title" && inTitle)
- inTitle = false;
- else if (qName == "link" && inLink)
- inLink = false;
- else if (qName == "item") {
- if (!titleString.isEmpty() && !linkString.isEmpty())
- emit newItem(titleString, linkString);
- inItem = false;
- titleString = "";
- linkString = "";
- }
-
- return true;
-}
-
-/*
- Collect characters when reading the contents of title or link elements
- when they occur within an item element.
-
- We return true to indicate that parsing should continue.
-*/
-
-bool Handler::characters (const QString &chars)
-{
- if (inTitle)
- titleString += chars;
- else if (inLink)
- linkString += chars;
-
- return true;
-}
-
-/*
- Report a fatal parsing error, and return false to indicate to the reader
- that parsing should stop.
-*/
-
-//! [0]
-bool Handler::fatalError (const QXmlParseException & exception)
-{
- qWarning() << "Fatal error on line" << exception.lineNumber()
- << ", column" << exception.columnNumber() << ':'
- << exception.message();
-
- return false;
-}
-//! [0]
diff --git a/src/xml/doc/snippets/rsslisting/listing.cpp b/src/xml/doc/snippets/rsslisting/listing.cpp
deleted file mode 100644
index d7fd28d56c..0000000000
--- a/src/xml/doc/snippets/rsslisting/listing.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-
-/*
-rsslisting.cpp
-
-Provides a widget for displaying news items from RDF news sources.
-RDF is an XML-based format for storing items of information (see
-http://www.w3.org/RDF/ for details).
-
-The widget itself provides a simple user interface for specifying
-the URL of a news source, and controlling the downloading of news.
-
-The widget downloads and parses the XML asynchronously, feeding the
-data to an XML reader in pieces. This allows the user to interrupt
-its operation, and also allows very large data sources to be read.
-*/
-
-
-#include <QtCore>
-#include <QtGui>
-#include <QtNetwork>
-#include <QtXml>
-
-#include "rsslisting.h"
-
-
-/*
- Constructs an RSSListing widget with a simple user interface, and sets
- up the XML reader to use a custom handler class.
-
- The user interface consists of a line edit, two push buttons, and a
- list view widget. The line edit is used for entering the URLs of news
- sources; the push buttons start and abort the process of reading the
- news.
-*/
-
-RSSListing::RSSListing(QWidget *parent)
- : QWidget(parent)
-{
- lineEdit = new QLineEdit(this);
-
- fetchButton = new QPushButton(tr("Fetch"), this);
- abortButton = new QPushButton(tr("Abort"), this);
- abortButton->setEnabled(false);
-
- treeWidget = new QTreeWidget(this);
- QStringList headerLabels;
- headerLabels << tr("Title") << tr("Link");
- treeWidget->setHeaderLabels(headerLabels);
-
- handler = 0;
-
- connect(&http, SIGNAL(readyRead(QHttpResponseHeader)),
- this, SLOT(readData(QHttpResponseHeader)));
-
- connect(&http, SIGNAL(requestFinished(int,bool)),
- this, SLOT(finished(int,bool)));
-
- connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(fetch()));
- connect(fetchButton, SIGNAL(clicked()), this, SLOT(fetch()));
- connect(abortButton, SIGNAL(clicked()), &http, SLOT(abort()));
-
- QVBoxLayout *layout = new QVBoxLayout(this);
-
- QHBoxLayout *hboxLayout = new QHBoxLayout;
-
- hboxLayout->addWidget(lineEdit);
- hboxLayout->addWidget(fetchButton);
- hboxLayout->addWidget(abortButton);
-
- layout->addLayout(hboxLayout);
- layout->addWidget(treeWidget);
-
- setWindowTitle(tr("RSS listing example"));
-}
-
-/*
- Starts fetching data from a news source specified in the line
- edit widget.
-
- The line edit is made read only to prevent the user from modifying its
- contents during the fetch; this is only for cosmetic purposes.
- The fetch button is disabled, and the abort button is enabled to allow
- the user to interrupt processing. The list view is cleared, and we
- define the last list view item to be 0, meaning that there are no
- existing items in the list.
-
- We reset the flag used to determine whether parsing should begin again
- or continue. A new handler is created, if required, and made available
- to the reader.
-
- The HTTP handler is supplied with the raw contents of the line edit and
- a fetch is initiated. We keep the ID value returned by the HTTP handler
- for future reference.
-*/
-
-void RSSListing::fetch()
-{
- lineEdit->setReadOnly(true);
- fetchButton->setEnabled(false);
- abortButton->setEnabled(true);
- treeWidget->clear();
-
- lastItemCreated = 0;
-
- newInformation = true;
-
- if (handler != 0)
- delete handler;
- handler = new Handler;
-
-//! [0]
- xmlReader.setContentHandler(handler);
- xmlReader.setErrorHandler(handler);
-//! [0]
-
- connect(handler, SIGNAL(newItem(QString&,QString&)),
- this, SLOT(addItem(QString&,QString&)));
-
- QUrl url(lineEdit->text());
-
- http.setHost(url.host());
- connectionId = http.get(url.path());
-}
-
-/*
- Reads data received from the RDF source.
-
- We read all the available data, and pass it to the XML
- input source. The first time we receive new information,
- the reader is set up for a new incremental parse;
- we continue parsing using a different function on
- subsequent calls involving the same data source.
-
- If parsing fails for any reason, we abort the fetch.
-*/
-
-//! [1]
-void RSSListing::readData(const QHttpResponseHeader &resp)
-{
- bool ok;
-
- if (resp.statusCode() != 200)
- http.abort();
- else {
- xmlInput.setData(http.readAll());
-
- if (newInformation) {
- ok = xmlReader.parse(&xmlInput, true);
- newInformation = false;
- }
- else
- ok = xmlReader.parseContinue();
-
- if (!ok)
- http.abort();
- }
-}
-//! [1]
-
-/*
- Finishes processing an HTTP request.
-
- The default behavior is to keep the text edit read only.
-
- If an error has occurred, the user interface is made available
- to the user for further input, allowing a new fetch to be
- started.
-
- If the HTTP get request has finished, we perform a final
- parsing operation on the data returned to ensure that it was
- well-formed. Whether this is successful or not, we make the
- user interface available to the user for further input.
-*/
-
-void RSSListing::finished(int id, bool error)
-{
- if (error) {
- qWarning("Received error during HTTP fetch.");
- lineEdit->setReadOnly(false);
- abortButton->setEnabled(false);
- fetchButton->setEnabled(true);
- }
- else if (id == connectionId) {
-
- bool ok = xmlReader.parseContinue();
- if (!ok)
- qWarning("Parse error at the end of input.");
-
- lineEdit->setReadOnly(false);
- abortButton->setEnabled(false);
- fetchButton->setEnabled(true);
- }
-}
-
-/*
- Adds an item to the list view as it is reported by the handler.
-
- We keep a record of the last item created to ensure that the
- items are created in sequence.
-*/
-
-void RSSListing::addItem(QString &title, QString &link)
-{
- QTreeWidgetItem *item;
-
- item = new QTreeWidgetItem(treeWidget, lastItemCreated);
- item->setText(0, title);
- item->setText(1, link);
-
- lastItemCreated = item;
-}
-
diff --git a/src/xml/doc/src/qt6-changes.qdoc b/src/xml/doc/src/qt6-changes.qdoc
index cca6aa9317..f3ff82130a 100644
--- a/src/xml/doc/src/qt6-changes.qdoc
+++ b/src/xml/doc/src/qt6-changes.qdoc
@@ -5,7 +5,7 @@
\page xml-changes-qt6.html
\title Changes to Qt XML
\ingroup changes-qt-5-to-6
- \brief Migrate Qt XML to Qt 6.
+ \brief Use QXmlStreamReader for reading XML files.
Qt 6 is a result of the conscious effort to make the framework more
efficient and easy to use.
diff --git a/src/xml/doc/src/qtxml-index.qdoc b/src/xml/doc/src/qtxml-index.qdoc
index d6a7defb20..7ad55350a5 100644
--- a/src/xml/doc/src/qtxml-index.qdoc
+++ b/src/xml/doc/src/qtxml-index.qdoc
@@ -4,11 +4,9 @@
/*!
\page qtxml-index.html
\title Qt XML
- \brief The Qt XML module provides C++ implementations of the SAX and DOM standards for XML.
+ \brief The Qt XML module provides a C++ implementation of the DOM standard for XML.
-
- The Qt XML module provides implementations of the SAX and DOM standards for
- XML.
+ The Qt XML module provides an implementation of the DOM standard for XML.
\note Qt XML will no longer receive additional features. For reading or
writing XML documents iteratively (SAX), use the QXmlStreamReader and
diff --git a/src/xml/doc/src/qtxml.qdoc b/src/xml/doc/src/qtxml.qdoc
index f0e2d5f9b7..76394392be 100644
--- a/src/xml/doc/src/qtxml.qdoc
+++ b/src/xml/doc/src/qtxml.qdoc
@@ -8,7 +8,7 @@
\qtcmakepackage Xml
\qtvariable xml
- \brief The Qt XML module provides C++ implementations of the SAX and DOM standards for XML.
+ \brief The Qt XML module provides a C++ implementation of the DOM standard for XML.
The \l{Qt XML} page contains information about how to use the module.
diff --git a/src/xml/doc/src/xml-processing.qdoc b/src/xml/doc/src/xml-processing.qdoc
index b98749ca41..acca1b070b 100644
--- a/src/xml/doc/src/xml-processing.qdoc
+++ b/src/xml/doc/src/xml-processing.qdoc
@@ -7,7 +7,7 @@
\brief Classes that support XML.
- These classes are relevant to XML users.
+ These classes are relevant to \l{XML Processing}{XML} users.
\generatelist{related}
*/
@@ -15,6 +15,7 @@
/*!
\page xml-processing.html
\title XML Processing
+ \ingroup explanations-dataprocessingandio
\brief An Overview of the XML processing facilities in Qt.
@@ -180,7 +181,7 @@
namespace prefix. In this case the local part and the qualified name
are identical (i.e. \e chapter).
- \sa {DOM Bookmarks Example}
+ \sa {DOM Bookmarks Application}
*/
/*!
@@ -191,7 +192,8 @@
\nextpage Working with the DOM Tree
Qt provides two classes for reading and writing XML through a simple streaming
- API: QXmlStreamReader and QXmlStreamWriter.
+ API: QXmlStreamReader and QXmlStreamWriter. These classes are located in
+ \l{Qt Serialization}{Qt Serialization (part of QtCore)}.
A stream reader reports an XML document as a stream
of tokens. This differs from SAX as SAX applications provide handlers to
@@ -207,27 +209,14 @@
\l{QXmlStreamReader::error()}{error()} and \l{QXmlStreamReader::hasError()}
{hasError()} can be used to check and view the errors.
- An example of QXmlStreamReader implementation would be the \c XbelReader in
- \l{QXmlStream Bookmarks Example}, which wraps a QXmlStreamReader.
- The constructor takes \a treeWidget as a parameter and the class has Xbel
- specific functions:
-
- \snippet streambookmarks/xbelreader.h 1
-
- \dots
- \snippet streambookmarks/xbelreader.h 2
- \dots
+ An example of an implementation tha uses QXmlStreamReader would be the
+ \l{QXmlStream Bookmarks Example#xbelreader-class-definition}{XbelReader} in
+ \l{QXmlStream Bookmarks Example}, which wraps a QXmlStreamReader. Read the
+ \l{QXmlStream Bookmarks Example#xbelreader-class-implementation}{implementation}
+ to learn more about how to use the QXmlStreamReader class.
- The \c read() function accepts a QIODevice and sets it with
- \l{QXmlStreamReader::setDevice()}{setDevice()}. The
- \l{QXmlStreamReader::raiseError()}{raiseError()} function is used to
- display a custom error message, inidicating that the file's version
- is incorrect.
-
- \snippet streambookmarks/xbelreader.cpp 1
-
- The pendent to QXmlStreamReader is QXmlStreamWriter, which provides an XML
- writer with a simple streaming API. QXmlStreamWriter operates on a
+ Paired with QXmlStreamReader is the QXmlStreamWriter class, which provides
+ an XML writer with a simple streaming API. QXmlStreamWriter operates on a
QIODevice and has specialized functions for all XML tokens or events you
want to write, such as \l{QXmlStreamWriter::writeDTD()}{writeDTD()},
\l{QXmlStreamWriter::writeCharacters()}{writeCharacters()},
@@ -253,11 +242,10 @@
or subsequent calls to \l{QXmlStreamWriter::writeStartElement()}
{writeStartElement()}.
- The \c XbelWriter class from \l{QXmlStream Bookmarks Example} wraps a
- QXmlStreamWriter. Its \c writeFile() function illustrates the core
- functions of QXmlStreamWriter mentioned above:
-
- \snippet streambookmarks/xbelwriter.cpp 1
+ The \l{QXmlStream Bookmarks Example#xbelwriter-class-definition}{XbelWriter}
+ class from \l{QXmlStream Bookmarks Example} wraps a QXmlStreamWriter. View
+ the \l{QXmlStream Bookmarks Example#xbelwriter-class-implementation}{implementation}
+ to see how to use the QXmlStreamWriter class.
*/
/*!
@@ -352,7 +340,7 @@
DOM implementation.
To get started please refer to the \l QDomDocument documentation.
- You might also want to take a look at the \l{DOM Bookmarks Example},
+ You might also want to take a look at the \l{DOM Bookmarks Application},
which illustrates how to read and write an XML bookmark file (XBEL)
using DOM.
*/
diff --git a/src/xml/dom/qdom.cpp b/src/xml/dom/qdom.cpp
index 5928255778..b25cdf487f 100644
--- a/src/xml/dom/qdom.cpp
+++ b/src/xml/dom/qdom.cpp
@@ -47,7 +47,7 @@ using namespace Qt::StringLiterals;
/* ##### new TODOs:
- Remove empty emthods in the *Private classes
+ Remove empty methods in the *Private classes
Make a lot of the (mostly empty) methods in the public classes inline.
Specially constructors assignment operators and comparison operators are candidates.
@@ -374,52 +374,52 @@ QDomImplementation::QDomImplementation()
}
/*!
- Constructs a copy of \a x.
+ Constructs a copy of \a implementation.
*/
-QDomImplementation::QDomImplementation(const QDomImplementation &x)
+QDomImplementation::QDomImplementation(const QDomImplementation &implementation)
+ : impl(implementation.impl)
{
- impl = x.impl;
if (impl)
impl->ref.ref();
}
-QDomImplementation::QDomImplementation(QDomImplementationPrivate *p)
+QDomImplementation::QDomImplementation(QDomImplementationPrivate *pimpl)
+ : impl(pimpl)
{
// We want to be co-owners, so increase the reference count
- impl = p;
if (impl)
impl->ref.ref();
}
/*!
- Assigns \a x to this DOM implementation.
+ Assigns \a other to this DOM implementation.
*/
-QDomImplementation& QDomImplementation::operator=(const QDomImplementation &x)
+QDomImplementation& QDomImplementation::operator=(const QDomImplementation &other)
{
- if (x.impl)
- x.impl->ref.ref();
+ if (other.impl)
+ other.impl->ref.ref();
if (impl && !impl->ref.deref())
delete impl;
- impl = x.impl;
+ impl = other.impl;
return *this;
}
/*!
- Returns \c true if \a x and this DOM implementation object were
+ Returns \c true if \a other and this DOM implementation object were
created from the same QDomDocument; otherwise returns \c false.
*/
-bool QDomImplementation::operator==(const QDomImplementation &x) const
+bool QDomImplementation::operator==(const QDomImplementation &other) const
{
- return (impl == x.impl);
+ return impl == other.impl;
}
/*!
- Returns \c true if \a x and this DOM implementation object were
+ Returns \c true if \a other and this DOM implementation object were
created from different QDomDocuments; otherwise returns \c false.
*/
-bool QDomImplementation::operator!=(const QDomImplementation &x) const
+bool QDomImplementation::operator!=(const QDomImplementation &other) const
{
- return (impl != x.impl);
+ return !operator==(other);
}
/*!
@@ -646,10 +646,10 @@ bool QDomNodeListPrivate::operator==(const QDomNodeListPrivate &other) const
bool QDomNodeListPrivate::operator!=(const QDomNodeListPrivate &other) const
{
- return (node_impl != other.node_impl) || (tagname != other.tagname);
+ return !operator==(other);
}
-void QDomNodeListPrivate::createList()
+void QDomNodeListPrivate::createList() const
{
if (!node_impl)
return;
@@ -703,16 +703,21 @@ void QDomNodeListPrivate::createList()
}
}
-QDomNodePrivate* QDomNodeListPrivate::item(int index)
+bool QDomNodeListPrivate::maybeCreateList() const
{
if (!node_impl)
- return nullptr;
+ return false;
const QDomDocumentPrivate *const doc = node_impl->ownerDocument();
if (!doc || timestamp != doc->nodeListTime)
createList();
- if (index >= list.size())
+ return true;
+}
+
+QDomNodePrivate *QDomNodeListPrivate::item(int index)
+{
+ if (!maybeCreateList() || index >= list.size() || index < 0)
return nullptr;
return list.at(index);
@@ -720,15 +725,9 @@ QDomNodePrivate* QDomNodeListPrivate::item(int index)
int QDomNodeListPrivate::length() const
{
- if (!node_impl)
+ if (!maybeCreateList())
return 0;
- const QDomDocumentPrivate *const doc = node_impl->ownerDocument();
- if (!doc || timestamp != doc->nodeListTime) {
- QDomNodeListPrivate *that = const_cast<QDomNodeListPrivate *>(this);
- that->createList();
- }
-
return list.size();
}
@@ -771,54 +770,54 @@ QDomNodeList::QDomNodeList()
{
}
-QDomNodeList::QDomNodeList(QDomNodeListPrivate* p)
- : impl(p)
+QDomNodeList::QDomNodeList(QDomNodeListPrivate *pimpl)
+ : impl(pimpl)
{
}
/*!
- Constructs a copy of \a n.
+ Constructs a copy of \a nodeList.
*/
-QDomNodeList::QDomNodeList(const QDomNodeList& n)
+QDomNodeList::QDomNodeList(const QDomNodeList &nodeList)
+ : impl(nodeList.impl)
{
- impl = n.impl;
if (impl)
impl->ref.ref();
}
/*!
- Assigns \a n to this node list.
+ Assigns \a other to this node list.
*/
-QDomNodeList& QDomNodeList::operator=(const QDomNodeList &n)
+QDomNodeList& QDomNodeList::operator=(const QDomNodeList &other)
{
- if (n.impl)
- n.impl->ref.ref();
+ if (other.impl)
+ other.impl->ref.ref();
if (impl && !impl->ref.deref())
delete impl;
- impl = n.impl;
+ impl = other.impl;
return *this;
}
/*!
- Returns \c true if the node list \a n and this node list are equal;
+ Returns \c true if the node list \a other and this node list are equal;
otherwise returns \c false.
*/
-bool QDomNodeList::operator==(const QDomNodeList &n) const
+bool QDomNodeList::operator==(const QDomNodeList &other) const
{
- if (impl == n.impl)
+ if (impl == other.impl)
return true;
- if (!impl || !n.impl)
+ if (!impl || !other.impl)
return false;
- return (*impl == *n.impl);
+ return (*impl == *other.impl);
}
/*!
- Returns \c true the node list \a n and this node list are not equal;
+ Returns \c true the node list \a other and this node list are not equal;
otherwise returns \c false.
*/
-bool QDomNodeList::operator!=(const QDomNodeList &n) const
+bool QDomNodeList::operator!=(const QDomNodeList &other) const
{
- return !operator==(n);
+ return !operator==(other);
}
/*!
@@ -1474,48 +1473,48 @@ QDomNode::QDomNode()
}
/*!
- Constructs a copy of \a n.
+ Constructs a copy of \a node.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomNode::QDomNode(const QDomNode &n)
+QDomNode::QDomNode(const QDomNode &node)
+ : impl(node.impl)
{
- impl = n.impl;
if (impl)
impl->ref.ref();
}
/*! \internal
- Constructs a new node for the data \a n.
+ Constructs a new node for the data \a pimpl.
*/
-QDomNode::QDomNode(QDomNodePrivate *n)
+QDomNode::QDomNode(QDomNodePrivate *pimpl)
+ : impl(pimpl)
{
- impl = n;
if (impl)
impl->ref.ref();
}
/*!
- Assigns a copy of \a n to this DOM node.
+ Assigns a copy of \a other to this DOM node.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomNode& QDomNode::operator=(const QDomNode &n)
+QDomNode& QDomNode::operator=(const QDomNode &other)
{
- if (n.impl)
- n.impl->ref.ref();
+ if (other.impl)
+ other.impl->ref.ref();
if (impl && !impl->ref.deref())
delete impl;
- impl = n.impl;
+ impl = other.impl;
return *this;
}
/*!
- Returns \c true if \a n and this DOM node are equal; otherwise
+ Returns \c true if \a other and this DOM node are equal; otherwise
returns \c false.
Any instance of QDomNode acts as a reference to an underlying data
@@ -1534,18 +1533,18 @@ QDomNode& QDomNode::operator=(const QDomNode &n)
\c {element3 == element4} will return false because they refer to
two different nodes in the underlying data structure.
*/
-bool QDomNode::operator== (const QDomNode& n) const
+bool QDomNode::operator==(const QDomNode &other) const
{
- return (impl == n.impl);
+ return impl == other.impl;
}
/*!
- Returns \c true if \a n and this DOM node are not equal; otherwise
+ Returns \c true if \a other and this DOM node are not equal; otherwise
returns \c false.
*/
-bool QDomNode::operator!= (const QDomNode& n) const
+bool QDomNode::operator!=(const QDomNode &other) const
{
- return (impl != n.impl);
+ return !operator==(other);
}
/*!
@@ -1622,15 +1621,14 @@ QString QDomNode::nodeValue() const
}
/*!
- Sets the node's value to \a v.
+ Sets the node's value to \a value.
\sa nodeValue()
*/
-void QDomNode::setNodeValue(const QString& v)
+void QDomNode::setNodeValue(const QString& value)
{
- if (!impl)
- return;
- IMPL->setNodeValue(v);
+ if (impl)
+ IMPL->setNodeValue(value);
}
/*!
@@ -2504,11 +2502,12 @@ int QDomNode::columnNumber() const
*
**************************************************************/
-QDomNamedNodeMapPrivate::QDomNamedNodeMapPrivate(QDomNodePrivate* n) : ref(1)
+QDomNamedNodeMapPrivate::QDomNamedNodeMapPrivate(QDomNodePrivate *pimpl)
+ : ref(1)
+ , parent(pimpl)
+ , readonly(false)
+ , appendToParent(false)
{
- readonly = false;
- parent = n;
- appendToParent = false;
}
QDomNamedNodeMapPrivate::~QDomNamedNodeMapPrivate()
@@ -2516,16 +2515,16 @@ QDomNamedNodeMapPrivate::~QDomNamedNodeMapPrivate()
clearMap();
}
-QDomNamedNodeMapPrivate* QDomNamedNodeMapPrivate::clone(QDomNodePrivate* p)
+QDomNamedNodeMapPrivate* QDomNamedNodeMapPrivate::clone(QDomNodePrivate *pimpl)
{
- std::unique_ptr<QDomNamedNodeMapPrivate> m(new QDomNamedNodeMapPrivate(p));
+ std::unique_ptr<QDomNamedNodeMapPrivate> m(new QDomNamedNodeMapPrivate(pimpl));
m->readonly = readonly;
m->appendToParent = appendToParent;
auto it = map.constBegin();
for (; it != map.constEnd(); ++it) {
QDomNodePrivate *new_node = it.value()->cloneNode();
- new_node->setParent(p);
+ new_node->setParent(pimpl);
m->setNamedItem(new_node);
}
@@ -2697,51 +2696,51 @@ QDomNamedNodeMap::QDomNamedNodeMap()
}
/*!
- Constructs a copy of \a n.
+ Constructs a copy of \a namedNodeMap.
*/
-QDomNamedNodeMap::QDomNamedNodeMap(const QDomNamedNodeMap &n)
+QDomNamedNodeMap::QDomNamedNodeMap(const QDomNamedNodeMap &namedNodeMap)
+ : impl(namedNodeMap.impl)
{
- impl = n.impl;
if (impl)
impl->ref.ref();
}
-QDomNamedNodeMap::QDomNamedNodeMap(QDomNamedNodeMapPrivate *n)
+QDomNamedNodeMap::QDomNamedNodeMap(QDomNamedNodeMapPrivate *pimpl)
+ : impl(pimpl)
{
- impl = n;
if (impl)
impl->ref.ref();
}
/*!
- Assigns \a n to this named node map.
+ Assigns \a other to this named node map.
*/
-QDomNamedNodeMap& QDomNamedNodeMap::operator=(const QDomNamedNodeMap &n)
+QDomNamedNodeMap& QDomNamedNodeMap::operator=(const QDomNamedNodeMap &other)
{
- if (n.impl)
- n.impl->ref.ref();
+ if (other.impl)
+ other.impl->ref.ref();
if (impl && !impl->ref.deref())
delete impl;
- impl = n.impl;
+ impl = other.impl;
return *this;
}
/*!
- Returns \c true if \a n and this named node map are equal; otherwise
+ Returns \c true if \a other and this named node map are equal; otherwise
returns \c false.
*/
-bool QDomNamedNodeMap::operator== (const QDomNamedNodeMap& n) const
+bool QDomNamedNodeMap::operator==(const QDomNamedNodeMap &other) const
{
- return (impl == n.impl);
+ return impl == other.impl;
}
/*!
- Returns \c true if \a n and this named node map are not equal;
+ Returns \c true if \a other and this named node map are not equal;
otherwise returns \c false.
*/
-bool QDomNamedNodeMap::operator!= (const QDomNamedNodeMap& n) const
+bool QDomNamedNodeMap::operator!=(const QDomNamedNodeMap &other) const
{
- return (impl != n.impl);
+ return !operator==(other);
}
/*!
@@ -3117,30 +3116,30 @@ QDomDocumentType::QDomDocumentType() : QDomNode()
}
/*!
- Constructs a copy of \a n.
+ Constructs a copy of \a documentType.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomDocumentType::QDomDocumentType(const QDomDocumentType& n)
- : QDomNode(n)
+QDomDocumentType::QDomDocumentType(const QDomDocumentType &documentType)
+ : QDomNode(documentType)
{
}
-QDomDocumentType::QDomDocumentType(QDomDocumentTypePrivate* n)
- : QDomNode(n)
+QDomDocumentType::QDomDocumentType(QDomDocumentTypePrivate *pimpl)
+ : QDomNode(pimpl)
{
}
/*!
- Assigns \a n to this document type.
+ Assigns \a other to this document type.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomDocumentType &QDomDocumentType::operator=(const QDomDocumentType &n) = default;
+QDomDocumentType &QDomDocumentType::operator=(const QDomDocumentType &other) = default;
/*!
Returns the name of the document type as specified in the
&lt;!DOCTYPE name&gt; tag.
@@ -3298,25 +3297,25 @@ QDomDocumentFragment::QDomDocumentFragment(QDomDocumentFragmentPrivate* n)
}
/*!
- Constructs a copy of \a x.
+ Constructs a copy of \a documentFragment.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomDocumentFragment::QDomDocumentFragment(const QDomDocumentFragment& x)
- : QDomNode(x)
+QDomDocumentFragment::QDomDocumentFragment(const QDomDocumentFragment &documentFragment)
+ : QDomNode(documentFragment)
{
}
/*!
- Assigns \a x to this DOM document fragment.
+ Assigns \a other to this DOM document fragment.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomDocumentFragment &QDomDocumentFragment::operator=(const QDomDocumentFragment &x) = default;
+QDomDocumentFragment &QDomDocumentFragment::operator=(const QDomDocumentFragment &other) = default;
/*!
\fn QDomNode::NodeType QDomDocumentFragment::nodeType() const
@@ -3424,14 +3423,14 @@ QDomCharacterData::QDomCharacterData()
}
/*!
- Constructs a copy of \a x.
+ Constructs a copy of \a characterData.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomCharacterData::QDomCharacterData(const QDomCharacterData& x)
- : QDomNode(x)
+QDomCharacterData::QDomCharacterData(const QDomCharacterData &characterData)
+ : QDomNode(characterData)
{
}
@@ -3441,13 +3440,13 @@ QDomCharacterData::QDomCharacterData(QDomCharacterDataPrivate* n)
}
/*!
- Assigns \a x to this character data.
+ Assigns \a other to this character data.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomCharacterData &QDomCharacterData::operator=(const QDomCharacterData &x) = default;
+QDomCharacterData &QDomCharacterData::operator=(const QDomCharacterData &other) = default;
/*!
Returns the string stored in this object.
@@ -3463,12 +3462,12 @@ QString QDomCharacterData::data() const
}
/*!
- Sets this object's string to \a v.
+ Sets this object's string to \a data.
*/
-void QDomCharacterData::setData(const QString& v)
+void QDomCharacterData::setData(const QString &data)
{
if (impl)
- impl->setNodeValue(v);
+ impl->setNodeValue(data);
}
/*!
@@ -3730,14 +3729,14 @@ QDomAttr::QDomAttr()
}
/*!
- Constructs a copy of \a x.
+ Constructs a copy of \a attr.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomAttr::QDomAttr(const QDomAttr& x)
- : QDomNode(x)
+QDomAttr::QDomAttr(const QDomAttr &attr)
+ : QDomNode(attr)
{
}
@@ -3747,13 +3746,13 @@ QDomAttr::QDomAttr(QDomAttrPrivate* n)
}
/*!
- Assigns \a x to this DOM attribute.
+ Assigns \a other to this DOM attribute.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomAttr &QDomAttr::operator=(const QDomAttr &x) = default;
+QDomAttr &QDomAttr::operator=(const QDomAttr &other) = default;
/*!
Returns the attribute's name.
@@ -3805,15 +3804,15 @@ QString QDomAttr::value() const
}
/*!
- Sets the attribute's value to \a v.
+ Sets the attribute's value to \a value.
\sa value()
*/
-void QDomAttr::setValue(const QString& v)
+void QDomAttr::setValue(const QString &value)
{
if (!impl)
return;
- impl->setNodeValue(v);
+ impl->setNodeValue(value);
IMPL->m_specified = true;
}
@@ -4201,14 +4200,14 @@ QDomElement::QDomElement()
}
/*!
- Constructs a copy of \a x.
+ Constructs a copy of \a element.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomElement::QDomElement(const QDomElement& x)
- : QDomNode(x)
+QDomElement::QDomElement(const QDomElement &element)
+ : QDomNode(element)
{
}
@@ -4218,13 +4217,13 @@ QDomElement::QDomElement(QDomElementPrivate* n)
}
/*!
- Assigns \a x to this DOM element.
+ Assigns \a other to this DOM element.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomElement &QDomElement::operator=(const QDomElement &x) = default;
+QDomElement &QDomElement::operator=(const QDomElement &other) = default;
/*!
\fn QDomNode::NodeType QDomElement::nodeType() const
@@ -4671,6 +4670,10 @@ QDomTextPrivate* QDomTextPrivate::splitText(int offset)
value.truncate(offset);
parent()->insertAfter(t, this);
+ Q_ASSERT(t->ref.loadRelaxed() == 2);
+
+ // We are not interested in this node
+ t->ref.deref();
return t;
}
@@ -4718,14 +4721,14 @@ QDomText::QDomText()
}
/*!
- Constructs a copy of \a x.
+ Constructs a copy of \a text.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomText::QDomText(const QDomText& x)
- : QDomCharacterData(x)
+QDomText::QDomText(const QDomText &text)
+ : QDomCharacterData(text)
{
}
@@ -4735,13 +4738,13 @@ QDomText::QDomText(QDomTextPrivate* n)
}
/*!
- Assigns \a x to this DOM text.
+ Assigns \a other to this DOM text.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomText &QDomText::operator=(const QDomText &x) = default;
+QDomText &QDomText::operator=(const QDomText &other) = default;
/*!
\fn QDomNode::NodeType QDomText::nodeType() const
@@ -4846,14 +4849,14 @@ QDomComment::QDomComment()
}
/*!
- Constructs a copy of \a x.
+ Constructs a copy of \a comment.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomComment::QDomComment(const QDomComment& x)
- : QDomCharacterData(x)
+QDomComment::QDomComment(const QDomComment &comment)
+ : QDomCharacterData(comment)
{
}
@@ -4863,13 +4866,13 @@ QDomComment::QDomComment(QDomCommentPrivate* n)
}
/*!
- Assigns \a x to this DOM comment.
+ Assigns \a other to this DOM comment.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomComment &QDomComment::operator=(const QDomComment &x) = default;
+QDomComment &QDomComment::operator=(const QDomComment &other) = default;
/*!
\fn QDomNode::NodeType QDomComment::nodeType() const
@@ -4951,14 +4954,14 @@ QDomCDATASection::QDomCDATASection()
}
/*!
- Constructs a copy of \a x.
+ Constructs a copy of \a cdataSection.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomCDATASection::QDomCDATASection(const QDomCDATASection& x)
- : QDomText(x)
+QDomCDATASection::QDomCDATASection(const QDomCDATASection &cdataSection)
+ : QDomText(cdataSection)
{
}
@@ -4968,13 +4971,13 @@ QDomCDATASection::QDomCDATASection(QDomCDATASectionPrivate* n)
}
/*!
- Assigns \a x to this CDATA section.
+ Assigns \a other to this CDATA section.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomCDATASection &QDomCDATASection::operator=(const QDomCDATASection &x) = default;
+QDomCDATASection &QDomCDATASection::operator=(const QDomCDATASection &other) = default;
/*!
\fn QDomNode::NodeType QDomCDATASection::nodeType() const
@@ -5072,14 +5075,14 @@ QDomNotation::QDomNotation()
}
/*!
- Constructs a copy of \a x.
+ Constructs a copy of \a notation.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomNotation::QDomNotation(const QDomNotation& x)
- : QDomNode(x)
+QDomNotation::QDomNotation(const QDomNotation &notation)
+ : QDomNode(notation)
{
}
@@ -5089,13 +5092,13 @@ QDomNotation::QDomNotation(QDomNotationPrivate* n)
}
/*!
- Assigns \a x to this DOM notation.
+ Assigns \a other to this DOM notation.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomNotation &QDomNotation::operator=(const QDomNotation &x) = default;
+QDomNotation &QDomNotation::operator=(const QDomNotation &other) = default;
/*!
\fn QDomNode::NodeType QDomNotation::nodeType() const
@@ -5266,14 +5269,14 @@ QDomEntity::QDomEntity()
/*!
- Constructs a copy of \a x.
+ Constructs a copy of \a entity.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomEntity::QDomEntity(const QDomEntity& x)
- : QDomNode(x)
+QDomEntity::QDomEntity(const QDomEntity &entity)
+ : QDomNode(entity)
{
}
@@ -5283,13 +5286,13 @@ QDomEntity::QDomEntity(QDomEntityPrivate* n)
}
/*!
- Assigns \a x to this DOM entity.
+ Assigns \a other to this DOM entity.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomEntity &QDomEntity::operator=(const QDomEntity &x) = default;
+QDomEntity &QDomEntity::operator=(const QDomEntity &other) = default;
/*!
\fn QDomNode::NodeType QDomEntity::nodeType() const
@@ -5415,14 +5418,14 @@ QDomEntityReference::QDomEntityReference()
}
/*!
- Constructs a copy of \a x.
+ Constructs a copy of \a entityReference.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomEntityReference::QDomEntityReference(const QDomEntityReference& x)
- : QDomNode(x)
+QDomEntityReference::QDomEntityReference(const QDomEntityReference &entityReference)
+ : QDomNode(entityReference)
{
}
@@ -5432,13 +5435,13 @@ QDomEntityReference::QDomEntityReference(QDomEntityReferencePrivate* n)
}
/*!
- Assigns \a x to this entity reference.
+ Assigns \a other to this entity reference.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomEntityReference &QDomEntityReference::operator=(const QDomEntityReference &x) = default;
+QDomEntityReference &QDomEntityReference::operator=(const QDomEntityReference &other) = default;
/*!
\fn QDomNode::NodeType QDomEntityReference::nodeType() const
@@ -5529,14 +5532,14 @@ QDomProcessingInstruction::QDomProcessingInstruction()
}
/*!
- Constructs a copy of \a x.
+ Constructs a copy of \a processingInstruction.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomProcessingInstruction::QDomProcessingInstruction(const QDomProcessingInstruction& x)
- : QDomNode(x)
+QDomProcessingInstruction::QDomProcessingInstruction(const QDomProcessingInstruction &processingInstruction)
+ : QDomNode(processingInstruction)
{
}
@@ -5546,14 +5549,14 @@ QDomProcessingInstruction::QDomProcessingInstruction(QDomProcessingInstructionPr
}
/*!
- Assigns \a x to this processing instruction.
+ Assigns \a other to this processing instruction.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
QDomProcessingInstruction &
-QDomProcessingInstruction::operator=(const QDomProcessingInstruction &x) = default;
+QDomProcessingInstruction::operator=(const QDomProcessingInstruction &other) = default;
/*!
\fn QDomNode::NodeType QDomProcessingInstruction::nodeType() const
@@ -5586,15 +5589,14 @@ QString QDomProcessingInstruction::data() const
}
/*!
- Sets the data contained in the processing instruction to \a d.
+ Sets the data contained in the processing instruction to \a data.
\sa data()
*/
-void QDomProcessingInstruction::setData(const QString& d)
+void QDomProcessingInstruction::setData(const QString &data)
{
- if (!impl)
- return;
- impl->setNodeValue(d);
+ if (impl)
+ impl->setNodeValue(data);
}
/**************************************************************
@@ -5992,8 +5994,8 @@ void QDomDocumentPrivate::saveDocument(QTextStream& s, const int indent, QDomNod
representation of the document can be obtained using toString().
\note The DOM tree might end up reserving a lot of memory if the XML
- document is big. For such documents, the QXmlStreamReader or the
- QXmlQuery classes might be better solutions.
+ document is big. For such documents, the QXmlStreamReader class
+ might be a better solution.
It is possible to insert a node from another document into the
document using importNode().
@@ -6018,10 +6020,9 @@ void QDomDocumentPrivate::saveDocument(QTextStream& s, const int indent, QDomNod
\l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}
Specifications.
- \sa {DOM Bookmarks Example}, {Simple DOM Model Example}
+ \sa {DOM Bookmarks Application}
*/
-
/*!
Constructs an empty document.
*/
@@ -6051,30 +6052,30 @@ QDomDocument::QDomDocument(const QDomDocumentType& doctype)
}
/*!
- Constructs a copy of \a x.
+ Constructs a copy of \a document.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomDocument::QDomDocument(const QDomDocument& x)
- : QDomNode(x)
+QDomDocument::QDomDocument(const QDomDocument &document)
+ : QDomNode(document)
{
}
-QDomDocument::QDomDocument(QDomDocumentPrivate* x)
- : QDomNode(x)
+QDomDocument::QDomDocument(QDomDocumentPrivate *pimpl)
+ : QDomNode(pimpl)
{
}
/*!
- Assigns \a x to this DOM document.
+ Assigns \a other to this DOM document.
The data of the copy is shared (shallow copy): modifying one node
will also change the other. If you want to make a deep copy, use
cloneNode().
*/
-QDomDocument &QDomDocument::operator=(const QDomDocument &x) = default;
+QDomDocument &QDomDocument::operator=(const QDomDocument &other) = default;
/*!
Destroys the object and frees its resources.
@@ -6105,6 +6106,7 @@ bool QDomDocument::setContent(const QString& text, bool namespaceProcessing,
/*!
\deprecated [6.8] Use the overload taking ParseOptions instead.
+ \overload
This function parses the XML document from the byte array \a
data and sets it as the content of the document. It tries to
@@ -6177,7 +6179,7 @@ static inline void unpackParseResult(const QDomDocument::ParseResult &parseResul
if (errorLine)
*errorLine = static_cast<int>(parseResult.errorLine);
if (errorColumn)
- *errorColumn = static_cast<int>(parseResult.errorLine);
+ *errorColumn = static_cast<int>(parseResult.errorColumn);
}
}
@@ -6336,8 +6338,8 @@ QT_WARNING_POP
/*!
\fn QDomDocument::ParseResult::operator bool() const
- Returns \c true if an error is found by QDomDocument::setContent();
- otherwise returns \c false.
+ Returns \c false if any error is found by QDomDocument::setContent();
+ otherwise returns \c true.
\sa QDomDocument::setContent()
*/
diff --git a/src/xml/dom/qdom.h b/src/xml/dom/qdom.h
index 7333b60774..a3900609c4 100644
--- a/src/xml/dom/qdom.h
+++ b/src/xml/dom/qdom.h
@@ -7,6 +7,8 @@
#include <QtXml/qtxmlglobal.h>
#include <QtCore/qstring.h>
+class tst_QDom;
+
QT_BEGIN_NAMESPACE
@@ -58,11 +60,11 @@ class Q_XML_EXPORT QDomImplementation
{
public:
QDomImplementation();
- QDomImplementation(const QDomImplementation&);
+ QDomImplementation(const QDomImplementation &implementation);
~QDomImplementation();
- QDomImplementation& operator= (const QDomImplementation&);
- bool operator== (const QDomImplementation&) const;
- bool operator!= (const QDomImplementation&) const;
+ QDomImplementation& operator=(const QDomImplementation &other);
+ bool operator==(const QDomImplementation &other) const;
+ bool operator!=(const QDomImplementation &other) const;
// functions
bool hasFeature(const QString& feature, const QString& version) const;
@@ -110,10 +112,10 @@ public:
};
QDomNode();
- QDomNode(const QDomNode&);
- QDomNode& operator= (const QDomNode&);
- bool operator== (const QDomNode&) const;
- bool operator!= (const QDomNode&) const;
+ QDomNode(const QDomNode &node);
+ QDomNode& operator=(const QDomNode &other);
+ bool operator==(const QDomNode &other) const;
+ bool operator!=(const QDomNode &other) const;
~QDomNode();
// DOM functions
@@ -144,7 +146,7 @@ public:
// DOM attributes
QString nodeValue() const;
- void setNodeValue(const QString&);
+ void setNodeValue(const QString &value);
QString prefix() const;
void setPrefix(const QString& pre);
@@ -201,6 +203,7 @@ protected:
QDomNode(QDomNodePrivate*);
private:
+ friend class ::tst_QDom;
friend class QDomDocument;
friend class QDomDocumentType;
friend class QDomNodeList;
@@ -211,10 +214,10 @@ class Q_XML_EXPORT QDomNodeList
{
public:
QDomNodeList();
- QDomNodeList(const QDomNodeList&);
- QDomNodeList& operator= (const QDomNodeList&);
- bool operator== (const QDomNodeList&) const;
- bool operator!= (const QDomNodeList&) const;
+ QDomNodeList(const QDomNodeList &nodeList);
+ QDomNodeList& operator=(const QDomNodeList &other);
+ bool operator==(const QDomNodeList &other) const;
+ bool operator!=(const QDomNodeList &other) const;
~QDomNodeList();
// DOM functions
@@ -240,8 +243,8 @@ class Q_XML_EXPORT QDomDocumentType : public QDomNode
{
public:
QDomDocumentType();
- QDomDocumentType(const QDomDocumentType& x);
- QDomDocumentType& operator= (const QDomDocumentType&);
+ QDomDocumentType(const QDomDocumentType &documentType);
+ QDomDocumentType& operator=(const QDomDocumentType &other);
// DOM read only attributes
QString name() const;
@@ -284,8 +287,8 @@ public:
QDomDocument();
explicit QDomDocument(const QString& name);
explicit QDomDocument(const QDomDocumentType& doctype);
- QDomDocument(const QDomDocument& x);
- QDomDocument& operator= (const QDomDocument&);
+ QDomDocument(const QDomDocument &document);
+ QDomDocument& operator=(const QDomDocument &other);
~QDomDocument();
// DOM functions
@@ -339,8 +342,8 @@ public:
ParseResult setContent(QXmlStreamReader *reader, ParseOptions options = ParseOption::Default);
// Qt extensions
- QString toString(int = 1) const;
- QByteArray toByteArray(int = 1) const;
+ QString toString(int indent = 1) const;
+ QByteArray toByteArray(int indent = 1) const;
private:
ParseResult setContentImpl(const QByteArray &data, ParseOptions options);
@@ -354,10 +357,10 @@ class Q_XML_EXPORT QDomNamedNodeMap
{
public:
QDomNamedNodeMap();
- QDomNamedNodeMap(const QDomNamedNodeMap&);
- QDomNamedNodeMap& operator= (const QDomNamedNodeMap&);
- bool operator== (const QDomNamedNodeMap&) const;
- bool operator!= (const QDomNamedNodeMap&) const;
+ QDomNamedNodeMap(const QDomNamedNodeMap &namedNodeMap);
+ QDomNamedNodeMap& operator=(const QDomNamedNodeMap &other);
+ bool operator==(const QDomNamedNodeMap &other) const;
+ bool operator!=(const QDomNamedNodeMap &other) const;
~QDomNamedNodeMap();
// DOM functions
@@ -391,8 +394,8 @@ class Q_XML_EXPORT QDomDocumentFragment : public QDomNode
{
public:
QDomDocumentFragment();
- QDomDocumentFragment(const QDomDocumentFragment& x);
- QDomDocumentFragment& operator= (const QDomDocumentFragment&);
+ QDomDocumentFragment(const QDomDocumentFragment &documentFragment);
+ QDomDocumentFragment& operator=(const QDomDocumentFragment &other);
// Overridden from QDomNode
inline QDomNode::NodeType nodeType() const { return DocumentFragmentNode; }
@@ -408,8 +411,8 @@ class Q_XML_EXPORT QDomCharacterData : public QDomNode
{
public:
QDomCharacterData();
- QDomCharacterData(const QDomCharacterData& x);
- QDomCharacterData& operator= (const QDomCharacterData&);
+ QDomCharacterData(const QDomCharacterData &characterData);
+ QDomCharacterData& operator=(const QDomCharacterData &other);
// DOM functions
QString substringData(unsigned long offset, unsigned long count);
@@ -423,7 +426,7 @@ public:
// DOM attributes
QString data() const;
- void setData(const QString&);
+ void setData(const QString &data);
// Overridden from QDomNode
QDomNode::NodeType nodeType() const;
@@ -441,8 +444,8 @@ class Q_XML_EXPORT QDomAttr : public QDomNode
{
public:
QDomAttr();
- QDomAttr(const QDomAttr& x);
- QDomAttr& operator= (const QDomAttr&);
+ QDomAttr(const QDomAttr &attr);
+ QDomAttr& operator=(const QDomAttr &other);
// DOM read only attributes
QString name() const;
@@ -451,7 +454,7 @@ public:
// DOM attributes
QString value() const;
- void setValue(const QString&);
+ void setValue(const QString &value);
// Overridden from QDomNode
inline QDomNode::NodeType nodeType() const { return AttributeNode; }
@@ -468,8 +471,8 @@ class Q_XML_EXPORT QDomElement : public QDomNode
{
public:
QDomElement();
- QDomElement(const QDomElement& x);
- QDomElement& operator= (const QDomElement&);
+ QDomElement(const QDomElement &element);
+ QDomElement& operator=(const QDomElement &other);
// DOM functions
QString attribute(const QString& name, const QString& defValue = QString() ) const;
@@ -526,8 +529,8 @@ class Q_XML_EXPORT QDomText : public QDomCharacterData
{
public:
QDomText();
- QDomText(const QDomText& x);
- QDomText& operator= (const QDomText&);
+ QDomText(const QDomText &text);
+ QDomText& operator=(const QDomText &other);
// DOM functions
QDomText splitText(int offset);
@@ -547,8 +550,8 @@ class Q_XML_EXPORT QDomComment : public QDomCharacterData
{
public:
QDomComment();
- QDomComment(const QDomComment& x);
- QDomComment& operator= (const QDomComment&);
+ QDomComment(const QDomComment &comment);
+ QDomComment& operator=(const QDomComment &other);
// Overridden from QDomCharacterData
inline QDomNode::NodeType nodeType() const { return CommentNode; }
@@ -564,8 +567,8 @@ class Q_XML_EXPORT QDomCDATASection : public QDomText
{
public:
QDomCDATASection();
- QDomCDATASection(const QDomCDATASection& x);
- QDomCDATASection& operator= (const QDomCDATASection&);
+ QDomCDATASection(const QDomCDATASection &cdataSection);
+ QDomCDATASection& operator=(const QDomCDATASection &other);
// Overridden from QDomText
inline QDomNode::NodeType nodeType() const { return CDATASectionNode; }
@@ -581,8 +584,8 @@ class Q_XML_EXPORT QDomNotation : public QDomNode
{
public:
QDomNotation();
- QDomNotation(const QDomNotation& x);
- QDomNotation& operator= (const QDomNotation&);
+ QDomNotation(const QDomNotation &notation);
+ QDomNotation& operator=(const QDomNotation &other);
// DOM read only attributes
QString publicId() const;
@@ -602,8 +605,8 @@ class Q_XML_EXPORT QDomEntity : public QDomNode
{
public:
QDomEntity();
- QDomEntity(const QDomEntity& x);
- QDomEntity& operator= (const QDomEntity&);
+ QDomEntity(const QDomEntity &entity);
+ QDomEntity& operator=(const QDomEntity &other);
// DOM read only attributes
QString publicId() const;
@@ -623,8 +626,8 @@ class Q_XML_EXPORT QDomEntityReference : public QDomNode
{
public:
QDomEntityReference();
- QDomEntityReference(const QDomEntityReference& x);
- QDomEntityReference& operator= (const QDomEntityReference&);
+ QDomEntityReference(const QDomEntityReference &entityReference);
+ QDomEntityReference& operator=(const QDomEntityReference &other);
// Overridden from QDomNode
inline QDomNode::NodeType nodeType() const { return EntityReferenceNode; }
@@ -640,15 +643,15 @@ class Q_XML_EXPORT QDomProcessingInstruction : public QDomNode
{
public:
QDomProcessingInstruction();
- QDomProcessingInstruction(const QDomProcessingInstruction& x);
- QDomProcessingInstruction& operator= (const QDomProcessingInstruction&);
+ QDomProcessingInstruction(const QDomProcessingInstruction &processingInstruction);
+ QDomProcessingInstruction& operator=(const QDomProcessingInstruction &other);
// DOM read only attributes
QString target() const;
// DOM attributes
QString data() const;
- void setData(const QString& d);
+ void setData(const QString &data);
// Overridden from QDomNode
inline QDomNode::NodeType nodeType() const { return ProcessingInstructionNode; }
@@ -661,7 +664,7 @@ private:
};
-Q_XML_EXPORT QTextStream& operator<<(QTextStream&, const QDomNode&);
+Q_XML_EXPORT QTextStream& operator<<(QTextStream& stream, const QDomNode& node);
#endif // QT_NO_DOM
diff --git a/src/xml/dom/qdom_p.h b/src/xml/dom/qdom_p.h
index fb71f8ce23..b2ecd534c8 100644
--- a/src/xml/dom/qdom_p.h
+++ b/src/xml/dom/qdom_p.h
@@ -142,7 +142,8 @@ public:
bool operator==(const QDomNodeListPrivate &) const;
bool operator!=(const QDomNodeListPrivate &) const;
- void createList();
+ void createList() const;
+ bool maybeCreateList() const;
QDomNodePrivate *item(int index);
int length() const;
@@ -153,8 +154,8 @@ public:
QDomNodePrivate *node_impl;
QString tagname;
QString nsURI;
- QList<QDomNodePrivate *> list;
- long timestamp;
+ mutable QList<QDomNodePrivate *> list;
+ mutable long timestamp;
};
class QDomNamedNodeMapPrivate
diff --git a/src/xml/dom/qdomhelpers.cpp b/src/xml/dom/qdomhelpers.cpp
index 62258fbdfd..0649e0c75d 100644
--- a/src/xml/dom/qdomhelpers.cpp
+++ b/src/xml/dom/qdomhelpers.cpp
@@ -8,6 +8,7 @@
#include "qdomhelpers_p.h"
#include "qdom_p.h"
#include "qxmlstream.h"
+#include "private/qxmlstream_p.h"
#include <memory>
#include <stack>
@@ -264,9 +265,9 @@ bool QDomParser::parseProlog()
if (reader->isStandaloneDocument()) {
value += u" standalone='yes'"_s;
} else {
- // TODO: Add standalone='no', if 'standalone' is specified. With the current
- // QXmlStreamReader there is no way to figure out if it was specified or not.
- // QXmlStreamReader needs to be modified for handling that case correctly.
+ // Add the standalone attribute only if it was specified
+ if (reader->hasStandaloneDeclaration())
+ value += u" standalone='no'"_s;
}
if (!domBuilder.processingInstruction(u"xml"_s, value)) {